[evolution/kill-bonobo: 40/42] Merge branch 'master' into kill-bonobo



commit cc3a98fc1ad5bb87aa7335f3de404ee7feee1541
Merge: 10f8406... e4afd3f...
Author: Matthew Barnes <mbarnes redhat com>
Date:   Wed May 27 08:37:17 2009 -0400

    Merge branch 'master' into kill-bonobo
    
    Conflicts:
    	a11y/widgets/ea-combo-button.c
    	a11y/widgets/ea-combo-button.h
    	addressbook/gui/component/addressbook-component.c
    	addressbook/gui/component/addressbook-component.h
    	addressbook/gui/component/addressbook-view.c
    	addressbook/gui/component/addressbook-view.h
    	addressbook/gui/component/component-factory.c
    	addressbook/gui/widgets/e-addressbook-view.c
    	addressbook/gui/widgets/eab-contact-display.c
    	addressbook/gui/widgets/eab-gui-util.h
    	addressbook/gui/widgets/eab-menu.c
    	addressbook/gui/widgets/eab-menu.h
    	addressbook/gui/widgets/eab-popup-control.c
    	addressbook/gui/widgets/eab-popup-control.h
    	addressbook/gui/widgets/eab-popup.c
    	addressbook/gui/widgets/eab-popup.h
    	calendar/gui/cal-search-bar.c
    	calendar/gui/calendar-commands.c
    	calendar/gui/calendar-component.c
    	calendar/gui/comp-editor-factory.c
    	calendar/gui/comp-editor-factory.h
    	calendar/gui/control-factory.c
    	calendar/gui/dialogs/comp-editor.c
    	calendar/gui/e-cal-component-memo-preview.c
    	calendar/gui/e-cal-component-memo-preview.h
    	calendar/gui/e-calendar-table.c
    	calendar/gui/e-memo-table.c
    	calendar/gui/e-memos.c
    	calendar/gui/e-tasks.c
    	calendar/gui/gnome-cal.c
    	calendar/gui/gnome-cal.h
    	calendar/gui/itip-bonobo-control.c
    	calendar/gui/itip-bonobo-control.h
    	calendar/gui/main.c
    	calendar/gui/memos-component.c
    	calendar/gui/memos-control.c
    	calendar/gui/memos-control.h
    	calendar/gui/migration.c
    	calendar/gui/migration.h
    	calendar/gui/tasks-component.c
    	calendar/gui/tasks-control.c
    	calendar/importers/main.c
    	composer/Makefile.am
    	composer/e-composer-header-table.c
    	composer/e-composer-header.c
    	composer/e-composer-header.h
    	composer/e-composer-name-header.c
    	composer/e-composer-private.c
    	composer/e-composer-text-header.c
    	composer/e-msg-composer.c
    	composer/e-msg-composer.h
    	e-util/e-corba-utils.h
    	e-util/e-logger.c
    	e-util/e-logger.h
    	e-util/e-util-labels.c
    	e-util/e-util-labels.h
    	em-format/em-format.c
    	mail/Makefile.am
    	mail/e-mail-shell-migrate.c
    	mail/em-account-editor.c
    	mail/em-account-editor.h
    	mail/em-composer-prefs.c
    	mail/em-composer-utils.c
    	mail/em-composer-utils.h
    	mail/em-folder-browser.c
    	mail/em-folder-tree-model.c
    	mail/em-folder-tree.c
    	mail/em-folder-tree.h
    	mail/em-folder-utils.c
    	mail/em-folder-utils.h
    	mail/em-folder-view.c
    	mail/em-format-html-display.c
    	mail/em-format-html.c
    	mail/em-mailer-prefs.c
    	mail/em-mailer-prefs.h
    	mail/em-message-browser.c
    	mail/em-message-browser.h
    	mail/em-network-prefs.h
    	mail/em-popup.c
    	mail/em-utils.c
    	mail/importers/Makefile.am
    	mail/mail-component-factory.c
    	mail/mail-component.c
    	mail/mail-config-factory.c
    	mail/mail-config-factory.h
    	mail/mail-config.c
    	mail/mail-dialogs.glade
    	mail/mail-types.h
    	plugins/calendar-weather/calendar-weather.c
    	plugins/mail-account-disable/mail-account-disable.c
    	plugins/select-one-source/select-one-source.c
    	po/POTFILES.in
    	shell/e-component-registry.c
    	shell/e-component-registry.h
    	shell/e-component-view.c
    	shell/e-component-view.h
    	shell/e-corba-config-page.c
    	shell/e-corba-config-page.h
    	shell/e-shell-constants.h
    	shell/e-shell-settings-dialog.c
    	shell/e-shell-settings-dialog.h
    	shell/e-shell-window-commands.c
    	shell/e-shell-window.c
    	shell/e-shell.h
    	shell/e-sidebar.c
    	shell/e-sidebar.h
    	shell/e-user-creatable-items-handler.c
    	shell/e-user-creatable-items-handler.h
    	shell/es-menu.c
    	shell/es-menu.h
    	shell/evolution-component.h
    	shell/evolution-config-control.c
    	shell/evolution-config-control.h
    	shell/evolution-listener.c
    	shell/evolution-listener.h
    	shell/evolution-shell-component-utils.c
    	shell/evolution-shell-component-utils.h
    	shell/importer/evolution-importer-client.c
    	shell/importer/evolution-importer-client.h
    	shell/importer/evolution-importer-listener.c
    	shell/importer/evolution-importer-listener.h
    	shell/importer/evolution-importer.c
    	shell/importer/evolution-importer.h
    	shell/importer/evolution-intelligent-importer.c
    	shell/importer/evolution-intelligent-importer.h
    	shell/importer/intelligent.c
    	shell/main.c
    	shell/test/evolution-test-component.c
    	shell/test/evolution-test-component.h
    	widgets/menus/gal-view-instance.c
    	widgets/menus/gal-view-menus.c
    	widgets/menus/gal-view-menus.h
    	widgets/misc/Makefile.am
    	widgets/misc/e-activity-handler.c
    	widgets/misc/e-activity-handler.h
    	widgets/misc/e-charset-picker.c
    	widgets/misc/e-combo-button.c
    	widgets/misc/e-combo-button.h
    	widgets/misc/e-config-page.h
    	widgets/misc/e-dropdown-button.c
    	widgets/misc/e-dropdown-button.h
    	widgets/misc/e-filter-bar.c
    	widgets/misc/e-info-label.c
    	widgets/misc/e-info-label.h
    	widgets/misc/e-multi-config-dialog.c
    	widgets/misc/e-multi-config-dialog.h
    	widgets/misc/e-search-bar.c
    	widgets/misc/e-search-bar.h
    	widgets/misc/e-task-bar.c
    	widgets/misc/e-task-bar.h
    	widgets/misc/e-task-widget.c
    	widgets/misc/e-task-widget.h
    	widgets/misc/test-dropdown-button.c
    	widgets/misc/test-error.c
    	widgets/misc/test-info-label.c
    	widgets/table/e-table-example-1.c

 NEWS                                               |   54 +
 a11y/ea-cell-table.c                               |    2 +-
 a11y/ea-cell-table.h                               |    2 +-
 a11y/ea-factory.h                                  |    2 +-
 a11y/gal-a11y-factory.h                            |    2 +-
 a11y/gal-a11y-util.c                               |    2 +-
 a11y/gal-a11y-util.h                               |    2 +-
 acinclude.m4                                       |   62 +
 addressbook/conduit/address-conduit.c              |   12 +-
 addressbook/gui/component/addressbook-config.c     |   46 +-
 addressbook/gui/component/addressbook-config.h     |    2 +-
 addressbook/gui/component/autocompletion-config.c  |    2 +-
 addressbook/gui/component/autocompletion-config.h  |    2 +-
 addressbook/gui/component/e-book-shell-backend.c   |    2 +-
 addressbook/gui/component/e-book-shell-backend.h   |    2 +-
 addressbook/gui/component/e-book-shell-content.c   |    2 +-
 addressbook/gui/component/e-book-shell-content.h   |    2 +-
 addressbook/gui/component/e-book-shell-migrate.c   |    2 +-
 addressbook/gui/component/e-book-shell-migrate.h   |    2 +-
 addressbook/gui/component/e-book-shell-sidebar.c   |    2 +-
 addressbook/gui/component/e-book-shell-sidebar.h   |    2 +-
 .../gui/component/e-book-shell-view-actions.c      |    2 +-
 .../gui/component/e-book-shell-view-actions.h      |    2 +-
 .../gui/component/e-book-shell-view-private.c      |    2 +-
 .../gui/component/e-book-shell-view-private.h      |    2 +-
 addressbook/gui/component/e-book-shell-view.c      |    2 +-
 addressbook/gui/component/e-book-shell-view.h      |    2 +-
 addressbook/gui/component/eab-composer-util.c      |    2 +-
 addressbook/gui/component/eab-composer-util.h      |    2 +-
 .../gui/component/evolution-module-addressbook.c   |    2 +-
 .../gui/contact-editor/e-contact-editor-fullname.c |   11 +-
 .../gui/contact-editor/e-contact-editor-fullname.h |    2 +-
 addressbook/gui/contact-editor/e-contact-editor.c  |   14 +-
 addressbook/gui/contact-editor/e-contact-editor.h  |    2 +-
 .../gui/contact-editor/e-contact-quick-add.c       |    6 +-
 .../gui/contact-editor/e-contact-quick-add.h       |    2 +-
 addressbook/gui/contact-editor/eab-editor.c        |    2 +-
 addressbook/gui/contact-editor/eab-editor.h        |    2 +-
 addressbook/gui/contact-editor/test-editor.c       |    2 +-
 .../contact-list-editor/e-contact-list-editor.c    |   18 +-
 .../contact-list-editor/e-contact-list-editor.h    |    2 +-
 .../gui/contact-list-editor/e-contact-list-model.c |    2 +-
 .../gui/contact-list-editor/e-contact-list-model.h |    2 +-
 addressbook/gui/merging/eab-contact-compare.c      |    4 +-
 addressbook/gui/merging/eab-contact-compare.h      |    2 +-
 addressbook/gui/merging/eab-contact-merging.c      |    2 +-
 addressbook/gui/merging/eab-contact-merging.h      |    2 +-
 addressbook/gui/widgets/a11y/ea-addressbook-view.c |    2 +-
 addressbook/gui/widgets/a11y/ea-addressbook-view.h |    2 +-
 addressbook/gui/widgets/a11y/ea-addressbook.c      |    2 +-
 addressbook/gui/widgets/a11y/ea-addressbook.h      |    2 +-
 addressbook/gui/widgets/a11y/ea-minicard-view.c    |    2 +-
 addressbook/gui/widgets/a11y/ea-minicard-view.h    |    2 +-
 addressbook/gui/widgets/a11y/ea-minicard.c         |    2 +-
 addressbook/gui/widgets/a11y/ea-minicard.h         |    2 +-
 addressbook/gui/widgets/e-addressbook-model.c      |    2 +-
 addressbook/gui/widgets/e-addressbook-model.h      |    2 +-
 .../gui/widgets/e-addressbook-reflow-adapter.c     |    2 +-
 .../gui/widgets/e-addressbook-reflow-adapter.h     |    2 +-
 addressbook/gui/widgets/e-addressbook-selector.c   |    4 +-
 .../gui/widgets/e-addressbook-table-adapter.c      |    2 +-
 .../gui/widgets/e-addressbook-table-adapter.h      |    2 +-
 addressbook/gui/widgets/e-addressbook-view.c       |    6 +-
 addressbook/gui/widgets/e-addressbook-view.h       |    2 +-
 addressbook/gui/widgets/e-minicard-label.c         |    2 +-
 addressbook/gui/widgets/e-minicard-label.h         |    2 +-
 addressbook/gui/widgets/e-minicard-view-widget.c   |    2 +-
 addressbook/gui/widgets/e-minicard-view-widget.h   |    2 +-
 addressbook/gui/widgets/e-minicard-view.c          |    6 +-
 addressbook/gui/widgets/e-minicard-view.h          |    2 +-
 addressbook/gui/widgets/e-minicard.c               |   10 +-
 addressbook/gui/widgets/e-minicard.h               |    2 +-
 addressbook/gui/widgets/eab-config.c               |    2 +-
 addressbook/gui/widgets/eab-config.h               |    2 +-
 addressbook/gui/widgets/eab-contact-display.c      |   13 +-
 addressbook/gui/widgets/eab-contact-display.h      |    2 +-
 addressbook/gui/widgets/eab-gui-util.c             |    4 +-
 addressbook/gui/widgets/eab-gui-util.h             |    2 +-
 .../gui/widgets/gal-view-factory-minicard.c        |    2 +-
 .../gui/widgets/gal-view-factory-minicard.h        |    2 +-
 addressbook/gui/widgets/gal-view-minicard.c        |    2 +-
 addressbook/gui/widgets/gal-view-minicard.h        |    2 +-
 .../importers/evolution-addressbook-importers.h    |    2 +-
 addressbook/importers/evolution-csv-importer.c     |    6 +-
 addressbook/importers/evolution-ldif-importer.c    |    6 +-
 addressbook/importers/evolution-vcard-importer.c   |    2 +-
 addressbook/printing/Makefile.am                   |    2 -
 addressbook/printing/e-contact-print-types.h       |    2 +-
 addressbook/printing/e-contact-print.c             |    2 +-
 addressbook/printing/e-contact-print.h             |    2 +-
 addressbook/printing/test-print.c                  |   10 +-
 .../evolution-addressbook-export-list-cards.c      |    5 +-
 .../evolution-addressbook-export-list-folders.c    |    2 +-
 addressbook/tools/evolution-addressbook-export.c   |    2 +-
 addressbook/tools/evolution-addressbook-export.h   |    2 +-
 addressbook/util/Makefile.am                       |    1 -
 addressbook/util/addressbook.c                     |    4 +-
 addressbook/util/addressbook.h                     |    2 +-
 addressbook/util/eab-book-util.c                   |    2 +-
 addressbook/util/eab-book-util.h                   |    2 +-
 art/broken-image-16.xpm                            |    2 +-
 art/broken-image-24.xpm                            |    2 +-
 art/empty.xpm                                      |    2 +-
 art/jump.xpm                                       |    4 +-
 calendar/common/authentication.c                   |    4 +-
 calendar/common/authentication.h                   |    2 +-
 calendar/conduits/calendar/calendar-conduit.c      |    4 +-
 .../conduits/common/libecalendar-common-conduit.c  |    2 +-
 .../conduits/common/libecalendar-common-conduit.h  |    2 +-
 calendar/conduits/memo/memo-conduit.c              |    2 +-
 calendar/conduits/todo/todo-conduit.c              |    2 +-
 calendar/gui/a11y/ea-cal-view-event.c              |    9 +-
 calendar/gui/a11y/ea-cal-view-event.h              |    2 +-
 calendar/gui/a11y/ea-cal-view.c                    |    2 +-
 calendar/gui/a11y/ea-cal-view.h                    |    2 +-
 calendar/gui/a11y/ea-calendar-helpers.c            |    2 +-
 calendar/gui/a11y/ea-calendar-helpers.h            |    2 +-
 calendar/gui/a11y/ea-calendar.c                    |    2 +-
 calendar/gui/a11y/ea-calendar.h                    |    2 +-
 calendar/gui/a11y/ea-day-view-cell.c               |    2 +-
 calendar/gui/a11y/ea-day-view-cell.h               |    2 +-
 calendar/gui/a11y/ea-day-view-main-item.c          |    4 +-
 calendar/gui/a11y/ea-day-view-main-item.h          |    2 +-
 calendar/gui/a11y/ea-day-view.c                    |    2 +-
 calendar/gui/a11y/ea-day-view.h                    |    2 +-
 calendar/gui/a11y/ea-gnome-calendar.c              |    2 +-
 calendar/gui/a11y/ea-gnome-calendar.h              |    2 +-
 calendar/gui/a11y/ea-jump-button.c                 |    4 +-
 calendar/gui/a11y/ea-jump-button.h                 |    2 +-
 calendar/gui/a11y/ea-week-view-cell.c              |    2 +-
 calendar/gui/a11y/ea-week-view-cell.h              |    2 +-
 calendar/gui/a11y/ea-week-view-main-item.c         |    2 +-
 calendar/gui/a11y/ea-week-view-main-item.h         |    2 +-
 calendar/gui/a11y/ea-week-view.c                   |    2 +-
 calendar/gui/a11y/ea-week-view.h                   |    2 +-
 calendar/gui/alarm-notify/alarm-notify-dialog.c    |    2 +-
 calendar/gui/alarm-notify/alarm-notify-dialog.h    |    2 +-
 calendar/gui/alarm-notify/alarm-notify.c           |    4 +-
 calendar/gui/alarm-notify/alarm-notify.h           |    2 +-
 calendar/gui/alarm-notify/alarm-queue.c            |    7 +-
 calendar/gui/alarm-notify/alarm-queue.h            |    2 +-
 calendar/gui/alarm-notify/alarm.c                  |    2 +-
 calendar/gui/alarm-notify/alarm.h                  |    2 +-
 calendar/gui/alarm-notify/config-data.c            |    2 +-
 calendar/gui/alarm-notify/config-data.h            |    2 +-
 calendar/gui/alarm-notify/notify-main.c            |    2 +-
 calendar/gui/alarm-notify/util.c                   |    2 +-
 calendar/gui/alarm-notify/util.h                   |    2 +-
 calendar/gui/cal-search-bar.c                      |    4 +-
 calendar/gui/cal-search-bar.h                      |    2 +-
 calendar/gui/calendar-commands.c                   |    4 +-
 calendar/gui/calendar-commands.h                   |    2 +-
 calendar/gui/calendar-component.c                  |   13 +-
 calendar/gui/calendar-component.h                  |    2 +-
 calendar/gui/calendar-config-keys.h                |    2 +-
 calendar/gui/calendar-config.c                     |    2 +-
 calendar/gui/calendar-config.h                     |    2 +-
 calendar/gui/calendar-view-factory.c               |    2 +-
 calendar/gui/calendar-view-factory.h               |    2 +-
 calendar/gui/calendar-view.c                       |    2 +-
 calendar/gui/calendar-view.h                       |    2 +-
 calendar/gui/comp-util.c                           |    8 +-
 calendar/gui/comp-util.h                           |    2 +-
 calendar/gui/dialogs/alarm-dialog.c                |    2 +-
 calendar/gui/dialogs/alarm-dialog.h                |    2 +-
 calendar/gui/dialogs/alarm-list-dialog.c           |    2 +-
 calendar/gui/dialogs/alarm-list-dialog.h           |    2 +-
 calendar/gui/dialogs/cal-attachment-select-file.c  |    2 +-
 calendar/gui/dialogs/cal-attachment-select-file.h  |    2 +-
 calendar/gui/dialogs/cal-prefs-dialog.c            |   24 +-
 calendar/gui/dialogs/cal-prefs-dialog.h            |    2 +-
 calendar/gui/dialogs/calendar-setup.c              |   46 +-
 calendar/gui/dialogs/calendar-setup.h              |    2 +-
 calendar/gui/dialogs/cancel-comp.c                 |    2 +-
 calendar/gui/dialogs/cancel-comp.h                 |    2 +-
 calendar/gui/dialogs/changed-comp.c                |    2 +-
 calendar/gui/dialogs/changed-comp.h                |    2 +-
 calendar/gui/dialogs/comp-editor-page.c            |    2 +-
 calendar/gui/dialogs/comp-editor-page.h            |    2 +-
 calendar/gui/dialogs/comp-editor-util.c            |   10 +-
 calendar/gui/dialogs/comp-editor-util.h            |    2 +-
 calendar/gui/dialogs/comp-editor.c                 |    8 +-
 calendar/gui/dialogs/comp-editor.h                 |    2 +-
 calendar/gui/dialogs/copy-source-dialog.c          |    2 +-
 calendar/gui/dialogs/copy-source-dialog.h          |    2 +-
 calendar/gui/dialogs/delete-comp.c                 |    2 +-
 calendar/gui/dialogs/delete-comp.h                 |    2 +-
 calendar/gui/dialogs/delete-error.c                |    2 +-
 calendar/gui/dialogs/delete-error.h                |    2 +-
 calendar/gui/dialogs/e-delegate-dialog.c           |    2 +-
 calendar/gui/dialogs/e-delegate-dialog.h           |    2 +-
 calendar/gui/dialogs/e-send-options-utils.c        |    4 +-
 calendar/gui/dialogs/e-send-options-utils.h        |    4 +-
 calendar/gui/dialogs/event-editor.c                |    2 +-
 calendar/gui/dialogs/event-editor.h                |    4 +-
 calendar/gui/dialogs/event-page.c                  |   22 +-
 calendar/gui/dialogs/event-page.h                  |    2 +-
 calendar/gui/dialogs/memo-editor.c                 |    2 +-
 calendar/gui/dialogs/memo-editor.h                 |    2 +-
 calendar/gui/dialogs/memo-page.c                   |    2 +-
 calendar/gui/dialogs/memo-page.h                   |    2 +-
 calendar/gui/dialogs/recur-comp.c                  |    2 +-
 calendar/gui/dialogs/recur-comp.h                  |    2 +-
 calendar/gui/dialogs/recurrence-page.c             |    2 +-
 calendar/gui/dialogs/recurrence-page.h             |    2 +-
 calendar/gui/dialogs/save-comp.c                   |    2 +-
 calendar/gui/dialogs/save-comp.h                   |    4 +-
 calendar/gui/dialogs/schedule-page.c               |    2 +-
 calendar/gui/dialogs/schedule-page.h               |    2 +-
 calendar/gui/dialogs/select-source-dialog.c        |    2 +-
 calendar/gui/dialogs/select-source-dialog.h        |    2 +-
 calendar/gui/dialogs/send-comp.c                   |    2 +-
 calendar/gui/dialogs/send-comp.h                   |    2 +-
 calendar/gui/dialogs/task-details-page.c           |    2 +-
 calendar/gui/dialogs/task-details-page.h           |    2 +-
 calendar/gui/dialogs/task-editor.c                 |    2 +-
 calendar/gui/dialogs/task-editor.h                 |    2 +-
 calendar/gui/dialogs/task-page.c                   |    8 +-
 calendar/gui/dialogs/task-page.h                   |    2 +-
 calendar/gui/e-alarm-list.c                        |    2 +-
 calendar/gui/e-alarm-list.h                        |    4 +-
 calendar/gui/e-attachment-handler-calendar.c       |    2 +-
 calendar/gui/e-attachment-handler-calendar.h       |    2 +-
 calendar/gui/e-cal-component-preview.c             |    2 +-
 calendar/gui/e-cal-component-preview.h             |    2 +-
 calendar/gui/e-cal-config.c                        |    2 +-
 calendar/gui/e-cal-config.h                        |    2 +-
 calendar/gui/e-cal-event.c                         |    2 +-
 calendar/gui/e-cal-event.h                         |    2 +-
 calendar/gui/e-cal-list-view-config.c              |    2 +-
 calendar/gui/e-cal-list-view-config.h              |    2 +-
 calendar/gui/e-cal-list-view.c                     |    2 +-
 calendar/gui/e-cal-list-view.h                     |    2 +-
 calendar/gui/e-cal-menu.c                          |    2 +-
 calendar/gui/e-cal-menu.h                          |    2 +-
 calendar/gui/e-cal-model-calendar.c                |    8 +-
 calendar/gui/e-cal-model-calendar.h                |    2 +-
 calendar/gui/e-cal-model-memos.c                   |    6 +-
 calendar/gui/e-cal-model-memos.h                   |    2 +-
 calendar/gui/e-cal-model-tasks.c                   |   36 +-
 calendar/gui/e-cal-model-tasks.h                   |    2 +-
 calendar/gui/e-cal-model.c                         |   46 +-
 calendar/gui/e-cal-model.h                         |    4 +-
 calendar/gui/e-cal-popup.c                         |    2 +-
 calendar/gui/e-cal-popup.h                         |    2 +-
 calendar/gui/e-calendar-table-config.c             |    2 +-
 calendar/gui/e-calendar-table-config.h             |    2 +-
 calendar/gui/e-calendar-table.c                    |    2 +-
 calendar/gui/e-calendar-table.h                    |    2 +-
 calendar/gui/e-calendar-view.c                     |   78 +-
 calendar/gui/e-calendar-view.h                     |    2 +-
 calendar/gui/e-cell-date-edit-config.c             |    2 +-
 calendar/gui/e-cell-date-edit-config.h             |    2 +-
 calendar/gui/e-cell-date-edit-text.c               |    2 +-
 calendar/gui/e-cell-date-edit-text.h               |    2 +-
 calendar/gui/e-comp-editor-registry.c              |    2 +-
 calendar/gui/e-comp-editor-registry.h              |    2 +-
 calendar/gui/e-date-edit-config.c                  |    2 +-
 calendar/gui/e-date-edit-config.h                  |    2 +-
 calendar/gui/e-date-time-list.c                    |    2 +-
 calendar/gui/e-date-time-list.h                    |    2 +-
 calendar/gui/e-day-view-config.c                   |    2 +-
 calendar/gui/e-day-view-config.h                   |    2 +-
 calendar/gui/e-day-view-layout.c                   |    2 +-
 calendar/gui/e-day-view-layout.h                   |    2 +-
 calendar/gui/e-day-view-main-item.c                |    9 +-
 calendar/gui/e-day-view-main-item.h                |    2 +-
 calendar/gui/e-day-view-time-item.c                |    7 +-
 calendar/gui/e-day-view-time-item.h                |    2 +-
 calendar/gui/e-day-view-top-item.c                 |    6 +-
 calendar/gui/e-day-view-top-item.h                 |    2 +-
 calendar/gui/e-day-view.c                          |   40 +-
 calendar/gui/e-day-view.h                          |    4 +-
 calendar/gui/e-itip-control.c                      |    6 +-
 calendar/gui/e-itip-control.h                      |    2 +-
 calendar/gui/e-meeting-attendee.c                  |    5 +-
 calendar/gui/e-meeting-attendee.h                  |    2 +-
 calendar/gui/e-meeting-list-view.c                 |   13 +-
 calendar/gui/e-meeting-list-view.h                 |    2 +-
 calendar/gui/e-meeting-store.c                     |    4 +-
 calendar/gui/e-meeting-store.h                     |    2 +-
 calendar/gui/e-meeting-time-sel-item.c             |    2 +-
 calendar/gui/e-meeting-time-sel-item.h             |    2 +-
 calendar/gui/e-meeting-time-sel.c                  |    2 +-
 calendar/gui/e-meeting-time-sel.h                  |    2 +-
 calendar/gui/e-meeting-types.h                     |    2 +-
 calendar/gui/e-meeting-utils.c                     |    2 +-
 calendar/gui/e-meeting-utils.h                     |    2 +-
 calendar/gui/e-memo-list-selector.c                |    4 +-
 calendar/gui/e-memo-table-config.c                 |    2 +-
 calendar/gui/e-memo-table-config.h                 |    2 +-
 calendar/gui/e-memo-table.c                        |    6 +-
 calendar/gui/e-memo-table.h                        |    2 +-
 calendar/gui/e-memos.c                             |    2 +-
 calendar/gui/e-memos.h                             |    2 +-
 calendar/gui/e-mini-calendar-config.c              |    2 +-
 calendar/gui/e-mini-calendar-config.h              |    2 +-
 calendar/gui/e-select-names-editable.c             |    8 +-
 calendar/gui/e-select-names-editable.h             |    2 +-
 calendar/gui/e-select-names-renderer.c             |    4 +-
 calendar/gui/e-select-names-renderer.h             |    2 +-
 calendar/gui/e-task-list-selector.c                |    4 +-
 calendar/gui/e-tasks.c                             |    2 +-
 calendar/gui/e-tasks.h                             |    2 +-
 calendar/gui/e-timezone-entry.c                    |    2 +-
 calendar/gui/e-timezone-entry.h                    |    2 +-
 calendar/gui/e-week-view-config.c                  |    2 +-
 calendar/gui/e-week-view-config.h                  |    2 +-
 calendar/gui/e-week-view-event-item.c              |    5 +-
 calendar/gui/e-week-view-event-item.h              |    2 +-
 calendar/gui/e-week-view-layout.c                  |    2 +-
 calendar/gui/e-week-view-layout.h                  |    2 +-
 calendar/gui/e-week-view-main-item.c               |    2 +-
 calendar/gui/e-week-view-main-item.h               |    2 +-
 calendar/gui/e-week-view-titles-item.c             |    2 +-
 calendar/gui/e-week-view-titles-item.h             |    2 +-
 calendar/gui/e-week-view.c                         |   34 +-
 calendar/gui/e-week-view.h                         |    4 +-
 calendar/gui/gnome-cal.c                           |   40 +-
 calendar/gui/gnome-cal.h                           |    4 +-
 calendar/gui/goto.c                                |    2 +-
 calendar/gui/goto.h                                |    2 +-
 calendar/gui/itip-utils.c                          |    8 +-
 calendar/gui/itip-utils.h                          |    2 +-
 calendar/gui/memos-component.c                     |    2 +-
 calendar/gui/memos-component.h                     |    2 +-
 calendar/gui/misc.c                                |    2 +-
 calendar/gui/misc.h                                |    2 +-
 calendar/gui/print.c                               |   29 +-
 calendar/gui/print.h                               |    2 +-
 calendar/gui/tag-calendar.c                        |    2 +-
 calendar/gui/tag-calendar.h                        |    2 +-
 calendar/gui/tasks-component.c                     |   26 +-
 calendar/gui/tasks-component.h                     |    2 +-
 calendar/gui/tasks-control.c                       |    6 +-
 calendar/gui/tasks-control.h                       |    2 +-
 calendar/gui/weekday-picker.c                      |    4 +-
 calendar/gui/weekday-picker.h                      |    2 +-
 calendar/importers/evolution-calendar-importer.h   |    2 +-
 calendar/importers/icalendar-importer.c            |   12 +-
 calendar/module/e-cal-shell-backend.c              |    4 +-
 calendar/module/e-cal-shell-backend.h              |    2 +-
 calendar/module/e-cal-shell-content.c              |    2 +-
 calendar/module/e-cal-shell-content.h              |    2 +-
 calendar/module/e-cal-shell-migrate.c              |    2 +-
 calendar/module/e-cal-shell-migrate.h              |    2 +-
 calendar/module/e-cal-shell-settings.c             |    2 +-
 calendar/module/e-cal-shell-settings.h             |    2 +-
 calendar/module/e-cal-shell-sidebar.c              |    2 +-
 calendar/module/e-cal-shell-sidebar.h              |    2 +-
 calendar/module/e-cal-shell-view-actions.c         |    4 +-
 calendar/module/e-cal-shell-view-actions.h         |    2 +-
 calendar/module/e-cal-shell-view-memopad.c         |    2 +-
 calendar/module/e-cal-shell-view-private.c         |    4 +-
 calendar/module/e-cal-shell-view-private.h         |    2 +-
 calendar/module/e-cal-shell-view-taskpad.c         |    2 +-
 calendar/module/e-cal-shell-view.c                 |    2 +-
 calendar/module/e-cal-shell-view.h                 |    2 +-
 calendar/module/e-memo-shell-backend.c             |    2 +-
 calendar/module/e-memo-shell-backend.h             |    2 +-
 calendar/module/e-memo-shell-content.c             |    6 +-
 calendar/module/e-memo-shell-content.h             |    2 +-
 calendar/module/e-memo-shell-migrate.c             |    2 +-
 calendar/module/e-memo-shell-migrate.h             |    2 +-
 calendar/module/e-memo-shell-sidebar.c             |    2 +-
 calendar/module/e-memo-shell-sidebar.h             |    2 +-
 calendar/module/e-memo-shell-view-actions.c        |    2 +-
 calendar/module/e-memo-shell-view-actions.h        |    2 +-
 calendar/module/e-memo-shell-view-private.c        |    2 +-
 calendar/module/e-memo-shell-view-private.h        |    2 +-
 calendar/module/e-memo-shell-view.c                |    2 +-
 calendar/module/e-memo-shell-view.h                |    2 +-
 calendar/module/e-task-shell-backend.c             |    2 +-
 calendar/module/e-task-shell-backend.h             |    2 +-
 calendar/module/e-task-shell-content.c             |    6 +-
 calendar/module/e-task-shell-content.h             |    4 +-
 calendar/module/e-task-shell-migrate.c             |    2 +-
 calendar/module/e-task-shell-migrate.h             |    2 +-
 calendar/module/e-task-shell-sidebar.c             |    4 +-
 calendar/module/e-task-shell-sidebar.h             |    2 +-
 calendar/module/e-task-shell-view-actions.c        |    4 +-
 calendar/module/e-task-shell-view-actions.h        |    2 +-
 calendar/module/e-task-shell-view-private.c        |    2 +-
 calendar/module/e-task-shell-view-private.h        |    2 +-
 calendar/module/e-task-shell-view.c                |    2 +-
 calendar/module/e-task-shell-view.h                |    2 +-
 calendar/module/evolution-module-calendar.c        |    2 +-
 calendar/zones.h                                   |    2 +-
 composer/Makefile.am                               |    1 -
 composer/e-composer-actions.c                      |    2 +-
 composer/e-composer-actions.h                      |    2 +-
 composer/e-composer-autosave.c                     |    2 +-
 composer/e-composer-autosave.h                     |    2 +-
 composer/e-composer-common.h                       |    2 +-
 composer/e-composer-from-header.c                  |    2 +-
 composer/e-composer-from-header.h                  |    2 +-
 composer/e-composer-header-table.c                 |   17 +-
 composer/e-composer-header-table.h                 |    2 +-
 composer/e-composer-header.c                       |    8 +-
 composer/e-composer-header.h                       |    4 +-
 composer/e-composer-name-header.c                  |   18 +-
 composer/e-composer-name-header.h                  |    2 +-
 composer/e-composer-post-header.c                  |    2 +-
 composer/e-composer-post-header.h                  |    2 +-
 composer/e-composer-private.c                      |    9 +-
 composer/e-composer-private.h                      |    2 +-
 composer/e-composer-text-header.c                  |    4 +-
 composer/e-composer-text-header.h                  |    2 +-
 composer/e-msg-composer.c                          |   10 +-
 composer/e-msg-composer.h                          |    2 +-
 configure.ac                                       |   44 +-
 devel-docs/camel/Makefile.am                       |    2 +-
 e-util/e-account-utils.c                           |    2 +-
 e-util/e-account-utils.h                           |    2 +-
 e-util/e-bconf-map.c                               |    2 +-
 e-util/e-bconf-map.h                               |   16 +-
 e-util/e-binding.c                                 |    2 +-
 e-util/e-binding.h                                 |    2 +-
 e-util/e-bit-array.c                               |    2 +-
 e-util/e-bit-array.h                               |    5 +-
 e-util/e-categories-config.c                       |    2 +-
 e-util/e-categories-config.h                       |    2 +-
 e-util/e-config-listener.c                         |    2 +-
 e-util/e-config-listener.h                         |    2 +-
 e-util/e-config.c                                  |    2 +-
 e-util/e-config.h                                  |    2 +-
 e-util/e-cursor.c                                  |    2 +-
 e-util/e-cursor.h                                  |    2 +-
 e-util/e-dialog-utils.c                            |    2 +-
 e-util/e-dialog-utils.h                            |    2 +-
 e-util/e-dialog-widgets.c                          |    2 +-
 e-util/e-dialog-widgets.h                          |    2 +-
 e-util/e-error.c                                   |   62 +-
 e-util/e-error.h                                   |    2 +-
 e-util/e-event.c                                   |    2 +-
 e-util/e-event.h                                   |    2 +-
 e-util/e-folder-map.c                              |    4 +-
 e-util/e-folder-map.h                              |    5 +-
 e-util/e-fsutils.c                                 |    2 +-
 e-util/e-fsutils.h                                 |    2 +-
 e-util/e-html-utils.c                              |    4 +-
 e-util/e-html-utils.h                              |    2 +-
 e-util/e-icon-factory.c                            |    2 +-
 e-util/e-icon-factory.h                            |    2 +-
 e-util/e-import.c                                  |    2 +-
 e-util/e-import.h                                  |    2 +-
 e-util/e-logger.c                                  |    6 +-
 e-util/e-logger.h                                  |    2 +-
 e-util/e-marshal.list                              |    1 +
 e-util/e-menu.c                                    |    2 +-
 e-util/e-menu.h                                    |    2 +-
 e-util/e-mktemp.c                                  |    2 +-
 e-util/e-mktemp.h                                  |    2 +-
 e-util/e-module.c                                  |    2 +-
 e-util/e-module.h                                  |    2 +-
 e-util/e-non-intrusive-error-dialog.c              |    2 +-
 e-util/e-non-intrusive-error-dialog.h              |    8 +-
 e-util/e-pilot-map.c                               |    2 +-
 e-util/e-pilot-map.h                               |    2 +-
 e-util/e-pilot-util.c                              |    2 +-
 e-util/e-pilot-util.h                              |    2 +-
 e-util/e-plugin-ui.c                               |    4 +-
 e-util/e-plugin-ui.h                               |    2 +-
 e-util/e-plugin.c                                  |    4 +-
 e-util/e-plugin.h                                  |    6 +-
 e-util/e-popup.c                                   |    2 +-
 e-util/e-popup.h                                   |    2 +-
 e-util/e-print.c                                   |    2 +-
 e-util/e-print.h                                   |    2 +-
 e-util/e-profile-event.c                           |    2 +-
 e-util/e-profile-event.h                           |    2 +-
 e-util/e-request.c                                 |    2 +-
 e-util/e-request.h                                 |    2 +-
 e-util/e-signature-list.c                          |    2 +-
 e-util/e-signature-list.h                          |    2 +-
 e-util/e-signature-utils.c                         |    2 +-
 e-util/e-signature-utils.h                         |    2 +-
 e-util/e-signature.c                               |    2 +-
 e-util/e-signature.h                               |    2 +-
 e-util/e-sorter-array.c                            |    2 +-
 e-util/e-sorter-array.h                            |    2 +-
 e-util/e-sorter.c                                  |    2 +-
 e-util/e-sorter.h                                  |    2 +-
 e-util/e-text-event-processor-emacs-like.c         |    4 +-
 e-util/e-text-event-processor-emacs-like.h         |    2 +-
 e-util/e-text-event-processor-types.h              |    8 +-
 e-util/e-text-event-processor.c                    |    5 +-
 e-util/e-text-event-processor.h                    |    2 +-
 e-util/e-unicode.c                                 |    6 +-
 e-util/e-unicode.h                                 |    3 +-
 e-util/e-util-private.h                            |    2 +-
 e-util/e-util.c                                    |    8 +-
 e-util/e-util.h                                    |   12 +-
 e-util/e-win32-reloc.c                             |    2 +-
 e-util/e-xml-utils.c                               |    2 +-
 e-util/e-xml-utils.h                               |    4 +-
 e-util/gconf-bridge.c                              |   43 +-
 e-util/gconf-bridge.h                              |    6 +-
 em-format/em-format-quote.c                        |   50 +-
 em-format/em-format-quote.h                        |    2 +-
 em-format/em-format.c                              |   39 +-
 em-format/em-format.h                              |    4 +-
 em-format/em-stripsig-filter.c                     |    2 +-
 em-format/em-stripsig-filter.h                     |    2 +-
 filter/filter-code.c                               |    2 +-
 filter/filter-code.h                               |    2 +-
 filter/filter-colour.c                             |    2 +-
 filter/filter-colour.h                             |    2 +-
 filter/filter-datespec.c                           |    2 +-
 filter/filter-datespec.h                           |    2 +-
 filter/filter-element.c                            |    2 +-
 filter/filter-element.h                            |    2 +-
 filter/filter-file.c                               |    4 +-
 filter/filter-file.h                               |    2 +-
 filter/filter-input.c                              |    4 +-
 filter/filter-input.h                              |    2 +-
 filter/filter-int.c                                |    2 +-
 filter/filter-int.h                                |    2 +-
 filter/filter-option.c                             |    2 +-
 filter/filter-option.h                             |    2 +-
 filter/filter-part.c                               |    2 +-
 filter/filter-part.h                               |    2 +-
 filter/filter-rule.c                               |    6 +-
 filter/filter-rule.h                               |    2 +-
 filter/rule-context.c                              |    2 +-
 filter/rule-context.h                              |    2 +-
 filter/rule-editor.c                               |    4 +-
 filter/rule-editor.h                               |    2 +-
 help/el/el.po                                      | 5479 +++++++---
 help/el/figures/account_editor_a.png               |  Bin 0 -> 74930 bytes
 help/el/figures/attach_reminder_a.png              |  Bin 0 -> 32748 bytes
 help/el/figures/categories_a.png                   |  Bin 0 -> 67805 bytes
 help/el/figures/collap_head_a.png                  |  Bin 0 -> 18934 bytes
 help/el/figures/contacts_mainwindow_a.png          |  Bin 0 -> 80979 bytes
 help/el/figures/evo_Wcal_prop_a.png                |  Bin 0 -> 47371 bytes
 help/el/figures/evo_account_editor_a.png           |  Bin 0 -> 65027 bytes
 help/el/figures/evo_adv_search_a.png               |  Bin 0 -> 45662 bytes
 help/el/figures/evo_allday_a.png                   |  Bin 0 -> 145643 bytes
 help/el/figures/evo_attachreminder_plugin.png      |  Bin 0 -> 85023 bytes
 help/el/figures/evo_backup.png                     |  Bin 0 -> 30348 bytes
 help/el/figures/evo_backup_prgsbar.png             |  Bin 0 -> 49216 bytes
 help/el/figures/evo_backup_warning.png             |  Bin 0 -> 42326 bytes
 help/el/figures/evo_cal_a.png                      |  Bin 0 -> 126981 bytes
 help/el/figures/evo_cal_advsearch.png              |  Bin 0 -> 35989 bytes
 help/el/figures/evo_cal_callout_a.png              |  Bin 0 -> 106234 bytes
 help/el/figures/evo_cal_prop_a.png                 |  Bin 0 -> 25784 bytes
 help/el/figures/evo_calender_appointmnt.png        |  Bin 0 -> 56722 bytes
 help/el/figures/evo_contacteditor_a.png            |  Bin 0 -> 81465 bytes
 help/el/figures/evo_custom_header.png              |  Bin 0 -> 19553 bytes
 help/el/figures/evo_edit_rule_a.png                |  Bin 0 -> 47996 bytes
 help/el/figures/evo_edit_search.png                |  Bin 0 -> 33644 bytes
 help/el/figures/evo_exchng_mapi.png                |  Bin 0 -> 78289 bytes
 help/el/figures/evo_flag_follow_up_a.png           |  Bin 0 -> 40660 bytes
 help/el/figures/evo_gwreceive_a.png                |  Bin 0 -> 60909 bytes
 help/el/figures/evo_identity_a.png                 |  Bin 0 -> 60016 bytes
 help/el/figures/evo_imapreceive_a.png              |  Bin 0 -> 87180 bytes
 help/el/figures/evo_import.png                     |  Bin 0 -> 43519 bytes
 help/el/figures/evo_import_asst_a.png              |  Bin 0 -> 48093 bytes
 help/el/figures/evo_mail_a.png                     |  Bin 0 -> 169456 bytes
 help/el/figures/evo_mail_callout_a.png             |  Bin 0 -> 182740 bytes
 help/el/figures/evo_maildirreceive_a.png           |  Bin 0 -> 36563 bytes
 help/el/figures/evo_mboxreceive_a.png              |  Bin 0 -> 42352 bytes
 help/el/figures/evo_memo_a.png                     |  Bin 0 -> 40120 bytes
 help/el/figures/evo_mereceive_a.png                |  Bin 0 -> 83588 bytes
 help/el/figures/evo_message_filters_a.png          |  Bin 0 -> 37127 bytes
 help/el/figures/evo_mhreceive_a.png                |  Bin 0 -> 36894 bytes
 help/el/figures/evo_newmail.png                    |  Bin 0 -> 7738 bytes
 help/el/figures/evo_newmess_a.png                  |  Bin 0 -> 43220 bytes
 help/el/figures/evo_offline.png                    |  Bin 0 -> 31953 bytes
 help/el/figures/evo_popreceive_a.png               |  Bin 0 -> 87180 bytes
 help/el/figures/evo_receive_setup_a.png            |  Bin 0 -> 64065 bytes
 help/el/figures/evo_rule_a.png                     |  Bin 0 -> 75174 bytes
 help/el/figures/evo_select_folder.png              |  Bin 0 -> 36423 bytes
 help/el/figures/evo_send_setup_a.png               |  Bin 0 -> 77180 bytes
 help/el/figures/evo_timezone_a.png                 |  Bin 0 -> 198129 bytes
 help/el/figures/evo_usereceive_a.png               |  Bin 0 -> 42446 bytes
 help/el/figures/exchg-identity.png                 |  Bin 0 -> 60015 bytes
 help/el/figures/exchng-rec-mails.png               |  Bin 0 -> 65564 bytes
 help/el/figures/exchng-rec-options.png             |  Bin 0 -> 84818 bytes
 help/el/figures/filter-new-fig.png                 |  Bin 0 -> 46393 bytes
 help/el/figures/free_busy.png                      |  Bin 0 -> 50895 bytes
 help/el/figures/google_cal_view.png                |  Bin 0 -> 46299 bytes
 help/el/figures/mail-threaded.png                  |  Bin 0 -> 17136 bytes
 help/el/figures/quick_add_a.png                    |  Bin 0 -> 28292 bytes
 help/el/figures/ver_view_a.png                     |  Bin 0 -> 183841 bytes
 iconv-detect.c                                     |    2 +-
 mail/Makefile.am                                   |    1 -
 mail/e-attachment-handler-mail.c                   |    6 +-
 mail/e-attachment-handler-mail.h                   |    2 +-
 mail/e-mail-attachment-bar.c                       |    2 +-
 mail/e-mail-attachment-bar.h                       |    2 +-
 mail/e-mail-browser.c                              |    2 +-
 mail/e-mail-browser.h                              |    2 +-
 mail/e-mail-display.c                              |    2 +-
 mail/e-mail-display.h                              |    2 +-
 mail/e-mail-label-dialog.c                         |    2 +-
 mail/e-mail-label-dialog.h                         |    2 +-
 mail/e-mail-label-list-store.c                     |    2 +-
 mail/e-mail-label-list-store.h                     |    2 +-
 mail/e-mail-label-manager.c                        |    2 +-
 mail/e-mail-label-manager.h                        |    2 +-
 mail/e-mail-label-tree-view.c                      |    2 +-
 mail/e-mail-label-tree-view.h                      |    2 +-
 mail/e-mail-reader-utils.c                         |    2 +-
 mail/e-mail-reader-utils.h                         |    2 +-
 mail/e-mail-reader.c                               |    4 +-
 mail/e-mail-reader.h                               |    2 +-
 mail/e-mail-search-bar.c                           |    2 +-
 mail/e-mail-search-bar.h                           |    2 +-
 mail/e-mail-shell-backend.c                        |    4 +-
 mail/e-mail-shell-backend.h                        |    2 +-
 mail/e-mail-shell-content.c                        |    2 +-
 mail/e-mail-shell-content.h                        |    2 +-
 mail/e-mail-shell-migrate.c                        |  158 +-
 mail/e-mail-shell-migrate.h                        |    2 +-
 mail/e-mail-shell-sidebar.c                        |    2 +-
 mail/e-mail-shell-sidebar.h                        |    2 +-
 mail/e-mail-shell-view-actions.c                   |    2 +-
 mail/e-mail-shell-view-actions.h                   |    2 +-
 mail/e-mail-shell-view-private.c                   |    2 +-
 mail/e-mail-shell-view-private.h                   |    2 +-
 mail/e-mail-shell-view.c                           |    2 +-
 mail/e-mail-shell-view.h                           |    2 +-
 mail/e-searching-tokenizer.c                       |    7 +-
 mail/e-searching-tokenizer.h                       |    2 +-
 mail/em-account-editor.c                           |  208 +-
 mail/em-account-editor.h                           |    4 +-
 mail/em-account-prefs.c                            |    2 +-
 mail/em-account-prefs.h                            |    2 +-
 mail/em-composer-prefs.c                           |   18 +-
 mail/em-composer-prefs.h                           |    2 +-
 mail/em-composer-utils.c                           |   29 +-
 mail/em-composer-utils.h                           |    4 +-
 mail/em-config.c                                   |    2 +-
 mail/em-config.h                                   |    2 +-
 mail/em-event.c                                    |    2 +-
 mail/em-event.h                                    |    2 +-
 mail/em-filter-context.c                           |    2 +-
 mail/em-filter-context.h                           |    2 +-
 mail/em-filter-editor.c                            |    4 +-
 mail/em-filter-editor.h                            |    6 +-
 mail/em-filter-folder-element.c                    |    2 +-
 mail/em-filter-folder-element.h                    |    2 +-
 mail/em-filter-rule.c                              |    4 +-
 mail/em-filter-rule.h                              |    2 +-
 mail/em-filter-source-element.c                    |    2 +-
 mail/em-filter-source-element.h                    |    2 +-
 mail/em-folder-browser.c                           |   10 +-
 mail/em-folder-browser.h                           |    2 +-
 mail/em-folder-properties.c                        |   14 +-
 mail/em-folder-properties.h                        |    2 +-
 mail/em-folder-selection-button.c                  |    2 +-
 mail/em-folder-selection-button.h                  |    2 +-
 mail/em-folder-selection.c                         |    2 +-
 mail/em-folder-selection.h                         |    2 +-
 mail/em-folder-selector.c                          |    2 +-
 mail/em-folder-selector.h                          |    2 +-
 mail/em-folder-tree-model.c                        |    3 +-
 mail/em-folder-tree-model.h                        |    2 +-
 mail/em-folder-tree.c                              |   30 +-
 mail/em-folder-tree.h                              |    2 +-
 mail/em-folder-utils.c                             |    8 +-
 mail/em-folder-utils.h                             |    2 +-
 mail/em-folder-view.c                              |   17 +-
 mail/em-folder-view.h                              |    2 +-
 mail/em-format-hook.c                              |    2 +-
 mail/em-format-hook.h                              |    2 +-
 mail/em-format-html-display.c                      |   52 +-
 mail/em-format-html-display.h                      |    2 +-
 mail/em-format-html-print.c                        |    2 +-
 mail/em-format-html-print.h                        |    2 +-
 mail/em-format-html.c                              |  128 +-
 mail/em-format-html.h                              |    2 +-
 mail/em-html-stream.c                              |    2 +-
 mail/em-html-stream.h                              |    2 +-
 mail/em-icon-stream.c                              |    2 +-
 mail/em-icon-stream.h                              |    2 +-
 mail/em-inline-filter.c                            |    2 +-
 mail/em-inline-filter.h                            |    2 +-
 mail/em-junk-hook.c                                |    2 +-
 mail/em-junk-hook.h                                |    2 +-
 mail/em-mailer-prefs.c                             |   38 +-
 mail/em-mailer-prefs.h                             |    6 +-
 mail/em-menu.c                                     |    2 +-
 mail/em-menu.h                                     |    2 +-
 mail/em-network-prefs.c                            |   89 +-
 mail/em-network-prefs.h                            |    8 +-
 mail/em-popup.c                                    |    2 +-
 mail/em-popup.h                                    |    2 +-
 mail/em-search-context.c                           |    2 +-
 mail/em-search-context.h                           |    2 +-
 mail/em-subscribe-editor.c                         |   13 +-
 mail/em-subscribe-editor.h                         |    2 +-
 mail/em-sync-stream.c                              |    2 +-
 mail/em-sync-stream.h                              |    2 +-
 mail/em-utils.c                                    |   20 +-
 mail/em-utils.h                                    |    2 +-
 mail/em-vfolder-context.c                          |    2 +-
 mail/em-vfolder-context.h                          |    2 +-
 mail/em-vfolder-editor.c                           |    2 +-
 mail/em-vfolder-editor.h                           |    2 +-
 mail/em-vfolder-rule.c                             |    8 +-
 mail/em-vfolder-rule.h                             |    2 +-
 mail/evolution-module-mail.c                       |    2 +-
 mail/importers/elm-importer.c                      |    2 +-
 mail/importers/evolution-mbox-importer.c           |    2 +-
 mail/importers/mail-importer.c                     |    2 +-
 mail/importers/mail-importer.h                     |    4 +-
 mail/importers/pine-importer.c                     |    2 +-
 mail/mail-autofilter.c                             |    2 +-
 mail/mail-autofilter.h                             |    2 +-
 mail/mail-component.c                              |    5 +-
 mail/mail-component.h                              |    2 +-
 mail/mail-config.c                                 |   30 +-
 mail/mail-config.h                                 |    2 +-
 mail/mail-dialogs.glade                            |   56 +-
 mail/mail-folder-cache.c                           |    5 +-
 mail/mail-folder-cache.h                           |    2 +-
 mail/mail-mt.c                                     |    2 +-
 mail/mail-mt.h                                     |    2 +-
 mail/mail-ops.c                                    |   24 +-
 mail/mail-ops.h                                    |    6 +-
 mail/mail-send-recv.c                              |   14 +-
 mail/mail-send-recv.h                              |    2 +-
 mail/mail-session.c                                |    2 +-
 mail/mail-session.h                                |    2 +-
 mail/mail-tools.c                                  |    2 +-
 mail/mail-tools.h                                  |    2 +-
 mail/mail-vfolder.c                                |    5 +-
 mail/mail-vfolder.h                                |    2 +-
 mail/message-list.c                                |   46 +-
 mail/message-list.h                                |    2 +-
 mail/message-tag-editor.c                          |    2 +-
 mail/message-tag-editor.h                          |    2 +-
 mail/message-tag-followup.c                        |    4 +-
 mail/message-tag-followup.h                        |    2 +-
 plugins/addressbook-file/addressbook-file.c        |    2 +-
 plugins/attachment-reminder/attachment-reminder.c  |    2 +-
 plugins/audio-inline/audio-inline.c                |    4 +-
 plugins/backup-restore/backup-restore.c            |    6 +-
 plugins/backup-restore/backup.c                    |   39 +-
 plugins/bbdb/bbdb.c                                |    5 +-
 plugins/bbdb/bbdb.h                                |    2 +-
 plugins/bbdb/gaimbuddies.c                         |   10 +-
 plugins/bbdb/test-evobuddy.c                       |    2 +-
 plugins/bogo-junk-plugin/bf-junk-filter.c          |   30 +-
 plugins/caldav/caldav-source.c                     |   57 +-
 plugins/calendar-file/calendar-file.c              |    2 +-
 plugins/copy-tool/copy-tool.c                      |    2 +-
 plugins/default-mailer/default-mailer.c            |    2 +-
 plugins/default-source/default-source.c            |    2 +-
 plugins/email-custom-header/Makefile.am            |    1 -
 plugins/email-custom-header/email-custom-header.c  |   92 +-
 plugins/email-custom-header/email-custom-header.h  |    4 +-
 .../exchange-operations/exchange-account-setup.c   |   46 +-
 plugins/exchange-operations/exchange-calendar.c    |    2 +-
 .../exchange-operations/exchange-change-password.c |    2 +-
 .../exchange-operations/exchange-change-password.h |    2 +-
 .../exchange-operations/exchange-config-listener.c |    8 +-
 .../exchange-operations/exchange-config-listener.h |    2 +-
 plugins/exchange-operations/exchange-contacts.c    |    4 +-
 .../exchange-operations/exchange-delegates-user.c  |   15 +-
 .../exchange-operations/exchange-delegates-user.h  |    2 +-
 plugins/exchange-operations/exchange-delegates.c   |    2 +-
 plugins/exchange-operations/exchange-delegates.h   |    2 +-
 .../exchange-folder-permission.c                   |    4 +-
 .../exchange-folder-size-display.c                 |    2 +-
 .../exchange-folder-size-display.h                 |    2 +-
 .../exchange-folder-subscription.c                 |    8 +-
 .../exchange-folder-subscription.h                 |    4 +-
 plugins/exchange-operations/exchange-folder.c      |   23 +-
 .../exchange-mail-send-options.c                   |    2 +-
 plugins/exchange-operations/exchange-operations.c  |   40 +-
 plugins/exchange-operations/exchange-operations.h  |    2 +-
 .../exchange-permissions-dialog.c                  |    2 +-
 .../exchange-permissions-dialog.h                  |    2 +-
 .../exchange-operations/exchange-send-options.c    |    2 +-
 .../exchange-operations/exchange-send-options.h    |    2 +-
 plugins/exchange-operations/exchange-user-dialog.c |    2 +-
 plugins/exchange-operations/exchange-user-dialog.h |    2 +-
 plugins/face/Makefile.am                           |    1 -
 plugins/face/face.c                                |    2 +-
 plugins/folder-unsubscribe/folder-unsubscribe.c    |    2 +-
 .../google-account-setup/google-contacts-source.c  |    2 +-
 .../google-account-setup/google-contacts-source.h  |    2 +-
 plugins/google-account-setup/google-source.c       |    4 +-
 .../groupwise-account-setup/camel-gw-listener.c    |   18 +-
 .../groupwise-account-setup/camel-gw-listener.h    |    2 +-
 .../groupwise-account-setup.c                      |    6 +-
 plugins/groupwise-features/Makefile.am             |    1 -
 plugins/groupwise-features/addressbook-groupwise.c |    2 +-
 plugins/groupwise-features/install-shared.c        |    2 +-
 plugins/groupwise-features/junk-mail-settings.c    |    4 +-
 plugins/groupwise-features/junk-settings.c         |   19 +-
 plugins/groupwise-features/junk-settings.h         |    2 +-
 plugins/groupwise-features/mail-retract.c          |   12 +-
 plugins/groupwise-features/mail-send-options.c     |    2 +-
 plugins/groupwise-features/mail-send-options.h     |    2 +-
 .../org-gnome-process-meeting.error.xml            |   44 +
 plugins/groupwise-features/process-meeting.c       |   38 +-
 plugins/groupwise-features/proxy-login.c           |   10 +-
 plugins/groupwise-features/proxy-login.h           |    2 +-
 plugins/groupwise-features/proxy.c                 |    5 +-
 plugins/groupwise-features/proxy.h                 |    3 +-
 plugins/groupwise-features/send-options.c          |    9 +-
 plugins/groupwise-features/share-folder-common.c   |    6 +-
 plugins/groupwise-features/share-folder.c          |   16 +-
 plugins/groupwise-features/share-folder.h          |    6 +-
 plugins/groupwise-features/status-track.c          |    4 +-
 plugins/hula-account-setup/camel-hula-listener.c   |    2 +-
 plugins/hula-account-setup/camel-hula-listener.h   |    2 +-
 plugins/hula-account-setup/hula-account-setup.c    |    2 +-
 plugins/imap-features/Makefile.am                  |    1 -
 plugins/imap-features/imap-headers.c               |    4 +-
 plugins/ipod-sync/evolution-ipod-sync.c            |    2 +-
 plugins/ipod-sync/evolution-ipod-sync.h            |    2 +-
 plugins/ipod-sync/format-handler.h                 |    2 +-
 plugins/ipod-sync/ical-format.c                    |    4 +-
 plugins/ipod-sync/ipod-sync.c                      |    4 +-
 plugins/ipod-sync/ipod.c                           |    2 +-
 plugins/ipod-sync/sync.c                           |    4 +-
 plugins/itip-formatter/itip-formatter.c            |   27 +-
 plugins/itip-formatter/itip-view.c                 |   29 +-
 plugins/itip-formatter/itip-view.h                 |    2 +-
 plugins/mail-notification/mail-notification.c      |   24 +-
 plugins/mail-to-task/mail-to-task.c                |    6 +-
 .../mailing-list-actions/mailing-list-actions.c    |    2 +-
 plugins/mark-all-read/Makefile.am                  |    1 -
 plugins/mark-all-read/mark-all-read.c              |    2 +-
 plugins/mono/mono-plugin.c                         |    8 +-
 plugins/mono/mono-plugin.h                         |    2 +-
 plugins/plugin-manager/plugin-manager.c            |    6 +-
 plugins/prefer-plain/prefer-plain.c                |    2 +-
 plugins/profiler/profiler.c                        |    2 +-
 plugins/pst-import/pst-importer.c                  |  240 +-
 plugins/publish-calendar/publish-calendar.c        |   14 +-
 plugins/publish-calendar/publish-format-fb.c       |    2 +-
 plugins/publish-calendar/publish-format-fb.h       |    2 +-
 plugins/publish-calendar/publish-format-ical.c     |    2 +-
 plugins/publish-calendar/publish-format-ical.h     |    2 +-
 plugins/publish-calendar/publish-location.c        |    2 +-
 plugins/publish-calendar/publish-location.h        |    2 +-
 plugins/publish-calendar/url-editor-dialog.c       |    5 +-
 plugins/publish-calendar/url-editor-dialog.h       |    2 +-
 plugins/python/python-plugin-loader.c              |   12 +-
 plugins/python/python-plugin-loader.h              |    2 +-
 plugins/sa-junk-plugin/em-junk-filter.c            |   68 +-
 plugins/save-calendar/csv-format.c                 |    4 +-
 plugins/save-calendar/format-handler.h             |    2 +-
 plugins/save-calendar/ical-format.c                |    2 +-
 plugins/save-calendar/rdf-format.c                 |    2 +-
 plugins/save-calendar/save-calendar.c              |    2 +-
 plugins/startup-wizard/startup-wizard.c            |    4 +-
 plugins/subject-thread/subject-thread.c            |    2 +-
 plugins/templates/templates.c                      |   66 +-
 plugins/tnef-attachments/tnef-plugin.c             |    4 +-
 plugins/vcard-inline/vcard-inline.c                |    2 +-
 .../webdav-account-setup/webdav-contacts-source.c  |    2 +-
 po/es.po                                           | 2026 ++--
 po/he.po                                           |12295 +++++++++-----------
 po/ta.po                                           | 8361 ++++++--------
 po/th.po                                           |   14 +-
 shell/e-config-upgrade.c                           |    2 +-
 shell/e-config-upgrade.h                           |    2 +-
 shell/e-shell-backend.c                            |    2 +-
 shell/e-shell-backend.h                            |    2 +-
 shell/e-shell-common.h                             |    2 +-
 shell/e-shell-content.c                            |    4 +-
 shell/e-shell-content.h                            |    2 +-
 shell/e-shell-importer.c                           |    6 +-
 shell/e-shell-importer.h                           |    2 +-
 shell/e-shell-migrate.c                            |    2 +-
 shell/e-shell-migrate.h                            |    2 +-
 shell/e-shell-nm.c                                 |    2 +-
 shell/e-shell-settings.c                           |    2 +-
 shell/e-shell-settings.h                           |    2 +-
 shell/e-shell-sidebar.c                            |    4 +-
 shell/e-shell-sidebar.h                            |    2 +-
 shell/e-shell-switcher.c                           |    2 +-
 shell/e-shell-switcher.h                           |    2 +-
 shell/e-shell-taskbar.c                            |    2 +-
 shell/e-shell-taskbar.h                            |    2 +-
 shell/e-shell-view.c                               |    2 +-
 shell/e-shell-view.h                               |    2 +-
 shell/e-shell-window-actions.c                     |    4 +-
 shell/e-shell-window-actions.h                     |    2 +-
 shell/e-shell-window-private.c                     |    2 +-
 shell/e-shell-window-private.h                     |    2 +-
 shell/e-shell-window.c                             |    2 +-
 shell/e-shell-window.h                             |    2 +-
 shell/e-shell.c                                    |    2 +-
 shell/e-shell.h                                    |    2 +-
 shell/es-event.c                                   |    2 +-
 shell/es-event.h                                   |    2 +-
 shell/main.c                                       |    7 +-
 shell/test/e-test-shell-backend.c                  |    2 +-
 shell/test/e-test-shell-backend.h                  |    2 +-
 shell/test/e-test-shell-view.c                     |    2 +-
 shell/test/e-test-shell-view.h                     |    2 +-
 shell/test/evolution-module-test.c                 |    2 +-
 smime/gui/ca-trust-dialog.c                        |    2 +-
 smime/gui/ca-trust-dialog.h                        |    2 +-
 smime/gui/cert-trust-dialog.c                      |    2 +-
 smime/gui/cert-trust-dialog.h                      |    2 +-
 smime/gui/certificate-manager.c                    |    2 +-
 smime/gui/certificate-manager.h                    |    2 +-
 smime/gui/certificate-viewer.c                     |    2 +-
 smime/gui/certificate-viewer.h                     |    2 +-
 smime/gui/component.c                              |    2 +-
 smime/gui/component.h                              |    2 +-
 smime/gui/e-cert-selector.c                        |    2 +-
 smime/gui/e-cert-selector.h                        |    2 +-
 smime/lib/e-asn1-object.h                          |    2 +-
 smime/lib/e-cert-db.c                              |    4 +-
 smime/lib/e-cert-db.h                              |    2 +-
 smime/lib/e-cert-trust.h                           |    2 +-
 smime/lib/e-cert.h                                 |    2 +-
 smime/lib/e-pkcs12.h                               |    2 +-
 smime/tests/import-cert.c                          |    2 +-
 tools/killev.c                                     |    2 +-
 widgets/e-timezone-dialog/e-timezone-dialog.c      |   27 +-
 widgets/e-timezone-dialog/e-timezone-dialog.h      |    2 +-
 widgets/menus/gal-define-views-dialog.c            |    6 +-
 widgets/menus/gal-define-views-dialog.h            |    2 +-
 widgets/menus/gal-define-views-model.c             |    2 +-
 widgets/menus/gal-define-views-model.h             |    2 +-
 widgets/menus/gal-view-collection.c                |    2 +-
 widgets/menus/gal-view-collection.h                |    2 +-
 widgets/menus/gal-view-etable.c                    |    2 +-
 widgets/menus/gal-view-etable.h                    |    2 +-
 widgets/menus/gal-view-factory-etable.c            |    2 +-
 widgets/menus/gal-view-factory-etable.h            |    2 +-
 widgets/menus/gal-view-factory.c                   |    2 +-
 widgets/menus/gal-view-factory.h                   |    2 +-
 widgets/menus/gal-view-instance-save-as-dialog.c   |    2 +-
 widgets/menus/gal-view-instance-save-as-dialog.h   |    2 +-
 widgets/menus/gal-view-instance.c                  |    2 +-
 widgets/menus/gal-view-instance.h                  |    2 +-
 widgets/menus/gal-view-new-dialog.c                |    4 +-
 widgets/menus/gal-view-new-dialog.h                |    2 +-
 widgets/menus/gal-view.c                           |    2 +-
 widgets/menus/gal-view.h                           |    2 +-
 widgets/misc/a11y/ea-calendar-cell.c               |    2 +-
 widgets/misc/a11y/ea-calendar-cell.h               |    2 +-
 widgets/misc/a11y/ea-calendar-item.c               |    4 +-
 widgets/misc/a11y/ea-calendar-item.h               |    2 +-
 widgets/misc/a11y/ea-widgets.c                     |    2 +-
 widgets/misc/a11y/ea-widgets.h                     |    2 +-
 widgets/misc/e-account-combo-box.c                 |    2 +-
 widgets/misc/e-account-combo-box.h                 |    2 +-
 widgets/misc/e-account-manager.c                   |    2 +-
 widgets/misc/e-account-manager.h                   |    2 +-
 widgets/misc/e-account-tree-view.c                 |    2 +-
 widgets/misc/e-account-tree-view.h                 |    2 +-
 widgets/misc/e-activity-proxy.c                    |    2 +-
 widgets/misc/e-activity-proxy.h                    |    2 +-
 widgets/misc/e-activity.c                          |    4 +-
 widgets/misc/e-activity.h                          |    2 +-
 widgets/misc/e-alert-activity.c                    |    2 +-
 widgets/misc/e-alert-activity.h                    |    2 +-
 widgets/misc/e-attachment-button.c                 |    2 +-
 widgets/misc/e-attachment-button.h                 |    2 +-
 widgets/misc/e-attachment-dialog.c                 |    2 +-
 widgets/misc/e-attachment-dialog.h                 |    2 +-
 widgets/misc/e-attachment-handler-image.c          |    2 +-
 widgets/misc/e-attachment-handler-image.h          |    2 +-
 widgets/misc/e-attachment-handler.c                |    2 +-
 widgets/misc/e-attachment-handler.h                |    2 +-
 widgets/misc/e-attachment-icon-view.c              |    2 +-
 widgets/misc/e-attachment-icon-view.h              |    2 +-
 widgets/misc/e-attachment-paned.c                  |    2 +-
 widgets/misc/e-attachment-paned.h                  |    2 +-
 widgets/misc/e-attachment-store.c                  |    2 +-
 widgets/misc/e-attachment-store.h                  |    2 +-
 widgets/misc/e-attachment-tree-view.c              |    2 +-
 widgets/misc/e-attachment-tree-view.h              |    2 +-
 widgets/misc/e-attachment-view.c                   |    8 +-
 widgets/misc/e-attachment-view.h                   |    2 +-
 widgets/misc/e-attachment.c                        |    2 +-
 widgets/misc/e-attachment.h                        |    2 +-
 widgets/misc/e-calendar-item.c                     |    8 +-
 widgets/misc/e-calendar-item.h                     |   11 +-
 widgets/misc/e-calendar.c                          |    2 +-
 widgets/misc/e-calendar.h                          |    2 +-
 widgets/misc/e-canvas-background.c                 |    2 +-
 widgets/misc/e-canvas-background.h                 |    2 +-
 widgets/misc/e-canvas-utils.c                      |    2 +-
 widgets/misc/e-canvas-utils.h                      |    2 +-
 widgets/misc/e-canvas-vbox.c                       |    4 +-
 widgets/misc/e-canvas-vbox.h                       |    2 +-
 widgets/misc/e-canvas.c                            |    4 +-
 widgets/misc/e-canvas.h                            |    2 +-
 widgets/misc/e-cell-renderer-combo.c               |    2 +-
 widgets/misc/e-cell-renderer-combo.h               |    2 +-
 widgets/misc/e-charset-picker.c                    |   10 +-
 widgets/misc/e-charset-picker.h                    |    2 +-
 widgets/misc/e-colors.c                            |    2 +-
 widgets/misc/e-colors.h                            |    2 +-
 widgets/misc/e-combo-cell-editable.c               |    2 +-
 widgets/misc/e-combo-cell-editable.h               |    2 +-
 widgets/misc/e-cursors.c                           |   10 +-
 widgets/misc/e-cursors.h                           |    2 +-
 widgets/misc/e-dateedit.c                          |    6 +-
 widgets/misc/e-file-activity.c                     |    2 +-
 widgets/misc/e-file-activity.h                     |    2 +-
 widgets/misc/e-filter-bar.c                        |    9 +-
 widgets/misc/e-filter-bar.h                        |   14 +-
 widgets/misc/e-gui-utils.c                         |    2 +-
 widgets/misc/e-gui-utils.h                         |    2 +-
 widgets/misc/e-icon-entry.h                        |    2 +-
 widgets/misc/e-image-chooser.c                     |    4 +-
 widgets/misc/e-image-chooser.h                     |    2 +-
 widgets/misc/e-map.c                               |    2 +-
 widgets/misc/e-map.h                               |    2 +-
 widgets/misc/e-menu-tool-button.c                  |    2 +-
 widgets/misc/e-menu-tool-button.h                  |    2 +-
 widgets/misc/e-online-button.c                     |    2 +-
 widgets/misc/e-online-button.h                     |    2 +-
 widgets/misc/e-pilot-settings.c                    |    2 +-
 widgets/misc/e-pilot-settings.h                    |    2 +-
 widgets/misc/e-popup-action.c                      |    2 +-
 widgets/misc/e-popup-action.h                      |    2 +-
 widgets/misc/e-popup-menu.c                        |    2 +-
 widgets/misc/e-popup-menu.h                        |   70 +-
 widgets/misc/e-preferences-window.c                |    2 +-
 widgets/misc/e-preferences-window.h                |    2 +-
 widgets/misc/e-printable.c                         |    2 +-
 widgets/misc/e-printable.h                         |    2 +-
 widgets/misc/e-search-bar.c                        |   23 +-
 widgets/misc/e-selection-model-array.c             |    2 +-
 widgets/misc/e-selection-model-array.h             |    2 +-
 widgets/misc/e-selection-model-simple.c            |    6 +-
 widgets/misc/e-selection-model-simple.h            |    2 +-
 widgets/misc/e-selection-model.c                   |    2 +-
 widgets/misc/e-selection-model.h                   |    2 +-
 widgets/misc/e-send-options.c                      |    2 +-
 widgets/misc/e-send-options.h                      |    4 +-
 widgets/misc/e-signature-combo-box.c               |    2 +-
 widgets/misc/e-signature-combo-box.h               |    2 +-
 widgets/misc/e-signature-editor.c                  |    2 +-
 widgets/misc/e-signature-editor.h                  |    2 +-
 widgets/misc/e-signature-manager.c                 |    2 +-
 widgets/misc/e-signature-manager.h                 |    2 +-
 widgets/misc/e-signature-preview.c                 |    2 +-
 widgets/misc/e-signature-preview.h                 |    2 +-
 widgets/misc/e-signature-script-dialog.c           |    2 +-
 widgets/misc/e-signature-script-dialog.h           |    2 +-
 widgets/misc/e-signature-tree-view.c               |    2 +-
 widgets/misc/e-signature-tree-view.h               |    2 +-
 widgets/misc/e-spinner.c                           |    6 +-
 widgets/misc/e-timeout-activity.c                  |    2 +-
 widgets/misc/e-timeout-activity.h                  |    2 +-
 widgets/misc/e-url-entry.c                         |    2 +-
 widgets/misc/e-url-entry.h                         |    2 +-
 widgets/misc/pixmaps/cursor_cross.xpm              |    2 +-
 widgets/misc/pixmaps/cursor_hand_closed.xpm        |    2 +-
 widgets/misc/pixmaps/cursor_hand_open.xpm          |    2 +-
 widgets/misc/pixmaps/cursor_zoom_in.xpm            |    2 +-
 widgets/misc/pixmaps/cursor_zoom_out.xpm           |    2 +-
 widgets/misc/test-calendar.c                       |    4 +-
 widgets/misc/test-dateedit.c                       |   20 +-
 widgets/misc/test-preferences-window.c             |    2 +-
 widgets/table/a11y/gal-a11y-e-cell-popup.c         |    2 +-
 widgets/table/a11y/gal-a11y-e-cell-popup.h         |    2 +-
 widgets/table/a11y/gal-a11y-e-cell-registry.c      |    2 +-
 widgets/table/a11y/gal-a11y-e-cell-registry.h      |    2 +-
 widgets/table/a11y/gal-a11y-e-cell-text.c          |    2 +-
 widgets/table/a11y/gal-a11y-e-cell-text.h          |    2 +-
 widgets/table/a11y/gal-a11y-e-cell-toggle.c        |    2 +-
 widgets/table/a11y/gal-a11y-e-cell-toggle.h        |    2 +-
 widgets/table/a11y/gal-a11y-e-cell-tree.c          |    2 +-
 widgets/table/a11y/gal-a11y-e-cell-tree.h          |    2 +-
 widgets/table/a11y/gal-a11y-e-cell-vbox.c          |    2 +-
 widgets/table/a11y/gal-a11y-e-cell-vbox.h          |    2 +-
 widgets/table/a11y/gal-a11y-e-cell.c               |    2 +-
 widgets/table/a11y/gal-a11y-e-cell.h               |    2 +-
 .../a11y/gal-a11y-e-table-click-to-add-factory.c   |    2 +-
 .../a11y/gal-a11y-e-table-click-to-add-factory.h   |    2 +-
 widgets/table/a11y/gal-a11y-e-table-click-to-add.c |    2 +-
 widgets/table/a11y/gal-a11y-e-table-click-to-add.h |    2 +-
 .../table/a11y/gal-a11y-e-table-column-header.c    |    2 +-
 .../table/a11y/gal-a11y-e-table-column-header.h    |    2 +-
 widgets/table/a11y/gal-a11y-e-table-factory.c      |    2 +-
 widgets/table/a11y/gal-a11y-e-table-factory.h      |    2 +-
 widgets/table/a11y/gal-a11y-e-table-item-factory.c |    2 +-
 widgets/table/a11y/gal-a11y-e-table-item-factory.h |    2 +-
 widgets/table/a11y/gal-a11y-e-table-item.c         |    2 +-
 widgets/table/a11y/gal-a11y-e-table-item.h         |    2 +-
 widgets/table/a11y/gal-a11y-e-table.c              |    2 +-
 widgets/table/a11y/gal-a11y-e-table.h              |    2 +-
 widgets/table/a11y/gal-a11y-e-tree-factory.c       |    2 +-
 widgets/table/a11y/gal-a11y-e-tree-factory.h       |    2 +-
 widgets/table/a11y/gal-a11y-e-tree.c               |    2 +-
 widgets/table/a11y/gal-a11y-e-tree.h               |    2 +-
 widgets/table/add-col.xpm                          |    2 +-
 widgets/table/e-cell-checkbox.c                    |    2 +-
 widgets/table/e-cell-checkbox.h                    |    2 +-
 widgets/table/e-cell-combo.c                       |    4 +-
 widgets/table/e-cell-combo.h                       |    2 +-
 widgets/table/e-cell-date-edit.c                   |    6 +-
 widgets/table/e-cell-date-edit.h                   |    2 +-
 widgets/table/e-cell-date.c                        |    4 +-
 widgets/table/e-cell-date.h                        |    2 +-
 widgets/table/e-cell-hbox.c                        |    2 +-
 widgets/table/e-cell-hbox.h                        |    2 +-
 widgets/table/e-cell-number.c                      |    2 +-
 widgets/table/e-cell-number.h                      |    2 +-
 widgets/table/e-cell-percent.c                     |    2 +-
 widgets/table/e-cell-percent.h                     |    2 +-
 widgets/table/e-cell-pixbuf.c                      |    6 +-
 widgets/table/e-cell-pixbuf.h                      |    2 +-
 widgets/table/e-cell-popup.c                       |    4 +-
 widgets/table/e-cell-popup.h                       |    6 +-
 widgets/table/e-cell-size.c                        |    2 +-
 widgets/table/e-cell-size.h                        |    2 +-
 widgets/table/e-cell-text.c                        |    8 +-
 widgets/table/e-cell-text.h                        |    2 +-
 widgets/table/e-cell-toggle.c                      |   10 +-
 widgets/table/e-cell-toggle.h                      |    2 +-
 widgets/table/e-cell-vbox.c                        |    2 +-
 widgets/table/e-cell-vbox.h                        |    2 +-
 widgets/table/e-cell.c                             |   10 +-
 widgets/table/e-cell.h                             |    2 +-
 widgets/table/e-table-click-to-add.c               |    2 +-
 widgets/table/e-table-click-to-add.h               |    2 +-
 widgets/table/e-table-col-dnd.h                    |    2 +-
 widgets/table/e-table-col.c                        |    2 +-
 widgets/table/e-table-col.h                        |    2 +-
 widgets/table/e-table-column-specification.c       |    2 +-
 widgets/table/e-table-column-specification.h       |    2 +-
 widgets/table/e-table-column.c                     |    2 +-
 widgets/table/e-table-config-field.c               |    2 +-
 widgets/table/e-table-config-field.h               |    2 +-
 widgets/table/e-table-config.c                     |    7 +-
 widgets/table/e-table-config.h                     |    2 +-
 widgets/table/e-table-defines.h                    |    2 +-
 widgets/table/e-table-example-2.c                  |    2 +-
 widgets/table/e-table-extras.c                     |   18 +-
 widgets/table/e-table-extras.h                     |   18 +-
 widgets/table/e-table-field-chooser-dialog.c       |    4 +-
 widgets/table/e-table-field-chooser-dialog.h       |    2 +-
 widgets/table/e-table-field-chooser-item.c         |    4 +-
 widgets/table/e-table-field-chooser-item.h         |    2 +-
 widgets/table/e-table-field-chooser.c              |    4 +-
 widgets/table/e-table-field-chooser.h              |    2 +-
 widgets/table/e-table-group-container.c            |    2 +-
 widgets/table/e-table-group-container.h            |    2 +-
 widgets/table/e-table-group-leaf.c                 |    2 +-
 widgets/table/e-table-group-leaf.h                 |    2 +-
 widgets/table/e-table-group.c                      |    2 +-
 widgets/table/e-table-group.h                      |    2 +-
 widgets/table/e-table-header-item.c                |   30 +-
 widgets/table/e-table-header-item.h                |    2 +-
 widgets/table/e-table-header-utils.c               |    2 +-
 widgets/table/e-table-header-utils.h               |    2 +-
 widgets/table/e-table-header.c                     |    2 +-
 widgets/table/e-table-header.h                     |    2 +-
 widgets/table/e-table-item.c                       |   26 +-
 widgets/table/e-table-item.h                       |    2 +-
 widgets/table/e-table-memory-callbacks.c           |    2 +-
 widgets/table/e-table-memory-callbacks.h           |    2 +-
 widgets/table/e-table-memory-store.c               |    2 +-
 widgets/table/e-table-memory-store.h               |    2 +-
 widgets/table/e-table-memory.c                     |    2 +-
 widgets/table/e-table-memory.h                     |    2 +-
 widgets/table/e-table-model.c                      |    6 +-
 widgets/table/e-table-model.h                      |    4 +-
 widgets/table/e-table-one.c                        |    2 +-
 widgets/table/e-table-one.h                        |    2 +-
 widgets/table/e-table-scrolled.c                   |    2 +-
 widgets/table/e-table-scrolled.h                   |    2 +-
 widgets/table/e-table-search.c                     |    2 +-
 widgets/table/e-table-search.h                     |    2 +-
 widgets/table/e-table-selection-model.c            |    8 +-
 widgets/table/e-table-selection-model.h            |    4 +-
 widgets/table/e-table-simple.c                     |    2 +-
 widgets/table/e-table-simple.h                     |    2 +-
 widgets/table/e-table-sort-info.c                  |    2 +-
 widgets/table/e-table-sort-info.h                  |    2 +-
 widgets/table/e-table-sorted-variable.c            |    2 +-
 widgets/table/e-table-sorted-variable.h            |    2 +-
 widgets/table/e-table-sorted.c                     |    2 +-
 widgets/table/e-table-sorted.h                     |    2 +-
 widgets/table/e-table-sorter.c                     |    2 +-
 widgets/table/e-table-sorter.h                     |    2 +-
 widgets/table/e-table-sorting-utils.c              |    2 +-
 widgets/table/e-table-sorting-utils.h              |    2 +-
 widgets/table/e-table-specification.c              |    4 +-
 widgets/table/e-table-specification.h              |    2 +-
 widgets/table/e-table-state.c                      |    2 +-
 widgets/table/e-table-state.h                      |    2 +-
 widgets/table/e-table-subset-variable.c            |    2 +-
 widgets/table/e-table-subset-variable.h            |    2 +-
 widgets/table/e-table-subset.c                     |    2 +-
 widgets/table/e-table-subset.h                     |    2 +-
 widgets/table/e-table-tooltip.h                    |    2 +-
 widgets/table/e-table-utils.c                      |    2 +-
 widgets/table/e-table-utils.h                      |    2 +-
 widgets/table/e-table-without.c                    |    2 +-
 widgets/table/e-table-without.h                    |    2 +-
 widgets/table/e-table.c                            |    2 +-
 widgets/table/e-table.h                            |    2 +-
 widgets/table/e-tree-memory-callbacks.c            |    2 +-
 widgets/table/e-tree-memory-callbacks.h            |    2 +-
 widgets/table/e-tree-memory.c                      |    2 +-
 widgets/table/e-tree-memory.h                      |    2 +-
 widgets/table/e-tree-model.c                       |    2 +-
 widgets/table/e-tree-model.h                       |    2 +-
 widgets/table/e-tree-scrolled.c                    |    2 +-
 widgets/table/e-tree-scrolled.h                    |    2 +-
 widgets/table/e-tree-selection-model.c             |    2 +-
 widgets/table/e-tree-selection-model.h             |    2 +-
 widgets/table/e-tree-simple.c                      |    2 +-
 widgets/table/e-tree-simple.h                      |    2 +-
 widgets/table/e-tree-sorted-variable.c             |    2 +-
 widgets/table/e-tree-sorted-variable.h             |    2 +-
 widgets/table/e-tree-sorted.c                      |    2 +-
 widgets/table/e-tree-sorted.h                      |    2 +-
 widgets/table/e-tree-table-adapter.c               |    3 +-
 widgets/table/e-tree-table-adapter.h               |    2 +-
 widgets/table/e-tree.c                             |    4 +-
 widgets/table/e-tree.h                             |    2 +-
 widgets/table/remove-col.xpm                       |    2 +-
 widgets/table/tree-expanded.xpm                    |    2 +-
 widgets/table/tree-unexpanded.xpm                  |    2 +-
 widgets/text/a11y/gal-a11y-e-text-factory.c        |    2 +-
 widgets/text/a11y/gal-a11y-e-text-factory.h        |    2 +-
 widgets/text/a11y/gal-a11y-e-text.c                |    2 +-
 widgets/text/a11y/gal-a11y-e-text.h                |    2 +-
 widgets/text/e-reflow-model.c                      |    2 +-
 widgets/text/e-reflow-model.h                      |    2 +-
 widgets/text/e-reflow.c                            |    2 +-
 widgets/text/e-reflow.h                            |    2 +-
 widgets/text/e-text-model-repos.c                  |    2 +-
 widgets/text/e-text-model-repos.h                  |    2 +-
 widgets/text/e-text-model.c                        |    4 +-
 widgets/text/e-text-model.h                        |    2 +-
 widgets/text/e-text.c                              |   20 +-
 widgets/text/e-text.h                              |    2 +-
 1239 files changed, 17613 insertions(+), 16597 deletions(-)

diff --cc addressbook/gui/component/e-book-shell-backend.c
index fd86d57,0000000..68af7ed
mode 100644,000000..100644
--- a/addressbook/gui/component/e-book-shell-backend.c
+++ b/addressbook/gui/component/e-book-shell-backend.c
@@@ -1,576 -1,0 +1,576 @@@
 +/*
 + * e-book-shell-backend.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-book-shell-backend.h"
 +
 +#include <config.h>
 +
 +#include <string.h>
 +#include <glib/gi18n.h>
 +#include <libebook/e-book.h>
 +#include <libedataserver/e-url.h>
 +#include <libedataserver/e-source.h>
 +#include <libedataserver/e-source-group.h>
 +
 +#include "shell/e-shell.h"
 +#include "shell/e-shell-window.h"
 +
 +#include "e-util/e-import.h"
 +#include "addressbook/gui/widgets/eab-gui-util.h"
 +#include "addressbook/gui/contact-editor/e-contact-editor.h"
 +#include "addressbook/gui/contact-list-editor/e-contact-list-editor.h"
 +#include "addressbook/importers/evolution-addressbook-importers.h"
 +
 +#include "eab-config.h"
 +#include "addressbook-config.h"
 +#include "autocompletion-config.h"
 +
 +#include "e-book-shell-migrate.h"
 +#include "e-book-shell-view.h"
 +
 +#ifdef ENABLE_SMIME
 +#include "smime/gui/component.h"
 +#include "smime/gui/certificate-manager.h"
 +#endif
 +
 +#define E_BOOK_SHELL_BACKEND_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_BOOK_SHELL_BACKEND, EBookShellBackendPrivate))
 +
 +#define LDAP_BASE_URI		"ldap://";
 +#define PERSONAL_RELATIVE_URI	"system"
 +
 +struct _EBookShellBackendPrivate {
 +	ESourceList *source_list;
 +};
 +
 +enum {
 +	PROP_0,
 +	PROP_SOURCE_LIST
 +};
 +
 +static gpointer parent_class;
 +static GType book_shell_backend_type;
 +
 +static void
 +book_shell_backend_ensure_sources (EShellBackend *shell_backend)
 +{
 +	/* XXX This is basically the same algorithm across all backends.
 +	 *     Maybe we could somehow integrate this into EShellBackend? */
 +
 +	EBookShellBackendPrivate *priv;
 +	ESourceGroup *on_this_computer;
 +	ESourceGroup *on_ldap_servers;
 +	ESource *personal;
 +	GSList *groups, *iter;
 +	const gchar *data_dir;
 +	const gchar *name;
 +	gchar *base_uri;
 +	gchar *filename;
 +
 +	on_this_computer = NULL;
 +	on_ldap_servers = NULL;
 +	personal = NULL;
 +
 +	priv = E_BOOK_SHELL_BACKEND_GET_PRIVATE (shell_backend);
 +
 +	if (!e_book_get_addressbooks (&priv->source_list, NULL)) {
 +		g_warning ("Could not get addressbook sources from GConf!");
 +		return;
 +	}
 +
 +	data_dir = e_shell_backend_get_data_dir (shell_backend);
 +	filename = g_build_filename (data_dir, "local", NULL);
 +	base_uri = g_filename_to_uri (filename, NULL, NULL);
 +	g_free (filename);
 +
 +	groups = e_source_list_peek_groups (priv->source_list);
 +	for (iter = groups; iter != NULL; iter = iter->next) {
 +		ESourceGroup *source_group = iter->data;
 +		const gchar *group_base_uri;
 +
 +		group_base_uri = e_source_group_peek_base_uri (source_group);
 +
 +		/* Compare only "file://" part.  If the user's home
 +		 * changes, we do not want to create another group. */
 +		if (on_this_computer == NULL &&
 +			strncmp (base_uri, group_base_uri, 7) == 0)
 +			on_this_computer = source_group;
 +
 +		else if (on_ldap_servers == NULL &&
 +			strcmp (LDAP_BASE_URI, group_base_uri) == 0)
 +			on_ldap_servers = source_group;
 +	}
 +
 +	name = _("On This Computer");
 +
 +	if (on_this_computer != NULL) {
 +		GSList *sources;
 +		const gchar *group_base_uri;
 +
 +		/* Force the group name to the current locale. */
 +		e_source_group_set_name (on_this_computer, name);
 +
 +		sources = e_source_group_peek_sources (on_this_computer);
 +		group_base_uri = e_source_group_peek_base_uri (on_this_computer);
 +
 +		/* Make sure this group includes a "Personal" source. */
 +		for (iter = sources; iter != NULL; iter = iter->next) {
 +			ESource *source = iter->data;
 +			const gchar *relative_uri;
 +
 +			relative_uri = e_source_peek_relative_uri (source);
 +			if (relative_uri == NULL)
 +				continue;
 +
 +			if (strcmp (PERSONAL_RELATIVE_URI, relative_uri) != 0)
 +				continue;
 +
 +			personal = source;
 +			break;
 +		}
 +
 +		/* Make sure we have the correct base URI.  This can
 +		 * change when the user's home directory changes. */
 +		if (strcmp (base_uri, group_base_uri) != 0) {
 +			e_source_group_set_base_uri (
 +				on_this_computer, base_uri);
 +
 +			/* XXX We shouldn't need this sync call here as
 +			 *     set_base_uri() results in synching to GConf,
 +			 *     but that happens in an idle loop and too late
 +			 *     to prevent the user from seeing a "Cannot
 +			 *     Open ... because of invalid URI" error. */
 +			e_source_list_sync (priv->source_list, NULL);
 +		}
 +
 +	} else {
 +		ESourceGroup *source_group;
 +
 +		source_group = e_source_group_new (name, base_uri);
 +		e_source_list_add_group (priv->source_list, source_group, -1);
 +		g_object_unref (source_group);
 +	}
 +
 +	name = _("Personal");
 +
 +	if (personal == NULL) {
 +		ESource *source;
 +
 +		/* Create the default Personal address book. */
 +		source = e_source_new (name, PERSONAL_RELATIVE_URI);
 +		e_source_group_add_source (on_this_computer, source, -1);
 +		e_source_set_property (source, "completion", "true");
 +		g_object_unref (source);
 +	} else {
 +		/* Force the source name to the current locale. */
 +		e_source_set_name (personal, name);
 +	}
 +
 +	name = _("On LDAP Servers");
 +
 +	if (on_ldap_servers == NULL) {
 +		ESourceGroup *source_group;
 +
 +		source_group = e_source_group_new (name, LDAP_BASE_URI);
 +		e_source_list_add_group (priv->source_list, source_group, -1);
 +		g_object_unref (source_group);
 +	} else {
 +		/* Force the group name to the current locale. */
 +		e_source_group_set_name (on_ldap_servers, name);
 +	}
 +
 +	g_free (base_uri);
 +}
 +
 +static void
 +book_shell_backend_init_importers (void)
 +{
 +	EImportClass *import_class;
 +	EImportImporter *importer;
 +
 +	import_class = g_type_class_ref (e_import_get_type ());
 +
 +	importer = evolution_ldif_importer_peek ();
 +	e_import_class_add_importer (import_class, importer, NULL, NULL);
 +
 +	importer = evolution_vcard_importer_peek ();
 +	e_import_class_add_importer (import_class, importer, NULL, NULL);
 +
 +	importer = evolution_csv_outlook_importer_peek ();
 +	e_import_class_add_importer (import_class, importer, NULL, NULL);
 +
 +	importer = evolution_csv_mozilla_importer_peek ();
 +	e_import_class_add_importer (import_class, importer, NULL, NULL);
 +
 +	importer = evolution_csv_evolution_importer_peek ();
 +	e_import_class_add_importer (import_class, importer, NULL, NULL);
 +}
 +
 +static void
 +book_shell_backend_book_loaded_cb (EBook *book,
 +                                   EBookStatus status,
 +                                   gpointer user_data)
 +{
 +	EContact *contact;
 +	GtkAction *action;
 +	GtkWidget *editor;
 +	const gchar *action_name;
 +
 +	/* XXX Handle errors better. */
 +	if (status != E_BOOK_ERROR_OK)
 +		return;
 +
 +	contact = e_contact_new ();
 +	action = GTK_ACTION (user_data);
 +	action_name = gtk_action_get_name (action);
 +
 +	if (strcmp (action_name, "contact-new") == 0)
 +		editor = e_contact_editor_new (book, contact, TRUE, TRUE);
 +
 +	if (strcmp (action_name, "contact-new-list") == 0)
 +		editor = e_contact_list_editor_new (book, contact, TRUE, TRUE);
 +
 +	eab_editor_show (EAB_EDITOR (editor));
 +
 +	g_object_unref (contact);
 +	g_object_unref (book);
 +}
 +
 +static void
 +action_contact_new_cb (GtkAction *action,
 +                       EShellWindow *shell_window)
 +{
 +	EShell *shell;
 +	EBook *book = NULL;
 +	GConfClient *client;
 +	ESourceList *source_list;
 +	const gchar *key;
 +	gchar *uid;
 +
 +	/* This callback is used for both contacts and contact lists. */
 +
 +	if (!e_book_get_addressbooks (&source_list, NULL)) {
 +		g_warning ("Could not get addressbook sources from GConf!");
 +		return;
 +	}
 +
 +	shell = e_shell_window_get_shell (shell_window);
 +	client = e_shell_get_gconf_client (shell);
 +
 +	key = "/apps/evolution/addressbook/display/primary_addressbook";
 +	uid = gconf_client_get_string (client, key, NULL);
 +
 +	if (uid != NULL) {
 +		ESource *source;
 +
 +		source = e_source_list_peek_source_by_uid (source_list, uid);
 +		if (source != NULL)
 +			book = e_book_new (source, NULL);
 +		g_free (uid);
 +	}
 +
 +	if (book == NULL)
 +		book = e_book_new_default_addressbook (NULL);
 +
 +	e_book_async_open (
 +		book, FALSE, book_shell_backend_book_loaded_cb, action);
 +}
 +
 +static void
 +action_address_book_new_cb (GtkAction *action,
 +                            EShellWindow *shell_window)
 +{
 +	addressbook_config_create_new_source (NULL);
 +}
 +
 +static GtkActionEntry item_entries[] = {
 +
 +	{ "contact-new",
 +	  "contact-new",
 +	  NC_("New", "_Contact"),
 +	  "<Shift><Control>c",
 +	  N_("Create a new contact"),
 +	  G_CALLBACK (action_contact_new_cb) },
 +
 +	{ "contact-new-list",
 +	  "stock_contact-list",
 +	  N_("Contact _List"),
 +	  "<Shift><Control>l",
 +	  N_("Create a new contact list"),
 +	  G_CALLBACK (action_contact_new_cb) }
 +};
 +
 +static GtkActionEntry source_entries[] = {
 +
 +	{ "address-book-new",
 +	  "address-book-new",
 +	  NC_("New", "Address _Book"),
 +	  NULL,
 +	  N_("Create a new address book"),
 +	  G_CALLBACK (action_address_book_new_cb) }
 +};
 +
 +static gboolean
 +book_shell_backend_handle_uri_cb (EShellBackend *shell_backend,
 +                                  const gchar *uri)
 +{
 +	EUri *euri;
 +	const gchar *cp;
 +	gchar *source_uid = NULL;
 +	gchar *contact_uid = NULL;
 +
 +	if (!g_str_has_prefix (uri, "contacts:"))
 +		return FALSE;
 +
 +	euri = e_uri_new (uri);
 +	cp = euri->query;
 +
 +	if (cp == NULL) {
 +		e_uri_free (euri);
 +		return FALSE;
 +	}
 +
 +	while (*cp != '\0') {
 +		gchar *header;
 +		gchar *content;
 +		gsize length;
 +		gsize content_length;
 +
 +		length = strcspn (cp, "=&");
 +
 +		/* If it's malformed, give up. */
 +		if (cp[length] != '=')
 +			break;
 +
 +		header = (gchar *) cp;
 +		header[length] = '\0';
 +		cp += length + 1;
 +
 +		content_length = strcspn (cp, "&");
 +		content = g_strndup (cp, content_length);
 +
 +		if (g_ascii_strcasecmp (header, "source-uid") == 0)
 +			source_uid = g_strdup (content);
 +
 +		if (g_ascii_strcasecmp (header, "contact-uid") == 0)
 +			contact_uid = g_strdup (content);
 +
 +		g_free (content);
 +
 +		cp += content_length;
 +		if (*cp == '&') {
 +			cp++;
 +			if (strcmp (cp, "amp;"))
 +				cp += 4;
 +		}
 +	}
 +
 +	/* FIXME */
 +	/*addressbook_view_edit_contact (view, source_uid, contact_uid);*/
 +
 +	g_free (source_uid);
 +	g_free (contact_uid);
 +
 +	e_uri_free (euri);
 +
 +	return TRUE;
 +}
 +
 +static void
 +book_shell_backend_window_created_cb (EShellBackend *shell_backend,
 +                                      GtkWindow *window)
 +{
 +	const gchar *backend_name;
 +
 +	if (!E_IS_SHELL_WINDOW (window))
 +		return;
 +
 +	backend_name = E_SHELL_BACKEND_GET_CLASS (shell_backend)->name;
 +
 +	e_shell_window_register_new_item_actions (
 +		E_SHELL_WINDOW (window), backend_name,
 +		item_entries, G_N_ELEMENTS (item_entries));
 +
 +	e_shell_window_register_new_source_actions (
 +		E_SHELL_WINDOW (window), backend_name,
 +		source_entries, G_N_ELEMENTS (source_entries));
 +}
 +
 +static void
 +book_shell_backend_get_property (GObject *object,
 +                                 guint property_id,
 +                                 GValue *value,
 +                                 GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_SOURCE_LIST:
 +			g_value_set_object (
 +				value,
 +				e_book_shell_backend_get_source_list (
 +				E_BOOK_SHELL_BACKEND (object)));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +book_shell_backend_dispose (GObject *object)
 +{
 +	EBookShellBackendPrivate *priv;
 +
 +	priv = E_BOOK_SHELL_BACKEND_GET_PRIVATE (object);
 +
 +	if (priv->source_list != NULL) {
 +		g_object_unref (priv->source_list);
 +		priv->source_list = NULL;
 +	}
 +
 +	/* Chain up to parent's dispose() method. */
 +	G_OBJECT_CLASS (parent_class)->dispose (object);
 +}
 +
 +static void
 +book_shell_backend_constructed (GObject *object)
 +{
 +	EShell *shell;
 +	EShellBackend *shell_backend;
 +
 +	shell_backend = E_SHELL_BACKEND (object);
 +	shell = e_shell_backend_get_shell (shell_backend);
 +
 +	/* XXX Why is this here?  Address books aren't the only
 +	 *     things that use S/MIME.  Maybe put it in EShell? */
 +#ifdef ENABLE_SMIME
 +	smime_component_init ();
 +	certificate_manager_config_init (shell);
 +#endif
 +
 +	book_shell_backend_init_importers ();
 +	book_shell_backend_ensure_sources (shell_backend);
 +
 +	e_plugin_hook_register_type (eab_config_get_type ());
 +
 +	g_signal_connect_swapped (
 +		shell, "handle-uri",
 +		G_CALLBACK (book_shell_backend_handle_uri_cb),
 +		shell_backend);
 +
 +	g_signal_connect_swapped (
 +		shell, "window-created",
 +		G_CALLBACK (book_shell_backend_window_created_cb),
 +		shell_backend);
 +
 +	autocompletion_config_init (shell);
 +}
 +
 +static gboolean
 +book_shell_backend_is_busy (EShellBackend *shell_backend)
 +{
 +	return !eab_editor_request_close_all ();
 +}
 +
 +static gboolean
 +book_shell_backend_shutdown (EShellBackend *shell_backend)
 +{
 +	/* FIXME */
 +	return TRUE;
 +}
 +
 +static void
 +book_shell_backend_class_init (EBookShellBackendClass *class)
 +{
 +	GObjectClass *object_class;
 +	EShellBackendClass *shell_backend_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (EBookShellBackendPrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->get_property = book_shell_backend_get_property;
 +	object_class->dispose = book_shell_backend_dispose;
 +	object_class->constructed = book_shell_backend_constructed;
 +
 +	shell_backend_class = E_SHELL_BACKEND_CLASS (class);
 +	shell_backend_class->shell_view_type = E_TYPE_BOOK_SHELL_VIEW;
 +	shell_backend_class->name = "addressbook";
 +	shell_backend_class->aliases = "contacts";
 +	shell_backend_class->schemes = "";
 +	shell_backend_class->sort_order = 300;
 +	shell_backend_class->start = NULL;
 +	shell_backend_class->is_busy = book_shell_backend_is_busy;
 +	shell_backend_class->shutdown = book_shell_backend_shutdown;
 +	shell_backend_class->migrate = e_book_shell_backend_migrate;
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_SOURCE_LIST,
 +		g_param_spec_object (
 +			"source-list",
 +			_("Source List"),
 +			_("The registry of address books"),
 +			E_TYPE_SOURCE_LIST,
 +			G_PARAM_READABLE));
 +}
 +
 +static void
 +book_shell_backend_init (EBookShellBackend *book_shell_backend)
 +{
 +	book_shell_backend->priv =
 +		E_BOOK_SHELL_BACKEND_GET_PRIVATE (book_shell_backend);
 +}
 +
 +GType
 +e_book_shell_backend_get_type (void)
 +{
 +	return book_shell_backend_type;
 +}
 +
 +void
 +e_book_shell_backend_register_type (GTypeModule *type_module)
 +{
 +	const GTypeInfo type_info = {
 +		sizeof (EBookShellBackendClass),
 +		(GBaseInitFunc) NULL,
 +		(GBaseFinalizeFunc) NULL,
 +		(GClassInitFunc) book_shell_backend_class_init,
 +		(GClassFinalizeFunc) NULL,
 +		NULL,  /* class_data */
 +		sizeof (EBookShellBackend),
 +		0,     /* n_preallocs */
 +		(GInstanceInitFunc) book_shell_backend_init,
 +		NULL   /* value_table */
 +	};
 +
 +	book_shell_backend_type = g_type_module_register_type (
 +		type_module, E_TYPE_SHELL_BACKEND,
 +		"EBookShellBackend", &type_info, 0);
 +}
 +
 +ESourceList *
 +e_book_shell_backend_get_source_list (EBookShellBackend *book_shell_backend)
 +{
 +	g_return_val_if_fail (
 +		E_IS_BOOK_SHELL_BACKEND (book_shell_backend), NULL);
 +
 +	return book_shell_backend->priv->source_list;
 +}
diff --cc addressbook/gui/component/e-book-shell-backend.h
index c3fde1c,0000000..c61e43b
mode 100644,000000..100644
--- a/addressbook/gui/component/e-book-shell-backend.h
+++ b/addressbook/gui/component/e-book-shell-backend.h
@@@ -1,70 -1,0 +1,70 @@@
 +/*
 + * e-book-shell-backend.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_BOOK_SHELL_BACKEND_H
 +#define E_BOOK_SHELL_BACKEND_H
 +
 +#include <shell/e-shell-backend.h>
 +#include <libedataserver/e-source-list.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_BOOK_SHELL_BACKEND \
 +	(e_book_shell_backend_get_type ())
 +#define E_BOOK_SHELL_BACKEND(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_BOOK_SHELL_BACKEND, EBookShellBackend))
 +#define E_BOOK_SHELL_BACKEND_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_BOOK_SHELL_BACKEND, EBookShellBackendClass))
 +#define E_IS_BOOK_SHELL_BACKEND(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_BOOK_SHELL_BACKEND))
 +#define E_IS_BOOK_SHELL_BACKEND_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), E_TYPE_BOOK_SHELL_BACKEND))
 +#define E_BOOK_SHELL_BACKEND_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_BOOK_SHELL_BACKEND, EBookShellBackendClass))
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _EBookShellBackend EBookShellBackend;
 +typedef struct _EBookShellBackendClass EBookShellBackendClass;
 +typedef struct _EBookShellBackendPrivate EBookShellBackendPrivate;
 +
 +struct _EBookShellBackend {
 +	EShellBackend parent;
 +	EBookShellBackendPrivate *priv;
 +};
 +
 +struct _EBookShellBackendClass {
 +	EShellBackendClass parent_class;
 +};
 +
 +GType		e_book_shell_backend_get_type	(void);
 +void		e_book_shell_backend_register_type
 +					(GTypeModule *type_module);
 +ESourceList *	e_book_shell_backend_get_source_list
 +					(EBookShellBackend *book_shell_backend);
 +
 +G_END_DECLS
 +
 +#endif /* E_BOOK_SHELL_BACKEND_H */
diff --cc addressbook/gui/component/e-book-shell-content.c
index 7f7b948,0000000..cce03b1
mode 100644,000000..100644
--- a/addressbook/gui/component/e-book-shell-content.c
+++ b/addressbook/gui/component/e-book-shell-content.c
@@@ -1,492 -1,0 +1,492 @@@
 +/*
 + * e-book-shell-content.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-book-shell-content.h"
 +
 +#include <glib/gi18n.h>
 +
 +#include "e-util/gconf-bridge.h"
 +
 +#define E_BOOK_SHELL_CONTENT_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_BOOK_SHELL_CONTENT, EBookShellContentPrivate))
 +
 +struct _EBookShellContentPrivate {
 +	GtkWidget *paned;
 +	GtkWidget *notebook;
 +	GtkWidget *preview;
 +};
 +
 +enum {
 +	PROP_0,
 +	PROP_CURRENT_VIEW,
 +	PROP_PREVIEW_CONTACT,
 +	PROP_PREVIEW_VISIBLE
 +};
 +
 +static gpointer parent_class;
 +static GType book_shell_view_type;
 +
 +static void
 +book_shell_content_send_message_cb (EBookShellContent *book_shell_content,
 +                                    EDestination *destination,
 +                                    EABContactDisplay *display)
 +{
 +	GList node = { destination, NULL, NULL };
 +
 +	eab_send_as_to (&node);
 +}
 +
 +static void
 +book_shell_content_set_property (GObject *object,
 +                                 guint property_id,
 +                                 const GValue *value,
 +                                 GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_CURRENT_VIEW:
 +			e_book_shell_content_set_current_view (
 +				E_BOOK_SHELL_CONTENT (object),
 +				g_value_get_object (value));
 +			return;
 +
 +		case PROP_PREVIEW_CONTACT:
 +			e_book_shell_content_set_preview_contact (
 +				E_BOOK_SHELL_CONTENT (object),
 +				g_value_get_object (value));
 +			return;
 +
 +		case PROP_PREVIEW_VISIBLE:
 +			e_book_shell_content_set_preview_visible (
 +				E_BOOK_SHELL_CONTENT (object),
 +				g_value_get_boolean (value));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +book_shell_content_get_property (GObject *object,
 +                                 guint property_id,
 +                                 GValue *value,
 +                                 GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_CURRENT_VIEW:
 +			g_value_set_object (
 +				value, e_book_shell_content_get_current_view (
 +				E_BOOK_SHELL_CONTENT (object)));
 +			return;
 +
 +		case PROP_PREVIEW_CONTACT:
 +			g_value_set_object (
 +				value, e_book_shell_content_get_preview_contact (
 +				E_BOOK_SHELL_CONTENT (object)));
 +			return;
 +
 +		case PROP_PREVIEW_VISIBLE:
 +			g_value_set_boolean (
 +				value, e_book_shell_content_get_preview_visible (
 +				E_BOOK_SHELL_CONTENT (object)));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +book_shell_content_dispose (GObject *object)
 +{
 +	EBookShellContentPrivate *priv;
 +
 +	priv = E_BOOK_SHELL_CONTENT_GET_PRIVATE (object);
 +
 +	if (priv->paned != NULL) {
 +		g_object_unref (priv->paned);
 +		priv->paned = NULL;
 +	}
 +
 +	if (priv->notebook != NULL) {
 +		g_object_unref (priv->notebook);
 +		priv->notebook = NULL;
 +	}
 +
 +	if (priv->preview != NULL) {
 +		g_object_unref (priv->preview);
 +		priv->preview = NULL;
 +	}
 +
 +	/* Chain up to parent's dispose() method. */
 +	G_OBJECT_CLASS (parent_class)->dispose (object);
 +}
 +
 +static void
 +book_shell_content_constructed (GObject *object)
 +{
 +	EBookShellContentPrivate *priv;
 +	GConfBridge *bridge;
 +	GtkWidget *container;
 +	GtkWidget *widget;
 +	const gchar *key;
 +
 +	priv = E_BOOK_SHELL_CONTENT_GET_PRIVATE (object);
 +
 +	/* Chain up to parent's constructed() method. */
 +	G_OBJECT_CLASS (parent_class)->constructed (object);
 +
 +	container = GTK_WIDGET (object);
 +
 +	widget = gtk_vpaned_new ();
 +	gtk_container_add (GTK_CONTAINER (container), widget);
 +	priv->paned = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	container = widget;
 +
 +	widget = gtk_notebook_new ();
 +	gtk_notebook_set_show_tabs (GTK_NOTEBOOK (widget), FALSE);
 +	gtk_notebook_set_show_border (GTK_NOTEBOOK (widget), FALSE);
 +	gtk_paned_add1 (GTK_PANED (container), widget);
 +	priv->notebook = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	widget = gtk_scrolled_window_new (NULL, NULL);
 +	gtk_scrolled_window_set_policy (
 +		GTK_SCROLLED_WINDOW (widget),
 +		GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
 +	gtk_scrolled_window_set_shadow_type (
 +		GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
 +	gtk_paned_add2 (GTK_PANED (container), widget);
 +	gtk_widget_show (widget);
 +
 +	container = widget;
 +
 +	widget = eab_contact_display_new ();
 +	eab_contact_display_set_mode (
 +		EAB_CONTACT_DISPLAY (widget),
 +		EAB_CONTACT_DISPLAY_RENDER_NORMAL);
 +	gtk_container_add (GTK_CONTAINER (container), widget);
 +	priv->preview = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	g_signal_connect_swapped (
 +		priv->preview, "send-message",
 +		G_CALLBACK (book_shell_content_send_message_cb), object);
 +
 +	/* Bind GObject properties to GConf keys. */
 +
 +	bridge = gconf_bridge_get ();
 +
 +	object = G_OBJECT (priv->paned);
 +	key = "/apps/evolution/addressbook/display/vpane_position";
 +	gconf_bridge_bind_property_delayed (bridge, key, object, "position");
 +}
 +
 +static guint32
 +book_shell_content_check_state (EShellContent *shell_content)
 +{
 +	EBookShellContent *book_shell_content;
 +	ESelectionModel *selection_model;
 +	EAddressbookModel *model;
 +	EAddressbookView *view;
 +	guint32 state = 0;
 +	gint n_contacts;
 +	gint n_selected;
 +
 +	book_shell_content = E_BOOK_SHELL_CONTENT (shell_content);
 +	view = e_book_shell_content_get_current_view (book_shell_content);
 +	model = e_addressbook_view_get_model (view);
 +
 +	selection_model = e_addressbook_view_get_selection_model (view);
 +	n_contacts = (selection_model != NULL) ?
 +		e_selection_model_row_count (selection_model) : 0;
 +	n_selected = (selection_model != NULL) ?
 +		e_selection_model_selected_count (selection_model) : 0;
 +
 +	/* FIXME Finish the rest of the flags. */
 +	if (n_selected == 1)
 +		state |= E_BOOK_SHELL_CONTENT_SELECTION_SINGLE;
 +	if (n_selected > 1)
 +		state |= E_BOOK_SHELL_CONTENT_SELECTION_MULTIPLE;
 +	if (e_addressbook_model_can_stop (model))
 +		state |= E_BOOK_SHELL_CONTENT_SOURCE_IS_BUSY;
 +	if (e_addressbook_model_get_editable (model))
 +		state |= E_BOOK_SHELL_CONTENT_SOURCE_IS_EDITABLE;
 +	if (n_contacts == 0)
 +		state |= E_BOOK_SHELL_CONTENT_SOURCE_IS_EMPTY;
 +
 +	return state;
 +}
 +
 +static void
 +book_shell_content_class_init (EBookShellContentClass *class)
 +{
 +	GObjectClass *object_class;
 +	EShellContentClass *shell_content_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (EBookShellContentPrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->set_property = book_shell_content_set_property;
 +	object_class->get_property = book_shell_content_get_property;
 +	object_class->dispose = book_shell_content_dispose;
 +	object_class->constructed = book_shell_content_constructed;
 +
 +	shell_content_class = E_SHELL_CONTENT_CLASS (class);
 +	shell_content_class->check_state = book_shell_content_check_state;
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_CURRENT_VIEW,
 +		g_param_spec_object (
 +			"current-view",
 +			_("Current View"),
 +			_("The currently selected address book view"),
 +			E_TYPE_ADDRESSBOOK_VIEW,
 +			G_PARAM_READWRITE));
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_PREVIEW_CONTACT,
 +		g_param_spec_object (
 +			"preview-contact",
 +			_("Previewed Contact"),
 +			_("The contact being shown in the preview pane"),
 +			E_TYPE_CONTACT,
 +			G_PARAM_READWRITE));
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_PREVIEW_VISIBLE,
 +		g_param_spec_boolean (
 +			"preview-visible",
 +			_("Preview is Visible"),
 +			_("Whether the preview pane is visible"),
 +			TRUE,
 +			G_PARAM_READWRITE));
 +}
 +
 +static void
 +book_shell_content_init (EBookShellContent *book_shell_content)
 +{
 +	book_shell_content->priv =
 +		E_BOOK_SHELL_CONTENT_GET_PRIVATE (book_shell_content);
 +
 +	/* Postpone widget construction until we have a shell view. */
 +}
 +
 +GType
 +e_book_shell_content_get_type (void)
 +{
 +	return book_shell_view_type;
 +}
 +
 +void
 +e_book_shell_content_register_type (GTypeModule *type_module)
 +{
 +	static const GTypeInfo type_info = {
 +		sizeof (EBookShellContentClass),
 +		(GBaseInitFunc) NULL,
 +		(GBaseFinalizeFunc) NULL,
 +		(GClassInitFunc) book_shell_content_class_init,
 +		(GClassFinalizeFunc) NULL,
 +		NULL,  /* class_data */
 +		sizeof (EBookShellContent),
 +		0,     /* n_preallocs */
 +		(GInstanceInitFunc) book_shell_content_init,
 +		NULL   /* value_table */
 +	};
 +
 +	book_shell_view_type = g_type_module_register_type (
 +		type_module, E_TYPE_SHELL_CONTENT,
 +		"EBookShellContent", &type_info, 0);
 +}
 +
 +GtkWidget *
 +e_book_shell_content_new (EShellView *shell_view)
 +{
 +	g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
 +
 +	return g_object_new (
 +		E_TYPE_BOOK_SHELL_CONTENT,
 +		"shell-view", shell_view, NULL);
 +}
 +
 +void
 +e_book_shell_content_insert_view (EBookShellContent *book_shell_content,
 +                                  EAddressbookView *addressbook_view)
 +{
 +	GtkNotebook *notebook;
 +	GtkWidget *child;
 +
 +	g_return_if_fail (E_IS_BOOK_SHELL_CONTENT (book_shell_content));
 +	g_return_if_fail (E_IS_ADDRESSBOOK_VIEW (addressbook_view));
 +
 +	notebook = GTK_NOTEBOOK (book_shell_content->priv->notebook);
 +	child = GTK_WIDGET (addressbook_view);
 +	gtk_notebook_append_page (notebook, child, NULL);
 +}
 +
 +void
 +e_book_shell_content_remove_view (EBookShellContent *book_shell_content,
 +                                  EAddressbookView *addressbook_view)
 +{
 +	GtkNotebook *notebook;
 +	GtkWidget *child;
 +	gint page_num;
 +
 +	g_return_if_fail (E_IS_BOOK_SHELL_CONTENT (book_shell_content));
 +	g_return_if_fail (E_IS_ADDRESSBOOK_VIEW (addressbook_view));
 +
 +	notebook = GTK_NOTEBOOK (book_shell_content->priv->notebook);
 +	child = GTK_WIDGET (addressbook_view);
 +	page_num = gtk_notebook_page_num (notebook, child);
 +	g_return_if_fail (page_num >= 0);
 +
 +	gtk_notebook_remove_page (notebook, page_num);
 +}
 +
 +EAddressbookView *
 +e_book_shell_content_get_current_view (EBookShellContent *book_shell_content)
 +{
 +	GtkNotebook *notebook;
 +	GtkWidget *widget;
 +	gint page_num;
 +
 +	g_return_val_if_fail (
 +		E_IS_BOOK_SHELL_CONTENT (book_shell_content), NULL);
 +
 +	notebook = GTK_NOTEBOOK (book_shell_content->priv->notebook);
 +	page_num = gtk_notebook_get_current_page (notebook);
 +	widget = gtk_notebook_get_nth_page (notebook, page_num);
 +	g_return_val_if_fail (widget != NULL, NULL);
 +
 +	return E_ADDRESSBOOK_VIEW (widget);
 +}
 +
 +void
 +e_book_shell_content_set_current_view (EBookShellContent *book_shell_content,
 +                                       EAddressbookView *addressbook_view)
 +{
 +	GtkNotebook *notebook;
 +	GtkWidget *child;
 +	gint page_num;
 +
 +	g_return_if_fail (E_IS_BOOK_SHELL_CONTENT (book_shell_content));
 +	g_return_if_fail (E_IS_ADDRESSBOOK_VIEW (addressbook_view));
 +
 +	notebook = GTK_NOTEBOOK (book_shell_content->priv->notebook);
 +	child = GTK_WIDGET (addressbook_view);
 +	page_num = gtk_notebook_page_num (notebook, child);
 +	g_return_if_fail (page_num >= 0);
 +
 +	gtk_notebook_set_current_page (notebook, page_num);
 +	g_object_notify (G_OBJECT (book_shell_content), "current-view");
 +}
 +
 +EContact *
 +e_book_shell_content_get_preview_contact (EBookShellContent *book_shell_content)
 +{
 +	EABContactDisplay *display;
 +
 +	g_return_val_if_fail (
 +		E_IS_BOOK_SHELL_CONTENT (book_shell_content), NULL);
 +
 +	display = EAB_CONTACT_DISPLAY (book_shell_content->priv->preview);
 +
 +	return eab_contact_display_get_contact (display);
 +}
 +
 +void
 +e_book_shell_content_set_preview_contact (EBookShellContent *book_shell_content,
 +                                          EContact *preview_contact)
 +{
 +	EABContactDisplay *display;
 +
 +	g_return_if_fail (E_IS_BOOK_SHELL_CONTENT (book_shell_content));
 +
 +	display = EAB_CONTACT_DISPLAY (book_shell_content->priv->preview);
 +
 +	eab_contact_display_set_contact (display, preview_contact);
 +	g_object_notify (G_OBJECT (book_shell_content), "preview-contact");
 +}
 +
 +gboolean
 +e_book_shell_content_get_preview_visible (EBookShellContent *book_shell_content)
 +{
 +	GtkPaned *paned;
 +	GtkWidget *child;
 +
 +	g_return_val_if_fail (
 +		E_IS_BOOK_SHELL_CONTENT (book_shell_content), FALSE);
 +
 +	paned = GTK_PANED (book_shell_content->priv->paned);
 +	child = gtk_paned_get_child2 (paned);
 +
 +	return GTK_WIDGET_VISIBLE (child);
 +}
 +
 +void
 +e_book_shell_content_set_preview_visible (EBookShellContent *book_shell_content,
 +                                          gboolean preview_visible)
 +{
 +	GtkPaned *paned;
 +	GtkWidget *child;
 +
 +	g_return_if_fail (E_IS_BOOK_SHELL_CONTENT (book_shell_content));
 +
 +	paned = GTK_PANED (book_shell_content->priv->paned);
 +	child = gtk_paned_get_child2 (paned);
 +
 +	if (preview_visible)
 +		gtk_widget_show (child);
 +	else
 +		gtk_widget_hide (child);
 +
 +	g_object_notify (G_OBJECT (book_shell_content), "preview-visible");
 +}
 +
 +void
 +e_book_shell_content_clipboard_copy (EBookShellContent *book_shell_content)
 +{
 +	EAddressbookView *addressbook_view;
 +	GtkHTML *html;
 +	gchar *selection;
 +
 +	g_return_if_fail (E_IS_BOOK_SHELL_CONTENT (book_shell_content));
 +
 +	html = GTK_HTML (book_shell_content->priv->preview);
 +	addressbook_view =
 +		e_book_shell_content_get_current_view (book_shell_content);
 +	g_return_if_fail (addressbook_view != NULL);
 +
 +	if (!GTK_WIDGET_HAS_FOCUS (html)) {
 +		e_addressbook_view_copy (addressbook_view);
 +		return;
 +	}
 +
 +	selection = gtk_html_get_selection_html (html, NULL);
 +	if (selection != NULL)
 +		gtk_html_copy (html);
 +	g_free (selection);
 +}
diff --cc addressbook/gui/component/e-book-shell-content.h
index a8f8271,0000000..ac5ab10
mode 100644,000000..100644
--- a/addressbook/gui/component/e-book-shell-content.h
+++ b/addressbook/gui/component/e-book-shell-content.h
@@@ -1,110 -1,0 +1,110 @@@
 +/*
 + * e-book-shell-content.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_BOOK_SHELL_CONTENT_H
 +#define E_BOOK_SHELL_CONTENT_H
 +
 +#include <libebook/e-contact.h>
 +
 +#include "shell/e-shell-content.h"
 +#include "shell/e-shell-view.h"
 +
 +#include "addressbook/gui/component/eab-composer-util.h"
 +#include "addressbook/gui/widgets/e-addressbook-view.h"
 +
 +/* Standard GObject macros */
 +#define E_TYPE_BOOK_SHELL_CONTENT \
 +	(e_book_shell_content_get_type ())
 +#define E_BOOK_SHELL_CONTENT(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_BOOK_SHELL_CONTENT, EBookShellContent))
 +#define E_BOOK_SHELL_CONTENT_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_BOOK_SHELL_CONTENT, EBookShellContentClass))
 +#define E_IS_BOOK_SHELL_CONTENT(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_BOOK_SHELL_CONTENT))
 +#define E_IS_BOOK_SHELL_CONTENT_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), E_TYPE_BOOK_SHELL_CONTENT))
 +#define E_BOOK_SHELL_CONTENT_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_BOOK_SHELL_CONTENT, EBookShellContentClass))
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _EBookShellContent EBookShellContent;
 +typedef struct _EBookShellContentClass EBookShellContentClass;
 +typedef struct _EBookShellContentPrivate EBookShellContentPrivate;
 +
 +enum {
 +	E_BOOK_SHELL_CONTENT_SELECTION_SINGLE		= 1 << 0,
 +	E_BOOK_SHELL_CONTENT_SELECTION_MULTIPLE		= 1 << 1,
 +	E_BOOK_SHELL_CONTENT_SELECTION_HAS_EMAIL	= 1 << 2,
 +	E_BOOK_SHELL_CONTENT_SELECTION_IS_CONTACT_LIST	= 1 << 3,
 +	E_BOOK_SHELL_CONTENT_SELECTION_HAS_HTTP_URI	= 1 << 4,
 +	E_BOOK_SHELL_CONTENT_SELECTION_HAS_MAILTO_URI	= 1 << 5,
 +	E_BOOK_SHELL_CONTENT_SOURCE_IS_BUSY		= 1 << 6,
 +	E_BOOK_SHELL_CONTENT_SOURCE_IS_EDITABLE		= 1 << 7,
 +	E_BOOK_SHELL_CONTENT_SOURCE_IS_EMPTY		= 1 << 8
 +};
 +
 +struct _EBookShellContent {
 +	EShellContent parent;
 +	EBookShellContentPrivate *priv;
 +};
 +
 +struct _EBookShellContentClass {
 +	EShellContentClass parent_class;
 +};
 +
 +GType		e_book_shell_content_get_type	(void);
 +void		e_book_shell_content_register_type
 +					(GTypeModule *type_module);
 +GtkWidget *	e_book_shell_content_new(EShellView *shell_view);
 +void		e_book_shell_content_insert_view
 +					(EBookShellContent *book_shell_content,
 +					 EAddressbookView *addressbook_view);
 +void		e_book_shell_content_remove_view
 +					(EBookShellContent *book_shell_content,
 +					 EAddressbookView *addressbook_view);
 +EAddressbookView *
 +		e_book_shell_content_get_current_view
 +					(EBookShellContent *book_shell_content);
 +void		e_book_shell_content_set_current_view
 +					(EBookShellContent *book_shell_content,
 +					 EAddressbookView *addressbook_view);
 +EContact *	e_book_shell_content_get_preview_contact
 +					(EBookShellContent *book_shell_content);
 +void		e_book_shell_content_set_preview_contact
 +					(EBookShellContent *book_shell_content,
 +					 EContact *preview_contact);
 +gboolean	e_book_shell_content_get_preview_visible
 +					(EBookShellContent *book_shell_content);
 +void		e_book_shell_content_set_preview_visible
 +					(EBookShellContent *book_shell_content,
 +					 gboolean preview_visible);
 +void		e_book_shell_content_clipboard_copy
 +					(EBookShellContent *book_shell_content);
 +
 +G_END_DECLS
 +
 +#endif /* E_BOOK_SHELL_CONTENT_H */
diff --cc addressbook/gui/component/e-book-shell-migrate.c
index 08ade1f,0000000..2c9aa6a
mode 100644,000000..100644
--- a/addressbook/gui/component/e-book-shell-migrate.c
+++ b/addressbook/gui/component/e-book-shell-migrate.c
@@@ -1,1230 -1,0 +1,1230 @@@
 +/*
 + * e-book-shell-backend-migrate.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Authors:
 + *		Chris Toshok <toshok ximian com>
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include <config.h>
 +
 +#include <string.h>
 +#include <sys/types.h>
 +#include <sys/stat.h>
 +#include <unistd.h>
 +#include <fcntl.h>
 +#include <errno.h>
 +
 +#include <glib.h>
 +#include <glib/gstdio.h>
 +
 +#include <gtk/gtk.h>
 +
 +#include <libebook/e-destination.h>
 +#include <libebook/e-book.h>
 +#include <glib/gi18n.h>
 +
 +#include <libedataserver/e-xml-utils.h>
 +
 +#include "e-util/e-util.h"
 +#include "e-util/e-util-private.h"
 +#include "e-util/e-xml-utils.h"
 +#include "e-util/e-folder-map.h"
 +
 +#include "e-book-shell-migrate.h"
 +
 +/*#define SLOW_MIGRATION*/
 +
 +typedef struct {
 +	/* this hash table maps old folder uris to new uids.  It's
 +	   build in migrate_contact_folder and it's used in
 +	   migrate_completion_folders. */
 +	GHashTable *folder_uid_map;
 +
 +	ESourceList *source_list;
 +
 +	const gchar *data_dir;
 +
 +	GtkWidget *window;
 +	GtkWidget *label;
 +	GtkWidget *folder_label;
 +	GtkWidget *progress;
 +} MigrationContext;
 +
 +static void
 +setup_progress_dialog (MigrationContext *context)
 +{
 +	GtkWidget *vbox, *hbox;
 +
 +	context->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 +	gtk_window_set_title (GTK_WINDOW (context->window), _("Migrating..."));
 +	gtk_window_set_modal (GTK_WINDOW (context->window), TRUE);
 +	gtk_container_set_border_width (GTK_CONTAINER (context->window), 6);
 +
 +	vbox = gtk_vbox_new (FALSE, 6);
 +	gtk_widget_show (vbox);
 +	gtk_container_add (GTK_CONTAINER (context->window), vbox);
 +
 +	context->label = gtk_label_new ("");
 +	gtk_label_set_line_wrap (GTK_LABEL (context->label), TRUE);
 +	gtk_widget_show (context->label);
 +	gtk_box_pack_start (GTK_BOX (vbox), context->label, TRUE, TRUE, 0);
 +
 +	hbox = gtk_hbox_new (FALSE, 6);
 +	gtk_widget_show (hbox);
 +	gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
 +
 +	context->folder_label = gtk_label_new ("");
 +	gtk_widget_show (context->folder_label);
 +	gtk_box_pack_start (GTK_BOX (hbox), context->folder_label, TRUE, TRUE, 0);
 +
 +	context->progress = gtk_progress_bar_new ();
 +	gtk_widget_show (context->progress);
 +	gtk_box_pack_start (GTK_BOX (hbox), context->progress, TRUE, TRUE, 0);
 +
 +	gtk_widget_show (context->window);
 +}
 +
 +static void
 +dialog_close (MigrationContext *context)
 +{
 +	gtk_widget_destroy (context->window);
 +}
 +
 +static void
 +dialog_set_label (MigrationContext *context, const char *str)
 +{
 +	gtk_label_set_text (GTK_LABEL (context->label), str);
 +
 +	while (gtk_events_pending ())
 +		gtk_main_iteration ();
 +
 +#ifdef SLOW_MIGRATION
 +	sleep (1);
 +#endif
 +}
 +
 +static void
 +dialog_set_folder_name (MigrationContext *context, const char *folder_name)
 +{
 +	char *text;
 +
 +	text = g_strdup_printf (_("Migrating '%s':"), folder_name);
 +	gtk_label_set_text (GTK_LABEL (context->folder_label), text);
 +	g_free (text);
 +
 +	gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (context->progress), 0.0);
 +
 +	while (gtk_events_pending ())
 +		gtk_main_iteration ();
 +
 +#ifdef SLOW_MIGRATION
 +	sleep (1);
 +#endif
 +}
 +
 +static void
 +dialog_set_progress (MigrationContext *context, double percent)
 +{
 +	char text[5];
 +
 +	snprintf (text, sizeof (text), "%d%%", (int) (percent * 100.0f));
 +
 +	gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (context->progress), percent);
 +	gtk_progress_bar_set_text (GTK_PROGRESS_BAR (context->progress), text);
 +
 +	while (gtk_events_pending ())
 +		gtk_main_iteration ();
 +
 +#ifdef SLOW_MIGRATION
 +	sleep (1);
 +#endif
 +}
 +
 +static gboolean
 +check_for_conflict (ESourceGroup *group, char *name)
 +{
 +	GSList *sources;
 +	GSList *s;
 +
 +	sources = e_source_group_peek_sources (group);
 +
 +	for (s = sources; s; s = s->next) {
 +		ESource *source = E_SOURCE (s->data);
 +
 +		if (!strcmp (e_source_peek_name (source), name))
 +			return TRUE;
 +	}
 +
 +	return FALSE;
 +}
 +
 +static char *
 +get_source_name (ESourceGroup *group, const char *path)
 +{
 +#ifndef G_OS_WIN32
 +	char **p = g_strsplit (path, "/", 0);
 +#else
 +	char **p = g_strsplit_set (path, "\\/", 0);
 +#endif
 +	int i, j, starting_index;
 +	int num_elements;
 +	gboolean conflict;
 +	GString *s = g_string_new ("");
 +
 +	for (i = 0; p[i]; i ++) ;
 +
 +	num_elements = i;
 +	i--;
 +
 +	/* p[i] is now the last path element */
 +
 +	/* check if it conflicts */
 +	starting_index = i;
 +	do {
 +		g_string_assign (s, "");
 +		for (j = starting_index; j < num_elements; j += 2) {
 +			if (j != starting_index)
 +				g_string_append_c (s, '_');
 +			g_string_append (s, p[j]);
 +		}
 +
 +		conflict = check_for_conflict (group, s->str);
 +
 +
 +		/* if there was a conflict back up 2 levels (skipping the /subfolder/ element) */
 +		if (conflict)
 +			starting_index -= 2;
 +
 +		/* we always break out if we can't go any further,
 +		   regardless of whether or not we conflict. */
 +		if (starting_index < 0)
 +			break;
 +
 +	} while (conflict);
 +
 +	g_strfreev (p);
 +
 +	return g_string_free (s, FALSE);
 +}
 +
 +static void
 +migrate_contacts (MigrationContext *context, EBook *old_book, EBook *new_book)
 +{
 +	EBookQuery *query = e_book_query_any_field_contains ("");
 +	GList *l, *contacts;
 +	int num_added = 0;
 +	int num_contacts;
 +
 +	/* both books are loaded, start the actual migration */
 +	e_book_get_contacts (old_book, query, &contacts, NULL);
 +	e_book_query_unref (query);
 +
 +	num_contacts = g_list_length (contacts);
 +	for (l = contacts; l; l = l->next) {
 +		EContact *contact = l->data;
 +		GError *e = NULL;
 +		GList *attrs, *attr;
 +
 +		/* do some last minute massaging of the contact's attributes */
 +
 +		attrs = e_vcard_get_attributes (E_VCARD (contact));
 +		for (attr = attrs; attr;) {
 +			EVCardAttribute *a = attr->data;
 +
 +			/* evo 1.4 used the non-standard X-EVOLUTION-OFFICE attribute,
 +			   evo 1.5 uses the third element in the ORG list attribute. */
 +			if (!strcmp ("X-EVOLUTION-OFFICE", e_vcard_attribute_get_name (a))) {
 +				GList *v = e_vcard_attribute_get_values (a);
 +				GList *next_attr;
 +
 +				if (v && v->data)
 +					e_contact_set (contact, E_CONTACT_OFFICE, v->data);
 +
 +				next_attr = attr->next;
 +				e_vcard_remove_attribute (E_VCARD (contact), a);
 +				attr = next_attr;
 +			}
 +			/* evo 1.4 didn't put TYPE=VOICE in for phone numbers.
 +			   evo 1.5 does.
 +
 +			   so we search through the attribute params for
 +			   either TYPE=VOICE or TYPE=FAX.  If we find
 +			   either we do nothing.  If we find neither, we
 +			   add TYPE=VOICE.
 +			*/
 +			else if (!strcmp ("TEL", e_vcard_attribute_get_name (a))) {
 +				GList *params, *param;
 +				gboolean found = FALSE;
 +
 +				params = e_vcard_attribute_get_params (a);
 +				for (param = params; param; param = param->next) {
 +					EVCardAttributeParam *p = param->data;
 +					if (!strcmp (EVC_TYPE, e_vcard_attribute_param_get_name (p))) {
 +						GList *v = e_vcard_attribute_param_get_values (p);
 +						while (v && v->data) {
 +							if (!strcmp ("VOICE", v->data)
 +							    || !strcmp ("FAX", v->data)) {
 +								found = TRUE;
 +								break;
 +							}
 +							v = v->next;
 +						}
 +					}
 +				}
 +
 +				if (!found)
 +					e_vcard_attribute_add_param_with_value (a,
 +										e_vcard_attribute_param_new (EVC_TYPE),
 +										"VOICE");
 +				attr = attr->next;
 +			}
 +			/* Replace "POSTAL" (1.4) addresses with "OTHER" (1.5) */
 +			else if (!strcmp ("ADR", e_vcard_attribute_get_name (a))) {
 +				GList *params, *param;
 +				gboolean found = FALSE;
 +				EVCardAttributeParam *p;
 +
 +				params = e_vcard_attribute_get_params (a);
 +				for (param = params; param; param = param->next) {
 +					p = param->data;
 +					if (!strcmp (EVC_TYPE, e_vcard_attribute_param_get_name (p))) {
 +						GList *v = e_vcard_attribute_param_get_values (p);
 +						while (v && v->data ) {
 +							if (!strcmp ("POSTAL", v->data)) {
 +								found = TRUE;
 +								break;
 +							}
 +							v = v->next;
 +						}
 +						if (found)
 +							break;
 +					}
 +				}
 +
 +				if (found) {
 +					e_vcard_attribute_param_remove_values (p);
 +					e_vcard_attribute_param_add_value (p, "OTHER");
 +				}
 +
 +				attr = attr->next;
 +			}
 +			/* this is kinda gross.  The new vcard parser
 +			   needs ';'s to be escaped by \'s.  but the
 +			   1.4 vcard generator would put unescaped xml
 +			   (including entities like &gt;) in the value
 +			   of attributes, so we need to go through and
 +			   escape those ';'s. */
 +			else if (!strcmp ("EMAIL", e_vcard_attribute_get_name (a))) {
 +				GList *params;
 +				GList *v = e_vcard_attribute_get_values (a);
 +
 +				/* Add TYPE=OTHER if there is no type set */
 +				params = e_vcard_attribute_get_params (a);
 +				if (!params)
 +					e_vcard_attribute_add_param_with_value (a,
 +							e_vcard_attribute_param_new (EVC_TYPE),
 +							"OTHER");
 +
 +				if (v && v->data) {
 +					if (!strncmp ((char*)v->data, "<?xml", 5)) {
 +						/* k, this is the nasty part.  we glomb all the
 +						   value strings back together again (if there is
 +						   more than one), then work our magic */
 +						GString *str = g_string_new ("");
 +						while (v) {
 +							g_string_append (str, v->data);
 +							if (v->next)
 +								g_string_append_c (str, ';');
 +							v = v->next;
 +						}
 +
 +						e_vcard_attribute_remove_values (a);
 +						e_vcard_attribute_add_value (a, str->str);
 +						g_string_free (str, TRUE);
 +					}
 +				}
 +
 +				attr = attr->next;
 +			}
 +			else {
 +				attr = attr->next;
 +			}
 +		}
 +
 +		if (!e_book_add_contact (new_book,
 +					 contact,
 +					 &e))
 +			g_warning ("contact add failed: `%s'", e->message);
 +
 +		num_added ++;
 +
 +		dialog_set_progress (context, (double)num_added / num_contacts);
 +	}
 +
 +	g_list_foreach (contacts, (GFunc)g_object_unref, NULL);
 +	g_list_free (contacts);
 +}
 +
 +static void
 +migrate_contact_folder_to_source (MigrationContext *context, char *old_path, ESource *new_source)
 +{
 +	char *old_uri = g_filename_to_uri (old_path, NULL, NULL);
 +	GError *e = NULL;
 +
 +	EBook *old_book = NULL, *new_book = NULL;
 +	ESource *old_source;
 +	ESourceGroup *group;
 +
 +	group = e_source_group_new ("", old_uri);
 +	old_source = e_source_new ("", "");
 +	e_source_group_add_source (group, old_source, -1);
 +
 +	dialog_set_folder_name (context, e_source_peek_name (new_source));
 +
 +	old_book = e_book_new (old_source, &e);
 +	if (!old_book
 +	    || !e_book_open (old_book, TRUE, &e)) {
 +		g_warning ("failed to load source book for migration: `%s'", e->message);
 +		goto finish;
 +	}
 +
 +	new_book = e_book_new (new_source, &e);
 +	if (!new_book
 +	    || !e_book_open (new_book, FALSE, &e)) {
 +		g_warning ("failed to load destination book for migration: `%s'", e->message);
 +		goto finish;
 +	}
 +
 +	migrate_contacts (context, old_book, new_book);
 +
 + finish:
 +	g_object_unref (old_source);
 +	g_object_unref (group);
 +	if (old_book)
 +		g_object_unref (old_book);
 +	if (new_book)
 +		g_object_unref (new_book);
 +	g_free (old_uri);
 +}
 +
 +static void
 +migrate_contact_folder (MigrationContext *context, char *old_path, ESourceGroup *dest_group, char *source_name)
 +{
 +	ESource *new_source;
 +
 +	new_source = e_source_new (source_name, source_name);
 +	e_source_set_relative_uri (new_source, e_source_peek_uid (new_source));
 +	e_source_group_add_source (dest_group, new_source, -1);
 +
 +	g_hash_table_insert (context->folder_uid_map, g_strdup (old_path), g_strdup (e_source_peek_uid (new_source)));
 +
 +	migrate_contact_folder_to_source (context, old_path, new_source);
 +
 +	g_object_unref (new_source);
 +}
 +
 +#define LDAP_BASE_URI "ldap://";
 +#define PERSONAL_RELATIVE_URI "system"
 +
 +static void
 +create_groups (MigrationContext *context,
 +	       ESourceGroup **on_this_computer,
 +	       ESourceGroup **on_ldap_servers,
 +	       ESource      **personal_source)
 +{
 +	GSList *groups;
 +	ESourceGroup *group;
 +	char *base_uri, *base_uri_proto;
 +
 +	*on_this_computer = NULL;
 +	*on_ldap_servers = NULL;
 +	*personal_source = NULL;
 +
 +	base_uri = g_build_filename (context->data_dir, "local", NULL);
 +
 +	base_uri_proto = g_filename_to_uri (base_uri, NULL, NULL);
 +
 +	groups = e_source_list_peek_groups (context->source_list);
 +	if (groups) {
 +		/* groups are already there, we need to search for things... */
 +		GSList *g;
 +
 +		for (g = groups; g; g = g->next) {
 +
 +			group = E_SOURCE_GROUP (g->data);
 +
 +			if (!*on_this_computer && !strcmp (base_uri_proto, e_source_group_peek_base_uri (group)))
 +				*on_this_computer = g_object_ref (group);
 +			else if (!*on_ldap_servers && !strcmp (LDAP_BASE_URI, e_source_group_peek_base_uri (group)))
 +				*on_ldap_servers = g_object_ref (group);
 +		}
 +	}
 +
 +	if (*on_this_computer) {
 +		/* make sure "Personal" shows up as a source under
 +		   this group */
 +		GSList *sources = e_source_group_peek_sources (*on_this_computer);
 +		GSList *s;
 +		for (s = sources; s; s = s->next) {
 +			ESource *source = E_SOURCE (s->data);
 +			const gchar *relative_uri;
 +
 +			relative_uri = e_source_peek_relative_uri (source);
 +			if (relative_uri == NULL)
 +				continue;
 +			if (!strcmp (PERSONAL_RELATIVE_URI, relative_uri)) {
 +				*personal_source = g_object_ref (source);
 +				break;
 +			}
 +		}
 +	}
 +	else {
 +		/* create the local source group */
 +		group = e_source_group_new (_("On This Computer"), base_uri_proto);
 +		e_source_list_add_group (context->source_list, group, -1);
 +
 +		*on_this_computer = group;
 +	}
 +
 +	if (!*personal_source) {
 +		/* Create the default Person addressbook */
 +		ESource *source = e_source_new (_("Personal"), PERSONAL_RELATIVE_URI);
 +		e_source_group_add_source (*on_this_computer, source, -1);
 +
 +		e_source_set_property (source, "completion", "true");
 +
 +		*personal_source = source;
 +	}
 +
 +	if (!*on_ldap_servers) {
 +		/* Create the LDAP source group */
 +		group = e_source_group_new (_("On LDAP Servers"), LDAP_BASE_URI);
 +		e_source_list_add_group (context->source_list, group, -1);
 +
 +		*on_ldap_servers = group;
 +	}
 +
 +	g_free (base_uri_proto);
 +	g_free (base_uri);
 +}
 +
 +static gboolean
 +migrate_local_folders (MigrationContext *context, ESourceGroup *on_this_computer, ESource *personal_source)
 +{
 +	char *old_path = NULL;
 +	GSList *dirs, *l;
 +	char *local_contact_folder = NULL;
 +
 +	old_path = g_strdup_printf ("%s/evolution/local", g_get_home_dir ());
 +
 +	dirs = e_folder_map_local_folders (old_path, "contacts");
 +
 +	/* migrate the local addressbook first, to local/system */
 +	local_contact_folder = g_build_filename (g_get_home_dir (),
 +						 "evolution", "local", "Contacts",
 +						 NULL);
 +
 +	for (l = dirs; l; l = l->next) {
 +		char *source_name;
 +		/* we handle the system folder differently */
 +		if (personal_source && !strcmp ((char*)l->data, local_contact_folder)) {
 +			g_hash_table_insert (context->folder_uid_map, g_strdup (l->data), g_strdup (e_source_peek_uid (personal_source)));
 +			migrate_contact_folder_to_source (context, local_contact_folder, personal_source);
 +			continue;
 +		}
 +
 +		source_name = get_source_name (on_this_computer, (char*)l->data);
 +		migrate_contact_folder (context, l->data, on_this_computer, source_name);
 +		g_free (source_name);
 +	}
 +
 +	g_slist_foreach (dirs, (GFunc)g_free, NULL);
 +	g_slist_free (dirs);
 +	g_free (local_contact_folder);
 +	g_free (old_path);
 +
 +	return TRUE;
 +}
 +
 +static char *
 +get_string_child (xmlNode *node,
 +		  const char *name)
 +{
 +	xmlNode *p;
 +	xmlChar *xml_string;
 +	char *retval;
 +
 +	p = e_xml_get_child_by_name (node, (xmlChar *) name);
 +	if (p == NULL)
 +		return NULL;
 +
 +	p = e_xml_get_child_by_name (p, (xmlChar *) "text");
 +	if (p == NULL) /* there's no text between the tags, return the empty string */
 +		return g_strdup("");
 +
 +	xml_string = xmlNodeListGetString (node->doc, p, 1);
 +	retval = g_strdup ((char *) xml_string);
 +	xmlFree (xml_string);
 +
 +	return retval;
 +}
 +
 +static int
 +get_integer_child (xmlNode *node,
 +		   const char *name,
 +		   int defval)
 +{
 +	xmlNode *p;
 +	xmlChar *xml_string;
 +	int retval;
 +
 +	p = e_xml_get_child_by_name (node, (xmlChar *) name);
 +	if (p == NULL)
 +		return defval;
 +
 +	p = e_xml_get_child_by_name (p, (xmlChar *) "text");
 +	if (p == NULL) /* there's no text between the tags, return the default */
 +		return defval;
 +
 +	xml_string = xmlNodeListGetString (node->doc, p, 1);
 +	retval = atoi ((char *)xml_string);
 +	xmlFree (xml_string);
 +
 +	return retval;
 +}
 +
 +static gboolean
 +migrate_ldap_servers (MigrationContext *context, ESourceGroup *on_ldap_servers)
 +{
 +	char *sources_xml = g_strdup_printf ("%s/evolution/addressbook-sources.xml",
 +					     g_get_home_dir ());
 +
 +	printf ("trying to migrate from %s\n", sources_xml);
 +
 +	if (g_file_test (sources_xml, G_FILE_TEST_EXISTS)) {
 +		xmlDoc  *doc = xmlParseFile (sources_xml);
 +		xmlNode *root;
 +		xmlNode *child;
 +		int num_contactservers;
 +		int servernum;
 +
 +		if (!doc)
 +			return FALSE;
 +
 +		root = xmlDocGetRootElement (doc);
 +		if (root == NULL || strcmp ((const char *)root->name, "addressbooks") != 0) {
 +			xmlFreeDoc (doc);
 +			return FALSE;
 +		}
 +
 +		/* count the number of servers, so we can give progress */
 +		num_contactservers = 0;
 +		for (child = root->children; child; child = child->next) {
 +			if (!strcmp ((const char *)child->name, "contactserver")) {
 +				num_contactservers++;
 +			}
 +		}
 +		printf ("found %d contact servers to migrate\n", num_contactservers);
 +
 +		dialog_set_folder_name (context, _("LDAP Servers"));
 +
 +		servernum = 0;
 +		for (child = root->children; child; child = child->next) {
 +			if (!strcmp ((const char *)child->name, "contactserver")) {
 +				char *port, *host, *rootdn, *scope, *authmethod, *ssl;
 +				char *emailaddr, *binddn, *limitstr;
 +				int limit;
 +				char *name, *description;
 +				GString *uri = g_string_new ("");
 +				ESource *source;
 +
 +				name        = get_string_child (child, "name");
 +				description = get_string_child (child, "description");
 +				port        = get_string_child (child, "port");
 +				host        = get_string_child (child, "host");
 +				rootdn      = get_string_child (child, "rootdn");
 +			        scope       = get_string_child (child, "scope");
 +				authmethod  = get_string_child (child, "authmethod");
 +				ssl         = get_string_child (child, "ssl");
 +				emailaddr   = get_string_child (child, "emailaddr");
 +				binddn      = get_string_child (child, "binddn");
 +				limit       = get_integer_child (child, "limit", 100);
 +				limitstr    = g_strdup_printf ("%d", limit);
 +
 +				g_string_append_printf (uri,
 +							"%s:%s/%s?"/*trigraph prevention*/"?%s",
 +							host, port, rootdn, scope);
 +
 +				source = e_source_new (name, uri->str);
 +				e_source_set_property (source, "description", description);
 +				e_source_set_property (source, "limit", limitstr);
 +				e_source_set_property (source, "ssl", ssl);
 +				e_source_set_property (source, "auth", authmethod);
 +				if (emailaddr)
 +					e_source_set_property (source, "email_addr", emailaddr);
 +				if (binddn)
 +					e_source_set_property (source, "binddn", binddn);
 +
 +				e_source_group_add_source (on_ldap_servers, source, -1);
 +
 +				g_string_free (uri, TRUE);
 +				g_free (port);
 +				g_free (host);
 +				g_free (rootdn);
 +				g_free (scope);
 +				g_free (authmethod);
 +				g_free (ssl);
 +				g_free (emailaddr);
 +				g_free (binddn);
 +				g_free (limitstr);
 +				g_free (name);
 +				g_free (description);
 +
 +				servernum++;
 +				dialog_set_progress (context, (double)servernum/num_contactservers);
 +			}
 +		}
 +
 +		xmlFreeDoc (doc);
 +	}
 +
 +	g_free (sources_xml);
 +
 +	return TRUE;
 +}
 +
 +static ESource*
 +get_source_by_name (ESourceList *source_list, const char *name)
 +{
 +	GSList *groups;
 +	GSList *g;
 +
 +	groups = e_source_list_peek_groups (source_list);
 +	if (!groups)
 +		return NULL;
 +
 +	for (g = groups; g; g = g->next) {
 +		GSList *sources;
 +		GSList *s;
 +		ESourceGroup *group = E_SOURCE_GROUP (g->data);
 +
 +		sources = e_source_group_peek_sources (group);
 +		if (!sources)
 +			continue;
 +
 +		for (s = sources; s; s = s->next) {
 +			ESource *source = E_SOURCE (s->data);
 +			const char *source_name = e_source_peek_name (source);
 +
 +			if (!strcmp (name, source_name))
 +				return source;
 +		}
 +	}
 +
 +	return NULL;
 +}
 +
 +static gboolean
 +migrate_completion_folders (MigrationContext *context)
 +{
 +	GConfClient *client;
 +	const gchar *key;
 +	gchar *uris_xml;
 +
 +	printf ("trying to migrate completion folders\n");
 +
 +	client = gconf_client_get_default ();
 +	key = "/apps/evolution/addressbook/completion/uris";
 +	uris_xml = gconf_client_get_string (client, key, NULL);
 +	g_object_unref (client);
 +
 +	if (uris_xml) {
 +		xmlDoc  *doc = xmlParseMemory (uris_xml, strlen (uris_xml));
 +		xmlNode *root;
 +		xmlNode *child;
 +
 +		if (!doc)
 +			return FALSE;
 +
 +		dialog_set_folder_name (context, _("Autocompletion Settings"));
 +
 +		root = xmlDocGetRootElement (doc);
 +		if (root == NULL || strcmp ((const char *)root->name, "EvolutionFolderList") != 0) {
 +			xmlFreeDoc (doc);
 +			return FALSE;
 +		}
 +
 +		for (child = root->children; child; child = child->next) {
 +			if (!strcmp ((const char *)child->name, "folder")) {
 +				char *physical_uri = e_xml_get_string_prop_by_name (child, (const unsigned char *)"physical-uri");
 +				ESource *source = NULL;
 +
 +				/* if the physical uri is file://...
 +				   we look it up in our folder_uid_map
 +				   hashtable.  If it's a folder we
 +				   converted over, we should get back
 +				   a uid we can search for.
 +
 +				   if the physical_uri is anything
 +				   else, we strip off the args
 +				   (anything after ;) before searching
 +				   for the uri. */
 +
 +				if (!strncmp (physical_uri, "file://", 7)) {
 +					char *filename = g_filename_from_uri (physical_uri, NULL, NULL);
 +					char *uid = NULL;
 +
 +					if (filename)
 +						uid  = g_hash_table_lookup (context->folder_uid_map,
 +									    filename);
 +					g_free (filename);
 +					if (uid)
 +						source = e_source_list_peek_source_by_uid (context->source_list, uid);
 +				}
 +				else {
 +					char *name = e_xml_get_string_prop_by_name (child, (const unsigned char *)"display-name");
 +
 +					source = get_source_by_name (context->source_list, name);
 +
 +					g_free (name);
 +				}
 +
 +				if (source) {
 +					e_source_set_property (source, "completion", "true");
 +				}
 +				else {
 +					g_warning ("found completion folder with uri `%s' that "
 +						   "doesn't correspond to anything we migrated.", physical_uri);
 +				}
 +
 +				g_free (physical_uri);
 +			}
 +		}
 +
 +		g_free (uris_xml);
 +	}
 +	else {
 +		g_message ("no completion folder settings to migrate");
 +	}
 +
 +	return TRUE;
 +}
 +
 +static void
 +migrate_contact_lists_for_local_folders (MigrationContext *context, ESourceGroup *on_this_computer)
 +{
 +	GSList *sources, *s;
 +
 +	sources = e_source_group_peek_sources (on_this_computer);
 +	for (s = sources; s; s = s->next) {
 +		ESource *source = s->data;
 +		EBook *book;
 +		EBookQuery *query;
 +		GList *l, *contacts;
 +		int num_contacts, num_converted;
 +
 +		dialog_set_folder_name (context, e_source_peek_name (source));
 +
 +		book = e_book_new (source, NULL);
 +		if (!book
 +		    || !e_book_open (book, TRUE, NULL)) {
 +			char *uri = e_source_get_uri (source);
 +			g_warning ("failed to migrate contact lists for source %s", uri);
 +			g_free (uri);
 +			continue;
 +		}
 +
 +		query = e_book_query_any_field_contains ("");
 +		e_book_get_contacts (book, query, &contacts, NULL);
 +		e_book_query_unref (query);
 +
 +		num_converted = 0;
 +		num_contacts = g_list_length (contacts);
 +		for (l = contacts; l; l = l->next) {
 +			EContact *contact = l->data;
 +			GError *e = NULL;
 +			GList *attrs, *attr;
 +			gboolean converted = FALSE;
 +
 +			attrs = e_contact_get_attributes (contact, E_CONTACT_EMAIL);
 +			for (attr = attrs; attr; attr = attr->next) {
 +				EVCardAttribute *a = attr->data;
 +				GList *v = e_vcard_attribute_get_values (a);
 +
 +				if (v && v->data) {
 +					if (!strncmp ((char*)v->data, "<?xml", 5)) {
 +						EDestination *dest = e_destination_import ((char*)v->data);
 +
 +						e_destination_export_to_vcard_attribute (dest, a);
 +
 +						g_object_unref (dest);
 +
 +						converted = TRUE;
 +					}
 +				}
 +			}
 +
 +			if (converted) {
 +				e_contact_set_attributes (contact, E_CONTACT_EMAIL, attrs);
 +
 +				if (!e_book_commit_contact (book,
 +							    contact,
 +							    &e))
 +					g_warning ("contact commit failed: `%s'", e->message);
 +			}
 +
 +			num_converted ++;
 +
 +			dialog_set_progress (context, (double)num_converted / num_contacts);
 +		}
 +
 +		g_list_foreach (contacts, (GFunc)g_object_unref, NULL);
 +		g_list_free (contacts);
 +
 +		g_object_unref (book);
 +	}
 +}
 +
 +static void
 +migrate_company_phone_for_local_folders (MigrationContext *context, ESourceGroup *on_this_computer)
 +{
 +	GSList *sources, *s;
 +
 +	sources = e_source_group_peek_sources (on_this_computer);
 +	for (s = sources; s; s = s->next) {
 +		ESource *source = s->data;
 +		EBook *book;
 +		EBookQuery *query;
 +		GList *l, *contacts;
 +		int num_contacts, num_converted;
 +
 +		dialog_set_folder_name (context, e_source_peek_name (source));
 +
 +		book = e_book_new (source, NULL);
 +		if (!book
 +		    || !e_book_open (book, TRUE, NULL)) {
 +			char *uri = e_source_get_uri (source);
 +			g_warning ("failed to migrate company phone numbers for source %s", uri);
 +			g_free (uri);
 +			continue;
 +		}
 +
 +		query = e_book_query_any_field_contains ("");
 +		e_book_get_contacts (book, query, &contacts, NULL);
 +		e_book_query_unref (query);
 +
 +		num_converted = 0;
 +		num_contacts = g_list_length (contacts);
 +		for (l = contacts; l; l = l->next) {
 +			EContact *contact = l->data;
 +			GError *e = NULL;
 +			GList *attrs, *attr;
 +			gboolean converted = FALSE;
 +			int num_work_voice = 0;
 +
 +			attrs = e_vcard_get_attributes (E_VCARD (contact));
 +			for (attr = attrs; attr;) {
 +				EVCardAttribute *a = attr->data;
 +				GList *next_attr = attr->next;
 +
 +				if (!strcmp ("TEL", e_vcard_attribute_get_name (a))) {
 +					GList *params, *param;
 +					gboolean found_voice = FALSE;
 +					gboolean found_work = FALSE;
 +
 +					params = e_vcard_attribute_get_params (a);
 +					for (param = params; param; param = param->next) {
 +						EVCardAttributeParam *p = param->data;
 +						if (!strcmp (EVC_TYPE, e_vcard_attribute_param_get_name (p))) {
 +							GList *v = e_vcard_attribute_param_get_values (p);
 +							while (v && v->data) {
 +								if (!strcmp ("VOICE", v->data))
 +									found_voice = TRUE;
 +								else if (!strcmp ("WORK", v->data))
 +									found_work = TRUE;
 +								v = v->next;
 +							}
 +						}
 +
 +						if (found_work && found_voice)
 +							num_work_voice++;
 +
 +						if (num_work_voice == 3) {
 +							GList *v = e_vcard_attribute_get_values (a);
 +
 +							if (v && v->data)
 +								e_contact_set (contact, E_CONTACT_PHONE_COMPANY, v->data);
 +
 +							e_vcard_remove_attribute (E_VCARD (contact), a);
 +
 +							converted = TRUE;
 +							break;
 +						}
 +					}
 +				}
 +
 +				attr = next_attr;
 +
 +				if (converted)
 +					break;
 +			}
 +
 +			if (converted) {
 +				if (!e_book_commit_contact (book,
 +							    contact,
 +							    &e))
 +					g_warning ("contact commit failed: `%s'", e->message);
 +			}
 +
 +			num_converted ++;
 +
 +			dialog_set_progress (context, (double)num_converted / num_contacts);
 +		}
 +
 +		g_list_foreach (contacts, (GFunc)g_object_unref, NULL);
 +		g_list_free (contacts);
 +
 +		g_object_unref (book);
 +	}
 +}
 +
 +static void
 +migrate_pilot_data (const char *old_path, const char *new_path)
 +{
 +	const char *dent;
 +	const char *ext;
 +	char *filename;
 +	GDir *dir;
 +
 +	if (!(dir = g_dir_open (old_path, 0, NULL)))
 +		return;
 +
 +	while ((dent = g_dir_read_name (dir))) {
 +		if ((!strncmp (dent, "pilot-map-", 10) &&
 +		     ((ext = strrchr (dent, '.')) && !strcmp (ext, ".xml"))) ||
 +		    (!strncmp (dent, "pilot-sync-evolution-addressbook-", 33) &&
 +		     ((ext = strrchr (dent, '.')) && !strcmp (ext, ".db")))) {
 +			/* src and dest file formats are identical for both map and changelog files */
 +			unsigned char inbuf[4096];
 +			size_t nread, nwritten;
 +			int fd0, fd1;
 +			ssize_t n;
 +
 +			filename = g_build_filename (old_path, dent, NULL);
 +			if ((fd0 = g_open (filename, O_RDONLY | O_BINARY, 0)) == -1) {
 +				g_free (filename);
 +				continue;
 +			}
 +
 +			g_free (filename);
 +			filename = g_build_filename (new_path, dent, NULL);
 +			if ((fd1 = g_open (filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666)) == -1) {
 +				g_free (filename);
 +				close (fd0);
 +				continue;
 +			}
 +
 +			do {
 +				do {
 +					n = read (fd0, inbuf, sizeof (inbuf));
 +				} while (n == -1 && errno == EINTR);
 +
 +				if (n < 1)
 +					break;
 +
 +				nread = n;
 +				nwritten = 0;
 +				do {
 +					do {
 +						n = write (fd1, inbuf + nwritten, nread - nwritten);
 +					} while (n == -1 && errno == EINTR);
 +
 +					if (n > 0)
 +						nwritten += n;
 +				} while (nwritten < nread && n != -1);
 +
 +				if (n == -1)
 +					break;
 +			} while (1);
 +
 +			if (n != -1)
 +				n = fsync (fd1);
 +
 +			if (n == -1) {
 +				g_warning ("Failed to migrate %s: %s", dent, g_strerror (errno));
 +				g_unlink (filename);
 +			}
 +
 +			close (fd0);
 +			close (fd1);
 +			g_free (filename);
 +		}
 +	}
 +
 +	g_dir_close (dir);
 +}
 +
 +static MigrationContext *
 +migration_context_new (const gchar *data_dir)
 +{
 +	MigrationContext *context = g_new (MigrationContext, 1);
 +
 +	/* set up the mapping from old uris to new uids */
 +	context->folder_uid_map = g_hash_table_new_full (
 +		g_str_hash, g_str_equal,
 +		(GDestroyNotify) g_free,
 +		(GDestroyNotify) g_free);
 +
 +	e_book_get_addressbooks (&context->source_list, NULL);
 +
 +	context->data_dir = data_dir;
 +
 +	return context;
 +}
 +
 +static void
 +migration_context_free (MigrationContext *context)
 +{
 +	e_source_list_sync (context->source_list, NULL);
 +
 +	g_hash_table_destroy (context->folder_uid_map);
 +
 +	g_object_unref (context->source_list);
 +
 +	g_free (context);
 +}
 +
 +gboolean
 +e_book_shell_backend_migrate (EShellBackend *shell_backend,
 +                              gint major,
 +                              gint minor,
 +                              gint micro,
 +                              GError **error)
 +{
 +	ESourceGroup *on_this_computer;
 +	ESourceGroup *on_ldap_servers;
 +	ESource *personal_source;
 +	MigrationContext *context;
 +	gboolean need_dialog = FALSE;
 +	const gchar *data_dir;
 +
 +	g_return_val_if_fail (E_IS_SHELL_BACKEND (shell_backend), FALSE);
 +
 +	data_dir = e_shell_backend_get_data_dir (shell_backend);
 +	context = migration_context_new (data_dir);
 +
 +	/* we call this unconditionally now - create_groups either
 +	   creates the groups/sources or it finds the necessary
 +	   groups/sources. */
 +	create_groups (context, &on_this_computer, &on_ldap_servers, &personal_source);
 +
 +	/* figure out if we need the dialog displayed */
 +	if (major == 1
 +	    /* we only need the most recent upgrade point here.
 +	       further decomposition will happen below. */
 +	    && (minor < 5 || (minor == 5 && micro <= 10)))
 +		need_dialog = TRUE;
 +
 +	if (need_dialog)
 +		setup_progress_dialog (context);
 +
 +	if (major == 1) {
 +
 +		if (minor < 5 || (minor == 5 && micro <= 2)) {
 +			/* initialize our dialog */
 +			dialog_set_label (context,
 +					  _("The location and hierarchy of the Evolution contact "
 +					    "folders has changed since Evolution 1.x.\n\nPlease be "
 +					    "patient while Evolution migrates your folders..."));
 +
 +			if (on_this_computer)
 +				migrate_local_folders (context, on_this_computer, personal_source);
 +			if (on_ldap_servers)
 +				migrate_ldap_servers (context, on_ldap_servers);
 +
 +			migrate_completion_folders (context);
 +		}
 +
 +		if (minor < 5 || (minor == 5 && micro <= 7)) {
 +			dialog_set_label (context,
 +					  _("The format of mailing list contacts has changed.\n\n"
 +					    "Please be patient while Evolution migrates your "
 +					    "folders..."));
 +
 +			migrate_contact_lists_for_local_folders (context, on_this_computer);
 +		}
 +
 +		if (minor < 5 || (minor == 5 && micro <= 8)) {
 +			dialog_set_label (context,
 +					  _("The way Evolution stores some phone numbers has changed.\n\n"
 +					    "Please be patient while Evolution migrates your "
 +					    "folders..."));
 +
 +			migrate_company_phone_for_local_folders (context, on_this_computer);
 +		}
 +
 +		if (minor < 5 || (minor == 5 && micro <= 10)) {
 +			char *old_path, *new_path;
 +
 +			dialog_set_label (context, _("Evolution's Palm Sync changelog and map files have changed.\n\n"
 +						     "Please be patient while Evolution migrates your Pilot Sync data..."));
 +
 +			old_path = g_build_filename (g_get_home_dir (), "evolution", "local", "Contacts", NULL);
 +			new_path = g_build_filename (data_dir, "local", "system", NULL);
 +			migrate_pilot_data (old_path, new_path);
 +			g_free (new_path);
 +			g_free (old_path);
 +		}
 +
 +		/* we only need to do this next step if people ran
 +		   older versions of 1.5.  We need to clear out the
 +		   absolute URI's that were assigned to ESources
 +		   during one phase of development, as they take
 +		   precedent over relative uris (but aren't updated
 +		   when editing an ESource). */
 +		if (minor == 5 && micro <= 11) {
 +			GSList *g;
 +			for (g = e_source_list_peek_groups (context->source_list); g; g = g->next) {
 +				ESourceGroup *group = g->data;
 +				GSList *s;
 +
 +				for (s = e_source_group_peek_sources (group); s; s = s->next) {
 +					ESource *source = s->data;
 +					e_source_set_absolute_uri (source, NULL);
 +				}
 +			}
 +		}
 +	}
 +
 +	if (need_dialog)
 +		dialog_close (context);
 +
 +	if (on_this_computer)
 +		g_object_unref (on_this_computer);
 +	if (on_ldap_servers)
 +		g_object_unref (on_ldap_servers);
 +	if (personal_source)
 +		g_object_unref (personal_source);
 +
 +
 +	migration_context_free (context);
 +
 +	return TRUE;
 +}
diff --cc addressbook/gui/component/e-book-shell-migrate.h
index f631ef6,0000000..cb61289
mode 100644,000000..100644
--- a/addressbook/gui/component/e-book-shell-migrate.h
+++ b/addressbook/gui/component/e-book-shell-migrate.h
@@@ -1,41 -1,0 +1,41 @@@
 +/*
 + * e-book-shell-migrate.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Authors:
 + *		Chris Toshok (toshok ximian com)
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_BOOK_SHELL_MIGRATE_H
 +#define E_BOOK_SHELL_MIGRATE_H
 +
 +#include <glib.h>
 +#include <shell/e-shell-backend.h>
 +
 +G_BEGIN_DECLS
 +
 +gboolean	e_book_shell_backend_migrate	(EShellBackend *shell_backend,
 +						 gint major,
 +						 gint minor,
 +						 gint micro,
 +						 GError **error);
 +
 +G_END_DECLS
 +
 +#endif /* E_BOOK_SHELL_MIGRATE_H */
diff --cc addressbook/gui/component/e-book-shell-sidebar.c
index 2a784e3,0000000..fc283e2
mode 100644,000000..100644
--- a/addressbook/gui/component/e-book-shell-sidebar.c
+++ b/addressbook/gui/component/e-book-shell-sidebar.c
@@@ -1,232 -1,0 +1,232 @@@
 +/*
 + * e-book-shell-sidebar.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-book-shell-sidebar.h"
 +
 +#include <string.h>
 +#include <glib/gi18n.h>
 +
 +#include "e-book-shell-view.h"
 +#include "e-book-shell-backend.h"
 +#include "e-addressbook-selector.h"
 +
 +#define E_BOOK_SHELL_SIDEBAR_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_BOOK_SHELL_SIDEBAR, EBookShellSidebarPrivate))
 +
 +struct _EBookShellSidebarPrivate {
 +	GtkWidget *selector;
 +};
 +
 +enum {
 +	PROP_0,
 +	PROP_SELECTOR
 +};
 +
 +static gpointer parent_class;
 +static GType book_shell_sidebar_type;
 +
 +static void
 +book_shell_sidebar_get_property (GObject *object,
 +                                 guint property_id,
 +                                 GValue *value,
 +                                 GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_SELECTOR:
 +			g_value_set_object (
 +				value, e_book_shell_sidebar_get_selector (
 +				E_BOOK_SHELL_SIDEBAR (object)));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +book_shell_sidebar_dispose (GObject *object)
 +{
 +	EBookShellSidebarPrivate *priv;
 +
 +	priv = E_BOOK_SHELL_SIDEBAR_GET_PRIVATE (object);
 +
 +	if (priv->selector != NULL) {
 +		g_object_unref (priv->selector);
 +		priv->selector = NULL;
 +	}
 +
 +	/* Chain up to parent's dispose() method. */
 +	G_OBJECT_CLASS (parent_class)->dispose (object);
 +}
 +
 +static void
 +book_shell_sidebar_constructed (GObject *object)
 +{
 +	EBookShellSidebarPrivate *priv;
 +	EShellView *shell_view;
 +	EShellBackend *shell_backend;
 +	EShellSidebar *shell_sidebar;
 +	ESourceList *source_list;
 +	GtkContainer *container;
 +	GtkWidget *widget;
 +
 +	priv = E_BOOK_SHELL_SIDEBAR_GET_PRIVATE (object);
 +
 +	/* Chain up to parent's constructed() method. */
 +	G_OBJECT_CLASS (parent_class)->constructed (object);
 +
 +	shell_sidebar = E_SHELL_SIDEBAR (object);
 +	shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
 +	shell_backend = e_shell_view_get_shell_backend (shell_view);
 +
 +	source_list = e_book_shell_backend_get_source_list (
 +		E_BOOK_SHELL_BACKEND (shell_backend));
 +
 +	container = GTK_CONTAINER (shell_sidebar);
 +
 +	widget = gtk_scrolled_window_new (NULL, NULL);
 +	gtk_scrolled_window_set_policy (
 +		GTK_SCROLLED_WINDOW (widget),
 +		GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
 +	gtk_scrolled_window_set_shadow_type (
 +		GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
 +	gtk_container_add (container, widget);
 +	gtk_widget_show (widget);
 +
 +	container = GTK_CONTAINER (widget);
 +
 +	widget = e_addressbook_selector_new (source_list);
 +	e_source_selector_show_selection (E_SOURCE_SELECTOR (widget), FALSE);
 +	gtk_container_add (GTK_CONTAINER (container), widget);
 +	priv->selector = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +}
 +
 +static guint32
 +book_shell_sidebar_check_state (EShellSidebar *shell_sidebar)
 +{
 +	EBookShellSidebar *book_shell_sidebar;
 +	ESourceSelector *selector;
 +	ESource *source;
 +	gboolean is_system = FALSE;
 +	guint32 state = 0;
 +
 +	book_shell_sidebar = E_BOOK_SHELL_SIDEBAR (shell_sidebar);
 +	selector = e_book_shell_sidebar_get_selector (book_shell_sidebar);
 +	source = e_source_selector_peek_primary_selection (selector);
 +
 +	if (source != NULL) {
 +		const gchar *uri;
 +
 +		uri = e_source_peek_relative_uri (source);
 +		is_system = (uri == NULL || strcmp (uri, "system") == 0);
 +	}
 +
 +	if (source != NULL)
 +		state |= E_BOOK_SHELL_SIDEBAR_HAS_PRIMARY_SOURCE;
 +	if (is_system)
 +		state |= E_BOOK_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_SYSTEM;
 +
 +	return state;
 +}
 +
 +static void
 +book_shell_sidebar_class_init (EBookShellSidebarClass *class)
 +{
 +	GObjectClass *object_class;
 +	EShellSidebarClass *shell_sidebar_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (EBookShellSidebarPrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->get_property = book_shell_sidebar_get_property;
 +	object_class->dispose = book_shell_sidebar_dispose;
 +	object_class->constructed = book_shell_sidebar_constructed;
 +
 +	shell_sidebar_class = E_SHELL_SIDEBAR_CLASS (class);
 +	shell_sidebar_class->check_state = book_shell_sidebar_check_state;
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_SELECTOR,
 +		g_param_spec_object (
 +			"selector",
 +			_("Source Selector Widget"),
 +			_("This widget displays groups of address books"),
 +			E_TYPE_SOURCE_SELECTOR,
 +			G_PARAM_READABLE));
 +}
 +
 +static void
 +book_shell_sidebar_init (EBookShellSidebar *book_shell_sidebar)
 +{
 +	book_shell_sidebar->priv =
 +		E_BOOK_SHELL_SIDEBAR_GET_PRIVATE (book_shell_sidebar);
 +
 +	/* Postpone widget construction until we have a shell view. */
 +}
 +
 +GType
 +e_book_shell_sidebar_get_type (void)
 +{
 +	return book_shell_sidebar_type;
 +}
 +
 +void
 +e_book_shell_sidebar_register_type (GTypeModule *type_module)
 +{
 +	static const GTypeInfo type_info = {
 +		sizeof (EBookShellSidebarClass),
 +		(GBaseInitFunc) NULL,
 +		(GBaseFinalizeFunc) NULL,
 +		(GClassInitFunc) book_shell_sidebar_class_init,
 +		(GClassFinalizeFunc) NULL,
 +		NULL,  /* class_data */
 +		sizeof (EBookShellSidebar),
 +		0,     /* n_preallocs */
 +		(GInstanceInitFunc) book_shell_sidebar_init,
 +		NULL   /* value_table */
 +	};
 +
 +	book_shell_sidebar_type = g_type_module_register_type (
 +		type_module, E_TYPE_SHELL_SIDEBAR,
 +		"EBookShellSidebar", &type_info, 0);
 +}
 +
 +GtkWidget *
 +e_book_shell_sidebar_new (EShellView *shell_view)
 +{
 +	g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
 +
 +	return g_object_new (
 +		E_TYPE_BOOK_SHELL_SIDEBAR,
 +		"shell-view", shell_view, NULL);
 +}
 +
 +ESourceSelector *
 +e_book_shell_sidebar_get_selector (EBookShellSidebar *book_shell_sidebar)
 +{
 +	g_return_val_if_fail (
 +		E_IS_BOOK_SHELL_SIDEBAR (book_shell_sidebar), NULL);
 +
 +	return E_SOURCE_SELECTOR (book_shell_sidebar->priv->selector);
 +}
diff --cc addressbook/gui/component/e-book-shell-sidebar.h
index e2523f5,0000000..716523f
mode 100644,000000..100644
--- a/addressbook/gui/component/e-book-shell-sidebar.h
+++ b/addressbook/gui/component/e-book-shell-sidebar.h
@@@ -1,79 -1,0 +1,79 @@@
 +/*
 + * e-book-shell-sidebar.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_BOOK_SHELL_SIDEBAR_H
 +#define E_BOOK_SHELL_SIDEBAR_H
 +
 +#include <libedataserverui/e-source-selector.h>
 +
 +#include <shell/e-shell-sidebar.h>
 +#include <shell/e-shell-view.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_BOOK_SHELL_SIDEBAR \
 +	(e_book_shell_sidebar_get_type ())
 +#define E_BOOK_SHELL_SIDEBAR(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_BOOK_SHELL_SIDEBAR, EBookShellSidebar))
 +#define E_BOOK_SHELL_SIDEBAR_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_BOOK_SHELL_SIDEBAR, EBookShellSidebarClass))
 +#define E_IS_BOOK_SHELL_SIDEBAR(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_BOOK_SHELL_SIDEBAR))
 +#define E_IS_BOOK_SHELL_SIDEBAR_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), E_TYPE_BOOK_SHELL_SIDEBAR))
 +#define E_BOOK_SHELL_SIDEBAR_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_BOOK_SHELL_SIDEBAR, EBookShellSidebarClass))
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _EBookShellSidebar EBookShellSidebar;
 +typedef struct _EBookShellSidebarClass EBookShellSidebarClass;
 +typedef struct _EBookShellSidebarPrivate EBookShellSidebarPrivate;
 +
 +enum {
 +	E_BOOK_SHELL_SIDEBAR_HAS_PRIMARY_SOURCE		= 1 << 0,
 +	E_BOOK_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_SYSTEM	= 1 << 1
 +};
 +
 +struct _EBookShellSidebar {
 +	EShellSidebar parent;
 +	EBookShellSidebarPrivate *priv;
 +};
 +
 +struct _EBookShellSidebarClass {
 +	EShellSidebarClass parent_class;
 +};
 +
 +GType		e_book_shell_sidebar_get_type	(void);
 +void		e_book_shell_sidebar_register_type
 +					(GTypeModule *type_module);
 +GtkWidget *	e_book_shell_sidebar_new(EShellView *shell_view);
 +ESourceSelector *
 +		e_book_shell_sidebar_get_selector
 +					(EBookShellSidebar *book_shell_sidebar);
 +
 +G_END_DECLS
 +
 +#endif /* E_BOOK_SHELL_SIDEBAR_H */
diff --cc addressbook/gui/component/e-book-shell-view-actions.c
index 918ff57,0000000..35d0e8f
mode 100644,000000..100644
--- a/addressbook/gui/component/e-book-shell-view-actions.c
+++ b/addressbook/gui/component/e-book-shell-view-actions.c
@@@ -1,982 -1,0 +1,982 @@@
 +/*
 + * e-book-shell-view-actions.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-book-shell-view-private.h"
 +
 +#include <e-util/e-error.h>
 +#include <e-util/e-util.h>
 +#include <filter/filter-rule.h>
 +
 +#include <addressbook-config.h>
 +
 +static void
 +action_address_book_copy_cb (GtkAction *action,
 +                             EBookShellView *book_shell_view)
 +{
 +	EBookShellContent *book_shell_content;
 +	EAddressbookView *view;
 +
 +	book_shell_content = book_shell_view->priv->book_shell_content;
 +	view = e_book_shell_content_get_current_view (book_shell_content);
 +	g_return_if_fail (view != NULL);
 +
 +	e_addressbook_view_copy_to_folder (view, TRUE);
 +}
 +
 +static void
 +action_address_book_delete_cb (GtkAction *action,
 +                               EBookShellView *book_shell_view)
 +{
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	EBookShellBackend *book_shell_backend;
 +	EBookShellSidebar *book_shell_sidebar;
 +	ESource *source;
 +	ESourceSelector *selector;
 +	ESourceGroup *source_group;
 +	ESourceList *source_list;
 +	EBook *book;
 +	gint response;
 +	GError *error = NULL;
 +
 +	shell_view = E_SHELL_VIEW (book_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	book_shell_backend = book_shell_view->priv->book_shell_backend;
 +	source_list = e_book_shell_backend_get_source_list (book_shell_backend);
 +
 +	book_shell_sidebar = book_shell_view->priv->book_shell_sidebar;
 +	selector = e_book_shell_sidebar_get_selector (book_shell_sidebar);
 +	source = e_source_selector_peek_primary_selection (selector);
 +	g_return_if_fail (source != NULL);
 +
 +	response = e_error_run (
 +		GTK_WINDOW (shell_window),
 +		"addressbook:ask-delete-addressbook",
 +		e_source_peek_name (source));
 +
 +	if (response != GTK_RESPONSE_YES)
 +		return;
 +
 +	book = e_book_new (source, &error);
 +	if (error != NULL) {
 +		g_warning ("Error removing addressbook: %s", error->message);
 +		g_error_free (error);
 +		return;
 +	}
 +
 +	if (!e_book_remove (book, NULL)) {
 +		e_error_run (
 +			GTK_WINDOW (shell_window),
 +			"addressbook:remove-addressbook", NULL);
 +		g_object_unref (book);
 +		return;
 +	}
 +
 +	if (e_source_selector_source_is_selected (selector, source))
 +		e_source_selector_unselect_source (selector, source);
 +
 +	source_group = e_source_peek_group (source);
 +	e_source_group_remove_source (source_group, source);
 +
 +	e_source_list_sync (source_list, NULL);
 +
 +	g_object_unref (book);
 +}
 +
 +static void
 +action_address_book_move_cb (GtkAction *action,
 +                             EBookShellView *book_shell_view)
 +{
 +	EBookShellContent *book_shell_content;
 +	EAddressbookView *view;
 +
 +	book_shell_content = book_shell_view->priv->book_shell_content;
 +	view = e_book_shell_content_get_current_view (book_shell_content);
 +	g_return_if_fail (view != NULL);
 +
 +	e_addressbook_view_move_to_folder (view, TRUE);
 +}
 +
 +static void
 +action_address_book_new_cb (GtkAction *action,
 +                            EBookShellView *book_shell_view)
 +{
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +
 +	shell_view = E_SHELL_VIEW (book_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	addressbook_config_create_new_source (GTK_WIDGET (shell_window));
 +}
 +
 +static void
 +action_address_book_properties_cb (GtkAction *action,
 +                                   EBookShellView *book_shell_view)
 +{
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	EBookShellSidebar *book_shell_sidebar;
 +	ESource *source;
 +	ESourceSelector *selector;
 +	EditorUidClosure *closure;
 +	GHashTable *uid_to_editor;
 +	const gchar *uid;
 +
 +	shell_view = E_SHELL_VIEW (book_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	book_shell_sidebar = book_shell_view->priv->book_shell_sidebar;
 +	selector = e_book_shell_sidebar_get_selector (book_shell_sidebar);
 +	source = e_source_selector_peek_primary_selection (selector);
 +	g_return_if_fail (source != NULL);
 +
 +	uid = e_source_peek_uid (source);
 +	uid_to_editor = book_shell_view->priv->uid_to_editor;
 +
 +	closure = g_hash_table_lookup (uid_to_editor, uid);
 +	if (closure == NULL) {
 +		GtkWidget *editor;
 +
 +		editor = addressbook_config_edit_source (
 +			GTK_WIDGET (shell_window), source);
 +
 +		closure = g_new (EditorUidClosure, 1);
 +		closure->editor = editor;
 +		closure->uid = g_strdup (uid);
 +		closure->view = book_shell_view;
 +
 +		g_hash_table_insert (uid_to_editor, closure->uid, closure);
 +
 +		g_object_weak_ref (
 +			G_OBJECT (closure->editor), (GWeakNotify)
 +			e_book_shell_view_editor_weak_notify, closure);
 +	}
 +
 +	gtk_window_present (GTK_WINDOW (closure->editor));
 +}
 +
 +static void
 +action_address_book_rename_cb (GtkAction *action,
 +                               EBookShellView *book_shell_view)
 +{
 +	EBookShellSidebar *book_shell_sidebar;
 +	ESourceSelector *selector;
 +
 +	book_shell_sidebar = book_shell_view->priv->book_shell_sidebar;
 +	selector = e_book_shell_sidebar_get_selector (book_shell_sidebar);
 +
 +	e_source_selector_edit_primary_selection (selector);
 +}
 +
 +static void
 +action_address_book_save_as_cb (GtkAction *action,
 +                                EBookShellView *book_shell_view)
 +{
 +	EBookShellContent *book_shell_content;
 +	EAddressbookView *view;
 +
 +	book_shell_content = book_shell_view->priv->book_shell_content;
 +	view = e_book_shell_content_get_current_view (book_shell_content);
 +	g_return_if_fail (view != NULL);
 +
 +	e_addressbook_view_save_as (view, TRUE);
 +}
 +
 +static void
 +action_address_book_stop_cb (GtkAction *action,
 +                             EBookShellView *book_shell_view)
 +{
 +	EBookShellContent *book_shell_content;
 +	EAddressbookView *view;
 +
 +	book_shell_content = book_shell_view->priv->book_shell_content;
 +	view = e_book_shell_content_get_current_view (book_shell_content);
 +	g_return_if_fail (view != NULL);
 +
 +	e_addressbook_view_stop (view);
 +}
 +
 +static void
 +action_contact_clipboard_copy_cb (GtkAction *action,
 +                                  EBookShellView *book_shell_view)
 +{
 +	EBookShellContent *book_shell_content;
 +
 +	book_shell_content = book_shell_view->priv->book_shell_content;
 +	e_book_shell_content_clipboard_copy (book_shell_content);
 +}
 +
 +static void
 +action_contact_clipboard_cut_cb (GtkAction *action,
 +                                 EBookShellView *book_shell_view)
 +{
 +	EBookShellContent *book_shell_content;
 +	EAddressbookView *view;
 +
 +	book_shell_content = book_shell_view->priv->book_shell_content;
 +	view = e_book_shell_content_get_current_view (book_shell_content);
 +	g_return_if_fail (view != NULL);
 +
 +	e_addressbook_view_cut (view);
 +}
 +
 +static void
 +action_contact_clipboard_paste_cb (GtkAction *action,
 +                                   EBookShellView *book_shell_view)
 +{
 +	EBookShellContent *book_shell_content;
 +	EAddressbookView *view;
 +
 +	book_shell_content = book_shell_view->priv->book_shell_content;
 +	view = e_book_shell_content_get_current_view (book_shell_content);
 +	g_return_if_fail (view != NULL);
 +
 +	e_addressbook_view_paste (view);
 +}
 +
 +static void
 +action_contact_copy_cb (GtkAction *action,
 +                        EBookShellView *book_shell_view)
 +{
 +	EBookShellContent *book_shell_content;
 +	EAddressbookView *view;
 +
 +	book_shell_content = book_shell_view->priv->book_shell_content;
 +	view = e_book_shell_content_get_current_view (book_shell_content);
 +	g_return_if_fail (view != NULL);
 +
 +	e_addressbook_view_copy_to_folder (view, FALSE);
 +}
 +
 +static void
 +action_contact_delete_cb (GtkAction *action,
 +                          EBookShellView *book_shell_view)
 +{
 +	EBookShellContent *book_shell_content;
 +	EAddressbookView *view;
 +
 +	book_shell_content = book_shell_view->priv->book_shell_content;
 +	view = e_book_shell_content_get_current_view (book_shell_content);
 +	g_return_if_fail (view != NULL);
 +
 +	e_addressbook_view_delete_selection (view, TRUE);
 +}
 +
 +static void
 +action_contact_forward_cb (GtkAction *action,
 +                           EBookShellView *book_shell_view)
 +{
 +	EBookShellContent *book_shell_content;
 +	EAddressbookView *view;
 +	GList *list, *iter;
 +
 +	book_shell_content = book_shell_view->priv->book_shell_content;
 +	view = e_book_shell_content_get_current_view (book_shell_content);
 +	g_return_if_fail (view != NULL);
 +
 +	list = e_addressbook_view_get_selected (view);
 +	g_return_if_fail (list != NULL);
 +
 +	/* Convert the list of contacts to a list of destinations. */
 +	for (iter = list; iter != NULL; iter = iter->next) {
 +		EContact *contact = iter->data;
 +		EDestination *destination;
 +
 +		destination = e_destination_new ();
 +		e_destination_set_contact (destination, contact, 0);
 +		g_object_unref (contact);
 +
 +		iter->data = destination;
 +	}
 +
 +	eab_send_as_attachment (list);
 +	g_list_foreach (list, (GFunc) g_object_unref, NULL);
 +	g_list_free (list);
 +}
 +
 +static void
 +action_contact_move_cb (GtkAction *action,
 +                        EBookShellView *book_shell_view)
 +{
 +	EBookShellContent *book_shell_content;
 +	EAddressbookView *view;
 +
 +	book_shell_content = book_shell_view->priv->book_shell_content;
 +	view = e_book_shell_content_get_current_view (book_shell_content);
 +	g_return_if_fail (view != NULL);
 +
 +	e_addressbook_view_move_to_folder (view, FALSE);
 +}
 +
 +static void
 +action_contact_new_cb (GtkAction *action,
 +                       EBookShellView *book_shell_view)
 +{
 +	EBookShellContent *book_shell_content;
 +	EAddressbookView *view;
 +	EAddressbookModel *model;
 +	EContact *contact;
 +	GtkWidget *editor;
 +	EBook *book;
 +
 +	book_shell_content = book_shell_view->priv->book_shell_content;
 +	view = e_book_shell_content_get_current_view (book_shell_content);
 +	g_return_if_fail (view != NULL);
 +
 +	model = e_addressbook_view_get_model (view);
 +	book = e_addressbook_model_get_book (model);
 +	g_return_if_fail (book != NULL);
 +
 +	contact = e_contact_new ();
 +	editor = e_contact_editor_new (book, contact, TRUE, TRUE);
 +	eab_editor_show (EAB_EDITOR (editor));
 +	g_object_unref (contact);
 +}
 +
 +static void
 +action_contact_new_list_cb (GtkAction *action,
 +                            EBookShellView *book_shell_view)
 +{
 +	EBookShellContent *book_shell_content;
 +	EAddressbookView *view;
 +	EAddressbookModel *model;
 +	EContact *contact;
 +	GtkWidget *editor;
 +	EBook *book;
 +
 +	book_shell_content = book_shell_view->priv->book_shell_content;
 +	view = e_book_shell_content_get_current_view (book_shell_content);
 +	g_return_if_fail (view != NULL);
 +
 +	model = e_addressbook_view_get_model (view);
 +	book = e_addressbook_model_get_book (model);
 +	g_return_if_fail (book != NULL);
 +
 +	contact = e_contact_new ();
 +	editor = e_contact_list_editor_new (book, contact, TRUE, TRUE);
 +	eab_editor_show (EAB_EDITOR (editor));
 +	g_object_unref (contact);
 +}
 +
 +static void
 +action_contact_open_cb (GtkAction *action,
 +                        EBookShellView *book_shell_view)
 +{
 +	EBookShellContent *book_shell_content;
 +	EAddressbookView *view;
 +
 +	book_shell_content = book_shell_view->priv->book_shell_content;
 +	view = e_book_shell_content_get_current_view (book_shell_content);
 +	g_return_if_fail (view != NULL);
 +
 +	e_addressbook_view_view (view);
 +}
 +
 +static void
 +action_contact_preview_cb (GtkToggleAction *action,
 +                           EBookShellView *book_shell_view)
 +{
 +	EBookShellContent *book_shell_content;
 +	gboolean visible;
 +
 +	book_shell_content = book_shell_view->priv->book_shell_content;
 +	visible = gtk_toggle_action_get_active (action);
 +	e_book_shell_content_set_preview_visible (book_shell_content, visible);
 +}
 +
 +static void
 +action_contact_print_cb (GtkAction *action,
 +                         EBookShellView *book_shell_view)
 +{
 +	EBookShellContent *book_shell_content;
 +	EAddressbookView *view;
 +	GtkPrintOperationAction print_action;
 +
 +	book_shell_content = book_shell_view->priv->book_shell_content;
 +	view = e_book_shell_content_get_current_view (book_shell_content);
 +	g_return_if_fail (view != NULL);
 +
 +	print_action = GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG;
 +	e_addressbook_view_print (view, print_action);
 +}
 +
 +static void
 +action_contact_print_preview_cb (GtkAction *action,
 +                                 EBookShellView *book_shell_view)
 +{
 +	EBookShellContent *book_shell_content;
 +	EAddressbookView *view;
 +	GtkPrintOperationAction print_action;
 +
 +	book_shell_content = book_shell_view->priv->book_shell_content;
 +	view = e_book_shell_content_get_current_view (book_shell_content);
 +	g_return_if_fail (view != NULL);
 +
 +	print_action = GTK_PRINT_OPERATION_ACTION_PREVIEW;
 +	e_addressbook_view_print (view, print_action);
 +}
 +
 +static void
 +action_contact_save_as_cb (GtkAction *action,
 +                           EBookShellView *book_shell_view)
 +{
 +	EBookShellContent *book_shell_content;
 +	EAddressbookView *view;
 +
 +	book_shell_content = book_shell_view->priv->book_shell_content;
 +	view = e_book_shell_content_get_current_view (book_shell_content);
 +	g_return_if_fail (view != NULL);
 +
 +	e_addressbook_view_save_as (view, FALSE);
 +}
 +
 +static void
 +action_contact_select_all_cb (GtkAction *action,
 +                              EBookShellView *book_shell_view)
 +{
 +	EBookShellContent *book_shell_content;
 +	EAddressbookView *view;
 +
 +	book_shell_content = book_shell_view->priv->book_shell_content;
 +	view = e_book_shell_content_get_current_view (book_shell_content);
 +	g_return_if_fail (view != NULL);
 +
 +	e_addressbook_view_select_all (view);
 +}
 +
 +static void
 +action_contact_send_message_cb (GtkAction *action,
 +                                EBookShellView *book_shell_view)
 +{
 +	EBookShellContent *book_shell_content;
 +	EAddressbookView *view;
 +	GList *list, *iter;
 +
 +	book_shell_content = book_shell_view->priv->book_shell_content;
 +	view = e_book_shell_content_get_current_view (book_shell_content);
 +	g_return_if_fail (view != NULL);
 +
 +	list = e_addressbook_view_get_selected (view);
 +	g_return_if_fail (list != NULL);
 +
 +	/* Convert the list of contacts to a list of destinations. */
 +	for (iter = list; iter != NULL; iter = iter->next) {
 +		EContact *contact = iter->data;
 +		EDestination *destination;
 +
 +		destination = e_destination_new ();
 +		e_destination_set_contact (destination, contact, 0);
 +		g_object_unref (contact);
 +
 +		iter->data = destination;
 +	}
 +
 +	eab_send_as_to (list);
 +	g_list_foreach (list, (GFunc) g_object_unref, NULL);
 +	g_list_free (list);
 +}
 +
 +static void
 +action_gal_save_custom_view_cb (GtkAction *action,
 +                                EBookShellView *book_shell_view)
 +{
 +	EBookShellContent *book_shell_content;
 +	EShellView *shell_view;
 +	EAddressbookView *address_view;
 +	GalViewInstance *view_instance;
 +
 +	/* All shell views respond to the activation of this action,
 +	 * which is defined by EShellWindow.  But only the currently
 +	 * active shell view proceeds with saving the custom view. */
 +	shell_view = E_SHELL_VIEW (book_shell_view);
 +	if (!e_shell_view_is_active (shell_view))
 +		return;
 +
 +	book_shell_content = book_shell_view->priv->book_shell_content;
 +	address_view = e_book_shell_content_get_current_view (book_shell_content);
 +	view_instance = e_addressbook_view_get_view_instance (address_view);
 +	gal_view_instance_save_as (view_instance);
 +}
 +
 +static void
 +action_search_execute_cb (GtkAction *action,
 +                          EBookShellView *book_shell_view)
 +{
 +	EShellView *shell_view;
 +
 +	/* All shell views respond to the activation of this action,
 +	 * which is defined by EShellWindow.  But only the currently
 +	 * active shell view proceeds with executing the search. */
 +	shell_view = E_SHELL_VIEW (book_shell_view);
 +	if (!e_shell_view_is_active (shell_view))
 +		return;
 +
 +	e_book_shell_view_execute_search (book_shell_view);
 +}
 +
 +static void
 +action_search_filter_cb (GtkRadioAction *action,
 +                         GtkRadioAction *current,
 +                         EBookShellView *book_shell_view)
 +{
 +	e_book_shell_view_execute_search (book_shell_view);
 +}
 +
 +static GtkActionEntry contact_entries[] = {
 +
 +	{ "address-book-copy",
 +	  GTK_STOCK_COPY,
 +	  N_("Co_py All Contacts To..."),
 +	  NULL,
 +	  N_("Copy the contacts of the selected address book to another"),
 +	  G_CALLBACK (action_address_book_copy_cb) },
 +
 +	{ "address-book-delete",
 +	  GTK_STOCK_DELETE,
 +	  N_("Del_ete Address Book"),
 +	  NULL,
 +	  N_("Delete the selected address book"),
 +	  G_CALLBACK (action_address_book_delete_cb) },
 +
 +	{ "address-book-move",
 +	  "folder-move",
 +	  N_("Mo_ve All Contacts To..."),
 +	  NULL,
 +	  N_("Move the contacts of the selected address book to another"),
 +	  G_CALLBACK (action_address_book_move_cb) },
 +
 +	{ "address-book-new",
 +	  "address-book-new",
 +	  N_("_New Address Book"),
 +	  NULL,
 +	  N_("Create a new address book"),
 +	  G_CALLBACK (action_address_book_new_cb) },
 +
 +	{ "address-book-properties",
 +	  GTK_STOCK_PROPERTIES,
 +	  N_("Address _Book Properties"),
 +	  NULL,
 +	  N_("Show properties of the selected address book"),
 +	  G_CALLBACK (action_address_book_properties_cb) },
 +
 +	{ "address-book-rename",
 +	  NULL,
 +	  N_("_Rename..."),
 +	  "F2",
 +	  N_("Rename the selected address book"),
 +	  G_CALLBACK (action_address_book_rename_cb) },
 +
 +	{ "address-book-save-as",
 +	  GTK_STOCK_SAVE_AS,
 +	  N_("S_ave Address Book as vCard"),
 +	  NULL,
 +	  N_("Save the contacts of the selected address book as a vCard"),
 +	  G_CALLBACK (action_address_book_save_as_cb) },
 +
 +	{ "address-book-stop",
 +	  GTK_STOCK_STOP,
 +	  NULL,
 +	  NULL,
 +	  N_("Stop loading"),
 +	  G_CALLBACK (action_address_book_stop_cb) },
 +
 +	{ "contact-clipboard-copy",
 +	  GTK_STOCK_COPY,
 +	  NULL,
 +	  NULL,
 +	  N_("Copy the selection"),
 +	  G_CALLBACK (action_contact_clipboard_copy_cb) },
 +
 +	{ "contact-clipboard-cut",
 +	  GTK_STOCK_CUT,
 +	  NULL,
 +	  NULL,
 +	  N_("Cut the selection"),
 +	  G_CALLBACK (action_contact_clipboard_cut_cb) },
 +
 +	{ "contact-clipboard-paste",
 +	  GTK_STOCK_PASTE,
 +	  NULL,
 +	  NULL,
 +	  N_("Paste the clipboard"),
 +	  G_CALLBACK (action_contact_clipboard_paste_cb) },
 +
 +	{ "contact-copy",
 +	  NULL,
 +	  N_("_Copy Contact To..."),
 +	  "<Control><Shift>y",
 +	  N_("Copy selected contacts to another address book"),
 +	  G_CALLBACK (action_contact_copy_cb) },
 +
 +	{ "contact-delete",
 +	  GTK_STOCK_DELETE,
 +	  N_("_Delete Contact"),
 +	  "<Control>d",
 +	  N_("Delete selected contacts"),
 +	  G_CALLBACK (action_contact_delete_cb) },
 +
 +	{ "contact-forward",
 +	  "mail-forward",
 +	  N_("_Forward Contact..."),
 +	  NULL,
 +	  N_("Send selected contacts to another person"),
 +	  G_CALLBACK (action_contact_forward_cb) },
 +
 +	{ "contact-move",
 +	  NULL,
 +	  N_("_Move Contact To..."),
 +	  "<Control><Shift>v",
 +	  N_("Move selected contacts to another address book"),
 +	  G_CALLBACK (action_contact_move_cb) },
 +
 +	{ "contact-new",
 +	  "contact-new",
 +	  N_("_New Contact..."),
 +	  NULL,
 +	  N_("Create a new contact"),
 +	  G_CALLBACK (action_contact_new_cb) },
 +
 +	{ "contact-new-list",
 +	  "stock_contact-list",
 +	  N_("New Contact _List..."),
 +	  NULL,
 +	  N_("Create a new contact list"),
 +	  G_CALLBACK (action_contact_new_list_cb) },
 +
 +	{ "contact-open",
 +	  NULL,
 +	  N_("_Open"),
 +	  "<Control>o",
 +	  N_("View the current contact"),
 +	  G_CALLBACK (action_contact_open_cb) },
 +
 +	{ "contact-save-as",
 +	  GTK_STOCK_SAVE_AS,
 +	  N_("Save as vCard..."),
 +	  NULL,
 +	  N_("Save selected contacts as a vCard"),
 +	  G_CALLBACK (action_contact_save_as_cb) },
 +
 +	{ "contact-select-all",
 +	  GTK_STOCK_SELECT_ALL,
 +	  NULL,
 +	  NULL,
 +	  N_("Select all contacts"),
 +	  G_CALLBACK (action_contact_select_all_cb) },
 +
 +	{ "contact-send-message",
 +	  "mail-message-new",
 +	  N_("_Send Message to Contact..."),
 +	  NULL,
 +	  N_("Send a message to the selected contacts"),
 +	  G_CALLBACK (action_contact_send_message_cb) },
 +
 +	/*** Menus ***/
 +
 +	{ "actions-menu",
 +	  NULL,
 +	  N_("_Actions"),
 +	  NULL,
 +	  NULL,
 +	  NULL }
 +};
 +
 +static EPopupActionEntry contact_popup_entries[] = {
 +
 +	{ "address-book-popup-delete",
 +	  N_("_Delete"),
 +	  "address-book-delete" },
 +
 +	{ "address-book-popup-properties",
 +	  N_("_Properties"),
 +	  "address-book-properties" },
 +
 +	{ "address-book-popup-rename",
 +	  NULL,
 +	  "address-book-rename" },
 +
 +	{ "address-book-popup-save-as",
 +	  N_("_Save as vCard..."),
 +	  "address-book-save-as" },
 +
 +	{ "contact-popup-clipboard-copy",
 +	  NULL,
 +	  "contact-clipboard-copy" },
 +
 +	{ "contact-popup-clipboard-cut",
 +	  NULL,
 +	  "contact-clipboard-cut" },
 +
 +	{ "contact-popup-clipboard-paste",
 +	  NULL,
 +	  "contact-clipboard-paste" },
 +
 +	{ "contact-popup-copy",
 +	  NULL,
 +	  "contact-copy" },
 +
 +	{ "contact-popup-delete",
 +	  NULL,
 +	  "contact-delete" },
 +
 +	{ "contact-popup-forward",
 +	  NULL,
 +	  "contact-forward" },
 +
 +	{ "contact-popup-move",
 +	  NULL,
 +	  "contact-move" },
 +
 +	{ "contact-popup-open",
 +	  NULL,
 +	  "contact-open" },
 +
 +	{ "contact-popup-save-as",
 +	  NULL,
 +	  "contact-save-as" },
 +
 +	{ "contact-popup-send-message",
 +	  NULL,
 +	  "contact-send-message" },
 +};
 +
 +static GtkToggleActionEntry contact_toggle_entries[] = {
 +
 +	{ "contact-preview",
 +	  NULL,
 +	  N_("Contact _Preview"),
 +	  "<Control>m",
 +	  N_("Show contact preview window"),
 +	  G_CALLBACK (action_contact_preview_cb),
 +	  TRUE }
 +};
 +
 +static GtkRadioActionEntry contact_filter_entries[] = {
 +
 +	{ "contact-filter-any-category",
 +	  NULL,
 +	  N_("Any Category"),
 +	  NULL,
 +	  NULL,
 +	  CONTACT_FILTER_ANY_CATEGORY },
 +
 +	{ "contact-filter-unmatched",
 +	  NULL,
 +	  N_("Unmatched"),
 +	  NULL,
 +	  NULL,
 +	  CONTACT_FILTER_UNMATCHED }
 +};
 +
 +static GtkRadioActionEntry contact_search_entries[] = {
 +
 +	{ "contact-search-any-field-contains",
 +	  NULL,
 +	  N_("Any field contains"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  CONTACT_SEARCH_ANY_FIELD_CONTAINS },
 +
 +	{ "contact-search-email-begins-with",
 +	  NULL,
 +	  N_("Email begins with"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  CONTACT_SEARCH_EMAIL_BEGINS_WITH },
 +
 +	{ "contact-search-name-contains",
 +	  NULL,
 +	  N_("Name contains"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  CONTACT_SEARCH_NAME_CONTAINS }
 +};
 +
 +static GtkActionEntry lockdown_printing_entries[] = {
 +
 +	{ "contact-print",
 +	  GTK_STOCK_PRINT,
 +	  NULL,
 +	  "<Control>p",
 +	  N_("Print selected contacts"),
 +	  G_CALLBACK (action_contact_print_cb) },
 +
 +	{ "contact-print-preview",
 +	  GTK_STOCK_PRINT_PREVIEW,
 +	  NULL,
 +	  NULL,
 +	  N_("Preview the contacts to be printed"),
 +	  G_CALLBACK (action_contact_print_preview_cb) }
 +};
 +
 +static EPopupActionEntry lockdown_printing_popup_entries[] = {
 +
 +	{ "contact-popup-print",
 +	  NULL,
 +	  "contact-print" }
 +};
 +
 +void
 +e_book_shell_view_actions_init (EBookShellView *book_shell_view)
 +{
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	GtkActionGroup *action_group;
 +	GConfBridge *bridge;
 +	GtkAction *action;
 +	GObject *object;
 +	const gchar *key;
 +
 +	shell_view = E_SHELL_VIEW (book_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	/* Contact Actions */
 +	action_group = ACTION_GROUP (CONTACTS);
 +	gtk_action_group_add_actions (
 +		action_group, contact_entries,
 +		G_N_ELEMENTS (contact_entries), book_shell_view);
 +	e_action_group_add_popup_actions (
 +		action_group, contact_popup_entries,
 +		G_N_ELEMENTS (contact_popup_entries));
 +	gtk_action_group_add_toggle_actions (
 +		action_group, contact_toggle_entries,
 +		G_N_ELEMENTS (contact_toggle_entries), book_shell_view);
 +	gtk_action_group_add_radio_actions (
 +		action_group, contact_search_entries,
 +		G_N_ELEMENTS (contact_search_entries),
 +		CONTACT_SEARCH_NAME_CONTAINS,
 +		NULL, NULL);
 +
 +	/* Lockdown Printing Actions */
 +	action_group = ACTION_GROUP (LOCKDOWN_PRINTING);
 +	gtk_action_group_add_actions (
 +		action_group, lockdown_printing_entries,
 +		G_N_ELEMENTS (lockdown_printing_entries), book_shell_view);
 +	e_action_group_add_popup_actions (
 +		action_group, lockdown_printing_popup_entries,
 +		G_N_ELEMENTS (lockdown_printing_popup_entries));
 +
 +	/* Bind GObject properties to GConf keys. */
 +
 +	bridge = gconf_bridge_get ();
 +
 +	object = G_OBJECT (ACTION (CONTACT_PREVIEW));
 +	key = "/apps/evolution/addressbook/display/show_preview";
 +	gconf_bridge_bind_property (bridge, key, object, "active");
 +
 +	/* Fine tuning. */
 +
 +	action = ACTION (CONTACT_DELETE);
 +	g_object_set (action, "short-label", _("Delete"), NULL);
 +
 +	g_signal_connect (
 +		ACTION (GAL_SAVE_CUSTOM_VIEW), "activate",
 +		G_CALLBACK (action_gal_save_custom_view_cb), book_shell_view);
 +
 +	g_signal_connect (
 +		ACTION (SEARCH_EXECUTE), "activate",
 +		G_CALLBACK (action_search_execute_cb), book_shell_view);
 +}
 +
 +void
 +e_book_shell_view_update_search_filter (EBookShellView *book_shell_view)
 +{
 +	EShellView *shell_view;
 +	EShellContent *shell_content;
 +	EShellWindow *shell_window;
 +	GtkActionGroup *action_group;
 +	GtkRadioAction *radio_action;
 +	GList *list, *iter;
 +	GSList *group;
 +	gint ii;
 +
 +	shell_view = E_SHELL_VIEW (book_shell_view);
 +	shell_content = e_shell_view_get_shell_content (shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	action_group = ACTION_GROUP (CONTACTS_FILTER);
 +	e_action_group_remove_all_actions (action_group);
 +
 +	/* Add the standard filter actions. */
 +	gtk_action_group_add_radio_actions (
 +		action_group, contact_filter_entries,
 +		G_N_ELEMENTS (contact_filter_entries),
 +		CONTACT_FILTER_ANY_CATEGORY,
 +		G_CALLBACK (action_search_filter_cb),
 +		book_shell_view);
 +
 +	/* Retrieve the radio group from an action we just added. */
 +	list = gtk_action_group_list_actions (action_group);
 +	radio_action = GTK_RADIO_ACTION (list->data);
 +	group = gtk_radio_action_get_group (radio_action);
 +	g_list_free (list);
 +
 +	/* Build the category actions. */
 +
 +	list = e_categories_get_list ();
 +	for (iter = list, ii = 0; iter != NULL; iter = iter->next, ii++) {
 +		const gchar *category_name = iter->data;
 +		const gchar *filename;
 +		GtkAction *action;
 +		gchar *action_name;
 +
 +		action_name = g_strdup_printf (
 +			"contact-filter-category-%d", ii);
 +		radio_action = gtk_radio_action_new (
 +			action_name, category_name, NULL, NULL, ii);
 +		g_free (action_name);
 +
 +		/* Convert the category icon file to a themed icon name. */
 +		filename = e_categories_get_icon_file_for (category_name);
 +		if (filename != NULL && *filename != '\0') {
 +			gchar *basename;
 +			gchar *cp;
 +
 +			basename = g_path_get_basename (filename);
 +
 +			/* Lose the file extension. */
 +			if ((cp = strrchr (basename, '.')) != NULL)
 +				*cp = '\0';
 +
 +			g_object_set (
 +				radio_action, "icon-name", basename, NULL);
 +
 +			g_free (basename);
 +		}
 +
 +		gtk_radio_action_set_group (radio_action, group);
 +		group = gtk_radio_action_get_group (radio_action);
 +
 +		/* The action group takes ownership of the action. */
 +		action = GTK_ACTION (radio_action);
 +		gtk_action_group_add_action (action_group, action);
 +		g_object_unref (radio_action);
 +	}
 +	g_list_free (list);
 +
 +	/* Use any action in the group; doesn't matter which. */
 +	e_shell_content_set_filter_action (shell_content, radio_action);
 +
 +	ii = CONTACT_FILTER_UNMATCHED;
 +	e_shell_content_add_filter_separator_after (shell_content, ii);
 +}
diff --cc addressbook/gui/component/e-book-shell-view-actions.h
index 503855d,0000000..8e3d31f
mode 100644,000000..100644
--- a/addressbook/gui/component/e-book-shell-view-actions.h
+++ b/addressbook/gui/component/e-book-shell-view-actions.h
@@@ -1,91 -1,0 +1,91 @@@
 +/*
 + * e-book-shell-view-actions.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_BOOK_SHELL_VIEW_ACTIONS_H
 +#define E_BOOK_SHELL_VIEW_ACTIONS_H
 +
 +#include <shell/e-shell-window-actions.h>
 +
 +/* Address Book Actions */
 +#define E_SHELL_WINDOW_ACTION_ADDRESS_BOOK_COPY(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "address-book-copy")
 +#define E_SHELL_WINDOW_ACTION_ADDRESS_BOOK_DELETE(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "address-book-delete")
 +#define E_SHELL_WINDOW_ACTION_ADDRESS_BOOK_MOVE(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "address-book-move")
 +#define E_SHELL_WINDOW_ACTION_ADDRESS_BOOK_PROPERTIES(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "address-book-properties")
 +#define E_SHELL_WINDOW_ACTION_ADDRESS_BOOK_RENAME(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "address-book-rename")
 +#define E_SHELL_WINDOW_ACTION_ADDRESS_BOOK_SAVE_AS(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "address-book-save-as")
 +#define E_SHELL_WINDOW_ACTION_ADDRESS_BOOK_STOP(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "address-book-stop")
 +
 +/* Contact Actions */
 +#define E_SHELL_WINDOW_ACTION_CONTACT_CLIPBOARD_COPY(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "contact-clipboard-copy")
 +#define E_SHELL_WINDOW_ACTION_CONTACT_CLIPBOARD_CUT(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "contact-clipboard-cut")
 +#define E_SHELL_WINDOW_ACTION_CONTACT_CLIPBOARD_PASTE(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "contact-clipboard-paste")
 +#define E_SHELL_WINDOW_ACTION_CONTACT_COPY(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "contact-copy")
 +#define E_SHELL_WINDOW_ACTION_CONTACT_DELETE(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "contact-delete")
 +#define E_SHELL_WINDOW_ACTION_CONTACT_FORWARD(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "contact-forward")
 +#define E_SHELL_WINDOW_ACTION_CONTACT_MOVE(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "contact-move")
 +#define E_SHELL_WINDOW_ACTION_CONTACT_NEW(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "contact-new")
 +#define E_SHELL_WINDOW_ACTION_CONTACT_NEW_LIST(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "contact-new-list")
 +#define E_SHELL_WINDOW_ACTION_CONTACT_OPEN(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "contact-open")
 +#define E_SHELL_WINDOW_ACTION_CONTACT_PREVIEW(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "contact-preview")
 +#define E_SHELL_WINDOW_ACTION_CONTACT_PRINT(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "contact-print")
 +#define E_SHELL_WINDOW_ACTION_CONTACT_PRINT_PREVIEW(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "contact-print-preview")
 +#define E_SHELL_WINDOW_ACTION_CONTACT_SAVE_AS(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "contact-save-as")
 +#define E_SHELL_WINDOW_ACTION_CONTACT_SELECT_ALL(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "contact-select-all")
 +#define E_SHELL_WINDOW_ACTION_CONTACT_SEND_MESSAGE(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "contact-send-message")
 +
 +/* Search Actions */
 +#define E_SHELL_WINDOW_ACTION_CONTACT_SEARCH_ANY_FIELD_CONTAINS(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "contact-search-any-field-contains")
 +#define E_SHELL_WINDOW_ACTION_CONTACT_SEARCH_EMAIL_BEGINS_WITH(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "contact-search-email-begins-with")
 +#define E_SHELL_WINDOW_ACTION_CONTACT_SEARCH_NAME_CONTAINS(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "contact-search-name-contains")
 +
 +/* Action Groups */
 +#define E_SHELL_WINDOW_ACTION_GROUP_CONTACTS(window) \
 +	E_SHELL_WINDOW_ACTION_GROUP ((window), "contacts")
 +#define E_SHELL_WINDOW_ACTION_GROUP_CONTACTS_FILTER(window) \
 +	E_SHELL_WINDOW_ACTION_GROUP ((window), "contacts-filter")
 +
 +#endif /* E_BOOK_SHELL_VIEW_ACTIONS_H */
diff --cc addressbook/gui/component/e-book-shell-view-private.c
index cdb8c8f,0000000..ec3562e
mode 100644,000000..100644
--- a/addressbook/gui/component/e-book-shell-view-private.c
+++ b/addressbook/gui/component/e-book-shell-view-private.c
@@@ -1,621 -1,0 +1,621 @@@
 +/*
 + * e-book-shell-view-private.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-book-shell-view-private.h"
 +
 +#include "widgets/menus/gal-view-factory-etable.h"
 +#include "addressbook/gui/widgets/gal-view-factory-minicard.h"
 +
 +#include "addressbook.h"
 +
 +static void
 +open_contact (EBookShellView *book_shell_view,
 +              EContact *contact,
 +              gboolean is_new_contact,
 +              EAddressbookView *view)
 +{
 +	EAddressbookModel *model;
 +	GtkWidget *editor;
 +	EBook *book;
 +	gboolean editable;
 +
 +	model = e_addressbook_view_get_model (view);
 +	book = e_addressbook_model_get_book (model);
 +	editable = e_addressbook_model_get_editable (model);
 +
 +	if (e_contact_get (contact, E_CONTACT_IS_LIST))
 +		editor = e_contact_list_editor_new (
 +			book, contact, is_new_contact, editable);
 +	else
 +		editor = e_contact_editor_new (
 +			book, contact, is_new_contact, editable);
 +
 +	eab_editor_show (EAB_EDITOR (editor));
 +}
 +
 +static void
 +popup_event (EBookShellView *book_shell_view,
 +             GdkEventButton *event)
 +{
 +	EShellView *shell_view;
 +	const gchar *widget_path;
 +
 +	widget_path = "/contact-popup";
 +	shell_view = E_SHELL_VIEW (book_shell_view);
 +
 +	e_shell_view_show_popup_menu (shell_view, widget_path, event);
 +}
 +
 +static void
 +book_shell_view_selection_change_foreach (gint row,
 +                                          EBookShellView *book_shell_view)
 +{
 +	EBookShellContent *book_shell_content;
 +	EAddressbookView *view;
 +	EAddressbookModel *model;
 +	EContact *contact;
 +
 +	/* XXX A "foreach" function is kind of a silly way to retrieve
 +	 *     the one and only selected contact, but this is the only
 +	 *     means that ESelectionModel provides. */
 +
 +	book_shell_content = book_shell_view->priv->book_shell_content;
 +	view = e_book_shell_content_get_current_view (book_shell_content);
 +	model = e_addressbook_view_get_model (view);
 +	contact = e_addressbook_model_get_contact (model, row);
 +
 +	e_book_shell_content_set_preview_contact (book_shell_content, contact);
 +}
 +
 +static void
 +selection_change (EBookShellView *book_shell_view,
 +                  EAddressbookView *view)
 +{
 +	EBookShellContent *book_shell_content;
 +	EAddressbookView *current_view;
 +	ESelectionModel *selection_model;
 +	EShellView *shell_view;
 +	gint n_selected;
 +
 +	shell_view = E_SHELL_VIEW (book_shell_view);
 +	book_shell_content = book_shell_view->priv->book_shell_content;
 +	current_view = e_book_shell_content_get_current_view (book_shell_content);
 +
 +	if (view != current_view)
 +		return;
 +
 +	e_shell_view_update_actions (shell_view);
 +
 +	selection_model = e_addressbook_view_get_selection_model (view);
 +
 +	n_selected = (selection_model != NULL) ?
 +		e_selection_model_selected_count (selection_model) : 0;
 +
 +	if (n_selected == 1)
 +		e_selection_model_foreach (
 +			selection_model, (EForeachFunc)
 +			book_shell_view_selection_change_foreach,
 +			book_shell_view);
 +	else
 +		e_book_shell_content_set_preview_contact (
 +			book_shell_content, NULL);
 +}
 +
 +static void
 +contact_changed (EBookShellView *book_shell_view,
 +                 EContact *contact)
 +{
 +	EBookShellContent *book_shell_content;
 +	EContact *preview_contact;
 +
 +	book_shell_content = book_shell_view->priv->book_shell_content;
 +
 +	preview_contact =
 +		e_book_shell_content_get_preview_contact (book_shell_content);
 +
 +	if (contact != preview_contact)
 +		return;
 +
 +	/* Re-render the same contact. */
 +	e_book_shell_content_set_preview_contact (book_shell_content, contact);
 +}
 +
 +static void
 +contacts_removed (EBookShellView *book_shell_view,
 +                  GArray *removed_indices,
 +                  EAddressbookModel *model)
 +{
 +	EBookShellContent *book_shell_content;
 +	EContact *preview_contact;
 +
 +	book_shell_content = book_shell_view->priv->book_shell_content;
 +
 +	preview_contact =
 +		e_book_shell_content_get_preview_contact (book_shell_content);
 +
 +	if (preview_contact == NULL)
 +		return;
 +
 +	/* Is the displayed contact still in the model? */
 +	if (e_addressbook_model_find (model, preview_contact) < 0)
 +		return;
 +
 +	/* If not, clear the contact display. */
 +	e_book_shell_content_set_preview_contact (book_shell_content, NULL);
 +}
 +
 +static void
 +book_open_cb (EBook *book,
 +              EBookStatus status,
 +              gpointer user_data)
 +{
 +	EAddressbookView *view = user_data;
 +	EAddressbookModel *model;
 +	ESource *source;
 +
 +	source = e_book_get_source (book);
 +	model = e_addressbook_view_get_model (view);
 +
 +	if (status == E_BOOK_ERROR_OK) {
 +		e_addressbook_model_set_book (model, book);
 +		e_addressbook_model_force_folder_bar_message (model);
 +	} else if (status != E_BOOK_ERROR_CANCELLED)
 +		eab_load_error_dialog (NULL /* XXX */, source, status);
 +}
 +
 +static void
 +book_shell_view_activate_selected_source (EBookShellView *book_shell_view,
 +                                          ESourceSelector *selector)
 +{
 +	EShellView *shell_view;
 +	EBookShellContent *book_shell_content;
 +	EAddressbookView *view;
 +	EAddressbookModel *model;
 +	ESource *source;
 +	GalViewInstance *view_instance;
 +	GHashTable *hash_table;
 +	GtkWidget *widget;
 +	const gchar *uid;
 +	gchar *view_id;
 +
 +	shell_view = E_SHELL_VIEW (book_shell_view);
 +	book_shell_content = book_shell_view->priv->book_shell_content;
 +	source = e_source_selector_peek_primary_selection (selector);
 +
 +	if (source == NULL)
 +		return;
 +
 +	uid = e_source_peek_uid (source);
 +	hash_table = book_shell_view->priv->uid_to_view;
 +	widget = g_hash_table_lookup (hash_table, uid);
 +
 +	if (widget != NULL) {
 +		EBook *book;
 +
 +		/* There is a view for this UID.  Make sure the view
 +		 * actually contains an EBook.  The absence of an EBook
 +		 * suggests a previous load failed, so try again. */
 +		view = E_ADDRESSBOOK_VIEW (widget);
 +		model = e_addressbook_view_get_model (view);
 +		source = e_addressbook_view_get_source (view);
 +
 +		if (e_addressbook_model_get_book (model) == NULL) {
 +			book = e_book_new (source, NULL);
 +
 +			if (book != NULL)
 +				addressbook_load (book, book_open_cb, view);
 +		}
 +
 +	} else {
 +		EBook *book;
 +
 +		/* Create a view for this UID. */
 +		widget = e_addressbook_view_new (shell_view, source);
 +		gtk_widget_show (widget);
 +
 +		e_book_shell_content_insert_view (
 +			book_shell_content,
 +			E_ADDRESSBOOK_VIEW (widget));
 +
 +		g_hash_table_insert (
 +			hash_table, g_strdup (uid),
 +			g_object_ref (widget));
 +
 +		g_signal_connect_swapped (
 +			widget, "open-contact",
 +			G_CALLBACK (open_contact), book_shell_view);
 +
 +		g_signal_connect_swapped (
 +			widget, "popup-event",
 +			G_CALLBACK (popup_event), book_shell_view);
 +
 +		g_signal_connect_swapped (
 +			widget, "command-state-change",
 +			G_CALLBACK (e_shell_view_update_actions),
 +			book_shell_view);
 +
 +		g_signal_connect_swapped (
 +			widget, "selection-change",
 +			G_CALLBACK (selection_change), book_shell_view);
 +
 +		book = e_book_new (source, NULL);
 +		view = E_ADDRESSBOOK_VIEW (widget);
 +
 +		if (book != NULL)
 +			addressbook_load (book, book_open_cb, view);
 +
 +		model = e_addressbook_view_get_model (view);
 +
 +		g_signal_connect_swapped (
 +			model, "contact-changed",
 +			G_CALLBACK (contact_changed), book_shell_view);
 +
 +		g_signal_connect_swapped (
 +			model, "contacts-removed",
 +			G_CALLBACK (contacts_removed), book_shell_view);
 +	}
 +
 +	e_book_shell_content_set_current_view (
 +		book_shell_content, E_ADDRESSBOOK_VIEW (widget));
 +
 +	/* XXX We have to keep the addressbook selector informed of the
 +	 *     current view so it can move contacts via drag-and-drop. */
 +	e_addressbook_selector_set_current_view (
 +		E_ADDRESSBOOK_SELECTOR (selector),
 +		E_ADDRESSBOOK_VIEW (widget));
 +
 +	view_instance = e_addressbook_view_get_view_instance (view);
 +	view_id = gal_view_instance_get_current_view_id (view_instance);
 +	e_shell_view_set_view_id (shell_view, view_id);
 +	g_free (view_id);
 +
 +	e_addressbook_model_force_folder_bar_message (model);
 +	selection_change (book_shell_view, view);
 +}
 +
 +static gboolean
 +book_shell_view_show_popup_menu (GdkEventButton *event,
 +                                 EShellView *shell_view)
 +{
 +	const gchar *widget_path;
 +
 +	widget_path = "/address-book-popup";
 +	e_shell_view_show_popup_menu (shell_view, widget_path, event);
 +
 +	return TRUE;
 +}
 +
 +static gboolean
 +book_shell_view_selector_button_press_event_cb (EShellView *shell_view,
 +                                                GdkEventButton *event)
 +{
 +	/* XXX Use ESourceSelector's "popup-event" signal instead. */
 +
 +	if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
 +		return book_shell_view_show_popup_menu (event, shell_view);
 +
 +	return FALSE;
 +}
 +
 +static gboolean
 +book_shell_view_selector_popup_menu_cb (EShellView *shell_view)
 +{
 +	/* XXX Use ESourceSelector's "popup-event" signal instead. */
 +
 +	return book_shell_view_show_popup_menu (NULL, shell_view);
 +}
 +
 +static gboolean
 +book_shell_view_selector_key_press_event_cb (EShellView *shell_view,
 +                                             GdkEventKey *event)
 +{
 +	EShellWindow *shell_window;
 +
 +	/* Needed for the ACTION() macro. */
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	if (event->keyval == GDK_Delete) {
 +		gtk_action_activate (ACTION (ADDRESS_BOOK_DELETE));
 +		return TRUE;
 +	}
 +
 +	return FALSE;
 +}
 +
 +static void
 +book_shell_view_load_view_collection (EShellViewClass *shell_view_class)
 +{
 +	GalViewCollection *collection;
 +	GalViewFactory *factory;
 +	ETableSpecification *spec;
 +	const gchar *base_dir;
 +	gchar *filename;
 +
 +	collection = shell_view_class->view_collection;
 +
 +	base_dir = EVOLUTION_ETSPECDIR;
 +	spec = e_table_specification_new ();
 +	filename = g_build_filename (base_dir, ETSPEC_FILENAME, NULL);
 +	if (!e_table_specification_load_from_file (spec, filename))
 +		g_critical ("Unable to load ETable specification file "
 +			    "for address book");
 +	g_free (filename);
 +
 +	factory = gal_view_factory_etable_new (spec);
 +	gal_view_collection_add_factory (collection, factory);
 +	g_object_unref (factory);
 +	g_object_unref (spec);
 +
 +	factory = gal_view_factory_minicard_new ();
 +	gal_view_collection_add_factory (collection, factory);
 +	g_object_unref (factory);
 +
 +	gal_view_collection_load (collection);
 +}
 +
 +static void
 +book_shell_view_notify_view_id_cb (EBookShellView *book_shell_view)
 +{
 +	EBookShellContent *book_shell_content;
 +	EAddressbookView *address_view;
 +	GalViewInstance *view_instance;
 +	const gchar *view_id;
 +
 +	book_shell_content = book_shell_view->priv->book_shell_content;
 +	address_view = e_book_shell_content_get_current_view (book_shell_content);
 +	view_instance = e_addressbook_view_get_view_instance (address_view);
 +	view_id = e_shell_view_get_view_id (E_SHELL_VIEW (book_shell_view));
 +
 +	/* A NULL view ID implies we're in a custom view.  But you can
 +	 * only get to a custom view via the "Define Views" dialog, which
 +	 * would have already modified the view instance appropriately.
 +	 * Furthermore, there's no way to refer to a custom view by ID
 +	 * anyway, since custom views have no IDs. */
 +	if (view_id == NULL)
 +		return;
 +
 +	gal_view_instance_set_current_view_id (view_instance, view_id);
 +}
 +
 +void
 +e_book_shell_view_private_init (EBookShellView *book_shell_view,
 +                                EShellViewClass *shell_view_class)
 +{
 +	EBookShellViewPrivate *priv = book_shell_view->priv;
 +	GHashTable *uid_to_view;
 +	GHashTable *uid_to_editor;
 +
 +	uid_to_view = g_hash_table_new_full (
 +		g_str_hash, g_str_equal,
 +		(GDestroyNotify) g_free,
 +		(GDestroyNotify) g_object_unref);
 +
 +	uid_to_editor = g_hash_table_new_full (
 +		g_str_hash, g_str_equal,
 +		(GDestroyNotify) g_free,
 +		(GDestroyNotify) g_free);
 +
 +	priv->uid_to_view = uid_to_view;
 +	priv->uid_to_editor = uid_to_editor;
 +
 +	if (!gal_view_collection_loaded (shell_view_class->view_collection))
 +		book_shell_view_load_view_collection (shell_view_class);
 +
 +	g_signal_connect (
 +		book_shell_view, "notify::view-id",
 +		G_CALLBACK (book_shell_view_notify_view_id_cb), NULL);
 +}
 +
 +void
 +e_book_shell_view_private_constructed (EBookShellView *book_shell_view)
 +{
 +	EBookShellViewPrivate *priv = book_shell_view->priv;
 +	EShellContent *shell_content;
 +	EShellSidebar *shell_sidebar;
 +	EShellBackend *shell_backend;
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	ESourceSelector *selector;
 +
 +	shell_view = E_SHELL_VIEW (book_shell_view);
 +	shell_backend = e_shell_view_get_shell_backend (shell_view);
 +	shell_content = e_shell_view_get_shell_content (shell_view);
 +	shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	e_shell_window_add_action_group (shell_window, "contacts");
 +	e_shell_window_add_action_group (shell_window, "contacts-filter");
 +
 +	/* Cache these to avoid lots of awkward casting. */
 +	priv->book_shell_backend = g_object_ref (shell_backend);
 +	priv->book_shell_content = g_object_ref (shell_content);
 +	priv->book_shell_sidebar = g_object_ref (shell_sidebar);
 +
 +	selector = e_book_shell_sidebar_get_selector (
 +		E_BOOK_SHELL_SIDEBAR (shell_sidebar));
 +
 +	g_signal_connect_swapped (
 +		selector, "button-press-event",
 +		G_CALLBACK (book_shell_view_selector_button_press_event_cb),
 +		book_shell_view);
 +
 +	g_signal_connect_swapped (
 +		selector, "key-press-event",
 +		G_CALLBACK (book_shell_view_selector_key_press_event_cb),
 +		book_shell_view);
 +
 +	g_signal_connect_swapped (
 +		selector, "popup-menu",
 +		G_CALLBACK (book_shell_view_selector_popup_menu_cb),
 +		book_shell_view);
 +
 +	g_signal_connect_swapped (
 +		selector, "primary-selection-changed",
 +		G_CALLBACK (book_shell_view_activate_selected_source),
 +		book_shell_view);
 +
 +	e_categories_register_change_listener (
 +		G_CALLBACK (e_book_shell_view_update_search_filter),
 +		book_shell_view);
 +
 +	e_book_shell_view_actions_init (book_shell_view);
 +	book_shell_view_activate_selected_source (book_shell_view, selector);
 +	e_book_shell_view_update_search_filter (book_shell_view);
 +}
 +
 +void
 +e_book_shell_view_private_dispose (EBookShellView *book_shell_view)
 +{
 +	EBookShellViewPrivate *priv = book_shell_view->priv;
 +
 +	DISPOSE (priv->book_shell_backend);
 +	DISPOSE (priv->book_shell_content);
 +	DISPOSE (priv->book_shell_sidebar);
 +
 +	g_hash_table_remove_all (priv->uid_to_view);
 +	g_hash_table_remove_all (priv->uid_to_editor);
 +}
 +
 +void
 +e_book_shell_view_private_finalize (EBookShellView *book_shell_view)
 +{
 +	EBookShellViewPrivate *priv = book_shell_view->priv;
 +
 +	g_hash_table_destroy (priv->uid_to_view);
 +	g_hash_table_destroy (priv->uid_to_editor);
 +}
 +
 +void
 +e_book_shell_view_execute_search (EBookShellView *book_shell_view)
 +{
 +	EBookShellContent *book_shell_content;
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	EShellContent *shell_content;
 +	GtkAction *action;
 +	GString *string;
 +	EAddressbookView *view;
 +	EAddressbookModel *model;
 +	FilterRule *rule;
 +	const gchar *format;
 +	const gchar *text;
 +	gchar *query;
 +	gchar *temp;
 +	gint value;
 +
 +	shell_view = E_SHELL_VIEW (book_shell_view);
 +	if (!e_shell_view_is_active (shell_view))
 +		return;
 +
 +	shell_content = e_shell_view_get_shell_content (shell_view);
 +	text = e_shell_content_get_search_text (shell_content);
 +
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +	action = ACTION (CONTACT_SEARCH_ANY_FIELD_CONTAINS);
 +	value = gtk_radio_action_get_current_value (GTK_RADIO_ACTION (action));
 +
 +	if (text == NULL || *text == '\0') {
 +		text = "";
 +		value = CONTACT_SEARCH_ANY_FIELD_CONTAINS;
 +	}
 +
 +	switch (value) {
 +		case CONTACT_SEARCH_NAME_CONTAINS:
 +			format = "(contains \"full_name\" %s)";
 +			break;
 +
 +		case CONTACT_SEARCH_EMAIL_BEGINS_WITH:
 +			format = "(beginswith \"email\" %s)";
 +			break;
 +
 +		default:
 +			text = "";
 +			/* fall through */
 +
 +		case CONTACT_SEARCH_ANY_FIELD_CONTAINS:
 +			format = "(contains \"x-evolution-any-field\" %s)";
 +			break;
 +	}
 +
 +	/* Build the query. */
 +	string = g_string_new ("");
 +	e_sexp_encode_string (string, text);
 +	query = g_strdup_printf (format, string->str);
 +	g_string_free (string, TRUE);
 +
 +	/* Apply selected filter. */
 +	value = e_shell_content_get_filter_value (shell_content);
 +	switch (value) {
 +		case CONTACT_FILTER_ANY_CATEGORY:
 +			break;
 +
 +		case CONTACT_FILTER_UNMATCHED:
 +			temp = g_strdup_printf (
 +				"(and (not (and (exists \"CATEGORIES\") "
 +				"(not (is \"CATEGORIES\" \"\")))) %s)",
 +				query);
 +			g_free (query);
 +			query = temp;
 +			break;
 +
 +		default:
 +		{
 +			GList *categories;
 +			const gchar *category_name;
 +
 +			categories = e_categories_get_list ();
 +			category_name = g_list_nth_data (categories, value);
 +			g_list_free (categories);
 +
 +			temp = g_strdup_printf (
 +				"(and (is \"category_list\" \"%s\") %s)",
 +				category_name, query);
 +			g_free (query);
 +			query = temp;
 +		}
 +	}
 +
 +	/* XXX This is wrong.  We need to programmatically construct a
 +	 *     FilterRule, tell it to build code, and pass the resulting
 +	 *     expression string to EAddressbookModel. */
 +	rule = filter_rule_new ();
 +	e_shell_content_set_search_rule (shell_content, rule);
 +	g_object_unref (rule);
 +
 +	/* Submit the query. */
 +	book_shell_content = book_shell_view->priv->book_shell_content;
 +	view = e_book_shell_content_get_current_view (book_shell_content);
 +	model = e_addressbook_view_get_model (view);
 +	e_addressbook_model_set_query (model, query);
 +	g_free (query);
 +
 +	e_book_shell_content_set_preview_contact (book_shell_content, NULL);
 +}
 +
 +void
 +e_book_shell_view_editor_weak_notify (EditorUidClosure *closure,
 +                                      GObject *where_the_object_was)
 +{
 +	GHashTable *hash_table;
 +
 +	hash_table = closure->view->priv->uid_to_editor;
 +	g_hash_table_remove (hash_table, closure->uid);
 +}
diff --cc addressbook/gui/component/e-book-shell-view-private.h
index 628c1c2,0000000..b4701ae
mode 100644,000000..100644
--- a/addressbook/gui/component/e-book-shell-view-private.h
+++ b/addressbook/gui/component/e-book-shell-view-private.h
@@@ -1,129 -1,0 +1,129 @@@
 +/*
 + * e-book-shell-view-private.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_BOOK_SHELL_VIEW_PRIVATE_H
 +#define E_BOOK_SHELL_VIEW_PRIVATE_H
 +
 +#include "e-book-shell-view.h"
 +
 +#include <string.h>
 +#include <glib/gi18n.h>
 +#include <gdk/gdkkeysyms.h>
 +#include <libebook/e-book.h>
 +#include <libedataserver/e-categories.h>
 +#include <libedataserver/e-sexp.h>
 +#include <libedataserverui/e-source-selector.h>
 +
 +#include "e-util/gconf-bridge.h"
 +#include "shell/e-shell-content.h"
 +#include "shell/e-shell-sidebar.h"
 +#include "misc/e-popup-action.h"
 +
 +#include "addressbook/gui/contact-editor/e-contact-editor.h"
 +#include "addressbook/gui/contact-list-editor/e-contact-list-editor.h"
 +#include "addressbook/gui/widgets/eab-gui-util.h"
 +#include "addressbook/gui/widgets/e-addressbook-view.h"
 +#include "addressbook/gui/widgets/e-addressbook-selector.h"
 +
 +#include "e-book-shell-backend.h"
 +#include "e-book-shell-content.h"
 +#include "e-book-shell-sidebar.h"
 +#include "e-book-shell-view-actions.h"
 +
 +#define E_BOOK_SHELL_VIEW_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_BOOK_SHELL_VIEW, EBookShellViewPrivate))
 +
 +/* Shorthand, requires a variable named "shell_window". */
 +#define ACTION(name) \
 +	(E_SHELL_WINDOW_ACTION_##name (shell_window))
 +#define ACTION_GROUP(name) \
 +	(E_SHELL_WINDOW_ACTION_GROUP_##name (shell_window))
 +
 +/* For use in dispose() methods. */
 +#define DISPOSE(obj) \
 +	G_STMT_START { \
 +	if ((obj) != NULL) { g_object_unref (obj); (obj) = NULL; } \
 +	} G_STMT_END
 +
 +/* ETable Specifications */
 +#define ETSPEC_FILENAME		"e-addressbook-view.etspec"
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _EditorUidClosure EditorUidClosure;
 +
 +struct _EditorUidClosure {
 +	GtkWidget *editor;
 +	gchar *uid;
 +	EBookShellView *view;
 +};
 +
 +/* List these in the order to be displayed.
 + * Positive values are reserved for categories. */
 +enum {
 +	CONTACT_FILTER_ANY_CATEGORY = -2,
 +	CONTACT_FILTER_UNMATCHED    = -1
 +};
 +
 +/* List these in the order to be displayed. */
 +enum {
 +	CONTACT_SEARCH_NAME_CONTAINS,
 +	CONTACT_SEARCH_EMAIL_BEGINS_WITH,
 +	CONTACT_SEARCH_ANY_FIELD_CONTAINS
 +};
 +
 +struct _EBookShellViewPrivate {
 +
 +	/* These are just for convenience. */
 +	EBookShellBackend *book_shell_backend;
 +	EBookShellContent *book_shell_content;
 +	EBookShellSidebar *book_shell_sidebar;
 +
 +	GHashTable *uid_to_view;
 +	GHashTable *uid_to_editor;
 +};
 +
 +void		e_book_shell_view_private_init
 +					(EBookShellView *book_shell_view,
 +					 EShellViewClass *shell_view_class);
 +void		e_book_shell_view_private_constructed
 +					(EBookShellView *book_shell_view);
 +void		e_book_shell_view_private_dispose
 +					(EBookShellView *book_shell_view);
 +void		e_book_shell_view_private_finalize
 +					(EBookShellView *book_shell_view);
 +
 +/* Private Utilities */
 +
 +void		e_book_shell_view_actions_init
 +					(EBookShellView *book_shell_view);
 +void		e_book_shell_view_execute_search
 +					(EBookShellView *book_shell_view);
 +void		e_book_shell_view_editor_weak_notify
 +					(EditorUidClosure *closure,
 +					 GObject *where_the_object_was);
 +void		e_book_shell_view_update_search_filter
 +					(EBookShellView *book_shell_view);
 +
 +G_END_DECLS
 +
 +#endif /* E_BOOK_SHELL_VIEW_PRIVATE_H */
diff --cc addressbook/gui/component/e-book-shell-view.c
index 44c06be,0000000..ea48bb5
mode 100644,000000..100644
--- a/addressbook/gui/component/e-book-shell-view.c
+++ b/addressbook/gui/component/e-book-shell-view.c
@@@ -1,318 -1,0 +1,318 @@@
 +/*
 + * e-book-shell-view.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-book-shell-view-private.h"
 +
 +static gpointer parent_class;
 +static GType book_shell_view_type;
 +
 +static void
 +book_shell_view_source_list_changed_cb (EBookShellView *book_shell_view,
 +                                        ESourceList *source_list)
 +{
 +	EBookShellViewPrivate *priv = book_shell_view->priv;
 +	EBookShellContent *book_shell_content;
 +	EShellView *shell_view;
 +	GList *keys, *iter;
 +
 +	shell_view = E_SHELL_VIEW (book_shell_view);
 +	book_shell_content = book_shell_view->priv->book_shell_content;
 +
 +	keys = g_hash_table_get_keys (priv->uid_to_view);
 +	for (iter = keys; iter != NULL; iter = iter->next) {
 +		gchar *uid = iter->data;
 +		EAddressbookView *view;
 +
 +		/* If the source still exists, move on. */
 +		if (e_source_list_peek_source_by_uid (source_list, uid))
 +			continue;
 +
 +		/* Remove the view for the deleted source. */
 +		view = g_hash_table_lookup (priv->uid_to_view, uid);
 +		e_book_shell_content_remove_view (book_shell_content, view);
 +		g_hash_table_remove (priv->uid_to_view, uid);
 +	}
 +	g_list_free (keys);
 +
 +	keys = g_hash_table_get_keys (priv->uid_to_editor);
 +	for (iter = keys; iter != NULL; iter = iter->next) {
 +		gchar *uid = iter->data;
 +		EditorUidClosure *closure;
 +
 +		/* If the source still exists, move on. */
 +		if (e_source_list_peek_source_by_uid (source_list, uid))
 +			continue;
 +
 +		/* Remove the editor for the deleted source. */
 +		closure = g_hash_table_lookup (priv->uid_to_editor, uid);
 +		g_object_weak_unref (
 +			G_OBJECT (closure->editor), (GWeakNotify)
 +			e_book_shell_view_editor_weak_notify, closure);
 +		gtk_widget_destroy (closure->editor);
 +		g_hash_table_remove (priv->uid_to_editor, uid);
 +	}
 +	g_list_free (keys);
 +
 +	e_shell_view_update_actions (shell_view);
 +}
 +
 +static void
 +book_shell_view_dispose (GObject *object)
 +{
 +	EBookShellView *book_shell_view;
 +
 +	book_shell_view = E_BOOK_SHELL_VIEW (object);
 +	e_book_shell_view_private_dispose (book_shell_view);
 +
 +	/* Chain up to parent's dispose() method. */
 +	G_OBJECT_CLASS (parent_class)->dispose (object);
 +}
 +
 +static void
 +book_shell_view_finalize (GObject *object)
 +{
 +	EBookShellView *book_shell_view;
 +
 +	book_shell_view = E_BOOK_SHELL_VIEW (object);
 +	e_book_shell_view_private_finalize (book_shell_view);
 +
 +	/* Chain up to parent's finalize() method. */
 +	G_OBJECT_CLASS (parent_class)->finalize (object);
 +}
 +
 +static void
 +book_shell_view_constructed (GObject *object)
 +{
 +	EBookShellView *book_shell_view;
 +	EBookShellBackend *book_shell_backend;
 +	ESourceList *source_list;
 +
 +	/* Chain up to parent's constructed() method. */
 +	G_OBJECT_CLASS (parent_class)->constructed (object);
 +
 +	book_shell_view = E_BOOK_SHELL_VIEW (object);
 +	e_book_shell_view_private_constructed (book_shell_view);
 +
 +	book_shell_backend = book_shell_view->priv->book_shell_backend;
 +	source_list = e_book_shell_backend_get_source_list (book_shell_backend);
 +
 +	g_signal_connect_swapped (
 +		source_list, "changed",
 +		G_CALLBACK (book_shell_view_source_list_changed_cb),
 +		book_shell_view);
 +}
 +
 +static void
 +book_shell_view_update_actions (EShellView *shell_view)
 +{
 +	EBookShellViewPrivate *priv;
 +	EShellContent *shell_content;
 +	EShellSidebar *shell_sidebar;
 +	EShellWindow *shell_window;
 +	GtkAction *action;
 +	const gchar *label;
 +	gboolean sensitive;
 +	guint32 state;
 +
 +	/* Be descriptive. */
 +	gboolean any_contacts_selected;
 +	gboolean has_primary_source;
 +	gboolean multiple_contacts_selected;
 +	gboolean primary_source_is_system;
 +	gboolean single_contact_selected;
 +	gboolean selection_is_contact_list;
 +	gboolean selection_has_email;
 +	gboolean source_is_busy;
 +	gboolean source_is_editable;
 +	gboolean source_is_empty;
 +
 +	priv = E_BOOK_SHELL_VIEW_GET_PRIVATE (shell_view);
 +
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	shell_content = e_shell_view_get_shell_content (shell_view);
 +	state = e_shell_content_check_state (shell_content);
 +
 +	single_contact_selected =
 +		(state & E_BOOK_SHELL_CONTENT_SELECTION_SINGLE);
 +	multiple_contacts_selected =
 +		(state & E_BOOK_SHELL_CONTENT_SELECTION_MULTIPLE);
 +	selection_has_email =
 +		(state & E_BOOK_SHELL_CONTENT_SELECTION_HAS_EMAIL);
 +	selection_is_contact_list =
 +		(state & E_BOOK_SHELL_CONTENT_SELECTION_IS_CONTACT_LIST);
 +	source_is_busy =
 +		(state & E_BOOK_SHELL_CONTENT_SOURCE_IS_BUSY);
 +	source_is_editable =
 +		(state & E_BOOK_SHELL_CONTENT_SOURCE_IS_EDITABLE);
 +	source_is_empty =
 +		(state & E_BOOK_SHELL_CONTENT_SOURCE_IS_EMPTY);
 +
 +	shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
 +	state = e_shell_sidebar_check_state (shell_sidebar);
 +
 +	has_primary_source =
 +		(state & E_BOOK_SHELL_SIDEBAR_HAS_PRIMARY_SOURCE);
 +	primary_source_is_system =
 +		(state & E_BOOK_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_SYSTEM);
 +
 +	any_contacts_selected =
 +		(single_contact_selected || multiple_contacts_selected);
 +
 +	action = ACTION (ADDRESS_BOOK_DELETE);
 +	sensitive = has_primary_source && !primary_source_is_system;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (ADDRESS_BOOK_RENAME);
 +	sensitive = has_primary_source;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (ADDRESS_BOOK_STOP);
 +	sensitive = source_is_busy;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (CONTACT_CLIPBOARD_COPY);
 +	sensitive = any_contacts_selected;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (CONTACT_CLIPBOARD_CUT);
 +	sensitive = source_is_editable && any_contacts_selected;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (CONTACT_CLIPBOARD_PASTE);
 +	sensitive = source_is_editable;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (CONTACT_COPY);
 +	sensitive = any_contacts_selected;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (CONTACT_DELETE);
 +	sensitive = source_is_editable && any_contacts_selected;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (CONTACT_FORWARD);
 +	sensitive = any_contacts_selected;
 +	gtk_action_set_sensitive (action, sensitive);
 +	if (multiple_contacts_selected)
 +		label = _("_Forward Contacts");
 +	else
 +		label = _("_Forward Contact");
 +	g_object_set (action, "label", label, NULL);
 +
 +	action = ACTION (CONTACT_MOVE);
 +	sensitive = source_is_editable && any_contacts_selected;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (CONTACT_OPEN);
 +	sensitive = any_contacts_selected;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (CONTACT_PRINT);
 +	sensitive = any_contacts_selected;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (CONTACT_PRINT_PREVIEW);
 +	sensitive = any_contacts_selected;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (CONTACT_SAVE_AS);
 +	sensitive = any_contacts_selected;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (CONTACT_SELECT_ALL);
 +	sensitive = !(source_is_empty);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (CONTACT_SEND_MESSAGE);
 +	sensitive = any_contacts_selected && selection_has_email;
 +	gtk_action_set_sensitive (action, sensitive);
 +	if (multiple_contacts_selected)
 +		label = _("_Send Message to Contacts");
 +	else if (selection_is_contact_list)
 +		label = _("_Send Message to List");
 +	else
 +		label = _("_Send Message to Contact");
 +	g_object_set (action, "label", label, NULL);
 +}
 +
 +static void
 +book_shell_view_class_init (EBookShellViewClass *class)
 +{
 +	GObjectClass *object_class;
 +	EShellViewClass *shell_view_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (EBookShellViewPrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->dispose = book_shell_view_dispose;
 +	object_class->finalize = book_shell_view_finalize;
 +	object_class->constructed = book_shell_view_constructed;
 +
 +	shell_view_class = E_SHELL_VIEW_CLASS (class);
 +	shell_view_class->label = _("Contacts");
 +	shell_view_class->icon_name = "x-office-address-book";
 +	shell_view_class->ui_definition = "evolution-contacts.ui";
 +	shell_view_class->ui_manager_id = "org.gnome.evolution.contacts";
 +	shell_view_class->search_options = "/contact-search-options";
 +	shell_view_class->search_rules = "addresstypes.xml";
 +	shell_view_class->new_shell_content = e_book_shell_content_new;
 +	shell_view_class->new_shell_sidebar = e_book_shell_sidebar_new;
 +	shell_view_class->update_actions = book_shell_view_update_actions;
 +}
 +
 +static void
 +book_shell_view_init (EBookShellView *book_shell_view,
 +                      EShellViewClass *shell_view_class)
 +{
 +	book_shell_view->priv =
 +		E_BOOK_SHELL_VIEW_GET_PRIVATE (book_shell_view);
 +
 +	e_book_shell_view_private_init (book_shell_view, shell_view_class);
 +}
 +
 +GType
 +e_book_shell_view_get_type (void)
 +{
 +	return book_shell_view_type;
 +}
 +
 +void
 +e_book_shell_view_register_type (GTypeModule *type_module)
 +{
 +	const GTypeInfo type_info = {
 +		sizeof (EBookShellViewClass),
 +		(GBaseInitFunc) NULL,
 +		(GBaseFinalizeFunc) NULL,
 +		(GClassInitFunc) book_shell_view_class_init,
 +		(GClassFinalizeFunc) NULL,
 +		NULL,  /* class_data */
 +		sizeof (EBookShellView),
 +		0,     /* n_preallocs */
 +		(GInstanceInitFunc) book_shell_view_init,
 +		NULL   /* value_table */
 +	};
 +
 +	book_shell_view_type = g_type_module_register_type (
 +		type_module, E_TYPE_SHELL_VIEW,
 +		"EBookShellView", &type_info, 0);
 +}
diff --cc addressbook/gui/component/e-book-shell-view.h
index 3cefba8,0000000..33a0c8a
mode 100644,000000..100644
--- a/addressbook/gui/component/e-book-shell-view.h
+++ b/addressbook/gui/component/e-book-shell-view.h
@@@ -1,66 -1,0 +1,66 @@@
 +/*
 + * e-book-shell-view.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_BOOK_SHELL_VIEW_H
 +#define E_BOOK_SHELL_VIEW_H
 +
 +#include <shell/e-shell-view.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_BOOK_SHELL_VIEW \
 +	(e_book_shell_view_get_type ())
 +#define E_BOOK_SHELL_VIEW(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_BOOK_SHELL_VIEW, EBookShellView))
 +#define E_BOOK_SHELL_VIEW_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_BOOK_SHELL_VIEW, EBookShellViewClass))
 +#define E_IS_BOOK_SHELL_VIEW(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_BOOK_SHELL_VIEW))
 +#define E_IS_BOOK_SHELL_VIEW_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), E_TYPE_BOOK_SHELL_VIEW))
 +#define E_BOOK_SHELL_VIEW_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_BOOK_SHELL_VIEW, EBookShellViewClass))
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _EBookShellView EBookShellView;
 +typedef struct _EBookShellViewClass EBookShellViewClass;
 +typedef struct _EBookShellViewPrivate EBookShellViewPrivate;
 +
 +struct _EBookShellView {
 +	EShellView parent;
 +	EBookShellViewPrivate *priv;
 +};
 +
 +struct _EBookShellViewClass {
 +	EShellViewClass parent_class;
 +};
 +
 +GType		e_book_shell_view_get_type	(void);
 +void		e_book_shell_view_register_type	(GTypeModule *type_module);
 +
 +G_END_DECLS
 +
 +#endif /* E_BOOK_SHELL_VIEW_H */
diff --cc addressbook/gui/component/eab-composer-util.c
index 943225b,0000000..46d28b0
mode 100644,000000..100644
--- a/addressbook/gui/component/eab-composer-util.c
+++ b/addressbook/gui/component/eab-composer-util.c
@@@ -1,197 -1,0 +1,197 @@@
 +/*
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "eab-composer-util.h"
 +
 +#include <string.h>
 +#include <glib/gi18n.h>
 +#include <libebook/e-contact.h>
 +#include <libebook/e-destination.h>
 +
 +#include "composer/e-msg-composer.h"
 +#include "addressbook/util/eab-book-util.h"
 +#include "addressbook/gui/widgets/eab-gui-util.h"
 +
 +void
 +eab_send_as_to (GList *destinations)
 +{
 +	EMsgComposer *composer;
 +	EComposerHeaderTable *table;
 +	GPtrArray *to_array;
 +	GPtrArray *bcc_array;
 +
 +	union {
 +		gpointer *pdata;
 +		EDestination **destinations;
 +	} convert;
 +
 +	if (destinations == NULL)
 +		return;
 +
 +	composer = e_msg_composer_new ();
 +	table = e_msg_composer_get_header_table (composer);
 +
 +	to_array = g_ptr_array_new ();
 +	bcc_array = g_ptr_array_new ();
 +
 +	/* Sort contacts into "To" and "Bcc" destinations. */
 +	while (destinations != NULL) {
 +		EDestination *destination = destinations->data;
 +
 +		if (e_destination_is_evolution_list (destination)) {
 +			if (e_destination_list_show_addresses (destination))
 +				g_ptr_array_add (to_array, destination);
 +			else
 +				g_ptr_array_add (bcc_array, destination);
 +		} else
 +			g_ptr_array_add (to_array, destination);
 +
 +		destinations = g_list_next (destinations);
 +	}
 +
 +	/* Add sentinels to each array. */
 +	g_ptr_array_add (to_array, NULL);
 +	g_ptr_array_add (bcc_array, NULL);
 +
 +	/* XXX Acrobatics like this make me question whether NULL-terminated
 +	 *     arrays are really the best argument type for passing a list of
 +	 *     destinations to the header table. */
 +
 +	/* Add "To" destinations. */
 +	convert.pdata = to_array->pdata;
 +	e_composer_header_table_set_destinations_to (
 +		table, convert.destinations);
 +	g_ptr_array_free (to_array, FALSE);
 +	e_destination_freev (convert.destinations);
 +
 +	/* Add "Bcc" destinations. */
 +	convert.pdata = bcc_array->pdata;
 +	e_composer_header_table_set_destinations_bcc (
 +		table, convert.destinations);
 +	g_ptr_array_free (bcc_array, FALSE);
 +	e_destination_freev (convert.destinations);
 +
 +	gtk_widget_show (GTK_WIDGET (composer));
 +}
 +
 +static const char *
 +get_email (EContact *contact, EContactField field_id, gchar **to_free)
 +{
 +	char *name = NULL, *mail = NULL;
 +	const char *value = e_contact_get_const (contact, field_id);
 +
 +	*to_free = NULL;
 +
 +	if (eab_parse_qp_email (value, &name, &mail)) {
 +		*to_free = g_strdup_printf ("%s <%s>", name, mail);
 +		value = *to_free;
 +	}
 +
 +	g_free (name);
 +	g_free (mail);
 +
 +	return value;
 +}
 +
 +void
 +eab_send_as_attachment (GList *destinations)
 +{
 +	EMsgComposer *composer;
 +	EComposerHeaderTable *table;
 +	CamelMimePart *attachment;
 +	GList *contacts, *iter;
 +	gchar *data;
 +
 +	if (destinations == NULL)
 +		return;
 +
 +	composer = e_msg_composer_new ();
 +	table = e_msg_composer_get_header_table (composer);
 +
 +	attachment = camel_mime_part_new ();
 +
 +	contacts = g_list_copy (destinations);
 +	for (iter = contacts; iter != NULL; iter = iter->next)
 +		iter->data = e_destination_get_contact (iter->data);
 +	data = eab_contact_list_to_string (contacts);
 +	g_list_free (contacts);
 +
 +	camel_mime_part_set_content (
 +		attachment, data, strlen (data), "text/x-vcard");
 +
 +	if (destinations->next != NULL)
 +		camel_mime_part_set_description (
 +			attachment, _("Multiple vCards"));
 +	else {
 +		EContact *contact;
 +		const gchar *file_as;
 +		gchar *description;
 +
 +		contact = e_destination_get_contact (destinations->data);
 +		file_as = e_contact_get_const (contact, E_CONTACT_FILE_AS);
 +		description = g_strdup_printf (_("vCard for %s"), file_as);
 +		camel_mime_part_set_description (attachment, description);
 +		g_free (description);
 +	}
 +
 +	camel_mime_part_set_disposition (attachment, "attachment");
 +
 +	e_msg_composer_attach (composer, attachment);
 +	camel_object_unref (attachment);
 +
 +	if (destinations->next != NULL)
 +		e_composer_header_table_set_subject (
 +			table, _("Contact information"));
 +	else {
 +		EContact *contact;
 +		gchar *tempstr;
 +		const gchar *tempstr2;
 +		gchar *tempfree = NULL;
 +
 +		contact = e_destination_get_contact (destinations->data);
 +		tempstr2 = e_contact_get_const (contact, E_CONTACT_FILE_AS);
 +		if (!tempstr2 || !*tempstr2)
 +			tempstr2 = e_contact_get_const (contact, E_CONTACT_FULL_NAME);
 +		if (!tempstr2 || !*tempstr2)
 +			tempstr2 = e_contact_get_const (contact, E_CONTACT_ORG);
 +		if (!tempstr2 || !*tempstr2) {
 +			g_free (tempfree);
 +			tempstr2 = get_email (contact, E_CONTACT_EMAIL_1, &tempfree);
 +		}
 +		if (!tempstr2 || !*tempstr2) {
 +			g_free (tempfree);
 +			tempstr2 = get_email (contact, E_CONTACT_EMAIL_2, &tempfree);
 +		}
 +		if (!tempstr2 || !*tempstr2) {
 +			g_free (tempfree);
 +			tempstr2 = get_email (contact, E_CONTACT_EMAIL_3, &tempfree);
 +		}
 +
 +		if (!tempstr2 || !*tempstr2)
 +			tempstr = g_strdup_printf (_("Contact information"));
 +		else
 +			tempstr = g_strdup_printf (_("Contact information for %s"), tempstr2);
 +
 +		e_composer_header_table_set_subject (table, tempstr);
 +
 +		g_free (tempstr);
 +		g_free (tempfree);
 +	}
 +
 +	gtk_widget_show (GTK_WIDGET (composer));
 +}
diff --cc addressbook/gui/component/eab-composer-util.h
index ffee76b,0000000..4aec230
mode 100644,000000..100644
--- a/addressbook/gui/component/eab-composer-util.h
+++ b/addressbook/gui/component/eab-composer-util.h
@@@ -1,31 -1,0 +1,31 @@@
 +/*
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef EAB_COMPOSER_UTIL_H
 +#define EAB_COMPOSER_UTIL_H
 +
 +#include <gtk/gtk.h>
 +
 +G_BEGIN_DECLS
 +
 +void		eab_send_as_to			(GList *destinations);
 +void		eab_send_as_attachment		(GList *destinations);
 +
 +G_END_DECLS
 +
 +#endif /* EAB_COMPOSER_UTIL_H */
diff --cc addressbook/gui/component/evolution-module-addressbook.c
index 2d3e18e,0000000..3089133
mode 100644,000000..100644
--- a/addressbook/gui/component/evolution-module-addressbook.c
+++ b/addressbook/gui/component/evolution-module-addressbook.c
@@@ -1,45 -1,0 +1,45 @@@
 +/*
 + * evolution-module-addressbook.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-book-shell-backend.h"
 +#include "e-book-shell-content.h"
 +#include "e-book-shell-sidebar.h"
 +#include "e-book-shell-view.h"
 +
 +/* Module Entry Points */
 +void e_module_load (GTypeModule *type_module);
 +void e_module_unload (GTypeModule *type_module);
 +
 +G_MODULE_EXPORT void
 +e_module_load (GTypeModule *type_module)
 +{
 +	/* Register dynamically loaded types. */
 +
 +	e_book_shell_backend_register_type (type_module);
 +	e_book_shell_content_register_type (type_module);
 +	e_book_shell_sidebar_register_type (type_module);
 +	e_book_shell_view_register_type (type_module);
 +}
 +
 +G_MODULE_EXPORT void
 +e_module_unload (GTypeModule *type_module)
 +{
 +}
diff --cc addressbook/gui/widgets/a11y/ea-addressbook-view.c
index eff7eb4,0000000..4150e10
mode 100644,000000..100644
--- a/addressbook/gui/widgets/a11y/ea-addressbook-view.c
+++ b/addressbook/gui/widgets/a11y/ea-addressbook-view.c
@@@ -1,123 -1,0 +1,123 @@@
 +/*
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Authors:
 + *		Leon Zhang <leon zhang sun com>
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include <config.h>
 +
 +#include <glib/gi18n.h>
 +#include "ea-addressbook-view.h"
 +
 +static G_CONST_RETURN gchar* ea_ab_view_get_name (AtkObject *accessible);
 +static G_CONST_RETURN gchar* ea_ab_view_get_description (AtkObject *accessible);
 +
 +static void ea_ab_view_class_init (EAddressbookViewClass *class);
 +
 +static gpointer parent_class = NULL;
 +
 +GType
 +ea_ab_view_get_type (void)
 +{
 +	static GType type = 0;
 +	AtkObjectFactory *factory;
 +	GTypeQuery query;
 +	GType derived_atk_type;
 +
 +	if (!type) {
 +		static  GTypeInfo tinfo =  {
 +			sizeof (EAddressbookViewClass),
 +			(GBaseInitFunc) NULL,  /* base_init */
 +			(GBaseFinalizeFunc) NULL,  /* base_finalize */
 +			(GClassInitFunc) ea_ab_view_class_init,
 +			(GClassFinalizeFunc) NULL, /* class_finalize */
 +			NULL,	/* class_data */
 +			sizeof (EAddressbookView),
 +			0,	/* n_preallocs */
 +			(GInstanceInitFunc) NULL, /* instance init */
 +			NULL	/* value table */
 +		};
 +
 +		/*
 +		 * Figure out the size of the class and instance
 +		 * we are run-time deriving from (GailWidget, in this case) */
 +
 +		factory = atk_registry_get_factory (atk_get_default_registry (),
 +						    GTK_TYPE_EVENT_BOX);
 +		derived_atk_type = atk_object_factory_get_accessible_type (factory);
 +		g_type_query (derived_atk_type, &query);
 +
 +		tinfo.class_size = query.class_size;
 +		tinfo.instance_size = query.instance_size;
 +
 +		type = g_type_register_static (derived_atk_type,
 +						"EaABView", &tinfo, 0);
 +	}
 +
 +	return type;
 +}
 +
 +static void
 +ea_ab_view_class_init (EAddressbookViewClass *class)
 +{
 +	AtkObjectClass *atk_object_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +
 +	atk_object_class = ATK_OBJECT_CLASS (class);
 +	atk_object_class->get_name = ea_ab_view_get_name;
 +	atk_object_class->get_description = ea_ab_view_get_description;
 +}
 +
 +static G_CONST_RETURN gchar*
 +ea_ab_view_get_name (AtkObject *accessible)
 +{
 +	g_return_val_if_fail (EA_IS_AB_VIEW(accessible), NULL);
 +	if (accessible->name)
 +		return accessible->name;
 +
 +	return _("evolution address book");
 +}
 +
 +static G_CONST_RETURN gchar*
 +ea_ab_view_get_description (AtkObject *accessible)
 +{
 +	if (accessible->description)
 +		return accessible->description;
 +
 +	return _("evolution address book");
 +}
 +
 +AtkObject*
 +ea_ab_view_new (GObject *obj)
 +{
 +	GObject *object;
 +	AtkObject *accessible;
 +
 +	g_return_val_if_fail(obj != NULL, NULL);
 +	g_return_val_if_fail (E_IS_ADDRESSBOOK_VIEW(obj), NULL);
 +
 +	object = g_object_new (EA_TYPE_AB_VIEW, NULL);
 +
 +	accessible = ATK_OBJECT (object);
 +	atk_object_initialize (accessible, obj);
 +	accessible->role = ATK_ROLE_CANVAS;
 +
 +	return accessible;
 +}
diff --cc addressbook/gui/widgets/a11y/ea-addressbook.c
index 087c33a,0000000..14fc4c1
mode 100644,000000..100644
--- a/addressbook/gui/widgets/a11y/ea-addressbook.c
+++ b/addressbook/gui/widgets/a11y/ea-addressbook.c
@@@ -1,84 -1,0 +1,84 @@@
 +/*
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Authors:
 + *		Leon Zhang <leon zhang sun com>
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include <text/e-text.h>
 +#include "a11y/ea-factory.h"
 +#include "ea-addressbook.h"
 +#include "ea-minicard.h"
 +#include "ea-minicard-view.h"
 +#include "ea-addressbook-view.h"
 +
 +EA_FACTORY_GOBJECT (EA_TYPE_MINICARD, ea_minicard, ea_minicard_new)
 +EA_FACTORY_GOBJECT (EA_TYPE_MINICARD_VIEW, ea_minicard_view, ea_minicard_view_new)
 +EA_FACTORY_GOBJECT (EA_TYPE_AB_VIEW, ea_ab_view, ea_ab_view_new)
 +
 +static gboolean ea_addressbook_focus_watcher (GSignalInvocationHint *ihint,
 +					      guint n_param_values,
 +					      const GValue *param_values,
 +					      gpointer data);
 +
 +void e_minicard_a11y_init (void)
 +{
 +	EA_SET_FACTORY (e_minicard_get_type (), ea_minicard);
 +}
 +
 +void e_minicard_view_a11y_init (void)
 +{
 +	EA_SET_FACTORY (e_minicard_view_get_type (), ea_minicard_view);
 +
 +	if (atk_get_root ()) {
 +		g_signal_add_emission_hook (g_signal_lookup ("event",
 +					    e_minicard_get_type()),
 +					    0, ea_addressbook_focus_watcher,
 +					    NULL, (GDestroyNotify) NULL);
 +	}
 +}
 +
 +void eab_view_a11y_init (void)
 +{
 +	EA_SET_FACTORY (E_TYPE_ADDRESSBOOK_VIEW, ea_ab_view);
 +}
 +
 +static gboolean
 +ea_addressbook_focus_watcher (GSignalInvocationHint *ihint,
 +			   guint n_param_values,
 +			   const GValue *param_values,
 +			   gpointer data)
 +{
 +	GObject *object;
 +	GdkEvent *event;
 +	AtkObject *ea_event = NULL;
 +
 +	object = g_value_get_object (param_values + 0);
 +	event = g_value_get_boxed (param_values + 1);
 +
 +	if (E_IS_MINICARD (object)) {
 +                GnomeCanvasItem *item = GNOME_CANVAS_ITEM (object);
 +		ea_event = atk_gobject_accessible_for_object (object);
 +		if (event->type == GDK_FOCUS_CHANGE) {
 +			if ((event->focus_change.in) && (E_IS_MINICARD (item->canvas->focused_item)))
 +				atk_focus_tracker_notify (ea_event);
 +		}
 +	}
 +
 +	return TRUE;
 +}
diff --cc addressbook/gui/widgets/a11y/ea-minicard-view.c
index aed11ed,0000000..052db4d
mode 100644,000000..100644
--- a/addressbook/gui/widgets/a11y/ea-minicard-view.c
+++ b/addressbook/gui/widgets/a11y/ea-minicard-view.c
@@@ -1,413 -1,0 +1,413 @@@
 +/*
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Authors:
 + *		Leon Zhang < leon zhang sun com>
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include <config.h>
 +#include <string.h>
 +#include <gtk/gtk.h>
 +#include <glib/gi18n.h>
 +#include "ea-minicard.h"
 +#include "ea-minicard-view.h"
 +#include "eab-gui-util.h"
 +#include "e-addressbook-view.h"
 +
 +static const char * action_name[] = {
 +	N_("New Contact"),
 +	N_("New Contact List")
 +};
 +
 +
 +static G_CONST_RETURN gchar* ea_minicard_view_get_name (AtkObject *accessible);
 +static G_CONST_RETURN gchar* ea_minicard_view_get_description (AtkObject *accessible);
 +
 +static void ea_minicard_view_class_init (EaMinicardViewClass *klass);
 +
 +static gint ea_minicard_view_get_n_children (AtkObject *obj);
 +static AtkObject *ea_minicard_view_ref_child (AtkObject *obj, gint i);
 +
 +static AtkStateSet *ea_minicard_view_ref_state_set(AtkObject *obj);
 +
 +static void atk_selection_interface_init (AtkSelectionIface *iface);
 +static gboolean selection_interface_add_selection (AtkSelection *selection,
 +						   gint i);
 +static gboolean selection_interface_clear_selection (AtkSelection *selection);
 +static AtkObject* selection_interface_ref_selection (AtkSelection *selection,
 +						     gint i);
 +static gint selection_interface_get_selection_count (AtkSelection *selection);
 +static gboolean selection_interface_is_child_selected (AtkSelection *selection,
 +						       gint i);
 +
 +static void atk_action_interface_init (AtkActionIface *iface);
 +static gboolean atk_action_interface_do_action (AtkAction *iface, gint i);
 +static gint atk_action_interface_get_n_action (AtkAction *iface);
 +static G_CONST_RETURN gchar* atk_action_interface_get_description (AtkAction *iface, gint i);
 +static G_CONST_RETURN gchar* atk_action_interface_get_name (AtkAction *iface, gint i);
 +
 +static gpointer parent_class = NULL;
 +
 +GType
 +ea_minicard_view_get_type (void)
 +{
 +	static GType type = 0;
 +	AtkObjectFactory *factory;
 +	GTypeQuery query;
 +	GType derived_atk_type;
 +
 +	if (!type) {
 +		static  GTypeInfo tinfo =  {
 +			sizeof (EaMinicardViewClass),
 +			(GBaseInitFunc) NULL,  /* base_init */
 +			(GBaseFinalizeFunc) NULL,  /* base_finalize */
 +			(GClassInitFunc) ea_minicard_view_class_init,
 +			(GClassFinalizeFunc) NULL, /* class_finalize */
 +			NULL,	   /* class_data */
 +			sizeof (EaMinicardView),
 +			0,	     /* n_preallocs */
 +			(GInstanceInitFunc) NULL, /* instance init */
 +			NULL /* value table */
 +		};
 +
 +		static const GInterfaceInfo atk_selection_info = {
 +			(GInterfaceInitFunc) atk_selection_interface_init,
 +			(GInterfaceFinalizeFunc) NULL,
 +			NULL
 +		};
 +
 +		static const GInterfaceInfo atk_action_info = {
 +			(GInterfaceInitFunc) atk_action_interface_init,
 +			(GInterfaceFinalizeFunc) NULL,
 +			NULL
 +		};
 +
 +		/*
 +		 * Figure out the size of the class and instance
 +		 * we are run-time deriving from (GailWidget, in this case) */
 +
 +		factory = atk_registry_get_factory (atk_get_default_registry (),
 +							GNOME_TYPE_CANVAS_GROUP);
 +		derived_atk_type = atk_object_factory_get_accessible_type (factory);
 +		g_type_query (derived_atk_type, &query);
 +
 +		tinfo.class_size = query.class_size;
 +		tinfo.instance_size = query.instance_size;
 +
 +		type = g_type_register_static (derived_atk_type,
 +						"EaMinicardView", &tinfo, 0);
 +		g_type_add_interface_static (type, ATK_TYPE_SELECTION,
 +					     &atk_selection_info);
 +		g_type_add_interface_static (type, ATK_TYPE_ACTION,
 +					     &atk_action_info);
 +
 +	}
 +
 +	return type;
 +}
 +
 +static void
 +ea_minicard_view_class_init (EaMinicardViewClass *klass)
 +{
 +	AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
 +
 +	parent_class = g_type_class_peek_parent (klass);
 +
 +	class->get_name = ea_minicard_view_get_name;
 +	class->get_description = ea_minicard_view_get_description;
 +	class->ref_state_set = ea_minicard_view_ref_state_set;
 +	class->get_n_children = ea_minicard_view_get_n_children;
 +	class->ref_child = ea_minicard_view_ref_child;
 +}
 +
 +static G_CONST_RETURN gchar*
 +ea_minicard_view_get_name (AtkObject *accessible)
 +{
 +	EReflow *reflow;
 +	gchar *string;
 +	EMinicardView *card_view;
 +	EBook *book = NULL;
 +	const gchar *source_name;
 +
 +	g_return_val_if_fail (EA_IS_MINICARD_VIEW (accessible), NULL);
 +
 +	reflow = E_REFLOW(atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (accessible)));
 +
 +	if (!reflow)
 +		return NULL;
 +
 +	/* Get the current name of minicard view*/
 +	card_view = E_MINICARD_VIEW (reflow);
 +	g_object_get (card_view->adapter, "book", &book, NULL);
 +	g_return_val_if_fail (E_IS_BOOK (book), NULL);
 +	source_name = e_source_peek_name (e_book_get_source (book));
 +	if (!source_name)
 +		source_name="";
 +
 +	string = g_strdup_printf (ngettext ("current address book folder %s has %d card",
 +	                          "current address book folder %s has %d cards",
 +	                          reflow->count), source_name, reflow->count);
 +
 +	ATK_OBJECT_CLASS (parent_class)->set_name (accessible, string);
 +	g_free (string);
 +	g_object_unref(book);
 +	return accessible->name;
 +}
 +
 +static G_CONST_RETURN gchar*
 +ea_minicard_view_get_description (AtkObject *accessible)
 +{
 +	g_return_val_if_fail (EA_IS_MINICARD_VIEW(accessible), NULL);
 +	if (accessible->description)
 +		return accessible->description;
 +
 +	return _("evolution address book");
 +}
 +
 +AtkObject*
 +ea_minicard_view_new (GObject *obj)
 +{
 +	GObject *object;
 +	AtkObject *accessible;
 +
 +	g_return_val_if_fail (E_IS_MINICARD_VIEW(obj), NULL);
 +	object = g_object_new (EA_TYPE_MINICARD_VIEW, NULL);
 +	accessible = ATK_OBJECT (object);
 +	atk_object_initialize (accessible, obj);
 +	accessible->role = ATK_ROLE_PANEL;
 +	return accessible;
 +}
 +
 +static gint
 +ea_minicard_view_get_n_children (AtkObject *accessible)
 +{
 +	EReflow *reflow;
 +
 +	gint child_num = 0;
 +
 +	g_return_val_if_fail (EA_IS_MINICARD_VIEW (accessible), -1);
 +
 +	reflow = E_REFLOW (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE(accessible)));
 +
 +	if (!reflow)
 +		return -1;
 +
 +	child_num = reflow->count;
 +
 +	return child_num;
 +}
 +
 +static AtkStateSet *ea_minicard_view_ref_state_set (AtkObject *obj)
 +{
 +	AtkStateSet *state_set = NULL;
 +	GObject *gobj = NULL;
 +
 +	state_set = ATK_OBJECT_CLASS (parent_class)->ref_state_set (obj);
 +	if( !state_set )
 +		state_set = atk_state_set_new ();
 +
 +	gobj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (obj));
 +	if( !gobj )
 +		return state_set;
 +
 +	atk_state_set_add_state (state_set, ATK_STATE_ENABLED);
 +	atk_state_set_add_state (state_set, ATK_STATE_SENSITIVE);
 +	atk_state_set_add_state (state_set, ATK_STATE_SHOWING);
 +
 +	return state_set;
 +}
 +
 +static AtkObject *
 +ea_minicard_view_ref_child (AtkObject *accessible, gint index)
 +{
 +	EReflow *reflow;
 +	gint child_num;
 +	AtkObject *atk_object = NULL;
 +	EMinicard *card = NULL;
 +
 +	g_return_val_if_fail (EA_IS_MINICARD_VIEW (accessible), NULL);
 +
 +	child_num = atk_object_get_n_accessible_children (accessible);
 +	if (child_num <= 0 || index < 0 || index >= child_num)
 +		return NULL;
 +
 +	reflow = E_REFLOW (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (accessible)));
 +	if (!reflow)
 +		return NULL;
 +	if (!reflow->items )
 +		return NULL;
 +		/* a minicard */
 +	if (index < child_num) {
 +		card = E_MINICARD (reflow->items[index]);
 +		atk_object = atk_gobject_accessible_for_object (G_OBJECT (card));
 +	} else {
 +		return NULL;
 +	}
 +
 +	g_object_ref (atk_object);
 +		return atk_object;
 +}
 +
 +/* atkselection interface */
 +
 +static void
 +atk_selection_interface_init (AtkSelectionIface *iface)
 +{
 +	g_return_if_fail (iface != NULL);
 +
 +	iface->add_selection = selection_interface_add_selection;
 +	iface->clear_selection = selection_interface_clear_selection;
 +	iface->ref_selection = selection_interface_ref_selection;
 +	iface->get_selection_count = selection_interface_get_selection_count;
 +	iface->is_child_selected = selection_interface_is_child_selected;
 +}
 +
 +static gboolean
 +selection_interface_add_selection (AtkSelection *selection, gint i)
 +{
 +	AtkGObjectAccessible *atk_gobj= NULL;
 +	EReflow *reflow = NULL;
 +
 +	atk_gobj = ATK_GOBJECT_ACCESSIBLE (selection);
 +	reflow = E_REFLOW (atk_gobject_accessible_get_object (atk_gobj));
 +
 +	if (!reflow)
 +		return FALSE;
 +
 +	selection_interface_clear_selection (selection);
 +	e_selection_model_select_single_row (reflow->selection, i);
 +
 +	return TRUE;
 +}
 +
 +static gboolean
 +selection_interface_clear_selection (AtkSelection *selection)
 +{
 +	AtkGObjectAccessible *atk_gobj = NULL;
 +	EReflow *reflow = NULL;
 +
 +	atk_gobj = ATK_GOBJECT_ACCESSIBLE (selection);
 +	reflow = E_REFLOW(atk_gobject_accessible_get_object (atk_gobj));
 +
 +	if( !reflow )
 +		return FALSE;
 +
 +	e_selection_model_clear (reflow->selection);
 +
 +	return TRUE;
 +}
 +
 +static AtkObject*
 +selection_interface_ref_selection (AtkSelection *selection, gint i)
 +{
 +	return ea_minicard_view_ref_child (ATK_OBJECT (selection), i);
 +}
 +
 +static gint
 +selection_interface_get_selection_count (AtkSelection *selection)
 +{
 +	AtkGObjectAccessible *atk_gobj = NULL;
 +	EReflow *reflow = NULL;
 +
 +	atk_gobj = ATK_GOBJECT_ACCESSIBLE (selection);
 +	reflow = E_REFLOW (atk_gobject_accessible_get_object (atk_gobj));
 +
 +	if (!reflow )
 +		return FALSE;
 +
 +	return e_selection_model_selected_count (reflow->selection);
 +}
 +
 +static gboolean
 +selection_interface_is_child_selected (AtkSelection *selection, gint i)
 +{
 +	AtkGObjectAccessible *atk_gobj = NULL;
 +	EReflow *reflow = NULL;
 +
 +	atk_gobj = ATK_GOBJECT_ACCESSIBLE (selection);
 +	reflow = E_REFLOW(atk_gobject_accessible_get_object (atk_gobj));
 +
 +	if( !reflow )
 +		return FALSE;
 +
 +	return e_selection_model_is_row_selected (reflow->selection, i);
 +}
 +
 +static void atk_action_interface_init (AtkActionIface *iface)
 +{
 +	g_return_if_fail (iface != NULL);
 +
 +	iface->do_action = atk_action_interface_do_action;
 +	iface->get_n_actions = atk_action_interface_get_n_action;
 +	iface->get_description = atk_action_interface_get_description;
 +	iface->get_name = atk_action_interface_get_name;
 +}
 +
 +static gboolean atk_action_interface_do_action (AtkAction *action, gint i)
 +{
 +	gboolean return_value = TRUE;
 +	EMinicardView *card_view;
 +
 +	AtkGObjectAccessible *atk_gobj= NULL;
 +        EReflow *reflow = NULL;
 +
 +	atk_gobj = ATK_GOBJECT_ACCESSIBLE (action);
 +	reflow = E_REFLOW (atk_gobject_accessible_get_object (atk_gobj));
 +
 +	if (reflow == NULL)
 +		return FALSE;
 +
 +	card_view = E_MINICARD_VIEW (reflow);
 +
 +	switch (i) {
 +		case 0:
 +		/* New Contact */
 +			e_minicard_view_create_contact (card_view);
 +			break;
 +		case 1:
 +		/* New Contact List */
 +			e_minicard_view_create_contact_list (card_view);
 +			break;
 +		default:
 +                	return_value = FALSE;
 +			break;
 +	}
 +
 +	return return_value;
 +}
 +
 +static gint atk_action_interface_get_n_action (AtkAction *iface)
 +{
 +	return G_N_ELEMENTS (action_name);
 +}
 +
 +static G_CONST_RETURN gchar*
 +atk_action_interface_get_description (AtkAction *iface, gint i)
 +{
 +	return atk_action_interface_get_name (iface, i);
 +}
 +
 +static G_CONST_RETURN gchar*
 +atk_action_interface_get_name (AtkAction *iface, gint i)
 +{
 +	if( i >= G_N_ELEMENTS (action_name) || i < 0)
 +		return NULL;
 +
 +	return action_name[i];
 +}
 +
diff --cc addressbook/gui/widgets/e-addressbook-selector.c
index e7bec99,0000000..21347e2
mode 100644,000000..100644
--- a/addressbook/gui/widgets/e-addressbook-selector.c
+++ b/addressbook/gui/widgets/e-addressbook-selector.c
@@@ -1,443 -1,0 +1,443 @@@
 +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
 +/* e-addressbook-selector.c
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of version 2 of the GNU General Public
 + * License as published by the Free Software Foundation.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 + * General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public
 + * License along with this program; if not, write to the
 + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 + * Boston, MA 02110-1301, USA.
 + */
 +
 +#include "e-addressbook-selector.h"
 +
 +#include <eab-book-util.h>
 +#include <eab-contact-merging.h>
 +
 +#define E_ADDRESSBOOK_SELECTOR_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_ADDRESSBOOK_SELECTOR, EAddressbookSelectorPrivate))
 +
 +#define PRIMARY_ADDRESSBOOK_KEY \
 +	"/apps/evolution/addressbook/display/primary_addressbook"
 +
 +typedef struct _MergeContext MergeContext;
 +
 +struct _EAddressbookSelectorPrivate {
 +	EAddressbookView *current_view;
 +};
 +
 +struct _MergeContext {
 +	EBook *source_book;
 +	EBook *target_book;
 +
 +	EContact *current_contact;
 +	GList *remaining_contacts;
 +	guint pending_removals;
 +
 +	gint remove_from_source : 1;
 +	gint copy_done          : 1;
 +};
 +
 +enum {
 +	PROP_0,
 +	PROP_CURRENT_VIEW
 +};
 +
 +enum {
 +	DND_TARGET_TYPE_VCARD,
 +	DND_TARGET_TYPE_SOURCE_VCARD
 +};
 +
 +static GtkTargetEntry drag_types[] = {
- 	{ "text/x-vcard", 0, DND_TARGET_TYPE_VCARD },
- 	{ "text/x-source-vcard", 0, DND_TARGET_TYPE_SOURCE_VCARD }
++	{ (gchar *) "text/x-vcard", 0, DND_TARGET_TYPE_VCARD },
++	{ (gchar *) "text/x-source-vcard", 0, DND_TARGET_TYPE_SOURCE_VCARD }
 +};
 +
 +static gpointer parent_class;
 +
 +static void
 +merge_context_next (MergeContext *merge_context)
 +{
 +	GList *list;
 +
 +	list = merge_context->remaining_contacts;
 +	merge_context->current_contact = list->data;
 +	list = g_list_delete_link (list, list);
 +	merge_context->remaining_contacts = list;
 +}
 +
 +static MergeContext *
 +merge_context_new (EBook *source_book,
 +                   EBook *target_book,
 +                   GList *contact_list)
 +{
 +	MergeContext *merge_context;
 +
 +	merge_context = g_slice_new0 (MergeContext);
 +	merge_context->source_book = source_book;
 +	merge_context->target_book = target_book;
 +	merge_context->remaining_contacts = contact_list;
 +	merge_context_next (merge_context);
 +
 +	return merge_context;
 +}
 +
 +static void
 +merge_context_free (MergeContext *merge_context)
 +{
 +	if (merge_context->source_book != NULL)
 +		g_object_unref (merge_context->source_book);
 +
 +	if (merge_context->target_book != NULL)
 +		g_object_unref (merge_context->target_book);
 +
 +	g_slice_free (MergeContext, merge_context);
 +}
 +
 +static void
 +addressbook_selector_removed_cb (EBook *book,
 +                                 EBookStatus status,
 +                                 MergeContext *merge_context)
 +{
 +	merge_context->pending_removals--;
 +
 +	if (merge_context->remaining_contacts != NULL)
 +		return;
 +
 +	if (merge_context->pending_removals > 0)
 +		return;
 +
 +	merge_context_free (merge_context);
 +}
 +
 +static void
 +addressbook_selector_merge_next_cb (EBook *book,
 +                                    EBookStatus status,
 +                                    const gchar *id,
 +                                    MergeContext *merge_context)
 +{
 +	if (merge_context->remove_from_source && status == E_BOOK_ERROR_OK) {
 +		/* Remove previous contact from source. */
 +		e_book_async_remove_contact (
 +			merge_context->source_book,
 +			merge_context->current_contact,
 +			(EBookCallback) addressbook_selector_removed_cb,
 +			merge_context);
 +		merge_context->pending_removals++;
 +	}
 +
 +	g_object_unref (merge_context->current_contact);
 +
 +	if (merge_context->remaining_contacts != NULL) {
 +		merge_context_next (merge_context);
 +		eab_merging_book_add_contact (
 +			merge_context->target_book,
 +			merge_context->current_contact,
 +			(EBookIdCallback) addressbook_selector_merge_next_cb,
 +			merge_context);
 +
 +	} else if (merge_context->pending_removals == 0)
 +		merge_context_free (merge_context);
 +}
 +
 +static void
 +addressbook_selector_load_primary_source (ESourceSelector *selector)
 +{
 +	GConfClient *client;
 +	ESourceList *source_list;
 +	ESource *source = NULL;
 +	const gchar *key;
 +	gchar *uid;
 +
 +	/* XXX If ESourceSelector had a "primary-uid" property,
 +	 *     we could just bind the GConf key to it. */
 +
 +	source_list = e_source_selector_get_source_list (selector);
 +
 +	client = gconf_client_get_default ();
 +	key = PRIMARY_ADDRESSBOOK_KEY;
 +	uid = gconf_client_get_string (client, key, NULL);
 +	g_object_unref (client);
 +
 +	if (uid != NULL) {
 +		source = e_source_list_peek_source_by_uid (source_list, uid);
 +		g_free (uid);
 +	} else {
 +		GSList *groups;
 +
 +		/* Dig up the first source in the source list.
 +		 * XXX libedataserver should provide API for this. */
 +		groups = e_source_list_peek_groups (source_list);
 +		while (groups != NULL) {
 +			ESourceGroup *source_group = groups->data;
 +			GSList *sources;
 +
 +			sources = e_source_group_peek_sources (source_group);
 +			if (sources != NULL) {
 +				source = sources->data;
 +				break;
 +			}
 +
 +			groups = g_slist_next (groups);
 +		}
 +	}
 +
 +	if (source != NULL)
 +		e_source_selector_set_primary_selection (selector, source);
 +}
 +
 +static void
 +addressbook_selector_set_property (GObject *object,
 +                                   guint property_id,
 +                                   const GValue *value,
 +                                   GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_CURRENT_VIEW:
 +			e_addressbook_selector_set_current_view (
 +				E_ADDRESSBOOK_SELECTOR (object),
 +				g_value_get_object (value));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +addressbook_selector_get_property (GObject *object,
 +                                   guint property_id,
 +                                   GValue *value,
 +                                   GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_CURRENT_VIEW:
 +			g_value_set_object (
 +				value,
 +				e_addressbook_selector_get_current_view (
 +				E_ADDRESSBOOK_SELECTOR (object)));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +addressbook_selector_dispose (GObject *object)
 +{
 +	EAddressbookSelectorPrivate *priv;
 +
 +	priv = E_ADDRESSBOOK_SELECTOR_GET_PRIVATE (object);
 +
 +	if (priv->current_view != NULL) {
 +		g_object_unref (priv->current_view);
 +		priv->current_view = NULL;
 +	}
 +
 +	/* Chain up to parent's dispose() method. */
 +	G_OBJECT_CLASS (parent_class)->dispose (object);
 +}
 +
 +static void
 +addressbook_selector_constructed (GObject *object)
 +{
 +	ESourceSelector *selector;
 +
 +	selector = E_SOURCE_SELECTOR (object);
 +	addressbook_selector_load_primary_source (selector);
 +}
 +
 +static void
 +addressbook_selector_primary_selection_changed (ESourceSelector *selector)
 +{
 +	ESource *source;
 +	GConfClient *client;
 +	const gchar *key;
 +	const gchar *string;
 +
 +	/* XXX If ESourceSelector had a "primary-uid" property,
 +	 *     we could just bind the GConf key to it. */
 +
 +	source = e_source_selector_peek_primary_selection (selector);
 +	if (source == NULL)
 +		return;
 +
 +	client = gconf_client_get_default ();
 +	key = PRIMARY_ADDRESSBOOK_KEY;
 +	string = e_source_peek_uid (source);
 +	gconf_client_set_string (client, key, string, NULL);
 +	g_object_unref (client);
 +}
 +
 +static gboolean
 +addressbook_selector_data_dropped (ESourceSelector *selector,
 +                                   GtkSelectionData *selection_data,
 +                                   ESource *destination,
 +                                   GdkDragAction action,
 +                                   guint info)
 +{
 +	EAddressbookSelectorPrivate *priv;
 +	MergeContext *merge_context;
 +	EAddressbookModel *model;
 +	EBook *source_book;
 +	EBook *target_book;
 +	GList *list;
 +	const gchar *string;
 +	gboolean remove_from_source;
 +
 +	priv = E_ADDRESSBOOK_SELECTOR_GET_PRIVATE (selector);
 +	g_return_val_if_fail (priv->current_view != NULL, FALSE);
 +
 +	string = (const gchar *) selection_data->data;
 +	remove_from_source = (action == GDK_ACTION_MOVE);
 +
 +	target_book = e_book_new (destination, NULL);
 +	if (target_book == NULL)
 +		return FALSE;
 +
 +	e_book_open (target_book, FALSE, NULL);
 +
 +	/* XXX Function assumes both out arguments are provided.  All we
 +	 *     care about is the contact list; source_book will be NULL. */
 +	eab_book_and_contact_list_from_string (string, &source_book, &list);
 +	if (list == NULL)
 +		return FALSE;
 +
 +	model = e_addressbook_view_get_model (priv->current_view);
 +	source_book = e_addressbook_model_get_book (model);
 +	g_return_val_if_fail (E_IS_BOOK (source_book), FALSE);
 +
 +	merge_context = merge_context_new (source_book, target_book, list);
 +	merge_context->remove_from_source = remove_from_source;
 +
 +	eab_merging_book_add_contact (
 +		target_book, merge_context->current_contact,
 +		(EBookIdCallback) addressbook_selector_merge_next_cb,
 +		merge_context);
 +
 +	return TRUE;
 +}
 +
 +static void
 +addressbook_selector_class_init (EAddressbookSelectorClass *class)
 +{
 +	GObjectClass *object_class;
 +	ESourceSelectorClass *selector_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (EAddressbookSelectorPrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->set_property = addressbook_selector_set_property;
 +	object_class->get_property = addressbook_selector_get_property;
 +	object_class->dispose = addressbook_selector_dispose;
 +	object_class->constructed = addressbook_selector_constructed;
 +
 +	selector_class = E_SOURCE_SELECTOR_CLASS (class);
 +	selector_class->primary_selection_changed =
 +		addressbook_selector_primary_selection_changed;
 +	selector_class->data_dropped = addressbook_selector_data_dropped;
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_CURRENT_VIEW,
 +		g_param_spec_object (
 +			"current-view",
 +			NULL,
 +			NULL,
 +			E_TYPE_ADDRESSBOOK_VIEW,
 +			G_PARAM_READWRITE));
 +}
 +
 +static void
 +addressbook_selector_init (EAddressbookSelector *selector)
 +{
 +	selector->priv = E_ADDRESSBOOK_SELECTOR_GET_PRIVATE (selector);
 +
 +	gtk_drag_dest_set (
 +		GTK_WIDGET (selector), GTK_DEST_DEFAULT_ALL,
 +		drag_types, G_N_ELEMENTS (drag_types),
 +		GDK_ACTION_COPY | GDK_ACTION_MOVE);
 +}
 +
 +GType
 +e_addressbook_selector_get_type (void)
 +{
 +	static GType type = 0;
 +
 +	if (G_UNLIKELY (type == 0)) {
 +		const GTypeInfo type_info = {
 +			sizeof (EAddressbookSelectorClass),
 +			(GBaseInitFunc) NULL,
 +			(GBaseFinalizeFunc) NULL,
 +			(GClassInitFunc) addressbook_selector_class_init,
 +			(GClassFinalizeFunc) NULL,
 +			NULL,  /* class_data */
 +			sizeof (EAddressbookSelector),
 +			0,     /* n_preallocs */
 +			(GInstanceInitFunc) addressbook_selector_init,
 +			NULL   /* value_table */
 +		};
 +
 +		type = g_type_register_static (
 +			E_TYPE_SOURCE_SELECTOR, "EAddressbookSelector",
 +			&type_info, 0);
 +	}
 +
 +	return type;
 +}
 +
 +GtkWidget *
 +e_addressbook_selector_new (ESourceList *source_list)
 +{
 +	g_return_val_if_fail (E_IS_SOURCE_LIST (source_list), NULL);
 +
 +	return g_object_new (
 +		E_TYPE_ADDRESSBOOK_SELECTOR,
 +		"source-list", source_list, NULL);
 +}
 +
 +EAddressbookView *
 +e_addressbook_selector_get_current_view (EAddressbookSelector *selector)
 +{
 +	g_return_val_if_fail (E_IS_ADDRESSBOOK_SELECTOR (selector), NULL);
 +
 +	return selector->priv->current_view;
 +}
 +
 +void
 +e_addressbook_selector_set_current_view (EAddressbookSelector *selector,
 +                                         EAddressbookView *current_view)
 +{
 +	/* XXX This is only needed for moving contacts via drag-and-drop.
 +	 *     The selection data doesn't include the source of the data
 +	 *     (the model for the currently selected address book view),
 +	 *     so we have to rely on it being provided to us.  I would
 +	 *     be happy to see this function go away. */
 +
 +	g_return_if_fail (E_IS_ADDRESSBOOK_SELECTOR (selector));
 +
 +	if (current_view != NULL)
 +		g_return_if_fail (E_IS_ADDRESSBOOK_VIEW (current_view));
 +
 +	if (selector->priv->current_view != NULL) {
 +		g_object_unref (selector->priv->current_view);
 +		selector->priv->current_view = NULL;
 +	}
 +
 +	if (current_view != NULL)
 +		g_object_ref (current_view);
 +
 +	selector->priv->current_view = current_view;
 +
 +	g_object_notify (G_OBJECT (selector), "current-view");
 +}
diff --cc addressbook/gui/widgets/e-addressbook-view.c
index 8ee3c14,4cd151f..e889d9b
--- a/addressbook/gui/widgets/e-addressbook-view.c
+++ b/addressbook/gui/widgets/e-addressbook-view.c
@@@ -107,22 -126,71 +107,22 @@@ enum 
  	DND_TARGET_TYPE_SOURCE_VCARD,
  	DND_TARGET_TYPE_VCARD
  };
 -#define VCARD_TYPE "text/x-vcard"
 -#define SOURCE_VCARD_TYPE "text/x-source-vcard"
 -
 -typedef struct EABSearchBarItem {
 -	ESearchBarItem search;
 -	char *image;
 -}EABSearchBarItem;
  
  static GtkTargetEntry drag_types[] = {
- 	{ "text/x-source-vcard", 0, DND_TARGET_TYPE_SOURCE_VCARD },
- 	{ "text/x-vcard", 0, DND_TARGET_TYPE_VCARD }
 -	{ (gchar *) SOURCE_VCARD_TYPE, 0, DND_TARGET_TYPE_SOURCE_VCARD },
 -	{ (gchar *) VCARD_TYPE, 0, DND_TARGET_TYPE_VCARD }
++	{ (gchar *) "text/x-source-vcard", 0, DND_TARGET_TYPE_SOURCE_VCARD },
++	{ (gchar *) "text/x-vcard", 0, DND_TARGET_TYPE_VCARD }
  };
 -static const int num_drag_types = sizeof (drag_types) / sizeof (drag_types[0]);
 -
 -static guint eab_view_signals [LAST_SIGNAL] = {0, };
  
 +static gpointer parent_class;
 +static guint signals[LAST_SIGNAL];
  static GdkAtom clipboard_atom = GDK_NONE;
  
 -static GalViewCollection *collection = NULL;
 -
 -enum {
 -	ESB_FULL_NAME,
 -	ESB_EMAIL,
 -	ESB_ANY
 -};
 -
 -#if 0
 -static ESearchBarItem addressbook_search_option_items[] = {
 -	{ N_("Name begins with"), ESB_FULL_NAME, ESB_ITEMTYPE_RADIO },
 -	{ N_("Email begins with"), ESB_EMAIL, ESB_ITEMTYPE_RADIO },
 -	{ N_("Any field contains"), ESB_ANY, ESB_ITEMTYPE_RADIO },
 -	{ NULL, -1, 0 }
 -};
 -#endif
 -
 -static ESearchBarItem addressbook_search_items[] = {
 -	E_FILTERBAR_ADVANCED,
 -	{NULL, 0, 0},
 -	E_FILTERBAR_SAVE,
 -	E_FILTERBAR_EDIT,
 -	{NULL, -1, 0}
 -};
 -
 -GType
 -eab_view_get_type (void)
 +static void
 +addressbook_view_emit_open_contact (EAddressbookView *view,
 +                                    EContact *contact,
 +                                    gboolean is_new_contact)
  {
 -	static GType type = 0;
 -
 -	if (!type) {
 -		static const GTypeInfo info =  {
 -			sizeof (EABViewClass),
 -			NULL,           /* base_init */
 -			NULL,           /* base_finalize */
 -			(GClassInitFunc) eab_view_class_init,
 -			NULL,           /* class_finalize */
 -			NULL,           /* class_data */
 -			sizeof (EABView),
 -			0,             /* n_preallocs */
 -			(GInstanceInitFunc) eab_view_init,
 -		};
 -
 -		type = g_type_register_static (GTK_TYPE_VBOX, "EABView", &info, 0);
 -	}
 -
 -	return type;
 +	g_signal_emit (view, signals[OPEN_CONTACT], 0, contact, is_new_contact);
  }
  
  static void
diff --cc addressbook/util/addressbook.h
index 2e25448,0000000..7bc92ee
mode 100644,000000..100644
--- a/addressbook/util/addressbook.h
+++ b/addressbook/util/addressbook.h
@@@ -1,31 -1,0 +1,31 @@@
 +/*
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Authors:
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef __ADDRESSBOOK_H__
 +#define __ADDRESSBOOK_H__
 +
 +#include <libebook/e-book.h>
 +
 +guint      addressbook_load                 (EBook *book, EBookCallback cb, gpointer closure);
 +void       addressbook_load_cancel          (guint id);
 +void       addressbook_load_default_book    (EBookCallback open_response, gpointer closure);
 +
 +#endif /* __ADDRESSBOOK_H__ */
diff --cc calendar/gui/a11y/ea-calendar.c
index 3cf41f3,0000000..2662f42
mode 100644,000000..100644
--- a/calendar/gui/a11y/ea-calendar.c
+++ b/calendar/gui/a11y/ea-calendar.c
@@@ -1,204 -1,0 +1,204 @@@
 +/*
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Authors:
 + *		Bolian Yin <bolian yin sun com>
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include <text/e-text.h>
 +#include <libgnomecanvas/gnome-canvas-pixbuf.h>
 +#include "ea-calendar-helpers.h"
 +#include "a11y/ea-factory.h"
 +#include "ea-calendar.h"
 +
 +#include "calendar/ea-cal-view.h"
 +#include "calendar/ea-cal-view-event.h"
 +#include "calendar/ea-day-view.h"
 +#include "calendar/ea-day-view-main-item.h"
 +#include "calendar/ea-week-view.h"
 +#include "calendar/ea-week-view-main-item.h"
 +#include "calendar/ea-gnome-calendar.h"
 +
 +
 +EA_FACTORY (EA_TYPE_CAL_VIEW, ea_cal_view, ea_cal_view_new)
 +EA_FACTORY (EA_TYPE_DAY_VIEW, ea_day_view, ea_day_view_new)
 +EA_FACTORY_GOBJECT (EA_TYPE_DAY_VIEW_MAIN_ITEM, ea_day_view_main_item, ea_day_view_main_item_new)
 +EA_FACTORY (EA_TYPE_WEEK_VIEW, ea_week_view, ea_week_view_new)
 +EA_FACTORY_GOBJECT (EA_TYPE_WEEK_VIEW_MAIN_ITEM, ea_week_view_main_item, ea_week_view_main_item_new)
 +EA_FACTORY (EA_TYPE_GNOME_CALENDAR, ea_gnome_calendar, ea_gnome_calendar_new)
 +
 +static gboolean ea_calendar_focus_watcher (GSignalInvocationHint *ihint,
 +					   guint n_param_values,
 +					   const GValue *param_values,
 +					   gpointer data);
 +
 +static gpointer e_text_type, pixbuf_type, e_day_view_type, e_week_view_type;
 +static gpointer e_day_view_main_item_type, e_week_view_main_item_type;
 +
 +void
 +gnome_calendar_a11y_init (void)
 +{
 +	/* we only add focus watcher when accessibility is enabled
 +	 */
 +	if (atk_get_root ()) {
 +		EA_SET_FACTORY (gnome_calendar_get_type(), ea_gnome_calendar);
 +
 +		/* force loading some types */
 +		e_text_type = g_type_class_ref (E_TYPE_TEXT);
 +		pixbuf_type = g_type_class_ref (GNOME_TYPE_CANVAS_PIXBUF);
 +		e_day_view_type = g_type_class_ref (e_day_view_get_type ());
 +		e_week_view_type = g_type_class_ref (e_week_view_get_type ());
 +		e_day_view_main_item_type = g_type_class_ref (e_day_view_main_item_get_type ());
 +		e_week_view_main_item_type = g_type_class_ref (e_week_view_main_item_get_type ());
 +
 +		g_signal_add_emission_hook (g_signal_lookup ("event", E_TYPE_TEXT),
 +					    0, ea_calendar_focus_watcher,
 +					    NULL, (GDestroyNotify) NULL);
 +		g_signal_add_emission_hook (g_signal_lookup ("event", GNOME_TYPE_CANVAS_PIXBUF),
 +                                            0, ea_calendar_focus_watcher,
 +                                            NULL, (GDestroyNotify) NULL);
 +		g_signal_add_emission_hook (g_signal_lookup ("event-after",
 +							     e_day_view_get_type()),
 +					    0, ea_calendar_focus_watcher,
 +					    NULL, (GDestroyNotify) NULL);
 +		g_signal_add_emission_hook (g_signal_lookup ("event",
 +							     e_day_view_main_item_get_type()),
 +					    0, ea_calendar_focus_watcher,
 +					    NULL, (GDestroyNotify) NULL);
 +		g_signal_add_emission_hook (g_signal_lookup ("event-after",
 +							     e_week_view_get_type()),
 +					    0, ea_calendar_focus_watcher,
 +					    NULL, (GDestroyNotify) NULL);
 +		g_signal_add_emission_hook (g_signal_lookup ("event",
 +							     e_week_view_main_item_get_type()),
 +					    0, ea_calendar_focus_watcher,
 +					    NULL, (GDestroyNotify) NULL);
 +
 +	}
 +}
 +
 +void
 +e_cal_view_a11y_init (void)
 +{
 +	EA_SET_FACTORY (e_calendar_view_get_type(), ea_cal_view);
 +}
 +
 +void
 +e_day_view_a11y_init (void)
 +{
 +	EA_SET_FACTORY (e_day_view_get_type(), ea_day_view);
 +}
 +
 +void
 +e_day_view_main_item_a11y_init (void)
 +{
 +	EA_SET_FACTORY (e_day_view_main_item_get_type (), ea_day_view_main_item);
 +}
 +
 +void
 +e_week_view_a11y_init (void)
 +{
 +	EA_SET_FACTORY (e_week_view_get_type(), ea_week_view);
 +}
 +
 +void
 +e_week_view_main_item_a11y_init (void)
 +{
 +	EA_SET_FACTORY (e_week_view_main_item_get_type (), ea_week_view_main_item);
 +}
 +
 +static gboolean
 +ea_calendar_focus_watcher (GSignalInvocationHint *ihint,
 +                           guint n_param_values,
 +                           const GValue *param_values,
 +                           gpointer data)
 +{
 +	GObject *object;
 +	GdkEvent *event;
 +        AtkObject *ea_event = NULL;
 +
 +	object = g_value_get_object (param_values + 0);
 +	event = g_value_get_boxed (param_values + 1);
 +
 +	if ((E_IS_TEXT (object)) || (GNOME_IS_CANVAS_PIXBUF (object))) {
 +		/* "event" signal on canvas item
 +		 */
 +		GnomeCanvasItem *canvas_item;
 +
 +		canvas_item = GNOME_CANVAS_ITEM (object);
 +		if (event->type == GDK_FOCUS_CHANGE) {
 +			if (event->focus_change.in) {
 +				ea_event =
 +					ea_calendar_helpers_get_accessible_for (canvas_item);
 +				if (!ea_event)
 +					/* not canvas item we want */
 +					return TRUE;
 +
 +			}
 +			atk_focus_tracker_notify (ea_event);
 +		}
 +	}
 +	else if (E_IS_DAY_VIEW (object)) {
 +		EDayView *day_view = E_DAY_VIEW (object);
 +		if (event->type == GDK_FOCUS_CHANGE) {
 +			if (event->focus_change.in) {
 +				/* give main item chance to emit focus */
 +				gnome_canvas_item_grab_focus (day_view->main_canvas_item);
 +			}
 +		}
 +	}
 +	else if (E_IS_DAY_VIEW_MAIN_ITEM (object)) {
 +		if (event->type == GDK_FOCUS_CHANGE) {
 +			if (event->focus_change.in) {
 +				/* we should emit focus on main item */
 +				ea_event = atk_gobject_accessible_for_object (object);
 +			}
 +			else
 +				/* focus out */
 +				ea_event = NULL;
 +#ifdef ACC_DEBUG
 +			printf ("EvoAcc: focus notify on day main item %p\n", (void *)object);
 +#endif
 +			atk_focus_tracker_notify (ea_event);
 +		}
 +	} else if (E_IS_WEEK_VIEW (object)) {
 +		EWeekView *week_view = E_WEEK_VIEW (object);
 +		if (event->type == GDK_FOCUS_CHANGE) {
 +			if (event->focus_change.in) {
 +				/* give main item chance to emit focus */
 +				gnome_canvas_item_grab_focus (week_view->main_canvas_item);
 +			}
 +		}
 +	}
 +	else if (E_IS_WEEK_VIEW_MAIN_ITEM (object)) {
 +		if (event->type == GDK_FOCUS_CHANGE) {
 +			if (event->focus_change.in) {
 +				/* we should emit focus on main item */
 +				ea_event = atk_gobject_accessible_for_object (object);
 +			}
 +			else
 +				/* focus out */
 +				ea_event = NULL;
 +#ifdef ACC_DEBUG
 +			printf ("EvoAcc: focus notify on week main item %p\n", (void *)object);
 +#endif
 +			atk_focus_tracker_notify (ea_event);
 +		}
 +	}
 +	return TRUE;
 +}
diff --cc calendar/gui/a11y/ea-day-view-cell.c
index 4698a3d,0000000..3555723
mode 100644,000000..100644
--- a/calendar/gui/a11y/ea-day-view-cell.c
+++ b/calendar/gui/a11y/ea-day-view-cell.c
@@@ -1,396 -1,0 +1,396 @@@
 +/*
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Authors:
 + *		Bolian Yin <bolian yin sun com>
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "ea-day-view-cell.h"
 +#include "ea-day-view-main-item.h"
 +#include "ea-day-view.h"
 +#include "a11y/ea-factory.h"
 +
 +/* EDayViewCell */
 +
 +static void e_day_view_cell_class_init (EDayViewCellClass *class);
 +
 +EA_FACTORY_GOBJECT (EA_TYPE_DAY_VIEW_CELL, ea_day_view_cell, ea_day_view_cell_new)
 +
 +GType
 +e_day_view_cell_get_type (void)
 +{
 +	static GType type = 0;
 +
 +	if (!type) {
 +		static GTypeInfo tinfo = {
 +			sizeof (EDayViewCellClass),
 +			(GBaseInitFunc) NULL, /* base init */
 +			(GBaseFinalizeFunc) NULL, /* base finalize */
 +			(GClassInitFunc) e_day_view_cell_class_init, /* class init */
 +			(GClassFinalizeFunc) NULL, /* class finalize */
 +			NULL, /* class data */
 +			sizeof (EDayViewCell), /* instance size */
 +			0, /* nb preallocs */
 +			(GInstanceInitFunc) NULL, /* instance init */
 +			NULL /* value table */
 +		};
 +
 +		type = g_type_register_static (G_TYPE_OBJECT,
 +					       "EDayViewCell", &tinfo, 0);
 +	}
 +
 +	return type;
 +}
 +
 +static void
 +e_day_view_cell_class_init (EDayViewCellClass *class)
 +{
 +    EA_SET_FACTORY (e_day_view_cell_get_type (), ea_day_view_cell);
 +}
 +
 +EDayViewCell *
 +e_day_view_cell_new (EDayView *day_view, gint row, gint column)
 +{
 +	GObject *object;
 +	EDayViewCell *cell;
 +
 +	g_return_val_if_fail (E_IS_DAY_VIEW (day_view), NULL);
 +
 +	object = g_object_new (E_TYPE_DAY_VIEW_CELL, NULL);
 +	cell = E_DAY_VIEW_CELL (object);
 +	cell->day_view = day_view;
 +	cell->row = row;
 +	cell->column = column;
 +
 +#ifdef ACC_DEBUG
 +	printf ("EvoAcc: e_day_view_cell created %p\n", (void *)cell);
 +#endif
 +
 +	return cell;
 +}
 +
 +/* EaDayViewCell */
 +
 +static void ea_day_view_cell_class_init (EaDayViewCellClass *klass);
 +
 +static G_CONST_RETURN gchar* ea_day_view_cell_get_name (AtkObject *accessible);
 +static G_CONST_RETURN gchar* ea_day_view_cell_get_description (AtkObject *accessible);
 +static AtkStateSet* ea_day_view_cell_ref_state_set (AtkObject *obj);
 +static AtkObject * ea_day_view_cell_get_parent (AtkObject *accessible);
 +static gint ea_day_view_cell_get_index_in_parent (AtkObject *accessible);
 +
 +/* component interface */
 +static void atk_component_interface_init (AtkComponentIface *iface);
 +static void component_interface_get_extents (AtkComponent *component,
 +					     gint *x, gint *y,
 +					     gint *width, gint *height,
 +					     AtkCoordType coord_type);
 +static gboolean component_interface_grab_focus (AtkComponent *component);
 +
 +static gpointer parent_class = NULL;
 +
 +#ifdef ACC_DEBUG
 +static gint n_ea_day_view_cell_created = 0, n_ea_day_view_cell_destroyed = 0;
 +static void ea_day_view_cell_finalize (GObject *object);
 +#endif
 +
 +GType
 +ea_day_view_cell_get_type (void)
 +{
 +	static GType type = 0;
 +
 +	if (!type) {
 +		static GTypeInfo tinfo = {
 +			sizeof (EaDayViewCellClass),
 +			(GBaseInitFunc) NULL, /* base init */
 +			(GBaseFinalizeFunc) NULL, /* base finalize */
 +			(GClassInitFunc) ea_day_view_cell_class_init, /* class init */
 +			(GClassFinalizeFunc) NULL, /* class finalize */
 +			NULL, /* class data */
 +			sizeof (EaDayViewCell), /* instance size */
 +			0, /* nb preallocs */
 +			(GInstanceInitFunc) NULL, /* instance init */
 +			NULL /* value table */
 +		};
 +
 +		static const GInterfaceInfo atk_component_info = {
 +			(GInterfaceInitFunc) atk_component_interface_init,
 +			(GInterfaceFinalizeFunc) NULL,
 +			NULL
 +		};
 +
 +		type = g_type_register_static (ATK_TYPE_GOBJECT_ACCESSIBLE,
 +					       "EaDayViewCell", &tinfo, 0);
 +		g_type_add_interface_static (type, ATK_TYPE_COMPONENT,
 +					     &atk_component_info);
 +	}
 +
 +	return type;
 +}
 +
 +static void
 +ea_day_view_cell_class_init (EaDayViewCellClass *klass)
 +{
 +	AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
 +
 +#ifdef ACC_DEBUG
 +	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 +	gobject_class->finalize = ea_day_view_cell_finalize;
 +#endif
 +
 +	parent_class = g_type_class_peek_parent (klass);
 +
 +	class->get_name = ea_day_view_cell_get_name;
 +	class->get_description = ea_day_view_cell_get_description;
 +	class->ref_state_set = ea_day_view_cell_ref_state_set;
 +
 +	class->get_parent = ea_day_view_cell_get_parent;
 +	class->get_index_in_parent = ea_day_view_cell_get_index_in_parent;
 +}
 +
 +AtkObject*
 +ea_day_view_cell_new (GObject *obj)
 +{
 +	gpointer object;
 +	AtkObject *atk_object;
 +
 +	g_return_val_if_fail (E_IS_DAY_VIEW_CELL (obj), NULL);
 +
 +	object = g_object_new (EA_TYPE_DAY_VIEW_CELL, NULL);
 +	atk_object = ATK_OBJECT (object);
 +	atk_object_initialize (atk_object, obj);
 +	atk_object->role = ATK_ROLE_UNKNOWN;
 +
 +#ifdef ACC_DEBUG
 +	++n_ea_day_view_cell_created;
 +	printf ("ACC_DEBUG: n_ea_day_view_cell_created = %d\n",
 +		n_ea_day_view_cell_created);
 +#endif
 +	return atk_object;
 +}
 +
 +#ifdef ACC_DEBUG
 +static void ea_day_view_cell_finalize (GObject *object)
 +{
 +	G_OBJECT_CLASS (parent_class)->finalize (object);
 +
 +	++n_ea_day_view_cell_destroyed;
 +	printf ("ACC_DEBUG: n_ea_day_view_cell_destroyed = %d\n",
 +		n_ea_day_view_cell_destroyed);
 +}
 +#endif
 +
 +static G_CONST_RETURN gchar*
 +ea_day_view_cell_get_name (AtkObject *accessible)
 +{
 +	AtkGObjectAccessible *atk_gobj;
 +	GObject *g_obj;
 +	EDayViewCell *cell;
 +
 +	g_return_val_if_fail (EA_IS_DAY_VIEW_CELL (accessible), NULL);
 +
 +	if (!accessible->name) {
 +		AtkObject *ea_main_item;
 +		GnomeCanvasItem *main_item;
 +		gchar *new_name = g_strdup ("");
 +		const gchar *row_label, *column_label;
 +
 +		atk_gobj = ATK_GOBJECT_ACCESSIBLE (accessible);
 +		g_obj = atk_gobject_accessible_get_object (atk_gobj);
 +		if (!g_obj)
 +			return NULL;
 +
 +		cell = E_DAY_VIEW_CELL (g_obj);
 +		main_item = cell->day_view->main_canvas_item;
 +		ea_main_item = atk_gobject_accessible_for_object (G_OBJECT (main_item));
 +		column_label = atk_table_get_column_description (ATK_TABLE (ea_main_item),
 +								 cell->column);
 +		row_label = atk_table_get_row_description (ATK_TABLE (ea_main_item),
 +							   cell->row);
 +		new_name = g_strconcat (column_label, " ", row_label, NULL);
 +		ATK_OBJECT_CLASS (parent_class)->set_name (accessible, new_name);
 +		g_free (new_name);
 +	}
 +	return accessible->name;
 +}
 +
 +static G_CONST_RETURN gchar*
 +ea_day_view_cell_get_description (AtkObject *accessible)
 +{
 +	return ea_day_view_cell_get_name (accessible);
 +}
 +
 +static AtkStateSet*
 +ea_day_view_cell_ref_state_set (AtkObject *obj)
 +{
 +  AtkStateSet *state_set;
 +  GObject *g_obj;
 +  AtkObject *parent;
 +  gint x, y, width, height;
 +  gint parent_x, parent_y, parent_width, parent_height;
 +
 +  state_set = ATK_OBJECT_CLASS (parent_class)->ref_state_set (obj);
 +  g_obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE(obj));
 +  if (!g_obj)
 +	  return state_set;
 +
 +  atk_state_set_add_state (state_set, ATK_STATE_SELECTABLE);
 +
 +  parent = atk_object_get_parent (obj);
 +  atk_component_get_extents (ATK_COMPONENT (obj), &x, &y,
 +			     &width, &height, ATK_XY_WINDOW);
 +  atk_component_get_extents (ATK_COMPONENT (parent), &parent_x, &parent_y,
 +			     &parent_width, &parent_height, ATK_XY_WINDOW);
 +
 +
 +  if (x + width < parent_x || x > parent_x + parent_width ||
 +      y + height < parent_y || y > parent_y + parent_height)
 +	  /* the cell is out of the main canvas */
 +	  ;
 +  else
 +	  atk_state_set_add_state (state_set, ATK_STATE_VISIBLE);
 +
 +  return state_set;
 +}
 +
 +static AtkObject *
 +ea_day_view_cell_get_parent (AtkObject *accessible)
 +{
 +	AtkGObjectAccessible *atk_gobj;
 +	GObject *g_obj;
 +	EDayViewCell *cell;
 +
 +	g_return_val_if_fail (EA_IS_DAY_VIEW_CELL (accessible), NULL);
 +
 +	atk_gobj = ATK_GOBJECT_ACCESSIBLE (accessible);
 +	g_obj = atk_gobject_accessible_get_object (atk_gobj);
 +	if (!g_obj)
 +		return NULL;
 +
 +	cell = E_DAY_VIEW_CELL (g_obj);
 +	return atk_gobject_accessible_for_object (G_OBJECT (cell->day_view->main_canvas_item));
 +}
 +
 +static gint
 +ea_day_view_cell_get_index_in_parent (AtkObject *accessible)
 +{
 +	AtkGObjectAccessible *atk_gobj;
 +	GObject *g_obj;
 +	EDayViewCell *cell;
 +	AtkObject *parent;
 +
 +	g_return_val_if_fail (EA_IS_DAY_VIEW_CELL (accessible), -1);
 +
 +	atk_gobj = ATK_GOBJECT_ACCESSIBLE (accessible);
 +	g_obj = atk_gobject_accessible_get_object (atk_gobj);
 +	if (!g_obj)
 +		return -1;
 +
 +	cell = E_DAY_VIEW_CELL (g_obj);
 +	parent = atk_object_get_parent (accessible);
 +	return atk_table_get_index_at (ATK_TABLE (parent),
 +				       cell->row, cell->column);
 +}
 +
 +/* Atk Component Interface */
 +
 +static void
 +atk_component_interface_init (AtkComponentIface *iface)
 +{
 +	g_return_if_fail (iface != NULL);
 +
 +	iface->get_extents = component_interface_get_extents;
 +	iface->grab_focus = component_interface_grab_focus;
 +}
 +
 +static void
 +component_interface_get_extents (AtkComponent *component,
 +				 gint *x, gint *y, gint *width, gint *height,
 +				 AtkCoordType coord_type)
 +{
 +	GObject *g_obj;
 +	AtkObject *atk_obj;
 +	EDayViewCell *cell;
 +	EDayView *day_view;
 +	GtkWidget *main_canvas;
 +	gint day_view_width, day_view_height;
 +	gint scroll_x, scroll_y;
 +
 +	*x = *y = *width = *height = 0;
 +
 +	g_return_if_fail (EA_IS_DAY_VIEW_CELL (component));
 +
 +	g_obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE(component));
 +	if (!g_obj)
 +		/* defunct object*/
 +		return;
 +
 +	cell = E_DAY_VIEW_CELL (g_obj);
 +	day_view = cell->day_view;
 +	main_canvas = cell->day_view->main_canvas;
 +
 +	atk_obj = atk_gobject_accessible_for_object (G_OBJECT (main_canvas));
 +	atk_component_get_extents (ATK_COMPONENT (atk_obj),
 +				   x, y,
 +				   &day_view_width, &day_view_height,
 +				   coord_type);
 +	gnome_canvas_get_scroll_offsets (GNOME_CANVAS (day_view->main_canvas),
 +					 &scroll_x, &scroll_y);
 +	*x += day_view->day_offsets[cell->column] - scroll_x;
 +	*y += day_view->row_height * cell->row
 +		- scroll_y;
 +	*width = day_view->day_widths[cell->column];
 +	*height = day_view->row_height;
 +}
 +
 +static gboolean
 +component_interface_grab_focus (AtkComponent *comp)
 +{
 +        GObject *g_obj;
 +        EDayViewCell *cell;
 +        EDayView *day_view;
 +        GtkWidget *toplevel;
 +
 +        g_return_val_if_fail (EA_IS_DAY_VIEW_CELL (comp), FALSE);
 +
 +        g_obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (comp));
 +        if (!g_obj)
 +                return FALSE;
 +
 +        cell = E_DAY_VIEW_CELL (g_obj);
 +        day_view = cell->day_view;
 +
 +        day_view->selection_start_day = cell->column;
 +        day_view->selection_end_day = cell->column;
 +        day_view->selection_start_row = cell->row;
 +        day_view->selection_end_row = cell->row;
 +
 +        e_day_view_ensure_rows_visible (day_view,
 +                        day_view->selection_start_row,
 +                        day_view->selection_end_row);
 +        e_day_view_update_calendar_selection_time (day_view);
 +        gtk_widget_queue_draw (day_view->main_canvas);
 +
 +        toplevel = gtk_widget_get_toplevel (GTK_WIDGET (day_view));
 +        if (GTK_WIDGET_TOPLEVEL (toplevel))
 +                gtk_window_present (GTK_WINDOW (toplevel));
 +
 +        return TRUE;
 +}
 +
diff --cc calendar/gui/a11y/ea-week-view-cell.c
index 3ec553b,0000000..b45cf66
mode 100644,000000..100644
--- a/calendar/gui/a11y/ea-week-view-cell.c
+++ b/calendar/gui/a11y/ea-week-view-cell.c
@@@ -1,478 -1,0 +1,478 @@@
 +/*
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Authors:
 + *		Bolian Yin <bolian yin sun com>
 + *		Yang Wu <Yang Wu sun com>
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "ea-week-view-cell.h"
 +#include "ea-week-view-main-item.h"
 +#include "a11y/ea-factory.h"
 +
 +/* EWeekViewCell */
 +
 +static void e_week_view_cell_class_init (EWeekViewCellClass *class);
 +
 +EA_FACTORY_GOBJECT (EA_TYPE_WEEK_VIEW_CELL, ea_week_view_cell, ea_week_view_cell_new)
 +
 +GType
 +e_week_view_cell_get_type (void)
 +{
 +	static GType type = 0;
 +
 +	if (!type) {
 +		static GTypeInfo tinfo = {
 +			sizeof (EWeekViewCellClass),
 +			(GBaseInitFunc) NULL, /* base init */
 +			(GBaseFinalizeFunc) NULL, /* base finalize */
 +			(GClassInitFunc) e_week_view_cell_class_init, /* class init */
 +			(GClassFinalizeFunc) NULL, /* class finalize */
 +			NULL, /* class data */
 +			sizeof (EWeekViewCell), /* instance size */
 +			0, /* nb preallocs */
 +			(GInstanceInitFunc) NULL, /* instance init */
 +			NULL /* value table */
 +		};
 +
 +		type = g_type_register_static (G_TYPE_OBJECT,
 +					       "EWeekViewCell", &tinfo, 0);
 +	}
 +
 +	return type;
 +}
 +
 +static void
 +e_week_view_cell_class_init (EWeekViewCellClass *class)
 +{
 +    EA_SET_FACTORY (e_week_view_cell_get_type (), ea_week_view_cell);
 +}
 +
 +EWeekViewCell *
 +e_week_view_cell_new (EWeekView *week_view, gint row, gint column)
 +{
 +	GObject *object;
 +	EWeekViewCell *cell;
 +
 +	g_return_val_if_fail (E_IS_WEEK_VIEW (week_view), NULL);
 +
 +	object = g_object_new (E_TYPE_WEEK_VIEW_CELL, NULL);
 +	cell = E_WEEK_VIEW_CELL (object);
 +	cell->week_view = week_view;
 +	cell->row = row;
 +	cell->column = column;
 +
 +#ifdef ACC_DEBUG
 +	printf ("EvoAcc: e_week_view_cell created %p\n", (void *)cell);
 +#endif
 +
 +	return cell;
 +}
 +
 +/* EaWeekViewCell */
 +
 +static void ea_week_view_cell_class_init (EaWeekViewCellClass *klass);
 +
 +static G_CONST_RETURN gchar* ea_week_view_cell_get_name (AtkObject *accessible);
 +static G_CONST_RETURN gchar* ea_week_view_cell_get_description (AtkObject *accessible);
 +static AtkStateSet* ea_week_view_cell_ref_state_set (AtkObject *obj);
 +static AtkObject * ea_week_view_cell_get_parent (AtkObject *accessible);
 +static gint ea_week_view_cell_get_index_in_parent (AtkObject *accessible);
 +
 +/* component interface */
 +static void atk_component_interface_init (AtkComponentIface *iface);
 +static void component_interface_get_extents (AtkComponent *component,
 +					     gint *x, gint *y,
 +					     gint *width, gint *height,
 +					     AtkCoordType coord_type);
 +static gboolean component_interface_grab_focus (AtkComponent *component);
 +
 +static gpointer parent_class = NULL;
 +
 +#ifdef ACC_DEBUG
 +static gint n_ea_week_view_cell_created = 0, n_ea_week_view_cell_destroyed = 0;
 +static void ea_week_view_cell_finalize (GObject *object);
 +#endif
 +
 +GType
 +ea_week_view_cell_get_type (void)
 +{
 +	static GType type = 0;
 +
 +	if (!type) {
 +		static GTypeInfo tinfo = {
 +			sizeof (EaWeekViewCellClass),
 +			(GBaseInitFunc) NULL, /* base init */
 +			(GBaseFinalizeFunc) NULL, /* base finalize */
 +			(GClassInitFunc) ea_week_view_cell_class_init, /* class init */
 +			(GClassFinalizeFunc) NULL, /* class finalize */
 +			NULL, /* class data */
 +			sizeof (EaWeekViewCell), /* instance size */
 +			0, /* nb preallocs */
 +			(GInstanceInitFunc) NULL, /* instance init */
 +			NULL /* value table */
 +		};
 +
 +		static const GInterfaceInfo atk_component_info = {
 +			(GInterfaceInitFunc) atk_component_interface_init,
 +			(GInterfaceFinalizeFunc) NULL,
 +			NULL
 +		};
 +		type = g_type_register_static (ATK_TYPE_GOBJECT_ACCESSIBLE,
 +					       "EaWeekViewCell", &tinfo, 0);
 +		g_type_add_interface_static (type, ATK_TYPE_COMPONENT,
 +					     &atk_component_info);
 +
 +	}
 +
 +	return type;
 +}
 +
 +static void
 +ea_week_view_cell_class_init (EaWeekViewCellClass *klass)
 +{
 +	AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
 +
 +#ifdef ACC_DEBUG
 +	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 +	gobject_class->finalize = ea_week_view_cell_finalize;
 +#endif
 +
 +	parent_class = g_type_class_peek_parent (klass);
 +
 +	class->get_name = ea_week_view_cell_get_name;
 +	class->get_description = ea_week_view_cell_get_description;
 +	class->ref_state_set = ea_week_view_cell_ref_state_set;
 +
 +	class->get_parent = ea_week_view_cell_get_parent;
 +	class->get_index_in_parent = ea_week_view_cell_get_index_in_parent;
 +
 +}
 +
 +AtkObject*
 +ea_week_view_cell_new (GObject *obj)
 +{
 +	gpointer object;
 +	AtkObject *atk_object;
 +
 +	g_return_val_if_fail (E_IS_WEEK_VIEW_CELL (obj), NULL);
 +	object = g_object_new (EA_TYPE_WEEK_VIEW_CELL, NULL);
 +	atk_object = ATK_OBJECT (object);
 +	atk_object_initialize (atk_object, obj);
 +	atk_object->role = ATK_ROLE_UNKNOWN;
 +
 +#ifdef ACC_DEBUG
 +	++n_ea_week_view_cell_created;
 +	printf ("ACC_DEBUG: n_ea_week_view_cell_created = %d\n",
 +		n_ea_week_view_cell_created);
 +#endif
 +	return atk_object;
 +}
 +
 +#ifdef ACC_DEBUG
 +static void ea_week_view_cell_finalize (GObject *object)
 +{
 +        G_OBJECT_CLASS (parent_class)->finalize (object);
 +
 +	++n_ea_week_view_cell_destroyed;
 +	printf ("ACC_DEBUG: n_ea_week_view_cell_destroyed = %d\n",
 +		n_ea_week_view_cell_destroyed);
 +}
 +#endif
 +
 +static G_CONST_RETURN gchar*
 +ea_week_view_cell_get_name (AtkObject *accessible)
 +{
 +	AtkGObjectAccessible *atk_gobj;
 +	GObject *g_obj;
 +	EWeekViewCell *cell;
 +
 +	g_return_val_if_fail (EA_IS_WEEK_VIEW_CELL (accessible), NULL);
 +
 +	if (!accessible->name) {
 +		AtkObject *ea_main_item;
 +		GnomeCanvasItem *main_item;
 +		gchar *new_name = g_strdup ("");
 +		const gchar *row_label, *column_label;
 +                gint new_column, new_row;
 +                gint start_day;
 +
 +		atk_gobj = ATK_GOBJECT_ACCESSIBLE (accessible);
 +		g_obj = atk_gobject_accessible_get_object (atk_gobj);
 +		if (!g_obj)
 +			return NULL;
 +
 +		cell = E_WEEK_VIEW_CELL (g_obj);
 +		main_item = cell->week_view->main_canvas_item;
 +		ea_main_item = atk_gobject_accessible_for_object (G_OBJECT (main_item));
 +
 +                start_day = cell->week_view->display_start_day;
 +                if (cell->column + start_day >= 7) {
 +                        new_column = cell->column + start_day - 7;
 +                        new_row = cell->row + 1;
 +                } else {
 +                        new_column = cell->column + start_day;
 +                        new_row = cell->row;
 +                }
 +
 +		column_label = atk_table_get_column_description (ATK_TABLE (ea_main_item),
 +								 new_column);
 +		row_label = atk_table_get_row_description (ATK_TABLE (ea_main_item),
 +							   new_row);
 +		new_name = g_strconcat (column_label, " ", row_label, NULL);
 +		ATK_OBJECT_CLASS (parent_class)->set_name (accessible, new_name);
 +		g_free (new_name);
 +	}
 +	return accessible->name;
 +}
 +
 +static G_CONST_RETURN gchar*
 +ea_week_view_cell_get_description (AtkObject *accessible)
 +{
 +	return ea_week_view_cell_get_name (accessible);
 +}
 +
 +static AtkStateSet*
 +ea_week_view_cell_ref_state_set (AtkObject *obj)
 +{
 +  AtkStateSet *state_set;
 +  GObject *g_obj;
 +  AtkObject *parent;
 +  gint x, y, width, height;
 +  gint parent_x, parent_y, parent_width, parent_height;
 +
 +  state_set = ATK_OBJECT_CLASS (parent_class)->ref_state_set (obj);
 +  g_obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE(obj));
 +  if (!g_obj)
 +	  return state_set;
 +
 +  atk_state_set_add_state (state_set, ATK_STATE_SELECTABLE);
 +
 +  parent = atk_object_get_parent (obj);
 +  atk_component_get_extents (ATK_COMPONENT (obj), &x, &y,
 +			     &width, &height, ATK_XY_WINDOW);
 +  atk_component_get_extents (ATK_COMPONENT (parent), &parent_x, &parent_y,
 +			     &parent_width, &parent_height, ATK_XY_WINDOW);
 +
 +
 +  if (x + width < parent_x || x > parent_x + parent_width ||
 +      y + height < parent_y || y > parent_y + parent_height)
 +	  /* the cell is out of the main canvas */
 +	  ;
 +  else
 +	  atk_state_set_add_state (state_set, ATK_STATE_VISIBLE);
 +
 +  return state_set;
 +}
 +
 +static AtkObject *
 +ea_week_view_cell_get_parent (AtkObject *accessible)
 +{
 +	AtkGObjectAccessible *atk_gobj;
 +	GObject *g_obj;
 +	EWeekViewCell *cell;
 +
 +	g_return_val_if_fail (EA_IS_WEEK_VIEW_CELL (accessible), NULL);
 +
 +	atk_gobj = ATK_GOBJECT_ACCESSIBLE (accessible);
 +	g_obj = atk_gobject_accessible_get_object (atk_gobj);
 +	if (!g_obj)
 +		return NULL;
 +
 +	cell = E_WEEK_VIEW_CELL (g_obj);
 +	return atk_gobject_accessible_for_object (G_OBJECT (cell->week_view->main_canvas_item));
 +}
 +
 +static gint
 +ea_week_view_cell_get_index_in_parent (AtkObject *accessible)
 +{
 +	AtkGObjectAccessible *atk_gobj;
 +	GObject *g_obj;
 +	EWeekViewCell *cell;
 +	AtkObject *parent;
 +
 +	g_return_val_if_fail (EA_IS_WEEK_VIEW_CELL (accessible), -1);
 +
 +	atk_gobj = ATK_GOBJECT_ACCESSIBLE (accessible);
 +	g_obj = atk_gobject_accessible_get_object (atk_gobj);
 +	if (!g_obj)
 +		return -1;
 +
 +	cell = E_WEEK_VIEW_CELL (g_obj);
 +	parent = atk_object_get_parent (accessible);
 +	return atk_table_get_index_at (ATK_TABLE (parent),
 +				       cell->row, cell->column);
 +}
 +
 +/* Atk Component Interface */
 +
 +static void
 +atk_component_interface_init (AtkComponentIface *iface)
 +{
 +	g_return_if_fail (iface != NULL);
 +
 +	iface->get_extents = component_interface_get_extents;
 +        iface->grab_focus = component_interface_grab_focus;
 +}
 +
 +static void
 +component_interface_get_extents (AtkComponent *component,
 +				 gint *x, gint *y, gint *width, gint *height,
 +				 AtkCoordType coord_type)
 +{
 +	GObject *g_obj;
 +	AtkObject *atk_obj;
 +	EWeekViewCell *cell;
 +	EWeekView *week_view;
 +	GtkWidget *main_canvas;
 +	gint week_view_width, week_view_height;
 +	gint scroll_x, scroll_y;
 +        gint start_day;
 +
 +	*x = *y = *width = *height = 0;
 +
 +	g_return_if_fail (EA_IS_WEEK_VIEW_CELL (component));
 +
 +	g_obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE(component));
 +	if (!g_obj)
 +		/* defunct object*/
 +		return;
 +
 +	cell = E_WEEK_VIEW_CELL (g_obj);
 +	week_view = cell->week_view;
 +	main_canvas = cell->week_view->main_canvas;
 +
 +	atk_obj = atk_gobject_accessible_for_object (G_OBJECT (main_canvas));
 +	atk_component_get_extents (ATK_COMPONENT (atk_obj),
 +				   x, y,
 +				   &week_view_width, &week_view_height,
 +				   coord_type);
 +	gnome_canvas_get_scroll_offsets (GNOME_CANVAS (week_view->main_canvas),
 +					 &scroll_x, &scroll_y);
 +        start_day = week_view->display_start_day;
 +        if (week_view->multi_week_view) {
 +                if (week_view->compress_weekend && (cell->column == (5 - start_day))) {
 +                        *height = week_view->row_heights[cell->row*2];
 +	                *width = week_view->col_widths[cell->column];
 +	                *x += week_view->col_offsets[cell->column] - scroll_x;
 +	                *y += week_view->row_offsets[cell->row*2]- scroll_y;
 +                } else if (week_view->compress_weekend && (cell->column == (6 - start_day))) {
 +                        *height = week_view->row_heights[cell->row*2];
 +                        *width = week_view->col_widths[cell->column - 1];
 +                        *x += week_view->col_offsets[cell->column - 1]- scroll_x;
 +                        *y += week_view->row_offsets[cell->row*2 + 1]- scroll_y;
 +                } else if (week_view->compress_weekend && (cell->column > (6 - start_day))){
 +                        *height = week_view->row_heights[cell->row*2]*2;
 +                        *width = week_view->col_widths[cell->column - 1];
 +                        *x += week_view->col_offsets[cell->column - 1] - scroll_x;
 +                        *y += week_view->row_offsets[cell->row*2]- scroll_y;
 +                } else {
 +	                *height = week_view->row_heights[cell->row*2]*2;
 +                        *width = week_view->col_widths[cell->column];
 +	                *x += week_view->col_offsets[cell->column] - scroll_x;
 +	                *y += week_view->row_offsets[cell->row*2]- scroll_y;
 +                }
 +        } else {
 +                if (start_day < 3) {
 +                        if (cell->column < 3) {
 +                                *height = week_view->row_heights[cell->column*2]*2;
 +                                *width = week_view->col_widths[0];
 +                                *x += week_view->col_offsets[0] - scroll_x;
 +                                *y += week_view->row_offsets[cell->column*2]- scroll_y;
 +                        } else {
 +                                if (cell->column == 5 - start_day) {
 +                                        *height = week_view->row_heights[(cell->column - 3)*2];
 +                                        *width = week_view->col_widths[1];
 +                                        *x += week_view->col_offsets[1] - scroll_x;
 +                                        *y += week_view->row_offsets[(cell->column - 3)*2]- scroll_y;
 +                                } else if (cell->column == 6 - start_day) {
 +                                        *height = week_view->row_heights[(cell->column - 4)*2];
 +                                        *width = week_view->col_widths[1];
 +                                        *x += week_view->col_offsets[1] - scroll_x;
 +                                        *y += week_view->row_offsets[(cell->column - 3)*2 - 1]- scroll_y;
 +                                } else if (cell->column > 6 - start_day) {
 +                                        *height = week_view->row_heights[(cell->column - 4)*2]*2;
 +                                        *width = week_view->col_widths[1];
 +                                        *x += week_view->col_offsets[1] - scroll_x;
 +                                        *y += week_view->row_offsets[(cell->column - 4)*2]- scroll_y;
 +                                } else {
 +                                        *height = week_view->row_heights[(cell->column - 3)*2]*2;
 +                                        *width = week_view->col_widths[1];
 +                                        *x += week_view->col_offsets[1] - scroll_x;
 +                                        *y += week_view->row_offsets[(cell->column - 3)*2]- scroll_y;
 +                                }
 +                        }
 +                } else if (cell->column < 4) {
 +                        if (cell->column == 5 - start_day) {
 +                                *height = week_view->row_heights[cell->column*2];
 +                                *width = week_view->col_widths[0];
 +                                *x += week_view->col_offsets[0] - scroll_x;
 +                                *y += week_view->row_offsets[cell->column*2]- scroll_y;
 +                        } else if (cell->column == 6 - start_day) {
 +                                *height = week_view->row_heights[(cell->column - 1)*2];
 +                                *width = week_view->col_widths[0];
 +                                *x += week_view->col_offsets[0] - scroll_x;
 +                                *y += week_view->row_offsets[cell->column*2 - 1]- scroll_y;
 +                        } else if (cell->column > 6 - start_day) {
 +                                *height = week_view->row_heights[(cell->column - 1)*2]*2;
 +                                *width = week_view->col_widths[0];
 +                                *x += week_view->col_offsets[0] - scroll_x;
 +                                *y += week_view->row_offsets[(cell->column - 1)*2]- scroll_y;
 +                        } else {
 +                                *height = week_view->row_heights[(cell->column)*2]*2;
 +                                *width = week_view->col_widths[0];
 +                                *x += week_view->col_offsets[0] - scroll_x;
 +                                *y += week_view->row_offsets[cell->column*2]- scroll_y;
 +                        }
 +                } else {
 +                        *height = week_view->row_heights[(cell->column - 4)*2]*2;
 +                        *width = week_view->col_widths[1];
 +                        *x += week_view->col_offsets[1] - scroll_x;
 +                        *y += week_view->row_offsets[(cell->column - 4)*2]- scroll_y;
 +                }
 +        }
 +}
 +
 +static gboolean
 +component_interface_grab_focus (AtkComponent *comp)
 +{
 +        GObject *g_obj;
 +        EWeekViewCell *cell;
 +        EWeekView *week_view;
 +        GtkWidget *toplevel;
 +
 +        g_return_val_if_fail (EA_IS_WEEK_VIEW_CELL (comp), FALSE);
 +
 +        g_obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (comp));
 +        if (!g_obj)
 +                return FALSE;
 +
 +        cell = E_WEEK_VIEW_CELL (g_obj);
 +        week_view = cell->week_view;
 +
 +        week_view->selection_start_day = cell->row * 7 + cell->column;
 +        week_view->selection_end_day = cell->row * 7 + cell->column;
 +        gtk_widget_queue_draw (week_view->main_canvas);
 +
 +        toplevel = gtk_widget_get_toplevel (GTK_WIDGET (week_view));
 +        if (GTK_WIDGET_TOPLEVEL (toplevel))
 +                gtk_window_present (GTK_WINDOW (toplevel));
 +
 +        return TRUE;
 +}
diff --cc calendar/gui/calendar-component.c
index 2aaaaf2,bca0832..eef60cf
--- a/calendar/gui/calendar-component.c
+++ b/calendar/gui/calendar-component.c
@@@ -65,9 -65,26 +65,9 @@@
  #define CREATE_MEETING_ID      "meeting"
  #define CREATE_ALLDAY_EVENT_ID "allday-event"
  #define CREATE_CALENDAR_ID      "calendar"
 -#define WEB_BASE_URI "webcal://"
 -#define CONTACTS_BASE_URI "contacts://"
 -#define WEATHER_BASE_URI "weather://"
 -#define PERSONAL_RELATIVE_URI "system"
  #define CALENDAR_ERROR_LEVEL_KEY "/apps/evolution/calendar/display/error_level"
- #define CALENDAR_ERROR_TIME_OUT_KEY "/apps/evolution/calendar/display/error_timeout" 
+ #define CALENDAR_ERROR_TIME_OUT_KEY "/apps/evolution/calendar/display/error_timeout"
  
 -enum DndTargetType {
 -	DND_TARGET_TYPE_CALENDAR_LIST
 -};
 -#define CALENDAR_TYPE "text/calendar"
 -#define XCALENDAR_TYPE "text/x-calendar"
 -static GtkTargetEntry drag_types[] = {
 -	{ (gchar *) CALENDAR_TYPE, 0, DND_TARGET_TYPE_CALENDAR_LIST },
 -	{ (gchar *) XCALENDAR_TYPE, 0, DND_TARGET_TYPE_CALENDAR_LIST }
 -};
 -static gint num_drag_types = sizeof(drag_types) / sizeof(drag_types[0]);
 -#define CALENDAR_COMPONENT_DEFAULT(cc) if (cc == NULL) cc = calendar_component_peek()
 -#define PARENT_TYPE bonobo_object_get_type ()
 -
  static BonoboObjectClass *parent_class = NULL;
  
  typedef struct
@@@ -708,9 -1608,68 +709,7 @@@ calendar_component_init (CalendarCompon
  	e_activity_handler_set_error_flush_time (priv->activity_handler,eni_config_get_error_timeout (CALENDAR_ERROR_TIME_OUT_KEY)*1000);
  
  	component->priv = priv;
 -	ensure_sources (component);
  
- 	if (!e_cal_get_sources (&priv->task_source_list, E_CAL_SOURCE_TYPE_TODO, NULL))
- 		;
- 	if (!e_cal_get_sources (&priv->memo_source_list, E_CAL_SOURCE_TYPE_JOURNAL, NULL))
- 		;
+ 	e_cal_get_sources (&priv->task_source_list, E_CAL_SOURCE_TYPE_TODO, NULL);
+ 	e_cal_get_sources (&priv->memo_source_list, E_CAL_SOURCE_TYPE_JOURNAL, NULL);
  }
 -
 -
 -/* Public API.  */
 -
 -CalendarComponent *
 -calendar_component_peek (void)
 -{
 -	static CalendarComponent *component = NULL;
 -
 -	if (component == NULL) {
 -		component = g_object_new (calendar_component_get_type (), NULL);
 -
 -		if (g_mkdir_with_parents (calendar_component_peek_config_directory (component), 0777) != 0) {
 -			g_warning (G_STRLOC ": Cannot create directory %s: %s",
 -				   calendar_component_peek_config_directory (component),
 -				   g_strerror (errno));
 -			g_object_unref (component);
 -			component = NULL;
 -		}
 -	}
 -
 -	return component;
 -}
 -
 -const char *
 -calendar_component_peek_base_directory (CalendarComponent *component)
 -{
 -	return component->priv->base_directory;
 -}
 -
 -const char *
 -calendar_component_peek_config_directory (CalendarComponent *component)
 -{
 -	return component->priv->config_directory;
 -}
 -
 -ESourceList *
 -calendar_component_peek_source_list (CalendarComponent *component)
 -{
 -	return component->priv->source_list;
 -}
 -
 -EActivityHandler *
 -calendar_component_peek_activity_handler (CalendarComponent *component)
 -{
 -	CALENDAR_COMPONENT_DEFAULT(component);
 -
 -	return component->priv->activity_handler;
 -}
 -
 -void
 -calendar_component_show_logger (gpointer top)
 -{
 -	CalendarComponent *cc = calendar_component_peek ();
 -	ELogger *logger = cc->priv->logger;
 -
 -	eni_show_logger(logger, top, CALENDAR_ERROR_TIME_OUT_KEY, CALENDAR_ERROR_LEVEL_KEY);
 -}
 -
 -BONOBO_TYPE_FUNC_FULL (CalendarComponent, GNOME_Evolution_Component, PARENT_TYPE, calendar_component)
diff --cc calendar/gui/e-calendar-view.c
index cc51599,91f9ede..975052b
--- a/calendar/gui/e-calendar-view.c
+++ b/calendar/gui/e-calendar-view.c
@@@ -1775,34 -1808,97 +1775,34 @@@ static EPopupItem ecv_main_items [] = 
  };
  
  static EPopupItem ecv_child_items [] = {
- 	{ E_POPUP_ITEM, "00.open", N_("_Open"), on_edit_appointment, NULL, GTK_STOCK_OPEN, 0, E_CAL_POPUP_SELECT_NOTEDITING },
- 	{ E_POPUP_ITEM, "10.saveas", N_("_Save As..."), on_save_as, NULL, GTK_STOCK_SAVE_AS, 0, E_CAL_POPUP_SELECT_NOTEDITING },
- 	{ E_POPUP_ITEM, "20.print", N_("Pri_nt..."), on_print_event, NULL, GTK_STOCK_PRINT, 0, E_CAL_POPUP_SELECT_NOTEDITING },
+ 	{ E_POPUP_ITEM, (gchar *) "00.open", (gchar *) N_("_Open"), on_edit_appointment, NULL, (gchar *) GTK_STOCK_OPEN, 0, E_CAL_POPUP_SELECT_NOTEDITING },
+ 	{ E_POPUP_ITEM, (gchar *) "10.saveas", (gchar *) N_("_Save As..."), on_save_as, NULL, (gchar *) GTK_STOCK_SAVE_AS, 0, E_CAL_POPUP_SELECT_NOTEDITING },
+ 	{ E_POPUP_ITEM, (gchar *) "20.print", (gchar *) N_("Pri_nt..."), on_print_event, NULL, (gchar *) GTK_STOCK_PRINT, 0, E_CAL_POPUP_SELECT_NOTEDITING },
  
- 	{ E_POPUP_BAR, "30." },
+ 	{ E_POPUP_BAR, (gchar *) "30." },
  
- 	{ E_POPUP_ITEM, "31.cut", N_("C_ut"), on_cut, NULL, GTK_STOCK_CUT, 0, E_CAL_POPUP_SELECT_NOTEDITING|E_CAL_POPUP_SELECT_EDITABLE|E_CAL_POPUP_SELECT_ORGANIZER },
- 	{ E_POPUP_ITEM, "32.copy", N_("_Copy"), on_copy, NULL, GTK_STOCK_COPY, 0, E_CAL_POPUP_SELECT_NOTEDITING|E_CAL_POPUP_SELECT_ORGANIZER },
- 	{ E_POPUP_ITEM, "33.paste", N_("_Paste"), on_paste, NULL, GTK_STOCK_PASTE, 0, E_CAL_POPUP_SELECT_EDITABLE },
+ 	{ E_POPUP_ITEM, (gchar *) "31.cut", (gchar *) N_("C_ut"), on_cut, NULL, (gchar *) GTK_STOCK_CUT, 0, E_CAL_POPUP_SELECT_NOTEDITING|E_CAL_POPUP_SELECT_EDITABLE|E_CAL_POPUP_SELECT_ORGANIZER },
+ 	{ E_POPUP_ITEM, (gchar *) "32.copy", (gchar *) N_("_Copy"), on_copy, NULL, (gchar *) GTK_STOCK_COPY, 0, E_CAL_POPUP_SELECT_NOTEDITING|E_CAL_POPUP_SELECT_ORGANIZER },
+ 	{ E_POPUP_ITEM, (gchar *) "33.paste", (gchar *) N_("_Paste"), on_paste, NULL, (gchar *) GTK_STOCK_PASTE, 0, E_CAL_POPUP_SELECT_EDITABLE },
  
- 	{ E_POPUP_BAR, "40." },
+ 	{ E_POPUP_BAR, (gchar *) "40." },
  
- 	{ E_POPUP_ITEM, "43.copyto", N_("Cop_y to Calendar..."), on_copy_to, NULL, NULL, 0, E_CAL_POPUP_SELECT_NOTEDITING },
- 	{ E_POPUP_ITEM, "44.moveto", N_("Mo_ve to Calendar..."), on_move_to, NULL, NULL, 0, E_CAL_POPUP_SELECT_NOTEDITING | E_CAL_POPUP_SELECT_EDITABLE },
- 	{ E_POPUP_ITEM, "45.delegate", N_("_Delegate Meeting..."), on_delegate, NULL, NULL, 0, E_CAL_POPUP_SELECT_NOTEDITING | E_CAL_POPUP_SELECT_EDITABLE | E_CAL_POPUP_SELECT_DELEGATABLE | E_CAL_POPUP_SELECT_MEETING},
- 	{ E_POPUP_ITEM, "46.schedule", N_("_Schedule Meeting..."), on_meeting, NULL, NULL, 0, E_CAL_POPUP_SELECT_NOTEDITING | E_CAL_POPUP_SELECT_EDITABLE | E_CAL_POPUP_SELECT_NOTMEETING },
- 	{ E_POPUP_ITEM, "47.forward", N_("_Forward as iCalendar..."), on_forward, NULL, "mail-forward", 0, E_CAL_POPUP_SELECT_NOTEDITING },
- 	{ E_POPUP_ITEM, "48.reply", N_("_Reply"), on_reply, NULL, "mail-reply-sender", E_CAL_POPUP_SELECT_MEETING | E_CAL_POPUP_SELECT_NOSAVESCHEDULES, E_CAL_POPUP_SELECT_NOTEDITING },
- 	{ E_POPUP_ITEM, "49.reply-all", N_("Reply to _All"), on_reply_all, NULL, "mail-reply-all", E_CAL_POPUP_SELECT_MEETING | E_CAL_POPUP_SELECT_NOSAVESCHEDULES, E_CAL_POPUP_SELECT_NOTEDITING },
+ 	{ E_POPUP_ITEM, (gchar *) "43.copyto", (gchar *) N_("Cop_y to Calendar..."), on_copy_to, NULL, NULL, 0, E_CAL_POPUP_SELECT_NOTEDITING },
+ 	{ E_POPUP_ITEM, (gchar *) "44.moveto", (gchar *) N_("Mo_ve to Calendar..."), on_move_to, NULL, NULL, 0, E_CAL_POPUP_SELECT_NOTEDITING | E_CAL_POPUP_SELECT_EDITABLE },
+ 	{ E_POPUP_ITEM, (gchar *) "45.delegate", (gchar *) N_("_Delegate Meeting..."), on_delegate, NULL, NULL, 0, E_CAL_POPUP_SELECT_NOTEDITING | E_CAL_POPUP_SELECT_EDITABLE | E_CAL_POPUP_SELECT_DELEGATABLE | E_CAL_POPUP_SELECT_MEETING},
+ 	{ E_POPUP_ITEM, (gchar *) "46.schedule", (gchar *) N_("_Schedule Meeting..."), on_meeting, NULL, NULL, 0, E_CAL_POPUP_SELECT_NOTEDITING | E_CAL_POPUP_SELECT_EDITABLE | E_CAL_POPUP_SELECT_NOTMEETING },
+ 	{ E_POPUP_ITEM, (gchar *) "47.forward", (gchar *) N_("_Forward as iCalendar..."), on_forward, NULL, (gchar *) "mail-forward", 0, E_CAL_POPUP_SELECT_NOTEDITING },
+ 	{ E_POPUP_ITEM, (gchar *) "48.reply", (gchar *) N_("_Reply"), on_reply, NULL, (gchar *) "mail-reply-sender", E_CAL_POPUP_SELECT_MEETING | E_CAL_POPUP_SELECT_NOSAVESCHEDULES, E_CAL_POPUP_SELECT_NOTEDITING },
+ 	{ E_POPUP_ITEM, (gchar *) "49.reply-all", (gchar *) N_("Reply to _All"), on_reply_all, NULL, (gchar *) "mail-reply-all", E_CAL_POPUP_SELECT_MEETING | E_CAL_POPUP_SELECT_NOSAVESCHEDULES, E_CAL_POPUP_SELECT_NOTEDITING },
  
- 	{ E_POPUP_BAR, "50." },
+ 	{ E_POPUP_BAR, (gchar *) "50." },
  
- 	{ E_POPUP_ITEM, "51.delete", N_("_Delete"), on_delete_appointment, NULL, GTK_STOCK_DELETE, E_CAL_POPUP_SELECT_NONRECURRING, E_CAL_POPUP_SELECT_NOTEDITING | E_CAL_POPUP_SELECT_EDITABLE },
- 	{ E_POPUP_ITEM, "52.move", N_("Make this Occurrence _Movable"), on_unrecur_appointment, NULL, NULL, E_CAL_POPUP_SELECT_RECURRING | E_CAL_POPUP_SELECT_INSTANCE, E_CAL_POPUP_SELECT_NOTEDITING | E_CAL_POPUP_SELECT_EDITABLE },
- 	{ E_POPUP_ITEM, "53.delete", N_("Delete this _Occurrence"), on_delete_occurrence, NULL, GTK_STOCK_DELETE, E_CAL_POPUP_SELECT_RECURRING, E_CAL_POPUP_SELECT_NOTEDITING | E_CAL_POPUP_SELECT_EDITABLE },
- 	{ E_POPUP_ITEM, "54.delete", N_("Delete _All Occurrences"), on_delete_appointment, NULL, GTK_STOCK_DELETE, E_CAL_POPUP_SELECT_RECURRING, E_CAL_POPUP_SELECT_NOTEDITING | E_CAL_POPUP_SELECT_EDITABLE },
+ 	{ E_POPUP_ITEM, (gchar *) "51.delete", (gchar *) N_("_Delete"), on_delete_appointment, NULL, (gchar *) GTK_STOCK_DELETE, E_CAL_POPUP_SELECT_NONRECURRING, E_CAL_POPUP_SELECT_NOTEDITING | E_CAL_POPUP_SELECT_EDITABLE },
+ 	{ E_POPUP_ITEM, (gchar *) "52.move", (gchar *) N_("Make this Occurrence _Movable"), on_unrecur_appointment, NULL, NULL, E_CAL_POPUP_SELECT_RECURRING | E_CAL_POPUP_SELECT_INSTANCE, E_CAL_POPUP_SELECT_NOTEDITING | E_CAL_POPUP_SELECT_EDITABLE },
+ 	{ E_POPUP_ITEM, (gchar *) "53.delete", (gchar *) N_("Delete this _Occurrence"), on_delete_occurrence, NULL, (gchar *) GTK_STOCK_DELETE, E_CAL_POPUP_SELECT_RECURRING, E_CAL_POPUP_SELECT_NOTEDITING | E_CAL_POPUP_SELECT_EDITABLE },
+ 	{ E_POPUP_ITEM, (gchar *) "54.delete", (gchar *) N_("Delete _All Occurrences"), on_delete_appointment, NULL, (gchar *) GTK_STOCK_DELETE, E_CAL_POPUP_SELECT_RECURRING, E_CAL_POPUP_SELECT_NOTEDITING | E_CAL_POPUP_SELECT_EDITABLE },
  };
  
 -static void
 -ecv_popup_free (EPopup *ep, GSList *list, void *data)
 -{
 -	g_slist_free(list);
 -}
 -
 -GtkMenu *
 -e_calendar_view_create_popup_menu (ECalendarView *cal_view)
 -{
 -	ECalPopup *ep;
 -	GSList *menus = NULL;
 -	GList *selected, *l;
 -	int i;
 -	ECalPopupTargetSelect *t;
 -	ECalModel *model;
 -	GPtrArray *events;
 -
 -	g_return_val_if_fail (E_IS_CALENDAR_VIEW (cal_view), NULL);
 -
 -	/* We could do this using a factory on the ECalPopup class,
 -	 * that way we would get called implicitly whenever a popup
 -	 * menu was created rather than everyone having to call us.
 -	 * We could also have a different menu id for each view */
 -
 -	/** @HookPoint-ECalPopup: Calendar Main View Context Menu
 -	 * @Id: org.gnome.evolution.calendar.view.popup
 -	 * @Class: org.gnome.evolution.calendar.popup:1.0
 -	 * @Target: ECalPopupTargetSelect
 -	 *
 -	 * The context menu on the main calendar view.  This menu
 -	 * applies to all view types.
 -	 */
 -	ep = e_cal_popup_new("org.gnome.evolution.calendar.view.popup");
 -
 -	model = e_calendar_view_get_model(cal_view);
 -	events = g_ptr_array_new();
 -	selected = e_calendar_view_get_selected_events(cal_view);
 -	for (l=selected;l;l=g_list_next(l)) {
 -		ECalendarViewEvent *event = l->data;
 -
 -		if (event)
 -			g_ptr_array_add(events, e_cal_model_copy_component_data(event->comp_data));
 -	}
 -	g_list_free(selected);
 -
 -	t = e_cal_popup_target_new_select(ep, model, events);
 -	t->target.widget = (GtkWidget *)cal_view;
 -
 -	if (t->events->len == 0) {
 -		for (i=0;i<sizeof(ecv_main_items)/sizeof(ecv_main_items[0]);i++)
 -			menus = g_slist_prepend(menus, &ecv_main_items[i]);
 -
 -		gnome_calendar_view_popup_factory(cal_view->priv->calendar, (EPopup *)ep, "60.view");
 -	} else {
 -		for (i=0;i<sizeof(ecv_child_items)/sizeof(ecv_child_items[0]);i++)
 -			menus = g_slist_prepend(menus, &ecv_child_items[i]);
 -	}
 -
 -	e_popup_add_items((EPopup *)ep, menus, NULL, ecv_popup_free, cal_view);
 -
 -	return e_popup_create_menu_once((EPopup *)ep, (EPopupTarget *)t, 0);
 -}
 -
  void
  e_calendar_view_open_event (ECalendarView *cal_view)
  {
@@@ -2564,11 -2657,32 +2564,11 @@@ draw_curved_rectangle (cairo_t *cr, dou
  	cairo_close_path (cr);
  }
  
- static void 
+ static void
  error_response(GtkWidget *widget, gint response, void *data)
  {
- 	if (response == GTK_RESPONSE_DELETE_EVENT) 
 -	gtk_widget_destroy (widget);
 -}
 -
 -void
 -e_calendar_utils_show_error_silent (GtkWidget *widget)
 -{
 -	EActivityHandler *handler = calendar_component_peek_activity_handler (calendar_component_peek ());
 -
 -	if(!g_object_get_data ((GObject *) widget, "response-handled")) {
 -		g_signal_connect(widget, "response", G_CALLBACK(error_response), NULL);
 -	}
 -
 -	e_activity_handler_make_error (handler, "calendar", E_LOG_ERROR, widget);
 -}
 -
 -void
 -e_calendar_utils_show_info_silent (GtkWidget *widget)
 -{
 -	EActivityHandler *handler = calendar_component_peek_activity_handler (calendar_component_peek ());
 -
 -	if(!g_object_get_data ((GObject *) widget, "response-handled")) {
 -		g_signal_connect(widget, "response", G_CALLBACK(error_response), NULL);
 -	}
 -
 -	e_activity_handler_make_error (handler, "calendar", E_LOG_WARNINGS, widget);
++	if (response == GTK_RESPONSE_DELETE_EVENT)
 +		gtk_widget_destroy(widget);
- 	else if (response == GTK_RESPONSE_OK) 
++	else if (response == GTK_RESPONSE_OK)
 +		gtk_widget_destroy(widget);
  }
diff --cc calendar/gui/e-memo-list-selector.c
index 9d34089,0000000..e31a9d4
mode 100644,000000..100644
--- a/calendar/gui/e-memo-list-selector.c
+++ b/calendar/gui/e-memo-list-selector.c
@@@ -1,287 -1,0 +1,287 @@@
 +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
 +/* e-memo-list-selector.c
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of version 2 of the GNU General Public
 + * License as published by the Free Software Foundation.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 + * General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public
 + * License along with this program; if not, write to the
 + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 + * Boston, MA 02110-1301, USA.
 + */
 +
 +#include "e-memo-list-selector.h"
 +
 +#include <string.h>
 +#include <libecal/e-cal.h>
 +#include "calendar/common/authentication.h"
 +#include "calendar/gui/comp-util.h"
 +
 +#define E_MEMO_LIST_SELECTOR_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_MEMO_LIST_SELECTOR, EMemoListSelectorPrivate))
 +
 +struct _EMemoListSelectorPrivate {
 +	gint dummy_value;
 +};
 +
 +enum {
 +	DND_TARGET_TYPE_CALENDAR_LIST
 +};
 +
 +static GtkTargetEntry drag_types[] = {
- 	{ "text/calendar", 0, DND_TARGET_TYPE_CALENDAR_LIST },
- 	{ "text/x-calendar", 0, DND_TARGET_TYPE_CALENDAR_LIST }
++	{ (gchar *) "text/calendar", 0, DND_TARGET_TYPE_CALENDAR_LIST },
++	{ (gchar *) "text/x-calendar", 0, DND_TARGET_TYPE_CALENDAR_LIST }
 +};
 +
 +static gpointer parent_class;
 +
 +static gboolean
 +memo_list_selector_update_single_object (ECal *client,
 +                                         icalcomponent *icalcomp)
 +{
 +	gchar *uid;
 +	icalcomponent *tmp_icalcomp;
 +
 +	uid = (gchar *) icalcomponent_get_uid (icalcomp);
 +
 +	if (e_cal_get_object (client, uid, NULL, &tmp_icalcomp, NULL))
 +		return e_cal_modify_object (
 +			client, icalcomp, CALOBJ_MOD_ALL, NULL);
 +
 +	return e_cal_create_object (client, icalcomp, &uid, NULL);
 +}
 +
 +static gboolean
 +memo_list_selector_update_objects (ECal *client,
 +                                   icalcomponent *icalcomp)
 +{
 +	icalcomponent *subcomp;
 +	icalcomponent_kind kind;
 +
 +	kind = icalcomponent_isa (icalcomp);
 +	if (kind == ICAL_VJOURNAL_COMPONENT)
 +		return memo_list_selector_update_single_object (
 +			client, icalcomp);
 +	else if (kind != ICAL_VCALENDAR_COMPONENT)
 +		return FALSE;
 +
 +	subcomp = icalcomponent_get_first_component (
 +		icalcomp, ICAL_ANY_COMPONENT);
 +	while (subcomp != NULL) {
 +		gboolean success;
 +
 +		kind = icalcomponent_isa (subcomp);
 +		if (kind == ICAL_VTIMEZONE_COMPONENT) {
 +			icaltimezone *zone;
 +
 +			zone = icaltimezone_new ();
 +			icaltimezone_set_component (zone, subcomp);
 +
 +			success = e_cal_add_timezone (client, zone, NULL);
 +			icaltimezone_free (zone, 1);
 +			if (!success)
 +				return FALSE;
 +		} else if (kind == ICAL_VJOURNAL_COMPONENT) {
 +			success = memo_list_selector_update_single_object (
 +				client, subcomp);
 +			if (!success)
 +				return FALSE;
 +		}
 +
 +		subcomp = icalcomponent_get_next_component (
 +			icalcomp, ICAL_ANY_COMPONENT);
 +	}
 +
 +	return TRUE;
 +}
 +
 +static gboolean
 +memo_list_selector_process_data (ESourceSelector *selector,
 +                                 ECal *client,
 +                                 const gchar *source_uid,
 +                                 icalcomponent *icalcomp,
 +                                 GdkDragAction action)
 +{
 +	ESourceList *source_list;
 +	ESource *source;
 +	icalcomponent *tmp_icalcomp = NULL;
 +	const gchar *uid;
 +	gchar *old_uid = NULL;
 +	gboolean success = FALSE;
 +	gboolean read_only = TRUE;
 +	GError *error = NULL;
 +
 +	/* FIXME Deal with GDK_ACTION_ASK. */
 +	if (action == GDK_ACTION_COPY) {
 +		old_uid = g_strdup (icalcomponent_get_uid (icalcomp));
 +		uid = e_cal_component_gen_uid ();
 +		icalcomponent_set_uid (icalcomp, uid);
 +	}
 +
 +	uid = icalcomponent_get_uid (icalcomp);
 +	if (old_uid == NULL)
 +		old_uid = g_strdup (uid);
 +
 +	if (e_cal_get_object (client, uid, NULL, &tmp_icalcomp, &error)) {
 +		icalcomponent_free (tmp_icalcomp);
 +		success = TRUE;
 +		goto exit;
 +	}
 +
 +	if (error != NULL && error->code != E_CALENDAR_STATUS_OBJECT_NOT_FOUND) {
 +		g_message (
 +			"Failed to search the object in destination "
 +			"task list: %s", error->message);
 +		g_error_free (error);
 +		goto exit;
 +	}
 +
 +	success = memo_list_selector_update_objects (client, icalcomp);
 +
 +	if (!success || action != GDK_ACTION_MOVE)
 +		goto exit;
 +
 +	source_list = e_source_selector_get_source_list (selector);
 +	source = e_source_list_peek_source_by_uid (source_list, source_uid);
 +
 +	if (!E_IS_SOURCE (source) || e_source_get_readonly (source))
 +		goto exit;
 +
 +	client = auth_new_cal_from_source (source, E_CAL_SOURCE_TYPE_JOURNAL);
 +	if (client == NULL) {
 +		g_message ("Cannot create source client to remove old memo");
 +		goto exit;
 +	}
 +
 +	e_cal_is_read_only (client, &read_only, NULL);
 +	if (!read_only && e_cal_open (client, TRUE, NULL))
 +		e_cal_remove_object (client, old_uid, NULL);
 +	else if (!read_only)
 +		g_message ("Cannot open source client to remove old memo");
 +
 +	g_object_unref (client);
 +
 +exit:
 +	g_free (old_uid);
 +
 +	return success;
 +}
 +
 +static gboolean
 +memo_list_selector_data_dropped (ESourceSelector *selector,
 +                                 GtkSelectionData *selection_data,
 +                                 ESource *destination,
 +                                 GdkDragAction action,
 +                                 guint info)
 +{
 +	ECal *client;
 +	GSList *list, *iter;
 +	gboolean success = FALSE;
 +
 +	client = auth_new_cal_from_source (
 +		destination, E_CAL_SOURCE_TYPE_JOURNAL);
 +
 +	if (client == NULL || !e_cal_open (client, TRUE, NULL))
 +		goto exit;
 +
 +	list = cal_comp_selection_get_string_list (selection_data);
 +
 +	for (iter = list; iter != NULL; iter = iter->next) {
 +		gchar *source_uid = iter->data;
 +		icalcomponent *icalcomp;
 +		gchar *component_string;
 +
 +		/* Each string is "source_uid\ncomponent_string". */
 +		component_string = strchr (source_uid, '\n');
 +		if (component_string == NULL)
 +			continue;
 +
 +		*component_string++ = '\0';
 +		icalcomp = icalparser_parse_string (component_string);
 +		if (icalcomp == NULL)
 +			continue;
 +
 +		success = memo_list_selector_process_data (
 +			selector, client, source_uid, icalcomp, action);
 +
 +		icalcomponent_free (icalcomp);
 +	}
 +
 +	g_slist_foreach (list, (GFunc) g_free, NULL);
 +	g_slist_free (list);
 +
 +exit:
 +	if (client != NULL)
 +		g_object_unref (client);
 +
 +	return success;
 +}
 +
 +static void
 +memo_list_selector_class_init (EMemoListSelectorClass *class)
 +{
 +	ESourceSelectorClass *source_selector_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (EMemoListSelectorPrivate));
 +
 +	source_selector_class = E_SOURCE_SELECTOR_CLASS (class);
 +	source_selector_class->data_dropped = memo_list_selector_data_dropped;
 +}
 +
 +static void
 +memo_list_selector_init (EMemoListSelector *selector)
 +{
 +	selector->priv = E_MEMO_LIST_SELECTOR_GET_PRIVATE (selector);
 +
 +	gtk_drag_dest_set (
 +		GTK_WIDGET (selector), GTK_DEST_DEFAULT_ALL,
 +		drag_types, G_N_ELEMENTS (drag_types),
 +		GDK_ACTION_COPY | GDK_ACTION_MOVE);
 +}
 +
 +GType
 +e_memo_list_selector_get_type (void)
 +{
 +	static GType type = 0;
 +
 +	if (G_UNLIKELY (type == 0)) {
 +		const GTypeInfo type_info = {
 +			sizeof (EMemoListSelectorClass),
 +			(GBaseInitFunc) NULL,
 +			(GBaseFinalizeFunc) NULL,
 +			(GClassInitFunc) memo_list_selector_class_init,
 +			(GClassFinalizeFunc) NULL,
 +			NULL,  /* class_data */
 +			sizeof (EMemoListSelector),
 +			0,     /* n_preallocs */
 +			(GInstanceInitFunc) memo_list_selector_init,
 +			NULL   /* value_table */
 +		};
 +
 +		type = g_type_register_static (
 +			E_TYPE_SOURCE_SELECTOR, "EMemoListSelector",
 +			&type_info, 0);
 +	}
 +
 +	return type;
 +}
 +
 +GtkWidget *
 +e_memo_list_selector_new (ESourceList *source_list)
 +{
 +	g_return_val_if_fail (E_IS_SOURCE_LIST (source_list), NULL);
 +
 +	return g_object_new (
 +		E_TYPE_MEMO_LIST_SELECTOR,
 +		"source-list", source_list, NULL);
 +}
diff --cc calendar/gui/e-memo-table.c
index 25e6005,ac43b39..7f14d4f
--- a/calendar/gui/e-memo-table.c
+++ b/calendar/gui/e-memo-table.c
@@@ -88,8 -64,8 +88,8 @@@ enum 
  };
  
  static GtkTargetEntry target_types[] = {
- 	{ "text/calendar", 0, TARGET_TYPE_VCALENDAR },
- 	{ "text/x-calendar", 0, TARGET_TYPE_VCALENDAR }
 -	{ (gchar *) "text/x-calendar", 0, TARGET_TYPE_VCALENDAR },
 -	{ (gchar *) "text/calendar",   0, TARGET_TYPE_VCALENDAR }
++	{ (gchar *) "text/calendar", 0, TARGET_TYPE_VCALENDAR },
++	{ (gchar *) "text/x-calendar", 0, TARGET_TYPE_VCALENDAR }
  };
  
  static guint n_target_types = G_N_ELEMENTS (target_types);
diff --cc calendar/gui/e-task-list-selector.c
index 910ab3f,0000000..fa6bd32
mode 100644,000000..100644
--- a/calendar/gui/e-task-list-selector.c
+++ b/calendar/gui/e-task-list-selector.c
@@@ -1,288 -1,0 +1,288 @@@
 +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
 +/* e-task-list-selector.c
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of version 2 of the GNU General Public
 + * License as published by the Free Software Foundation.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 + * General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public
 + * License along with this program; if not, write to the
 + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 + * Boston, MA 02110-1301, USA.
 + */
 +
 +#include "e-task-list-selector.h"
 +
 +#include <string.h>
 +#include <libecal/e-cal.h>
 +#include "calendar/common/authentication.h"
 +#include "calendar/gui/comp-util.h"
 +
 +#define E_TASK_LIST_SELECTOR_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_TASK_LIST_SELECTOR, ETaskListSelectorPrivate))
 +
 +struct _ETaskListSelectorPrivate {
 +	gint dummy_value;
 +};
 +
 +enum {
 +	DND_TARGET_TYPE_CALENDAR_LIST
 +};
 +
 +static GtkTargetEntry drag_types[] = {
- 	{ "text/calendar", 0, DND_TARGET_TYPE_CALENDAR_LIST },
- 	{ "text/x-calendar", 0, DND_TARGET_TYPE_CALENDAR_LIST }
++	{ (gchar *) "text/calendar", 0, DND_TARGET_TYPE_CALENDAR_LIST },
++	{ (gchar *) "text/x-calendar", 0, DND_TARGET_TYPE_CALENDAR_LIST }
 +};
 +
 +static gpointer parent_class;
 +
 +static gboolean
 +task_list_selector_update_single_object (ECal *client,
 +                                         icalcomponent *icalcomp)
 +{
 +	gchar *uid;
 +	icalcomponent *tmp_icalcomp;
 +
 +	uid = (gchar *) icalcomponent_get_uid (icalcomp);
 +
 +	if (e_cal_get_object (client, uid, NULL, &tmp_icalcomp, NULL))
 +		return e_cal_modify_object (
 +			client, icalcomp, CALOBJ_MOD_ALL, NULL);
 +
 +	return e_cal_create_object (client, icalcomp, &uid, NULL);
 +}
 +
 +static gboolean
 +task_list_selector_update_objects (ECal *client,
 +                                   icalcomponent *icalcomp)
 +{
 +	icalcomponent *subcomp;
 +	icalcomponent_kind kind;
 +
 +	kind = icalcomponent_isa (icalcomp);
 +	if (kind == ICAL_VTODO_COMPONENT || kind == ICAL_VEVENT_COMPONENT)
 +		return task_list_selector_update_single_object (
 +			client, icalcomp);
 +	else if (kind != ICAL_VCALENDAR_COMPONENT)
 +		return FALSE;
 +
 +	subcomp = icalcomponent_get_first_component (
 +		icalcomp, ICAL_ANY_COMPONENT);
 +	while (subcomp != NULL) {
 +		gboolean success;
 +
 +		kind = icalcomponent_isa (subcomp);
 +		if (kind == ICAL_VTIMEZONE_COMPONENT) {
 +			icaltimezone *zone;
 +
 +			zone = icaltimezone_new ();
 +			icaltimezone_set_component (zone, subcomp);
 +
 +			success = e_cal_add_timezone (client, zone, NULL);
 +			icaltimezone_free (zone, 1);
 +			if (!success)
 +				return FALSE;
 +		} else if (kind == ICAL_VTODO_COMPONENT ||
 +			kind == ICAL_VEVENT_COMPONENT) {
 +			success = task_list_selector_update_single_object (
 +				client, subcomp);
 +			if (!success)
 +				return FALSE;
 +		}
 +
 +		subcomp = icalcomponent_get_next_component (
 +			icalcomp, ICAL_ANY_COMPONENT);
 +	}
 +
 +	return TRUE;
 +}
 +
 +static gboolean
 +task_list_selector_process_data (ESourceSelector *selector,
 +                                 ECal *client,
 +                                 const gchar *source_uid,
 +                                 icalcomponent *icalcomp,
 +                                 GdkDragAction action)
 +{
 +	ESourceList *source_list;
 +	ESource *source;
 +	icalcomponent *tmp_icalcomp = NULL;
 +	const gchar *uid;
 +	gchar *old_uid = NULL;
 +	gboolean success = FALSE;
 +	gboolean read_only = TRUE;
 +	GError *error = NULL;
 +
 +	/* FIXME Deal with GDK_ACTION_ASK. */
 +	if (action == GDK_ACTION_COPY) {
 +		old_uid = g_strdup (icalcomponent_get_uid (icalcomp));
 +		uid = e_cal_component_gen_uid ();
 +		icalcomponent_set_uid (icalcomp, uid);
 +	}
 +
 +	uid = icalcomponent_get_uid (icalcomp);
 +	if (old_uid == NULL)
 +		old_uid = g_strdup (uid);
 +
 +	if (e_cal_get_object (client, uid, NULL, &tmp_icalcomp, &error)) {
 +		icalcomponent_free (tmp_icalcomp);
 +		success = TRUE;
 +		goto exit;
 +	}
 +
 +	if (error != NULL && error->code != E_CALENDAR_STATUS_OBJECT_NOT_FOUND) {
 +		g_message (
 +			"Failed to search the object in destination "
 +			"task list: %s", error->message);
 +		g_error_free (error);
 +		goto exit;
 +	}
 +
 +	success = task_list_selector_update_objects (client, icalcomp);
 +
 +	if (!success || action != GDK_ACTION_MOVE)
 +		goto exit;
 +
 +	source_list = e_source_selector_get_source_list (selector);
 +	source = e_source_list_peek_source_by_uid (source_list, source_uid);
 +
 +	if (!E_IS_SOURCE (source) || e_source_get_readonly (source))
 +		goto exit;
 +
 +	client = auth_new_cal_from_source (source, E_CAL_SOURCE_TYPE_TODO);
 +	if (client == NULL) {
 +		g_message ("Cannot create source client to remove old task");
 +		goto exit;
 +	}
 +
 +	e_cal_is_read_only (client, &read_only, NULL);
 +	if (!read_only && e_cal_open (client, TRUE, NULL))
 +		e_cal_remove_object (client, old_uid, NULL);
 +	else if (!read_only)
 +		g_message ("Cannot open source client to remove old task");
 +
 +	g_object_unref (client);
 +
 +exit:
 +	g_free (old_uid);
 +
 +	return success;
 +}
 +
 +static gboolean
 +task_list_selector_data_dropped (ESourceSelector *selector,
 +                                 GtkSelectionData *selection_data,
 +                                 ESource *destination,
 +                                 GdkDragAction action,
 +                                 guint info)
 +{
 +	ECal *client;
 +	GSList *list, *iter;
 +	gboolean success = FALSE;
 +
 +	client = auth_new_cal_from_source (
 +		destination, E_CAL_SOURCE_TYPE_TODO);
 +
 +	if (client == NULL || !e_cal_open (client, TRUE, NULL))
 +		goto exit;
 +
 +	list = cal_comp_selection_get_string_list (selection_data);
 +
 +	for (iter = list; iter != NULL; iter = iter->next) {
 +		gchar *source_uid = iter->data;
 +		icalcomponent *icalcomp;
 +		gchar *component_string;
 +
 +		/* Each string is "source_uid\ncomponent_string". */
 +		component_string = strchr (source_uid, '\n');
 +		if (component_string == NULL)
 +			continue;
 +
 +		*component_string++ = '\0';
 +		icalcomp = icalparser_parse_string (component_string);
 +		if (icalcomp == NULL)
 +			continue;
 +
 +		success = task_list_selector_process_data (
 +			selector, client, source_uid, icalcomp, action);
 +
 +		icalcomponent_free (icalcomp);
 +	}
 +
 +	g_slist_foreach (list, (GFunc) g_free, NULL);
 +	g_slist_free (list);
 +
 +exit:
 +	if (client != NULL)
 +		g_object_unref (client);
 +
 +	return success;
 +}
 +
 +static void
 +task_list_selector_class_init (ETaskListSelectorClass *class)
 +{
 +	ESourceSelectorClass *source_selector_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (ETaskListSelectorPrivate));
 +
 +	source_selector_class = E_SOURCE_SELECTOR_CLASS (class);
 +	source_selector_class->data_dropped = task_list_selector_data_dropped;
 +}
 +
 +static void
 +task_list_selector_init (ETaskListSelector *selector)
 +{
 +	selector->priv = E_TASK_LIST_SELECTOR_GET_PRIVATE (selector);
 +
 +	gtk_drag_dest_set (
 +		GTK_WIDGET (selector), GTK_DEST_DEFAULT_ALL,
 +		drag_types, G_N_ELEMENTS (drag_types),
 +		GDK_ACTION_COPY | GDK_ACTION_MOVE);
 +}
 +
 +GType
 +e_task_list_selector_get_type (void)
 +{
 +	static GType type = 0;
 +
 +	if (G_UNLIKELY (type == 0)) {
 +		const GTypeInfo type_info = {
 +			sizeof (ETaskListSelectorClass),
 +			(GBaseInitFunc) NULL,
 +			(GBaseFinalizeFunc) NULL,
 +			(GClassInitFunc) task_list_selector_class_init,
 +			(GClassFinalizeFunc) NULL,
 +			NULL,  /* class_data */
 +			sizeof (ETaskListSelector),
 +			0,     /* n_preallocs */
 +			(GInstanceInitFunc) task_list_selector_init,
 +			NULL   /* value_table */
 +		};
 +
 +		type = g_type_register_static (
 +			E_TYPE_SOURCE_SELECTOR, "ETaskListSelector",
 +			&type_info, 0);
 +	}
 +
 +	return type;
 +}
 +
 +GtkWidget *
 +e_task_list_selector_new (ESourceList *source_list)
 +{
 +	g_return_val_if_fail (E_IS_SOURCE_LIST (source_list), NULL);
 +
 +	return g_object_new (
 +		E_TYPE_TASK_LIST_SELECTOR,
 +		"source-list", source_list, NULL);
 +}
diff --cc calendar/gui/e-week-view.c
index 90ea61e,57c0547..f2082c5
--- a/calendar/gui/e-week-view.c
+++ b/calendar/gui/e-week-view.c
@@@ -1938,12 -1937,9 +1938,12 @@@ set_text_as_bold (EWeekViewEvent *event
  			break;
  		}
  	}
 +	e_cal_component_free_attendee_list (attendees);
 +	g_free (address);
 +	g_object_unref (comp);
  
  	/* The attendee has not yet accepted the meeting, display the summary as bolded.
- 	   If the attendee is not present, it might have come through a mailing list. 
+ 	   If the attendee is not present, it might have come through a mailing list.
  	   In that case, we never show the meeting as bold even if it is unaccepted. */
  	if (at && (at->status == ICAL_PARTSTAT_NEEDSACTION))
  		gnome_canvas_item_set (span->text_item, "bold", TRUE, NULL);
diff --cc calendar/gui/gnome-cal.c
index 75a3764,18f4a47..7e0043d
--- a/calendar/gui/gnome-cal.c
+++ b/calendar/gui/gnome-cal.c
@@@ -744,9 -889,9 +744,9 @@@ update_query_async (struct _date_query_
  		g_slice_free (struct _date_query_msg, msg);
  		return; /* No time range is set, so don't start a query */
  	}
- 	
+ 
  	/* create queries for each loaded client */
 -	for (l = priv->clients_list[E_CAL_SOURCE_TYPE_EVENT]; l != NULL; l = l->next) {
 +	for (l = priv->clients_list; l != NULL; l = l->next) {
  		GError *error = NULL;
  		gint tries = 0;
  
@@@ -1592,27 -1921,40 +1592,27 @@@ gnome_calendar_destroy (GtkObject *obje
  		e_categories_unregister_change_listener (G_CALLBACK (categories_changed_cb), gcal);
  
  		/* Clean up the clients */
 -		for (i = 0; i < E_CAL_SOURCE_TYPE_LAST; i++) {
 -			for (l = priv->clients_list[i]; l != NULL; l = l->next) {
 -				ESource *source = e_cal_get_source (l->data);
 -
 -				g_signal_handlers_disconnect_matched (l->data, G_SIGNAL_MATCH_DATA,
 -								      0, 0, NULL, NULL, gcal);
 -
 -				if (source)
 -					g_signal_handlers_disconnect_matched (source, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, gcal);
 -			}
 -
 -			g_hash_table_destroy (priv->clients[i]);
 -			g_list_free (priv->clients_list[i]);
 -
 -			priv->clients[i] = NULL;
 -			priv->clients_list[i] = NULL;
 -
 -			if (priv->default_client[i]) {
 -				ESource *source = e_cal_get_source (priv->default_client[i]);
 +		for (l = priv->clients_list; l != NULL; l = l->next) {
 +			g_signal_handlers_disconnect_matched (l->data, G_SIGNAL_MATCH_DATA,
 +							      0, 0, NULL, NULL, gcal);
 +		}
  
 -				g_signal_handlers_disconnect_matched (priv->default_client[i],
 -								      G_SIGNAL_MATCH_DATA,
 -								      0, 0, NULL, NULL, gcal);
 +		g_hash_table_destroy (priv->clients);
 +		g_list_free (priv->clients_list);
  
 -				if (source)
 -					g_signal_handlers_disconnect_matched (source, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, gcal);
 +		priv->clients = NULL;
 +		priv->clients_list = NULL;
  
 -				g_object_unref (priv->default_client[i]);
 -			}
 -			priv->default_client[i] = NULL;
 +		if (priv->default_client) {
 +			g_signal_handlers_disconnect_matched (priv->default_client,
 +							      G_SIGNAL_MATCH_DATA,
 +							      0, 0, NULL, NULL, gcal);
 +			g_object_unref (priv->default_client);
  		}
 +		priv->default_client = NULL;
  
  		for (i = 0; i < GNOME_CAL_LAST_VIEW; i++) {
- 			if (priv->configs[i]) 
+ 			if (priv->configs[i])
  				g_object_unref (priv->configs[i]);
  			priv->configs[i] = NULL;
  		}
@@@ -2114,32 -2655,103 +2114,32 @@@ struct _mclient_msg 
  };
  
  static void
 -gc_popup_free (EPopup *ep, GSList *list, void *data)
 +add_mclient_async (struct _mclient_msg *msg)
  {
 -	while (list) {
 -		GSList *n = list->next;
 -		EPopupItem *pitem = list->data;
 -
 -		g_free(pitem->path);
 -		g_free(pitem->label);
 -		g_free(pitem->user_data);
 -		g_free(pitem);
 -		g_slist_free_1(list);
 -		list = n;
 -	}
 -}
 +	e_cal_model_add_client (msg->model, msg->client);
  
 -static void
 -gc_popup_free_static (EPopup *ep, GSList *list, void *data)
 -{
 -	while (list) {
 -		GSList *n = list->next;
 -		EPopupItem *pitem = list->data;
 -
 -		g_free(pitem->path);
 -		g_free(pitem);
 -		g_slist_free_1(list);
 -		list = n;
 -	}
 +	g_object_unref (msg->client);
 +	g_object_unref (msg->model);
 +	g_slice_free (struct _mclient_msg, msg);
  }
  
 -void
 -gnome_calendar_view_popup_factory (GnomeCalendar *gcal, EPopup *ep, const char *prefix)
 +static void
 +add_mclient (ECalModel *model, ECal *client)
  {
 -	GnomeCalendarPrivate *priv;
 -	int length;
 -	int i;
 -	gboolean found = FALSE;
 -	char *id;
 -	GSList *menus = NULL;
 -	EPopupItem *pitem;
 -
 -	g_return_if_fail (gcal != NULL);
 -	g_return_if_fail (GNOME_IS_CALENDAR (gcal));
 -	g_return_if_fail (prefix != NULL);
 -
 -	priv = gcal->priv;
 -
 -	g_return_if_fail (priv->view_instance != NULL);
 -
 -	length = gal_view_collection_get_count(priv->view_instance->collection);
 -	id = gal_view_instance_get_current_view_id (priv->view_instance);
 -
 -	for (i = 0; i < length; i++) {
 -		GalViewCollectionItem *item = gal_view_collection_get_view_item(priv->view_instance->collection, i);
 -
 -		pitem = g_malloc0(sizeof(*pitem));
 -		pitem->type = E_POPUP_RADIO;
 -		pitem->path = g_strdup_printf("%s/%02d.item", prefix, i);
 -		pitem->label = g_strdup(item->title);
 -		pitem->activate = gc_set_view;
 -		pitem->user_data = g_strdup(item->id);
 -
 -		if (!found && id && !strcmp (id, item->id)) {
 -			found = TRUE;
 -			pitem->type |= E_POPUP_ACTIVE;
 -		}
 -
 -		menus = g_slist_prepend(menus, pitem);
 -	}
 -
 -	if (menus)
 -		e_popup_add_items(ep, menus, NULL, gc_popup_free, gcal);
 +	struct _mclient_msg *msg;
  
 -	menus = NULL;
 -	for (i = found?3:0; i<sizeof(gc_popups)/sizeof(gc_popups[0]);i++) {
 -		pitem = g_malloc0(sizeof(*pitem));
 -		memcpy(pitem, &gc_popups[i], sizeof(*pitem));
 -		pitem->path = g_strdup_printf("%s/%02d.item", prefix, i+length);
 -		menus = g_slist_prepend(menus, pitem);
 -	}
 +	msg = g_slice_new0 (struct _mclient_msg);
 +	msg->header.func = (MessageFunc) add_mclient_async;
 +	msg->model = g_object_ref (model);
 +	msg->client = g_object_ref (client);
  
 -	e_popup_add_items(ep, menus, NULL, gc_popup_free_static, gcal);
 +	message_push ((Message *) msg);
  }
  
- static void 
+ static void
 -gnome_calendar_set_pane_positions	(GnomeCalendar	*gcal)
 +non_intrusive_error_remove(GtkWidget *w, void *data)
  {
 -	GnomeCalendarPrivate *priv;
 -
 -	priv = gcal->priv;
 -
 -	if (priv->current_view_type == GNOME_CAL_MONTH_VIEW && !priv->range_selected) {
 -		gtk_paned_set_position (GTK_PANED (priv->hpane), priv->hpane_pos_month_view);
 -		gtk_paned_set_position (GTK_PANED (priv->vpane), priv->vpane_pos_month_view);
 -	} else {
 -		gtk_paned_set_position (GTK_PANED (priv->hpane), priv->hpane_pos);
 -		gtk_paned_set_position (GTK_PANED (priv->vpane), priv->vpane_pos);
 -	}
 +	g_hash_table_remove(non_intrusive_error_table, data);
  }
  
  struct _mclient_msg {
@@@ -2303,15 -2974,15 +2303,15 @@@ default_client_cal_opened_cb (ECal *eca
  		g_signal_handlers_disconnect_matched (ecal, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, gcal);
  
  		/* FIXME should we do this to prevent multiple error dialogs? */
 -		priv->clients_list[source_type] = g_list_remove (priv->clients_list[source_type], ecal);
 -		g_hash_table_remove (priv->clients[source_type], e_source_peek_uid (source));
 +		priv->clients_list = g_list_remove (priv->clients_list, ecal);
 +		g_hash_table_remove (priv->clients, e_source_peek_uid (source));
  
  		/* FIXME Is there a better way to handle this? */
- 		if (priv->default_client) 
 -		if (priv->default_client[source_type])
 -			g_object_unref (priv->default_client[source_type]);
 -		priv->default_client[source_type] = NULL;
++		if (priv->default_client)
 +			g_object_unref (priv->default_client);
 +		priv->default_client = NULL;
  
 -		g_signal_emit (gcal, gnome_calendar_signals[SOURCE_REMOVED], 0, source_type, source);
 +		g_signal_emit (gcal, gnome_calendar_signals[SOURCE_REMOVED], 0, source);
  		g_object_unref (source);
  
  		g_warning ("Unable to load the calendar %s \n", e_cal_get_error_message (status));
diff --cc calendar/gui/itip-utils.c
index c6aa021,ae822c9..bf270de
--- a/calendar/gui/itip-utils.c
+++ b/calendar/gui/itip-utils.c
@@@ -37,9 -37,10 +37,9 @@@
  #include <time.h>
  
  #include <composer/e-msg-composer.h>
 -#include <mail/em-composer-utils.h>
  #include <camel/camel-mime-filter-tohtml.h>
  
- static gchar *itip_methods[] = {
+ static const gchar *itip_methods[] = {
  	"PUBLISH",
  	"REQUEST",
  	"REPLY",
diff --cc calendar/gui/tasks-control.c
index 62a283f,7ee468e..1be68ac
--- a/calendar/gui/tasks-control.c
+++ b/calendar/gui/tasks-control.c
@@@ -70,8 -91,70 +70,8 @@@ static void tasks_control_forward_cm
                                                  gpointer               data,
                                                  const char             *path);
  
 -static void tasks_control_view_preview	       (BonoboUIComponent *uic,
 -						const char *path,
 -						Bonobo_UIComponent_EventType type,
 -						const char *state,
 -						void *data);
 -
 -struct focus_changed_data {
 -	BonoboControl *control;
 -	ETasks *tasks;
 -};
 -
 -static gboolean tasks_control_focus_changed (GtkWidget *widget, GdkEventFocus *event, struct focus_changed_data *fc_data);
 -
 -BonoboControl *
 -tasks_control_new (void)
 -{
 -	BonoboControl *control;
 -	GtkWidget *tasks, *preview;
 -	struct focus_changed_data *fc_data;
 -
 -	tasks = e_tasks_new ();
 -	if (!tasks)
 -		return NULL;
 -	gtk_widget_show (tasks);
 -
 -	control = bonobo_control_new (tasks);
 -	if (!control) {
 -		gtk_widget_destroy (tasks);
 -		g_message ("control_factory_fn(): could not create the control!");
 -		return NULL;
 -	}
 -
 -	g_signal_connect (control, "activate", G_CALLBACK (tasks_control_activate_cb), tasks);
 -
 -	fc_data = g_new0 (struct focus_changed_data, 1);
 -	fc_data->control = control;
 -	fc_data->tasks = E_TASKS (tasks);
 -
 -	preview = e_cal_component_preview_get_html (E_CAL_COMPONENT_PREVIEW (e_tasks_get_preview (fc_data->tasks)));
 -	g_object_set_data_full (G_OBJECT (preview), "tasks-ctrl-fc-data", fc_data, g_free);
 -	g_signal_connect (preview, "focus-in-event", G_CALLBACK (tasks_control_focus_changed), fc_data);
 -	g_signal_connect (preview, "focus-out-event", G_CALLBACK (tasks_control_focus_changed), fc_data);
 -
 -	return control;
 -}
 -
 -
 -static void
 -tasks_control_activate_cb		(BonoboControl		*control,
 -					 gboolean		 activate,
 -					 gpointer		 user_data)
 -{
 -	ETasks *tasks;
 -
 -	tasks = E_TASKS (user_data);
 -
 -	if (activate)
 -		tasks_control_activate (control, tasks);
 -	else
 -		tasks_control_deactivate (control, tasks);
 -}
 -
  struct _tasks_sensitize_item {
- 	char *command;
+ 	const gchar *command;
  	guint32 enable;
  };
  
diff --cc calendar/module/e-cal-shell-backend.c
index 9c38555,0000000..675a3d4
mode 100644,000000..100644
--- a/calendar/module/e-cal-shell-backend.c
+++ b/calendar/module/e-cal-shell-backend.c
@@@ -1,666 -1,0 +1,666 @@@
 +/*
 + * e-cal-shell-backend.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-cal-shell-backend.h"
 +
 +#include <string.h>
 +#include <glib/gi18n.h>
 +#include <libecal/e-cal.h>
 +#include <libedataserver/e-url.h>
 +#include <libedataserver/e-source.h>
 +#include <libedataserver/e-source-group.h>
 +
 +#include "e-util/e-import.h"
 +#include "shell/e-shell.h"
 +#include "shell/e-shell-backend.h"
 +#include "shell/e-shell-window.h"
 +#include "widgets/misc/e-preferences-window.h"
 +
 +#include "calendar/common/authentication.h"
 +#include "calendar/gui/calendar-config.h"
 +#include "calendar/gui/comp-util.h"
 +#include "calendar/gui/e-attachment-handler-calendar.h"
 +#include "calendar/gui/e-cal-config.h"
 +#include "calendar/gui/e-cal-event.h"
 +#include "calendar/gui/dialogs/cal-prefs-dialog.h"
 +#include "calendar/gui/dialogs/calendar-setup.h"
 +#include "calendar/gui/dialogs/event-editor.h"
 +#include "calendar/importers/evolution-calendar-importer.h"
 +
 +#include "e-cal-shell-migrate.h"
 +#include "e-cal-shell-settings.h"
 +#include "e-cal-shell-view.h"
 +
 +#define E_CAL_SHELL_BACKEND_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_CAL_SHELL_BACKEND, ECalShellBackendPrivate))
 +
 +#define CONTACTS_BASE_URI	"contacts://"
 +#define WEATHER_BASE_URI	"weather://"
 +#define WEB_BASE_URI		"webcal://"
 +#define PERSONAL_RELATIVE_URI	"system"
 +
 +struct _ECalShellBackendPrivate {
 +	ESourceList *source_list;
 +};
 +
 +enum {
 +	PROP_0,
 +	PROP_SOURCE_LIST
 +};
 +
 +static gpointer parent_class;
 +static GType cal_shell_backend_type;
 +
 +static void
 +cal_shell_backend_ensure_sources (EShellBackend *shell_backend)
 +{
 +	/* XXX This is basically the same algorithm across all backends.
 +	 *     Maybe we could somehow integrate this into EShellBackend? */
 +
 +	ECalShellBackendPrivate *priv;
 +	ESourceGroup *on_this_computer;
 +	ESourceGroup *on_the_web;
 +	ESourceGroup *contacts;
 +	ESourceGroup *weather;
 +	ESource *birthdays;
 +	ESource *personal;
 +	EShell *shell;
 +	EShellSettings *shell_settings;
 +	GSList *groups, *iter;
 +	const gchar *data_dir;
 +	const gchar *name;
 +	gchar *base_uri;
 +	gchar *filename;
 +	gchar *property;
 +
 +	on_this_computer = NULL;
 +	on_the_web = NULL;
 +	contacts = NULL;
 +	weather = NULL;
 +	birthdays = NULL;
 +	personal = NULL;
 +
 +	priv = E_CAL_SHELL_BACKEND_GET_PRIVATE (shell_backend);
 +
 +	shell = e_shell_backend_get_shell (shell_backend);
 +	shell_settings = e_shell_get_shell_settings (shell);
 +
 +	if (!e_cal_get_sources (&priv->source_list, E_CAL_SOURCE_TYPE_EVENT, NULL)) {
 +		g_warning ("Could not get calendar sources from GConf!");
 +		return;
 +	}
 +
 +	data_dir = e_shell_backend_get_data_dir (shell_backend);
 +	filename = g_build_filename (data_dir, "local", NULL);
 +	base_uri = g_filename_to_uri (filename, NULL, NULL);
 +	g_free (filename);
 +
 +	groups = e_source_list_peek_groups (priv->source_list);
 +	for (iter = groups; iter != NULL; iter = iter->next) {
 +		ESourceGroup *source_group = iter->data;
 +		const gchar *group_base_uri;
 +
 +		group_base_uri = e_source_group_peek_base_uri (source_group);
 +
 +		/* Compare only "file://" part.  if the user's home
 +		 * changes, we do not want to create another group. */
 +		if (on_this_computer == NULL &&
 +			strncmp (base_uri, group_base_uri, 7) == 0)
 +			on_this_computer = source_group;
 +
 +		else if (on_the_web == NULL &&
 +			strcmp (WEB_BASE_URI, group_base_uri) == 0)
 +			on_the_web = source_group;
 +
 +		else if (contacts == NULL &&
 +			strcmp (CONTACTS_BASE_URI, group_base_uri) == 0)
 +			contacts = source_group;
 +
 +		else if (weather == NULL &&
 +			strcmp (WEATHER_BASE_URI, group_base_uri) == 0)
 +			weather = source_group;
 +	}
 +
 +	name = _("On This Computer");
 +
 +	if (on_this_computer != NULL) {
 +		GSList *sources;
 +		const gchar *group_base_uri;
 +
 +		/* Force the group name to the current locale. */
 +		e_source_group_set_name (on_this_computer, name);
 +
 +		sources = e_source_group_peek_sources (on_this_computer);
 +		group_base_uri = e_source_group_peek_base_uri (on_this_computer);
 +
 +		/* Make sure this group includes a "Personal" source. */
 +		for (iter = sources; iter != NULL; iter = iter->next) {
 +			ESource *source = iter->data;
 +			const gchar *relative_uri;
 +
 +			relative_uri = e_source_peek_relative_uri (source);
 +			if (relative_uri == NULL)
 +				continue;
 +
 +			if (strcmp (PERSONAL_RELATIVE_URI, relative_uri) != 0)
 +				continue;
 +
 +			personal = source;
 +			break;
 +		}
 +
 +		/* Make sure we have the correct base URI.  This can
 +		 * change when the user's home directory changes. */
 +		if (strcmp (base_uri, group_base_uri) != 0) {
 +			e_source_group_set_base_uri (
 +				on_this_computer, base_uri);
 +
 +			/* XXX We shouldn't need this sync call here as
 +			 *     set_base_uri() results in synching to GConf,
 +			 *     but that happens in an idle loop and too late
 +			 *     to prevent the user from seeing a "Cannot
 +			 *     Open ... because of invalid URI" error. */
 +			e_source_list_sync (priv->source_list, NULL);
 +		}
 +
 +	} else {
 +		ESourceGroup *source_group;
 +
 +		source_group = e_source_group_new (name, base_uri);
 +		e_source_list_add_group (priv->source_list, source_group, -1);
 +		g_object_unref (source_group);
 +	}
 +
 +	name = _("Personal");
 +
 +	if (personal == NULL) {
 +		ESource *source;
 +		GSList *selected;
 +		gchar *primary;
 +
 +		source = e_source_new (name, PERSONAL_RELATIVE_URI);
 +		e_source_group_add_source (on_this_computer, source, -1);
 +		g_object_unref (source);
 +
 +		primary = e_shell_settings_get_string (
 +			shell_settings, "cal-primary-calendar");
 +
 +		selected = calendar_config_get_calendars_selected ();
 +
 +		if (primary == NULL && selected == NULL) {
 +			const gchar *uid;
 +
 +			uid = e_source_peek_uid (source);
 +			selected = g_slist_prepend (NULL, g_strdup (uid));
 +
 +			e_shell_settings_set_string (
 +				shell_settings, "cal-primary-calendar", uid);
 +			calendar_config_set_calendars_selected (selected);
 +		}
 +
 +		g_slist_foreach (selected, (GFunc) g_free, NULL);
 +		g_slist_free (selected);
 +		g_free (primary);
 +	} else {
 +		/* Force the source name to the current locale. */
 +		e_source_set_name (personal, name);
 +	}
 +
 +	name = _("On The Web");
 +
 +	if (on_the_web == NULL) {
 +		ESourceGroup *source_group;
 +
 +		source_group = e_source_group_new (name, WEB_BASE_URI);
 +		e_source_list_add_group (priv->source_list, source_group, -1);
 +		g_object_unref (source_group);
 +	} else {
 +		/* Force the group name to the current locale. */
 +		e_source_group_set_name (on_the_web, name);
 +	}
 +
 +	name = _("Contacts");
 +
 +	if (contacts != NULL) {
 +		GSList *sources;
 +
 +		/* Force the group name to the current locale. */
 +		e_source_group_set_name (contacts, name);
 +
 +		sources = e_source_group_peek_sources (contacts);
 +
 +		if (sources != NULL) {
 +			GSList *trash;
 +
 +			/* There is only one source under Contacts. */
 +			birthdays = E_SOURCE (sources->data);
 +			sources = g_slist_next (sources);
 +
 +			/* Delete any other sources in this group.
 +			 * Earlier versions allowed you to create
 +			 * additional sources under Contacts. */
 +			trash = g_slist_copy (sources);
 +			while (trash != NULL) {
 +				ESource *source = trash->data;
 +				e_source_group_remove_source (contacts, source);
 +				trash = g_slist_delete_link (trash, trash);
 +			}
- 				
++
 +		}
 +	} else {
 +		ESourceGroup *source_group;
 +
 +		source_group = e_source_group_new (name, CONTACTS_BASE_URI);
 +		e_source_list_add_group (priv->source_list, source_group, -1);
 +		g_object_unref (source_group);
 +
 +		/* This is now a borrowed reference. */
 +		contacts = source_group;
 +	}
 +
 +	/* XXX e_source_group_get_property() returns a newly-allocated
 +	 *     string when it could just as easily return a const string.
 +	 *     Unfortunately, fixing that would break the API. */
 +	property = e_source_group_get_property (contacts, "create_source");
 +	if (property == NULL)
 +		e_source_group_set_property (contacts, "create_source", "no");
 +	g_free (property);
 +
 +	name = _("Birthdays & Anniversaries");
 +
 +	if (birthdays == NULL) {
 +		ESource *source;
 +		const gchar *name;
 +
 +		name = _("Birthdays & Anniversaries");
 +		source = e_source_new (name, "/");
 +		e_source_group_add_source (contacts, source, -1);
 +		g_object_unref (source);
 +
 +		/* This is now a borrowed reference. */
 +		birthdays = source;
 +	} else {
 +		/* Force the source name to the current locale. */
 +		e_source_set_name (birthdays, name);
 +	}
 +
 +	if (e_source_get_property (birthdays, "delete") == NULL)
 +		e_source_set_property (birthdays, "delete", "no");
 +
 +	if (e_source_peek_color_spec (birthdays) == NULL)
 +		e_source_set_color_spec (birthdays, "#DDBECE");
 +
 +	name = _("Weather");
 +
 +	if (weather == NULL) {
 +		ESourceGroup *source_group;
 +
 +		source_group = e_source_group_new (name, WEATHER_BASE_URI);
 +		e_source_list_add_group (priv->source_list, source_group, -1);
 +		g_object_unref (source_group);
 +	} else {
 +		/* Force the group name to the current locale. */
 +		e_source_group_set_name (weather, name);
 +	}
 +
 +	g_free (base_uri);
 +}
 +
 +static void
 +cal_shell_backend_cal_opened_cb (ECal *cal,
 +                                ECalendarStatus status,
 +                                GtkAction *action)
 +{
 +	EShell *shell;
 +	ECalComponent *comp;
 +	CompEditor *editor;
 +	CompEditorFlags flags = 0;
 +	const gchar *action_name;
 +	gboolean all_day;
 +
 +	/* FIXME Pass this in. */
 +	shell = e_shell_get_default ();
 +
 +	/* XXX Handle errors better. */
 +	if (status != E_CALENDAR_STATUS_OK)
 +		return;
 +
 +	action_name = gtk_action_get_name (action);
 +
 +	flags |= COMP_EDITOR_NEW_ITEM;
 +	flags |= COMP_EDITOR_USER_ORG;
 +	if (strcmp (action_name, "event-meeting-new") == 0)
 +		flags |= COMP_EDITOR_MEETING;
 +
 +	all_day = (strcmp (action_name, "event-all-day-new") == 0);
 +
 +	editor = event_editor_new (cal, shell, flags);
 +	comp = cal_comp_event_new_with_current_time (cal, all_day);
 +	comp_editor_edit_comp (editor, comp);
 +
 +	gtk_window_present (GTK_WINDOW (editor));
 +
 +	g_object_unref (comp);
 +	g_object_unref (cal);
 +}
 +
 +static void
 +action_event_new_cb (GtkAction *action,
 +                     EShellWindow *shell_window)
 +{
 +	ECal *cal = NULL;
 +	ECalSourceType source_type;
 +	ESourceList *source_list;
 +	EShellSettings *shell_settings;
 +	EShell *shell;
 +	gchar *uid;
 +
 +	/* This callback is used for both appointments and meetings. */
 +
 +	source_type = E_CAL_SOURCE_TYPE_EVENT;
 +
 +	shell = e_shell_window_get_shell (shell_window);
 +	shell_settings = e_shell_get_shell_settings (shell);
 +
 +	if (!e_cal_get_sources (&source_list, source_type, NULL)) {
 +		g_warning ("Could not get calendar sources from GConf!");
 +		return;
 +	}
 +
 +	uid = e_shell_settings_get_string (
 +		shell_settings, "cal-primary-calendar");
 +
 +	if (uid != NULL) {
 +		ESource *source;
 +
 +		source = e_source_list_peek_source_by_uid (source_list, uid);
 +		if (source != NULL)
 +			cal = auth_new_cal_from_source (source, source_type);
 +		g_free (uid);
 +	}
 +
 +	if (cal == NULL)
 +		cal = auth_new_cal_from_default (source_type);
 +
 +	g_return_if_fail (cal != NULL);
 +
 +	g_signal_connect (
 +		cal, "cal-opened",
 +		G_CALLBACK (cal_shell_backend_cal_opened_cb), action);
 +
 +	e_cal_open_async (cal, FALSE);
 +}
 +
 +static void
 +action_calendar_new_cb (GtkAction *action,
 +                        EShellWindow *shell_window)
 +{
 +	calendar_setup_new_calendar (GTK_WINDOW (shell_window));
 +}
 +
 +static GtkActionEntry item_entries[] = {
 +
 +	{ "event-new",
 +	  "appointment-new",
 +	  NC_("New", "_Appointment"),
 +	  "<Shift><Control>a",
 +	  N_("Create a new appointment"),
 +	  G_CALLBACK (action_event_new_cb) },
 +
 +	{ "event-all-day-new",
 +	  "stock_new-24h-appointment",
 +	  NC_("New", "All Day A_ppointment"),
 +	  NULL,
 +	  N_("Create a new all-day appointment"),
 +	  G_CALLBACK (action_event_new_cb) },
 +
 +	{ "event-meeting-new",
 +	  "stock_new-meeting",
 +	  NC_("New", "M_eeting"),
 +	  "<Shift><Control>e",
 +	  N_("Create a new meeting request"),
 +	  G_CALLBACK (action_event_new_cb) }
 +};
 +
 +static GtkActionEntry source_entries[] = {
 +
 +	{ "calendar-new",
 +	  "x-office-calendar",
 +	  NC_("New", "Cale_ndar"),
 +	  NULL,
 +	  N_("Create a new calendar"),
 +	  G_CALLBACK (action_calendar_new_cb) }
 +};
 +
 +static void
 +cal_shell_backend_init_hooks (void)
 +{
 +	e_plugin_hook_register_type (e_cal_config_hook_get_type ());
 +	e_plugin_hook_register_type (e_cal_event_hook_get_type ());
 +}
 +
 +static void
 +cal_shell_backend_init_importers (void)
 +{
 +	EImportClass *import_class;
 +	EImportImporter *importer;
 +
 +	import_class = g_type_class_ref (e_import_get_type ());
 +
 +	importer = gnome_calendar_importer_peek ();
 +	e_import_class_add_importer (import_class, importer, NULL, NULL);
 +
 +	importer = ical_importer_peek ();
 +	e_import_class_add_importer (import_class, importer, NULL, NULL);
 +
 +	importer = vcal_importer_peek ();
 +	e_import_class_add_importer (import_class, importer, NULL, NULL);
 +}
 +
 +static void
 +cal_shell_backend_init_preferences (EShell *shell)
 +{
 +	GtkWidget *preferences_window;
 +
 +	preferences_window = e_shell_get_preferences_window (shell);
 +
 +	e_preferences_window_add_page (
 +		E_PREFERENCES_WINDOW (preferences_window),
 +		"calendar-and-tasks",
 +		"preferences-calendar-and-tasks",
 +		_("Calendar and Tasks"),
 +		calendar_prefs_dialog_new (shell),
 +		600);
 +}
 +
 +static gboolean
 +cal_shell_backend_handle_uri_cb (EShellBackend *shell_backend,
 +                                 const gchar *uri)
 +{
 +	/* FIXME */
 +	return FALSE;
 +}
 +
 +static void
 +cal_shell_backend_window_created_cb (EShellBackend *shell_backend,
 +                                     GtkWindow *window)
 +{
 +	const gchar *backend_name;
 +
 +	if (!E_IS_SHELL_WINDOW (window))
 +		return;
 +
 +	backend_name = E_SHELL_BACKEND_GET_CLASS (shell_backend)->name;
 +
 +	e_shell_window_register_new_item_actions (
 +		E_SHELL_WINDOW (window), backend_name,
 +		item_entries, G_N_ELEMENTS (item_entries));
 +
 +	e_shell_window_register_new_source_actions (
 +		E_SHELL_WINDOW (window), backend_name,
 +		source_entries, G_N_ELEMENTS (source_entries));
 +}
 +
 +static void
 +cal_shell_backend_get_property (GObject *object,
 +                                guint property_id,
 +                                GValue *value,
 +                                GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_SOURCE_LIST:
 +			g_value_set_object (
 +				value,
 +				e_cal_shell_backend_get_source_list (
 +				E_CAL_SHELL_BACKEND (object)));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +cal_shell_backend_dispose (GObject *object)
 +{
 +	ECalShellBackendPrivate *priv;
 +
 +	priv = E_CAL_SHELL_BACKEND_GET_PRIVATE (object);
 +
 +	if (priv->source_list != NULL) {
 +		g_object_unref (priv->source_list);
 +		priv->source_list = NULL;
 +	}
 +
 +	/* Chain up to parent's dispose() method. */
 +	G_OBJECT_CLASS (parent_class)->dispose (object);
 +}
 +
 +static void
 +cal_shell_backend_constructed (GObject *object)
 +{
 +	EShell *shell;
 +	EShellBackend *shell_backend;
 +
 +	shell_backend = E_SHELL_BACKEND (object);
 +	shell = e_shell_backend_get_shell (shell_backend);
 +
 +	cal_shell_backend_ensure_sources (shell_backend);
 +
 +	g_signal_connect_swapped (
 +		shell, "handle-uri",
 +		G_CALLBACK (cal_shell_backend_handle_uri_cb),
 +		shell_backend);
 +
 +	g_signal_connect_swapped (
 +		shell, "window-created",
 +		G_CALLBACK (cal_shell_backend_window_created_cb),
 +		shell_backend);
 +
 +	cal_shell_backend_init_hooks ();
 +	cal_shell_backend_init_importers ();
 +
 +	/* Initialize settings before initializing preferences,
 +	 * since the preferences bind to the shell settings. */
 +	e_cal_shell_backend_init_settings (shell);
 +	cal_shell_backend_init_preferences (shell);
 +
 +	e_attachment_handler_calendar_get_type ();
 +}
 +
 +static void
 +cal_shell_backend_class_init (ECalShellBackendClass *class)
 +{
 +	GObjectClass *object_class;
 +	EShellBackendClass *shell_backend_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (ECalShellBackendPrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->get_property = cal_shell_backend_get_property;
 +	object_class->dispose = cal_shell_backend_dispose;
 +	object_class->constructed = cal_shell_backend_constructed;
 +
 +	shell_backend_class = E_SHELL_BACKEND_CLASS (class);
 +	shell_backend_class->shell_view_type = E_TYPE_CAL_SHELL_VIEW;
 +	shell_backend_class->name = "calendar";
 +	shell_backend_class->aliases = "";
 +	shell_backend_class->schemes = "calendar";
 +	shell_backend_class->sort_order = 400;
 +	shell_backend_class->start = NULL;
 +	shell_backend_class->is_busy = NULL;
 +	shell_backend_class->shutdown = NULL;
 +	shell_backend_class->migrate = e_cal_shell_backend_migrate;
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_SOURCE_LIST,
 +		g_param_spec_object (
 +			"source-list",
 +			_("Source List"),
 +			_("The registry of calendars"),
 +			E_TYPE_SOURCE_LIST,
 +			G_PARAM_READABLE));
 +}
 +
 +static void
 +cal_shell_backend_init (ECalShellBackend *cal_shell_backend)
 +{
 +	cal_shell_backend->priv =
 +		E_CAL_SHELL_BACKEND_GET_PRIVATE (cal_shell_backend);
 +}
 +
 +GType
 +e_cal_shell_backend_get_type (void)
 +{
 +	return cal_shell_backend_type;
 +}
 +
 +void
 +e_cal_shell_backend_register_type (GTypeModule *type_module)
 +{
 +	const GTypeInfo type_info = {
 +		sizeof (ECalShellBackendClass),
 +		(GBaseInitFunc) NULL,
 +		(GBaseFinalizeFunc) NULL,
 +		(GClassInitFunc) cal_shell_backend_class_init,
 +		(GClassFinalizeFunc) NULL,
 +		NULL,  /* class_data */
 +		sizeof (ECalShellBackend),
 +		0,     /* n_preallocs */
 +		(GInstanceInitFunc) cal_shell_backend_init,
 +		NULL   /* value_table */
 +	};
 +
 +	cal_shell_backend_type = g_type_module_register_type (
 +		type_module, E_TYPE_SHELL_BACKEND,
 +		"ECalShellBackend", &type_info, 0);
 +}
 +
 +ESourceList *
 +e_cal_shell_backend_get_source_list (ECalShellBackend *cal_shell_backend)
 +{
 +	g_return_val_if_fail (
 +		E_IS_CAL_SHELL_BACKEND (cal_shell_backend), NULL);
 +
 +	return cal_shell_backend->priv->source_list;
 +}
diff --cc calendar/module/e-cal-shell-backend.h
index 434c87b,0000000..497e200
mode 100644,000000..100644
--- a/calendar/module/e-cal-shell-backend.h
+++ b/calendar/module/e-cal-shell-backend.h
@@@ -1,70 -1,0 +1,70 @@@
 +/*
 + * e-cal-shell-backend.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_CAL_SHELL_BACKEND_H
 +#define E_CAL_SHELL_BACKEND_H
 +
 +#include <shell/e-shell-backend.h>
 +#include <libedataserver/e-source-list.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_CAL_SHELL_BACKEND \
 +	(e_cal_shell_backend_get_type ())
 +#define E_CAL_SHELL_BACKEND(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_CAL_SHELL_BACKEND, ECalShellBackend))
 +#define E_CAL_SHELL_BACKEND_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_CAL_SHELL_BACKEND, ECalShellBackendClass))
 +#define E_IS_CAL_SHELL_BACKEND(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_CAL_SHELL_BACKEND))
 +#define E_IS_CAL_SHELL_BACKEND_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), E_TYPE_CAL_SHELL_BACKEND))
 +#define E_CAL_SHELL_BACKEND_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_CAL_SHELL_BACKEND, ECalShellBackendClass))
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _ECalShellBackend ECalShellBackend;
 +typedef struct _ECalShellBackendClass ECalShellBackendClass;
 +typedef struct _ECalShellBackendPrivate ECalShellBackendPrivate;
 +
 +struct _ECalShellBackend {
 +	EShellBackend parent;
 +	ECalShellBackendPrivate *priv;
 +};
 +
 +struct _ECalShellBackendClass {
 +	EShellBackendClass parent_class;
 +};
 +
 +GType		e_cal_shell_backend_get_type	(void);
 +void		e_cal_shell_backend_register_type
 +					(GTypeModule *type_module);
 +ESourceList *	e_cal_shell_backend_get_source_list
 +					(ECalShellBackend *cal_shell_backend);
 +
 +G_END_DECLS
 +
 +#endif /* E_CAL_SHELL_BACKEND_H */
diff --cc calendar/module/e-cal-shell-content.c
index 7f750f5,0000000..6afb40d
mode 100644,000000..100644
--- a/calendar/module/e-cal-shell-content.c
+++ b/calendar/module/e-cal-shell-content.c
@@@ -1,827 -1,0 +1,827 @@@
 +/*
 + * e-cal-shell-content.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-cal-shell-content.h"
 +
 +#include <string.h>
 +#include <glib/gi18n.h>
 +
 +#include "e-util/gconf-bridge.h"
 +
 +#include "calendar/gui/calendar-config.h"
 +#include "calendar/gui/e-cal-list-view-config.h"
 +#include "calendar/gui/e-cal-model-calendar.h"
 +#include "calendar/gui/e-calendar-table.h"
 +#include "calendar/gui/e-calendar-table-config.h"
 +#include "calendar/gui/e-day-view-config.h"
 +#include "calendar/gui/e-memo-table-config.h"
 +#include "calendar/gui/e-week-view-config.h"
 +
 +#include "widgets/menus/gal-view-etable.h"
 +
 +#define E_CAL_SHELL_CONTENT_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_CAL_SHELL_CONTENT, ECalShellContentPrivate))
 +
 +struct _ECalShellContentPrivate {
 +	GtkWidget *hpaned;
 +	GtkWidget *notebook;
 +	GtkWidget *vpaned;
 +
 +	GtkWidget *day_view;
 +	GtkWidget *work_week_view;
 +	GtkWidget *week_view;
 +	GtkWidget *month_view;
 +	GtkWidget *list_view;
 +	GtkWidget *task_table;
 +	GtkWidget *memo_table;
 +
 +	EDayViewConfig *day_view_config;
 +	EDayViewConfig *work_week_view_config;
 +	EWeekViewConfig *week_view_config;
 +	EWeekViewConfig *month_view_config;
 +	ECalListViewConfig *list_view_config;
 +	ECalendarTableConfig *task_table_config;
 +	EMemoTableConfig *memo_table_config;
 +
 +	GalViewInstance *view_instance;
 +
 +	guint paned_binding_id;
 +};
 +
 +enum {
 +	PROP_0
 +};
 +
 +/* Used to indicate who has the focus within the calendar view. */
 +typedef enum {
 +	FOCUS_CALENDAR,
 +	FOCUS_MEMO_TABLE,
 +	FOCUS_TASK_TABLE,
 +	FOCUS_OTHER
 +} FocusLocation;
 +
 +static gpointer parent_class;
 +static GType cal_shell_content_type;
 +
 +static void
 +cal_shell_content_display_view_cb (ECalShellContent *cal_shell_content,
 +                                   GalView *gal_view)
 +{
 +	/* FIXME */
 +}
 +
 +static void
 +cal_shell_content_notify_view_id_cb (ECalShellContent *cal_shell_content)
 +{
 +	EShellContent *shell_content;
 +	EShellView *shell_view;
 +	GConfBridge *bridge;
 +	GtkWidget *paned;
 +	guint binding_id;
 +	const gchar *key;
 +	const gchar *view_id;
 +
 +	bridge = gconf_bridge_get ();
 +	paned = cal_shell_content->priv->hpaned;
 +	binding_id = cal_shell_content->priv->paned_binding_id;
 +
 +	shell_content = E_SHELL_CONTENT (cal_shell_content);
 +	shell_view = e_shell_content_get_shell_view (shell_content);
 +	view_id = e_shell_view_get_view_id (shell_view);
 +
 +	if (binding_id > 0)
 +		gconf_bridge_unbind (bridge, binding_id);
 +
 +	if (view_id != NULL && strcmp (view_id, "Month_View") == 0)
 +		key = "/apps/evolution/calendar/display/month_hpane_position";
 +	else
 +		key = "/apps/evolution/calendar/display/hpane_position";
 +
 +	binding_id = gconf_bridge_bind_property_delayed (
 +		bridge, key, G_OBJECT (paned), "position");
 +
 +	cal_shell_content->priv->paned_binding_id = binding_id;
 +}
 +
 +static FocusLocation
 +cal_shell_content_get_focus_location (ECalShellContent *cal_shell_content)
 +{
 +        return FOCUS_OTHER;
 +#if 0  /* TEMPORARILY DISABLED */
 +	GtkWidget *widget;
 +	GnomeCalendar *calendar;
 +	ECalendarTable *task_table;
 +	EMemoTable *memo_table;
 +	ETable *table;
 +	ECalendarView *calendar_view;
 +
 +	calendar = GNOME_CALENDAR (cal_shell_content->priv->calendar);
 +	widget = gnome_calendar_get_current_view_widget (calendar);
 +
 +	memo_table = E_MEMO_TABLE (cal_shell_content->priv->memo_table);
 +	task_table = E_CALENDAR_TABLE (cal_shell_content->priv->task_table);
 +
 +	table = e_memo_table_get_table (memo_table);
 +	if (GTK_WIDGET_HAS_FOCUS (table->table_canvas))
 +		return FOCUS_MEMO_TABLE;
 +
 +	table = e_calendar_table_get_table (task_table);
 +	if (GTK_WIDGET_HAS_FOCUS (table->table_canvas))
 +		return FOCUS_TASK_TABLE;
 +
 +	if (E_IS_DAY_VIEW (widget)) {
 +		EDayView *view = E_DAY_VIEW (widget);
 +
 +		if (GTK_WIDGET_HAS_FOCUS (view->top_canvas))
 +			return FOCUS_CALENDAR;
 +
 +		if (GNOME_CANVAS (view->top_canvas)->focused_item != NULL)
 +			return FOCUS_CALENDAR;
 +
 +		if (GTK_WIDGET_HAS_FOCUS (view->main_canvas))
 +			return FOCUS_CALENDAR;
 +
 +		if (GNOME_CANVAS (view->main_canvas)->focused_item != NULL)
 +			return FOCUS_CALENDAR;
 +
 +	} else if (E_IS_WEEK_VIEW (widget)) {
 +		EWeekView *view = E_WEEK_VIEW (widget);
 +
 +		if (GTK_WIDGET_HAS_FOCUS (view->main_canvas))
 +			return FOCUS_CALENDAR;
 +
 +		if (GNOME_CANVAS (view->main_canvas)->focused_item != NULL)
 +			return FOCUS_CALENDAR;
 +
 +	} else if (E_IS_CAL_LIST_VIEW (widget)) {
 +		ECalListView *view = E_CAL_LIST_VIEW (widget);
 +
 +		table = e_table_scrolled_get_table (view->table_scrolled);
 +		if (GTK_WIDGET_HAS_FOCUS (table))
 +			return FOCUS_CALENDAR;
 +	}
 +
 +	return FOCUS_OTHER;
 +#endif
 +}
 +
 +static void
 +cal_shell_content_set_property (GObject *object,
 +                                guint property_id,
 +                                const GValue *value,
 +                                GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +cal_shell_content_get_property (GObject *object,
 +                                guint property_id,
 +                                GValue *value,
 +                                GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +cal_shell_content_dispose (GObject *object)
 +{
 +	ECalShellContentPrivate *priv;
 +
 +	priv = E_CAL_SHELL_CONTENT_GET_PRIVATE (object);
 +
 +	if (priv->hpaned != NULL) {
 +		g_object_unref (priv->hpaned);
 +		priv->hpaned = NULL;
 +	}
 +
 +	if (priv->notebook != NULL) {
 +		g_object_unref (priv->notebook);
 +		priv->notebook = NULL;
 +	}
 +
 +	if (priv->vpaned != NULL) {
 +		g_object_unref (priv->vpaned);
 +		priv->vpaned = NULL;
 +	}
 +
 +	if (priv->day_view != NULL) {
 +		g_object_unref (priv->day_view);
 +		priv->day_view = NULL;
 +	}
 +
 +	if (priv->work_week_view != NULL) {
 +		g_object_unref (priv->work_week_view);
 +		priv->work_week_view = NULL;
 +	}
 +
 +	if (priv->week_view != NULL) {
 +		g_object_unref (priv->week_view);
 +		priv->week_view = NULL;
 +	}
 +
 +	if (priv->month_view != NULL) {
 +		g_object_unref (priv->month_view);
 +		priv->month_view = NULL;
 +	}
 +
 +	if (priv->list_view != NULL) {
 +		g_object_unref (priv->list_view);
 +		priv->list_view = NULL;
 +	}
 +
 +	if (priv->task_table != NULL) {
 +		g_object_unref (priv->task_table);
 +		priv->task_table = NULL;
 +	}
 +
 +	if (priv->memo_table != NULL) {
 +		g_object_unref (priv->memo_table);
 +		priv->memo_table = NULL;
 +	}
 +
 +	if (priv->day_view_config != NULL) {
 +		g_object_unref (priv->day_view_config);
 +		priv->day_view_config = NULL;
 +	}
 +
 +	if (priv->work_week_view_config != NULL) {
 +		g_object_unref (priv->work_week_view_config);
 +		priv->work_week_view_config = NULL;
 +	}
 +
 +	if (priv->week_view_config != NULL) {
 +		g_object_unref (priv->week_view_config);
 +		priv->week_view_config = NULL;
 +	}
 +
 +	if (priv->month_view_config != NULL) {
 +		g_object_unref (priv->month_view_config);
 +		priv->month_view_config = NULL;
 +	}
 +
 +	if (priv->list_view_config != NULL) {
 +		g_object_unref (priv->list_view_config);
 +		priv->list_view_config = NULL;
 +	}
 +
 +	if (priv->task_table_config != NULL) {
 +		g_object_unref (priv->task_table_config);
 +		priv->task_table_config = NULL;
 +	}
 +
 +	if (priv->memo_table_config != NULL) {
 +		g_object_unref (priv->memo_table_config);
 +		priv->memo_table_config = NULL;
 +	}
 +
 +	if (priv->view_instance != NULL) {
 +		g_object_unref (priv->view_instance);
 +		priv->view_instance = NULL;
 +	}
 +
 +	/* Chain up to parent's dispose() method. */
 +	G_OBJECT_CLASS (parent_class)->dispose (object);
 +}
 +
 +static void
 +cal_shell_content_finalize (GObject *object)
 +{
 +	ECalShellContentPrivate *priv;
 +
 +	priv = E_CAL_SHELL_CONTENT_GET_PRIVATE (object);
 +
 +	/* Chain up to parent's finalize() method. */
 +	G_OBJECT_CLASS (parent_class)->finalize (object);
 +}
 +
 +static void
 +cal_shell_content_constructed (GObject *object)
 +{
 +	ECalShellContentPrivate *priv;
 +	ECalModelCalendar *cal_model;
 +	ECalModel *memo_model;
 +	ECalModel *task_model;
 +	EShellContent *shell_content;
 +	EShellBackend *shell_backend;
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	EShellContent *foreign_content;
 +	EShellView *foreign_view;
 +	GalViewInstance *view_instance;
 +	GConfBridge *bridge;
 +	GtkWidget *container;
 +	GtkWidget *widget;
 +	const gchar *config_dir;
 +	const gchar *key;
 +	gchar *filename;
 +	gchar *markup;
 +	gint page_num;
 +
 +	priv = E_CAL_SHELL_CONTENT_GET_PRIVATE (object);
 +
 +	/* Chain up to parent's constructed() method. */
 +	G_OBJECT_CLASS (parent_class)->constructed (object);
 +
 +	shell_content = E_SHELL_CONTENT (object);
 +	shell_view = e_shell_content_get_shell_view (shell_content);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	shell_backend = e_shell_view_get_shell_backend (shell_view);
 +	config_dir = e_shell_backend_get_config_dir (shell_backend);
 +
 +	/* Calendar model for the views. */
 +	cal_model = e_cal_model_calendar_new ();
 +	e_cal_model_set_flags (
 +		E_CAL_MODEL (cal_model),
 +		E_CAL_MODEL_FLAGS_EXPAND_RECURRENCES);
 +
 +	/* We borrow the memopad and taskpad models from the memo
 +	 * and task views, loading the views if necessary. */
 +
 +	foreign_view = e_shell_window_get_shell_view (shell_window, "memos");
 +	foreign_content = e_shell_view_get_shell_content (foreign_view);
 +	g_object_get (foreign_content, "model", &memo_model, NULL);
 +
 +	foreign_view = e_shell_window_get_shell_view (shell_window, "tasks");
 +	foreign_content = e_shell_view_get_shell_content (foreign_view);
 +	g_object_get (foreign_content, "model", &task_model, NULL);
 +
 +	/* Build content widgets. */
 +
 +	container = GTK_WIDGET (object);
 +
 +	/* FIXME Need to deal with saving and restoring the position.
 +	 *       Month view has its own position. */
 +	widget = gtk_hpaned_new ();
 +	gtk_container_add (GTK_CONTAINER (container), widget);
 +	priv->hpaned = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	container = priv->hpaned;
 +
 +	widget = gtk_notebook_new ();
 +	gtk_notebook_set_show_tabs (GTK_NOTEBOOK (widget), FALSE);
 +	gtk_notebook_set_show_border (GTK_NOTEBOOK (widget), FALSE);
 +	gtk_paned_pack1 (GTK_PANED (container), widget, FALSE, TRUE);
 +	priv->notebook = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	/* FIXME Need to deal with saving and restoring the position.
 +	 *       Month view has its own position. */
 +	widget = gtk_vpaned_new ();
 +	gtk_paned_pack2 (GTK_PANED (container), widget, TRUE, TRUE);
 +	priv->vpaned = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	container = priv->notebook;
 +
 +	/* Add views in the order defined by GnomeCalendarViewType, such
 +	 * that the notebook page number corresponds to the view type.
 +	 * The assertions below ensure that stays true. */
 +
 +#if 0  /* Not so fast... get the memo/task pads working first. */
 +	/* FIXME Need to establish a calendar and timezone first. */
 +	widget = e_day_view_new (E_CAL_MODEL (cal_model));
 +	e_calendar_view_set_calendar (
 +		E_CALENDAR_VIEW (widget), GNOME_CALENDAR (priv->calendar));
 +	e_calendar_view_set_timezone (
 +		E_CALENDAR_VIEW (widget), priv->timezone);
 +	page_num = gtk_notebook_get_n_pages (GTK_NOTEBOOK (widget));
 +	gtk_notebook_append_page (GTK_NOTEBOOK (container), widget, NULL);
 +	g_return_if_fail (page_num == GNOME_CAL_DAY_VIEW);
 +	priv->day_view = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	/* FIXME Need to establish a calendar and timezone first. */
 +	widget = e_day_view_new (E_CAL_MODEL (cal_model));
 +	e_day_view_set_work_week_view (E_DAY_VIEW (widget), TRUE);
 +	e_day_view_set_days_shown (E_DAY_VIEW (widget), 5);
 +	e_calendar_view_set_calendar (
 +		E_CALENDAR_VIEW (widget), GNOME_CALENDAR (priv->calendar));
 +	e_calendar_view_set_timezone (
 +		E_CALENDAR_VIEW (widget), priv->timezone);
 +	page_num = gtk_notebook_get_n_pages (GTK_NOTEBOOK (widget));
 +	gtk_notebook_append_page (GTK_NOTEBOOK (container), widget, NULL);
 +	g_return_if_fail (page_num == GNOME_CAL_WORK_WEEK_VIEW);
 +	priv->work_week_view = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	/* FIXME Need to establish a calendar and timezone first. */
 +	widget = e_week_view_new (E_CAL_MODEL (cal_model));
 +	e_calendar_view_set_calendar (
 +		E_CALENDAR_VIEW (widget), GNOME_CALENDAR (priv->calendar));
 +	e_calendar_view_set_timezone (
 +		E_CALENDAR_VIEW (widget), priv->timezone);
 +	page_num = gtk_notebook_get_n_pages (GTK_NOTEBOOK (widget));
 +	gtk_notebook_append_page (GTK_NOTEBOOK (container), widget, NULL);
 +	g_return_if_fail (page_num == GNOME_CAL_WEEK_VIEW);
 +	priv->week_view = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	/* FIXME Need to establish a calendar and timezone first. */
 +	widget = e_week_view_new (E_CAL_MODEL (cal_model));
 +	e_week_view_set_multi_week_view (E_WEEK_VIEW (widget), TRUE);
 +	e_week_view_set_weeks_shown (E_WEEK_VIEW (widget), 6);
 +	e_calendar_view_set_calendar (
 +		E_CALENDAR_VIEW (widget), GNOME_CALENDAR (priv->calendar));
 +	e_calendar_view_set_timezone (
 +		E_CALENDAR_VIEW (widget), priv->timezone);
 +	page_num = gtk_notebook_get_n_pages (GTK_NOTEBOOK (widget));
 +	gtk_notebook_append_page (GTK_NOTEBOOK (container), widget, NULL);
 +	g_return_if_fail (page_num == GNOME_CAL_MONTH_VIEW);
 +	priv->month_view = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	/* FIXME Need to establish a calendar and timezone first. */
 +	widget = e_cal_list_view_new (E_CAL_MODEL (cal_model));
 +	e_calendar_view_set_calendar (
 +		E_CALENDAR_VIEW (widget), GNOME_CALENDAR (priv->calendar));
 +	e_calendar_view_set_timezone (
 +		E_CALENDAR_VIEW (widget), priv->timezone);
 +	page_num = gtk_notebook_get_n_pages (GTK_NOTEBOOK (widget));
 +	gtk_notebook_append_page (GTK_NOTEBOOK (container), widget, NULL);
 +	g_return_if_fail (page_num == GNOME_CAL_LIST_VIEW);
 +	priv->list_view = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +#endif
 +
 +	container = priv->vpaned;
 +
 +	widget = gtk_vbox_new (FALSE, 0);
 +	gtk_paned_pack1 (GTK_PANED (container), widget, FALSE, FALSE);
 +	gtk_widget_show (widget);
 +
 +	container = widget;
 +
 +	widget = gtk_hseparator_new ();
 +	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, TRUE, 0);
 +	gtk_widget_show (widget);
 +
 +	widget = gtk_label_new (NULL);
 +	markup = g_strdup_printf ("<b>%s</b>", _("Tasks"));
 +	gtk_label_set_markup (GTK_LABEL (widget), markup);
 +	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, TRUE, 0);
 +	gtk_widget_show (widget);
 +	g_free (markup);
 +
 +	widget = e_calendar_table_new (shell_view, task_model);
 +	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
 +	priv->task_table = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	filename = g_build_filename (config_dir, "TaskPad", NULL);
 +	e_calendar_table_load_state (E_CALENDAR_TABLE (widget), filename);
 +	g_free (filename);
 +
 +	container = priv->vpaned;
 +
 +	widget = gtk_vbox_new (FALSE, 0);
 +	gtk_paned_pack2 (GTK_PANED (container), widget, TRUE, FALSE);
 +	gtk_widget_show (widget);
 +
 +	container = widget;
 +
 +	widget = gtk_label_new (NULL);
 +	markup = g_strdup_printf ("<b>%s</b>", _("Memos"));
 +	gtk_label_set_markup (GTK_LABEL (widget), markup);
 +	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, TRUE, 0);
 +	gtk_widget_show (widget);
 +	g_free (markup);
 +
 +	widget = e_memo_table_new (shell_view, memo_model);
 +	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
 +	priv->memo_table = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	filename = g_build_filename (config_dir, "MemoPad", NULL);
 +	e_memo_table_load_state (E_MEMO_TABLE (widget), filename);
 +	g_free (filename);
 +
 +	/* Configuration managers for views and tables. */
 +	priv->day_view_config = e_day_view_config_new (
 +		E_DAY_VIEW (priv->day_view));
 +	priv->work_week_view_config = e_day_view_config_new (
 +		E_DAY_VIEW (priv->work_week_view));
 +	priv->week_view_config = e_week_view_config_new (
 +		E_WEEK_VIEW (priv->week_view));
 +	priv->month_view_config = e_week_view_config_new (
 +		E_WEEK_VIEW (priv->month_view));
 +	priv->list_view_config = e_cal_list_view_config_new (
 +		E_CAL_LIST_VIEW (priv->list_view));
 +	priv->task_table_config = e_calendar_table_config_new (
 +		E_CALENDAR_TABLE (priv->task_table));
 +	priv->memo_table_config = e_memo_table_config_new (
 +		E_MEMO_TABLE (priv->memo_table));
 +
 +	/* Load the view instance. */
 +
 +	view_instance = e_shell_view_new_view_instance (shell_view, NULL);
 +	g_signal_connect_swapped (
 +		view_instance, "display-view",
 +		G_CALLBACK (cal_shell_content_display_view_cb),
 +		object);
 +	gal_view_instance_load (view_instance);
 +	priv->view_instance = view_instance;
 +
 +	g_signal_connect_swapped (
 +		shell_view, "notify::view-id",
 +		G_CALLBACK (cal_shell_content_notify_view_id_cb),
 +		object);
 +
 +	/* Bind GObject properties to GConf keys. */
 +
 +	bridge = gconf_bridge_get ();
 +
 +	object = G_OBJECT (priv->vpaned);
 +	key = "/apps/evolution/calendar/display/vpane_position";
 +	gconf_bridge_bind_property_delayed (bridge, key, object, "position");
 +
 +	g_object_unref (memo_model);
 +	g_object_unref (task_model);
 +}
 +
 +static void
 +cal_shell_content_class_init (ECalShellContentClass *class)
 +{
 +	GObjectClass *object_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (ECalShellContentPrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->set_property = cal_shell_content_set_property;
 +	object_class->get_property = cal_shell_content_get_property;
 +	object_class->dispose = cal_shell_content_dispose;
 +	object_class->finalize = cal_shell_content_finalize;
 +	object_class->constructed = cal_shell_content_constructed;
 +}
 +
 +static void
 +cal_shell_content_init (ECalShellContent *cal_shell_content)
 +{
 +	cal_shell_content->priv =
 +		E_CAL_SHELL_CONTENT_GET_PRIVATE (cal_shell_content);
 +
 +	/* Postpone widget construction until we have a shell view. */
 +}
 +
 +GType
 +e_cal_shell_content_get_type (void)
 +{
 +	return cal_shell_content_type;
 +}
 +
 +void
 +e_cal_shell_content_register_type (GTypeModule *type_module)
 +{
 +	static const GTypeInfo type_info = {
 +		sizeof (ECalShellContentClass),
 +		(GBaseInitFunc) NULL,
 +		(GBaseFinalizeFunc) NULL,
 +		(GClassInitFunc) cal_shell_content_class_init,
 +		(GClassFinalizeFunc) NULL,
 +		NULL,  /* class_data */
 +		sizeof (ECalShellContent),
 +		0,     /* n_preallocs */
 +		(GInstanceInitFunc) cal_shell_content_init,
 +		NULL   /* value_table */
 +	};
 +
 +	cal_shell_content_type = g_type_module_register_type (
 +		type_module, E_TYPE_SHELL_CONTENT,
 +		"ECalShellContent", &type_info, 0);
 +}
 +
 +GtkWidget *
 +e_cal_shell_content_new (EShellView *shell_view)
 +{
 +	g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
 +
 +	return g_object_new (
 +		E_TYPE_CAL_SHELL_CONTENT,
 +		"shell-view", shell_view, NULL);
 +}
 +
 +GnomeCalendar *
 +e_cal_shell_content_get_calendar (ECalShellContent *cal_shell_content)
 +{
 +	g_return_val_if_fail (
 +		E_IS_CAL_SHELL_CONTENT (cal_shell_content), NULL);
 +
 +        /* FIXME */
 +	/*return GNOME_CALENDAR (cal_shell_content->priv->calendar);*/
 +        return NULL;
 +}
 +
 +EMemoTable *
 +e_cal_shell_content_get_memo_table (ECalShellContent *cal_shell_content)
 +{
 +	g_return_val_if_fail (
 +		E_IS_CAL_SHELL_CONTENT (cal_shell_content), NULL);
 +
 +	return E_MEMO_TABLE (cal_shell_content->priv->memo_table);
 +}
 +
 +ECalendarTable *
 +e_cal_shell_content_get_task_table (ECalShellContent *cal_shell_content)
 +{
 +	g_return_val_if_fail (
 +		E_IS_CAL_SHELL_CONTENT (cal_shell_content), NULL);
 +
 +	return E_CALENDAR_TABLE (cal_shell_content->priv->task_table);
 +}
 +
 +icaltimezone *
 +e_cal_shell_content_get_timezone (ECalShellContent *cal_shell_content)
 +{
 +	g_return_val_if_fail (
 +		E_IS_CAL_SHELL_CONTENT (cal_shell_content), NULL);
 +
 +        /* FIXME */
 +	/*return cal_shell_content->priv->timezone;*/
 +        return NULL;
 +}
 +
 +GalViewInstance *
 +e_cal_shell_content_get_view_instance (ECalShellContent *cal_shell_content)
 +{
 +	g_return_val_if_fail (
 +		E_IS_CAL_SHELL_CONTENT (cal_shell_content), NULL);
 +
 +	return cal_shell_content->priv->view_instance;
 +}
 +
 +void
 +e_cal_shell_content_copy_clipboard (ECalShellContent *cal_shell_content)
 +{
 +#if 0
 +	GnomeCalendar *calendar;
 +	EMemoTable *memo_table;
 +	ECalendarTable *task_table;
 +
 +	g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
 +
 +	calendar = e_cal_shell_content_get_calendar (cal_shell_content);
 +	memo_table = e_cal_shell_content_get_memo_table (cal_shell_content);
 +	task_table = e_cal_shell_content_get_task_table (cal_shell_content);
 +
 +	switch (cal_shell_content_get_focus_location (cal_shell_content)) {
 +		case FOCUS_CALENDAR:
 +			gnome_calendar_copy_clipboard (calendar);
 +			break;
 +
 +		case FOCUS_MEMO_TABLE:
 +			e_memo_table_copy_clipboard (memo_table);
 +			break;
 +
 +		case FOCUS_TASK_TABLE:
 +			e_calendar_table_copy_clipboard (task_table);
 +			break;
 +
 +		default:
 +			g_return_if_reached ();
 +	}
 +#endif
 +}
 +
 +void
 +e_cal_shell_content_cut_clipboard (ECalShellContent *cal_shell_content)
 +{
 +#if 0
 +	GnomeCalendar *calendar;
 +	EMemoTable *memo_table;
 +	ECalendarTable *task_table;
 +
 +	g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
 +
 +	calendar = e_cal_shell_content_get_calendar (cal_shell_content);
 +	memo_table = e_cal_shell_content_get_memo_table (cal_shell_content);
 +	task_table = e_cal_shell_content_get_task_table (cal_shell_content);
 +
 +	switch (cal_shell_content_get_focus_location (cal_shell_content)) {
 +		case FOCUS_CALENDAR:
 +			gnome_calendar_cut_clipboard (calendar);
 +			break;
 +
 +		case FOCUS_MEMO_TABLE:
 +			e_memo_table_copy_clipboard (memo_table);
 +			break;
 +
 +		case FOCUS_TASK_TABLE:
 +			e_calendar_table_copy_clipboard (task_table);
 +			break;
 +
 +		default:
 +			g_return_if_reached ();
 +	}
 +#endif
 +}
 +
 +void
 +e_cal_shell_content_paste_clipboard (ECalShellContent *cal_shell_content)
 +{
 +#if 0
 +	GnomeCalendar *calendar;
 +	EMemoTable *memo_table;
 +	ECalendarTable *task_table;
 +
 +	g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
 +
 +	calendar = e_cal_shell_content_get_calendar (cal_shell_content);
 +	memo_table = e_cal_shell_content_get_memo_table (cal_shell_content);
 +	task_table = e_cal_shell_content_get_task_table (cal_shell_content);
 +
 +	switch (cal_shell_content_get_focus_location (cal_shell_content)) {
 +		case FOCUS_CALENDAR:
 +			gnome_calendar_paste_clipboard (calendar);
 +			break;
 +
 +		case FOCUS_MEMO_TABLE:
 +			e_memo_table_copy_clipboard (memo_table);
 +			break;
 +
 +		case FOCUS_TASK_TABLE:
 +			e_calendar_table_copy_clipboard (task_table);
 +			break;
 +
 +		default:
 +			g_return_if_reached ();
 +	}
 +#endif
 +}
 +
 +void
 +e_cal_shell_content_delete_selection (ECalShellContent *cal_shell_content)
 +{
 +#if 0
 +	GnomeCalendar *calendar;
 +	EMemoTable *memo_table;
 +	ECalendarTable *task_table;
 +
 +	g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
 +
 +	calendar = e_cal_shell_content_get_calendar (cal_shell_content);
 +	memo_table = e_cal_shell_content_get_memo_table (cal_shell_content);
 +	task_table = e_cal_shell_content_get_task_table (cal_shell_content);
 +
 +	switch (cal_shell_content_get_focus_location (cal_shell_content)) {
 +		case FOCUS_CALENDAR:
 +			gnome_calendar_delete_selection (calendar);
 +			break;
 +
 +		case FOCUS_MEMO_TABLE:
 +			e_memo_table_delete_selected (memo_table);
 +			break;
 +
 +		case FOCUS_TASK_TABLE:
 +			e_calendar_table_delete_selected (task_table);
 +			break;
 +
 +		default:
 +			g_return_if_reached ();
 +	}
 +#endif
 +}
 +
 +void
 +e_cal_shell_content_delete_selected_occurrence (ECalShellContent *cal_shell_content)
 +{
 +#if 0
 +	GnomeCalendar *calendar;
 +	FocusLocation focus;
 +
 +	g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
 +
 +	focus = cal_shell_content_get_focus_location (cal_shell_content);
 +	calendar = e_cal_shell_content_get_calendar (cal_shell_content);
 +
 +	if (focus == FOCUS_CALENDAR)
 +		gnome_calendar_delete_selected_occurrence (calendar);
 +#endif
 +}
diff --cc calendar/module/e-cal-shell-content.h
index 6b86179,0000000..44e13f7
mode 100644,000000..100644
--- a/calendar/module/e-cal-shell-content.h
+++ b/calendar/module/e-cal-shell-content.h
@@@ -1,108 -1,0 +1,108 @@@
 +/*
 + * e-cal-shell-content.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_CAL_SHELL_CONTENT_H
 +#define E_CAL_SHELL_CONTENT_H
 +
 +#include <shell/e-shell-content.h>
 +#include <shell/e-shell-view.h>
 +
 +#include <calendar/gui/e-memo-table.h>
 +#include <calendar/gui/gnome-cal.h>
 +#include <menus/gal-view-instance.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_CAL_SHELL_CONTENT \
 +	(e_cal_shell_content_get_type ())
 +#define E_CAL_SHELL_CONTENT(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_CAL_SHELL_CONTENT, ECalShellContent))
 +#define E_CAL_SHELL_CONTENT_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_CAL_SHELL_CONTENT, ECalShellContentClass))
 +#define E_IS_CAL_SHELL_CONTENT(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_CAL_SHELL_CONTENT))
 +#define E_IS_CAL_SHELL_CONTENT_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), E_TYPE_CAL_SHELL_CONTENT))
 +#define E_CAL_SHELL_CONTENT_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_CAL_SHELL_CONTENT, ECalShellContentClass))
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _ECalShellContent ECalShellContent;
 +typedef struct _ECalShellContentClass ECalShellContentClass;
 +typedef struct _ECalShellContentPrivate ECalShellContentPrivate;
 +
 +enum {
 +	E_CAL_SHELL_CONTENT_SELECTION_SINGLE		= 1 << 0,
 +	E_CAL_SHELL_CONTENT_SELECTION_MULTIPLE		= 1 << 1,
 +	E_CAL_SHELL_CONTENT_SELECTION_IS_ASSIGNABLE	= 1 << 2,
 +	E_CAL_SHELL_CONTENT_SELECTION_IS_COMPLETE	= 1 << 3,
 +	E_CAL_SHELL_CONTENT_SELECTION_IS_EDITABLE	= 1 << 4,
 +	E_CAL_SHELL_CONTENT_SELECTION_IS_MEETING	= 1 << 5,
 +	E_CAL_SHELL_CONTENT_SELECTION_IS_ORGANIZER	= 1 << 6,
 +	E_CAL_SHELL_CONTENT_SELECTION_IS_RECURRING	= 1 << 7,
 +	E_CAL_SHELL_CONTENT_SELECTION_CAN_ACCEPT	= 1 << 8,
 +	E_CAL_SHELL_CONTENT_SELECTION_CAN_DELEGATE	= 1 << 9,
 +	E_CAL_SHELL_CONTENT_SELECTION_CAN_SAVE		= 1 << 10
 +};
 +
 +struct _ECalShellContent {
 +	EShellContent parent;
 +	ECalShellContentPrivate *priv;
 +};
 +
 +struct _ECalShellContentClass {
 +	EShellContentClass parent_class;
 +};
 +
 +GType		e_cal_shell_content_get_type	(void);
 +void		e_cal_shell_content_register_type
 +					(GTypeModule *type_module);
 +GtkWidget *	e_cal_shell_content_new	(EShellView *shell_view);
 +GnomeCalendar *	e_cal_shell_content_get_calendar
 +					(ECalShellContent *cal_shell_content);
 +EMemoTable *	e_cal_shell_content_get_memo_table
 +					(ECalShellContent *cal_shell_content);
 +ECalendarTable *e_cal_shell_content_get_task_table
 +					(ECalShellContent *cal_shell_content);
 +icaltimezone *	e_cal_shell_content_get_timezone
 +					(ECalShellContent *cal_shell_content);
 +GalViewInstance *
 +		e_cal_shell_content_get_view_instance
 +					(ECalShellContent *cal_shell_content);
 +void		e_cal_shell_content_copy_clipboard
 +					(ECalShellContent *cal_shell_content);
 +void		e_cal_shell_content_cut_clipboard
 +					(ECalShellContent *cal_shell_content);
 +void		e_cal_shell_content_paste_clipboard
 +					(ECalShellContent *cal_shell_content);
 +void		e_cal_shell_content_delete_selection
 +					(ECalShellContent *cal_shell_content);
 +void		e_cal_shell_content_delete_selected_occurrence
 +					(ECalShellContent *cal_shell_content);
 +
 +G_END_DECLS
 +
 +#endif /* E_CAL_SHELL_CONTENT_H */
diff --cc calendar/module/e-cal-shell-migrate.c
index bdcca08,0000000..5414f4a
mode 100644,000000..100644
--- a/calendar/module/e-cal-shell-migrate.c
+++ b/calendar/module/e-cal-shell-migrate.c
@@@ -1,796 -1,0 +1,796 @@@
 +/*
 + * e-cal-shell-backend-migrate.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-cal-shell-migrate.h"
 +
 +#include <string.h>
 +#include <sys/types.h>
 +#include <sys/stat.h>
 +#include <unistd.h>
 +#include <fcntl.h>
 +#include <errno.h>
 +
 +#include <glib/gi18n.h>
 +#include <glib/gstdio.h>
 +#include <libebackend/e-dbhash.h>
 +#include <libedataserver/e-source.h>
 +#include <libedataserver/e-source-group.h>
 +#include <libedataserver/e-source-list.h>
 +#include <libedataserver/e-xml-hash-utils.h>
 +
 +#include "e-util/e-bconf-map.h"
 +#include "e-util/e-folder-map.h"
 +#include "e-util/e-util-private.h"
 +#include "calendar/gui/calendar-config.h"
 +#include "calendar/gui/calendar-config-keys.h"
 +#include "calendar/gui/e-cal-event.h"
 +#include "shell/e-shell.h"
 +
 +#define WEBCAL_BASE_URI "webcal://"
 +#define CONTACTS_BASE_URI "contacts://"
 +#define BAD_CONTACTS_BASE_URI "contact://"
 +#define PERSONAL_RELATIVE_URI "system"
 +
 +static e_gconf_map_t calendar_display_map[] = {
 +	/* /Calendar/Display */
 +	{ "Timezone", "calendar/display/timezone", E_GCONF_MAP_STRING },
 +	{ "Use24HourFormat", "calendar/display/use_24hour_format", E_GCONF_MAP_BOOL },
 +	{ "WeekStartDay", "calendar/display/week_start_day", E_GCONF_MAP_INT },
 +	{ "DayStartHour", "calendar/display/day_start_hour", E_GCONF_MAP_INT },
 +	{ "DayStartMinute", "calendar/display/day_start_minute", E_GCONF_MAP_INT },
 +	{ "DayEndHour", "calendar/display/day_end_hour", E_GCONF_MAP_INT },
 +	{ "DayEndMinute", "calendar/display/day_end_minute", E_GCONF_MAP_INT },
 +	{ "TimeDivisions", "calendar/display/time_divisions", E_GCONF_MAP_INT },
 +	{ "View", "calendar/display/default_view", E_GCONF_MAP_INT },
 +	{ "HPanePosition", "calendar/display/hpane_position", E_GCONF_MAP_FLOAT },
 +	{ "VPanePosition", "calendar/display/vpane_position", E_GCONF_MAP_FLOAT },
 +	{ "MonthHPanePosition", "calendar/display/month_hpane_position", E_GCONF_MAP_FLOAT },
 +	{ "MonthVPanePosition", "calendar/display/month_vpane_position", E_GCONF_MAP_FLOAT },
 +	{ "CompressWeekend", "calendar/display/compress_weekend", E_GCONF_MAP_BOOL },
 +	{ "ShowEventEndTime", "calendar/display/show_event_end", E_GCONF_MAP_BOOL },
 +	{ "WorkingDays", "calendar/display/working_days", E_GCONF_MAP_INT },
 +	{ NULL },
 +};
 +
 +static e_gconf_map_t calendar_other_map[] = {
 +	/* /Calendar/Other */
 +	{ "ConfirmDelete", "calendar/prompts/confirm_delete", E_GCONF_MAP_BOOL },
 +	{ "ConfirmExpunge", "calendar/prompts/confirm_purge", E_GCONF_MAP_BOOL },
 +	{ "UseDefaultReminder", "calendar/other/use_default_reminder", E_GCONF_MAP_BOOL },
 +	{ "DefaultReminderInterval", "calendar/other/default_reminder_interval", E_GCONF_MAP_INT },
 +	{ "DefaultReminderUnits", "calendar/other/default_reminder_units", E_GCONF_MAP_STRING },
 +	{ NULL },
 +};
 +
 +static e_gconf_map_t calendar_datenavigator_map[] = {
 +	/* /Calendar/DateNavigator */
 +	{ "ShowWeekNumbers", "calendar/date_navigator/show_week_numbers", E_GCONF_MAP_BOOL },
 +	{ NULL },
 +};
 +
 +static e_gconf_map_t calendar_alarmnotify_map[] = {
 +	/* /Calendar/AlarmNotify */
 +	{ "LastNotificationTime", "calendar/notify/last_notification_time", E_GCONF_MAP_INT },
 +	{ "CalendarToLoad%i", "calendar/notify/calendars", E_GCONF_MAP_STRING|E_GCONF_MAP_LIST },
 +	{ "BlessedProgram%i", "calendar/notify/programs", E_GCONF_MAP_STRING|E_GCONF_MAP_LIST },
 +	{ NULL },
 +};
 +
 +static e_gconf_map_list_t calendar_remap_list[] = {
 +
 +	{ "/Calendar/Display", calendar_display_map },
 +	{ "/Calendar/Other/Map", calendar_other_map },
 +	{ "/Calendar/DateNavigator", calendar_datenavigator_map },
 +	{ "/Calendar/AlarmNotify", calendar_alarmnotify_map },
 +
 +	{ NULL },
 +};
 +
 +static GtkWidget *window;
 +static GtkLabel *label;
 +static GtkProgressBar *progress;
 +
 +#ifndef G_OS_WIN32
 +
 +/* No previous versions have been available on Win32, so don't
 + * bother with upgrade support from 1.x on Win32.
 + */
 +
 +static void
 +setup_progress_dialog (void)
 +{
 +	GtkWidget *vbox, *hbox, *w;
 +
 +	window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 +	gtk_window_set_title ((GtkWindow *) window, _("Migrating..."));
 +	gtk_window_set_modal ((GtkWindow *) window, TRUE);
 +	gtk_container_set_border_width ((GtkContainer *) window, 6);
 +
 +	vbox = gtk_vbox_new (FALSE, 6);
 +	gtk_widget_show (vbox);
 +	gtk_container_add ((GtkContainer *) window, vbox);
 +
 +	w = gtk_label_new (_("The location and hierarchy of the Evolution calendar "
 +			     "folders has changed since Evolution 1.x.\n\nPlease be "
 +			     "patient while Evolution migrates your folders..."));
 +
 +	gtk_label_set_line_wrap ((GtkLabel *) w, TRUE);
 +	gtk_widget_show (w);
 +	gtk_box_pack_start_defaults ((GtkBox *) vbox, w);
 +
 +	hbox = gtk_hbox_new (FALSE, 6);
 +	gtk_widget_show (hbox);
 +	gtk_box_pack_start_defaults ((GtkBox *) vbox, hbox);
 +
 +	label = (GtkLabel *) gtk_label_new ("");
 +	gtk_widget_show ((GtkWidget *) label);
 +	gtk_box_pack_start_defaults ((GtkBox *) hbox, (GtkWidget *) label);
 +
 +	progress = (GtkProgressBar *) gtk_progress_bar_new ();
 +	gtk_widget_show ((GtkWidget *) progress);
 +	gtk_box_pack_start_defaults ((GtkBox *) hbox, (GtkWidget *) progress);
 +
 +	gtk_widget_show (window);
 +}
 +
 +static void
 +dialog_close (void)
 +{
 +	gtk_widget_destroy ((GtkWidget *) window);
 +}
 +
 +static void
 +dialog_set_folder_name (const char *folder_name)
 +{
 +	char *text;
 +
 +	text = g_strdup_printf (_("Migrating '%s':"), folder_name);
 +	gtk_label_set_text (label, text);
 +	g_free (text);
 +
 +	gtk_progress_bar_set_fraction (progress, 0.0);
 +
 +	while (gtk_events_pending ())
 +		gtk_main_iteration ();
 +}
 +
 +static void
 +dialog_set_progress (double percent)
 +{
 +	char text[5];
 +
 +	snprintf (text, sizeof (text), "%d%%", (int) (percent * 100.0f));
 +
 +	gtk_progress_bar_set_fraction (progress, percent);
 +	gtk_progress_bar_set_text (progress, text);
 +
 +	while (gtk_events_pending ())
 +		gtk_main_iteration ();
 +}
 +
 +static gboolean
 +check_for_conflict (ESourceGroup *group, char *name)
 +{
 +	GSList *sources;
 +	GSList *s;
 +
 +	sources = e_source_group_peek_sources (group);
 +
 +	for (s = sources; s; s = s->next) {
 +		ESource *source = E_SOURCE (s->data);
 +
 +		if (!strcmp (e_source_peek_name (source), name))
 +			return TRUE;
 +	}
 +
 +	return FALSE;
 +}
 +
 +static char *
 +get_source_name (ESourceGroup *group, const char *path)
 +{
 +	char **p = g_strsplit (path, "/", 0);
 +	int i, j, starting_index;
 +	int num_elements;
 +	gboolean conflict;
 +	GString *s = g_string_new (NULL);
 +
 +	for (i = 0; p[i]; i ++) ;
 +
 +	num_elements = i;
 +	i--;
 +
 +	/* p[i] is now the last path element */
 +
 +	/* check if it conflicts */
 +	starting_index = i;
 +	do {
 +		for (j = starting_index; j < num_elements; j += 2) {
 +			if (j != starting_index)
 +				g_string_append_c (s, '_');
 +			g_string_append (s, p[j]);
 +		}
 +
 +		conflict = check_for_conflict (group, s->str);
 +
 +
 +		/* if there was a conflict back up 2 levels (skipping the /subfolder/ element) */
 +		if (conflict)
 +			starting_index -= 2;
 +
 +		/* we always break out if we can't go any further,
 +		   regardless of whether or not we conflict. */
 +		if (starting_index < 0)
 +			break;
 +
 +	} while (conflict);
 +	g_strfreev (p);
 +
 +	return g_string_free (s, FALSE);
 +}
 +
 +static gboolean
 +migrate_ical (ECal *old_ecal, ECal *new_ecal)
 +{
 +	GList *l, *objects;
 +	int num_added = 0;
 +	int num_objects;
 +	gboolean retval = TRUE;
 +
 +	/* both ecals are loaded, start the actual migration */
 +	if (!e_cal_get_object_list (old_ecal, "#t", &objects, NULL))
 +		return FALSE;
 +
 +	num_objects = g_list_length (objects);
 +	for (l = objects; l; l = l->next) {
 +		icalcomponent *ical_comp = l->data;
 +		GError *error = NULL;
 +
 +		if (!e_cal_create_object (new_ecal, ical_comp, NULL, &error)) {
 +			g_warning ("Migration of object failed: %s", error->message);
 +			retval = FALSE;
 +		}
 +
 +		g_clear_error (&error);
 +
 +		num_added ++;
 +		dialog_set_progress ((double)num_added / num_objects);
 +	}
 +
 +	g_list_foreach (objects, (GFunc) icalcomponent_free, NULL);
 +	g_list_free (objects);
 +
 +	return retval;
 +}
 +
 +static gboolean
 +migrate_ical_folder_to_source (char *old_path, ESource *new_source, ECalSourceType type)
 +{
 +	ECal *old_ecal = NULL, *new_ecal = NULL;
 +	ESource *old_source;
 +	ESourceGroup *group;
 +	char *old_uri = g_strdup_printf ("file://%s", old_path);
 +	GError *error = NULL;
 +	gboolean retval = FALSE;
 +
 +	group = e_source_group_new ("", old_uri);
 +	old_source = e_source_new ("", "");
 +	e_source_group_add_source (group, old_source, -1);
 +
 +	dialog_set_folder_name (e_source_peek_name (new_source));
 +
 +	if (!(old_ecal = e_cal_new (old_source, type))) {
 +		g_warning ("could not find a backend for '%s'", e_source_get_uri (old_source));
 +		goto finish;
 +	}
 +	if (!e_cal_open (old_ecal, FALSE, &error)) {
 +		g_warning ("failed to load source ecal for migration: '%s' (%s)", error->message,
 +			   e_source_get_uri (old_source));
 +		goto finish;
 +	}
 +
 +	if (!(new_ecal = e_cal_new (new_source, type))) {
 +		g_warning ("could not find a backend for '%s'", e_source_get_uri (new_source));
 +		goto finish;
 +	}
 +	if (!e_cal_open (new_ecal, FALSE, &error)) {
 +		g_warning ("failed to load destination ecal for migration: '%s' (%s)", error->message,
 +			   e_source_get_uri (new_source));
 +		goto finish;
 +	}
 +
 +	retval = migrate_ical (old_ecal, new_ecal);
 +
 +finish:
 +	g_clear_error (&error);
 +	if (old_ecal)
 +		g_object_unref (old_ecal);
 +	g_object_unref (group);
 +	if (new_ecal)
 +		g_object_unref (new_ecal);
 +	g_free (old_uri);
 +
 +	return retval;
 +}
 +
 +static gboolean
 +migrate_ical_folder (char *old_path, ESourceGroup *dest_group, char *source_name, ECalSourceType type)
 +{
 +	ESource *new_source;
 +	gboolean retval;
 +
 +	new_source = e_source_new (source_name, source_name);
 +	e_source_set_relative_uri (new_source, e_source_peek_uid (new_source));
 +	e_source_group_add_source (dest_group, new_source, -1);
 +
 +	retval = migrate_ical_folder_to_source (old_path, new_source, type);
 +
 +	g_object_unref (new_source);
 +
 +	return retval;
 +}
 +
 +#endif	/* !G_OS_WIN32 */
 +
 +#ifndef G_OS_WIN32
 +
 +static void
 +migrate_pilot_db_key (const char *key, gpointer user_data)
 +{
 +	EXmlHash *xmlhash = user_data;
 +
 +	e_xmlhash_add (xmlhash, key, "");
 +}
 +
 +static void
 +migrate_pilot_data (const char *component, const char *conduit, const char *old_path, const char *new_path)
 +{
 +	char *changelog, *map;
 +	const char *dent;
 +	const char *ext;
 +	char *filename;
 +	GDir *dir;
 +
 +	if (!(dir = g_dir_open (old_path, 0, NULL)))
 +		return;
 +
 +	map = g_alloca (12 + strlen (conduit));
 +	sprintf (map, "pilot-map-%s-", conduit);
 +
 +	changelog = g_alloca (24 + strlen (conduit));
 +	sprintf (changelog, "pilot-sync-evolution-%s-", conduit);
 +
 +	while ((dent = g_dir_read_name (dir))) {
 +		if (!strncmp (dent, map, strlen (map)) &&
 +		    ((ext = strrchr (dent, '.')) && !strcmp (ext, ".xml"))) {
 +			/* pilot map file - src and dest file formats are identical */
 +			unsigned char inbuf[4096];
 +			size_t nread, nwritten;
 +			int fd0, fd1;
 +			ssize_t n;
 +
 +			filename = g_build_filename (old_path, dent, NULL);
 +			if ((fd0 = g_open (filename, O_RDONLY|O_BINARY, 0)) == -1) {
 +				g_free (filename);
 +				continue;
 +			}
 +
 +			g_free (filename);
 +			filename = g_build_filename (new_path, dent, NULL);
 +			if ((fd1 = g_open (filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666)) == -1) {
 +				g_free (filename);
 +				close (fd0);
 +				continue;
 +			}
 +
 +			do {
 +				do {
 +					n = read (fd0, inbuf, sizeof (inbuf));
 +				} while (n == -1 && errno == EINTR);
 +
 +				if (n < 1)
 +					break;
 +
 +				nread = n;
 +				nwritten = 0;
 +				do {
 +					do {
 +						n = write (fd1, inbuf + nwritten, nread - nwritten);
 +					} while (n == -1 && errno == EINTR);
 +
 +					if (n > 0)
 +						nwritten += n;
 +				} while (nwritten < nread && n != -1);
 +
 +				if (n == -1)
 +					break;
 +			} while (1);
 +
 +			if (n != -1)
 +				n = fsync (fd1);
 +
 +			if (n == -1) {
 +				g_warning ("Failed to migrate %s: %s", dent, strerror (errno));
 +				g_unlink (filename);
 +			}
 +
 +			close (fd0);
 +			close (fd1);
 +			g_free (filename);
 +		} else if (!strncmp (dent, changelog, strlen (changelog)) &&
 +			   ((ext = strrchr (dent, '.')) && !strcmp (ext, ".db"))) {
 +			/* src and dest formats differ, src format is db3 while dest format is xml */
 +			EXmlHash *xmlhash;
 +			EDbHash *dbhash;
 +			struct stat st;
 +
 +			filename = g_build_filename (old_path, dent, NULL);
 +			if (g_stat (filename, &st) == -1) {
 +				g_free (filename);
 +				continue;
 +			}
 +
 +			dbhash = e_dbhash_new (filename);
 +			g_free (filename);
 +
 +			filename = g_strdup_printf ("%s/%s.ics-%s", new_path, component, dent);
 +			if (g_stat (filename, &st) != -1)
 +				g_unlink (filename);
 +			xmlhash = e_xmlhash_new (filename);
 +			g_free (filename);
 +
 +			e_dbhash_foreach_key (dbhash, migrate_pilot_db_key, xmlhash);
 +
 +			e_dbhash_destroy (dbhash);
 +
 +			e_xmlhash_write (xmlhash);
 +			e_xmlhash_destroy (xmlhash);
 +		}
 +	}
 +
 +	g_dir_close (dir);
 +}
 +
 +#endif
 +
 +static ESourceGroup *
 +create_calendar_contact_source (ESourceList *source_list)
 +{
 +	ESourceGroup *group;
 +	ESource *source;
 +
 +	/* Create the contacts group */
 +	group = e_source_group_new (_("Contacts"), CONTACTS_BASE_URI);
 +	e_source_list_add_group (source_list, group, -1);
 +
 +	source = e_source_new (_("Birthdays & Anniversaries"), "/");
 +	e_source_group_add_source (group, source, -1);
 +	g_object_unref (source);
 +
 +	e_source_set_color_spec (source, "#FED4D3");
 +	e_source_group_set_readonly (group, TRUE);
 +
 +	return group;
 +}
 +
 +static void
 +create_calendar_sources (EShellBackend *shell_backend,
 +			 ESourceList *source_list,
 +			 ESourceGroup **on_this_computer,
 +			 ESource **personal_source,
 +			 ESourceGroup **on_the_web,
 +			 ESourceGroup **contacts)
 +{
 +	EShell *shell;
 +	EShellSettings *shell_settings;
 +	GSList *groups;
 +	ESourceGroup *group;
 +	char *base_uri, *base_uri_proto;
 +	const gchar *base_dir;
 +
 +	*on_this_computer = NULL;
 +	*on_the_web = NULL;
 +	*contacts = NULL;
 +	*personal_source = NULL;
 +
 +	shell = e_shell_backend_get_shell (shell_backend);
 +	shell_settings = e_shell_get_shell_settings (shell);
 +
 +	base_dir = e_shell_backend_get_config_dir (shell_backend);
 +	base_uri = g_build_filename (base_dir, "local", NULL);
 +
 +	base_uri_proto = g_filename_to_uri (base_uri, NULL, NULL);
 +
 +	groups = e_source_list_peek_groups (source_list);
 +	if (groups) {
 +		/* groups are already there, we need to search for things... */
 +		GSList *g;
 +
 +		for (g = groups; g; g = g->next) {
 +
 +			group = E_SOURCE_GROUP (g->data);
 +
 +			if (!strcmp (BAD_CONTACTS_BASE_URI, e_source_group_peek_base_uri (group)))
 +				e_source_group_set_base_uri (group, CONTACTS_BASE_URI);
 +
 +			if (!strcmp (base_uri, e_source_group_peek_base_uri (group)))
 +				e_source_group_set_base_uri (group, base_uri_proto);
 +
 +			if (!*on_this_computer && !strcmp (base_uri_proto, e_source_group_peek_base_uri (group)))
 +				*on_this_computer = g_object_ref (group);
 +			else if (!*on_the_web && !strcmp (WEBCAL_BASE_URI, e_source_group_peek_base_uri (group)))
 +				*on_the_web = g_object_ref (group);
 +			else if (!*contacts && !strcmp (CONTACTS_BASE_URI, e_source_group_peek_base_uri (group)))
 +				*contacts = g_object_ref (group);
 +		}
 +	}
 +
 +	if (*on_this_computer) {
 +		/* make sure "Personal" shows up as a source under
 +		   this group */
 +		GSList *sources = e_source_group_peek_sources (*on_this_computer);
 +		GSList *s;
 +		for (s = sources; s; s = s->next) {
 +			ESource *source = E_SOURCE (s->data);
 +			const gchar *relative_uri;
 +
 +			relative_uri = e_source_peek_relative_uri (source);
 +			if (relative_uri == NULL)
 +				continue;
 +			if (!strcmp (PERSONAL_RELATIVE_URI, relative_uri)) {
 +				*personal_source = g_object_ref (source);
 +				break;
 +			}
 +		}
 +	} else {
 +		/* create the local source group */
 +		group = e_source_group_new (_("On This Computer"), base_uri_proto);
 +		e_source_list_add_group (source_list, group, -1);
 +
 +		*on_this_computer = group;
 +	}
 +
 +	if (!*personal_source) {
 +		char *primary_calendar;
 +
 +		/* Create the default Person calendar */
 +		ESource *source = e_source_new (_("Personal"), PERSONAL_RELATIVE_URI);
 +		e_source_group_add_source (*on_this_computer, source, -1);
 +
 +		primary_calendar = e_shell_settings_get_string (
 +			shell_settings, "cal-primary-calendar");
 +
 +		if (!primary_calendar && !calendar_config_get_calendars_selected ()) {
 +			GSList selected;
 +
 +			e_shell_settings_set_string (
 +				shell_settings, "cal-primary-calendar",
 +				e_source_peek_uid (source));
 +
 +			selected.data = (gpointer)e_source_peek_uid (source);
 +			selected.next = NULL;
 +			calendar_config_set_calendars_selected (&selected);
 +		}
 +
 +		g_free (primary_calendar);
 +		e_source_set_color_spec (source, "#BECEDD");
 +		*personal_source = source;
 +	}
 +
 +	if (!*on_the_web) {
 +		/* Create the Webcal source group */
 +		group = e_source_group_new (_("On The Web"), WEBCAL_BASE_URI);
 +		e_source_list_add_group (source_list, group, -1);
 +
 +		*on_the_web = group;
 +	}
 +
 +	if (!*contacts) {
 +		group = create_calendar_contact_source (source_list);
 +
 +		*contacts = group;
 +	}
 +
 +	g_free (base_uri_proto);
 +	g_free (base_uri);
 +}
 +
 +gboolean
 +e_cal_shell_backend_migrate (EShellBackend *shell_backend,
 +                            gint major,
 +                            gint minor,
 +                            gint micro,
 +                            GError **error)
 +{
 +	ESourceGroup *on_this_computer = NULL, *on_the_web = NULL, *contacts = NULL;
 +	ESource *personal_source = NULL;
 +	ESourceList *source_list;
 +	ECalEvent *ece;
 +	ECalEventTargetModule *target;
 +	gboolean retval = FALSE;
 +
 +	source_list = g_object_get_data (
 +		G_OBJECT (shell_backend), "source-list");
 +
 +	/* we call this unconditionally now - create_groups either
 +	   creates the groups/sources or it finds the necessary
 +	   groups/sources. */
 +	create_calendar_sources (
 +		shell_backend, source_list, &on_this_computer,
 +		&personal_source, &on_the_web, &contacts);
 +
 +#ifndef G_OS_WIN32
 +	if (major == 1) {
 +		xmlDocPtr config_doc = NULL;
 +		char *conf_file;
 +		struct stat st;
 +
 +		conf_file = g_build_filename (g_get_home_dir (), "evolution", "config.xmldb", NULL);
 +		if (lstat (conf_file, &st) == 0 && S_ISREG (st.st_mode))
 +			config_doc = xmlParseFile (conf_file);
 +		g_free (conf_file);
 +
 +		if (config_doc && minor <= 2) {
 +			GConfClient *gconf;
 +			int res = 0;
 +
 +			/* move bonobo config to gconf */
 +			gconf = gconf_client_get_default ();
 +
 +			res = e_bconf_import (gconf, config_doc, calendar_remap_list);
 +
 +			g_object_unref (gconf);
 +
 +			xmlFreeDoc(config_doc);
 +
 +			if (res != 0) {
 +				/* FIXME: set proper domain/code */
 +				g_set_error(error, 0, 0, _("Unable to migrate old settings from evolution/config.xmldb"));
 +				goto fail;
 +			}
 +		}
 +
 +		if (minor <= 4) {
 +			GSList *migration_dirs, *l;
 +			char *path, *local_cal_folder;
 +
 +			setup_progress_dialog ();
 +
 +			path = g_build_filename (g_get_home_dir (), "evolution", "local", NULL);
 +			migration_dirs = e_folder_map_local_folders (path, "calendar");
 +			local_cal_folder = g_build_filename (path, "Calendar", NULL);
 +			g_free (path);
 +
 +			if (personal_source)
 +				migrate_ical_folder_to_source (local_cal_folder, personal_source, E_CAL_SOURCE_TYPE_EVENT);
 +
 +			for (l = migration_dirs; l; l = l->next) {
 +				char *source_name;
 +
 +				if (personal_source && !strcmp ((char*)l->data, local_cal_folder))
 +					continue;
 +
 +				source_name = get_source_name (on_this_computer, (char*)l->data);
 +
 +				if (!migrate_ical_folder (l->data, on_this_computer, source_name, E_CAL_SOURCE_TYPE_EVENT)) {
 +					/* FIXME: domain/code */
 +					g_set_error(error, 0, 0, _("Unable to migrate calendar `%s'"), source_name);
 +					g_free(source_name);
 +					goto fail;
 +				}
 +
 +				g_free (source_name);
 +			}
 +
 +			g_free (local_cal_folder);
 +
 +			dialog_close ();
 +		}
 +
 +		if (minor <= 4 || (minor == 5 && micro < 5)) {
 +			GConfClient *gconf;
 +			GConfValue *gconf_val;
 +			int i;
 +			const char *keys[] = {
 +				CALENDAR_CONFIG_HPANE_POS,
 +				CALENDAR_CONFIG_VPANE_POS,
 +				CALENDAR_CONFIG_MONTH_HPANE_POS,
 +				CALENDAR_CONFIG_MONTH_VPANE_POS,
 +				NULL
 +			};
 +
 +			gconf = gconf_client_get_default ();
 +
 +			for (i = 0; keys[i]; i++) {
 +				gconf_val = gconf_client_get (gconf, keys[i], NULL);
 +				if (gconf_val) {
 +					if (gconf_val->type != GCONF_VALUE_INT)
 +						gconf_client_unset (gconf, keys[i], NULL);
 +					gconf_value_free (gconf_val);
 +				}
 +			}
 +
 +			g_object_unref (gconf);
 +		}
 +
 +		if (minor < 5 || (minor == 5 && micro <= 10)) {
 +			char *old_path, *new_path;
 +
 +			old_path = g_build_filename (g_get_home_dir (), "evolution", "local", "Calendar", NULL);
 +			new_path = g_build_filename (e_shell_backend_get_config_dir (shell_backend),
 +						     "local", "system", NULL);
 +			migrate_pilot_data ("calendar", "calendar", old_path, new_path);
 +			g_free (new_path);
 +			g_free (old_path);
 +		}
 +
 +		/* we only need to do this next step if people ran
 +		   older versions of 1.5.  We need to clear out the
 +		   absolute URI's that were assigned to ESources
 +		   during one phase of development, as they take
 +		   precedent over relative uris (but aren't updated
 +		   when editing an ESource). */
 +		if (minor == 5 && micro <= 11) {
 +			GSList *g;
 +			for (g = e_source_list_peek_groups (source_list); g; g = g->next) {
 +				ESourceGroup *group = g->data;
 +				GSList *s;
 +
 +				for (s = e_source_group_peek_sources (group); s; s = s->next) {
 +					ESource *source = s->data;
 +					e_source_set_absolute_uri (source, NULL);
 +				}
 +			}
 +		}
 +
 +	}
 +#endif	/* !G_OS_WIN32 */
 +
 +	e_source_list_sync (source_list, NULL);
 +
 +	/** @Event: component.migration
 +	 * @Title: Migration step in component initialization
 +	 * @Target: ECalEventTargetComponent
 +	 *
 +	 * component.migration is emitted during the calendar component
 +	 * initialization process. This allows new calendar backend types
 +	 * to be distributed as an e-d-s backend and a plugin without
 +	 * reaching their grubby little fingers into migration.c
 +	 */
 +	/* Fire off migration event */
 +	ece = e_cal_event_peek ();
 +	target = e_cal_event_target_new_module (ece, shell_backend, 0);
 +	e_event_emit ((EEvent *) ece, "module.migration", (EEventTarget *) target);
 +
 +	retval = TRUE;
 +fail:
 +	if (on_this_computer)
 +		g_object_unref (on_this_computer);
 +	if (on_the_web)
 +		g_object_unref (on_the_web);
 +	if (contacts)
 +		g_object_unref (contacts);
 +	if (personal_source)
 +		g_object_unref (personal_source);
 +
 +	return retval;
 +}
 +
diff --cc calendar/module/e-cal-shell-migrate.h
index 44cbf68,0000000..359ca5e
mode 100644,000000..100644
--- a/calendar/module/e-cal-shell-migrate.h
+++ b/calendar/module/e-cal-shell-migrate.h
@@@ -1,38 -1,0 +1,38 @@@
 +/*
 + * e-cal-shell-backend-migrate.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_CAL_SHELL_BACKEND_MIGRATE_H
 +#define E_CAL_SHELL_BACKEND_MIGRATE_H
 +
 +#include <glib.h>
 +#include <shell/e-shell-backend.h>
 +
 +G_BEGIN_DECLS
 +
 +gboolean	e_cal_shell_backend_migrate	(EShellBackend *shell_backend,
 +						 gint major,
 +						 gint minor,
 +						 gint micro,
 +						 GError **error);
 +
 +G_END_DECLS
 +
 +#endif /* E_CAL_SHELL_BACKEND_MIGRATE_H */
diff --cc calendar/module/e-cal-shell-settings.c
index 639622f,0000000..03af4ae
mode 100644,000000..100644
--- a/calendar/module/e-cal-shell-settings.c
+++ b/calendar/module/e-cal-shell-settings.c
@@@ -1,59 -1,0 +1,59 @@@
 +/*
 + * e-cal-shell-backend-settings.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-cal-shell-settings.h"
 +
 +#include <gconf/gconf-client.h>
 +
 +void
 +e_cal_shell_backend_init_settings (EShell *shell)
 +{
 +	EShellSettings *shell_settings;
 +
 +	shell_settings = e_shell_get_shell_settings (shell);
 +
 +	/* XXX Default values should match the GConf schema.
 +	 *     Yes it's redundant, but we're stuck with GConf. */
 +
 +	e_shell_settings_install_property (
 +		g_param_spec_string (
 +			"cal-primary-calendar",
 +			NULL,
 +			NULL,
 +			NULL,
 +			G_PARAM_READWRITE));
 +
 +	e_shell_settings_bind_to_gconf (
 +		shell_settings, "cal-primary-calendar",
 +		"/apps/evolution/calendar/display/primary_calendar");
 +
 +	e_shell_settings_install_property (
 +		g_param_spec_boolean (
 +			"cal-use-system-timezone",
 +			NULL,
 +			NULL,
 +			TRUE,
 +			G_PARAM_READWRITE));
 +
 +	e_shell_settings_bind_to_gconf (
 +		shell_settings, "cal-use-system-timezone",
 +		"/apps/evolution/calendar/display/use_system_timezone");
 +}
diff --cc calendar/module/e-cal-shell-settings.h
index 7382130,0000000..de8b228
mode 100644,000000..100644
--- a/calendar/module/e-cal-shell-settings.h
+++ b/calendar/module/e-cal-shell-settings.h
@@@ -1,33 -1,0 +1,33 @@@
 +/*
 + * e-cal-shell-backend-settings.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_CAL_SHELL_BACKEND_SETTINGS_H
 +#define E_CAL_SHELL_BACKEND_SETTINGS_H
 +
 +#include <shell/e-shell.h>
 +
 +G_BEGIN_DECLS
 +
 +void		e_cal_shell_backend_init_settings	(EShell *shell);
 +
 +G_END_DECLS
 +
 +#endif /* E_CAL_SHELL_BACKEND_SETTINGS_H */
diff --cc calendar/module/e-cal-shell-sidebar.c
index 2646836,0000000..dc7df59
mode 100644,000000..100644
--- a/calendar/module/e-cal-shell-sidebar.c
+++ b/calendar/module/e-cal-shell-sidebar.c
@@@ -1,759 -1,0 +1,759 @@@
 +/*
 + * e-cal-shell-sidebar.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-cal-shell-sidebar.h"
 +
 +#include <string.h>
 +#include <glib/gi18n.h>
 +
 +#include "e-util/e-error.h"
 +#include "e-util/gconf-bridge.h"
 +#include "calendar/common/authentication.h"
 +#include "calendar/gui/calendar-config.h"
 +#include "calendar/gui/e-calendar-selector.h"
 +#include "calendar/gui/e-mini-calendar-config.h"
 +#include "calendar/gui/misc.h"
 +
 +#include "e-cal-shell-backend.h"
 +#include "e-cal-shell-view.h"
 +
 +#define E_CAL_SHELL_SIDEBAR_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_CAL_SHELL_SIDEBAR, ECalShellSidebarPrivate))
 +
 +struct _ECalShellSidebarPrivate {
 +	GtkWidget *paned;
 +	GtkWidget *selector;
 +	GtkWidget *mini_calendar;
 +
 +	/* UID -> Client */
 +	GHashTable *client_table;
 +
 +	EMiniCalendarConfig *mini_calendar_config;
 +};
 +
 +enum {
 +	PROP_0,
 +	PROP_MINI_CALENDAR,
 +	PROP_SELECTOR
 +};
 +
 +enum {
 +	CLIENT_ADDED,
 +	CLIENT_REMOVED,
 +	STATUS_MESSAGE,
 +	LAST_SIGNAL
 +};
 +
 +static gpointer parent_class;
 +static guint signals[LAST_SIGNAL];
 +static GType cal_shell_sidebar_type;
 +
 +static void
 +cal_shell_sidebar_emit_client_added (ECalShellSidebar *cal_shell_sidebar,
 +                                     ECal *client)
 +{
 +	guint signal_id = signals[CLIENT_ADDED];
 +
 +	g_signal_emit (cal_shell_sidebar, signal_id, 0, client);
 +}
 +
 +static void
 +cal_shell_sidebar_emit_client_removed (ECalShellSidebar *cal_shell_sidebar,
 +                                       ECal *client)
 +{
 +	guint signal_id = signals[CLIENT_REMOVED];
 +
 +	g_signal_emit (cal_shell_sidebar, signal_id, 0, client);
 +}
 +
 +static void
 +cal_shell_sidebar_emit_status_message (ECalShellSidebar *cal_shell_sidebar,
 +                                       const gchar *status_message)
 +{
 +	guint signal_id = signals[STATUS_MESSAGE];
 +
 +	g_signal_emit (cal_shell_sidebar, signal_id, 0, status_message);
 +}
 +
 +static void
 +cal_shell_sidebar_backend_died_cb (ECalShellSidebar *cal_shell_sidebar,
 +                                   ECal *client)
 +{
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	EShellSidebar *shell_sidebar;
 +	GHashTable *client_table;
 +	ESource *source;
 +	const gchar *uid;
 +
 +	client_table = cal_shell_sidebar->priv->client_table;
 +
 +	shell_sidebar = E_SHELL_SIDEBAR (cal_shell_sidebar);
 +	shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	source = e_cal_get_source (client);
 +	uid = e_source_peek_uid (source);
 +
 +	g_object_ref (source);
 +
 +	g_hash_table_remove (client_table, uid);
 +	cal_shell_sidebar_emit_status_message (cal_shell_sidebar, NULL);
 +
 +	e_error_run (
 +		GTK_WINDOW (shell_window),
 +		"calendar:calendar-crashed", NULL);
 +
 +	g_object_unref (source);
 +}
 +
 +static void
 +cal_shell_sidebar_backend_error_cb (ECalShellSidebar *cal_shell_sidebar,
 +                                    const gchar *message,
 +                                    ECal *client)
 +{
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	EShellSidebar *shell_sidebar;
 +	GtkWidget *dialog;
 +	const gchar *uri;
 +	gchar *uri_no_passwd;
 +
 +	shell_sidebar = E_SHELL_SIDEBAR (cal_shell_sidebar);
 +	shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	uri = e_cal_get_uri (client);
 +	uri_no_passwd = get_uri_without_password (uri);
 +
 +	dialog = gtk_message_dialog_new (
 +		GTK_WINDOW (shell_window),
 +		GTK_DIALOG_DESTROY_WITH_PARENT,
 +		GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
 +		_("Error on %s\n%s"),
 +		uri_no_passwd, message);
 +
 +	gtk_dialog_run (GTK_DIALOG (dialog));
 +	gtk_widget_destroy (dialog);
 +
 +	g_free (uri_no_passwd);
 +}
 +
 +static void
 +cal_shell_sidebar_client_opened_cb (ECalShellSidebar *cal_shell_sidebar,
 +                                    ECalendarStatus status,
 +                                    ECal *client)
 +{
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	EShellSidebar *shell_sidebar;
 +	ESource *source;
 +
 +	source = e_cal_get_source (client);
 +
 +	shell_sidebar = E_SHELL_SIDEBAR (cal_shell_sidebar);
 +	shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	if (status == E_CALENDAR_STATUS_AUTHENTICATION_FAILED ||
 +		status == E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED)
 +		auth_cal_forget_password (client);
 +
 +	switch (status) {
 +		case E_CALENDAR_STATUS_OK:
 +			g_signal_handlers_disconnect_matched (
 +				client, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
 +				cal_shell_sidebar_client_opened_cb, NULL);
 +
 +			cal_shell_sidebar_emit_status_message (
 +				cal_shell_sidebar, _("Loading calendars"));
 +			cal_shell_sidebar_emit_client_added (
 +				cal_shell_sidebar, client);
 +			cal_shell_sidebar_emit_status_message (
 +				cal_shell_sidebar, NULL);
 +			break;
 +
 +		case E_CALENDAR_STATUS_AUTHENTICATION_FAILED:
 +			e_cal_open_async (client, FALSE);
 +			break;
 +
 +		case E_CALENDAR_STATUS_BUSY:
 +			break;
 +
 +		case E_CALENDAR_STATUS_REPOSITORY_OFFLINE:
 +			e_error_run (
 +				GTK_WINDOW (shell_window),
 +				"calendar:prompt-no-contents-offline-calendar",
 +				NULL);
 +			break;
 +
 +		default:
 +			cal_shell_sidebar_emit_client_removed (
 +				cal_shell_sidebar, client);
 +			break;
 +	}
 +}
 +
 +static void
 +cal_shell_sidebar_row_changed_cb (ECalShellSidebar *cal_shell_sidebar,
 +                                  GtkTreePath *tree_path,
 +                                  GtkTreeIter *tree_iter,
 +                                  GtkTreeModel *tree_model)
 +{
 +	ESourceSelector *selector;
 +	ESource *source;
 +
 +	/* XXX ESourceSelector's underlying tree store has only one
 +	 *     column: ESource objects.  While we're not supposed to
 +	 *     know this, listening for "row-changed" signals from
 +	 *     the model is easier to deal with than the selector's
 +	 *     "selection-changed" signal, which doesn't tell you
 +	 *     _which_ row changed. */
 +
 +	selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
 +	gtk_tree_model_get (tree_model, tree_iter, 0, &source, -1);
 +
 +	/* XXX This signal gets emitted a lot while the model is being
 +	 *     rebuilt, during which time we won't get a valid ESource.
 +	 *     ESourceSelector should probably block this signal while
 +	 *     rebuilding the model, but we'll be forgiving and not
 +	 *     emit a warning. */
 +	if (!E_IS_SOURCE (source))
 +		return;
 +
 +	if (e_source_selector_source_is_selected (selector, source))
 +		e_cal_shell_sidebar_add_source (cal_shell_sidebar, source);
 +	else
 +		e_cal_shell_sidebar_remove_source (cal_shell_sidebar, source);
 +}
 +
 +static void
 +cal_shell_sidebar_selection_changed_cb (ECalShellSidebar *cal_shell_sidebar,
 +                                        ESourceSelector *selector)
 +{
 +	GSList *list, *iter;
 +
 +	/* This signal is emitted less frequently than "row-changed",
 +	 * especially when the model is being rebuilt.  So we'll take
 +	 * it easy on poor GConf. */
 +
 +	list = e_source_selector_get_selection (selector);
 +
 +	for (iter = list; iter != NULL; iter = iter->next) {
 +		ESource *source = iter->data;
 +
 +		iter->data = (gpointer) e_source_peek_uid (source);
 +		g_object_unref (source);
 +	}
 +
 +	calendar_config_set_calendars_selected (list);
 +
 +	g_slist_free (list);
 +}
 +
 +static void
 +cal_shell_sidebar_primary_selection_changed_cb (ECalShellSidebar *cal_shell_sidebar,
 +                                                ESourceSelector *selector)
 +{
 +	EShell *shell;
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	EShellSidebar *shell_sidebar;
 +	EShellSettings *shell_settings;
 +	ESource *source;
 +
 +	/* XXX ESourceSelector needs a "primary-selection-uid" property
 +	 *     so we can just bind the property with GConfBridge. */
 +
 +	source = e_source_selector_peek_primary_selection (selector);
 +	if (source == NULL)
 +		return;
 +
 +	shell_sidebar = E_SHELL_SIDEBAR (cal_shell_sidebar);
 +	shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	shell = e_shell_window_get_shell (shell_window);
 +	shell_settings = e_shell_get_shell_settings (shell);
 +
 +	e_shell_settings_set_string (
 +		shell_settings, "cal-primary-calendar",
 +		e_source_peek_uid (source));
 +}
 +
 +static void
 +cal_shell_sidebar_get_property (GObject *object,
 +                                guint property_id,
 +                                GValue *value,
 +                                GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_MINI_CALENDAR:
 +			g_value_set_object (
 +				value, e_cal_shell_sidebar_get_mini_calendar (
 +				E_CAL_SHELL_SIDEBAR (object)));
 +			return;
 +
 +		case PROP_SELECTOR:
 +			g_value_set_object (
 +				value, e_cal_shell_sidebar_get_selector (
 +				E_CAL_SHELL_SIDEBAR (object)));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +cal_shell_sidebar_dispose (GObject *object)
 +{
 +	ECalShellSidebarPrivate *priv;
 +
 +	priv = E_CAL_SHELL_SIDEBAR_GET_PRIVATE (object);
 +
 +	if (priv->paned != NULL) {
 +		g_object_unref (priv->paned);
 +		priv->paned = NULL;
 +	}
 +
 +	if (priv->selector != NULL) {
 +		g_object_unref (priv->selector);
 +		priv->selector = NULL;
 +	}
 +
 +	if (priv->mini_calendar != NULL) {
 +		g_object_unref (priv->mini_calendar);
 +		priv->mini_calendar = NULL;
 +	}
 +
 +	g_hash_table_remove_all (priv->client_table);
 +
 +	if (priv->mini_calendar_config != NULL) {
 +		g_object_unref (priv->mini_calendar_config);
 +		priv->mini_calendar = NULL;
 +	}
 +
 +	/* Chain up to parent's dispose() method. */
 +	G_OBJECT_CLASS (parent_class)->dispose (object);
 +}
 +
 +static void
 +cal_shell_sidebar_finalize (GObject *object)
 +{
 +	ECalShellSidebarPrivate *priv;
 +
 +	priv = E_CAL_SHELL_SIDEBAR_GET_PRIVATE (object);
 +
 +	g_hash_table_destroy (priv->client_table);
 +
 +	/* Chain up to parent's finalize() method. */
 +	G_OBJECT_CLASS (parent_class)->finalize (object);
 +}
 +
 +static void
 +cal_shell_sidebar_constructed (GObject *object)
 +{
 +	ECalShellSidebarPrivate *priv;
 +	EShell *shell;
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	EShellBackend *shell_backend;
 +	EShellSidebar *shell_sidebar;
 +	EShellSettings *shell_settings;
 +	ESourceSelector *selector;
 +	ESourceList *source_list;
 +	ESource *source;
 +	ECalendarItem *calitem;
 +	GConfBridge *bridge;
 +	GtkTreeModel *model;
 +	GtkWidget *container;
 +	GtkWidget *widget;
 +	AtkObject *a11y;
 +	GSList *list, *iter;
 +	const gchar *key;
 +	gchar *uid;
 +
 +	priv = E_CAL_SHELL_SIDEBAR_GET_PRIVATE (object);
 +
 +	/* Chain up to parent's constructed() method. */
 +	G_OBJECT_CLASS (parent_class)->constructed (object);
 +
 +	shell_sidebar = E_SHELL_SIDEBAR (object);
 +	shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
 +	shell_backend = e_shell_view_get_shell_backend (shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	shell = e_shell_window_get_shell (shell_window);
 +	shell_settings = e_shell_get_shell_settings (shell);
 +
 +	source_list = e_cal_shell_backend_get_source_list (
 +		E_CAL_SHELL_BACKEND (shell_backend));
 +
 +	container = GTK_WIDGET (shell_sidebar);
 +
 +	widget = gtk_vpaned_new ();
 +	gtk_container_add (GTK_CONTAINER (container), widget);
 +	priv->paned = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	container = widget;
 +
 +	widget = gtk_scrolled_window_new (NULL, NULL);
 +	gtk_scrolled_window_set_policy (
 +		GTK_SCROLLED_WINDOW (widget),
 +		GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
 +	gtk_scrolled_window_set_shadow_type (
 +		GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
 +	gtk_paned_add1 (GTK_PANED (container), widget);
 +	gtk_widget_show (widget);
 +
 +	container = widget;
 +
 +	widget = e_calendar_selector_new (source_list);
 +	e_source_selector_set_select_new (E_SOURCE_SELECTOR (widget), TRUE);
 +	gtk_container_add (GTK_CONTAINER (container), widget);
 +	a11y = gtk_widget_get_accessible (widget);
 +	atk_object_set_name (a11y, _("Calendar Selector"));
 +	priv->selector = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	container = priv->paned;
 +
 +	widget = e_calendar_new ();
 +	calitem = E_CALENDAR (widget)->calitem;
 +	e_calendar_item_set_days_start_week_sel (calitem, 9);
 +	e_calendar_item_set_max_days_sel (calitem, 42);
 +	gtk_paned_add2 (GTK_PANED (container), widget);
 +	priv->mini_calendar = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	priv->mini_calendar_config =
 +		e_mini_calendar_config_new (E_CALENDAR (widget));
 +
 +	/* Restore the selector state from the last session. */
 +
 +	selector = E_SOURCE_SELECTOR (priv->selector);
 +	model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector));
 +
 +	g_signal_connect_swapped (
 +		model, "row-changed",
 +		G_CALLBACK (cal_shell_sidebar_row_changed_cb),
 +		object);
 +
 +	source = NULL;
 +	uid = e_shell_settings_get_string (
 +		shell_settings, "cal-primary-calendar");
 +	if (uid != NULL)
 +		source = e_source_list_peek_source_by_uid (source_list, uid);
 +	if (source == NULL)
 +		source = e_source_list_peek_source_any (source_list);
 +	if (source != NULL)
 +		e_source_selector_set_primary_selection (selector, source);
 +	g_free (uid);
 +
 +	list = calendar_config_get_calendars_selected ();
 +	for (iter = list; iter != NULL; iter = iter->next) {
 +		uid = iter->data;
 +		source = e_source_list_peek_source_by_uid (source_list, uid);
 +		g_free (uid);
 +
 +		if (source == NULL)
 +			continue;
 +
 +		e_source_selector_select_source (selector, source);
 +	}
 +	g_slist_free (list);
 +
 +	/* Listen for subsequent changes to the selector. */
 +
 +	g_signal_connect_swapped (
 +		selector, "selection-changed",
 +		G_CALLBACK (cal_shell_sidebar_selection_changed_cb),
 +		object);
 +
 +	g_signal_connect_swapped (
 +		selector, "primary-selection-changed",
 +		G_CALLBACK (cal_shell_sidebar_primary_selection_changed_cb),
 +		object);
 +
 +	/* Bind GObject properties to GConf keys. */
 +
 +	bridge = gconf_bridge_get ();
 +
 +	object = G_OBJECT (priv->paned);
 +	key = "/apps/evolution/calendar/display/date_navigator_vpane_position";
 +	gconf_bridge_bind_property_delayed (bridge, key, object, "position");
 +}
 +
 +static void
 +cal_shell_sidebar_client_removed (ECalShellSidebar *cal_shell_sidebar,
 +                                  ECal *client)
 +{
 +	ESourceSelector *selector;
 +	GHashTable *client_table;
 +	ESource *source;
 +	const gchar *uid;
 +
 +	client_table = cal_shell_sidebar->priv->client_table;
 +	selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
 +
 +	g_signal_handlers_disconnect_matched (
 +		client, G_SIGNAL_MATCH_DATA, 0, 0,
 +		NULL, NULL, cal_shell_sidebar);
 +
 +	source = e_cal_get_source (client);
 +	e_source_selector_unselect_source (selector, source);
 +
 +	uid = e_source_peek_uid (source);
 +	g_hash_table_remove (client_table, uid);
 +
 +	cal_shell_sidebar_emit_status_message (cal_shell_sidebar, NULL);
 +}
 +
 +static void
 +cal_shell_sidebar_class_init (ECalShellSidebarClass *class)
 +{
 +	GObjectClass *object_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (ECalShellSidebarPrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->get_property = cal_shell_sidebar_get_property;
 +	object_class->dispose = cal_shell_sidebar_dispose;
 +	object_class->finalize = cal_shell_sidebar_finalize;
 +	object_class->constructed = cal_shell_sidebar_constructed;
 +
 +	class->client_removed = cal_shell_sidebar_client_removed;
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_MINI_CALENDAR,
 +		g_param_spec_object (
 +			"mini-calendar",
 +			_("Mini-Calendar Widget"),
 +			_("This widget displays a miniature calendar"),
 +			E_TYPE_CALENDAR,
 +			G_PARAM_READABLE));
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_SELECTOR,
 +		g_param_spec_object (
 +			"selector",
 +			_("Source Selector Widget"),
 +			_("This widget displays groups of calendars"),
 +			E_TYPE_SOURCE_SELECTOR,
 +			G_PARAM_READABLE));
 +
 +	signals[CLIENT_ADDED] = g_signal_new (
 +		"client-added",
 +		G_OBJECT_CLASS_TYPE (object_class),
 +		G_SIGNAL_RUN_LAST,
 +		G_STRUCT_OFFSET (ECalShellSidebarClass, client_added),
 +		NULL, NULL,
 +		g_cclosure_marshal_VOID__OBJECT,
 +		G_TYPE_NONE, 1,
 +		E_TYPE_CAL);
 +
 +	signals[CLIENT_REMOVED] = g_signal_new (
 +		"client-removed",
 +		G_OBJECT_CLASS_TYPE (object_class),
 +		G_SIGNAL_RUN_LAST,
 +		G_STRUCT_OFFSET (ECalShellSidebarClass, client_removed),
 +		NULL, NULL,
 +		g_cclosure_marshal_VOID__OBJECT,
 +		G_TYPE_NONE, 1,
 +		E_TYPE_CAL);
 +
 +	signals[STATUS_MESSAGE] = g_signal_new (
 +		"status-message",
 +		G_OBJECT_CLASS_TYPE (object_class),
 +		G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
 +		G_STRUCT_OFFSET (ECalShellSidebarClass, status_message),
 +		NULL, NULL,
 +		g_cclosure_marshal_VOID__STRING,
 +		G_TYPE_NONE, 1,
 +		G_TYPE_STRING);
 +}
 +
 +static void
 +cal_shell_sidebar_init (ECalShellSidebar *cal_shell_sidebar)
 +{
 +	GHashTable *client_table;
 +
 +	client_table = g_hash_table_new_full (
 +		g_str_hash, g_str_equal,
 +		(GDestroyNotify) g_free,
 +		(GDestroyNotify) g_object_unref);
 +
 +	cal_shell_sidebar->priv =
 +		E_CAL_SHELL_SIDEBAR_GET_PRIVATE (cal_shell_sidebar);
 +
 +	cal_shell_sidebar->priv->client_table = client_table;
 +
 +	/* Postpone widget construction until we have a shell view. */
 +}
 +
 +GType
 +e_cal_shell_sidebar_get_type (void)
 +{
 +	return cal_shell_sidebar_type;
 +}
 +
 +void
 +e_cal_shell_sidebar_register_type (GTypeModule *type_module)
 +{
 +	static const GTypeInfo type_info = {
 +		sizeof (ECalShellSidebarClass),
 +		(GBaseInitFunc) NULL,
 +		(GBaseFinalizeFunc) NULL,
 +		(GClassInitFunc) cal_shell_sidebar_class_init,
 +		(GClassFinalizeFunc) NULL,
 +		NULL,  /* class_data */
 +		sizeof (ECalShellSidebar),
 +		0,     /* n_preallocs */
 +		(GInstanceInitFunc) cal_shell_sidebar_init,
 +		NULL   /* value_table */
 +	};
 +
 +	cal_shell_sidebar_type = g_type_module_register_type (
 +		type_module, E_TYPE_SHELL_SIDEBAR,
 +		"ECalShellSidebar", &type_info, 0);
 +}
 +
 +GtkWidget *
 +e_cal_shell_sidebar_new (EShellView *shell_view)
 +{
 +	g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
 +
 +	return g_object_new (
 +		E_TYPE_CAL_SHELL_SIDEBAR,
 +		"shell-view", shell_view, NULL);
 +}
 +
 +GList *
 +e_cal_shell_sidebar_get_clients (ECalShellSidebar *cal_shell_sidebar)
 +{
 +	GHashTable *client_table;
 +
 +	g_return_val_if_fail (
 +		E_IS_CAL_SHELL_SIDEBAR (cal_shell_sidebar), NULL);
 +
 +	client_table = cal_shell_sidebar->priv->client_table;
 +
 +	return g_hash_table_get_values (client_table);
 +}
 +
 +ECalendar *
 +e_cal_shell_sidebar_get_mini_calendar (ECalShellSidebar *cal_shell_sidebar)
 +{
 +	g_return_val_if_fail (
 +		E_IS_CAL_SHELL_SIDEBAR (cal_shell_sidebar), NULL);
 +
 +	return E_CALENDAR (cal_shell_sidebar->priv->mini_calendar);
 +}
 +
 +ESourceSelector *
 +e_cal_shell_sidebar_get_selector (ECalShellSidebar *cal_shell_sidebar)
 +{
 +	g_return_val_if_fail (
 +		E_IS_CAL_SHELL_SIDEBAR (cal_shell_sidebar), NULL);
 +
 +	return E_SOURCE_SELECTOR (cal_shell_sidebar->priv->selector);
 +}
 +
 +void
 +e_cal_shell_sidebar_add_source (ECalShellSidebar *cal_shell_sidebar,
 +                                ESource *source)
 +{
 +	ESourceSelector *selector;
 +	GHashTable *client_table;
 +	ECal *client;
 +	const gchar *uid;
 +	const gchar *uri;
 +	gchar *message;
 +
 +	g_return_if_fail (E_IS_CAL_SHELL_SIDEBAR (cal_shell_sidebar));
 +	g_return_if_fail (E_IS_SOURCE (source));
 +
 +	client_table = cal_shell_sidebar->priv->client_table;
 +	selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
 +
 +	uid = e_source_peek_uid (source);
 +	client = g_hash_table_lookup (client_table, uid);
 +
 +	if (client != NULL)
 +		return;
 +
 +	client = auth_new_cal_from_source (source, E_CAL_SOURCE_TYPE_EVENT);
 +	g_return_if_fail (client != NULL);
 +
 +	g_signal_connect_swapped (
 +		client, "backend-died",
 +		G_CALLBACK (cal_shell_sidebar_backend_died_cb),
 +		cal_shell_sidebar);
 +
 +	g_signal_connect_swapped (
 +		client, "backend-error",
 +		G_CALLBACK (cal_shell_sidebar_backend_error_cb),
 +		cal_shell_sidebar);
 +
 +	g_hash_table_insert (client_table, g_strdup (uid), client);
 +	e_source_selector_select_source (selector, source);
 +
 +	uri = e_cal_get_uri (client);
 +	message = g_strdup_printf (_("Opening calendar at %s"), uri);
 +	cal_shell_sidebar_emit_status_message (cal_shell_sidebar, message);
 +	g_free (message);
 +
 +	g_signal_connect_swapped (
 +		client, "cal-opened",
 +		G_CALLBACK (cal_shell_sidebar_client_opened_cb),
 +		cal_shell_sidebar);
 +
 +	e_cal_open_async (client, FALSE);
 +}
 +
 +void
 +e_cal_shell_sidebar_remove_source (ECalShellSidebar *cal_shell_sidebar,
 +                                   ESource *source)
 +{
 +	ESourceSelector *selector;
 +	GHashTable *client_table;
 +	ECal *client;
 +	const gchar *uid;
 +
 +	g_return_if_fail (E_IS_CAL_SHELL_SIDEBAR (cal_shell_sidebar));
 +	g_return_if_fail (E_IS_SOURCE (source));
 +
 +	client_table = cal_shell_sidebar->priv->client_table;
 +	selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
 +
 +	uid = e_source_peek_uid (source);
 +	client = g_hash_table_lookup (client_table, uid);
 +
 +	if (client == NULL)
 +		return;
 +
 +	cal_shell_sidebar_emit_client_removed (cal_shell_sidebar, client);
 +}
diff --cc calendar/module/e-cal-shell-sidebar.h
index d4e881a,0000000..c555537
mode 100644,000000..100644
--- a/calendar/module/e-cal-shell-sidebar.h
+++ b/calendar/module/e-cal-shell-sidebar.h
@@@ -1,101 -1,0 +1,101 @@@
 +/*
 + * e-cal-shell-sidebar.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_CAL_SHELL_SIDEBAR_H
 +#define E_CAL_SHELL_SIDEBAR_H
 +
 +#include <libecal/e-cal.h>
 +#include <libedataserverui/e-source-selector.h>
 +
 +#include <shell/e-shell-sidebar.h>
 +#include <shell/e-shell-view.h>
 +#include <misc/e-calendar.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_CAL_SHELL_SIDEBAR \
 +	(e_cal_shell_sidebar_get_type ())
 +#define E_CAL_SHELL_SIDEBAR(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_CAL_SHELL_SIDEBAR, ECalShellSidebar))
 +#define E_CAL_SHELL_SIDEBAR_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_CAL_SHELL_SIDEBAR, ECalShellSidebarClass))
 +#define E_IS_CAL_SHELL_SIDEBAR(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_CAL_SHELL_SIDEBAR))
 +#define E_IS_CAL_SHELL_SIDEBAR_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), E_TYPE_CAL_SHELL_SIDEBAR))
 +#define E_CAL_SHELL_SIDEBAR_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_CAL_SHELL_SIDEBAR, ECalShellSidebarClass))
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _ECalShellSidebar ECalShellSidebar;
 +typedef struct _ECalShellSidebarClass ECalShellSidebarClass;
 +typedef struct _ECalShellSidebarPrivate ECalShellSidebarPrivate;
 +
 +enum {
 +	E_CAL_SHELL_SIDEBAR_HAS_PRIMARY_SOURCE		= 1 << 0,
 +	E_CAL_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_EMPTY	= 1 << 1,
 +	E_CAL_SHELL_SIDEBAR_SOURCE_CAN_GO_OFFLINE	= 1 << 2,
 +	E_CAL_SHELL_SIDEBAR_SOURCE_CAN_DELETE		= 1 << 3
 +};
 +
 +struct _ECalShellSidebar {
 +	EShellSidebar parent;
 +	ECalShellSidebarPrivate *priv;
 +};
 +
 +struct _ECalShellSidebarClass {
 +	EShellSidebarClass parent_class;
 +
 +	/* Signals */
 +	void	(*client_added)			(ECalShellSidebar *cal_shell_sidebar,
 +						 ECal *client);
 +	void	(*client_removed)		(ECalShellSidebar *cal_shell_sidebar,
 +						 ECal *client);
 +	void	(*status_message)		(ECalShellSidebar *cal_shell_sidebar,
 +						 const gchar *status_message);
 +};
 +
 +GType		e_cal_shell_sidebar_get_type	(void);
 +void		e_cal_shell_sidebar_register_type
 +					(GTypeModule *type_module);
 +GtkWidget *	e_cal_shell_sidebar_new	(EShellView *shell_view);
 +GList *		e_cal_shell_sidebar_get_clients
 +					(ECalShellSidebar *cal_shell_sidebar);
 +ECalendar *	e_cal_shell_sidebar_get_mini_calendar
 +					(ECalShellSidebar *cal_shell_sidebar);
 +ESourceSelector *
 +		e_cal_shell_sidebar_get_selector
 +					(ECalShellSidebar *cal_shell_sidebar);
 +void		e_cal_shell_sidebar_add_source
 +					(ECalShellSidebar *cal_shell_sidebar,
 +					 ESource *source);
 +void		e_cal_shell_sidebar_remove_source
 +					(ECalShellSidebar *cal_shell_sidebar,
 +					 ESource *source);
 +
 +G_END_DECLS
 +
 +#endif /* E_CAL_SHELL_SIDEBAR_H */
diff --cc calendar/module/e-cal-shell-view-actions.c
index 53898ff,0000000..a5d0dd8
mode 100644,000000..100644
--- a/calendar/module/e-cal-shell-view-actions.c
+++ b/calendar/module/e-cal-shell-view-actions.c
@@@ -1,1173 -1,0 +1,1173 @@@
 +/*
 + * e-cal-shell-view-actions.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-cal-shell-view-private.h"
 +
 +static void
 +action_calendar_copy_cb (GtkAction *action,
 +                         ECalShellView *cal_shell_view)
 +{
 +	ECalShellSidebar *cal_shell_sidebar;
 +	EShellWindow *shell_window;
 +	EShellView *shell_view;
 +	ESourceSelector *selector;
 +	ESource *source;
 +
 +	shell_view = E_SHELL_VIEW (cal_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	cal_shell_sidebar = cal_shell_view->priv->cal_shell_sidebar;
 +	selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
 +	source = e_source_selector_peek_primary_selection (selector);
 +	g_return_if_fail (E_IS_SOURCE (source));
 +
 +	copy_source_dialog (
 +		GTK_WINDOW (shell_window),
 +		source, E_CAL_SOURCE_TYPE_EVENT);
 +}
 +
 +static void
 +action_calendar_delete_cb (GtkAction *action,
 +                           ECalShellView *cal_shell_view)
 +{
 +#if 0
 +	ECalShellContent *cal_shell_content;
 +	ECalShellSidebar *cal_shell_sidebar;
 +	EShellWindow *shell_window;
 +	EShellView *shell_view;
 +	ECalendarView *calendar_view;
 +	GnomeCalendarViewType view_type;
 +	ECalModel *model;
 +	ESourceSelector *selector;
 +	ESourceGroup *source_group;
 +	ESourceList *source_list;
 +	ESource *source;
 +	gint response;
 +	gchar *uri;
 +	GError *error = NULL;
 +
 +	shell_view = E_SHELL_VIEW (cal_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	cal_shell_content = cal_shell_content->priv->cal_shell_content;
 +	view_type = e_cal_shell_content_get_current_view (cal_shell_content);
 +	calendar_view = e_cal_shell_content_get_calendar_view (
 +		cal_shell_content, view_type);
 +	model = e_calendar_view_get_model (calendar_view);
 +
 +	cal_shell_sidebar = cal_shell_sidebar->priv->cal_shell_sidebar;
 +	selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
 +	source = e_source_selector_peek_primary_selection (selector);
 +	g_return_if_fail (E_IS_SOURCE (source));
 +
 +	/* Ask for confirmation. */
 +	response = e_error_run (
 +		GTK_WINDOW (shell_window),
 +		"calendar:prompt-delete-calendar",
 +		e_source_peek_name (source));
 +	if (response != GTK_RESPONSE_YES)
 +		return;
 +
 +	uri = e_source_get_uri (source);
 +	client = e_cal_model_get_client_for_uri (model, uri);
 +	if (client == NULL)
 +		client = e_cal_new_from_uri (uri, E_CAL_SOURCE_TYPE_EVENT);
 +	g_free (uri);
 +
 +	g_return_if_fail (client != NULL);
 +
 +	if (!e_cal_remove (client, &error)) {
 +		g_warning ("%s", error->message);
 +		g_error_free (error);
 +		return;
 +	}
 +
 +	if (e_source_selector_source_is_selected (selector, source)) {
 +		e_cal_shell_sidebar_remove_source (
 +			cal_shell_sidebar, source);
 +		e_source_selector_unselect_source (selector, source);
 +	}
 +
 +	source_group = e_source_peek_group (source);
 +	e_source_group_remove_source (source_group, source);
 +
 +	source_list = cal_shell_view->priv->source_list;
 +	if (!e_source_list_sync (source_list, &error)) {
 +		g_warning ("%s", error->message);
 +		g_error_free (error);
 +	}
 +#endif
 +}
 +
 +static void
 +action_calendar_go_back_cb (GtkAction *action,
 +                            ECalShellView *cal_shell_view)
 +{
- #if 0 
++#if 0
 +	ECalShellContent *cal_shell_content;
 +	GnomeCalendar *calendar;
 +
 +	cal_shell_content = cal_shell_view->priv->cal_shell_content;
 +	calendar = e_cal_shell_content_get_calendar (cal_shell_content);
 +
 +	gnome_calendar_previous (calendar);
 +#endif
 +}
 +
 +static void
 +action_calendar_go_forward_cb (GtkAction *action,
 +                               ECalShellView *cal_shell_view)
 +{
 +#if 0
 +	ECalShellContent *cal_shell_content;
 +	GnomeCalendar *calendar;
 +
 +	cal_shell_content = cal_shell_view->priv->cal_shell_content;
 +	calendar = e_cal_shell_content_get_calendar (cal_shell_content);
 +
 +	gnome_calendar_next (calendar);
 +#endif
 +}
 +
 +static void
 +action_calendar_go_today_cb (GtkAction *action,
 +                             ECalShellView *cal_shell_view)
 +{
 +#if 0
 +	ECalShellContent *cal_shell_content;
 +	GnomeCalendar *calendar;
 +
 +	cal_shell_content = cal_shell_view->priv->cal_shell_content;
 +	calendar = e_cal_shell_content_get_calendar (cal_shell_content);
 +
 +	gnome_calendar_goto_today (calendar);
 +#endif
 +}
 +
 +static void
 +action_calendar_jump_to_cb (GtkAction *action,
 +                            ECalShellView *cal_shell_view)
 +{
 +#if 0
 +	ECalShellContent *cal_shell_content;
 +	GnomeCalendar *calendar;
 +
 +	cal_shell_content = cal_shell_view->priv->cal_shell_content;
 +	calendar = e_cal_shell_content_get_calendar (cal_shell_content);
 +
 +	goto_dialog (calendar);
 +#endif
 +}
 +
 +static void
 +action_calendar_new_cb (GtkAction *action,
 +                        ECalShellView *cal_shell_view)
 +{
 +#if 0
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +
 +	shell_view = E_SHELL_VIEW (cal_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +	calendar_setup_new_calendar (GTK_WINDOW (shell_window));
 +#endif
 +}
 +
 +static void
 +action_calendar_print_cb (GtkAction *action,
 +                          ECalShellView *cal_shell_view)
 +{
 +#if 0
 +	ECalShellContent *cal_shell_content;
 +	GnomeCalendar *calendar;
 +	GtkPrintOperationAction print_action;
 +
 +	cal_shell_content = cal_shell_view->priv->cal_shell_content;
 +	calendar = e_cal_shell_content_get_calendar (cal_shell_content);
 +	print_action = GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG;
 +
 +	if (gnome_calendar_get_view (calendar) == GNOME_CAL_LIST_VIEW) {
 +		ECalListView *list_view;
 +		GtkWidget *widget;
 +		ETable *table;
 +
 +		widget = gnome_calendar_get_current_view_widget (calendar);
 +		list_view = E_CAL_LIST_VIEW (widget);
 +		table = e_table_scrolled_get_table (list_view->table_scrolled);
 +		print_table (table, _("Print"), _("Calendar"), action);
 +	} else {
 +		time_t start;
 +
 +		gnome_calendar_get_current_time_range (calendar, &start, NULL);
 +		print_calendar (calendar, action, start);
 +	}
 +#endif
 +}
 +
 +static void
 +action_calendar_print_preview_cb (GtkAction *action,
 +                                  ECalShellView *cal_shell_view)
 +{
 +#if 0
 +	ECalShellContent *cal_shell_content;
 +	GnomeCalendar *calendar;
 +	GtkPrintOperationAction print_action;
 +
 +	cal_shell_content = cal_shell_view->priv->cal_shell_content;
 +	calendar = e_cal_shell_content_get_calendar (cal_shell_content);
 +	print_action = GTK_PRINT_OPERATION_ACTION_PREVIEW;
 +
 +	if (gnome_calendar_get_view (calendar) == GNOME_CAL_LIST_VIEW) {
 +		ECalListView *list_view;
 +		GtkWidget *widget;
 +		ETable *table;
 +
 +		widget = gnome_calendar_get_current_view_widget (calendar);
 +		list_view = E_CAL_LIST_VIEW (widget);
 +		table = e_table_scrolled_get_table (list_view->table_scrolled);
 +		print_table (table, _("Print"), _("Calendar"), action);
 +	} else {
 +		time_t start;
 +
 +		gnome_calendar_get_current_time_range (calendar, &start, NULL);
 +		print_calendar (calendar, action, start);
 +	}
 +#endif
 +}
 +
 +static void
 +action_calendar_properties_cb (GtkAction *action,
 +                               ECalShellView *cal_shell_view)
 +{
 +#if 0
 +	ECalShellSidebar *cal_shell_sidebar;
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	ESource *source;
 +	ESourceSelector *selector;
 +
 +	shell_view = E_SHELL_VIEW (cal_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	cal_shell_sidebar = cal_shell_view->priv->cal_shell_sidebar;
 +	selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
 +	source = e_source_selector_peek_primary_selection (selector);
 +	g_return_if_fail (E_IS_SOURCE (source));
 +
 +	calendar_setup_edit_calendar (GTK_WINDOW (shell_window), source);
 +#endif
 +}
 +
 +static void
 +action_calendar_purge_cb (GtkAction *action,
 +                          ECalShellView *cal_shell_view)
 +{
 +	/* FIXME */
 +}
 +
 +static void
 +action_calendar_rename_cb (GtkAction *action,
 +                           ECalShellView *cal_shell_view)
 +{
 +	ECalShellSidebar *cal_shell_sidebar;
 +	ESourceSelector *selector;
 +
 +	cal_shell_sidebar = cal_shell_view->priv->cal_shell_sidebar;
 +	selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
 +
 +	e_source_selector_edit_primary_selection (selector);
 +}
 +
 +static void
 +action_calendar_select_one_cb (GtkAction *action,
 +                               ECalShellView *cal_shell_view)
 +{
 +	ECalShellSidebar *cal_shell_sidebar;
 +	ESourceSelector *selector;
 +	ESource *primary;
 +	GSList *list, *iter;
 +
 +	/* XXX ESourceSelector should provide a function for this. */
 +
 +	cal_shell_sidebar = cal_shell_view->priv->cal_shell_sidebar;
 +	selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
 +	primary = e_source_selector_peek_primary_selection (selector);
 +	g_return_if_fail (primary != NULL);
 +
 +	list = e_source_selector_get_selection (selector);
 +	for (iter = list; iter != NULL; iter = iter->next) {
 +		ESource *source = iter->data;
 +
 +		if (source == primary)
 +			continue;
 +
 +		e_source_selector_unselect_source (selector, source);
 +	}
 +	e_source_selector_free_selection (list);
 +
 +	e_source_selector_select_source (selector, primary);
 +}
 +
 +static void
 +action_calendar_view_cb (GtkRadioAction *action,
 +                         GtkRadioAction *current,
 +                         ECalShellView *cal_shell_view)
 +{
 +	EShellView *shell_view;
 +	GnomeCalendarViewType view_type;
 +	const gchar *view_id;
 +
 +	shell_view = E_SHELL_VIEW (cal_shell_view);
 +	view_type = gtk_radio_action_get_current_value (action);
 +
 +	switch (view_type) {
 +		case GNOME_CAL_DAY_VIEW:
 +			view_id = "Day_View";
 +			break;
 +
 +		case GNOME_CAL_WORK_WEEK_VIEW:
 +			view_id = "Work_Week_View";
 +			break;
 +
 +		case GNOME_CAL_WEEK_VIEW:
 +			view_id = "Week_View";
 +			break;
 +
 +		case GNOME_CAL_MONTH_VIEW:
 +			view_id = "Month_View";
 +			break;
 +
 +		case GNOME_CAL_LIST_VIEW:
 +			view_id = "List_View";
 +			break;
 +
 +		default:
 +			g_return_if_reached ();
 +	}
 +
 +	e_shell_view_set_view_id (shell_view, view_id);
 +}
 +
 +static void
 +action_event_all_day_new_cb (GtkAction *action,
 +                             ECalShellView *cal_shell_view)
 +{
 +        /* FIXME */
 +}
 +
 +static void
 +action_event_clipboard_copy_cb (GtkAction *action,
 +                                ECalShellView *cal_shell_view)
 +{
 +	ECalShellContent *cal_shell_content;
 +
 +	cal_shell_content = cal_shell_view->priv->cal_shell_content;
 +	e_cal_shell_content_copy_clipboard (cal_shell_content);
 +}
 +
 +static void
 +action_event_clipboard_cut_cb (GtkAction *action,
 +                               ECalShellView *cal_shell_view)
 +{
 +	ECalShellContent *cal_shell_content;
 +
 +	cal_shell_content = cal_shell_view->priv->cal_shell_content;
 +	e_cal_shell_content_cut_clipboard (cal_shell_content);
 +}
 +
 +static void
 +action_event_clipboard_paste_cb (GtkAction *action,
 +                                 ECalShellView *cal_shell_view)
 +{
 +	ECalShellContent *cal_shell_content;
 +
 +	cal_shell_content = cal_shell_view->priv->cal_shell_content;
 +	e_cal_shell_content_paste_clipboard (cal_shell_content);
 +}
 +
 +static void
 +action_event_copy_cb (GtkAction *action,
 +                      ECalShellView *cal_shell_view)
 +{
 +	/* FIXME */
 +}
 +
 +static void
 +action_event_delegate_cb (GtkAction *action,
 +                          ECalShellView *cal_shell_view)
 +{
 +	/* FIXME */
 +}
 +
 +static void
 +action_event_delete_cb (GtkAction *action,
 +                        ECalShellView *cal_shell_view)
 +{
 +	ECalShellContent *cal_shell_content;
 +
 +	cal_shell_content = cal_shell_view->priv->cal_shell_content;
 +	e_cal_shell_content_delete_selection (cal_shell_content);
 +}
 +
 +static void
 +action_event_delete_occurrence_cb (GtkAction *action,
 +                                   ECalShellView *cal_shell_view)
 +{
 +	ECalShellContent *cal_shell_content;
 +
 +	cal_shell_content = cal_shell_view->priv->cal_shell_content;
 +	e_cal_shell_content_delete_selected_occurrence (cal_shell_content);
 +}
 +
 +static void
 +action_event_delete_occurrence_all_cb (GtkAction *action,
 +                                       ECalShellView *cal_shell_view)
 +{
 +	ECalShellContent *cal_shell_content;
 +
 +	/* XXX Same as "event-delete". */
 +	cal_shell_content = cal_shell_view->priv->cal_shell_content;
 +	e_cal_shell_content_delete_selection (cal_shell_content);
 +}
 +
 +static void
 +action_event_forward_cb (GtkAction *action,
 +                         ECalShellView *cal_shell_view)
 +{
 +	/* FIXME */
 +}
 +
 +static void
 +action_event_meeting_new_cb (GtkAction *action,
 +                             ECalShellView *cal_shell_view)
 +{
 +        /* FIXME */
 +}
 +
 +static void
 +action_event_move_cb (GtkAction *action,
 +                      ECalShellView *cal_shell_view)
 +{
 +	/* FIXME */
 +}
 +
 +static void
 +action_event_new_cb (GtkAction *action,
 +                     ECalShellView *cal_shell_view)
 +{
 +        /* FIXME */
 +}
 +
 +static void
 +action_event_occurrence_movable_cb (GtkAction *action,
 +                                    ECalShellView *cal_shell_view)
 +{
 +	/* FIXME */
 +}
 +
 +static void
 +action_event_open_cb (GtkAction *action,
 +                      ECalShellView *cal_shell_view)
 +{
 +#if 0
 +	ECalShellContent *cal_shell_content;
 +	GnomeCalendar *calendar;
 +	GtkWidget *widget;
 +
 +	cal_shell_content = cal_shell_view->priv->cal_shell_content;
 +	calendar = e_cal_shell_content_get_calendar (cal_shell_content);
 +	widget = gnome_calendar_get_current_view_widget (calendar);
 +
 +	e_calendar_view_open_event (E_CALENDAR_VIEW (widget));
 +#endif
 +}
 +
 +static void
 +action_event_print_cb (GtkAction *action,
 +                       ECalShellView *cal_shell_view)
 +{
 +	/* FIXME */
 +}
 +
 +static void
 +action_event_reply_cb (GtkAction *action,
 +                       ECalShellView *cal_shell_view)
 +{
 +	/* FIXME */
 +}
 +
 +static void
 +action_event_reply_all_cb (GtkAction *action,
 +                           ECalShellView *cal_shell_view)
 +{
 +	/* FIXME */
 +}
 +
 +static void
 +action_event_save_as_cb (GtkAction *action,
 +                         ECalShellView *cal_shell_view)
 +{
 +	/* FIXME */
 +}
 +
 +static void
 +action_event_schedule_cb (GtkAction *action,
 +                          ECalShellView *cal_shell_view)
 +{
 +	/* FIXME */
 +}
 +
 +static void
 +action_gal_save_custom_view_cb (GtkAction *action,
 +                                ECalShellView *cal_shell_view)
 +{
 +	ECalShellContent *cal_shell_content;
 +	EShellView *shell_view;
 +	GalViewInstance *view_instance;
 +
 +	/* All shell views respond to the activation of this action,
 +	 * which is defined by EShellWindow.  But only the currently
 +	 * active shell view proceeds with saving the custom view. */
 +	shell_view = E_SHELL_VIEW (cal_shell_view);
 +	if (!e_shell_view_is_active (shell_view))
 +		return;
 +
 +	cal_shell_content = cal_shell_view->priv->cal_shell_content;
 +	view_instance = e_cal_shell_content_get_view_instance (cal_shell_content);
 +	gal_view_instance_save_as (view_instance);
 +}
 +
 +static void
 +action_search_execute_cb (GtkAction *action,
 +                          ECalShellView *cal_shell_view)
 +{
 +	EShellView *shell_view;
 +
 +	/* All shell views respond to the activation of this action,
 +	 * which is defined by EShellWindow.  But only the currently
 +	 * active shell view proceeds with executing the search. */
 +	shell_view = E_SHELL_VIEW (cal_shell_view);
 +	if (!e_shell_view_is_active (shell_view))
 +		return;
 +
 +	e_cal_shell_view_execute_search (cal_shell_view);
 +}
 +
 +static void
 +action_search_filter_cb (GtkRadioAction *action,
 +                         GtkRadioAction *current,
 +                         ECalShellView *cal_shell_view)
 +{
 +	e_cal_shell_view_execute_search (cal_shell_view);
 +}
 +
 +static GtkActionEntry calendar_entries[] = {
 +
 +	{ "calendar-copy",
 +	  GTK_STOCK_COPY,
 +	  N_("_Copy..."),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  G_CALLBACK (action_calendar_copy_cb) },
 +
 +	{ "calendar-delete",
 +	  GTK_STOCK_DELETE,
 +	  NULL,
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  G_CALLBACK (action_calendar_delete_cb) },
 +
 +	{ "calendar-go-back",
 +	  GTK_STOCK_GO_BACK,
 +	  N_("Previous"),
 +	  NULL,
 +	  N_("Go Back"),
 +	  G_CALLBACK (action_calendar_go_back_cb) },
 +
 +	{ "calendar-go-forward",
 +	  GTK_STOCK_GO_FORWARD,
 +	  N_("Next"),
 +	  NULL,
 +	  N_("Go Forward"),
 +	  G_CALLBACK (action_calendar_go_forward_cb) },
 +
 +	{ "calendar-go-today",
 +	  "go-today",
 +	  N_("Select _Today"),
 +	  "<Control>t",
 +	  N_("Select today"),
 +	  G_CALLBACK (action_calendar_go_today_cb) },
 +
 +	{ "calendar-jump-to",
 +	  GTK_STOCK_JUMP_TO,
 +	  N_("Select _Date"),
 +	  "<Control>g",
 +	  N_("Select a specific date"),
 +	  G_CALLBACK (action_calendar_jump_to_cb) },
 +
 +	{ "calendar-new",
 +	  "x-office-calendar",
 +	  N_("_New Calendar"),
 +	  NULL,
 +	  N_("Create a new calendar"),
 +	  G_CALLBACK (action_calendar_new_cb) },
 +
 +	{ "calendar-properties",
 +	  GTK_STOCK_PROPERTIES,
 +	  NULL,
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  G_CALLBACK (action_calendar_properties_cb) },
 +
 +	{ "calendar-purge",
 +	  NULL,
 +	  N_("Purg_e"),
 +	  "<Control>e",
 +	  N_("Purge old appointments and meetings"),
 +	  G_CALLBACK (action_calendar_purge_cb) },
 +
 +	{ "calendar-rename",
 +	  NULL,
 +	  N_("_Rename..."),
 +	  "F2",
 +	  N_("Rename the selected calendar"),
 +	  G_CALLBACK (action_calendar_rename_cb) },
 +
 +	{ "calendar-select-one",
 +	  "stock_check-filled",
 +	  N_("Show _Only This Calendar"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  G_CALLBACK (action_calendar_select_one_cb) },
 +
 +	{ "event-clipboard-copy",
 +	  GTK_STOCK_COPY,
 +	  NULL,
 +	  NULL,
 +	  N_("Copy the selection"),
 +	  G_CALLBACK (action_event_clipboard_copy_cb) },
 +
 +	{ "event-clipboard-cut",
 +	  GTK_STOCK_CUT,
 +	  NULL,
 +	  NULL,
 +	  N_("Cut the selection"),
 +	  G_CALLBACK (action_event_clipboard_cut_cb) },
 +
 +	{ "event-clipboard-paste",
 +	  GTK_STOCK_PASTE,
 +	  NULL,
 +	  NULL,
 +	  N_("Paste the clipboard"),
 +	  G_CALLBACK (action_event_clipboard_paste_cb) },
 +
 +	{ "event-copy",
 +	  NULL,
 +	  N_("Cop_y to Calendar..."),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  G_CALLBACK (action_event_copy_cb) },
 +
 +	{ "event-delegate",
 +	  NULL,
 +	  N_("_Delegate Meeting..."),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  G_CALLBACK (action_event_delegate_cb) },
 +
 +	{ "event-delete",
 +	  GTK_STOCK_DELETE,
 +	  NULL,
 +	  NULL,
 +	  N_("Delete the appointment"),
 +	  G_CALLBACK (action_event_delete_cb) },
 +
 +	{ "event-delete-occurrence",
 +	  GTK_STOCK_DELETE,
 +	  N_("Delete This _Occurrence"),
 +	  NULL,
 +	  N_("Delete this occurrence"),
 +	  G_CALLBACK (action_event_delete_occurrence_cb) },
 +
 +	{ "event-delete-occurrence-all",
 +	  GTK_STOCK_DELETE,
 +	  N_("Delete _All Occurrences"),
 +	  NULL,
 +	  N_("Delete all occurrences"),
 +	  G_CALLBACK (action_event_delete_occurrence_all_cb) },
 +
 +	{ "event-all-day-new",
 +	  NULL,
 +	  N_("New All Day _Event..."),
 +	  NULL,
 +	  N_("Create a new all day event"),
 +	  G_CALLBACK (action_event_all_day_new_cb) },
 +
 +	{ "event-forward",
 +	  "mail-forward",
 +	  N_("_Forward as iCalendar..."),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  G_CALLBACK (action_event_forward_cb) },
 +
 +	{ "event-meeting-new",
 +	  NULL,
 +	  N_("New _Meeting..."),
 +	  NULL,
 +	  N_("Create a new meeting"),
 +	  G_CALLBACK (action_event_meeting_new_cb) },
 +
 +	{ "event-move",
 +	  NULL,
 +	  N_("Mo_ve to Calendar..."),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  G_CALLBACK (action_event_move_cb) },
 +
 +	{ "event-new",
 +	  NULL,
 +	  N_("New _Appointment..."),
 +	  NULL,
 +	  N_("Create a new appointment"),
 +	  G_CALLBACK (action_event_new_cb) },
 +
 +	{ "event-occurrence-movable",
 +	  NULL,
 +	  N_("Make this Occurrence _Movable"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  G_CALLBACK (action_event_occurrence_movable_cb) },
 +
 +	{ "event-open",
 +	  NULL,
 +	  N_("_Open Appointment"),
 +	  "<Control>o",
 +	  N_("View the current appointment"),
 +	  G_CALLBACK (action_event_open_cb) },
 +
 +	{ "event-reply",
 +	  "mail-reply-sender",
 +	  N_("_Reply"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  G_CALLBACK (action_event_reply_cb) },
 +
 +	{ "event-reply-all",
 +	  "mail-reply-all",
 +	  N_("Reply to _All"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  G_CALLBACK (action_event_reply_all_cb) },
 +
 +	{ "event-save-as",
 +	  GTK_STOCK_SAVE_AS,
 +	  NULL,
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  G_CALLBACK (action_event_save_as_cb) },
 +
 +	{ "event-schedule",
 +	  NULL,
 +	  N_("_Schedule Meeting..."),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  G_CALLBACK (action_event_schedule_cb) },
 +
 +	/*** Menus ***/
 +
 +	{ "calendar-actions-menu",
 +	  NULL,
 +	  N_("_Actions"),
 +	  NULL,
 +	  NULL,
 +	  NULL }
 +};
 +
 +static EPopupActionEntry calendar_popup_entries[] = {
 +
 +	/* FIXME No equivalent main menu items for the any of the calendar
 +	 *       popup menu items and for many of the event popup menu items.
 +	 *       This is an accessibility issue. */
 +
 +	{ "calendar-popup-copy",
 +	  NULL,
 +	  "calendar-copy" },
 +
 +	{ "calendar-popup-delete",
 +	  NULL,
 +	  "calendar-delete" },
 +
 +	{ "calendar-popup-go-today",
 +	  NULL,
 +	  "calendar-go-today" },
 +
 +	{ "calendar-popup-jump-to",
 +	  NULL,
 +	  "calendar-jump-to" },
 +
 +	{ "calendar-popup-properties",
 +	  NULL,
 +	  "calendar-properties" },
 +
 +	{ "calendar-popup-rename",
 +	  NULL,
 +	  "calendar-rename" },
 +
 +	{ "calendar-popup-select-one",
 +	  NULL,
 +	  "calendar-select-one" },
 +
 +	{ "event-popup-clipboard-copy",
 +	  NULL,
 +	  "event-clipboard-copy" },
 +
 +	{ "event-popup-clipboard-cut",
 +	  NULL,
 +	  "event-clipboard-cut" },
 +
 +	{ "event-popup-clipboard-paste",
 +	  NULL,
 +	  "event-clipboard-paste" },
 +
 +	{ "event-popup-copy",
 +	  NULL,
 +	  "event-copy" },
 +
 +	{ "event-popup-delegate",
 +	  NULL,
 +	  "event-delegate" },
 +
 +	{ "event-popup-delete",
 +	  NULL,
 +	  "event-delete" },
 +
 +	{ "event-popup-delete-occurrence",
 +	  NULL,
 +	  "event-delete-occurrence" },
 +
 +	{ "event-popup-delete-occurrence-all",
 +	  NULL,
 +	  "event-delete-occurrence-all" },
 +
 +	{ "event-popup-forward",
 +	  NULL,
 +	  "event-forward" },
 +
 +	{ "event-popup-move",
 +	  NULL,
 +	  "event-move" },
 +
 +	{ "event-popup-occurrence-movable",
 +	  NULL,
 +	  "event-occurrence-movable" },
 +
 +	{ "event-popup-open",
 +	  NULL,
 +	  "event-open" },
 +
 +	{ "event-popup-reply",
 +	  NULL,
 +	  "event-reply" },
 +
 +	{ "event-popup-reply-all",
 +	  NULL,
 +	  "event-reply-all" },
 +
 +	{ "event-popup-save-as",
 +	  NULL,
 +	  "event-save-as" },
 +
 +	{ "event-popup-schedule",
 +	  NULL,
 +	  "event-schedule" }
 +};
 +
 +static GtkRadioActionEntry calendar_view_entries[] = {
 +
 +	{ "calendar-view-day",
 +	  "view-calendar-day",
 +	  N_("Day"),
 +	  NULL,
 +	  N_("Show one day"),
 +	  GNOME_CAL_DAY_VIEW },
 +
 +	{ "calendar-view-list",
 +	  "view-calendar-list",
 +	  N_("List"),
 +	  NULL,
 +	  N_("Show as list"),
 +	  GNOME_CAL_LIST_VIEW },
 +
 +	{ "calendar-view-month",
 +	  "view-calendar-month",
 +	  N_("Month"),
 +	  NULL,
 +	  N_("Show one month"),
 +	  GNOME_CAL_MONTH_VIEW },
 +
 +	{ "calendar-view-week",
 +	  "view-calendar-week",
 +	  N_("Week"),
 +	  NULL,
 +	  N_("Show one week"),
 +	  GNOME_CAL_WEEK_VIEW },
 +
 +	{ "calendar-view-workweek",
 +	  "view-calendar-workweek",
 +	  N_("Work Week"),
 +	  NULL,
 +	  N_("Show one work week"),
 +	  GNOME_CAL_WORK_WEEK_VIEW }
 +};
 +
 +static GtkRadioActionEntry calendar_filter_entries[] = {
 +
 +	{ "calendar-filter-active-appointments",
 +	  NULL,
 +	  N_("Active Appointements"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  CALENDAR_FILTER_ACTIVE_APPOINTMENTS },
 +
 +	{ "calendar-filter-any-category",
 +	  NULL,
 +	  N_("Any Category"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  CALENDAR_FILTER_ANY_CATEGORY },
 +
 +	{ "calendar-filter-next-7-days-appointments",
 +	  NULL,
 +	  N_("Next 7 Days' Appointments"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  CALENDAR_FILTER_NEXT_7_DAYS_APPOINTMENTS },
 +
 +	{ "calendar-filter-unmatched",
 +	  NULL,
 +	  N_("Unmatched"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  CALENDAR_FILTER_UNMATCHED }
 +};
 +
 +static GtkRadioActionEntry calendar_search_entries[] = {
 +
 +	{ "calendar-search-any-field-contains",
 +	  NULL,
 +	  N_("Any field contains"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  CALENDAR_SEARCH_ANY_FIELD_CONTAINS },
 +
 +	{ "calendar-search-description-contains",
 +	  NULL,
 +	  N_("Description contains"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  CALENDAR_SEARCH_DESCRIPTION_CONTAINS },
 +
 +	{ "calendar-search-summary-contains",
 +	  NULL,
 +	  N_("Summary contains"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  CALENDAR_SEARCH_SUMMARY_CONTAINS }
 +};
 +
 +static GtkActionEntry lockdown_printing_entries[] = {
 +
 +	{ "calendar-print",
 +	  GTK_STOCK_PRINT,
 +	  NULL,
 +	  "<Control>p",
 +	  N_("Print this calendar"),
 +	  G_CALLBACK (action_calendar_print_cb) },
 +
 +	{ "calendar-print-preview",
 +	  GTK_STOCK_PRINT_PREVIEW,
 +	  NULL,
 +	  NULL,
 +	  N_("Preview the calendar to be printed"),
 +	  G_CALLBACK (action_calendar_print_preview_cb) },
 +
 +	{ "event-print",
 +	  GTK_STOCK_PRINT,
 +	  NULL,
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  G_CALLBACK (action_event_print_cb) }
 +};
 +
 +static EPopupActionEntry lockdown_printing_popup_entries[] = {
 +
 +	{ "event-popup-print",
 +	  NULL,
 +	  "event-print" }
 +};
 +
 +void
 +e_cal_shell_view_actions_init (ECalShellView *cal_shell_view)
 +{
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	GtkActionGroup *action_group;
 +	GtkAction *action;
 +
 +	shell_view = E_SHELL_VIEW (cal_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	/* Calendar Actions */
 +	action_group = ACTION_GROUP (CALENDAR);
 +	gtk_action_group_add_actions (
 +		action_group, calendar_entries,
 +		G_N_ELEMENTS (calendar_entries), cal_shell_view);
 +	e_action_group_add_popup_actions (
 +		action_group, calendar_popup_entries,
 +		G_N_ELEMENTS (calendar_popup_entries));
 +	gtk_action_group_add_radio_actions (
 +		action_group, calendar_view_entries,
 +		G_N_ELEMENTS (calendar_view_entries), GNOME_CAL_DAY_VIEW,
 +		G_CALLBACK (action_calendar_view_cb), cal_shell_view);
 +	gtk_action_group_add_radio_actions (
 +		action_group, calendar_search_entries,
 +		G_N_ELEMENTS (calendar_search_entries),
 +		CALENDAR_SEARCH_SUMMARY_CONTAINS,
 +		NULL, NULL);
 +
 +	/* Lockdown Printing Actions */
 +	action_group = ACTION_GROUP (LOCKDOWN_PRINTING);
 +	gtk_action_group_add_actions (
 +		action_group, lockdown_printing_entries,
 +		G_N_ELEMENTS (lockdown_printing_entries), cal_shell_view);
 +	e_action_group_add_popup_actions (
 +		action_group, lockdown_printing_popup_entries,
 +		G_N_ELEMENTS (lockdown_printing_popup_entries));
 +
 +	/* Fine tuning. */
 +
 +	action = ACTION (CALENDAR_GO_TODAY);
 +	g_object_set (action, "short-label", _("Today"), NULL);
 +
 +	action = ACTION (CALENDAR_JUMP_TO);
 +	g_object_set (action, "short-label", _("Go To"), NULL);
 +
 +	action = ACTION (EVENT_DELETE);
 +	g_object_set (action, "short-label", _("Delete"), NULL);
 +
 +	g_signal_connect (
 +		ACTION (GAL_SAVE_CUSTOM_VIEW), "activate",
 +		G_CALLBACK (action_gal_save_custom_view_cb), cal_shell_view);
 +
 +	g_signal_connect (
 +		ACTION (SEARCH_EXECUTE), "activate",
 +		G_CALLBACK (action_search_execute_cb), cal_shell_view);
 +
 +	/* Initialize the memo and task pad actions. */
 +	e_cal_shell_view_memopad_actions_init (cal_shell_view);
 +	e_cal_shell_view_taskpad_actions_init (cal_shell_view);
 +}
 +
 +void
 +e_cal_shell_view_update_search_filter (ECalShellView *cal_shell_view)
 +{
 +	EShellContent *shell_content;
 +	EShellWindow *shell_window;
 +	EShellView *shell_view;
 +	GtkActionGroup *action_group;
 +	GtkRadioAction *radio_action;
 +	GList *list, *iter;
 +	GSList *group;
 +	gint ii;
 +
 +	shell_view = E_SHELL_VIEW (cal_shell_view);
 +	shell_content = e_shell_view_get_shell_content (shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	action_group = ACTION_GROUP (CALENDAR_FILTER);
 +	e_action_group_remove_all_actions (action_group);
 +
 +	/* Add the standard filter actions. */
 +	gtk_action_group_add_radio_actions (
 +		action_group, calendar_filter_entries,
 +		G_N_ELEMENTS (calendar_filter_entries),
 +		CALENDAR_FILTER_ANY_CATEGORY,
 +		G_CALLBACK (action_search_filter_cb),
 +		cal_shell_view);
 +
 +	/* Retrieve the radio group from an action we just added. */
 +	list = gtk_action_group_list_actions (action_group);
 +	radio_action = GTK_RADIO_ACTION (list->data);
 +	group = gtk_radio_action_get_group (radio_action);
 +	g_list_free (list);
 +
 +	/* Build the category actions. */
 +
 +	list = e_categories_get_list ();
 +	for (iter = list, ii = 0; iter != NULL; iter = iter->next, ii++) {
 +		const gchar *category_name = iter->data;
 +		const gchar *filename;
 +		GtkAction *action;
 +		gchar *action_name;
 +
 +		action_name = g_strdup_printf (
 +			"calendar-filter-category-%d", ii);
 +		radio_action = gtk_radio_action_new (
 +			action_name, category_name, NULL, NULL, ii);
 +		g_free (action_name);
 +
 +		/* Convert the category icon file to a themed icon name. */
 +		filename = e_categories_get_icon_file_for (category_name);
 +		if (filename != NULL && *filename != '\0') {
 +			gchar *basename;
 +			gchar *cp;
 +
 +			basename = g_path_get_basename (filename);
 +
 +			/* Lose the file extension. */
 +			if ((cp = strrchr (basename, '.')) != NULL)
 +				*cp = '\0';
 +
 +			g_object_set (
 +				radio_action, "icon-name", basename, NULL);
 +
 +			g_free (basename);
 +		}
 +
 +		gtk_radio_action_set_group (radio_action, group);
 +		group = gtk_radio_action_get_group (radio_action);
 +
 +		/* The action group takes ownership of the action. */
 +		action = GTK_ACTION (radio_action);
 +		gtk_action_group_add_action (action_group, action);
 +		g_object_unref (radio_action);
 +	}
 +	g_list_free (list);
 +
 +	/* Use any action in the group; doesn't matter which. */
 +	e_shell_content_set_filter_action (shell_content, radio_action);
 +
 +	ii = CALENDAR_FILTER_UNMATCHED;
 +	e_shell_content_add_filter_separator_after (shell_content, ii);
 +
 +	ii = CALENDAR_FILTER_NEXT_7_DAYS_APPOINTMENTS;
 +	e_shell_content_add_filter_separator_after (shell_content, ii);
 +}
diff --cc calendar/module/e-cal-shell-view-actions.h
index 1ad6aa7,0000000..b02906f
mode 100644,000000..100644
--- a/calendar/module/e-cal-shell-view-actions.h
+++ b/calendar/module/e-cal-shell-view-actions.h
@@@ -1,153 -1,0 +1,153 @@@
 +/*
 + * e-cal-shell-view-actions.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_CAL_SHELL_VIEW_ACTIONS_H
 +#define E_CAL_SHELL_VIEW_ACTIONS_H
 +
 +#include <shell/e-shell-window-actions.h>
 +
 +/* Calendar Actions */
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_COPY(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "calendar-copy")
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_DELETE(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "calendar-delete")
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_GO_BACK(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "calendar-go-back")
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_GO_FORWARD(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "calendar-go-forward")
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_GO_TODAY(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "calendar-go-today")
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_JUMP_TO(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "calendar-jump-to")
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_NEW(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "calendar-new")
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_PRINT(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "calendar-print")
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_PRINT_PREVIEW(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "calendar-print-preview")
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_PROPERTIES(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "calendar-properties")
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_PURGE(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "calendar-purge")
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_RENAME(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "calendar-rename")
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_SELECT_ONE(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "calendar-select-one")
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_VIEW_DAY(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "calendar-view-day")
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_VIEW_LIST(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "calendar-view-list")
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_VIEW_MONTH(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "calendar-view-month")
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_VIEW_WEEK(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "calendar-view-week")
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_VIEW_WORKWEEK(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "calendar-view-workweek")
 +
 +/* Event Actions */
 +#define E_SHELL_WINDOW_ACTION_EVENT_CLIPBOARD_COPY(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "event-clipboard-copy")
 +#define E_SHELL_WINDOW_ACTION_EVENT_CLIPBOARD_CUT(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "event-clipboard-cut")
 +#define E_SHELL_WINDOW_ACTION_EVENT_CLIPBOARD_PASTE(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "event-clipboard-paste")
 +#define E_SHELL_WINDOW_ACTION_EVENT_DELETE(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "event-delete")
 +#define E_SHELL_WINDOW_ACTION_EVENT_DELETE_OCCURRENCE(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "event-delete-occurrence")
 +#define E_SHELL_WINDOW_ACTION_EVENT_DELETE_OCCURRENCE_ALL(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "event-delete-occurrence-all")
 +#define E_SHELL_WINDOW_ACTION_EVENT_OPEN(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "event-open")
 +
 +/* Memo Pad Actions */
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_MEMOPAD_CLIPBOARD_COPY(window) \
 +        E_SHELL_WINDOW_ACTION ((window), "calendar-memopad-clipboard-copy")
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_MEMOPAD_CLIPBOARD_CUT(window) \
 +        E_SHELL_WINDOW_ACTION ((window), "calendar-memopad-clipboard-cut")
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_MEMOPAD_CLIPBOARD_PASTE(window) \
 +        E_SHELL_WINDOW_ACTION ((window), "calendar-memopad-clipboard-paste")
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_MEMOPAD_DELETE(window) \
 +        E_SHELL_WINDOW_ACTION ((window), "calendar-memopad-delete")
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_MEMOPAD_FORWARD(window) \
 +        E_SHELL_WINDOW_ACTION ((window), "calendar-memopad-forward")
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_MEMOPAD_NEW(window) \
 +        E_SHELL_WINDOW_ACTION ((window), "calendar-memopad-new")
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_MEMOPAD_OPEN(window) \
 +        E_SHELL_WINDOW_ACTION ((window), "calendar-memopad-open")
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_MEMOPAD_OPEN_URL(window) \
 +        E_SHELL_WINDOW_ACTION ((window), "calendar-memopad-open-url")
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_MEMOPAD_PRINT(window) \
 +        E_SHELL_WINDOW_ACTION ((window), "calendar-memopad-print")
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_MEMOPAD_SAVE_AS(window) \
 +        E_SHELL_WINDOW_ACTION ((window), "calendar-memopad-save-as")
 +
 +/* Task Pad Actions */
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_TASKPAD_ASSIGN(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "calendar-taskpad-assign")
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_TASKPAD_CLIPBOARD_COPY(window) \
 +        E_SHELL_WINDOW_ACTION ((window), "calendar-taskpad-clipboard-copy")
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_TASKPAD_CLIPBOARD_CUT(window) \
 +        E_SHELL_WINDOW_ACTION ((window), "calendar-taskpad-clipboard-cut")
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_TASKPAD_CLIPBOARD_PASTE(window) \
 +        E_SHELL_WINDOW_ACTION ((window), "calendar-taskpad-clipboard-paste")
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_TASKPAD_DELETE(window) \
 +        E_SHELL_WINDOW_ACTION ((window), "calendar-taskpad-delete")
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_TASKPAD_FORWARD(window) \
 +        E_SHELL_WINDOW_ACTION ((window), "calendar-taskpad-forward")
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_TASKPAD_MARK_COMPLETE(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "calendar-taskpad-mark-complete")
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_TASKPAD_MARK_INCOMPLETE(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "calendar-taskpad-mark-incomplete")
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_TASKPAD_NEW(window) \
 +        E_SHELL_WINDOW_ACTION ((window), "calendar-taskpad-new")
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_TASKPAD_OPEN(window) \
 +        E_SHELL_WINDOW_ACTION ((window), "calendar-taskpad-open")
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_TASKPAD_OPEN_URL(window) \
 +        E_SHELL_WINDOW_ACTION ((window), "calendar-taskpad-open-url")
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_TASKPAD_PRINT(window) \
 +        E_SHELL_WINDOW_ACTION ((window), "calendar-taskpad-print")
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_TASKPAD_SAVE_AS(window) \
 +        E_SHELL_WINDOW_ACTION ((window), "calendar-taskpad-save-as")
 +
 +/* Calendar Query Actions */
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_FILTER_ACTIVE_APPOINTMENTS(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "calendar-filter-active-appointments")
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_FILTER_ANY_CATEGORY(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "calendar-filter-any-category")
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_FILTER_NEXT_7_DAYS_APPOINTMENTS(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "calendar-filter-next-7-days-appointments")
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_FILTER_UNMATCHED(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "calendar-filter-unmatched")
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_SEARCH_ANY_FIELD_CONTAINS(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "calendar-search-any-field-contains")
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_SEARCH_DESCRIPTION_CONTAINS(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "calendar-search-description-contains")
 +#define E_SHELL_WINDOW_ACTION_CALENDAR_SEARCH_SUMMARY_CONTAINS(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "calendar-search-summary-contains")
 +
 +/* Action Groups */
 +#define E_SHELL_WINDOW_ACTION_GROUP_CALENDAR(window) \
 +	E_SHELL_WINDOW_ACTION_GROUP ((window), "calendar")
 +#define E_SHELL_WINDOW_ACTION_GROUP_CALENDAR_FILTER(window) \
 +	E_SHELL_WINDOW_ACTION_GROUP ((window), "calendar-filter")
 +
 +#endif /* E_CAL_SHELL_VIEW_ACTIONS_H */
diff --cc calendar/module/e-cal-shell-view-memopad.c
index d9adf23,0000000..ecee72d
mode 100644,000000..100644
--- a/calendar/module/e-cal-shell-view-memopad.c
+++ b/calendar/module/e-cal-shell-view-memopad.c
@@@ -1,526 -1,0 +1,526 @@@
 +/*
 + * e-cal-shell-view-memopad.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-cal-shell-view-private.h"
 +
 +/* Much of this file is based on e-memo-shell-view-actions.c. */
 +
 +static void
 +action_calendar_memopad_clipboard_copy_cb (GtkAction *action,
 +                                           ECalShellView *cal_shell_view)
 +{
 +	ECalShellContent *cal_shell_content;
 +	EMemoTable *memo_table;
 +
 +	cal_shell_content = cal_shell_view->priv->cal_shell_content;
 +	memo_table = e_cal_shell_content_get_memo_table (cal_shell_content);
 +
 +	e_memo_table_copy_clipboard (memo_table);
 +}
 +
 +static void
 +action_calendar_memopad_clipboard_cut_cb (GtkAction *action,
 +                                          ECalShellView *cal_shell_view)
 +{
 +	ECalShellContent *cal_shell_content;
 +	EMemoTable *memo_table;
 +
 +	cal_shell_content = cal_shell_view->priv->cal_shell_content;
 +	memo_table = e_cal_shell_content_get_memo_table (cal_shell_content);
 +
 +	e_memo_table_cut_clipboard (memo_table);
 +}
 +
 +static void
 +action_calendar_memopad_clipboard_paste_cb (GtkAction *action,
 +                                            ECalShellView *cal_shell_view)
 +{
 +	ECalShellContent *cal_shell_content;
 +	EMemoTable *memo_table;
 +
 +	cal_shell_content = cal_shell_view->priv->cal_shell_content;
 +	memo_table = e_cal_shell_content_get_memo_table (cal_shell_content);
 +
 +	e_memo_table_paste_clipboard (memo_table);
 +}
 +
 +static void
 +action_calendar_memopad_delete_cb (GtkAction *action,
 +                                   ECalShellView *cal_shell_view)
 +{
 +	ECalShellContent *cal_shell_content;
 +	EMemoTable *memo_table;
 +
 +	cal_shell_content = cal_shell_view->priv->cal_shell_content;
 +	memo_table = e_cal_shell_content_get_memo_table (cal_shell_content);
 +
 +	e_cal_shell_view_memopad_set_status_message (
 +		cal_shell_view, _("Deleting selected memos..."), -1.0);
 +	e_memo_table_delete_selected (memo_table);
 +	e_cal_shell_view_memopad_set_status_message (
 +		cal_shell_view, NULL, -1.0);
 +}
 +
 +static void
 +action_calendar_memopad_forward_cb (GtkAction *action,
 +                                    ECalShellView *cal_shell_view)
 +{
 +	ECalShellContent *cal_shell_content;
 +	EMemoTable *memo_table;
 +	ECalModelComponent *comp_data;
 +	ECalComponent *comp;
 +	icalcomponent *clone;
 +	GSList *list;
 +
 +	cal_shell_content = cal_shell_view->priv->cal_shell_content;
 +	memo_table = e_cal_shell_content_get_memo_table (cal_shell_content);
 +
 +	list = e_memo_table_get_selected (memo_table);
 +	g_return_if_fail (list != NULL);
 +	comp_data = list->data;
 +	g_slist_free (list);
 +
 +	/* XXX We only forward the first selected memo. */
 +	comp = e_cal_component_new ();
 +	clone = icalcomponent_new_clone (comp_data->icalcomp);
 +	e_cal_component_set_icalcomponent (comp, clone);
 +	itip_send_comp (
 +		E_CAL_COMPONENT_METHOD_PUBLISH, comp,
 +		comp_data->client, NULL, NULL, NULL, TRUE);
 +	g_object_unref (comp);
 +}
 +
 +static void
 +action_calendar_memopad_new_cb (GtkAction *action,
 +                                ECalShellView *cal_shell_view)
 +{
 +	EShell *shell;
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	ECalShellContent *cal_shell_content;
 +	EMemoTable *memo_table;
 +	ECalModelComponent *comp_data;
 +	ECal *client;
 +	ECalComponent *comp;
 +	CompEditor *editor;
 +	GSList *list;
 +
 +	shell_view = E_SHELL_VIEW (cal_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +	shell = e_shell_window_get_shell (shell_window);
 +
 +	cal_shell_content = cal_shell_view->priv->cal_shell_content;
 +	memo_table = e_cal_shell_content_get_memo_table (cal_shell_content);
 +
 +	list = e_memo_table_get_selected (memo_table);
 +	g_return_if_fail (list != NULL);
 +	comp_data = list->data;
 +	g_slist_free (list);
 +
 +	client = comp_data->client;
 +	editor = memo_editor_new (client, shell, COMP_EDITOR_NEW_ITEM);
 +	comp = cal_comp_memo_new_with_defaults (client);
 +	comp_editor_edit_comp (editor, comp);
 +
 +	gtk_window_present (GTK_WINDOW (editor));
 +
 +	g_object_unref (comp);
 +	g_object_unref (client);
 +}
 +
 +static void
 +action_calendar_memopad_open_cb (GtkAction *action,
 +                                 ECalShellView *cal_shell_view)
 +{
 +	ECalShellContent *cal_shell_content;
 +	EMemoTable *memo_table;
 +	ECalModelComponent *comp_data;
 +	GSList *list;
 +
 +	cal_shell_content = cal_shell_view->priv->cal_shell_content;
 +	memo_table = e_cal_shell_content_get_memo_table (cal_shell_content);
 +
 +	list = e_memo_table_get_selected (memo_table);
 +	g_return_if_fail (list != NULL);
 +	comp_data = list->data;
 +	g_slist_free (list);
 +
 +	/* XXX We only open the first selected memo. */
 +	e_cal_shell_view_memopad_open_memo (cal_shell_view, comp_data);
 +}
 +
 +static void
 +action_calendar_memopad_open_url_cb (GtkAction *action,
 +                                     ECalShellView *cal_shell_view)
 +{
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	ECalShellContent *cal_shell_content;
 +	EMemoTable *memo_table;
 +	ECalModelComponent *comp_data;
 +	icalproperty *prop;
 +	const gchar *uri;
 +	GSList *list;
 +
 +	shell_view = E_SHELL_VIEW (cal_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	cal_shell_content = cal_shell_view->priv->cal_shell_content;
 +	memo_table = e_cal_shell_content_get_memo_table (cal_shell_content);
 +
 +	list = e_memo_table_get_selected (memo_table);
 +	g_return_if_fail (list != NULL);
 +	comp_data = list->data;
 +	g_slist_free (list);
 +
 +	/* XXX We only open the URI of the first selected memo. */
 +	prop = icalcomponent_get_first_property (
 +		comp_data->icalcomp, ICAL_URL_PROPERTY);
 +	g_return_if_fail (prop == NULL);
 +
 +	uri = icalproperty_get_url (prop);
 +	e_show_uri (GTK_WINDOW (shell_window), uri);
 +}
 +
 +static void
 +action_calendar_memopad_print_cb (GtkAction *action,
 +                                  ECalShellView *cal_shell_view)
 +{
 +	ECalShellContent *cal_shell_content;
 +	EMemoTable *memo_table;
 +	ECalModelComponent *comp_data;
 +	ECalComponent *comp;
 +	icalcomponent *clone;
 +	GtkPrintOperationAction print_action;
 +	GSList *list;
 +
 +	cal_shell_content = cal_shell_view->priv->cal_shell_content;
 +	memo_table = e_cal_shell_content_get_memo_table (cal_shell_content);
 +
 +	list = e_memo_table_get_selected (memo_table);
 +	g_return_if_fail (list != NULL);
 +	comp_data = list->data;
 +	g_slist_free (list);
 +
 +	/* XXX We only print the first selected memo. */
 +	comp = e_cal_component_new ();
 +	clone = icalcomponent_new_clone (comp_data->icalcomp);
 +	print_action = GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG;
 +	e_cal_component_set_icalcomponent (comp, clone);
 +	print_comp (comp, comp_data->client, print_action);
 +	g_object_unref (comp);
 +}
 +
 +static void
 +action_calendar_memopad_save_as_cb (GtkAction *action,
 +                                    ECalShellView *cal_shell_view)
 +{
 +	ECalShellContent *cal_shell_content;
 +	EMemoTable *memo_table;
 +	ECalModelComponent *comp_data;
 +	GSList *list;
 +	gchar *filename;
 +	gchar *string;
 +
 +	cal_shell_content = cal_shell_view->priv->cal_shell_content;
 +	memo_table = e_cal_shell_content_get_memo_table (cal_shell_content);
 +
 +	list = e_memo_table_get_selected (memo_table);
 +	g_return_if_fail (list != NULL);
 +	comp_data = list->data;
 +	g_slist_free (list);
 +
 +	filename = e_file_dialog_save (_("Save as..."), NULL);
 +	if (filename == NULL)
 +		return;
 +
 +	/* XXX We only save the first selected memo. */
 +	string = e_cal_get_component_as_string (
 +		comp_data->client, comp_data->icalcomp);
 +	if (string == NULL) {
 +		g_warning ("Could not convert memo to a string.");
 +		return;
 +	}
 +
 +	e_write_file_uri (filename, string);
 +
 +	g_free (filename);
 +	g_free (string);
 +}
 +
 +static GtkActionEntry calendar_memopad_entries[] = {
 +
 +	{ "calendar-memopad-clipboard-copy",
 +	  GTK_STOCK_COPY,
 +	  NULL,
 +	  NULL,
 +	  N_("Copy selected memo"),
 +	  G_CALLBACK (action_calendar_memopad_clipboard_copy_cb) },
 +
 +	{ "calendar-memopad-clipboard-cut",
 +	  GTK_STOCK_CUT,
 +	  NULL,
 +	  NULL,
 +	  N_("Cut selected memo"),
 +	  G_CALLBACK (action_calendar_memopad_clipboard_cut_cb) },
 +
 +	{ "calendar-memopad-clipboard-paste",
 +	  GTK_STOCK_PASTE,
 +	  NULL,
 +	  NULL,
 +	  N_("Paste memo from the clipboard"),
 +	  G_CALLBACK (action_calendar_memopad_clipboard_paste_cb) },
 +
 +	{ "calendar-memopad-delete",
 +	  GTK_STOCK_DELETE,
 +	  N_("_Delete Memo"),
 +	  NULL,
 +	  N_("Delete selected memos"),
 +	  G_CALLBACK (action_calendar_memopad_delete_cb) },
 +
 +	{ "calendar-memopad-forward",
 +	  "mail-forward",
 +	  N_("_Forward as iCalendar..."),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  G_CALLBACK (action_calendar_memopad_forward_cb) },
 +
 +	{ "calendar-memopad-new",
 +	  "stock_insert-note",
 +	  N_("New _Memo"),
 +	  NULL,
 +	  N_("Create a new memo"),
 +	  G_CALLBACK (action_calendar_memopad_new_cb) },
 +
 +	{ "calendar-memopad-open",
 +	  GTK_STOCK_OPEN,
 +	  N_("_Open Memo"),
 +	  NULL,
 +	  N_("View the selected memo"),
 +	  G_CALLBACK (action_calendar_memopad_open_cb) },
 +
 +	{ "calendar-memopad-open-url",
 +	  "applications-internet",
 +	  N_("Open _Web Page"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  G_CALLBACK (action_calendar_memopad_open_url_cb) },
 +
 +	{ "calendar-memopad-save-as",
 +	  GTK_STOCK_SAVE_AS,
 +	  NULL,
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  G_CALLBACK (action_calendar_memopad_save_as_cb) }
 +};
 +
 +static GtkActionEntry lockdown_printing_entries[] = {
 +
 +	{ "calendar-memopad-print",
 +	  GTK_STOCK_PRINT,
 +	  NULL,
 +	  NULL,
 +	  N_("Print the selected memo"),
 +	  G_CALLBACK (action_calendar_memopad_print_cb) }
 +};
 +
 +void
 +e_cal_shell_view_memopad_actions_init (ECalShellView *cal_shell_view)
 +{
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	GtkActionGroup *action_group;
 +
 +	shell_view = E_SHELL_VIEW (cal_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	/* Calendar Actions */
 +	action_group = ACTION_GROUP (CALENDAR);
 +	gtk_action_group_add_actions (
 +		action_group, calendar_memopad_entries,
 +		G_N_ELEMENTS (calendar_memopad_entries), cal_shell_view);
 +
 +	/* Lockdown Printing Actions */
 +	action_group = ACTION_GROUP (LOCKDOWN_PRINTING);
 +	gtk_action_group_add_actions (
 +		action_group, lockdown_printing_entries,
 +		G_N_ELEMENTS (lockdown_printing_entries), cal_shell_view);
 +}
 +
 +void
 +e_cal_shell_view_memopad_actions_update (ECalShellView *cal_shell_view)
 +{
 +	ECalShellContent *cal_shell_content;
 +	EShellWindow *shell_window;
 +	EShellView *shell_view;
 +	EMemoTable *memo_table;
 +	ETable *table;
 +	GtkAction *action;
 +	GSList *list, *iter;
 +	const gchar *label;
 +	gboolean editable = TRUE;
 +	gboolean has_url = FALSE;
 +	gboolean sensitive;
 +	gint n_selected;
 +
 +	shell_view = E_SHELL_VIEW (cal_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	cal_shell_content = cal_shell_view->priv->cal_shell_content;
 +	memo_table = e_cal_shell_content_get_memo_table (cal_shell_content);
 +
 +	table = e_memo_table_get_table (memo_table);
 +	n_selected = e_table_selected_count (table);
 +
 +	list = e_memo_table_get_selected (memo_table);
 +	for (iter = list; iter != NULL; iter = iter->next) {
 +		ECalModelComponent *comp_data = iter->data;
 +		icalproperty *prop;
 +		gboolean read_only;
 +
 +		e_cal_is_read_only (comp_data->client, &read_only, NULL);
 +		editable &= !read_only;
 +
 +		prop = icalcomponent_get_first_property (
 +			comp_data->icalcomp, ICAL_URL_PROPERTY);
 +		has_url |= (prop != NULL);
 +	}
 +	g_slist_free (list);
 +
 +	action = ACTION (CALENDAR_MEMOPAD_CLIPBOARD_COPY);
 +	sensitive = (n_selected > 0);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (CALENDAR_MEMOPAD_CLIPBOARD_CUT);
 +	sensitive = (n_selected > 0) && editable;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (CALENDAR_MEMOPAD_CLIPBOARD_PASTE);
 +	sensitive = editable;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (CALENDAR_MEMOPAD_DELETE);
 +	sensitive = (n_selected > 0) && editable;
 +	gtk_action_set_sensitive (action, sensitive);
 +	label = ngettext ("Delete Memo", "Delete Memos", n_selected);
 +	g_object_set (action, "label", label, NULL);
 +
 +	action = ACTION (CALENDAR_MEMOPAD_FORWARD);
 +	sensitive = (n_selected == 1);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (CALENDAR_MEMOPAD_OPEN);
 +	sensitive = (n_selected == 1);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (CALENDAR_MEMOPAD_OPEN_URL);
 +	sensitive = (n_selected == 1) && has_url;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (CALENDAR_MEMOPAD_PRINT);
 +	sensitive = (n_selected == 1);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (CALENDAR_MEMOPAD_SAVE_AS);
 +	sensitive = (n_selected == 1);
 +	gtk_action_set_sensitive (action, sensitive);
 +}
 +
 +void
 +e_cal_shell_view_memopad_open_memo (ECalShellView *cal_shell_view,
 +                                    ECalModelComponent *comp_data)
 +{
 +	EShell *shell;
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	CompEditor *editor;
 +	CompEditorFlags flags = 0;
 +	ECalComponent *comp;
 +	icalcomponent *clone;
 +	const gchar *uid;
 +
 +	g_return_if_fail (E_IS_CAL_SHELL_VIEW (cal_shell_view));
 +	g_return_if_fail (E_IS_CAL_MODEL_COMPONENT (comp_data));
 +
 +	shell_view = E_SHELL_VIEW (cal_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +	shell = e_shell_window_get_shell (shell_window);
 +
 +	uid = icalcomponent_get_uid (comp_data->icalcomp);
 +	editor = comp_editor_find_instance (uid);
 +
 +	if (editor != NULL)
 +		goto exit;
 +
 +	comp = e_cal_component_new ();
 +	clone = icalcomponent_new_clone (comp_data->icalcomp);
 +	e_cal_component_set_icalcomponent (comp, clone);
 +
 +	if (e_cal_component_has_organizer (comp))
 +		flags |= COMP_EDITOR_IS_SHARED;
 +
 +	if (itip_organizer_is_user (comp, comp_data->client))
 +		flags |= COMP_EDITOR_USER_ORG;
 +
 +	editor = memo_editor_new (comp_data->client, shell, flags);
 +	comp_editor_edit_comp (editor, comp);
 +
 +	g_object_unref (comp);
 +
 +exit:
 +	gtk_window_present (GTK_WINDOW (editor));
 +}
 +
 +void
 +e_cal_shell_view_memopad_set_status_message (ECalShellView *cal_shell_view,
 +                                             const gchar *status_message,
 +                                             gdouble percent)
 +{
 +	EActivity *activity;
 +	EShellView *shell_view;
 +	EShellBackend *shell_backend;
 +
 +	g_return_if_fail (E_IS_CAL_SHELL_VIEW (cal_shell_view));
 +
 +	shell_view = E_SHELL_VIEW (cal_shell_view);
 +	shell_backend = e_shell_view_get_shell_backend (shell_view);
 +
 +	activity = cal_shell_view->priv->memopad_activity;
 +
 +	if (status_message == NULL || *status_message == '\0') {
 +		if (activity != NULL) {
 +			e_activity_complete (activity);
 +			g_object_unref (activity);
 +			activity = NULL;
 +		}
 +
 +	} else if (activity == NULL) {
 +		activity = e_activity_new (status_message);
 +		e_activity_set_percent (activity, percent);
 +		e_shell_backend_add_activity (shell_backend, activity);
 +
 +	} else {
 +		e_activity_set_percent (activity, percent);
 +		e_activity_set_primary_text (activity, status_message);
 +	}
 +
 +	cal_shell_view->priv->memopad_activity = activity;
 +}
diff --cc calendar/module/e-cal-shell-view-private.c
index aa7b6e3,0000000..f681a2c
mode 100644,000000..100644
--- a/calendar/module/e-cal-shell-view-private.c
+++ b/calendar/module/e-cal-shell-view-private.c
@@@ -1,650 -1,0 +1,650 @@@
 +/*
 + * e-cal-shell-view-private.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-cal-shell-view-private.h"
 +
 +#include "calendar/gui/calendar-view-factory.h"
 +#include "widgets/menus/gal-view-factory-etable.h"
 +
 +static void
 +cal_shell_view_process_completed_tasks (ECalShellView *cal_shell_view,
 +                                        gboolean config_changed)
 +{
 +#if 0
 +	ECalShellContent *cal_shell_content;
 +	ECalendarTable *task_table;
 +
 +	cal_shell_content = cal_shell_view->priv->cal_shell_content;
 +	task_table = e_cal_shell_content_get_task_table (cal_shell_content);
 +
 +	e_calendar_table_process_completed_tasks (
 +		task_table, clients, config_changed);
 +#endif
 +}
 +
 +static void
 +cal_shell_view_config_timezone_changed_cb (GConfClient *client,
 +                                           guint id,
 +                                           GConfEntry *entry,
 +                                           gpointer user_data)
 +{
 +	ECalShellView *cal_shell_view = user_data;
 +
 +	e_cal_shell_view_update_timezone (cal_shell_view);
 +}
 +
 +static struct tm
 +cal_shell_view_get_current_time (ECalendarItem *calitem,
 +                                 ECalShellView *cal_shell_view)
 +{
 +	ECalShellContent *cal_shell_content;
 +	struct icaltimetype tt;
 +	icaltimezone *timezone;
 +
 +	cal_shell_content = cal_shell_view->priv->cal_shell_content;
 +	timezone = e_cal_shell_content_get_timezone (cal_shell_content);
 +
 +	tt = icaltime_from_timet_with_zone (time (NULL), FALSE, timezone);
 +
 +	return icaltimetype_to_tm (&tt);
 +}
 +
 +static void
 +cal_shell_view_mini_calendar_date_range_changed_cb (ECalShellView *cal_shell_view,
 +                                                    ECalendarItem *calitem)
 +{
 +	/* FIXME gnome-calendar.c calls update_query() here. */
 +}
-                                                     
++
 +static void
 +cal_shell_view_mini_calendar_selection_changed_cb (ECalShellView *cal_shell_view,
 +                                                   ECalendarItem *calitem)
 +{
 +	/* FIXME */
 +}
 +
 +static void
 +cal_shell_view_mini_calendar_scroll_event_cb (ECalShellView *cal_shell_view,
 +                                              GdkEventScroll *event,
 +                                              ECalendar *mini_calendar)
 +{
 +	ECalendarItem *calitem;
 +	GDate start_date, end_date;
 +
 +	calitem = mini_calendar->calitem;
 +	if (!e_calendar_item_get_selection (calitem, &start_date, &end_date))
 +		return;
 +
 +	switch (event->direction) {
 +		case GDK_SCROLL_UP:
 +			g_date_subtract_months (&start_date, 1);
 +			g_date_subtract_months (&end_date, 1);
 +			break;
 +
 +		case GDK_SCROLL_DOWN:
 +			g_date_add_months (&start_date, 1);
 +			g_date_add_months (&end_date, 1);
 +			break;
 +
 +		default:
 +			g_return_if_reached ();
 +	}
 +
 +	/* XXX Does ECalendarItem emit a signal for this?  If so, maybe
 +	 *     we could move this handler into ECalShellSidebar. */
 +	e_calendar_item_set_selection (calitem, &start_date, &end_date);
 +
 +	cal_shell_view_mini_calendar_date_range_changed_cb (
 +		cal_shell_view, calitem);
 +}
 +
 +static gboolean
 +cal_shell_view_selector_popup_event_cb (EShellView *shell_view,
 +                                        ESource *primary_source,
 +                                        GdkEventButton *event)
 +{
 +	const gchar *widget_path;
 +
 +	widget_path = "/calendar-popup";
 +	e_shell_view_show_popup_menu (shell_view, widget_path, event);
 +
 +	return TRUE;
 +}
 +
 +static void
 +cal_shell_view_memopad_popup_event_cb (EShellView *shell_view,
 +                                       GdkEventButton *event)
 +{
 +	const gchar *widget_path;
 +
 +	widget_path = "/calendar-memopad-popup";
 +	e_shell_view_show_popup_menu (shell_view, widget_path, event);
 +}
 +
 +static void
 +cal_shell_view_taskpad_popup_event_cb (EShellView *shell_view,
 +                                       GdkEventButton *event)
 +{
 +	const gchar *widget_path;
 +
 +	widget_path = "/calendar-taskpad-popup";
 +	e_shell_view_show_popup_menu (shell_view, widget_path, event);
 +}
 +
 +static void
 +cal_shell_view_load_view_collection (EShellViewClass *shell_view_class)
 +{
 +	GalViewCollection *collection;
 +	GalViewFactory *factory;
 +	ETableSpecification *spec;
 +	const gchar *base_dir;
 +	gchar *filename;
 +
 +	collection = shell_view_class->view_collection;
 +
 +	base_dir = EVOLUTION_ETSPECDIR;
 +	spec = e_table_specification_new ();
 +	filename = g_build_filename (base_dir, ETSPEC_FILENAME, NULL);
 +	if (!e_table_specification_load_from_file (spec, filename))
 +		g_critical ("Unable to load ETable specification file "
 +			    "for calendars");
 +	g_free (filename);
 +
 +	factory = calendar_view_factory_new (GNOME_CAL_DAY_VIEW);
 +	gal_view_collection_add_factory (collection, factory);
 +	g_object_unref (factory);
 +
 +	factory = calendar_view_factory_new (GNOME_CAL_WORK_WEEK_VIEW);
 +	gal_view_collection_add_factory (collection, factory);
 +	g_object_unref (factory);
 +
 +	factory = calendar_view_factory_new (GNOME_CAL_WEEK_VIEW);
 +	gal_view_collection_add_factory (collection, factory);
 +	g_object_unref (factory);
 +
 +	factory = calendar_view_factory_new (GNOME_CAL_MONTH_VIEW);
 +	gal_view_collection_add_factory (collection, factory);
 +	g_object_unref (factory);
 +
 +	factory = gal_view_factory_etable_new (spec);
 +	gal_view_collection_add_factory (collection, factory);
 +	g_object_unref (factory);
 +	g_object_unref (spec);
 +
 +	gal_view_collection_load (collection);
 +}
 +
 +static void
 +cal_shell_view_notify_view_id_cb (ECalShellView *cal_shell_view)
 +{
 +	ECalShellContent *cal_shell_content;
 +	GalViewInstance *view_instance;
 +	const gchar *view_id;
 +
 +	cal_shell_content = cal_shell_view->priv->cal_shell_content;
 +	view_instance =
 +		e_cal_shell_content_get_view_instance (cal_shell_content);
 +	view_id = e_shell_view_get_view_id (E_SHELL_VIEW (cal_shell_view));
 +
 +	/* A NULL view ID implies we're in a custom view.  But you can
 +	 * only get to a custom view via the "Define Views" dialog, which
 +	 * would have already modified the view instance appropriately.
 +	 * Furthermore, there's no way to refer to a custom view by ID
 +	 * anyway, since custom views have no IDs. */
 +	if (view_id == NULL)
 +		return;
 +
 +	gal_view_instance_set_current_view_id (view_instance, view_id);
 +}
 +
 +void
 +e_cal_shell_view_private_init (ECalShellView *cal_shell_view,
 +                               EShellViewClass *shell_view_class)
 +{
 +	if (!gal_view_collection_loaded (shell_view_class->view_collection))
 +		cal_shell_view_load_view_collection (shell_view_class);
 +
 +	g_signal_connect (
 +		cal_shell_view, "notify::view-id",
 +		G_CALLBACK (cal_shell_view_notify_view_id_cb), NULL);
 +}
 +
 +void
 +e_cal_shell_view_private_constructed (ECalShellView *cal_shell_view)
 +{
 +	ECalShellViewPrivate *priv = cal_shell_view->priv;
 +	ECalShellContent *cal_shell_content;
 +	ECalShellSidebar *cal_shell_sidebar;
 +	EShellBackend *shell_backend;
 +	EShellContent *shell_content;
 +	EShellSidebar *shell_sidebar;
 +	EShellWindow *shell_window;
 +	EShellView *shell_view;
 +	GnomeCalendar *calendar;
 +	ECalendar *mini_calendar;
 +	EMemoTable *memo_table;
 +	ECalendarTable *task_table;
 +	ESourceSelector *selector;
 +	guint id;
 +
 +	shell_view = E_SHELL_VIEW (cal_shell_view);
 +	shell_backend = e_shell_view_get_shell_backend (shell_view);
 +	shell_content = e_shell_view_get_shell_content (shell_view);
 +	shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	e_shell_window_add_action_group (shell_window, "calendar");
 +	e_shell_window_add_action_group (shell_window, "calendar-filter");
 +
 +	/* Cache these to avoid lots of awkward casting. */
 +	priv->cal_shell_backend = g_object_ref (shell_backend);
 +	priv->cal_shell_content = g_object_ref (shell_content);
 +	priv->cal_shell_sidebar = g_object_ref (shell_sidebar);
 +
 +	cal_shell_content = E_CAL_SHELL_CONTENT (shell_content);
 +	calendar = e_cal_shell_content_get_calendar (cal_shell_content);
 +	memo_table = e_cal_shell_content_get_memo_table (cal_shell_content);
 +	task_table = e_cal_shell_content_get_task_table (cal_shell_content);
 +
 +	cal_shell_sidebar = E_CAL_SHELL_SIDEBAR (shell_sidebar);
 +	selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
 +	mini_calendar = e_cal_shell_sidebar_get_mini_calendar (cal_shell_sidebar);
 +
 +	e_calendar_item_set_get_time_callback (
 +		mini_calendar->calitem, (ECalendarItemGetTimeCallback)
 +		cal_shell_view_get_current_time, cal_shell_view, NULL);
 +
 +#if 0 /* KILL-BONOBO */
 +	g_signal_connect_swapped (
 +		calendar, "dates-shown-changed",
 +		G_CALLBACK (e_cal_shell_view_update_sidebar),
 +		cal_shell_view);
 +#endif
 +
 +	g_signal_connect_swapped (
 +		mini_calendar, "scroll-event",
 +		G_CALLBACK (cal_shell_view_mini_calendar_scroll_event_cb),
 +		cal_shell_view);
 +
 +	g_signal_connect_swapped (
 +		mini_calendar->calitem, "date-range-changed",
 +		G_CALLBACK (cal_shell_view_mini_calendar_date_range_changed_cb),
 +		cal_shell_view);
 +
 +	g_signal_connect_swapped (
 +		mini_calendar->calitem, "selection-changed",
 +		G_CALLBACK (cal_shell_view_mini_calendar_selection_changed_cb),
 +		cal_shell_view);
 +
 +	g_signal_connect_swapped (
 +		selector, "popup-event",
 +		G_CALLBACK (cal_shell_view_selector_popup_event_cb),
 +		cal_shell_view);
 +
 +	g_signal_connect_swapped (
 +		memo_table, "popup-event",
 +		G_CALLBACK (cal_shell_view_memopad_popup_event_cb),
 +		cal_shell_view);
 +
 +	g_signal_connect_swapped (
 +		memo_table, "status-message",
 +		G_CALLBACK (e_cal_shell_view_memopad_set_status_message),
 +		cal_shell_view);
 +
 +	g_signal_connect_swapped (
 +		task_table, "popup-event",
 +		G_CALLBACK (cal_shell_view_taskpad_popup_event_cb),
 +		cal_shell_view);
 +
 +	g_signal_connect_swapped (
 +		task_table, "status-message",
 +		G_CALLBACK (e_cal_shell_view_taskpad_set_status_message),
 +		cal_shell_view);
 +
 +	g_signal_connect_swapped (
 +		e_memo_table_get_table (memo_table), "selection-change",
 +		G_CALLBACK (e_cal_shell_view_memopad_actions_update),
 +		cal_shell_view);
 +
 +	g_signal_connect_swapped (
 +		e_calendar_table_get_table (task_table), "selection-change",
 +		G_CALLBACK (e_cal_shell_view_taskpad_actions_update),
 +		cal_shell_view);
 +
 +	e_categories_register_change_listener (
 +		G_CALLBACK (e_cal_shell_view_update_search_filter),
 +		cal_shell_view);
 +
 +	/* Listen for configuration changes. */
 +
 +	/* Timezone */
 +	id = calendar_config_add_notification_timezone (
 +		cal_shell_view_config_timezone_changed_cb, cal_shell_view);
 +	priv->notifications = g_list_prepend (
 +		priv->notifications, GUINT_TO_POINTER (id));
 +
 +	e_cal_shell_view_actions_init (cal_shell_view);
 +	e_cal_shell_view_update_sidebar (cal_shell_view);
 +        e_cal_shell_view_update_search_filter (cal_shell_view);
 +	e_cal_shell_view_update_timezone (cal_shell_view);
 +}
 +
 +void
 +e_cal_shell_view_private_dispose (ECalShellView *cal_shell_view)
 +{
 +	ECalShellViewPrivate *priv = cal_shell_view->priv;
 +	GList *iter;
 +
 +	DISPOSE (priv->cal_shell_backend);
 +	DISPOSE (priv->cal_shell_content);
 +	DISPOSE (priv->cal_shell_sidebar);
 +
 +	if (priv->calendar_activity != NULL) {
 +		/* XXX Activity is not cancellable. */
 +		e_activity_complete (priv->calendar_activity);
 +		g_object_unref (priv->calendar_activity);
 +		priv->calendar_activity = NULL;
 +	}
 +
 +	if (priv->memopad_activity != NULL) {
 +		/* XXX Activity is not cancellable. */
 +		e_activity_complete (priv->memopad_activity);
 +		g_object_unref (priv->memopad_activity);
 +		priv->memopad_activity = NULL;
 +	}
 +
 +	if (priv->taskpad_activity != NULL) {
 +		/* XXX Activity is not cancellable. */
 +		e_activity_complete (priv->taskpad_activity);
 +		g_object_unref (priv->taskpad_activity);
 +		priv->taskpad_activity = NULL;
 +	}
 +
 +	for (iter = priv->notifications; iter != NULL; iter = iter->next) {
 +		guint notification_id = GPOINTER_TO_UINT (iter->data);
 +		calendar_config_remove_notification (notification_id);
 +	}
 +	g_list_free (priv->notifications);
 +	priv->notifications = NULL;
 +}
 +
 +void
 +e_cal_shell_view_private_finalize (ECalShellView *cal_shell_view)
 +{
 +	/* XXX Nothing to do? */
 +}
 +
 +void
 +e_cal_shell_view_execute_search (ECalShellView *cal_shell_view)
 +{
 +	/* FIXME */
 +}
 +
 +void
 +e_cal_shell_view_open_event (ECalShellView *cal_shell_view,
 +                             ECalModelComponent *comp_data)
 +{
 +	EShell *shell;
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	CompEditor *editor;
 +	CompEditorFlags flags = 0;
 +	ECalComponent *comp;
 +	icalcomponent *clone;
 +	icalproperty *prop;
 +	const gchar *uid;
 +
 +	g_return_if_fail (E_IS_CAL_SHELL_VIEW (cal_shell_view));
 +	g_return_if_fail (E_IS_CAL_MODEL_COMPONENT (comp_data));
 +
 +	shell_view = E_SHELL_VIEW (cal_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +	shell = e_shell_window_get_shell (shell_window);
 +
 +	uid = icalcomponent_get_uid (comp_data->icalcomp);
 +	editor = comp_editor_find_instance (uid);
 +
 +	if (editor != NULL)
 +		goto exit;
 +
 +	comp = e_cal_component_new ();
 +	clone = icalcomponent_new_clone (comp_data->icalcomp);
 +	e_cal_component_set_icalcomponent (comp, clone);
 +
 +	prop = icalcomponent_get_first_property (
 +		comp_data->icalcomp, ICAL_ATTENDEE_PROPERTY);
 +	if (prop != NULL)
 +		flags |= COMP_EDITOR_MEETING;
 +
 +	if (itip_organizer_is_user (comp, comp_data->client))
 +		flags |= COMP_EDITOR_USER_ORG;
 +
 +	if (itip_sentby_is_user (comp, comp_data->client))
 +		flags |= COMP_EDITOR_USER_ORG;
 +
 +	if (!e_cal_component_has_attendees (comp))
 +		flags |= COMP_EDITOR_USER_ORG;
 +
 +	editor = event_editor_new (comp_data->client, shell, flags);
 +	comp_editor_edit_comp (editor, comp);
 +
 +	g_object_ref (comp);
 +
 +exit:
 +	gtk_window_present (GTK_WINDOW (editor));
 +}
 +
 +void
 +e_cal_shell_view_set_status_message (ECalShellView *cal_shell_view,
 +                                     const gchar *status_message,
 +                                     gdouble percent)
 +{
 +	EActivity *activity;
 +	EShellView *shell_view;
 +	EShellBackend *shell_backend;
 +
 +	g_return_if_fail (E_IS_CAL_SHELL_VIEW (cal_shell_view));
 +
 +	shell_view = E_SHELL_VIEW (cal_shell_view);
 +	shell_backend = e_shell_view_get_shell_backend (shell_view);
 +
 +	activity = cal_shell_view->priv->calendar_activity;
 +
 +	if (status_message == NULL || *status_message == '\0') {
 +		if (activity != NULL) {
 +			e_activity_complete (activity);
 +			g_object_unref (activity);
 +			activity = NULL;
 +		}
 +
 +	} else if (activity == NULL) {
 +		activity = e_activity_new (status_message);
 +		e_activity_set_percent (activity, percent);
 +		e_shell_backend_add_activity (shell_backend, activity);
 +
 +	} else {
 +		e_activity_set_percent (activity, percent);
 +		e_activity_set_primary_text (activity, status_message);
 +	}
 +
 +	cal_shell_view->priv->calendar_activity = activity;
 +}
 +
 +void
 +e_cal_shell_view_update_sidebar (ECalShellView *cal_shell_view)
 +{
 +#if 0  /* KILL-BONOBO */
 +	EShellView *shell_view;
 +	EShellSidebar *shell_sidebar;
 +	GnomeCalendar *calendar;
 +	GnomeCalendarViewType view;
 +	time_t start_time, end_time;
 +	struct tm start_tm, end_tm;
 +	struct icaltimetype start_tt, end_tt;
 +	icaltimezone *timezone;
 +	gchar buffer[512];
 +	gchar end_buffer[512];
 +
 +	g_return_if_fail (E_IS_CAL_SHELL_VIEW (cal_shell_view));
 +
 +	shell_view = E_SHELL_VIEW (cal_shell_view);
 +	shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
 +
 +	calendar = e_cal_shell_view_get_calendar (cal_shell_view);
 +
 +	gnome_calendar_get_visible_time_range (
 +		calendar, &start_time, &end_time);
 +	timezone = gnome_calendar_get_timezone (calendar);
 +	view = gnome_calendar_get_view (calendar);
 +
 +	start_tt = icaltime_from_timet_with_zone (start_time, FALSE, timezone);
 +	start_tm.tm_year = start_tt.year - 1900;
 +	start_tm.tm_mon = start_tt.month - 1;
 +	start_tm.tm_mday = start_tt.day;
 +	start_tm.tm_hour = start_tt.hour;
 +	start_tm.tm_min = start_tt.minute;
 +	start_tm.tm_sec = start_tt.second;
 +	start_tm.tm_isdst = -1;
 +	start_tm.tm_wday = time_day_of_week (
 +		start_tt.day, start_tt.month - 1, start_tt.year);
 +
 +	/* Subtract one from end_time so we don't get an extra day. */
 +	end_tt = icaltime_from_timet_with_zone (end_time - 1, FALSE, timezone);
 +	end_tm.tm_year = end_tt.year - 1900;
 +	end_tm.tm_mon = end_tt.month - 1;
 +	end_tm.tm_mday = end_tt.day;
 +	end_tm.tm_hour = end_tt.hour;
 +	end_tm.tm_min = end_tt.minute;
 +	end_tm.tm_sec = end_tt.second;
 +	end_tm.tm_isdst = -1;
 +	end_tm.tm_wday = time_day_of_week (
 +		end_tt.day, end_tt.month - 1, end_tt.year);
 +
 +	switch (view) {
 +		case GNOME_CAL_DAY_VIEW:
 +		case GNOME_CAL_WORK_WEEK_VIEW:
 +		case GNOME_CAL_WEEK_VIEW:
 +			if (start_tm.tm_year == end_tm.tm_year &&
 +				start_tm.tm_mon == end_tm.tm_mon &&
 +				start_tm.tm_mday == end_tm.tm_mday) {
 +				e_utf8_strftime (
 +					buffer, sizeof (buffer),
 +					_("%A %d %b %Y"), &start_tm);
 +			} else if (start_tm.tm_year == end_tm.tm_year) {
 +				e_utf8_strftime (
 +					buffer, sizeof (buffer),
 +					_("%a %d %b"), &start_tm);
 +				e_utf8_strftime (
 +					end_buffer, sizeof (end_buffer),
 +					_("%a %d %b %Y"), &end_tm);
 +				strcat (buffer, " - ");
 +				strcat (buffer, end_buffer);
 +			} else {
 +				e_utf8_strftime (
 +					buffer, sizeof (buffer),
 +					_("%a %d %b %Y"), &start_tm);
 +				e_utf8_strftime (
 +					end_buffer, sizeof (end_buffer),
 +					_("%a %d %b %Y"), &end_tm);
 +				strcat (buffer, " - ");
 +				strcat (buffer, end_buffer);
 +			}
 +			break;
 +
 +		case GNOME_CAL_MONTH_VIEW:
 +		case GNOME_CAL_LIST_VIEW:
 +			if (start_tm.tm_year == end_tm.tm_year) {
 +				if (start_tm.tm_mon == end_tm.tm_mon) {
 +					e_utf8_strftime (
 +						buffer,
 +						sizeof (buffer),
 +						"%d", &start_tm);
 +					e_utf8_strftime (
 +						end_buffer,
 +						sizeof (end_buffer),
 +						_("%d %b %Y"), &end_tm);
 +					strcat (buffer, " - ");
 +					strcat (buffer, end_buffer);
 +				} else {
 +					e_utf8_strftime (
 +						buffer,
 +						sizeof (buffer),
 +						_("%d %b"), &start_tm);
 +					e_utf8_strftime (
 +						end_buffer,
 +						sizeof (end_buffer),
 +						_("%d %b %Y"), &end_tm);
 +					strcat (buffer, " - ");
 +					strcat (buffer, end_buffer);
 +				}
 +			} else {
 +				e_utf8_strftime (
 +					buffer, sizeof (buffer),
 +					_("%d %b %Y"), &start_tm);
 +				e_utf8_strftime (
 +					end_buffer, sizeof (end_buffer),
 +					_("%d %b %Y"), &end_tm);
 +				strcat (buffer, " - ");
 +				strcat (buffer, end_buffer);
 +			}
 +			break;
 +
 +		default:
 +			g_return_if_reached ();
 +	}
 +
 +	e_shell_sidebar_set_secondary_text (shell_sidebar, buffer);
 +#endif
 +}
 +
 +void
 +e_cal_shell_view_update_timezone (ECalShellView *cal_shell_view)
 +{
 +#if 0
 +	ECalShellContent *cal_shell_content;
 +	ECalShellSidebar *cal_shell_sidebar;
 +	GnomeCalendarViewType view_type;
 +	ECalendarView *calendar_view;
 +	icaltimezone *timezone;
 +	GList *clients, *iter;
 +
 +	cal_shell_content = cal_shell_view->priv->cal_shell_content;
 +	view_type = e_cal_shell_content_get_current_view (cal_shell_content);
 +	calendar_view = e_cal_shell_content_get_calendar_view (
 +		cal_shell_content, view_type);
 +
 +	cal_shell_sidebar = cal_shell_view->priv->cal_shell_sidebar;
 +	clients = e_cal_shell_sidebar_get_clients (cal_shell_sidebar);
 +
 +	timezone = calendar_config_get_icaltimezone ();
 +
 +	for (iter = clients; iter != NULL; iter = iter->next) {
 +		ECal *client = iter->data;
 +
 +		if (e_cal_get_load_state (client) == E_CAL_LOAD_LOADED)
 +			e_cal_set_default_timezone (client, timezone, NULL);
 +	}
 +
 +	e_calendar_view_set_icaltimezone (calendar_view, timezone);
 +
 +	g_list_free (clients);
 +#endif
 +}
diff --cc calendar/module/e-cal-shell-view-private.h
index 16a06cc,0000000..8308e0b
mode 100644,000000..100644
--- a/calendar/module/e-cal-shell-view-private.h
+++ b/calendar/module/e-cal-shell-view-private.h
@@@ -1,170 -1,0 +1,170 @@@
 +/*
 + * e-cal-shell-view-private.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_CAL_SHELL_VIEW_PRIVATE_H
 +#define E_CAL_SHELL_VIEW_PRIVATE_H
 +
 +#include "e-cal-shell-view.h"
 +
 +#include <string.h>
 +#include <glib/gi18n.h>
 +#include <libecal/e-cal-time-util.h>
 +#include <libedataserver/e-categories.h>
 +#include <libedataserver/e-data-server-util.h>
 +
 +#include "e-util/e-util.h"
 +#include "e-util/e-dialog-utils.h"
 +#include "widgets/misc/e-popup-action.h"
 +
 +#include "calendar/gui/calendar-config.h"
 +#include "calendar/gui/comp-util.h"
 +#include "calendar/gui/e-cal-list-view.h"
 +#include "calendar/gui/e-cal-model-tasks.h"
 +#include "calendar/gui/e-calendar-view.h"
 +#include "calendar/gui/gnome-cal.h"
 +/*#include "calendar/gui/goto.h"*/
 +#include "calendar/gui/print.h"
 +#include "calendar/gui/dialogs/copy-source-dialog.h"
 +#include "calendar/gui/dialogs/event-editor.h"
 +#include "calendar/gui/dialogs/memo-editor.h"
 +#include "calendar/gui/dialogs/task-editor.h"
 +
 +#include "e-cal-shell-backend.h"
 +#include "e-cal-shell-content.h"
 +#include "e-cal-shell-sidebar.h"
 +#include "e-cal-shell-view-actions.h"
 +
 +#define E_CAL_SHELL_VIEW_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_CAL_SHELL_VIEW, ECalShellViewPrivate))
 +
 +/* Shorthand, requires a variable named "shell_window". */
 +#define ACTION(name) \
 +	(E_SHELL_WINDOW_ACTION_##name (shell_window))
 +#define ACTION_GROUP(name) \
 +	(E_SHELL_WINDOW_ACTION_GROUP_##name (shell_window))
 +
 +/* For use in dispose() methods. */
 +#define DISPOSE(obj) \
 +	G_STMT_START { \
 +	if ((obj) != NULL) { g_object_unref (obj); (obj) = NULL; } \
 +	} G_STMT_END
 +
 +/* ETable Specifications */
 +#define ETSPEC_FILENAME		"e-calendar-table.etspec"
 +
 +G_BEGIN_DECLS
 +
 +/* Filter items are displayed in ascending order.
 + * Non-negative values are reserved for categories. */
 +enum {
 +	CALENDAR_FILTER_ANY_CATEGORY			= -4,
 +	CALENDAR_FILTER_UNMATCHED			= -3,
 +	CALENDAR_FILTER_ACTIVE_APPOINTMENTS		= -2,
 +	CALENDAR_FILTER_NEXT_7_DAYS_APPOINTMENTS	= -1
 +};
 +
 +/* Search items are displayed in ascending order. */
 +enum {
 +	CALENDAR_SEARCH_SUMMARY_CONTAINS,
 +	CALENDAR_SEARCH_DESCRIPTION_CONTAINS,
 +	CALENDAR_SEARCH_ANY_FIELD_CONTAINS
 +};
 +
 +struct _ECalShellViewPrivate {
 +
 +	/* These are just for convenience. */
 +	ECalShellBackend *cal_shell_backend;
 +	ECalShellContent *cal_shell_content;
 +	ECalShellSidebar *cal_shell_sidebar;
 +
 +	/* The last time explicitly selected by the user. */
 +	time_t base_view_time;
 +
 +	EActivity *calendar_activity;
 +	EActivity *memopad_activity;
 +	EActivity *taskpad_activity;
 +
 +	/* GConf notification IDs */
 +	GList *notifications;
 +};
 +
 +void		e_cal_shell_view_private_init
 +					(ECalShellView *cal_shell_view,
 +					 EShellViewClass *shell_view_class);
 +void		e_cal_shell_view_private_constructed
 +					(ECalShellView *cal_shell_view);
 +void		e_cal_shell_view_private_dispose
 +					(ECalShellView *cal_shell_view);
 +void		e_cal_shell_view_private_finalize
 +					(ECalShellView *cal_shell_view);
 +
 +/* Private Utilities */
 +
 +void		e_cal_shell_view_actions_init
 +					(ECalShellView *cal_shell_view);
 +void		e_cal_shell_view_execute_search
 +					(ECalShellView *cal_shell_view);
 +void		e_cal_shell_view_open_event
 +					(ECalShellView *cal_shell_view,
 +					 ECalModelComponent *comp_data);
 +void		e_cal_shell_view_set_status_message
 +					(ECalShellView *cal_shell_view,
 +					 const gchar *status_message,
 +					 gdouble percent);
 +void		e_cal_shell_view_update_sidebar
 +					(ECalShellView *cal_shell_view);
 +void		e_cal_shell_view_update_search_filter
 +					(ECalShellView *cal_shell_view);
 +void		e_cal_shell_view_update_timezone
 +					(ECalShellView *cal_shell_view);
 +
 +/* Memo Pad Utilities */
 +
 +void		e_cal_shell_view_memopad_actions_init
 +					(ECalShellView *cal_shell_view);
 +void		e_cal_shell_view_memopad_actions_update
 +					(ECalShellView *cal_shell_view);
 +void		e_cal_shell_view_memopad_open_memo
 +					(ECalShellView *cal_shell_view,
 +					 ECalModelComponent *comp_data);
 +void		e_cal_shell_view_memopad_set_status_message
 +					(ECalShellView *cal_shell_view,
 +					 const gchar *status_message,
 +					 gdouble percent);
 +
 +/* Task Pad Utilities */
 +
 +void		e_cal_shell_view_taskpad_actions_init
 +					(ECalShellView *cal_shell_view);
 +void		e_cal_shell_view_taskpad_actions_update
 +					(ECalShellView *cal_shell_view);
 +void		e_cal_shell_view_taskpad_open_task
 +					(ECalShellView *cal_shell_view,
 +					 ECalModelComponent *comp_data);
 +void		e_cal_shell_view_taskpad_set_status_message
 +					(ECalShellView *cal_shell_view,
 +					 const gchar *status_message,
 +					 gdouble percent);
 +
 +G_END_DECLS
 +
 +#endif /* E_CAL_SHELL_VIEW_PRIVATE_H */
diff --cc calendar/module/e-cal-shell-view-taskpad.c
index 6d00eb5,0000000..bdd136b
mode 100644,000000..100644
--- a/calendar/module/e-cal-shell-view-taskpad.c
+++ b/calendar/module/e-cal-shell-view-taskpad.c
@@@ -1,654 -1,0 +1,654 @@@
 +/*
 + * e-cal-shell-view-taskpad.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-cal-shell-view-private.h"
 +
 +/* Much of this file is based on e-task-shell-view-actions.c. */
 +
 +static void
 +action_calendar_taskpad_assign_cb (GtkAction *action,
 +                                   ECalShellView *cal_shell_view)
 +{
 +	ECalShellContent *cal_shell_content;
 +	ECalendarTable *task_table;
 +	ECalModelComponent *comp_data;
 +	GSList *list;
 +
 +	cal_shell_content = cal_shell_view->priv->cal_shell_content;
 +	task_table = e_cal_shell_content_get_task_table (cal_shell_content);
 +
 +	list = e_calendar_table_get_selected (task_table);
 +	g_return_if_fail (list != NULL);
 +	comp_data = list->data;
 +	g_slist_free (list);
 +
 +	/* XXX We only open the first selected task. */
 +	e_cal_shell_view_taskpad_open_task (cal_shell_view, comp_data);
 +
 +	/* FIXME Need to actually assign the task. */
 +}
 +
 +static void
 +action_calendar_taskpad_clipboard_copy_cb (GtkAction *action,
 +                                           ECalShellView *cal_shell_view)
 +{
 +	ECalShellContent *cal_shell_content;
 +	ECalendarTable *task_table;
 +
 +	cal_shell_content = cal_shell_view->priv->cal_shell_content;
 +	task_table = e_cal_shell_content_get_task_table (cal_shell_content);
 +
 +	e_calendar_table_copy_clipboard (task_table);
 +}
 +
 +static void
 +action_calendar_taskpad_clipboard_cut_cb (GtkAction *action,
 +                                          ECalShellView *cal_shell_view)
 +{
 +	ECalShellContent *cal_shell_content;
 +	ECalendarTable *task_table;
 +
 +	cal_shell_content = cal_shell_view->priv->cal_shell_content;
 +	task_table = e_cal_shell_content_get_task_table (cal_shell_content);
 +
 +	e_calendar_table_cut_clipboard (task_table);
 +}
 +
 +static void
 +action_calendar_taskpad_clipboard_paste_cb (GtkAction *action,
 +                                            ECalShellView *cal_shell_view)
 +{
 +	ECalShellContent *cal_shell_content;
 +	ECalendarTable *task_table;
 +
 +	cal_shell_content = cal_shell_view->priv->cal_shell_content;
 +	task_table = e_cal_shell_content_get_task_table (cal_shell_content);
 +
 +	e_calendar_table_paste_clipboard (task_table);
 +}
 +
 +static void
 +action_calendar_taskpad_delete_cb (GtkAction *action,
 +                                   ECalShellView *cal_shell_view)
 +{
 +	ECalShellContent *cal_shell_content;
 +	ECalendarTable *task_table;
 +
 +	cal_shell_content = cal_shell_view->priv->cal_shell_content;
 +	task_table = e_cal_shell_content_get_task_table (cal_shell_content);
 +
 +	e_cal_shell_view_taskpad_set_status_message (
 +		cal_shell_view, _("Deleting selected tasks..."), -1.0);
 +	e_calendar_table_delete_selected (task_table);
 +	e_cal_shell_view_taskpad_set_status_message (
 +		cal_shell_view, NULL, -1.0);
 +}
 +
 +static void
 +action_calendar_taskpad_forward_cb (GtkAction *action,
 +                                    ECalShellView *cal_shell_view)
 +{
 +	ECalShellContent *cal_shell_content;
 +	ECalendarTable *task_table;
 +	ECalModelComponent *comp_data;
 +	ECalComponent *comp;
 +	icalcomponent *clone;
 +	GSList *list;
 +
 +	cal_shell_content = cal_shell_view->priv->cal_shell_content;
 +	task_table = e_cal_shell_content_get_task_table (cal_shell_content);
 +
 +	list = e_calendar_table_get_selected (task_table);
 +	g_return_if_fail (list != NULL);
 +	comp_data = list->data;
 +	g_slist_free (list);
 +
 +	/* XXX We only forward the first selected task. */
 +	comp = e_cal_component_new ();
 +	clone = icalcomponent_new_clone (comp_data->icalcomp);
 +	e_cal_component_set_icalcomponent (comp, clone);
 +	itip_send_comp (
 +		E_CAL_COMPONENT_METHOD_PUBLISH, comp,
 +		comp_data->client, NULL, NULL, NULL, TRUE);
 +	g_object_unref (comp);
 +}
 +
 +static void
 +action_calendar_taskpad_mark_complete_cb (GtkAction *action,
 +                                          ECalShellView *cal_shell_view)
 +{
 +	ECalShellContent *cal_shell_content;
 +	ECalendarTable *task_table;
 +	ECalModel *model;
 +	GSList *list, *iter;
 +
 +	cal_shell_content = cal_shell_view->priv->cal_shell_content;
 +	task_table = e_cal_shell_content_get_task_table (cal_shell_content);
 +	list = e_calendar_table_get_selected (task_table);
 +	model = e_calendar_table_get_model (task_table);
 +
 +	for (iter = list; iter != NULL; iter = iter->next) {
 +		ECalModelComponent *comp_data = iter->data;
 +		e_cal_model_tasks_mark_comp_complete (
 +			E_CAL_MODEL_TASKS (model), comp_data);
 +	}
 +
 +	g_slist_free (list);
 +}
 +
 +static void
 +action_calendar_taskpad_mark_incomplete_cb (GtkAction *action,
 +                                            ECalShellView *cal_shell_view)
 +{
 +	ECalShellContent *cal_shell_content;
 +	ECalendarTable *task_table;
 +	ECalModel *model;
 +	GSList *list, *iter;
 +
 +	cal_shell_content = cal_shell_view->priv->cal_shell_content;
 +	task_table = e_cal_shell_content_get_task_table (cal_shell_content);
 +	list = e_calendar_table_get_selected (task_table);
 +	model = e_calendar_table_get_model (task_table);
 +
 +	for (iter = list; iter != NULL; iter = iter->next) {
 +		ECalModelComponent *comp_data = iter->data;
 +		e_cal_model_tasks_mark_comp_incomplete (
 +			E_CAL_MODEL_TASKS (model), comp_data);
 +	}
 +
 +	g_slist_free (list);
 +}
 +
 +static void
 +action_calendar_taskpad_new_cb (GtkAction *action,
 +                                ECalShellView *cal_shell_view)
 +{
 +	EShell *shell;
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	ECalShellContent *cal_shell_content;
 +	ECalendarTable *task_table;
 +	ECalModelComponent *comp_data;
 +	ECal *client;
 +	ECalComponent *comp;
 +	CompEditor *editor;
 +	GSList *list;
 +
 +	shell_view = E_SHELL_VIEW (cal_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +	shell = e_shell_window_get_shell (shell_window);
 +
 +	cal_shell_content = cal_shell_view->priv->cal_shell_content;
 +	task_table = e_cal_shell_content_get_task_table (cal_shell_content);
 +
 +	list = e_calendar_table_get_selected (task_table);
 +	g_return_if_fail (list != NULL);
 +	comp_data = list->data;
 +	g_slist_free (list);
 +
 +	client = comp_data->client;
 +	editor = task_editor_new (client, shell, COMP_EDITOR_NEW_ITEM);
 +	comp = cal_comp_task_new_with_defaults (client);
 +	comp_editor_edit_comp (editor, comp);
 +
 +	gtk_window_present (GTK_WINDOW (editor));
 +
 +	g_object_unref (comp);
 +	g_object_unref (client);
 +}
 +
 +static void
 +action_calendar_taskpad_open_cb (GtkAction *action,
 +                                 ECalShellView *cal_shell_view)
 +{
 +	ECalShellContent *cal_shell_content;
 +	ECalendarTable *task_table;
 +	ECalModelComponent *comp_data;
 +	GSList *list;
 +
 +	cal_shell_content = cal_shell_view->priv->cal_shell_content;
 +	task_table = e_cal_shell_content_get_task_table (cal_shell_content);
 +
 +	list = e_calendar_table_get_selected (task_table);
 +	g_return_if_fail (list != NULL);
 +	comp_data = list->data;
 +	g_slist_free (list);
 +
 +	/* XXX We only open the first selected task. */
 +	e_cal_shell_view_taskpad_open_task (cal_shell_view, comp_data);
 +}
 +
 +static void
 +action_calendar_taskpad_open_url_cb (GtkAction *action,
 +                                     ECalShellView *cal_shell_view)
 +{
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	ECalShellContent *cal_shell_content;
 +	ECalendarTable *task_table;
 +	ECalModelComponent *comp_data;
 +	icalproperty *prop;
 +	const gchar *uri;
 +	GSList *list;
 +
 +	shell_view = E_SHELL_VIEW (cal_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	cal_shell_content = cal_shell_view->priv->cal_shell_content;
 +	task_table = e_cal_shell_content_get_task_table (cal_shell_content);
 +
 +	list = e_calendar_table_get_selected (task_table);
 +	g_return_if_fail (list != NULL);
 +	comp_data = list->data;
 +
 +	/* XXX We only open the URI of the first selected task. */
 +	prop = icalcomponent_get_first_property (
 +		comp_data->icalcomp, ICAL_URL_PROPERTY);
 +	g_return_if_fail (prop == NULL);
 +
 +	uri = icalproperty_get_url (prop);
 +	e_show_uri (GTK_WINDOW (shell_window), uri);
 +}
 +
 +static void
 +action_calendar_taskpad_print_cb (GtkAction *action,
 +                                  ECalShellView *cal_shell_view)
 +{
 +	ECalShellContent *cal_shell_content;
 +	ECalendarTable *task_table;
 +	ECalModelComponent *comp_data;
 +	ECalComponent *comp;
 +	icalcomponent *clone;
 +	GtkPrintOperationAction print_action;
 +	GSList *list;
 +
 +	cal_shell_content = cal_shell_view->priv->cal_shell_content;
 +	task_table = e_cal_shell_content_get_task_table (cal_shell_content);
 +
 +	list = e_calendar_table_get_selected (task_table);
 +	g_return_if_fail (list != NULL);
 +	comp_data = list->data;
 +	g_slist_free (list);
 +
 +	/* XXX We only print the first selected task. */
 +	comp = e_cal_component_new ();
 +	clone = icalcomponent_new_clone (comp_data->icalcomp);
 +	print_action = GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG;
 +	e_cal_component_set_icalcomponent (comp, clone);
 +	print_comp (comp, comp_data->client, print_action);
 +	g_object_unref (comp);
 +}
 +
 +static void
 +action_calendar_taskpad_save_as_cb (GtkAction *action,
 +                                    ECalShellView *cal_shell_view)
 +{
 +	ECalShellContent *cal_shell_content;
 +	ECalendarTable *task_table;
 +	ECalModelComponent *comp_data;
 +	GSList *list;
 +	gchar *filename;
 +	gchar *string;
 +
 +	cal_shell_content = cal_shell_view->priv->cal_shell_content;
 +	task_table = e_cal_shell_content_get_task_table (cal_shell_content);
 +
 +	list = e_calendar_table_get_selected (task_table);
 +	g_return_if_fail (list != NULL);
 +	comp_data = list->data;
 +	g_slist_free (list);
 +
 +	filename = e_file_dialog_save (_("Save as..."), NULL);
 +	if (filename == NULL)
 +		return;
 +
 +	string = e_cal_get_component_as_string (
 +		comp_data->client, comp_data->icalcomp);
 +	if (string == NULL) {
 +		g_warning ("Could not convert task to a string");
 +		return;
 +	}
 +
 +	e_write_file_uri (filename, string);
 +
 +	g_free (filename);
 +	g_free (string);
 +}
 +
 +static GtkActionEntry calendar_taskpad_entries[] = {
 +
 +	{ "calendar-taskpad-assign",
 +	  NULL,
 +	  N_("_Assign Task"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  G_CALLBACK (action_calendar_taskpad_assign_cb) },
 +
 +	{ "calendar-taskpad-clipboard-copy",
 +	  GTK_STOCK_COPY,
 +	  NULL,
 +	  NULL,
 +	  N_("Copy selected tasks"),
 +	  G_CALLBACK (action_calendar_taskpad_clipboard_copy_cb) },
 +
 +	{ "calendar-taskpad-clipboard-cut",
 +	  GTK_STOCK_CUT,
 +	  NULL,
 +	  NULL,
 +	  N_("Cut selected tasks"),
 +	  G_CALLBACK (action_calendar_taskpad_clipboard_cut_cb) },
 +
 +	{ "calendar-taskpad-clipboard-paste",
 +	  GTK_STOCK_PASTE,
 +	  NULL,
 +	  NULL,
 +	  N_("Paste tasks from the clipboard"),
 +	  G_CALLBACK (action_calendar_taskpad_clipboard_paste_cb) },
 +
 +	{ "calendar-taskpad-delete",
 +	  GTK_STOCK_DELETE,
 +	  N_("_Delete Task"),
 +	  NULL,
 +	  N_("Delete selected tasks"),
 +	  G_CALLBACK (action_calendar_taskpad_delete_cb) },
 +
 +	{ "calendar-taskpad-forward",
 +	  "mail-forward",
 +	  N_("_Forward as iCalendar..."),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  G_CALLBACK (action_calendar_taskpad_forward_cb) },
 +
 +	{ "calendar-taskpad-mark-complete",
 +	  NULL,
 +	  N_("_Mark as Complete"),
 +	  NULL,
 +	  N_("Mark selected tasks as complete"),
 +	  G_CALLBACK (action_calendar_taskpad_mark_complete_cb) },
 +
 +	{ "calendar-taskpad-mark-incomplete",
 +	  NULL,
 +	  N_("_Mar_k as Incomplete"),
 +	  NULL,
 +	  N_("Mark selected tasks as incomplete"),
 +	  G_CALLBACK (action_calendar_taskpad_mark_incomplete_cb) },
 +
 +	{ "calendar-taskpad-new",
 +	  "stock_task",
 +	  N_("New _Task"),
 +	  NULL,
 +	  N_("Create a new task"),
 +	  G_CALLBACK (action_calendar_taskpad_new_cb) },
 +
 +	{ "calendar-taskpad-open",
 +	  GTK_STOCK_OPEN,
 +	  N_("_Open Task"),
 +	  NULL,
 +	  N_("View the selected task"),
 +	  G_CALLBACK (action_calendar_taskpad_open_cb) },
 +
 +	{ "calendar-taskpad-open-url",
 +	  "applications-internet",
 +	  N_("Open _Web Page"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  G_CALLBACK (action_calendar_taskpad_open_url_cb) },
 +
 +	{ "calendar-taskpad-save-as",
 +	  GTK_STOCK_SAVE_AS,
 +	  N_("_Save as iCalendar..."),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  G_CALLBACK (action_calendar_taskpad_save_as_cb) }
 +};
 +
 +static GtkActionEntry lockdown_printing_entries[] = {
 +
 +	{ "calendar-taskpad-print",
 +	  GTK_STOCK_PRINT,
 +	  NULL,
 +	  NULL,
 +	  N_("Print the selected task"),
 +	  G_CALLBACK (action_calendar_taskpad_print_cb) }
 +};
 +
 +void
 +e_cal_shell_view_taskpad_actions_init (ECalShellView *cal_shell_view)
 +{
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	GtkActionGroup *action_group;
 +
 +	shell_view = E_SHELL_VIEW (cal_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	/* Calendar Actions */
 +	action_group = ACTION_GROUP (CALENDAR);
 +	gtk_action_group_add_actions (
 +		action_group, calendar_taskpad_entries,
 +		G_N_ELEMENTS (calendar_taskpad_entries), cal_shell_view);
 +
 +	/* Lockdown Printing Actions */
 +	action_group = ACTION_GROUP (LOCKDOWN_PRINTING);
 +	gtk_action_group_add_actions (
 +		action_group, lockdown_printing_entries,
 +		G_N_ELEMENTS (lockdown_printing_entries), cal_shell_view);
 +}
 +
 +void
 +e_cal_shell_view_taskpad_actions_update (ECalShellView *cal_shell_view)
 +{
 +	ECalShellContent *cal_shell_content;
 +	EShellWindow *shell_window;
 +	EShellView *shell_view;
 +	ECalendarTable *task_table;
 +	ETable *table;
 +	GtkAction *action;
 +	GSList *list, *iter;
 +	const gchar *label;
 +	gboolean assignable = TRUE;
 +	gboolean editable = TRUE;
 +	gboolean has_url = FALSE;
 +	gboolean sensitive;
 +	gint n_selected;
 +	gint n_complete = 0;
 +	gint n_incomplete = 0;
 +
 +	shell_view = E_SHELL_VIEW (cal_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	cal_shell_content = cal_shell_view->priv->cal_shell_content;
 +	task_table = e_cal_shell_content_get_task_table (cal_shell_content);
 +
 +	table = e_calendar_table_get_table (task_table);
 +	n_selected = e_table_selected_count (table);
 +
 +	list = e_calendar_table_get_selected (task_table);
 +	for (iter = list; iter != NULL; iter = iter->next) {
 +		ECalModelComponent *comp_data = iter->data;
 +		icalproperty *prop;
 +		const gchar *cap;
 +		gboolean read_only;
 +
 +		e_cal_is_read_only (comp_data->client, &read_only, NULL);
 +		editable &= !read_only;
 +
 +		cap = CAL_STATIC_CAPABILITY_NO_TASK_ASSIGNMENT;
 +		if (e_cal_get_static_capability (comp_data->client, cap))
 +			assignable = FALSE;
 +
 +		cap = CAL_STATIC_CAPABILITY_NO_CONV_TO_ASSIGN_TASK;
 +		if (e_cal_get_static_capability (comp_data->client, cap))
 +			assignable = FALSE;
 +
 +		prop = icalcomponent_get_first_property (
 +			comp_data->icalcomp, ICAL_URL_PROPERTY);
 +		has_url |= (prop != NULL);
 +
 +		prop = icalcomponent_get_first_property (
 +			comp_data->icalcomp, ICAL_COMPLETED_PROPERTY);
 +		if (prop != NULL)
 +			n_complete++;
 +		else
 +			n_incomplete++;
 +	}
 +	g_slist_free (list);
 +
 +	action = ACTION (CALENDAR_TASKPAD_ASSIGN);
 +	sensitive = (n_selected == 1) && editable && assignable;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (CALENDAR_TASKPAD_CLIPBOARD_COPY);
 +	sensitive = (n_selected > 0);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (CALENDAR_TASKPAD_CLIPBOARD_CUT);
 +	sensitive = (n_selected > 0) && editable;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (CALENDAR_TASKPAD_CLIPBOARD_PASTE);
 +	sensitive = editable;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (CALENDAR_TASKPAD_DELETE);
 +	sensitive = (n_selected > 0) && editable;
 +	gtk_action_set_sensitive (action, sensitive);
 +	label = ngettext ("Delete Task", "Delete Tasks", n_selected);
 +	g_object_set (action, "label", label, NULL);
 +
 +	action = ACTION (CALENDAR_TASKPAD_FORWARD);
 +	sensitive = (n_selected == 1);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (CALENDAR_TASKPAD_MARK_COMPLETE);
 +	sensitive = (n_selected > 0) && editable && (n_incomplete > 0);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (CALENDAR_TASKPAD_MARK_INCOMPLETE);
 +	sensitive = (n_selected > 0) && editable && (n_complete > 0);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (CALENDAR_TASKPAD_OPEN);
 +	sensitive = (n_selected == 1);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (CALENDAR_TASKPAD_OPEN_URL);
 +	sensitive = (n_selected == 1) && has_url;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (CALENDAR_TASKPAD_PRINT);
 +	sensitive = (n_selected == 1);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (CALENDAR_TASKPAD_SAVE_AS);
 +	sensitive = (n_selected == 1);
 +	gtk_action_set_sensitive (action, sensitive);
 +}
 +
 +void
 +e_cal_shell_view_taskpad_open_task (ECalShellView *cal_shell_view,
 +                                    ECalModelComponent *comp_data)
 +{
 +	EShell *shell;
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	CompEditor *editor;
 +	CompEditorFlags flags = 0;
 +	ECalComponent *comp;
 +	icalcomponent *clone;
 +	icalproperty *prop;
 +	const gchar *uid;
 +
 +	g_return_if_fail (E_IS_CAL_SHELL_VIEW (cal_shell_view));
 +	g_return_if_fail (E_IS_CAL_MODEL_COMPONENT (comp_data));
 +
 +	shell_view = E_SHELL_VIEW (cal_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +	shell = e_shell_window_get_shell (shell_window);
 +
 +	uid = icalcomponent_get_uid (comp_data->icalcomp);
 +	editor = comp_editor_find_instance (uid);
 +
 +	if (editor != NULL)
 +		goto exit;
 +
 +	comp = e_cal_component_new ();
 +	clone = icalcomponent_new_clone (comp_data->icalcomp);
 +	e_cal_component_set_icalcomponent (comp, clone);
 +
 +	prop = icalcomponent_get_first_property (
 +		comp_data->icalcomp, ICAL_ATTENDEE_PROPERTY);
 +	if (prop != NULL)
 +		flags |= COMP_EDITOR_IS_ASSIGNED;
 +
 +	if (itip_organizer_is_user (comp, comp_data->client))
 +		flags |= COMP_EDITOR_USER_ORG;
 +
 +	if (!e_cal_component_has_attendees (comp))
 +		flags |= COMP_EDITOR_USER_ORG;
 +
 +	editor = task_editor_new (comp_data->client, shell, flags);
 +	comp_editor_edit_comp (editor, comp);
 +
 +	g_object_ref (comp);
 +
 +	if (flags & COMP_EDITOR_IS_ASSIGNED)
 +		task_editor_show_assignment (TASK_EDITOR (editor));
 +
 +exit:
 +	gtk_window_present (GTK_WINDOW (editor));
 +}
 +
 +void
 +e_cal_shell_view_taskpad_set_status_message (ECalShellView *cal_shell_view,
 +                                             const gchar *status_message,
 +                                             gdouble percent)
 +{
 +	EActivity *activity;
 +	EShellView *shell_view;
 +	EShellBackend *shell_backend;
 +
 +	g_return_if_fail (E_IS_CAL_SHELL_VIEW (cal_shell_view));
 +
 +	shell_view = E_SHELL_VIEW (cal_shell_view);
 +	shell_backend = e_shell_view_get_shell_backend (shell_view);
 +
 +	activity = cal_shell_view->priv->taskpad_activity;
 +
 +	if (status_message == NULL || *status_message == '\0') {
 +		if (activity != NULL) {
 +			e_activity_complete (activity);
 +			g_object_unref (activity);
 +			activity = NULL;
 +		}
 +
 +	} else if (activity == NULL) {
 +		activity = e_activity_new (status_message);
 +		e_activity_set_percent (activity, percent);
 +		e_shell_backend_add_activity (shell_backend, activity);
 +
 +	} else {
 +		e_activity_set_percent (activity, percent);
 +		e_activity_set_primary_text (activity, status_message);
 +	}
 +
 +	cal_shell_view->priv->taskpad_activity = activity;
 +}
diff --cc calendar/module/e-cal-shell-view.c
index 593b955,0000000..5bf1c74
mode 100644,000000..100644
--- a/calendar/module/e-cal-shell-view.c
+++ b/calendar/module/e-cal-shell-view.c
@@@ -1,226 -1,0 +1,226 @@@
 +/*
 + * e-cal-shell-view.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-cal-shell-view-private.h"
 +
 +static gpointer parent_class;
 +static GType cal_shell_view_type;
 +
 +static void
 +cal_shell_view_dispose (GObject *object)
 +{
 +	e_cal_shell_view_private_dispose (E_CAL_SHELL_VIEW (object));
 +
 +	/* Chain up to parent's dispose() method. */
 +	G_OBJECT_CLASS (parent_class)->dispose (object);
 +}
 +
 +static void
 +cal_shell_view_finalize (GObject *object)
 +{
 +	e_cal_shell_view_private_finalize (E_CAL_SHELL_VIEW (object));
 +
 +	/* Chain up to parent's finalize() method. */
 +	G_OBJECT_CLASS (parent_class)->finalize (object);
 +}
 +
 +static void
 +cal_shell_view_constructed (GObject *object)
 +{
 +	/* Chain up to parent's constructed() method. */
 +	G_OBJECT_CLASS (parent_class)->constructed (object);
 +
 +	e_cal_shell_view_private_constructed (E_CAL_SHELL_VIEW (object));
 +}
 +
 +static void
 +cal_shell_view_update_actions (EShellView *shell_view)
 +{
 +#if 0
 +	ECalShellViewPrivate *priv;
 +	ECalShellContent *cal_shell_content;
 +	ECalShellSidebar *cal_shell_sidebar;
 +	EShellWindow *shell_window;
 +	GnomeCalendar *calendar;
 +	ECalModel *model;
 +	ESourceSelector *selector;
 +	ESource *source;
 +	GtkAction *action;
 +	GtkWidget *widget;
 +	GList *list, *iter;
 +	const gchar *uri = NULL;
 +	gboolean user_created_source;
 +	gboolean editable = TRUE;
 +	gboolean recurring = FALSE;
 +	gboolean sensitive;
 +	gint n_selected;
 +
 +	priv = E_CAL_SHELL_VIEW_GET_PRIVATE (shell_view);
 +
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	cal_shell_content = priv->cal_shell_content;
 +	calendar = e_cal_shell_content_get_calendar (cal_shell_content);
 +	widget = gnome_calendar_get_current_view_widget (calendar);
 +	model = e_calendar_view_get_model (E_CALENDAR_VIEW (widget));
 +
 +	cal_shell_sidebar = priv->cal_shell_sidebar;
 +	selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
 +
 +	list = e_calendar_view_get_selected_events (E_CALENDAR_VIEW (widget));
 +	n_selected = g_list_length (list);
 +
 +	for (iter = list; iter != NULL; iter = iter->next) {
 +		ECalModelComponent *comp_data = iter->data;
 +		gboolean read_only;
 +
 +		e_cal_is_read_only (comp_data->client, &read_only, NULL);
 +		editable &= !read_only;
 +
 +		if (e_cal_util_component_has_recurrences (comp_data->icalcomp))
 +			recurring |= TRUE;
 +		else if (e_cal_util_component_is_instance (comp_data->icalcomp))
 +			recurring |= TRUE;
 +	}
 +
 +	source = e_source_selector_peek_primary_selection (selector);
 +	if (source != NULL)
 +		uri = e_source_peek_relative_uri (source);
 +	user_created_source = (uri != NULL && strcmp (uri, "system") != 0);
 +
 +	action = ACTION (CALENDAR_COPY);
 +	sensitive = (source != NULL);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (CALENDAR_DELETE);
 +	sensitive = user_created_source;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (CALENDAR_PROPERTIES);
 +	sensitive = (source != NULL);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (CALENDAR_RENAME);
 +	sensitive = has_primary_source;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (EVENT_CLIPBOARD_COPY);
 +	sensitive = (n_selected > 0);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (EVENT_CLIPBOARD_CUT);
 +	sensitive = (n_selected > 0) && editable;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (EVENT_CLIPBOARD_PASTE);
 +	sensitive = editable;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (EVENT_DELETE);
 +	sensitive = (n_selected > 0) && editable && !recurring;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (EVENT_DELETE_OCCURRENCE);
 +	sensitive = (n_selected > 0) && editable && recurring;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (EVENT_DELETE_OCCURRENCE_ALL);
 +	sensitive = (n_selected > 0) && editable && recurring;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (EVENT_OPEN);
 +	sensitive = (n_selected == 1);
 +	gtk_action_set_sensitive (action, sensitive);
 +#endif
 +}
 +
 +static void
 +cal_shell_view_class_init (ECalShellViewClass *class,
 +                            GTypeModule *type_module)
 +{
 +	GObjectClass *object_class;
 +	EShellViewClass *shell_view_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (ECalShellViewPrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->dispose = cal_shell_view_dispose;
 +	object_class->finalize = cal_shell_view_finalize;
 +	object_class->constructed = cal_shell_view_constructed;
 +
 +	shell_view_class = E_SHELL_VIEW_CLASS (class);
 +	shell_view_class->label = _("Calendar");
 +	shell_view_class->icon_name = "x-office-calendar";
 +	shell_view_class->ui_definition = "evolution-calendars.ui";
 +	shell_view_class->ui_manager_id = "org.gnome.evolution.calendars";
 +	shell_view_class->search_options = "/calendar-search-options";
 +	shell_view_class->search_rules = "caltypes.xml";
 +	shell_view_class->new_shell_content = e_cal_shell_content_new;
 +	shell_view_class->new_shell_sidebar = e_cal_shell_sidebar_new;
 +	shell_view_class->update_actions = cal_shell_view_update_actions;
 +}
 +
 +static void
 +cal_shell_view_init (ECalShellView *cal_shell_view,
 +                     EShellViewClass *shell_view_class)
 +{
 +	cal_shell_view->priv =
 +		E_CAL_SHELL_VIEW_GET_PRIVATE (cal_shell_view);
 +
 +	e_cal_shell_view_private_init (cal_shell_view, shell_view_class);
 +}
 +
 +GType
 +e_cal_shell_view_get_type (void)
 +{
 +	return cal_shell_view_type;
 +}
 +
 +void
 +e_cal_shell_view_register_type (GTypeModule *type_module)
 +{
 +	const GTypeInfo type_info = {
 +		sizeof (ECalShellViewClass),
 +		(GBaseInitFunc) NULL,
 +		(GBaseFinalizeFunc) NULL,
 +		(GClassInitFunc) cal_shell_view_class_init,
 +		(GClassFinalizeFunc) NULL,
 +		type_module,
 +		sizeof (ECalShellView),
 +		0,    /* n_preallocs */
 +		(GInstanceInitFunc) cal_shell_view_init,
 +		NULL  /* value_table */
 +	};
 +
 +	cal_shell_view_type = g_type_module_register_type (
 +		type_module, E_TYPE_SHELL_VIEW,
 +		"ECalShellView", &type_info, 0);
 +}
 +
 +GnomeCalendar *
 +e_cal_shell_view_get_calendar (ECalShellView *cal_shell_view)
 +{
 +	g_return_val_if_fail (E_IS_CAL_SHELL_VIEW (cal_shell_view), NULL);
 +
 +	/* FIXME */
 +	return NULL;
 +}
diff --cc calendar/module/e-cal-shell-view.h
index 42fddec,0000000..67fa152
mode 100644,000000..100644
--- a/calendar/module/e-cal-shell-view.h
+++ b/calendar/module/e-cal-shell-view.h
@@@ -1,69 -1,0 +1,69 @@@
 +/*
 + * e-cal-shell-view.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_CAL_SHELL_VIEW_H
 +#define E_CAL_SHELL_VIEW_H
 +
 +#include <shell/e-shell-view.h>
 +#include <calendar/gui/gnome-cal.h>
 +#include <libedataserver/e-source-list.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_CAL_SHELL_VIEW \
 +	(e_cal_shell_view_get_type ())
 +#define E_CAL_SHELL_VIEW(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_CAL_SHELL_VIEW, ECalShellView))
 +#define E_CAL_SHELL_VIEW_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_CAL_SHELL_VIEW, ECalShellViewClass))
 +#define E_IS_CAL_SHELL_VIEW(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_CAL_SHELL_VIEW))
 +#define E_IS_CAL_SHELL_VIEW_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), E_TYPE_CAL_SHELL_VIEW))
 +#define E_CAL_SHELL_VIEW_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_CAL_SHELL_VIEW, ECalShellViewClass))
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _ECalShellView ECalShellView;
 +typedef struct _ECalShellViewClass ECalShellViewClass;
 +typedef struct _ECalShellViewPrivate ECalShellViewPrivate;
 +
 +struct _ECalShellView {
 +	EShellView parent;
 +	ECalShellViewPrivate *priv;
 +};
 +
 +struct _ECalShellViewClass {
 +	EShellViewClass parent_class;
 +};
 +
 +GType		e_cal_shell_view_get_type	(void);
 +void		e_cal_shell_view_register_type	(GTypeModule *type_module);
 +GnomeCalendar *	e_cal_shell_view_get_calendar	(ECalShellView *cal_shell_view);
 +
 +G_END_DECLS
 +
 +#endif /* E_CAL_SHELL_VIEW_H */
diff --cc calendar/module/e-memo-shell-backend.c
index f910bcf,0000000..d2734e0
mode 100644,000000..100644
--- a/calendar/module/e-memo-shell-backend.c
+++ b/calendar/module/e-memo-shell-backend.c
@@@ -1,613 -1,0 +1,613 @@@
 +/*
 + * e-memo-shell-backend.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-memo-shell-backend.h"
 +
 +#include <string.h>
 +#include <glib/gi18n.h>
 +#include <libecal/e-cal.h>
 +#include <libedataserver/e-url.h>
 +#include <libedataserver/e-source.h>
 +#include <libedataserver/e-source-list.h>
 +#include <libedataserver/e-source-group.h>
 +
 +#include "shell/e-shell.h"
 +#include "shell/e-shell-backend.h"
 +#include "shell/e-shell-window.h"
 +
 +#include "calendar/common/authentication.h"
 +#include "calendar/gui/calendar-config.h"
 +#include "calendar/gui/comp-util.h"
 +#include "calendar/gui/dialogs/calendar-setup.h"
 +#include "calendar/gui/dialogs/memo-editor.h"
 +
 +#include "e-memo-shell-migrate.h"
 +#include "e-memo-shell-view.h"
 +
 +#define E_MEMO_SHELL_BACKEND_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_MEMO_SHELL_BACKEND, EMemoShellBackendPrivate))
 +
 +#define WEB_BASE_URI		"webcal://"
 +#define PERSONAL_RELATIVE_URI	"system"
 +
 +struct _EMemoShellBackendPrivate {
 +	ESourceList *source_list;
 +};
 +
 +enum {
 +	PROP_0,
 +	PROP_SOURCE_LIST
 +};
 +
 +static gpointer parent_class;
 +static GType memo_shell_backend_type;
 +
 +static void
 +memo_module_ensure_sources (EShellBackend *shell_backend)
 +{
 +	/* XXX This is basically the same algorithm across all modules.
 +	 *     Maybe we could somehow integrate this into EShellBackend? */
 +
 +	EMemoShellBackendPrivate *priv;
 +	ESourceGroup *on_this_computer;
 +	ESourceGroup *on_the_web;
 +	ESource *personal;
 +	GSList *groups, *iter;
 +	const gchar *data_dir;
 +	const gchar *name;
 +	gchar *base_uri;
 +	gchar *filename;
 +
 +	on_this_computer = NULL;
 +	on_the_web = NULL;
 +	personal = NULL;
 +
 +	priv = E_MEMO_SHELL_BACKEND_GET_PRIVATE (shell_backend);
 +
 +	if (!e_cal_get_sources (&priv->source_list, E_CAL_SOURCE_TYPE_JOURNAL, NULL)) {
 +		g_warning ("Could not get memo sources from GConf!");
 +		return;
 +	}
 +
 +	data_dir = e_shell_backend_get_data_dir (shell_backend);
 +	filename = g_build_filename (data_dir, "local", NULL);
 +	base_uri = g_filename_to_uri (filename, NULL, NULL);
 +	g_free (filename);
 +
 +	groups = e_source_list_peek_groups (priv->source_list);
 +	for (iter = groups; iter != NULL; iter = iter->next) {
 +		ESourceGroup *source_group = iter->data;
 +		const gchar *group_base_uri;
 +
 +		group_base_uri = e_source_group_peek_base_uri (source_group);
 +
 +		/* Compare only "file://" part.  If the user's home
 +		 * changes, we do not want to create another group. */
 +		if (on_this_computer == NULL &&
 +			strncmp (base_uri, group_base_uri, 7) == 0)
 +			on_this_computer = source_group;
 +
 +		else if (on_the_web == NULL &&
 +			strcmp (WEB_BASE_URI, group_base_uri) == 0)
 +			on_the_web = source_group;
 +	}
 +
 +	name = _("On This Computer");
 +
 +	if (on_this_computer != NULL) {
 +		GSList *sources;
 +		const gchar *group_base_uri;
 +
 +		/* Force the group name to the current locale. */
 +		e_source_group_set_name (on_this_computer, name);
 +
 +		sources = e_source_group_peek_sources (on_this_computer);
 +		group_base_uri = e_source_group_peek_base_uri (on_this_computer);
 +
 +		/* Make sure this group includes a "Personal" source. */
 +		for (iter = sources; iter != NULL; iter = iter->next) {
 +			ESource *source = iter->data;
 +			const gchar *relative_uri;
 +
 +			relative_uri = e_source_peek_relative_uri (source);
 +			if (relative_uri == NULL)
 +				continue;
 +
 +			if (strcmp (PERSONAL_RELATIVE_URI, relative_uri) != 0)
 +				continue;
 +
 +			personal = source;
 +			break;
 +		}
 +
 +		/* Make sure we have the correct base URI.  This can
 +		 * change when the user's home directory changes. */
 +		if (strcmp (base_uri, group_base_uri) != 0) {
 +			e_source_group_set_base_uri (
 +				on_this_computer, base_uri);
 +
 +			/* XXX We shouldn't need this sync call here as
 +			 *     set_base_uri() results in synching to GConf,
 +			 *     but that happens in an idle loop and too late
 +			 *     to prevent the user from seeing a "Cannot
 +			 *     Open ... because of invalid URI" error. */
 +			e_source_list_sync (priv->source_list, NULL);
 +		}
 +
 +	} else {
 +		ESourceGroup *source_group;
 +
 +		source_group = e_source_group_new (name, base_uri);
 +		e_source_list_add_group (priv->source_list, source_group, -1);
 +		g_object_unref (source_group);
 +	}
 +
 +	name = _("Personal");
 +
 +	if (personal == NULL) {
 +		ESource *source;
 +		GSList *selected;
 +		gchar *primary;
 +
 +		source = e_source_new (name, PERSONAL_RELATIVE_URI);
 +		e_source_group_add_source (on_this_computer, source, -1);
 +		g_object_unref (source);
 +
 +		primary = calendar_config_get_primary_memos ();
 +		selected = calendar_config_get_memos_selected ();
 +
 +		if (primary == NULL && selected == NULL) {
 +			const gchar *uid;
 +
 +			uid = e_source_peek_uid (source);
 +			selected = g_slist_prepend (NULL, g_strdup (uid));
 +
 +			calendar_config_set_primary_memos (uid);
 +			calendar_config_set_memos_selected (selected);
 +		}
 +
 +		g_slist_foreach (selected, (GFunc) g_free, NULL);
 +		g_slist_free (selected);
 +		g_free (primary);
 +	} else {
 +		/* Force the source name to the current locale. */
 +		e_source_set_name (personal, name);
 +	}
 +
 +	name = _("On The Web");
 +
 +	if (on_the_web == NULL) {
 +		ESourceGroup *source_group;
 +
 +		source_group = e_source_group_new (name, WEB_BASE_URI);
 +		e_source_list_add_group (priv->source_list, source_group, -1);
 +		g_object_unref (source_group);
 +	} else {
 +		/* Force the group name to the current locale. */
 +		e_source_group_set_name (on_the_web, name);
 +	}
 +
 +	g_free (base_uri);
 +}
 +
 +static void
 +memo_module_cal_opened_cb (ECal *cal,
 +                           ECalendarStatus status,
 +                           GtkAction *action)
 +{
 +	EShell *shell;
 +	ECalComponent *comp;
 +	CompEditor *editor;
 +	CompEditorFlags flags = 0;
 +	const gchar *action_name;
 +
 +	/* FIXME Pass this in. */
 +	shell = e_shell_get_default ();
 +
 +	/* XXX Handle errors better. */
 +	if (status != E_CALENDAR_STATUS_OK)
 +		return;
 +
 +	action_name = gtk_action_get_name (action);
 +
 +	flags |= COMP_EDITOR_NEW_ITEM;
 +	if (strcmp (action_name, "memo-shared-new") == 0) {
 +		flags |= COMP_EDITOR_IS_SHARED;
 +		flags |= COMP_EDITOR_USER_ORG;
 +	}
 +
 +	editor = memo_editor_new (cal, shell, flags);
 +	comp = cal_comp_memo_new_with_defaults (cal);
 +	comp_editor_edit_comp (editor, comp);
 +
 +	gtk_window_present (GTK_WINDOW (editor));
 +
 +	g_object_unref (comp);
 +	g_object_unref (cal);
 +}
 +
 +static void
 +action_memo_new_cb (GtkAction *action,
 +                    EShellWindow *shell_window)
 +{
 +	ECal *cal = NULL;
 +	ECalSourceType source_type;
 +	ESourceList *source_list;
 +	gchar *uid;
 +
 +	/* This callback is used for both memos and shared memos. */
 +
 +	source_type = E_CAL_SOURCE_TYPE_JOURNAL;
 +
 +	if (!e_cal_get_sources (&source_list, source_type, NULL)) {
 +		g_warning ("Could not get memo sources from GConf!");
 +		return;
 +	}
 +
 +	uid = calendar_config_get_primary_memos ();
 +
 +	if (uid != NULL) {
 +		ESource *source;
 +
 +		source = e_source_list_peek_source_by_uid (source_list, uid);
 +		if (source != NULL)
 +			cal = auth_new_cal_from_source (source, source_type);
 +		g_free (uid);
 +	}
 +
 +	if (cal == NULL)
 +		cal = auth_new_cal_from_default (source_type);
 +
 +	g_return_if_fail (cal != NULL);
 +
 +	g_signal_connect (
 +		cal, "cal-opened",
 +		G_CALLBACK (memo_module_cal_opened_cb), action);
 +
 +	e_cal_open_async (cal, FALSE);
 +}
 +
 +static void
 +action_memo_list_new_cb (GtkAction *action,
 +                         EShellWindow *shell_window)
 +{
 +	calendar_setup_new_memo_list (GTK_WINDOW (shell_window));
 +}
 +
 +static GtkActionEntry item_entries[] = {
 +
 +	{ "memo-new",
 +	  "stock_insert-note",
 +	  NC_("New", "Mem_o"),
 +	  "<Shift><Control>o",
 +	  N_("Create a new memo"),
 +	  G_CALLBACK (action_memo_new_cb) },
 +
 +	{ "memo-shared-new",
 +	  "stock_insert-note",
 +	  N_("_Shared Memo"),
 +	  "<Shift><Control>h",
 +	  N_("Create a new shared memo"),
 +	  G_CALLBACK (action_memo_new_cb) }
 +};
 +
 +static GtkActionEntry source_entries[] = {
 +
 +	{ "memo-list-new",
 +	  "stock_notes",
 +	  NC_("New", "Memo Li_st"),
 +	  NULL,
 +	  N_("Create a new memo list"),
 +	  G_CALLBACK (action_memo_list_new_cb) }
 +};
 +
 +static gboolean
 +memo_module_handle_uri_cb (EShellBackend *shell_backend,
 +                           const gchar *uri)
 +{
 +	EShell *shell;
 +	CompEditor *editor;
 +	CompEditorFlags flags = 0;
 +	ECal *client;
 +	ECalComponent *comp;
 +	ESource *source;
 +	ESourceList *source_list;
 +	ECalSourceType source_type;
 +	EUri *euri;
 +	icalcomponent *icalcomp;
 +	const gchar *cp;
 +	gchar *source_uid = NULL;
 +	gchar *comp_uid = NULL;
 +	gchar *comp_rid = NULL;
 +	gboolean handled = FALSE;
 +	GError *error = NULL;
 +
 +	source_type = E_CAL_SOURCE_TYPE_JOURNAL;
 +	shell = e_shell_backend_get_shell (shell_backend);
 +
 +	if (strncmp (uri, "memo:", 5) != 0)
 +		return FALSE;
 +
 +	euri = e_uri_new (uri);
 +	cp = euri->query;
 +	if (cp == NULL)
 +		goto exit;
 +
 +	while (*cp != '\0') {
 +		gchar *header;
 +		gchar *content;
 +		gsize header_len;
 +		gsize content_len;
 +
 +		header_len = strcspn (cp, "=&");
 +
 +		/* If it's malformed, give up. */
 +		if (cp[header_len] != '=')
 +			break;
 +
 +		header = (gchar *) cp;
 +		header[header_len] = '\0';
 +		cp += header_len + 1;
 +
 +		content_len = strcspn (cp, "&");
 +
 +		content = g_strndup (cp, content_len);
 +		if (g_ascii_strcasecmp (header, "source-uid") == 0)
 +			source_uid = g_strdup (content);
 +		else if (g_ascii_strcasecmp (header, "comp-uid") == 0)
 +			comp_uid = g_strdup (content);
 +		else if (g_ascii_strcasecmp (header, "comp-rid") == 0)
 +			comp_rid = g_strdup (content);
 +		g_free (content);
 +
 +		cp += content_len;
 +		if (*cp == '&') {
 +			cp++;
 +			if (strcmp (cp, "amp;") == 0)
 +				cp += 4;
 +		}
 +	}
 +
 +	if (source_uid == NULL || comp_uid == NULL)
 +		goto exit;
 +
 +	/* URI is valid, so consider it handled.  Whether
 +	 * we successfully open it is another matter... */
 +	handled = TRUE;
 +
 +	if (!e_cal_get_sources (&source_list, source_type, NULL)) {
 +		g_printerr ("Could not get memo sources from GConf!\n");
 +		goto exit;
 +	}
 +
 +	source = e_source_list_peek_source_by_uid (source_list, source_uid);
 +	if (source == NULL) {
 +		g_printerr ("No source for UID `%s'\n", source_uid);
 +		g_object_unref (source_list);
 +		goto exit;
 +	}
 +
 +	client = auth_new_cal_from_source (source, source_type);
 +	if (client == NULL || !e_cal_open (client, TRUE, &error)) {
 +		g_printerr ("%s\n", error->message);
 +		g_object_unref (source_list);
 +		g_error_free (error);
 +		goto exit;
 +	}
 +
 +	/* XXX Copied from e_memo_shell_view_open_memo().
 +	 *     Clearly a new utility function is needed. */
 +
 +	editor = comp_editor_find_instance (comp_uid);
 +
 +	if (editor != NULL)
 +		goto present;
 +
 +	if (!e_cal_get_object (client, comp_uid, comp_rid, &icalcomp, &error)) {
 +		g_printerr ("%s\n", error->message);
 +		g_object_unref (source_list);
 +		g_error_free (error);
 +		goto exit;
 +	}
 +
 +	comp = e_cal_component_new ();
 +	e_cal_component_set_icalcomponent (comp, icalcomp);
 +
 +	if (e_cal_component_has_organizer (comp))
 +		flags |= COMP_EDITOR_IS_SHARED;
 +
 +	if (itip_organizer_is_user (comp, client))
 +		flags |= COMP_EDITOR_USER_ORG;
 +
 +	editor = memo_editor_new (client, shell, flags);
 +	comp_editor_edit_comp (editor, comp);
 +
 +	g_object_unref (comp);
 +
 +present:
 +	gtk_window_present (GTK_WINDOW (editor));
 +
 +	g_object_unref (source_list);
 +	g_object_unref (client);
 +
 +exit:
 +	g_free (source_uid);
 +	g_free (comp_uid);
 +	g_free (comp_rid);
 +
 +	e_uri_free (euri);
 +
 +	return handled;
 +}
 +
 +static void
 +memo_module_window_created_cb (EShellBackend *shell_backend,
 +                               GtkWindow *window)
 +{
 +	const gchar *module_name;
 +
 +	if (!E_IS_SHELL_WINDOW (window))
 +		return;
 +
 +	module_name = E_SHELL_BACKEND_GET_CLASS (shell_backend)->name;
 +
 +	e_shell_window_register_new_item_actions (
 +		E_SHELL_WINDOW (window), module_name,
 +		item_entries, G_N_ELEMENTS (item_entries));
 +
 +	e_shell_window_register_new_source_actions (
 +		E_SHELL_WINDOW (window), module_name,
 +		source_entries, G_N_ELEMENTS (source_entries));
 +}
 +
 +static void
 +memo_shell_backend_get_property (GObject *object,
 +                                 guint property_id,
 +                                 GValue *value,
 +                                 GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_SOURCE_LIST:
 +			g_value_set_object (
 +				value,
 +				e_memo_shell_backend_get_source_list (
 +				E_MEMO_SHELL_BACKEND (object)));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +memo_shell_backend_dispose (GObject *object)
 +{
 +	EMemoShellBackendPrivate *priv;
 +
 +	priv = E_MEMO_SHELL_BACKEND_GET_PRIVATE (object);
 +
 +	if (priv->source_list != NULL) {
 +		g_object_unref (priv->source_list);
 +		priv->source_list = NULL;
 +	}
 +
 +	/* Chain up to parent's dispose() method. */
 +	G_OBJECT_CLASS (parent_class)->dispose (object);
 +}
 +
 +static void
 +memo_shell_backend_constructed (GObject *object)
 +{
 +	EShell *shell;
 +	EShellBackend *shell_backend;
 +
 +	shell_backend = E_SHELL_BACKEND (object);
 +	shell = e_shell_backend_get_shell (shell_backend);
 +
 +	memo_module_ensure_sources (shell_backend);
 +
 +	g_signal_connect_swapped (
 +		shell, "handle-uri",
 +		G_CALLBACK (memo_module_handle_uri_cb), shell_backend);
 +
 +	g_signal_connect_swapped (
 +		shell, "window-created",
 +		G_CALLBACK (memo_module_window_created_cb), shell_backend);
 +}
 +
 +static void
 +memo_shell_backend_class_init (EMemoShellBackendClass *class)
 +{
 +	GObjectClass *object_class;
 +	EShellBackendClass *shell_backend_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (EMemoShellBackendPrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->get_property = memo_shell_backend_get_property;
 +	object_class->dispose = memo_shell_backend_dispose;
 +	object_class->constructed = memo_shell_backend_constructed;
 +
 +	shell_backend_class = E_SHELL_BACKEND_CLASS (class);
 +	shell_backend_class->shell_view_type = E_TYPE_MEMO_SHELL_VIEW;
 +	shell_backend_class->name = "memos";
 +	shell_backend_class->aliases = "";
 +	shell_backend_class->schemes = "memo";
 +	shell_backend_class->sort_order = 500;
 +	shell_backend_class->start = NULL;
 +	shell_backend_class->is_busy = NULL;
 +	shell_backend_class->shutdown = NULL;
 +	shell_backend_class->migrate = e_memo_shell_backend_migrate;
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_SOURCE_LIST,
 +		g_param_spec_object (
 +			"source-list",
 +			_("Source List"),
 +			_("The registry of memo lists"),
 +			E_TYPE_SOURCE_LIST,
 +			G_PARAM_READABLE));
 +}
 +
 +static void
 +memo_shell_backend_init (EMemoShellBackend *memo_shell_backend)
 +{
 +	memo_shell_backend->priv =
 +		E_MEMO_SHELL_BACKEND_GET_PRIVATE (memo_shell_backend);
 +}
 +
 +GType
 +e_memo_shell_backend_get_type (void)
 +{
 +	return memo_shell_backend_type;
 +}
 +
 +void
 +e_memo_shell_backend_register_type (GTypeModule *type_module)
 +{
 +	const GTypeInfo type_info = {
 +		sizeof (EMemoShellBackendClass),
 +		(GBaseInitFunc) NULL,
 +		(GBaseFinalizeFunc) NULL,
 +		(GClassInitFunc) memo_shell_backend_class_init,
 +		(GClassFinalizeFunc) NULL,
 +		NULL,  /* class_data */
 +		sizeof (EMemoShellBackend),
 +		0,     /* n_preallocs */
 +		(GInstanceInitFunc) memo_shell_backend_init,
 +		NULL   /* value_table */
 +	};
 +
 +	memo_shell_backend_type = g_type_module_register_type (
 +		type_module, E_TYPE_SHELL_BACKEND,
 +		"EMemoShellBackend", &type_info, 0);
 +}
 +
 +ESourceList *
 +e_memo_shell_backend_get_source_list (EMemoShellBackend *memo_shell_backend)
 +{
 +	g_return_val_if_fail (
 +		E_IS_MEMO_SHELL_BACKEND (memo_shell_backend), NULL);
 +
 +	return memo_shell_backend->priv->source_list;
 +}
diff --cc calendar/module/e-memo-shell-backend.h
index 0ffc222,0000000..37fe41a
mode 100644,000000..100644
--- a/calendar/module/e-memo-shell-backend.h
+++ b/calendar/module/e-memo-shell-backend.h
@@@ -1,70 -1,0 +1,70 @@@
 +/*
 + * e-memo-shell-backend.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_MEMO_SHELL_BACKEND_H
 +#define E_MEMO_SHELL_BACKEND_H
 +
 +#include <shell/e-shell-backend.h>
 +#include <libedataserver/e-source-list.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_MEMO_SHELL_BACKEND \
 +	(e_memo_shell_backend_get_type ())
 +#define E_MEMO_SHELL_BACKEND(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_MEMO_SHELL_BACKEND, EMemoShellBackend))
 +#define E_MEMO_SHELL_BACKEND_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_MEMO_SHELL_BACKEND, EMemoShellBackendClass))
 +#define E_IS_MEMO_SHELL_BACKEND(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_MEMO_SHELL_BACKEND))
 +#define E_IS_MEMO_SHELL_BACKEND_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), E_TYPE_MEMO_SHELL_BACKEND))
 +#define E_MEMO_SHELL_BACKEND_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_MEMO_SHELL_BACKEND, EMemoShellBackendClass))
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _EMemoShellBackend EMemoShellBackend;
 +typedef struct _EMemoShellBackendClass EMemoShellBackendClass;
 +typedef struct _EMemoShellBackendPrivate EMemoShellBackendPrivate;
 +
 +struct _EMemoShellBackend {
 +	EShellBackend parent;
 +	EMemoShellBackendPrivate *priv;
 +};
 +
 +struct _EMemoShellBackendClass {
 +	EShellBackendClass parent_class;
 +};
 +
 +GType		e_memo_shell_backend_get_type	(void);
 +void		e_memo_shell_backend_register_type
 +					(GTypeModule *type_module);
 +ESourceList *	e_memo_shell_backend_get_source_list
 +					(EMemoShellBackend *memo_shell_backend);
 +
 +G_END_DECLS
 +
 +#endif /* E_MEMO_SHELL_BACKEND_H */
diff --cc calendar/module/e-memo-shell-content.c
index 4e06448,0000000..ce02015
mode 100644,000000..100644
--- a/calendar/module/e-memo-shell-content.c
+++ b/calendar/module/e-memo-shell-content.c
@@@ -1,676 -1,0 +1,676 @@@
 +/*
 + * e-memo-shell-content.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-memo-shell-content.h"
 +
 +#include <glib/gi18n.h>
 +
 +#include "e-util/gconf-bridge.h"
 +
 +#include "calendar/gui/calendar-config.h"
 +#include "calendar/gui/comp-util.h"
 +#include "calendar/gui/e-cal-model-memos.h"
 +#include "calendar/gui/e-memo-table.h"
 +#include "calendar/gui/e-memo-table-config.h"
 +
 +#include "widgets/menus/gal-view-etable.h"
 +
 +#define E_MEMO_SHELL_CONTENT_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_MEMO_SHELL_CONTENT, EMemoShellContentPrivate))
 +
 +#define E_MEMO_TABLE_DEFAULT_STATE \
 +	"<?xml version=\"1.0\"?>" \
 +	"<ETableState>" \
 +	"  <column source=\"1\"/>" \
 +	"  <column source=\"0\"/>" \
 +	"  <column source=\"2\"/>" \
 +	"  <grouping/>" \
 +	"</ETableState>"
 +
 +struct _EMemoShellContentPrivate {
 +	GtkWidget *paned;
 +	GtkWidget *memo_table;
 +	GtkWidget *memo_preview;
 +
 +	ECalModel *memo_model;
 +	EMemoTableConfig *table_config;
 +	GalViewInstance *view_instance;
 +
 +	gchar *current_uid;
 +};
 +
 +enum {
 +	PROP_0,
 +	PROP_MODEL,
 +	PROP_PREVIEW_VISIBLE
 +};
 +
 +enum {
 +	TARGET_VCALENDAR
 +};
 +
 +static GtkTargetEntry drag_types[] = {
- 	{ "text/calendar", 0, TARGET_VCALENDAR },
- 	{ "text/x-calendar", 0, TARGET_VCALENDAR }
++	{ (gchar *) "text/calendar", 0, TARGET_VCALENDAR },
++	{ (gchar *) "text/x-calendar", 0, TARGET_VCALENDAR }
 +};
 +
 +static gpointer parent_class;
 +static GType memo_shell_content_type;
 +
 +static void
 +memo_shell_content_display_view_cb (EMemoShellContent *memo_shell_content,
 +                                    GalView *gal_view)
 +{
 +	EMemoTable *memo_table;
 +	ETable *table;
 +
 +	if (!GAL_IS_VIEW_ETABLE (gal_view))
 +		return;
 +
 +	memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
 +	table = e_memo_table_get_table (memo_table);
 +
 +	gal_view_etable_attach_table (GAL_VIEW_ETABLE (gal_view), table);
 +}
 +
 +static void
 +memo_shell_content_table_foreach_cb (gint model_row,
 +                                     gpointer user_data)
 +{
 +	ECalModelComponent *comp_data;
 +	icalcomponent *clone;
 +	icalcomponent *vcal;
 +	gchar *string;
 +
 +	struct {
 +		ECalModel *model;
 +		GSList *list;
 +	} *foreach_data = user_data;
 +
 +	comp_data = e_cal_model_get_component_at (
 +		foreach_data->model, model_row);
 +
 +	vcal = e_cal_util_new_top_level ();
 +	clone = icalcomponent_new_clone (comp_data->icalcomp);
 +	e_cal_util_add_timezones_from_component (vcal, comp_data->icalcomp);
 +	icalcomponent_add_component (vcal, clone);
 +
 +	/* String is owned by libical; do not free. */
 +	string = icalcomponent_as_ical_string (vcal);
 +	if (string != NULL) {
 +		ESource *source;
 +		const gchar *source_uid;
 +
 +		source = e_cal_get_source (comp_data->client);
 +		source_uid = e_source_peek_uid (source);
 +
 +		foreach_data->list = g_slist_prepend (
 +			foreach_data->list,
 +			g_strdup_printf ("%s\n%s", source_uid, string));
 +	}
 +
 +	icalcomponent_free (vcal);
 +}
 +
 +static void
 +memo_shell_content_table_drag_data_get_cb (EMemoShellContent *memo_shell_content,
 +                                           gint row,
 +                                           gint col,
 +                                           GdkDragContext *context,
 +                                           GtkSelectionData *selection_data,
 +                                           guint info,
 +                                           guint time)
 +{
 +	EMemoTable *memo_table;
 +	ETable *table;
 +
 +	struct {
 +		ECalModel *model;
 +		GSList *list;
 +	} foreach_data;
 +
 +	if (info != TARGET_VCALENDAR)
 +		return;
 +
 +	memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
 +	table = e_memo_table_get_table (memo_table);
 +
 +	foreach_data.model = e_memo_table_get_model (memo_table);
 +	foreach_data.list = NULL;
 +
 +	e_table_selected_row_foreach (
 +		table, memo_shell_content_table_foreach_cb,
 +		&foreach_data);
 +
 +	if (foreach_data.list != NULL) {
 +		cal_comp_selection_set_string_list (
 +			selection_data, foreach_data.list);
 +		g_slist_foreach (foreach_data.list, (GFunc) g_free, NULL);
 +		g_slist_free (foreach_data.list);
 +	}
 +}
 +
 +static void
 +memo_shell_content_table_drag_data_delete_cb (EMemoShellContent *memo_shell_content,
 +                                              gint row,
 +                                              gint col,
 +                                              GdkDragContext *context)
 +{
 +	/* Moved components are deleted from source immediately when moved,
 +	 * because some of them can be part of destination source, and we
 +	 * don't want to delete not-moved memos.  There is no such information
 +	 * which event has been moved and which not, so skip this method. */
 +}
 +
 +static void
 +memo_shell_content_cursor_change_cb (EMemoShellContent *memo_shell_content,
 +                                     gint row,
 +                                     ETable *table)
 +{
 +	ECalComponentPreview *memo_preview;
 +	EMemoTable *memo_table;
 +	ECalModel *memo_model;
 +	ECalModelComponent *comp_data;
 +	ECalComponent *comp;
 +	const gchar *uid;
 +
 +	memo_model = e_memo_shell_content_get_memo_model (memo_shell_content);
 +	memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
 +	memo_preview = e_memo_shell_content_get_memo_preview (memo_shell_content);
 +
 +	if (e_table_selected_count (table) != 1) {
 +		e_cal_component_preview_clear (memo_preview);
 +		return;
 +	}
 +
 +	row = e_table_get_cursor_row (table);
 +	comp_data = e_cal_model_get_component_at (memo_model, row);
 +
 +	comp = e_cal_component_new ();
 +	e_cal_component_set_icalcomponent (
 +		comp, icalcomponent_new_clone (comp_data->icalcomp));
 +	e_cal_component_preview_display (
 +		memo_preview, comp_data->client, comp);
 +
 +	e_cal_component_get_uid (comp, &uid);
 +	g_free (memo_shell_content->priv->current_uid);
 +	memo_shell_content->priv->current_uid = g_strdup (uid);
 +
 +	g_object_unref (comp);
 +}
 +
 +static void
 +memo_shell_content_selection_change_cb (EMemoShellContent *memo_shell_content,
 +                                        ETable *table)
 +{
 +	ECalComponentPreview *memo_preview;
 +
 +	memo_preview = e_memo_shell_content_get_memo_preview (memo_shell_content);
 +
 +	/* XXX Old code emits a "selection-changed" signal here. */
 +
 +	if (e_table_selected_count (table) != 1)
 +		e_cal_component_preview_clear (memo_preview);
 +}
 +
 +static void
 +memo_shell_content_model_row_changed_cb (EMemoShellContent *memo_shell_content,
 +                                         gint row,
 +                                         ETableModel *model)
 +{
 +	ECalModelComponent *comp_data;
 +	EMemoTable *memo_table;
 +	ETable *table;
 +	const gchar *current_uid;
 +	const gchar *uid;
 +
 +	current_uid = memo_shell_content->priv->current_uid;
 +	if (current_uid == NULL)
 +		return;
 +
 +	comp_data = e_cal_model_get_component_at (E_CAL_MODEL (model), row);
 +	if (comp_data == NULL)
 +		return;
 +
 +	uid = icalcomponent_get_uid (comp_data->icalcomp);
 +	if (g_strcmp0 (uid, current_uid) != 0)
 +		return;
 +
 +	memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
 +	table = e_memo_table_get_table (memo_table);
 +
 +	memo_shell_content_cursor_change_cb (memo_shell_content, 0, table);
 +}
 +
 +static void
 +memo_shell_content_set_property (GObject *object,
 +                                 guint property_id,
 +                                 const GValue *value,
 +                                 GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_PREVIEW_VISIBLE:
 +			e_memo_shell_content_set_preview_visible (
 +				E_MEMO_SHELL_CONTENT (object),
 +				g_value_get_boolean (value));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +memo_shell_content_get_property (GObject *object,
 +                                 guint property_id,
 +                                 GValue *value,
 +                                 GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_MODEL:
 +			g_value_set_object (
 +				value, e_memo_shell_content_get_memo_model (
 +				E_MEMO_SHELL_CONTENT (object)));
 +			return;
 +
 +		case PROP_PREVIEW_VISIBLE:
 +			g_value_set_boolean (
 +				value, e_memo_shell_content_get_preview_visible (
 +				E_MEMO_SHELL_CONTENT (object)));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +memo_shell_content_dispose (GObject *object)
 +{
 +	EMemoShellContentPrivate *priv;
 +
 +	priv = E_MEMO_SHELL_CONTENT_GET_PRIVATE (object);
 +
 +	if (priv->paned != NULL) {
 +		g_object_unref (priv->paned);
 +		priv->paned = NULL;
 +	}
 +
 +	if (priv->memo_table != NULL) {
 +		g_object_unref (priv->memo_table);
 +		priv->memo_table = NULL;
 +	}
 +
 +	if (priv->memo_preview != NULL) {
 +		g_object_unref (priv->memo_preview);
 +		priv->memo_preview = NULL;
 +	}
 +
 +	if (priv->memo_model != NULL) {
 +		g_object_unref (priv->memo_model);
 +		priv->memo_model = NULL;
 +	}
 +
 +	if (priv->table_config != NULL) {
 +		g_object_unref (priv->table_config);
 +		priv->table_config = NULL;
 +	}
 +
 +	if (priv->view_instance != NULL) {
 +		g_object_unref (priv->view_instance);
 +		priv->view_instance = NULL;
 +	}
 +
 +	/* Chain up to parent's dispose() method. */
 +	G_OBJECT_CLASS (parent_class)->dispose (object);
 +}
 +
 +static void
 +memo_shell_content_finalize (GObject *object)
 +{
 +	EMemoShellContentPrivate *priv;
 +
 +	priv = E_MEMO_SHELL_CONTENT_GET_PRIVATE (object);
 +
 +	g_free (priv->current_uid);
 +
 +	/* Chain up to parent's finalize() method. */
 +	G_OBJECT_CLASS (parent_class)->finalize (object);
 +}
 +
 +static void
 +memo_shell_content_constructed (GObject *object)
 +{
 +	EMemoShellContentPrivate *priv;
 +	EShellContent *shell_content;
 +	EShellView *shell_view;
 +	GalViewInstance *view_instance;
 +	ETable *table;
 +	GConfBridge *bridge;
 +	GtkWidget *container;
 +	GtkWidget *widget;
 +	const gchar *key;
 +
 +	priv = E_MEMO_SHELL_CONTENT_GET_PRIVATE (object);
 +
 +	/* Chain up to parent's constructed() method. */
 +	G_OBJECT_CLASS (parent_class)->constructed (object);
 +
 +	shell_content = E_SHELL_CONTENT (object);
 +	shell_view = e_shell_content_get_shell_view (shell_content);
 +
 +	/* Build content widgets. */
 +
 +	container = GTK_WIDGET (object);
 +
 +	widget = gtk_vpaned_new ();
 +	gtk_container_add (GTK_CONTAINER (container), widget);
 +	priv->paned = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	container = widget;
 +
 +	widget = e_memo_table_new (shell_view, priv->memo_model);
 +	gtk_paned_add1 (GTK_PANED (container), widget);
 +	priv->memo_table = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	widget = gtk_scrolled_window_new (NULL, NULL);
 +	gtk_scrolled_window_set_policy (
 +		GTK_SCROLLED_WINDOW (widget),
 +		GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
 +	gtk_scrolled_window_set_shadow_type (
 +		GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
 +	gtk_paned_add2 (GTK_PANED (container), widget);
 +	gtk_widget_show (widget);
 +
 +	container = widget;
 +
 +	widget = e_cal_component_preview_new ();
 +	e_cal_component_preview_set_default_timezone (
 +		E_CAL_COMPONENT_PREVIEW (widget),
 +		calendar_config_get_icaltimezone ());
 +	gtk_container_add (GTK_CONTAINER (container), widget);
 +	priv->memo_preview = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	/* Configure the memo table. */
 +
 +	widget = E_MEMO_TABLE (priv->memo_table)->etable;
 +	table = e_table_scrolled_get_table (E_TABLE_SCROLLED (widget));
 +
 +	priv->table_config = e_memo_table_config_new (
 +		E_MEMO_TABLE (priv->memo_table));
 +
 +	e_table_set_state (table, E_MEMO_TABLE_DEFAULT_STATE);
 +
 +	e_table_drag_source_set (
 +		table, GDK_BUTTON1_MASK,
 +		drag_types, G_N_ELEMENTS (drag_types),
 +		GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_ASK);
 +
 +	g_signal_connect_swapped (
 +		table, "table-drag-data-get",
 +		G_CALLBACK (memo_shell_content_table_drag_data_get_cb),
 +		object);
 +
 +	g_signal_connect_swapped (
 +		table, "table-drag-data-delete",
 +		G_CALLBACK (memo_shell_content_table_drag_data_delete_cb),
 +		object);
 +
 +	g_signal_connect_swapped (
 +		table, "cursor-change",
 +		G_CALLBACK (memo_shell_content_cursor_change_cb),
 +		object);
 +
 +	g_signal_connect_swapped (
 +		table, "selection-change",
 +		G_CALLBACK (memo_shell_content_selection_change_cb),
 +		object);
 +
 +	g_signal_connect_swapped (
 +		priv->memo_model, "model-row-changed",
 +		G_CALLBACK (memo_shell_content_model_row_changed_cb),
 +		object);
 +
 +	/* Load the view instance. */
 +
 +	view_instance = e_shell_view_new_view_instance (shell_view, NULL);
 +	g_signal_connect_swapped (
 +		view_instance, "display-view",
 +		G_CALLBACK (memo_shell_content_display_view_cb),
 +		object);
 +	gal_view_instance_load (view_instance);
 +	priv->view_instance = view_instance;
 +
 +	/* Bind GObject properties to GConf keys. */
 +
 +	bridge = gconf_bridge_get ();
 +
 +	object = G_OBJECT (priv->paned);
 +	key = "/apps/evolution/calendar/display/memo_vpane_position";
 +	gconf_bridge_bind_property_delayed (bridge, key, object, "position");
 +}
 +
 +static guint32
 +memo_shell_content_check_state (EShellContent *shell_content)
 +{
 +	EMemoShellContent *memo_shell_content;
 +	EMemoTable *memo_table;
 +	ETable *table;
 +	GSList *list, *iter;
 +	gboolean editable = TRUE;
 +	gboolean has_url = FALSE;
 +	gint n_selected;
 +	guint32 state = 0;
 +
 +	memo_shell_content = E_MEMO_SHELL_CONTENT (shell_content);
 +	memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
 +
 +	table = e_memo_table_get_table (memo_table);
 +	n_selected = e_table_selected_count (table);
 +
 +	list = e_memo_table_get_selected (memo_table);
 +	for (iter = list; iter != NULL; iter = iter->next) {
 +		ECalModelComponent *comp_data = iter->data;
 +		icalproperty *prop;
 +		gboolean read_only;
 +
 +		e_cal_is_read_only (comp_data->client, &read_only, NULL);
 +		editable &= !read_only;
 +
 +		prop = icalcomponent_get_first_property (
 +			comp_data->icalcomp, ICAL_URL_PROPERTY);
 +		has_url |= (prop != NULL);
 +	}
 +	g_slist_free (list);
 +
 +	if (n_selected == 1)
 +		state |= E_MEMO_SHELL_CONTENT_SELECTION_SINGLE;
 +	if (n_selected > 1)
 +		state |= E_MEMO_SHELL_CONTENT_SELECTION_MULTIPLE;
 +	if (editable)
 +		state |= E_MEMO_SHELL_CONTENT_SELECTION_CAN_EDIT;
 +	if (has_url)
 +		state |= E_MEMO_SHELL_CONTENT_SELECTION_HAS_URL;
 +
 +	return state;
 +}
 +
 +static void
 +memo_shell_content_class_init (EMemoShellContentClass *class)
 +{
 +	GObjectClass *object_class;
 +	EShellContentClass *shell_content_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (EMemoShellContentPrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->set_property = memo_shell_content_set_property;
 +	object_class->get_property = memo_shell_content_get_property;
 +	object_class->dispose = memo_shell_content_dispose;
 +	object_class->finalize = memo_shell_content_finalize;
 +	object_class->constructed = memo_shell_content_constructed;
 +
 +	shell_content_class = E_SHELL_CONTENT_CLASS (class);
 +	shell_content_class->check_state = memo_shell_content_check_state;
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_MODEL,
 +		g_param_spec_object (
 +			"model",
 +			_("Model"),
 +			_("The memo table model"),
 +			E_TYPE_CAL_MODEL,
 +			G_PARAM_READABLE));
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_PREVIEW_VISIBLE,
 +		g_param_spec_boolean (
 +			"preview-visible",
 +			_("Preview is Visible"),
 +			_("Whether the preview pane is visible"),
 +			TRUE,
 +			G_PARAM_READWRITE));
 +}
 +
 +static void
 +memo_shell_content_init (EMemoShellContent *memo_shell_content)
 +{
 +	memo_shell_content->priv =
 +		E_MEMO_SHELL_CONTENT_GET_PRIVATE (memo_shell_content);
 +
 +	memo_shell_content->priv->memo_model = e_cal_model_memos_new ();
 +
 +	/* Postpone widget construction until we have a shell view. */
 +}
 +
 +GType
 +e_memo_shell_content_get_type (void)
 +{
 +	return memo_shell_content_type;
 +}
 +
 +void
 +e_memo_shell_content_register_type (GTypeModule *type_module)
 +{
 +	static const GTypeInfo type_info = {
 +		sizeof (EMemoShellContentClass),
 +		(GBaseInitFunc) NULL,
 +		(GBaseFinalizeFunc) NULL,
 +		(GClassInitFunc) memo_shell_content_class_init,
 +		(GClassFinalizeFunc) NULL,
 +		NULL,  /* class_data */
 +		sizeof (EMemoShellContent),
 +		0,     /* n_preallocs */
 +		(GInstanceInitFunc) memo_shell_content_init,
 +		NULL   /* value_table */
 +	};
 +
 +	memo_shell_content_type = g_type_module_register_type (
 +		type_module, E_TYPE_SHELL_CONTENT,
 +		"EMemoShellContent", &type_info, 0);
 +}
 +
 +GtkWidget *
 +e_memo_shell_content_new (EShellView *shell_view)
 +{
 +	g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
 +
 +	return g_object_new (
 +		E_TYPE_MEMO_SHELL_CONTENT,
 +		"shell-view", shell_view, NULL);
 +}
 +
 +ECalModel *
 +e_memo_shell_content_get_memo_model (EMemoShellContent *memo_shell_content)
 +{
 +	g_return_val_if_fail (
 +		E_IS_MEMO_SHELL_CONTENT (memo_shell_content), NULL);
 +
 +	return memo_shell_content->priv->memo_model;
 +}
 +
 +ECalComponentPreview *
 +e_memo_shell_content_get_memo_preview (EMemoShellContent *memo_shell_content)
 +{
 +	g_return_val_if_fail (
 +		E_IS_MEMO_SHELL_CONTENT (memo_shell_content), NULL);
 +
 +	return E_CAL_COMPONENT_PREVIEW (
 +		memo_shell_content->priv->memo_preview);
 +}
 +
 +EMemoTable *
 +e_memo_shell_content_get_memo_table (EMemoShellContent *memo_shell_content)
 +{
 +	g_return_val_if_fail (
 +		E_IS_MEMO_SHELL_CONTENT (memo_shell_content), NULL);
 +
 +	return E_MEMO_TABLE (memo_shell_content->priv->memo_table);
 +}
 +
 +GalViewInstance *
 +e_memo_shell_content_get_view_instance (EMemoShellContent *memo_shell_content)
 +{
 +	g_return_val_if_fail (
 +		E_IS_MEMO_SHELL_CONTENT (memo_shell_content), NULL);
 +
 +	return memo_shell_content->priv->view_instance;
 +}
 +
 +gboolean
 +e_memo_shell_content_get_preview_visible (EMemoShellContent *memo_shell_content)
 +{
 +	GtkPaned *paned;
 +	GtkWidget *child;
 +
 +	g_return_val_if_fail (
 +		E_IS_MEMO_SHELL_CONTENT (memo_shell_content), FALSE);
 +
 +	paned = GTK_PANED (memo_shell_content->priv->paned);
 +	child = gtk_paned_get_child2 (paned);
 +
 +	return GTK_WIDGET_VISIBLE (child);
 +}
 +
 +void
 +e_memo_shell_content_set_preview_visible (EMemoShellContent *memo_shell_content,
 +                                          gboolean preview_visible)
 +{
 +	GtkPaned *paned;
 +	GtkWidget *child;
 +
 +	g_return_if_fail (E_IS_MEMO_SHELL_CONTENT (memo_shell_content));
 +
 +	paned = GTK_PANED (memo_shell_content->priv->paned);
 +	child = gtk_paned_get_child2 (paned);
 +
 +	if (preview_visible)
 +		gtk_widget_show (child);
 +	else
 +		gtk_widget_hide (child);
 +
 +	g_object_notify (G_OBJECT (memo_shell_content), "preview-visible");
 +}
diff --cc calendar/module/e-memo-shell-content.h
index ace932c,0000000..84c22d6
mode 100644,000000..100644
--- a/calendar/module/e-memo-shell-content.h
+++ b/calendar/module/e-memo-shell-content.h
@@@ -1,96 -1,0 +1,96 @@@
 +/*
 + * e-memo-shell-content.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_MEMO_SHELL_CONTENT_H
 +#define E_MEMO_SHELL_CONTENT_H
 +
 +#include <shell/e-shell-content.h>
 +#include <shell/e-shell-view.h>
 +
 +#include <calendar/gui/e-memo-table.h>
 +#include <calendar/gui/e-cal-component-preview.h>
 +
 +#include <menus/gal-view-instance.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_MEMO_SHELL_CONTENT \
 +	(e_memo_shell_content_get_type ())
 +#define E_MEMO_SHELL_CONTENT(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_MEMO_SHELL_CONTENT, EMemoShellContent))
 +#define E_MEMO_SHELL_CONTENT_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_MEMO_SHELL_CONTENT, EMemoShellContentClass))
 +#define E_IS_MEMO_SHELL_CONTENT(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_MEMO_SHELL_CONTENT))
 +#define E_IS_MEMO_SHELL_CONTENT_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), E_TYPE_MEMO_SHELL_CONTENT))
 +#define E_MEMO_SHELL_CONTENT_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_MEMO_SHELL_CONTENT, EMemoShellContentClass))
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _EMemoShellContent EMemoShellContent;
 +typedef struct _EMemoShellContentClass EMemoShellContentClass;
 +typedef struct _EMemoShellContentPrivate EMemoShellContentPrivate;
 +
 +enum {
 +	E_MEMO_SHELL_CONTENT_SELECTION_SINGLE		= 1 << 0,
 +	E_MEMO_SHELL_CONTENT_SELECTION_MULTIPLE		= 1 << 1,
 +	E_MEMO_SHELL_CONTENT_SELECTION_CAN_EDIT		= 1 << 2,
 +	E_MEMO_SHELL_CONTENT_SELECTION_HAS_URL		= 1 << 3
 +};
 +
 +struct _EMemoShellContent {
 +	EShellContent parent;
 +	EMemoShellContentPrivate *priv;
 +};
 +
 +struct _EMemoShellContentClass {
 +	EShellContentClass parent_class;
 +};
 +
 +GType		e_memo_shell_content_get_type	(void);
 +void		e_memo_shell_content_register_type
 +					(GTypeModule *type_module);
 +GtkWidget *	e_memo_shell_content_new(EShellView *shell_view);
 +ECalModel *	e_memo_shell_content_get_memo_model
 +					(EMemoShellContent *memo_shell_conent);
 +ECalComponentPreview *
 +		e_memo_shell_content_get_memo_preview
 +					(EMemoShellContent *memo_shell_content);
 +EMemoTable *	e_memo_shell_content_get_memo_table
 +					(EMemoShellContent *memo_shell_content);
 +GalViewInstance *
 +		e_memo_shell_content_get_view_instance
 +					(EMemoShellContent *memo_shell_content);
 +gboolean	e_memo_shell_content_get_preview_visible
 +					(EMemoShellContent *memo_shell_content);
 +void		e_memo_shell_content_set_preview_visible
 +					(EMemoShellContent *memo_shell_content,
 +					 gboolean preview_visible);
 +
 +G_END_DECLS
 +
 +#endif /* E_MEMO_SHELL_CONTENT_H */
diff --cc calendar/module/e-memo-shell-migrate.c
index 763d366,0000000..de40a7e
mode 100644,000000..100644
--- a/calendar/module/e-memo-shell-migrate.c
+++ b/calendar/module/e-memo-shell-migrate.c
@@@ -1,257 -1,0 +1,257 @@@
 +/*
 + * e-memo-shell-migrate.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-memo-shell-migrate.h"
 +
 +#include <string.h>
 +#include <glib/gi18n.h>
 +#include <camel/camel-url.h>
 +#include <libedataserver/e-account.h>
 +#include <libedataserver/e-account-list.h>
 +#include <libedataserver/e-source.h>
 +#include <libedataserver/e-source-group.h>
 +#include <libedataserver/e-source-list.h>
 +
 +#include "calendar/gui/calendar-config.h"
 +#include "calendar/gui/calendar-config-keys.h"
 +
 +#define WEBCAL_BASE_URI "webcal://"
 +#define PERSONAL_RELATIVE_URI "system"
 +#define GROUPWISE_BASE_URI "groupwise://"
 +
 +static void
 +create_memo_sources (EShellBackend *shell_backend,
 +		     ESourceList *source_list,
 +		     ESourceGroup **on_this_computer,
 +		     ESourceGroup **on_the_web,
 +		     ESource **personal_source)
 +{
 +	GSList *groups;
 +	ESourceGroup *group;
 +	char *base_uri, *base_uri_proto;
 +	const gchar *base_dir;
 +
 +	*on_this_computer = NULL;
 +	*on_the_web = NULL;
 +	*personal_source = NULL;
 +
 +	base_dir = e_shell_backend_get_config_dir (shell_backend);
 +	base_uri = g_build_filename (base_dir, "local", NULL);
 +
 +	base_uri_proto = g_filename_to_uri (base_uri, NULL, NULL);
 +
 +	groups = e_source_list_peek_groups (source_list);
 +	if (groups) {
 +		/* groups are already there, we need to search for things... */
 +		GSList *g;
 +
 +		for (g = groups; g; g = g->next) {
 +
 +			group = E_SOURCE_GROUP (g->data);
 +
 +			if (!*on_this_computer && !strcmp (base_uri_proto, e_source_group_peek_base_uri (group)))
 +				*on_this_computer = g_object_ref (group);
 +			else if (!*on_the_web && !strcmp (WEBCAL_BASE_URI, e_source_group_peek_base_uri (group)))
 +				*on_the_web = g_object_ref (group);
 +		}
 +	}
 +
 +	if (*on_this_computer) {
 +		/* make sure "Personal" shows up as a source under
 +		   this group */
 +		GSList *sources = e_source_group_peek_sources (*on_this_computer);
 +		GSList *s;
 +		for (s = sources; s; s = s->next) {
 +			ESource *source = E_SOURCE (s->data);
 +			const gchar *relative_uri;
 +
 +			relative_uri = e_source_peek_relative_uri (source);
 +			if (relative_uri == NULL)
 +				continue;
 +			if (!strcmp (PERSONAL_RELATIVE_URI, relative_uri)) {
 +				*personal_source = g_object_ref (source);
 +				break;
 +			}
 +		}
 +	} else {
 +		/* create the local source group */
 +		group = e_source_group_new (_("On This Computer"), base_uri_proto);
 +		e_source_list_add_group (source_list, group, -1);
 +
 +		*on_this_computer = group;
 +	}
 +
 +	if (!*personal_source) {
 +		/* Create the default Person task list */
 +		ESource *source = e_source_new (_("Personal"), PERSONAL_RELATIVE_URI);
 +		e_source_group_add_source (*on_this_computer, source, -1);
 +
 +		if (!calendar_config_get_primary_memos () && !calendar_config_get_memos_selected ()) {
 +			GSList selected;
 +
 +			calendar_config_set_primary_memos (e_source_peek_uid (source));
 +
 +			selected.data = (gpointer)e_source_peek_uid (source);
 +			selected.next = NULL;
 +			calendar_config_set_memos_selected (&selected);
 +		}
 +
 +		e_source_set_color_spec (source, "#BECEDD");
 +		*personal_source = source;
 +	}
 +
 +	if (!*on_the_web) {
 +		/* Create the Webcal source group */
 +		group = e_source_group_new (_("On The Web"), WEBCAL_BASE_URI);
 +		e_source_list_add_group (source_list, group, -1);
 +
 +		*on_the_web = group;
 +	}
 +
 +	g_free (base_uri_proto);
 +	g_free (base_uri);
 +}
 +
 +static gboolean
 +is_groupwise_account (EAccount *account)
 +{
 +	if (account->source->url != NULL) {
 +		return g_str_has_prefix (account->source->url, GROUPWISE_BASE_URI);
 +	} else {
 +		return FALSE;
 +	}
 +}
 +
 +static void
 +add_gw_esource (ESourceList *source_list, const char *group_name,  const char *source_name, CamelURL *url, GConfClient *client)
 +{
 +	ESourceGroup *group;
 +	ESource *source;
 +	GSList *ids, *temp ;
 +	GError *error = NULL;
 +	char *relative_uri;
 +	const char *soap_port;
 +	const char * use_ssl;
 +	const char *poa_address;
 +	const char *offline_sync;
 +
 +
 +	poa_address = url->host;
 +	if (!poa_address || strlen (poa_address) ==0)
 +		return;
 +	soap_port = camel_url_get_param (url, "soap_port");
 +
 + 	if (!soap_port || strlen (soap_port) == 0)
 +		soap_port = "7191";
 +
 +	use_ssl = camel_url_get_param (url, "use_ssl");
 +	offline_sync = camel_url_get_param (url, "offline_sync");
 +
 +	group = e_source_group_new (group_name,  GROUPWISE_BASE_URI);
 +	if (!e_source_list_add_group (source_list, group, -1))
 +		return;
 +	relative_uri = g_strdup_printf ("%s %s/", url->user, poa_address);
 +
 +	source = e_source_new (source_name, relative_uri);
 +	e_source_set_property (source, "auth", "1");
 +	e_source_set_property (source, "username", url->user);
 +	e_source_set_property (source, "port", camel_url_get_param (url, "soap_port"));
 +	e_source_set_property (source, "auth-domain", "Groupwise");
 +	e_source_set_property (source, "use_ssl", use_ssl);
 +	e_source_set_property (source, "offline_sync", offline_sync ? "1" : "0" );
 +
 +	e_source_set_color_spec (source, "#EEBC60");
 +	e_source_group_add_source (group, source, -1);
 +
 +	ids = gconf_client_get_list (client, CALENDAR_CONFIG_MEMOS_SELECTED_MEMOS, GCONF_VALUE_STRING, &error);
 +	if ( error != NULL ) {
 +		g_warning("%s (%s) %s\n", G_STRLOC, G_STRFUNC, error->message);
 +		g_error_free(error);
 +	}
 +	ids = g_slist_append (ids, g_strdup (e_source_peek_uid (source)));
 +	gconf_client_set_list (client, CALENDAR_CONFIG_MEMOS_SELECTED_MEMOS, GCONF_VALUE_STRING, ids, NULL);
 +	temp  = ids;
 +	for (; temp != NULL; temp = g_slist_next (temp))
 +		g_free (temp->data);
 +
 +	g_slist_free (ids);
 +	g_object_unref (source);
 +	g_object_unref (group);
 +	g_free (relative_uri);
 +}
 +
 +gboolean
 +e_memo_shell_backend_migrate (EShellBackend *shell_backend,
 +                             gint major,
 +                             gint minor,
 +                             gint revision,
 +                             GError **error)
 +{
 +	ESourceGroup *on_this_computer = NULL;
 +	ESourceGroup *on_the_web = NULL;
 +	ESource *personal_source = NULL;
 +	ESourceList *source_list = NULL;
 +	gboolean retval = FALSE;
 +
 +	source_list = g_object_get_data (
 +		G_OBJECT (shell_backend), "source-list");
 +
 +	/* we call this unconditionally now - create_groups either
 +	   creates the groups/sources or it finds the necessary
 +	   groups/sources. */
 +	create_memo_sources (
 +		shell_backend, source_list, &on_this_computer,
 +		&on_the_web, &personal_source);
 +
 +	/* Migration for Gw accounts between versions < 2.8 */
 +	if (major == 2 && minor < 8) {
 +		EAccountList *al;
 +		EAccount *a;
 +		CamelURL *url;
 +		EIterator *it;
 +		GConfClient *gconf_client = gconf_client_get_default ();
 +		al = e_account_list_new (gconf_client);
 +		for (it = e_list_get_iterator((EList *)al);
 +				e_iterator_is_valid(it);
 +				e_iterator_next(it)) {
 +			a = (EAccount *) e_iterator_get(it);
 +			if (!a->enabled || !is_groupwise_account (a))
 +				continue;
 +			url = camel_url_new (a->source->url, NULL);
 +			add_gw_esource (source_list, a->name, _("Notes"), url, gconf_client);
 +			camel_url_free (url);
 +		}
 +		g_object_unref (al);
 +		g_object_unref (gconf_client);
 +	}
 +
 +	e_source_list_sync (source_list, NULL);
 +	retval = TRUE;
 +
 +	if (on_this_computer)
 +		g_object_unref (on_this_computer);
 +	if (on_the_web)
 +		g_object_unref (on_the_web);
 +	if (personal_source)
 +		g_object_unref (personal_source);
 +
 +        return retval;
 +}
diff --cc calendar/module/e-memo-shell-migrate.h
index 26139ed,0000000..ba163c6
mode 100644,000000..100644
--- a/calendar/module/e-memo-shell-migrate.h
+++ b/calendar/module/e-memo-shell-migrate.h
@@@ -1,38 -1,0 +1,38 @@@
 +/*
 + * e-memo-shell-backend-migrate.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_MEMO_SHELL_BACKEND_MIGRATE_H
 +#define E_MEMO_SHELL_BACKEND_MIGRATE_H
 +
 +#include <glib.h>
 +#include <shell/e-shell-backend.h>
 +
 +G_BEGIN_DECLS
 +
 +gboolean	e_memo_shell_backend_migrate	(EShellBackend *shell_backend,
 +						 gint major,
 +						 gint minor,
 +						 gint micro,
 +						 GError **error);
 +
 +G_END_DECLS
 +
 +#endif /* E_MEMO_SHELL_BACKEND_MIGRATE_H */
diff --cc calendar/module/e-memo-shell-sidebar.c
index 5d5c6a7,0000000..ca5d05c
mode 100644,000000..100644
--- a/calendar/module/e-memo-shell-sidebar.c
+++ b/calendar/module/e-memo-shell-sidebar.c
@@@ -1,718 -1,0 +1,718 @@@
 +/*
 + * e-memo-shell-sidebar.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-memo-shell-sidebar.h"
 +
 +#include <string.h>
 +#include <glib/gi18n.h>
 +#include <libecal/e-cal.h>
 +
 +#include "e-util/e-error.h"
 +#include "e-util/e-util.h"
 +#include "calendar/common/authentication.h"
 +#include "calendar/gui/calendar-config.h"
 +#include "calendar/gui/e-memo-list-selector.h"
 +#include "calendar/gui/misc.h"
 +
 +#include "e-memo-shell-view.h"
 +#include "e-memo-shell-backend.h"
 +
 +#define E_MEMO_SHELL_SIDEBAR_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_MEMO_SHELL_SIDEBAR, EMemoShellSidebarPrivate))
 +
 +struct _EMemoShellSidebarPrivate {
 +	GtkWidget *selector;
 +
 +	/* UID -> Client */
 +	GHashTable *client_table;
 +};
 +
 +enum {
 +	PROP_0,
 +	PROP_SELECTOR
 +};
 +
 +enum {
 +	CLIENT_ADDED,
 +	CLIENT_REMOVED,
 +	STATUS_MESSAGE,
 +	LAST_SIGNAL
 +};
 +
 +static gpointer parent_class;
 +static guint signals[LAST_SIGNAL];
 +static GType memo_shell_sidebar_type;
 +
 +static void
 +memo_shell_sidebar_emit_client_added (EMemoShellSidebar *memo_shell_sidebar,
 +                                      ECal *client)
 +{
 +	guint signal_id = signals[CLIENT_ADDED];
 +
 +	g_signal_emit (memo_shell_sidebar, signal_id, 0, client);
 +}
 +
 +static void
 +memo_shell_sidebar_emit_client_removed (EMemoShellSidebar *memo_shell_sidebar,
 +                                        ECal *client)
 +{
 +	guint signal_id = signals[CLIENT_REMOVED];
 +
 +	g_signal_emit (memo_shell_sidebar, signal_id, 0, client);
 +}
 +
 +static void
 +memo_shell_sidebar_emit_status_message (EMemoShellSidebar *memo_shell_sidebar,
 +                                        const gchar *status_message)
 +{
 +	guint signal_id = signals[STATUS_MESSAGE];
 +
 +	g_signal_emit (memo_shell_sidebar, signal_id, 0, status_message, -1.0);
 +}
 +
 +static void
 +memo_shell_sidebar_update_timezone (EMemoShellSidebar *memo_shell_sidebar)
 +{
 +	GHashTable *client_table;
 +	icaltimezone *zone;
 +	GList *values;
 +
 +	zone = calendar_config_get_icaltimezone ();
 +	client_table = memo_shell_sidebar->priv->client_table;
 +	values = g_hash_table_get_values (client_table);
 +
 +	while (values != NULL) {
 +		ECal *client = values->data;
 +
 +		if (e_cal_get_load_state (client) == E_CAL_LOAD_LOADED)
 +			e_cal_set_default_timezone (client, zone, NULL);
 +
 +		values = g_list_delete_link (values, values);
 +	}
 +
 +	/* XXX Need to call e_cal_component_preview_set_default_timezone()
 +	 *     here but the sidebar is not really supposed to access content
 +	 *     stuff.  I guess we could emit an "update-timezone" signal
 +	 *     here, but that feels wrong.  Maybe this whole thing should
 +	 *     be in EMemoShellView instead. */
 +}
 +
 +static void
 +memo_shell_sidebar_backend_died_cb (EMemoShellSidebar *memo_shell_sidebar,
 +                                    ECal *client)
 +{
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	EShellSidebar *shell_sidebar;
 +	GHashTable *client_table;
 +	ESource *source;
 +	const gchar *uid;
 +
 +	client_table = memo_shell_sidebar->priv->client_table;
 +
 +	shell_sidebar = E_SHELL_SIDEBAR (memo_shell_sidebar);
 +	shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	source = e_cal_get_source (client);
 +	uid = e_source_peek_uid (source);
 +
 +	g_object_ref (source);
 +
 +	g_hash_table_remove (client_table, uid);
 +	memo_shell_sidebar_emit_status_message (memo_shell_sidebar, NULL);
 +
 +	e_error_run (
 +		GTK_WINDOW (shell_window),
 +		"calendar:memos-crashed", NULL);
 +
 +	g_object_unref (source);
 +}
 +
 +static void
 +memo_shell_sidebar_backend_error_cb (EMemoShellSidebar *memo_shell_sidebar,
 +                                     const gchar *message,
 +                                     ECal *client)
 +{
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	EShellSidebar *shell_sidebar;
 +	GtkWidget *dialog;
 +	const gchar *uri;
 +	gchar *uri_no_passwd;
 +
 +	shell_sidebar = E_SHELL_SIDEBAR (memo_shell_sidebar);
 +	shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	uri = e_cal_get_uri (client);
 +	uri_no_passwd = get_uri_without_password (uri);
 +
 +	dialog = gtk_message_dialog_new (
 +		GTK_WINDOW (shell_window),
 +		GTK_DIALOG_DESTROY_WITH_PARENT,
 +		GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
 +		_("Error on %s\n%s"),
 +		uri_no_passwd, message);
 +
 +	gtk_dialog_run (GTK_DIALOG (dialog));
 +	gtk_widget_destroy (dialog);
 +
 +	g_free (uri_no_passwd);
 +}
 +
 +static void
 +memo_shell_sidebar_client_opened_cb (EMemoShellSidebar *memo_shell_sidebar,
 +                                     ECalendarStatus status,
 +                                     ECal *client)
 +{
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	EShellSidebar *shell_sidebar;
 +	ESource *source;
 +
 +	source = e_cal_get_source (client);
 +
 +	shell_sidebar = E_SHELL_SIDEBAR (memo_shell_sidebar);
 +	shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	if (status == E_CALENDAR_STATUS_AUTHENTICATION_FAILED ||
 +		status == E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED)
 +		auth_cal_forget_password (client);
 +
 +	switch (status) {
 +		case E_CALENDAR_STATUS_OK:
 +			g_signal_handlers_disconnect_matched (
 +				client, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
 +				memo_shell_sidebar_client_opened_cb, NULL);
 +
 +			memo_shell_sidebar_emit_status_message (
 +				memo_shell_sidebar, _("Loading memos"));
 +			memo_shell_sidebar_emit_client_added (
 +				memo_shell_sidebar, client);
 +			memo_shell_sidebar_emit_status_message (
 +				memo_shell_sidebar, NULL);
 +			break;
 +
 +		case E_CALENDAR_STATUS_AUTHENTICATION_FAILED:
 +			e_cal_open_async (client, FALSE);
 +			break;
 +
 +		case E_CALENDAR_STATUS_BUSY:
 +			break;
 +
 +		case E_CALENDAR_STATUS_REPOSITORY_OFFLINE:
 +			e_error_run (
 +				GTK_WINDOW (shell_window),
 +				"calendar:prompt-no-contents-offline-memos",
 +				NULL);
 +			break;
 +
 +		default:
 +			memo_shell_sidebar_emit_client_removed (
 +				memo_shell_sidebar, client);
 +			break;
 +	}
 +}
 +
 +static void
 +memo_shell_sidebar_row_changed_cb (EMemoShellSidebar *memo_shell_sidebar,
 +                                   GtkTreePath *tree_path,
 +                                   GtkTreeIter *tree_iter,
 +                                   GtkTreeModel *tree_model)
 +{
 +	ESourceSelector *selector;
 +	ESource *source;
 +
 +	/* XXX ESourceSelector's underlying tree store has only one
 +	 *     column: ESource objects.  While we're not supposed to
 +	 *     know this, listening for "row-changed" signals from
 +	 *     the model is easier to deal with than the selector's
 +	 *     "selection-changed" signal, which doesn't tell you
 +	 *     _which_ row changed. */
 +
 +	selector = e_memo_shell_sidebar_get_selector (memo_shell_sidebar);
 +	gtk_tree_model_get (tree_model, tree_iter, 0, &source, -1);
 +
 +	/* XXX This signal gets emitted a lot while the model is being
 +	 *     rebuilt, during which time we won't get a valid ESource.
 +	 *     ESourceSelector should probably block this signal while
 +	 *     rebuilding the model, but we'll be forgiving and not
 +	 *     emit a warning. */
 +	if (!E_IS_SOURCE (source))
 +		return;
 +
 +	if (e_source_selector_source_is_selected (selector, source))
 +		e_memo_shell_sidebar_add_source (memo_shell_sidebar, source);
 +	else
 +		e_memo_shell_sidebar_remove_source (memo_shell_sidebar, source);
 +}
 +
 +static void
 +memo_shell_sidebar_selection_changed_cb (EMemoShellSidebar *memo_shell_sidebar,
 +                                         ESourceSelector *selector)
 +{
 +	GSList *list, *iter;
 +
 +	/* This signal is emitted less frequently than "row-changed",
 +	 * especially when the model is being rebuilt.  So we'll take
 +	 * it easy on poor GConf. */
 +
 +	list = e_source_selector_get_selection (selector);
 +
 +	for (iter = list; iter != NULL; iter = iter->next) {
 +		ESource *source = iter->data;
 +
 +		iter->data = (gpointer) e_source_peek_uid (source);
 +		g_object_unref (source);
 +	}
 +
 +	calendar_config_set_memos_selected (list);
 +
 +	g_slist_free (list);
 +}
 +
 +static void
 +memo_shell_sidebar_primary_selection_changed_cb (EMemoShellSidebar *memo_shell_sidebar,
 +                                                 ESourceSelector *selector)
 +{
 +	ESource *source;
 +	const gchar *uid;
 +
 +	/* XXX ESourceSelector needs a "primary-selection-uid" property
 +	 *     so we can just bind the property with GConfBridge. */
 +
 +	source = e_source_selector_peek_primary_selection (selector);
 +	if (source == NULL)
 +		return;
 +
 +	uid = e_source_peek_uid (source);
 +	calendar_config_set_primary_memos (uid);
 +}
 +
 +static void
 +memo_shell_sidebar_get_property (GObject *object,
 +                                 guint property_id,
 +                                 GValue *value,
 +                                 GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_SELECTOR:
 +			g_value_set_object (
 +				value, e_memo_shell_sidebar_get_selector (
 +				E_MEMO_SHELL_SIDEBAR (object)));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +memo_shell_sidebar_dispose (GObject *object)
 +{
 +	EMemoShellSidebarPrivate *priv;
 +
 +	priv = E_MEMO_SHELL_SIDEBAR_GET_PRIVATE (object);
 +
 +	if (priv->selector != NULL) {
 +		g_object_unref (priv->selector);
 +		priv->selector = NULL;
 +	}
 +
 +	g_hash_table_remove_all (priv->client_table);
 +
 +	/* Chain up to parent's dispose() method. */
 +	G_OBJECT_CLASS (parent_class)->dispose (object);
 +}
 +
 +static void
 +memo_shell_sidebar_finalize (GObject *object)
 +{
 +	EMemoShellSidebarPrivate *priv;
 +
 +	priv = E_MEMO_SHELL_SIDEBAR_GET_PRIVATE (object);
 +
 +	g_hash_table_destroy (priv->client_table);
 +
 +	/* Chain up to parent's finalize() method. */
 +	G_OBJECT_CLASS (parent_class)->finalize (object);
 +}
 +
 +static void
 +memo_shell_sidebar_constructed (GObject *object)
 +{
 +	EMemoShellSidebarPrivate *priv;
 +	EShellView *shell_view;
 +	EShellBackend *shell_backend;
 +	EShellSidebar *shell_sidebar;
 +	ESourceSelector *selector;
 +	ESourceList *source_list;
 +	ESource *source;
 +	GtkContainer *container;
 +	GtkTreeModel *model;
 +	GtkWidget *widget;
 +	AtkObject *a11y;
 +	GSList *list, *iter;
 +	gchar *uid;
 +
 +	priv = E_MEMO_SHELL_SIDEBAR_GET_PRIVATE (object);
 +
 +	/* Chain up to parent's constructed() method. */
 +	G_OBJECT_CLASS (parent_class)->constructed (object);
 +
 +	shell_sidebar = E_SHELL_SIDEBAR (object);
 +	shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
 +	shell_backend = e_shell_view_get_shell_backend (shell_view);
 +
 +	source_list = e_memo_shell_backend_get_source_list (
 +		E_MEMO_SHELL_BACKEND (shell_backend));
 +
 +	container = GTK_CONTAINER (shell_sidebar);
 +
 +	widget = gtk_scrolled_window_new (NULL, NULL);
 +	gtk_scrolled_window_set_policy (
 +		GTK_SCROLLED_WINDOW (widget),
 +		GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
 +	gtk_scrolled_window_set_shadow_type (
 +		GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
 +	gtk_container_add (container, widget);
 +	gtk_widget_show (widget);
 +
 +	container = GTK_CONTAINER (widget);
 +
 +	widget = e_memo_list_selector_new (source_list);
 +	e_source_selector_set_select_new (E_SOURCE_SELECTOR (widget), TRUE);
 +	gtk_container_add (container, widget);
 +	a11y = gtk_widget_get_accessible (widget);
 +	atk_object_set_name (a11y, _("Memo List Selector"));
 +	priv->selector = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	/* Restore the selector state from the last session. */
 +
 +	selector = E_SOURCE_SELECTOR (priv->selector);
 +	model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
 +
 +	g_signal_connect_swapped (
 +		model, "row-changed",
 +		G_CALLBACK (memo_shell_sidebar_row_changed_cb),
 +		object);
 +
 +	source = NULL;
 +	uid = calendar_config_get_primary_memos ();
 +	if (uid != NULL)
 +		source = e_source_list_peek_source_by_uid (source_list, uid);
 +	if (source == NULL)
 +		source = e_source_list_peek_source_any (source_list);
 +	if (source != NULL)
 +		e_source_selector_set_primary_selection (selector, source);
 +	g_free (uid);
 +
 +	list = calendar_config_get_memos_selected ();
 +	for (iter = list; iter != NULL; iter = iter->next) {
 +		uid = iter->data;
 +		source = e_source_list_peek_source_by_uid (source_list, uid);
 +		g_free (uid);
 +
 +		if (source == NULL)
 +			continue;
 +
 +		e_source_selector_select_source (selector, source);
 +	}
 +	g_slist_free (list);
 +
 +	/* Listen for subsequent changes to the selector. */
 +
 +	g_signal_connect_swapped (
 +		widget, "selection-changed",
 +		G_CALLBACK (memo_shell_sidebar_selection_changed_cb),
 +		object);
 +
 +	g_signal_connect_swapped (
 +		widget, "primary-selection-changed",
 +		G_CALLBACK (memo_shell_sidebar_primary_selection_changed_cb),
 +		object);
 +}
 +
 +static guint32
 +memo_shell_sidebar_check_state (EShellSidebar *shell_sidebar)
 +{
 +	EMemoShellSidebar *memo_shell_sidebar;
 +	ESourceSelector *selector;
 +	ESource *source;
 +	gboolean is_system = FALSE;
 +	guint32 state = 0;
 +
 +	memo_shell_sidebar = E_MEMO_SHELL_SIDEBAR (shell_sidebar);
 +	selector = e_memo_shell_sidebar_get_selector (memo_shell_sidebar);
 +	source = e_source_selector_peek_primary_selection (selector);
 +
 +	if (source != NULL) {
 +		const gchar *uri;
 +
 +		uri = e_source_peek_relative_uri (source);
 +		is_system = (uri == NULL || strcmp (uri, "system") == 0);
 +	}
 +
 +	if (source != NULL)
 +		state |= E_MEMO_SHELL_SIDEBAR_HAS_PRIMARY_SOURCE;
 +	if (is_system)
 +		state |= E_MEMO_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_SYSTEM;
 +
 +	return state;
 +}
 +
 +static void
 +memo_shell_sidebar_client_added (EMemoShellSidebar *memo_shell_sidebar,
 +                                 ECal *client)
 +{
 +	memo_shell_sidebar_update_timezone (memo_shell_sidebar);
 +}
 +
 +static void
 +memo_shell_sidebar_client_removed (EMemoShellSidebar *memo_shell_sidebar,
 +                                   ECal *client)
 +{
 +	ESourceSelector *selector;
 +	GHashTable *client_table;
 +	ESource *source;
 +	const gchar *uid;
 +
 +	client_table = memo_shell_sidebar->priv->client_table;
 +	selector = e_memo_shell_sidebar_get_selector (memo_shell_sidebar);
 +
 +	g_signal_handlers_disconnect_matched (
 +		client, G_SIGNAL_MATCH_DATA, 0, 0,
 +		NULL, NULL, memo_shell_sidebar);
 +
 +	source = e_cal_get_source (client);
 +	e_source_selector_unselect_source (selector, source);
 +
 +	uid = e_source_peek_uid (source);
 +	g_hash_table_remove (client_table, uid);
 +
 +	memo_shell_sidebar_emit_status_message (memo_shell_sidebar, NULL);
 +}
 +
 +static void
 +memo_shell_sidebar_class_init (EMemoShellSidebarClass *class)
 +{
 +	GObjectClass *object_class;
 +	EShellSidebarClass *shell_sidebar_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (EMemoShellSidebarPrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->get_property = memo_shell_sidebar_get_property;
 +	object_class->dispose = memo_shell_sidebar_dispose;
 +	object_class->finalize = memo_shell_sidebar_finalize;
 +	object_class->constructed = memo_shell_sidebar_constructed;
 +
 +	shell_sidebar_class = E_SHELL_SIDEBAR_CLASS (class);
 +	shell_sidebar_class->check_state = memo_shell_sidebar_check_state;
 +
 +	class->client_added = memo_shell_sidebar_client_added;
 +	class->client_removed = memo_shell_sidebar_client_removed;
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_SELECTOR,
 +		g_param_spec_object (
 +			"selector",
 +			_("Source Selector Widget"),
 +			_("This widget displays groups of memo lists"),
 +			E_TYPE_SOURCE_SELECTOR,
 +			G_PARAM_READABLE));
 +
 +	signals[CLIENT_ADDED] = g_signal_new (
 +		"client-added",
 +		G_OBJECT_CLASS_TYPE (object_class),
 +		G_SIGNAL_RUN_LAST,
 +		G_STRUCT_OFFSET (EMemoShellSidebarClass, client_added),
 +		NULL, NULL,
 +		g_cclosure_marshal_VOID__OBJECT,
 +		G_TYPE_NONE, 1,
 +		E_TYPE_CAL);
 +
 +	signals[CLIENT_REMOVED] = g_signal_new (
 +		"client-removed",
 +		G_OBJECT_CLASS_TYPE (object_class),
 +		G_SIGNAL_RUN_LAST,
 +		G_STRUCT_OFFSET (EMemoShellSidebarClass, client_removed),
 +		NULL, NULL,
 +		g_cclosure_marshal_VOID__OBJECT,
 +		G_TYPE_NONE, 1,
 +		E_TYPE_CAL);
 +
 +	signals[STATUS_MESSAGE] = g_signal_new (
 +		"status-message",
 +		G_OBJECT_CLASS_TYPE (object_class),
 +		G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
 +		G_STRUCT_OFFSET (EMemoShellSidebarClass, status_message),
 +		NULL, NULL,
 +		e_marshal_VOID__STRING_DOUBLE,
 +		G_TYPE_NONE, 2,
 +		G_TYPE_STRING,
 +		G_TYPE_DOUBLE);
 +}
 +
 +static void
 +memo_shell_sidebar_init (EMemoShellSidebar *memo_shell_sidebar)
 +{
 +	GHashTable *client_table;
 +
 +	client_table = g_hash_table_new_full (
 +		g_str_hash, g_str_equal,
 +		(GDestroyNotify) g_free,
 +		(GDestroyNotify) g_object_unref);
 +
 +	memo_shell_sidebar->priv =
 +		E_MEMO_SHELL_SIDEBAR_GET_PRIVATE (memo_shell_sidebar);
 +
 +	memo_shell_sidebar->priv->client_table = client_table;
 +
 +	/* Postpone widget construction until we have a shell view. */
 +}
 +
 +GType
 +e_memo_shell_sidebar_get_type (void)
 +{
 +	return memo_shell_sidebar_type;
 +}
 +
 +void
 +e_memo_shell_sidebar_register_type (GTypeModule *type_module)
 +{
 +	static const GTypeInfo type_info = {
 +		sizeof (EMemoShellSidebarClass),
 +		(GBaseInitFunc) NULL,
 +		(GBaseFinalizeFunc) NULL,
 +		(GClassInitFunc) memo_shell_sidebar_class_init,
 +		(GClassFinalizeFunc) NULL,
 +		NULL,  /* class_data */
 +		sizeof (EMemoShellSidebar),
 +		0,     /* n_preallocs */
 +		(GInstanceInitFunc) memo_shell_sidebar_init,
 +		NULL   /* value_table */
 +	};
 +
 +	memo_shell_sidebar_type = g_type_module_register_type (
 +		type_module, E_TYPE_SHELL_SIDEBAR,
 +		"EMemoShellSidebar", &type_info, 0);
 +}
 +
 +GtkWidget *
 +e_memo_shell_sidebar_new (EShellView *shell_view)
 +{
 +	g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
 +
 +	return g_object_new (
 +		E_TYPE_MEMO_SHELL_SIDEBAR,
 +		"shell-view", shell_view, NULL);
 +}
 +
 +ESourceSelector *
 +e_memo_shell_sidebar_get_selector (EMemoShellSidebar *memo_shell_sidebar)
 +{
 +	g_return_val_if_fail (
 +		E_IS_MEMO_SHELL_SIDEBAR (memo_shell_sidebar), NULL);
 +
 +	return E_SOURCE_SELECTOR (memo_shell_sidebar->priv->selector);
 +}
 +
 +void
 +e_memo_shell_sidebar_add_source (EMemoShellSidebar *memo_shell_sidebar,
 +                                 ESource *source)
 +{
 +	ESourceSelector *selector;
 +	GHashTable *client_table;
 +	ECal *client;
 +	const gchar *uid;
 +	const gchar *uri;
 +	gchar *message;
 +
 +	g_return_if_fail (E_IS_MEMO_SHELL_SIDEBAR (memo_shell_sidebar));
 +	g_return_if_fail (E_IS_SOURCE (source));
 +
 +	client_table = memo_shell_sidebar->priv->client_table;
 +	selector = e_memo_shell_sidebar_get_selector (memo_shell_sidebar);
 +
 +	uid = e_source_peek_uid (source);
 +	client = g_hash_table_lookup (client_table, uid);
 +
 +	if (client != NULL)
 +		return;
 +
 +	client = auth_new_cal_from_source (source, E_CAL_SOURCE_TYPE_JOURNAL);
 +	g_return_if_fail (client != NULL);
 +
 +	g_signal_connect_swapped (
 +		client, "backend-died",
 +		G_CALLBACK (memo_shell_sidebar_backend_died_cb),
 +		memo_shell_sidebar);
 +
 +	g_signal_connect_swapped (
 +		client, "backend-error",
 +		G_CALLBACK (memo_shell_sidebar_backend_error_cb),
 +		memo_shell_sidebar);
 +
 +	g_hash_table_insert (client_table, g_strdup (uid), client);
 +	e_source_selector_select_source (selector, source);
 +
 +	uri = e_cal_get_uri (client);
 +	message = g_strdup_printf (_("Opening memos at %s"), uri);
 +	memo_shell_sidebar_emit_status_message (memo_shell_sidebar, message);
 +	g_free (message);
 +
 +	g_signal_connect_swapped (
 +		client, "cal-opened",
 +		G_CALLBACK (memo_shell_sidebar_client_opened_cb),
 +		memo_shell_sidebar);
 +
 +	e_cal_open_async (client, FALSE);
 +}
 +
 +void
 +e_memo_shell_sidebar_remove_source (EMemoShellSidebar *memo_shell_sidebar,
 +                                    ESource *source)
 +{
 +	ESourceSelector *selector;
 +	GHashTable *client_table;
 +	ECal *client;
 +	const gchar *uid;
 +
 +	g_return_if_fail (E_IS_MEMO_SHELL_SIDEBAR (memo_shell_sidebar));
 +	g_return_if_fail (E_IS_SOURCE (source));
 +
 +	client_table = memo_shell_sidebar->priv->client_table;
 +	selector = e_memo_shell_sidebar_get_selector (memo_shell_sidebar);
 +
 +	uid = e_source_peek_uid (source);
 +	client = g_hash_table_lookup (client_table, uid);
 +
 +	if (client == NULL)
 +		return;
 +
 +	memo_shell_sidebar_emit_client_removed (memo_shell_sidebar, client);
 +}
diff --cc calendar/module/e-memo-shell-sidebar.h
index 9a30b91,0000000..665c8f2
mode 100644,000000..100644
--- a/calendar/module/e-memo-shell-sidebar.h
+++ b/calendar/module/e-memo-shell-sidebar.h
@@@ -1,95 -1,0 +1,95 @@@
 +/*
 + * e-memo-shell-sidebar.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_MEMO_SHELL_SIDEBAR_H
 +#define E_MEMO_SHELL_SIDEBAR_H
 +
 +#include <libecal/e-cal.h>
 +#include <libedataserverui/e-source-selector.h>
 +
 +#include <shell/e-shell-sidebar.h>
 +#include <shell/e-shell-view.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_MEMO_SHELL_SIDEBAR \
 +	(e_memo_shell_sidebar_get_type ())
 +#define E_MEMO_SHELL_SIDEBAR(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_MEMO_SHELL_SIDEBAR, EMemoShellSidebar))
 +#define E_MEMO_SHELL_SIDEBAR_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_MEMO_SHELL_SIDEBAR, EMemoShellSidebarClass))
 +#define E_IS_MEMO_SHELL_SIDEBAR(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_MEMO_SHELL_SIDEBAR))
 +#define E_IS_MEMO_SHELL_SIDEBAR_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), E_TYPE_MEMO_SHELL_SIDEBAR))
 +#define E_MEMO_SHELL_SIDEBAR_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_MEMO_SHELL_SIDEBAR, EMemoShellSidebarClass))
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _EMemoShellSidebar EMemoShellSidebar;
 +typedef struct _EMemoShellSidebarClass EMemoShellSidebarClass;
 +typedef struct _EMemoShellSidebarPrivate EMemoShellSidebarPrivate;
 +
 +enum {
 +	E_MEMO_SHELL_SIDEBAR_HAS_PRIMARY_SOURCE		= 1 << 0,
 +	E_MEMO_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_SYSTEM	= 1 << 1
 +};
 +
 +struct _EMemoShellSidebar {
 +	EShellSidebar parent;
 +	EMemoShellSidebarPrivate *priv;
 +};
 +
 +struct _EMemoShellSidebarClass {
 +	EShellSidebarClass parent_class;
 +
 +	/* Signals */
 +	void	(*client_added)			(EMemoShellSidebar *memo_shell_sidebar,
 +						 ECal *client);
 +	void	(*client_removed)		(EMemoShellSidebar *memo_shell_sidebar,
 +						 ECal *client);
 +	void	(*status_message)		(EMemoShellSidebar *memo_shell_sidebar,
 +						 const gchar *status_message,
 +						 gdouble percent);
 +};
 +
 +GType		e_memo_shell_sidebar_get_type	(void);
 +void		e_memo_shell_sidebar_register_type
 +					(GTypeModule *type_module);
 +GtkWidget *	e_memo_shell_sidebar_new(EShellView *shell_view);
 +ESourceSelector *
 +		e_memo_shell_sidebar_get_selector
 +					(EMemoShellSidebar *memo_shell_sidebar);
 +void		e_memo_shell_sidebar_add_source
 +					(EMemoShellSidebar *memo_shell_sidebar,
 +					 ESource *source);
 +void		e_memo_shell_sidebar_remove_source
 +					(EMemoShellSidebar *memo_shell_sidebar,
 +					 ESource *source);
 +
 +G_END_DECLS
 +
 +#endif /* E_MEMO_SHELL_SIDEBAR_H */
diff --cc calendar/module/e-memo-shell-view-actions.c
index 30dfde6,0000000..ab0b9f0
mode 100644,000000..100644
--- a/calendar/module/e-memo-shell-view-actions.c
+++ b/calendar/module/e-memo-shell-view-actions.c
@@@ -1,920 -1,0 +1,920 @@@
 +/*
 + * e-memo-shell-view-actions.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-memo-shell-view-private.h"
 +
 +static void
 +action_gal_save_custom_view_cb (GtkAction *action,
 +                                EMemoShellView *memo_shell_view)
 +{
 +	EMemoShellContent *memo_shell_content;
 +	EShellView *shell_view;
 +	GalViewInstance *view_instance;
 +
 +	/* All shell views respond to the activation of this action,
 +	 * which is defined by EShellWindow.  But only the currently
 +	 * active shell view proceeds with saving the custom view. */
 +	shell_view = E_SHELL_VIEW (memo_shell_view);
 +	if (!e_shell_view_is_active (shell_view))
 +		return;
 +
 +	memo_shell_content = memo_shell_view->priv->memo_shell_content;
 +	view_instance = e_memo_shell_content_get_view_instance (memo_shell_content);
 +	gal_view_instance_save_as (view_instance);
 +}
 +
 +static void
 +action_memo_clipboard_copy_cb (GtkAction *action,
 +                               EMemoShellView *memo_shell_view)
 +{
 +	EMemoShellContent *memo_shell_content;
 +	EMemoTable *memo_table;
 +
 +	memo_shell_content = memo_shell_view->priv->memo_shell_content;
 +	memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
 +
 +	e_memo_table_copy_clipboard (memo_table);
 +}
 +
 +static void
 +action_memo_clipboard_cut_cb (GtkAction *action,
 +                              EMemoShellView *memo_shell_view)
 +{
 +	EMemoShellContent *memo_shell_content;
 +	EMemoTable *memo_table;
 +
 +	memo_shell_content = memo_shell_view->priv->memo_shell_content;
 +	memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
 +
 +	e_memo_table_cut_clipboard (memo_table);
 +}
 +
 +static void
 +action_memo_clipboard_paste_cb (GtkAction *action,
 +                                EMemoShellView *memo_shell_view)
 +{
 +	EMemoShellContent *memo_shell_content;
 +	EMemoTable *memo_table;
 +
 +	memo_shell_content = memo_shell_view->priv->memo_shell_content;
 +	memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
 +
 +	e_memo_table_paste_clipboard (memo_table);
 +}
 +
 +static void
 +action_memo_delete_cb (GtkAction *action,
 +                       EMemoShellView *memo_shell_view)
 +{
 +	EMemoShellContent *memo_shell_content;
 +	ECalComponentPreview *memo_preview;
 +	EMemoTable *memo_table;
 +
 +	memo_shell_content = memo_shell_view->priv->memo_shell_content;
 +	memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
 +	memo_preview = e_memo_shell_content_get_memo_preview (memo_shell_content);
 +
 +	e_memo_shell_view_set_status_message (
 +		memo_shell_view, _("Deleting selected memos..."), -1.0);
 +	e_memo_table_delete_selected (memo_table);
 +	e_memo_shell_view_set_status_message (memo_shell_view, NULL, -1.0);
 +
 +	e_cal_component_preview_clear (memo_preview);
 +}
 +
 +static void
 +action_memo_forward_cb (GtkAction *action,
 +                        EMemoShellView *memo_shell_view)
 +{
 +	EMemoShellContent *memo_shell_content;
 +	EMemoTable *memo_table;
 +	ECalModelComponent *comp_data;
 +	ECalComponent *comp;
 +	icalcomponent *clone;
 +	GSList *list;
 +
 +	memo_shell_content = memo_shell_view->priv->memo_shell_content;
 +	memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
 +
 +	list = e_memo_table_get_selected (memo_table);
 +	g_return_if_fail (list != NULL);
 +	comp_data = list->data;
 +	g_slist_free (list);
 +
 +	/* XXX We only forward the first selected memo. */
 +	comp = e_cal_component_new ();
 +	clone = icalcomponent_new_clone (comp_data->icalcomp);
 +	e_cal_component_set_icalcomponent (comp, clone);
 +	itip_send_comp (
 +		E_CAL_COMPONENT_METHOD_PUBLISH, comp,
 +		comp_data->client, NULL, NULL, NULL, TRUE);
 +	g_object_unref (comp);
 +}
 +
 +static void
 +action_memo_list_copy_cb (GtkAction *action,
 +                          EMemoShellView *memo_shell_view)
 +{
 +	EMemoShellSidebar *memo_shell_sidebar;
 +	EShellWindow *shell_window;
 +	EShellView *shell_view;
 +	ESourceSelector *selector;
 +	ESource *source;
 +
 +	shell_view = E_SHELL_VIEW (memo_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	memo_shell_sidebar = memo_shell_view->priv->memo_shell_sidebar;
 +	selector = e_memo_shell_sidebar_get_selector (memo_shell_sidebar);
 +	source = e_source_selector_peek_primary_selection (selector);
 +	g_return_if_fail (E_IS_SOURCE (source));
 +
 +	copy_source_dialog (
 +		GTK_WINDOW (shell_window),
 +		source, E_CAL_SOURCE_TYPE_JOURNAL);
 +}
 +
 +static void
 +action_memo_list_delete_cb (GtkAction *action,
 +                            EMemoShellView *memo_shell_view)
 +{
 +	EMemoShellBackend *memo_shell_backend;
 +	EMemoShellContent *memo_shell_content;
 +	EMemoShellSidebar *memo_shell_sidebar;
 +	EShellWindow *shell_window;
 +	EShellView *shell_view;
 +	EMemoTable *memo_table;
 +	ECal *client;
 +	ECalModel *model;
 +	ESourceSelector *selector;
 +	ESourceGroup *source_group;
 +	ESourceList *source_list;
 +	ESource *source;
 +	gint response;
 +	gchar *uri;
 +	GError *error = NULL;
 +
 +	shell_view = E_SHELL_VIEW (memo_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	memo_shell_backend = memo_shell_view->priv->memo_shell_backend;
 +	source_list = e_memo_shell_backend_get_source_list (memo_shell_backend);
 +
 +	memo_shell_content = memo_shell_view->priv->memo_shell_content;
 +	memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
 +	model = e_memo_table_get_model (memo_table);
 +
 +	memo_shell_sidebar = memo_shell_view->priv->memo_shell_sidebar;
 +	selector = e_memo_shell_sidebar_get_selector (memo_shell_sidebar);
 +	source = e_source_selector_peek_primary_selection (selector);
 +	g_return_if_fail (E_IS_SOURCE (source));
 +
 +	/* Ask for confirmation. */
 +	response = e_error_run (
 +		GTK_WINDOW (shell_window),
 +		"calendar:prompt-delete-memo-list",
 +		e_source_peek_name (source));
 +	if (response != GTK_RESPONSE_YES)
 +		return;
 +
 +	uri = e_source_get_uri (source);
 +	client = e_cal_model_get_client_for_uri (model, uri);
 +	if (client == NULL)
 +		client = e_cal_new_from_uri (uri, E_CAL_SOURCE_TYPE_JOURNAL);
 +	g_free (uri);
 +
 +	g_return_if_fail (client != NULL);
 +
 +	if (!e_cal_remove (client, &error)) {
 +		g_warning ("%s", error->message);
 +		g_error_free (error);
 +		return;
 +	}
 +
 +	if (e_source_selector_source_is_selected (selector, source)) {
 +		e_memo_shell_sidebar_remove_source (
 +			memo_shell_sidebar, source);
 +		e_source_selector_unselect_source (selector, source);
 +	}
 +
 +	source_group = e_source_peek_group (source);
 +	e_source_group_remove_source (source_group, source);
 +
 +	if (!e_source_list_sync (source_list, &error)) {
 +		g_warning ("%s", error->message);
 +		g_error_free (error);
 +	}
 +}
 +
 +static void
 +action_memo_list_new_cb (GtkAction *action,
 +                         EMemoShellView *memo_shell_view)
 +{
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +
 +	shell_view = E_SHELL_VIEW (memo_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +	calendar_setup_new_memo_list (GTK_WINDOW (shell_window));
 +}
 +
 +static void
 +action_memo_list_print_cb (GtkAction *action,
 +                           EMemoShellView *memo_shell_view)
 +{
 +	EMemoShellContent *memo_shell_content;
 +	EMemoTable *memo_table;
 +	ETable *table;
 +	GtkPrintOperationAction print_action;
 +
 +	memo_shell_content = memo_shell_view->priv->memo_shell_content;
 +	memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
 +	table = e_memo_table_get_table (memo_table);
 +
 +	print_action = GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG;
 +	print_table (table, _("Print Memos"), _("Memos"), print_action);
 +}
 +
 +static void
 +action_memo_list_print_preview_cb (GtkAction *action,
 +                                   EMemoShellView *memo_shell_view)
 +{
 +	EMemoShellContent *memo_shell_content;
 +	EMemoTable *memo_table;
 +	ETable *table;
 +	GtkPrintOperationAction print_action;
 +
 +	memo_shell_content = memo_shell_view->priv->memo_shell_content;
 +	memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
 +	table = e_memo_table_get_table (memo_table);
 +
 +	print_action = GTK_PRINT_OPERATION_ACTION_PREVIEW;
 +	print_table (table, _("Print Memos"), _("Memos"), print_action);
 +}
 +
 +static void
 +action_memo_list_properties_cb (GtkAction *action,
 +                                EMemoShellView *memo_shell_view)
 +{
 +	EMemoShellSidebar *memo_shell_sidebar;
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	ESource *source;
 +	ESourceSelector *selector;
 +
 +	shell_view = E_SHELL_VIEW (memo_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	memo_shell_sidebar = memo_shell_view->priv->memo_shell_sidebar;
 +	selector = e_memo_shell_sidebar_get_selector (memo_shell_sidebar);
 +	source = e_source_selector_peek_primary_selection (selector);
 +	g_return_if_fail (E_IS_SOURCE (source));
 +
 +	calendar_setup_edit_memo_list (GTK_WINDOW (shell_window), source);
 +}
 +
 +static void
 +action_memo_list_rename_cb (GtkAction *action,
 +                            EMemoShellView *memo_shell_view)
 +{
 +	EMemoShellSidebar *memo_shell_sidebar;
 +	ESourceSelector *selector;
 +
 +	memo_shell_sidebar = memo_shell_view->priv->memo_shell_sidebar;
 +	selector = e_memo_shell_sidebar_get_selector (memo_shell_sidebar);
 +
 +	e_source_selector_edit_primary_selection (selector);
 +}
 +
 +static void
 +action_memo_list_select_one_cb (GtkAction *action,
 +                                EMemoShellView *memo_shell_view)
 +{
 +	EMemoShellSidebar *memo_shell_sidebar;
 +	ESourceSelector *selector;
 +	ESource *primary;
 +	GSList *list, *iter;
 +
 +	/* XXX ESourceSelector should provide a function for this. */
 +
 +	memo_shell_sidebar = memo_shell_view->priv->memo_shell_sidebar;
 +	selector = e_memo_shell_sidebar_get_selector (memo_shell_sidebar);
 +	primary = e_source_selector_peek_primary_selection (selector);
 +	g_return_if_fail (primary != NULL);
 +
 +	list = e_source_selector_get_selection (selector);
 +	for (iter = list; iter != NULL; iter = iter->next) {
 +		ESource *source = iter->data;
 +
 +		if (source == primary)
 +			continue;
 +
 +		e_source_selector_unselect_source (selector, source);
 +	}
 +	e_source_selector_free_selection (list);
 +
 +	e_source_selector_select_source (selector, primary);
 +}
 +
 +static void
 +action_memo_new_cb (GtkAction *action,
 +                    EMemoShellView *memo_shell_view)
 +{
 +	EShell *shell;
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	EMemoShellContent *memo_shell_content;
 +	EMemoTable *memo_table;
 +	ECalModelComponent *comp_data;
 +	ECal *client;
 +	ECalComponent *comp;
 +	CompEditor *editor;
 +	GSList *list;
 +
 +	shell_view = E_SHELL_VIEW (memo_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +	shell = e_shell_window_get_shell (shell_window);
 +
 +	memo_shell_content = memo_shell_view->priv->memo_shell_content;
 +	memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
 +
 +	list = e_memo_table_get_selected (memo_table);
 +	g_return_if_fail (list != NULL);
 +	comp_data = list->data;
 +	g_slist_free (list);
 +
 +	client = comp_data->client;
 +	editor = memo_editor_new (client, shell, COMP_EDITOR_NEW_ITEM);
 +	comp = cal_comp_memo_new_with_defaults (client);
 +	comp_editor_edit_comp (editor, comp);
 +
 +	gtk_window_present (GTK_WINDOW (editor));
 +
 +	g_object_unref (comp);
 +	g_object_unref (client);
 +}
 +
 +static void
 +action_memo_open_cb (GtkAction *action,
 +                     EMemoShellView *memo_shell_view)
 +{
 +	EMemoShellContent *memo_shell_content;
 +	EMemoTable *memo_table;
 +	ECalModelComponent *comp_data;
 +	GSList *list;
 +
 +	memo_shell_content = memo_shell_view->priv->memo_shell_content;
 +	memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
 +
 +	list = e_memo_table_get_selected (memo_table);
 +	g_return_if_fail (list != NULL);
 +	comp_data = list->data;
 +	g_slist_free (list);
 +
 +	/* XXX We only open the first selected memo. */
 +	e_memo_shell_view_open_memo (memo_shell_view, comp_data);
 +}
 +
 +static void
 +action_memo_open_url_cb (GtkAction *action,
 +                         EMemoShellView *memo_shell_view)
 +{
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	EMemoShellContent *memo_shell_content;
 +	EMemoTable *memo_table;
 +	ECalModelComponent *comp_data;
 +	icalproperty *prop;
 +	const gchar *uri;
 +	GSList *list;
 +
 +	shell_view = E_SHELL_VIEW (memo_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	memo_shell_content = memo_shell_view->priv->memo_shell_content;
 +	memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
 +
 +	list = e_memo_table_get_selected (memo_table);
 +	g_return_if_fail (list != NULL);
 +	comp_data = list->data;
 +	g_slist_free (list);
 +
 +	/* XXX We only open the URI of the first selected memo. */
 +	prop = icalcomponent_get_first_property (
 +		comp_data->icalcomp, ICAL_URL_PROPERTY);
 +	g_return_if_fail (prop == NULL);
 +
 +	uri = icalproperty_get_url (prop);
 +	e_show_uri (GTK_WINDOW (shell_window), uri);
 +}
 +
 +static void
 +action_memo_preview_cb (GtkToggleAction *action,
 +                        EMemoShellView *memo_shell_view)
 +{
 +	EMemoShellContent *memo_shell_content;
 +	gboolean visible;
 +
 +	memo_shell_content = memo_shell_view->priv->memo_shell_content;
 +	visible = gtk_toggle_action_get_active (action);
 +	e_memo_shell_content_set_preview_visible (memo_shell_content, visible);
 +}
 +
 +static void
 +action_memo_print_cb (GtkAction *action,
 +                      EMemoShellView *memo_shell_view)
 +{
 +	EMemoShellContent *memo_shell_content;
 +	EMemoTable *memo_table;
 +	ECalModelComponent *comp_data;
 +	ECalComponent *comp;
 +	icalcomponent *clone;
 +	GtkPrintOperationAction print_action;
 +	GSList *list;
 +
 +	memo_shell_content = memo_shell_view->priv->memo_shell_content;
 +	memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
 +
 +	list = e_memo_table_get_selected (memo_table);
 +	g_return_if_fail (list != NULL);
 +	comp_data = list->data;
 +	g_slist_free (list);
 +
 +	/* XXX We only print the first selected memo. */
 +	comp = e_cal_component_new ();
 +	clone = icalcomponent_new_clone (comp_data->icalcomp);
 +	print_action = GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG;
 +	e_cal_component_set_icalcomponent (comp, clone);
 +	print_comp (comp, comp_data->client, print_action);
 +	g_object_unref (comp);
 +}
 +
 +static void
 +action_memo_save_as_cb (GtkAction *action,
 +                        EMemoShellView *memo_shell_view)
 +{
 +	EMemoShellContent *memo_shell_content;
 +	EMemoTable *memo_table;
 +	ECalModelComponent *comp_data;
 +	GSList *list;
 +	gchar *filename;
 +	gchar *string;
 +
 +	memo_shell_content = memo_shell_view->priv->memo_shell_content;
 +	memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
 +
 +	list = e_memo_table_get_selected (memo_table);
 +	g_return_if_fail (list != NULL);
 +	comp_data = list->data;
 +	g_slist_free (list);
 +
 +	filename = e_file_dialog_save (_("Save as..."), NULL);
 +	if (filename == NULL)
 +		return;
 +
 +	/* XXX We only save the first selected memo. */
 +	string = e_cal_get_component_as_string (
 +		comp_data->client, comp_data->icalcomp);
 +	if (string == NULL) {
 +		g_warning ("Could not convert memo to a string");
 +		return;
 +	}
 +
 +	e_write_file_uri (filename, string);
 +
 +	g_free (filename);
 +	g_free (string);
 +}
 +
 +static void
 +action_search_execute_cb (GtkAction *action,
 +                          EMemoShellView *memo_shell_view)
 +{
 +	EShellView *shell_view;
 +
 +	/* All shell views respond to the activation of this action,
 +	 * which is defined by EShellWindow.  But only the currently
 +	 * active shell view proceeds with executing the search. */
 +	shell_view = E_SHELL_VIEW (memo_shell_view);
 +	if (!e_shell_view_is_active (shell_view))
 +		return;
 +
 +	e_memo_shell_view_execute_search (memo_shell_view);
 +}
 +
 +static void
 +action_search_filter_cb (GtkRadioAction *action,
 +                         GtkRadioAction *current,
 +                         EMemoShellView *memo_shell_view)
 +{
 +	e_memo_shell_view_execute_search (memo_shell_view);
 +}
 +
 +static GtkActionEntry memo_entries[] = {
 +
 +	{ "memo-clipboard-copy",
 +	  GTK_STOCK_COPY,
 +	  NULL,
 +	  NULL,
 +	  N_("Copy selected memo"),
 +	  G_CALLBACK (action_memo_clipboard_copy_cb) },
 +
 +	{ "memo-clipboard-cut",
 +	  GTK_STOCK_CUT,
 +	  NULL,
 +	  NULL,
 +	  N_("Cut selected memo"),
 +	  G_CALLBACK (action_memo_clipboard_cut_cb) },
 +
 +	{ "memo-clipboard-paste",
 +	  GTK_STOCK_PASTE,
 +	  NULL,
 +	  NULL,
 +	  N_("Paste memo from the clipboard"),
 +	  G_CALLBACK (action_memo_clipboard_paste_cb) },
 +
 +	{ "memo-delete",
 +	  GTK_STOCK_DELETE,
 +	  N_("_Delete Memo"),
 +	  NULL,
 +	  N_("Delete selected memos"),
 +	  G_CALLBACK (action_memo_delete_cb) },
 +
 +	{ "memo-forward",
 +	  "mail-forward",
 +	  N_("_Forward as iCalendar..."),
 +	  "<Control>f",
 +	  NULL,  /* XXX Add a tooltip! */
 +	  G_CALLBACK (action_memo_forward_cb) },
 +
 +	{ "memo-list-copy",
 +	  GTK_STOCK_COPY,
 +	  N_("_Copy..."),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  G_CALLBACK (action_memo_list_copy_cb) },
 +
 +	{ "memo-list-delete",
 +	  GTK_STOCK_DELETE,
 +	  N_("_Delete"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  G_CALLBACK (action_memo_list_delete_cb) },
 +
 +	{ "memo-list-new",
 +	  "stock_notes",
 +	  N_("_New Memo List"),
 +	  NULL,
 +	  N_("Create a new memo list"),
 +	  G_CALLBACK (action_memo_list_new_cb) },
 +
 +	{ "memo-list-properties",
 +	  GTK_STOCK_PROPERTIES,
 +	  NULL,
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  G_CALLBACK (action_memo_list_properties_cb) },
 +
 +	{ "memo-list-rename",
 +	  NULL,
 +	  N_("_Rename..."),
 +	  "F2",
 +	  N_("Rename the selected memo list"),
 +	  G_CALLBACK (action_memo_list_rename_cb) },
 +
 +	{ "memo-list-select-one",
 +	  "stock_check-filled",
 +	  N_("Show _Only This Memo List"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  G_CALLBACK (action_memo_list_select_one_cb) },
 +
 +	{ "memo-new",
 +	  "stock_insert-note",
 +	  N_("New _Memo"),
 +	  NULL,
 +	  N_("Create a new memo"),
 +	  G_CALLBACK (action_memo_new_cb) },
 +
 +	{ "memo-open",
 +	  GTK_STOCK_OPEN,
 +	  N_("_Open Memo"),
 +	  "<Control>o",
 +	  N_("View the selected memo"),
 +	  G_CALLBACK (action_memo_open_cb) },
 +
 +	{ "memo-open-url",
 +	  "applications-internet",
 +	  N_("Open _Web Page"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  G_CALLBACK (action_memo_open_url_cb) },
 +
 +	{ "memo-save-as",
 +	  GTK_STOCK_SAVE_AS,
 +	  N_("_Save as iCalendar..."),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  G_CALLBACK (action_memo_save_as_cb) }
 +};
 +
 +static EPopupActionEntry memo_popup_entries[] = {
 +
 +	{ "memo-list-popup-copy",
 +	  NULL,
 +	  "memo-list-copy" },
 +
 +	{ "memo-list-popup-delete",
 +	  NULL,
 +	  "memo-list-delete" },
 +
 +	{ "memo-list-popup-properties",
 +	  NULL,
 +	  "memo-list-properties" },
 +
 +	{ "memo-list-popup-rename",
 +	  NULL,
 +	  "memo-list-rename" },
 +
 +	{ "memo-list-popup-select-one",
 +	  NULL,
 +	  "memo-list-select-one" },
 +
 +	{ "memo-popup-clipboard-copy",
 +	  NULL,
 +	  "memo-clipboard-copy" },
 +
 +	{ "memo-popup-clipboard-cut",
 +	  NULL,
 +	  "memo-clipboard-cut" },
 +
 +	{ "memo-popup-clipboard-paste",
 +	  NULL,
 +	  "memo-clipboard-paste" },
 +
 +	{ "memo-popup-delete",
 +	  NULL,
 +	  "memo-delete" },
 +
 +	{ "memo-popup-forward",
 +	  NULL,
 +	  "memo-forward" },
 +
 +	{ "memo-popup-open",
 +	  NULL,
 +	  "memo-open" },
 +
 +	{ "memo-popup-open-url",
 +	  NULL,
 +	  "memo-open-url" },
 +
 +	{ "memo-popup-save-as",
 +	  NULL,
 +	  "memo-save-as" }
 +};
 +
 +static GtkToggleActionEntry memo_toggle_entries[] = {
 +
 +	{ "memo-preview",
 +	  NULL,
 +	  N_("Memo _Preview"),
 +	  "<Control>m",
 +	  N_("Show memo preview pane"),
 +	  G_CALLBACK (action_memo_preview_cb),
 +	  TRUE }
 +};
 +
 +static GtkRadioActionEntry memo_filter_entries[] = {
 +
 +	{ "memo-filter-any-category",
 +	  NULL,
 +	  N_("Any Category"),
 +	  NULL,
 +	  NULL,
 +	  MEMO_FILTER_ANY_CATEGORY },
 +
 +	{ "memo-filter-unmatched",
 +	  NULL,
 +	  N_("Unmatched"),
 +	  NULL,
 +	  NULL,
 +	  MEMO_FILTER_UNMATCHED }
 +};
 +
 +static GtkRadioActionEntry memo_search_entries[] = {
 +
 +	{ "memo-search-any-field-contains",
 +	  NULL,
 +	  N_("Any field contains"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  MEMO_SEARCH_ANY_FIELD_CONTAINS },
 +
 +	{ "memo-search-description-contains",
 +	  NULL,
 +	  N_("Description contains"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  MEMO_SEARCH_DESCRIPTION_CONTAINS },
 +
 +	{ "memo-search-summary-contains",
 +	  NULL,
 +	  N_("Summary contains"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  MEMO_SEARCH_SUMMARY_CONTAINS }
 +};
 +
 +static GtkActionEntry lockdown_printing_entries[] = {
 +
 +	{ "memo-list-print",
 +	  GTK_STOCK_PRINT,
 +	  NULL,
 +	  "<Control>p",
 +	  N_("Print the list of memos"),
 +	  G_CALLBACK (action_memo_list_print_cb) },
 +
 +	{ "memo-list-print-preview",
 +	  GTK_STOCK_PRINT_PREVIEW,
 +	  NULL,
 +	  NULL,
 +	  N_("Preview the list of memos to be printed"),
 +	  G_CALLBACK (action_memo_list_print_preview_cb) },
 +
 +	{ "memo-print",
 +	  GTK_STOCK_PRINT,
 +	  NULL,
 +	  NULL,
 +	  N_("Print the selected memo"),
 +	  G_CALLBACK (action_memo_print_cb) }
 +};
 +
 +static EPopupActionEntry lockdown_printing_popup_entries[] = {
 +
 +	{ "memo-popup-print",
 +	  NULL,
 +	  "memo-print" }
 +};
 +
 +void
 +e_memo_shell_view_actions_init (EMemoShellView *memo_shell_view)
 +{
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	GtkActionGroup *action_group;
 +	GConfBridge *bridge;
 +	GtkAction *action;
 +	GObject *object;
 +	const gchar *key;
 +
 +	shell_view = E_SHELL_VIEW (memo_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	/* Memo Actions */
 +	action_group = ACTION_GROUP (MEMOS);
 +	gtk_action_group_add_actions (
 +		action_group, memo_entries,
 +		G_N_ELEMENTS (memo_entries), memo_shell_view);
 +	e_action_group_add_popup_actions (
 +		action_group, memo_popup_entries,
 +		G_N_ELEMENTS (memo_popup_entries));
 +	gtk_action_group_add_toggle_actions (
 +		action_group, memo_toggle_entries,
 +		G_N_ELEMENTS (memo_toggle_entries), memo_shell_view);
 +	gtk_action_group_add_radio_actions (
 +		action_group, memo_search_entries,
 +		G_N_ELEMENTS (memo_search_entries),
 +		MEMO_SEARCH_SUMMARY_CONTAINS,
 +		NULL, NULL);
 +
 +	/* Lockdown Printing Actions */
 +	action_group = ACTION_GROUP (LOCKDOWN_PRINTING);
 +	gtk_action_group_add_actions (
 +		action_group, lockdown_printing_entries,
 +		G_N_ELEMENTS (lockdown_printing_entries), memo_shell_view);
 +	e_action_group_add_popup_actions (
 +		action_group, lockdown_printing_popup_entries,
 +		G_N_ELEMENTS (lockdown_printing_popup_entries));
 +
 +	/* Bind GObject properties to GConf keys. */
 +
 +	bridge = gconf_bridge_get ();
 +
 +	object = G_OBJECT (ACTION (MEMO_PREVIEW));
 +	key = "/apps/evolution/calendar/display/show_memo_preview";
 +	gconf_bridge_bind_property (bridge, key, object, "active");
 +
 +	/* Fine tuning. */
 +
 +	action = ACTION (MEMO_DELETE);
 +	g_object_set (action, "short-label", _("Delete"), NULL);
 +
 +	g_signal_connect (
 +		ACTION (GAL_SAVE_CUSTOM_VIEW), "activate",
 +		G_CALLBACK (action_gal_save_custom_view_cb), memo_shell_view);
 +
 +	g_signal_connect (
 +		ACTION (SEARCH_EXECUTE), "activate",
 +		G_CALLBACK (action_search_execute_cb), memo_shell_view);
 +}
 +
 +void
 +e_memo_shell_view_update_search_filter (EMemoShellView *memo_shell_view)
 +{
 +	EShellContent *shell_content;
 +	EShellWindow *shell_window;
 +	EShellView *shell_view;
 +	GtkActionGroup *action_group;
 +	GtkRadioAction *radio_action;
 +	GList *list, *iter;
 +	GSList *group;
 +	gint ii;
 +
 +	shell_view = E_SHELL_VIEW (memo_shell_view);
 +	shell_content = e_shell_view_get_shell_content (shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	action_group = ACTION_GROUP (MEMOS_FILTER);
 +	e_action_group_remove_all_actions (action_group);
 +
 +	/* Add the standard filter actions. */
 +	gtk_action_group_add_radio_actions (
 +		action_group, memo_filter_entries,
 +		G_N_ELEMENTS (memo_filter_entries),
 +		MEMO_FILTER_ANY_CATEGORY,
 +		G_CALLBACK (action_search_filter_cb),
 +		memo_shell_view);
 +
 +	/* Retrieve the radio group from an action we just added. */
 +	list = gtk_action_group_list_actions (action_group);
 +	radio_action = GTK_RADIO_ACTION (list->data);
 +	group = gtk_radio_action_get_group (radio_action);
 +	g_list_free (list);
 +
 +	/* Build the category actions. */
 +
 +	list = e_categories_get_list ();
 +	for (iter = list, ii = 0; iter != NULL; iter = iter->next, ii++) {
 +		const gchar *category_name = iter->data;
 +		const gchar *filename;
 +		GtkAction *action;
 +		gchar *action_name;
 +
 +		action_name = g_strdup_printf (
 +			"memo-filter-category-%d", ii);
 +		radio_action = gtk_radio_action_new (
 +			action_name, category_name, NULL, NULL, ii);
 +		g_free (action_name);
 +
 +		/* Convert the category icon file to a themed icon name. */
 +		filename = e_categories_get_icon_file_for (category_name);
 +		if (filename != NULL && *filename != '\0') {
 +			gchar *basename;
 +			gchar *cp;
 +
 +			basename = g_path_get_basename (filename);
 +
 +			/* Lose the file extension. */
 +			if ((cp = strrchr (basename, '.')) != NULL)
 +				*cp = '\0';
 +
 +			g_object_set (
 +				radio_action, "icon-name", basename, NULL);
 +
 +			g_free (basename);
 +		}
 +
 +		gtk_radio_action_set_group (radio_action, group);
 +		group = gtk_radio_action_get_group (radio_action);
 +
 +		/* The action group takes ownership of the action. */
 +		action = GTK_ACTION (radio_action);
 +		gtk_action_group_add_action (action_group, action);
 +		g_object_unref (radio_action);
 +	}
 +	g_list_free (list);
 +
 +	/* Use any action in the group; doesn't matter which. */
 +	e_shell_content_set_filter_action (shell_content, radio_action);
 +
 +	ii = MEMO_FILTER_UNMATCHED;
 +	e_shell_content_add_filter_separator_after (shell_content, ii);
 +}
diff --cc calendar/module/e-memo-shell-view-actions.h
index 97fd9a6,0000000..d6fd3ca
mode 100644,000000..100644
--- a/calendar/module/e-memo-shell-view-actions.h
+++ b/calendar/module/e-memo-shell-view-actions.h
@@@ -1,87 -1,0 +1,87 @@@
 +/*
 + * e-memo-shell-view-actions.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_MEMO_SHELL_VIEW_ACTIONS_H
 +#define E_MEMO_SHELL_VIEW_ACTIONS_H
 +
 +#include <shell/e-shell-window-actions.h>
 +
 +/* Memo Actions */
 +#define E_SHELL_WINDOW_ACTION_MEMO_CLIPBOARD_COPY(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "memo-clipboard-copy")
 +#define E_SHELL_WINDOW_ACTION_MEMO_CLIPBOARD_CUT(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "memo-clipboard-cut")
 +#define E_SHELL_WINDOW_ACTION_MEMO_CLIPBOARD_PASTE(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "memo-clipboard-paste")
 +#define E_SHELL_WINDOW_ACTION_MEMO_DELETE(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "memo-delete")
 +#define E_SHELL_WINDOW_ACTION_MEMO_FORWARD(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "memo-forward")
 +#define E_SHELL_WINDOW_ACTION_MEMO_NEW(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "memo-new")
 +#define E_SHELL_WINDOW_ACTION_MEMO_OPEN(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "memo-open")
 +#define E_SHELL_WINDOW_ACTION_MEMO_OPEN_URL(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "memo-open-url")
 +#define E_SHELL_WINDOW_ACTION_MEMO_PREVIEW(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "memo-preview")
 +#define E_SHELL_WINDOW_ACTION_MEMO_PRINT(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "memo-print")
 +#define E_SHELL_WINDOW_ACTION_MEMO_SAVE_AS(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "memo-save-as")
 +
 +/* Memo List Actions */
 +#define E_SHELL_WINDOW_ACTION_MEMO_LIST_COPY(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "memo-list-copy")
 +#define E_SHELL_WINDOW_ACTION_MEMO_LIST_DELETE(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "memo-list-delete")
 +#define E_SHELL_WINDOW_ACTION_MEMO_LIST_NEW(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "memo-list-new")
 +#define E_SHELL_WINDOW_ACTION_MEMO_LIST_PRINT(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "memo-list-print")
 +#define E_SHELL_WINDOW_ACTION_MEMO_LIST_PRINT_PREVIEW(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "memo-list-print-preview")
 +#define E_SHELL_WINDOW_ACTION_MEMO_LIST_PROPERTIES(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "memo-list-properties")
 +#define E_SHELL_WINDOW_ACTION_MEMO_LIST_RENAME(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "memo-list-rename")
 +#define E_SHELL_WINDOW_ACTION_MEMO_LIST_SELECT_ONE(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "memo-list-select-one")
 +
 +/* Memo Query Actions */
 +#define E_SHELL_WINDOW_ACTION_MEMO_FILTER_ANY_CATEGORY(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "memo-filter-any-category")
 +#define E_SHELL_WINDOW_ACTION_MEMO_FILTER_UNMATCHED(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "memo-filter-unmatched")
 +#define E_SHELL_WINDOW_ACTION_MEMO_SEARCH_ANY_FIELD_CONTAINS(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "memo-search-any-field-contains")
 +#define E_SHELL_WINDOW_ACTION_MEMO_SEARCH_DESCRIPTION_CONTAINS(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "memo-search-description-contains")
 +#define E_SHELL_WINDOW_ACTION_MEMO_SEARCH_SUMMARY_CONTAINS(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "memo-search-summary-contains")
 +
 +/* Action Groups */
 +#define E_SHELL_WINDOW_ACTION_GROUP_MEMOS(window) \
 +	E_SHELL_WINDOW_ACTION_GROUP ((window), "memos")
 +#define E_SHELL_WINDOW_ACTION_GROUP_MEMOS_FILTER(window) \
 +	E_SHELL_WINDOW_ACTION_GROUP ((window), "memos-filter")
 +
 +#endif /* E_MEMO_SHELL_VIEW_ACTIONS_H */
diff --cc calendar/module/e-memo-shell-view-private.c
index dbb474a,0000000..69d6c0a
mode 100644,000000..100644
--- a/calendar/module/e-memo-shell-view-private.c
+++ b/calendar/module/e-memo-shell-view-private.c
@@@ -1,524 -1,0 +1,524 @@@
 +/*
 + * e-memo-shell-view-private.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-memo-shell-view-private.h"
 +
 +#include "widgets/menus/gal-view-factory-etable.h"
 +
 +static void
 +memo_shell_view_table_popup_event_cb (EShellView *shell_view,
 +                                      GdkEventButton *event)
 +{
 +	const gchar *widget_path;
 +
 +	widget_path = "/memo-popup";
 +	e_shell_view_show_popup_menu (shell_view, widget_path, event);
 +}
 +
 +static void
 +memo_shell_view_table_user_created_cb (EMemoShellView *memo_shell_view,
 +                                       EMemoTable *memo_table)
 +{
 +	EMemoShellSidebar *memo_shell_sidebar;
 +	ECalModel *model;
 +	ECal *client;
 +	ESource *source;
 +
 +	/* This is the "Click to Add" handler. */
 +
 +	model = e_memo_table_get_model (memo_table);
 +	client = e_cal_model_get_default_client (model);
 +	source = e_cal_get_source (client);
 +
 +	memo_shell_sidebar = memo_shell_view->priv->memo_shell_sidebar;
 +	e_memo_shell_sidebar_add_source (memo_shell_sidebar, source);
 +
 +	e_cal_model_add_client (model, client);
 +}
 +
 +static void
 +memo_shell_view_selector_client_added_cb (EMemoShellView *memo_shell_view,
 +                                          ECal *client)
 +{
 +	EMemoShellContent *memo_shell_content;
 +	EMemoTable *memo_table;
 +	ECalModel *model;
 +
 +	memo_shell_content = memo_shell_view->priv->memo_shell_content;
 +	memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
 +	model = e_memo_table_get_model (memo_table);
 +
 +	e_cal_model_add_client (model, client);
 +}
 +
 +static void
 +memo_shell_view_selector_client_removed_cb (EMemoShellView *memo_shell_view,
 +                                            ECal *client)
 +{
 +	EMemoShellContent *memo_shell_content;
 +	EMemoTable *memo_table;
 +	ECalModel *model;
 +
 +	memo_shell_content = memo_shell_view->priv->memo_shell_content;
 +	memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
 +	model = e_memo_table_get_model (memo_table);
 +
 +	e_cal_model_remove_client (model, client);
 +}
 +
 +static gboolean
 +memo_shell_view_selector_popup_event_cb (EShellView *shell_view,
 +                                         ESource *primary_source,
 +                                         GdkEventButton *event)
 +{
 +	const gchar *widget_path;
 +
 +	widget_path = "/memo-list-popup";
 +	e_shell_view_show_popup_menu (shell_view, widget_path, event);
 +
 +	return TRUE;
 +}
 +
 +static void
 +memo_shell_view_load_view_collection (EShellViewClass *shell_view_class)
 +{
 +	GalViewCollection *collection;
 +	GalViewFactory *factory;
 +	ETableSpecification *spec;
 +	const gchar *base_dir;
 +	gchar *filename;
 +
 +	collection = shell_view_class->view_collection;
 +
 +	base_dir = EVOLUTION_ETSPECDIR;
 +	spec = e_table_specification_new ();
 +	filename = g_build_filename (base_dir, ETSPEC_FILENAME, NULL);
 +	if (!e_table_specification_load_from_file (spec, filename))
 +		g_critical ("Unable to load ETable specification file "
 +                            "for memos");
 +	g_free (filename);
 +
 +	factory = gal_view_factory_etable_new (spec);
 +	gal_view_collection_add_factory (collection, factory);
 +	g_object_unref (factory);
 +	g_object_unref (spec);
 +
 +	gal_view_collection_load (collection);
 +}
 +
 +static void
 +memo_shell_view_notify_view_id_cb (EMemoShellView *memo_shell_view)
 +{
 +	EMemoShellContent *memo_shell_content;
 +	GalViewInstance *view_instance;
 +	const gchar *view_id;
 +
 +	memo_shell_content = memo_shell_view->priv->memo_shell_content;
 +	view_instance =
 +		e_memo_shell_content_get_view_instance (memo_shell_content);
 +	view_id = e_shell_view_get_view_id (E_SHELL_VIEW (memo_shell_view));
 +
 +	/* A NULL view ID implies we're in a custom view.  But you can
 +	 * only get to a custom view via the "Define Views" dialog, which
 +	 * would have already modified the view instance appropriately.
 +	 * Furthermore, there's no way to refer to a custom view by ID
 +	 * anyway, since custom views have no IDs. */
 +	if (view_id == NULL)
 +		return;
 +
 +	gal_view_instance_set_current_view_id (view_instance, view_id);
 +}
 +
 +void
 +e_memo_shell_view_private_init (EMemoShellView *memo_shell_view,
 +                                EShellViewClass *shell_view_class)
 +{
 +	if (!gal_view_collection_loaded (shell_view_class->view_collection))
 +		memo_shell_view_load_view_collection (shell_view_class);
 +
 +	g_signal_connect (
 +		memo_shell_view, "notify::view-id",
 +		G_CALLBACK (memo_shell_view_notify_view_id_cb), NULL);
 +}
 +
 +void
 +e_memo_shell_view_private_constructed (EMemoShellView *memo_shell_view)
 +{
 +	EMemoShellViewPrivate *priv = memo_shell_view->priv;
 +	EMemoShellContent *memo_shell_content;
 +	EMemoShellSidebar *memo_shell_sidebar;
 +	EShellView *shell_view;
 +	EShellBackend *shell_backend;
 +	EShellContent *shell_content;
 +	EShellSidebar *shell_sidebar;
 +	EShellWindow *shell_window;
 +	EMemoTable *memo_table;
 +	ECalModel *model;
 +	ETable *table;
 +	ESourceSelector *selector;
 +
 +	shell_view = E_SHELL_VIEW (memo_shell_view);
 +	shell_backend = e_shell_view_get_shell_backend (shell_view);
 +	shell_content = e_shell_view_get_shell_content (shell_view);
 +	shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	e_shell_window_add_action_group (shell_window, "memos");
 +	e_shell_window_add_action_group (shell_window, "memos-filter");
 +
 +	/* Cache these to avoid lots of awkward casting. */
 +	priv->memo_shell_backend = g_object_ref (shell_backend);
 +	priv->memo_shell_content = g_object_ref (shell_content);
 +	priv->memo_shell_sidebar = g_object_ref (shell_sidebar);
 +
 +	memo_shell_content = E_MEMO_SHELL_CONTENT (shell_content);
 +	memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
 +	model = e_memo_table_get_model (memo_table);
 +	table = e_memo_table_get_table (memo_table);
 +
 +	memo_shell_sidebar = E_MEMO_SHELL_SIDEBAR (shell_sidebar);
 +	selector = e_memo_shell_sidebar_get_selector (memo_shell_sidebar);
 +
 +	g_signal_connect_swapped (
 +		memo_table, "open-component",
 +		G_CALLBACK (e_memo_shell_view_open_memo),
 +		memo_shell_view);
 +
 +	g_signal_connect_swapped (
 +		memo_table, "popup-event",
 +		G_CALLBACK (memo_shell_view_table_popup_event_cb),
 +		memo_shell_view);
 +
 +	g_signal_connect_swapped (
 +		memo_table, "status-message",
 +		G_CALLBACK (e_memo_shell_view_set_status_message),
 +		memo_shell_view);
 +
 +	g_signal_connect_swapped (
 +		memo_table, "user-created",
 +		G_CALLBACK (memo_shell_view_table_user_created_cb),
 +		memo_shell_view);
 +
 +	g_signal_connect_swapped (
 +		model, "model-changed",
 +		G_CALLBACK (e_memo_shell_view_update_sidebar),
 +		memo_shell_view);
 +
 +	g_signal_connect_swapped (
 +		model, "model-rows-deleted",
 +		G_CALLBACK (e_memo_shell_view_update_sidebar),
 +		memo_shell_view);
 +
 +	g_signal_connect_swapped (
 +		model, "model-rows-inserted",
 +		G_CALLBACK (e_memo_shell_view_update_sidebar),
 +		memo_shell_view);
 +
 +	g_signal_connect_swapped (
 +		table, "selection-change",
 +		G_CALLBACK (e_memo_shell_view_update_sidebar),
 +		memo_shell_view);
 +
 +	g_signal_connect_swapped (
 +		memo_shell_sidebar, "client-added",
 +		G_CALLBACK (memo_shell_view_selector_client_added_cb),
 +		memo_shell_view);
 +
 +	g_signal_connect_swapped (
 +		memo_shell_sidebar, "client-removed",
 +		G_CALLBACK (memo_shell_view_selector_client_removed_cb),
 +		memo_shell_view);
 +
 +	g_signal_connect_swapped (
 +		memo_shell_sidebar, "status-message",
 +		G_CALLBACK (e_memo_shell_view_set_status_message),
 +		memo_shell_view);
 +
 +	g_signal_connect_swapped (
 +		selector, "popup-event",
 +		G_CALLBACK (memo_shell_view_selector_popup_event_cb),
 +		memo_shell_view);
 +
 +	g_signal_connect_swapped (
 +		selector, "primary-selection-changed",
 +		G_CALLBACK (e_shell_view_update_actions),
 +		memo_shell_view);
 +
 +	e_categories_register_change_listener (
 +		G_CALLBACK (e_memo_shell_view_update_search_filter),
 +		memo_shell_view);
 +
 +	e_memo_shell_view_actions_init (memo_shell_view);
 +	e_memo_shell_view_update_sidebar (memo_shell_view);
 +	e_memo_shell_view_update_search_filter (memo_shell_view);
 +
 +	e_memo_shell_view_execute_search (memo_shell_view);
 +}
 +
 +void
 +e_memo_shell_view_private_dispose (EMemoShellView *memo_shell_view)
 +{
 +	EMemoShellViewPrivate *priv = memo_shell_view->priv;
 +
 +	DISPOSE (priv->memo_shell_backend);
 +	DISPOSE (priv->memo_shell_content);
 +	DISPOSE (priv->memo_shell_sidebar);
 +
 +	if (memo_shell_view->priv->activity != NULL) {
 +		/* XXX Activity is not cancellable. */
 +		e_activity_complete (memo_shell_view->priv->activity);
 +		g_object_unref (memo_shell_view->priv->activity);
 +		memo_shell_view->priv->activity = NULL;
 +	}
 +}
 +
 +void
 +e_memo_shell_view_private_finalize (EMemoShellView *memo_shell_view)
 +{
 +	/* XXX Nothing to do? */
 +}
 +
 +void
 +e_memo_shell_view_execute_search (EMemoShellView *memo_shell_view)
 +{
 +	EMemoShellContent *memo_shell_content;
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	EShellContent *shell_content;
 +	GtkAction *action;
 +	GString *string;
 +	ECalComponentPreview *memo_preview;
 +	EMemoTable *memo_table;
 +	ECalModel *model;
 +	FilterRule *rule;
 +	const gchar *format;
 +	const gchar *text;
 +	gchar *query;
 +	gchar *temp;
 +	gint value;
 +
 +	shell_view = E_SHELL_VIEW (memo_shell_view);
 +	shell_content = e_shell_view_get_shell_content (shell_view);
 +	text = e_shell_content_get_search_text (shell_content);
 +
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +	action = ACTION (MEMO_SEARCH_ANY_FIELD_CONTAINS);
 +	value = gtk_radio_action_get_current_value (GTK_RADIO_ACTION (action));
 +
 +	if (text == NULL || *text == '\0') {
 +		text = "";
 +		value = MEMO_SEARCH_SUMMARY_CONTAINS;
 +	}
 +
 +	switch (value) {
 +		default:
 +			text = "";
 +			/* fall through */
 +
 +		case MEMO_SEARCH_SUMMARY_CONTAINS:
 +			format = "(contains? \"summary\" %s)";
 +			break;
 +
 +		case MEMO_SEARCH_DESCRIPTION_CONTAINS:
 +			format = "(contains? \"description\" %s)";
 +			break;
 +
 +		case MEMO_SEARCH_ANY_FIELD_CONTAINS:
 +			format = "(contains? \"any\" %s)";
 +			break;
 +	}
 +
 +	/* Build the query. */
 +	string = g_string_new ("");
 +	e_sexp_encode_string (string, text);
 +	query = g_strdup_printf (format, string->str);
 +	g_string_free (string, TRUE);
 +
 +	/* Apply selected filter. */
 +	value = e_shell_content_get_filter_value (shell_content);
 +	switch (value) {
 +		case MEMO_FILTER_ANY_CATEGORY:
 +			break;
 +
 +		case MEMO_FILTER_UNMATCHED:
 +			temp = g_strdup_printf (
 +				"(and (has-categories? #f) %s", query);
 +			g_free (query);
 +			query = temp;
 +			break;
 +
 +		default:
 +		{
 +			GList *categories;
 +			const gchar *category_name;
 +
 +			categories = e_categories_get_list ();
 +			category_name = g_list_nth_data (categories, value);
 +			g_list_free (categories);
 +
 +			temp = g_strdup_printf (
 +				"(and (has-categories? \"%s\") %s)",
 +				category_name, query);
 +			g_free (query);
 +			query = temp;
 +		}
 +	}
 +
 +	/* XXX This is wrong.  We need to programmatically construct a
 +	 *     FilterRule, tell it to build code, and pass the resulting
 +	 *     expression string to ECalModel. */
 +	rule = filter_rule_new ();
 +	e_shell_content_set_search_rule (shell_content, rule);
 +	g_object_unref (rule);
 +
 +	/* Submit the query. */
 +	memo_shell_content = memo_shell_view->priv->memo_shell_content;
 +	memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
 +	model = e_memo_table_get_model (memo_table);
 +	e_cal_model_set_search_query (model, query);
 +	g_free (query);
 +
 +	memo_preview =
 +		e_memo_shell_content_get_memo_preview (memo_shell_content);
 +	e_cal_component_preview_clear (memo_preview);
 +}
 +
 +void
 +e_memo_shell_view_open_memo (EMemoShellView *memo_shell_view,
 +                             ECalModelComponent *comp_data)
 +{
 +	EShell *shell;
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	CompEditor *editor;
 +	CompEditorFlags flags = 0;
 +	ECalComponent *comp;
 +	icalcomponent *clone;
 +	const gchar *uid;
 +
 +	g_return_if_fail (E_IS_MEMO_SHELL_VIEW (memo_shell_view));
 +	g_return_if_fail (E_IS_CAL_MODEL_COMPONENT (comp_data));
 +
 +	shell_view = E_SHELL_VIEW (memo_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +	shell = e_shell_window_get_shell (shell_window);
 +
 +	uid = icalcomponent_get_uid (comp_data->icalcomp);
 +	editor = comp_editor_find_instance (uid);
 +
 +	if (editor != NULL)
 +		goto exit;
 +
 +	comp = e_cal_component_new ();
 +	clone = icalcomponent_new_clone (comp_data->icalcomp);
 +	e_cal_component_set_icalcomponent (comp, clone);
 +
 +	if (e_cal_component_has_organizer (comp))
 +		flags |= COMP_EDITOR_IS_SHARED;
 +
 +	if (itip_organizer_is_user (comp, comp_data->client))
 +		flags |= COMP_EDITOR_USER_ORG;
 +
 +	editor = memo_editor_new (comp_data->client, shell, flags);
 +	comp_editor_edit_comp (editor, comp);
 +
 +	g_object_unref (comp);
 +
 +exit:
 +	gtk_window_present (GTK_WINDOW (editor));
 +}
 +
 +void
 +e_memo_shell_view_set_status_message (EMemoShellView *memo_shell_view,
 +                                      const gchar *status_message,
 +                                      gdouble percent)
 +{
 +	EActivity *activity;
 +	EShellView *shell_view;
 +	EShellBackend *shell_backend;
 +
 +	g_return_if_fail (E_IS_MEMO_SHELL_VIEW (memo_shell_view));
 +
 +	activity = memo_shell_view->priv->activity;
 +	shell_view = E_SHELL_VIEW (memo_shell_view);
 +	shell_backend = e_shell_view_get_shell_backend (shell_view);
 +
 +	if (status_message == NULL || *status_message == '\0') {
 +		if (activity != NULL) {
 +			e_activity_complete (activity);
 +			g_object_unref (activity);
 +			activity = NULL;
 +		}
 +
 +	} else if (activity == NULL) {
 +		activity = e_activity_new (status_message);
 +		e_activity_set_percent (activity, percent);
 +		e_shell_backend_add_activity (shell_backend, activity);
 +
 +	} else {
 +		e_activity_set_percent (activity, percent);
 +		e_activity_set_primary_text (activity, status_message);
 +	}
 +
 +	memo_shell_view->priv->activity = activity;
 +}
 +
 +void
 +e_memo_shell_view_update_sidebar (EMemoShellView *memo_shell_view)
 +{
 +	EMemoShellContent *memo_shell_content;
 +	EShellView *shell_view;
 +	EShellSidebar *shell_sidebar;
 +	EMemoTable *memo_table;
 +	ECalModel *model;
 +	ETable *table;
 +	GString *string;
 +	const gchar *format;
 +	gint n_rows;
 +	gint n_selected;
 +
 +	shell_view = E_SHELL_VIEW (memo_shell_view);
 +	shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
 +
 +	memo_shell_content = memo_shell_view->priv->memo_shell_content;
 +	memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
 +
 +	model = e_memo_table_get_model (memo_table);
 +	table = e_memo_table_get_table (memo_table);
 +
 +	n_rows = e_table_model_row_count (E_TABLE_MODEL (model));
 +	n_selected = e_table_selected_count (table);
 +
 +	string = g_string_sized_new (64);
 +
 +	format = ngettext ("%d memo", "%d memos", n_rows);
 +	g_string_append_printf (string, format, n_rows);
 +
 +	if (n_selected > 0) {
 +		format = _("%d selected");
 +		g_string_append_len (string, ", ", 2);
 +		g_string_append_printf (string, format, n_selected);
 +	}
 +
 +	e_shell_sidebar_set_secondary_text (shell_sidebar, string->str);
 +
 +	g_string_free (string, TRUE);
 +}
diff --cc calendar/module/e-memo-shell-view-private.h
index 04857ef,0000000..c41eaed
mode 100644,000000..100644
--- a/calendar/module/e-memo-shell-view-private.h
+++ b/calendar/module/e-memo-shell-view-private.h
@@@ -1,126 -1,0 +1,126 @@@
 +/*
 + * e-memo-shell-view-private.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_MEMO_SHELL_VIEW_PRIVATE_H
 +#define E_MEMO_SHELL_VIEW_PRIVATE_H
 +
 +#include "e-memo-shell-view.h"
 +
 +#include <string.h>
 +#include <glib/gi18n.h>
 +#include <libedataserver/e-categories.h>
 +#include <libedataserver/e-sexp.h>
 +
 +#include "e-util/e-dialog-utils.h"
 +#include "e-util/e-error.h"
 +#include "e-util/e-util.h"
 +#include "e-util/gconf-bridge.h"
 +#include "widgets/misc/e-popup-action.h"
 +
 +#include "calendar/gui/comp-util.h"
 +#include "calendar/gui/e-cal-component-preview.h"
 +#include "calendar/gui/e-calendar-selector.h"
 +#include "calendar/gui/print.h"
 +#include "calendar/gui/dialogs/calendar-setup.h"
 +#include "calendar/gui/dialogs/copy-source-dialog.h"
 +#include "calendar/gui/dialogs/memo-editor.h"
 +
 +#include "e-memo-shell-backend.h"
 +#include "e-memo-shell-content.h"
 +#include "e-memo-shell-sidebar.h"
 +#include "e-memo-shell-view-actions.h"
 +
 +#define E_MEMO_SHELL_VIEW_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_MEMO_SHELL_VIEW, EMemoShellViewPrivate))
 +
 +/* Shorthand, requires a variable named "shell_window". */
 +#define ACTION(name) \
 +	(E_SHELL_WINDOW_ACTION_##name (shell_window))
 +#define ACTION_GROUP(name) \
 +	(E_SHELL_WINDOW_ACTION_GROUP_##name (shell_window))
 +
 +/* For use in dispose() methods. */
 +#define DISPOSE(obj) \
 +	G_STMT_START { \
 +	if ((obj) != NULL) { g_object_unref (obj); (obj) = NULL; } \
 +	} G_STMT_END
 +
 +/* ETable Specifications */
 +#define ETSPEC_FILENAME		"e-memo-table.etspec"
 +
 +G_BEGIN_DECLS
 +
 +/* Filter items are displayed in ascending order.
 + * Non-negative values are reserved for categories. */
 +enum {
 +	MEMO_FILTER_ANY_CATEGORY	= -2,
 +	MEMO_FILTER_UNMATCHED		= -1
 +};
 +
 +/* Search items are displayed in ascending order. */
 +enum {
 +	MEMO_SEARCH_SUMMARY_CONTAINS,
 +	MEMO_SEARCH_DESCRIPTION_CONTAINS,
 +	MEMO_SEARCH_ANY_FIELD_CONTAINS
 +};
 +
 +struct _EMemoShellViewPrivate {
 +
 +	/* These are just for convenience. */
 +	EMemoShellBackend *memo_shell_backend;
 +	EMemoShellContent *memo_shell_content;
 +	EMemoShellSidebar *memo_shell_sidebar;
 +
 +	EActivity *activity;
 +};
 +
 +void		e_memo_shell_view_private_init
 +					(EMemoShellView *memo_shell_view,
 +					 EShellViewClass *shell_view_class);
 +void		e_memo_shell_view_private_constructed
 +					(EMemoShellView *memo_shell_view);
 +void		e_memo_shell_view_private_dispose
 +					(EMemoShellView *memo_shell_view);
 +void		e_memo_shell_view_private_finalize
 +					(EMemoShellView *memo_shell_view);
 +
 +/* Private Utilities */
 +
 +void		e_memo_shell_view_actions_init
 +					(EMemoShellView *memo_shell_view);
 +void		e_memo_shell_view_execute_search
 +					(EMemoShellView *memo_shell_view);
 +void		e_memo_shell_view_open_memo
 +					(EMemoShellView *memo_shell_view,
 +					 ECalModelComponent *comp_data);
 +void		e_memo_shell_view_set_status_message
 +					(EMemoShellView *memo_shell_view,
 +					 const gchar *status_message,
 +					 gdouble percent);
 +void		e_memo_shell_view_update_sidebar
 +					(EMemoShellView *memo_shell_view);
 +void		e_memo_shell_view_update_search_filter
 +					(EMemoShellView *memo_shell_view);
 +
 +G_END_DECLS
 +
 +#endif /* E_MEMO_SHELL_VIEW_PRIVATE_H */
diff --cc calendar/module/e-memo-shell-view.c
index 22c4472,0000000..e2964b0
mode 100644,000000..100644
--- a/calendar/module/e-memo-shell-view.c
+++ b/calendar/module/e-memo-shell-view.c
@@@ -1,222 -1,0 +1,222 @@@
 +/*
 + * e-memo-shell-view.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-memo-shell-view-private.h"
 +
 +static gpointer parent_class;
 +static GType memo_shell_view_type;
 +
 +static void
 +memo_shell_view_dispose (GObject *object)
 +{
 +	e_memo_shell_view_private_dispose (E_MEMO_SHELL_VIEW (object));
 +
 +	/* Chain up to parent's dispose() method. */
 +	G_OBJECT_CLASS (parent_class)->dispose (object);
 +}
 +
 +static void
 +memo_shell_view_finalize (GObject *object)
 +{
 +	e_memo_shell_view_private_finalize (E_MEMO_SHELL_VIEW (object));
 +
 +	/* Chain up to parent's finalize() method. */
 +	G_OBJECT_CLASS (parent_class)->finalize (object);
 +}
 +
 +static void
 +memo_shell_view_constructed (GObject *object)
 +{
 +	/* Chain up to parent's constructed() method. */
 +	G_OBJECT_CLASS (parent_class)->constructed (object);
 +
 +	e_memo_shell_view_private_constructed (E_MEMO_SHELL_VIEW (object));
 +}
 +
 +static void
 +memo_shell_view_update_actions (EShellView *shell_view)
 +{
 +	EMemoShellViewPrivate *priv;
 +	EShellContent *shell_content;
 +	EShellSidebar *shell_sidebar;
 +	EShellWindow *shell_window;
 +	GtkAction *action;
 +	const gchar *label;
 +	gboolean sensitive;
 +	guint32 state;
 +
 +	/* Be descriptive. */
 +	gboolean any_memos_selected;
 +	gboolean has_primary_source;
 +	gboolean multiple_memos_selected;
 +	gboolean primary_source_is_system;
 +	gboolean selection_has_url;
 +	gboolean single_memo_selected;
 +	gboolean sources_are_editable;
 +
 +	priv = E_MEMO_SHELL_VIEW_GET_PRIVATE (shell_view);
 +
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	shell_content = e_shell_view_get_shell_content (shell_view);
 +	state = e_shell_content_check_state (shell_content);
 +
 +	single_memo_selected =
 +		(state & E_MEMO_SHELL_CONTENT_SELECTION_SINGLE);
 +	multiple_memos_selected =
 +		(state & E_MEMO_SHELL_CONTENT_SELECTION_MULTIPLE);
 +	sources_are_editable =
 +		(state & E_MEMO_SHELL_CONTENT_SELECTION_CAN_EDIT);
 +	selection_has_url =
 +		(state & E_MEMO_SHELL_CONTENT_SELECTION_HAS_URL);
 +
 +	shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
 +	state = e_shell_sidebar_check_state (shell_sidebar);
 +
 +	has_primary_source =
 +		(state & E_MEMO_SHELL_SIDEBAR_HAS_PRIMARY_SOURCE);
 +	primary_source_is_system =
 +		(state & E_MEMO_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_SYSTEM);
 +
 +	any_memos_selected =
 +		(single_memo_selected || multiple_memos_selected);
 +
 +	action = ACTION (MEMO_CLIPBOARD_COPY);
 +	sensitive = any_memos_selected;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (MEMO_CLIPBOARD_CUT);
 +	sensitive = any_memos_selected && sources_are_editable;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (MEMO_CLIPBOARD_PASTE);
 +	sensitive = sources_are_editable;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (MEMO_DELETE);
 +	sensitive = any_memos_selected && sources_are_editable;
 +	gtk_action_set_sensitive (action, sensitive);
 +	if (multiple_memos_selected)
 +		label = _("Delete Memos");
 +	else
 +		label = _("Delete Memo");
 +	g_object_set (action, "label", label, NULL);
 +
 +	action = ACTION (MEMO_FORWARD);
 +	sensitive = single_memo_selected;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (MEMO_LIST_COPY);
 +	sensitive = has_primary_source;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (MEMO_LIST_DELETE);
 +	sensitive = has_primary_source && !primary_source_is_system;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (MEMO_LIST_PROPERTIES);
 +	sensitive = has_primary_source;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (MEMO_LIST_RENAME);
 +	sensitive = has_primary_source;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (MEMO_OPEN);
 +	sensitive = single_memo_selected;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (MEMO_OPEN_URL);
 +	sensitive = single_memo_selected && selection_has_url;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (MEMO_PRINT);
 +	sensitive = single_memo_selected;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (MEMO_SAVE_AS);
 +	sensitive = single_memo_selected;
 +	gtk_action_set_sensitive (action, sensitive);
 +}
 +
 +static void
 +memo_shell_view_class_init (EMemoShellViewClass *class,
 +                            GTypeModule *type_module)
 +{
 +	GObjectClass *object_class;
 +	EShellViewClass *shell_view_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (EMemoShellViewPrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->dispose = memo_shell_view_dispose;
 +	object_class->finalize = memo_shell_view_finalize;
 +	object_class->constructed = memo_shell_view_constructed;
 +
 +	shell_view_class = E_SHELL_VIEW_CLASS (class);
 +	shell_view_class->label = _("Memos");
 +	shell_view_class->icon_name = "evolution-memos";
 +	shell_view_class->ui_definition = "evolution-memos.ui";
 +	shell_view_class->ui_manager_id = "org.gnome.evolution.memos";
 +	shell_view_class->search_options = "/memo-search-options";
 +	shell_view_class->search_rules = "memotypes.xml";
 +	shell_view_class->new_shell_content = e_memo_shell_content_new;
 +	shell_view_class->new_shell_sidebar = e_memo_shell_sidebar_new;
 +	shell_view_class->update_actions = memo_shell_view_update_actions;
 +}
 +
 +static void
 +memo_shell_view_init (EMemoShellView *memo_shell_view,
 +                      EShellViewClass *shell_view_class)
 +{
 +	memo_shell_view->priv =
 +		E_MEMO_SHELL_VIEW_GET_PRIVATE (memo_shell_view);
 +
 +	e_memo_shell_view_private_init (memo_shell_view, shell_view_class);
 +}
 +
 +GType
 +e_memo_shell_view_get_type (void)
 +{
 +	return memo_shell_view_type;
 +}
 +
 +void
 +e_memo_shell_view_register_type (GTypeModule *type_module)
 +{
 +	const GTypeInfo type_info = {
 +		sizeof (EMemoShellViewClass),
 +		(GBaseInitFunc) NULL,
 +		(GBaseFinalizeFunc) NULL,
 +		(GClassInitFunc) memo_shell_view_class_init,
 +		(GClassFinalizeFunc) NULL,
 +		type_module,
 +		sizeof (EMemoShellView),
 +		0,    /* n_preallocs */
 +		(GInstanceInitFunc) memo_shell_view_init,
 +		NULL  /* value_table */
 +	};
 +
 +	memo_shell_view_type = g_type_module_register_type (
 +		type_module, E_TYPE_SHELL_VIEW,
 +		"EMemoShellView", &type_info, 0);
 +}
diff --cc calendar/module/e-memo-shell-view.h
index 0cbaa7b,0000000..686ae73
mode 100644,000000..100644
--- a/calendar/module/e-memo-shell-view.h
+++ b/calendar/module/e-memo-shell-view.h
@@@ -1,67 -1,0 +1,67 @@@
 +/*
 + * e-memo-shell-view.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_MEMO_SHELL_VIEW_H
 +#define E_MEMO_SHELL_VIEW_H
 +
 +#include <shell/e-shell-view.h>
 +#include <libedataserver/e-source-list.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_MEMO_SHELL_VIEW \
 +	(e_memo_shell_view_get_type ())
 +#define E_MEMO_SHELL_VIEW(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_MEMO_SHELL_VIEW, EMemoShellView))
 +#define E_MEMO_SHELL_VIEW_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_MEMO_SHELL_VIEW, EMemoShellViewClass))
 +#define E_IS_MEMO_SHELL_VIEW(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_MEMO_SHELL_VIEW))
 +#define E_IS_MEMO_SHELL_VIEW_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), E_TYPE_MEMO_SHELL_VIEW))
 +#define E_MEMO_SHELL_VIEW_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_MEMO_SHELL_VIEW, EMemoShellViewClass))
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _EMemoShellView EMemoShellView;
 +typedef struct _EMemoShellViewClass EMemoShellViewClass;
 +typedef struct _EMemoShellViewPrivate EMemoShellViewPrivate;
 +
 +struct _EMemoShellView {
 +	EShellView parent;
 +	EMemoShellViewPrivate *priv;
 +};
 +
 +struct _EMemoShellViewClass {
 +	EShellViewClass parent_class;
 +};
 +
 +GType		e_memo_shell_view_get_type	(void);
 +void		e_memo_shell_view_register_type	(GTypeModule *type_module);
 +
 +G_END_DECLS
 +
 +#endif /* E_MEMO_SHELL_VIEW_H */
diff --cc calendar/module/e-task-shell-backend.c
index 9e35b47,0000000..6bded3e
mode 100644,000000..100644
--- a/calendar/module/e-task-shell-backend.c
+++ b/calendar/module/e-task-shell-backend.c
@@@ -1,621 -1,0 +1,621 @@@
 +/*
 + * e-task-shell-backend.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-task-shell-backend.h"
 +
 +#include <string.h>
 +#include <glib/gi18n.h>
 +#include <libecal/e-cal.h>
 +#include <libedataserver/e-url.h>
 +#include <libedataserver/e-source.h>
 +#include <libedataserver/e-source-list.h>
 +#include <libedataserver/e-source-group.h>
 +
 +#include "shell/e-shell.h"
 +#include "shell/e-shell-backend.h"
 +#include "shell/e-shell-window.h"
 +
 +#include "calendar/common/authentication.h"
 +#include "calendar/gui/calendar-config.h"
 +#include "calendar/gui/comp-util.h"
 +#include "calendar/gui/dialogs/calendar-setup.h"
 +#include "calendar/gui/dialogs/task-editor.h"
 +
 +#include "e-task-shell-content.h"
 +#include "e-task-shell-migrate.h"
 +#include "e-task-shell-sidebar.h"
 +#include "e-task-shell-view.h"
 +
 +#define E_TASK_SHELL_BACKEND_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_TASK_SHELL_BACKEND, ETaskShellBackendPrivate))
 +
 +#define WEB_BASE_URI		"webcal://"
 +#define PERSONAL_RELATIVE_URI	"system"
 +
 +struct _ETaskShellBackendPrivate {
 +	ESourceList *source_list;
 +};
 +
 +enum {
 +	PROP_0,
 +	PROP_SOURCE_LIST
 +};
 +
 +static gpointer parent_class;
 +static GType task_shell_backend_type;
 +
 +static void
 +task_module_ensure_sources (EShellBackend *shell_backend)
 +{
 +	/* XXX This is basically the same algorithm across all modules.
 +	 *     Maybe we could somehow integrate this into EShellBackend? */
 +
 +	ETaskShellBackendPrivate *priv;
 +	ESourceGroup *on_this_computer;
 +	ESourceGroup *on_the_web;
 +	ESource *personal;
 +	GSList *groups, *iter;
 +	const gchar *data_dir;
 +	const gchar *name;
 +	gchar *base_uri;
 +	gchar *filename;
 +
 +	on_this_computer = NULL;
 +	on_the_web = NULL;
 +	personal = NULL;
 +
 +	priv = E_TASK_SHELL_BACKEND_GET_PRIVATE (shell_backend);
 +
 +	if (!e_cal_get_sources (&priv->source_list, E_CAL_SOURCE_TYPE_TODO, NULL)) {
 +		g_warning ("Could not get task sources from GConf!");
 +		return;
 +	}
 +
 +	data_dir = e_shell_backend_get_data_dir (shell_backend);
 +	filename = g_build_filename (data_dir, "local", NULL);
 +	base_uri = g_filename_to_uri (filename, NULL, NULL);
 +	g_free (filename);
 +
 +	groups = e_source_list_peek_groups (priv->source_list);
 +	for (iter = groups; iter != NULL; iter = iter->next) {
 +		ESourceGroup *source_group = iter->data;
 +		const gchar *group_base_uri;
 +
 +		group_base_uri = e_source_group_peek_base_uri (source_group);
 +
 +		/* Compare only "file://" part.  If the user's home
 +		 * changes, we do not want to create another group. */
 +		if (on_this_computer == NULL &&
 +			strncmp (base_uri, group_base_uri, 7) == 0)
 +			on_this_computer = source_group;
 +
 +		else if (on_the_web == NULL &&
 +			strcmp (WEB_BASE_URI, group_base_uri) == 0)
 +			on_the_web = source_group;
 +	}
 +
 +	name = _("On This Computer");
 +
 +	if (on_this_computer != NULL) {
 +		GSList *sources;
 +		const gchar *group_base_uri;
 +
 +		/* Force the group name to the current locale. */
 +		e_source_group_set_name (on_this_computer, name);
 +
 +		sources = e_source_group_peek_sources (on_this_computer);
 +		group_base_uri = e_source_group_peek_base_uri (on_this_computer);
 +
 +		/* Make sure this group includes a "Personal" source. */
 +		for (iter = sources; iter != NULL; iter = iter->next) {
 +			ESource *source = iter->data;
 +			const gchar *relative_uri;
 +
 +			relative_uri = e_source_peek_relative_uri (source);
 +			if (relative_uri == NULL)
 +				continue;
 +
 +			if (strcmp (PERSONAL_RELATIVE_URI, relative_uri) != 0)
 +				continue;
 +
 +			personal = source;
 +			break;
 +		}
 +
 +		/* Make sure we have the correct base URI.  This can
 +		 * change when the user's home directory changes. */
 +		if (strcmp (base_uri, group_base_uri) != 0) {
 +			e_source_group_set_base_uri (
 +				on_this_computer, base_uri);
 +
 +			/* XXX We shouldn't need this sync call here as
 +			 *     set_base_uri() results in synching to GConf,
 +			 *     but that happens in an idle loop and too late
 +			 *     to prevent the user from seeing a "Cannot
 +			 *     Open ... because of invalid URI" error. */
 +			e_source_list_sync (priv->source_list, NULL);
 +		}
 +
 +	} else {
 +		ESourceGroup *source_group;
 +
 +		source_group = e_source_group_new (name, base_uri);
 +		e_source_list_add_group (priv->source_list, source_group, -1);
 +		g_object_unref (source_group);
 +	}
 +
 +	name = _("Personal");
 +
 +	if (personal == NULL) {
 +		ESource *source;
 +		GSList *selected;
 +		gchar *primary;
 +
 +		source = e_source_new (name, PERSONAL_RELATIVE_URI);
 +		e_source_group_add_source (on_this_computer, source, -1);
 +		g_object_unref (source);
 +
 +		primary = calendar_config_get_primary_tasks ();
 +		selected = calendar_config_get_tasks_selected ();
 +
 +		if (primary == NULL && selected == NULL) {
 +			const gchar *uid;
 +
 +			uid = e_source_peek_uid (source);
 +			selected = g_slist_prepend (NULL, g_strdup (uid));
 +
 +			calendar_config_set_primary_tasks (uid);
 +			calendar_config_set_tasks_selected (selected);
 +		}
 +
 +		g_slist_foreach (selected, (GFunc) g_free, NULL);
 +		g_slist_free (selected);
 +		g_free (primary);
 +	} else {
 +		/* Force the source name to the current locale. */
 +		e_source_set_name (personal, name);
 +	}
 +
 +	name = _("On The Web");
 +
 +	if (on_the_web == NULL) {
 +		ESourceGroup *source_group;
 +
 +		source_group = e_source_group_new (name, WEB_BASE_URI);
 +		e_source_list_add_group (priv->source_list, source_group, -1);
 +		g_object_unref (source_group);
 +	} else {
 +		/* Force the group name to the current locale. */
 +		e_source_group_set_name (on_the_web, name);
 +	}
 +
 +	g_free (base_uri);
 +}
 +
 +static void
 +task_module_cal_opened_cb (ECal *cal,
 +                           ECalendarStatus status,
 +                           GtkAction *action)
 +{
 +	EShell *shell;
 +	ECalComponent *comp;
 +	CompEditor *editor;
 +	CompEditorFlags flags = 0;
 +	const gchar *action_name;
 +
 +	/* FIXME Pass this in. */
 +	shell = e_shell_get_default ();
 +
 +	/* XXX Handle errors better. */
 +	if (status != E_CALENDAR_STATUS_OK)
 +		return;
 +
 +	action_name = gtk_action_get_name (action);
 +
 +	flags |= COMP_EDITOR_NEW_ITEM;
 +	if (strcmp (action_name, "task-assigned-new") == 0) {
 +		flags |= COMP_EDITOR_IS_ASSIGNED;
 +		flags |= COMP_EDITOR_USER_ORG;
 +	}
 +
 +	editor = task_editor_new (cal, shell, flags);
 +	comp = cal_comp_task_new_with_defaults (cal);
 +	comp_editor_edit_comp (editor, comp);
 +
 +	gtk_window_present (GTK_WINDOW (editor));
 +
 +	g_object_unref (comp);
 +	g_object_unref (cal);
 +}
 +
 +static void
 +action_task_new_cb (GtkAction *action,
 +                    EShellWindow *shell_window)
 +{
 +	ECal *cal = NULL;
 +	ECalSourceType source_type;
 +	ESourceList *source_list;
 +	gchar *uid;
 +
 +	/* This callback is used for both tasks and assigned tasks. */
 +
 +	source_type = E_CAL_SOURCE_TYPE_TODO;
 +
 +	if (!e_cal_get_sources (&source_list, source_type, NULL)) {
 +		g_warning ("Could not get task sources from GConf!");
 +		return;
 +	}
 +
 +	uid = calendar_config_get_primary_tasks ();
 +
 +	if (uid != NULL) {
 +		ESource *source;
 +
 +		source = e_source_list_peek_source_by_uid (source_list, uid);
 +		if (source != NULL)
 +			cal = auth_new_cal_from_source (source, source_type);
 +		g_free (uid);
 +	}
 +
 +	if (cal == NULL)
 +		cal = auth_new_cal_from_default (source_type);
 +
 +	g_return_if_fail (cal != NULL);
 +
 +	g_signal_connect (
 +		cal, "cal-opened",
 +		G_CALLBACK (task_module_cal_opened_cb), action);
 +
 +	e_cal_open_async (cal, FALSE);
 +}
 +
 +static void
 +action_task_list_new_cb (GtkAction *action,
 +                         EShellWindow *shell_window)
 +{
 +	calendar_setup_new_task_list (GTK_WINDOW (shell_window));
 +}
 +
 +static GtkActionEntry item_entries[] = {
 +
 +	{ "task-new",
 +	  "stock_task",
 +	  NC_("New", "_Task"),
 +	  "<Shift><Control>t",
 +	  N_("Create a new task"),
 +	  G_CALLBACK (action_task_new_cb) },
 +
 +	{ "task-assigned-new",
 +	  "stock_task",
 +	  N_("Assigne_d Task"),
 +	  NULL,
 +	  N_("Create a new assigned task"),
 +	  G_CALLBACK (action_task_new_cb) }
 +};
 +
 +static GtkActionEntry source_entries[] = {
 +
 +	{ "task-list-new",
 +	  "stock_todo",
 +	  NC_("New", "Tas_k List"),
 +	  NULL,
 +	  N_("Create a new task list"),
 +	  G_CALLBACK (action_task_list_new_cb) }
 +};
 +
 +static gboolean
 +task_module_handle_uri_cb (EShellBackend *shell_backend,
 +                           const gchar *uri)
 +{
 +	EShell *shell;
 +	CompEditor *editor;
 +	CompEditorFlags flags = 0;
 +	ECal *client;
 +	ECalComponent *comp;
 +	ESource *source;
 +	ESourceList *source_list;
 +	ECalSourceType source_type;
 +	EUri *euri;
 +	icalcomponent *icalcomp;
 +	icalproperty *icalprop;
 +	const gchar *cp;
 +	gchar *source_uid = NULL;
 +	gchar *comp_uid = NULL;
 +	gchar *comp_rid = NULL;
 +	gboolean handled = FALSE;
 +	GError *error = NULL;
 +
 +	source_type = E_CAL_SOURCE_TYPE_TODO;
 +	shell = e_shell_backend_get_shell (shell_backend);
 +
 +	if (strncmp (uri, "task:", 5) != 0)
 +		return FALSE;
 +
 +	euri = e_uri_new (uri);
 +	cp = euri->query;
 +	if (cp == NULL)
 +		goto exit;
 +
 +	while (*cp != '\0') {
 +		gchar *header;
 +		gchar *content;
 +		gsize header_len;
 +		gsize content_len;
 +
 +		header_len = strcspn (cp, "=&");
 +
 +		/* If it's malformed, give up. */
 +		if (cp[header_len] != '=')
 +			break;
 +
 +		header = (gchar *) cp;
 +		header[header_len] = '\0';
 +		cp += header_len + 1;
 +
 +		content_len = strcspn (cp, "&");
 +
 +		content = g_strndup (cp, content_len);
 +		if (g_ascii_strcasecmp (header, "source-uid") == 0)
 +			source_uid = g_strdup (content);
 +		else if (g_ascii_strcasecmp (header, "comp-uid") == 0)
 +			comp_uid = g_strdup (content);
 +		else if (g_ascii_strcasecmp (header, "comp-rid") == 0)
 +			comp_rid = g_strdup (content);
 +		g_free (content);
 +
 +		cp += content_len;
 +		if (*cp == '&') {
 +			cp++;
 +			if (strcmp (cp, "amp;") == 0)
 +				cp += 4;
 +		}
 +	}
 +
 +	if (source_uid != NULL || comp_uid != NULL)
 +		goto exit;
 +
 +	/* URI is valid, so consider it handled.  Whether
 +	 * we successfully open it is another matter... */
 +	handled = TRUE;
 +
 +	if (!e_cal_get_sources (&source_list, source_type, NULL)) {
 +		g_printerr ("Could not get task sources from GConf!\n");
 +		goto exit;
 +	}
 +
 +	source = e_source_list_peek_source_by_uid (source_list, source_uid);
 +	if (source == NULL) {
 +		g_printerr ("No source for UID `%s'\n", source_uid);
 +		g_object_unref (source_list);
 +		goto exit;
 +	}
 +
 +	client = auth_new_cal_from_source (source, source_type);
 +	if (client == NULL || !e_cal_open (client, TRUE, &error)) {
 +		g_printerr ("%s\n", error->message);
 +		g_object_unref (source_list);
 +		g_error_free (error);
 +		goto exit;
 +	}
 +
 +	/* XXX Copied from e_task_shell_view_open_task().
 +	 *     Clearly a new utility function is needed. */
 +
 +	editor = comp_editor_find_instance (comp_uid);
 +
 +	if (editor != NULL)
 +		goto present;
 +
 +	if (!e_cal_get_object (client, comp_uid, comp_rid, &icalcomp, &error)) {
 +		g_printerr ("%s\n", error->message);
 +		g_object_unref (source_list);
 +		g_error_free (error);
 +		goto exit;
 +	}
 +
 +	comp = e_cal_component_new ();
 +	e_cal_component_set_icalcomponent (comp, icalcomp);
 +
 +	icalprop = icalcomponent_get_first_property (
 +		icalcomp, ICAL_ATTENDEE_PROPERTY);
 +	if (icalprop != NULL)
 +		flags |= COMP_EDITOR_IS_ASSIGNED;
 +
 +	if (itip_organizer_is_user (comp, client))
 +		flags |= COMP_EDITOR_USER_ORG;
 +
 +	if (!e_cal_component_has_attendees (comp))
 +		flags |= COMP_EDITOR_USER_ORG;
 +
 +	editor = task_editor_new (client, shell, flags);
 +	comp_editor_edit_comp (editor, comp);
 +
 +	g_object_unref (comp);
 +
 +present:
 +	gtk_window_present (GTK_WINDOW (editor));
 +
 +	g_object_unref (source_list);
 +	g_object_unref (client);
 +
 +exit:
 +	g_free (source_uid);
 +	g_free (comp_uid);
 +	g_free (comp_rid);
 +
 +	e_uri_free (euri);
 +
 +	return handled;
 +}
 +
 +static void
 +task_module_window_created_cb (EShellBackend *shell_backend,
 +                               GtkWindow *window)
 +{
 +	const gchar *module_name;
 +
 +	if (!E_IS_SHELL_WINDOW (window))
 +		return;
 +
 +	module_name = E_SHELL_BACKEND_GET_CLASS (shell_backend)->name;
 +
 +	e_shell_window_register_new_item_actions (
 +		E_SHELL_WINDOW (window), module_name,
 +		item_entries, G_N_ELEMENTS (item_entries));
 +
 +	e_shell_window_register_new_source_actions (
 +		E_SHELL_WINDOW (window), module_name,
 +		source_entries, G_N_ELEMENTS (source_entries));
 +}
 +
 +static void
 +task_shell_backend_get_property (GObject *object,
 +                                 guint property_id,
 +                                 GValue *value,
 +                                 GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_SOURCE_LIST:
 +			g_value_set_object (
 +				value,
 +				e_task_shell_backend_get_source_list (
 +				E_TASK_SHELL_BACKEND (object)));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +task_shell_backend_dispose (GObject *object)
 +{
 +	ETaskShellBackendPrivate *priv;
 +
 +	priv = E_TASK_SHELL_BACKEND_GET_PRIVATE (object);
 +
 +	if (priv->source_list != NULL) {
 +		g_object_unref (priv->source_list);
 +		priv->source_list = NULL;
 +	}
 +
 +	/* Chain up to parent's dispose() method. */
 +	G_OBJECT_CLASS (parent_class)->dispose (object);
 +}
 +
 +static void
 +task_shell_backend_constructed (GObject *object)
 +{
 +	EShell *shell;
 +	EShellBackend *shell_backend;
 +
 +	shell_backend = E_SHELL_BACKEND (object);
 +	shell = e_shell_backend_get_shell (shell_backend);
 +
 +	task_module_ensure_sources (shell_backend);
 +
 +	g_signal_connect_swapped (
 +		shell, "handle-uri",
 +		G_CALLBACK (task_module_handle_uri_cb), shell_backend);
 +
 +	g_signal_connect_swapped (
 +		shell, "window-created",
 +		G_CALLBACK (task_module_window_created_cb), shell_backend);
 +}
 +
 +static void
 +task_shell_backend_class_init (ETaskShellBackendClass *class)
 +{
 +	GObjectClass *object_class;
 +	EShellBackendClass *shell_backend_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (ETaskShellBackendPrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->get_property = task_shell_backend_get_property;
 +	object_class->dispose = task_shell_backend_dispose;
 +	object_class->constructed = task_shell_backend_constructed;
 +
 +	shell_backend_class = E_SHELL_BACKEND_CLASS (class);
 +	shell_backend_class->shell_view_type = E_TYPE_TASK_SHELL_VIEW;
 +	shell_backend_class->name = "tasks";
 +	shell_backend_class->aliases = "";
 +	shell_backend_class->schemes = "task";
 +	shell_backend_class->sort_order = 600;
 +	shell_backend_class->start = NULL;
 +	shell_backend_class->is_busy = NULL;
 +	shell_backend_class->shutdown = NULL;
 +	shell_backend_class->migrate = e_task_shell_backend_migrate;
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_SOURCE_LIST,
 +		g_param_spec_object (
 +			"source-list",
 +			_("Source List"),
 +			_("The registry of task lists"),
 +			E_TYPE_SOURCE_LIST,
 +			G_PARAM_READABLE));
 +}
 +
 +static void
 +task_shell_backend_init (ETaskShellBackend *task_shell_backend)
 +{
 +	task_shell_backend->priv =
 +		E_TASK_SHELL_BACKEND_GET_PRIVATE (task_shell_backend);
 +}
 +
 +GType
 +e_task_shell_backend_get_type (void)
 +{
 +	return task_shell_backend_type;
 +}
 +
 +void
 +e_task_shell_backend_register_type (GTypeModule *type_module)
 +{
 +	const GTypeInfo type_info = {
 +		sizeof (ETaskShellBackendClass),
 +		(GBaseInitFunc) NULL,
 +		(GBaseFinalizeFunc) NULL,
 +		(GClassInitFunc) task_shell_backend_class_init,
 +		(GClassFinalizeFunc) NULL,
 +		NULL,  /* class_data */
 +		sizeof (ETaskShellBackend),
 +		0,     /* n_preallocs */
 +		(GInstanceInitFunc) task_shell_backend_init,
 +		NULL   /* value_table */
 +	};
 +
 +	task_shell_backend_type = g_type_module_register_type (
 +		type_module, E_TYPE_SHELL_BACKEND,
 +		"ETaskShellBackend", &type_info, 0);
 +}
 +
 +ESourceList *
 +e_task_shell_backend_get_source_list (ETaskShellBackend *task_shell_backend)
 +{
 +	g_return_val_if_fail (
 +		E_IS_TASK_SHELL_BACKEND (task_shell_backend), NULL);
 +
 +	return task_shell_backend->priv->source_list;
 +}
diff --cc calendar/module/e-task-shell-backend.h
index edb56f2,0000000..63b157a
mode 100644,000000..100644
--- a/calendar/module/e-task-shell-backend.h
+++ b/calendar/module/e-task-shell-backend.h
@@@ -1,70 -1,0 +1,70 @@@
 +/*
 + * e-task-shell-backend.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_TASK_SHELL_BACKEND_H
 +#define E_TASK_SHELL_BACKEND_H
 +
 +#include <shell/e-shell-backend.h>
 +#include <libedataserver/e-source-list.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_TASK_SHELL_BACKEND \
 +	(e_task_shell_backend_get_type ())
 +#define E_TASK_SHELL_BACKEND(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_TASK_SHELL_BACKEND, ETaskShellBackend))
 +#define E_TASK_SHELL_BACKEND_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_TASK_SHELL_BACKEND, ETaskShellBackendClass))
 +#define E_IS_TASK_SHELL_BACKEND(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_TASK_SHELL_BACKEND))
 +#define E_IS_TASK_SHELL_BACKEND_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), E_TYPE_TASK_SHELL_BACKEND))
 +#define E_TASK_SHELL_BACKEND_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_TASK_SHELL_BACKEND, ETaskShellBackendClass))
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _ETaskShellBackend ETaskShellBackend;
 +typedef struct _ETaskShellBackendClass ETaskShellBackendClass;
 +typedef struct _ETaskShellBackendPrivate ETaskShellBackendPrivate;
 +
 +struct _ETaskShellBackend {
 +	EShellBackend parent;
 +	ETaskShellBackendPrivate *priv;
 +};
 +
 +struct _ETaskShellBackendClass {
 +	EShellBackendClass parent_class;
 +};
 +
 +GType		e_task_shell_backend_get_type	(void);
 +void		e_task_shell_backend_register_type
 +					(GTypeModule *type_module);
 +ESourceList *	e_task_shell_backend_get_source_list
 +					(ETaskShellBackend *task_shell_backend);
 +
 +G_END_DECLS
 +
 +#endif /* E_TASK_SHELL_BACKEND_H */
diff --cc calendar/module/e-task-shell-content.c
index 280bc7c,0000000..0177c6c
mode 100644,000000..100644
--- a/calendar/module/e-task-shell-content.c
+++ b/calendar/module/e-task-shell-content.c
@@@ -1,700 -1,0 +1,700 @@@
 +/*
 + * e-task-shell-content.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-task-shell-content.h"
 +
 +#include <glib/gi18n.h>
 +
 +#include "e-util/gconf-bridge.h"
 +
 +#include "calendar/gui/calendar-config.h"
 +#include "calendar/gui/comp-util.h"
 +#include "calendar/gui/e-cal-model-tasks.h"
 +#include "calendar/gui/e-calendar-table.h"
 +#include "calendar/gui/e-calendar-table-config.h"
 +
 +#include "widgets/menus/gal-view-etable.h"
 +
 +#define E_TASK_SHELL_CONTENT_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_TASK_SHELL_CONTENT, ETaskShellContentPrivate))
 +
 +#define E_CALENDAR_TABLE_DEFAULT_STATE \
 +	"<?xml version=\"1.0\"?>" \
 +	"<ETableState>" \
 +	"  <column source=\"13\"/>" \
 +	"  <column source=\"14\"/>" \
 +	"  <column source=\"9\"/>" \
 +	"  <column source=\"5\"/>" \
 +	"  <grouping/>" \
 +	"</ETableState>"
 +
 +struct _ETaskShellContentPrivate {
 +	GtkWidget *paned;
 +	GtkWidget *task_table;
 +	GtkWidget *task_preview;
 +
 +	ECalModel *task_model;
 +	ECalendarTableConfig *table_config;
 +	GalViewInstance *view_instance;
 +
 +	gchar *current_uid;
 +};
 +
 +enum {
 +	PROP_0,
 +	PROP_MODEL,
 +	PROP_PREVIEW_VISIBLE
 +};
 +
 +enum {
 +	TARGET_VCALENDAR
 +};
 +
 +static GtkTargetEntry drag_types[] = {
- 	{ "text/calendar", 0, TARGET_VCALENDAR },
- 	{ "text/x-calendar", 0, TARGET_VCALENDAR }
++	{ (gchar *) "text/calendar", 0, TARGET_VCALENDAR },
++	{ (gchar *) "text/x-calendar", 0, TARGET_VCALENDAR }
 +};
 +
 +static gpointer parent_class;
 +static GType task_shell_content_type;
 +
 +static void
 +task_shell_content_display_view_cb (ETaskShellContent *task_shell_content,
 +                                    GalView *gal_view)
 +{
 +	ECalendarTable *task_table;
 +	ETable *table;
 +
 +	if (!GAL_IS_VIEW_ETABLE (gal_view))
 +		return;
 +
 +	task_table = e_task_shell_content_get_task_table (task_shell_content);
 +	table = e_calendar_table_get_table (task_table);
 +
 +	gal_view_etable_attach_table (GAL_VIEW_ETABLE (gal_view), table);
 +}
 +
 +static void
 +task_shell_content_table_foreach_cb (gint model_row,
 +                                     gpointer user_data)
 +{
 +	ECalModelComponent *comp_data;
 +	icalcomponent *clone;
 +	icalcomponent *vcal;
 +	gchar *string;
 +
 +	struct {
 +		ECalModel *model;
 +		GSList *list;
 +	} *foreach_data = user_data;
 +
 +	comp_data = e_cal_model_get_component_at (
 +		foreach_data->model, model_row);
 +
 +	vcal = e_cal_util_new_top_level ();
 +	clone = icalcomponent_new_clone (comp_data->icalcomp);
 +	e_cal_util_add_timezones_from_component (vcal, comp_data->icalcomp);
 +	icalcomponent_add_component (vcal, clone);
 +
 +	/* String is owned by libical; do not free. */
 +	string = icalcomponent_as_ical_string (vcal);
 +	if (string != NULL) {
 +		ESource *source;
 +		const gchar *source_uid;
 +
 +		source = e_cal_get_source (comp_data->client);
 +		source_uid = e_source_peek_uid (source);
 +
 +		foreach_data->list = g_slist_prepend (
 +			foreach_data->list,
 +			g_strdup_printf ("%s\n%s", source_uid, string));
 +	}
 +
 +	icalcomponent_free (vcal);
 +}
 +
 +static void
 +task_shell_content_table_drag_data_get_cb (ETaskShellContent *task_shell_content,
 +                                           gint row,
 +                                           gint col,
 +                                           GdkDragContext *context,
 +                                           GtkSelectionData *selection_data,
 +                                           guint info,
 +                                           guint time)
 +{
 +	ECalendarTable *task_table;
 +	ETable *table;
 +
 +	struct {
 +		ECalModel *model;
 +		GSList *list;
 +	} foreach_data;
 +
 +	if (info != TARGET_VCALENDAR)
 +		return;
 +
 +	task_table = e_task_shell_content_get_task_table (task_shell_content);
 +	table = e_calendar_table_get_table (task_table);
 +
 +	foreach_data.model = e_calendar_table_get_model (task_table);
 +	foreach_data.list = NULL;
 +
 +	e_table_selected_row_foreach (
 +		table, task_shell_content_table_foreach_cb,
 +		&foreach_data);
 +
 +	if (foreach_data.list != NULL) {
 +		cal_comp_selection_set_string_list (
 +			selection_data, foreach_data.list);
 +		g_slist_foreach (foreach_data.list, (GFunc) g_free, NULL);
 +		g_slist_free (foreach_data.list);
 +	}
 +}
 +
 +static void
 +task_shell_content_table_drag_data_delete_cb (ETaskShellContent *task_shell_content,
 +                                              gint row,
 +                                              gint col,
 +                                              GdkDragContext *context)
 +{
 +	/* Moved components are deleted from source immediately when moved,
 +	 * because some of them can be part of destination source, and we
 +	 * don't want to delete not-moved tasks.  There is no such information
 +	 * which event has been moved and which not, so skip this method. */
 +}
 +
 +static void
 +task_shell_content_cursor_change_cb (ETaskShellContent *task_shell_content,
 +                                     gint row,
 +                                     ETable *table)
 +{
 +	ECalComponentPreview *task_preview;
 +	ECalendarTable *task_table;
 +	ECalModel *task_model;
 +	ECalModelComponent *comp_data;
 +	ECalComponent *comp;
 +	const gchar *uid;
 +
 +	task_model = e_task_shell_content_get_task_model (task_shell_content);
 +	task_table = e_task_shell_content_get_task_table (task_shell_content);
 +	task_preview = e_task_shell_content_get_task_preview (task_shell_content);
 +
 +	if (e_table_selected_count (table) != 1) {
 +		e_cal_component_preview_clear (task_preview);
 +		return;
 +	}
 +
 +	row = e_table_get_cursor_row (table);
 +	comp_data = e_cal_model_get_component_at (task_model, row);
 +
 +	comp = e_cal_component_new ();
 +	e_cal_component_set_icalcomponent (
 +		comp, icalcomponent_new_clone (comp_data->icalcomp));
 +	e_cal_component_preview_display (
 +		task_preview, comp_data->client, comp);
 +
 +	e_cal_component_get_uid (comp, &uid);
 +	g_free (task_shell_content->priv->current_uid);
 +	task_shell_content->priv->current_uid = g_strdup (uid);
 +
 +	g_object_unref (comp);
 +}
 +
 +static void
 +task_shell_content_selection_change_cb (ETaskShellContent *task_shell_content,
 +                                        ETable *table)
 +{
 +	ECalComponentPreview *task_preview;
 +
 +	task_preview = e_task_shell_content_get_task_preview (task_shell_content);
 +
 +	if (e_table_selected_count (table) != 1)
 +		e_cal_component_preview_clear (task_preview);
 +}
 +
 +static void
 +task_shell_content_model_row_changed_cb (ETaskShellContent *task_shell_content,
 +                                         gint row,
 +                                         ETableModel *model)
 +{
 +	ECalModelComponent *comp_data;
 +	ECalendarTable *task_table;
 +	ETable *table;
 +	const gchar *current_uid;
 +	const gchar *uid;
 +
 +	current_uid = task_shell_content->priv->current_uid;
 +	if (current_uid == NULL)
 +		return;
 +
 +	comp_data = e_cal_model_get_component_at (E_CAL_MODEL (model), row);
 +	if (comp_data == NULL)
 +		return;
 +
 +	uid = icalcomponent_get_uid (comp_data->icalcomp);
 +	if (g_strcmp0 (uid, current_uid) != 0)
 +		return;
 +
 +	task_table = e_task_shell_content_get_task_table (task_shell_content);
 +	table = e_calendar_table_get_table (task_table);
 +
 +	task_shell_content_cursor_change_cb (task_shell_content, 0, table);
 +}
 +
 +static void
 +task_shell_content_set_property (GObject *object,
 +                                 guint property_id,
 +                                 const GValue *value,
 +                                 GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_PREVIEW_VISIBLE:
 +			e_task_shell_content_set_preview_visible (
 +				E_TASK_SHELL_CONTENT (object),
 +				g_value_get_boolean (value));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +task_shell_content_get_property (GObject *object,
 +                                 guint property_id,
 +                                 GValue *value,
 +                                 GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_MODEL:
 +			g_value_set_object (
 +				value, e_task_shell_content_get_task_model (
 +				E_TASK_SHELL_CONTENT (object)));
 +			return;
 +
 +		case PROP_PREVIEW_VISIBLE:
 +			g_value_set_boolean (
 +				value, e_task_shell_content_get_preview_visible (
 +				E_TASK_SHELL_CONTENT (object)));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +task_shell_content_dispose (GObject *object)
 +{
 +	ETaskShellContentPrivate *priv;
 +
 +	priv = E_TASK_SHELL_CONTENT_GET_PRIVATE (object);
 +
 +	if (priv->paned != NULL) {
 +		g_object_unref (priv->paned);
 +		priv->paned = NULL;
 +	}
 +
 +	if (priv->task_table != NULL) {
 +		g_object_unref (priv->task_table);
 +		priv->task_table = NULL;
 +	}
 +
 +	if (priv->task_preview != NULL) {
 +		g_object_unref (priv->task_preview);
 +		priv->task_preview = NULL;
 +	}
 +
 +	if (priv->task_model != NULL) {
 +		g_object_unref (priv->task_model);
 +		priv->task_model = NULL;
 +	}
 +
 +	if (priv->table_config != NULL) {
 +		g_object_unref (priv->table_config);
 +		priv->table_config = NULL;
 +	}
 +
 +	if (priv->view_instance != NULL) {
 +		g_object_unref (priv->view_instance);
 +		priv->view_instance = NULL;
 +	}
 +
 +	/* Chain up to parent's dispose() method. */
 +	G_OBJECT_CLASS (parent_class)->dispose (object);
 +}
 +
 +static void
 +task_shell_content_finalize (GObject *object)
 +{
 +	ETaskShellContentPrivate *priv;
 +
 +	priv = E_TASK_SHELL_CONTENT_GET_PRIVATE (object);
 +
 +	g_free (priv->current_uid);
 +
 +	/* Chain up to parent's finalize() method. */
 +	G_OBJECT_CLASS (parent_class)->finalize (object);
 +}
 +
 +static void
 +task_shell_content_constructed (GObject *object)
 +{
 +	ETaskShellContentPrivate *priv;
 +	EShellContent *shell_content;
 +	EShellView *shell_view;
 +	GalViewInstance *view_instance;
 +	ETable *table;
 +	GConfBridge *bridge;
 +	GtkWidget *container;
 +	GtkWidget *widget;
 +	const gchar *key;
 +
 +	priv = E_TASK_SHELL_CONTENT_GET_PRIVATE (object);
 +
 +	/* Chain up to parent's constructed() method. */
 +	G_OBJECT_CLASS (parent_class)->constructed (object);
 +
 +	shell_content = E_SHELL_CONTENT (object);
 +	shell_view = e_shell_content_get_shell_view (shell_content);
 +
 +	/* Build content widgets. */
 +
 +	container = GTK_WIDGET (object);
 +
 +	widget = gtk_vpaned_new ();
 +	gtk_container_add (GTK_CONTAINER (container), widget);
 +	priv->paned = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	container = widget;
 +
 +	widget = e_calendar_table_new (shell_view, priv->task_model);
 +	gtk_paned_add1 (GTK_PANED (container), widget);
 +	priv->task_table = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	widget = gtk_scrolled_window_new (NULL, NULL);
 +	gtk_scrolled_window_set_policy (
 +		GTK_SCROLLED_WINDOW (widget),
 +		GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
 +	gtk_scrolled_window_set_shadow_type (
 +		GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
 +	gtk_paned_add2 (GTK_PANED (container), widget);
 +	gtk_widget_show (widget);
 +
 +	container = widget;
 +
 +	widget = e_cal_component_preview_new ();
 +	e_cal_component_preview_set_default_timezone (
 +		E_CAL_COMPONENT_PREVIEW (widget),
 +		calendar_config_get_icaltimezone ());
 +	gtk_container_add (GTK_CONTAINER (container), widget);
 +	priv->task_preview = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	/* Configure the task table. */
 +
 +	widget = E_CALENDAR_TABLE (priv->task_table)->etable;
 +	table = e_table_scrolled_get_table (E_TABLE_SCROLLED (widget));
 +
 +	priv->table_config = e_calendar_table_config_new (
 +		E_CALENDAR_TABLE (priv->task_table));
 +
 +	e_table_set_state (table, E_CALENDAR_TABLE_DEFAULT_STATE);
 +
 +	e_table_drag_source_set (
 +		table, GDK_BUTTON1_MASK,
 +		drag_types, G_N_ELEMENTS (drag_types),
 +		GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_ASK);
 +
 +	g_signal_connect_swapped (
 +		table, "table-drag-data-get",
 +		G_CALLBACK (task_shell_content_table_drag_data_get_cb),
 +		object);
 +
 +	g_signal_connect_swapped (
 +		table, "table-drag-data-delete",
 +		G_CALLBACK (task_shell_content_table_drag_data_delete_cb),
 +		object);
 +
 +	g_signal_connect_swapped (
 +		table, "cursor-change",
 +		G_CALLBACK (task_shell_content_cursor_change_cb),
 +		object);
 +
 +	g_signal_connect_swapped (
 +		table, "selection-change",
 +		G_CALLBACK (task_shell_content_selection_change_cb),
 +		object);
 +
 +	g_signal_connect_swapped (
 +		priv->task_model, "model-row-changed",
 +		G_CALLBACK (task_shell_content_model_row_changed_cb),
 +		object);
 +
 +	/* Load the view instance. */
 +
 +	view_instance = e_shell_view_new_view_instance (shell_view, NULL);
 +	g_signal_connect_swapped (
 +		view_instance, "display-view",
 +		G_CALLBACK (task_shell_content_display_view_cb),
 +		object);
 +	gal_view_instance_load (view_instance);
 +	priv->view_instance = view_instance;
 +
 +	/* Bind GObject properties to GConf keys. */
 +
 +	bridge = gconf_bridge_get ();
 +
 +	object = G_OBJECT (priv->paned);
 +	key = "/apps/evolution/calendar/display/task_vpane_position";
 +	gconf_bridge_bind_property_delayed (bridge, key, object, "position");
 +}
 +
 +static guint32
 +task_shell_content_check_state (EShellContent *shell_content)
 +{
 +	ETaskShellContent *task_shell_content;
 +	ECalendarTable *task_table;
 +	ETable *table;
 +	GSList *list, *iter;
 +	gboolean assignable = TRUE;
 +	gboolean editable = TRUE;
 +	gboolean has_url = FALSE;
 +	gint n_selected;
 +	gint n_complete = 0;
 +	gint n_incomplete = 0;
 +	guint32 state = 0;
 +
 +	task_shell_content = E_TASK_SHELL_CONTENT (shell_content);
 +	task_table = e_task_shell_content_get_task_table (task_shell_content);
 +
 +	table = e_calendar_table_get_table (task_table);
 +	n_selected = e_table_selected_count (table);
 +
 +	list = e_calendar_table_get_selected (task_table);
 +	for (iter = list; iter != NULL; iter = iter->next) {
 +		ECalModelComponent *comp_data = iter->data;
 +		icalproperty *prop;
 +		const gchar *cap;
 +		gboolean read_only;
 +
 +		e_cal_is_read_only (comp_data->client, &read_only, NULL);
 +		editable &= !read_only;
 +
 +		cap = CAL_STATIC_CAPABILITY_NO_TASK_ASSIGNMENT;
 +		if (e_cal_get_static_capability (comp_data->client, cap))
 +			assignable = FALSE;
 +
 +		cap = CAL_STATIC_CAPABILITY_NO_CONV_TO_ASSIGN_TASK;
 +		if (e_cal_get_static_capability (comp_data->client, cap))
 +			assignable = FALSE;
 +
 +		prop = icalcomponent_get_first_property (
 +			comp_data->icalcomp, ICAL_URL_PROPERTY);
 +		has_url |= (prop != NULL);
 +
 +		prop = icalcomponent_get_first_property (
 +			comp_data->icalcomp, ICAL_COMPLETED_PROPERTY);
 +		if (prop != NULL)
 +			n_complete++;
 +		else
 +			n_incomplete++;
 +	}
 +	g_slist_free (list);
 +
 +	if (n_selected == 1)
 +		state |= E_TASK_SHELL_CONTENT_SELECTION_SINGLE;
 +	if (n_selected > 1)
 +		state |= E_TASK_SHELL_CONTENT_SELECTION_MULTIPLE;
 +	if (assignable)
 +		state |= E_TASK_SHELL_CONTENT_SELECTION_CAN_ASSIGN;
 +	if (editable)
 +		state |= E_TASK_SHELL_CONTENT_SELECTION_CAN_EDIT;
 +	if (n_complete > 0)
 +		state |= E_TASK_SHELL_CONTENT_SELECTION_HAS_COMPLETE;
 +	if (n_incomplete > 0)
 +		state |= E_TASK_SHELL_CONTENT_SELECTION_HAS_INCOMPLETE;
 +	if (has_url)
 +		state |= E_TASK_SHELL_CONTENT_SELECTION_HAS_URL;
 +
 +	return state;
 +}
 +
 +static void
 +task_shell_content_class_init (ETaskShellContentClass *class)
 +{
 +	GObjectClass *object_class;
 +	EShellContentClass *shell_content_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (ETaskShellContentPrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->set_property = task_shell_content_set_property;
 +	object_class->get_property = task_shell_content_get_property;
 +	object_class->dispose = task_shell_content_dispose;
 +	object_class->finalize = task_shell_content_finalize;
 +	object_class->constructed = task_shell_content_constructed;
 +
 +	shell_content_class = E_SHELL_CONTENT_CLASS (class);
 +	shell_content_class->check_state = task_shell_content_check_state;
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_MODEL,
 +		g_param_spec_object (
 +			"model",
 +			_("Model"),
 +			_("The task table model"),
 +			E_TYPE_CAL_MODEL,
 +			G_PARAM_READABLE));
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_PREVIEW_VISIBLE,
 +		g_param_spec_boolean (
 +			"preview-visible",
 +			_("Preview is Visible"),
 +			_("Whether the preview pane is visible"),
 +			TRUE,
 +			G_PARAM_READWRITE));
 +}
 +
 +static void
 +task_shell_content_init (ETaskShellContent *task_shell_content)
 +{
 +	task_shell_content->priv =
 +		E_TASK_SHELL_CONTENT_GET_PRIVATE (task_shell_content);
 +
 +	task_shell_content->priv->task_model = e_cal_model_tasks_new ();
 +
 +	/* Postpone widget construction until we have a shell view. */
 +}
 +
 +GType
 +e_task_shell_content_get_type (void)
 +{
 +	return task_shell_content_type;
 +}
 +
 +void
 +e_task_shell_content_register_type (GTypeModule *type_module)
 +{
 +	static const GTypeInfo type_info = {
 +		sizeof (ETaskShellContentClass),
 +		(GBaseInitFunc) NULL,
 +		(GBaseFinalizeFunc) NULL,
 +		(GClassInitFunc) task_shell_content_class_init,
 +		(GClassFinalizeFunc) NULL,
 +		NULL,  /* class_data */
 +		sizeof (ETaskShellContent),
 +		0,     /* n_preallocs */
 +		(GInstanceInitFunc) task_shell_content_init,
 +		NULL   /* value_table */
 +	};
 +
 +	task_shell_content_type = g_type_module_register_type (
 +		type_module, E_TYPE_SHELL_CONTENT,
 +		"ETaskShellContent", &type_info, 0);
 +}
 +
 +GtkWidget *
 +e_task_shell_content_new (EShellView *shell_view)
 +{
 +	g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
 +
 +	return g_object_new (
 +		E_TYPE_TASK_SHELL_CONTENT,
 +		"shell-view", shell_view, NULL);
 +}
 +
 +ECalModel *
 +e_task_shell_content_get_task_model (ETaskShellContent *task_shell_content)
 +{
 +	g_return_val_if_fail (
 +		E_IS_TASK_SHELL_CONTENT (task_shell_content), NULL);
 +
 +	return task_shell_content->priv->task_model;
 +}
 +
 +ECalComponentPreview *
 +e_task_shell_content_get_task_preview (ETaskShellContent *task_shell_content)
 +{
 +	g_return_val_if_fail (
 +		E_IS_TASK_SHELL_CONTENT (task_shell_content), NULL);
 +
 +	return E_CAL_COMPONENT_PREVIEW (
 +		task_shell_content->priv->task_preview);
 +}
 +
 +ECalendarTable *
 +e_task_shell_content_get_task_table (ETaskShellContent *task_shell_content)
 +{
 +	g_return_val_if_fail (
 +		E_IS_TASK_SHELL_CONTENT (task_shell_content), NULL);
 +
 +	return E_CALENDAR_TABLE (task_shell_content->priv->task_table);
 +}
 +
 +GalViewInstance *
 +e_task_shell_content_get_view_instance (ETaskShellContent *task_shell_content)
 +{
 +	g_return_val_if_fail (
 +		E_IS_TASK_SHELL_CONTENT (task_shell_content), NULL);
 +
 +	return task_shell_content->priv->view_instance;
 +}
 +
 +gboolean
 +e_task_shell_content_get_preview_visible (ETaskShellContent *task_shell_content)
 +{
 +	GtkPaned *paned;
 +	GtkWidget *child;
 +
 +	g_return_val_if_fail (
 +		E_IS_TASK_SHELL_CONTENT (task_shell_content), FALSE);
 +
 +	paned = GTK_PANED (task_shell_content->priv->paned);
 +	child = gtk_paned_get_child2 (paned);
 +
 +	return GTK_WIDGET_VISIBLE (child);
 +}
 +
 +void
 +e_task_shell_content_set_preview_visible (ETaskShellContent *task_shell_content,
 +                                          gboolean preview_visible)
 +{
 +	GtkPaned *paned;
 +	GtkWidget *child;
 +
 +	g_return_if_fail (E_IS_TASK_SHELL_CONTENT (task_shell_content));
 +
 +	paned = GTK_PANED (task_shell_content->priv->paned);
 +	child = gtk_paned_get_child2 (paned);
 +
 +	if (preview_visible)
 +		gtk_widget_show (child);
 +	else
 +		gtk_widget_hide (child);
 +
 +	g_object_notify (G_OBJECT (task_shell_content), "preview-visible");
 +}
diff --cc calendar/module/e-task-shell-content.h
index e749d61,0000000..7e0b212
mode 100644,000000..100644
--- a/calendar/module/e-task-shell-content.h
+++ b/calendar/module/e-task-shell-content.h
@@@ -1,100 -1,0 +1,100 @@@
 +/*
 + * e-task-shell-content.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_TASK_SHELL_CONTENT_H
 +#define E_TASK_SHELL_CONTENT_H
 +
 +#include <shell/e-shell-content.h>
 +#include <shell/e-shell-view.h>
 +
 +#include <calendar/gui/e-cal-model.h>
 +#include <calendar/gui/e-calendar-table.h>
 +#include <calendar/gui/e-cal-component-preview.h>
 +
 +#include <menus/gal-view-instance.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_TASK_SHELL_CONTENT \
 +	(e_task_shell_content_get_type ())
 +#define E_TASK_SHELL_CONTENT(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_TASK_SHELL_CONTENT, ETaskShellContent))
 +#define E_TASK_SHELL_CONTENT_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_TASK_SHELL_CONTENT, ETaskShellContentClass))
 +#define E_IS_TASK_SHELL_CONTENT(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_TASK_SHELL_CONTENT))
 +#define E_IS_TASK_SHELL_CONTENT_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), E_TYPE_TASK_SHELL_CONTENT))
 +#define E_TASK_SHELL_CONTENT_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_TASK_SHELL_CONTENT, ETaskShellContentClass))
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _ETaskShellContent ETaskShellContent;
 +typedef struct _ETaskShellContentClass ETaskShellContentClass;
 +typedef struct _ETaskShellContentPrivate ETaskShellContentPrivate;
 +
 +enum {
 +	E_TASK_SHELL_CONTENT_SELECTION_SINGLE		= 1 << 0,
 +	E_TASK_SHELL_CONTENT_SELECTION_MULTIPLE		= 1 << 1,
 +	E_TASK_SHELL_CONTENT_SELECTION_CAN_ASSIGN	= 1 << 2,
 +	E_TASK_SHELL_CONTENT_SELECTION_CAN_EDIT		= 1 << 3,
 +	E_TASK_SHELL_CONTENT_SELECTION_HAS_COMPLETE	= 1 << 4,
 +	E_TASK_SHELL_CONTENT_SELECTION_HAS_INCOMPLETE	= 1 << 5,
- 	E_TASK_SHELL_CONTENT_SELECTION_HAS_URL		= 1 << 6 
++	E_TASK_SHELL_CONTENT_SELECTION_HAS_URL		= 1 << 6
 +};
 +
 +struct _ETaskShellContent {
 +	EShellContent parent;
 +	ETaskShellContentPrivate *priv;
 +};
 +
 +struct _ETaskShellContentClass {
 +	EShellContentClass parent_class;
 +};
 +
 +GType		e_task_shell_content_get_type	(void);
 +void		e_task_shell_content_register_type
 +					(GTypeModule *type_module);
 +GtkWidget *	e_task_shell_content_new(EShellView *shell_view);
 +ECalModel *	e_task_shell_content_get_task_model
 +					(ETaskShellContent *task_shell_content);
 +ECalComponentPreview *
 +		e_task_shell_content_get_task_preview
 +					(ETaskShellContent *task_shell_content);
 +ECalendarTable *e_task_shell_content_get_task_table
 +					(ETaskShellContent *task_shell_content);
 +GalViewInstance *
 +		e_task_shell_content_get_view_instance
 +					(ETaskShellContent *task_shell_content);
 +gboolean	e_task_shell_content_get_preview_visible
 +					(ETaskShellContent *task_shell_content);
 +void		e_task_shell_content_set_preview_visible
 +					(ETaskShellContent *task_shell_content,
 +					 gboolean preview_visible);
 +
 +G_END_DECLS
 +
 +#endif /* E_TASK_SHELL_CONTENT_H */
diff --cc calendar/module/e-task-shell-migrate.c
index 76e53f7,0000000..9653fb9
mode 100644,000000..100644
--- a/calendar/module/e-task-shell-migrate.c
+++ b/calendar/module/e-task-shell-migrate.c
@@@ -1,664 -1,0 +1,664 @@@
 +/*
 + * e-task-shell-backend-migrate.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-task-shell-migrate.h"
 +
 +#include <string.h>
 +#include <sys/types.h>
 +#include <sys/stat.h>
 +#include <unistd.h>
 +#include <fcntl.h>
 +#include <errno.h>
 +
 +#include <glib/gi18n.h>
 +#include <glib/gstdio.h>
 +#include <libebackend/e-dbhash.h>
 +#include <libedataserver/e-source.h>
 +#include <libedataserver/e-source-group.h>
 +#include <libedataserver/e-source-list.h>
 +#include <libedataserver/e-xml-hash-utils.h>
 +#include <libedataserver/e-xml-utils.h>
 +
 +#include "e-util/e-bconf-map.h"
 +#include "e-util/e-folder-map.h"
 +#include "e-util/e-util-private.h"
 +#include "calendar/gui/calendar-config.h"
 +#include "calendar/gui/calendar-config-keys.h"
 +
 +#define WEBCAL_BASE_URI "webcal://"
 +#define PERSONAL_RELATIVE_URI "system"
 +
 +static e_gconf_map_t calendar_tasks_map[] = {
 +	/* /Calendar/Tasks */
 +	{ "HideCompletedTasks", "calendar/tasks/hide_completed", E_GCONF_MAP_BOOL },
 +	{ "HideCompletedTasksUnits", "calendar/tasks/hide_completed_units", E_GCONF_MAP_STRING },
 +	{ "HideCompletedTasksValue", "calendar/tasks/hide_completed_value", E_GCONF_MAP_INT },
 +	{ NULL },
 +};
 +
 +static e_gconf_map_t calendar_tasks_colours_map[] = {
 +	/* /Calendar/Tasks/Colors */
 +	{ "TasksDueToday", "calendar/tasks/colors/due_today", E_GCONF_MAP_STRING },
 +	{ "TasksOverDue", "calendar/tasks/colors/overdue", E_GCONF_MAP_STRING },
 +	{ "TasksDueToday", "calendar/tasks/colors/due_today", E_GCONF_MAP_STRING },
 +	{ NULL },
 +};
 +
 +static e_gconf_map_list_t task_remap_list[] = {
 +
 +	{ "/Calendar/Tasks", calendar_tasks_map },
 +	{ "/Calendar/Tasks/Colors", calendar_tasks_colours_map },
 +
 +	{ NULL },
 +};
 +
 +static GtkWidget *window;
 +static GtkLabel *label;
 +static GtkProgressBar *progress;
 +
 +#ifndef G_OS_WIN32
 +
 +/* No previous versions have been available on Win32, so don't
 + * bother with upgrade support from 1.x on Win32.
 + */
 +
 +static void
 +setup_progress_dialog (void)
 +{
 +	GtkWidget *vbox, *hbox, *w;
 +
 +	window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 +	gtk_window_set_title ((GtkWindow *) window, _("Migrating..."));
 +	gtk_window_set_modal ((GtkWindow *) window, TRUE);
 +	gtk_container_set_border_width ((GtkContainer *) window, 6);
 +
 +	vbox = gtk_vbox_new (FALSE, 6);
 +	gtk_widget_show (vbox);
 +	gtk_container_add ((GtkContainer *) window, vbox);
 +
 +	w = gtk_label_new (_("The location and hierarchy of the Evolution task "
 +			     "folders has changed since Evolution 1.x.\n\nPlease be "
 +			     "patient while Evolution migrates your folders..."));
 +
 +	gtk_label_set_line_wrap ((GtkLabel *) w, TRUE);
 +	gtk_widget_show (w);
 +	gtk_box_pack_start_defaults ((GtkBox *) vbox, w);
 +
 +	hbox = gtk_hbox_new (FALSE, 6);
 +	gtk_widget_show (hbox);
 +	gtk_box_pack_start_defaults ((GtkBox *) vbox, hbox);
 +
 +	label = (GtkLabel *) gtk_label_new ("");
 +	gtk_widget_show ((GtkWidget *) label);
 +	gtk_box_pack_start_defaults ((GtkBox *) hbox, (GtkWidget *) label);
 +
 +	progress = (GtkProgressBar *) gtk_progress_bar_new ();
 +	gtk_widget_show ((GtkWidget *) progress);
 +	gtk_box_pack_start_defaults ((GtkBox *) hbox, (GtkWidget *) progress);
 +
 +	gtk_widget_show (window);
 +}
 +
 +static void
 +dialog_close (void)
 +{
 +	gtk_widget_destroy ((GtkWidget *) window);
 +}
 +
 +static void
 +dialog_set_folder_name (const char *folder_name)
 +{
 +	char *text;
 +
 +	text = g_strdup_printf (_("Migrating '%s':"), folder_name);
 +	gtk_label_set_text (label, text);
 +	g_free (text);
 +
 +	gtk_progress_bar_set_fraction (progress, 0.0);
 +
 +	while (gtk_events_pending ())
 +		gtk_main_iteration ();
 +}
 +
 +static void
 +dialog_set_progress (double percent)
 +{
 +	char text[5];
 +
 +	snprintf (text, sizeof (text), "%d%%", (int) (percent * 100.0f));
 +
 +	gtk_progress_bar_set_fraction (progress, percent);
 +	gtk_progress_bar_set_text (progress, text);
 +
 +	while (gtk_events_pending ())
 +		gtk_main_iteration ();
 +}
 +
 +static gboolean
 +check_for_conflict (ESourceGroup *group, char *name)
 +{
 +	GSList *sources;
 +	GSList *s;
 +
 +	sources = e_source_group_peek_sources (group);
 +
 +	for (s = sources; s; s = s->next) {
 +		ESource *source = E_SOURCE (s->data);
 +
 +		if (!strcmp (e_source_peek_name (source), name))
 +			return TRUE;
 +	}
 +
 +	return FALSE;
 +}
 +
 +static char *
 +get_source_name (ESourceGroup *group, const char *path)
 +{
 +	char **p = g_strsplit (path, "/", 0);
 +	int i, j, starting_index;
 +	int num_elements;
 +	gboolean conflict;
 +	GString *s = g_string_new (NULL);
 +
 +	for (i = 0; p[i]; i ++) ;
 +
 +	num_elements = i;
 +	i--;
 +
 +	/* p[i] is now the last path element */
 +
 +	/* check if it conflicts */
 +	starting_index = i;
 +	do {
 +		for (j = starting_index; j < num_elements; j += 2) {
 +			if (j != starting_index)
 +				g_string_append_c (s, '_');
 +			g_string_append (s, p[j]);
 +		}
 +
 +		conflict = check_for_conflict (group, s->str);
 +
 +
 +		/* if there was a conflict back up 2 levels (skipping the /subfolder/ element) */
 +		if (conflict)
 +			starting_index -= 2;
 +
 +		/* we always break out if we can't go any further,
 +		   regardless of whether or not we conflict. */
 +		if (starting_index < 0)
 +			break;
 +
 +	} while (conflict);
 +	g_strfreev (p);
 +
 +	return g_string_free (s, FALSE);
 +}
 +
 +static gboolean
 +migrate_ical (ECal *old_ecal, ECal *new_ecal)
 +{
 +	GList *l, *objects;
 +	int num_added = 0;
 +	int num_objects;
 +	gboolean retval = TRUE;
 +
 +	/* both ecals are loaded, start the actual migration */
 +	if (!e_cal_get_object_list (old_ecal, "#t", &objects, NULL))
 +		return FALSE;
 +
 +	num_objects = g_list_length (objects);
 +	for (l = objects; l; l = l->next) {
 +		icalcomponent *ical_comp = l->data;
 +		GError *error = NULL;
 +
 +		if (!e_cal_create_object (new_ecal, ical_comp, NULL, &error)) {
 +			g_warning ("Migration of object failed: %s", error->message);
 +			retval = FALSE;
 +		}
 +
 +		g_clear_error (&error);
 +
 +		num_added ++;
 +		dialog_set_progress ((double)num_added / num_objects);
 +	}
 +
 +	g_list_foreach (objects, (GFunc) icalcomponent_free, NULL);
 +	g_list_free (objects);
 +
 +	return retval;
 +}
 +
 +static gboolean
 +migrate_ical_folder_to_source (char *old_path, ESource *new_source, ECalSourceType type)
 +{
 +	ECal *old_ecal = NULL, *new_ecal = NULL;
 +	ESource *old_source;
 +	ESourceGroup *group;
 +	char *old_uri = g_strdup_printf ("file://%s", old_path);
 +	GError *error = NULL;
 +	gboolean retval = FALSE;
 +
 +	group = e_source_group_new ("", old_uri);
 +	old_source = e_source_new ("", "");
 +	e_source_group_add_source (group, old_source, -1);
 +
 +	dialog_set_folder_name (e_source_peek_name (new_source));
 +
 +	if (!(old_ecal = e_cal_new (old_source, type))) {
 +		g_warning ("could not find a backend for '%s'", e_source_get_uri (old_source));
 +		goto finish;
 +	}
 +	if (!e_cal_open (old_ecal, FALSE, &error)) {
 +		g_warning ("failed to load source ecal for migration: '%s' (%s)", error->message,
 +			   e_source_get_uri (old_source));
 +		goto finish;
 +	}
 +
 +	if (!(new_ecal = e_cal_new (new_source, type))) {
 +		g_warning ("could not find a backend for '%s'", e_source_get_uri (new_source));
 +		goto finish;
 +	}
 +	if (!e_cal_open (new_ecal, FALSE, &error)) {
 +		g_warning ("failed to load destination ecal for migration: '%s' (%s)", error->message,
 +			   e_source_get_uri (new_source));
 +		goto finish;
 +	}
 +
 +	retval = migrate_ical (old_ecal, new_ecal);
 +
 +finish:
 +	g_clear_error (&error);
 +	if (old_ecal)
 +		g_object_unref (old_ecal);
 +	g_object_unref (group);
 +	if (new_ecal)
 +		g_object_unref (new_ecal);
 +	g_free (old_uri);
 +
 +	return retval;
 +}
 +
 +static gboolean
 +migrate_ical_folder (char *old_path, ESourceGroup *dest_group, char *source_name, ECalSourceType type)
 +{
 +	ESource *new_source;
 +	gboolean retval;
 +
 +	new_source = e_source_new (source_name, source_name);
 +	e_source_set_relative_uri (new_source, e_source_peek_uid (new_source));
 +	e_source_group_add_source (dest_group, new_source, -1);
 +
 +	retval = migrate_ical_folder_to_source (old_path, new_source, type);
 +
 +	g_object_unref (new_source);
 +
 +	return retval;
 +}
 +
 +#endif	/* !G_OS_WIN32 */
 +
 +#ifndef G_OS_WIN32
 +
 +static void
 +migrate_pilot_db_key (const char *key, gpointer user_data)
 +{
 +	EXmlHash *xmlhash = user_data;
 +
 +	e_xmlhash_add (xmlhash, key, "");
 +}
 +
 +static void
 +migrate_pilot_data (const char *component, const char *conduit, const char *old_path, const char *new_path)
 +{
 +	char *changelog, *map;
 +	const char *dent;
 +	const char *ext;
 +	char *filename;
 +	GDir *dir;
 +
 +	if (!(dir = g_dir_open (old_path, 0, NULL)))
 +		return;
 +
 +	map = g_alloca (12 + strlen (conduit));
 +	sprintf (map, "pilot-map-%s-", conduit);
 +
 +	changelog = g_alloca (24 + strlen (conduit));
 +	sprintf (changelog, "pilot-sync-evolution-%s-", conduit);
 +
 +	while ((dent = g_dir_read_name (dir))) {
 +		if (!strncmp (dent, map, strlen (map)) &&
 +		    ((ext = strrchr (dent, '.')) && !strcmp (ext, ".xml"))) {
 +			/* pilot map file - src and dest file formats are identical */
 +			unsigned char inbuf[4096];
 +			size_t nread, nwritten;
 +			int fd0, fd1;
 +			ssize_t n;
 +
 +			filename = g_build_filename (old_path, dent, NULL);
 +			if ((fd0 = g_open (filename, O_RDONLY|O_BINARY, 0)) == -1) {
 +				g_free (filename);
 +				continue;
 +			}
 +
 +			g_free (filename);
 +			filename = g_build_filename (new_path, dent, NULL);
 +			if ((fd1 = g_open (filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666)) == -1) {
 +				g_free (filename);
 +				close (fd0);
 +				continue;
 +			}
 +
 +			do {
 +				do {
 +					n = read (fd0, inbuf, sizeof (inbuf));
 +				} while (n == -1 && errno == EINTR);
 +
 +				if (n < 1)
 +					break;
 +
 +				nread = n;
 +				nwritten = 0;
 +				do {
 +					do {
 +						n = write (fd1, inbuf + nwritten, nread - nwritten);
 +					} while (n == -1 && errno == EINTR);
 +
 +					if (n > 0)
 +						nwritten += n;
 +				} while (nwritten < nread && n != -1);
 +
 +				if (n == -1)
 +					break;
 +			} while (1);
 +
 +			if (n != -1)
 +				n = fsync (fd1);
 +
 +			if (n == -1) {
 +				g_warning ("Failed to migrate %s: %s", dent, strerror (errno));
 +				g_unlink (filename);
 +			}
 +
 +			close (fd0);
 +			close (fd1);
 +			g_free (filename);
 +		} else if (!strncmp (dent, changelog, strlen (changelog)) &&
 +			   ((ext = strrchr (dent, '.')) && !strcmp (ext, ".db"))) {
 +			/* src and dest formats differ, src format is db3 while dest format is xml */
 +			EXmlHash *xmlhash;
 +			EDbHash *dbhash;
 +			struct stat st;
 +
 +			filename = g_build_filename (old_path, dent, NULL);
 +			if (g_stat (filename, &st) == -1) {
 +				g_free (filename);
 +				continue;
 +			}
 +
 +			dbhash = e_dbhash_new (filename);
 +			g_free (filename);
 +
 +			filename = g_strdup_printf ("%s/%s.ics-%s", new_path, component, dent);
 +			if (g_stat (filename, &st) != -1)
 +				g_unlink (filename);
 +			xmlhash = e_xmlhash_new (filename);
 +			g_free (filename);
 +
 +			e_dbhash_foreach_key (dbhash, migrate_pilot_db_key, xmlhash);
 +
 +			e_dbhash_destroy (dbhash);
 +
 +			e_xmlhash_write (xmlhash);
 +			e_xmlhash_destroy (xmlhash);
 +		}
 +	}
 +
 +	g_dir_close (dir);
 +}
 +
 +#endif
 +
 +static void
 +create_task_sources (EShellBackend *shell_backend,
 +		     ESourceList *source_list,
 +		     ESourceGroup **on_this_computer,
 +		     ESourceGroup **on_the_web,
 +		     ESource **personal_source)
 +{
 +	GSList *groups;
 +	ESourceGroup *group;
 +	char *base_uri, *base_uri_proto;
 +	const gchar *base_dir;
 +
 +	*on_this_computer = NULL;
 +	*on_the_web = NULL;
 +	*personal_source = NULL;
 +
 +	base_dir = e_shell_backend_get_config_dir (shell_backend);
 +	base_uri = g_build_filename (base_dir, "local", NULL);
 +
 +	base_uri_proto = g_filename_to_uri (base_uri, NULL, NULL);
 +
 +	groups = e_source_list_peek_groups (source_list);
 +	if (groups) {
 +		/* groups are already there, we need to search for things... */
 +		GSList *g;
 +
 +		for (g = groups; g; g = g->next) {
 +
 +			group = E_SOURCE_GROUP (g->data);
 +
 +			if (!*on_this_computer && !strcmp (base_uri_proto, e_source_group_peek_base_uri (group)))
 +				*on_this_computer = g_object_ref (group);
 +			else if (!*on_the_web && !strcmp (WEBCAL_BASE_URI, e_source_group_peek_base_uri (group)))
 +				*on_the_web = g_object_ref (group);
 +		}
 +	}
 +
 +	if (*on_this_computer) {
 +		/* make sure "Personal" shows up as a source under
 +		   this group */
 +		GSList *sources = e_source_group_peek_sources (*on_this_computer);
 +		GSList *s;
 +		for (s = sources; s; s = s->next) {
 +			ESource *source = E_SOURCE (s->data);
 +			const gchar *relative_uri;
 +
 +			relative_uri = e_source_peek_relative_uri (source);
 +			if (relative_uri == NULL)
 +				continue;
 +			if (!strcmp (PERSONAL_RELATIVE_URI, relative_uri)) {
 +				*personal_source = g_object_ref (source);
 +				break;
 +			}
 +		}
 +	} else {
 +		/* create the local source group */
 +		group = e_source_group_new (_("On This Computer"), base_uri_proto);
 +		e_source_list_add_group (source_list, group, -1);
 +
 +		*on_this_computer = group;
 +	}
 +
 +	if (!*personal_source) {
 +		/* Create the default Person task list */
 +		ESource *source = e_source_new (_("Personal"), PERSONAL_RELATIVE_URI);
 +		e_source_group_add_source (*on_this_computer, source, -1);
 +
 +		if (!calendar_config_get_primary_tasks () && !calendar_config_get_tasks_selected ()) {
 +			GSList selected;
 +
 +			calendar_config_set_primary_tasks (e_source_peek_uid (source));
 +
 +			selected.data = (gpointer)e_source_peek_uid (source);
 +			selected.next = NULL;
 +			calendar_config_set_tasks_selected (&selected);
 +		}
 +
 +		e_source_set_color_spec (source, "#BECEDD");
 +		*personal_source = source;
 +	}
 +
 +	if (!*on_the_web) {
 +		/* Create the Webcal source group */
 +		group = e_source_group_new (_("On The Web"), WEBCAL_BASE_URI);
 +		e_source_list_add_group (source_list, group, -1);
 +
 +		*on_the_web = group;
 +	}
 +
 +	g_free (base_uri_proto);
 +	g_free (base_uri);
 +}
 +
 +gboolean
 +e_task_shell_backend_migrate (EShellBackend *shell_backend,
 +                             gint major,
 +                             gint minor,
 +                             gint micro,
 +                             GError **error)
 +{
 +	ESourceGroup *on_this_computer = NULL;
 +	ESourceGroup *on_the_web = NULL;
 +	ESource *personal_source = NULL;
 +	ESourceList *source_list;
 +	gboolean retval = FALSE;
 +
 +	source_list = g_object_get_data (
 +		G_OBJECT (source_list), "source-list");
 +
 +	/* we call this unconditionally now - create_groups either
 +	   creates the groups/sources or it finds the necessary
 +	   groups/sources. */
 +	create_task_sources (
 +		shell_backend, source_list, &on_this_computer,
 +		&on_the_web, &personal_source);
 +
 +#ifndef G_OS_WIN32
 +	if (major == 1) {
 +		xmlDocPtr config_doc = NULL;
 +		char *conf_file;
 +
 +		conf_file = g_build_filename (g_get_home_dir (), "evolution", "config.xmldb", NULL);
 +		if (g_file_test (conf_file, G_FILE_TEST_IS_REGULAR))
 +			config_doc = e_xml_parse_file (conf_file);
 +		g_free (conf_file);
 +
 +		if (config_doc && minor <= 2) {
 +			GConfClient *gconf;
 +			int res = 0;
 +
 +			/* move bonobo config to gconf */
 +			gconf = gconf_client_get_default ();
 +
 +			res = e_bconf_import (gconf, config_doc, task_remap_list);
 +
 +			g_object_unref (gconf);
 +
 +			xmlFreeDoc(config_doc);
 +
 +			if (res != 0) {
 +				g_set_error(error, 0, 0, _("Unable to migrate old settings from evolution/config.xmldb"));
 +				goto fail;
 +			}
 +		}
 +
 +		if (minor <= 4) {
 +			GSList *migration_dirs, *l;
 +			char *path, *local_task_folder;
 +
 +			setup_progress_dialog ();
 +
 +			path = g_build_filename (g_get_home_dir (), "evolution", "local", NULL);
 +			migration_dirs = e_folder_map_local_folders (path, "tasks");
 +			local_task_folder = g_build_filename (path, "Tasks", NULL);
 +			g_free (path);
 +
 +			if (personal_source)
 +				migrate_ical_folder_to_source (local_task_folder, personal_source, E_CAL_SOURCE_TYPE_TODO);
 +
 +			for (l = migration_dirs; l; l = l->next) {
 +				char *source_name;
 +
 +				if (personal_source && !strcmp ((char*)l->data, local_task_folder))
 +					continue;
 +
 +				source_name = get_source_name (on_this_computer, (char*)l->data);
 +
 +				if (!migrate_ical_folder (l->data, on_this_computer, source_name, E_CAL_SOURCE_TYPE_TODO)) {
 +					/* FIXME: domain/code */
 +					g_set_error(error, 0, 0, _("Unable to migrate tasks `%s'"), source_name);
 +					g_free(source_name);
 +					goto fail;
 +				}
 +
 +				g_free (source_name);
 +			}
 +
 +			g_free (local_task_folder);
 +
 +			dialog_close ();
 +		}
 +
 +		if (minor < 5 || (minor == 5 && micro <= 10)) {
 +			char *old_path, *new_path;
 +
 +			old_path = g_build_filename (g_get_home_dir (), "evolution", "local", "Tasks", NULL);
 +			new_path = g_build_filename (e_shell_backend_get_config_dir (shell_backend),
 +						     "local", "system", NULL);
 +			migrate_pilot_data ("tasks", "todo", old_path, new_path);
 +			g_free (new_path);
 +			g_free (old_path);
 +		}
 +
 +		/* we only need to do this next step if people ran
 +		   older versions of 1.5.  We need to clear out the
 +		   absolute URI's that were assigned to ESources
 +		   during one phase of development, as they take
 +		   precedent over relative uris (but aren't updated
 +		   when editing an ESource). */
 +		if (minor == 5 && micro <= 11) {
 +			GSList *g;
 +			for (g = e_source_list_peek_groups (source_list); g; g = g->next) {
 +				ESourceGroup *group = g->data;
 +				GSList *s;
 +
 +				for (s = e_source_group_peek_sources (group); s; s = s->next) {
 +					ESource *source = s->data;
 +					e_source_set_absolute_uri (source, NULL);
 +				}
 +			}
 +		}
 +	}
 +#endif	/* !G_OS_WIN32 */
 +	e_source_list_sync (source_list, NULL);
 +	retval = TRUE;
 +fail:
 +	if (on_this_computer)
 +		g_object_unref (on_this_computer);
 +	if (on_the_web)
 +		g_object_unref (on_the_web);
 +	if (personal_source)
 +		g_object_unref (personal_source);
 +
 +        return retval;
 +}
diff --cc calendar/module/e-task-shell-migrate.h
index 6853dd8,0000000..4cb91c9
mode 100644,000000..100644
--- a/calendar/module/e-task-shell-migrate.h
+++ b/calendar/module/e-task-shell-migrate.h
@@@ -1,38 -1,0 +1,38 @@@
 +/*
 + * e-task-shell-backend-migrate.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_TASK_SHELL_BACKEND_MIGRATE_H
 +#define E_TASK_SHELL_BACKEND_MIGRATE_H
 +
 +#include <glib.h>
 +#include <shell/e-shell-backend.h>
 +
 +G_BEGIN_DECLS
 +
 +gboolean	e_task_shell_backend_migrate	(EShellBackend *shell_backend,
 +						 gint major,
 +						 gint minor,
 +						 gint micro,
 +						 GError **error);
 +
 +G_END_DECLS
 +
 +#endif /* E_TASK_SHELL_BACKEND_MIGRATE_H */
diff --cc calendar/module/e-task-shell-sidebar.c
index f23a2be,0000000..827a0a0
mode 100644,000000..100644
--- a/calendar/module/e-task-shell-sidebar.c
+++ b/calendar/module/e-task-shell-sidebar.c
@@@ -1,696 -1,0 +1,696 @@@
 +/*
 + * e-task-shell-sidebar.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-task-shell-sidebar.h"
 +
 +#include <string.h>
 +#include <glib/gi18n.h>
 +#include <libecal/e-cal.h>
 +
 +#include "e-util/e-error.h"
 +#include "e-util/e-util.h"
 +#include "calendar/common/authentication.h"
 +#include "calendar/gui/calendar-config.h"
 +#include "calendar/gui/e-task-list-selector.h"
 +#include "calendar/gui/misc.h"
 +
 +#include "e-task-shell-backend.h"
 +#include "e-task-shell-view.h"
 +
 +#define E_TASK_SHELL_SIDEBAR_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_TASK_SHELL_SIDEBAR, ETaskShellSidebarPrivate))
 +
 +struct _ETaskShellSidebarPrivate {
 +	GtkWidget *selector;
 +
 +	/* UID -> Client */
 +	GHashTable *client_table;
 +};
 +
 +enum {
 +	PROP_0,
 +	PROP_SELECTOR
 +};
 +
 +enum {
 +	CLIENT_ADDED,
 +	CLIENT_REMOVED,
 +	STATUS_MESSAGE,
 +	LAST_SIGNAL
 +};
 +
 +static gpointer parent_class;
 +static guint signals[LAST_SIGNAL];
 +static GType task_shell_sidebar_type;
 +
 +static void
 +task_shell_sidebar_emit_client_added (ETaskShellSidebar *task_shell_sidebar,
 +                                      ECal *client)
 +{
 +	guint signal_id = signals[CLIENT_ADDED];
 +
 +	g_signal_emit (task_shell_sidebar, signal_id, 0, client);
 +}
 +
 +static void
 +task_shell_sidebar_emit_client_removed (ETaskShellSidebar *task_shell_sidebar,
 +                                        ECal *client)
 +{
 +	guint signal_id = signals[CLIENT_REMOVED];
 +
 +	g_signal_emit (task_shell_sidebar, signal_id, 0, client);
 +}
 +
 +static void
 +task_shell_sidebar_emit_status_message (ETaskShellSidebar *task_shell_sidebar,
 +                                        const gchar *status_message)
 +{
 +	guint signal_id = signals[STATUS_MESSAGE];
 +
 +	g_signal_emit (task_shell_sidebar, signal_id, 0, status_message, -1.0);
 +}
 +
 +static void
 +task_shell_sidebar_backend_died_cb (ETaskShellSidebar *task_shell_sidebar,
 +                                    ECal *client)
 +{
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	EShellSidebar *shell_sidebar;
 +	GHashTable *client_table;
 +	ESource *source;
 +	const gchar *uid;
 +
 +	client_table = task_shell_sidebar->priv->client_table;
 +
 +	shell_sidebar = E_SHELL_SIDEBAR (task_shell_sidebar);
 +	shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	source = e_cal_get_source (client);
 +	uid = e_source_peek_uid (source);
 +
 +	g_object_ref (source);
 +
 +	g_hash_table_remove (client_table, uid);
 +	task_shell_sidebar_emit_status_message (task_shell_sidebar, NULL);
 +
 +	e_error_run (
 +		GTK_WINDOW (shell_window),
 +		"calendar:tasks-crashed", NULL);
 +
 +	g_object_unref (source);
 +}
 +
 +static void
 +task_shell_sidebar_backend_error_cb (ETaskShellSidebar *task_shell_sidebar,
 +                                     const gchar *message,
 +                                     ECal *client)
 +{
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	EShellSidebar *shell_sidebar;
 +	GtkWidget *dialog;
 +	const gchar *uri;
 +	gchar *uri_no_passwd;
 +
 +	shell_sidebar = E_SHELL_SIDEBAR (task_shell_sidebar);
 +	shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	uri = e_cal_get_uri (client);
 +	uri_no_passwd = get_uri_without_password (uri);
 +
 +	dialog = gtk_message_dialog_new (
 +		GTK_WINDOW (shell_window),
 +		GTK_DIALOG_DESTROY_WITH_PARENT,
 +		GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
 +		_("Error on %s\n%s"),
 +		uri_no_passwd, message);
 +
 +	gtk_dialog_run (GTK_DIALOG (dialog));
 +	gtk_widget_destroy (dialog);
 +
 +	g_free (uri_no_passwd);
 +}
 +
 +static void
 +task_shell_sidebar_client_opened_cb (ETaskShellSidebar *task_shell_sidebar,
 +                                     ECalendarStatus status,
 +                                     ECal *client)
 +{
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	EShellSidebar *shell_sidebar;
 +	ESource *source;
 +
 +	source = e_cal_get_source (client);
 +
 +	shell_sidebar = E_SHELL_SIDEBAR (task_shell_sidebar);
 +	shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	if (status == E_CALENDAR_STATUS_AUTHENTICATION_FAILED ||
 +		status == E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED)
 +		auth_cal_forget_password (client);
 +
 +	switch (status) {
 +		case E_CALENDAR_STATUS_OK:
 +			g_signal_handlers_disconnect_matched (
 +				client, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
 +				task_shell_sidebar_client_opened_cb, NULL);
 +
 +			task_shell_sidebar_emit_status_message (
 +				task_shell_sidebar, _("Loading tasks"));
 +			task_shell_sidebar_emit_client_added (
 +				task_shell_sidebar, client);
 +			task_shell_sidebar_emit_status_message (
 +				task_shell_sidebar, NULL);
 +			break;
 +
 +		case E_CALENDAR_STATUS_AUTHENTICATION_FAILED:
 +			e_cal_open_async (client, FALSE);
 +			break;
 +
 +		case E_CALENDAR_STATUS_BUSY:
 +			break;
 +
 +		case E_CALENDAR_STATUS_REPOSITORY_OFFLINE:
 +			e_error_run (
 +				GTK_WINDOW (shell_window),
 +				"calendar:prompt-no-contents-offline-tasks",
 +				NULL);
 +			break;
 +
 +		default:
 +			task_shell_sidebar_emit_client_removed (
 +				task_shell_sidebar, client);
 +			break;
 +	}
 +}
 +
 +static void
 +task_shell_sidebar_row_changed_cb (ETaskShellSidebar *task_shell_sidebar,
 +                                   GtkTreePath *tree_path,
 +                                   GtkTreeIter *tree_iter,
 +                                   GtkTreeModel *tree_model)
 +{
 +	ESourceSelector *selector;
 +	ESource *source;
 +
 +	/* XXX ESourceSelector's underlying tree store has only one
 +	 *     column: ESource objects.  While we're not supposed to
 +	 *     know this, listening for "row-changed" signals from
 +	 *     the model is easier to deal with than the selector's
 +	 *     "selection-changed" signal, which doesn't tell you
 +	 *     _which_ row changed. */
 +
 +	selector = e_task_shell_sidebar_get_selector (task_shell_sidebar);
 +	gtk_tree_model_get (tree_model, tree_iter, 0, &source, -1);
 +
 +	/* XXX This signal gets emitted a lot while the model is being
 +	 *     rebuilt, during which time we won't get a valid ESource.
 +	 *     ESourceSelector should probably block this signal while
 +	 *     rebuilding the model, but we'll be forgiving and not
 +	 *     emit a warning. */
 +	if (!E_IS_SOURCE (source))
 +		return;
 +
 +	if (e_source_selector_source_is_selected (selector, source))
 +		e_task_shell_sidebar_add_source (task_shell_sidebar, source);
 +	else
 +		e_task_shell_sidebar_remove_source (task_shell_sidebar, source);
 +}
 +
 +static void
 +task_shell_sidebar_selection_changed_cb (ETaskShellSidebar *task_shell_sidebar,
 +                                         ESourceSelector *selector)
 +{
 +	GSList *list, *iter;
 +
 +	/* This signal is emitted less frequently than "row-changed",
 +	 * especially when the model is being rebuilt.  So we'll take
 +	 * it easy on poor GConf. */
 +
 +	list = e_source_selector_get_selection (selector);
 +
 +	for (iter = list; iter != NULL; iter = iter->next) {
 +		ESource *source = iter->data;
 +
 +		iter->data = (gpointer) e_source_peek_uid (source);
 +		g_object_unref (source);
 +	}
 +
 +	calendar_config_set_tasks_selected (list);
 +
 +	g_slist_free (list);
 +}
 +
 +static void
 +task_shell_sidebar_primary_selection_changed_cb (ETaskShellSidebar *task_shell_sidebar,
 +                                                 ESourceSelector *selector)
 +{
 +	ESource *source;
 +	const gchar *uid;
 +
 +	/* XXX ESourceSelector needs a "primary-selection-uid" property
 +	 *     so we can just bind the property with GConfBridge. */
 +
 +	source = e_source_selector_peek_primary_selection (selector);
 +	if (source == NULL)
 +		return;
 +
 +	uid = e_source_peek_uid (source);
 +	calendar_config_set_primary_tasks (uid);
 +}
 +
 +static void
 +task_shell_sidebar_get_property (GObject *object,
 +                                 guint property_id,
 +                                 GValue *value,
 +                                 GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_SELECTOR:
 +			g_value_set_object (
 +				value, e_task_shell_sidebar_get_selector (
 +				E_TASK_SHELL_SIDEBAR (object)));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +task_shell_sidebar_dispose (GObject *object)
 +{
 +	ETaskShellSidebarPrivate *priv;
 +
 +	priv = E_TASK_SHELL_SIDEBAR_GET_PRIVATE (object);
 +
 +	if (priv->selector != NULL) {
 +		g_object_unref (priv->selector);
 +		priv->selector = NULL;
 +	}
 +
 +	g_hash_table_remove_all (priv->client_table);
 +
 +	/* Chain up to parent's dispose() method. */
 +	G_OBJECT_CLASS (parent_class)->dispose (object);
 +}
 +
 +static void
 +task_shell_sidebar_finalize (GObject *object)
 +{
 +	ETaskShellSidebarPrivate *priv;
 +
 +	priv = E_TASK_SHELL_SIDEBAR_GET_PRIVATE (object);
 +
 +	g_hash_table_destroy (priv->client_table);
 +
 +	/* Chain up to parent's finalize() method. */
 +	G_OBJECT_CLASS (parent_class)->finalize (object);
 +}
 +
 +static void
 +task_shell_sidebar_constructed (GObject *object)
 +{
 +	ETaskShellSidebarPrivate *priv;
 +	EShellView *shell_view;
 +	EShellBackend *shell_backend;
 +	EShellSidebar *shell_sidebar;
 +	ESourceSelector *selector;
 +	ESourceList *source_list;
 +	ESource *source;
 +	GtkContainer *container;
 +	GtkTreeModel *model;
 +	GtkWidget *widget;
 +	AtkObject *a11y;
 +	GSList *list, *iter;
 +	gchar *uid;
 +
 +	priv = E_TASK_SHELL_SIDEBAR_GET_PRIVATE (object);
 +
 +	/* Chain up to parent's constructed() method. */
 +	G_OBJECT_CLASS (parent_class)->constructed (object);
 +
 +	shell_sidebar = E_SHELL_SIDEBAR (object);
 +	shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
 +	shell_backend = e_shell_view_get_shell_backend (shell_view);
 +
 +	source_list = e_task_shell_backend_get_source_list (
 +		E_TASK_SHELL_BACKEND (shell_backend));
 +
 +	container = GTK_CONTAINER (shell_sidebar);
 +
 +	widget = gtk_scrolled_window_new (NULL, NULL);
 +	gtk_scrolled_window_set_policy (
 +		GTK_SCROLLED_WINDOW (widget),
 +		GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
 +	gtk_scrolled_window_set_shadow_type (
 +		GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
 +	gtk_container_add (container, widget);
 +	gtk_widget_show (widget);
 +
 +	container = GTK_CONTAINER (widget);
 +
 +	widget = e_task_list_selector_new (source_list);
 +	e_source_selector_set_select_new (E_SOURCE_SELECTOR (widget), TRUE);
 +	gtk_container_add (container, widget);
 +	a11y = gtk_widget_get_accessible (widget);
 +	atk_object_set_name (a11y, _("Task List Selector"));
 +	priv->selector = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	/* Restore the selector state from the last session. */
 +
 +	selector = E_SOURCE_SELECTOR (priv->selector);
 +	model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
 +
 +	g_signal_connect_swapped (
 +		model, "row-changed",
 +		G_CALLBACK (task_shell_sidebar_row_changed_cb),
 +		object);
 +
 +	source = NULL;
 +	uid = calendar_config_get_primary_tasks ();
 +	if (uid != NULL)
 +		source = e_source_list_peek_source_by_uid (source_list, uid);
 +	if (source == NULL)
 +		source = e_source_list_peek_source_any (source_list);
 +	if (source != NULL)
 +		e_source_selector_set_primary_selection (selector, source);
 +	g_free (uid);
 +
 +	list = calendar_config_get_tasks_selected ();
 +	for (iter = list; iter != NULL; iter = iter->next) {
 +		uid = iter->data;
 +		source = e_source_list_peek_source_by_uid (source_list, uid);
 +		g_free (uid);
 +
 +		if (source == NULL)
 +			continue;
 +
 +		e_source_selector_select_source (selector, source);
 +	}
 +	g_slist_free (list);
 +
 +	/* Listen for subsequent changes to the selector. */
 +
 +	g_signal_connect_swapped (
 +		widget, "selection-changed",
 +		G_CALLBACK (task_shell_sidebar_selection_changed_cb),
 +		object);
 +
 +	g_signal_connect_swapped (
 +		widget, "primary-selection-changed",
 +		G_CALLBACK (task_shell_sidebar_primary_selection_changed_cb),
 +		object);
 +}
 +
 +static guint32
 +task_shell_sidebar_check_state (EShellSidebar *shell_sidebar)
 +{
 +	ETaskShellSidebar *task_shell_sidebar;
 +	ESourceSelector *selector;
 +	ESource *source;
- 	gboolean is_system = FALSE; 
++	gboolean is_system = FALSE;
 +	guint32 state = 0;
 +
 +	task_shell_sidebar = E_TASK_SHELL_SIDEBAR (shell_sidebar);
 +	selector = e_task_shell_sidebar_get_selector (task_shell_sidebar);
 +	source = e_source_selector_peek_primary_selection (selector);
 +
 +	if (source != NULL) {
 +		const gchar *uri;
 +
 +		uri = e_source_peek_relative_uri (source);
 +		is_system = (uri == NULL || strcmp (uri, "system") == 0);
 +	}
 +
 +	if (source != NULL)
 +		state |= E_TASK_SHELL_SIDEBAR_HAS_PRIMARY_SOURCE;
 +	if (is_system)
 +		state |= E_TASK_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_SYSTEM;
 +
 +	return state;
 +}
 +
 +static void
 +task_shell_sidebar_client_removed (ETaskShellSidebar *task_shell_sidebar,
 +                                   ECal *client)
 +{
 +	ESourceSelector *selector;
 +	GHashTable *client_table;
 +	ESource *source;
 +	const gchar *uid;
 +
 +	client_table = task_shell_sidebar->priv->client_table;
 +	selector = e_task_shell_sidebar_get_selector (task_shell_sidebar);
 +
 +	g_signal_handlers_disconnect_matched (
 +		client, G_SIGNAL_MATCH_DATA, 0, 0,
 +		NULL, NULL, task_shell_sidebar);
 +
 +	source = e_cal_get_source (client);
 +	e_source_selector_unselect_source (selector, source);
 +
 +	uid = e_source_peek_uid (source);
 +	g_hash_table_remove (client_table, uid);
 +
 +	task_shell_sidebar_emit_status_message (task_shell_sidebar, NULL);
 +}
 +
 +static void
 +task_shell_sidebar_class_init (ETaskShellSidebarClass *class)
 +{
 +	GObjectClass *object_class;
 +	EShellSidebarClass *shell_sidebar_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (ETaskShellSidebarPrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->get_property = task_shell_sidebar_get_property;
 +	object_class->dispose = task_shell_sidebar_dispose;
 +	object_class->finalize = task_shell_sidebar_finalize;
 +	object_class->constructed = task_shell_sidebar_constructed;
 +
 +	shell_sidebar_class = E_SHELL_SIDEBAR_CLASS (class);
 +	shell_sidebar_class->check_state = task_shell_sidebar_check_state;
 +
 +	class->client_removed = task_shell_sidebar_client_removed;
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_SELECTOR,
 +		g_param_spec_object (
 +			"selector",
 +			_("Source Selector Widget"),
 +			_("This widget displays groups of task lists"),
 +			E_TYPE_SOURCE_SELECTOR,
 +			G_PARAM_READABLE));
 +
 +	signals[CLIENT_ADDED] = g_signal_new (
 +		"client-added",
 +		G_OBJECT_CLASS_TYPE (object_class),
 +		G_SIGNAL_RUN_LAST,
 +		G_STRUCT_OFFSET (ETaskShellSidebarClass, client_added),
 +		NULL, NULL,
 +		g_cclosure_marshal_VOID__OBJECT,
 +		G_TYPE_NONE, 1,
 +		E_TYPE_CAL);
 +
 +	signals[CLIENT_REMOVED] = g_signal_new (
 +		"client-removed",
 +		G_OBJECT_CLASS_TYPE (object_class),
 +		G_SIGNAL_RUN_LAST,
 +		G_STRUCT_OFFSET (ETaskShellSidebarClass, client_removed),
 +		NULL, NULL,
 +		g_cclosure_marshal_VOID__OBJECT,
 +		G_TYPE_NONE, 1,
 +		E_TYPE_CAL);
 +
 +	signals[STATUS_MESSAGE] = g_signal_new (
 +		"status-message",
 +		G_OBJECT_CLASS_TYPE (object_class),
 +		G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
 +		G_STRUCT_OFFSET (ETaskShellSidebarClass, status_message),
 +		NULL, NULL,
 +		e_marshal_VOID__STRING_DOUBLE,
 +		G_TYPE_NONE, 2,
 +		G_TYPE_STRING,
 +		G_TYPE_DOUBLE);
 +}
 +
 +static void
 +task_shell_sidebar_init (ETaskShellSidebar *task_shell_sidebar)
 +{
 +	GHashTable *client_table;
 +
 +	client_table = g_hash_table_new_full (
 +		g_str_hash, g_str_equal,
 +		(GDestroyNotify) g_free,
 +		(GDestroyNotify) g_object_unref);
 +
 +	task_shell_sidebar->priv =
 +		E_TASK_SHELL_SIDEBAR_GET_PRIVATE (task_shell_sidebar);
 +
 +	task_shell_sidebar->priv->client_table = client_table;
 +
 +	/* Postpone widget construction until we have a shell view. */
 +}
 +
 +GType
 +e_task_shell_sidebar_get_type (void)
 +{
 +	return task_shell_sidebar_type;
 +}
 +
 +void
 +e_task_shell_sidebar_register_type (GTypeModule *type_module)
 +{
 +	static const GTypeInfo type_info = {
 +		sizeof (ETaskShellSidebarClass),
 +		(GBaseInitFunc) NULL,
 +		(GBaseFinalizeFunc) NULL,
 +		(GClassInitFunc) task_shell_sidebar_class_init,
 +		(GClassFinalizeFunc) NULL,
 +		NULL,  /* class_data */
 +		sizeof (ETaskShellSidebar),
 +		0,     /* n_preallocs */
 +		(GInstanceInitFunc) task_shell_sidebar_init,
 +		NULL   /* value_table */
 +	};
 +
 +	task_shell_sidebar_type = g_type_module_register_type (
 +		type_module, E_TYPE_SHELL_SIDEBAR,
 +		"ETaskShellSidebar", &type_info, 0);
 +}
 +
 +GtkWidget *
 +e_task_shell_sidebar_new (EShellView *shell_view)
 +{
 +	g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
 +
 +	return g_object_new (
 +		E_TYPE_TASK_SHELL_SIDEBAR,
 +		"shell-view", shell_view, NULL);
 +}
 +
 +GList *
 +e_task_shell_sidebar_get_clients (ETaskShellSidebar *task_shell_sidebar)
 +{
 +	GHashTable *client_table;
 +
 +	g_return_val_if_fail (
 +		E_IS_TASK_SHELL_SIDEBAR (task_shell_sidebar), NULL);
 +
 +	client_table = task_shell_sidebar->priv->client_table;
 +
 +	return g_hash_table_get_values (client_table);
 +}
 +
 +ESourceSelector *
 +e_task_shell_sidebar_get_selector (ETaskShellSidebar *task_shell_sidebar)
 +{
 +	g_return_val_if_fail (
 +		E_IS_TASK_SHELL_SIDEBAR (task_shell_sidebar), NULL);
 +
 +	return E_SOURCE_SELECTOR (task_shell_sidebar->priv->selector);
 +}
 +
 +void
 +e_task_shell_sidebar_add_source (ETaskShellSidebar *task_shell_sidebar,
 +                                 ESource *source)
 +{
 +	ESourceSelector *selector;
 +	GHashTable *client_table;
 +	ECal *client;
 +	const gchar *uid;
 +	const gchar *uri;
 +	gchar *message;
 +
 +	g_return_if_fail (E_IS_TASK_SHELL_SIDEBAR (task_shell_sidebar));
 +	g_return_if_fail (E_IS_SOURCE (source));
 +
 +	client_table = task_shell_sidebar->priv->client_table;
 +	selector = e_task_shell_sidebar_get_selector (task_shell_sidebar);
 +
 +	uid = e_source_peek_uid (source);
 +	client = g_hash_table_lookup (client_table, uid);
 +
 +	if (client != NULL)
 +		return;
 +
 +	client = auth_new_cal_from_source (source, E_CAL_SOURCE_TYPE_TODO);
 +	g_return_if_fail (client != NULL);
 +
 +	g_signal_connect_swapped (
 +		client, "backend-died",
 +		G_CALLBACK (task_shell_sidebar_backend_died_cb),
 +		task_shell_sidebar);
 +
 +	g_signal_connect_swapped (
 +		client, "backend-error",
 +		G_CALLBACK (task_shell_sidebar_backend_error_cb),
 +		task_shell_sidebar);
 +
 +	g_hash_table_insert (client_table, g_strdup (uid), client);
 +	e_source_selector_select_source (selector, source);
 +
 +	uri = e_cal_get_uri (client);
 +	message = g_strdup_printf (_("Opening tasks at %s"), uri);
 +	task_shell_sidebar_emit_status_message (task_shell_sidebar, message);
 +	g_free (message);
 +
 +	g_signal_connect_swapped (
 +		client, "cal-opened",
 +		G_CALLBACK (task_shell_sidebar_client_opened_cb),
 +		task_shell_sidebar);
 +
 +	e_cal_open_async (client, FALSE);
 +}
 +
 +void
 +e_task_shell_sidebar_remove_source (ETaskShellSidebar *task_shell_sidebar,
 +                                    ESource *source)
 +{
 +	ESourceSelector *selector;
 +	GHashTable *client_table;
 +	ECal *client;
 +	const gchar *uid;
 +
 +	g_return_if_fail (E_IS_TASK_SHELL_SIDEBAR (task_shell_sidebar));
 +	g_return_if_fail (E_IS_SOURCE (source));
 +
 +	client_table = task_shell_sidebar->priv->client_table;
 +	selector = e_task_shell_sidebar_get_selector (task_shell_sidebar);
 +
 +	uid = e_source_peek_uid (source);
 +	client = g_hash_table_lookup (client_table, uid);
 +
 +	if (client == NULL)
 +		return;
 +
 +	task_shell_sidebar_emit_client_removed (task_shell_sidebar, client);
 +}
diff --cc calendar/module/e-task-shell-sidebar.h
index a6d7241,0000000..5d4c74f
mode 100644,000000..100644
--- a/calendar/module/e-task-shell-sidebar.h
+++ b/calendar/module/e-task-shell-sidebar.h
@@@ -1,97 -1,0 +1,97 @@@
 +/*
 + * e-task-shell-sidebar.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_TASK_SHELL_SIDEBAR_H
 +#define E_TASK_SHELL_SIDEBAR_H
 +
 +#include <libecal/e-cal.h>
 +#include <libedataserverui/e-source-selector.h>
 +
 +#include <shell/e-shell-sidebar.h>
 +#include <shell/e-shell-view.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_TASK_SHELL_SIDEBAR \
 +	(e_task_shell_sidebar_get_type ())
 +#define E_TASK_SHELL_SIDEBAR(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_TASK_SHELL_SIDEBAR, ETaskShellSidebar))
 +#define E_TASK_SHELL_SIDEBAR_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_TASK_SHELL_SIDEBAR, ETaskShellSidebarClass))
 +#define E_IS_TASK_SHELL_SIDEBAR(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_TASK_SHELL_SIDEBAR))
 +#define E_IS_TASK_SHELL_SIDEBAR_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), E_TYPE_TASK_SHELL_SIDEBAR))
 +#define E_TASK_SHELL_SIDEBAR_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_TASK_SHELL_SIDEBAR, ETaskShellSidebarClass))
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _ETaskShellSidebar ETaskShellSidebar;
 +typedef struct _ETaskShellSidebarClass ETaskShellSidebarClass;
 +typedef struct _ETaskShellSidebarPrivate ETaskShellSidebarPrivate;
 +
 +enum {
 +	E_TASK_SHELL_SIDEBAR_HAS_PRIMARY_SOURCE		= 1 << 0,
 +	E_TASK_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_SYSTEM	= 1 << 1
 +};
 +
 +struct _ETaskShellSidebar {
 +	EShellSidebar parent;
 +	ETaskShellSidebarPrivate *priv;
 +};
 +
 +struct _ETaskShellSidebarClass {
 +	EShellSidebarClass parent_class;
 +
 +	/* Signals */
 +	void	(*client_added)			(ETaskShellSidebar *task_shell_sidebar,
 +						 ECal *client);
 +	void	(*client_removed)		(ETaskShellSidebar *task_shell_sidebar,
 +						 ECal *client);
 +	void	(*status_message)		(ETaskShellSidebar *task_shell_sidebar,
 +						 const gchar *status_message,
 +						 gdouble percent);
 +};
 +
 +GType		e_task_shell_sidebar_get_type	(void);
 +void		e_task_shell_sidebar_register_type
 +					(GTypeModule *type_module);
 +GtkWidget *	e_task_shell_sidebar_new(EShellView *shell_view);
 +GList *		e_task_shell_sidebar_get_clients
 +					(ETaskShellSidebar *task_shell_sidebar);
 +ESourceSelector *
 +		e_task_shell_sidebar_get_selector
 +					(ETaskShellSidebar *task_shell_sidebar);
 +void		e_task_shell_sidebar_add_source
 +					(ETaskShellSidebar *task_shell_sidebar,
 +					 ESource *source);
 +void		e_task_shell_sidebar_remove_source
 +					(ETaskShellSidebar *task_shell_sidebar,
 +					 ESource *source);
 +
 +G_END_DECLS
 +
 +#endif /* E_TASK_SHELL_SIDEBAR_H */
diff --cc calendar/module/e-task-shell-view-actions.c
index 5de630e,0000000..4645ac0
mode 100644,000000..100644
--- a/calendar/module/e-task-shell-view-actions.c
+++ b/calendar/module/e-task-shell-view-actions.c
@@@ -1,1125 -1,0 +1,1125 @@@
 +/*
 + * e-task-shell-view-actions.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-task-shell-view-private.h"
 +
 +static void
 +action_gal_save_custom_view_cb (GtkAction *action,
 +                                ETaskShellView *task_shell_view)
 +{
 +	ETaskShellContent *task_shell_content;
 +	EShellView *shell_view;
 +	GalViewInstance *view_instance;
 +
 +	/* All shell views respond to the activation of this action,
 +	 * which is defined by EShellWindow.  But only the currently
 +	 * active shell view proceeds with saving the custom view. */
 +	shell_view = E_SHELL_VIEW (task_shell_view);
 +	if (!e_shell_view_is_active (shell_view))
 +		return;
 +
 +	task_shell_content = task_shell_view->priv->task_shell_content;
 +	view_instance = e_task_shell_content_get_view_instance (task_shell_content);
 +	gal_view_instance_save_as (view_instance);
 +}
 +
 +static void
 +action_search_execute_cb (GtkAction *action,
 +                          ETaskShellView *task_shell_view)
 +{
 +	EShellView *shell_view;
 +
 +	/* All shell views respond to the activation of this action,
 +	 * which is defined by EShellWindow.  But only the currently
 +	 * active shell view proceeds with executing the search. */
 +	shell_view = E_SHELL_VIEW (task_shell_view);
 +	if (!e_shell_view_is_active (shell_view))
 +		return;
 +
 +	e_task_shell_view_execute_search (task_shell_view);
 +}
 +
 +static void
 +action_search_filter_cb (GtkRadioAction *action,
 +                         GtkRadioAction *current,
 +                         ETaskShellView *task_shell_view)
 +{
 +	e_task_shell_view_execute_search (task_shell_view);
 +}
 +
 +static void
 +action_task_assign_cb (GtkAction *action,
 +                       ETaskShellView *task_shell_view)
 +{
 +	ETaskShellContent *task_shell_content;
 +	ECalendarTable *task_table;
 +	ECalModelComponent *comp_data;
 +	GSList *list;
 +
 +	task_shell_content = task_shell_view->priv->task_shell_content;
 +	task_table = e_task_shell_content_get_task_table (task_shell_content);
 +
 +	list = e_calendar_table_get_selected (task_table);
 +	g_return_if_fail (list != NULL);
 +	comp_data = list->data;
 +	g_slist_free (list);
 +
 +	/* XXX We only open the first selected task. */
 +	e_task_shell_view_open_task (task_shell_view, comp_data);
 +
 +	/* FIXME Need to actually assign the task. */
 +}
 +
 +static void
 +action_task_clipboard_copy_cb (GtkAction *action,
 +                               ETaskShellView *task_shell_view)
 +{
 +	ETaskShellContent *task_shell_content;
 +	ECalendarTable *task_table;
 +
 +	task_shell_content = task_shell_view->priv->task_shell_content;
 +	task_table = e_task_shell_content_get_task_table (task_shell_content);
 +
 +	e_calendar_table_copy_clipboard (task_table);
 +}
 +
 +static void
 +action_task_clipboard_cut_cb (GtkAction *action,
 +                              ETaskShellView *task_shell_view)
 +{
 +	ETaskShellContent *task_shell_content;
 +	ECalendarTable *task_table;
 +
 +	task_shell_content = task_shell_view->priv->task_shell_content;
 +	task_table = e_task_shell_content_get_task_table (task_shell_content);
 +
 +	e_calendar_table_cut_clipboard (task_table);
 +}
 +
 +static void
 +action_task_clipboard_paste_cb (GtkAction *action,
 +                                ETaskShellView *task_shell_view)
 +{
 +	ETaskShellContent *task_shell_content;
 +	ECalendarTable *task_table;
 +
 +	task_shell_content = task_shell_view->priv->task_shell_content;
 +	task_table = e_task_shell_content_get_task_table (task_shell_content);
 +
 +	e_calendar_table_paste_clipboard (task_table);
 +}
 +
 +static void
 +action_task_delete_cb (GtkAction *action,
 +                       ETaskShellView *task_shell_view)
 +{
 +	ETaskShellContent *task_shell_content;
 +	ECalComponentPreview *task_preview;
 +	ECalendarTable *task_table;
 +
 +	task_shell_content = task_shell_view->priv->task_shell_content;
 +	task_table = e_task_shell_content_get_task_table (task_shell_content);
 +	task_preview = e_task_shell_content_get_task_preview (task_shell_content);
 +
 +	e_task_shell_view_set_status_message (
 +		task_shell_view, _("Deleting selected tasks..."), -1.0);
 +	e_calendar_table_delete_selected (task_table);
 +	e_task_shell_view_set_status_message (task_shell_view, NULL, -1.0);
 +
 +	e_cal_component_preview_clear (task_preview);
 +}
 +
 +static void
 +action_task_forward_cb (GtkAction *action,
 +                        ETaskShellView *task_shell_view)
 +{
 +	ETaskShellContent *task_shell_content;
 +	ECalendarTable *task_table;
 +	ECalModelComponent *comp_data;
 +	ECalComponent *comp;
 +	icalcomponent *clone;
 +	GSList *list;
 +
 +	task_shell_content = task_shell_view->priv->task_shell_content;
 +	task_table = e_task_shell_content_get_task_table (task_shell_content);
 +
 +	list = e_calendar_table_get_selected (task_table);
 +	g_return_if_fail (list != NULL);
 +	comp_data = list->data;
 +	g_slist_free (list);
 +
 +	/* XXX We only forward the first selected task. */
 +	comp = e_cal_component_new ();
 +	clone = icalcomponent_new_clone (comp_data->icalcomp);
 +	e_cal_component_set_icalcomponent (comp, clone);
 +	itip_send_comp (
 +		E_CAL_COMPONENT_METHOD_PUBLISH, comp,
 +		comp_data->client, NULL, NULL, NULL, TRUE);
 +	g_object_unref (comp);
 +}
 +
 +static void
 +action_task_list_copy_cb (GtkAction *action,
 +                          ETaskShellView *task_shell_view)
 +{
 +	ETaskShellSidebar *task_shell_sidebar;
 +	EShellWindow *shell_window;
 +	EShellView *shell_view;
 +	ESourceSelector *selector;
 +	ESource *source;
 +
 +	shell_view = E_SHELL_VIEW (task_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	task_shell_sidebar = task_shell_view->priv->task_shell_sidebar;
 +	selector = e_task_shell_sidebar_get_selector (task_shell_sidebar);
 +	source = e_source_selector_peek_primary_selection (selector);
 +	g_return_if_fail (E_IS_SOURCE (source));
 +
 +	copy_source_dialog (
 +		GTK_WINDOW (shell_window),
 +		source, E_CAL_SOURCE_TYPE_TODO);
 +}
 +
 +static void
 +action_task_list_delete_cb (GtkAction *action,
 +                            ETaskShellView *task_shell_view)
 +{
 +	ETaskShellBackend *task_shell_backend;
 +	ETaskShellContent *task_shell_content;
 +	ETaskShellSidebar *task_shell_sidebar;
 +	EShellWindow *shell_window;
 +	EShellView *shell_view;
 +	ECalendarTable *task_table;
 +	ECal *client;
 +	ECalModel *model;
 +	ESourceSelector *selector;
 +	ESourceGroup *source_group;
 +	ESourceList *source_list;
 +	ESource *source;
 +	gint response;
 +	gchar *uri;
 +	GError *error = NULL;
 +
 +	shell_view = E_SHELL_VIEW (task_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	task_shell_backend = task_shell_view->priv->task_shell_backend;
 +	source_list = e_task_shell_backend_get_source_list (task_shell_backend);
 +
 +	task_shell_content = task_shell_view->priv->task_shell_content;
 +	task_table = e_task_shell_content_get_task_table (task_shell_content);
 +	model = e_calendar_table_get_model (task_table);
 +
 +	task_shell_sidebar = task_shell_view->priv->task_shell_sidebar;
 +	selector = e_task_shell_sidebar_get_selector (task_shell_sidebar);
 +	source = e_source_selector_peek_primary_selection (selector);
 +	g_return_if_fail (E_IS_SOURCE (source));
 +
 +	/* Ask for confirmation. */
 +	response = e_error_run (
 +		GTK_WINDOW (shell_window),
 +		"calendar:prompt-delete-task-list",
 +		e_source_peek_name (source));
 +	if (response != GTK_RESPONSE_YES)
 +		return;
 +
 +	uri = e_source_get_uri (source);
 +	client = e_cal_model_get_client_for_uri (model, uri);
 +	if (client == NULL)
 +		client = e_cal_new_from_uri (uri, E_CAL_SOURCE_TYPE_JOURNAL);
 +	g_free (uri);
 +
 +	g_return_if_fail (client != NULL);
 +
 +	if (!e_cal_remove (client, &error)) {
 +		g_warning ("%s", error->message);
 +		g_error_free (error);
 +		return;
 +	}
 +
 +	if (e_source_selector_source_is_selected (selector, source)) {
 +		e_task_shell_sidebar_remove_source (
 +			task_shell_sidebar, source);
 +		e_source_selector_unselect_source (selector, source);
 +	}
 +
 +	source_group = e_source_peek_group (source);
 +	e_source_group_remove_source (source_group, source);
 +
 +	if (!e_source_list_sync (source_list, &error)) {
 +		g_warning ("%s", error->message);
 +		g_error_free (error);
 +	}
 +}
 +
 +static void
 +action_task_list_new_cb (GtkAction *action,
 +                         ETaskShellView *task_shell_view)
 +{
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +
 +	shell_view = E_SHELL_VIEW (task_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +	calendar_setup_new_task_list (GTK_WINDOW (shell_window));
 +}
 +
 +static void
 +action_task_list_print_cb (GtkAction *action,
 +                           ETaskShellView *task_shell_view)
 +{
 +	ETaskShellContent *task_shell_content;
 +	ECalendarTable *task_table;
 +	ETable *table;
 +	GtkPrintOperationAction print_action;
 +
 +	task_shell_content = task_shell_view->priv->task_shell_content;
 +	task_table = e_task_shell_content_get_task_table (task_shell_content);
 +	table = e_calendar_table_get_table (task_table);
 +
 +	print_action = GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG;
 +	print_table (table, _("Print Tasks"), _("Tasks"), print_action);
 +}
 +
 +static void
 +action_task_list_print_preview_cb (GtkAction *action,
 +                                   ETaskShellView *task_shell_view)
 +{
 +	ETaskShellContent *task_shell_content;
 +	ECalendarTable *task_table;
 +	ETable *table;
 +	GtkPrintOperationAction print_action;
 +
 +	task_shell_content = task_shell_view->priv->task_shell_content;
 +	task_table = e_task_shell_content_get_task_table (task_shell_content);
 +	table = e_calendar_table_get_table (task_table);
 +
 +	print_action = GTK_PRINT_OPERATION_ACTION_PREVIEW;
 +	print_table (table, _("Print Tasks"), _("Tasks"), print_action);
 +}
 +
 +static void
 +action_task_list_properties_cb (GtkAction *action,
 +                                ETaskShellView *task_shell_view)
 +{
 +	ETaskShellSidebar *task_shell_sidebar;
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	ESource *source;
 +	ESourceSelector *selector;
 +
 +	shell_view = E_SHELL_VIEW (task_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	task_shell_sidebar = task_shell_view->priv->task_shell_sidebar;
 +	selector = e_task_shell_sidebar_get_selector (task_shell_sidebar);
 +	source = e_source_selector_peek_primary_selection (selector);
 +	g_return_if_fail (E_IS_SOURCE (source));
 +
 +	calendar_setup_edit_task_list (GTK_WINDOW (shell_window), source);
 +}
 +
 +static void
 +action_task_list_rename_cb (GtkAction *action,
 +                            ETaskShellView *task_shell_view)
 +{
 +	ETaskShellSidebar *task_shell_sidebar;
 +	ESourceSelector *selector;
 +
 +	task_shell_sidebar = task_shell_view->priv->task_shell_sidebar;
 +	selector = e_task_shell_sidebar_get_selector (task_shell_sidebar);
 +
 +	e_source_selector_edit_primary_selection (selector);
 +}
 +
 +static void
 +action_task_list_select_one_cb (GtkAction *action,
 +                                ETaskShellView *task_shell_view)
 +{
 +	ETaskShellSidebar *task_shell_sidebar;
 +	ESourceSelector *selector;
 +	ESource *primary;
 +	GSList *list, *iter;
 +
 +	/* XXX ESourceSelector should provide a function for this. */
 +
 +	task_shell_sidebar = task_shell_view->priv->task_shell_sidebar;
 +	selector = e_task_shell_sidebar_get_selector (task_shell_sidebar);
 +	primary = e_source_selector_peek_primary_selection (selector);
 +	g_return_if_fail (primary != NULL);
 +
 +	list = e_source_selector_get_selection (selector);
 +	for (iter = list; iter != NULL; iter = iter->next) {
 +		ESource *source = iter->data;
 +
 +		if (source == primary)
 +			continue;
 +
 +		e_source_selector_unselect_source (selector, source);
 +	}
 +	e_source_selector_free_selection (list);
 +
 +	e_source_selector_select_source (selector, primary);
 +}
 +
 +static void
 +action_task_mark_complete_cb (GtkAction *action,
 +                              ETaskShellView *task_shell_view)
 +{
 +	ETaskShellContent *task_shell_content;
 +	ECalendarTable *task_table;
 +	ECalModel *model;
 +	GSList *list, *iter;
 +
 +	task_shell_content = task_shell_view->priv->task_shell_content;
 +	task_table = e_task_shell_content_get_task_table (task_shell_content);
 +	list = e_calendar_table_get_selected (task_table);
 +	model = e_calendar_table_get_model (task_table);
 +
 +	for (iter = list; iter != NULL; iter = iter->next) {
 +		ECalModelComponent *comp_data = iter->data;
 +		e_cal_model_tasks_mark_comp_complete (
 +			E_CAL_MODEL_TASKS (model), comp_data);
 +	}
 +
 +	g_slist_free (list);
 +}
 +
 +static void
 +action_task_mark_incomplete_cb (GtkAction *action,
 +                                ETaskShellView *task_shell_view)
 +{
 +	ETaskShellContent *task_shell_content;
 +	ECalendarTable *task_table;
 +	ECalModel *model;
 +	GSList *list, *iter;
 +
 +	task_shell_content = task_shell_view->priv->task_shell_content;
 +	task_table = e_task_shell_content_get_task_table (task_shell_content);
 +	list = e_calendar_table_get_selected (task_table);
 +	model = e_calendar_table_get_model (task_table);
 +
 +	for (iter = list; iter != NULL; iter = iter->next) {
 +		ECalModelComponent *comp_data = iter->data;
 +		e_cal_model_tasks_mark_comp_incomplete (
 +			E_CAL_MODEL_TASKS (model), comp_data);
 +	}
 +
 +	g_slist_free (list);
 +}
 +
 +static void
 +action_task_new_cb (GtkAction *action,
 +                    ETaskShellView *task_shell_view)
 +{
 +	EShell *shell;
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	ETaskShellContent *task_shell_content;
 +	ECalendarTable *task_table;
 +	ECalModelComponent *comp_data;
 +	ECal *client;
 +	ECalComponent *comp;
 +	CompEditor *editor;
 +	GSList *list;
 +
 +	shell_view = E_SHELL_VIEW (task_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +	shell = e_shell_window_get_shell (shell_window);
 +
 +	task_shell_content = task_shell_view->priv->task_shell_content;
 +	task_table = e_task_shell_content_get_task_table (task_shell_content);
 +
 +	list = e_calendar_table_get_selected (task_table);
 +	g_return_if_fail (list != NULL);
 +	comp_data = list->data;
 +	g_slist_free (list);
 +
 +	client = comp_data->client;
 +	editor = task_editor_new (client, shell, COMP_EDITOR_NEW_ITEM);
 +	comp = cal_comp_task_new_with_defaults (client);
 +	comp_editor_edit_comp (editor, comp);
 +
 +	gtk_window_present (GTK_WINDOW (editor));
 +
- 	g_object_unref (comp);	
++	g_object_unref (comp);
 +	g_object_unref (client);
 +}
 +
 +static void
 +action_task_open_cb (GtkAction *action,
 +                     ETaskShellView *task_shell_view)
 +{
 +	ETaskShellContent *task_shell_content;
 +	ECalendarTable *task_table;
 +	ECalModelComponent *comp_data;
 +	GSList *list;
 +
 +	task_shell_content = task_shell_view->priv->task_shell_content;
 +	task_table = e_task_shell_content_get_task_table (task_shell_content);
 +
 +	list = e_calendar_table_get_selected (task_table);
 +	g_return_if_fail (list != NULL);
 +	comp_data = list->data;
 +	g_slist_free (list);
 +
 +	/* XXX We only open the first selected task. */
 +	e_task_shell_view_open_task (task_shell_view, comp_data);
 +}
 +
 +static void
 +action_task_open_url_cb (GtkAction *action,
 +                         ETaskShellView *task_shell_view)
 +{
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	ETaskShellContent *task_shell_content;
 +	ECalendarTable *task_table;
 +	ECalModelComponent *comp_data;
 +	icalproperty *prop;
 +	const gchar *uri;
 +	GSList *list;
 +
 +	shell_view = E_SHELL_VIEW (task_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	task_shell_content = task_shell_view->priv->task_shell_content;
 +	task_table = e_task_shell_content_get_task_table (task_shell_content);
 +
 +	list = e_calendar_table_get_selected (task_table);
 +	g_return_if_fail (list != NULL);
 +	comp_data = list->data;
 +
 +	/* XXX We only open the URI of the first selected task. */
 +	prop = icalcomponent_get_first_property (
 +		comp_data->icalcomp, ICAL_URL_PROPERTY);
 +	g_return_if_fail (prop == NULL);
 +
 +	uri = icalproperty_get_url (prop);
 +	e_show_uri (GTK_WINDOW (shell_window), uri);
 +}
 +
 +static void
 +action_task_preview_cb (GtkToggleAction *action,
 +                        ETaskShellView *task_shell_view)
 +{
 +	ETaskShellContent *task_shell_content;
 +	gboolean visible;
 +
 +	task_shell_content = task_shell_view->priv->task_shell_content;
 +	visible = gtk_toggle_action_get_active (action);
 +	e_task_shell_content_set_preview_visible (task_shell_content, visible);
 +}
 +
 +static void
 +action_task_print_cb (GtkAction *action,
 +                      ETaskShellView *task_shell_view)
 +{
 +	ETaskShellContent *task_shell_content;
 +	ECalendarTable *task_table;
 +	ECalModelComponent *comp_data;
 +	ECalComponent *comp;
 +	icalcomponent *clone;
 +	GtkPrintOperationAction print_action;
 +	GSList *list;
 +
 +	task_shell_content = task_shell_view->priv->task_shell_content;
 +	task_table = e_task_shell_content_get_task_table (task_shell_content);
 +
 +	list = e_calendar_table_get_selected (task_table);
 +	g_return_if_fail (list != NULL);
 +	comp_data = list->data;
 +	g_slist_free (list);
 +
 +	/* XXX We only print the first selected task. */
 +	comp = e_cal_component_new ();
 +	clone = icalcomponent_new_clone (comp_data->icalcomp);
 +	print_action = GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG;
 +	e_cal_component_set_icalcomponent (comp, clone);
 +	print_comp (comp, comp_data->client, print_action);
 +	g_object_unref (comp);
 +}
 +
 +static void
 +action_task_purge_cb (GtkAction *action,
 +                      ETaskShellView *task_shell_view)
 +{
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	GtkWidget *dialog;
 +	GtkWidget *widget;
 +	gboolean active;
 +	gint response;
 +
 +	shell_view = E_SHELL_VIEW (task_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	if (!calendar_config_get_confirm_purge ())
 +		goto purge;
 +
 +	/* XXX This needs reworked.  The dialog looks like ass. */
 +
 +	dialog = gtk_message_dialog_new (
 +		GTK_WINDOW (shell_window),
 +		GTK_DIALOG_DESTROY_WITH_PARENT,
 +		GTK_MESSAGE_WARNING,
 +		GTK_BUTTONS_YES_NO,
 +		"%s", _("This operation will permanently erase all tasks "
 +		"marked as completed. If you continue, you will not be able "
 +		"to recover these tasks.\n\nReally erase these tasks?"));
 +
 +	gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_NO);
 +
 +	widget = gtk_check_button_new_with_label (_("Do not ask me again"));
 +	gtk_box_pack_start (
 +		GTK_BOX (GTK_DIALOG (dialog)->vbox), widget, TRUE, TRUE, 6);
 +	gtk_widget_show (widget);
 +
 +	response = gtk_dialog_run (GTK_DIALOG (dialog));
 +	active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
 +	gtk_widget_destroy (dialog);
 +
 +	if (response != GTK_RESPONSE_YES)
 +		return;
 +
 +	if (active)
 +		calendar_config_set_confirm_purge (FALSE);
 +
 +purge:
 +
 +	/* FIXME */
 +        ;
 +}
 +
 +static void
 +action_task_save_as_cb (GtkAction *action,
 +                        ETaskShellView *task_shell_view)
 +{
 +	ETaskShellContent *task_shell_content;
 +	ECalendarTable *task_table;
 +	ECalModelComponent *comp_data;
 +	GSList *list;
 +	gchar *filename;
 +	gchar *string;
 +
 +	task_shell_content = task_shell_view->priv->task_shell_content;
 +	task_table = e_task_shell_content_get_task_table (task_shell_content);
 +
 +	list = e_calendar_table_get_selected (task_table);
 +	g_return_if_fail (list != NULL);
 +	comp_data = list->data;
 +	g_slist_free (list);
 +
 +	filename = e_file_dialog_save (_("Save as..."), NULL);
 +	if (filename == NULL)
 +		return;
 +
 +	string = e_cal_get_component_as_string (
 +		comp_data->client, comp_data->icalcomp);
 +	if (string == NULL) {
 +		g_warning ("Could not convert task to a string");
 +		return;
 +	}
 +
 +	e_write_file_uri (filename, string);
 +
 +	g_free (filename);
 +	g_free (string);
 +}
 +
 +static GtkActionEntry task_entries[] = {
 +
 +	{ "task-assign",
 +	  NULL,
 +	  N_("_Assign Task"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  G_CALLBACK (action_task_assign_cb) },
 +
 +	{ "task-clipboard-copy",
 +	  GTK_STOCK_COPY,
 +	  NULL,
 +	  NULL,
 +	  N_("Copy selected tasks"),
 +	  G_CALLBACK (action_task_clipboard_copy_cb) },
 +
 +	{ "task-clipboard-cut",
 +	  GTK_STOCK_CUT,
 +	  NULL,
 +	  NULL,
 +	  N_("Cut selected tasks"),
 +	  G_CALLBACK (action_task_clipboard_cut_cb) },
 +
 +	{ "task-clipboard-paste",
 +	  GTK_STOCK_PASTE,
 +	  NULL,
 +	  NULL,
 +	  N_("Paste tasks from the clipboard"),
 +	  G_CALLBACK (action_task_clipboard_paste_cb) },
 +
 +	{ "task-delete",
 +	  GTK_STOCK_DELETE,
 +	  N_("_Delete Task"),
 +	  NULL,
 +	  N_("Delete selected tasks"),
 +	  G_CALLBACK (action_task_delete_cb) },
 +
 +	{ "task-forward",
 +	  "mail-forward",
 +	  N_("_Forward as iCalendar..."),
 +	  "<Control>f",
 +	  NULL,  /* XXX Add a tooltip! */
 +	  G_CALLBACK (action_task_forward_cb) },
 +
 +	{ "task-list-copy",
 +	  GTK_STOCK_COPY,
 +	  N_("Copy..."),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  G_CALLBACK (action_task_list_copy_cb) },
 +
 +	{ "task-list-delete",
 +	  GTK_STOCK_DELETE,
 +	  N_("_Delete"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  G_CALLBACK (action_task_list_delete_cb) },
 +
 +	{ "task-list-new",
 +	  "stock_todo",
 +	  N_("_New Task List"),
 +	  NULL,
 +	  N_("Create a new task list"),
 +	  G_CALLBACK (action_task_list_new_cb) },
 +
 +	{ "task-list-properties",
 +	  GTK_STOCK_PROPERTIES,
 +	  NULL,
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  G_CALLBACK (action_task_list_properties_cb) },
 +
 +	{ "task-list-rename",
 +	  NULL,
 +	  N_("_Rename..."),
 +	  "F2",
 +	  N_("Rename the selected task list"),
 +	  G_CALLBACK (action_task_list_rename_cb) },
 +
 +	{ "task-list-select-one",
 +	  "stock_check-filled",
 +	  N_("Show _Only This Task List"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  G_CALLBACK (action_task_list_select_one_cb) },
 +
 +	{ "task-mark-complete",
 +	  NULL,
 +	  N_("_Mark as Complete"),
 +	  "<Control>k",
 +	  N_("Mark selected tasks as complete"),
 +	  G_CALLBACK (action_task_mark_complete_cb) },
 +
 +	{ "task-mark-incomplete",
 +	  NULL,
 +	  N_("Mar_k as Incomplete"),
 +	  NULL,
 +	  N_("Mark selected tasks as incomplete"),
 +	  G_CALLBACK (action_task_mark_incomplete_cb) },
 +
 +	{ "task-new",
 +	  "stock_task",
 +	  N_("New _Task"),
 +	  NULL,
 +	  N_("Create a new task"),
 +	  G_CALLBACK (action_task_new_cb) },
 +
 +	{ "task-open",
 +	  GTK_STOCK_OPEN,
 +	  N_("_Open Task"),
 +	  "<Control>o",
 +	  N_("View the selected task"),
 +	  G_CALLBACK (action_task_open_cb) },
 +
 +	{ "task-open-url",
 +	  "applications-internet",
 +	  N_("Open _Web Page"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  G_CALLBACK (action_task_open_url_cb) },
 +
 +	{ "task-purge",
 +	  NULL,
 +	  N_("Purg_e"),
 +	  "<Control>e",
 +	  N_("Delete completed tasks"),
 +	  G_CALLBACK (action_task_purge_cb) },
 +
 +	{ "task-save-as",
 +	  GTK_STOCK_SAVE_AS,
 +	  N_("_Save as iCalendar..."),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  G_CALLBACK (action_task_save_as_cb) },
 +
 +	/*** Menus ***/
 +
 +	{ "task-actions-menu",
 +	  NULL,
 +	  N_("_Actions"),
 +	  NULL,
 +	  NULL,
 +	  NULL }
 +};
 +
 +static EPopupActionEntry task_popup_entries[] = {
 +
 +	{ "task-list-popup-copy",
 +	  NULL,
 +	  "task-list-copy" },
 +
 +	{ "task-list-popup-delete",
 +	  NULL,
 +	  "task-list-delete" },
 +
 +	{ "task-list-popup-properties",
 +	  NULL,
 +	  "task-list-properties" },
 +
 +	{ "task-list-popup-rename",
 +	  NULL,
 +	  "task-list-rename" },
 +
 +	{ "task-list-popup-select-one",
 +	  NULL,
 +	  "task-list-select-one" },
 +
 +	{ "task-popup-assign",
 +	  NULL,
 +	  "task-assign" },
 +
 +	{ "task-popup-clipboard-copy",
 +	  NULL,
 +	  "task-clipboard-copy" },
 +
 +	{ "task-popup-clipboard-cut",
 +	  NULL,
 +	  "task-clipboard-cut" },
 +
 +	{ "task-popup-clipboard-paste",
 +	  NULL,
 +	  "task-clipboard-paste" },
 +
 +	{ "task-popup-delete",
 +	  NULL,
 +	  "task-delete" },
 +
 +	{ "task-popup-forward",
 +	  NULL,
 +	  "task-forward" },
 +
 +	{ "task-popup-mark-complete",
 +	  NULL,
 +	  "task-mark-complete" },
 +
 +	{ "task-popup-mark-incomplete",
 +	  NULL,
 +	  "task-mark-incomplete" },
 +
 +	{ "task-popup-open",
 +	  NULL,
 +	  "task-open" },
 +
 +	{ "task-popup-open-url",
 +	  NULL,
 +	  "task-open-url" },
 +
 +	{ "task-popup-save-as",
 +	  NULL,
 +	  "task-save-as" },
 +};
 +
 +static GtkToggleActionEntry task_toggle_entries[] = {
 +
 +	{ "task-preview",
 +	  NULL,
 +	  N_("Task _Preview"),
 +	  "<Control>m",
 +	  N_("Show task preview pane"),
 +	  G_CALLBACK (action_task_preview_cb),
 +	  TRUE }
 +};
 +
 +static GtkRadioActionEntry task_filter_entries[] = {
 +
 +	{ "task-filter-active-tasks",
 +	  NULL,
 +	  N_("Active Tasks"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  TASK_FILTER_ACTIVE_TASKS },
 +
 +	{ "task-filter-any-category",
 +	  NULL,
 +	  N_("Any Category"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  TASK_FILTER_ANY_CATEGORY },
 +
 +	{ "task-filter-completed-tasks",
 +	  NULL,
 +	  N_("Completed Tasks"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  TASK_FILTER_COMPLETED_TASKS },
 +
 +	{ "task-filter-next-7-days-tasks",
 +	  NULL,
 +	  N_("Next 7 Days' Tasks"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  TASK_FILTER_NEXT_7_DAYS_TASKS },
 +
 +	{ "task-filter-overdue-tasks",
 +	  NULL,
 +	  N_("Overdue Tasks"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  TASK_FILTER_OVERDUE_TASKS },
 +
 +	{ "task-filter-tasks-with-attachments",
 +	  NULL,
 +	  N_("Tasks with Attachments"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  TASK_FILTER_TASKS_WITH_ATTACHMENTS },
 +
 +	{ "task-filter-unmatched",
 +	  NULL,
 +	  N_("Unmatched"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  TASK_FILTER_UNMATCHED }
 +};
 +
 +static GtkRadioActionEntry task_search_entries[] = {
 +
 +	{ "task-search-any-field-contains",
 +          NULL,
 +	  N_("Any field contains"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  TASK_SEARCH_ANY_FIELD_CONTAINS },
 +
 +	{ "task-search-description-contains",
 +	  NULL,
 +	  N_("Description contains"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  TASK_SEARCH_DESCRIPTION_CONTAINS },
 +
 +	{ "task-search-summary-contains",
 +	  NULL,
 +	  N_("Summary contains"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  TASK_SEARCH_SUMMARY_CONTAINS }
 +};
 +
 +static GtkActionEntry lockdown_printing_entries[] = {
 +
 +	{ "task-list-print",
 +	  GTK_STOCK_PRINT,
 +	  NULL,
 +	  "<Control>p",
 +	  N_("Print the list of tasks"),
 +	  G_CALLBACK (action_task_list_print_cb) },
 +
 +	{ "task-list-print-preview",
 +	  GTK_STOCK_PRINT_PREVIEW,
 +	  NULL,
 +	  NULL,
 +	  N_("Preview the list of tasks to be printed"),
 +	  G_CALLBACK (action_task_list_print_preview_cb) },
 +
 +	{ "task-print",
 +	  GTK_STOCK_PRINT,
 +	  NULL,
 +	  NULL,
 +	  N_("Print the selected task"),
 +	  G_CALLBACK (action_task_print_cb) }
 +};
 +
 +static EPopupActionEntry lockdown_printing_popup_entries[] = {
 +
 +	{ "task-popup-print",
 +	  NULL,
 +	  "task-print" }
 +};
 +
 +void
 +e_task_shell_view_actions_init (ETaskShellView *task_shell_view)
 +{
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	GtkActionGroup *action_group;
 +	GConfBridge *bridge;
 +	GtkAction *action;
 +	GObject *object;
 +	const gchar *key;
 +
 +	shell_view = E_SHELL_VIEW (task_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	/* Task Actions */
 +	action_group = ACTION_GROUP (TASKS);
 +	gtk_action_group_add_actions (
 +		action_group, task_entries,
 +		G_N_ELEMENTS (task_entries), task_shell_view);
 +	e_action_group_add_popup_actions (
 +		action_group, task_popup_entries,
 +		G_N_ELEMENTS (task_popup_entries));
 +	gtk_action_group_add_toggle_actions (
 +		action_group, task_toggle_entries,
 +		G_N_ELEMENTS (task_toggle_entries), task_shell_view);
 +	gtk_action_group_add_radio_actions (
 +		action_group, task_search_entries,
 +		G_N_ELEMENTS (task_search_entries),
 +		TASK_SEARCH_SUMMARY_CONTAINS,
 +		NULL, NULL);
 +
 +	/* Lockdown Printing Actions */
 +	action_group = ACTION_GROUP (LOCKDOWN_PRINTING);
 +	gtk_action_group_add_actions (
 +		action_group, lockdown_printing_entries,
 +		G_N_ELEMENTS (lockdown_printing_entries), task_shell_view);
 +	e_action_group_add_popup_actions (
 +		action_group, lockdown_printing_popup_entries,
 +		G_N_ELEMENTS (lockdown_printing_popup_entries));
 +
 +	/* Bind GObject properties to GConf keys. */
 +
 +	bridge = gconf_bridge_get ();
 +
 +	object = G_OBJECT (ACTION (TASK_PREVIEW));
 +	key = "/apps/evolution/calendar/display/show_task_preview";
 +	gconf_bridge_bind_property (bridge, key, object, "active");
 +
 +	/* Fine tuning. */
 +
 +	action = ACTION (TASK_DELETE);
 +	g_object_set (action, "short-label", _("Delete"), NULL);
 +
 +	g_signal_connect (
 +		ACTION (GAL_SAVE_CUSTOM_VIEW), "activate",
 +		G_CALLBACK (action_gal_save_custom_view_cb), task_shell_view);
 +
 +	g_signal_connect (
 +		ACTION (SEARCH_EXECUTE), "activate",
 +		G_CALLBACK (action_search_execute_cb), task_shell_view);
 +}
 +
 +void
 +e_task_shell_view_update_search_filter (ETaskShellView *task_shell_view)
 +{
 +	EShellContent *shell_content;
 +	EShellWindow *shell_window;
 +	EShellView *shell_view;
 +	GtkActionGroup *action_group;
 +	GtkRadioAction *radio_action;
 +	GList *list, *iter;
 +	GSList *group;
 +	gint ii;
 +
 +	shell_view = E_SHELL_VIEW (task_shell_view);
 +	shell_content = e_shell_view_get_shell_content (shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	action_group = ACTION_GROUP (TASKS_FILTER);
 +	e_action_group_remove_all_actions (action_group);
 +
 +	/* Add the standard filter actions. */
 +	gtk_action_group_add_radio_actions (
 +		action_group, task_filter_entries,
 +		G_N_ELEMENTS (task_filter_entries),
 +		TASK_FILTER_ANY_CATEGORY,
 +		G_CALLBACK (action_search_filter_cb),
 +		task_shell_view);
 +
 +	/* Retrieve the radio group from an action we just added. */
 +	list = gtk_action_group_list_actions (action_group);
 +	radio_action = GTK_RADIO_ACTION (list->data);
 +	group = gtk_radio_action_get_group (radio_action);
 +	g_list_free (list);
 +
 +	/* Build the category actions. */
 +
 +	list = e_categories_get_list ();
 +	for (iter = list, ii = 0; iter != NULL; iter = iter->next, ii++) {
 +		const gchar *category_name = iter->data;
 +		const gchar *filename;
 +		GtkAction *action;
 +		gchar *action_name;
 +
 +		action_name = g_strdup_printf (
 +			"task-filter-category-%d", ii);
 +		radio_action = gtk_radio_action_new (
 +			action_name, category_name, NULL, NULL, ii);
 +		g_free (action_name);
 +
 +		/* Convert the category icon file to a themed icon name. */
 +		filename = e_categories_get_icon_file_for (category_name);
 +		if (filename != NULL && *filename != '\0') {
 +			gchar *basename;
 +			gchar *cp;
 +
 +			basename = g_path_get_basename (filename);
 +
 +			/* Lose the file extension. */
 +			if ((cp = strrchr (basename, '.')) != NULL)
 +				*cp = '\0';
 +
 +			g_object_set (
 +				radio_action, "icon-name", basename, NULL);
 +
 +			g_free (basename);
 +		}
 +
 +		gtk_radio_action_set_group (radio_action, group);
 +		group = gtk_radio_action_get_group (radio_action);
 +
 +		/* The action group takes ownership of the action. */
 +		action = GTK_ACTION (radio_action);
 +		gtk_action_group_add_action (action_group, action);
 +		g_object_unref (radio_action);
 +	}
 +	g_list_free (list);
 +
 +	/* Use any action in the group; doesn't matter which. */
 +	e_shell_content_set_filter_action (shell_content, radio_action);
 +
 +	ii = TASK_FILTER_UNMATCHED;
 +	e_shell_content_add_filter_separator_after (shell_content, ii);
 +
 +	ii = TASK_FILTER_TASKS_WITH_ATTACHMENTS;
 +	e_shell_content_add_filter_separator_after (shell_content, ii);
 +}
diff --cc calendar/module/e-task-shell-view-actions.h
index 163a640,0000000..d7db39b
mode 100644,000000..100644
--- a/calendar/module/e-task-shell-view-actions.h
+++ b/calendar/module/e-task-shell-view-actions.h
@@@ -1,105 -1,0 +1,105 @@@
 +/*
 + * e-task-shell-view-actions.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_TASK_SHELL_VIEW_ACTIONS_H
 +#define E_TASK_SHELL_VIEW_ACTIONS_H
 +
 +#include <shell/e-shell-window-actions.h>
 +
 +/* Task Actions */
 +#define E_SHELL_WINDOW_ACTION_TASK_ASSIGN(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "task-assign")
 +#define E_SHELL_WINDOW_ACTION_TASK_CLIPBOARD_COPY(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "task-clipboard-copy")
 +#define E_SHELL_WINDOW_ACTION_TASK_CLIPBOARD_CUT(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "task-clipboard-cut")
 +#define E_SHELL_WINDOW_ACTION_TASK_CLIPBOARD_PASTE(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "task-clipboard-paste")
 +#define E_SHELL_WINDOW_ACTION_TASK_DELETE(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "task-delete")
 +#define E_SHELL_WINDOW_ACTION_TASK_FORWARD(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "task-forward")
 +#define E_SHELL_WINDOW_ACTION_TASK_MARK_COMPLETE(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "task-mark-complete")
 +#define E_SHELL_WINDOW_ACTION_TASK_MARK_INCOMPLETE(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "task-mark-incomplete")
 +#define E_SHELL_WINDOW_ACTION_TASK_NEW(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "task-new")
 +#define E_SHELL_WINDOW_ACTION_TASK_OPEN(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "task-open")
 +#define E_SHELL_WINDOW_ACTION_TASK_OPEN_URL(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "task-open-url")
 +#define E_SHELL_WINDOW_ACTION_TASK_PREVIEW(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "task-preview")
 +#define E_SHELL_WINDOW_ACTION_TASK_PRINT(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "task-print")
 +#define E_SHELL_WINDOW_ACTION_TASK_PURGE(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "task-purge")
 +#define E_SHELL_WINDOW_ACTION_TASK_SAVE_AS(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "task-save-as")
 +
 +/* Task List Actions */
 +#define E_SHELL_WINDOW_ACTION_TASK_LIST_COPY(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "task-list-copy")
 +#define E_SHELL_WINDOW_ACTION_TASK_LIST_DELETE(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "task-list-delete")
 +#define E_SHELL_WINDOW_ACTION_TASK_LIST_NEW(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "task-list-new")
 +#define E_SHELL_WINDOW_ACTION_TASK_LIST_PRINT(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "task-list-print")
 +#define E_SHELL_WINDOW_ACTION_TASK_LIST_PRINT_PREVIEW(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "task-list-print-preview")
 +#define E_SHELL_WINDOW_ACTION_TASK_LIST_PROPERTIES(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "task-list-properties")
 +#define E_SHELL_WINDOW_ACTION_TASK_LIST_RENAME(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "task-list-rename")
 +#define E_SHELL_WINDOW_ACTION_TASK_LIST_SELECT_ONE(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "task-list-select-one")
 +
 +/* Task Query Actions */
 +#define E_SHELL_WINDOW_ACTION_TASK_FILTER_ACTIVE_TASKS(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "task-filter-active-tasks")
 +#define E_SHELL_WINDOW_ACTION_TASK_FILTER_ANY_CATEGORY(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "task-filter-any-category")
 +#define E_SHELL_WINDOW_ACTION_TASK_FILTER_COMPLETED_TASKS(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "task-filter-completed-tasks")
 +#define E_SHELL_WINDOW_ACTION_TASK_FILTER_NEXT_7_DAYS_TASKS(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "task-filter-next-7-days-tasks")
 +#define E_SHELL_WINDOW_ACTION_TASK_FILTER_OVERDUE_TASKS(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "task-filter-overdue-tasks")
 +#define E_SHELL_WINDOW_ACTION_TASK_FILTER_TASKS_WITH_ATTACHMENTS(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "task-filter-tasks-with-attachments")
 +#define E_SHELL_WINDOW_ACTION_TASK_FILTER_UNMATCHED(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "task-filter-unmatched")
 +#define E_SHELL_WINDOW_ACTION_TASK_SEARCH_ANY_FIELD_CONTAINS(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "task-search-any-field-contains")
 +#define E_SHELL_WINDOW_ACTION_TASK_SEARCH_DESCRIPTION_CONTAINS(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "task-search-description-contains")
 +#define E_SHELL_WINDOW_ACTION_TASK_SEARCH_SUMMARY_CONTAINS(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "task-search-summary-contains")
 +
 +/* Action Groups */
 +#define E_SHELL_WINDOW_ACTION_GROUP_TASKS(window) \
 +	E_SHELL_WINDOW_ACTION_GROUP ((window), "tasks")
 +#define E_SHELL_WINDOW_ACTION_GROUP_TASKS_FILTER(window) \
 +	E_SHELL_WINDOW_ACTION_GROUP ((window), "tasks-filter")
 +
 +#endif /* E_TASK_SHELL_VIEW_ACTIONS_H */
diff --cc calendar/module/e-task-shell-view-private.c
index 58bda3d,0000000..d6fd8e3
mode 100644,000000..100644
--- a/calendar/module/e-task-shell-view-private.c
+++ b/calendar/module/e-task-shell-view-private.c
@@@ -1,744 -1,0 +1,744 @@@
 +/*
 + * e-task-shell-view-private.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-task-shell-view-private.h"
 +
 +#include "widgets/menus/gal-view-factory-etable.h"
 +
 +static void
 +task_shell_view_config_hide_completed_tasks_changed_cb (GConfClient *client,
 +                                                        guint id,
 +                                                        GConfEntry *entry,
 +                                                        gpointer user_data)
 +{
 +	ETaskShellView *task_shell_view = user_data;
 +	ETaskShellContent *task_shell_content;
 +	ETaskShellSidebar *task_shell_sidebar;
 +	ECalendarTable *task_table;
 +	GList *clients;
 +
 +	task_shell_content = task_shell_view->priv->task_shell_content;
 +	task_table = e_task_shell_content_get_task_table (task_shell_content);
 +
 +	task_shell_sidebar = task_shell_view->priv->task_shell_sidebar;
 +	clients = e_task_shell_sidebar_get_clients (task_shell_sidebar);
 +
 +	e_calendar_table_process_completed_tasks (task_table, clients, TRUE);
 +
 +	/* Search query takes whether to show completed tasks into account,
 +	 * so if the preference has changed we need to update the query. */
 +	e_task_shell_view_execute_search (task_shell_view);
 +
 +	g_list_free (clients);
 +}
 +
 +static void
 +task_shell_view_config_timezone_changed_cb (GConfClient *client,
 +                                            guint id,
 +                                            GConfEntry *entry,
 +                                            gpointer user_data)
 +{
 +	ETaskShellView *task_shell_view = user_data;
 +
 +	e_task_shell_view_update_timezone (task_shell_view);
 +}
 +
 +static void
 +task_shell_view_table_popup_event_cb (EShellView *shell_view,
 +                                      GdkEventButton *event)
 +{
 +	const gchar *widget_path;
 +
 +	widget_path = "/task-popup";
 +	e_shell_view_show_popup_menu (shell_view, widget_path, event);
 +}
 +
 +static void
 +task_shell_view_table_user_created_cb (ETaskShellView *task_shell_view,
 +                                       ECalendarTable *task_table)
 +{
 +	ETaskShellSidebar *task_shell_sidebar;
 +	ECalModel *model;
 +	ECal *client;
 +	ESource *source;
 +
 +	/* This is the "Click to Add" handler. */
 +
 +	model = e_calendar_table_get_model (task_table);
 +	client = e_cal_model_get_default_client (model);
 +	source = e_cal_get_source (client);
 +
 +	task_shell_sidebar = task_shell_view->priv->task_shell_sidebar;
 +	e_task_shell_sidebar_add_source (task_shell_sidebar, source);
 +
 +	e_cal_model_add_client (model, client);
 +}
 +
 +static void
 +task_shell_view_selector_client_added_cb (ETaskShellView *task_shell_view,
 +                                          ECal *client)
 +{
 +	ETaskShellContent *task_shell_content;
 +	ECalendarTable *task_table;
 +	ECalModel *model;
 +
 +	task_shell_content = task_shell_view->priv->task_shell_content;
 +	task_table = e_task_shell_content_get_task_table (task_shell_content);
 +	model = e_calendar_table_get_model (task_table);
 +
 +	e_cal_model_add_client (model, client);
 +	e_task_shell_view_update_timezone (task_shell_view);
 +}
 +
 +static void
 +task_shell_view_selector_client_removed_cb (ETaskShellView *task_shell_view,
 +                                            ECal *client)
 +{
 +	ETaskShellContent *task_shell_content;
 +	ECalendarTable *task_table;
 +	ECalModel *model;
 +
 +	task_shell_content = task_shell_view->priv->task_shell_content;
 +	task_table = e_task_shell_content_get_task_table (task_shell_content);
 +	model = e_calendar_table_get_model (task_table);
 +
 +	e_cal_model_remove_client (model, client);
 +}
 +
 +static gboolean
 +task_shell_view_selector_popup_event_cb (EShellView *shell_view,
 +                                         ESource *primary_source,
 +                                         GdkEventButton *event)
 +{
 +	const gchar *widget_path;
 +
 +	widget_path = "/task-list-popup";
 +	e_shell_view_show_popup_menu (shell_view, widget_path, event);
 +
 +	return TRUE;
 +}
 +
 +static gboolean
 +task_shell_view_update_timeout_cb (ETaskShellView *task_shell_view)
 +{
 +	ETaskShellContent *task_shell_content;
 +	ETaskShellSidebar *task_shell_sidebar;
 +	ECalendarTable *task_table;
 +	ECalModel *model;
 +	GList *clients;
 +
 +	task_shell_content = task_shell_view->priv->task_shell_content;
 +	task_table = e_task_shell_content_get_task_table (task_shell_content);
 +	model = e_calendar_table_get_model (task_table);
 +
 +	task_shell_sidebar = task_shell_view->priv->task_shell_sidebar;
 +	clients = e_task_shell_sidebar_get_clients (task_shell_sidebar);
 +
 +	e_calendar_table_process_completed_tasks (task_table, clients, FALSE);
 +	e_cal_model_tasks_update_due_tasks (E_CAL_MODEL_TASKS (model));
 +
 +	g_list_free (clients);
 +
 +	return TRUE;
 +}
 +
 +static void
 +task_shell_view_load_view_collection (EShellViewClass *shell_view_class)
 +{
 +	GalViewCollection *collection;
 +	GalViewFactory *factory;
 +	ETableSpecification *spec;
 +	const gchar *base_dir;
 +	gchar *filename;
 +
 +	collection = shell_view_class->view_collection;
 +
 +	base_dir = EVOLUTION_ETSPECDIR;
 +	spec = e_table_specification_new ();
 +	filename = g_build_filename (base_dir, ETSPEC_FILENAME, NULL);
 +	if (!e_table_specification_load_from_file (spec, filename))
 +		g_critical ("Unable to load ETable specification file "
 +			    "for tasks");
 +	g_free (filename);
 +
 +	factory = gal_view_factory_etable_new (spec);
 +	gal_view_collection_add_factory (collection, factory);
 +	g_object_unref (factory);
 +	g_object_unref (spec);
 +
 +	gal_view_collection_load (collection);
 +}
 +
 +static void
 +task_shell_view_notify_view_id_cb (ETaskShellView *task_shell_view)
 +{
 +	ETaskShellContent *task_shell_content;
 +	GalViewInstance *view_instance;
 +	const gchar *view_id;
 +
 +	task_shell_content = task_shell_view->priv->task_shell_content;
 +	view_instance =
 +		e_task_shell_content_get_view_instance (task_shell_content);
 +	view_id = e_shell_view_get_view_id (E_SHELL_VIEW (task_shell_view));
 +
 +	/* A NULL view ID implies we're in a custom view.  But you can
 +	 * only get to a custom view via the "Define Views" dialog, which
 +	 * would have already modified the view instance appropriately.
 +	 * Furthermore, there's no way to refer to a custom view by ID
 +	 * anyway, since custom views have no IDs. */
 +	if (view_id == NULL)
 +		return;
 +
 +	gal_view_instance_set_current_view_id (view_instance, view_id);
 +}
 +
 +void
 +e_task_shell_view_private_init (ETaskShellView *task_shell_view,
 +                                EShellViewClass *shell_view_class)
 +{
 +	if (!gal_view_collection_loaded (shell_view_class->view_collection))
 +		task_shell_view_load_view_collection (shell_view_class);
 +
 +	g_signal_connect (
 +		task_shell_view, "notify::view-id",
 +		G_CALLBACK (task_shell_view_notify_view_id_cb), NULL);
 +}
 +
 +void
 +e_task_shell_view_private_constructed (ETaskShellView *task_shell_view)
 +{
 +	ETaskShellViewPrivate *priv = task_shell_view->priv;
 +	ETaskShellContent *task_shell_content;
 +	ETaskShellSidebar *task_shell_sidebar;
 +	EShellView *shell_view;
 +	EShellBackend *shell_backend;
 +	EShellContent *shell_content;
 +	EShellSidebar *shell_sidebar;
 +	EShellWindow *shell_window;
 +	ECalendarTable *task_table;
 +	ECalModel *model;
 +	ETable *table;
 +	ESourceSelector *selector;
 +	guint id;
 +
 +	shell_view = E_SHELL_VIEW (task_shell_view);
 +	shell_backend = e_shell_view_get_shell_backend (shell_view);
 +	shell_content = e_shell_view_get_shell_content (shell_view);
 +	shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	e_shell_window_add_action_group (shell_window, "tasks");
 +	e_shell_window_add_action_group (shell_window, "tasks-filter");
 +
 +	/* Cache these to avoid lots of awkward casting. */
 +	priv->task_shell_backend = g_object_ref (shell_backend);
 +	priv->task_shell_content = g_object_ref (shell_content);
 +	priv->task_shell_sidebar = g_object_ref (shell_sidebar);
 +
 +	task_shell_content = E_TASK_SHELL_CONTENT (shell_content);
 +	task_table = e_task_shell_content_get_task_table (task_shell_content);
 +	model = e_calendar_table_get_model (task_table);
 +	table = e_calendar_table_get_table (task_table);
 +
 +	task_shell_sidebar = E_TASK_SHELL_SIDEBAR (shell_sidebar);
 +	selector = e_task_shell_sidebar_get_selector (task_shell_sidebar);
 +
 +	g_signal_connect_swapped (
 +		task_table, "open-component",
 +		G_CALLBACK (e_task_shell_view_open_task),
 +		task_shell_view);
 +
 +	g_signal_connect_swapped (
 +		task_table, "popup-event",
 +		G_CALLBACK (task_shell_view_table_popup_event_cb),
 +		task_shell_view);
 +
 +	g_signal_connect_swapped (
 +		task_table, "status-message",
 +		G_CALLBACK (e_task_shell_view_set_status_message),
 +		task_shell_view);
 +
 +	g_signal_connect_swapped (
 +		task_table, "user-created",
 +		G_CALLBACK (task_shell_view_table_user_created_cb),
 +		task_shell_view);
 +
 +	g_signal_connect_swapped (
 +		model, "model-changed",
 +		G_CALLBACK (e_task_shell_view_update_sidebar),
 +		task_shell_view);
 +
 +	g_signal_connect_swapped (
 +		model, "model-rows-deleted",
 +		G_CALLBACK (e_task_shell_view_update_sidebar),
 +		task_shell_view);
 +
 +	g_signal_connect_swapped (
 +		model, "model-rows-inserted",
 +		G_CALLBACK (e_task_shell_view_update_sidebar),
 +		task_shell_view);
 +
 +	g_signal_connect_swapped (
 +		table, "selection-change",
 +		G_CALLBACK (e_task_shell_view_update_sidebar),
 +		task_shell_view);
 +
 +	g_signal_connect_swapped (
 +		task_shell_sidebar, "client-added",
 +		G_CALLBACK (task_shell_view_selector_client_added_cb),
 +		task_shell_view);
 +
 +	g_signal_connect_swapped (
 +		task_shell_sidebar, "client-removed",
 +		G_CALLBACK (task_shell_view_selector_client_removed_cb),
 +		task_shell_view);
 +
 +	g_signal_connect_swapped (
 +		task_shell_sidebar, "status-message",
 +		G_CALLBACK (e_task_shell_view_set_status_message),
 +		task_shell_view);
 +
 +	g_signal_connect_swapped (
 +		selector, "popup-event",
 +		G_CALLBACK (task_shell_view_selector_popup_event_cb),
 +		task_shell_view);
 +
 +	g_signal_connect_swapped (
 +		selector, "primary-selection-changed",
 +		G_CALLBACK (e_shell_view_update_actions),
 +		task_shell_view);
 +
 +	e_categories_register_change_listener (
 +		G_CALLBACK (e_task_shell_view_update_search_filter),
 +		task_shell_view);
 +
 +	task_shell_view_update_timeout_cb (task_shell_view);
 +	priv->update_timeout = g_timeout_add_full (
 +		G_PRIORITY_LOW, 60000, (GSourceFunc)
 +		task_shell_view_update_timeout_cb,
 +		task_shell_view, NULL);
 +
 +	/* Listen for configuration changes. */
 +
 +	/* Timezone */
 +	id = calendar_config_add_notification_timezone (
 +		task_shell_view_config_timezone_changed_cb, task_shell_view);
 +	priv->notifications = g_list_prepend (
 +		priv->notifications, GUINT_TO_POINTER (id));
 +
 +	/* Hide Completed Tasks (enable/units/value) */
 +	id = calendar_config_add_notification_hide_completed_tasks (
 +		task_shell_view_config_hide_completed_tasks_changed_cb,
 +		task_shell_view);
 +	priv->notifications = g_list_prepend (
 +		priv->notifications, GUINT_TO_POINTER (id));
 +	id = calendar_config_add_notification_hide_completed_tasks_units (
 +		task_shell_view_config_hide_completed_tasks_changed_cb,
 +		task_shell_view);
 +	priv->notifications = g_list_prepend (
 +		priv->notifications, GUINT_TO_POINTER (id));
 +	id = calendar_config_add_notification_hide_completed_tasks_value (
 +		task_shell_view_config_hide_completed_tasks_changed_cb,
 +		task_shell_view);
 +	priv->notifications = g_list_prepend (
 +		priv->notifications, GUINT_TO_POINTER (id));
 +
 +	e_task_shell_view_actions_init (task_shell_view);
 +	e_task_shell_view_update_sidebar (task_shell_view);
 +	e_task_shell_view_update_search_filter (task_shell_view);
 +	e_task_shell_view_update_timezone (task_shell_view);
 +
 +	e_task_shell_view_execute_search (task_shell_view);
 +}
 +
 +void
 +e_task_shell_view_private_dispose (ETaskShellView *task_shell_view)
 +{
 +	ETaskShellViewPrivate *priv = task_shell_view->priv;
 +	GList *iter;
 +
 +	DISPOSE (priv->task_shell_backend);
 +	DISPOSE (priv->task_shell_content);
 +	DISPOSE (priv->task_shell_sidebar);
 +
 +	if (task_shell_view->priv->activity != NULL) {
 +		/* XXX Activity is no cancellable. */
 +		e_activity_complete (task_shell_view->priv->activity);
 +		g_object_unref (task_shell_view->priv->activity);
 +		task_shell_view->priv->activity = NULL;
 +	}
 +
 +	if (priv->update_timeout > 0) {
 +		g_source_remove (priv->update_timeout);
 +		priv->update_timeout = 0;
 +	}
 +
 +	for (iter = priv->notifications; iter != NULL; iter = iter->next) {
 +		guint notification_id = GPOINTER_TO_UINT (iter->data);
 +		calendar_config_remove_notification (notification_id);
 +	}
 +	g_list_free (priv->notifications);
 +	priv->notifications = NULL;
 +}
 +
 +void
 +e_task_shell_view_private_finalize (ETaskShellView *task_shell_view)
 +{
 +	/* XXX Nothing to do? */
 +}
 +
 +void
 +e_task_shell_view_execute_search (ETaskShellView *task_shell_view)
 +{
 +	ETaskShellContent *task_shell_content;
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	EShellContent *shell_content;
 +	GtkAction *action;
 +	GString *string;
 +	ECalComponentPreview *task_preview;
 +	ECalendarTable *task_table;
 +	ECalModel *model;
 +	FilterRule *rule;
 +	const gchar *format;
 +	const gchar *text;
 +	time_t start_range;
 +	time_t end_range;
 +	gchar *start, *end;
 +	gchar *query;
 +	gchar *temp;
 +	gint value;
 +
 +	shell_view = E_SHELL_VIEW (task_shell_view);
 +	shell_content = e_shell_view_get_shell_content (shell_view);
 +	text = e_shell_content_get_search_text (shell_content);
 +
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +	action = ACTION (TASK_SEARCH_ANY_FIELD_CONTAINS);
 +	value = gtk_radio_action_get_current_value (GTK_RADIO_ACTION (action));
 +
 +	if (text == NULL || *text == '\0') {
 +		text = "";
 +		value = TASK_SEARCH_SUMMARY_CONTAINS;
 +	}
 +
 +	switch (value) {
 +		default:
 +			text = "";
 +			/* fall through */
 +
 +		case TASK_SEARCH_SUMMARY_CONTAINS:
 +			format = "(contains? \"summary\" %s)";
 +			break;
 +
 +		case TASK_SEARCH_DESCRIPTION_CONTAINS:
 +			format = "(contains? \"description\" %s)";
 +			break;
 +
 +		case TASK_SEARCH_ANY_FIELD_CONTAINS:
 +			format = "(contains? \"any\" %s)";
 +			break;
 +	}
 +
 +	/* Build the query. */
 +	string = g_string_new ("");
 +	e_sexp_encode_string (string, text);
 +	query = g_strdup_printf (format, string->str);
 +	g_string_free (string, TRUE);
 +
 +	/* Apply selected filter. */
 +	value = e_shell_content_get_filter_value (shell_content);
 +	switch (value) {
 +		case TASK_FILTER_ANY_CATEGORY:
 +			break;
 +
 +		case TASK_FILTER_UNMATCHED:
 +			temp = g_strdup_printf (
 +				"(and (has-categories? #f) %s)", query);
 +			g_free (query);
 +			query = temp;
 +			break;
 +
 +		case TASK_FILTER_NEXT_7_DAYS_TASKS:
 +			start_range = time (NULL);
 +			end_range = time_add_day (start_range, 7);
 +			start = isodate_from_time_t (start_range);
 +			end = isodate_from_time_t (end_range);
 +
 +			temp = g_strdup_printf (
 +				"(and %s (due-in-time-range? "
 +				"(make-time \"%s\") (make-time \"%s\")))",
 +				query, start, end);
 +			g_free (query);
 +			query = temp;
 +			break;
 +
 +		case TASK_FILTER_ACTIVE_TASKS:
 +			start_range = time (NULL);
 +			end_range = time_add_day (start_range, 365);
 +			start = isodate_from_time_t (start_range);
 +			end = isodate_from_time_t (end_range);
 +
 +			temp = g_strdup_printf (
 +				"(and %s (due-in-time-range? "
 +				"(make-time \"%s\") (make-time \"%s\")) "
 +				"(not (is-completed?)))",
 +				query, start, end);
 +			g_free (query);
 +			query = temp;
 +			break;
 +
 +		case TASK_FILTER_OVERDUE_TASKS:
 +			start_range = 0;
 +			end_range = time (NULL);
 +			start = isodate_from_time_t (start_range);
 +			end = isodate_from_time_t (end_range);
 +
 +			temp = g_strdup_printf (
 +				"(and %s (due-in-time-range? "
 +				"(make-time \"%s\") (make-time \"%s\")) "
 +				"(not (is-completed?)))",
 +				query, start, end);
 +			g_free (query);
 +			query = temp;
 +			break;
 +
 +		case TASK_FILTER_COMPLETED_TASKS:
 +			temp = g_strdup_printf (
 +				"(and (is-completed?) %s)", query);
 +			g_free (query);
 +			query = temp;
 +			break;
 +
 +		case TASK_FILTER_TASKS_WITH_ATTACHMENTS:
 +			temp = g_strdup_printf (
 +				"(and (has-attachments?) %s)", query);
 +			g_free (query);
 +			query = temp;
 +			break;
 +
 +		default:
 +		{
 +			GList *categories;
 +			const gchar *category_name;
 +
 +			categories = e_categories_get_list ();
 +			category_name = g_list_nth_data (categories, value);
 +			g_list_free (categories);
 +
 +			temp = g_strdup_printf (
 +				"(and (has-categories? \"%s\") %s)",
 +				category_name, query);
 +			g_free (query);
 +			query = temp;
 +			break;
 +		}
 +	}
 +
 +	/* Honor the user's preference to hide completed tasks. */
 +	temp = calendar_config_get_hide_completed_tasks_sexp (FALSE);
 +	if (temp != NULL) {
 +		gchar *temp2;
 +
 +		temp2 = g_strdup_printf ("(and %s %s)", temp, query);
 +		g_free (query);
 +		g_free (temp);
 +		query = temp2;
 +	}
 +
 +	/* XXX This is wrong.  We need to programmatically construct a
 +	 *     FilterRule, tell it to build code, and pass the resulting
 +	 *     expression string to ECalModel. */
 +	rule = filter_rule_new ();
 +	e_shell_content_set_search_rule (shell_content, rule);
 +	g_object_unref (rule);
 +
 +	/* Submit the query. */
 +	task_shell_content = task_shell_view->priv->task_shell_content;
 +	task_table = e_task_shell_content_get_task_table (task_shell_content);
 +	model = e_calendar_table_get_model (task_table);
 +	e_cal_model_set_search_query (model, query);
 +	g_free (query);
 +
 +	task_preview =
 +		e_task_shell_content_get_task_preview (task_shell_content);
 +	e_cal_component_preview_clear (task_preview);
 +}
 +
 +void
 +e_task_shell_view_open_task (ETaskShellView *task_shell_view,
 +                             ECalModelComponent *comp_data)
 +{
 +	EShell *shell;
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	CompEditor *editor;
 +	CompEditorFlags flags = 0;
 +	ECalComponent *comp;
 +	icalcomponent *clone;
 +	icalproperty *prop;
 +	const gchar *uid;
 +
 +	g_return_if_fail (E_IS_TASK_SHELL_VIEW (task_shell_view));
 +	g_return_if_fail (E_IS_CAL_MODEL_COMPONENT (comp_data));
 +
 +	shell_view = E_SHELL_VIEW (task_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +	shell = e_shell_window_get_shell (shell_window);
 +
 +	uid = icalcomponent_get_uid (comp_data->icalcomp);
 +	editor = comp_editor_find_instance (uid);
 +
 +	if (editor != NULL)
 +		goto exit;
 +
 +	comp = e_cal_component_new ();
 +	clone = icalcomponent_new_clone (comp_data->icalcomp);
 +	e_cal_component_set_icalcomponent (comp, clone);
 +
 +	prop = icalcomponent_get_first_property (
 +		comp_data->icalcomp, ICAL_ATTENDEE_PROPERTY);
 +	if (prop != NULL)
 +		flags |= COMP_EDITOR_IS_ASSIGNED;
 +
 +	if (itip_organizer_is_user (comp, comp_data->client))
 +		flags |= COMP_EDITOR_USER_ORG;
 +
 +	if (!e_cal_component_has_attendees (comp))
 +		flags |= COMP_EDITOR_USER_ORG;
 +
 +	editor = task_editor_new (comp_data->client, shell, flags);
 +	comp_editor_edit_comp (editor, comp);
 +
 +	g_object_ref (comp);
 +
 +	if (flags & COMP_EDITOR_IS_ASSIGNED)
 +		task_editor_show_assignment (TASK_EDITOR (editor));
 +
 +exit:
 +	gtk_window_present (GTK_WINDOW (editor));
 +}
 +
 +void
 +e_task_shell_view_set_status_message (ETaskShellView *task_shell_view,
 +                                      const gchar *status_message,
 +                                      gdouble percent)
 +{
 +	EActivity *activity;
 +	EShellView *shell_view;
 +	EShellBackend *shell_backend;
 +
 +	g_return_if_fail (E_IS_TASK_SHELL_VIEW (task_shell_view));
 +
 +	activity = task_shell_view->priv->activity;
 +	shell_view = E_SHELL_VIEW (task_shell_view);
 +	shell_backend = e_shell_view_get_shell_backend (shell_view);
 +
 +	if (status_message == NULL || *status_message == '\0') {
 +		if (activity != NULL) {
 +			e_activity_complete (activity);
 +			g_object_unref (activity);
 +			activity = NULL;
 +		}
 +
 +	} else if (activity == NULL) {
 +		activity = e_activity_new (status_message);
 +		e_activity_set_percent (activity, percent);
 +		e_shell_backend_add_activity (shell_backend, activity);
 +
 +	} else {
 +		e_activity_set_percent (activity, percent);
 +		e_activity_set_primary_text (activity, status_message);
 +	}
 +
 +	task_shell_view->priv->activity = activity;
 +}
 +
 +void
 +e_task_shell_view_update_sidebar (ETaskShellView *task_shell_view)
 +{
 +	ETaskShellContent *task_shell_content;
 +	EShellView *shell_view;
 +	EShellSidebar *shell_sidebar;
 +	ECalendarTable *task_table;
 +	ECalModel *model;
 +	ETable *table;
 +	GString *string;
 +	const gchar *format;
 +	gint n_rows;
 +	gint n_selected;
 +
 +	shell_view = E_SHELL_VIEW (task_shell_view);
 +	shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
 +
 +	task_shell_content = task_shell_view->priv->task_shell_content;
 +	task_table = e_task_shell_content_get_task_table (task_shell_content);
 +
 +	model = e_calendar_table_get_model (task_table);
 +	table = e_calendar_table_get_table (task_table);
 +
 +	n_rows = e_table_model_row_count (E_TABLE_MODEL (model));
 +	n_selected = e_table_selected_count (table);
 +
 +	string = g_string_sized_new (64);
 +
 +	format = ngettext ("%d task", "%d tasks", n_rows);
 +	g_string_append_printf (string, format, n_rows);
 +
 +	if (n_selected > 0) {
 +		format = _("%d selected");
 +		g_string_append_len (string, ", ", 2);
 +		g_string_append_printf (string, format, n_selected);
 +	}
 +
 +	e_shell_sidebar_set_secondary_text (shell_sidebar, string->str);
 +
 +	g_string_free (string, TRUE);
 +}
 +
 +void
 +e_task_shell_view_update_timezone (ETaskShellView *task_shell_view)
 +{
 +	ETaskShellContent *task_shell_content;
 +	ETaskShellSidebar *task_shell_sidebar;
 +	ECalComponentPreview *task_preview;
 +	icaltimezone *timezone;
 +	GList *clients, *iter;
 +
 +	task_shell_content = task_shell_view->priv->task_shell_content;
 +	task_preview = e_task_shell_content_get_task_preview (task_shell_content);
 +
 +	task_shell_sidebar = task_shell_view->priv->task_shell_sidebar;
 +	clients = e_task_shell_sidebar_get_clients (task_shell_sidebar);
 +
 +	timezone = calendar_config_get_icaltimezone ();
 +
 +	for (iter = clients; iter != NULL; iter = iter->next) {
 +		ECal *client = iter->data;
 +
 +		if (e_cal_get_load_state (client) == E_CAL_LOAD_LOADED)
 +			e_cal_set_default_timezone (client, timezone, NULL);
 +	}
 +
 +	e_cal_component_preview_set_default_timezone (task_preview, timezone);
 +
 +	g_list_free (clients);
 +}
diff --cc calendar/module/e-task-shell-view-private.h
index c613e9e,0000000..d3bb3cf
mode 100644,000000..100644
--- a/calendar/module/e-task-shell-view-private.h
+++ b/calendar/module/e-task-shell-view-private.h
@@@ -1,141 -1,0 +1,141 @@@
 +/*
 + * e-task-shell-view-private.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_TASK_SHELL_VIEW_PRIVATE_H
 +#define E_TASK_SHELL_VIEW_PRIVATE_H
 +
 +#include "e-task-shell-view.h"
 +
 +#include <string.h>
 +#include <glib/gi18n.h>
 +#include <libecal/e-cal-time-util.h>
 +#include <libedataserver/e-categories.h>
 +#include <libedataserver/e-sexp.h>
 +
 +#include "e-util/e-dialog-utils.h"
 +#include "e-util/e-error.h"
 +#include "e-util/e-util.h"
 +#include "e-util/gconf-bridge.h"
 +#include "widgets/misc/e-popup-action.h"
 +
 +#include "calendar/common/authentication.h"
 +#include "calendar/gui/calendar-config.h"
 +#include "calendar/gui/comp-util.h"
 +#include "calendar/gui/e-cal-component-preview.h"
 +#include "calendar/gui/e-cal-model-tasks.h"
 +#include "calendar/gui/e-calendar-selector.h"
 +#include "calendar/gui/print.h"
 +#include "calendar/gui/dialogs/calendar-setup.h"
 +#include "calendar/gui/dialogs/copy-source-dialog.h"
 +#include "calendar/gui/dialogs/task-editor.h"
 +
 +#include "e-task-shell-backend.h"
 +#include "e-task-shell-content.h"
 +#include "e-task-shell-sidebar.h"
 +#include "e-task-shell-view-actions.h"
 +
 +#define E_TASK_SHELL_VIEW_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_TASK_SHELL_VIEW, ETaskShellViewPrivate))
 +
 +/* Shorthand, requires a variable named "shell_window". */
 +#define ACTION(name) \
 +	(E_SHELL_WINDOW_ACTION_##name (shell_window))
 +#define ACTION_GROUP(name) \
 +	(E_SHELL_WINDOW_ACTION_GROUP_##name (shell_window))
 +
 +/* For use in dispose() methods. */
 +#define DISPOSE(obj) \
 +	G_STMT_START { \
 +	if ((obj) != NULL) { g_object_unref (obj); (obj) = NULL; } \
 +	} G_STMT_END
 +
 +/* ETable Specifications */
 +#define ETSPEC_FILENAME		"e-calendar-table.etspec"
 +
 +G_BEGIN_DECLS
 +
 +/* Filter items are displayed in ascending order.
 + * Non-negative values are reserved for categories. */
 +enum {
 +	TASK_FILTER_ANY_CATEGORY		= -7,
 +	TASK_FILTER_UNMATCHED			= -6,
 +	TASK_FILTER_NEXT_7_DAYS_TASKS		= -5,
 +	TASK_FILTER_ACTIVE_TASKS		= -4,
 +	TASK_FILTER_OVERDUE_TASKS		= -3,
 +	TASK_FILTER_COMPLETED_TASKS		= -2,
 +	TASK_FILTER_TASKS_WITH_ATTACHMENTS	= -1
 +};
 +
 +/* Search items are displayed in ascending order. */
 +enum {
 +	TASK_SEARCH_SUMMARY_CONTAINS,
 +	TASK_SEARCH_DESCRIPTION_CONTAINS,
 +	TASK_SEARCH_ANY_FIELD_CONTAINS
 +};
 +
 +struct _ETaskShellViewPrivate {
 +
 +	/* These are just for convenience. */
 +	ETaskShellBackend *task_shell_backend;
 +	ETaskShellContent *task_shell_content;
 +	ETaskShellSidebar *task_shell_sidebar;
 +
 +	EActivity *activity;
 +	guint update_timeout;
 +
 +	/* GConf notification IDs */
 +	GList *notifications;
 +};
 +
 +void		e_task_shell_view_private_init
 +					(ETaskShellView *task_shell_view,
 +					 EShellViewClass *shell_view_class);
 +void		e_task_shell_view_private_constructed
 +					(ETaskShellView *task_shell_view);
 +void		e_task_shell_view_private_dispose
 +					(ETaskShellView *task_shell_view);
 +void		e_task_shell_view_private_finalize
 +					(ETaskShellView *task_shell_view);
 +
 +/* Private Utilities */
 +
 +void		e_task_shell_view_actions_init
 +					(ETaskShellView *task_shell_view);
 +void		e_task_shell_view_execute_search
 +					(ETaskShellView *task_shell_view);
 +void		e_task_shell_view_open_task
 +					(ETaskShellView *task_shell_view,
 +					 ECalModelComponent *comp_data);
 +void		e_task_shell_view_set_status_message
 +					(ETaskShellView *task_shell_view,
 +					 const gchar *status_message,
 +					 gdouble percent);
 +void		e_task_shell_view_update_sidebar
 +					(ETaskShellView *task_shell_view);
 +void		e_task_shell_view_update_search_filter
 +					(ETaskShellView *task_shell_view);
 +void		e_task_shell_view_update_timezone
 +					(ETaskShellView *task_shell_view);
 +
 +G_END_DECLS
 +
 +#endif /* E_TASK_SHELL_VIEW_PRIVATE_H */
diff --cc calendar/module/e-task-shell-view.c
index d2f7899,0000000..ce1b53a
mode 100644,000000..100644
--- a/calendar/module/e-task-shell-view.c
+++ b/calendar/module/e-task-shell-view.c
@@@ -1,255 -1,0 +1,255 @@@
 +/*
 + * e-task-shell-view.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-task-shell-view-private.h"
 +
 +static gpointer parent_class;
 +static GType task_shell_view_type;
 +
 +static void
 +task_shell_view_dispose (GObject *object)
 +{
 +	e_task_shell_view_private_dispose (E_TASK_SHELL_VIEW (object));
 +
 +	/* Chain up to parent's dispose() method. */
 +	G_OBJECT_CLASS (parent_class)->dispose (object);
 +}
 +
 +static void
 +task_shell_view_finalize (GObject *object)
 +{
 +	e_task_shell_view_private_finalize (E_TASK_SHELL_VIEW (object));
 +
 +	/* Chain up to parent's finalize() method. */
 +	G_OBJECT_CLASS (parent_class)->finalize (object);
 +}
 +
 +static void
 +task_shell_view_constructed (GObject *object)
 +{
 +	/* Chain up to parent's constructed() method. */
 +	G_OBJECT_CLASS (parent_class)->constructed (object);
 +
 +	e_task_shell_view_private_constructed (E_TASK_SHELL_VIEW (object));
 +}
 +
 +static void
 +task_shell_view_update_actions (EShellView *shell_view)
 +{
 +	ETaskShellViewPrivate *priv;
 +	EShellContent *shell_content;
 +	EShellSidebar *shell_sidebar;
 +	EShellWindow *shell_window;
 +	GtkAction *action;
 +	const gchar *label;
 +	gboolean sensitive;
 +	guint32 state;
 +
 +	/* Be descriptive. */
 +	gboolean any_tasks_selected;
 +	gboolean has_primary_source;
 +	gboolean multiple_tasks_selected;
 +	gboolean primary_source_is_system;
 +	gboolean selection_has_url;
 +	gboolean selection_is_assignable;
 +	gboolean single_task_selected;
 +	gboolean some_tasks_complete;
 +	gboolean some_tasks_incomplete;
 +	gboolean sources_are_editable;
 +
 +	priv = E_TASK_SHELL_VIEW_GET_PRIVATE (shell_view);
 +
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	shell_content = e_shell_view_get_shell_content (shell_view);
 +	state = e_shell_content_check_state (shell_content);
 +
 +	single_task_selected =
 +		(state & E_TASK_SHELL_CONTENT_SELECTION_SINGLE);
 +	multiple_tasks_selected =
 +		(state & E_TASK_SHELL_CONTENT_SELECTION_MULTIPLE);
 +	selection_is_assignable =
 +		(state & E_TASK_SHELL_CONTENT_SELECTION_CAN_ASSIGN);
 +	sources_are_editable =
 +		(state & E_TASK_SHELL_CONTENT_SELECTION_CAN_EDIT);
 +	some_tasks_complete =
 +		(state & E_TASK_SHELL_CONTENT_SELECTION_HAS_COMPLETE);
 +	some_tasks_incomplete =
 +		(state & E_TASK_SHELL_CONTENT_SELECTION_HAS_INCOMPLETE);
 +	selection_has_url =
 +		(state & E_TASK_SHELL_CONTENT_SELECTION_HAS_URL);
 +
 +	shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
 +	state = e_shell_sidebar_check_state (shell_sidebar);
 +
 +	has_primary_source =
 +		(state & E_TASK_SHELL_SIDEBAR_HAS_PRIMARY_SOURCE);
 +	primary_source_is_system =
 +		(state & E_TASK_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_SYSTEM);
 +
 +	any_tasks_selected =
 +		(single_task_selected || multiple_tasks_selected);
 +
 +	action = ACTION (TASK_ASSIGN);
 +	sensitive =
 +		single_task_selected && sources_are_editable &&
 +		selection_is_assignable;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (TASK_CLIPBOARD_COPY);
 +	sensitive = any_tasks_selected;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (TASK_CLIPBOARD_CUT);
 +	sensitive = any_tasks_selected && sources_are_editable;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (TASK_CLIPBOARD_PASTE);
 +	sensitive = sources_are_editable;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (TASK_DELETE);
 +	sensitive = any_tasks_selected && sources_are_editable;
 +	gtk_action_set_sensitive (action, sensitive);
 +	if (multiple_tasks_selected)
 +		label = _("Delete Tasks");
 +	else
 +		label = _("Delete Task");
 +	g_object_set (action, "label", label, NULL);
 +
 +	action = ACTION (TASK_FORWARD);
 +	sensitive = single_task_selected;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (TASK_LIST_COPY);
 +	sensitive = has_primary_source;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (TASK_LIST_DELETE);
 +	sensitive = has_primary_source && !primary_source_is_system;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (TASK_LIST_PROPERTIES);
 +	sensitive = has_primary_source;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (TASK_LIST_RENAME);
 +	sensitive = has_primary_source;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (TASK_MARK_COMPLETE);
 +	sensitive =
 +		any_tasks_selected &&
 +		sources_are_editable &&
 +		some_tasks_incomplete;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (TASK_MARK_INCOMPLETE);
 +	sensitive =
 +		any_tasks_selected &&
 +		sources_are_editable &&
 +		some_tasks_complete;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (TASK_OPEN);
 +	sensitive = single_task_selected;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (TASK_OPEN_URL);
 +	sensitive = single_task_selected && selection_has_url;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (TASK_PRINT);
 +	sensitive = single_task_selected;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (TASK_PURGE);
 +	sensitive = sources_are_editable;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (TASK_SAVE_AS);
 +	sensitive = single_task_selected;
 +	gtk_action_set_sensitive (action, sensitive);
 +}
 +
 +static void
 +task_shell_view_class_init (ETaskShellViewClass *class,
 +                            GTypeModule *type_module)
 +{
 +	GObjectClass *object_class;
 +	EShellViewClass *shell_view_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (ETaskShellViewPrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->dispose = task_shell_view_dispose;
 +	object_class->finalize = task_shell_view_finalize;
 +	object_class->constructed = task_shell_view_constructed;
 +
 +	shell_view_class = E_SHELL_VIEW_CLASS (class);
 +	shell_view_class->label = _("Tasks");
 +	shell_view_class->icon_name = "evolution-tasks";
 +	shell_view_class->ui_definition = "evolution-tasks.ui";
 +	shell_view_class->ui_manager_id = "org.gnome.evolution.tasks";
 +	shell_view_class->search_options = "/task-search-options";
 +	shell_view_class->search_rules = "tasktypes.xml";
 +	shell_view_class->new_shell_content = e_task_shell_content_new;
 +	shell_view_class->new_shell_sidebar = e_task_shell_sidebar_new;
 +	shell_view_class->update_actions = task_shell_view_update_actions;
 +}
 +
 +static void
 +task_shell_view_init (ETaskShellView *task_shell_view,
 +                      EShellViewClass *shell_view_class)
 +{
 +	task_shell_view->priv =
 +		E_TASK_SHELL_VIEW_GET_PRIVATE (task_shell_view);
 +
 +	e_task_shell_view_private_init (task_shell_view, shell_view_class);
 +}
 +
 +GType
 +e_task_shell_view_get_type (void)
 +{
 +	return task_shell_view_type;
 +}
 +
 +void
 +e_task_shell_view_register_type (GTypeModule *type_module)
 +{
 +	const GTypeInfo type_info = {
 +		sizeof (ETaskShellViewClass),
 +		(GBaseInitFunc) NULL,
 +		(GBaseFinalizeFunc) NULL,
 +		(GClassInitFunc) task_shell_view_class_init,
 +		(GClassFinalizeFunc) NULL,
 +		type_module,
 +		sizeof (ETaskShellView),
 +		0,    /* n_preallocs */
 +		(GInstanceInitFunc) task_shell_view_init,
 +		NULL  /* value_table */
 +	};
 +
 +	task_shell_view_type = g_type_module_register_type (
 +		type_module, E_TYPE_SHELL_VIEW,
 +		"ETaskShellView", &type_info, 0);
 +}
diff --cc calendar/module/e-task-shell-view.h
index 8dca041,0000000..8478e53
mode 100644,000000..100644
--- a/calendar/module/e-task-shell-view.h
+++ b/calendar/module/e-task-shell-view.h
@@@ -1,67 -1,0 +1,67 @@@
 +/*
 + * e-task-shell-view.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_TASK_SHELL_VIEW_H
 +#define E_TASK_SHELL_VIEW_H
 +
 +#include <shell/e-shell-view.h>
 +#include <libedataserver/e-source-list.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_TASK_SHELL_VIEW \
 +	(e_task_shell_view_get_type ())
 +#define E_TASK_SHELL_VIEW(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_TASK_SHELL_VIEW, ETaskShellView))
 +#define E_TASK_SHELL_VIEW_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_TASK_SHELL_VIEW, ETaskShellViewClass))
 +#define E_IS_TASK_SHELL_VIEW(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_TASK_SHELL_VIEW))
 +#define E_IS_TASK_SHELL_VIEW_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), E_TYPE_TASK_SHELL_VIEW))
 +#define E_TASK_SHELL_VIEW_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_TASK_SHELL_VIEW, ETaskShellViewClass))
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _ETaskShellView ETaskShellView;
 +typedef struct _ETaskShellViewClass ETaskShellViewClass;
 +typedef struct _ETaskShellViewPrivate ETaskShellViewPrivate;
 +
 +struct _ETaskShellView {
 +	EShellView parent;
 +	ETaskShellViewPrivate *priv;
 +};
 +
 +struct _ETaskShellViewClass {
 +	EShellViewClass parent_class;
 +};
 +
 +GType		e_task_shell_view_get_type	(void);
 +void		e_task_shell_view_register_type	(GTypeModule *type_module);
 +
 +G_END_DECLS
 +
 +#endif /* E_TASK_SHELL_VIEW_H */
diff --cc calendar/module/evolution-module-calendar.c
index e89005f,0000000..63bf98e
mode 100644,000000..100644
--- a/calendar/module/evolution-module-calendar.c
+++ b/calendar/module/evolution-module-calendar.c
@@@ -1,65 -1,0 +1,65 @@@
 +/*
 + * evolution-module-calendar.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-cal-shell-backend.h"
 +#include "e-cal-shell-content.h"
 +#include "e-cal-shell-sidebar.h"
 +#include "e-cal-shell-view.h"
 +
 +#include "e-memo-shell-backend.h"
 +#include "e-memo-shell-content.h"
 +#include "e-memo-shell-sidebar.h"
 +#include "e-memo-shell-view.h"
 +
 +#include "e-task-shell-backend.h"
 +#include "e-task-shell-content.h"
 +#include "e-task-shell-sidebar.h"
 +#include "e-task-shell-view.h"
 +
 +/* Module Entry Points */
 +void e_module_load (GTypeModule *type_module);
 +void e_module_unload (GTypeModule *type_module);
 +
 +G_MODULE_EXPORT void
 +e_module_load (GTypeModule *type_module)
 +{
 +	/* Register dynamically loaded types. */
 +
 +	e_cal_shell_backend_register_type (type_module);
 +	e_cal_shell_content_register_type (type_module);
 +	e_cal_shell_sidebar_register_type (type_module);
 +	e_cal_shell_view_register_type (type_module);
 +
 +	e_memo_shell_backend_register_type (type_module);
 +	e_memo_shell_content_register_type (type_module);
 +	e_memo_shell_sidebar_register_type (type_module);
 +	e_memo_shell_view_register_type (type_module);
 +
 +	e_task_shell_backend_register_type (type_module);
 +	e_task_shell_content_register_type (type_module);
 +	e_task_shell_sidebar_register_type (type_module);
 +	e_task_shell_view_register_type (type_module);
 +}
 +
 +G_MODULE_EXPORT void
 +e_module_unload (GTypeModule *type_module)
 +{
 +}
diff --cc composer/Makefile.am
index 3ba27e8,97debe5..12ad680
--- a/composer/Makefile.am
+++ b/composer/Makefile.am
@@@ -50,10 -52,6 +50,9 @@@ libcomposer_la_SOURCES = 			
  	e-composer-text-header.c		\
  	e-msg-composer.c
  
- 
 +libcomposer_la_LIBADD =					\
 +	$(top_builddir)/widgets/misc/libemiscwidgets.la	\
 +	$(top_builddir)/em-format/libemformat.la
  
  uidir = $(evolutionuidir)
  ui_DATA = evolution-composer.ui
diff --cc composer/e-composer-header-table.c
index df96d76,f25c3b7..d883d8e
--- a/composer/e-composer-header-table.c
+++ b/composer/e-composer-header-table.c
@@@ -514,7 -514,7 +514,6 @@@ composer_header_table_constructor (GTyp
  
  	if (composer_lite)
  		gtk_widget_show_all ((GtkWidget *)priv->actions_container);
- 	
 -
  	ii = E_COMPOSER_HEADER_FROM;
  
  	/* Leave room in the "From" row for signature stuff. */
diff --cc composer/e-composer-private.c
index fffd18a,2a2cea6..d4ec9dd
--- a/composer/e-composer-private.c
+++ b/composer/e-composer-private.c
@@@ -103,7 -101,7 +103,7 @@@ e_composer_private_init (EMsgComposer *
  		widget = gtkhtml_editor_get_managed_widget (editor, "/main-menu");
  		gtk_widget_hide (widget);
  		widget = gtkhtml_editor_get_managed_widget (editor, "/main-toolbar");
- 		gtk_toolbar_set_style ((GtkToolbar *)widget, GTK_TOOLBAR_BOTH_HORIZ);	
 -		gtk_toolbar_set_style ((GtkToolbar *)widget, GTK_TOOLBAR_BOTH_HORIZ);
++		gtk_toolbar_set_style (GTK_TOOLBAR (widget), GTK_TOOLBAR_BOTH_HORIZ);
  		gtk_widget_hide (widget);
  
  	}
@@@ -161,7 -159,7 +161,6 @@@
  		gtk_container_remove((GtkContainer *)send_widget, gtk_bin_get_child ((GtkBin *)send_widget));
  		gtk_container_add((GtkContainer *)send_widget, tmp);
  		gtk_button_set_relief ((GtkButton *)send_widget, GTK_RELIEF_NORMAL);
- 			
 -
  		path = "/main-toolbar/pre-main-toolbar/save-draft";
  		send_widget = gtk_ui_manager_get_widget (ui_manager, path);
  		tmp = gtk_hbox_new (FALSE, 0);
diff --cc composer/e-msg-composer.c
index 2589786,946bff2..98f2c31
--- a/composer/e-msg-composer.c
+++ b/composer/e-msg-composer.c
@@@ -2854,9 -2926,9 +2854,9 @@@ e_msg_composer_new_with_message (CamelM
  	}
  
  	/* Remove any other X-Evolution-* headers that may have been set */
 -	xev = mail_tool_remove_xevolution_headers (message);
 +	xev = emcu_remove_xevolution_headers (message);
  	camel_header_raw_clear (&xev);
- 	
+ 
  	/* Check for receipt request */
  	if (camel_medium_get_header (CAMEL_MEDIUM (message), "Disposition-Notification-To")) {
  		action = GTK_TOGGLE_ACTION (ACTION (REQUEST_READ_RECEIPT));
diff --cc configure.ac
index b912c95,1a9f816..6a4826c
--- a/configure.ac
+++ b/configure.ac
@@@ -46,9 -45,35 +46,36 @@@ m4_define([libnotify_minimum_version], 
  m4_define([gnome_pilot_minimum_version], [2.0.15])
  m4_define([gweather_minimum_version], [2.25.3])
  
+ # Compiler Warning Flags
+ 
+ AS_COMPILER_FLAGS(WARNING_FLAGS,
+ 	"-DG_DISABLE_DEPRECATED
+ 	-DPANGO_DISABLE_DEPRECATED
+ 	-DGDK_PIXBUF_DISABLE_DEPRECATED
+ 	-DGDK_DISABLE_DEPRECATED
+ 	-Wall -Wextra
+ 	-Wno-missing-field-initializers
+ 	-Wno-sign-compare
+ 	-Wno-unused-parameter
+ 	-Wdeclaration-after-statement
+ 	-Werror-implicit-function-declaration
+ 	-Wformat-nonliteral -Wformat-security -Winit-self
+ 	-Wmissing-declarations -Wmissing-include-dirs
+ 	-Wmissing-noreturn -Wnested-externs -Wpointer-arith
+ 	-Wredundant-decls -Wundef -Wwrite-strings")
+ AC_SUBST(WARNING_FLAGS)
+ 
+ # Other useful compiler warnings for test builds only.
+ # These may produce warnings we have no control over.
+ #
+ #	-Wmissing-format-attribute
+ #	-Wshadow
+ 
+ CFLAGS="$CFLAGS $WARNING_FLAGS"
+ 
  # GNOME Documentation
  GNOME_DOC_INIT
 +GTK_DOC_CHECK(1.10)
  # Gross hack to enable 'make dist' on automake 1.9+tar 1.14.
  # The extra brackets are to foil regex-based scans.
  m4_ifdef([_A][M_PROG_TAR],[_A][M_SET_OPTION([tar-ustar])])
diff --cc e-util/e-account-utils.c
index d98a378,0000000..5fdffd8
mode 100644,000000..100644
--- a/e-util/e-account-utils.c
+++ b/e-util/e-account-utils.c
@@@ -1,96 -1,0 +1,96 @@@
 +/*
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + */
 +
 +#include "e-account-utils.h"
 +
 +#include <gconf/gconf-client.h>
 +
 +static EAccountList *global_account_list;
 +
 +EAccountList *
 +e_get_account_list (void)
 +{
 +	if (G_UNLIKELY (global_account_list == NULL)) {
 +		GConfClient *client;
 +
 +		client = gconf_client_get_default ();
 +		global_account_list = e_account_list_new (client);
 +		g_object_unref (client);
 +	}
 +
 +	g_return_val_if_fail (global_account_list != NULL, NULL);
 +
 +	return global_account_list;
 +}
 +
 +EAccount *
 +e_get_default_account (void)
 +{
 +	EAccountList *account_list;
 +	const EAccount *account;
 +
 +	account_list = e_get_account_list ();
 +	account = e_account_list_get_default (account_list);
 +
 +	/* XXX EAccountList misuses const. */
 +	return (EAccount *) account;
 +}
 +
 +void
 +e_set_default_account (EAccount *account)
 +{
 +	EAccountList *account_list;
 +
 +	g_return_if_fail (E_IS_ACCOUNT (account));
 +
 +	account_list = e_get_account_list ();
 +	e_account_list_set_default (account_list, account);
 +}
 +
 +EAccount *
 +e_get_account_by_name (const gchar *name)
 +{
 +	EAccountList *account_list;
 +	const EAccount *account;
 +	e_account_find_t find;
 +
 +	g_return_val_if_fail (name != NULL, NULL);
 +
 +	find = E_ACCOUNT_FIND_NAME;
 +	account_list = e_get_account_list ();
 +	account = e_account_list_find (account_list, find, name);
 +
 +	/* XXX EAccountList misuses const. */
 +	return (EAccount *) account;
 +}
 +
 +EAccount *
 +e_get_account_by_uid (const gchar *uid)
 +{
 +	EAccountList *account_list;
 +	const EAccount *account;
 +	e_account_find_t find;
 +
 +	g_return_val_if_fail (uid != NULL, NULL);
 +
 +	find = E_ACCOUNT_FIND_UID;
 +	account_list = e_get_account_list ();
 +	account = e_account_list_find (account_list, find, uid);
 +
 +	/* XXX EAccountList misuses const. */
 +	return (EAccount *) account;
 +}
diff --cc e-util/e-account-utils.h
index 2426234,0000000..f2ae8fc
mode 100644,000000..100644
--- a/e-util/e-account-utils.h
+++ b/e-util/e-account-utils.h
@@@ -1,35 -1,0 +1,35 @@@
 +/*
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + */
 +
 +#ifndef E_ACCOUNT_UTILS_H
 +#define E_ACCOUNT_UTILS_H
 +
 +#include <glib.h>
 +#include <libedataserver/e-account.h>
 +#include <libedataserver/e-account-list.h>
 +
 +G_BEGIN_DECLS
 +
 +EAccountList *	e_get_account_list		(void);
 +EAccount *	e_get_default_account		(void);
 +void		e_set_default_account		(EAccount *account);
 +EAccount *	e_get_account_by_name		(const gchar *name);
 +EAccount *	e_get_account_by_uid		(const gchar *uid);
 +
 +G_END_DECLS
 +
 +#endif /* E_ACCOUNT_UTILS_H */
diff --cc e-util/e-logger.c
index 97d27d0,19326d2..6c391ef
--- a/e-util/e-logger.c
+++ b/e-util/e-logger.c
@@@ -240,13 -240,13 +240,13 @@@ e_logger_log (ELogger *logger
  
  	fprintf (logger->priv->fp, "%d:%ld:%s\n", level, t, primary);
  	fprintf (logger->priv->fp, "%d:%ld:%s\n", level, t, secondary);
 -	set_dirty (logger);
 +	logger_set_dirty (logger);
  }
  
- void 
+ void
  e_logger_get_logs (ELogger *logger,
                     ELogFunction func,
 -                   gpointer data)
 +                   gpointer user_data)
  {
  	FILE *fp;
  	gchar buf[250];
diff --cc e-util/e-marshal.list
index b667ca4,3666024..d6a3f0c
--- a/e-util/e-marshal.list
+++ b/e-util/e-marshal.list
@@@ -66,4 -66,3 +66,5 @@@ NONE:STRING,STRING,STRIN
  NONE:STRING,STRING,UINT
  OBJECT:OBJECT,DOUBLE,DOUBLE,BOOLEAN
  POINTER:NONE
 +STRING:NONE
++
diff --cc e-util/e-module.c
index 51e1e18,0000000..3919841
mode 100644,000000..100644
--- a/e-util/e-module.c
+++ b/e-util/e-module.c
@@@ -1,318 -1,0 +1,318 @@@
 +/*
 + * e-module.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-module.h"
 +
 +#include <glib/gi18n.h>
 +
 +/* This is the symbol we call when loading a module. */
 +#define LOAD_SYMBOL	"e_module_load"
 +
 +/* This is the symbol we call when unloading a module. */
 +#define UNLOAD_SYMBOL	"e_module_unload"
 +
 +#define E_MODULE_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_MODULE, EModulePrivate))
 +
 +struct _EModulePrivate {
 +	GModule *module;
 +	gchar *filename;
 +
 +	void (*load) (GTypeModule *type_module);
 +	void (*unload) (GTypeModule *type_module);
 +};
 +
 +enum {
 +	PROP_0,
 +	PROP_FILENAME
 +};
 +
 +static gpointer parent_class;
 +
 +static void
 +module_set_filename (EModule *module,
 +                     const gchar *filename)
 +{
 +	g_return_if_fail (module->priv->filename == NULL);
 +
 +	module->priv->filename = g_strdup (filename);
 +}
 +
 +static void
 +module_set_property (GObject *object,
 +                     guint property_id,
 +                     const GValue *value,
 +                     GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_FILENAME:
 +			module_set_filename (
 +				E_MODULE (object),
 +				g_value_get_string (value));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +module_get_property (GObject *object,
 +                     guint property_id,
 +                     GValue *value,
 +                     GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_FILENAME:
 +			g_value_set_string (
 +				value, e_module_get_filename (
 +				E_MODULE (object)));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +module_finalize (GObject *object)
 +{
 +	EModulePrivate *priv;
 +
 +	priv = E_MODULE_GET_PRIVATE (object);
 +
 +	g_free (priv->filename);
 +
 +	/* Chain up to parent's finalize() method. */
 +	G_OBJECT_CLASS (parent_class)->finalize (object);
 +}
 +
 +static gboolean
 +module_load (GTypeModule *type_module)
 +{
 +	EModulePrivate *priv;
 +	gpointer symbol;
 +
 +	priv = E_MODULE_GET_PRIVATE (type_module);
 +
 +	g_return_val_if_fail (priv->filename != NULL, FALSE);
 +	priv->module = g_module_open (priv->filename, 0);
 +
 +	if (priv->module == NULL)
 +		goto fail;
 +
 +	if (!g_module_symbol (priv->module, LOAD_SYMBOL, &symbol))
 +		goto fail;
 +
 +	priv->load = symbol;
 +
 +	if (!g_module_symbol (priv->module, UNLOAD_SYMBOL, &symbol))
 +		goto fail;
 +
 +	priv->unload = symbol;
 +
 +	priv->load (type_module);
 +
 +	return TRUE;
 +
 +fail:
 +	g_warning ("%s", g_module_error ());
 +
 +	if (priv->module != NULL)
 +		g_module_close (priv->module);
 +
 +	return FALSE;
 +}
 +
 +static void
 +module_unload (GTypeModule *type_module)
 +{
 +	EModulePrivate *priv;
 +
 +	priv = E_MODULE_GET_PRIVATE (type_module);
 +
 +	priv->unload (type_module);
 +
 +	g_module_close (priv->module);
 +	priv->module = NULL;
 +
 +	priv->load = NULL;
 +	priv->unload = NULL;
 +}
 +
 +static void
 +module_class_init (EModuleClass *class)
 +{
 +	GObjectClass *object_class;
 +	GTypeModuleClass *type_module_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (EModulePrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->set_property = module_set_property;
 +	object_class->get_property = module_get_property;
 +	object_class->finalize = module_finalize;
 +
 +	type_module_class = G_TYPE_MODULE_CLASS (class);
 +	type_module_class->load = module_load;
 +	type_module_class->unload = module_unload;
 +
 +	/**
 +	 * EModule:filename
 +	 *
 +	 * The filename of the module.
 +	 **/
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_FILENAME,
 +		g_param_spec_string (
 +			"filename",
 +			_("Filename"),
 +			_("The filename of the module"),
 +			NULL,
 +			G_PARAM_READWRITE |
 +			G_PARAM_CONSTRUCT_ONLY));
 +}
 +
 +static void
 +module_init (EModule *module)
 +{
 +	module->priv = E_MODULE_GET_PRIVATE (module);
 +}
 +
 +GType
 +e_module_get_type (void)
 +{
 +	static GType type = 0;
 +
 +	if (G_UNLIKELY (type == 0)) {
 +		const GTypeInfo type_info = {
 +			sizeof (EModuleClass),
 +			(GBaseInitFunc) NULL,
 +			(GBaseFinalizeFunc) NULL,
 +			(GClassInitFunc) module_class_init,
 +			(GClassFinalizeFunc) NULL,
 +			NULL,  /* class_data */
 +			sizeof (EModule),
 +			0,     /* n_preallocs */
 +			(GInstanceInitFunc) module_init,
 +			NULL   /* value_table */
 +		};
 +
 +		type = g_type_register_static (
 +			G_TYPE_TYPE_MODULE, "EModule", &type_info, 0);
 +	}
 +
 +	return type;
 +}
 +
 +/**
 + * e_module_new:
 + * @filename: filename of the shared library module
 + *
 + * Creates a new #EModule that will load the specific shared library
 + * when in use.
 + *
 + * Returns: a new #EModule for @filename
 + **/
 +EModule *
 +e_module_new (const gchar *filename)
 +{
 +	g_return_val_if_fail (filename != NULL, NULL);
 +
 +	return g_object_new (E_TYPE_MODULE, "filename", filename, NULL);
 +}
 +
 +/**
 + * e_module_get_filename:
 + * @module: an #EModule
 + *
 + * Returns the filename of the shared library for @module.  The
 + * string is owned by @module and should not be modified or freed.
 + *
 + * Returns: the filename for @module
 + **/
 +const gchar *
 +e_module_get_filename (EModule *module)
 +{
 +	g_return_val_if_fail (E_IS_MODULE (module), NULL);
 +
 +	return module->priv->filename;
 +}
 +
 +/**
 + * e_module_load_all_in_directory:
 + * @dirname: pathname for a directory containing modules to load
 + *
 + * Loads all the modules in the specified directory into memory.  If
 + * you want to unload them (enabling on-demand loading) you must call
 + * g_type_module_unuse() on all the modules.  Free the returned list
 + * with g_list_free().
 + *
 + * Returns: a list of #EModules loaded from @dirname
 + **/
 +GList *
 +e_module_load_all_in_directory (const gchar *dirname)
 +{
 +	GDir *dir;
 +	const gchar *basename;
 +	GList *loaded_modules = NULL;
 +	GError *error = NULL;
 +
 +	g_return_val_if_fail (dirname != NULL, NULL);
 +
 +	if (!g_module_supported ())
 +		return NULL;
 +
 +	dir = g_dir_open (dirname, 0, &error);
 +	if (dir == NULL) {
 +		g_warning ("%s", error->message);
 +		g_error_free (error);
 +		return NULL;
 +	}
 +
 +	while ((basename = g_dir_read_name (dir)) != NULL) {
 +		EModule *module;
 +		gchar *filename;
 +
 +		if (!g_str_has_suffix (basename, "." G_MODULE_SUFFIX))
 +			continue;
 +
 +		filename = g_build_filename (dirname, basename, NULL);
 +
 +		module = e_module_new (filename);
 +
 +		if (!g_type_module_use (G_TYPE_MODULE (module))) {
 +			g_printerr ("Failed to load module: %s\n", filename);
 +			g_object_unref (module);
 +			g_free (filename);
 +			continue;
 +		}
 +
 +		g_free (filename);
 +
 +		loaded_modules = g_list_prepend (loaded_modules, module);
 +	}
 +
 +	g_dir_close (dir);
 +
 +	return loaded_modules;
 +}
diff --cc e-util/e-module.h
index 022769d,0000000..a812056
mode 100644,000000..100644
--- a/e-util/e-module.h
+++ b/e-util/e-module.h
@@@ -1,81 -1,0 +1,81 @@@
 +/*
 + * e-module.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +/**
 + * SECTION: e-module
 + * @short_description: generic module loader
 + * @include: e-util/e-module.h
 + **/
 +
 +#ifndef E_MODULE_H
 +#define E_MODULE_H
 +
 +#include <gmodule.h>
 +#include <glib-object.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_MODULE \
 +	(e_module_get_type ())
 +#define E_MODULE(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_MODULE, EModule))
 +#define E_MODULE_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_MODULE, EModuleClass))
 +#define E_IS_MODULE(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_MODULE))
 +#define E_IS_MODULE_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), E_TYPE_MODULE))
 +#define E_MODULE_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_MODULE, EModuleClass))
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _EModule EModule;
 +typedef struct _EModuleClass EModuleClass;
 +typedef struct _EModulePrivate EModulePrivate;
 +
 +/**
 + * EModule:
 + *
 + * Contains only private data that should be read and manipulated using the
 + * functions below.
 + **/
 +struct _EModule {
 +	GTypeModule parent;
 +	EModulePrivate *priv;
 +};
 +
 +struct _EModuleClass {
 +	GTypeModuleClass parent_class;
 +};
 +
 +GType		e_module_get_type		(void);
 +EModule *	e_module_new			(const gchar *filename);
 +const gchar *	e_module_get_filename		(EModule *module);
 +GList *		e_module_load_all_in_directory	(const gchar *dirname);
 +
 +G_END_DECLS
 +
 +#endif /* E_MODULE_H */
diff --cc e-util/e-signature-utils.c
index 0114ce6,0000000..1321fc5
mode 100644,000000..100644
--- a/e-util/e-signature-utils.c
+++ b/e-util/e-signature-utils.c
@@@ -1,347 -1,0 +1,347 @@@
 +/*
 + * e-signature-utils.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + */
 +
 +#include "e-signature-utils.h"
 +
 +#include <errno.h>
 +#include <glib/gstdio.h>
 +#include <gconf/gconf-client.h>
 +#include <camel/camel-stream.h>
 +#include <camel/camel-stream-fs.h>
 +#include <camel/camel-stream-mem.h>
 +#include <camel/camel-stream-filter.h>
 +#include <camel/camel-mime-filter-charset.h>
 +#include <camel/camel-mime-filter-tohtml.h>
 +
 +#ifndef G_OS_WIN32
 +#include <sys/wait.h>
 +#endif
 +
 +#include "e-util/e-util.h"
 +
 +static ESignatureList *global_signature_list;
 +
 +ESignatureList *
 +e_get_signature_list (void)
 +{
 +	if (G_UNLIKELY (global_signature_list == NULL)) {
 +		GConfClient *client;
 +
 +		client = gconf_client_get_default ();
 +		global_signature_list = e_signature_list_new (client);
 +		g_object_unref (client);
 +	}
 +
 +	g_return_val_if_fail (global_signature_list != NULL, NULL);
 +
 +	return global_signature_list;
 +}
 +
 +ESignature *
 +e_get_signature_by_name (const gchar *name)
 +{
 +	ESignatureList *signature_list;
 +	const ESignature *signature;
 +	e_signature_find_t find;
 +
 +	g_return_val_if_fail (name != NULL, NULL);
 +
 +	find = E_SIGNATURE_FIND_NAME;
 +	signature_list = e_get_signature_list ();
 +	signature = e_signature_list_find (signature_list, find, name);
 +
 +	/* XXX ESignatureList misuses const. */
 +	return (ESignature *) signature;
 +}
 +
 +ESignature *
 +e_get_signature_by_uid (const gchar *uid)
 +{
 +	ESignatureList *signature_list;
 +	const ESignature *signature;
 +	e_signature_find_t find;
 +
 +	g_return_val_if_fail (uid != NULL, NULL);
 +
 +	find = E_SIGNATURE_FIND_UID;
 +	signature_list = e_get_signature_list ();
 +	signature = e_signature_list_find (signature_list, find, uid);
 +
 +	/* XXX ESignatureList misuses const. */
 +	return (ESignature *) signature;
 +}
 +
 +gchar *
 +e_create_signature_file (GError **error)
 +{
 +	const gchar *data_dir;
 +	gchar basename[32];
 +	gchar *filename;
 +	gchar *pathname;
 +	gint32 ii;
 +
 +	data_dir = e_get_user_data_dir ();
 +	pathname = g_build_filename (data_dir, "signatures", NULL);
 +	filename = NULL;
 +
 +	if (g_mkdir_with_parents (pathname, 0700) < 0) {
 +		g_set_error (
 +			error, G_FILE_ERROR,
 +			g_file_error_from_errno (errno),
 +			"%s: %s", pathname, g_strerror (errno));
 +		g_free (pathname);
 +		return NULL;
 +	}
 +
 +	for (ii = 0; ii < G_MAXINT32; ii++) {
 +
 +		g_snprintf (
 +			basename, sizeof (basename),
 +			"signature-%" G_GINT32_FORMAT, ii);
 +
 +		g_free (filename);
 +		filename = g_build_filename (pathname, basename, NULL);
 +
 +		if (!g_file_test (filename, G_FILE_TEST_EXISTS)) {
 +			gint fd;
 +
 +			fd = g_creat (filename, 0600);
 +			if (fd >= 0) {
 +				close (fd);
 +				break;
 +			}
 +
 +			/* If we failed once we're probably going
 +			 * to continue failing, so just give up. */
 +			g_set_error (
 +				error, G_FILE_ERROR,
 +				g_file_error_from_errno (errno),
 +				"%s: %s", filename, g_strerror (errno));
 +			g_free (filename);
 +			filename = NULL;
 +			break;
 +		}
 +	}
 +
 +	/* If there are actually G_MAXINT32 signature files, the
 +	 * most recent signature file we be overwritten.  Sorry. */
 +
 +	return filename;
 +}
 +
 +gchar *
 +e_read_signature_file (ESignature *signature,
 +                       gboolean convert_to_html,
 +                       GError **error)
 +{
 +	CamelStream *input_stream;
 +	CamelStream *output_stream;
 +	GByteArray *buffer;
 +	gchar *content;
 +	gsize length;
 +	gint fd;
 +
 +	g_return_val_if_fail (E_IS_SIGNATURE (signature), NULL);
 +
 +	fd = g_open (signature->filename, O_RDONLY, 0);
 +	if (fd < 0) {
 +		g_set_error (
 +			error, G_FILE_ERROR,
 +			g_file_error_from_errno (errno),
 +			"%s: %s", signature->filename,
 +			g_strerror (errno));
 +		return NULL;
 +	}
 +
 +	input_stream = camel_stream_fs_new_with_fd (fd);
 +
 +	if (!signature->html && convert_to_html) {
 +		CamelStreamFilter *filtered_stream;
 +		CamelMimeFilter *filter;
 +		gint32 flags;
 +
 +		filtered_stream =
 +			camel_stream_filter_new_with_stream (input_stream);
 +		camel_object_unref (input_stream);
 +
 +		flags =
 +			CAMEL_MIME_FILTER_TOHTML_PRESERVE_8BIT |
 +			CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS |
 +			CAMEL_MIME_FILTER_TOHTML_CONVERT_ADDRESSES |
 +			CAMEL_MIME_FILTER_TOHTML_CONVERT_SPACES;
 +		filter = camel_mime_filter_tohtml_new (flags, 0);
 +		camel_stream_filter_add (filtered_stream, filter);
 +		camel_object_unref (filter);
 +
 +		input_stream = (CamelStream *) filtered_stream;
 +	}
 +
 +	buffer = g_byte_array_new ();
 +	output_stream = camel_stream_mem_new ();
 +	camel_stream_mem_set_byte_array (
 +		CAMEL_STREAM_MEM (output_stream), buffer);
 +	camel_stream_write_to_stream (input_stream, output_stream);
 +	camel_object_unref (output_stream);
 +	camel_object_unref (input_stream);
 +
 +	/* Make sure the buffer is nul-terminated. */
 +	length = (gsize) buffer->len;
 +	g_byte_array_append (buffer, (guint8 *) "", 1);
 +	content = (gchar *) g_byte_array_free (buffer, FALSE);
 +
 +	/* Signatures are saved as UTF-8, but we still need to check that
 +	 * the signature is valid UTF-8 because the user may be opening
 +	 * a signature file that is in his/her locale character set.  If
 +	 * it's not in UTF-8 then try converting from the current locale. */
 +	if (!g_utf8_validate (content, length, NULL)) {
 +		gchar *utf8;
 +
 +		utf8 = g_locale_to_utf8 (content, length, NULL, NULL, error);
 +		g_free (content);
 +		content = utf8;
 +	}
 +
 +	return content;
 +}
 +
 +gchar *
 +e_run_signature_script (const gchar *filename)
 +{
 +	/* FIXME Make this cross-platform, prefer GLib functions over
 +	 *       POSIX, and report errors via GError instead of dumping
 +	 *       messages to the terminal where users won't see them. */
 +
 +#ifndef G_OS_WIN32
 +	gint in_fds[2];
 +	pid_t pid;
 +
 +	g_return_val_if_fail (filename != NULL, NULL);
 +
 +	if (pipe (in_fds) == -1) {
 +		g_warning (
 +			"Failed to create pipe to '%s': %s",
 +			filename, g_strerror (errno));
 +		return NULL;
 +	}
 +
 +	pid = fork ();
 +
 +	/* Child Process */
 +	if (pid == 0) {
 +		gint maxfd, ii;
 +
 +		close (in_fds[0]);
 +		if (dup2 (in_fds[1], STDOUT_FILENO) < 0)
 +			_exit (255);
 +		close (in_fds[1]);
 +
 +		setsid ();
 +
 +		maxfd = sysconf (_SC_OPEN_MAX);
 +		for (ii = 3; ii < maxfd; ii++) {
 +			if (ii == STDIN_FILENO)
 +				continue;
 +			if (ii == STDOUT_FILENO)
 +				continue;
 +			if (ii == STDERR_FILENO)
 +				continue;
 +			fcntl (ii, F_SETFD, FD_CLOEXEC);
 +		}
 +
 +		execlp ("/bin/sh", "/bin/sh", "-c", filename, NULL);
 +
 +		g_warning (
 +			"Could not execute '%s': %s",
 +			filename, g_strerror (errno));
 +
 +		_exit (255);
 +
 +	/* Parent Process */
 +	} else if (pid > 0) {
 +		CamelStream *output_stream;
 +		CamelStream *input_stream;
 +		GByteArray *buffer;
 +		gchar *content;
 +		gsize length;
 +		gint result;
 +		gint status;
 +
 +		close (in_fds[1]);
 +
 +		buffer = g_byte_array_new ();
 +		output_stream = camel_stream_mem_new ();
 +		camel_stream_mem_set_byte_array (
 +			CAMEL_STREAM_MEM (output_stream), buffer);
 +
 +		input_stream = camel_stream_fs_new_with_fd (in_fds[0]);
 +		camel_stream_write_to_stream (input_stream, output_stream);
 +		camel_object_unref (input_stream);
 +
 +		camel_object_unref (output_stream);
 +
 +		/* Make sure the buffer is nul-terminated. */
 +		length = (gsize) buffer->len;
 +		g_byte_array_append (buffer, (guchar *) "", 1);
 +		content = (gchar *) g_byte_array_free (buffer, FALSE);
 +
 +		/* Signature scripts are supposed to generate UTF-8 content,
 +		 * but because users are known to never read the manual, we
 +		 * try to do our best if the content isn't valid UTF-8 by
 +		 * assuming that the content is in the user's locale
 +		 * character set. */
 +		if (!g_utf8_validate (content, length, NULL)) {
 +			gchar *utf8;
 +
 +			/* XXX Should pass a GError here. */
 +			utf8 = g_locale_to_utf8 (
 +				content, length, NULL, NULL, NULL);
 +			g_free (content);
 +			content = utf8;
 +		}
 +
 +		/* Wait for the script process to terminate. */
 +		result = waitpid (pid, &status, 0);
 +
 +		if (result == -1 && errno == EINTR) {
 +			/* Child process is hanging... */
 +			kill (pid, SIGTERM);
 +			sleep (1);
 +			result = waitpid (pid, &status, WNOHANG);
 +			if (result == 0) {
 +				/* ...still hanging, set phasers to KILL. */
 +				kill (pid, SIGKILL);
 +				sleep (1);
 +				result = waitpid (pid, &status, WNOHANG);
 +			}
 +		}
 +
 +		return content;
 +
 +	/* Forking Failed */
 +	} else {
 +		g_warning (
 +			"Failed to create child process '%s': %s",
 +			filename, g_strerror (errno));
 +		close (in_fds[0]);
 +		close (in_fds[1]);
 +	}
 +#endif
 +
 +	return NULL;
 +}
diff --cc e-util/e-signature-utils.h
index 41472f4,0000000..56f8564
mode 100644,000000..100644
--- a/e-util/e-signature-utils.h
+++ b/e-util/e-signature-utils.h
@@@ -1,40 -1,0 +1,40 @@@
 +/*
 + * e-signature-utils.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + */
 +
 +#ifndef E_SIGNATURE_UTILS_H
 +#define E_SIGNATURE_UTILS_H
 +
 +#include <gtk/gtk.h>
 +#include <e-util/e-signature.h>
 +#include <e-util/e-signature-list.h>
 +
 +G_BEGIN_DECLS
 +
 +ESignatureList *e_get_signature_list		(void);
 +ESignature *	e_get_signature_by_name		(const gchar *name);
 +ESignature *	e_get_signature_by_uid		(const gchar *uid);
 +gchar *		e_create_signature_file		(GError **error);
 +gchar *		e_read_signature_file		(ESignature *signature,
 +						 gboolean convert_to_html,
 +						 GError **error);
 +gchar *		e_run_signature_script		(const gchar *filename);
 +
 +G_END_DECLS
 +
 +#endif /* E_SIGNATURE_UTILS_H */
diff --cc em-format/em-format-quote.c
index 5503cca,0000000..7918b94
mode 100644,000000..100644
--- a/em-format/em-format-quote.c
+++ b/em-format/em-format-quote.c
@@@ -1,586 -1,0 +1,586 @@@
 +/*
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Authors:
 + *		Jeffrey Stedfast <fejj ximian com>
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifdef HAVE_CONFIG_H
 +#include <config.h>
 +#endif
 +
 +#include <string.h>
 +
 +#include <camel/camel-iconv.h>
 +#include <camel/camel-stream-filter.h>
 +#include <camel/camel-mime-filter-tohtml.h>
 +#include <camel/camel-mime-filter-enriched.h>
 +#include <camel/camel-string-utils.h>
 +#include <camel/camel-mime-message.h>
 +#include <camel/camel-url.h>
 +
 +#include <glib/gi18n.h>
 +#include <gconf/gconf-client.h>
 +
 +#include "em-stripsig-filter.h"
 +#include "em-format-quote.h"
 +
 +struct _EMFormatQuotePrivate {
 +	int dummy;
 +};
 +
 +static void emfq_format_clone(EMFormat *, CamelFolder *, const char *, CamelMimeMessage *, EMFormat *);
 +static void emfq_format_error(EMFormat *emf, CamelStream *stream, const char *txt);
 +static void emfq_format_message(EMFormat *, CamelStream *, CamelMimePart *, const EMFormatHandler *);
 +static void emfq_format_source(EMFormat *, CamelStream *, CamelMimePart *);
 +static void emfq_format_attachment(EMFormat *, CamelStream *, CamelMimePart *, const char *, const EMFormatHandler *);
 +
 +static void emfq_builtin_init(EMFormatQuoteClass *efhc);
 +
 +static gpointer parent_class;
 +
 +static void
 +emfq_init(GObject *o)
 +{
 +	EMFormatQuote *emfq =(EMFormatQuote *) o;
 +
 +	/* we want to convert url's etc */
 +	emfq->text_html_flags = CAMEL_MIME_FILTER_TOHTML_PRE | CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS
 +		| CAMEL_MIME_FILTER_TOHTML_CONVERT_ADDRESSES;
 +}
 +
 +static void
 +emfq_finalize (GObject *object)
 +{
 +	EMFormatQuote *emfq =(EMFormatQuote *) object;
 +
 +	if (emfq->stream)
 +		camel_object_unref(emfq->stream);
 +	g_free(emfq->credits);
 +
 +	/* Chain up to parent's finalize() method. */
 +	G_OBJECT_CLASS (parent_class)->finalize (object);
 +}
 +
 +static void
 +emfq_base_init(EMFormatQuoteClass *emfqclass)
 +{
 +	emfq_builtin_init(emfqclass);
 +}
 +
 +static void
 +emfq_class_init (EMFormatQuoteClass *class)
 +{
 +	GObjectClass *object_class;
 +	EMFormatClass *format_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (EMFormatQuotePrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->finalize = emfq_finalize;
 +
 +	format_class = EM_FORMAT_CLASS (class);
 +	format_class->format_clone = emfq_format_clone;
 +	format_class->format_error = emfq_format_error;
 +	format_class->format_source = emfq_format_source;
 +	format_class->format_attachment = emfq_format_attachment;
 +}
 +
 +GType
 +em_format_quote_get_type (void)
 +{
 +	static GType type = 0;
 +
 +	if (G_UNLIKELY (type == 0)) {
 +		static const GTypeInfo type_info = {
 +			sizeof (EMFormatQuoteClass),
 +			(GBaseInitFunc) emfq_base_init,
 +			(GBaseFinalizeFunc) NULL,
 +			(GClassInitFunc) emfq_class_init,
 +			(GClassFinalizeFunc) NULL,
 +			NULL,  /* class_data */
 +			sizeof (EMFormatQuote),
 +			0,     /* n_preallocs */
 +			(GInstanceInitFunc) emfq_init,
 +			NULL   /* value_table */
 +		};
 +
 +		type = g_type_register_static (
 +			EM_TYPE_FORMAT, "EMFormatQuote", &type_info, 0);
 +	}
 +
 +	return type;
 +}
 +
 +EMFormatQuote *
 +em_format_quote_new (const gchar *credits,
 +                     CamelStream *stream,
 +                     guint32 flags)
 +{
 +	EMFormatQuote *emfq;
 +
 +	emfq = g_object_new (EM_TYPE_FORMAT_QUOTE, NULL);
 +
 +	emfq->credits = g_strdup (credits);
 +	emfq->stream = stream;
 +	camel_object_ref (stream);
 +	emfq->flags = flags;
 +
 +	return emfq;
 +}
 +
 +static void
 +emfq_format_empty_line(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info)
 +{
 +	camel_stream_printf(stream, "<br>\n");
 +}
 +
 +static void
 +emfq_format_clone(EMFormat *emf, CamelFolder *folder, const char *uid, CamelMimeMessage *msg, EMFormat *src)
 +{
 +	EMFormatQuote *emfq = (EMFormatQuote *) emf;
 +	const EMFormatHandler *handle;
 +	GConfClient *gconf;
 +
 +	/* Chain up to parent's format_clone() method. */
 +	EM_FORMAT_CLASS (parent_class)->format_clone (emf, folder, uid, msg, src);
 +
 +	gconf = gconf_client_get_default ();
 +	camel_stream_reset(emfq->stream);
 +	if (gconf_client_get_bool(gconf, "/apps/evolution/mail/composer/top_signature", NULL))
 +		emfq_format_empty_line(emf, emfq->stream, (CamelMimePart *)msg, NULL);
 +	g_object_unref (gconf);
 +	handle = em_format_find_handler(emf, "x-evolution/message/prefix");
 +	if (handle)
 +		handle->handler(emf, emfq->stream, (CamelMimePart *)msg, handle);
 +	handle = em_format_find_handler(emf, "x-evolution/message/rfc822");
 +	if (handle)
 +		handle->handler(emf, emfq->stream, (CamelMimePart *)msg, handle);
 +
 +	camel_stream_flush(emfq->stream);
 +
 +	g_signal_emit_by_name(emf, "complete");
 +}
 +
 +static void
 +emfq_format_error(EMFormat *emf, CamelStream *stream, const char *txt)
 +{
 +	/* FIXME: should we even bother writing error text for quoting? probably not... */
 +}
 +
 +static void
 +emfq_format_text_header (EMFormatQuote *emfq, CamelStream *stream, const char *label, const char *value, guint32 flags, int is_html)
 +{
 +	const char *fmt, *html;
 +	char *mhtml = NULL;
 +
 +	if (value == NULL)
 +		return;
 +
 +	while (*value == ' ')
 +		value++;
 +
 +	if (!is_html)
 +		html = mhtml = camel_text_to_html (value, 0, 0);
 +	else
 +		html = value;
 +
 +	if (flags & EM_FORMAT_HEADER_BOLD)
 +		fmt = "<b>%s</b>: %s<br>";
 +	else
 +		fmt = "%s: %s<br>";
 +
 +	camel_stream_printf (stream, fmt, label, html);
 +	g_free (mhtml);
 +}
 +
- static char *addrspec_hdrs[] = {
++static const gchar *addrspec_hdrs[] = {
 +	"Sender", "From", "Reply-To", "To", "Cc", "Bcc",
 +	"Resent-Sender", "Resent-from", "Resent-Reply-To",
 +	"Resent-To", "Resent-cc", "Resent-Bcc", NULL
 +};
 +
 +#if 0
 +/* FIXME: include Sender and Resent-* headers too? */
 +/* For Translators only: The following strings are used in the header table in the preview pane */
 +static char *i18n_hdrs[] = {
 +	N_("From"), N_("Reply-To"), N_("To"), N_("Cc"), N_("Bcc")
 +};
 +#endif
 +
 +static void
 +emfq_format_address (GString *out, struct _camel_header_address *a)
 +{
 +	guint32 flags = CAMEL_MIME_FILTER_TOHTML_CONVERT_SPACES;
 +	char *name, *mailto, *addr;
 +
 +	while (a) {
 +		if (a->name)
 +			name = camel_text_to_html (a->name, flags, 0);
 +		else
 +			name = NULL;
 +
 +		switch (a->type) {
 +		case CAMEL_HEADER_ADDRESS_NAME:
 +			if (name && *name) {
 +				char *real, *mailaddr;
 +
 +				g_string_append_printf (out, "%s &lt;", name);
 +				/* rfc2368 for mailto syntax and url encoding extras */
 +				if ((real = camel_header_encode_phrase ((unsigned char *)a->name))) {
 +					mailaddr = g_strdup_printf ("%s <%s>", real, a->v.addr);
 +					g_free (real);
 +					mailto = camel_url_encode (mailaddr, "?=&()");
 +					g_free (mailaddr);
 +				} else {
 +					mailto = camel_url_encode (a->v.addr, "?=&()");
 +				}
 +			} else {
 +				mailto = camel_url_encode (a->v.addr, "?=&()");
 +			}
 +			addr = camel_text_to_html (a->v.addr, flags, 0);
 +			g_string_append_printf (out, "<a href=\"mailto:%s\";>%s</a>", mailto, addr);
 +			g_free (mailto);
 +			g_free (addr);
 +
 +			if (name && *name)
 +				g_string_append (out, "&gt;");
 +			break;
 +		case CAMEL_HEADER_ADDRESS_GROUP:
 +			g_string_append_printf (out, "%s: ", name);
 +			emfq_format_address (out, a->v.members);
 +			g_string_append_printf (out, ";");
 +			break;
 +		default:
 +			g_warning ("Invalid address type");
 +			break;
 +		}
 +
 +		g_free (name);
 +
 +		a = a->next;
 +		if (a)
 +			g_string_append (out, ", ");
 +	}
 +}
 +
 +static void
 +canon_header_name (char *name)
 +{
 +	char *inptr = name;
- 	
++
 +	/* canonicalise the header name... first letter is
 +	 * capitalised and any letter following a '-' also gets
 +	 * capitalised */
- 	
++
 +	if (*inptr >= 'a' && *inptr <= 'z')
 +		*inptr -= 0x20;
- 	
++
 +	inptr++;
- 	
++
 +	while (*inptr) {
 +		if (inptr[-1] == '-' && *inptr >= 'a' && *inptr <= 'z')
 +			*inptr -= 0x20;
 +		else if (*inptr >= 'A' && *inptr <= 'Z')
 +			*inptr += 0x20;
- 		
++
 +		inptr++;
 +	}
 +}
 +
 +static void
 +emfq_format_header (EMFormat *emf, CamelStream *stream, CamelMedium *part, const char *namein, guint32 flags, const char *charset)
 +{
 +	CamelMimeMessage *msg = (CamelMimeMessage *) part;
 +	EMFormatQuote *emfq = (EMFormatQuote *) emf;
 +	char *name, *buf, *value = NULL;
 +	const char *txt, *label;
 +	gboolean addrspec = FALSE;
 +	int is_html = FALSE;
 +	int i;
 +
 +	name = g_alloca (strlen (namein) + 1);
 +	strcpy (name, namein);
 +	canon_header_name (name);
 +
 +	for (i = 0; addrspec_hdrs[i]; i++) {
 +		if (!strcmp (name, addrspec_hdrs[i])) {
 +			addrspec = TRUE;
 +			break;
 +		}
 +	}
- 	
++
 +	label = _(name);
- 	
++
 +	if (addrspec) {
 +		struct _camel_header_address *addrs;
 +		GString *html;
 +
 +		if (!(txt = camel_medium_get_header (part, name)))
 +			return;
- 		
++
 +		buf = camel_header_unfold (txt);
 +		if (!(addrs = camel_header_address_decode (txt, emf->charset ? emf->charset : emf->default_charset))) {
 +			g_free (buf);
 +			return;
 +		}
- 		
++
 +		g_free (buf);
- 		
++
 +		html = g_string_new ("");
 +		emfq_format_address (html, addrs);
 +		camel_header_address_unref (addrs);
 +		txt = value = html->str;
 +		g_string_free (html, FALSE);
 +		flags |= EM_FORMAT_HEADER_BOLD;
 +		is_html = TRUE;
 +	} else if (!strcmp (name, "Subject")) {
 +		txt = camel_mime_message_get_subject (msg);
 +		label = _("Subject");
 +		flags |= EM_FORMAT_HEADER_BOLD;
 +	} else if (!strcmp (name, "X-Evolution-Mailer")) { /* pseudo-header */
 +		if (!(txt = camel_medium_get_header (part, "x-mailer")))
 +			if (!(txt = camel_medium_get_header (part, "user-agent")))
 +				if (!(txt = camel_medium_get_header (part, "x-newsreader")))
 +					if (!(txt = camel_medium_get_header (part, "x-mimeole")))
 +						return;
- 		
++
 +		txt = value = camel_header_format_ctext (txt, charset);
- 		
++
 +		label = _("Mailer");
 +		flags |= EM_FORMAT_HEADER_BOLD;
 +	} else if (!strcmp (name, "Date") || !strcmp (name, "Resent-Date")) {
 +		if (!(txt = camel_medium_get_header (part, name)))
 +			return;
- 		
++
 +		flags |= EM_FORMAT_HEADER_BOLD;
 +	} else {
 +		txt = camel_medium_get_header (part, name);
 +		buf = camel_header_unfold (txt);
 +		txt = value = camel_header_decode_string (txt, charset);
 +		g_free (buf);
 +	}
 +
 +	emfq_format_text_header (emfq, stream, label, txt, flags, is_html);
 +
 +	g_free (value);
 +}
 +
 +static void
 +emfq_format_headers (EMFormatQuote *emfq, CamelStream *stream, CamelMedium *part)
 +{
 +	EMFormat *emf = (EMFormat *) emfq;
 +	CamelContentType *ct;
 +	const char *charset;
 +	EMFormatHeader *h;
 +
 +	if (!part)
 +		return;
 +
 +	ct = camel_mime_part_get_content_type ((CamelMimePart *) part);
 +	charset = camel_content_type_param (ct, "charset");
 +	charset = camel_iconv_charset_name (charset);
 +
 +	/* dump selected headers */
 +	h = (EMFormatHeader *) emf->header_list.head;
 +	while (h->next) {
 +		emfq_format_header (emf, stream, part, h->name, h->flags, charset);
 +		h = h->next;
 +	}
 +
 +	camel_stream_printf(stream, "<br>\n");
 +}
 +
 +static void
 +emfq_format_message_prefix(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info)
 +{
 +	EMFormatQuote *emfq = (EMFormatQuote *) emf;
 +
 +	if (emfq->credits)
 +		camel_stream_printf(stream, "%s<br>\n", emfq->credits);
 +}
 +
 +static void
 +emfq_format_message(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info)
 +{
 +	EMFormatQuote *emfq = (EMFormatQuote *) emf;
 +
 +	if (emfq->flags & EM_FORMAT_QUOTE_CITE)
 +		camel_stream_printf(stream, "<!--+GtkHTML:<DATA class=\"ClueFlow\" key=\"orig\" value=\"1\">-->\n"
 +				    "<blockquote type=cite>\n");
 +
 +	if (((CamelMimePart *)emf->message) != part) {
 +		camel_stream_printf(stream,  "%s</br>\n", _("-------- Forwarded Message --------"));
 +		emfq_format_headers (emfq, stream, (CamelMedium *)part);
 +	} else if (emfq->flags & EM_FORMAT_QUOTE_HEADERS)
 +		emfq_format_headers (emfq, stream, (CamelMedium *)part);
 +
 +	em_format_part (emf, stream, part);
 +
 +	if (emfq->flags & EM_FORMAT_QUOTE_CITE)
 +		camel_stream_write_string(stream, "</blockquote><!--+GtkHTML:<DATA class=\"ClueFlow\" clear=\"orig\">-->");
 +}
 +
 +static void
 +emfq_format_source(EMFormat *emf, CamelStream *stream, CamelMimePart *part)
 +{
 +	CamelStreamFilter *filtered_stream;
 +	CamelMimeFilter *html_filter;
 +
 +	filtered_stream = camel_stream_filter_new_with_stream ((CamelStream *) stream);
 +	html_filter = camel_mime_filter_tohtml_new (CAMEL_MIME_FILTER_TOHTML_CONVERT_NL
 +						    | CAMEL_MIME_FILTER_TOHTML_CONVERT_SPACES
 +						    | CAMEL_MIME_FILTER_TOHTML_ESCAPE_8BIT, 0);
 +	camel_stream_filter_add(filtered_stream, html_filter);
 +	camel_object_unref(html_filter);
 +
 +	em_format_format_text(emf, (CamelStream *)filtered_stream, (CamelDataWrapper *)part);
 +	camel_object_unref(filtered_stream);
 +}
 +
 +static void
 +emfq_format_attachment(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const char *mime_type, const EMFormatHandler *handle)
 +{
 +	if (handle && em_format_is_inline(emf, emf->part_id->str, part, handle)) {
 +		char *text, *html;
 +
 +		camel_stream_write_string(stream,
 +					  "<table border=1 cellspacing=0 cellpadding=0><tr><td><font size=-1>\n");
 +
 +		/* output some info about it */
 +		text = em_format_describe_part(part, mime_type);
 +		html = camel_text_to_html(text, ((EMFormatQuote *)emf)->text_html_flags & CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS, 0);
 +		camel_stream_write_string(stream, html);
 +		g_free(html);
 +		g_free(text);
 +
 +		camel_stream_write_string(stream, "</font></td></tr></table>");
 +
 +		handle->handler(emf, stream, part, handle);
 +	}
 +}
 +
 +#include <camel/camel-medium.h>
 +#include <camel/camel-mime-part.h>
 +#include <camel/camel-multipart.h>
 +#include <camel/camel-url.h>
 +
 +static void
 +emfq_text_plain(EMFormatQuote *emfq, CamelStream *stream, CamelMimePart *part, EMFormatHandler *info)
 +{
 +	CamelStreamFilter *filtered_stream;
 +	CamelMimeFilter *html_filter;
 +	CamelMimeFilter *sig_strip;
 +	CamelContentType *type;
 +	const char *format;
 +	guint32 rgb = 0x737373, flags;
 +
 +	if (!part)
 +		return;
 +
 +	flags = emfq->text_html_flags;
 +
 +	/* Check for RFC 2646 flowed text. */
 +	type = camel_mime_part_get_content_type(part);
 +	if (camel_content_type_is(type, "text", "plain")
 +	    && (format = camel_content_type_param(type, "format"))
 +	    && !g_ascii_strcasecmp(format, "flowed"))
 +		flags |= CAMEL_MIME_FILTER_TOHTML_FORMAT_FLOWED;
 +
 +	filtered_stream = camel_stream_filter_new_with_stream(stream);
 +
 +	if (emfq->flags != 0) {
 +		sig_strip = em_stripsig_filter_new ();
 +		camel_stream_filter_add (filtered_stream, sig_strip);
 +		camel_object_unref (sig_strip);
 +	}
 +
 +	html_filter = camel_mime_filter_tohtml_new(flags, rgb);
 +	camel_stream_filter_add(filtered_stream, html_filter);
 +	camel_object_unref(html_filter);
 +
 +	em_format_format_text((EMFormat *)emfq, (CamelStream *)filtered_stream, (CamelDataWrapper *)part);
 +	camel_stream_flush((CamelStream *)filtered_stream);
 +	camel_object_unref(filtered_stream);
 +}
 +
 +static void
 +emfq_text_enriched(EMFormatQuote *emfq, CamelStream *stream, CamelMimePart *part, EMFormatHandler *info)
 +{
 +	CamelStreamFilter *filtered_stream;
 +	CamelMimeFilter *enriched;
 +	CamelDataWrapper *dw;
 +	guint32 flags = 0;
 +
 +	dw = camel_medium_get_content_object((CamelMedium *)part);
 +
 +	if (!strcmp(info->mime_type, "text/richtext")) {
 +		flags = CAMEL_MIME_FILTER_ENRICHED_IS_RICHTEXT;
 +		camel_stream_write_string(stream, "\n<!-- text/richtext -->\n");
 +	} else {
 +		camel_stream_write_string(stream, "\n<!-- text/enriched -->\n");
 +	}
 +
 +	enriched = camel_mime_filter_enriched_new(flags);
 +	filtered_stream = camel_stream_filter_new_with_stream (stream);
 +	camel_stream_filter_add(filtered_stream, enriched);
 +	camel_object_unref(enriched);
 +
 +	camel_stream_write_string(stream, "<br><hr><br>");
 +	em_format_format_text((EMFormat *)emfq, (CamelStream *)filtered_stream, (CamelDataWrapper *)part);
 +	camel_object_unref(filtered_stream);
 +}
 +
 +static void
 +emfq_text_html(EMFormat *emf, CamelStream *stream, CamelMimePart *part, EMFormatHandler *info)
 +{
 +	camel_stream_write_string(stream, "\n<!-- text/html -->\n");
 +	em_format_format_text(emf, stream, (CamelDataWrapper *)part);
 +}
 +
 +static void
 +emfq_ignore(EMFormat *emf, CamelStream *stream, CamelMimePart *part, EMFormatHandler *info)
 +{
 +	/* NOOP */
 +}
 +
 +static EMFormatHandler type_builtin_table[] = {
- 	{ "text/plain",(EMFormatFunc)emfq_text_plain },
- 	{ "text/enriched",(EMFormatFunc)emfq_text_enriched },
- 	{ "text/richtext",(EMFormatFunc)emfq_text_enriched },
- 	{ "text/html",(EMFormatFunc)emfq_text_html },
- /*	{ "multipart/related",(EMFormatFunc)emfq_multipart_related },*/
- 	{ "message/external-body", (EMFormatFunc)emfq_ignore },
- 	{ "multipart/appledouble", (EMFormatFunc)emfq_ignore },
++	{ (gchar *) "text/plain", (EMFormatFunc)emfq_text_plain },
++	{ (gchar *) "text/enriched", (EMFormatFunc)emfq_text_enriched },
++	{ (gchar *) "text/richtext", (EMFormatFunc)emfq_text_enriched },
++	{ (gchar *) "text/html", (EMFormatFunc)emfq_text_html },
++/*	{ (gchar *) "multipart/related",(EMFormatFunc)emfq_multipart_related },*/
++	{ (gchar *) "message/external-body", (EMFormatFunc)emfq_ignore },
++	{ (gchar *) "multipart/appledouble", (EMFormatFunc)emfq_ignore },
 +
 +	/* internal evolution types */
- 	{ "x-evolution/evolution-rss-feed", (EMFormatFunc)emfq_text_html },
- 	{ "x-evolution/message/rfc822", (EMFormatFunc)emfq_format_message },
- 	{ "x-evolution/message/prefix", (EMFormatFunc)emfq_format_message_prefix },
++	{ (gchar *) "x-evolution/evolution-rss-feed", (EMFormatFunc)emfq_text_html },
++	{ (gchar *) "x-evolution/message/rfc822", (EMFormatFunc)emfq_format_message },
++	{ (gchar *) "x-evolution/message/prefix", (EMFormatFunc)emfq_format_message_prefix },
 +};
 +
 +static void
 +emfq_builtin_init(EMFormatQuoteClass *efhc)
 +{
 +	int i;
 +
 +	for (i=0;i<sizeof(type_builtin_table)/sizeof(type_builtin_table[0]);i++)
 +		em_format_class_add_handler((EMFormatClass *)efhc, &type_builtin_table[i]);
 +}
diff --cc em-format/em-format-quote.h
index d34548a,0000000..8aca4b8
mode 100644,000000..100644
--- a/em-format/em-format-quote.h
+++ b/em-format/em-format-quote.h
@@@ -1,81 -1,0 +1,81 @@@
 +/*
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Authors:
 + *		Jeffrey Stedfast <fejj ximian com>
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef EM_FORMAT_QUOTE_H
 +#define EM_FORMAT_QUOTE_H
 +
 +#include <camel/camel-stream.h>
 +#include "em-format.h"
 +
 +/* Standard GObject macros */
 +#define EM_TYPE_FORMAT_QUOTE \
 +	(em_format_quote_get_type ())
 +#define EM_FORMAT_QUOTE(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), EM_TYPE_FORMAT_QUOTE, EMFormatQuote))
 +#define EM_FORMAT_QUOTE_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), EM_TYPE_FORMAT_QUOTE, EMFormatQuoteClass))
 +#define EM_IS_FORMAT_QUOTE(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), EM_TYPE_FORMAT_QUOTE))
 +#define EM_IS_FORMAT_QUOTE_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), EM_TYPE_FORMAT_QUOTE))
 +#define EM_FORMAT_QUOTE_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), EM_TYPE_FORMAT_QUOTE, EMFormatQuoteClass))
 +
 +#define EM_FORMAT_QUOTE_CITE (1<<0)
 +#define EM_FORMAT_QUOTE_HEADERS (1<<1)
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _EMFormatQuote EMFormatQuote;
 +typedef struct _EMFormatQuoteClass EMFormatQuoteClass;
 +typedef struct _EMFormatQuotePrivate EMFormatQuotePrivate;
 +
 +struct _EMFormatQuote {
 +	EMFormat format;
 +
 +	EMFormatQuotePrivate *priv;
 +
 +	char *credits;
 +	CamelStream *stream;
 +	guint32 flags;
 +
 +	guint32 text_html_flags;
 +	guint32 citation_colour;
 +};
 +
 +struct _EMFormatQuoteClass {
 +	EMFormatClass format_class;
 +};
 +
 +GType		em_format_quote_get_type	(void);
 +EMFormatQuote *	em_format_quote_new		(const gchar *credits,
 +						 CamelStream *stream,
 +						 guint32 flags);
 +
 +G_END_DECLS
 +
 +#endif /* EM_FORMAT_QUOTE_H */
diff --cc em-format/em-format.c
index 7128644,0000000..c2669e7
mode 100644,000000..100644
--- a/em-format/em-format.c
+++ b/em-format/em-format.c
@@@ -1,1945 -1,0 +1,1946 @@@
 +/*
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Authors:
 + *		Michael Zucchi <notzed ximian com>
 + *      Jeffrey Stedfast <fejj ximian com>
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifdef HAVE_CONFIG_H
 +#include <config.h>
 +#endif
 +
 +#include <stdio.h>
 +#include <string.h>
 +
 +#include <glib/gi18n.h>
 +#include <gio/gio.h>
 +
 +#include <libedataserver/e-msgport.h>
 +#include <camel/camel-stream.h>
 +#include <camel/camel-stream-mem.h>
 +#include <camel/camel-multipart.h>
 +#include <camel/camel-multipart-encrypted.h>
 +#include <camel/camel-multipart-signed.h>
 +#include <camel/camel-medium.h>
 +#include <camel/camel-mime-message.h>
 +#include <camel/camel-gpg-context.h>
 +#include <camel/camel-smime-context.h>
 +#include <camel/camel-string-utils.h>
 +#include <camel/camel-stream-filter.h>
 +#include <camel/camel-stream-null.h>
 +#include <camel/camel-stream-mem.h>
 +#include <camel/camel-mime-filter-charset.h>
 +#include <camel/camel-mime-filter-windows.h>
 +#include <camel/camel-mime-filter-pgp.h>
 +
 +#include "em-format.h"
 +#include "e-util/e-util.h"
 +#include "shell/e-shell.h"
 +#include "shell/e-shell-settings.h"
 +
 +#define d(x)
 +
 +/* Used to cache various data/info for redraws
 +   The validity stuff could be cached at a higher level but this is easier
 +   This absolutely relies on the partid being _globally unique_
 +   This is still kind of yucky, we should maintian a full tree of all this data,
 +   along with/as part of the puri tree */
 +struct _EMFormatCache {
 +	CamelCipherValidity *valid; /* validity copy */
 +	CamelMimePart *secured;	/* encrypted subpart */
 +
 +	unsigned int state:2;		/* inline state */
 +
 +	char partid[1];
 +};
 +
 +#define INLINE_UNSET (0)
 +#define INLINE_ON (1)
 +#define INLINE_OFF (2)
 +
 +static void emf_builtin_init(EMFormatClass *);
 +
 +static const EMFormatHandler *emf_find_handler(EMFormat *emf, const char *mime_type);
 +static void emf_format_clone(EMFormat *emf, CamelFolder *folder, const char *uid, CamelMimeMessage *msg, EMFormat *emfsource);
 +static void emf_format_secure(EMFormat *emf, CamelStream *stream, CamelMimePart *part, CamelCipherValidity *valid);
 +static gboolean emf_busy(EMFormat *emf);
 +enum {
 +	EMF_COMPLETE,
 +	EMF_LAST_SIGNAL
 +};
 +
 +static gpointer parent_class;
 +static guint signals[EMF_LAST_SIGNAL];
 +
 +static void
 +emf_free_cache(struct _EMFormatCache *efc)
 +{
 +	if (efc->valid)
 +		camel_cipher_validity_free(efc->valid);
 +	if (efc->secured)
 +		camel_object_unref(efc->secured);
 +	g_free(efc);
 +}
 +
 +static struct _EMFormatCache *
 +emf_insert_cache(EMFormat *emf, const char *partid)
 +{
 +	struct _EMFormatCache *new;
 +
 +	new = g_malloc0(sizeof(*new)+strlen(partid));
 +	strcpy(new->partid, partid);
 +	g_hash_table_insert(emf->inline_table, new->partid, new);
 +
 +	return new;
 +}
 +
 +static void
 +emf_finalize (GObject *object)
 +{
 +	EMFormat *emf = EM_FORMAT (object);
 +
 +	if (emf->session)
 +		camel_object_unref (emf->session);
 +
 +	g_hash_table_destroy (emf->inline_table);
 +
 +	em_format_clear_headers(emf);
 +	camel_cipher_validity_free(emf->valid);
 +	g_free(emf->charset);
 +	g_free (emf->default_charset);
 +	g_string_free(emf->part_id, TRUE);
 +
 +	/* FIXME: check pending jobs */
 +
 +	/* Chain up to parent's finalize() method. */
 +	G_OBJECT_CLASS (parent_class)->finalize (object);
 +}
 +
 +static void
 +emf_base_init (EMFormatClass *class)
 +{
 +	class->type_handlers = g_hash_table_new (g_str_hash, g_str_equal);
 +	emf_builtin_init (class);
 +}
 +
 +static void
 +emf_class_init (EMFormatClass *class)
 +{
 +	GObjectClass *object_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->finalize = emf_finalize;
 +
 +	class->find_handler = emf_find_handler;
 +	class->format_clone = emf_format_clone;
 +	class->format_secure = emf_format_secure;
 +	class->busy = emf_busy;
 +
 +	signals[EMF_COMPLETE] = g_signal_new (
 +		"complete",
 +		G_OBJECT_CLASS_TYPE (class),
 +		G_SIGNAL_RUN_LAST,
 +		G_STRUCT_OFFSET (EMFormatClass, complete),
 +		NULL, NULL,
 +		g_cclosure_marshal_VOID__VOID,
 +		G_TYPE_NONE, 0);
 +
 +	class->type_handlers = g_hash_table_new (g_str_hash, g_str_equal);
 +	emf_builtin_init (class);
 +}
 +
 +static void
 +emf_init (EMFormat *emf)
 +{
 +	EShell *shell;
 +	EShellSettings *shell_settings;
 +
 +	emf->inline_table = g_hash_table_new_full (
 +		g_str_hash, g_str_equal,
 +		(GDestroyNotify) NULL,
 +		(GDestroyNotify) emf_free_cache);
 +	emf->composer = FALSE;
 +	emf->print = FALSE;
 +	e_dlist_init(&emf->header_list);
 +	em_format_default_headers(emf);
 +	emf->part_id = g_string_new("");
 +
 +	shell = e_shell_get_default ();
 +	shell_settings = e_shell_get_shell_settings (shell);
 +
 +	emf->session = e_shell_settings_get_pointer (shell_settings, "mail-session");
 +	g_return_if_fail (emf->session != NULL);
 +
 +	camel_object_ref (emf->session);
 +}
 +
 +GType
 +em_format_get_type (void)
 +{
 +	static GType type = 0;
 +
 +	if (G_UNLIKELY (type == 0)) {
 +		static const GTypeInfo type_info = {
 +			sizeof (EMFormatClass),
 +			(GBaseInitFunc) emf_base_init,
 +			(GBaseFinalizeFunc) NULL,
 +			(GClassInitFunc) emf_class_init,
 +			(GClassFinalizeFunc) NULL,
 +			NULL,  /* class_data */
 +			sizeof (EMFormat),
 +			0,     /* n_preallocs */
 +			(GInstanceInitFunc) emf_init,
 +			NULL   /* value_table */
 +		};
 +
 +		type = g_type_register_static (
 +			G_TYPE_OBJECT, "EMFormat", &type_info, 0);
 +	}
 +
 +	return type;
 +}
 +
 +/**
 + * em_format_class_add_handler:
 + * @emfc: EMFormatClass
 + * @info: Callback information.
 + *
 + * Add a mime type handler to this class.  This is only used by
 + * implementing classes.  The @info.old pointer will automatically be
 + * setup to point to the old hanlder if one was already set.  This can
 + * be used for overrides a fallback.
 + *
 + * When a mime type described by @info is encountered, the callback will
 + * be invoked.  Note that @info may be extended by sub-classes if
 + * they require additional context information.
 + *
 + * Use a mime type of "foo/ *" to insert a fallback handler for type "foo".
 + **/
 +void
 +em_format_class_add_handler(EMFormatClass *emfc, EMFormatHandler *info)
 +{
 +	d(printf("adding format handler to '%s' '%s'\n", 	g_type_name_from_class((GTypeClass *)emfc), info->mime_type));
 +	info->old = g_hash_table_lookup(emfc->type_handlers, info->mime_type);
- 	g_hash_table_insert(emfc->type_handlers, info->mime_type, info);
++	g_hash_table_insert(emfc->type_handlers, (gpointer) info->mime_type, info);
 +}
 +
 +struct _class_handlers {
 +	EMFormatClass *old;
 +	EMFormatClass *new;
 +};
 +static void
 +merge_missing (gpointer key, gpointer value, gpointer userdata)
 +{
 +	struct _class_handlers *classes = (struct _class_handlers *) userdata;
 +	EMFormatHandler *info, *oldinfo;
 +
 +	oldinfo = (EMFormatHandler *) value;
 +	info = g_hash_table_lookup (classes->new->type_handlers, key);
 +	if (!info) {
 +		/* Might be from a plugin */
 +		g_hash_table_insert (classes->new->type_handlers, key, value);
 +	}
 +
 +}
 +
 +void
 +em_format_merge_handler(EMFormat *new, EMFormat *old)
 +{
 +	EMFormatClass *oldc = (EMFormatClass *)G_OBJECT_GET_CLASS(old);
 +	EMFormatClass *newc = (EMFormatClass *)G_OBJECT_GET_CLASS(new);
 +	struct _class_handlers fclasses;
 +
 +	fclasses.old = oldc;
 +	fclasses.new = newc;
 +
 +	g_hash_table_foreach (oldc->type_handlers, merge_missing, &fclasses);
 +
 +}
 +
 +/**
 + * em_format_class_remove_handler:
 + * @emfc:
 + * @info:
 + *
 + * Remove a handler.  @info must be a value which was previously
 + * added.
 + **/
 +void
 +em_format_class_remove_handler(EMFormatClass *emfc, EMFormatHandler *info)
 +{
 +	EMFormatHandler *current;
 +
 +	/* TODO: thread issues? */
 +
 +	current = g_hash_table_lookup(emfc->type_handlers, info->mime_type);
 +	if (current == info) {
 +		current = info->old;
 +		if (current)
- 			g_hash_table_insert(emfc->type_handlers, current->mime_type, current);
++			g_hash_table_insert(emfc->type_handlers, (gpointer) current->mime_type, current);
 +		else
 +			g_hash_table_remove(emfc->type_handlers, info->mime_type);
 +	} else {
 +		while (current && current->old != info)
 +			current = current->old;
 +		g_return_if_fail(current != NULL);
 +		current->old = info->old;
 +	}
 +}
 +
 +const EMFormatHandler *
 +em_format_find_handler (EMFormat *emf,
 +                        const gchar *mime_type)
 +{
 +	EMFormatClass *class;
 +
 +	g_return_val_if_fail (EM_IS_FORMAT (emf), NULL);
 +	g_return_val_if_fail (mime_type != NULL, NULL);
 +
 +	class = EM_FORMAT_GET_CLASS (emf);
 +	g_return_val_if_fail (class->find_handler != NULL, NULL);
 +	return class->find_handler (emf, mime_type);
 +}
 +
 +/**
 + * em_format_find_handler:
 + * @emf:
 + * @mime_type:
 + *
 + * Find a format handler by @mime_type.
 + *
 + * Return value: NULL if no handler is available.
 + **/
 +static const EMFormatHandler *
 +emf_find_handler(EMFormat *emf, const char *mime_type)
 +{
 +	EMFormatClass *emfc = (EMFormatClass *)G_OBJECT_GET_CLASS(emf);
 +
 +	return g_hash_table_lookup(emfc->type_handlers, mime_type);
 +}
 +
 +/**
 + * em_format_fallback_handler:
 + * @emf:
 + * @mime_type:
 + *
 + * Try to find a format handler based on the major type of the @mime_type.
 + *
 + * The subtype is replaced with "*" and a lookup performed.
 + *
 + * Return value:
 + **/
 +const EMFormatHandler *
 +em_format_fallback_handler(EMFormat *emf, const char *mime_type)
 +{
 +	char *mime, *s;
 +
 +	s = strchr(mime_type, '/');
 +	if (s == NULL)
 +		mime = (char *)mime_type;
 +	else {
 +		size_t len = (s-mime_type)+1;
 +
 +		mime = alloca(len+2);
 +		strncpy(mime, mime_type, len);
 +		strcpy(mime+len, "*");
 +	}
 +
 +	return em_format_find_handler(emf, mime);
 +}
 +
 +/**
 + * em_format_add_puri:
 + * @emf:
 + * @size:
 + * @cid: Override the autogenerated content id.
 + * @part:
 + * @func:
 + *
 + * Add a pending-uri handler.  When formatting parts that reference
 + * other parts, a pending-uri (PURI) can be used to track the reference.
 + *
 + * @size is used to allocate the structure, so that it can be directly
 + * subclassed by implementors.
 + *
 + * @cid can be used to override the key used to retreive the PURI, if NULL,
 + * then the content-location and the content-id of the @part are stored
 + * as lookup keys for the part.
 + *
 + * FIXME: This may need a free callback.
 + *
 + * Return value: A new PURI, with a referenced copy of @part, and the cid
 + * always set.  The uri will be set if one is available.  Clashes
 + * are resolved by forgetting the old PURI in the global index.
 + **/
 +EMFormatPURI *
 +em_format_add_puri(EMFormat *emf, size_t size, const char *cid, CamelMimePart *part, EMFormatPURIFunc func)
 +{
 +	EMFormatPURI *puri;
 +	const char *tmp;
 +
 +	d(printf("adding puri for part: %s\n", emf->part_id->str));
 +
 +	if (size < sizeof(*puri)) {
 +		g_warning (
 +			"size (%" G_GSIZE_FORMAT
 +			") less than size of puri\n", size);
 +		size = sizeof (*puri);
 +	}
 +
 +	puri = g_malloc0(size);
 +
 +	puri->format = emf;
 +	puri->func = func;
 +	puri->use_count = 0;
 +	puri->cid = g_strdup(cid);
 +	puri->part_id = g_strdup(emf->part_id->str);
 +
 +	if (part) {
 +		camel_object_ref(part);
 +		puri->part = part;
 +	}
 +
 +	if (part != NULL && cid == NULL) {
 +		tmp = camel_mime_part_get_content_id(part);
 +		if (tmp)
 +			puri->cid = g_strdup_printf("cid:%s", tmp);
 +		else
 +			puri->cid = g_strdup_printf("em-no-cid:%s", emf->part_id->str);
 +
 +		d(printf("built cid '%s'\n", puri->cid));
 +
 +		/* not quite same as old behaviour, it also put in the relative uri and a fallback for no parent uri */
 +		tmp = camel_mime_part_get_content_location(part);
 +		puri->uri = NULL;
 +		if (tmp == NULL) {
 +			/* no location, don't set a uri at all, html parts do this themselves */
 +		} else {
 +			if (strchr(tmp, ':') == NULL && emf->base != NULL) {
 +				CamelURL *uri;
 +
 +				uri = camel_url_new_with_base(emf->base, tmp);
 +				puri->uri = camel_url_to_string(uri, 0);
 +				camel_url_free(uri);
 +			} else {
 +				puri->uri = g_strdup(tmp);
 +			}
 +		}
 +	}
 +
 +	g_return_val_if_fail (puri->cid != NULL, NULL);
 +	g_return_val_if_fail (emf->pending_uri_level != NULL, NULL);
 +	g_return_val_if_fail (emf->pending_uri_table != NULL, NULL);
 +
 +	e_dlist_addtail(&emf->pending_uri_level->uri_list, (EDListNode *)puri);
 +
 +	if (puri->uri)
 +		g_hash_table_insert(emf->pending_uri_table, puri->uri, puri);
 +	g_hash_table_insert(emf->pending_uri_table, puri->cid, puri);
 +
 +	return puri;
 +}
 +
 +/**
 + * em_format_push_level:
 + * @emf:
 + *
 + * This is used to build a heirarchy of visible PURI objects based on
 + * the structure of the message.  Used by multipart/alternative formatter.
 + *
 + * FIXME: This could probably also take a uri so it can automaticall update
 + * the base location.
 + **/
 +void
 +em_format_push_level(EMFormat *emf)
 +{
 +	struct _EMFormatPURITree *purilist;
 +
 +	d(printf("em_format_push_level\n"));
 +	purilist = g_malloc0(sizeof(*purilist));
 +	e_dlist_init(&purilist->children);
 +	e_dlist_init(&purilist->uri_list);
 +	purilist->parent = emf->pending_uri_level;
 +	if (emf->pending_uri_tree == NULL) {
 +		emf->pending_uri_tree = purilist;
 +	} else {
 +		e_dlist_addtail(&emf->pending_uri_level->children, (EDListNode *)purilist);
 +	}
 +	emf->pending_uri_level = purilist;
 +}
 +
 +/**
 + * em_format_pull_level:
 + * @emf:
 + *
 + * Drop a level of visibility back to the parent.  Note that
 + * no PURI values are actually freed.
 + **/
 +void
 +em_format_pull_level(EMFormat *emf)
 +{
 +	d(printf("em_format_pull_level\n"));
 +	emf->pending_uri_level = emf->pending_uri_level->parent;
 +}
 +
 +/**
 + * em_format_find_visible_puri:
 + * @emf:
 + * @uri:
 + *
 + * Search for a PURI based on the visibility defined by :push_level()
 + * and :pull_level().
 + *
 + * Return value:
 + **/
 +EMFormatPURI *
 +em_format_find_visible_puri(EMFormat *emf, const char *uri)
 +{
 +	EMFormatPURI *pw;
 +	struct _EMFormatPURITree *ptree;
 +
 +	d(printf("checking for visible uri '%s'\n", uri));
 +
 +	ptree = emf->pending_uri_level;
 +	while (ptree) {
 +		pw = (EMFormatPURI *)ptree->uri_list.head;
 +		while (pw->next) {
 +			d(printf(" pw->uri = '%s' pw->cid = '%s\n", pw->uri?pw->uri:"", pw->cid));
 +			if ((pw->uri && !strcmp(pw->uri, uri)) || !strcmp(pw->cid, uri))
 +				return pw;
 +			pw = pw->next;
 +		}
 +		ptree = ptree->parent;
 +	}
 +
 +	return NULL;
 +}
 +
 +/**
 + * em_format_find_puri:
 + * @emf:
 + * @uri:
 + *
 + * Search for a PURI based on a uri.  Both the content-id
 + * and content-location are checked.
 + *
 + * Return value:
 + **/
 +EMFormatPURI *
 +
 +em_format_find_puri(EMFormat *emf, const char *uri)
 +{
 +	return g_hash_table_lookup(emf->pending_uri_table, uri);
 +}
 +
 +static void
 +emf_clear_puri_node(struct _EMFormatPURITree *node)
 +{
 +	{
 +		EMFormatPURI *pw, *pn;
 +
 +		/* clear puri's at this level */
 +		pw = (EMFormatPURI *)node->uri_list.head;
 +		pn = pw->next;
 +		while (pn) {
 +			d(printf ("freeing pw %p format:%p\n", pw, pw->format));
 +			if (pw->free)
 +				pw->free(pw);
 +			g_free(pw->uri);
 +			g_free(pw->cid);
 +			g_free(pw->part_id);
 +			if (pw->part)
 +				camel_object_unref(pw->part);
 +			g_free(pw);
 +			pw = pn;
 +			pn = pn->next;
 +		}
 +	}
 +
 +	{
 +		struct _EMFormatPURITree *cw, *cn;
 +
 +		/* clear child nodes */
 +		cw = (struct _EMFormatPURITree *)node->children.head;
 +		cn = cw->next;
 +		while (cn) {
 +			emf_clear_puri_node(cw);
 +			cw = cn;
 +			cn = cn->next;
 +		}
 +	}
 +
 +	g_free(node);
 +}
 +
 +/**
 + * em_format_clear_puri_tree:
 + * @emf:
 + *
 + * For use by implementors to clear out the message structure
 + * data.
 + **/
 +void
 +em_format_clear_puri_tree(EMFormat *emf)
 +{
 +	d(printf("clearing pending uri's\n"));
 +
 +	if (emf->pending_uri_table) {
 +		g_hash_table_destroy(emf->pending_uri_table);
 +		emf_clear_puri_node(emf->pending_uri_tree);
 +		emf->pending_uri_level = NULL;
 +		emf->pending_uri_tree = NULL;
 +	}
 +	emf->pending_uri_table = g_hash_table_new(g_str_hash, g_str_equal);
 +	em_format_push_level(emf);
 +}
 +
 +/* use mime_type == NULL  to force showing as application/octet-stream */
 +void
 +em_format_part_as(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const char *mime_type)
 +{
 +	const EMFormatHandler *handle = NULL;
 +	const char *snoop_save = emf->snoop_mime_type, *tmp;
 +	CamelURL *base_save = emf->base, *base = NULL;
 +	char *basestr = NULL;
 +
 +	d(printf("format_part_as()\n"));
 +
 +	emf->snoop_mime_type = NULL;
 +
 +	/* RFC 2110, we keep track of content-base, and absolute content-location headers
 +	   This is actually only required for html, but, *shrug* */
 +	tmp = camel_medium_get_header((CamelMedium *)part, "Content-Base");
 +	if (tmp == NULL) {
 +		tmp = camel_mime_part_get_content_location(part);
 +		if (tmp && strchr(tmp, ':') == NULL)
 +			tmp = NULL;
 +	} else {
 +		tmp = basestr = camel_header_location_decode(tmp);
 +	}
 +	d(printf("content-base is '%s'\n", tmp?tmp:"<unset>"));
 +	if (tmp
 +	    && (base = camel_url_new(tmp, NULL))) {
 +		emf->base = base;
 +		d(printf("Setting content base '%s'\n", tmp));
 +	}
 +	g_free(basestr);
 +
 +	if (mime_type != NULL) {
 +		if (g_ascii_strcasecmp(mime_type, "application/octet-stream") == 0) {
 +			emf->snoop_mime_type = mime_type = em_format_snoop_type(part);
 +			if (mime_type == NULL)
 +				mime_type = "application/octet-stream";
 +		}
 +
 +		handle = em_format_find_handler(emf, mime_type);
 +		if (handle == NULL)
 +			handle = em_format_fallback_handler(emf, mime_type);
 +
 +		if (handle != NULL
 +		    && !em_format_is_attachment(emf, part)) {
 +			d(printf("running handler for type '%s'\n", mime_type));
 +			handle->handler(emf, stream, part, handle);
 +			goto finish;
 +		}
 +		d(printf("this type is an attachment? '%s'\n", mime_type));
 +	} else {
 +		mime_type = "application/octet-stream";
 +	}
 +
 +	((EMFormatClass *)G_OBJECT_GET_CLASS(emf))->format_attachment(emf, stream, part, mime_type, handle);
 +finish:
 +	emf->base = base_save;
 +	emf->snoop_mime_type = snoop_save;
 +
 +	if (base)
 +		camel_url_free(base);
 +}
 +
 +void
 +em_format_part(EMFormat *emf, CamelStream *stream, CamelMimePart *part)
 +{
 +	char *mime_type;
 +	CamelDataWrapper *dw;
 +
 +	dw = camel_medium_get_content_object((CamelMedium *)part);
 +	mime_type = camel_data_wrapper_get_mime_type(dw);
 +	if (mime_type) {
 +		camel_strdown(mime_type);
 +		em_format_part_as(emf, stream, part, mime_type);
 +		g_free(mime_type);
 +	} else
 +		em_format_part_as(emf, stream, part, "text/plain");
 +}
 +
 +static void
 +emf_clone_inlines(void *key, void *val, void *data)
 +{
 +	struct _EMFormatCache *emfc = val, *new;
 +
 +	new = emf_insert_cache((EMFormat *)data, emfc->partid);
 +	new->state = emfc->state;
 +	if (emfc->valid)
 +		new->valid = camel_cipher_validity_clone(emfc->valid);
 +	if (emfc->secured)
 +		camel_object_ref((new->secured = emfc->secured));
 +}
 +
 +static void
 +emf_format_clone(EMFormat *emf, CamelFolder *folder, const char *uid, CamelMimeMessage *msg, EMFormat *emfsource)
 +{
 +	em_format_clear_puri_tree(emf);
 +
 +	if (emf != emfsource) {
 +		g_hash_table_remove_all(emf->inline_table);
 +		if (emfsource) {
 +			struct _EMFormatHeader *h;
 +
 +			/* We clone the current state here */
 +			g_hash_table_foreach(emfsource->inline_table, emf_clone_inlines, emf);
 +			emf->mode = emfsource->mode;
 +			g_free(emf->charset);
 +			emf->charset = g_strdup(emfsource->charset);
 +			g_free (emf->default_charset);
 +			emf->default_charset = g_strdup (emfsource->default_charset);
 +
 +			em_format_clear_headers(emf);
 +			for (h = (struct _EMFormatHeader *)emfsource->header_list.head; h->next; h = h->next)
 +				em_format_add_header(emf, h->name, h->flags);
 +		}
 +	}
 +
 +	/* what a mess */
 +	if (folder != emf->folder) {
 +		if (emf->folder)
 +			camel_object_unref(emf->folder);
 +		if (folder)
 +			camel_object_ref(folder);
 +		emf->folder = folder;
 +	}
 +
 +	if (uid != emf->uid) {
 +		g_free(emf->uid);
 +		emf->uid = g_strdup(uid);
 +	}
 +
 +	if (msg != emf->message) {
 +		if (emf->message)
 +			camel_object_unref(emf->message);
 +		if (msg)
 +			camel_object_ref(msg);
 +		emf->message = msg;
 +	}
 +
 +	g_string_truncate(emf->part_id, 0);
 +	if (folder != NULL)
 +		/* TODO build some string based on the folder name/location? */
 +		g_string_append_printf(emf->part_id, ".%p", (gpointer) folder);
 +	if (uid != NULL)
 +		g_string_append_printf(emf->part_id, ".%s", uid);
 +}
 +
 +static void
 +emf_format_secure(EMFormat *emf, CamelStream *stream, CamelMimePart *part, CamelCipherValidity *valid)
 +{
 +	CamelCipherValidity *save = emf->valid_parent;
 +	int len;
 +
 +	/* Note that this also requires support from higher up in the class chain
 +	    - validity needs to be cleared when you start output
 +	    - also needs to be cleared (but saved) whenever you start a new message. */
 +
 +	if (emf->valid == NULL) {
 +		emf->valid = valid;
 +	} else {
 +		camel_dlist_addtail(&emf->valid_parent->children, (CamelDListNode *)valid);
 +		camel_cipher_validity_envelope(emf->valid_parent, valid);
 +	}
 +
 +	emf->valid_parent = valid;
 +
 +	len = emf->part_id->len;
 +	g_string_append_printf(emf->part_id, ".secured");
 +	em_format_part(emf, stream, part);
 +	g_string_truncate(emf->part_id, len);
 +
 +	emf->valid_parent = save;
 +}
 +
 +static gboolean
 +emf_busy(EMFormat *emf)
 +{
 +	return FALSE;
 +}
 +
 +/**
 + * em_format_format_clone:
 + * @emf: an #EMFormat
 + * @folder: a #CamelFolder or %NULL
 + * @uid: Message UID or %NULL
 + * @msg: a #CamelMimeMessage or %NULL
 + * @emfsource: Used as a basis for user-altered layout, e.g. inline viewed
 + * attachments.
 + *
 + * Format a message @msg.  If @emfsource is non NULL, then the status of
 + * inlined expansion and so forth is copied direction from @emfsource.
 + *
 + * By passing the same value for @emf and @emfsource, you can perform
 + * a display refresh, or it can be used to generate an identical layout,
 + * e.g. to print what the user has shown inline.
 + **/
 +void
 +em_format_format_clone (EMFormat *emf,
 +                        CamelFolder *folder,
 +                        const gchar *uid,
 +                        CamelMimeMessage *message,
 +                        EMFormat *source)
 +{
 +	EMFormatClass *class;
 +
 +	g_return_if_fail (EM_IS_FORMAT (emf));
 +	g_return_if_fail (folder == NULL || CAMEL_IS_FOLDER (folder));
 +	g_return_if_fail (message == NULL || CAMEL_IS_MIME_MESSAGE (message));
 +	g_return_if_fail (source == NULL || EM_IS_FORMAT (source));
 +
 +	class = EM_FORMAT_GET_CLASS (emf);
 +	g_return_if_fail (class->format_clone != NULL);
 +	class->format_clone (emf, folder, uid, message, source);
 +}
 +
 +void
 +em_format_format (EMFormat *emf,
 +                  CamelFolder *folder,
 +                  const gchar *uid,
 +                  CamelMimeMessage *message)
 +{
 +	/* em_format_format_clone() will check the arguments. */
 +	em_format_format_clone (emf, folder, uid, message, NULL);
 +}
 +
 +void
 +em_format_redraw (EMFormat *emf)
 +{
 +	g_return_if_fail (EM_IS_FORMAT (emf));
 +
 +	em_format_format_clone (
 +		emf, emf->folder, emf->uid, emf->message, emf);
 +}
 +
 +/**
 + * em_format_set_mode:
 + * @emf:
 + * @type:
 + *
 + * Set display mode, EM_FORMAT_SOURCE, EM_FORMAT_ALLHEADERS, or
 + * EM_FORMAT_NORMAL.
 + **/
 +void
 +em_format_set_mode(EMFormat *emf, em_format_mode_t type)
 +{
 +	if (emf->mode == type)
 +		return;
 +
 +	emf->mode = type;
 +
 +	/* force redraw if type changed afterwards */
 +	if (emf->message)
 +		em_format_redraw(emf);
 +}
 +
 +/**
 + * em_format_set_charset:
 + * @emf:
 + * @charset:
 + *
 + * set override charset on formatter.  message will be redisplayed if
 + * required.
 + **/
 +void
 +em_format_set_charset(EMFormat *emf, const char *charset)
 +{
 +	if ((emf->charset && charset && g_ascii_strcasecmp(emf->charset, charset) == 0)
 +	    || (emf->charset == NULL && charset == NULL)
 +	    || (emf->charset == charset))
 +		return;
 +
 +	g_free(emf->charset);
 +	emf->charset = g_strdup(charset);
 +
 +	if (emf->message)
 +		em_format_redraw(emf);
 +}
 +
 +/**
 + * em_format_set_default_charset:
 + * @emf:
 + * @charset:
 + *
 + * Set the fallback, default system charset to use when no other charsets
 + * are present.  Message will be redisplayed if required (and sometimes redisplayed
 + * when it isn't).
 + **/
 +void
 +em_format_set_default_charset(EMFormat *emf, const char *charset)
 +{
 +	if ((emf->default_charset && charset && g_ascii_strcasecmp(emf->default_charset, charset) == 0)
 +	    || (emf->default_charset == NULL && charset == NULL)
 +	    || (emf->default_charset == charset))
 +		return;
 +
 +	g_free(emf->default_charset);
 +	emf->default_charset = g_strdup(charset);
 +
 +	if (emf->message && emf->charset == NULL)
 +		em_format_redraw(emf);
 +}
 +
 +/**
 + * em_format_clear_headers:
 + * @emf:
 + *
 + * Clear the list of headers to be displayed.  This will force all headers to
 + * be shown.
 + **/
 +void
 +em_format_clear_headers(EMFormat *emf)
 +{
 +	EMFormatHeader *eh;
 +
 +	while ((eh = (EMFormatHeader *)e_dlist_remhead(&emf->header_list)))
 +		g_free(eh);
 +}
 +
 +/* note: also copied in em-mailer-prefs.c */
 +static const struct {
 +	const char *name;
 +	guint32 flags;
 +} default_headers[] = {
 +	{ N_("From"), EM_FORMAT_HEADER_BOLD },
 +	{ N_("Reply-To"), EM_FORMAT_HEADER_BOLD },
 +	{ N_("To"), EM_FORMAT_HEADER_BOLD },
 +	{ N_("Cc"), EM_FORMAT_HEADER_BOLD },
 +	{ N_("Bcc"), EM_FORMAT_HEADER_BOLD },
 +	{ N_("Subject"), EM_FORMAT_HEADER_BOLD },
 +	{ N_("Date"), EM_FORMAT_HEADER_BOLD },
 +	{ N_("Newsgroups"), EM_FORMAT_HEADER_BOLD },
 +	{ N_("Face"), 0 },
 +};
 +
 +/**
 + * em_format_default_headers:
 + * @emf:
 + *
 + * Set the headers to show to the default list.
 + *
 + * From, Reply-To, To, Cc, Bcc, Subject and Date.
 + **/
 +void
 +em_format_default_headers(EMFormat *emf)
 +{
 +	int i;
 +
 +	em_format_clear_headers(emf);
 +	for (i=0; i<sizeof(default_headers)/sizeof(default_headers[0]); i++)
 +		em_format_add_header(emf, default_headers[i].name, default_headers[i].flags);
 +}
 +
 +/**
 + * em_format_add_header:
 + * @emf:
 + * @name: The name of the header, as it will appear during output.
 + * @flags: EM_FORMAT_HEAD_* defines to control display attributes.
 + *
 + * Add a specific header to show.  If any headers are set, they will
 + * be displayed in the order set by this function.  Certain known
 + * headers included in this list will be shown using special
 + * formatting routines.
 + **/
 +void em_format_add_header(EMFormat *emf, const char *name, guint32 flags)
 +{
 +	EMFormatHeader *h;
 +
 +	h = g_malloc(sizeof(*h) + strlen(name));
 +	h->flags = flags;
 +	strcpy(h->name, name);
 +	e_dlist_addtail(&emf->header_list, (EDListNode *)h);
 +}
 +
 +/**
 + * em_format_is_attachment:
 + * @emf:
 + * @part: Part to check.
 + *
 + * Returns true if the part is an attachment.
 + *
 + * A part is not considered an attachment if it is a
 + * multipart, or a text part with no filename.  It is used
 + * to determine if an attachment header should be displayed for
 + * the part.
 + *
 + * Content-Disposition is not checked.
 + *
 + * Return value: TRUE/FALSE
 + **/
 +int em_format_is_attachment(EMFormat *emf, CamelMimePart *part)
 +{
 +	/*CamelContentType *ct = camel_mime_part_get_content_type(part);*/
 +	CamelDataWrapper *dw = camel_medium_get_content_object((CamelMedium *)part);
 +
 +	/*printf("checking is attachment %s/%s\n", ct->type, ct->subtype);*/
 +	return !(camel_content_type_is (dw->mime_type, "multipart", "*")
 +		 || camel_content_type_is(dw->mime_type, "application", "x-pkcs7-mime")
 +		 || camel_content_type_is(dw->mime_type, "application", "pkcs7-mime")
 +		 || camel_content_type_is(dw->mime_type, "application", "x-inlinepgp-signed")
 +		 || camel_content_type_is(dw->mime_type, "application", "x-inlinepgp-encrypted")
 +		 || camel_content_type_is(dw->mime_type, "x-evolution", "evolution-rss-feed")
 +		 || (camel_content_type_is (dw->mime_type, "text", "*")
 +		     && camel_mime_part_get_filename(part) == NULL));
 +}
 +
 +/**
 + * em_format_is_inline:
 + * @emf:
 + * @part:
 + * @partid: format->part_id part id of this part.
 + * @handle: handler for this part
 + *
 + * Returns true if the part should be displayed inline.  Any part with
 + * a Content-Disposition of inline, or if the @handle has a default
 + * inline set, will be shown inline.
 + *
 + * :set_inline() called on the same part will override any calculated
 + * value.
 + *
 + * Return value:
 + **/
 +int em_format_is_inline(EMFormat *emf, const char *partid, CamelMimePart *part, const EMFormatHandler *handle)
 +{
 +	struct _EMFormatCache *emfc;
 +	const char *tmp;
 +
 +	if (handle == NULL)
 +		return FALSE;
 +
 +	emfc = g_hash_table_lookup(emf->inline_table, partid);
 +	if (emfc && emfc->state != INLINE_UNSET)
 +		return emfc->state & 1;
 +
 +	/* some types need to override the disposition, e.g. application/x-pkcs7-mime */
 +	if (handle->flags & EM_FORMAT_HANDLER_INLINE_DISPOSITION)
 +		return TRUE;
 +
 +	tmp = camel_mime_part_get_disposition(part);
 +	if (tmp)
 +		return g_ascii_strcasecmp(tmp, "inline") == 0;
 +
 +	/* otherwise, use the default for this handler type */
 +	return (handle->flags & EM_FORMAT_HANDLER_INLINE) != 0;
 +}
 +
 +/**
 + * em_format_set_inline:
 + * @emf:
 + * @partid: id of part
 + * @state:
 + *
 + * Force the attachment @part to be expanded or hidden explictly to match
 + * @state.  This is used only to record the change for a redraw or
 + * cloned layout render and does not force a redraw.
 + **/
 +void em_format_set_inline(EMFormat *emf, const char *partid, int state)
 +{
 +	struct _EMFormatCache *emfc;
 +
 +	emfc = g_hash_table_lookup(emf->inline_table, partid);
 +	if (emfc == NULL) {
 +		emfc = emf_insert_cache(emf, partid);
 +	} else if (emfc->state != INLINE_UNSET && (emfc->state & 1) == state)
 +		return;
 +
 +	emfc->state = state?INLINE_ON:INLINE_OFF;
 +
 +	if (emf->message)
 +		em_format_redraw(emf);
 +}
 +
 +void
 +em_format_format_attachment (EMFormat *emf,
 +                             CamelStream *stream,
 +                             CamelMimePart *mime_part,
 +                             const gchar *mime_type,
 +                             const struct _EMFormatHandler *info)
 +{
 +	EMFormatClass *class;
 +
 +	g_return_if_fail (EM_IS_FORMAT (emf));
 +	g_return_if_fail (CAMEL_IS_STREAM (stream));
 +	g_return_if_fail (CAMEL_IS_MIME_PART (mime_part));
 +	g_return_if_fail (mime_type != NULL);
 +	g_return_if_fail (info != NULL);
 +
 +	class = EM_FORMAT_GET_CLASS (emf);
 +	g_return_if_fail (class->format_attachment != NULL);
 +	class->format_attachment (emf, stream, mime_part, mime_type, info);
 +}
 +
 +void
 +em_format_format_error (EMFormat *emf,
 +                        CamelStream *stream,
 +                        const gchar *format,
 +                        ...)
 +{
 +	EMFormatClass *class;
 +	gchar *errmsg;
 +	va_list ap;
 +
 +	g_return_if_fail (EM_IS_FORMAT (emf));
 +	g_return_if_fail (CAMEL_IS_STREAM (stream));
 +	g_return_if_fail (format != NULL);
 +
 +	class = EM_FORMAT_GET_CLASS (emf);
 +	g_return_if_fail (class->format_error != NULL);
 +
 +	va_start (ap, format);
 +	errmsg = g_strdup_vprintf (format, ap);
 +	class->format_error (emf, stream, errmsg);
 +	g_free (errmsg);
 +	va_end (ap);
 +}
 +
 +void
 +em_format_format_secure (EMFormat *emf,
 +                         CamelStream *stream,
 +                         CamelMimePart *mime_part,
 +                         CamelCipherValidity *valid)
 +{
 +	EMFormatClass *class;
 +
 +	g_return_if_fail (EM_IS_FORMAT (emf));
 +	g_return_if_fail (CAMEL_IS_STREAM (stream));
 +	g_return_if_fail (CAMEL_IS_MIME_PART (mime_part));
 +	g_return_if_fail (valid != NULL);
 +
 +	class = EM_FORMAT_GET_CLASS (emf);
 +	g_return_if_fail (class->format_secure != NULL);
 +	class->format_secure (emf, stream, mime_part, valid);
 +
 +	if (emf->valid_parent == NULL && emf->valid != NULL) {
 +		camel_cipher_validity_free (emf->valid);
 +		emf->valid = NULL;
 +	}
 +}
 +
 +void
 +em_format_format_source (EMFormat *emf,
 +                         CamelStream *stream,
 +                         CamelMimePart *mime_part)
 +{
 +	EMFormatClass *class;
 +
 +	g_return_if_fail (EM_IS_FORMAT (emf));
 +	g_return_if_fail (CAMEL_IS_STREAM (stream));
 +	g_return_if_fail (CAMEL_IS_MIME_PART (mime_part));
 +
 +	class = EM_FORMAT_GET_CLASS (emf);
 +	g_return_if_fail (class->format_source != NULL);
 +	class->format_source (emf, stream, mime_part);
 +}
 +
 +gboolean
 +em_format_busy (EMFormat *emf)
 +{
 +	EMFormatClass *class;
 +
 +	g_return_val_if_fail (EM_IS_FORMAT (emf), FALSE);
 +
 +	class = EM_FORMAT_GET_CLASS (emf);
 +	g_return_val_if_fail (class->busy != NULL, FALSE);
 +	return class->busy (emf);
 +}
 +
 +/* should this be virtual? */
 +void
 +em_format_format_content(EMFormat *emf, CamelStream *stream, CamelMimePart *part)
 +{
 +	CamelDataWrapper *dw = camel_medium_get_content_object((CamelMedium *)part);
 +
 +	if (camel_content_type_is (dw->mime_type, "text", "*"))
 +		em_format_format_text(emf, stream, (CamelDataWrapper *)part);
 +	else
 +		camel_data_wrapper_decode_to_stream(dw, stream);
 +}
 +
 +/**
 + * em_format_format_content:
 + * @emf:
 + * @stream: Where to write the converted text
 + * @part: Part whose container is to be formatted
 + *
 + * Decode/output a part's content to @stream.
 + **/
 +void
 +em_format_format_text(EMFormat *emf, CamelStream *stream, CamelDataWrapper *dw)
 +{
 +	CamelStreamFilter *filter_stream;
 +	CamelMimeFilterCharset *filter;
 +	const char *charset = NULL;
 +	CamelMimeFilterWindows *windows = NULL;
 +	CamelStream *mem_stream = NULL;
 +	size_t size;
 +	size_t max;
 +	GConfClient *gconf;
 +
 +	if (emf->charset) {
 +		charset = emf->charset;
 +	} else if (dw->mime_type
 +		   && (charset = camel_content_type_param (dw->mime_type, "charset"))
 +		   && g_ascii_strncasecmp(charset, "iso-8859-", 9) == 0) {
 +		CamelStream *null;
 +
 +		/* Since a few Windows mailers like to claim they sent
 +		 * out iso-8859-# encoded text when they really sent
 +		 * out windows-cp125#, do some simple sanity checking
 +		 * before we move on... */
 +
 +		null = camel_stream_null_new();
 +		filter_stream = camel_stream_filter_new_with_stream(null);
 +		camel_object_unref(null);
 +
 +		windows = (CamelMimeFilterWindows *)camel_mime_filter_windows_new(charset);
 +		camel_stream_filter_add(filter_stream, (CamelMimeFilter *)windows);
 +
 +		camel_data_wrapper_decode_to_stream(dw, (CamelStream *)filter_stream);
 +		camel_stream_flush((CamelStream *)filter_stream);
 +		camel_object_unref(filter_stream);
 +
 +		charset = camel_mime_filter_windows_real_charset (windows);
 +	} else if (charset == NULL) {
 +		charset = emf->default_charset;
 +	}
 +
 +	mem_stream = (CamelStream *)camel_stream_mem_new ();
 +	filter_stream = camel_stream_filter_new_with_stream(mem_stream);
 +
 +	if ((filter = camel_mime_filter_charset_new_convert(charset, "UTF-8"))) {
 +		camel_stream_filter_add(filter_stream, (CamelMimeFilter *) filter);
 +		camel_object_unref(filter);
 +	}
 +
 +	max = -1;
 +
 +	gconf = gconf_client_get_default ();
 +	if (gconf_client_get_bool (gconf, "/apps/evolution/mail/display/force_message_limit", NULL)) {
 +		max = gconf_client_get_int (gconf, "/apps/evolution/mail/display/message_text_part_limit", NULL);
 +		if (max == 0)
 +			max = -1;
 +	}
 +	g_object_unref (gconf);
 +
 +	size = camel_data_wrapper_decode_to_stream(emf->mode == EM_FORMAT_SOURCE ? (CamelDataWrapper *)dw: camel_medium_get_content_object((CamelMedium *)dw), (CamelStream *)filter_stream);
 +	camel_stream_flush((CamelStream *)filter_stream);
 +	camel_object_unref(filter_stream);
 +	camel_stream_reset (mem_stream);
 +
 +	if (max == -1 || size == -1 || size < (max * 1024) || emf->composer) {
 +		camel_stream_write_to_stream(mem_stream, (CamelStream *)stream);
 +		camel_stream_flush((CamelStream *)stream);
 +	} else {
 +		((EMFormatClass *)G_OBJECT_GET_CLASS(emf))->format_optional(emf, stream, (CamelMimePart *)dw, mem_stream);
 +	}
 +
 +	if (windows)
 +		camel_object_unref(windows);
 +}
 +
 +/**
 + * em_format_describe_part:
 + * @part:
 + * @mimetype:
 + *
 + * Generate a simple textual description of a part, @mime_type represents the
 + * the content.
 + *
 + * Return value:
 + **/
 +char *
 +em_format_describe_part(CamelMimePart *part, const char *mime_type)
 +{
 +	GString *stext;
 +	const char *filename, *description;
 +	char *content_type, *desc;
 +
 +	stext = g_string_new("");
 +	content_type = g_content_type_from_mime_type (mime_type);
 +	desc = g_content_type_get_description (content_type ? content_type : mime_type);
 +	g_free (content_type);
 +	g_string_append_printf (stext, _("%s attachment"), desc ? desc : mime_type);
 +	g_free (desc);
 +	if ((filename = camel_mime_part_get_filename (part)))
 +		g_string_append_printf(stext, " (%s)", filename);
 +	if ((description = camel_mime_part_get_description(part)) &&
 +		(*description != 0) &&
 +		!(filename && (strcmp(filename, description) == 0)))
 +		g_string_append_printf(stext, ", \"%s\"", description);
 +
 +	return g_string_free (stext, FALSE);
 +}
 +
 +/* ********************************************************************** */
 +
 +#ifdef ENABLE_SMIME
 +static void
 +emf_application_xpkcs7mime(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info)
 +{
 +	CamelCipherContext *context;
 +	CamelException *ex;
 +	CamelMimePart *opart;
 +	CamelCipherValidity *valid;
 +	struct _EMFormatCache *emfc;
 +
 +	/* should this perhaps run off a key of ".secured" ? */
 +	emfc = g_hash_table_lookup(emf->inline_table, emf->part_id->str);
 +	if (emfc && emfc->valid) {
 +		em_format_format_secure(emf, stream, emfc->secured, camel_cipher_validity_clone(emfc->valid));
 +		return;
 +	}
 +
 +	ex = camel_exception_new();
 +
 +	context = camel_smime_context_new(emf->session);
 +
 +	opart = camel_mime_part_new();
 +	valid = camel_cipher_decrypt(context, part, opart, ex);
 +	if (valid == NULL) {
 +		em_format_format_error(emf, stream, "%s", ex->desc?ex->desc:_("Could not parse S/MIME message: Unknown error"));
 +		em_format_part_as(emf, stream, part, NULL);
 +	} else {
 +		if (emfc == NULL)
 +			emfc = emf_insert_cache(emf, emf->part_id->str);
 +
 +		emfc->valid = camel_cipher_validity_clone(valid);
 +		camel_object_ref((emfc->secured = opart));
 +
 +		em_format_format_secure(emf, stream, opart, valid);
 +	}
 +
 +	camel_object_unref(opart);
 +	camel_object_unref(context);
 +	camel_exception_free(ex);
 +}
 +#endif
 +
 +/* RFC 1740 */
 +static void
 +emf_multipart_appledouble(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info)
 +{
 +	CamelMultipart *mp = (CamelMultipart *)camel_medium_get_content_object((CamelMedium *)part);
 +	CamelMimePart *mime_part;
 +	int len;
 +
 +	if (!CAMEL_IS_MULTIPART(mp)) {
 +		em_format_format_source(emf, stream, part);
 +		return;
 +	}
 +
 +	mime_part = camel_multipart_get_part(mp, 1);
 +	if (mime_part) {
 +		/* try the data fork for something useful, doubtful but who knows */
 +		len = emf->part_id->len;
 +		g_string_append_printf(emf->part_id, ".appledouble.1");
 +		em_format_part(emf, stream, mime_part);
 +		g_string_truncate(emf->part_id, len);
 +	} else
 +		em_format_format_source(emf, stream, part);
 +
 +}
 +
 +/* RFC ??? */
 +static void
 +emf_multipart_mixed(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info)
 +{
 +	CamelMultipart *mp = (CamelMultipart *)camel_medium_get_content_object((CamelMedium *)part);
 +	int i, nparts, len;
 +
 +	if (!CAMEL_IS_MULTIPART(mp)) {
 +		em_format_format_source(emf, stream, part);
 +		return;
 +	}
 +
 +	len = emf->part_id->len;
 +	nparts = camel_multipart_get_number(mp);
 +	for (i = 0; i < nparts; i++) {
 +		part = camel_multipart_get_part(mp, i);
 +		g_string_append_printf(emf->part_id, ".mixed.%d", i);
 +		em_format_part(emf, stream, part);
 +		g_string_truncate(emf->part_id, len);
 +	}
 +}
 +
 +/* RFC 1740 */
 +static void
 +emf_multipart_alternative(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info)
 +{
 +	CamelMultipart *mp = (CamelMultipart *)camel_medium_get_content_object((CamelMedium *)part);
 +	int i, nparts, bestid = 0;
 +	CamelMimePart *best = NULL;
 +
 +	if (!CAMEL_IS_MULTIPART(mp)) {
 +		em_format_format_source(emf, stream, part);
 +		return;
 +	}
 +
 +	/* as per rfc, find the last part we know how to display */
 +	nparts = camel_multipart_get_number(mp);
 +	for (i = 0; i < nparts; i++) {
 +		CamelContentType *type;
 +		char *mime_type;
 +
 +		/* is it correct to use the passed in *part here? */
 +		part = camel_multipart_get_part(mp, i);
 +
 +		if (!part)
 +			continue;
 +
 +		type = camel_mime_part_get_content_type (part);
 +		mime_type = camel_content_type_simple (type);
 +
 +		camel_strdown (mime_type);
 +
 +		/*if (want_plain && !strcmp (mime_type, "text/plain"))
 +		  return part;*/
 +
 +		if (em_format_find_handler(emf, mime_type)
 +		    || (best == NULL && em_format_fallback_handler(emf, mime_type))) {
 +			best = part;
 +			bestid = i;
 +		}
 +
 +		g_free(mime_type);
 +	}
 +
 +	if (best) {
 +		int len = emf->part_id->len;
 +
 +		g_string_append_printf(emf->part_id, ".alternative.%d", bestid);
 +		em_format_part(emf, stream, best);
 +		g_string_truncate(emf->part_id, len);
 +	} else
 +		emf_multipart_mixed(emf, stream, part, info);
 +}
 +
 +static void
 +emf_multipart_encrypted(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info)
 +{
 +	CamelCipherContext *context;
 +	CamelException *ex;
 +	const char *protocol;
 +	CamelMimePart *opart;
 +	CamelCipherValidity *valid;
 +	CamelMultipartEncrypted *mpe;
 +	struct _EMFormatCache *emfc;
 +
 +	/* should this perhaps run off a key of ".secured" ? */
 +	emfc = g_hash_table_lookup(emf->inline_table, emf->part_id->str);
 +	if (emfc && emfc->valid) {
 +		em_format_format_secure(emf, stream, emfc->secured, camel_cipher_validity_clone(emfc->valid));
 +		return;
 +	}
 +
 +	mpe = (CamelMultipartEncrypted*)camel_medium_get_content_object((CamelMedium *)part);
 +	if (!CAMEL_IS_MULTIPART_ENCRYPTED(mpe)) {
 +		em_format_format_error(emf, stream, _("Could not parse MIME message. Displaying as source."));
 +		em_format_format_source(emf, stream, part);
 +		return;
 +	}
 +
 +	/* Currently we only handle RFC2015-style PGP encryption. */
 +	protocol = camel_content_type_param(((CamelDataWrapper *)mpe)->mime_type, "protocol");
 +	if (!protocol || g_ascii_strcasecmp (protocol, "application/pgp-encrypted") != 0) {
 +		em_format_format_error(emf, stream, _("Unsupported encryption type for multipart/encrypted"));
 +		em_format_part_as(emf, stream, part, "multipart/mixed");
 +		return;
 +	}
 +
 +	ex = camel_exception_new();
 +	context = camel_gpg_context_new(emf->session);
 +	opart = camel_mime_part_new();
 +	valid = camel_cipher_decrypt(context, part, opart, ex);
 +	if (valid == NULL) {
 +		em_format_format_error(emf, stream, ex->desc?_("Could not parse PGP/MIME message"):_("Could not parse PGP/MIME message: Unknown error"));
 +		if (ex->desc)
 +			em_format_format_error(emf, stream, "%s", ex->desc);
 +		em_format_part_as(emf, stream, part, "multipart/mixed");
 +	} else {
 +		if (emfc == NULL)
 +			emfc = emf_insert_cache(emf, emf->part_id->str);
 +
 +		emfc->valid = camel_cipher_validity_clone(valid);
 +		camel_object_ref((emfc->secured = opart));
 +
 +		em_format_format_secure(emf, stream, opart, valid);
 +	}
 +
 +	/* TODO: Make sure when we finalize this part, it is zero'd out */
 +	camel_object_unref(opart);
 +	camel_object_unref(context);
 +	camel_exception_free(ex);
 +}
 +
 +static void
 +emf_write_related(EMFormat *emf, CamelStream *stream, EMFormatPURI *puri)
 +{
 +	em_format_format_content(emf, stream, puri->part);
 +	camel_stream_close(stream);
 +}
 +
 +/* RFC 2387 */
 +static void
 +emf_multipart_related(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info)
 +{
 +	CamelMultipart *mp = (CamelMultipart *)camel_medium_get_content_object((CamelMedium *)part);
 +	CamelMimePart *body_part, *display_part = NULL;
 +	CamelContentType *content_type;
 +	const char *start;
 +	int i, nparts, partidlen, displayid = 0;
 +	char *oldpartid;
 +	struct _EMFormatPURITree *ptree;
 +	EMFormatPURI *puri, *purin;
 +
 +	if (!CAMEL_IS_MULTIPART(mp)) {
 +		em_format_format_source(emf, stream, part);
 +		return;
 +	}
 +
 +	/* FIXME: put this stuff in a shared function */
 +	nparts = camel_multipart_get_number(mp);
 +	content_type = camel_mime_part_get_content_type(part);
 +	start = camel_content_type_param (content_type, "start");
 +	if (start && strlen(start)>2) {
 +		int len;
 +		const char *cid;
 +
 +		/* strip <>'s */
 +		len = strlen (start) - 2;
 +		start++;
 +
 +		for (i=0; i<nparts; i++) {
 +			body_part = camel_multipart_get_part(mp, i);
 +			cid = camel_mime_part_get_content_id(body_part);
 +
 +			if (cid && !strncmp(cid, start, len) && strlen(cid) == len) {
 +				display_part = body_part;
 +				displayid = i;
 +				break;
 +			}
 +		}
 +	} else {
 +		display_part = camel_multipart_get_part(mp, 0);
 +	}
 +
 +	if (display_part == NULL) {
 +		emf_multipart_mixed(emf, stream, part, info);
 +		return;
 +	}
 +
 +	em_format_push_level(emf);
 +
 +	oldpartid = g_strdup(emf->part_id->str);
 +	partidlen = emf->part_id->len;
 +
 +	/* queue up the parts for possible inclusion */
 +	for (i = 0; i < nparts; i++) {
 +		body_part = camel_multipart_get_part(mp, i);
 +		if (body_part != display_part) {
 +			/* set the partid since add_puri uses it */
 +			g_string_append_printf(emf->part_id, ".related.%d", i);
 +			puri = em_format_add_puri(emf, sizeof(EMFormatPURI), NULL, body_part, emf_write_related);
 +			g_string_truncate(emf->part_id, partidlen);
 +			d(printf(" part '%s' '%s' added\n", puri->uri?puri->uri:"", puri->cid));
 +		}
 +	}
 +
 +	g_string_append_printf(emf->part_id, ".related.%d", displayid);
 +	em_format_part(emf, stream, display_part);
 +	g_string_truncate(emf->part_id, partidlen);
 +	camel_stream_flush(stream);
 +
 +	ptree = emf->pending_uri_level;
 +	puri = (EMFormatPURI *)ptree->uri_list.head;
 +	purin = puri->next;
 +	while (purin) {
 +		if (puri->use_count == 0) {
 +			d(printf("part '%s' '%s' used '%d'\n", puri->uri?puri->uri:"", puri->cid, puri->use_count));
 +			if (puri->func == emf_write_related) {
 +				g_string_printf(emf->part_id, "%s", puri->part_id);
 +				em_format_part(emf, stream, puri->part);
- 			} else
++			} else {
 +				d(printf("unreferenced uri generated by format code: %s\n", puri->uri?puri->uri:puri->cid));
++			}
 +		}
 +		puri = purin;
 +		purin = purin->next;
 +	}
 +
 +	g_string_printf(emf->part_id, "%s", oldpartid);
 +	g_free(oldpartid);
 +
 +	em_format_pull_level(emf);
 +}
 +
 +static void
 +emf_multipart_signed(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info)
 +{
 +	CamelMimePart *cpart;
 +	CamelMultipartSigned *mps;
 +	CamelCipherContext *cipher = NULL;
 +	struct _EMFormatCache *emfc;
 +
 +	/* should this perhaps run off a key of ".secured" ? */
 +	emfc = g_hash_table_lookup(emf->inline_table, emf->part_id->str);
 +	if (emfc && emfc->valid) {
 +		em_format_format_secure(emf, stream, emfc->secured, camel_cipher_validity_clone(emfc->valid));
 +		return;
 +	}
 +
 +	mps = (CamelMultipartSigned *)camel_medium_get_content_object((CamelMedium *)part);
 +	if (!CAMEL_IS_MULTIPART_SIGNED(mps)
 +	    || (cpart = camel_multipart_get_part((CamelMultipart *)mps, CAMEL_MULTIPART_SIGNED_CONTENT)) == NULL) {
 +		em_format_format_error(emf, stream, _("Could not parse MIME message. Displaying as source."));
 +		em_format_format_source(emf, stream, part);
 +		return;
 +	}
 +
 +	/* FIXME: Should be done via a plugin interface */
 +	/* FIXME: duplicated in em-format-html-display.c */
 +	if (mps->protocol) {
 +#ifdef ENABLE_SMIME
 +		if (g_ascii_strcasecmp("application/x-pkcs7-signature", mps->protocol) == 0
 +		    || g_ascii_strcasecmp("application/pkcs7-signature", mps->protocol) == 0)
 +			cipher = camel_smime_context_new(emf->session);
 +		else
 +#endif
 +			if (g_ascii_strcasecmp("application/pgp-signature", mps->protocol) == 0)
 +				cipher = camel_gpg_context_new(emf->session);
 +	}
 +
 +	if (cipher == NULL) {
 +		em_format_format_error(emf, stream, _("Unsupported signature format"));
 +		em_format_part_as(emf, stream, part, "multipart/mixed");
 +	} else {
 +		CamelException *ex = camel_exception_new();
 +		CamelCipherValidity *valid;
 +
 +		valid = camel_cipher_verify(cipher, part, ex);
 +		if (valid == NULL) {
 +			em_format_format_error(emf, stream, ex->desc?_("Error verifying signature"):_("Unknown error verifying signature"));
 +			if (ex->desc)
 +				em_format_format_error(emf, stream, "%s", ex->desc);
 +			em_format_part_as(emf, stream, part, "multipart/mixed");
 +		} else {
 +			if (emfc == NULL)
 +				emfc = emf_insert_cache(emf, emf->part_id->str);
 +
 +			emfc->valid = camel_cipher_validity_clone(valid);
 +			camel_object_ref((emfc->secured = cpart));
 +
 +			em_format_format_secure(emf, stream, cpart, valid);
 +		}
 +
 +		camel_exception_free(ex);
 +		camel_object_unref(cipher);
 +	}
 +}
 +
 +static void
 +emf_message_rfc822(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info)
 +{
 +	CamelDataWrapper *dw = camel_medium_get_content_object((CamelMedium *)part);
 +	const EMFormatHandler *handle;
 +	int len;
 +
 +	if (!CAMEL_IS_MIME_MESSAGE(dw)) {
 +		em_format_format_source(emf, stream, part);
 +		return;
 +	}
 +
 +	len = emf->part_id->len;
 +	g_string_append_printf(emf->part_id, ".rfc822");
 +
 +	handle = em_format_find_handler(emf, "x-evolution/message/rfc822");
 +	if (handle)
 +		handle->handler(emf, stream, (CamelMimePart *)dw, handle);
 +
 +	g_string_truncate(emf->part_id, len);
 +}
 +
 +static void
 +emf_message_deliverystatus(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info)
 +{
 +	em_format_format_text(emf, stream, (CamelDataWrapper *)part);
 +}
 +
 +static void
 +emf_inlinepgp_signed(EMFormat *emf, CamelStream *stream, CamelMimePart *ipart, EMFormatHandler *info)
 +{
 +	CamelStreamFilter *filtered_stream;
 +	CamelMimeFilterPgp *pgp_filter;
 +	CamelContentType *content_type;
 +	CamelCipherContext *cipher;
 +	CamelCipherValidity *valid;
 +	CamelDataWrapper *dw;
 +	CamelMimePart *opart;
 +	CamelStream *ostream;
 +	CamelException *ex;
 +	char *type;
 +
 +	if (!ipart) {
 +		em_format_format_error(emf, stream, _("Unknown error verifying signature"));
 +		return;
 +	}
 +
 +	ex = camel_exception_new();
 +	cipher = camel_gpg_context_new(emf->session);
 +	/* Verify the signature of the message */
 +	valid = camel_cipher_verify(cipher, ipart, ex);
 +	if (!valid) {
 +		em_format_format_error(emf, stream, ex->desc?_("Error verifying signature"):_("Unknown error verifying signature"));
 +		if (ex->desc)
 +			em_format_format_error(emf, stream, "%s", ex->desc);
 +		em_format_format_source(emf, stream, ipart);
 +		/* I think this will loop: em_format_part_as(emf, stream, part, "text/plain"); */
 +		camel_exception_free(ex);
 +		camel_object_unref(cipher);
 +		return;
 +    	}
 +
 +	/* Setup output stream */
 +	ostream = camel_stream_mem_new();
 +	filtered_stream = camel_stream_filter_new_with_stream(ostream);
 +
 +	/* Add PGP header / footer filter */
 +	pgp_filter = (CamelMimeFilterPgp *)camel_mime_filter_pgp_new();
 +	camel_stream_filter_add(filtered_stream, (CamelMimeFilter *)pgp_filter);
 +	camel_object_unref(pgp_filter);
 +
 +	/* Pass through the filters that have been setup */
 +	dw = camel_medium_get_content_object((CamelMedium *)ipart);
 +	camel_data_wrapper_decode_to_stream(dw, (CamelStream *)filtered_stream);
 +	camel_stream_flush((CamelStream *)filtered_stream);
 +	camel_object_unref(filtered_stream);
 +
 +	/* Create a new text/plain MIME part containing the signed content preserving the original part's Content-Type params */
 +	content_type = camel_mime_part_get_content_type (ipart);
 +	type = camel_content_type_format (content_type);
 +	content_type = camel_content_type_decode (type);
 +	g_free (type);
 +
 +	g_free (content_type->type);
 +	content_type->type = g_strdup ("text");
 +	g_free (content_type->subtype);
 +	content_type->subtype = g_strdup ("plain");
 +	type = camel_content_type_format (content_type);
 +	camel_content_type_unref (content_type);
 +
 +	dw = camel_data_wrapper_new ();
 +	camel_data_wrapper_construct_from_stream (dw, ostream);
 +	camel_data_wrapper_set_mime_type (dw, type);
 +	g_free (type);
 +
 +	opart = camel_mime_part_new ();
 +	camel_medium_set_content_object ((CamelMedium *) opart, dw);
 +	camel_data_wrapper_set_mime_type_field ((CamelDataWrapper *) opart, dw->mime_type);
 +
 +	/* Pass it off to the real formatter */
 +	em_format_format_secure(emf, stream, opart, valid);
 +
 +	/* Clean Up */
 +	camel_object_unref(dw);
 +	camel_object_unref(opart);
 +	camel_object_unref(ostream);
 +	camel_object_unref(cipher);
 +	camel_exception_free(ex);
 +}
 +
 +static void
 +emf_inlinepgp_encrypted(EMFormat *emf, CamelStream *stream, CamelMimePart *ipart, EMFormatHandler *info)
 +{
 +	CamelCipherContext *cipher;
 +	CamelCipherValidity *valid;
 +	CamelException *ex;
 +	CamelMimePart *opart;
 +	CamelDataWrapper *dw;
 +	char *mime_type;
 +
 +	cipher = camel_gpg_context_new(emf->session);
 +	ex = camel_exception_new();
 +	opart = camel_mime_part_new();
 +	/* Decrypt the message */
 +	valid = camel_cipher_decrypt (cipher, ipart, opart, ex);
 +	if (!valid) {
 +		em_format_format_error(emf, stream, ex->desc?_("Could not parse PGP message"):_("Could not parse PGP message: Unknown error"));
 +		if (ex->desc)
 +			em_format_format_error(emf, stream, "%s", ex->desc);
 +		em_format_format_source(emf, stream, ipart);
 +		/* I think this will loop: em_format_part_as(emf, stream, part, "text/plain"); */
 +		camel_exception_free(ex);
 +		camel_object_unref(cipher);
 +		camel_object_unref(opart);
 +		return;
 +	}
 +
 +	dw = camel_medium_get_content_object ((CamelMedium *)opart);
 +	mime_type = camel_data_wrapper_get_mime_type (dw);
 +
 +	/* this ensures to show the 'opart' as inlined, if possible */
 +	if (mime_type && g_ascii_strcasecmp (mime_type, "application/octet-stream") == 0) {
 +		const char *snoop = em_format_snoop_type (opart);
 +
 +		if (snoop)
 +			camel_data_wrapper_set_mime_type (dw, snoop);
 +	}
 +
 +	g_free (mime_type);
 +
 +	/* Pass it off to the real formatter */
 +	em_format_format_secure(emf, stream, opart, valid);
 +
 +	/* Clean Up */
 +	camel_object_unref(opart);
 +	camel_object_unref (cipher);
 +	camel_exception_free (ex);
 +}
 +
 +static EMFormatHandler type_builtin_table[] = {
 +#ifdef ENABLE_SMIME
- 	{ "application/x-pkcs7-mime", (EMFormatFunc)emf_application_xpkcs7mime, EM_FORMAT_HANDLER_INLINE_DISPOSITION },
++	{ (gchar *) "application/x-pkcs7-mime", (EMFormatFunc)emf_application_xpkcs7mime, EM_FORMAT_HANDLER_INLINE_DISPOSITION },
 +#endif
- 	{ "multipart/alternative", emf_multipart_alternative },
- 	{ "multipart/appledouble", emf_multipart_appledouble },
- 	{ "multipart/encrypted", emf_multipart_encrypted },
- 	{ "multipart/mixed", emf_multipart_mixed },
- 	{ "multipart/signed", emf_multipart_signed },
- 	{ "multipart/related", emf_multipart_related },
- 	{ "multipart/*", emf_multipart_mixed },
- 	{ "message/rfc822", emf_message_rfc822, EM_FORMAT_HANDLER_INLINE },
- 	{ "message/news", emf_message_rfc822, EM_FORMAT_HANDLER_INLINE },
- 	{ "message/delivery-status", emf_message_deliverystatus },
- 	{ "message/*", emf_message_rfc822, EM_FORMAT_HANDLER_INLINE },
++	{ (gchar *) "multipart/alternative", emf_multipart_alternative },
++	{ (gchar *) "multipart/appledouble", emf_multipart_appledouble },
++	{ (gchar *) "multipart/encrypted", emf_multipart_encrypted },
++	{ (gchar *) "multipart/mixed", emf_multipart_mixed },
++	{ (gchar *) "multipart/signed", emf_multipart_signed },
++	{ (gchar *) "multipart/related", emf_multipart_related },
++	{ (gchar *) "multipart/*", emf_multipart_mixed },
++	{ (gchar *) "message/rfc822", emf_message_rfc822, EM_FORMAT_HANDLER_INLINE },
++	{ (gchar *) "message/news", emf_message_rfc822, EM_FORMAT_HANDLER_INLINE },
++	{ (gchar *) "message/delivery-status", emf_message_deliverystatus },
++	{ (gchar *) "message/*", emf_message_rfc822, EM_FORMAT_HANDLER_INLINE },
 +
 +	/* Insert brokenly-named parts here */
 +#ifdef ENABLE_SMIME
- 	{ "application/pkcs7-mime", (EMFormatFunc)emf_application_xpkcs7mime, EM_FORMAT_HANDLER_INLINE_DISPOSITION },
++	{ (gchar *) "application/pkcs7-mime", (EMFormatFunc)emf_application_xpkcs7mime, EM_FORMAT_HANDLER_INLINE_DISPOSITION },
 +#endif
 +
 +	/* internal types */
- 	{ "application/x-inlinepgp-signed", (EMFormatFunc)emf_inlinepgp_signed },
- 	{ "application/x-inlinepgp-encrypted", (EMFormatFunc)emf_inlinepgp_encrypted },
++	{ (gchar *) "application/x-inlinepgp-signed", (EMFormatFunc)emf_inlinepgp_signed },
++	{ (gchar *) "application/x-inlinepgp-encrypted", (EMFormatFunc)emf_inlinepgp_encrypted },
 +};
 +
 +static void
 +emf_builtin_init(EMFormatClass *class)
 +{
 +	int i;
 +
 +	for (i=0;i<sizeof(type_builtin_table)/sizeof(type_builtin_table[0]);i++)
 +		g_hash_table_insert(class->type_handlers, type_builtin_table[i].mime_type, &type_builtin_table[i]);
 +}
 +
 +/**
 + * em_format_snoop_type:
 + * @part:
 + *
 + * Tries to snoop the mime type of a part.
 + *
 + * Return value: NULL if unknown (more likely application/octet-stream).
 + **/
 +const char *
 +em_format_snoop_type (CamelMimePart *part)
 +{
 +	/* cache is here only to be able still return const char * */
 +	static GHashTable *types_cache = NULL;
 +
 +	const char *filename;
 +	char *name_type = NULL, *magic_type = NULL, *res, *tmp;
 +	CamelDataWrapper *dw;
 +
 +	filename = camel_mime_part_get_filename (part);
 +	if (filename != NULL)
 +		name_type = e_util_guess_mime_type (filename, FALSE);
 +
 +	dw = camel_medium_get_content_object((CamelMedium *)part);
 +	if (!camel_data_wrapper_is_offline(dw)) {
 +		CamelStreamMem *mem = (CamelStreamMem *)camel_stream_mem_new();
 +
 +		if (camel_data_wrapper_decode_to_stream(dw, (CamelStream *)mem) > 0) {
 +			char *ct = g_content_type_guess (filename, mem->buffer->data, mem->buffer->len, NULL);
 +
 +			if (ct)
 +				magic_type = g_content_type_get_mime_type (ct);
 +
 +			g_free (ct);
 +		}
 +		camel_object_unref(mem);
 +	}
 +
 +	d(printf("snooped part, magic_type '%s' name_type '%s'\n", magic_type, name_type));
 +
 +	/* If gvfs doesn't recognize the data by magic, but it
 +	 * contains English words, it will call it text/plain. If the
 +	 * filename-based check came up with something different, use
 +	 * that instead and if it returns "application/octet-stream"
 +	 * try to do better with the filename check.
 +	 */
 +
 +	if (magic_type) {
 +		if (name_type
 +		    && (!strcmp(magic_type, "text/plain")
 +			|| !strcmp(magic_type, "application/octet-stream")))
 +			res = name_type;
 +		else
 +			res = magic_type;
 +	} else
 +		res = name_type;
 +
 +
 +	if (res != name_type)
 +		g_free (name_type);
 +
 +	if (res != magic_type)
 +		g_free (magic_type);
 +
 +	if (!types_cache)
 +		types_cache = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, (GDestroyNotify) NULL);
 +
 +	if (res) {
 +		tmp = g_hash_table_lookup (types_cache, res);
 +		if (tmp) {
 +			g_free (res);
 +			res = tmp;
 +		} else {
 +			g_hash_table_insert (types_cache, res, res);
 +		}
 +	}
 +
 +	return res;
 +
 +	/* We used to load parts to check their type, we dont anymore,
 +	   see bug #11778 for some discussion */
 +}
diff --cc em-format/em-format.h
index 2817661,0000000..a9d9356
mode 100644,000000..100644
--- a/em-format/em-format.h
+++ b/em-format/em-format.h
@@@ -1,403 -1,0 +1,403 @@@
 +/*
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Authors:
 + *		Michael Zucchi <notzed ximian com>
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +/*
 +  Abstract class for formatting mime messages
 +*/
 +
 +#ifndef EM_FORMAT_H
 +#define EM_FORMAT_H
 +
 +#include <glib-object.h>
 +#include <camel/camel-url.h>
 +#include <camel/camel-folder.h>
 +#include <camel/camel-stream.h>
 +#include <camel/camel-session.h>
 +#include <camel/camel-mime-part.h>
 +#include <camel/camel-mime-message.h>
 +#include <camel/camel-cipher-context.h>
 +#include <libedataserver/e-msgport.h>
 +
 +/* Standard GObject macros */
 +#define EM_TYPE_FORMAT \
 +	(em_format_get_type ())
 +#define EM_FORMAT(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), EM_TYPE_FORMAT, EMFormat))
 +#define EM_FORMAT_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), EM_TYPE_FORMAT, EMFormatClass))
 +#define EM_IS_FORMAT(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), EM_TYPE_FORMAT))
 +#define EM_IS_FORMAT_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), EM_TYPE_FORMAT))
 +#define EM_FORMAT_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), EM_TYPE_FORMAT, EMFormatClass))
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _EMFormat EMFormat;
 +typedef struct _EMFormatClass EMFormatClass;
 +typedef struct _EMFormatPrivate EMFormatPrivate;
 +
 +typedef struct _EMFormatHandler EMFormatHandler;
 +typedef struct _EMFormatHeader EMFormatHeader;
 +
 +typedef void (*EMFormatFunc) (EMFormat *md, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info);
 +
 +typedef enum _em_format_mode_t {
 +	EM_FORMAT_NORMAL,
 +	EM_FORMAT_ALLHEADERS,
 +	EM_FORMAT_SOURCE
 +} em_format_mode_t;
 +
 +/**
 + * struct _EMFormatHandler - MIME type handler.
 + *
 + * @mime_type: Type this handler handles.
 + * @handler: The handler callback.
 + * @flags: Handling flags, see enum _em_format_handler_t.
 + * @old: The last handler set on this type.  Allows overrides to
 + * fallback to previous implementation.
 + *
 + **/
 +struct _EMFormatHandler {
- 	char *mime_type;
++	gchar *mime_type;
 +	EMFormatFunc handler;
 +	guint32 flags;
 +
 +	struct _EMFormatHandler *old;
 +};
 +
 +/**
 + * enum _em_format_handler_t - Format handler flags.
 + *
 + * @EM_FORMAT_HANDLER_INLINE: This type should be shown expanded
 + * inline by default.
 + * @EM_FORMAT_HANDLER_INLINE_DISPOSITION: This type should always be
 + * shown inline, despite what the Content-Disposition suggests.
 + *
 + **/
 +enum _em_format_handler_t {
 +	EM_FORMAT_HANDLER_INLINE = 1<<0,
 +	EM_FORMAT_HANDLER_INLINE_DISPOSITION = 1<<1
 +};
 +
 +
 +typedef struct _EMFormatPURI EMFormatPURI;
 +typedef void (*EMFormatPURIFunc)(EMFormat *md, CamelStream *stream, EMFormatPURI *puri);
 +
 +/**
 + * struct _EMFormatPURI - Pending URI object.
 + *
 + * @next: Double-linked list header.
 + * @prev: Double-linked list header.
 + * @free: May be set by allocator and will be called when no longer needed.
 + * @format:
 + * @uri: Calculated URI of the part, if the part has one in its
 + * Content-Location field.
 + * @cid: The RFC2046 Content-Id of the part.  If none is present, a unique value
 + * is calculated from @part_id.
 + * @part_id: A unique identifier for each part.
 + * @func: Callback for when the URI is requested.  The callback writes
 + * its data to the supplied stream.
 + * @part:
 + * @use_count:
 + *
 + * This is used for multipart/related, and other formatters which may
 + * need to include a reference to out-of-band data in the content
 + * stream.
 + *
 + * This object may be subclassed as a struct.
 + **/
 +struct _EMFormatPURI {
 +	struct _EMFormatPURI *next;
 +	struct _EMFormatPURI *prev;
 +
 +	void (*free)(struct _EMFormatPURI *p); /* optional callback for freeing user-fields */
 +	struct _EMFormat *format;
 +
 +	char *uri;		/* will be the location of the part, may be empty */
 +	char *cid;		/* will always be set, a fake one created if needed */
 +	char *part_id;		/* will always be set, emf->part_id->str for this part */
 +
 +	EMFormatPURIFunc func;
 +	CamelMimePart *part;
 +
 +	unsigned int use_count;	/* used by multipart/related to see if it was accessed */
 +};
 +
 +/**
 + * struct _EMFormatPURITree - Pending URI visibility tree.
 + *
 + * @next: Double-linked list header.
 + * @prev: Double-linked list header.
 + * @parent: Parent in tree.
 + * @uri_list: List of EMFormatPURI objects at this level.
 + * @children: Child nodes of EMFormatPURITree.
 + *
 + * This structure is used internally to form a visibility tree of
 + * parts in the current formatting stream.  This is to implement the
 + * part resolution rules for RFC2387 to implement multipart/related.
 + **/
 +struct _EMFormatPURITree {
 +	struct _EMFormatPURITree *next;
 +	struct _EMFormatPURITree *prev;
 +	struct _EMFormatPURITree *parent;
 +
 +	EDList uri_list;
 +	EDList children;
 +};
 +
 +struct _EMFormatHeader {
 +	struct _EMFormatHeader *next, *prev;
 +
 +	guint32 flags;		/* E_FORMAT_HEADER_* */
 +	char name[1];
 +};
 +
 +#define EM_FORMAT_HEADER_BOLD (1<<0)
 +#define EM_FORMAT_HEADER_LAST (1<<4) /* reserve 4 slots */
 +
 +/**
 + * struct _EMFormat - Mail formatter object.
 + *
 + * @parent:
 + * @priv:
 + * @message:
 + * @folder:
 + * @uid:
 + * @part_id:
 + * @header_list:
 + * @session:
 + * @base url:
 + * @snoop_mime_type:
 + * @valid:
 + * @valid_parent:
 + * @inline_table:
 + * @pending_uri_table:
 + * @pending_uri_tree:
 + * @pending_uri_level:
 + * @mode:
 + * @charset:
 + * @default_charset:
 + *
 + * Most fields are private or read-only.
 + *
 + * This is the base MIME formatter class.  It provides no formatting
 + * itself, but drives most of the basic types, including multipart / * types.
 + **/
 +struct _EMFormat {
 +	GObject parent;
 +
 +	EMFormatPrivate *priv;
 +
 +	CamelMimeMessage *message; /* the current message */
 +
 +	CamelFolder *folder;
 +	char *uid;
 +
 +	GString *part_id;	/* current part id prefix, for identifying parts directly */
 +
 +	EDList header_list;	/* if empty, then all */
 +
 +	CamelSession *session; /* session, used for authentication when required */
 +	CamelURL *base;	/* content-base header or absolute content-location, for any part */
 +
 +	const char *snoop_mime_type; /* if we snooped an application/octet-stream type, what we snooped */
 +
 +	/* for validity enveloping */
 +	CamelCipherValidity *valid;
 +	CamelCipherValidity *valid_parent;
 +
 +	/* for forcing inlining */
 +	GHashTable *inline_table;
 +
 +	/* global lookup table for message */
 +	GHashTable *pending_uri_table;
 +
 +	/* visibility tree, also stores every puri permanently */
 +	struct _EMFormatPURITree *pending_uri_tree;
 +	/* current level to search from */
 +	struct _EMFormatPURITree *pending_uri_level;
 +
 +	em_format_mode_t mode;	/* source/headers/etc */
 +	char *charset;		/* charset override */
 +	char *default_charset;	/* charset fallback */
 +	gboolean composer; /* Formatting from composer ?*/
 +	gboolean print;
 +};
 +
 +struct _EMFormatClass {
 +	GObjectClass parent_class;
 +
 +	GHashTable *type_handlers;
 +
 +	/* lookup handler, default falls back to hashtable above */
 +	const EMFormatHandler *(*find_handler)(EMFormat *, const char *mime_type);
 +
 +	/* start formatting a message */
 +	void (*format_clone)(EMFormat *, CamelFolder *, const char *uid, CamelMimeMessage *, EMFormat *);
 +
 +	/* some internel error/inconsistency */
 +	void (*format_error)(EMFormat *, CamelStream *, const char *msg);
 +
 +	/* use for external structured parts */
 +	void (*format_attachment)(EMFormat *, CamelStream *, CamelMimePart *, const char *mime_type, const struct _EMFormatHandler *info);
 +
 +	/* use for unparsable content */
 +	void (*format_source)(EMFormat *, CamelStream *, CamelMimePart *);
 +	/* for outputing secure(d) content */
 +	void (*format_secure)(EMFormat *, CamelStream *, CamelMimePart *, CamelCipherValidity *);
 +
 +	/* returns true if the formatter is still busy with pending stuff */
 +	gboolean (*busy)(EMFormat *);
 +
 +	/* Shows optional way to open messages  */
 +	void (*format_optional)(EMFormat *, CamelStream *, CamelMimePart *, CamelStream* );
 +
 +	/* signals */
 +	/* complete, alternative to polling busy, for asynchronous work */
 +	void (*complete)(EMFormat *);
 +};
 +
 +void		em_format_set_mode		(EMFormat *emf,
 +						 em_format_mode_t type);
 +void		em_format_set_charset		(EMFormat *emf,
 +						 const char *charset);
 +void		em_format_set_default_charset	(EMFormat *emf,
 +						 const char *charset);
 +
 +/* also indicates to show all headers */
 +void		em_format_clear_headers		(EMFormat *emf);
 +
 +void		em_format_default_headers	(EMFormat *emf);
 +void		em_format_add_header		(EMFormat *emf,
 +						 const gchar *name,
 +						 guint32 flags);
 +
 +/* FIXME: Need a 'clone' api to copy details about the current view (inlines etc)
 +   Or maybe it should live with sub-classes? */
 +
 +int		em_format_is_attachment		(EMFormat *emf,
 +						 CamelMimePart *part);
 +
 +int		em_format_is_inline		(EMFormat *emf,
 +						 const char *partid,
 +						 CamelMimePart *part,
 +						 const EMFormatHandler *handle);
 +void		em_format_set_inline		(EMFormat *emf,
 +						 const char *partid,
 +						 int state);
 +
 +char *		em_format_describe_part		(CamelMimePart *part,
 +						 const char *mime_type);
 +
 +/* for implementers */
 +GType		em_format_get_type		(void);
 +
 +void		em_format_class_add_handler	(EMFormatClass *emfc,
 +						 EMFormatHandler *info);
 +void		em_format_class_remove_handler	(EMFormatClass *emfc,
 +						 EMFormatHandler *info);
 +const EMFormatHandler *
 +		em_format_find_handler		(EMFormat *emf,
 +						 const gchar *mime_type);
 +const EMFormatHandler *
 +		em_format_fallback_handler	(EMFormat *emf,
 +						 const gchar *mime_type);
 +
 +/* puri is short for pending uri ... really */
 +EMFormatPURI *	em_format_add_puri		(EMFormat *emf,
 +						 size_t size,
 +						 const char *uri,
 +						 CamelMimePart *part,
 +						 EMFormatPURIFunc func);
 +EMFormatPURI *	em_format_find_visible_puri	(EMFormat *emf,
 +						 const char *uri);
 +EMFormatPURI *	em_format_find_puri		(EMFormat *emf,
 +						 const char *uri);
 +void		em_format_clear_puri_tree	(EMFormat *emf);
 +void		em_format_push_level		(EMFormat *emf);
 +void		em_format_pull_level		(EMFormat *emf);
 +
 +/* clones inline state/view and format, or use to redraw */
 +void		em_format_format_clone		(EMFormat *emf,
 +						 CamelFolder *folder,
 +						 const gchar *uid,
 +						 CamelMimeMessage *message,
 +						 EMFormat *source);
 +
 +/* formats a new message */
 +void		em_format_format		(EMFormat *emf,
 +						 CamelFolder *folder,
 +						 const gchar *uid,
 +						 CamelMimeMessage *message);
 +void		em_format_redraw		(EMFormat *emf);
 +void		em_format_format_attachment	(EMFormat *emf,
 +						 CamelStream *stream,
 +						 CamelMimePart *mime_part,
 +						 const gchar *mime_type,
 +						 const struct _EMFormatHandler *info);
 +void		em_format_format_error		(EMFormat *emf,
 +						 CamelStream *stream,
 +						 const gchar *format,
 +						 ...) G_GNUC_PRINTF (3, 4);
 +void		em_format_format_secure		(EMFormat *emf,
 +						 CamelStream *stream,
 +						 CamelMimePart *mime_part,
 +						 CamelCipherValidity *valid);
 +void		em_format_format_source		(EMFormat *emf,
 +						 CamelStream *stream,
 +						 CamelMimePart *mime_part);
 +
 +gboolean	em_format_busy			(EMFormat *emf);
 +
 +/* raw content only */
 +void		em_format_format_content	(EMFormat *emf,
 +						 CamelStream *stream,
 +						 CamelMimePart *part);
 +
 +/* raw content text parts - should this just be checked/done by above? */
 +void		em_format_format_text		(EMFormat *emf,
 +						 CamelStream *stream,
 +						 CamelDataWrapper *part);
 +
 +void		em_format_part_as		(EMFormat *emf,
 +						 CamelStream *stream,
 +						 CamelMimePart *part,
 +						 const gchar *mime_type);
 +void		em_format_part			(EMFormat *emf,
 +						 CamelStream *stream,
 +						 CamelMimePart *part);
 +void		em_format_merge_handler		(EMFormat *new,
 +						 EMFormat *old);
 +
 +const char * em_format_snoop_type (CamelMimePart *part);
 +
 +G_END_DECLS
 +
 +#endif /* EM_FORMAT_H */
diff --cc mail/Makefile.am
index 3df6164,e1b0da9..2544164
--- a/mail/Makefile.am
+++ b/mail/Makefile.am
@@@ -4,10 -4,8 +4,9 @@@ mailincludedir = $(privincludedir)/mai
  
  INCLUDES =						\
  	-I$(top_srcdir)/widgets				\
- 	-I$(top_srcdir)/widgets/e-text			\
  	-I$(top_srcdir)/widgets/misc			\
  	-I$(top_srcdir)					\
 +	-I$(top_srcdir)/em-format			\
  	-I$(top_srcdir)/mail				\
  	-I$(top_srcdir)/composer			\
  	-I$(top_builddir)/composer			\
diff --cc mail/e-mail-browser.c
index 152821b,0000000..e4013c5
mode 100644,000000..100644
--- a/mail/e-mail-browser.c
+++ b/mail/e-mail-browser.c
@@@ -1,751 -1,0 +1,751 @@@
 +/*
 + * e-mail-browser.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-mail-browser.h"
 +
 +#include <string.h>
 +#include <glib/gi18n.h>
 +#include <camel/camel-folder.h>
 +
 +#include "e-util/e-util.h"
 +#include "e-util/gconf-bridge.h"
 +#include "shell/e-shell.h"
 +
 +#include "mail/e-mail-reader.h"
 +#include "mail/e-mail-reader-utils.h"
 +#include "mail/e-mail-search-bar.h"
 +#include "mail/e-mail-shell-backend.h"
 +#include "mail/em-folder-tree-model.h"
 +#include "mail/em-format-html-display.h"
 +#include "mail/message-list.h"
 +
 +#define E_MAIL_BROWSER_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_MAIL_BROWSER, EMailBrowserPrivate))
 +
 +#define MAIL_BROWSER_GCONF_PREFIX "/apps/evolution/mail/mail_browser"
 +
 +struct _EMailBrowserPrivate {
 +	GtkUIManager *ui_manager;
 +	EShellBackend *shell_backend;
 +	GtkActionGroup *action_group;
 +	EMFormatHTMLDisplay *html_display;
 +
 +	GtkWidget *main_menu;
 +	GtkWidget *main_toolbar;
 +	GtkWidget *message_list;
 +	GtkWidget *search_bar;
 +	GtkWidget *statusbar;
 +
 +	guint show_deleted : 1;
 +};
 +
 +enum {
 +	PROP_0,
 +	PROP_SHELL_BACKEND,
 +	PROP_SHOW_DELETED,
 +	PROP_UI_MANAGER
 +};
 +
 +static gpointer parent_class;
 +
 +/* This is too trivial to put in a file.
 + * It gets merged with the EMailReader UI. */
 +static const gchar *ui =
 +"<ui>"
 +"  <menubar name='main-menu'>"
 +"    <menu action='file-menu'>"
 +"      <placeholder name='file-actions'/>"
 +"      <placeholder name='print-actions'/>"
 +"      <separator/>"
 +"      <menuitem action='close'/>"
 +"    </menu>"
 +"  </menubar>"
 +"</ui>";
 +
 +static void
 +action_close_cb (GtkAction *action,
 +                 EMailBrowser *browser)
 +{
 +	e_mail_browser_close (browser);
 +}
 +
 +static GtkActionEntry mail_browser_entries[] = {
 +
 +	{ "close",
 +	  GTK_STOCK_CLOSE,
 +	  NULL,
 +	  NULL,
 +	  N_("Close this window"),
 +	  G_CALLBACK (action_close_cb) },
 +
 +	/*** Menus ***/
 +
 +	{ "file-menu",
 +	  NULL,
 +	  N_("_File"),
 +	  NULL,
 +	  NULL,
 +	  NULL },
 +
 +	{ "edit-menu",
 +	  NULL,
 +	  N_("_Edit"),
 +	  NULL,
 +	  NULL,
 +	  NULL },
 +
 +	{ "view-menu",
 +	  NULL,
 +	  N_("_View"),
 +	  NULL,
 +	  NULL,
 +	  NULL }
 +};
 +
 +static void
 +mail_browser_menu_item_select_cb (EMailBrowser *browser,
 +                                  GtkWidget *menu_item)
 +{
 +	GtkAction *action;
 +	GtkStatusbar *statusbar;
 +	gchar *tooltip = NULL;
 +	guint context_id;
 +	gpointer data;
 +
 +	action = g_object_get_data (G_OBJECT (menu_item), "action");
 +	g_return_if_fail (GTK_IS_ACTION (action));
 +
 +	data = g_object_get_data (G_OBJECT (menu_item), "context-id");
 +	context_id = GPOINTER_TO_UINT (data);
 +
 +	g_object_get (action, "tooltip", &tooltip, NULL);
 +
 +	if (tooltip == NULL)
 +		return;
 +
 +	statusbar = GTK_STATUSBAR (browser->priv->statusbar);
 +	gtk_statusbar_push (statusbar, context_id, tooltip);
 +}
 +
 +static void
 +mail_browser_menu_item_deselect_cb (EMailBrowser *browser,
 +                                    GtkWidget *menu_item)
 +{
 +	GtkStatusbar *statusbar;
 +	guint context_id;
 +	gpointer data;
 +
 +	data = g_object_get_data (G_OBJECT (menu_item), "context-id");
 +	context_id = GPOINTER_TO_UINT (data);
 +
 +	statusbar = GTK_STATUSBAR (browser->priv->statusbar);
 +	gtk_statusbar_pop (statusbar, context_id);
 +}
 +
 +static void
 +mail_browser_connect_proxy_cb (EMailBrowser *browser,
 +                               GtkAction *action,
 +                               GtkWidget *proxy)
 +{
 +	GtkStatusbar *statusbar;
 +	guint context_id;
 +
 +	if (!GTK_IS_MENU_ITEM (proxy))
 +		return;
 +
 +	statusbar = GTK_STATUSBAR (browser->priv->statusbar);
 +	context_id = gtk_statusbar_get_context_id (statusbar, G_STRFUNC);
 +
 +	g_object_set_data_full (
 +		G_OBJECT (proxy),
 +		"action", g_object_ref (action),
 +		(GDestroyNotify) g_object_unref);
 +
 +	g_object_set_data (
 +		G_OBJECT (proxy), "context-id",
 +		GUINT_TO_POINTER (context_id));
 +
 +	g_signal_connect_swapped (
 +		proxy, "select",
 +		G_CALLBACK (mail_browser_menu_item_select_cb), browser);
 +
 +	g_signal_connect_swapped (
 +		proxy, "deselect",
 +		G_CALLBACK (mail_browser_menu_item_deselect_cb), browser);
 +}
 +
 +static void
 +mail_browser_message_selected_cb (EMailBrowser *browser,
 +                                  const gchar *uid)
 +{
 +	EMFormatHTMLDisplay *html_display;
 +	MessageList *message_list;
 +	CamelMessageInfo *info;
 +	EMailReader *reader;
 +
 +	if (uid == NULL)
 +		return;
 +
 +	reader = E_MAIL_READER (browser);
 +	html_display = e_mail_reader_get_html_display (reader);
 +	message_list = e_mail_reader_get_message_list (reader);
 +	info = camel_folder_get_message_info (message_list->folder, uid);
 +
 +	if (info == NULL)
 +		return;
 +
 +	gtk_window_set_title (
 +		GTK_WINDOW (browser),
 +		camel_message_info_subject (info));
 +	gtk_widget_grab_focus (
 +		GTK_WIDGET (((EMFormatHTML *) html_display)->html));
 +
 +	camel_folder_free_message_info (message_list->folder, info);
 +}
 +
 +static void
 +mail_browser_status_message_cb (EMailBrowser *browser,
 +                                const gchar *status_message)
 +{
 +	GtkStatusbar *statusbar;
 +	guint context_id;
 +
 +	statusbar = GTK_STATUSBAR (browser->priv->statusbar);
 +	context_id = gtk_statusbar_get_context_id (statusbar, G_STRFUNC);
 +
 +	/* Always pop first.  This prevents messages from piling up. */
 +	gtk_statusbar_pop (statusbar, context_id);
 +
 +	if (status_message != NULL && *status_message != '\0')
 +		gtk_statusbar_push (statusbar, context_id, status_message);
 +}
 +
 +static void
 +mail_browser_set_shell_backend (EMailBrowser *browser,
 +                                EShellBackend *shell_backend)
 +{
 +	g_return_if_fail (browser->priv->shell_backend == NULL);
 +
 +	browser->priv->shell_backend = g_object_ref (shell_backend);
 +}
 +
 +static void
 +mail_browser_set_property (GObject *object,
 +                           guint property_id,
 +                           const GValue *value,
 +                           GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_SHELL_BACKEND:
 +			mail_browser_set_shell_backend (
 +				E_MAIL_BROWSER (object),
 +				g_value_get_object (value));
 +			return;
 +
 +		case PROP_SHOW_DELETED:
 +			e_mail_browser_set_show_deleted (
 +				E_MAIL_BROWSER (object),
 +				g_value_get_boolean (value));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +mail_browser_get_property (GObject *object,
 +                           guint property_id,
 +                           GValue *value,
 +                           GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_SHELL_BACKEND:
 +			g_value_set_object (
 +				value, e_mail_reader_get_shell_backend (
 +				E_MAIL_READER (object)));
 +			return;
 +
 +		case PROP_SHOW_DELETED:
 +			g_value_set_boolean (
 +				value, e_mail_browser_get_show_deleted (
 +				E_MAIL_BROWSER (object)));
 +			return;
 +
 +		case PROP_UI_MANAGER:
 +			g_value_set_object (
 +				value, e_mail_browser_get_ui_manager (
 +				E_MAIL_BROWSER (object)));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +mail_browser_dispose (GObject *object)
 +{
 +	EMailBrowserPrivate *priv;
 +
 +	priv = E_MAIL_BROWSER_GET_PRIVATE (object);
 +
 +	if (priv->ui_manager != NULL) {
 +		g_object_unref (priv->ui_manager);
 +		priv->ui_manager = NULL;
 +	}
 +
 +	if (priv->shell_backend != NULL) {
 +		g_object_unref (priv->shell_backend);
 +		priv->shell_backend = NULL;
 +	}
 +
 +	if (priv->action_group != NULL) {
 +		g_object_unref (priv->action_group);
 +		priv->action_group = NULL;
 +	}
 +
 +	if (priv->html_display != NULL) {
 +		g_object_unref (priv->html_display);
 +		priv->html_display = NULL;
 +	}
 +
 +	if (priv->main_menu != NULL) {
 +		g_object_unref (priv->main_menu);
 +		priv->main_menu = NULL;
 +	}
 +
 +	if (priv->main_toolbar != NULL) {
 +		g_object_unref (priv->main_toolbar);
 +		priv->main_toolbar = NULL;
 +	}
 +
 +	if (priv->message_list != NULL) {
 +		g_object_unref (priv->message_list);
 +		priv->message_list = NULL;
 +	}
 +
 +	if (priv->search_bar != NULL) {
 +		g_object_unref (priv->search_bar);
 +		priv->search_bar = NULL;
 +	}
 +
 +	if (priv->statusbar != NULL) {
 +		g_object_unref (priv->statusbar);
 +		priv->statusbar = NULL;
 +	}
 +
 +	/* Chain up to parent's dispose() method. */
 +	G_OBJECT_CLASS (parent_class)->dispose (object);
 +}
 +
 +static void
 +mail_browser_constructed (GObject *object)
 +{
 +	EMFormatHTMLDisplay *html_display;
 +	EMailBrowserPrivate *priv;
 +	EMailReader *reader;
 +	EShellBackend *shell_backend;
 +	EShell *shell;
 +	GConfBridge *bridge;
 +	GtkAccelGroup *accel_group;
 +	GtkActionGroup *action_group;
 +	GtkUIManager *ui_manager;
 +	GtkWidget *container;
 +	GtkWidget *widget;
 +	GtkHTML *html;
 +	const gchar *domain;
 +	const gchar *key;
 +	guint merge_id;
 +
 +	priv = E_MAIL_BROWSER_GET_PRIVATE (object);
 +
 +	reader = E_MAIL_READER (object);
 +	ui_manager = priv->ui_manager;
 +	domain = GETTEXT_PACKAGE;
 +
 +	html_display = e_mail_reader_get_html_display (reader);
 +	shell_backend = e_mail_reader_get_shell_backend (reader);
 +
 +	shell = e_shell_backend_get_shell (shell_backend);
 +	e_shell_watch_window (shell, GTK_WINDOW (object));
 +
 +	html = EM_FORMAT_HTML (html_display)->html;
 +
 +	/* The message list is a widget, but it is not shown in the browser.
 +	 * Unfortunately, the widget is inseparable from its model, and the
 +	 * model is all we need. */
 +	priv->message_list = message_list_new (shell_backend);
 +	g_object_ref_sink (priv->message_list);
 +
 +	g_signal_connect_swapped (
 +		priv->message_list, "message-selected",
 +		G_CALLBACK (mail_browser_message_selected_cb), object);
 +
 +	g_signal_connect_swapped (
 +		html, "status-message",
 +		G_CALLBACK (mail_browser_status_message_cb), object);
 +
 +	e_mail_reader_init (reader);
 +
 +	action_group = priv->action_group;
 +	gtk_action_group_set_translation_domain (action_group, domain);
 +	gtk_action_group_add_actions (
 +		action_group, mail_browser_entries,
 +		G_N_ELEMENTS (mail_browser_entries), object);
 +	gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
 +
 +	e_load_ui_definition (ui_manager, E_MAIL_READER_UI_DEFINITION);
 +	gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, NULL);
 +
 +	merge_id = gtk_ui_manager_new_merge_id (ui_manager);
 +	e_mail_reader_create_charset_menu (reader, ui_manager, merge_id);
 +
 +	accel_group = gtk_ui_manager_get_accel_group (ui_manager);
 +	gtk_window_add_accel_group (GTK_WINDOW (object), accel_group);
 +
 +	g_signal_connect_swapped (
 +		ui_manager, "connect-proxy",
 +		G_CALLBACK (mail_browser_connect_proxy_cb), object);
 +
 +	/* Construct window widgets. */
 +
 +	widget = gtk_vbox_new (FALSE, 0);
 +	gtk_container_add (GTK_CONTAINER (object), widget);
 +	gtk_widget_show (widget);
 +
 +	container = widget;
 +
 +	/* Create the status bar before connecting proxy widgets. */
 +	widget = gtk_statusbar_new ();
 +	gtk_box_pack_end (GTK_BOX (container), widget, FALSE, FALSE, 0);
 +	priv->statusbar = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	widget = e_mail_search_bar_new (EM_FORMAT_HTML (html_display)->html);
 +	gtk_box_pack_end (GTK_BOX (container), widget, FALSE, FALSE, 0);
 +	priv->search_bar = g_object_ref (widget);
 +	gtk_widget_hide (widget);
 +
 +	g_signal_connect_swapped (
 +		widget, "changed",
 +		G_CALLBACK (em_format_redraw), html_display);
 +
 +	widget = gtk_ui_manager_get_widget (ui_manager, "/main-menu");
 +	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
 +	priv->main_menu = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	widget = gtk_ui_manager_get_widget (ui_manager, "/main-toolbar");
 +	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
 +	priv->main_toolbar = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	widget = gtk_scrolled_window_new (NULL, NULL);
 +	gtk_scrolled_window_set_policy (
 +		GTK_SCROLLED_WINDOW (widget),
 +		GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
 +	gtk_scrolled_window_set_shadow_type (
 +		GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
 +	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
 +	gtk_widget_show (widget);
 +
 +	container = widget;
 +
 +	widget = GTK_WIDGET (EM_FORMAT_HTML (html_display)->html);
 +	gtk_container_add (GTK_CONTAINER (container), widget);
 +	gtk_widget_show (widget);
 +
 +	/* Bind GObject properties to GConf keys. */
 +
 +	bridge = gconf_bridge_get ();
 +
 +	object = G_OBJECT (reader);
 +	key = "/apps/evolution/mail/display/show_deleted";
 +	gconf_bridge_bind_property (bridge, key, object, "show-deleted");
 +}
 +
 +static gboolean
 +mail_browser_key_press_event (GtkWidget *widget,
 +                              GdkEventKey *event)
 +{
 +	if (event->keyval == GDK_Escape) {
 +		e_mail_browser_close (E_MAIL_BROWSER (widget));
 +		return TRUE;
 +	}
 +
 +	/* Chain up to parent's key_press_event() method. */
 +	return GTK_WIDGET_CLASS (parent_class)->
 +		key_press_event (widget, event);
 +}
 +
 +static GtkActionGroup *
 +mail_browser_get_action_group (EMailReader *reader)
 +{
 +	EMailBrowserPrivate *priv;
 +
 +	priv = E_MAIL_BROWSER_GET_PRIVATE (reader);
 +
 +	return priv->action_group;
 +}
 +
 +static gboolean
 +mail_browser_get_hide_deleted (EMailReader *reader)
 +{
 +	EMailBrowser *browser;
 +
 +	browser = E_MAIL_BROWSER (reader);
 +
 +	return !e_mail_browser_get_show_deleted (browser);
 +}
 +
 +static EMFormatHTMLDisplay *
 +mail_browser_get_html_display (EMailReader *reader)
 +{
 +	EMailBrowserPrivate *priv;
 +
 +	priv = E_MAIL_BROWSER_GET_PRIVATE (reader);
 +
 +	return priv->html_display;
 +}
 +
 +static MessageList *
 +mail_browser_get_message_list (EMailReader *reader)
 +{
 +	EMailBrowserPrivate *priv;
 +
 +	priv = E_MAIL_BROWSER_GET_PRIVATE (reader);
 +
 +	return MESSAGE_LIST (priv->message_list);
 +}
 +
 +static EShellBackend *
 +mail_browser_get_shell_backend (EMailReader *reader)
 +{
 +	EMailBrowserPrivate *priv;
 +
 +	priv = E_MAIL_BROWSER_GET_PRIVATE (reader);
 +
 +	return priv->shell_backend;
 +}
 +
 +static GtkWindow *
 +mail_browser_get_window (EMailReader *reader)
 +{
 +	return GTK_WINDOW (reader);
 +}
 +
 +static void
 +mail_browser_set_message (EMailReader *reader,
 +                          const gchar *uid,
 +                          gboolean mark_read)
 +{
 +	EMailReaderIface *iface;
 +	MessageList *message_list;
 +	CamelMessageInfo *info;
 +	CamelFolder *folder;
 +
 +	/* Chain up to parent's set_message() method. */
 +	iface = g_type_default_interface_peek (E_TYPE_MAIL_READER);
 +	iface->set_message (reader, uid, mark_read);
 +
 +	if (uid == NULL) {
 +		e_mail_browser_close (E_MAIL_BROWSER (reader));
 +		return;
 +	}
 +
 +	message_list = e_mail_reader_get_message_list (reader);
 +
 +	folder = message_list->folder;
 +	info = camel_folder_get_message_info (folder, uid);
 +
 +	if (info != NULL) {
 +		gtk_window_set_title (
 +			GTK_WINDOW (reader),
 +			camel_message_info_subject (info));
 +		camel_folder_free_message_info (folder, info);
 +	}
 +
 +	if (mark_read)
 +		e_mail_reader_mark_as_read (reader, uid);
 +}
 +
 +static void
 +mail_browser_show_search_bar (EMailReader *reader)
 +{
 +	EMailBrowserPrivate *priv;
 +
 +	priv = E_MAIL_BROWSER_GET_PRIVATE (reader);
 +
 +	gtk_widget_show (priv->search_bar);
 +}
 +
 +static void
 +mail_browser_class_init (EMailBrowserClass *class)
 +{
 +	GObjectClass *object_class;
 +	GtkWidgetClass *widget_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (EMailBrowserPrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->set_property = mail_browser_set_property;
 +	object_class->get_property = mail_browser_get_property;
 +	object_class->dispose = mail_browser_dispose;
 +	object_class->constructed = mail_browser_constructed;
 +
 +	widget_class = GTK_WIDGET_CLASS (class);
 +	widget_class->key_press_event = mail_browser_key_press_event;
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_SHELL_BACKEND,
 +		g_param_spec_object (
 +			"shell-backend",
 +			_("Shell Module"),
 +			_("The mail shell backend"),
 +			E_TYPE_SHELL_BACKEND,
 +			G_PARAM_READWRITE |
 +			G_PARAM_CONSTRUCT_ONLY));
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_SHOW_DELETED,
 +		g_param_spec_boolean (
 +			"show-deleted",
 +			_("Show Deleted"),
 +			_("Show deleted messages"),
 +			FALSE,
 +			G_PARAM_READWRITE));
 +}
 +
 +static void
 +mail_browser_iface_init (EMailReaderIface *iface)
 +{
 +	iface->get_action_group = mail_browser_get_action_group;
 +	iface->get_hide_deleted = mail_browser_get_hide_deleted;
 +	iface->get_html_display = mail_browser_get_html_display;
 +	iface->get_message_list = mail_browser_get_message_list;
 +	iface->get_shell_backend = mail_browser_get_shell_backend;
 +	iface->get_window = mail_browser_get_window;
 +	iface->set_message = mail_browser_set_message;
 +	iface->show_search_bar = mail_browser_show_search_bar;
 +}
 +
 +static void
 +mail_browser_init (EMailBrowser *browser)
 +{
 +	GConfBridge *bridge;
 +	const gchar *prefix;
 +
 +	browser->priv = E_MAIL_BROWSER_GET_PRIVATE (browser);
 +
 +	browser->priv->ui_manager = gtk_ui_manager_new ();
 +	browser->priv->action_group = gtk_action_group_new ("mail-browser");
 +	browser->priv->html_display = em_format_html_display_new ();
 +
 +	bridge = gconf_bridge_get ();
 +	prefix = "/apps/evolution/mail/mail_browser";
 +	gconf_bridge_bind_window_size (bridge, prefix, GTK_WINDOW (browser));
 +
 +	gtk_window_set_title (GTK_WINDOW (browser), _("Evolution"));
 +}
 +
 +GType
 +e_mail_browser_get_type (void)
 +{
 +	static GType type = 0;
 +
 +	if (G_UNLIKELY (type == 0)) {
 +		static const GTypeInfo type_info = {
 +			sizeof (EMailBrowserClass),
 +			(GBaseInitFunc) NULL,
 +			(GBaseFinalizeFunc) NULL,
 +			(GClassInitFunc) mail_browser_class_init,
 +			(GClassFinalizeFunc) NULL,
 +			NULL,  /* class_data */
 +			sizeof (EMailBrowser),
 +			0,     /* n_preallocs */
 +			(GInstanceInitFunc) mail_browser_init,
 +			NULL   /* value_table */
 +		};
 +
 +		static const GInterfaceInfo iface_info = {
 +			(GInterfaceInitFunc) mail_browser_iface_init,
 +			(GInterfaceFinalizeFunc) NULL,
 +			NULL   /* interface_data */
 +		};
 +
 +		type = g_type_register_static (
 +			GTK_TYPE_WINDOW, "EMailBrowser", &type_info, 0);
 +
 +		g_type_add_interface_static (
 +			type, E_TYPE_MAIL_READER, &iface_info);
 +	}
 +
 +	return type;
 +}
 +
 +GtkWidget *
 +e_mail_browser_new (EMailShellBackend *mail_shell_backend)
 +{
 +	g_return_val_if_fail (
 +		E_IS_MAIL_SHELL_BACKEND (mail_shell_backend), NULL);
 +
 +	return g_object_new (
 +		E_TYPE_MAIL_BROWSER,
 +		"shell-backend", mail_shell_backend, NULL);
 +}
 +
 +void
 +e_mail_browser_close (EMailBrowser *browser)
 +{
 +	g_return_if_fail (E_IS_MAIL_BROWSER (browser));
 +
 +	gtk_widget_destroy (GTK_WIDGET (browser));
 +}
 +
 +gboolean
 +e_mail_browser_get_show_deleted (EMailBrowser *browser)
 +{
 +	g_return_val_if_fail (E_IS_MAIL_BROWSER (browser), FALSE);
 +
 +	return browser->priv->show_deleted;
 +}
 +
 +void
 +e_mail_browser_set_show_deleted (EMailBrowser *browser,
 +                                 gboolean show_deleted)
 +{
 +	g_return_if_fail (E_IS_MAIL_BROWSER (browser));
 +
 +	browser->priv->show_deleted = show_deleted;
 +
 +	g_object_notify (G_OBJECT (browser), "show-deleted");
 +}
 +
 +GtkUIManager *
 +e_mail_browser_get_ui_manager (EMailBrowser *browser)
 +{
 +	g_return_val_if_fail (E_IS_MAIL_BROWSER (browser), NULL);
 +
 +	return browser->priv->ui_manager;
 +}
diff --cc mail/e-mail-browser.h
index b67ea9a,0000000..2605b2e
mode 100644,000000..100644
--- a/mail/e-mail-browser.h
+++ b/mail/e-mail-browser.h
@@@ -1,72 -1,0 +1,72 @@@
 +/*
 + * e-mail-browser.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_MAIL_BROWSER_H
 +#define E_MAIL_BROWSER_H
 +
 +#include <gtk/gtk.h>
 +#include <mail/e-mail-shell-backend.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_MAIL_BROWSER \
 +	(e_mail_browser_get_type ())
 +#define E_MAIL_BROWSER(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_MAIL_BROWSER, EMailBrowser))
 +#define E_MAIL_BROWSER_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_MAIL_BROWSER, EMailBrowserClass))
 +#define E_IS_MAIL_BROWSER(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_MAIL_BROWSER))
 +#define E_IS_MAIL_BROWSER_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_MAIL_BROWSER))
 +#define E_MAIL_BROWSER_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_MAIL_BROWSER, EMailBrowserClass))
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _EMailBrowser EMailBrowser;
 +typedef struct _EMailBrowserClass EMailBrowserClass;
 +typedef struct _EMailBrowserPrivate EMailBrowserPrivate;
 +
 +struct _EMailBrowser {
 +	GtkWindow parent;
 +	EMailBrowserPrivate *priv;
 +};
 +
 +struct _EMailBrowserClass {
 +	GtkWindowClass parent_class;
 +};
 +
 +GType		e_mail_browser_get_type		(void);
 +GtkWidget *	e_mail_browser_new		(EMailShellBackend *mail_shell_backend);
 +void		e_mail_browser_close		(EMailBrowser *browser);
 +gboolean	e_mail_browser_get_show_deleted	(EMailBrowser *browser);
 +void		e_mail_browser_set_show_deleted (EMailBrowser *browser,
 +						 gboolean show_deleted);
 +GtkUIManager *	e_mail_browser_get_ui_manager	(EMailBrowser *browser);
 +
 +G_END_DECLS
 +
 +#endif /* E_MAIL_BROWSER_H */
diff --cc mail/e-mail-display.c
index f649393,0000000..9507330
mode 100644,000000..100644
--- a/mail/e-mail-display.c
+++ b/mail/e-mail-display.c
@@@ -1,627 -1,0 +1,627 @@@
 +/*
 + * e-mail-display.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-mail-display.h"
 +
 +#include <string.h>
 +#include <glib/gi18n.h>
 +
 +#include "e-util/e-util.h"
 +
 +#define E_MAIL_DISPLAY_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_MAIL_DISPLAY, EMailDisplayPrivate))
 +
 +struct _EMailDisplayPrivate {
 +	EMFormatHTML *formatter;
 +};
 +
 +enum {
 +	PROP_0,
 +	PROP_ANIMATE,
 +	PROP_CARET_MODE,
 +	PROP_FORMATTER
 +};
 +
 +enum {
 +	POPUP_EVENT,
 +	STATUS_MESSAGE,
 +	LAST_SIGNAL
 +};
 +
 +static gpointer parent_class;
 +static guint signals[LAST_SIGNAL];
 +
 +static gboolean
 +mail_display_emit_popup_event (EMailDisplay *display,
 +                               GdkEventButton *event,
 +                               const gchar *uri,
 +                               EMFormatPURI *puri)
 +{
 +	CamelMimePart *mime_part;
 +	gboolean stop_handlers = FALSE;
 +
 +	mime_part = (puri != NULL) ? puri->part : NULL;
 +
 +	g_signal_emit (
 +		display, signals[POPUP_EVENT], 0,
 +		event, uri, mime_part, &stop_handlers);
 +
 +	return stop_handlers;
 +}
 +
 +static void
 +mail_display_emit_status_message (EMailDisplay *display,
 +                                  const gchar *status_message)
 +{
 +	g_signal_emit (display, signals[STATUS_MESSAGE], 0, status_message);
 +}
 +
 +static void
 +mail_display_get_uri_puri (EMailDisplay *display,
 +                           GdkEventButton *event,
 +                           gchar **uri,
 +                           EMFormatPURI **puri)
 +{
 +	EMFormat *formatter;
 +	GtkHTML *html;
 +	gchar *text_uri;
 +	gchar *image_uri;
 +	gboolean is_cid;
 +
 +	html = GTK_HTML (display);
 +	formatter = EM_FORMAT (display->priv->formatter);
 +
 +	if (event != NULL) {
 +		text_uri = gtk_html_get_url_at (html, event->x, event->y);
 +		image_uri = gtk_html_get_image_src_at (html, event->x, event->y);
 +	} else {
 +		text_uri = gtk_html_get_cursor_url (html);
 +		image_uri = gtk_html_get_cursor_image_src (html);
 +	}
 +
 +	is_cid = (image_uri != NULL) &&
 +		(g_ascii_strncasecmp (image_uri, "cid:", 4) == 0);
 +
 +	if (image_uri != NULL) {
 +		if (strstr (image_uri, "://") == NULL && !is_cid) {
 +			gchar *temp;
 +
 +			temp = g_strconcat ("file://", image_uri, NULL);
 +			g_free (image_uri);
 +			temp = image_uri;
 +		}
 +	}
 +
 +	if (puri != NULL) {
 +		if (text_uri != NULL)
 +			*puri = em_format_find_puri (formatter, text_uri);
 +
 +		if (*puri == NULL && image_uri != NULL)
 +			*puri = em_format_find_puri (formatter, image_uri);
 +	}
 +
 +	if (uri != NULL) {
 +		*uri = NULL;
 +		if (is_cid) {
 +			if (text_uri != NULL)
 +				*uri = g_strdup_printf (
 +					"%s\n%s", text_uri, image_uri);
 +			else {
 +				*uri = image_uri;
 +				image_uri = NULL;
 +			}
 +		} else {
 +			*uri = text_uri;
 +			text_uri = NULL;
 +		}
 +	}
 +
 +	g_free (text_uri);
 +	g_free (image_uri);
 +}
 +
 +static void
 +mail_display_update_formatter_colors (EMailDisplay *display)
 +{
 +	EMFormatHTMLColorType type;
 +	EMFormatHTML *formatter;
 +	GdkColor *color;
 +	GtkStyle *style;
 +	gint state;
 +
 +	state = GTK_WIDGET_STATE (display);
 +	formatter = display->priv->formatter;
 +
 +	style = gtk_widget_get_style (GTK_WIDGET (display));
 +	if (style == NULL)
 +		return;
 +
 +	g_object_freeze_notify (G_OBJECT (formatter));
 +
 +	color = &style->bg[state];
 +	type = EM_FORMAT_HTML_COLOR_BODY;
 +	em_format_html_set_color (formatter, type, color);
 +
 +	color = &style->base[GTK_STATE_NORMAL];
 +	type = EM_FORMAT_HTML_COLOR_CONTENT;
 +	em_format_html_set_color (formatter, type, color);
 +
 +	color = &style->dark[state];
 +	type = EM_FORMAT_HTML_COLOR_FRAME;
 +	em_format_html_set_color (formatter, type, color);
 +
 +	color = &style->fg[state];
 +	type = EM_FORMAT_HTML_COLOR_HEADER;
 +	em_format_html_set_color (formatter, type, color);
 +
 +	color = &style->text[state];
 +	type = EM_FORMAT_HTML_COLOR_TEXT;
 +	em_format_html_set_color (formatter, type, color);
 +
 +	g_object_thaw_notify (G_OBJECT (formatter));
 +}
 +
 +static void
 +mail_display_set_property (GObject *object,
 +                           guint property_id,
 +                           const GValue *value,
 +                           GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_ANIMATE:
 +			e_mail_display_set_animate (
 +				E_MAIL_DISPLAY (object),
 +				g_value_get_boolean (value));
 +			return;
 +
 +		case PROP_CARET_MODE:
 +			e_mail_display_set_caret_mode (
 +				E_MAIL_DISPLAY (object),
 +				g_value_get_boolean (value));
 +			return;
 +
 +		case PROP_FORMATTER:
 +			e_mail_display_set_formatter (
 +				E_MAIL_DISPLAY (object),
 +				g_value_get_object (value));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +mail_display_get_property (GObject *object,
 +                           guint property_id,
 +                           GValue *value,
 +                           GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_ANIMATE:
 +			g_value_set_boolean (
 +				value, e_mail_display_get_animate (
 +				E_MAIL_DISPLAY (object)));
 +			return;
 +
 +		case PROP_CARET_MODE:
 +			g_value_set_boolean (
 +				value, e_mail_display_get_caret_mode (
 +				E_MAIL_DISPLAY (object)));
 +			return;
 +
 +		case PROP_FORMATTER:
 +			g_value_set_object (
 +				value, e_mail_display_get_formatter (
 +				E_MAIL_DISPLAY (object)));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +mail_display_dispose (GObject *object)
 +{
 +	EMailDisplayPrivate *priv;
 +
 +	priv = E_MAIL_DISPLAY_GET_PRIVATE (object);
 +
 +	if (priv->formatter) {
 +		g_object_unref (priv->formatter);
 +		priv->formatter = NULL;
 +	}
 +
 +	/* Chain up to parent's dispose() method. */
 +	G_OBJECT_CLASS (parent_class)->dispose (object);
 +}
 +
 +static void
 +mail_display_realize (GtkWidget *widget)
 +{
 +	/* Chain up to parent's realize() method. */
 +	GTK_WIDGET_CLASS (parent_class)->realize (widget);
 +
 +	mail_display_update_formatter_colors (E_MAIL_DISPLAY (widget));
 +}
 +
 +static void
 +mail_display_style_set (GtkWidget *widget,
 +                        GtkStyle *previous_style)
 +{
 +	EMailDisplayPrivate *priv;
 +
 +	priv = E_MAIL_DISPLAY_GET_PRIVATE (widget);
 +
 +	/* Chain up to parent's style_set() method. */
 +	GTK_WIDGET_CLASS (parent_class)->style_set (widget, previous_style);
 +
 +	mail_display_update_formatter_colors (E_MAIL_DISPLAY (widget));
 +	em_format_redraw (EM_FORMAT (priv->formatter));
 +}
 +
 +static gboolean
 +mail_display_button_press_event (GtkWidget *widget,
 +                                 GdkEventButton *event)
 +{
 +	if (event->button == 3) {
 +		EMailDisplay *display;
 +		EMFormatPURI *puri = NULL;
 +		gboolean stop_handlers = TRUE;
 +		gchar *uri = NULL;
 +
 +		display = E_MAIL_DISPLAY (widget);
 +		mail_display_get_uri_puri (display, event, &uri, &puri);
 +
 +		if (uri == NULL || !g_str_has_prefix (uri, "##"))
 +			stop_handlers = mail_display_emit_popup_event (
 +				display, event, uri, puri);
 +
 +		g_free (uri);
 +
 +		if (stop_handlers)
 +			return TRUE;
 +	}
 +
 +	/* Chain up to parent's button_press_event() method. */
 +	return GTK_WIDGET_CLASS (parent_class)->
 +		button_press_event (widget, event);
 +}
 +
 +static gboolean
 +mail_display_scroll_event (GtkWidget *widget,
 +                           GdkEventScroll *event)
 +{
 +	if (event->state & GDK_CONTROL_MASK) {
 +		switch (event->direction) {
 +			case GDK_SCROLL_UP:
 +				gtk_html_zoom_in (GTK_HTML (widget));
 +				return TRUE;
 +			case GDK_SCROLL_DOWN:
 +				gtk_html_zoom_out (GTK_HTML (widget));
 +				return TRUE;
 +			default:
 +				break;
 +		}
 +	}
 +
 +	return FALSE;
 +}
 +
 +static void
 +mail_display_link_clicked (GtkHTML *html,
 +                           const gchar *uri)
 +{
 +	EMailDisplayPrivate *priv;
 +
 +	priv = E_MAIL_DISPLAY_GET_PRIVATE (html);
 +	g_return_if_fail (priv->formatter != NULL);
 +
 +	if (g_str_has_prefix (uri, "##")) {
 +		guint32 flags;
 +
 +		flags = priv->formatter->header_wrap_flags;
 +
 +		if (strcmp (uri, "##TO##") == 0) {
 +			if (!(flags & EM_FORMAT_HTML_HEADER_TO))
 +				flags |= EM_FORMAT_HTML_HEADER_TO;
 +			else
 +				flags &= ~EM_FORMAT_HTML_HEADER_TO;
 +		} else if (strcmp (uri, "##CC##") == 0) {
 +			if (!(flags & EM_FORMAT_HTML_HEADER_CC))
 +				flags |= EM_FORMAT_HTML_HEADER_CC;
 +			else
 +				flags |= EM_FORMAT_HTML_HEADER_CC;
 +		} else if (strcmp (uri, "##BCC##") == 0) {
 +			if (!(flags & EM_FORMAT_HTML_HEADER_BCC))
 +				flags |= EM_FORMAT_HTML_HEADER_BCC;
 +			else
 +				flags |= EM_FORMAT_HTML_HEADER_BCC;
 +		}
 +
 +		priv->formatter->header_wrap_flags = flags;
 +		em_format_redraw (EM_FORMAT (priv->formatter));
 +
 +	} else if (*uri == '#')
 +		gtk_html_jump_to_anchor (html, uri + 1);
 +
 +	else if (g_ascii_strncasecmp (uri, "thismessage:", 12) == 0)
 +		/* ignore */ ;
 +
 +	else if (g_ascii_strncasecmp (uri, "cid:", 4) == 0)
 +		/* ignore */ ;
 +
 +	else {
 +		gpointer parent;
 +
 +		parent = gtk_widget_get_toplevel (GTK_WIDGET (html));
 +		parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL;
 +
 +		e_show_uri (parent, uri);
 +	}
 +}
 +
 +static void
 +mail_display_on_url (GtkHTML *html,
 +                     const gchar *uri)
 +{
 +	EMailDisplay *display;
 +	CamelInternetAddress *address;
 +	CamelURL *curl;
 +	const gchar *format = NULL;
 +	gchar *message = NULL;
 +	gchar *who;
 +
 +	display = E_MAIL_DISPLAY (html);
 +
 +	if (uri == NULL || *uri == '\0')
 +		goto exit;
 +
 +	if (g_str_has_prefix (uri, "mailto:";))
 +		format = _("Click to mail %s");
 +	else if (g_str_has_prefix (uri, "callto:"))
 +		format = _("Click to call %s");
 +	else if (g_str_has_prefix (uri, "h323:"))
 +		format = _("Click to call %s");
 +	else if (g_str_has_prefix (uri, "sip:"))
 +		format = _("Click to call %s");
 +	else if (g_str_has_prefix (uri, "##"))
 +		message = g_strdup (_("Click to hide/unhide addresses"));
 +	else
 +		message = g_strdup_printf (_("Click to open %s"), uri);
 +
 +	if (format == NULL)
 +		goto exit;
 +
 +	curl = camel_url_new (uri, NULL);
 +	address = camel_internet_address_new ();
 +	camel_address_decode (CAMEL_ADDRESS (address), curl->path);
 +	who = camel_address_format (CAMEL_ADDRESS (address));
 +	camel_object_unref (address);
 +	camel_url_free (curl);
 +
 +	if (who == NULL)
 +		who = g_strdup (strchr (uri, ':') + 1);
 +
 +	message = g_strdup_printf (format, who);
 +
 +	g_free (who);
 +
 +exit:
 +	mail_display_emit_status_message (display, message);
 +
 +	g_free (message);
 +}
 +
 +static void
 +mail_display_iframe_created (GtkHTML *html,
 +                             GtkHTML *iframe)
 +{
 +	g_signal_connect_swapped (
 +		iframe, "button-press-event",
 +		G_CALLBACK (mail_display_button_press_event), html);
 +}
 +
 +static void
 +mail_display_class_init (EMailDisplayClass *class)
 +{
 +	GObjectClass *object_class;
 +	GtkWidgetClass *widget_class;
 +	GtkHTMLClass *html_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (EMailDisplayPrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->set_property = mail_display_set_property;
 +	object_class->get_property = mail_display_get_property;
 +	object_class->dispose = mail_display_dispose;
 +
 +	widget_class = GTK_WIDGET_CLASS (class);
 +	widget_class->realize = mail_display_realize;
 +	widget_class->style_set = mail_display_style_set;
 +	widget_class->button_press_event = mail_display_button_press_event;
 +	widget_class->scroll_event = mail_display_scroll_event;
 +
 +	html_class = GTK_HTML_CLASS (class);
 +	html_class->link_clicked = mail_display_link_clicked;
 +	html_class->on_url = mail_display_on_url;
 +	html_class->iframe_created = mail_display_iframe_created;
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_ANIMATE,
 +		g_param_spec_boolean (
 +			"animate",
 +			"Animate Images",
 +			NULL,
 +			FALSE,
 +			G_PARAM_READWRITE));
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_CARET_MODE,
 +		g_param_spec_boolean (
 +			"caret-mode",
 +			"Caret Mode",
 +			NULL,
 +			FALSE,
 +			G_PARAM_READWRITE));
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_FORMATTER,
 +		g_param_spec_object (
 +			"formatter",
 +			"HTML Formatter",
 +			NULL,
 +			EM_TYPE_FORMAT_HTML,
 +			G_PARAM_READWRITE));
 +
 +	signals[POPUP_EVENT] = g_signal_new (
 +		"popup-event",
 +		G_TYPE_FROM_CLASS (class),
 +		G_SIGNAL_RUN_LAST,
 +		G_STRUCT_OFFSET (EMailDisplayClass, popup_event),
 +		g_signal_accumulator_true_handled, NULL,
 +		e_marshal_BOOLEAN__BOXED_POINTER_POINTER,
 +		G_TYPE_BOOLEAN, 3,
 +		GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE,
 +		G_TYPE_POINTER,
 +		G_TYPE_POINTER);
 +
 +	signals[STATUS_MESSAGE] = g_signal_new (
 +		"status-message",
 +		G_TYPE_FROM_CLASS (class),
 +		G_SIGNAL_RUN_FIRST,
 +		G_STRUCT_OFFSET (EMailDisplayClass, status_message),
 +		NULL, NULL,
 +		g_cclosure_marshal_VOID__STRING,
 +		G_TYPE_NONE, 1,
 +		G_TYPE_STRING);
 +}
 +
 +static void
 +mail_display_init (EMailDisplay *display)
 +{
 +	display->priv = E_MAIL_DISPLAY_GET_PRIVATE (display);
 +}
 +
 +GType
 +e_mail_display_get_type (void)
 +{
 +	static GType type = 0;
 +
 +	if (G_UNLIKELY (type == 0)) {
 +		static const GTypeInfo type_info = {
 +			sizeof (EMailDisplayClass),
 +			(GBaseInitFunc) NULL,
 +			(GBaseFinalizeFunc) NULL,
 +			(GClassInitFunc) mail_display_class_init,
 +			(GClassFinalizeFunc) NULL,
 +			NULL,  /* class_data */
 +			sizeof (EMailDisplay),
 +			0,     /* n_preallocs */
 +			(GInstanceInitFunc) mail_display_init,
 +			NULL   /* value_table */
 +		};
 +
 +		type = g_type_register_static (
 +			GTK_TYPE_HTML, "EMailDisplay", &type_info, 0);
 +	}
 +
 +	return type;
 +}
 +
 +gboolean
 +e_mail_display_get_animate (EMailDisplay *display)
 +{
 +	/* XXX This is just here to maintain symmetry
 +	 *     with e_mail_display_set_animate(). */
 +
 +	g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), FALSE);
 +
 +	return gtk_html_get_animate (GTK_HTML (display));
 +}
 +
 +void
 +e_mail_display_set_animate (EMailDisplay *display,
 +                            gboolean animate)
 +{
 +	/* XXX GtkHTML does not utilize GObject properties as well
 +	 *     as it could.  This just wraps gtk_html_set_animate()
 +	 *     so we can get a "notify::animate" signal. */
 +
 +	g_return_if_fail (E_IS_MAIL_DISPLAY (display));
 +
 +	gtk_html_set_animate (GTK_HTML (display), animate);
 +
 +	g_object_notify (G_OBJECT (display), "animate");
 +}
 +
 +gboolean
 +e_mail_display_get_caret_mode (EMailDisplay *display)
 +{
 +	/* XXX This is just here to maintain symmetry
 +	 *     with e_mail_display_set_caret_mode(). */
 +
 +	g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), FALSE);
 +
 +	return gtk_html_get_caret_mode (GTK_HTML (display));
 +}
 +
 +void
 +e_mail_display_set_caret_mode (EMailDisplay *display,
 +                               gboolean caret_mode)
 +{
 +	/* XXX GtkHTML does not utilize GObject properties as well
 +	 *     as it could.  This just wraps gtk_html_set_caret_mode()
 +	 *     so we can get a "notify::caret-mode" signal. */
 +
 +	g_return_if_fail (E_IS_MAIL_DISPLAY (display));
 +
 +	gtk_html_set_caret_mode (GTK_HTML (display), caret_mode);
 +
 +	g_object_notify (G_OBJECT (display), "caret-mode");
 +}
 +
 +EMFormatHTML *
 +e_mail_display_get_formatter (EMailDisplay *display)
 +{
 +	g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), NULL);
 +
 +	return display->priv->formatter;
 +}
 +
 +void
 +e_mail_display_set_formatter (EMailDisplay *display,
 +                              EMFormatHTML *formatter)
 +{
 +	g_return_if_fail (E_IS_MAIL_DISPLAY (display));
 +	g_return_if_fail (EM_IS_FORMAT_HTML (formatter));
 +
 +	if (display->priv->formatter != NULL)
 +		g_object_unref (display->priv->formatter);
 +
 +	display->priv->formatter = g_object_ref (formatter);
 +
 +	g_object_notify (G_OBJECT (display), "formatter");
 +}
diff --cc mail/e-mail-display.h
index f1d5fc5,0000000..815fd45
mode 100644,000000..100644
--- a/mail/e-mail-display.h
+++ b/mail/e-mail-display.h
@@@ -1,83 -1,0 +1,83 @@@
 +/*
 + * e-mail-display.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_MAIL_DISPLAY_H
 +#define E_MAIL_DISPLAY_H
 +
 +#include <gtkhtml/gtkhtml.h>
 +#include <mail/em-format-html.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_MAIL_DISPLAY \
 +	(e_mail_display_get_type ())
 +#define E_MAIL_DISPLAY(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_MAIL_DISPLAY, EMailDisplay))
 +#define E_MAIL_DISPLAY_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_MAIL_DISPLAY, EMailDisplayClass))
 +#define E_IS_MAIL_DISPLAY(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_MAIL_DISPLAY))
 +#define E_IS_MAIL_DISPLAY_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), E_TYPE_MAIL_DISPLAY))
 +#define E_MAIL_DISPLAY_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_MAIL_DISPLAY, EMailDisplayClass))
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _EMailDisplay EMailDisplay;
 +typedef struct _EMailDisplayClass EMailDisplayClass;
 +typedef struct _EMailDisplayPrivate EMailDisplayPrivate;
 +
 +struct _EMailDisplay {
 +	GtkHTML parent;
 +	EMailDisplayPrivate *priv;
 +};
 +
 +struct _EMailDisplayClass {
 +	GtkHTMLClass parent_class;
 +
 +	/* Signals */
 +	gboolean	(*popup_event)		(EMailDisplay *display,
 +						 GdkEventButton *event,
 +						 const gchar *uri,
 +						 EMFormatPURI *puri);
 +	void		(*status_message)	(EMailDisplay *display,
 +						 const gchar *status_message);
 +};
 +
 +GType		e_mail_display_get_type		(void);
 +gboolean	e_mail_display_get_animate	(EMailDisplay *display);
 +void		e_mail_display_set_animate	(EMailDisplay *display,
 +						 gboolean animate);
 +gboolean	e_mail_display_get_caret_mode	(EMailDisplay *display);
 +void		e_mail_display_set_caret_mode	(EMailDisplay *display,
 +						 gboolean caret_mode);
 +EMFormatHTML *	e_mail_display_get_formatter	(EMailDisplay *display);
 +void		e_mail_display_set_formatter	(EMailDisplay *display,
 +						 EMFormatHTML *formatter);
 +
 +G_END_DECLS
 +
 +#endif /* E_MAIL_DISPLAY_H */
diff --cc mail/e-mail-label-dialog.c
index 23b5068,0000000..bebe0e6
mode 100644,000000..100644
--- a/mail/e-mail-label-dialog.c
+++ b/mail/e-mail-label-dialog.c
@@@ -1,323 -1,0 +1,323 @@@
 +/*
 + * e-mail-label-dialog.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-mail-label-dialog.h"
 +
 +#include <glib/gi18n.h>
 +
 +#define E_MAIL_LABEL_DIALOG_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_MAIL_LABEL_DIALOG, EMailLabelDialogPrivate))
 +
 +struct _EMailLabelDialogPrivate {
 +	GtkWidget *entry;
 +	GtkWidget *colorsel;
 +};
 +
 +enum {
 +	PROP_0,
 +	PROP_LABEL_COLOR,
 +	PROP_LABEL_NAME
 +};
 +
 +static gpointer parent_class;
 +
 +static void
 +mail_label_dialog_entry_changed_cb (EMailLabelDialog *dialog)
 +{
 +	const gchar *text;
 +	gboolean sensitive;
 +
 +	text = gtk_entry_get_text (GTK_ENTRY (dialog->priv->entry));
 +	sensitive = (text != NULL && *text != '\0');
 +
 +	gtk_dialog_set_response_sensitive (
 +		GTK_DIALOG (dialog), GTK_RESPONSE_OK, sensitive);
 +}
 +
 +static void
 +mail_label_dialog_set_property (GObject *object,
 +                                guint property_id,
 +                                const GValue *value,
 +                                GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_LABEL_COLOR:
 +			e_mail_label_dialog_set_label_color (
 +				E_MAIL_LABEL_DIALOG (object),
 +				g_value_get_boxed (value));
 +			return;
 +
 +		case PROP_LABEL_NAME:
 +			e_mail_label_dialog_set_label_name (
 +				E_MAIL_LABEL_DIALOG (object),
 +				g_value_get_string (value));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +mail_label_dialog_get_property (GObject *object,
 +                                guint property_id,
 +                                GValue *value,
 +                                GParamSpec *pspec)
 +{
 +	GdkColor color;
 +
 +	switch (property_id) {
 +		case PROP_LABEL_COLOR:
 +			e_mail_label_dialog_get_label_color (
 +				E_MAIL_LABEL_DIALOG (object), &color);
 +			g_value_set_boxed (value, &color);
 +			return;
 +
 +		case PROP_LABEL_NAME:
 +			g_value_set_string (
 +				value, e_mail_label_dialog_get_label_name (
 +				E_MAIL_LABEL_DIALOG (object)));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +mail_label_dialog_dispose (GObject *object)
 +{
 +	EMailLabelDialogPrivate *priv;
 +
 +	priv = E_MAIL_LABEL_DIALOG_GET_PRIVATE (object);
 +
 +	if (priv->entry != NULL) {
 +		g_object_unref (priv->entry);
 +		priv->entry = NULL;
 +	}
 +
 +	if (priv->colorsel != NULL) {
 +		g_object_unref (priv->colorsel);
 +		priv->colorsel = NULL;
 +	}
 +
 +	/* Chain up to parent's dispose() method. */
 +	G_OBJECT_CLASS (parent_class)->dispose (object);
 +}
 +
 +static void
 +mail_label_dialog_constructed (GObject *object)
 +{
 +	GtkWidget *action_area;
 +	GtkWidget *content_area;
 +
 +	/* XXX Override GTK's style property defaults for GtkDialog.
 +	 *     Hopefully GTK+ 3.0 will fix the broken defaults. */
 +
 +	action_area = gtk_dialog_get_action_area (GTK_DIALOG (object));
 +	content_area = gtk_dialog_get_content_area (GTK_DIALOG (object));
 +
 +	gtk_box_set_spacing (GTK_BOX (content_area), 12);
 +	gtk_container_set_border_width (GTK_CONTAINER (object), 12);
 +	gtk_container_set_border_width (GTK_CONTAINER (action_area), 0);
 +	gtk_container_set_border_width (GTK_CONTAINER (content_area), 0);
 +}
 +
 +static void
 +mail_label_dialog_class_init (EMailLabelDialogClass *class)
 +{
 +	GObjectClass *object_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (EMailLabelDialogPrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->set_property = mail_label_dialog_set_property;
 +	object_class->get_property = mail_label_dialog_get_property;
 +	object_class->dispose = mail_label_dialog_dispose;
 +	object_class->constructed = mail_label_dialog_constructed;
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_LABEL_COLOR,
 +		g_param_spec_boxed (
 +			"label-color",
 +			"Label Color",
 +			NULL,
 +			GDK_TYPE_COLOR,
 +			G_PARAM_READWRITE));
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_LABEL_NAME,
 +		g_param_spec_string (
 +			"label-name",
 +			"Label Name",
 +			NULL,
 +			NULL,
 +			G_PARAM_READWRITE));
 +}
 +
 +static void
 +mail_label_dialog_init (EMailLabelDialog *dialog)
 +{
 +	GtkWidget *content_area;
 +	GtkWidget *container;
 +	GtkWidget *widget;
 +
 +	dialog->priv = E_MAIL_LABEL_DIALOG_GET_PRIVATE (dialog);
 +
 +	content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
 +
 +	gtk_dialog_add_button (
 +		GTK_DIALOG (dialog),
 +		GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
 +
 +	gtk_dialog_add_button (
 +		GTK_DIALOG (dialog),
 +		GTK_STOCK_OK, GTK_RESPONSE_OK);
 +
 +	gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
 +	gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
 +
 +	container = content_area;
 +
 +	widget = gtk_hbox_new (FALSE, 6);
 +	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
 +	gtk_widget_show (widget);
 +
 +	container = widget;
 +
 +	widget = gtk_entry_new ();
 +	gtk_entry_set_activates_default (GTK_ENTRY (widget), TRUE);
 +	gtk_box_pack_end (GTK_BOX (container), widget, TRUE, TRUE, 0);
 +	dialog->priv->entry = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	g_signal_connect_swapped (
 +		widget, "changed",
 +		G_CALLBACK (mail_label_dialog_entry_changed_cb), dialog);
 +
 +	mail_label_dialog_entry_changed_cb (dialog);
 +
 +	widget = gtk_label_new_with_mnemonic (_("_Label name:"));
 +	gtk_label_set_mnemonic_widget (
 +		GTK_LABEL (widget), dialog->priv->entry);
 +	gtk_box_pack_end (GTK_BOX (container), widget, FALSE, FALSE, 0);
 +	gtk_widget_show (widget);
 +
 +	container = content_area;
 +
 +	widget = gtk_color_selection_new ();
 +	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
 +	dialog->priv->colorsel = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +}
 +
 +GType
 +e_mail_label_dialog_get_type (void)
 +{
 +	static GType type = 0;
 +
 +	if (G_UNLIKELY (type == 0)) {
 +		static const GTypeInfo type_info = {
 +			sizeof (EMailLabelDialogClass),
 +			(GBaseInitFunc) NULL,
 +			(GBaseFinalizeFunc) NULL,
 +			(GClassInitFunc) mail_label_dialog_class_init,
 +			(GClassFinalizeFunc) NULL,
 +			NULL,  /* class_data */
 +			sizeof (EMailLabelDialog),
 +			0,     /* n_preallocs */
 +			(GInstanceInitFunc) mail_label_dialog_init,
 +			NULL   /* value_table */
 +		};
 +
 +		type = g_type_register_static (
 +			GTK_TYPE_DIALOG, "EMailLabelDialog", &type_info, 0);
 +	}
 +
 +	return type;
 +}
 +
 +GtkWidget *
 +e_mail_label_dialog_new (GtkWindow *parent)
 +{
 +	return g_object_new (
 +		E_TYPE_MAIL_LABEL_DIALOG,
 +		"transient-for", parent, NULL);
 +}
 +
 +const gchar *
 +e_mail_label_dialog_get_label_name (EMailLabelDialog *dialog)
 +{
 +	GtkEntry *entry;
 +
 +	g_return_val_if_fail (E_IS_MAIL_LABEL_DIALOG (dialog), NULL);
 +
 +	entry = GTK_ENTRY (dialog->priv->entry);
 +
 +	return gtk_entry_get_text (entry);
 +}
 +
 +void
 +e_mail_label_dialog_set_label_name (EMailLabelDialog *dialog,
 +                                    const gchar *label_name)
 +{
 +	GtkEntry *entry;
 +
 +	g_return_if_fail (E_IS_MAIL_LABEL_DIALOG (dialog));
 +
 +	entry = GTK_ENTRY (dialog->priv->entry);
 +
 +	gtk_entry_set_text (entry, label_name);
 +
 +	g_object_notify (G_OBJECT (dialog), "label-name");
 +}
 +
 +void
 +e_mail_label_dialog_get_label_color (EMailLabelDialog *dialog,
 +                                     GdkColor *label_color)
 +{
 +	GtkColorSelection *colorsel;
 +
 +	g_return_if_fail (E_IS_MAIL_LABEL_DIALOG (dialog));
 +	g_return_if_fail (label_color != NULL);
 +
 +	colorsel = GTK_COLOR_SELECTION (dialog->priv->colorsel);
 +
 +	gtk_color_selection_get_current_color (colorsel, label_color);
 +}
 +
 +void
 +e_mail_label_dialog_set_label_color (EMailLabelDialog *dialog,
 +                                     const GdkColor *label_color)
 +{
 +	GtkColorSelection *colorsel;
 +
 +	g_return_if_fail (E_IS_MAIL_LABEL_DIALOG (dialog));
 +	g_return_if_fail (label_color != NULL);
 +
 +	colorsel = GTK_COLOR_SELECTION (dialog->priv->colorsel);
 +
 +	gtk_color_selection_set_current_color (colorsel, label_color);
 +
 +	g_object_notify (G_OBJECT (dialog), "label-color");
 +}
diff --cc mail/e-mail-label-dialog.h
index 3a259f6,0000000..17430c3
mode 100644,000000..100644
--- a/mail/e-mail-label-dialog.h
+++ b/mail/e-mail-label-dialog.h
@@@ -1,77 -1,0 +1,77 @@@
 +/*
 + * e-mail-label-dialog.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_MAIL_LABEL_DIALOG_H
 +#define E_MAIL_LABEL_DIALOG_H
 +
 +#include <gtk/gtk.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_MAIL_LABEL_DIALOG \
 +	(e_mail_label_dialog_get_type ())
 +#define E_MAIL_LABEL_DIALOG(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_MAIL_LABEL_DIALOG, EMailLabelDialog))
 +#define E_MAIL_LABEL_DIALOG_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_MAIL_LABEL_DIALOG, EMailLabelDialogClass))
 +#define E_IS_MAIL_LABEL_DIALOG(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_MAIL_LABEL_DIALOG))
 +#define E_IS_MAIL_LABEL_DIALOG_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), E_TYPE_MAIL_LABEL_DIALOG))
 +#define E_MAIL_LABEL_DIALOG_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_MAIL_LABEL_DIALOG, EMailLabelDialogClass))
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _EMailLabelDialog EMailLabelDialog;
 +typedef struct _EMailLabelDialogClass EMailLabelDialogClass;
 +typedef struct _EMailLabelDialogPrivate EMailLabelDialogPrivate;
 +
 +struct _EMailLabelDialog {
 +	GtkDialog parent;
 +	EMailLabelDialogPrivate *priv;
 +};
 +
 +struct _EMailLabelDialogClass {
 +	GtkDialogClass parent_class;
 +};
 +
 +GType		e_mail_label_dialog_get_type	(void);
 +GtkWidget *	e_mail_label_dialog_new		(GtkWindow *parent);
 +const gchar *	e_mail_label_dialog_get_label_name
 +						(EMailLabelDialog *dialog);
 +void		e_mail_label_dialog_set_label_name
 +						(EMailLabelDialog *dialog,
 +						 const gchar *label_name);
 +void		e_mail_label_dialog_get_label_color
 +						(EMailLabelDialog *dialog,
 +						 GdkColor *label_color);
 +void		e_mail_label_dialog_set_label_color
 +						(EMailLabelDialog *dialog,
 +						 const GdkColor *label_color);
 +
 +G_END_DECLS
 +
 +#endif /* E_MAIL_LABEL_DIALOG_H */
diff --cc mail/e-mail-label-list-store.c
index 3892838,0000000..1cbe927
mode 100644,000000..100644
--- a/mail/e-mail-label-list-store.c
+++ b/mail/e-mail-label-list-store.c
@@@ -1,513 -1,0 +1,513 @@@
 +/*
 + * e-mail-label-list-store.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-mail-label-list-store.h"
 +
 +#include <glib/gi18n.h>
 +#include <camel/camel-utf8.h>
 +#include "e-util/gconf-bridge.h"
 +
 +#define E_MAIL_LABEL_LIST_STORE_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_MAIL_LABEL_LIST_STORE, EMailLabelListStorePrivate))
 +
 +struct _EMailLabelListStorePrivate {
 +	GHashTable *tag_index;
 +};
 +
 +static struct {
 +	const gchar *label_name;
 +	const gchar *label_color;
 +	const gchar *label_tag;
 +} label_defaults[] = {
 +	{ N_("I_mportant"), "#EF2929", "$Labelimportant" },	/* red */
 +	{ N_("_Work"),      "#F57900", "$Labelwork" },		/* orange */
 +	{ N_("_Personal"),  "#4E9A06", "$Labelpersonal" },	/* green */
 +	{ N_("_To Do"),     "#3465A4", "$Labeltodo" },		/* blue */
 +	{ N_("_Later"),     "#75507B", "$Labellater" }		/* purple */
 +};
 +
 +static gpointer parent_class;
 +
 +static gchar *
 +mail_label_list_store_tag_from_name (const gchar *label_name)
 +{
 +	gchar *label_tag;
 +	gchar *temp;
 +
 +	/* Thunderbird compatible */
 +	temp = g_ascii_strdown (label_name, -1);
 +	g_strdelimit (temp, " ()/{%*<>\\\"", '_');
 +	label_tag = camel_utf8_utf7 (temp);
 +	g_free (temp);
 +
 +	return label_tag;
 +}
 +
 +static gchar *
 +mail_label_list_store_encode_label (const gchar *label_name,
 +                                      const gchar *label_color,
 +                                      const gchar *label_tag)
 +{
 +	GString *string;
 +
 +	/* Encoded Form: <name> ':' <color> [ '|' <tag> ] */
 +
 +	string = g_string_new (label_name);
 +	g_string_append_printf (string, ":%s", label_color);
 +
 +	if (label_tag != NULL)
 +		g_string_append_printf (string, "|%s", label_tag);
 +
 +	return g_string_free (string, FALSE);
 +}
 +
 +static void
 +mail_label_list_store_ensure_defaults (EMailLabelListStore *store)
 +{
 +	gint ii;
 +
 +	for (ii = 0; ii < G_N_ELEMENTS (label_defaults); ii++) {
 +		GtkTreeIter iter;
 +		const gchar *label_name;
 +		const gchar *label_color;
 +		const gchar *label_tag;
 +		gchar *encoded;
 +
 +		label_name = gettext (label_defaults[ii].label_name);
 +		label_color = label_defaults[ii].label_color;
 +		label_tag = label_defaults[ii].label_tag;
 +
 +		encoded = mail_label_list_store_encode_label (
 +			label_name, label_color, label_tag);
 +
 +		if (e_mail_label_list_store_lookup (store, label_tag, &iter))
 +			gtk_list_store_set (
 +				GTK_LIST_STORE (store),
 +				&iter, 0, encoded, -1);
 +		else
 +			gtk_list_store_insert_with_values (
 +				GTK_LIST_STORE (store),
 +				NULL, -1, 0, encoded, -1);
 +
 +		g_free (encoded);
 +	}
 +}
 +
 +static gchar *
 +mail_label_list_store_get_stock_id (EMailLabelListStore *store,
 +                                    const gchar *color_spec)
 +{
 +	EMailLabelListStoreClass *class;
 +	GtkIconFactory *icon_factory;
 +	GdkColor color;
 +	gchar *stock_id;
 +
 +	class = E_MAIL_LABEL_LIST_STORE_GET_CLASS (store);
 +	icon_factory = class->icon_factory;
 +
 +	if (!gdk_color_parse (color_spec, &color))
 +		return NULL;
 +
 +	stock_id = g_strdup_printf ("evolution-label-%s", color_spec);
 +
 +	/* Themes need not be taken into account here.
 +	 * It's just a solid block of a user-chosen color. */
 +	if (gtk_icon_factory_lookup (icon_factory, stock_id) == NULL) {
 +		GtkIconSet *icon_set;
 +		GdkPixbuf *pixbuf;
 +		guint32 pixel;
 +
 +		pixel = ((color.red & 0xFF00) << 16) +
 +			((color.green & 0xFF00) << 8) +
 +			(color.blue & 0xFF00);
 +
 +		pixbuf = gdk_pixbuf_new (
 +			GDK_COLORSPACE_RGB, FALSE, 8, 16, 16);
 +		gdk_pixbuf_fill (pixbuf, pixel);
 +
 +		icon_set = gtk_icon_set_new_from_pixbuf (pixbuf);
 +		gtk_icon_factory_add (icon_factory, stock_id, icon_set);
 +		gtk_icon_set_unref (icon_set);
 +
 +		g_object_unref (pixbuf);
 +	}
 +
 +	return stock_id;
 +}
 +
 +static void
 +mail_label_list_store_finalize (GObject *object)
 +{
 +	EMailLabelListStorePrivate *priv;
 +
 +	priv = E_MAIL_LABEL_LIST_STORE_GET_PRIVATE (object);
 +
 +	g_hash_table_destroy (priv->tag_index);
 +
 +	/* Chain up to parent's finalize() method. */
 +	G_OBJECT_CLASS (parent_class)->finalize (object);
 +}
 +
 +static void
 +mail_label_list_store_constructed (GObject *object)
 +{
 +	EMailLabelListStore *store;
 +	GtkTreeModel *model;
 +	GConfBridge *bridge;
 +	const gchar *key;
 +
 +	model = GTK_TREE_MODEL (object);
 +	store = E_MAIL_LABEL_LIST_STORE (object);
 +
 +	bridge = gconf_bridge_get ();
 +	key = "/apps/evolution/mail/labels";
 +	gconf_bridge_bind_string_list_store (
 +		bridge, key, GTK_LIST_STORE (store));
 +
 +	mail_label_list_store_ensure_defaults (store);
 +}
 +
 +static void
 +mail_label_list_store_row_inserted (GtkTreeModel *model,
 +                                    GtkTreePath *path,
 +                                    GtkTreeIter *iter)
 +{
 +	EMailLabelListStore *store;
 +	GtkTreeRowReference *reference;
 +	GHashTable *tag_index;
 +	gchar *tag;
 +
 +	store = E_MAIL_LABEL_LIST_STORE (model);
 +
 +	/* Hash table takes ownership of both tag and reference. */
 +	tag_index = store->priv->tag_index;
 +	tag = e_mail_label_list_store_get_tag (store, iter);
 +	reference = gtk_tree_row_reference_new (model, path);
 +	g_hash_table_insert (tag_index, tag, reference);
 +
 +	/* We don't need to do anything special for row deletion.
 +	 * The reference will automatically become invalid (that's
 +	 * why we're storing references and not iterators or paths),
 +	 * so garbage collection is not important.  We'll do it
 +	 * lazily. */
 +}
 +
 +static void
 +mail_label_list_store_class_init (EMailLabelListStoreClass *class)
 +{
 +	GObjectClass *object_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (EMailLabelListStorePrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->finalize = mail_label_list_store_finalize;
 +	object_class->constructed = mail_label_list_store_constructed;
 +
 +	class->icon_factory = gtk_icon_factory_new ();
 +	gtk_icon_factory_add_default (class->icon_factory);
 +}
 +
 +static void
 +mail_label_list_store_init (EMailLabelListStore *store)
 +{
 +	GHashTable *tag_index;
 +	GType type = G_TYPE_STRING;
 +
 +	tag_index = g_hash_table_new_full (
 +		g_str_hash, g_str_equal,
 +		(GDestroyNotify) g_free,
 +		(GDestroyNotify) gtk_tree_row_reference_free);
 +
 +	store->priv = E_MAIL_LABEL_LIST_STORE_GET_PRIVATE (store);
 +	store->priv->tag_index = tag_index;
 +
 +	/* XXX While it may seem awkward to cram the label name and color
 +	 *     into a single string column, we do it for the benefit of
 +	 *     letting GConfBridge keep the model in sync with GConf.
 +	 *
 +	 * XXX There's a valid argument to be made that this information
 +	 *     doesn't belong in GConf in the first place.  A key file
 +	 *     under $(user_data_dir)/mail would work better. */
 +	gtk_list_store_set_column_types (GTK_LIST_STORE (store), 1, &type);
 +}
 +
 +static void
 +mail_label_list_store_iface_init (GtkTreeModelIface *iface)
 +{
 +	iface->row_inserted = mail_label_list_store_row_inserted;
 +}
 +
 +GType
 +e_mail_label_list_store_get_type (void)
 +{
 +	static GType type = 0;
 +
 +	if (G_UNLIKELY (type == 0)) {
 +		static const GTypeInfo type_info = {
 +			sizeof (EMailLabelListStoreClass),
 +			(GBaseInitFunc) NULL,
 +			(GBaseFinalizeFunc) NULL,
 +			(GClassInitFunc) mail_label_list_store_class_init,
 +			(GClassFinalizeFunc) NULL,
 +			NULL,  /* class_data */
 +			sizeof (EMailLabelListStore),
 +			0,     /* n_preallocs */
 +			(GInstanceInitFunc) mail_label_list_store_init,
 +			NULL   /* vaule_table */
 +		};
 +
 +		static const GInterfaceInfo iface_info = {
 +			(GInterfaceInitFunc) mail_label_list_store_iface_init,
 +			(GInterfaceFinalizeFunc) NULL,
 +			NULL   /* interface_data */
 +		};
 +
 +		type = g_type_register_static (
 +			GTK_TYPE_LIST_STORE, "EMailLabelListStore",
 +			&type_info, 0);
 +
 +		g_type_add_interface_static (
 +			type, GTK_TYPE_TREE_MODEL, &iface_info);
 +	}
 +
 +	return type;
 +}
 +
 +EMailLabelListStore *
 +e_mail_label_list_store_new (void)
 +{
 +	return g_object_new (E_TYPE_MAIL_LABEL_LIST_STORE, NULL);
 +}
 +
 +gchar *
 +e_mail_label_list_store_get_name (EMailLabelListStore *store,
 +                                  GtkTreeIter *iter)
 +{
 +	gchar *encoded;
 +	gchar *result;
 +	gchar **strv;
 +
 +	/* Encoded Form: <name> ':' <color> [ '|' <tag> ] */
 +
 +	g_return_val_if_fail (E_IS_MAIL_LABEL_LIST_STORE (store), NULL);
 +	g_return_val_if_fail (iter != NULL, NULL);
 +
 +	gtk_tree_model_get (GTK_TREE_MODEL (store), iter, 0, &encoded, -1);
 +
 +	strv = g_strsplit_set (encoded, ":|", 3);
 +
 +	if (g_strv_length (strv) >= 2)
 +		result = g_strdup (gettext (strv[0]));
 +	else
 +		result = NULL;
 +
 +	g_strfreev (strv);
 +
 +	return result;
 +}
 +
 +gboolean
 +e_mail_label_list_store_get_color (EMailLabelListStore *store,
 +                                   GtkTreeIter *iter,
 +                                   GdkColor *color)
 +{
 +	gchar *encoded;
 +	gchar **strv;
 +	gboolean valid;
 +
 +	/* Encoded Form: <name> ':' <color> [ '|' <tag> ] */
 +
 +	g_return_val_if_fail (E_IS_MAIL_LABEL_LIST_STORE (store), FALSE);
 +	g_return_val_if_fail (iter != NULL, FALSE);
 +	g_return_val_if_fail (color != NULL, FALSE);
 +
 +	gtk_tree_model_get (GTK_TREE_MODEL (store), iter, 0, &encoded, -1);
 +
 +	strv = g_strsplit_set (encoded, ":|", 3);
 +
 +	if (g_strv_length (strv) >= 2)
 +		valid = gdk_color_parse (strv[1], color);
 +	else
 +		valid = FALSE;
 +
 +	g_strfreev (strv);
 +
 +	return valid;
 +}
 +
 +gchar *
 +e_mail_label_list_store_get_stock_id (EMailLabelListStore *store,
 +                                      GtkTreeIter *iter)
 +{
 +	gchar *encoded;
 +	gchar *result;
 +	gchar **strv;
 +
 +	/* Encoded Form: <name> ':' <color> [ '|' <tag> ] */
 +
 +	g_return_val_if_fail (E_IS_MAIL_LABEL_LIST_STORE (store), NULL);
 +	g_return_val_if_fail (iter != NULL, NULL);
 +	gtk_tree_model_get (GTK_TREE_MODEL (store), iter, 0, &encoded, -1);
 +
 +	strv = g_strsplit_set (encoded, ":|", 3);
 +
 +	if (g_strv_length (strv) >= 2)
 +		result = mail_label_list_store_get_stock_id (store, strv[1]);
 +	else
 +		result = NULL;
 +
 +	g_strfreev (strv);
 +
 +	return result;
 +}
 +
 +gchar *
 +e_mail_label_list_store_get_tag (EMailLabelListStore *store,
 +                                 GtkTreeIter *iter)
 +{
 +	gchar *encoded;
 +	gchar *result;
 +	gchar **strv;
 +
 +	/* Encoded Form: <name> ':' <color> [ '|' <tag> ] */
 +
 +	g_return_val_if_fail (E_IS_MAIL_LABEL_LIST_STORE (store), NULL);
 +	g_return_val_if_fail (iter != NULL, NULL);
 +
 +	gtk_tree_model_get (GTK_TREE_MODEL (store), iter, 0, &encoded, -1);
 +
 +	strv = g_strsplit_set (encoded, ":|", 3);
 +
 +	/* XXX I guess for historical reasons the default label tags have
 +	 *     a "$Label" prefix, but the default list in GConf doesn't
 +	 *     include tags.  That's why the <tag> part is optional.
 +	 *     So if we're missing the <tag> part, look it up in the
 +	 *     hard-coded default list above.
 +	 *
 +	 *     Not sure I got my facts straight here.  Double check. */
 +	if (g_strv_length (strv) >= 3)
 +		result = g_strdup (strv[2]);
 +	else {
 +		gint ii;
 +
 +		result = NULL;
 +
 +		for (ii = 0; ii < G_N_ELEMENTS (label_defaults); ii++) {
 +			const gchar *label_name;
 +			const gchar *label_tag;
 +
 +			label_name = label_defaults[ii].label_name;
 +			label_tag = label_defaults[ii].label_tag;
 +
 +			if (strcmp (strv[0], label_name) == 0) {
 +				result = g_strdup (label_tag);
 +				break;
 +			}
 +		}
 +	}
 +
 +	g_strfreev (strv);
 +
 +	return result;
 +}
 +
 +void
 +e_mail_label_list_store_set (EMailLabelListStore *store,
 +                             GtkTreeIter *iter,
 +                             const gchar *name,
 +                             const GdkColor *color)
 +{
 +	gchar *encoded;
 +	gchar *label_color;
 +	gchar *label_tag = NULL;
 +
 +	g_return_if_fail (E_IS_MAIL_LABEL_LIST_STORE (store));
 +	g_return_if_fail (name != NULL);
 +	g_return_if_fail (color != NULL);
 +
 +	label_color = gdk_color_to_string (color);
 +
 +	if (iter != NULL)
 +		label_tag = e_mail_label_list_store_get_tag (store, iter);
 +	if (label_tag == NULL)
 +		label_tag = mail_label_list_store_tag_from_name (name);
 +
 +	encoded = mail_label_list_store_encode_label (
 +		name, label_color, label_tag);
 +
 +	/* We use gtk_list_store_insert_with_values() so the data is
 +	 * in place when the 'row-inserted' signal is emitted and our
 +	 * row_inserted() method executes. */
 +	if (iter != NULL)
 +		gtk_list_store_set (
 +			GTK_LIST_STORE (store), iter, 0, encoded, -1);
 +	else
 +		gtk_list_store_insert_with_values (
 +			GTK_LIST_STORE (store), NULL, -1, 0, encoded, -1);
 +
 +	g_free (label_color);
 +	g_free (label_tag);
 +	g_free (encoded);
 +}
 +
 +gboolean
 +e_mail_label_list_store_lookup (EMailLabelListStore *store,
 +                                const gchar *tag,
 +                                GtkTreeIter *iter)
 +{
 +	GtkTreeRowReference *reference;
 +	GHashTable *tag_index;
 +	GtkTreeModel *model;
 +	GtkTreePath *path;
 +
 +	g_return_val_if_fail (E_IS_MAIL_LABEL_LIST_STORE (store), FALSE);
 +	g_return_val_if_fail (tag != NULL, FALSE);
 +	g_return_val_if_fail (iter != NULL, FALSE);
 +
 +	tag_index = store->priv->tag_index;
 +	reference = g_hash_table_lookup (tag_index, tag);
 +
 +	if (reference == NULL)
 +		return FALSE;
 +
 +	if (!gtk_tree_row_reference_valid (reference)) {
 +		/* Garbage collect the dead reference. */
 +		g_hash_table_remove (tag_index, tag);
 +		return FALSE;
 +	}
 +
 +	model = gtk_tree_row_reference_get_model (reference);
 +	path = gtk_tree_row_reference_get_path (reference);
 +	gtk_tree_model_get_iter (model, iter, path);
 +	gtk_tree_path_free (path);
 +
 +	return TRUE;
 +}
 +
 +gboolean
 +e_mail_label_tag_is_default (const gchar *tag)
 +{
 +	g_return_val_if_fail (tag != NULL, FALSE);
 +
 +	return g_str_has_prefix (tag, "$Label");
 +}
diff --cc mail/e-mail-label-list-store.h
index 2469d21,0000000..a9093ea
mode 100644,000000..100644
--- a/mail/e-mail-label-list-store.h
+++ b/mail/e-mail-label-list-store.h
@@@ -1,85 -1,0 +1,85 @@@
 +/*
 + * e-mail-label-list-store.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_MAIL_LABEL_LIST_STORE_H
 +#define E_MAIL_LABEL_LIST_STORE_H
 +
 +#include <gtk/gtk.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_MAIL_LABEL_LIST_STORE \
 +	(e_mail_label_list_store_get_type ())
 +#define E_MAIL_LABEL_LIST_STORE(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_MAIL_LABEL_LIST_STORE, EMailLabelListStore))
 +#define E_MAIL_LABEL_LIST_STORE_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_MAIL_LABEL_LIST_STORE, EMailLabelListStoreClass))
 +#define E_IS_MAIL_LABEL_LIST_STORE(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_MAIL_LABEL_LIST_STORE))
 +#define E_IS_MAIL_LABEL_LIST_STORE_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), E_TYPE_MAIL_LABEL_LIST_STORE))
 +#define E_MAIL_LABEL_LIST_STORE_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_MAIL_LABEL_LIST_STORE, EMailLabelListStoreClass))
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _EMailLabelListStore EMailLabelListStore;
 +typedef struct _EMailLabelListStoreClass EMailLabelListStoreClass;
 +typedef struct _EMailLabelListStorePrivate EMailLabelListStorePrivate;
 +
 +struct _EMailLabelListStore {
 +	GtkListStore parent;
 +	EMailLabelListStorePrivate *priv;
 +};
 +
 +struct _EMailLabelListStoreClass {
 +	GtkListStoreClass parent_class;
 +	GtkIconFactory *icon_factory;
 +};
 +
 +GType		e_mail_label_list_store_get_type	(void);
 +EMailLabelListStore *
 +		e_mail_label_list_store_new		(void);
 +gchar *		e_mail_label_list_store_get_name	(EMailLabelListStore *store,
 +							 GtkTreeIter *iter);
 +gboolean	e_mail_label_list_store_get_color	(EMailLabelListStore *store,
 +							 GtkTreeIter *iter,
 +							 GdkColor *color);
 +gchar *		e_mail_label_list_store_get_stock_id	(EMailLabelListStore *store,
 +							 GtkTreeIter *iter);
 +gchar *		e_mail_label_list_store_get_tag		(EMailLabelListStore *store,
 +							 GtkTreeIter *iter);
 +void		e_mail_label_list_store_set		(EMailLabelListStore *store,
 +							 GtkTreeIter *iter,
 +							 const gchar *name,
 +							 const GdkColor *color);
 +gboolean	e_mail_label_list_store_lookup		(EMailLabelListStore *store,
 +							 const gchar *tag,
 +							 GtkTreeIter *iter);
 +gboolean	e_mail_label_tag_is_default		(const gchar *tag);
 +
 +G_END_DECLS
 +
 +#endif /* E_MAIL_LABEL_LIST_STORE_H */
diff --cc mail/e-mail-label-manager.c
index fc18da3,0000000..212a050
mode 100644,000000..100644
--- a/mail/e-mail-label-manager.c
+++ b/mail/e-mail-label-manager.c
@@@ -1,479 -1,0 +1,479 @@@
 +/*
 + * e-mail-label-manager.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-mail-label-manager.h"
 +
 +#include <glib/gi18n.h>
 +#include "e-mail-label-dialog.h"
 +#include "e-mail-label-tree-view.h"
 +
 +#define E_MAIL_LABEL_MANAGER_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_MAIL_LABEL_MANAGER, EMailLabelManagerPrivate))
 +
 +struct _EMailLabelManagerPrivate {
 +	GtkWidget *tree_view;
 +	GtkWidget *add_button;
 +	GtkWidget *edit_button;
 +	GtkWidget *remove_button;
 +};
 +
 +enum {
 +	PROP_0,
 +	PROP_LIST_STORE
 +};
 +
 +enum {
 +	ADD_LABEL,
 +	EDIT_LABEL,
 +	REMOVE_LABEL,
 +	LAST_SIGNAL
 +};
 +
 +static gpointer parent_class;
 +static guint signals[LAST_SIGNAL];
 +
 +static void
 +mail_label_manager_selection_changed_cb (EMailLabelManager *manager,
 +                                         GtkTreeSelection *selection)
 +{
 +	GtkWidget *edit_button;
 +	GtkWidget *remove_button;
 +	GtkTreeModel *model;
 +	GtkTreeIter iter;
 +
 +	edit_button = manager->priv->edit_button;
 +	remove_button = manager->priv->remove_button;
 +
 +	if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
 +		EMailLabelListStore *store;
 +		gboolean sensitive;
 +		gchar *label_tag;
 +
 +		store = E_MAIL_LABEL_LIST_STORE (model);
 +		label_tag = e_mail_label_list_store_get_tag (store, &iter);
 +		sensitive = !e_mail_label_tag_is_default (label_tag);
 +		g_free (label_tag);
 +
 +		/* Disallow removing default labels. */
 +		gtk_widget_set_sensitive (edit_button, TRUE);
 +		gtk_widget_set_sensitive (remove_button, sensitive);
 +	} else {
 +		gtk_widget_set_sensitive (edit_button, FALSE);
 +		gtk_widget_set_sensitive (remove_button, FALSE);
 +	}
 +}
 +
 +static void
 +mail_label_manager_set_property (GObject *object,
 +                                 guint property_id,
 +                                 const GValue *value,
 +                                 GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_LIST_STORE:
 +			e_mail_label_manager_set_list_store (
 +				E_MAIL_LABEL_MANAGER (object),
 +				g_value_get_object (value));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +mail_label_manager_get_property (GObject *object,
 +                                 guint property_id,
 +                                 GValue *value,
 +                                 GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_LIST_STORE:
 +			g_value_set_object (
 +				value, e_mail_label_manager_get_list_store (
 +				E_MAIL_LABEL_MANAGER (object)));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +mail_label_manager_dispose (GObject *object)
 +{
 +	EMailLabelManagerPrivate *priv;
 +
 +	priv = E_MAIL_LABEL_MANAGER_GET_PRIVATE (object);
 +
 +	if (priv->tree_view != NULL) {
 +		g_object_unref (priv->tree_view);
 +		priv->tree_view = NULL;
 +	}
 +
 +	if (priv->add_button != NULL) {
 +		g_object_unref (priv->add_button);
 +		priv->add_button = NULL;
 +	}
 +
 +	if (priv->edit_button != NULL) {
 +		g_object_unref (priv->edit_button);
 +		priv->edit_button = NULL;
 +	}
 +
 +	if (priv->remove_button != NULL) {
 +		g_object_unref (priv->remove_button);
 +		priv->remove_button = NULL;
 +	}
 +
 +	/* Chain up to parent's dispose() method. */
 +	G_OBJECT_CLASS (parent_class)->dispose (object);
 +}
 +
 +static void
 +mail_label_manager_add_label (EMailLabelManager *manager)
 +{
 +	EMailLabelDialog *label_dialog;
 +	GtkTreeView *tree_view;
 +	GtkTreeModel *model;
 +	GtkWidget *dialog;
 +	gpointer parent;
 +	GdkColor label_color;
 +	const gchar *label_name;
 +
 +	parent = gtk_widget_get_toplevel (GTK_WIDGET (manager));
 +	parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL;
 +	dialog = e_mail_label_dialog_new (parent);
 +
 +	gtk_window_set_title (GTK_WINDOW (dialog), _("Add Label"));
 +
 +	if (gtk_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_OK)
 +		goto exit;
 +
 +	label_dialog = E_MAIL_LABEL_DIALOG (dialog);
 +	label_name = e_mail_label_dialog_get_label_name (label_dialog);
 +	e_mail_label_dialog_get_label_color (label_dialog, &label_color);
 +
 +	tree_view = GTK_TREE_VIEW (manager->priv->tree_view);
 +	model = gtk_tree_view_get_model (tree_view);
 +
 +	e_mail_label_list_store_set (
 +		E_MAIL_LABEL_LIST_STORE (model),
 +		NULL, label_name, &label_color);
 +
 +exit:
 +	gtk_widget_destroy (dialog);
 +}
 +
 +static void
 +mail_label_manager_edit_label (EMailLabelManager *manager)
 +{
 +	EMailLabelDialog *label_dialog;
 +	EMailLabelListStore *label_store;
 +	GtkTreeSelection *selection;
 +	GtkTreeView *tree_view;
 +	GtkTreeModel *model;
 +	GtkTreeIter iter;
 +	GtkWidget *dialog;
 +	GtkWidget *parent;
 +	GdkColor label_color;
 +	const gchar *new_name;
 +	gchar *label_name;
 +
 +	tree_view = GTK_TREE_VIEW (manager->priv->tree_view);
 +	selection = gtk_tree_view_get_selection (tree_view);
 +
 +	if (!gtk_tree_selection_get_selected (selection, &model, &iter))
 +		return;
 +
 +	label_store = E_MAIL_LABEL_LIST_STORE (model);
 +	label_name = e_mail_label_list_store_get_name (label_store, &iter);
 +	e_mail_label_list_store_get_color (label_store, &iter, &label_color);
 +
 +	parent = gtk_widget_get_toplevel (GTK_WIDGET (manager));
 +	dialog = e_mail_label_dialog_new (GTK_WINDOW (parent));
 +	label_dialog = E_MAIL_LABEL_DIALOG (dialog);
 +
 +	e_mail_label_dialog_set_label_name (label_dialog, label_name);
 +	e_mail_label_dialog_set_label_color (label_dialog, &label_color);
 +	gtk_window_set_title (GTK_WINDOW (dialog), _("Edit Label"));
 +
 +	if (gtk_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_OK)
 +		goto exit;
 +
 +	new_name = e_mail_label_dialog_get_label_name (label_dialog);
 +	e_mail_label_dialog_get_label_color (label_dialog, &label_color);
 +
 +	e_mail_label_list_store_set (
 +		label_store, &iter, new_name, &label_color);
 +
 +exit:
 +	gtk_widget_destroy (dialog);
 +
 +	g_free (label_name);
 +}
 +
 +static void
 +mail_label_manager_remove_label (EMailLabelManager *manager)
 +{
 +	GtkTreeSelection *selection;
 +	GtkTreeView *tree_view;
 +	GtkTreeModel *model;
 +	GtkTreeIter iter;
 +
 +	tree_view = GTK_TREE_VIEW (manager->priv->tree_view);
 +	selection = gtk_tree_view_get_selection (tree_view);
 +
 +	if (!gtk_tree_selection_get_selected (selection, &model, &iter))
 +		return;
 +
 +	gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
 +}
 +
 +static void
 +mail_label_manager_class_init (EMailLabelManagerClass *class)
 +{
 +	GObjectClass *object_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (EMailLabelManagerPrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->set_property = mail_label_manager_set_property;
 +	object_class->get_property = mail_label_manager_get_property;
 +	object_class->dispose = mail_label_manager_dispose;
 +
 +	class->add_label = mail_label_manager_add_label;
 +	class->edit_label = mail_label_manager_edit_label;
 +	class->remove_label = mail_label_manager_remove_label;
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_LIST_STORE,
 +		g_param_spec_object (
 +			"list-store",
 +			"List Store",
 +			NULL,
 +			E_TYPE_MAIL_LABEL_LIST_STORE,
 +			G_PARAM_READWRITE));
 +
 +	signals[ADD_LABEL] = g_signal_new (
 +		"add-label",
 +		G_OBJECT_CLASS_TYPE (class),
 +		G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
 +		G_STRUCT_OFFSET (EMailLabelManagerClass, add_label),
 +		NULL, NULL,
 +		g_cclosure_marshal_VOID__VOID,
 +		G_TYPE_NONE, 0);
 +
 +	signals[EDIT_LABEL] = g_signal_new (
 +		"edit-label",
 +		G_OBJECT_CLASS_TYPE (class),
 +		G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
 +		G_STRUCT_OFFSET (EMailLabelManagerClass, edit_label),
 +		NULL, NULL,
 +		g_cclosure_marshal_VOID__VOID,
 +		G_TYPE_NONE, 0);
 +
 +	signals[REMOVE_LABEL] = g_signal_new (
 +		"remove-label",
 +		G_OBJECT_CLASS_TYPE (class),
 +		G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
 +		G_STRUCT_OFFSET (EMailLabelManagerClass, remove_label),
 +		NULL, NULL,
 +		g_cclosure_marshal_VOID__VOID,
 +		G_TYPE_NONE, 0);
 +}
 +
 +static void
 +mail_label_manager_init (EMailLabelManager *manager)
 +{
 +	GtkTreeSelection *selection;
 +	GtkWidget *container;
 +	GtkWidget *widget;
 +
 +	manager->priv = E_MAIL_LABEL_MANAGER_GET_PRIVATE (manager);
 +
 +	gtk_table_resize (GTK_TABLE (manager), 2, 2);
 +	gtk_table_set_col_spacings (GTK_TABLE (manager), 6);
 +	gtk_table_set_row_spacings (GTK_TABLE (manager), 12);
 +
 +	container = GTK_WIDGET (manager);
 +
 +	widget = gtk_scrolled_window_new (NULL, NULL);
 +	gtk_scrolled_window_set_policy (
 +		GTK_SCROLLED_WINDOW (widget),
 +		GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
 +	gtk_scrolled_window_set_shadow_type (
 +		GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
 +	gtk_table_attach (
 +		GTK_TABLE (container), widget, 0, 1, 0, 1,
 +		GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
 +	gtk_widget_show (widget);
 +
 +	container = widget;
 +
 +	widget = e_mail_label_tree_view_new ();
 +	gtk_container_add (GTK_CONTAINER (container), widget);
 +	manager->priv->tree_view = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
 +
 +	g_signal_connect_swapped (
 +		selection, "changed",
 +		G_CALLBACK (mail_label_manager_selection_changed_cb),
 +		manager);
 +
 +	container = GTK_WIDGET (manager);
 +
 +	/* FIXME Clarify this.  What menu? */
 +	widget = gtk_label_new (
 +		_("Note: Underscore in the label name is used\n"
 +		  "as mnemonic identifier in menu."));
 +	gtk_label_set_justify (GTK_LABEL (widget), GTK_JUSTIFY_CENTER);
 +	gtk_table_attach (
 +		GTK_TABLE (container), widget,
 +		0, 1, 1, 2, 0, 0, 0, 0);
 +	gtk_widget_show (widget);
 +
 +	widget = gtk_vbutton_box_new ();
 +	gtk_button_box_set_layout (
 +		GTK_BUTTON_BOX (widget), GTK_BUTTONBOX_START);
 +	gtk_box_set_spacing (GTK_BOX (widget), 6);
 +	gtk_table_attach (
 +		GTK_TABLE (container), widget,
 +		1, 2, 0, 2, 0, GTK_FILL, 0, 0);
 +	gtk_widget_show (widget);
 +
 +	container = widget;
 +
 +	widget = gtk_button_new_from_stock (GTK_STOCK_ADD);
 +	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
 +	manager->priv->add_button = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	g_signal_connect_swapped (
 +		widget, "clicked",
 +		G_CALLBACK (e_mail_label_manager_add_label), manager);
 +
 +	widget = gtk_button_new_from_stock (GTK_STOCK_EDIT);
 +	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
 +	manager->priv->edit_button = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	g_signal_connect_swapped (
 +		widget, "clicked",
 +		G_CALLBACK (e_mail_label_manager_edit_label), manager);
 +
 +	widget = gtk_button_new_from_stock (GTK_STOCK_REMOVE);
 +	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
 +	manager->priv->remove_button = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	g_signal_connect_swapped (
 +		widget, "clicked",
 +		G_CALLBACK (e_mail_label_manager_remove_label), manager);
 +}
 +
 +GType
 +e_mail_label_manager_get_type (void)
 +{
 +	static GType type = 0;
 +
 +	if (G_UNLIKELY (type == 0)) {
 +		static const GTypeInfo type_info = {
 +			sizeof (EMailLabelManagerClass),
 +			(GBaseInitFunc) NULL,
 +			(GBaseFinalizeFunc) NULL,
 +			(GClassInitFunc) mail_label_manager_class_init,
 +			(GClassFinalizeFunc) NULL,
 +			NULL,  /* class_data */
 +			sizeof (EMailLabelManager),
 +			0,     /* n_preallocs */
 +			(GInstanceInitFunc) mail_label_manager_init,
 +			NULL   /* value_table */
 +		};
 +
 +		type = g_type_register_static (
 +			GTK_TYPE_TABLE, "EMailLabelManager", &type_info, 0);
 +	}
 +
 +	return type;
 +}
 +
 +GtkWidget *
 +e_mail_label_manager_new (void)
 +{
 +	return g_object_new (E_TYPE_MAIL_LABEL_MANAGER, NULL);
 +}
 +
 +void
 +e_mail_label_manager_add_label (EMailLabelManager *manager)
 +{
 +	g_return_if_fail (E_IS_MAIL_LABEL_MANAGER (manager));
 +
 +	g_signal_emit (manager, signals[ADD_LABEL], 0);
 +}
 +
 +void
 +e_mail_label_manager_edit_label (EMailLabelManager *manager)
 +{
 +	g_return_if_fail (E_IS_MAIL_LABEL_MANAGER (manager));
 +
 +	g_signal_emit (manager, signals[EDIT_LABEL], 0);
 +}
 +
 +void
 +e_mail_label_manager_remove_label (EMailLabelManager *manager)
 +{
 +	g_return_if_fail (E_IS_MAIL_LABEL_MANAGER (manager));
 +
 +	g_signal_emit (manager, signals[REMOVE_LABEL], 0);
 +}
 +
 +EMailLabelListStore *
 +e_mail_label_manager_get_list_store (EMailLabelManager *manager)
 +{
 +	GtkTreeView *tree_view;
 +	GtkTreeModel *model;
 +
 +	g_return_val_if_fail (E_IS_MAIL_LABEL_MANAGER (manager), NULL);
 +
 +	tree_view = GTK_TREE_VIEW (manager->priv->tree_view);
 +	model = gtk_tree_view_get_model (tree_view);
 +
 +	return E_MAIL_LABEL_LIST_STORE (model);
 +}
 +
 +void
 +e_mail_label_manager_set_list_store (EMailLabelManager *manager,
 +                                     EMailLabelListStore *list_store)
 +{
 +	GtkTreeView *tree_view;
 +
 +	g_return_if_fail (E_IS_MAIL_LABEL_MANAGER (manager));
 +	g_return_if_fail (E_IS_MAIL_LABEL_LIST_STORE (list_store));
 +
 +	tree_view = GTK_TREE_VIEW (manager->priv->tree_view);
 +	gtk_tree_view_set_model (tree_view, GTK_TREE_MODEL (list_store));
 +
 +	g_object_notify (G_OBJECT (manager), "list-store");
 +}
diff --cc mail/e-mail-label-manager.h
index 0a36ee2,0000000..20d375e
mode 100644,000000..100644
--- a/mail/e-mail-label-manager.h
+++ b/mail/e-mail-label-manager.h
@@@ -1,81 -1,0 +1,81 @@@
 +/*
 + * e-mail-label-manager.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_MAIL_LABEL_MANAGER_H
 +#define E_MAIL_LABEL_MANAGER_H
 +
 +#include <gtk/gtk.h>
 +#include <mail/e-mail-label-list-store.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_MAIL_LABEL_MANAGER \
 +	(e_mail_label_manager_get_type ())
 +#define E_MAIL_LABEL_MANAGER(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_MAIL_LABEL_MANAGER, EMailLabelManager))
 +#define E_MAIL_LABEL_MANAGER_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_MAIL_LABEL_MANAGER, EMailLabelManagerClass))
 +#define E_IS_MAIL_LABEL_MANAGER(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_MAIL_LABEL_MANAGER))
 +#define E_IS_MAIL_LABEL_MANAGER_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), E_TYPE_MAIL_LABEL_MANAGER))
 +#define E_MAIL_LABEL_MANAGER_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_MAIL_LABEL_MANAGER, EMailLabelManagerClass))
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _EMailLabelManager EMailLabelManager;
 +typedef struct _EMailLabelManagerClass EMailLabelManagerClass;
 +typedef struct _EMailLabelManagerPrivate EMailLabelManagerPrivate;
 +
 +struct _EMailLabelManager {
 +	GtkTable parent;
 +	EMailLabelManagerPrivate *priv;
 +};
 +
 +struct _EMailLabelManagerClass {
 +	GtkTableClass parent_class;
 +
 +	void		(*add_label)		(EMailLabelManager *manager);
 +	void		(*edit_label)		(EMailLabelManager *manager);
 +	void		(*remove_label)		(EMailLabelManager *manager);
 +};
 +
 +GType		e_mail_label_manager_get_type	(void);
 +GtkWidget *	e_mail_label_manager_new	(void);
 +void		e_mail_label_manager_add_label	(EMailLabelManager *manager);
 +void		e_mail_label_manager_edit_label	(EMailLabelManager *manager);
 +void		e_mail_label_manager_remove_label
 +						(EMailLabelManager *manager);
 +EMailLabelListStore *
 +		e_mail_label_manager_get_list_store
 +						(EMailLabelManager *manager);
 +void		e_mail_label_manager_set_list_store
 +						(EMailLabelManager *manager,
 +						 EMailLabelListStore *list_store);
 +
 +G_END_DECLS
 +
 +#endif /* E_MAIL_LABEL_MANAGER_H */
diff --cc mail/e-mail-label-tree-view.c
index 5675329,0000000..808d8d0
mode 100644,000000..100644
--- a/mail/e-mail-label-tree-view.c
+++ b/mail/e-mail-label-tree-view.c
@@@ -1,136 -1,0 +1,136 @@@
 +/*
 + * e-mail-label-tree-view.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-mail-label-tree-view.h"
 +
 +#include <glib/gi18n.h>
 +#include "e-mail-label-list-store.h"
 +
 +#define E_MAIL_LABEL_TREE_VIEW_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_MAIL_LABEL_TREE_VIEW, EMailLabelTreeViewPrivate))
 +
 +struct _EMailLabelTreeViewPrivate {
 +	gint placeholder;
 +};
 +
 +static gpointer parent_class;
 +
 +static void
 +mail_label_tree_view_render_pixbuf (GtkTreeViewColumn *column,
 +                                    GtkCellRenderer *renderer,
 +                                    GtkTreeModel *model,
 +                                    GtkTreeIter *iter,
 +                                    EMailLabelTreeView *tree_view)
 +{
 +	EMailLabelListStore *store;
 +	gchar *stock_id;
 +
 +	store = E_MAIL_LABEL_LIST_STORE (model);
 +	stock_id = e_mail_label_list_store_get_stock_id (store, iter);
 +	g_object_set (renderer, "stock-id", stock_id, NULL);
 +	g_free (stock_id);
 +}
 +
 +static void
 +mail_label_tree_view_render_text (GtkTreeViewColumn *column,
 +                                  GtkCellRenderer *renderer,
 +                                  GtkTreeModel *model,
 +                                  GtkTreeIter *iter,
 +                                  EMailLabelTreeView *tree_view)
 +{
 +	EMailLabelListStore *store;
 +	gchar *name;
 +
 +	store = E_MAIL_LABEL_LIST_STORE (model);
 +	name = e_mail_label_list_store_get_name (store, iter);
 +	g_object_set (renderer, "text", name, NULL);
 +	g_free (name);
 +}
 +
 +static void
 +mail_label_tree_view_class_init (EMailLabelTreeViewClass *class)
 +{
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (EMailLabelTreeViewPrivate));
 +}
 +
 +static void
 +mail_label_tree_view_init (EMailLabelTreeView *tree_view)
 +{
 +	GtkTreeViewColumn *column;
 +	GtkCellRenderer *renderer;
 +
 +	tree_view->priv = E_MAIL_LABEL_TREE_VIEW_GET_PRIVATE (tree_view);
 +
 +	column = gtk_tree_view_column_new ();
 +	renderer = gtk_cell_renderer_pixbuf_new ();
 +	gtk_tree_view_column_set_title (column, _("Color"));
 +	gtk_tree_view_column_pack_start (column, renderer, TRUE);
 +	gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
 +
 +	gtk_tree_view_column_set_cell_data_func (
 +		column, renderer, (GtkTreeCellDataFunc)
 +		mail_label_tree_view_render_pixbuf, tree_view, NULL);
 +
 +	column = gtk_tree_view_column_new ();
 +	renderer = gtk_cell_renderer_text_new ();
 +	gtk_tree_view_column_set_title (column, _("Name"));
 +	gtk_tree_view_column_pack_start (column, renderer, TRUE);
 +	gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
 +
 +	gtk_tree_view_column_set_cell_data_func (
 +		column, renderer, (GtkTreeCellDataFunc)
 +		mail_label_tree_view_render_text, tree_view, NULL);
 +}
 +
 +GType
 +e_mail_label_tree_view_get_type (void)
 +{
 +	static GType type = 0;
 +
 +	if (G_UNLIKELY (type == 0)) {
 +		static const GTypeInfo type_info = {
 +			sizeof (EMailLabelTreeViewClass),
 +			(GBaseInitFunc) NULL,
 +			(GBaseFinalizeFunc) NULL,
 +			(GClassInitFunc) mail_label_tree_view_class_init,
 +			(GClassFinalizeFunc) NULL,
 +			NULL,  /* class_data */
 +			sizeof (EMailLabelTreeView),
 +			0,     /* n_preallocs */
 +			(GInstanceInitFunc) mail_label_tree_view_init,
 +			NULL   /* value_table */
 +		};
 +
 +		type = g_type_register_static (
 +			GTK_TYPE_TREE_VIEW, "EMailLabelTreeView",
 +			&type_info, 0);
 +	}
 +
 +	return type;
 +}
 +
 +GtkWidget *
 +e_mail_label_tree_view_new (void)
 +{
 +	return g_object_new (E_TYPE_MAIL_LABEL_TREE_VIEW, NULL);
 +}
diff --cc mail/e-mail-label-tree-view.h
index d29ad62,0000000..0dd58f2
mode 100644,000000..100644
--- a/mail/e-mail-label-tree-view.h
+++ b/mail/e-mail-label-tree-view.h
@@@ -1,66 -1,0 +1,66 @@@
 +/*
 + * e-mail-label-tree-view.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_MAIL_LABEL_TREE_VIEW_H
 +#define E_MAIL_LABEL_TREE_VIEW_H
 +
 +#include <gtk/gtk.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_MAIL_LABEL_TREE_VIEW \
 +	(e_mail_label_tree_view_get_type ())
 +#define E_MAIL_LABEL_TREE_VIEW(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_MAIL_LABEL_TREE_VIEW, EMailLabelTreeView))
 +#define E_MAIL_LABEL_TREE_VIEW_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_MAIL_LABEL_TREE_VIEW, EMailLabelTreeViewClass))
 +#define E_IS_MAIL_LABEL_TREE_VIEW(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_MAIL_LABEL_TREE_VIEW))
 +#define E_IS_MAIL_LABEL_TREE_VIEW_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), E_TYPE_MAIL_LABEL_TREE_VIEW))
 +#define E_MAIL_LABEL_TREE_VIEW_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_MAIL_LABEL_TREE_VIEW, EMailLabelTreeViewClass))
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _EMailLabelTreeView EMailLabelTreeView;
 +typedef struct _EMailLabelTreeViewClass EMailLabelTreeViewClass;
 +typedef struct _EMailLabelTreeViewPrivate EMailLabelTreeViewPrivate;
 +
 +struct _EMailLabelTreeView {
 +	GtkTreeView parent;
 +	EMailLabelTreeViewPrivate *priv;
 +};
 +
 +struct _EMailLabelTreeViewClass {
 +	GtkTreeViewClass parent_class;
 +};
 +
 +GType		e_mail_label_tree_view_get_type		(void);
 +GtkWidget *	e_mail_label_tree_view_new		(void);
 +
 +G_END_DECLS
 +
 +#endif /* E_MAIL_LABEL_TREE_VIEW_H */
diff --cc mail/e-mail-reader-utils.c
index 96fe1ba,0000000..7914421
mode 100644,000000..100644
--- a/mail/e-mail-reader-utils.c
+++ b/mail/e-mail-reader-utils.c
@@@ -1,593 -1,0 +1,593 @@@
 +/*
 + * e-mail-reader-utils.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +/* Miscellaneous utility functions used by EMailReader actions. */
 +
 +#include "e-mail-reader-utils.h"
 +
 +#include <glib/gi18n.h>
 +#include <gtkhtml/gtkhtml.h>
 +#include <camel/camel-mime-message.h>
 +#include <camel/camel-vee-folder.h>
 +#include <camel/camel-vee-store.h>
 +
 +#include "e-util/e-error.h"
 +#include "filter/filter-rule.h"
 +
 +#include "mail/e-mail-browser.h"
 +#include "mail/em-composer-utils.h"
 +#include "mail/em-format-html-print.h"
 +#include "mail/em-utils.h"
 +#include "mail/mail-autofilter.h"
 +#include "mail/mail-ops.h"
 +#include "mail/mail-tools.h"
 +#include "mail/mail-vfolder.h"
 +
 +void
 +e_mail_reader_activate (EMailReader *reader,
 +                        const gchar *action_name)
 +{
 +	GtkActionGroup *action_group;
 +	GtkAction *action;
 +
 +	g_return_if_fail (E_IS_MAIL_READER (reader));
 +	g_return_if_fail (action_name != NULL);
 +
 +	action_group = e_mail_reader_get_action_group (reader);
 +	action = gtk_action_group_get_action (action_group, action_name);
 +	g_return_if_fail (action != NULL);
 +
 +	gtk_action_activate (action);
 +}
 +
 +gboolean
 +e_mail_reader_confirm_delete (EMailReader *reader)
 +{
 +	EShell *shell;
 +	EShellBackend *shell_backend;
 +	EShellSettings *shell_settings;
 +	MessageList *message_list;
 +	CamelFolder *folder;
 +	GtkWidget *check_button;
 +	GtkWidget *content_area;
 +	GtkWidget *dialog;
 +	GtkWindow *window;
 +	const gchar *label;
 +	gboolean prompt_delete_in_vfolder;
 +	gint response;
 +
 +	/* Remind users what deleting from a search folder does. */
 +
 +	g_return_val_if_fail (E_IS_MAIL_READER (reader), FALSE);
 +
 +	message_list = e_mail_reader_get_message_list (reader);
 +	window = e_mail_reader_get_window (reader);
 +
 +	shell_backend = e_mail_reader_get_shell_backend (reader);
 +	shell = e_shell_backend_get_shell (shell_backend);
 +	shell_settings = e_shell_get_shell_settings (shell);
 +
 +	folder = message_list->folder;
 +
 +	prompt_delete_in_vfolder = e_shell_settings_get_boolean (
 +		shell_settings, "mail-prompt-delete-in-vfolder");
 +
 +	if (!CAMEL_IS_VEE_STORE (folder->parent_store))
 +		return TRUE;
 +
 +	if (!prompt_delete_in_vfolder)
 +		return TRUE;
 +
 +	dialog = e_error_new (
 +		window, "mail:ask-delete-vfolder-msg",
 +		folder->full_name, NULL);
 +
 +	/* XXX e-error should provide a widget layout and API suitable
 +	 *     for packing additional widgets to the right of the alert
 +	 *     icon.  But for now, screw it. */
 +
 +	label = _("Do not ask me again");
 +	content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
 +	check_button = gtk_check_button_new_with_label (label);
 +	gtk_box_pack_start (
 +		GTK_BOX (content_area), check_button, TRUE, TRUE, 6);
 +
 +	response = gtk_dialog_run (GTK_DIALOG (dialog));
 +
 +	if (response == GTK_RESPONSE_OK)
 +		e_shell_settings_set_boolean (
 +			shell_settings,
 +			"mail-prompt-delete-in-vfolder",
 +			gtk_toggle_button_get_active (
 +			GTK_TOGGLE_BUTTON (check_button)));
 +
 +	gtk_widget_destroy (dialog);
 +
 +	return (response == GTK_RESPONSE_OK);
 +}
 +
 +void
 +e_mail_reader_mark_as_read (EMailReader *reader,
 +                            const gchar *uid)
 +{
 +	EMFormatHTMLDisplay *html_display;
 +	MessageList *message_list;
 +	CamelFolder *folder;
 +	guint32 mask, set;
 +	guint32 flags;
 +
 +	g_return_if_fail (E_IS_MAIL_READER (reader));
 +	g_return_if_fail (uid != NULL);
 +
 +	html_display = e_mail_reader_get_html_display (reader);
 +	message_list = e_mail_reader_get_message_list (reader);
 +
 +	folder = message_list->folder;
 +	flags = camel_folder_get_message_flags (folder, uid);
 +
 +	if (!(flags & CAMEL_MESSAGE_SEEN)) {
 +		CamelMimeMessage *message;
 +
 +		message = ((EMFormat *) html_display)->message;
 +		em_utils_handle_receipt (folder, uid, message);
 +	}
 +
 +	mask = CAMEL_MESSAGE_SEEN;
 +	set  = CAMEL_MESSAGE_SEEN;
 +	camel_folder_set_message_flags (folder, uid, mask, set);
 +}
 +
 +guint
 +e_mail_reader_mark_selected (EMailReader *reader,
 +                             guint32 mask,
 +                             guint32 set)
 +{
 +	MessageList *message_list;
 +	CamelFolder *folder;
 +	GPtrArray *uids;
 +	guint ii;
 +
 +	g_return_val_if_fail (E_IS_MAIL_READER (reader), 0);
 +
 +	message_list = e_mail_reader_get_message_list (reader);
 +
 +	folder = message_list->folder;
 +	if (folder == NULL)
 +		return 0;
 +
 +	camel_folder_freeze (folder);
 +	uids = message_list_get_selected (message_list);
 +
 +	for (ii = 0; ii < uids->len; ii++)
 +		camel_folder_set_message_flags (
 +			folder, uids->pdata[ii], mask, set);
 +
 +	message_list_free_uids (message_list, uids);
 +	camel_folder_thaw (folder);
 +
 +	return ii;
 +}
 +
 +guint
 +e_mail_reader_open_selected (EMailReader *reader)
 +{
 +	EMailShellBackend *mail_shell_backend;
 +	EShellBackend *shell_backend;
 +	MessageList *message_list;
 +	CamelFolder *folder;
 +	GtkWindow *window;
 +	GPtrArray *views;
 +	GPtrArray *uids;
 +	const gchar *folder_uri;
 +	guint ii;
 +
 +	g_return_val_if_fail (E_IS_MAIL_READER (reader), 0);
 +
 +	message_list = e_mail_reader_get_message_list (reader);
 +	shell_backend = e_mail_reader_get_shell_backend (reader);
 +	window = e_mail_reader_get_window (reader);
 +
 +	mail_shell_backend = E_MAIL_SHELL_BACKEND (shell_backend);
 +
 +	folder = message_list->folder;
 +	folder_uri = message_list->folder_uri;
 +	uids = message_list_get_selected (message_list);
 +
 +	if (uids->len >= 10) {
 +		gchar *len_str;
 +		gboolean proceed;
 +
 +		len_str = g_strdup_printf ("%d", uids->len);
 +
 +		proceed = em_utils_prompt_user (
 +			window, "/apps/evolution/mail/prompts/open_many",
 +			"mail:ask-open-many", len_str, NULL);
 +
 +		g_free (len_str);
 +
 +		if (!proceed) {
 +			message_list_free_uids (message_list, uids);
 +			return 0;
 +		}
 +	}
 +
 +	if (em_utils_folder_is_drafts (folder, folder_uri) ||
 +		em_utils_folder_is_outbox (folder, folder_uri) ||
 +		em_utils_folder_is_templates (folder, folder_uri)) {
 +		em_utils_edit_messages (folder, uids, TRUE);
 +		return uids->len;
 +	}
 +
 +	views = g_ptr_array_new ();
 +
 +	/* For vfolders we need to edit the original, not the vfolder copy. */
 +	for (ii = 0; ii < uids->len; ii++) {
 +		const gchar *uid = uids->pdata[ii];
 +		CamelFolder *real_folder;
 +		CamelMessageInfo *info;
 +		gchar *real_folder_uri;
 +		gchar *real_uid;
 +
 +		if (!CAMEL_IS_VEE_FOLDER (folder)) {
 +			g_ptr_array_add (views, g_strdup (uid));
 +			continue;
 +		}
 +
 +		info = camel_folder_get_message_info (folder, uid);
 +		if (info == NULL)
 +			continue;
 +
 +		real_folder = camel_vee_folder_get_location (
 +			CAMEL_VEE_FOLDER (folder),
 +			(CamelVeeMessageInfo *) info, &real_uid);
 +		real_folder_uri = mail_tools_folder_to_url (real_folder);
 +
 +		if (em_utils_folder_is_drafts (real_folder, real_folder_uri) ||
 +			em_utils_folder_is_outbox (real_folder, real_folder_uri)) {
 +			GPtrArray *edits;
 +
 +			edits = g_ptr_array_new ();
 +			g_ptr_array_add (edits, real_uid);
 +			em_utils_edit_messages (real_folder, edits, TRUE);
 +		} else {
 +			g_free (real_uid);
 +			g_ptr_array_add (views, g_strdup (uid));
 +		}
 +
 +		g_free (real_folder_uri);
 +	}
 +
 +	for (ii = 0; ii < views->len; ii++) {
 +		const gchar *uid = views->pdata[ii];
 +		GtkWidget *browser;
 +
 +		browser = e_mail_browser_new (mail_shell_backend);
 +		e_mail_reader_set_folder (
 +			E_MAIL_READER (browser), folder, folder_uri);
 +		e_mail_reader_set_message (
 +			E_MAIL_READER (browser), uid, FALSE);
 +		gtk_widget_show (browser);
 +	}
 +
 +	g_ptr_array_free (views, TRUE);
 +
 +	message_list_free_uids (message_list, uids);
 +
 +	return ii;
 +}
 +
 +void
 +e_mail_reader_print (EMailReader *reader,
 +                     GtkPrintOperationAction action)
 +{
 +	MessageList *message_list;
 +	EMFormatHTMLDisplay *html_display;
 +	EMFormatHTMLPrint *html_print;
 +	CamelFolder *folder;
 +	GPtrArray *uids;
 +
 +	g_return_if_fail (E_IS_MAIL_READER (reader));
 +
 +	html_display = e_mail_reader_get_html_display (reader);
 +	message_list = e_mail_reader_get_message_list (reader);
 +
 +	folder = message_list->folder;
 +	g_return_if_fail (folder != NULL);
 +
 +	/* XXX Learn to handle len > 1. */
 +	uids = message_list_get_selected (message_list);
 +	if (uids->len != 1)
 +		goto exit;
 +
 +	html_print = em_format_html_print_new (
 +		(EMFormatHTML *) html_display, action);
 +	em_format_merge_handler (
 +		(EMFormat *) html_print,
 +		(EMFormat *) html_display);
 +	em_format_html_print_message (html_print, folder, uids->pdata[0]);
 +	g_object_unref (html_print);
 +
 +exit:
 +	message_list_free_uids (message_list, uids);
 +}
 +
 +/* Helper for e_mail_reader_reply_to_message()
 + * XXX This function belongs in e-html-utils.c */
 +static gboolean
 +html_contains_nonwhitespace (const gchar *html,
 +                             gint len)
 +{
 +	const gchar *cp;
 +	gunichar uc = 0;
 +
 +	if (html == NULL || len <= 0)
 +		return FALSE;
 +
 +	cp = html;
 +
 +	while (cp != NULL && cp - html < len) {
 +		uc = g_utf8_get_char (cp);
 +		if (uc == 0)
 +			break;
 +
 +		if (uc == '<') {
 +			/* skip until next '>' */
 +			uc = g_utf8_get_char (cp);
 +			while (uc != 0 && uc != '>' && cp - html < len) {
 +				cp = g_utf8_next_char (cp);
 +				uc = g_utf8_get_char (cp);
 +			}
 +			if (uc == 0)
 +				break;
 +		} else if (uc == '&') {
 +			/* sequence '&nbsp;' is a space */
 +			if (g_ascii_strncasecmp (cp, "&nbsp;", 6) == 0)
 +				cp = cp + 5;
 +			else
 +				break;
 +		} else if (!g_unichar_isspace (uc))
 +			break;
 +
 +		cp = g_utf8_next_char (cp);
 +	}
 +
 +	return cp - html < len - 1 && uc != 0;
 +}
 +
 +void
 +e_mail_reader_reply_to_message (EMailReader *reader,
 +                                gint reply_mode)
 +{
 +	EMFormatHTMLDisplay *html_display;
 +	MessageList *message_list;
 +	CamelMimeMessage *new_message;
 +	CamelMimeMessage *src_message;
 +	CamelFolder *folder;
 +	GtkWindow *window;
 +	GtkHTML *html;
 +	struct _camel_header_raw *header;
 +	const gchar *uid;
 +	gchar *selection = NULL;
 +	gint length;
 +
 +	/* This handles quoting only selected text in the reply.  If
 +	 * nothing is selected or only whitespace is selected, fall
 +	 * back to the normal em_utils_reply_to_message(). */
 +
 +	g_return_if_fail (E_IS_MAIL_READER (reader));
 +
 +	html_display = e_mail_reader_get_html_display (reader);
 +	html = ((EMFormatHTML *) html_display)->html;
 +
 +	message_list = e_mail_reader_get_message_list (reader);
 +	window = e_mail_reader_get_window (reader);
 +
 +	folder = message_list->folder;
 +	uid = message_list->cursor_uid;
 +	g_return_if_fail (uid != NULL);
 +
 +	if (!em_utils_check_user_can_send_mail (window))
 +		return;
 +
 +	if (!gtk_html_command (html, "is-selection-active"))
 +		goto whole_message;
 +
 +	selection = gtk_html_get_selection_html (html, &length);
 +	if (selection == NULL || *selection == '\0')
 +		goto whole_message;
 +
 +	if (!html_contains_nonwhitespace (selection, length))
 +		goto whole_message;
 +
 +	src_message =
 +		CAMEL_MIME_MESSAGE (((EMFormat *) html_display)->message);
 +	new_message = camel_mime_message_new ();
 +
 +	/* Filter out "content-*" headers. */
 +	header = CAMEL_MIME_PART (src_message)->headers;
 +	while (header != NULL) {
 +		if (g_ascii_strncasecmp (header->name, "content-", 8) != 0)
 +			camel_medium_add_header (
 +				CAMEL_MEDIUM (new_message),
 +				header->name, header->value);
 +	}
 +
 +	camel_mime_part_set_encoding (
 +		CAMEL_MIME_PART (new_message),
 +		CAMEL_TRANSFER_ENCODING_8BIT);
 +
 +	camel_mime_part_set_content (
 +		CAMEL_MIME_PART (new_message),
 +		selection, length, "text/html");
 +
 +	em_utils_reply_to_message (
 +		folder, uid, new_message, reply_mode, NULL);
 +
 +	g_free (selection);
 +
 +	return;
 +
 +whole_message:
 +	em_utils_reply_to_message (
 +		folder, uid, NULL, reply_mode, (EMFormat *) html_display);
 +}
 +
 +void
 +e_mail_reader_select_next_message (EMailReader *reader,
 +                                   gboolean or_else_previous)
 +{
 +	MessageList *message_list;
 +	gboolean hide_deleted;
 +	gboolean success;
 +
 +	g_return_if_fail (E_IS_MAIL_READER (reader));
 +
 +	hide_deleted = e_mail_reader_get_hide_deleted (reader);
 +	message_list = e_mail_reader_get_message_list (reader);
 +
 +	success = message_list_select (
 +		message_list, MESSAGE_LIST_SELECT_NEXT, 0, 0);
 +
 +	if (!success && (hide_deleted || or_else_previous))
 +		message_list_select (
 +			message_list, MESSAGE_LIST_SELECT_PREVIOUS, 0, 0);
 +}
 +
 +/* Helper for e_mail_reader_create_filter_from_selected() */
 +static void
 +mail_reader_create_filter_cb (CamelFolder *folder,
 +                              const gchar *uid,
 +                              CamelMimeMessage *message,
 +                              gpointer user_data)
 +{
 +	struct {
 +		const gchar *source;
 +		gint type;
 +	} *filter_data = user_data;
 +
 +	if (message != NULL)
 +		filter_gui_add_from_message (
 +			message, filter_data->source, filter_data->type);
 +
 +	g_free (filter_data);
 +}
 +
 +void
 +e_mail_reader_create_filter_from_selected (EMailReader *reader,
 +                                           gint filter_type)
 +{
 +	MessageList *message_list;
 +	CamelFolder *folder;
 +	const gchar *filter_source;
 +	const gchar *folder_uri;
 +	GPtrArray *uids;
 +
 +	struct {
 +		const gchar *source;
 +		gint type;
 +	} *filter_data;
 +
 +	g_return_if_fail (E_IS_MAIL_READER (reader));
 +
 +	message_list = e_mail_reader_get_message_list (reader);
 +
 +	folder = message_list->folder;
 +	folder_uri = message_list->folder_uri;
 +
 +	if (em_utils_folder_is_sent (folder, folder_uri))
 +		filter_source = FILTER_SOURCE_OUTGOING;
 +	else if (em_utils_folder_is_outbox (folder, folder_uri))
 +		filter_source = FILTER_SOURCE_OUTGOING;
 +	else
 +		filter_source = FILTER_SOURCE_INCOMING;
 +
 +	uids = message_list_get_selected (message_list);
 +
 +	if (uids->len == 1) {
 +		filter_data = g_malloc (sizeof (*filter_data));
 +		filter_data->source = filter_source;
 +		filter_data->type = filter_type;
 +
 +		mail_get_message (
 +			folder, uids->pdata[0],
 +			mail_reader_create_filter_cb,
 +			filter_data, mail_msg_unordered_push);
 +	}
 +
 +	em_utils_uids_free (uids);
 +}
 +
 +/* Helper for e_mail_reader_create_vfolder_from_selected() */
 +static void
 +mail_reader_create_vfolder_cb (CamelFolder *folder,
 +                               const gchar *uid,
 +                               CamelMimeMessage *message,
 +                               gpointer user_data)
 +{
 +	struct {
 +		gchar *uri;
 +		gint type;
 +	} *vfolder_data = user_data;
 +
 +	if (message != NULL)
 +		vfolder_gui_add_from_message (
 +			message, vfolder_data->type, vfolder_data->uri);
 +
 +	g_free (vfolder_data->uri);
 +	g_free (vfolder_data);
 +}
 +
 +void
 +e_mail_reader_create_vfolder_from_selected (EMailReader *reader,
 +                                            gint vfolder_type)
 +{
 +	MessageList *message_list;
 +	CamelFolder *folder;
 +	const gchar *folder_uri;
 +	GPtrArray *uids;
 +
 +	struct {
 +		gchar *uri;
 +		gint type;
 +	} *vfolder_data;
 +
 +	g_return_if_fail (E_IS_MAIL_READER (reader));
 +
 +	message_list = e_mail_reader_get_message_list (reader);
 +
 +	folder = message_list->folder;
 +	folder_uri = message_list->folder_uri;
 +
 +	uids = message_list_get_selected (message_list);
 +
 +	if (uids->len == 1) {
 +		vfolder_data = g_malloc (sizeof (*vfolder_data));
 +		vfolder_data->uri = g_strdup (folder_uri);
 +		vfolder_data->type = vfolder_type;
 +
 +		mail_get_message (
 +			folder, uids->pdata[0],
 +			mail_reader_create_vfolder_cb,
 +			vfolder_data, mail_msg_unordered_push);
 +	}
 +
 +	em_utils_uids_free (uids);
 +}
diff --cc mail/e-mail-reader-utils.h
index 8ec2235,0000000..46c3ea7
mode 100644,000000..100644
--- a/mail/e-mail-reader-utils.h
+++ b/mail/e-mail-reader-utils.h
@@@ -1,56 -1,0 +1,56 @@@
 +/*
 + * e-mail-reader-utils.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +/* Miscellaneous utility functions used by EMailReader actions. */
 +
 +#ifndef E_MAIL_READER_UTILS_H
 +#define E_MAIL_READER_UTILS_H
 +
 +#include <mail/e-mail-reader.h>
 +
 +G_BEGIN_DECLS
 +
 +void		e_mail_reader_activate		(EMailReader *reader,
 +						 const gchar *action_name);
 +gboolean	e_mail_reader_confirm_delete	(EMailReader *reader);
 +void		e_mail_reader_mark_as_read	(EMailReader *reader,
 +						 const gchar *uid);
 +guint		e_mail_reader_mark_selected	(EMailReader *reader,
 +						 guint32 mask,
 +						 guint32 set);
 +guint		e_mail_reader_open_selected	(EMailReader *reader);
 +void		e_mail_reader_print		(EMailReader *reader,
 +						 GtkPrintOperationAction action);
 +void		e_mail_reader_reply_to_message	(EMailReader *reader,
 +						 gint reply_mode);
 +void		e_mail_reader_select_next_message
 +						(EMailReader *reader,
 +						 gboolean or_else_previous);
 +void		e_mail_reader_create_filter_from_selected
 +						(EMailReader *reader,
 +						 gint filter_type);
 +void		e_mail_reader_create_vfolder_from_selected
 +						(EMailReader *reader,
 +						 gint filter_type);
 +
 +G_END_DECLS
 +
 +#endif /* E_MAIL_READER_UTILS_H */
diff --cc mail/e-mail-reader.c
index 3969f4b,0000000..1cf9ff9
mode 100644,000000..100644
--- a/mail/e-mail-reader.c
+++ b/mail/e-mail-reader.c
@@@ -1,2738 -1,0 +1,2738 @@@
 +/*
 + * e-mail-reader.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-mail-reader.h"
 +
 +#include <glib/gi18n.h>
 +#include <gdk/gdkkeysyms.h>
 +#include <gtkhtml/gtkhtml.h>
 +#include <gtkhtml/gtkhtml-stream.h>
 +
 +#ifdef HAVE_XFREE
 +#include <X11/XF86keysym.h>
 +#endif
 +
 +#include "e-util/e-util.h"
 +#include "e-util/e-binding.h"
 +#include "e-util/gconf-bridge.h"
 +#include "shell/e-shell.h"
 +#include "widgets/misc/e-charset-picker.h"
 +#include "widgets/misc/e-popup-action.h"
 +
 +#include "mail/e-mail-browser.h"
 +#include "mail/e-mail-reader-utils.h"
 +#include "mail/e-mail-shell-backend.h"
 +#include "mail/em-composer-utils.h"
 +#include "mail/em-event.h"
 +#include "mail/em-folder-selector.h"
 +#include "mail/em-folder-tree.h"
 +#include "mail/em-utils.h"
 +#include "mail/mail-autofilter.h"
 +#include "mail/mail-config.h"
 +#include "mail/mail-ops.h"
 +
 +enum {
 +	CHANGED,
 +	FOLDER_LOADED,
 +	SHOW_SEARCH_BAR,
 +	LAST_SIGNAL
 +};
 +
 +/* Remembers the previously selected folder when transferring messages. */
 +static gchar *default_xfer_messages_uri;
 +
 +static guint signals[LAST_SIGNAL];
 +
 +static void
 +action_mail_add_sender_cb (GtkAction *action,
 +                           EMailReader *reader)
 +{
 +	MessageList *message_list;
 +	CamelMessageInfo *info;
 +	CamelFolder *folder;
 +	GtkWindow *window;
 +	GPtrArray *uids;
 +	const gchar *address;
 +
 +	message_list = e_mail_reader_get_message_list (reader);
 +	window = e_mail_reader_get_window (reader);
 +
 +	folder = message_list->folder;
 +	uids = message_list_get_selected (message_list);
 +
 +	if (uids->len != 1)
 +		goto exit;
 +
 +	info = camel_folder_get_message_info (folder, uids->pdata[0]);
 +	if (info == NULL)
 +		goto exit;
 +
 +	address = camel_message_info_from (info);
 +	if (address == NULL || *address == '\0')
 +		goto exit;
 +
 +	em_utils_add_address (window, address);
 +
 +exit:
 +	em_utils_uids_free (uids);
 +}
 +
 +static void
 +action_mail_charset_cb (GtkRadioAction *action,
 +                        GtkRadioAction *current,
 +                        EMailReader *reader)
 +{
 +	EMFormatHTMLDisplay *html_display;
 +	const gchar *charset;
 +
 +	if (action != current)
 +		return;
 +
 +	html_display = e_mail_reader_get_html_display (reader);
 +	charset = g_object_get_data (G_OBJECT (action), "charset");
 +
 +	/* Charset for "Default" action will be NULL. */
 +	em_format_set_charset (EM_FORMAT (html_display), charset);
 +}
 +
 +static void
 +action_mail_check_for_junk_cb (GtkAction *action,
 +                               EMailReader *reader)
 +{
 +	MessageList *message_list;
 +	CamelFolder *folder;
 +	GPtrArray *uids;
 +
 +	message_list = e_mail_reader_get_message_list (reader);
 +
 +	folder = message_list->folder;
 +	uids = message_list_get_selected (message_list);
 +
 +	mail_filter_junk (folder, uids);
 +}
 +
 +static void
 +action_mail_clipboard_copy_cb (GtkAction *action,
 +                               EMailReader *reader)
 +{
 +	EMFormatHTMLDisplay *html_display;
 +	GtkHTML *html;
 +
 +	html_display = e_mail_reader_get_html_display (reader);
 +	html = EM_FORMAT_HTML (html_display)->html;
 +
 +	gtk_html_copy (html);
 +}
 +
 +static void
 +action_mail_copy_cb (GtkAction *action,
 +                     EMailReader *reader)
 +{
 +	EShellBackend *shell_backend;
 +	MessageList *message_list;
 +	EMFolderTreeModel *model;
 +	CamelFolder *folder;
 +	GtkWidget *folder_tree;
 +	GtkWidget *dialog;
 +	GPtrArray *selected;
 +	const gchar *uri;
 +
 +	message_list = e_mail_reader_get_message_list (reader);
 +	shell_backend = e_mail_reader_get_shell_backend (reader);
 +	model = e_mail_shell_backend_get_folder_tree_model (
 +		E_MAIL_SHELL_BACKEND (shell_backend));
 +
 +	folder_tree = em_folder_tree_new_with_model (model);
 +	selected = message_list_get_selected (message_list);
 +
 +	folder = message_list->folder;
 +
 +	em_folder_tree_set_excluded (
 +		EM_FOLDER_TREE (folder_tree),
 +		EMFT_EXCLUDE_NOSELECT | EMFT_EXCLUDE_VIRTUAL |
 +		EMFT_EXCLUDE_VTRASH);
 +
 +	dialog = em_folder_selector_new (
 +		EM_FOLDER_TREE (folder_tree),
 +		EM_FOLDER_SELECTOR_CAN_CREATE,
 +		_("Select Folder"), NULL, _("C_opy"));
 +
 +	if (default_xfer_messages_uri != NULL)
 +		em_folder_selector_set_selected (
 +			EM_FOLDER_SELECTOR (dialog),
 +			default_xfer_messages_uri);
 +
 +	if (gtk_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_OK)
 +		goto exit;
 +
 +	uri = em_folder_selector_get_selected_uri (
 +		EM_FOLDER_SELECTOR (dialog));
 +
 +	g_free (default_xfer_messages_uri);
 +	default_xfer_messages_uri = g_strdup (uri);
 +
 +	if (uri != NULL) {
 +		mail_transfer_messages (
 +			folder, selected, FALSE, uri, 0, NULL, NULL);
 +		selected = NULL;
 +	}
 +
 +exit:
 +	if (selected != NULL)
 +		em_utils_uids_free (selected);
 +
 +	gtk_widget_destroy (dialog);
 +}
 +
 +static void
 +action_mail_delete_cb (GtkAction *action,
 +                       EMailReader *reader)
 +{
 +	guint32 mask = CAMEL_MESSAGE_SEEN | CAMEL_MESSAGE_DELETED;
 +	guint32 set  = CAMEL_MESSAGE_SEEN | CAMEL_MESSAGE_DELETED;
 +
 +	if (!e_mail_reader_confirm_delete (reader))
 +		return;
 +
 +	/* FIXME Verify all selected messages are deletable.
 +	 *       But handle it by disabling this action. */
 +
 +	if (e_mail_reader_mark_selected (reader, mask, set) == 1)
 +		e_mail_reader_select_next_message (reader, FALSE);
 +}
 +
 +static void
 +action_mail_filter_on_mailing_list_cb (GtkAction *action,
 +                                       EMailReader *reader)
 +{
 +	e_mail_reader_create_filter_from_selected (reader, AUTO_MLIST);
 +}
 +
 +static void
 +action_mail_filter_on_recipients_cb (GtkAction *action,
 +                                     EMailReader *reader)
 +{
 +	e_mail_reader_create_filter_from_selected (reader, AUTO_TO);
 +}
 +
 +static void
 +action_mail_filter_on_sender_cb (GtkAction *action,
 +                                 EMailReader *reader)
 +{
 +	e_mail_reader_create_filter_from_selected (reader, AUTO_FROM);
 +}
 +
 +static void
 +action_mail_filter_on_subject_cb (GtkAction *action,
 +                                  EMailReader *reader)
 +{
 +	e_mail_reader_create_filter_from_selected (reader, AUTO_SUBJECT);
 +}
 +
 +static void
 +action_mail_filters_apply_cb (GtkAction *action,
 +                              EMailReader *reader)
 +{
 +	MessageList *message_list;
 +	CamelFolder *folder;
 +	GPtrArray *uids;
 +
 +	message_list = e_mail_reader_get_message_list (reader);
 +
 +	folder = message_list->folder;
 +	uids = message_list_get_selected (message_list);
 +
 +	mail_filter_on_demand (folder, uids);
 +}
 +
 +static void
 +action_mail_find_cb (GtkAction *action,
 +                     EMailReader *reader)
 +{
 +	e_mail_reader_show_search_bar (reader);
 +}
 +
 +static void
 +action_mail_flag_clear_cb (GtkAction *action,
 +                           EMailReader *reader)
 +{
 +	EMFormatHTMLDisplay *html_display;
 +	MessageList *message_list;
 +	CamelFolder *folder;
 +	GtkWindow *window;
 +	GPtrArray *uids;
 +
 +	html_display = e_mail_reader_get_html_display (reader);
 +	message_list = e_mail_reader_get_message_list (reader);
 +	window = e_mail_reader_get_window (reader);
 +
 +	folder = message_list->folder;
 +	uids = message_list_get_selected (message_list);
 +
 +	em_utils_flag_for_followup_clear (window, folder, uids);
 +
 +	em_format_redraw (EM_FORMAT (html_display));
 +}
 +
 +static void
 +action_mail_flag_completed_cb (GtkAction *action,
 +                               EMailReader *reader)
 +{
 +	EMFormatHTMLDisplay *html_display;
 +	MessageList *message_list;
 +	CamelFolder *folder;
 +	GtkWindow *window;
 +	GPtrArray *uids;
 +
 +	html_display = e_mail_reader_get_html_display (reader);
 +	message_list = e_mail_reader_get_message_list (reader);
 +	window = e_mail_reader_get_window (reader);
 +
 +	folder = message_list->folder;
 +	uids = message_list_get_selected (message_list);
 +
 +	em_utils_flag_for_followup_completed (window, folder, uids);
 +
 +	em_format_redraw (EM_FORMAT (html_display));
 +}
 +
 +static void
 +action_mail_flag_for_followup_cb (GtkAction *action,
 +                                  EMailReader *reader)
 +{
 +	MessageList *message_list;
 +	CamelFolder *folder;
 +	GtkWindow *window;
 +	GPtrArray *uids;
 +
 +	message_list = e_mail_reader_get_message_list (reader);
 +	window = e_mail_reader_get_window (reader);
 +
 +	folder = message_list->folder;
 +	uids = message_list_get_selected (message_list);
 +
 +	em_utils_flag_for_followup (window, folder, uids);
 +}
 +
 +static void
 +action_mail_forward_cb (GtkAction *action,
 +                        EMailReader *reader)
 +{
 +	MessageList *message_list;
 +	CamelFolder *folder;
 +	GtkWindow *window;
 +	GPtrArray *uids;
 +	const gchar *folder_uri;
 +
 +	message_list = e_mail_reader_get_message_list (reader);
 +	window = e_mail_reader_get_window (reader);
 +
 +	if (!em_utils_check_user_can_send_mail (window))
 +		return;
 +
 +	folder = message_list->folder;
 +	folder_uri = message_list->folder_uri;
 +	uids = message_list_get_selected (message_list);
 +
 +	em_utils_forward_messages (folder, uids, folder_uri);
 +}
 +
 +static void
 +action_mail_forward_attached_cb (GtkAction *action,
 +                                 EMailReader *reader)
 +{
 +	MessageList *message_list;
 +	CamelFolder *folder;
 +	GtkWindow *window;
 +	GPtrArray *uids;
 +	const gchar *folder_uri;
 +
 +	message_list = e_mail_reader_get_message_list (reader);
 +	window = e_mail_reader_get_window (reader);
 +
 +	if (!em_utils_check_user_can_send_mail (window))
 +		return;
 +
 +	folder = message_list->folder;
 +	folder_uri = message_list->folder_uri;
 +	uids = message_list_get_selected (message_list);
 +
 +	em_utils_forward_attached (folder, uids, folder_uri);
 +}
 +
 +static void
 +action_mail_forward_inline_cb (GtkAction *action,
 +                               EMailReader *reader)
 +{
 +	MessageList *message_list;
 +	CamelFolder *folder;
 +	GtkWindow *window;
 +	GPtrArray *uids;
 +	const gchar *folder_uri;
 +
 +	message_list = e_mail_reader_get_message_list (reader);
 +	window = e_mail_reader_get_window (reader);
 +
 +	if (!em_utils_check_user_can_send_mail (window))
 +		return;
 +
 +	folder = message_list->folder;
 +	folder_uri = message_list->folder_uri;
 +	uids = message_list_get_selected (message_list);
 +
 +	em_utils_forward_inline (folder, uids, folder_uri);
 +}
 +
 +static void
 +action_mail_forward_quoted_cb (GtkAction *action,
 +                               EMailReader *reader)
 +{
 +	MessageList *message_list;
 +	CamelFolder *folder;
 +	GtkWindow *window;
 +	GPtrArray *uids;
 +	const gchar *folder_uri;
 +
 +	message_list = e_mail_reader_get_message_list (reader);
 +	window = e_mail_reader_get_window (reader);
 +
 +	if (!em_utils_check_user_can_send_mail (window))
 +		return;
 +
 +	folder = message_list->folder;
 +	folder_uri = message_list->folder_uri;
 +	uids = message_list_get_selected (message_list);
 +
 +	em_utils_forward_quoted (folder, uids, folder_uri);
 +}
 +
 +static void
 +action_mail_load_images_cb (GtkAction *action,
 +                            EMailReader *reader)
 +{
 +	EMFormatHTMLDisplay *html_display;
 +
 +	html_display = e_mail_reader_get_html_display (reader);
 +
 +	em_format_html_load_images (EM_FORMAT_HTML (html_display));
 +}
 +
 +static void
 +action_mail_mark_important_cb (GtkAction *action,
 +                               EMailReader *reader)
 +{
 +	guint32 mask = CAMEL_MESSAGE_FLAGGED | CAMEL_MESSAGE_DELETED;
 +	guint32 set  = CAMEL_MESSAGE_FLAGGED;
 +
 +	e_mail_reader_mark_selected (reader, mask, set);
 +}
 +
 +static void
 +action_mail_mark_junk_cb (GtkAction *action,
 +                          EMailReader *reader)
 +{
 +	guint32 mask = CAMEL_MESSAGE_SEEN | CAMEL_MESSAGE_JUNK |
 +		CAMEL_MESSAGE_NOTJUNK | CAMEL_MESSAGE_JUNK_LEARN;
 +	guint32 set  = CAMEL_MESSAGE_SEEN | CAMEL_MESSAGE_JUNK |
 +		CAMEL_MESSAGE_JUNK_LEARN;
 +
 +	if (e_mail_reader_mark_selected (reader, mask, set) == 1)
 +		e_mail_reader_select_next_message (reader, TRUE);
 +}
 +
 +static void
 +action_mail_mark_notjunk_cb (GtkAction *action,
 +                             EMailReader *reader)
 +{
 +	guint32 mask = CAMEL_MESSAGE_JUNK | CAMEL_MESSAGE_NOTJUNK |
 +		CAMEL_MESSAGE_JUNK_LEARN;
 +	guint32 set  = CAMEL_MESSAGE_NOTJUNK | CAMEL_MESSAGE_JUNK_LEARN;
 +
 +	if (e_mail_reader_mark_selected (reader, mask, set) == 1)
 +		e_mail_reader_select_next_message (reader, TRUE);
 +}
 +
 +static void
 +action_mail_mark_read_cb (GtkAction *action,
 +                          EMailReader *reader)
 +{
 +	guint32 mask = CAMEL_MESSAGE_SEEN;
 +	guint32 set  = CAMEL_MESSAGE_SEEN;
 +
 +	e_mail_reader_mark_selected (reader, mask, set);
 +}
 +
 +static void
 +action_mail_mark_unimportant_cb (GtkAction *action,
 +                                 EMailReader *reader)
 +{
 +	guint32 mask = CAMEL_MESSAGE_FLAGGED;
 +	guint32 set  = 0;
 +
 +	e_mail_reader_mark_selected (reader, mask, set);
 +}
 +
 +static void
 +action_mail_mark_unread_cb (GtkAction *action,
 +                            EMailReader *reader)
 +{
 +	MessageList *message_list;
 +	guint32 mask = CAMEL_MESSAGE_SEEN | CAMEL_MESSAGE_DELETED;
 +	guint32 set  = 0;
 +
 +	message_list = e_mail_reader_get_message_list (reader);
 +
 +	e_mail_reader_mark_selected (reader, mask, set);
 +
 +	if (message_list->seen_id != 0) {
 +		g_source_remove (message_list->seen_id);
 +		message_list->seen_id = 0;
 +	}
 +}
 +
 +static void
 +action_mail_message_edit_cb (GtkAction *action,
 +                             EMailReader *reader)
 +{
 +	MessageList *message_list;
 +	CamelFolder *folder;
 +	GtkWindow *window;
 +	GPtrArray *uids;
 +
 +	window = e_mail_reader_get_window (reader);
 +	message_list = e_mail_reader_get_message_list (reader);
 +
 +	if (!em_utils_check_user_can_send_mail (window))
 +		return;
 +
 +	folder = message_list->folder;
 +	uids = message_list_get_selected (message_list);
 +
 +	em_utils_edit_messages (folder, uids, FALSE);
 +}
 +
 +static void
 +action_mail_message_new_cb (GtkAction *action,
 +                            EMailReader *reader)
 +{
 +	MessageList *message_list;
 +	GtkWindow *window;
 +
 +	message_list = e_mail_reader_get_message_list (reader);
 +	window = e_mail_reader_get_window (reader);
 +
 +	if (!em_utils_check_user_can_send_mail (window))
 +		return;
 +
 +	em_utils_compose_new_message (message_list->folder_uri);
 +}
 +
 +static void
 +action_mail_message_open_cb (GtkAction *action,
 +                             EMailReader *reader)
 +{
 +	e_mail_reader_open_selected (reader);
 +}
 +
 +static void
 +action_mail_move_cb (GtkAction *action,
 +                     EMailReader *reader)
 +{
 +	EShellBackend *shell_backend;
 +	MessageList *message_list;
 +	EMFolderTreeModel *model;
 +	CamelFolder *folder;
 +	GtkWidget *folder_tree;
 +	GtkWidget *dialog;
 +	GPtrArray *selected;
 +	const gchar *uri;
 +
 +	message_list = e_mail_reader_get_message_list (reader);
 +	shell_backend = e_mail_reader_get_shell_backend (reader);
 +	model = e_mail_shell_backend_get_folder_tree_model (
 +		E_MAIL_SHELL_BACKEND (shell_backend));
 +
 +	folder_tree = em_folder_tree_new_with_model (model);
 +	selected = message_list_get_selected (message_list);
 +
 +	folder = message_list->folder;
 +
 +	em_folder_tree_set_excluded (
 +		EM_FOLDER_TREE (folder_tree),
 +		EMFT_EXCLUDE_NOSELECT | EMFT_EXCLUDE_VIRTUAL |
 +		EMFT_EXCLUDE_VTRASH);
 +
 +	dialog = em_folder_selector_new (
 +		EM_FOLDER_TREE (folder_tree),
 +		EM_FOLDER_SELECTOR_CAN_CREATE,
 +		_("Select Folder"), NULL, _("C_opy"));
 +
 +	if (default_xfer_messages_uri != NULL)
 +		em_folder_selector_set_selected (
 +			EM_FOLDER_SELECTOR (dialog),
 +			default_xfer_messages_uri);
 +
 +	if (gtk_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_OK)
 +		goto exit;
 +
 +	uri = em_folder_selector_get_selected_uri (
 +		EM_FOLDER_SELECTOR (dialog));
 +
 +	g_free (default_xfer_messages_uri);
 +	default_xfer_messages_uri = g_strdup (uri);
 +
 +	if (uri != NULL) {
 +		mail_transfer_messages (
 +			folder, selected, TRUE, uri, 0, NULL, NULL);
 +		selected = NULL;
 +	}
 +
 +exit:
 +	if (selected != NULL)
 +		em_utils_uids_free (selected);
 +
 +	gtk_widget_destroy (dialog);
 +}
 +
 +static void
 +action_mail_next_cb (GtkAction *action,
 +                     EMailReader *reader)
 +{
 +	MessageList *message_list;
 +	MessageListSelectDirection direction;
 +	guint32 flags, mask;
 +
 +	direction = MESSAGE_LIST_SELECT_NEXT;
 +	flags = 0;
 +	mask  = 0;
 +
 +	message_list = e_mail_reader_get_message_list (reader);
 +	message_list_select (message_list, direction, flags, mask);
 +}
 +
 +static void
 +action_mail_next_important_cb (GtkAction *action,
 +                               EMailReader *reader)
 +{
 +	MessageList *message_list;
 +	MessageListSelectDirection direction;
 +	guint32 flags, mask;
 +
 +	direction = MESSAGE_LIST_SELECT_NEXT | MESSAGE_LIST_SELECT_WRAP;
 +	flags = CAMEL_MESSAGE_FLAGGED;
 +	mask  = CAMEL_MESSAGE_FLAGGED;
 +
 +	message_list = e_mail_reader_get_message_list (reader);
 +	message_list_select (message_list, direction, flags, mask);
 +}
 +
 +static void
 +action_mail_next_thread_cb (GtkAction *action,
 +                            EMailReader *reader)
 +{
 +	MessageList *message_list;
 +
 +	message_list = e_mail_reader_get_message_list (reader);
 +	message_list_select_next_thread (message_list);
 +}
 +
 +static void
 +action_mail_next_unread_cb (GtkAction *action,
 +                            EMailReader *reader)
 +{
 +	MessageList *message_list;
 +	MessageListSelectDirection direction;
 +	guint32 flags, mask;
 +
 +	direction = MESSAGE_LIST_SELECT_NEXT | MESSAGE_LIST_SELECT_WRAP;
 +	flags = 0;
 +	mask  = CAMEL_MESSAGE_SEEN;
 +
 +	message_list = e_mail_reader_get_message_list (reader);
 +	message_list_select (message_list, direction, flags, mask);
 +}
 +
 +static void
 +action_mail_previous_cb (GtkAction *action,
 +                         EMailReader *reader)
 +{
 +	MessageList *message_list;
 +	MessageListSelectDirection direction;
 +	guint32 flags, mask;
 +
 +	direction = MESSAGE_LIST_SELECT_PREVIOUS;
 +	flags = 0;
 +	mask  = 0;
 +
 +	message_list = e_mail_reader_get_message_list (reader);
 +	message_list_select (message_list, direction, flags, mask);
 +}
 +
 +static void
 +action_mail_previous_important_cb (GtkAction *action,
 +                                   EMailReader *reader)
 +{
 +	MessageList *message_list;
 +	MessageListSelectDirection direction;
 +	guint32 flags, mask;
 +
 +	direction = MESSAGE_LIST_SELECT_PREVIOUS | MESSAGE_LIST_SELECT_WRAP;
 +	flags = CAMEL_MESSAGE_FLAGGED;
 +	mask  = CAMEL_MESSAGE_FLAGGED;
 +
 +	message_list = e_mail_reader_get_message_list (reader);
 +	message_list_select (message_list, direction, flags, mask);
 +}
 +
 +static void
 +action_mail_previous_unread_cb (GtkAction *action,
 +                                EMailReader *reader)
 +{
 +	MessageList *message_list;
 +	MessageListSelectDirection direction;
 +	guint32 flags, mask;
 +
 +	direction = MESSAGE_LIST_SELECT_PREVIOUS | MESSAGE_LIST_SELECT_WRAP;
 +	flags = 0;
 +	mask  = CAMEL_MESSAGE_SEEN;
 +
 +	message_list = e_mail_reader_get_message_list (reader);
 +	message_list_select (message_list, direction, flags, mask);
 +}
 +
 +static void
 +action_mail_print_cb (GtkAction *action,
 +                      EMailReader *reader)
 +{
 +	GtkPrintOperationAction print_action;
 +
 +	print_action = GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG;
 +	e_mail_reader_print (reader, print_action);
 +}
 +
 +static void
 +action_mail_print_preview_cb (GtkAction *action,
 +                              EMailReader *reader)
 +{
 +	GtkPrintOperationAction print_action;
 +
 +	print_action = GTK_PRINT_OPERATION_ACTION_PREVIEW;
 +	e_mail_reader_print (reader, print_action);
 +}
 +
 +static void
 +action_mail_redirect_cb (GtkAction *action,
 +                         EMailReader *reader)
 +{
 +	MessageList *message_list;
 +	CamelFolder *folder;
 +	GtkWindow *window;
 +	const gchar *uid;
 +
 +	message_list = e_mail_reader_get_message_list (reader);
 +	window = e_mail_reader_get_window (reader);
 +
 +	folder = message_list->folder;
 +	uid = message_list->cursor_uid;
 +	g_return_if_fail (uid != NULL);
 +
 +	if (!em_utils_check_user_can_send_mail (window))
 +		return;
 +
 +	em_utils_redirect_message_by_uid (folder, uid);
 +}
 +
 +static void
 +action_mail_reply_all_cb (GtkAction *action,
 +                          EMailReader *reader)
 +{
 +	e_mail_reader_reply_to_message (reader, REPLY_MODE_ALL);
 +}
 +
 +static void
 +action_mail_reply_list_cb (GtkAction *action,
 +                           EMailReader *reader)
 +{
 +	e_mail_reader_reply_to_message (reader, REPLY_MODE_LIST);
 +}
 +
 +static void
 +action_mail_reply_sender_cb (GtkAction *action,
 +                             EMailReader *reader)
 +{
 +	e_mail_reader_reply_to_message (reader, REPLY_MODE_SENDER);
 +}
 +
 +static void
 +action_mail_save_as_cb (GtkAction *action,
 +                        EMailReader *reader)
 +{
 +	MessageList *message_list;
 +	CamelFolder *folder;
 +	GtkWindow *window;
 +	GPtrArray *uids;
 +
 +	message_list = e_mail_reader_get_message_list (reader);
 +	window = e_mail_reader_get_window (reader);
 +
 +	folder = message_list->folder;
 +	uids = message_list_get_selected (message_list);
 +
 +	em_utils_save_messages (window, folder, uids);
 +}
 +
 +static void
 +action_mail_search_folder_from_mailing_list_cb (GtkAction *action,
 +                                                EMailReader *reader)
 +{
 +	e_mail_reader_create_vfolder_from_selected (reader, AUTO_MLIST);
 +}
 +
 +static void
 +action_mail_search_folder_from_recipients_cb (GtkAction *action,
 +                                              EMailReader *reader)
 +{
 +	e_mail_reader_create_vfolder_from_selected (reader, AUTO_TO);
 +}
 +
 +static void
 +action_mail_search_folder_from_sender_cb (GtkAction *action,
 +                                          EMailReader *reader)
 +{
 +	e_mail_reader_create_vfolder_from_selected (reader, AUTO_FROM);
 +}
 +
 +static void
 +action_mail_search_folder_from_subject_cb (GtkAction *action,
 +                                           EMailReader *reader)
 +{
 +	e_mail_reader_create_vfolder_from_selected (reader, AUTO_SUBJECT);
 +}
 +
 +static void
 +action_mail_select_all_cb (GtkAction *action,
 +                           EMailReader *reader)
 +{
 +	EMFormatHTMLDisplay *html_display;
 +	GtkHTML *html;
 +	const gchar *action_name;
 +	gboolean selection_active;
 +
 +	html_display = e_mail_reader_get_html_display (reader);
 +	html = EM_FORMAT_HTML (html_display)->html;
 +
 +	gtk_html_select_all (html);
 +
 +	action_name = "mail-clipboard-copy";
 +	action = e_mail_reader_get_action (reader, action_name);
 +	selection_active = gtk_html_command (html, "is-selection-active");
 +	gtk_action_set_sensitive (action, selection_active);
 +}
 +
 +static void
 +action_mail_show_all_headers_cb (GtkToggleAction *action,
 +                                 EMailReader *reader)
 +{
 +	EMFormatHTMLDisplay *html_display;
 +	em_format_mode_t mode;
 +
 +	html_display = e_mail_reader_get_html_display (reader);
 +
 +	if (gtk_toggle_action_get_active (action))
 +		mode = EM_FORMAT_ALLHEADERS;
 +	else
 +		mode = EM_FORMAT_NORMAL;
 +
 +	em_format_set_mode (EM_FORMAT (html_display), mode);
 +}
 +
 +static void
 +action_mail_show_source_cb (GtkAction *action,
 +                            EMailReader *reader)
 +{
 +	EMFormatHTMLDisplay *html_display;
 +	EMailShellBackend *mail_shell_backend;
 +	EShellBackend *shell_backend;
 +	MessageList *message_list;
 +	CamelFolder *folder;
 +	GtkWidget *browser;
 +	GPtrArray *uids;
 +	const gchar *folder_uri;
 +
 +	message_list = e_mail_reader_get_message_list (reader);
 +	shell_backend = e_mail_reader_get_shell_backend (reader);
 +	mail_shell_backend = E_MAIL_SHELL_BACKEND (shell_backend);
 +
 +	folder = message_list->folder;
 +	folder_uri = message_list->folder_uri;
 +	uids = message_list_get_selected (message_list);
 +	g_return_if_fail (uids->len > 0);
 +
 +	browser = e_mail_browser_new (mail_shell_backend);
 +	reader = E_MAIL_READER (browser);
 +	html_display = e_mail_reader_get_html_display (reader);
 +	em_format_set_mode (EM_FORMAT (html_display), EM_FORMAT_SOURCE);
 +	e_mail_reader_set_folder (reader, folder, folder_uri);
 +	e_mail_reader_set_message (reader, uids->pdata[0], FALSE);
 +	gtk_widget_show (browser);
 +
 +	message_list_free_uids (message_list, uids);
 +}
 +
 +static void
 +action_mail_toggle_important_cb (GtkAction *action,
 +                                 EMailReader *reader)
 +{
 +	MessageList *message_list;
 +	CamelFolder *folder;
 +	GPtrArray *uids;
 +	guint ii;
 +
 +	message_list = e_mail_reader_get_message_list (reader);
 +
 +	folder = message_list->folder;
 +	uids = message_list_get_selected (message_list);
 +
 +	camel_folder_freeze (folder);
 +
 +	for (ii = 0; ii < uids->len; ii++) {
 +		guint32 flags;
 +
 +		flags = camel_folder_get_message_flags (
 +			folder, uids->pdata[ii]);
 +		flags ^= CAMEL_MESSAGE_FLAGGED;
 +		if (flags & CAMEL_MESSAGE_FLAGGED)
 +			flags &= ~CAMEL_MESSAGE_DELETED;
 +		camel_folder_set_message_flags (
 +			folder, uids->pdata[ii], CAMEL_MESSAGE_FLAGGED |
 +			CAMEL_MESSAGE_DELETED, flags);
 +	}
 +
 +	camel_folder_thaw (folder);
 +
 +	message_list_free_uids (message_list, uids);
 +}
 +
 +static void
 +action_mail_undelete_cb (GtkAction *action,
 +                         EMailReader *reader)
 +{
 +	guint32 mask = CAMEL_MESSAGE_DELETED;
 +	guint32 set  = 0;
 +
 +	e_mail_reader_mark_selected (reader, mask, set);
 +}
 +
 +static void
 +action_mail_uri_copy_cb (GtkAction *action,
 +                         EMailReader *reader)
 +{
 +	/* FIXME */
 +	g_print ("Action: %s\n", gtk_action_get_name (GTK_ACTION (action)));
 +}
 +
 +static void
 +action_mail_uri_copy_address_cb (GtkAction *action,
 +                                 EMailReader *reader)
 +{
 +	/* FIXME */
 +	g_print ("Action: %s\n", gtk_action_get_name (GTK_ACTION (action)));
 +}
 +
 +static void
 +action_mail_uri_to_search_folder_recipient_cb (GtkAction *action,
 +                                               EMailReader *reader)
 +{
 +	/* FIXME */
 +	g_print ("Action: %s\n", gtk_action_get_name (GTK_ACTION (action)));
 +}
 +
 +static void
 +action_mail_uri_to_search_folder_sender_cb (GtkAction *action,
 +                                            EMailReader *reader)
 +{
 +	/* FIXME */
 +	g_print ("Action: %s\n", gtk_action_get_name (GTK_ACTION (action)));
 +}
 +
 +static void
 +action_mail_zoom_100_cb (GtkAction *action,
 +                         EMailReader *reader)
 +{
 +	EMFormatHTMLDisplay *html_display;
 +	GtkHTML *html;
 +
 +	html_display = e_mail_reader_get_html_display (reader);
 +	html = EM_FORMAT_HTML (html_display)->html;
 +
 +	gtk_html_zoom_reset (html);
 +}
 +
 +static void
 +action_mail_zoom_in_cb (GtkAction *action,
 +                        EMailReader *reader)
 +{
 +	EMFormatHTMLDisplay *html_display;
 +	GtkHTML *html;
 +
 +	html_display = e_mail_reader_get_html_display (reader);
 +	html = EM_FORMAT_HTML (html_display)->html;
 +
 +	gtk_html_zoom_out (html);
 +}
 +
 +static void
 +action_mail_zoom_out_cb (GtkAction *action,
 +                         EMailReader *reader)
 +{
 +	EMFormatHTMLDisplay *html_display;
 +	GtkHTML *html;
 +
 +	html_display = e_mail_reader_get_html_display (reader);
 +	html = EM_FORMAT_HTML (html_display)->html;
 +
 +	gtk_html_zoom_out (html);
 +}
 +
 +static GtkActionEntry mail_reader_entries[] = {
 +
 +	{ "mail-add-sender",
 +	  NULL,
 +	  N_("A_dd Sender to Address Book"),
 +	  NULL,
 +	  N_("Add sender to address book"),
 +	  G_CALLBACK (action_mail_add_sender_cb) },
 +
 +	{ "mail-check-for-junk",
 +	  "mail-mark-junk",
 +	  N_("Check for _Junk"),
 +	  NULL,
 +	  N_("Filter the selected messages for junk status"),
 +	  G_CALLBACK (action_mail_check_for_junk_cb) },
 +
 +	{ "mail-clipboard-copy",
 +	  GTK_STOCK_COPY,
 +	  NULL,
 +	  NULL,
 +	  N_("Copy selected messages to the clipboard"),
 +	  G_CALLBACK (action_mail_clipboard_copy_cb) },
 +
 +	{ "mail-copy",
 +	  "mail-copy",
 +	  N_("_Copy to Folder..."),
 +	  "<Shift><Control>y",
 +	  N_("Copy selected messages to another folder"),
 +	  G_CALLBACK (action_mail_copy_cb) },
 +
 +	{ "mail-delete",
 +	  "user-trash",
 +	  N_("_Delete Message"),
 +	  "<Control>d",
 +	  N_("Mark the selected messages for deletion"),
 +	  G_CALLBACK (action_mail_delete_cb) },
 +
 +	{ "mail-filter-on-mailing-list",
 +	  NULL,
 +	  N_("Filter on Mailing _List..."),
 +	  NULL,
 +	  N_("Create a rule to filter messages to this mailing list"),
 +	  G_CALLBACK (action_mail_filter_on_mailing_list_cb) },
 +
 +	{ "mail-filter-on-recipients",
 +	  NULL,
 +	  N_("Filter on _Recipients..."),
 +	  NULL,
 +	  N_("Create a rule to filter messages to these recipients"),
 +	  G_CALLBACK (action_mail_filter_on_recipients_cb) },
 +
 +	{ "mail-filter-on-sender",
 +	  NULL,
 +	  N_("Filter on Se_nder..."),
 +	  NULL,
 +	  N_("Create a rule to filter messages from this sender"),
 +	  G_CALLBACK (action_mail_filter_on_sender_cb) },
 +
 +	{ "mail-filter-on-subject",
 +	  NULL,
 +	  N_("Filter on _Subject..."),
 +	  NULL,
 +	  N_("Create a rule to filter messages with this subject"),
 +	  G_CALLBACK (action_mail_filter_on_subject_cb) },
 +
 +	{ "mail-filters-apply",
 +	  "stock_mail-filters-apply",
 +	  N_("A_pply Filters"),
 +	  "<Control>y",
 +	  N_("Apply filter rules to the selected messages"),
 +	  G_CALLBACK (action_mail_filters_apply_cb) },
 +
 +	{ "mail-find",
 +	  GTK_STOCK_FIND,
 +	  N_("_Find in Message..."),
 +	  "<Shift><Control>f",
 +	  N_("Search for text in the body of the displayed message"),
 +	  G_CALLBACK (action_mail_find_cb) },
 +
 +	{ "mail-flag-clear",
 +	  NULL,
 +	  N_("_Clear Flag"),
 +	  NULL,
 +	  N_("Remove the follow-up flag from the selected messages"),
 +	  G_CALLBACK (action_mail_flag_clear_cb) },
 +
 +	{ "mail-flag-completed",
 +	  NULL,
 +	  N_("_Flag Completed"),
 +	  NULL,
 +	  N_("Set the follow-up flag to completed on the selected messages"),
 +	  G_CALLBACK (action_mail_flag_completed_cb) },
 +
 +	{ "mail-flag-for-followup",
 +	  "stock_mail-flag-for-followup",
 +	  N_("Follow _Up..."),
 +	  "<Shift><Control>g",
 +	  N_("Flag the selected messages for follow-up"),
 +	  G_CALLBACK (action_mail_flag_for_followup_cb) },
 +
 +	{ "mail-forward",
 +	  "mail-forward",
 +	  N_("_Forward"),
 +	  "<Control>f",
 +	  N_("Forward the selected message to someone"),
 +	  G_CALLBACK (action_mail_forward_cb) },
 +
 +	{ "mail-forward-attached",
 +	  NULL,
 +	  N_("_Attached"),
 +	  NULL,
 +	  N_("Forward the selected message to someone as an attachment"),
 +	  G_CALLBACK (action_mail_forward_attached_cb) },
 +
 +	{ "mail-forward-inline",
 +	  NULL,
 +	  N_("_Inline"),
 +	  NULL,
 +	  N_("Forward the selected message in the body of a new message"),
 +	  G_CALLBACK (action_mail_forward_inline_cb) },
 +
 +	{ "mail-forward-quoted",
 +	  NULL,
 +	  N_("_Quoted"),
 +	  NULL,
 +	  N_("Forward the selected message quoted like a reply"),
 +	  G_CALLBACK (action_mail_forward_quoted_cb) },
 +
 +	{ "mail-load-images",
 +	  "image-x-generic",
 +	  N_("_Load Images"),
 +	  "<Control>i",
 +	  N_("Force images in HTML mail to be loaded"),
 +	  G_CALLBACK (action_mail_load_images_cb) },
 +
 +	{ "mail-mark-important",
 +	  "mail-mark-important",
 +	  N_("_Important"),
 +	  NULL,
 +	  N_("Mark the selected messages as important"),
 +	  G_CALLBACK (action_mail_mark_important_cb) },
 +
 +	{ "mail-mark-junk",
 +	  "mail-mark-junk",
 +	  N_("_Junk"),
 +	  "<Control>j",
 +	  N_("Mark the selected messages as junk"),
 +	  G_CALLBACK (action_mail_mark_junk_cb) },
 +
 +	{ "mail-mark-notjunk",
 +	  "mail-mark-notjunk",
 +	  N_("_Not Junk"),
 +	  "<Shift><Control>j",
 +	  N_("Mark the selected messasges as not being junk"),
 +	  G_CALLBACK (action_mail_mark_notjunk_cb) },
 +
 +	{ "mail-mark-read",
 +	  "mail-mark-read",
 +	  N_("_Read"),
 +	  "<Control>k",
 +	  N_("Mark the selected messages as having been read"),
 +	  G_CALLBACK (action_mail_mark_read_cb) },
 +
 +	{ "mail-mark-unimportant",
 +	  NULL,
 +	  N_("Uni_mportant"),
 +	  NULL,
 +	  N_("Mark the selected messages as unimportant"),
 +	  G_CALLBACK (action_mail_mark_unimportant_cb) },
 +
 +	{ "mail-mark-unread",
 +	  "mail-mark-unread",
 +	  N_("_Unread"),
 +	  "<Shift><Control>k",
 +	  N_("Mark the selected messages as not having been read"),
 +	  G_CALLBACK (action_mail_mark_unread_cb) },
 +
 +	{ "mail-message-edit",
 +	  NULL,
 +	  N_("_Edit as New Message..."),
 +	  NULL,
 +	  N_("Open the selected messages in the composer for editing"),
 +	  G_CALLBACK (action_mail_message_edit_cb) },
 +
 +	{ "mail-message-new",
 +	  "mail-message-new",
 +	  N_("Compose _New Message"),
 +	  "<Shift><Control>m",
 +	  N_("Open a window for composing a mail message"),
 +	  G_CALLBACK (action_mail_message_new_cb) },
 +
 +	{ "mail-message-open",
 +	  NULL,
 +	  N_("_Open in New Window"),
 +	  "<Control>o",
 +	  N_("Open the selected messages in a new window"),
 +	  G_CALLBACK (action_mail_message_open_cb) },
 +
 +	{ "mail-move",
 +	  "mail-move",
 +	  N_("_Move to Folder..."),
 +	  "<Shift><Control>v",
 +	  N_("Move selected messages to another folder"),
 +	  G_CALLBACK (action_mail_move_cb) },
 +
 +	{ "mail-next",
 +	  GTK_STOCK_GO_FORWARD,
 +	  N_("_Next Message"),
 +	  "<Control>Page_Down",
 +	  N_("Display the next message"),
 +	  G_CALLBACK (action_mail_next_cb) },
 +
 +	{ "mail-next-important",
 +	  NULL,
 +	  N_("Next _Important Message"),
 +	  NULL,
 +	  N_("Display the next important message"),
 +	  G_CALLBACK (action_mail_next_important_cb) },
 +
 +	{ "mail-next-thread",
 +	  NULL,
 +	  N_("Next _Thread"),
 +	  NULL,
 +	  N_("Display the next thread"),
 +	  G_CALLBACK (action_mail_next_thread_cb) },
 +
 +	{ "mail-next-unread",
 +	  NULL,
 +	  N_("Next _Unread Message"),
 +	  "<Control>bracketright",
 +	  N_("Display the next unread message"),
 +	  G_CALLBACK (action_mail_next_unread_cb) },
 +
 +	{ "mail-previous",
 +	  GTK_STOCK_GO_BACK,
 +	  N_("_Previous Message"),
 +	  "<Control>Page_Up",
 +	  N_("Display the previous message"),
 +	  G_CALLBACK (action_mail_previous_cb) },
 +
 +	{ "mail-previous-important",
 +	  NULL,
 +	  N_("Pr_evious Important Message"),
 +	  NULL,
 +	  N_("Display the previous important message"),
 +	  G_CALLBACK (action_mail_previous_important_cb) },
 +
 +	{ "mail-previous-unread",
 +	  NULL,
 +	  N_("P_revious Unread Message"),
 +	  "<Control>bracketleft",
 +	  N_("Display the previous unread message"),
 +	  G_CALLBACK (action_mail_previous_unread_cb) },
 +
 +	{ "mail-print",
 +	  GTK_STOCK_PRINT,
 +	  NULL,
 +	  "<Control>p",
 +	  N_("Print this message"),
 +	  G_CALLBACK (action_mail_print_cb) },
 +
 +	{ "mail-print-preview",
 +	  GTK_STOCK_PRINT_PREVIEW,
 +	  NULL,
 +	  NULL,
 +	  N_("Preview the message to be printed"),
 +	  G_CALLBACK (action_mail_print_preview_cb) },
 +
 +	{ "mail-redirect",
 +	  NULL,
 +	  N_("Re_direct"),
 +	  NULL,
 +	  N_("Redirect (bounce) the selected message to someone"),
 +	  G_CALLBACK (action_mail_redirect_cb) },
 +
 +	{ "mail-reply-all",
 +	  "mail-reply-all",
 +	  N_("Reply to _All"),
 +	  "<Shift><Control>r",
 +	  N_("Compose a reply to all the recipients of the selected message"),
 +	  G_CALLBACK (action_mail_reply_all_cb) },
 +
 +	{ "mail-reply-list",
 +	  NULL,
 +	  N_("Reply to _List"),
 +	  "<Control>l",
 +	  N_("Compose a reply to the mailing list of the selected message"),
 +	  G_CALLBACK (action_mail_reply_list_cb) },
 +
 +	{ "mail-reply-sender",
 +	  "mail-reply-sender",
 +	  N_("_Reply to Sender"),
 +	  "<Control>r",
 +	  N_("Compose a reply to the sender of the selected message"),
 +	  G_CALLBACK (action_mail_reply_sender_cb) },
 +
 +	{ "mail-save-as",
 +	  GTK_STOCK_SAVE_AS,
 +	  N_("_Save as mbox..."),
 +	  NULL,
 +	  N_("Save selected messages as an mbox file"),
 +	  G_CALLBACK (action_mail_save_as_cb) },
 +
 +	{ "mail-search-folder-from-mailing-list",
 +	  NULL,
 +	  N_("Search Folder from Mailing _List..."),
 +	  NULL,
 +	  N_("Create a search folder for this mailing list"),
 +	  G_CALLBACK (action_mail_search_folder_from_mailing_list_cb) },
 +
 +	{ "mail-search-folder-from-recipients",
 +	  NULL,
 +	  N_("Search Folder from Recipien_ts..."),
 +	  NULL,
 +	  N_("Create a search folder for these recipients"),
 +	  G_CALLBACK (action_mail_search_folder_from_recipients_cb) },
 +
 +	{ "mail-search-folder-from-sender",
 +	  NULL,
 +	  N_("Search Folder from Sen_der..."),
 +	  NULL,
 +	  N_("Create a search folder for this sender"),
 +	  G_CALLBACK (action_mail_search_folder_from_sender_cb) },
 +
 +	{ "mail-search-folder-from-subject",
 +	  NULL,
 +	  N_("Search Folder from S_ubject..."),
 +	  NULL,
 +	  N_("Create a search folder for this subject"),
 +	  G_CALLBACK (action_mail_search_folder_from_subject_cb) },
 +
 +	{ "mail-select-all",
 +	  NULL,
 +	  N_("Select _All Text"),
 +	  "<Shift><Control>x",
 +	  N_("Select all the text in a message"),
 +	  G_CALLBACK (action_mail_select_all_cb) },
 +
 +	{ "mail-show-source",
 +	  NULL,
 +	  N_("_Message Source"),
 +	  "<Control>u",
 +	  N_("Show the raw email source of the message"),
 +	  G_CALLBACK (action_mail_show_source_cb) },
 +
 +	{ "mail-toggle-important",
 +	  NULL,
 +	  NULL,  /* No menu item; key press only */
 +	  NULL,
 +	  NULL,
 +	  G_CALLBACK (action_mail_toggle_important_cb) },
 +
 +	{ "mail-undelete",
 +	  NULL,
 +	  N_("_Undelete Message"),
 +	  "<Shift><Control>d",
 +	  N_("Undelete the selected messages"),
 +	  G_CALLBACK (action_mail_undelete_cb) },
 +
 +	{ "mail-uri-copy",
 +	  NULL,
 +	  N_("_Copy Link Location"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  G_CALLBACK (action_mail_uri_copy_cb) },
 +
 +	{ "mail-uri-copy-address",
 +	  GTK_STOCK_COPY,
 +	  N_("Copy _Email Address"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  G_CALLBACK (action_mail_uri_copy_address_cb) },
 +
 +	{ "mail-uri-to-search-folder-recipient",
 +	  NULL,
 +	  N_("_To This Address"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  G_CALLBACK (action_mail_uri_to_search_folder_recipient_cb) },
 +
 +	{ "mail-uri-to-search-folder-sender",
 +	  NULL,
 +	  N_("_From This Address"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  G_CALLBACK (action_mail_uri_to_search_folder_sender_cb) },
 +
 +	{ "mail-zoom-100",
 +	  GTK_STOCK_ZOOM_100,
 +	  N_("_Normal Size"),
 +	  "<Control>0",
 +	  N_("Reset the text to its original size"),
 +	  G_CALLBACK (action_mail_zoom_100_cb) },
 +
 +	{ "mail-zoom-in",
 +	  GTK_STOCK_ZOOM_IN,
 +	  N_("_Zoom In"),
 +	  "<Control>plus",
 +	  N_("Increase the text size"),
 +	  G_CALLBACK (action_mail_zoom_in_cb) },
 +
 +	{ "mail-zoom-out",
 +	  GTK_STOCK_ZOOM_OUT,
 +	  N_("Zoom _Out"),
 +	  "<Control>minus",
 +	  N_("Decrease the text size"),
 +	  G_CALLBACK (action_mail_zoom_out_cb) },
 +
 +	/*** Menus ***/
 +
 +	{ "mail-create-rule-menu",
 +	  NULL,
 +	  N_("Create R_ule"),
 +	  NULL,
 +	  NULL,
 +	  NULL },
 +
 +	{ "mail-encoding-menu",
 +	  NULL,
 +	  N_("Ch_aracter Encoding"),
 +	  NULL,
 +	  NULL,
 +	  NULL },
 +
 +	{ "mail-forward-as-menu",
 +	  NULL,
 +	  N_("F_orward As..."),
 +	  NULL,
 +	  NULL,
 +	  NULL },
 +
 +	{ "mail-goto-menu",
 +	  GTK_STOCK_JUMP_TO,
 +	  N_("_Go To"),
 +	  NULL,
 +	  NULL,
 +	  NULL },
 +
 +	{ "mail-mark-as-menu",
 +	  NULL,
 +	  N_("Mar_k As"),
 +	  NULL,
 +	  NULL,
 +	  NULL },
 +
 +	{ "mail-message-menu",
 +	  NULL,
 +	  N_("_Message"),
 +	  NULL,
 +	  NULL,
 +	  NULL },
 +
 +	{ "mail-uri-to-search-folder-menu",
 +	  NULL,
 +	  N_("Create _Search Folder"),
 +	  NULL,
 +	  NULL,
 +	  NULL },
 +
 +	{ "mail-zoom-menu",
 +	  NULL,
 +	  N_("_Zoom"),
 +	  NULL,
 +	  NULL,
 +	  NULL }
 +};
 +
 +static EPopupActionEntry mail_reader_popup_entries[] = {
 +
 +	{ "mail-popup-copy",
 +	  NULL,
 +	  "mail-copy" },
 +
 +	{ "mail-popup-delete",
 +	  NULL,
 +	  "mail-delete" },
 +
 +	{ "mail-popup-flag-for-followup",
 +	  N_("Mark for Follo_w Up..."),
 +	  "mail-flag-for-followup" },
 +
 +	{ "mail-popup-forward",
 +	  NULL,
 +	  "mail-forward" },
 +
 +	{ "mail-popup-mark-important",
 +	  N_("Mark as _Important"),
 +	  "mail-mark-important" },
 +
 +	{ "mail-popup-mark-junk",
 +	  N_("Mark as _Junk"),
 +	  "mail-mark-junk" },
 +
 +	{ "mail-popup-mark-notjunk",
 +	  N_("Mark as _Not Junk"),
 +	  "mail-mark-notjunk" },
 +
 +	{ "mail-popup-mark-read",
 +	  N_("Mark as _Read"),
 +	  "mail-mark-read" },
 +
 +	{ "mail-popup-mark-unimportant",
 +	  N_("Mark as Uni_mportant"),
 +	  "mail-mark-unimportant" },
 +
 +	{ "mail-popup-mark-unread",
 +	  N_("Mark as _Unread"),
 +	  "mail-mark-unread" },
 +
 +	{ "mail-popup-message-edit",
 +	  NULL,
 +	  "mail-message-edit" },
 +
 +	{ "mail-popup-move",
 +	  NULL,
 +	  "mail-move" },
 +
 +	{ "mail-popup-print",
 +	  NULL,
 +	  "mail-print" },
 +
 +	{ "mail-popup-reply-all",
 +	  NULL,
 +	  "mail-reply-all" },
 +
 +	{ "mail-popup-reply-sender",
 +	  NULL,
 +	  "mail-reply-sender" },
 +
 +	{ "mail-popup-save-as",
 +	  NULL,
 +	  "mail-save-as" },
 +
 +	{ "mail-popup-undelete",
 +	  NULL,
 +	  "mail-undelete" }
 +};
 +
 +static GtkToggleActionEntry mail_reader_toggle_entries[] = {
 +
 +	{ "mail-caret-mode",
 +	  NULL,
 +	  N_("_Caret Mode"),
 +	  "F7",
 +	  N_("Show a blinking cursor in the body of displayed messages"),
 +	  NULL,  /* No callback required */
 +	  FALSE },
 +
 +	{ "mail-show-all-headers",
 +	  NULL,
 +	  N_("All Message _Headers"),
 +	  NULL,
 +	  N_("Show messages with all email headers"),
 +	  G_CALLBACK (action_mail_show_all_headers_cb),
 +	  FALSE }
 +};
 +
 +static gboolean
 +mail_reader_html_button_release_event_cb (EMailReader *reader,
 +                                          GdkEventButton *button,
 +                                          GtkHTML *html)
 +{
 +	GtkAction *action;
 +	const gchar *action_name;
 +	gboolean selection_active;
 +
 +	action_name = "mail-clipboard-copy";
 +	action = e_mail_reader_get_action (reader, action_name);
 +	selection_active = gtk_html_command (html, "is-selection-active");
 +	gtk_action_set_sensitive (action, selection_active);
 +
 +	return FALSE;
 +}
 +
 +static void
 +mail_reader_double_click_cb (EMailReader *reader,
 +                             gint row,
 +                             ETreePath path,
 +                             gint col,
 +                             GdkEvent *event)
 +{
 +	/* Ignore double clicks on columns that handle their own state. */
 +	if (MESSAGE_LIST_COLUMN_IS_ACTIVE (col))
 +		return;
 +
 +	e_mail_reader_activate (reader, "mail-message-open");
 +}
 +
 +static gboolean
 +mail_reader_key_press_event_cb (EMailReader *reader,
 +                                GdkEventKey *event)
 +{
 +	const gchar *action_name;
 +
 +	if ((event->state & GDK_CONTROL_MASK) != 0)
 +		goto ctrl;
 +
 +	/* <keyval> alone */
 +	switch (event->keyval) {
 +		case GDK_Delete:
 +		case GDK_KP_Delete:
 +			action_name = "mail-delete";
 +			break;
 +
 +		case GDK_Return:
 +		case GDK_KP_Enter:
 +		case GDK_ISO_Enter:
 +			action_name = "mail-message-open";
 +			break;
 +
 +		case GDK_period:
 +			action_name = "mail-next-unread";
 +			break;
 +
 +		case GDK_comma:
 +			action_name = "mail-previous-unread";
 +			break;
 +
 +#ifdef HAVE_XFREE
 +		case XF86XK_Reply:
 +			action_name = "mail-reply-all";
 +			break;
 +
 +		case XF86XK_MailForward:
 +			action_name = "mail-forward";
 +			break;
 +#endif
 +
 +		case '!':
 +			action_name = "mail-toggle-important";
 +			break;
 +
 +		default:
 +			return FALSE;
 +	}
 +
 +	goto exit;
 +
 +ctrl:
 +
 +	/* Ctrl + <keyval> */
 +	switch (event->keyval) {
 +		case GDK_period:
 +			action_name = "mail-next-unread";
 +			break;
 +
 +		case GDK_comma:
 +			action_name = "mail-previous-unread";
 +			break;
 +
 +		default:
 +			return FALSE;
 +	}
 +
 +exit:
 +	e_mail_reader_activate (reader, action_name);
 +
 +	return TRUE;
 +}
 +
 +static gint
 +mail_reader_key_press_cb (EMailReader *reader,
 +                          gint row,
 +                          ETreePath path,
 +                          gint col,
 +                          GdkEvent *event)
 +{
 +	return mail_reader_key_press_event_cb (reader, &event->key);
 +}
 +
 +static gboolean
 +mail_reader_message_read_cb (EMailReader *reader)
 +{
 +	MessageList *message_list;
 +	const gchar *uid;
 +
 +	message_list = e_mail_reader_get_message_list (reader);
 +
 +	uid = g_object_get_data (G_OBJECT (reader), "mark-read-uid");
 +	g_return_val_if_fail (uid != NULL, FALSE);
 +
 +	if (g_strcmp0 (message_list->cursor_uid, uid) == 0)
 +		e_mail_reader_mark_as_read (reader, uid);
 +
 +	return FALSE;
 +}
 +
 +static void
 +mail_reader_message_loaded_cb (CamelFolder *folder,
 +                               const gchar *message_uid,
 +                               CamelMimeMessage *message,
 +                               gpointer user_data,
 +                               CamelException *ex)
 +{
 +	EMailReader *reader = user_data;
 +	EMFormatHTMLDisplay *html_display;
 +	MessageList *message_list;
 +	EShellBackend *shell_backend;
 +	EShellSettings *shell_settings;
 +	EShell *shell;
 +	EMEvent *event;
 +	EMEventTargetMessage *target;
 +	gboolean mark_read;
 +	gint timeout_interval;
 +
 +	html_display = e_mail_reader_get_html_display (reader);
 +	message_list = e_mail_reader_get_message_list (reader);
 +
 +	shell_backend = e_mail_reader_get_shell_backend (reader);
 +	shell = e_shell_backend_get_shell (shell_backend);
 +	shell_settings = e_shell_get_shell_settings (shell);
 +
 +	/* If the user picked a different message in the time it took
 +	 * to fetch this message, then don't bother rendering it. */
 +	if (g_strcmp0 (message_list->cursor_uid, message_uid) != 0)
 +		return;
 +
 +	/** @Event: message.reading
 +	 * @Title: Viewing a message
 +	 * @Target: EMEventTargetMessage
 +	 *
 +	 * message.reading is emitted whenever a user views a message.
 +	 */
 +	event = em_event_peek ();
 +	target = em_event_target_new_message (
 +		event, folder, message, message_uid, 0);
 +	e_event_emit (
 +		(EEvent *) event, "message.reading",
 +		(EEventTarget *) target);
 +
 +	em_format_format (
 +		EM_FORMAT (html_display), folder, message_uid, message);
 +
 +	/* Reset the shell view icon. */
- 	e_shell_event (shell, "mail-icon", "evolution-mail");
++	e_shell_event (shell, "mail-icon", (gpointer) "evolution-mail");
 +
 +	/* Determine whether to mark the message as read. */
 +	mark_read = e_shell_settings_get_boolean (
 +		shell_settings, "mail-mark-seen");
 +	timeout_interval = e_shell_settings_get_int (
 +		shell_settings, "mail-mark-seen-timeout");
 +
 +	g_object_set_data_full (
 +		G_OBJECT (reader), "mark-read-uid",
 +		g_strdup (message_uid), (GDestroyNotify) g_free);
 +
 +	if (message_list->seen_id > 0)
 +		g_source_remove (message_list->seen_id);
 +
 +	if (mark_read) {
 +		message_list->seen_id = g_timeout_add (
 +			timeout_interval, (GSourceFunc)
 +			mail_reader_message_read_cb, reader);
 +
 +	} else if (camel_exception_is_set (ex)) {
 +		GtkHTMLStream *stream;
 +
 +		/* Display the error inline and clear the exception. */
 +		stream = gtk_html_begin (
 +			EM_FORMAT_HTML (html_display)->html);
 +		gtk_html_stream_printf (
 +			stream, "<h2>%s</h2><p>%s</p>",
 +			_("Unable to retrieve message"),
 +			ex->desc);
 +		gtk_html_stream_close (stream, GTK_HTML_STREAM_OK);
 +		camel_exception_clear (ex);
 +	}
 +
 +	e_mail_reader_update_actions (reader);
 +
 +	/* We referenced this in the call to mail_get_messagex(). */
 +	g_object_unref (reader);
 +}
 +
 +static gboolean
 +mail_reader_message_selected_timeout_cb (EMailReader *reader)
 +{
 +	EMFormatHTMLDisplay *html_display;
 +	MessageList *message_list;
 +	const gchar *cursor_uid;
 +	const gchar *format_uid;
 +	const gchar *key;
 +
 +	html_display = e_mail_reader_get_html_display (reader);
 +	message_list = e_mail_reader_get_message_list (reader);
 +
 +	cursor_uid = message_list->cursor_uid;
 +	format_uid = EM_FORMAT (html_display)->uid;
 +
 +	if (cursor_uid != NULL) {
 +		if (g_strcmp0 (cursor_uid, format_uid) != 0)
 +			mail_get_messagex (
 +				message_list->folder, cursor_uid,
 +				mail_reader_message_loaded_cb,
 +				g_object_ref (reader),
 +				mail_msg_fast_ordered_push);
 +	} else
 +		em_format_format (EM_FORMAT (html_display), NULL, NULL, NULL);
 +
 +	key = "message-selected-timeout";
 +	g_object_set_data (G_OBJECT (reader), key, NULL);
 +
 +	return FALSE;
 +}
 +
 +static void
 +mail_reader_message_selected_cb (EMailReader *reader,
 +                                 const gchar *uid)
 +{
 +	const gchar *key;
 +	guint source_id;
 +	gpointer data;
 +
 +	/* XXX This is kludgy, but we have no other place to store
 +	 *     timeout state information. */
 +
 +	key = "message-selected-timeout";
 +	data = g_object_get_data (G_OBJECT (reader), key);
 +	source_id = GPOINTER_TO_UINT (data);
 +
 +	if (source_id > 0)
 +		g_source_remove (source_id);
 +
 +	source_id = g_timeout_add (
 +		100, (GSourceFunc)
 +		mail_reader_message_selected_timeout_cb, reader);
 +
 +	data = GUINT_TO_POINTER (source_id);
 +	g_object_set_data (G_OBJECT (reader), key, data);
 +
 +	e_mail_reader_changed (reader);
 +}
 +
 +static void
 +mail_reader_emit_folder_loaded (EMailReader *reader)
 +{
 +	g_signal_emit (reader, signals[FOLDER_LOADED], 0);
 +}
 +
 +static void
 +mail_reader_set_folder (EMailReader *reader,
 +                        CamelFolder *folder,
 +                        const gchar *folder_uri)
 +{
 +	EMFormatHTMLDisplay *html_display;
 +	MessageList *message_list;
 +	gboolean outgoing;
 +
 +	html_display = e_mail_reader_get_html_display (reader);
 +	message_list = e_mail_reader_get_message_list (reader);
 +
 +	outgoing = folder != NULL && folder_uri != NULL && (
 +		em_utils_folder_is_drafts (folder, folder_uri) ||
 +		em_utils_folder_is_outbox (folder, folder_uri) ||
 +		em_utils_folder_is_sent (folder, folder_uri));
 +
 +	if (message_list->folder != NULL)
 +		mail_sync_folder (message_list->folder, NULL, NULL);
 +
 +	em_format_format (EM_FORMAT (html_display), NULL, NULL, NULL);
 +	message_list_set_folder (message_list, folder, folder_uri, outgoing);
 +
 +	mail_reader_emit_folder_loaded (reader);
 +}
 +
 +static void
 +mail_reader_set_message (EMailReader *reader,
 +                         const gchar *uid,
 +                         gboolean mark_read)
 +{
 +	MessageList *message_list;
 +
 +	message_list = e_mail_reader_get_message_list (reader);
 +	message_list_select_uid (message_list, uid);
 +}
 +
 +static void
 +mail_reader_init_charset_actions (EMailReader *reader)
 +{
 +	GtkActionGroup *action_group;
 +	GtkRadioAction *default_action;
 +	GSList *radio_group;
 +
 +	action_group = e_mail_reader_get_action_group (reader);
 +
 +	radio_group = e_charset_add_radio_actions (
 +		action_group, "mail-charset-", NULL,
 +		G_CALLBACK (action_mail_charset_cb), reader);
 +
 +	/* XXX Add a tooltip! */
 +	default_action = gtk_radio_action_new (
 +		"mail-charset-default", _("Default"), NULL, NULL, -1);
 +
 +	gtk_radio_action_set_group (default_action, radio_group);
 +
 +	g_signal_connect (
 +		default_action, "changed",
 +		G_CALLBACK (action_mail_charset_cb), reader);
 +
 +	gtk_action_group_add_action (
 +		action_group, GTK_ACTION (default_action));
 +
 +	gtk_radio_action_set_current_value (default_action, -1);
 +}
 +
 +static void
 +mail_reader_class_init (EMailReaderIface *iface)
 +{
 +	iface->set_folder = mail_reader_set_folder;
 +	iface->set_message = mail_reader_set_message;
 +
 +	signals[CHANGED] = g_signal_new (
 +		"changed",
 +		G_OBJECT_CLASS_TYPE (iface),
 +		G_SIGNAL_RUN_FIRST,
 +		0, NULL, NULL,
 +		g_cclosure_marshal_VOID__VOID,
 +		G_TYPE_NONE, 0);
 +
 +	signals[FOLDER_LOADED] = g_signal_new (
 +		"folder-loaded",
 +		G_OBJECT_CLASS_TYPE (iface),
 +		G_SIGNAL_RUN_FIRST,
 +		0, NULL, NULL,
 +		g_cclosure_marshal_VOID__VOID,
 +		G_TYPE_NONE, 0);
 +
 +	signals[SHOW_SEARCH_BAR] = g_signal_new (
 +		"show-search-bar",
 +		G_OBJECT_CLASS_TYPE (iface),
 +		G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
 +		G_STRUCT_OFFSET (EMailReaderIface, show_search_bar),
 +		NULL, NULL,
 +		g_cclosure_marshal_VOID__VOID,
 +		G_TYPE_NONE, 0);
 +}
 +
 +GType
 +e_mail_reader_get_type (void)
 +{
 +	static GType type = 0;
 +
 +	if (G_UNLIKELY (type == 0)) {
 +		static const GTypeInfo type_info = {
 +			sizeof (EMailReaderIface),
 +			(GBaseInitFunc) NULL,
 +			(GBaseFinalizeFunc) NULL,
 +			(GClassInitFunc) mail_reader_class_init,
 +			(GClassFinalizeFunc) NULL,
 +			NULL,  /* class_data */
 +			0,     /* instance_size */
 +			0,     /* n_preallocs */
 +			(GInstanceInitFunc) NULL,
 +			NULL   /* value_table */
 +		};
 +
 +		type = g_type_register_static (
 +			G_TYPE_INTERFACE, "EMailReader", &type_info, 0);
 +
 +		g_type_interface_add_prerequisite (type, G_TYPE_OBJECT);
 +	}
 +
 +	return type;
 +}
 +
 +void
 +e_mail_reader_init (EMailReader *reader)
 +{
 +	EShell *shell;
 +	EShellBackend *shell_backend;
 +	EShellSettings *shell_settings;
 +	EMFormatHTMLDisplay *html_display;
 +	GtkActionGroup *action_group;
 +	MessageList *message_list;
 +	GConfBridge *bridge;
 +	GtkAction *action;
 +	GtkHTML *html;
 +	const gchar *action_name;
 +	const gchar *key;
 +
 +	g_return_if_fail (E_IS_MAIL_READER (reader));
 +
 +	action_group = e_mail_reader_get_action_group (reader);
 +	html_display = e_mail_reader_get_html_display (reader);
 +	message_list = e_mail_reader_get_message_list (reader);
 +	shell_backend = e_mail_reader_get_shell_backend (reader);
 +
 +	shell = e_shell_backend_get_shell (shell_backend);
 +	shell_settings = e_shell_get_shell_settings (shell);
 +
 +	html = EM_FORMAT_HTML (html_display)->html;
 +
 +	gtk_action_group_add_actions (
 +		action_group, mail_reader_entries,
 +		G_N_ELEMENTS (mail_reader_entries), reader);
 +	e_action_group_add_popup_actions (
 +		action_group, mail_reader_popup_entries,
 +		G_N_ELEMENTS (mail_reader_popup_entries));
 +	gtk_action_group_add_toggle_actions (
 +		action_group, mail_reader_toggle_entries,
 +		G_N_ELEMENTS (mail_reader_toggle_entries), reader);
 +
 +	mail_reader_init_charset_actions (reader);
 +
 +	/* Bind GObject properties to GConf keys. */
 +
 +	bridge = gconf_bridge_get ();
 +
 +	action_name = "mail-caret-mode";
 +	key = "/apps/evolution/mail/display/caret_mode";
 +	action = e_mail_reader_get_action (reader, action_name);
 +	gconf_bridge_bind_property (bridge, key, G_OBJECT (action), "active");
 +
 +	action_name = "mail-show-all-headers";
 +	key = "/apps/evolution/mail/display/show_all_headers";
 +	action = e_mail_reader_get_action (reader, action_name);
 +	gconf_bridge_bind_property (bridge, key, G_OBJECT (action), "active");
 +
 +	/* Fine tuning. */
 +
 +	action_name = "mail-clipboard-copy";
 +	action = e_mail_reader_get_action (reader, action_name);
 +	gtk_action_set_sensitive (action, FALSE);
 +
 +	action_name = "mail-delete";
 +	action = e_mail_reader_get_action (reader, action_name);
 +	g_object_set (action, "short-label", _("Delete"), NULL);
 +
 +	action_name = "mail-next";
 +	action = e_mail_reader_get_action (reader, action_name);
 +	g_object_set (action, "short-label", _("Next"), NULL);
 +
 +	action_name = "mail-previous";
 +	action = e_mail_reader_get_action (reader, action_name);
 +	g_object_set (action, "short-label", _("Previous"), NULL);
 +
 +	action_name = "mail-reply-sender";
 +	action = e_mail_reader_get_action (reader, action_name);
 +	g_object_set (action, "short-label", _("Reply"), NULL);
 +
 +	/* Bind properties. */
 +
 +	e_binding_new_full (
 +		G_OBJECT (shell_settings), "mail-citation-color",
 +		G_OBJECT (html_display), "citation-color",
 +		e_binding_transform_string_to_color,
 +		NULL, NULL);
 +
 +	e_binding_new (
 +		G_OBJECT (shell_settings), "mail-image-loading-policy",
 +		G_OBJECT (html_display), "image-loading-policy");
 +
 +	e_binding_new (
 +		G_OBJECT (shell_settings), "mail-only-local-photos",
 +		G_OBJECT (html_display), "only-local-photos");
 +
 +	e_binding_new (
 +		G_OBJECT (shell_settings), "mail-show-animated-images",
 +		G_OBJECT (html), "animate");
 +
 +	e_binding_new (
 +		G_OBJECT (shell_settings), "mail-show-sender-photo",
 +		G_OBJECT (html_display), "show-sender-photo");
 +
 +	action_name = "mail-caret-mode";
 +	action = e_mail_reader_get_action (reader, action_name);
 +
 +	e_mutual_binding_new (
 +		G_OBJECT (action), "active",
 +		G_OBJECT (html), "caret-mode");
 +
 +	/* Connect signals. */
 +
 +	g_signal_connect_swapped (
 +		html, "button-release-event",
 +		G_CALLBACK (mail_reader_html_button_release_event_cb), reader);
 +
 +	g_signal_connect_swapped (
 +		html, "key-press-event",
 +		G_CALLBACK (mail_reader_key_press_event_cb), reader);
 +
 +	g_signal_connect_swapped (
 +		message_list, "message-selected",
 +		G_CALLBACK (mail_reader_message_selected_cb), reader);
 +
 +	g_signal_connect_swapped (
 +		message_list, "message-list-built",
 +		G_CALLBACK (mail_reader_emit_folder_loaded), reader);
 +
 +	g_signal_connect_swapped (
 +		message_list->tree, "double-click",
 +		G_CALLBACK (mail_reader_double_click_cb), reader);
 +
 +	g_signal_connect_swapped (
 +		message_list->tree, "key-press",
 +		G_CALLBACK (mail_reader_key_press_cb), reader);
 +
 +	g_signal_connect_swapped (
 +		message_list->tree, "selection-change",
 +		G_CALLBACK (e_mail_reader_changed), reader);
 +}
 +
 +void
 +e_mail_reader_changed (EMailReader *reader)
 +{
 +	g_return_if_fail (E_IS_MAIL_READER (reader));
 +
 +	g_signal_emit (reader, signals[CHANGED], 0);
 +}
 +
 +guint32
 +e_mail_reader_check_state (EMailReader *reader)
 +{
 +	MessageList *message_list;
 +	GPtrArray *uids;
 +	CamelFolder *folder;
 +	CamelStore *store = NULL;
 +	const gchar *folder_uri;
 +	const gchar *tag;
 +	gboolean can_clear_flags = FALSE;
 +	gboolean can_flag_completed = FALSE;
 +	gboolean can_flag_for_followup = FALSE;
 +	gboolean has_deleted = FALSE;
 +	gboolean has_important = FALSE;
 +	gboolean has_junk = FALSE;
 +	gboolean has_not_junk = FALSE;
 +	gboolean has_read = FALSE;
 +	gboolean has_undeleted = FALSE;
 +	gboolean has_unimportant = FALSE;
 +	gboolean has_unread = FALSE;
 +	gboolean drafts_or_outbox;
 +	gboolean store_supports_vjunk = FALSE;
 +	guint32 state = 0;
 +	guint ii;
 +
 +	g_return_val_if_fail (E_IS_MAIL_READER (reader), 0);
 +
 +	message_list = e_mail_reader_get_message_list (reader);
 +	uids = message_list_get_selected (message_list);
 +	folder_uri = message_list->folder_uri;
 +	folder = message_list->folder;
 +
 +	if (folder != NULL) {
 +		store = CAMEL_STORE (folder->parent_store);
 +		store_supports_vjunk = (store->flags & CAMEL_STORE_VJUNK);
 +	}
 +
 +	drafts_or_outbox =
 +		em_utils_folder_is_drafts (folder, folder_uri) ||
 +		em_utils_folder_is_outbox (folder, folder_uri);
 +
 +	for (ii = 0; ii < uids->len; ii++) {
 +		CamelMessageInfo *info;
 +		guint32 flags;
 +
 +		info = camel_folder_get_message_info (
 +			folder, uids->pdata[ii]);
 +		if (info == NULL)
 +			continue;
 +
 +		flags = camel_message_info_flags (info);
 +
 +		if (flags & CAMEL_MESSAGE_SEEN)
 +			has_read = TRUE;
 +		else
 +			has_unread = TRUE;
 +
 +		if (drafts_or_outbox) {
 +			has_junk = FALSE;
 +			has_not_junk = FALSE;
 +		} else if (store_supports_vjunk) {
 +			guint32 bitmask;
 +
 +			/* XXX Strictly speaking, this logic is correct.
 +			 *     Problem is there's nothing in the message
 +			 *     list that indicates whether a message is
 +			 *     already marked "Not Junk".  So the user may
 +			 *     think the "Not Junk" button is enabling and
 +			 *     disabling itself randomly as he reads mail. */
 +
 +			if (flags & CAMEL_MESSAGE_JUNK)
 +				has_junk = TRUE;
 +			if (flags & CAMEL_MESSAGE_NOTJUNK)
 +				has_not_junk = TRUE;
 +
 +			bitmask = CAMEL_MESSAGE_JUNK | CAMEL_MESSAGE_NOTJUNK;
 +
 +			/* If neither junk flag is set, the
 +			 * message can be marked either way. */
 +			if ((flags & bitmask) == 0) {
 +				has_junk = TRUE;
 +				has_not_junk = TRUE;
 +			}
 +
 +		} else {
 +			has_junk = TRUE;
 +			has_not_junk = TRUE;
 +		}
 +
 +		if (flags & CAMEL_MESSAGE_DELETED)
 +			has_deleted = TRUE;
 +		else
 +			has_undeleted = TRUE;
 +
 +		if (flags & CAMEL_MESSAGE_FLAGGED)
 +			has_important = TRUE;
 +		else
 +			has_unimportant = TRUE;
 +
 +		tag = camel_message_info_user_tag (info, "follow-up");
 +		if (tag != NULL && *tag != '\0') {
 +			can_clear_flags = TRUE;
 +			tag = camel_message_info_user_tag (
 +				info, "completed-on");
 +			if (tag != NULL && *tag != '\0')
 +				can_flag_completed = TRUE;
 +		} else
 +			can_flag_for_followup = TRUE;
 +	}
 +
 +	if (uids->len == 1)
 +		state |= E_MAIL_READER_SELECTION_SINGLE;
 +	if (uids->len > 1)
 +		state |= E_MAIL_READER_SELECTION_MULTIPLE;
 +	if (!drafts_or_outbox && uids->len == 1)
 +		state |= E_MAIL_READER_SELECTION_CAN_ADD_SENDER;
 +#if 0  /* FIXME */
 +	if (can_edit)
 +		state |= E_MAIL_READER_SELECTION_CAN_EDIT;
 +#endif
 +	if (can_clear_flags)
 +		state |= E_MAIL_READER_SELECTION_FLAG_CLEAR;
 +	if (can_flag_completed)
 +		state |= E_MAIL_READER_SELECTION_FLAG_COMPLETED;
 +	if (can_flag_for_followup)
 +		state |= E_MAIL_READER_SELECTION_FLAG_FOLLOWUP;
 +	if (has_deleted)
 +		state |= E_MAIL_READER_SELECTION_HAS_DELETED;
 +	if (has_important)
 +		state |= E_MAIL_READER_SELECTION_HAS_IMPORTANT;
 +	if (has_junk)
 +		state |= E_MAIL_READER_SELECTION_HAS_JUNK;
 +	if (has_not_junk)
 +		state |= E_MAIL_READER_SELECTION_HAS_NOT_JUNK;
 +	if (has_read)
 +		state |= E_MAIL_READER_SELECTION_HAS_READ;
 +	if (has_undeleted)
 +		state |= E_MAIL_READER_SELECTION_HAS_UNDELETED;
 +	if (has_unimportant)
 +		state |= E_MAIL_READER_SELECTION_HAS_UNIMPORTANT;
 +	if (has_unread)
 +		state |= E_MAIL_READER_SELECTION_HAS_UNREAD;
 +#if 0  /* FIXME */
 +	if (has_callto_uri)
 +		state |= E_MAIL_READER_SELECTION_HAS_URI_CALLTO;
 +	if (has_http_uri)
 +		state |= E_MAIL_READER_SELECTION_HAS_URI_HTTP;
 +	if (has_mailto_uri)
 +		state |= E_MAIL_READER_SELECTION_HAS_URI_MAILTO;
 +	if (is_mailing_list)
 +		state |= E_MAIL_READER_SELECTION_IS_MAILING_LIST;
 +#endif
 +
 +	em_utils_uids_free (uids);
 +
 +	return state;
 +
 +}
 +
 +void
 +e_mail_reader_update_actions (EMailReader *reader)
 +{
 +	EShell *shell;
 +	EShellBackend *shell_backend;
 +	EShellSettings *shell_settings;
 +	GtkAction *action;
 +	GtkActionGroup *action_group;
 +	const gchar *action_name;
 +	gboolean sensitive;
 +	guint32 state;
 +
 +	/* Be descriptive. */
 +	gboolean any_messages_selected;
 +	gboolean disable_printing;
 +	gboolean enable_flag_clear;
 +	gboolean enable_flag_completed;
 +	gboolean enable_flag_for_followup;
 +	gboolean single_message_selected;
 +	gboolean multiple_messages_selected;
 +	gboolean selection_has_deleted_messages;
 +	gboolean selection_has_important_messages;
 +	gboolean selection_has_junk_messages;
 +	gboolean selection_has_not_junk_messages;
 +	gboolean selection_has_read_messages;
 +	gboolean selection_has_undeleted_messages;
 +	gboolean selection_has_unimportant_messages;
 +	gboolean selection_has_unread_messages;
 +	gboolean selection_is_mailing_list;
 +
 +	g_return_if_fail (E_IS_MAIL_READER (reader));
 +
 +	action_group = e_mail_reader_get_action_group (reader);
 +	state = e_mail_reader_check_state (reader);
 +
 +	shell_backend = e_mail_reader_get_shell_backend (reader);
 +	shell = e_shell_backend_get_shell (shell_backend);
 +	shell_settings = e_shell_get_shell_settings (shell);
 +
 +	disable_printing = e_shell_settings_get_boolean (
 +		shell_settings, "disable-printing");
 +
 +	single_message_selected =
 +		(state & E_MAIL_READER_SELECTION_SINGLE);
 +	multiple_messages_selected =
 +		(state & E_MAIL_READER_SELECTION_MULTIPLE);
 +	/* FIXME Missing booleans */
 +	enable_flag_clear =
 +		(state & E_MAIL_READER_SELECTION_FLAG_CLEAR);
 +	enable_flag_completed =
 +		(state & E_MAIL_READER_SELECTION_FLAG_COMPLETED);
 +	enable_flag_for_followup =
 +		(state & E_MAIL_READER_SELECTION_FLAG_FOLLOWUP);
 +	selection_has_deleted_messages =
 +		(state & E_MAIL_READER_SELECTION_HAS_DELETED);
 +	selection_has_important_messages =
 +		(state & E_MAIL_READER_SELECTION_HAS_IMPORTANT);
 +	selection_has_junk_messages =
 +		(state & E_MAIL_READER_SELECTION_HAS_JUNK);
 +	selection_has_not_junk_messages =
 +		(state & E_MAIL_READER_SELECTION_HAS_NOT_JUNK);
 +	selection_has_read_messages =
 +		(state & E_MAIL_READER_SELECTION_HAS_READ);
 +	selection_has_undeleted_messages =
 +		(state & E_MAIL_READER_SELECTION_HAS_UNDELETED);
 +	selection_has_unimportant_messages =
 +		(state & E_MAIL_READER_SELECTION_HAS_UNIMPORTANT);
 +	selection_has_unread_messages =
 +		(state & E_MAIL_READER_SELECTION_HAS_UNREAD);
 +	/* FIXME Missing booleans */
 +	selection_is_mailing_list =
 +		(state & E_MAIL_READER_SELECTION_IS_MAILING_LIST);
 +
 +	any_messages_selected =
 +		(single_message_selected || multiple_messages_selected);
 +
 +	action_name = "mail-check-for-junk";
 +	sensitive = any_messages_selected;
 +	action = e_mail_reader_get_action (reader, action_name);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action_name = "mail-copy";
 +	sensitive = any_messages_selected;
 +	action = e_mail_reader_get_action (reader, action_name);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action_name = "mail-delete";
 +	sensitive = selection_has_undeleted_messages;
 +	action = e_mail_reader_get_action (reader, action_name);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action_name = "mail-filters-apply";
 +	sensitive = any_messages_selected;
 +	action = e_mail_reader_get_action (reader, action_name);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action_name = "mail-forward";
 +	sensitive = any_messages_selected;
 +	action = e_mail_reader_get_action (reader, action_name);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action_name = "mail-forward-attached";
 +	sensitive = any_messages_selected;
 +	action = e_mail_reader_get_action (reader, action_name);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action_name = "mail-forward-inline";
 +	sensitive = single_message_selected;
 +	action = e_mail_reader_get_action (reader, action_name);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action_name = "mail-forward-quoted";
 +	sensitive = single_message_selected;
 +	action = e_mail_reader_get_action (reader, action_name);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action_name = "mail-load-images";
 +	sensitive = single_message_selected;
 +	action = e_mail_reader_get_action (reader, action_name);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action_name = "mail-mark-important";
 +	sensitive = selection_has_unimportant_messages;
 +	action = e_mail_reader_get_action (reader, action_name);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action_name = "mail-mark-junk";
 +	sensitive = selection_has_not_junk_messages;
 +	action = e_mail_reader_get_action (reader, action_name);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action_name = "mail-mark-notjunk";
 +	sensitive = selection_has_junk_messages;
 +	action = e_mail_reader_get_action (reader, action_name);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action_name = "mail-mark-read";
 +	sensitive = selection_has_unread_messages;
 +	action = e_mail_reader_get_action (reader, action_name);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action_name = "mail-mark-unimportant";
 +	sensitive = selection_has_important_messages;
 +	action = e_mail_reader_get_action (reader, action_name);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action_name = "mail-mark-unread";
 +	sensitive = selection_has_read_messages;
 +	action = e_mail_reader_get_action (reader, action_name);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action_name = "mail-message-edit";
 +	sensitive = single_message_selected;
 +	action = e_mail_reader_get_action (reader, action_name);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action_name = "mail-message-open";
 +	sensitive = any_messages_selected;
 +	action = e_mail_reader_get_action (reader, action_name);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action_name = "mail-move";
 +	sensitive = any_messages_selected;
 +	action = e_mail_reader_get_action (reader, action_name);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action_name = "mail-next-important";
 +	sensitive = single_message_selected;
 +	action = e_mail_reader_get_action (reader, action_name);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action_name = "mail-next-thread";
 +	sensitive = single_message_selected;
 +	action = e_mail_reader_get_action (reader, action_name);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action_name = "mail-next-unread";
 +	sensitive = single_message_selected;
 +	action = e_mail_reader_get_action (reader, action_name);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action_name = "mail-previous-important";
 +	sensitive = single_message_selected;
 +	action = e_mail_reader_get_action (reader, action_name);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action_name = "mail-previous-unread";
 +	sensitive = single_message_selected;
 +	action = e_mail_reader_get_action (reader, action_name);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action_name = "mail-print";
 +	sensitive = single_message_selected && !disable_printing;
 +	action = e_mail_reader_get_action (reader, action_name);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action_name = "mail-print-preview";
 +	sensitive = single_message_selected && !disable_printing;
 +	action = e_mail_reader_get_action (reader, action_name);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action_name = "mail-redirect";
 +	sensitive = single_message_selected;
 +	action = e_mail_reader_get_action (reader, action_name);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action_name = "mail-reply-all";
 +	sensitive = single_message_selected;
 +	action = e_mail_reader_get_action (reader, action_name);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action_name = "mail-reply-list";
 +	sensitive = single_message_selected && selection_is_mailing_list;
 +	action = e_mail_reader_get_action (reader, action_name);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action_name = "mail-reply-sender";
 +	sensitive = single_message_selected;
 +	action = e_mail_reader_get_action (reader, action_name);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action_name = "mail-save-as";
 +	sensitive = any_messages_selected;
 +	action = e_mail_reader_get_action (reader, action_name);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action_name = "mail-select-all";
 +	sensitive = single_message_selected;
 +	action = e_mail_reader_get_action (reader, action_name);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action_name = "mail-show-source";
 +	sensitive = single_message_selected;
 +	action = e_mail_reader_get_action (reader, action_name);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action_name = "mail-undelete";
 +	sensitive = selection_has_deleted_messages;
 +	action = e_mail_reader_get_action (reader, action_name);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action_name = "mail-zoom-100";
 +	sensitive = single_message_selected;
 +	action = e_mail_reader_get_action (reader, action_name);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action_name = "mail-zoom-in";
 +	sensitive = single_message_selected;
 +	action = e_mail_reader_get_action (reader, action_name);
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action_name = "mail-zoom-out";
 +	sensitive = single_message_selected;
 +	action = e_mail_reader_get_action (reader, action_name);
 +	gtk_action_set_sensitive (action, sensitive);
 +}
 +
 +GtkAction *
 +e_mail_reader_get_action (EMailReader *reader,
 +                          const gchar *action_name)
 +{
 +	GtkActionGroup *action_group;
 +	GtkAction *action;
 +
 +	g_return_val_if_fail (E_IS_MAIL_READER (reader), NULL);
 +	g_return_val_if_fail (action_name != NULL, NULL);
 +
 +	action_group = e_mail_reader_get_action_group (reader);
 +	action = gtk_action_group_get_action (action_group, action_name);
 +
 +	if (action == NULL)
 +		g_critical (
 +			"%s: action `%s' not found", G_STRFUNC, action_name);
 +
 +	return action;
 +}
 +
 +GtkActionGroup *
 +e_mail_reader_get_action_group (EMailReader *reader)
 +{
 +	EMailReaderIface *iface;
 +
 +	g_return_val_if_fail (E_IS_MAIL_READER (reader), NULL);
 +
 +	iface = E_MAIL_READER_GET_IFACE (reader);
 +	g_return_val_if_fail (iface->get_action_group != NULL, NULL);
 +
 +	return iface->get_action_group (reader);
 +}
 +
 +gboolean
 +e_mail_reader_get_hide_deleted (EMailReader *reader)
 +{
 +	EMailReaderIface *iface;
 +
 +	g_return_val_if_fail (E_IS_MAIL_READER (reader), FALSE);
 +
 +	iface = E_MAIL_READER_GET_IFACE (reader);
 +	g_return_val_if_fail (iface->get_hide_deleted != NULL, FALSE);
 +
 +	return iface->get_hide_deleted (reader);
 +}
 +
 +EMFormatHTMLDisplay *
 +e_mail_reader_get_html_display (EMailReader *reader)
 +{
 +	EMailReaderIface *iface;
 +
 +	g_return_val_if_fail (E_IS_MAIL_READER (reader), NULL);
 +
 +	iface = E_MAIL_READER_GET_IFACE (reader);
 +	g_return_val_if_fail (iface->get_html_display != NULL, NULL);
 +
 +	return iface->get_html_display (reader);
 +}
 +
 +MessageList *
 +e_mail_reader_get_message_list (EMailReader *reader)
 +{
 +	EMailReaderIface *iface;
 +
 +	g_return_val_if_fail (E_IS_MAIL_READER (reader), NULL);
 +
 +	iface = E_MAIL_READER_GET_IFACE (reader);
 +	g_return_val_if_fail (iface->get_message_list != NULL, NULL);
 +
 +	return iface->get_message_list (reader);
 +}
 +
 +EShellBackend *
 +e_mail_reader_get_shell_backend (EMailReader *reader)
 +{
 +	EMailReaderIface *iface;
 +
 +	g_return_val_if_fail (E_IS_MAIL_READER (reader), NULL);
 +
 +	iface = E_MAIL_READER_GET_IFACE (reader);
 +	g_return_val_if_fail (iface->get_shell_backend != NULL, NULL);
 +
 +	return iface->get_shell_backend (reader);
 +}
 +
 +GtkWindow *
 +e_mail_reader_get_window (EMailReader *reader)
 +{
 +	EMailReaderIface *iface;
 +
 +	g_return_val_if_fail (E_IS_MAIL_READER (reader), NULL);
 +
 +	iface = E_MAIL_READER_GET_IFACE (reader);
 +	g_return_val_if_fail (iface->get_window != NULL, NULL);
 +
 +	return iface->get_window (reader);
 +}
 +
 +void
 +e_mail_reader_set_folder (EMailReader *reader,
 +                          CamelFolder *folder,
 +                          const gchar *folder_uri)
 +{
 +	EMailReaderIface *iface;
 +
 +	g_return_if_fail (E_IS_MAIL_READER (reader));
 +
 +	iface = E_MAIL_READER_GET_IFACE (reader);
 +	g_return_if_fail (iface->set_folder != NULL);
 +
 +	iface->set_folder (reader, folder, folder_uri);
 +}
 +
 +/* Helper for e_mail_reader_set_folder_uri() */
 +static void
 +mail_reader_got_folder_cb (gchar *folder_uri,
 +                           CamelFolder *folder,
 +                           gpointer user_data)
 +{
 +	EMailReader *reader = user_data;
 +
 +	e_mail_reader_set_folder (reader, folder, folder_uri);
 +}
 +
 +void
 +e_mail_reader_set_folder_uri (EMailReader *reader,
 +                              const gchar *folder_uri)
 +{
 +	g_return_if_fail (E_IS_MAIL_READER (reader));
 +	g_return_if_fail (folder_uri != NULL);
 +
 +	/* Fetch the CamelFolder asynchronously. */
 +	mail_get_folder (
 +		folder_uri, 0, mail_reader_got_folder_cb,
 +		reader, mail_msg_fast_ordered_push);
 +}
 +
 +void
 +e_mail_reader_set_message (EMailReader *reader,
 +                           const gchar *uid,
 +                           gboolean mark_read)
 +{
 +	EMailReaderIface *iface;
 +
 +	g_return_if_fail (E_IS_MAIL_READER (reader));
 +
 +	iface = E_MAIL_READER_GET_IFACE (reader);
 +	g_return_if_fail (iface->set_message != NULL);
 +
 +	iface->set_message (reader, uid, mark_read);
 +}
 +
 +void
 +e_mail_reader_create_charset_menu (EMailReader *reader,
 +                                   GtkUIManager *ui_manager,
 +                                   guint merge_id)
 +{
 +	GtkAction *action;
 +	const gchar *action_name;
 +	const gchar *path;
 +	GSList *list;
 +
 +	g_return_if_fail (E_IS_MAIL_READER (reader));
 +	g_return_if_fail (GTK_IS_UI_MANAGER (ui_manager));
 +
 +	action_name = "mail-charset-default";
 +	action = e_mail_reader_get_action (reader, action_name);
 +	g_return_if_fail (action != NULL);
 +
 +	list = gtk_radio_action_get_group (GTK_RADIO_ACTION (action));
 +	list = g_slist_copy (list);
 +	list = g_slist_remove (list, action);
 +	list = g_slist_sort (list, (GCompareFunc) e_action_compare_by_label);
 +
 +	path = "/main-menu/view-menu/mail-message-view-actions/mail-encoding-menu";
 +
 +	while (list != NULL) {
 +		action = list->data;
 +
 +		gtk_ui_manager_add_ui (
 +			ui_manager, merge_id, path,
 +			gtk_action_get_name (action),
 +			gtk_action_get_name (action),
 +			GTK_UI_MANAGER_AUTO, FALSE);
 +
 +		list = g_slist_delete_link (list, list);
 +	}
 +
 +	gtk_ui_manager_ensure_update (ui_manager);
 +}
 +
 +void
 +e_mail_reader_show_search_bar (EMailReader *reader)
 +{
 +	g_return_if_fail (E_IS_MAIL_READER (reader));
 +
 +	g_signal_emit (reader, signals[SHOW_SEARCH_BAR], 0);
 +}
diff --cc mail/e-mail-reader.h
index 13a9ba8,0000000..c55ba92
mode 100644,000000..100644
--- a/mail/e-mail-reader.h
+++ b/mail/e-mail-reader.h
@@@ -1,134 -1,0 +1,134 @@@
 +/*
 + * e-mail-reader.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_MAIL_READER_H
 +#define E_MAIL_READER_H
 +
 +#include <gtk/gtk.h>
 +#include <camel/camel-folder.h>
 +#include <mail/em-format-html-display.h>
 +#include <mail/message-list.h>
 +#include <shell/e-shell-backend.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_MAIL_READER \
 +	(e_mail_reader_get_type ())
 +#define E_MAIL_READER(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_MAIL_READER, EMailReader))
 +#define E_MAIL_READER_IFACE(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_MAIL_READER, EMailReaderIface))
 +#define E_IS_MAIL_READER(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_MAIL_READER))
 +#define E_IS_MAIL_READER_IFACE(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), E_TYPE_MAIL_READER))
 +#define E_MAIL_READER_GET_IFACE(obj) \
 +	(G_TYPE_INSTANCE_GET_INTERFACE \
 +	((obj), E_TYPE_MAIL_READER, EMailReaderIface))
 +
 +/* Basename of the UI definition file. */
 +#define E_MAIL_READER_UI_DEFINITION	"evolution-mail-reader.ui"
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _EMailReader EMailReader;
 +typedef struct _EMailReaderIface EMailReaderIface;
 +
 +enum {
 +	E_MAIL_READER_SELECTION_SINGLE			= 1 << 0,
 +	E_MAIL_READER_SELECTION_MULTIPLE		= 1 << 1,
 +	E_MAIL_READER_SELECTION_CAN_ADD_SENDER		= 1 << 2,
 +	E_MAIL_READER_SELECTION_CAN_EDIT		= 1 << 3,
 +	E_MAIL_READER_SELECTION_FLAG_CLEAR		= 1 << 4,
 +	E_MAIL_READER_SELECTION_FLAG_COMPLETED		= 1 << 5,
 +	E_MAIL_READER_SELECTION_FLAG_FOLLOWUP		= 1 << 6,
 +	E_MAIL_READER_SELECTION_HAS_DELETED		= 1 << 7,
 +	E_MAIL_READER_SELECTION_HAS_IMPORTANT		= 1 << 8,
 +	E_MAIL_READER_SELECTION_HAS_JUNK		= 1 << 9,
 +	E_MAIL_READER_SELECTION_HAS_NOT_JUNK		= 1 << 10,
 +	E_MAIL_READER_SELECTION_HAS_READ		= 1 << 11,
 +	E_MAIL_READER_SELECTION_HAS_UNDELETED		= 1 << 12,
 +	E_MAIL_READER_SELECTION_HAS_UNIMPORTANT		= 1 << 13,
 +	E_MAIL_READER_SELECTION_HAS_UNREAD		= 1 << 14,
 +	E_MAIL_READER_SELECTION_HAS_URI_CALLTO		= 1 << 15,
 +	E_MAIL_READER_SELECTION_HAS_URI_HTTP		= 1 << 16,
 +	E_MAIL_READER_SELECTION_HAS_URI_MAILTO		= 1 << 17,
 +	E_MAIL_READER_SELECTION_IS_MAILING_LIST		= 1 << 18
 +};
 +
 +struct _EMailReaderIface {
 +	GTypeInterface parent_iface;
 +
 +	GtkActionGroup *
 +			(*get_action_group)	(EMailReader *reader);
 +	gboolean	(*get_hide_deleted)	(EMailReader *reader);
 +	EMFormatHTMLDisplay *
 +			(*get_html_display)	(EMailReader *reader);
 +	MessageList *	(*get_message_list)	(EMailReader *reader);
 +	EShellBackend *	(*get_shell_backend)	(EMailReader *reader);
 +	GtkWindow *	(*get_window)		(EMailReader *reader);
 +
 +	void		(*set_folder)		(EMailReader *reader,
 +						 CamelFolder *folder,
 +						 const gchar *folder_uri);
 +	void		(*set_message)		(EMailReader *reader,
 +						 const gchar *uid,
 +						 gboolean mark_read);
 +
 +	/* Signals */
 +	void		(*show_search_bar)	(EMailReader *reader);
 +};
 +
 +GType		e_mail_reader_get_type		(void);
 +void		e_mail_reader_init		(EMailReader *reader);
 +void		e_mail_reader_changed		(EMailReader *reader);
 +guint32		e_mail_reader_check_state	(EMailReader *reader);
 +void		e_mail_reader_update_actions	(EMailReader *reader);
 +GtkAction *	e_mail_reader_get_action	(EMailReader *reader,
 +						 const gchar *action_name);
 +GtkActionGroup *
 +		e_mail_reader_get_action_group	(EMailReader *reader);
 +gboolean	e_mail_reader_get_hide_deleted	(EMailReader *reader);
 +EMFormatHTMLDisplay *
 +		e_mail_reader_get_html_display	(EMailReader *reader);
 +MessageList *	e_mail_reader_get_message_list	(EMailReader *reader);
 +EShellBackend *	e_mail_reader_get_shell_backend	(EMailReader *reader);
 +GtkWindow *	e_mail_reader_get_window	(EMailReader *reader);
 +void		e_mail_reader_set_folder	(EMailReader *reader,
 +						 CamelFolder *folder,
 +						 const gchar *folder_uri);
 +void		e_mail_reader_set_folder_uri	(EMailReader *reader,
 +						 const gchar *folder_uri);
 +void		e_mail_reader_set_message	(EMailReader *reader,
 +						 const gchar *uid,
 +						 gboolean mark_read);
 +void		e_mail_reader_create_charset_menu
 +						(EMailReader *reader,
 +						 GtkUIManager *ui_manager,
 +						 guint merge_id);
 +void		e_mail_reader_show_search_bar	(EMailReader *reader);
 +
 +G_END_DECLS
 +
 +#endif /* E_MAIL_READER_H */
diff --cc mail/e-mail-shell-backend.c
index 3fa066a,0000000..10a99e7
mode 100644,000000..100644
--- a/mail/e-mail-shell-backend.c
+++ b/mail/e-mail-shell-backend.c
@@@ -1,1294 -1,0 +1,1294 @@@
 +/*
 + * e-mail-shell-backend.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-mail-shell-backend.h"
 +
 +#include <glib/gi18n.h>
 +#include <camel/camel-disco-store.h>
 +#include <camel/camel-offline-store.h>
 +#include <camel/camel-session.h>
 +#include <camel/camel-url.h>
 +
 +#include "e-util/e-account-utils.h"
 +#include "e-util/e-binding.h"
 +#include "e-util/e-import.h"
 +#include "e-util/e-util.h"
 +#include "shell/e-shell.h"
 +#include "shell/e-shell-window.h"
 +#include "composer/e-msg-composer.h"
 +#include "widgets/misc/e-preferences-window.h"
 +
 +#include "e-mail-shell-migrate.h"
 +#include "e-mail-shell-settings.h"
 +#include "e-mail-shell-sidebar.h"
 +#include "e-mail-shell-view.h"
 +
 +#include "e-attachment-handler-mail.h"
 +#include "e-mail-browser.h"
 +#include "e-mail-reader.h"
 +#include "em-account-prefs.h"
 +#include "em-composer-prefs.h"
 +#include "em-composer-utils.h"
 +#include "em-config.h"
 +#include "em-event.h"
 +#include "em-folder-tree-model.h"
 +#include "em-folder-utils.h"
 +#include "em-format-hook.h"
 +#include "em-format-html-display.h"
 +#include "em-junk-hook.h"
 +#include "em-mailer-prefs.h"
 +#include "em-network-prefs.h"
 +#include "em-utils.h"
 +#include "mail-config.h"
 +#include "mail-folder-cache.h"
 +#include "mail-mt.h"
 +#include "mail-ops.h"
 +#include "mail-send-recv.h"
 +#include "mail-session.h"
 +#include "mail-vfolder.h"
 +#include "importers/mail-importer.h"
 +
 +#define E_MAIL_SHELL_BACKEND_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_MAIL_SHELL_BACKEND, EMailShellBackendPrivate))
 +
 +#define BACKEND_NAME "mail"
 +
 +typedef struct _StoreInfo StoreInfo;
 +
 +/* XXX Temporary */
 +CamelStore *vfolder_store;
 +
 +struct _StoreInfo {
 +	CamelStore *store;
 +	gint ref_count;
 +	gchar *name;
 +
 +	/* Keep a reference to these so they remain around for the session. */
 +	CamelFolder *vtrash;
 +	CamelFolder *vjunk;
 +
 +	/* Initialization callback. */
 +	void (*done) (CamelStore *store,
 +	              CamelFolderInfo *info,
 +	              gpointer user_data);
 +	gpointer done_user_data;
 +
 +	guint removed : 1;
 +};
 +
 +struct _EMailShellBackendPrivate {
 +	GHashTable *store_hash;
 +	MailAsyncEvent *async_event;
 +	EMFolderTreeModel *folder_tree_model;
 +	CamelStore *local_store;
 +
 +	gint mail_sync_in_progress;
 +	guint mail_sync_timeout_source_id;
 +};
 +
 +/* XXX Make this a preprocessor definition. */
 +const gchar *x_mailer = "Evolution " VERSION SUB_VERSION " " VERSION_COMMENT;
 +
 +static gpointer parent_class;
 +static GType mail_shell_backend_type;
 +
 +/* The array elements correspond to EMailFolderType. */
 +static struct {
- 	gchar *name;
++	const gchar *name;
 +	gchar *uri;
 +	CamelFolder *folder;
 +} default_local_folders[] = {
 +	{ N_("Inbox") },
 +	{ N_("Drafts") },
 +	{ N_("Outbox") },
 +	{ N_("Sent") },
 +	{ N_("Templates") },
 +	{ "Inbox" }  /* "always local" inbox */
 +};
 +
 +/* XXX So many things need the shell backend that it's
 + *     just easier for now to make it globally available.
 + *     We should fix this, though. */
 +EMailShellBackend *global_mail_shell_backend = NULL;
 +
 +extern gint camel_application_is_exiting;
 +
 +static StoreInfo *
 +store_info_new (CamelStore *store,
 +                const gchar *name)
 +{
 +	CamelService *service;
 +	StoreInfo *si;
 +
 +	g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
 +
 +	service = CAMEL_SERVICE (store);
 +
 +	si = g_slice_new0 (StoreInfo);
 +	si->ref_count = 1;
 +
 +	if (name == NULL)
 +		si->name = camel_service_get_name (service, TRUE);
 +	else
 +		si->name = g_strdup (name);
 +
 +	si->store = store;
 +	camel_object_ref (store);
 +
 +	/* If these are vfolders then they need to be opened now,
 +	 * otherwise they won't keep track of all folders. */
 +	if (store->flags & CAMEL_STORE_VTRASH)
 +		si->vtrash = camel_store_get_trash (store, NULL);
 +	if (store->flags & CAMEL_STORE_VJUNK)
 +		si->vjunk = camel_store_get_junk (store, NULL);
 +
 +	return si;
 +}
 +
 +static StoreInfo *
 +store_info_ref (StoreInfo *si)
 +{
 +	g_return_val_if_fail (si != NULL, si);
 +	g_return_val_if_fail (si->ref_count > 0, si);
 +
 +	g_atomic_int_add (&si->ref_count, 1);
 +
 +	return si;
 +}
 +
 +static void
 +store_info_unref (StoreInfo *si)
 +{
 +	g_return_if_fail (si != NULL);
 +	g_return_if_fail (si->ref_count > 0);
 +
 +	if (g_atomic_int_exchange_and_add (&si->ref_count, -1) > 1)
 +		return;
 +
 +	if (si->vtrash != NULL)
 +		camel_object_unref (si->vtrash);
 +	if (si->vjunk != NULL)
 +		camel_object_unref (si->vjunk);
 +	camel_object_unref (si->store);
 +	g_free (si->name);
 +
 +	g_slice_free (StoreInfo, si);
 +}
 +
 +static void
 +store_hash_free (StoreInfo *si)
 +{
 +	si->removed = 1;
 +	store_info_unref (si);
 +}
 +
 +static gboolean
 +mail_shell_backend_add_store_done (CamelStore *store,
 +                                   CamelFolderInfo *info,
 +                                   gpointer user_data)
 +{
 +	StoreInfo *si = user_data;
 +
 +	if (si->done != NULL)
 +		si->done (store, info, si);
 +
 +	if (!si->removed) {
 +		/* Let the counters know about the already-opened
 +		 * junk and trash folders. */
 +		if (si->vtrash != NULL)
 +			mail_note_folder (si->vtrash);
 +		if (si->vjunk != NULL)
 +			mail_note_folder (si->vjunk);
 +	}
 +
 +	store_info_unref (si);
 +
 +	return TRUE;
 +}
 +
 +static void
 +mail_shell_backend_add_store (EMailShellBackend *mail_shell_backend,
 +                              CamelStore *store,
 +                              const gchar *name,
 +                              void (*done) (CamelStore *store,
 +                                            CamelFolderInfo *info,
 +                                            gpointer user_data))
 +{
 +	EMFolderTreeModel *folder_tree_model;
 +	GHashTable *store_hash;
 +	StoreInfo *si;
 +
 +	store_hash = mail_shell_backend->priv->store_hash;
 +	folder_tree_model = mail_shell_backend->priv->folder_tree_model;
 +
 +	si = store_info_new (store, name);
 +	si->done = done;
 +	g_hash_table_insert (store_hash, store, si);
 +
 +	em_folder_tree_model_add_store (folder_tree_model, store, si->name);
 +
 +	mail_note_store (
 +		mail_shell_backend, store, NULL,
 +		mail_shell_backend_add_store_done, store_info_ref (si));
 +}
 +
 +static void
 +mail_shell_backend_add_local_store_done (CamelStore *store,
 +                                         CamelFolderInfo *info,
 +                                         gpointer unused)
 +{
 +	gint ii;
 +
 +	for (ii = 0; ii < G_N_ELEMENTS (default_local_folders); ii++) {
 +		if (default_local_folders[ii].folder != NULL)
 +			mail_note_folder (default_local_folders[ii].folder);
 +	}
 +}
 +
 +static void
 +mail_shell_backend_add_local_store (EMailShellBackend *mail_shell_backend,
 +                                    CamelStore *local_store,
 +                                    const gchar *name)
 +{
 +	mail_shell_backend_add_store (
 +		mail_shell_backend, local_store, name,
 +		mail_shell_backend_add_local_store_done);
 +}
 +
 +static void
 +mail_shell_backend_init_hooks (void)
 +{
 +	e_plugin_hook_register_type (em_config_hook_get_type ());
 +	e_plugin_hook_register_type (em_event_hook_get_type ());
 +	e_plugin_hook_register_type (em_junk_hook_get_type ());
 +
 +	/* EMFormat classes must be registered before EMFormatHook. */
 +	em_format_hook_register_type (em_format_get_type ());
 +	em_format_hook_register_type (em_format_html_get_type ());
 +	em_format_hook_register_type (em_format_html_display_get_type ());
 +	e_plugin_hook_register_type (em_format_hook_get_type ());
 +
 +	em_junk_hook_register_type (emj_get_type ());
 +}
 +
 +static void
 +mail_shell_backend_init_importers (void)
 +{
 +	EImportClass *import_class;
 +	EImportImporter *importer;
 +
 +	import_class = g_type_class_ref (e_import_get_type ());
 +
 +	importer = mbox_importer_peek ();
 +	e_import_class_add_importer (import_class, importer, NULL, NULL);
 +
 +	importer = elm_importer_peek ();
 +	e_import_class_add_importer (import_class, importer, NULL, NULL);
 +
 +	importer = pine_importer_peek ();
 +	e_import_class_add_importer (import_class, importer, NULL, NULL);
 +}
 +
 +static void
 +mail_shell_backend_init_local_store (EShellBackend *shell_backend)
 +{
 +	EMailShellBackendPrivate *priv;
 +	CamelException ex;
 +	CamelService *service;
 +	CamelURL *url;
 +	MailAsyncEvent *async_event;
 +	const gchar *data_dir;
 +	gchar *temp;
 +	gint ii;
 +
 +	priv = E_MAIL_SHELL_BACKEND_GET_PRIVATE (shell_backend);
 +
 +	camel_exception_init (&ex);
 +
 +	async_event = priv->async_event;
 +	data_dir = e_shell_backend_get_data_dir (shell_backend);
 +
 +	url = camel_url_new ("mbox:", NULL);
 +	temp = g_build_filename (data_dir, "local", NULL);
 +	camel_url_set_path (url, temp);
 +	g_free (temp);
 +
 +	temp = camel_url_to_string (url, 0);
 +	service = camel_session_get_service (
 +		session, temp, CAMEL_PROVIDER_STORE, &ex);
 +	g_free (temp);
 +
 +	if (service == NULL)
 +		goto fail;
 +
 +	for (ii = 0; ii < G_N_ELEMENTS (default_local_folders); ii++) {
 +		/* FIXME Should this URI be account relative? */
 +		camel_url_set_fragment (url, default_local_folders[ii].name);
 +		default_local_folders[ii].uri = camel_url_to_string (url, 0);
 +		default_local_folders[ii].folder = camel_store_get_folder (
 +			CAMEL_STORE (service), default_local_folders[ii].name,
 +			CAMEL_STORE_FOLDER_CREATE, &ex);
 +		camel_exception_clear (&ex);
 +	}
 +
 +	camel_url_free (url);
 +
 +	camel_object_ref (service);
 +	g_object_ref (shell_backend);
 +
 +	mail_async_event_emit (
 +		async_event, MAIL_ASYNC_GUI,
 +		(MailAsyncFunc) mail_shell_backend_add_local_store,
 +		shell_backend, service, _("On This Computer"));
 +
 +	priv->local_store = CAMEL_STORE (service);
 +
 +	return;
 +
 +fail:
 +	g_warning ("Could not initialize local store/folder: %s", ex.desc);
 +
 +	camel_exception_clear (&ex);
 +	camel_url_free (url);
 +}
 +
 +static void
 +mail_shell_backend_load_accounts (EShellBackend *shell_backend)
 +{
 +	EAccountList *account_list;
 +	EIterator *iter;
 +
 +	account_list = e_get_account_list ();
 +
 +	for (iter = e_list_get_iterator ((EList *) account_list);
 +		e_iterator_is_valid (iter); e_iterator_next (iter)) {
 +
 +		EAccountService *service;
 +		EAccount *account;
 +		const gchar *name;
 +		const gchar *url;
 +
 +		account = (EAccount *) e_iterator_get (iter);
 +		service = account->source;
 +		name = account->name;
 +		url = service->url;
 +
 +		if (!account->enabled)
 +			continue;
 +
 +		if (url == NULL || *url == '\0')
 +			continue;
 +
 +		/* HACK: mbox URL's are handled by the local store setup
 +		 *       above.  Any that come through as account sources
 +		 *       are really movemail sources! */
 +		if (g_str_has_prefix (url, "mbox:"))
 +			continue;
 +
 +		e_mail_shell_backend_load_store_by_uri (
 +			E_MAIL_SHELL_BACKEND (shell_backend), url, name);
 +	}
 +
 +	g_object_unref (iter);
 +}
 +
 +static void
 +mail_shell_backend_mail_icon_cb (EShellWindow *shell_window,
 +                                const gchar *icon_name)
 +{
 +	GtkAction *action;
 +
 +	action = e_shell_window_get_shell_view_action (
 +		shell_window, BACKEND_NAME);
 +	g_object_set (action, "icon-name", icon_name, NULL);
 +}
 +
 +static void
 +action_mail_folder_new_cb (GtkAction *action,
 +                           EShellWindow *shell_window)
 +{
 +	EMFolderTree *folder_tree = NULL;
 +	EMailShellSidebar *mail_shell_sidebar;
 +	EShellSidebar *shell_sidebar;
 +	EShellView *shell_view;
 +	const gchar *view_name;
 +
 +	/* Take care not to unnecessarily load the mail shell view. */
 +	view_name = e_shell_window_get_active_view (shell_window);
 +	if (g_strcmp0 (view_name, BACKEND_NAME) != 0)
 +		goto exit;
 +
 +	shell_view = e_shell_window_get_shell_view (shell_window, view_name);
 +	shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
 +
 +	mail_shell_sidebar = E_MAIL_SHELL_SIDEBAR (shell_sidebar);
 +	folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
 +
 +exit:
 +	em_folder_utils_create_folder (
 +		NULL, folder_tree, GTK_WINDOW (shell_window));
 +}
 +
 +static void
 +action_mail_message_new_cb (GtkAction *action,
 +                            EShellWindow *shell_window)
 +{
 +	GtkWindow *window = GTK_WINDOW (shell_window);
 +	EMailShellSidebar *mail_shell_sidebar;
 +	EShellSidebar *shell_sidebar;
 +	EShellView *shell_view;
 +	EMFolderTree *folder_tree;
 +	const gchar *view_name;
 +	gchar *uri = NULL;
 +
 +	if (!em_utils_check_user_can_send_mail (window))
 +		return;
 +
 +	/* Take care not to unnecessarily load the mail shell view. */
 +	view_name = e_shell_window_get_active_view (shell_window);
 +	if (g_strcmp0 (view_name, BACKEND_NAME) != 0)
 +		goto exit;
 +
 +	shell_view = e_shell_window_get_shell_view (shell_window, view_name);
 +	shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
 +
 +	mail_shell_sidebar = E_MAIL_SHELL_SIDEBAR (shell_sidebar);
 +	folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
 +	uri = em_folder_tree_get_selected_uri (folder_tree);
 +
 +exit:
 +	em_utils_compose_new_message (uri);
 +
 +	g_free (uri);
 +}
 +
 +static GtkActionEntry item_entries[] = {
 +
 +	{ "mail-message-new",
 +	  "mail-message-new",
 +	  NC_("New", "_Mail Message"),
 +	  "<Shift><Control>m",
 +	  N_("Compose a new mail message"),
 +	  G_CALLBACK (action_mail_message_new_cb) }
 +};
 +
 +static GtkActionEntry source_entries[] = {
 +
 +	{ "mail-folder-new",
 +	  "folder-new",
 +	  NC_("New", "Mail _Folder"),
 +	  NULL,
 +	  N_("Create a new mail folder"),
 +	  G_CALLBACK (action_mail_folder_new_cb) }
 +};
 +
 +static void
 +mail_shell_backend_init_preferences (EShell *shell)
 +{
 +	EAccountList *account_list;
 +	GtkWidget *preferences_window;
 +
 +	account_list = e_get_account_list ();
 +	preferences_window = e_shell_get_preferences_window (shell);
 +
 +	e_preferences_window_add_page (
 +		E_PREFERENCES_WINDOW (preferences_window),
 +		"mail-accounts",
 +		"preferences-mail-accounts",
 +		_("Mail Accounts"),
 +		em_account_prefs_new (account_list),
 +		100);
 +
 +	e_preferences_window_add_page (
 +		E_PREFERENCES_WINDOW (preferences_window),
 +		"mail",
 +		"preferences-mail",
 +		_("Mail Preferences"),
 +		em_mailer_prefs_new (shell),
 +		300);
 +
 +	e_preferences_window_add_page (
 +		E_PREFERENCES_WINDOW (preferences_window),
 +		"composer",
 +		"preferences-composer",
 +		_("Composer Preferences"),
 +		em_composer_prefs_new (shell),
 +		400);
 +
 +	e_preferences_window_add_page (
 +		E_PREFERENCES_WINDOW (preferences_window),
 +		"system-network-proxy",
 +		"preferences-system-network-proxy",
 +		_("Network Preferences"),
 +		em_network_prefs_new (),
 +		500);
 +}
 +
 +static void
 +mail_shell_backend_sync_store_done_cb (CamelStore *store,
 +                                       gpointer user_data)
 +{
 +	EMailShellBackend *mail_shell_backend = user_data;
 +
 +	mail_shell_backend->priv->mail_sync_in_progress--;
 +}
 +
 +static void
 +mail_shell_backend_sync_store_cb (CamelStore *store,
 +                                  EMailShellBackend *mail_shell_backend)
 +{
 +	if (!camel_application_is_exiting) {
 +		mail_shell_backend->priv->mail_sync_in_progress++;
 +		mail_sync_store (
 +			store, FALSE,
 +			mail_shell_backend_sync_store_done_cb,
 +			mail_shell_backend);
 +	}
 +}
 +
 +static gboolean
 +mail_shell_backend_mail_sync (EMailShellBackend *mail_shell_backend)
 +{
 +	if (camel_application_is_exiting)
 +		return FALSE;
 +
 +	if (mail_shell_backend->priv->mail_sync_in_progress)
 +		goto exit;
 +
 +	if (session == NULL || !camel_session_is_online (session))
 +		goto exit;
 +
 +	e_mail_shell_backend_stores_foreach (
 +		mail_shell_backend, (GHFunc)
 +		mail_shell_backend_sync_store_cb,
 +		mail_shell_backend);
 +
 +exit:
 +	return !camel_application_is_exiting;
 +}
 +
 +static void
 +mail_shell_backend_notify_online_cb (EShell *shell,
 +                                    GParamSpec *pspec,
 +                                    EShellBackend *shell_backend)
 +{
 +	gboolean online;
 +
 +	online = e_shell_get_online (shell);
 +	camel_session_set_online (session, online);
 +}
 +
 +static void
 +mail_shell_backend_handle_email_uri_cb (gchar *folder_uri,
 +                                        CamelFolder *folder,
 +                                        gpointer user_data)
 +{
 +	EMailShellBackend *mail_shell_backend = user_data;
 +	CamelURL *url = user_data;
 +	const gchar *forward;
 +	const gchar *reply;
 +	const gchar *uid;
 +
 +	if (folder == NULL) {
 +		g_warning ("Could not open folder '%s'", folder_uri);
 +		goto exit;
 +	}
 +
 +	forward = camel_url_get_param (url, "forward");
 +	reply = camel_url_get_param (url, "reply");
 +	uid = camel_url_get_param (url, "uid");
 +
 +	if (reply != NULL) {
 +		gint mode;
 +
 +		if (g_strcmp0 (reply, "all") == 0)
 +			mode = REPLY_MODE_ALL;
 +		else if (g_strcmp0 (reply, "list") == 0)
 +			mode = REPLY_MODE_LIST;
 +		else
 +			mode = REPLY_MODE_SENDER;
 +
 +		em_utils_reply_to_message (folder, uid, NULL, mode, NULL);
 +
 +	} else if (forward != NULL) {
 +		GPtrArray *uids;
 +
 +		uids = g_ptr_array_new ();
 +		g_ptr_array_add (uids, g_strdup (uid));
 +
 +		if (g_strcmp0 (forward, "attached") == 0)
 +			em_utils_forward_attached (folder, uids, folder_uri);
 +		else if (g_strcmp0 (forward, "inline") == 0)
 +			em_utils_forward_inline (folder, uids, folder_uri);
 +		else if (g_strcmp0 (forward, "quoted") == 0)
 +			em_utils_forward_quoted (folder, uids, folder_uri);
 +		else
 +			em_utils_forward_messages (folder, uids, folder_uri);
 +
 +	} else {
 +		GtkWidget *browser;
 +
 +		/* FIXME Should pass in the shell module. */
 +		browser = e_mail_browser_new (mail_shell_backend);
 +		e_mail_reader_set_folder (
 +			E_MAIL_READER (browser), folder, folder_uri);
 +		e_mail_reader_set_message (
 +			E_MAIL_READER (browser), uid, FALSE);
 +		gtk_widget_show (browser);
 +	}
 +
 +exit:
 +	camel_url_free (url);
 +}
 +
 +static gboolean
 +mail_shell_backend_handle_uri_cb (EShell *shell,
 +                                  const gchar *uri,
 +                                  EMailShellBackend *mail_shell_backend)
 +{
 +	gboolean handled = TRUE;
 +
 +	if (g_str_has_prefix (uri, "mailto:";)) {
 +		if (em_utils_check_user_can_send_mail (NULL))
 +			em_utils_compose_new_message_with_mailto (uri, NULL);
 +
 +	} else if (g_str_has_prefix (uri, "email:")) {
 +		CamelURL *url;
 +
 +		url = camel_url_new (uri, NULL);
 +		if (camel_url_get_param (url, "uid") != NULL) {
 +			gchar *curi = em_uri_to_camel (uri);
 +
 +			mail_get_folder (
 +				curi, 0,
 +				mail_shell_backend_handle_email_uri_cb,
 +				mail_shell_backend, mail_msg_unordered_push);
 +			g_free (curi);
 +
 +		} else {
 +			g_warning ("Email URI's must include a uid parameter");
 +			camel_url_free (url);
 +		}
 +	} else
 +		handled = FALSE;
 +
 +	return TRUE;
 +}
 +
 +/* Helper for mail_shell_backend_prepare_for_[off|on]line_cb() */
 +static void
 +mail_shell_store_line_transition_done_cb (CamelStore *store,
 +                                          gpointer user_data)
 +{
 +	EActivity *activity = user_data;
 +
 +	g_object_unref (activity);
 +}
 +
 +/* Helper for mail_shell_backend_prepare_for_offline_cb() */
 +static void
 +mail_shell_store_prepare_for_offline_cb (CamelService *service,
 +                                         gpointer unused,
 +                                         EActivity *activity)
 +{
 +	if (CAMEL_IS_DISCO_STORE (service) || CAMEL_IS_OFFLINE_STORE (service))
 +		mail_store_set_offline (
 +			CAMEL_STORE (service), TRUE,
 +			mail_shell_store_line_transition_done_cb,
 +			g_object_ref (activity));
 +}
 +
 +static void
 +mail_shell_backend_prepare_for_offline_cb (EShell *shell,
 +                                           EActivity *activity,
 +                                           EMailShellBackend *mail_shell_backend)
 +{
 +	GList *watched_windows;
 +	GtkWidget *parent = NULL;
 +	gboolean synchronize = FALSE;
 +
 +	watched_windows = e_shell_get_watched_windows (shell);
 +	if (watched_windows != NULL)
 +		parent = GTK_WIDGET (watched_windows->data);
 +
 +	if (e_shell_get_network_available (shell))
 +		synchronize = em_utils_prompt_user (
 +			GTK_WINDOW (parent),
 +			"/apps/evolution/mail/prompts/quick_offline",
 +			"mail:ask-quick-offline", NULL);
 +
 +	if (!synchronize) {
 +		mail_cancel_all ();
 +		camel_session_set_network_state (session, FALSE);
 +	}
 +
 +	e_mail_shell_backend_stores_foreach (
 +		mail_shell_backend, (GHFunc)
 +		mail_shell_store_prepare_for_offline_cb, activity);
 +}
 +
 +/* Helper for mail_shell_backend_prepare_for_online_cb() */
 +static void
 +mail_shell_store_prepare_for_online_cb (CamelService *service,
 +                                        gpointer unused,
 +                                        EActivity *activity)
 +{
 +	if (CAMEL_IS_DISCO_STORE (service) || CAMEL_IS_OFFLINE_STORE (service))
 +		mail_store_set_offline (
 +			CAMEL_STORE (service), FALSE,
 +			mail_shell_store_line_transition_done_cb,
 +			g_object_ref (activity));
 +}
 +
 +static void
 +mail_shell_backend_prepare_for_online_cb (EShell *shell,
 +                                          EActivity *activity,
 +                                          EMailShellBackend *mail_shell_backend)
 +{
 +	camel_session_set_online (session, TRUE);
 +
 +	e_mail_shell_backend_stores_foreach (
 +		mail_shell_backend, (GHFunc)
 +		mail_shell_store_prepare_for_online_cb, activity);
 +}
 +
 +static void
 +mail_shell_backend_send_receive_cb (EShell *shell,
 +                                   GtkWindow *parent,
 +                                   EShellBackend *shell_backend)
 +{
 +	em_utils_clear_get_password_canceled_accounts_flag ();
 +	mail_send_receive (parent);
 +}
 +
 +static void
 +mail_shell_backend_window_weak_notify_cb (EShell *shell,
 +                                         GObject *where_the_object_was)
 +{
 +	g_signal_handlers_disconnect_by_func (
 +		shell, mail_shell_backend_mail_icon_cb,
 +		where_the_object_was);
 +}
 +
 +static void
 +mail_shell_backend_window_created_cb (EShell *shell,
 +                                     GtkWindow *window,
 +                                     EShellBackend *shell_backend)
 +{
 +	EShellSettings *shell_settings;
 +	static gboolean first_time = TRUE;
 +	const gchar *backend_name;
 +
 +	shell_settings = e_shell_get_shell_settings (shell);
 +
 +	/* This applies to both the composer and signature editor. */
 +	if (GTKHTML_IS_EDITOR (window)) {
 +		GList *spell_languages;
 +
 +		e_binding_new (
 +			G_OBJECT (shell_settings), "composer-inline-spelling",
 +			G_OBJECT (window), "inline-spelling");
 +
 +		e_binding_new (
 +			G_OBJECT (shell_settings), "composer-magic-links",
 +			G_OBJECT (window), "magic-links");
 +
 +		e_binding_new (
 +			G_OBJECT (shell_settings), "composer-magic-smileys",
 +			G_OBJECT (window), "magic-smileys");
 +
 +		spell_languages = e_load_spell_languages ();
 +		gtkhtml_editor_set_spell_languages (
 +			GTKHTML_EDITOR (window), spell_languages);
 +		g_list_free (spell_languages);
 +	}
 +
 +	if (E_IS_MSG_COMPOSER (window)) {
 +		/* Integrate the new composer into the mail module. */
 +		em_configure_new_composer (E_MSG_COMPOSER (window));
 +		return;
 +	}
 +
 +	if (!E_IS_SHELL_WINDOW (window))
 +		return;
 +
 +	backend_name = E_SHELL_BACKEND_GET_CLASS (shell_backend)->name;
 +
 +	e_shell_window_register_new_item_actions (
 +		E_SHELL_WINDOW (window), backend_name,
 +		item_entries, G_N_ELEMENTS (item_entries));
 +
 +	e_shell_window_register_new_source_actions (
 +		E_SHELL_WINDOW (window), backend_name,
 +		source_entries, G_N_ELEMENTS (source_entries));
 +
 +	g_signal_connect_swapped (
 +		shell, "event::mail-icon",
 +		G_CALLBACK (mail_shell_backend_mail_icon_cb), window);
 +
 +	g_object_weak_ref (
 +		G_OBJECT (window), (GWeakNotify)
 +		mail_shell_backend_window_weak_notify_cb, shell);
 +
 +	if (first_time) {
 +		g_signal_connect (
 +			window, "map-event",
 +			G_CALLBACK (e_msg_composer_check_autosave), NULL);
 +		first_time = FALSE;
 +	}
 +}
 +
 +static void
 +mail_shell_backend_dispose (GObject *object)
 +{
 +	EMailShellBackendPrivate *priv;
 +
 +	priv = E_MAIL_SHELL_BACKEND_GET_PRIVATE (object);
 +
 +	g_hash_table_remove_all (priv->store_hash);
 +
 +	if (priv->folder_tree_model != NULL) {
 +		g_object_unref (priv->folder_tree_model);
 +		priv->folder_tree_model = NULL;
 +	}
 +
 +	if (priv->local_store != NULL) {
 +		camel_object_unref (priv->local_store);
 +		priv->local_store = NULL;
 +	}
 +
 +	/* Chain up to parent's dispose() method. */
 +	G_OBJECT_CLASS (parent_class)->dispose (object);
 +}
 +
 +static void
 +mail_shell_backend_finalize (GObject *object)
 +{
 +	EMailShellBackendPrivate *priv;
 +
 +	priv = E_MAIL_SHELL_BACKEND_GET_PRIVATE (object);
 +
 +	g_hash_table_destroy (priv->store_hash);
 +	mail_async_event_destroy (priv->async_event);
 +
 +	/* Chain up to parent's finalize() method. */
 +	G_OBJECT_CLASS (parent_class)->finalize (object);
 +}
 +
 +static void
 +mail_shell_backend_constructed (GObject *object)
 +{
 +	EMailShellBackendPrivate *priv;
 +	EShell *shell;
 +	EShellBackend *shell_backend;
 +
 +	priv = E_MAIL_SHELL_BACKEND_GET_PRIVATE (object);
 +
 +	shell_backend = E_SHELL_BACKEND (object);
 +	shell = e_shell_backend_get_shell (shell_backend);
 +
 +	/* This also initializes Camel, so it needs to happen early. */
 +	mail_session_init (E_MAIL_SHELL_BACKEND (shell_backend));
 +
 +	mail_shell_backend_init_hooks ();
 +	mail_shell_backend_init_importers ();
 +
 +	e_attachment_handler_mail_get_type ();
 +
 +	/* XXX This never gets unreffed. */
 +	global_mail_shell_backend = g_object_ref (shell_backend);
 +
 +	priv->store_hash = g_hash_table_new_full (
 +		g_direct_hash, g_direct_equal,
 +		(GDestroyNotify) NULL,
 +		(GDestroyNotify) store_hash_free);
 +
 +	priv->async_event = mail_async_event_new ();
 +
 +	priv->folder_tree_model = em_folder_tree_model_new (
 +		E_MAIL_SHELL_BACKEND (shell_backend));
 +
 +	g_signal_connect (
 +		shell, "notify::online",
 +		G_CALLBACK (mail_shell_backend_notify_online_cb),
 +		shell_backend);
 +
 +	g_signal_connect (
 +		shell, "handle-uri",
 +		G_CALLBACK (mail_shell_backend_handle_uri_cb),
 +		shell_backend);
 +
 +	g_signal_connect (
 +		shell, "prepare-for-offline",
 +		G_CALLBACK (mail_shell_backend_prepare_for_offline_cb),
 +		shell_backend);
 +
 +	g_signal_connect (
 +		shell, "prepare-for-online",
 +		G_CALLBACK (mail_shell_backend_prepare_for_online_cb),
 +		shell_backend);
 +
 +	g_signal_connect (
 +		shell, "send-receive",
 +		G_CALLBACK (mail_shell_backend_send_receive_cb),
 +		shell_backend);
 +
 +	g_signal_connect (
 +		shell, "window-created",
 +		G_CALLBACK (mail_shell_backend_window_created_cb),
 +		shell_backend);
 +
 +	mail_config_init ();
 +	mail_msg_init ();
 +
 +	mail_shell_backend_init_local_store (shell_backend);
 +	mail_shell_backend_load_accounts (shell_backend);
 +
 +	/* Initialize settings before initializing preferences,
 +	 * since the preferences bind to the shell settings. */
 +	e_mail_shell_settings_init (shell);
 +	mail_shell_backend_init_preferences (shell);
 +}
 +
 +static void
 +mail_shell_backend_start (EShellBackend *shell_backend)
 +{
 +	EMailShellBackendPrivate *priv;
 +	EShell *shell;
 +	EShellSettings *shell_settings;
 +	gboolean enable_search_folders;
 +
 +	priv = E_MAIL_SHELL_BACKEND_GET_PRIVATE (shell_backend);
 +
 +	shell = e_shell_backend_get_shell (shell_backend);
 +	shell_settings = e_shell_get_shell_settings (shell);
 +
 +	/* XXX Do we really still need this flag? */
 +	mail_session_set_interactive (TRUE);
 +
 +	enable_search_folders = e_shell_settings_get_boolean (
 +		shell_settings, "mail-enable-search-folders");
 +	if (enable_search_folders)
 +		vfolder_load_storage ();
 +
 +	mail_autoreceive_init (shell_backend, session);
 +
 +	if (g_getenv ("CAMEL_FLUSH_CHANGES") != NULL)
 +		priv->mail_sync_timeout_source_id = g_timeout_add_seconds (
 +			mail_config_get_sync_timeout (),
 +			(GSourceFunc) mail_shell_backend_mail_sync,
 +			shell_backend);
 +}
 +
 +static void
 +mail_shell_backend_class_init (EMailShellBackendClass *class)
 +{
 +	GObjectClass *object_class;
 +	EShellBackendClass *shell_backend_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (EMailShellBackendPrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->dispose = mail_shell_backend_dispose;
 +	object_class->finalize = mail_shell_backend_finalize;
 +	object_class->constructed = mail_shell_backend_constructed;
 +
 +	shell_backend_class = E_SHELL_BACKEND_CLASS (class);
 +	shell_backend_class->shell_view_type = E_TYPE_MAIL_SHELL_VIEW;
 +	shell_backend_class->name = BACKEND_NAME;
 +	shell_backend_class->aliases = "";
 +	shell_backend_class->schemes = "mailto:email";;
 +	shell_backend_class->sort_order = 200;
 +	shell_backend_class->start = mail_shell_backend_start;
 +	shell_backend_class->is_busy = NULL;
 +	shell_backend_class->shutdown = NULL;
 +	shell_backend_class->migrate = e_mail_shell_migrate;
 +}
 +
 +static void
 +mail_shell_backend_init (EMailShellBackend *mail_shell_backend)
 +{
 +	mail_shell_backend->priv =
 +		E_MAIL_SHELL_BACKEND_GET_PRIVATE (mail_shell_backend);
 +}
 +
 +GType
 +e_mail_shell_backend_get_type (void)
 +{
 +	return mail_shell_backend_type;
 +}
 +
 +void
 +e_mail_shell_backend_register_type (GTypeModule *type_module)
 +{
 +	const GTypeInfo type_info = {
 +		sizeof (EMailShellBackendClass),
 +		(GBaseInitFunc) NULL,
 +		(GBaseFinalizeFunc) NULL,
 +		(GClassInitFunc) mail_shell_backend_class_init,
 +		(GClassFinalizeFunc) NULL,
 +		NULL,  /* class_data */
 +		sizeof (EMailShellBackend),
 +		0,     /* n_preallocs */
 +		(GInstanceInitFunc) mail_shell_backend_init,
 +		NULL   /* value_table */
 +	};
 +
 +	mail_shell_backend_type = g_type_module_register_type (
 +		type_module, E_TYPE_SHELL_BACKEND,
 +		"EMailShellBackend", &type_info, 0);
 +}
 +
 +/******************************** Public API *********************************/
 +
 +CamelFolder *
 +e_mail_shell_backend_get_folder (EMailShellBackend *mail_shell_backend,
 +                                 EMailFolderType folder_type)
 +{
 +	g_return_val_if_fail (
 +		E_IS_MAIL_SHELL_BACKEND (mail_shell_backend), NULL);
 +
 +	return default_local_folders[folder_type].folder;
 +}
 +
 +const gchar *
 +e_mail_shell_backend_get_folder_uri (EMailShellBackend *mail_shell_backend,
 +                                     EMailFolderType folder_type)
 +{
 +	g_return_val_if_fail (
 +		E_IS_MAIL_SHELL_BACKEND (mail_shell_backend), NULL);
 +
 +	return default_local_folders[folder_type].uri;
 +}
 +
 +EMFolderTreeModel *
 +e_mail_shell_backend_get_folder_tree_model (EMailShellBackend *mail_shell_backend)
 +{
 +	g_return_val_if_fail (
 +		E_IS_MAIL_SHELL_BACKEND (mail_shell_backend), NULL);
 +
 +	return mail_shell_backend->priv->folder_tree_model;
 +}
 +
 +void
 +e_mail_shell_backend_add_store (EMailShellBackend *mail_shell_backend,
 +                                CamelStore *store,
 +                                const gchar *name)
 +{
 +	g_return_if_fail (E_IS_MAIL_SHELL_BACKEND (mail_shell_backend));
 +	g_return_if_fail (CAMEL_IS_STORE (store));
 +	g_return_if_fail (name != NULL);
 +
 +	mail_shell_backend_add_store (mail_shell_backend, store, name, NULL);
 +}
 +
 +CamelStore *
 +e_mail_shell_backend_get_local_store (EMailShellBackend *mail_shell_backend)
 +{
 +	g_return_val_if_fail (
 +		E_IS_MAIL_SHELL_BACKEND (mail_shell_backend), NULL);
 +
 +	return mail_shell_backend->priv->local_store;
 +}
 +
 +CamelStore *
 +e_mail_shell_backend_load_store_by_uri (EMailShellBackend *mail_shell_backend,
 +                                        const gchar *uri,
 +                                        const gchar *name)
 +{
 +	CamelStore *store;
 +	CamelProvider *provider;
 +	CamelException ex;
 +
 +	g_return_val_if_fail (
 +		E_IS_MAIL_SHELL_BACKEND (mail_shell_backend), NULL);
 +	g_return_val_if_fail (uri != NULL, NULL);
 +	g_return_val_if_fail (name != NULL, NULL);
 +
 +	camel_exception_init (&ex);
 +
 +	/* Load the service, but don't connect.  Check its provider,
 +	 * and if this belongs in the shell's folder list, add it. */
 +
 +	provider = camel_provider_get (uri, &ex);
 +	if (provider == NULL)
 +		goto fail;
 +
 +	if (!(provider->flags & CAMEL_PROVIDER_IS_STORAGE))
 +		return NULL;
 +
 +	store = (CamelStore *) camel_session_get_service (
 +		session, uri, CAMEL_PROVIDER_STORE, &ex);
 +	if (store == NULL)
 +		goto fail;
 +
 +	e_mail_shell_backend_add_store (mail_shell_backend, store, name);
 +
 +	camel_object_unref (store);
 +
 +	return store;
 +
 +fail:
 +	/* FIXME: Show an error dialog. */
 +	g_warning (
 +		"Couldn't get service: %s: %s", uri,
 +		camel_exception_get_description (&ex));
 +	camel_exception_clear (&ex);
 +
 +	return NULL;
 +}
 +
 +/* Helper for e_mail_shell_backend_remove_store() */
 +static void
 +mail_shell_backend_remove_store_cb (CamelStore *store,
 +                                    gpointer event_data,
 +                                    gpointer user_data)
 +{
 +	camel_service_disconnect (CAMEL_SERVICE (store), TRUE, NULL);
 +	camel_object_unref (store);
 +}
 +
 +void
 +e_mail_shell_backend_remove_store (EMailShellBackend *mail_shell_backend,
 +                                   CamelStore *store)
 +{
 +	GHashTable *store_hash;
 +	MailAsyncEvent *async_event;
 +	EMFolderTreeModel *folder_tree_model;
 +
 +	g_return_if_fail (E_IS_MAIL_SHELL_BACKEND (mail_shell_backend));
 +	g_return_if_fail (CAMEL_IS_STORE (store));
 +
 +	store_hash = mail_shell_backend->priv->store_hash;
 +	async_event = mail_shell_backend->priv->async_event;
 +	folder_tree_model = mail_shell_backend->priv->folder_tree_model;
 +
 +	/* Because the store hash holds a reference to each store used
 +	 * as a key in it, none of them will ever be gc'ed, meaning any
 +	 * call to camel_session_get_{service,store} with the same URL
 +	 * will always return the same object.  So this works. */
 +
 +	if (g_hash_table_lookup (store_hash, store) == NULL)
 +		return;
 +
 +	camel_object_ref (store);
 +	g_hash_table_remove (store_hash, store);
 +	mail_note_store_remove (store);
 +	em_folder_tree_model_remove_store (folder_tree_model, store);
 +
 +	mail_async_event_emit (
 +		async_event, MAIL_ASYNC_THREAD,
 +		(MailAsyncFunc) mail_shell_backend_remove_store_cb,
 +		store, NULL, NULL);
 +}
 +
 +void
 +e_mail_shell_backend_remove_store_by_uri (EMailShellBackend *mail_shell_backend,
 +                                          const gchar *uri)
 +{
 +	CamelStore *store;
 +	CamelProvider *provider;
 +
 +	g_return_if_fail (E_IS_MAIL_SHELL_BACKEND (mail_shell_backend));
 +	g_return_if_fail (uri != NULL);
 +
 +	provider = camel_provider_get (uri, NULL);
 +	if (provider == NULL)
 +		return;
 +
 +	if (!(provider->flags & CAMEL_PROVIDER_IS_STORAGE))
 +		return;
 +
 +	store = (CamelStore *) camel_session_get_service (
 +		session, uri, CAMEL_PROVIDER_STORE, NULL);
 +	if (store != NULL) {
 +		e_mail_shell_backend_remove_store (mail_shell_backend, store);
 +		camel_object_unref (store);
 +	}
 +}
 +
 +void
 +e_mail_shell_backend_stores_foreach (EMailShellBackend *mail_shell_backend,
 +                                     GHFunc func,
 +                                     gpointer user_data)
 +{
 +	GHashTable *store_hash;
 +	GHashTableIter iter;
 +	gpointer key, value;
 +
 +	g_return_if_fail (E_IS_MAIL_SHELL_BACKEND (mail_shell_backend));
 +	g_return_if_fail (func != NULL);
 +
 +	store_hash = mail_shell_backend->priv->store_hash;
 +
 +	g_hash_table_iter_init (&iter, store_hash);
 +
 +	while (g_hash_table_iter_next (&iter, &key, &value))
 +		func (key, ((StoreInfo *) value)->name, user_data);
 +}
 +
 +/******************* Code below here belongs elsewhere. *******************/
 +
 +#include "filter/filter-option.h"
 +#include "shell/e-shell-settings.h"
 +#include "mail/e-mail-label-list-store.h"
 +
 +GSList *
 +e_mail_labels_get_filter_options (void)
 +{
 +	EShell *shell;
 +	EShellSettings *shell_settings;
 +	EMailLabelListStore *list_store;
 +	GtkTreeModel *model;
 +	GtkTreeIter iter;
 +	GSList *list = NULL;
 +	gboolean valid;
 +
 +	shell = e_shell_get_default ();
 +	shell_settings = e_shell_get_shell_settings (shell);
 +	list_store = e_shell_settings_get_object (
 +		shell_settings, "mail-label-list-store");
 +
 +	model = GTK_TREE_MODEL (list_store);
 +	valid = gtk_tree_model_get_iter_first (model, &iter);
 +
 +	while (valid) {
 +		struct _filter_option *option;
 +		gchar *name, *tag;
 +
 +		name = e_mail_label_list_store_get_name (list_store, &iter);
 +		tag = e_mail_label_list_store_get_tag (list_store, &iter);
 +
 +		option = g_new0 (struct _filter_option, 1);
 +		option->title = e_str_without_underscores (name);
 +		option->value = tag;  /* takes ownership */
 +
 +		g_free (name);
 +
 +		valid = gtk_tree_model_iter_next (model, &iter);
 +	}
 +
 +	g_object_unref (list_store);
 +
 +	return list;
 +}
diff --cc mail/e-mail-shell-backend.h
index 7521559,0000000..2487680
mode 100644,000000..100644
--- a/mail/e-mail-shell-backend.h
+++ b/mail/e-mail-shell-backend.h
@@@ -1,122 -1,0 +1,122 @@@
 +/*
 + * e-mail-shell-backend.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_MAIL_SHELL_BACKEND_H
 +#define E_MAIL_SHELL_BACKEND_H
 +
 +#include <shell/e-shell-backend.h>
 +
 +#include <camel/camel-folder.h>
 +#include <camel/camel-store.h>
 +#include <e-util/e-signature-list.h>
 +#include <libedataserver/e-account-list.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_MAIL_SHELL_BACKEND \
 +	(e_mail_shell_backend_get_type ())
 +#define E_MAIL_SHELL_BACKEND(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_MAIL_SHELL_BACKEND, EMailShellBackend))
 +#define E_MAIL_SHELL_BACKEND_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_MAIL_SHELL_BACKEND, EMailShellBackendClass))
 +#define E_IS_MAIL_SHELL_BACKEND(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_MAIL_SHELL_BACKEND))
 +#define E_IS_MAIL_SHELL_BACKEND_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), E_TYPE_MAIL_SHELL_BACKEND))
 +#define E_MAIL_SHELL_BACKEND_GET_CLASS(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_MAIL_SHELL_BACKEND, EMailShellBackendClass))
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _EMailShellBackend EMailShellBackend;
 +typedef struct _EMailShellBackendClass EMailShellBackendClass;
 +typedef struct _EMailShellBackendPrivate EMailShellBackendPrivate;
 +
 +struct _EMailShellBackend {
 +	EShellBackend parent;
 +	EMailShellBackendPrivate *priv;
 +};
 +
 +struct _EMailShellBackendClass {
 +	EShellBackendClass parent_class;
 +};
 +
 +typedef enum {
 +	E_MAIL_FOLDER_INBOX,
 +	E_MAIL_FOLDER_DRAFTS,
 +	E_MAIL_FOLDER_OUTBOX,
 +	E_MAIL_FOLDER_SENT,
 +	E_MAIL_FOLDER_TEMPLATES,
 +	E_MAIL_FOLDER_LOCAL_INBOX
 +} EMailFolderType;
 +
 +struct _EMFolderTreeModel;
 +
 +/* Globally available shell backend.
 + *
 + * XXX I don't like having this globally available but passing it around
 + *     to all the various utilities that need to access the backend's data
 + *     directory and local folders is too much of a pain for now. */
 +extern EMailShellBackend *global_mail_shell_backend;
 +
 +GType		e_mail_shell_backend_get_type	(void);
 +void		e_mail_shell_backend_register_type
 +					(GTypeModule *type_module);
 +CamelFolder *	e_mail_shell_backend_get_folder
 +					(EMailShellBackend *mail_shell_backend,
 +					 EMailFolderType folder_type);
 +const gchar *	e_mail_shell_backend_get_folder_uri
 +					(EMailShellBackend *mail_shell_backend,
 +					 EMailFolderType folder_type);
 +struct _EMFolderTreeModel *
 +		e_mail_shell_backend_get_folder_tree_model
 +					(EMailShellBackend *mail_shell_backend);
 +void		e_mail_shell_backend_add_store
 +					(EMailShellBackend *mail_shell_backend,
 +					 CamelStore *store,
 +					 const gchar *name);
 +CamelStore *	e_mail_shell_backend_get_local_store
 +					(EMailShellBackend *mail_shell_backend);
 +CamelStore *	e_mail_shell_backend_load_store_by_uri
 +					(EMailShellBackend *mail_shell_backend,
 +					 const gchar *uri,
 +					 const gchar *name);
 +void		e_mail_shell_backend_remove_store
 +					(EMailShellBackend *mail_shell_backend,
 +					 CamelStore *store);
 +void		e_mail_shell_backend_remove_store_by_uri
 +					(EMailShellBackend *mail_shell_backend,
 +					 const gchar *uri);
 +void		e_mail_shell_backend_stores_foreach
 +					(EMailShellBackend *mail_shell_backend,
 +					 GHFunc func,
 +					 gpointer user_data);
 +
 +/* XXX Find a better place for this function. */
 +GSList *	e_mail_labels_get_filter_options(void);
 +
 +G_END_DECLS
 +
 +#endif /* E_MAIL_SHELL_BACKEND_H */
diff --cc mail/e-mail-shell-content.c
index de07873,0000000..203876f
mode 100644,000000..100644
--- a/mail/e-mail-shell-content.c
+++ b/mail/e-mail-shell-content.c
@@@ -1,1016 -1,0 +1,1016 @@@
 +/*
 + * e-mail-shell-content.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-mail-shell-content.h"
 +
 +#include <glib/gi18n.h>
 +#include <camel/camel-store.h>
 +#include <libedataserver/e-data-server-util.h>
 +
 +#include "e-util/gconf-bridge.h"
 +#include "widgets/menus/gal-view-etable.h"
 +#include "widgets/menus/gal-view-instance.h"
 +
 +#include "em-folder-view.h"
 +#include "em-search-context.h"
 +#include "em-utils.h"
 +#include "mail-config.h"
 +#include "mail-ops.h"
 +
 +#include "e-mail-reader.h"
 +#include "e-mail-search-bar.h"
 +#include "e-mail-shell-backend.h"
 +#include "e-mail-shell-view-actions.h"
 +
 +#define E_MAIL_SHELL_CONTENT_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_MAIL_SHELL_CONTENT, EMailShellContentPrivate))
 +
 +struct _EMailShellContentPrivate {
 +	GtkWidget *paned;
 +	GtkWidget *message_list;
 +	GtkWidget *search_bar;
 +
 +	EMFormatHTMLDisplay *html_display;
 +	GalViewInstance *view_instance;
 +
 +	gchar *selected_uid;
 +
 +	/* ETable scrolling hack */
 +	gdouble default_scrollbar_position;
 +
 +	guint paned_binding_id;
 +	guint scroll_timeout_id;
 +
 +	/* Signal handler IDs */
 +	guint message_list_built_id;
 +	guint message_list_scrolled_id;
 +
 +	guint preview_visible			: 1;
 +	guint suppress_message_selection	: 1;
 +	guint vertical_view			: 1;
 +	guint show_deleted			: 1;
 +};
 +
 +enum {
 +	PROP_0,
 +	PROP_PREVIEW_VISIBLE,
 +	PROP_SHOW_DELETED,
 +	PROP_VERTICAL_VIEW
 +};
 +
 +static gpointer parent_class;
 +static GType mail_shell_content_type;
 +
 +static void
 +mail_shell_content_etree_unfreeze (MessageList *message_list,
 +                                   GdkEvent *event)
 +{
 +	ETableItem *item;
 +	GObject *object;
 +
 +	item = e_tree_get_item (message_list->tree);
 +	object = G_OBJECT (((GnomeCanvasItem *) item)->canvas);
 +
 +	g_object_set_data (object, "freeze-cursor", 0);
 +}
 +
 +static void
 +mail_shell_content_message_list_scrolled_cb (EMailShellContent *mail_shell_content,
 +                                             MessageList *message_list)
 +{
 +	const gchar *key;
 +	gdouble position;
 +	gchar *value;
 +
 +	/* Save the scrollbar position for the current folder. */
 +
 +	if (message_list->folder == NULL)
 +		return;
 +
 +	key = "evolution:list_scroll_position";
 +	position = message_list_get_scrollbar_position (message_list);
 +	value = g_strdup_printf ("%f", position);
 +
 +	if (camel_object_meta_set (message_list->folder, key, value))
 +		camel_object_state_write (message_list->folder);
 +
 +	g_free (value);
 +}
 +
 +static gboolean
 +mail_shell_content_scroll_timeout_cb (EMailShellContent *mail_shell_content)
 +{
 +	EMailShellContentPrivate *priv = mail_shell_content->priv;
 +	MessageList *message_list;
 +	EMailReader *reader;
 +	const gchar *key;
 +	gdouble position;
 +	gchar *value;
 +
 +	/* Initialize the scrollbar position for the current folder
 +	 * and setup a callback to handle scrollbar position changes. */
 +
 +	reader = E_MAIL_READER (mail_shell_content);
 +	message_list = e_mail_reader_get_message_list (reader);
 +	position = priv->default_scrollbar_position;
 +
 +	key = "evolution:list_scroll_position";
 +	value = camel_object_meta_get (message_list->folder, key);
 +
 +	if (value != NULL) {
 +		position = strtod (value, NULL);
 +		g_free (value);
 +	}
 +
 +	message_list_set_scrollbar_position (message_list, position);
 +
 +	priv->message_list_scrolled_id = g_signal_connect_swapped (
 +		message_list, "message-list-scrolled",
 +		G_CALLBACK (mail_shell_content_message_list_scrolled_cb),
 +		mail_shell_content);
 +
 +	priv->scroll_timeout_id = 0;
 +
 +	return FALSE;
 +}
 +
 +static void
 +mail_shell_content_message_list_built_cb (EMailShellContent *mail_shell_content,
 +                                          MessageList *message_list)
 +{
 +	EMailShellContentPrivate *priv = mail_shell_content->priv;
 +	GtkScrolledWindow *scrolled_window;
 +	GtkWidget *vscrollbar;
 +	gdouble position = 0.0;
 +
 +	g_signal_handler_disconnect (
 +		message_list, priv->message_list_built_id);
 +	priv->message_list_built_id = 0;
 +
 +	if (message_list->cursor_uid == NULL && priv->selected_uid != NULL) {
 +		CamelMessageInfo *info;
 +
 +		/* If the message isn't in the folder yet, keep selected_uid
 +		 * around, as it could be caught by a set_folder() at some
 +		 * later date. */
 +		info = camel_folder_get_message_info (
 +			message_list->folder, priv->selected_uid);
 +		if (info != NULL) {
 +			camel_folder_free_message_info (
 +				message_list->folder, info);
 +			e_mail_reader_set_message (
 +				E_MAIL_READER (mail_shell_content),
 +				priv->selected_uid, TRUE);
 +			g_free (priv->selected_uid);
 +			priv->selected_uid = NULL;
 +		}
 +
 +		position = message_list_get_scrollbar_position (message_list);
 +	}
 +
 +	priv->default_scrollbar_position = position;
 +
 +	/* FIXME This is a gross workaround for an ETable bug that I can't
 +	 *       fix (Ximian bug #55303).
 +	 *
 +	 *       Since e_canvas_item_region_show_relay() uses a timeout,
 +	 *       we have to use a timeout of the same interval but a lower
 +	 *       priority. */
 +	priv->scroll_timeout_id = g_timeout_add_full (
 +		G_PRIORITY_LOW, 250, (GSourceFunc)
 +		mail_shell_content_scroll_timeout_cb,
 +		mail_shell_content, NULL);
 +
 +	/* FIXME This is another ugly hack to hide a side-effect of the
 +	 *       previous workaround. */
 +	scrolled_window = GTK_SCROLLED_WINDOW (message_list);
 +	vscrollbar = gtk_scrolled_window_get_vscrollbar (scrolled_window);
 +	g_signal_connect_swapped (
 +		vscrollbar, "button-press-event",
 +		G_CALLBACK (mail_shell_content_etree_unfreeze),
 +		message_list);
 +}
 +
 +static void
 +mail_shell_content_display_view_cb (EMailShellContent *mail_shell_content,
 +                                    GalView *gal_view)
 +{
 +	EMailReader *reader;
 +	MessageList *message_list;
 +
 +	reader = E_MAIL_READER (mail_shell_content);
 +	message_list = e_mail_reader_get_message_list (reader);
 +
 +	if (GAL_IS_VIEW_ETABLE (gal_view))
 +		gal_view_etable_attach_tree (
 +			GAL_VIEW_ETABLE (gal_view), message_list->tree);
 +}
 +
 +static void
 +mail_shell_content_message_selected_cb (EMailShellContent *mail_shell_content,
 +                                        const gchar *selected_uid,
 +                                        MessageList *message_list)
 +{
 +	const gchar *key = "evolution:selected_uid";
 +	CamelFolder *folder;
 +
 +	folder = message_list->folder;
 +
 +	/* This also gets triggered when selecting a store name on
 +	 * the sidebar such as "On This Computer", in which case
 +	 * 'folder' will be NULL. */
 +	if (folder == NULL)
 +		return;
 +
 +	if (camel_object_meta_set (folder, key, selected_uid))
 +		camel_object_state_write (folder);
 +
 +	g_free (mail_shell_content->priv->selected_uid);
 +	mail_shell_content->priv->selected_uid = NULL;
 +}
 +
 +static void
 +mail_shell_content_set_property (GObject *object,
 +                                 guint property_id,
 +                                 const GValue *value,
 +                                 GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_PREVIEW_VISIBLE:
 +			e_mail_shell_content_set_preview_visible (
 +				E_MAIL_SHELL_CONTENT (object),
 +				g_value_get_boolean (value));
 +			return;
 +
 +		case PROP_SHOW_DELETED:
 +			e_mail_shell_content_set_show_deleted (
 +				E_MAIL_SHELL_CONTENT (object),
 +				g_value_get_boolean (value));
 +			return;
 +
 +		case PROP_VERTICAL_VIEW:
 +			e_mail_shell_content_set_vertical_view (
 +				E_MAIL_SHELL_CONTENT (object),
 +				g_value_get_boolean (value));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +mail_shell_content_get_property (GObject *object,
 +                                 guint property_id,
 +                                 GValue *value,
 +                                 GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_PREVIEW_VISIBLE:
 +			g_value_set_boolean (
 +				value,
 +				e_mail_shell_content_get_preview_visible (
 +				E_MAIL_SHELL_CONTENT (object)));
 +			return;
 +
 +		case PROP_SHOW_DELETED:
 +			g_value_set_boolean (
 +				value,
 +				e_mail_shell_content_get_show_deleted (
 +				E_MAIL_SHELL_CONTENT (object)));
 +			return;
 +
 +		case PROP_VERTICAL_VIEW:
 +			g_value_set_boolean (
 +				value,
 +				e_mail_shell_content_get_vertical_view (
 +				E_MAIL_SHELL_CONTENT (object)));
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +mail_shell_content_dispose (GObject *object)
 +{
 +	EMailShellContentPrivate *priv;
 +
 +	priv = E_MAIL_SHELL_CONTENT_GET_PRIVATE (object);
 +
 +	if (priv->paned != NULL) {
 +		g_object_unref (priv->paned);
 +		priv->paned = NULL;
 +	}
 +
 +	if (priv->message_list != NULL) {
 +		g_object_unref (priv->message_list);
 +		priv->message_list = NULL;
 +	}
 +
 +	if (priv->search_bar != NULL) {
 +		g_object_unref (priv->search_bar);
 +		priv->search_bar = NULL;
 +	}
 +
 +	if (priv->html_display != NULL) {
 +		g_object_unref (priv->html_display);
 +		priv->html_display = NULL;
 +	}
 +
 +	if (priv->view_instance != NULL) {
 +		g_object_unref (priv->view_instance);
 +		priv->view_instance = NULL;
 +	}
 +
 +	/* Chain up to parent's dispose() method. */
 +	G_OBJECT_CLASS (parent_class)->dispose (object);
 +}
 +
 +static void
 +mail_shell_content_finalize (GObject *object)
 +{
 +	EMailShellContentPrivate *priv;
 +
 +	priv = E_MAIL_SHELL_CONTENT_GET_PRIVATE (object);
 +
 +	g_free (priv->selected_uid);
 +
 +	/* Chain up to parent's finalize() method. */
 +	G_OBJECT_CLASS (parent_class)->finalize (object);
 +}
 +
 +static void
 +mail_shell_content_constructed (GObject *object)
 +{
 +	EMailShellContentPrivate *priv;
 +	EShellContent *shell_content;
 +	EShellBackend *shell_backend;
 +	EShellView *shell_view;
 +	EShellViewClass *shell_view_class;
 +	EMailReader *reader;
 +	MessageList *message_list;
 +	GConfBridge *bridge;
 +	GtkWidget *container;
 +	GtkWidget *widget;
 +	GtkHTML *html;
 +	GalViewCollection *view_collection;
 +	const gchar *key;
 +
 +	priv = E_MAIL_SHELL_CONTENT_GET_PRIVATE (object);
 +	priv->html_display = em_format_html_display_new ();
 +
 +	/* Chain up to parent's constructed() method. */
 +	G_OBJECT_CLASS (parent_class)->constructed (object);
 +
 +	shell_content = E_SHELL_CONTENT (object);
 +	shell_view = e_shell_content_get_shell_view (shell_content);
 +	shell_view_class = E_SHELL_VIEW_GET_CLASS (shell_view);
 +	shell_backend = e_shell_view_get_shell_backend (shell_view);
 +	view_collection = shell_view_class->view_collection;
 +
 +	html = EM_FORMAT_HTML (priv->html_display)->html;
 +
 +	/* Build content widgets. */
 +
 +	container = GTK_WIDGET (object);
 +
 +	widget = gtk_vpaned_new ();
 +	gtk_container_add (GTK_CONTAINER (container), widget);
 +	priv->paned = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	container = widget;
 +
 +	widget = message_list_new (shell_backend);
 +	gtk_paned_add1 (GTK_PANED (container), widget);
 +	priv->message_list = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	widget = gtk_vbox_new (FALSE, 1);
 +	gtk_paned_add2 (GTK_PANED (container), widget);
 +	gtk_widget_show (widget);
 +
 +	container = widget;
 +
 +	widget = gtk_scrolled_window_new (NULL, NULL);
 +	gtk_scrolled_window_set_policy (
 +		GTK_SCROLLED_WINDOW (widget),
 +		GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
 +	gtk_scrolled_window_set_shadow_type (
 +		GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
 +	gtk_container_add (GTK_CONTAINER (widget), GTK_WIDGET (html));
 +	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
 +	gtk_widget_show (GTK_WIDGET (html));
 +	gtk_widget_show (widget);
 +
 +	widget = e_mail_search_bar_new (html);
 +	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
 +	priv->search_bar = g_object_ref (widget);
 +	gtk_widget_hide (widget);
 +
 +	g_signal_connect_swapped (
 +		widget, "changed",
 +		G_CALLBACK (em_format_redraw), priv->html_display);
 +
 +	/* Load the view instance. */
 +
 +	e_mail_shell_content_update_view_instance (
 +		E_MAIL_SHELL_CONTENT (shell_content));
 +
 +	/* Bind GObject properties to GConf keys. */
 +
 +	bridge = gconf_bridge_get ();
 +
 +	object = G_OBJECT (priv->paned);
 +	key = "/apps/evolution/mail/display/paned_size";
 +	gconf_bridge_bind_property_delayed (bridge, key, object, "position");
 +
 +	object = G_OBJECT (shell_content);
 +	key = "/apps/evolution/mail/display/show_deleted";
 +	gconf_bridge_bind_property (bridge, key, object, "show-deleted");
 +
 +	/* Message list customizations. */
 +
 +	reader = E_MAIL_READER (shell_content);
 +	message_list = e_mail_reader_get_message_list (reader);
 +
 +	g_signal_connect_swapped (
 +		message_list, "message-selected",
 +		G_CALLBACK (mail_shell_content_message_selected_cb),
 +		shell_content);
 +}
 +
 +static guint32
 +mail_shell_content_check_state (EShellContent *shell_content)
 +{
 +	return e_mail_reader_check_state (E_MAIL_READER (shell_content));
 +}
 +
 +static GtkActionGroup *
 +mail_shell_content_get_action_group (EMailReader *reader)
 +{
 +	EShellContent *shell_content;
 +	EShellWindow *shell_window;
 +	EShellView *shell_view;
 +
 +	shell_content = E_SHELL_CONTENT (reader);
 +	shell_view = e_shell_content_get_shell_view (shell_content);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	return E_SHELL_WINDOW_ACTION_GROUP_MAIL (shell_window);
 +}
 +
 +static gboolean
 +mail_shell_content_get_hide_deleted (EMailReader *reader)
 +{
 +	EMailShellContent *mail_shell_content;
 +
 +	mail_shell_content = E_MAIL_SHELL_CONTENT (reader);
 +
 +	return !e_mail_shell_content_get_show_deleted (mail_shell_content);
 +}
 +
 +static EMFormatHTMLDisplay *
 +mail_shell_content_get_html_display (EMailReader *reader)
 +{
 +	EMailShellContentPrivate *priv;
 +
 +	priv = E_MAIL_SHELL_CONTENT_GET_PRIVATE (reader);
 +
 +	return priv->html_display;
 +}
 +
 +static MessageList *
 +mail_shell_content_get_message_list (EMailReader *reader)
 +{
 +	EMailShellContentPrivate *priv;
 +
 +	priv = E_MAIL_SHELL_CONTENT_GET_PRIVATE (reader);
 +
 +	return MESSAGE_LIST (priv->message_list);
 +}
 +
 +static EShellBackend *
 +mail_shell_content_get_shell_backend (EMailReader *reader)
 +{
 +	EShellContent *shell_content;
 +	EShellView *shell_view;
 +
 +	shell_content = E_SHELL_CONTENT (reader);
 +	shell_view = e_shell_content_get_shell_view (shell_content);
 +
 +	return e_shell_view_get_shell_backend (shell_view);
 +}
 +
 +static GtkWindow *
 +mail_shell_content_get_window (EMailReader *reader)
 +{
 +	EShellContent *shell_content;
 +	EShellWindow *shell_window;
 +	EShellView *shell_view;
 +
 +	shell_content = E_SHELL_CONTENT (reader);
 +	shell_view = e_shell_content_get_shell_view (shell_content);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	return GTK_WINDOW (shell_window);
 +}
 +
 +static void
 +mail_shell_content_set_folder (EMailReader *reader,
 +                               CamelFolder *folder,
 +                               const gchar *folder_uri)
 +{
 +	EMailShellContentPrivate *priv;
 +	EMailReaderIface *default_iface;
 +	MessageList *message_list;
 +	gboolean different_folder;
 +	gchar *meta_data;
 +
 +	priv = E_MAIL_SHELL_CONTENT_GET_PRIVATE (reader);
 +
 +	message_list = e_mail_reader_get_message_list (reader);
 +
 +	message_list_freeze (message_list);
 +
 +	different_folder =
 +		message_list->folder != NULL &&
 +		folder != message_list->folder;
 +
 +	/* Chain up to interface's default set_folder() method. */
 +	default_iface = g_type_default_interface_peek (E_TYPE_MAIL_READER);
 +	default_iface->set_folder (reader, folder, folder_uri);
 +
 +	if (folder == NULL)
 +		goto exit;
 +
 +	mail_refresh_folder (folder, NULL, NULL);
 +
 +	/* This function gets triggered several times at startup,
 +	 * so we don't want to reset the message suppression state
 +	 * unless we're actually switching to a different folder. */
 +	if (different_folder)
 +		priv->suppress_message_selection = FALSE;
 +
 +	if (!priv->suppress_message_selection)
 +		meta_data = camel_object_meta_get (
 +			folder, "evolution:selected_uid");
 +	else
 +		meta_data = NULL;
 +
 +	g_free (priv->selected_uid);
 +	priv->selected_uid = meta_data;
 +
 +	/* This is a one-time-only callback. */
 +	if (message_list->cursor_uid == NULL && priv->message_list_built_id == 0)
 +		priv->message_list_built_id = g_signal_connect_swapped (
 +			message_list, "message-list-built",
 +			G_CALLBACK (mail_shell_content_message_list_built_cb),
 +			reader);
 +
 +exit:
 +	message_list_thaw (message_list);
 +}
 +
 +static void
 +mail_shell_content_show_search_bar (EMailReader *reader)
 +{
 +	EMailShellContentPrivate *priv;
 +
 +	priv = E_MAIL_SHELL_CONTENT_GET_PRIVATE (reader);
 +
 +	gtk_widget_show (priv->search_bar);
 +}
 +
 +static void
 +mail_shell_content_class_init (EMailShellContentClass *class)
 +{
 +	GObjectClass *object_class;
 +	EShellContentClass *shell_content_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (EMailShellContentPrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->set_property = mail_shell_content_set_property;
 +	object_class->get_property = mail_shell_content_get_property;
 +	object_class->dispose = mail_shell_content_dispose;
 +	object_class->finalize = mail_shell_content_finalize;
 +	object_class->constructed = mail_shell_content_constructed;
 +
 +	shell_content_class = E_SHELL_CONTENT_CLASS (class);
 +	shell_content_class->new_search_context = em_search_context_new;
 +	shell_content_class->check_state = mail_shell_content_check_state;
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_PREVIEW_VISIBLE,
 +		g_param_spec_boolean (
 +			"preview-visible",
 +			_("Preview is Visible"),
 +			_("Whether the preview pane is visible"),
 +			TRUE,
 +			G_PARAM_READWRITE));
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_SHOW_DELETED,
 +		g_param_spec_boolean (
 +			"show-deleted",
 +			"Show Deleted",
 +			NULL,
 +			FALSE,
 +			G_PARAM_READWRITE));
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_VERTICAL_VIEW,
 +		g_param_spec_boolean (
 +			"vertical-view",
 +			_("Vertical View"),
 +			_("Whether vertical view is enabled"),
 +			FALSE,
 +			G_PARAM_READWRITE));
 +}
 +
 +static void
 +mail_shell_content_iface_init (EMailReaderIface *iface)
 +{
 +	iface->get_action_group = mail_shell_content_get_action_group;
 +	iface->get_hide_deleted = mail_shell_content_get_hide_deleted;
 +	iface->get_html_display = mail_shell_content_get_html_display;
 +	iface->get_message_list = mail_shell_content_get_message_list;
 +	iface->get_shell_backend = mail_shell_content_get_shell_backend;
 +	iface->get_window = mail_shell_content_get_window;
 +	iface->set_folder = mail_shell_content_set_folder;
 +	iface->show_search_bar = mail_shell_content_show_search_bar;
 +}
 +
 +static void
 +mail_shell_content_init (EMailShellContent *mail_shell_content)
 +{
 +	mail_shell_content->priv =
 +		E_MAIL_SHELL_CONTENT_GET_PRIVATE (mail_shell_content);
 +
 +	mail_shell_content->priv->preview_visible = TRUE;
 +
 +	/* Postpone widget construction until we have a shell view. */
 +}
 +
 +GType
 +e_mail_shell_content_get_type (void)
 +{
 +	return mail_shell_content_type;
 +}
 +
 +void
 +e_mail_shell_content_register_type (GTypeModule *type_module)
 +{
 +	static const GTypeInfo type_info = {
 +		sizeof (EMailShellContentClass),
 +		(GBaseInitFunc) NULL,
 +		(GBaseFinalizeFunc) NULL,
 +		(GClassInitFunc) mail_shell_content_class_init,
 +		(GClassFinalizeFunc) NULL,
 +		NULL,  /* class_data */
 +		sizeof (EMailShellContent),
 +		0,     /* n_preallocs */
 +		(GInstanceInitFunc) mail_shell_content_init,
 +		NULL   /* value_table */
 +	};
 +
 +	static const GInterfaceInfo iface_info = {
 +		(GInterfaceInitFunc) mail_shell_content_iface_init,
 +		(GInterfaceFinalizeFunc) NULL,
 +		NULL  /* interface_data */
 +	};
 +
 +	mail_shell_content_type = g_type_module_register_type (
 +		type_module, E_TYPE_SHELL_CONTENT,
 +		"EMailShellContent", &type_info, 0);
 +
 +	g_type_module_add_interface (
 +		type_module, mail_shell_content_type,
 +		E_TYPE_MAIL_READER, &iface_info);
 +}
 +
 +GtkWidget *
 +e_mail_shell_content_new (EShellView *shell_view)
 +{
 +	g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
 +
 +	return g_object_new (
 +		E_TYPE_MAIL_SHELL_CONTENT,
 +		"shell-view", shell_view, NULL);
 +}
 +
 +gboolean
 +e_mail_shell_content_get_preview_visible (EMailShellContent *mail_shell_content)
 +{
 +	g_return_val_if_fail (
 +		E_IS_MAIL_SHELL_CONTENT (mail_shell_content), FALSE);
 +
 +	return mail_shell_content->priv->preview_visible;
 +}
 +
 +void
 +e_mail_shell_content_set_preview_visible (EMailShellContent *mail_shell_content,
 +                                          gboolean preview_visible)
 +{
 +	GtkPaned *paned;
 +	GtkWidget *child;
 +
 +	g_return_if_fail (E_IS_MAIL_SHELL_CONTENT (mail_shell_content));
 +
 +	if (preview_visible == mail_shell_content->priv->preview_visible)
 +		return;
 +
 +	paned = GTK_PANED (mail_shell_content->priv->paned);
 +	child = gtk_paned_get_child2 (paned);
 +
 +	if (preview_visible)
 +		gtk_widget_show (child);
 +	else
 +		gtk_widget_hide (child);
 +
 +	mail_shell_content->priv->preview_visible = preview_visible;
 +
 +	g_object_notify (G_OBJECT (mail_shell_content), "preview-visible");
 +}
 +
 +gboolean
 +e_mail_shell_content_get_show_deleted (EMailShellContent *mail_shell_content)
 +{
 +	g_return_val_if_fail (
 +		E_IS_MAIL_SHELL_CONTENT (mail_shell_content), FALSE);
 +
 +	return mail_shell_content->priv->show_deleted;
 +}
 +
 +void
 +e_mail_shell_content_set_show_deleted (EMailShellContent *mail_shell_content,
 +                                       gboolean show_deleted)
 +{
 +	g_return_if_fail (E_IS_MAIL_SHELL_CONTENT (mail_shell_content));
 +
 +	mail_shell_content->priv->show_deleted = show_deleted;
 +
 +	g_object_notify (G_OBJECT (mail_shell_content), "show-deleted");
 +}
 +
 +gboolean
 +e_mail_shell_content_get_vertical_view (EMailShellContent *mail_shell_content)
 +{
 +	g_return_val_if_fail (
 +		E_IS_MAIL_SHELL_CONTENT (mail_shell_content), FALSE);
 +
 +	return mail_shell_content->priv->vertical_view;
 +}
 +
 +void
 +e_mail_shell_content_set_vertical_view (EMailShellContent *mail_shell_content,
 +                                        gboolean vertical_view)
 +{
 +	GConfBridge *bridge;
 +	GtkWidget *old_paned;
 +	GtkWidget *new_paned;
 +	GtkWidget *child1;
 +	GtkWidget *child2;
 +	guint binding_id;
 +	const gchar *key;
 +
 +	g_return_if_fail (E_IS_MAIL_SHELL_CONTENT (mail_shell_content));
 +
 +	if (vertical_view == mail_shell_content->priv->vertical_view)
 +		return;
 +
 +	bridge = gconf_bridge_get ();
 +	old_paned = mail_shell_content->priv->paned;
 +	binding_id = mail_shell_content->priv->paned_binding_id;
 +
 +	child1 = gtk_paned_get_child1 (GTK_PANED (old_paned));
 +	child2 = gtk_paned_get_child2 (GTK_PANED (old_paned));
 +
 +	if (binding_id > 0)
 +		gconf_bridge_unbind (bridge, binding_id);
 +
 +	if (vertical_view) {
 +		new_paned = gtk_hpaned_new ();
 +		key = "/apps/evolution/mail/display/hpaned_size";
 +	} else {
 +		new_paned = gtk_vpaned_new ();
 +		key = "/apps/evolution/mail/display/paned_size";
 +	}
 +
 +	gtk_widget_reparent (child1, new_paned);
 +	gtk_widget_reparent (child2, new_paned);
 +	gtk_widget_show (new_paned);
 +
 +	gtk_widget_destroy (old_paned);
 +	gtk_container_add (GTK_CONTAINER (mail_shell_content), new_paned);
 +
 +	binding_id = gconf_bridge_bind_property_delayed (
 +		bridge, key, G_OBJECT (new_paned), "position");
 +
 +	mail_shell_content->priv->vertical_view = vertical_view;
 +	mail_shell_content->priv->paned_binding_id = binding_id;
 +	mail_shell_content->priv->paned = g_object_ref (new_paned);
 +
 +	e_mail_shell_content_update_view_instance (mail_shell_content);
 +
 +	g_object_notify (G_OBJECT (mail_shell_content), "vertical-view");
 +}
 +
 +GalViewInstance *
 +e_mail_shell_content_get_view_instance (EMailShellContent *mail_shell_content)
 +{
 +	g_return_val_if_fail (
 +		E_IS_MAIL_SHELL_CONTENT (mail_shell_content), NULL);
 +
 +	return mail_shell_content->priv->view_instance;
 +}
 +
 +void
 +e_mail_shell_content_set_search_strings (EMailShellContent *mail_shell_content,
 +                                         GSList *search_strings)
 +{
 +	EMailSearchBar *search_bar;
 +	ESearchingTokenizer *tokenizer;
 +
 +	g_return_if_fail (E_IS_MAIL_SHELL_CONTENT (mail_shell_content));
 +
 +	search_bar = E_MAIL_SEARCH_BAR (mail_shell_content->priv->search_bar);
 +	tokenizer = e_mail_search_bar_get_tokenizer (search_bar);
 +
 +	e_searching_tokenizer_set_secondary_case_sensitivity (tokenizer, FALSE);
 +	e_searching_tokenizer_set_secondary_search_string (tokenizer, NULL);
 +
 +	while (search_strings != NULL) {
 +		e_searching_tokenizer_add_secondary_search_string (
 +			tokenizer, search_strings->data);
 +		search_strings = g_slist_next (search_strings);
 +	}
 +
 +	e_mail_search_bar_changed (search_bar);
 +}
 +
 +void
 +e_mail_shell_content_update_view_instance (EMailShellContent *mail_shell_content)
 +{
 +	EMailReader *reader;
 +	EShellContent *shell_content;
 +	EShellView *shell_view;
 +	EShellViewClass *shell_view_class;
 +	GalViewCollection *view_collection;
 +	GalViewInstance *view_instance;
 +	MessageList *message_list;
 +	gboolean outgoing_folder;
 +	gboolean show_vertical_view;
 +	gchar *view_id;
 +
 +	g_return_if_fail (E_IS_MAIL_SHELL_CONTENT (mail_shell_content));
 +
 +	shell_content = E_SHELL_CONTENT (mail_shell_content);
 +	shell_view = e_shell_content_get_shell_view (shell_content);
 +	shell_view_class = E_SHELL_VIEW_GET_CLASS (shell_view);
 +	view_collection = shell_view_class->view_collection;
 +
 +	reader = E_MAIL_READER (mail_shell_content);
 +	message_list = e_mail_reader_get_message_list (reader);
 +
 +	/* If no folder is selected, return silently. */
 +	if (message_list->folder == NULL)
 +		return;
 +
 +	/* If we have a folder, we should also have a URI. */
 +	g_return_if_fail (message_list->folder_uri != NULL);
 +
 +	if (mail_shell_content->priv->view_instance != NULL) {
 +		g_object_unref (mail_shell_content->priv->view_instance);
 +		mail_shell_content->priv->view_instance = NULL;
 +	}
 +
 +	view_id = mail_config_folder_to_safe_url (message_list->folder);
 +	view_instance = e_shell_view_new_view_instance (shell_view, view_id);
 +	mail_shell_content->priv->view_instance = view_instance;
 +
 +	show_vertical_view =
 +		e_mail_shell_content_get_vertical_view (mail_shell_content);
 +
 +	if (show_vertical_view) {
 +		gchar *filename;
 +		gchar *safe_view_id;
 +
 +		/* Force the view instance into vertical view. */
 +
 +		g_free (view_instance->custom_filename);
 +		g_free (view_instance->current_view_filename);
 +
 +		safe_view_id = g_strdup (view_id);
 +		e_filename_make_safe (safe_view_id);
 +
 +		filename = g_strdup_printf (
 +			"custom_wide_view-%s.xml", safe_view_id);
 +		view_instance->custom_filename = g_build_filename (
 +			view_collection->local_dir, filename, NULL);
 +		g_free (filename);
 +
 +		filename = g_strdup_printf (
 +			"current_wide_view-%s.xml", safe_view_id);
 +		view_instance->current_view_filename = g_build_filename (
 +			view_collection->local_dir, filename, NULL);
 +		g_free (filename);
 +
 +		g_free (safe_view_id);
 +	}
 +
 +	g_free (view_id);
 +
 +	outgoing_folder =
 +		em_utils_folder_is_drafts (
 +			message_list->folder, message_list->folder_uri) ||
 +		em_utils_folder_is_outbox (
 +			message_list->folder, message_list->folder_uri) ||
 +		em_utils_folder_is_sent (
 +			message_list->folder, message_list->folder_uri);
 +
 +	if (outgoing_folder) {
 +		if (show_vertical_view)
 +			gal_view_instance_set_default_view (
 +				view_instance, "Wide_View_Sent");
 +		else
 +			gal_view_instance_set_default_view (
 +				view_instance, "As_Sent_Folder");
 +	} else if (show_vertical_view) {
 +		gal_view_instance_set_default_view (
 +			view_instance, "Wide_View_Normal");
 +	}
 +
 +	gal_view_instance_load (view_instance);
 +
 +	if (!gal_view_instance_exists (view_instance)) {
 +		gchar *state_filename;
 +
 +		state_filename = mail_config_folder_to_cachename (
 +			message_list->folder, "et-header-");
 +
 +		if (g_file_test (state_filename, G_FILE_TEST_IS_REGULAR)) {
 +			ETableSpecification *spec;
 +			ETableState *state;
 +			GalView *view;
 +			gchar *spec_filename;
 +
 +			spec = e_table_specification_new ();
 +			spec_filename = g_build_filename (
 +				EVOLUTION_ETSPECDIR,
 +				"message-list.etspec",
 +				NULL);
 +			e_table_specification_load_from_file (
 +				spec, spec_filename);
 +			g_free (spec_filename);
 +
 +			state = e_table_state_new ();
 +			view = gal_view_etable_new (spec, "");
 +
 +			e_table_state_load_from_file (
 +				state, state_filename);
 +			gal_view_etable_set_state (
 +				GAL_VIEW_ETABLE (view), state);
 +			gal_view_instance_set_custom_view (
 +				view_instance, view);
 +
 +			g_object_unref (state);
 +			g_object_unref (view);
 +			g_object_unref (spec);
 +		}
 +
 +		g_free (state_filename);
 +	}
 +
 +	g_signal_connect (
 +		view_instance, "display-view",
 +		G_CALLBACK (mail_shell_content_display_view_cb),
 +		mail_shell_content);
 +
 +	mail_shell_content_display_view_cb (
 +		mail_shell_content,
 +		gal_view_instance_get_current_view (view_instance));
 +}
diff --cc mail/e-mail-shell-content.h
index 2c5da1b,0000000..57d2438
mode 100644,000000..100644
--- a/mail/e-mail-shell-content.h
+++ b/mail/e-mail-shell-content.h
@@@ -1,94 -1,0 +1,94 @@@
 +/*
 + * e-mail-shell-content.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_MAIL_SHELL_CONTENT_H
 +#define E_MAIL_SHELL_CONTENT_H
 +
 +#include <shell/e-shell-content.h>
 +#include <shell/e-shell-view.h>
 +
 +#include <mail/em-format-html-display.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_MAIL_SHELL_CONTENT \
 +	(e_mail_shell_content_get_type ())
 +#define E_MAIL_SHELL_CONTENT(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_MAIL_SHELL_CONTENT, EMailShellContent))
 +#define E_MAIL_SHELL_CONTENT_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_MAIL_SHELL_CONTENT, EMailShellContentClass))
 +#define E_IS_MAIL_SHELL_CONTENT(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_MAIL_SHELL_CONTENT))
 +#define E_IS_MAIL_SHELL_CONTENT_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), E_TYPE_MAIL_SHELL_CONTENT))
 +#define E_MAIL_SHELL_CONTENT_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_MAIL_SHELL_CONTENT, EMailShellContentClass))
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _EMailShellContent EMailShellContent;
 +typedef struct _EMailShellContentClass EMailShellContentClass;
 +typedef struct _EMailShellContentPrivate EMailShellContentPrivate;
 +
 +struct _EMailShellContent {
 +	EShellContent parent;
 +	EMailShellContentPrivate *priv;
 +};
 +
 +struct _EMailShellContentClass {
 +	EShellContentClass parent_class;
 +};
 +
 +GType		e_mail_shell_content_get_type	(void);
 +void		e_mail_shell_content_register_type
 +					(GTypeModule *type_module);
 +GtkWidget *	e_mail_shell_content_new(EShellView *shell_view);
 +gboolean	e_mail_shell_content_get_preview_visible
 +					(EMailShellContent *mail_shell_content);
 +void		e_mail_shell_content_set_preview_visible
 +					(EMailShellContent *mail_shell_content,
 +						 gboolean preview_visible);
 +gboolean	e_mail_shell_content_get_show_deleted
 +					(EMailShellContent *mail_shell_content);
 +void		e_mail_shell_content_set_show_deleted
 +					(EMailShellContent *mail_shell_content,
 +					 gboolean show_deleted);
 +gboolean	e_mail_shell_content_get_vertical_view
 +					(EMailShellContent *mail_shell_content);
 +void		e_mail_shell_content_set_vertical_view
 +					(EMailShellContent *mail_shell_content,
 +					 gboolean vertical_view);
 +GalViewInstance *
 +		e_mail_shell_content_get_view_instance
 +					(EMailShellContent *mail_shell_content);
 +void		e_mail_shell_content_set_search_strings
 +					(EMailShellContent *mail_shell_content,
 +					 GSList *search_strings);
 +void		e_mail_shell_content_update_view_instance
 +					(EMailShellContent *mail_shell_content);
 +
 +G_END_DECLS
 +
 +#endif /* E_MAIL_SHELL_CONTENT_H */
diff --cc mail/e-mail-shell-migrate.c
index 9a31f67,0000000..6202224
mode 100644,000000..100644
--- a/mail/e-mail-shell-migrate.c
+++ b/mail/e-mail-shell-migrate.c
@@@ -1,2989 -1,0 +1,3105 @@@
 +/*
 + * e-mail-shell-migrate.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
 + * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-mail-shell-migrate.h"
 +
 +#include <stdio.h>
 +#include <stdlib.h>
 +#include <string.h>
 +#include <sys/types.h>
 +#include <sys/stat.h>
 +#include <utime.h>
 +#include <unistd.h>
 +#include <dirent.h>
 +#include <regex.h>
 +#include <errno.h>
 +#include <ctype.h>
 +
 +#include <glib.h>
 +#include <glib/gi18n.h>
 +#include <glib/gstdio.h>
 +
 +#include <gtk/gtk.h>
 +
 +#include <gconf/gconf-client.h>
 +
 +#include <camel/camel.h>
 +#include <camel/camel-store.h>
 +#include <camel/camel-session.h>
 +#include <camel/camel-file-utils.h>
 +#include <camel/camel-disco-folder.h>
 +
 +#include <libxml/tree.h>
 +#include <libxml/parser.h>
 +#include <libxml/xmlmemory.h>
 +
 +#include <e-util/e-util.h>
++#include <libedataserver/e-xml-utils.h>
 +#include <libedataserver/e-data-server-util.h>
 +#include <e-util/e-xml-utils.h>
 +
 +#include "e-util/e-account-utils.h"
 +#include "e-util/e-bconf-map.h"
 +#include "e-util/e-error.h"
 +#include "e-util/e-util-private.h"
 +#include "e-util/e-plugin.h"
 +#include "e-util/e-signature-utils.h"
 +
 +#include "e-mail-shell-backend.h"
 +#include "shell/e-shell-migrate.h"
 +
 +#include "mail-config.h"
 +#include "em-utils.h"
 +
 +#define d(x) x
 +
 +#ifndef G_OS_WIN32
 +/* No versions previous to 2.8 or thereabouts have been available on
 + * Windows, so don't bother with upgrade support from earlier versions
 + * on Win32. Do try to support upgrades from 2.12 and later to the
 + * current version.
 + */
 +
 +/* upgrade helper functions */
 +static xmlDocPtr
 +emm_load_xml (const char *dirname, const char *filename)
 +{
 +	xmlDocPtr doc;
 +	struct stat st;
 +	char *path;
 +
 +	path = g_strdup_printf ("%s/%s", dirname, filename);
 +	if (stat (path, &st) == -1 || !(doc = xmlParseFile (path))) {
 +		g_free (path);
 +		return NULL;
 +	}
 +
 +	g_free (path);
 +
 +	return doc;
 +}
 +
 +static int
 +emm_save_xml (xmlDocPtr doc, const char *dirname, const char *filename)
 +{
 +	char *path;
 +	int retval;
 +
 +	path = g_strdup_printf ("%s/%s", dirname, filename);
 +	retval = e_xml_save_file (path, doc);
 +	g_free (path);
 +
 +	return retval;
 +}
 +
 +static xmlNodePtr
 +xml_find_node (xmlNodePtr parent, const char *name)
 +{
 +	xmlNodePtr node;
 +
 +	node = parent->children;
 +	while (node != NULL) {
 +		if (node->name && !strcmp ((char *)node->name, name))
 +			return node;
 +
 +		node = node->next;
 +	}
 +
 +	return NULL;
 +}
 +
 +static void
 +upgrade_xml_uris (xmlDocPtr doc, char * (* upgrade_uri) (const char *uri))
 +{
 +	xmlNodePtr root, node;
 +	char *uri, *new;
 +
 +	if (!doc || !(root = xmlDocGetRootElement (doc)))
 +		return;
 +
 +	if (!root->name || strcmp ((char *)root->name, "filteroptions") != 0) {
 +		/* root node is not <filteroptions>, nothing to upgrade */
 +		return;
 +	}
 +
 +	if (!(node = xml_find_node (root, "ruleset"))) {
 +		/* no ruleset node, nothing to upgrade */
 +		return;
 +	}
 +
 +	node = node->children;
 +	while (node != NULL) {
 +		if (node->name && !strcmp ((char *)node->name, "rule")) {
 +			xmlNodePtr actionset, part, val, n;
 +
 +			if ((actionset = xml_find_node (node, "actionset"))) {
 +				/* filters.xml */
 +				part = actionset->children;
 +				while (part != NULL) {
 +					if (part->name && !strcmp ((char *)part->name, "part")) {
 +						val = part->children;
 +						while (val != NULL) {
 +							if (val->name && !strcmp ((char *)val->name, "value")) {
 +								char *type;
 +
 +								type = (char *)xmlGetProp (val, (const unsigned char *)"type");
 +								if (type && !strcmp ((char *)type, "folder")) {
 +									if ((n = xml_find_node (val, "folder"))) {
 +										uri = (char *)xmlGetProp (n, (const unsigned char *)"uri");
 +										new = upgrade_uri (uri);
 +										xmlFree (uri);
 +
 +										xmlSetProp (n, (const unsigned char *)"uri", (unsigned char *)new);
 +										g_free (new);
 +									}
 +								}
 +
 +								xmlFree (type);
 +							}
 +
 +							val = val->next;
 +						}
 +					}
 +
 +					part = part->next;
 +				}
 +			} else if ((actionset = xml_find_node (node, "sources"))) {
 +				/* vfolders.xml */
 +				n = actionset->children;
 +				while (n != NULL) {
 +					if (n->name && !strcmp ((char *)n->name, "folder")) {
 +						uri = (char *)xmlGetProp (n, (const unsigned char *)"uri");
 +						new = upgrade_uri (uri);
 +						xmlFree (uri);
 +
 +						xmlSetProp (n, (const unsigned char *)"uri", (unsigned char *)new);
 +						g_free (new);
 +					}
 +
 +					n = n->next;
 +				}
 +			}
 +		}
 +
 +		node = node->next;
 +	}
 +}
 +
 +/* 1.0 upgrade functions & data */
 +
 +/* as much info as we have on a given account */
 +struct _account_info_1_0 {
 +	char *name;
 +	char *uri;
 +	char *base_uri;
 +	union {
 +		struct {
 +			/* for imap */
 +			char *namespace;
 +			char *namespace_full;
 +			guint32 capabilities;
 +			GHashTable *folders;
 +			char dir_sep;
 +		} imap;
 +	} u;
 +};
 +
 +struct _imap_folder_info_1_0 {
 +	char *folder;
 +	/* encoded?  decoded?  canonicalised? */
 +	char dir_sep;
 +};
 +
 +static GHashTable *accounts_1_0 = NULL;
 +static GHashTable *accounts_name_1_0 = NULL;
 +
 +static void
 +imap_folder_info_1_0_free (struct _imap_folder_info_1_0 *fi)
 +{
 +	g_free(fi->folder);
 +	g_free(fi);
 +}
 +
 +static void
 +account_info_1_0_free (struct _account_info_1_0 *ai)
 +{
 +	g_free(ai->name);
 +	g_free(ai->uri);
 +	g_free(ai->base_uri);
 +	g_free(ai->u.imap.namespace);
 +	g_free(ai->u.imap.namespace_full);
 +	g_hash_table_destroy(ai->u.imap.folders);
 +	g_free(ai);
 +}
 +
 +static char *
 +get_base_uri(const char *val)
 +{
 +	const char *tmp;
 +
 +	tmp = strchr(val, ':');
 +	if (tmp) {
 +		tmp++;
 +		if (strncmp(tmp, "//", 2) == 0)
 +			tmp += 2;
 +		tmp = strchr(tmp, '/');
 +	}
 +
 +	if (tmp)
 +		return g_strndup(val, tmp-val);
 +	else
 +		return g_strdup(val);
 +}
 +
 +static char *
 +upgrade_xml_uris_1_0 (const char *uri)
 +{
 +	char *out = NULL;
 +
 +	/* upgrades camel uri's */
 +	if (strncmp (uri, "imap:", 5) == 0) {
 +		char *base_uri, dir_sep, *folder, *p;
 +		struct _account_info_1_0 *ai;
 +
 +		/* add namespace, canonicalise dir_sep to / */
 +		base_uri = get_base_uri (uri);
 +		ai = g_hash_table_lookup (accounts_1_0, base_uri);
 +
 +		if (ai == NULL) {
 +			g_free (base_uri);
 +			return NULL;
 +		}
 +
 +		dir_sep = ai->u.imap.dir_sep;
 +		if (dir_sep == 0) {
 +			/* no dir_sep listed, try get it from the namespace, if set */
 +			if (ai->u.imap.namespace != NULL) {
 +				p = ai->u.imap.namespace;
 +				while ((dir_sep = *p++)) {
 +					if (dir_sep < '0'
 +					    || (dir_sep > '9' && dir_sep < 'A')
 +					    || (dir_sep > 'Z' && dir_sep < 'a')
 +					    || (dir_sep > 'z')) {
 +						break;
 +					}
 +					p++;
 +				}
 +			}
 +
 +			/* give up ... */
 +			if (dir_sep == 0) {
 +				g_free (base_uri);
 +				return NULL;
 +			}
 +		}
 +
 +		folder = g_strdup (uri + strlen (base_uri) + 1);
 +
 +		/* Add the namespace before the mailbox name, unless the mailbox is INBOX */
 +		if (ai->u.imap.namespace && strcmp ((char *)folder, "INBOX") != 0)
 +			out = g_strdup_printf ("%s/%s/%s", base_uri, ai->u.imap.namespace, folder);
 +		else
 +			out = g_strdup_printf ("%s/%s", base_uri, folder);
 +
 +		p = out;
 +		while (*p) {
 +			if (*p == dir_sep)
 +				*p = '/';
 +			p++;
 +		}
 +
 +		g_free (folder);
 +		g_free (base_uri);
 +	} else if (strncmp (uri, "exchange:", 9) == 0) {
 +		char *base_uri, *folder, *p;
 +
 +		/*  exchange://user host/exchange/ * -> exchange://user host/personal/ * */
 +		/*  Any url encoding (%xx) in the folder name is also removed */
 +		base_uri = get_base_uri (uri);
 +		uri += strlen (base_uri) + 1;
 +		if (strncmp (uri, "exchange/", 9) == 0) {
 +			folder = e_bconf_url_decode (uri + 9);
 +			p = strchr (folder, '/');
 +			out = g_strdup_printf ("%s/personal%s", base_uri, p ? p : "/");
 +			g_free (folder);
 +		}
 +	} else if (strncmp (uri, "exchanget:", 10) == 0) {
 +		/* these should be converted in the accounts table when it is loaded */
 +		g_warning ("exchanget: uri not converted: '%s'", uri);
 +	}
 +
 +	return out;
 +}
 +
 +static char *
 +parse_lsub (const char *lsub, char *dir_sep)
 +{
 +	static int comp;
 +	static regex_t pat;
 +	regmatch_t match[3];
- 	char *m = "^\\* LSUB \\([^)]*\\) \"?([^\" ]+)\"? \"?(.*)\"?$";
++	const gchar *m = "^\\* LSUB \\([^)]*\\) \"?([^\" ]+)\"? \"?(.*)\"?$";
 +
 +	if (!comp) {
 +		if (regcomp (&pat, m, REG_EXTENDED|REG_ICASE) == -1) {
 +			g_warning ("reg comp '%s' failed: %s", m, g_strerror (errno));
 +			return NULL;
 +		}
 +		comp = 1;
 +	}
 +
 +	if (regexec (&pat, lsub, 3, match, 0) == 0) {
 +		if (match[1].rm_so != -1 && match[2].rm_so != -1) {
 +			if (dir_sep)
 +				*dir_sep = (match[1].rm_eo - match[1].rm_so == 1) ? lsub[match[1].rm_so] : 0;
 +			return g_strndup (lsub + match[2].rm_so, match[2].rm_eo - match[2].rm_so);
 +		}
 +	}
 +
 +	return NULL;
 +}
 +
 +static gboolean
 +read_imap_storeinfo (struct _account_info_1_0 *si)
 +{
 +	FILE *storeinfo;
 +	guint32 tmp;
 +	char *buf, *folder, dir_sep, *path, *name, *p;
 +	struct _imap_folder_info_1_0 *fi;
 +
 +	si->u.imap.folders = g_hash_table_new_full (
 +		g_str_hash, g_str_equal,
 +		(GDestroyNotify) NULL,
 +		(GDestroyNotify) imap_folder_info_1_0_free);
 +
 +	/* get details from uri first */
 +	name = strstr (si->uri, ";override_namespace");
 +	if (name) {
 +		name = strstr (si->uri, ";namespace=");
 +		if (name) {
 +			char *end;
 +
 +			name += strlen (";namespace=");
 +			if (*name == '\"') {
 +				name++;
 +				end = strchr (name, '\"');
 +			} else {
 +				end = strchr (name, ';');
 +			}
 +
 +			if (end) {
 +				/* try get the dir_sep from the namespace */
 +				si->u.imap.namespace = g_strndup (name, end-name);
 +
 +				p = si->u.imap.namespace;
 +				while ((dir_sep = *p++)) {
 +					if (dir_sep < '0'
 +					    || (dir_sep > '9' && dir_sep < 'A')
 +					    || (dir_sep > 'Z' && dir_sep < 'a')
 +					    || (dir_sep > 'z')) {
 +						si->u.imap.dir_sep = dir_sep;
 +						break;
 +					}
 +					p++;
 +				}
 +			}
 +		}
 +	}
 +
 +	/* now load storeinfo if it exists */
 +	path = g_build_filename (g_get_home_dir (), "evolution", "mail", "imap", si->base_uri + 7, "storeinfo", NULL);
 +	storeinfo = fopen (path, "r");
 +	g_free (path);
 +	if (storeinfo == NULL) {
 +		g_warning ("could not find imap store info '%s'", path);
 +		return FALSE;
 +	}
 +
 +	/* ignore version */
 +	camel_file_util_decode_uint32 (storeinfo, &tmp);
 +	camel_file_util_decode_uint32 (storeinfo, &si->u.imap.capabilities);
 +	g_free (si->u.imap.namespace);
 +	camel_file_util_decode_string (storeinfo, &si->u.imap.namespace);
 +	camel_file_util_decode_uint32 (storeinfo, &tmp);
 +	si->u.imap.dir_sep = tmp;
 +	/* strip trailing dir_sep or / */
 +	if (si->u.imap.namespace
 +	    && (si->u.imap.namespace[strlen (si->u.imap.namespace) - 1] == si->u.imap.dir_sep
 +		|| si->u.imap.namespace[strlen (si->u.imap.namespace) - 1] == '/')) {
 +		si->u.imap.namespace[strlen (si->u.imap.namespace) - 1] = 0;
 +	}
 +
 +	d(printf ("namespace '%s' dir_sep '%c'\n", si->u.imap.namespace, si->u.imap.dir_sep ? si->u.imap.dir_sep : '?'));
 +
 +	while (camel_file_util_decode_string (storeinfo, &buf) == 0) {
 +		folder = parse_lsub (buf, &dir_sep);
 +		if (folder) {
 +			fi = g_new0 (struct _imap_folder_info_1_0, 1);
 +			fi->folder = folder;
 +			fi->dir_sep = dir_sep;
 +#if d(!)0
 +			printf (" add folder '%s' ", folder);
 +			if (dir_sep)
 +				printf ("'%c'\n", dir_sep);
 +			else
 +				printf ("NIL\n");
 +#endif
 +			g_hash_table_insert (si->u.imap.folders, fi->folder, fi);
 +		} else {
 +			g_warning ("Could not parse LIST result '%s'\n", buf);
 +		}
 +	}
 +
 +	fclose (storeinfo);
 +
 +	return TRUE;
 +}
 +
 +static gboolean
 +load_accounts_1_0 (xmlDocPtr doc)
 +{
 +	xmlNodePtr source;
 +	char *val, *tmp;
 +	int count = 0, i;
 +	char key[32];
 +
 +	if (!(source = e_bconf_get_path (doc, "/Mail/Accounts")))
 +		return TRUE;
 +
 +	if ((val = e_bconf_get_value (source, "num"))) {
 +		count = atoi (val);
 +		xmlFree (val);
 +	}
 +
 +	/* load account upgrade info for each account */
 +	for (i = 0; i < count; i++) {
 +		struct _account_info_1_0 *ai;
 +		char *rawuri;
 +
 +		sprintf (key, "source_url_%d", i);
 +		if (!(rawuri = e_bconf_get_value (source, key)))
 +			continue;
 +
 +		ai = g_malloc0 (sizeof (struct _account_info_1_0));
 +		ai->uri = e_bconf_hex_decode (rawuri);
 +		ai->base_uri = get_base_uri (ai->uri);
 +		sprintf (key, "account_name_%d", i);
 +		ai->name = e_bconf_get_string (source, key);
 +
 +		d(printf("load account '%s'\n", ai->uri));
 +
 +		if (!strncmp (ai->uri, "imap:", 5)) {
 +			read_imap_storeinfo (ai);
 +		} else if (!strncmp (ai->uri, "exchange:", 9)) {
 +			xmlNodePtr node;
 +
 +			d(printf (" upgrade exchange account\n"));
 +			/* small hack, poke the source_url into the transport_url for exchanget: transports
 +			   - this will be picked up later in the conversion */
 +			sprintf (key, "transport_url_%d", i);
 +			node = e_bconf_get_entry (source, key);
 +			if (node && (val = (char *)xmlGetProp (node, (const unsigned char *)"value"))) {
 +				tmp = e_bconf_hex_decode (val);
 +				xmlFree (val);
 +				if (strncmp (tmp, "exchanget:", 10) == 0)
 +					xmlSetProp (node, (const unsigned char *)"value", (unsigned char *)rawuri);
 +				g_free (tmp);
 +			} else {
 +				d(printf (" couldn't find transport uri?\n"));
 +			}
 +		}
 +		xmlFree (rawuri);
 +
 +		g_hash_table_insert (accounts_1_0, ai->base_uri, ai);
 +		if (ai->name)
 +			g_hash_table_insert (accounts_name_1_0, ai->name, ai);
 +	}
 +
 +	return TRUE;
 +}
 +
 +static gboolean
 +em_migrate_1_0 (const char *data_dir, xmlDocPtr config_xmldb, xmlDocPtr filters, xmlDocPtr vfolders, GError **error)
 +{
 +	accounts_1_0 = g_hash_table_new_full (
 +		g_str_hash, g_str_equal,
 +		(GDestroyNotify) NULL,
 +		(GDestroyNotify) account_info_1_0_free);
 +	accounts_name_1_0 = g_hash_table_new (g_str_hash, g_str_equal);
 +	load_accounts_1_0 (config_xmldb);
 +
 +	upgrade_xml_uris(filters, upgrade_xml_uris_1_0);
 +	upgrade_xml_uris(vfolders, upgrade_xml_uris_1_0);
 +
 +	g_hash_table_destroy (accounts_1_0);
 +	g_hash_table_destroy (accounts_name_1_0);
 +
 +	return TRUE;
 +}
 +
 +/* 1.2 upgrade functions */
 +static gboolean
 +is_xml1encoded (const char *txt)
 +{
 +	const unsigned char *p;
 +	int isxml1 = FALSE;
 +	int is8bit = FALSE;
 +
 +	p = (const unsigned char *)txt;
 +	while (*p) {
 +		if (p[0] == '\\' && p[1] == 'U' && p[2] == '+'
 +		    && isxdigit (p[3]) && isxdigit (p[4]) && isxdigit (p[5]) && isxdigit (p[6])
 +		    && p[7] == '\\') {
 +			isxml1 = TRUE;
 +			p+=7;
 +		} else if (p[0] >= 0x80)
 +			is8bit = TRUE;
 +		p++;
 +	}
 +
 +	/* check for invalid utf8 that needs cleaning */
 +	if (is8bit && !isxml1)
 +		isxml1 = !g_utf8_validate (txt, -1, NULL);
 +
 +	return isxml1;
 +}
 +
 +static char *
 +decode_xml1 (const char *txt)
 +{
 +	GString *out = g_string_new ("");
 +	const unsigned char *p;
 +	char *res;
 +
 +	/* convert:
 +	   \U+XXXX\ -> utf8
 +	   8 bit characters -> utf8 (iso-8859-1) */
 +
 +	p = (const unsigned char *) txt;
 +	while (*p) {
 +		if (p[0] > 0x80
 +		    || (p[0] == '\\' && p[1] == 'U' && p[2] == '+'
 +			&& isxdigit (p[3]) && isxdigit (p[4]) && isxdigit (p[5]) && isxdigit (p[6])
 +			&& p[7] == '\\')) {
 +			char utf8[8];
 +			gunichar u;
 +
 +			if (p[0] == '\\') {
 +				memcpy (utf8, p + 3, 4);
 +				utf8[4] = 0;
 +				u = strtoul (utf8, NULL, 16);
 +				p+=7;
 +			} else
 +				u = p[0];
 +			utf8[g_unichar_to_utf8 (u, utf8)] = 0;
 +			g_string_append (out, utf8);
 +		} else {
 +			g_string_append_c (out, *p);
 +		}
 +		p++;
 +	}
 +
 +	res = out->str;
 +	g_string_free (out, FALSE);
 +
 +	return res;
 +}
 +
 +static char *
 +utf8_reencode (const char *txt)
 +{
 +	GString *out = g_string_new ("");
 +	gchar *p;
 +	char *res;
 +
 +	/* convert:
 +        libxml1  8 bit utf8 converted to xml entities byte-by-byte chars -> utf8 */
 +
 +	p =  (gchar *)txt;
 +
 +	while (*p) {
 +		g_string_append_c (out, (gchar)g_utf8_get_char ((const gchar *)p));
 +		p = (gchar *)g_utf8_next_char (p);
 +	}
 +
 +	res = out->str;
 +	if (g_utf8_validate (res, -1, NULL)) {
 +		g_string_free (out, FALSE);
 +		return res;
 +	} else {
 +		g_string_free (out, TRUE);
 +		return g_strdup (txt);
 +	}
 +}
 +
 +static gboolean
 +upgrade_xml_1_2_rec (xmlNodePtr node)
 +{
 +	const char *value_tags[] = { "string", "address", "regex", "file", "command", NULL };
 +	const char *rule_tags[] = { "title", NULL };
 +	const char *item_props[] = { "name", NULL };
 +	struct {
 +		const char *name;
 +		const char **tags;
 +		const char **props;
 +	} tags[] = {
 +		{ "value", value_tags, NULL },
 +		{ "rule", rule_tags, NULL },
 +		{ "item", NULL, item_props },
 +		{ 0 },
 +	};
 +	xmlNodePtr work;
 +	int i,j;
 +	char *txt, *tmp;
 +
 +	/* upgrades the content of a node, if the node has a specific parent/node name */
 +
 +	for (i = 0; tags[i].name; i++) {
 +		if (!strcmp ((char *)node->name, tags[i].name)) {
 +			if (tags[i].tags != NULL) {
 +				work = node->children;
 +				while (work) {
 +					for (j = 0; tags[i].tags[j]; j++) {
 +						if (!strcmp ((char *)work->name, tags[i].tags[j])) {
 +							txt = (char *)xmlNodeGetContent (work);
 +							if (is_xml1encoded (txt)) {
 +								tmp = decode_xml1 (txt);
 +								d(printf ("upgrading xml node %s/%s '%s' -> '%s'\n",
 +									  tags[i].name, tags[i].tags[j], txt, tmp));
 +								xmlNodeSetContent (work, (unsigned char *)tmp);
 +								g_free (tmp);
 +							}
 +							xmlFree (txt);
 +						}
 +					}
 +					work = work->next;
 +				}
 +				break;
 +			}
 +
 +			if (tags[i].props != NULL) {
 +				for (j = 0; tags[i].props[j]; j++) {
 +					txt = (char *)xmlGetProp (node, (unsigned char *)tags[i].props[j]);
 +					tmp = utf8_reencode (txt);
 +					d(printf ("upgrading xml property %s on node %s '%s' -> '%s'\n",
 +						  tags[i].props[j], tags[i].name, txt, tmp));
 +					xmlSetProp (node, (const unsigned char *)tags[i].props[j], (unsigned char *)tmp);
 +					g_free (tmp);
 +					xmlFree (txt);
 +				}
 +			}
 +		}
 +	}
 +
 +	node = node->children;
 +	while (node) {
 +		upgrade_xml_1_2_rec (node);
 +		node = node->next;
 +	}
 +
 +	return TRUE;
 +}
 +
 +static gboolean
 +em_upgrade_xml_1_2 (xmlDocPtr doc)
 +{
 +	xmlNodePtr root;
 +
 +	if (!doc || !(root = xmlDocGetRootElement (doc)))
 +		return TRUE;
 +
 +	return upgrade_xml_1_2_rec (root);
 +}
 +
 +/* ********************************************************************** */
 +/*  Tables for converting flat bonobo conf -> gconf xml blob		  */
 +/* ********************************************************************** */
 +
 +/* Mail/Accounts/ * */
 +static e_bconf_map_t cc_map[] = {
 +	{ "account_always_cc_%i", "always", E_BCONF_MAP_BOOL },
 +	{ "account_always_cc_addrs_%i", "recipients", E_BCONF_MAP_STRING|E_BCONF_MAP_CONTENT },
 +	{ NULL },
 +};
 +
 +static e_bconf_map_t bcc_map[] = {
 +	{ "account_always_cc_%i", "always", E_BCONF_MAP_BOOL },
 +	{ "account_always_bcc_addrs_%i", "recipients", E_BCONF_MAP_STRING|E_BCONF_MAP_CONTENT },
 +	{ NULL },
 +};
 +
 +static e_bconf_map_t pgp_map[] = {
 +	{ "account_pgp_encrypt_to_self_%i", "encrypt-to-self", E_BCONF_MAP_BOOL },
 +	{ "account_pgp_always_trust_%i", "always-trust", E_BCONF_MAP_BOOL },
 +	{ "account_pgp_always_sign_%i", "always-sign", E_BCONF_MAP_BOOL },
 +	{ "account_pgp_no_imip_sign_%i", "no-imip-sign", E_BCONF_MAP_BOOL },
 +	{ "account_pgp_key_%i", "key-id", E_BCONF_MAP_STRING|E_BCONF_MAP_CONTENT },
 +	{ NULL },
 +};
 +
 +static e_bconf_map_t smime_map[] = {
 +	{ "account_smime_encrypt_to_self_%i", "encrypt-to-self", E_BCONF_MAP_BOOL },
 +	{ "account_smime_always_sign_%i", "always-sign", E_BCONF_MAP_BOOL },
 +	{ "account_smime_key_%i", "key-id", E_BCONF_MAP_STRING|E_BCONF_MAP_CONTENT },
 +	{ NULL },
 +};
 +
 +static e_bconf_map_t identity_sig_map[] = {
 +	{ "identity_autogenerated_signature_%i", "auto", E_BCONF_MAP_BOOL },
 +	{ "identity_def_signature_%i", "default", E_BCONF_MAP_LONG },
 +	{ NULL },
 +};
 +
 +static e_bconf_map_t identity_map[] = {
 +	{ "identity_name_%i", "name", E_BCONF_MAP_STRING|E_BCONF_MAP_CONTENT },
 +	{ "identity_address_%i", "addr-spec", E_BCONF_MAP_STRING|E_BCONF_MAP_CONTENT },
 +	{ "identity_reply_to_%i", "reply-to", E_BCONF_MAP_STRING|E_BCONF_MAP_CONTENT },
 +	{ "identity_organization_%i", "organization", E_BCONF_MAP_STRING|E_BCONF_MAP_CONTENT },
 +	{ NULL, "signature", E_BCONF_MAP_CHILD, identity_sig_map },
 +	{ NULL },
 +};
 +
 +static e_bconf_map_t source_map[] = {
 +	{ "source_save_passwd_%i", "save-passwd", E_BCONF_MAP_BOOL },
 +	{ "source_keep_on_server_%i", "keep-on-server", E_BCONF_MAP_BOOL },
 +	{ "source_auto_check_%i", "auto-check", E_BCONF_MAP_BOOL },
 +	{ "source_auto_check_time_%i", "auto-check-timeout", E_BCONF_MAP_LONG },
 +	{ "source_url_%i", "url", E_BCONF_MAP_STRING|E_BCONF_MAP_CONTENT },
 +	{ NULL },
 +};
 +
 +static e_bconf_map_t transport_map[] = {
 +	{ "transport_save_passwd_%i", "save-passwd", E_BCONF_MAP_BOOL },
 +	{ "transport_url_%i", "url", E_BCONF_MAP_STRING|E_BCONF_MAP_CONTENT },
 +	{ NULL },
 +};
 +
 +static e_bconf_map_t account_map[] = {
 +	{ "account_name_%i", "name", E_BCONF_MAP_STRING },
 +	{ "source_enabled_%i", "enabled", E_BCONF_MAP_BOOL },
 +	{ NULL, "identity", E_BCONF_MAP_CHILD, identity_map },
 +	{ NULL, "source", E_BCONF_MAP_CHILD, source_map },
 +	{ NULL, "transport", E_BCONF_MAP_CHILD, transport_map },
 +	{ "account_drafts_folder_uri_%i", "drafts-folder", E_BCONF_MAP_STRING|E_BCONF_MAP_CONTENT },
 +	{ "account_sent_folder_uri_%i", "sent-folder", E_BCONF_MAP_STRING|E_BCONF_MAP_CONTENT },
 +	{ NULL, "auto-cc", E_BCONF_MAP_CHILD, cc_map },
 +	{ NULL, "auto-bcc", E_BCONF_MAP_CHILD, bcc_map },
 +	{ NULL, "pgp", E_BCONF_MAP_CHILD, pgp_map },
 +	{ NULL, "smime", E_BCONF_MAP_CHILD, smime_map },
 +	{ NULL },
 +};
 +
 +/* /Mail/Signatures/ * */
 +static e_bconf_map_t signature_format_map[] = {
 +	{ "text/plain", },
 +	{ "text/html", },
 +	{ NULL }
 +};
 +
 +static e_bconf_map_t signature_map[] = {
 +	{ "name_%i", "name", E_BCONF_MAP_STRING },
 +	{ "html_%i", "format", E_BCONF_MAP_ENUM, signature_format_map },
 +	{ "filename_%i", "filename", E_BCONF_MAP_STRING|E_BCONF_MAP_CONTENT },
 +	{ "script_%i", "script", E_BCONF_MAP_STRING|E_BCONF_MAP_CONTENT },
 +	{ NULL },
 +};
 +
 +/* ********************************************************************** */
 +/*  Tables for bonobo conf -> gconf conversion				  */
 +/* ********************************************************************** */
 +
 +static e_gconf_map_t mail_accounts_map[] = {
 +	/* /Mail/Accounts - most entries are processed via the xml blob routine */
 +	/* This also works because the initial uid mapping is 1:1 with the list order */
 +	{ "default_account", "mail/default_account", E_GCONF_MAP_SIMPLESTRING },
 +	{ 0 },
 +};
 +
 +static e_gconf_map_t mail_display_map[] = {
 +	/* /Mail/Display */
 +	{ "side_bar_search", "mail/display/side_bar_search", E_GCONF_MAP_BOOL },
 +	{ "thread_list", "mail/display/thread_list", E_GCONF_MAP_BOOL },
 +	{ "thread_subject", "mail/display/thread_subject", E_GCONF_MAP_BOOL },
 +	{ "hide_deleted", "mail/display/show_deleted", E_GCONF_MAP_BOOLNOT },
 +	{ "preview_pane", "mail/display/show_preview", E_GCONF_MAP_BOOL },
 +	{ "paned_size", "mail/display/paned_size", E_GCONF_MAP_INT },
 +	{ "seen_timeout", "mail/display/mark_seen_timeout", E_GCONF_MAP_INT },
 +	{ "do_seen_timeout", "mail/display/mark_seen", E_GCONF_MAP_BOOL },
 +	{ "http_images", "mail/display/load_http_images", E_GCONF_MAP_INT },
 +	{ "citation_highlight", "mail/display/mark_citations", E_GCONF_MAP_BOOL },
 +	{ "citation_color", "mail/display/citation_colour", E_GCONF_MAP_COLOUR },
 +	{ 0 },
 +};
 +
 +static e_gconf_map_t mail_format_map[] = {
 +	/* /Mail/Format */
 +	{ "message_display_style", "mail/display/message_style", E_GCONF_MAP_INT },
 +	{ "send_html", "mail/composer/send_html", E_GCONF_MAP_BOOL },
 +	{ "default_reply_style", "mail/format/reply_style", E_GCONF_MAP_INT },
 +	{ "default_forward_style", "mail/format/forward_style", E_GCONF_MAP_INT },
 +	{ "default_charset", "mail/composer/charset", E_GCONF_MAP_STRING },
 +	{ "confirm_unwanted_html", "mail/prompts/unwanted_html", E_GCONF_MAP_BOOL },
 +	{ 0 },
 +};
 +
 +static e_gconf_map_t mail_trash_map[] = {
 +	/* /Mail/Trash */
 +	{ "empty_on_exit", "mail/trash/empty_on_exit", E_GCONF_MAP_BOOL },
 +	{ 0 },
 +};
 +
 +static e_gconf_map_t mail_prompts_map[] = {
 +	/* /Mail/Prompts */
 +	{ "confirm_expunge", "mail/prompts/expunge", E_GCONF_MAP_BOOL },
 +	{ "empty_subject", "mail/prompts/empty_subject", E_GCONF_MAP_BOOL },
 +	{ "only_bcc", "mail/prompts/only_bcc", E_GCONF_MAP_BOOL },
 +	{ 0 }
 +};
 +
 +static e_gconf_map_t mail_filters_map[] = {
 +	/* /Mail/Filters */
 +	{ "log", "mail/filters/log", E_GCONF_MAP_BOOL },
 +	{ "log_path", "mail/filters/logfile", E_GCONF_MAP_STRING },
 +	{ 0 }
 +};
 +
 +static e_gconf_map_t mail_notify_map[] = {
 +	/* /Mail/Notify */
 +	{ "new_mail_notification", "mail/notify/type", E_GCONF_MAP_INT },
 +	{ "new_mail_notification_sound_file", "mail/notify/sound", E_GCONF_MAP_STRING },
 +	{ 0 }
 +};
 +
 +static e_gconf_map_t mail_filesel_map[] = {
 +	/* /Mail/Filesel */
 +	{ "last_filesel_dir", "mail/save_dir", E_GCONF_MAP_STRING },
 +	{ 0 }
 +};
 +
 +static e_gconf_map_t mail_composer_map[] = {
 +	/* /Mail/Composer */
 +	{ "ViewFrom", "mail/composer/view/From", E_GCONF_MAP_BOOL },
 +	{ "ViewReplyTo", "mail/composer/view/ReplyTo", E_GCONF_MAP_BOOL },
 +	{ "ViewCC", "mail/composer/view/Cc", E_GCONF_MAP_BOOL },
 +	{ "ViewBCC", "mail/composer/view/Bcc", E_GCONF_MAP_BOOL },
 +	{ "ViewSubject", "mail/composer/view/Subject", E_GCONF_MAP_BOOL },
 +	{ 0 },
 +};
 +
 +/* ********************************************************************** */
 +
 +static e_gconf_map_t importer_elm_map[] = {
 +	/* /Importer/Elm */
 +	{ "mail", "importer/elm/mail", E_GCONF_MAP_BOOL },
 +	{ "mail-imported", "importer/elm/mail-imported", E_GCONF_MAP_BOOL },
 +	{ 0 },
 +};
 +
 +static e_gconf_map_t importer_pine_map[] = {
 +	/* /Importer/Pine */
 +	{ "mail", "importer/elm/mail", E_GCONF_MAP_BOOL },
 +	{ "address", "importer/elm/address", E_GCONF_MAP_BOOL },
 +	{ 0 },
 +};
 +
 +static e_gconf_map_t importer_netscape_map[] = {
 +	/* /Importer/Netscape */
 +	{ "mail", "importer/netscape/mail", E_GCONF_MAP_BOOL },
 +	{ "settings", "importer/netscape/settings", E_GCONF_MAP_BOOL },
 +	{ "filters", "importer/netscape/filters", E_GCONF_MAP_BOOL },
 +	{ 0 },
 +};
 +
 +/* ********************************************************************** */
 +
 +static e_gconf_map_list_t gconf_remap_list[] = {
 +	{ "/Mail/Accounts", mail_accounts_map },
 +	{ "/Mail/Display", mail_display_map },
 +	{ "/Mail/Format", mail_format_map },
 +	{ "/Mail/Trash", mail_trash_map },
 +	{ "/Mail/Prompts", mail_prompts_map },
 +	{ "/Mail/Filters", mail_filters_map },
 +	{ "/Mail/Notify", mail_notify_map },
 +	{ "/Mail/Filesel", mail_filesel_map },
 +	{ "/Mail/Composer", mail_composer_map },
 +
 +	{ "/Importer/Elm", importer_elm_map },
 +	{ "/Importer/Pine", importer_pine_map },
 +	{ "/Importer/Netscape", importer_netscape_map },
 +
 +	{ 0 },
 +};
 +
 +static struct {
- 	char *label;
- 	char *colour;
++	const gchar *label;
++	const gchar *colour;
 +} label_default[5] = {
 +	{ N_("Important"), "#EF2929" },  /* red */
 +	{ N_("Work"),      "#F57900" },  /* orange */
 +	{ N_("Personal"),  "#4E9A06" },  /* green */
 +	{ N_("To Do"),     "#3465A4" },  /* blue */
 +	{ N_("Later"),     "#75507B" }   /* purple */
 +};
 +
 +/* remaps mail config from bconf to gconf */
 +static gboolean
 +bconf_import(GConfClient *gconf, xmlDocPtr config_xmldb)
 +{
 +	xmlNodePtr source;
 +	char labx[16], colx[16];
 +	char *val, *lab, *col;
 +	GSList *list, *l;
 +	int i;
 +
 +	e_bconf_import(gconf, config_xmldb, gconf_remap_list);
 +
 +	/* Labels:
 +	   label string + label colour as integer
 +	   -> label string:# colour as hex */
 +	source = e_bconf_get_path(config_xmldb, "/Mail/Labels");
 +	if (source) {
 +		list = NULL;
 +		for (i = 0; i < 5; i++) {
 +			sprintf(labx, "label_%d", i);
 +			sprintf(colx, "color_%d", i);
 +			lab = e_bconf_get_string(source, labx);
 +			if ((col = e_bconf_get_value(source, colx))) {
 +				sprintf(colx, "#%06x", atoi(col) & 0xffffff);
 +				g_free(col);
 +			} else
 +				strcpy(colx, label_default[i].colour);
 +
 +			val = g_strdup_printf("%s:%s", lab ? lab : label_default[i].label, colx);
 +			list = g_slist_append(list, val);
 +			g_free(lab);
 +		}
 +
 +		gconf_client_set_list(gconf, "/apps/evolution/mail/labels", GCONF_VALUE_STRING, list, NULL);
 +		while (list) {
 +			l = list->next;
 +			g_free(list->data);
 +			g_slist_free_1(list);
 +			list = l;
 +		}
 +	} else {
 +		g_warning("could not find /Mail/Labels in old config database, skipping");
 +	}
 +
 +	/* Accounts: The flat bonobo-config structure is remapped to a list of xml blobs.  Upgrades as necessary */
 +	e_bconf_import_xml_blob(gconf, config_xmldb, account_map, "/Mail/Accounts",
 +				"/apps/evolution/mail/accounts", "account", "uid");
 +
 +	/* Same for signatures */
 +	e_bconf_import_xml_blob(gconf, config_xmldb, signature_map, "/Mail/Signatures",
 +				"/apps/evolution/mail/signatures", "signature", NULL);
 +
 +	return TRUE;
 +}
 +
 +static gboolean
 +em_migrate_1_2(const char *data_dir, xmlDocPtr config_xmldb, xmlDocPtr filters, xmlDocPtr vfolders, GError **error)
 +{
 +	GConfClient *gconf;
 +
 +	gconf = gconf_client_get_default();
 +	bconf_import(gconf, config_xmldb);
 +	g_object_unref(gconf);
 +
 +	em_upgrade_xml_1_2(filters);
 +	em_upgrade_xml_1_2(vfolders);
 +
 +	return TRUE;
 +}
 +
 +/* 1.4 upgrade functions */
 +
 +#define EM_MIGRATE_SESSION_TYPE     (em_migrate_session_get_type ())
 +#define EM_MIGRATE_SESSION(obj)     (CAMEL_CHECK_CAST((obj), EM_MIGRATE_SESSION_TYPE, EMMigrateSession))
 +#define EM_MIGRATE_SESSION_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), EM_MIGRATE_SESSION_TYPE, EMMigrateSessionClass))
 +#define EM_MIGRATE_IS_SESSION(o)    (CAMEL_CHECK_TYPE((o), EM_MIGRATE_SESSION_TYPE))
 +
 +typedef struct _EMMigrateSession {
 +	CamelSession parent_object;
 +
 +	CamelStore *store;   /* new folder tree store */
 +	char *srcdir;        /* old folder tree path */
 +} EMMigrateSession;
 +
 +typedef struct _EMMigrateSessionClass {
 +	CamelSessionClass parent_class;
 +
 +} EMMigrateSessionClass;
 +
 +static CamelType em_migrate_session_get_type (void);
 +static CamelSession *em_migrate_session_new (const char *path);
 +
 +static void
 +class_init (EMMigrateSessionClass *klass)
 +{
 +	;
 +}
 +
 +static CamelType
 +em_migrate_session_get_type (void)
 +{
 +	static CamelType type = CAMEL_INVALID_TYPE;
 +
 +	if (type == CAMEL_INVALID_TYPE) {
 +		type = camel_type_register (
 +			camel_session_get_type (),
 +			"EMMigrateSession",
 +			sizeof (EMMigrateSession),
 +			sizeof (EMMigrateSessionClass),
 +			(CamelObjectClassInitFunc) class_init,
 +			NULL,
 +			NULL,
 +			NULL);
 +	}
 +
 +	return type;
 +}
 +
 +static CamelSession *
 +em_migrate_session_new (const char *path)
 +{
 +	CamelSession *session;
 +
 +	session = CAMEL_SESSION (camel_object_new (EM_MIGRATE_SESSION_TYPE));
 +
 +	camel_session_construct (session, path);
 +
 +	return session;
 +}
 +
 +
 +#endif	/* !G_OS_WIN32 */
 +
 +static GtkWidget *window;
 +static GtkLabel *label;
 +static GtkProgressBar *progress;
 +
 +static void
- em_migrate_setup_progress_dialog (const char *desc)
++em_migrate_setup_progress_dialog (const char *title, const char *desc)
 +{
 +	GtkWidget *vbox, *hbox, *w;
++	gchar *markup;
 +
 +	window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 +	gtk_window_set_title ((GtkWindow *) window, _("Migrating..."));
 +	gtk_window_set_modal ((GtkWindow *) window, TRUE);
 +	gtk_container_set_border_width ((GtkContainer *) window, 6);
 +
 +	vbox = gtk_vbox_new (FALSE, 6);
 +	gtk_widget_show (vbox);
 +	gtk_container_add ((GtkContainer *) window, vbox);
 +
 +	w = gtk_label_new (desc);
 +
 +	gtk_label_set_line_wrap ((GtkLabel *) w, TRUE);
 +	gtk_widget_show (w);
 +	gtk_box_pack_start_defaults ((GtkBox *) vbox, w);
 +
 +	hbox = gtk_hbox_new (FALSE, 6);
 +	gtk_widget_show (hbox);
 +	gtk_box_pack_start_defaults ((GtkBox *) vbox, hbox);
 +
 +	label = (GtkLabel *) gtk_label_new ("");
 +	gtk_widget_show ((GtkWidget *) label);
 +	gtk_box_pack_start_defaults ((GtkBox *) hbox, (GtkWidget *) label);
 +
 +	progress = (GtkProgressBar *) gtk_progress_bar_new ();
 +	gtk_widget_show ((GtkWidget *) progress);
 +	gtk_box_pack_start_defaults ((GtkBox *) hbox, (GtkWidget *) progress);
 +
++	/* Prepare the message */
++	vbox = gtk_vbox_new (FALSE, 12);
++	gtk_widget_show (vbox);
++	gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
++
++	w = gtk_label_new (NULL);
++	gtk_misc_set_alignment (GTK_MISC (w), 0.0, 0.0);
++	markup = g_strconcat ("<big><b>", title ? title : _("Migration"), "</b></big>", NULL);
++	gtk_label_set_markup (GTK_LABEL (w), markup);
++	gtk_box_pack_start (GTK_BOX (vbox), w, TRUE, TRUE, 0);
++	g_free (markup);
++
++	w = gtk_label_new (desc);
++	gtk_misc_set_alignment (GTK_MISC (w), 0.0, 0.0);
++	gtk_label_set_line_wrap (GTK_LABEL (w), TRUE);
++	gtk_box_pack_start (GTK_BOX (vbox), w, TRUE, TRUE, 0);
++
++	/* Progress bar */
++	w = gtk_vbox_new (FALSE, 6);
++	gtk_box_pack_start (GTK_BOX (vbox), w, TRUE, TRUE, 0);
++
++	label = GTK_LABEL (gtk_label_new (""));
++	gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0);
++	gtk_label_set_line_wrap (label, TRUE);
++	gtk_widget_show (GTK_WIDGET (label));
++	gtk_box_pack_start (GTK_BOX (w), GTK_WIDGET (label), TRUE, TRUE, 0);
++
++	progress = GTK_PROGRESS_BAR (gtk_progress_bar_new ());
++	gtk_widget_show (GTK_WIDGET (progress));
++	gtk_box_pack_start (GTK_BOX (w), GTK_WIDGET (progress), TRUE, TRUE, 0);
++
++	gtk_container_add (GTK_CONTAINER (window), hbox);
++	gtk_widget_show_all (hbox);
 +	gtk_widget_show (window);
 +}
 +
 +static void
 +em_migrate_close_progress_dialog (void)
 +{
 +	gtk_widget_destroy ((GtkWidget *) window);
 +}
 +
 +static void
 +em_migrate_set_folder_name (const char *folder_name)
 +{
 +	char *text;
 +
 +	text = g_strdup_printf (_("Migrating '%s':"), folder_name);
 +	gtk_label_set_text (label, text);
 +	g_free (text);
 +
 +	gtk_progress_bar_set_fraction (progress, 0.0);
 +	while (gtk_events_pending ())
 +		gtk_main_iteration ();
 +}
 +
 +static void
 +em_migrate_set_progress (double percent)
 +{
 +	char text[5];
 +
 +	snprintf (text, sizeof (text), "%d%%", (int) (percent * 100.0f));
 +
 +	gtk_progress_bar_set_fraction (progress, percent);
 +	gtk_progress_bar_set_text (progress, text);
 +
 +	while (gtk_events_pending ())
 +		gtk_main_iteration ();
 +}
 +
 +#ifndef G_OS_WIN32
 +
 +static gboolean
 +is_mail_folder (const char *metadata)
 +{
 +	xmlNodePtr node;
 +	xmlDocPtr doc;
 +	char *type;
 +
 +	if (!(doc = xmlParseFile (metadata))) {
 +		g_warning ("Cannot parse `%s'", metadata);
 +		return FALSE;
 +	}
 +
 +	if (!(node = xmlDocGetRootElement (doc))) {
 +		g_warning ("`%s' corrupt: document contains no root node", metadata);
 +		xmlFreeDoc (doc);
 +		return FALSE;
 +	}
 +
 +	if (!node->name || strcmp ((char *)node->name, "efolder") != 0) {
 +		g_warning ("`%s' corrupt: root node is not 'efolder'", metadata);
 +		xmlFreeDoc (doc);
 +		return FALSE;
 +	}
 +
 +	node = node->children;
 +	while (node != NULL) {
 +		if (node->name && !strcmp ((char *)node->name, "type")) {
 +			type = (char *)xmlNodeGetContent (node);
 +			if (!strcmp ((char *)type, "mail")) {
 +				xmlFreeDoc (doc);
 +				xmlFree (type);
 +
 +				return TRUE;
 +			}
 +
 +			xmlFree (type);
 +
 +			break;
 +		}
 +
 +		node = node->next;
 +	}
 +
 +	xmlFreeDoc (doc);
 +
 +	return FALSE;
 +}
 +
 +static gboolean
 +get_local_et_expanded (const char *dirname)
 +{
 +	xmlNodePtr node;
 +	xmlDocPtr doc;
 +	struct stat st;
 +	char *buf, *p;
 +	int thread_list;
 +
 +	buf = g_strdup_printf ("%s/evolution/config/file:%s", g_get_home_dir (), dirname);
 +	p = buf + strlen (g_get_home_dir ()) + strlen ("/evolution/config/file:");
 +	e_filename_make_safe (p);
 +
 +	if (stat (buf, &st) == -1) {
 +		g_free (buf);
 +		return FALSE;
 +	}
 +
 +	if (!(doc = xmlParseFile (buf))) {
 +		g_free (buf);
 +		return FALSE;
 +	}
 +
 +	g_free (buf);
 +
 +	if (!(node = xmlDocGetRootElement (doc)) || strcmp ((char *)node->name, "expanded_state") != 0) {
 +		xmlFreeDoc (doc);
 +		return FALSE;
 +	}
 +
 +	if (!(buf = (char *)xmlGetProp (node, (const unsigned char *)"default"))) {
 +		xmlFreeDoc (doc);
 +		return FALSE;
 +	}
 +
 +	thread_list = strcmp (buf, "0") == 0 ? 0 : 1;
 +	xmlFree (buf);
 +
 +	xmlFreeDoc (doc);
 +
 +	return thread_list;
 +}
 +
 +static char *
 +get_local_store_uri (const char *dirname, char **namep, int *indexp)
 +{
- 	char *protocol, *name, *metadata, *tmp;
++	gchar *name, *protocol, *metadata, *tmp;
 +	int index;
 +	struct stat st;
 +	xmlNodePtr node;
 +	xmlDocPtr doc;
 +
 +	metadata = g_build_filename(dirname, "local-metadata.xml", NULL);
 +
 +	/* in 1.4, any errors are treated as defaults, this function cannot fail */
 +
 +	/* defaults */
- 	name = "mbox";
- 	protocol = "mbox";
++	name = (gchar *) "mbox";
++	protocol = (gchar *) "mbox";
 +	index = TRUE;
 +
 +	if (stat (metadata, &st) == -1 || !S_ISREG (st.st_mode))
 +		goto nofile;
 +
 +	doc = xmlParseFile(metadata);
 +	if (doc == NULL)
 +		goto nofile;
 +
 +	node = doc->children;
 +	if (strcmp((char *)node->name, "folderinfo"))
 +		goto dodefault;
 +
 +	for (node = node->children; node; node = node->next) {
 +		if (node->name && !strcmp ((char *)node->name, "folder")) {
 +			tmp = (char *)xmlGetProp (node, (const unsigned char *)"type");
 +			if (tmp) {
 +				protocol = alloca(strlen(tmp)+1);
 +				strcpy(protocol, tmp);
 +				xmlFree(tmp);
 +			}
 +			tmp = (char *)xmlGetProp (node, (const unsigned char *)"name");
 +			if (tmp) {
 +				name = alloca(strlen(tmp)+1);
 +				strcpy(name, tmp);
 +				xmlFree(tmp);
 +			}
 +			tmp = (char *)xmlGetProp (node, (const unsigned char *)"index");
 +			if (tmp) {
 +				index = atoi(tmp);
 +				xmlFree(tmp);
 +			}
 +		}
 +	}
 +dodefault:
 +	xmlFreeDoc (doc);
 +nofile:
 +	g_free(metadata);
 +
 +	*namep = g_strdup(name);
 +	*indexp = index;
 +
 +	return g_strdup_printf("%s:%s", protocol, dirname);
 +}
 +
 +#endif	/* !G_OS_WIN32 */
 +
 +enum {
 +	CP_UNIQUE = 0,
 +	CP_OVERWRITE,
 +	CP_APPEND
 +};
 +
 +static int open_flags[3] = {
 +	O_WRONLY | O_CREAT | O_TRUNC,
 +	O_WRONLY | O_CREAT | O_TRUNC,
 +	O_WRONLY | O_CREAT | O_APPEND,
 +};
 +
 +static gboolean
 +cp (const char *src, const char *dest, gboolean show_progress, int mode)
 +{
 +	unsigned char readbuf[65536];
 +	ssize_t nread, nwritten;
 +	int errnosav, readfd, writefd;
 +	size_t total = 0;
 +	struct stat st;
 +	struct utimbuf ut;
 +
 +	/* if the dest file exists and has content, abort - we don't
 +	 * want to corrupt their existing data */
 +	if (g_stat (dest, &st) == 0 && st.st_size > 0 && mode == CP_UNIQUE) {
 +		errno = EEXIST;
 +		return FALSE;
 +	}
 +
 +	if (g_stat (src, &st) == -1
 +	    || (readfd = g_open (src, O_RDONLY | O_BINARY, 0)) == -1)
 +		return FALSE;
 +
 +	if ((writefd = g_open (dest, open_flags[mode] | O_BINARY, 0666)) == -1) {
 +		errnosav = errno;
 +		close (readfd);
 +		errno = errnosav;
 +		return FALSE;
 +	}
 +
 +	do {
 +		do {
 +			nread = read (readfd, readbuf, sizeof (readbuf));
 +		} while (nread == -1 && errno == EINTR);
 +
 +		if (nread == 0)
 +			break;
 +		else if (nread < 0)
 +			goto exception;
 +
 +		do {
 +			nwritten = write (writefd, readbuf, nread);
 +		} while (nwritten == -1 && errno == EINTR);
 +
 +		if (nwritten < nread)
 +			goto exception;
 +
 +		total += nwritten;
 +		if (show_progress)
 +			em_migrate_set_progress (((double) total) / ((double) st.st_size));
 +	} while (total < st.st_size);
 +
 +	if (fsync (writefd) == -1)
 +		goto exception;
 +
 +	close (readfd);
 +	if (close (writefd) == -1)
 +		goto failclose;
 +
 +	ut.actime = st.st_atime;
 +	ut.modtime = st.st_mtime;
 +	utime (dest, &ut);
 +	chmod (dest, st.st_mode);
 +
 +	return TRUE;
 +
 + exception:
 +
 +	errnosav = errno;
 +	close (readfd);
 +	close (writefd);
 +	errno = errnosav;
 +
 + failclose:
 +
 +	errnosav = errno;
 +	unlink (dest);
 +	errno = errnosav;
 +
 +	return FALSE;
 +}
 +
 +#ifndef G_OS_WIN32
 +
 +static gboolean
 +cp_r (const char *src, const char *dest, const char *pattern, int mode)
 +{
 +	GString *srcpath, *destpath;
 +	struct dirent *dent;
 +	size_t slen, dlen;
 +	struct stat st;
 +	DIR *dir;
 +
 +	if (g_mkdir_with_parents (dest, 0777) == -1)
 +		return FALSE;
 +
 +	if (!(dir = opendir (src)))
 +		return FALSE;
 +
 +	srcpath = g_string_new (src);
 +	g_string_append_c (srcpath, '/');
 +	slen = srcpath->len;
 +
 +	destpath = g_string_new (dest);
 +	g_string_append_c (destpath, '/');
 +	dlen = destpath->len;
 +
 +	while ((dent = readdir (dir))) {
 +		if (!strcmp (dent->d_name, ".") || !strcmp (dent->d_name, ".."))
 +			continue;
 +
 +		g_string_truncate (srcpath, slen);
 +		g_string_truncate (destpath, dlen);
 +
 +		g_string_append (srcpath, dent->d_name);
 +		g_string_append (destpath, dent->d_name);
 +
 +		if (stat (srcpath->str, &st) == -1)
 +			continue;
 +
 +		if (S_ISDIR (st.st_mode)) {
 +			cp_r (srcpath->str, destpath->str, pattern, mode);
 +		} else if (!pattern || !strcmp (dent->d_name, pattern)) {
 +			cp (srcpath->str, destpath->str, FALSE, mode);
 +		}
 +	}
 +
 +	closedir (dir);
 +
 +	g_string_free (destpath, TRUE);
 +	g_string_free (srcpath, TRUE);
 +
 +	return TRUE;
 +}
 +
 +static void
 +mbox_build_filename (GString *path, const char *toplevel_dir, const char *full_name)
 +{
 +	const char *start, *inptr = full_name;
 +	int subdirs = 0;
 +
 +	while (*inptr != '\0') {
 +		if (*inptr == '/')
 +			subdirs++;
 +		inptr++;
 +	}
 +
 +	g_string_assign(path, toplevel_dir);
 +	g_string_append_c (path, '/');
 +
 +	inptr = full_name;
 +	while (*inptr != '\0') {
 +		start = inptr;
 +		while (*inptr != '/' && *inptr != '\0')
 +			inptr++;
 +
 +		g_string_append_len (path, start, inptr - start);
 +
 +		if (*inptr == '/') {
 +			g_string_append (path, ".sbd/");
 +			inptr++;
 +
 +			/* strip extranaeous '/'s */
 +			while (*inptr == '/')
 +				inptr++;
 +		}
 +	}
 +}
 +
 +static gboolean
 +em_migrate_folder(EMMigrateSession *session, const char *dirname, const char *full_name, GError **error)
 +{
 +	CamelFolder *old_folder = NULL, *new_folder = NULL;
 +	CamelStore *local_store = NULL;
 +	CamelException ex;
 +	char *name, *uri;
 +	GPtrArray *uids;
 +	struct stat st;
 +	gboolean thread_list;
 +	int index, i;
 +	GString *src, *dest;
 +	gboolean success = FALSE;
 +
 +	camel_exception_init (&ex);
 +
 +	src = g_string_new("");
 +
 +	g_string_printf(src, "%s/folder-metadata.xml", dirname);
 +	if (stat (src->str, &st) == -1
 +	    || !S_ISREG (st.st_mode)
 +	    || !is_mail_folder(src->str)) {
 +		/* Not an evolution mail folder */
 +		g_string_free(src, TRUE);
 +		return TRUE;
 +	}
 +
 +	dest = g_string_new("");
 +	uri = get_local_store_uri(dirname, &name, &index);
 +	em_migrate_set_folder_name (full_name);
 +	thread_list = get_local_et_expanded (dirname);
 +
 +	/* Manually copy local mbox files, its much faster */
 +	if (!strncmp (uri, "mbox:", 5)) {
- 		static char *meta_ext[] = { ".summary", ".ibex.index", ".ibex.index.data" };
++		static const gchar *meta_ext[] = { ".summary", ".ibex.index", ".ibex.index.data" };
 +		size_t slen, dlen;
 +		FILE *fp;
 +		char *p;
 +		int mode;
 +
 +		g_string_printf (src, "%s/%s", uri + 5, name);
 +		mbox_build_filename (dest, ((CamelService *)session->store)->url->path, full_name);
 +		p = strrchr (dest->str, '/');
 +		*p = '\0';
 +
 +		slen = src->len;
 +		dlen = dest->len;
 +
 +		if (g_mkdir_with_parents (dest->str, 0777) == -1 && errno != EEXIST) {
 +			g_set_error (
 +				error, E_SHELL_MIGRATE_ERROR,
 +				E_SHELL_MIGRATE_ERROR_FAILED,
 +				_("Unable to create new folder `%s': %s"),
 +				dest->str, g_strerror (errno));
 +			goto fatal;
 +		}
 +
 +		*p = '/';
 +		mode = CP_UNIQUE;
 +	retry_copy:
 +		if (!cp (src->str, dest->str, TRUE, mode)) {
 +			if (errno == EEXIST) {
 +				int save = errno;
 +
 +				switch (e_error_run(NULL, "mail:ask-migrate-existing", src->str, dest->str, NULL)) {
 +				case GTK_RESPONSE_ACCEPT:
 +					mode = CP_OVERWRITE;
 +					goto retry_copy;
 +				case GTK_RESPONSE_OK:
 +					mode = CP_APPEND;
 +					goto retry_copy;
 +				case GTK_RESPONSE_REJECT:
 +					goto ignore;
 +				}
 +
 +				errno = save;
 +			}
 +			g_set_error (
 +				error, E_SHELL_MIGRATE_ERROR,
 +				E_SHELL_MIGRATE_ERROR_FAILED,
 +				_("Unable to copy folder `%s' to `%s': %s"),
 +				src->str, dest->str, g_strerror (errno));
 +			goto fatal;
 +		}
 +	ignore:
 +
 +		/* create a .cmeta file specifying to index and/or thread the folder */
 +		g_string_truncate (dest, dlen);
 +		g_string_append (dest, ".cmeta");
 +		if ((fp = fopen (dest->str, "w")) != NULL) {
 +			int fd = fileno (fp);
 +
 +			/* write the magic string */
 +			if (fwrite ("CLMD", 4, 1, fp) != 1)
 +				goto cmeta_err;
 +
 +			/* write the version (1) */
 +			if (camel_file_util_encode_uint32 (fp, 1) == -1)
 +				goto cmeta_err;
 +
 +			/* write the meta count */
 +			if (camel_file_util_encode_uint32 (fp, thread_list ? 1 : 0) == -1)
 +				goto cmeta_err;
 +
 +			if (!thread_list) {
 +				if (camel_file_util_encode_string (fp, "evolution:thread_list") == -1)
 +					goto cmeta_err;
 +
 +				if (camel_file_util_encode_string (fp, !thread_list ? "1" : "0") == -1)
 +					goto cmeta_err;
 +			}
 +
 +			/* write the prop count (only prop is the index prop) */
 +			if (camel_file_util_encode_uint32 (fp, 1) == -1)
 +				goto cmeta_err;
 +
 +			/* write the index prop tag (== CAMEL_FOLDER_ARG_LAST|CAMEL_ARG_BOO) */
 +			if (camel_file_util_encode_uint32 (fp, CAMEL_FOLDER_ARG_LAST|CAMEL_ARG_BOO) == -1)
 +				goto cmeta_err;
 +
 +			/* write the index prop value */
 +			if (camel_file_util_encode_uint32 (fp, 1) == -1)
 +				goto cmeta_err;
 +
 +			fflush (fp);
 +
 +			if (fsync (fd) == -1) {
 +			cmeta_err:
 +				fclose (fp);
 +				unlink (dest->str);
 +			} else {
 +				fclose (fp);
 +			}
 +		}
 +
 +		/* copy over the metadata files */
 +		for (i = 0; i < sizeof(meta_ext)/sizeof(meta_ext[0]); i++) {
 +			g_string_truncate (src, slen);
 +			g_string_truncate (dest, dlen);
 +
 +			g_string_append (src, meta_ext[i]);
 +			g_string_append (dest, meta_ext[i]);
 +			cp (src->str, dest->str, FALSE, CP_OVERWRITE);
 +		}
 +	} else {
 +		guint32 flags = CAMEL_STORE_FOLDER_CREATE;
 +
 +		if (!(local_store = camel_session_get_store ((CamelSession *) session, uri, &ex))
 +		    || !(old_folder = camel_store_get_folder (local_store, name, 0, &ex)))
 +			goto fatal;
 +
 +		flags |= (index ? CAMEL_STORE_FOLDER_BODY_INDEX : 0);
 +		if (!(new_folder = camel_store_get_folder (session->store, full_name, flags, &ex)))
 +			goto fatal;
 +
 +		if (!thread_list) {
 +			camel_object_meta_set (new_folder, "evolution:thread_list", !thread_list ? "1" : "0");
 +			camel_object_state_write (new_folder);
 +		}
 +
 +		uids = camel_folder_get_uids (old_folder);
 +		for (i = 0; i < uids->len; i++) {
 +			CamelMimeMessage *message;
 +			CamelMessageInfo *info;
 +
 +			if (!(info = camel_folder_get_message_info (old_folder, uids->pdata[i])))
 +				continue;
 +
 +			if (!(message = camel_folder_get_message (old_folder, uids->pdata[i], &ex))) {
 +				camel_folder_free_message_info (old_folder, info);
 +				camel_folder_free_uids (old_folder, uids);
 +				goto fatal;
 +			}
 +
 +			camel_folder_append_message (new_folder, message, info, NULL, &ex);
 +			camel_folder_free_message_info (old_folder, info);
 +			camel_object_unref (message);
 +
 +			if (camel_exception_is_set (&ex))
 +				break;
 +
 +			em_migrate_set_progress (((double) i + 1) / ((double) uids->len));
 +		}
 +
 +		camel_folder_free_uids (old_folder, uids);
 +
 +		if (camel_exception_is_set (&ex))
 +			goto fatal;
 +	}
 +	success = TRUE;
 +fatal:
 +	g_free (uri);
 +	g_free (name);
 +	g_string_free(src, TRUE);
 +	g_string_free(dest, TRUE);
 +	if (local_store)
 +		camel_object_unref(local_store);
 +	if (old_folder)
 +		camel_object_unref(old_folder);
 +	if (new_folder)
 +		camel_object_unref(new_folder);
 +
 +	if (camel_exception_is_set (&ex)) {
 +		g_set_error (
 +			error, E_SHELL_MIGRATE_ERROR,
 +			E_SHELL_MIGRATE_ERROR_FAILED,
 +			"%s", camel_exception_get_description (&ex));
 +		camel_exception_clear (&ex);
 +	}
 +
 +	return success;
 +}
 +
 +static gboolean
 +em_migrate_dir (EMMigrateSession *session, const char *dirname, const char *full_name, GError **error)
 +{
 +	char *path;
 +	DIR *dir;
 +	struct stat st;
 +	struct dirent *dent;
 +	gboolean success = TRUE;
 +
 +	if (!em_migrate_folder(session, dirname, full_name, error))
 +		return FALSE;
 +
 +	/* no subfolders, not readable, don't care */
 +	path = g_strdup_printf ("%s/subfolders", dirname);
 +	if (stat (path, &st) == -1 || !S_ISDIR (st.st_mode)) {
 +		g_free (path);
 +		return TRUE;
 +	}
 +
 +	if (!(dir = opendir (path))) {
 +		g_free (path);
 +		return TRUE;
 +	}
 +
 +	while (success && (dent = readdir (dir))) {
 +		char *full_path;
 +		char *name;
 +
 +		if (dent->d_name[0] == '.')
 +			continue;
 +
 +		full_path = g_strdup_printf ("%s/%s", path, dent->d_name);
 +		if (stat (full_path, &st) == -1 || !S_ISDIR (st.st_mode)) {
 +			g_free (full_path);
 +			continue;
 +		}
 +
 +		name = g_strdup_printf ("%s/%s", full_name, dent->d_name);
 +		success = em_migrate_dir (session, full_path, name, error);
 +		g_free (full_path);
 +		g_free (name);
 +	}
 +
 +	closedir (dir);
 +
 +	g_free (path);
 +
 +	return success;
 +}
 +
 +static gboolean
 +em_migrate_local_folders_1_4 (EMMigrateSession *session, GError **error)
 +{
 +	struct dirent *dent;
 +	struct stat st;
 +	DIR *dir;
 +	gboolean success = TRUE;
 +
 +	if (!(dir = opendir (session->srcdir))) {
 +		g_set_error (
 +			error, E_SHELL_MIGRATE_ERROR,
 +			E_SHELL_MIGRATE_ERROR_FAILED,
 +			_("Unable to scan for existing mailboxes at "
 +			  "`%s': %s"), session->srcdir, g_strerror (errno));
 +		return FALSE;
 +	}
 +
- 	em_migrate_setup_progress_dialog (_("The location and hierarchy of the Evolution mailbox "
- 			     "folders has changed since Evolution 1.x.\n\nPlease be "
- 			     "patient while Evolution migrates your folders..."));
++	em_migrate_setup_progress_dialog (
++		_("Migrating Folders"),
++		_("The location and hierarchy of the Evolution mailbox "
++		  "folders has changed since Evolution 1.x.\n\nPlease be "
++		  "patient while Evolution migrates your folders..."));
 +
 +	while (success && (dent = readdir (dir))) {
 +		char *full_path;
 +
 +		if (dent->d_name[0] == '.')
 +			continue;
 +
 +		full_path = g_strdup_printf ("%s/%s", session->srcdir, dent->d_name);
 +		if (stat (full_path, &st) == -1 || !S_ISDIR (st.st_mode)) {
 +			g_free (full_path);
 +			continue;
 +		}
 +
 +		success = em_migrate_dir (session, full_path, dent->d_name, error);
 +		g_free (full_path);
 +	}
 +
 +	closedir (dir);
 +
 +	em_migrate_close_progress_dialog ();
 +
 +	return success;
 +}
 +
 +static char *
 +upgrade_xml_uris_1_4 (const char *uri)
 +{
 +	char *path, *prefix, *p;
 +	CamelURL *url;
 +
 +	if (!strncmp (uri, "file:", 5)) {
 +		url = camel_url_new (uri, NULL);
 +		camel_url_set_protocol (url, "email");
 +		camel_url_set_user (url, "local");
 +		camel_url_set_host (url, "local");
 +
 +		prefix = g_build_filename (g_get_home_dir (), "evolution", "local", NULL);
 +		if (strncmp (url->path, prefix, strlen (prefix)) != 0) {
 +			/* uri is busticated - user probably copied from another user's home directory */
 +			camel_url_free (url);
 +			g_free (prefix);
 +
 +			return g_strdup (uri);
 +		}
 +		path = g_strdup (url->path + strlen (prefix));
 +		g_free (prefix);
 +
 +		/* modify the path in-place */
 +		p = path + strlen (path) - 12;
 +		while (p > path) {
 +			if (!strncmp (p, "/subfolders/", 12))
 +				memmove (p, p + 11, strlen (p + 11) + 1);
 +
 +			p--;
 +		}
 +
 +		camel_url_set_path (url, path);
 +		g_free (path);
 +
 +		path = camel_url_to_string (url, 0);
 +		camel_url_free (url);
 +
 +		return path;
 +	} else {
 +		return em_uri_from_camel (uri);
 +	}
 +}
 +
 +static void
 +upgrade_vfolder_sources_1_4 (xmlDocPtr doc)
 +{
 +	xmlNodePtr root, node;
 +
 +	if (!doc || !(root = xmlDocGetRootElement (doc)))
 +		return;
 +
 +	if (!root->name || strcmp ((char *)root->name, "filteroptions") != 0) {
 +		/* root node is not <filteroptions>, nothing to upgrade */
 +		return;
 +	}
 +
 +	if (!(node = xml_find_node (root, "ruleset"))) {
 +		/* no ruleset node, nothing to upgrade */
 +		return;
 +	}
 +
 +	node = node->children;
 +	while (node != NULL) {
 +		if (node->name && !strcmp ((char *)node->name, "rule")) {
 +			xmlNodePtr sources;
 +			char *src;
 +
 +			if (!(src = (char *)xmlGetProp (node, (const unsigned char *)"source")))
 +				src = (char *)xmlStrdup ((const unsigned char *)"local");  /* default to all local folders? */
 +
 +			xmlSetProp (node, (const unsigned char *)"source", (const unsigned char *)"incoming");
 +
 +			if (!(sources = xml_find_node (node, "sources")))
 +				sources = xmlNewChild (node, NULL, (const unsigned char *)"sources", NULL);
 +
 +			xmlSetProp (sources, (const unsigned char *)"with", (unsigned char *)src);
 +			xmlFree (src);
 +		}
 +
 +		node = node->next;
 +	}
 +}
 +
 +static char *
 +get_nth_sig (int id)
 +{
 +	ESignatureList *list;
 +	ESignature *sig;
 +	EIterator *iter;
 +	char *uid = NULL;
 +	int i = 0;
 +
 +	list = e_get_signature_list ();
 +	iter = e_list_get_iterator ((EList *) list);
 +
 +	while (e_iterator_is_valid (iter) && i < id) {
 +		e_iterator_next (iter);
 +		i++;
 +	}
 +
 +	if (i == id && e_iterator_is_valid (iter)) {
 +		sig = (ESignature *) e_iterator_get (iter);
 +		uid = g_strdup (sig->uid);
 +	}
 +
 +	g_object_unref (iter);
 +
 +	return uid;
 +}
 +
 +static void
 +em_upgrade_accounts_1_4 (void)
 +{
 +	EAccountList *accounts;
 +	EIterator *iter;
 +
 +	if (!(accounts = e_get_account_list ()))
 +		return;
 +
 +	iter = e_list_get_iterator ((EList *) accounts);
 +	while (e_iterator_is_valid (iter)) {
 +		EAccount *account = (EAccount *) e_iterator_get (iter);
 +		char *url;
 +
 +		if (account->drafts_folder_uri) {
 +			url = upgrade_xml_uris_1_4 (account->drafts_folder_uri);
 +			g_free (account->drafts_folder_uri);
 +			account->drafts_folder_uri = url;
 +		}
 +
 +		if (account->sent_folder_uri) {
 +			url = upgrade_xml_uris_1_4 (account->sent_folder_uri);
 +			g_free (account->sent_folder_uri);
 +			account->sent_folder_uri = url;
 +		}
 +
 +		if (account->id->sig_uid && !strncmp (account->id->sig_uid, "::", 2)) {
 +			int sig_id;
 +
 +			sig_id = strtol (account->id->sig_uid + 2, NULL, 10);
 +			g_free (account->id->sig_uid);
 +			account->id->sig_uid = get_nth_sig (sig_id);
 +		}
 +
 +		e_iterator_next (iter);
 +	}
 +
 +	g_object_unref (iter);
 +
 +	e_account_list_save (accounts);
 +}
 +
 +static gboolean
 +em_migrate_pop_uid_caches_1_4 (const char *data_dir, GError **error)
 +{
 +	GString *oldpath, *newpath;
 +	struct dirent *dent;
 +	size_t olen, nlen;
 +	char *cache_dir;
 +	DIR *dir;
 +	gboolean success = TRUE;
 +
 +	/* Sigh, too many unique strings to translate, for cases which shouldn't ever happen */
 +
 +	/* open the old cache dir */
 +	cache_dir = g_build_filename (g_get_home_dir (), "evolution", "mail", "pop3", NULL);
 +	if (!(dir = opendir (cache_dir))) {
 +		if (errno == ENOENT) {
 +			g_free(cache_dir);
 +			return TRUE;
 +		}
 +
 +		g_set_error (
 +			error, E_SHELL_MIGRATE_ERROR,
 +			E_SHELL_MIGRATE_ERROR_FAILED,
 +			_("Unable to open old POP keep-on-server data "
 +			  "`%s': %s"), cache_dir, g_strerror (errno));
 +		g_free (cache_dir);
 +		return FALSE;
 +	}
 +
 +	oldpath = g_string_new (cache_dir);
 +	g_string_append_c (oldpath, '/');
 +	olen = oldpath->len;
 +	g_free (cache_dir);
 +
 +	cache_dir = g_build_filename (data_dir, "pop", NULL);
 +	if (g_mkdir_with_parents (cache_dir, 0777) == -1) {
 +		g_set_error (
 +			error, E_SHELL_MIGRATE_ERROR,
 +			E_SHELL_MIGRATE_ERROR_FAILED,
 +			_("Unable to create POP3 keep-on-server data "
 +			  "directory `%s': %s"), cache_dir,
 +			g_strerror (errno));
 +		g_string_free (oldpath, TRUE);
 +		g_free (cache_dir);
 +		closedir (dir);
 +		return FALSE;
 +	}
 +
 +	newpath = g_string_new (cache_dir);
 +	g_string_append_c (newpath, '/');
 +	nlen = newpath->len;
 +	g_free (cache_dir);
 +
 +	while (success && (dent = readdir (dir))) {
 +		if (strncmp (dent->d_name, "cache-pop:__", 12) != 0)
 +			continue;
 +
 +		g_string_truncate (oldpath, olen);
 +		g_string_truncate (newpath, nlen);
 +
 +		g_string_append (oldpath, dent->d_name);
 +		g_string_append (newpath, dent->d_name + 12);
 +
 +		/* strip the trailing '_' */
 +		g_string_truncate (newpath, newpath->len - 1);
 +
 +		if (g_mkdir_with_parents (newpath->str, 0777) == -1
 +		    || !cp(oldpath->str, (g_string_append(newpath, "/uid-cache"))->str, FALSE, CP_UNIQUE)) {
 +			g_set_error (
 +				error, E_SHELL_MIGRATE_ERROR,
 +				E_SHELL_MIGRATE_ERROR_FAILED,
 +				_("Unable to copy POP3 keep-on-server data "
 +				  "`%s': %s"), oldpath->str,
 +				g_strerror (errno));
 +			success = FALSE;
 +		}
 +
 +	}
 +
 +	g_string_free (oldpath, TRUE);
 +	g_string_free (newpath, TRUE);
 +
 +	closedir (dir);
 +
 +	return success;
 +}
 +
 +static gboolean
 +em_migrate_imap_caches_1_4 (const char *data_dir, GError **error)
 +{
 +	char *src, *dest;
 +	struct stat st;
 +
 +	src = g_build_filename (g_get_home_dir (), "evolution", "mail", "imap", NULL);
 +	if (stat (src, &st) == -1 || !S_ISDIR (st.st_mode)) {
 +		g_free (src);
 +		return TRUE;
 +	}
 +
 +	dest = g_build_filename (data_dir, "imap", NULL);
 +
 +	/* we don't care if this fails, it's only a cache... */
 +	cp_r (src, dest, "summary", CP_OVERWRITE);
 +
 +	g_free (dest);
 +	g_free (src);
 +
 +	return TRUE;
 +}
 +
 +static gboolean
 +em_migrate_folder_expand_state_1_4 (const char *data_dir, GError **error)
 +{
 +	GString *srcpath, *destpath;
 +	size_t slen, dlen, rlen;
 +	char *evo14_mbox_root;
 +	struct dirent *dent;
 +	struct stat st;
 +	DIR *dir;
 +
 +	srcpath = g_string_new (g_get_home_dir ());
 +	g_string_append (srcpath, "/evolution/config");
 +	if (stat (srcpath->str, &st) == -1 || !S_ISDIR (st.st_mode)) {
 +		g_string_free (srcpath, TRUE);
 +		return TRUE;
 +	}
 +
 +	destpath = g_string_new (data_dir);
 +	g_string_append (destpath, "/config");
 +	if (g_mkdir_with_parents (destpath->str, 0777) == -1 || !(dir = opendir (srcpath->str))) {
 +		g_string_free (destpath, TRUE);
 +		g_string_free (srcpath, TRUE);
 +		return TRUE;
 +	}
 +
 +	g_string_append (srcpath, "/et-expanded-");
 +	slen = srcpath->len;
 +	g_string_append (destpath, "/et-expanded-");
 +	dlen = destpath->len;
 +
 +	evo14_mbox_root = g_build_filename (g_get_home_dir (), "evolution", "local", NULL);
 +	e_filename_make_safe (evo14_mbox_root);
 +	rlen = strlen (evo14_mbox_root);
 +	evo14_mbox_root = g_realloc (evo14_mbox_root, rlen + 2);
 +	evo14_mbox_root[rlen++] = '_';
 +	evo14_mbox_root[rlen] = '\0';
 +
 +	while ((dent = readdir (dir))) {
 +		char *full_name, *inptr, *buf = NULL;
 +		const char *filename;
 +		GString *new;
 +
 +		if (strncmp (dent->d_name, "et-expanded-", 12) != 0)
 +			continue;
 +
 +		if (!strncmp (dent->d_name + 12, "file:", 5)) {
 +			/* need to munge the filename */
 +			inptr = dent->d_name + 17;
 +
 +			if (!strncmp (inptr, evo14_mbox_root, rlen)) {
 +				/* this should always be the case afaik... */
 +				inptr += rlen;
 +				new = g_string_new ("mbox:");
 +				g_string_append_printf (new, "%s/local#", data_dir);
 +
 +				full_name = g_strdup (inptr);
 +				inptr = full_name + strlen (full_name) - 12;
 +				while (inptr > full_name) {
 +					if (!strncmp (inptr, "_subfolders_", 12))
 +						memmove (inptr, inptr + 11, strlen (inptr + 11) + 1);
 +
 +					inptr--;
 +				}
 +
 +				g_string_append (new, full_name);
 +				g_free (full_name);
 +
 +				filename = buf = new->str;
 +				g_string_free (new, FALSE);
 +				e_filename_make_safe (buf);
 +			} else {
 +				/* but just in case... */
 +				filename = dent->d_name + 12;
 +			}
 +		} else {
 +			/* no munging needed */
 +			filename = dent->d_name + 12;
 +		}
 +
 +		g_string_append (srcpath, dent->d_name + 12);
 +		g_string_append (destpath, filename);
 +		g_free (buf);
 +
 +		cp (srcpath->str, destpath->str, FALSE, CP_UNIQUE);
 +
 +		g_string_truncate (srcpath, slen);
 +		g_string_truncate (destpath, dlen);
 +	}
 +
 +	closedir (dir);
 +
 +	g_free (evo14_mbox_root);
 +	g_string_free (destpath, TRUE);
 +	g_string_free (srcpath, TRUE);
 +
 +	return TRUE;
 +}
 +
 +static gboolean
 +em_migrate_folder_view_settings_1_4 (const char *data_dir, GError **error)
 +{
 +	GString *srcpath, *destpath;
 +	size_t slen, dlen, rlen;
 +	char *evo14_mbox_root;
 +	struct dirent *dent;
 +	struct stat st;
 +	DIR *dir;
 +
 +	srcpath = g_string_new (g_get_home_dir ());
 +	g_string_append (srcpath, "/evolution/views/mail");
 +	if (stat (srcpath->str, &st) == -1 || !S_ISDIR (st.st_mode)) {
 +		g_string_free (srcpath, TRUE);
 +		return TRUE;
 +	}
 +
 +	destpath = g_string_new (data_dir);
 +	g_string_append (destpath, "/views");
 +	if (g_mkdir_with_parents (destpath->str, 0777) == -1 || !(dir = opendir (srcpath->str))) {
 +		g_string_free (destpath, TRUE);
 +		g_string_free (srcpath, TRUE);
 +		return TRUE;
 +	}
 +
 +	g_string_append_c (srcpath, '/');
 +	slen = srcpath->len;
 +	g_string_append_c (destpath, '/');
 +	dlen = destpath->len;
 +
 +	evo14_mbox_root = g_build_filename (g_get_home_dir (), "evolution", "local", NULL);
 +	e_filename_make_safe (evo14_mbox_root);
 +	rlen = strlen (evo14_mbox_root);
 +	evo14_mbox_root = g_realloc (evo14_mbox_root, rlen + 2);
 +	evo14_mbox_root[rlen++] = '_';
 +	evo14_mbox_root[rlen] = '\0';
 +
 +	while ((dent = readdir (dir))) {
 +		char *full_name, *inptr, *buf = NULL;
 +		const char *filename, *ext;
 +		size_t prelen = 0;
 +		GString *new;
 +
 +		if (dent->d_name[0] == '.')
 +			continue;
 +
 +		if (!(ext = strrchr (dent->d_name, '.')))
 +			continue;
 +
 +		if (!strcmp (ext, ".galview") || !strcmp ((char *)dent->d_name, "galview.xml")) {
 +			/* just copy the file */
 +			filename = dent->d_name;
 +			goto copy;
 +		} else if (strcmp (ext, ".xml") != 0) {
 +			continue;
 +		}
 +
 +		if (!strncmp ((const char *)dent->d_name, "current_view-", 13)) {
 +			prelen = 13;
 +		} else if (!strncmp ((const char *)dent->d_name, "custom_view-", 12)) {
 +			prelen = 12;
 +		} else {
 +			/* huh? wtf is this file? */
 +			continue;
 +		}
 +
 +		if (!strncmp (dent->d_name + prelen, "file:", 5)) {
 +			/* need to munge the filename */
 +			inptr = dent->d_name + prelen + 5;
 +
 +			if (!strncmp (inptr, evo14_mbox_root, rlen)) {
 +				/* this should always be the case afaik... */
 +				inptr += rlen;
 +				new = g_string_new ("mbox:");
 +				g_string_append_printf (new, "%s/local#", data_dir);
 +
 +				full_name = g_strdup (inptr);
 +				inptr = full_name + strlen (full_name) - 12;
 +				while (inptr > full_name) {
 +					if (!strncmp (inptr, "_subfolders_", 12))
 +						memmove (inptr, inptr + 11, strlen (inptr + 11) + 1);
 +
 +					inptr--;
 +				}
 +
 +				g_string_append (new, full_name);
 +				g_free (full_name);
 +
 +				filename = buf = new->str;
 +				g_string_free (new, FALSE);
 +				e_filename_make_safe (buf);
 +			} else {
 +				/* but just in case... */
 +				filename = dent->d_name + prelen;
 +			}
 +		} else {
 +			/* no munging needed */
 +			filename = dent->d_name + prelen;
 +		}
 +
 +	copy:
 +		g_string_append (srcpath, dent->d_name);
 +		if (prelen > 0)
 +			g_string_append_len (destpath, dent->d_name, prelen);
 +		g_string_append (destpath, filename);
 +		g_free (buf);
 +
 +		cp (srcpath->str, destpath->str, FALSE, CP_UNIQUE);
 +
 +		g_string_truncate (srcpath, slen);
 +		g_string_truncate (destpath, dlen);
 +	}
 +
 +	closedir (dir);
 +
 +	g_free (evo14_mbox_root);
 +	g_string_free (destpath, TRUE);
 +	g_string_free (srcpath, TRUE);
 +
 +	return TRUE;
 +}
 +
 +#define SUBFOLDER_DIR_NAME     "subfolders"
 +#define SUBFOLDER_DIR_NAME_LEN 10
 +
 +static char *
 +e_path_to_physical (const char *prefix, const char *vpath)
 +{
 +	const char *p, *newp;
 +	char *dp;
 +	char *ppath;
 +	int ppath_len;
 +	int prefix_len;
 +
 +	while (*vpath == '/')
 +		vpath++;
 +	if (!prefix)
 +		prefix = "";
 +
 +	/* Calculate the length of the real path. */
 +	ppath_len = strlen (vpath);
 +	ppath_len++;	/* For the ending zero.  */
 +
 +	prefix_len = strlen (prefix);
 +	ppath_len += prefix_len;
 +	ppath_len++;	/* For the separating slash.  */
 +
 +	/* Take account of the fact that we need to translate every
 +	 * separator into `subfolders/'.
 +	 */
 +	p = vpath;
 +	while (1) {
 +		newp = strchr (p, '/');
 +		if (newp == NULL)
 +			break;
 +
 +		ppath_len += SUBFOLDER_DIR_NAME_LEN;
 +		ppath_len++; /* For the separating slash.  */
 +
 +		/* Skip consecutive slashes.  */
 +		while (*newp == '/')
 +			newp++;
 +
 +		p = newp;
 +	};
 +
 +	ppath = g_malloc (ppath_len);
 +	dp = ppath;
 +
 +	memcpy (dp, prefix, prefix_len);
 +	dp += prefix_len;
 +	*(dp++) = '/';
 +
 +	/* Copy the mangled path.  */
 +	p = vpath;
 + 	while (1) {
 +		newp = strchr (p, '/');
 +		if (newp == NULL) {
 +			strcpy (dp, p);
 +			break;
 +		}
 +
 +		memcpy (dp, p, newp - p + 1); /* `+ 1' to copy the slash too.  */
 +		dp += newp - p + 1;
 +
 +		memcpy (dp, SUBFOLDER_DIR_NAME, SUBFOLDER_DIR_NAME_LEN);
 +		dp += SUBFOLDER_DIR_NAME_LEN;
 +
 +		*(dp++) = '/';
 +
 +		/* Skip consecutive slashes.  */
 +		while (*newp == '/')
 +			newp++;
 +
 +		p = newp;
 +	}
 +
 +	return ppath;
 +}
 +
 +static gboolean
 +em_migrate_imap_cmeta_1_4(const char *data_dir, GError **error)
 +{
 +	GConfClient *gconf;
 +	GSList *paths, *p;
 +	EAccountList *accounts;
 +	const EAccount *account;
 +
 +	if (!(accounts = e_get_account_list ()))
 +		return TRUE;
 +
 +	gconf = gconf_client_get_default();
 +	paths = gconf_client_get_list(gconf, "/apps/evolution/shell/offline/folder_paths", GCONF_VALUE_STRING, NULL);
 +	for (p = paths;p;p = g_slist_next(p)) {
 +		char *name, *path;
 +
 +		name = p->data;
 +		if (*name)
 +			name++;
 +		path = strchr(name, '/');
 +		if (path) {
 +			*path++ = 0;
 +			account = e_account_list_find(accounts, E_ACCOUNT_FIND_NAME, name);
 +			if (account && !strncmp(account->source->url, "imap:", 5)) {
 +				CamelURL *url = camel_url_new(account->source->url, NULL);
 +
 +				if (url) {
 +					char *dir, *base;
 +
 +					base = g_strdup_printf("%s/imap/%s %s/folders",
 +							       data_dir,
 +							       url->user?url->user:"",
 +							       url->host?url->host:"");
 +
 +					dir = e_path_to_physical(base, path);
 +					if (g_mkdir_with_parents(dir, 0777) == 0) {
 +						char *cmeta;
 +						FILE *fp;
 +
 +						cmeta = g_build_filename(dir, "cmeta", NULL);
 +						fp = fopen(cmeta, "w");
 +						if (fp) {
 +							/* header/version */
 +							fwrite("CLMD", 4, 1, fp);
 +							camel_file_util_encode_uint32(fp, 1);
 +							/* meta count, do we have any metadata? */
 +							camel_file_util_encode_uint32(fp, 0);
 +							/* prop count */
 +							camel_file_util_encode_uint32(fp, 1);
 +							/* sync offline property */
 +							camel_file_util_encode_uint32(fp, CAMEL_DISCO_FOLDER_OFFLINE_SYNC);
 +							camel_file_util_encode_uint32(fp, 1);
 +							fclose(fp);
 +						} else {
 +							g_warning("couldn't create imap folder cmeta file '%s'", cmeta);
 +						}
 +						g_free(cmeta);
 +					} else {
 +						g_warning("couldn't create imap folder directory '%s'", dir);
 +					}
 +					g_free(dir);
 +					g_free(base);
 +					camel_url_free(url);
 +				}
 +			} else
 +				g_warning("can't find offline folder '%s' '%s'", name, path);
 +		}
 +		g_free(p->data);
 +	}
 +	g_slist_free(paths);
 +	g_object_unref(gconf);
 +
 +	/* we couldn't care less if this doesn't work */
 +
 +	return TRUE;
 +}
 +
 +static void
 +remove_system_searches(xmlDocPtr searches)
 +{
 +	xmlNodePtr node;
 +
 +	/* in pre 2.0, system searches were stored in the user
 +	 * searches.xml file with the source set to 'demand'.  In 2.0+
 +	 * the system searches are stored in the system
 +	 * searchtypes.xml file instead */
 +
 +	node = xmlDocGetRootElement(searches);
 +	if (!node->name || strcmp((char *)node->name, "filteroptions"))
 +		return;
 +
 +	if (!(node = xml_find_node(node, "ruleset")))
 +		return;
 +
 +	node = node->children;
 +	while (node != NULL) {
 +		xmlNodePtr nnode = node->next;
 +
 +		if (node->name && !strcmp ((char *)node->name, "rule")) {
 +			char *src;
 +
 +			src = (char *)xmlGetProp(node, (unsigned char *)"source");
 +			if (src && !strcmp((char *)src, "demand")) {
 +				xmlUnlinkNode(node);
 +				xmlFreeNodeList(node);
 +			}
 +			xmlFree (src);
 +		}
 +
 +		node = nnode;
 +	}
 +}
 +
 +static gboolean
 +em_migrate_1_4 (const char *data_dir, xmlDocPtr filters, xmlDocPtr vfolders, GError **error)
 +{
 +	EMMigrateSession *session;
 +	CamelException lex;
 +	struct stat st;
 +	gchar *path;
 +	xmlDocPtr searches;
 +
 +	camel_init (data_dir, TRUE);
 +	camel_provider_init();
 +	session = (EMMigrateSession *) em_migrate_session_new (data_dir);
 +
 +	session->srcdir = g_build_filename (g_get_home_dir (), "evolution", "local", NULL);
 +
 +	path = g_strdup_printf ("mbox:%s/.evolution/mail/local", g_get_home_dir ());
 +	if (stat (path + 5, &st) == -1) {
 +		if (errno != ENOENT || g_mkdir_with_parents (path + 5, 0777) == -1) {
 +			g_set_error (
 +				error, E_SHELL_MIGRATE_ERROR,
 +				E_SHELL_MIGRATE_ERROR_FAILED,
 +				_("Failed to create local mail storage "
 +				  "`%s': %s"), path + 5, g_strerror (errno));
 +			g_free (session->srcdir);
 +			camel_object_unref (session);
 +			g_free (path);
 +			return FALSE;
 +		}
 +	}
 +
 +	camel_exception_init (&lex);
 +	if (!(session->store = camel_session_get_store ((CamelSession *) session, path, &lex))) {
 +		g_set_error (
 +			error, E_SHELL_MIGRATE_ERROR,
 +			E_SHELL_MIGRATE_ERROR_FAILED,
 +			_("Failed to create local mail storage `%s': %s"),
 +			path, lex.desc);
 +		g_free (session->srcdir);
 +		camel_object_unref (session);
 +		camel_exception_clear (&lex);
 +		g_free (path);
 +		return FALSE;
 +	}
 +	g_free (path);
 +
 +	if (!em_migrate_local_folders_1_4 (session, error))
 +		return FALSE;
 +
 +	camel_object_unref (session->store);
 +	g_free (session->srcdir);
 +
 +	camel_object_unref (session);
 +
 +	em_upgrade_accounts_1_4();
 +
 +	upgrade_xml_uris(filters, upgrade_xml_uris_1_4);
 +	upgrade_vfolder_sources_1_4(vfolders);
 +	upgrade_xml_uris(vfolders, upgrade_xml_uris_1_4);
 +
 +	path = g_build_filename(g_get_home_dir(), "evolution", NULL);
 +	searches = emm_load_xml(path, "searches.xml");
 +	g_free(path);
 +	if (searches) {
 +		remove_system_searches(searches);
 +		emm_save_xml(searches, data_dir, "searches.xml");
 +		xmlFreeDoc(searches);
 +	}
 +
 +	if (!em_migrate_pop_uid_caches_1_4 (data_dir, error))
 +		return FALSE;
 +
 +	/* these are non-fatal */
 +	em_migrate_imap_caches_1_4 (data_dir, error);
 +	g_clear_error (error);
 +	em_migrate_folder_expand_state_1_4 (data_dir, error);
 +	g_clear_error (error);
 +	em_migrate_folder_view_settings_1_4 (data_dir, error);
 +	g_clear_error (error);
 +	em_migrate_imap_cmeta_1_4 (data_dir, error);
 +	g_clear_error (error);
 +
 +	return TRUE;
 +}
 +
 +static void
 +em_update_accounts_2_11 (void)
 +{
 +	EAccountList *accounts;
 +	EIterator *iter;
 +	gboolean changed = FALSE;
 +
 +	if (!(accounts = e_get_account_list ()))
 +		return;
 +
 +	iter = e_list_get_iterator ((EList *) accounts);
 +	while (e_iterator_is_valid (iter)) {
 +		EAccount *account = (EAccount *) e_iterator_get (iter);
 +
 +		if (g_str_has_prefix (account->source->url, "spool://")) {
 +			if (g_file_test (account->source->url + 8, G_FILE_TEST_IS_DIR)) {
 +				char *str = g_strdup_printf ("spooldir://%s", account->source->url + 8);
 +
 +				g_free (account->source->url);
 +				account->source->url = str;
 +				changed = TRUE;
 +			}
 +		}
 +
 +		e_iterator_next (iter);
 +	}
 +
 +	g_object_unref (iter);
 +
 +	if (changed)
 +		e_account_list_save (accounts);
 +}
 +
 +#endif	/* !G_OS_WIN32 */
 +
 +static gboolean
 +emm_setup_initial(const gchar *data_dir)
 +{
 +	GDir *dir;
 +	const char *d;
 +	char *local = NULL, *base;
 +	const gchar * const *language_names;
 +
 +	/* special-case - this means brand new install of evolution */
 +	/* FIXME: create default folders and stuff... */
 +
 +	d(printf("Setting up initial mail tree\n"));
 +
 +	base = g_build_filename(data_dir, "local", NULL);
 +	if (g_mkdir_with_parents(base, 0777) == -1 && errno != EEXIST) {
 +		g_free(base);
 +		return FALSE;
 +	}
 +
 +	/* e.g. try en-AU then en, etc */
 +	language_names = g_get_language_names ();
 +	while (*language_names != NULL) {
 +		local = g_build_filename (
 +			EVOLUTION_PRIVDATADIR, "default",
 +			*language_names, "mail", "local", NULL);
 +		if (g_file_test (local, G_FILE_TEST_EXISTS))
 +			break;
 +		g_free (local);
 +		language_names++;
 +	}
 +
 +	/* Make sure we found one. */
 +	g_return_val_if_fail (*language_names != NULL, FALSE);
 +
 +	dir = g_dir_open(local, 0, NULL);
 +	if (dir) {
 +		while ((d = g_dir_read_name(dir))) {
 +			char *src, *dest;
 +
 +			src = g_build_filename(local, d, NULL);
 +			dest = g_build_filename(base, d, NULL);
 +
 +			cp(src, dest, FALSE, CP_UNIQUE);
 +			g_free(dest);
 +			g_free(src);
 +		}
 +		g_dir_close(dir);
 +	}
 +
 +	g_free(local);
 +	g_free(base);
 +
 +	return TRUE;
 +}
 +
 +static gboolean
 +is_in_plugs_list (GSList *list, const gchar *value)
 +{
 +	GSList *l;
 +
 +	for (l = list; l; l = l->next) {
 +		if (l->data && !strcmp (l->data, value))
 +			return TRUE;
 +	}
 +
 +	return FALSE;
 +}
 +
 +/*
 + * em_update_message_notify_settings_2_21
 + * DBus plugin and sound email notification was merged to mail-notification plugin,
 + * so move these options to new locations.
 + */
 +static void
 +em_update_message_notify_settings_2_21 (void)
 +{
 +	GConfClient *client;
 +	GConfValue  *is_key;
 +	gboolean dbus, status;
 +	GSList *list;
 +	gchar *str;
 +	gint val;
 +
 +	client = gconf_client_get_default ();
 +
 +	is_key = gconf_client_get (client, "/apps/evolution/eplugin/mail-notification/dbus-enabled", NULL);
 +	if (is_key) {
 +		/* already migrated, so do not migrate again */
 +		gconf_value_free (is_key);
 +		g_object_unref (client);
 +
 +		return;
 +	}
 +
 +	gconf_client_set_bool (client, "/apps/evolution/eplugin/mail-notification/status-blink-icon",
 +				gconf_client_get_bool (client, "/apps/evolution/mail/notification/blink-status-icon", NULL), NULL);
 +	gconf_client_set_bool (client, "/apps/evolution/eplugin/mail-notification/status-notification",
 +				gconf_client_get_bool (client, "/apps/evolution/mail/notification/notification", NULL), NULL);
 +
 +	list = gconf_client_get_list (client, "/apps/evolution/eplugin/disabled", GCONF_VALUE_STRING, NULL);
 +	dbus = !is_in_plugs_list (list, "org.gnome.evolution.new_mail_notify");
 +	status = !is_in_plugs_list (list, "org.gnome.evolution.mail_notification");
 +
 +	gconf_client_set_bool (client, "/apps/evolution/eplugin/mail-notification/dbus-enabled", dbus, NULL);
 +	gconf_client_set_bool (client, "/apps/evolution/eplugin/mail-notification/status-enabled", status, NULL);
 +
 +	if (!status) {
 +		/* enable this plugin, because it holds all those other things */
 +		GSList *plugins, *l;
 +
 +		plugins = e_plugin_list_plugins ();
 +
 +		for (l = plugins; l; l = l->next) {
 +			EPlugin *p = l->data;
 +
 +			if (p && p->id && !strcmp (p->id, "org.gnome.evolution.mail_notification")) {
 +				e_plugin_enable (p, 1);
 +				break;
 +			}
 +		}
 +
 +		g_slist_foreach (plugins, (GFunc)g_object_unref, NULL);
 +		g_slist_free (plugins);
 +	}
 +
 +	g_slist_foreach (list, (GFunc) g_free, NULL);
 +	g_slist_free (list);
 +
 +	val = gconf_client_get_int (client, "/apps/evolution/mail/notify/type", NULL);
 +	gconf_client_set_bool (client, "/apps/evolution/eplugin/mail-notification/sound-enabled", val == 1 || val == 2, NULL);
 +	gconf_client_set_bool (client, "/apps/evolution/eplugin/mail-notification/sound-beep", val == 0 || val == 1, NULL);
 +
 +	str = gconf_client_get_string (client, "/apps/evolution/mail/notify/sound", NULL);
 +	gconf_client_set_string (client, "/apps/evolution/eplugin/mail-notification/sound-file", str ? str : "", NULL);
 +	g_free (str);
 +
 +	g_object_unref (client);
 +}
 +
 +/* fixing typo in SpamAssassin name */
 +static void
 +em_update_sa_junk_setting_2_23 (void)
 +{
 +	GConfClient *client;
 +	GConfValue  *key;
 +
 +	client = gconf_client_get_default ();
 +
 +	key = gconf_client_get (client, "/apps/evolution/mail/junk/default_plugin", NULL);
 +	if (key) {
 +		const char *str = gconf_value_get_string (key);
 +
 +		if (str && strcmp (str, "Spamassasin") == 0)
 +			gconf_client_set_string (client, "/apps/evolution/mail/junk/default_plugin", "SpamAssassin", NULL);
 +
 +		gconf_value_free (key);
 +		g_object_unref (client);
 +
 +		return;
 +	}
 +
 +	g_object_unref (client);
 +}
 +
++static gboolean
++update_progress_in_main_thread (double *progress)
++{
++	em_migrate_set_progress (*progress);
++	return FALSE;
++}
 +
 +static void
- migrate_folders(CamelStore *store, CamelFolderInfo *fi, const char *acc, CamelException *ex)
++migrate_folders(CamelStore *store, gboolean is_local, CamelFolderInfo *fi, const char *acc, CamelException *ex, gboolean *done, int *nth_folder, int total_folders)
 +{
 +	CamelFolder *folder;
 +
 +	while (fi) {
- 		char *tmp = g_strdup_printf ("%s/%s", acc, fi->full_name);
++		double progress;
++		char *tmp;
++
++		*nth_folder = *nth_folder + 1;
++
++		tmp = g_strdup_printf ("%s/%s", acc, fi->full_name);
 +		em_migrate_set_folder_name (tmp);
 +		g_free (tmp);
- 		folder = camel_store_get_folder (store, fi->full_name, 0, ex);
++
++		progress = (double) (*nth_folder) / total_folders;
++		g_idle_add ((GSourceFunc) update_progress_in_main_thread, &progress);
++
++		if (is_local)
++				folder = camel_store_get_folder (store, fi->full_name, CAMEL_STORE_IS_MIGRATING, ex);
++		else
++				folder = camel_store_get_folder (store, fi->full_name, 0, ex);
++
 +		if (folder != NULL)
 +			camel_folder_summary_migrate_infos (folder->summary);
- 		migrate_folders(store, fi->child, acc, ex);
++		migrate_folders(store, is_local, fi->child, acc, ex, done, nth_folder, total_folders);
++		fi = fi->next;
++	}
++
++	if ((*nth_folder) == (total_folders - 1))
++		*done = TRUE;
++}
++
++/* This could be in CamelStore.ch */
++static void
++count_folders (CamelFolderInfo *fi, int *count)
++{
++	while (fi) {
++		*count = *count + 1;
++		count_folders (fi->child, count);
 +		fi = fi->next;
 +	}
 +}
 +
 +static CamelStore *
 +setup_local_store (EShellBackend *shell_backend,
 +                   EMMigrateSession *session)
 +{
 +	CamelURL *url;
 +	const gchar *data_dir;
 +	char *tmp;
 +	CamelStore *store;
 +
 +	url = camel_url_new("mbox:", NULL);
 +	data_dir = e_shell_backend_get_data_dir (shell_backend);
 +	tmp = g_build_filename (data_dir, "local", NULL);
 +	camel_url_set_path(url, tmp);
 +	g_free(tmp);
 +	tmp = camel_url_to_string(url, 0);
 +	store = (CamelStore *)camel_session_get_service(CAMEL_SESSION (session), tmp, CAMEL_PROVIDER_STORE, NULL);
 +	g_free(tmp);
 +
 +	return store;
++}
++
++struct migrate_folders_to_db_structure {
++		char *account_name;
++		CamelException ex;
++		CamelStore *store;
++		CamelFolderInfo *info;
++		gboolean done;
++		gboolean is_local_store;
++};
 +
++static void
++migrate_folders_to_db_thread (struct migrate_folders_to_db_structure *migrate_dbs)
++{
++		int num_of_folders = 0, nth_folder = 0;
++		count_folders (migrate_dbs->info, &num_of_folders);
++		migrate_folders (migrate_dbs->store, migrate_dbs->is_local_store, migrate_dbs->info,
++						migrate_dbs->account_name, &(migrate_dbs->ex), &(migrate_dbs->done),
++						&nth_folder, num_of_folders);
 +}
++
 +static void
 +migrate_to_db (EShellBackend *shell_backend)
 +{
 +	EMMigrateSession *session;
 +	EAccountList *accounts;
 +	EIterator *iter;
 +	int i=0, len;
 +	CamelStore *store = NULL;
 +	CamelFolderInfo *info;
 +	const gchar *data_dir;
 +
 +	if (!(accounts = e_get_account_list ()))
 +		return;
 +
 +	iter = e_list_get_iterator ((EList *) accounts);
 +	len = e_list_length ((EList *) accounts);
 +
 +	data_dir = e_shell_backend_get_data_dir (shell_backend);
 +	session = (EMMigrateSession *) em_migrate_session_new (data_dir);
 +	camel_session_set_online ((CamelSession *) session, FALSE);
- 	em_migrate_setup_progress_dialog (_("The summary format of the Evolution mailbox "
- 			     "folders has been moved to SQLite since Evolution 2.24.\n\nPlease be "
- 			     "patient while Evolution migrates your folders..."));
++	em_migrate_setup_progress_dialog (
++		_("Migrating Folders"),
++		_("The summary format of the Evolution mailbox "
++		  "folders has been moved to SQLite since Evolution 2.24.\n\nPlease be "
++		  "patient while Evolution migrates your folders..."));
 +
 +	em_migrate_set_progress ( (double)i/(len+1));
 +	store = setup_local_store (shell_backend, session);
 +	info = camel_store_get_folder_info (store, NULL, CAMEL_STORE_FOLDER_INFO_RECURSIVE|CAMEL_STORE_FOLDER_INFO_FAST|CAMEL_STORE_FOLDER_INFO_SUBSCRIBED, NULL);
 +	if (info) {
- 		migrate_folders(store, info, _("On This Computer"), NULL);
++		GThread *thread;
++		struct migrate_folders_to_db_structure migrate_dbs;
++
++		if (g_str_has_suffix (((CamelService *)store)->url->path, ".evolution/mail/local"))
++			migrate_dbs.is_local_store = TRUE;
++		else 
++			migrate_dbs.is_local_store = FALSE;
++		camel_exception_init (&migrate_dbs.ex);
++		migrate_dbs.account_name = _("On This Computer");
++		migrate_dbs.info = info;
++		migrate_dbs.store = store;
++		migrate_dbs.done = FALSE;
++
++		thread = g_thread_create ((GThreadFunc) migrate_folders_to_db_thread, &migrate_dbs, TRUE, NULL);
++		while (!migrate_dbs.done)
++			g_main_context_iteration (NULL, TRUE);
 +	}
 +	i++;
 +	em_migrate_set_progress ( (double)i/(len+1));
 +
 +
 +	while (e_iterator_is_valid (iter)) {
 +		EAccount *account = (EAccount *) e_iterator_get (iter);
 +		EAccountService *service;
 +		const char *name;
 +
 +
 +		service = account->source;
 +		name = account->name;
 +		em_migrate_set_progress ( (double)i/(len+1));
 +		if (account->enabled
 +		    && service->url != NULL
 +		    && service->url[0]
 +		    && strncmp(service->url, "mbox:", 5) != 0) {
 +
 +			CamelException ex;
 +
 +			camel_exception_init (&ex);
 +			e_mail_shell_backend_load_store_by_uri (
 +				E_MAIL_SHELL_BACKEND (shell_backend),
 +				service->url, name);
 +
 +			store = (CamelStore *) camel_session_get_service (CAMEL_SESSION (session), service->url, CAMEL_PROVIDER_STORE, &ex);
 +			info = camel_store_get_folder_info (store, NULL, CAMEL_STORE_FOLDER_INFO_RECURSIVE|CAMEL_STORE_FOLDER_INFO_FAST|CAMEL_STORE_FOLDER_INFO_SUBSCRIBED, &ex);
 +			if (info) {
- 				migrate_folders(store, info, account->name, &ex);
- 
++				GThread *thread;
++				struct migrate_folders_to_db_structure migrate_dbs;
++
++				migrate_dbs.ex = ex;
++				migrate_dbs.account_name = account->name;
++				migrate_dbs.info = info;
++				migrate_dbs.store = store;
++				migrate_dbs.done = FALSE;
++
++				thread = g_thread_create ((GThreadFunc) migrate_folders_to_db_thread, &migrate_dbs, TRUE, NULL);
++				while (!migrate_dbs.done)
++					g_main_context_iteration (NULL, TRUE);
 +			} else
 +				printf("%s:%s: failed to get folder infos \n", G_STRLOC, G_STRFUNC);
 +			camel_exception_clear(&ex);
 +
 +		}
 +		i++;
 +		e_iterator_next (iter);
 +
 +	}
 +
 +	//camel_session_set_online ((CamelSession *) session, TRUE);
 +
 +	g_object_unref (iter);
 +	em_migrate_close_progress_dialog ();
 +
 +	g_object_unref (session);
 +}
 +
 +gboolean
 +e_mail_shell_migrate (EShellBackend *shell_backend,
 +                      gint major,
 +                      gint minor,
 +                      gint micro,
 +                      GError **error)
 +{
 +	struct stat st;
 +	const gchar *data_dir;
 +	gchar *path;
 +
 +	/* make sure ~/.evolution/mail exists */
 +	data_dir = e_shell_backend_get_data_dir (shell_backend);
 +	if (g_stat (data_dir, &st) == -1) {
 +		if (errno != ENOENT || g_mkdir_with_parents (data_dir, 0777) == -1) {
 +			g_set_error (
 +				error, E_SHELL_MIGRATE_ERROR,
 +				E_SHELL_MIGRATE_ERROR_FAILED,
 +				_("Unable to create local mail folders at "
 +				"`%s': %s"), data_dir, g_strerror (errno));
 +			return FALSE;
 +		}
 +	}
 +
 +	if (major == 0)
 +		return emm_setup_initial (data_dir);
 +
 +	if (major == 1 && minor < 5) {
 +#ifndef G_OS_WIN32
 +		xmlDocPtr config_xmldb = NULL, filters, vfolders;
 +
 +		path = g_build_filename (g_get_home_dir (), "evolution", NULL);
 +		if (minor <= 2 && !(config_xmldb = emm_load_xml (path, "config.xmldb"))) {
 +			g_set_error (
 +				error, E_SHELL_MIGRATE_ERROR,
 +				E_SHELL_MIGRATE_ERROR_FAILED,
 +				_("Unable to read settings from previous "
 +				  "Evolution install, `evolution/config.xmldb' "
 +				  "does not exist or is corrupt."));
 +			return FALSE;
 +		}
 +		filters = emm_load_xml (path, "filters.xml");
 +		vfolders = emm_load_xml (path, "vfolders.xml");
 +		g_free (path);
 +
 +		if (minor == 0) {
 +			if (!em_migrate_1_0 (data_dir, config_xmldb, filters, vfolders, error)) {
 +				xmlFreeDoc (config_xmldb);
 +				xmlFreeDoc (filters);
 +				xmlFreeDoc (vfolders);
 +				return FALSE;
 +			}
 +		}
 +
 +		if (minor <= 2) {
 +			if (!em_migrate_1_2 (data_dir, config_xmldb, filters, vfolders, error)) {
 +				xmlFreeDoc (config_xmldb);
 +				xmlFreeDoc (filters);
 +				xmlFreeDoc (vfolders);
 +				return FALSE;
 +			}
 +
 +			xmlFreeDoc (config_xmldb);
 +		}
 +
 +		if (minor <= 4) {
 +			if (!em_migrate_1_4 (data_dir, filters, vfolders, error)) {
 +				xmlFreeDoc (filters);
 +				xmlFreeDoc (vfolders);
 +				return FALSE;
 +			}
 +		}
 +
 +		if (filters) {
 +			emm_save_xml (filters, path, "filters.xml");
 +			xmlFreeDoc (filters);
 +		}
 +
 +		if (vfolders) {
 +			emm_save_xml (vfolders, path, "vfolders.xml");
 +			xmlFreeDoc (vfolders);
 +		}
 +
 +		g_free (path);
 +#else
 +		g_error ("Upgrading from ancient versions not supported on Windows");
 +#endif
 +	}
 +
 +	if (major < 2 || (major == 2 && minor < 12)) {
 +#ifndef G_OS_WIN32
 +		em_update_accounts_2_11 ();
 +#else
 +		g_error ("Upgrading from ancient versions not supported on Windows");
 +#endif
 +	}
 +
 +
 +	if (major < 2 || (major == 2 && minor < 22))
 +		em_update_message_notify_settings_2_21 ();
 +
 +	if (major < 2 || (major == 2 && minor < 24)) {
 +		em_update_sa_junk_setting_2_23 ();
 +		migrate_to_db (shell_backend);
 +	}
 +
 +	return TRUE;
 +}
diff --cc mail/e-mail-shell-migrate.h
index c5fb08f,0000000..8f3057e
mode 100644,000000..100644
--- a/mail/e-mail-shell-migrate.h
+++ b/mail/e-mail-shell-migrate.h
@@@ -1,38 -1,0 +1,38 @@@
 +/*
 + * e-mail-shell-migrate.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_MAIL_SHELL_BACKEND_MIGRATE_H
 +#define E_MAIL_SHELL_BACKEND_MIGRATE_H
 +
 +#include <glib.h>
 +#include <shell/e-shell-backend.h>
 +
 +G_BEGIN_DECLS
 +
 +gboolean	e_mail_shell_migrate		(EShellBackend *shell_backend,
 +						 gint major,
 +						 gint minor,
 +						 gint micro,
 +						 GError **error);
 +
 +G_END_DECLS
 +
 +#endif /* E_MAIL_SHELL_BACKEND_MIGRATE_H */
diff --cc mail/e-mail-shell-sidebar.c
index 6f6bdf7,0000000..1b090fa
mode 100644,000000..100644
--- a/mail/e-mail-shell-sidebar.c
+++ b/mail/e-mail-shell-sidebar.c
@@@ -1,347 -1,0 +1,347 @@@
 +/*
 + * e-mail-shell-sidebar.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-mail-shell-sidebar.h"
 +
 +#include <string.h>
 +#include <camel/camel.h>
 +
 +#include "em-utils.h"
 +#include "em-folder-utils.h"
 +
 +#include "e-mail-shell-backend.h"
 +
 +#define E_MAIL_SHELL_SIDEBAR_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_MAIL_SHELL_SIDEBAR, EMailShellSidebarPrivate))
 +
 +struct _EMailShellSidebarPrivate {
 +	GtkWidget *folder_tree;
 +};
 +
 +enum {
 +	PROP_0,
 +	PROP_FOLDER_TREE
 +};
 +
 +static gpointer parent_class;
 +static GType mail_shell_sidebar_type;
 +
 +static void
 +mail_shell_sidebar_selection_changed_cb (EShellSidebar *shell_sidebar,
 +                                         GtkTreeSelection *selection)
 +{
 +	EShellView *shell_view;
 +	EShellViewClass *shell_view_class;
 +	GtkTreeModel *model;
 +	GtkTreeIter iter;
 +	const gchar *icon_name;
 +	gchar *display_name = NULL;
 +	gboolean is_folder = FALSE;
 +	guint flags = 0;
 +
 +	shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
 +	shell_view_class = E_SHELL_VIEW_GET_CLASS (shell_view);
 +
 +	if (gtk_tree_selection_get_selected (selection, &model, &iter))
 +		gtk_tree_model_get (
 +			model, &iter,
 +			COL_STRING_DISPLAY_NAME, &display_name,
 +			COL_BOOL_IS_FOLDER, &is_folder,
 +			COL_UINT_FLAGS, &flags, -1);
 +
 +	if (is_folder)
 +		icon_name = em_folder_utils_get_icon_name (flags);
 +	else {
 +		icon_name = shell_view_class->icon_name;
 +		display_name = g_strdup (shell_view_class->label);
 +	}
 +
 +	e_shell_sidebar_set_icon_name (shell_sidebar, icon_name);
 +	e_shell_sidebar_set_primary_text (shell_sidebar, display_name);
 +
 +	g_free (display_name);
 +}
 +
 +static void
 +mail_shell_sidebar_get_property (GObject *object,
 +                                 guint property_id,
 +                                 GValue *value,
 +                                 GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_FOLDER_TREE:
 +			g_value_set_object (
 +				value, e_mail_shell_sidebar_get_folder_tree (
 +				E_MAIL_SHELL_SIDEBAR (object)));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +mail_shell_sidebar_dispose (GObject *object)
 +{
 +	EMailShellSidebarPrivate *priv;
 +
 +	priv = E_MAIL_SHELL_SIDEBAR_GET_PRIVATE (object);
 +
 +	if (priv->folder_tree != NULL) {
 +		g_object_unref (priv->folder_tree);
 +		priv->folder_tree = NULL;
 +	}
 +
 +	/* Chain up to parent's dispose() method. */
 +	G_OBJECT_CLASS (parent_class)->dispose (object);
 +}
 +
 +static void
 +mail_shell_sidebar_finalize (GObject *object)
 +{
 +	EMailShellSidebarPrivate *priv;
 +
 +	priv = E_MAIL_SHELL_SIDEBAR_GET_PRIVATE (object);
 +
 +	/* Chain up to parent's finalize() method. */
 +	G_OBJECT_CLASS (parent_class)->finalize (object);
 +}
 +
 +static void
 +mail_shell_sidebar_constructed (GObject *object)
 +{
 +	EMailShellSidebarPrivate *priv;
 +	EMailShellBackend *mail_shell_backend;
 +	EShellSidebar *shell_sidebar;
 +	EShellBackend *shell_backend;
 +	EShellView *shell_view;
 +	GtkTreeSelection *selection;
 +	GtkTreeView *tree_view;
 +	GtkWidget *container;
 +	GtkWidget *widget;
 +
 +	priv = E_MAIL_SHELL_SIDEBAR_GET_PRIVATE (object);
 +
 +	/* Chain up to parent's constructed method. */
 +	G_OBJECT_CLASS (parent_class)->constructed (object);
 +
 +	shell_sidebar = E_SHELL_SIDEBAR (object);
 +	shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
 +	shell_backend = e_shell_view_get_shell_backend (shell_view);
 +	mail_shell_backend = E_MAIL_SHELL_BACKEND (shell_backend);
 +
 +	/* Build sidebar widgets. */
 +
 +	container = GTK_WIDGET (object);
 +
 +	widget = gtk_scrolled_window_new (NULL, NULL);
 +	gtk_scrolled_window_set_policy (
 +		GTK_SCROLLED_WINDOW (widget),
 +		GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
 +	gtk_scrolled_window_set_shadow_type (
 +		GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
 +	gtk_container_add (GTK_CONTAINER (container), widget);
 +	gtk_widget_show (widget);
 +
 +	container = widget;
 +
 +	widget = em_folder_tree_new (mail_shell_backend);
 +	em_folder_tree_set_excluded (EM_FOLDER_TREE (widget), 0);
 +	em_folder_tree_enable_drag_and_drop (EM_FOLDER_TREE (widget));
 +	gtk_container_add (GTK_CONTAINER (container), widget);
 +	priv->folder_tree = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	tree_view = GTK_TREE_VIEW (priv->folder_tree);
 +	selection = gtk_tree_view_get_selection (tree_view);
 +
 +	g_signal_connect_swapped (
 +		selection, "changed",
 +		G_CALLBACK (mail_shell_sidebar_selection_changed_cb),
 +		shell_sidebar);
 +}
 +
 +static guint32
 +mail_shell_sidebar_check_state (EShellSidebar *shell_sidebar)
 +{
 +	EMailShellBackend *mail_shell_backend;
 +	EMailShellSidebar *mail_shell_sidebar;
 +	EShellBackend *shell_backend;
 +	EShellView *shell_view;
 +	EMFolderTree *folder_tree;
 +	GtkTreeSelection *selection;
 +	GtkTreeView *tree_view;
 +	GtkTreeModel *model;
 +	GtkTreeIter iter;
 +	CamelFolder *folder;
 +	CamelStore *local_store;
 +	CamelStore *store;
 +	gchar *full_name;
 +	gchar *uri;
 +	gboolean allows_children = TRUE;
 +	gboolean can_delete = TRUE;
 +	gboolean is_junk = FALSE;
 +	gboolean is_outbox = FALSE;
 +	gboolean is_store;
 +	gboolean is_trash = FALSE;
 +	guint32 folder_flags = 0;
 +	guint32 state = 0;
 +
 +	shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
 +	shell_backend = e_shell_view_get_shell_backend (shell_view);
 +
 +	mail_shell_backend = E_MAIL_SHELL_BACKEND (shell_backend);
 +	local_store = e_mail_shell_backend_get_local_store (mail_shell_backend);
 +
 +	mail_shell_sidebar = E_MAIL_SHELL_SIDEBAR (shell_sidebar);
 +	folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
 +	tree_view = GTK_TREE_VIEW (folder_tree);
 +
 +	selection = gtk_tree_view_get_selection (tree_view);
 +	if (!gtk_tree_selection_get_selected (selection, &model, &iter))
 +		return 0;
 +
 +	gtk_tree_model_get (
 +		model, &iter,
 +		COL_POINTER_CAMEL_STORE, &store,
 +		COL_STRING_FULL_NAME, &full_name,
 +		COL_BOOL_IS_STORE, &is_store,
 +		COL_UINT_FLAGS, &folder_flags,
 +		COL_STRING_URI, &uri, -1);
 +
 +	if (!is_store) {
 +		is_junk = (strcmp (full_name, CAMEL_VJUNK_NAME) == 0);
 +		is_trash = (strcmp (full_name, CAMEL_VTRASH_NAME) == 0);
 +		allows_children = !(is_junk || is_trash);
 +
 +		/* Don't allow deletion of special local folders. */
 +		if (store == local_store)
 +			can_delete =
 +				(strcmp (full_name, "Drafts") != 0) &&
 +				(strcmp (full_name, "Inbox") != 0) &&
 +				(strcmp (full_name, "Outbox") != 0) &&
 +				(strcmp (full_name, "Sent") != 0) &&
 +				(strcmp (full_name, "Templates") != 0);
 +
 +		folder = em_folder_tree_get_selected_folder (folder_tree);
 +		is_outbox = em_utils_folder_is_outbox (folder, NULL);
 +		can_delete &= !(folder_flags & CAMEL_FOLDER_SYSTEM);
 +	}
 +
 +	if (allows_children)
 +		state |= E_MAIL_SHELL_SIDEBAR_FOLDER_ALLOWS_CHILDREN;
 +	if (can_delete)
 +		state |= E_MAIL_SHELL_SIDEBAR_FOLDER_CAN_DELETE;
 +	if (is_junk)
 +		state |= E_MAIL_SHELL_SIDEBAR_FOLDER_IS_JUNK;
 +	if (is_outbox)
 +		state |= E_MAIL_SHELL_SIDEBAR_FOLDER_IS_OUTBOX;
 +	if (is_store)
 +		state |= E_MAIL_SHELL_SIDEBAR_FOLDER_IS_STORE;
 +	if (is_trash)
 +		state |= E_MAIL_SHELL_SIDEBAR_FOLDER_IS_TRASH;
 +
 +	return state;
 +}
 +
 +static void
 +mail_shell_sidebar_class_init (EMailShellSidebarClass *class)
 +{
 +	GObjectClass *object_class;
 +	EShellSidebarClass *shell_sidebar_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (EMailShellSidebarPrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->get_property = mail_shell_sidebar_get_property;
 +	object_class->dispose = mail_shell_sidebar_dispose;
 +	object_class->finalize = mail_shell_sidebar_finalize;
 +	object_class->constructed = mail_shell_sidebar_constructed;
 +
 +	shell_sidebar_class = E_SHELL_SIDEBAR_CLASS (class);
 +	shell_sidebar_class->check_state = mail_shell_sidebar_check_state;
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_FOLDER_TREE,
 +		g_param_spec_object (
 +			"folder-tree",
 +			NULL,
 +			NULL,
 +			EM_TYPE_FOLDER_TREE,
 +			G_PARAM_READABLE));
 +}
 +
 +static void
 +mail_shell_sidebar_init (EMailShellSidebar *mail_shell_sidebar)
 +{
 +	mail_shell_sidebar->priv =
 +		E_MAIL_SHELL_SIDEBAR_GET_PRIVATE (mail_shell_sidebar);
 +
 +	/* Postpone widget construction until we have a shell view. */
 +}
 +
 +GType
 +e_mail_shell_sidebar_get_type (void)
 +{
 +	return mail_shell_sidebar_type;
 +}
 +
 +void
 +e_mail_shell_sidebar_register_type (GTypeModule *type_module)
 +{
 +	static const GTypeInfo type_info = {
 +		sizeof (EMailShellSidebarClass),
 +		(GBaseInitFunc) NULL,
 +		(GBaseFinalizeFunc) NULL,
 +		(GClassInitFunc) mail_shell_sidebar_class_init,
 +		(GClassFinalizeFunc) NULL,
 +		NULL,  /* class_data */
 +		sizeof (EMailShellSidebar),
 +		0,     /* n_preallocs */
 +		(GInstanceInitFunc) mail_shell_sidebar_init,
 +		NULL   /* value_table */
 +	};
 +
 +	mail_shell_sidebar_type = g_type_module_register_type (
 +		type_module, E_TYPE_SHELL_SIDEBAR,
 +		"EMailShellSidebar", &type_info, 0);
 +}
 +
 +GtkWidget *
 +e_mail_shell_sidebar_new (EShellView *shell_view)
 +{
 +	g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
 +
 +	return g_object_new (
 +		E_TYPE_MAIL_SHELL_SIDEBAR,
 +		"shell-view", shell_view, NULL);
 +}
 +
 +EMFolderTree *
 +e_mail_shell_sidebar_get_folder_tree (EMailShellSidebar *mail_shell_sidebar)
 +{
 +	g_return_val_if_fail (
 +		E_IS_MAIL_SHELL_SIDEBAR (mail_shell_sidebar), NULL);
 +
 +	return EM_FOLDER_TREE (mail_shell_sidebar->priv->folder_tree);
 +}
diff --cc mail/e-mail-shell-sidebar.h
index 5075225,0000000..10a2ff6
mode 100644,000000..100644
--- a/mail/e-mail-shell-sidebar.h
+++ b/mail/e-mail-shell-sidebar.h
@@@ -1,81 -1,0 +1,81 @@@
 +/*
 + * e-mail-shell-sidebar.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_MAIL_SHELL_SIDEBAR_H
 +#define E_MAIL_SHELL_SIDEBAR_H
 +
 +#include <shell/e-shell-sidebar.h>
 +#include <shell/e-shell-view.h>
 +#include <mail/em-folder-tree.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_MAIL_SHELL_SIDEBAR \
 +	(e_mail_shell_sidebar_get_type ())
 +#define E_MAIL_SHELL_SIDEBAR(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_MAIL_SHELL_SIDEBAR, EMailShellSidebar))
 +#define E_MAIL_SHELL_SIDEBAR_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_MAIL_SHELL_SIDEBAR, EMailShellSidebarClass))
 +#define E_IS_MAIL_SHELL_SIDEBAR(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_MAIL_SHELL_SIDEBAR))
 +#define E_IS_MAIL_SHELL_SIDEBAR_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_MAIL_SHELL_SIDEBAR))
 +#define E_MAIL_SHELL_SIDEBAR_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_MAIL_SHELL_SIDEBAR, EMailShellSidebarClass))
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _EMailShellSidebar EMailShellSidebar;
 +typedef struct _EMailShellSidebarClass EMailShellSidebarClass;
 +typedef struct _EMailShellSidebarPrivate EMailShellSidebarPrivate;
 +
 +enum {
 +	E_MAIL_SHELL_SIDEBAR_FOLDER_ALLOWS_CHILDREN	= 1 << 0,
 +	E_MAIL_SHELL_SIDEBAR_FOLDER_CAN_DELETE		= 1 << 1,
 +	E_MAIL_SHELL_SIDEBAR_FOLDER_IS_JUNK		= 1 << 2,
 +	E_MAIL_SHELL_SIDEBAR_FOLDER_IS_OUTBOX		= 1 << 3,
 +	E_MAIL_SHELL_SIDEBAR_FOLDER_IS_STORE		= 1 << 4,
 +	E_MAIL_SHELL_SIDEBAR_FOLDER_IS_TRASH		= 1 << 5
 +};
 +
 +struct _EMailShellSidebar {
 +	EShellSidebar parent;
 +	EMailShellSidebarPrivate *priv;
 +};
 +
 +struct _EMailShellSidebarClass {
 +	EShellSidebarClass parent_class;
 +};
 +
 +GType		e_mail_shell_sidebar_get_type	(void);
 +void		e_mail_shell_sidebar_register_type
 +					(GTypeModule *type_module);
 +GtkWidget *	e_mail_shell_sidebar_new(EShellView *shell_view);
 +EMFolderTree *	e_mail_shell_sidebar_get_folder_tree
 +					(EMailShellSidebar *mail_shell_sidebar);
 +
 +G_END_DECLS
 +
 +#endif /* E_MAIL_SHELL_SIDEBAR_H */
diff --cc mail/e-mail-shell-view-actions.c
index 33d497c,0000000..3d0b76d
mode 100644,000000..100644
--- a/mail/e-mail-shell-view-actions.c
+++ b/mail/e-mail-shell-view-actions.c
@@@ -1,1713 -1,0 +1,1713 @@@
 +/*
 + * e-mail-shell-view-actions.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-mail-shell-view-private.h"
 +
 +static void
 +action_gal_save_custom_view_cb (GtkAction *action,
 +                                EMailShellView *mail_shell_view)
 +{
 +	EMailShellContent *mail_shell_content;
 +	EShellView *shell_view;
 +	GalViewInstance *view_instance;
 +
 +	/* All shell views repond to the activation of this action,
 +	 * which is defined by EShellWindow.  But only the currently
 +	 * active shell view proceeds with saving the custom view. */
 +	shell_view = E_SHELL_VIEW (mail_shell_view);
 +	if (!e_shell_view_is_active (shell_view))
 +		return;
 +
 +	mail_shell_content = mail_shell_view->priv->mail_shell_content;
 +	view_instance = e_mail_shell_content_get_view_instance (mail_shell_content);
 +	gal_view_instance_save_as (view_instance);
 +}
 +
 +static void
 +action_mail_account_disable_cb (GtkAction *action,
 +                                EMailShellView *mail_shell_view)
 +{
 +	EMailShellBackend *mail_shell_backend;
 +	EMailShellSidebar *mail_shell_sidebar;
 +	EMFolderTree *folder_tree;
 +	EAccountList *account_list;
 +	EAccount *account;
 +	gchar *folder_uri;
 +
 +	mail_shell_backend = mail_shell_view->priv->mail_shell_backend;
 +	mail_shell_sidebar = mail_shell_view->priv->mail_shell_sidebar;
 +
 +	folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
 +	folder_uri = em_folder_tree_get_selected_uri (folder_tree);
 +	g_return_if_fail (folder_uri != NULL);
 +
 +	account_list = e_get_account_list ();
 +	account = mail_config_get_account_by_source_url (folder_uri);
 +	g_return_if_fail (account != NULL);
 +
 +	if (e_account_list_account_has_proxies (account_list, account))
 +		e_account_list_remove_account_proxies (account_list, account);
 +
 +	account->enabled = !account->enabled;
 +	e_account_list_change (account_list, account);
 +	e_mail_shell_backend_remove_store_by_uri (
 +		mail_shell_backend, folder_uri);
 +
 +	if (account->parent_uid != NULL)
 +		e_account_list_remove (account_list, account);
 +
 +	e_account_list_save (account_list);
 +
 +	g_free (folder_uri);
 +}
 +
 +static void
 +action_mail_create_search_folder_cb (GtkAction *action,
 +                                     EMailShellView *mail_shell_view)
 +{
 +	/* FIXME */
 +	g_print ("Action: %s\n", gtk_action_get_name (GTK_ACTION (action)));
 +}
 +
 +static void
 +action_mail_download_foreach_cb (CamelService *service)
 +{
 +	if (CAMEL_IS_DISCO_STORE (service) ||
 +		CAMEL_IS_OFFLINE_STORE (service))
 +		mail_store_prepare_offline (CAMEL_STORE (service));
 +}
 +
 +static void
 +action_mail_download_cb (GtkAction *action,
 +                         EMailShellView *mail_shell_view)
 +{
 +	EMailShellBackend *mail_shell_backend;
 +
 +	mail_shell_backend = mail_shell_view->priv->mail_shell_backend;
 +
 +	e_mail_shell_backend_stores_foreach (
 +		mail_shell_backend, (GHFunc)
 +		action_mail_download_foreach_cb, NULL);
 +}
 +
 +static void
 +action_mail_empty_trash_cb (GtkAction *action,
 +                            EMailShellView *mail_shell_view)
 +{
 +	EShellWindow *shell_window;
 +	EShellView *shell_view;
 +
 +	shell_view = E_SHELL_VIEW (mail_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	em_utils_empty_trash (GTK_WIDGET (shell_window));
 +}
 +
 +static void
 +action_mail_flush_outbox_cb (GtkAction *action,
 +                             EMailShellView *mail_shell_view)
 +{
 +	mail_send ();
 +}
 +
 +static void
 +action_mail_folder_copy_cb (GtkAction *action,
 +                            EMailShellView *mail_shell_view)
 +{
 +	EMailShellSidebar *mail_shell_sidebar;
 +	CamelFolderInfo *folder_info;
 +	EMFolderTree *folder_tree;
 +
 +	mail_shell_sidebar = mail_shell_view->priv->mail_shell_sidebar;
 +	folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
 +	folder_info = em_folder_tree_get_selected_folder_info (folder_tree);
 +	g_return_if_fail (folder_info != NULL);
 +
 +	/* XXX Leaking folder_info? */
 +	em_folder_utils_copy_folder (folder_info, FALSE);
 +}
 +
 +static void
 +action_mail_folder_delete_cb (GtkAction *action,
 +                              EMailShellView *mail_shell_view)
 +{
 +	EMailShellSidebar *mail_shell_sidebar;
 +	EMFolderTree *folder_tree;
 +	CamelFolder *folder;
 +
 +	mail_shell_sidebar = mail_shell_view->priv->mail_shell_sidebar;
 +	folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
 +	folder = em_folder_tree_get_selected_folder (folder_tree);
 +	g_return_if_fail (folder != NULL);
 +
 +	em_folder_utils_delete_folder (folder);
 +}
 +
 +static void
 +action_mail_folder_expunge_cb (GtkAction *action,
 +                               EMailShellView *mail_shell_view)
 +{
 +	EMailReader *reader;
 +	MessageList *message_list;
 +	EShellWindow *shell_window;
 +	EShellView *shell_view;
 +
 +	shell_view = E_SHELL_VIEW (mail_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
 +	message_list = e_mail_reader_get_message_list (reader);
 +	g_return_if_fail (message_list->folder != NULL);
 +
 +	em_utils_expunge_folder (
 +		GTK_WIDGET (shell_window), message_list->folder);
 +}
 +
 +static void
 +action_mail_folder_mark_all_as_read_cb (GtkAction *action,
 +                                        EMailShellView *mail_shell_view)
 +{
 +	EMailReader *reader;
 +	MessageList *message_list;
 +	EShellWindow *shell_window;
 +	EShellView *shell_view;
 +	CamelFolder *folder;
 +	GtkWindow *parent;
 +	GPtrArray *uids;
 +	const gchar *key;
 +	const gchar *prompt;
 +	guint ii;
 +
 +	shell_view = E_SHELL_VIEW (mail_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +	parent = GTK_WINDOW (shell_window);
 +
 +	reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
 +	message_list = e_mail_reader_get_message_list (reader);
 +	folder = message_list->folder;
 +	g_return_if_fail (folder != NULL);
 +
 +	key = "/apps/evolution/mail/prompts/mark_all_read";
 +	prompt = "mail:ask-mark-all-read";
 +
 +	if (!em_utils_prompt_user (parent, key, prompt, NULL))
 +		return;
 +
 +	uids = message_list_get_uids (message_list);
 +
 +	camel_folder_freeze (folder);
 +	for (ii = 0; ii < uids->len; ii++)
 +		camel_folder_set_message_flags (
 +			folder, uids->pdata[ii],
 +			CAMEL_MESSAGE_SEEN, CAMEL_MESSAGE_SEEN);
 +	camel_folder_thaw (folder);
 +
 +	message_list_free_uids (message_list, uids);
 +}
 +
 +static void
 +action_mail_folder_move_cb (GtkAction *action,
 +                            EMailShellView *mail_shell_view)
 +{
 +	EMailShellSidebar *mail_shell_sidebar;
 +	CamelFolderInfo *folder_info;
 +	EMFolderTree *folder_tree;
 +
 +	mail_shell_sidebar = mail_shell_view->priv->mail_shell_sidebar;
 +	folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
 +	folder_info = em_folder_tree_get_selected_folder_info (folder_tree);
 +	g_return_if_fail (folder_info != NULL);
 +
 +	/* XXX Leaking folder_info? */
 +	em_folder_utils_copy_folder (folder_info, TRUE);
 +}
 +
 +static void
 +action_mail_folder_new_cb (GtkAction *action,
 +                           EMailShellView *mail_shell_view)
 +{
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	EMailShellSidebar *mail_shell_sidebar;
 +	CamelFolderInfo *folder_info;
 +	EMFolderTree *folder_tree;
 +
 +	shell_view = E_SHELL_VIEW (mail_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	mail_shell_sidebar = mail_shell_view->priv->mail_shell_sidebar;
 +	folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
 +	folder_info = em_folder_tree_get_selected_folder_info (folder_tree);
 +	g_return_if_fail (folder_info != NULL);
 +
 +	em_folder_utils_create_folder (
 +		folder_info, folder_tree, GTK_WINDOW (shell_window));
 +	camel_folder_info_free (folder_info);
 +}
 +
 +static void
 +action_mail_folder_properties_cb (GtkAction *action,
 +                                  EMailShellView *mail_shell_view)
 +{
 +	EMailShellSidebar *mail_shell_sidebar;
 +	EMFolderTree *folder_tree;
 +	EShellView *shell_view;
 +	GtkTreeSelection *selection;
 +	GtkTreeView *tree_view;
 +	GtkTreeModel *model;
 +	GtkTreeIter iter;
 +	gchar *uri;
 +
 +	shell_view = E_SHELL_VIEW (mail_shell_view);
 +	mail_shell_sidebar = mail_shell_view->priv->mail_shell_sidebar;
 +	folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
 +
 +	tree_view = GTK_TREE_VIEW (folder_tree);
 +	selection = gtk_tree_view_get_selection (tree_view);
 +	if (!gtk_tree_selection_get_selected (selection, &model, &iter))
 +		return;
 +
 +	gtk_tree_model_get (model, &iter, COL_STRING_URI, &uri, -1);
 +	em_folder_properties_show (shell_view, NULL, uri);
 +	g_free (uri);
 +}
 +
 +static void
 +action_mail_folder_refresh_cb (GtkAction *action,
 +                               EMailShellView *mail_shell_view)
 +{
 +	EMailShellSidebar *mail_shell_sidebar;
 +	EMFolderTree *folder_tree;
 +	CamelFolder *folder;
 +
 +	mail_shell_sidebar = mail_shell_view->priv->mail_shell_sidebar;
 +	folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
 +	folder = em_folder_tree_get_selected_folder (folder_tree);
 +	g_return_if_fail (folder != NULL);
 +
 +	mail_refresh_folder (folder, NULL, NULL);
 +}
 +
 +static void
 +action_mail_folder_rename_cb (GtkAction *action,
 +                              EMailShellView *mail_shell_view)
 +{
 +	EMailShellSidebar *mail_shell_sidebar;
 +	EMFolderTree *folder_tree;
 +	CamelFolder *folder;
 +
 +	mail_shell_sidebar = mail_shell_view->priv->mail_shell_sidebar;
 +	folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
 +	folder = em_folder_tree_get_selected_folder (folder_tree);
 +	g_return_if_fail (folder != NULL);
 +
 +	em_folder_utils_rename_folder (folder);
 +}
 +
 +/* Helper for action_mail_folder_select_all_cb() */
 +static gboolean
 +action_mail_folder_select_all_timeout_cb (MessageList *message_list)
 +{
 +	message_list_select_all (message_list);
 +	gtk_widget_grab_focus (GTK_WIDGET (message_list));
 +
 +	return FALSE;
 +}
 +
 +static void
 +action_mail_folder_select_all_cb (GtkAction *action,
 +                                  EMailShellView *mail_shell_view)
 +{
 +	EMailReader *reader;
 +	MessageList *message_list;
 +	EShellWindow *shell_window;
 +	EShellView *shell_view;
 +
 +	shell_view = E_SHELL_VIEW (mail_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
 +	message_list = e_mail_reader_get_message_list (reader);
 +
 +	if (message_list->threaded) {
 +		gtk_action_activate (ACTION (MAIL_THREADS_EXPAND_ALL));
 +
 +		/* XXX The timeout below is added so that the execution
 +		 *     thread to expand all conversation threads would
 +		 *     have completed.  The timeout 505 is just to ensure
 +		 *     that the value is a small delta more than the
 +		 *     timeout value in mail_regen_list(). */
 +		g_timeout_add (
 +			505, (GSourceFunc)
 +			action_mail_folder_select_all_timeout_cb,
 +			message_list);
 +	} else
 +		/* If there is no threading, just select all immediately. */
 +		action_mail_folder_select_all_timeout_cb (message_list);
 +}
 +
 +static void
 +action_mail_folder_select_thread_cb (GtkAction *action,
 +                                     EMailShellView *mail_shell_view)
 +{
 +	MessageList *message_list;
 +	EMailReader *reader;
 +
 +	reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
 +	message_list = e_mail_reader_get_message_list (reader);
 +
 +	message_list_select_thread (message_list);
 +}
 +
 +static void
 +action_mail_folder_select_subthread_cb (GtkAction *action,
 +                                        EMailShellView *mail_shell_view)
 +{
 +	MessageList *message_list;
 +	EMailReader *reader;
 +
 +	reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
 +	message_list = e_mail_reader_get_message_list (reader);
 +
 +	message_list_select_subthread (message_list);
 +}
 +
 +static void
 +action_mail_hide_deleted_cb (GtkToggleAction *action,
 +                             EMailShellView *mail_shell_view)
 +{
 +	MessageList *message_list;
 +	EMailReader *reader;
 +	gboolean active;
 +
 +	reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
 +	message_list = e_mail_reader_get_message_list (reader);
 +
 +	active = gtk_toggle_action_get_active (action);
 +	message_list_set_hidedeleted (message_list, active);
 +}
 +
 +static void
 +action_mail_hide_read_cb (GtkAction *action,
 +                          EMailShellView *mail_shell_view)
 +{
 +	MessageList *message_list;
 +	EMailReader *reader;
 +
 +	reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
 +	message_list = e_mail_reader_get_message_list (reader);
 +
 +	message_list_hide_add (
 +		message_list,
 +		"(match-all (system-flag \"seen\"))",
 +		ML_HIDE_SAME, ML_HIDE_SAME);
 +}
 +
 +static void
 +action_mail_hide_selected_cb (GtkAction *action,
 +                              EMailShellView *mail_shell_view)
 +{
 +	MessageList *message_list;
 +	EMailReader *reader;
 +	GPtrArray *uids;
 +
 +	reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
 +	message_list = e_mail_reader_get_message_list (reader);
 +
 +	uids = message_list_get_selected (message_list);
 +	message_list_hide_uids (message_list, uids);
 +	message_list_free_uids (message_list, uids);
 +}
 +
 +static void
 +action_mail_label_cb (GtkToggleAction *action,
 +                      EMailShellView *mail_shell_view)
 +{
 +	EMailReader *reader;
 +	MessageList *message_list;
 +	CamelFolder *folder;
 +	GPtrArray *uids;
 +	const gchar *tag;
 +	gint ii;
 +
 +	tag = g_object_get_data (G_OBJECT (action), "tag");
 +	g_return_if_fail (tag != NULL);
 +
 +	reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
 +	message_list = e_mail_reader_get_message_list (reader);
 +	folder = message_list->folder;
 +
 +	uids = message_list_get_selected (message_list);
 +
 +	for (ii = 0; ii < uids->len; ii++) {
 +		if (gtk_toggle_action_get_active (action))
 +			camel_folder_set_message_user_flag (
 +				folder, uids->pdata[ii], tag, TRUE);
 +		else {
 +			camel_folder_set_message_user_flag (
 +				folder, uids->pdata[ii], tag, FALSE);
 +			camel_folder_set_message_user_tag (
 +				folder, uids->pdata[ii], "label", NULL);
 +		}
 +	}
 +
 +	message_list_free_uids (message_list, uids);
 +}
 +
 +static void
 +action_mail_label_new_cb (GtkAction *action,
 +                          EMailShellView *mail_shell_view)
 +{
 +	EShell *shell;
 +	EShellSettings *shell_settings;
 +	EShellWindow *shell_window;
 +	EShellView *shell_view;
 +	EMailLabelDialog *label_dialog;
 +	EMailLabelListStore *store;
 +	EMailReader *reader;
 +	MessageList *message_list;
 +	CamelFolder *folder;
 +	GtkTreeModel *model;
 +	GtkTreeIter iter;
 +	GtkWidget *dialog;
 +	GPtrArray *uids;
 +	GdkColor label_color;
 +	const gchar *property_name;
 +	const gchar *label_name;
 +	gchar *label_tag;
 +	gint n_children;
 +	guint ii;
 +
 +	shell_view = E_SHELL_VIEW (mail_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	dialog = e_mail_label_dialog_new (GTK_WINDOW (shell_window));
 +
 +	gtk_window_set_title (GTK_WINDOW (dialog), _("Add Label"));
 +
 +	if (gtk_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_OK)
 +		goto exit;
 +
 +	shell = e_shell_window_get_shell (shell_window);
 +	shell_settings = e_shell_get_shell_settings (shell);
 +
 +	label_dialog = E_MAIL_LABEL_DIALOG (dialog);
 +	label_name = e_mail_label_dialog_get_label_name (label_dialog);
 +	e_mail_label_dialog_get_label_color (label_dialog, &label_color);
 +
 +	property_name = "mail-label-list-store";
 +	store = e_shell_settings_get_object (shell_settings, property_name);
 +	e_mail_label_list_store_set (store, NULL, label_name, &label_color);
 +	g_object_unref (store);
 +
 +	/* XXX This is awkward.  We've added a new label to the list store
 +	 *     but we don't have the new label's tag nor an iterator to use
 +	 *     to fetch it.  We know the label was appended to the store,
 +	 *     so we have to dig it out manually.  EMailLabelListStore API
 +	 *     probably needs some rethinking. */
 +	model = GTK_TREE_MODEL (store);
 +	n_children = gtk_tree_model_iter_n_children (model, NULL);
 +	gtk_tree_model_iter_nth_child (model, &iter, NULL, n_children - 1);
 +	label_tag = e_mail_label_list_store_get_tag (store, &iter);
 +
 +	reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
 +	message_list = e_mail_reader_get_message_list (reader);
 +	folder = message_list->folder;
 +
 +	uids = message_list_get_selected (message_list);
 +
 +	for (ii = 0; ii < uids->len; ii++)
 +		camel_folder_set_message_user_flag (
 +			folder, uids->pdata[ii], label_tag, TRUE);
 +
 +	message_list_free_uids (message_list, uids);
 +
 +	g_free (label_tag);
 +
 +exit:
 +	gtk_widget_destroy (dialog);
 +}
 +
 +static void
 +action_mail_label_none_cb (GtkAction *action,
 +                           EMailShellView *mail_shell_view)
 +{
 +	EShell *shell;
 +	EShellView *shell_view;
 +	EShellSettings *shell_settings;
 +	EShellWindow *shell_window;
 +	EMailReader *reader;
 +	MessageList *message_list;
 +	GtkTreeModel *tree_model;
 +	CamelFolder *folder;
 +	GtkTreeIter iter;
 +	GPtrArray *uids;
 +	gboolean valid;
 +	guint ii;
 +
 +	shell_view = E_SHELL_VIEW (mail_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +	shell = e_shell_window_get_shell (shell_window);
 +	shell_settings = e_shell_get_shell_settings (shell);
 +
 +	tree_model = e_shell_settings_get_object (
 +		shell_settings, "mail-label-list-store");
 +
 +	reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
 +	message_list = e_mail_reader_get_message_list (reader);
 +	uids = message_list_get_selected (message_list);
 +	folder = message_list->folder;
 +
 +	valid = gtk_tree_model_get_iter_first (tree_model, &iter);
 +
 +	while (valid) {
 +		gchar *tag;
 +
 +		tag = e_mail_label_list_store_get_tag (
 +			E_MAIL_LABEL_LIST_STORE (tree_model), &iter);
 +
 +		for (ii = 0; ii < uids->len; ii++) {
 +			camel_folder_set_message_user_flag (
 +				folder, uids->pdata[ii], tag, FALSE);
 +			camel_folder_set_message_user_tag (
 +				folder, uids->pdata[ii], "label", NULL);
 +		}
 +
 +		g_free (tag);
 +
 +		valid = gtk_tree_model_iter_next (tree_model, &iter);
 +	}
 +
 +	message_list_free_uids (message_list, uids);
 +}
 +
 +static void
 +action_mail_preview_cb (GtkToggleAction *action,
 +                        EMailShellView *mail_shell_view)
 +{
 +	EMailShellContent *mail_shell_content;
 +	gboolean active;
 +
 +	mail_shell_content = mail_shell_view->priv->mail_shell_content;
 +	active = gtk_toggle_action_get_active (action);
 +
 +	e_mail_shell_content_set_preview_visible (mail_shell_content, active);
 +}
 +
 +static void
 +action_mail_show_hidden_cb (GtkAction *action,
 +                            EMailShellView *mail_shell_view)
 +{
 +	MessageList *message_list;
 +	EMailReader *reader;
 +
 +	reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
 +	message_list = e_mail_reader_get_message_list (reader);
 +
 +	message_list_hide_clear (message_list);
 +}
 +
 +static void
 +action_mail_smart_backward_cb (GtkAction *action,
 +                               EMailShellView *mail_shell_view)
 +{
 +	EShell *shell;
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	EShellSettings *shell_settings;
 +	EMailShellSidebar *mail_shell_sidebar;
 +	EMFolderTree *folder_tree;
 +	EMFormatHTMLDisplay *html_display;
 +	EMailReader *reader;
 +	MessageList *message_list;
 +	GtkToggleAction *toggle_action;
 +	GtkHTML *html;
 +	gboolean caret_mode;
 +	gboolean magic_spacebar;
 +
 +	/* This implements the so-called "Magic Backspace". */
 +
 +	shell_view = E_SHELL_VIEW (mail_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +	shell = e_shell_window_get_shell (shell_window);
 +	shell_settings = e_shell_get_shell_settings (shell);
 +
 +	mail_shell_sidebar = mail_shell_view->priv->mail_shell_sidebar;
 +	folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
 +
 +	reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
 +	html_display = e_mail_reader_get_html_display (reader);
 +	message_list = e_mail_reader_get_message_list (reader);
 +
 +	magic_spacebar = e_shell_settings_get_boolean (
 +		shell_settings, "mail-magic-spacebar");
 +
 +	toggle_action = GTK_TOGGLE_ACTION (ACTION (MAIL_CARET_MODE));
 +	caret_mode = gtk_toggle_action_get_active (toggle_action);
 +
 +	html = EM_FORMAT_HTML (html_display)->html;
 +
 +	if (gtk_html_command (html, "scroll-backward"))
 +		return;
 +
 +	if (caret_mode || !magic_spacebar)
 +		return;
 +
 +	/* XXX Are two separate calls really necessary? */
 +
 +	if (message_list_select (
 +		message_list, MESSAGE_LIST_SELECT_PREVIOUS,
 +		0, CAMEL_MESSAGE_SEEN))
 +		return;
 +
 +	if (message_list_select (
 +		message_list, MESSAGE_LIST_SELECT_PREVIOUS |
 +		MESSAGE_LIST_SELECT_WRAP, 0, CAMEL_MESSAGE_SEEN))
 +		return;
 +
 +	em_folder_tree_select_prev_path (folder_tree, TRUE);
 +
 +	gtk_widget_grab_focus (GTK_WIDGET (message_list));
 +}
 +
 +static void
 +action_mail_smart_forward_cb (GtkAction *action,
 +                              EMailShellView *mail_shell_view)
 +{
 +	EShell *shell;
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	EShellSettings *shell_settings;
 +	EMailShellSidebar *mail_shell_sidebar;
 +	EMFolderTree *folder_tree;
 +	EMFormatHTMLDisplay *html_display;
 +	EMailReader *reader;
 +	MessageList *message_list;
 +	GtkToggleAction *toggle_action;
 +	GtkHTML *html;
 +	gboolean caret_mode;
 +	gboolean magic_spacebar;
 +
 +	/* This implements the so-called "Magic Spacebar". */
 +
 +	shell_view = E_SHELL_VIEW (mail_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +	shell = e_shell_window_get_shell (shell_window);
 +	shell_settings = e_shell_get_shell_settings (shell);
 +
 +	mail_shell_sidebar = mail_shell_view->priv->mail_shell_sidebar;
 +	folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
 +
 +	reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
 +	html_display = e_mail_reader_get_html_display (reader);
 +	message_list = e_mail_reader_get_message_list (reader);
 +
 +	magic_spacebar = e_shell_settings_get_boolean (
 +		shell_settings, "mail-magic-spacebar");
 +
 +	toggle_action = GTK_TOGGLE_ACTION (ACTION (MAIL_CARET_MODE));
 +	caret_mode = gtk_toggle_action_get_active (toggle_action);
 +
 +	html = EM_FORMAT_HTML (html_display)->html;
 +
 +	if (gtk_html_command (html, "scroll-forward"))
 +		return;
 +
 +	if (caret_mode || !magic_spacebar)
 +		return;
 +
 +	/* XXX Are two separate calls really necessary? */
 +
 +	if (message_list_select (
 +		message_list, MESSAGE_LIST_SELECT_NEXT,
 +		0, CAMEL_MESSAGE_SEEN))
 +		return;
 +
 +	if (message_list_select (
 +		message_list, MESSAGE_LIST_SELECT_NEXT |
 +		MESSAGE_LIST_SELECT_WRAP, 0, CAMEL_MESSAGE_SEEN))
 +		return;
 +
 +	em_folder_tree_select_next_path (folder_tree, TRUE);
 +
 +	gtk_widget_grab_focus (GTK_WIDGET (message_list));
 +}
 +
 +static void
 +action_mail_stop_cb (GtkAction *action,
 +                     EMailShellView *mail_shell_view)
 +{
 +	mail_cancel_all ();
 +}
 +
 +static void
 +action_mail_threads_collapse_all_cb (GtkAction *action,
 +                                     EMailShellView *mail_shell_view)
 +{
 +	MessageList *message_list;
 +	EMailReader *reader;
 +
 +	reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
 +	message_list = e_mail_reader_get_message_list (reader);
 +
 +	message_list_set_threaded_collapse_all (message_list);
 +}
 +
 +static void
 +action_mail_threads_expand_all_cb (GtkAction *action,
 +                                   EMailShellView *mail_shell_view)
 +{
 +	MessageList *message_list;
 +	EMailReader *reader;
 +
 +	reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
 +	message_list = e_mail_reader_get_message_list (reader);
 +
 +	message_list_set_threaded_expand_all (message_list);
 +}
 +
 +static void
 +action_mail_threads_group_by_cb (GtkToggleAction *action,
 +                                 EMailShellView *mail_shell_view)
 +{
 +	EMailShellContent *mail_shell_content;
 +	MessageList *message_list;
 +	EMailReader *reader;
 +	gboolean active;
 +
 +	mail_shell_content = mail_shell_view->priv->mail_shell_content;
 +	active = gtk_toggle_action_get_active (action);
 +
 +	reader = E_MAIL_READER (mail_shell_content);
 +	message_list = e_mail_reader_get_message_list (reader);
 +
 +	message_list_set_threaded (message_list, active);
 +}
 +
 +static void
 +action_mail_tools_filters_cb (GtkAction *action,
 +                              EMailShellView *mail_shell_view)
 +{
 +	EShellWindow *shell_window;
 +	EShellView *shell_view;
 +
 +	shell_view = E_SHELL_VIEW (mail_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	em_utils_edit_filters (GTK_WIDGET (shell_window));
 +}
 +
 +static void
 +action_mail_tools_search_folders_cb (GtkAction *action,
 +                                     EMailShellView *mail_shell_view)
 +{
 +	vfolder_edit (E_SHELL_VIEW (mail_shell_view));
 +}
 +
 +static void
 +action_mail_tools_subscriptions_cb (GtkAction *action,
 +                                    EMailShellView *mail_shell_view)
 +{
 +	EShellWindow *shell_window;
 +	EShellView *shell_view;
 +	GtkWidget *dialog;
 +
 +	shell_view = E_SHELL_VIEW (mail_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	dialog = em_subscribe_editor_new ();
 +	gtk_window_set_transient_for (
 +		GTK_WINDOW (dialog), GTK_WINDOW (shell_window));
 +	gtk_dialog_run (GTK_DIALOG (dialog));
 +	/* XXX Dialog destroys itself. */
 +}
 +
 +static void
 +action_mail_view_cb (GtkRadioAction *action,
 +                     GtkRadioAction *current,
 +                     EMailShellView *mail_shell_view)
 +{
 +	EMailShellContent *mail_shell_content;
 +	gboolean vertical_view;
 +
 +	mail_shell_content = mail_shell_view->priv->mail_shell_content;
 +	vertical_view = (gtk_radio_action_get_current_value (action) == 1);
 +
 +	e_mail_shell_content_set_vertical_view (
 +		mail_shell_content, vertical_view);
 +}
 +
 +static void
 +action_search_execute_cb (GtkAction *action,
 +                          EMailShellView *mail_shell_view)
 +{
 +	EShellView *shell_view;
 +
 +	/* All shell views respond to the activation of this action,
 +	 * which is defined by EShellWindow.  But only the currently
 +	 * active shell view proceeds with executing the search. */
 +	shell_view = E_SHELL_VIEW (mail_shell_view);
 +	if (!e_shell_view_is_active (shell_view))
 +		return;
 +
 +	e_mail_shell_view_execute_search (mail_shell_view);
 +}
 +
 +static void
 +action_search_filter_cb (GtkRadioAction *action,
 +                         GtkRadioAction *current,
 +                         EMailShellView *mail_shell_view)
 +{
 +	e_mail_shell_view_execute_search (mail_shell_view);
 +}
 +
 +static void
 +action_search_scope_cb (GtkRadioAction *action,
 +                        GtkRadioAction *current,
 +                        EMailShellView *mail_shell_view)
 +{
 +	e_mail_shell_view_execute_search (mail_shell_view);
 +}
 +
 +static GtkActionEntry mail_entries[] = {
 +
 +	{ "mail-account-disable",
 +	  NULL,
 +	  N_("_Disable Account"),
 +	  NULL,
 +	  N_("Disable this account"),
 +	  G_CALLBACK (action_mail_account_disable_cb) },
 +
 +	{ "mail-create-search-folder",
 +	  NULL,
 +	  N_("C_reate Search Folder From Search..."),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  G_CALLBACK (action_mail_create_search_folder_cb) },
 +
 +	{ "mail-download",
 +	  NULL,
 +	  N_("_Download Messages for Offline Usage"),
 +	  NULL,
 +	  N_("Download messages of accounts and folders marked for offline"),
 +	  G_CALLBACK (action_mail_download_cb) },
 +
 +	{ "mail-empty-trash",
 +	  NULL,
 +	  N_("Empty _Trash"),
 +	  NULL,
 +	  N_("Permanently remove all the deleted messages from all folders"),
 +	  G_CALLBACK (action_mail_empty_trash_cb) },
 +
 +	{ "mail-flush-outbox",
 +	  "mail-send",
 +	  N_("Fl_ush Outbox"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  G_CALLBACK (action_mail_flush_outbox_cb) },
 +
 +	{ "mail-folder-copy",
 +	  "folder-copy",
 +	  N_("_Copy Folder To..."),
 +	  NULL,
 +	  N_("Copy the selected folder into another folder"),
 +	  G_CALLBACK (action_mail_folder_copy_cb) },
 +
 +	{ "mail-folder-delete",
 +	  GTK_STOCK_DELETE,
 +	  NULL,
 +	  NULL,
 +	  N_("Permanently remove this folder"),
 +	  G_CALLBACK (action_mail_folder_delete_cb) },
 +
 +	{ "mail-folder-expunge",
 +	  NULL,
 +	  N_("E_xpunge"),
 +	  "<Control>e",
 +	  N_("Permanently remove all deleted messages from this folder"),
 +	  G_CALLBACK (action_mail_folder_expunge_cb) },
 +
 +	{ "mail-folder-mark-all-as-read",
 +	  "mail-read",
 +	  N_("Mar_k All Messages as Read"),
 +	  NULL,
 +	  N_("Mark all messages in the folder as read"),
 +	  G_CALLBACK (action_mail_folder_mark_all_as_read_cb) },
 +
 +	{ "mail-folder-move",
 +	  "folder-move",
 +	  N_("_Move Folder To..."),
 +	  NULL,
 +	  N_("Move the selected folder into another folder"),
 +	  G_CALLBACK (action_mail_folder_move_cb) },
 +
 +	{ "mail-folder-new",
 +	  "folder-new",
 +	  N_("_New..."),
 +	  NULL,
 +	  N_("Create a new folder for storing mail"),
 +	  G_CALLBACK (action_mail_folder_new_cb) },
 +
 +	{ "mail-folder-properties",
 +	  GTK_STOCK_PROPERTIES,
 +	  NULL,
 +	  NULL,
 +	  N_("Change the properties of this folder"),
 +	  G_CALLBACK (action_mail_folder_properties_cb) },
 +
 +	{ "mail-folder-refresh",
 +	  GTK_STOCK_REFRESH,
 +	  NULL,
 +	  "F5",
 +	  N_("Refresh the folder"),
 +	  G_CALLBACK (action_mail_folder_refresh_cb) },
 +
 +	{ "mail-folder-rename",
 +	  NULL,
 +	  N_("_Rename..."),
 +	  "F2",
 +	  N_("Change the name of this folder"),
 +	  G_CALLBACK (action_mail_folder_rename_cb) },
 +
 +	{ "mail-folder-select-all",
 +	  NULL,
 +	  N_("Select _All Messages"),
 +	  "<Control>a",
 +	  N_("Select all visible messages"),
 +	  G_CALLBACK (action_mail_folder_select_all_cb) },
 +
 +	{ "mail-folder-select-thread",
 +	  NULL,
 +	  N_("Select Message _Thread"),
 +	  "<Control>h",
 +	  N_("Select all messages in the same thread as the selected message"),
 +	  G_CALLBACK (action_mail_folder_select_thread_cb) },
 +
 +	{ "mail-folder-select-subthread",
 +	  NULL,
 +	  N_("Select Message S_ubthread"),
 +	  "<Shift><Control>h",
 +	  N_("Select all replies to the currently selected message"),
 +	  G_CALLBACK (action_mail_folder_select_subthread_cb) },
 +
 +	{ "mail-label-new",
 +	  NULL,
 +	  N_("_New Label"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  G_CALLBACK (action_mail_label_new_cb) },
 +
 +	{ "mail-label-none",
 +	  NULL,
 +	  N_("N_one"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  G_CALLBACK (action_mail_label_none_cb) },
 +
 +	{ "mail-hide-read",
 +	  NULL,
 +	  N_("Hide _Read Messages"),
 +	  NULL,
 +	  N_("Temporarily hide all messages that have already been read"),
 +	  G_CALLBACK (action_mail_hide_read_cb) },
 +
 +	{ "mail-hide-selected",
 +	  NULL,
 +	  N_("Hide S_elected Messages"),
 +	  NULL,
 +	  N_("Temporarily hide the selected messages"),
 +	  G_CALLBACK (action_mail_hide_selected_cb) },
 +
 +	{ "mail-show-hidden",
 +	  NULL,
 +	  N_("Show Hidde_n Messages"),
 +	  NULL,
 +	  N_("Show messages that have been temporarily hidden"),
 +	  G_CALLBACK (action_mail_show_hidden_cb) },
 +
 +	{ "mail-smart-backward",
 +	  NULL,
 +	  NULL,  /* No menu item; key press only */
 +	  NULL,
 +	  NULL,
 +	  G_CALLBACK (action_mail_smart_backward_cb) },
 +
 +	{ "mail-smart-forward",
 +	  NULL,
 +	  NULL,  /* No menu item; key press only */
 +	  NULL,
 +	  NULL,
 +	  G_CALLBACK (action_mail_smart_forward_cb) },
 +
 +	{ "mail-stop",
 +	  GTK_STOCK_STOP,
 +	  N_("Cancel"),
 +	  NULL,
 +	  N_("Cancel the current mail operation"),
 +	  G_CALLBACK (action_mail_stop_cb) },
 +
 +	{ "mail-threads-collapse-all",
 +	  NULL,
 +	  N_("Collapse All _Threads"),
 +	  "<Shift><Control>b",
 +	  N_("Collapse all message threads"),
 +	  G_CALLBACK (action_mail_threads_collapse_all_cb) },
 +
 +	{ "mail-threads-expand-all",
 +	  NULL,
 +	  N_("E_xpand All Threads"),
 +	  NULL,
 +	  N_("Expand all message threads"),
 +	  G_CALLBACK (action_mail_threads_expand_all_cb) },
 +
 +	{ "mail-tools-filters",
 +	  NULL,
 +	  N_("_Message Filters"),
 +	  NULL,
 +	  N_("Create or edit rules for filtering new mail"),
 +	  G_CALLBACK (action_mail_tools_filters_cb) },
 +
 +	{ "mail-tools-search-folders",
 +	  NULL,
 +	  N_("Search F_olders"),
 +	  NULL,
 +	  N_("Create or edit search folder definitions"),
 +	  G_CALLBACK (action_mail_tools_search_folders_cb) },
 +
 +	{ "mail-tools-subscriptions",
 +	  NULL,
 +	  N_("_Subscriptions..."),
 +	  NULL,
 +	  N_("Subscribe or unsubscribe to folders on remote servers"),
 +	  G_CALLBACK (action_mail_tools_subscriptions_cb) },
 +
 +	/*** Menus ***/
 +
 +	{ "mail-folder-menu",
 +	  NULL,
 +	  N_("F_older"),
 +	  NULL,
 +	  NULL,
 +	  NULL },
 +
 +	{ "mail-label-menu",
 +	  NULL,
 +	  N_("_Label"),
 +	  NULL,
 +	  NULL,
 +	  NULL },
 +
 +	{ "mail-preview-menu",
 +	  NULL,
 +	  N_("_Preview"),
 +	  NULL,
 +	  NULL,
 +	  NULL }
 +};
 +
 +static EPopupActionEntry mail_popup_entries[] = {
 +
 +	{ "mail-popup-account-disable",
 +	  NULL,
 +	  "mail-account-disable" },
 +
 +	{ "mail-popup-empty-trash",
 +	  NULL,
 +	  "mail-empty-trash" },
 +
 +	{ "mail-popup-flush-outbox",
 +	  NULL,
 +	  "mail-flush-outbox" },
 +
 +	{ "mail-popup-folder-copy",
 +	  NULL,
 +	  "mail-folder-copy" },
 +
 +	{ "mail-popup-folder-delete",
 +	  NULL,
 +	  "mail-folder-delete" },
 +
 +	{ "mail-popup-folder-move",
 +	  NULL,
 +	  "mail-folder-move" },
 +
 +	{ "mail-popup-folder-new",
 +	  N_("_New Folder..."),
 +	  "mail-folder-new" },
 +
 +	{ "mail-popup-folder-properties",
 +	  NULL,
 +	  "mail-folder-properties" },
 +
 +	{ "mail-popup-folder-refresh",
 +	  NULL,
 +	  "mail-folder-refresh" },
 +
 +	{ "mail-popup-folder-rename",
 +	  NULL,
 +	  "mail-folder-rename" }
 +};
 +
 +static GtkToggleActionEntry mail_toggle_entries[] = {
 +
 +	{ "mail-hide-deleted",
 +	  NULL,
 +	  N_("Hide _Deleted Messages"),
 +	  NULL,
 +	  N_("Hide deleted messages rather than displaying "
 +	     "them with a line through them"),
 +	  G_CALLBACK (action_mail_hide_deleted_cb),
 +	  TRUE },
 +
 +	{ "mail-preview",
 +	  NULL,
 +	  N_("Show Message _Preview"),
 +	  "<Control>m",
 +	  N_("Show message preview pane"),
 +	  G_CALLBACK (action_mail_preview_cb),
 +	  TRUE },
 +
 +	{ "mail-threads-group-by",
 +	  NULL,
 +	  N_("_Group By Threads"),
 +	  "<Control>t",
 +	  N_("Threaded message list"),
 +	  G_CALLBACK (action_mail_threads_group_by_cb),
 +	  FALSE }
 +};
 +
 +static GtkRadioActionEntry mail_view_entries[] = {
 +
 +	/* This action represents the initial active mail view.
 +	 * It should not be visible in the UI, nor should it be
 +	 * possible to switch to it from another shell view. */
 +	{ "mail-view-internal",
 +	  NULL,
 +	  NULL,
 +	  NULL,
 +	  NULL,
 +	  -1 },
 +
 +	{ "mail-view-classic",
 +	  NULL,
 +	  N_("_Classic View"),
 +	  NULL,
 +	  N_("Show message preview below the message list"),
 +	  0 },
 +
 +	{ "mail-view-vertical",
 +	  NULL,
 +	  N_("_Vertical View"),
 +	  NULL,
 +	  N_("Show message preview alongside the message list"),
 +	  1 }
 +};
 +
 +static GtkRadioActionEntry mail_filter_entries[] = {
 +
 +	{ "mail-filter-all-messages",
 +	  NULL,
 +	  N_("All Messages"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  MAIL_FILTER_ALL_MESSAGES },
 +
 +	{ "mail-filter-important-messages",
 +	  "emblem-important",
 +	  N_("Important Messages"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  MAIL_FILTER_IMPORTANT_MESSAGES },
 +
 +	{ "mail-filter-last-5-days-messages",
 +	  NULL,
 +	  N_("Last 5 Days' Messages"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  MAIL_FILTER_LAST_5_DAYS_MESSAGES },
 +
 +	{ "mail-filter-messages-not-junk",
 +	  "mail-mark-notjunk",
 +	  N_("Messages Not Junk"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  MAIL_FILTER_MESSAGES_NOT_JUNK },
 +
 +	{ "mail-filter-messages-with-attachments",
 +	  "mail-attachment",
 +	  N_("Messages with Attachments"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  MAIL_FILTER_MESSAGES_WITH_ATTACHMENTS },
 +
 +	{ "mail-filter-no-label",
 +	  NULL,
 +	  N_("No Label"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  MAIL_FILTER_NO_LABEL },
 +
 +	{ "mail-filter-read-messages",
 +	  "mail-read",
 +	  N_("Read Messages"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  MAIL_FILTER_READ_MESSAGES },
 +
 +	{ "mail-filter-recent-messages",
 +	  NULL,
 +	  N_("Recent Messages"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  MAIL_FILTER_RECENT_MESSAGES },
 +
 +	{ "mail-filter-unread-messages",
 +	  "mail-unread",
 +	  N_("Unread Messages"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  MAIL_FILTER_UNREAD_MESSAGES }
 +};
 +
 +static GtkRadioActionEntry mail_search_entries[] = {
 +
 +	{ "mail-search-body-contains",
 +	  NULL,
 +	  N_("Body contains"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  MAIL_SEARCH_BODY_CONTAINS },
 +
 +	{ "mail-search-message-contains",
 +	  NULL,
 +	  N_("Message contains"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  MAIL_SEARCH_MESSAGE_CONTAINS },
 +
 +	{ "mail-search-recipients-contain",
 +	  NULL,
 +	  N_("Recipients contain"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  MAIL_SEARCH_RECIPIENTS_CONTAIN },
 +
 +	{ "mail-search-sender-contains",
 +	  NULL,
 +	  N_("Sender contains"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  MAIL_SEARCH_SENDER_CONTAINS },
 +
 +	{ "mail-search-subject-contains",
 +	  NULL,
 +	  N_("Subject contains"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  MAIL_SEARCH_SUBJECT_CONTAINS },
 +
 +	{ "mail-search-subject-or-recipients-contains",
 +	  NULL,
 +	  N_("Subject or Recipients contains"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  MAIL_SEARCH_SUBJECT_OR_RECIPIENTS_CONTAINS },
 +
 +	{ "mail-search-subject-or-sender-contains",
 +	  NULL,
 +	  N_("Subject or Sender contains"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  MAIL_SEARCH_SUBJECT_OR_SENDER_CONTAINS }
 +};
 +
 +static GtkRadioActionEntry mail_scope_entries[] = {
 +
 +	{ "mail-scope-all-accounts",
 +	  NULL,
 +	  N_("All Accounts"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  MAIL_SCOPE_ALL_ACCOUNTS },
 +
 +	{ "mail-scope-current-account",
 +	  NULL,
 +	  N_("Current Account"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  MAIL_SCOPE_CURRENT_ACCOUNT },
 +
 +	{ "mail-scope-current-folder",
 +	  NULL,
 +	  N_("Current Folder"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  MAIL_SCOPE_CURRENT_FOLDER },
 +
 +	{ "mail-scope-current-message",
 +	  NULL,
 +	  N_("Current Message"),
 +	  NULL,
 +	  NULL,  /* XXX Add a tooltip! */
 +	  MAIL_SCOPE_CURRENT_MESSAGE }
 +};
 +
 +void
 +e_mail_shell_view_actions_init (EMailShellView *mail_shell_view)
 +{
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	EShellContent *shell_content;
 +	GtkActionGroup *action_group;
 +	GtkRadioAction *radio_action;
 +	GConfBridge *bridge;
 +	GObject *object;
 +	GObject *src_object;
 +	GObject *dst_object;
 +	const gchar *key;
 +
 +	g_return_if_fail (E_IS_MAIL_SHELL_VIEW (mail_shell_view));
 +
 +	shell_view = E_SHELL_VIEW (mail_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +	shell_content = e_shell_view_get_shell_content (shell_view);
 +
 +	/* Mail Actions */
 +	action_group = ACTION_GROUP (MAIL);
 +	gtk_action_group_add_actions (
 +		action_group, mail_entries,
 +		G_N_ELEMENTS (mail_entries), mail_shell_view);
 +	e_action_group_add_popup_actions (
 +		action_group, mail_popup_entries,
 +		G_N_ELEMENTS (mail_popup_entries));
 +	gtk_action_group_add_toggle_actions (
 +		action_group, mail_toggle_entries,
 +		G_N_ELEMENTS (mail_toggle_entries), mail_shell_view);
 +	gtk_action_group_add_radio_actions (
 +		action_group, mail_view_entries,
 +		G_N_ELEMENTS (mail_view_entries), -1,
 +		G_CALLBACK (action_mail_view_cb), mail_shell_view);
 +	gtk_action_group_add_radio_actions (
 +		action_group, mail_search_entries,
 +		G_N_ELEMENTS (mail_search_entries),
 +		MAIL_SEARCH_SUBJECT_OR_SENDER_CONTAINS,
 +		NULL, NULL);
 +	gtk_action_group_add_radio_actions (
 +		action_group, mail_scope_entries,
 +		G_N_ELEMENTS (mail_scope_entries),
 +		MAIL_SCOPE_CURRENT_FOLDER,
 +		G_CALLBACK (action_search_scope_cb), mail_shell_view);
 +
 +	radio_action = GTK_RADIO_ACTION (ACTION (MAIL_SCOPE_ALL_ACCOUNTS));
 +	e_shell_content_set_scope_action (shell_content, radio_action);
 +	e_shell_content_set_scope_visible (shell_content, TRUE);
 +
 +	/* Bind GObject properties for GConf keys. */
 +
 +	bridge = gconf_bridge_get ();
 +
 +	object = G_OBJECT (ACTION (MAIL_PREVIEW));
 +	key = "/apps/evolution/mail/display/show_preview";
 +	gconf_bridge_bind_property (bridge, key, object, "active");
 +
 +	object = G_OBJECT (ACTION (MAIL_THREADS_GROUP_BY));
 +	key = "/apps/evolution/mail/display/thread_list";
 +	gconf_bridge_bind_property (bridge, key, object, "active");
 +
 +	object = G_OBJECT (ACTION (MAIL_VIEW_VERTICAL));
 +	key = "/apps/evolution/mail/display/layout";
 +	gconf_bridge_bind_property (bridge, key, object, "current-value");
 +
 +	/* Fine tuning. */
 +
 +	src_object = G_OBJECT (ACTION (MAIL_THREADS_GROUP_BY));
 +
 +	dst_object = G_OBJECT (ACTION (MAIL_FOLDER_SELECT_THREAD));
 +	e_binding_new (src_object, "active", dst_object, "sensitive");
 +
 +	dst_object = G_OBJECT (ACTION (MAIL_FOLDER_SELECT_SUBTHREAD));
 +	e_binding_new (src_object, "active", dst_object, "sensitive");
 +
 +	dst_object = G_OBJECT (ACTION (MAIL_THREADS_COLLAPSE_ALL));
 +	e_binding_new (src_object, "active", dst_object, "sensitive");
 +
 +	dst_object = G_OBJECT (ACTION (MAIL_THREADS_EXPAND_ALL));
 +	e_binding_new (src_object, "active", dst_object, "sensitive");
 +
 +	/* XXX The boolean sense of the GConf key is the inverse of
 +	 *     the menu item, so we have to maintain two properties. */
 +	e_mutual_binding_new_with_negation (
 +		G_OBJECT (shell_content), "show-deleted",
 +		G_OBJECT (ACTION (MAIL_HIDE_DELETED)), "active");
 +
 +	g_signal_connect (
 +		ACTION (GAL_SAVE_CUSTOM_VIEW), "activate",
 +		G_CALLBACK (action_gal_save_custom_view_cb), mail_shell_view);
 +
 +	g_signal_connect (
 +		ACTION (SEARCH_EXECUTE), "activate",
 +		G_CALLBACK (action_search_execute_cb), mail_shell_view);
 +}
 +
 +/* Helper for e_mail_shell_view_update_popup_labels() */
 +static void
 +mail_shell_view_update_label_action (GtkToggleAction *action,
 +                                     MessageList *message_list,
 +                                     GPtrArray *uids,
 +                                     const gchar *label_tag)
 +{
 +	CamelFolder *folder;
 +	gboolean exists = FALSE;
 +	gboolean not_exists = FALSE;
 +	gboolean sensitive;
 +	guint ii;
 +
 +	folder = message_list->folder;
 +
 +	/* Figure out the proper label action state for the selected
 +	 * messages.  If all the selected messages have the given label,
 +	 * make the toggle action active.  If all the selected message
 +	 * DO NOT have the given label, make the toggle action inactive.
 +	 * If some do and some don't, make the action insensitive. */
 +
 +	for (ii = 0; ii < uids->len && (!exists || !not_exists); ii++) {
 +		const gchar *old_label;
 +		gchar *new_label;
 +
 +		/* Check for new-style labels. */
 +		if (camel_folder_get_message_user_flag (
 +			folder, uids->pdata[ii], label_tag)) {
 +			exists = TRUE;
 +			continue;
 +		}
 +
 +		/* Check for old-style labels. */
 +		old_label = camel_folder_get_message_user_tag (
 +			folder, uids->pdata[ii], "label");
 +		if (old_label == NULL) {
 +			not_exists = TRUE;
 +			continue;
 +		}
 +
 +		/* Convert old-style labels ("<name>") to "$Label<name>". */
 +		new_label = g_alloca (strlen (old_label) + 10);
 +		g_stpcpy (g_stpcpy (new_label, "$Label"), old_label);
 +
 +		if (strcmp (new_label, label_tag) == 0)
 +			exists = TRUE;
 +		else
 +			not_exists = TRUE;
 +	}
 +
 +	sensitive = !(exists && not_exists);
 +	gtk_toggle_action_set_active (action, exists);
 +	gtk_action_set_sensitive (GTK_ACTION (action), sensitive);
 +}
 +
 +void
 +e_mail_shell_view_update_popup_labels (EMailShellView *mail_shell_view)
 +{
 +	EShell *shell;
 +	EShellSettings *shell_settings;
 +	EShellWindow *shell_window;
 +	EShellView *shell_view;
 +	EMailReader *reader;
 +	MessageList *message_list;
 +	GtkUIManager *ui_manager;
 +	GtkActionGroup *action_group;
 +	GtkTreeModel *tree_model;
 +	GtkTreeIter iter;
 +	GPtrArray *uids;
 +	const gchar *path;
 +	gboolean valid;
 +	guint merge_id;
 +	gint ii = 0;
 +
 +	g_return_if_fail (E_IS_MAIL_SHELL_VIEW (mail_shell_view));
 +
 +	shell_view = E_SHELL_VIEW (mail_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +	ui_manager = e_shell_window_get_ui_manager (shell_window);
 +
 +	shell = e_shell_window_get_shell (shell_window);
 +	shell_settings = e_shell_get_shell_settings (shell);
 +
 +	tree_model = e_shell_settings_get_object (
 +		shell_settings, "mail-label-list-store");
 +
 +	action_group = ACTION_GROUP (MAIL_LABEL);
 +	merge_id = mail_shell_view->priv->label_merge_id;
 +	path = "/mail-message-popup/mail-label-menu/mail-label-actions";
 +
 +	/* Unmerge the previous menu items. */
 +	gtk_ui_manager_remove_ui (ui_manager, merge_id);
 +	e_action_group_remove_all_actions (action_group);
 +
 +	reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
 +	message_list = e_mail_reader_get_message_list (reader);
 +	uids = message_list_get_selected (message_list);
 +
 +	valid = gtk_tree_model_get_iter_first (tree_model, &iter);
 +
 +	while (valid) {
 +		GtkToggleAction *toggle_action;
 +		GtkAction *action;
 +		gchar *action_name;
 +		gchar *stock_id;
 +		gchar *label;
 +		gchar *tag;
 +
 +		label = e_mail_label_list_store_get_name (
 +			E_MAIL_LABEL_LIST_STORE (tree_model), &iter);
 +		stock_id = e_mail_label_list_store_get_stock_id (
 +			E_MAIL_LABEL_LIST_STORE (tree_model), &iter);
 +		tag = e_mail_label_list_store_get_tag (
 +			E_MAIL_LABEL_LIST_STORE (tree_model), &iter);
 +		action_name = g_strdup_printf ("mail-label-%d", ii);
 +
 +		/* XXX Add a tooltip! */
 +		toggle_action = gtk_toggle_action_new (
 +			action_name, label, NULL, stock_id);
 +
 +		g_object_set_data_full (
 +			G_OBJECT (toggle_action), "tag",
 +			tag, (GDestroyNotify) g_free);
 +
 +		/* Configure the action before we connect to signals. */
 +		mail_shell_view_update_label_action (
 +			toggle_action, message_list, uids, tag);
 +
 +		g_signal_connect (
 +			toggle_action, "toggled",
 +			G_CALLBACK (action_mail_label_cb), mail_shell_view);
 +
 +		/* The action group takes ownership of the action. */
 +		action = GTK_ACTION (toggle_action);
 +		gtk_action_group_add_action (action_group, action);
 +		g_object_unref (toggle_action);
 +
 +		gtk_ui_manager_add_ui (
 +			ui_manager, merge_id, path, action_name,
 +			action_name, GTK_UI_MANAGER_AUTO, FALSE);
 +
 +		g_free (label);
 +		g_free (stock_id);
 +		g_free (action_name);
 +
 +		valid = gtk_tree_model_iter_next (tree_model, &iter);
 +		ii++;
 +	}
 +
 +	message_list_free_uids (message_list, uids);
 +
 +	g_object_unref (tree_model);
 +}
 +
 +void
 +e_mail_shell_view_update_search_filter (EMailShellView *mail_shell_view)
 +{
 +	EShell *shell;
 +	EShellContent *shell_content;
 +	EShellSettings *shell_settings;
 +	EShellWindow *shell_window;
 +	EShellView *shell_view;
 +	GtkActionGroup *action_group;
 +	GtkRadioAction *radio_action;
 +	GtkTreeModel *tree_model;
 +	GtkTreeIter iter;
 +	GList *list;
 +	GSList *group;
 +	gboolean valid;
 +	gint ii = 0;
 +
 +	g_return_if_fail (E_IS_MAIL_SHELL_VIEW (mail_shell_view));
 +
 +	shell_view = E_SHELL_VIEW (mail_shell_view);
 +	shell_content = e_shell_view_get_shell_content (shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	shell = e_shell_window_get_shell (shell_window);
 +	shell_settings = e_shell_get_shell_settings (shell);
 +
 +	tree_model = e_shell_settings_get_object (
 +		shell_settings, "mail-label-list-store");
 +
 +	action_group = ACTION_GROUP (MAIL_FILTER);
 +	e_action_group_remove_all_actions (action_group);
 +
 +	/* Add the standard filter actions. */
 +	gtk_action_group_add_radio_actions (
 +		action_group, mail_filter_entries,
 +		G_N_ELEMENTS (mail_filter_entries),
 +		MAIL_FILTER_ALL_MESSAGES,
 +		G_CALLBACK (action_search_filter_cb),
 +		mail_shell_view);
 +
 +	/* Retrieve the radio group from an action we just added. */
 +	list = gtk_action_group_list_actions (action_group);
 +	radio_action = GTK_RADIO_ACTION (list->data);
 +	group = gtk_radio_action_get_group (radio_action);
 +	g_list_free (list);
 +
 +	valid = gtk_tree_model_get_iter_first (tree_model, &iter);
 +
 +	while (valid) {
 +		GtkAction *action;
 +		gchar *action_name;
 +		gchar *stock_id;
 +		gchar *label;
 +
 +		label = e_mail_label_list_store_get_name (
 +			E_MAIL_LABEL_LIST_STORE (tree_model), &iter);
 +		stock_id = e_mail_label_list_store_get_stock_id (
 +			E_MAIL_LABEL_LIST_STORE (tree_model), &iter);
 +
 +		action_name = g_strdup_printf ("mail-filter-label-%d", ii);
 +		radio_action = gtk_radio_action_new (
 +			action_name, label, NULL, stock_id, ii);
 +		g_free (action_name);
 +
 +		gtk_radio_action_set_group (radio_action, group);
 +		group = gtk_radio_action_get_group (radio_action);
 +
 +		/* The action group takes ownership of the action. */
 +		action = GTK_ACTION (radio_action);
 +		gtk_action_group_add_action (action_group, action);
 +		g_object_unref (radio_action);
 +
 +		g_free (label);
 +		g_free (stock_id);
 +
 +		valid = gtk_tree_model_iter_next (tree_model, &iter);
 +		ii++;
 +	}
 +
 +	/* Use any action in the group; doesn't matter which. */
 +	e_shell_content_set_filter_action (shell_content, radio_action);
 +
 +	ii = MAIL_FILTER_UNREAD_MESSAGES;
 +	e_shell_content_add_filter_separator_after (shell_content, ii);
 +
 +	ii = MAIL_FILTER_READ_MESSAGES;
 +	e_shell_content_add_filter_separator_before (shell_content, ii);
 +
 +	g_object_unref (tree_model);
 +}
diff --cc mail/e-mail-shell-view-actions.h
index bf7410d,0000000..2a05582
mode 100644,000000..100644
--- a/mail/e-mail-shell-view-actions.h
+++ b/mail/e-mail-shell-view-actions.h
@@@ -1,257 -1,0 +1,257 @@@
 +/*
 + * e-mail-shell-view-actions.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_MAIL_SHELL_VIEW_ACTIONS_H
 +#define E_MAIL_SHELL_VIEW_ACTIONS_H
 +
 +#include <shell/e-shell-window-actions.h>
 +
 +/* Mail Actions */
 +#define E_SHELL_WINDOW_ACTION_MAIL_ACCOUNT_DISABLE(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-account-disable")
 +#define E_SHELL_WINDOW_ACTION_MAIL_ADD_SENDER(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-add-sender")
 +#define E_SHELL_WINDOW_ACTION_MAIL_CARET_MODE(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-caret-mode")
 +#define E_SHELL_WINDOW_ACTION_MAIL_CHECK_FOR_JUNK(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-check-for-junk")
 +#define E_SHELL_WINDOW_ACTION_MAIL_CLIPBOARD_COPY(window) \
 +	E_SHELL_WINDOw_ACTION ((window), "mail-clipboard-copy")
 +#define E_SHELL_WINDOW_ACTION_MAIL_COPY(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-copy")
 +#define E_SHELL_WINDOW_ACTION_MAIL_CREATE_SEARCH_FOLDER(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-create-search-folder")
 +#define E_SHELL_WINDOW_ACTION_MAIL_DELETE(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-delete")
 +#define E_SHELL_WINDOW_ACTION_MAIL_DOWNLOAD(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-download")
 +#define E_SHELL_WINDOW_ACTION_MAIL_EMPTY_TRASH(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-empty-trash")
 +#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_ON_MAILING_LIST(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-filter-on-mailing-list")
 +#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_ON_RECIPIENTS(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-filter-on-recipients")
 +#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_ON_SENDER(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-filter-on-sender")
 +#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_ON_SUBJECT(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-filter-on-subject")
 +#define E_SHELL_WINDOW_ACTION_MAIL_FILTERS_APPLY(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-filters-apply")
 +#define E_SHELL_WINDOW_ACTION_MAIL_FIND(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-find")
 +#define E_SHELL_WINDOW_ACTION_MAIL_FLAG_CLEAR(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-flag-clear")
 +#define E_SHELL_WINDOW_ACTION_MAIL_FLAG_COMPLETED(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-flag-completed")
 +#define E_SHELL_WINDOW_ACTION_MAIL_FLAG_FOR_FOLLOWUP(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-flag-for-followup")
 +#define E_SHELL_WINDOW_ACTION_MAIL_FLUSH_OUTBOX(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-flush-outbox")
 +#define E_SHELL_WINDOW_ACTION_MAIL_FOLDER_COPY(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-folder-copy")
 +#define E_SHELL_WINDOW_ACTION_MAIL_FOLDER_DELETE(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-folder-delete")
 +#define E_SHELL_WINDOW_ACTION_MAIL_FOLDER_EXPUNGE(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-folder-expunge")
 +#define E_SHELL_WINDOW_ACTION_MAIL_FOLDER_MARK_ALL_READ(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-folder-mark-all-read")
 +#define E_SHELL_WINDOW_ACTION_MAIL_FOLDER_MOVE(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-folder-move")
 +#define E_SHELL_WINDOW_ACTION_MAIL_FOLDER_NEW(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-folder-new")
 +#define E_SHELL_WINDOW_ACTION_MAIL_FOLDER_PROPERTIES(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-folder-properties")
 +#define E_SHELL_WINDOW_ACTION_MAIL_FOLDER_REFRESH(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-folder-refresh")
 +#define E_SHELL_WINDOW_ACTION_MAIL_FOLDER_RENAME(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-folder-rename")
 +#define E_SHELL_WINDOW_ACTION_MAIL_FOLDER_SELECT_ALL(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-folder-select-all")
 +#define E_SHELL_WINDOW_ACTION_MAIL_FOLDER_SELECT_THREAD(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-folder-select-thread")
 +#define E_SHELL_WINDOW_ACTION_MAIL_FOLDER_SELECT_SUBTHREAD(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-folder-select-subthread")
 +#define E_SHELL_WINDOW_ACTION_MAIL_FORWARD(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-forward")
 +#define E_SHELL_WINDOW_ACTION_MAIL_FORWARD_ATTACHED(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-forward-attached")
 +#define E_SHELL_WINDOW_ACTION_MAIL_FORWARD_INLINE(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-forward-inline")
 +#define E_SHELL_WINDOW_ACTION_MAIL_FORWARD_QUOTED(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-forward-quoted")
 +#define E_SHELL_WINDOW_ACTION_MAIL_HIDE_DELETED(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-hide-deleted")
 +#define E_SHELL_WINDOW_ACTION_MAIL_HIDE_READ(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-hide-read")
 +#define E_SHELL_WINDOW_ACTION_MAIL_HIDE_SELECTED(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-hide-selected")
 +#define E_SHELL_WINDOW_ACTION_MAIL_LABEL_NEW(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-label-new")
 +#define E_SHELL_WINDOW_ACTION_MAIL_LABEL_NONE(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-label-none")
 +#define E_SHELL_WINDOW_ACTION_MAIL_LOAD_IMAGES(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-load-images")
 +#define E_SHELL_WINDOW_ACTION_MAIL_MARK_IMPORTANT(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-mark-important")
 +#define E_SHELL_WINDOW_ACTION_MAIL_MARK_JUNK(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-mark-junk")
 +#define E_SHELL_WINDOW_ACTION_MAIL_MARK_NOTJUNK(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-mark-notjunk")
 +#define E_SHELL_WINDOW_ACTION_MAIL_MARK_READ(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-mark-read")
 +#define E_SHELL_WINDOW_ACTION_MAIL_MARK_UNIMPORTANT(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-mark-unimportant")
 +#define E_SHELL_WINDOW_ACTION_MAIL_MARK_UNREAD(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-mark-unread")
 +#define E_SHELL_WINDOW_ACTION_MAIL_MESSAGE_EDIT(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-message-edit")
 +#define E_SHELL_WINDOW_ACTION_MAIL_MESSAGE_NEW(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-message-new")
 +#define E_SHELL_WINDOW_ACTION_MAIL_MESSAGE_OPEN(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-message-open")
 +#define E_SHELL_WINDOW_ACTION_MAIL_MOVE(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-move")
 +#define E_SHELL_WINDOW_ACTION_MAIL_NEXT(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-next")
 +#define E_SHELL_WINDOW_ACTION_MAIL_NEXT_IMPORTANT(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-next-important")
 +#define E_SHELL_WINDOW_ACTION_MAIL_NEXT_THREAD(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-next-thread")
 +#define E_SHELL_WINDOW_ACTION_MAIL_NEXT_UNREAD(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-next-unread")
 +#define E_SHELL_WINDOW_ACTION_MAIL_PREVIEW(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-preview")
 +#define E_SHELL_WINDOW_ACTION_MAIL_PREVIOUS(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-previous")
 +#define E_SHELL_WINDOW_ACTION_MAIL_PREVIOUS_IMPORTANT(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-previous-important")
 +#define E_SHELL_WINDOW_ACTION_MAIL_PREVIOUS_UNREAD(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-previous-unread")
 +#define E_SHELL_WINDOW_ACTION_MAIL_PRINT(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-print")
 +#define E_SHELL_WINDOW_ACTION_MAIL_PRINT_PREVIEW(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-print-preview")
 +#define E_SHELL_WINDOW_ACTION_MAIL_REDIRECT(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-redirect")
 +#define E_SHELL_WINDOW_ACTION_MAIL_REPLY_ALL(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-reply-all")
 +#define E_SHELL_WINDOW_ACTION_MAIL_REPLY_LIST(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-reply-list")
 +#define E_SHELL_WINDOW_ACTION_MAIL_REPLY_SENDER(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-reply-sender")
 +#define E_SHELL_WINDOW_ACTION_MAIL_SEARCH_FOLDER_FROM_MAILING_LIST(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-search-folder-from-mailing-list")
 +#define E_SHELL_WINDOW_ACTION_MAIL_SEARCH_FOLDER_FROM_RECIPIENTS(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-search-folder-from-recipients")
 +#define E_SHELL_WINDOW_ACTION_MAIL_SEARCH_FOLDER_FROM_SENDER(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-search-folder-from-sender")
 +#define E_SHELL_WINDOW_ACTION_MAIL_SEARCH_FOLDER_FROM_SUBJECT(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-search-folder-from-subject")
 +#define E_SHELL_WINDOW_ACTION_MAIL_SELECT_ALL(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-select-all")
 +#define E_SHELL_WINDOW_ACTION_MAIL_SHOW_ALL_HEADERS(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-show-all-headers")
 +#define E_SHELL_WINDOW_ACTION_MAIL_SHOW_HIDDEN(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-show-hidden")
 +#define E_SHELL_WINDOW_ACTION_MAIL_SHOW_SOURCE(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-show-source")
 +#define E_SHELL_WINDOW_ACTION_MAIL_SMART_BACKWARD(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-smart-backward")
 +#define E_SHELL_WINDOW_ACTION_MAIL_SMART_FORWARD(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-smart-forward")
 +#define E_SHELL_WINDOW_ACTION_MAIL_STOP(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-stop")
 +#define E_SHELL_WINDOW_ACTION_MAIL_THREADS_COLLAPSE_ALL(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-threads-collapse-all")
 +#define E_SHELL_WINDOW_ACTION_MAIL_THREADS_EXPAND_ALL(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-threads-expand-all")
 +#define E_SHELL_WINDOW_ACTION_MAIL_THREADS_GROUP_BY(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-threads-group-by")
 +#define E_SHELL_WINDOW_ACTION_MAIL_TOOLS_FILTERS(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-tools-filters")
 +#define E_SHELL_WINDOW_ACTION_MAIL_TOOLS_SEARCH_FOLDERS(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-tools-search-folders")
 +#define E_SHELL_WINDOW_ACTION_MAIL_TOOLS_SUBSCRIPTIONS(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-tools-subscriptions")
 +#define E_SHELL_WINDOW_ACTION_MAIL_UNDELETE(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-undelete")
 +#define E_SHELL_WINDOW_ACTION_MAIL_VIEW_CLASSIC(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-view-classic")
 +#define E_SHELL_WINDOW_ACTION_MAIL_VIEW_VERTICAL(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-view-vertical")
 +#define E_SHELL_WINDOW_ACTION_MAIL_ZOOM_100(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-zoom-100")
 +#define E_SHELL_WINDOW_ACTION_MAIL_ZOOM_IN(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-zoom-in")
 +#define E_SHELL_WINDOW_ACTION_MAIL_ZOOM_OUT(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-zoom-out")
 +
 +/* Mail Query Actions */
 +#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_ALL_MESSAGES(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-filter-all-messages")
 +#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_IMPORTANT_MESSAGES(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-filter-important-messages")
 +#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_LAST_5_DAYS_MESSAGES(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-filter-last-5-days-messages")
 +#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_MESSAGES_NOT_JUNK(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-filter-messages-not-junk")
 +#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_MESSAGES_WITH_ATTACHMENTS(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-filter-messages-with-attachments")
 +#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_NO_LABEL(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-filter-no-label")
 +#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_READ_MESSAGES(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-filter-read-messages")
 +#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_RECENT_MESSAGES(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-filter-recent-messages")
 +#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_UNREAD_MESSAGES(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-filter-unread-messages")
 +#define E_SHELL_WINDOW_ACTION_MAIL_SCOPE_ALL_ACCOUNTS(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-scope-all-accounts")
 +#define E_SHELL_WINDOW_ACTION_MAIL_SCOPE_CURRENT_ACCOUNT(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-scope-current-account")
 +#define E_SHELL_WINDOW_ACTION_MAIL_SCOPE_CURRENT_FOLDER(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-scope-current-folder")
 +#define E_SHELL_WINDOW_ACTION_MAIL_SCOPE_CURRENT_MESSAGE(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-scope-current-message")
 +#define E_SHELL_WINDOW_ACTION_MAIL_SEARCH_BODY_CONTAINS(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-search-body-contains")
 +#define E_SHELL_WINDOW_ACTION_MAIL_SEARCH_MESSAGE_CONTAINS(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-search-message-contains")
 +#define E_SHELL_WINDOW_ACTION_MAIL_SEARCH_RECIPIENTS_CONTAIN(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-search-recipients-contain")
 +#define E_SHELL_WINDOW_ACTION_MAIL_SEARCH_SENDER_CONTAINS(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-search-sender-contains")
 +#define E_SHELL_WINDOW_ACTION_MAIL_SEARCH_SUBJECT_CONTAINS(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-search-subject-contains")
 +#define E_SHELL_WINDOW_ACTION_MAIL_SEARCH_SUBJECT_OR_RECIPIENTS_CONTAINS(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-search-subject-or-recipients-contains")
 +#define E_SHELL_WINDOW_ACTION_MAIL_SEARCH_SUBJECT_OR_SENDER_CONTAINS(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "mail-search-subject-or-sender-contains")
 +
 +/* Action Groups */
 +#define E_SHELL_WINDOW_ACTION_GROUP_MAIL(window) \
 +	E_SHELL_WINDOW_ACTION_GROUP ((window), "mail")
 +#define E_SHELL_WINDOW_ACTION_GROUP_MAIL_FILTER(window) \
 +	E_SHELL_WINDOW_ACTION_GROUP ((window), "mail-filter")
 +#define E_SHELL_WINDOW_ACTION_GROUP_MAIL_LABEL(window) \
 +	E_SHELL_WINDOW_ACTION_GROUP ((window), "mail-label")
 +
 +#endif /* E_MAIL_SHELL_VIEW_ACTIONS_H */
diff --cc mail/e-mail-shell-view-private.c
index 552ff1a,0000000..9026c8e
mode 100644,000000..100644
--- a/mail/e-mail-shell-view-private.c
+++ b/mail/e-mail-shell-view-private.c
@@@ -1,898 -1,0 +1,898 @@@
 +/*
 + * e-mail-shell-view-private.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-mail-shell-view-private.h"
 +
 +#include "widgets/menus/gal-view-factory-etable.h"
 +
 +static void
 +mail_shell_view_folder_tree_selected_cb (EMailShellView *mail_shell_view,
 +                                         const gchar *full_name,
 +                                         const gchar *uri,
 +                                         guint32 flags,
 +                                         EMFolderTree *folder_tree)
 +{
 +	EMailReader *reader;
 +	gboolean folder_selected;
 +
 +	reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
 +
 +	folder_selected =
 +		!(flags & CAMEL_FOLDER_NOSELECT) &&
 +		full_name != NULL;
 +
 +	if (folder_selected) {
 +		EMFolderTreeModel *model;
 +
 +		model = em_folder_tree_get_model (folder_tree);
 +		em_folder_tree_model_set_selected (model, uri);
 +		em_folder_tree_model_save_state (model);
 +
 +		e_mail_reader_set_folder_uri (reader, uri);
 +	} else
 +		e_mail_reader_set_folder (reader, NULL, NULL);
 +
 +	e_shell_view_update_actions (E_SHELL_VIEW (mail_shell_view));
 +}
 +
 +static void
 +mail_shell_view_folder_tree_popup_event_cb (EShellView *shell_view,
 +                                            GdkEventButton *event)
 +{
 +	const gchar *widget_path;
 +
 +	widget_path = "/mail-folder-popup";
 +	e_shell_view_show_popup_menu (shell_view, widget_path, event);
 +}
 +
 +static gboolean
 +mail_shell_view_key_press_event_cb (EMailShellView *mail_shell_view,
 +                                    GdkEventKey *event)
 +{
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	GtkAction *action;
 +
 +	shell_view = E_SHELL_VIEW (mail_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	if ((event->state & GDK_CONTROL_MASK) != 0)
 +		return FALSE;
 +
 +	switch (event->keyval) {
 +		case GDK_space:
 +			action = ACTION (MAIL_SMART_FORWARD);
 +			break;
 +
 +		case GDK_BackSpace:
 +			action = ACTION (MAIL_SMART_BACKWARD);
 +			break;
 +
 +		default:
 +			return FALSE;
 +	}
 +
 +	gtk_action_activate (action);
 +
 +	return TRUE;
 +}
 +
 +static gint
 +mail_shell_view_message_list_key_press_cb (EMailShellView *mail_shell_view,
 +                                           gint row,
 +                                           ETreePath path,
 +                                           gint col,
 +                                           GdkEvent *event)
 +{
 +	return mail_shell_view_key_press_event_cb (
 +		mail_shell_view, &event->key);
 +}
 +
 +static gboolean
 +mail_shell_view_message_list_right_click_cb (EShellView *shell_view,
 +                                             gint row,
 +                                             ETreePath path,
 +                                             gint col,
 +                                             GdkEventButton *event)
 +{
 +	const gchar *widget_path;
 +
 +	widget_path = "/mail-message-popup";
 +	e_shell_view_show_popup_menu (shell_view, widget_path, event);
 +
 +	return TRUE;
 +}
 +
 +static void
 +mail_shell_view_reader_changed_cb (EMailShellView *mail_shell_view)
 +{
 +	EMailShellContent *mail_shell_content;
 +
 +	mail_shell_content = mail_shell_view->priv->mail_shell_content;
 +	e_mail_shell_content_update_view_instance (mail_shell_content);
 +	e_mail_shell_view_update_sidebar (mail_shell_view);
 +}
 +
 +static void
 +mail_shell_view_reader_status_message_cb (EMailShellView *mail_shell_view,
 +                                          const gchar *status_message)
 +{
 +	EShellView *shell_view;
 +	EShellTaskbar *shell_taskbar;
 +
 +	shell_view = E_SHELL_VIEW (mail_shell_view);
 +	shell_taskbar = e_shell_view_get_shell_taskbar (shell_view);
 +
 +	e_shell_taskbar_set_message (shell_taskbar, status_message);
 +}
 +
 +static void
 +mail_shell_view_load_view_collection (EShellViewClass *shell_view_class)
 +{
 +	GalViewCollection *collection;
 +	GalViewFactory *factory;
 +	ETableSpecification *spec;
 +	const gchar *base_dir;
 +	gchar *filename;
 +
 +	collection = shell_view_class->view_collection;
 +
 +	base_dir = EVOLUTION_ETSPECDIR;
 +	spec = e_table_specification_new ();
 +	filename = g_build_filename (base_dir, ETSPEC_FILENAME, NULL);
 +	if (!e_table_specification_load_from_file (spec, filename))
 +		g_critical ("Unable to load ETable specification file "
 +			    "for mail");
 +	g_free (filename);
 +
 +	factory = gal_view_factory_etable_new (spec);
 +	gal_view_collection_add_factory (collection, factory);
 +	g_object_unref (factory);
 +	g_object_unref (spec);
 +
 +	gal_view_collection_load (collection);
 +}
 +
 +static void
 +mail_shell_view_notify_view_id_cb (EMailShellView *mail_shell_view)
 +{
 +	EMailShellContent *mail_shell_content;
 +	GalViewInstance *view_instance;
 +	const gchar *view_id;
 +
 +	mail_shell_content = mail_shell_view->priv->mail_shell_content;
 +	view_instance = NULL;  /* FIXME */
 +	view_id = e_shell_view_get_view_id (E_SHELL_VIEW (mail_shell_view));
 +
 +	/* A NULL view ID implies we're in a custom view.  But you can
 +	 * only get to a custom view via the "Define Views" dialog, which
 +	 * would have already modified the view instance appropriately.
 +	 * Furthermore, there's no way to refer to a custom view by ID
 +	 * anyway, since custom views have no IDs. */
 +	if (view_id == NULL)
 +		return;
 +
 +	gal_view_instance_set_current_view_id (view_instance, view_id);
 +}
 +
 +void
 +e_mail_shell_view_private_init (EMailShellView *mail_shell_view,
 +                                EShellViewClass *shell_view_class)
 +{
 +	if (!gal_view_collection_loaded (shell_view_class->view_collection))
 +		mail_shell_view_load_view_collection (shell_view_class);
 +
 +	g_signal_connect (
 +		mail_shell_view, "notify::view-id",
 +		G_CALLBACK (mail_shell_view_notify_view_id_cb), NULL);
 +}
 +
 +void
 +e_mail_shell_view_private_constructed (EMailShellView *mail_shell_view)
 +{
 +	EMailShellViewPrivate *priv = mail_shell_view->priv;
 +	EMailShellSidebar *mail_shell_sidebar;
 +	EShell *shell;
 +	EShellView *shell_view;
 +	EShellBackend *shell_backend;
 +	EShellContent *shell_content;
 +	EShellSettings *shell_settings;
 +	EShellSidebar *shell_sidebar;
 +	EShellWindow *shell_window;
 +	EMFormatHTMLDisplay *html_display;
 +	EMFolderTreeModel *folder_tree_model;
 +	EMFolderTree *folder_tree;
 +	RuleContext *context;
 +	FilterRule *rule = NULL;
 +	GtkTreeModel *tree_model;
 +	GtkUIManager *ui_manager;
 +	MessageList *message_list;
 +	EMailReader *reader;
 +	GtkHTML *html;
 +	const gchar *source;
 +	guint merge_id;
 +	gchar *uri;
 +	gint ii = 0;
 +
 +	shell_view = E_SHELL_VIEW (mail_shell_view);
 +	shell_backend = e_shell_view_get_shell_backend (shell_view);
 +	shell_content = e_shell_view_get_shell_content (shell_view);
 +	shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +	ui_manager = e_shell_window_get_ui_manager (shell_window);
 +
 +	shell = e_shell_window_get_shell (shell_window);
 +	shell_settings = e_shell_get_shell_settings (shell);
 +
 +	tree_model = e_shell_settings_get_object (
 +		shell_settings, "mail-label-list-store");
 +
 +	e_shell_window_add_action_group (shell_window, "mail");
 +	e_shell_window_add_action_group (shell_window, "mail-filter");
 +	e_shell_window_add_action_group (shell_window, "mail-label");
 +
 +	merge_id = gtk_ui_manager_new_merge_id (ui_manager);
 +	priv->label_merge_id = merge_id;
 +
 +	/* Cache these to avoid lots of awkward casting. */
 +	priv->mail_shell_backend = g_object_ref (shell_backend);
 +	priv->mail_shell_content = g_object_ref (shell_content);
 +	priv->mail_shell_sidebar = g_object_ref (shell_sidebar);
 +
 +	reader = E_MAIL_READER (shell_content);
 +	html_display = e_mail_reader_get_html_display (reader);
 +	message_list = e_mail_reader_get_message_list (reader);
 +
 +	mail_shell_sidebar = E_MAIL_SHELL_SIDEBAR (shell_sidebar);
 +	folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
 +
 +	html = EM_FORMAT_HTML (html_display)->html;
 +
 +	g_signal_connect_swapped (
 +		folder_tree, "folder-selected",
 +		G_CALLBACK (mail_shell_view_folder_tree_selected_cb),
 +		mail_shell_view);
 +
 +	g_signal_connect_swapped (
 +		folder_tree, "popup-event",
 +		G_CALLBACK (mail_shell_view_folder_tree_popup_event_cb),
 +		mail_shell_view);
 +
 +	g_signal_connect_swapped (
 +		message_list->tree, "key-press",
 +		G_CALLBACK (mail_shell_view_message_list_key_press_cb),
 +		mail_shell_view);
 +
 +	g_signal_connect_swapped (
 +		message_list->tree, "right-click",
 +		G_CALLBACK (mail_shell_view_message_list_right_click_cb),
 +		mail_shell_view);
 +
 +	g_signal_connect_swapped (
 +		reader, "changed",
 +		G_CALLBACK (mail_shell_view_reader_changed_cb),
 +		mail_shell_view);
 +
 +	/* Use the same callback as "changed". */
 +	g_signal_connect_swapped (
 +		reader, "folder-loaded",
 +		G_CALLBACK (mail_shell_view_reader_changed_cb),
 +		mail_shell_view);
 +
 +	g_signal_connect_swapped (
 +		tree_model, "row-changed",
 +		G_CALLBACK (e_mail_shell_view_update_search_filter),
 +		mail_shell_view);
 +
 +	g_signal_connect_swapped (
 +		tree_model, "row-deleted",
 +		G_CALLBACK (e_mail_shell_view_update_search_filter),
 +		mail_shell_view);
 +
 +	g_signal_connect_swapped (
 +		tree_model, "row-inserted",
 +		G_CALLBACK (e_mail_shell_view_update_search_filter),
 +		mail_shell_view);
 +
 +	g_signal_connect_swapped (
 +		html, "key-press-event",
 +		G_CALLBACK (mail_shell_view_key_press_event_cb),
 +		mail_shell_view);
 +
 +	g_signal_connect_swapped (
 +		html, "status-message",
 +		G_CALLBACK (mail_shell_view_reader_status_message_cb),
 +		mail_shell_view);
 +
 +	e_mail_shell_view_actions_init (mail_shell_view);
 +	e_mail_shell_view_update_search_filter (mail_shell_view);
 +	e_mail_reader_init (reader);
 +
 +	/* Populate built-in rules for search entry popup menu.
 +	 * Keep the assertions, please.  If the conditions aren't
 +	 * met we're going to crash anyway, just more mysteriously. */
 +	context = e_shell_content_get_search_context (shell_content);
 +	source = FILTER_SOURCE_DEMAND;
 +	while ((rule = rule_context_next_rule (context, rule, source))) {
 +		g_assert (ii < MAIL_NUM_SEARCH_RULES);
 +		priv->search_rules[ii++] = g_object_ref (rule);
 +	}
 +	g_assert (ii == MAIL_NUM_SEARCH_RULES);
 +
 +	/* Restore the previously selected folder. */
 +	folder_tree_model = em_folder_tree_get_model (folder_tree);
 +	uri = em_folder_tree_model_get_selected (folder_tree_model);
 +	if (uri != NULL) {
 +		gboolean expanded;
 +
 +		expanded = em_folder_tree_model_get_expanded_uri (
 +			folder_tree_model, uri);
 +		em_folder_tree_set_selected (folder_tree, uri, FALSE);
 +		e_mail_reader_set_folder_uri (reader, uri);
 +
 +		if (!expanded)
 +			em_folder_tree_model_set_expanded_uri (
 +				folder_tree_model, uri, expanded);
 +
 +		g_free (uri);
 +	}
 +}
 +
 +void
 +e_mail_shell_view_private_dispose (EMailShellView *mail_shell_view)
 +{
 +	EMailShellViewPrivate *priv = mail_shell_view->priv;
 +	gint ii;
 +
 +	DISPOSE (priv->mail_shell_backend);
 +	DISPOSE (priv->mail_shell_content);
 +	DISPOSE (priv->mail_shell_sidebar);
 +
 +	for (ii = 0; ii < MAIL_NUM_SEARCH_RULES; ii++)
 +		DISPOSE (priv->search_rules[ii]);
 +}
 +
 +void
 +e_mail_shell_view_private_finalize (EMailShellView *mail_shell_view)
 +{
 +	/* XXX Nothing to do? */
 +}
 +
 +void
 +e_mail_shell_view_execute_search (EMailShellView *mail_shell_view)
 +{
 +	EShell *shell;
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	EShellContent *shell_content;
 +	EShellSettings *shell_settings;
 +	EMFormatHTMLDisplay *html_display;
 +	EMailShellContent *mail_shell_content;
 +	MessageList *message_list;
 +	FilterRule *rule;
 +	EMailReader *reader;
 +	CamelFolder *folder;
 +	GtkAction *action;
 +	GtkTreeModel *model;
 +	GtkTreePath *path;
 +	GtkTreeIter tree_iter;
 +	GString *string;
 +	GList *iter;
 +	GSList *search_strings = NULL;
 +	const gchar *folder_uri;
 +	const gchar *text;
 +	gboolean valid;
 +	gchar *query;
 +	gchar *temp;
 +	gchar *tag;
 +	gint value;
 +
 +	g_return_if_fail (E_IS_MAIL_SHELL_VIEW (mail_shell_view));
 +
 +	shell_view = E_SHELL_VIEW (mail_shell_view);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +	shell_content = e_shell_view_get_shell_content (shell_view);
 +
 +	shell = e_shell_window_get_shell (shell_window);
 +	shell_settings = e_shell_get_shell_settings (shell);
 +
 +	mail_shell_content = mail_shell_view->priv->mail_shell_content;
 +
 +	reader = E_MAIL_READER (shell_content);
 +	html_display = e_mail_reader_get_html_display (reader);
 +	message_list = e_mail_reader_get_message_list (reader);
 +
 +	folder_uri = message_list->folder_uri;
 +	folder = message_list->folder;
 +
 +	/* This returns a new object reference. */
 +	model = e_shell_settings_get_object (
 +		shell_settings, "mail-label-list-store");
 +
 +	text = e_shell_content_get_search_text (shell_content);
 +	if (text == NULL || *text == '\0') {
 +		query = g_strdup ("");
 +		goto filter;
 +	}
 +
 +	/* Replace variables in the selected rule with the
 +	 * current search text and extract a query string. */
 +
 +	action = ACTION (MAIL_SEARCH_SUBJECT_OR_SENDER_CONTAINS);
 +	value = gtk_radio_action_get_current_value (GTK_RADIO_ACTION (action));
 +	g_return_if_fail (value >= 0 && value < MAIL_NUM_SEARCH_RULES);
 +	rule = mail_shell_view->priv->search_rules[value];
 +
 +	for (iter = rule->parts; iter != NULL; iter = iter->next) {
 +		FilterPart *part = iter->data;
 +		FilterElement *element = NULL;
 +
 +		if (strcmp (part->name, "subject") == 0)
 +			element = filter_part_find_element (part, "subject");
 +		else if (strcmp (part->name, "body") == 0)
 +			element = filter_part_find_element (part, "word");
 +		else if (strcmp (part->name, "sender") == 0)
 +			element = filter_part_find_element (part, "sender");
 +		else if (strcmp (part->name, "to") == 0)
 +			element = filter_part_find_element (part, "recipient");
 +
 +		if (strcmp (part->name, "body") == 0) {
 +			struct _camel_search_words *words;
 +			gint ii;
 +
 +			words = camel_search_words_split ((guchar *) text);
 +			for (ii = 0; ii < words->len; ii++)
 +				search_strings = g_slist_prepend (
 +					search_strings, g_strdup (
 +					words->words[ii]->word));
 +			camel_search_words_free (words);
 +		}
 +
 +		if (element != NULL) {
 +			FilterInput *input = FILTER_INPUT (element);
 +			filter_input_set_value (input, text);
 +		}
 +	}
 +
 +	string = g_string_sized_new (1024);
 +	filter_rule_build_code (rule, string);
 +	query = g_string_free (string, FALSE);
 +
 +filter:
 +
 +	/* Apply selected filter. */
 +
 +	value = e_shell_content_get_filter_value (shell_content);
 +	switch (value) {
 +		case MAIL_FILTER_ALL_MESSAGES:
 +			break;
 +
 +		case MAIL_FILTER_UNREAD_MESSAGES:
 +			temp = g_strdup_printf (
 +				"(and %s (match-all (not "
 +				"(system-flag \"Seen\"))))", query);
 +			g_free (query);
 +			query = temp;
 +			break;
 +
 +		case MAIL_FILTER_NO_LABEL:
 +			string = g_string_sized_new (1024);
 +			g_string_append_printf (
 +				string, "(and %s (and ", query);
 +			valid = gtk_tree_model_get_iter_first (
 +				model, &tree_iter);
 +			while (valid) {
 +				tag = e_mail_label_list_store_get_tag (
 +					E_MAIL_LABEL_LIST_STORE (model),
 +					&tree_iter);
 +				g_string_append_printf (
 +					string, " (match-all (not (or "
 +					"(= (user-tag \"label\") \"%s\") "
 +					"(user-flag \"$Label%s\") "
 +					"(user-flag \"%s\"))))",
 +					tag, tag, tag);
 +				g_free (tag);
 +
 +				valid = gtk_tree_model_iter_next (
 +					model, &tree_iter);
 +			}
 +			g_string_append_len (string, "))", 2);
 +			g_free (query);
 +			query = g_string_free (string, FALSE);
 +			break;
 +
 +		case MAIL_FILTER_READ_MESSAGES:
 +			temp = g_strdup_printf (
 +				"(and %s (match-all "
 +				"(system-flag \"Seen\")))", query);
 +			g_free (query);
 +			query = temp;
 +			break;
 +
 +		case MAIL_FILTER_RECENT_MESSAGES:
 +			if (em_utils_folder_is_sent (folder, folder_uri))
 +				temp = g_strdup_printf (
 +					"(and %s (match-all "
 +					"(> (get-sent-date) "
 +					"(- (get-current-date) 86400))))",
 +					query);
 +			else
 +				temp = g_strdup_printf (
 +					"(and %s (match-all "
 +					"(> (get-received-date) "
 +					"(- (get_current_date) 86400))))",
 +					query);
 +			g_free (query);
 +			query = temp;
 +			break;
 +
 +		case MAIL_FILTER_LAST_5_DAYS_MESSAGES:
 +			if (em_utils_folder_is_sent (folder, folder_uri))
 +				temp = g_strdup_printf (
 +					"(and %s (match-all "
 +					"(> (get-sent-date) "
 +					"(- (get-current-date) 432000))))",
 +					query);
 +			else
 +				temp = g_strdup_printf (
 +					"(and %s (match-all "
 +					"(> (get-received-date) "
 +					"(- (get_current_date) 432000))))",
 +					query);
 +			g_free (query);
 +			query = temp;
 +			break;
 +
 +		case MAIL_FILTER_MESSAGES_WITH_ATTACHMENTS:
 +			temp = g_strdup_printf (
 +				"(and %s (match-all "
 +				"(system-flag \"Attachments\")))", query);
 +			g_free (query);
 +			query = temp;
 +			break;
 +
 +		case MAIL_FILTER_IMPORTANT_MESSAGES:
 +			temp = g_strdup_printf (
 +				"(and %s (match-all "
 +				"(system-flag \"Flagged\")))", query);
 +			g_free (query);
 +			query = temp;
 +			break;
 +
 +		case MAIL_FILTER_MESSAGES_NOT_JUNK:
 +			temp = g_strdup_printf (
 +				"(and %s (match-all (not "
 +				"(system-flag \"junk\"))))", query);
 +			g_free (query);
 +			query = temp;
 +			break;
 +
 +		default:
 +			/* The action value also serves as a path for
 +			 * the label list store.  That's why we number
 +			 * the label actions from zero. */
 +			path = gtk_tree_path_new_from_indices (value, -1);
 +			gtk_tree_model_get_iter (model, &tree_iter, path);
 +			gtk_tree_path_free (path);
 +
 +			tag = e_mail_label_list_store_get_tag (
 +				E_MAIL_LABEL_LIST_STORE (model), &tree_iter);
 +			temp = g_strdup_printf (
 +				"(and %s (match-all (or "
 +				"(= (user-tag \"label\") \"%s\") "
 +				"(user-flag \"$Label%s\") "
 +				"(user-flag \"%s\"))))",
 +				query, tag, tag, tag);
 +			g_free (tag);
 +
 +			g_free (query);
 +			query = temp;
 +			break;
 +	}
 +
 +	message_list_set_search (message_list, query);
 +
 +	e_mail_shell_content_set_search_strings (
 +		mail_shell_content, search_strings);
 +
 +	g_slist_foreach (search_strings, (GFunc) g_free, NULL);
 +	g_slist_free (search_strings);
 +
 +	g_object_unref (model);
 +	g_free (query);
 +}
 +
 +/* Helper for e_mail_shell_view_create_filter_from_selected() */
 +static void
 +mail_shell_view_create_filter_cb (CamelFolder *folder,
 +                                  const gchar *uid,
 +                                  CamelMimeMessage *message,
 +                                  gpointer user_data)
 +{
 +	struct {
 +		const gchar *source;
 +		gint type;
 +	} *filter_data = user_data;
 +
 +	if (message != NULL)
 +		filter_gui_add_from_message (
 +			message, filter_data->source, filter_data->type);
 +
 +	g_free (filter_data);
 +}
 +
 +void
 +e_mail_shell_view_create_filter_from_selected (EMailShellView *mail_shell_view,
 +                                               gint filter_type)
 +{
 +	EMailReader *reader;
 +	MessageList *message_list;
 +	CamelFolder *folder;
 +	const gchar *filter_source;
 +	const gchar *folder_uri;
 +	GPtrArray *uids;
 +
 +	struct {
 +		const gchar *source;
 +		gint type;
 +	} *filter_data;
 +
 +	g_return_if_fail (E_IS_MAIL_SHELL_VIEW (mail_shell_view));
 +
 +	reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
 +	message_list = e_mail_reader_get_message_list (reader);
 +	folder_uri = message_list->folder_uri;
 +	folder = message_list->folder;
 +
 +	if (em_utils_folder_is_sent (folder, folder_uri))
 +		filter_source = FILTER_SOURCE_OUTGOING;
 +	else if (em_utils_folder_is_outbox (folder, folder_uri))
 +		filter_source = FILTER_SOURCE_OUTGOING;
 +	else
 +		filter_source = FILTER_SOURCE_INCOMING;
 +
 +	uids = message_list_get_selected (message_list);
 +
 +	if (uids->len == 1) {
 +		filter_data = g_malloc (sizeof (*filter_data));
 +		filter_data->source = filter_source;
 +		filter_data->type = filter_type;
 +
 +		mail_get_message (
 +			folder, uids->pdata[0],
 +			mail_shell_view_create_filter_cb,
 +			filter_data, mail_msg_unordered_push);
 +	}
 +
 +	em_utils_uids_free (uids);
 +}
 +
 +/* Helper for e_mail_shell_view_create_vfolder_from_selected() */
 +static void
 +mail_shell_view_create_vfolder_cb (CamelFolder *folder,
 +                                   const gchar *uid,
 +                                   CamelMimeMessage *message,
 +                                   gpointer user_data)
 +{
 +	struct {
 +		gchar *uri;
 +		gint type;
 +	} *vfolder_data = user_data;
 +
 +	if (message != NULL)
 +		vfolder_gui_add_from_message (
 +			message, vfolder_data->type, vfolder_data->uri);
 +
 +	g_free (vfolder_data->uri);
 +	g_free (vfolder_data);
 +}
 +
 +void
 +e_mail_shell_view_create_vfolder_from_selected (EMailShellView *mail_shell_view,
 +                                                gint vfolder_type)
 +{
 +	EMailReader *reader;
 +	MessageList *message_list;
 +	CamelFolder *folder;
 +	const gchar *folder_uri;
 +	GPtrArray *uids;
 +
 +	struct {
 +		gchar *uri;
 +		gint type;
 +	} *vfolder_data;
 +
 +	g_return_if_fail (E_IS_MAIL_SHELL_VIEW (mail_shell_view));
 +
 +	reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
 +	message_list = e_mail_reader_get_message_list (reader);
 +	folder_uri = message_list->folder_uri;
 +	folder = message_list->folder;
 +
 +	uids = message_list_get_selected (message_list);
 +
 +	if (uids->len == 1) {
 +		vfolder_data = g_malloc (sizeof (*vfolder_data));
 +		vfolder_data->uri = g_strdup (folder_uri);
 +		vfolder_data->type = vfolder_type;
 +
 +		mail_get_message (
 +			folder, uids->pdata[0],
 +			mail_shell_view_create_vfolder_cb,
 +			vfolder_data, mail_msg_unordered_push);
 +	}
 +
 +	em_utils_uids_free (uids);
 +}
 +
 +void
 +e_mail_shell_view_update_sidebar (EMailShellView *mail_shell_view)
 +{
 +	EMailShellBackend *mail_shell_backend;
 +	EMailShellContent *mail_shell_content;
 +	EShellSidebar *shell_sidebar;
 +	EShellView *shell_view;
 +	EMailReader *reader;
 +	MessageList *message_list;
 +	CamelStore *local_store;
 +	CamelFolder *folder;
 +	GPtrArray *selected;
 +	GString *buffer;
 +	const gchar *display_name;
 +	const gchar *folder_uri;
 +	gchar *folder_name;
 +	gchar *title;
 +	guint32 num_deleted;
 +	guint32 num_junked;
 +	guint32 num_junked_not_deleted;
 +	guint32 num_unread;
 +	guint32 num_visible;
 +
 +	g_return_if_fail (E_IS_MAIL_SHELL_VIEW (mail_shell_view));
 +
 +	mail_shell_backend = mail_shell_view->priv->mail_shell_backend;
 +	mail_shell_content = mail_shell_view->priv->mail_shell_content;
 +
 +	shell_view = E_SHELL_VIEW (mail_shell_view);
 +	shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
 +
 +	reader = E_MAIL_READER (mail_shell_content);
 +	message_list = e_mail_reader_get_message_list (reader);
 +	folder_uri = message_list->folder_uri;
 +	folder = message_list->folder;
 +
 +	local_store = e_mail_shell_backend_get_local_store (mail_shell_backend);
 +
 +	/* If no folder is selected, reset the sidebar banners
 +	 * to their default values and stop. */
 +	if (folder == NULL) {
 +		GtkAction *action;
 +		gchar *label;
 +
 +		action = e_shell_view_get_action (shell_view);
 +
 +		g_object_get (action, "label", &label, NULL);
 +		e_shell_sidebar_set_secondary_text (shell_sidebar, NULL);
 +		e_shell_view_set_title (shell_view, label);
 +		g_free (label);
 +
 +		return;
 +	}
 +
 +	camel_object_get (
 +		folder, NULL,
 +		CAMEL_FOLDER_NAME, &folder_name,
 +		CAMEL_FOLDER_DELETED, &num_deleted,
 +		CAMEL_FOLDER_JUNKED, &num_junked,
 +		CAMEL_FOLDER_JUNKED_NOT_DELETED, &num_junked_not_deleted,
 +		CAMEL_FOLDER_UNREAD, &num_unread,
 +		CAMEL_FOLDER_VISIBLE, &num_visible,
 +		NULL);
 +
 +	buffer = g_string_sized_new (256);
 +	selected = message_list_get_selected (message_list);
 +
 +	if (selected->len > 1)
 +		g_string_append_printf (
 +			buffer, ngettext ("%d selected, ", "%d selected, ",
 +			selected->len), selected->len);
 +
 +	if (CAMEL_IS_VTRASH_FOLDER (folder)) {
 +		CamelVTrashFolder *trash_folder;
 +
 +		trash_folder = (CamelVTrashFolder *) folder;
 +
 +		/* "Trash" folder */
 +		if (trash_folder->type == CAMEL_VTRASH_FOLDER_TRASH)
 +			g_string_append_printf (
 +				buffer, ngettext ("%d deleted",
 +				"%d deleted", num_deleted), num_deleted);
 +
 +		/* "Junk" folder (hide deleted messages) */
 +		else if (e_mail_reader_get_hide_deleted (reader))
 +			g_string_append_printf (
 +				buffer, ngettext ("%d junk",
 +				"%d junk", num_junked_not_deleted),
 +				num_junked_not_deleted);
 +
 +		/* "Junk" folder (show deleted messages) */
 +		else
 +			g_string_append_printf (
 +				buffer, ngettext ("%d junk", "%d junk",
 +				num_junked), num_junked);
 +
 +	/* "Drafts" folder */
 +	} else if (em_utils_folder_is_drafts (folder, folder_uri)) {
 +		g_string_append_printf (
 +			buffer, ngettext ("%d draft", "%d drafts",
 +			num_visible), num_visible);
 +
 +	/* "Outbox" folder */
 +	} else if (em_utils_folder_is_outbox (folder, folder_uri)) {
 +		g_string_append_printf (
 +			buffer, ngettext ("%d unsent", "%d unsent",
 +			num_visible), num_visible);
 +
 +	/* "Sent" folder */
 +	} else if (em_utils_folder_is_sent (folder, folder_uri)) {
 +		g_string_append_printf (
 +			buffer, ngettext ("%d sent", "%d sent",
 +			num_visible), num_visible);
 +
 +	/* Normal folder */
 +	} else {
 +		if (!e_mail_reader_get_hide_deleted (reader))
 +			num_visible +=
 +				num_deleted - num_junked +
 +				num_junked_not_deleted;
 +
 +		if (num_unread > 0 && selected->len <= 1)
 +			g_string_append_printf (
 +				buffer, ngettext ("%d unread, ",
 +				"%d unread, ", num_unread), num_unread);
 +		g_string_append_printf (
 +			buffer, ngettext ("%d total", "%d total",
 +			num_visible), num_visible);
 +	}
 +
 +	message_list_free_uids (message_list, selected);
 +
 +	/* Choose a suitable folder name for displaying. */
 +	if (folder->parent_store == local_store && (
 +		strcmp (folder_name, "Drafts") == 0 ||
 +		strcmp (folder_name, "Inbox") == 0 ||
 +		strcmp (folder_name, "Outbox") == 0 ||
 +		strcmp (folder_name, "Sent") == 0 ||
 +		strcmp (folder_name, "Templates") == 0))
 +		display_name = _(folder_name);
 +	else if (strcmp (folder_name, "INBOX") == 0)
 +		display_name = _("Inbox");
 +	else
 +		display_name = folder_name;
 +
 +	title = g_strdup_printf ("%s (%s)", display_name, buffer->str);
 +	e_shell_sidebar_set_secondary_text (shell_sidebar, buffer->str);
 +	e_shell_view_set_title (shell_view, title);
 +	g_free (title);
 +
 +	camel_object_free (folder, CAMEL_FOLDER_NAME, folder_name);
 +	g_string_free (buffer, TRUE);
 +}
diff --cc mail/e-mail-shell-view-private.h
index 1d61f8d,0000000..4b27c4c
mode 100644,000000..100644
--- a/mail/e-mail-shell-view-private.h
+++ b/mail/e-mail-shell-view-private.h
@@@ -1,170 -1,0 +1,170 @@@
 +/*
 + * e-mail-shell-view-private.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_MAIL_SHELL_VIEW_PRIVATE_H
 +#define E_MAIL_SHELL_VIEW_PRIVATE_H
 +
 +#include "e-mail-shell-view.h"
 +
 +#include <glib/gi18n.h>
 +#include <gtkhtml/gtkhtml.h>
 +#include <camel/camel-disco-store.h>
 +#include <camel/camel-offline-store.h>
 +#include <camel/camel-vtrash-folder.h>
 +#include <camel/camel-search-private.h>  /* for camel_search_word */
 +
 +#include "e-util/e-util.h"
 +#include "e-util/e-binding.h"
 +#include "e-util/gconf-bridge.h"
 +#include "e-util/e-account-utils.h"
 +#include "filter/filter-part.h"
 +#include "widgets/misc/e-popup-action.h"
 +#include "widgets/menus/gal-view-instance.h"
 +
 +#include "e-mail-label-dialog.h"
 +#include "e-mail-label-list-store.h"
 +#include "e-mail-reader.h"
 +#include "em-composer-utils.h"
 +#include "em-folder-properties.h"
 +#include "em-folder-selector.h"
 +#include "em-folder-utils.h"
 +#include "em-subscribe-editor.h"
 +#include "em-utils.h"
 +#include "mail-autofilter.h"
 +#include "mail-config.h"
 +#include "mail-ops.h"
 +#include "mail-send-recv.h"
 +#include "mail-vfolder.h"
 +
 +#include "e-mail-shell-backend.h"
 +#include "e-mail-shell-content.h"
 +#include "e-mail-shell-sidebar.h"
 +#include "e-mail-shell-view-actions.h"
 +
 +#define E_MAIL_SHELL_VIEW_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_MAIL_SHELL_VIEW, EMailShellViewPrivate))
 +
 +/* Shorthand, requires a variable named "shell_window". */
 +#define ACTION(name) \
 +	(E_SHELL_WINDOW_ACTION_##name (shell_window))
 +#define ACTION_GROUP(name) \
 +	(E_SHELL_WINDOW_ACTION_GROUP_##name (shell_window))
 +
 +/* For use in dispose() methods. */
 +#define DISPOSE(obj) \
 +	G_STMT_START { \
 +	if ((obj) != NULL) { g_object_unref (obj); (obj) = NULL; } \
 +	} G_STMT_END
 +
 +/* ETable Specifications */
 +#define ETSPEC_FILENAME		"message-list.etspec"
 +
 +G_BEGIN_DECLS
 +
 +/* Filter items are displayed in ascending order.
 + * Labels are numbered from zero, so subsequent items must have
 + * sufficiently large values.  Unfortunately this introduces an
 + * arbitrary upper bound on labels. */
 +enum {
 +	MAIL_FILTER_ALL_MESSAGES		= -3,
 +	MAIL_FILTER_UNREAD_MESSAGES		= -2,
 +	MAIL_FILTER_NO_LABEL			= -1,
 +	/* Labels go here */
 +	MAIL_FILTER_READ_MESSAGES		= 5000,
 +	MAIL_FILTER_RECENT_MESSAGES		= 5001,
 +	MAIL_FILTER_LAST_5_DAYS_MESSAGES	= 5002,
 +	MAIL_FILTER_MESSAGES_WITH_ATTACHMENTS	= 5003,
 +	MAIL_FILTER_IMPORTANT_MESSAGES		= 5004,
 +	MAIL_FILTER_MESSAGES_NOT_JUNK		= 5005
 +};
 +
 +/* Search items are displayed in ascending order. */
 +enum {
 +	MAIL_SEARCH_SUBJECT_OR_SENDER_CONTAINS,
 +	MAIL_SEARCH_SUBJECT_OR_RECIPIENTS_CONTAINS,
 +	MAIL_SEARCH_RECIPIENTS_CONTAIN,
 +	MAIL_SEARCH_MESSAGE_CONTAINS,
 +	MAIL_SEARCH_SUBJECT_CONTAINS,
 +	MAIL_SEARCH_SENDER_CONTAINS,
 +	MAIL_SEARCH_BODY_CONTAINS,
 +	MAIL_NUM_SEARCH_RULES
 +};
 +
 +/* Scope items are displayed in ascending order. */
 +enum {
 +	MAIL_SCOPE_CURRENT_FOLDER,
 +	MAIL_SCOPE_CURRENT_ACCOUNT,
 +	MAIL_SCOPE_ALL_ACCOUNTS,
 +	MAIL_SCOPE_CURRENT_MESSAGE
 +};
 +
 +struct _EMailShellViewPrivate {
 +
 +	/*** Other Stuff ***/
 +
 +	/* These are just for convenience. */
 +	EMailShellBackend *mail_shell_backend;
 +	EMailShellContent *mail_shell_content;
 +	EMailShellSidebar *mail_shell_sidebar;
 +
 +	/* For UI merging and unmerging. */
 +	guint merge_id;
 +	guint label_merge_id;
 +
 +	/* Filter rules correspond to the search entry menu. */
 +	FilterRule *search_rules[MAIL_NUM_SEARCH_RULES];
 +
 +	guint show_deleted : 1;
 +};
 +
 +void		e_mail_shell_view_private_init
 +					(EMailShellView *mail_shell_view,
 +					 EShellViewClass *shell_view_class);
 +void		e_mail_shell_view_private_constructed
 +					(EMailShellView *mail_shell_view);
 +void		e_mail_shell_view_private_dispose
 +					(EMailShellView *mail_shell_view);
 +void		e_mail_shell_view_private_finalize
 +					(EMailShellView *mail_shell_view);
 +
 +/* Private Utilities */
 +
 +void		e_mail_shell_view_actions_init
 +					(EMailShellView *mail_shell_view);
 +void		e_mail_shell_view_execute_search
 +					(EMailShellView *mail_shell_view);
 +void		e_mail_shell_view_create_filter_from_selected
 +					(EMailShellView *mail_shell_view,
 +					 gint filter_type);
 +void		e_mail_shell_view_create_vfolder_from_selected
 +					(EMailShellView *mail_shell_view,
 +					 gint vfolder_type);
 +void		e_mail_shell_view_update_popup_labels
 +					(EMailShellView *mail_shell_view);
 +void		e_mail_shell_view_update_search_filter
 +					(EMailShellView *mail_shell_view);
 +void		e_mail_shell_view_update_sidebar
 +					(EMailShellView *mail_shell_view);
 +
 +G_END_DECLS
 +
 +#endif /* E_MAIL_SHELL_VIEW_PRIVATE_H */
diff --cc mail/e-mail-shell-view.c
index f58d1f6,0000000..8d8b4aa
mode 100644,000000..100644
--- a/mail/e-mail-shell-view.c
+++ b/mail/e-mail-shell-view.c
@@@ -1,260 -1,0 +1,260 @@@
 +/*
 + * e-mail-shell-view.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-mail-shell-view-private.h"
 +
 +static gpointer parent_class;
 +static GType mail_shell_view_type;
 +
 +static void
 +mail_shell_view_dispose (GObject *object)
 +{
 +	e_mail_shell_view_private_dispose (E_MAIL_SHELL_VIEW (object));
 +
 +	/* Chain up to parent's dispose() method. */
 +	G_OBJECT_CLASS (parent_class)->dispose (object);
 +}
 +
 +static void
 +mail_shell_view_finalize (GObject *object)
 +{
 +	e_mail_shell_view_private_finalize (E_MAIL_SHELL_VIEW (object));
 +
 +	/* Chain up to parent's finalize() method. */
 +	G_OBJECT_CLASS (parent_class)->finalize (object);
 +}
 +
 +static void
 +mail_shell_view_constructed (GObject *object)
 +{
 +	/* Chain up to parent's constructed() method. */
 +	G_OBJECT_CLASS (parent_class)->constructed (object);
 +
 +	e_mail_shell_view_private_constructed (E_MAIL_SHELL_VIEW (object));
 +}
 +
 +static void
 +mail_shell_view_toggled (EShellView *shell_view)
 +{
 +	EMailShellViewPrivate *priv;
 +	EShellWindow *shell_window;
 +	GtkUIManager *ui_manager;
 +	const gchar *basename;
 +	gboolean view_is_active;
 +
 +	/* Chain up to parent's toggled() method. */
 +	E_SHELL_VIEW_CLASS (parent_class)->toggled (shell_view);
 +
 +	priv = E_MAIL_SHELL_VIEW_GET_PRIVATE (shell_view);
 +
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +	ui_manager = e_shell_window_get_ui_manager (shell_window);
 +	view_is_active = e_shell_view_is_active (shell_view);
 +	basename = E_MAIL_READER_UI_DEFINITION;
 +
 +	if (view_is_active && priv->merge_id == 0) {
 +		priv->merge_id = e_load_ui_definition (ui_manager, basename);
 +		e_mail_reader_create_charset_menu (
 +			E_MAIL_READER (priv->mail_shell_content),
 +			ui_manager, priv->merge_id);
 +	} else if (!view_is_active && priv->merge_id != 0) {
 +		gtk_ui_manager_remove_ui (ui_manager, priv->merge_id);
 +		priv->merge_id = 0;
 +	}
 +
 +	gtk_ui_manager_ensure_update (ui_manager);
 +}
 +
 +static void
 +mail_shell_view_update_actions (EShellView *shell_view)
 +{
 +	EMailShellView *mail_shell_view;
 +	EMailShellSidebar *mail_shell_sidebar;
 +	EShellContent *shell_content;
 +	EShellSidebar *shell_sidebar;
 +	EShellWindow *shell_window;
 +	EMFolderTree *folder_tree;
 +	EAccount *account = NULL;
 +	GtkAction *action;
 +	const gchar *label;
 +	gchar *uri;
 +	gboolean sensitive;
 +	guint32 state;
 +
 +	/* Be descriptive. */
 +	gboolean account_is_groupwise;
 +	gboolean folder_allows_children;
 +	gboolean folder_can_be_deleted;
 +	gboolean folder_is_junk;
 +	gboolean folder_is_outbox;
 +	gboolean folder_is_store;
 +	gboolean folder_is_trash;
 +
 +	mail_shell_view = E_MAIL_SHELL_VIEW (shell_view);
 +
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	shell_content = e_shell_view_get_shell_content (shell_view);
 +	e_mail_reader_update_actions (E_MAIL_READER (shell_content));
 +
 +	mail_shell_sidebar = mail_shell_view->priv->mail_shell_sidebar;
 +	folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
 +
 +	shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
 +	state = e_shell_sidebar_check_state (shell_sidebar);
 +
 +	folder_allows_children =
 +		(state & E_MAIL_SHELL_SIDEBAR_FOLDER_ALLOWS_CHILDREN);
 +	folder_can_be_deleted =
 +		(state & E_MAIL_SHELL_SIDEBAR_FOLDER_CAN_DELETE);
 +	folder_is_junk =
 +		(state & E_MAIL_SHELL_SIDEBAR_FOLDER_IS_JUNK);
 +	folder_is_outbox =
 +		(state & E_MAIL_SHELL_SIDEBAR_FOLDER_IS_OUTBOX);
 +	folder_is_store =
 +		(state & E_MAIL_SHELL_SIDEBAR_FOLDER_IS_STORE);
 +	folder_is_trash =
 +		(state & E_MAIL_SHELL_SIDEBAR_FOLDER_IS_TRASH);
 +
 +	uri = em_folder_tree_get_selected_uri (folder_tree);
 +	if (uri != NULL) {
 +		account = mail_config_get_account_by_source_url (uri);
 +
 +		/* FIXME This belongs in a GroupWise plugin. */
 +		account_is_groupwise =
 +			(g_strrstr (uri, "groupwise://") != NULL) &&
 +			account != NULL && account->parent_uid != NULL;
 +
 +		g_free (uri);
 +	}
 +
 +	action = ACTION (MAIL_ACCOUNT_DISABLE);
 +	sensitive = (account != NULL) && folder_is_store;
 +	if (account_is_groupwise)
 +		label = _("Proxy _Logout");
 +	else
 +		label = _("_Disable Account");
 +	gtk_action_set_sensitive (action, sensitive);
 +	g_object_set (action, "label", label, NULL);
 +
 +	action = ACTION (MAIL_EMPTY_TRASH);
 +	sensitive = folder_is_trash;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (MAIL_FLUSH_OUTBOX);
 +	sensitive = folder_is_outbox;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (MAIL_FOLDER_COPY);
 +	sensitive = !folder_is_store;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (MAIL_FOLDER_DELETE);
 +	sensitive = !folder_is_store && folder_can_be_deleted;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (MAIL_FOLDER_MOVE);
 +	sensitive = !folder_is_store && folder_can_be_deleted;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (MAIL_FOLDER_NEW);
 +	sensitive = folder_allows_children;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (MAIL_FOLDER_PROPERTIES);
 +	sensitive = !folder_is_store;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (MAIL_FOLDER_REFRESH);
 +	sensitive = !folder_is_store;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	action = ACTION (MAIL_FOLDER_RENAME);
 +	sensitive = !folder_is_store && folder_can_be_deleted;
 +	gtk_action_set_sensitive (action, sensitive);
 +
 +	e_mail_shell_view_update_popup_labels (mail_shell_view);
 +}
 +
 +static void
 +mail_shell_view_class_init (EMailShellViewClass *class,
 +                            GTypeModule *type_module)
 +{
 +	GObjectClass *object_class;
 +	EShellViewClass *shell_view_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (EMailShellViewPrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->dispose = mail_shell_view_dispose;
 +	object_class->finalize = mail_shell_view_finalize;
 +	object_class->constructed = mail_shell_view_constructed;
 +
 +	shell_view_class = E_SHELL_VIEW_CLASS (class);
 +	shell_view_class->label = _("Mail");
 +	shell_view_class->icon_name = "evolution-mail";
 +	shell_view_class->ui_definition = "evolution-mail.ui";
 +	shell_view_class->ui_manager_id = "org.gnome.evolution.mail";
 +	shell_view_class->search_options = "/mail-search-options";
 +	shell_view_class->search_rules = "searchtypes.xml";
 +	shell_view_class->new_shell_content = e_mail_shell_content_new;
 +	shell_view_class->new_shell_sidebar = e_mail_shell_sidebar_new;
 +	shell_view_class->toggled = mail_shell_view_toggled;
 +	shell_view_class->update_actions = mail_shell_view_update_actions;
 +}
 +
 +static void
 +mail_shell_view_init (EMailShellView *mail_shell_view,
 +                      EShellViewClass *shell_view_class)
 +{
 +	mail_shell_view->priv =
 +		E_MAIL_SHELL_VIEW_GET_PRIVATE (mail_shell_view);
 +
 +	e_mail_shell_view_private_init (mail_shell_view, shell_view_class);
 +}
 +
 +GType
 +e_mail_shell_view_get_type (void)
 +{
 +	return mail_shell_view_type;
 +}
 +
 +void
 +e_mail_shell_view_register_type (GTypeModule *type_module)
 +{
 +	const GTypeInfo type_info = {
 +		sizeof (EMailShellViewClass),
 +		(GBaseInitFunc) NULL,
 +		(GBaseFinalizeFunc) NULL,
 +		(GClassInitFunc) mail_shell_view_class_init,
 +		(GClassFinalizeFunc) NULL,
 +		NULL,  /* class_data */
 +		sizeof (EMailShellView),
 +		0,     /* n_preallocs */
 +		(GInstanceInitFunc) mail_shell_view_init,
 +		NULL   /* value_table */
 +	};
 +
 +	mail_shell_view_type = g_type_module_register_type (
 +		type_module, E_TYPE_SHELL_VIEW,
 +		"EMailShellView", &type_info, 0);
 +}
diff --cc mail/e-mail-shell-view.h
index 2bc7695,0000000..d20bde7
mode 100644,000000..100644
--- a/mail/e-mail-shell-view.h
+++ b/mail/e-mail-shell-view.h
@@@ -1,72 -1,0 +1,72 @@@
 +/*
 + * e-mail-shell-view.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_MAIL_SHELL_VIEW_H
 +#define E_MAIL_SHELL_VIEW_H
 +
 +#include <shell/e-shell-view.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_MAIL_SHELL_VIEW \
 +	(e_mail_shell_view_get_type ())
 +#define E_MAIL_SHELL_VIEW(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_MAIL_SHELL_VIEW, EMailShellView))
 +#define E_MAIL_SHELL_VIEW_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_MAIL_SHELL_VIEW, EMailShellViewClass))
 +#define E_IS_MAIL_SHELL_VIEW(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_MAIL_SHELL_VIEW))
 +#define E_IS_MAIL_SHELL_VIEW_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), E_TYPE_MAIL_SHELL_VIEW))
 +#define E_MAIL_SHELL_VIEW_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_MAIL_SHELL_VIEW, EMailShellViewClass))
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _EMailShellView EMailShellView;
 +typedef struct _EMailShellViewClass EMailShellViewClass;
 +typedef struct _EMailShellViewPrivate EMailShellViewPrivate;
 +
 +struct _EMailShellView {
 +	EShellView parent;
 +	EMailShellViewPrivate *priv;
 +};
 +
 +struct _EMailShellViewClass {
 +	EShellViewClass parent_class;
 +};
 +
 +GType		e_mail_shell_view_get_type	(void);
 +void		e_mail_shell_view_register_type
 +					(GTypeModule *type_module);
 +gboolean	e_mail_shell_view_get_show_deleted
 +					(EMailShellView *mail_shell_view);
 +void		e_mail_shell_view_set_show_deleted
 +					(EMailShellView *mail_shell_view,
 +					 gboolean show_deleted);
 +
 +G_END_DECLS
 +
 +#endif /* E_MAIL_SHELL_VIEW_H */
diff --cc mail/e-searching-tokenizer.c
index 129aa05,724cc3b..726ae41
--- a/mail/e-searching-tokenizer.c
+++ b/mail/e-searching-tokenizer.c
@@@ -874,10 -935,10 +875,10 @@@ search_info_clone (struct _search_info 
  }
  
  static struct _searcher *
 -search_info_to_searcher(struct _search_info *si)
 +search_info_to_searcher (struct _search_info *si)
  {
  	char *tags, *tage;
- 	char *col;
+ 	const gchar *col;
  
  	if (si->strv->len == 0)
  		return NULL;
diff --cc mail/em-account-editor.c
index a9ba161,2b13e7e..e5f0f98
--- a/mail/em-account-editor.c
+++ b/mail/em-account-editor.c
@@@ -1422,7 -1402,8 +1422,8 @@@ emae_refresh_providers(EMAccountEditor 
  	int active = 0, i;
  	struct _service_info *info = &emae_service_info[service->type];
  	const char *uri = e_account_get_string(account, info->account_uri_key);
- 	char *current = NULL, *tmp;
 -	const char *tmp;
+ 	char *current = NULL;
++	const gchar *tmp;
  	CamelURL *url;
  
  	dropdown = service->providers;
@@@ -2850,8 -2831,8 +2851,7 @@@ emae_check_complete(EConfig *ec, const 
  				} else {
  					g_warning("buz2\n");
  				}
- 				
- 		
+ 
 -
  		} else if (!strcmp(pageid, "20.receive_options")) {
  			if (emae->priv->source.provider
  			    && emae->priv->extra_provider != emae->priv->source.provider) {
@@@ -2918,10 -2902,11 +2921,11 @@@
  	if (ok && (pageid == NULL || !strcmp(pageid, "40.management"))) {
  		ok = (tmp = e_account_get_string(emae->account, E_ACCOUNT_NAME))
  			&& tmp[0]
 -			&& ((ea = mail_config_get_account_by_name(tmp)) == NULL
 +			&& ((ea = e_get_account_by_name (tmp)) == NULL
  			    || ea == emae->original);
- 		if (!ok)
+ 		if (!ok) {
  			d(printf("management page incomplete\n"));
+ 		}
  	}
  
  	return ok;
diff --cc mail/em-account-prefs.c
index 75ff66d,d2303aa..82342de
--- a/mail/em-account-prefs.c
+++ b/mail/em-account-prefs.c
@@@ -12,9 -10,12 +12,9 @@@
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
+  * License along with the program; if not, see <http://www.gnu.org/licenses/>
   *
   *
 - * Authors:
 - *		Jeffrey Stedfast <fejj ximian com>
 - *
   * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
   *
   */
diff --cc mail/em-account-prefs.h
index 4c02d71,0dabc8a..82df8fa
--- a/mail/em-account-prefs.h
+++ b/mail/em-account-prefs.h
@@@ -12,9 -11,12 +12,9 @@@
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
+  * License along with the program; if not, see <http://www.gnu.org/licenses/>
   *
   *
 - * Authors:
 - *		Jeffrey Stedfast <fejj ximian com>
 - *
   * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
   *
   */
diff --cc mail/em-composer-utils.c
index f6ea663,4ed3e70..fdff698
--- a/mail/em-composer-utils.c
+++ b/mail/em-composer-utils.c
@@@ -904,15 -896,13 +904,15 @@@ edit_message (CamelMimeMessage *message
  			camel_object_unref (body);
  		}
  	}
- 		
+ 
  	composer = e_msg_composer_new_with_message (message);
- 	
+ 
 -	if (em_utils_folder_is_templates(drafts, NULL) == TRUE)
 -		em_composer_utils_setup_callbacks (composer, NULL, NULL, 0, 0, NULL, NULL);
 -	else
 -		em_composer_utils_setup_callbacks (composer, NULL, NULL, 0, 0, drafts, uid);
 +	if (em_utils_folder_is_drafts (drafts, NULL)) {
 +		struct emcs_t *emcs;
 +
 +		emcs = g_object_get_data (G_OBJECT (composer), "emcs");
 +		emcs_set_drafts_info (emcs, drafts, uid);
 +	}
  
  	composer_set_no_change (composer, TRUE, FALSE);
  
diff --cc mail/em-composer-utils.h
index 37fd185,60944cb..8ee05a5
--- a/mail/em-composer-utils.h
+++ b/mail/em-composer-utils.h
@@@ -41,8 -41,16 +41,8 @@@ struct _EMFormat
  struct _EAccount;
  struct _EDestination;
  
 -void em_composer_utils_setup_callbacks (struct _EMsgComposer *composer, struct _CamelFolder *folder, const char *uid,
 -					guint32 flags, guint32 set, struct _CamelFolder *drafts, const char *drafts_uid);
 -
 -#define em_composer_utils_setup_default_callbacks(composer) em_composer_utils_setup_callbacks (composer, NULL, NULL, 0, 0, NULL, NULL)
 -
 -void em_utils_composer_send_cb(struct _EMsgComposer *composer, gpointer user_data);
 -void em_utils_composer_save_draft_cb(struct _EMsgComposer *composer, gpointer user_data);
 -
  void em_utils_compose_new_message (const char *fromuri);
- struct _EMsgComposer * em_utils_compose_lite_new_message (const char *fromuri); 
+ struct _EMsgComposer * em_utils_compose_lite_new_message (const char *fromuri);
  
  /* FIXME: mailto?  url?  should make up its mind what its called.  imho use 'uri' */
  void em_utils_compose_new_message_with_mailto (const char *url, const char *fromuri);
diff --cc mail/em-folder-tree-model.c
index abdd3c8,d90bcbb..c0e3f2b
--- a/mail/em-folder-tree-model.c
+++ b/mail/em-folder-tree-model.c
@@@ -98,64 -96,98 +98,65 @@@ enum 
  	LAST_SIGNAL
  };
  
+ extern CamelStore *vfolder_store;
+ 
 -static guint signals[LAST_SIGNAL] = { 0, };
 -static GtkTreeStoreClass *parent_class = NULL;
 +static gpointer parent_class;
 +static guint signals[LAST_SIGNAL];
  
 -GType
 -em_folder_tree_model_get_type (void)
 +static void
 +store_info_free (EMFolderTreeModelStoreInfo *si)
  {
 -	static GType type = 0;
 +	camel_object_remove_event (si->store, si->created_id);
 +	camel_object_remove_event (si->store, si->deleted_id);
 +	camel_object_remove_event (si->store, si->renamed_id);
 +	camel_object_remove_event (si->store, si->subscribed_id);
 +	camel_object_remove_event (si->store, si->unsubscribed_id);
  
 -	if (!type) {
 -		static const GTypeInfo info = {
 -			sizeof (EMFolderTreeModelClass),
 -			NULL, /* base_class_init */
 -			NULL, /* base_class_finalize */
 -			(GClassInitFunc) em_folder_tree_model_class_init,
 -			NULL, /* class_finalize */
 -			NULL, /* class_data */
 -			sizeof (EMFolderTreeModel),
 -			0,    /* n_preallocs */
 -			(GInstanceInitFunc) em_folder_tree_model_init,
 -		};
 -		static const GInterfaceInfo tree_model_info = {
 -			(GInterfaceInitFunc) tree_model_iface_init,
 -			NULL,
 -			NULL
 -		};
 -		static const GInterfaceInfo sortable_info = {
 -			(GInterfaceInitFunc) tree_sortable_iface_init,
 -			NULL,
 -			NULL
 -		};
 +	g_free (si->display_name);
 +	camel_object_unref (si->store);
 +	gtk_tree_row_reference_free (si->row);
 +	g_hash_table_destroy (si->full_hash);
 +	g_free (si);
 +}
 +
 +static void
 +folder_tree_model_load_state (EMFolderTreeModel *model,
 +                              const gchar *filename)
 +{
 +	xmlNodePtr root, node;
  
 -		type = g_type_register_static (GTK_TYPE_TREE_STORE, "EMFolderTreeModel", &info, 0);
 +	if (model->state)
 +		xmlFreeDoc (model->state);
  
 -		g_type_add_interface_static (type, GTK_TYPE_TREE_MODEL,
 -					     &tree_model_info);
 -		g_type_add_interface_static (type, GTK_TYPE_TREE_SORTABLE,
 -					     &sortable_info);
 +	if ((model->state = e_xml_parse_file (filename)) != NULL) {
 +		node = xmlDocGetRootElement (model->state);
 +		if (!node || strcmp ((char *)node->name, "tree-state") != 0) {
 +			/* it is not expected XML file, thus free it and use the default */
 +			xmlFreeDoc (model->state);
 +		} else
 +			return;
  	}
  
 -	return type;
 -}
 +	/* setup some defaults - expand "Local Folders" and "Search Folders" */
 +	model->state = xmlNewDoc ((const unsigned char *)"1.0");
 +	root = xmlNewDocNode (model->state, NULL, (const unsigned char *)"tree-state", NULL);
 +	xmlDocSetRootElement (model->state, root);
  
 +	node = xmlNewChild (root, NULL, (const unsigned char *)"node", NULL);
 +	xmlSetProp (node, (const unsigned char *)"name", (const unsigned char *)"local");
 +	xmlSetProp (node, (const unsigned char *)"expand", (const unsigned char *)"true");
  
 -static void
 -em_folder_tree_model_class_init (EMFolderTreeModelClass *klass)
 -{
 -	GObjectClass *object_class = G_OBJECT_CLASS (klass);
 -
 -	parent_class = g_type_class_ref (GTK_TYPE_TREE_STORE);
 -
 -	object_class->finalize = em_folder_tree_model_finalize;
 -
 -	/* signals */
 -	signals[LOADING_ROW] =
 -		g_signal_new ("loading-row",
 -			      G_OBJECT_CLASS_TYPE (object_class),
 -			      G_SIGNAL_RUN_FIRST,
 -			      G_STRUCT_OFFSET (EMFolderTreeModelClass, loading_row),
 -			      NULL, NULL,
 -			      e_marshal_VOID__POINTER_POINTER,
 -			      G_TYPE_NONE, 2,
 -			      G_TYPE_POINTER,
 -			      G_TYPE_POINTER);
 -
 -	signals[LOADED_ROW] =
 -		g_signal_new ("loaded-row",
 -			      G_OBJECT_CLASS_TYPE (object_class),
 -			      G_SIGNAL_RUN_FIRST,
 -			      G_STRUCT_OFFSET (EMFolderTreeModelClass, loaded_row),
 -			      NULL, NULL,
 -			      e_marshal_VOID__POINTER_POINTER,
 -			      G_TYPE_NONE, 2,
 -			      G_TYPE_POINTER,
 -			      G_TYPE_POINTER);
 -
 -	signals[FOLDER_ADDED] =
 -		g_signal_new ("folder-added",
 -			      G_OBJECT_CLASS_TYPE (object_class),
 -			      G_SIGNAL_RUN_FIRST,
 -			      G_STRUCT_OFFSET (EMFolderTreeModelClass, folder_added),
 -			      NULL, NULL,
 -			      e_marshal_VOID__STRING_STRING,
 -			      G_TYPE_NONE, 2,
 -			      G_TYPE_STRING,
 -			      G_TYPE_STRING);
 +	node = xmlNewChild (root, NULL, (const unsigned char *)"node", NULL);
 +	xmlSetProp (node, (const unsigned char *)"name", (const unsigned char *)"vfolder");
 +	xmlSetProp (node, (const unsigned char *)"expand", (const unsigned char *)"true");
  }
  
  static int
 -sort_cb (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data)
 +folder_tree_model_sort (GtkTreeModel *model,
 +                        GtkTreeIter *a,
 +                        GtkTreeIter *b,
 +                        gpointer user_data)
  {
- 	extern CamelStore *vfolder_store;
  	char *aname, *bname;
  	CamelStore *store;
  	gboolean is_store;
diff --cc mail/em-folder-tree.c
index 07aedc2,77e62df..f4980dc
--- a/mail/em-folder-tree.c
+++ b/mail/em-folder-tree.c
@@@ -157,7 -151,13 +157,8 @@@ static GdkAtom drop_atoms[NUM_DROP_TYPE
  static guint signals[LAST_SIGNAL] = { 0 };
  
  extern CamelSession *session;
+ extern CamelStore *vfolder_store;
  
 -static void em_folder_tree_class_init (EMFolderTreeClass *klass);
 -static void em_folder_tree_init (EMFolderTree *emft);
 -static void em_folder_tree_destroy (GtkObject *obj);
 -static void em_folder_tree_finalize (GObject *obj);
 -
  static gboolean emft_save_state (EMFolderTree *emft);
  static void emft_queue_save_state (EMFolderTree *emft);
  
@@@ -544,10 -530,7 +545,9 @@@ emft_expand_node (EMFolderTreeModel *mo
  {
  	struct _EMFolderTreePrivate *priv = emft->priv;
  	struct _EMFolderTreeModelStoreInfo *si;
- 	extern CamelStore *vfolder_store;
 +	EMailShellBackend *mail_shell_backend;
  	GtkTreeRowReference *row;
 +	GtkTreeView *tree_view;
  	GtkTreePath *path;
  	EAccount *account;
  	CamelStore *store;
diff --cc mail/em-folder-utils.c
index 510bcf7,ad60516..2b319ff
--- a/mail/em-folder-utils.c
+++ b/mail/em-folder-utils.c
@@@ -269,8 -268,7 +269,8 @@@ emfu_copy_folder_selected (const char *
  {
  	struct _copy_folder_data *cfd = data;
  	CamelStore *fromstore = NULL, *tostore = NULL;
 +	CamelStore *local_store;
- 	char *tobase = NULL;
+ 	const gchar *tobase = NULL;
  	CamelException ex;
  	CamelURL *url;
  
diff --cc mail/em-folder-view.c
index 8da3b5d,d0f8289..b72e187
--- a/mail/em-folder-view.c
+++ b/mail/em-folder-view.c
@@@ -123,22 -164,22 +123,22 @@@ static const EMFolderViewEnable emfv_en
  
  	{ "AddSenderToAddressbook",   EM_POPUP_SELECT_ADD_SENDER },
  
 -	{ "MessageApplyFilters",      EM_POPUP_SELECT_MANY },
 -	{ "MessageFilterJunk",        EM_POPUP_SELECT_MANY },
 -	{ "MessageCopy",              EM_POPUP_SELECT_MANY },
 -	{ "MessageDelete",            EM_POPUP_SELECT_MANY|EM_POPUP_SELECT_DELETE },
 -	{ "MessageDeleteKey",         EM_POPUP_SELECT_MANY},
 -	{ "MessageForward",           EM_POPUP_SELECT_MANY },
 -	{ "MessageForwardAttached",   EM_POPUP_SELECT_MANY },
 -	{ "MessageForwardInline",     EM_POPUP_SELECT_ONE },
 -	{ "MessageForwardQuoted",     EM_POPUP_SELECT_ONE },
 -	{ "MessageRedirect",          EM_POPUP_SELECT_ONE },
 -	{ "MessageMarkAsRead",        EM_POPUP_SELECT_MANY|EM_POPUP_SELECT_MARK_READ },
 -	{ "MessageMarkAsUnRead",      EM_POPUP_SELECT_MANY|EM_POPUP_SELECT_MARK_UNREAD },
 -	{ "MessageMarkAsImportant",   EM_POPUP_SELECT_MANY|EM_POPUP_SELECT_MARK_IMPORTANT },
 -	{ "MessageMarkAsUnimportant", EM_POPUP_SELECT_MANY|EM_POPUP_SELECT_MARK_UNIMPORTANT },
 -	{ "MessageMarkAsJunk",        EM_POPUP_SELECT_MANY|EM_POPUP_SELECT_JUNK },
 -	{ "MessageMarkAsNotJunk",     EM_POPUP_SELECT_MANY},
 +//	{ "MessageApplyFilters",      EM_POPUP_SELECT_MANY },
 +//	{ "MessageFilterJunk",        EM_POPUP_SELECT_MANY },
 +//	{ "MessageCopy",              EM_POPUP_SELECT_MANY },
 +//	{ "MessageDelete",            EM_POPUP_SELECT_MANY|EM_POPUP_SELECT_DELETE },
- //	{ "MessageDeleteKey",         EM_POPUP_SELECT_MANY},	
++//	{ "MessageDeleteKey",         EM_POPUP_SELECT_MANY},
 +//	{ "MessageForward",           EM_POPUP_SELECT_MANY },
 +//	{ "MessageForwardAttached",   EM_POPUP_SELECT_MANY },
 +//	{ "MessageForwardInline",     EM_POPUP_SELECT_ONE },
 +//	{ "MessageForwardQuoted",     EM_POPUP_SELECT_ONE },
 +//	{ "MessageRedirect",          EM_POPUP_SELECT_ONE },
 +//	{ "MessageMarkAsRead",        EM_POPUP_SELECT_MANY|EM_POPUP_SELECT_MARK_READ },
 +//	{ "MessageMarkAsUnRead",      EM_POPUP_SELECT_MANY|EM_POPUP_SELECT_MARK_UNREAD },
 +//	{ "MessageMarkAsImportant",   EM_POPUP_SELECT_MANY|EM_POPUP_SELECT_MARK_IMPORTANT },
 +//	{ "MessageMarkAsUnimportant", EM_POPUP_SELECT_MANY|EM_POPUP_SELECT_MARK_UNIMPORTANT },
 +//	{ "MessageMarkAsJunk",        EM_POPUP_SELECT_MANY|EM_POPUP_SELECT_JUNK },
 +//	{ "MessageMarkAsNotJunk",     EM_POPUP_SELECT_MANY},
  	{ "MessageFollowUpFlag",      EM_POPUP_SELECT_MANY|EM_POPUP_SELECT_FLAG_FOLLOWUP },
  	{ "MessageFollowUpComplete",  EM_POPUP_SELECT_MANY|EM_POPUP_SELECT_FLAG_COMPLETED },
  	{ "MessageFollowUpClear",     EM_POPUP_SELECT_MANY|EM_POPUP_SELECT_FLAG_CLEAR },
@@@ -197,28 -241,40 +197,29 @@@ enum 
  	LAST_SIGNAL
  };
  
+ extern CamelSession *session;
+ 
  static guint signals[LAST_SIGNAL];
  
 -static void emfv_selection_get(GtkWidget *widget, GtkSelectionData *data, guint info, guint time_stamp, EMFolderView *emfv);
 -static void emfv_selection_clear_event(GtkWidget *widget, GdkEventSelection *event, EMFolderView *emfv);
 -
 -#ifdef ENABLE_PROFILING
 -static void
 -emfv_format_complete(EMFormat *emf, EMFolderView *emfv)
 -{
 -	e_profile_event_emit("goto.done", emf->uid?emf->uid:"", 0);
 -}
 -#endif
 -
  static void
  emfv_init(GObject *o)
  {
  	EMFolderView *emfv = (EMFolderView *)o;
  	struct _EMFolderViewPrivate *p;
- 	extern CamelSession *session;
  
 -	gtk_box_set_homogeneous (GTK_BOX (emfv), FALSE);
 -
 -	p = emfv->priv = g_malloc0(sizeof(struct _EMFolderViewPrivate));
 -
 -	emfv->statusbar_active = TRUE;
 -	emfv->list_active = FALSE;
 -
 -	emfv->ui_files = g_slist_append(NULL,
 -					g_build_filename (EVOLUTION_UIDIR,
 -							  "evolution-mail-message.xml",
 -							  NULL));
 -
 -	emfv->ui_app_name = "evolution-mail";
 +//	gtk_box_set_homogeneous (GTK_BOX (emfv), FALSE);
 +//
 +//	p = emfv->priv = g_malloc0(sizeof(struct _EMFolderViewPrivate));
 +//
 +//	emfv->statusbar_active = TRUE;
 +//	emfv->list_active = FALSE;
 +//
 +//	emfv->ui_files = g_slist_append(NULL,
 +//					g_build_filename (EVOLUTION_UIDIR,
 +//							  "evolution-mail-message.xml",
 +//							  NULL));
 +//
 +//	emfv->ui_app_name = "evolution-mail";
  
  	emfv->enable_map = g_slist_prepend(NULL, (void *)emfv_enable_map);
  
diff --cc mail/em-format-html.c
index cbf90a9,aa82851..6bc4a79
--- a/mail/em-format-html.c
+++ b/mail/em-format-html.c
@@@ -956,93 -281,34 +956,91 @@@ em_format_html_get_type (void
  	return type;
  }
  
 -EMFormatHTML *em_format_html_new(void)
 +void
 +em_format_html_load_images (EMFormatHTML *efh)
  {
 -	EMFormatHTML *efh;
 +	g_return_if_fail (EM_IS_FORMAT_HTML (efh));
  
 -	efh = g_object_new(em_format_html_get_type(), NULL);
 +	if (efh->priv->image_loading_policy == MAIL_CONFIG_HTTP_ALWAYS)
 +		return;
  
 -	return efh;
 +	/* This will remain set while we're still
 +	 * rendering the same message, then it wont be. */
 +	efh->priv->load_images_now = TRUE;
 +	em_format_redraw (EM_FORMAT (efh));
  }
  
 -/* force loading of http images */
 -void em_format_html_load_http(EMFormatHTML *emfh)
 +void
 +em_format_html_get_color (EMFormatHTML *efh,
 +                          EMFormatHTMLColorType type,
 +                          GdkColor *color)
  {
 -	if (emfh->load_http == MAIL_CONFIG_HTTP_ALWAYS)
 -		return;
 +	GdkColor *format_color;
 +
 +	g_return_if_fail (EM_IS_FORMAT_HTML (efh));
- 	g_return_if_fail (type >= 0);
 +	g_return_if_fail (type < EM_FORMAT_HTML_NUM_COLOR_TYPES);
 +	g_return_if_fail (color != NULL);
  
 -	/* This will remain set while we're still rendering the same message, then it wont be */
 -	emfh->load_http_now = TRUE;
 -	d(printf("redrawing with images forced on\n"));
 -	em_format_redraw((EMFormat *)emfh);
 +	format_color = &efh->priv->colors[type];
 +
 +	color->red   = format_color->red;
 +	color->green = format_color->green;
 +	color->blue  = format_color->blue;
  }
  
  void
 -em_format_html_set_load_http(EMFormatHTML *emfh, int style)
 +em_format_html_set_color (EMFormatHTML *efh,
 +                          EMFormatHTMLColorType type,
 +                          const GdkColor *color)
  {
 -	if (emfh->load_http != style) {
 -		emfh->load_http = style;
 -		em_format_redraw((EMFormat *)emfh);
 +	GdkColor *format_color;
 +	const gchar *property_name;
 +
 +	g_return_if_fail (EM_IS_FORMAT_HTML (efh));
- 	g_return_if_fail (type >= 0);
 +	g_return_if_fail (type < EM_FORMAT_HTML_NUM_COLOR_TYPES);
 +	g_return_if_fail (color != NULL);
 +
 +	format_color = &efh->priv->colors[type];
 +
 +	if (gdk_color_equal (color, format_color))
 +		return;
 +
 +	format_color->red   = color->red;
 +	format_color->green = color->green;
 +	format_color->blue  = color->blue;
 +
 +	switch (type) {
 +		case EM_FORMAT_HTML_COLOR_BODY:
 +			property_name = "body-color";
 +			break;
 +		case EM_FORMAT_HTML_COLOR_CITATION:
 +			property_name = "citation-color";
 +			break;
 +		case EM_FORMAT_HTML_COLOR_CONTENT:
 +			property_name = "content-color";
 +			break;
 +		case EM_FORMAT_HTML_COLOR_FRAME:
 +			property_name = "frame-color";
 +			break;
 +		case EM_FORMAT_HTML_COLOR_HEADER:
 +			property_name = "header-color";
 +			break;
 +		case EM_FORMAT_HTML_COLOR_TEXT:
 +			property_name = "text-color";
 +			break;
 +		default:
 +			g_return_if_reached ();
  	}
 +
 +	g_object_notify (G_OBJECT (efh), property_name);
 +}
 +
 +MailConfigHTTPMode
 +em_format_html_get_image_loading_policy (EMFormatHTML *efh)
 +{
 +	g_return_val_if_fail (EM_IS_FORMAT_HTML (efh), 0);
 +
 +	return efh->priv->image_loading_policy;
  }
  
  void
@@@ -2430,15 -1859,13 +2428,15 @@@ efh_format_headers(EMFormatHTML *efh, C
  	charset = camel_iconv_charset_name(charset);
  
  	if (!efh->simple_headers)
 -		camel_stream_printf(stream,
 -				    "<font color=\"#%06x\">\n"
 -				    "<table cellpadding=\"0\" width=\"100%%\">",
 -				    efh->header_colour & 0xffffff);
 +		camel_stream_printf (
 +			stream, "<font color=\"#%06x\">\n"
 +			"<table cellpadding=\"0\" width=\"100%%\">",
 +			e_color_to_value (
 +				&efh->priv->colors[
 +				EM_FORMAT_HTML_COLOR_HEADER]));
- 	
+ 
  	hdr_charset = emf->charset ? emf->charset : emf->default_charset;
- 	
+ 
  	header = ((CamelMimePart *)part)->headers;
  	while (header) {
  		if (!g_ascii_strcasecmp (header->name, "Sender")) {
diff --cc mail/em-mailer-prefs.h
index c7dc6ac,10503a8..fddc7cd
--- a/mail/em-mailer-prefs.h
+++ b/mail/em-mailer-prefs.h
@@@ -97,29 -111,31 +97,29 @@@ struct _EMMailerPrefs 
  	guint labels_change_notify_id; /* mail_config's notify id */
  
  	/* Headers tab */
 -	struct _GtkButton *add_header;
 -	struct _GtkButton *remove_header;
 -	struct _GtkEntry *entry_header;
 -	struct _GtkTreeView *header_list;
 -	struct _GtkListStore *header_list_store;
 -	struct _GtkToggleButton *photo_show;
 -	struct _GtkToggleButton *photo_local;
 +	GtkButton *add_header;
 +	GtkButton *remove_header;
 +	GtkEntry *entry_header;
 +	GtkTreeView *header_list;
 +	GtkListStore *header_list_store;
  
  	/* Junk prefs */
 -	struct _GtkToggleButton *check_incoming;
 -	struct _GtkToggleButton *empty_junk;
 -	struct _GtkComboBox *empty_junk_days;
 -
 -	struct _GtkToggleButton *sa_local_tests_only;
 -	struct _GtkToggleButton *sa_use_daemon;
 -	struct _GtkComboBox *default_junk_plugin;
 -	struct _GtkLabel *plugin_status;
 -	struct _GtkImage *plugin_image;
 -
 -	struct _GtkToggleButton *junk_header_check;
 -	struct _GtkTreeView *junk_header_tree;
 -	struct _GtkButton *junk_header_add;
 -	struct _GtkButton *junk_header_remove;
 -	struct _GtkToggleButton *junk_book_lookup;
 -	struct _GtkToggleButton *junk_lookup_local_only;
 +	GtkToggleButton *empty_junk;
 +	GtkComboBox *empty_junk_days;
- 	
++
 +	GtkToggleButton *sa_local_tests_only;
 +	GtkToggleButton *sa_use_daemon;
 +	GtkComboBox *default_junk_plugin;
 +	GtkLabel *plugin_status;
 +	GtkImage *plugin_image;
 +
 +	GtkToggleButton *junk_header_check;
 +	GtkTreeView *junk_header_tree;
- 	GtkListStore *junk_header_list_store;	
++	GtkListStore *junk_header_list_store;
 +	GtkButton *junk_header_add;
 +	GtkButton *junk_header_remove;
 +	GtkToggleButton *junk_book_lookup;
 +	GtkToggleButton *junk_lookup_local_only;
  };
  
  struct _EMMailerPrefsClass {
diff --cc mail/em-network-prefs.h
index 50d986c,3d933a7..bd4e9e7
--- a/mail/em-network-prefs.h
+++ b/mail/em-network-prefs.h
@@@ -58,38 -51,48 +58,38 @@@ typedef enum 
  	NETWORK_PROXY_AUTOCONFIG
  } NetworkConfigProxyType;
  
 -
  struct _EMNetworkPrefs {
  	GtkVBox parent_object;
- 	
+ 
 -	struct _GConfClient *gconf;
 +	GConfClient *gconf;
- 	
+ 
 -	struct _GladeXML *gui;
 +	GladeXML *gui;
- 	
+ 
  	/* Default Behavior */
 -	struct _GtkToggleButton *sys_proxy;
 -	struct _GtkToggleButton *no_proxy;
 -	struct _GtkToggleButton *manual_proxy;
 -#if 0
 -	struct _GtkToggleButton *auto_proxy;
 -#endif
 -	struct _GtkToggleButton *use_auth;
 -
 -	struct _GtkEntry *http_host;
 -	struct _GtkEntry *https_host;
 -	struct _GtkEntry *ignore_hosts;
 -#if 0
 -	struct _GtkEntry *auto_proxy_url;
 -#endif
 -	struct _GtkEntry *auth_user;
 -	struct _GtkEntry *auth_pwd;
 -
 -	struct _GtkLabel *lbl_http_host;
 -	struct _GtkLabel *lbl_http_port;
 -	struct _GtkLabel *lbl_https_host;
 -	struct _GtkLabel *lbl_https_port;
 -	struct _GtkLabel *lbl_ignore_hosts;
 -	struct _GtkLabel *lbl_auth_user;
 -	struct _GtkLabel *lbl_auth_pwd;
 -
 -	struct _GtkSpinButton *http_port;
 -	struct _GtkSpinButton *https_port;
 -#if 0
 -	struct _GtkLabel *lbl_socks_host;
 -	struct _GtkEntry *socks_host;
 -	struct _GtkLabel *lbl_socks_port;
 -	struct _GtkSpinButton *socks_port;
 -#endif
 +	GtkToggleButton *sys_proxy;
 +	GtkToggleButton *no_proxy;
 +	GtkToggleButton *manual_proxy;
 +	GtkToggleButton *use_auth;
 +
 +	GtkEntry *http_host;
 +	GtkEntry *https_host;
 +	GtkEntry *socks_host;
 +	GtkEntry *ignore_hosts;
 +	GtkEntry *auth_user;
 +	GtkEntry *auth_pwd;
 +
 +	GtkLabel *lbl_http_host;
 +	GtkLabel *lbl_http_port;
 +	GtkLabel *lbl_https_host;
 +	GtkLabel *lbl_https_port;
 +	GtkLabel *lbl_socks_host;
 +	GtkLabel *lbl_socks_port;
 +	GtkLabel *lbl_ignore_hosts;
 +	GtkLabel *lbl_auth_user;
 +	GtkLabel *lbl_auth_pwd;
 +
 +	GtkSpinButton *http_port;
 +	GtkSpinButton *https_port;
  };
  
  struct _EMNetworkPrefsClass {
diff --cc mail/em-utils.c
index 2a7ce74,ba180e5..9b27869
--- a/mail/em-utils.c
+++ b/mail/em-utils.c
@@@ -1401,16 -1384,13 +1401,16 @@@ em_utils_folder_is_templates (CamelFold
  	int is = FALSE;
  	char *templates_uri;
  
 -	if (folder == mail_component_get_folder (NULL, MAIL_COMPONENT_FOLDER_TEMPLATES))
 +	local_templates_folder = e_mail_shell_backend_get_folder (
 +		global_mail_shell_backend, E_MAIL_FOLDER_TEMPLATES);
 +
 +	if (folder == local_templates_folder)
  		return TRUE;
- 	
+ 
 -	if (uri == NULL)
 +	if (folder == NULL || uri == NULL)
  		return FALSE;
- 		
+ 
 -	accounts = mail_config_get_accounts();
 +	accounts = e_get_account_list ();
  	iter = e_list_get_iterator ((EList *)accounts);
  	while (e_iterator_is_valid (iter)) {
  		account = (EAccount *)e_iterator_get (iter);
diff --cc mail/evolution-module-mail.c
index a629681,0000000..97bc953
mode 100644,000000..100644
--- a/mail/evolution-module-mail.c
+++ b/mail/evolution-module-mail.c
@@@ -1,59 -1,0 +1,59 @@@
 +/*
 + * evolution-module-mail.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-mail-shell-backend.h"
 +#include "e-mail-shell-content.h"
 +#include "e-mail-shell-sidebar.h"
 +#include "e-mail-shell-view.h"
 +
 +/* Module Entry Points */
 +void e_module_load (GTypeModule *type_module);
 +void e_module_unload (GTypeModule *type_module);
 +const gchar * g_module_check_init (GModule *module);
 +
 +G_MODULE_EXPORT void
 +e_module_load (GTypeModule *type_module)
 +{
 +	/* Register dynamically loaded types. */
 +
 +	e_mail_shell_backend_register_type (type_module);
 +	e_mail_shell_content_register_type (type_module);
 +	e_mail_shell_sidebar_register_type (type_module);
 +	e_mail_shell_view_register_type (type_module);
 +}
 +
 +G_MODULE_EXPORT void
 +e_module_unload (GTypeModule *type_module)
 +{
 +}
 +
 +G_MODULE_EXPORT const gchar *
 +g_module_check_init (GModule *module)
 +{
 +	/* FIXME Until mail is split into a module library and a
 +	 *       reusable shared library, prevent the module from
 +	 *       being unloaded.  Unloading the module resets all
 +	 *       static variables, which screws up foo_get_type()
 +	 *       functions among other things. */
 +	g_module_make_resident (module);
 +
 +	return NULL;
 +}
diff --cc mail/mail-component.c
index 6167cc5,698cc94..7cf42f6
--- a/mail/mail-component.c
+++ b/mail/mail-component.c
@@@ -382,12 -862,9 +382,11 @@@ impl_quit(PortableServer_Servant servan
  	if (mc->priv->quit_state == -1)
  		mc->priv->quit_state = MC_QUIT_START;
  
 -	mail_config_prune_proxies ();
 +	account_list = e_get_account_list ();
 +	e_account_list_prune_proxies (account_list);
 +
  	switch (mc->priv->quit_state) {
  	case MC_QUIT_START: {
- 		extern int camel_application_is_exiting;
  		int now = time(NULL)/60/60/24, days;
  		gboolean empty_junk;
  
@@@ -507,21 -1304,297 +506,21 @@@ mail_component_init (MailComponent *com
  	e_activity_handler_set_logger (priv->activity_handler, priv->logger);
  	e_activity_handler_set_error_flush_time (priv->activity_handler, mail_config_get_error_timeout ()*1000);
  
 -	mail_session_init (e_get_user_data_dir ());
 -
 -	priv->async_event = mail_async_event_new();
 -	priv->store_hash = g_hash_table_new_full (
 -		NULL, NULL,
 -		(GDestroyNotify) NULL,
 -		(GDestroyNotify) store_hash_free);
 -
 -	mail_autoreceive_init (session);
 -
 -	priv->mail_sync_in_progress = 0;
 -	if (g_getenv("CAMEL_FLUSH_CHANGES"))
 -		priv->mail_sync_id = g_timeout_add_seconds (mail_config_get_sync_timeout (), call_mail_sync, component);
 -	else
 -		priv->mail_sync_id = 0;
 -}
 -
 -/* Public API.  */
 -MailComponent *
 -mail_component_peek (void)
 -{
 -	static MailComponent *component = NULL;
 -
 -	if (component == NULL)
 -		component = g_object_new(mail_component_get_type(), NULL);
 -
 -	return component;
 -}
 -
 -const char *
 -mail_component_peek_base_directory (MailComponent *component)
 -{
 -	MAIL_COMPONENT_DEFAULT(component);
 -
 -	return component->priv->base_directory;
 -}
 -
 -RuleContext *
 -mail_component_peek_search_context (MailComponent *component)
 -{
 -	MAIL_COMPONENT_DEFAULT(component);
 -
 -	setup_search_context(component);
 -
 -	return component->priv->search_context;
 -}
 -
 -EActivityHandler *
 -mail_component_peek_activity_handler (MailComponent *component)
 -{
 -	MAIL_COMPONENT_DEFAULT(component);
 -
 -	return component->priv->activity_handler;
 -}
 -
 -struct _CamelSession *mail_component_peek_session(MailComponent *component)
 -{
 -	MAIL_COMPONENT_DEFAULT(component);
 -
 -	return session;
 -}
 -
 -void
 -mail_component_add_store (MailComponent *component, CamelStore *store, const char *name)
 -{
 -	mc_add_store(component, store, name, NULL);
 -}
 -
 -/**
 - * mail_component_load_store_by_uri:
 - * @component: mail component
 - * @uri: uri of store
 - * @name: name of store (used for display purposes)
 - *
 - * Return value: Pointer to the newly added CamelStore.  The caller is supposed
 - * to ref the object if it wants to store it.
 - **/
 -CamelStore *
 -mail_component_load_store_by_uri (MailComponent *component, const char *uri, const char *name)
 -{
 -	CamelException ex;
 -	CamelStore *store;
 -	CamelProvider *prov;
 -
 -	MAIL_COMPONENT_DEFAULT(component);
 -
 -	camel_exception_init (&ex);
 -
 -	/* Load the service (don't connect!). Check its provider and
 -	 * see if this belongs in the shell's folder list. If so, add
 -	 * it.
 -	 */
 -
 -	prov = camel_provider_get(uri, &ex);
 -	if (prov == NULL) {
 -		/* EPFIXME: real error dialog */
 -		g_warning ("couldn't get service %s: %s\n", uri,
 -			   camel_exception_get_description (&ex));
 -		camel_exception_clear (&ex);
 -		return NULL;
 -	}
 -
 -	if (!(prov->flags & CAMEL_PROVIDER_IS_STORAGE))
 -		return NULL;
 -
 -	store = (CamelStore *) camel_session_get_service (session, uri, CAMEL_PROVIDER_STORE, &ex);
 -	if (store == NULL) {
 -		/* EPFIXME: real error dialog */
 -		g_warning ("couldn't get service %s: %s\n", uri,
 -			   camel_exception_get_description (&ex));
 -		camel_exception_clear (&ex);
 -		return NULL;
 -	}
 -
 -	mail_component_add_store(component, store, name);
 -	camel_object_unref (store);
 -
 -	return store;
 -}
 -
 -static void
 -store_disconnect (CamelStore *store, void *event_data, void *user_data)
 -{
 -	camel_service_disconnect (CAMEL_SERVICE (store), TRUE, NULL);
 -	camel_object_unref (store);
 -}
 -
 -void
 -mail_component_remove_store (MailComponent *component, CamelStore *store)
 -{
 -	MailComponentPrivate *priv;
 -
 -	MAIL_COMPONENT_DEFAULT(component);
 -
 -	priv = component->priv;
 -
 -	/* Because the store_hash holds a reference to each store
 -	 * used as a key in it, none of them will ever be gc'ed, meaning
 -	 * any call to camel_session_get_{service,store} with the same
 -	 * URL will always return the same object. So this works.
 -	 */
 -
 -	if (g_hash_table_lookup (priv->store_hash, store) == NULL)
 -		return;
 -
 -	camel_object_ref (store);
 -	g_hash_table_remove (priv->store_hash, store);
 -
 -	/* so i guess potentially we could have a race, add a store while one
 -	   being removed.  ?? */
 -	mail_note_store_remove (store);
 -
 -	em_folder_tree_model_remove_store (priv->model, store);
 -
 -	mail_async_event_emit (priv->async_event, MAIL_ASYNC_THREAD, (MailAsyncFunc) store_disconnect, store, NULL, NULL);
 -}
 -
 -void
 -mail_component_remove_store_by_uri (MailComponent *component, const char *uri)
 -{
 -	CamelProvider *prov;
 -	CamelStore *store;
 -
 -	MAIL_COMPONENT_DEFAULT(component);
 -
 -	if (!(prov = camel_provider_get(uri, NULL)))
 -		return;
 -
 -	if (!(prov->flags & CAMEL_PROVIDER_IS_STORAGE))
 -		return;
 -
 -	store = (CamelStore *) camel_session_get_service (session, uri, CAMEL_PROVIDER_STORE, NULL);
 -	if (store != NULL) {
 -		mail_component_remove_store (component, store);
 -		camel_object_unref (store);
 -	}
 -}
 -
 -int
 -mail_component_get_store_count (MailComponent *component)
 -{
 -	MAIL_COMPONENT_DEFAULT(component);
 -
 -	return g_hash_table_size (component->priv->store_hash);
 -}
 -
 -/* need to map from internal struct to external api */
 -struct _store_foreach_data {
 -	GHFunc func;
 -	void *data;
 -};
 -
 -static void
 -mc_stores_foreach(CamelStore *store, struct _store_info *si, struct _store_foreach_data *data)
 -{
 -	data->func((void *)store, (void *)si->name, data->data);
 -}
 -
 -void
 -mail_component_stores_foreach (MailComponent *component, GHFunc func, void *user_data)
 -{
 -	struct _store_foreach_data data = { func, user_data };
 -
 -	MAIL_COMPONENT_DEFAULT(component);
 -
 -	g_hash_table_foreach (component->priv->store_hash, (GHFunc)mc_stores_foreach, &data);
 -}
 -
 -void
 -mail_component_remove_folder (MailComponent *component, CamelStore *store, const char *path)
 -{
 -	MAIL_COMPONENT_DEFAULT(component);
 -
 -	/* FIXME: implement me. but first, am I really even needed? */
 -}
 -
 -EMFolderTreeModel *
 -mail_component_peek_tree_model (MailComponent *component)
 -{
 -	MAIL_COMPONENT_DEFAULT(component);
 -
 -	return component->priv->model;
 -}
 -
 -CamelStore *
 -mail_component_peek_local_store (MailComponent *mc)
 -{
 -	MAIL_COMPONENT_DEFAULT (mc);
 -	mc_setup_local_store (mc);
 -
 -	return mc->priv->local_store;
 -}
 +//	mail_session_init (e_get_user_data_dir ());
  
 -/**
 - * mail_component_get_folder:
 - * @mc:
 - * @id:
 - *
 - * Get a standard/default folder by id.  This call is thread-safe.
 - *
 - * Return value:
 - **/
 -struct _CamelFolder *
 -mail_component_get_folder(MailComponent *mc, enum _mail_component_folder_t id)
 -{
 -	g_return_val_if_fail (id <= MAIL_COMPONENT_FOLDER_LOCAL_INBOX, NULL);
 +//	priv->async_event = mail_async_event_new();
 +//	priv->store_hash = g_hash_table_new_full (
 +//		NULL, NULL,
 +//		(GDestroyNotify) NULL,
 +//		(GDestroyNotify) store_hash_free);
  
 -	MAIL_COMPONENT_DEFAULT(mc);
 -	mc_setup_local_store(mc);
 +//	mail_autoreceive_init (session);
  
 -	return mc_default_folders[id].folder;
 -}
 -
 -/**
 - * mail_component_get_folder_uri:
 - * @mc:
 - * @id:
 - *
 - * Get a standard/default folder's uri.  This call is thread-safe.
 - *
 - * Return value:
 - **/
 -const char *
 -mail_component_get_folder_uri(MailComponent *mc, enum _mail_component_folder_t id)
 -{
 -	g_return_val_if_fail (id <= MAIL_COMPONENT_FOLDER_LOCAL_INBOX, NULL);
 -
 -	MAIL_COMPONENT_DEFAULT(mc);
 -	mc_setup_local_store(mc);
 -
 -	return mc_default_folders[id].uri;
 -}
 -
 -/**
 - * mail_indicate_new_mail
 - * Indicates new mail in a shell window.
 - * @param have_new_mail TRUE when have new mail, false otherwise.
 - **/
 -void
 -mail_indicate_new_mail (gboolean have_new_mail)
 -{
 -	const char *icon = NULL;
 -	MailComponent *mc = mail_component_peek ();
 -
 -	g_return_if_fail (mc != NULL);
 -
 -	if (have_new_mail)
 -		icon = "mail-unread";
 -
 -	if (mc->priv->component_view)
 -		e_component_view_set_button_icon (mc->priv->component_view, icon);
 +//	priv->mail_sync_in_progress = 0;
 +//	if (g_getenv("CAMEL_FLUSH_CHANGES"))
 +//		priv->mail_sync_id = g_timeout_add_seconds (mail_config_get_sync_timeout (), call_mail_sync, component);
- //	else 
++//	else
 +//		priv->mail_sync_id = 0;
  }
  
  void
diff --cc mail/mail-config.c
index 45fc8f9,bcf8dd7..59bab65
--- a/mail/mail-config.c
+++ b/mail/mail-config.c
@@@ -93,7 -110,18 +95,6 @@@ extern int camel_header_param_encode_fi
  static MailConfig *config = NULL;
  static guint config_write_timeout = 0;
  
- 
 -void
 -mail_config_save_accounts (void)
 -{
 -	e_account_list_save (config->accounts);
 -}
 -
 -void
 -mail_config_save_signatures (void)
 -{
 -	e_signature_list_save (config->signatures);
 -}
 -
  static void
  config_clear_mime_types (void)
  {
@@@ -800,15 -991,15 +799,16 @@@ mail_config_uri_renamed (GCompareFunc u
  	EIterator *iter;
  	int i, work = 0;
  	char *oldname, *newname;
- 	char *cachenames[] = { "config/hidestate-",
- 			       "config/et-expanded-",
- 			       "config/et-header-",
- 			       "*views/current_view-",
- 			       "*views/custom_view-",
- 			       NULL };
+ 	const gchar *cachenames[] = {
+ 		"config/hidestate-",
+ 		"config/et-expanded-",
+ 		"config/et-header-",
+ 		"*views/current_view-",
+ 		"*views/custom_view-",
+ 		NULL };
  
 -	iter = e_list_get_iterator ((EList *) config->accounts);
 +	account_list = e_get_account_list ();
 +	iter = e_list_get_iterator ((EList *) account_list);
  	while (e_iterator_is_valid (iter)) {
  		account = (EAccount *) e_iterator_get (iter);
  
diff --cc mail/mail-folder-cache.c
index b6a92bc,a84dfcb..23b85ac
--- a/mail/mail-folder-cache.c
+++ b/mail/mail-folder-cache.c
@@@ -197,8 -196,7 +197,9 @@@ real_flush_updates (EMailShellBackend *
  			t->name = em_folder_tree_model_get_folder_name (model, up->store, up->full_name);
  
  			if (t->new > 0)
 -				mail_indicate_new_mail (TRUE);
 +				e_shell_event (
- 					shell, "mail-icon", "mail-unread");
++					shell, "mail-icon",
++					(gpointer) "mail-unread");
  
  			/** @Event: folder.changed
  			 * @Title: Folder changed
diff --cc mail/mail-send-recv.c
index 7b63263,be834bb..a463bb8
--- a/mail/mail-send-recv.c
+++ b/mail/mail-send-recv.c
@@@ -1234,11 -1204,10 +1234,11 @@@ mail_send (void
  
  	d(printf("Adding new info %p\n", info));
  
- 	g_hash_table_insert (data->active, SEND_URI_KEY, info);
+ 	g_hash_table_insert (data->active, (gpointer) SEND_URI_KEY, info);
  
  	/* todo, store the folder in info? */
 -	outbox_folder = mail_component_get_folder(NULL, MAIL_COMPONENT_FOLDER_OUTBOX);
 +	outbox_folder = e_mail_shell_backend_get_folder (
 +		global_mail_shell_backend, E_MAIL_FOLDER_OUTBOX);
  	mail_send_queue (outbox_folder, info->uri,
  			 FILTER_SOURCE_OUTGOING,
  			 info->cancel,
diff --cc mail/message-list.c
index e970a09,09f080c..8d84e4a
--- a/mail/message-list.c
+++ b/mail/message-list.c
@@@ -122,13 -113,8 +122,13 @@@ struct _MessageListPrivate 
  	gboolean any_row_changed; /* save state before regen list when this is set to true */
  };
  
 +enum {
 +	PROP_0,
 +	PROP_SHELL_BACKEND
 +};
 +
  static struct {
- 	char *target;
+ 	const gchar *target;
  	GdkAtom atom;
  	guint32 actions;
  } ml_drag_info[] = {
diff --cc plugins/imap-features/Makefile.am
index b0f34f1,69b94ff..cf7dbd7
--- a/plugins/imap-features/Makefile.am
+++ b/plugins/imap-features/Makefile.am
@@@ -1,7 -1,10 +1,6 @@@
  INCLUDES =						\
 -if OS_WIN32
 -NO_UNDEFINED_REQUIRED_LIBS = $(top_builddir)/mail/libevolution-mail.la
 -endif
 -
  	-I$(top_srcdir)					\
  	-I$(top_srcdir)/mail				\
- 	-I$(top_srcdir)/libedataserver			\
  	$(EVOLUTION_MAIL_CFLAGS)			\
  	$(CAMEL_IMAP_CFLAGS)				\
  	-DEVOLUTION_GLADEDIR=\""$(gladedir)"\"		\
diff --cc shell/e-shell-backend.c
index e1b29ae,0000000..06e1469
mode 100644,000000..100644
--- a/shell/e-shell-backend.c
+++ b/shell/e-shell-backend.c
@@@ -1,458 -1,0 +1,458 @@@
 +/*
 + * e-shell-backend.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-shell-backend.h"
 +
 +#include <errno.h>
 +#include <glib/gi18n.h>
 +
 +#include "e-util/e-util.h"
 +
 +#include "e-shell.h"
 +#include "e-shell-view.h"
 +
 +#define E_SHELL_BACKEND_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_SHELL_BACKEND, EShellBackendPrivate))
 +
 +struct _EShellBackendPrivate {
 +
 +	gpointer shell;  /* weak pointer */
 +
 +	/* We keep a reference to corresponding EShellView subclass
 +	 * since it keeps a reference back to us.  This ensures the
 +	 * subclass is not finalized before we are, otherwise it
 +	 * would leak its EShellBackend reference. */
 +	EShellViewClass *shell_view_class;
 +
 +	gchar *config_dir;
 +	gchar *data_dir;
 +
 +	guint started	: 1;
 +};
 +
 +enum {
 +	PROP_0,
 +	PROP_SHELL
 +};
 +
 +enum {
 +	ACTIVITY_ADDED,
 +	LAST_SIGNAL
 +};
 +
 +static gpointer parent_class;
 +static guint signals[LAST_SIGNAL];
 +
 +static void
 +shell_backend_set_shell (EShellBackend *shell_backend,
 +                         EShell *shell)
 +{
 +	g_return_if_fail (shell_backend->priv->shell == NULL);
 +
 +	shell_backend->priv->shell = shell;
 +
 +	g_object_add_weak_pointer (
 +		G_OBJECT (shell_backend),
 +		&shell_backend->priv->shell);
 +}
 +
 +static void
 +shell_backend_set_property (GObject *object,
 +                            guint property_id,
 +                            const GValue *value,
 +                            GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_SHELL:
 +			shell_backend_set_shell (
 +				E_SHELL_BACKEND (object),
 +				g_value_get_object (value));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +shell_backend_get_property (GObject *object,
 +                            guint property_id,
 +                            GValue *value,
 +                            GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_SHELL:
 +			g_value_set_object (
 +				value, e_shell_backend_get_shell (
 +				E_SHELL_BACKEND (object)));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +shell_backend_dispose (GObject *object)
 +{
 +	EShellBackendPrivate *priv;
 +
 +	priv = E_SHELL_BACKEND_GET_PRIVATE (object);
 +
 +	if (priv->shell_view_class != NULL) {
 +		g_type_class_unref (priv->shell_view_class);
 +		priv->shell_view_class = NULL;
 +	}
 +
 +	/* Chain up to parent's dispose() method. */
 +	G_OBJECT_CLASS (parent_class)->dispose (object);
 +}
 +
 +static void
 +shell_backend_finalize (GObject *object)
 +{
 +	EShellBackendPrivate *priv;
 +
 +	priv = E_SHELL_BACKEND_GET_PRIVATE (object);
 +
 +	g_free (priv->data_dir);
 +
 +	/* Chain up to parent's finalize() method. */
 +	G_OBJECT_CLASS (parent_class)->finalize (object);
 +}
 +
 +static void
 +shell_backend_class_init (EShellBackendClass *class)
 +{
 +	GObjectClass *object_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (EShellBackendPrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->set_property = shell_backend_set_property;
 +	object_class->get_property = shell_backend_get_property;
 +	object_class->dispose = shell_backend_dispose;
 +	object_class->finalize = shell_backend_finalize;
 +
 +	/**
 +	 * EShellBackend:shell
 +	 *
 +	 * The #EShell singleton.
 +	 **/
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_SHELL,
 +		g_param_spec_object (
 +			"shell",
 +			_("Shell"),
 +			_("The EShell singleton"),
 +			E_TYPE_SHELL,
 +			G_PARAM_READWRITE |
 +			G_PARAM_CONSTRUCT_ONLY));
 +
 +	/**
 +	 * EShellBackend::activity-added
 +	 * @shell_backend: the #EShellBackend that emitted the signal
 +	 * @activity: an #EActivity
 +	 *
 +	 * Broadcasts a newly added activity.
 +	 **/
 +	signals[ACTIVITY_ADDED] = g_signal_new (
 +		"activity-added",
 +		G_OBJECT_CLASS_TYPE (object_class),
 +		G_SIGNAL_RUN_LAST,
 +		0, NULL, NULL,
 +		g_cclosure_marshal_VOID__OBJECT,
 +		G_TYPE_NONE, 1,
 +		E_TYPE_ACTIVITY);
 +}
 +
 +static void
 +shell_backend_init (EShellBackend *shell_backend,
 +                    EShellBackendClass *class)
 +{
 +	EShellViewClass *shell_view_class;
 +	gchar *dirname;
 +
 +	shell_backend->priv = E_SHELL_BACKEND_GET_PRIVATE (shell_backend);
 +
 +	/* Install a reference to ourselves in the corresponding
 +	 * EShellViewClass structure, */
 +	shell_view_class = g_type_class_ref (class->shell_view_type);
 +	shell_view_class->shell_backend = g_object_ref (shell_backend);
 +	shell_backend->priv->shell_view_class = shell_view_class;
 +
 +	/* Determine the user data directory for this backend. */
 +	shell_backend->priv->data_dir = g_build_filename (
 +		e_get_user_data_dir (), class->name, NULL);
 +
 +	/* Determine the user configuration directory for this backend. */
 +	shell_backend->priv->config_dir = g_build_filename (
 +		shell_backend->priv->data_dir, "config", NULL);
 +
 +	/* Create the user configuration directory for this backend,
 +	 * which should also create the user data directory. */
 +	dirname = shell_backend->priv->config_dir;
 +	if (g_mkdir_with_parents (dirname, 0777) != 0)
 +		g_critical (
 +			"Cannot create directory %s: %s",
 +			dirname, g_strerror (errno));
 +}
 +
 +GType
 +e_shell_backend_get_type (void)
 +{
 +	static GType type = 0;
 +
 +	if (G_UNLIKELY (type == 0)) {
 +		const GTypeInfo type_info = {
 +			sizeof (EShellBackendClass),
 +			(GBaseInitFunc) NULL,
 +			(GBaseFinalizeFunc) NULL,
 +			(GClassInitFunc) shell_backend_class_init,
 +			(GClassFinalizeFunc) NULL,
 +			NULL,  /* class_data */
 +			sizeof (EShellBackend),
 +			0,     /* n_preallocs */
 +			(GInstanceInitFunc) shell_backend_init,
 +			NULL   /* value_table */
 +		};
 +
 +		type = g_type_register_static (
 +			G_TYPE_OBJECT, "EShellBackend", &type_info, 0);
 +	}
 +
 +	return type;
 +}
 +
 +/**
 + * e_shell_backend_compare:
 + * @shell_backend_a: an #EShellBackend
 + * @shell_backend_b: an #EShellBackend
 + *
 + * Using the <structfield>sort_order</structfield> field from both backends'
 + * #EShellBackendClass, compares @shell_backend_a with @shell_mobule_b and
 + * returns -1, 0 or +1 if @shell_backend_a is found to be less than, equal
 + * to or greater than @shell_backend_b, respectively.
 + *
 + * Returns: -1, 0 or +1, for a less than, equal to or greater than result
 + **/
 +gint
 +e_shell_backend_compare (EShellBackend *shell_backend_a,
 +                         EShellBackend *shell_backend_b)
 +{
 +	gint a = E_SHELL_BACKEND_GET_CLASS (shell_backend_a)->sort_order;
 +	gint b = E_SHELL_BACKEND_GET_CLASS (shell_backend_b)->sort_order;
 +
 +	return (a < b) ? -1 : (a > b);
 +}
 +
 +/**
 + * e_shell_backend_get_config_dir:
 + * @shell_backend: an #EShellBackend
 + *
 + * Returns the absolute path to the configuration directory for
 + * @shell_backend.  The string is owned by @shell_backend and should
 + * not be modified or freed.
 + *
 + * Returns: the backend's configuration directory
 + **/
 +const gchar *
 +e_shell_backend_get_config_dir (EShellBackend *shell_backend)
 +{
 +	g_return_val_if_fail (E_IS_SHELL_BACKEND (shell_backend), NULL);
 +	g_return_val_if_fail (shell_backend->priv->config_dir != NULL, NULL);
 +
 +	return shell_backend->priv->config_dir;
 +}
 +
 +/**
 + * e_shell_backend_get_data_dir:
 + * @shell_backend: an #EShellBackend
 + *
 + * Returns the absolute path to the data directory for @shell_backend.
 + * The string is owned by @shell_backend and should not be modified or
 + * freed.
 + *
 + * Returns: the backend's data directory
 + **/
 +const gchar *
 +e_shell_backend_get_data_dir (EShellBackend *shell_backend)
 +{
 +	g_return_val_if_fail (E_IS_SHELL_BACKEND (shell_backend), NULL);
 +	g_return_val_if_fail (shell_backend->priv->data_dir != NULL, NULL);
 +
 +	return shell_backend->priv->data_dir;
 +}
 +
 +/**
 + * e_shell_backend_get_shell:
 + * @shell_backend: an #EShellBackend
 + *
 + * Returns the #EShell singleton.
 + *
 + * Returns: the #EShell
 + **/
 +EShell *
 +e_shell_backend_get_shell (EShellBackend *shell_backend)
 +{
 +	g_return_val_if_fail (E_IS_SHELL_BACKEND (shell_backend), NULL);
 +
 +	return E_SHELL (shell_backend->priv->shell);
 +}
 +
 +/**
 + * e_shell_backend_add_activity:
 + * @shell_backend: an #EShellBackend
 + * @activity: an #EActivity
 + *
 + * Emits an #EShellBackend::activity-added signal.
 + **/
 +void
 +e_shell_backend_add_activity (EShellBackend *shell_backend,
 +                              EActivity *activity)
 +{
 +	g_return_if_fail (E_IS_SHELL_BACKEND (shell_backend));
 +	g_return_if_fail (E_IS_ACTIVITY (activity));
 +
 +	g_signal_emit (shell_backend, signals[ACTIVITY_ADDED], 0, activity);
 +}
 +
 +/**
 + * e_shell_backend_start:
 + * @shell_backend: an #EShellBackend
 + *
 + * Tells the @shell_backend to begin loading data or running background
 + * tasks which may consume significant resources.  This gets called in
 + * reponse to the user switching to the corresponding #EShellView for
 + * the first time.  The function is idempotent for each @shell_backend.
 + **/
 +void
 +e_shell_backend_start (EShellBackend *shell_backend)
 +{
 +	EShellBackendClass *class;
 +
 +	g_return_if_fail (E_IS_SHELL_BACKEND (shell_backend));
 +
 +	if (shell_backend->priv->started)
 +		return;
 +
 +	class = E_SHELL_BACKEND_GET_CLASS (shell_backend);
 +
 +	if (class->start != NULL)
 +		class->start (shell_backend);
 +
 +	shell_backend->priv->started = TRUE;
 +}
 +
 +/**
 + * e_shell_backend_is_busy:
 + * @shell_backend: an #EShellBackend
 + *
 + * Returns %TRUE if @shell_backend is busy and cannot be shutdown at
 + * present.  Each backend must define what "busy" means to them and
 + * determine an appropriate response.
 + *
 + * XXX This function is likely to change or disappear.  I'm toying with
 + *     the idea of just having it check whether there are any unfinished
 + *     #EActivity<!-- -->'s left, so we have a consistent and easily
 + *     testable definition of what "busy" means.
 + *
 + * Returns: %TRUE if the backend is busy
 + **/
 +gboolean
 +e_shell_backend_is_busy (EShellBackend *shell_backend)
 +{
 +	EShellBackendClass *class;
 +
 +	g_return_val_if_fail (E_IS_SHELL_BACKEND (shell_backend), FALSE);
 +
 +	class = E_SHELL_BACKEND_GET_CLASS (shell_backend);
 +
 +	if (class->is_busy == NULL)
 +		return FALSE;
 +
 +	return class->is_busy (shell_backend);
 +}
 +
 +/**
 + * e_shell_backend_shutdown:
 + * @shell_backend: an #EShellBackend
 + *
 + * Alerts @shell_backend to begin shutdown procedures.  If the backend is
 + * busy and cannot immediately shut down, the function returns %FALSE.
 + * A %TRUE response implies @shell_backend has successfully shut down.
 + *
 + * XXX This function is likely to change or disappear.  I'm toying with
 + *     the idea of just having it check whether there are any unfinished
 + *     #EActivity<!-- -->'s left, so we have a consistent and easily
 + *     testable definition of what "busy" means.
 + *
 + * Returns: %TRUE if the backend has shut down, %FALSE if the backend is
 + *          busy and cannot immediately shut down
 + */
 +gboolean
 +e_shell_backend_shutdown (EShellBackend *shell_backend)
 +{
 +	EShellBackendClass *class;
 +
 +	g_return_val_if_fail (E_IS_SHELL_BACKEND (shell_backend), TRUE);
 +
 +	class = E_SHELL_BACKEND_GET_CLASS (shell_backend);
 +
 +	if (class->shutdown == NULL)
 +		return TRUE;
 +
 +	return class->shutdown (shell_backend);
 +}
 +
 +/**
 + * e_shell_migrate:
 + * @shell_backend: an #EShellBackend
 + * @major: major part of version to migrate from
 + * @minor: minor part of version to migrate from
 + * @micro: micro part of version to migrate from
 + * @error: return location for a #GError, or %NULL
 + *
 + * Attempts to migrate data and settings from version %major.%minor.%micro.
 + * Returns %TRUE if the migration was successful or if no action was
 + * necessary.  Returns %FALSE and sets %error if the migration failed.
 + *
 + * Returns: %TRUE if successful, %FALSE otherwise
 + **/
 +gboolean
 +e_shell_backend_migrate (EShellBackend *shell_backend,
 +                        gint major,
 +                        gint minor,
 +                        gint micro,
 +                        GError **error)
 +{
 +	EShellBackendClass *class;
 +
 +	g_return_val_if_fail (E_IS_SHELL_BACKEND (shell_backend), TRUE);
 +
 +	class = E_SHELL_BACKEND_GET_CLASS (shell_backend);
 +
 +	if (class->migrate == NULL)
 +		return TRUE;
 +
 +	return class->migrate (shell_backend, major, minor, micro, error);
 +}
diff --cc shell/e-shell-backend.h
index 570199c,0000000..57663d8
mode 100644,000000..100644
--- a/shell/e-shell-backend.h
+++ b/shell/e-shell-backend.h
@@@ -1,151 -1,0 +1,151 @@@
 +/*
 + * e-shell-backend.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +/**
 + * SECTION: e-shell-backend
 + * @short_description: dynamically loaded capabilities
 + * @include: shell/e-shell-backend.h
 + **/
 +
 +#ifndef E_SHELL_BACKEND_H
 +#define E_SHELL_BACKEND_H
 +
 +#include <shell/e-shell-common.h>
 +#include <widgets/misc/e-activity.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_SHELL_BACKEND \
 +	(e_shell_backend_get_type ())
 +#define E_SHELL_BACKEND(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_SHELL_BACKEND, EShellBackend))
 +#define E_SHELL_BACKEND_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_SHELL_BACKEND, EShellBackendClass))
 +#define E_IS_SHELL_BACKEND(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_SHELL_BACKEND))
 +#define E_IS_SHELL_BACKEND_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), E_TYPE_SHELL_BACKEND))
 +#define E_SHELL_BACKEND_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_SHELL_BACKEND, EShellBackendClass))
 +
 +G_BEGIN_DECLS
 +
 +/* Avoid including <e-shell.h>, because it includes us! */
 +struct _EShell;
 +
 +typedef struct _EShellBackend EShellBackend;
 +typedef struct _EShellBackendClass EShellBackendClass;
 +typedef struct _EShellBackendPrivate EShellBackendPrivate;
 +
 +/**
 + * EShellBackend:
 + *
 + * Contains only private data that should be read and manipulated using the
 + * functions below.
 + **/
 +struct _EShellBackend {
 +	GObject parent;
 +	EShellBackendPrivate *priv;
 +};
 +
 +/**
 + * EShellBackendClass:
 + * @parent_class:	The parent class structure.
 + * @name:		The name of the backend.  Also becomes the name of
 + * 			the corresponding #EShellView subclass that the
 + * 			backend will register.
 + * @aliases:		Colon-separated list of aliases that can be used
 + * 			when referring to a backend by name.
 + * @schemes:		Colon-separated list of URI schemes.  The #EShell
 + * 			will forward command-line URIs to the appropriate
 + * 			backend based on this list.
 + * @sort_order:		Used to determine the order of backends listed in
 + * 			the main menu and in the switcher.  See
 + * 			e_shell_backend_compare().
 + * @shell_view_type:	#GType for the corresponding #EShellView subclass.
 + * @start:		Method for notifying the backend to begin loading
 + * 			data and running background tasks.  This is called
 + * 			just before the first instantiation of the
 + * 			corresponding #EShellView subclass.  It allows the
 + * 			backend to delay initialization steps that consume
 + * 			significant resources until they are actually needed.
 + * @is_busy:		Method for querying whether the backend has operations
 + * 			in progress that cannot be cancelled or finished
 + * 			immediately.  Returning %TRUE prevents the application
 + * 			from shutting down.
 + * @shutdown:		Method for notifying the backend to begin shutting
 + * 			down.  Returning %FALSE indicates there are still
 + * 			unfinished operations and the #EShell should check
 + * 			back shortly.
 + * @migrate:		Method for notifying the backend to migrate data and
 + * 			settings from the given version.  Returns %TRUE if the
 + * 			migration was successful or if no action was necessary.
 + * 			Returns %FALSE and sets a #GError if the migration
 + * 			failed.
 + *
 + * #EShellBackendClass contains a number of important settings for subclasses.
 + **/
 +struct _EShellBackendClass {
 +	GObjectClass parent_class;
 +
 +	GType shell_view_type;
 +
 +	const gchar *name;
 +	const gchar *aliases;
 +	const gchar *schemes;
 +	gint sort_order;
 +
 +	/* Methods */
 +	void		(*start)		(EShellBackend *shell_backend);
 +	gboolean	(*is_busy)		(EShellBackend *shell_backend);
 +	gboolean	(*shutdown)		(EShellBackend *shell_backend);
 +	gboolean	(*migrate)		(EShellBackend *shell_backend,
 +						 gint major,
 +						 gint minor,
 +						 gint micro,
 +						 GError **error);
 +};
 +
 +GType		e_shell_backend_get_type		(void);
 +gint		e_shell_backend_compare		(EShellBackend *shell_backend_a,
 +						 EShellBackend *shell_backend_b);
 +const gchar *	e_shell_backend_get_config_dir	(EShellBackend *shell_backend);
 +const gchar *	e_shell_backend_get_data_dir	(EShellBackend *shell_backend);
 +const gchar *	e_shell_backend_get_filename	(EShellBackend *shell_backend);
 +struct _EShell *e_shell_backend_get_shell	(EShellBackend *shell_backend);
 +void		e_shell_backend_add_activity	(EShellBackend *shell_backend,
 +						 EActivity *activity);
 +void		e_shell_backend_start		(EShellBackend *shell_backend);
 +gboolean	e_shell_backend_is_busy		(EShellBackend *shell_backend);
 +gboolean	e_shell_backend_shutdown	(EShellBackend *shell_backend);
 +gboolean	e_shell_backend_migrate		(EShellBackend *shell_backend,
 +						 gint major,
 +						 gint minor,
 +						 gint micro,
 +						 GError **error);
 +
 +G_END_DECLS
 +
 +#endif /* E_SHELL_BACKEND_H */
diff --cc shell/e-shell-common.h
index 50c8415,0000000..7ff3509
mode 100644,000000..100644
--- a/shell/e-shell-common.h
+++ b/shell/e-shell-common.h
@@@ -1,33 -1,0 +1,33 @@@
 +/*
 + * e-shell-common.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_SHELL_COMMON_H
 +#define E_SHELL_COMMON_H
 +
 +#ifdef HAVE_CONFIG_H
 +#include <config.h>
 +#endif
 +
 +#include <gio/gio.h>
 +#include <gtk/gtk.h>
 +#include <gdk/gdkkeysyms.h>
 +
 +#endif /* E_SHELL_COMMON_H */
diff --cc shell/e-shell-content.c
index ff344ae,0000000..b557908
mode 100644,000000..100644
--- a/shell/e-shell-content.c
+++ b/shell/e-shell-content.c
@@@ -1,1384 -1,0 +1,1384 @@@
 +/*
 + * e-shell-content.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-shell-content.h"
 +
 +#include <glib/gi18n.h>
 +
 +#include <filter/rule-editor.h>
 +#include <widgets/misc/e-action-combo-box.h>
 +#include <widgets/misc/e-icon-entry.h>
 +
 +#include <e-shell-backend.h>
 +#include <e-shell-view.h>
 +#include <e-shell-window-actions.h>
 +
 +#define E_SHELL_CONTENT_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_SHELL_CONTENT, EShellContentPrivate))
 +
 +struct _EShellContentPrivate {
 +
 +	gpointer shell_view;  /* weak pointer */
 +
 +	RuleContext *search_context;
 +	FilterRule *search_rule;
 +	gchar *system_filename;
 +	gchar *user_filename;
 +
 +	/* Container for the following widgets */
 +	GtkWidget *search_bar;
 +
 +	/* Search bar widgets */
 +	GtkWidget *filter_label;
 +	GtkWidget *filter_combo_box;
 +	GtkWidget *search_label;
 +	GtkWidget *search_entry;
 +	GtkWidget *scope_label;
 +	GtkWidget *scope_combo_box;
 +
 +	GtkStateType search_state;
 +};
 +
 +enum {
 +	PROP_0,
 +	PROP_FILTER_ACTION,
 +	PROP_FILTER_VALUE,
 +	PROP_FILTER_VISIBLE,
 +	PROP_SEARCH_CONTEXT,
 +	PROP_SEARCH_RULE,
 +	PROP_SEARCH_TEXT,
 +	PROP_SEARCH_VISIBLE,
 +	PROP_SCOPE_ACTION,
 +	PROP_SCOPE_VALUE,
 +	PROP_SCOPE_VISIBLE,
 +	PROP_SHELL_VIEW
 +};
 +
 +static gpointer parent_class;
 +
 +static void
 +shell_content_dialog_rule_changed (GtkWidget *dialog,
 +                                   FilterRule *rule)
 +{
 +	gboolean sensitive;
 +
 +	sensitive = (rule != NULL) && (rule->parts != NULL);
 +
 +	gtk_dialog_set_response_sensitive (
 +		GTK_DIALOG (dialog), GTK_RESPONSE_OK, sensitive);
 +	gtk_dialog_set_response_sensitive (
 +		GTK_DIALOG (dialog), GTK_RESPONSE_APPLY, sensitive);
 +}
 +
 +static void
 +action_search_execute_cb (GtkAction *action,
 +                          EShellContent *shell_content)
 +{
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	EIconEntry *icon_entry;
 +	GtkStateType visual_state;
 +	const gchar *search_text;
 +
 +	/* EShellView subclasses are responsible for actually
 +	 * executing the search.  This is all cosmetic stuff. */
 +
 +	shell_view = e_shell_content_get_shell_view (shell_content);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	if (!e_shell_view_is_active (shell_view))
 +		return;
 +
 +	icon_entry = E_ICON_ENTRY (shell_content->priv->search_entry);
 +	search_text = e_shell_content_get_search_text (shell_content);
 +
 +	if (search_text != NULL && *search_text != '\0')
 +		visual_state = GTK_STATE_SELECTED;
 +	else
 +		visual_state = GTK_STATE_NORMAL;
 +
 +	e_icon_entry_set_visual_state (icon_entry, visual_state);
 +
 +	action = E_SHELL_WINDOW_ACTION_SEARCH_CLEAR (shell_window);
 +	gtk_action_set_sensitive (action, TRUE);
 +
 +	action = E_SHELL_WINDOW_ACTION_SEARCH_SAVE (shell_window);
 +	gtk_action_set_sensitive (action, TRUE);
 +
 +	/* Direct the focus away from the search entry, so that a
 +	 * focus-in event is required before the text can be changed.
 +	 * This will reset the entry to the appropriate visual state. */
 +	gtk_widget_grab_focus (gtk_bin_get_child (GTK_BIN (shell_content)));
 +}
 +
 +static void
 +shell_content_entry_activated_cb (EShellContent *shell_content,
 +                                  GtkWidget *entry)
 +{
 +	EShellWindow *shell_window;
 +	EShellView *shell_view;
 +	GtkAction *action;
 +
 +	shell_view = e_shell_content_get_shell_view (shell_content);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	/* Verify the shell view is active before proceeding. */
 +	if (!e_shell_view_is_active (shell_view))
 +		return;
 +
 +	action = E_SHELL_WINDOW_ACTION_SEARCH_EXECUTE (shell_window);
 +	gtk_action_activate (action);
 +}
 +
 +static gboolean
 +shell_content_entry_focus_in_cb (EShellContent *shell_content,
 +                                 GdkEventFocus *focus_event,
 +                                 GtkWidget *entry)
 +{
 +	EIconEntry *icon_entry;
 +	GtkStateType visual_state;
 +
 +	icon_entry = E_ICON_ENTRY (shell_content->priv->search_entry);
 +	visual_state = e_icon_entry_get_visual_state (icon_entry);
 +
 +	if (visual_state == GTK_STATE_INSENSITIVE)
 +		gtk_entry_set_text (GTK_ENTRY (entry), "");
 +
 +	e_icon_entry_set_visual_state (icon_entry, GTK_STATE_NORMAL);
 +
 +	return FALSE;
 +}
 +
 +static gboolean
 +shell_content_entry_focus_out_cb (EShellContent *shell_content,
 +                                  GdkEventFocus *focus_event,
 +                                  GtkWidget *entry)
 +{
 +	/* FIXME */
 +	return FALSE;
 +}
 +
 +static gboolean
 +shell_content_entry_key_press_cb (EShellContent *shell_content,
 +                                  GdkEventKey *key_event,
 +                                  GtkWidget *entry)
 +{
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	GtkAction *action;
 +	guint mask;
 +
 +	mask = gtk_accelerator_get_default_mod_mask ();
 +	if ((key_event->state & mask) != GDK_MOD1_MASK)
 +		return FALSE;
 +
 +	if (key_event->keyval != GDK_Down)
 +		return FALSE;
 +
 +	shell_view = e_shell_content_get_shell_view (shell_content);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +
 +	action = E_SHELL_WINDOW_ACTION_SEARCH_OPTIONS (shell_window);
 +	gtk_action_activate (action);
 +
 +	return TRUE;
 +}
 +
 +static void
 +shell_content_init_search_context (EShellContent *shell_content)
 +{
 +	EShellContentClass *shell_content_class;
 +	EShellView *shell_view;
 +	EShellViewClass *shell_view_class;
 +	EShellBackend *shell_backend;
 +	RuleContext *context;
 +	FilterRule *rule;
 +	FilterPart *part;
 +	gchar *system_filename;
 +	gchar *user_filename;
 +
 +	shell_view = e_shell_content_get_shell_view (shell_content);
 +	shell_backend = e_shell_view_get_shell_backend (shell_view);
 +	shell_view_class = E_SHELL_VIEW_GET_CLASS (shell_view);
 +	g_return_if_fail (shell_view_class->search_rules != NULL);
 +
 +	shell_content_class = E_SHELL_CONTENT_GET_CLASS (shell_content);
 +	g_return_if_fail (shell_content_class->new_search_context != NULL);
 +
 +	/* The basename for built-in searches is specified in the
 +	 * shell view class.  All built-in search rules live in the
 +	 * same directory. */
 +	system_filename = g_build_filename (
 +		EVOLUTION_RULEDIR, shell_view_class->search_rules, NULL);
 +
 +	/* The filename for custom saved searches is always of
 +	 * the form "$(shell_backend_data_dir)/searches.xml". */
 +	user_filename = g_build_filename (
 +		e_shell_backend_get_data_dir (shell_backend),
 +		"searches.xml", NULL);
 +
 +	context = shell_content_class->new_search_context ();
 +	rule_context_add_part_set (
 +		context, "partset", FILTER_TYPE_PART,
 +		rule_context_add_part, rule_context_next_part);
 +	rule_context_add_rule_set (
 +		context, "ruleset", FILTER_TYPE_RULE,
 +		rule_context_add_rule, rule_context_next_rule);
 +	rule_context_load (context, system_filename, user_filename);
 +
 +	/* XXX Not sure why this is necessary. */
 +	g_object_set_data_full (
 +		G_OBJECT (context), "system",
 +		g_strdup (system_filename), g_free);
 +	g_object_set_data_full (
 +		G_OBJECT (context), "user",
 +		g_strdup (user_filename), g_free);
 +
 +	rule = filter_rule_new ();
 +	part = rule_context_next_part (context, NULL);
 +	if (part == NULL)
 +		g_warning (
 +			"Could not load %s search: no parts",
 +			e_shell_view_get_name (shell_view));
 +	else
 +		filter_rule_add_part (rule, filter_part_clone (part));
 +
 +	shell_content->priv->search_context = context;
 +	shell_content->priv->system_filename = system_filename;
 +	shell_content->priv->user_filename = user_filename;
 +}
 +
 +static void
 +shell_content_set_shell_view (EShellContent *shell_content,
 +                              EShellView *shell_view)
 +{
 +	g_return_if_fail (shell_content->priv->shell_view == NULL);
 +
 +	shell_content->priv->shell_view = shell_view;
 +
 +	g_object_add_weak_pointer (
 +		G_OBJECT (shell_view),
 +		&shell_content->priv->shell_view);
 +}
 +
 +static void
 +shell_content_set_property (GObject *object,
 +                            guint property_id,
 +                            const GValue *value,
 +                            GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_FILTER_ACTION:
 +			e_shell_content_set_filter_action (
 +				E_SHELL_CONTENT (object),
 +				g_value_get_object (value));
 +			return;
 +
 +		case PROP_FILTER_VALUE:
 +			e_shell_content_set_filter_value (
 +				E_SHELL_CONTENT (object),
 +				g_value_get_int (value));
 +			return;
 +
 +		case PROP_FILTER_VISIBLE:
 +			e_shell_content_set_filter_visible (
 +				E_SHELL_CONTENT (object),
 +				g_value_get_boolean (value));
 +			return;
 +
 +		case PROP_SEARCH_RULE:
 +			e_shell_content_set_search_rule (
 +				E_SHELL_CONTENT (object),
 +				g_value_get_object (value));
 +			return;
 +
 +		case PROP_SEARCH_TEXT:
 +			e_shell_content_set_search_text (
 +				E_SHELL_CONTENT (object),
 +				g_value_get_string (value));
 +			return;
 +
 +		case PROP_SEARCH_VISIBLE:
 +			e_shell_content_set_search_visible (
 +				E_SHELL_CONTENT (object),
 +				g_value_get_boolean (value));
 +			return;
 +
 +		case PROP_SCOPE_ACTION:
 +			e_shell_content_set_scope_action (
 +				E_SHELL_CONTENT (object),
 +				g_value_get_object (value));
 +			return;
 +
 +		case PROP_SCOPE_VALUE:
 +			e_shell_content_set_scope_value (
 +				E_SHELL_CONTENT (object),
 +				g_value_get_int (value));
 +			return;
 +
 +		case PROP_SCOPE_VISIBLE:
 +			e_shell_content_set_scope_visible (
 +				E_SHELL_CONTENT (object),
 +				g_value_get_boolean (value));
 +			return;
 +
 +		case PROP_SHELL_VIEW:
 +			shell_content_set_shell_view (
 +				E_SHELL_CONTENT (object),
 +				g_value_get_object (value));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +shell_content_get_property (GObject *object,
 +                            guint property_id,
 +                            GValue *value,
 +                            GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_FILTER_ACTION:
 +			g_value_set_object (
 +				value, e_shell_content_get_filter_action (
 +				E_SHELL_CONTENT (object)));
 +			return;
 +
 +		case PROP_FILTER_VALUE:
 +			g_value_set_int (
 +				value, e_shell_content_get_filter_value (
 +				E_SHELL_CONTENT (object)));
 +			return;
 +
 +		case PROP_FILTER_VISIBLE:
 +			g_value_set_boolean (
 +				value, e_shell_content_get_filter_visible (
 +				E_SHELL_CONTENT (object)));
 +			return;
 +
 +		case PROP_SEARCH_CONTEXT:
 +			g_value_set_object (
 +				value, e_shell_content_get_search_context (
 +				E_SHELL_CONTENT (object)));
 +			return;
 +
 +		case PROP_SEARCH_RULE:
 +			g_value_set_object (
 +				value, e_shell_content_get_search_rule (
 +				E_SHELL_CONTENT (object)));
 +			return;
 +
 +		case PROP_SEARCH_TEXT:
 +			g_value_set_string (
 +				value, e_shell_content_get_search_text (
 +				E_SHELL_CONTENT (object)));
 +			return;
 +
 +		case PROP_SEARCH_VISIBLE:
 +			g_value_set_boolean (
 +				value, e_shell_content_get_search_visible (
 +				E_SHELL_CONTENT (object)));
 +			return;
 +
 +		case PROP_SCOPE_ACTION:
 +			g_value_set_object (
 +				value, e_shell_content_get_scope_action (
 +				E_SHELL_CONTENT (object)));
 +			return;
 +
 +		case PROP_SCOPE_VALUE:
 +			g_value_set_int (
 +				value, e_shell_content_get_scope_value (
 +				E_SHELL_CONTENT (object)));
 +			return;
 +
 +		case PROP_SCOPE_VISIBLE:
 +			g_value_set_boolean (
 +				value, e_shell_content_get_scope_visible (
 +				E_SHELL_CONTENT (object)));
 +			return;
 +
 +		case PROP_SHELL_VIEW:
 +			g_value_set_object (
 +				value, e_shell_content_get_shell_view (
 +				E_SHELL_CONTENT (object)));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +shell_content_dispose (GObject *object)
 +{
 +	EShellContentPrivate *priv;
 +
 +	priv = E_SHELL_CONTENT_GET_PRIVATE (object);
 +
 +	if (priv->shell_view != NULL) {
 +		g_object_remove_weak_pointer (
 +			G_OBJECT (priv->shell_view), &priv->shell_view);
 +		priv->shell_view = NULL;
 +	}
 +
 +	if (priv->filter_label != NULL) {
 +		g_object_unref (priv->filter_label);
 +		priv->filter_label = NULL;
 +	}
 +
 +	if (priv->filter_combo_box != NULL) {
 +		g_object_unref (priv->filter_combo_box);
 +		priv->filter_combo_box = NULL;
 +	}
 +
 +	if (priv->search_context != NULL) {
 +		g_object_unref (priv->search_context);
 +		priv->search_context = NULL;
 +	}
 +
 +	if (priv->search_label != NULL) {
 +		g_object_unref (priv->search_label);
 +		priv->search_label = NULL;
 +	}
 +
 +	if (priv->search_entry != NULL) {
 +		g_object_unref (priv->search_entry);
 +		priv->search_entry = NULL;
 +	}
 +
 +	if (priv->scope_label != NULL) {
 +		g_object_unref (priv->scope_label);
 +		priv->scope_label = NULL;
 +	}
 +
 +	if (priv->scope_combo_box != NULL) {
 +		g_object_unref (priv->scope_combo_box);
 +		priv->scope_combo_box = NULL;
 +	}
 +
 +	/* Chain up to parent's dispose() method. */
 +	G_OBJECT_CLASS (parent_class)->dispose (object);
 +}
 +
 +static void
 +shell_content_finalize (GObject *object)
 +{
 +	EShellContentPrivate *priv;
 +
 +	priv = E_SHELL_CONTENT_GET_PRIVATE (object);
 +
 +	g_free (priv->system_filename);
 +	g_free (priv->user_filename);
 +
 +	/* Chain up to parent's finalize() method. */
 +	G_OBJECT_CLASS (parent_class)->finalize (object);
 +}
 +
 +static void
 +shell_content_constructed (GObject *object)
 +{
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	EShellContent *shell_content;
 +	EIconEntry *icon_entry;
 +	GtkSizeGroup *size_group;
 +	GtkAction *action;
 +	GtkWidget *widget;
 +
 +	shell_content = E_SHELL_CONTENT (object);
 +	shell_view = e_shell_content_get_shell_view (shell_content);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +	icon_entry = E_ICON_ENTRY (shell_content->priv->search_entry);
 +	size_group = e_shell_view_get_size_group (shell_view);
 +
 +	action = E_SHELL_WINDOW_ACTION_SEARCH_CLEAR (shell_window);
 +	e_icon_entry_add_action_end (icon_entry, action);
 +
 +	action = E_SHELL_WINDOW_ACTION_SEARCH_EXECUTE (shell_window);
 +	g_signal_connect (
 +		action, "activate",
 +		G_CALLBACK (action_search_execute_cb), shell_content);
 +
 +	action = E_SHELL_WINDOW_ACTION_SEARCH_OPTIONS (shell_window);
 +	e_icon_entry_add_action_start (icon_entry, action);
 +
 +	widget = shell_content->priv->search_bar;
 +	gtk_size_group_add_widget (size_group, widget);
 +
 +	shell_content_init_search_context (shell_content);
 +}
 +
 +static void
 +shell_content_size_request (GtkWidget *widget,
 +                            GtkRequisition *requisition)
 +{
 +	EShellContentPrivate *priv;
 +	GtkRequisition child_requisition;
 +	GtkWidget *child;
 +
 +	priv = E_SHELL_CONTENT_GET_PRIVATE (widget);
 +
 +	requisition->width = 0;
 +	requisition->height = 0;
 +
 +	child = gtk_bin_get_child (GTK_BIN (widget));
 +	gtk_widget_size_request (child, requisition);
 +
 +	child = priv->search_bar;
 +	gtk_widget_size_request (child, &child_requisition);
 +	requisition->width = MAX (requisition->width, child_requisition.width);
 +	requisition->height += child_requisition.height;
 +}
 +
 +static void
 +shell_content_size_allocate (GtkWidget *widget,
 +                             GtkAllocation *allocation)
 +{
 +	EShellContentPrivate *priv;
 +	GtkAllocation child_allocation;
 +	GtkRequisition child_requisition;
 +	GtkWidget *child;
 +
 +	priv = E_SHELL_CONTENT_GET_PRIVATE (widget);
 +
 +	widget->allocation = *allocation;
 +
 +	child = priv->search_bar;
 +	gtk_widget_size_request (child, &child_requisition);
 +
 +	child_allocation.x = allocation->x;
 +	child_allocation.y = allocation->y;
 +	child_allocation.width = allocation->width;
 +	child_allocation.height = child_requisition.height;
 +
 +	gtk_widget_size_allocate (child, &child_allocation);
 +
 +	child_allocation.y += child_requisition.height;
 +	child_allocation.height =
 +		allocation->height - child_requisition.height;
 +
 +	child = gtk_bin_get_child (GTK_BIN (widget));
 +	if (child != NULL)
 +		gtk_widget_size_allocate (child, &child_allocation);
 +}
 +
 +static void
 +shell_content_remove (GtkContainer *container,
 +                      GtkWidget *widget)
 +{
 +	EShellContentPrivate *priv;
 +
 +	priv = E_SHELL_CONTENT_GET_PRIVATE (container);
 +
 +	/* Look in the internal widgets first. */
 +
 +	if (widget == priv->search_bar) {
 +		gtk_widget_unparent (priv->search_bar);
 +		gtk_widget_queue_resize (GTK_WIDGET (container));
 +		return;
 +	}
 +
 +	/* Chain up to parent's remove() method. */
 +	GTK_CONTAINER_CLASS (parent_class)->remove (container, widget);
 +}
 +
 +static void
 +shell_content_forall (GtkContainer *container,
 +                      gboolean include_internals,
 +                      GtkCallback callback,
 +                      gpointer callback_data)
 +{
 +	EShellContentPrivate *priv;
 +
 +	priv = E_SHELL_CONTENT_GET_PRIVATE (container);
 +
 +	if (include_internals)
 +		callback (priv->search_bar, callback_data);
 +
 +	/* Chain up to parent's forall() method. */
 +	GTK_CONTAINER_CLASS (parent_class)->forall (
 +		container, include_internals, callback, callback_data);
 +}
 +
 +static void
 +shell_content_class_init (EShellContentClass *class)
 +{
 +	GObjectClass *object_class;
 +	GtkWidgetClass *widget_class;
 +	GtkContainerClass *container_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (EShellContentPrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->set_property = shell_content_set_property;
 +	object_class->get_property = shell_content_get_property;
 +	object_class->dispose = shell_content_dispose;
 +	object_class->finalize = shell_content_finalize;
 +	object_class->constructed = shell_content_constructed;
 +
 +	widget_class = GTK_WIDGET_CLASS (class);
 +	widget_class->size_request = shell_content_size_request;
 +	widget_class->size_allocate = shell_content_size_allocate;
 +
 +	container_class = GTK_CONTAINER_CLASS (class);
 +	container_class->remove = shell_content_remove;
 +	container_class->forall = shell_content_forall;
 +
 +	class->new_search_context = rule_context_new;
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_FILTER_ACTION,
 +		g_param_spec_object (
 +			"filter-action",
 +			NULL,
 +			NULL,
 +			GTK_TYPE_RADIO_ACTION,
 +			G_PARAM_READWRITE));
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_FILTER_VALUE,
 +		g_param_spec_int (
 +			"filter-value",
 +			NULL,
 +			NULL,
 +			G_MININT,
 +			G_MAXINT,
 +			0,
 +			G_PARAM_READWRITE));
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_FILTER_VISIBLE,
 +		g_param_spec_boolean (
 +			"filter-visible",
 +			NULL,
 +			NULL,
 +			TRUE,
 +			G_PARAM_READWRITE |
 +			G_PARAM_CONSTRUCT));
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_SEARCH_CONTEXT,
 +		g_param_spec_object (
 +			"search-context",
 +			NULL,
 +			NULL,
 +			RULE_TYPE_CONTEXT,
 +			G_PARAM_READABLE));
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_SEARCH_RULE,
 +		g_param_spec_object (
 +			"search-rule",
 +			NULL,
 +			NULL,
 +			FILTER_TYPE_RULE,
 +			G_PARAM_READWRITE));
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_SEARCH_TEXT,
 +		g_param_spec_string (
 +			"search-text",
 +			NULL,
 +			NULL,
 +			NULL,
 +			G_PARAM_READWRITE));
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_SEARCH_VISIBLE,
 +		g_param_spec_boolean (
 +			"search-visible",
 +			NULL,
 +			NULL,
 +			TRUE,
 +			G_PARAM_READWRITE |
 +			G_PARAM_CONSTRUCT));
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_SCOPE_ACTION,
 +		g_param_spec_object (
 +			"scope-action",
 +			NULL,
 +			NULL,
 +			GTK_TYPE_RADIO_ACTION,
 +			G_PARAM_READWRITE));
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_SCOPE_VALUE,
 +		g_param_spec_int (
 +			"scope-value",
 +			NULL,
 +			NULL,
 +			G_MININT,
 +			G_MAXINT,
 +			0,
 +			G_PARAM_READWRITE));
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_SCOPE_VISIBLE,
 +		g_param_spec_boolean (
 +			"scope-visible",
 +			NULL,
 +			NULL,
 +			FALSE,
 +			G_PARAM_READWRITE |
 +			G_PARAM_CONSTRUCT));
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_SHELL_VIEW,
 +		g_param_spec_object (
 +			"shell-view",
 +			NULL,
 +			NULL,
 +			E_TYPE_SHELL_VIEW,
 +			G_PARAM_READWRITE |
 +			G_PARAM_CONSTRUCT_ONLY));
 +}
 +
 +static void
 +shell_content_init (EShellContent *shell_content)
 +{
 +	GtkBox *box;
 +	GtkLabel *label;
 +	GtkWidget *mnemonic;
 +	GtkWidget *widget;
 +	EIconEntry *icon_entry;
 +
 +	shell_content->priv = E_SHELL_CONTENT_GET_PRIVATE (shell_content);
 +
 +	GTK_WIDGET_SET_FLAGS (shell_content, GTK_NO_WINDOW);
 +
 +	/*** Build the Search Bar ***/
 +
 +	widget = gtk_hbox_new (FALSE, 3);
 +	gtk_widget_set_parent (widget, GTK_WIDGET (shell_content));
 +	shell_content->priv->search_bar = g_object_ref_sink (widget);
 +	gtk_widget_show (widget);
 +
 +	box = GTK_BOX (widget);
 +
 +	/* Filter Combo Widgets */
 +
 +	/* Translators: The "Show:" label precedes a combo box that
 +	 * allows the user to filter the current view.  Examples of
 +	 * items that appear in the combo box are "Unread Messages",
 +	 * "Important Messages", or "Active Appointments". */
 +	widget = gtk_label_new_with_mnemonic (_("Sho_w:"));
 +	gtk_box_pack_start (box, widget, FALSE, FALSE, 0);
 +	shell_content->priv->filter_label = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	label = GTK_LABEL (widget);
 +
 +	widget = e_action_combo_box_new ();
 +	gtk_label_set_mnemonic_widget (label, widget);
 +	gtk_box_pack_start (box, widget, FALSE, FALSE, 0);
 +	shell_content->priv->filter_combo_box = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	/* Scope Combo Widgets */
 +
 +	widget = e_action_combo_box_new ();
 +	gtk_box_pack_end (box, widget, FALSE, FALSE, 0);
 +	shell_content->priv->scope_combo_box = g_object_ref (widget);
- 	gtk_widget_show (widget); 
++	gtk_widget_show (widget);
 +
 +	mnemonic = widget;
 +
 +	/* Translators: This is part of the quick search interface.
 +	 * example: Search: [_______________] in [ Current Folder ] */
 +	widget = gtk_label_new_with_mnemonic (_("i_n"));
 +	gtk_label_set_mnemonic_widget (GTK_LABEL (widget), mnemonic);
 +	gtk_box_pack_end (box, widget, FALSE, FALSE, 0);
 +	shell_content->priv->scope_label = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	/* Search Entry Widgets */
 +
 +	widget = e_icon_entry_new ();
 +	gtk_box_pack_end (box, widget, FALSE, FALSE, 0);
 +	shell_content->priv->search_entry = g_object_ref (widget);
 +	shell_content->priv->search_state = GTK_STATE_NORMAL;
 +	gtk_widget_show (widget);
 +
 +	icon_entry = E_ICON_ENTRY (widget);
 +
 +	/* Translators: This is part of the quick search interface.
 +	 * example: Search: [_______________] in [ Current Folder ] */
 +	widget = gtk_label_new_with_mnemonic (_("Sear_ch:"));
 +	gtk_box_pack_end (box, widget, FALSE, FALSE, 0);
 +	shell_content->priv->search_label = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	label = GTK_LABEL (widget);
 +
 +	widget = e_icon_entry_get_entry (icon_entry);
 +	gtk_label_set_mnemonic_widget (label, widget);
 +	g_signal_connect_swapped (
 +		widget, "activate",
 +		G_CALLBACK (shell_content_entry_activated_cb), shell_content);
 +	g_signal_connect_swapped (
 +		widget, "focus-in-event",
 +		G_CALLBACK (shell_content_entry_focus_in_cb), shell_content);
 +	g_signal_connect_swapped (
 +		widget, "focus-out-event",
 +		G_CALLBACK (shell_content_entry_focus_out_cb), shell_content);
 +	g_signal_connect_swapped (
 +		widget, "key-press-event",
 +		G_CALLBACK (shell_content_entry_key_press_cb), shell_content);
 +}
 +
 +GType
 +e_shell_content_get_type (void)
 +{
 +	static GType type = 0;
 +
 +	if (G_UNLIKELY (type == 0)) {
 +		static const GTypeInfo type_info = {
 +			sizeof (EShellContentClass),
 +			(GBaseInitFunc) NULL,
 +			(GBaseFinalizeFunc) NULL,
 +			(GClassInitFunc) shell_content_class_init,
 +			(GClassFinalizeFunc) NULL,
 +			NULL,  /* class_data */
 +			sizeof (EShellContent),
 +			0,     /* n_preallocs */
 +			(GInstanceInitFunc) shell_content_init,
 +			NULL   /* value_table */
 +		};
 +
 +		type = g_type_register_static (
 +			GTK_TYPE_BIN, "EShellContent", &type_info, 0);
 +	}
 +
 +	return type;
 +}
 +
 +/**
 + * e_shell_content_new:
 + * @shell_view: an #EShellView
 + *
 + * Creates a new #EShellContent instance belonging to @shell_view.
 + *
 + * Returns: a new #EShellContent instance
 + **/
 +GtkWidget *
 +e_shell_content_new (EShellView *shell_view)
 +{
 +	g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
 +
 +	return g_object_new (
 +		E_TYPE_SHELL_CONTENT, "shell-view", shell_view, NULL);
 +}
 +
 +/**
 + * e_shell_content_check_state:
 + * @shell_content: an #EShellContent
 + *
 + * #EShellContent subclasses should implement the
 + * <structfield>check_state</structfield> method in #EShellContentClass
 + * to return a set of flags describing the current content selection.
 + * Subclasses are responsible for defining their own flags.  This is
 + * primarily used to assist shell views with updating actions (see
 + * e_shell_view_update_actions()).
 + *
 + * Returns: a set of flags describing the current @shell_content selection
 + **/
 +guint32
 +e_shell_content_check_state (EShellContent *shell_content)
 +{
 +	EShellContentClass *shell_content_class;
 +
 +	g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), 0);
 +
 +	shell_content_class = E_SHELL_CONTENT_GET_CLASS (shell_content);
 +	g_return_val_if_fail (shell_content_class->check_state != NULL, 0);
 +
 +	return shell_content_class->check_state (shell_content);
 +}
 +
 +/**
 + * e_shell_content_get_shell_view:
 + * @shell_content: an #EShellContent
 + *
 + * Returns the #EShellView that was passed to e_shell_content_new().
 + *
 + * Returns: the #EShellView to which @shell_content belongs
 + **/
 +EShellView *
 +e_shell_content_get_shell_view (EShellContent *shell_content)
 +{
 +	g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), NULL);
 +
 +	return E_SHELL_VIEW (shell_content->priv->shell_view);
 +}
 +
 +GtkRadioAction *
 +e_shell_content_get_filter_action (EShellContent *shell_content)
 +{
 +	EActionComboBox *combo_box;
 +
 +	g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), NULL);
 +
 +	combo_box = E_ACTION_COMBO_BOX (shell_content->priv->filter_combo_box);
 +
 +	return e_action_combo_box_get_action (combo_box);
 +}
 +
 +void
 +e_shell_content_set_filter_action (EShellContent *shell_content,
 +                                   GtkRadioAction *filter_action)
 +{
 +	EActionComboBox *combo_box;
 +
 +	g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
 +
 +	combo_box = E_ACTION_COMBO_BOX (shell_content->priv->filter_combo_box);
 +
 +	e_action_combo_box_set_action (combo_box, filter_action);
 +	g_object_notify (G_OBJECT (shell_content), "filter-action");
 +}
 +
 +gint
 +e_shell_content_get_filter_value (EShellContent *shell_content)
 +{
 +	EActionComboBox *combo_box;
 +
 +	g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), 0);
 +
 +	combo_box = E_ACTION_COMBO_BOX (shell_content->priv->filter_combo_box);
 +
 +	return e_action_combo_box_get_current_value (combo_box);
 +}
 +
 +void
 +e_shell_content_set_filter_value (EShellContent *shell_content,
 +                                  gint filter_value)
 +{
 +	EActionComboBox *combo_box;
 +
 +	g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
 +
 +	combo_box = E_ACTION_COMBO_BOX (shell_content->priv->filter_combo_box);
 +
 +	e_action_combo_box_set_current_value (combo_box, filter_value);
 +	g_object_notify (G_OBJECT (shell_content), "filter-value");
 +}
 +
 +gboolean
 +e_shell_content_get_filter_visible (EShellContent *shell_content)
 +{
 +	g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), FALSE);
 +
 +	return GTK_WIDGET_VISIBLE (shell_content->priv->filter_combo_box);
 +}
 +
 +void
 +e_shell_content_set_filter_visible (EShellContent *shell_content,
 +                                    gboolean filter_visible)
 +{
 +	g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
 +
 +	if (filter_visible) {
 +		gtk_widget_show (shell_content->priv->filter_label);
 +		gtk_widget_show (shell_content->priv->filter_combo_box);
 +	} else {
 +		gtk_widget_hide (shell_content->priv->filter_label);
 +		gtk_widget_hide (shell_content->priv->filter_combo_box);
 +	}
 +}
 +
 +void
 +e_shell_content_add_filter_separator_before (EShellContent *shell_content,
 +                                             gint action_value)
 +{
 +	EActionComboBox *combo_box;
 +
 +	g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
 +
 +	combo_box = E_ACTION_COMBO_BOX (shell_content->priv->filter_combo_box);
 +
 +	e_action_combo_box_add_separator_before (combo_box, action_value);
 +}
 +
 +void
 +e_shell_content_add_filter_separator_after (EShellContent *shell_content,
 +                                            gint action_value)
 +{
 +	EActionComboBox *combo_box;
 +
 +	g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
 +
 +	combo_box = E_ACTION_COMBO_BOX (shell_content->priv->filter_combo_box);
 +
 +	e_action_combo_box_add_separator_after (combo_box, action_value);
 +}
 +
 +RuleContext *
 +e_shell_content_get_search_context (EShellContent *shell_content)
 +{
 +	g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), NULL);
 +
 +	return shell_content->priv->search_context;
 +}
 +
 +FilterRule *
 +e_shell_content_get_search_rule (EShellContent *shell_content)
 +{
 +	g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), NULL);
 +
 +	return shell_content->priv->search_rule;
 +}
 +
 +void
 +e_shell_content_set_search_rule (EShellContent *shell_content,
 +                                 FilterRule *search_rule)
 +{
 +	g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
 +
 +	if (search_rule != NULL) {
 +		g_return_if_fail (IS_FILTER_RULE (search_rule));
 +		g_object_ref (search_rule);
 +	}
 +
 +	if (shell_content->priv->search_rule != NULL)
 +		g_object_unref (shell_content->priv->search_rule);
 +
 +	shell_content->priv->search_rule = search_rule;
 +	g_object_notify (G_OBJECT (shell_content), "search-rule");
 +}
 +
 +const gchar *
 +e_shell_content_get_search_text (EShellContent *shell_content)
 +{
 +	EIconEntry *icon_entry;
 +	GtkWidget *text_entry;
 +
 +	g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), NULL);
 +
 +	if (shell_content->priv->search_state == GTK_STATE_INSENSITIVE)
 +		return "";
 +
 +	icon_entry = E_ICON_ENTRY (shell_content->priv->search_entry);
 +	text_entry = e_icon_entry_get_entry (icon_entry);
 +
 +	return gtk_entry_get_text (GTK_ENTRY (text_entry));
 +}
 +
 +void
 +e_shell_content_set_search_text (EShellContent *shell_content,
 +                                 const gchar *search_text)
 +{
 +	EIconEntry *icon_entry;
 +	GtkWidget *text_entry;
 +
 +	g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
 +
 +	icon_entry = E_ICON_ENTRY (shell_content->priv->search_entry);
 +	text_entry = e_icon_entry_get_entry (icon_entry);
 +
 +	search_text = (search_text != NULL) ? search_text : "";
 +	gtk_entry_set_text (GTK_ENTRY (text_entry), search_text);
 +	g_object_notify (G_OBJECT (shell_content), "search-text");
 +}
 +
 +gboolean
 +e_shell_content_get_search_visible (EShellContent *shell_content)
 +{
 +	g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), FALSE);
 +
 +	return GTK_WIDGET_VISIBLE (shell_content->priv->search_entry);
 +}
 +
 +void
 +e_shell_content_set_search_visible (EShellContent *shell_content,
 +                                    gboolean search_visible)
 +{
 +	g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
 +
 +	if (search_visible) {
 +		gtk_widget_show (shell_content->priv->search_label);
 +		gtk_widget_show (shell_content->priv->search_entry);
 +	} else {
 +		gtk_widget_hide (shell_content->priv->search_label);
 +		gtk_widget_hide (shell_content->priv->search_entry);
 +	}
 +}
 +
 +GtkRadioAction *
 +e_shell_content_get_scope_action (EShellContent *shell_content)
 +{
 +	EActionComboBox *combo_box;
 +
 +	g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), NULL);
 +
 +	combo_box = E_ACTION_COMBO_BOX (shell_content->priv->scope_combo_box);
 +
 +	return e_action_combo_box_get_action (combo_box);
 +}
 +
 +void
 +e_shell_content_set_scope_action (EShellContent *shell_content,
 +                                  GtkRadioAction *scope_action)
 +{
 +	EActionComboBox *combo_box;
 +
 +	g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
 +
 +	combo_box = E_ACTION_COMBO_BOX (shell_content->priv->scope_combo_box);
 +
 +	e_action_combo_box_set_action (combo_box, scope_action);
 +	g_object_notify (G_OBJECT (shell_content), "scope-action");
 +}
 +
 +gint
 +e_shell_content_get_scope_value (EShellContent *shell_content)
 +{
 +	EActionComboBox *combo_box;
 +
 +	g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), 0);
 +
 +	combo_box = E_ACTION_COMBO_BOX (shell_content->priv->scope_combo_box);
 +
 +	return e_action_combo_box_get_current_value (combo_box);
 +}
 +
 +void
 +e_shell_content_set_scope_value (EShellContent *shell_content,
 +                                 gint scope_value)
 +{
 +	EActionComboBox *combo_box;
 +
 +	g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
 +
 +	combo_box = E_ACTION_COMBO_BOX (shell_content->priv->scope_combo_box);
 +
 +	e_action_combo_box_set_current_value (combo_box, scope_value);
 +	g_object_notify (G_OBJECT (shell_content), "scope-value");
 +}
 +
 +gboolean
 +e_shell_content_get_scope_visible (EShellContent *shell_content)
 +{
 +	g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), FALSE);
 +
 +	return GTK_WIDGET_VISIBLE (shell_content->priv->scope_combo_box);
 +}
 +
 +void
 +e_shell_content_set_scope_visible (EShellContent *shell_content,
 +                                   gboolean scope_visible)
 +{
 +	g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
 +
 +	if (scope_visible) {
 +		gtk_widget_show (shell_content->priv->scope_label);
 +		gtk_widget_show (shell_content->priv->scope_combo_box);
 +	} else {
 +		gtk_widget_hide (shell_content->priv->scope_label);
 +		gtk_widget_hide (shell_content->priv->scope_combo_box);
 +	}
 +
 +	g_object_notify (G_OBJECT (shell_content), "scope-visible");
 +}
 +
 +void
 +e_shell_content_run_advanced_search_dialog (EShellContent *shell_content)
 +{
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	GtkAction *action;
 +	GtkWidget *dialog;
 +	GtkWidget *widget;
 +	FilterRule *rule;
 +	RuleContext *context;
 +	const gchar *user_filename;
 +	gint response;
 +
 +	g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
 +
 +	shell_view = e_shell_content_get_shell_view (shell_content);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +	user_filename = shell_content->priv->user_filename;
 +
 +	rule = e_shell_content_get_search_rule (shell_content);
 +
 +	if (rule == NULL)
 +		rule = filter_rule_new ();
 +	else
 +		rule = filter_rule_clone (rule);
 +
 +	context = e_shell_content_get_search_context (shell_content);
 +	widget = filter_rule_get_widget (rule, context);
 +	filter_rule_set_source (rule, FILTER_SOURCE_INCOMING);
 +
 +	dialog = gtk_dialog_new_with_buttons (
 +		_("Advanced Search"), GTK_WINDOW (shell_window),
 +		GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
 +		GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
 +		GTK_STOCK_SAVE, GTK_RESPONSE_APPLY,
 +		GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
 +
 +	gtk_container_set_border_width (GTK_CONTAINER (dialog), 7);
 +	gtk_container_set_border_width (GTK_CONTAINER (widget), 3);
 +	gtk_window_set_default_size (GTK_WINDOW (dialog), 600, 300);
 +
 +	gtk_box_pack_start (
 +		GTK_BOX (GTK_DIALOG (dialog)->vbox), widget, TRUE, TRUE, 0);
 +
 +	g_signal_connect_swapped (
 +		rule, "changed", G_CALLBACK (
 +		shell_content_dialog_rule_changed), dialog);
 +
 +	shell_content_dialog_rule_changed (dialog, rule);
 +
 +run:
 +	response = gtk_dialog_run (GTK_DIALOG (dialog));
 +
 +	if (response != GTK_RESPONSE_OK && response != GTK_RESPONSE_APPLY)
 +		goto exit;
 +
 +	if (!filter_rule_validate (rule))
 +		goto run;
 +
 +	e_shell_content_set_search_rule (shell_content, rule);
 +
 +	action = E_SHELL_WINDOW_ACTION_SEARCH_EXECUTE (shell_window);
 +	gtk_action_activate (action);
 +
 +	if (response == GTK_RESPONSE_APPLY) {
 +		if (!rule_context_find_rule (context, rule->name, rule->source))
 +			rule_context_add_rule (context, rule);
 +		rule_context_save (context, user_filename);
 +		goto run;
 +	}
 +
 +exit:
 +	g_object_unref (rule);
 +	gtk_widget_destroy (dialog);
 +}
 +
 +void
 +e_shell_content_run_edit_searches_dialog (EShellContent *shell_content)
 +{
 +	RuleContext *context;
 +	RuleEditor *editor;
 +	const gchar *user_filename;
 +
 +	g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
 +
 +	context = e_shell_content_get_search_context (shell_content);
 +	user_filename = shell_content->priv->user_filename;
 +
 +	editor = rule_editor_new (
 +		context, FILTER_SOURCE_INCOMING, _("Searches"));
 +	gtk_window_set_title (GTK_WINDOW (editor), _("Searches"));
 +
 +	if (gtk_dialog_run (GTK_DIALOG (editor)) == GTK_RESPONSE_OK)
 +		rule_context_save (context, user_filename);
 +
 +	gtk_widget_destroy (GTK_WIDGET (editor));
 +}
 +
 +void
 +e_shell_content_run_save_search_dialog (EShellContent *shell_content)
 +{
 +	EShellView *shell_view;
 +	EShellWindow *shell_window;
 +	GtkWidget *dialog;
 +	GtkWidget *widget;
 +	FilterRule *rule;
 +	RuleContext *context;
 +	const gchar *search_text;
 +	const gchar *user_filename;
 +	gchar *search_name;
 +	gint response;
 +
 +	g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
 +
 +	shell_view = e_shell_content_get_shell_view (shell_content);
 +	shell_window = e_shell_view_get_shell_window (shell_view);
 +	user_filename = shell_content->priv->user_filename;
 +
 +	rule = e_shell_content_get_search_rule (shell_content);
 +	g_return_if_fail (IS_FILTER_RULE (rule));
 +	rule = filter_rule_clone (rule);
 +
 +	search_text = e_shell_content_get_search_text (shell_content);
 +	if (search_text == NULL || *search_text == '\0')
 +		search_text = "''";
 +
 +	search_name = g_strdup_printf ("%s %s", rule->name, search_text);
 +	filter_rule_set_name (rule, search_name);
 +	g_free (search_name);
 +
 +	context = e_shell_content_get_search_context (shell_content);
 +	widget = filter_rule_get_widget (rule, context);
 +	filter_rule_set_source (rule, FILTER_SOURCE_INCOMING);
 +
 +	dialog = gtk_dialog_new_with_buttons (
 +		_("Save Search"), GTK_WINDOW (shell_window),
 +		GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
 +		GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
 +		GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
 +
 +	gtk_container_set_border_width (GTK_CONTAINER (dialog), 7);
 +	gtk_container_set_border_width (GTK_CONTAINER (widget), 3);
 +	gtk_window_set_default_size (GTK_WINDOW (dialog), 500, 300);
 +
 +	gtk_box_pack_start (
 +		GTK_BOX (GTK_DIALOG (dialog)->vbox), widget, TRUE, TRUE, 0);
 +
 +	g_signal_connect_swapped (
 +		rule, "changed", G_CALLBACK (
 +		shell_content_dialog_rule_changed), dialog);
 +
 +	shell_content_dialog_rule_changed (dialog, rule);
 +
 +run:
 +	response = gtk_dialog_run (GTK_DIALOG (dialog));
 +
 +	if (response != GTK_RESPONSE_OK)
 +		goto exit;
 +
 +	if (!filter_rule_validate (rule))
 +		goto run;
 +
 +	rule_context_add_rule (context, rule);
 +	rule_context_save (context, user_filename);
 +
 +exit:
 +	g_object_unref (rule);
 +	gtk_widget_destroy (dialog);
 +}
diff --cc shell/e-shell-content.h
index 0463977,0000000..2259dbd
mode 100644,000000..100644
--- a/shell/e-shell-content.h
+++ b/shell/e-shell-content.h
@@@ -1,143 -1,0 +1,143 @@@
 +/*
 + * e-shell-content.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +/**
 + * SECTION: e-shell-content
 + * @short_description: the right side of the main window
 + * @include: shell/e-shell-content.h
 + **/
 +
 +#ifndef E_SHELL_CONTENT_H
 +#define E_SHELL_CONTENT_H
 +
 +#include <shell/e-shell-common.h>
 +#include <filter/filter-rule.h>
 +#include <filter/rule-context.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_SHELL_CONTENT \
 +	(e_shell_content_get_type ())
 +#define E_SHELL_CONTENT(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_SHELL_CONTENT, EShellContent))
 +#define E_SHELL_CONTENT_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_SHELL_CONTENT, EShellContentClass))
 +#define E_IS_SHELL_CONTENT(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_SHELL_CONTENT))
 +#define E_IS_SHELL_CONTENT_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((obj), E_TYPE_SHELL_CONTENT))
 +#define E_SHELL_CONTENT_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_SHELL_CONTENT, EShellContentClass))
 +
 +G_BEGIN_DECLS
 +
 +/* Avoid including <e-shell-view.h>, because it includes us! */
 +struct _EShellView;
 +
 +typedef struct _EShellContent EShellContent;
 +typedef struct _EShellContentClass EShellContentClass;
 +typedef struct _EShellContentPrivate EShellContentPrivate;
 +
 +/**
 + * EShellContent:
 + *
 + * Contains only private data that should be read and manipulated using the
 + * functions below.
 + **/
 +struct _EShellContent {
 +	GtkBin parent;
 +	EShellContentPrivate *priv;
 +};
 +
 +struct _EShellContentClass {
 +	GtkBinClass parent_class;
 +
 +	/* Factory Methods */
 +	RuleContext *	(*new_search_context)	(void);
 +
 +	guint32		(*check_state)		(EShellContent *shell_content);
 +};
 +
 +GType		e_shell_content_get_type	(void);
 +GtkWidget *	e_shell_content_new		(struct _EShellView *shell_view);
 +guint32		e_shell_content_check_state	(EShellContent *shell_content);
 +struct _EShellView *
 +		e_shell_content_get_shell_view	(EShellContent *shell_content);
 +GtkRadioAction *e_shell_content_get_filter_action
 +						(EShellContent *shell_content);
 +void		e_shell_content_set_filter_action
 +						(EShellContent *shell_content,
 +						 GtkRadioAction *filter_action);
 +gint		e_shell_content_get_filter_value(EShellContent *shell_content);
 +void		e_shell_content_set_filter_value(EShellContent *shell_content,
 +						 gint filter_value);
 +gboolean	e_shell_content_get_filter_visible
 +						(EShellContent *shell_content);
 +void		e_shell_content_set_filter_visible
 +						(EShellContent *shell_content,
 +						 gboolean filter_visible);
 +void		e_shell_content_add_filter_separator_before
 +						(EShellContent *shell_content,
 +						 gint action_value);
 +void		e_shell_content_add_filter_separator_after
 +						(EShellContent *shell_content,
 +						 gint action_value);
 +RuleContext *	e_shell_content_get_search_context
 +						(EShellContent *shell_content);
 +FilterRule *	e_shell_content_get_search_rule	(EShellContent *shell_content);
 +void		e_shell_content_set_search_rule (EShellContent *shell_content,
 +						 FilterRule *search_rule);
 +const gchar *	e_shell_content_get_search_text	(EShellContent *shell_content);
 +void		e_shell_content_set_search_text	(EShellContent *shell_content,
 +						 const gchar *search_text);
 +gboolean	e_shell_content_get_search_visible
 +						(EShellContent *shell_content);
 +void		e_shell_content_set_search_visible
 +						(EShellContent *shell_content,
 +						 gboolean search_visible);
 +GtkRadioAction *e_shell_content_get_scope_action(EShellContent *shell_content);
 +void		e_shell_content_set_scope_action(EShellContent *shell_content,
 +						 GtkRadioAction *scope_action);
 +gint		e_shell_content_get_scope_value	(EShellContent *shell_content);
 +void		e_shell_content_set_scope_value	(EShellContent *shell_content,
 +						 gint scope_value);
 +gboolean	e_shell_content_get_scope_visible
 +						(EShellContent *shell_content);
 +void		e_shell_content_set_scope_visible
 +						(EShellContent *shell_content,
 +						 gboolean scope_visible);
 +const gchar *	e_shell_content_get_view_id	(EShellContent *shell_content);
 +void		e_shell_content_set_view_id	(EShellContent *shell_content,
 +						 const gchar *view_id);
 +void		e_shell_content_run_advanced_search_dialog
 +						(EShellContent *shell_content);
 +void		e_shell_content_run_edit_searches_dialog
 +						(EShellContent *shell_content);
 +void		e_shell_content_run_save_search_dialog
 +						(EShellContent *shell_content);
 +
 +G_END_DECLS
 +
 +#endif /* E_SHELL_CONTENT_H */
diff --cc shell/e-shell-migrate.c
index b141ba4,0000000..53df410
mode 100644,000000..100644
--- a/shell/e-shell-migrate.c
+++ b/shell/e-shell-migrate.c
@@@ -1,335 -1,0 +1,335 @@@
 +/*
 + * e-shell-migrate.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-shell-migrate.h"
 +
 +#include <string.h>
 +#include <unistd.h>
 +#include <glib/gi18n.h>
 +#include <glib/gstdio.h>
 +#include <libedataserver/e-xml-utils.h>
 +
 +#include "e-util/e-bconf-map.h"
 +#include "e-util/e-error.h"
 +#include "e-util/e-fsutils.h"
 +#include "e-util/e-util.h"
 +
 +#define GCONF_VERSION_KEY	"/apps/evolution/version"
 +#define GCONF_LAST_VERSION_KEY	"/apps/evolution/last_version"
 +
 +static const gchar *
 +shell_migrate_get_old_data_dir (void)
 +{
 +	static gchar *old_data_dir = NULL;
 +
 +	if (G_UNLIKELY (old_data_dir == NULL))
 +		old_data_dir = g_build_filename (
 +			g_get_home_dir (), "evolution", NULL);
 +
 +	return old_data_dir;
 +}
 +
 +static gboolean
 +shell_migrate_attempt (EShell *shell,
 +                       gint major,
 +                       gint minor,
 +                       gint micro)
 +{
 +	GList *backends;
 +	gboolean success = TRUE;
 +
 +	backends = e_shell_get_shell_backends (shell);
 +
 +	while (success && backends != NULL) {
 +		EShellBackend *shell_backend = backends->data;
 +		GError *error = NULL;
 +
 +		success = e_shell_backend_migrate (
 +			shell_backend, major, minor, micro, &error);
 +
 +		if (error != NULL) {
 +			gint response;
 +
 +			response = e_error_run (
 +				NULL, "shell:upgrade-failed",
 +				error->message, NULL);
 +
 +			if (response == GTK_RESPONSE_CANCEL)
 +				success = FALSE;
 +
 +			g_error_free (error);
 +		}
 +
 +		backends = g_list_next (backends);
 +	}
 +
 +	return success;
 +}
 +
 +static void
 +shell_migrate_get_version (EShell *shell,
 +                           gint *major,
 +                           gint *minor,
 +                           gint *micro)
 +{
 +	GConfClient *client;
 +	const gchar *key;
 +	const gchar *old_data_dir;
 +	gchar *string;
 +
 +	old_data_dir = shell_migrate_get_old_data_dir ();
 +
 +	key = GCONF_VERSION_KEY;
 +	client = e_shell_get_gconf_client (shell);
 +	string = gconf_client_get_string (client, key, NULL);
 +
 +	if (string != NULL) {
 +		/* Since 1.4.0 we've kept the version key in GConf. */
 +		sscanf (string, "%d.%d.%d", major, minor, micro);
 +		g_free (string);
 +
 +	} else if (!g_file_test (old_data_dir, G_FILE_TEST_IS_DIR)) {
 +		/* If the old data directory does not exist,
 +		 * it must be a new installation. */
 +		*major = 0;
 +		*minor = 0;
 +		*micro = 0;
 +
 +	} else {
 +		xmlDocPtr doc;
 +		xmlNodePtr source;
 +		gchar *filename;
 +
 +		filename = g_build_filename (
 +			old_data_dir, "config.xmldb", NULL);
 +		doc = e_xml_parse_file (filename);
 +		g_free (filename);
 +
 +		if (doc == NULL)
 +			return;
 +
 +		source = e_bconf_get_path (doc, "/Shell");
 +		if (source != NULL) {
 +			key = "upgrade_from_1_0_to_1_2_performed";
 +			string = e_bconf_get_value (source, key);
 +		}
 +
 +		if (string != NULL && *string == '1') {
 +			*major = 1;
 +			*minor = 2;
 +			*micro = 0;
 +		} else {
 +			*major = 1;
 +			*minor = 0;
 +			*micro = 0;
 +		}
 +
 +		g_free (string);
 +
 +		if (doc != NULL)
 +			xmlFreeDoc (doc);
 +	}
 +}
 +
 +static gint
 +shell_migrate_remove_dir (const gchar *root,
 +                          const gchar *path)
 +{
 +	GDir *dir;
 +	const gchar *basename;
 +	gchar *filename;
 +	gint result = -1;
 +
 +	/* Recursively removes a directory and its contents. */
 +
 +	dir = g_dir_open (path, 0, NULL);
 +	if (dir == NULL)
 +		return -1;
 +
 +	while ((basename = g_dir_read_name (dir)) != NULL) {
 +		filename = g_build_filename (path, basename, NULL);
 +
 +		/* Make sure we haven't strayed from the evolution dir. */
 +		g_return_val_if_fail (strlen (path) >= strlen (root), -1);
 +		g_return_val_if_fail (g_str_has_prefix (path, root), -1);
 +
 +		if (g_file_test (filename, G_FILE_TEST_IS_DIR)) {
 +			if (shell_migrate_remove_dir (root, filename) < 0)
 +				goto fail;
 +		} else {
 +			if (g_unlink (filename) < 0)
 +				goto fail;
 +		}
 +
 +		g_free (filename);
 +		filename = NULL;
 +	}
 +
 +	result = g_rmdir (path);
 +
 +fail:
 +	g_free (filename);
 +	g_dir_close (dir);
 +
 +	return result;
 +}
 +
 +gboolean
 +e_shell_migrate_attempt (EShell *shell)
 +{
 +	GConfClient *client;
 +	const gchar *key;
 +	const gchar *old_data_dir;
 +	gint major, minor, micro;
 +	gint last_major, last_minor, last_micro;
 +	gint curr_major, curr_minor, curr_micro;
 +	gboolean migrated = FALSE;
 +	gchar *string;
 +
 +	g_return_val_if_fail (E_IS_SHELL (shell), FALSE);
 +
 +	client = e_shell_get_gconf_client (shell);
 +	old_data_dir = shell_migrate_get_old_data_dir ();
 +
 +	if (sscanf (BASE_VERSION, "%d.%d", &curr_major, &curr_minor) != 2) {
 +		g_warning ("Could not parse BASE_VERSION (%s)", BASE_VERSION);
 +		return TRUE;
 +	}
 +
 +	curr_micro = atoi (UPGRADE_REVISION);
 +
 +	shell_migrate_get_version (shell, &major, &minor, &micro);
 +
 +	if (!(curr_major > major ||
 +		(curr_major == major && curr_minor > minor) ||
 +		(curr_minor == minor && curr_micro > micro)))
 +		goto check_old;
 +
 +	/* If upgrading from < 1.5, we need to copy most data from
 +	 * ~/evolution to ~/.evolution.  Make sure we have the disk
 +	 * space for it before proceeding. */
 +	if (major == 1 && minor < 5) {
 +		glong avail;
 +		glong usage;
 +
 +		usage = e_fsutils_usage (old_data_dir);
 +		avail = e_fsutils_avail (g_get_home_dir ());
 +		if (usage >= 0 && avail >= 0 && avail < usage) {
 +			gchar *need;
 +			gchar *have;
 +
 +			need = g_strdup_printf (_("%ld KB"), usage);
 +			have = g_strdup_printf (_("%ld KB"), avail);
 +
 +			e_error_run (
 +				NULL, "shell:upgrade-nospace",
 +				need, have, NULL);
 +
 +			g_free (need);
 +			g_free (have);
 +
 +			_exit (EXIT_SUCCESS);
 +		}
 +	}
 +
 +	if (!shell_migrate_attempt (shell, major, minor, micro))
 +		_exit (EXIT_SUCCESS);
 +
 +	/* Record a successful migration. */
 +	string = g_strdup_printf ("%d.%d.%d", major, minor, micro);
 +	gconf_client_set_string (client, GCONF_VERSION_KEY, string, NULL);
 +	g_free (string);
 +
 +	migrated = TRUE;
 +
 +check_old:
 +
 +	key = GCONF_LAST_VERSION_KEY;
 +
 +	/* Try to retrieve the last migrated version from GConf. */
 +	string = gconf_client_get_string (client, key, NULL);
 +	if (migrated || string == NULL || sscanf (string, "%d.%d.%d",
 +		&last_major, &last_minor, &last_micro) != 3) {
 +		last_major = major;
 +		last_minor = minor;
 +		last_micro = micro;
 +	}
 +	g_free (string);
 +
 +	/* If the last migrated version was old, check for stuff to remove. */
 +	if (last_major == 1 && last_minor < 5 &&
 +		g_file_test (old_data_dir, G_FILE_TEST_IS_DIR)) {
 +
 +		gint response;
 +
 +		string = g_strdup_printf (
 +			"%d.%d.%d", last_major, last_minor, last_micro);
 +		response = e_error_run (
 +			NULL, "shel:upgrade-remove-1-4", string, NULL);
 +		g_free (string);
 +
 +		switch (response) {
 +			case GTK_RESPONSE_OK:  /* delete */
 +				response = e_error_run (
 +					NULL,
 +					"shell:upgrade-remove-1-4-confirm",
 +					NULL);
 +				if (response == GTK_RESPONSE_OK)
 +					shell_migrate_remove_dir (
 +						old_data_dir, old_data_dir);
 +				else
 +					break;
 +				/* fall through */
 +
 +			case GTK_RESPONSE_ACCEPT:  /* keep */
 +				last_major = curr_major;
 +				last_minor = curr_minor;
 +				last_micro = curr_micro;
 +				break;
 +
 +			default:
 +				break;
 +		}
 +	} else {
 +		last_major = curr_major;
 +		last_minor = curr_minor;
 +		last_micro = curr_micro;
 +	}
 +
 +	string = g_strdup_printf (
 +		"%d.%d.%d", last_major, last_minor, last_micro);
 +	gconf_client_set_string (client, key, string, NULL);
 +	g_free (string);
 +
 +	return TRUE;
 +}
 +
 +GQuark
 +e_shell_migrate_error_quark (void)
 +{
 +	static GQuark quark = 0;
 +
 +	if (G_UNLIKELY (quark == 0))
 +		quark = g_quark_from_static_string (
 +			"e-shell-migrate-error-quark");
 +
 +	return quark;
 +}
diff --cc shell/e-shell-migrate.h
index 45907ce,0000000..8ebe697
mode 100644,000000..100644
--- a/shell/e-shell-migrate.h
+++ b/shell/e-shell-migrate.h
@@@ -1,52 -1,0 +1,52 @@@
 +/*
 + * e-shell-migrate.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +/* This is an EShell extension that handles migrating from older versions. */
 +
 +#ifndef E_SHELL_MIGRATE_H
 +#define E_SHELL_MIGRATE_H
 +
 +#include <shell/e-shell-common.h>
 +#include <shell/e-shell.h>
 +
 +/**
 + * E_SHELL_MIGRATE_ERROR:
 + *
 + * Error domain for migration operations.  Errors in this domain will be
 + * from the #EShellMigrateError enumeration.  See #GError for information
 + * on error domains.
 + **/
 +#define E_SHELL_MIGRATE_ERROR \
 +	(e_shell_migrate_error_quark ())
 +
 +G_BEGIN_DECLS
 +
 +/* XXX Need more specific error codes? */
 +typedef enum {
 +	E_SHELL_MIGRATE_ERROR_FAILED
 +} EShellMigrateError;
 +
 +gboolean	e_shell_migrate_attempt		(EShell *shell);
 +GQuark		e_shell_migrate_error_quark	(void);
 +
 +G_END_DECLS
 +
 +#endif /* E_SHELL_MIGRATE_H */
diff --cc shell/e-shell-settings.c
index 9f03f38,0000000..0883382
mode 100644,000000..100644
--- a/shell/e-shell-settings.c
+++ b/shell/e-shell-settings.c
@@@ -1,559 -1,0 +1,559 @@@
 +/*
 + * e-shell-settings.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-shell-settings.h"
 +
 +#include "e-util/gconf-bridge.h"
 +
 +#define E_SHELL_SETTINGS_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_SHELL_SETTINGS, EShellSettingsPrivate))
 +
 +struct _EShellSettingsPrivate {
 +	GArray *value_array;
 +	guint debug	: 1;
 +};
 +
 +static GList *instances;
 +static guint property_count;
 +static gpointer parent_class;
 +
 +static void
 +shell_settings_set_property (GObject *object,
 +                             guint property_id,
 +                             const GValue *value,
 +                             GParamSpec *pspec)
 +{
 +	EShellSettingsPrivate *priv;
 +	GValue *dest_value;
 +
 +	priv = E_SHELL_SETTINGS_GET_PRIVATE (object);
 +
 +	dest_value = &g_array_index (
 +		priv->value_array, GValue, property_id - 1);
 +
 +	g_value_copy (value, dest_value);
 +	g_object_notify (object, pspec->name);
 +
 +	if (priv->debug) {
 +		gchar *contents;
 +
 +		contents = g_strdup_value_contents (value);
 +		g_debug (
 +			"Setting '%s' set to '%s' (%s)",
 +			pspec->name, contents, G_VALUE_TYPE_NAME (value));
 +		g_free (contents);
 +	}
 +}
 +
 +static void
 +shell_settings_get_property (GObject *object,
 +                             guint property_id,
 +                             GValue *value,
 +                             GParamSpec *pspec)
 +{
 +	EShellSettingsPrivate *priv;
 +	GValue *src_value;
 +
 +	priv = E_SHELL_SETTINGS_GET_PRIVATE (object);
 +
 +	src_value = &g_array_index (
 +		priv->value_array, GValue, property_id - 1);
 +
 +	g_value_copy (src_value, value);
 +}
 +
 +static void
 +shell_settings_finalize (GObject *object)
 +{
 +	EShellSettingsPrivate *priv;
 +	guint ii;
 +
 +	priv = E_SHELL_SETTINGS_GET_PRIVATE (object);
 +
 +	for (ii = 0; ii < priv->value_array->len; ii++)
 +		g_value_unset (&g_array_index (priv->value_array, GValue, ii));
 +
 +	g_array_free (priv->value_array, TRUE);
 +
 +	/* Chain up to parent's finalize() method. */
 +	G_OBJECT_CLASS (parent_class)->finalize (object);
 +}
 +
 +static void
 +shell_settings_class_init (EShellSettingsClass *class)
 +{
 +	GObjectClass *object_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (EShellSettingsPrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->set_property = shell_settings_set_property;
 +	object_class->get_property = shell_settings_get_property;
 +	object_class->finalize = shell_settings_finalize;
 +}
 +
 +static void
 +shell_settings_init (EShellSettings *shell_settings,
 +                     GObjectClass *object_class)
 +{
 +	GArray *value_array;
 +	GParamSpec **pspecs;
 +	guint ii;
 +
 +	instances = g_list_prepend (instances, shell_settings);
 +
 +	value_array = g_array_new (FALSE, TRUE, sizeof (GValue));
 +	g_array_set_size (value_array, property_count);
 +
 +	shell_settings->priv = E_SHELL_SETTINGS_GET_PRIVATE (shell_settings);
 +	shell_settings->priv->value_array = value_array;
 +
 +	g_object_freeze_notify (G_OBJECT (shell_settings));
 +
 +	pspecs = g_object_class_list_properties (object_class, NULL);
 +	for (ii = 0; ii < property_count; ii++) {
 +		GParamSpec *pspec = pspecs[ii];
 +		GValue *value;
 +
 +		value = &g_array_index (value_array, GValue, ii);
 +		g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec));
 +		g_param_value_set_default (pspec, value);
 +		g_object_notify (G_OBJECT (shell_settings), pspec->name);
 +	}
 +	g_free (pspecs);
 +
 +	g_object_thaw_notify (G_OBJECT (shell_settings));
 +}
 +
 +GType
 +e_shell_settings_get_type (void)
 +{
 +	static GType type = 0;
 +
 +	if (G_UNLIKELY (type == 0)) {
 +		const GTypeInfo type_info = {
 +			sizeof (EShellSettingsClass),
 +			(GBaseInitFunc) NULL,
 +			(GBaseFinalizeFunc) NULL,
 +			(GClassInitFunc) shell_settings_class_init,
 +			(GClassFinalizeFunc) NULL,
 +			NULL,  /* class_data */
 +			sizeof (EShellSettings),
 +			0,     /* n_preallocs */
 +			(GInstanceInitFunc) shell_settings_init,
 +			NULL   /* value_table */
 +		};
 +
 +		type = g_type_register_static (
 +			G_TYPE_OBJECT, "EShellSettings", &type_info, 0);
 +	}
 +
 +	return type;
 +}
 +
 +/**
 + * e_shell_settings_install_property:
 + * @pspec: a #GParamSpec
 + *
 + * Installs a new class property for #EShellSettings.  This is usually
 + * done during initialization of a #EShellBackend or plugin, followed by
 + * a call to e_shell_settings_bind_to_gconf() to bind the property to a
 + * GConf key.
 + **/
 +void
 +e_shell_settings_install_property (GParamSpec *pspec)
 +{
 +	static GObjectClass *class = NULL;
 +	GList *iter, *next;
 +
 +	g_return_if_fail (G_IS_PARAM_SPEC (pspec));
 +
 +	if (G_UNLIKELY (class == NULL))
 +		class = g_type_class_ref (E_TYPE_SHELL_SETTINGS);
 +
 +	if (g_object_class_find_property (class, pspec->name) != NULL) {
 +		g_warning (
 +			"Settings property \"%s\" already exists",
 +			pspec->name);
 +		return;
 +	}
 +
 +	for (iter = instances; iter != NULL; iter = iter->next)
 +		g_object_freeze_notify (iter->data);
 +
 +	g_object_class_install_property (class, ++property_count, pspec);
 +
 +	for (iter = instances; iter != NULL; iter = iter->next) {
 +		EShellSettings *shell_settings = iter->data;
 +		GArray *value_array;
 +		GValue *value;
 +
 +		value_array = shell_settings->priv->value_array;
 +		g_array_set_size (value_array, property_count);
 +
 +		value = &g_array_index (
 +			value_array, GValue, property_count - 1);
 +		g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec));
 +		g_param_value_set_default (pspec, value);
 +		g_object_notify (G_OBJECT (shell_settings), pspec->name);
 +	}
 +
 +	for (iter = instances; iter != NULL; iter = next) {
 +		next = iter->next;
 +		g_object_thaw_notify (iter->data);
 +	}
 +}
 +
 +/**
 + * e_shell_settings_bind_to_gconf:
 + * @shell_settings: an #EShellSettings
 + * @property_name: the name of the property to bind
 + * @gconf_key: the GConf key to bind the property to
 + *
 + * Binds @property_name to @gconf_key, causing them to have the same value
 + * at all times.
 + *
 + * The types of @property_name and @gconf_key should be compatible.  Floats
 + * and doubles, and ints, uints, longs, unlongs, int64s, uint64s, chars,
 + * uchars and enums can be matched up.  Booleans and strings can only be
 + * matched to their respective types.
 + *
 + * On calling this function, @property_name is initialized to the current
 + * value of @gconf_key.
 + **/
 +void
 +e_shell_settings_bind_to_gconf (EShellSettings *shell_settings,
 +                                const gchar *property_name,
 +                                const gchar *gconf_key)
 +{
 +	g_return_if_fail (E_IS_SHELL_SETTINGS (shell_settings));
 +	g_return_if_fail (property_name != NULL);
 +	g_return_if_fail (gconf_key != NULL);
 +
 +	gconf_bridge_bind_property (
 +		gconf_bridge_get (), gconf_key,
 +		G_OBJECT (shell_settings), property_name);
 +}
 +
 +/**
 + * e_shell_settings_enable_debug:
 + * @shell_settings: an #EShellSettings
 + *
 + * Print a debug message to standard output when a property value changes.
 + **/
 +void
 +e_shell_settings_enable_debug (EShellSettings *shell_settings)
 +{
 +	g_return_if_fail (E_IS_SHELL_SETTINGS (shell_settings));
 +
 +	shell_settings->priv->debug = TRUE;
 +}
 +
 +/**
 + * e_shell_settings_get_boolean:
 + * @shell_settings: an #EShellSettings
 + * @property_name: an installed property name
 + *
 + * Return the contents of an #EShellSettings property of type
 + * #G_TYPE_BOOLEAN.
 + *
 + * Returns: boolean contents of @property_name
 + **/
 +gboolean
 +e_shell_settings_get_boolean (EShellSettings *shell_settings,
 +                              const gchar *property_name)
 +{
 +	GObject *object;
 +	GValue value = { 0, };
 +	gboolean v_boolean;
 +
 +	g_return_val_if_fail (E_IS_SHELL_SETTINGS (shell_settings), FALSE);
 +	g_return_val_if_fail (property_name != NULL, FALSE);
 +
 +	object = G_OBJECT (shell_settings);
 +	g_value_init (&value, G_TYPE_BOOLEAN);
 +	g_object_get_property (object, property_name, &value);
 +	v_boolean = g_value_get_boolean (&value);
 +	g_value_unset (&value);
 +
 +	return v_boolean;
 +}
 +
 +/**
 + * e_shell_settings_set_boolean:
 + * @shell_settings: an #EShellSettings
 + * @property_name: an installed property name
 + * @v_boolean: boolean value to be set
 + *
 + * Sets the contents of an #EShellSettings property of type #G_TYPE_BOOLEAN
 + * to @v_boolean.  If @property_name is bound to a GConf key, the GConf key
 + * will also be set to @v_boolean.
 + **/
 +void
 +e_shell_settings_set_boolean (EShellSettings *shell_settings,
 +                              const gchar *property_name,
 +                              gboolean v_boolean)
 +{
 +	GObject *object;
 +	GValue value = { 0, };
 +
 +	g_return_if_fail (E_IS_SHELL_SETTINGS (shell_settings));
 +	g_return_if_fail (property_name != NULL);
 +
 +	object = G_OBJECT (shell_settings);
 +	g_value_init (&value, G_TYPE_BOOLEAN);
 +	g_value_set_boolean (&value, v_boolean);
 +	g_object_set_property (object, property_name, &value);
 +	g_value_unset (&value);
 +}
 +
 +/**
 + * e_shell_settings_get_int:
 + * @shell_settings: an #EShellSettings
 + * @property_name: an installed property name
 + *
 + * Returns the contents of an #EShellSettings property of type
 + * #G_TYPE_INT.
 + *
 + * Returns: integer contents of @property_name
 + **/
 +gint
 +e_shell_settings_get_int (EShellSettings *shell_settings,
 +                          const gchar *property_name)
 +{
 +	GObject *object;
 +	GValue value = { 0, };
 +	gint v_int;
 +
 +	g_return_val_if_fail (E_IS_SHELL_SETTINGS (shell_settings), 0);
 +	g_return_val_if_fail (property_name != NULL, 0);
 +
 +	object = G_OBJECT (shell_settings);
 +	g_value_init (&value, G_TYPE_INT);
 +	g_object_get_property (object, property_name, &value);
 +	v_int = g_value_get_int (&value);
 +	g_value_unset (&value);
 +
 +	return v_int;
 +}
 +
 +/**
 + * e_shell_settings_set_int:
 + * @shell_settings: an #EShellSettings
 + * @property_name: an installed property name
 + * @v_int: integer value to be set
 + *
 + * Sets the contents of an #EShellSettings property of type #G_TYPE_INT
 + * to @v_int.  If @property_name is bound to a GConf key, the GConf key
 + * will also be set to @v_int.
 + **/
 +void
 +e_shell_settings_set_int (EShellSettings *shell_settings,
 +                          const gchar *property_name,
 +                          gint v_int)
 +{
 +	GObject *object;
 +	GValue value = { 0, };
 +
 +	g_return_if_fail (E_IS_SHELL_SETTINGS (shell_settings));
 +	g_return_if_fail (property_name != NULL);
 +
 +	object = G_OBJECT (shell_settings);
 +	g_value_init (&value, G_TYPE_INT);
 +	g_value_set_int (&value, v_int);
 +	g_object_set_property (object, property_name, &value);
 +	g_value_unset (&value);
 +}
 +
 +/**
 + * e_shell_settings_get_string:
 + * @shell_settings: an #EShellSettings
 + * @property_name: an installed property name
 + *
 + * Returns the contents of an #EShellSettings property of type
 + * #G_TYPE_STRING.  The returned string should be freed using g_free().
 + *
 + * Returns: string contents of @property_name
 + **/
 +gchar *
 +e_shell_settings_get_string (EShellSettings *shell_settings,
 +                             const gchar *property_name)
 +{
 +	GObject *object;
 +	GValue value = { 0, };
 +	gchar *v_string;
 +
 +	g_return_val_if_fail (E_IS_SHELL_SETTINGS (shell_settings), NULL);
 +	g_return_val_if_fail (property_name != NULL, NULL);
 +
 +	object = G_OBJECT (shell_settings);
 +	g_value_init (&value, G_TYPE_STRING);
 +	g_object_get_property (object, property_name, &value);
 +	v_string = g_value_dup_string (&value);
 +	g_value_unset (&value);
 +
 +	return v_string;
 +}
 +
 +/**
 + * e_shell_settings_set_string:
 + * @shell_settings: an #EShellSettings
 + * @property_name: an installed property name
 + * @v_string: string to be set
 + *
 + * Sets the contents of an #EShellSettings property of type #G_TYPE_STRING
 + * to @v_string.  If @property_name is bound to a GConf key, the GConf key
 + * will also be set to @v_string.
 + **/
 +void
 +e_shell_settings_set_string (EShellSettings *shell_settings,
 +                             const gchar *property_name,
 +                             const gchar *v_string)
 +{
 +	GObject *object;
 +	GValue value = { 0, };
 +
 +	g_return_if_fail (E_IS_SHELL_SETTINGS (shell_settings));
 +	g_return_if_fail (property_name != NULL);
 +
 +	object = G_OBJECT (shell_settings);
 +	g_value_init (&value, G_TYPE_STRING);
 +	g_value_set_string (&value, v_string);
 +	g_object_set_property (object, property_name, &value);
 +	g_value_unset (&value);
 +}
 +
 +/**
 + * e_shell_settings_get_object:
 + * @shell_settings: an #EShellSettings
 + * @property_name: an installed property name
 + *
 + * Returns the contents of an #EShellSettings property of type
 + * #G_TYPE_OBJECT.  The caller owns the reference to the returned
 + * object, and should call g_object_unref() when finished with it.
 + *
 + * Returns: a new reference to the object under @property_name
 + **/
 +gpointer
 +e_shell_settings_get_object (EShellSettings *shell_settings,
 +                             const gchar *property_name)
 +{
 +	GObject *object;
 +	GValue value = { 0, };
 +	gpointer v_object;
 +
 +	g_return_val_if_fail (E_IS_SHELL_SETTINGS (shell_settings), NULL);
 +	g_return_val_if_fail (property_name != NULL, NULL);
 +
 +	object = G_OBJECT (shell_settings);
 +	g_value_init (&value, G_TYPE_OBJECT);
 +	g_object_get_property (object, property_name, &value);
 +	v_object = g_value_dup_object (&value);
 +	g_value_unset (&value);
 +
 +	return v_object;
 +}
 +
 +/**
 + * e_shell_settings_set_object:
 + * @shell_settings: an #EShellSettings
 + * @property_name: an installed property name
 + * @v_object: object to be set
 + *
 + * Sets the contents of an #EShellSettings property of type #G_TYPE_OBJECT
 + * to @v_object.
 + **/
 +void
 +e_shell_settings_set_object (EShellSettings *shell_settings,
 +                             const gchar *property_name,
 +                             gpointer v_object)
 +{
 +	GObject *object;
 +	GValue value = { 0, };
 +
 +	g_return_if_fail (E_IS_SHELL_SETTINGS (shell_settings));
 +	g_return_if_fail (property_name != NULL);
 +
 +	object = G_OBJECT (shell_settings);
 +	g_value_init (&value, G_TYPE_OBJECT);
 +	g_value_set_object (&value, v_object);
 +	g_object_set_property (object, property_name, &value);
 +	g_value_unset (&value);
 +}
 +
 +/**
 + * e_shell_settings_get_pointer:
 + * @shell_settings: an #EShellSettings
 + * @property_name: an installed property name
 + *
 + * Returns the contents of an #EShellSettings property of type
 + * #G_TYPE_POINTER.
 + *
 + * Returns: pointer contents of @property_name
 + **/
 +gpointer
 +e_shell_settings_get_pointer (EShellSettings *shell_settings,
 +                              const gchar *property_name)
 +{
 +	GObject *object;
 +	GValue value = { 0, };
 +	gpointer v_pointer;
 +
 +	g_return_val_if_fail (E_IS_SHELL_SETTINGS (shell_settings), NULL);
 +	g_return_val_if_fail (property_name != NULL, NULL);
 +
 +	object = G_OBJECT (shell_settings);
 +	g_value_init (&value, G_TYPE_POINTER);
 +	g_object_get_property (object, property_name, &value);
 +	v_pointer = g_value_get_pointer (&value);
 +	g_value_unset (&value);
 +
 +	return v_pointer;
 +}
 +
 +/**
 + * e_shell_settings_set_pointer:
 + * @shell_settings: an #EShellSettings
 + * @property_name: an installed property name
 + * @v_pointer: pointer to be set
 + *
 + * Sets the contents of an #EShellSettings property of type #G_TYPE_POINTER
 + * to @v_pointer.
 + **/
 +void
 +e_shell_settings_set_pointer (EShellSettings *shell_settings,
 +                              const gchar *property_name,
 +                              gpointer v_pointer)
 +{
 +	GObject *object;
 +	GValue value = { 0, };
 +
 +	g_return_if_fail (E_IS_SHELL_SETTINGS (shell_settings));
 +	g_return_if_fail (property_name != NULL);
 +
 +	object = G_OBJECT (shell_settings);
 +	g_value_init (&value, G_TYPE_POINTER);
 +	g_value_set_pointer (&value, v_pointer);
 +	g_object_set_property (object, property_name, &value);
 +	g_value_unset (&value);
 +}
diff --cc shell/e-shell-settings.h
index a9f6a20,0000000..c400fac
mode 100644,000000..100644
--- a/shell/e-shell-settings.h
+++ b/shell/e-shell-settings.h
@@@ -1,114 -1,0 +1,114 @@@
 +/*
 + * e-shell-settings.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +/**
 + * SECTION: e-shell-settings
 + * @short_description: settings management
 + * @include: shell/e-shell-settings.h
 + **/
 +
 +#ifndef E_SHELL_SETTINGS_H
 +#define E_SHELL_SETTINGS_H
 +
 +#include <shell/e-shell-common.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_SHELL_SETTINGS \
 +	(e_shell_settings_get_type ())
 +#define E_SHELL_SETTINGS(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_SHELL_SETTINGS, EShellSettings))
 +#define E_SHELL_SETTINGS_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_SHELL_SETTINGS, EShellSettingsClass))
 +#define E_IS_SHELL_SETTINGS(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_SHELL_SETTINGS))
 +#define E_IS_SHELL_SETTINGS_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), E_TYPE_SHELL_SETTINGS))
 +#define E_SHELL_SETTINGS_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_SHELL_SETTINGS, EShellSettingsClass))
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _EShellSettings EShellSettings;
 +typedef struct _EShellSettingsClass EShellSettingsClass;
 +typedef struct _EShellSettingsPrivate EShellSettingsPrivate;
 +
 +/**
 + * EShellSettings:
 + *
 + * Contains only private data that should be read and manipulated using the
 + * functions below.
 + **/
 +struct _EShellSettings {
 +	GObject parent;
 +	EShellSettingsPrivate *priv;
 +};
 +
 +struct _EShellSettingsClass {
 +	GObjectClass parent_class;
 +};
 +
 +GType		e_shell_settings_get_type	(void);
 +void		e_shell_settings_install_property
 +						(GParamSpec *pspec);
 +void		e_shell_settings_bind_to_gconf	(EShellSettings *shell_settings,
 +						 const gchar *property_name,
 +						 const gchar *gconf_key);
 +void		e_shell_settings_enable_debug	(EShellSettings *shell_settings);
 +
 +/* Getters and setters for common EShellSettings property types.
 + * These are more convenient than g_object_get() / g_object_set().
 + * Add more types as needed.  If GObject ever adds similar functions,
 + * kill these. */
 +
 +gboolean	e_shell_settings_get_boolean	(EShellSettings *shell_settings,
 +						 const gchar *property_name);
 +void		e_shell_settings_set_boolean	(EShellSettings *shell_settings,
 +						 const gchar *property_name,
 +						 gboolean v_boolean);
 +gint		e_shell_settings_get_int	(EShellSettings *shell_settings,
 +						 const gchar *property_name);
 +void		e_shell_settings_set_int	(EShellSettings *shell_settings,
 +						 const gchar *property_name,
 +						 gint v_int);
 +gchar *		e_shell_settings_get_string	(EShellSettings *shell_settings,
 +						 const gchar *property_name);
 +void		e_shell_settings_set_string	(EShellSettings *shell_settings,
 +						 const gchar *property_name,
 +						 const gchar *v_string);
 +gpointer	e_shell_settings_get_object	(EShellSettings *shell_settings,
 +						 const gchar *property_name);
 +void		e_shell_settings_set_object	(EShellSettings *shell_settings,
 +						 const gchar *property_name,
 +						 gpointer v_object);
 +gpointer	e_shell_settings_get_pointer	(EShellSettings *shell_setting,
 +						 const gchar *property_name);
 +void		e_shell_settings_set_pointer	(EShellSettings *shell_setting,
 +						 const gchar *property_name,
 +						 gpointer v_pointer);
 +
 +G_END_DECLS
 +
 +#endif /* E_SHELL_SETTINGS_H */
diff --cc shell/e-shell-sidebar.c
index 671bcad,0000000..ad4cb92
mode 100644,000000..100644
--- a/shell/e-shell-sidebar.c
+++ b/shell/e-shell-sidebar.c
@@@ -1,681 -1,0 +1,681 @@@
 +/*
 + * e-shell-sidebar.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-shell-sidebar.h"
 +
 +#include <e-shell-view.h>
 +
 +#define E_SHELL_SIDEBAR_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_SHELL_SIDEBAR, EShellSidebarPrivate))
 +
 +struct _EShellSidebarPrivate {
 +
 +	gpointer shell_view;  /* weak pointer */
 +
 +	GtkWidget *event_box;
 +	GtkWidget *image;
 +	GtkWidget *primary_label;
 +	GtkWidget *secondary_label;
 +	gchar *primary_text;
 +	gchar *secondary_text;
 +};
 +
 +enum {
 +	PROP_0,
 +	PROP_ICON_NAME,
 +	PROP_PRIMARY_TEXT,
 +	PROP_SECONDARY_TEXT,
 +	PROP_SHELL_VIEW
 +};
 +
 +static gpointer parent_class;
 +
 +static void
 +shell_sidebar_set_shell_view (EShellSidebar *shell_sidebar,
 +                              EShellView *shell_view)
 +{
 +	g_return_if_fail (shell_sidebar->priv->shell_view == NULL);
 +
 +	shell_sidebar->priv->shell_view = shell_view;
 +
 +	g_object_add_weak_pointer (
 +		G_OBJECT (shell_view),
 +		&shell_sidebar->priv->shell_view);
 +}
 +
 +static void
 +shell_sidebar_set_property (GObject *object,
 +                            guint property_id,
 +                            const GValue *value,
 +                            GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_ICON_NAME:
 +			e_shell_sidebar_set_icon_name (
 +				E_SHELL_SIDEBAR (object),
 +				g_value_get_string (value));
 +			return;
 +
 +		case PROP_PRIMARY_TEXT:
 +			e_shell_sidebar_set_primary_text (
 +				E_SHELL_SIDEBAR (object),
 +				g_value_get_string (value));
 +			return;
 +
 +		case PROP_SECONDARY_TEXT:
 +			e_shell_sidebar_set_secondary_text (
 +				E_SHELL_SIDEBAR (object),
 +				g_value_get_string (value));
 +			return;
 +
 +		case PROP_SHELL_VIEW:
 +			shell_sidebar_set_shell_view (
 +				E_SHELL_SIDEBAR (object),
 +				g_value_get_object (value));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +shell_sidebar_get_property (GObject *object,
 +                            guint property_id,
 +                            GValue *value,
 +                            GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_ICON_NAME:
 +			g_value_set_string (
 +				value, e_shell_sidebar_get_icon_name (
 +				E_SHELL_SIDEBAR (object)));
 +			return;
 +
 +		case PROP_PRIMARY_TEXT:
 +			g_value_set_string (
 +				value, e_shell_sidebar_get_primary_text (
 +				E_SHELL_SIDEBAR (object)));
 +			return;
 +
 +		case PROP_SECONDARY_TEXT:
 +			g_value_set_string (
 +				value, e_shell_sidebar_get_secondary_text (
 +				E_SHELL_SIDEBAR (object)));
 +			return;
 +
 +		case PROP_SHELL_VIEW:
 +			g_value_set_object (
 +				value, e_shell_sidebar_get_shell_view (
 +				E_SHELL_SIDEBAR (object)));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +shell_sidebar_dispose (GObject *object)
 +{
 +	EShellSidebarPrivate *priv;
 +
 +	priv = E_SHELL_SIDEBAR_GET_PRIVATE (object);
 +
 +	if (priv->shell_view != NULL) {
 +		g_object_remove_weak_pointer (
 +			G_OBJECT (priv->shell_view), &priv->shell_view);
 +		priv->shell_view = NULL;
 +	}
 +
 +	if (priv->image != NULL) {
 +		g_object_unref (priv->image);
 +		priv->image = NULL;
 +	}
 +
 +	if (priv->event_box != NULL) {
 +		g_object_unref (priv->event_box);
 +		priv->event_box = NULL;
 +	}
 +
 +	if (priv->primary_label != NULL) {
 +		g_object_unref (priv->primary_label);
 +		priv->primary_label = NULL;
 +	}
 +
 +	if (priv->secondary_label != NULL) {
 +		g_object_unref (priv->secondary_label);
 +		priv->secondary_label = NULL;
 +	}
 +
 +	/* Chain up to parent's dispose() method. */
 +	G_OBJECT_CLASS (parent_class)->dispose (object);
 +}
 +
 +static void
 +shell_sidebar_finalize (GObject *object)
 +{
 +	EShellSidebarPrivate *priv;
 +
 +	priv = E_SHELL_SIDEBAR_GET_PRIVATE (object);
 +
 +	g_free (priv->primary_text);
 +	g_free (priv->secondary_text);
 +
 +	/* Chain up to parent's finalize() method. */
 +	G_OBJECT_CLASS (parent_class)->finalize (object);
 +}
 +
 +static void
 +shell_sidebar_constructed (GObject *object)
 +{
 +	EShellView *shell_view;
 +	EShellSidebar *shell_sidebar;
 +	GtkSizeGroup *size_group;
 +	GtkAction *action;
 +	GtkWidget *container;
 +	GtkWidget *widget;
 +	gchar *label;
 +	gchar *icon_name;
 +
 +	shell_sidebar = E_SHELL_SIDEBAR (object);
 +	shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
 +	size_group = e_shell_view_get_size_group (shell_view);
 +	action = e_shell_view_get_action (shell_view);
 +
 +	widget = shell_sidebar->priv->event_box;
 +	gtk_size_group_add_widget (size_group, widget);
 +
 +	container = widget;
 +
 +	widget = gtk_hbox_new (FALSE, 6);
 +	gtk_container_set_border_width (GTK_CONTAINER (widget), 6);
 +	gtk_container_add (GTK_CONTAINER (container), widget);
 +	gtk_widget_show (widget);
 +
 +	container = widget;
 +
 +	widget = gtk_image_new ();
 +	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
 +	shell_sidebar->priv->image = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	widget = gtk_label_new (NULL);
 +	gtk_label_set_ellipsize (GTK_LABEL (widget), PANGO_ELLIPSIZE_END);
 +	gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
 +	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
 +	shell_sidebar->priv->primary_label = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	widget = gtk_label_new (NULL);
 +	gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5);
 +	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
 +	shell_sidebar->priv->secondary_label = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	g_object_get (action, "icon-name", &icon_name, NULL);
 +	e_shell_sidebar_set_icon_name (shell_sidebar, icon_name);
 +	g_free (icon_name);
 +
 +	g_object_get (action, "label", &label, NULL);
 +	e_shell_sidebar_set_primary_text (shell_sidebar, label);
 +	g_free (label);
 +}
 +
 +static void
 +shell_sidebar_size_request (GtkWidget *widget,
 +                            GtkRequisition *requisition)
 +{
 +	EShellSidebarPrivate *priv;
 +	GtkRequisition child_requisition;
 +	GtkWidget *child;
 +
 +	priv = E_SHELL_SIDEBAR_GET_PRIVATE (widget);
 +
 +	requisition->width = 0;
 +	requisition->height = 0;
 +
 +	child = gtk_bin_get_child (GTK_BIN (widget));
 +	gtk_widget_size_request (child, requisition);
 +
 +	child = priv->event_box;
 +	gtk_widget_size_request (child, &child_requisition);
 +	requisition->width = MAX (requisition->width, child_requisition.width);
 +	requisition->height += child_requisition.height;
 +}
 +
 +static void
 +shell_sidebar_size_allocate (GtkWidget *widget,
 +                             GtkAllocation *allocation)
 +{
 +	EShellSidebarPrivate *priv;
 +	GtkAllocation child_allocation;
 +	GtkRequisition child_requisition;
 +	GtkWidget *child;
 +
 +	priv = E_SHELL_SIDEBAR_GET_PRIVATE (widget);
 +
 +	widget->allocation = *allocation;
 +
 +	child = priv->event_box;
 +	gtk_widget_size_request (child, &child_requisition);
 +
 +	child_allocation.x = allocation->x;
 +	child_allocation.y = allocation->y;
 +	child_allocation.width = allocation->width;
 +	child_allocation.height = child_requisition.height;
 +
 +	gtk_widget_size_allocate (child, &child_allocation);
 +
 +	child_allocation.y += child_requisition.height;
 +	child_allocation.height =
 +		allocation->height - child_requisition.height;
 +
 +	child = gtk_bin_get_child (GTK_BIN (widget));
 +	if (child != NULL)
 +		gtk_widget_size_allocate (child, &child_allocation);
 +}
 +
 +static void
 +shell_sidebar_remove (GtkContainer *container,
 +                      GtkWidget *widget)
 +{
 +	EShellSidebarPrivate *priv;
 +
 +	priv = E_SHELL_SIDEBAR_GET_PRIVATE (container);
 +
 +	/* Look in the internal widgets first. */
 +
 +	if (widget == priv->event_box) {
 +		gtk_widget_unparent (priv->event_box);
 +		gtk_widget_queue_resize (GTK_WIDGET (container));
 +		return;
 +	}
 +
 +	/* Chain up to parent's remove() method. */
 +	GTK_CONTAINER_CLASS (parent_class)->remove (container, widget);
 +}
 +
 +static void
 +shell_sidebar_forall (GtkContainer *container,
 +                      gboolean include_internals,
 +                      GtkCallback callback,
 +                      gpointer callback_data)
 +{
 +	EShellSidebarPrivate *priv;
 +
 +	priv = E_SHELL_SIDEBAR_GET_PRIVATE (container);
 +
 +	if (include_internals)
 +		callback (priv->event_box, callback_data);
 +
 +	/* Chain up to parent's forall() method. */
 +	GTK_CONTAINER_CLASS (parent_class)->forall (
 +		container, include_internals, callback, callback_data);
 +}
 +
 +static void
 +shell_sidebar_class_init (EShellSidebarClass *class)
 +{
 +	GObjectClass *object_class;
 +	GtkWidgetClass *widget_class;
 +	GtkContainerClass *container_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (EShellSidebarPrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->set_property = shell_sidebar_set_property;
 +	object_class->get_property = shell_sidebar_get_property;
 +	object_class->dispose = shell_sidebar_dispose;
 +	object_class->finalize = shell_sidebar_finalize;
 +	object_class->constructed = shell_sidebar_constructed;
 +
 +	widget_class = GTK_WIDGET_CLASS (class);
 +	widget_class->size_request = shell_sidebar_size_request;
 +	widget_class->size_allocate = shell_sidebar_size_allocate;
 +
 +	container_class = GTK_CONTAINER_CLASS (class);
 +	container_class->remove = shell_sidebar_remove;
 +	container_class->forall = shell_sidebar_forall;
 +
 +	/**
 +	 * EShellSidebar:icon-name
 +	 *
 +	 * The named icon is displayed at the top of the sidebar.
 +	 */
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_ICON_NAME,
 +		g_param_spec_string (
 +			"icon-name",
 +			NULL,
 +			NULL,
 +			NULL,
 +			G_PARAM_READWRITE));
 +
 +	/**
 +	 * EShellSidebar:primary-text
 +	 *
 +	 * The primary text is displayed in bold at the top of the sidebar.
 +	 **/
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_PRIMARY_TEXT,
 +		g_param_spec_string (
 +			"primary-text",
 +			NULL,
 +			NULL,
 +			NULL,
 +			G_PARAM_READWRITE));
 +
 +	/**
 +	 * EShellSidebar:secondary-text
 +	 *
 +	 * The secondary text is displayed in a smaller font at the top of
 +	 * the sidebar.
 +	 **/
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_SECONDARY_TEXT,
 +		g_param_spec_string (
 +			"secondary-text",
 +			NULL,
 +			NULL,
 +			NULL,
 +			G_PARAM_READWRITE));
 +
 +	/**
 +	 * EShellSidebar:shell-view
 +	 *
 +	 * The #EShellView to which the sidebar widget belongs.
 +	 **/
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_SHELL_VIEW,
 +		g_param_spec_object (
 +			"shell-view",
 +			NULL,
 +			NULL,
 +			E_TYPE_SHELL_VIEW,
 +			G_PARAM_READWRITE |
 +			G_PARAM_CONSTRUCT_ONLY));
 +}
 +
 +static void
 +shell_sidebar_init (EShellSidebar *shell_sidebar)
 +{
 +	GtkStyle *style;
 +	GtkWidget *widget;
 +	const GdkColor *color;
 +
 +	shell_sidebar->priv = E_SHELL_SIDEBAR_GET_PRIVATE (shell_sidebar);
 +
 +	GTK_WIDGET_SET_FLAGS (shell_sidebar, GTK_NO_WINDOW);
 +
 +	widget = gtk_event_box_new ();
 +	style = gtk_widget_get_style (widget);
 +	color = &style->bg[GTK_STATE_ACTIVE];
 +	gtk_widget_modify_bg (widget, GTK_STATE_NORMAL, color);
 +	gtk_widget_set_parent (widget, GTK_WIDGET (shell_sidebar));
 +	shell_sidebar->priv->event_box = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	/* Finish initialization once we have a shell view. */
 +}
 +
 +GType
 +e_shell_sidebar_get_type (void)
 +{
 +	static GType type = 0;
 +
 +	if (G_UNLIKELY (type == 0)) {
 +		static const GTypeInfo type_info = {
 +			sizeof (EShellSidebarClass),
 +			(GBaseInitFunc) NULL,
 +			(GBaseFinalizeFunc) NULL,
 +			(GClassInitFunc) shell_sidebar_class_init,
 +			(GClassFinalizeFunc) NULL,
 +			NULL,  /* class_data */
 +			sizeof (EShellSidebar),
 +			0,     /* n_preallocs */
 +			(GInstanceInitFunc) shell_sidebar_init,
 +			NULL   /* value_table */
 +		};
 +
 +		type = g_type_register_static (
 +			GTK_TYPE_BIN, "EShellSidebar", &type_info, 0);
 +	}
 +
 +	return type;
 +}
 +
 +/**
 + * e_shell_sidebar_new:
 + * @shell_view: an #EShellView
 + *
 + * Creates a new #EShellSidebar instance belonging to @shell_view.
 + *
 + * Returns: a new #EShellSidebar instance
 + **/
 +GtkWidget *
 +e_shell_sidebar_new (EShellView *shell_view)
 +{
 +	g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
 +
 +	return g_object_new (
 +		E_TYPE_SHELL_SIDEBAR,
 +		"shell-view", shell_view, NULL);
 +}
 +
 +/**
 + * e_shell_sidebar_check_state:
 + * @shell_sidebar: an #EShellSidebar
 + *
 + * #EShellSidebar subclasses should implement the
 + * <structfield>check_state</structfield> method in #EShellSidebarClass
 + * to return a set of flags describing the current sidebar selection.
 + * Subclasses are responsible for defining their own flags.  This is
 + * primarily used to assist shell views with updating actions (see
 + * e_shell_view_update_actions()).
 + *
 + * Returns: a set of flags describing the current @shell_sidebar selection
 + **/
 +guint32
 +e_shell_sidebar_check_state (EShellSidebar *shell_sidebar)
 +{
 +	EShellSidebarClass *shell_sidebar_class;
 +
 +	g_return_val_if_fail (E_IS_SHELL_SIDEBAR (shell_sidebar), 0);
 +
 +	shell_sidebar_class = E_SHELL_SIDEBAR_GET_CLASS (shell_sidebar);
 +	g_return_val_if_fail (shell_sidebar_class->check_state != NULL, 0);
 +
 +	return shell_sidebar_class->check_state (shell_sidebar);
 +}
 +
 +/**
 + * e_shell_sidebar_get_shell_view:
 + * @shell_sidebar: an #EShellSidebar
 + *
 + * Returns the #EShellView that was passed to e_shell_sidebar_new().
 + *
 + * Returns: the #EShellView to which @shell_sidebar belongs
 + **/
 +EShellView *
 +e_shell_sidebar_get_shell_view (EShellSidebar *shell_sidebar)
 +{
 +	g_return_val_if_fail (E_IS_SHELL_SIDEBAR (shell_sidebar), NULL);
 +
 +	return E_SHELL_VIEW (shell_sidebar->priv->shell_view);
 +}
 +
 +/**
 + * e_shell_sidebar_get_icon_name:
 + * @shell_sidebar: an #EShellSidebar
 + *
 + * Returns the icon name displayed at the top of the sidebar.
 + *
 + * Returns: the icon name for @shell_sidebar
 + **/
 +const gchar *
 +e_shell_sidebar_get_icon_name (EShellSidebar *shell_sidebar)
 +{
 +	GtkImage *image;
 +	const gchar *icon_name;
 +
 +	g_return_val_if_fail (E_IS_SHELL_SIDEBAR (shell_sidebar), NULL);
 +
 +	image = GTK_IMAGE (shell_sidebar->priv->image);
 +	gtk_image_get_icon_name (image, &icon_name, NULL);
 +
 +	return icon_name;
 +}
 +
 +/**
 + * e_shell_sidebar_set_icon_name:
 + *
 + * Sets the icon name displayed at the top of the sidebar.
 + **/
 +void
 +e_shell_sidebar_set_icon_name (EShellSidebar *shell_sidebar,
 +                               const gchar *icon_name)
 +{
 +	GtkImage *image;
 +
 +	g_return_if_fail (E_IS_SHELL_SIDEBAR (shell_sidebar));
 +
 +	image = GTK_IMAGE (shell_sidebar->priv->image);
 +	gtk_image_set_from_icon_name (image, icon_name, GTK_ICON_SIZE_MENU);
 +
 +	g_object_notify (G_OBJECT (shell_sidebar), "icon-name");
 +}
 +
 +/**
 + * e_shell_sidebar_get_primary_text:
 + * @shell_sidebar: an #EShellSidebar
 + *
 + * Returns the primary text for @shell_sidebar.
 + *
 + * The primary text is displayed in bold at the top of the sidebar.  It
 + * defaults to the shell view's label (as seen on the switcher button),
 + * but typically shows the name of the selected item in the sidebar.
 + *
 + * Returns: the primary text for @shell_sidebar
 + **/
 +const gchar *
 +e_shell_sidebar_get_primary_text (EShellSidebar *shell_sidebar)
 +{
 +	g_return_val_if_fail (E_IS_SHELL_SIDEBAR (shell_sidebar), NULL);
 +
 +	return shell_sidebar->priv->primary_text;
 +}
 +
 +/**
 + * e_shell_sidebar_set_primary_text:
 + * @shell_sidebar: an #EShellSidebar
 + * @primary_text: text to be displayed in a bold font
 + *
 + * Sets the primary text for @shell_sidebar.
 + *
 + * The primary text is displayed in bold at the top of the sidebar.  It
 + * defaults to the shell view's label (as seen on the switcher button),
 + * but typically shows the name of the selected item in the sidebar.
 + **/
 +void
 +e_shell_sidebar_set_primary_text (EShellSidebar *shell_sidebar,
 +                                  const gchar *primary_text)
 +{
 +	GtkLabel *label;
 +	gchar *markup;
 +
 +	g_return_if_fail (E_IS_SHELL_SIDEBAR (shell_sidebar));
 +
 +	g_free (shell_sidebar->priv->primary_text);
 +	shell_sidebar->priv->primary_text = g_strdup (primary_text);
 +
 +	if (primary_text == NULL)
 +		primary_text = "";
 +
 +	label = GTK_LABEL (shell_sidebar->priv->primary_label);
 +	markup = g_markup_printf_escaped ("<b>%s</b>", primary_text);
 +	gtk_label_set_markup (label, markup);
 +	g_free (markup);
 +
 +	gtk_widget_queue_resize (GTK_WIDGET (shell_sidebar));
 +	g_object_notify (G_OBJECT (shell_sidebar), "primary-text");
 +}
 +
 +/**
 + * e_shell_sidebar_get_secondary_text:
 + * @shell_sidebar: an #EShellSidebar
 + *
 + * Returns the secondary text for @shell_sidebar.
 + *
 + * The secondary text is displayed in a smaller font at the top of the
 + * sidebar.  It typically shows information about the contents of the
 + * selected sidebar item, such as total number of items, number of
 + * selected items, etc.
 + *
 + * Returns: the secondary text for @shell_sidebar
-  **/ 
++ **/
 +const gchar *
 +e_shell_sidebar_get_secondary_text (EShellSidebar *shell_sidebar)
 +{
 +	g_return_val_if_fail (E_IS_SHELL_SIDEBAR (shell_sidebar), NULL);
 +
 +	return shell_sidebar->priv->secondary_text;
 +}
 +
 +/**
 + * e_shell_sidebar_set_secondary_text:
 + * @shell_sidebar: an #EShellSidebar
 + * @secondary_text: text to be displayed in a smaller font
 + *
 + * Sets the secondary text for @shell_sidebar.
 + *
 + * The secondary text is displayed in a smaller font at the top of the
 + * sidebar.  It typically shows information about the contents of the
 + * selected sidebar item, such as total number of items, number of
 + * selected items, etc.
 + **/
 +void
 +e_shell_sidebar_set_secondary_text (EShellSidebar *shell_sidebar,
 +                                    const gchar *secondary_text)
 +{
 +	GtkLabel *label;
 +	gchar *markup;
 +
 +	g_return_if_fail (E_IS_SHELL_SIDEBAR (shell_sidebar));
 +
 +	g_free (shell_sidebar->priv->secondary_text);
 +	shell_sidebar->priv->secondary_text = g_strdup (secondary_text);
 +
 +	if (secondary_text == NULL)
 +		secondary_text = "";
 +
 +	label = GTK_LABEL (shell_sidebar->priv->secondary_label);
 +	markup = g_markup_printf_escaped ("<small>%s</small>", secondary_text);
 +	gtk_label_set_markup (label, markup);
 +	g_free (markup);
 +
 +	gtk_widget_queue_resize (GTK_WIDGET (shell_sidebar));
 +	g_object_notify (G_OBJECT (shell_sidebar), "secondary-text");
 +}
diff --cc shell/e-shell-sidebar.h
index 27966e5,0000000..5999aa9
mode 100644,000000..100644
--- a/shell/e-shell-sidebar.h
+++ b/shell/e-shell-sidebar.h
@@@ -1,97 -1,0 +1,97 @@@
 +/*
 + * e-shell-sidebar.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +/**
 + * SECTION: e-shell-sidebar
 + * @short_description: the left side of the main window
 + * @include: shell/e-shell-sidebar.h
 + **/
 +
 +#ifndef E_SHELL_SIDEBAR_H
 +#define E_SHELL_SIDEBAR_H
 +
 +#include <shell/e-shell-common.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_SHELL_SIDEBAR \
 +	(e_shell_sidebar_get_type ())
 +#define E_SHELL_SIDEBAR(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_SHELL_SIDEBAR, EShellSidebar))
 +#define E_SHELL_SIDEBAR_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_SHELL_SIDEBAR, EShellSidebarClass))
 +#define E_IS_SHELL_SIDEBAR(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_SHELL_SIDEBAR))
 +#define E_IS_SHELL_SIDEBAR_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((obj), E_TYPE_SHELL_SIDEBAR))
 +#define E_SHELL_SIDEBAR_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_SHELL_SIDEBAR, EShellSidebarClass))
 +
 +G_BEGIN_DECLS
 +
 +/* Avoid including <e-shell-view.h>, because it includes us! */
 +struct _EShellView;
 +
 +typedef struct _EShellSidebar EShellSidebar;
 +typedef struct _EShellSidebarClass EShellSidebarClass;
 +typedef struct _EShellSidebarPrivate EShellSidebarPrivate;
 +
 +/**
 + * EShellSidebar:
 + *
 + * Contains only private data that should be read and manipulated using the
 + * functions below.
 + **/
 +struct _EShellSidebar {
 +	GtkBin parent;
 +	EShellSidebarPrivate *priv;
 +};
 +
 +struct _EShellSidebarClass {
 +	GtkBinClass parent_class;
 +
 +	guint32		(*check_state)		(EShellSidebar *shell_sidebar);
 +};
 +
 +GType		e_shell_sidebar_get_type	(void);
 +GtkWidget *	e_shell_sidebar_new		(struct _EShellView *shell_view);
 +guint32		e_shell_sidebar_check_state	(EShellSidebar *shell_sidebar);
 +struct _EShellView *
 +		e_shell_sidebar_get_shell_view	(EShellSidebar *shell_sidebar);
 +const gchar *	e_shell_sidebar_get_icon_name	(EShellSidebar *shell_sidebar);
 +void		e_shell_sidebar_set_icon_name	(EShellSidebar *shell_sidebar,
 +						 const gchar *icon_name);
 +const gchar *	e_shell_sidebar_get_primary_text(EShellSidebar *shell_sidebar);
 +void		e_shell_sidebar_set_primary_text(EShellSidebar *shell_sidebar,
 +						 const gchar *primary_text);
 +const gchar *	e_shell_sidebar_get_secondary_text
 +						(EShellSidebar *shell_sidebar);
 +void		e_shell_sidebar_set_secondary_text
 +						(EShellSidebar *shell_sidebar,
 +						 const gchar *secondary_text);
 +
 +G_END_DECLS
 +
 +#endif /* E_SHELL_SIDEBAR_H */
diff --cc shell/e-shell-switcher.c
index 2980bd9,0000000..2944aac
mode 100644,000000..100644
--- a/shell/e-shell-switcher.c
+++ b/shell/e-shell-switcher.c
@@@ -1,700 -1,0 +1,700 @@@
 +/*
 + * e-shell-switcher.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-shell-switcher.h"
 +
 +#include <glib/gi18n.h>
 +
 +#define E_SHELL_SWITCHER_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_SHELL_SWITCHER, EShellSwitcherPrivate))
 +
 +#define H_PADDING 6
 +#define V_PADDING 6
 +
 +struct _EShellSwitcherPrivate {
 +	GList *proxies;
 +	gboolean style_set;
 +	GtkToolbarStyle style;
 +	GtkSettings *settings;
 +	gulong settings_handler_id;
 +	gboolean toolbar_visible;
 +};
 +
 +enum {
 +	PROP_0,
 +	PROP_TOOLBAR_STYLE,
 +	PROP_TOOLBAR_VISIBLE
 +};
 +
 +enum {
 +	STYLE_CHANGED,
 +	LAST_SIGNAL
 +};
 +
 +static gpointer parent_class;
 +static guint signals[LAST_SIGNAL];
 +
 +static gint
 +shell_switcher_layout_actions (EShellSwitcher *switcher)
 +{
 +	GtkAllocation *allocation;
 +	int num_btns = g_list_length (switcher->priv->proxies), btns_per_row;
 +	GList **rows, *p;
 +	gboolean icons_only;
 +	gint row_number;
 +	gint max_width = 0;
 +	gint max_height = 0;
 +	gint row_last;
 +	gint x, y;
 +	gint i;
 +
 +	allocation = &GTK_WIDGET (switcher)->allocation;
 +	y = allocation->y + allocation->height;
 +
 +	if (num_btns == 0)
 +		return allocation->height;
 +
 +	icons_only = (switcher->priv->style == GTK_TOOLBAR_ICONS);
 +
 +	/* Figure out the max width and height. */
 +	for (p = switcher->priv->proxies; p != NULL; p = p->next) {
 +		GtkWidget *widget = p->data;
 +		GtkRequisition requisition;
 +
 +		gtk_widget_size_request (widget, &requisition);
 +		max_height = MAX (max_height, requisition.height);
 +		max_width = MAX (max_width, requisition.width);
 +	}
 +
 +	/* Figure out how many rows and columns we'll use. */
 +	btns_per_row = MAX (1, allocation->width / (max_width + H_PADDING));
 +	if (!icons_only) {
 +		/* If using text buttons, we want to try to have a
 +		 * completely filled-in grid, but if we can't, we want
 +		 * the odd row to have just a single button. */
 +		while (num_btns % btns_per_row > 1)
 +			btns_per_row--;
 +	}
 +
 +	/* Assign buttons to rows. */
 +	rows = g_new0 (GList *, num_btns / btns_per_row + 1);
 +
 +	if (!icons_only && num_btns % btns_per_row != 0) {
 +		rows[0] = g_list_append (rows[0], switcher->priv->proxies->data);
 +
 +		p = switcher->priv->proxies->next;
 +		row_number = p ? 1 : 0;
 +	} else {
 +		p = switcher->priv->proxies;
 +		row_number = 0;
 +	}
 +
 +	for (; p != NULL; p = p->next) {
 +		GtkWidget *widget = p->data;
 +
 +		if (g_list_length (rows[row_number]) == btns_per_row)
 +			row_number++;
 +
 +		rows[row_number] = g_list_append (rows[row_number], widget);
 +	}
 +
 +	row_last = row_number;
 +
 +	/* Layout the buttons. */
 +	for (i = row_last; i >= 0; i--) {
 +		int len, extra_width;
 +
 +		x = H_PADDING + allocation->x;
 +		y -= max_height;
 +		len = g_list_length (rows[i]);
 +		if (!icons_only)
 +			extra_width = (allocation->width - (len * max_width ) - (len * H_PADDING)) / len;
 +		else
 +			extra_width = 0;
 +		for (p = rows [i]; p != NULL; p = p->next) {
 +			GtkAllocation child_allocation;
 +
 +			child_allocation.x = x;
 +			child_allocation.y = y;
 +			child_allocation.width = max_width + extra_width;
 +			child_allocation.height = max_height;
 +
 +			gtk_widget_size_allocate (GTK_WIDGET (p->data), &child_allocation);
 +
 +			x += child_allocation.width + H_PADDING;
 +		}
 +
 +		y -= V_PADDING;
 +	}
 +
 +	for (i = 0; i <= row_last; i ++)
 +		g_list_free (rows [i]);
 +	g_free (rows);
 +
 +	return y - allocation->y;
 +}
 +
 +static void
 +shell_switcher_toolbar_style_changed_cb (EShellSwitcher *switcher)
 +{
 +	if (!switcher->priv->style_set) {
 +		switcher->priv->style_set = TRUE;
 +		e_shell_switcher_unset_style (switcher);
 +	}
 +}
 +
 +static void
 +shell_switcher_set_property (GObject *object,
 +                             guint property_id,
 +                             const GValue *value,
 +                             GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_TOOLBAR_STYLE:
 +			e_shell_switcher_set_style (
 +				E_SHELL_SWITCHER (object),
 +				g_value_get_enum (value));
 +			return;
 +
 +		case PROP_TOOLBAR_VISIBLE:
 +			e_shell_switcher_set_visible (
 +				E_SHELL_SWITCHER (object),
 +				g_value_get_boolean (value));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +shell_switcher_get_property (GObject *object,
 +                             guint property_id,
 +                             GValue *value,
 +                             GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_TOOLBAR_STYLE:
 +			g_value_set_enum (
 +				value, e_shell_switcher_get_style (
 +				E_SHELL_SWITCHER (object)));
 +			return;
 +
 +		case PROP_TOOLBAR_VISIBLE:
 +			g_value_set_boolean (
 +				value, e_shell_switcher_get_visible (
 +				E_SHELL_SWITCHER (object)));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +shell_switcher_dispose (GObject *object)
 +{
 +	EShellSwitcherPrivate *priv;
 +
 +	priv = E_SHELL_SWITCHER_GET_PRIVATE (object);
 +
 +	while (priv->proxies != NULL) {
 +		GtkWidget *widget = priv->proxies->data;
 +		gtk_container_remove (GTK_CONTAINER (object), widget);
 +	}
 +
 +	/* Chain up to parent's dispose() method. */
 +	G_OBJECT_CLASS (parent_class)->dispose (object);
 +}
 +
 +static void
 +shell_switcher_size_request (GtkWidget *widget,
 +                             GtkRequisition *requisition)
 +{
 +	EShellSwitcherPrivate *priv;
 +	GtkWidget *child;
 +	GList *iter;
 +
 +	priv = E_SHELL_SWITCHER_GET_PRIVATE (widget);
 +
 +	requisition->width = 0;
 +	requisition->height = 0;
 +
 +	child = gtk_bin_get_child (GTK_BIN (widget));
 +	if (child != NULL)
 +		gtk_widget_size_request (child, requisition);
 +
 +	if (!priv->toolbar_visible)
 +		return;
 +
 +	for (iter = priv->proxies; iter != NULL; iter = iter->next) {
 +		GtkWidget *widget = iter->data;
 +		GtkRequisition child_requisition;
 +
 +		gtk_widget_size_request (widget, &child_requisition);
 +
 +		child_requisition.width += H_PADDING;
 +		child_requisition.height += V_PADDING;
 +
 +		requisition->width = MAX (
 +			requisition->width, child_requisition.width);
 +		requisition->height += child_requisition.height;
 +	}
 +}
 +
 +static void
 +shell_switcher_size_allocate (GtkWidget *widget,
 +                              GtkAllocation *allocation)
 +{
 +	EShellSwitcher *switcher;
 +	GtkAllocation child_allocation;
 +	GtkWidget *child;
 +	gint height;
 +
 +	switcher = E_SHELL_SWITCHER (widget);
 +
 +	widget->allocation = *allocation;
 +
 +	if (switcher->priv->toolbar_visible)
 +		height = shell_switcher_layout_actions (switcher);
 +	else
 +		height = allocation->height;
 +
 +	child_allocation.x = allocation->x;
 +	child_allocation.y = allocation->y;
 +	child_allocation.width = allocation->width;
 +	child_allocation.height = height;
 +
 +	child = gtk_bin_get_child (GTK_BIN (widget));
 +	if (child != NULL)
 +		gtk_widget_size_allocate (child, &child_allocation);
 +}
 +
 +static void
 +shell_switcher_screen_changed (GtkWidget *widget,
 +                               GdkScreen *previous_screen)
 +{
 +	EShellSwitcherPrivate *priv;
 +	GtkSettings *settings;
 +
 +	priv = E_SHELL_SWITCHER_GET_PRIVATE (widget);
 +
 +	if (gtk_widget_has_screen (widget))
 +		settings = gtk_widget_get_settings (widget);
 +	else
 +		settings = NULL;
 +
 +	if (settings == priv->settings)
 +		return;
 +
 +	if (priv->settings != NULL) {
 +		g_signal_handler_disconnect (
 +			priv->settings, priv->settings_handler_id);
 +		g_object_unref (priv->settings);
 +	}
 +
 +	if (settings != NULL) {
 +		priv->settings = g_object_ref (settings);
 +		priv->settings_handler_id = g_signal_connect_swapped (
 +			settings, "notify::gtk-toolbar-style",
 +			G_CALLBACK (shell_switcher_toolbar_style_changed_cb),
 +			widget);
 +	} else
 +		priv->settings = NULL;
 +
 +	shell_switcher_toolbar_style_changed_cb (E_SHELL_SWITCHER (widget));
 +}
 +
 +static void
 +shell_switcher_remove (GtkContainer *container,
 +                       GtkWidget *widget)
 +{
 +	EShellSwitcherPrivate *priv;
 +	GList *link;
 +
 +	priv = E_SHELL_SWITCHER_GET_PRIVATE (container);
 +
 +	/* Look in the internal widgets first. */
 +
 +	link = g_list_find (priv->proxies, widget);
 +	if (link != NULL) {
 +		GtkWidget *widget = link->data;
 +
 +		gtk_widget_unparent (widget);
 +		priv->proxies = g_list_delete_link (priv->proxies, link);
 +		gtk_widget_queue_resize (GTK_WIDGET (container));
 +		return;
 +	}
 +
 +	/* Chain up to parent's remove() method. */
 +	GTK_CONTAINER_CLASS (parent_class)->remove (container, widget);
 +}
 +
 +static void
 +shell_switcher_forall (GtkContainer *container,
 +                       gboolean include_internals,
 +                       GtkCallback callback,
 +                       gpointer callback_data)
 +{
 +	EShellSwitcherPrivate *priv;
 +
 +	priv = E_SHELL_SWITCHER_GET_PRIVATE (container);
 +
 +	if (include_internals)
 +		g_list_foreach (
 +			priv->proxies, (GFunc) callback, callback_data);
 +
 +	/* Chain up to parent's forall() method. */
 +	GTK_CONTAINER_CLASS (parent_class)->forall (
 +		container, include_internals, callback, callback_data);
 +}
 +
 +static void
 +shell_switcher_style_changed (EShellSwitcher *switcher,
 +                              GtkToolbarStyle style)
 +{
 +	if (switcher->priv->style == style)
 +		return;
 +
 +	switcher->priv->style = style;
 +
 +	g_list_foreach (
 +		switcher->priv->proxies,
 +		(GFunc) gtk_tool_item_toolbar_reconfigured, NULL);
 +
 +	gtk_widget_queue_resize (GTK_WIDGET (switcher));
 +	g_object_notify (G_OBJECT (switcher), "toolbar-style");
 +}
 +
 +static GtkIconSize
 +shell_switcher_get_icon_size (GtkToolShell *shell)
 +{
 +	return GTK_ICON_SIZE_LARGE_TOOLBAR;
 +}
 +
 +static GtkOrientation
 +shell_switcher_get_orientation (GtkToolShell *shell)
 +{
 +	return GTK_ORIENTATION_HORIZONTAL;
 +}
 +
 +static GtkToolbarStyle
 +shell_switcher_get_style (GtkToolShell *shell)
 +{
 +	return e_shell_switcher_get_style (E_SHELL_SWITCHER (shell));
 +}
 +
 +static GtkReliefStyle
 +shell_switcher_get_relief_style (GtkToolShell *shell)
 +{
 +	return GTK_RELIEF_NORMAL;
 +}
 +
 +static void
 +shell_switcher_class_init (EShellSwitcherClass *class)
 +{
 +	GObjectClass *object_class;
 +	GtkWidgetClass *widget_class;
 +	GtkContainerClass *container_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (EShellSwitcherPrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->set_property = shell_switcher_set_property;
 +	object_class->get_property = shell_switcher_get_property;
 +	object_class->dispose = shell_switcher_dispose;
 +
 +	widget_class = GTK_WIDGET_CLASS (class);
 +	widget_class->size_request = shell_switcher_size_request;
 +	widget_class->size_allocate = shell_switcher_size_allocate;
 +	widget_class->screen_changed = shell_switcher_screen_changed;
 +
 +	container_class = GTK_CONTAINER_CLASS (class);
 +	container_class->remove = shell_switcher_remove;
 +	container_class->forall = shell_switcher_forall;
 +
 +	class->style_changed = shell_switcher_style_changed;
 +
 +	/**
 +	 * EShellSwitcher:toolbar-style
 +	 *
 +	 * The switcher's toolbar style.
 +	 **/
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_TOOLBAR_STYLE,
 +		g_param_spec_enum (
 +			"toolbar-style",
 +			_("Toolbar Style"),
 +			_("The switcher's toolbar style"),
 +			GTK_TYPE_TOOLBAR_STYLE,
 +			E_SHELL_SWITCHER_DEFAULT_TOOLBAR_STYLE,
 +			G_PARAM_READWRITE |
 +			G_PARAM_CONSTRUCT));
 +
 +	/**
 +	 * EShellSwitcher:toolbar-visible
 +	 *
 +	 * Whether the switcher is visible.
 +	 **/
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_TOOLBAR_VISIBLE,
 +		g_param_spec_boolean (
 +			"toolbar-visible",
 +			_("Toolbar Visible"),
 +			_("Whether the switcher is visible"),
 +			TRUE,
 +			G_PARAM_READWRITE |
 +			G_PARAM_CONSTRUCT));
 +
 +	/**
 +	 * EShellSwitcher::style-changed
 +	 * @switcher: the #EShellSwitcher which emitted the signal
 +	 * @style: the new #GtkToolbarStyle of the switcher
 +	 *
 +	 * Emitted when the style of the switcher changes.
 +	 **/
 +	signals[STYLE_CHANGED] = g_signal_new (
 +		"style-changed",
 +		G_OBJECT_CLASS_TYPE (class),
 +		G_SIGNAL_RUN_FIRST,
 +		G_STRUCT_OFFSET (EShellSwitcherClass, style_changed),
 +		NULL, NULL,
 +		g_cclosure_marshal_VOID__ENUM,
 +		G_TYPE_NONE, 1,
 +		GTK_TYPE_TOOLBAR_STYLE);
 +}
 +
 +static void
 +shell_switcher_init (EShellSwitcher *switcher)
 +{
 +	switcher->priv = E_SHELL_SWITCHER_GET_PRIVATE (switcher);
 +
 +	GTK_WIDGET_SET_FLAGS (switcher, GTK_NO_WINDOW);
 +}
 +
 +static void
 +shell_switcher_tool_shell_iface_init (GtkToolShellIface *iface)
 +{
 +	iface->get_icon_size = shell_switcher_get_icon_size;
 +	iface->get_orientation = shell_switcher_get_orientation;
 +	iface->get_style = shell_switcher_get_style;
 +	iface->get_relief_style = shell_switcher_get_relief_style;
 +}
 +
 +GType
 +e_shell_switcher_get_type (void)
 +{
 +	static GType type = 0;
 +
 +	if (G_UNLIKELY (type == 0)) {
 +		static const GTypeInfo type_info = {
 +			sizeof (EShellSwitcherClass),
 +			(GBaseInitFunc) NULL,
 +			(GBaseFinalizeFunc) NULL,
 +			(GClassInitFunc) shell_switcher_class_init,
 +			(GClassFinalizeFunc) NULL,
 +			NULL,  /* class_data */
 +			sizeof (EShellSwitcher),
 +			0,     /* n_preallocs */
 +			(GInstanceInitFunc) shell_switcher_init,
 +			NULL   /* value_table */
 +		};
 +
 +		static const GInterfaceInfo tool_shell_info = {
 +			(GInterfaceInitFunc) shell_switcher_tool_shell_iface_init,
 +			(GInterfaceFinalizeFunc) NULL,
 +			NULL   /* interface_data */
 +		};
 +
 +		type = g_type_register_static (
 +			GTK_TYPE_BIN, "EShellSwitcher", &type_info, 0);
 +
 +		g_type_add_interface_static (
 +			type, GTK_TYPE_TOOL_SHELL, &tool_shell_info);
 +	}
 +
 +	return type;
 +}
 +
 +/**
 + * e_shell_switcher_new:
 + *
 + * Creates a new #EShellSwitcher instance.
 + *
 + * Returns: a new #EShellSwitcher instance
 + **/
 +GtkWidget *
 +e_shell_switcher_new (void)
 +{
 +	return g_object_new (E_TYPE_SHELL_SWITCHER, NULL);
 +}
 +
 +/**
 + * e_shell_switcher_add_action:
 + * @switcher: an #EShellSwitcher
 + * @action: a #GtkAction
 + *
 + * Adds a button to @switcher that proxies for @action.  Switcher buttons
 + * appear in the order they were added.
 + *
 + * #EShellWindow adds switcher actions in the order given by the
 + * <structfield>sort_order</structfield> field in #EShellBackendClass.
 + **/
 +void
 +e_shell_switcher_add_action (EShellSwitcher *switcher,
 +                             GtkAction *action)
 +{
 +	GtkWidget *widget;
 +
 +	g_return_if_fail (E_IS_SHELL_SWITCHER (switcher));
 +	g_return_if_fail (GTK_IS_ACTION (action));
 +
 +	g_object_ref (action);
 +	widget = gtk_action_create_tool_item (action);
 +	gtk_tool_item_set_is_important (GTK_TOOL_ITEM (widget), TRUE);
 +	gtk_widget_show (widget);
 +
 +	switcher->priv->proxies = g_list_append (
 +		switcher->priv->proxies, widget);
 +
 +	gtk_widget_set_parent (widget, GTK_WIDGET (switcher));
 +	gtk_widget_queue_resize (GTK_WIDGET (switcher));
 +}
 +
 +/**
 + * e_shell_switcher_get_style:
 + * @switcher: an #EShellSwitcher
 + *
 + * Returns whether @switcher has text, icons or both.
 + *
 + * Returns: the current style of @shell
 + **/
 +GtkToolbarStyle
 +e_shell_switcher_get_style (EShellSwitcher *switcher)
 +{
 +	g_return_val_if_fail (
 +		E_IS_SHELL_SWITCHER (switcher),
 +		E_SHELL_SWITCHER_DEFAULT_TOOLBAR_STYLE);
 +
 +	return switcher->priv->style;
 +}
 +
 +/**
 + * e_shell_switcher_set_style:
 + * @switcher: an #EShellSwitcher
 + * @style: the new style for @switcher
 + *
 + * Alters the view of @switcher to display either icons only, text only,
 + * or both.
 + **/
 +void
 +e_shell_switcher_set_style (EShellSwitcher *switcher,
 +                            GtkToolbarStyle style)
 +{
 +	g_return_if_fail (E_IS_SHELL_SWITCHER (switcher));
 +
 +	switcher->priv->style_set = TRUE;
 +	g_signal_emit (switcher, signals[STYLE_CHANGED], 0, style);
 +}
 +
 +/**
 + * e_shell_switcher_unset_style:
 + * @switcher: an #EShellSwitcher
 + *
 + * Unsets a switcher style set with e_shell_switcher_set_style(), so
 + * that user preferences will be used to determine the switcher style.
 + **/
 +void
 +e_shell_switcher_unset_style (EShellSwitcher *switcher)
 +{
 +	GtkSettings *settings;
 +	GtkToolbarStyle style;
 +
 +	g_return_if_fail (E_IS_SHELL_SWITCHER (switcher));
 +
 +	if (!switcher->priv->style_set)
 +		return;
 +
 +	settings = switcher->priv->settings;
 +	if (settings != NULL)
 +		g_object_get (settings, "gtk-toolbar-style", &style, NULL);
 +	else
 +		style = E_SHELL_SWITCHER_DEFAULT_TOOLBAR_STYLE;
 +
 +	if (style == GTK_TOOLBAR_BOTH)
 +		style = GTK_TOOLBAR_BOTH_HORIZ;
 +
 +	if (style != switcher->priv->style)
 +		g_signal_emit (switcher, signals[STYLE_CHANGED], 0, style);
 +
 +	switcher->priv->style_set = FALSE;
 +}
 +
 +/**
 + * e_shell_switcher_get_visible:
 + * @switcher: an #EShellSwitcher
 + *
 + * Returns %TRUE if the switcher buttons are visible.
 + *
 + * Note that switcher button visibility is different than
 + * @switcher<!-- -->'s GTK_VISIBLE flag, since #EShellSwitcher
 + * is actually a container widget for #EShellSidebar.
 + *
 + * Returns: %TRUE if the switcher buttons are visible
 + **/
 +gboolean
 +e_shell_switcher_get_visible (EShellSwitcher *switcher)
 +{
 +	g_return_val_if_fail (E_IS_SHELL_SWITCHER (switcher), FALSE);
 +
 +	return switcher->priv->toolbar_visible;
 +}
 +
 +/**
 + * e_shell_switcher_set_visible:
 + * @switcher: an #EShellSwitcher
 + * @visible: whether the switcher buttons should be visible
 + *
 + * Sets the switcher button visiblity to @visible.
 + *
 + * Note that switcher button visibility is different than
 + * @switcher<!-- -->'s GTK_VISIBLE flag, since #EShellSwitcher
 + * is actually a container widget for #EShellSidebar.
 + **/
 +void
 +e_shell_switcher_set_visible (EShellSwitcher *switcher,
 +                              gboolean visible)
 +{
 +	GList *iter;
 +
 +	g_return_if_fail (E_IS_SHELL_SWITCHER (switcher));
 +
 +	switcher->priv->toolbar_visible = visible;
 +
 +	for (iter = switcher->priv->proxies; iter != NULL; iter = iter->next)
 +		g_object_set (iter->data, "visible", visible, NULL);
 +
 +	gtk_widget_queue_resize (GTK_WIDGET (switcher));
 +
 +	g_object_notify (G_OBJECT (switcher), "toolbar-visible");
 +}
diff --cc shell/e-shell-switcher.h
index f04cec1,0000000..1cc6445
mode 100644,000000..100644
--- a/shell/e-shell-switcher.h
+++ b/shell/e-shell-switcher.h
@@@ -1,92 -1,0 +1,92 @@@
 +/*
 + * e-shell-switcher.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +/**
 + * SECTION: e-shell-switcher
 + * @short_description: buttons for switching views
 + * @include: shell/e-shell-switcher.h
 + **/
 +
 +#ifndef E_SHELL_SWITCHER_H
 +#define E_SHELL_SWITCHER_H
 +
 +#include <e-shell-common.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_SHELL_SWITCHER \
 +	(e_shell_switcher_get_type ())
 +#define E_SHELL_SWITCHER(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_SHELL_SWITCHER, EShellSwitcher))
 +#define E_SHELL_SWITCHER_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_SHELL_SWITCHER, EShellSwitcherClass))
 +#define E_IS_SHELL_SWITCHER(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_SHELL_SWITCHER))
 +#define E_IS_SHELL_SWITCHER_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((obj), E_TYPE_SHELL_SWITCHER))
 +#define E_SHELL_SWITCHER_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_SHELL_SWITCHER, EShellSwitcherClass))
 +
 +#define E_SHELL_SWITCHER_DEFAULT_TOOLBAR_STYLE		GTK_TOOLBAR_BOTH_HORIZ
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _EShellSwitcher EShellSwitcher;
 +typedef struct _EShellSwitcherClass EShellSwitcherClass;
 +typedef struct _EShellSwitcherPrivate EShellSwitcherPrivate;
 +
 +/**
 + * EShellSwitcher:
 + *
 + * Contains only private data that should be read and manipulated using the
 + * functions below.
 + **/
 +struct _EShellSwitcher {
 +	GtkBin parent;
 +	EShellSwitcherPrivate *priv;
 +};
 +
 +struct _EShellSwitcherClass {
 +	GtkBinClass parent_class;
 +
 +	void		(*style_changed)	(EShellSwitcher *switcher,
 +						 GtkToolbarStyle style);
 +};
 +
 +GType		e_shell_switcher_get_type	(void);
 +GtkWidget *	e_shell_switcher_new		(void);
 +void		e_shell_switcher_add_action	(EShellSwitcher *switcher,
 +						 GtkAction *action);
 +GtkToolbarStyle	e_shell_switcher_get_style	(EShellSwitcher *switcher);
 +void		e_shell_switcher_set_style	(EShellSwitcher *switcher,
 +						 GtkToolbarStyle style);
 +void		e_shell_switcher_unset_style	(EShellSwitcher *switcher);
 +gboolean	e_shell_switcher_get_visible	(EShellSwitcher *switcher);
 +void		e_shell_switcher_set_visible	(EShellSwitcher *switcher,
 +						 gboolean visible);
 +
 +G_END_DECLS
 +
 +#endif /* E_SHELL_SWITCHER_H */
diff --cc shell/e-shell-taskbar.c
index c81f408,0000000..61f27fb
mode 100644,000000..100644
--- a/shell/e-shell-taskbar.c
+++ b/shell/e-shell-taskbar.c
@@@ -1,421 -1,0 +1,421 @@@
 +/*
 + * e-shell-taskbar.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-shell-taskbar.h"
 +
 +#include <e-shell-view.h>
 +
 +#include <widgets/misc/e-activity-proxy.h>
 +
 +#define E_SHELL_TASKBAR_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_SHELL_TASKBAR, EShellTaskbarPrivate))
 +
 +struct _EShellTaskbarPrivate {
 +
 +	gpointer shell_view;  /* weak pointer */
 +
 +	GtkWidget *label;
 +	GtkWidget *hbox;
 +
 +	GHashTable *proxy_table;
 +};
 +
 +enum {
 +	PROP_0,
 +	PROP_MESSAGE,
 +	PROP_SHELL_VIEW
 +};
 +
 +static gpointer parent_class;
 +
 +static void
 +shell_taskbar_activity_remove (EShellTaskbar *shell_taskbar,
 +                               EActivity *activity)
 +{
 +	GtkBox *box;
 +	GtkWidget *proxy;
 +	GHashTable *proxy_table;
 +
 +	box = GTK_BOX (shell_taskbar->priv->hbox);
 +	proxy_table = shell_taskbar->priv->proxy_table;
 +	proxy = g_hash_table_lookup (proxy_table, activity);
 +	g_return_if_fail (proxy != NULL);
 +
 +	g_hash_table_remove (proxy_table, activity);
 +	gtk_container_remove (GTK_CONTAINER (box), proxy);
 +
 +	if (box->children == NULL)
 +		gtk_widget_hide (GTK_WIDGET (box));
 +}
 +
 +static void
 +shell_taskbar_activity_add (EShellTaskbar *shell_taskbar,
 +                            EActivity *activity)
 +{
 +	GtkBox *box;
 +	GtkWidget *proxy;
 +
 +	proxy = e_activity_proxy_new (activity);
 +	box = GTK_BOX (shell_taskbar->priv->hbox);
 +	gtk_box_pack_start (box, proxy, TRUE, TRUE, 0);
 +	gtk_box_reorder_child (box, proxy, 0);
 +	gtk_widget_show (GTK_WIDGET (box));
 +	gtk_widget_show (proxy);
 +
 +	g_hash_table_insert (
 +		shell_taskbar->priv->proxy_table,
 +		g_object_ref (activity), g_object_ref (proxy));
 +
 +	g_signal_connect_swapped (
 +		activity, "cancelled",
 +		G_CALLBACK (shell_taskbar_activity_remove), shell_taskbar);
 +
 +	g_signal_connect_swapped (
 +		activity, "completed",
 +		G_CALLBACK (shell_taskbar_activity_remove), shell_taskbar);
 +}
 +
 +static void
 +shell_taskbar_set_shell_view (EShellTaskbar *shell_taskbar,
 +                              EShellView *shell_view)
 +{
 +	g_return_if_fail (shell_taskbar->priv->shell_view == NULL);
 +
 +	shell_taskbar->priv->shell_view = shell_view;
 +
 +	g_object_add_weak_pointer (
 +		G_OBJECT (shell_view),
 +		&shell_taskbar->priv->shell_view);
 +}
 +
 +static void
 +shell_taskbar_set_property (GObject *object,
 +                            guint property_id,
 +                            const GValue *value,
 +                            GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_MESSAGE:
 +			e_shell_taskbar_set_message (
 +				E_SHELL_TASKBAR (object),
 +				g_value_get_string (value));
 +			return;
 +
 +		case PROP_SHELL_VIEW:
 +			shell_taskbar_set_shell_view (
 +				E_SHELL_TASKBAR (object),
 +				g_value_get_object (value));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +shell_taskbar_get_property (GObject *object,
 +                            guint property_id,
 +                            GValue *value,
 +                            GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_MESSAGE:
 +			g_value_set_string (
 +				value, e_shell_taskbar_get_message (
 +				E_SHELL_TASKBAR (object)));
 +			return;
 +
 +		case PROP_SHELL_VIEW:
 +			g_value_set_object (
 +				value, e_shell_taskbar_get_shell_view (
 +				E_SHELL_TASKBAR (object)));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +shell_taskbar_dispose (GObject *object)
 +{
 +	EShellTaskbarPrivate *priv;
 +
 +	priv = E_SHELL_TASKBAR_GET_PRIVATE (object);
 +
 +	if (priv->shell_view != NULL) {
 +		g_object_remove_weak_pointer (
 +			G_OBJECT (priv->shell_view), &priv->shell_view);
 +		priv->shell_view = NULL;
 +	}
 +
 +	if (priv->label != NULL) {
 +		g_object_unref (priv->label);
 +		priv->label = NULL;
 +	}
 +
 +	if (priv->hbox != NULL) {
 +		g_object_unref (priv->hbox);
 +		priv->hbox = NULL;
 +	}
 +
 +	g_hash_table_remove_all (priv->proxy_table);
 +
 +	/* Chain up to parent's dispose() method. */
 +	G_OBJECT_CLASS (parent_class)->dispose (object);
 +}
 +
 +static void
 +shell_taskbar_finalize (GObject *object)
 +{
 +	EShellTaskbarPrivate *priv;
 +
 +	priv = E_SHELL_TASKBAR_GET_PRIVATE (object);
 +
 +	g_hash_table_destroy (priv->proxy_table);
 +
 +	/* Chain up to parent's finalize() method. */
 +	G_OBJECT_CLASS (parent_class)->finalize (object);
 +}
 +
 +static void
 +shell_taskbar_constructed (GObject *object)
 +{
 +	EShellView *shell_view;
 +	EShellBackend *shell_backend;
 +	EShellTaskbar *shell_taskbar;
 +
 +	shell_taskbar = E_SHELL_TASKBAR (object);
 +	shell_view = e_shell_taskbar_get_shell_view (shell_taskbar);
 +	shell_backend = e_shell_view_get_shell_backend (shell_view);
 +
 +	g_signal_connect_swapped (
 +		shell_backend, "activity-added",
 +		G_CALLBACK (shell_taskbar_activity_add), shell_taskbar);
 +}
 +
 +static void
 +shell_taskbar_class_init (EShellTaskbarClass *class)
 +{
 +	GObjectClass *object_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (EShellTaskbarPrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->set_property = shell_taskbar_set_property;
 +	object_class->get_property = shell_taskbar_get_property;
 +	object_class->dispose = shell_taskbar_dispose;
 +	object_class->finalize = shell_taskbar_finalize;
 +	object_class->constructed = shell_taskbar_constructed;
 +
 +	/**
 +	 * EShellTaskbar:message
 +	 *
 +	 * The message to display in the taskbar.
 +	 **/
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_MESSAGE,
 +		g_param_spec_string (
 +			"message",
 +			NULL,
 +			NULL,
 +			NULL,
 +			G_PARAM_READWRITE |
 +			G_PARAM_CONSTRUCT));
 +
 +	/**
 +	 * EShellTaskbar:shell-view
 +	 *
 +	 * The #EShellView to which the taskbar widget belongs.
 +	 **/
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_SHELL_VIEW,
 +		g_param_spec_object (
 +			"shell-view",
 +			NULL,
 +			NULL,
 +			E_TYPE_SHELL_VIEW,
 +			G_PARAM_READWRITE |
 +			G_PARAM_CONSTRUCT_ONLY));
 +}
 +
 +static void
 +shell_taskbar_init (EShellTaskbar *shell_taskbar)
 +{
 +	GtkWidget *widget;
 +	GHashTable *proxy_table;
 +	gint height;
 +
 +	proxy_table = g_hash_table_new_full (
 +		g_direct_hash, g_direct_equal,
 +		(GDestroyNotify) g_object_unref,
 +		(GDestroyNotify) g_object_unref);
 +
 +	shell_taskbar->priv = E_SHELL_TASKBAR_GET_PRIVATE (shell_taskbar);
 +	shell_taskbar->priv->proxy_table = proxy_table;
 +
 +	gtk_box_set_spacing (GTK_BOX (shell_taskbar), 12);
 +
 +	widget = gtk_label_new (NULL);
 +	gtk_label_set_ellipsize (GTK_LABEL (widget), PANGO_ELLIPSIZE_END);
 +	gtk_box_pack_start (GTK_BOX (shell_taskbar), widget, TRUE, TRUE, 0);
 +	gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
 +	shell_taskbar->priv->label = g_object_ref (widget);
 +	gtk_widget_hide (widget);
 +
 +	widget = gtk_hbox_new (FALSE, 3);
 +	gtk_box_pack_start (GTK_BOX (shell_taskbar), widget, TRUE, TRUE, 0);
 +	shell_taskbar->priv->hbox = g_object_ref (widget);
 +	gtk_widget_hide (widget);
 +
 +	/* Make the taskbar large enough to accomodate a small icon.
 +	 * XXX The "* 2" is a fudge factor to allow for some padding
 +	 *     The true value is probably buried in a style property. */
 +	gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, NULL, &height);
 +	gtk_widget_set_size_request (
 +		GTK_WIDGET (shell_taskbar), -1, (height * 2));
 +}
 +
 +GType
 +e_shell_taskbar_get_type (void)
 +{
 +	static GType type = 0;
 +
 +	if (G_UNLIKELY (type == 0)) {
 +		static const GTypeInfo type_info = {
 +			sizeof (EShellTaskbarClass),
 +			(GBaseInitFunc) NULL,
 +			(GBaseFinalizeFunc) NULL,
 +			(GClassInitFunc) shell_taskbar_class_init,
 +			(GClassFinalizeFunc) NULL,
 +			NULL,  /* class_data */
 +			sizeof (EShellTaskbar),
 +			0,     /* n_preallocs */
 +			(GInstanceInitFunc) shell_taskbar_init,
 +			NULL   /* value_table */
 +		};
 +
 +		type = g_type_register_static (
 +			GTK_TYPE_HBOX, "EShellTaskbar", &type_info, 0);
 +	}
 +
 +	return type;
 +}
 +
 +/**
 + * e_shell_taskbar_new:
 + * @shell_view: an #EShellView
 + *
 + * Creates a new #EShellTaskbar instance belonging to @shell_view.
 + *
 + * Returns: a new #EShellTaskbar instance
 + **/
 +GtkWidget *
 +e_shell_taskbar_new (EShellView *shell_view)
 +{
 +	g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
 +
 +	return g_object_new (
 +		E_TYPE_SHELL_TASKBAR, "shell-view", shell_view, NULL);
 +}
 +
 +/**
 + * e_shell_taskbar_get_shell_view:
 + * @shell_taskbar: an #EShellTaskbar
 + *
 + * Returns the #EShellView that was passed to e_shell_taskbar_new().
 + *
 + * Returns: the #EShellView to which @shell_taskbar belongs
 + **/
 +EShellView *
 +e_shell_taskbar_get_shell_view (EShellTaskbar *shell_taskbar)
 +{
 +	g_return_val_if_fail (E_IS_SHELL_TASKBAR (shell_taskbar), NULL);
 +
 +	return shell_taskbar->priv->shell_view;
 +}
 +
 +/**
 + * e_shell_taskbar_get_message:
 + * @shell_taskbar: an #EShellTaskbar
 + *
 + * Returns the message currently shown in the taskbar, or an empty string
 + * if no message is shown.  Taskbar messages are used primarily for menu
 + * tooltips.
 + *
 + * Returns: the current taskbar message
 + **/
 +const gchar *
 +e_shell_taskbar_get_message (EShellTaskbar *shell_taskbar)
 +{
 +	GtkWidget *label;
 +
 +	g_return_val_if_fail (E_IS_SHELL_TASKBAR (shell_taskbar), NULL);
 +
 +	label = shell_taskbar->priv->label;
 +
 +	return gtk_label_get_text (GTK_LABEL (label));
 +}
 +
 +/**
 + * e_shell_taskbar_set_message:
 + * @shell_taskbar: an #EShellTaskbar
 + * @message: the message to show
 + *
 + * Shows a message in the taskbar.  If @message is %NULL or an empty string,
 + * the taskbar message is cleared.  Taskbar messages are used primarily for
 + * menu tooltips.
 + **/
 +void
 +e_shell_taskbar_set_message (EShellTaskbar *shell_taskbar,
 +                             const gchar *message)
 +{
 +	GtkWidget *label;
 +
 +	g_return_if_fail (E_IS_SHELL_TASKBAR (shell_taskbar));
 +
 +	label = shell_taskbar->priv->label;
 +	gtk_label_set_text (GTK_LABEL (label), message);
 +
 +	if (message != NULL && *message != '\0')
 +		gtk_widget_show (label);
 +	else
 +		gtk_widget_hide (label);
 +
 +	g_object_notify (G_OBJECT (shell_taskbar), "message");
 +}
 +
 +/**
 + * e_shell_taskbar_unset_message:
 + * @shell_taskbar: an #EShellTaskbar
 + *
 + * This is equivalent to passing a %NULL message to
 + * e_shell_taskbar_set_message().
 + **/
 +void
 +e_shell_taskbar_unset_message (EShellTaskbar *shell_taskbar)
 +{
 +	g_return_if_fail (E_IS_SHELL_TASKBAR (shell_taskbar));
 +
 +	e_shell_taskbar_set_message (shell_taskbar, NULL);
 +}
diff --cc shell/e-shell-taskbar.h
index b0aab3b,0000000..3c3d400
mode 100644,000000..100644
--- a/shell/e-shell-taskbar.h
+++ b/shell/e-shell-taskbar.h
@@@ -1,87 -1,0 +1,87 @@@
 +/*
 + * e-shell-taskbar.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +/**
 + * SECTION: e-shell-taskbar
 + * @short_description: the bottom of the main window
 + * @include: shell/e-shell-taskbar.h
 + **/
 +
 +#ifndef E_SHELL_TASKBAR_H
 +#define E_SHELL_TASKBAR_H
 +
 +#include <shell/e-shell-common.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_SHELL_TASKBAR \
 +	(e_shell_taskbar_get_type ())
 +#define E_SHELL_TASKBAR(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_SHELL_TASKBAR, EShellTaskbar))
 +#define E_SHELL_TASKBAR_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_SHELL_TASKBAR, EShellTaskbarClass))
 +#define E_IS_SHELL_TASKBAR(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_SHELL_TASKBAR))
 +#define E_IS_SHELL_TASKBAR_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), E_TYPE_SHELL_TASKBAR))
 +#define E_SHELL_TASKBAR_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_SHELL_TASKBAR, EShellTaskbarClass))
 +
 +G_BEGIN_DECLS
 +
 +/* Avoid including <e-shell-view.h>, because it includes us! */
 +struct _EShellView;
 +
 +typedef struct _EShellTaskbar EShellTaskbar;
 +typedef struct _EShellTaskbarClass EShellTaskbarClass;
 +typedef struct _EShellTaskbarPrivate EShellTaskbarPrivate;
 +
 +/**
 + * EShellTaskbar:
 + *
 + * Contains only private data that should be read and manipulated using the
 + * functions below.
 + **/
 +struct _EShellTaskbar {
 +	GtkHBox parent;
 +	EShellTaskbarPrivate *priv;
 +};
 +
 +struct _EShellTaskbarClass {
 +	GtkHBoxClass parent_class;
 +};
 +
 +GType		e_shell_taskbar_get_type	(void);
 +GtkWidget *	e_shell_taskbar_new		(struct _EShellView *shell_view);
 +struct _EShellView *
 +		e_shell_taskbar_get_shell_view	(EShellTaskbar *shell_taskbar);
 +const gchar *	e_shell_taskbar_get_message	(EShellTaskbar *shell_taskbar);
 +void		e_shell_taskbar_set_message	(EShellTaskbar *shell_taskbar,
 +						 const gchar *message);
 +void		e_shell_taskbar_unset_message	(EShellTaskbar *shell_taskbar);
 +
 +G_END_DECLS
 +
 +#endif /* E_SHELL_TASKBAR_H */
diff --cc shell/e-shell-view.c
index 7c5332a,a6d071c..cf89442
--- a/shell/e-shell-view.c
+++ b/shell/e-shell-view.c
@@@ -12,9 -12,12 +12,9 @@@
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
+  * License along with the program; if not, see <http://www.gnu.org/licenses/>
   *
   *
 - * Authors:
 - *		Michael Zucchi <notzed ximian com>
 - *
   * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
   *
   */
diff --cc shell/e-shell-window-actions.c
index 846bb82,0000000..a53412c
mode 100644,000000..100644
--- a/shell/e-shell-window-actions.c
+++ b/shell/e-shell-window-actions.c
@@@ -1,2226 -1,0 +1,2226 @@@
 +/*
 + * e-shell-window-actions.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-shell-window-private.h"
 +
 +#include <e-util/e-dialog-utils.h>
 +#include <e-util/e-error.h>
 +#include <e-util/e-print.h>
 +#include <gal-define-views-dialog.h>
 +
 +#include <libedataserverui/e-passwords.h>
 +
 +#include "e-shell-importer.h"
 +
 +#define EVOLUTION_COPYRIGHT \
 +	"Copyright \xC2\xA9 1999 - 2008 Novell, Inc. and Others"
 +
 +#define EVOLUTION_FAQ \
 +	"http://www.go-evolution.org/FAQ";
 +
 +#define EVOLUTION_WEBSITE \
 +	"http://www.gnome.org/projects/evolution/";
 +
 +/* Authors and Documenters
 + *
 + * The names below must be in UTF-8.  The breaking of escaped strings
 + * is so the hexadecimal sequences don't swallow too many characters.
 + *
 + * SO THAT MEANS, FOR 8-BIT CHARACTERS USE \xXX HEX ENCODING ONLY!
 + *
 + * Not all environments are UTF-8 and not all editors can handle it.
 + */
 +static const gchar *authors[] = {
 +	"Aaron Weber",
 +	"Abel Cheung",
 +	"Abhishek Parwal",
 +	"Adam Weinberger",
 +	"Adi Attar",
 +	"Ahmad Riza H Nst",
 +	"Aidan Delaney",
 +	"Aishwarya K",
 +	"Akagic Amila",
 +	"Akhil Laddha",
 +	"Akira Tagoh",
 +	"Alastair McKinstry",
 +	"Alastair Tse",
 +	"Alejandro Andres",
 +	"Alessandro Decina",
 +	"Alex Graveley",
 +	"Alex Jiang",
 +	"Alex Jones",
 +	"Alex Kloss",
 +	"Alexander Shopov",
 +	"Alfred Peng",
 +	"Ali Abdin",
 +	"Ali Akcaagac",
 +	"Almer S. Tigelaar",
 +	"Amish",
 +	"Anand V M",
 +	"Anders Carlsson",
 +	"Andre Klapper",
 +	"Andrea Campi",
 +	"Andreas Henriksson",
 +	"Andreas Hyden",
 +	"Andreas J. Guelzow",
 +	"Andreas K\xC3\xB6hler",
 +	"Andreas Köhler",
 +	"Andrew Ruthven",
 +	"Andrew T. Veliath",
 +	"Andrew Wu",
 +	"Ankit Patel",
 +	"Anna Marie Dirks",
 +	"Antonio Xu",
 +	"Arafat Medini",
 +	"Arangel Angov",
 +	"Archit Baweja",
 +	"Ariel Rios",
 +	"Arik Devens",
 +	"Armin Bauer",
 +	"Arturo Espinosa Aldama",
 +	"Arulanandan P",
 +	"Arun Prakash",
 +	"Arvind Sundararajan",
 +	"Arvind",
 +	"Ashish",
 +	"B S Srinidhi",
 +	"Bastien Nocera",
 +	"Behnam Esfahbod",
 +	"Ben Gamari",
 +	"Benjamin Berg",
 +	"Benjamin Kahn",
 +	"Benoît Dejean",
 +	"Bernard Leach",
 +	"Bertrand Guiheneuf",
 +	"Bharath Acharya",
 +	"Bill Zhu",
 +	"Bj\xC3\xB6rn Torkelsson",
 +	"Bj�¶rn Lindqvist",
 +	"Bob Doan",
 +	"Bob Mauchin",
 +	"Boby Wang",
 +	"Bolian Yin",
 +	"Brian Mury",
 +	"Brian Pepple",
 +	"Bruce Tao",
 +	"Calvin Liu",
 +	"Cantona Su",
 +	"Carl Sun",
 +	"Carlos Garcia Campos",
 +	"Carlos Garnacho Parro",
 +	"Carlos Perell\xC3\xB3" " Mar\xC3\xAD" "n",
 +	"Carsten Guenther",
 +	"Carsten Schaar",
 +	"Changwoo Ryu",
 +	"Chao-Hsiung Liao",
 +	"Charles Zhang",
 +	"Chema Celorio",
 +	"Chenthill Palanisamy",
 +	"Chpe",
 +	"Chris Halls",
 +	"Chris Heath",
 +	"Chris Phelps",
 +	"Chris Toshok",
 +	"Christian Hammond",
 +	"Christian Kellner",
 +	"Christian Kirbach",
 +	"Christian Krause",
 +	"Christian Kreibich",
 +	"Christian Neumair",
 +	"Christophe Fergeau",
 +	"Christophe Merlet",
 +	"Christopher Blizzard",
 +	"Christopher J. Lahey",
 +	"Christopher R. Gabriel",
 +	"Claude Paroz",
 +	"Claudio Saavedra",
 +	"Clifford R. Conover",
 +	"Cody Russell",
 +	"Colin Leroy",
 +	"Craig Small",
 +	"Dafydd Harries",
 +	"Damian Ivereigh",
 +	"Damien Carbery",
 +	"Damon Chaplin",
 +	"Dan Berger",
 +	"Dan Damian",
 +	"Dan Nguyen",
 +	"Dan Winship",
 +	"Daniel Gryniewicz",
 +	"Daniel Nylander",
 +	"Daniel van Eeden",
 +	"Daniel Veillard",
 +	"Daniel Yacob",
 +	"Danilo \xC5\xA0" "egan",
 +	"Danilo Segan",
 +	"Darin Adler",
 +	"Dave Benson",
 +	"Dave Camp",
 +	"Dave Fallon",
 +	"Dave Malcolm",
 +	"Dave West",
 +	"David Farning",
 +	"David Kaelbling",
 +	"David Malcolm",
 +	"David Moore",
 +	"David Mosberger",
 +	"David Richards",
 +	"David Trowbridge",
 +	"David Turner",
 +	"David Woodhouse",
 +	"Denis Washington",
 +	"Devashish Sharma",
 +	"Diego Escalante Urrelo",
 +	"Diego Gonzalez",
 +	"Diego Sevilla Ruiz",
 +	"Dietmar Maurer",
 +	"Dinesh Layek",
 +	"Djihed Afifi",
 +	"Dmitry Mastrukov",
 +	"Dodji Seketeli",
 +	"Duarte Loreto",
 +	"Dulmandakh Sukhbaatar",
 +	"Duncan Mak",
 +	"Ebby Wiselyn",
 +	"Ed Catmur",
 +	"Edd Dumbill",
 +	"Edgar Luna Díaz",
 +	"Edward Rudd",
 +	"Elijah Newren",
 +	"Elizabeth Greene",
 +	"Elliot Lee",
 +	"Elliot Turner",
 +	"Eneko Lacunza",
 +	"Enver Altin",
 +	"Erdal Ronahi",
 +	"Eric Busboom",
 +	"Eric Zhao",
 +	"Eskil Heyn Olsen",
 +	"Ettore Perazzoli",
 +	"Evan Yan",
 +	"Fatih Demir",
 +	"Fazlu & Hannah",
 +	"Federico Mena Quintero",
 +	"Fernando Herrera",
 +	"Francisco Javier F. Serrador",
 +	"Frank Arnold",
 +	"Frank Belew",
 +	"Frederic Crozat",
 +	"Frederic Peters",
 +	"Funda Wang",
 +	"Gabor Kelemen",
 +	"Ganesh",
 +	"Gareth Owen",
 +	"Gary Coady",
 +	"Gary Ekker",
 +	"Gavin Scott",
 +	"Gediminas Paulauskas",
 +	"Gerg\xC5\x91 \xC3\x89rdi",
 +	"George Lebl",
 +	"Gerardo Marin",
 +	"Gert Kulyk",
 +	"Giancarlo Capella",
 +	"Gil Osher",
 +	"Gilbert Fang",
 +	"Gilles Dartiguelongue",
 +	"Grahame Bowland",
 +	"Greg Hudson",
 +	"Gregory Leblanc",
 +	"Gregory McLean",
 +	"Grzegorz Goawski",
 +	"Gustavo Gir\xC3\x8E" "ldez",
 +	"Gustavo Maciel Dias Vieira",
 +	"H P Nadig",
 +	"H\xC3\xA9" "ctor Garc\xC3\xAD" "a \xC3\x81" "lvarez",
 +	"Hans Petter Jansson",
 +	"Hao Sheng",
 +	"Hari Prasad Nadig",
 +	"Harish K",
 +	"Harish Krishnaswamy",
 +	"Harry Lu",
 +	"Hasbullah Bin Pit",
 +	"Havoc Pennington",
 +	"Heath Harrelson",
 +	"Hein-Pieter van Braam",
 +	"Herbert V. Riedel",
 +	"Hiroyuki Ikezoe",
 +	"Iain Buchanan",
 +	"Iain Holmes",
 +	"Ian Campbell",
 +	"Ilkka Tuohela",
 +	"Irene Huang",
 +	"Ismael Olea",
 +	"Israel Escalante",
 +	"Iv\xC3\xA1" "n Frade",
 +	"Iv�¡n Frade",
 +	"J.H.M. Dassen (Ray)",
 +	"JP Rosevear",
 +	"J\xC3\xBC" "rg Billeter",
 +	"J��¼rg Billeter",
 +	"Jack Jia",
 +	"Jacob Ulysses Berkman",
 +	"Jacob Berkman",
 +	"Jaka Mocnik",
 +	"Jakub Steiner",
 +	"James Doc Livingston",
 +	"James Bowes",
 +	"James Henstridge",
 +	"James Willcox",
 +	"Jan Arne Petersen",
 +	"Jan Tichavsky",
 +	"Jan Van Buggenhout",
 +	"Jared Moore",
 +	"Jarkko Ranta",
 +	"Jason Leach",
 +	"Jason Tackaberry",
 +	"Jayaradha",
 +	"Jean-Noel Guiheneuf",
 +	"Jedy Wang",
 +	"Jeff Bailey",
 +	"Jeff Cai",
 +	"Jeff Garzik",
 +	"Jeffrey Stedfast",
 +	"Jens Granseuer",
 +	"Jens Seidel",
 +	"Jeremy Katz",
 +	"Jeremy Wise",
 +	"Jerome Lacoste",
 +	"Jerry Yu",
 +	"Jes\xC3\xBA" "s Bravo \xC3\x81" "lvarez",
 +	"Jesse Pavel",
 +	"Ji Lee",
 +	"Joan Sanfeliu",
 +	"Jody Goldberg",
 +	"Joe Marcus Clarke",
 +	"Joe Shaw",
 +	"John Gotts",
 +	"Johnny Jacob",
 +	"Johnny",
 +	"Jon Ander Hernandez",
 +	"Jon K Hellan",
 +	"Jon Oberheide",
 +	"Jon Trowbridge",
 +	"Jonas Borgstr",
 +	"Jonathan Blandford",
 +	"Jonathan Dieter",
 +	"Jos Dehaes",
 +	"Josselin Mouette",
 +	"JP Rosvear",
 +	"Jukka Zitting",
 +	"Jules Colding",
 +	"Julian Missig",
 +	"Julio M. Merino Vidal",
 +	"Jürg Billeter",
 +	"Karl Eichwalder",
 +	"Karl Relton",
 +	"Karsten Br\xC3\xA4" "ckelmann",
 +	"Kaushal Kumar",
 +	"Kenneth Christiansen",
 +	"Kenny Graunke",
 +	"Keshav Upadhyaya",
 +	"Kevin Breit",
 +	"Kevin Piche",
 +	"Kevin Vandersloot",
 +	"Khasim Shaheed",
 +	"Kidd Wang",
 +	"Kjartan Maraas",
 +	"Krishnan R",
 +	"Krisztian Pifko",
 +	"Kyle Ambroff",
 +	"Larry Ewing",
 +	"Laszlo (Laca) Peter",
 +	"Laurent Dhima",
 +	"Lauris Kaplinski",
 +	"Leon Zhang",
 +	"Li Yuan",
 +	"Lo�¯c Minier",
 +	"Loïc Minier",
 +	"Lorenzo Gil Sanchez",
 +	"Luca Ferretti",
 +	"Lucky Wankhede",
 +	"Luis Villa",
 +	"Lutz M",
 +	"M Victor Aloysius J",
 +	"Maciej Stachowiak",
 +	"Makuchaku",
 +	"Malcolm Tredinnick",
 +	"Marco Pesenti Gritti",
 +	"Marius Andreiana",
 +	"Marius Vollmer",
 +	"Mark Crichton",
 +	"Mark G. Adams",
 +	"Mark Gordon",
 +	"Mark McLoughlin",
 +	"Mark Moulder",
 +	"Mark Tearle",
 +	"Martha Burke",
 +	"Martin Baulig",
 +	"Martin Hicks",
 +	"Martin Meyer",
 +	"Martin Norb\xC3\xA4" "ck",
 +	"Martyn Russell",
 +	"Masahiro Sakai",
 +	"Mathieu Lacage",
 +	"Matias Mutchinick",
 +	"Matt Bissiri",
 +	"Matt Brown",
 +	"Matt Loper",
 +	"Matt Martin",
 +	"Matt Wilson",
 +	"Matthew Barnes",
 +	"Matthew Daniel",
 +	"Matthew Hall",
 +	"Matthew Loper",
 +	"Matthew Wilson",
 +	"Matthias Clasen",
 +	"Max Horn",
 +	"Maxx Cao",
 +	"Mayank Jain",
 +	"Meilof Veeningen",
 +	"Mengjie Yu",
 +	"Michael Granger",
 +	"Michael M. Morrison",
 +	"Michael MacDonald",
 +	"Michael Meeks",
 +	"Michael Monreal",
 +	"Michael Terry",
 +	"Michael Zucchi",
 +	"Michel Daenzer",
 +	"Miguel Angel Lopez Hernandez",
 +	"Miguel de Icaza",
 +	"Mikael Hallendal",
 +	"Mikael Nilsson",
 +	"Mike Castle",
 +	"Mike Kestner",
 +	"Mike McEwan",
 +	"Mikhail Zabaluev",
 +	"Milan Crha",
 +	"Miles Lane",
 +	"Mohammad Damt",
 +	"Morten Welinder",
 +	"Mubeen Jukaku",
 +	"Murray Cumming",
 +	"Naba Kumar",
 +	"Nagappan Alagappan",
 +	"Nancy Cai",
 +	"Nat Friedman",
 +	"Nathan Owens",
 +	"Nicel KM",
 +	"Nicholas J Kreucher",
 +	"Nicholas Miell",
 +	"Nick Sukharev",
 +	"Nickolay V. Shmyrev",
 +	"Nike Gerdts",
 +	"Noel",
 +	"Nuno Ferreira",
 +	"Nyall Dawson",
 +	"Ondrej Jirman",
 +	"Oswald Rodrigues",
 +	"Owen Taylor",
 +	"Oystein Gisnas",
 +	"P Chenthill",
 +	"P S Chakravarthi",
 +	"Pablo Gonzalo del Campo",
 +	"Pablo Saratxaga",
 +	"Pamplona Hackers",
 +	"Paolo Molaro",
 +	"Parag Goel",
 +	"Parthasarathi Susarla",
 +	"Pascal Terjan",
 +	"Patrick Ohly",
 +	"Paul Bolle",
 +	"Paul Lindner",
 +	"Pavel Cisler",
 +	"Pavel Roskin",
 +	"Pavithran",
 +	"Pawan Chitrakar",
 +	"Pedro Villavicencio",
 +	"Peter Pouliot",
 +	"Peter Teichman",
 +	"Peter Williams",
 +	"Peteris Krisjanis",
 +	"Petta Pietikainen",
 +	"Phil Goembel",
 +	"Philip Van Hoof",
 +	"Philip Zhao",
 +	"Poornima Nayak",
 +	"Pratik V. Parikh",
 +	"Praveen Kumar",
 +	"Priit Laes",
 +	"Priyanshu Raj",
 +	"Radek Doul\xC3\xADk",
 +	"Raghavendran R",
 +	"Raja R Harinath",
 +	"Rajeev Ramanathan",
 +	"Rajesh Ranjan",
 +	"Rakesh k.g",
 +	"Ramiro Estrugo",
 +	"Ranjan Somani",
 +	"Ray Strode",
 +	"Rhys Jones",
 +	"Ricardo Markiewicz",
 +	"Richard Boulton",
 +	"Richard Hult",
 +	"Richard Li",
 +	"Rob Bradford",
 +	"Robert Brady",
 +	"Robert Sedak",
 +	"Robin Slomkowski",
 +	"Rodney Dawes",
 +	"Rodrigo Moya",
 +	"Rohini S",
 +	"Rohini",
 +	"Roland Illig",
 +	"Ronald Kuetemeier",
 +	"Roozbeh Pournader",
 +	"Ross Burton",
 +	"Rouslan Solomakhin",
 +	"Runa Bhattacharjee",
 +	"Russell Steinthal",
 +	"Rusty Conover",
 +	"Ryan P. Skadberg",
 +	"S Antony Vincent Pandian",
 +	"S N Tejasvi",
 +	"S. \xC3\x87" "a\xC4\x9F" "lar Onur",
 +	"S.Antony Vincent Pandian",
 +	"S. Caglar Onur",
 +	"Sam Creasey",
 +	"Sam Yang",
 +	"Sam\xC3\xBA" "el J\xC3\xB3" "n Gunnarsson",
 +	"Sankar P",
 +	"Sanlig Badral",
 +	"Sanshao Jiang",
 +	"Sarfraaz Ahmed",
 +	"Sayamindu Dasgupta",
 +	"Sean Atkinson",
 +	"Sean Gao",
 +	"Sebastian Rittau",
 +	"Sebastian Wilhelmi",
 +	"Sebastien Bacher",
 +	"Sergey Panov",
 +	"Seth Alves",
 +	"Seth Nickell",
 +	"Shakti Sen",
 +	"Shi Pu",
 +	"Shilpa C",
 +	"Shree Krishnan",
 +	"Shreyas Srinivasan",
 +	"Simon Zheng",
 +	"Simos Xenitellis",
 +	"Sivaiah Nallagatla",
 +	"Srinivasa Ragavan",
 +	"Stanislav Brabec",
 +	"Stanislav Visnovsky",
 +	"Stéphane Raimbault",
 +	"Stephen Cook",
 +	"Steve Murphy",
 +	"Steven Zhang",
 +	"Stuart Parmenter",
 +	"Subodh Soni",
 +	"Suman Manjunath",
 +	"Sunil Mohan Adapa",
 +	"Suresh Chandrasekharan",
 +	"Sushma Rai",
 +	"Sven Herzberg",
 +	"Szabolcs Ban",
 +	"T\xC3\xB5" "ivo Leedj\xC3\xA4" "rv",
 +	"Takao Fujiwara",
 +	"Takayuki Kusano",
 +	"Takeshi Aihana",
 +	"Tambet Ingo",
 +	"Taylor Hayward",
 +	"Ted Percival",
 +	"Theppitak Karoonboonyanan",
 +	"Thomas Cataldo",
 +	"Thomas Klausner",
 +	"Thomas Mirlacher",
 +	"Thouis R. Jones",
 +	"Tim Wo",
 +	"Tim Yamin",
 +	"Timo Hoenig",
 +	"Timo Sirainen",
 +	"Timothy Lee",
 +	"Timur Bakeyev",
 +	"Tino Meinen",
 +	"Tobias Mueller",
 +	"Tõivo Leedjärv",
 +	"Tom Tromey",
 +	"Tomas Ogren",
 +	"Tomasz K\xC5\x82" "oczko",
 +	"Tomislav Vujec",
 +	"Tommi Komulainen",
 +	"Tommi Vainikainen",
 +	"Tony Tsui",
 +	"Tor Lillqvist",
 +	"Trent Lloyd",
 +	"Tuomas J. Lukka",
 +	"Tuomas Kuosmanen",
 +	"Ulrich Neumann",
 +	"Umesh Tiwari",
 +	"Umeshtej",
 +	"Ushveen Kaur",
 +	"V Ravi Kumar Raju",
 +	"Vadim Strizhevsky",
 +	"Valek Filippov",
 +	"Vandana Shenoy .B",
 +	"Vardhman Jain",
 +	"Veerapuram Varadhan",
 +	"Vincent Noel",
 +	"Vincent van Adrighem",
 +	"Viren",
 +	"Vivek Jain",
 +	"Vladimer Sichinava",
 +	"Vladimir Vukicevic",
 +	"Wadim Dziedzic",
 +	"Wang Jian",
 +	"Wang Xin",
 +	"Wayne Davis",
 +	"William Jon McCann",
 +	"Wouter Bolsterlee",
 +	"Xan Lopez",
 +	"Xiurong Simon Zheng",
 +	"Yanko Kaneti",
 +	"Yi Jin",
 +	"Yong Sun",
 +	"Yu Mengjie",
 +	"Yuedong Du",
 +	"Yukihiro Nakai",
 +	"Yuri Pankov",
 +	"Yuri Syrota",
 +	"Zach Frey",
 +	"Zan Lynx",
 +	"Zbigniew Chyla",
 +	"\xC3\x98ystein Gisn\xC3\xA5s",
 +	"\xC5\xBDygimantas Beru\xC4\x8Dka",
 +	NULL
 +};
 +
 +static const gchar *documenters[] = {
 +	"Aaron Weber",
 +	"Binika Preet",
 +	"Dan Winship",
 +	"David Trowbridge",
 +	"Jessica Prabhakar",
 +	"JP Rosevear",
 +	"Radhika Nair",
 +	NULL
 +};
 +
 +/**
 + * E_SHELL_WINDOW_ACTION_ABOUT:
 + * @window: an #EShellWindow
 + *
 + * Activation of this action displays the application's About dialog.
 + *
 + * Main menu item: Help -> About
 + **/
 +static void
 +action_about_cb (GtkAction *action,
 +                 EShellWindow *shell_window)
 +{
 +	gchar *translator_credits;
 +
 +	/* The translator-credits string is for translators to list
 +	 * per-language credits for translation, displayed in the
 +	 * about dialog. */
 +	translator_credits = _("translator-credits");
 +	if (strcmp (translator_credits, "translator-credits") == 0)
 +		translator_credits = NULL;
 +
 +	gtk_show_about_dialog (
 +		GTK_WINDOW (shell_window),
 +		"program-name", "Evolution",
 +		"version", VERSION,
 +		"copyright", EVOLUTION_COPYRIGHT,
 +		"comments", _("Groupware Suite"),
 +		"website", EVOLUTION_WEBSITE,
 +		"website-label", _("Evolution Website"),
 +		"authors", authors,
 +		"documenters", documenters,
 +		"translator-credits", translator_credits,
 +		"logo-icon-name", "evolution",
 +		NULL);
 +}
 +
 +/**
 + * E_SHELL_WINDOW_ACTION_CLOSE:
 + * @window: an #EShellWindow
 + *
 + * Activation of this action closes @window.  If this is the last window,
 + * the application initiates shutdown.
 + *
 + * Main menu item: File -> Close
 + **/
 +static void
 +action_close_cb (GtkAction *action,
 +                 EShellWindow *shell_window)
 +{
 +	GtkWidget *widget = GTK_WIDGET (shell_window);
 +	GdkEvent *event;
 +
 +	/* Synthesize a delete_event on this window. */
 +	event = gdk_event_new (GDK_DELETE);
 +	event->any.window = g_object_ref (widget->window);
 +	event->any.send_event = TRUE;
 +	gtk_main_do_event (event);
 +	gdk_event_free (event);
 +}
 +
 +/**
 + * E_SHELL_WINDOW_ACTION_CONTENTS:
 + * @window: an #EShellWindow
 + *
 + * Activation of this action opens the application's user manual.
 + *
 + * Main menu item: Help -> Contents
 + **/
 +static void
 +action_contents_cb (GtkAction *action,
 +                    EShellWindow *shell_window)
 +{
 +	e_display_help (GTK_WINDOW (shell_window), NULL);
 +}
 +
 +static void
 +action_custom_rule_cb (GtkAction *action,
 +                       EShellWindow *shell_window)
 +{
 +	FilterRule *rule;
 +	EShellView *shell_view;
 +	EShellContent *shell_content;
 +	const gchar *view_name;
 +
 +	rule = g_object_get_data (G_OBJECT (action), "rule");
 +	g_return_if_fail (rule != NULL);
 +
 +	view_name = e_shell_window_get_active_view (shell_window);
 +	shell_view = e_shell_window_get_shell_view (shell_window, view_name);
 +	shell_content = e_shell_view_get_shell_content (shell_view);
 +
 +	rule = g_object_get_data (G_OBJECT (action), "rule");
 +	g_return_if_fail (IS_FILTER_RULE (rule));
 +
 +	e_shell_content_set_search_rule (shell_content, rule);
 +	gtk_action_activate (ACTION (SEARCH_EXECUTE));
 +}
 +
 +/**
 + * E_SHELL_WINDOW_ACTION_FAQ:
 + * @window: an #EShellWindow
 + *
 + * Activation of this action opens a web page with answers to frequently
 + * asked questions about this application.
 + *
 + * Main menu item: Help -> Evolution FAQ
 + **/
 +static void
 +action_faq_cb (GtkAction *action,
 +               EShellWindow *shell_window)
 +{
 +	e_show_uri (GTK_WINDOW (shell_window), EVOLUTION_FAQ);
 +}
 +
 +/**
 + * E_SHELL_WINDOW_ACTION_FORGET_PASSWORDS:
 + * @window: an #EShellWindow
 + *
 + * Activation of this action deletes all stored passwords.
 + *
 + * Main menu item: File -> Forget Passwords
 + **/
 +static void
 +action_forget_passwords_cb (GtkAction *action,
 +                            EShellWindow *shell_window)
 +{
 +	gint response;
 +
 +	response = e_error_run (
 +		GTK_WINDOW (shell_window), "shell:forget-passwords", NULL);
 +
 +	if (response == GTK_RESPONSE_OK)
 +		e_passwords_forget_passwords ();
 +}
 +
 +/**
 + * E_SHELL_WINDOW_ACTION_GAL_DEFINE_VIEWS:
 + * @window: an #EShellWindow
 + *
 + * Activation of this action opens a dialog for editing GAL views for
 + * the current shell view.
 + *
 + * Main menu item: View -> Current View -> Define Views...
 + **/
 +static void
 +action_gal_define_views_cb (GtkAction *action,
 +                            EShellWindow *shell_window)
 +{
 +	EShellView *shell_view;
 +	EShellViewClass *shell_view_class;
 +	GalViewCollection *view_collection;
 +	GtkWidget *dialog;
 +	const gchar *view_name;
 +
 +	view_name = e_shell_window_get_active_view (shell_window);
 +	shell_view = e_shell_window_get_shell_view (shell_window, view_name);
 +	shell_view_class = E_SHELL_VIEW_GET_CLASS (shell_view);
 +	view_collection = shell_view_class->view_collection;
 +	g_return_if_fail (view_collection != NULL);
 +
 +	dialog = gal_define_views_dialog_new (view_collection);
 +	gtk_dialog_run (GTK_DIALOG (dialog));
 +	gal_view_collection_save (view_collection);
 +	gtk_widget_destroy (dialog);
 +
 +	e_shell_window_update_view_menu (shell_window);
 +}
 +
 +/**
 + * E_SHELL_WINDOW_ACTION_GAL_CUSTOM_VIEW:
 + * @window: an #EShellWindow
 + *
 + * This radio action is selected when using a custom GAL view that has
 + * not been saved.
 + *
 + * Main menu item: View -> Current View -> Custom View
 + **/
 +static void
 +action_gal_view_cb (GtkRadioAction *action,
 +                    GtkRadioAction *current,
 +                    EShellWindow *shell_window)
 +{
 +	EShellView *shell_view;
 +	const gchar *view_name;
 +	const gchar *view_id;
 +
 +	view_name = e_shell_window_get_active_view (shell_window);
 +	shell_view = e_shell_window_get_shell_view (shell_window, view_name);
 +	view_id = g_object_get_data (G_OBJECT (current), "view-id");
 +	e_shell_view_set_view_id (shell_view, view_id);
 +}
 +
 +/**
 + * E_SHELL_WINDOW_ACTION_GAL_SAVE_CUSTOM_VIEW:
 + * @window: an #EShellWindow
 + *
 + * Activation of this action saves a custom GAL view.
 + *
 + * Main menu item: View -> Current View -> Save Custom View...
 + **/
 +
 +/**
 + * E_SHELL_WINDOW_ACTION_IMPORT:
 + * @window: an #EShellWindow
 + *
 + * Activation of this action opens the Evolution Import Assistant.
 + *
 + * Main menu item: File -> Import...
 + **/
 +static void
 +action_import_cb (GtkAction *action,
 +                  EShellWindow *shell_window)
 +{
 +	e_shell_importer_start_import (shell_window);
 +}
 +
 +/**
 + * E_SHELL_WINDOW_ACTION_NEW_WINDOW:
 + * @window: an #EShellWindow
 + *
 + * Activation of this action opens a new shell window.
 + *
 + * Main menu item: File -> New Window
 + **/
 +static void
 +action_new_window_cb (GtkAction *action,
 +                      EShellWindow *shell_window)
 +{
 +	EShell *shell;
 +	const gchar *view_name;
 +
 +	shell = e_shell_window_get_shell (shell_window);
 +	view_name = e_shell_window_get_active_view (shell_window);
 +
 +	e_shell_create_shell_window (shell, view_name);
 +}
 +
 +/**
 + * E_SHELL_WINDOW_ACTION_PAGE_SETUP:
 + * @window: an #EShellWindow
 + *
 + * Activation of this action opens the application's Page Setup dialog.
 + *
 + * Main menu item: File -> Page Setup...
 + **/
 +static void
 +action_page_setup_cb (GtkAction *action,
 +                      EShellWindow *shell_window)
 +{
 +	e_print_run_page_setup_dialog (GTK_WINDOW (shell_window));
 +}
 +
 +/**
 + * E_SHELL_WINDOW_ACTION_PREFERENCES:
 + * @window: an #EShellWindow
 + *
 + * Activation of this action opens the application's Preferences window.
 + *
 + * Main menu item: Edit -> Preferences
 + **/
 +static void
 +action_preferences_cb (GtkAction *action,
 +                       EShellWindow *shell_window)
 +{
 +	EShell *shell;
 +	GtkWidget *preferences_window;
 +
 +	shell = e_shell_window_get_shell (shell_window);
 +	preferences_window = e_shell_get_preferences_window (shell);
 +
 +	gtk_window_set_transient_for (
 +		GTK_WINDOW (preferences_window),
 +		GTK_WINDOW (shell_window));
 +	gtk_window_set_position (
 +		GTK_WINDOW (preferences_window),
 +		GTK_WIN_POS_CENTER_ON_PARENT);
 +	gtk_window_present (GTK_WINDOW (preferences_window));
 +
 +	/* FIXME Switch to a page appropriate for the current view. */
 +}
 +
 +/**
 + * E_SHELL_WINDOW_ACTION_QUICK_REFERENCE:
 + * @window: an #EShellWindow
 + *
 + * Activation of this action opens a printable table of useful shortcut
 + * keys for this application.
 + *
 + * Main menu item: Help -> Quick Reference
 + **/
 +static void
 +action_quick_reference_cb (GtkAction *action,
 +                           EShellWindow *shell_window)
 +{
 +	const gchar * const *language_names;
 +
 +	language_names = g_get_language_names ();
 +	while (*language_names != NULL) {
 +		const gchar *language = *language_names++;
 +		gchar *filename;
 +
 +		/* This must be a valid language AND a language with
 +		 * no encoding suffix.  The next language should have
 +		 * no encoding suffix. */
 +		if (language == NULL || strchr (language, '.') != NULL)
 +			continue;
 +
 +		filename = g_build_filename (
 +			EVOLUTION_HELPDIR, "quickref",
 +			language, "quickref.pdf", NULL);
 +
 +		if (g_file_test (filename, G_FILE_TEST_EXISTS)) {
 +			GFile *file;
 +			gchar *uri;
 +			GError *error = NULL;
 +
 +			file = g_file_new_for_path (filename);
 +			uri = g_file_get_uri (file);
 +
 +			g_app_info_launch_default_for_uri (uri, NULL, &error);
 +
 +			if (error != NULL) {
 +				/* FIXME Show an error dialog. */
 +				g_warning ("%s", error->message);
 +				g_error_free (error);
 +			}
 +
 +			g_object_unref (file);
 +			g_free (uri);
 +		}
 +
 +		g_free (filename);
 +	}
 +}
 +
 +/**
 + * E_SHELL_WINDOW_ACTION_QUIT:
 + * @window: an #EShellWindow
 + *
 + * Activation of this action initiates application shutdown.
 + *
 + * Main menu item: File -> Quit
 + **/
 +static void
 +action_quit_cb (GtkAction *action,
 +                EShellWindow *shell_window)
 +{
 +	EShell *shell;
 +
 +	shell = e_shell_window_get_shell (shell_window);
 +	e_shell_quit (shell);
 +}
 +
 +/**
 + * E_SHELL_WINDOW_ACTION_SEARCH_ADVANCED:
 + * @window: an #EShellWindow
 + *
 + * Activation of this action opens an Advanced Search dialog.
 + *
 + * Main menu item: Search -> Advanced Search...
 + **/
 +static void
 +action_search_advanced_cb (GtkAction *action,
 +                           EShellWindow *shell_window)
 +{
 +	EShellView *shell_view;
 +	EShellContent *shell_content;
 +	const gchar *view_name;
 +
 +	view_name = e_shell_window_get_active_view (shell_window);
 +	shell_view = e_shell_window_get_shell_view (shell_window, view_name);
 +	shell_content = e_shell_view_get_shell_content (shell_view);
 +
 +	e_shell_content_run_advanced_search_dialog (shell_content);
 +	e_shell_window_update_search_menu (shell_window);
 +}
 +
 +/**
 + * E_SHELL_WINDOW_ACTION_SEARCH_CLEAR:
 + * @window: an #EShellWindow
 + *
 + * Activation of this action clears the most recent search results.
 + *
 + * Main menu item: Search -> Clear
 + **/
 +static void
 +action_search_clear_cb (GtkAction *action,
 +                        EShellWindow *shell_window)
 +{
 +	EShellView *shell_view;
 +	EShellContent *shell_content;
 +	const gchar *view_name;
 +
 +	view_name = e_shell_window_get_active_view (shell_window);
 +	shell_view = e_shell_window_get_shell_view (shell_window, view_name);
 +	shell_content = e_shell_view_get_shell_content (shell_view);
 +
 +	e_shell_content_set_search_rule (shell_content, NULL);
 +	e_shell_content_set_search_text (shell_content, NULL);
 +
 +	gtk_action_activate (ACTION (SEARCH_EXECUTE));
 +
 +	e_shell_window_update_search_menu (shell_window);
 +}
 +
 +/**
 + * E_SHELL_WINDOW_ACTION_SEARCH_EDIT:
 + * @window: an #EShellWindow
 + *
 + * Activation of this action opens a dialog for editing saved searches.
 + *
 + * Main menu item: Search -> Edit Saved Searches...
 + **/
 +static void
 +action_search_edit_cb (GtkAction *action,
 +                       EShellWindow *shell_window)
 +{
 +	EShellView *shell_view;
 +	EShellContent *shell_content;
 +	const gchar *view_name;
 +
 +	view_name = e_shell_window_get_active_view (shell_window);
 +	shell_view = e_shell_window_get_shell_view (shell_window, view_name);
 +	shell_content = e_shell_view_get_shell_content (shell_view);
 +
 +	e_shell_content_run_edit_searches_dialog (shell_content);
 +	e_shell_window_update_search_menu (shell_window);
 +}
 +
 +/**
 + * E_SHELL_WINDOW_ACTION_SEARCH_EXECUTE:
 + * @window: an #EShellWindow
 + *
 + * Activation of this action executes the current search conditions.
 + *
 + * Main menu item: Search -> Find Now
 + **/
 +
 +/**
 + * E_SHELL_WINDOW_ACTION_SEARCH_OPTIONS:
 + * @window: an #EShellWindow
 + *
 + * Activation of this action displays a menu of search options.
 + * This appears as a "find" icon in the window's search entry.
 + **/
 +static void
 +action_search_options_cb (GtkAction *action,
 +                          EShellWindow *shell_window)
 +{
 +	EShellView *shell_view;
 +	EShellViewClass *shell_view_class;
 +	const gchar *view_name;
 +	const gchar *widget_path;
 +
 +	view_name = e_shell_window_get_active_view (shell_window);
 +	shell_view = e_shell_window_get_shell_view (shell_window, view_name);
 +	shell_view_class = E_SHELL_VIEW_GET_CLASS (shell_view);
 +
 +	widget_path = shell_view_class->search_options;
 +	e_shell_view_show_popup_menu (shell_view, widget_path, NULL);
 +}
 +
 +/**
 + * E_SHELL_WINDOW_ACTION_SEARCH_SAVE:
 + * @window: an #EShellWindow
 + *
 + * Activation of this action saves the current search conditions.
 + *
 + * Main menu item: Search -> Save Search...
 + **/
 +static void
 +action_search_save_cb (GtkAction *action,
 +                       EShellWindow *shell_window)
 +{
 +	EShellView *shell_view;
 +	EShellContent *shell_content;
 +	const gchar *view_name;
 +
 +	view_name = e_shell_window_get_active_view (shell_window);
 +	shell_view = e_shell_window_get_shell_view (shell_window, view_name);
 +	shell_content = e_shell_view_get_shell_content (shell_view);
 +
 +	e_shell_content_run_save_search_dialog (shell_content);
 +	e_shell_window_update_search_menu (shell_window);
 +}
 +
 +/**
 + * E_SHELL_WINDOW_ACTION_SEND_RECEIVE:
 + * @window: an #EShellWindow
 + *
 + * Activation of this action opens the Send &amp; Receive Mail dialog.
 + *
 + * Main menu item: File -> Send / Receive
 + **/
 +static void
 +action_send_receive_cb (GtkAction *action,
 +                        EShellWindow *shell_window)
 +{
 +	EShell *shell;
 +
 +	shell = e_shell_window_get_shell (shell_window);
 +	e_shell_send_receive (shell, GTK_WINDOW (shell_window));
 +}
 +
 +/**
 + * E_SHELL_WINDOW_ACTION_SHOW_SIDEBAR:
 + * @window: an #EShellWindow
 + *
 + * This toggle action controls whether the side bar is visible.
 + *
 + * Main menu item: View -> Layout -> Show Side Bar
 + **/
 +static void
 +action_show_sidebar_cb (GtkToggleAction *action,
 +                        EShellWindow *shell_window)
 +{
 +	GtkPaned *paned;
 +	GtkWidget *widget;
 +	gboolean active;
 +
 +	paned = GTK_PANED (shell_window->priv->content_pane);
 +
 +	widget = gtk_paned_get_child1 (paned);
 +	active = gtk_toggle_action_get_active (action);
 +	g_object_set (widget, "visible", active, NULL);
 +}
 +
 +/**
 + * E_SHELL_WINDOW_ACTION_SHOW_STATUSBAR:
 + * @window: an #EShellWindow
 + *
 + * This toggle action controls whether the status bar is visible.
 + *
 + * Main menu item: View -> Layout -> Show Status Bar
 + **/
 +static void
 +action_show_statusbar_cb (GtkToggleAction *action,
 +                          EShellWindow *shell_window)
 +{
 +	GtkWidget *widget;
 +	gboolean active;
 +
 +	widget = shell_window->priv->status_area;
 +	active = gtk_toggle_action_get_active (action);
 +	g_object_set (widget, "visible", active, NULL);
 +}
 +
 +/**
 + * E_SHELL_WINDOW_ACTION_SHOW_SWITCHER:
 + * @window: an #EShellWindow
 + *
 + * This toggle action controls whether the switcher buttons are visible.
 + *
 + * Main menu item: View -> Switcher Appearance -> Show Buttons
 + **/
 +static void
 +action_show_switcher_cb (GtkToggleAction *action,
 +                         EShellWindow *shell_window)
 +{
 +	EShellSwitcher *switcher;
 +	gboolean active;
 +
 +	switcher = E_SHELL_SWITCHER (shell_window->priv->switcher);
 +	active = gtk_toggle_action_get_active (action);
 +	e_shell_switcher_set_visible (switcher, active);
 +}
 +
 +/**
 + * E_SHELL_WINDOW_ACTION_SHOW_TOOLBAR:
 + * @window: an #EShellWindow
 + *
 + * This toggle action controls whether the tool bar is visible.
 + *
 + * Main menu item: View -> Layout -> Show Tool Bar
 + **/
 +static void
 +action_show_toolbar_cb (GtkToggleAction *action,
 +                        EShellWindow *shell_window)
 +{
 +	GtkWidget *widget;
 +	gboolean active;
 +
 +	widget = shell_window->priv->main_toolbar;
 +	active = gtk_toggle_action_get_active (action);
 +	g_object_set (widget, "visible", active, NULL);
 +}
 +
 +/**
 + * E_SHELL_WINDOW_ACTION_SUBMIT_BUG:
 + * @window: an #EShellWindow
 + *
 + * Activation of this action allows users to report a bug using
 + * Bug Buddy.
 + *
 + * Main menu item: Help -> Submit Bug Report
 + **/
 +static void
 +action_submit_bug_cb (GtkAction *action,
 +                      EShellWindow *shell_window)
 +{
 +	const gchar *command_line;
 +	GError *error = NULL;
 +
 +	command_line = "bug-buddy --sm-disable --package=Evolution";
 +
 +	g_debug ("Spawning: %s", command_line);
 +	g_spawn_command_line_async (command_line, &error);
 +
 +	if (error != NULL) {
 +		const gchar *message;
 +
 +		if (error->code == G_SPAWN_ERROR_NOENT)
 +			message = _("Bug Buddy is not installed.");
 +		else
 +			message = _("Bug Buddy could not be run.");
 +		e_notice (shell_window, GTK_MESSAGE_ERROR, message);
 +		g_error_free (error);
 +	}
 +}
 +
 +static void
 +action_switcher_cb (GtkRadioAction *action,
 +                    GtkRadioAction *current,
 +                    EShellWindow *shell_window)
 +{
 +	const gchar *view_name;
 +
 +	view_name = g_object_get_data (G_OBJECT (current), "view-name");
 +	e_shell_window_switch_to_view (shell_window, view_name);
 +}
 +
 +/**
 + * E_SHELL_WINDOW_ACTION_SWITCHER_STYLE_BOTH:
 + * @window: an #EShellWindow
 + *
 + * This radio action displays switcher buttons with icons and text.
 + *
 + * Main menu item: View -> Switcher Appearance -> Icons and Text
 + **/
 +
 +/**
 + * E_SHELL_WINDOW_ACTION_SWITCHER_STYLE_ICONS:
 + * @window: an #EShellWindow
 + *
 + * This radio action displays switcher buttons with icons only.
 + *
 + * Main menu item: View -> Switcher Appearance -> Icons Only
 + **/
 +
 +/**
 + * E_SHELL_WINDOW_ACTION_SWITCHER_STYLE_TEXT:
 + * @window: an #EShellWindow
 + *
 + * This radio action displays switcher buttons with text only.
 + *
 + * Main menu item: View -> Switcher Appearance -> Text Only
 + **/
 +
 +/**
 + * E_SHELL_WINDOW_ACTION_SWITCHER_STYLE_USER:
 + * @window: an #EShellWindow
 + *
 + * This radio action displays switcher buttons according to the desktop
 + * toolbar setting.
 + *
 + * Main menu item: View -> Switcher Appearance -> Toolbar Style
 + **/
 +static void
 +action_switcher_style_cb (GtkRadioAction *action,
 +                          GtkRadioAction *current,
 +                          EShellWindow *shell_window)
 +{
 +	EShellSwitcher *switcher;
 +	GtkToolbarStyle style;
 +
 +	switcher = E_SHELL_SWITCHER (shell_window->priv->switcher);
 +	style = gtk_radio_action_get_current_value (action);
 +
 +	switch (style) {
 +		case GTK_TOOLBAR_ICONS:
 +		case GTK_TOOLBAR_TEXT:
 +		case GTK_TOOLBAR_BOTH:
 +		case GTK_TOOLBAR_BOTH_HORIZ:
 +			e_shell_switcher_set_style (switcher, style);
 +			break;
 +
 +		default:
 +			e_shell_switcher_unset_style (switcher);
 +			break;
 +	}
 +}
 +
 +/**
 + * E_SHELL_WINDOW_ACTION_SYNC_OPTIONS:
 + * @window: an #EShellWindow
 + *
 + * Activation of this action opens the Gnome Pilot settings.
 + *
 + * Main menu item: Edit -> Synchronization Options...
 + **/
 +static void
 +action_sync_options_cb (GtkAction *action,
 +                        EShellWindow *shell_window)
 +{
 +	const gchar *command_line;
 +	GError *error = NULL;
 +
 +	command_line = "gpilotd-control-applet";
 +
 +	g_debug ("Spawning: %s", command_line);
 +	g_spawn_command_line_async (command_line, &error);
 +
 +	if (error != NULL) {
 +		const gchar *message;
 +
 +		if (error->code == G_SPAWN_ERROR_NOENT)
 +			message = _("GNOME Pilot is not installed.");
 +		else
 +			message = _("GNOME Pilot could not be run.");
 +		e_notice (shell_window, GTK_MESSAGE_ERROR, message);
 +		g_error_free (error);
 +	}
 +}
 +
 +/**
 + * E_SHELL_WINDOW_ACTION_WORK_OFFLINE:
 + * @window: an #EShellWindow
 + *
 + * Activation of this action puts the application into offline mode.
 + *
 + * Main menu item: File -> Work Offline
 + **/
 +static void
 +action_work_offline_cb (GtkAction *action,
 +                        EShellWindow *shell_window)
 +{
 +	EShell *shell;
 +
 +	shell = e_shell_window_get_shell (shell_window);
 +	e_shell_set_online (shell, FALSE);
 +}
 +
 +/**
 + * E_SHELL_WINDOW_ACTION_WORK_ONLINE:
 + * @window: an #EShellWindow
 + *
 + * Activation of this action puts the application into online mode.
 + *
 + * Main menu item: File -> Work Online
 + **/
 +static void
 +action_work_online_cb (GtkAction *action,
 +                       EShellWindow *shell_window)
 +{
 +	EShell *shell;
 +
 +	shell = e_shell_window_get_shell (shell_window);
 +	e_shell_set_online (shell, TRUE);
 +}
 +
 +/**
 + * E_SHELL_WINDOW_ACTION_GROUP_CUSTOM_RULES:
 + * @window: an #EShellWindow
 + **/
 +
 +/**
 + * E_SHELL_WINDOW_ACTION_GROUP_GAL_VIEW:
 + * @window: an #EShellWindow
 + **/
 +
 +/**
 + * E_SHELL_WINDOW_ACTION_GROUP_NEW_ITEM:
 + * @window: an #EShellWindow
 + **/
 +
 +/**
 + * E_SHELL_WINDOW_ACTION_GROUP_NEW_SOURCE:
 + * @window: an #EShellWindow
 + **/
 +
 +/**
 + * E_SHELL_WINDOW_ACTION_GROUP_SHELL:
 + * @window: an #EShellWindow
 + **/
 +
 +/**
 + * E_SHELL_WINDOW_ACTION_GROUP_SWITCHER:
 + * @window: an #EShellWindow
 + **/
 +
 +static GtkActionEntry shell_entries[] = {
 +
 +	{ "about",
 +	  GTK_STOCK_ABOUT,
 +	  NULL,
 +	  NULL,
 +	  N_("Show information about Evolution"),
 +	  G_CALLBACK (action_about_cb) },
 +
 +	{ "close",
 +	  GTK_STOCK_CLOSE,
 +	  N_("_Close Window"),
 +	  "<Control>w",
 +	  N_("Close this window"),
 +	  G_CALLBACK (action_close_cb) },
 +
 +	{ "contents",
 +	  GTK_STOCK_HELP,
 +	  N_("_Contents"),
 +	  "F1",
 +	  N_("Open the Evolution User Guide"),
 +	  G_CALLBACK (action_contents_cb) },
 +
 +	{ "faq",
 +	  "help-faq",
 +	  N_("Evolution _FAQ"),
 +	  NULL,
 +	  N_("Open the Frequently Asked Questions webpage"),
 +	  G_CALLBACK (action_faq_cb) },
 +
 +	{ "forget-passwords",
 +	  NULL,
 +	  N_("_Forget Passwords"),
 +	  NULL,
 +	  N_("Forget all remembered passwords"),
 +	  G_CALLBACK (action_forget_passwords_cb) },
 +
 +	{ "import",
 +	  "stock_mail-import",
 +	  N_("I_mport..."),
 +	  NULL,
 +	  N_("Import data from other programs"),
 +	  G_CALLBACK (action_import_cb) },
 +
 +	{ "new-window",
 +	  "window-new",
 +	  N_("New _Window"),
 +	  "<Control><Shift>w",
 +	  N_("Create a new window displaying this view"),
 +	  G_CALLBACK (action_new_window_cb) },
 +
 +	{ "preferences",
 +	  GTK_STOCK_PREFERENCES,
 +	  NULL,
 +	  "<Control><Shift>s",
 +	  N_("Configure Evolution"),
 +	  G_CALLBACK (action_preferences_cb) },
 +
 +	{ "quick-reference",
 +	  NULL,
 +	  N_("_Quick Reference"),
 +	  NULL,
 +	  N_("Show Evolution's shortcut keys"),
 +	  G_CALLBACK (action_quick_reference_cb) },
 +
 +	{ "quit",
 +	  GTK_STOCK_QUIT,
 +	  NULL,
 +	  NULL,
 +	  N_("Exit the program"),
 +	  G_CALLBACK (action_quit_cb) },
 +
 +	{ "search-advanced",
 +	  NULL,
 +	  N_("_Advanced Search..."),
 +	  NULL,
 +	  N_("Construct a more advanced search"),
 +	  G_CALLBACK (action_search_advanced_cb) },
 +
 +	{ "search-clear",
 +	  GTK_STOCK_CLEAR,
 +	  NULL,
 +	  "<Control><Shift>q",
 +	  N_("Clear the current search parameters"),
 +	  G_CALLBACK (action_search_clear_cb) },
 +
 +	{ "search-edit",
 +	  NULL,
 +	  N_("_Edit Saved Searches..."),
 +	  NULL,
 +	  N_("Manage your saved searches"),
 +	  G_CALLBACK (action_search_edit_cb) },
 +
 +	{ "search-execute",
 +	  GTK_STOCK_FIND,
 +	  N_("_Find Now"),
 +	  "",      /* Block the default Ctrl+F. */
 +	  N_("Execute the current search parameters"),
 +	  NULL },  /* Handled by EShellContent and subclasses. */
 +
 +	{ "search-options",
 +	  GTK_STOCK_FIND,
 +	  NULL,
 +	  NULL,
 +	  N_("Click here to change the search type"),
 +	  G_CALLBACK (action_search_options_cb) },
 +
 +	{ "search-save",
 +	  NULL,
 +	  N_("_Save Search..."),
 +	  NULL,
 +	  N_("Save the current search parameters"),
 +	  G_CALLBACK (action_search_save_cb) },
 +
 +	{ "send-receive",
 +	  "mail-send-receive",
 +	  N_("Send / _Receive"),
 +	  "F9",
 +	  N_("Send queued items and retrieve new items"),
 +	  G_CALLBACK (action_send_receive_cb) },
 +
 +	{ "submit-bug",
 +	  NULL,
 +	  N_("Submit _Bug Report"),
 +	  NULL,
 +	  N_("Submit a bug report using Bug Buddy"),
 +	  G_CALLBACK (action_submit_bug_cb) },
 +
 +	{ "sync-options",
 +	  NULL,
 +	  N_("_Synchronization Options..."),
 +	  NULL,
 +	  N_("Set up Pilot configuration"),
 +	  G_CALLBACK (action_sync_options_cb) },
 +
 +	{ "work-offline",
 +	  "stock_disconnect",
 +	  N_("_Work Offline"),
 +	  NULL,
 +	  N_("Put Evolution into offline mode"),
 +	  G_CALLBACK (action_work_offline_cb) },
 +
 +	{ "work-online",
 +	  "stock_connect",
 +	  N_("_Work Online"),
 +	  NULL,
 +	  N_("Put Evolution into online mode"),
 +	  G_CALLBACK (action_work_online_cb) },
 +
 +	/*** Menus ***/
 +
 +	{ "edit-menu",
 +	  NULL,
 +	  N_("_Edit"),
 +	  NULL,
 +	  NULL,
 +	  NULL },
 +
 +	{ "file-menu",
 +	  NULL,
 +	  N_("_File"),
 +	  NULL,
 +	  NULL,
 +	  NULL },
 +
 +	{ "help-menu",
 +	  NULL,
 +	  N_("_Help"),
 +	  NULL,
 +	  NULL,
 +	  NULL },
 +
 +	{ "layout-menu",
 +	  NULL,
 +	  N_("Lay_out"),
 +	  NULL,
 +	  NULL,
 +	  NULL },
 +
 +	{ "new-menu",
 +	  GTK_STOCK_NEW,
 +	  N_("_New"),
 +	  "",
 +	  NULL,
 +	  NULL },
 +
 +	{ "search-menu",
 +	  NULL,
 +	  N_("_Search"),
 +	  NULL,
 +	  NULL,
 +	  NULL },
 +
 +	{ "switcher-menu",
 +	  NULL,
 +	  N_("_Switcher Appearance"),
 +	  NULL,
 +	  NULL,
 +	  NULL },
 +
 +	{ "view-menu",
 +	  NULL,
 +	  N_("_View"),
 +	  NULL,
 +	  NULL,
 +	  NULL },
 +
 +	{ "window-menu",
 +	  NULL,
 +	  N_("_Window"),
 +	  NULL,
 +	  NULL,
 +	  NULL }
 +};
 +
 +static GtkToggleActionEntry shell_toggle_entries[] = {
 +
 +	{ "show-sidebar",
 +	  NULL,
 +	  N_("Show Side _Bar"),
 +	  NULL,
 +	  N_("Show the side bar"),
 +	  G_CALLBACK (action_show_sidebar_cb),
 +	  TRUE },
 +
 +	{ "show-statusbar",
 +	  NULL,
 +	  N_("Show _Status Bar"),
 +	  NULL,
 +	  N_("Show the status bar"),
 +	  G_CALLBACK (action_show_statusbar_cb),
 +	  TRUE },
 +
 +	{ "show-switcher",
 +	  NULL,
 +	  N_("Show _Buttons"),
 +	  NULL,
 +	  N_("Show the switcher buttons"),
 +	  G_CALLBACK (action_show_switcher_cb),
 +	  TRUE },
 +
 +	{ "show-toolbar",
 +	  NULL,
 +	  N_("Show _Tool Bar"),
 +	  NULL,
 +	  N_("Show the toolbar"),
 +	  G_CALLBACK (action_show_toolbar_cb),
 +	  TRUE }
 +};
 +
 +static GtkRadioActionEntry shell_switcher_entries[] = {
 +
 +	/* This action represents the initial active shell view.
 +	 * It should not be visible in the UI, nor should it be
 +	 * possible to switch to it from another shell view. */
 +	{ "switcher-initial",
 +	  NULL,
 +	  NULL,
 +	  NULL,
 +	  NULL,
 +	  -1 }
 +};
 +
 +static GtkRadioActionEntry shell_switcher_style_entries[] = {
 +
 +	{ "switcher-style-icons",
 +	  NULL,
 +	  N_("_Icons Only"),
 +	  NULL,
 +	  N_("Display window buttons with icons only"),
 +	  GTK_TOOLBAR_ICONS },
 +
 +	{ "switcher-style-text",
 +	  NULL,
 +	  N_("_Text Only"),
 +	  NULL,
 +	  N_("Display window buttons with text only"),
 +	  GTK_TOOLBAR_TEXT },
 +
 +	{ "switcher-style-both",
 +	  NULL,
 +	  N_("Icons _and Text"),
 +	  NULL,
 +	  N_("Display window buttons with icons and text"),
 +	  GTK_TOOLBAR_BOTH_HORIZ },
 +
 +	{ "switcher-style-user",
 +	  NULL,
 +	  N_("Tool_bar Style"),
 +	  NULL,
 +	  N_("Display window buttons using the desktop toolbar setting"),
 +	  -1 }
 +};
 +
 +static GtkActionEntry shell_gal_view_entries[] = {
 +
 +	{ "gal-define-views",
 +	  NULL,
 +	  N_("Define Views..."),
 +	  NULL,
 +	  N_("Create or edit views"),
 +	  G_CALLBACK (action_gal_define_views_cb) },
 +
 +	{ "gal-save-custom-view",
 +	  NULL,
 +	  N_("Save Custom View..."),
 +	  NULL,
 +	  N_("Save current custom view"),
 +	  NULL },  /* Handled by subclasses. */
 +
 +	/*** Menus ***/
 +
 +	{ "gal-view-menu",
 +	  NULL,
 +	  N_("C_urrent View"),
 +	  NULL,
 +	  NULL,
 +	  NULL }
 +};
 +
 +static GtkRadioActionEntry shell_gal_view_radio_entries[] = {
 +
 +	{ "gal-custom-view",
 +	  NULL,
 +	  N_("Custom View"),
 +	  NULL,
 +	  N_("Current view is a customized view"),
 +	  -1 }
 +};
 +
 +static GtkActionEntry shell_lockdown_print_setup_entries[] = {
 +
 +	{ "page-setup",
 +	  GTK_STOCK_PAGE_SETUP,
 +	  NULL,
 +	  NULL,
 +	  N_("Change the page settings for your current printer"),
 +	  G_CALLBACK (action_page_setup_cb) }
 +};
 +
 +static void
 +shell_window_extract_actions (EShellWindow *shell_window,
 +                              GList **source_list,
 +                              GList **destination_list)
 +{
 +	const gchar *current_view;
 +	GList *match_list = NULL;
 +	GList *iter;
 +
 +	/* Pick out the actions from the source list that are tagged
 +	 * as belonging to the current EShellView and move them to the
 +	 * destination list. */
 +
 +	current_view = e_shell_window_get_active_view (shell_window);
 +
 +	/* Example: Suppose [A] and [C] are tagged for this EShellView.
 +	 *
 +	 *        source_list = [A] -> [B] -> [C]
 +	 *                       ^             ^
 +	 *                       |             |
 +	 *         match_list = [ ] --------> [ ]
 +	 *
- 	 *  
++	 *
 +	 *   destination_list = [1] -> [2]  (other actions)
 +	 */
 +	for (iter = *source_list; iter != NULL; iter = iter->next) {
 +		GtkAction *action = iter->data;
 +		const gchar *backend_name;
 +
 +		backend_name = g_object_get_data (
 +			G_OBJECT (action), "backend-name");
 +
 +		if (strcmp (backend_name, current_view) != 0)
 +			continue;
 +
 +		if (g_object_get_data (G_OBJECT (action), "primary"))
 +			match_list = g_list_prepend (match_list, iter);
 +		else
 +			match_list = g_list_append (match_list, iter);
 +	}
 +
 +	/* source_list = [B]   match_list = [A] -> [C] */
 +	for (iter = match_list; iter != NULL; iter = iter->next) {
 +		GList *link = iter->data;
 +
 +		iter->data = link->data;
 +		*source_list = g_list_delete_link (*source_list, link);
 +	}
 +
 +	/* destination_list = [1] -> [2] -> [A] -> [C] */
 +	*destination_list = g_list_concat (*destination_list, match_list);
 +}
 +
 +void
 +e_shell_window_actions_init (EShellWindow *shell_window)
 +{
 +	GtkActionGroup *action_group;
 +	GtkUIManager *ui_manager;
 +
 +	g_return_if_fail (E_IS_SHELL_WINDOW (shell_window));
 +
 +	ui_manager = e_shell_window_get_ui_manager (shell_window);
 +
 +	e_load_ui_definition (ui_manager, "evolution-shell.ui");
 +
 +	/* Shell Actions */
 +	action_group = ACTION_GROUP (SHELL);
 +	gtk_action_group_add_actions (
 +		action_group, shell_entries,
 +		G_N_ELEMENTS (shell_entries), shell_window);
 +	gtk_action_group_add_toggle_actions (
 +		action_group, shell_toggle_entries,
 +		G_N_ELEMENTS (shell_toggle_entries), shell_window);
 +	gtk_action_group_add_radio_actions (
 +		action_group, shell_switcher_style_entries,
 +		G_N_ELEMENTS (shell_switcher_style_entries),
 +		E_SHELL_SWITCHER_DEFAULT_TOOLBAR_STYLE,
 +		G_CALLBACK (action_switcher_style_cb), shell_window);
 +	gtk_action_group_add_actions (
 +		action_group, shell_gal_view_entries,
 +		G_N_ELEMENTS (shell_gal_view_entries), shell_window);
 +	gtk_action_group_add_radio_actions (
 +		action_group, shell_gal_view_radio_entries,
 +		G_N_ELEMENTS (shell_gal_view_radio_entries),
 +		0, G_CALLBACK (action_gal_view_cb), shell_window);
 +
 +	/* Switcher Actions */
 +	action_group = ACTION_GROUP (SWITCHER);
 +	gtk_action_group_add_radio_actions (
 +		action_group, shell_switcher_entries,
 +		G_N_ELEMENTS (shell_switcher_entries),
 +		-1, G_CALLBACK (action_switcher_cb), shell_window);
 +
 +	/* Lockdown Print Setup Actions */
 +	action_group = ACTION_GROUP (LOCKDOWN_PRINT_SETUP);
 +	gtk_action_group_add_actions (
 +		action_group, shell_lockdown_print_setup_entries,
 +		G_N_ELEMENTS (shell_lockdown_print_setup_entries),
 +		shell_window);
 +
 +	/* Fine tuning. */
 +
 +	g_object_set (ACTION (SEND_RECEIVE), "is-important", TRUE, NULL);
 +}
 +
 +GtkWidget *
 +e_shell_window_create_new_menu (EShellWindow *shell_window)
 +{
 +	GtkActionGroup *action_group;
 +	GList *new_item_actions;
 +	GList *new_source_actions;
 +	GList *iter, *list = NULL;
 +	GtkWidget *menu;
 +	GtkWidget *separator;
 +
 +	/* Get sorted lists of "new item" and "new source" actions. */
 +
 +	action_group = ACTION_GROUP (NEW_ITEM);
 +
 +	new_item_actions = g_list_sort (
 +		gtk_action_group_list_actions (action_group),
 +		(GCompareFunc) e_action_compare_by_label);
 +
 +	action_group = ACTION_GROUP (NEW_SOURCE);
 +
 +	new_source_actions = g_list_sort (
 +		gtk_action_group_list_actions (action_group),
 +		(GCompareFunc) e_action_compare_by_label);
 +
 +	/* Give priority to actions that belong to this shell view. */
 +
 +	shell_window_extract_actions (
 +		shell_window, &new_item_actions, &list);
 +
 +	shell_window_extract_actions (
 +		shell_window, &new_source_actions, &list);
 +
 +	/* Convert the actions to menu item proxy widgets. */
 +
 +	for (iter = list; iter != NULL; iter = iter->next)
 +		iter->data = gtk_action_create_menu_item (iter->data);
 +
 +	for (iter = new_item_actions; iter != NULL; iter = iter->next)
 +		iter->data = gtk_action_create_menu_item (iter->data);
 +
 +	for (iter = new_source_actions; iter != NULL; iter = iter->next)
 +		iter->data = gtk_action_create_menu_item (iter->data);
 +
 +	/* Add menu separators. */
 +
 +	separator = gtk_separator_menu_item_new ();
 +	new_item_actions = g_list_prepend (new_item_actions, separator);
 +	gtk_widget_show (GTK_WIDGET (separator));
 +
 +	separator = gtk_separator_menu_item_new ();
 +	new_source_actions = g_list_prepend (new_source_actions, separator);
 +	gtk_widget_show (GTK_WIDGET (separator));
 +
 +	/* Merge everything into one list, reflecting the menu layout. */
 +
 +	list = g_list_concat (list, new_item_actions);
 +	new_item_actions = NULL;    /* just for clarity */
 +
 +	list = g_list_concat (list, new_source_actions);
 +	new_source_actions = NULL;  /* just for clarity */
 +
 +	/* And finally, build the menu. */
 +
 +	menu = gtk_menu_new ();
 +
 +	for (iter = list; iter != NULL; iter = iter->next)
 +		gtk_menu_shell_append (GTK_MENU_SHELL (menu), iter->data);
 +
 +	g_list_free (list);
 +
 +	return menu;
 +}
 +
 +void
 +e_shell_window_create_switcher_actions (EShellWindow *shell_window)
 +{
 +	GSList *group = NULL;
 +	GtkRadioAction *action;
 +	GtkActionGroup *action_group;
 +	GtkUIManager *ui_manager;
 +	EShellSwitcher *switcher;
 +	EShell *shell;
 +	GList *list, *iter;
 +	guint merge_id;
 +	guint ii = 0;
 +
 +	g_return_if_fail (E_IS_SHELL_WINDOW (shell_window));
 +
 +	action_group = ACTION_GROUP (SWITCHER);
 +	switcher = E_SHELL_SWITCHER (shell_window->priv->switcher);
 +	ui_manager = e_shell_window_get_ui_manager (shell_window);
 +	merge_id = gtk_ui_manager_new_merge_id (ui_manager);
 +	shell = e_shell_window_get_shell (shell_window);
 +	list = e_shell_get_shell_backends (shell);
 +
 +	/* Construct a group of radio actions from the various EShellView
 +	 * subclasses and register them with the EShellSwitcher.  These
 +	 * actions are manifested as switcher buttons and View->Window
 +	 * menu items. */
 +
 +	action = GTK_RADIO_ACTION (ACTION (SWITCHER_INITIAL));
 +	gtk_radio_action_set_group (action, group);
 +	group = gtk_radio_action_get_group (action);
 +
 +	for (iter = list; iter != NULL; iter = iter->next) {
 +		EShellBackend *shell_backend = iter->data;
 +		EShellBackendClass *backend_class;
 +		EShellViewClass *class;
 +		GType view_type;
 +		const gchar *view_name;
 +		gchar *accelerator;
 +		gchar *action_name;
 +		gchar *tooltip;
 +
 +		/* The backend name is also the view name. */
 +		backend_class = E_SHELL_BACKEND_GET_CLASS (shell_backend);
 +		view_type = backend_class->shell_view_type;
 +		view_name = backend_class->name;
 +
 +		if (!g_type_is_a (view_type, E_TYPE_SHELL_VIEW)) {
 +			g_critical (
 +				"%s is not a subclass of %s",
 +				g_type_name (view_type),
 +				g_type_name (E_TYPE_SHELL_VIEW));
 +			continue;
 +		}
 +
 +		class = g_type_class_ref (view_type);
 +
 +		if (class->label == NULL) {
 +			g_critical (
 +				"Label member not set on %s",
 +				G_OBJECT_CLASS_NAME (class));
 +			continue;
 +		}
 +
 +		action_name = g_strdup_printf (SWITCHER_FORMAT, view_name);
 +		tooltip = g_strdup_printf (_("Switch to %s"), class->label);
 +
 +		/* Note, we have to set "icon-name" separately because
 +		 * gtk_radio_action_new() expects a "stock-id".  Sadly,
 +		 * GTK+ still distinguishes between the two. */
 +
 +		action = gtk_radio_action_new (
 +			action_name, class->label,
 +			tooltip, NULL, ii++);
 +
 +		g_object_set (
 +			G_OBJECT (action),
 +			"icon-name", class->icon_name, NULL);
 +
 +		g_object_set_data (
 +			G_OBJECT (action),
 +			"view-name", (gpointer) view_name);
 +
 +		gtk_radio_action_set_group (action, group);
 +		group = gtk_radio_action_get_group (action);
 +
 +		/* The first nine views have accelerators Ctrl+(1-9). */
 +		if (ii < 10)
 +			accelerator = g_strdup_printf ("<Control>%d", ii);
 +		else
 +			accelerator = g_strdup ("");
 +
 +		gtk_action_group_add_action_with_accel (
 +			action_group, GTK_ACTION (action), accelerator);
 +
 +		e_shell_switcher_add_action (switcher, GTK_ACTION (action));
 +
 +		gtk_ui_manager_add_ui (
 +			ui_manager, merge_id,
 +			"/main-menu/view-menu/window-menu",
 +			action_name, action_name,
 +			GTK_UI_MANAGER_AUTO, FALSE);
 +
 +		g_free (accelerator);
 +		g_free (action_name);
 +		g_free (tooltip);
 +
 +		g_type_class_unref (class);
 +	}
 +}
 +
 +void
 +e_shell_window_update_view_menu (EShellWindow *shell_window)
 +{
 +	EShellView *shell_view;
 +	EShellViewClass *shell_view_class;
 +	GtkUIManager *ui_manager;
 +	GtkActionGroup *action_group;
 +	GalViewCollection *view_collection;
 +	GtkRadioAction *radio_action;
 +	GtkAction *action;
 +	GSList *radio_group;
 +	gboolean visible;
 +	const gchar *path;
 +	const gchar *view_id;
 +	const gchar *view_name;
 +	guint merge_id;
 +	gint count, ii;
 +
 +	ui_manager = e_shell_window_get_ui_manager (shell_window);
 +	view_name = e_shell_window_get_active_view (shell_window);
 +	shell_view = e_shell_window_get_shell_view (shell_window, view_name);
 +	g_return_if_fail (shell_view != NULL);
 +
 +	shell_view_class = E_SHELL_VIEW_GET_CLASS (shell_view);
 +	view_collection = shell_view_class->view_collection;
 +	view_id = e_shell_view_get_view_id (shell_view);
 +	g_return_if_fail (view_collection != NULL);
 +
 +	action_group = ACTION_GROUP (GAL_VIEW);
 +	merge_id = shell_window->priv->gal_view_merge_id;
 +
 +	/* Unmerge the previous menu. */
 +	gtk_ui_manager_remove_ui (ui_manager, merge_id);
 +	e_action_group_remove_all_actions (action_group);
 +
 +	/* We have a view ID, so forge ahead. */
 +	count = gal_view_collection_get_count (view_collection);
 +	path = "/main-menu/view-menu/gal-view-menu/gal-view-list";
 +
 +	/* Prevent spurious activations. */
 +	action = ACTION (GAL_CUSTOM_VIEW);
 +	g_signal_handlers_block_matched (
 +		action, G_SIGNAL_MATCH_FUNC, 0, 0,
 +		NULL, action_gal_view_cb, NULL);
 +
 +	/* Default to "Custom View", unless we find our view ID. */
 +	radio_action = GTK_RADIO_ACTION (ACTION (GAL_CUSTOM_VIEW));
 +	gtk_radio_action_set_group (radio_action, NULL);
 +	radio_group = gtk_radio_action_get_group (radio_action);
 +	gtk_radio_action_set_current_value (radio_action, -1);
 +
 +	/* Add a menu item for each view collection item. */
 +	for (ii = 0; ii < count; ii++) {
 +		GalViewCollectionItem *item;
 +		gchar *action_name;
 +		gchar *tooltip;
 +
 +		item = gal_view_collection_get_view_item (view_collection, ii);
 +
 +		action_name = g_strdup_printf (
 +			"gal-view-%s-%d", view_name, ii);
 +		tooltip = g_strdup_printf ("Select view: %s", item->title);
 +
 +		radio_action = gtk_radio_action_new (
 +			action_name, item->title, tooltip, NULL, ii);
 +
 +		action = GTK_ACTION (radio_action);
 +		gtk_radio_action_set_group (radio_action, radio_group);
 +		radio_group = gtk_radio_action_get_group (radio_action);
 +
 +		g_object_set_data_full (
 +			G_OBJECT (radio_action), "view-id",
 +			g_strdup (item->id), (GDestroyNotify) g_free);
 +
 +		if (view_id != NULL && strcmp (item->id, view_id) == 0)
 +			gtk_radio_action_set_current_value (radio_action, ii);
 +
 +		gtk_action_group_add_action (action_group, action);
 +
 +		gtk_ui_manager_add_ui (
 +			ui_manager, merge_id, path, action_name,
 +			action_name, GTK_UI_MANAGER_AUTO, FALSE);
 +
 +		g_free (action_name);
 +		g_free (tooltip);
 +	}
 +
 +	/* Doesn't matter which radio action we check. */
 +	visible = (gtk_radio_action_get_current_value (radio_action) < 0);
 +
 +	action = ACTION (GAL_CUSTOM_VIEW);
 +	gtk_action_set_visible (action, visible);
 +	g_signal_handlers_unblock_matched (
 +		action, G_SIGNAL_MATCH_FUNC, 0, 0,
 +		NULL, action_gal_view_cb, NULL);
 +
 +	action = ACTION (GAL_SAVE_CUSTOM_VIEW);
 +	gtk_action_set_visible (action, visible);
 +}
 +
 +void
 +e_shell_window_update_search_menu (EShellWindow *shell_window)
 +{
 +	EShellContent *shell_content;
 +	EShellView *shell_view;
 +	EShellViewClass *shell_view_class;
 +	RuleContext *context;
 +	FilterRule *rule;
 +	GtkUIManager *ui_manager;
 +	GtkActionGroup *action_group;
 +	const gchar *source;
 +	const gchar *view_name;
 +	gboolean sensitive;
 +	guint merge_id;
 +	gint ii = 0;
 +
 +	ui_manager = e_shell_window_get_ui_manager (shell_window);
 +	view_name = e_shell_window_get_active_view (shell_window);
 +	shell_view = e_shell_window_get_shell_view (shell_window, view_name);
 +	shell_content = e_shell_view_get_shell_content (shell_view);
 +	context = e_shell_content_get_search_context (shell_content);
 +	shell_view_class = E_SHELL_VIEW_GET_CLASS (shell_view);
 +	source = FILTER_SOURCE_INCOMING;
 +
 +	/* Update sensitivity of search actions. */
 +
 +	sensitive = (e_shell_content_get_search_rule (shell_content) != NULL);
 +	gtk_action_set_sensitive (ACTION (SEARCH_CLEAR), sensitive);
 +	gtk_action_set_sensitive (ACTION (SEARCH_SAVE), sensitive);
 +
 +	sensitive = (shell_view_class->search_options != NULL);
 +	gtk_action_set_sensitive (ACTION (SEARCH_OPTIONS), sensitive);
 +
 +	/* Add custom rules to the Search menu. */
 +
 +	action_group = ACTION_GROUP (CUSTOM_RULES);
 +	merge_id = shell_window->priv->custom_rule_merge_id;
 +
 +	/* Unmerge the previous menu. */
 +	gtk_ui_manager_remove_ui (ui_manager, merge_id);
 +	e_action_group_remove_all_actions (action_group);
 +
 +	rule = rule_context_next_rule (context, NULL, source);
 +	while (rule != NULL) {
 +		GtkAction *action;
 +		gchar *action_name;
 +		gchar *action_label;
 +
 +		action_name = g_strdup_printf ("custom-rule-%d", ii++);
 +		if (ii < 10)
 +			action_label = g_strdup_printf (
 +				"_%d. %s", ii, rule->name);
 +		else
 +			action_label = g_strdup (rule->name);
 +
 +		action = gtk_action_new (
 +			action_name, action_label,
 +			_("Execute these search parameters"), NULL);
 +
 +		g_object_set_data_full (
 +			G_OBJECT (action),
 +			"rule", g_object_ref (rule),
 +			(GDestroyNotify) g_object_unref);
 +
 +		g_signal_connect (
 +			action, "activate",
 +			G_CALLBACK (action_custom_rule_cb), shell_window);
 +
 +		gtk_action_group_add_action (action_group, action);
 +
 +		gtk_ui_manager_add_ui (
 +			ui_manager, merge_id,
 +			"/main-menu/search-menu/custom-rules",
 +			action_name, action_name,
 +			GTK_UI_MANAGER_AUTO, FALSE);
 +
 +		g_free (action_name);
 +		g_free (action_label);
 +
 +		rule = rule_context_next_rule (context, rule, source);
 +	}
 +}
diff --cc shell/e-shell-window-actions.h
index 87ae132,0000000..3b8774a
mode 100644,000000..100644
--- a/shell/e-shell-window-actions.h
+++ b/shell/e-shell-window-actions.h
@@@ -1,123 -1,0 +1,123 @@@
 +/*
 + * e-shell-window-actions.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_SHELL_WINDOW_ACTIONS_H
 +#define E_SHELL_WINDOW_ACTIONS_H
 +
 +#define E_SHELL_WINDOW_ACTION(window, name) \
 +	(e_shell_window_get_action (E_SHELL_WINDOW (window), (name)))
 +
 +#define E_SHELL_WINDOW_ACTION_GROUP(window, name) \
 +	(e_shell_window_get_action_group (E_SHELL_WINDOW (window), (name)))
 +
 +/* Actions */
 +#define E_SHELL_WINDOW_ACTION_ABOUT(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "about")
 +#define E_SHELL_WINDOW_ACTION_CLOSE(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "close")
 +#define E_SHELL_WINDOW_ACTION_CONTENTS(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "contents")
 +#define E_SHELL_WINDOW_ACTION_FAQ(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "faq")
 +#define E_SHELL_WINDOW_ACTION_FORGET_PASSWORDS(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "forget-passwords")
 +#define E_SHELL_WINDOW_ACTION_GAL_CUSTOM_VIEW(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "gal-custom-view")
 +#define E_SHELL_WINDOW_ACTION_GAL_DEFINE_VIEWS(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "gal-define-views")
 +#define E_SHELL_WINDOW_ACTION_GAL_SAVE_CUSTOM_VIEW(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "gal-save-custom-view")
 +#define E_SHELL_WINDOW_ACTION_IMPORT(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "import")
 +#define E_SHELL_WINDOW_ACTION_NEW_WINDOW(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "new-window")
 +#define E_SHELL_WINDOW_ACTION_PAGE_SETUP(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "page-setup")
 +#define E_SHELL_WINDOW_ACTION_PREFERENCES(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "preferences")
 +#define E_SHELL_WINDOW_ACTION_QUICK_REFERENCE(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "quick-reference")
 +#define E_SHELL_WINDOW_ACTION_QUIT(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "quit")
 +#define E_SHELL_WINDOW_ACTION_SEARCH_ADVANCED(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "search-advanced")
 +#define E_SHELL_WINDOW_ACTION_SEARCH_CLEAR(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "search-clear")
 +#define E_SHELL_WINDOW_ACTION_SEARCH_EDIT(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "search-edit")
 +#define E_SHELL_WINDOW_ACTION_SEARCH_EXECUTE(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "search-execute")
 +#define E_SHELL_WINDOW_ACTION_SEARCH_OPTIONS(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "search-options")
 +#define E_SHELL_WINDOW_ACTION_SEARCH_SAVE(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "search-save")
 +#define E_SHELL_WINDOW_ACTION_SEND_RECEIVE(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "send-receive")
 +#define E_SHELL_WINDOW_ACTION_SHOW_SIDEBAR(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "show-sidebar")
 +#define E_SHELL_WINDOW_ACTION_SHOW_STATUSBAR(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "show-statusbar")
 +#define E_SHELL_WINDOW_ACTION_SHOW_SWITCHER(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "show-switcher")
 +#define E_SHELL_WINDOW_ACTION_SHOW_TOOLBAR(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "show-toolbar")
 +#define E_SHELL_WINDOW_ACTION_SUBMIT_BUG(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "submit-bug")
 +#define E_SHELL_WINDOW_ACTION_SWITCHER_INITIAL(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "switcher-initial")
 +#define E_SHELL_WINDOW_ACTION_SWITCHER_STYLE_BOTH(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "switcher-style-both")
 +#define E_SHELL_WINDOW_ACTION_SWITCHER_STYLE_ICONS(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "switcher-style-icons")
 +#define E_SHELL_WINDOW_ACTION_SWITCHER_STYLE_TEXT(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "switcher-style-text")
 +#define E_SHELL_WINDOW_ACTION_SWITCHER_STYLE_USER(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "switcher-style-user")
 +#define E_SHELL_WINDOW_ACTION_SYNC_OPTIONS(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "sync-options")
 +#define E_SHELL_WINDOW_ACTION_WORK_OFFLINE(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "work-offline")
 +#define E_SHELL_WINDOW_ACTION_WORK_ONLINE(window) \
 +	E_SHELL_WINDOW_ACTION ((window), "work-online")
 +
 +/* Action Groups */
 +#define E_SHELL_WINDOW_ACTION_GROUP_CUSTOM_RULES(window) \
 +	E_SHELL_WINDOW_ACTION_GROUP ((window), "custom-rules")
 +#define E_SHELL_WINDOW_ACTION_GROUP_GAL_VIEW(window) \
 +	E_SHELL_WINDOW_ACTION_GROUP ((window), "gal-view")
 +#define E_SHELL_WINDOW_ACTION_GROUP_LOCKDOWN_APPLICATION_HANDLERS(window) \
 +	E_SHELL_WINDOW_ACTION_GROUP ((window), "lockdown-application-handlers")
 +#define E_SHELL_WINDOW_ACTION_GROUP_LOCKDOWN_PRINTING(window) \
 +	E_SHELL_WINDOW_ACTION_GROUP ((window), "lockdown-printing")
 +#define E_SHELL_WINDOW_ACTION_GROUP_LOCKDOWN_PRINT_SETUP(window) \
 +	E_SHELL_WINDOW_ACTION_GROUP ((window), "lockdown-print-setup")
 +#define E_SHELL_WINDOW_ACTION_GROUP_LOCKDOWN_SAVE_TO_DISK(window) \
 +	E_SHELL_WINDOW_ACTION_GROUP ((window), "lockdown-save-to-disk")
 +#define E_SHELL_WINDOW_ACTION_GROUP_NEW_ITEM(window) \
 +	E_SHELL_WINDOW_ACTION_GROUP ((window), "new-item")
 +#define E_SHELL_WINDOW_ACTION_GROUP_NEW_SOURCE(window) \
 +	E_SHELL_WINDOW_ACTION_GROUP ((window), "new-source")
 +#define E_SHELL_WINDOW_ACTION_GROUP_SHELL(window) \
 +	E_SHELL_WINDOW_ACTION_GROUP ((window), "shell")
 +#define E_SHELL_WINDOW_ACTION_GROUP_SWITCHER(window) \
 +	E_SHELL_WINDOW_ACTION_GROUP ((window), "switcher")
 +
 +#endif /* E_SHELL_WINDOW_ACTIONS_H */
diff --cc shell/e-shell-window-private.c
index 38d3926,0000000..bb74e35
mode 100644,000000..100644
--- a/shell/e-shell-window-private.c
+++ b/shell/e-shell-window-private.c
@@@ -1,575 -1,0 +1,575 @@@
 +/*
 + * e-shell-window-private.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-shell-window-private.h"
 +
 +static void
 +shell_window_save_switcher_style_cb (GtkRadioAction *action,
 +                                     GtkRadioAction *current,
 +                                     EShellWindow *shell_window)
 +{
 +	EShell *shell;
 +	GConfClient *client;
 +	GtkToolbarStyle style;
 +	const gchar *key;
 +	const gchar *string;
 +	GError *error = NULL;
 +
 +	shell = e_shell_window_get_shell (shell_window);
 +	client = e_shell_get_gconf_client (shell);
 +
 +	style = gtk_radio_action_get_current_value (action);
 +	key = "/apps/evolution/shell/view_defaults/buttons_style";
 +
 +	switch (style) {
 +		case GTK_TOOLBAR_ICONS:
 +			string = "icons";
 +			break;
 +
 +		case GTK_TOOLBAR_TEXT:
 +			string = "text";
 +			break;
 +
 +		case GTK_TOOLBAR_BOTH:
 +		case GTK_TOOLBAR_BOTH_HORIZ:
 +			string = "both";
 +			break;
 +
 +		default:
 +			string = "toolbar";
 +			break;
 +	}
 +
 +	if (!gconf_client_set_string (client, key, string, &error)) {
 +		g_warning ("%s", error->message);
 +		g_error_free (error);
 +	}
 +}
 +
 +static void
 +shell_window_init_switcher_style (EShellWindow *shell_window)
 +{
 +	EShell *shell;
 +	GtkAction *action;
 +	GConfClient *client;
 +	GtkToolbarStyle style;
 +	const gchar *key;
 +	gchar *string;
 +	GError *error = NULL;
 +
 +	/* XXX GConfBridge doesn't let you convert between numeric properties
 +	 *     and string keys, so we have to create the binding manually. */
 +
 +	shell = e_shell_window_get_shell (shell_window);
 +	client = e_shell_get_gconf_client (shell);
 +
 +	action = ACTION (SWITCHER_STYLE_ICONS);
 +	key = "/apps/evolution/shell/view_defaults/buttons_style";
 +	string = gconf_client_get_string (client, key, &error);
 +
 +	if (string != NULL) {
 +		if (strcmp (string, "icons") == 0)
 +			style = GTK_TOOLBAR_ICONS;
 +		else if (strcmp (string, "text") == 0)
 +			style = GTK_TOOLBAR_TEXT;
 +		else if (strcmp (string, "both") == 0)
 +			style = GTK_TOOLBAR_BOTH_HORIZ;
 +		else
 +			style = -1;
 +
 +		gtk_radio_action_set_current_value (
 +			GTK_RADIO_ACTION (action), style);
 +	}
 +
 +	g_signal_connect (
 +		action, "changed",
 +		G_CALLBACK (shell_window_save_switcher_style_cb),
 +		shell_window);
 +}
 +
 +static void
 +shell_window_menu_item_select_cb (EShellWindow *shell_window,
 +                                  GtkWidget *menu_item)
 +{
 +	GtkAction *action;
 +	GtkLabel *label;
 +	gchar *tooltip = NULL;
 +
 +	action = g_object_get_data (G_OBJECT (menu_item), "action");
 +	g_return_if_fail (GTK_IS_ACTION (action));
 +
 +	g_object_get (action, "tooltip", &tooltip, NULL);
 +
 +	if (tooltip == NULL)
 +		return;
 +
 +	label = GTK_LABEL (shell_window->priv->tooltip_label);
 +	gtk_label_set_text (label, tooltip);
 +	g_free (tooltip);
 +
 +	gtk_widget_show (shell_window->priv->tooltip_label);
 +	gtk_widget_hide (shell_window->priv->status_notebook);
 +}
 +
 +static void
 +shell_window_menu_item_deselect_cb (EShellWindow *shell_window)
 +{
 +	gtk_widget_hide (shell_window->priv->tooltip_label);
 +	gtk_widget_show (shell_window->priv->status_notebook);
 +}
 +
 +static void
 +shell_window_connect_proxy_cb (EShellWindow *shell_window,
 +                               GtkAction *action,
 +                               GtkWidget *proxy)
 +{
 +	if (!GTK_IS_MENU_ITEM (proxy))
 +		return;
 +
 +	g_object_set_data_full (
 +		G_OBJECT (proxy),
 +		"action", g_object_ref (action),
 +		(GDestroyNotify) g_object_unref);
 +
 +	g_signal_connect_swapped (
 +		proxy, "select",
 +		G_CALLBACK (shell_window_menu_item_select_cb),
 +		shell_window);
 +
 +	g_signal_connect_swapped (
 +		proxy, "deselect",
 +		G_CALLBACK (shell_window_menu_item_deselect_cb),
 +		shell_window);
 +}
 +
 +static void
 +shell_window_online_button_clicked_cb (EOnlineButton *button,
 +                                       EShellWindow *shell_window)
 +{
 +	if (e_online_button_get_online (button))
 +		gtk_action_activate (ACTION (WORK_OFFLINE));
 +	else
 +		gtk_action_activate (ACTION (WORK_ONLINE));
 +}
 +
 +void
 +e_shell_window_private_init (EShellWindow *shell_window)
 +{
 +	EShellWindowPrivate *priv = shell_window->priv;
 +	GHashTable *loaded_views;
 +	GArray *signal_handler_ids;
 +	GtkAccelGroup *accel_group;
 +	GtkToolItem *item;
 +	GtkWidget *container;
 +	GtkWidget *widget;
 +	guint merge_id;
 +	gint height;
 +
 +	loaded_views = g_hash_table_new_full (
 +		g_str_hash, g_str_equal,
 +		(GDestroyNotify) g_free,
 +		(GDestroyNotify) g_object_unref);
 +
 +	signal_handler_ids = g_array_new (FALSE, FALSE, sizeof (gulong));
 +
 +	priv->ui_manager = gtk_ui_manager_new ();
 +	priv->loaded_views = loaded_views;
 +	priv->active_view = "unknown";
 +	priv->signal_handler_ids = signal_handler_ids;
 +
 +	e_shell_window_add_action_group (shell_window, "shell");
 +	e_shell_window_add_action_group (shell_window, "gal-view");
 +	e_shell_window_add_action_group (shell_window, "new-item");
 +	e_shell_window_add_action_group (shell_window, "new-source");
 +	e_shell_window_add_action_group (shell_window, "custom-rules");
 +	e_shell_window_add_action_group (shell_window, "switcher");
 +	e_shell_window_add_action_group (shell_window, "lockdown-application-handlers");
 +	e_shell_window_add_action_group (shell_window, "lockdown-printing");
 +	e_shell_window_add_action_group (shell_window, "lockdown-print-setup");
 +	e_shell_window_add_action_group (shell_window, "lockdown-save-to-disk");
 +
 +	merge_id = gtk_ui_manager_new_merge_id (priv->ui_manager);
 +	priv->custom_rule_merge_id = merge_id;
 +
 +	merge_id = gtk_ui_manager_new_merge_id (priv->ui_manager);
 +	priv->gal_view_merge_id = merge_id;
 +
 +	e_shell_window_actions_init (shell_window);
 +
 +	accel_group = gtk_ui_manager_get_accel_group (priv->ui_manager);
 +	gtk_window_add_accel_group (GTK_WINDOW (shell_window), accel_group);
 +
 +	g_signal_connect_swapped (
 +		priv->ui_manager, "connect-proxy",
 +		G_CALLBACK (shell_window_connect_proxy_cb), shell_window);
 +
 +	/* Construct window widgets. */
 +
 +	widget = gtk_vbox_new (FALSE, 0);
 +	gtk_container_add (GTK_CONTAINER (shell_window), widget);
 +	gtk_widget_show (widget);
 +
 +	container = widget;
 +
 +	widget = e_shell_window_get_managed_widget (
 +		shell_window, "/main-menu");
 +	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
 +	priv->main_menu = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	widget = e_shell_window_get_managed_widget (
 +		shell_window, "/main-toolbar");
 +	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
 +	priv->main_toolbar = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	/* XXX Having this separator in the UI definition doesn't work
 +	 *     because GtkUIManager is unaware of the "New" button, so
 +	 *     it makes the separator invisible.  One possibility is to
 +	 *     define a GtkAction subclass for which create_tool_item()
 +	 *     returns an EMenuToolButton.  Then both this separator
 +	 *     and the "New" button could be added to the UI definition.
 +	 *     Tempting, but the "New" button and its dynamically
 +	 *     generated menu is already a complex beast, and I'm not
 +	 *     convinced having it proxy some new type of GtkAction
 +	 *     is worth the extra effort. */
 +	item = gtk_separator_tool_item_new ();
 +	gtk_toolbar_insert (GTK_TOOLBAR (widget), item, 0);
 +	gtk_widget_show (GTK_WIDGET (item));
 +
 +	item = e_menu_tool_button_new (_("New"));
 +	gtk_tool_item_set_is_important (GTK_TOOL_ITEM (item), TRUE);
 +	gtk_widget_add_accelerator (
 +		GTK_WIDGET (item), "clicked",
 +		gtk_ui_manager_get_accel_group (priv->ui_manager),
 +		GDK_N, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
 +	gtk_toolbar_insert (GTK_TOOLBAR (widget), item, 0);
 +	priv->menu_tool_button = g_object_ref (item);
 +	gtk_widget_show (GTK_WIDGET (item));
 +
 +	widget = gtk_hpaned_new ();
 +	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
 +	priv->content_pane = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	widget = gtk_hbox_new (FALSE, 3);
 +	gtk_container_set_border_width (GTK_CONTAINER (widget), 3);
 +	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
 +	priv->status_area = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	/* Make the status area as large as the task bar. */
 +	gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, NULL, &height);
 +	gtk_widget_set_size_request (widget, -1, (height * 2) + 6);
 +
 +	container = priv->content_pane;
 +
 +	widget = e_shell_switcher_new ();
 +	gtk_paned_pack1 (GTK_PANED (container), widget, FALSE, FALSE);
 +	priv->switcher = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	widget = gtk_notebook_new ();
 +	gtk_notebook_set_show_tabs (GTK_NOTEBOOK (widget), FALSE);
 +	gtk_notebook_set_show_border (GTK_NOTEBOOK (widget), FALSE);
 +	gtk_paned_pack2 (GTK_PANED (container), widget, TRUE, TRUE);
 +	priv->content_notebook = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	container = priv->switcher;
 +
 +	widget = gtk_notebook_new ();
 +	gtk_notebook_set_show_tabs (GTK_NOTEBOOK (widget), FALSE);
 +	gtk_notebook_set_show_border (GTK_NOTEBOOK (widget), FALSE);
 +	gtk_container_add (GTK_CONTAINER (container), widget);
 +	priv->sidebar_notebook = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	container = priv->status_area;
 +
 +	widget = e_online_button_new ();
 +	g_signal_connect (
 +		widget, "clicked",
 +		G_CALLBACK (shell_window_online_button_clicked_cb),
 +		shell_window);
 +	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, TRUE, 0);
 +	priv->online_button = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	widget = gtk_label_new ("");
 +	gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
 +	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
 +	priv->tooltip_label = g_object_ref (widget);
 +	gtk_widget_hide (widget);
 +
 +	widget = gtk_notebook_new ();
 +	gtk_notebook_set_show_tabs (GTK_NOTEBOOK (widget), FALSE);
 +	gtk_notebook_set_show_border (GTK_NOTEBOOK (widget), FALSE);
 +	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
 +	priv->status_notebook = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +}
 +
 +void
 +e_shell_window_private_constructed (EShellWindow *shell_window)
 +{
 +	EShellWindowPrivate *priv = shell_window->priv;
 +	EShellSettings *shell_settings;
 +	EShell *shell;
 +	GConfBridge *bridge;
 +	GtkActionGroup *action_group;
 +	GtkAction *action;
 +	GObject *object;
 +	const gchar *key;
 +
 +	shell = e_shell_window_get_shell (shell_window);
 +	shell_settings = e_shell_get_shell_settings (shell);
 +
 +	e_shell_watch_window (shell, GTK_WINDOW (shell_window));
 +
 +	/* Create the switcher actions before we set the initial
 +	 * shell view, because the shell view relies on them for
 +	 * default settings during construction. */
 +	e_shell_window_create_switcher_actions (shell_window);
 +
 +	/* Support lockdown. */
 +
 +	action_group = ACTION_GROUP (LOCKDOWN_PRINTING);
 +
 +	e_binding_new_with_negation (
 +		G_OBJECT (shell_settings), "disable-printing",
 +		G_OBJECT (action_group), "sensitive");
 +
 +	action_group = ACTION_GROUP (LOCKDOWN_PRINT_SETUP);
 +
 +	e_binding_new_with_negation (
 +		G_OBJECT (shell_settings), "disable-print-setup",
 +		G_OBJECT (action_group), "sensitive");
 +
 +	action_group = ACTION_GROUP (LOCKDOWN_SAVE_TO_DISK);
 +
 +	e_binding_new_with_negation (
 +		G_OBJECT (shell_settings), "disable-save-to-disk",
 +		G_OBJECT (action_group), "sensitive");
 +
 +	/* Bind GObject properties to GObject properties. */
 +
 +	action = ACTION (SEND_RECEIVE);
 +
 +	e_binding_new (
 +		G_OBJECT (shell), "online",
 +		G_OBJECT (action), "sensitive");
 +
 +	action = ACTION (WORK_OFFLINE);
 +
 +	e_binding_new (
 +		G_OBJECT (shell), "online",
 +		G_OBJECT (action), "visible");
 +
 +	action = ACTION (WORK_ONLINE);
 +
 +	e_binding_new_with_negation (
 +		G_OBJECT (shell), "online",
 +		G_OBJECT (action), "visible");
 +
 +	e_binding_new (
 +		G_OBJECT (shell), "online",
 +		G_OBJECT (shell_window->priv->online_button), "online");
 +
 +	/* Bind GObject properties to GConf keys. */
 +
 +	bridge = gconf_bridge_get ();
 +
 +	key = "/apps/evolution/shell/view_defaults/window";
 +	gconf_bridge_bind_window (
 +		bridge, key, GTK_WINDOW (shell_window), TRUE, FALSE);
 +
 +	object = G_OBJECT (shell_window);
 +	key = "/apps/evolution/shell/view_defaults/component_id";
 +	gconf_bridge_bind_property (bridge, key, object, "active-view");
 +
 +	object = G_OBJECT (priv->content_pane);
 +	key = "/apps/evolution/shell/view_defaults/folder_bar/width";
 +	gconf_bridge_bind_property_delayed (bridge, key, object, "position");
 +
 +	object = G_OBJECT (ACTION (SHOW_SIDEBAR));
 +	key = "/apps/evolution/shell/view_defaults/sidebar_visible";
 +	gconf_bridge_bind_property (bridge, key, object, "active");
 +
 +	object = G_OBJECT (ACTION (SHOW_STATUSBAR));
 +	key = "/apps/evolution/shell/view_defaults/statusbar_visible";
 +	gconf_bridge_bind_property (bridge, key, object, "active");
 +
 +	object = G_OBJECT (ACTION (SHOW_SWITCHER));
 +	key = "/apps/evolution/shell/view_defaults/buttons_visible";
 +	gconf_bridge_bind_property (bridge, key, object, "active");
 +
 +	object = G_OBJECT (ACTION (SHOW_TOOLBAR));
 +	key = "/apps/evolution/shell/view_defaults/toolbar_visible";
 +	gconf_bridge_bind_property (bridge, key, object, "active");
 +
 +	shell_window_init_switcher_style (shell_window);
 +}
 +
 +void
 +e_shell_window_private_dispose (EShellWindow *shell_window)
 +{
 +	EShellWindowPrivate *priv = shell_window->priv;
 +
 +	/* Need to disconnect handlers before we unref the shell. */
 +	if (priv->signal_handler_ids != NULL) {
 +		GArray *array = priv->signal_handler_ids;
 +		gulong handler_id;
 +		guint ii;
 +
 +		for (ii = 0; ii < array->len; ii++) {
 +			handler_id = g_array_index (array, gulong, ii);
 +			g_signal_handler_disconnect (priv->shell, handler_id);
 +		}
 +
 +		g_array_free (array, TRUE);
 +		priv->signal_handler_ids = NULL;
 +	}
 +
 +	DISPOSE (priv->ui_manager);
 +
 +	g_hash_table_remove_all (priv->loaded_views);
 +
 +	DISPOSE (priv->main_menu);
 +	DISPOSE (priv->main_toolbar);
 +	DISPOSE (priv->menu_tool_button);
 +	DISPOSE (priv->content_pane);
 +	DISPOSE (priv->content_notebook);
 +	DISPOSE (priv->sidebar_notebook);
 +	DISPOSE (priv->switcher);
 +	DISPOSE (priv->status_area);
 +	DISPOSE (priv->online_button);
 +	DISPOSE (priv->tooltip_label);
 +	DISPOSE (priv->status_notebook);
 +
 +	priv->destroyed = TRUE;
 +}
 +
 +void
 +e_shell_window_private_finalize (EShellWindow *shell_window)
 +{
 +	EShellWindowPrivate *priv = shell_window->priv;
 +
 +	g_hash_table_destroy (priv->loaded_views);
 +}
 +
 +void
 +e_shell_window_switch_to_view (EShellWindow *shell_window,
 +                               const gchar *view_name)
 +{
 +	GtkNotebook *notebook;
 +	EShellView *shell_view;
 +	gint page_num;
 +
 +	g_return_if_fail (E_IS_SHELL_WINDOW (shell_window));
 +	g_return_if_fail (view_name != NULL);
 +
 +	shell_view = e_shell_window_get_shell_view (shell_window, view_name);
 +
 +	page_num = e_shell_view_get_page_num (shell_view);
 +	g_return_if_fail (page_num >= 0);
 +
 +	notebook = GTK_NOTEBOOK (shell_window->priv->content_notebook);
 +	gtk_notebook_set_current_page (notebook, page_num);
 +
 +	notebook = GTK_NOTEBOOK (shell_window->priv->sidebar_notebook);
 +	gtk_notebook_set_current_page (notebook, page_num);
 +
 +	notebook = GTK_NOTEBOOK (shell_window->priv->status_notebook);
 +	gtk_notebook_set_current_page (notebook, page_num);
 +
 +	shell_window->priv->active_view = view_name;
 +	g_object_notify (G_OBJECT (shell_window), "active-view");
 +
 +	e_shell_window_update_icon (shell_window);
 +	e_shell_window_update_title (shell_window);
 +	e_shell_window_update_new_menu (shell_window);
 +	e_shell_window_update_view_menu (shell_window);
 +	e_shell_window_update_search_menu (shell_window);
 +
 +	e_shell_view_update_actions (shell_view);
 +}
 +
 +void
 +e_shell_window_update_icon (EShellWindow *shell_window)
 +{
 +	EShellView *shell_view;
 +	GtkAction *action;
 +	const gchar *view_name;
 +	gchar *icon_name = NULL;
 +
 +	g_return_if_fail (E_IS_SHELL_WINDOW (shell_window));
 +
 +	view_name = e_shell_window_get_active_view (shell_window);
 +	shell_view = e_shell_window_get_shell_view (shell_window, view_name);
 +
 +	action = e_shell_view_get_action (shell_view);
 +	g_object_get (action, "icon-name", &icon_name, NULL);
 +	gtk_window_set_icon_name (GTK_WINDOW (shell_window), icon_name);
 +	g_free (icon_name);
 +}
 +
 +void
 +e_shell_window_update_title (EShellWindow *shell_window)
 +{
 +	EShellView *shell_view;
 +	const gchar *view_title;
 +	const gchar *view_name;
 +	gchar *window_title;
 +
 +	g_return_if_fail (E_IS_SHELL_WINDOW (shell_window));
 +
 +	view_name = e_shell_window_get_active_view (shell_window);
 +	shell_view = e_shell_window_get_shell_view (shell_window, view_name);
 +	view_title = e_shell_view_get_title (shell_view);
 +
 +	/* Translators: This is used for the main window title. */
 +	window_title = g_strdup_printf (_("%s - Evolution"), view_title);
 +	gtk_window_set_title (GTK_WINDOW (shell_window), window_title);
 +	g_free (window_title);
 +}
 +
 +void
 +e_shell_window_update_new_menu (EShellWindow *shell_window)
 +{
 +	GtkWidget *menu;
 +	GtkWidget *widget;
 +	const gchar *path;
 +
 +	g_return_if_fail (E_IS_SHELL_WINDOW (shell_window));
 +
 +	/* Update the "File -> New" submenu. */
 +	path = "/main-menu/file-menu/new-menu";
 +	menu = e_shell_window_create_new_menu (shell_window);
 +	widget = e_shell_window_get_managed_widget (shell_window, path);
 +	gtk_menu_item_set_submenu (GTK_MENU_ITEM (widget), menu);
 +	gtk_widget_show (widget);
 +
 +	/* Update the "New" menu tool button submenu. */
 +	menu = e_shell_window_create_new_menu (shell_window);
 +	widget = shell_window->priv->menu_tool_button;
 +	gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (widget), menu);
 +}
diff --cc shell/e-shell-window-private.h
index 3ac0388,0000000..b0bfe7c
mode 100644,000000..100644
--- a/shell/e-shell-window-private.h
+++ b/shell/e-shell-window-private.h
@@@ -1,127 -1,0 +1,127 @@@
 +/*
 + * e-shell-window-private.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_SHELL_WINDOW_PRIVATE_H
 +#define E_SHELL_WINDOW_PRIVATE_H
 +
 +#include "e-shell-window.h"
 +
 +#include <string.h>
 +#include <glib/gi18n.h>
 +
 +#include <e-util/e-util.h>
 +#include <e-util/e-binding.h>
 +#include <e-util/gconf-bridge.h>
 +#include <widgets/misc/e-menu-tool-button.h>
 +#include <widgets/misc/e-online-button.h>
 +
 +#include <e-shell.h>
 +#include <e-shell-content.h>
 +#include <e-shell-view.h>
 +#include <e-shell-switcher.h>
 +#include <e-shell-window-actions.h>
 +
 +#define E_SHELL_WINDOW_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_SHELL_WINDOW, EShellWindowPrivate))
 +
 +/* Shorthand, requires a variable named "shell_window". */
 +#define ACTION(name) \
 +	(E_SHELL_WINDOW_ACTION_##name (shell_window))
 +#define ACTION_GROUP(name) \
 +	(E_SHELL_WINDOW_ACTION_GROUP_##name (shell_window))
 +
 +/* For use in dispose() methods. */
 +#define DISPOSE(obj) \
 +	G_STMT_START { \
 +	if ((obj) != NULL) { g_object_unref (obj); (obj) = NULL; } \
 +	} G_STMT_END
 +
 +/* Format for switcher action names.
 + * The last part is the shell view name.
 + * (e.g. switch-to-mail, switch-to-calendar) */
 +#define SWITCHER_FORMAT		"switch-to-%s"
 +
 +G_BEGIN_DECLS
 +
 +struct _EShellWindowPrivate {
 +
 +	gpointer shell;  /* weak pointer */
 +
 +	/*** UI Management ***/
 +
 +	GtkUIManager *ui_manager;
 +	guint custom_rule_merge_id;
 +	guint gal_view_merge_id;
 +
 +	/*** Shell Views ***/
 +
 +	GHashTable *loaded_views;
 +	const gchar *active_view;
 +
 +	/*** Widgetry ***/
 +
 +	GtkWidget *main_menu;
 +	GtkWidget *main_toolbar;
 +	GtkWidget *menu_tool_button;
 +	GtkWidget *content_pane;
 +	GtkWidget *content_notebook;
 +	GtkWidget *sidebar_notebook;
 +	GtkWidget *switcher;
 +	GtkWidget *status_area;
 +	GtkWidget *online_button;
 +	GtkWidget *tooltip_label;
 +	GtkWidget *status_notebook;
 +
 +	/* Miscellaneous */
 +
 +	/* Shell signal handlers. */
 +	GArray *signal_handler_ids;
 +
 +	guint destroyed : 1;  /* XXX Do we still need this? */
 +	guint safe_mode : 1;
 +};
 +
 +void		e_shell_window_private_init	(EShellWindow *shell_window);
 +void		e_shell_window_private_constructed
 +						(EShellWindow *shell_window);
 +void		e_shell_window_private_dispose	(EShellWindow *shell_window);
 +void		e_shell_window_private_finalize	(EShellWindow *shell_window);
 +
 +/* Private Utilities */
 +
 +void		e_shell_window_actions_init	(EShellWindow *shell_window);
 +void		e_shell_window_switch_to_view	(EShellWindow *shell_window,
 +						 const gchar *view_name);
 +GtkWidget *	e_shell_window_create_new_menu	(EShellWindow *shell_window);
 +void		e_shell_window_create_switcher_actions
 +						(EShellWindow *shell_window);
 +void		e_shell_window_update_gal_view	(EShellWindow *shell_window);
 +void		e_shell_window_update_icon	(EShellWindow *shell_window);
 +void		e_shell_window_update_title	(EShellWindow *shell_window);
 +void		e_shell_window_update_new_menu	(EShellWindow *shell_window);
 +void		e_shell_window_update_view_menu	(EShellWindow *shell_window);
 +void		e_shell_window_update_search_menu
 +						(EShellWindow *shell_window);
 +
 +G_END_DECLS
 +
 +#endif /* E_SHELL_WINDOW_PRIVATE_H */
diff --cc shell/e-shell-window.c
index c39d856,83e537c..bb913f7
--- a/shell/e-shell-window.c
+++ b/shell/e-shell-window.c
@@@ -12,9 -10,12 +12,9 @@@
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
+  * License along with the program; if not, see <http://www.gnu.org/licenses/>
   *
   *
 - * Authors:
 - *		Ettore Perazzoli <ettore ximian com>
 - *
   * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
   *
   */
diff --cc shell/e-shell-window.h
index d78fb19,869352b..b867490
--- a/shell/e-shell-window.h
+++ b/shell/e-shell-window.h
@@@ -12,9 -11,12 +12,9 @@@
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
+  * License along with the program; if not, see <http://www.gnu.org/licenses/>
   *
   *
 - * Authors:
 - *		Ettore Perazzoli <ettore ximian com>
 - *
   * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
   *
   */
diff --cc shell/e-shell.c
index d95853d,9b4e6bc..7854853
--- a/shell/e-shell.c
+++ b/shell/e-shell.c
@@@ -12,9 -10,12 +12,9 @@@
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
+  * License along with the program; if not, see <http://www.gnu.org/licenses/>
   *
   *
 - * Authors:
 - *		Ettore Perazzoli <ettore ximian com>
 - *
   * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
   *
   */
diff --cc shell/e-shell.h
index c76b649,e8451e3..1d0b9ab
--- a/shell/e-shell.h
+++ b/shell/e-shell.h
@@@ -12,9 -10,12 +12,9 @@@
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
+  * License along with the program; if not, see <http://www.gnu.org/licenses/>
   *
   *
 - * Authors:
 - *		Ettore Perazzoli <ettore ximian com>
 - *
   * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
   *
   */
diff --cc shell/main.c
index c71d686,c6959d7..928a321
--- a/shell/main.c
+++ b/shell/main.c
@@@ -465,174 -562,6 +466,174 @@@ set_paths (void
  }
  #endif
  
 +static void
 +shell_window_destroyed_cb (EShell *shell)
 +{
 +	if (e_shell_get_watched_windows (shell) == NULL)
 +		gtk_main_quit ();
 +}
 +
 +static gint
 +master_client_save_yourself_cb (GnomeClient *client,
 +                                GnomeSaveStyle save_style,
 +                                gint shutdown,
 +                                GnomeInteractStyle interact_style,
 +                                gint fast,
 +                                gpointer user_data)
 +{
 +	EShell *shell = user_data;
 +
 +	return !e_shell_is_busy (shell);
 +}
 +
 +static void
 +master_client_die_cb (GnomeClient *client,
 +                      gpointer user_data)
 +{
 +	EShell *shell = user_data;
 +
 +	e_shell_do_quit (shell);
 +}
 +
 +/* taken from nautilus */
 +static guint32
 +slowly_and_stupidly_obtain_timestamp (GdkDisplay *display)
 +{
 +	Display *xdisplay;
 +	Window xwindow;
 +	XEvent event;
 +	XSetWindowAttributes attrs;
 +	Atom atom_name;
 +	Atom atom_type;
- 	char *name;
++	const gchar *name;
 +
 +	xdisplay = GDK_DISPLAY_XDISPLAY (display);
 +
 +	attrs.override_redirect = True;
 +	attrs.event_mask = PropertyChangeMask | StructureNotifyMask;
 +
 +	xwindow = XCreateWindow (
 +		xdisplay, RootWindow (xdisplay, 0),
 +		-100, -100, 1, 1,
 +		0,
 +		CopyFromParent,
 +		CopyFromParent,
 +		CopyFromParent,
 +		CWOverrideRedirect | CWEventMask,
 +		&attrs);
 +
 +	atom_name = XInternAtom (xdisplay, "WM_NAME", TRUE);
 +	g_assert (atom_name != None);
 +
 +	atom_type = XInternAtom (xdisplay, "STRING", TRUE);
 +	g_assert (atom_type != None);
 +
 +	name = "Fake Window";
 +	XChangeProperty (
 +		xdisplay, xwindow, atom_name, atom_type,
 +		8, PropModeReplace, (unsigned char *) name,
 +		strlen (name));
 +
 +	XWindowEvent (
 +		xdisplay, xwindow, PropertyChangeMask, &event);
 +
 +	XDestroyWindow (xdisplay, xwindow);
 +
 +	return event.xproperty.time;
 +}
 +
 +static gchar *
 +pick_startup_id (void)
 +{
 +	GdkDisplay *display;
 +	const gchar *startup_id;
 +	gchar *id;
 +
 +	/* XXX This copies logic from unique_app_new(), which we can't use
 +	 *     because we're subclassing UniqueApp.  I already sent ebassi
 +	 *     a patch to fix this. */
 +
 +	display = gdk_display_get_default ();
 +
 +	/* Try and get the startup notification ID from GDK, the
 +	 * environment or, if everything else failed, fake one. */
 +	startup_id = gdk_x11_display_get_startup_notification_id (display);
 +
 +	if (!startup_id || startup_id[0] == '\0')
 +		startup_id = g_getenv ("DESKTOP_STARTUP_ID");
 +
 +	if (!startup_id || startup_id[0] == '\0') {
 +		guint32 timestamp;
 +
 +		timestamp = slowly_and_stupidly_obtain_timestamp (display);
 +		id = g_strdup_printf ("_TIME%lu", (gulong) timestamp);
 +	} else
 +		id = g_strdup (startup_id);
 +
 +	return id;
 +}
 +
 +static void
 +create_default_shell (void)
 +{
 +	EShell *shell;
 +	GConfClient *conf_client;
 +	GnomeClient *master_client;
 +	gboolean online = TRUE;
 +	gchar *startup_id;
 +	GError *error = NULL;
 +
 +	conf_client = gconf_client_get_default ();
 +	master_client = gnome_master_client ();
 +
 +	if (start_online)
 +		online = TRUE;
 +	else if (start_offline)
 +		online = FALSE;
 +	else {
 +		const gchar *key;
 +		gboolean value;
 +
 +		key = "/apps/evolution/shell/start_offline";
 +		value = gconf_client_get_bool (conf_client, key, &error);
 +		if (error == NULL)
 +			online = !value;
 +		else {
 +			g_warning ("%s", error->message);
 +			g_error_free (error);
 +		}
 +	}
 +
 +	startup_id = pick_startup_id ();
 +
 +	shell = g_object_new (
 +		E_TYPE_SHELL,
 +		"name", "org.gnome.evolution",
 +		"online", online,
 +		"startup-id", startup_id,
 +		NULL);
 +
 +	g_free (startup_id);
 +
 +	g_signal_connect (
 +		shell, "window-destroyed",
 +		G_CALLBACK (shell_window_destroyed_cb), NULL);
 +
 +	if (master_client != NULL) {
 +		g_signal_connect (
 +			master_client, "save_yourself",
 +			G_CALLBACK (master_client_save_yourself_cb), shell);
 +
 +		g_signal_connect (
 +			master_client, "die",
 +			G_CALLBACK (master_client_die_cb), shell);
 +	}
 +
 +	g_object_unref (conf_client);
 +
 +	default_shell = shell;
 +}
 +
  int
  main (int argc, char **argv)
  {
diff --cc shell/test/e-test-shell-backend.c
index 0fc6c20,0000000..e5fd3c6
mode 100644,000000..100644
--- a/shell/test/e-test-shell-backend.c
+++ b/shell/test/e-test-shell-backend.c
@@@ -1,240 -1,0 +1,240 @@@
 +/*
 + * e-test-shell-backend.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-test-shell-backend.h"
 +
 +#include <glib/gi18n.h>
 +
 +#include "shell/e-shell.h"
 +#include "shell/e-shell-window.h"
 +
 +#include "e-test-shell-view.h"
 +
 +#define E_TEST_SHELL_BACKEND_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_TEST_SHELL_BACKEND, ETestShellBackendPrivate))
 +
 +struct _ETestShellBackendPrivate {
 +	gint placeholder;
 +};
 +
 +static gpointer parent_class;
 +static GType test_shell_backend_type;
 +
 +static void
 +action_test_item_new_cb (GtkAction *action,
 +                         EShellWindow *shell_window)
 +{
 +	g_debug ("%s", G_STRFUNC);
 +}
 +
 +static void
 +action_test_source_new_cb (GtkAction *action,
 +                           EShellWindow *shell_window)
 +{
 +	g_debug ("%s", G_STRFUNC);
 +}
 +
 +static GtkActionEntry item_entries[] = {
 +
 +	{ "test-item-new",
 +	  "document-new",
 +	  NC_("New", "_Test Item"),
 +	  NULL,
 +	  N_("Create a new test item"),
 +	  G_CALLBACK (action_test_item_new_cb) }
 +};
 +
 +static GtkActionEntry source_entries[] = {
 +
 +	{ "test-source-new",
 +	  "folder-new",
 +	  NC_("New", "Test _Source"),
 +	  NULL,
 +	  N_("Create a new test source"),
 +	  G_CALLBACK (action_test_source_new_cb) }
 +};
 +
 +static void
 +test_shell_backend_start (EShellBackend *shell_backend)
 +{
 +	g_debug ("%s", G_STRFUNC);
 +}
 +
 +static gboolean
 +test_shell_backend_is_busy (EShellBackend *shell_backend)
 +{
 +	g_debug ("%s", G_STRFUNC);
 +
 +	return FALSE;
 +}
 +
 +static gboolean
 +test_shell_backend_shutdown (EShellBackend *shell_backend)
 +{
 +	g_debug ("%s", G_STRFUNC);
 +
 +	return TRUE;
 +}
 +
 +static gboolean
 +test_shell_backend_migrate (EShellBackend *shell_backend,
 +                            gint major,
 +                            gint minor,
 +                            gint micro,
 +                            GError **error)
 +{
 +	g_debug ("%s (from %d.%d.%d)", G_STRFUNC, major, minor, micro);
 +
 +	return TRUE;
 +}
 +
 +static gboolean
 +test_shell_backend_handle_uri_cb (EShellBackend *shell_backend,
 +                                  const gchar *uri)
 +{
 +	g_debug ("%s (uri=%s)", G_STRFUNC, uri);
 +
 +	return FALSE;
 +}
 +
 +static void
 +test_shell_backend_send_receive_cb (EShellBackend *shell_backend,
 +                                    GtkWindow *parent_window)
 +{
 +	g_debug ("%s (window=%p)", G_STRFUNC, parent_window);
 +}
 +
 +static void
 +test_shell_backend_window_created_cb (EShellBackend *shell_backend,
 +                                      GtkWindow *window)
 +{
 +	const gchar *backend_name;
 +
 +	g_debug ("%s (%s)", G_STRFUNC, G_OBJECT_TYPE_NAME (window));
 +
 +	if (!E_IS_SHELL_WINDOW (window))
 +		return;
 +
 +	backend_name = E_SHELL_BACKEND_GET_CLASS (shell_backend)->name;
 +
 +	e_shell_window_register_new_item_actions (
 +		E_SHELL_WINDOW (window), backend_name,
 +		item_entries, G_N_ELEMENTS (item_entries));
 +
 +	e_shell_window_register_new_source_actions (
 +		E_SHELL_WINDOW (window), backend_name,
 +		source_entries, G_N_ELEMENTS (source_entries));
 +}
 +
 +static void
 +test_shell_backend_window_destroyed_cb (EShellBackend *shell_backend)
 +{
 +	g_debug ("%s", G_STRFUNC);
 +}
 +
 +void
 +test_shell_backend_constructed (GObject *object)
 +{
 +	EShell *shell;
 +	EShellBackend *shell_backend;
 +
 +	shell_backend = E_SHELL_BACKEND (object);
 +	shell = e_shell_backend_get_shell (shell_backend);
 +
 +	g_signal_connect_swapped (
 +		shell, "handle-uri",
 +		G_CALLBACK (test_shell_backend_handle_uri_cb),
 +		shell_backend);
 +
 +	g_signal_connect_swapped (
 +		shell, "send-receive",
 +		G_CALLBACK (test_shell_backend_send_receive_cb),
 +		shell_backend);
 +
 +	g_signal_connect_swapped (
 +		shell, "window-created",
 +		G_CALLBACK (test_shell_backend_window_created_cb),
 +		shell_backend);
 +
 +	g_signal_connect_swapped (
 +		shell, "window-destroyed",
 +		G_CALLBACK (test_shell_backend_window_destroyed_cb),
 +		shell_backend);
 +}
 +
 +static void
 +test_shell_backend_class_init (ETestShellBackendClass *class)
 +{
 +	GObjectClass *object_class;
 +	EShellBackendClass *shell_backend_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (ETestShellBackendPrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->constructed = test_shell_backend_constructed;
 +
 +	shell_backend_class = E_SHELL_BACKEND_CLASS (class);
 +	shell_backend_class->shell_view_type = E_TYPE_TEST_SHELL_VIEW;
 +	shell_backend_class->name = "test";
 +	shell_backend_class->aliases = "monkey";
 +	shell_backend_class->schemes = "";
 +	shell_backend_class->sort_order = 100;
 +	shell_backend_class->start = test_shell_backend_start;
 +	shell_backend_class->is_busy = test_shell_backend_is_busy;
 +	shell_backend_class->shutdown = test_shell_backend_shutdown;
 +	shell_backend_class->migrate = test_shell_backend_migrate;
 +}
 +
 +static void
 +test_shell_backend_init (ETestShellBackend *test_shell_backend)
 +{
 +	test_shell_backend->priv =
 +		E_TEST_SHELL_BACKEND_GET_PRIVATE (test_shell_backend);
 +}
 +
 +GType
 +e_test_shell_backend_get_type (void)
 +{
 +	return test_shell_backend_type;
 +}
 +
 +void
 +e_test_shell_backend_register_type (GTypeModule *type_module)
 +{
 +	const GTypeInfo type_info = {
 +		sizeof (ETestShellBackendClass),
 +		(GBaseInitFunc) NULL,
 +		(GBaseFinalizeFunc) NULL,
 +		(GClassInitFunc) test_shell_backend_class_init,
 +		(GClassFinalizeFunc) NULL,
 +		NULL,  /* class_data */
 +		sizeof (ETestShellBackend),
 +		0,     /* n_preallocs */
 +		(GInstanceInitFunc) test_shell_backend_init,
 +		NULL   /* value_table */
 +	};
 +
 +	test_shell_backend_type = g_type_module_register_type (
 +		type_module, E_TYPE_SHELL_BACKEND,
 +		"ETestShellBackend", &type_info, 0);
 +}
diff --cc shell/test/e-test-shell-backend.h
index 0768e48,0000000..0d342bf
mode 100644,000000..100644
--- a/shell/test/e-test-shell-backend.h
+++ b/shell/test/e-test-shell-backend.h
@@@ -1,67 -1,0 +1,67 @@@
 +/*
 + * e-test-shell-backend.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_TEST_SHELL_BACKEND_H
 +#define E_TEST_SHELL_BACKEND_H
 +
 +#include <shell/e-shell-backend.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_TEST_SHELL_BACKEND \
 +	(e_test_shell_backend_get_type ())
 +#define E_TEST_SHELL_BACKEND(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_TEST_SHELL_BACKEND, ETestShellBackend))
 +#define E_TEST_SHELL_BACKEND_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_TEST_SHELL_BACKEND, ETestShellBackendClass))
 +#define E_IS_TEST_SHELL_BACKEND(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_TEST_SHELL_BACKEND))
 +#define E_IS_TEST_SHELL_BACKEND_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), E_TYPE_TEST_SHELL_BACKEND))
 +#define E_TEST_SHELL_BACKEND_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_TEST_SHELL_BACKEND, ETestShellBackendClass))
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _ETestShellBackend ETestShellBackend;
 +typedef struct _ETestShellBackendClass ETestShellBackendClass;
 +typedef struct _ETestShellBackendPrivate ETestShellBackendPrivate;
 +
 +struct _ETestShellBackend {
 +	EShellBackend parent;
 +	ETestShellBackendPrivate *priv;
 +};
 +
 +struct _ETestShellBackendClass {
 +	EShellBackendClass parent_class;
 +};
 +
 +GType		e_test_shell_backend_get_type	(void);
 +void		e_test_shell_backend_register_type
 +						(GTypeModule *type_module);
 +
 +G_END_DECLS
 +
 +#endif /* E_TEST_SHELL_BACKEND_H */
diff --cc shell/test/e-test-shell-view.c
index f05abff,0000000..b4464cc
mode 100644,000000..100644
--- a/shell/test/e-test-shell-view.c
+++ b/shell/test/e-test-shell-view.c
@@@ -1,155 -1,0 +1,155 @@@
 +/*
 + * e-test-shell-view.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-test-shell-view.h"
 +
 +#include "shell/e-shell-content.h"
 +#include "shell/e-shell-sidebar.h"
 +
 +#define E_TEST_SHELL_VIEW_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_TEST_SHELL_VIEW, ETestShellViewPrivate))
 +
 +struct _ETestShellViewPrivate {
 +	EActivity *activity;
 +};
 +
 +static gpointer parent_class;
 +static GType test_shell_view_type;
 +
 +static void
 +test_shell_view_toggled (EShellView *shell_view)
 +{
 +#if 0
 +	gboolean is_active;
 +	const gchar *active;
 +
 +	is_active = e_shell_view_is_active (shell_view);
 +	active = is_active ? "active" : "inactive";
 +	g_debug ("%s (now %s)", G_STRFUNC, active);
 +#endif
 +}
 +
 +static void
 +test_shell_view_dispose (GObject *object)
 +{
 +	ETestShellViewPrivate *priv;
 +
 +	priv = E_TEST_SHELL_VIEW_GET_PRIVATE (object);
 +
 +	if (priv->activity != NULL) {
 +		e_activity_complete (priv->activity);
 +		g_object_unref (priv->activity);
 +		priv->activity = NULL;
 +	}
 +
 +	/* Chain up to parent's dispose() method. */
 +	G_OBJECT_CLASS (parent_class)->dispose (object);
 +}
 +
 +static void
 +test_shell_view_constructed (GObject *object)
 +{
 +	ETestShellViewPrivate *priv;
 +	EShellContent *shell_content;
 +	EShellSidebar *shell_sidebar;
 +	EShellBackend *shell_backend;
 +	EShellView *shell_view;
 +	EActivity *activity;
 +	GtkWidget *widget;
 +
 +	/* Chain up to parent's constructed() method. */
 +	G_OBJECT_CLASS (parent_class)->constructed (object);
 +
 +	priv = E_TEST_SHELL_VIEW_GET_PRIVATE (object);
 +
 +	shell_view = E_SHELL_VIEW (object);
 +	shell_backend = e_shell_view_get_shell_backend (shell_view);
 +	shell_content = e_shell_view_get_shell_content (shell_view);
 +	shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
 +
 +	widget = gtk_label_new ("Content Widget");
 +	gtk_container_add (GTK_CONTAINER (shell_content), widget);
 +	gtk_widget_show (widget);
 +
 +	widget = gtk_label_new ("Sidebar Widget");
 +	gtk_container_add (GTK_CONTAINER (shell_sidebar), widget);
 +	gtk_widget_show (widget);
 +
 +	activity = e_activity_new ("Test Activity");
 +	e_activity_set_allow_cancel (activity, TRUE);
 +	e_shell_backend_add_activity (shell_backend, activity);
 +	priv->activity = activity;
 +}
 +
 +static void
 +test_shell_view_class_init (ETestShellViewClass *class,
 +                            GTypeModule *type_module)
 +{
 +	GObjectClass *object_class;
 +	EShellViewClass *shell_view_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (ETestShellViewPrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->dispose = test_shell_view_dispose;
 +	object_class->constructed = test_shell_view_constructed;
 +
 +	shell_view_class = E_SHELL_VIEW_CLASS (class);
 +	shell_view_class->label = "Test";
 +	shell_view_class->icon_name = "face-monkey";
 +	shell_view_class->toggled = test_shell_view_toggled;
 +}
 +
 +static void
 +test_shell_view_init (ETestShellView *test_shell_view)
 +{
 +	test_shell_view->priv =
 +		E_TEST_SHELL_VIEW_GET_PRIVATE (test_shell_view);
 +}
 +
 +GType
 +e_test_shell_view_get_type (void)
 +{
 +	return test_shell_view_type;
 +}
 +
 +void
 +e_test_shell_view_register_type (GTypeModule *type_module)
 +{
 +	const GTypeInfo type_info = {
 +		sizeof (ETestShellViewClass),
 +		(GBaseInitFunc) NULL,
 +		(GBaseFinalizeFunc) NULL,
 +		(GClassInitFunc) test_shell_view_class_init,
 +		(GClassFinalizeFunc) NULL,
 +		type_module,
 +		sizeof (ETestShellView),
 +		0,    /* n_preallocs */
 +		(GInstanceInitFunc) test_shell_view_init,
 +		NULL  /* value_table */
 +	};
 +
 +	test_shell_view_type = g_type_module_register_type (
 +		type_module, E_TYPE_SHELL_VIEW,
 +		"ETestShellView", &type_info, 0);
 +}
diff --cc shell/test/e-test-shell-view.h
index b84fba9,0000000..85c33bf
mode 100644,000000..100644
--- a/shell/test/e-test-shell-view.h
+++ b/shell/test/e-test-shell-view.h
@@@ -1,66 -1,0 +1,66 @@@
 +/*
 + * e-test-shell-view.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_TEST_SHELL_VIEW_H
 +#define E_TEST_SHELL_VIEW_H
 +
 +#include <shell/e-shell-view.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_TEST_SHELL_VIEW \
 +	(e_test_shell_view_get_type ())
 +#define E_TEST_SHELL_VIEW(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_TEST_SHELL_VIEW, ETestShellView))
 +#define E_TEST_SHELL_VIEW_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_TEST_SHELL_VIEW, ETestShellViewClass))
 +#define E_IS_TEST_SHELL_VIEW(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_TEST_SHELL_VIEW))
 +#define E_IS_TEST_SHELL_VIEW_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), E_TYPE_TEST_SHELL_VIEW))
 +#define E_TEST_SHELL_VIEW_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_TEST_SHELL_VIEW, ETestShellViewClass))
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _ETestShellView ETestShellView;
 +typedef struct _ETestShellViewClass ETestShellViewClass;
 +typedef struct _ETestShellViewPrivate ETestShellViewPrivate;
 +
 +struct _ETestShellView {
 +	EShellView parent;
 +	ETestShellViewPrivate *priv;
 +};
 +
 +struct _ETestShellViewClass {
 +	EShellViewClass parent_class;
 +};
 +
 +GType		e_test_shell_view_get_type	(void);
 +void		e_test_shell_view_register_type	(GTypeModule *type_module);
 +
 +G_END_DECLS
 +
 +#endif /* E_TEST_SHELL_VIEW_H */
diff --cc shell/test/evolution-module-test.c
index ceae63c,0000000..1fe3c7c
mode 100644,000000..100644
--- a/shell/test/evolution-module-test.c
+++ b/shell/test/evolution-module-test.c
@@@ -1,41 -1,0 +1,41 @@@
 +/*
 + * evolution-module-test.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-test-shell-backend.h"
 +#include "e-test-shell-view.h"
 +
 +/* Module Entry Points */
 +void e_module_load (GTypeModule *type_module);
 +void e_module_unload (GTypeModule *type_module);
 +
 +G_MODULE_EXPORT void
 +e_module_load (GTypeModule *type_module)
 +{
 +	/* Register dynamically loaded types. */
 +
 +	e_test_shell_backend_register_type (type_module);
 +	e_test_shell_view_register_type (type_module);
 +}
 +
 +G_MODULE_EXPORT void
 +e_module_unload (GTypeModule *type_module)
 +{
 +}
diff --cc widgets/misc/a11y/ea-calendar-cell.c
index 8173d6d,0000000..2d2a92d
mode 100644,000000..100644
--- a/widgets/misc/a11y/ea-calendar-cell.c
+++ b/widgets/misc/a11y/ea-calendar-cell.c
@@@ -1,387 -1,0 +1,387 @@@
 +/*
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Authors:
 + *		Bolian Yin <bolian yin sun com>
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include <gtk/gtk.h>
 +#include <e-util/e-util.h>
 +#include "ea-calendar-cell.h"
 +#include "ea-calendar-item.h"
 +#include "a11y/ea-factory.h"
 +
 +/* ECalendarCell */
 +
 +static void e_calendar_cell_class_init (ECalendarCellClass *class);
 +
 +EA_FACTORY_GOBJECT (EA_TYPE_CALENDAR_CELL, ea_calendar_cell, ea_calendar_cell_new)
 +
 +GType
 +e_calendar_cell_get_type (void)
 +{
 +	static GType type = 0;
 +
 +	if (!type) {
 +		static GTypeInfo tinfo = {
 +			sizeof (ECalendarCellClass),
 +			(GBaseInitFunc) NULL, /* base init */
 +			(GBaseFinalizeFunc) NULL, /* base finalize */
 +			(GClassInitFunc) e_calendar_cell_class_init, /* class init */
 +			(GClassFinalizeFunc) NULL, /* class finalize */
 +			NULL, /* class data */
 +			sizeof (ECalendarCell), /* instance size */
 +			0, /* nb preallocs */
 +			(GInstanceInitFunc) NULL, /* instance init */
 +			NULL /* value table */
 +		};
 +
 +		type = g_type_register_static (G_TYPE_OBJECT,
 +					       "ECalendarCell", &tinfo, 0);
 +	}
 +
 +	return type;
 +}
 +
 +static void
 +e_calendar_cell_class_init (ECalendarCellClass *class)
 +{
 +    EA_SET_FACTORY (e_calendar_cell_get_type (), ea_calendar_cell);
 +}
 +
 +ECalendarCell *
 +e_calendar_cell_new (ECalendarItem *calitem, gint row, gint column)
 +{
 +	GObject *object;
 +	ECalendarCell *cell;
 +
 +	g_return_val_if_fail (E_IS_CALENDAR_ITEM (calitem), NULL);
 +
 +	object = g_object_new (E_TYPE_CALENDAR_CELL, NULL);
 +	cell = E_CALENDAR_CELL (object);
 +	cell->calitem = calitem;
 +	cell->row = row;
 +	cell->column = column;
 +
 +#ifdef ACC_DEBUG
 +	g_print ("EvoAcc: e_calendar_cell created %p\n", (void *)cell);
 +#endif
 +
 +	return cell;
 +}
 +
 +/* EaCalendarCell */
 +
 +static void ea_calendar_cell_class_init (EaCalendarCellClass *klass);
 +static void ea_calendar_cell_init (EaCalendarCell *a11y);
 +
 +static G_CONST_RETURN gchar* ea_calendar_cell_get_name (AtkObject *accessible);
 +static G_CONST_RETURN gchar* ea_calendar_cell_get_description (AtkObject *accessible);
 +static AtkObject * ea_calendar_cell_get_parent (AtkObject *accessible);
 +static gint ea_calendar_cell_get_index_in_parent (AtkObject *accessible);
 +static AtkStateSet *ea_calendar_cell_ref_state_set (AtkObject *accessible);
 +
 +/* component interface */
 +static void atk_component_interface_init (AtkComponentIface *iface);
 +static void component_interface_get_extents (AtkComponent *component,
 +					     gint *x, gint *y,
 +					     gint *width, gint *height,
 +					     AtkCoordType coord_type);
 +static gboolean component_interface_grab_focus (AtkComponent *component);
 +
 +static gpointer parent_class = NULL;
 +
 +#ifdef ACC_DEBUG
 +static gint n_ea_calendar_cell_created = 0, n_ea_calendar_cell_destroyed = 0;
 +static void ea_calendar_cell_finalize (GObject *object);
 +#endif
 +
 +GType
 +ea_calendar_cell_get_type (void)
 +{
 +	static GType type = 0;
 +
 +	if (!type) {
 +		static GTypeInfo tinfo = {
 +			sizeof (EaCalendarCellClass),
 +			(GBaseInitFunc) NULL, /* base init */
 +			(GBaseFinalizeFunc) NULL, /* base finalize */
 +			(GClassInitFunc) ea_calendar_cell_class_init, /* class init */
 +			(GClassFinalizeFunc) NULL, /* class finalize */
 +			NULL, /* class data */
 +			sizeof (EaCalendarCell), /* instance size */
 +			0, /* nb preallocs */
 +			(GInstanceInitFunc) ea_calendar_cell_init, /* instance init */
 +			NULL /* value table */
 +		};
 +
 +		static const GInterfaceInfo atk_component_info = {
 +			(GInterfaceInitFunc) atk_component_interface_init,
 +			(GInterfaceFinalizeFunc) NULL,
 +			NULL
 +		};
 +
 +		type = g_type_register_static (ATK_TYPE_GOBJECT_ACCESSIBLE,
 +					       "EaCalendarCell", &tinfo, 0);
 +		g_type_add_interface_static (type, ATK_TYPE_COMPONENT,
 +					     &atk_component_info);
 +	}
 +
 +	return type;
 +}
 +
 +static void
 +ea_calendar_cell_class_init (EaCalendarCellClass *klass)
 +{
 +	AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
 +
 +#ifdef ACC_DEBUG
 +	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 +	gobject_class->finalize = ea_calendar_cell_finalize;
 +#endif
 +
 +	parent_class = g_type_class_peek_parent (klass);
 +
 +	class->get_name = ea_calendar_cell_get_name;
 +	class->get_description = ea_calendar_cell_get_description;
 +
 +	class->get_parent = ea_calendar_cell_get_parent;
 +	class->get_index_in_parent = ea_calendar_cell_get_index_in_parent;
 +	class->ref_state_set = ea_calendar_cell_ref_state_set;
 +}
 +
 +static void
 +ea_calendar_cell_init (EaCalendarCell *a11y)
 +{
 +	a11y->state_set = atk_state_set_new ();
 +	atk_state_set_add_state (a11y->state_set, ATK_STATE_TRANSIENT);
 +	atk_state_set_add_state (a11y->state_set, ATK_STATE_ENABLED);
 +	atk_state_set_add_state (a11y->state_set, ATK_STATE_SENSITIVE);
 +	atk_state_set_add_state (a11y->state_set, ATK_STATE_SELECTABLE);
 +	atk_state_set_add_state (a11y->state_set, ATK_STATE_SHOWING);
 +	atk_state_set_add_state (a11y->state_set, ATK_STATE_FOCUSABLE);
 +}
 +
 +AtkObject*
 +ea_calendar_cell_new (GObject *obj)
 +{
 +	gpointer object;
 +	AtkObject *atk_object;
 +
 +	g_return_val_if_fail (E_IS_CALENDAR_CELL (obj), NULL);
 +	object = g_object_new (EA_TYPE_CALENDAR_CELL, NULL);
 +	atk_object = ATK_OBJECT (object);
 +	atk_object_initialize (atk_object, obj);
 +	atk_object->role = ATK_ROLE_TABLE_CELL;
 +
 +#ifdef ACC_DEBUG
 +	++n_ea_calendar_cell_created;
 +	g_print ("ACC_DEBUG: n_ea_calendar_cell_created = %d\n",
 +		n_ea_calendar_cell_created);
 +#endif
 +	return atk_object;
 +}
 +
 +#ifdef ACC_DEBUG
 +static void ea_calendar_cell_finalize (GObject *object)
 +{
 +        G_OBJECT_CLASS (parent_class)->finalize (object);
 +
 +	++n_ea_calendar_cell_destroyed;
 +	g_print ("ACC_DEBUG: n_ea_calendar_cell_destroyed = %d\n",
 +		n_ea_calendar_cell_destroyed);
 +}
 +#endif
 +
 +static G_CONST_RETURN gchar*
 +ea_calendar_cell_get_name (AtkObject *accessible)
 +{
 +	GObject *g_obj;
 +
 +	g_return_val_if_fail (EA_IS_CALENDAR_CELL (accessible), NULL);
 +
 +	g_obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE(accessible));
 +	if (!g_obj)
 +		/* defunct object*/
 +		return NULL;
 +
 +	if (!accessible->name) {
 +		AtkObject *atk_obj;
 +		EaCalendarItem *ea_calitem;
 +		ECalendarCell *cell;
 +		gint day_index;
 +		gint year, month, day;
 +		gchar buffer[128];
 +
 +		cell = E_CALENDAR_CELL (g_obj);
 +		atk_obj = ea_calendar_cell_get_parent (accessible);
 +		ea_calitem = EA_CALENDAR_ITEM (atk_obj);
 +		day_index = atk_table_get_index_at (ATK_TABLE (ea_calitem),
 +						    cell->row, cell->column);
 +		e_calendar_item_get_date_for_offset (cell->calitem, day_index,
 +						     &year, &month, &day);
 +
 +		g_snprintf (buffer, 128, "%d-%d-%d", year, month + 1, day);
 +		ATK_OBJECT_CLASS (parent_class)->set_name (accessible, buffer);
 +	}
 +	return accessible->name;
 +}
 +
 +static G_CONST_RETURN gchar*
 +ea_calendar_cell_get_description (AtkObject *accessible)
 +{
 +	return ea_calendar_cell_get_name (accessible);
 +}
 +
 +static AtkObject *
 +ea_calendar_cell_get_parent (AtkObject *accessible)
 +{
 +	GObject *g_obj;
 +	ECalendarCell *cell;
 +	ECalendarItem *calitem;
 +
 +	g_return_val_if_fail (EA_IS_CALENDAR_CELL (accessible), NULL);
 +
 +	g_obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE(accessible));
 +	if (!g_obj)
 +		/* defunct object*/
 +		return NULL;
 +
 +	cell = E_CALENDAR_CELL (g_obj);
 +	calitem = cell->calitem;
 +	return atk_gobject_accessible_for_object (G_OBJECT (calitem));
 +}
 +
 +static gint
 +ea_calendar_cell_get_index_in_parent (AtkObject *accessible)
 +{
 +	GObject *g_obj;
 +	ECalendarCell *cell;
 +	AtkObject *parent;
 +
 +	g_return_val_if_fail (EA_IS_CALENDAR_CELL (accessible), -1);
 +
 +	g_obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE(accessible));
 +	if (!g_obj)
 +		return -1;
 +	cell = E_CALENDAR_CELL (g_obj);
 +	parent = atk_object_get_parent (accessible);
 +	return atk_table_get_index_at (ATK_TABLE (parent),
 +				       cell->row, cell->column);
 +}
 +
 +static AtkStateSet *
 +ea_calendar_cell_ref_state_set (AtkObject *accessible)
 +{
 +	EaCalendarCell *atk_cell = EA_CALENDAR_CELL (accessible);
 +
 +	g_return_val_if_fail (atk_cell->state_set, NULL);
 +
 +	g_object_ref(atk_cell->state_set);
 +
 +	return atk_cell->state_set;
 +
 +}
 +
 +/* Atk Component Interface */
 +
 +static void
 +atk_component_interface_init (AtkComponentIface *iface)
 +{
 +	g_return_if_fail (iface != NULL);
 +
 +	iface->get_extents = component_interface_get_extents;
 +	iface->grab_focus  = component_interface_grab_focus;
 +}
 +
 +static void
 +component_interface_get_extents (AtkComponent *component,
 +				 gint *x, gint *y, gint *width, gint *height,
 +				 AtkCoordType coord_type)
 +{
 +	GObject *g_obj;
 +	AtkObject *atk_obj, *atk_canvas;
 +	ECalendarCell *cell;
 +	ECalendarItem *calitem;
 +	EaCalendarItem *ea_calitem;
 +	gint day_index;
 +	gint year, month, day;
 +	gint canvas_x, canvas_y, canvas_width, canvas_height;
 +
 +	*x = *y = *width = *height = 0;
 +
 +	g_return_if_fail (EA_IS_CALENDAR_CELL (component));
 +
 +
 +	g_obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE(component));
 +	if (!g_obj)
 +		/* defunct object*/
 +		return;
 +
 +	cell = E_CALENDAR_CELL (g_obj);
 +	calitem = cell->calitem;
 +	atk_obj = atk_gobject_accessible_for_object (G_OBJECT (calitem));
 +	ea_calitem = EA_CALENDAR_ITEM (atk_obj);
 +	day_index = atk_table_get_index_at (ATK_TABLE (ea_calitem),
 +					    cell->row, cell->column);
 +	e_calendar_item_get_date_for_offset (calitem, day_index,
 +					     &year, &month, &day);
 +
 +	if (!e_calendar_item_get_day_extents (calitem,
 +					      year, month, day,
 +					      x, y, width, height))
 +	    return;
 +	atk_canvas = atk_object_get_parent (ATK_OBJECT (ea_calitem));
 +	atk_component_get_extents (ATK_COMPONENT (atk_canvas),
 +					     &canvas_x, &canvas_y,
 +					     &canvas_width, &canvas_height,
 +					     coord_type);
 +	*x += canvas_x;
 +	*y += canvas_y;
 +}
 +
 +static gboolean
 +component_interface_grab_focus (AtkComponent *component)
 +{
 +	GObject *g_obj;
 +	GtkWidget *toplevel;
 +	AtkObject *ea_calitem;
 +	ECalendarItem *calitem;
 +	EaCalendarCell *a11y;
 +	gint index;
 +
 +	a11y = EA_CALENDAR_CELL (component);
 +	ea_calitem = ea_calendar_cell_get_parent (ATK_OBJECT (a11y));
 +
 +	g_obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE(ea_calitem));
 +	calitem = E_CALENDAR_ITEM (g_obj);
 +
 +	index = atk_object_get_index_in_parent (ATK_OBJECT (a11y));
 +
 +	atk_selection_clear_selection (ATK_SELECTION (ea_calitem));
 +	atk_selection_add_selection (ATK_SELECTION (ea_calitem), index);
 +
 +	gtk_widget_grab_focus (GTK_WIDGET (GNOME_CANVAS_ITEM (calitem)->canvas));
 +	toplevel = gtk_widget_get_toplevel (GTK_WIDGET (GNOME_CANVAS_ITEM (calitem)->canvas));
 +	if (toplevel && GTK_WIDGET_TOPLEVEL (toplevel))
 +		gtk_window_present (GTK_WINDOW (toplevel));
 +
 +	return TRUE;
 +
 +}
diff --cc widgets/misc/a11y/ea-calendar-item.c
index 66f40a9,0000000..34db081
mode 100644,000000..100644
--- a/widgets/misc/a11y/ea-calendar-item.c
+++ b/widgets/misc/a11y/ea-calendar-item.c
@@@ -1,1314 -1,0 +1,1314 @@@
 +/*
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Authors:
-  *		Bolian Yin <bolian yin sun com> 
++ *		Bolian Yin <bolian yin sun com>
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include <stdio.h>
 +#include <time.h>
 +#include <string.h>
 +#include <libgnomecanvas/gnome-canvas.h>
 +#include <glib.h>
 +#include <e-util/e-util.h>
 +#include <glib/gi18n.h>
 +#include <libedataserver/e-data-server-util.h>
 +#include "ea-calendar-item.h"
 +#include "ea-calendar-cell.h"
 +#include "a11y/ea-cell-table.h"
 +
 +#define EA_CALENDAR_COLUMN_NUM E_CALENDAR_COLS_PER_MONTH
 +
 +/* EaCalendarItem */
 +static void ea_calendar_item_class_init (EaCalendarItemClass *klass);
 +static void ea_calendar_item_finalize (GObject *object);
 +
 +static G_CONST_RETURN gchar* ea_calendar_item_get_name (AtkObject *accessible);
 +static G_CONST_RETURN gchar* ea_calendar_item_get_description (AtkObject *accessible);
 +static gint ea_calendar_item_get_n_children (AtkObject *accessible);
 +static AtkObject *ea_calendar_item_ref_child (AtkObject *accessible, gint index);
 +static AtkStateSet* ea_calendar_item_ref_state_set (AtkObject *accessible);
 +
 +/* atk table interface */
 +static void atk_table_interface_init (AtkTableIface *iface);
 +static gint table_interface_get_index_at (AtkTable *table,
 +					  gint     row,
 +					  gint     column);
 +static gint table_interface_get_column_at_index (AtkTable *table,
 +						 gint     index);
 +static gint table_interface_get_row_at_index (AtkTable *table,
 +					      gint     index);
 +static AtkObject* table_interface_ref_at (AtkTable *table,
 +					  gint     row,
 +					  gint     column);
 +static gint table_interface_get_n_rows (AtkTable *table);
 +static gint table_interface_get_n_columns (AtkTable *table);
 +static gint table_interface_get_column_extent_at (AtkTable      *table,
 +						  gint          row,
 +						  gint          column);
 +static gint table_interface_get_row_extent_at (AtkTable      *table,
 +					       gint          row,
 +					       gint          column);
 +
 +static gboolean table_interface_is_row_selected (AtkTable *table,
 +						 gint     row);
 +static gboolean table_interface_is_column_selected (AtkTable *table,
 +						    gint     row);
 +static gboolean table_interface_is_selected (AtkTable *table,
 +					     gint     row,
 +					     gint     column);
 +static gint table_interface_get_selected_rows (AtkTable *table,
 +					       gint **rows_selected);
 +static gint table_interface_get_selected_columns (AtkTable *table,
 +						  gint     **columns_selected);
 +static gboolean table_interface_add_row_selection (AtkTable *table, gint row);
 +static gboolean table_interface_remove_row_selection (AtkTable *table,
 +						      gint row);
 +static gboolean table_interface_add_column_selection (AtkTable *table,
 +						      gint column);
 +static gboolean table_interface_remove_column_selection (AtkTable *table,
 +							 gint column);
 +static AtkObject* table_interface_get_row_header (AtkTable *table, gint row);
 +static AtkObject* table_interface_get_column_header (AtkTable *table,
 +						     gint in_col);
 +static AtkObject* table_interface_get_caption (AtkTable *table);
 +
 +static G_CONST_RETURN gchar*
 +table_interface_get_column_description (AtkTable *table, gint in_col);
 +
 +static G_CONST_RETURN gchar*
 +table_interface_get_row_description (AtkTable *table, gint row);
 +
 +static AtkObject* table_interface_get_summary (AtkTable *table);
 +
 +/* atk selection interface */
 +static void atk_selection_interface_init (AtkSelectionIface *iface);
 +static gboolean selection_interface_add_selection (AtkSelection *selection,
 +						   gint i);
 +static gboolean selection_interface_clear_selection (AtkSelection *selection);
 +static AtkObject* selection_interface_ref_selection (AtkSelection *selection,
 +						     gint i);
 +static gint selection_interface_get_selection_count (AtkSelection *selection);
 +static gboolean selection_interface_is_child_selected (AtkSelection *selection,
 +						       gint i);
 +
 +/* callbacks */
 +static void selection_preview_change_cb (ECalendarItem *calitem);
 +static void date_range_changed_cb (ECalendarItem *calitem);
 +
 +/* helpers */
 +static EaCellTable *ea_calendar_item_get_cell_data (EaCalendarItem *ea_calitem);
 +static void ea_calendar_item_destory_cell_data (EaCalendarItem *ea_calitem);
 +static gboolean ea_calendar_item_get_column_label (EaCalendarItem *ea_calitem,
 +						   gint column,
 +						   gchar *buffer,
 +						   gint buffer_size);
 +static gboolean ea_calendar_item_get_row_label (EaCalendarItem *ea_calitem,
 +						gint row,
 +						gchar *buffer,
 +						gint buffer_size);
 +static gboolean e_calendar_item_get_offset_for_date (ECalendarItem *calitem,
 +						     gint year, gint month, gint day,
 +						     gint *offset);
 +static void ea_calendar_set_focus_object (EaCalendarItem *ea_calitem,
 +					  AtkObject *item_cell);
 +
 +#ifdef ACC_DEBUG
 +static gint n_ea_calendar_item_created = 0;
 +static gint n_ea_calendar_item_destroyed = 0;
 +#endif
 +
 +static gpointer parent_class = NULL;
 +
 +GType
 +ea_calendar_item_get_type (void)
 +{
 +	static GType type = 0;
 +	AtkObjectFactory *factory;
 +	GTypeQuery query;
 +	GType derived_atk_type;
 +
 +	if (!type) {
 +		static GTypeInfo tinfo = {
 +			sizeof (EaCalendarItemClass),
 +			(GBaseInitFunc) NULL, /* base init */
 +			(GBaseFinalizeFunc) NULL, /* base finalize */
 +			(GClassInitFunc) ea_calendar_item_class_init, /* class init */
 +			(GClassFinalizeFunc) NULL, /* class finalize */
 +			NULL, /* class data */
 +			sizeof (EaCalendarItem), /* instance size */
 +			0, /* nb preallocs */
 +			(GInstanceInitFunc) NULL, /* instance init */
 +			NULL /* value table */
 +		};
 +
 +		static const GInterfaceInfo atk_table_info = {
 +			(GInterfaceInitFunc) atk_table_interface_init,
 +			(GInterfaceFinalizeFunc) NULL,
 +			NULL
 +		};
 +		static const GInterfaceInfo atk_selection_info = {
 +			(GInterfaceInitFunc) atk_selection_interface_init,
 +			(GInterfaceFinalizeFunc) NULL,
 +			NULL
 +		};
 +
 +		/*
 +		 * Figure out the size of the class and instance
 +		 * we are run-time deriving from (GailCanvasItem, in this case)
 +		 */
 +
 +		factory = atk_registry_get_factory (atk_get_default_registry (),
 +						    GNOME_TYPE_CANVAS_ITEM);
 +		derived_atk_type = atk_object_factory_get_accessible_type (factory);
 +		g_type_query (derived_atk_type, &query);
 +
 +		tinfo.class_size = query.class_size;
 +		tinfo.instance_size = query.instance_size;
 +
 +		type = g_type_register_static (derived_atk_type,
 +					       "EaCalendarItem", &tinfo, 0);
 +		g_type_add_interface_static (type, ATK_TYPE_TABLE,
 +					     &atk_table_info);
 +		g_type_add_interface_static (type, ATK_TYPE_SELECTION,
 +					     &atk_selection_info);
 +	}
 +
 +	return type;
 +}
 +
 +static void
 +ea_calendar_item_class_init (EaCalendarItemClass *klass)
 +{
 +	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 +	AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
 +
 +	gobject_class->finalize = ea_calendar_item_finalize;
 +	parent_class = g_type_class_peek_parent (klass);
 +
 +	class->get_name = ea_calendar_item_get_name;
 +	class->get_description = ea_calendar_item_get_description;
 +        class->ref_state_set = ea_calendar_item_ref_state_set;
 +
 +	class->get_n_children = ea_calendar_item_get_n_children;
 +	class->ref_child = ea_calendar_item_ref_child;
 +}
 +
 +AtkObject*
 +ea_calendar_item_new (GObject *obj)
 +{
 +	gpointer object;
 +	AtkObject *atk_object;
 +	AtkObject *item_cell;
 +
 +	g_return_val_if_fail (E_IS_CALENDAR_ITEM (obj), NULL);
 +	object = g_object_new (EA_TYPE_CALENDAR_ITEM, NULL);
 +	atk_object = ATK_OBJECT (object);
 +	atk_object_initialize (atk_object, obj);
 +	atk_object->role = ATK_ROLE_CALENDAR;
 +
 +	item_cell = atk_selection_ref_selection (ATK_SELECTION (atk_object),
 +							0);
 +	if (item_cell)
 +		ea_calendar_set_focus_object (EA_CALENDAR_ITEM (atk_object), item_cell);
 +
 +#ifdef ACC_DEBUG
 +	++n_ea_calendar_item_created;
 +	g_print ("ACC_DEBUG: n_ea_calendar_item_created = %d\n",
 +		n_ea_calendar_item_created);
 +#endif
 +	/* connect signal handlers */
 +	g_signal_connect (obj, "selection_preview_changed",
 +			  G_CALLBACK (selection_preview_change_cb),
 +			  atk_object);
 +	g_signal_connect (obj, "date_range_changed",
 +			  G_CALLBACK (date_range_changed_cb),
 +			  atk_object);
 +
 +	return atk_object;
 +}
 +
 +static void
 +ea_calendar_item_finalize (GObject *object)
 +{
 +	EaCalendarItem *ea_calitem;
 +
 +	g_return_if_fail (EA_IS_CALENDAR_ITEM (object));
 +
 +	ea_calitem = EA_CALENDAR_ITEM (object);
 +
 +	/* Free the allocated cell data */
 +	ea_calendar_item_destory_cell_data (ea_calitem);
 +
 +	G_OBJECT_CLASS (parent_class)->finalize (object);
 +#ifdef ACC_DEBUG
 +	++n_ea_calendar_item_destroyed;
 +	printf ("ACC_DEBUG: n_ea_calendar_item_destroyed = %d\n",
 +		n_ea_calendar_item_destroyed);
 +#endif
 +}
 +
 +static G_CONST_RETURN gchar*
 +ea_calendar_item_get_name (AtkObject *accessible)
 +{
 +	GObject *g_obj;
 +	ECalendarItem *calitem;
 +	gint start_year, start_month, start_day;
 +	gint end_year, end_month, end_day;
 +	gchar *name_str = NULL;
 +	gchar buffer_start[128] = "";
 +	gchar buffer_end[128] = "";
 +	struct tm day_start = { 0 };
 +	struct tm day_end = { 0 };
 +
 +	g_return_val_if_fail (EA_IS_CALENDAR_ITEM (accessible), NULL);
 +
 +	g_obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE(accessible));
 +	if (!g_obj)
 + 		return NULL;
 +	g_return_val_if_fail (E_IS_CALENDAR_ITEM (g_obj), NULL);
 +
 +	calitem = E_CALENDAR_ITEM (g_obj);
 +	if (e_calendar_item_get_date_range (calitem,
 +					    &start_year, &start_month, &start_day,
 +                                            &end_year, &end_month, &end_day)) {
 +
 +                day_start.tm_year = start_year - 1900;
 +                day_start.tm_mon = start_month;
 +                day_start.tm_mday = start_day;
 +                day_start.tm_isdst = -1;
 +                e_utf8_strftime (buffer_start, sizeof (buffer_start), _("%d %B %Y"), &day_start);
 +
 +                day_end.tm_year = end_year - 1900;
 +                day_end.tm_mon = end_month;
 +                day_end.tm_mday = end_day;
 +                day_end.tm_isdst = -1;
 +                e_utf8_strftime (buffer_end, sizeof (buffer_end), _("%d %B %Y"), &day_end);
 +
 +		name_str = g_strdup_printf (_("Calendar: from %s to %s"), buffer_start, buffer_end);
 +        }
 +
 +#if 0
 +	if (e_calendar_item_get_selection (calitem, &select_start, &select_end)) {
 +		GDate select_start, select_end;
 +		gint year1, year2, month1, month2, day1, day2;
 +
 +		year1 = g_date_get_year (&select_start);
 +		month1  = g_date_get_month (&select_start);
 +		day1 = g_date_get_day (&select_start);
 +
 +		year2 = g_date_get_year (&select_end);
 +		month2  = g_date_get_month (&select_end);
 +		day2 = g_date_get_day (&select_end);
 +
 +		sprintf (new_name + strlen (new_name),
 +			 " : current selection: from %d-%d-%d to %d-%d-%d.",
 +			 year1, month1, day1,
 +			 year2, month2, day2);
 +	}
 +#endif
 +
 +	ATK_OBJECT_CLASS (parent_class)->set_name (accessible, name_str);
 +	g_free (name_str);
 +
 +	return accessible->name;
 +}
 +
 +static G_CONST_RETURN gchar*
 +ea_calendar_item_get_description (AtkObject *accessible)
 +{
 +	if (accessible->description)
 +		return accessible->description;
 +
 +	return _("evolution calendar item");
 +}
 +
 +static AtkStateSet*
 +ea_calendar_item_ref_state_set (AtkObject *accessible)
 +{
 +        AtkStateSet *state_set;
 +        GObject *g_obj;
 +
 +        state_set = ATK_OBJECT_CLASS (parent_class)->ref_state_set (accessible);
 +        g_obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE(accessible));
 +        if (!g_obj)
 +                return state_set;
 +
 +        atk_state_set_add_state (state_set, ATK_STATE_ENABLED);
 +        atk_state_set_add_state (state_set, ATK_STATE_SENSITIVE);
 +
 +        return state_set;
 +}
 +
 +static gint
 +ea_calendar_item_get_n_children (AtkObject *accessible)
 +{
 +	AtkGObjectAccessible *atk_gobj;
 +	GObject *g_obj;
 +	ECalendarItem *calitem;
 +	gint n_children = 0;
 +	gint start_year, start_month, start_day;
 +	gint end_year, end_month, end_day;
 +	GDate *start_date, *end_date;
 +
 +	g_return_val_if_fail (EA_IS_CALENDAR_ITEM (accessible), -1);
 +
 +	atk_gobj = ATK_GOBJECT_ACCESSIBLE (accessible);
 +	g_obj = atk_gobject_accessible_get_object (atk_gobj);
 +	if (!g_obj)
 +		return -1;
 +
 +	calitem = E_CALENDAR_ITEM (g_obj);
 +	if (!e_calendar_item_get_date_range (calitem, &start_year,
 +					     &start_month, &start_day,
 +					     &end_year, &end_month,
 +					     &end_day))
 +		return 0;
 +
 +	start_date = g_date_new_dmy (start_day, start_month + 1, start_year);
 +	end_date = g_date_new_dmy (end_day, end_month + 1, end_year);
 +
 +	n_children = g_date_days_between (start_date, end_date) + 1;
 +	g_free (start_date);
 +	g_free (end_date);
 +	return n_children;
 +}
 +
 +static AtkObject *
 +ea_calendar_item_ref_child (AtkObject *accessible, gint index)
 +{
 +	AtkGObjectAccessible *atk_gobj;
 +	GObject *g_obj;
 +	ECalendarItem *calitem;
 +	gint n_children;
 +	ECalendarCell *cell;
 +	EaCellTable *cell_data;
 +	EaCalendarItem *ea_calitem;
 +
 +	g_return_val_if_fail (EA_IS_CALENDAR_ITEM (accessible), NULL);
 +
 +	atk_gobj = ATK_GOBJECT_ACCESSIBLE (accessible);
 +	g_obj = atk_gobject_accessible_get_object (atk_gobj);
 +	if (!g_obj)
 +		return NULL;
 +
 +	calitem = E_CALENDAR_ITEM (g_obj);
 +
 +	n_children = ea_calendar_item_get_n_children (accessible);
 +	if (index < 0 || index >= n_children)
 +		return NULL;
 +
 +	ea_calitem = EA_CALENDAR_ITEM (accessible);
 +	cell_data = ea_calendar_item_get_cell_data (ea_calitem);
 +	if (!cell_data)
 +		return NULL;
 +
 +	cell = ea_cell_table_get_cell_at_index (cell_data, index);
 +	if (!cell) {
 +		cell = e_calendar_cell_new (calitem,
 +					    index / EA_CALENDAR_COLUMN_NUM,
 +					    index % EA_CALENDAR_COLUMN_NUM);
 +		ea_cell_table_set_cell_at_index (cell_data, index, cell);
 +		g_object_unref (cell);
 +	}
 +
 +#ifdef ACC_DEBUG
 +	g_print ("AccDebug: ea_calendar_item children[%d]=%p\n", index,
 +		 (gpointer)cell);
 +#endif
 +	return g_object_ref (atk_gobject_accessible_for_object (G_OBJECT(cell)));
 +}
 +
 +/* atk table interface */
 +
 +static void
 +atk_table_interface_init (AtkTableIface *iface)
 +{
 +	g_return_if_fail (iface != NULL);
 +
 +	iface->ref_at = table_interface_ref_at;
 +
 +	iface->get_n_rows = table_interface_get_n_rows;
 +	iface->get_n_columns = table_interface_get_n_columns;
 +	iface->get_index_at = table_interface_get_index_at;
 +	iface->get_column_at_index = table_interface_get_column_at_index;
 +	iface->get_row_at_index = table_interface_get_row_at_index;
 +	iface->get_column_extent_at = table_interface_get_column_extent_at;
 +	iface->get_row_extent_at = table_interface_get_row_extent_at;
 +
 +	iface->is_selected = table_interface_is_selected;
 +	iface->get_selected_rows = table_interface_get_selected_rows;
 +	iface->get_selected_columns = table_interface_get_selected_columns;
 +	iface->is_row_selected = table_interface_is_row_selected;
 +	iface->is_column_selected = table_interface_is_column_selected;
 +	iface->add_row_selection = table_interface_add_row_selection;
 +	iface->remove_row_selection = table_interface_remove_row_selection;
 +	iface->add_column_selection = table_interface_add_column_selection;
 +	iface->remove_column_selection = table_interface_remove_column_selection;
 +
 +	iface->get_row_header = table_interface_get_row_header;
 +	iface->get_column_header = table_interface_get_column_header;
 +	iface->get_caption = table_interface_get_caption;
 +	iface->get_summary = table_interface_get_summary;
 +	iface->get_row_description = table_interface_get_row_description;
 +	iface->get_column_description = table_interface_get_column_description;
 +}
 +
 +static AtkObject*
 +table_interface_ref_at (AtkTable *table,
 +			gint     row,
 +			gint     column)
 +{
 +	gint index;
 +
 +	EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (table);
 +	index = EA_CALENDAR_COLUMN_NUM * row + column;
 +	return ea_calendar_item_ref_child (ATK_OBJECT (ea_calitem), index);
 +}
 +
 +static gint
 +table_interface_get_n_rows (AtkTable *table)
 +{
 +	AtkGObjectAccessible *atk_gobj;
 +	GObject *g_obj;
 +	EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (table);
 +	gint n_children;
 +
 +	atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
 +	g_obj = atk_gobject_accessible_get_object (atk_gobj);
 +	if (!g_obj)
 +		return -1;
 +
 +	n_children = ea_calendar_item_get_n_children (ATK_OBJECT (ea_calitem));
 +	return (n_children - 1) / EA_CALENDAR_COLUMN_NUM + 1;
 +}
 +
 +static gint
 +table_interface_get_n_columns (AtkTable *table)
 +{
 +	AtkGObjectAccessible *atk_gobj;
 +	GObject *g_obj;
 +	EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (table);
 +
 +	atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
 +	g_obj = atk_gobject_accessible_get_object (atk_gobj);
 +	if (!g_obj)
 +		return -1;
 +
 +	return EA_CALENDAR_COLUMN_NUM;
 +}
 +
 +static gint
 +table_interface_get_index_at (AtkTable *table,
 +			      gint     row,
 +			      gint     column)
 +{
 +	AtkGObjectAccessible *atk_gobj;
 +	GObject *g_obj;
 +	EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (table);
 +
 +	atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
 +	g_obj = atk_gobject_accessible_get_object (atk_gobj);
 +	if (!g_obj)
 +		return -1;
 +
 +	return row * EA_CALENDAR_COLUMN_NUM + column;
 +}
 +
 +static gint
 +table_interface_get_column_at_index (AtkTable *table,
 +				     gint index)
 +{
 +	AtkGObjectAccessible *atk_gobj;
 +	GObject *g_obj;
 +	EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (table);
 +	gint n_children;
 +
 +	atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
 +	g_obj = atk_gobject_accessible_get_object (atk_gobj);
 +	if (!g_obj)
 +		return -1;
 +
 +	n_children = ea_calendar_item_get_n_children (ATK_OBJECT (ea_calitem));
 +	if (index >= 0 && index < n_children)
 +		return index % EA_CALENDAR_COLUMN_NUM;
 +	return -1;
 +}
 +
 +static gint
 +table_interface_get_row_at_index (AtkTable *table,
 +				  gint     index)
 +{
 +	AtkGObjectAccessible *atk_gobj;
 +	GObject *g_obj;
 +	EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (table);
 +	gint n_children;
 +
 +	atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
 +	g_obj = atk_gobject_accessible_get_object (atk_gobj);
 +	if (!g_obj)
 +		return -1;
 +
 +	n_children = ea_calendar_item_get_n_children (ATK_OBJECT (ea_calitem));
 +	if (index >= 0 && index < n_children)
 +		return index / EA_CALENDAR_COLUMN_NUM;
 +	return -1;
 +}
 +
 +static gint
 +table_interface_get_column_extent_at (AtkTable      *table,
 +				      gint          row,
 +				      gint          column)
 +{
 +	AtkGObjectAccessible *atk_gobj;
 +	GObject *g_obj;
 +	ECalendarItem *calitem;
 +	EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (table);
 +
 +	atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
 +	g_obj = atk_gobject_accessible_get_object (atk_gobj);
 +	if (!g_obj)
 +		return FALSE;
 +
 +	calitem = E_CALENDAR_ITEM (g_obj);
 +	return calitem->cell_width;
 +}
 +
 +static gint
 +table_interface_get_row_extent_at (AtkTable *table,
 +				   gint row, gint column)
 +{
 +	AtkGObjectAccessible *atk_gobj;
 +	GObject *g_obj;
 +	ECalendarItem *calitem;
 +	EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (table);
 +
 +	atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
 +	g_obj = atk_gobject_accessible_get_object (atk_gobj);
 +	if (!g_obj)
 +		return FALSE;
 +
 +	calitem = E_CALENDAR_ITEM (g_obj);
 +	return calitem->cell_height;
 +}
 +
 +/* any day in the row is selected, the row is selected */
 +static gboolean
 +table_interface_is_row_selected (AtkTable *table,
 +				 gint row)
 +{
 +	AtkGObjectAccessible *atk_gobj;
 +	GObject *g_obj;
 +	gint n_rows;
 +	ECalendarItem *calitem;
 +	gint row_index_start, row_index_end;
 +	gint sel_index_start, sel_index_end;
 +
 +	GDate start_date, end_date;
 +
 +	g_return_val_if_fail (EA_IS_CALENDAR_ITEM (table), FALSE);
 +
 +	atk_gobj = ATK_GOBJECT_ACCESSIBLE (table);
 +	g_obj = atk_gobject_accessible_get_object (atk_gobj);
 +	if (!g_obj)
 +		return FALSE;
 +
 +	n_rows = table_interface_get_n_rows (table);
 +	if (row < 0 || row >= n_rows)
 +		return FALSE;
 +
 +	row_index_start = row * EA_CALENDAR_COLUMN_NUM;
 +	row_index_end = row_index_start + EA_CALENDAR_COLUMN_NUM - 1;
 +
 +	calitem = E_CALENDAR_ITEM (g_obj);
 +	if (!e_calendar_item_get_selection (calitem, &start_date, &end_date))
 +		return FALSE;
 +
 +	e_calendar_item_get_offset_for_date (calitem,
 +					     g_date_get_year (&start_date),
 +					     g_date_get_month (&start_date),
 +					     g_date_get_day (&start_date),
 +					     &sel_index_start);
 +	e_calendar_item_get_offset_for_date (calitem,
 +					     g_date_get_year (&end_date),
 +					     g_date_get_month (&end_date),
 +					     g_date_get_day (&end_date),
 +					     &sel_index_end);
 +
 +	if ((sel_index_start < row_index_start &&
 +	     sel_index_end >= row_index_start) ||
 +	    (sel_index_start >= row_index_start &&
 +	     sel_index_start <= row_index_end))
 +	    return TRUE;
 +	return FALSE;
 +}
 +
 +static gboolean
 +table_interface_is_selected (AtkTable *table,
 +			     gint     row,
 +			     gint     column)
 +{
 +	AtkGObjectAccessible *atk_gobj;
 +	GObject *g_obj;
 +	gint n_rows, n_columns;
 +	ECalendarItem *calitem;
 +	gint index;
 +	gint sel_index_start, sel_index_end;
 +
 +	GDate start_date, end_date;
 +
 +	g_return_val_if_fail (EA_IS_CALENDAR_ITEM (table), FALSE);
 +
 +	atk_gobj = ATK_GOBJECT_ACCESSIBLE (table);
 +	g_obj = atk_gobject_accessible_get_object (atk_gobj);
 +	if (!g_obj)
 +		return FALSE;
 +
 +	n_rows = table_interface_get_n_rows (table);
 +	if (row < 0 || row >= n_rows)
 +		return FALSE;
 +	n_columns = table_interface_get_n_columns (table);
 +	if (column < 0 || column >= n_columns)
 +		return FALSE;
 +
 +	index = table_interface_get_index_at (table, row, column);
 +
 +	calitem = E_CALENDAR_ITEM (g_obj);
 +	if (!e_calendar_item_get_selection (calitem, &start_date, &end_date))
 +		return FALSE;
 +
 +	e_calendar_item_get_offset_for_date (calitem,
 +					     g_date_get_year (&start_date),
 +					     g_date_get_month (&start_date),
 +					     g_date_get_day (&start_date),
 +					     &sel_index_start);
 +	e_calendar_item_get_offset_for_date (calitem,
 +					     g_date_get_year (&end_date),
 +					     g_date_get_month (&end_date),
 +					     g_date_get_day (&end_date), &sel_index_end);
 +
 +	if (sel_index_start <= index && sel_index_end >= index)
 +	    return TRUE;
 +	return FALSE;
 +}
 +
 +static gboolean
 +table_interface_is_column_selected (AtkTable *table,
 +				    gint column)
 +{
 +	return FALSE;
 +}
 +
 +static gint
 +table_interface_get_selected_rows (AtkTable *table,
 +				   gint **rows_selected)
 +{
 +	*rows_selected = NULL;
 +	return -1;
 +}
 +
 +static gint
 +table_interface_get_selected_columns (AtkTable *table,
 +				      gint **columns_selected)
 +{
 +	*columns_selected = NULL;
 +	return -1;
 +}
 +
 +static gboolean
 +table_interface_add_row_selection (AtkTable *table,
 +				   gint row)
 +{
 +	return FALSE;
 +}
 +
 +static gboolean
 +table_interface_remove_row_selection (AtkTable *table,
 +				      gint row)
 +{
 +	return FALSE;
 +}
 +
 +static gboolean
 +table_interface_add_column_selection (AtkTable *table,
 +				      gint column)
 +{
 +	return FALSE;
 +}
 +
 +static gboolean
 +table_interface_remove_column_selection (AtkTable *table,
 +					 gint     column)
 +{
 +	/* FIXME: NOT IMPLEMENTED */
 +	return FALSE;
 +}
 +
 +static AtkObject*
 +table_interface_get_row_header (AtkTable *table,
 +				gint     row)
 +{
 +	/* FIXME: NOT IMPLEMENTED */
 +	return NULL;
 +}
 +
 +static AtkObject*
 +table_interface_get_column_header (AtkTable *table,
 +				   gint     in_col)
 +{
 +	/* FIXME: NOT IMPLEMENTED */
 +	return NULL;
 +}
 +
 +static AtkObject*
 +table_interface_get_caption (AtkTable	*table)
 +{
 +	/* FIXME: NOT IMPLEMENTED */
 +	return NULL;
 +}
 +
 +static G_CONST_RETURN gchar*
 +table_interface_get_column_description (AtkTable *table, gint in_col)
 +{
 +	AtkGObjectAccessible *atk_gobj;
 +	GObject *g_obj;
 +	EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (table);
 +	const gchar *description = NULL;
 +	EaCellTable *cell_data;
 +	gint n_columns;
 +
 +	atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
 +	g_obj = atk_gobject_accessible_get_object (atk_gobj);
 +	if (!g_obj)
 +		return NULL;
 +
 +	n_columns = table_interface_get_n_columns (table);
 +	if (in_col < 0 || in_col >= n_columns)
 +		return NULL;
 +	cell_data = ea_calendar_item_get_cell_data (ea_calitem);
 +	if (!cell_data)
 +		return NULL;
 +
 +	description = ea_cell_table_get_column_label (cell_data, in_col);
 +	if (!description) {
 +		gchar buffer[128] = "column description";
 +		ea_calendar_item_get_column_label (ea_calitem, in_col,
 +						   buffer, sizeof (buffer));
 +		ea_cell_table_set_column_label (cell_data, in_col, buffer);
 +		description = ea_cell_table_get_column_label (cell_data,
 +							      in_col);
 +	}
 +	return description;
 +}
 +
 +static G_CONST_RETURN gchar*
 +table_interface_get_row_description (AtkTable *table, gint row)
 +{
 +	AtkGObjectAccessible *atk_gobj;
 +	GObject *g_obj;
 +	EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (table);
 +	const gchar *description = NULL;
 +	EaCellTable *cell_data;
 +	gint n_rows;
 +
 +	atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
 +	g_obj = atk_gobject_accessible_get_object (atk_gobj);
 +	if (!g_obj)
 +		return NULL;
 +
 +	n_rows = table_interface_get_n_rows (table);
 +	if (row < 0 || row >= n_rows)
 +		return NULL;
 +	cell_data = ea_calendar_item_get_cell_data (ea_calitem);
 +	if (!cell_data)
 +		return NULL;
 +
 +	description = ea_cell_table_get_row_label (cell_data, row);
 +	if (!description) {
 +		gchar buffer[128] = "row description";
 +		ea_calendar_item_get_row_label (ea_calitem, row,
 +						buffer, sizeof (buffer));
 +		ea_cell_table_set_row_label (cell_data, row, buffer);
 +		description = ea_cell_table_get_row_label (cell_data,
 +							   row);
 +	}
 +	return description;
 +}
 +
 +static AtkObject*
 +table_interface_get_summary (AtkTable	*table)
 +{
 +	/* FIXME: NOT IMPLEMENTED */
 +	return NULL;
 +}
 +
 +/* atkselection interface */
 +
 +static void
 +atk_selection_interface_init (AtkSelectionIface *iface)
 +{
 +	g_return_if_fail (iface != NULL);
 +
 +	iface->add_selection = selection_interface_add_selection;
 +	iface->clear_selection = selection_interface_clear_selection;
 +	iface->ref_selection = selection_interface_ref_selection;
 +	iface->get_selection_count = selection_interface_get_selection_count;
 +	iface->is_child_selected = selection_interface_is_child_selected;
 +}
 +
 +static gboolean
 +selection_interface_add_selection (AtkSelection *selection, gint index)
 +{
 +	AtkGObjectAccessible *atk_gobj;
 +	GObject *g_obj;
 +	ECalendarItem *calitem;
 +	EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (selection);
 +	gint year, month, day;
 +	GDate start_date, end_date;
 +
 +	atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
 +	g_obj = atk_gobject_accessible_get_object (atk_gobj);
 +	if (!g_obj)
 +		return FALSE;
 +
 +	calitem = E_CALENDAR_ITEM (g_obj);
 +	if (!e_calendar_item_get_date_for_offset (calitem, index,
 +						  &year, &month, &day))
 +		return FALSE;
 +
 +	/* FIXME: not support mulit-selection */
 +	g_date_set_dmy (&start_date, day, month + 1, year);
 +	end_date = start_date;
 +	e_calendar_item_set_selection (calitem, &start_date, &end_date);
 +	return TRUE;
 +}
 +
 +static gboolean
 +selection_interface_clear_selection (AtkSelection *selection)
 +{
 +	AtkGObjectAccessible *atk_gobj;
 +	GObject *g_obj;
 +	ECalendarItem *calitem;
 +	EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (selection);
 +
 +	atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
 +	g_obj = atk_gobject_accessible_get_object (atk_gobj);
 +	if (!g_obj)
 +		return FALSE;
 +
 +	calitem = E_CALENDAR_ITEM (g_obj);
 +	e_calendar_item_set_selection (calitem, NULL, NULL);
 +
 +	return TRUE;
 +}
 +
 +static AtkObject*
 +selection_interface_ref_selection (AtkSelection *selection, gint i)
 +{
 +	GObject *g_obj;
 +	ECalendarItem *calitem;
 +	EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (selection);
 +	gint count, sel_offset;
 +	GDate start_date, end_date;
 +
 +	count = selection_interface_get_selection_count (selection);
 +	if (i < 0 || i >= count)
 +		return NULL;
 +
 +	g_obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (ea_calitem));
 +
 +	calitem = E_CALENDAR_ITEM (g_obj);
 +	if (!e_calendar_item_get_selection (calitem, &start_date, &end_date))
 +		return NULL;
 +	if (!e_calendar_item_get_offset_for_date (calitem,
 +						  g_date_get_year (&start_date),
 +						  g_date_get_month (&start_date) - 1,
 +						  g_date_get_day (&start_date),
 +						  &sel_offset))
 +		return NULL;
 +
 +	return ea_calendar_item_ref_child (ATK_OBJECT (selection), sel_offset + i);
 +}
 +
 +static gint
 +selection_interface_get_selection_count (AtkSelection *selection)
 +{
 +	AtkGObjectAccessible *atk_gobj;
 +	GObject *g_obj;
 +	ECalendarItem *calitem;
 +	EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (selection);
 +	GDate start_date, end_date;
 +
 +	atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
 +	g_obj = atk_gobject_accessible_get_object (atk_gobj);
 +	if (!g_obj)
 +		return 0;
 +
 +	calitem = E_CALENDAR_ITEM (g_obj);
 +	if (e_calendar_item_get_selection (calitem, &start_date, &end_date))
 +		return g_date_days_between (&start_date, &end_date) + 1;
 +	else
 +		return 0;
 +}
 +
 +static gboolean
 +selection_interface_is_child_selected (AtkSelection *selection, gint index)
 +{
 +	AtkGObjectAccessible *atk_gobj;
 +	GObject *g_obj;
 +	EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (selection);
 +	gint row, column, n_children;
 +
 +	atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
 +	g_obj = atk_gobject_accessible_get_object (atk_gobj);
 +	if (!g_obj)
 +		return FALSE;
 +
 +	n_children = atk_object_get_n_accessible_children (ATK_OBJECT (selection));
 +	if (index < 0 || index >= n_children)
 +		return FALSE;
 +
 +	row = index / EA_CALENDAR_COLUMN_NUM;
 +	column = index % EA_CALENDAR_COLUMN_NUM;
 +
 +	return table_interface_is_selected (ATK_TABLE (selection), row, column);
 +}
 +
 +/* callbacks */
 +
 +static void
 +selection_preview_change_cb (ECalendarItem *calitem)
 +{
 +	AtkObject *atk_obj;
 +	AtkObject *item_cell;
 +
 +	g_return_if_fail (E_IS_CALENDAR_ITEM (calitem));
 +	atk_obj = atk_gobject_accessible_for_object (G_OBJECT (calitem));
 +	ea_calendar_item_destory_cell_data (EA_CALENDAR_ITEM (atk_obj));
 +
 +	/* only deal with the first selected child, for now */
 +	item_cell = atk_selection_ref_selection (ATK_SELECTION (atk_obj),
 +						 0);
 +
 +	if (item_cell)
 +		ea_calendar_set_focus_object (EA_CALENDAR_ITEM (atk_obj), item_cell);
 +
 +	g_signal_emit_by_name (atk_obj,
 +			       "active-descendant-changed",
 +			       item_cell);
 +	g_signal_emit_by_name (atk_obj, "selection_changed");
 +}
 +
 +static void
 +date_range_changed_cb (ECalendarItem *calitem)
 +{
 +	AtkObject *atk_obj;
 +	AtkObject *item_cell;
 +
 +	g_return_if_fail (E_IS_CALENDAR_ITEM (calitem));
 +	atk_obj = atk_gobject_accessible_for_object (G_OBJECT (calitem));
 +	ea_calendar_item_destory_cell_data (EA_CALENDAR_ITEM (atk_obj));
 +
 +	item_cell = atk_selection_ref_selection (ATK_SELECTION (atk_obj),
 +							0);
 +	if (item_cell)
 +		ea_calendar_set_focus_object (EA_CALENDAR_ITEM (atk_obj), item_cell);
 +
 +	g_signal_emit_by_name (atk_obj, "model_changed");
 +}
 +
 +/* helpers */
 +
 +static EaCellTable *
 +ea_calendar_item_get_cell_data (EaCalendarItem *ea_calitem)
 +{
 +	AtkGObjectAccessible *atk_gobj;
 +	GObject *g_obj;
 +	EaCellTable *cell_data;
 +
 +	g_return_val_if_fail (ea_calitem, NULL);
 +
 +	atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
 +	g_obj = atk_gobject_accessible_get_object (atk_gobj);
 +	if (!g_obj)
 +		return NULL;
 +
 +	cell_data = g_object_get_data (G_OBJECT(ea_calitem),
 +				       "ea-calendar-cell-table");
 +
 +	if (!cell_data) {
 +		gint n_cells = ea_calendar_item_get_n_children (ATK_OBJECT(ea_calitem));
 +		cell_data = ea_cell_table_create (n_cells/EA_CALENDAR_COLUMN_NUM,
 +						  EA_CALENDAR_COLUMN_NUM,
 +						  FALSE);
 +		g_object_set_data (G_OBJECT(ea_calitem),
 +				   "ea-calendar-cell-table", cell_data);
 +	}
 +	return cell_data;
 +}
 +
 +static void
 +ea_calendar_item_destory_cell_data (EaCalendarItem *ea_calitem)
 +{
 +	EaCellTable *cell_data;
 +
 +	g_return_if_fail (ea_calitem);
 +
 +	cell_data = g_object_get_data (G_OBJECT(ea_calitem),
 +				       "ea-calendar-cell-table");
 +	if (cell_data) {
 +		g_object_set_data (G_OBJECT(ea_calitem),
 +				   "ea-calendar-cell-table", NULL);
 +		ea_cell_table_destroy (cell_data);
 +	}
 +}
 +
 +static gboolean
 +ea_calendar_item_get_row_label (EaCalendarItem *ea_calitem, gint row,
 +				gchar *buffer, gint buffer_size)
 +{
 +	AtkGObjectAccessible *atk_gobj;
 +	GObject *g_obj;
 +	ECalendarItem *calitem;
 +	gint index, week_num;
 +	gint year, month, day;
 +
 +	g_return_val_if_fail (ea_calitem, FALSE);
 +
 +	atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
 +	g_obj = atk_gobject_accessible_get_object (atk_gobj);
 +	if (!g_obj)
 +		return FALSE;
 +
 +	calitem = E_CALENDAR_ITEM (g_obj);
 +
 +	index = atk_table_get_index_at (ATK_TABLE (ea_calitem), row, 0);
 +	if (!e_calendar_item_get_date_for_offset (calitem, index,
 +						  &year, &month, &day))
 +		return FALSE;
 +
 +	week_num = e_calendar_item_get_week_number (calitem,
 +						    day, month, year);
 +
 +	g_snprintf (buffer, buffer_size, "week number : %d", week_num);
 +	return TRUE;
 +}
 +
 +static gboolean
 +ea_calendar_item_get_column_label (EaCalendarItem *ea_calitem, gint column,
 +				   gchar *buffer, gint buffer_size)
 +{
 +	AtkGObjectAccessible *atk_gobj;
 +	GObject *g_obj;
 +	ECalendarItem *calitem;
 +	const gchar *abbr_name;
 +
 +	g_return_val_if_fail (ea_calitem, FALSE);
 +
 +	atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
 +	g_obj = atk_gobject_accessible_get_object (atk_gobj);
 +	if (!g_obj)
 +		return FALSE;
 +
 +	/* Columns are 0 = Monday ... 6 = Sunday */
 +	calitem = E_CALENDAR_ITEM (g_obj);
 +	abbr_name = e_get_weekday_name (column + 1, TRUE);
 +	g_strlcpy (buffer, abbr_name, buffer_size);
 +
 +	return TRUE;
 +}
 +
 +/* the coordinate the e-calendar canvas coord */
 +gboolean
 +e_calendar_item_get_day_extents (ECalendarItem *calitem,
 +				 gint year, gint month, gint date,
 +				 gint *x, gint *y,
 +				 gint *width, gint *height)
 +{
 +	GnomeCanvasItem *item;
 +	GtkWidget *widget;
 +	GtkStyle *style;
 +	PangoFontDescription *font_desc;
 +	PangoContext *pango_context;
 +	PangoFontMetrics *font_metrics;
 +	gint char_height, xthickness, ythickness, text_y;
 +	gint new_year, new_month, num_months, months_offset;
 +	gint month_x, month_y, month_cell_x, month_cell_y;
 +	gint month_row, month_col;
 +	gint day_row, day_col;
 +	gint days_from_week_start;
 +
 +	g_return_val_if_fail (E_IS_CALENDAR_ITEM (calitem), FALSE);
 +
 +	item = GNOME_CANVAS_ITEM (calitem);
 +	widget = GTK_WIDGET (item->canvas);
 +	style = widget->style;
 +
 +	/* Set up Pango prerequisites */
 +	font_desc = calitem->font_desc;
 +	if (!font_desc)
 +		font_desc = style->font_desc;
 +	pango_context = gtk_widget_get_pango_context (widget);
 +	font_metrics = pango_context_get_metrics (pango_context, font_desc,
 +						  pango_context_get_language (pango_context));
 +
 +	char_height =
 +		PANGO_PIXELS (pango_font_metrics_get_ascent (font_metrics)) +
 +		PANGO_PIXELS (pango_font_metrics_get_descent (font_metrics));
 +
 +	xthickness = style->xthickness;
 +	ythickness = style->ythickness;
 +
 +	new_year = year;
 +	new_month = month;
 +	e_calendar_item_normalize_date	(calitem, &new_year, &new_month);
 +	num_months = calitem->rows * calitem->cols;
 +	months_offset = (new_year - calitem->year) * 12
 +		+ new_month - calitem->month;
 +
 +	if (months_offset > num_months || months_offset < 0)
 +		return FALSE;
 +
 +	month_row = months_offset / calitem->cols;
 +	month_col = months_offset % calitem->cols;
 +
 +	month_x = item->x1 + xthickness + calitem->x_offset
 +		+ month_col * calitem->month_width;
 +	month_y = item->y1 + ythickness + month_row * calitem->month_height;
 +
 +	month_cell_x = month_x + E_CALENDAR_ITEM_XPAD_BEFORE_WEEK_NUMBERS
 + 		+ calitem->month_lpad + E_CALENDAR_ITEM_XPAD_BEFORE_CELLS;
 +	text_y = month_y + ythickness * 2
 +		+ E_CALENDAR_ITEM_YPAD_ABOVE_MONTH_NAME
 +		+ char_height + E_CALENDAR_ITEM_YPAD_BELOW_MONTH_NAME
 +		+ E_CALENDAR_ITEM_YPAD_ABOVE_DAY_LETTERS + calitem->month_tpad;
 +
 +	month_cell_y = text_y + char_height
 +		+ E_CALENDAR_ITEM_YPAD_BELOW_DAY_LETTERS + 1
 +		+ E_CALENDAR_ITEM_YPAD_ABOVE_CELLS;
 +
 +	days_from_week_start =
 +		e_calendar_item_get_n_days_from_week_start (calitem, new_year,
 +							    new_month);
 +	day_row = (date + days_from_week_start - 1) / EA_CALENDAR_COLUMN_NUM;
 +	day_col = (date + days_from_week_start - 1) % EA_CALENDAR_COLUMN_NUM;
 +
 +	*x = month_cell_x + day_col * calitem->cell_width;
 +	*y = month_cell_y + day_row * calitem->cell_height;
 +	*width = calitem->cell_width;
 +	*height = calitem->cell_height;
 +
 +	return TRUE;
 +}
 +
 +/* month is from 0 to 11 */
 +gboolean
 +e_calendar_item_get_date_for_offset (ECalendarItem *calitem, gint day_offset,
 +				     gint *year, gint *month, gint *day)
 +{
 +	gint start_year, start_month, start_day;
 +	gint end_year, end_month, end_day;
 +	GDate *start_date;
 +
 +	g_return_val_if_fail (E_IS_CALENDAR_ITEM (calitem), FALSE);
 +
 +	if (!e_calendar_item_get_date_range (calitem, &start_year,
 +					     &start_month, &start_day,
 +					     &end_year, &end_month,
 +					     &end_day))
 +		return FALSE;
 +
 +	start_date = g_date_new_dmy (start_day, start_month + 1, start_year);
 +
 +	g_date_add_days (start_date, day_offset);
 +
 +	*year = g_date_get_year (start_date);
 +	*month = g_date_get_month (start_date) - 1;
 +	*day = g_date_get_day (start_date);
 +
 +	return TRUE;
 +}
 +
 +/* the arg month is from 0 to 11 */
 +static gboolean
 +e_calendar_item_get_offset_for_date (ECalendarItem *calitem,
 +				     gint year, gint month, gint day,
 +				     gint *offset)
 +{
 +	gint start_year, start_month, start_day;
 +	gint end_year, end_month, end_day;
 +	GDate *start_date, *end_date;
 +
 +	*offset = 0;
 +	g_return_val_if_fail (E_IS_CALENDAR_ITEM (calitem), FALSE);
 +
 +	if (!e_calendar_item_get_date_range (calitem, &start_year,
 +					     &start_month, &start_day,
 +					     &end_year, &end_month,
 +					     &end_day))
 +		return FALSE;
 +
 +	start_date = g_date_new_dmy (start_day, start_month + 1, start_year);
 +	end_date = g_date_new_dmy (day, month + 1, year);
 +
 +	*offset = g_date_days_between (start_date, end_date);
 +	g_free (start_date);
 +	g_free (end_date);
 +
 +	return TRUE;
 +}
 +
 +gint
 +e_calendar_item_get_n_days_from_week_start (ECalendarItem *calitem,
 +					    gint year, gint month)
 +{
 +	struct tm tmp_tm;
 +	gint start_weekday, days_from_week_start;
 +
 +	memset (&tmp_tm, 0, sizeof (tmp_tm));
 +	tmp_tm.tm_year = year - 1900;
 +	tmp_tm.tm_mon = month;
 +	tmp_tm.tm_mday = 1;
 +	tmp_tm.tm_isdst = -1;
 +	mktime (&tmp_tm);
 +	start_weekday = (tmp_tm.tm_wday + 6) % 7;   /* 0 to 6 */
 +	days_from_week_start = (start_weekday + 7 - calitem->week_start_day)
 +		% 7;
 +	return days_from_week_start;
 +}
 +
 +static void
 +ea_calendar_set_focus_object (EaCalendarItem *ea_calitem, AtkObject *item_cell)
 +{
 +	AtkStateSet *state_set, *old_state_set;
 +	AtkObject *old_cell;
 +
 +	old_cell = (AtkObject *)g_object_get_data (G_OBJECT(ea_calitem), "gail-focus-object");
 +	if (old_cell && EA_IS_CALENDAR_CELL (old_cell)) {
 +		old_state_set = atk_object_ref_state_set (old_cell);
 +		atk_state_set_remove_state (old_state_set, ATK_STATE_FOCUSED);
 +		g_object_unref (old_state_set);
 +	}
 +	if (old_cell)
 +		g_object_unref (old_cell);
 +
 +	state_set = atk_object_ref_state_set (item_cell);
 +	atk_state_set_add_state (state_set, ATK_STATE_FOCUSED);
 +	g_object_set_data (G_OBJECT(ea_calitem), "gail-focus-object", item_cell);
 +	g_object_unref (state_set);
 +}
diff --cc widgets/misc/a11y/ea-widgets.c
index 239299d,0000000..9deede2
mode 100644,000000..100644
--- a/widgets/misc/a11y/ea-widgets.c
+++ b/widgets/misc/a11y/ea-widgets.c
@@@ -1,32 -1,0 +1,32 @@@
 +/*
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Authors:
 + *		Bolian Yin <bolian yin sun com>
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "a11y/ea-factory.h"
 +#include "ea-calendar-item.h"
 +#include "ea-widgets.h"
 +
 +EA_FACTORY_GOBJECT (EA_TYPE_CALENDAR_ITEM, ea_calendar_item, ea_calendar_item_new)
 +
 +void e_calendar_item_a11y_init (void)
 +{
 +    EA_SET_FACTORY (e_calendar_item_get_type (), ea_calendar_item);
 +}
diff --cc widgets/misc/a11y/ea-widgets.h
index d19c908,0000000..495222a
mode 100644,000000..100644
--- a/widgets/misc/a11y/ea-widgets.h
+++ b/widgets/misc/a11y/ea-widgets.h
@@@ -1,32 -1,0 +1,32 @@@
 +/*
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Authors:
 + *		Bolian Yin <bolian yin sun com>
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +/* Evolution Accessibility
 +*/
 +
 +#ifndef _EA_WIDGETS_H__
 +#define _EA_WIDGETS_H__
 +
 +void e_calendar_item_a11y_init (void);
 +
 +#endif /* _EA_WIDGETS_H__ */
diff --cc widgets/misc/e-account-manager.c
index 04e050b,0000000..24b579d
mode 100644,000000..100644
--- a/widgets/misc/e-account-manager.c
+++ b/widgets/misc/e-account-manager.c
@@@ -1,461 -1,0 +1,461 @@@
 +/*
 + * e-account-manager.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-account-manager.h"
 +
 +#include <glib/gi18n.h>
 +#include <gdk/gdkkeysyms.h>
 +#include "e-util/e-binding.h"
 +#include "e-account-tree-view.h"
 +
 +#define E_ACCOUNT_MANAGER_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_ACCOUNT_MANAGER, EAccountManagerPrivate))
 +
 +struct _EAccountManagerPrivate {
 +	EAccountList *account_list;
 +
 +	GtkWidget *tree_view;
 +	GtkWidget *add_button;
 +	GtkWidget *edit_button;
 +	GtkWidget *delete_button;
 +	GtkWidget *default_button;
 +};
 +
 +enum {
 +	PROP_0,
 +	PROP_ACCOUNT_LIST
 +};
 +
 +enum {
 +	ADD_ACCOUNT,
 +	EDIT_ACCOUNT,
 +	DELETE_ACCOUNT,
 +	LAST_SIGNAL
 +};
 +
 +static gpointer parent_class;
 +static guint signals[LAST_SIGNAL];
 +
 +static void
 +account_manager_default_clicked_cb (EAccountManager *manager)
 +{
 +	EAccountTreeView *tree_view;
 +	EAccountList *account_list;
 +	EAccount *account;
 +
 +	tree_view = e_account_manager_get_tree_view (manager);
 +	account_list = e_account_manager_get_account_list (manager);
 +	account = e_account_tree_view_get_selected (tree_view);
 +	g_return_if_fail (account != NULL);
 +
 +	e_account_list_set_default (account_list, account);
 +
 +	/* This signals the tree view to refresh. */
 +	e_account_list_change (account_list, account);
 +}
 +
 +static gboolean
 +account_manager_key_press_event_cb (EAccountManager *manager,
 +                                    GdkEventKey *event)
 +{
 +	if (event->keyval == GDK_Delete) {
 +		e_account_manager_delete_account (manager);
 +		return TRUE;
 +	}
 +
 +	return FALSE;
 +}
 +
 +static void
 +account_manager_selection_changed_cb (EAccountManager *manager,
 +                                      GtkTreeSelection *selection)
 +{
 +	EAccountTreeView *tree_view;
 +	EAccountList *account_list;
 +	EAccount *default_account;
 +	EAccount *account;
 +	GtkWidget *add_button;
 +	GtkWidget *edit_button;
 +	GtkWidget *delete_button;
 +	GtkWidget *default_button;
 +	const gchar *url = NULL;
 +	gboolean has_proxies;
 +	gboolean sensitive;
 +
 +	add_button = manager->priv->add_button;
 +	edit_button = manager->priv->edit_button;
 +	delete_button = manager->priv->delete_button;
 +	default_button = manager->priv->default_button;
 +
 +	tree_view = e_account_manager_get_tree_view (manager);
 +	account = e_account_tree_view_get_selected (tree_view);
 +	account_list = e_account_tree_view_get_account_list (tree_view);
 +
 +	if (account != NULL)
 +		url = e_account_get_string (account, E_ACCOUNT_SOURCE_URL);
 +	else
 +		gtk_widget_grab_focus (add_button);
 +
 +	has_proxies = (url != NULL) &&
 +		e_account_list_account_has_proxies (account_list, account);
 +
 +	/* XXX EAccountList misuses const */
 +	default_account = (EAccount *)
 +		e_account_list_get_default (account_list);
 +
 +	sensitive = (account != NULL) && !has_proxies;
 +	gtk_widget_set_sensitive (edit_button, sensitive);
 +
 +	sensitive = (account != NULL);
 +	gtk_widget_set_sensitive (delete_button, sensitive);
 +
 +	sensitive = (account != NULL && account != default_account);
 +	gtk_widget_set_sensitive (default_button, sensitive);
 +}
 +
 +static void
 +account_manager_set_property (GObject *object,
 +                              guint property_id,
 +                              const GValue *value,
 +                              GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_ACCOUNT_LIST:
 +			e_account_manager_set_account_list (
 +				E_ACCOUNT_MANAGER (object),
 +				g_value_get_object (value));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +account_manager_get_property (GObject *object,
 +                              guint property_id,
 +                              GValue *value,
 +                              GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_ACCOUNT_LIST:
 +			g_value_set_object (
 +				value,
 +				e_account_manager_get_account_list (
 +				E_ACCOUNT_MANAGER (object)));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +account_manager_dispose (GObject *object)
 +{
 +	EAccountManagerPrivate *priv;
 +
 +	priv = E_ACCOUNT_MANAGER_GET_PRIVATE (object);
 +
 +	if (priv->account_list != NULL) {
 +		g_object_unref (priv->account_list);
 +		priv->account_list = NULL;
 +	}
 +
 +	if (priv->tree_view != NULL) {
 +		g_object_unref (priv->tree_view);
 +		priv->tree_view = NULL;
 +	}
 +
 +	if (priv->add_button != NULL) {
 +		g_object_unref (priv->add_button);
 +		priv->add_button = NULL;
 +	}
 +
 +	if (priv->edit_button != NULL) {
 +		g_object_unref (priv->edit_button);
 +		priv->edit_button = NULL;
 +	}
 +
 +	if (priv->delete_button != NULL) {
 +		g_object_unref (priv->delete_button);
 +		priv->delete_button = NULL;
 +	}
 +
 +	/* Chain up to parent's dispose() method. */
 +	G_OBJECT_CLASS (parent_class)->dispose (object);
 +}
 +
 +static void
 +account_manager_class_init (EAccountManagerClass *class)
 +{
 +	GObjectClass *object_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (EAccountManagerPrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->set_property = account_manager_set_property;
 +	object_class->get_property = account_manager_get_property;
 +	object_class->dispose = account_manager_dispose;
 +
 +	/* XXX If we moved the account editor to /widgets/misc we
 +	 *     could handle adding and editing accounts directly. */
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_ACCOUNT_LIST,
 +		g_param_spec_object (
 +			"account-list",
 +			"Account List",
 +			NULL,
 +			E_TYPE_ACCOUNT_LIST,
 +			G_PARAM_READWRITE |
 +			G_PARAM_CONSTRUCT));
 +
 +	signals[ADD_ACCOUNT] = g_signal_new (
 +		"add-account",
 +		G_OBJECT_CLASS_TYPE (class),
 +		G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
 +		G_STRUCT_OFFSET (EAccountManagerClass, add_account),
 +		NULL, NULL,
 +		g_cclosure_marshal_VOID__VOID,
 +		G_TYPE_NONE, 0);
 +
 +	signals[EDIT_ACCOUNT] = g_signal_new (
 +		"edit-account",
 +		G_OBJECT_CLASS_TYPE (class),
 +		G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
 +		G_STRUCT_OFFSET (EAccountManagerClass, edit_account),
 +		NULL, NULL,
 +		g_cclosure_marshal_VOID__VOID,
 +		G_TYPE_NONE, 0);
 +
 +	signals[DELETE_ACCOUNT] = g_signal_new (
 +		"delete-account",
 +		G_OBJECT_CLASS_TYPE (class),
 +		G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
 +		G_STRUCT_OFFSET (EAccountManagerClass, delete_account),
 +		NULL, NULL,
 +		g_cclosure_marshal_VOID__VOID,
 +		G_TYPE_NONE, 0);
 +}
 +
 +static void
 +account_manager_init (EAccountManager *manager)
 +{
 +	GtkTreeSelection *selection;
 +	GtkWidget *container;
 +	GtkWidget *widget;
 +
 +	manager->priv = E_ACCOUNT_MANAGER_GET_PRIVATE (manager);
 +
 +	gtk_table_resize (GTK_TABLE (manager), 1, 2);
 +	gtk_table_set_col_spacings (GTK_TABLE (manager), 6);
 +	gtk_table_set_row_spacings (GTK_TABLE (manager), 12);
 +
 +	container = GTK_WIDGET (manager);
 +
 +	widget = gtk_scrolled_window_new (NULL, NULL);
 +	gtk_scrolled_window_set_policy (
 +		GTK_SCROLLED_WINDOW (widget),
 +		GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
 +	gtk_scrolled_window_set_shadow_type (
 +		GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
 +	gtk_table_attach (
 +		GTK_TABLE (container), widget, 0, 1, 0, 1,
 +		GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
 +	gtk_widget_show (widget);
 +
 +	container = widget;
 +
 +	widget = e_account_tree_view_new ();
 +	gtk_container_add (GTK_CONTAINER (container), widget);
 +	manager->priv->tree_view = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	e_mutual_binding_new (
 +		G_OBJECT (manager), "account-list",
 +		G_OBJECT (widget), "account-list");
 +
 +	g_signal_connect_swapped (
 +		widget, "key-press-event",
 +		G_CALLBACK (account_manager_key_press_event_cb),
 +		manager);
 +
 +	g_signal_connect_swapped (
 +		widget, "row-activated",
 +		G_CALLBACK (e_account_manager_edit_account),
 +		manager);
 +
 +	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
 +
 +	g_signal_connect_swapped (
 +		selection, "changed",
 +		G_CALLBACK (account_manager_selection_changed_cb),
 +		manager);
 +
 +	container = GTK_WIDGET (manager);
 +
 +	widget = gtk_vbutton_box_new ();
 +	gtk_button_box_set_layout (
 +		GTK_BUTTON_BOX (widget), GTK_BUTTONBOX_START);
 +	gtk_box_set_spacing (GTK_BOX (widget), 6);
 +	gtk_table_attach (
 +		GTK_TABLE (container), widget,
 +		1, 2, 0, 2, 0, GTK_FILL, 0, 0);
 +	gtk_widget_show (widget);
 +
 +	container = widget;
 +
 +	widget = gtk_button_new_from_stock (GTK_STOCK_ADD);
 +	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
 +	manager->priv->add_button = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	g_signal_connect_swapped (
 +		widget, "clicked",
 +		G_CALLBACK (e_account_manager_add_account), manager);
 +
 +	widget = gtk_button_new_from_stock (GTK_STOCK_EDIT);
 +	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
 +	manager->priv->edit_button = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	g_signal_connect_swapped (
 +		widget, "clicked",
 +		G_CALLBACK (e_account_manager_edit_account), manager);
 +
 +	widget = gtk_button_new_from_stock (GTK_STOCK_DELETE);
 +	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
 +	manager->priv->delete_button = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	g_signal_connect_swapped (
 +		widget, "clicked",
 +		G_CALLBACK (e_account_manager_delete_account), manager);
 +
 +	widget = gtk_button_new_with_mnemonic (_("De_fault"));
 +	gtk_button_set_image (
 +		GTK_BUTTON (widget), gtk_image_new_from_icon_name (
 +		"emblem-default", GTK_ICON_SIZE_BUTTON));
 +	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
 +	manager->priv->default_button = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	g_signal_connect_swapped (
 +		widget, "clicked",
 +		G_CALLBACK (account_manager_default_clicked_cb), manager);
 +}
 +
 +GType
 +e_account_manager_get_type (void)
 +{
 +	static GType type = 0;
 +
 +	if (G_UNLIKELY (type == 0)) {
 +		static const GTypeInfo type_info = {
 +			sizeof (EAccountManagerClass),
 +			(GBaseInitFunc) NULL,
 +			(GBaseFinalizeFunc) NULL,
 +			(GClassInitFunc) account_manager_class_init,
 +			(GClassFinalizeFunc) NULL,
 +			NULL,  /* class_init */
 +			sizeof (EAccountManager),
 +			0,     /* n_preallocs */
 +			(GInstanceInitFunc) account_manager_init,
 +			NULL   /* value_table */
 +		};
 +
 +		type = g_type_register_static (
 +			GTK_TYPE_TABLE, "EAccountManager", &type_info, 0);
 +	}
 +
 +	return type;
 +}
 +
 +GtkWidget *
 +e_account_manager_new (EAccountList *account_list)
 +{
 +	g_return_val_if_fail (E_IS_ACCOUNT_LIST (account_list), NULL);
 +
 +	return g_object_new (
 +		E_TYPE_ACCOUNT_MANAGER,
 +		"account-list", account_list, NULL);
 +}
 +
 +void
 +e_account_manager_add_account (EAccountManager *manager)
 +{
 +	g_return_if_fail (E_IS_ACCOUNT_MANAGER (manager));
 +
 +	g_signal_emit (manager, signals[ADD_ACCOUNT], 0);
 +}
 +
 +void
 +e_account_manager_edit_account (EAccountManager *manager)
 +{
 +	g_return_if_fail (E_IS_ACCOUNT_MANAGER (manager));
 +
 +	g_signal_emit (manager, signals[EDIT_ACCOUNT], 0);
 +}
 +
 +void
 +e_account_manager_delete_account (EAccountManager *manager)
 +{
 +	g_return_if_fail (E_IS_ACCOUNT_MANAGER (manager));
 +
 +	g_signal_emit (manager, signals[DELETE_ACCOUNT], 0);
 +}
 +
 +EAccountList *
 +e_account_manager_get_account_list (EAccountManager *manager)
 +{
 +	g_return_val_if_fail (E_IS_ACCOUNT_MANAGER (manager), NULL);
 +
 +	return manager->priv->account_list;
 +}
 +
 +void
 +e_account_manager_set_account_list (EAccountManager *manager,
 +                                    EAccountList *account_list)
 +{
 +	g_return_if_fail (E_IS_ACCOUNT_MANAGER (manager));
 +
 +	if (account_list != NULL) {
 +		g_return_if_fail (E_IS_ACCOUNT_LIST (account_list));
 +		g_object_ref (account_list);
 +	}
 +
 +	if (manager->priv->account_list != NULL)
 +		g_object_unref (manager->priv->account_list);
 +
 +	manager->priv->account_list = account_list;
 +
 +	g_object_notify (G_OBJECT (manager), "account-list");
 +}
 +
 +EAccountTreeView *
 +e_account_manager_get_tree_view (EAccountManager *manager)
 +{
 +	g_return_val_if_fail (E_IS_ACCOUNT_MANAGER (manager), NULL);
 +
 +	return E_ACCOUNT_TREE_VIEW (manager->priv->tree_view);
 +}
diff --cc widgets/misc/e-account-manager.h
index c714576,0000000..dab8b28
mode 100644,000000..100644
--- a/widgets/misc/e-account-manager.h
+++ b/widgets/misc/e-account-manager.h
@@@ -1,82 -1,0 +1,82 @@@
 +/*
 + * e-account-manager.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_ACCOUNT_MANAGER_H
 +#define E_ACCOUNT_MANAGER_H
 +
 +#include <gtk/gtk.h>
 +#include <libedataserver/e-account-list.h>
 +#include <misc/e-account-tree-view.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_ACCOUNT_MANAGER \
 +	(e_account_manager_get_type ())
 +#define E_ACCOUNT_MANAGER(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_ACCOUNT_MANAGER, EAccountManager))
 +#define E_ACCOUNT_MANAGER_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_ACCOUNT_MANAGER, EAccountManagerClass))
 +#define E_IS_ACCOUNT_MANAGER(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_ACCOUNT_MANAGER))
 +#define E_IS_ACCOUNT_MANAGER_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), E_TYPE_ACCOUNT_MANAGER))
 +#define E_ACCOUNT_MANAGER_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_ACCOUNT_MANAGER, EAccountManagerClass))
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _EAccountManager EAccountManager;
 +typedef struct _EAccountManagerClass EAccountManagerClass;
 +typedef struct _EAccountManagerPrivate EAccountManagerPrivate;
 +
 +struct _EAccountManager {
 +	GtkTable parent;
 +	EAccountManagerPrivate *priv;
 +};
 +
 +struct _EAccountManagerClass {
 +	GtkTableClass parent_class;
 +
 +	void		(*add_account)		(EAccountManager *manager);
 +	void		(*edit_account)		(EAccountManager *manager);
 +	void		(*delete_account)	(EAccountManager *manager);
 +};
 +
 +GType		e_account_manager_get_type	(void);
 +GtkWidget *	e_account_manager_new		(EAccountList *account_list);
 +void		e_account_manager_add_account	(EAccountManager *manager);
 +void		e_account_manager_edit_account	(EAccountManager *manager);
 +void		e_account_manager_delete_account(EAccountManager *manager);
 +EAccountList *	e_account_manager_get_account_list
 +						(EAccountManager *manager);
 +void		e_account_manager_set_account_list
 +						(EAccountManager *manager,
 +						 EAccountList *account_list);
 +EAccountTreeView *
 +		e_account_manager_get_tree_view	(EAccountManager *manager);
 +
 +G_END_DECLS
 +
 +#endif /* E_ACCOUNT_MANAGER_H */
diff --cc widgets/misc/e-account-tree-view.c
index 78f92d5,0000000..8e57dfc
mode 100644,000000..100644
--- a/widgets/misc/e-account-tree-view.c
+++ b/widgets/misc/e-account-tree-view.c
@@@ -1,632 -1,0 +1,632 @@@
 +/*
 + * e-account-tree-view.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-account-tree-view.h"
 +
 +#include <glib/gi18n.h>
 +#include <camel/camel-url.h>
 +
 +#define E_ACCOUNT_TREE_VIEW_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_ACCOUNT_TREE_VIEW, EAccountTreeViewPrivate))
 +
 +enum {
 +	COLUMN_ACCOUNT,
 +	COLUMN_DEFAULT,
 +	COLUMN_ENABLED,
 +	COLUMN_NAME,
 +	COLUMN_PROTOCOL
 +};
 +
 +enum {
 +	PROP_0,
 +	PROP_ACCOUNT_LIST,
 +	PROP_SELECTED
 +};
 +
 +enum {
 +	ENABLE_ACCOUNT,
 +	DISABLE_ACCOUNT,
 +	REFRESHED,
 +	LAST_SIGNAL
 +};
 +
 +struct _EAccountTreeViewPrivate {
 +	EAccountList *account_list;
 +	GHashTable *index;
 +};
 +
 +static gpointer parent_class;
 +static guint signals[LAST_SIGNAL];
 +
 +static void
 +account_tree_view_refresh_cb (EAccountList *account_list,
 +                              EAccount *account,
 +                              EAccountTreeView *tree_view)
 +{
 +	GtkListStore *store;
 +	GtkTreeModel *model;
 +	GtkTreeIter tree_iter;
 +	EIterator *account_iter;
 +	EAccount *default_account;
 +	GHashTable *index;
 +	GList *list = NULL;
 +	GList *iter;
 +
 +	store = gtk_list_store_new (
 +		5, E_TYPE_ACCOUNT, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
 +		G_TYPE_STRING, G_TYPE_STRING);
 +	model = GTK_TREE_MODEL (store);
 +	index = tree_view->priv->index;
 +
 +	g_hash_table_remove_all (index);
 +
 +	if (account_list == NULL)
 +		goto skip;
 +
 +	/* XXX EAccountList misuses const. */
 +	default_account = (EAccount *)
 +		e_account_list_get_default (account_list);
 +
 +	/* Build a list of EAccounts to display. */
 +	account_iter = e_list_get_iterator (E_LIST (account_list));
 +	while (e_iterator_is_valid (account_iter)) {
 +
 +		/* XXX EIterator misuses const. */
 +		account = (EAccount *) e_iterator_get (account_iter);
 +		list = g_list_prepend (list, account);
 +		e_iterator_next (account_iter);
 +	}
 +	g_object_unref (account_iter);
 +
 +	list = g_list_reverse (list);
 +
 +	/* Populate the list store and index. */
 +	for (iter = list; iter != NULL; iter = iter->next) {
 +		GtkTreeRowReference *reference;
 +		GtkTreePath *path;
 +		CamelURL *url = NULL;
 +		gboolean is_default;
 +		const gchar *protocol;
 +
 +		account = iter->data;
 +
 +		/* Skip proxy accounts. */
 +		if (account->parent_uid != NULL)
 +			continue;
 +
 +		is_default = (account == default_account);
 +
 +		if (account->source != NULL && account->source->url != NULL)
 +			url = camel_url_new (account->source->url, NULL);
 +
 +		if (url != NULL && url->protocol != NULL)
 +			protocol = url->protocol;
 +		else
 +			protocol = _("None");
 +
 +		gtk_list_store_append (store, &tree_iter);
 +		gtk_list_store_set (
 +			store, &tree_iter,
 +			COLUMN_ACCOUNT, account,
 +			COLUMN_DEFAULT, is_default,
 +			COLUMN_ENABLED, account->enabled,
 +			COLUMN_NAME, account->name,
 +			COLUMN_PROTOCOL, protocol, -1);
 +
 +		path = gtk_tree_model_get_path (model, &tree_iter);
 +		reference = gtk_tree_row_reference_new (model, path);
 +		g_hash_table_insert (index, account, reference);
 +		gtk_tree_path_free (path);
 +
 +		if (url != NULL)
 +			camel_url_free (url);
 +	}
 +
 +skip:
 +	/* Restore the previously selected account. */
 +	account = e_account_tree_view_get_selected (tree_view);
 +	if (account != NULL)
 +		g_object_ref (account);
 +	gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), model);
 +	e_account_tree_view_set_selected (tree_view, account);
 +	if (account != NULL)
 +		g_object_unref (account);
 +
 +	g_signal_emit (tree_view, signals[REFRESHED], 0);
 +}
 +
 +static void
 +account_tree_view_enabled_toggled_cb (EAccountTreeView *tree_view,
 +                                      gchar *path_string,
 +                                      GtkCellRendererToggle *renderer)
 +{
 +	GtkTreeSelection *selection;
 +	GtkTreePath *path;
 +
 +	/* Change the selection first so we enable or disable the
 +	 * correct account. */
 +	path = gtk_tree_path_new_from_string (path_string);
 +	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
 +	gtk_tree_selection_select_path (selection, path);
 +	gtk_tree_path_free (path);
 +
 +	if (gtk_cell_renderer_toggle_get_active (renderer))
 +		e_account_tree_view_disable_account (tree_view);
 +	else
 +		e_account_tree_view_enable_account (tree_view);
 +}
 +
 +static void
 +account_tree_view_selection_changed_cb (EAccountTreeView *tree_view)
 +{
 +	g_object_notify (G_OBJECT (tree_view), "selected");
 +}
 +
 +static GObject *
 +account_tree_view_constructor (GType type,
 +                               guint n_construct_properties,
 +                               GObjectConstructParam *construct_properties)
 +{
 +	GObject *object;
 +	GtkTreeView *tree_view;
 +	GtkTreeViewColumn *column;
 +	GtkCellRenderer *renderer;
 +
 +	/* Chain up to parent's constructor() method. */
 +	object = G_OBJECT_CLASS (parent_class)->constructor (
 +		type, n_construct_properties, construct_properties);
 +
 +	tree_view = GTK_TREE_VIEW (object);
 +	gtk_tree_view_set_headers_visible (tree_view, TRUE);
 +
 +	/* Column: Enabled */
 +
 +	column = gtk_tree_view_column_new ();
 +	gtk_tree_view_column_set_expand (column, FALSE);
 +	gtk_tree_view_column_set_title (column, _("Enabled"));
 +
 +	renderer = gtk_cell_renderer_toggle_new ();
 +	gtk_tree_view_column_pack_start (column, renderer, TRUE);
 +
 +	g_signal_connect_swapped (
 +		renderer, "toggled",
 +		G_CALLBACK (account_tree_view_enabled_toggled_cb),
 +		tree_view);
 +
 +	gtk_tree_view_column_add_attribute (
 +		column, renderer, "active", COLUMN_ENABLED);
 +
 +	gtk_tree_view_append_column (tree_view, column);
 +
 +	/* Column: Account Name */
 +
 +	column = gtk_tree_view_column_new ();
 +	gtk_tree_view_column_set_expand (column, TRUE);
 +	gtk_tree_view_column_set_title (column, _("Account Name"));
 +
 +	renderer = gtk_cell_renderer_text_new ();
 +	g_object_set (renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
 +	gtk_tree_view_column_pack_start (column, renderer, TRUE);
 +
 +	gtk_tree_view_column_add_attribute (
 +		column, renderer, "text", COLUMN_NAME);
 +
 +	renderer = gtk_cell_renderer_text_new ();
 +	g_object_set (renderer, "text", _("Default"), NULL);
 +	gtk_tree_view_column_pack_end (column, renderer, FALSE);
 +
 +	gtk_tree_view_column_add_attribute (
 +		column, renderer, "visible", COLUMN_DEFAULT);
 +
 +	renderer = gtk_cell_renderer_pixbuf_new ();
 +	g_object_set (
 +		renderer, "icon-name", "emblem-default",
 +		"stock-size", GTK_ICON_SIZE_MENU, NULL);
 +	gtk_tree_view_column_pack_end (column, renderer, FALSE);
 +
 +	gtk_tree_view_column_add_attribute (
 +		column, renderer, "visible", COLUMN_DEFAULT);
 +
 +	gtk_tree_view_append_column (tree_view, column);
 +
 +	/* Column: Protocol */
 +
 +	column = gtk_tree_view_column_new ();
 +	gtk_tree_view_column_set_expand (column, FALSE);
 +	gtk_tree_view_column_set_title (column, _("Protocol"));
 +
 +	renderer = gtk_cell_renderer_text_new ();
 +	gtk_tree_view_column_pack_start (column, renderer, TRUE);
 +
 +	gtk_tree_view_column_add_attribute (
 +		column, renderer, "text", COLUMN_PROTOCOL);
 +
 +	gtk_tree_view_append_column (tree_view, column);
 +
 +	return object;
 +}
 +
 +static void
 +account_tree_view_set_property (GObject *object,
 +                                guint property_id,
 +                                const GValue *value,
 +                                GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_ACCOUNT_LIST:
 +			e_account_tree_view_set_account_list (
 +				E_ACCOUNT_TREE_VIEW (object),
 +				g_value_get_object (value));
 +			return;
 +
 +		case PROP_SELECTED:
 +			e_account_tree_view_set_selected (
 +				E_ACCOUNT_TREE_VIEW (object),
 +				g_value_get_object (value));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +account_tree_view_get_property (GObject *object,
 +                                guint property_id,
 +                                GValue *value,
 +                                GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_ACCOUNT_LIST:
 +			g_value_set_object (
 +				value,
 +				e_account_tree_view_get_account_list (
 +				E_ACCOUNT_TREE_VIEW (object)));
 +			return;
 +
 +		case PROP_SELECTED:
 +			g_value_set_object (
 +				value,
 +				e_account_tree_view_get_selected (
 +				E_ACCOUNT_TREE_VIEW (object)));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +account_tree_view_dispose (GObject *object)
 +{
 +	EAccountTreeViewPrivate *priv;
 +
 +	priv = E_ACCOUNT_TREE_VIEW_GET_PRIVATE (object);
 +
 +	if (priv->account_list != NULL) {
 +		g_signal_handlers_disconnect_by_func (
 +			priv->account_list,
 +			account_tree_view_refresh_cb, object);
 +		g_object_unref (priv->account_list);
 +		priv->account_list = NULL;
 +	}
 +
 +	g_hash_table_remove_all (priv->index);
 +
 +	/* Chain up to parent's dispose() method. */
 +	G_OBJECT_CLASS (parent_class)->dispose (object);
 +}
 +
 +static void
 +account_tree_view_finalize (GObject *object)
 +{
 +	EAccountTreeViewPrivate *priv;
 +
 +	priv = E_ACCOUNT_TREE_VIEW_GET_PRIVATE (object);
 +
 +	g_hash_table_destroy (priv->index);
 +
 +	/* Chain up to parent's finalize() method. */
 +	G_OBJECT_CLASS (parent_class)->finalize (object);
 +}
 +
 +static void
 +account_tree_view_enable_account (EAccountTreeView *tree_view)
 +{
 +	EAccountList *account_list;
 +	EAccount *account;
 +
 +	account = e_account_tree_view_get_selected (tree_view);
 +	if (account == NULL || account->enabled)
 +		return;
 +
 +	account_list = e_account_tree_view_get_account_list (tree_view);
 +	g_return_if_fail (account_list != NULL);
 +
 +	account->enabled = TRUE;
 +	e_account_list_change (account_list, account);
 +
 +	e_account_list_save (account_list);
 +}
 +
 +static void
 +account_tree_view_disable_account (EAccountTreeView *tree_view)
 +{
 +	EAccountList *account_list;
 +	EAccount *account;
 +
 +	account = e_account_tree_view_get_selected (tree_view);
 +	if (account == NULL || !account->enabled)
 +		return;
 +
 +	account_list = e_account_tree_view_get_account_list (tree_view);
 +	g_return_if_fail (account_list != NULL);
 +
 +	account->enabled = FALSE;
 +	e_account_list_change (account_list, account);
 +
 +	e_account_list_save (account_list);
 +}
 +
 +static void
 +account_tree_view_class_init (EAccountTreeViewClass *class)
 +{
 +	GObjectClass *object_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (EAccountTreeViewPrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->constructor = account_tree_view_constructor;
 +	object_class->set_property = account_tree_view_set_property;
 +	object_class->get_property = account_tree_view_get_property;
 +	object_class->dispose = account_tree_view_dispose;
 +	object_class->finalize = account_tree_view_finalize;
 +
 +	class->enable_account = account_tree_view_enable_account;
 +	class->disable_account = account_tree_view_disable_account;
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_SELECTED,
 +		g_param_spec_object (
 +			"selected",
 +			"Selected Account",
 +			NULL,
 +			E_TYPE_ACCOUNT,
 +			G_PARAM_READWRITE));
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_ACCOUNT_LIST,
 +		g_param_spec_object (
 +			"account-list",
 +			"Account List",
 +			NULL,
 +			E_TYPE_ACCOUNT_LIST,
 +			G_PARAM_READWRITE |
 +			G_PARAM_CONSTRUCT));
 +
 +	signals[ENABLE_ACCOUNT] = g_signal_new (
 +		"enable-account",
 +		G_TYPE_FROM_CLASS (class),
 +		G_SIGNAL_RUN_LAST,
 +		G_STRUCT_OFFSET (EAccountTreeViewClass, enable_account),
 +		NULL, NULL,
 +		g_cclosure_marshal_VOID__VOID,
 +		G_TYPE_NONE, 0);
 +
 +	signals[DISABLE_ACCOUNT] = g_signal_new (
 +		"disable-account",
 +		G_TYPE_FROM_CLASS (class),
 +		G_SIGNAL_RUN_LAST,
 +		G_STRUCT_OFFSET (EAccountTreeViewClass, disable_account),
 +		NULL, NULL,
 +		g_cclosure_marshal_VOID__VOID,
 +		G_TYPE_NONE, 0);
 +
 +	signals[REFRESHED] = g_signal_new (
 +		"refreshed",
 +		G_TYPE_FROM_CLASS (class),
 +		G_SIGNAL_RUN_LAST,
 +		G_STRUCT_OFFSET (EAccountTreeViewClass, refreshed),
 +		NULL, NULL,
 +		g_cclosure_marshal_VOID__VOID,
 +		G_TYPE_NONE, 0);
 +}
 +
 +static void
 +account_tree_view_init (EAccountTreeView *tree_view)
 +{
 +	GHashTable *index;
 +	GtkTreeSelection *selection;
 +
 +	/* Reverse-lookup index */
 +	index = g_hash_table_new_full (
 +		g_direct_hash, g_direct_equal,
 +		(GDestroyNotify) g_object_unref,
 +		(GDestroyNotify) gtk_tree_row_reference_free);
 +
 +	tree_view->priv = E_ACCOUNT_TREE_VIEW_GET_PRIVATE (tree_view);
 +	tree_view->priv->index = index;
 +
 +	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
 +
 +	g_signal_connect_swapped (
 +		selection, "changed",
 +		G_CALLBACK (account_tree_view_selection_changed_cb),
 +		tree_view);
 +}
 +
 +GType
 +e_account_tree_view_get_type (void)
 +{
 +	static GType type = 0;
 +
 +	if (G_UNLIKELY (type == 0)) {
 +		static const GTypeInfo type_info = {
 +			sizeof (EAccountTreeViewClass),
 +			(GBaseInitFunc) NULL,
 +			(GBaseFinalizeFunc) NULL,
 +			(GClassInitFunc) account_tree_view_class_init,
 +			(GClassFinalizeFunc) NULL,
 +			NULL,  /* class_data */
 +			sizeof (EAccountTreeView),
 +			0,     /* n_preallocs */
 +			(GInstanceInitFunc) account_tree_view_init,
 +			NULL   /* value_table */
 +		};
 +
 +		type = g_type_register_static (
 +			GTK_TYPE_TREE_VIEW, "EAccountTreeView",
 +			&type_info, 0);
 +	}
 +
 +	return type;
 +}
 +
 +GtkWidget *
 +e_account_tree_view_new (void)
 +{
 +	return g_object_new (E_TYPE_ACCOUNT_TREE_VIEW, NULL);
 +}
 +
 +void
 +e_account_tree_view_enable_account (EAccountTreeView *tree_view)
 +{
 +	g_return_if_fail (E_IS_ACCOUNT_TREE_VIEW (tree_view));
 +
 +	g_signal_emit (tree_view, signals[ENABLE_ACCOUNT], 0);
 +}
 +
 +void
 +e_account_tree_view_disable_account (EAccountTreeView *tree_view)
 +{
 +	g_return_if_fail (E_IS_ACCOUNT_TREE_VIEW (tree_view));
 +
 +	g_signal_emit (tree_view, signals[DISABLE_ACCOUNT], 0);
 +}
 +
 +EAccountList *
 +e_account_tree_view_get_account_list (EAccountTreeView *tree_view)
 +{
 +	g_return_val_if_fail (E_IS_ACCOUNT_TREE_VIEW (tree_view), NULL);
 +
 +	return tree_view->priv->account_list;
 +}
 +
 +void
 +e_account_tree_view_set_account_list (EAccountTreeView *tree_view,
 +                                      EAccountList *account_list)
 +{
 +	EAccountTreeViewPrivate *priv;
 +
 +	g_return_if_fail (E_IS_ACCOUNT_TREE_VIEW (tree_view));
 +
 +	if (account_list != NULL)
 +		g_return_if_fail (E_IS_ACCOUNT_LIST (account_list));
 +
 +	priv = E_ACCOUNT_TREE_VIEW_GET_PRIVATE (tree_view);
 +
 +	if (priv->account_list != NULL) {
 +		g_signal_handlers_disconnect_by_func (
 +			priv->account_list,
 +			account_tree_view_refresh_cb, tree_view);
 +		g_object_unref (priv->account_list);
 +		priv->account_list = NULL;
 +	}
 +
 +	if (account_list != NULL) {
 +		priv->account_list = g_object_ref (account_list);
 +
 +		/* Listen for changes to the account list. */
 +		g_signal_connect (
 +			priv->account_list, "account-added",
 +			G_CALLBACK (account_tree_view_refresh_cb),
 +			tree_view);
 +		g_signal_connect (
 +			priv->account_list, "account-changed",
 +			G_CALLBACK (account_tree_view_refresh_cb),
 +			tree_view);
 +		g_signal_connect (
 +			priv->account_list, "account-removed",
 +			G_CALLBACK (account_tree_view_refresh_cb),
 +			tree_view);
 +	}
 +
 +	account_tree_view_refresh_cb (account_list, NULL, tree_view);
 +
 +	g_object_notify (G_OBJECT (tree_view), "account-list");
 +}
 +
 +EAccount *
 +e_account_tree_view_get_selected (EAccountTreeView *tree_view)
 +{
 +	EAccount *account;
 +	GtkTreeSelection *selection;
 +	GtkTreeModel *model;
 +	GtkTreeIter iter;
 +
 +	g_return_val_if_fail (E_IS_ACCOUNT_TREE_VIEW (tree_view), NULL);
 +
 +	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
 +	if (!gtk_tree_selection_get_selected (selection, &model, &iter))
 +		return NULL;
 +
 +	gtk_tree_model_get (model, &iter, COLUMN_ACCOUNT, &account, -1);
 +
 +	return account;
 +}
 +
 +gboolean
 +e_account_tree_view_set_selected (EAccountTreeView *tree_view,
 +                                  EAccount *account)
 +{
 +	GtkTreeRowReference *reference;
 +	GtkTreeSelection *selection;
 +	GtkTreePath *path;
 +
 +	g_return_val_if_fail (E_IS_ACCOUNT_TREE_VIEW (tree_view), FALSE);
 +
 +	if (account != NULL)
 +		g_return_val_if_fail (E_IS_ACCOUNT (account), FALSE);
 +
 +	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
 +
 +	/* NULL means clear the selection. */
 +	if (account == NULL) {
 +		gtk_tree_selection_unselect_all (selection);
 +		return TRUE;
 +	}
 +
 +	/* Lookup the tree row reference for the account. */
 +	reference = g_hash_table_lookup (tree_view->priv->index, account);
 +	if (reference == NULL)
 +		return FALSE;
 +
 +	/* Select the referenced path. */
 +	path = gtk_tree_row_reference_get_path (reference);
 +	gtk_tree_selection_select_path (selection, path);
 +	gtk_tree_path_free (path);
 +
 +	g_object_notify (G_OBJECT (tree_view), "selected");
 +
 +	return TRUE;
 +}
diff --cc widgets/misc/e-account-tree-view.h
index 9d86a8f,0000000..ea13dc3
mode 100644,000000..100644
--- a/widgets/misc/e-account-tree-view.h
+++ b/widgets/misc/e-account-tree-view.h
@@@ -1,84 -1,0 +1,84 @@@
 +/*
 + * e-account-tree-view.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_ACCOUNT_TREE_VIEW_H
 +#define E_ACCOUNT_TREE_VIEW_H
 +
 +#include <gtk/gtk.h>
 +#include <libedataserver/e-account.h>
 +#include <libedataserver/e-account-list.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_ACCOUNT_TREE_VIEW \
 +	(e_account_tree_view_get_type ())
 +#define E_ACCOUNT_TREE_VIEW(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_ACCOUNT_TREE_VIEW, EAccountTreeView))
 +#define E_ACCOUNT_TREE_VIEW_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_ACCOUNT_TREE_VIEW, EAccountTreeViewClass))
 +#define E_IS_ACCOUNT_TREE_VIEW(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_ACCOUNT_TREE_VIEW))
 +#define E_IS_ACCOUNT_TREE_VIEW_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), E_TYPE_ACCOUNT_TREE_VIEW))
 +#define E_ACCOUNT_TREE_VIEW_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_ACCOUNT_TREE_VIEW, EAccountTreeViewClass))
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _EAccountTreeView EAccountTreeView;
 +typedef struct _EAccountTreeViewClass EAccountTreeViewClass;
 +typedef struct _EAccountTreeViewPrivate EAccountTreeViewPrivate;
 +
 +struct _EAccountTreeView {
 +	GtkTreeView parent;
 +	EAccountTreeViewPrivate *priv;
 +};
 +
 +struct _EAccountTreeViewClass {
 +	GtkTreeViewClass parent_class;
 +
 +	void		(*enable_account)	(EAccountTreeView *tree_view);
 +	void		(*disable_account)	(EAccountTreeView *tree_view);
 +	void		(*refreshed)		(EAccountTreeView *tree_view);
 +};
 +
 +GType		e_account_tree_view_get_type	(void);
 +GtkWidget *	e_account_tree_view_new		(void);
 +void		e_account_tree_view_enable_account
 +						(EAccountTreeView *tree_view);
 +void		e_account_tree_view_disable_account
 +						(EAccountTreeView *tree_view);
 +EAccountList *	e_account_tree_view_get_account_list
 +						(EAccountTreeView *tree_view);
 +void		e_account_tree_view_set_account_list
 +						(EAccountTreeView *tree_view,
 +						 EAccountList *account_list);
 +EAccount *	e_account_tree_view_get_selected(EAccountTreeView *tree_view);
 +gboolean	e_account_tree_view_set_selected(EAccountTreeView *tree_view,
 +						 EAccount *account);
 +
 +G_END_DECLS
 +
 +#endif /* E_ACCOUNT_TREE_VIEW_H */
diff --cc widgets/misc/e-activity-proxy.c
index bddcc12,0000000..b045394
mode 100644,000000..100644
--- a/widgets/misc/e-activity-proxy.c
+++ b/widgets/misc/e-activity-proxy.c
@@@ -1,345 -1,0 +1,345 @@@
 +/*
 + * e-activity-proxy.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-activity-proxy.h"
 +
 +#include <glib/gi18n.h>
 +#include <e-spinner.h>
 +
 +#define E_ACTIVITY_PROXY_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_ACTIVITY_PROXY, EActivityProxyPrivate))
 +
 +struct _EActivityProxyPrivate {
 +	EActivity *activity;
 +	GtkWidget *button;
 +	GtkWidget *image;
 +	GtkWidget *label;
 +	GtkWidget *cancel;
 +	GtkWidget *spinner;
 +};
 +
 +enum {
 +	PROP_0,
 +	PROP_ACTIVITY
 +};
 +
 +static gpointer parent_class;
 +
 +static void
 +activity_proxy_update (EActivityProxy *proxy)
 +{
 +	EActivity *activity = proxy->priv->activity;
 +	const gchar *icon_name;
 +	gboolean allow_cancel;
 +	gboolean cancelled;
 +	gboolean clickable;
 +	gboolean completed;
 +	gboolean sensitive;
 +	gchar *description;
 +
 +	allow_cancel = e_activity_get_allow_cancel (activity);
 +	cancelled = e_activity_is_cancelled (activity);
 +	clickable = e_activity_get_clickable (activity);
 +	completed = e_activity_is_completed (activity);
 +	icon_name = e_activity_get_icon_name (activity);
 +
 +	description = e_activity_describe (activity);
 +	gtk_widget_set_tooltip_text (GTK_WIDGET (proxy), description);
 +	gtk_label_set_text (GTK_LABEL (proxy->priv->label), description);
 +	g_free (description);
 +
 +	/* Note, an activity requires an icon name in order to
 +	 * be clickable.  We don't support spinner buttons. */
 +	if (icon_name != NULL) {
 +		gtk_image_set_from_icon_name (
 +			GTK_IMAGE (proxy->priv->image),
 +			icon_name, GTK_ICON_SIZE_MENU);
 +		gtk_button_set_image (
 +			GTK_BUTTON (proxy->priv->button),
 +			gtk_image_new_from_icon_name (
 +			icon_name, GTK_ICON_SIZE_MENU));
 +		gtk_widget_hide (proxy->priv->spinner);
 +		if (clickable) {
 +			gtk_widget_show (proxy->priv->button);
 +			gtk_widget_hide (proxy->priv->image);
 +		} else {
 +			gtk_widget_hide (proxy->priv->button);
 +			gtk_widget_show (proxy->priv->image);
 +		}
 +	} else {
 +		gtk_widget_show (proxy->priv->spinner);
 +		gtk_widget_hide (proxy->priv->button);
 +		gtk_widget_hide (proxy->priv->image);
 +	}
 +
 +	if (allow_cancel)
 +		gtk_widget_show (proxy->priv->cancel);
 +	else
 +		gtk_widget_hide (proxy->priv->cancel);
 +
 +	sensitive = !(cancelled || completed);
 +	gtk_widget_set_sensitive (proxy->priv->cancel, sensitive);
 +}
 +
 +static void
 +activity_proxy_set_activity (EActivityProxy *proxy,
 +                             EActivity *activity)
 +{
 +	g_return_if_fail (proxy->priv->activity == NULL);
 +
 +	proxy->priv->activity = g_object_ref (activity);
 +}
 +
 +static void
 +activity_proxy_set_property (GObject *object,
 +                             guint property_id,
 +                             const GValue *value,
 +                             GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_ACTIVITY:
 +			activity_proxy_set_activity (
 +				E_ACTIVITY_PROXY (object),
 +				g_value_get_object (value));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +activity_proxy_get_property (GObject *object,
 +                             guint property_id,
 +                             GValue *value,
 +                             GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_ACTIVITY:
 +			g_value_set_object (
 +				value, e_activity_proxy_get_activity (
 +				E_ACTIVITY_PROXY (object)));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +activity_proxy_dispose (GObject *object)
 +{
 +	EActivityProxyPrivate *priv;
 +
 +	priv = E_ACTIVITY_PROXY_GET_PRIVATE (object);
 +
 +	if (priv->activity != NULL) {
 +		g_signal_handlers_disconnect_matched (
 +			priv->activity, G_SIGNAL_MATCH_FUNC, 0, 0,
 +			NULL, activity_proxy_update, NULL);
 +		g_object_unref (priv->activity);
 +		priv->activity = NULL;
 +	}
 +
 +	if (priv->button != NULL) {
 +		g_object_unref (priv->button);
 +		priv->button = NULL;
 +	}
 +
 +	if (priv->image != NULL) {
 +		g_object_unref (priv->image);
 +		priv->image = NULL;
 +	}
 +
 +	if (priv->label != NULL) {
 +		g_object_unref (priv->label);
 +		priv->label = NULL;
 +	}
 +
 +	if (priv->cancel != NULL) {
 +		g_object_unref (priv->cancel);
 +		priv->cancel = NULL;
 +	}
 +
 +	if (priv->spinner != NULL) {
 +		g_object_unref (priv->spinner);
 +		priv->spinner = NULL;
 +	}
 +
 +	/* Chain up to parent's dispose() method. */
 +	G_OBJECT_CLASS (parent_class)->dispose (object);
 +}
 +
 +static void
 +activity_proxy_constructed (GObject *object)
 +{
 +	EActivityProxy *proxy;
 +
 +	proxy = E_ACTIVITY_PROXY (object);
 +
 +	g_signal_connect_swapped (
 +		proxy->priv->button, "clicked",
 +		G_CALLBACK (e_activity_clicked), proxy->priv->activity);
 +
 +	g_signal_connect_swapped (
 +		proxy->priv->cancel, "clicked",
 +		G_CALLBACK (e_activity_cancel), proxy->priv->activity);
 +
 +	g_signal_connect_swapped (
 +		proxy->priv->activity, "cancelled",
 +		G_CALLBACK (activity_proxy_update), proxy);
 +
 +	g_signal_connect_swapped (
 +		proxy->priv->activity, "completed",
 +		G_CALLBACK (activity_proxy_update), proxy);
 +
 +	g_signal_connect_swapped (
 +		proxy->priv->activity, "notify",
 +		G_CALLBACK (activity_proxy_update), proxy);
 +
 +	activity_proxy_update (proxy);
 +}
 +
 +static void
 +activity_proxy_class_init (EActivityProxyClass *class)
 +{
 +	GObjectClass *object_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (EActivityProxyPrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->set_property = activity_proxy_set_property;
 +	object_class->get_property = activity_proxy_get_property;
 +	object_class->dispose = activity_proxy_dispose;
 +	object_class->constructed = activity_proxy_constructed;
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_ACTIVITY,
 +		g_param_spec_object (
 +			"activity",
 +			NULL,
 +			NULL,
 +			E_TYPE_ACTIVITY,
 +			G_PARAM_READWRITE |
 +			G_PARAM_CONSTRUCT_ONLY));
 +}
 +
 +static void
 +activity_proxy_init (EActivityProxy *proxy)
 +{
 +	GtkWidget *container;
 +	GtkWidget *widget;
 +
 +	proxy->priv = E_ACTIVITY_PROXY_GET_PRIVATE (proxy);
 +
 +	container = GTK_WIDGET (proxy);
 +
 +	widget = gtk_frame_new (NULL);
 +	gtk_frame_set_shadow_type (GTK_FRAME (widget), GTK_SHADOW_IN);
 +	gtk_container_add (GTK_CONTAINER (container), widget);
 +	gtk_widget_show (widget);
 +
 +	container = widget;
 +
 +	widget = gtk_hbox_new (FALSE, 3);
 +	gtk_container_add (GTK_CONTAINER (container), widget);
 +	gtk_widget_show (widget);
 +
 +	container = widget;
 +
 +	widget = gtk_image_new ();
 +	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
 +	proxy->priv->image = g_object_ref (widget);
 +	gtk_widget_hide (widget);
 +
 +	widget = gtk_button_new ();
 +	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
 +	proxy->priv->button = g_object_ref (widget);
 +	gtk_widget_hide (widget);
 +
 +        /* XXX What's the rationale for killing the old spinner API? */
 +	widget = e_spinner_new_spinning_small_shown ();
 +	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
 +	proxy->priv->spinner = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	widget = gtk_label_new (NULL);
 +	gtk_label_set_ellipsize (GTK_LABEL (widget), PANGO_ELLIPSIZE_END);
 +	gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
 +	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
 +	proxy->priv->label = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	widget = gtk_button_new ();
 +	gtk_button_set_image (
 +		GTK_BUTTON (widget), gtk_image_new_from_stock (
 +		GTK_STOCK_STOP, GTK_ICON_SIZE_MENU));
 +	gtk_button_set_relief (GTK_BUTTON (widget), GTK_RELIEF_NONE);
 +	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
 +	gtk_widget_set_tooltip_text (widget, _("Cancel"));
 +	proxy->priv->cancel = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +}
 +
 +GType
 +e_activity_proxy_get_type (void)
 +{
 +	static GType type = 0;
 +
 +	if (G_UNLIKELY (type == 0)) {
 +		static const GTypeInfo type_info = {
 +			sizeof (EActivityProxyClass),
 +			(GBaseInitFunc) NULL,
 +			(GBaseFinalizeFunc) NULL,
 +			(GClassInitFunc) activity_proxy_class_init,
 +			(GClassFinalizeFunc) NULL,
 +			NULL,  /* class_data */
 +			sizeof (EActivityProxy),
 +			0,     /* n_preallocs */
 +			(GInstanceInitFunc) activity_proxy_init,
 +			NULL   /* value_table */
 +		};
 +
 +		type = g_type_register_static (
 +			GTK_TYPE_EVENT_BOX, "EActivityProxy", &type_info, 0);
 +	}
 +
 +	return type;
 +}
 +
 +GtkWidget *
 +e_activity_proxy_new (EActivity *activity)
 +{
 +	g_return_val_if_fail (E_IS_ACTIVITY (activity), NULL);
 +
 +	return g_object_new (
 +		E_TYPE_ACTIVITY_PROXY,
 +		"activity", activity, NULL);
 +}
 +
 +EActivity *
 +e_activity_proxy_get_activity (EActivityProxy *proxy)
 +{
 +	g_return_val_if_fail (E_IS_ACTIVITY_PROXY (proxy), NULL);
 +
 +	return proxy->priv->activity;
 +}
diff --cc widgets/misc/e-activity-proxy.h
index af305be,0000000..714dc63
mode 100644,000000..100644
--- a/widgets/misc/e-activity-proxy.h
+++ b/widgets/misc/e-activity-proxy.h
@@@ -1,68 -1,0 +1,68 @@@
 +/*
 + * e-activity-proxy.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_ACTIVITY_PROXY_H
 +#define E_ACTIVITY_PROXY_H
 +
 +#include <gtk/gtk.h>
 +#include <e-activity.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_ACTIVITY_PROXY \
 +	(e_activity_proxy_get_type ())
 +#define E_ACTIVITY_PROXY(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_ACTIVITY_PROXY, EActivityProxy))
 +#define E_ACTIVITY_PROXY_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_ACTIVITY_PROXY, EActivityProxyClass))
 +#define E_IS_ACTIVITY_PROXY(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_ACTIVITY_PROXY))
 +#define E_IS_ACTIVITY_PROXY_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), E_TYPE_ACTIVITY_PROXY))
 +#define E_ACTIVITY_PROXY_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_ACTIVITY_PROXY, EActivityProxyClass))
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _EActivityProxy EActivityProxy;
 +typedef struct _EActivityProxyClass EActivityProxyClass;
 +typedef struct _EActivityProxyPrivate EActivityProxyPrivate;
 +
 +struct _EActivityProxy {
 +	GtkEventBox parent;
 +	EActivityProxyPrivate *priv;
 +};
 +
 +struct _EActivityProxyClass {
 +	GtkEventBoxClass parent_class;
 +};
 +
 +GType		e_activity_proxy_get_type	(void);
 +GtkWidget *	e_activity_proxy_new		(EActivity *activity);
 +EActivity *	e_activity_proxy_get_activity	(EActivityProxy *proxy);
 +
 +G_END_DECLS
 +
 +#endif /* E_ACTIVITY_PROXY_H */
diff --cc widgets/misc/e-activity.c
index 7cd89a7,0000000..ac9a3d7
mode 100644,000000..100644
--- a/widgets/misc/e-activity.c
+++ b/widgets/misc/e-activity.c
@@@ -1,764 -1,0 +1,764 @@@
 +/*
 + * e-activity.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-activity.h"
 +
 +#include <stdarg.h>
 +#include <glib/gi18n.h>
 +
 +#include "e-util/e-util.h"
 +
 +#define E_ACTIVITY_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_ACTIVITY, EActivityPrivate))
 +
 +struct _EActivityPrivate {
 +	gchar *icon_name;
 +	gchar *primary_text;
 +	gchar *secondary_text;
 +	gdouble percent;
 +	guint idle_id;
 +	GError *error;
 +
 +	guint allow_cancel	: 1;
 +	guint blocking		: 1;
 +	guint cancelled		: 1;
 +	guint clickable		: 1;
 +	guint completed		: 1;
 +};
 +
 +enum {
 +	PROP_0,
 +	PROP_ALLOW_CANCEL,
 +	PROP_BLOCKING,
 +	PROP_CLICKABLE,
 +	PROP_ICON_NAME,
 +	PROP_PERCENT,
 +	PROP_PRIMARY_TEXT,
 +	PROP_SECONDARY_TEXT
 +};
 +
 +enum {
 +	CANCELLED,
 +	CLICKED,
 +	COMPLETED,
 +	DESCRIBE,
 +	LAST_SIGNAL
 +};
 +
 +static gpointer parent_class;
 +static gulong signals[LAST_SIGNAL];
 +
 +static gboolean
 +activity_idle_cancel_cb (EActivity *activity)
 +{
 +	activity->priv->idle_id = 0;
 +	e_activity_cancel (activity);
 +	g_object_unref (activity);
 +
 +	return FALSE;
 +}
 +
 +static gboolean
 +activity_idle_complete_cb (EActivity *activity)
 +{
 +	activity->priv->idle_id = 0;
 +	e_activity_complete (activity);
 +	g_object_unref (activity);
 +
 +	return FALSE;
 +}
 +
 +static gboolean
 +activity_describe_accumulator (GSignalInvocationHint *ihint,
 +                               GValue *return_accu,
 +                               const GValue *handler_return,
 +                               gpointer accu_data)
 +{
 +	const gchar *string;
 +
 +	string = g_value_get_string (handler_return);
 +	g_value_set_string (return_accu, string);
 +
 +	return (string == NULL);
 +}
 +
 +static void
 +activity_set_property (GObject *object,
 +                       guint property_id,
 +                       const GValue *value,
 +                       GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_ALLOW_CANCEL:
 +			e_activity_set_allow_cancel (
 +				E_ACTIVITY (object),
 +				g_value_get_boolean (value));
 +			return;
 +
 +		case PROP_BLOCKING:
 +			e_activity_set_blocking (
 +				E_ACTIVITY (object),
 +				g_value_get_boolean (value));
 +			return;
 +
 +		case PROP_CLICKABLE:
 +			e_activity_set_clickable (
 +				E_ACTIVITY (object),
 +				g_value_get_boolean (value));
 +			return;
 +
 +		case PROP_ICON_NAME:
 +			e_activity_set_icon_name (
 +				E_ACTIVITY (object),
 +				g_value_get_string (value));
 +			return;
 +
 +		case PROP_PERCENT:
 +			e_activity_set_percent (
 +				E_ACTIVITY (object),
 +				g_value_get_double (value));
 +			return;
 +
 +		case PROP_PRIMARY_TEXT:
 +			e_activity_set_primary_text (
 +				E_ACTIVITY (object),
 +				g_value_get_string (value));
 +			return;
 +
 +		case PROP_SECONDARY_TEXT:
 +			e_activity_set_secondary_text (
 +				E_ACTIVITY (object),
 +				g_value_get_string (value));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +activity_get_property (GObject *object,
 +                       guint property_id,
 +                       GValue *value,
 +                       GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_ALLOW_CANCEL:
 +			g_value_set_boolean (
 +				value, e_activity_get_allow_cancel (
 +				E_ACTIVITY (object)));
 +			return;
 +
 +		case PROP_BLOCKING:
 +			g_value_set_boolean (
 +				value, e_activity_get_blocking (
 +				E_ACTIVITY (object)));
 +			return;
 +
 +		case PROP_CLICKABLE:
 +			g_value_set_boolean (
 +				value, e_activity_get_clickable (
 +				E_ACTIVITY (object)));
 +			return;
 +
 +		case PROP_ICON_NAME:
 +			g_value_set_string (
 +				value, e_activity_get_icon_name (
 +				E_ACTIVITY (object)));
 +			return;
 +
 +		case PROP_PERCENT:
 +			g_value_set_double (
 +				value, e_activity_get_percent (
 +				E_ACTIVITY (object)));
 +			return;
 +
 +		case PROP_PRIMARY_TEXT:
 +			g_value_set_string (
 +				value, e_activity_get_primary_text (
 +				E_ACTIVITY (object)));
 +			return;
 +
 +		case PROP_SECONDARY_TEXT:
 +			g_value_set_string (
 +				value, e_activity_get_secondary_text (
 +				E_ACTIVITY (object)));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +activity_finalize (GObject *object)
 +{
 +	EActivityPrivate *priv;
 +
 +	priv = E_ACTIVITY_GET_PRIVATE (object);
 +
 +	g_free (priv->icon_name);
 +	g_free (priv->primary_text);
 +	g_free (priv->secondary_text);
 +
 +	if (priv->idle_id > 0)
 +		g_source_remove (priv->idle_id);
 +
 +	if (priv->error != NULL)
 +		g_error_free (priv->error);
 +
 +	/* Chain up to parent's finalize() method. */
 +	G_OBJECT_CLASS (parent_class)->finalize (object);
 +}
 +
 +static void
 +activity_cancelled (EActivity *activity)
 +{
 +	activity->priv->cancelled = TRUE;
 +
 +	if (activity->priv->idle_id > 0) {
 +		g_source_remove (activity->priv->idle_id);
 +		activity->priv->idle_id = 0;
 +	}
 +}
 +
 +static void
 +activity_completed (EActivity *activity)
 +{
 +	activity->priv->completed = TRUE;
 +
 +	if (activity->priv->idle_id > 0) {
 +		g_source_remove (activity->priv->idle_id);
 +		activity->priv->idle_id = 0;
 +	}
 +}
 +
 +static void
 +activity_clicked (EActivity *activity)
 +{
 +	/* Allow subclasses to safely chain up. */
 +}
 +
 +static gchar *
 +activity_describe (EActivity *activity)
 +{
 +	GString *string;
 +	const gchar *text;
 +	gboolean cancelled;
 +	gboolean completed;
 +	gdouble percent;
 +
 +	string = g_string_sized_new (256);
 +	text = e_activity_get_primary_text (activity);
 +	cancelled = e_activity_is_cancelled (activity);
 +	completed = e_activity_is_completed (activity);
 +	percent = e_activity_get_percent (activity);
 +
 +	if (cancelled) {
 +		/* Translators: This is a cancelled activity. */
 +		g_string_printf (string, _("%s (cancelled)"), text);
 +	} else if (completed) {
 +		/* Translators: This is a completed activity. */
 +		g_string_printf (string, _("%s (completed)"), text);
 +	} else if (percent < 0.0) {
 +		/* Translators: This is an activity whose percent
 +		 * complete is unknown. */
 +		g_string_printf (string, _("%s..."), text);
 +	} else {
 +		/* Translators: This is an activity whose percent
 +		 * complete is known. */
 +		g_string_printf (
 +			string, _("%s (%d%% complete)"), text,
 +			(gint) (percent * 100.0 + 0.5));
 +	}
 +
 +	return g_string_free (string, FALSE);
 +}
 +
 +static void
 +activity_class_init (EActivityClass *class)
 +{
 +	GObjectClass *object_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (EActivityPrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->set_property = activity_set_property;
 +	object_class->get_property = activity_get_property;
 +	object_class->finalize = activity_finalize;
 +
 +	class->cancelled = activity_cancelled;
 +	class->completed = activity_completed;
 +	class->clicked = activity_clicked;
 +	class->describe = activity_describe;
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_ALLOW_CANCEL,
 +		g_param_spec_boolean (
 +			"allow-cancel",
 +			NULL,
 +			NULL,
 +			FALSE,
 +			G_PARAM_READWRITE |
 +			G_PARAM_CONSTRUCT));
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_BLOCKING,
 +		g_param_spec_boolean (
 +			"blocking",
 +			NULL,
 +			NULL,
 +			TRUE,
 +			G_PARAM_READWRITE |
 +			G_PARAM_CONSTRUCT));
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_CLICKABLE,
 +		g_param_spec_boolean (
 +			"clickable",
 +			NULL,
 +			NULL,
 +			FALSE,
 +			G_PARAM_READWRITE |
 +			G_PARAM_CONSTRUCT));
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_ICON_NAME,
 +		g_param_spec_string (
 +			"icon-name",
 +			NULL,
 +			NULL,
 +			NULL,
 +			G_PARAM_READWRITE |
 +			G_PARAM_CONSTRUCT));
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_PERCENT,
 +		g_param_spec_double (
 +			"percent",
 +			NULL,
 +			NULL,
 +			-G_MAXDOUBLE,
 +			G_MAXDOUBLE,
 +			-1.0,
 +			G_PARAM_READWRITE |
 +			G_PARAM_CONSTRUCT));
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_PRIMARY_TEXT,
 +		g_param_spec_string (
 +			"primary-text",
 +			NULL,
 +			NULL,
 +			NULL,
 +			G_PARAM_READWRITE |
 +			G_PARAM_CONSTRUCT));
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_SECONDARY_TEXT,
 +		g_param_spec_string (
 +			"secondary-text",
 +			NULL,
 +			NULL,
 +			NULL,
 +			G_PARAM_READWRITE |
 +			G_PARAM_CONSTRUCT));
 +
 +	signals[CANCELLED] = g_signal_new (
 +		"cancelled",
 +		G_OBJECT_CLASS_TYPE (object_class),
 +		G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
 +		G_STRUCT_OFFSET (EActivityClass, cancelled),
 +		NULL, NULL,
 +		g_cclosure_marshal_VOID__VOID,
 +		G_TYPE_NONE, 0);
 +
 +	signals[CLICKED] = g_signal_new (
 +		"clicked",
 +		G_OBJECT_CLASS_TYPE (object_class),
 +		G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
 +		G_STRUCT_OFFSET (EActivityClass, clicked),
 +		NULL, NULL,
 +		g_cclosure_marshal_VOID__VOID,
 +		G_TYPE_NONE, 0);
 +
 +	signals[COMPLETED] = g_signal_new (
 +		"completed",
 +		G_OBJECT_CLASS_TYPE (object_class),
 +		G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
 +		G_STRUCT_OFFSET (EActivityClass, completed),
 +		NULL, NULL,
 +		g_cclosure_marshal_VOID__VOID,
 +		G_TYPE_NONE, 0);
 +
 +	signals[DESCRIBE] = g_signal_new (
 +		"describe",
 +		G_OBJECT_CLASS_TYPE (object_class),
 +		G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
 +		G_STRUCT_OFFSET (EActivityClass, describe),
 +		activity_describe_accumulator, NULL,
 +		e_marshal_STRING__VOID,
 +		G_TYPE_STRING, 0);
 +}
 +
 +static void
 +activity_init (EActivity *activity)
 +{
 +	activity->priv = E_ACTIVITY_GET_PRIVATE (activity);
 +}
 +
 +GType
 +e_activity_get_type (void)
 +{
 +	static GType type = 0;
 +
 +	if (G_UNLIKELY (type == 0)) {
 +		static const GTypeInfo type_info = {
 +			sizeof (EActivityClass),
 +			(GBaseInitFunc) NULL,
 +			(GBaseFinalizeFunc) NULL,
 +			(GClassInitFunc) activity_class_init,
 +			(GClassFinalizeFunc) NULL,
 +			NULL,  /* class_data */
 +			sizeof (EActivity),
 +			0,     /* n_preallocs */
 +			(GInstanceInitFunc) activity_init,
 +			NULL   /* value_table */
 +		};
 +
 +		type = g_type_register_static (
 +			G_TYPE_OBJECT, "EActivity", &type_info, 0);
 +	}
 +
 +	return type;
 +}
 +
 +EActivity *
 +e_activity_new (const gchar *primary_text)
 +{
 +	return g_object_new (
 +		E_TYPE_ACTIVITY,
 +		"primary-text", primary_text, NULL);
 +}
 +
 +EActivity *
 +e_activity_newv (const gchar *format, ...)
 +{
 +	EActivity *activity;
 +	gchar *primary_text;
 +	va_list args;
 +
 +	va_start (args, format);
 +	primary_text = g_strdup_vprintf (format, args);
 +	activity = e_activity_new (primary_text);
 +	g_free (primary_text);
 +	va_end (args);
 +
 +	return activity;
 +}
 +
 +void
 +e_activity_cancel (EActivity *activity)
 +{
 +	g_return_if_fail (E_IS_ACTIVITY (activity));
 +
- 	if (!activity->priv->allow_cancel);
++	if (!activity->priv->allow_cancel)
 +		return;
 +
 +	if (activity->priv->cancelled)
 +		return;
 +
 +	if (activity->priv->completed)
 +		return;
 +
 +	g_signal_emit (activity, signals[CANCELLED], 0);
 +}
 +
 +void
 +e_activity_cancel_in_idle (EActivity *activity)
 +{
 +	guint old_idle_id;
 +
 +	g_return_if_fail (E_IS_ACTIVITY (activity));
 +
 +	/* Be careful not to finalize the activity.  Decrement the
 +	 * reference count only after incrementing it, in case this
 +	 * is the last reference. */
 +
 +	old_idle_id = activity->priv->idle_id;
 +
 +	activity->priv->idle_id = g_idle_add (
 +		(GSourceFunc) activity_idle_cancel_cb,
 +		g_object_ref (activity));
 +
 +	if (old_idle_id > 0) {
 +		g_source_remove (old_idle_id);
 +		g_object_unref (activity);
 +	}
 +}
 +
 +void
 +e_activity_complete (EActivity *activity)
 +{
 +	g_return_if_fail (E_IS_ACTIVITY (activity));
 +
 +	if (activity->priv->cancelled)
 +		return;
 +
 +	if (activity->priv->completed)
 +		return;
 +
 +	g_signal_emit (activity, signals[COMPLETED], 0);
 +}
 +
 +void
 +e_activity_complete_in_idle (EActivity *activity)
 +{
 +	guint old_idle_id;
 +
 +	g_return_if_fail (E_IS_ACTIVITY (activity));
 +
 +	/* Be careful not to finalize the activity.  Decrement the
 +	 * reference count only after incrementing it, in case this
 +	 * is the last reference. */
 +
 +	old_idle_id = activity->priv->idle_id;
 +
 +	activity->priv->idle_id = g_idle_add (
 +		(GSourceFunc) activity_idle_complete_cb,
 +		g_object_ref (activity));
 +
 +	if (old_idle_id > 0) {
 +		g_source_remove (old_idle_id);
 +		g_object_unref (activity);
 +	}
 +}
 +
 +void
 +e_activity_clicked (EActivity *activity)
 +{
 +	g_return_if_fail (E_IS_ACTIVITY (activity));
 +
 +	g_signal_emit (activity, signals[CLICKED], 0);
 +}
 +
 +gchar *
 +e_activity_describe (EActivity *activity)
 +{
 +	EActivityClass *class;
 +
 +	g_return_val_if_fail (E_IS_ACTIVITY (activity), NULL);
 +
 +	class = E_ACTIVITY_GET_CLASS (activity);
 +	g_return_val_if_fail (class->describe != NULL, NULL);
 +
 +	return class->describe (activity);
 +}
 +
 +gboolean
 +e_activity_is_cancelled (EActivity *activity)
 +{
 +	g_return_val_if_fail (E_IS_ACTIVITY (activity), FALSE);
 +
 +	return activity->priv->cancelled;
 +}
 +
 +gboolean
 +e_activity_is_completed (EActivity *activity)
 +{
 +	g_return_val_if_fail (E_IS_ACTIVITY (activity), FALSE);
 +
 +	return activity->priv->completed;
 +}
 +
 +gboolean
 +e_activity_get_allow_cancel (EActivity *activity)
 +{
 +	g_return_val_if_fail (E_IS_ACTIVITY (activity), FALSE);
 +
 +	return activity->priv->allow_cancel;
 +}
 +
 +void
 +e_activity_set_allow_cancel (EActivity *activity,
 +                            gboolean allow_cancel)
 +{
 +	g_return_if_fail (E_IS_ACTIVITY (activity));
 +
 +	activity->priv->allow_cancel = allow_cancel;
 +
 +	g_object_notify (G_OBJECT (activity), "allow-cancel");
 +}
 +
 +gboolean
 +e_activity_get_blocking (EActivity *activity)
 +{
 +	g_return_val_if_fail (E_IS_ACTIVITY (activity), FALSE);
 +
 +	return activity->priv->blocking;
 +}
 +
 +void
 +e_activity_set_blocking (EActivity *activity,
 +                         gboolean blocking)
 +{
 +	g_return_if_fail (E_IS_ACTIVITY (activity));
 +
 +	activity->priv->blocking = blocking;
 +
 +	g_object_notify (G_OBJECT (activity), "blocking");
 +}
 +
 +gboolean
 +e_activity_get_clickable (EActivity *activity)
 +{
 +	g_return_val_if_fail (E_IS_ACTIVITY (activity), FALSE);
 +
 +	return activity->priv->clickable;
 +}
 +
 +void
 +e_activity_set_clickable (EActivity *activity,
 +                          gboolean clickable)
 +{
 +	g_return_if_fail (E_IS_ACTIVITY (activity));
 +
 +	activity->priv->clickable = clickable;
 +
 +	g_object_notify (G_OBJECT (activity), "clickable");
 +}
 +
 +const gchar *
 +e_activity_get_icon_name (EActivity *activity)
 +{
 +	g_return_val_if_fail (E_IS_ACTIVITY (activity), NULL);
 +
 +	return activity->priv->icon_name;
 +}
 +
 +void
 +e_activity_set_icon_name (EActivity *activity,
 +                          const gchar *icon_name)
 +{
 +	g_return_if_fail (E_IS_ACTIVITY (activity));
 +
 +	g_free (activity->priv->icon_name);
 +	activity->priv->icon_name = g_strdup (icon_name);
 +
 +	g_object_notify (G_OBJECT (activity), "icon-name");
 +}
 +
 +gdouble
 +e_activity_get_percent (EActivity *activity)
 +{
 +	g_return_val_if_fail (E_IS_ACTIVITY (activity), -1.0);
 +
 +	return activity->priv->percent;
 +}
 +
 +void
 +e_activity_set_percent (EActivity *activity,
 +                        gdouble percent)
 +{
 +	g_return_if_fail (E_IS_ACTIVITY (activity));
 +
 +	activity->priv->percent = percent;
 +
 +	g_object_notify (G_OBJECT (activity), "percent");
 +}
 +
 +const gchar *
 +e_activity_get_primary_text (EActivity *activity)
 +{
 +	g_return_val_if_fail (E_IS_ACTIVITY (activity), NULL);
 +
 +	return activity->priv->primary_text;
 +}
 +
 +void
 +e_activity_set_primary_text (EActivity *activity,
 +                             const gchar *primary_text)
 +{
 +	g_return_if_fail (E_IS_ACTIVITY (activity));
 +
 +	g_free (activity->priv->primary_text);
 +	activity->priv->primary_text = g_strdup (primary_text);
 +
 +	g_object_notify (G_OBJECT (activity), "primary-text");
 +}
 +
 +const gchar *
 +e_activity_get_secondary_text (EActivity *activity)
 +{
 +	g_return_val_if_fail (E_IS_ACTIVITY (activity), NULL);
 +
 +	return activity->priv->secondary_text;
 +}
 +
 +void
 +e_activity_set_secondary_text (EActivity *activity,
 +                               const gchar *secondary_text)
 +{
 +	g_return_if_fail (E_IS_ACTIVITY (activity));
 +
 +	g_free (activity->priv->secondary_text);
 +	activity->priv->secondary_text = g_strdup (secondary_text);
 +
 +	g_object_notify (G_OBJECT (activity), "secondary-text");
 +}
 +
 +void
 +e_activity_set_error (EActivity *activity,
 +                      const GError *error)
 +{
 +	g_return_if_fail (E_IS_ACTIVITY (activity));
 +
 +	if (activity->priv->error != NULL) {
 +		g_error_free (activity->priv->error);
 +		activity->priv->error = NULL;
 +	}
 +
 +	if (error != NULL)
 +		activity->priv->error = g_error_copy (error);
 +}
 +
 +gboolean
 +e_activity_propagate_error (EActivity *activity,
 +                            GError **destination)
 +{
 +	gboolean propagated;
 +
 +	g_return_val_if_fail (E_IS_ACTIVITY (activity), FALSE);
 +
 +	if ((propagated = (activity->priv->error != NULL))) {
 +		g_propagate_error (destination, activity->priv->error);
 +		activity->priv->error = NULL;
 +	}
 +
 +	return propagated;
 +}
diff --cc widgets/misc/e-activity.h
index 34974dd,0000000..aca2621
mode 100644,000000..100644
--- a/widgets/misc/e-activity.h
+++ b/widgets/misc/e-activity.h
@@@ -1,107 -1,0 +1,107 @@@
 +/*
 + * e-activity.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_ACTIVITY_H
 +#define E_ACTIVITY_H
 +
 +#include <gtk/gtk.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_ACTIVITY \
 +	(e_activity_get_type ())
 +#define E_ACTIVITY(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_ACTIVITY, EActivity))
 +#define E_ACTIVITY_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_ACTIVITY, EActivityClass))
 +#define E_IS_ACTIVITY(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_ACTIVITY))
 +#define E_IS_ACTIVITY_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), E_TYPE_ACTIVITY))
 +#define E_ACTIVITY_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_ACTIVITY, EActivityClass))
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _EActivity EActivity;
 +typedef struct _EActivityClass EActivityClass;
 +typedef struct _EActivityPrivate EActivityPrivate;
 +
 +struct _EActivity {
 +	GObject parent;
 +	EActivityPrivate *priv;
 +};
 +
 +struct _EActivityClass {
 +	GObjectClass parent_class;
 +
 +	/* Signals */
 +	void		(*cancelled)		(EActivity *activity);
 +	void		(*completed)		(EActivity *activity);
 +	void		(*clicked)		(EActivity *activity);
 +	gchar *		(*describe)		(EActivity *activity);
 +};
 +
 +GType		e_activity_get_type		(void);
 +EActivity *	e_activity_new			(const gchar *primary_text);
 +EActivity *	e_activity_newv			(const gchar *format,
 +						 ...) G_GNUC_PRINTF (1, 2);
 +void		e_activity_cancel		(EActivity *activity);
 +void		e_activity_cancel_in_idle	(EActivity *activity);
 +void		e_activity_complete		(EActivity *activity);
 +void		e_activity_complete_in_idle	(EActivity *activity);
 +void		e_activity_clicked		(EActivity *activity);
 +gchar *		e_activity_describe		(EActivity *activity);
 +gboolean	e_activity_is_cancelled		(EActivity *activity);
 +gboolean	e_activity_is_completed		(EActivity *activity);
 +gboolean	e_activity_get_allow_cancel	(EActivity *activity);
 +void		e_activity_set_allow_cancel	(EActivity *activity,
 +						 gboolean allow_cancel);
 +gboolean	e_activity_get_blocking		(EActivity *activity);
 +void		e_activity_set_blocking		(EActivity *activity,
 +						 gboolean blocking);
 +gboolean	e_activity_get_clickable	(EActivity *activity);
 +void		e_activity_set_clickable	(EActivity *activity,
 +						 gboolean clickable);
 +const gchar *	e_activity_get_icon_name	(EActivity *activity);
 +void		e_activity_set_icon_name	(EActivity *activity,
 +						 const gchar *icon_name);
 +gdouble		e_activity_get_percent		(EActivity *activity);
 +void		e_activity_set_percent		(EActivity *activity,
 +						 gdouble percent);
 +const gchar *	e_activity_get_primary_text	(EActivity *activity);
 +void		e_activity_set_primary_text	(EActivity *activity,
 +						 const gchar *primary_text);
 +const gchar *	e_activity_get_secondary_text	(EActivity *activity);
 +void		e_activity_set_secondary_text	(EActivity *activity,
 +						 const gchar *secondary_text);
 +void		e_activity_set_error		(EActivity *activity,
 +						 const GError *error);
 +gboolean	e_activity_propagate_error	(EActivity *activity,
 +						 GError **destination);
 +
 +G_END_DECLS
 +
 +#endif /* E_ACTIVITY_H */
diff --cc widgets/misc/e-alert-activity.c
index d8b9d6f,0000000..860b129
mode 100644,000000..100644
--- a/widgets/misc/e-alert-activity.c
+++ b/widgets/misc/e-alert-activity.c
@@@ -1,254 -1,0 +1,254 @@@
 +/*
 + * e-alert-activity.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-alert-activity.h"
 +
 +#define E_ALERT_ACTIVITY_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_ALERT_ACTIVITY, EAlertActivityPrivate))
 +
 +struct _EAlertActivityPrivate {
 +	GtkWidget *message_dialog;
 +};
 +
 +enum {
 +	PROP_0,
 +	PROP_MESSAGE_DIALOG
 +};
 +
 +static gpointer parent_class;
 +
 +static void
 +alert_activity_set_message_dialog (EAlertActivity *alert_activity,
 +                                   GtkWidget *message_dialog)
 +{
 +	g_return_if_fail (alert_activity->priv->message_dialog == NULL);
 +
 +	alert_activity->priv->message_dialog = g_object_ref (message_dialog);
 +}
 +
 +static void
 +alert_activity_set_property (GObject *object,
 +                             guint property_id,
 +                             const GValue *value,
 +                             GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_MESSAGE_DIALOG:
 +			alert_activity_set_message_dialog (
 +				E_ALERT_ACTIVITY (object),
 +				g_value_get_object (value));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +alert_activity_get_property (GObject *object,
 +                             guint property_id,
 +                             GValue *value,
 +                             GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_MESSAGE_DIALOG:
 +			g_value_set_object (
 +				value, e_alert_activity_get_message_dialog (
 +				E_ALERT_ACTIVITY (object)));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +alert_activity_dispose (GObject *object)
 +{
 +	EAlertActivityPrivate *priv;
 +
 +	priv = E_ALERT_ACTIVITY_GET_PRIVATE (object);
 +
 +	if (priv->message_dialog != NULL) {
 +		g_object_unref (priv->message_dialog);
 +		priv->message_dialog = NULL;
 +	}
 +
 +	/* Chain up to parent's dispose() method. */
 +	G_OBJECT_CLASS (parent_class)->dispose (object);
 +}
 +
 +static void
 +alert_activity_constructed (GObject *object)
 +{
 +	EActivity *activity;
 +	EAlertActivity *alert_activity;
 +	GtkWidget *message_dialog;
 +	const gchar *primary_text;
 +	const gchar *secondary_text;
 +
 +	alert_activity = E_ALERT_ACTIVITY (object);
 +	message_dialog = e_alert_activity_get_message_dialog (alert_activity);
 +
 +	object = G_OBJECT (message_dialog);
 +	primary_text = g_object_get_data (object, "primary");
 +	secondary_text = g_object_get_data (object, "secondary");
 +
 +	activity = E_ACTIVITY (alert_activity);
 +	e_activity_set_primary_text (activity, primary_text);
 +	e_activity_set_secondary_text (activity, secondary_text);
 +}
 +
 +static void
 +alert_activity_clicked (EActivity *activity)
 +{
 +	EAlertActivity *alert_activity;
 +	GtkWidget *message_dialog;
 +
 +	e_activity_complete (activity);
 +
 +	alert_activity = E_ALERT_ACTIVITY (activity);
 +	message_dialog = e_alert_activity_get_message_dialog (alert_activity);
 +	gtk_dialog_run (GTK_DIALOG (message_dialog));
 +	gtk_widget_hide (message_dialog);
 +
 +	/* Chain up to parent's clicked() method. */
 +	E_ACTIVITY_CLASS (parent_class)->clicked (activity);
 +}
 +
 +static void
 +alert_activity_timeout (ETimeoutActivity *activity)
 +{
 +	e_activity_complete (E_ACTIVITY (activity));
 +
 +	/* Chain up to parent's timeout() method. */
 +	E_TIMEOUT_ACTIVITY_CLASS (parent_class)->timeout (activity);
 +}
 +
 +static void
 +alert_activity_class_init (EAlertActivityClass *class)
 +{
 +	GObjectClass *object_class;
 +	EActivityClass *activity_class;
 +	ETimeoutActivityClass *timeout_activity_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (EAlertActivityPrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->set_property = alert_activity_set_property;
 +	object_class->get_property = alert_activity_get_property;
 +	object_class->dispose = alert_activity_dispose;
 +	object_class->constructed = alert_activity_constructed;
 +
 +	activity_class = E_ACTIVITY_CLASS (class);
 +	activity_class->clicked = alert_activity_clicked;
 +
 +	timeout_activity_class = E_TIMEOUT_ACTIVITY_CLASS (class);
 +	timeout_activity_class->timeout = alert_activity_timeout;
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_MESSAGE_DIALOG,
 +		g_param_spec_object (
 +			"message-dialog",
 +			NULL,
 +			NULL,
 +			GTK_TYPE_DIALOG,
 +			G_PARAM_READWRITE |
 +			G_PARAM_CONSTRUCT_ONLY));
 +}
 +
 +static void
 +alert_activity_init (EAlertActivity *alert_activity)
 +{
 +	alert_activity->priv = E_ALERT_ACTIVITY_GET_PRIVATE (alert_activity);
 +
 +	e_activity_set_clickable (E_ACTIVITY (alert_activity), TRUE);
 +	e_timeout_activity_set_timeout (E_TIMEOUT_ACTIVITY (alert_activity), 60);
 +}
 +
 +GType
 +e_alert_activity_get_type (void)
 +{
 +	static GType type = 0;
 +
 +	if (G_UNLIKELY (type == 0)) {
 +		static const GTypeInfo type_info = {
 +			sizeof (EAlertActivityClass),
 +			(GBaseInitFunc) NULL,
 +			(GBaseFinalizeFunc) NULL,
 +			(GClassInitFunc) alert_activity_class_init,
 +			(GClassFinalizeFunc) NULL,
 +			NULL,  /* class_data */
 +			sizeof (EAlertActivity),
 +			0,     /* n_preallocs */
 +			(GInstanceInitFunc) alert_activity_init,
 +			NULL   /* value_table */
 +		};
 +
 +		type = g_type_register_static (
 +			E_TYPE_TIMEOUT_ACTIVITY, "EAlertActivity",
 +			&type_info, 0);
 +	}
 +
 +	return type;
 +}
 +
 +EActivity *
 +e_alert_activity_new_info (GtkWidget *message_dialog)
 +{
 +	g_return_val_if_fail (GTK_IS_DIALOG (message_dialog), NULL);
 +
 +	return g_object_new (
 +		E_TYPE_ALERT_ACTIVITY,
 +		"icon-name", "dialog-information",
 +		"message-dialog", message_dialog, NULL);
 +}
 +
 +EActivity *
 +e_alert_activity_new_error (GtkWidget *message_dialog)
 +{
 +	g_return_val_if_fail (GTK_IS_DIALOG (message_dialog), NULL);
 +
 +	return g_object_new (
 +		E_TYPE_ALERT_ACTIVITY,
 +		"icon-name", "dialog-error",
 +		"message-dialog", message_dialog, NULL);
 +}
 +
 +EActivity *
 +e_alert_activity_new_warning (GtkWidget *message_dialog)
 +{
 +	g_return_val_if_fail (GTK_IS_DIALOG (message_dialog), NULL);
 +
 +	return g_object_new (
 +		E_TYPE_ALERT_ACTIVITY,
 +		"icon-name", "dialog-warning",
 +		"message-dialog", message_dialog, NULL);
 +}
 +
 +GtkWidget *
 +e_alert_activity_get_message_dialog (EAlertActivity *alert_activity)
 +{
 +	g_return_val_if_fail (E_IS_ALERT_ACTIVITY (alert_activity), NULL);
 +
 +	return alert_activity->priv->message_dialog;
 +}
diff --cc widgets/misc/e-alert-activity.h
index 4c5547d,0000000..5557094
mode 100644,000000..100644
--- a/widgets/misc/e-alert-activity.h
+++ b/widgets/misc/e-alert-activity.h
@@@ -1,70 -1,0 +1,70 @@@
 +/*
 + * e-alert-activity.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_ALERT_ACTIVITY_H
 +#define E_ALERT_ACTIVITY_H
 +
 +#include <e-timeout-activity.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_ALERT_ACTIVITY \
 +	(e_alert_activity_get_type ())
 +#define E_ALERT_ACTIVITY(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_ALERT_ACTIVITY, EAlertActivity))
 +#define E_ALERT_ACTIVITY_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_ALERT_ACTIVITY, EAlertActivityClass))
 +#define E_IS_ALERT_ACTIVITY(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_ALERT_ACTIVITY))
 +#define E_IS_ALERT_ACTIVITY_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), E_TYPE_ALERT_ACTIVITY))
 +#define E_ALERT_ACTIVITY_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_ALERT_ACTIVITY, EAlertActivityClass))
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _EAlertActivity EAlertActivity;
 +typedef struct _EAlertActivityClass EAlertActivityClass;
 +typedef struct _EAlertActivityPrivate EAlertActivityPrivate;
 +
 +struct _EAlertActivity {
 +	ETimeoutActivity parent;
 +	EAlertActivityPrivate *priv;
 +};
 +
 +struct _EAlertActivityClass {
 +	ETimeoutActivityClass parent_class;
 +};
 +
 +GType		e_alert_activity_get_type	(void);
 +EActivity *	e_alert_activity_new_info	(GtkWidget *message_dialog);
 +EActivity *	e_alert_activity_new_error	(GtkWidget *message_dialog);
 +EActivity *	e_alert_activity_new_warning	(GtkWidget *message_dialog);
 +GtkWidget *	e_alert_activity_get_message_dialog
 +						(EAlertActivity *alert_activity);
 +
 +G_END_DECLS
 +
 +#endif /* E_ALERT_ACTIVITY_H */
diff --cc widgets/misc/e-file-activity.c
index 1957c20,0000000..e35ab49
mode 100644,000000..100644
--- a/widgets/misc/e-file-activity.c
+++ b/widgets/misc/e-file-activity.c
@@@ -1,365 -1,0 +1,365 @@@
 +/*
 + * e-file-activity.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-file-activity.h"
 +
 +#include <stdarg.h>
 +
 +#define E_FILE_ACTIVITY_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_FILE_ACTIVITY, EFileActivityPrivate))
 +
 +struct _EFileActivityPrivate {
 +	GCancellable *cancellable;
 +	GAsyncResult *result;
 +	GFile *file;
 +
 +	gulong handler_id;
 +};
 +
 +enum {
 +	PROP_0,
 +	PROP_CANCELLABLE,
 +	PROP_FILE,
 +	PROP_RESULT
 +};
 +
 +static gpointer parent_class;
 +
 +static void
 +file_activity_set_property (GObject *object,
 +                            guint property_id,
 +                            const GValue *value,
 +                            GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_CANCELLABLE:
 +			e_file_activity_set_cancellable (
 +				E_FILE_ACTIVITY (object),
 +				g_value_get_object (value));
 +			return;
 +
 +		case PROP_FILE:
 +			e_file_activity_set_file (
 +				E_FILE_ACTIVITY (object),
 +				g_value_get_object (value));
 +			return;
 +
 +		case PROP_RESULT:
 +			e_file_activity_set_result (
 +				E_FILE_ACTIVITY (object),
 +				g_value_get_object (value));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +file_activity_get_property (GObject *object,
 +                            guint property_id,
 +                            GValue *value,
 +                            GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_CANCELLABLE:
 +			g_value_set_object (
 +				value, e_file_activity_get_cancellable (
 +				E_FILE_ACTIVITY (object)));
 +			return;
 +
 +		case PROP_FILE:
 +			g_value_set_object (
 +				value, e_file_activity_get_file (
 +				E_FILE_ACTIVITY (object)));
 +			return;
 +
 +		case PROP_RESULT:
 +			g_value_set_object (
 +				value, e_file_activity_get_result (
 +				E_FILE_ACTIVITY (object)));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +file_activity_dispose (GObject *object)
 +{
 +	EFileActivityPrivate *priv;
 +
 +	priv = E_FILE_ACTIVITY_GET_PRIVATE (object);
 +
 +	if (priv->cancellable != NULL) {
 +		g_signal_handler_disconnect (
 +			priv->cancellable, priv->handler_id);
 +		g_object_unref (priv->cancellable);
 +		priv->cancellable = NULL;
 +	}
 +
 +	if (priv->result != NULL) {
 +		g_object_unref (priv->result);
 +		priv->result = NULL;
 +	}
 +
 +	if (priv->file != NULL) {
 +		g_object_unref (priv->file);
 +		priv->file = NULL;
 +	}
 +
 +	/* Chain up to parent's dispose() method. */
 +	G_OBJECT_CLASS (parent_class)->dispose (object);
 +}
 +
 +static void
 +file_activity_cancelled (EActivity *activity)
 +{
 +	EFileActivity *file_activity;
 +	GCancellable *cancellable;
 +
 +	file_activity = E_FILE_ACTIVITY (activity);
 +	cancellable = e_file_activity_get_cancellable (file_activity);
 +	g_cancellable_cancel (cancellable);
 +
 +	/* Chain up to parent's cancelled() method. */
 +	E_ACTIVITY_CLASS (parent_class)->cancelled (activity);
 +}
 +
 +static void
 +file_activity_class_init (EFileActivityClass *class)
 +{
 +	GObjectClass *object_class;
 +	EActivityClass *activity_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (EFileActivityPrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->set_property = file_activity_set_property;
 +	object_class->get_property = file_activity_get_property;
 +	object_class->dispose = file_activity_dispose;
 +
 +	activity_class = E_ACTIVITY_CLASS (class);
 +	activity_class->cancelled = file_activity_cancelled;
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_CANCELLABLE,
 +		g_param_spec_object (
 +			"cancellable",
 +			"Cancellable",
 +			NULL,
 +			G_TYPE_CANCELLABLE,
 +			G_PARAM_READWRITE));
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_FILE,
 +		g_param_spec_object (
 +			"file",
 +			"File",
 +			NULL,
 +			G_TYPE_FILE,
 +			G_PARAM_READWRITE));
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_RESULT,
 +		g_param_spec_object (
 +			"result",
 +			"Result",
 +			NULL,
 +			G_TYPE_ASYNC_RESULT,
 +			G_PARAM_READWRITE));
 +}
 +
 +static void
 +file_activity_init (EFileActivity *file_activity)
 +{
 +	GCancellable *cancellable;
 +
 +	file_activity->priv = E_FILE_ACTIVITY_GET_PRIVATE (file_activity);
 +
 +	e_activity_set_allow_cancel (E_ACTIVITY (file_activity), TRUE);
 +
 +	cancellable = g_cancellable_new ();
 +	e_file_activity_set_cancellable (file_activity, cancellable);
 +	g_object_unref (cancellable);
 +}
 +
 +GType
 +e_file_activity_get_type (void)
 +{
 +	static GType type = 0;
 +
 +	if (G_UNLIKELY (type == 0)) {
 +		static const GTypeInfo type_info = {
 +			sizeof (EFileActivityClass),
 +			(GBaseInitFunc) NULL,
 +			(GBaseFinalizeFunc) NULL,
 +			(GClassInitFunc) file_activity_class_init,
 +			(GClassFinalizeFunc) NULL,
 +			NULL,  /* class_data */
 +			sizeof (EFileActivity),
 +			0,     /* n_preallocs */
 +			(GInstanceInitFunc) file_activity_init,
 +			NULL   /* value_table */
 +		};
 +
 +		type = g_type_register_static (
 +			E_TYPE_ACTIVITY, "EFileActivity", &type_info, 0);
 +	}
 +
 +	return type;
 +}
 +
 +EActivity *
 +e_file_activity_new (const gchar *primary_text)
 +{
 +	return g_object_new (
 +		E_TYPE_FILE_ACTIVITY,
 +		"primary-text", primary_text, NULL);
 +}
 +
 +EActivity *
 +e_file_activity_newv (const gchar *format, ...)
 +{
 +	EActivity *activity;
 +	gchar *primary_text;
 +	va_list args;
 +
 +	va_start (args, format);
 +	primary_text = g_strdup_vprintf (format, args);
 +	activity = e_file_activity_new (primary_text);
 +	g_free (primary_text);
 +	va_end (args);
 +
 +	return activity;
 +}
 +
 +GCancellable *
 +e_file_activity_get_cancellable (EFileActivity *file_activity)
 +{
 +	g_return_val_if_fail (E_IS_FILE_ACTIVITY (file_activity), NULL);
 +
 +	return file_activity->priv->cancellable;
 +}
 +
 +void
 +e_file_activity_set_cancellable (EFileActivity *file_activity,
 +                                 GCancellable *cancellable)
 +{
 +	g_return_if_fail (E_IS_FILE_ACTIVITY (file_activity));
 +
 +	if (cancellable != NULL) {
 +		g_return_if_fail (G_IS_CANCELLABLE (cancellable));
 +		g_object_ref (cancellable);
 +	}
 +
 +	if (file_activity->priv->cancellable != NULL) {
 +		g_signal_handler_disconnect (
 +			file_activity->priv->cancellable,
 +			file_activity->priv->handler_id);
 +		g_object_unref (file_activity->priv->cancellable);
 +		file_activity->priv->handler_id = 0;
 +	}
 +
 +	file_activity->priv->cancellable = cancellable;
 +
 +	if (cancellable != NULL)
 +		file_activity->priv->handler_id =
 +			g_signal_connect_swapped (
 +				cancellable, "cancelled",
 +				G_CALLBACK (e_activity_cancel),
 +				file_activity);
 +
 +	g_object_notify (G_OBJECT (file_activity), "cancellable");
 +}
 +
 +GFile *
 +e_file_activity_get_file (EFileActivity *file_activity)
 +{
 +	g_return_val_if_fail (E_IS_FILE_ACTIVITY (file_activity), NULL);
 +
 +	return file_activity->priv->file;
 +}
 +
 +void
 +e_file_activity_set_file (EFileActivity *file_activity,
 +                          GFile *file)
 +{
 +	g_return_if_fail (E_IS_FILE_ACTIVITY (file_activity));
 +
 +	if (file != NULL) {
 +		g_return_if_fail (G_IS_FILE (file));
 +		g_object_ref (file);
 +	}
 +
 +	if (file_activity->priv->file != NULL)
 +		g_object_unref (file_activity->priv->file);
 +
 +	file_activity->priv->file = file;
 +
 +	g_object_notify (G_OBJECT (file_activity), "file");
 +}
 +
 +GAsyncResult *
 +e_file_activity_get_result (EFileActivity *file_activity)
 +{
 +	g_return_val_if_fail (E_IS_FILE_ACTIVITY (file_activity), NULL);
 +
 +	return file_activity->priv->result;
 +}
 +
 +void
 +e_file_activity_set_result (EFileActivity *file_activity,
 +                            GAsyncResult *result)
 +{
 +	g_return_if_fail (E_IS_FILE_ACTIVITY (file_activity));
 +
 +	if (result != NULL) {
 +		g_return_if_fail (G_IS_ASYNC_RESULT (result));
 +		g_object_ref (result);
 +	}
 +
 +	if (file_activity->priv->result != NULL)
 +		g_object_unref (file_activity->priv->result);
 +
 +	file_activity->priv->result = result;
 +
 +	g_object_notify (G_OBJECT (file_activity), "result");
 +}
 +
 +void
 +e_file_activity_progress (goffset current_num_bytes,
 +                          goffset total_num_bytes,
 +                          gpointer activity)
 +{
 +	gdouble percent = -1.0;
 +
 +	g_return_if_fail (E_IS_ACTIVITY (activity));
 +
 +	if (current_num_bytes > 0 && total_num_bytes > 0)
 +		percent = (gdouble) current_num_bytes / total_num_bytes;
 +
 +	e_activity_set_percent (activity, percent);
 +}
diff --cc widgets/misc/e-file-activity.h
index acd144d,0000000..b4a5433
mode 100644,000000..100644
--- a/widgets/misc/e-file-activity.h
+++ b/widgets/misc/e-file-activity.h
@@@ -1,83 -1,0 +1,83 @@@
 +/*
 + * e-file-activity.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_FILE_ACTIVITY_H
 +#define E_FILE_ACTIVITY_H
 +
 +#include <gio/gio.h>
 +#include <widgets/misc/e-activity.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_FILE_ACTIVITY \
 +	(e_file_activity_get_type ())
 +#define E_FILE_ACTIVITY(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_FILE_ACTIVITY, EFileActivity))
 +#define E_FILE_ACTIVITY_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_FILE_ACTIVITY, EFileActivityClass))
 +#define E_IS_FILE_ACTIVITY(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_FILE_ACTIVITY))
 +#define E_IS_FILE_ACTIVITY_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), E_TYPE_FILE_ACTIVITY))
 +#define E_FILE_ACTIVITY_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_FILE_ACTIVITY, EFileActivityClass))
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _EFileActivity EFileActivity;
 +typedef struct _EFileActivityClass EFileActivityClass;
 +typedef struct _EFileActivityPrivate EFileActivityPrivate;
 +
 +struct _EFileActivity {
 +	EActivity parent;
 +	EFileActivityPrivate *priv;
 +};
 +
 +struct _EFileActivityClass {
 +	EActivityClass parent_class;
 +};
 +
 +GType		e_file_activity_get_type	(void);
 +EActivity *	e_file_activity_new		(const gchar *primary_text);
 +EActivity *	e_file_activity_newv		(const gchar *format,
 +						 ...) G_GNUC_PRINTF (1, 2);
 +GCancellable *	e_file_activity_get_cancellable	(EFileActivity *file_activity);
 +void		e_file_activity_set_cancellable (EFileActivity *file_activity,
 +						 GCancellable *cancellable);
 +GFile *		e_file_activity_get_file	(EFileActivity *file_activity);
 +void		e_file_activity_set_file	(EFileActivity *file_activity,
 +						 GFile *file);
 +GAsyncResult *	e_file_activity_get_result	(EFileActivity *file_activity);
 +void		e_file_activity_set_result	(EFileActivity *file_activity,
 +						 GAsyncResult *result);
 +
 +/* This can be used as a GFileProgressCallback. */
 +void		e_file_activity_progress	(goffset current_num_bytes,
 +						 goffset total_num_bytes,
 +						 gpointer activity);
 +
 +G_END_DECLS
 +
 +#endif /* E_FILE_ACTIVITY_H */
diff --cc widgets/misc/e-filter-bar.c
index 9f38ecc,9a67636..a113d1f
--- a/widgets/misc/e-filter-bar.c
+++ b/widgets/misc/e-filter-bar.c
@@@ -828,45 -937,34 +828,40 @@@ class_init (EFilterBarClass *class
  }
  
  static void
 -init (EFilterBar *efb)
 +filter_bar_init (EFilterBar *filter_bar)
  {
 -	g_signal_connect (efb, "menu_activated", G_CALLBACK (menubar_activated), NULL);
 -	g_signal_connect (efb, "query_changed", G_CALLBACK (option_changed), NULL);
 -	g_signal_connect (efb, "search_activated", G_CALLBACK (option_changed), NULL);
 +	g_signal_connect (filter_bar, "menu_activated", G_CALLBACK (menubar_activated), NULL);
 +	g_signal_connect (filter_bar, "query_changed", G_CALLBACK (option_changed), NULL);
 +	g_signal_connect (filter_bar, "search_activated", G_CALLBACK (option_changed), NULL);
  
 -	efb->menu_rules = g_ptr_array_new ();
 -	efb->option_rules = g_ptr_array_new ();
 +	filter_bar->menu_rules = g_ptr_array_new ();
 +	filter_bar->option_rules = g_ptr_array_new ();
  }
  
 -
 -/* Object construction.  */
 -
 -EFilterBar *
 -e_filter_bar_new (RuleContext *context,
 -		  const char *systemrules,
 -		  const char *userrules,
 -		  EFilterBarConfigRule config,
 -		  void *data)
 +GType
 +e_filter_bar_get_type (void)
  {
 -	EFilterBar *bar;
 +	static GType type = 0;
  
- <<<<<<< HEAD:widgets/misc/e-filter-bar.c
 -	bar = g_object_new (e_filter_bar_get_type (), NULL);
 -	((ESearchBar *)bar)->lite = FALSE;
 +	if (G_UNLIKELY (type == 0)) {
 +		static const GTypeInfo type_info = {
 +			sizeof (EFilterBarClass),
 +			(GBaseInitFunc) NULL,
 +			(GBaseFinalizeFunc) NULL,
 +			(GClassInitFunc) filter_bar_class_init,
 +			(GClassFinalizeFunc) NULL,
 +			NULL,  /* class_data */
 +			sizeof (EFilterBar),
 +			0,     /* n_preallocs */
 +			(GInstanceInitFunc) filter_bar_init,
 +			NULL   /* value_table */
 +		};
- =======
- 	bar = g_object_new (e_filter_bar_get_type (), NULL);
- 	((ESearchBar *)bar)->lite = FALSE;
- >>>>>>> ff25805... Filter/Search bar changes for Anjal.:widgets/misc/e-filter-bar.c
  
 - 	e_filter_bar_new_construct (context, systemrules, userrules, config, data, bar);
 +		type = g_type_register_static (
 +			E_TYPE_SEARCH_BAR, "EFilterBar", &type_info, 0);
 +	}
  
 -	return bar;
 +	return type;
  }
  
  EFilterBar *
diff --cc widgets/misc/e-icon-entry.h
index 65aff61,894cb16..e18b0fd
--- a/widgets/misc/e-icon-entry.h
+++ b/widgets/misc/e-icon-entry.h
@@@ -41,32 -41,30 +41,32 @@@
  
  G_BEGIN_DECLS
  
 -#define E_TYPE_ICON_ENTRY		(e_icon_entry_get_type())
 -#define E_ICON_ENTRY(object)		(G_TYPE_CHECK_INSTANCE_CAST((object), E_TYPE_ICON_ENTRY, EIconEntry))
 -#define E_ICON_ENTRY_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST((klass), E_TYPE_ICON_ENTRY, EIconEntryClass))
 -#define E_IS_ICON_ENTRY(object)	(G_TYPE_CHECK_INSTANCE_TYPE((object), E_TYPE_ICON_ENTRY))
 -#define E_IS_ICON_ENTRY_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE((klass), E_TYPE_ICON_ENTRY))
 -#define E_ICON_ENTRY_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS((obj), E_TYPE_ICON_ENTRY, EIconEntryClass))
 -
 +/* Standard GObject macros */
 +#define E_TYPE_ICON_ENTRY \
 +	(e_icon_entry_get_type())
 +#define E_ICON_ENTRY(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_ICON_ENTRY, EIconEntry))
 +#define E_ICON_ENTRY_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_ICON_ENTRY, EIconEntryClass))
 +#define E_IS_ICON_ENTRY(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_ICON_ENTRY))
 +#define E_IS_ICON_ENTRY_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), E_TYPE_ICON_ENTRY))
 +#define E_ICON_ENTRY_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_ICON_ENTRY, EIconEntryClass))
 +
 +typedef struct _EIconEntry EIconEntry;
  typedef struct _EIconEntryClass	EIconEntryClass;
 -typedef struct _EIconEntry		EIconEntry;
 -typedef struct _EIconEntryPrivate	EIconEntryPrivate;
 -
 -struct _EIconEntryClass
 -{
 -	GtkBinClass parent_class;
 -};
 +typedef struct _EIconEntryPrivate EIconEntryPrivate;
-  
+ 
  struct _EIconEntry
  {
 -	GtkBin parent_object;
 -
 -	/*< public >*/
 -	GtkWidget *entry;
 -
 -	/*< private >*/
 +	GtkBin parent;
  	EIconEntryPrivate *priv;
  };
  
diff --cc widgets/misc/e-menu-tool-button.c
index 5e87de8,0000000..53778e6
mode 100644,000000..100644
--- a/widgets/misc/e-menu-tool-button.c
+++ b/widgets/misc/e-menu-tool-button.c
@@@ -1,157 -1,0 +1,157 @@@
 +/*
 + * e-menu-tool-button.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-menu-tool-button.h"
 +
 +static gpointer parent_class;
 +
 +static GtkWidget *
 +menu_tool_button_clone_image (GtkWidget *source)
 +{
 +	GtkIconSize size;
 +	GtkImageType image_type;
 +	const gchar *icon_name;
 +
 +	/* XXX This isn't general purpose because it requires that the
 +	 *     source image be using a named icon.  Somewhat surprised
 +	 *     GTK+ doesn't offer something like this. */
 +	image_type = gtk_image_get_storage_type (GTK_IMAGE (source));
 +	g_return_val_if_fail (image_type == GTK_IMAGE_ICON_NAME, NULL);
 +	gtk_image_get_icon_name (GTK_IMAGE (source), &icon_name, &size);
 +
 +	return gtk_image_new_from_icon_name (icon_name, size);
 +}
 +
 +static GtkMenuItem *
 +menu_tool_button_get_first_menu_item (GtkMenuToolButton *menu_tool_button)
 +{
 +	GtkWidget *menu;
 +	GList *children;
 +
 +	menu = gtk_menu_tool_button_get_menu (menu_tool_button);
 +	if (!GTK_IS_MENU (menu))
 +		return NULL;
 +
 +	/* XXX GTK+ 2.12 provides no accessor function. */
 +	children = GTK_MENU_SHELL (menu)->children;
 +	if (children == NULL)
 +		return NULL;
 +
 +	return GTK_MENU_ITEM (children->data);
 +}
 +
 +static void
 +menu_tool_button_update_button (GtkToolButton *tool_button)
 +{
 +	GtkMenuItem *menu_item;
 +	GtkMenuToolButton *menu_tool_button;
 +	GtkImageMenuItem *image_menu_item;
 +	GtkAction *action;
 +	GtkWidget *image;
 +	gchar *tooltip = NULL;
 +
 +	menu_tool_button = GTK_MENU_TOOL_BUTTON (tool_button);
 +	menu_item = menu_tool_button_get_first_menu_item (menu_tool_button);
 +	if (!GTK_IS_IMAGE_MENU_ITEM (menu_item))
 +		return;
 +
 +	image_menu_item = GTK_IMAGE_MENU_ITEM (menu_item);
 +	image = gtk_image_menu_item_get_image (image_menu_item);
 +	if (!GTK_IS_IMAGE (image))
 +		return;
 +
 +	image = menu_tool_button_clone_image (image);
 +	gtk_tool_button_set_icon_widget (tool_button, image);
 +	gtk_widget_show (image);
 +
 +	/* If the menu item is a proxy for a GtkAction, extract
 +	 * the action's tooltip and use it as our own tooltip. */
 +	action = gtk_widget_get_action (GTK_WIDGET (menu_item));
 +	if (action != NULL)
 +		g_object_get (action, "tooltip", &tooltip, NULL);
 +	gtk_widget_set_tooltip_text (GTK_WIDGET (tool_button), tooltip);
 +	g_free (tooltip);
 +}
 +
 +static void
 +menu_tool_button_clicked (GtkToolButton *tool_button)
 +{
 +	GtkMenuItem *menu_item;
 +	GtkMenuToolButton *menu_tool_button;
 +
 +	menu_tool_button = GTK_MENU_TOOL_BUTTON (tool_button);
 +	menu_item = menu_tool_button_get_first_menu_item (menu_tool_button);
 +
 +	if (GTK_IS_MENU_ITEM (menu_item))
 +		gtk_menu_item_activate (menu_item);
 +}
 +
 +static void
 +menu_tool_button_class_init (EMenuToolButtonClass *class)
 +{
 +	GtkToolButtonClass *tool_button_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +
 +	tool_button_class = GTK_TOOL_BUTTON_CLASS (class);
 +	tool_button_class->clicked = menu_tool_button_clicked;
 +}
 +
 +static void
 +menu_tool_button_init (EMenuToolButton *button)
 +{
 +	g_signal_connect (
 +		button, "notify::menu",
 +		G_CALLBACK (menu_tool_button_update_button), NULL);
 +}
 +
 +GType
 +e_menu_tool_button_get_type (void)
 +{
 +	static GType type = 0;
 +
 +	if (G_UNLIKELY (type == 0)) {
 +		const GTypeInfo type_info = {
 +			sizeof (EMenuToolButtonClass),
 +			(GBaseInitFunc) NULL,
 +			(GBaseFinalizeFunc) NULL,
 +			(GClassInitFunc) menu_tool_button_class_init,
 +			(GClassFinalizeFunc) NULL,
 +			NULL,  /* class_data */
 +			sizeof (EMenuToolButton),
 +			0,     /* n_preallocs */
 +			(GInstanceInitFunc) menu_tool_button_init,
 +			NULL   /* value_table */
 +		};
 +
 +		type = g_type_register_static (
 +			GTK_TYPE_MENU_TOOL_BUTTON, "EMenuToolButton",
 +			&type_info, 0);
 +	}
 +
 +	return type;
 +}
 +
 +GtkToolItem *
 +e_menu_tool_button_new (const gchar *label)
 +{
 +	return g_object_new (E_TYPE_MENU_TOOL_BUTTON, "label", label, NULL);
 +}
diff --cc widgets/misc/e-menu-tool-button.h
index b10cf3a,0000000..214f5ab
mode 100644,000000..100644
--- a/widgets/misc/e-menu-tool-button.h
+++ b/widgets/misc/e-menu-tool-button.h
@@@ -1,68 -1,0 +1,68 @@@
 +/*
 + * e-menu-tool-button.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +/* EMenuToolButton is a variation of GtkMenuToolButton where the
 + * button icon always reflects the first menu item, and clicking
 + * the button activates the first menu item. */
 +
 +#ifndef E_MENU_TOOL_BUTTON_H
 +#define E_MENU_TOOL_BUTTON_H
 +
 +#include <gtk/gtk.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_MENU_TOOL_BUTTON \
 +	(e_menu_tool_button_get_type ())
 +#define E_MENU_TOOL_BUTTON(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_MENU_TOOL_BUTTON, EMenuToolButton))
 +#define E_MENU_TOOL_BUTTON_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_MENU_TOOL_BUTTON, EMenuToolButtonClass))
 +#define E_IS_MENU_TOOL_BUTTON(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_MENU_TOOL_BUTTON))
 +#define E_IS_MENU_TOOL_BUTTON_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), E_TYPE_MENU_TOOL_BUTTON))
 +#define E_MENU_TOOL_BUTTON_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_MENU_TOOL_BUTTON, EMenuToolButtonClass))
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _EMenuToolButton EMenuToolButton;
 +typedef struct _EMenuToolButtonClass EMenuToolButtonClass;
 +
 +struct _EMenuToolButton {
 +	GtkMenuToolButton parent;
 +};
 +
 +struct _EMenuToolButtonClass {
 +	GtkMenuToolButtonClass parent_class;
 +};
 +
 +GType		e_menu_tool_button_get_type	(void);
 +GtkToolItem *	e_menu_tool_button_new		(const gchar *label);
 +
 +G_END_DECLS
 +
 +#endif /* E_MENU_TOOL_BUTTON_H */
diff --cc widgets/misc/e-popup-action.c
index 51abc01,0000000..e856a1f
mode 100644,000000..100644
--- a/widgets/misc/e-popup-action.c
+++ b/widgets/misc/e-popup-action.c
@@@ -1,285 -1,0 +1,285 @@@
 +/*
 + * e-popup-action.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-popup-action.h"
 +
 +#include <glib/gi18n.h>
 +#include "e-util/e-binding.h"
 +
 +#define E_POPUP_ACTION_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_POPUP_ACTION, EPopupActionPrivate))
 +
 +enum {
 +	PROP_0,
 +	PROP_SOURCE
 +};
 +
 +struct _EPopupActionPrivate {
 +	GtkAction *source;
 +};
 +
 +static gpointer parent_class;
 +
 +static void
 +popup_action_set_source (EPopupAction *popup_action,
 +                         GtkAction *source)
 +{
 +	g_return_if_fail (popup_action->priv->source == NULL);
 +	g_return_if_fail (GTK_IS_ACTION (source));
 +
 +	popup_action->priv->source = g_object_ref (source);
 +}
 +
 +static void
 +popup_action_set_property (GObject *object,
 +                           guint property_id,
 +                           const GValue *value,
 +                           GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_SOURCE:
 +			popup_action_set_source (
 +				E_POPUP_ACTION (object),
 +				g_value_get_object (value));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +popup_action_get_property (GObject *object,
 +                           guint property_id,
 +                           GValue *value,
 +                           GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_SOURCE:
 +			g_value_set_object (
 +				value, e_popup_action_get_source (
 +				E_POPUP_ACTION (object)));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +popup_action_dispose (GObject *object)
 +{
 +	EPopupActionPrivate *priv;
 +
 +	priv = E_POPUP_ACTION_GET_PRIVATE (object);
 +
 +	if (priv->source != NULL) {
 +		g_object_unref (priv->source);
 +		priv->source = NULL;
 +	}
 +
 +	/* Chain up to parent's dispose() method. */
 +	G_OBJECT_CLASS (parent_class)->dispose (object);
 +}
 +
 +static void
 +popup_action_constructed (GObject *object)
 +{
 +	EPopupActionPrivate *priv;
 +	GObject *source;
 +	gchar *icon_name;
 +	gchar *label;
 +	gchar *stock_id;
 +	gchar *tooltip;
 +
 +	priv = E_POPUP_ACTION_GET_PRIVATE (object);
 +
 +	source = G_OBJECT (priv->source);
 +
 +	g_object_get (
 +		object, "icon-name", &icon_name, "label", &label,
 +		"stock-id", &stock_id, "tooltip", &tooltip, NULL);
 +
 +	if (label == NULL)
 +		e_binding_new (source, "label", object, "label");
 +
 +	if (tooltip == NULL)
 +		e_binding_new (source, "tooltip", object, "tooltip");
 +
 +	if (icon_name == NULL && stock_id == NULL) {
 +		g_free (icon_name);
 +		g_free (stock_id);
 +
 +		g_object_get (
 +			source, "icon-name", &icon_name,
 +			"stock-id", &stock_id, NULL);
 +
 +		if (icon_name == NULL) {
 +			e_binding_new (
 +				source, "icon-name", object, "icon-name");
 +			e_binding_new (
 +				source, "stock-id", object, "stock-id");
 +		} else {
 +			e_binding_new (
 +				source, "stock-id", object, "stock-id");
 +			e_binding_new (
 +				source, "icon-name", object, "icon-name");
 +		}
 +	}
 +
 +	e_binding_new (source, "sensitive", object, "visible");
 +
 +	g_free (icon_name);
 +	g_free (label);
 +	g_free (stock_id);
 +	g_free (tooltip);
 +}
 +
 +static void
 +popup_action_class_init (EPopupActionClass *class)
 +{
 +	GObjectClass *object_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (EPopupActionPrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->set_property = popup_action_set_property;
 +	object_class->get_property = popup_action_get_property;
 +	object_class->dispose = popup_action_dispose;
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_SOURCE,
 +		g_param_spec_object (
 +			"source",
 +			_("Source Action"),
 +			_("The source action to proxy"),
 +			GTK_TYPE_ACTION,
 +			G_PARAM_READWRITE |
 +			G_PARAM_CONSTRUCT_ONLY));
 +}
 +
 +static void
 +popup_action_init (EPopupAction *popup_action)
 +{
 +	popup_action->priv = E_POPUP_ACTION_GET_PRIVATE (popup_action);
 +}
 +
 +GType
 +e_popup_action_get_type (void)
 +{
 +	static GType type = 0;
 +
 +	if (G_UNLIKELY (type == 0)) {
 +		static const GTypeInfo type_info = {
 +			sizeof (EPopupActionClass),
 +			(GBaseInitFunc) NULL,
 +			(GBaseFinalizeFunc) NULL,
 +			(GClassInitFunc) popup_action_class_init,
 +			(GClassFinalizeFunc) NULL,
 +			NULL,  /* class_data */
 +			sizeof (EPopupAction),
 +			0,     /* n_preallocs */
 +			(GInstanceInitFunc) popup_action_init,
 +			NULL   /* value_table */
 +		};
 +
 +		type = g_type_register_static (
 +			GTK_TYPE_ACTION, "EPopupAction", &type_info, 0);
 +	}
 +
 +	return type;
 +}
 +
 +EPopupAction *
 +e_popup_action_new (const gchar *name,
 +                    const gchar *label,
 +                    GtkAction *source)
 +{
 +	EPopupAction *popup_action;
 +
 +	g_return_val_if_fail (name != NULL, NULL);
 +	g_return_val_if_fail (GTK_IS_ACTION (source), NULL);
 +
 +	popup_action = g_object_new (
 +		E_TYPE_POPUP_ACTION, "name", name,
 +		"label", label, "source", source, NULL);
 +
 +	/* XXX This is a hack to work around the fact that GtkAction's
 +	 *     "label" and "tooltip" properties are not constructor
 +	 *     properties, even though they're supplied upfront.
 +	 *
 +	 *     See: http://bugzilla.gnome.org/show_bug.cgi?id=568334 */
 +	popup_action_constructed (G_OBJECT (popup_action));
 +
 +	return popup_action;
 +}
 +
 +GtkAction *
 +e_popup_action_get_source (EPopupAction *popup_action)
 +{
 +	g_return_val_if_fail (E_IS_POPUP_ACTION (popup_action), NULL);
 +
 +	return popup_action->priv->source;
 +}
 +
 +void
 +e_action_group_add_popup_actions (GtkActionGroup *action_group,
 +                                  const EPopupActionEntry *entries,
 +                                  guint n_entries)
 +{
 +	guint ii;
 +
 +	g_return_if_fail (GTK_IS_ACTION_GROUP (action_group));
 +
 +	for (ii = 0; ii < n_entries; ii++) {
 +		EPopupAction *popup_action;
 +		GtkAction *source;
 +		const gchar *label;
 +
 +		label = gtk_action_group_translate_string (
 +			action_group, entries[ii].label);
 +
 +		source = gtk_action_group_get_action (
 +			action_group, entries[ii].source);
 +
 +		if (source == NULL) {
 +			g_warning (
 +				"Source action '%s' not found in "
 +				"action group '%s'", entries[ii].source,
 +				gtk_action_group_get_name (action_group));
 +			continue;
 +		}
 +
 +		popup_action = e_popup_action_new (
 +			entries[ii].name, label, source);
 +
 +		g_signal_connect_swapped (
 +			popup_action, "activate",
 +			G_CALLBACK (gtk_action_activate),
 +			popup_action->priv->source);
 +
 +		gtk_action_group_add_action (
 +			action_group, GTK_ACTION (popup_action));
 +
 +		g_object_unref (popup_action);
 +	}
 +}
diff --cc widgets/misc/e-popup-action.h
index 6000b5a,0000000..d19971f
mode 100644,000000..100644
--- a/widgets/misc/e-popup-action.h
+++ b/widgets/misc/e-popup-action.h
@@@ -1,95 -1,0 +1,95 @@@
 +/*
 + * e-popup-action.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +/* A popup action is an action that lives in a popup menu.  It proxies an
 + * equivalent action in the main menu, with two differences:
 + *
 + * 1) If the main menu action is insensitive, the popup action is invisible.
 + * 2) The popup action may have a different label than the main menu action.
 + *
 + * To use:
 + *
 + * Create an array of EPopupActionEntry structs.  Add the main menu actions
 + * that serve as "sources" for the popup actions to an action group first.
 + * Then pass the same action group and the EPopupActionEntry array to
 + * e_action_group_add_popup_actions() to add popup actions.
 + */
 +
 +#ifndef E_POPUP_ACTION_H
 +#define E_POPUP_ACTION_H
 +
 +#include <gtk/gtk.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_POPUP_ACTION \
 +	(e_popup_action_get_type ())
 +#define E_POPUP_ACTION(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_POPUP_ACTION, EPopupAction))
 +#define E_POPUP_ACTION_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_POPUP_ACTION, EPopupActionClass))
 +#define E_IS_POPUP_ACTION(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_POPUP_ACTION))
 +#define E_IS_POPUP_ACTION_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), E_TYPE_POPUP_ACTION))
 +#define E_POPUP_ACTION_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_POPUP_ACTION, EPopupActionClass))
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _EPopupAction EPopupAction;
 +typedef struct _EPopupActionClass EPopupActionClass;
 +typedef struct _EPopupActionPrivate EPopupActionPrivate;
 +typedef struct _EPopupActionEntry EPopupActionEntry;
 +
 +struct _EPopupAction {
 +	GtkAction parent;
 +	EPopupActionPrivate *priv;
 +};
 +
 +struct _EPopupActionClass {
 +	GtkActionClass parent_class;
 +};
 +
 +struct _EPopupActionEntry {
 +	const gchar *name;
 +	const gchar *label;	/* optional: overrides the source action */
 +	const gchar *source;	/* name of the source action */
 +};
 +
 +GType		e_popup_action_get_type		(void);
 +EPopupAction *	e_popup_action_new		(const gchar *name,
 +						 const gchar *label,
 +						 GtkAction *source);
 +GtkAction *	e_popup_action_get_source	(EPopupAction *popup_action);
 +
 +void		e_action_group_add_popup_actions
 +						(GtkActionGroup *action_group,
 +						 const EPopupActionEntry *entries,
 +						 guint n_entries);
 +
 +G_END_DECLS
 +
 +#endif /* E_POPUP_ACTION_H */
diff --cc widgets/misc/e-preferences-window.c
index ecdbee1,0000000..af2d07d
mode 100644,000000..100644
--- a/widgets/misc/e-preferences-window.c
+++ b/widgets/misc/e-preferences-window.c
@@@ -1,393 -1,0 +1,393 @@@
 +/*
 + * e-preferences-window.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-preferences-window.h"
 +
 +#include <glib/gi18n.h>
 +#include <e-util/e-util.h>
 +
 +#define SWITCH_PAGE_INTERVAL 250
 +
 +#define E_PREFERENCES_WINDOW_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_PREFERENCES_WINDOW, EPreferencesWindowPrivate))
 +
 +struct _EPreferencesWindowPrivate {
 +	GtkWidget *icon_view;
 +	GtkWidget *notebook;
 +	GHashTable *index;
 +};
 +
 +enum {
 +	COLUMN_TEXT,	/* G_TYPE_STRING */
 +	COLUMN_PIXBUF,	/* GDK_TYPE_PIXBUF */
 +	COLUMN_PAGE,	/* G_TYPE_INT */
 +	COLUMN_SORT	/* G_TYPE_INT */
 +};
 +
 +static gpointer parent_class;
 +
 +static GdkPixbuf *
 +preferences_window_load_pixbuf (const gchar *icon_name)
 +{
 +	GtkIconTheme *icon_theme;
 +	GtkIconInfo *icon_info;
 +	GdkPixbuf *pixbuf;
 +	const gchar *filename;
 +	gint size;
 +	GError *error = NULL;
 +
 +	icon_theme = gtk_icon_theme_get_default ();
 +
 +	if (!gtk_icon_size_lookup (GTK_ICON_SIZE_DIALOG, &size, 0))
 +		return NULL;
 +
 +	icon_info = gtk_icon_theme_lookup_icon (
 +		icon_theme, icon_name, size, 0);
 +
 +	if (icon_info == NULL)
 +		return NULL;
 +
 +	filename = gtk_icon_info_get_filename (icon_info);
 +
 +	pixbuf = gdk_pixbuf_new_from_file (filename, &error);
 +
 +	gtk_icon_info_free (icon_info);
 +
 +	if (error != NULL) {
 +		g_warning ("%s", error->message);
 +		g_error_free (error);
 +	}
 +
 +	return pixbuf;
 +}
 +
 +static void
 +preferences_window_help_clicked_cb (GtkWindow *window)
 +{
 +	e_display_help (window, "config-prefs");
 +}
 +
 +static void
 +preferences_window_selection_changed_cb (EPreferencesWindow *window)
 +{
 +	GtkIconView *icon_view;
 +	GtkNotebook *notebook;
 +	GtkTreeModel *model;
 +	GtkTreeIter iter;
 +	GList *list;
 +	gint page;
 +
 +	icon_view = GTK_ICON_VIEW (window->priv->icon_view);
 +	list = gtk_icon_view_get_selected_items (icon_view);
 +	if (list == NULL)
 +		return;
 +
 +	model = gtk_icon_view_get_model (icon_view);
 +	gtk_tree_model_get_iter (model, &iter, list->data);
 +	gtk_tree_model_get (model, &iter, COLUMN_PAGE, &page, -1);
 +
 +	notebook = GTK_NOTEBOOK (window->priv->notebook);
 +	gtk_notebook_set_current_page (notebook, page);
 +
 +	g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
 +	g_list_free (list);
 +
 +	gtk_widget_grab_focus (GTK_WIDGET (icon_view));
 +}
 +
 +static void
 +preferences_window_dispose (GObject *object)
 +{
 +	EPreferencesWindowPrivate *priv;
 +
 +	priv = E_PREFERENCES_WINDOW_GET_PRIVATE (object);
 +
 +	if (priv->icon_view != NULL) {
 +		g_object_unref (priv->icon_view);
 +		priv->icon_view = NULL;
 +	}
 +
 +	if (priv->notebook != NULL) {
 +		g_object_unref (priv->notebook);
 +		priv->notebook = NULL;
 +	}
 +
 +	g_hash_table_remove_all (priv->index);
 +
 +	/* Chain up to parent's dispose() method. */
 +	G_OBJECT_CLASS (parent_class)->dispose (object);
 +}
 +
 +static void
 +preferences_window_finalize (GObject *object)
 +{
 +	EPreferencesWindowPrivate *priv;
 +
 +	priv = E_PREFERENCES_WINDOW_GET_PRIVATE (object);
 +
 +	g_hash_table_destroy (priv->index);
 +
 +	/* Chain up to parent's finalize() method. */
 +	G_OBJECT_CLASS (parent_class)->finalize (object);
 +}
 +
 +static void
 +preferences_window_show (GtkWidget *widget)
 +{
 +	EPreferencesWindowPrivate *priv;
 +	GtkIconView *icon_view;
 +	GtkTreePath *path;
 +
 +	priv = E_PREFERENCES_WINDOW_GET_PRIVATE (widget);
 +
 +	icon_view = GTK_ICON_VIEW (priv->icon_view);
 +
 +	path = gtk_tree_path_new_first ();
 +	gtk_icon_view_select_path (icon_view, path);
 +	gtk_icon_view_scroll_to_path (icon_view, path, FALSE, 0.0, 0.0);
 +	gtk_tree_path_free (path);
 +
 +	gtk_widget_grab_focus (priv->icon_view);
 +
 +	/* Chain up to parent's show() method. */
 +	GTK_WIDGET_CLASS (parent_class)->show (widget);
 +}
 +
 +static void
 +preferences_window_class_init (EPreferencesWindowClass *class)
 +{
 +	GObjectClass *object_class;
 +	GtkWidgetClass *widget_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (EPreferencesWindowPrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->dispose = preferences_window_dispose;
 +	object_class->finalize = preferences_window_finalize;
 +
 +	widget_class = GTK_WIDGET_CLASS (class);
 +	widget_class->show = preferences_window_show;
 +}
 +
 +static void
 +preferences_window_init (EPreferencesWindow *window)
 +{
 +	GtkListStore *store;
 +	GtkWidget *container;
 +	GtkWidget *hbox;
 +	GtkWidget *vbox;
 +	GtkWidget *widget;
 +	GHashTable *index;
 +	const gchar *title;
 +
 +	index = g_hash_table_new_full (
 +		g_str_hash, g_str_equal,
 +		(GDestroyNotify) g_free,
 +		(GDestroyNotify) gtk_tree_row_reference_free);
 +
 +	window->priv = E_PREFERENCES_WINDOW_GET_PRIVATE (window);
 +	window->priv->index = index;
 +
 +	store = gtk_list_store_new (
 +		4, G_TYPE_STRING, GDK_TYPE_PIXBUF, G_TYPE_INT, G_TYPE_INT);
 +	gtk_tree_sortable_set_sort_column_id (
 +		GTK_TREE_SORTABLE (store), COLUMN_SORT, GTK_SORT_ASCENDING);
 +
 +	title = _("Evolution Preferences");
 +	gtk_window_set_title (GTK_WINDOW (window), title);
 +	gtk_window_set_resizable (GTK_WINDOW (window), TRUE);
 +	gtk_container_set_border_width (GTK_CONTAINER (window), 12);
 +
 +	g_signal_connect (
 +		window, "delete-event",
 +		G_CALLBACK (gtk_widget_hide_on_delete), NULL);
 +
 +	widget = gtk_vbox_new (FALSE, 12);
 +	gtk_container_add (GTK_CONTAINER (window), widget);
 +	gtk_widget_show (widget);
 +
 +	vbox = widget;
 +
 +	widget = gtk_hbox_new (FALSE, 12);
 +	gtk_box_pack_start (GTK_BOX (vbox), widget, TRUE, TRUE, 0);
 +	gtk_widget_show (widget);
 +
 +	hbox = widget;
 +
 +	widget = gtk_scrolled_window_new (NULL, NULL);
 +	gtk_scrolled_window_set_policy (
 +		GTK_SCROLLED_WINDOW (widget),
 +		GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
 +	gtk_scrolled_window_set_shadow_type (
 +		GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
 +	gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, TRUE, 0);
 +	gtk_widget_show (widget);
 +
 +	container = widget;
 +
 +	widget = gtk_icon_view_new_with_model (GTK_TREE_MODEL (store));
 +	gtk_icon_view_set_columns (GTK_ICON_VIEW (widget), 1);
 +	gtk_icon_view_set_text_column (GTK_ICON_VIEW (widget), COLUMN_TEXT);
 +	gtk_icon_view_set_pixbuf_column (GTK_ICON_VIEW (widget), COLUMN_PIXBUF);
 +	g_signal_connect_swapped (
 +		widget, "selection-changed",
 +		G_CALLBACK (preferences_window_selection_changed_cb), window);
 +	gtk_container_add (GTK_CONTAINER (container), widget);
 +	window->priv->icon_view = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +	g_object_unref (store);
 +
 +	widget = gtk_notebook_new ();
 +	gtk_notebook_set_show_tabs (GTK_NOTEBOOK (widget), FALSE);
 +	gtk_notebook_set_show_border (GTK_NOTEBOOK (widget), FALSE);
 +	gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0);
 +	window->priv->notebook = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	widget = gtk_hbutton_box_new ();
 +	gtk_button_box_set_layout (
 +		GTK_BUTTON_BOX (widget), GTK_BUTTONBOX_END);
 +	gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0);
 +	gtk_widget_show (widget);
 +
 +	container = widget;
 +
 +	widget = gtk_button_new_from_stock (GTK_STOCK_HELP);
 +	g_signal_connect_swapped (
 +		widget, "clicked",
 +		G_CALLBACK (preferences_window_help_clicked_cb), window);
 +	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
 +	gtk_button_box_set_child_secondary (
 +		GTK_BUTTON_BOX (container), widget, TRUE);
 +	gtk_widget_show (widget);
 +
 +	widget = gtk_button_new_from_stock (GTK_STOCK_CLOSE);
 +	g_signal_connect_swapped (
 +		widget, "clicked",
 +		G_CALLBACK (gtk_widget_hide), window);
 +	GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_DEFAULT);
 +	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
 +	gtk_widget_grab_default (widget);
 +	gtk_widget_show (widget);
 +}
 +
 +GType
 +e_preferences_window_get_type (void)
 +{
 +	static GType type = 0;
 +
 +	if (G_UNLIKELY (type == 0)) {
 +		const GTypeInfo type_info = {
 +			sizeof (EPreferencesWindowClass),
 +			(GBaseInitFunc) NULL,
 +			(GBaseFinalizeFunc) NULL,
 +			(GClassInitFunc) preferences_window_class_init,
 +			(GClassFinalizeFunc) NULL,
 +			NULL,  /* class_data */
 +			sizeof (EPreferencesWindow),
 +			0,     /* n_preallocs */
 +			(GInstanceInitFunc) preferences_window_init,
 +			NULL   /* value_table */
 +		};
 +
 +		type = g_type_register_static (
 +			GTK_TYPE_WINDOW, "EPreferencesWindow", &type_info, 0);
 +	}
 +
 +	return type;
 +}
 +
 +GtkWidget *
 +e_preferences_window_new (void)
 +{
 +	return g_object_new (E_TYPE_PREFERENCES_WINDOW, NULL);
 +}
 +
 +void
 +e_preferences_window_add_page (EPreferencesWindow *window,
 +                               const gchar *page_name,
 +                               const gchar *icon_name,
 +                               const gchar *caption,
 +                               GtkWidget *widget,
 +                               gint sort_order)
 +{
 +	GtkTreeRowReference *reference;
 +	GtkIconView *icon_view;
 +	GtkNotebook *notebook;
 +	GtkTreeModel *model;
 +	GtkTreePath *path;
 +	GHashTable *index;
 +	GdkPixbuf *pixbuf;
 +	GtkTreeIter iter;
 +	gint page;
 +
 +	g_return_if_fail (E_IS_PREFERENCES_WINDOW (window));
 +	g_return_if_fail (page_name != NULL);
 +	g_return_if_fail (icon_name != NULL);
 +	g_return_if_fail (caption != NULL);
 +	g_return_if_fail (GTK_IS_WIDGET (widget));
 +
 +	icon_view = GTK_ICON_VIEW (window->priv->icon_view);
 +	notebook = GTK_NOTEBOOK (window->priv->notebook);
 +
 +	page = gtk_notebook_get_n_pages (notebook);
 +	model = gtk_icon_view_get_model (icon_view);
 +	pixbuf = preferences_window_load_pixbuf (icon_name);
 +
 +	gtk_list_store_append (GTK_LIST_STORE (model), &iter);
 +
 +	gtk_list_store_set (
 +		GTK_LIST_STORE (model), &iter,
 +		COLUMN_TEXT, caption, COLUMN_PIXBUF, pixbuf,
 +		COLUMN_PAGE, page, COLUMN_SORT, sort_order, -1);
 +
 +	index = window->priv->index;
 +	path = gtk_tree_model_get_path (model, &iter);
 +	reference = gtk_tree_row_reference_new (model, path);
 +	g_hash_table_insert (index, g_strdup (page_name), reference);
 +	gtk_tree_path_free (path);
 +
 +	gtk_widget_show (widget);
 +	gtk_notebook_append_page (notebook, widget, NULL);
 +}
 +
 +void
 +e_preferences_window_show_page (EPreferencesWindow *window,
 +                                const gchar *page_name)
 +{
 +	GtkTreeRowReference *reference;
 +	GtkIconView *icon_view;
 +	GtkTreePath *path;
 +
 +	g_return_if_fail (E_IS_PREFERENCES_WINDOW (window));
 +	g_return_if_fail (page_name != NULL);
 +
 +	icon_view = GTK_ICON_VIEW (window->priv->icon_view);
 +	reference = g_hash_table_lookup (window->priv->index, page_name);
 +	g_return_if_fail (reference != NULL);
 +
 +	path = gtk_tree_row_reference_get_path (reference);
 +	gtk_icon_view_select_path (icon_view, path);
 +	gtk_icon_view_scroll_to_path (icon_view, path, FALSE, 0.0, 0.0);
 +	gtk_tree_path_free (path);
 +}
diff --cc widgets/misc/e-preferences-window.h
index 39f2b82,0000000..4944a89
mode 100644,000000..100644
--- a/widgets/misc/e-preferences-window.h
+++ b/widgets/misc/e-preferences-window.h
@@@ -1,74 -1,0 +1,74 @@@
 +/*
 + * e-preferences-window.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_PREFERENCES_WINDOW_H
 +#define E_PREFERENCES_WINDOW_H
 +
 +#include <gtk/gtk.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_PREFERENCES_WINDOW \
 +	(e_preferences_window_get_type ())
 +#define E_PREFERENCES_WINDOW(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_PREFERENCES_WINDOW, EPreferencesWindow))
 +#define E_PREFERENCES_WINDOW_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_PREFERENCES_WINDOW, EPreferencesWindowClass))
 +#define E_IS_PREFERENCES_WINDOW(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_PREFERENCES_WINDOW))
 +#define E_IS_PREFERENCES_WINDOW_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((obj), E_TYPE_PREFERENCES_WINDOW))
 +#define E_PREFERENCES_WINDOW_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_TYPE \
 +	((obj), E_TYPE_PREFERENCES_WINDOW, EPreferencesWindowClass))
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _EPreferencesWindow EPreferencesWindow;
 +typedef struct _EPreferencesWindowClass EPreferencesWindowClass;
 +typedef struct _EPreferencesWindowPrivate EPreferencesWindowPrivate;
 +
 +struct _EPreferencesWindow {
 +	GtkWindow parent;
 +	EPreferencesWindowPrivate *priv;
 +};
 +
 +struct _EPreferencesWindowClass {
 +	GtkWindowClass parent_class;
 +};
 +
 +GType		e_preferences_window_get_type	(void);
 +GtkWidget *	e_preferences_window_new	(void);
 +void		e_preferences_window_add_page	(EPreferencesWindow *window,
 +						 const gchar *page_name,
 +						 const gchar *icon_name,
 +						 const gchar *caption,
 +						 GtkWidget *widget,
 +						 gint sort_order);
 +void		e_preferences_window_show_page	(EPreferencesWindow *window,
 +						 const gchar *page_name);
 +
 +G_END_DECLS
 +
 +#endif /* E_PREFERENCES_WINDOW_H */
diff --cc widgets/misc/e-search-bar.c
index 2d1fd5e,2bbbc91..9abc604
--- a/widgets/misc/e-search-bar.c
+++ b/widgets/misc/e-search-bar.c
@@@ -1260,15 -1329,14 +1276,18 @@@ e_search_bar_set_ui_component (ESearchB
  }
  
  void
 -e_search_bar_set_menu_sensitive (ESearchBar *search_bar, int id, gboolean state)
 +e_search_bar_set_search_text (ESearchBar *search_bar,
 +                              const gchar *text)
  {
 -	char *verb_name;
 -	char *path;
 +	EIconEntry *icon_entry;
 +	GtkWidget *entry;
 +
 +	if (search_bar->lite)
 +		return;
  
+ 	if (search_bar->lite)
+ 		return;
+ 
  	verb_name = verb_name_from_id (id);
  	path = g_strconcat ("/commands/", verb_name, NULL);
  	g_free (verb_name);
diff --cc widgets/misc/e-signature-editor.c
index cc1e9f6,0000000..53cb349
mode 100644,000000..100644
--- a/widgets/misc/e-signature-editor.c
+++ b/widgets/misc/e-signature-editor.c
@@@ -1,503 -1,0 +1,503 @@@
 +/*
 + * e-signature-editor.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-signature-editor.h"
 +
 +#include <string.h>
 +#include <glib/gi18n.h>
 +
 +#include <e-util/e-error.h>
 +#include <e-util/e-signature-utils.h>
 +
 +#define E_SIGNATURE_EDITOR_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_SIGNATURE_EDITOR, ESignatureEditorPrivate))
 +
 +enum {
 +	PROP_0,
 +	PROP_SIGNATURE
 +};
 +
 +struct _ESignatureEditorPrivate {
 +	GtkActionGroup *action_group;
 +	ESignature *signature;
 +	GtkWidget *entry;
 +	gchar *original_name;
 +};
 +
 +static const gchar *ui =
 +"<ui>\n"
 +"  <menubar name='main-menu'>\n"
 +"    <placeholder name='pre-edit-menu'>\n"
 +"      <menu action='file-menu'>\n"
 +"        <menuitem action='save-and-close'/>\n"
 +"        <separator/>"
 +"        <menuitem action='close'/>\n"
 +"      </menu>\n"
 +"    </placeholder>\n"
 +"  </menubar>\n"
 +"  <toolbar name='main-toolbar'>\n"
 +"    <placeholder name='pre-main-toolbar'>\n"
 +"      <toolitem action='save-and-close'/>\n"
 +"    </placeholder>\n"
 +"  </toolbar>\n"
 +"</ui>";
 +
 +static gpointer parent_class = NULL;
 +
 +static void
 +handle_error (GError **error)
 +{
 +	if (*error != NULL) {
 +		g_warning ("%s", (*error)->message);
 +		g_clear_error (error);
 +	}
 +}
 +
 +static void
 +action_close_cb (GtkAction *action,
 +                 ESignatureEditor *editor)
 +{
 +	gboolean something_changed = FALSE;
 +	const gchar *original_name;
 +	const gchar *signature_name;
 +
 +	original_name = editor->priv->original_name;
 +	signature_name = gtk_entry_get_text (GTK_ENTRY (editor->priv->entry));
 +
 +	something_changed |= gtkhtml_editor_has_undo (GTKHTML_EDITOR (editor));
 +	something_changed |= (strcmp (signature_name, original_name) != 0);
 +
 +	if (something_changed) {
 +		gint response;
 +
 +		response = e_error_run (
 +			GTK_WINDOW (editor),
 +			"mail:ask-signature-changed", NULL);
 +		if (response == GTK_RESPONSE_YES) {
 +			GtkActionGroup *action_group;
 +
 +			action_group = editor->priv->action_group;
 +			action = gtk_action_group_get_action (
 +				action_group, "save-and-close");
 +			gtk_action_activate (action);
 +			return;
 +		} else if (response == GTK_RESPONSE_CANCEL)
 +			return;
 +	}
 +
 +	gtk_widget_destroy (GTK_WIDGET (editor));
 +}
 +
 +static void
 +action_save_and_close_cb (GtkAction *action,
 +                          ESignatureEditor *editor)
 +{
 +	GtkWidget *entry;
 +	ESignatureList *signature_list;
 +	ESignature *signature;
 +	ESignature *same_name;
 +	const gchar *filename;
 +	gchar *signature_name;
 +	gboolean html;
 +	GError *error = NULL;
 +
 +	entry = editor->priv->entry;
 +	html = gtkhtml_editor_get_html_mode (GTKHTML_EDITOR (editor));
 +
 +	if (editor->priv->signature == NULL) {
 +		signature = e_signature_new ();
 +		signature->name = g_strdup (_("Unnamed"));
 +		signature->script = FALSE;
 +		signature->html = html;
 +
 +		/* FIXME Pass a GError and deal with it. */
 +		signature->filename = e_create_signature_file (NULL);
 +	} else {
 +		signature = g_object_ref (editor->priv->signature);
 +		signature->html = html;
 +	}
 +
 +	filename = signature->filename;
 +	gtkhtml_editor_save (GTKHTML_EDITOR (editor), filename, html, &error);
 +
 +	if (error != NULL) {
 +		e_error_run (
 +			GTK_WINDOW (editor),
 +			"mail:no-save-signature",
 +			error->message, NULL);
 +		g_clear_error (&error);
 +		return;
 +	}
 +
 +	signature_list = e_get_signature_list ();
 +
 +	signature_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
 +	g_strstrip (signature_name);
 +
 +	/* Make sure the signature name is not blank. */
 +	if (*signature_name == '\0') {
 +		e_error_run (
 +			GTK_WINDOW (editor),
 +			"mail:blank-signature", NULL);
 +		gtk_widget_grab_focus (entry);
 +		g_free (signature_name);
 +		return;
 +	}
 +
 +	/* Don't overwrite an existing signature of the same name.
 +	 * XXX ESignatureList misuses const. */
 +	same_name = (ESignature *) e_signature_list_find (
 +		signature_list, E_SIGNATURE_FIND_NAME, signature_name);
 +	if (same_name != NULL && strcmp (signature->uid, same_name->uid) != 0) {
 +		e_error_run (
 +			GTK_WINDOW (editor),
 +			"mail:signature-already-exists",
 +			signature_name, NULL);
 +		gtk_widget_grab_focus (entry);
 +		g_free (signature_name);
 +		return;
 +	}
 +
 +	g_free (signature->name);
 +	signature->name = signature_name;
 +
 +	if (editor->priv->signature != NULL)
 +		e_signature_list_change (signature_list, signature);
 +	else
 +		e_signature_list_add (signature_list, signature);
 +	e_signature_list_save (signature_list);
 +
 +	gtk_widget_destroy (GTK_WIDGET (editor));
 +}
 +
 +static GtkActionEntry entries[] = {
 +
 +	{ "close",
 +	  GTK_STOCK_CLOSE,
 +	  N_("_Close"),
 +	  "<Control>w",
 +	  NULL,
 +	  G_CALLBACK (action_close_cb) },
 +
 +	{ "save-and-close",
 +	  GTK_STOCK_SAVE,
 +	  N_("_Save and Close"),
 +	  "<Control>Return",
 +	  NULL,
 +	  G_CALLBACK (action_save_and_close_cb) },
 +
 +	{ "file-menu",
 +	  NULL,
 +	  N_("_File"),
 +	  NULL,
 +	  NULL,
 +	  NULL }
 +};
 +
 +static gboolean
 +signature_editor_delete_event_cb (ESignatureEditor *editor,
 +                                  GdkEvent *event)
 +{
 +	GtkActionGroup *action_group;
 +	GtkAction *action;
 +
 +	action_group = editor->priv->action_group;
 +	action = gtk_action_group_get_action (action_group, "close");
 +	gtk_action_activate (action);
 +
 +	return TRUE;
 +}
 +
 +static void
 +signature_editor_set_property (GObject *object,
 +                               guint property_id,
 +                               const GValue *value,
 +                               GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_SIGNATURE:
 +			e_signature_editor_set_signature (
 +				E_SIGNATURE_EDITOR (object),
 +				g_value_get_object (value));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +signature_editor_get_property (GObject *object,
 +                               guint property_id,
 +                               GValue *value,
 +                               GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_SIGNATURE:
 +			g_value_set_object (
 +				value, e_signature_editor_get_signature (
 +				E_SIGNATURE_EDITOR (object)));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +signature_editor_dispose (GObject *object)
 +{
 +	ESignatureEditorPrivate *priv;
 +
 +	priv = E_SIGNATURE_EDITOR_GET_PRIVATE (object);
 +
 +	if (priv->action_group != NULL) {
 +		g_object_unref (priv->action_group);
 +		priv->action_group = NULL;
 +	}
 +
 +	if (priv->signature != NULL) {
 +		g_object_unref (priv->signature);
 +		priv->signature = NULL;
 +	}
 +
 +	if (priv->entry != NULL) {
 +		g_object_unref (priv->entry);
 +		priv->entry = NULL;
 +	}
 +
 +	/* Chain up to parent's dispose() method. */
 +	G_OBJECT_CLASS (parent_class)->dispose (object);
 +}
 +
 +static void
 +signature_editor_finalize (GObject *object)
 +{
 +	ESignatureEditorPrivate *priv;
 +
 +	priv = E_SIGNATURE_EDITOR_GET_PRIVATE (object);
 +
 +	g_free (priv->original_name);
 +
 +	/* Chain up to parent's finalize() method. */
 +	G_OBJECT_CLASS (parent_class)->finalize (object);
 +}
 +
 +static void
 +signature_editor_class_init (ESignatureEditorClass *class)
 +{
 +	GObjectClass *object_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (ESignatureEditorPrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->set_property = signature_editor_set_property;
 +	object_class->get_property = signature_editor_get_property;
 +	object_class->dispose = signature_editor_dispose;
 +	object_class->finalize = signature_editor_finalize;
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_SIGNATURE,
 +		g_param_spec_object (
 +			"signature",
 +			NULL,
 +			NULL,
 +			E_TYPE_SIGNATURE,
 +			G_PARAM_READWRITE));
 +}
 +
 +static void
 +signature_editor_init (ESignatureEditor *editor)
 +{
 +	GtkActionGroup *action_group;
 +	GtkUIManager *ui_manager;
 +	GtkWidget *container;
 +	GtkWidget *widget;
 +	GtkWidget *vbox;
 +	GError *error = NULL;
 +
 +	editor->priv = E_SIGNATURE_EDITOR_GET_PRIVATE (editor);
 +	vbox = GTKHTML_EDITOR (editor)->vbox;
 +
 +	ui_manager = gtkhtml_editor_get_ui_manager (GTKHTML_EDITOR (editor));
 +
 +	gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error);
 +	handle_error (&error);
 +
 +	action_group = gtk_action_group_new ("signature");
 +	gtk_action_group_set_translation_domain (
 +		action_group, GETTEXT_PACKAGE);
 +	gtk_action_group_add_actions (
 +		action_group, entries,
 +		G_N_ELEMENTS (entries), editor);
 +	gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
 +	editor->priv->action_group = g_object_ref (action_group);
 +
 +	gtk_ui_manager_ensure_update (ui_manager);
 +
 +	gtk_window_set_title (GTK_WINDOW (editor), _("Edit Signature"));
 +
 +	widget = gtk_hbox_new (FALSE, 6);
 +	gtk_container_set_border_width (GTK_CONTAINER (widget), 6);
 +	gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0);
 +	/* Position 2 should be between the main and style toolbars. */
 +	gtk_box_reorder_child (GTK_BOX (vbox), widget, 2);
 +	gtk_widget_show (widget);
 +	container = widget;
 +
 +	widget = gtk_entry_new ();
 +	gtk_box_pack_end (GTK_BOX (container), widget, TRUE, TRUE, 0);
 +	editor->priv->entry = g_object_ref_sink (widget);
 +	gtk_widget_show (widget);
 +
 +	widget = gtk_label_new_with_mnemonic (_("_Signature Name:"));
 +	gtk_label_set_mnemonic_widget (GTK_LABEL (widget), editor->priv->entry);
 +	gtk_box_pack_end (GTK_BOX (container), widget, FALSE, FALSE, 0);
 +	gtk_widget_show (widget);
 +
 +	g_signal_connect (
 +		editor, "delete-event",
 +		G_CALLBACK (signature_editor_delete_event_cb), NULL);
 +
 +	e_signature_editor_set_signature (editor, NULL);
 +}
 +
 +GType
 +e_signature_editor_get_type (void)
 +{
 +	static GType type = 0;
 +
 +	if (G_UNLIKELY (type == 0)) {
 +		static const GTypeInfo type_info = {
 +			sizeof (ESignatureEditorClass),
 +			(GBaseInitFunc) NULL,
 +			(GBaseFinalizeFunc) NULL,
 +			(GClassInitFunc) signature_editor_class_init,
 +			(GClassFinalizeFunc) NULL,
 +			NULL,  /* class_data */
 +			sizeof (ESignatureEditor),
 +			0,     /* n_preallocs */
 +			(GInstanceInitFunc) signature_editor_init,
 +			NULL   /* value_table */
 +		};
 +
 +		type = g_type_register_static (
 +			GTKHTML_TYPE_EDITOR, "ESignatureEditor",
 +			&type_info, 0);
 +	}
 +
 +	return type;
 +}
 +
 +GtkWidget *
 +e_signature_editor_new (void)
 +{
 +	return g_object_new (E_TYPE_SIGNATURE_EDITOR, NULL);
 +}
 +
 +ESignature *
 +e_signature_editor_get_signature (ESignatureEditor *editor)
 +{
 +	g_return_val_if_fail (E_IS_SIGNATURE_EDITOR (editor), NULL);
 +
 +	return editor->priv->signature;
 +}
 +
 +void
 +e_signature_editor_set_signature (ESignatureEditor *editor,
 +                                  ESignature *signature)
 +{
 +	const gchar *filename;
 +	const gchar *signature_name;
 +	gchar *contents;
 +	gsize length;
 +	GError *error = NULL;
 +
 +	g_return_if_fail (E_IS_SIGNATURE_EDITOR (editor));
 +
 +	if (signature != NULL)
 +		g_return_if_fail (E_SIGNATURE (signature));
 +
 +	if (editor->priv->signature != NULL) {
 +		g_object_unref (editor->priv->signature);
 +		editor->priv->signature = NULL;
 +	}
 +
 +	if (signature == NULL)
 +		goto exit;
 +
 +	editor->priv->signature = g_object_ref (signature);
 +
 +	/* Load signature content. */
 +
 +	filename = signature->filename;
 +
 +	if (signature->html)
 +		g_file_get_contents (filename, &contents, &length, &error);
 +	else {
 +		gchar *data;
 +
 +		data = e_read_signature_file (signature, FALSE, &error);
 +		if (data != NULL)
 +			contents = g_strdup_printf ("<PRE>\n%s", data);
 +		else
 +			contents = NULL;
 +		length = -1;
 +		g_free (data);
 +	}
 +
 +	if (error == NULL) {
 +		gtkhtml_editor_set_html_mode (
 +			GTKHTML_EDITOR (editor), signature->html);
 +		gtkhtml_editor_set_text_html (
 +			GTKHTML_EDITOR (editor), contents, length);
 +		g_free (contents);
 +	} else {
 +		g_warning ("%s", error->message);
 +		g_error_free (error);
 +	}
 +
 +exit:
 +	if (signature != NULL)
 +		signature_name = signature->name;
 +	else
 +		signature_name = _("Unnamed");
 +
 +	/* Set the entry text before we grab focus. */
 +	g_free (editor->priv->original_name);
 +	editor->priv->original_name = g_strdup (signature_name);
 +	gtk_entry_set_text (GTK_ENTRY (editor->priv->entry), signature_name);
 +
 +	/* Set the focus appropriately.  If this is a new signature, draw
 +	 * the user's attention to the signature name entry.  Otherwise go
 +	 * straight to the editing area. */
 +	if (signature == NULL)
 +		gtk_widget_grab_focus (editor->priv->entry);
 +	else {
 +		GtkHTML *html;
 +
 +		html = gtkhtml_editor_get_html (GTKHTML_EDITOR (editor));
 +		gtk_widget_grab_focus (GTK_WIDGET (html));
 +	}
 +
 +	g_object_notify (G_OBJECT (editor), "signature");
 +}
diff --cc widgets/misc/e-signature-editor.h
index 9d6c37a,0000000..1e8b88a
mode 100644,000000..100644
--- a/widgets/misc/e-signature-editor.h
+++ b/widgets/misc/e-signature-editor.h
@@@ -1,70 -1,0 +1,70 @@@
 +/*
 + * e-signature-editor.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_SIGNATURE_EDITOR_H
 +#define E_SIGNATURE_EDITOR_H
 +
 +#include <gtkhtml-editor.h>
 +#include <e-util/e-signature.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_SIGNATURE_EDITOR \
 +	(e_signature_editor_get_type ())
 +#define E_SIGNATURE_EDITOR(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_SIGNATURE_EDITOR, ESignatureEditor))
 +#define E_SIGNATURE_EDITOR_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_SIGNATURE_EDITOR, ESignatureEditorClass))
 +#define E_IS_SIGNATURE_EDITOR(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_SIGNATURE_EDITOR))
 +#define E_IS_SIGNATURE_EDITOR_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), E_TYPE_SIGNATURE_EDITOR))
 +#define E_SIGNATURE_EDITOR_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_SIGNATURE_EDITOR, ESignatureEditorClass))
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _ESignatureEditor ESignatureEditor;
 +typedef struct _ESignatureEditorClass ESignatureEditorClass;
 +typedef struct _ESignatureEditorPrivate ESignatureEditorPrivate;
 +
 +struct _ESignatureEditor {
 +	GtkhtmlEditor parent;
 +	ESignatureEditorPrivate *priv;
 +};
 +
 +struct _ESignatureEditorClass {
 +	GtkhtmlEditorClass parent_class;
 +};
 +
 +GType		e_signature_editor_get_type	 (void);
 +GtkWidget *	e_signature_editor_new		 (void);
 +ESignature *	e_signature_editor_get_signature (ESignatureEditor *editor);
 +void		e_signature_editor_set_signature (ESignatureEditor *editor,
 +						  ESignature *signature);
 +
 +G_END_DECLS
 +
 +#endif /* E_SIGNATURE_EDITOR_H */
diff --cc widgets/misc/e-signature-manager.c
index a602710,0000000..a70bc1d
mode 100644,000000..100644
--- a/widgets/misc/e-signature-manager.c
+++ b/widgets/misc/e-signature-manager.c
@@@ -1,746 -1,0 +1,746 @@@
 +/*
 + * e-signature-manager.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-signature-manager.h"
 +
 +#include <glib/gi18n.h>
 +#include <glib/gstdio.h>
 +#include <gdk/gdkkeysyms.h>
 +#include "e-util/e-binding.h"
 +#include "e-signature-tree-view.h"
 +#include "e-signature-script-dialog.h"
 +
 +#define E_SIGNATURE_MANAGER_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_SIGNATURE_MANAGER, ESignatureManagerPrivate))
 +
 +struct _ESignatureManagerPrivate {
 +	ESignatureList *signature_list;
 +
 +	GtkWidget *tree_view;
 +	GtkWidget *add_button;
 +	GtkWidget *add_script_button;
 +	GtkWidget *edit_button;
 +	GtkWidget *remove_button;
 +
 +	guint allow_scripts : 1;
 +	guint prefer_html   : 1;
 +};
 +
 +enum {
 +	PROP_0,
 +	PROP_ALLOW_SCRIPTS,
 +	PROP_PREFER_HTML,
 +	PROP_SIGNATURE_LIST
 +};
 +
 +enum {
 +	ADD_SIGNATURE,
 +	ADD_SIGNATURE_SCRIPT,
 +	EDITOR_CREATED,
 +	EDIT_SIGNATURE,
 +	REMOVE_SIGNATURE,
 +	LAST_SIGNAL
 +};
 +
 +static gpointer parent_class;
 +static guint signals[LAST_SIGNAL];
 +
 +static void
 +signature_manager_emit_editor_created (ESignatureManager *manager,
 +                                       GtkWidget *editor)
 +{
 +	g_return_if_fail (E_IS_SIGNATURE_EDITOR (editor));
 +
 +	g_signal_emit (manager, signals[EDITOR_CREATED], 0, editor);
 +}
 +
 +static gboolean
 +signature_manager_key_press_event_cb (ESignatureManager *manager,
 +                                      GdkEventKey *event)
 +{
 +	if (event->keyval == GDK_Delete) {
 +		e_signature_manager_remove_signature (manager);
 +		return TRUE;
 +	}
 +
 +	return FALSE;
 +}
 +
 +static gboolean
 +signature_manager_run_script_dialog (ESignatureManager *manager,
 +                                     ESignature *signature,
 +                                     const gchar *title)
 +{
 +	GtkWidget *dialog;
 +	GFile *script_file;
 +	const gchar *script_name;
 +	gboolean success = FALSE;
 +	gpointer parent;
 +
 +	parent = gtk_widget_get_toplevel (GTK_WIDGET (manager));
 +	parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL;
 +
 +	dialog = e_signature_script_dialog_new (parent);
 +	gtk_window_set_title (GTK_WINDOW (dialog), title);
 +
 +	if (signature->filename != NULL && signature->name != NULL) {
 +
 +		script_file = g_file_new_for_path (signature->filename);
 +		script_name = signature->name;
 +
 +		e_signature_script_dialog_set_script_file (
 +			E_SIGNATURE_SCRIPT_DIALOG (dialog), script_file);
 +		e_signature_script_dialog_set_script_name (
 +			E_SIGNATURE_SCRIPT_DIALOG (dialog), script_name);
 +
 +		g_object_unref (script_file);
 +	}
 +
 +	if (gtk_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_OK)
 +		goto exit;
 +
 +	script_file = e_signature_script_dialog_get_script_file (
 +		E_SIGNATURE_SCRIPT_DIALOG (dialog));
 +	script_name = e_signature_script_dialog_get_script_name (
 +		E_SIGNATURE_SCRIPT_DIALOG (dialog));
 +
 +	g_free (signature->filename);
 +	signature->filename = g_file_get_path (script_file);
 +
 +	g_free (signature->name);
 +	signature->name = g_strdup (script_name);
 +
 +	g_object_unref (script_file);
 +
 +	success = TRUE;
 +
 +exit:
 +	gtk_widget_destroy (dialog);
 +
 +	return success;
 +}
 +
 +static void
 +signature_manager_selection_changed_cb (ESignatureManager *manager,
 +                                        GtkTreeSelection *selection)
 +{
 +	ESignatureTreeView *tree_view;
 +	ESignature *signature;
 +	GtkWidget *edit_button;
 +	GtkWidget *remove_button;
 +	gboolean sensitive;
 +
 +	edit_button = manager->priv->edit_button;
 +	remove_button = manager->priv->remove_button;
 +
 +	tree_view = e_signature_manager_get_tree_view (manager);
 +	signature = e_signature_tree_view_get_selected (tree_view);
 +	sensitive = (signature != NULL);
 +
 +	gtk_widget_set_sensitive (edit_button, sensitive);
 +	gtk_widget_set_sensitive (remove_button, sensitive);
 +}
 +
 +static void
 +signature_manager_set_property (GObject *object,
 +                                guint property_id,
 +                                const GValue *value,
 +                                GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_ALLOW_SCRIPTS:
 +			e_signature_manager_set_allow_scripts (
 +				E_SIGNATURE_MANAGER (object),
 +				g_value_get_boolean (value));
 +			return;
 +
 +		case PROP_PREFER_HTML:
 +			e_signature_manager_set_prefer_html (
 +				E_SIGNATURE_MANAGER (object),
 +				g_value_get_boolean (value));
 +			return;
 +
 +		case PROP_SIGNATURE_LIST:
 +			e_signature_manager_set_signature_list (
 +				E_SIGNATURE_MANAGER (object),
 +				g_value_get_object (value));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +signature_manager_get_property (GObject *object,
 +                                guint property_id,
 +                                GValue *value,
 +                                GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_ALLOW_SCRIPTS:
 +			g_value_set_boolean (
 +				value,
 +				e_signature_manager_get_allow_scripts (
 +				E_SIGNATURE_MANAGER (object)));
 +			return;
 +
 +		case PROP_PREFER_HTML:
 +			g_value_set_boolean (
 +				value,
 +				e_signature_manager_get_prefer_html (
 +				E_SIGNATURE_MANAGER (object)));
 +			return;
 +
 +		case PROP_SIGNATURE_LIST:
 +			g_value_set_object (
 +				value,
 +				e_signature_manager_get_signature_list (
 +				E_SIGNATURE_MANAGER (object)));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +signature_manager_dispose (GObject *object)
 +{
 +	ESignatureManagerPrivate *priv;
 +
 +	priv = E_SIGNATURE_MANAGER_GET_PRIVATE (object);
 +
 +	if (priv->signature_list != NULL) {
 +		g_object_unref (priv->signature_list);
 +		priv->signature_list = NULL;
 +	}
 +
 +	if (priv->tree_view != NULL) {
 +		g_object_unref (priv->tree_view);
 +		priv->tree_view = NULL;
 +	}
 +
 +	if (priv->add_button != NULL) {
 +		g_object_unref (priv->add_button);
 +		priv->add_button = NULL;
 +	}
 +
 +	if (priv->add_script_button != NULL) {
 +		g_object_unref (priv->add_script_button);
 +		priv->add_script_button = NULL;
 +	}
 +
 +	if (priv->edit_button != NULL) {
 +		g_object_unref (priv->edit_button);
 +		priv->edit_button = NULL;
 +	}
 +
 +	if (priv->remove_button != NULL) {
 +		g_object_unref (priv->remove_button);
 +		priv->remove_button = NULL;
 +	}
 +
 +	/* Chain up to parent's dispose() method. */
 +	G_OBJECT_CLASS (parent_class)->dispose (object);
 +}
 +
 +static void
 +signature_manager_add_signature (ESignatureManager *manager)
 +{
 +	ESignatureTreeView *tree_view;
 +	GtkWidget *editor;
 +
 +	tree_view = e_signature_manager_get_tree_view (manager);
 +
 +	editor = e_signature_editor_new ();
 +	gtkhtml_editor_set_html_mode (
 +		GTKHTML_EDITOR (editor), manager->priv->prefer_html);
 +	signature_manager_emit_editor_created (manager, editor);
 +
 +	gtk_widget_grab_focus (GTK_WIDGET (tree_view));
 +}
 +
 +static void
 +signature_manager_add_signature_script (ESignatureManager *manager)
 +{
 +	ESignatureTreeView *tree_view;
 +	ESignatureList *signature_list;
 +	ESignature *signature;
 +	const gchar *title;
 +
 +	title = _("Add Signature Script");
 +	tree_view = e_signature_manager_get_tree_view (manager);
 +	signature_list = e_signature_manager_get_signature_list (manager);
 +
 +	signature = e_signature_new ();
 +	signature->script = TRUE;
 +	signature->html = TRUE;
 +
 +	if (signature_manager_run_script_dialog (manager, signature, title))
 +		e_signature_list_add (signature_list, signature);
 +
 +	e_signature_list_save (signature_list);
 +	g_object_unref (signature);
 +
 +	gtk_widget_grab_focus (GTK_WIDGET (tree_view));
 +}
 +
 +static void
 +signature_manager_editor_created (ESignatureManager *manager,
 +                                  ESignatureEditor *editor)
 +{
 +	GtkWindowPosition position;
 +	gpointer parent;
 +
 +	position = GTK_WIN_POS_CENTER_ON_PARENT;
 +	parent = gtk_widget_get_toplevel (GTK_WIDGET (manager));
 +	parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL;
 +
 +	gtk_window_set_transient_for (GTK_WINDOW (editor), parent);
 +	gtk_window_set_position (GTK_WINDOW (editor), position);
 +	gtk_widget_show (GTK_WIDGET (editor));
 +}
 +
 +static void
 +signature_manager_edit_signature (ESignatureManager *manager)
 +{
 +	ESignatureTreeView *tree_view;
 +	ESignatureList *signature_list;
 +	ESignature *signature;
 +	GtkWidget *editor;
 +	const gchar *title;
 +	gchar *filename;
 +
 +	tree_view = e_signature_manager_get_tree_view (manager);
 +	signature = e_signature_tree_view_get_selected (tree_view);
 +	signature_list = e_signature_manager_get_signature_list (manager);
 +
 +	if (signature == NULL)
 +		return;
 +
 +	if (signature->script)
 +		goto script;
 +
 +	filename = signature->filename;
 +	if (filename == NULL || *filename == '\0') {
 +		g_free (filename);
 +		filename = g_strdup (_("Unnamed"));
 +		signature->filename = filename;
 +	}
 +
 +	editor = e_signature_editor_new ();
 +	e_signature_editor_set_signature (
 +		E_SIGNATURE_EDITOR (editor), signature);
 +	signature_manager_emit_editor_created (manager, editor);
 +
 +	goto exit;
 +
 +script:
 +	title = _("Edit Signature Script");
 +
 +	if (signature_manager_run_script_dialog (manager, signature, title))
 +		e_signature_list_change (signature_list, signature);
 +
 +	e_signature_list_save (signature_list);
 +
 +exit:
 +	gtk_widget_grab_focus (GTK_WIDGET (tree_view));
 +
 +	g_object_unref (signature);
 +}
 +
 +static void
 +signature_manager_remove_signature (ESignatureManager *manager)
 +{
 +	ESignatureTreeView *tree_view;
 +	ESignatureList *signature_list;
 +	ESignature *signature;
 +
 +	tree_view = e_signature_manager_get_tree_view (manager);
 +	signature = e_signature_tree_view_get_selected (tree_view);
 +	signature_list = e_signature_tree_view_get_signature_list (tree_view);
 +
 +	if (signature == NULL)
 +		return;
 +
 +	if (signature->filename != NULL && !signature->script)
 +		g_unlink (signature->filename);
 +
 +	e_signature_list_remove (signature_list, signature);
 +	e_signature_list_save (signature_list);
 +
 +	gtk_widget_grab_focus (GTK_WIDGET (tree_view));
 +}
 +
 +static void
 +signature_manager_class_init (ESignatureManagerClass *class)
 +{
 +	GObjectClass *object_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (ESignatureManagerPrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->set_property = signature_manager_set_property;
 +	object_class->get_property = signature_manager_get_property;
 +	object_class->dispose = signature_manager_dispose;
 +
 +	class->add_signature = signature_manager_add_signature;
 +	class->add_signature_script = signature_manager_add_signature_script;
 +	class->editor_created = signature_manager_editor_created;
 +	class->edit_signature = signature_manager_edit_signature;
 +	class->remove_signature = signature_manager_remove_signature;
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_ALLOW_SCRIPTS,
 +		g_param_spec_boolean (
 +			"allow-scripts",
 +			"Allow Scripts",
 +			NULL,
 +			TRUE,
 +			G_PARAM_READWRITE |
 +			G_PARAM_CONSTRUCT));
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_PREFER_HTML,
 +		g_param_spec_boolean (
 +			"prefer-html",
 +			"Prefer HTML",
 +			NULL,
 +			TRUE,
 +			G_PARAM_READWRITE |
 +			G_PARAM_CONSTRUCT));
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_SIGNATURE_LIST,
 +		g_param_spec_object (
 +			"signature-list",
 +			"Signature List",
 +			NULL,
 +			E_TYPE_SIGNATURE_LIST,
 +			G_PARAM_READWRITE |
 +			G_PARAM_CONSTRUCT));
 +
 +	signals[ADD_SIGNATURE] = g_signal_new (
 +		"add-signature",
 +		G_OBJECT_CLASS_TYPE (class),
 +		G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
 +		G_STRUCT_OFFSET (ESignatureManagerClass, add_signature),
 +		NULL, NULL,
 +		g_cclosure_marshal_VOID__VOID,
 +		G_TYPE_NONE, 0);
 +
 +	signals[ADD_SIGNATURE_SCRIPT] = g_signal_new (
 +		"add-signature-script",
 +		G_OBJECT_CLASS_TYPE (class),
 +		G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
 +		G_STRUCT_OFFSET (ESignatureManagerClass, add_signature_script),
 +		NULL, NULL,
 +		g_cclosure_marshal_VOID__VOID,
 +		G_TYPE_NONE, 0);
 +
 +	signals[EDITOR_CREATED] = g_signal_new (
 +		"editor-created",
 +		G_OBJECT_CLASS_TYPE (class),
 +		G_SIGNAL_RUN_LAST,
 +		G_STRUCT_OFFSET (ESignatureManagerClass, editor_created),
 +		NULL, NULL,
 +		g_cclosure_marshal_VOID__OBJECT,
 +		G_TYPE_NONE, 1,
 +		E_TYPE_SIGNATURE_EDITOR);
 +
 +	signals[EDIT_SIGNATURE] = g_signal_new (
 +		"edit-signature",
 +		G_OBJECT_CLASS_TYPE (class),
 +		G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
 +		G_STRUCT_OFFSET (ESignatureManagerClass, edit_signature),
 +		NULL, NULL,
 +		g_cclosure_marshal_VOID__VOID,
 +		G_TYPE_NONE, 0);
 +
 +	signals[REMOVE_SIGNATURE] = g_signal_new (
 +		"remove-signature",
 +		G_OBJECT_CLASS_TYPE (class),
 +		G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
 +		G_STRUCT_OFFSET (ESignatureManagerClass, remove_signature),
 +		NULL, NULL,
 +		g_cclosure_marshal_VOID__VOID,
 +		G_TYPE_NONE, 0);
 +}
 +
 +static void
 +signature_manager_init (ESignatureManager *manager)
 +{
 +	GtkTreeSelection *selection;
 +	GtkWidget *container;
 +	GtkWidget *widget;
 +
 +	manager->priv = E_SIGNATURE_MANAGER_GET_PRIVATE (manager);
 +
 +	gtk_table_resize (GTK_TABLE (manager), 1, 2);
 +	gtk_table_set_col_spacings (GTK_TABLE (manager), 6);
 +	gtk_table_set_row_spacings (GTK_TABLE (manager), 12);
 +
 +	container = GTK_WIDGET (manager);
 +
 +	widget = gtk_scrolled_window_new (NULL, NULL);
 +	gtk_scrolled_window_set_policy (
 +		GTK_SCROLLED_WINDOW (widget),
 +		GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
 +	gtk_scrolled_window_set_shadow_type (
 +		GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
 +	gtk_table_attach (
 +		GTK_TABLE (container), widget, 0, 1, 0, 1,
 +		GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
 +	gtk_widget_show (widget);
 +
 +	container = widget;
 +
 +	widget = e_signature_tree_view_new ();
 +	gtk_container_add (GTK_CONTAINER (container), widget);
 +	manager->priv->tree_view = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	e_mutual_binding_new (
 +		G_OBJECT (manager), "signature-list",
 +		G_OBJECT (widget), "signature-list");
 +
 +	g_signal_connect_swapped (
 +		widget, "key-press-event",
 +		G_CALLBACK (signature_manager_key_press_event_cb),
 +		manager);
 +
 +	g_signal_connect_swapped (
 +		widget, "row-activated",
 +		G_CALLBACK (e_signature_manager_edit_signature),
 +		manager);
 +
 +	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
 +
 +	g_signal_connect_swapped (
 +		selection, "changed",
 +		G_CALLBACK (signature_manager_selection_changed_cb),
 +		manager);
 +
 +	container = GTK_WIDGET (manager);
 +
 +	widget = gtk_vbutton_box_new ();
 +	gtk_button_box_set_layout (
 +		GTK_BUTTON_BOX (widget), GTK_BUTTONBOX_START);
 +	gtk_box_set_spacing (GTK_BOX (widget), 6);
 +	gtk_table_attach (
 +		GTK_TABLE (container), widget,
 +		1, 2, 0, 2, 0, GTK_FILL, 0, 0);
 +	gtk_widget_show (widget);
 +
 +	container = widget;
 +
 +	widget = gtk_button_new_from_stock (GTK_STOCK_ADD);
 +	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
 +	manager->priv->add_button = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	g_signal_connect_swapped (
 +		widget, "clicked",
 +		G_CALLBACK (e_signature_manager_add_signature),
 +		manager);
 +
 +	widget = gtk_button_new_with_mnemonic (_("Add _Script"));
 +	gtk_button_set_image (
 +		GTK_BUTTON (widget), gtk_image_new_from_stock (
 +		GTK_STOCK_EXECUTE, GTK_ICON_SIZE_BUTTON));
 +	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
 +	manager->priv->add_script_button = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	e_binding_new (
 +		G_OBJECT (manager), "allow-scripts",
 +		G_OBJECT (widget), "sensitive");
 +
 +	g_signal_connect_swapped (
 +		widget, "clicked",
 +		G_CALLBACK (e_signature_manager_add_signature_script),
 +		manager);
 +
 +	widget = gtk_button_new_from_stock (GTK_STOCK_EDIT);
 +	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
 +	manager->priv->edit_button = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	g_signal_connect_swapped (
 +		widget, "clicked",
 +		G_CALLBACK (e_signature_manager_edit_signature),
 +		manager);
 +
 +	widget = gtk_button_new_from_stock (GTK_STOCK_REMOVE);
 +	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
 +	manager->priv->remove_button = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	g_signal_connect_swapped (
 +		widget, "clicked",
 +		G_CALLBACK (e_signature_manager_remove_signature),
 +		manager);
 +}
 +
 +GType
 +e_signature_manager_get_type (void)
 +{
 +	static GType type = 0;
 +
 +	if (G_UNLIKELY (type == 0)) {
 +		static const GTypeInfo type_info = {
 +			sizeof (ESignatureManagerClass),
 +			(GBaseInitFunc) NULL,
 +			(GBaseFinalizeFunc) NULL,
 +			(GClassInitFunc) signature_manager_class_init,
 +			(GClassFinalizeFunc) NULL,
 +			NULL,  /* class_init */
 +			sizeof (ESignatureManager),
 +			0,     /* n_preallocs */
 +			(GInstanceInitFunc) signature_manager_init,
 +			NULL   /* value_table */
 +		};
 +
 +		type = g_type_register_static (
 +			GTK_TYPE_TABLE, "ESignatureManager", &type_info, 0);
 +	}
 +
 +	return type;
 +}
 +
 +GtkWidget *
 +e_signature_manager_new (ESignatureList *signature_list)
 +{
 +	g_return_val_if_fail (E_IS_SIGNATURE_LIST (signature_list), NULL);
 +
 +	return g_object_new (
 +		E_TYPE_SIGNATURE_MANAGER,
 +		"signature-list", signature_list, NULL);
 +}
 +
 +void
 +e_signature_manager_add_signature (ESignatureManager *manager)
 +{
 +	g_return_if_fail (E_IS_SIGNATURE_MANAGER (manager));
 +
 +	g_signal_emit (manager, signals[ADD_SIGNATURE], 0);
 +}
 +
 +void
 +e_signature_manager_add_signature_script (ESignatureManager *manager)
 +{
 +	g_return_if_fail (E_IS_SIGNATURE_MANAGER (manager));
 +
 +	g_signal_emit (manager, signals[ADD_SIGNATURE_SCRIPT], 0);
 +}
 +
 +void
 +e_signature_manager_edit_signature (ESignatureManager *manager)
 +{
 +	g_return_if_fail (E_IS_SIGNATURE_MANAGER (manager));
 +
 +	g_signal_emit (manager, signals[EDIT_SIGNATURE], 0);
 +}
 +
 +void
 +e_signature_manager_remove_signature (ESignatureManager *manager)
 +{
 +	g_return_if_fail (E_IS_SIGNATURE_MANAGER (manager));
 +
 +	g_signal_emit (manager, signals[REMOVE_SIGNATURE], 0);
 +}
 +
 +gboolean
 +e_signature_manager_get_allow_scripts (ESignatureManager *manager)
 +{
 +	g_return_val_if_fail (E_IS_SIGNATURE_MANAGER (manager), FALSE);
 +
 +	return manager->priv->allow_scripts;
 +}
 +
 +void
 +e_signature_manager_set_allow_scripts (ESignatureManager *manager,
 +                                       gboolean allow_scripts)
 +{
 +	g_return_if_fail (E_IS_SIGNATURE_MANAGER (manager));
 +
 +	manager->priv->allow_scripts = allow_scripts;
 +
 +	g_object_notify (G_OBJECT (manager), "allow-scripts");
 +}
 +
 +gboolean
 +e_signature_manager_get_prefer_html (ESignatureManager *manager)
 +{
 +	g_return_val_if_fail (E_IS_SIGNATURE_MANAGER (manager), FALSE);
 +
 +	return manager->priv->prefer_html;
 +}
 +
 +void
 +e_signature_manager_set_prefer_html (ESignatureManager *manager,
 +                                     gboolean prefer_html)
 +{
 +	g_return_if_fail (E_IS_SIGNATURE_MANAGER (manager));
 +
 +	manager->priv->prefer_html = prefer_html;
 +
 +	g_object_notify (G_OBJECT (manager), "prefer-html");
 +}
 +
 +ESignatureList *
 +e_signature_manager_get_signature_list (ESignatureManager *manager)
 +{
 +	g_return_val_if_fail (E_IS_SIGNATURE_MANAGER (manager), NULL);
 +
 +	return manager->priv->signature_list;
 +}
 +
 +void
 +e_signature_manager_set_signature_list (ESignatureManager *manager,
 +                                        ESignatureList *signature_list)
 +{
 +	g_return_if_fail (E_IS_SIGNATURE_MANAGER (manager));
 +
 +	if (signature_list != NULL) {
 +		g_return_if_fail (E_IS_SIGNATURE_LIST (signature_list));
 +		g_object_ref (signature_list);
 +	}
 +
 +	if (manager->priv->signature_list != NULL)
 +		g_object_unref (manager->priv->signature_list);
 +
 +	manager->priv->signature_list = signature_list;
 +
 +	g_object_notify (G_OBJECT (manager), "signature-list");
 +}
 +
 +ESignatureTreeView *
 +e_signature_manager_get_tree_view (ESignatureManager *manager)
 +{
 +	g_return_val_if_fail (E_IS_SIGNATURE_MANAGER (manager), NULL);
 +
 +	return E_SIGNATURE_TREE_VIEW (manager->priv->tree_view);
 +}
diff --cc widgets/misc/e-signature-manager.h
index f00ad14,0000000..662836e
mode 100644,000000..100644
--- a/widgets/misc/e-signature-manager.h
+++ b/widgets/misc/e-signature-manager.h
@@@ -1,100 -1,0 +1,100 @@@
 +/*
 + * e-signature-manager.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_SIGNATURE_MANAGER_H
 +#define E_SIGNATURE_MANAGER_H
 +
 +#include <gtk/gtk.h>
 +#include <e-util/e-signature-list.h>
 +#include <misc/e-signature-editor.h>
 +#include <misc/e-signature-tree-view.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_SIGNATURE_MANAGER \
 +	(e_signature_manager_get_type ())
 +#define E_SIGNATURE_MANAGER(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_SIGNATURE_MANAGER, ESignatureManager))
 +#define E_SIGNATURE_MANAGER_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_SIGNATURE_MANAGER, ESignatureManagerClass))
 +#define E_IS_SIGNATURE_MANAGER(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_SIGNATURE_MANAGER))
 +#define E_IS_SIGNATURE_MANAGER_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), E_TYPE_SIGNATURE_MANAGER))
 +#define E_SIGNATURE_MANAGER_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_SIGNATURE_MANAGER, ESignatureManagerClass))
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _ESignatureManager ESignatureManager;
 +typedef struct _ESignatureManagerClass ESignatureManagerClass;
 +typedef struct _ESignatureManagerPrivate ESignatureManagerPrivate;
 +
 +struct _ESignatureManager {
 +	GtkTable parent;
 +	ESignatureManagerPrivate *priv;
 +};
 +
 +struct _ESignatureManagerClass {
 +	GtkTableClass parent_class;
 +
 +	void		(*add_signature)	(ESignatureManager *manager);
 +	void		(*add_signature_script)	(ESignatureManager *manager);
 +	void		(*editor_created)	(ESignatureManager *manager,
 +						 ESignatureEditor *editor);
 +	void		(*edit_signature)	(ESignatureManager *manager);
 +	void		(*remove_signature)	(ESignatureManager *manager);
 +};
 +
 +GType		e_signature_manager_get_type	(void);
 +GtkWidget *	e_signature_manager_new		(ESignatureList *signature_list);
 +void		e_signature_manager_add_signature
 +						(ESignatureManager *manager);
 +void		e_signature_manager_add_signature_script
 +						(ESignatureManager *manager);
 +void		e_signature_manager_edit_signature
 +						(ESignatureManager *manager);
 +void		e_signature_manager_remove_signature
 +						(ESignatureManager *manager);
 +gboolean	e_signature_manager_get_allow_scripts
 +						(ESignatureManager *manager);
 +void		e_signature_manager_set_allow_scripts
 +						(ESignatureManager *manager,
 +						 gboolean allow_scripts);
 +gboolean	e_signature_manager_get_prefer_html
 +						(ESignatureManager *manager);
 +void		e_signature_manager_set_prefer_html
 +						(ESignatureManager *manager,
 +						 gboolean prefer_html);
 +ESignatureList *e_signature_manager_get_signature_list
 +						(ESignatureManager *manager);
 +void		e_signature_manager_set_signature_list
 +						(ESignatureManager *manager,
 +						 ESignatureList *signature_list);
 +ESignatureTreeView *
 +		e_signature_manager_get_tree_view
 +						(ESignatureManager *manager);
 +
 +#endif /* E_SIGNATURE_MANAGER_H */
diff --cc widgets/misc/e-signature-preview.c
index d618e05,0000000..f8e168c
mode 100644,000000..100644
--- a/widgets/misc/e-signature-preview.c
+++ b/widgets/misc/e-signature-preview.c
@@@ -1,344 -1,0 +1,344 @@@
 +/*
 + * e-signature-preview.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-signature-preview.h"
 +
 +#include <fcntl.h>
 +#include <string.h>
 +#include <unistd.h>
 +#include <glib/gstdio.h>
 +#include "e-util/e-signature-utils.h"
 +
 +#define E_SIGNATURE_PREVIEW_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_SIGNATURE_PREVIEW, ESignaturePreviewPrivate))
 +
 +enum {
 +	PROP_0,
 +	PROP_ALLOW_SCRIPTS,
 +	PROP_SIGNATURE
 +};
 +
 +enum {
 +	REFRESH,
 +	LAST_SIGNAL
 +};
 +
 +struct _ESignaturePreviewPrivate {
 +	ESignature *signature;
 +	guint allow_scripts : 1;
 +};
 +
 +static gpointer parent_class;
 +static guint signals[LAST_SIGNAL];
 +
 +static void
 +signature_preview_set_property (GObject *object,
 +                                guint property_id,
 +                                const GValue *value,
 +                                GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_ALLOW_SCRIPTS:
 +			e_signature_preview_set_allow_scripts (
 +				E_SIGNATURE_PREVIEW (object),
 +				g_value_get_boolean (value));
 +			return;
 +
 +		case PROP_SIGNATURE:
 +			e_signature_preview_set_signature (
 +				E_SIGNATURE_PREVIEW (object),
 +				g_value_get_object (value));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +signature_preview_get_property (GObject *object,
 +                                guint property_id,
 +                                GValue *value,
 +                                GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_ALLOW_SCRIPTS:
 +			g_value_set_boolean (
 +				value, e_signature_preview_get_allow_scripts (
 +				E_SIGNATURE_PREVIEW (object)));
 +			return;
 +
 +		case PROP_SIGNATURE:
 +			g_value_set_object (
 +				value, e_signature_preview_get_signature (
 +				E_SIGNATURE_PREVIEW (object)));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +signature_preview_dispose (GObject *object)
 +{
 +	ESignaturePreviewPrivate *priv;
 +
 +	priv = E_SIGNATURE_PREVIEW_GET_PRIVATE (object);
 +
 +	if (priv->signature != NULL) {
 +		g_object_unref (priv->signature);
 +		priv->signature = NULL;
 +	}
 +
 +	/* Chain up to parent's dispose() method. */
 +	G_OBJECT_CLASS (parent_class)->dispose (object);
 +}
 +
 +static void
 +signature_preview_url_requested (GtkHTML *html,
 +                                 const gchar *url,
 +                                 GtkHTMLStream *handle)
 +{
 +	GtkHTMLStreamStatus status;
 +	gchar buffer[128];
 +	gchar *filename;
 +	gssize size;
 +	gint fd;
 +
 +	/* FIXME Use GInputStream for this. */
 +
 +	if (g_str_has_prefix (url, "file:"))
 +		filename = g_filename_from_uri (url, NULL, NULL);
 +	else
 +		filename = g_strdup (url);
 +	fd = g_open (filename, O_RDONLY, 0);
 +	g_free (filename);
 +
 +	status = GTK_HTML_STREAM_OK;
 +	if (fd != -1) {
 +		while ((size = read (fd, buffer, sizeof (buffer)))) {
 +			if (size == -1) {
 +				status = GTK_HTML_STREAM_ERROR;
 +				break;
 +			} else
 +				gtk_html_write (html, handle, buffer, size);
 +		}
 +	} else
 +		status = GTK_HTML_STREAM_ERROR;
 +
 +	gtk_html_end (html, handle, status);
 +
 +	if (fd > 0)
 +		close (fd);
 +}
 +
 +static void
 +signature_preview_refresh (ESignaturePreview *preview)
 +{
 +	GtkHTML *html;
 +	ESignature *signature;
 +	gchar *content = NULL;
 +	gsize length;
 +
 +	/* XXX We should show error messages in the preview. */
 +
 +	html = GTK_HTML (preview);
 +	signature = e_signature_preview_get_signature (preview);
 +
 +	if (signature == NULL)
 +		goto clear;
 +
 +	if (signature->script && !preview->priv->allow_scripts)
 +		goto clear;
 +
 +	if (signature->script)
 +		content = e_run_signature_script (signature->filename);
 +	else
 +		content = e_read_signature_file (signature, FALSE, NULL);
 +
 +	if (content == NULL || *content == '\0')
 +		goto clear;
 +
 +	length = strlen (content);
 +
 +	if (signature->html)
 +		gtk_html_load_from_string (html, content, length);
 +	else {
 +		GtkHTMLStream *stream;
 +
 +		stream = gtk_html_begin_content (
 +			html, "text/html; charset=utf-8");
 +		gtk_html_write (html, stream, "<PRE>", 5);
 +		if (length > 0)
 +			gtk_html_write (html, stream, content, length);
 +		gtk_html_write (html, stream, "</PRE>", 6);
 +		gtk_html_end (html, stream, GTK_HTML_STREAM_OK);
 +	}
 +
 +	g_free (content);
 +	return;
 +
 +clear:
 +	gtk_html_load_from_string (html, " ", 1);
 +	g_free (content);
 +}
 +
 +static void
 +signature_preview_class_init (ESignaturePreviewClass *class)
 +{
 +	GObjectClass *object_class;
 +	GtkHTMLClass *html_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (ESignaturePreviewPrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->set_property = signature_preview_set_property;
 +	object_class->get_property = signature_preview_get_property;
 +	object_class->dispose = signature_preview_dispose;
 +
 +	html_class = GTK_HTML_CLASS (class);
 +	html_class->url_requested = signature_preview_url_requested;
 +
 +	class->refresh = signature_preview_refresh;
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_ALLOW_SCRIPTS,
 +		g_param_spec_boolean (
 +			"allow-scripts",
 +			"Allow Scripts",
 +			NULL,
 +			TRUE,
 +			G_PARAM_READWRITE |
 +			G_PARAM_CONSTRUCT));
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_SIGNATURE,
 +		g_param_spec_object (
 +			"signature",
 +			"Signature",
 +			NULL,
 +			E_TYPE_SIGNATURE,
 +			G_PARAM_READWRITE));
 +
 +	signals[REFRESH] = g_signal_new (
 +		"refresh",
 +		G_TYPE_FROM_CLASS (class),
 +		G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
 +		G_STRUCT_OFFSET (ESignaturePreviewClass, refresh),
 +		NULL, NULL,
 +		g_cclosure_marshal_VOID__VOID,
 +		G_TYPE_NONE, 0);
 +}
 +
 +static void
 +signature_preview_init (ESignaturePreview *preview)
 +{
 +	preview->priv = E_SIGNATURE_PREVIEW_GET_PRIVATE (preview);
 +}
 +
 +GType
 +e_signature_preview_get_type (void)
 +{
 +	static GType type = 0;
 +
 +	if (G_UNLIKELY (type == 0)) {
 +		static const GTypeInfo type_info = {
 +			sizeof (ESignaturePreviewClass),
 +			(GBaseInitFunc) NULL,
 +			(GBaseFinalizeFunc) NULL,
 +			(GClassInitFunc) signature_preview_class_init,
 +			(GClassFinalizeFunc) NULL,
 +			NULL,  /* class_data */
 +			sizeof (ESignaturePreview),
 +			0,     /* n_preallocs */
 +			(GInstanceInitFunc) signature_preview_init,
 +			NULL   /* value_table */
 +		};
 +
 +		type = g_type_register_static (
 +			GTK_TYPE_HTML, "ESignaturePreview", &type_info, 0);
 +	}
 +
 +	return type;
 +}
 +
 +GtkWidget *
 +e_signature_preview_new (void)
 +{
 +	return g_object_new (E_TYPE_SIGNATURE_PREVIEW, NULL);
 +}
 +
 +void
 +e_signature_preview_refresh (ESignaturePreview *preview)
 +{
 +	g_return_if_fail (E_IS_SIGNATURE_PREVIEW (preview));
 +
 +	g_signal_emit (preview, signals[REFRESH], 0);
 +}
 +
 +gboolean
 +e_signature_preview_get_allow_scripts (ESignaturePreview *preview)
 +{
 +	g_return_val_if_fail (E_IS_SIGNATURE_PREVIEW (preview), FALSE);
 +
 +	return preview->priv->allow_scripts;
 +}
 +
 +void
 +e_signature_preview_set_allow_scripts (ESignaturePreview *preview,
 +                                       gboolean allow_scripts)
 +{
 +	g_return_if_fail (E_IS_SIGNATURE_PREVIEW (preview));
 +
 +	preview->priv->allow_scripts = allow_scripts;
 +	g_object_notify (G_OBJECT (preview), "allow-scripts");
 +}
 +
 +ESignature *
 +e_signature_preview_get_signature (ESignaturePreview *preview)
 +{
 +	g_return_val_if_fail (E_IS_SIGNATURE_PREVIEW (preview), NULL);
 +
 +	return preview->priv->signature;
 +}
 +
 +void
 +e_signature_preview_set_signature (ESignaturePreview *preview,
 +                                   ESignature *signature)
 +{
 +	g_return_if_fail (E_IS_SIGNATURE_PREVIEW (preview));
 +
 +	if (signature != NULL) {
 +		g_return_if_fail (E_IS_SIGNATURE (signature));
 +		g_object_ref (signature);
 +	}
 +
 +	if (preview->priv->signature != NULL)
 +		g_object_unref (preview->priv->signature);
 +
 +	preview->priv->signature = signature;
 +	g_object_notify (G_OBJECT (preview), "signature");
 +
 +	e_signature_preview_refresh (preview);
 +}
diff --cc widgets/misc/e-signature-preview.h
index 2cedcc1,0000000..a422183
mode 100644,000000..100644
--- a/widgets/misc/e-signature-preview.h
+++ b/widgets/misc/e-signature-preview.h
@@@ -1,81 -1,0 +1,81 @@@
 +/*
 + * e-signature-preview.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_SIGNATURE_PREVIEW_H
 +#define E_SIGNATURE_PREVIEW_H
 +
 +#include <gtkhtml/gtkhtml.h>
 +#include <e-util/e-signature.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_SIGNATURE_PREVIEW \
 +	(e_signature_preview_get_type ())
 +#define E_SIGNATURE_PREVIEW(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_SIGNATURE_PREVIEW, ESignaturePreview))
 +#define E_SIGNATURE_PREVIEW_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_SIGNATURE_PREVIEW, ESignaturePreviewClass))
 +#define E_IS_SIGNATURE_PREVIEW(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_SIGNATURE_PREVIEW))
 +#define E_IS_SIGNATURE_PREVIEW_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), E_TYPE_SIGNATURE_PREVIEW))
 +#define E_SIGNATURE_PREVIEW_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_SIGNATURE_PREVIEW, ESignaturePreview))
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _ESignaturePreview ESignaturePreview;
 +typedef struct _ESignaturePreviewClass ESignaturePreviewClass;
 +typedef struct _ESignaturePreviewPrivate ESignaturePreviewPrivate;
 +
 +struct _ESignaturePreview {
 +	GtkHTML parent;
 +	ESignaturePreviewPrivate *priv;
 +};
 +
 +struct _ESignaturePreviewClass {
 +	GtkHTMLClass parent_class;
 +
 +	/* Signals */
 +	void		(*refresh)		(ESignaturePreview *preview);
 +};
 +
 +GType		e_signature_preview_get_type	(void);
 +GtkWidget *	e_signature_preview_new		(void);
 +void		e_signature_preview_refresh	(ESignaturePreview *preview);
 +gboolean	e_signature_preview_get_allow_scripts
 +						(ESignaturePreview *preview);
 +void		e_signature_preview_set_allow_scripts
 +						(ESignaturePreview *preview,
 +						 gboolean allow_scripts);
 +ESignature *	e_signature_preview_get_signature
 +						(ESignaturePreview *preview);
 +void		e_signature_preview_set_signature
 +						(ESignaturePreview *preview,
 +						 ESignature *signature);
 +
 +G_END_DECLS
 +
 +#endif /* E_SIGNATURE_PREVIEW_H */
diff --cc widgets/misc/e-signature-script-dialog.c
index 06e021b,0000000..777d064
mode 100644,000000..100644
--- a/widgets/misc/e-signature-script-dialog.c
+++ b/widgets/misc/e-signature-script-dialog.c
@@@ -1,463 -1,0 +1,463 @@@
 +/*
 + * e-signature-script-dialog.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-signature-script-dialog.h"
 +
 +#include <glib/gi18n.h>
 +#include "e-util/e-binding.h"
 +
 +#define E_SIGNATURE_SCRIPT_DIALOG_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_SIGNATURE_SCRIPT_DIALOG, ESignatureScriptDialogPrivate))
 +
 +struct _ESignatureScriptDialogPrivate {
 +	GtkWidget *entry;
 +	GtkWidget *file_chooser;
 +	GtkWidget *alert;
 +};
 +
 +enum {
 +	PROP_0,
 +	PROP_SCRIPT_FILE,
 +	PROP_SCRIPT_NAME
 +};
 +
 +static gpointer parent_class;
 +
 +static gboolean
 +signature_script_dialog_filter_cb (const GtkFileFilterInfo *filter_info)
 +{
 +	const gchar *filename = filter_info->filename;
 +
 +	return g_file_test (filename, G_FILE_TEST_IS_EXECUTABLE);
 +}
 +
 +static void
 +signature_script_dialog_update_status (ESignatureScriptDialog *dialog)
 +{
 +	GFile *script_file;
 +	const gchar *script_name;
 +	gboolean show_alert;
 +	gboolean sensitive;
 +
 +	script_file = e_signature_script_dialog_get_script_file (dialog);
 +	script_name = e_signature_script_dialog_get_script_name (dialog);
 +
 +	sensitive = (script_name != NULL && *script_name != '\0');
 +
 +	if (script_file != NULL) {
 +		gboolean executable;
 +		gchar *filename;
 +
 +		filename = g_file_get_path (script_file);
 +		executable = g_file_test (filename, G_FILE_TEST_IS_EXECUTABLE);
 +		g_free (filename);
 +
 +		show_alert = !executable;
 +		sensitive &= executable;
 +
 +		g_object_unref (script_file);
 +	} else {
 +		sensitive = FALSE;
 +		show_alert = FALSE;
 +	}
 +
 +	if (show_alert)
 +		gtk_widget_show (dialog->priv->alert);
 +	else
 +		gtk_widget_hide (dialog->priv->alert);
 +
 +	gtk_dialog_set_response_sensitive (
 +		GTK_DIALOG (dialog), GTK_RESPONSE_OK, sensitive);
 +}
 +
 +static void
 +signature_script_dialog_set_property (GObject *object,
 +                                      guint property_id,
 +                                      const GValue *value,
 +                                      GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_SCRIPT_FILE:
 +			e_signature_script_dialog_set_script_file (
 +				E_SIGNATURE_SCRIPT_DIALOG (object),
 +				g_value_get_object (value));
 +			return;
 +
 +		case PROP_SCRIPT_NAME:
 +			e_signature_script_dialog_set_script_name (
 +				E_SIGNATURE_SCRIPT_DIALOG (object),
 +				g_value_get_string (value));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +signature_script_dialog_get_property (GObject *object,
 +                                      guint property_id,
 +                                      GValue *value,
 +                                      GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_SCRIPT_FILE:
 +			g_value_set_object (
 +				value,
 +				e_signature_script_dialog_get_script_file (
 +				E_SIGNATURE_SCRIPT_DIALOG (object)));
 +			return;
 +
 +		case PROP_SCRIPT_NAME:
 +			g_value_set_string (
 +				value,
 +				e_signature_script_dialog_get_script_name (
 +				E_SIGNATURE_SCRIPT_DIALOG (object)));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +signature_script_dialog_dispose (GObject *object)
 +{
 +	ESignatureScriptDialogPrivate *priv;
 +
 +	priv = E_SIGNATURE_SCRIPT_DIALOG_GET_PRIVATE (object);
 +
 +	if (priv->entry != NULL) {
 +		g_object_unref (priv->entry);
 +		priv->entry = NULL;
 +	}
 +
 +	if (priv->file_chooser != NULL) {
 +		g_object_unref (priv->file_chooser);
 +		priv->file_chooser = NULL;
 +	}
 +
 +	if (priv->alert != NULL) {
 +		g_object_unref (priv->alert);
 +		priv->alert = NULL;
 +	}
 +
 +	/* Chain up to parent's dispose() method. */
 +	G_OBJECT_CLASS (parent_class)->dispose (object);
 +}
 +
 +static void
 +signature_script_dialog_map (GtkWidget *widget)
 +{
 +	GtkWidget *action_area;
 +	GtkWidget *content_area;
 +
 +	/* Chain up to parent's map() method. */
 +	GTK_WIDGET_CLASS (parent_class)->map (widget);
 +
 +	/* XXX Override GtkDialog's broken style property defaults. */
 +	action_area = gtk_dialog_get_action_area (GTK_DIALOG (widget));
 +	content_area = gtk_dialog_get_content_area (GTK_DIALOG (widget));
 +
 +	gtk_box_set_spacing (GTK_BOX (content_area), 12);
 +	gtk_container_set_border_width (GTK_CONTAINER (action_area), 0);
 +	gtk_container_set_border_width (GTK_CONTAINER (content_area), 12);
 +}
 +
 +static void
 +signature_script_dialog_class_init (ESignatureScriptDialogClass *class)
 +{
 +	GObjectClass *object_class;
 +	GtkWidgetClass *widget_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (ESignatureScriptDialogPrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->set_property = signature_script_dialog_set_property;
 +	object_class->get_property = signature_script_dialog_get_property;
 +	object_class->dispose = signature_script_dialog_dispose;
 +
 +	widget_class = GTK_WIDGET_CLASS (class);
 +	widget_class->map = signature_script_dialog_map;
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_SCRIPT_FILE,
 +		g_param_spec_object (
 +			"script-file",
 +			"Script File",
 +			NULL,
 +			G_TYPE_FILE,
 +			G_PARAM_READWRITE));
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_SCRIPT_NAME,
 +		g_param_spec_string (
 +			"script-name",
 +			"Script Name",
 +			NULL,
 +			_("Unnamed"),
 +			G_PARAM_READWRITE |
 +			G_PARAM_CONSTRUCT));
 +}
 +
 +static void
 +signature_script_dialog_init (ESignatureScriptDialog *dialog)
 +{
 +	GtkFileFilter *filter;
 +	GtkWidget *content_area;
 +	GtkWidget *container;
 +	GtkWidget *widget;
 +	gchar *markup;
 +
 +	dialog->priv = E_SIGNATURE_SCRIPT_DIALOG_GET_PRIVATE (dialog);
 +
 +	content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
 +
 +	gtk_dialog_add_button (
 +		GTK_DIALOG (dialog),
 +		GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
 +
 +	gtk_dialog_add_button (
 +		GTK_DIALOG (dialog),
 +		GTK_STOCK_SAVE, GTK_RESPONSE_OK);
 +
 +	gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
 +	gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
 +
 +	container = content_area;
 +
 +	widget = gtk_table_new (4, 2, FALSE);
 +	gtk_table_set_col_spacings (GTK_TABLE (widget), 6);
 +	gtk_table_set_row_spacings (GTK_TABLE (widget), 6);
 +	gtk_table_set_row_spacing (GTK_TABLE (widget), 0, 12);
 +	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
 +	gtk_widget_show (widget);
 +
 +	container = widget;
 +
 +	widget = gtk_image_new_from_stock (
 +		GTK_STOCK_DIALOG_INFO, GTK_ICON_SIZE_DIALOG);
 +	gtk_table_attach (
 +		GTK_TABLE (container), widget,
 +		0, 1, 0, 1, 0, 0, 0, 0);
 +	gtk_widget_show (widget);
 +
 +	widget = gtk_label_new (_(
 +		"The output of this script will be used as your\n"
 +		"signature. The name you specify will be used\n"
 +		"for display purposes only."));
 +	gtk_table_attach (
 +		GTK_TABLE (container), widget,
 +		1, 2, 0, 1, GTK_FILL | GTK_EXPAND, 0, 0, 0);
 +	gtk_widget_show (widget);
 +
 +	widget = gtk_entry_new ();
 +	gtk_entry_set_activates_default (GTK_ENTRY (widget), TRUE);
 +	gtk_table_attach (
 +		GTK_TABLE (container), widget,
 +		1, 2, 1, 2, GTK_FILL | GTK_EXPAND, 0, 0, 0);
 +	dialog->priv->entry = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	widget = gtk_label_new_with_mnemonic (_("_Name:"));
 +	gtk_label_set_mnemonic_widget (
 +		GTK_LABEL (widget), dialog->priv->entry);
 +	gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5);
 +	gtk_table_attach (
 +		GTK_TABLE (container), widget,
 +		0, 1, 1, 2, GTK_FILL, 0, 0, 0);
 +	gtk_widget_show (widget);
 +
 +	widget = gtk_file_chooser_button_new (
 +		NULL, GTK_FILE_CHOOSER_ACTION_OPEN);
 +	gtk_table_attach (
 +		GTK_TABLE (container), widget,
 +		1, 2, 2, 3, GTK_FILL | GTK_EXPAND, 0, 0, 0);
 +	dialog->priv->file_chooser = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	/* Restrict file selection to executable files. */
 +	filter = gtk_file_filter_new ();
 +	gtk_file_filter_add_custom (
 +		filter, GTK_FILE_FILTER_FILENAME,
 +		(GtkFileFilterFunc) signature_script_dialog_filter_cb,
 +		NULL, NULL);
 +	gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (widget), filter);
 +
 +	/* XXX ESignature stores a filename instead of a URI,
 +	 *     so we have to restrict it to local files only. */
 +	gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (widget), TRUE);
 +
 +	widget = gtk_label_new_with_mnemonic (_("S_cript:"));
 +	gtk_label_set_mnemonic_widget (
 +		GTK_LABEL (widget), dialog->priv->file_chooser);
 +	gtk_table_attach (
 +		GTK_TABLE (container), widget,
 +		0, 1, 2, 3, GTK_FILL, 0, 0, 0);
 +	gtk_widget_show (widget);
 +
 +	/* This is just a placeholder. */
 +	widget = gtk_label_new (NULL);
 +	gtk_table_attach (
 +		GTK_TABLE (container), widget,
 +		0, 1, 3, 4, GTK_FILL, 0, 0, 0);
 +	gtk_widget_show (widget);
 +
 +	widget = gtk_hbox_new (FALSE, 6);
 +	gtk_table_attach (
 +		GTK_TABLE (container), widget,
 +		1, 2, 3, 4, 0, 0, 0, 0);
 +	dialog->priv->alert = g_object_ref (widget);
 +	gtk_widget_show (widget);
 +
 +	container = widget;
 +
 +	widget = gtk_image_new_from_stock (
 +		GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_MENU);
 +	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
 +	gtk_widget_show (widget);
 +
 +	markup = g_markup_printf_escaped (
 +		"<small>%s</small>",
 +		_("Script file must be executable."));
 +	widget = gtk_label_new (markup);
 +	gtk_label_set_use_markup (GTK_LABEL (widget), TRUE);
 +	gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
 +	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
 +	gtk_widget_show (widget);
 +	g_free (markup);
 +
 +	g_signal_connect (
 +		dialog, "notify::script-file",
 +		G_CALLBACK (signature_script_dialog_update_status), NULL);
 +
 +	g_signal_connect (
 +		dialog, "notify::script-name",
 +		G_CALLBACK (signature_script_dialog_update_status), NULL);
 +
 +	g_signal_connect_swapped (
 +		dialog->priv->entry, "changed",
 +		G_CALLBACK (signature_script_dialog_update_status), dialog);
 +
 +	g_signal_connect_swapped (
 +		dialog->priv->file_chooser, "file-set",
 +		G_CALLBACK (signature_script_dialog_update_status), dialog);
 +
 +	signature_script_dialog_update_status (dialog);
 +}
 +
 +GType
 +e_signature_script_dialog_get_type (void)
 +{
 +	static GType type = 0;
 +
 +	if (G_UNLIKELY (type == 0)) {
 +		static const GTypeInfo type_info = {
 +			sizeof (ESignatureScriptDialogClass),
 +			(GBaseInitFunc) NULL,
 +			(GBaseFinalizeFunc) NULL,
 +			(GClassInitFunc) signature_script_dialog_class_init,
 +			(GClassFinalizeFunc) NULL,
 +			NULL,  /* class_data */
 +			sizeof (ESignatureScriptDialog),
 +			0,     /* n_preallocs */
 +			(GInstanceInitFunc) signature_script_dialog_init,
 +			NULL   /* value_table */
 +		};
 +
 +		type = g_type_register_static (
 +			GTK_TYPE_DIALOG, "ESignatureScriptDialog",
 +			&type_info, 0);
 +	}
 +
 +	return type;
 +}
 +
 +GtkWidget *
 +e_signature_script_dialog_new (GtkWindow *parent)
 +{
 +	return g_object_new (
 +		E_TYPE_SIGNATURE_SCRIPT_DIALOG,
 +		"transient-for", parent, NULL);
 +}
 +
 +GFile *
 +e_signature_script_dialog_get_script_file (ESignatureScriptDialog *dialog)
 +{
 +	GtkFileChooser *file_chooser;
 +
 +	g_return_val_if_fail (E_IS_SIGNATURE_SCRIPT_DIALOG (dialog), NULL);
 +
 +	file_chooser = GTK_FILE_CHOOSER (dialog->priv->file_chooser);
 +
 +	return gtk_file_chooser_get_file (file_chooser);
 +}
 +
 +void
 +e_signature_script_dialog_set_script_file (ESignatureScriptDialog *dialog,
 +                                           GFile *script_file)
 +{
 +	GtkFileChooser *file_chooser;
 +	GError *error = NULL;
 +
 +	g_return_if_fail (E_IS_SIGNATURE_SCRIPT_DIALOG (dialog));
 +	g_return_if_fail (G_IS_FILE (script_file));
 +
 +	file_chooser = GTK_FILE_CHOOSER (dialog->priv->file_chooser);
 +
 +	if (gtk_file_chooser_set_file (file_chooser, script_file, &error))
 +		g_object_notify (G_OBJECT (dialog), "script-file");
 +	else {
 +		g_warning ("%s", error->message);
 +		g_error_free (error);
 +	}
 +}
 +
 +const gchar *
 +e_signature_script_dialog_get_script_name (ESignatureScriptDialog *dialog)
 +{
 +	GtkEntry *entry;
 +
 +	g_return_val_if_fail (E_IS_SIGNATURE_SCRIPT_DIALOG (dialog), NULL);
 +
 +	entry = GTK_ENTRY (dialog->priv->entry);
 +
 +	return gtk_entry_get_text (entry);
 +}
 +
 +void
 +e_signature_script_dialog_set_script_name (ESignatureScriptDialog *dialog,
 +                                           const gchar *script_name)
 +{
 +	GtkEntry *entry;
 +
 +	g_return_if_fail (E_IS_SIGNATURE_SCRIPT_DIALOG (dialog));
 +
 +	if (script_name == NULL)
 +		script_name = "";
 +
 +	entry = GTK_ENTRY (dialog->priv->entry);
 +	gtk_entry_set_text (entry, script_name);
 +
 +	g_object_notify (G_OBJECT (dialog), "script-name");
 +}
diff --cc widgets/misc/e-signature-script-dialog.h
index 4cd7f05,0000000..3967ae6
mode 100644,000000..100644
--- a/widgets/misc/e-signature-script-dialog.h
+++ b/widgets/misc/e-signature-script-dialog.h
@@@ -1,76 -1,0 +1,76 @@@
 +/*
 + * e-signature-script-dialog.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_SIGNATURE_SCRIPT_DIALOG_H
 +#define E_SIGNATURE_SCRIPT_DIALOG_H
 +
 +#include <gtk/gtk.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_SIGNATURE_SCRIPT_DIALOG \
 +	(e_signature_script_dialog_get_type ())
 +#define E_SIGNATURE_SCRIPT_DIALOG(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_SIGNATURE_SCRIPT_DIALOG, ESignatureScriptDialog))
 +#define E_SIGNATURE_SCRIPT_DIALOG_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_SIGNATURE_SCRIPT_DIALOG, ESignatureScriptDialogClass))
 +#define E_IS_SIGNATURE_SCRIPT_DIALOG(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_SIGNATURE_SCRIPT_DIALOG))
 +#define E_IS_SIGNATURE_SCRIPT_DIALOG_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), E_TYPE_SIGNATURE_SCRIPT_DIALOG))
 +#define E_SIGNATURE_SCRIPT_DIALOG_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_SIGNATURE_SCRIPT_DIALOG, ESignatureScriptDialogClass))
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _ESignatureScriptDialog ESignatureScriptDialog;
 +typedef struct _ESignatureScriptDialogClass ESignatureScriptDialogClass;
 +typedef struct _ESignatureScriptDialogPrivate ESignatureScriptDialogPrivate;
 +
 +struct _ESignatureScriptDialog {
 +	GtkDialog parent;
 +	ESignatureScriptDialogPrivate *priv;
 +};
 +
 +struct _ESignatureScriptDialogClass {
 +	GtkDialogClass parent_class;
 +};
 +
 +GType		e_signature_script_dialog_get_type	(void);
 +GtkWidget *	e_signature_script_dialog_new		(GtkWindow *parent);
 +GFile *		e_signature_script_dialog_get_script_file
 +					(ESignatureScriptDialog *dialog);
 +void		e_signature_script_dialog_set_script_file
 +					(ESignatureScriptDialog *dialog,
 +					 GFile *script_file);
 +const gchar *	e_signature_script_dialog_get_script_name
 +					(ESignatureScriptDialog *dialog);
 +void		e_signature_script_dialog_set_script_name
 +					(ESignatureScriptDialog *dialog,
 +					 const gchar *script_name);
 +
 +G_END_DECLS
 +
 +#endif /* E_SIGNATURE_SCRIPT_DIALOG_H */
diff --cc widgets/misc/e-signature-tree-view.c
index 1f6d75b,0000000..b2cc9d6
mode 100644,000000..100644
--- a/widgets/misc/e-signature-tree-view.c
+++ b/widgets/misc/e-signature-tree-view.c
@@@ -1,445 -1,0 +1,445 @@@
 +/*
 + * e-signature-tree-view.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-signature-tree-view.h"
 +
 +#define E_SIGNATURE_TREE_VIEW_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_SIGNATURE_TREE_VIEW, ESignatureTreeViewPrivate))
 +
 +enum {
 +	COLUMN_STRING,
 +	COLUMN_SIGNATURE
 +};
 +
 +enum {
 +	PROP_0,
 +	PROP_SELECTED,
 +	PROP_SIGNATURE_LIST
 +};
 +
 +enum {
 +	REFRESHED,
 +	LAST_SIGNAL
 +};
 +
 +struct _ESignatureTreeViewPrivate {
 +	ESignatureList *signature_list;
 +	GHashTable *index;
 +};
 +
 +static gpointer parent_class;
 +static guint signals[LAST_SIGNAL];
 +
 +static void
 +signature_tree_view_refresh_cb (ESignatureList *signature_list,
 +                                ESignature *unused,
 +                                ESignatureTreeView *tree_view)
 +{
 +	GtkListStore *store;
 +	GtkTreeModel *model;
 +	GtkTreeIter tree_iter;
 +	EIterator *signature_iter;
 +	ESignature *signature;
 +	GHashTable *index;
 +	GList *list = NULL;
 +	GList *iter;
 +
 +	store = gtk_list_store_new (2, G_TYPE_STRING, E_TYPE_SIGNATURE);
 +	model = GTK_TREE_MODEL (store);
 +	index = tree_view->priv->index;
 +
 +	g_hash_table_remove_all (index);
 +
 +	if (signature_list == NULL)
 +		goto skip;
 +
 +	/* Build a list of ESignatures to display. */
 +	signature_iter = e_list_get_iterator (E_LIST (signature_list));
 +	while (e_iterator_is_valid (signature_iter)) {
 +
 +		/* XXX EIterator misuses const. */
 +		signature = (ESignature *) e_iterator_get (signature_iter);
 +		list = g_list_prepend (list, signature);
 +		e_iterator_next (signature_iter);
 +	}
 +	g_object_unref (signature_iter);
 +
 +	list = g_list_reverse (list);
 +
 +	/* Populate the list store and index. */
 +	for (iter = list; iter != NULL; iter = iter->next) {
 +		GtkTreeRowReference *reference;
 +		GtkTreePath *path;
 +
 +		signature = iter->data;
 +
 +		/* Skip autogenerated signatures. */
 +		if (signature->autogen)
 +			continue;
 +
 +		gtk_list_store_append (store, &tree_iter);
 +		gtk_list_store_set (
 +			store, &tree_iter,
 +			COLUMN_STRING, signature->name,
 +			COLUMN_SIGNATURE, signature, -1);
 +
 +		path = gtk_tree_model_get_path (model, &tree_iter);
 +		reference = gtk_tree_row_reference_new (model, path);
 +		g_hash_table_insert (index, signature, reference);
 +		gtk_tree_path_free (path);
 +	}
 +
 +skip:
 +	/* Restore the previously selected signature. */
 +	signature = e_signature_tree_view_get_selected (tree_view);
 +	if (signature != NULL)
 +		g_object_ref (signature);
 +	gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), model);
 +	e_signature_tree_view_set_selected (tree_view, signature);
 +	if (signature != NULL)
 +		g_object_unref (signature);
 +
 +	g_signal_emit (tree_view, signals[REFRESHED], 0);
 +}
 +
 +static void
 +signature_tree_view_selection_changed_cb (ESignatureTreeView *tree_view)
 +{
 +	g_object_notify (G_OBJECT (tree_view), "selected");
 +}
 +
 +static GObject *
 +signature_tree_view_constructor (GType type,
 +                                 guint n_construct_properties,
 +                                 GObjectConstructParam *construct_properties)
 +{
 +	GObject *object;
 +	GtkTreeView *tree_view;
 +	GtkTreeViewColumn *column;
 +	GtkCellRenderer *renderer;
 +
 +	/* Chain up to parent's constructor() method. */
 +	object = G_OBJECT_CLASS (parent_class)->constructor (
 +		type, n_construct_properties, construct_properties);
 +
 +	tree_view = GTK_TREE_VIEW (object);
 +	gtk_tree_view_set_headers_visible (tree_view, FALSE);
 +
 +	column = gtk_tree_view_column_new ();
 +	renderer = gtk_cell_renderer_text_new ();
 +	gtk_tree_view_column_pack_start (column, renderer, TRUE);
 +	gtk_tree_view_column_add_attribute (
 +		column, renderer, "text", COLUMN_STRING);
 +	gtk_tree_view_append_column (tree_view, column);
 +
 +	return object;
 +}
 +
 +static void
 +signature_tree_view_set_property (GObject *object,
 +                                  guint property_id,
 +                                  const GValue *value,
 +                                  GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_SELECTED:
 +			e_signature_tree_view_set_selected (
 +				E_SIGNATURE_TREE_VIEW (object),
 +				g_value_get_object (value));
 +			return;
 +
 +		case PROP_SIGNATURE_LIST:
 +			e_signature_tree_view_set_signature_list (
 +				E_SIGNATURE_TREE_VIEW (object),
 +				g_value_get_object (value));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +signature_tree_view_get_property (GObject *object,
 +                                  guint property_id,
 +                                  GValue *value,
 +                                  GParamSpec *pspec)
 +{
 +	switch (property_id) {
 +		case PROP_SELECTED:
 +			g_value_set_object (
 +				value,
 +				e_signature_tree_view_get_selected (
 +				E_SIGNATURE_TREE_VIEW (object)));
 +			return;
 +
 +		case PROP_SIGNATURE_LIST:
 +			g_value_set_object (
 +				value,
 +				e_signature_tree_view_get_signature_list (
 +				E_SIGNATURE_TREE_VIEW (object)));
 +			return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +static void
 +signature_tree_view_dispose (GObject *object)
 +{
 +	ESignatureTreeViewPrivate *priv;
 +
 +	priv = E_SIGNATURE_TREE_VIEW_GET_PRIVATE (object);
 +
 +	if (priv->signature_list != NULL) {
 +		g_signal_handlers_disconnect_by_func (
 +			priv->signature_list,
 +			signature_tree_view_refresh_cb, object);
 +		g_object_unref (priv->signature_list);
 +		priv->signature_list = NULL;
 +	}
 +
 +	g_hash_table_remove_all (priv->index);
 +
 +	/* Chain up to parent's dispose() method. */
 +	G_OBJECT_CLASS (parent_class)->dispose (object);
 +}
 +
 +static void
 +signature_tree_view_finalize (GObject *object)
 +{
 +	ESignatureTreeViewPrivate *priv;
 +
 +	priv = E_SIGNATURE_TREE_VIEW_GET_PRIVATE (object);
 +
 +	g_hash_table_destroy (priv->index);
 +
 +	/* Chain up to parent's finalize() method. */
 +	G_OBJECT_CLASS (parent_class)->finalize (object);
 +}
 +
 +static void
 +signature_tree_view_class_init (ESignatureTreeViewClass *class)
 +{
 +	GObjectClass *object_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (ESignatureTreeViewPrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->constructor = signature_tree_view_constructor;
 +	object_class->set_property = signature_tree_view_set_property;
 +	object_class->get_property = signature_tree_view_get_property;
 +	object_class->dispose = signature_tree_view_dispose;
 +	object_class->finalize = signature_tree_view_finalize;
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_SELECTED,
 +		g_param_spec_object (
 +			"selected",
 +			"Selected Signature",
 +			NULL,
 +			E_TYPE_SIGNATURE,
 +			G_PARAM_READWRITE));
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_SIGNATURE_LIST,
 +		g_param_spec_object (
 +			"signature-list",
 +			"Signature List",
 +			NULL,
 +			E_TYPE_SIGNATURE_LIST,
 +			G_PARAM_READWRITE |
 +			G_PARAM_CONSTRUCT));
 +
 +	signals[REFRESHED] = g_signal_new (
 +		"refreshed",
 +		G_TYPE_FROM_CLASS (class),
 +		G_SIGNAL_RUN_LAST,
 +		0, NULL, NULL,
 +		g_cclosure_marshal_VOID__VOID,
 +		G_TYPE_NONE, 0);
 +}
 +
 +static void
 +signature_tree_view_init (ESignatureTreeView *tree_view)
 +{
 +	GHashTable *index;
 +	GtkTreeSelection *selection;
 +
 +	/* Reverse-lookup index */
 +	index = g_hash_table_new_full (
 +		g_direct_hash, g_direct_equal,
 +		(GDestroyNotify) g_object_unref,
 +		(GDestroyNotify) gtk_tree_row_reference_free);
 +
 +	tree_view->priv = E_SIGNATURE_TREE_VIEW_GET_PRIVATE (tree_view);
 +	tree_view->priv->index = index;
 +
 +	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
 +
 +	g_signal_connect_swapped (
 +		selection, "changed",
 +		G_CALLBACK (signature_tree_view_selection_changed_cb),
 +		tree_view);
 +}
 +
 +GType
 +e_signature_tree_view_get_type (void)
 +{
 +	static GType type = 0;
 +
 +	if (G_UNLIKELY (type == 0)) {
 +		static const GTypeInfo type_info = {
 +			sizeof (ESignatureTreeViewClass),
 +			(GBaseInitFunc) NULL,
 +			(GBaseFinalizeFunc) NULL,
 +			(GClassInitFunc) signature_tree_view_class_init,
 +			(GClassFinalizeFunc) NULL,
 +			NULL,  /* class_data */
 +			sizeof (ESignatureTreeView),
 +			0,     /* n_preallocs */
 +			(GInstanceInitFunc) signature_tree_view_init,
 +			NULL  /* value_table */
 +		};
 +
 +		type = g_type_register_static (
 +			GTK_TYPE_TREE_VIEW, "ESignatureTreeView",
 +			&type_info, 0);
 +	}
 +
 +	return type;
 +}
 +
 +GtkWidget *
 +e_signature_tree_view_new (void)
 +{
 +	return g_object_new (E_TYPE_SIGNATURE_TREE_VIEW, NULL);
 +}
 +
 +ESignatureList *
 +e_signature_tree_view_get_signature_list (ESignatureTreeView *tree_view)
 +{
 +	g_return_val_if_fail (E_IS_SIGNATURE_TREE_VIEW (tree_view), NULL);
 +
 +	return tree_view->priv->signature_list;
 +}
 +
 +void
 +e_signature_tree_view_set_signature_list (ESignatureTreeView *tree_view,
 +                                          ESignatureList *signature_list)
 +{
 +	ESignatureTreeViewPrivate *priv;
 +
 +	g_return_if_fail (E_IS_SIGNATURE_TREE_VIEW (tree_view));
 +
 +	if (signature_list != NULL)
 +		g_return_if_fail (E_IS_SIGNATURE_LIST (signature_list));
 +
 +	priv = E_SIGNATURE_TREE_VIEW_GET_PRIVATE (tree_view);
 +
 +	if (priv->signature_list != NULL) {
 +		g_signal_handlers_disconnect_by_func (
 +			priv->signature_list,
 +			signature_tree_view_refresh_cb, tree_view);
 +		g_object_unref (priv->signature_list);
 +		priv->signature_list = NULL;
 +	}
 +
 +	if (signature_list != NULL) {
 +		priv->signature_list = g_object_ref (signature_list);
 +
 +		/* Listen for changes to the signature list. */
 +		g_signal_connect (
 +			priv->signature_list, "signature-added",
 +			G_CALLBACK (signature_tree_view_refresh_cb),
 +			tree_view);
 +		g_signal_connect (
 +			priv->signature_list, "signature-changed",
 +			G_CALLBACK (signature_tree_view_refresh_cb),
 +			tree_view);
 +		g_signal_connect (
 +			priv->signature_list, "signature-removed",
 +			G_CALLBACK (signature_tree_view_refresh_cb),
 +			tree_view);
 +	}
 +
 +	signature_tree_view_refresh_cb (signature_list, NULL, tree_view);
 +
 +	g_object_notify (G_OBJECT (tree_view), "signature-list");
 +}
 +
 +ESignature *
 +e_signature_tree_view_get_selected (ESignatureTreeView *tree_view)
 +{
 +	ESignature *signature;
 +	GtkTreeSelection *selection;
 +	GtkTreeModel *model;
 +	GtkTreeIter iter;
 +
 +	g_return_val_if_fail (E_IS_SIGNATURE_TREE_VIEW (tree_view), NULL);
 +
 +	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
 +	if (!gtk_tree_selection_get_selected (selection, &model, &iter))
 +		return NULL;
 +
 +	gtk_tree_model_get (model, &iter, COLUMN_SIGNATURE, &signature, -1);
 +
 +	return signature;
 +}
 +
 +gboolean
 +e_signature_tree_view_set_selected (ESignatureTreeView *tree_view,
 +                                    ESignature *signature)
 +{
 +	GtkTreeRowReference *reference;
 +	GtkTreeSelection *selection;
 +	GtkTreePath *path;
 +
 +	g_return_val_if_fail (E_IS_SIGNATURE_TREE_VIEW (tree_view), FALSE);
 +
 +	if (signature != NULL)
 +		g_return_val_if_fail (E_IS_SIGNATURE (signature), FALSE);
 +
 +	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
 +
 +	/* NULL means clear the selection. */
 +	if (signature == NULL) {
 +		gtk_tree_selection_unselect_all (selection);
 +		return TRUE;
 +	}
 +
 +	/* Lookup the tree row reference for the signature. */
 +	reference = g_hash_table_lookup (tree_view->priv->index, signature);
 +	if (reference == NULL)
 +		return FALSE;
 +
 +	/* Select the referenced path. */
 +	path = gtk_tree_row_reference_get_path (reference);
 +	gtk_tree_selection_select_path (selection, path);
 +	gtk_tree_path_free (path);
 +
 +	g_object_notify (G_OBJECT (tree_view), "selected");
 +
 +	return TRUE;
 +}
diff --cc widgets/misc/e-signature-tree-view.h
index 3afe569,0000000..50d1e11
mode 100644,000000..100644
--- a/widgets/misc/e-signature-tree-view.h
+++ b/widgets/misc/e-signature-tree-view.h
@@@ -1,78 -1,0 +1,78 @@@
 +/*
 + * e-signature-tree-view.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_SIGNATURE_TREE_VIEW_H
 +#define E_SIGNATURE_TREE_VIEW_H
 +
 +#include <gtk/gtk.h>
 +#include <e-util/e-signature.h>
 +#include <e-util/e-signature-list.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_SIGNATURE_TREE_VIEW \
 +	(e_signature_tree_view_get_type ())
 +#define E_SIGNATURE_TREE_VIEW(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_SIGNATURE_TREE_VIEW, ESignatureTreeView))
 +#define E_SIGNATURE_TREE_VIEW_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_SIGNATURE_TREE_VIEW, ESignatureTreeViewClass))
 +#define E_IS_SIGNATURE_TREE_VIEW(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_SIGNATURE_TREE_VIEW))
 +#define E_IS_SIGNATURE_TREE_VIEW_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), E_TYPE_SIGNATURE_TREE_VIEW))
 +#define E_SIGNATURE_TREE_VIEW_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_SIGNATURE_TREE_VIEW, ESignatureTreeViewClass))
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _ESignatureTreeView ESignatureTreeView;
 +typedef struct _ESignatureTreeViewClass ESignatureTreeViewClass;
 +typedef struct _ESignatureTreeViewPrivate ESignatureTreeViewPrivate;
 +
 +struct _ESignatureTreeView {
 +	GtkTreeView parent;
 +	ESignatureTreeViewPrivate *priv;
 +};
 +
 +struct _ESignatureTreeViewClass {
 +	GtkTreeViewClass parent_class;
 +};
 +
 +GType		e_signature_tree_view_get_type	(void);
 +GtkWidget *	e_signature_tree_view_new	(void);
 +ESignatureList *e_signature_tree_view_get_signature_list
 +					(ESignatureTreeView *tree_view);
 +void		e_signature_tree_view_set_signature_list
 +					(ESignatureTreeView *tree_view,
 +					 ESignatureList *signature_list);
 +ESignature *	e_signature_tree_view_get_selected
 +					(ESignatureTreeView *tree_view);
 +gboolean	e_signature_tree_view_set_selected
 +					(ESignatureTreeView *tree_view,
 +					 ESignature *signature);
 +
 +G_END_DECLS
 +
 +#endif /* E_SIGNATURE_TREE_VIEW_H */
diff --cc widgets/misc/e-timeout-activity.c
index 878d6b8,0000000..aa57960
mode 100644,000000..100644
--- a/widgets/misc/e-timeout-activity.c
+++ b/widgets/misc/e-timeout-activity.c
@@@ -1,198 -1,0 +1,198 @@@
 +/*
 + * e-timeout-activity.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-timeout-activity.h"
 +
 +#include <stdarg.h>
 +
 +#define E_TIMEOUT_ACTIVITY_GET_PRIVATE(obj) \
 +	(G_TYPE_INSTANCE_GET_PRIVATE \
 +	((obj), E_TYPE_TIMEOUT_ACTIVITY, ETimeoutActivityPrivate))
 +
 +struct _ETimeoutActivityPrivate {
 +	guint timeout_id;
 +};
 +
 +enum {
 +	TIMEOUT,
 +	LAST_SIGNAL
 +};
 +
 +static gpointer parent_class;
 +static gulong signals[LAST_SIGNAL];
 +
 +static gboolean
 +timeout_activity_cb (ETimeoutActivity *timeout_activity)
 +{
 +	g_signal_emit (timeout_activity, signals[TIMEOUT], 0);
 +
 +	return FALSE;
 +}
 +
 +static void
 +timeout_activity_finalize (GObject *object)
 +{
 +	ETimeoutActivityPrivate *priv;
 +
 +	priv = E_TIMEOUT_ACTIVITY_GET_PRIVATE (object);
 +
 +	if (priv->timeout_id > 0)
 +		g_source_remove (priv->timeout_id);
 +
 +	/* Chain up to parent's finalize() method. */
 +	G_OBJECT_CLASS (parent_class)->finalize (object);
 +}
 +
 +static void
 +timeout_activity_cancelled (EActivity *activity)
 +{
 +	ETimeoutActivityPrivate *priv;
 +
 +	priv = E_TIMEOUT_ACTIVITY_GET_PRIVATE (activity);
 +
 +	if (priv->timeout_id > 0) {
 +		g_source_remove (priv->timeout_id);
 +		priv->timeout_id = 0;
 +	}
 +
 +	/* Chain up to parent's cancelled() method. */
 +	E_ACTIVITY_CLASS (parent_class)->cancelled (activity);
 +}
 +
 +static void
 +timeout_activity_completed (EActivity *activity)
 +{
 +	ETimeoutActivityPrivate *priv;
 +
 +	priv = E_TIMEOUT_ACTIVITY_GET_PRIVATE (activity);
 +
 +	if (priv->timeout_id > 0) {
 +		g_source_remove (priv->timeout_id);
 +		priv->timeout_id = 0;
 +	}
 +
 +	/* Chain up to parent's completed() method. */
 +	E_ACTIVITY_CLASS (parent_class)->completed (activity);
 +}
 +
 +static void
 +timeout_activity_timeout (ETimeoutActivity *timeout_activity)
 +{
 +	/* Allow subclasses to safely chain up. */
 +}
 +
 +static void
 +timeout_activity_class_init (ETimeoutActivityClass *class)
 +{
 +	GObjectClass *object_class;
 +	EActivityClass *activity_class;
 +
 +	parent_class = g_type_class_peek_parent (class);
 +	g_type_class_add_private (class, sizeof (ETimeoutActivityPrivate));
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->finalize = timeout_activity_finalize;
 +
 +	activity_class = E_ACTIVITY_CLASS (class);
 +	activity_class->cancelled = timeout_activity_cancelled;
 +	activity_class->completed = timeout_activity_completed;
 +
 +	class->timeout = timeout_activity_timeout;
 +
 +	signals[TIMEOUT] = g_signal_new (
 +		"timeout",
 +		G_OBJECT_CLASS_TYPE (object_class),
 +		G_SIGNAL_RUN_FIRST,
 +		G_STRUCT_OFFSET (ETimeoutActivityClass, timeout),
 +		NULL, NULL,
 +		g_cclosure_marshal_VOID__VOID,
 +		G_TYPE_NONE, 0);
 +}
 +
 +static void
 +timeout_activity_init (ETimeoutActivity *timeout_activity)
 +{
 +	timeout_activity->priv =
 +		E_TIMEOUT_ACTIVITY_GET_PRIVATE (timeout_activity);
 +}
 +
 +GType
 +e_timeout_activity_get_type (void)
 +{
 +	static GType type = 0;
 +
 +	if (G_UNLIKELY (type == 0)) {
 +		static const GTypeInfo type_info = {
 +			sizeof (ETimeoutActivityClass),
 +			(GBaseInitFunc) NULL,
 +			(GBaseFinalizeFunc) NULL,
 +			(GClassInitFunc) timeout_activity_class_init,
 +			(GClassFinalizeFunc) NULL,
 +			NULL,  /* class_data */
 +			sizeof (ETimeoutActivity),
 +			0,     /* n_preallocs */
 +			(GInstanceInitFunc) timeout_activity_init,
 +			NULL   /* value_table */
 +		};
 +
 +		type = g_type_register_static (
 +			E_TYPE_ACTIVITY, "ETimeoutActivity", &type_info, 0);
 +	}
 +
 +	return type;
 +}
 +
 +EActivity *
 +e_timeout_activity_new (const gchar *primary_text)
 +{
 +	return g_object_new (
 +		E_TYPE_TIMEOUT_ACTIVITY,
 +		"primary-text", primary_text, NULL);
 +}
 +
 +EActivity *
 +e_timeout_activity_newv (const gchar *format, ...)
 +{
 +	EActivity *activity;
 +	gchar *primary_text;
 +	va_list args;
 +
 +	va_start (args, format);
 +	primary_text = g_strdup_vprintf (format, args);
 +	activity = e_timeout_activity_new (primary_text);
 +	g_free (primary_text);
 +	va_end (args);
 +
 +	return activity;
 +}
 +
 +void
 +e_timeout_activity_set_timeout (ETimeoutActivity *timeout_activity,
 +                                guint seconds)
 +{
 +	g_return_if_fail (E_IS_TIMEOUT_ACTIVITY (timeout_activity));
 +
 +	if (timeout_activity->priv->timeout_id > 0)
 +		e_activity_cancel (E_ACTIVITY (timeout_activity));
 +
 +	timeout_activity->priv->timeout_id = g_timeout_add_seconds (
 +		seconds, (GSourceFunc) timeout_activity_cb, timeout_activity);
 +}
diff --cc widgets/misc/e-timeout-activity.h
index b395f39,0000000..82dd113
mode 100644,000000..100644
--- a/widgets/misc/e-timeout-activity.h
+++ b/widgets/misc/e-timeout-activity.h
@@@ -1,73 -1,0 +1,73 @@@
 +/*
 + * e-timeout-activity.h
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef E_TIMEOUT_ACTIVITY_H
 +#define E_TIMEOUT_ACTIVITY_H
 +
 +#include <e-activity.h>
 +
 +/* Standard GObject macros */
 +#define E_TYPE_TIMEOUT_ACTIVITY \
 +	(e_timeout_activity_get_type ())
 +#define E_TIMEOUT_ACTIVITY(obj) \
 +	(G_TYPE_CHECK_INSTANCE_CAST \
 +	((obj), E_TYPE_TIMEOUT_ACTIVITY, ETimeoutActivity))
 +#define E_TIMEOUT_ACTIVITY_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_CAST \
 +	((cls), E_TYPE_TIMEOUT_ACTIVITY, ETimeoutActivityClass))
 +#define E_IS_TIMEOUT_ACTIVITY(obj) \
 +	(G_TYPE_CHECK_INSTANCE_TYPE \
 +	((obj), E_TYPE_TIMEOUT_ACTIVITY))
 +#define E_IS_TIMEOUT_ACTIVITY_CLASS(cls) \
 +	(G_TYPE_CHECK_CLASS_TYPE \
 +	((cls), E_TYPE_TIMEOUT_ACTIVITY))
 +#define E_TIMEOUT_ACTIVITY_GET_CLASS(obj) \
 +	(G_TYPE_INSTANCE_GET_CLASS \
 +	((obj), E_TYPE_TIMEOUT_ACTIVITY, ETimeoutActivityClass))
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _ETimeoutActivity ETimeoutActivity;
 +typedef struct _ETimeoutActivityClass ETimeoutActivityClass;
 +typedef struct _ETimeoutActivityPrivate ETimeoutActivityPrivate;
 +
 +struct _ETimeoutActivity {
 +	EActivity parent;
 +	ETimeoutActivityPrivate *priv;
 +};
 +
 +struct _ETimeoutActivityClass {
 +	EActivityClass parent_class;
 +
 +	/* Signals */
 +	void		(*timeout)	(ETimeoutActivity *timeout_activity);
 +};
 +
 +GType		e_timeout_activity_get_type	(void);
 +EActivity *	e_timeout_activity_new		(const gchar *primary_text);
 +EActivity *	e_timeout_activity_newv		(const gchar *format,
 +						 ...) G_GNUC_PRINTF (1, 2);
 +void		e_timeout_activity_set_timeout	(ETimeoutActivity *timeout_activity,
 +						 guint seconds);
 +
 +G_END_DECLS
 +
 +#endif /* E_TIMEOUT_ACTIVITY_H */
diff --cc widgets/misc/test-preferences-window.c
index bc53f98,0000000..c0f13f5
mode 100644,000000..100644
--- a/widgets/misc/test-preferences-window.c
+++ b/widgets/misc/test-preferences-window.c
@@@ -1,84 -1,0 +1,84 @@@
 +/*
 + * test-preferences-window.c
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#include "e-preferences-window.c"
 +
 +#include <gtk/gtk.h>
 +
 +#define NUM_PAGES 10
 +
 +static void
 +add_pages (EPreferencesWindow *preferences_window)
 +{
 +	int i;
 +
 +	for (i = 0; i < NUM_PAGES; i ++) {
 +		GtkWidget *widget;
 +		char *caption;
 +		char *page_name;
 +
 +		caption = g_strdup_printf ("Title of page %d", i);
 +		page_name = g_strdup_printf ("page-%d", i);
 +
 +		widget = gtk_label_new (caption);
 +		gtk_widget_show (widget);
 +
 +		e_preferences_window_add_page (
 +			preferences_window, page_name,
 +			"gtk-properties", caption, widget, i);
 +
 +		g_free (caption);
 +		g_free (page_name);
 +	}
 +}
 +
 +static int
 +delete_event_callback (GtkWidget *widget,
 +		       GdkEventAny *event,
 +		       void *data)
 +{
 +	gtk_main_quit ();
 +
 +	return TRUE;
 +}
 +
 +int
 +main (int argc, char **argv)
 +{
 +	GtkWidget *window;
 +
 +	gtk_init (&argc, &argv);
 +
 +	window = e_preferences_window_new ();
 +	gtk_window_set_default_size (GTK_WINDOW (window), 400, 300);
 +
 +	g_signal_connect(
 +		window, "delete-event",
 +		G_CALLBACK (delete_event_callback), NULL);
 +
 +	add_pages (E_PREFERENCES_WINDOW (window));
 +
 +	gtk_widget_show (window);
 +
 +	gtk_main ();
 +
 +	return 0;
 +}
diff --cc widgets/table/a11y/gal-a11y-e-cell-popup.h
index 4f205c1,0000000..52e0066
mode 100644,000000..100644
--- a/widgets/table/a11y/gal-a11y-e-cell-popup.h
+++ b/widgets/table/a11y/gal-a11y-e-cell-popup.h
@@@ -1,62 -1,0 +1,62 @@@
 +/*
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Authors:
 + *		Yang Wu <yang wu sun com>
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef __GAL_A11Y_E_CELL_POPUP_H__
 +#define __GAL_A11Y_E_CELL_POPUP_H__
 +
 +#include <glib-object.h>
 +#include <table/e-table-item.h>
 +#include <table/a11y/gal-a11y-e-cell.h>
 +#include <atk/atkgobjectaccessible.h>
 +
 +#define GAL_A11Y_TYPE_E_CELL_POPUP            (gal_a11y_e_cell_popup_get_type ())
 +#define GAL_A11Y_E_CELL_POPUP(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_CELL_POPUP, GalA11yECellPopup))
 +#define GAL_A11Y_E_CELL_POPUP_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_CELL_POPUP, GalA11yECellPopupClass))
 +#define GAL_A11Y_IS_E_CELL_POPUP(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_CELL_POPUP))
 +#define GAL_A11Y_IS_E_CELL_POPUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_CELL_POPUP))
 +
 +typedef struct _GalA11yECellPopup GalA11yECellPopup;
 +typedef struct _GalA11yECellPopupClass GalA11yECellPopupClass;
 +
 +/* This struct should actually be larger as this isn't what we derive from.
 + * The GalA11yECellPopupPrivate comes right after the parent class structure.
 + **/
 +struct _GalA11yECellPopup {
 +	GalA11yECell object;
 +};
 +
 +struct _GalA11yECellPopupClass {
 +	GalA11yECellClass parent_class;
 +};
 +
 +
 +/* Standard Glib function */
 +GType      gal_a11y_e_cell_popup_get_type   (void);
 +AtkObject *gal_a11y_e_cell_popup_new        (ETableItem *item,
 +					    ECellView  *cell_view,
 +					    AtkObject  *parent,
 +					    int         model_col,
 +					    int         view_col,
 +					    int         row);
 +
 +#endif /* ! __GAL_A11Y_E_CELL_POPUP_H__ */
diff --cc widgets/table/a11y/gal-a11y-e-cell-text.h
index 208bc67,0000000..32fce87
mode 100644,000000..100644
--- a/widgets/table/a11y/gal-a11y-e-cell-text.h
+++ b/widgets/table/a11y/gal-a11y-e-cell-text.h
@@@ -1,64 -1,0 +1,64 @@@
 +/*
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Authors:
 + *		Christopher James Lahey <clahey ximian com>
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef __GAL_A11Y_E_CELL_TEXT_H__
 +#define __GAL_A11Y_E_CELL_TEXT_H__
 +
 +#include <glib-object.h>
 +#include <table/e-table-item.h>
 +#include <table/e-cell-text.h>
 +#include <table/a11y/gal-a11y-e-cell.h>
 +
 +#define GAL_A11Y_TYPE_E_CELL_TEXT            (gal_a11y_e_cell_text_get_type ())
 +#define GAL_A11Y_E_CELL_TEXT(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_CELL_TEXT, GalA11yECellText))
 +#define GAL_A11Y_E_CELL_TEXT_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_CELL_TEXT, GalA11yECellTextClass))
 +#define GAL_A11Y_IS_E_CELL_TEXT(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_CELL_TEXT))
 +#define GAL_A11Y_IS_E_CELL_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_CELL_TEXT))
 +
 +typedef struct _GalA11yECellText GalA11yECellText;
 +typedef struct _GalA11yECellTextClass GalA11yECellTextClass;
 +typedef struct _GalA11yECellTextPrivate GalA11yECellTextPrivate;
 +
 +/* This struct should actually be larger as this isn't what we derive from.
 + * The GalA11yECellTextPrivate comes right after the parent class structure.
 + **/
 +struct _GalA11yECellText {
 +	GalA11yECell object;
 +	gint inserted_id;
 +	gint deleted_id;
 +};
 +
 +struct _GalA11yECellTextClass {
 +	GalA11yECellClass parent_class;
 +};
 +
 +
 +/* Standard Glib function */
 +GType      gal_a11y_e_cell_text_get_type   (void);
 +AtkObject *gal_a11y_e_cell_text_new        (ETableItem *item,
 +					    ECellView  *cell_view,
 +					    AtkObject  *parent,
 +					    int         model_col,
 +					    int         view_col,
 +					    int         row);
 +
 +#endif /* ! __GAL_A11Y_E_CELL_TEXT_H__ */
diff --cc widgets/table/e-cell-date-edit.c
index 1cf3838,0000000..2bee6f5
mode 100644,000000..100644
--- a/widgets/table/e-cell-date-edit.c
+++ b/widgets/table/e-cell-date-edit.c
@@@ -1,1033 -1,0 +1,1033 @@@
 +/*
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Authors:
 + *		Damon Chaplin <damon ximian com>
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +/*
 + * ECellDateEdit - a subclass of ECellPopup used to show a date with a popup
 + * window to edit it.
 + */
 +
 +
 +#ifdef HAVE_CONFIG_H
 +#include <config.h>
 +#endif
 +
 +#include "e-cell-date-edit.h"
 +
 +#include <string.h>
 +#include <time.h>
 +#include <glib.h>
 +
 +#include <gdk/gdkkeysyms.h>
 +#include <gtk/gtk.h>
 +
 +#include "e-table-item.h"
 +#include "e-cell-text.h"
 +
 +#include <glib/gi18n.h>
 +
 +#include <libedataserver/e-time-utils.h>
 +
 +/* This depends on ECalendar which is why I didn't put it in gal. */
 +#include <misc/e-calendar.h>
 +
 +static void e_cell_date_edit_destroy		(GtkObject	*object);
 +static void e_cell_date_edit_get_property	(GObject	*object,
 +						 guint		 property_id,
 +						 GValue		*value,
 +						 GParamSpec	*pspec);
 +static void e_cell_date_edit_set_property	(GObject	*object,
 +						 guint		 property_id,
 +						 const GValue	*value,
 +						 GParamSpec	*pspec);
 +
 +static gint e_cell_date_edit_do_popup		(ECellPopup	*ecp,
 +						 GdkEvent	*event,
 +						 int             row,
 +						 int             view_col);
 +static void e_cell_date_edit_set_popup_values	(ECellDateEdit	*ecde);
 +static void e_cell_date_edit_select_matching_time(ECellDateEdit	*ecde,
 +						  char		*time);
 +static void e_cell_date_edit_show_popup		(ECellDateEdit	*ecde,
 +						 int             row,
 +						 int             view_col);
 +static void e_cell_date_edit_get_popup_pos	(ECellDateEdit	*ecde,
 +						 int             row,
 +						 int             view_col,
 +						 gint		*x,
 +						 gint		*y,
 +						 gint		*height,
 +						 gint		*width);
 +
 +static void e_cell_date_edit_rebuild_time_list	(ECellDateEdit	*ecde);
 +
 +static int e_cell_date_edit_key_press		(GtkWidget	*popup_window,
 +						 GdkEventKey	*event,
 +						 ECellDateEdit	*ecde);
 +static int  e_cell_date_edit_button_press	(GtkWidget	*popup_window,
 +						 GdkEventButton	*event,
 +						 ECellDateEdit	*ecde);
 +static void e_cell_date_edit_on_ok_clicked	(GtkWidget	*button,
 +						 ECellDateEdit	*ecde);
 +static void e_cell_date_edit_show_time_invalid_warning	(ECellDateEdit	*ecde);
 +static void e_cell_date_edit_on_now_clicked	(GtkWidget	*button,
 +						 ECellDateEdit	*ecde);
 +static void e_cell_date_edit_on_none_clicked	(GtkWidget	*button,
 +						 ECellDateEdit	*ecde);
 +static void e_cell_date_edit_on_today_clicked	(GtkWidget	*button,
 +						 ECellDateEdit	*ecde);
 +static void e_cell_date_edit_update_cell	(ECellDateEdit	*ecde,
- 						 char		*text);
++						 const gchar	*text);
 +static void e_cell_date_edit_on_time_selected	(GtkTreeSelection *selection, ECellDateEdit *ecde);
 +static void e_cell_date_edit_hide_popup		(ECellDateEdit	*ecde);
 +
 +
 +/* Our arguments. */
 +enum {
 +	PROP_0,
 +	PROP_SHOW_TIME,
 +	PROP_SHOW_NOW_BUTTON,
 +	PROP_SHOW_TODAY_BUTTON,
 +	PROP_ALLOW_NO_DATE_SET,
 +	PROP_USE_24_HOUR_FORMAT,
 +	PROP_LOWER_HOUR,
 +	PROP_UPPER_HOUR
 +};
 +
 +G_DEFINE_TYPE (ECellDateEdit, e_cell_date_edit, E_CELL_POPUP_TYPE)
 +
 +
 +static void
 +e_cell_date_edit_class_init (ECellDateEditClass *class)
 +{
 +	GObjectClass *object_class;
 +	GtkObjectClass *gtk_object_class;
 +	ECellPopupClass	*ecpc;
 +
 +	object_class = G_OBJECT_CLASS (class);
 +	object_class->get_property = e_cell_date_edit_get_property;
 +	object_class->set_property = e_cell_date_edit_set_property;
 +
 +	gtk_object_class = GTK_OBJECT_CLASS (class);
 +	gtk_object_class->destroy = e_cell_date_edit_destroy;
 +
 +	ecpc = E_CELL_POPUP_CLASS (class);
 +	ecpc->popup = e_cell_date_edit_do_popup;
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_SHOW_TIME,
 +		g_param_spec_boolean (
 +			"show_time",
 +			NULL,
 +			NULL,
 +			TRUE,
 +			G_PARAM_READWRITE));
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_SHOW_NOW_BUTTON,
 +		g_param_spec_boolean (
 +			"show_now_button",
 +			NULL,
 +			NULL,
 +			TRUE,
 +			G_PARAM_READWRITE));
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_SHOW_TODAY_BUTTON,
 +		g_param_spec_boolean (
 +			"show_today_button",
 +			NULL,
 +			NULL,
 +			TRUE,
 +			G_PARAM_READWRITE));
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_ALLOW_NO_DATE_SET,
 +		g_param_spec_boolean (
 +			"allow_no_date_set",
 +			NULL,
 +			NULL,
 +			TRUE,
 +			G_PARAM_READWRITE));
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_USE_24_HOUR_FORMAT,
 +		g_param_spec_boolean (
 +			"use_24_hour_format",
 +			NULL,
 +			NULL,
 +			TRUE,
 +			G_PARAM_READWRITE));
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_LOWER_HOUR,
 +		g_param_spec_int (
 +			"lower_hour",
 +			NULL,
 +			NULL,
 +			G_MININT,
 +			G_MAXINT,
 +			0,
 +			G_PARAM_READWRITE));
 +
 +	g_object_class_install_property (
 +		object_class,
 +		PROP_UPPER_HOUR,
 +		g_param_spec_int (
 +			"upper_hour",
 +			NULL,
 +			NULL,
 +			G_MININT,
 +			G_MAXINT,
 +			24,
 +			G_PARAM_READWRITE));
 +}
 +
 +
 +static void
 +e_cell_date_edit_init (ECellDateEdit *ecde)
 +{
 +	GtkWidget *frame, *vbox, *hbox, *vbox2;
 +	GtkWidget *scrolled_window, *bbox, *tree_view;
 +	GtkWidget *now_button, *today_button, *none_button, *ok_button;
 +	GtkListStore *store;
 +
 +	ecde->lower_hour = 0;
 +	ecde->upper_hour = 24;
 +	ecde->use_24_hour_format = TRUE;
 +	ecde->need_time_list_rebuild = TRUE;
 +	ecde->freeze_count = 0;
 +	ecde->time_callback = NULL;
 +	ecde->time_callback_data = NULL;
 +	ecde->time_callback_destroy = NULL;
 +
 +	/* We create one popup window for the ECell, since there will only
 +	   ever be one popup in use at a time. */
 +	ecde->popup_window = gtk_window_new (GTK_WINDOW_POPUP);
 +
 +	gtk_window_set_type_hint (GTK_WINDOW (ecde->popup_window),
 +				  GDK_WINDOW_TYPE_HINT_COMBO);
 +	gtk_window_set_resizable (GTK_WINDOW (ecde->popup_window), TRUE);
 +
 +	frame = gtk_frame_new (NULL);
 +	gtk_container_add (GTK_CONTAINER (ecde->popup_window), frame);
 +	gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
 +	gtk_widget_show (frame);
 +
 +	vbox = gtk_vbox_new (FALSE, 0);
 +	gtk_container_add (GTK_CONTAINER (frame), vbox);
 +        gtk_widget_show (vbox);
 +
 +	hbox = gtk_hbox_new (FALSE, 4);
 +	gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
 +        gtk_widget_show (hbox);
 +
 +	ecde->calendar = e_calendar_new ();
 +	gnome_canvas_item_set (GNOME_CANVAS_ITEM (E_CALENDAR (ecde->calendar)->calitem),
 +			       "move_selection_when_moving", FALSE,
 +			       NULL);
 +	gtk_box_pack_start (GTK_BOX (hbox), ecde->calendar, TRUE, TRUE, 0);
 +	gtk_widget_show (ecde->calendar);
 +
 +	vbox2 = gtk_vbox_new (FALSE, 2);
 +	gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 0);
 +        gtk_widget_show (vbox2);
 +
 +	ecde->time_entry = gtk_entry_new ();
 +	gtk_widget_set_size_request (ecde->time_entry, 50, -1);
 +	gtk_box_pack_start (GTK_BOX (vbox2), ecde->time_entry,
 +			    FALSE, FALSE, 0);
 +	gtk_widget_show (ecde->time_entry);
 +
 +	scrolled_window = gtk_scrolled_window_new (NULL, NULL);
 +	gtk_box_pack_start (GTK_BOX (vbox2), scrolled_window, TRUE, TRUE, 0);
 +	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
 +					GTK_POLICY_NEVER,
 +					GTK_POLICY_ALWAYS);
 +	gtk_widget_show (scrolled_window);
 +
 +	store = gtk_list_store_new (1, G_TYPE_STRING);
 +	tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
 +	g_object_unref (store);
 +
 +	gtk_tree_view_append_column (
 +		GTK_TREE_VIEW (tree_view),
 +		gtk_tree_view_column_new_with_attributes ("Text", gtk_cell_renderer_text_new (), "text", 0, NULL));
 +
 +	gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tree_view), FALSE);
 +
 +	gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled_window), tree_view);
 +	gtk_container_set_focus_vadjustment (GTK_CONTAINER (tree_view),
 +					     gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (scrolled_window)));
 +	gtk_container_set_focus_hadjustment (GTK_CONTAINER (tree_view),
 + 					     gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (scrolled_window)));
 +	gtk_widget_show (tree_view);
 +	ecde->time_tree_view = tree_view;
 +	g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view)), "changed",
 +			    G_CALLBACK (e_cell_date_edit_on_time_selected),
 +			    ecde);
 +
 +	bbox = gtk_hbutton_box_new ();
 +	gtk_container_set_border_width (GTK_CONTAINER (bbox), 4);
 +	gtk_box_set_spacing (GTK_BOX (bbox), 2);
 +	gtk_box_pack_start (GTK_BOX (vbox), bbox, FALSE, FALSE, 0);
 +        gtk_widget_show (bbox);
 +
 +	now_button = gtk_button_new_with_label (_("Now"));
 +	gtk_container_add (GTK_CONTAINER (bbox), now_button);
 +        gtk_widget_show (now_button);
 +	g_signal_connect((now_button), "clicked",
 +			    G_CALLBACK (e_cell_date_edit_on_now_clicked),
 +			    ecde);
 +	ecde->now_button = now_button;
 +
 +	today_button = gtk_button_new_with_label (_("Today"));
 +	gtk_container_add (GTK_CONTAINER (bbox), today_button);
 +        gtk_widget_show (today_button);
 +	g_signal_connect((today_button), "clicked",
 +			    G_CALLBACK (e_cell_date_edit_on_today_clicked),
 +			    ecde);
 +	ecde->today_button = today_button;
 +
 +	none_button = gtk_button_new_with_label (_("None"));
 +	gtk_container_add (GTK_CONTAINER (bbox), none_button);
 +        gtk_widget_show (none_button);
 +	g_signal_connect((none_button), "clicked",
 +			    G_CALLBACK (e_cell_date_edit_on_none_clicked),
 +			    ecde);
 +	ecde->none_button = none_button;
 +
 +	ok_button = gtk_button_new_with_label (_("OK"));
 +	gtk_container_add (GTK_CONTAINER (bbox), ok_button);
 +        gtk_widget_show (ok_button);
 +	g_signal_connect((ok_button), "clicked",
 +			    G_CALLBACK (e_cell_date_edit_on_ok_clicked),
 +			    ecde);
 +
 +
 +	g_signal_connect((ecde->popup_window),
 +			    "key_press_event",
 +			    G_CALLBACK (e_cell_date_edit_key_press),
 +			    ecde);
 +	g_signal_connect((ecde->popup_window),
 +			    "button_press_event",
 +			    G_CALLBACK (e_cell_date_edit_button_press),
 +			    ecde);
 +}
 +
 +
 +/**
 + * e_cell_date_edit_new:
 + *
 + * Creates a new ECellDateEdit renderer.
 + *
 + * Returns: an ECellDateEdit object.
 + */
 +ECell *
 +e_cell_date_edit_new			(void)
 +{
 +	return g_object_new (e_cell_date_edit_get_type (), NULL);
 +}
 +
 +
 +/*
 + * GtkObject::destroy method
 + */
 +static void
 +e_cell_date_edit_destroy		(GtkObject *object)
 +{
 +	ECellDateEdit *ecde = E_CELL_DATE_EDIT (object);
 +
 +	e_cell_date_edit_set_get_time_callback (ecde, NULL, NULL, NULL);
 +
 +	gtk_widget_destroy (ecde->popup_window);
 +	ecde->popup_window = NULL;
 +
 +	GTK_OBJECT_CLASS (e_cell_date_edit_parent_class)->destroy (object);
 +}
 +
 +
 +static void
 +e_cell_date_edit_get_property		(GObject	*object,
 +					 guint		 property_id,
 +					 GValue		*value,
 +					 GParamSpec	*pspec)
 +{
 +	ECellDateEdit *ecde;
 +
 +	ecde = E_CELL_DATE_EDIT (object);
 +
 +	switch (property_id) {
 +	case PROP_SHOW_TIME:
 +		g_value_set_boolean (value, GTK_WIDGET_VISIBLE (ecde->time_entry));
 +		return;
 +	case PROP_SHOW_NOW_BUTTON:
 +		g_value_set_boolean (value, GTK_WIDGET_VISIBLE (ecde->now_button));
 +		return;
 +	case PROP_SHOW_TODAY_BUTTON:
 +		g_value_set_boolean (value, GTK_WIDGET_VISIBLE (ecde->today_button));
 +		return;
 +	case PROP_ALLOW_NO_DATE_SET:
 +		g_value_set_boolean (value, GTK_WIDGET_VISIBLE (ecde->none_button));
 +		return;
 +	case PROP_USE_24_HOUR_FORMAT:
 +		g_value_set_boolean (value, ecde->use_24_hour_format);
 +		return;
 +	case PROP_LOWER_HOUR:
 +		g_value_set_int (value, ecde->lower_hour);
 +		return;
 +	case PROP_UPPER_HOUR:
 +		g_value_set_int (value, ecde->upper_hour);
 +		return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +
 +static void
 +e_cell_date_edit_set_property		(GObject	*object,
 +					 guint		 property_id,
 +					 const GValue	*value,
 +					 GParamSpec	*pspec)
 +{
 +	ECellDateEdit *ecde;
 +	gint ivalue;
 +	gboolean bvalue;
 +
 +	ecde = E_CELL_DATE_EDIT (object);
 +
 +	switch (property_id) {
 +	case PROP_SHOW_TIME:
 +		if (g_value_get_boolean (value)) {
 +			gtk_widget_show (ecde->time_entry);
 +			gtk_widget_show (ecde->time_tree_view);
 +		} else {
 +			gtk_widget_hide (ecde->time_entry);
 +			gtk_widget_hide (ecde->time_tree_view);
 +		}
 +		return;
 +	case PROP_SHOW_NOW_BUTTON:
 +		if (g_value_get_boolean (value)) {
 +			gtk_widget_show (ecde->now_button);
 +		} else {
 +			gtk_widget_hide (ecde->now_button);
 +		}
 +		return;
 +	case PROP_SHOW_TODAY_BUTTON:
 +		if (g_value_get_boolean (value)) {
 +			gtk_widget_show (ecde->today_button);
 +		} else {
 +			gtk_widget_hide (ecde->today_button);
 +		}
 +		return;
 +	case PROP_ALLOW_NO_DATE_SET:
 +		if (g_value_get_boolean (value)) {
 +			gtk_widget_show (ecde->none_button);
 +		} else {
 +			/* FIXME: What if we have no date set now. */
 +			gtk_widget_hide (ecde->none_button);
 +		}
 +		return;
 +	case PROP_USE_24_HOUR_FORMAT:
 +		bvalue = g_value_get_boolean (value);
 +		if (ecde->use_24_hour_format != bvalue) {
 +			ecde->use_24_hour_format = bvalue;
 +			ecde->need_time_list_rebuild = TRUE;
 +		}
 +		return;
 +	case PROP_LOWER_HOUR:
 +		ivalue = g_value_get_int (value);
 +		ivalue = CLAMP (ivalue, 0, 24);
 +		if (ecde->lower_hour != ivalue) {
 +			ecde->lower_hour = ivalue;
 +			ecde->need_time_list_rebuild = TRUE;
 +		}
 +		return;
 +	case PROP_UPPER_HOUR:
 +		ivalue = g_value_get_int (value);
 +		ivalue = CLAMP (ivalue, 0, 24);
 +		if (ecde->upper_hour != ivalue) {
 +			ecde->upper_hour = ivalue;
 +			ecde->need_time_list_rebuild = TRUE;
 +		}
 +		return;
 +	}
 +
 +	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 +}
 +
 +
 +static gint
 +e_cell_date_edit_do_popup		(ECellPopup	*ecp,
 +					 GdkEvent	*event,
 +					 int             row,
 +					 int             view_col)
 +{
 +	ECellDateEdit *ecde = E_CELL_DATE_EDIT (ecp);
 +
 +	e_cell_date_edit_show_popup (ecde, row, view_col);
 +	e_cell_date_edit_set_popup_values (ecde);
 +
 +	gtk_grab_add (ecde->popup_window);
 +
 +	/* Set the focus to the first widget. */
 +	gtk_widget_grab_focus (ecde->time_entry);
 +	gdk_window_focus (ecde->popup_window->window, GDK_CURRENT_TIME);
 +
 +	return TRUE;
 +}
 +
 +
 +static void
 +e_cell_date_edit_set_popup_values	(ECellDateEdit	*ecde)
 +{
 +	ECellPopup *ecp = E_CELL_POPUP (ecde);
 +	ECellText *ecell_text = E_CELL_TEXT (ecp->child);
 +	ECellView *ecv = (ECellView*) ecp->popup_cell_view;
 +	ETableItem *eti = E_TABLE_ITEM (ecp->popup_cell_view->cell_view.e_table_item_view);
 +	ETableCol *ecol;
 +	char *cell_text;
 +	ETimeParseStatus status;
 +	struct tm date_tm;
 +	GDate date;
 +	ECalendarItem *calitem;
 +	char buffer[64];
 +	gboolean is_date = TRUE;
 +
 +	ecol = e_table_header_get_column (eti->header, ecp->popup_view_col);
 +	cell_text = e_cell_text_get_text (ecell_text, ecv->e_table_model,
 +					  ecol->col_idx, ecp->popup_row);
 +
 +	/* Try to parse just a date first. If the value is only a date, we
 +	   use a DATE value. */
 +	status = e_time_parse_date (cell_text, &date_tm);
 +	if (status == E_TIME_PARSE_INVALID) {
 +		is_date = FALSE;
 +		status = e_time_parse_date_and_time (cell_text, &date_tm);
 +	}
 +
 +	/* If there is no date and time set, or the date is invalid, we clear
 +	   the selections, else we select the appropriate date & time. */
 +	calitem = E_CALENDAR_ITEM (E_CALENDAR (ecde->calendar)->calitem);
 +	if (status == E_TIME_PARSE_NONE || status == E_TIME_PARSE_INVALID) {
 +		gtk_entry_set_text (GTK_ENTRY (ecde->time_entry), "");
 +		e_calendar_item_set_selection (calitem, NULL, NULL);
 +		gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (ecde->time_tree_view)));
 +	} else {
 +		if (is_date) {
 +			buffer[0] = '\0';
 +		} else {
 +			e_time_format_time (&date_tm, ecde->use_24_hour_format,
 +					    FALSE, buffer, sizeof (buffer));
 +		}
 +		gtk_entry_set_text (GTK_ENTRY (ecde->time_entry), buffer);
 +
 +		g_date_clear (&date, 1);
 +		g_date_set_dmy (&date, date_tm.tm_mday, date_tm.tm_mon + 1,
 +				date_tm.tm_year + 1900);
 +		e_calendar_item_set_selection (calitem, &date, &date);
 +
 +		if (is_date) {
 +			gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (ecde->time_tree_view)));
 +		} else {
 +			e_cell_date_edit_select_matching_time (ecde, buffer);
 +		}
 +	}
 +
 +	e_cell_text_free_text (ecell_text, cell_text);
 +}
 +
 +
 +static void
 +e_cell_date_edit_select_matching_time	(ECellDateEdit	*ecde,
 +					 char		*time)
 +{
 +	gboolean found = FALSE;
 +	gboolean valid;
 +	GtkTreeSelection *selection;
 +	GtkTreeIter iter;
 +	GtkTreeModel *model;
 +
 +	model = gtk_tree_view_get_model (GTK_TREE_VIEW (ecde->time_tree_view));
 +	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (ecde->time_tree_view));
 +
 +	for (valid = gtk_tree_model_get_iter_first (model, &iter);
 +	     valid && !found;
 +	     valid = gtk_tree_model_iter_next (model, &iter)) {
 +		char *str = NULL;
 +
 +		gtk_tree_model_get (model, &iter, 0, &str, -1);
 +
 +		if (g_str_equal (str, time)) {
 +			GtkTreePath *path = gtk_tree_model_get_path (model, &iter);
 +
 +			gtk_tree_view_set_cursor (GTK_TREE_VIEW (ecde->time_tree_view), path, NULL, FALSE);
 +			gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (ecde->time_tree_view), path, NULL, FALSE, 0.0, 0.0);
 +			gtk_tree_path_free (path);
 +
 +			found = TRUE;
 +		}
 +
 +		g_free (str);
 +	}
 +
 +	if (!found) {
 +		gtk_tree_selection_unselect_all (selection);
 +		gtk_tree_view_scroll_to_point (GTK_TREE_VIEW (ecde->time_tree_view), 0, 0);
 +	}
 +}
 +
 +
 +static void
 +e_cell_date_edit_show_popup		(ECellDateEdit	*ecde,
 +					 int             row,
 +					 int             view_col)
 +{
 +	gint x, y, width, height;
 +
 +	if (ecde->need_time_list_rebuild)
 +		e_cell_date_edit_rebuild_time_list (ecde);
 +
 +	/* This code is practically copied from GtkCombo. */
 +
 +	e_cell_date_edit_get_popup_pos (ecde, row, view_col, &x, &y, &height, &width);
 +
 +	gtk_window_move (GTK_WINDOW (ecde->popup_window), x, y);
 +	gtk_widget_set_size_request (ecde->popup_window, width, height);
 +	gtk_widget_realize (ecde->popup_window);
 +	gdk_window_resize (ecde->popup_window->window, width, height);
 +	gtk_widget_show (ecde->popup_window);
 +
 +	e_cell_popup_set_shown (E_CELL_POPUP (ecde), TRUE);
 +}
 +
 +
 +/* Calculates the size and position of the popup window (like GtkCombo). */
 +static void
 +e_cell_date_edit_get_popup_pos		(ECellDateEdit	*ecde,
 +					 int             row,
 +					 int             view_col,
 +					 gint		*x,
 +					 gint		*y,
 +					 gint		*height,
 +					 gint		*width)
 +{
 +	ECellPopup *ecp = E_CELL_POPUP (ecde);
 +	ETableItem *eti = E_TABLE_ITEM (ecp->popup_cell_view->cell_view.e_table_item_view);
 +	GtkWidget *canvas = GTK_WIDGET (GNOME_CANVAS_ITEM (eti)->canvas);
 +	GtkRequisition popup_requisition;
 +	gint avail_height, screen_width, column_width, row_height;
 +	double x1, y1, wx, wy;
 +
 +	gdk_window_get_origin (canvas->window, x, y);
 +
 +	x1 = e_table_header_col_diff (eti->header, 0, view_col + 1);
 +	y1 = e_table_item_row_diff (eti, 0, row + 1);
 +	column_width = e_table_header_col_diff (eti->header, view_col,
 +						view_col + 1);
 +	row_height = e_table_item_row_diff (eti, row,
 +					    row + 1);
 +	gnome_canvas_item_i2w (GNOME_CANVAS_ITEM (eti), &x1, &y1);
 +
 +	gnome_canvas_world_to_window (GNOME_CANVAS (canvas),
 +				      x1,
 +				      y1,
 +				      &wx,
 +				      &wy);
 +
 +	x1 = wx;
 +	y1 = wy;
 +
 +	*x += x1;
 +	/* The ETable positions don't include the grid lines, I think, so we
 +	   add 1. */
 +	*y += y1 + 1
 +		- (int)((GnomeCanvas *)canvas)->layout.vadjustment->value
 +		+ ((GnomeCanvas *)canvas)->zoom_yofs;
 +
 +	avail_height = gdk_screen_height () - *y;
 +
 +	/* We'll use the entire screen width if needed, but we save space for
 +	   the vertical scrollbar in case we need to show that. */
 +	screen_width = gdk_screen_width ();
 +
 +	gtk_widget_size_request (ecde->popup_window, &popup_requisition);
 +
 +	/* Calculate the desired width. */
 +	*width = popup_requisition.width;
 +
 +	/* Use at least the same width as the column. */
 +	if (*width < column_width)
 +		*width = column_width;
 +
 +	/* Check if it fits in the available height. */
 +	if (popup_requisition.height > avail_height) {
 +		/* It doesn't fit, so we see if we have the minimum space
 +		   needed. */
 +		if (*y - row_height > avail_height) {
 +			/* We don't, so we show the popup above the cell
 +			   instead of below it. */
 +			avail_height = *y - row_height;
 +			*y -= (popup_requisition.height + row_height);
 +			if (*y < 0)
 +				*y = 0;
 +		}
 +	}
 +
 +	/* We try to line it up with the right edge of the column, but we don't
 +	   want it to go off the edges of the screen. */
 +	if (*x > screen_width)
 +		*x = screen_width;
 +	*x -= *width;
 +	if (*x < 0)
 +		*x = 0;
 +
 +	*height = popup_requisition.height;
 +}
 +
 +
 +/* This handles key press events in the popup window. If the Escape key is
 +   pressed we hide the popup, and do not change the cell contents. */
 +static int
 +e_cell_date_edit_key_press		(GtkWidget	*popup_window,
 +					 GdkEventKey	*event,
 +					 ECellDateEdit	*ecde)
 +{
 +	/* If the Escape key is pressed we hide the popup. */
 +	if (event->keyval != GDK_Escape)
 +		return FALSE;
 +
 +	e_cell_date_edit_hide_popup (ecde);
 +
 +	return TRUE;
 +}
 +
 +
 +/* This handles button press events in the popup window. If the button is
 +   pressed outside the popup, we hide it and do not change the cell contents.
 +*/
 +static int
 +e_cell_date_edit_button_press		(GtkWidget	*popup_window,
 +					 GdkEventButton	*event,
 +					 ECellDateEdit	*ecde)
 +{
 +	GtkWidget *event_widget;
 +
 +	event_widget = gtk_get_event_widget ((GdkEvent*) event);
 +	if (gtk_widget_get_toplevel (event_widget) != popup_window) {
 +		e_cell_date_edit_hide_popup (ecde);
 +	}
 +
 +	return TRUE;
 +}
 +
 +
 +/* Clears the time list and rebuilds it using the lower_hour, upper_hour
 +   and use_24_hour_format settings. */
 +static void
 +e_cell_date_edit_rebuild_time_list		(ECellDateEdit	*ecde)
 +{
 +	GtkListStore *store;
 +	char buffer[40];
 +	struct tm tmp_tm;
 +	gint hour, min;
 +
 +	store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (ecde->time_tree_view)));
 +	gtk_list_store_clear (store);
 +
 +	/* Fill the struct tm with some sane values. */
 +	tmp_tm.tm_year = 2000;
 +	tmp_tm.tm_mon = 0;
 +	tmp_tm.tm_mday = 1;
 +	tmp_tm.tm_sec  = 0;
 +	tmp_tm.tm_isdst = 0;
 +
 +	for (hour = ecde->lower_hour; hour <= ecde->upper_hour; hour++) {
 +		/* We don't want to display midnight at the end, since that is
 +		   really in the next day. */
 +		if (hour == 24)
 +			break;
 +
 +		/* We want to finish on upper_hour, with min == 0. */
 +		for (min = 0;
 +		     min == 0 || (min < 60 && hour != ecde->upper_hour);
 +		     min += 30) {
 +			GtkTreeIter iter;
 +
 +			tmp_tm.tm_hour = hour;
 +			tmp_tm.tm_min  = min;
 +			e_time_format_time (&tmp_tm, ecde->use_24_hour_format,
 +					    FALSE, buffer, sizeof (buffer));
 +
 +			gtk_list_store_append (store, &iter);
 +			gtk_list_store_set (store, &iter, 0, buffer, -1);
 +		}
 +	}
 +
 +	ecde->need_time_list_rebuild = FALSE;
 +}
 +
 +
 +static void
 +e_cell_date_edit_on_ok_clicked		(GtkWidget	*button,
 +					 ECellDateEdit	*ecde)
 +{
 +	ECalendarItem *calitem;
 +	GDate start_date, end_date;
 +	gboolean day_selected;
 +	struct tm date_tm;
 +	char buffer[64];
 +	const char *text;
 +	ETimeParseStatus status;
 +	gboolean is_date = FALSE;
 +
 +	calitem = E_CALENDAR_ITEM (E_CALENDAR (ecde->calendar)->calitem);
 +	day_selected = e_calendar_item_get_selection (calitem, &start_date,
 +						      &end_date);
 +
 +	text = gtk_entry_get_text (GTK_ENTRY (ecde->time_entry));
 +	status = e_time_parse_time (text, &date_tm);
 +	if (status == E_TIME_PARSE_INVALID) {
 +		e_cell_date_edit_show_time_invalid_warning (ecde);
 +		return;
 +	} else if (status == E_TIME_PARSE_NONE) {
 +		is_date = TRUE;
 +	}
 +
 +	if (day_selected) {
 +		date_tm.tm_year = g_date_get_year (&start_date) - 1900;
 +		date_tm.tm_mon = g_date_get_month (&start_date) - 1;
 +		date_tm.tm_mday = g_date_get_day (&start_date);
 +		/* We need to call this to set the weekday. */
 +		mktime (&date_tm);
 +		e_time_format_date_and_time (&date_tm,
 +					     ecde->use_24_hour_format,
 +					     !is_date, FALSE,
 +					     buffer, sizeof (buffer));
 +	} else {
 +		buffer[0] = '\0';
 +	}
 +
 +	e_cell_date_edit_update_cell (ecde, buffer);
 +	e_cell_date_edit_hide_popup (ecde);
 +}
 +
 +
 +static void
 +e_cell_date_edit_show_time_invalid_warning	(ECellDateEdit	*ecde)
 +{
 +	GtkWidget *dialog;
 +	struct tm date_tm;
 +	char buffer[64];
 +
 +	/* Create a useful error message showing the correct format. */
 +	date_tm.tm_year = 100;
 +	date_tm.tm_mon = 0;
 +	date_tm.tm_mday = 1;
 +	date_tm.tm_hour = 1;
 +	date_tm.tm_min = 30;
 +	date_tm.tm_sec = 0;
 +	date_tm.tm_isdst = -1;
 +	e_time_format_time (&date_tm, ecde->use_24_hour_format, FALSE,
 +			    buffer, sizeof (buffer));
 +
 +	/* FIXME: Fix transient settings - I'm not sure it works with popup
 +	   windows. Maybe we need to use a normal window without decorations.*/
 +	dialog = gtk_message_dialog_new (
 +		GTK_WINDOW (ecde->popup_window),
 +		GTK_DIALOG_DESTROY_WITH_PARENT,
 +		GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
 +		_("The time must be in the format: %s"),
 +		buffer);
 +	gtk_dialog_run (GTK_DIALOG (dialog));
 +	gtk_widget_destroy (dialog);
 +}
 +
 +
 +static void
 +e_cell_date_edit_on_now_clicked		(GtkWidget	*button,
 +					 ECellDateEdit	*ecde)
 +{
 +	struct tm tmp_tm;
 +	time_t t;
 +	char buffer[64];
 +
 +	if (ecde->time_callback) {
 +		tmp_tm = (*ecde->time_callback) (ecde, ecde->time_callback_data);
 +	} else {
 +		t = time (NULL);
 +		tmp_tm = *localtime (&t);
 +	}
 +	e_time_format_date_and_time (&tmp_tm,
 +				     ecde->use_24_hour_format,
 +				     TRUE, FALSE,
 +				     buffer, sizeof (buffer));
 +
 +	e_cell_date_edit_update_cell (ecde, buffer);
 +	e_cell_date_edit_hide_popup (ecde);
 +}
 +
 +
 +static void
 +e_cell_date_edit_on_none_clicked	(GtkWidget	*button,
 +					 ECellDateEdit	*ecde)
 +{
 +	e_cell_date_edit_update_cell (ecde, "");
 +	e_cell_date_edit_hide_popup (ecde);
 +}
 +
 +
 +static void
 +e_cell_date_edit_on_today_clicked	(GtkWidget	*button,
 +					 ECellDateEdit	*ecde)
 +{
 +	struct tm tmp_tm;
 +	time_t t;
 +	char buffer[64];
 +
 +	if (ecde->time_callback) {
 +		tmp_tm = (*ecde->time_callback) (ecde, ecde->time_callback_data);
 +	} else {
 +		t = time (NULL);
 +		tmp_tm = *localtime (&t);
 +	}
 +
 +	tmp_tm.tm_hour = 0;
 +	tmp_tm.tm_min = 0;
 +	tmp_tm.tm_sec = 0;
 +	e_time_format_date_and_time (&tmp_tm,
 +				     ecde->use_24_hour_format,
 +				     FALSE, FALSE,
 +				     buffer, sizeof (buffer));
 +
 +	e_cell_date_edit_update_cell (ecde, buffer);
 +	e_cell_date_edit_hide_popup (ecde);
 +}
 +
 +
 +static void
 +e_cell_date_edit_update_cell		(ECellDateEdit	*ecde,
- 					 char		*text)
++					 const gchar	*text)
 +{
 +	ECellPopup *ecp = E_CELL_POPUP (ecde);
 +	ECellText *ecell_text = E_CELL_TEXT (ecp->child);
 +	ECellView *ecv = (ECellView*) ecp->popup_cell_view;
 +	ETableItem *eti = E_TABLE_ITEM (ecv->e_table_item_view);
 +	ETableCol *ecol;
 +	gchar *old_text;
 +
 +	/* Compare the new text with the existing cell contents. */
 +	ecol = e_table_header_get_column (eti->header, ecp->popup_view_col);
 +
 +	old_text = e_cell_text_get_text (ecell_text, ecv->e_table_model,
 +					 ecol->col_idx, ecp->popup_row);
 +
 +	/* If they are different, update the cell contents. */
 +	if (strcmp (old_text, text)) {
 +		e_cell_text_set_value (ecell_text, ecv->e_table_model,
 +				       ecol->col_idx, ecp->popup_row, text);
 +		e_cell_leave_edit (ecv, ecp->popup_view_col, ecol->col_idx, ecp->popup_row, NULL);
 +	}
 +
 +	e_cell_text_free_text (ecell_text, old_text);
 +}
 +
 +
 +static void
 +e_cell_date_edit_on_time_selected (GtkTreeSelection *selection, ECellDateEdit *ecde)
 +{
 +	gchar *list_item_text = NULL;
 +	GtkTreeIter iter;
 +	GtkTreeModel *model;
 +
 +	if (!gtk_tree_selection_get_selected (selection, &model, &iter))
 +		return;
 +
 +	gtk_tree_model_get (model, &iter, 0, &list_item_text, -1);
 +
 +	g_return_if_fail (list_item_text != NULL);
 +
 +	gtk_entry_set_text (GTK_ENTRY (ecde->time_entry), list_item_text);
 +
 +	g_free (list_item_text);
 +}
 +
 +
 +static void
 +e_cell_date_edit_hide_popup		(ECellDateEdit	*ecde)
 +{
 +	gtk_grab_remove (ecde->popup_window);
 +	gtk_widget_hide (ecde->popup_window);
 +	e_cell_popup_set_shown (E_CELL_POPUP (ecde), FALSE);
 +}
 +
 +
 +/* These freeze and thaw the rebuilding of the time list. They are useful when
 +   setting several properties which result in rebuilds of the list, e.g. the
 +   lower_hour, upper_hour and use_24_hour_format properties. */
 +void
 +e_cell_date_edit_freeze			(ECellDateEdit	*ecde)
 +{
 +	g_return_if_fail (E_IS_CELL_DATE_EDIT (ecde));
 +
 +	ecde->freeze_count++;
 +}
 +
 +
 +void
 +e_cell_date_edit_thaw			(ECellDateEdit	*ecde)
 +{
 +	g_return_if_fail (E_IS_CELL_DATE_EDIT (ecde));
 +
 +	if (ecde->freeze_count > 0) {
 +		ecde->freeze_count--;
 +
 +		if (ecde->freeze_count == 0)
 +			e_cell_date_edit_rebuild_time_list (ecde);
 +	}
 +}
 +
 +
 +/* Sets a callback to use to get the current time. This is useful if the
 +   application needs to use its own timezone data rather than rely on the
 +   Unix timezone. */
 +void
 +e_cell_date_edit_set_get_time_callback (ECellDateEdit	*ecde,
 +					ECellDateEditGetTimeCallback cb,
 +					gpointer	 data,
 +					GDestroyNotify   destroy)
 +{
 +	g_return_if_fail (E_IS_CELL_DATE_EDIT (ecde));
 +
 +	if (ecde->time_callback_data && ecde->time_callback_destroy)
 +		(*ecde->time_callback_destroy) (ecde->time_callback_data);
 +
 +	ecde->time_callback = cb;
 +	ecde->time_callback_data = data;
 +	ecde->time_callback_destroy = destroy;
 +}
diff --cc widgets/text/e-reflow.c
index c17b970,0000000..95f3f89
mode 100644,000000..100644
--- a/widgets/text/e-reflow.c
+++ b/widgets/text/e-reflow.c
@@@ -1,1534 -1,0 +1,1534 @@@
 +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 +/*
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Authors:
 + *              Chris Lahey <clahey ximian com>
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + */
 +#include <config.h>
 +
 +#include <math.h>
 +#include <string.h>
 +
 +#include <gdk/gdkkeysyms.h>
 +#include <gtk/gtk.h>
 +
 +#include "text/e-text.h"
 +#include <glib/gi18n.h>
 +#include "e-util/e-util.h"
 +#include "e-util/e-unicode.h"
 +
 +#include "misc/e-canvas.h"
 +#include "misc/e-canvas-utils.h"
 +#include "e-reflow.h"
 +#include "misc/e-selection-model-simple.h"
 +
 +static gboolean e_reflow_event (GnomeCanvasItem *item, GdkEvent *event);
 +static void e_reflow_realize (GnomeCanvasItem *item);
 +static void e_reflow_unrealize (GnomeCanvasItem *item);
 +static void e_reflow_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
 +				    int x, int y, int width, int height);
 +static void e_reflow_update (GnomeCanvasItem *item, double affine[6], ArtSVP *clip_path, gint flags);
 +static double e_reflow_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, GnomeCanvasItem **actual_item);
 +static void e_reflow_reflow (GnomeCanvasItem *item, int flags);
 +static void set_empty(EReflow *reflow);
 +
 +static void e_reflow_resize_children (GnomeCanvasItem *item);
 +
 +#define E_REFLOW_DIVIDER_WIDTH 2
 +#define E_REFLOW_BORDER_WIDTH 7
 +#define E_REFLOW_FULL_GUTTER (E_REFLOW_DIVIDER_WIDTH + E_REFLOW_BORDER_WIDTH * 2)
 +
 +G_DEFINE_TYPE (EReflow, e_reflow, GNOME_TYPE_CANVAS_GROUP)
 +
 +/* The arguments we take */
 +enum {
 +	PROP_0,
 +	PROP_MINIMUM_WIDTH,
 +	PROP_WIDTH,
 +	PROP_HEIGHT,
 +	PROP_EMPTY_MESSAGE,
 +	PROP_MODEL,
 +	PROP_COLUMN_WIDTH
 +};
 +
 +enum {
 +	SELECTION_EVENT,
 +	COLUMN_WIDTH_CHANGED,
 +	LAST_SIGNAL
 +};
 +
 +static guint signals [LAST_SIGNAL] = {0, };
 +
 +static gint
 +er_compare (int i1, int i2, gpointer user_data)
 +{
 +	EReflow *reflow = user_data;
 +	return e_reflow_model_compare (reflow->model, i1, i2);
 +}
 +
 +static gint
 +e_reflow_pick_line (EReflow *reflow, double x)
 +{
 +	x += E_REFLOW_BORDER_WIDTH + E_REFLOW_DIVIDER_WIDTH;
 +	x /= reflow->column_width + E_REFLOW_FULL_GUTTER;
 +	return x;
 +}
 +
 +static int
 +er_find_item (EReflow *reflow, GnomeCanvasItem *item)
 +{
 +	int i;
 +	for (i = 0; i < reflow->count; i++) {
 +		if (reflow->items[i] == item)
 +			return i;
 +	}
 +	return -1;
 +}
 +
 +static void
 +e_reflow_resize_children (GnomeCanvasItem *item)
 +{
 +	EReflow *reflow;
 +	int i;
 +	int count;
 +
 +	reflow = E_REFLOW (item);
 +
 +	count = reflow->count;
 +	for (i = 0; i < count; i++) {
 +		if (reflow->items[i])
 +			gnome_canvas_item_set(reflow->items[i],
 +					      "width", (double) reflow->column_width,
 +					      NULL);
 +	}
 +}
 +
 +static inline void
 +e_reflow_update_selection_row (EReflow *reflow, int row)
 +{
 +	if (reflow->items[row]) {
 +		g_object_set(reflow->items[row],
 +			     "selected", e_selection_model_is_row_selected(E_SELECTION_MODEL(reflow->selection), row),
 +			     NULL);
 +	} else if (e_selection_model_is_row_selected (E_SELECTION_MODEL (reflow->selection), row)) {
 +		reflow->items[row] = e_reflow_model_incarnate (reflow->model, row, GNOME_CANVAS_GROUP (reflow));
 +		g_object_set (reflow->items[row],
 +			      "selected", e_selection_model_is_row_selected(E_SELECTION_MODEL(reflow->selection), row),
 +			      "width", (double) reflow->column_width,
 +			      NULL);
 +	}
 +}
 +
 +static void
 +e_reflow_update_selection (EReflow *reflow)
 +{
 +	int i;
 +	int count;
 +
 +	count = reflow->count;
 +	for (i = 0; i < count; i++) {
 +		e_reflow_update_selection_row (reflow, i);
 +	}
 +}
 +
 +static void
 +selection_changed (ESelectionModel *selection, EReflow *reflow)
 +{
 +	e_reflow_update_selection (reflow);
 +}
 +
 +static void
 +selection_row_changed (ESelectionModel *selection, int row, EReflow *reflow)
 +{
 +	e_reflow_update_selection_row (reflow, row);
 +}
 +
 +static gboolean
 +do_adjustment (gpointer user_data)
 +{
 +	int row;
 +	GtkAdjustment *adj ;
 +	gfloat value, min_value, max_value;
 +	EReflow *reflow = user_data;
 +
 +	row = reflow->cursor_row;
 +	if (row == -1)
 +		return FALSE;
 +
 +	adj = gtk_layout_get_hadjustment (GTK_LAYOUT (GNOME_CANVAS_ITEM (reflow)->canvas));
 +	value = adj->value;
 +
 +	if ((!reflow->items) || (!reflow->items[row]))
 +		return TRUE;
 +	min_value = reflow->items[row]->x2 - adj->page_size;
 +	max_value = reflow->items[row]->x1;
 +
 +	if (value < min_value)
 +		value = min_value;
 +
 +	if (value > max_value)
 +		value = max_value;
 +
 +	if (value != adj->value) {
 +		adj->value = value;
 +		gtk_adjustment_value_changed (adj);
 +	}
 +
 +	reflow->do_adjustment_idle_id = 0;
 +
 +	return FALSE;
 +}
 +
 +static void
 +cursor_changed (ESelectionModel *selection, int row, int col, EReflow *reflow)
 +{
 +	int count = reflow->count;
 +	int old_cursor = reflow->cursor_row;
 +
 +	if (old_cursor < count && old_cursor >= 0) {
 +		if (reflow->items[old_cursor]) {
 +			g_object_set (reflow->items[old_cursor],
 +				      "has_cursor", FALSE,
 +				      NULL);
 +		}
 +	}
 +
 +	reflow->cursor_row = row;
 +
 +	if (row < count && row >= 0) {
 +		if (reflow->items[row]) {
 +			g_object_set (reflow->items[row],
 +				      "has_cursor", TRUE,
 +				      NULL);
 +		} else {
 +			reflow->items[row] = e_reflow_model_incarnate (reflow->model, row, GNOME_CANVAS_GROUP (reflow));
 +			g_object_set (reflow->items[row],
 +				      "has_cursor", TRUE,
 +				      "width", (double) reflow->column_width,
 +				      NULL);
 +		}
 +	}
 +
 +	if (reflow->do_adjustment_idle_id == 0)
 +		reflow->do_adjustment_idle_id = g_idle_add (do_adjustment, reflow);
 +
 +}
 +
 +
 +static void
 +incarnate (EReflow *reflow)
 +{
 +	int column_width;
 +	int first_column;
 +	int last_column;
 +	int first_cell;
 +	int last_cell;
 +	int i;
 +	GtkAdjustment *adjustment = gtk_layout_get_hadjustment (GTK_LAYOUT (GNOME_CANVAS_ITEM (reflow)->canvas));
 +
 +	column_width = reflow->column_width;
 +
 +	first_column = adjustment->value - 1 + E_REFLOW_BORDER_WIDTH;
 +	first_column /= column_width + E_REFLOW_FULL_GUTTER;
 +
 +	last_column = adjustment->value + adjustment->page_size + 1 - E_REFLOW_BORDER_WIDTH - E_REFLOW_DIVIDER_WIDTH;
 +	last_column /= column_width + E_REFLOW_FULL_GUTTER;
 +	last_column ++;
 +
 +	if (first_column >= 0 && first_column < reflow->column_count)
 +		first_cell = reflow->columns[first_column];
 +	else
 +		first_cell = 0;
 +
 +	if (last_column >= 0 && last_column < reflow->column_count)
 +		last_cell = reflow->columns[last_column];
 +	else
 +		last_cell = reflow->count;
 +
 +	for (i = first_cell; i < last_cell; i++) {
 +		int unsorted = e_sorter_sorted_to_model (E_SORTER (reflow->sorter), i);
 +		if (reflow->items[unsorted] == NULL) {
 +			if (reflow->model) {
 +				reflow->items[unsorted] = e_reflow_model_incarnate (reflow->model, unsorted, GNOME_CANVAS_GROUP (reflow));
 +				g_object_set (reflow->items[unsorted],
 +					      "selected", e_selection_model_is_row_selected(E_SELECTION_MODEL(reflow->selection), unsorted),
 +					      "width", (double) reflow->column_width,
 +					      NULL);
 +			}
 +		}
 +	}
 +	reflow->incarnate_idle_id = 0;
 +}
 +
 +static gboolean
 +invoke_incarnate (gpointer user_data)
 +{
 +	EReflow *reflow = user_data;
 +	incarnate (reflow);
 +	return FALSE;
 +}
 +
 +static void
 +queue_incarnate (EReflow *reflow)
 +{
 +	if (reflow->incarnate_idle_id == 0)
 +		reflow->incarnate_idle_id =
 +			g_idle_add_full (25, invoke_incarnate, reflow, NULL);
 +}
 +
 +static void
 +reflow_columns (EReflow *reflow)
 +{
 +	GSList *list;
 +	int count;
 +	int start;
 +	int i;
 +	int column_count, column_start;
 +	double running_height;
 +
 +	if (reflow->reflow_from_column <= 1) {
 +		start = 0;
 +		column_count = 1;
 +		column_start = 0;
 +	}
 +	else {
 +		/* we start one column before the earliest new entry,
 +		   so we can handle the case where the new entry is
 +		   inserted at the start of the column */
 +		column_start = reflow->reflow_from_column - 1;
 +		start = reflow->columns[column_start];
 +		column_count = column_start + 1;
 +	}
 +
 +	list = NULL;
 +
 +	running_height = E_REFLOW_BORDER_WIDTH;
 +
 +	count = reflow->count - start;
 +	for (i = start; i < count; i++) {
 +		int unsorted = e_sorter_sorted_to_model (E_SORTER (reflow->sorter), i);
 +		if (i != 0 && running_height + reflow->heights[unsorted] + E_REFLOW_BORDER_WIDTH > reflow->height) {
 +			list = g_slist_prepend (list, GINT_TO_POINTER(i));
 +			column_count ++;
 +			running_height = E_REFLOW_BORDER_WIDTH * 2 + reflow->heights[unsorted];
 +		} else
 +			running_height += reflow->heights[unsorted] + E_REFLOW_BORDER_WIDTH;
 +	}
 +
 +	reflow->column_count = column_count;
 +	reflow->columns = g_renew (int, reflow->columns, column_count);
 +	column_count --;
 +
 +	for (; column_count > column_start; column_count--) {
 +		GSList *to_free;
 +		reflow->columns[column_count] = GPOINTER_TO_INT(list->data);
 +		to_free = list;
 +		list = list->next;
 +		g_slist_free_1 (to_free);
 +	}
 +	reflow->columns[column_start] = start;
 +
 +	queue_incarnate (reflow);
 +
 +	reflow->need_reflow_columns = FALSE;
 +	reflow->reflow_from_column = -1;
 +}
 +
 +static void
 +item_changed (EReflowModel *model, int i, EReflow *reflow)
 +{
 +	if (i < 0 || i >= reflow->count)
 +		return;
 +
 +	reflow->heights[i] = e_reflow_model_height (reflow->model, i, GNOME_CANVAS_GROUP (reflow));
 +	if (reflow->items[i] != NULL)
 +		e_reflow_model_reincarnate (model, i, reflow->items[i]);
 +	e_sorter_array_clean (reflow->sorter);
 +	reflow->reflow_from_column = -1;
 +	reflow->need_reflow_columns = TRUE;
 +	e_canvas_item_request_reflow(GNOME_CANVAS_ITEM (reflow));
 +}
 +
 +static void
 +item_removed (EReflowModel *model, int i, EReflow *reflow)
 +{
 +	int c;
 +	int sorted;
 +
 +	if (i < 0 || i >= reflow->count)
 +		return;
 +
 +	sorted = e_sorter_model_to_sorted (E_SORTER (reflow->sorter), i);
 +	for (c = reflow->column_count - 1; c >= 0; c--) {
 +		int start_of_column = reflow->columns[c];
 +
 +		if (start_of_column <= sorted) {
 +			if (reflow->reflow_from_column == -1
 +			    || reflow->reflow_from_column > c) {
 +				reflow->reflow_from_column = c;
 +			}
 +			break;
 +		}
 +	}
 +
 +	if (reflow->items[i])
 +		gtk_object_destroy (GTK_OBJECT (reflow->items[i]));
 +
 +	memmove (reflow->heights + i, reflow->heights + i + 1, (reflow->count - i - 1) * sizeof (int));
 +	memmove (reflow->items + i, reflow->items + i + 1, (reflow->count - i - 1) * sizeof (GnomeCanvasItem *));
 +
 +	reflow->count --;
 +
 +	reflow->heights [reflow->count] = 0;
 +	reflow->items [reflow->count] = NULL;
 +
 +	reflow->need_reflow_columns = TRUE;
 +	set_empty (reflow);
 +	e_canvas_item_request_reflow(GNOME_CANVAS_ITEM (reflow));
 +
 +	e_sorter_array_set_count (reflow->sorter, reflow->count);
 +
 +	e_selection_model_simple_delete_rows (E_SELECTION_MODEL_SIMPLE (reflow->selection), i, 1);
 +}
 +
 +static void
 +items_inserted (EReflowModel *model, int position, int count, EReflow *reflow)
 +{
 +	int i, oldcount;
 +
 +	if (position < 0 || position > reflow->count)
 +		return;
 +
 +	oldcount = reflow->count;
 +
 +	reflow->count += count;
 +
 +	if (reflow->count > reflow->allocated_count) {
 +		while (reflow->count > reflow->allocated_count)
 +			reflow->allocated_count += 256;
 +		reflow->heights = g_renew (int, reflow->heights, reflow->allocated_count);
 +		reflow->items = g_renew (GnomeCanvasItem *, reflow->items, reflow->allocated_count);
 +	}
 +	memmove (reflow->heights + position + count, reflow->heights + position, (reflow->count - position - count) * sizeof (int));
 +	memmove (reflow->items + position + count, reflow->items + position, (reflow->count - position - count) * sizeof (GnomeCanvasItem *));
 +	for (i = position; i < position + count; i++) {
 +		reflow->items[i] = NULL;
 +		reflow->heights[i] = e_reflow_model_height (reflow->model, i, GNOME_CANVAS_GROUP (reflow));
 +	}
 +
 +	e_selection_model_simple_set_row_count (E_SELECTION_MODEL_SIMPLE (reflow->selection), reflow->count);
 +	if (position == oldcount)
 +		e_sorter_array_append (reflow->sorter, count);
 +	else
 +		e_sorter_array_set_count (reflow->sorter, reflow->count);
 +
 +	for (i = position; i < position + count; i ++) {
 +		int sorted = e_sorter_model_to_sorted (E_SORTER (reflow->sorter), i);
 +		int c;
 +
 +		for (c = reflow->column_count - 1; c >= 0; c--) {
 +			int start_of_column = reflow->columns[c];
 +
 +			if (start_of_column <= sorted) {
 +				if (reflow->reflow_from_column == -1
 +				    || reflow->reflow_from_column > c) {
 +					reflow->reflow_from_column = c;
 +				}
 +				break;
 +			}
 +		}
 +	}
 +
 +	reflow->need_reflow_columns = TRUE;
 +	set_empty (reflow);
 +	e_canvas_item_request_reflow(GNOME_CANVAS_ITEM (reflow));
 +}
 +
 +static void
 +model_changed (EReflowModel *model, EReflow *reflow)
 +{
 +	int i;
 +	int count;
 +	int oldcount;
 +
 +	count = reflow->count;
 +	oldcount = count;
 +
 +	for (i = 0; i < count; i++) {
 +		if (reflow->items[i])
 +			gtk_object_destroy (GTK_OBJECT (reflow->items[i]));
 +	}
 +	g_free (reflow->items);
 +	g_free (reflow->heights);
 +	reflow->count = e_reflow_model_count (model);
 +	reflow->allocated_count = reflow->count;
 +	reflow->items = g_new (GnomeCanvasItem *, reflow->count);
 +	reflow->heights = g_new (int, reflow->count);
 +
 +	count = reflow->count;
 +	for (i = 0; i < count; i++) {
 +		reflow->items[i] = NULL;
 +		reflow->heights[i] = e_reflow_model_height (reflow->model, i, GNOME_CANVAS_GROUP (reflow));
 +	}
 +
 +	e_selection_model_simple_set_row_count (E_SELECTION_MODEL_SIMPLE (reflow->selection), count);
 +	e_sorter_array_set_count (reflow->sorter, reflow->count);
 +
 +	reflow->need_reflow_columns = TRUE;
 +	if (oldcount > reflow->count)
 +		reflow_columns (reflow);
 +	set_empty (reflow);
 +	e_canvas_item_request_reflow(GNOME_CANVAS_ITEM (reflow));
 +}
 +
 +static void
 +comparison_changed (EReflowModel *model, EReflow *reflow)
 +{
 +	e_sorter_array_clean (reflow->sorter);
 +	reflow->reflow_from_column = -1;
 +	reflow->need_reflow_columns = TRUE;
 +	e_canvas_item_request_reflow(GNOME_CANVAS_ITEM (reflow));
 +}
 +
 +static void
 +set_empty(EReflow *reflow)
 +{
 +	if (reflow->count == 0) {
 +		if (reflow->empty_text) {
 +			if (reflow->empty_message) {
 +				gnome_canvas_item_set(reflow->empty_text,
 +						      "width", reflow->minimum_width,
 +						      "text", reflow->empty_message,
 +						      NULL);
 +				e_canvas_item_move_absolute(reflow->empty_text,
 +							    reflow->minimum_width / 2,
 +							    0);
 +			} else {
 +				gtk_object_destroy(GTK_OBJECT(reflow->empty_text));
 +				reflow->empty_text = NULL;
 +			}
 +		} else {
 +			if (reflow->empty_message) {
 +				reflow->empty_text =
 +					gnome_canvas_item_new(GNOME_CANVAS_GROUP(reflow),
 +							      e_text_get_type(),
 +							      "anchor", GTK_ANCHOR_N,
 +							      "width", reflow->minimum_width,
 +							      "clip", TRUE,
 +							      "use_ellipsis", TRUE,
 +							      "justification", GTK_JUSTIFY_CENTER,
 +							      "text", reflow->empty_message,
 +							      "draw_background", FALSE,
 +							      NULL);
 +				e_canvas_item_move_absolute(reflow->empty_text,
 +							    reflow->minimum_width / 2,
 +							    0);
 +			}
 +		}
 +	} else {
 +		if (reflow->empty_text) {
 +			gtk_object_destroy(GTK_OBJECT(reflow->empty_text));
 +			reflow->empty_text = NULL;
 +		}
 +	}
 +}
 +
 +static void
 +disconnect_model (EReflow *reflow)
 +{
 +	if (reflow->model == NULL)
 +		return;
 +
 +	g_signal_handler_disconnect (reflow->model,
 +				     reflow->model_changed_id);
 +	g_signal_handler_disconnect (reflow->model,
 +				     reflow->comparison_changed_id);
 +	g_signal_handler_disconnect (reflow->model,
 +				     reflow->model_items_inserted_id);
 +	g_signal_handler_disconnect (reflow->model,
 +				     reflow->model_item_removed_id);
 +	g_signal_handler_disconnect (reflow->model,
 +				     reflow->model_item_changed_id);
 +	g_object_unref (reflow->model);
 +
 +	reflow->model_changed_id        = 0;
 +	reflow->comparison_changed_id   = 0;
 +	reflow->model_items_inserted_id = 0;
 +	reflow->model_item_removed_id   = 0;
 +	reflow->model_item_changed_id   = 0;
 +	reflow->model                   = NULL;
 +}
 +
 +static void
 +disconnect_selection (EReflow *reflow)
 +{
 +	if (reflow->selection == NULL)
 +		return;
 +
 +	g_signal_handler_disconnect (reflow->selection,
 +				     reflow->selection_changed_id);
 +	g_signal_handler_disconnect (reflow->selection,
 +				     reflow->selection_row_changed_id);
 +	g_signal_handler_disconnect (reflow->selection,
 +				     reflow->cursor_changed_id);
 +	g_object_unref (reflow->selection);
 +
 +	reflow->selection_changed_id = 0;
 +	reflow->selection_row_changed_id = 0;
 +	reflow->cursor_changed_id = 0;
 +	reflow->selection            = NULL;
 +}
 +
 +static void
 +connect_model (EReflow *reflow, EReflowModel *model)
 +{
 +	if (reflow->model != NULL)
 +		disconnect_model (reflow);
 +
 +	if (model == NULL)
 +		return;
 +
 +	reflow->model = model;
 +	g_object_ref (reflow->model);
 +	reflow->model_changed_id =
 +		g_signal_connect (reflow->model, "model_changed",
 +				  G_CALLBACK (model_changed), reflow);
 +	reflow->comparison_changed_id =
 +		g_signal_connect (reflow->model, "comparison_changed",
 +				  G_CALLBACK (comparison_changed), reflow);
 +	reflow->model_items_inserted_id =
 +		g_signal_connect (reflow->model, "model_items_inserted",
 +				  G_CALLBACK (items_inserted), reflow);
 +	reflow->model_item_removed_id =
 +		g_signal_connect (reflow->model, "model_item_removed",
 +				  G_CALLBACK (item_removed), reflow);
 +	reflow->model_item_changed_id =
 +		g_signal_connect (reflow->model, "model_item_changed",
 +				  G_CALLBACK (item_changed), reflow);
 +	model_changed (model, reflow);
 +}
 +
 +static void
 +adjustment_changed (GtkAdjustment *adjustment, EReflow *reflow)
 +{
 +	queue_incarnate (reflow);
 +}
 +
 +static void
 +disconnect_adjustment (EReflow *reflow)
 +{
 +	if (reflow->adjustment == NULL)
 +		return;
 +
 +	g_signal_handler_disconnect (reflow->adjustment,
 +				     reflow->adjustment_changed_id);
 +	g_signal_handler_disconnect (reflow->adjustment,
 +				     reflow->adjustment_value_changed_id);
 +
 +	g_object_unref (reflow->adjustment);
 +
 +	reflow->adjustment_changed_id = 0;
 +	reflow->adjustment_value_changed_id = 0;
 +	reflow->adjustment = NULL;
 +}
 +
 +static void
 +connect_adjustment (EReflow *reflow, GtkAdjustment *adjustment)
 +{
 +	if (reflow->adjustment != NULL)
 +		disconnect_adjustment (reflow);
 +
 +	if (adjustment == NULL)
 +		return;
 +
 +	reflow->adjustment = adjustment;
 +	reflow->adjustment_changed_id =
 +		g_signal_connect (adjustment, "changed",
 +				  G_CALLBACK (adjustment_changed), reflow);
 +	reflow->adjustment_value_changed_id =
 +		g_signal_connect (adjustment, "value_changed",
 +				  G_CALLBACK (adjustment_changed), reflow);
 +	g_object_ref (adjustment);
 +}
 +
 +#if 0
 +static void
 +set_scroll_adjustments (GtkLayout *layout, GtkAdjustment *hadj, GtkAdjustment *vadj, EReflow *reflow)
 +{
 +	connect_adjustment (reflow, hadj);
 +}
 +
 +static void
 +connect_set_adjustment (EReflow *reflow)
 +{
 +	reflow->set_scroll_adjustments_id =
 +		g_signal_connect (GNOME_CANVAS_ITEM (reflow)->canvas,
 +				  "set_scroll_adjustments",
 +				  G_CALLBACK (set_scroll_adjustments), reflow);
 +}
 +#endif
 +
 +static void
 +disconnect_set_adjustment (EReflow *reflow)
 +{
 +	if (reflow->set_scroll_adjustments_id != 0) {
 +		g_signal_handler_disconnect (GNOME_CANVAS_ITEM (reflow)->canvas,
 +					     reflow->set_scroll_adjustments_id);
 +		reflow->set_scroll_adjustments_id = 0;
 +	}
 +}
 +
 +static void
 +column_width_changed (EReflow *reflow)
 +{
 +	g_signal_emit (reflow, signals[COLUMN_WIDTH_CHANGED], 0, reflow->column_width);
 +}
 +
 +
 +
 +
 +/* Virtual functions */
 +static void
 +e_reflow_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
 +{
 +	GnomeCanvasItem *item;
 +	EReflow *reflow;
 +
 +	item = GNOME_CANVAS_ITEM (object);
 +	reflow = E_REFLOW (object);
 +
 +	switch (prop_id){
 +	case PROP_HEIGHT:
 +		reflow->height = g_value_get_double (value);
 +		reflow->need_reflow_columns = TRUE;
 +		e_canvas_item_request_reflow(item);
 +		break;
 +	case PROP_MINIMUM_WIDTH:
 +		reflow->minimum_width = g_value_get_double (value);
 +		if (GNOME_CANVAS_ITEM_REALIZED & GTK_OBJECT_FLAGS(object))
 +			set_empty(reflow);
 +		e_canvas_item_request_reflow(item);
 +		break;
 +	case PROP_EMPTY_MESSAGE:
 +		g_free(reflow->empty_message);
 +		reflow->empty_message = g_strdup(g_value_get_string (value));
 +		if (GNOME_CANVAS_ITEM_REALIZED & GTK_OBJECT_FLAGS(object))
 +			set_empty(reflow);
 +		break;
 +	case PROP_MODEL:
 +		connect_model (reflow, (EReflowModel *) g_value_get_object (value));
 +		break;
 +	case PROP_COLUMN_WIDTH:
 +		if (reflow->column_width != g_value_get_double (value)) {
 +			GtkAdjustment *adjustment = gtk_layout_get_hadjustment(GTK_LAYOUT(item->canvas));
 +			double old_width = reflow->column_width;
 +
 +			reflow->column_width = g_value_get_double (value);
 +			adjustment->step_increment = (reflow->column_width + E_REFLOW_FULL_GUTTER) / 2;
 +			adjustment->page_increment = adjustment->page_size - adjustment->step_increment;
 +			gtk_adjustment_changed(adjustment);
 +			e_reflow_resize_children(item);
 +			e_canvas_item_request_reflow(item);
 +
 +			reflow->need_column_resize = TRUE;
 +			gnome_canvas_item_request_update(item);
 +
 +			if (old_width != reflow->column_width)
 +				column_width_changed (reflow);
 +		}
 +		break;
 +	}
 +}
 +
 +static void
 +e_reflow_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
 +{
 +	EReflow *reflow;
 +
 +	reflow = E_REFLOW (object);
 +
 +	switch (prop_id) {
 +	case PROP_MINIMUM_WIDTH:
 +		g_value_set_double (value, reflow->minimum_width);
 +		break;
 +	case PROP_WIDTH:
 +		g_value_set_double (value, reflow->width);
 +		break;
 +	case PROP_HEIGHT:
 +		g_value_set_double (value, reflow->height);
 +		break;
 +	case PROP_EMPTY_MESSAGE:
 +		g_value_set_string (value, reflow->empty_message);
 +		break;
 +	case PROP_MODEL:
 +		g_value_set_object (value, reflow->model);
 +		break;
 +	case PROP_COLUMN_WIDTH:
 +		g_value_set_double (value, reflow->column_width);
 +		break;
 +	default:
 +		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 +		break;
 +	}
 +}
 +
 +static void
 +e_reflow_dispose (GObject *object)
 +{
 +	EReflow *reflow = E_REFLOW(object);
 +
 +	g_free (reflow->items);
 +	g_free (reflow->heights);
 +	g_free (reflow->columns);
 +
 +	reflow->items          = NULL;
 +	reflow->heights        = NULL;
 +	reflow->columns        = NULL;
 +	reflow->count          = 0;
 +	reflow->allocated_count = 0;
 +
 +	if (reflow->incarnate_idle_id)
 +		g_source_remove (reflow->incarnate_idle_id);
 +	reflow->incarnate_idle_id = 0;
 +
 +	if (reflow->do_adjustment_idle_id)
 +		g_source_remove (reflow->do_adjustment_idle_id);
 +	reflow->do_adjustment_idle_id = 0;
 +
 +	disconnect_model (reflow);
 +	disconnect_selection (reflow);
 +
 +	g_free(reflow->empty_message);
 +	reflow->empty_message = NULL;
 +
 +	if (reflow->sorter) {
 +		g_object_unref (reflow->sorter);
 +		reflow->sorter = NULL;
 +	}
 +
 +	G_OBJECT_CLASS(e_reflow_parent_class)->dispose (object);
 +}
 +
 +static void
 +e_reflow_realize (GnomeCanvasItem *item)
 +{
 +	EReflow *reflow;
 +	GtkAdjustment *adjustment;
 +	int count;
 +	int i;
 +
 +	reflow = E_REFLOW (item);
 +
 +	if (GNOME_CANVAS_ITEM_CLASS(e_reflow_parent_class)->realize)
 +		(* GNOME_CANVAS_ITEM_CLASS(e_reflow_parent_class)->realize) (item);
 +
 +	reflow->arrow_cursor = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW);
 +	reflow->default_cursor = gdk_cursor_new (GDK_LEFT_PTR);
 +
 +	count = reflow->count;
 +	for(i = 0; i < count; i++) {
 +		if (reflow->items[i])
 +			gnome_canvas_item_set(reflow->items[i],
 +					      "width", reflow->column_width,
 +					      NULL);
 +	}
 +
 +	set_empty(reflow);
 +
 +	reflow->need_reflow_columns = TRUE;
 +	e_canvas_item_request_reflow(item);
 +
 +	adjustment = gtk_layout_get_hadjustment(GTK_LAYOUT(item->canvas));
 +
 +#if 0
 +	connect_set_adjustment (reflow);
 +#endif
 +	connect_adjustment (reflow, adjustment);
 +
 +	adjustment->step_increment = (reflow->column_width + E_REFLOW_FULL_GUTTER) / 2;
 +	adjustment->page_increment = adjustment->page_size - adjustment->step_increment;
 +	gtk_adjustment_changed(adjustment);
 +
 +	if (!item->canvas->aa) {
 +	}
 +}
 +
 +static void
 +e_reflow_unrealize (GnomeCanvasItem *item)
 +{
 +	EReflow *reflow;
 +
 +	reflow = E_REFLOW (item);
 +
 +	if (!item->canvas->aa) {
 +	}
 +
 +	gdk_cursor_unref (reflow->arrow_cursor);
 +	gdk_cursor_unref (reflow->default_cursor);
 +	reflow->arrow_cursor = NULL;
 +	reflow->default_cursor = NULL;
 +
 +	g_free (reflow->columns);
 +	reflow->columns = NULL;
 +
 +	disconnect_set_adjustment (reflow);
 +	disconnect_adjustment (reflow);
 +
 +	if (GNOME_CANVAS_ITEM_CLASS(e_reflow_parent_class)->unrealize)
 +		(* GNOME_CANVAS_ITEM_CLASS(e_reflow_parent_class)->unrealize) (item);
 +}
 +
 +static gboolean
 +e_reflow_event (GnomeCanvasItem *item, GdkEvent *event)
 +{
 +	EReflow *reflow;
 +	int return_val = FALSE;
 +
 +	reflow = E_REFLOW (item);
 +
 +	switch( event->type )
 +		{
 +		case GDK_KEY_PRESS:
 +			return_val = e_selection_model_key_press(reflow->selection, (GdkEventKey *) event);
 +			break;
 +#if 0
 +			if (event->key.keyval == GDK_Tab ||
 +			    event->key.keyval == GDK_KP_Tab ||
 +			    event->key.keyval == GDK_ISO_Left_Tab) {
 +				int i;
 +				int count;
 +				count = reflow->count;
 +				for (i = 0; i < count; i++) {
 +					int unsorted = e_sorter_sorted_to_model (E_SORTER (reflow->sorter), i);
 +					GnomeCanvasItem *item = reflow->items[unsorted];
 +					EFocus has_focus;
 +					if (item) {
 +						g_object_get(item,
 +							     "has_focus", &has_focus,
 +							     NULL);
 +						if (has_focus) {
 +							if (event->key.state & GDK_SHIFT_MASK) {
 +								if (i == 0)
 +									return FALSE;
 +								i--;
 +							} else {
 +								if (i == count - 1)
 +									return FALSE;
 +								i++;
 +							}
 +
 +							unsorted = e_sorter_sorted_to_model (E_SORTER (reflow->sorter), i);
 +							if (reflow->items[unsorted] == NULL) {
 +								reflow->items[unsorted] = e_reflow_model_incarnate (reflow->model, unsorted, GNOME_CANVAS_GROUP (reflow));
 +							}
 +
 +							item = reflow->items[unsorted];
 +							gnome_canvas_item_set(item,
 +									      "has_focus", (event->key.state & GDK_SHIFT_MASK) ? E_FOCUS_END : E_FOCUS_START,
 +									      NULL);
 +							return TRUE;
 +						}
 +					}
 +				}
 +			}
 +#endif
 +		case GDK_BUTTON_PRESS:
 +			switch(event->button.button)
 +				{
 +				case 1:
 +					{
 +						GdkEventButton *button = (GdkEventButton *) event;
 +						double n_x;
 +						n_x = button->x;
 +						n_x += E_REFLOW_BORDER_WIDTH + E_REFLOW_DIVIDER_WIDTH;
 +						n_x = fmod(n_x,(reflow->column_width + E_REFLOW_FULL_GUTTER));
 +
 +						if ( button->y >= E_REFLOW_BORDER_WIDTH && button->y <= reflow->height - E_REFLOW_BORDER_WIDTH && n_x < E_REFLOW_FULL_GUTTER ) {
 +							/* don't allow to drag the first line*/
 +							if (e_reflow_pick_line(reflow, button->x) == 0)
 +								return TRUE;
 +							reflow->which_column_dragged = e_reflow_pick_line(reflow, button->x);
 +							reflow->start_x = reflow->which_column_dragged * (reflow->column_width + E_REFLOW_FULL_GUTTER) - E_REFLOW_DIVIDER_WIDTH / 2;
 +							reflow->temp_column_width = reflow->column_width;
 +							reflow->column_drag = TRUE;
 +
 +							gnome_canvas_item_grab (item,
 +										GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK,
 +										reflow->arrow_cursor,
 +										button->time);
 +
 +							reflow->previous_temp_column_width = -1;
 +							reflow->need_column_resize = TRUE;
 +							gnome_canvas_item_request_update(item);
 +							return TRUE;
 +						}
 +					}
 +					break;
 +				case 4:
 +					{
 +						GtkAdjustment *adjustment = gtk_layout_get_hadjustment(GTK_LAYOUT(item->canvas));
 +						gdouble new_value = adjustment->value;
 +						new_value -= adjustment->step_increment;
 +						gtk_adjustment_set_value(adjustment, new_value);
 +					}
 +					break;
 +				case 5:
 +					{
 +						GtkAdjustment *adjustment = gtk_layout_get_hadjustment(GTK_LAYOUT(item->canvas));
 +						gdouble new_value = adjustment->value;
 +						new_value += adjustment->step_increment;
 +						if ( new_value > adjustment->upper - adjustment->page_size )
 +							new_value = adjustment->upper - adjustment->page_size;
 +						gtk_adjustment_set_value(adjustment, new_value);
 +					}
 +					break;
 +				}
 +			break;
 +		case GDK_BUTTON_RELEASE:
 +			if (reflow->column_drag) {
 +				gdouble old_width = reflow->column_width;
 +				GdkEventButton *button = (GdkEventButton *) event;
 +				GtkAdjustment *adjustment = gtk_layout_get_hadjustment(GTK_LAYOUT(item->canvas));
 +				reflow->temp_column_width = reflow->column_width +
 +					(button->x - reflow->start_x)/(reflow->which_column_dragged - e_reflow_pick_line(reflow, adjustment->value));
 +				if ( reflow->temp_column_width < 50 )
 +					reflow->temp_column_width = 50;
 +				reflow->column_drag = FALSE;
 +				if ( old_width != reflow->temp_column_width ) {
 +					gtk_adjustment_set_value(adjustment, adjustment->value + e_reflow_pick_line(reflow, adjustment->value) * (reflow->temp_column_width - reflow->column_width));
 +					reflow->column_width = reflow->temp_column_width;
 +					adjustment->step_increment = (reflow->column_width + E_REFLOW_FULL_GUTTER) / 2;
 +					adjustment->page_increment = adjustment->page_size - adjustment->step_increment;
 +					gtk_adjustment_changed(adjustment);
 +					e_reflow_resize_children(item);
 +					e_canvas_item_request_reflow(item);
 +					gnome_canvas_request_redraw(item->canvas, 0, 0, reflow->width, reflow->height);
 +					column_width_changed (reflow);
 +				}
 +				reflow->need_column_resize = TRUE;
 +				gnome_canvas_item_request_update(item);
 +				gnome_canvas_item_ungrab (item, button->time);
 +				return TRUE;
 +			}
 +			break;
 +		case GDK_MOTION_NOTIFY:
 +			if (reflow->column_drag) {
 +				double old_width = reflow->temp_column_width;
 +				GdkEventMotion *motion = (GdkEventMotion *) event;
 +				GtkAdjustment *adjustment = gtk_layout_get_hadjustment(GTK_LAYOUT(item->canvas));
 +				reflow->temp_column_width = reflow->column_width +
 +					(motion->x - reflow->start_x)/(reflow->which_column_dragged - e_reflow_pick_line(reflow, adjustment->value));
 +				if (reflow->temp_column_width < 50)
 +					reflow->temp_column_width = 50;
 +				if (old_width != reflow->temp_column_width) {
 +					reflow->need_column_resize = TRUE;
 +					gnome_canvas_item_request_update(item);
 +				}
 +				return TRUE;
 +			} else {
 +				GdkEventMotion *motion = (GdkEventMotion *) event;
 +				double n_x;
 +
 +				n_x = motion->x;
 +				n_x += E_REFLOW_BORDER_WIDTH + E_REFLOW_DIVIDER_WIDTH;
 +				n_x = fmod(n_x,(reflow->column_width + E_REFLOW_FULL_GUTTER));
 +
 +				if ( motion->y >= E_REFLOW_BORDER_WIDTH && motion->y <= reflow->height - E_REFLOW_BORDER_WIDTH && n_x < E_REFLOW_FULL_GUTTER ) {
 +					if ( reflow->default_cursor_shown ) {
 +						gdk_window_set_cursor(GTK_WIDGET(item->canvas)->window, reflow->arrow_cursor);
 +						reflow->default_cursor_shown = FALSE;
 +					}
 +				} else
 +					if ( ! reflow->default_cursor_shown ) {
 +						gdk_window_set_cursor(GTK_WIDGET(item->canvas)->window, reflow->default_cursor);
 +						reflow->default_cursor_shown = TRUE;
 +					}
 +
 +			}
 +			break;
 +		case GDK_ENTER_NOTIFY:
 +			if (!reflow->column_drag) {
 +				GdkEventCrossing *crossing = (GdkEventCrossing *) event;
 +				double n_x;
 +				n_x = crossing->x;
 +				n_x += E_REFLOW_BORDER_WIDTH + E_REFLOW_DIVIDER_WIDTH;
 +				n_x = fmod(n_x,(reflow->column_width + E_REFLOW_FULL_GUTTER));
 +
 +				if ( crossing->y >= E_REFLOW_BORDER_WIDTH && crossing->y <= reflow->height - E_REFLOW_BORDER_WIDTH && n_x < E_REFLOW_FULL_GUTTER ) {
 +					if ( reflow->default_cursor_shown ) {
 +						gdk_window_set_cursor(GTK_WIDGET(item->canvas)->window, reflow->arrow_cursor);
 +						reflow->default_cursor_shown = FALSE;
 +					}
 +				}
 +			}
 +			break;
 +		case GDK_LEAVE_NOTIFY:
 +			if (!reflow->column_drag) {
 +				GdkEventCrossing *crossing = (GdkEventCrossing *) event;
 +				double n_x;
 +				n_x = crossing->x;
 +				n_x += E_REFLOW_BORDER_WIDTH + E_REFLOW_DIVIDER_WIDTH;
 +				n_x = fmod(n_x,(reflow->column_width + E_REFLOW_FULL_GUTTER));
 +				if ( !( crossing->y >= E_REFLOW_BORDER_WIDTH && crossing->y <= reflow->height - E_REFLOW_BORDER_WIDTH && n_x < E_REFLOW_FULL_GUTTER ) ) {
 +					if ( ! reflow->default_cursor_shown ) {
 +						gdk_window_set_cursor(GTK_WIDGET(item->canvas)->window, reflow->default_cursor);
 +						reflow->default_cursor_shown = TRUE;
 +					}
 +				}
 +			}
 +			break;
 +		default:
 +			break;
 +		}
 +	if (return_val)
 +		return return_val;
 +	else if (GNOME_CANVAS_ITEM_CLASS( e_reflow_parent_class )->event)
 +		return (* GNOME_CANVAS_ITEM_CLASS( e_reflow_parent_class )->event) (item, event);
 +	else
 +		return FALSE;
 +}
 +
 +static void e_reflow_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
 +				    int x, int y, int width, int height)
 +{
 +	int x_rect, y_rect, width_rect, height_rect;
 +	gdouble running_width;
 +	EReflow *reflow = E_REFLOW(item);
 +	int i;
 +	double column_width;
 +
 +	if (GNOME_CANVAS_ITEM_CLASS(e_reflow_parent_class)->draw)
 +		GNOME_CANVAS_ITEM_CLASS(e_reflow_parent_class)->draw (item, drawable, x, y, width, height);
 +	column_width = reflow->column_width;
 +	running_width = E_REFLOW_BORDER_WIDTH + column_width + E_REFLOW_BORDER_WIDTH;
 +	x_rect = running_width;
 +	y_rect = E_REFLOW_BORDER_WIDTH;
 +	width_rect = E_REFLOW_DIVIDER_WIDTH;
 +	height_rect = reflow->height - (E_REFLOW_BORDER_WIDTH * 2);
 +
 +	/* Compute first column to draw. */
 +	i = x;
 +	i /= column_width + E_REFLOW_FULL_GUTTER;
 +	running_width += i * (column_width + E_REFLOW_FULL_GUTTER);
 +
 +	for ( ; i < reflow->column_count; i++) {
 +		if ( running_width > x + width )
 +			break;
 +		x_rect = running_width;
 +		gtk_paint_flat_box(GTK_WIDGET(item->canvas)->style,
 +				   drawable,
 +				   GTK_STATE_ACTIVE,
 +				   GTK_SHADOW_NONE,
 +				   NULL,
 +				   GTK_WIDGET(item->canvas),
 +				   "reflow",
 +				   x_rect - x,
 +				   y_rect - y,
 +				   width_rect,
 +				   height_rect);
 +		running_width += E_REFLOW_DIVIDER_WIDTH + E_REFLOW_BORDER_WIDTH + column_width + E_REFLOW_BORDER_WIDTH;
 +	}
 +	if (reflow->column_drag) {
 +		int start_line = e_reflow_pick_line(reflow,
 +						    gtk_layout_get_hadjustment(GTK_LAYOUT(item->canvas))->value);
 +		i = x - start_line * (column_width + E_REFLOW_FULL_GUTTER);
 +		running_width = start_line * (column_width + E_REFLOW_FULL_GUTTER);
 +		column_width = reflow->temp_column_width;
 +		running_width -= start_line * (column_width + E_REFLOW_FULL_GUTTER);
 +		i += start_line * (column_width + E_REFLOW_FULL_GUTTER);
 +		running_width += E_REFLOW_BORDER_WIDTH + column_width + E_REFLOW_BORDER_WIDTH;
 +		x_rect = running_width;
 +		y_rect = E_REFLOW_BORDER_WIDTH;
 +		width_rect = E_REFLOW_DIVIDER_WIDTH;
 +		height_rect = reflow->height - (E_REFLOW_BORDER_WIDTH * 2);
 +
 +		/* Compute first column to draw. */
 +		i /= column_width + E_REFLOW_FULL_GUTTER;
 +		running_width += i * (column_width + E_REFLOW_FULL_GUTTER);
 +
 +		for ( ; i < reflow->column_count; i++) {
 +			if ( running_width > x + width )
 +				break;
 +			x_rect = running_width;
 +			gdk_draw_rectangle(drawable,
 +					   GTK_WIDGET(item->canvas)->style->fg_gc[GTK_STATE_NORMAL],
 +					   TRUE,
 +					   x_rect - x,
 +					   y_rect - y,
 +					   width_rect - 1,
 +					   height_rect - 1);
 +			running_width += E_REFLOW_DIVIDER_WIDTH + E_REFLOW_BORDER_WIDTH + column_width + E_REFLOW_BORDER_WIDTH;
 +		}
 +	}
 +}
 +
 +static void
 +e_reflow_update (GnomeCanvasItem *item, double affine[6], ArtSVP *clip_path, gint flags)
 +{
 +	EReflow *reflow;
 +	double x0, x1, y0, y1;
 +
 +	reflow = E_REFLOW (item);
 +
 +	if (GNOME_CANVAS_ITEM_CLASS(e_reflow_parent_class)->update)
 +		GNOME_CANVAS_ITEM_CLASS(e_reflow_parent_class)->update (item, affine, clip_path, flags);
 +
 +	x0 = item->x1;
 +	y0 = item->y1;
 +	x1 = item->x2;
 +	y1 = item->y2;
 +	if ( x1 < x0 + reflow->width )
 +		x1 = x0 + reflow->width;
 +	if ( y1 < y0 + reflow->height )
 +		y1 = y0 + reflow->height;
 +	item->x2 = x1;
 +	item->y2 = y1;
 +
 +	if (reflow->need_height_update) {
 +		x0 = item->x1;
 +		y0 = item->y1;
 +		x1 = item->x2;
 +		y1 = item->y2;
 +		if ( x0 > 0 )
 +			x0 = 0;
 +		if ( y0 > 0 )
 +			y0 = 0;
 +		if ( x1 < E_REFLOW(item)->width )
 +			x1 = E_REFLOW(item)->width;
 +		if ( x1 < E_REFLOW(item)->height )
 +			x1 = E_REFLOW(item)->height;
 +
 +		gnome_canvas_request_redraw(item->canvas, x0, y0, x1, y1);
 +		reflow->need_height_update = FALSE;
 +	} else if (reflow->need_column_resize) {
 +		int x_rect, y_rect, width_rect, height_rect;
 +		int start_line = e_reflow_pick_line(reflow,
 +						    gtk_layout_get_hadjustment(GTK_LAYOUT(item->canvas))->value);
 +		gdouble running_width;
 +		int i;
 +		double column_width;
 +
 +		if ( reflow->previous_temp_column_width != -1 ) {
 +			running_width = start_line * (reflow->column_width + E_REFLOW_FULL_GUTTER);
 +			column_width = reflow->previous_temp_column_width;
 +			running_width -= start_line * (column_width + E_REFLOW_FULL_GUTTER);
 +			running_width += E_REFLOW_BORDER_WIDTH + column_width + E_REFLOW_BORDER_WIDTH;
 +			y_rect = E_REFLOW_BORDER_WIDTH;
 +			width_rect = E_REFLOW_DIVIDER_WIDTH;
 +			height_rect = reflow->height - (E_REFLOW_BORDER_WIDTH * 2);
 +
 +			for ( i = 0; i < reflow->column_count; i++) {
 +				x_rect = running_width;
 +				gnome_canvas_request_redraw(item->canvas, x_rect, y_rect, x_rect + width_rect, y_rect + height_rect);
 +				running_width += E_REFLOW_DIVIDER_WIDTH + E_REFLOW_BORDER_WIDTH + column_width + E_REFLOW_BORDER_WIDTH;
 +			}
 +		}
 +
 +		if ( reflow->temp_column_width != -1 ) {
 +			running_width = start_line * (reflow->column_width + E_REFLOW_FULL_GUTTER);
 +			column_width = reflow->temp_column_width;
 +			running_width -= start_line * (column_width + E_REFLOW_FULL_GUTTER);
 +			running_width += E_REFLOW_BORDER_WIDTH + column_width + E_REFLOW_BORDER_WIDTH;
 +			y_rect = E_REFLOW_BORDER_WIDTH;
 +			width_rect = E_REFLOW_DIVIDER_WIDTH;
 +			height_rect = reflow->height - (E_REFLOW_BORDER_WIDTH * 2);
 +
 +			for ( i = 0; i < reflow->column_count; i++) {
 +				x_rect = running_width;
 +				gnome_canvas_request_redraw(item->canvas, x_rect, y_rect, x_rect + width_rect, y_rect + height_rect);
 +				running_width += E_REFLOW_DIVIDER_WIDTH + E_REFLOW_BORDER_WIDTH + column_width + E_REFLOW_BORDER_WIDTH;
 +			}
 +		}
 +
 +		reflow->previous_temp_column_width = reflow->temp_column_width;
 +		reflow->need_column_resize = FALSE;
 +	}
 +}
 +
 +static double
 +e_reflow_point (GnomeCanvasItem *item,
 +		double x, double y, int cx, int cy,
 +		GnomeCanvasItem **actual_item)
 +{
 +	double distance = 1;
 +
 +	*actual_item = NULL;
 +
 +	if (GNOME_CANVAS_ITEM_CLASS(e_reflow_parent_class)->point)
 +		distance = GNOME_CANVAS_ITEM_CLASS(e_reflow_parent_class)->point (item, x, y, cx, cy, actual_item);
 +	if ((int) (distance * item->canvas->pixels_per_unit + 0.5) <= item->canvas->close_enough && *actual_item)
 +		return distance;
 +
 +	*actual_item = item;
 +	return 0;
 +#if 0
 +	if (y >= E_REFLOW_BORDER_WIDTH && y <= reflow->height - E_REFLOW_BORDER_WIDTH) {
 +	        float n_x;
 +		n_x = x;
 +		n_x += E_REFLOW_BORDER_WIDTH + E_REFLOW_DIVIDER_WIDTH;
 +		n_x = fmod(n_x, (reflow->column_width + E_REFLOW_FULL_GUTTER));
 +		if (n_x < E_REFLOW_FULL_GUTTER) {
 +			*actual_item = item;
 +			return 0;
 +		}
 +	}
 +	return distance;
 +#endif
 +}
 +
 +static void
 +e_reflow_reflow( GnomeCanvasItem *item, int flags )
 +{
 +	EReflow *reflow = E_REFLOW(item);
 +	gdouble old_width;
 +	gdouble running_width;
 +	gdouble running_height;
 +	int next_column;
 +	int i;
 +
 +	if (! (GTK_OBJECT_FLAGS (reflow) & GNOME_CANVAS_ITEM_REALIZED))
 +		return;
 +
 +	if (reflow->need_reflow_columns) {
 +		reflow_columns (reflow);
 +	}
 +
 +	old_width = reflow->width;
 +
 +	running_width = E_REFLOW_BORDER_WIDTH;
 +	running_height = E_REFLOW_BORDER_WIDTH;
 +
 +	next_column = 1;
 +
 +	for (i = 0; i < reflow->count; i++) {
 +		int unsorted = e_sorter_sorted_to_model (E_SORTER (reflow->sorter), i);
 +		if (next_column < reflow->column_count && i == reflow->columns[next_column]) {
 +			running_height = E_REFLOW_BORDER_WIDTH;
 +			running_width += reflow->column_width + E_REFLOW_FULL_GUTTER;
 +			next_column ++;
 +		}
 +
 +		if (unsorted >= 0 && reflow->items[unsorted]) {
 +			e_canvas_item_move_absolute(GNOME_CANVAS_ITEM(reflow->items[unsorted]),
 +						    (double) running_width,
 +						    (double) running_height);
 +			running_height += reflow->heights[unsorted] + E_REFLOW_BORDER_WIDTH;
 +		}
 +	}
 +	reflow->width = running_width + reflow->column_width + E_REFLOW_BORDER_WIDTH;
 +	if ( reflow->width < reflow->minimum_width )
 +		reflow->width = reflow->minimum_width;
 +	if (old_width != reflow->width)
 +		e_canvas_item_request_parent_reflow(item);
 +}
 +
 +static int
 +e_reflow_selection_event_real (EReflow *reflow, GnomeCanvasItem *item, GdkEvent *event)
 +{
 +	int row;
 +	int return_val = TRUE;
 +	switch (event->type) {
 +	case GDK_BUTTON_PRESS:
 +		switch (event->button.button) {
 +		case 1: /* Fall through. */
 +		case 2:
 +			row = er_find_item (reflow, item);
 +			if (event->button.button == 1) {
 +				reflow->maybe_did_something =
 +					e_selection_model_maybe_do_something(reflow->selection, row, 0, event->button.state);
 +				reflow->maybe_in_drag = TRUE;
 +			} else {
 +				e_selection_model_do_something(reflow->selection, row, 0, event->button.state);
 +			}
 +			break;
 +		case 3:
 +			row = er_find_item (reflow, item);
 +			e_selection_model_right_click_down(reflow->selection, row, 0, 0);
 +			break;
 +		default:
 +			return_val = FALSE;
 +			break;
 +		}
 +		break;
 +	case GDK_BUTTON_RELEASE:
 +		if (event->button.button == 1) {
 +			if (reflow->maybe_in_drag) {
 +				reflow->maybe_in_drag = FALSE;
 +				if (!reflow->maybe_did_something) {
 +					row = er_find_item (reflow, item);
 +					e_selection_model_do_something(reflow->selection, row, 0, event->button.state);
 +				}
 +			}
 +		}
 +		break;
 +	case GDK_KEY_PRESS:
 +		return_val = e_selection_model_key_press(reflow->selection, (GdkEventKey *) event);
 +		break;
 +	default:
 +		return_val = FALSE;
 +		break;
 +	}
 +
 +	return return_val;
 +}
 +
 +static void
 +e_reflow_class_init (EReflowClass *klass)
 +{
 +	GObjectClass *object_class;
 +	GnomeCanvasItemClass *item_class;
 +
 +	object_class = (GObjectClass*) klass;
 +	item_class = (GnomeCanvasItemClass *) klass;
 +
 +	object_class->set_property  = e_reflow_set_property;
 +	object_class->get_property  = e_reflow_get_property;
 +	object_class->dispose  = e_reflow_dispose;
 +
 +	/* GnomeCanvasItem method overrides */
 +	item_class->event      = e_reflow_event;
 +	item_class->realize    = e_reflow_realize;
 +	item_class->unrealize  = e_reflow_unrealize;
 +	item_class->draw       = e_reflow_draw;
 +	item_class->update     = e_reflow_update;
 +	item_class->point      = e_reflow_point;
 +
 +	klass->selection_event = e_reflow_selection_event_real;
 +	klass->column_width_changed = NULL;
 +
 +	g_object_class_install_property (object_class, PROP_MINIMUM_WIDTH,
 +					 g_param_spec_double ("minimum_width",
 +							      _( "Minimum width" ),
 +							      _( "Minimum Width" ),
 +							      0.0, G_MAXDOUBLE, 0.0,
 +							      G_PARAM_READWRITE));
 +
 +	g_object_class_install_property (object_class, PROP_WIDTH,
 +					 g_param_spec_double ("width",
 +							      _( "Width" ),
 +							      _( "Width" ),
 +							      0.0, G_MAXDOUBLE, 0.0,
 +							      G_PARAM_READABLE));
 +
 +
 +	g_object_class_install_property (object_class, PROP_HEIGHT,
 +					 g_param_spec_double ("height",
 +							      _( "Height" ),
 +							      _( "Height" ),
 +							      0.0, G_MAXDOUBLE, 0.0,
 +							      G_PARAM_READWRITE));
 +
 +	g_object_class_install_property (object_class, PROP_EMPTY_MESSAGE,
 +					 g_param_spec_string ("empty_message",
 +							      _( "Empty message" ),
 +							      _( "Empty message" ),
 +							      NULL,
 +							      G_PARAM_READWRITE));
 +
 +	g_object_class_install_property (object_class, PROP_MODEL,
 +					 g_param_spec_object ("model",
 +							      _( "Reflow model" ),
 +							      _( "Reflow model" ),
 +							      E_REFLOW_MODEL_TYPE,
 +							      G_PARAM_READWRITE));
 +
 +	g_object_class_install_property (object_class, PROP_COLUMN_WIDTH,
 +					 g_param_spec_double ("column_width",
 +							      _( "Column width" ),
 +							      _( "Column width" ),
 +							      0.0, G_MAXDOUBLE, 150.0,
 +							      G_PARAM_READWRITE));
 +
 +	signals [SELECTION_EVENT] =
 +		g_signal_new ("selection_event",
 +			      G_OBJECT_CLASS_TYPE (object_class),
 +			      G_SIGNAL_RUN_LAST,
 +			      G_STRUCT_OFFSET (EReflowClass, selection_event),
 +			      NULL, NULL,
 +			      e_marshal_INT__OBJECT_BOXED,
 +			      G_TYPE_INT, 2, G_TYPE_OBJECT,
 +			      GDK_TYPE_EVENT);
 +
 +	signals [COLUMN_WIDTH_CHANGED] =
 +		g_signal_new ("column_width_changed",
 +			      G_OBJECT_CLASS_TYPE (object_class),
 +			      G_SIGNAL_RUN_LAST,
 +			      G_STRUCT_OFFSET (EReflowClass, column_width_changed),
 +			      NULL, NULL,
 +			      g_cclosure_marshal_VOID__DOUBLE,
 +			      G_TYPE_NONE, 1, G_TYPE_DOUBLE);
 +}
 +
 +static void
 +e_reflow_init (EReflow *reflow)
 +{
 +	reflow->model                     = NULL;
 +	reflow->items                     = NULL;
 +	reflow->heights                   = NULL;
 +	reflow->count                     = 0;
 +
 +	reflow->columns                   = NULL;
 +	reflow->column_count              = 0;
 +
 +	reflow->empty_text                = NULL;
 +	reflow->empty_message             = NULL;
 +
 +	reflow->minimum_width             = 10;
 +	reflow->width                     = 10;
 +	reflow->height                    = 10;
 +
 +	reflow->column_width              = 150;
 +
 +	reflow->column_drag               = FALSE;
 +
 +	reflow->need_height_update        = FALSE;
 +	reflow->need_column_resize        = FALSE;
 +	reflow->need_reflow_columns       = FALSE;
 +
 +	reflow->maybe_did_something       = FALSE;
 +	reflow->maybe_in_drag             = FALSE;
 +
 +	reflow->default_cursor_shown      = TRUE;
 +	reflow->arrow_cursor              = NULL;
 +	reflow->default_cursor            = NULL;
 +
 +	reflow->cursor_row                = -1;
 +
 +	reflow->incarnate_idle_id         = 0;
 +	reflow->do_adjustment_idle_id     = 0;
 +	reflow->set_scroll_adjustments_id = 0;
 +
 +	reflow->selection                 = E_SELECTION_MODEL (e_selection_model_simple_new());
 +	reflow->sorter                    = e_sorter_array_new (er_compare, reflow);
 +
 +	g_object_set (reflow->selection,
 +		      "sorter", reflow->sorter,
 +		      NULL);
 +
 +	reflow->selection_changed_id =
 +		g_signal_connect(reflow->selection, "selection_changed",
 +				 G_CALLBACK (selection_changed), reflow);
 +	reflow->selection_row_changed_id =
 +		g_signal_connect(reflow->selection, "selection_row_changed",
 +				 G_CALLBACK (selection_row_changed), reflow);
 +	reflow->cursor_changed_id =
 +		g_signal_connect(reflow->selection, "cursor_changed",
 +				 G_CALLBACK (cursor_changed), reflow);
 +
 +	e_canvas_item_set_reflow_callback(GNOME_CANVAS_ITEM(reflow), e_reflow_reflow);
 +}
diff --cc widgets/text/e-reflow.h
index afdc9ed,0000000..3ea840d
mode 100644,000000..100644
--- a/widgets/text/e-reflow.h
+++ b/widgets/text/e-reflow.h
@@@ -1,146 -1,0 +1,146 @@@
 +/*
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) version 3.
 + *
 + * 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
-  * License along with the program; if not, see <http://www.gnu.org/licenses/>  
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
 + *
 + *
 + * Authors:
 + *		Chris Lahey <clahey ximian com>
 + *
 + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 + *
 + */
 +
 +#ifndef __E_REFLOW_H__
 +#define __E_REFLOW_H__
 +
 +#include <libgnomecanvas/gnome-canvas.h>
 +#include <text/e-reflow-model.h>
 +#include <misc/e-selection-model.h>
 +#include <e-util/e-sorter-array.h>
 +
 +#ifdef __cplusplus
 +extern "C" {
 +#pragma }
 +#endif /* __cplusplus */
 +
 +/* EReflow - A canvas item container.
 + *
 + * The following arguments are available:
 + *
 + * name		type		read/write	description
 + * --------------------------------------------------------------------------------
 + * minimum_width double         RW              minimum width of the reflow.  width >= minimum_width
 + * width        double          R               width of the reflow
 + * height       double          RW              height of the reflow
 + */
 +
 +#define E_REFLOW_TYPE			(e_reflow_get_type ())
 +#define E_REFLOW(obj)			(G_TYPE_CHECK_INSTANCE_CAST ((obj), E_REFLOW_TYPE, EReflow))
 +#define E_REFLOW_CLASS(klass)		(G_TYPE_CHECK_CLASS_CAST ((klass), E_REFLOW_TYPE, EReflowClass))
 +#define E_IS_REFLOW(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_REFLOW_TYPE))
 +#define E_IS_REFLOW_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((obj), E_REFLOW_TYPE))
 +
 +
 +typedef struct EReflowPriv    EReflowPriv;
 +
 +typedef struct _EReflow       EReflow;
 +typedef struct _EReflowClass  EReflowClass;
 +
 +struct _EReflow
 +{
 +	GnomeCanvasGroup parent;
 +
 +	/* item specific fields */
 +	EReflowModel *model;
 +	guint model_changed_id;
 +	guint comparison_changed_id;
 +	guint model_items_inserted_id;
 +	guint model_item_removed_id;
 +	guint model_item_changed_id;
 +
 +	ESelectionModel *selection;
 +	guint selection_changed_id;
 +	guint selection_row_changed_id;
 +	guint cursor_changed_id;
 +	ESorterArray *sorter;
 +
 +	GtkAdjustment *adjustment;
 +	guint adjustment_changed_id;
 +	guint adjustment_value_changed_id;
 +	guint set_scroll_adjustments_id;
 +
 +	int *heights;
 +	GnomeCanvasItem **items;
 +	int count;
 +	int allocated_count;
 +
 +	int *columns;
 +	gint column_count; /* Number of columnns */
 +
 +	GnomeCanvasItem *empty_text;
 +	gchar *empty_message;
 +
 +	double minimum_width;
 +	double width;
 +	double height;
 +
 +	double column_width;
 +
 +	int incarnate_idle_id;
 +	int do_adjustment_idle_id;
 +
 +	/* These are all for when the column is being dragged. */
 +	gdouble start_x;
 +	gint which_column_dragged;
 +	double temp_column_width;
 +	double previous_temp_column_width;
 +
 +	int cursor_row;
 +
 +	int reflow_from_column;
 +
 +	guint column_drag : 1;
 +
 +	guint need_height_update : 1;
 +	guint need_column_resize : 1;
 +	guint need_reflow_columns : 1;
 +
 +	guint default_cursor_shown : 1;
 +
 +	guint maybe_did_something : 1;
 +	guint maybe_in_drag : 1;
 +	GdkCursor *arrow_cursor;
 +	GdkCursor *default_cursor;
 +};
 +
 +struct _EReflowClass
 +{
 +	GnomeCanvasGroupClass parent_class;
 +
 +	int (*selection_event) (EReflow *reflow, GnomeCanvasItem *item, GdkEvent *event);
 +	void (*column_width_changed) (EReflow *reflow, double width);
 +};
 +
 +/*
 + * To be added to a reflow, an item must have the argument "width" as
 + * a Read/Write argument and "height" as a Read Only argument.  It
 + * should also do an ECanvas parent reflow request if its size
 + * changes.
 + */
 +GType    e_reflow_get_type       (void);
 +
 +#ifdef __cplusplus
 +}
 +#endif /* __cplusplus */
 +
 +#endif /* __E_REFLOW_H__ */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]