/science/hdf5-18/

value='switch'/> Google Summer of Code 2013 - GNOME - Archive Integration workspace
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornobody <nobody@localhost>2005-02-18 22:48:48 +0800
committernobody <nobody@localhost>2005-02-18 22:48:48 +0800
commit4d272703e94a8594c38834c5127ff931a1df7429 (patch)
treec55aa9eee8aa7ae9eb73e1f2e39a66602bf274e0
parent130a7842f0b1b2a44f8a320dfb3cca112a42190c (diff)
downloadgsoc2013-evolution-EVOLUTION_2_0_4.tar.gz
gsoc2013-evolution-EVOLUTION_2_0_4.tar.zst
gsoc2013-evolution-EVOLUTION_2_0_4.zip
This commit was manufactured by cvs2svn to create tagEVOLUTION_2_0_4
'EVOLUTION_2_0_4'. svn path=/tags/EVOLUTION_2_0_4/; revision=28812
Diffstat
-rw-r--r--ChangeLog363
-rw-r--r--INSTALL131
-rw-r--r--NEWS557
-rw-r--r--README22
-rw-r--r--a11y/e-table/.cvsignore4
-rw-r--r--a11y/e-table/gal-a11y-e-cell-popup.c145
-rw-r--r--a11y/e-table/gal-a11y-e-cell-popup.h64
-rw-r--r--a11y/e-table/gal-a11y-e-cell-registry.c132
-rw-r--r--a11y/e-table/gal-a11y-e-cell-registry.h58
-rw-r--r--a11y/e-table/gal-a11y-e-cell-text.c721
-rw-r--r--a11y/e-table/gal-a11y-e-cell-text.h50
-rw-r--r--a11y/e-table/gal-a11y-e-cell-toggle.c169
-rw-r--r--a11y/e-table/gal-a11y-e-cell-toggle.h47
-rw-r--r--a11y/e-table/gal-a11y-e-cell-tree.c210
-rw-r--r--a11y/e-table/gal-a11y-e-cell-tree.h50
-rw-r--r--a11y/e-table/gal-a11y-e-cell-vbox.c214
-rw-r--r--a11y/e-table/gal-a11y-e-cell-vbox.h64
-rw-r--r--a11y/e-table/gal-a11y-e-cell.c621
-rw-r--r--a11y/e-table/gal-a11y-e-cell.h99
-rw-r--r--a11y/e-table/gal-a11y-e-table-click-to-add-factory.c88
-rw-r--r--a11y/e-table/gal-a11y-e-table-click-to-add-factory.h34
-rw-r--r--a11y/e-table/gal-a11y-e-table-click-to-add.c327
-rw-r--r--a11y/e-table/gal-a11y-e-table-click-to-add.h36
-rw-r--r--a11y/e-table/gal-a11y-e-table-factory.c83
-rw-r--r--a11y/e-table/gal-a11y-e-table-factory.h36
-rw-r--r--a11y/e-table/gal-a11y-e-table-item-factory.c87
-rw-r--r--a11y/e-table/gal-a11y-e-table-item-factory.h34
-rw-r--r--a11y/e-table/gal-a11y-e-table-item.c1310
-rw-r--r--a11y/e-table/gal-a11y-e-table-item.h44
-rw-r--r--a11y/e-table/gal-a11y-e-table.c293
-rw-r--r--a11y/e-table/gal-a11y-e-table.h45
-rw-r--r--a11y/e-table/gal-a11y-e-tree-factory.c81
-rw-r--r--a11y/e-table/gal-a11y-e-tree-factory.h34
-rw-r--r--a11y/e-table/gal-a11y-e-tree.c176
-rw-r--r--a11y/e-table/gal-a11y-e-tree.h43
-rw-r--r--a11y/e-text/.cvsignore4
-rw-r--r--a11y/e-text/gal-a11y-e-text-factory.c87
-rw-r--r--a11y/e-text/gal-a11y-e-text-factory.h36
-rw-r--r--a11y/e-text/gal-a11y-e-text.c1133
-rw-r--r--a11y/e-text/gal-a11y-e-text.h42
-rw-r--r--a11y/gal-a11y-factory.h94
-rw-r--r--a11y/gal-a11y-util.c31
-rw-r--r--a11y/gal-a11y-util.h21
-rw-r--r--addressbook/ChangeLog798
-rw-r--r--addressbook/gui/component/Makefile.am6
-rw-r--r--addressbook/gui/component/addressbook-component.c12
-rw-r--r--addressbook/gui/component/addressbook-config.c1446
-rw-r--r--addressbook/gui/component/addressbook-view.c155
-rw-r--r--addressbook/gui/component/addressbook.c99
-rw-r--r--addressbook/gui/component/apps_evolution_addressbook.schemas.in.in18
-rw-r--r--addressbook/gui/component/component-factory.c4
-rw-r--r--addressbook/gui/contact-editor/e-contact-editor.c228
-rw-r--r--addressbook/gui/contact-editor/e-contact-quick-add.c42
-rw-r--r--addressbook/gui/contact-list-editor/contact-list-editor.glade15
-rw-r--r--addressbook/gui/widgets/e-addressbook-view.c487
-rw-r--r--addressbook/gui/widgets/e-addressbook-view.h5
-rw-r--r--addressbook/gui/widgets/eab-contact-display.c27
-rw-r--r--addressbook/tools/evolution-addressbook-export.c6
-rw-r--r--addressbook/util/eab-book-util.c10
-rw-r--r--calendar/ChangeLog1542
-rw-r--r--calendar/gui/alarm-notify/alarm-notify-dialog.c354
-rw-r--r--calendar/gui/alarm-notify/alarm-queue.c167
-rw-r--r--calendar/gui/calendar-component.c254
-rw-r--r--calendar/gui/comp-editor-factory.c17
-rw-r--r--calendar/gui/dialogs/alarm-list-dialog.c4
-rw-r--r--calendar/gui/dialogs/comp-editor.c778
-rw-r--r--calendar/gui/dialogs/event-page.c131
-rw-r--r--calendar/gui/dialogs/event-page.glade71
-rw-r--r--calendar/gui/dialogs/meeting-page.c87
-rw-r--r--calendar/gui/dialogs/recurrence-page.c39
-rw-r--r--calendar/gui/dialogs/task-page.glade82
-rw-r--r--calendar/gui/e-cal-list-view.c20
-rw-r--r--calendar/gui/e-cal-model-calendar.c86
-rw-r--r--calendar/gui/e-cal-model-tasks.c60
-rw-r--r--calendar/gui/e-cal-model.c244
-rw-r--r--calendar/gui/e-calendar-table.c447
-rw-r--r--calendar/gui/e-calendar-view.c443
-rw-r--r--calendar/gui/e-day-view-config.c19
-rw-r--r--calendar/gui/e-day-view.c328
-rw-r--r--calendar/gui/e-itip-control.c29
-rw-r--r--calendar/gui/e-meeting-time-sel.c98
-rw-r--r--calendar/gui/e-week-view-event-item.c38
-rw-r--r--calendar/gui/e-week-view.c312
-rw-r--r--calendar/gui/gnome-cal.c409
-rw-r--r--calendar/gui/itip-utils.c77
-rw-r--r--calendar/gui/migration.c19
-rw-r--r--calendar/gui/print.c143
-rw-r--r--calendar/gui/tasks-component.c182
-rw-r--r--camel/ChangeLog4865
-rw-r--r--camel/camel-charset-map.c361
-rw-r--r--camel/camel-filter-driver.c1526
-rw-r--r--camel/camel-filter-search.c704
-rw-r--r--camel/camel-folder-search.c1409
-rw-r--r--camel/camel-folder-summary.c2888
-rw-r--r--camel/camel-gpg-context.c1817
-rw-r--r--camel/camel-html-parser.c807
-rw-r--r--camel/camel-http-stream.c612
-rw-r--r--camel/camel-lock-helper.c391
-rw-r--r--camel/camel-lock.c423
-rw-r--r--camel/camel-mime-filter-canon.c190
-rw-r--r--camel/camel-mime-filter-enriched.c603
-rw-r--r--camel/camel-mime-parser.c1930
-rw-r--r--camel/camel-mime-parser.h148
-rw-r--r--camel/camel-mime-utils.c4320
-rw-r--r--camel/camel-movemail.c540
-rw-r--r--camel/camel-multipart-signed.c794
-rw-r--r--camel/camel-operation.c730
-rw-r--r--camel/camel-sasl-digest-md5.c906
-rw-r--r--camel/camel-sasl-gssapi.c346
-rw-r--r--camel/camel-sasl-kerberos4.c230
-rw-r--r--camel/camel-sasl-ntlm.c706
-rw-r--r--camel/camel-service.c1060
-rw-r--r--camel/camel-service.h202
-rw-r--r--camel/camel-smime-context.c1054
-rw-r--r--camel/camel-store.c1205
-rw-r--r--camel/camel-tcp-stream-raw.c518
-rw-r--r--camel/camel-tcp-stream-ssl.c1256
-rw-r--r--camel/camel-tcp-stream.c208
-rw-r--r--camel/camel-tcp-stream.h123
-rw-r--r--camel/camel-uid-cache.c334
-rw-r--r--camel/camel-url.c592
-rw-r--r--camel/camel-vee-folder.c1789
-rw-r--r--camel/camel-vee-folder.h88
-rw-r--r--camel/camel-vee-store.c436
-rw-r--r--camel/camel-vee-store.h63
-rw-r--r--camel/camel-vtrash-folder.c230
-rw-r--r--camel/providers/groupwise/camel-gw-listener.c (renamed from plugins/groupwise-account-setup/camel-gw-listener.c)161
-rw-r--r--camel/providers/imap/camel-imap-command.c847
-rw-r--r--camel/providers/imap/camel-imap-folder.c2814
-rw-r--r--camel/providers/imap/camel-imap-store.c3271
-rw-r--r--camel/providers/imap4/camel-imap4-engine.c1550
-rw-r--r--camel/providers/imap4/camel-imap4-store.c1391
-rw-r--r--camel/providers/imapp/camel-imapp-store.c1016
-rw-r--r--camel/providers/local/camel-local-folder.c631
-rw-r--r--camel/providers/local/camel-local-folder.h109
-rw-r--r--camel/providers/local/camel-maildir-folder.c278
-rw-r--r--camel/providers/local/camel-maildir-store.c544
-rw-r--r--camel/providers/local/camel-mbox-folder.c557
-rw-r--r--camel/providers/local/camel-mbox-folder.h66
-rw-r--r--camel/providers/local/camel-mbox-store.c837
-rw-r--r--camel/providers/local/camel-mh-folder.c233
-rw-r--r--camel/providers/local/camel-spool-folder.c217
-rw-r--r--camel/providers/local/camel-spool-store.c465
-rw-r--r--camel/providers/nntp/camel-nntp-folder.c532
-rw-r--r--camel/providers/nntp/camel-nntp-private.h64
-rw-r--r--camel/providers/nntp/camel-nntp-store.c1408
-rw-r--r--camel/providers/nntp/camel-nntp-store.h114
-rw-r--r--camel/providers/nntp/camel-nntp-stream.c462
-rw-r--r--camel/providers/nntp/camel-nntp-summary.c504
-rw-r--r--camel/providers/pop3/camel-pop3-store.c682
-rw-r--r--camel/providers/smtp/camel-smtp-transport.c1413
-rw-r--r--camel/providers/smtp/camel-smtp-transport.h80
-rw-r--r--camel/tests/folder/Makefile.am28
-rw-r--r--camel/tests/folder/README14
-rw-r--r--camel/tests/folder/test11.c188
-rw-r--r--camel/tests/lib/folders.c580
-rw-r--r--camel/tests/message/test2.c326
-rw-r--r--camel/tests/message/test3.c196
-rw-r--r--camel/tests/mime-filter/Makefile.am38
-rw-r--r--camel/tests/mime-filter/test1.c108
-rw-r--r--composer/ChangeLog181
-rw-r--r--composer/e-msg-composer-attachment-bar.c293
-rw-r--r--composer/e-msg-composer.c372
-rw-r--r--composer/mail-composer-errors.xml2
-rw-r--r--composer/mail-composer-errors.xml.h2
-rw-r--r--configure.in265
-rw-r--r--doc/devel/executive-summary/evolution-services.hierarchy7
-rw-r--r--doc/devel/importer/evolution-shell-importer.hierarchy7
-rw-r--r--e-util/ChangeLog445
-rw-r--r--e-util/e-account.c222
-rw-r--r--e-util/e-bit-array.c429
-rw-r--r--e-util/e-bit-array.h104
-rw-r--r--e-util/e-i18n.h74
-rw-r--r--e-util/e-iconv.c614
-rw-r--r--e-util/e-iconv.h49
-rw-r--r--e-util/e-marshal.list52
-rw-r--r--e-util/e-memory.c1310
-rw-r--r--e-util/e-passwords.c14
-rw-r--r--e-util/e-sorter-array.c259
-rw-r--r--e-util/e-sorter-array.h77
-rw-r--r--e-util/e-sorter.c153
-rw-r--r--e-util/e-sorter.h82
-rw-r--r--e-util/e-text-event-processor-emacs-like.c495
-rw-r--r--e-util/e-text-event-processor-emacs-like.h70
-rw-r--r--e-util/e-text-event-processor-types.h132
-rw-r--r--e-util/e-text-event-processor.c148
-rw-r--r--e-util/e-text-event-processor.h77
-rw-r--r--e-util/e-url.c343
-rw-r--r--e-util/e-util.c1230
-rw-r--r--e-util/e-util.h231
-rw-r--r--e-util/e-xml-utils.c502
-rw-r--r--e-util/e-xml-utils.h101
-rw-r--r--filter/ChangeLog32
-rwxr-xr-xhelp/C/figures/evo_email_a.pngbin87620 -> 99857 bytes
-rwxr-xr-xhelp/C/figures/evo_identity_a.pngbin46427 -> 29371 bytes
-rwxr-xr-xhelp/C/figures/evo_mail_callout_a.pngbin90552 -> 90095 bytes
-rwxr-xr-xhelp/C/figures/evo_receive_setup_a.pngbin60130 -> 38207 bytes
-rwxr-xr-xhelp/C/figures/evo_send_setup_a.pngbin62908 -> 40068 bytes
-rw-r--r--help/ChangeLog6
-rw-r--r--help/devel/executive-summary/evolution-services.hierarchy7
-rw-r--r--help/devel/importer/evolution-shell-importer.hierarchy7
-rw-r--r--mail/ChangeLog1045
-rw-r--r--mail/em-composer-prefs.c157
-rw-r--r--mail/em-composer-utils.c62
-rw-r--r--mail/em-folder-browser.c16
-rw-r--r--mail/em-folder-properties.c250
-rw-r--r--mail/em-folder-selector.c38
-rw-r--r--mail/em-folder-selector.h3
-rw-r--r--mail/em-folder-tree-model.c52
-rw-r--r--mail/em-folder-tree.c315
-rw-r--r--mail/em-folder-tree.h3
-rw-r--r--mail/em-folder-view.c532
-rw-r--r--mail/em-format-html-display.c126
-rw-r--r--mail/em-format-html.c49
-rw-r--r--mail/em-format.c52
-rw-r--r--mail/em-format.h109
-rw-r--r--mail/em-junk-filter.c465
-rw-r--r--mail/em-message-browser.c10
-rw-r--r--mail/em-migrate.c83
-rw-r--r--mail/em-popup.c817
-rw-r--r--mail/em-subscribe-editor.c7
-rw-r--r--mail/em-utils.c30
-rw-r--r--mail/mail-account-gui.c2531
-rw-r--r--mail/mail-account-gui.h146
-rw-r--r--mail/mail-component.c59
-rw-r--r--mail/mail-config-druid.c767
-rw-r--r--mail/mail-config.c1
-rw-r--r--mail/mail-config.glade897
-rw-r--r--mail/mail-errors.xml27
-rw-r--r--mail/mail-errors.xml.h19
-rw-r--r--mail/mail-ops.c131
-rw-r--r--mail/mail-ops.h2
-rw-r--r--mail/mail-tools.c1
-rw-r--r--mail/mail-vfolder.c46
-rw-r--r--mail/message-list.c177
-rw-r--r--plugins/.cvsignore4
-rw-r--r--plugins/Makefile.am2
-rw-r--r--plugins/addressbook-file/ChangeLog3
-rw-r--r--plugins/addressbook-file/Makefile.am16
-rw-r--r--plugins/addressbook-file/addressbook-file.c56
-rw-r--r--plugins/addressbook-file/org-gnome-addressbook-file.eplug.in19
-rw-r--r--plugins/addressbook-groupwise/ChangeLog3
-rw-r--r--plugins/addressbook-groupwise/Makefile.am16
-rw-r--r--plugins/addressbook-groupwise/addressbook-groupwise.c75
-rw-r--r--plugins/addressbook-groupwise/org-gnome-addressbook-groupwise.eplug.in21
-rw-r--r--plugins/audio-inline/.cvsignore5
-rw-r--r--plugins/audio-inline/ChangeLog34
-rw-r--r--plugins/audio-inline/Makefile.am15
-rw-r--r--plugins/audio-inline/audio-inline.c306
-rw-r--r--plugins/audio-inline/org-gnome-audio-inline.eplug.in30
-rw-r--r--plugins/backup-restore/.cvsignore6
-rw-r--r--plugins/backup-restore/ChangeLog4
-rw-r--r--plugins/backup-restore/Makefile.am26
-rw-r--r--plugins/backup-restore/backup-restore.c122
-rw-r--r--plugins/backup-restore/backup.c153
-rw-r--r--plugins/backup-restore/org-gnome-backup-restore.eplug.in33
-rw-r--r--plugins/backup-restore/org-gnome-backup-restore.xml21
-rw-r--r--plugins/bbdb/.cvsignore4
-rw-r--r--plugins/bbdb/ChangeLog81
-rw-r--r--plugins/bbdb/Makefile.am14
-rw-r--r--plugins/bbdb/bbdb.c467
-rw-r--r--plugins/bbdb/bbdb.h22
-rw-r--r--plugins/bbdb/gaimbuddies.c439
-rw-r--r--plugins/bbdb/org-gnome-evolution-bbdb.eplug.in27
-rw-r--r--plugins/bbdb/test-evobuddy.c15
-rw-r--r--plugins/calendar-file/.cvsignore5
-rw-r--r--plugins/calendar-file/ChangeLog3
-rw-r--r--plugins/calendar-file/Makefile.am16
-rw-r--r--plugins/calendar-file/calendar-file.c57
-rw-r--r--plugins/calendar-file/org-gnome-calendar-file.eplug.in19
-rw-r--r--plugins/calendar-http/.cvsignore5
-rw-r--r--plugins/calendar-http/ChangeLog29
-rw-r--r--plugins/calendar-http/Makefile.am16
-rw-r--r--plugins/calendar-http/calendar-http.c314
-rw-r--r--plugins/calendar-http/org-gnome-calendar-http.eplug.in24
-rw-r--r--plugins/calendar-weather/.cvsignore5
-rw-r--r--plugins/calendar-weather/ChangeLog46
-rw-r--r--plugins/calendar-weather/Makefile.am33
-rw-r--r--plugins/calendar-weather/calendar-weather.c698
-rw-r--r--plugins/calendar-weather/category_weather_cloudy_16.pngbin597 -> 0 bytes
-rw-r--r--plugins/calendar-weather/category_weather_fog_16.pngbin217 -> 0 bytes
-rw-r--r--plugins/calendar-weather/category_weather_partly_cloudy_16.pngbin760 -> 0 bytes
-rw-r--r--plugins/calendar-weather/category_weather_rain_16.pngbin647 -> 0 bytes
-rw-r--r--plugins/calendar-weather/category_weather_snow_16.pngbin624 -> 0 bytes
-rw-r--r--plugins/calendar-weather/category_weather_sun_16.pngbin420 -> 0 bytes
-rw-r--r--plugins/calendar-weather/category_weather_tstorm_16.pngbin728 -> 0 bytes
-rw-r--r--plugins/calendar-weather/org-gnome-calendar-weather.eplug.in33
-rw-r--r--plugins/copy-tool/.cvsignore5
-rw-r--r--plugins/copy-tool/ChangeLog21
-rw-r--r--plugins/copy-tool/Makefile.am13
-rw-r--r--plugins/copy-tool/copy-tool.c100
-rw-r--r--plugins/copy-tool/org-gnome-copy-tool.eplug.in24
-rw-r--r--plugins/default-source/ChangeLog3
-rw-r--r--plugins/default-source/Makefile.am17
-rw-r--r--plugins/default-source/default-source.c123
-rw-r--r--plugins/default-source/org-gnome-default-source.eplug.in34
-rw-r--r--plugins/exchange-account-setup/ChangeLog158
-rw-r--r--plugins/exchange-account-setup/Makefile.am22
-rw-r--r--plugins/exchange-account-setup/exchange-account-setup.c533
-rw-r--r--plugins/exchange-account-setup/exchange-ask-password.c357
-rw-r--r--plugins/exchange-account-setup/org-gnome-exchange-account-setup.eplug.in39
-rw-r--r--plugins/folder-unsubscribe/.cvsignore3
-rw-r--r--plugins/folder-unsubscribe/ChangeLog8
-rw-r--r--plugins/folder-unsubscribe/Makefile.am13
-rw-r--r--plugins/folder-unsubscribe/folder-unsubscribe.c112
-rw-r--r--plugins/folder-unsubscribe/org-gnome-mail-folder-unsubscribe.eplug.in16
-rw-r--r--plugins/groupwise-account-setup/ChangeLog44
-rw-r--r--plugins/groupwise-account-setup/Makefile.am23
-rw-r--r--plugins/groupwise-account-setup/camel-gw-listener.h63
-rw-r--r--plugins/groupwise-account-setup/groupwise-account-setup.c67
-rw-r--r--plugins/groupwise-account-setup/org-gnome-gw-account-setup.eplug.in26
-rwxr-xr-xplugins/groupwise-send-options/ChangeLog13
-rw-r--r--plugins/groupwise-send-options/Makefile.am15
-rw-r--r--plugins/groupwise-send-options/org-gnome-compose-send-options.eplug.in25
-rw-r--r--plugins/groupwise-send-options/org-gnome-compose-send-options.xml17
-rw-r--r--plugins/groupwise-send-options/send-options.c144
-rw-r--r--plugins/groupwise-send-options/send-options.h40
-rw-r--r--plugins/groupwise-status-tracking/Changelog3
-rw-r--r--plugins/groupwise-status-tracking/Makefile.am15
-rw-r--r--plugins/groupwise-status-tracking/org-gnome-status-track.eplug.in25
-rw-r--r--plugins/groupwise-status-tracking/status-track.c237
-rw-r--r--plugins/itip-formatter/.cvsignore6
-rw-r--r--plugins/itip-formatter/ChangeLog343
-rw-r--r--plugins/itip-formatter/Makefile.am23
-rw-r--r--plugins/itip-formatter/itip-formatter.c1732
-rw-r--r--plugins/itip-formatter/itip-view.c1784
-rw-r--r--plugins/itip-formatter/itip-view.h164
-rw-r--r--plugins/itip-formatter/org-gnome-itip-formatter-errors.xml8
-rw-r--r--plugins/itip-formatter/org-gnome-itip-formatter.eplug.in20
-rw-r--r--plugins/mail-to-meeting/.cvsignore5
-rw-r--r--plugins/mail-to-meeting/ChangeLog21
-rw-r--r--plugins/mail-to-meeting/Makefile.am13
-rw-r--r--plugins/mail-to-meeting/mail-to-meeting.c179
-rw-r--r--plugins/mail-to-meeting/org-gnome-mail-to-meeting.eplug.in25
-rw-r--r--plugins/mail-to-task/.cvsignore5
-rw-r--r--plugins/mail-to-task/ChangeLog45
-rw-r--r--plugins/mail-to-task/Makefile.am13
-rw-r--r--plugins/mail-to-task/mail-to-task.c190
-rw-r--r--plugins/mail-to-task/org-gnome-mail-to-task.eplug.in25
-rw-r--r--plugins/mailing-list-actions/.cvsignore5
-rw-r--r--plugins/mailing-list-actions/ChangeLog34
-rw-r--r--plugins/mailing-list-actions/Makefile.am24
-rw-r--r--plugins/mailing-list-actions/mailing-list-actions.c217
-rw-r--r--plugins/mailing-list-actions/org-gnome-mailing-list-actions-errors.xml38
-rw-r--r--plugins/mailing-list-actions/org-gnome-mailing-list-actions-errors.xml.h28
-rw-r--r--plugins/mailing-list-actions/org-gnome-mailing-list-actions.eplug.in43
-rw-r--r--plugins/mailing-list-actions/org-gnome-mailing-list-actions.xml23
-rw-r--r--plugins/mark-calendar-offline/.cvsignore3
-rw-r--r--plugins/mark-calendar-offline/ChangeLog10
-rw-r--r--plugins/mark-calendar-offline/Makefile.am13
-rw-r--r--plugins/mark-calendar-offline/mark-calendar-offline.c54
-rw-r--r--plugins/mark-calendar-offline/org-gnome-mark-calendar-offline.eplug.in16
-rw-r--r--plugins/new-mail-notify/ChangeLog42
-rw-r--r--plugins/new-mail-notify/Makefile.am18
-rw-r--r--plugins/new-mail-notify/new-mail-notify.c143
-rw-r--r--plugins/new-mail-notify/org-gnome-new-mail-notify.eplug.in33
-rw-r--r--plugins/plugin-manager/.cvsignore5
-rw-r--r--plugins/plugin-manager/ChangeLog12
-rw-r--r--plugins/plugin-manager/Makefile.am15
-rw-r--r--plugins/plugin-manager/org-gnome-plugin-manager.eplug.in22
-rw-r--r--plugins/plugin-manager/org-gnome-plugin-manager.xml13
-rw-r--r--plugins/plugin-manager/plugin-manager.c289
-rw-r--r--plugins/prefer-plain/.cvsignore5
-rw-r--r--plugins/prefer-plain/ChangeLog13
-rw-r--r--plugins/prefer-plain/Makefile.am13
-rw-r--r--plugins/prefer-plain/org-gnome-prefer-plain.eplug.in33
-rw-r--r--plugins/prefer-plain/prefer-plain.c191
-rw-r--r--plugins/save-attachments/.cvsignore5
-rw-r--r--plugins/save-attachments/ChangeLog24
-rw-r--r--plugins/save-attachments/Makefile.am15
-rw-r--r--plugins/save-attachments/org-gnome-save-attachments.eplug.in23
-rw-r--r--plugins/save-attachments/org-gnome-save-attachments.xml19
-rw-r--r--plugins/save-attachments/save-attachments.c403
-rw-r--r--plugins/save-calendar/.cvsignore5
-rw-r--r--plugins/save-calendar/ChangeLog51
-rw-r--r--plugins/save-calendar/Makefile.am19
-rw-r--r--plugins/save-calendar/csv-format.c576
-rw-r--r--plugins/save-calendar/format-handler.h49
-rw-r--r--plugins/save-calendar/ical-format.c127
-rw-r--r--plugins/save-calendar/org-gnome-save-calendar.eplug.in14
-rw-r--r--plugins/save-calendar/rdf-format.c396
-rw-r--r--plugins/save-calendar/save-calendar.c260
-rw-r--r--plugins/select-one-source/.cvsignore5
-rw-r--r--plugins/select-one-source/ChangeLog10
-rw-r--r--plugins/select-one-source/Makefile.am13
-rw-r--r--plugins/select-one-source/mark-calendar-offline.c54
-rw-r--r--plugins/select-one-source/org-gnome-select-one-source.eplug.in14
-rw-r--r--plugins/select-one-source/select-one-source.c52
-rw-r--r--plugins/send-options/ChangeLog49
-rw-r--r--plugins/send-options/Makefile.am19
-rw-r--r--plugins/send-options/org-gnome-send-options.eplug.in14
-rw-r--r--plugins/send-options/send-options.c553
-rw-r--r--plugins/shared-folder/ChangeLog101
-rw-r--r--plugins/shared-folder/Makefile.am32
-rw-r--r--plugins/shared-folder/install-shared.c221
-rw-r--r--plugins/shared-folder/org-gnome-shared-folder-errors.xml19
-rw-r--r--plugins/shared-folder/org-gnome-shared-folder-errors.xml.h11
-rw-r--r--plugins/shared-folder/org-gnome-shared-folder.eplug.in41
-rw-r--r--plugins/shared-folder/properties.glade860
-rw-r--r--plugins/shared-folder/share-folder-common.c476
-rw-r--r--plugins/shared-folder/share-folder.c742
-rw-r--r--plugins/shared-folder/share-folder.h120
-rw-r--r--plugins/subject-thread/.cvsignore5
-rw-r--r--plugins/subject-thread/ChangeLog22
-rw-r--r--plugins/subject-thread/Makefile.am13
-rw-r--r--plugins/subject-thread/org-gnome-subject-thread.eplug.in11
-rw-r--r--plugins/subject-thread/subject-thread.c67
-rw-r--r--shell/ChangeLog179
-rw-r--r--shell/e-shell-settings-dialog.c23
-rw-r--r--shell/e-shell-window-commands.c86
-rw-r--r--shell/e-shell.c45
-rw-r--r--shell/main.c36
-rw-r--r--smime/ChangeLog16
-rw-r--r--smime/gui/e-cert-selector.c22
-rw-r--r--ui/evolution-addressbook.h25
-rw-r--r--ui/evolution-message-composer.h53
-rw-r--r--widgets/ChangeLog88
-rw-r--r--widgets/e-timezone-dialog/e-timezone-dialog.c18
-rw-r--r--widgets/e-timezone-dialog/e-timezone-dialog.glade3
-rw-r--r--widgets/menus/gal-define-views-dialog.c379
-rw-r--r--widgets/menus/gal-define-views-dialog.h78
-rw-r--r--widgets/menus/gal-define-views-model.c322
-rw-r--r--widgets/menus/gal-define-views-model.h72
-rw-r--r--widgets/menus/gal-define-views.glade192
-rw-r--r--widgets/menus/gal-view-collection.c823
-rw-r--r--widgets/menus/gal-view-collection.h151
-rw-r--r--widgets/menus/gal-view-etable.c305
-rw-r--r--widgets/menus/gal-view-etable.h78
-rw-r--r--widgets/menus/gal-view-factory-etable.c120
-rw-r--r--widgets/menus/gal-view-factory-etable.h62
-rw-r--r--widgets/menus/gal-view-factory.c107
-rw-r--r--widgets/menus/gal-view-factory.h79
-rw-r--r--widgets/menus/gal-view-instance-save-as-dialog.c307
-rw-r--r--widgets/menus/gal-view-instance-save-as-dialog.glade260
-rw-r--r--widgets/menus/gal-view-instance-save-as-dialog.h89
-rw-r--r--widgets/menus/gal-view-instance.c599
-rw-r--r--widgets/menus/gal-view-instance.h116
-rw-r--r--widgets/menus/gal-view-new-dialog.c285
-rw-r--r--widgets/menus/gal-view-new-dialog.glade175
-rw-r--r--widgets/menus/gal-view-new-dialog.h86
-rw-r--r--widgets/menus/gal-view.c206
-rw-r--r--widgets/menus/gal-view.h98
-rw-r--r--widgets/misc/ChangeLog271
-rw-r--r--widgets/misc/e-canvas-background.c496
-rw-r--r--widgets/misc/e-canvas-background.h71
-rw-r--r--widgets/misc/e-canvas-utils.c171
-rw-r--r--widgets/misc/e-canvas-utils.h55
-rw-r--r--widgets/misc/e-canvas-vbox.c381
-rw-r--r--widgets/misc/e-canvas-vbox.h93
-rw-r--r--widgets/misc/e-canvas.c1096
-rw-r--r--widgets/misc/e-canvas.h157
-rw-r--r--widgets/misc/e-cell-date-edit.c19
-rw-r--r--widgets/misc/e-colors.c103
-rw-r--r--widgets/misc/e-colors.h44
-rw-r--r--widgets/misc/e-cursors.c156
-rw-r--r--widgets/misc/e-cursors.h68
-rw-r--r--widgets/misc/e-gui-utils.c238
-rw-r--r--widgets/misc/e-gui-utils.h58
-rw-r--r--widgets/misc/e-hsv-utils.c178
-rw-r--r--widgets/misc/e-hsv-utils.h52
-rw-r--r--widgets/misc/e-multi-config-dialog.c27
-rw-r--r--widgets/misc/e-popup-menu.c240
-rw-r--r--widgets/misc/e-popup-menu.h142
-rw-r--r--widgets/misc/e-printable.c209
-rw-r--r--widgets/misc/e-printable.h90
-rw-r--r--widgets/misc/e-reflow-model.c355
-rw-r--r--widgets/misc/e-reflow-model.h112
-rw-r--r--widgets/misc/e-reflow.c1506
-rw-r--r--widgets/misc/e-reflow.h146
-rw-r--r--widgets/misc/e-selection-model-array.c557
-rw-r--r--widgets/misc/e-selection-model-array.h96
-rw-r--r--widgets/misc/e-selection-model-simple.c115
-rw-r--r--widgets/misc/e-selection-model-simple.h70
-rw-r--r--widgets/misc/e-selection-model.c689
-rw-r--r--widgets/misc/e-selection-model.h170
-rw-r--r--widgets/misc/e-unicode.c2055
-rw-r--r--widgets/misc/e-unicode.h115
-rw-r--r--widgets/misc/gal-categories.glade173
-rw-r--r--widgets/misc/gal-combo-box.c834
-rw-r--r--widgets/misc/gal-combo-box.h91
-rw-r--r--widgets/misc/gal-combo-text.c433
-rw-r--r--widgets/misc/gal-combo-text.h76
-rw-r--r--widgets/misc/pixmaps/.cvsignore2
-rw-r--r--widgets/misc/pixmaps/cursor_cross.xpm38
-rw-r--r--widgets/misc/pixmaps/cursor_hand_closed.xpm38
-rw-r--r--widgets/misc/pixmaps/cursor_hand_open.xpm38
-rw-r--r--widgets/misc/pixmaps/cursor_zoom_in.xpm37
-rw-r--r--widgets/misc/pixmaps/cursor_zoom_out.xpm37
-rw-r--r--widgets/misc/test-color.c76
-rw-r--r--widgets/table/.cvsignore13
-rw-r--r--widgets/table/add-col.xpm22
-rw-r--r--widgets/table/arrow-down.xpm21
-rw-r--r--widgets/table/arrow-up.xpm21
-rw-r--r--widgets/table/check-empty.xpm21
-rw-r--r--widgets/table/check-filled.xpm21
-rw-r--r--widgets/table/clip.pngbin192 -> 0 bytes
-rw-r--r--widgets/table/e-cell-checkbox.c67
-rw-r--r--widgets/table/e-cell-checkbox.h50
-rw-r--r--widgets/table/e-cell-combo.c703
-rw-r--r--widgets/table/e-cell-combo.h63
-rw-r--r--widgets/table/e-cell-date.c166
-rw-r--r--widgets/table/e-cell-date.h49
-rw-r--r--widgets/table/e-cell-float.c93
-rw-r--r--widgets/table/e-cell-float.h53
-rw-r--r--widgets/table/e-cell-number.c85
-rw-r--r--widgets/table/e-cell-number.h49
-rw-r--r--widgets/table/e-cell-pixbuf.c417
-rw-r--r--widgets/table/e-cell-pixbuf.h53
-rw-r--r--widgets/table/e-cell-popup.c519
-rw-r--r--widgets/table/e-cell-popup.h101
-rw-r--r--widgets/table/e-cell-progress.c456
-rw-r--r--widgets/table/e-cell-progress.h74
-rw-r--r--widgets/table/e-cell-size.c110
-rw-r--r--widgets/table/e-cell-size.h49
-rw-r--r--widgets/table/e-cell-spin-button.c670
-rw-r--r--widgets/table/e-cell-spin-button.h103
-rw-r--r--widgets/table/e-cell-text.c2854
-rw-r--r--widgets/table/e-cell-text.h129
-rw-r--r--widgets/table/e-cell-toggle.c489
-rw-r--r--widgets/table/e-cell-toggle.h62
-rw-r--r--widgets/table/e-cell-tree.c911
-rw-r--r--widgets/table/e-cell-tree.h77
-rw-r--r--widgets/table/e-cell-vbox.c486
-rw-r--r--widgets/table/e-cell-vbox.h72
-rw-r--r--widgets/table/e-cell.c499
-rw-r--r--widgets/table/e-cell.h224
-rw-r--r--widgets/table/e-table-click-to-add.c601
-rw-r--r--widgets/table/e-table-click-to-add.h78
-rw-r--r--widgets/table/e-table-col-dnd.h39
-rw-r--r--widgets/table/e-table-col.c236
-rw-r--r--widgets/table/e-table-col.h101
-rw-r--r--widgets/table/e-table-column-specification.c150
-rw-r--r--widgets/table/e-table-column-specification.h73
-rw-r--r--widgets/table/e-table-column.c291
-rw-r--r--widgets/table/e-table-config-field.c300
-rw-r--r--widgets/table/e-table-config-field.h69
-rw-r--r--widgets/table/e-table-config-no-group.glade2112
-rw-r--r--widgets/table/e-table-config.c1225
-rw-r--r--widgets/table/e-table-config.glade2181
-rw-r--r--widgets/table/e-table-config.h115
-rw-r--r--widgets/table/e-table-defines.h45
-rw-r--r--widgets/table/e-table-example-1.c308
-rw-r--r--widgets/table/e-table-example-2.c349
-rw-r--r--widgets/table/e-table-extras.c292
-rw-r--r--widgets/table/e-table-extras.h82
-rw-r--r--widgets/table/e-table-field-chooser-dialog.c224
-rw-r--r--widgets/table/e-table-field-chooser-dialog.h79
-rw-r--r--widgets/table/e-table-field-chooser-item.c711
-rw-r--r--widgets/table/e-table-field-chooser-item.h75
-rw-r--r--widgets/table/e-table-field-chooser.c302
-rw-r--r--widgets/table/e-table-field-chooser.glade123
-rw-r--r--widgets/table/e-table-field-chooser.h79
-rw-r--r--widgets/table/e-table-group-container.c1503
-rw-r--r--widgets/table/e-table-group-container.h108
-rw-r--r--widgets/table/e-table-group-leaf.c686
-rw-r--r--widgets/table/e-table-group-leaf.h90
-rw-r--r--widgets/table/e-table-group.c712
-rw-r--r--widgets/table/e-table-group.h178
-rw-r--r--widgets/table/e-table-header-item.c1910
-rw-r--r--widgets/table/e-table-header-item.h119
-rw-r--r--widgets/table/e-table-header-utils.c480
-rw-r--r--widgets/table/e-table-header-utils.h55
-rw-r--r--widgets/table/e-table-header.c952
-rw-r--r--widgets/table/e-table-header.h120
-rw-r--r--widgets/table/e-table-item.c3735
-rw-r--r--widgets/table/e-table-item.h231
-rw-r--r--widgets/table/e-table-memory-callbacks.c208
-rw-r--r--widgets/table/e-table-memory-callbacks.h91
-rw-r--r--widgets/table/e-table-memory-store.c583
-rw-r--r--widgets/table/e-table-memory-store.h138
-rw-r--r--widgets/table/e-table-memory.c277
-rw-r--r--widgets/table/e-table-memory.h76
-rw-r--r--widgets/table/e-table-model.c616
-rw-r--r--widgets/table/e-table-model.h173
-rw-r--r--widgets/table/e-table-one.c241
-rw-r--r--widgets/table/e-table-one.h57
-rw-r--r--widgets/table/e-table-scrolled.c229
-rw-r--r--widgets/table/e-table-scrolled.h76
-rw-r--r--widgets/table/e-table-search.c223
-rw-r--r--widgets/table/e-table-search.h71
-rw-r--r--widgets/table/e-table-selection-model.c347
-rw-r--r--widgets/table/e-table-selection-model.h76
-rw-r--r--widgets/table/e-table-simple.c289
-rw-r--r--widgets/table/e-table-simple.h122
-rw-r--r--widgets/table/e-table-size-test.c307
-rw-r--r--widgets/table/e-table-sort-info.c481
-rw-r--r--widgets/table/e-table-sort-info.h107
-rw-r--r--widgets/table/e-table-sorted-variable.c230
-rw-r--r--widgets/table/e-table-sorted-variable.h65
-rw-r--r--widgets/table/e-table-sorted.c310
-rw-r--r--widgets/table/e-table-sorted.h65
-rw-r--r--widgets/table/e-table-sorter.c462
-rw-r--r--widgets/table/e-table-sorter.h74
-rw-r--r--widgets/table/e-table-sorting-utils.c349
-rw-r--r--widgets/table/e-table-sorting-utils.h83
-rw-r--r--widgets/table/e-table-specification.c432
-rw-r--r--widgets/table/e-table-specification.h89
-rw-r--r--widgets/table/e-table-state.c299
-rw-r--r--widgets/table/e-table-state.h74
-rw-r--r--widgets/table/e-table-subset-variable.c250
-rw-r--r--widgets/table/e-table-subset-variable.h82
-rw-r--r--widgets/table/e-table-subset.c482
-rw-r--r--widgets/table/e-table-subset.h89
-rw-r--r--widgets/table/e-table-tooltip.h44
-rw-r--r--widgets/table/e-table-tree.h48
-rw-r--r--widgets/table/e-table-utils.c191
-rw-r--r--widgets/table/e-table-utils.h49
-rw-r--r--widgets/table/e-table-without.c392
-rw-r--r--widgets/table/e-table-without.h91
-rw-r--r--widgets/table/e-table.c3349
-rw-r--r--widgets/table/e-table.diabin4514 -> 0 bytes
-rw-r--r--widgets/table/e-table.h358
-rw-r--r--widgets/table/e-tree-memory-callbacks.c275
-rw-r--r--widgets/table/e-tree-memory-callbacks.h119
-rw-r--r--widgets/table/e-tree-memory.c717
-rw-r--r--widgets/table/e-tree-memory.h101
-rw-r--r--widgets/table/e-tree-model.c1098
-rw-r--r--widgets/table/e-tree-model.h227
-rw-r--r--widgets/table/e-tree-scrolled.c228
-rw-r--r--widgets/table/e-tree-scrolled.h75
-rw-r--r--widgets/table/e-tree-selection-model.c816
-rw-r--r--widgets/table/e-tree-selection-model.h79
-rw-r--r--widgets/table/e-tree-simple.c208
-rw-r--r--widgets/table/e-tree-simple.h85
-rw-r--r--widgets/table/e-tree-sorted-variable.c477
-rw-r--r--widgets/table/e-tree-sorted-variable.h85
-rw-r--r--widgets/table/e-tree-sorted.c1390
-rw-r--r--widgets/table/e-tree-sorted.h86
-rw-r--r--widgets/table/e-tree-table-adapter.c1174
-rw-r--r--widgets/table/e-tree-table-adapter.h95
-rw-r--r--widgets/table/e-tree.c3324
-rw-r--r--widgets/table/e-tree.h312
-rw-r--r--widgets/table/image1.pngbin1858 -> 0 bytes
-rw-r--r--widgets/table/image2.pngbin1987 -> 0 bytes
-rw-r--r--widgets/table/image3.pngbin2051 -> 0 bytes
-rw-r--r--widgets/table/remove-col.xpm22
-rw-r--r--widgets/table/sample.table45
-rw-r--r--widgets/table/spec.xml21
-rw-r--r--widgets/table/table-test.c62
-rw-r--r--widgets/table/table-test.h27
-rw-r--r--widgets/table/test-check.c221
-rw-r--r--widgets/table/test-cols.c265
-rw-r--r--widgets/table/test-table.c478
-rw-r--r--widgets/table/tree-expanded.xpm23
-rw-r--r--widgets/table/tree-unexpanded.xpm23
-rw-r--r--widgets/text/.cvsignore11
-rw-r--r--widgets/text/e-completion-callbacks.c98
-rw-r--r--widgets/text/e-completion-callbacks.h68
-rw-r--r--widgets/text/e-completion-match.c184
-rw-r--r--widgets/text/e-completion-match.h67
-rw-r--r--widgets/text/e-completion-view.c859
-rw-r--r--widgets/text/e-completion-view.h98
-rw-r--r--widgets/text/e-completion.c343
-rw-r--r--widgets/text/e-completion.h91
-rw-r--r--widgets/text/e-entry-test.c83
-rw-r--r--widgets/text/e-entry.c1392
-rw-r--r--widgets/text/e-entry.h87
-rw-r--r--widgets/text/e-table-text-model.c234
-rw-r--r--widgets/text/e-table-text-model.h64
-rw-r--r--widgets/text/e-text-model-repos.c87
-rw-r--r--widgets/text/e-text-model-repos.h69
-rw-r--r--widgets/text/e-text-model-test.c91
-rw-r--r--widgets/text/e-text-model-uri.c344
-rw-r--r--widgets/text/e-text-model-uri.h56
-rw-r--r--widgets/text/e-text-model.c600
-rw-r--r--widgets/text/e-text-model.h113
-rw-r--r--widgets/text/e-text-test.c168
-rw-r--r--widgets/text/e-text.c3867
-rw-r--r--widgets/text/e-text.h244
669 files changed, 69685 insertions, 123835 deletions
diff --git a/ChangeLog b/ChangeLog
index 356455230e..ba3226241f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,350 +1,60 @@
-2005-02-01 Priit Laes <amd@store20.com>
+2005-02-14 JP Rosevear <jpr@novell.com>
- * configure.in : Remove duplicate entries for addressbook-groupwise,
- groupwise-status-tracking and default-source in plugins list. Fixes
- make distclean.
-
-2005-02-01 JP Rosevear <jpr@novell.com>
-
- * MAINTAINERS: Update
-
-2005-02-01 Priit Laes <amd@store20.com>
-
- * configure.in : Remove duplicate entry for calendar-file in
- plugins list.
-
-2005-01-30 Harish Krishnaswamy <kharish@novell.com>
-
- * configure.in : Correct the typo in plugins_base made in
- the commit below - let the HEAD to get built again.
-
-2005-01-29 Sivaiah Nallagatla <snallagatla@novell.com>
-
- * configure.in : add addressbook-groupwise plguin to the
- plguin list
-
-2005-01-26 Rodney Dawes <dobey@novell.com>
-
- * configure.in: Add mail/default/pt/Makefile to AC_OUTPUT
-
-2005-01-24 JP Rosevear <jpr@novell.com>
-
- * configure.in: bump version and requires
-
-2005-01-21 JP Rosevear <jpr@novell.com>
-
- * configure.in: e-util needs libgnomeprintui now
-
-2005-01-21 Sivaiah Nallagatla <snallagatla@novell.com>
-
- * configure.in : added addressbook-file plugin
-
-2005-01-21 Sivaiah Nallagatla <snallagatla@novell.com>
-
- * configure.in : added default-source plugin
-
-2005-01-20 Parthasarathi Susarla <sparthasarathi@novell.com>
-
- * configure.in : added a plugin for displaying the
- groupwise status tracking options
-
-2005-01-13 JP Rosevear <jpr@novell.com>
-
- * configure.in: bump version to 2.1.3.2
-
-2005-01-13 Rodney Dawes <dobey@novell.com>
-
- * configure.in: Add new-mail-notify to the plugins_all listing
- so that it gets disted properly
-
-2005-01-12 JP Rosevear <jpr@novell.com>
-
- * configure.in: fix plugin listing, bump upgrade revision so
- weather calendar group appears
-
-2005-01-10 JP Rosevear <jpr@novell.com>
+ * configure.in: bump version, requires
- * configure.in: make itip-formatter a base plugin
+2004-10-11 JP Rosevear <jpr@novell.com>
-2005-01-11 JP Rosevear <jpr@novell.com>
+ * NEWS: update
* configure.in: bump version
-2005-01-11 Not Zed <NotZed@Ximian.com>
-
- * configure.in: added new mail plugin & checks.
+2004-09-24 JP Rosevear <jpr@novell.com>
-2005-01-10 Sushma Rai <rsushma@novell.com>
+ * NEWS: update
- * configure.in: Added Exchange account settings plugin
-
-2005-1-10 Parthasarathi Susarla <sparthasarathi@novell.com>
- * configure.in : added send options plugin to base plugin list
-
-2005-01-10 Vivek Jain <jvivek@novell.com>
-
- * configure.in : Add shared-folder to plugin
- and base plugin list. Add corresponding Makfile to AC_OUTPUT section.
-
-2005-01-10 Chenthill Palanisamy <pchenthill@novell.com>
-
- * configure.in: add send-options plugin
-
-2005-01-09 JP Rosevear <jpr@novell.com>
-
- * configure.in: add calendar-file plugin
-
-2005-01-08 Priit Laes <amd@store20.com>
-
- * configure.in : Remove duplicate entry for itip-formatter in
- plugins list.
-
-2005-01-08 Harish Krishnaswamy <kharish@novell.com>
-
- * configure.in : Add gnome-vfs-module-2.0 to Evo compile flags for
- the calendar.
-
-2005-01-08 Hans Petter Jansson <hpj@novell.com>
-
- * configure.in: Add libedataserverui to the e-util libs and cflags.
-
-2005-01-07 Rodrigo Moya <rodrigo@novell.com>
-
- * configure.in: removed weatherdatadir definition here.
-
-2005-01-07 David Trowbridge <David.Trowbridge@Colorado.edu>
-
- * configure.in: added calendar-weather plugin to build.
-
-2005-01-06 JP Rosevear <jpr@novell.com>
-
- * data/Makefile.am: add some uninstall rules for local data
-
-2005-01-03 JP Rosevear <jpr@novell.com>
-
- * configure.in: add itip-formatter to the "all" list, its not
- ready to be in the base yet though
-
-2004-12-23 Hans Petter Jansson <hpj@novell.com>
-
- * configure.in: Remove select-names from Makefile output list.
+ * configure.in: bump version, requirements
-2004-12-17 Not Zed <NotZed@Ximian.com>
+2004-09-13 Not Zed <NotZed@Ximian.com>
- * devel-docs/misc/errors.txt (BUILT_SOURCES): add translation stuff.
+ * configure.in: change the way ipv6 stuff is done. separate ipv6
+ setting from getaddrinfo call check, and default to on if the
+ interfaces are available.
-2004-12-16 Not Zed <NotZed@Ximian.com>
+2004-09-14 Danilo Å egan <dsegan@gmx.net>
- * Makefile.am, configure.in: added evolution-plugin.pc, pkg-config
- file required for plugin development.
+ * configure.in: Added "bs" to ALL_LINGUAS.
-2004-12-20 JP Rosevear <jpr@novell.com>
+2004-09-13 JP Rosevear <jpr@novell.com>
* configure.in: bump version, requires
-2004-12-14 JP Rosevear <jpr@novell.com>
-
- Fixes #6066
+2004-09-13 JP Rosevear <jpr@novell.com>
- * README.translators: New information for translators
-
- * README: Update slightly for 2.1/2.2
-
-2004-12-14 Rodney Dawes <dobey@novell.com>
-
- * configure.in (AC_OUTPUT): Add mail/default/zh_CN/Makefile
-
-2004-12-08 Hans Petter Jansson <hpj@novell.com>
-
- * plugins/shared-folder/share-folder-common.c: Include
- <libebook/e-destination.h> from evolution-data-server.
-
-2004-12-03 Sivaiah Nallagatla <snallagatla@novell.com>
-
- * configure.in : Add groupwise-account-setup to plguin
- and base plugin list. Add corresponding Makfile to AC_OUTPUT section.
+ Fixes #63369
-2004-12-01 Dafydd Harries <daf@muse.19inch.net>
-
- * configure.in: Add "cy" (Welsh) to ALL_LINGUAS.
-
-2004-11-29 JP Rosevear <jpr@novell.com>
-
- * configure.in: bump version, requires
-
-2004-12-02 Not Zed <NotZed@Ximian.com>
-
- * configure.in: Make evolution mail link to camel-provider not
- camel only. Removed some camel stuff.
-
-2004-11-16 Not Zed <NotZed@Ximian.com>
-
- * Makefile.am (SUBDIRS): removed camel.
-
- * configure.in: Removed camel building, fixed module includes to
- use camel via packageconfig.
-
-2004-11-15 Not Zed <NotZed@Ximian.com>
-
- * configure.in: Added libeds to camel and mail and filter cflags.
-
-2004-11-09 Rodney Dawes <dobey@novell.com>
-
- * configure.in: Add AC_SUBST for plugins_base also
-
- * plugins/Makefile.am: Add plugins_base to DIST_SUBDIRS so that we
- dist the plug-ins we actually build by default
-
-2004-11-04 Not Zed <NotZed@Ximian.com>
-
- * configure.in: added mailing-list-actions plugin.
-
-2004-11-04 Not Zed <NotZed@Ximian.com>
-
- * configure.in: modified base vs optional logic slightly and added
- a warning if you build with --enable-plugins=no.
-
-2004-11-04 David Trowbridge <David.Trowbridge@Colorado.edu>
-
- * configure.in: Added calendar-http module, and setup a mechanism
- for base vs optional plugins.
-
-2004-11-03 JP Rosevear <jpr@novell.com>
-
- * configure.in: fix the logic
-
-2004-11-03 JP Rosevear <jpr@novell.com>
-
- * configure.in: handle plain --enable-plugins and
- --enable-plugins=yes by making it the equivalent of "all"
-
-2004-11-03 Not Zed <NotZed@Ximian.com>
-
- * configure.in: added plugin-manager plugin.
-
-2004-11-01 JP Rosevear <jpr@novell.com>
-
- * Makefile.am: dist plugin.mk
-
-2004-10-29 Rodrigo Moya <rodrigo@novell.com>
-
- * configure.in: added mail-to-meeting plugin.
-
-2004-10-28 Nat Friedman <nat@novell.com>
-
- * configure.in: Re-enable bbwhatever becuase I think it works now.
-
-2004-10-27 JP Rosevear <jpr@novell.com>
-
- * configure.in: revive E_WIDGETS_CFLAGS/LIBS because of needing to
- add libedataserverui
-
-2004-10-27 Not Zed <NotZed@Ximian.com>
-
- * configure.in: removed bbwhatever it is until the makefiles are
- fixed.
-
-2004-10-25 Radek Doulik <rodo@ximian.com>
-
- * configure.in: added audio-inline plugin, added gstreamer check
- for it
-
- if gstreamer is not available, remove audio-inline plugin from the
- plugins list
-
-2004-10-22 Harish K <kharish@novell.com>
-
- * configure.in: Added mark-calendar-offline plugin
-
-2004-10-22 Jeffrey Stedfast <fejj@ximian.com>
-
- * configure.in: Added folder-unsubscribe plugin
-
-2004-10-22 Nat Friedman <nat@novell.com>
-
- * configure.in: Added the bbdb plugin.
-
-2004-10-21 Rodrigo Moya <rodrigo@novell.com>
-
- * configure.in: added save-calendar plugin.
-
-2004-10-21 Not Zed <NotZed@Ximian.com>
-
- * configure.in: added copy-tool plugin.
-
-2004-10-20 JP Rosevear <jpr@novell.com>
-
- * configure.in: add select-one-source to the plugin list
-
-2004-10-20 Not Zed <NotZed@Ximian.com>
-
- * configure.in: added prefer plain plugin.
-
-2004-10-20 Not Zed <NotZed@Ximian.com>
-
- * configure.in: added save attachments plugin.
-
-2004-10-20 JP Rosevear <jpr@novell.com>
-
- * Makefile.am: list plugins as a subdir
-
- * plugins/Makefile.am: build enabled plugins
-
- * plugin.mk: simple rule for creating .eplug files
-
- * configure.in: add plugin foo; --enable-plugins=all turns them
- all on, or you can --enable-plugins="<plugin dir> <plugin dir>" to
- list specific ones
-
-2004-10-15 Sarfraaz Ahmed <asarfraaz@novell.com>
-
- * camel.pc.in : Change gal-2.2 to gal-2.4
- * evolution-shell.pc.in : Similar
-
-2004-10-13 JP Rosevear <jpr@novell.com>
-
- * configure.in: remove plugins from ac output
-
-2004-10-13 JP Rosevear <jpr@novell.com>
-
- * configure.in: pull in libedataserverui as appropriate
-
-2004-10-01 Jeffrey Stedfast <fejj@novell.com>
-
- * configure.in (localedir): Enable imap4 plugin by default. We
- need to get people building this and testing it.
-
-2004-10-01 JP Rosevear <jpr@novell.com>
-
- * configure.in: set the GETTEXT_PACKAGE to evolution-2.2
-
-2004-10-01 JP Rosevear <jpr@novell.com>
-
- * configure.in: set a GTKHTML_API_VERSION variable
+ * README: Update
-2004-09-13 Not Zed <NotZed@Ximian.com>
+2004-09-12 Abel Cheung <maddog@linuxhall.org>
- * configure.in: change the way ipv6 stuff is done. separate ipv6
- setting from getaddrinfo call check, and default to on if the
- interfaces are available.
+ * configure.in: Added "hi" "mk" "ml" "ta" to ALL_LINGUAS.
-2004-09-17 William Jon McCann <mccann@jhu.edu>
+2004-09-10 Mohammad DAMT <mdamt@bisnisweb.com>
- * configure.in: Fix typos in gal dependency.
+ * configure.in: Added Indonesian "id" to ALL_LINGUAS
+ * po/id.po: Added Indonesian translation
-2004-09-16 JP Rosevear <jpr@novell.com>
+2004-09-09 Runa Bhattacharjee <runab@redhat.com>
+ * configure.in: Added Bengali "bn" to ALL_LINGUAS.
- * configure.in: use AC_DEFINE properly
-
-2004-09-16 JP Rosevear <jpr@novell.com>
+2004-09-04 Telsa Gwynne <hobbit@aloss.ukuu.org.uk>
- * configure.in: bump EDS and gal requirements
+ * configure.in: Added "cy" (Welsh) to ALL_LINGUAS.
-2004-09-16 JP Rosevear <jpr@novell.com>
+2004-08-30 JP Rosevear <jpr@novell.com>
- * configure.in: bump version to 2.1.0 and set base version to 2.2;
- define DEVELOPMENT here so we don't have to alter code to change
- in future
+ * configure.in: hard code BASE_VERSION to 2.0; reset
+ UPGRADE_VERSION to 0 because BASE_VERSION changed; base
+ GETTEXT_PACKAGE on BASE_VERSION
2004-09-13 Tomasz KÅ‚oczko <kloczek@pld.org.pl>
@@ -445,19 +155,6 @@
* configure.in: bump version, requirements
-2004-08-24 JP Rosevear <jpr@novell.com>
-
- * configure.in (plugindir): set a plugin dir so we can easily
- install to the same place everywhere
-
-2004-08-24 JP Rosevear <jpr@novell.com>
-
- * configure.in: Check for mono support properly
-
-2004-07-05 Not Zed <NotZed@Ximian.com>
-
- * configure.in: add some mono checks.
-
2004-06-24 Pablo Saratxaga <pablo@mandrakesoft.com>
* configure.in: Added Walloon (wa) to ALL_LINGUAS.
diff --git a/INSTALL b/INSTALL
index 54caf7c190..b42a17ac46 100644
--- a/INSTALL
+++ b/INSTALL
@@ -1,9 +1,3 @@
-Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software
-Foundation, Inc.
-
- This file is free documentation; the Free Software Foundation gives
-unlimited permission to copy, distribute and modify it.
-
Basic Installation
==================
@@ -14,27 +8,20 @@ various system-dependent variables used during compilation. It uses
those values to create a `Makefile' in each directory of the package.
It may also create one or more `.h' files containing system-dependent
definitions. Finally, it creates a shell script `config.status' that
-you can run in the future to recreate the current configuration, and a
-file `config.log' containing compiler output (useful mainly for
-debugging `configure').
-
- It can also use an optional file (typically called `config.cache'
-and enabled with `--cache-file=config.cache' or simply `-C') that saves
-the results of its tests to speed up reconfiguring. (Caching is
-disabled by default to prevent problems with accidental use of stale
-cache files.)
+you can run in the future to recreate the current configuration, a file
+`config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
If you need to do unusual things to compile the package, please try
to figure out how `configure' could check whether to do them, and mail
diffs or instructions to the address given in the `README' so they can
-be considered for the next release. If you are using the cache, and at
-some point `config.cache' contains results you don't want to keep, you
-may remove or edit it.
+be considered for the next release. If at some point `config.cache'
+contains results you don't want to keep, you may remove or edit it.
- The file `configure.ac' (or `configure.in') is used to create
-`configure' by a program called `autoconf'. You only need
-`configure.ac' if you want to change it or regenerate `configure' using
-a newer version of `autoconf'.
+ The file `configure.in' is used to create `configure' by a program
+called `autoconf'. You only need `configure.in' if you want to change
+it or regenerate `configure' using a newer version of `autoconf'.
The simplest way to compile this package is:
@@ -68,16 +55,14 @@ Compilers and Options
=====================
Some systems require unusual options for compilation or linking that
-the `configure' script does not know about. Run `./configure --help'
-for details on some of the pertinent environment variables.
-
- You can give `configure' initial values for configuration parameters
-by setting variables in the command line or in the environment. Here
-is an example:
+the `configure' script does not know about. You can give `configure'
+initial values for variables by setting them in the environment. Using
+a Bourne-compatible shell, you can do that on the command line like
+this:
+ CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
- ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
-
- *Note Defining Variables::, for more details.
+Or on systems that have the `env' program, you can do it like this:
+ env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
Compiling For Multiple Architectures
====================================
@@ -90,11 +75,11 @@ directory where you want the object files and executables to go and run
the `configure' script. `configure' automatically checks for the
source code in the directory that `configure' is in and in `..'.
- If you have to use a `make' that does not support the `VPATH'
-variable, you have to compile the package for one architecture at a
-time in the source code directory. After you have installed the
-package for one architecture, use `make distclean' before reconfiguring
-for another architecture.
+ If you have to use a `make' that does not supports the `VPATH'
+variable, you have to compile the package for one architecture at a time
+in the source code directory. After you have installed the package for
+one architecture, use `make distclean' before reconfiguring for another
+architecture.
Installation Names
==================
@@ -137,32 +122,22 @@ you can use the `configure' options `--x-includes=DIR' and
Specifying the System Type
==========================
- There may be some features `configure' cannot figure out
-automatically, but needs to determine by the type of machine the package
-will run on. Usually, assuming the package is built to be run on the
-_same_ architectures, `configure' can figure that out, but if it prints
-a message saying it cannot guess the machine type, give it the
-`--build=TYPE' option. TYPE can either be a short name for the system
-type, such as `sun4', or a canonical name which has the form:
-
+ There may be some features `configure' can not figure out
+automatically, but needs to determine by the type of host the package
+will run on. Usually `configure' can figure that out, but if it prints
+a message saying it can not guess the host type, give it the
+`--host=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name with three fields:
CPU-COMPANY-SYSTEM
-where SYSTEM can have one of these forms:
-
- OS KERNEL-OS
-
- See the file `config.sub' for the possible values of each field. If
+See the file `config.sub' for the possible values of each field. If
`config.sub' isn't included in this package, then this package doesn't
-need to know the machine type.
+need to know the host type.
- If you are _building_ compiler tools for cross-compiling, you should
+ If you are building compiler tools for cross-compiling, you can also
use the `--target=TYPE' option to select the type of system they will
-produce code for.
-
- If you want to _use_ a cross compiler, that generates code for a
-platform different from the build platform, you should specify the
-"host" platform (i.e., that on which the generated programs will
-eventually be run) with `--host=TYPE'.
+produce code for and the `--build=TYPE' option to select the type of
+system on which you are compiling the package.
Sharing Defaults
================
@@ -175,43 +150,19 @@ default values for variables like `CC', `cache_file', and `prefix'.
`CONFIG_SITE' environment variable to the location of the site script.
A warning: not all `configure' scripts look for a site script.
-Defining Variables
+Operation Controls
==================
- Variables not defined in a site shell script can be set in the
-environment passed to `configure'. However, some packages may run
-configure again during the build, and the customized values of these
-variables may be lost. In order to avoid this problem, you should set
-them in the `configure' command line, using `VAR=value'. For example:
-
- ./configure CC=/usr/local2/bin/gcc
-
-will cause the specified gcc to be used as the C compiler (unless it is
-overridden in the site shell script).
-
-`configure' Invocation
-======================
-
`configure' recognizes the following options to control how it
operates.
-`--help'
-`-h'
- Print a summary of the options to `configure', and exit.
-
-`--version'
-`-V'
- Print the version of Autoconf used to generate the `configure'
- script, and exit.
-
`--cache-file=FILE'
- Enable the cache: use and save the results of the tests in FILE,
- traditionally `config.cache'. FILE defaults to `/dev/null' to
- disable caching.
+ Use and save the results of the tests in FILE instead of
+ `./config.cache'. Set FILE to `/dev/null' to disable caching, for
+ debugging `configure'.
-`--config-cache'
-`-C'
- Alias for `--cache-file=config.cache'.
+`--help'
+ Print a summary of the options to `configure', and exit.
`--quiet'
`--silent'
@@ -224,6 +175,8 @@ operates.
Look for the package's source code in directory DIR. Usually
`configure' can determine that directory automatically.
-`configure' also accepts some other, not widely useful, options. Run
-`configure --help' for more details.
+`--version'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+`configure' also accepts some other, not widely useful, options.
diff --git a/NEWS b/NEWS
index c6806d9d74..27eea9135e 100644
--- a/NEWS
+++ b/NEWS
@@ -1,508 +1,181 @@
-Evolution 2.1.5, 2005-02-07
----------------------------
+Evolution 2.0.5, 2004-12-06
+----------------------------
Bugzilla bugs fixed (see http://bugzilla.ximian.com/show_bug.cgi):
* Addressbook
+
#36137 - Leading %s in addressbook message totally non-obvious (Siva)
- #57819 - Evolution allows to create several contact lists with same name
- (Partha)
- #61060 - Don't split sentences in Evolution (Siva)
- #61067 - Use translator comment for evolution addressbook message (Siva)
- #67411 - Crash: create new address book (Hans Petter)
- #68799 - Evolution doesn't store IM info on the LDAP server (Siva)
#70339 - vcard preview doesn't appear to work (Siva)
+ #70622 - Crash changing gtkhtml settings (JP)
+ #70922 - Email address types should show "Other" when importing vcards (Siva)
+ #70540 - Adding contact from email doesn't let you change "file as" (Hans)
* Calendar
- #33078 - No category list for Category searches in Calendar & Tasks (Rodrigo)
- #56901 - Only one line gets printed when printing Tasks and Appointments (Yong)
- #61078 - Please avoid using different styles of markup in translateable
- evolution messages (Priit)
- #64682 - Moving a appts from one calendar to another sends update (Chenthill)
- #71265 - Deletion Of Weather Calendar Crashes Evo (Rodrigo)
- #71452 - Pressing 2 times escape - edited meeting window disappear (JP)
- #71485 - String issues (JP)
- #71729 - Gnopernicus should report the full name of week day (Li)
- #71929 - Whitespace before colons in Evolution calendar a11y messages
- (Rodrigo)
- #71924, 71926, 71932 - Don't split sentences (Harry)
- #71944 - Failed to compile (JP)
- #72088 - Some calendar a11y functions don't work (Harry)
- #72090 - Evolution crashed when clicking on 'open calender' in sent items (Rodrigo)
-
- * Mail
- #65329 - Regression in default folder name localisation (Michael)
- #67083 - CJK-translated mail header names are line-wrapped with long lined headers
- (Michael)
- #68137 - Inconsistent VFolder vs vFolder (Rodney)
- #68696 - RFE: Simplifications to the "Account Management" page of the Account
- setup druid (Rodney)
- #68743 - Button jumps when you click it (Rodney)
- #69815 - Cannot quit while updating vfolders (Michael)
- #69850 - Crash: attempting to create a Vfolder based on a message without a Sender
- (Michael)
- #70454 - Folder shows unsubscribed, but is subscribed (Jeff)
- #71310 - Always loses my signature script settings (Michael)
- #71312 - Double-clicking vFolder of Draft folder doesn't allow editing (Michael)
- #71520 - Changing server type not displayed immediately in 'Account settings'
- (Michael)
- #71521 - 'Account Editor' does not allow to change hostname (Michael)
- #71774 - Evolution crashes when cancel 'Rename Folder' dialog (Mengjie)
- #71937 - Spamasssassin typo in Evolution mail schemas (JP)
-
- * Plugins
- #41235 - Spacing/padding of itip control (Rodney)
- #71460 - Clicking accept button in appointment - Unable to send item to calender
- 'Calender'. Invalid object (Chenthill)
- #71512 - Crash: AMD64 Unable to add or import contacts (Siva)
- #71644 - Empty string marked for translation (Sushma)
-
-Other bugs
-
- * Addressbook
- - Use new categories dialog in contact editor (Rodrigo)
- - HIG spacing fixes (Rodney)
- - Display warning dialog when GW server is old (Vivek)
-
- * Calendar
- - Fixed sensitation of widgets in recurrence page (Rodrigo)
- - Fixed IDL duplications (Hans Petter)
- - Don't build private libraries as modules (Hans Petter)
- - Fixed popup menu for detached recurrences (Rodrigo)
- - HIG spacing/padding fixes (Rodney)
- - Display warning dialog when GW server is old (Vivek)
- - Clear component preview when updating (Rodrigo)
- - Added help button to editors (Rodney)
- - Fix DND issues with calendar attachments (Harish)
-
- * Mail
- - HIG fixes (Rodney)
-
- * Plugins
- - Use icon factory in audio-inline plugin (JP)
- - Fix order of menus in calendar-http plugin (David)
- - Added missing ID's (JP)
- - Set weather categories as not searchable (Rodrigo)
- - Added auth type section in exchange-account-setup plugin (Sushma)
- - Fixed crash in groupwise-send-options dialog (Chenthill)
-
- * All
- - Added 'pt' default setup to build (Rodney)
- - Fixed druid lock on startup (Jeff)
- - a11y improvements (Mengjie, Li, Harry)
- - HIG fixes to e-passwords dialogs (Rodney)
-
-Updated translations:
- - bg (Alexander Shopov)
- - cs (Miloslav Trmac)
- - de (Hendrik Richter, Frank Arnold)
- - el (Kostas Papadimas)
- - en_CA (Adam Weinberger)
- - es (Francisco Javier F. Serrador)
- - et (Priit Laes)
- - it (Marco Ciampa)
- - ja (Takeshi AIHANA)
- - lt (Zygimantas Beruska)
- - nb (Kjartan Maraas)
- - no (Kjartan Maraas)
- - ru (Leonid Kanter)
- - sk (Marcel Telka)
- - sv (Christian Rose)
- - zh_CN (Funda Wang)
-
-Evolution 2.1.4, 2005-01-24
-----------------------------
-
-Bugzilla bugs fixed (see http://bugzilla.ximian.com/show_bug.cgi):
+
+ #41624 - only the last exception is deleted on palm device (JP)
+ #46901 - Only one line gets printed when printing Tasks and Appointments (Yong Sun)
* Mail
- #46287 - Space key should work for checkbox (JP)
- #57090 - Junk Button Sensitivity needs changes (Radek)
- #69122 - Make subject || sender contains the default search (Michael)
+ #33933 - Sorting by subject does not result in expected order (Jeff)
+ #70795 - Next/Previous Message Should Only Display Listed Emails (Michael)
+ #65329 - regression in default folder name localisation (Michael)
+ #71312 - Double-clicking vFolder of Draft folder doesn't allow editing (Michael)
+ #71310 - Always loses my signature script settings (Michael)
+ #71310 - Always loses my signature script settings (Michael)
+ #69850 - Crash: attempting to create a Vfolder based on a message without a Sender (Michael)
+ #65178 - newly created folder on local maildir doesn't show until evolution restart (Michael)
+ #70858 - selecting newly created folder flakey (Michael)
#60664 - message view does not follow theme change (Michael)
- #55831 - missing warning dialog about opening a lot of selected mails (Michael)
- #66943 - Crash when saving draft (Michael)
#70768 - 'Mark All as Read' marks all the mails which are not in current query as read (Michael)
+ #70563 - crash when 'load images' on MyEclipse newsletter email (Michael)
+ #66943 - Crash when saving draft (Michael)
#71105 - When trying to rename a folder containing a slash "/" and spaces, evil stuff happens (Michael)
- #65178 - newly created folder on local maildir doesn't show until evolution restart (Michael)
- #71029 - receiving settings not stored (Michael)
- #70990 - NNTP without username broken (Michael)
- #70018 - Signatures don't work (Michael)
- #68352 - Add post message keybinding (Rodney)
-
- * Calendar
-
- #71407 - Input Protect Read-Only Calendars (Rodrigo)
- #65820 - Evolution Calendar weekday names message needs translator comment (JP)
-
- * Addressbook
-
- #70622 - crash (JP)
- #71448 - Deleting many contacts is incredibly slow (Siva)
- #41210 - spacing/padding of "Contact Quick Add" dialog (Rodney)
- #60852 - "Add address" popup dialog UI is ugly/wrong size, and button is resizable (Rodney)
- #41228 - spacing/padding of "duplicate contact detected" dialog (Rodney)
- #70922 - Email address types should show "Other" when importing vcards (Siva)
- #61973 - add TTYTDD translator comment (JP)
-
- * Plugins
-
- #71384 - 'Forward' button is disabled while configuring mail id (Sushma)
- #29985 - Accepted meetings should have a replied-to icon (JP)
-
- * Miscellaneous
-
- #46404 - not remembering printer definition (JP)
+ #72020 - Error parsing filter: Unknown identifier: adjust-score (Michael)
+ #38791 - gpg can make evo hang if keyserver unreachable (Michael)
+ #36142 - Don't use acronyms as verbs in messages (Michael)
+ #70303 - pgp signature invalid with very short emails (Michael)
+ #69757 - Memory leak in imap_parse_list_response (Michael)
+ #22496 - Evolution does not appear to support ALERT messages (Michael)
+ #71427 - Evolution does not prompt for new password (Michael)
+ #71625 - Don't display content of e-mail when first selected (Michael)
+ #56110 - Messages in digest displayed as source (Michael)
+ #69024 - Doesn't update NNTP folder in a Virtual folder (Michael)
+ #47824 - nested, identical multipart boundaries dont parse properly (Michael)
+ #70919 - Crash during fetching mail (mail has gpg signature) (Michael)
+ #70556 - Unable load messages info from MS Exchange by IMAP (Michael)
Other bugs
- * Address Book
-
- - set full name appropriately when quick adding (Hans)
- - fix creation of local addressbooks (Siva)
- - a11y fixes (Hao Sheng)
-
* Mail
- - Add items to folder properties correctly (Jeff)
- - Add async descriptions (Jeff)
-
- * Calendar
-
- - for detached instances, disable recurrence UI (Rodrigo)
- - use receive_objects for importing (Rodrigo)
- - change free/busy prefs title (Nat)
- - handle attachment errors better (Harish)
- - fix possible day view resize crash (Michael)
-
- * Shell
-
- - fix offline handler crash (JP)
- - close import wizard on Esc (Mengjie Yu)
-
- * S/MIME
-
- - don't remove tree node if deleting cert failed (Michael)
-
- * Plugins
-
- - Add addressbook file config plugin so local calendar get set up right (Siva)
- - In BBDB check the buddy account name not alias (Nat)
- - In weather calendar fix units spelling (David Trowbridge)
- - In weather calendar use single metric/imperial specification (David Trowbridge)
- - Add default source plugin so its easy to set for the user (Siva)
- - Make exchange account setup simpler (Sushma)
- - In groupwise account setup simplify the settings for soap only (Siva)
- - Add groupwise status tracking plugin so the user can see the information they requested (Chen)
- - In itip-formatter extract the decoded text so non-ascii works (JP)
- - In itip-formatter handle utc dtstart/dtend correctly (JP)
- - In new-mail-notify fix DBUS event handling (Miguel Angel Lopez Hernandez)
- - In groupwise sendoptions, make sure the global send options actually work (Chen)
- - In groupwise shared folder, improve UI (Vivek)
- - In groupwise shared folder, add a wizard for shared folder notifications (Vivek)
-
-Updated translations:
- - es (Francisco Javier F. Serrador)
- - de (Hendrik Richter, Frank Arnold)
- - it (Marco Ciampa)
- - nl (Vincent van Adrighem)
- - lt (Zygimantas Berucka)
- - nb (Kjartan Maraas)
- - no (Kjartan Maraas)
- - et (Priit Laes)
- - el (Nikos Charonitakis)
- - ja (Takeshi AIHANA)
- - en_CA (Adam Weinberger)
-
-Evolution 2.1.3, 2004-01-10
-----------------------------
-
-Bugzilla bugs fixed (see http://bugzilla.ximian.com/show_bug.cgi):
-
- * Calendar
-
- #69663 - Task list on the web does not mark tasks as finished (JP)
- #61076 - Evolution calendar messages unnecessarily marked for translation (JP)
- #41624 - only the last exception is deleted on palm device (JP)
+ -64 bit fixes (Michael)
* Addressbook
- #61068 - Extraneous space in evolution message (Andre Klapper)
- #61975 - Can't translate string "Reflow test" (JP)
-
- * Plugins
-
- #30992 - Preferences dialog greys out OK button after Apply (JP)
-
-Other bugs
-
- * Address Book
-
- - set read only state better for contact editor (Hans)
- - add UI for marking calendars offline (Siva)
- - use new name selector api (Hans)
-
- * Mail
-
- - Display icon for shared folder (Vivek)
- - New offline folder/store classes (Jeff)
- - Handle reply in mailto: (Michael)
- - a11y fixes (Mengjie Yu)
- - (Mengjie Yu)
-
- * Calendar
-
- - detached instance recurrence handling (Rodrigo)
- - calendar attachments (Harish)
- - send options for meeting (Chen)
- - handle calendar:// uris (JP)
- - handle different calendars having the same uid (Rodrigo)
- - add UI for marking calendars offline (Chen)
- - use new name selector API (Hans)
- - prevent crash when searching for f/b info (JP)
- - a11y fixes (Harry)
- - calendar config cleanup (JP)
-
- * Shell
-
- - Make component buttons configurable (JP)
- - Set offline with gconf key (Siva)
-
- * Plugins
-
- - add component.migration event for calendar (David Trowbridge)
- - fix translations of popup menus (Michael)
- - HIG config dialog fixes (Rodney)
- - Add calendar file config plugin so local calendar get set up right (JP)
- - Add calendar weather config plugin (David Trowbridge)
- - Add exchange account config plugin (Sushma)
- - Add groupwise send options plugin (Partha)
- - Add itip formatter plugin (JP)
- - Add new-mail-notify plugin that uses DBUS (Miguel Angel Lopez Hernandez)
- - Use standard error messages in save-calendar plugin (Philip Van Hoof)
- - Add send options plugin for account editor (Chen)
- - Add shared folder notification plugin (vivek)
-
-Updated translations:
- - lt (Zygimantas Berucka)
- - ja (Takeshi AIHANA)
- - bg (Vladimir Petkov, Alexander Shopov)
- - et (Priit Laes, Ivar Smolin)
-
-Evolution 2.1.2, 2004-12-20
-----------------------------
-
-Bugzilla bugs fixed (see http://bugzilla.ximian.com/show_bug.cgi):
-
- * Mail
-
- #68759 - Evolution Shell can't load modules (JP)
- #69579 - Moving a message from an IMAP INBOX to an IMAP folder caused crash (Michael)
- #69339 - postscript and some other attachments not visable (Michael)
- #69579 - vFolders#UNMATCHED generates errors (Michael)
- #68958 - current message forgotten in vfolders (Michael)
- #69446 - Mail shown as attachment if some headers are upper case (Michael)
- #46229 - Filters dialog - label suggestions (Diego Sevilla Ruiz)
-
- * Calendar
-
- #47535 - Snooze Time "minutes" string Improperly marked for translation
- (Rodney)
- #67403 - wrong alarm time displayed (Rodrigo)
-
- * Shell
-
- #61065 - Evolution should be spelled with uppercase E in evolution message (Joan Sanfeliu)
-
-Other bugs
-
- * Address Book
-
- - Turkish locale fixes (S. Caglar Onur)
- - Set proper window title for editing addressbook properties (Vivek)
- - Prevent null UID from causing weird saving problems (Siva)
- - a11y fixes (Harry Lu, Hao Sheng)
-
- * Mail
+ - work around 67411 (Hans)
+ - 64 bit fixes (Michael)
+ - Turkish locale fixes (S.Çaglar Onur)
- - Add mnemonics everywhere (Mengjie Yu)
- - Moving a message from an IMAP INBOX to an IMAP folder caused crash (Radek)
-
* Calendar
- - let users set a template for fetching free/busy information (James
- Bowes)
- - Set proper window title for editing calendar/task properties (Vivek)
- - Leak fixes (Harish)
- - Fix 64 bit problem (David Mosberger)
- - UI Fixes for meetings and assigned tasks (Chen)
-
- * Shell
-
- - fix 64 bit problem (David Mosberger)
- - use new window icon (Rodney)
+ - fix potential resize crash (Michael)
- * Plugins
+ * S/MIME
- - make plugin hooks available for mail even when the mailer is not
- activated (Michael)
- - move groupwise config code to a plugin (Siva)
- - support csv and rdf calendar saving (Philip Van Hoof)
+ - don't remove the cert from the tree if it wasn't actually deleted (Michael)
Updated translations:
- nl (Vincent van Adrighem)
- - sv (Christian Rose)
+ - pt (Duarte Loreto)
+ - hu (Laszlo Dvornik)
- ca (Jordi Mallach)
- - zh_CN (Funda Wang)
- - bg (Alexander Shopov)
- - fi (Ilkka Tuohela)
+ - fr (Jeremie Knuesel, Sebastien Bacher, Christophe Merlet)
+ - sv (Christian Rose)
+ - de (Hendrik Brandt)
+ - id (Mohammad DAMT)
+ - es (Francisco Javier F. Serrador)
- da (Martin Willemoes Hansen)
- - tr (Baris Cicek)
- - lt (Zygimantas Berucka)
- - cy (Dafydd Harries)
+ - ko (Changwoo Ryu)
+ - zh_CN (Funda Wang)
+ - ms (Hasbullah Bin Pit)
+ - hu (Laszlo Dvornik)
+ - cs (Miloslav Trmac)
+ - ru (Leonid Kanter)
+ - bg (Vladimir Petkov)
+ - sq (Laurent Dhima)
+ - en_GB (David Lodge)
+ - pl (Artur Flinta)
+ - sr (Danilo Segan)
+ - sr@Latn (Danilo Segan)
+ - en_CA (Adam Weinberger)
+ - pt_BR (Raphael Higino)
+ - nn (Åsmund Skjæveland)
-Evolution 2.1.1, 2004-11-28
+Evolution 2.0.3, 2004-12-06
----------------------------
Bugzilla bugs fixed (see http://bugzilla.ximian.com/show_bug.cgi):
* Addressbook
- #28725 - should not say "no items in this view" until the backend is done responding (Sushma)
- #61065 - Evolution should be spelled with uppercase E in evolution message (Joan Sanfeliu)
- #61976 - Near-identical strings, should be made identical (Rodney)
#67656 - almost the same email address are considrered identical (Siva)
- #61966 - Typo in string: Word "be" missing (Andre Klapper)
#69079 - Data repeated after save with bad date format (Siva)
- #66854 - Some strings are missed to translation (partial, Rodney)
-
- * Mail
-
- #68787 - Crash when migrating 1.4 data to 2.0.2 (Michael)
- #69109 - EHLO or HELO with ip addresses does not conform rfc 821 (Michael)
- #69408 - Evolution hang in message fetching with ima4rev1 (Jeff)
- #69145 - toplevel message/rfc822 parts are broken for IMAP (Michael)
- #69241 - base64 attachement holding PGP block (Jeff)
- #69160 - IMAP4 dont freez on scaning imap folders (Jeff)
- #67496 - html email not rendered in preview pane (Michael)
+ #66854 - Some strings are missed to translation (Rodney)
* Calendar
-
- #68624 - Requires URL to have http:// or webcal:// at beginning (Diego Sevilla Ruiz)
+
#47529 - Date in reminder window appears in UTF-8 in non-UTF-8 locale (Rodney)
- #6767 - Fix hardcode colors in day, week, month views (Li Yuan)
#68707 - Events ending at 12:00 AM show as ending at 12:00 pm (JP)
+ #67403 - wrong alarm time displayed (Rodrigo)
+ #68077 - appointment dialog re-size (Rodrigo)
- * Shell
+ * Mail
- #61065 - Evolution should be spelled with uppercase E in evolution message (Joan Sanfeliu)
+ #69533 - Unable to subscribe to the alt hierarchy (Michael)
+ #69776 - Signed Mail with attachments displays everything with multipart/boundaries stuff (Michael)
+ #69615 - delete certificate after viewing smime message (Michael)
+ #69109 - EHLO or HELO with ip addresses does not conform rfc 821 (Michael)
+ #69982 - During Newsgroup list refresh, it crashes (Michael)
+ #69446 - Mail shown as attachment if some headers are upper case (S. Caglar Onur)
+ #68556 - NNTP with SSL won't work, even with stunnel (Michael)
+ #69145 - toplevel message/rfc822 parts are broken for IMAP (Michael)
+ #69241 - base64 attachement holding PGP block (Jeff)
+ #67895 - nntp support not asking for password (Michael)
+ #67898 - Use of symbolic port-names is not guaranteed to work everywhere (Michael)
+ #69851 - remember password check doesn't stick (Michael)
+ #69623 - Moving a message from an IMAP INBOX to an IMAP folder caused crash (Radek)
+ #69339 - postscript and some other attachments not visable (Michael)
+ #69579 - vFolders#UNMATCHED generates errors (Michael)
+ #68958 - current message forgotten in vfolders (Michael)
+ #68974 - Wizard doesn't store smtp auth settings (Michael)
+ #67496 - html email not rendered in preview pane (Michael)
+ #67014 - Checking supported auth types doesn't work with new SSL certificate (Michael)
+ #68006 - Evo crashed after viewing previously-sent email and copying URL from it (Michael)
+ #68787 - Crash when migrating 1.4 data to 2.0.2 (Michael)
+ #67622 - SMTP auth usernames containing % character fail (Jeff)
Other bugs
- * Address Book
-
- - Handle required fields (Siva)
- - a11y fixes (Hao Sheng)
- - make shift-F10 popup menu (Hao Sheng)
- - don't show error dialog when cancelling operation (Siva)
-
* Mail
- - Reduce memory for vfolder operations (Michael)
- - Use unix sockets for spam checking (Radek)
-
- * Calendar
-
- - warn is summary is blank (Chen)
- - allow creating new calendar with right click on a group (Harish)
- - EConfigize new calendar and calendar properties (David Trowbridge)
- - make sure switch between 12/24h time shows immediately (JP)
+ - fix pthread_key_delete args (Julio M. Merino Vidal)
- * Plugins
+ * Calendar
- - set "base" plugin target (Michael)
- - add webcal config plugin (David Trowbridge)
- - mailing list actions plugin (Meilof Venningen)
- - plugin manager plugin (Michael)
+ - leak fixes (Chen)
+ - sensitize menu items in list view properly (JP)
+ - redraw display when 24hr time setting changes (JP)
Updated translations:
- - da (Martin Willemoes Hansen)
- - lt (Žygimantas BeruÄka)
- nl (Vincent van Adrighem)
- - de (Hendrik Richter)
- - it (Marco Ciampa)
+ - pt (Duarte Loreto)
+ - hu (Laszlo Dvornik)
- ca (Jordi Mallach)
- - fa (Meelad Zakaria)
- - sq (Laurent Dhima)
- - fr (Sebastien Bacher)
- - cs (Juraj Kubelka)
-
-Evolution 2.1.0, 2004-11-01
-----------------------------
-
-Bugzilla bugs fixed (see http://bugzilla.ximian.com/show_bug.cgi):
-
- * Addressbook
-
- #61069 - Missing space in evolution addressbook message (Andre Klapper)
- #61972 - Typo in country name: Is "Grena-dines", should be "Grenadines" (Andre Klapper)
-
- * Mail
-
- #68894 - IMAP4 rev1, error on selecting INBOX (Jeff)
- #68814 - evo crash while fetching mail using IMAP4 rev1 (Jeff)
- #44876 - Missing keyboard navigation in the e-mail recipient section (Mengjie Yu)
-
-Other bugs
-
- * Address Book
-
- - Display multi value attributes in the preview (Nat)
-
- * Mail
-
- - Enable IMAP4 camel provider by default (Jeff)
- - IMAP4 offline folder info caching (Jeff)
-
- * Calendar
-
- - a11y fixes (Li Yuan)
- - make free/busy information gathering more efficient (Harish)
-
- * Shell
-
- - remove deprecated calls (Kjartan Maraas)
-
- * Plugins
-
- - convert mail, address book to econfig (Zucchi)
- - convert all components to e-menu (Zucchi)
- - add new mail event (Zucchi)
- - add message replied event (Nat/Zucchi)
- - add online/offline event (Zucchi)
- - inline audio via gstreamer (Radek)
- - big brother database (Nat)
- - copy address tool (Zucchi)
- - folder unsubscribe (Jeff)
- - mail to task (Rodrigo)
- - mark calendar for offline (Harish)
- - prefer plain text for messages (Zucchi)
- - save attachments (Zucchi)
- - save calendar (Rodrigo)
- - select one calendar/task (JP)
- - subject threading (JP/Zucchi)
-
-Updated translations:
-
+ - fr (Jeremie Knuesel, Sebastien Bacher, Christophe Merlet)
+ - sv (Christian Rose)
+ - de (Hendrik Brandt)
+ - id (Mohammad DAMT)
+ - es (Francisco Javier F. Serrador)
- da (Martin Willemoes Hansen)
- - it (Marco Ciampa)
- - sq (Laurent Dhima)
- - el (Nikos Charonitakis)
+ - ko (Changwoo Ryu)
+ - zh_CN (Funda Wang)
- ms (Hasbullah Bin Pit)
+ - hu (Laszlo Dvornik)
+ - cs (Miloslav Trmac)
+ - ru (Leonid Kanter)
- bg (Vladimir Petkov)
+ - sq (Laurent Dhima)
+ - en_GB (David Lodge)
+ - pl (Artur Flinta)
+ - sr (Danilo Segan)
+ - sr@Latn (Danilo Segan)
+ - en_CA (Adam Weinberger)
+ - pt_BR (Raphael Higino)
+ - nn (Åsmund Skjæveland)
Evolution 2.0.2, 2004-10-11
----------------------------
diff --git a/README b/README
index 42f9923fea..4ec10e3c1b 100644
--- a/README
+++ b/README
@@ -31,10 +31,10 @@ The rest of this file is dedicated to building Evolution.
DEPENDENCIES
------------
-In order to build Evolution you need to have the full set of GNOME 2.6
+In order to build Evolution you need to have the full set of GNOME 2.2
(or greater) development libraries installed.
-GNOME 2.6 or greater comes with most of the modern distributions, so
+GNOME 2.2 or greater comes with most of the modern distributions, so
in most cases it should be enough to just install all the devel
packages from your distribution.
@@ -44,25 +44,35 @@ installed, since bugs in the libraries can cause bugs in Evolution.
Additional dependencies, besides the stock GNOME libraries (the
dependencies should be compiled in the order they are listed here):
+ * [If compiling against GNOME 2.2] libgnomecanvas 2.2.0.2 or
+ later
+
+ If you have a GNOME 2.2 installation, you need to upgrade
+ libgnomecanvas to this version (or a later one), since
+ Evolution exposes a bug in the older versions of the library
+ which causes a crash.
+
+ * [If compiling against GNOME 2.2] libbonobo and libbonoboui 2.4
+
* gnome-icon-theme 1.2.0 or later
* ORBit 2.9.8 or later
ftp://ftp.gnome.org/pub/gnome/sources/libsoup
- * libsoup 2.2.1 or later
+ * libsoup 2.2.0 or later
ftp://ftp.gnome.org/pub/gnome/sources/libsoup
- * evolution-data-server 1.1.1 or later
+ * evolution-data-server 1.0.0 or later
ftp://ftp.gnome.org/pub/gnome/sources/evolution-data-server
- * gtkhtml 3.5.0 or later
+ * gtkhtml 3.2.0 or later
ftp://ftp.gnome.org/pub/gnome/sources/gtkhtml
- * gal 2.4.0 or later
+ * gal 2.2.0 or later
ftp://ftp.gnome.org/pub/gnome/sources/gal
diff --git a/a11y/e-table/.cvsignore b/a11y/e-table/.cvsignore
deleted file mode 100644
index 5b48d3f593..0000000000
--- a/a11y/e-table/.cvsignore
+++ /dev/null
@@ -1,4 +0,0 @@
-.libs
-Makefile.in
-Makefile
-*.la
diff --git a/a11y/e-table/gal-a11y-e-cell-popup.c b/a11y/e-table/gal-a11y-e-cell-popup.c
deleted file mode 100644
index 15cae2effb..0000000000
--- a/a11y/e-table/gal-a11y-e-cell-popup.c
+++ /dev/null
@@ -1,145 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/* vim:expandtab:shiftwidth=8:tabstop=8:
- */
-/* Evolution Accessibility: gal-a11y-e-cell-popup.h
- *
- * Copyright (C) 2003 Ximian, Inc.
- *
- * 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., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- *
- * Author: Yang Wu <yang.wu@sun.com> Sun Microsystem Inc., 2003
- *
- */
-
-#include <config.h>
-#include <gal/e-table/e-cell-popup.h>
-#include "gal-a11y-e-cell-popup.h"
-#include "gal-a11y-e-cell-registry.h"
-#include "gal-a11y-util.h"
-#include <atk/atkobject.h>
-#include <gdk/gdkkeysyms.h>
-#include <gtk/gtkwidget.h>
-#include <glib/gi18n.h>
-
-static AtkObjectClass *parent_class = NULL;
-#define PARENT_TYPE (gal_a11y_e_cell_get_type ())
-
-static void gal_a11y_e_cell_popup_class_init (GalA11yECellPopupClass *klass);
-static void popup_cell_action (GalA11yECell *cell);
-
-/**
- * gal_a11y_e_cell_popup_get_type:
- * @void:
- *
- * Registers the &GalA11yECellPopup class if necessary, and returns the type ID
- * associated to it.
- *
- * Return value: The type ID of the &GalA11yECellPopup class.
- **/
-GType
-gal_a11y_e_cell_popup_get_type (void)
-{
- static GType type = 0;
-
- if (!type) {
- GTypeInfo info = {
- sizeof (GalA11yECellPopupClass),
- (GBaseInitFunc) NULL,
- (GBaseFinalizeFunc) NULL,
- (GClassInitFunc) gal_a11y_e_cell_popup_class_init,
- (GClassFinalizeFunc) NULL,
- NULL, /* class_data */
- sizeof (GalA11yECellPopup),
- 0,
- (GInstanceInitFunc) NULL,
- NULL /* value_cell_popup */
- };
-
- type = g_type_register_static (PARENT_TYPE, "GalA11yECellPopup", &info, 0);
- gal_a11y_e_cell_type_add_action_interface (type);
- }
-
- return type;
-}
-
-static void
-gal_a11y_e_cell_popup_class_init (GalA11yECellPopupClass *klass)
-{
- parent_class = g_type_class_ref (PARENT_TYPE);
-}
-
-AtkObject *
-gal_a11y_e_cell_popup_new (ETableItem *item,
- ECellView *cell_view,
- AtkObject *parent,
- int model_col,
- int view_col,
- int row)
-{
- AtkObject *a11y;
- GalA11yECell *cell;
- ECellPopup *popupcell;
- ECellView* child_view = NULL;
-
- popupcell= E_CELL_POPUP(cell_view->ecell);
-
- if (popupcell && popupcell->popup_cell_view)
- child_view = popupcell->popup_cell_view->child_view;
-
- if (child_view && child_view->ecell) {
- a11y = gal_a11y_e_cell_registry_get_object (NULL,
- item,
- child_view,
- parent,
- model_col,
- view_col,
- row);
- } else {
- a11y = g_object_new (GAL_A11Y_TYPE_E_CELL_POPUP, NULL);
- gal_a11y_e_cell_construct (a11y,
- item,
- cell_view,
- parent,
- model_col,
- view_col,
- row);
- }
- g_return_val_if_fail (a11y != NULL, NULL);
- cell = GAL_A11Y_E_CELL(a11y);
- gal_a11y_e_cell_add_action (cell,
- _("popup"), /* action name*/
- _("popup a child"), /* action description */
- "<Alt>Down", /* action keybinding */
- popup_cell_action);
-
- a11y->role = ATK_ROLE_TABLE_CELL;
- return a11y;
-}
-
-static void
-popup_cell_action (GalA11yECell *cell)
-{
- gint finished;
- GdkEvent event;
-
- event.key.type = GDK_KEY_PRESS;
- event.key.window = GTK_LAYOUT(GNOME_CANVAS_ITEM(cell->item)->canvas)->bin_window;;
- event.key.send_event = TRUE;
- event.key.time = GDK_CURRENT_TIME;
- event.key.state = GDK_MOD1_MASK;
- event.key.keyval = GDK_Down;
-
- g_signal_emit_by_name (cell->item, "event", &event, &finished);
-}
diff --git a/a11y/e-table/gal-a11y-e-cell-popup.h b/a11y/e-table/gal-a11y-e-cell-popup.h
deleted file mode 100644
index 5809f9b4f4..0000000000
--- a/a11y/e-table/gal-a11y-e-cell-popup.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/* vim:expandtab:shiftwidth=8:tabstop=8:
- */
-/* Evolution Accessibility: gal-a11y-e-cell-popup.h
- *
- * Copyright (C) 2003 Ximian, Inc.
- *
- * 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., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- *
- * Author: Yang Wu <yang.wu@sun.com> Sun Microsystem Inc., 2003
- *
- */
-
-#ifndef __GAL_A11Y_E_CELL_POPUP_H__
-#define __GAL_A11Y_E_CELL_POPUP_H__
-
-#include <glib-object.h>
-#include <gal/e-table/e-table-item.h>
-#include <a11y/e-table/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 --git a/a11y/e-table/gal-a11y-e-cell-registry.c b/a11y/e-table/gal-a11y-e-cell-registry.c
deleted file mode 100644
index 7110179554..0000000000
--- a/a11y/e-table/gal-a11y-e-cell-registry.c
+++ /dev/null
@@ -1,132 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * Authors:
- * Christopher James Lahey <clahey@ximian.com>
- *
- * Copyright (C) 2002 Ximian, Inc.
- */
-
-#include <config.h>
-#include "gal-a11y-e-cell-registry.h"
-#include "gal-a11y-e-cell.h"
-
-static GObjectClass *parent_class;
-static GalA11yECellRegistry *default_registry;
-#define PARENT_TYPE (G_TYPE_OBJECT)
-
-struct _GalA11yECellRegistryPrivate {
- GHashTable *table;
-};
-
-/* Static functions */
-
-static void
-gal_a11y_e_cell_registry_finalize (GObject *obj)
-{
- GalA11yECellRegistry *registry = GAL_A11Y_E_CELL_REGISTRY (obj);
-
- g_hash_table_destroy (registry->priv->table);
- g_free (registry->priv);
-}
-
-static void
-gal_a11y_e_cell_registry_class_init (GalA11yECellRegistryClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- parent_class = g_type_class_ref (PARENT_TYPE);
-
- object_class->finalize = gal_a11y_e_cell_registry_finalize;
-}
-
-static void
-gal_a11y_e_cell_registry_init (GalA11yECellRegistry *registry)
-{
- registry->priv = g_new (GalA11yECellRegistryPrivate, 1);
- registry->priv->table = g_hash_table_new (NULL, NULL);
-}
-
-/**
- * gal_a11y_e_cell_registry_get_type:
- * @void:
- *
- * Registers the &GalA11yECellRegistry class if necessary, and returns the type ID
- * associated to it.
- *
- * Return value: The type ID of the &GalA11yECellRegistry class.
- **/
-GType
-gal_a11y_e_cell_registry_get_type (void)
-{
- static GType type = 0;
-
- if (!type) {
- GTypeInfo info = {
- sizeof (GalA11yECellRegistryClass),
- (GBaseInitFunc) NULL,
- (GBaseFinalizeFunc) NULL,
- (GClassInitFunc) gal_a11y_e_cell_registry_class_init,
- (GClassFinalizeFunc) NULL,
- NULL, /* class_data */
- sizeof (GalA11yECellRegistry),
- 0,
- (GInstanceInitFunc) gal_a11y_e_cell_registry_init,
- NULL /* value_cell */
- };
-
- type = g_type_register_static (PARENT_TYPE, "GalA11yECellRegistry", &info, 0);
- }
-
- return type;
-}
-
-static void
-init_default_registry (void)
-{
- if (default_registry == NULL) {
- default_registry = g_object_new (gal_a11y_e_cell_registry_get_type(), NULL);
- }
-}
-
-
-AtkObject *
-gal_a11y_e_cell_registry_get_object (GalA11yECellRegistry *registry,
- ETableItem *item,
- ECellView *cell_view,
- AtkObject *parent,
- int model_col,
- int view_col,
- int row)
-{
- GalA11yECellRegistryFunc func = NULL;
- GType type;
-
- if (registry == NULL) {
- init_default_registry ();
- registry = default_registry;
- }
-
- type = GTK_OBJECT_TYPE (cell_view->ecell);
- while (func == NULL && type != 0) {
- func = g_hash_table_lookup (registry->priv->table, GINT_TO_POINTER (type));
- type = g_type_parent (type);
- }
-
- if (func)
- return func (item, cell_view, parent, model_col, view_col, row);
- else
- return gal_a11y_e_cell_new (item, cell_view, parent, model_col, view_col, row);
-}
-
-void
-gal_a11y_e_cell_registry_add_cell_type (GalA11yECellRegistry *registry,
- GType type,
- GalA11yECellRegistryFunc func)
-{
- if (registry == NULL) {
- init_default_registry ();
- registry = default_registry;
- }
-
- g_hash_table_insert (registry->priv->table, GINT_TO_POINTER (type), func);
-}
diff --git a/a11y/e-table/gal-a11y-e-cell-registry.h b/a11y/e-table/gal-a11y-e-cell-registry.h
deleted file mode 100644
index eecd41139c..0000000000
--- a/a11y/e-table/gal-a11y-e-cell-registry.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * Authors:
- * Christopher James Lahey <clahey@ximian.com>
- *
- * Copyright (C) 2001 Chris Lahey
- */
-
-#ifndef __GAL_A11Y_E_CELL_REGISTRY_H__
-#define __GAL_A11Y_E_CELL_REGISTRY_H__
-
-#include <glib-object.h>
-#include <atk/atkobject.h>
-#include <gal/e-table/e-table-item.h>
-#include <gal/e-table/e-cell.h>
-
-#define GAL_A11Y_TYPE_E_CELL_REGISTRY (gal_a11y_e_cell_registry_get_type ())
-#define GAL_A11Y_E_CELL_REGISTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_CELL_REGISTRY, GalA11yECellRegistry))
-#define GAL_A11Y_E_CELL_REGISTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_CELL_REGISTRY, GalA11yECellRegistryClass))
-#define GAL_A11Y_IS_E_CELL_REGISTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_CELL_REGISTRY))
-#define GAL_A11Y_IS_E_CELL_REGISTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_CELL_REGISTRY))
-
-typedef struct _GalA11yECellRegistry GalA11yECellRegistry;
-typedef struct _GalA11yECellRegistryClass GalA11yECellRegistryClass;
-typedef struct _GalA11yECellRegistryPrivate GalA11yECellRegistryPrivate;
-
-typedef AtkObject *(*GalA11yECellRegistryFunc) (ETableItem *item,
- ECellView *cell_view,
- AtkObject *parent,
- int model_col,
- int view_col,
- int row);
-
-struct _GalA11yECellRegistry {
- GObject object;
-
- GalA11yECellRegistryPrivate *priv;
-};
-
-struct _GalA11yECellRegistryClass {
- GObjectClass parent_class;
-};
-
-
-/* Standard Glib function */
-GType gal_a11y_e_cell_registry_get_type (void);
-AtkObject *gal_a11y_e_cell_registry_get_object (GalA11yECellRegistry *registry,
- ETableItem *item,
- ECellView *cell_view,
- AtkObject *parent,
- int model_col,
- int view_col,
- int row);
-void gal_a11y_e_cell_registry_add_cell_type (GalA11yECellRegistry *registry,
- GType type,
- GalA11yECellRegistryFunc func);
-
-#endif /* ! __GAL_A11Y_E_CELL_REGISTRY_H__ */
diff --git a/a11y/e-table/gal-a11y-e-cell-text.c b/a11y/e-table/gal-a11y-e-cell-text.c
deleted file mode 100644
index 89c1b3a813..0000000000
--- a/a11y/e-table/gal-a11y-e-cell-text.c
+++ /dev/null
@@ -1,721 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * Authors:
- * Christopher James Lahey <clahey@ximian.com>
- *
- * Copyright (C) 2002 Ximian, Inc.
- */
-
-#include <config.h>
-#include <string.h>
-#include "gal-a11y-e-cell-text.h"
-#include "gal-a11y-util.h"
-#include <gal/e-table/e-cell-text.h>
-#include <atk/atkobject.h>
-#include <atk/atktext.h>
-#include <atk/atkeditabletext.h>
-#include <atk/atkaction.h>
-#include <atk/atkstateset.h>
-#include <glib/gi18n.h>
-
-#define CS_CLASS(a11y) (G_TYPE_INSTANCE_GET_CLASS ((a11y), C_TYPE_STREAM, GalA11yECellTextClass))
-static AtkObjectClass *parent_class;
-#define PARENT_TYPE (gal_a11y_e_cell_get_type ())
-
-/* Static functions */
-static void
-ect_dispose (GObject *object)
-{
- GObjectClass *g_class;
- GalA11yECell *gaec = GAL_A11Y_E_CELL (object);
- GalA11yECellText *gaet = GAL_A11Y_E_CELL_TEXT (object);
-
- if (gaet->inserted_id != 0) {
- ECellText *ect = E_CELL_TEXT (gaec->cell_view->ecell);
-
- if (ect) {
- g_signal_handler_disconnect (ect, gaet->inserted_id);
- g_signal_handler_disconnect (ect, gaet->deleted_id);
- }
-
- gaet->inserted_id = 0;
- gaet->deleted_id = 0;
- }
-
- g_class = (GObjectClass *)parent_class;
- if (g_class->dispose)
- g_class->dispose (object);
-
-}
-
-static gboolean
-ect_check (gpointer a11y)
-{
- GalA11yECell *gaec = GAL_A11Y_E_CELL (a11y);
- ETableItem *item = gaec->item;
-
- g_return_val_if_fail ((gaec->item != NULL), FALSE);
- g_return_val_if_fail ((gaec->cell_view != NULL), FALSE);
- g_return_val_if_fail ((gaec->cell_view->ecell != NULL), FALSE);
-
- if (atk_state_set_contains_state (gaec->state_set, ATK_STATE_DEFUNCT))
- return FALSE;
-
- if (gaec->row < 0 || gaec->row >= item->rows
- || gaec->view_col <0 || gaec->view_col >= item->cols
- || gaec->model_col <0 || gaec->model_col >= e_table_model_column_count (item->table_model))
- return FALSE;
-
- if (!E_IS_CELL_TEXT (gaec->cell_view->ecell))
- return FALSE;
-
- return TRUE;
-}
-
-static G_CONST_RETURN gchar*
-ect_get_name (AtkObject * a11y)
-{
- GalA11yECell *gaec;
- char *name;
-
- if (!ect_check (a11y))
- return NULL;
-
- gaec = GAL_A11Y_E_CELL (a11y);
- name = e_cell_text_get_text_by_view (gaec->cell_view, gaec->model_col, gaec->row);
- if (name != NULL) {
- ATK_OBJECT_CLASS (parent_class)->set_name (a11y, name);
- g_free (name);
- }
-
- if (a11y->name != NULL && strcmp (a11y->name, "")) {
- return a11y->name;
- } else {
- return parent_class->get_name (a11y);
- }
-}
-
-static gchar *
-ect_get_text (AtkText *text,
- gint start_offset,
- gint end_offset)
-{
- GalA11yECell *gaec = GAL_A11Y_E_CELL (text);
- gchar *full_text;
- gchar *ret_val;
-
- if (!ect_check (text))
- return NULL;
-
- full_text = e_cell_text_get_text_by_view (gaec->cell_view, gaec->model_col, gaec->row);
-
- if (end_offset == -1)
- end_offset = strlen (full_text);
- else
- end_offset = g_utf8_offset_to_pointer (full_text, end_offset) - full_text;
-
- start_offset = g_utf8_offset_to_pointer (full_text, start_offset) - full_text;
-
- ret_val = g_strndup (full_text + start_offset, end_offset - start_offset);
-
- g_free (full_text);
-
- return ret_val;
-}
-
-static gchar *
-ect_get_text_after_offset (AtkText *text,
- gint offset,
- AtkTextBoundary boundary_type,
- gint *start_offset,
- gint *end_offset)
-{
- /* Unimplemented */
- return NULL;
-}
-
-static gchar *
-ect_get_text_at_offset (AtkText *text,
- gint offset,
- AtkTextBoundary boundary_type,
- gint *start_offset,
- gint *end_offset)
-{
- /* Unimplemented */
- return NULL;
-}
-
-static gunichar
-ect_get_character_at_offset (AtkText *text,
- gint offset)
-{
- GalA11yECell *gaec = GAL_A11Y_E_CELL (text);
- gunichar ret_val;
- gchar *at_offset;
-
- if (!ect_check (text))
- return -1;
-
- gchar *full_text = e_cell_text_get_text_by_view (gaec->cell_view, gaec->model_col, gaec->row);
- at_offset = g_utf8_offset_to_pointer (full_text, offset);
- ret_val = g_utf8_get_char_validated (at_offset, -1);
- g_free (full_text);
-
- return ret_val;
-}
-
-
-static gchar*
-ect_get_text_before_offset (AtkText *text,
- gint offset,
- AtkTextBoundary boundary_type,
- gint *start_offset,
- gint *end_offset)
-{
- /* Unimplemented */
- return NULL;
-}
-
-
-static gint
-ect_get_caret_offset (AtkText *text)
-{
- GalA11yECell *gaec = GAL_A11Y_E_CELL (text);
- gint start, end;
-
- if (!ect_check (text))
- return -1;
-
- if (e_cell_text_get_selection (gaec->cell_view,
- gaec->view_col, gaec->row,
- &start, &end)) {
- gchar *full_text = e_cell_text_get_text_by_view (gaec->cell_view, gaec->model_col, gaec->row);
- end = g_utf8_pointer_to_offset (full_text, full_text + end);
- g_free (full_text);
-
- return end;
- }
- else
- return -1;
-}
-
-static AtkAttributeSet*
-ect_get_run_attributes (AtkText *text,
- gint offset,
- gint *start_offset,
- gint *end_offset)
-{
- /* Unimplemented */
- return NULL;
-}
-
-
-static AtkAttributeSet*
-ect_get_default_attributes (AtkText *text)
-{
- /* Unimplemented */
- return NULL;
-}
-
-
-static void
-ect_get_character_extents (AtkText *text,
- gint offset,
- gint *x,
- gint *y,
- gint *width,
- gint *height,
- AtkCoordType coords)
-{
- /* Unimplemented */
-}
-
-
-static gint
-ect_get_character_count (AtkText *text)
-{
- GalA11yECell *gaec = GAL_A11Y_E_CELL (text);
- gint ret_val;
-
- if (!ect_check (text))
- return -1;
-
- gchar *full_text = e_cell_text_get_text_by_view (gaec->cell_view, gaec->model_col, gaec->row);
-
- ret_val = g_utf8_strlen (full_text, -1);
- g_free (full_text);
- return ret_val;
-}
-
-
-static gint
-ect_get_offset_at_point (AtkText *text,
- gint x,
- gint y,
- AtkCoordType coords)
-{
- /* Unimplemented */
- return 0;
-}
-
-
-static gint
-ect_get_n_selections (AtkText *text)
-{
- GalA11yECell *gaec = GAL_A11Y_E_CELL (text);
- gint selection_start, selection_end;
-
- if (!ect_check (text))
- return 0;
-
- if (e_cell_text_get_selection (gaec->cell_view,
- gaec->view_col, gaec->row,
- &selection_start,
- &selection_end)
- && selection_start != selection_end)
- return 1;
- return 0;
-}
-
-
-static gchar*
-ect_get_selection (AtkText *text,
- gint selection_num,
- gint *start_offset,
- gint *end_offset)
-{
- GalA11yECell *gaec = GAL_A11Y_E_CELL (text);
- gchar *ret_val;
- gint selection_start, selection_end;
-
- if (selection_num == 0
- && e_cell_text_get_selection (gaec->cell_view,
- gaec->view_col, gaec->row,
- &selection_start,
- &selection_end)
- && selection_start != selection_end) {
- gint real_start, real_end, len;
- gchar *full_text = e_cell_text_get_text_by_view (gaec->cell_view, gaec->model_col, gaec->row);
- len = strlen (full_text);
- real_start = MIN (selection_start, selection_end);
- real_end = MAX (selection_start, selection_end);
- real_start = MIN (MAX (0, real_start), len);
- real_end = MIN (MAX (0, real_end), len);
-
- ret_val = g_strndup (full_text + real_start, real_end - real_start);
-
- real_start = g_utf8_pointer_to_offset (full_text, full_text + real_start);
- real_end = g_utf8_pointer_to_offset (full_text, full_text + real_end);
-
- if (start_offset)
- *start_offset = real_start;
- if (end_offset)
- *end_offset = real_end;
- g_free (full_text);
- } else {
- if (start_offset)
- *start_offset = 0;
- if (end_offset)
- *end_offset = 0;
- ret_val = NULL;
- }
-
- return ret_val;
-}
-
-
-static gboolean
-ect_add_selection (AtkText *text,
- gint start_offset,
- gint end_offset)
-{
- GalA11yECell *gaec = GAL_A11Y_E_CELL (text);
-
- if (start_offset != end_offset) {
- gint real_start, real_end, len;
- gchar *full_text =
- e_cell_text_get_text_by_view (gaec->cell_view, gaec->model_col, gaec->row);
-
- len = g_utf8_strlen (full_text, -1);
- if (end_offset == -1)
- end_offset = len;
-
- real_start = MIN (start_offset, end_offset);
- real_end = MAX (start_offset, end_offset);
-
- real_start = MIN (MAX (0, real_start), len);
- real_end = MIN (MAX (0, real_end), len);
-
- real_start = g_utf8_offset_to_pointer (full_text, real_start) - full_text;
- real_end = g_utf8_offset_to_pointer (full_text, real_end) - full_text;
- g_free (full_text);
-
- if (e_cell_text_set_selection (gaec->cell_view,
- gaec->view_col, gaec->row,
- real_start, real_end)) {
- g_signal_emit_by_name (ATK_OBJECT(text), "text_selection_changed");
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-
-static gboolean
-ect_remove_selection (AtkText *text,
- gint selection_num)
-{
- GalA11yECell *gaec = GAL_A11Y_E_CELL (text);
- gint selection_start, selection_end;
-
- if (selection_num == 0
- && e_cell_text_get_selection (gaec->cell_view,
- gaec->view_col, gaec->row,
- &selection_start,
- &selection_end)
- && selection_start != selection_end
- && e_cell_text_set_selection (gaec->cell_view,
- gaec->view_col, gaec->row,
- selection_end, selection_end)) {
- g_signal_emit_by_name (ATK_OBJECT(text), "text_selection_changed");
- return TRUE;
- }
- else
- return FALSE;
-}
-
-
-static gboolean
-ect_set_selection (AtkText *text,
- gint selection_num,
- gint start_offset,
- gint end_offset)
-{
- if (selection_num == 0) {
- atk_text_add_selection (text, start_offset, end_offset);
- return TRUE;
- }
- else
- return FALSE;
-}
-
-
-static gboolean
-ect_set_caret_offset (AtkText *text,
- gint offset)
-{
- GalA11yECell *gaec = GAL_A11Y_E_CELL (text);
- gchar *full_text;
- gint len;
-
- full_text = e_cell_text_get_text_by_view (gaec->cell_view, gaec->model_col, gaec->row);
-
- len = g_utf8_strlen (full_text, -1);
- if (offset == -1)
- offset = len;
- else
- offset = MIN (MAX (0, offset), len);
-
- offset = g_utf8_offset_to_pointer (full_text, offset) - full_text;
-
- g_free (full_text);
-
- return e_cell_text_set_selection (gaec->cell_view,
- gaec->view_col, gaec->row,
- offset, offset);
-}
-
-static gboolean
-ect_set_run_attributes (AtkEditableText *text,
- AtkAttributeSet *attrib_set,
- gint start_offset,
- gint end_offset)
-{
- /* Unimplemented */
- return FALSE;
-}
-
-static void
-ect_set_text_contents (AtkEditableText *text,
- const gchar *string)
-{
- GalA11yECell *gaec = GAL_A11Y_E_CELL (text);
- ECellText *ect = E_CELL_TEXT (gaec->cell_view->ecell);
-
- e_cell_text_set_value (ect, gaec->item->table_model, gaec->model_col, gaec->row, string);
- e_table_item_enter_edit (gaec->item, gaec->view_col, gaec->row);
-}
-
-static void
-ect_insert_text (AtkEditableText *text,
- const gchar *string,
- gint length,
- gint *position)
-{
- /* Utf8 unimplemented */
- GalA11yECell *gaec = GAL_A11Y_E_CELL (text);
- ECellText *ect = E_CELL_TEXT (gaec->cell_view->ecell);
-
- gchar *full_text = e_cell_text_get_text_by_view (gaec->cell_view, gaec->model_col, gaec->row);
- gchar *result = g_strdup_printf ("%.*s%.*s%s", *position, full_text, length, string, full_text + *position);
-
- e_cell_text_set_value (ect, gaec->item->table_model, gaec->model_col, gaec->row, result);
-
- *position += length;
-
- g_free (result);
- g_free (full_text);
-}
-
-static void
-ect_copy_text (AtkEditableText *text,
- gint start_pos,
- gint end_pos)
-{
- GalA11yECell *gaec = GAL_A11Y_E_CELL (text);
- if (start_pos != end_pos
- && atk_text_set_selection (ATK_TEXT (text), 0, start_pos, end_pos))
- e_cell_text_copy_clipboard (gaec->cell_view,
- gaec->view_col, gaec->row);
-}
-
-static void
-ect_delete_text (AtkEditableText *text,
- gint start_pos,
- gint end_pos)
-{
- GalA11yECell *gaec = GAL_A11Y_E_CELL (text);
- if (start_pos != end_pos
- && atk_text_set_selection (ATK_TEXT (text), 0, start_pos, end_pos))
- e_cell_text_delete_selection (gaec->cell_view,
- gaec->view_col, gaec->row);
-}
-
-static void
-ect_cut_text (AtkEditableText *text,
- gint start_pos,
- gint end_pos)
-{
- ect_copy_text (text, start_pos, end_pos);
- ect_delete_text (text, start_pos, end_pos);
-}
-
-static void
-ect_paste_text (AtkEditableText *text,
- gint position)
-{
- GalA11yECell *gaec = GAL_A11Y_E_CELL (text);
-
- e_table_item_enter_edit (gaec->item, gaec->view_col, gaec->row);
-
- if (atk_text_set_caret_offset (ATK_TEXT (text), position))
- e_cell_text_paste_clipboard (gaec->cell_view,
- gaec->view_col, gaec->row);
-}
-
-static void
-ect_do_action_edit (AtkAction *action)
-{
- GalA11yECell *a11y = GAL_A11Y_E_CELL (action);
- ETableModel *e_table_model = a11y->item->table_model;
-
- if (e_table_model_is_cell_editable(e_table_model, a11y->model_col, a11y->row)) {
- e_table_item_enter_edit (a11y->item, a11y->view_col, a11y->row);
- }
-}
-
-/* text signal handlers */
-static void
-ect_text_inserted_cb (ECellText *text, ECellView *cell_view, int pos, int len, int row, int model_col, gpointer data)
-{
- GalA11yECellText *gaet;
- GalA11yECell *gaec;
-
- if (!ect_check (data))
- return;
- gaet = GAL_A11Y_E_CELL_TEXT (data);
- gaec = GAL_A11Y_E_CELL (data);
-
- if (cell_view == gaec->cell_view && row == gaec->row && model_col == gaec->model_col) {
- g_signal_emit_by_name (gaet, "text_changed::insert", pos, len);
-
- }
-}
-
-static void
-ect_text_deleted_cb (ECellText *text, ECellView *cell_view, int pos, int len, int row, int model_col, gpointer data)
-{
- GalA11yECellText *gaet;
- GalA11yECell *gaec;
- if (!ect_check (data))
- return;
- gaet = GAL_A11Y_E_CELL_TEXT (data);
- gaec = GAL_A11Y_E_CELL (data);
- if (cell_view == gaec->cell_view && row == gaec->row && model_col == gaec->model_col) {
- g_signal_emit_by_name (gaet, "text_changed::delete", pos, len);
- }
-}
-
-static void
-ect_atk_text_iface_init (AtkTextIface *iface)
-{
- iface->get_text = ect_get_text;
- iface->get_text_after_offset = ect_get_text_after_offset;
- iface->get_text_at_offset = ect_get_text_at_offset;
- iface->get_character_at_offset = ect_get_character_at_offset;
- iface->get_text_before_offset = ect_get_text_before_offset;
- iface->get_caret_offset = ect_get_caret_offset;
- iface->get_run_attributes = ect_get_run_attributes;
- iface->get_default_attributes = ect_get_default_attributes;
- iface->get_character_extents = ect_get_character_extents;
- iface->get_character_count = ect_get_character_count;
- iface->get_offset_at_point = ect_get_offset_at_point;
- iface->get_n_selections = ect_get_n_selections;
- iface->get_selection = ect_get_selection;
- iface->add_selection = ect_add_selection;
- iface->remove_selection = ect_remove_selection;
- iface->set_selection = ect_set_selection;
- iface->set_caret_offset = ect_set_caret_offset;
-}
-
-static void
-ect_atk_editable_text_iface_init (AtkEditableTextIface *iface)
-{
- iface->set_run_attributes = ect_set_run_attributes;
- iface->set_text_contents = ect_set_text_contents;
- iface->insert_text = ect_insert_text;
- iface->copy_text = ect_copy_text;
- iface->cut_text = ect_cut_text;
- iface->delete_text = ect_delete_text;
- iface->paste_text = ect_paste_text;
-}
-
-static void
-ect_class_init (GalA11yECellTextClass *klass)
-{
- AtkObjectClass *a11y = ATK_OBJECT_CLASS (klass);
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- parent_class = g_type_class_ref (PARENT_TYPE);
- a11y->get_name = ect_get_name;
- object_class->dispose = ect_dispose;
-}
-
-static void
-ect_action_init (GalA11yECellText *a11y)
-{
- GalA11yECell *gaec = GAL_A11Y_E_CELL (a11y);
- ECellText *ect = E_CELL_TEXT (gaec->cell_view->ecell);
- if (ect->editable && e_table_model_is_cell_editable (gaec->cell_view->e_table_model, gaec->model_col, gaec->row))
- gal_a11y_e_cell_add_action (gaec,
- _("edit"),
- _("begin editing this cell"),
- NULL,
- (ACTION_FUNC) ect_do_action_edit);
-}
-
-/**
- * gal_a11y_e_cell_text_get_type:
- * @void:
- *
- * Registers the &GalA11yECellText class if necessary, and returns the type ID
- * associated to it.
- *
- * Return value: The type ID of the &GalA11yECellText class.
- **/
-GType
-gal_a11y_e_cell_text_get_type (void)
-{
- static GType type = 0;
-
- if (!type) {
- GTypeInfo info = {
- sizeof (GalA11yECellTextClass),
- (GBaseInitFunc) NULL,
- (GBaseFinalizeFunc) NULL,
- (GClassInitFunc) ect_class_init,
- (GClassFinalizeFunc) NULL,
- NULL, /* class_data */
- sizeof (GalA11yECellText),
- 0,
- (GInstanceInitFunc) NULL,
- NULL /* value_cell_text */
- };
-
- static const GInterfaceInfo atk_text_info = {
- (GInterfaceInitFunc) ect_atk_text_iface_init,
- (GInterfaceFinalizeFunc) NULL,
- NULL
- };
-
- static const GInterfaceInfo atk_editable_text_info = {
- (GInterfaceInitFunc) ect_atk_editable_text_iface_init,
- (GInterfaceFinalizeFunc) NULL,
- NULL
- };
-
- type = g_type_register_static (PARENT_TYPE, "GalA11yECellText", &info, 0);
- g_type_add_interface_static (type, ATK_TYPE_TEXT, &atk_text_info);
- g_type_add_interface_static (type, ATK_TYPE_EDITABLE_TEXT, &atk_editable_text_info);
- gal_a11y_e_cell_type_add_action_interface (type);
- }
-
- return type;
-}
-
-static void
-cell_text_destroyed (gpointer data)
-{
- g_return_if_fail (GAL_A11Y_IS_E_CELL_TEXT (data));
-
- g_object_unref (data);
-}
-
-AtkObject *
-gal_a11y_e_cell_text_new (ETableItem *item,
- ECellView *cell_view,
- AtkObject *parent,
- int model_col,
- int view_col,
- int row)
-{
- AtkObject *a11y;
- GalA11yECell *gaec;
- GalA11yECellText *gaet;
- ECellText *ect;
-
- a11y = g_object_new (gal_a11y_e_cell_text_get_type (), NULL);
-
- gal_a11y_e_cell_construct (a11y,
- item,
- cell_view,
- parent,
- model_col,
- view_col,
- row);
- gaet = GAL_A11Y_E_CELL_TEXT (a11y);
-
- /* will be unrefed in cell_text_destroyed */
- g_object_ref (a11y);
-
- gaet->inserted_id = g_signal_connect (E_CELL_TEXT (((ECellView *)cell_view)->ecell),
- "text_inserted", G_CALLBACK (ect_text_inserted_cb), a11y);
- gaet->deleted_id = g_signal_connect (E_CELL_TEXT (((ECellView *)cell_view)->ecell),
- "text_deleted", G_CALLBACK (ect_text_deleted_cb), a11y);
-
- g_object_weak_ref (G_OBJECT (((ECellView *)cell_view)->ecell),
- (GWeakNotify) cell_text_destroyed,
- a11y);
-
- ect_action_init (gaet);
-
- ect = E_CELL_TEXT (cell_view->ecell);
- gaec = GAL_A11Y_E_CELL (a11y);
- if (ect->editable && e_table_model_is_cell_editable (gaec->cell_view->e_table_model, gaec->model_col, gaec->row))
- gal_a11y_e_cell_add_state (gaec, ATK_STATE_EDITABLE, FALSE);
- else
- gal_a11y_e_cell_remove_state (gaec, ATK_STATE_EDITABLE, FALSE);
-
- return a11y;
-}
diff --git a/a11y/e-table/gal-a11y-e-cell-text.h b/a11y/e-table/gal-a11y-e-cell-text.h
deleted file mode 100644
index 50056476c3..0000000000
--- a/a11y/e-table/gal-a11y-e-cell-text.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * Authors:
- * Christopher James Lahey <clahey@ximian.com>
- *
- * Copyright (C) 2001 Chris Lahey
- */
-
-#ifndef __GAL_A11Y_E_CELL_TEXT_H__
-#define __GAL_A11Y_E_CELL_TEXT_H__
-
-#include <glib-object.h>
-#include <gal/e-table/e-table-item.h>
-#include <gal/e-table/e-cell-text.h>
-#include <a11y/e-table/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 --git a/a11y/e-table/gal-a11y-e-cell-toggle.c b/a11y/e-table/gal-a11y-e-cell-toggle.c
deleted file mode 100644
index 21f4955d1d..0000000000
--- a/a11y/e-table/gal-a11y-e-cell-toggle.c
+++ /dev/null
@@ -1,169 +0,0 @@
-#include <gtk/gtk.h>
-#include "gal-a11y-e-cell-toggle.h"
-#include <gal/e-table/e-cell-toggle.h>
-#include <gal/e-table/e-table-model.h>
-#include <atk/atkcomponent.h>
-#include <glib/gi18n.h>
-
-#define PARENT_TYPE (gal_a11y_e_cell_get_type ())
-static GObjectClass *parent_class;
-
-static void gal_a11y_e_cell_toggle_class_init (GalA11yECellToggleClass *klass);
-
-static void
-gal_a11y_e_cell_toggle_dispose (GObject *object)
-{
- GalA11yECellToggle *a11y = GAL_A11Y_E_CELL_TOGGLE (object);
-
- ETableModel *e_table_model = GAL_A11Y_E_CELL (a11y)->item->table_model;
-
- if (e_table_model && a11y->model_id > 0) {
- g_signal_handler_disconnect (e_table_model, a11y->model_id);
- a11y->model_id = 0;
- }
-
- if (parent_class->dispose)
- parent_class->dispose (object);
-}
-
-GType
-gal_a11y_e_cell_toggle_get_type (void)
-{
- static GType type = 0;
-
- if (!type)
- {
- static const GTypeInfo tinfo =
- {
- sizeof (GalA11yECellToggleClass),
- (GBaseInitFunc) NULL, /* base init */
- (GBaseFinalizeFunc) NULL, /* base finalize */
- (GClassInitFunc) gal_a11y_e_cell_toggle_class_init, /* class init */
- (GClassFinalizeFunc) NULL, /* class finalize */
- NULL, /* class data */
- sizeof (GalA11yECellToggle), /* instance size */
- 0, /* nb preallocs */
- NULL, /* instance init */
- NULL /* value table */
- };
-
-
- type = g_type_register_static (GAL_A11Y_TYPE_E_CELL,
- "GalA11yECellToggle", &tinfo, 0);
- gal_a11y_e_cell_type_add_action_interface (type);
-
- }
- return type;
-}
-
-
-static void
-gal_a11y_e_cell_toggle_class_init (GalA11yECellToggleClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- object_class->dispose = gal_a11y_e_cell_toggle_dispose;
- parent_class = g_type_class_ref (PARENT_TYPE);
-}
-
-static void
-toggle_cell_action (GalA11yECell *cell)
-{
- gint finished;
- GdkEventButton event;
- gint x, y, width, height;
- gint row, col;
-
- row = cell->row;
- col = cell->view_col;
-
- e_table_item_get_cell_geometry (cell->item, &row, &col,
- &x, &y, &width, &height);
-
- event.x = x + width / 2 + (int)(GNOME_CANVAS_ITEM (cell->item)->x1);
- event.y = y + height / 2 + (int)(GNOME_CANVAS_ITEM (cell->item)->y1);
-
- event.type = GDK_BUTTON_PRESS;
- event.window = GTK_LAYOUT(GNOME_CANVAS_ITEM(cell->item)->canvas)->bin_window;
- event.button = 1;
- event.send_event = TRUE;
- event.time = GDK_CURRENT_TIME;
- event.axes = NULL;
-
- g_signal_emit_by_name (cell->item, "event", &event, &finished);
-}
-
-static void
-model_change_cb (ETableModel *etm,
- gint col,
- gint row,
- GalA11yECell *cell)
-{
- gint value;
-
- if (col == cell->model_col && row == cell->row) {
-
- value = GPOINTER_TO_INT (
- e_table_model_value_at (cell->cell_view->e_table_model,
- cell->model_col, cell->row));
- /* Cheat gnopernicus, or it will ignore the state change signal */
- atk_focus_tracker_notify (ATK_OBJECT (cell));
-
- if (value)
- gal_a11y_e_cell_add_state (cell, ATK_STATE_CHECKED, TRUE);
- else
- gal_a11y_e_cell_remove_state (cell, ATK_STATE_CHECKED, TRUE);
- }
-}
-
-
-AtkObject*
-gal_a11y_e_cell_toggle_new (ETableItem *item,
- ECellView *cell_view,
- AtkObject *parent,
- int model_col,
- int view_col,
- int row)
-{
- AtkObject *a11y;
- GalA11yECell *cell;
- GalA11yECellToggle *toggle_cell;
- gint value;
-
- a11y = ATK_OBJECT(g_object_new (GAL_A11Y_TYPE_E_CELL_TOGGLE, NULL));
-
- g_return_val_if_fail (a11y != NULL, NULL);
-
- cell = GAL_A11Y_E_CELL(a11y);
- toggle_cell = GAL_A11Y_E_CELL_TOGGLE(a11y);
- a11y->role = ATK_ROLE_TABLE_CELL;
-
- gal_a11y_e_cell_construct (a11y,
- item,
- cell_view,
- parent,
- model_col,
- view_col,
- row);
-
- gal_a11y_e_cell_add_action (cell,
- _("toggle"), /* action name*/
- _("toggle the cell"), /* action description */
- NULL, /* action keybinding */
- toggle_cell_action);
-
- toggle_cell->model_id = g_signal_connect (item->table_model,
- "model_cell_changed",
- (GCallback) model_change_cb,
- a11y);
-
- value = GPOINTER_TO_INT (
- e_table_model_value_at (cell->cell_view->e_table_model,
- cell->model_col, cell->row));
- if (value)
- gal_a11y_e_cell_add_state (cell, ATK_STATE_CHECKED, FALSE);
- else
- gal_a11y_e_cell_remove_state (cell, ATK_STATE_CHECKED, FALSE);
-
- return a11y;
-}
diff --git a/a11y/e-table/gal-a11y-e-cell-toggle.h b/a11y/e-table/gal-a11y-e-cell-toggle.h
deleted file mode 100644
index 06f9448e02..0000000000
--- a/a11y/e-table/gal-a11y-e-cell-toggle.h
+++ /dev/null
@@ -1,47 +0,0 @@
-#ifndef __GAL_A11Y_E_CELL_TOGGLE_H__
-#define __GAL_A11Y_E_CELL_TOGGLE_H__
-
-#include <atk/atk.h>
-#include "gal-a11y-e-cell.h"
-#include "gal-a11y-e-cell-toggle.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-#define GAL_A11Y_TYPE_E_CELL_TOGGLE (gal_a11y_e_cell_toggle_get_type ())
-#define GAL_A11Y_E_CELL_TOGGLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_CELL_TOGGLE, GalA11yECellToggle))
-#define GAL_A11Y_E_CELL_TOGGLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_E_CELL_TOGGLE, GalA11yECellToggleClass))
-#define GAL_A11Y_IS_E_CELL_TOGGLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_CELL_TOGGLE))
-#define GAL_A11Y_IS_E_CELL_TOGGLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_CELL_TOGGLE))
-#define GAL_A11Y_E_CELL_TOGGLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GAL_A11Y_TYPE_E_CELL_TOGGLE, GalA11yECellToggleClass))
-
-typedef struct _GalA11yECellToggle GalA11yECellToggle;
-typedef struct _GalA11yECellToggleClass GalA11yECellToggleClass;
-
-struct _GalA11yECellToggle
-{
- GalA11yECell parent;
- gint model_id;
-};
-
-GType gal_a11y_e_cell_toggle_get_type (void);
-
-struct _GalA11yECellToggleClass
-{
- GalA11yECellClass parent_class;
-};
-
-AtkObject *gal_a11y_e_cell_toggle_new (ETableItem *item,
- ECellView *cell_view,
- AtkObject *parent,
- int model_col,
- int view_col,
- int row);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-
-#endif /* __GAL_A11Y_E_CELL_TOGGLE_H__ */
diff --git a/a11y/e-table/gal-a11y-e-cell-tree.c b/a11y/e-table/gal-a11y-e-cell-tree.c
deleted file mode 100644
index 126bbcfbe5..0000000000
--- a/a11y/e-table/gal-a11y-e-cell-tree.c
+++ /dev/null
@@ -1,210 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * Authors:
- * Tim Wo <tim.wo@sun.com>, Sun Microsystem Inc. 2003.
- *
- * Copyright (C) 2002 Ximian, Inc.
- */
-
-#include <config.h>
-#include <atk/atk.h>
-#include "gal-a11y-e-cell-tree.h"
-#include "gal-a11y-e-cell-registry.h"
-#include "gal-a11y-util.h"
-#include "gal/e-table/e-cell-tree.h"
-#include "gal/e-table/e-table.h"
-#include "gal/e-table/e-tree-table-adapter.h"
-#include <glib/gi18n.h>
-
-#define CS_CLASS(a11y) (G_TYPE_INSTANCE_GET_CLASS ((a11y), C_TYPE_STREAM, GalA11yECellTreeClass))
-static AtkObjectClass *a11y_parent_class;
-#define A11Y_PARENT_TYPE (gal_a11y_e_cell_get_type ())
-
-static void
-ectr_model_row_changed_cb (ETableModel *etm,
- gint row,
- GalA11yECell *a11y)
-{
- ETreePath node;
- ETreeModel *tree_model;
- ETreeTableAdapter *tree_table_adapter;
-
- g_return_if_fail (a11y);
- if (a11y->row != row)
- return;
-
- node = e_table_model_value_at (etm, -1, a11y->row);
- tree_model = e_table_model_value_at (etm, -2, a11y->row);
- tree_table_adapter = e_table_model_value_at (etm, -3, a11y->row);
-
- if (e_tree_model_node_is_expandable (tree_model, node)) {
- gboolean is_exp = e_tree_table_adapter_node_is_expanded (tree_table_adapter, node);
- if (is_exp)
- gal_a11y_e_cell_add_state (a11y, ATK_STATE_EXPANDED, TRUE);
- else
- gal_a11y_e_cell_remove_state (a11y, ATK_STATE_EXPANDED, TRUE);
- }
-}
-
-static void
-ectr_subcell_weak_ref (GalA11yECellTree *a11y,
- GalA11yECell *subcell_a11y)
-{
- g_signal_handler_disconnect (GAL_A11Y_E_CELL (a11y)->item->table_model,
- a11y->model_row_changed_id);
- g_object_unref (a11y);
-}
-
-static void
-ectr_do_action_expand (AtkAction *action)
-{
- GalA11yECell *a11y;
- ETableModel *table_model;
- ETreePath node;
- ETreeModel *tree_model;
- ETreeTableAdapter *tree_table_adapter;
-
- a11y = GAL_A11Y_E_CELL (action);
- table_model = a11y->item->table_model;
- node = e_table_model_value_at (table_model, -1, a11y->row);
- tree_model = e_table_model_value_at (table_model, -2, a11y->row);
- tree_table_adapter = e_table_model_value_at (table_model, -3, a11y->row);
-
- if (e_tree_model_node_is_expandable (tree_model, node)) {
- e_tree_table_adapter_node_set_expanded (tree_table_adapter,
- node,
- TRUE);
- gal_a11y_e_cell_add_state (a11y, ATK_STATE_EXPANDED, TRUE);
- }
-}
-
-static void
-ectr_do_action_collapse (AtkAction *action)
-{
- GalA11yECell *a11y;
- ETableModel *table_model;
- ETreePath node;
- ETreeModel *tree_model;
- ETreeTableAdapter *tree_table_adapter;
-
- a11y = GAL_A11Y_E_CELL (action);
- table_model = a11y->item->table_model;
- node = e_table_model_value_at (table_model, -1, a11y->row);
- tree_model = e_table_model_value_at (table_model, -2, a11y->row);
- tree_table_adapter = e_table_model_value_at (table_model, -3, a11y->row);
-
- if (e_tree_model_node_is_expandable (tree_model, node)) {
- e_tree_table_adapter_node_set_expanded (tree_table_adapter,
- node,
- FALSE);
- gal_a11y_e_cell_remove_state (a11y, ATK_STATE_EXPANDED, TRUE);
- }
-}
-
-static void
-ectr_class_init (GalA11yECellTreeClass *klass)
-{
- a11y_parent_class = g_type_class_ref (A11Y_PARENT_TYPE);
-}
-
-static void
-ectr_init (GalA11yECellTree *a11y)
-{
-}
-
-GType
-gal_a11y_e_cell_tree_get_type (void)
-{
- static GType type = 0;
-
- if (!type) {
- GTypeInfo info = {
- sizeof (GalA11yECellTreeClass),
- (GBaseInitFunc) NULL,
- (GBaseFinalizeFunc) NULL,
- (GClassInitFunc) ectr_class_init,
- (GClassFinalizeFunc) NULL,
- NULL, /* class_data */
- sizeof (GalA11yECellTree),
- 0,
- (GInstanceInitFunc) ectr_init,
- NULL /* value_cell_text */
- };
-
- type = g_type_register_static (A11Y_PARENT_TYPE, "GalA11yECellTree", &info, 0);
- gal_a11y_e_cell_type_add_action_interface (type);
- }
-
- return type;
-}
-
-AtkObject *
-gal_a11y_e_cell_tree_new (ETableItem *item,
- ECellView *cell_view,
- AtkObject *parent,
- int model_col,
- int view_col,
- int row)
-{
- AtkObject *subcell_a11y;
- GalA11yECellTree *a11y;
-
- ETreePath node;
- ETreeModel *tree_model;
- ETreeTableAdapter *tree_table_adapter;
-
- ECellView *subcell_view;
- subcell_view = e_cell_tree_view_get_subcell_view (cell_view);
-
- if (subcell_view->ecell) {
- subcell_a11y = gal_a11y_e_cell_registry_get_object (NULL,
- item,
- subcell_view,
- parent,
- model_col,
- view_col,
- row);
- gal_a11y_e_cell_add_action (GAL_A11Y_E_CELL (subcell_a11y),
- _("expand"),
- _("expands the row in the ETree containing this cell"),
- NULL,
- (ACTION_FUNC)ectr_do_action_expand);
-
- gal_a11y_e_cell_add_action (GAL_A11Y_E_CELL (subcell_a11y),
- _("collapse"),
- _("collapses the row in the ETree containing this cell"),
- NULL,
- (ACTION_FUNC)ectr_do_action_collapse);
-
- /* init AtkStates for the cell's a11y object */
- node = e_table_model_value_at (item->table_model, -1, row);
- tree_model = e_table_model_value_at (item->table_model, -2, row);
- tree_table_adapter = e_table_model_value_at (item->table_model, -3, row);
- if (e_tree_model_node_is_expandable (tree_model, node)) {
- gal_a11y_e_cell_add_state (GAL_A11Y_E_CELL (subcell_a11y), ATK_STATE_EXPANDABLE, FALSE);
- if (e_tree_table_adapter_node_is_expanded (tree_table_adapter, node))
- gal_a11y_e_cell_add_state (GAL_A11Y_E_CELL (subcell_a11y), ATK_STATE_EXPANDED, FALSE);
- }
- }
- else
- subcell_a11y = NULL;
-
- /* create a companion a11y object, this object has type GalA11yECellTree
- and it connects to some signals to determine whether a tree cell is
- expanded or collapsed */
- a11y = g_object_new (gal_a11y_e_cell_tree_get_type (), NULL);
- gal_a11y_e_cell_construct (ATK_OBJECT (a11y),
- item,
- cell_view,
- parent,
- model_col,
- view_col,
- row);
- a11y->model_row_changed_id =
- g_signal_connect (item->table_model, "model_row_changed",
- G_CALLBACK (ectr_model_row_changed_cb),
- subcell_a11y);
- g_object_weak_ref (G_OBJECT (subcell_a11y), (GWeakNotify) ectr_subcell_weak_ref, a11y);
-
- return subcell_a11y;
-}
diff --git a/a11y/e-table/gal-a11y-e-cell-tree.h b/a11y/e-table/gal-a11y-e-cell-tree.h
deleted file mode 100644
index 355670b5a4..0000000000
--- a/a11y/e-table/gal-a11y-e-cell-tree.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * Authors:
- * Tim Wo <tim.wo@sun.com>, Sun Microsystem Inc. 2003.
- *
- * Copyright (C) 2002 Ximian, Inc.
- */
-
-#ifndef __GAL_A11Y_E_CELL_TREE_H__
-#define __GAL_A11Y_E_CELL_TREE_H__
-
-#include <glib-object.h>
-#include <gal/e-table/e-table-item.h>
-#include <gal/e-table/e-cell-tree.h>
-#include "gal-a11y-e-cell.h"
-
-#define GAL_A11Y_TYPE_E_CELL_TREE (gal_a11y_e_cell_tree_get_type ())
-#define GAL_A11Y_E_CELL_TREE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_CELL_TREE, GalA11yECellTree))
-#define GAL_A11Y_E_CELL_TREE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_CELL_TREE, GalA11yECellTreeClass))
-#define GAL_A11Y_IS_E_CELL_TREE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_CELL_TREE))
-#define GAL_A11Y_IS_E_CELL_TREE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_CELL_TREE))
-
-typedef struct _GalA11yECellTree GalA11yECellTree;
-typedef struct _GalA11yECellTreeClass GalA11yECellTreeClass;
-typedef struct _GalA11yECellTreePrivate GalA11yECellTreePrivate;
-
-/* This struct should actually be larger as this isn't what we derive from.
- * The GalA11yECellTreePrivate comes right after the parent class structure.
- **/
-struct _GalA11yECellTree {
- GalA11yECell object;
-
- int model_row_changed_id;
-};
-
-struct _GalA11yECellTreeClass {
- GalA11yECellClass parent_class;
-};
-
-
-/* Standard Glib function */
-GType gal_a11y_e_cell_tree_get_type (void);
-AtkObject *gal_a11y_e_cell_tree_new (ETableItem *item,
- ECellView *cell_view,
- AtkObject *parent,
- int model_col,
- int view_col,
- int row);
-
-#endif /* ! __GAL_A11Y_E_CELL_TREE_H__ */
diff --git a/a11y/e-table/gal-a11y-e-cell-vbox.c b/a11y/e-table/gal-a11y-e-cell-vbox.c
deleted file mode 100644
index 4f2c156da8..0000000000
--- a/a11y/e-table/gal-a11y-e-cell-vbox.c
+++ /dev/null
@@ -1,214 +0,0 @@
-/* Evolution Accessibility: gal-a11y-e-cell-vbox.c
- *
- * Copyright (C) 2004 Sun Microsystem, Inc.
- *
- * 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., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- *
- * Author: Eric Zhao <eric.zhao@sun.com> Sun Microsystem Inc., 2004
- *
- */
-#include "gal-a11y-e-cell-vbox.h"
-#include "gal-a11y-e-cell-registry.h"
-#include <gal/e-table/e-cell-vbox.h>
-#include <atk/atkcomponent.h>
-
-static GObjectClass *parent_class;
-static AtkComponentIface *component_parent_iface;
-#define PARENT_TYPE (gal_a11y_e_cell_get_type ())
-
-static gint
-ecv_get_n_children (AtkObject *a11y)
-{
- g_return_val_if_fail (GAL_A11Y_IS_E_CELL_VBOX (a11y), 0);
- GalA11yECellVbox *gaev = GAL_A11Y_E_CELL_VBOX (a11y);
- return (gaev->a11y_subcell_count);
-}
-
-static void
-subcell_destroyed (gpointer data)
-{
- GalA11yECell *cell;
- AtkObject *parent;
- GalA11yECellVbox *gaev;
-
- g_return_if_fail (GAL_A11Y_IS_E_CELL (data));
- cell = GAL_A11Y_E_CELL (data);
-
- parent = atk_object_get_parent (ATK_OBJECT (cell));
- g_return_if_fail (GAL_A11Y_IS_E_CELL_VBOX (parent));
- gaev = GAL_A11Y_E_CELL_VBOX (parent);
-
- if (cell->view_col < gaev->a11y_subcell_count)
- gaev->a11y_subcells[cell->view_col] = NULL;
-}
-
-static AtkObject*
-ecv_ref_child (AtkObject *a11y, gint i)
-{
- GalA11yECellVbox *gaev = GAL_A11Y_E_CELL_VBOX (a11y);
- GalA11yECell *gaec = GAL_A11Y_E_CELL (a11y);
- ECellVboxView *ecvv = (ECellVboxView *) (gaec->cell_view);
- AtkObject *ret;
- if (i < gaev->a11y_subcell_count) {
- if (gaev->a11y_subcells[i] == NULL) {
- gint model_col, row;
- row = gaec->row;
- model_col = ecvv->model_cols[i];
- ECellView *subcell_view = ecvv->subcell_views[i];
- ret = gal_a11y_e_cell_registry_get_object (NULL,
- gaec->item,
- subcell_view,
- a11y,
- model_col,
- gaec->view_col, /* FIXME should the view column use a fake one or the same as its parent? */
- row);
- gaev->a11y_subcells[i] = ret;
- g_object_ref (ret);
- g_object_weak_ref (G_OBJECT (ret),
- (GWeakNotify) subcell_destroyed,
- ret);
- } else {
- ret = (AtkObject *) gaev->a11y_subcells[i];
- if (ATK_IS_OBJECT (ret))
- g_object_ref (ret);
- else
- ret = NULL;
- }
- } else {
- ret = NULL;
- }
-
- return ret;
-}
-
-static void
-ecv_dispose (GObject *object)
-{
- GalA11yECellVbox *gaev = GAL_A11Y_E_CELL_VBOX (object);
- if (gaev->a11y_subcells)
- g_free (gaev->a11y_subcells);
-
- if (parent_class->dispose)
- parent_class->dispose (object);
-}
-
-/* AtkComponet interface */
-static AtkObject*
-ecv_ref_accessible_at_point (AtkComponent *component,
- gint x,
- gint y,
- AtkCoordType coord_type)
-{
- gint x0, y0, width, height;
- int subcell_height, i;
-
- GalA11yECell *gaec = GAL_A11Y_E_CELL (component);
- ECellVboxView *ecvv = (ECellVboxView *) (gaec->cell_view);
-
- atk_component_get_extents (component, &x0, &y0, &width, &height, coord_type);
- x -= x0;
- y -= y0;
- if (x < 0 || x > width || y < 0 || y > height)
- return NULL;
-
- for (i = 0; i < ecvv->subcell_view_count; i++) {
- subcell_height = e_cell_height (ecvv->subcell_views[i], ecvv->model_cols[i], gaec->view_col, gaec->row);
- if ( 0 <= y && y <= subcell_height) {
- return ecv_ref_child ((AtkObject *)component, i);
- } else
- y -= subcell_height;
- }
-
- return NULL;
-}
-
-static void
-ecv_class_init (GalA11yECellVboxClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- AtkObjectClass *a11y_class = ATK_OBJECT_CLASS (klass);
- parent_class = g_type_class_ref (PARENT_TYPE);
-
- object_class->dispose = ecv_dispose;
-
- a11y_class->get_n_children = ecv_get_n_children;
- a11y_class->ref_child = ecv_ref_child;
-}
-
-static void
-ecv_init (GalA11yECellVbox *a11y)
-{
-}
-
-static void
-ecv_atk_component_iface_init (AtkComponentIface *iface)
-{
- component_parent_iface = g_type_interface_peek_parent (iface);
-
- iface->ref_accessible_at_point = ecv_ref_accessible_at_point;
-}
-
-GType
-gal_a11y_e_cell_vbox_get_type (void)
-{
- static GType type = 0;
- if (!type) {
- GTypeInfo info = {
- sizeof (GalA11yECellVboxClass),
- (GBaseInitFunc) NULL,
- (GBaseFinalizeFunc) NULL,
- (GClassInitFunc) ecv_class_init,
- (GClassFinalizeFunc) NULL,
- NULL, /* class_data */
- sizeof (GalA11yECellVbox),
- 0,
- (GInstanceInitFunc) ecv_init,
- NULL /* value_cell */
- };
-
- static const GInterfaceInfo atk_component_info = {
- (GInterfaceInitFunc) ecv_atk_component_iface_init,
- (GInterfaceFinalizeFunc) NULL,
- NULL
- };
-
- type = g_type_register_static (PARENT_TYPE, "GalA11yECellVbox", &info, 0);
- gal_a11y_e_cell_type_add_action_interface (type);
- g_type_add_interface_static (type, ATK_TYPE_COMPONENT, &atk_component_info);
- }
-
- return type;
-}
-
-AtkObject *gal_a11y_e_cell_vbox_new (ETableItem *item,
- ECellView *cell_view,
- AtkObject *parent,
- int model_col,
- int view_col,
- int row)
-{
- AtkObject *a11y;
-
- a11y = g_object_new (gal_a11y_e_cell_vbox_get_type (), NULL);
-
- gal_a11y_e_cell_construct (a11y, item, cell_view, parent, model_col, view_col, row);
-
- GalA11yECell *gaec = GAL_A11Y_E_CELL (a11y);
- GalA11yECellVbox *gaev = GAL_A11Y_E_CELL_VBOX (a11y);
- ECellVboxView *ecvv = (ECellVboxView *) (gaec->cell_view);
- gaev->a11y_subcell_count = ecvv->subcell_view_count;
- gaev->a11y_subcells = g_malloc0 (sizeof(AtkObject *)*gaev->a11y_subcell_count);
- return a11y;
-}
diff --git a/a11y/e-table/gal-a11y-e-cell-vbox.h b/a11y/e-table/gal-a11y-e-cell-vbox.h
deleted file mode 100644
index ea0c9d8dc9..0000000000
--- a/a11y/e-table/gal-a11y-e-cell-vbox.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/* Evolution Accessibility: gal-a11y-e-cell-vbox.h
- *
- * Copyright (C) 2004 Sun Microsystem, Inc.
- *
- * 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., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- *
- * Author: Eric Zhao <eric.zhao@sun.com> Sun Microsystem Inc., 2004
- *
- */
-#ifndef __GAL_A11Y_E_CELL_VBOX_H__
-#define __GAL_A11Y_E_CELL_VBOX_H__
-
-#include "gal-a11y-e-cell.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-#define GAL_A11Y_TYPE_E_CELL_VBOX (gal_a11y_e_cell_vbox_get_type ())
-#define GAL_A11Y_E_CELL_VBOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_CELL_VBOX, GalA11yECellVbox))
-#define GAL_A11Y_E_CELL_VBOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_E_CELL_VBOX, GalA11yECellVboxClass))
-#define GAL_A11Y_IS_E_CELL_VBOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_CELL_VBOX))
-#define GAL_A11Y_IS_E_CELL_VBOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_CELL_VBOX))
-#define GAL_A11Y_E_CELL_VBOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GAL_A11Y_TYPE_E_CELL_VBOX, GalA11yECellVboxClass))
-
-typedef struct _GalA11yECellVbox GalA11yECellVbox;
-typedef struct _GalA11yECellVboxClass GalA11yECellVboxClass;
-
-struct _GalA11yECellVbox
-{
- GalA11yECell object;
- int a11y_subcell_count;
- gpointer *a11y_subcells;
-};
-
-struct _GalA11yECellVboxClass
-{
- GalA11yECellClass parent_class;
-};
-
-GType gal_a11y_e_cell_vbox_get_type (void);
-AtkObject *gal_a11y_e_cell_vbox_new (ETableItem *item,
- ECellView *cell_view,
- AtkObject *parent,
- int model_col,
- int view_col,
- int row);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-#endif /* __GAL_A11Y_E_CELL_VBOX_H__ */
diff --git a/a11y/e-table/gal-a11y-e-cell.c b/a11y/e-table/gal-a11y-e-cell.c
deleted file mode 100644
index f22b8f6b44..0000000000
--- a/a11y/e-table/gal-a11y-e-cell.c
+++ /dev/null
@@ -1,621 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * Authors:
- * Christopher James Lahey <clahey@ximian.com>
- *
- * Copyright (C) 2002 Ximian, Inc.
- */
-
-#include <config.h>
-#include <string.h>
-#include "gal/e-table/e-table.h"
-#include "gal/e-table/e-tree.h"
-#include "gal-a11y-e-table-item.h"
-#include "gal-a11y-e-cell.h"
-#include "gal-a11y-util.h"
-#include <atk/atkobject.h>
-#include <atk/atkcomponent.h>
-#include <atk/atkaction.h>
-#include <atk/atkstateset.h>
-#include <gtk/gtkwindow.h>
-#include <glib/gi18n.h>
-
-#define CS_CLASS(a11y) (G_TYPE_INSTANCE_GET_CLASS ((a11y), C_TYPE_STREAM, GalA11yECellClass))
-static GObjectClass *parent_class;
-#define PARENT_TYPE (atk_object_get_type ())
-
-
-#if 0
-static void
-unref_item (gpointer user_data, GObject *obj_loc)
-{
- GalA11yECell *a11y = GAL_A11Y_E_CELL (user_data);
- a11y->item = NULL;
- g_object_unref (a11y);
-}
-
-static void
-unref_cell (gpointer user_data, GObject *obj_loc)
-{
- GalA11yECell *a11y = GAL_A11Y_E_CELL (user_data);
- a11y->cell_view = NULL;
- g_object_unref (a11y);
-}
-#endif
-
-static gboolean
-is_valid (AtkObject *cell)
-{
- GalA11yECell *a11y = GAL_A11Y_E_CELL (cell);
- GalA11yETableItem *a11yItem = GAL_A11Y_E_TABLE_ITEM (a11y->parent);
- AtkStateSet *item_ss;
- gboolean ret = TRUE;
-
- item_ss = atk_object_ref_state_set (ATK_OBJECT (a11yItem));
- if (atk_state_set_contains_state (item_ss, ATK_STATE_DEFUNCT))
- ret = FALSE;
-
- g_object_unref (item_ss);
-
- if (ret && atk_state_set_contains_state (a11y->state_set, ATK_STATE_DEFUNCT))
- ret = FALSE;
-
- return ret;
-}
-
-static void
-gal_a11y_e_cell_dispose (GObject *object)
-{
- GalA11yECell *a11y = GAL_A11Y_E_CELL (object);
-
-#if 0
- if (a11y->item)
- g_object_unref (G_OBJECT (a11y->item)); /*, unref_item, a11y); */
- if (a11y->cell_view)
- g_object_unref (G_OBJECT (a11y->cell_view)); /*, unref_cell, a11y); */
- if (a11y->parent)
- g_object_unref (a11y->parent);
-#endif
-
- if (a11y->state_set) {
- g_object_unref (a11y->state_set);
- a11y->state_set = NULL;
- }
-
- if (parent_class->dispose)
- parent_class->dispose (object);
-
-}
-
-/* Static functions */
-static G_CONST_RETURN gchar*
-gal_a11y_e_cell_get_name (AtkObject * a11y)
-{
- GalA11yECell *cell = GAL_A11Y_E_CELL (a11y);
- ETableCol *ecol;
-
- if (a11y->name != NULL && strcmp (a11y->name, ""))
- return a11y->name;
-
- if (cell->item != NULL) {
- ecol = e_table_header_get_column (cell->item->header, cell->view_col);
- if (ecol != NULL)
- return ecol->text;
- }
-
- return _("Table Cell");
-}
-
-static AtkStateSet *
-gal_a11y_e_cell_ref_state_set (AtkObject *accessible)
-{
- GalA11yECell *cell = GAL_A11Y_E_CELL (accessible);
-
- g_return_val_if_fail (cell->state_set, NULL);
-
- g_object_ref(cell->state_set);
-
- return cell->state_set;
-}
-
-static AtkObject*
-gal_a11y_e_cell_get_parent (AtkObject *accessible)
-{
- GalA11yECell *a11y = GAL_A11Y_E_CELL (accessible);
- return a11y->parent;
-}
-
-static gint
-gal_a11y_e_cell_get_index_in_parent (AtkObject *accessible)
-{
- GalA11yECell *a11y = GAL_A11Y_E_CELL (accessible);
-
- if (!is_valid (accessible))
- return -1;
-
- return a11y->row * a11y->item->cols + a11y->view_col;
-}
-
-
-/* Component IFace */
-static void
-gal_a11y_e_cell_get_extents (AtkComponent *component,
- gint *x,
- gint *y,
- gint *width,
- gint *height,
- AtkCoordType coord_type)
-{
- GalA11yECell *a11y = GAL_A11Y_E_CELL (component);
- GtkWidget *tableOrTree;
- int row;
- int col;
- int xval;
- int yval;
-
- row = a11y->row;
- col = a11y->view_col;
-
- tableOrTree = gtk_widget_get_parent (GTK_WIDGET (a11y->item->parent.canvas));
- if (E_IS_TREE (tableOrTree)) {
- e_tree_get_cell_geometry (E_TREE (tableOrTree),
- row, col, &xval, &yval,
- width, height);
- } else {
- e_table_get_cell_geometry (E_TABLE (tableOrTree),
- row, col, &xval, &yval,
- width, height);
- }
-
- atk_component_get_position (ATK_COMPONENT (a11y->parent),
- x, y, coord_type);
- if (x && *x != G_MININT)
- *x += xval;
- if (y && *y != G_MININT)
- *y += yval;
-}
-
-static gboolean
-gal_a11y_e_cell_grab_focus (AtkComponent *component)
-{
- GalA11yECell *a11y;
- gint index;
- GtkWidget *toplevel;
- GalA11yETableItem *a11yTableItem;
-
- a11y = GAL_A11Y_E_CELL (component);
- a11yTableItem = GAL_A11Y_E_TABLE_ITEM (a11y->parent);
- index = atk_object_get_index_in_parent (ATK_OBJECT (a11y));
-
- atk_selection_clear_selection (ATK_SELECTION (a11yTableItem));
- atk_selection_add_selection (ATK_SELECTION (a11yTableItem), index);
-
- gtk_widget_grab_focus (GTK_WIDGET (GNOME_CANVAS_ITEM (a11y->item)->canvas));
- toplevel = gtk_widget_get_toplevel (GTK_WIDGET (GNOME_CANVAS_ITEM (a11y->item)->canvas));
- if (toplevel && GTK_WIDGET_TOPLEVEL (toplevel))
- gtk_window_present (GTK_WINDOW (toplevel));
-
- return TRUE;
-}
-
-/* Table IFace */
-
-static void
-gal_a11y_e_cell_atk_component_iface_init (AtkComponentIface *iface)
-{
- iface->get_extents = gal_a11y_e_cell_get_extents;
- iface->grab_focus = gal_a11y_e_cell_grab_focus;
-}
-
-static void
-gal_a11y_e_cell_class_init (GalA11yECellClass *klass)
-{
- AtkObjectClass *atk_object_class = ATK_OBJECT_CLASS (klass);
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- parent_class = g_type_class_ref (PARENT_TYPE);
-
- object_class->dispose = gal_a11y_e_cell_dispose;
-
- atk_object_class->get_parent = gal_a11y_e_cell_get_parent;
- atk_object_class->get_index_in_parent = gal_a11y_e_cell_get_index_in_parent;
- atk_object_class->ref_state_set = gal_a11y_e_cell_ref_state_set;
- atk_object_class->get_name = gal_a11y_e_cell_get_name;
-}
-
-static void
-gal_a11y_e_cell_init (GalA11yECell *a11y)
-{
- a11y->item = NULL;
- a11y->cell_view = NULL;
- a11y->parent = NULL;
- a11y->model_col = -1;
- a11y->view_col = -1;
- a11y->row = -1;
-
- 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);
- atk_state_set_add_state (a11y->state_set, ATK_STATE_VISIBLE);
-}
-
-
-static ActionInfo *
-_gal_a11y_e_cell_get_action_info (GalA11yECell *cell,
- gint index)
-{
- GList *list_node;
-
- g_return_val_if_fail (GAL_A11Y_IS_E_CELL (cell), NULL);
- if (cell->action_list == NULL)
- return NULL;
- list_node = g_list_nth (cell->action_list, index);
- if (!list_node)
- return NULL;
- return (ActionInfo *) (list_node->data);
-}
-
-static void
-_gal_a11y_e_cell_destroy_action_info (gpointer action_info,
- gpointer user_data)
-{
- ActionInfo *info = (ActionInfo *)action_info;
-
- g_return_if_fail (info != NULL);
- g_free (info->name);
- g_free (info->description);
- g_free (info->keybinding);
- g_free (info);
-}
-
-
-gboolean
-gal_a11y_e_cell_add_action ( GalA11yECell * cell,
- const gchar *action_name,
- const gchar *action_description,
- const gchar *action_keybinding,
- ACTION_FUNC action_func)
-{
- ActionInfo *info;
- g_return_val_if_fail (GAL_A11Y_IS_E_CELL (cell), FALSE);
- info = g_new (ActionInfo, 1);
-
- if (action_name != NULL)
- info->name = g_strdup (action_name);
- else
- info->name = NULL;
-
- if (action_description != NULL)
- info->description = g_strdup (action_description);
- else
- info->description = NULL;
- if (action_keybinding != NULL)
- info->keybinding = g_strdup (action_keybinding);
- else
- info->keybinding = NULL;
- info->do_action_func = action_func;
-
- cell->action_list = g_list_append (cell->action_list, (gpointer) info);
- return TRUE;
-}
-
-gboolean
-gal_a11y_e_cell_remove_action (GalA11yECell *cell,
- gint action_index)
-{
- GList *list_node;
-
- g_return_val_if_fail (GAL_A11Y_IS_E_CELL (cell), FALSE);
- list_node = g_list_nth (cell->action_list, action_index);
- if (!list_node)
- return FALSE;
- g_return_val_if_fail (list_node->data != NULL, FALSE);
- _gal_a11y_e_cell_destroy_action_info (list_node->data, NULL);
- cell->action_list = g_list_remove_link (cell->action_list, list_node);
-
- return TRUE;
-}
-
-gboolean
-gal_a11y_e_cell_remove_action_by_name (GalA11yECell *cell,
- const gchar *action_name)
-{
- GList *list_node;
- gboolean action_found= FALSE;
-
- g_return_val_if_fail (GAL_A11Y_IS_E_CELL (cell), FALSE);
- for (list_node = cell->action_list; list_node && !action_found;
- list_node = list_node->next) {
- if (!g_strcasecmp (((ActionInfo *)(list_node->data))->name, action_name)) {
- action_found = TRUE;
- break;
- }
- }
-
- g_return_val_if_fail (action_found, FALSE);
- _gal_a11y_e_cell_destroy_action_info (list_node->data, NULL);
- cell->action_list = g_list_remove_link (cell->action_list, list_node);
-
- return TRUE;
-}
-
-static gint
-gal_a11y_e_cell_action_get_n_actions (AtkAction *action)
-{
- GalA11yECell *cell = GAL_A11Y_E_CELL(action);
- if (cell->action_list != NULL)
- return g_list_length (cell->action_list);
- else
- return 0;
-}
-
-static G_CONST_RETURN gchar *
-gal_a11y_e_cell_action_get_name (AtkAction *action,
- gint index)
-{
- GalA11yECell *cell = GAL_A11Y_E_CELL(action);
- ActionInfo *info = _gal_a11y_e_cell_get_action_info (cell, index);
-
- if (info == NULL)
- return NULL;
- return info->name;
-}
-
-static G_CONST_RETURN gchar *
-gal_a11y_e_cell_action_get_description (AtkAction *action,
- gint index)
-{
- GalA11yECell *cell = GAL_A11Y_E_CELL(action);
- ActionInfo *info = _gal_a11y_e_cell_get_action_info (cell, index);
-
- if (info == NULL)
- return NULL;
- return info->description;
-}
-
-static gboolean
-gal_a11y_e_cell_action_set_description (AtkAction *action,
- gint index,
- const gchar *desc)
-{
- GalA11yECell *cell = GAL_A11Y_E_CELL(action);
- ActionInfo *info = _gal_a11y_e_cell_get_action_info (cell, index);
-
- if (info == NULL)
- return FALSE;
- g_free (info->description);
- info->description = g_strdup (desc);
- return TRUE;
-}
-
-static G_CONST_RETURN gchar *
-gal_a11y_e_cell_action_get_keybinding (AtkAction *action,
- gint index)
-{
- GalA11yECell *cell = GAL_A11Y_E_CELL(action);
- ActionInfo *info = _gal_a11y_e_cell_get_action_info (cell, index);
- if (info == NULL)
- return NULL;
-
- return info->keybinding;
-}
-
-static gboolean
-idle_do_action (gpointer data)
-{
- GalA11yECell *cell;
-
- cell = GAL_A11Y_E_CELL (data);
-
- if (!is_valid (ATK_OBJECT (cell)))
- return FALSE;
-
- cell->action_idle_handler = 0;
- cell->action_func (cell);
-
- return FALSE;
-}
-
-static gboolean
-gal_a11y_e_cell_action_do_action (AtkAction *action,
- gint index)
-{
- GalA11yECell *cell = GAL_A11Y_E_CELL(action);
- ActionInfo *info = _gal_a11y_e_cell_get_action_info (cell, index);
-
- if (!is_valid (ATK_OBJECT (action)))
- return FALSE;
-
- if (info == NULL)
- return FALSE;
- g_return_val_if_fail (info->do_action_func, FALSE);
- if (cell->action_idle_handler)
- return FALSE;
- cell->action_func = info->do_action_func;
- cell->action_idle_handler = g_idle_add (idle_do_action, cell);
-
- return TRUE;
-}
-
-static void
-gal_a11y_e_cell_atk_action_interface_init (AtkActionIface *iface)
-{
- g_return_if_fail (iface != NULL);
-
- iface->get_n_actions = gal_a11y_e_cell_action_get_n_actions;
- iface->do_action = gal_a11y_e_cell_action_do_action;
- iface->get_name = gal_a11y_e_cell_action_get_name;
- iface->get_description = gal_a11y_e_cell_action_get_description;
- iface->set_description = gal_a11y_e_cell_action_set_description;
- iface->get_keybinding = gal_a11y_e_cell_action_get_keybinding;
-}
-
-void
-gal_a11y_e_cell_type_add_action_interface (GType type)
-{
- static const GInterfaceInfo atk_action_info =
- {
- (GInterfaceInitFunc) gal_a11y_e_cell_atk_action_interface_init,
- (GInterfaceFinalizeFunc) NULL,
- NULL
- };
-
- g_type_add_interface_static (type, ATK_TYPE_ACTION,
- &atk_action_info);
-}
-
-gboolean
-gal_a11y_e_cell_add_state (GalA11yECell *cell,
- AtkStateType state_type,
- gboolean emit_signal)
-{
- if (!atk_state_set_contains_state (cell->state_set, state_type)) {
- gboolean rc;
-
- rc = atk_state_set_add_state (cell->state_set, state_type);
- /*
- * The signal should only be generated if the value changed,
- * not when the cell is set up. So states that are set
- * initially should pass FALSE as the emit_signal argument.
- */
-
- if (emit_signal) {
- atk_object_notify_state_change (ATK_OBJECT (cell), state_type, TRUE);
- /* If state_type is ATK_STATE_VISIBLE, additional
- notification */
- if (state_type == ATK_STATE_VISIBLE)
- g_signal_emit_by_name (cell, "visible_data_changed");
- }
-
- return rc;
- }
- else
- return FALSE;
-}
-
-gboolean
-gal_a11y_e_cell_remove_state (GalA11yECell *cell,
- AtkStateType state_type,
- gboolean emit_signal)
-{
- if (atk_state_set_contains_state (cell->state_set, state_type)) {
- gboolean rc;
-
- rc = atk_state_set_remove_state (cell->state_set, state_type);
- /*
- * The signal should only be generated if the value changed,
- * not when the cell is set up. So states that are set
- * initially should pass FALSE as the emit_signal argument.
- */
-
- if (emit_signal) {
- atk_object_notify_state_change (ATK_OBJECT (cell), state_type, FALSE);
- /* If state_type is ATK_STATE_VISIBLE, additional notification */
- if (state_type == ATK_STATE_VISIBLE)
- g_signal_emit_by_name (cell, "visible_data_changed");
- }
-
- return rc;
- }
- else
- return FALSE;
-}
-
-/**
- * gal_a11y_e_cell_get_type:
- * @void:
- *
- * Registers the &GalA11yECell class if necessary, and returns the type ID
- * associated to it.
- *
- * Return value: The type ID of the &GalA11yECell class.
- **/
-GType
-gal_a11y_e_cell_get_type (void)
-{
- static GType type = 0;
-
- if (!type) {
- GTypeInfo info = {
- sizeof (GalA11yECellClass),
- (GBaseInitFunc) NULL,
- (GBaseFinalizeFunc) NULL,
- (GClassInitFunc) gal_a11y_e_cell_class_init,
- (GClassFinalizeFunc) NULL,
- NULL, /* class_data */
- sizeof (GalA11yECell),
- 0,
- (GInstanceInitFunc) gal_a11y_e_cell_init,
- NULL /* value_cell */
- };
-
- static const GInterfaceInfo atk_component_info = {
- (GInterfaceInitFunc) gal_a11y_e_cell_atk_component_iface_init,
- (GInterfaceFinalizeFunc) NULL,
- NULL
- };
-
- type = g_type_register_static (PARENT_TYPE, "GalA11yECell", &info, 0);
- g_type_add_interface_static (type, ATK_TYPE_COMPONENT, &atk_component_info);
- }
-
- return type;
-}
-
-AtkObject *
-gal_a11y_e_cell_new (ETableItem *item,
- ECellView *cell_view,
- AtkObject *parent,
- int model_col,
- int view_col,
- int row)
-{
- AtkObject *a11y;
-
- a11y = g_object_new (gal_a11y_e_cell_get_type (), NULL);
-
- gal_a11y_e_cell_construct (a11y,
- item,
- cell_view,
- parent,
- model_col,
- view_col,
- row);
- return a11y;
-}
-
-void
-gal_a11y_e_cell_construct (AtkObject *object,
- ETableItem *item,
- ECellView *cell_view,
- AtkObject *parent,
- int model_col,
- int view_col,
- int row)
-{
- GalA11yECell *a11y = GAL_A11Y_E_CELL (object);
- a11y->item = item;
- a11y->cell_view = cell_view;
- a11y->parent = parent;
- a11y->model_col = model_col;
- a11y->view_col = view_col;
- a11y->row = row;
- ATK_OBJECT (a11y) ->role = ATK_ROLE_TABLE_CELL;
-
- if (item)
- g_object_ref (G_OBJECT (item));
-
-#if 0
- if (parent)
- g_object_ref (parent);
-
- if (cell_view)
- g_object_ref (G_OBJECT (cell_view));
-
-
-#endif
-}
diff --git a/a11y/e-table/gal-a11y-e-cell.h b/a11y/e-table/gal-a11y-e-cell.h
deleted file mode 100644
index 53a6c0089d..0000000000
--- a/a11y/e-table/gal-a11y-e-cell.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * Authors:
- * Christopher James Lahey <clahey@ximian.com>
- *
- * Copyright (C) 2001 Chris Lahey
- */
-
-#ifndef __GAL_A11Y_E_CELL_H__
-#define __GAL_A11Y_E_CELL_H__
-
-#include <glib-object.h>
-#include <gal/e-table/e-table-item.h>
-#include <gal/e-table/e-cell.h>
-
-#define GAL_A11Y_TYPE_E_CELL (gal_a11y_e_cell_get_type ())
-#define GAL_A11Y_E_CELL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_CELL, GalA11yECell))
-#define GAL_A11Y_E_CELL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_CELL, GalA11yECellClass))
-#define GAL_A11Y_IS_E_CELL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_CELL))
-#define GAL_A11Y_IS_E_CELL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_CELL))
-
-typedef struct _GalA11yECell GalA11yECell;
-typedef struct _GalA11yECellClass GalA11yECellClass;
-typedef struct _GalA11yECellPrivate GalA11yECellPrivate;
-typedef struct _ActionInfo ActionInfo;
-typedef void (*ACTION_FUNC) (GalA11yECell *cell);
-
-
-/* This struct should actually be larger as this isn't what we derive from.
- * The GalA11yECellPrivate comes right after the parent class structure.
- **/
-struct _GalA11yECell {
- AtkObject object;
-
- ETableItem *item;
- ECellView *cell_view;
- AtkObject *parent;
- int model_col;
- int view_col;
- int row;
- AtkStateSet *state_set;
- GList *action_list;
- gint action_idle_handler;
- ACTION_FUNC action_func;
-};
-
-struct _GalA11yECellClass {
- AtkObjectClass parent_class;
-};
-
-struct _ActionInfo {
- gchar *name;
- gchar *description;
- gchar *keybinding;
- ACTION_FUNC do_action_func;
-};
-
-
-
-/* Standard Glib function */
-GType gal_a11y_e_cell_get_type (void);
-AtkObject *gal_a11y_e_cell_new (ETableItem *item,
- ECellView *cell_view,
- AtkObject *parent,
- int model_col,
- int view_col,
- int row);
-void gal_a11y_e_cell_construct (AtkObject *object,
- ETableItem *item,
- ECellView *cell_view,
- AtkObject *parent,
- int model_col,
- int view_col,
- int row);
-
-void gal_a11y_e_cell_type_add_action_interface (GType type);
-
-gboolean gal_a11y_e_cell_add_action (GalA11yECell *cell,
- const gchar *action_name,
- const gchar *action_description,
- const gchar *action_keybinding,
- ACTION_FUNC action_func);
-
-gboolean gal_a11y_e_cell_remove_action (GalA11yECell *cell,
- gint action_id);
-
-gboolean gal_a11y_e_cell_remove_action_by_name (GalA11yECell *cell,
- const gchar *action_name);
-
-gboolean gal_a11y_e_cell_add_state (GalA11yECell *cell,
- AtkStateType state_type,
- gboolean emit_signal);
-
-gboolean gal_a11y_e_cell_remove_state (GalA11yECell *cell,
- AtkStateType state_type,
- gboolean emit_signal);
-
-
-#endif /* ! __GAL_A11Y_E_CELL_H__ */
diff --git a/a11y/e-table/gal-a11y-e-table-click-to-add-factory.c b/a11y/e-table/gal-a11y-e-table-click-to-add-factory.c
deleted file mode 100644
index 9c46b2badc..0000000000
--- a/a11y/e-table/gal-a11y-e-table-click-to-add-factory.c
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Authors: Yuedong Du <yuedong.du@sun.com>
- *
- * Copyright (C) 2003 Ximian, Inc.
- */
-
-#include <config.h>
-#include "gal-a11y-e-table-click-to-add-factory.h"
-#include "gal-a11y-e-table-click-to-add.h"
-#include "gal-a11y-e-table.h"
-#include <gal/e-table/e-table.h>
-#include <gal/e-table/e-table-click-to-add.h>
-#include <atk/atk.h>
-
-
-#define CS_CLASS(factory) (G_TYPE_INSTANCE_GET_CLASS ((factory), C_TYPE_STREAM, GalA11yETableClickToAddFactoryClass))
-static AtkObjectFactoryClass *parent_class;
-#define PARENT_TYPE (ATK_TYPE_OBJECT_FACTORY)
-
-/* Static functions */
-
-static GType
-gal_a11y_e_table_click_to_add_factory_get_accessible_type (void)
-{
- return GAL_A11Y_TYPE_E_TABLE_CLICK_TO_ADD;
-}
-
-static AtkObject*
-gal_a11y_e_table_click_to_add_factory_create_accessible (GObject *obj)
-{
- AtkObject * atk_object;
-
- g_return_val_if_fail (E_IS_TABLE_CLICK_TO_ADD(obj), NULL);
-
- atk_object = gal_a11y_e_table_click_to_add_new (obj);
-
- return atk_object;
-}
-
-static void
-gal_a11y_e_table_click_to_add_factory_class_init (GalA11yETableClickToAddFactoryClass *klass)
-{
- AtkObjectFactoryClass *factory_class = ATK_OBJECT_FACTORY_CLASS (klass);
-
- parent_class = g_type_class_ref (PARENT_TYPE);
-
- factory_class->create_accessible = gal_a11y_e_table_click_to_add_factory_create_accessible;
- factory_class->get_accessible_type = gal_a11y_e_table_click_to_add_factory_get_accessible_type;
-}
-
-static void
-gal_a11y_e_table_click_to_add_factory_init (GalA11yETableClickToAddFactory *factory)
-{
-}
-
-/**
- * gal_a11y_e_table_factory_get_type:
- * @void:
- *
- * Registers the &GalA11yETableFactory class if necessary, and returns the type ID
- * associated to it.
- *
- * Return value: The type ID of the &GalA11yETableFactory class.
- **/
-GType
-gal_a11y_e_table_click_to_add_factory_get_type (void)
-{
- static GType type = 0;
-
- if (!type) {
- GTypeInfo info = {
- sizeof (GalA11yETableClickToAddFactoryClass),
- (GBaseInitFunc) NULL,
- (GBaseFinalizeFunc) NULL,
- (GClassInitFunc) gal_a11y_e_table_click_to_add_factory_class_init,
- (GClassFinalizeFunc) NULL,
- NULL, /* class_data */
- sizeof (GalA11yETableClickToAddFactory),
- 0,
- (GInstanceInitFunc) gal_a11y_e_table_click_to_add_factory_init,
- NULL /* value_table */
- };
-
- type = g_type_register_static (PARENT_TYPE, "GalA11yETableClickToAddFactory", &info, 0);
- }
-
- return type;
-}
diff --git a/a11y/e-table/gal-a11y-e-table-click-to-add-factory.h b/a11y/e-table/gal-a11y-e-table-click-to-add-factory.h
deleted file mode 100644
index d75453a780..0000000000
--- a/a11y/e-table/gal-a11y-e-table-click-to-add-factory.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Authors: * Yuedong Du <yuedong.du@sun.com>
- *
- * Copyright (C) 2003 Ximian, Inc.
- */
-
-#ifndef __GAL_A11Y_E_TABLE_CLICK_TO_ADD_FACTORY_H__
-#define __GAL_A11Y_E_TABLE_CLICK_TO_ADD_FACTORY_H__
-
-#include <glib-object.h>
-#include <atk/atkobjectfactory.h>
-
-#define GAL_A11Y_TYPE_E_TABLE_CLICK_TO_ADD_FACTORY (gal_a11y_e_table_item_factory_get_type ())
-#define GAL_A11Y_E_TABLE_CLICK_TO_ADD_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_TABLE_CLICK_TO_ADD_FACTORY, GalA11yETableClickToAddFactory))
-#define GAL_A11Y_E_TABLE_CLICK_TO_ADD_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_TABLE_CLICK_TO_ADD_FACTORY, GalA11yETableClickToAddFactoryClass))
-#define GAL_A11Y_IS_E_TABLE_CLICK_TO_ADD_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_TABLE_CLICK_TO_ADD_FACTORY))
-#define GAL_A11Y_IS_E_TABLE_CLICK_TO_ADD_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_TABLE_CLICK_TO_ADD_FACTORY))
-
-typedef struct _GalA11yETableClickToAddFactory GalA11yETableClickToAddFactory;
-typedef struct _GalA11yETableClickToAddFactoryClass GalA11yETableClickToAddFactoryClass;
-
-struct _GalA11yETableClickToAddFactory {
- AtkObject object;
-};
-
-struct _GalA11yETableClickToAddFactoryClass {
- AtkObjectClass parent_class;
-};
-
-
-/* Standard Glib function */
-GType gal_a11y_e_table_click_to_add_factory_get_type (void);
-
-#endif
diff --git a/a11y/e-table/gal-a11y-e-table-click-to-add.c b/a11y/e-table/gal-a11y-e-table-click-to-add.c
deleted file mode 100644
index da4933e647..0000000000
--- a/a11y/e-table/gal-a11y-e-table-click-to-add.c
+++ /dev/null
@@ -1,327 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * Yuedong Du <yuedong.du@sun.com>
- *
- * Copyright (C) 2002 Ximian, Inc.
- */
-
-#include <config.h>
-#include "gal-a11y-util.h"
-#include "gal-a11y-e-table-click-to-add.h"
-#include "gal-a11y-e-table-click-to-add-factory.h"
-#include <gal/e-table/e-table-group.h>
-#include <gal/e-table/e-table-group-leaf.h>
-#include <gal/e-table/e-table-click-to-add.h>
-#include <atk/atkcomponent.h>
-#include <atk/atkaction.h>
-#include <glib/gi18n.h>
-
-static AtkObjectClass *parent_class;
-static GType parent_type;
-static gint priv_offset;
-#define GET_PRIVATE(object) ((GalA11yETableClickToAddPrivate *) (((char *) object) + priv_offset))
-#define PARENT_TYPE (parent_type)
-
-struct _GalA11yETableClickToAddPrivate {
- gpointer rect;
- gpointer row;
-};
-
-
-static gint
-etcta_get_n_actions (AtkAction *action)
-{
- return 1;
-}
-
-static G_CONST_RETURN gchar*
-etcta_get_description (AtkAction *action,
- gint i)
-{
- if (i == 0)
- return _("click to add");
-
- return NULL;
-}
-
-static G_CONST_RETURN gchar*
-etcta_action_get_name (AtkAction *action, gint i)
-{
- if (i == 0)
- return _("click");
-
- return NULL;
-}
-
-
-static gboolean
-idle_do_action (gpointer data)
-{
- GdkEventButton event;
- ETableClickToAdd * etcta;
- gint finished;
-
- g_return_val_if_fail ( data!= NULL, FALSE);
-
- etcta = E_TABLE_CLICK_TO_ADD (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (data)));
- g_return_val_if_fail (etcta, FALSE);
-
- event.x = 0;
- event.y = 0;
-
- event.type = GDK_BUTTON_PRESS;
- event.window = GTK_LAYOUT(GNOME_CANVAS_ITEM(etcta)->canvas)->bin_window;
- event.button = 1;
- event.send_event = TRUE;
- event.time = GDK_CURRENT_TIME;
- event.axes = NULL;
-
- g_signal_emit_by_name (etcta, "event", &event, &finished);
-
- return FALSE;
-}
-
-static gboolean
-etcta_do_action (AtkAction * action, gint i)
-{
- g_return_val_if_fail (i == 0, FALSE);
-
- g_idle_add (idle_do_action, action);
-
- return TRUE;
-}
-
-static void
-atk_action_interface_init (AtkActionIface *iface)
-{
- g_return_if_fail (iface != NULL);
-
- iface->do_action = etcta_do_action;
- iface->get_n_actions = etcta_get_n_actions;
- iface->get_description = etcta_get_description;
- iface->get_name = etcta_action_get_name;
-}
-
-
-static G_CONST_RETURN gchar *
-etcta_get_name (AtkObject *obj)
-{
- ETableClickToAdd * etcta;
-
- g_return_val_if_fail (GAL_A11Y_IS_E_TABLE_CLICK_TO_ADD (obj), NULL);
-
- etcta = E_TABLE_CLICK_TO_ADD (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE(obj)));
- if (etcta && etcta->message != NULL)
- return etcta->message;
-
- return _("click to add");
-}
-
-static gint
-etcta_get_n_children (AtkObject *accessible)
-{
- return 1;
-}
-
-static AtkObject*
-etcta_ref_child (AtkObject *accessible,
- gint i)
-{
- AtkObject * atk_obj = NULL;
- ETableClickToAdd * etcta;
-
- if ( i != 0 )
- return NULL;
-
- etcta = E_TABLE_CLICK_TO_ADD(atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (accessible)));
-
- g_return_val_if_fail (etcta, NULL);
-
- if (etcta->rect) {
- atk_obj = atk_gobject_accessible_for_object (G_OBJECT(etcta->rect));
- } else if (etcta->row) {
- atk_obj = atk_gobject_accessible_for_object (G_OBJECT(etcta->row));
- }
-
- g_object_ref (atk_obj);
-
- return atk_obj;
-}
-
-static AtkStateSet *
-etcta_ref_state_set (AtkObject *accessible)
-{
- AtkStateSet * state_set = NULL;
-
- state_set = ATK_OBJECT_CLASS (parent_class)->ref_state_set (accessible);
- if (state_set != NULL) {
- atk_state_set_add_state (state_set, ATK_STATE_SENSITIVE);
- atk_state_set_add_state (state_set, ATK_STATE_SHOWING);
- }
-
- return state_set;
-}
-
-static void
-etcta_class_init (GalA11yETableClickToAddClass *klass)
-{
- AtkObjectClass *atk_object_class = ATK_OBJECT_CLASS (klass);
-
- parent_class = g_type_class_ref (PARENT_TYPE);
-
- atk_object_class->get_name = etcta_get_name;
- atk_object_class->get_n_children = etcta_get_n_children;
- atk_object_class->ref_child = etcta_ref_child;
- atk_object_class->ref_state_set = etcta_ref_state_set;
-}
-
-static void
-etcta_init (GalA11yETableClickToAdd *a11y)
-{
-}
-
-/**
- * gal_a11y_e_table_click_to_add_get_type:
- * @void:
- *
- * Registers the &GalA11yETableClickToAdd class if necessary, and returns the type ID
- * associated to it.
- *
- * Return value: The type ID of the &GalA11yETableClickToAdd class.
- **/
-GType
-gal_a11y_e_table_click_to_add_get_type (void)
-{
- static GType type = 0;
-
- if (!type) {
- AtkObjectFactory *factory;
-
- GTypeInfo info = {
- sizeof (GalA11yETableClickToAddClass),
- (GBaseInitFunc) NULL,
- (GBaseFinalizeFunc) NULL,
- (GClassInitFunc) etcta_class_init,
- (GClassFinalizeFunc) NULL,
- NULL, /* class_data */
- sizeof (GalA11yETableClickToAdd),
- 0,
- (GInstanceInitFunc) etcta_init,
- NULL /* value_table */
- };
-
- static const GInterfaceInfo atk_action_info = {
- (GInterfaceInitFunc) atk_action_interface_init,
- (GInterfaceFinalizeFunc) NULL,
- NULL
- };
-
- factory = atk_registry_get_factory (atk_get_default_registry (), GNOME_TYPE_CANVAS_ITEM);
-
- parent_type = atk_object_factory_get_accessible_type (factory);
- type = gal_a11y_type_register_static_with_private (PARENT_TYPE,
- "GalA11yETableClickToAdd", &info, 0,
- sizeof(GalA11yETableClickToAddPrivate), &priv_offset);
-
- g_type_add_interface_static (type, ATK_TYPE_ACTION, &atk_action_info);
-
- }
-
- return type;
-}
-
-static gboolean
-etcta_event (GnomeCanvasItem *item, GdkEvent *e, gpointer data)
-{
- ETableClickToAdd *etcta = E_TABLE_CLICK_TO_ADD (item);
- GalA11yETableClickToAdd *a11y;
- GalA11yETableClickToAddPrivate *priv;
-
- g_return_val_if_fail (item, TRUE);
-
- g_return_val_if_fail (GAL_A11Y_IS_E_TABLE_CLICK_TO_ADD(data), FALSE);
- a11y = GAL_A11Y_E_TABLE_CLICK_TO_ADD (data);
-
- priv = GET_PRIVATE (a11y);
-
- /* rect replaced by row. */
- if (etcta->rect == NULL && priv->rect != NULL) {
- g_signal_emit_by_name (a11y, "children_changed::remove", 0, NULL, NULL);
-
- }
- /* row inserted, and/or replaced by a new row. */
- if (etcta->row != NULL && priv->row == NULL) {
- g_signal_emit_by_name (a11y, "children_changed::add", 0, NULL, NULL);
- } else if (etcta->row != NULL && priv->row != NULL && etcta->row != priv->row) {
- g_signal_emit_by_name (a11y, "children_changed::remove", 0, NULL, NULL);
- g_signal_emit_by_name (a11y, "children_changed::add", 0, NULL, NULL);
- }
-
-
- priv->rect = etcta->rect;
- priv->row = etcta->row;
-
- return TRUE;
-}
-
-static void
-etcta_selection_cursor_changed (ESelectionModel *esm, gint row, gint col,
- GalA11yETableClickToAdd *a11y)
-{
- ETableClickToAdd *etcta;
- AtkObject *row_a11y;
-
- etcta = E_TABLE_CLICK_TO_ADD (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE(a11y)));
-
- if (etcta == NULL || etcta->row == NULL)
- return;
-
- row_a11y = atk_gobject_accessible_for_object (G_OBJECT(etcta->row));
- if (row_a11y) {
- AtkObject *cell_a11y = g_object_get_data (G_OBJECT(row_a11y), "gail-focus-object");
- if (cell_a11y) {
- atk_focus_tracker_notify (cell_a11y);
- }
- }
-}
-
-AtkObject *
-gal_a11y_e_table_click_to_add_new (GObject *widget)
-{
- GalA11yETableClickToAdd *a11y;
- ETableClickToAdd * etcta;
- GalA11yETableClickToAddPrivate *priv;
-
- g_return_val_if_fail (widget != NULL, NULL);
-
- a11y = g_object_new (gal_a11y_e_table_click_to_add_get_type (), NULL);
- priv = GET_PRIVATE (a11y);
-
- etcta = E_TABLE_CLICK_TO_ADD(widget);
-
-
- atk_object_initialize (ATK_OBJECT (a11y), etcta);
-
- priv->rect = etcta->rect;
- priv->row = etcta->row;
-
-
- g_signal_connect_after (G_OBJECT(widget), "event",
- G_CALLBACK (etcta_event), a11y);
-
- g_signal_connect (etcta->selection, "cursor_changed",
- G_CALLBACK (etcta_selection_cursor_changed), a11y);
-
- return ATK_OBJECT (a11y);
-}
-
-void
-gal_a11y_e_table_click_to_add_init (void)
-{
- if (atk_get_root ())
- atk_registry_set_factory_type (atk_get_default_registry (),
- E_TABLE_CLICK_TO_ADD_TYPE,
- gal_a11y_e_table_click_to_add_factory_get_type ());
-
-}
-
diff --git a/a11y/e-table/gal-a11y-e-table-click-to-add.h b/a11y/e-table/gal-a11y-e-table-click-to-add.h
deleted file mode 100644
index ea31ff6ef6..0000000000
--- a/a11y/e-table/gal-a11y-e-table-click-to-add.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-
-#ifndef __GAL_A11Y_E_TABLE_CLICK_TO_ADD_H__
-#define __GAL_A11Y_E_TABLE_CLICK_TO_ADD_H__
-
-#include <glib-object.h>
-#include <gal/e-table/e-table-item.h>
-#include <atk/atkgobjectaccessible.h>
-
-#define GAL_A11Y_TYPE_E_TABLE_CLICK_TO_ADD (gal_a11y_e_table_click_to_add_get_type ())
-#define GAL_A11Y_E_TABLE_CLICK_TO_ADD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_TABLE_CLICK_TO_ADD, GalA11yETableClickToAdd))
-#define GAL_A11Y_E_TABLE_CLICK_TO_ADD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_TABLE_CLICK_TO_ADD, GalA11yETableClickToAddClass))
-#define GAL_A11Y_IS_E_TABLE_CLICK_TO_ADD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_TABLE_CLICK_TO_ADD))
-#define GAL_A11Y_IS_E_TABLE_CLICK_TO_ADD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_TABLE_CLICK_TO_ADD))
-
-typedef struct _GalA11yETableClickToAdd GalA11yETableClickToAdd;
-typedef struct _GalA11yETableClickToAddClass GalA11yETableClickToAddClass;
-typedef struct _GalA11yETableClickToAddPrivate GalA11yETableClickToAddPrivate;
-
-/* This struct should actually be larger as this isn't what we derive from.
- * The GalA11yETableClickToAddPrivate comes right after the parent class structure.
- **/
-struct _GalA11yETableClickToAdd {
- AtkGObjectAccessible parent;
-};
-
-struct _GalA11yETableClickToAddClass {
- AtkGObjectAccessibleClass parent_class;
-};
-
-/* Standard Glib function */
-GType gal_a11y_e_table_click_to_add_get_type (void);
-AtkObject *gal_a11y_e_table_click_to_add_new (GObject *widget);
-
-void gal_a11y_e_table_click_to_add_init (void);
-#endif /* ! __GAL_A11Y_E_TABLE_CLICK_TO_ADD_H__ */
diff --git a/a11y/e-table/gal-a11y-e-table-factory.c b/a11y/e-table/gal-a11y-e-table-factory.c
deleted file mode 100644
index 14eaca3d19..0000000000
--- a/a11y/e-table/gal-a11y-e-table-factory.c
+++ /dev/null
@@ -1,83 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * Authors:
- * Christopher James Lahey <clahey@ximian.com>
- *
- * Copyright (C) 2002 Ximian, Inc.
- */
-
-#include <config.h>
-#include "gal-a11y-e-table-factory.h"
-#include "gal-a11y-e-table.h"
-
-#define CS_CLASS(factory) (G_TYPE_INSTANCE_GET_CLASS ((factory), C_TYPE_STREAM, GalA11yETableFactoryClass))
-static AtkObjectFactoryClass *parent_class;
-#define PARENT_TYPE (ATK_TYPE_OBJECT_FACTORY)
-
-/* Static functions */
-
-static GType
-gal_a11y_e_table_factory_get_accessible_type (void)
-{
- return GAL_A11Y_TYPE_E_TABLE;
-}
-
-static AtkObject*
-gal_a11y_e_table_factory_create_accessible (GObject *obj)
-{
- AtkObject *accessible;
-
- accessible = gal_a11y_e_table_new (obj);
-
- return accessible;
-}
-
-static void
-gal_a11y_e_table_factory_class_init (GalA11yETableFactoryClass *klass)
-{
- AtkObjectFactoryClass *factory_class = ATK_OBJECT_FACTORY_CLASS (klass);
-
- parent_class = g_type_class_ref (PARENT_TYPE);
-
- factory_class->create_accessible = gal_a11y_e_table_factory_create_accessible;
- factory_class->get_accessible_type = gal_a11y_e_table_factory_get_accessible_type;
-}
-
-static void
-gal_a11y_e_table_factory_init (GalA11yETableFactory *factory)
-{
-}
-
-/**
- * gal_a11y_e_table_factory_get_type:
- * @void:
- *
- * Registers the &GalA11yETableFactory class if necessary, and returns the type ID
- * associated to it.
- *
- * Return value: The type ID of the &GalA11yETableFactory class.
- **/
-GType
-gal_a11y_e_table_factory_get_type (void)
-{
- static GType type = 0;
-
- if (!type) {
- GTypeInfo info = {
- sizeof (GalA11yETableFactoryClass),
- (GBaseInitFunc) NULL,
- (GBaseFinalizeFunc) NULL,
- (GClassInitFunc) gal_a11y_e_table_factory_class_init,
- (GClassFinalizeFunc) NULL,
- NULL, /* class_data */
- sizeof (GalA11yETableFactory),
- 0,
- (GInstanceInitFunc) gal_a11y_e_table_factory_init,
- NULL /* value_table */
- };
-
- type = g_type_register_static (PARENT_TYPE, "GalA11yETableFactory", &info, 0);
- }
-
- return type;
-}
diff --git a/a11y/e-table/gal-a11y-e-table-factory.h b/a11y/e-table/gal-a11y-e-table-factory.h
deleted file mode 100644
index eb8eb55414..0000000000
--- a/a11y/e-table/gal-a11y-e-table-factory.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * Authors:
- * Christopher James Lahey <clahey@ximian.com>
- *
- * Copyright (C) 2001 Chris Lahey
- */
-
-#ifndef __GAL_A11Y_E_TABLE_FACTORY_H__
-#define __GAL_A11Y_E_TABLE_FACTORY_H__
-
-#include <glib-object.h>
-#include <atk/atkobjectfactory.h>
-
-#define GAL_A11Y_TYPE_E_TABLE_FACTORY (gal_a11y_e_table_factory_get_type ())
-#define GAL_A11Y_E_TABLE_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_TABLE_FACTORY, GalA11yETableFactory))
-#define GAL_A11Y_E_TABLE_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_TABLE_FACTORY, GalA11yETableFactoryClass))
-#define GAL_A11Y_IS_E_TABLE_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_TABLE_FACTORY))
-#define GAL_A11Y_IS_E_TABLE_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_TABLE_FACTORY))
-
-typedef struct _GalA11yETableFactory GalA11yETableFactory;
-typedef struct _GalA11yETableFactoryClass GalA11yETableFactoryClass;
-
-struct _GalA11yETableFactory {
- AtkObject object;
-};
-
-struct _GalA11yETableFactoryClass {
- AtkObjectClass parent_class;
-};
-
-
-/* Standard Glib function */
-GType gal_a11y_e_table_factory_get_type (void);
-
-#endif /* ! __GAL_A11Y_E_TABLE_FACTORY_H__ */
diff --git a/a11y/e-table/gal-a11y-e-table-item-factory.c b/a11y/e-table/gal-a11y-e-table-item-factory.c
deleted file mode 100644
index 3c8e60a4bb..0000000000
--- a/a11y/e-table/gal-a11y-e-table-item-factory.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Authors: Yuedong Du <yuedong.du@sun.com>
- *
- * Copyright (C) 2003 Ximian, Inc.
- */
-
-#include <config.h>
-#include "gal-a11y-e-table-item-factory.h"
-#include "gal-a11y-e-table-item.h"
-#include "gal-a11y-e-table.h"
-#include <gal/e-table/e-table.h>
-#include <gal/e-table/e-tree.h>
-#include <atk/atk.h>
-
-
-#define CS_CLASS(factory) (G_TYPE_INSTANCE_GET_CLASS ((factory), C_TYPE_STREAM, GalA11yETableItemFactoryClass))
-static AtkObjectFactoryClass *parent_class;
-#define PARENT_TYPE (ATK_TYPE_OBJECT_FACTORY)
-
-/* Static functions */
-
-static GType
-gal_a11y_e_table_item_factory_get_accessible_type (void)
-{
- return GAL_A11Y_TYPE_E_TABLE_ITEM;
-}
-
-static AtkObject*
-gal_a11y_e_table_item_factory_create_accessible (GObject *obj)
-{
- AtkObject *accessible;
-
- g_return_val_if_fail (E_IS_TABLE_ITEM(obj), NULL);
- accessible = gal_a11y_e_table_item_new (E_TABLE_ITEM (obj));
-
- return accessible;
-}
-
-static void
-gal_a11y_e_table_item_factory_class_init (GalA11yETableItemFactoryClass *klass)
-{
- AtkObjectFactoryClass *factory_class = ATK_OBJECT_FACTORY_CLASS (klass);
-
- parent_class = g_type_class_ref (PARENT_TYPE);
-
- factory_class->create_accessible = gal_a11y_e_table_item_factory_create_accessible;
- factory_class->get_accessible_type = gal_a11y_e_table_item_factory_get_accessible_type;
-}
-
-static void
-gal_a11y_e_table_item_factory_init (GalA11yETableItemFactory *factory)
-{
-}
-
-/**
- * gal_a11y_e_table_factory_get_type:
- * @void:
- *
- * Registers the &GalA11yETableFactory class if necessary, and returns the type ID
- * associated to it.
- *
- * Return value: The type ID of the &GalA11yETableFactory class.
- **/
-GType
-gal_a11y_e_table_item_factory_get_type (void)
-{
- static GType type = 0;
-
- if (!type) {
- GTypeInfo info = {
- sizeof (GalA11yETableItemFactoryClass),
- (GBaseInitFunc) NULL,
- (GBaseFinalizeFunc) NULL,
- (GClassInitFunc) gal_a11y_e_table_item_factory_class_init,
- (GClassFinalizeFunc) NULL,
- NULL, /* class_data */
- sizeof (GalA11yETableItemFactory),
- 0,
- (GInstanceInitFunc) gal_a11y_e_table_item_factory_init,
- NULL /* value_table */
- };
-
- type = g_type_register_static (PARENT_TYPE, "GalA11yETableItemFactory", &info, 0);
- }
-
- return type;
-}
diff --git a/a11y/e-table/gal-a11y-e-table-item-factory.h b/a11y/e-table/gal-a11y-e-table-item-factory.h
deleted file mode 100644
index cbbff9fb18..0000000000
--- a/a11y/e-table/gal-a11y-e-table-item-factory.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Authors: * Yuedong Du <yuedong.du@sun.com>
- *
- * Copyright (C) 2003 Ximian, Inc.
- */
-
-#ifndef __GAL_A11Y_E_TABLE_ITEM_FACTORY_H__
-#define __GAL_A11Y_E_TABLE_ITEM_FACTORY_H__
-
-#include <glib-object.h>
-#include <atk/atkobjectfactory.h>
-
-#define GAL_A11Y_TYPE_E_TABLE_ITEM_FACTORY (gal_a11y_e_table_item_factory_get_type ())
-#define GAL_A11Y_E_TABLE_ITEM_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_TABLE_ITEM_FACTORY, GalA11yETableItemFactory))
-#define GAL_A11Y_E_TABLE_ITEM_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_TABLE_ITEM_FACTORY, GalA11yETableItemFactoryClass))
-#define GAL_A11Y_IS_E_TABLE_ITEM_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_TABLE_ITEM_FACTORY))
-#define GAL_A11Y_IS_E_TABLE_ITEM_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_TABLE_ITEM_FACTORY))
-
-typedef struct _GalA11yETableItemFactory GalA11yETableItemFactory;
-typedef struct _GalA11yETableItemFactoryClass GalA11yETableItemFactoryClass;
-
-struct _GalA11yETableItemFactory {
- AtkObject object;
-};
-
-struct _GalA11yETableItemFactoryClass {
- AtkObjectClass parent_class;
-};
-
-
-/* Standard Glib function */
-GType gal_a11y_e_table_item_factory_get_type (void);
-
-#endif /* ! __GAL_A11Y_E_TABLE_FACTORY_H__ */
diff --git a/a11y/e-table/gal-a11y-e-table-item.c b/a11y/e-table/gal-a11y-e-table-item.c
deleted file mode 100644
index 2b45bfeef7..0000000000
--- a/a11y/e-table/gal-a11y-e-table-item.c
+++ /dev/null
@@ -1,1310 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * Authors:
- * Christopher James Lahey <clahey@ximian.com>
- * Bolian Yin <bolian.yin@sun.com>
- *
- * Copyright (C) 2002 Ximian, Inc.
- */
-
-#include <config.h>
-#include <string.h>
-#include "gal-a11y-e-table-item.h"
-#include "gal-a11y-e-table-item-factory.h"
-#include "gal-a11y-e-table-click-to-add.h"
-#include "gal-a11y-e-cell-registry.h"
-#include "gal-a11y-e-cell.h"
-#include "gal-a11y-util.h"
-#include <gal/e-table/e-table-subset.h>
-#include <gal/widgets/e-selection-model.h>
-#include <gal/widgets/e-canvas.h>
-#include <gal/e-table/e-table.h>
-#include <gal/e-table/e-table-click-to-add.h>
-#include <gal/e-table/e-tree.h>
-
-#include <atk/atkobject.h>
-#include <atk/atktable.h>
-#include <atk/atkcomponent.h>
-#include <atk/atkobjectfactory.h>
-#include <atk/atkregistry.h>
-#include <atk/atkgobjectaccessible.h>
-
-#define CS_CLASS(a11y) (G_TYPE_INSTANCE_GET_CLASS ((a11y), C_TYPE_STREAM, GalA11yETableItemClass))
-static GObjectClass *parent_class;
-static AtkComponentIface *component_parent_iface;
-static GType parent_type;
-static gint priv_offset;
-static GQuark quark_accessible_object = 0;
-#define GET_PRIVATE(object) ((GalA11yETableItemPrivate *) (((char *) object) + priv_offset))
-#define PARENT_TYPE (parent_type)
-
-struct _GalA11yETableItemPrivate {
- gint cols;
- gint rows;
- int selection_change_id;
- int cursor_change_id;
- ETableCol ** columns;
- ESelectionModel *selection;
- AtkStateSet *state_set;
- GtkWidget *widget;
-};
-
-static gboolean gal_a11y_e_table_item_ref_selection (GalA11yETableItem *a11y,
- ESelectionModel *selection);
-static gboolean gal_a11y_e_table_item_unref_selection (GalA11yETableItem *a11y);
-
-static AtkObject* eti_ref_at (AtkTable *table, gint row, gint column);
-
-static void
-item_destroyed (GtkObject *item, gpointer user_data)
-{
- GalA11yETableItem *a11y = GAL_A11Y_E_TABLE_ITEM (user_data);
- GalA11yETableItemPrivate *priv = GET_PRIVATE (a11y);
-
- atk_state_set_add_state (priv->state_set, ATK_STATE_DEFUNCT);
- atk_object_notify_state_change (ATK_OBJECT (a11y), ATK_STATE_DEFUNCT, TRUE);
-
- if (priv->selection)
- gal_a11y_e_table_item_unref_selection (a11y);
-
-}
-
-static AtkStateSet *
-eti_ref_state_set (AtkObject *accessible)
-{
- GalA11yETableItemPrivate *priv = GET_PRIVATE (accessible);
-
- g_object_ref(priv->state_set);
-
- return priv->state_set;
-}
-
-inline static gint
-view_to_model_row(ETableItem *eti, int row)
-{
- if (eti->uses_source_model) {
- ETableSubset *etss = E_TABLE_SUBSET(eti->table_model);
- if (row >= 0 && row < etss->n_map) {
- eti->row_guess = row;
- return etss->map_table[row];
- } else
- return -1;
- } else
- return row;
-}
-
-inline static gint
-view_to_model_col(ETableItem *eti, int col)
-{
- ETableCol *ecol = e_table_header_get_column (eti->header, col);
- return ecol ? ecol->col_idx : -1;
-}
-
-inline static gint
-model_to_view_row(ETableItem *eti, int row)
-{
- int i;
- if (row == -1)
- return -1;
- if (eti->uses_source_model) {
- ETableSubset *etss = E_TABLE_SUBSET(eti->table_model);
- if (eti->row_guess >= 0 && eti->row_guess < etss->n_map) {
- if (etss->map_table[eti->row_guess] == row) {
- return eti->row_guess;
- }
- }
- for (i = 0; i < etss->n_map; i++) {
- if (etss->map_table[i] == row)
- return i;
- }
- return -1;
- } else
- return row;
-}
-
-inline static gint
-model_to_view_col(ETableItem *eti, int col)
-{
- int i;
- if (col == -1)
- return -1;
- for (i = 0; i < eti->cols; i++) {
- ETableCol *ecol = e_table_header_get_column (eti->header, i);
- if (ecol->col_idx == col)
- return i;
- }
- return -1;
-}
-
-inline static GObject *
-eti_a11y_get_gobject (AtkObject *accessible)
-{
- return atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (accessible));
-}
-
-static void
-eti_dispose (GObject *object)
-{
- GalA11yETableItem *a11y = GAL_A11Y_E_TABLE_ITEM (object);
- GalA11yETableItemPrivate *priv = GET_PRIVATE (a11y);
-
- if (priv->columns) {
- g_free(priv->columns);
- priv->columns = NULL;
- }
-
- if (parent_class->dispose)
- parent_class->dispose (object);
-}
-
-/* Static functions */
-static gint
-eti_get_n_children (AtkObject *accessible)
-{
- g_return_val_if_fail (GAL_A11Y_IS_E_TABLE_ITEM (accessible), 0);
- if (!eti_a11y_get_gobject (accessible))
- return 0;
-
- return atk_table_get_n_columns (ATK_TABLE (accessible)) *
- atk_table_get_n_rows (ATK_TABLE (accessible));
-}
-
-static AtkObject*
-eti_ref_child (AtkObject *accessible, gint index)
-{
- ETableItem *item;
- gint col, row;
-
- g_return_val_if_fail (GAL_A11Y_IS_E_TABLE_ITEM (accessible), NULL);
- item = E_TABLE_ITEM (eti_a11y_get_gobject (accessible));
- if (!item)
- return NULL;
-
- /* don't support column header now */
-
- col = index % item->cols;
- row = index / item->cols;
-
- return eti_ref_at (ATK_TABLE (accessible), row, col);
-}
-
-static void
-eti_get_extents (AtkComponent *component,
- gint *x,
- gint *y,
- gint *width,
- gint *height,
- AtkCoordType coord_type)
-{
- ETableItem *item;
- AtkObject *parent;
-
- item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (component)));
- if (!item)
- return;
-
- parent = ATK_OBJECT (component)->accessible_parent;
- if (parent && ATK_IS_COMPONENT (parent))
- atk_component_get_extents (ATK_COMPONENT (parent), x, y,
- width, height,
- coord_type);
-
- if (parent && GAL_A11Y_IS_E_TABLE_CLICK_TO_ADD (parent)) {
- ETableClickToAdd *etcta = E_TABLE_CLICK_TO_ADD (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (parent)));
- if (etcta) {
- *width = etcta->width;
- *height = etcta->height;
- }
- }
-}
-
-static AtkObject*
-eti_ref_accessible_at_point (AtkComponent *component,
- gint x,
- gint y,
- AtkCoordType coord_type)
-{
- int row = -1;
- int col = -1;
- int x_origin, y_origin;
- ETableItem *item;
- GtkWidget *tableOrTree;
-
- item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (component)));
- if (!item)
- return NULL;
-
- atk_component_get_position (component,
- &x_origin,
- &y_origin,
- coord_type);
- x -= x_origin;
- y -= y_origin;
-
- tableOrTree = gtk_widget_get_parent (GTK_WIDGET (item->parent.canvas));
-
- if (E_IS_TREE(tableOrTree))
- e_tree_get_cell_at (E_TREE (tableOrTree), x, y, &row, &col);
- else
- e_table_get_cell_at (E_TABLE (tableOrTree), x, y, &row, &col);
-
- if (row != -1 && col != -1) {
- return eti_ref_at (ATK_TABLE (component), row, col);
- } else {
- return NULL;
- }
-}
-
-
-static void
-cell_destroyed (gpointer data)
-{
- GalA11yECell * cell;
-
- g_return_if_fail (GAL_A11Y_IS_E_CELL (data));
- cell = GAL_A11Y_E_CELL (data);
-
- g_return_if_fail (cell->item && G_IS_OBJECT (cell->item));
-
- if (cell->item) {
- g_object_unref (cell->item);
- cell->item = NULL;
- }
-
-}
-
-/* atk table */
-static AtkObject*
-eti_ref_at (AtkTable *table, gint row, gint column)
-{
- ETableItem *item;
- AtkObject* ret;
- GalA11yETableItemPrivate *priv = GET_PRIVATE (table);
-
- if (atk_state_set_contains_state (priv->state_set, ATK_STATE_DEFUNCT))
- return NULL;
-
-
- item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table)));
- if (!item)
- return NULL;
-
- if (column >= 0 &&
- column < item->cols &&
- row >= 0 &&
- row < item->rows &&
- item->cell_views_realized) {
- ECellView *cell_view = item->cell_views[column];
- ETableCol *ecol = e_table_header_get_column (item->header, column);
- ret = gal_a11y_e_cell_registry_get_object (NULL,
- item,
- cell_view,
- ATK_OBJECT (table),
- ecol->col_idx,
- column,
- row);
- if (ATK_IS_OBJECT (ret)) {
- g_object_weak_ref (G_OBJECT (ret),
- (GWeakNotify) cell_destroyed,
- ret);
- /* if current cell is focused, add FOCUSED state */
- if (e_selection_model_cursor_row (item->selection) == GAL_A11Y_E_CELL (ret)->row &&
- e_selection_model_cursor_col (item->selection) == GAL_A11Y_E_CELL (ret)->model_col)
- gal_a11y_e_cell_add_state (GAL_A11Y_E_CELL (ret), ATK_STATE_FOCUSED, FALSE);
- } else
- ret = NULL;
-
- return ret;
- }
-
- return NULL;
-}
-
-static gint
-eti_get_index_at (AtkTable *table, gint row, gint column)
-{
- ETableItem *item;
-
- item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table)));
- if (!item)
- return -1;
-
- return column + row * item->cols;
-}
-
-static gint
-eti_get_column_at_index (AtkTable *table, gint index)
-{
- ETableItem *item;
-
- item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table)));
- if (!item)
- return -1;
-
- return index % item->cols;
-}
-
-static gint
-eti_get_row_at_index (AtkTable *table, gint index)
-{
- ETableItem *item;
-
- item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table)));
- if (!item)
- return -1;
-
- return index / item->cols;
-}
-
-static gint
-eti_get_n_columns (AtkTable *table)
-{
- ETableItem *item;
-
- item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table)));
- if (!item)
- return -1;
-
- return item->cols;
-}
-
-static gint
-eti_get_n_rows (AtkTable *table)
-{
- ETableItem *item;
-
- item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table)));
- if (!item)
- return -1;
-
- return item->rows;
-}
-
-static gint
-eti_get_column_extent_at (AtkTable *table,
- gint row,
- gint column)
-{
- ETableItem *item;
- int width;
-
- item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table)));
- if (!item)
- return -1;
-
- e_table_item_get_cell_geometry (item,
- &row,
- &column,
- NULL,
- NULL,
- &width,
- NULL);
-
- return width;
-}
-
-static gint
-eti_get_row_extent_at (AtkTable *table,
- gint row,
- gint column)
-{
- ETableItem *item;
- int height;
-
- item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table)));
- if (!item)
- return -1;
-
- e_table_item_get_cell_geometry (item,
- &row,
- &column,
- NULL,
- NULL,
- NULL,
- &height);
-
- return height;
-}
-
-static AtkObject *
-eti_get_caption (AtkTable *table)
-{
- /* Unimplemented */
- return NULL;
-}
-
-static G_CONST_RETURN gchar *
-eti_get_column_description (AtkTable *table,
- gint column)
-{
- ETableItem *item;
- ETableCol *ecol;
-
- item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table)));
- if (!item)
- return NULL;
-
- ecol = e_table_header_get_column (item->header, column);
-
- return ecol->text;
-}
-
-static AtkObject *
-eti_get_column_header (AtkTable *table, gint column)
-{
- ETableItem *item;
- ETableCol *ecol;
- AtkObject *atk_obj = NULL;
-
- item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table)));
- if (!item)
- return NULL;
-
- ecol = e_table_header_get_column (item->header, column);
- if (ecol) {
- atk_obj = atk_gobject_accessible_for_object (G_OBJECT (ecol));
- if (atk_obj) {
- if (ecol->text)
- atk_object_set_name (atk_obj, ecol->text);
- atk_object_set_role (atk_obj, ATK_ROLE_TABLE_COLUMN_HEADER);
- }
- }
-
- return atk_obj;
-}
-
-static G_CONST_RETURN gchar *
-eti_get_row_description (AtkTable *table,
- gint row)
-{
- /* Unimplemented */
- return NULL;
-}
-
-static AtkObject *
-eti_get_row_header (AtkTable *table,
- gint row)
-{
- /* Unimplemented */
- return NULL;
-}
-
-static AtkObject *
-eti_get_summary (AtkTable *table)
-{
- /* Unimplemented */
- return NULL;
-}
-
-static gboolean
-table_is_row_selected (AtkTable *table, gint row)
-{
- ETableItem *item;
- GalA11yETableItemPrivate *priv = GET_PRIVATE (table);
-
- if (atk_state_set_contains_state (priv->state_set, ATK_STATE_DEFUNCT))
- return FALSE;
-
- item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table)));
- if (!item)
- return FALSE;
-
- return e_selection_model_is_row_selected(item->selection, view_to_model_row (item, row));
-}
-
-static gboolean
-table_is_selected (AtkTable *table, gint row, gint column)
-{
- return table_is_row_selected (table, row);
-}
-
-static gint
-table_get_selected_rows (AtkTable *table, gint **rows_selected)
-{
- ETableItem *item;
- gint n_selected, row, index_selected;
- GalA11yETableItemPrivate *priv = GET_PRIVATE (table);
-
- if (atk_state_set_contains_state (priv->state_set, ATK_STATE_DEFUNCT))
- return 0;
-
- item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table)));
- if (!item)
- return 0;
-
- n_selected = e_selection_model_selected_count (item->selection);
- if (rows_selected) {
- *rows_selected = (gint *) g_malloc (n_selected * sizeof (gint));
-
- index_selected = 0;
- for (row = 0; row < item->rows && index_selected < n_selected; ++row) {
- if (atk_table_is_row_selected (table, row)) {
- (*rows_selected)[index_selected] = row;
- ++index_selected;
- }
- }
- }
- return n_selected;
-}
-
-static gboolean
-table_add_row_selection (AtkTable *table, gint row)
-{
- ETableItem *item;
-
- item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table)));
- if (!item)
- return FALSE;
-
- if (table_is_row_selected (table, row))
- return TRUE;
- e_selection_model_toggle_single_row (item->selection,
- view_to_model_row (item, row));
-
- return TRUE;
-}
-
-static gboolean
-table_remove_row_selection (AtkTable *table, gint row)
-{
- ETableItem *item;
- GalA11yETableItemPrivate *priv = GET_PRIVATE (table);
-
- if (atk_state_set_contains_state (priv->state_set, ATK_STATE_DEFUNCT))
- return FALSE;
-
- item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table)));
- if (!item)
- return FALSE;
-
- if (!atk_table_is_row_selected (table, row))
- return TRUE;
- e_selection_model_toggle_single_row (item->selection, view_to_model_row (item, row));
- return TRUE;
-}
-
-static void
-eti_atk_table_iface_init (AtkTableIface *iface)
-{
- iface->ref_at = eti_ref_at;
- iface->get_index_at = eti_get_index_at;
- iface->get_column_at_index = eti_get_column_at_index;
- iface->get_row_at_index = eti_get_row_at_index;
- iface->get_n_columns = eti_get_n_columns;
- iface->get_n_rows = eti_get_n_rows;
- iface->get_column_extent_at = eti_get_column_extent_at;
- iface->get_row_extent_at = eti_get_row_extent_at;
- iface->get_caption = eti_get_caption;
- iface->get_column_description = eti_get_column_description;
- iface->get_column_header = eti_get_column_header;
- iface->get_row_description = eti_get_row_description;
- iface->get_row_header = eti_get_row_header;
- iface->get_summary = eti_get_summary;
-
- iface->is_row_selected = table_is_row_selected;
- iface->is_selected = table_is_selected;
- iface->get_selected_rows = table_get_selected_rows;
- iface->add_row_selection = table_add_row_selection;
- iface->remove_row_selection = table_remove_row_selection;
-}
-
-static void
-eti_atk_component_iface_init (AtkComponentIface *iface)
-{
- component_parent_iface = g_type_interface_peek_parent (iface);
-
- iface->ref_accessible_at_point = eti_ref_accessible_at_point;
- iface->get_extents = eti_get_extents;
-}
-
-static void
-eti_rows_inserted (ETableModel * model, int row, int count,
- AtkObject * table_item)
-{
- gint n_cols,n_rows,i,j;
- GalA11yETableItem * item_a11y;
- gint old_nrows;
-
- g_return_if_fail (table_item);
- item_a11y = GAL_A11Y_E_TABLE_ITEM (table_item);
-
- n_cols = atk_table_get_n_columns (ATK_TABLE(table_item));
- n_rows = atk_table_get_n_rows (ATK_TABLE(table_item));
-
- old_nrows = GET_PRIVATE(item_a11y)->rows;
-
- g_return_if_fail (n_cols > 0 && n_rows > 0);
- g_return_if_fail (old_nrows == n_rows - count);
-
- GET_PRIVATE(table_item)->rows = n_rows;
-
- g_signal_emit_by_name (table_item, "row-inserted", row,
- count, NULL);
-
- for (i = row; i < (row + count); i ++) {
- for (j = 0; j < n_cols; j ++) {
- g_signal_emit_by_name (table_item,
- "children_changed::add",
- ( (i*n_cols) + j), NULL, NULL);
- }
- }
-
- g_signal_emit_by_name (table_item, "visible-data-changed");
-}
-
-static void
-eti_rows_deleted (ETableModel * model, int row, int count,
- AtkObject * table_item)
-{
- gint i,j, n_rows, n_cols, old_nrows;
-
- n_rows = atk_table_get_n_rows (ATK_TABLE(table_item));
- n_cols = atk_table_get_n_columns (ATK_TABLE(table_item));
-
- old_nrows = GET_PRIVATE(table_item)->rows;
-
- g_return_if_fail ( row+count <= old_nrows);
- g_return_if_fail (old_nrows == n_rows + count);
- GET_PRIVATE(table_item)->rows = n_rows;
-
- g_signal_emit_by_name (table_item, "row-deleted", row,
- count, NULL);
-
- for (i = row; i < (row + count); i ++) {
- for (j = 0; j < n_cols; j ++) {
- g_signal_emit_by_name (table_item,
- "children_changed::remove",
- ( (i*n_cols) + j), NULL, NULL);
- }
- }
- g_signal_emit_by_name (table_item, "visible-data-changed");
-}
-
-static void
-eti_tree_model_node_changed_cb (ETreeModel *model, ETreePath node, ETableItem *eti)
-{
- AtkObject *atk_obj;
- GalA11yETableItem *a11y;
-
- g_return_if_fail (E_IS_TABLE_ITEM (eti));
-
- atk_obj = atk_gobject_accessible_for_object (G_OBJECT (eti));
- a11y = GAL_A11Y_E_TABLE_ITEM (atk_obj);
-
- /* we can't figure out which rows are changed, so just send out a signal ... */
- if (GET_PRIVATE (a11y)->rows > 0)
- g_signal_emit_by_name (a11y, "visible-data-changed");
-}
-
-enum {
- ETI_HEADER_UNCHANGED = 0,
- ETI_HEADER_REORDERED,
- ETI_HEADER_NEW_ADDED,
- ETI_HEADER_REMOVED,
-};
-
-/*
- * 1. Check what actually happened: column reorder, remove or add
- * 2. Update cache
- * 3. Emit signals
- */
-static void
-eti_header_structure_changed (ETableHeader *eth, AtkObject *a11y)
-{
-
- gboolean reorder_found=FALSE, added_found=FALSE, removed_found=FALSE;
- GalA11yETableItem * a11y_item;
- ETableCol ** cols, **prev_cols;
- GalA11yETableItemPrivate *priv;
- gint *state = NULL, *prev_state = NULL, *reorder = NULL;
- gint i,j,n_rows,n_cols, prev_n_cols;
-
- a11y_item = GAL_A11Y_E_TABLE_ITEM (a11y);
- priv = GET_PRIVATE (a11y_item);
-
- /* Assume rows do not changed. */
- n_rows = priv->rows;
-
- prev_n_cols = priv->cols;
- prev_cols = priv->columns;
-
- cols = e_table_header_get_columns (eth);
- n_cols = eth->col_count;
-
- g_return_if_fail (cols && prev_cols && n_cols > 0);
-
- /* Init to ETI_HEADER_UNCHANGED. */
- state = g_malloc0 (sizeof (gint) * n_cols);
- prev_state = g_malloc0 (sizeof (gint) * prev_n_cols);
- reorder = g_malloc0 (sizeof (gint) * n_cols);
-
- /* Compare with previously saved column headers. */
- for ( i = 0 ; i < n_cols && cols[i]; i ++ ) {
- for ( j = 0 ; j < prev_n_cols && prev_cols[j]; j ++ ) {
- if ( prev_cols [j] == cols[i] && i != j ) {
-
- reorder_found = TRUE;
- state [i] = ETI_HEADER_REORDERED;
- reorder [i] = j;
-
- break;
- } else if (prev_cols[j] == cols[i]) {
- /* OK, this column is not changed. */
- break;
- }
- }
-
- /* cols[i] is new added column. */
- if ( j == prev_n_cols ) {
- added_found = TRUE;
- state[i] = ETI_HEADER_NEW_ADDED;
- }
- }
-
- /* Now try to find if there are removed columns. */
- for (i = 0 ; i < prev_n_cols && prev_cols[i]; i ++) {
- for (j = 0 ; j < n_cols && cols[j]; j ++)
- if ( prev_cols [j] == cols[i] )
- break;
-
- /* Removed columns found. */
- if ( j == n_cols ) {
- removed_found = TRUE;
- prev_state[j] = ETI_HEADER_REMOVED;
- }
- }
-
- /* If nothing interesting just return. */
- if (!reorder_found && !added_found && !removed_found)
- return;
-
- /* Emit signals */
- if (reorder_found)
- g_signal_emit_by_name (G_OBJECT(a11y_item), "column_reordered");
-
-
- if (removed_found) {
- for (i = 0; i < prev_n_cols; i ++ ) {
- if (prev_state[i] == ETI_HEADER_REMOVED) {
- g_signal_emit_by_name (G_OBJECT(a11y_item), "column-deleted", i, 1);
- for (j = 0 ; j < n_rows; j ++)
- g_signal_emit_by_name (G_OBJECT(a11y_item), "children_changed::remove", (j*prev_n_cols+i), NULL, NULL);
- }
- }
- }
-
- if (added_found) {
- for ( i = 0; i < n_cols; i ++ ) {
- if (state[i] == ETI_HEADER_NEW_ADDED) {
- g_signal_emit_by_name (G_OBJECT(a11y_item), "column-inserted", i, 1);
- for (j = 0 ; j < n_rows; j ++)
- g_signal_emit_by_name (G_OBJECT(a11y_item), "children_changed::add", (j*n_cols+i), NULL, NULL);
- }
- }
- }
-
- priv->cols = n_cols;
-
- g_free (state);
- g_free (reorder);
- g_free (prev_state);
-
- g_free (priv->columns);
- priv->columns = cols;
-}
-
-
-static void
-eti_real_initialize (AtkObject *obj,
- gpointer data)
-{
- ETableItem * eti;
- ETableModel * model;
-
- ATK_OBJECT_CLASS (parent_class)->initialize (obj, data);
- eti = E_TABLE_ITEM (data);
-
- model = eti->table_model;
-
- g_signal_connect (model, "model-rows-inserted",
- G_CALLBACK (eti_rows_inserted),
- obj);
- g_signal_connect (model, "model-rows-deleted",
- G_CALLBACK (eti_rows_deleted),
- obj);
- g_signal_connect (G_OBJECT (eti->header), "structure_change",
- G_CALLBACK (eti_header_structure_changed), obj);
-
-}
-
-static void
-eti_class_init (GalA11yETableItemClass *klass)
-{
- AtkObjectClass *atk_object_class = ATK_OBJECT_CLASS (klass);
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- quark_accessible_object = g_quark_from_static_string ("gtk-accessible-object");
-
- parent_class = g_type_class_ref (PARENT_TYPE);
-
- object_class->dispose = eti_dispose;
-
- atk_object_class->get_n_children = eti_get_n_children;
- atk_object_class->ref_child = eti_ref_child;
- atk_object_class->initialize = eti_real_initialize;
- atk_object_class->ref_state_set = eti_ref_state_set;
-}
-
-static void
-eti_init (GalA11yETableItem *a11y)
-{
- GalA11yETableItemPrivate *priv;
-
- priv = GET_PRIVATE (a11y);
-
- priv->selection_change_id = 0;
- priv->cursor_change_id = 0;
- priv->selection = NULL;
-}
-
-/* atk selection */
-
-static void atk_selection_interface_init (AtkSelectionIface *iface);
-static gboolean selection_add_selection (AtkSelection *selection,
- gint i);
-static gboolean selection_clear_selection (AtkSelection *selection);
-static AtkObject* selection_ref_selection (AtkSelection *selection,
- gint i);
-static gint selection_get_selection_count (AtkSelection *selection);
-static gboolean selection_is_child_selected (AtkSelection *selection,
- gint i);
-
-/* callbacks */
-static void eti_a11y_selection_model_removed_cb (ETableItem *eti,
- ESelectionModel *selection,
- gpointer data);
-static void eti_a11y_selection_model_added_cb (ETableItem *eti,
- ESelectionModel *selection,
- gpointer data);
-static void eti_a11y_selection_changed_cb (ESelectionModel *selection,
- GalA11yETableItem *a11y);
-static void eti_a11y_cursor_changed_cb (ESelectionModel *selection,
- int row, int col,
- GalA11yETableItem *a11y);
-
-/**
- * gal_a11y_e_table_item_get_type:
- * @void:
- *
- * Registers the &GalA11yETableItem class if necessary, and returns the type ID
- * associated to it.
- *
- * Return value: The type ID of the &GalA11yETableItem class.
- **/
-GType
-gal_a11y_e_table_item_get_type (void)
-{
- static GType type = 0;
-
- if (!type) {
- AtkObjectFactory *factory;
-
- GTypeInfo info = {
- sizeof (GalA11yETableItemClass),
- (GBaseInitFunc) NULL,
- (GBaseFinalizeFunc) NULL,
- (GClassInitFunc) eti_class_init,
- (GClassFinalizeFunc) NULL,
- NULL, /* class_data */
- sizeof (GalA11yETableItem),
- 0,
- (GInstanceInitFunc) eti_init,
- NULL /* value_table_item */
- };
-
- static const GInterfaceInfo atk_component_info = {
- (GInterfaceInitFunc) eti_atk_component_iface_init,
- (GInterfaceFinalizeFunc) NULL,
- NULL
- };
- static const GInterfaceInfo atk_table_info = {
- (GInterfaceInitFunc) eti_atk_table_iface_init,
- (GInterfaceFinalizeFunc) NULL,
- NULL
- };
-
- static const GInterfaceInfo atk_selection_info = {
- (GInterfaceInitFunc) atk_selection_interface_init,
- (GInterfaceFinalizeFunc) NULL,
- NULL
- };
-
-
- factory = atk_registry_get_factory (atk_get_default_registry (), GNOME_TYPE_CANVAS_ITEM);
- parent_type = atk_object_factory_get_accessible_type (factory);
-
- type = gal_a11y_type_register_static_with_private (PARENT_TYPE, "GalA11yETableItem", &info, 0,
- sizeof (GalA11yETableItemPrivate), &priv_offset);
-
- g_type_add_interface_static (type, ATK_TYPE_COMPONENT, &atk_component_info);
- 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;
-}
-
-AtkObject *
-gal_a11y_e_table_item_new (ETableItem *item)
-{
- GalA11yETableItem *a11y;
- AtkObject *accessible;
- int n;
- ESelectionModel * esm;
- AtkObject * cell;
- AtkObject *parent;
- const char *name;
-
- g_return_val_if_fail (item && item->cols >= 0 && item->rows >= 0, NULL);
- a11y = g_object_new (gal_a11y_e_table_item_get_type (), NULL);
-
- atk_object_initialize (ATK_OBJECT (a11y), item);
-
- GET_PRIVATE (a11y)->state_set = atk_state_set_new ();
-
- atk_state_set_add_state (GET_PRIVATE(a11y)->state_set, ATK_STATE_TRANSIENT);
- atk_state_set_add_state (GET_PRIVATE(a11y)->state_set, ATK_STATE_ENABLED);
- atk_state_set_add_state (GET_PRIVATE(a11y)->state_set, ATK_STATE_SENSITIVE);
- atk_state_set_add_state (GET_PRIVATE(a11y)->state_set, ATK_STATE_SHOWING);
- atk_state_set_add_state (GET_PRIVATE(a11y)->state_set, ATK_STATE_VISIBLE);
-
-
- accessible = ATK_OBJECT(a11y);
-
- /* Initialize cell data. */
- n = item->cols * item->rows;
- GET_PRIVATE (a11y)->cols = item->cols;
- GET_PRIVATE (a11y)->rows = item->rows;
-
- GET_PRIVATE (a11y)->columns = e_table_header_get_columns (item->header);
- if ( GET_PRIVATE (a11y)->columns == NULL)
- return NULL;
-
- if (item) {
- g_signal_connect (G_OBJECT(item), "selection_model_removed",
- G_CALLBACK (eti_a11y_selection_model_removed_cb), NULL);
- g_signal_connect (G_OBJECT(item), "selection_model_added",
- G_CALLBACK (eti_a11y_selection_model_added_cb), NULL);
- if (item->selection)
- gal_a11y_e_table_item_ref_selection (a11y,
- item->selection);
-
- /* find the TableItem's parent: table or tree */
- GET_PRIVATE (a11y)->widget = gtk_widget_get_parent (GTK_WIDGET (item->parent.canvas));
- parent = gtk_widget_get_accessible (GET_PRIVATE (a11y)->widget);
- name = atk_object_get_name (parent);
- if (name)
- atk_object_set_name (accessible, name);
- atk_object_set_parent (accessible, parent);
-
- if (E_IS_TREE (GET_PRIVATE (a11y)->widget)) {
- ETreeModel *model;
- model = e_tree_get_model (E_TREE (GET_PRIVATE (a11y)->widget));
- g_signal_connect (G_OBJECT(model), "node_changed",
- G_CALLBACK (eti_tree_model_node_changed_cb), item);
- accessible->role = ATK_ROLE_TREE_TABLE;
- } else if (E_IS_TABLE (GET_PRIVATE (a11y)->widget)) {
- accessible->role = ATK_ROLE_TABLE;
- }
- }
-
- if (item)
- g_signal_connect (G_OBJECT (item), "destroy",
- G_CALLBACK (item_destroyed),
- a11y);
- esm = item->selection;
-
- if (esm != NULL) {
- int cursor_row, cursor_col, view_row, view_col;
-
- cursor_row = e_selection_model_cursor_row(esm);
- cursor_col = e_selection_model_cursor_col(esm);
-
- view_row = model_to_view_row (item, cursor_row);
- view_col = model_to_view_col (item, cursor_col);
-
- if (view_row == -1)
- view_row = 0;
- if (view_col == -1)
- view_col = 0;
-
- cell = eti_ref_at (ATK_TABLE (a11y), view_row, view_col);
- if (cell != NULL) {
- g_object_set_data (G_OBJECT(a11y), "gail-focus-object", cell);
- gal_a11y_e_cell_add_state (GAL_A11Y_E_CELL (cell), ATK_STATE_FOCUSED, FALSE);
- }
- }
-
- return ATK_OBJECT (a11y);
-}
-
-static gboolean
-gal_a11y_e_table_item_ref_selection (GalA11yETableItem *a11y,
- ESelectionModel *selection)
-{
- GalA11yETableItemPrivate *priv;
-
- g_return_val_if_fail (a11y && selection, FALSE);
-
- priv = GET_PRIVATE (a11y);
- priv->selection_change_id = g_signal_connect (
- G_OBJECT(selection), "selection_changed",
- G_CALLBACK (eti_a11y_selection_changed_cb), a11y);
- priv->cursor_change_id = g_signal_connect (
- G_OBJECT(selection), "cursor_changed",
- G_CALLBACK (eti_a11y_cursor_changed_cb), a11y);
-
- priv->selection = selection;
- g_object_ref (selection);
-
- return TRUE;
-}
-
-static gboolean
-gal_a11y_e_table_item_unref_selection (GalA11yETableItem *a11y)
-{
- GalA11yETableItemPrivate *priv;
-
- g_return_val_if_fail (a11y, FALSE);
-
- priv = GET_PRIVATE (a11y);
-
- g_return_val_if_fail (priv->selection_change_id != 0, FALSE);
- g_return_val_if_fail (priv->cursor_change_id != 0, FALSE);
-
-
- g_signal_handler_disconnect (priv->selection,
- priv->selection_change_id);
- g_signal_handler_disconnect (priv->selection,
- priv->cursor_change_id);
- priv->cursor_change_id = 0;
- priv->selection_change_id = 0;
-
- g_object_unref (priv->selection);
- priv->selection = NULL;
-
- return TRUE;
-}
-
-/* callbacks */
-
-static void
-eti_a11y_selection_model_removed_cb (ETableItem *eti, ESelectionModel *selection,
- gpointer data)
-{
- AtkObject *atk_obj;
- GalA11yETableItem *a11y;
-
- g_return_if_fail (E_IS_TABLE_ITEM (eti));
- g_return_if_fail (E_IS_SELECTION_MODEL (selection));
-
- atk_obj = atk_gobject_accessible_for_object (G_OBJECT (eti));
- a11y = GAL_A11Y_E_TABLE_ITEM (atk_obj);
-
- if (selection == GET_PRIVATE (a11y)->selection)
- gal_a11y_e_table_item_unref_selection (a11y);
-}
-
-static void
-eti_a11y_selection_model_added_cb (ETableItem *eti, ESelectionModel *selection,
- gpointer data)
-{
- AtkObject *atk_obj;
- GalA11yETableItem *a11y;
-
- g_return_if_fail (E_IS_TABLE_ITEM (eti));
- g_return_if_fail (E_IS_SELECTION_MODEL (selection));
-
- atk_obj = atk_gobject_accessible_for_object (G_OBJECT (eti));
- a11y = GAL_A11Y_E_TABLE_ITEM (atk_obj);
-
- if (GET_PRIVATE (a11y)->selection)
- gal_a11y_e_table_item_unref_selection (a11y);
- gal_a11y_e_table_item_ref_selection (a11y, selection);
-}
-
-static void
-eti_a11y_selection_changed_cb (ESelectionModel *selection, GalA11yETableItem *a11y)
-{
- GalA11yETableItemPrivate *priv = GET_PRIVATE (a11y);
-
- if (atk_state_set_contains_state (priv->state_set, ATK_STATE_DEFUNCT))
- return;
-
- g_return_if_fail (GAL_A11Y_IS_E_TABLE_ITEM (a11y));
-
- g_signal_emit_by_name (a11y, "selection_changed");
-}
-
-static void
-eti_a11y_cursor_changed_cb (ESelectionModel *selection,
- int row, int col, GalA11yETableItem *a11y)
-{
- AtkObject * cell;
- int view_row, view_col;
- ETableItem *item;
- GalA11yETableItemPrivate *priv = GET_PRIVATE (a11y);
-
- g_return_if_fail (GAL_A11Y_IS_E_TABLE_ITEM (a11y));
-
- if (atk_state_set_contains_state (priv->state_set, ATK_STATE_DEFUNCT))
- return;
-
- item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (a11y)));
-
- g_return_if_fail (item);
-
- if (row == -1 && col == -1)
- return;
-
- view_row = model_to_view_row (item, row);
- view_col = model_to_view_col (item, col);
-
- if (view_col == -1)
- view_col = 0;
- cell = eti_ref_at (ATK_TABLE (a11y), view_row, view_col);
- if (cell != NULL) {
- AtkObject *old_cell = (AtkObject *)g_object_get_data (G_OBJECT(a11y), "gail-focus-object");
- if (old_cell && GAL_A11Y_IS_E_CELL (old_cell))
- gal_a11y_e_cell_remove_state (GAL_A11Y_E_CELL (old_cell), ATK_STATE_FOCUSED, FALSE);
- if (old_cell)
- g_object_unref (old_cell);
-
- g_object_set_data (G_OBJECT(a11y), "gail-focus-object", cell);
-
- if (ATK_IS_OBJECT (cell))
- g_signal_emit_by_name (a11y,
- "active-descendant-changed",
- cell);
- }
-
-}
-
-/* atk selection */
-
-static void atk_selection_interface_init (AtkSelectionIface *iface)
-{
- g_return_if_fail (iface != NULL);
- iface->add_selection = selection_add_selection;
- iface->clear_selection = selection_clear_selection;
- iface->ref_selection = selection_ref_selection;
- iface->get_selection_count = selection_get_selection_count;
- iface->is_child_selected = selection_is_child_selected;
-}
-
-static gboolean
-selection_add_selection (AtkSelection *selection, gint index)
-{
- AtkTable *table;
- gint row, col, cursor_row, cursor_col, model_row, model_col;
- ETableItem *item;
-
- item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (selection)));
- if (!item)
- return FALSE;
-
- table = ATK_TABLE (selection);
-
- row = atk_table_get_row_at_index (table, index);
- col = atk_table_get_column_at_index (table, index);
-
- model_row = view_to_model_row (item, row);
- model_col = view_to_model_col (item, col);
-
- cursor_row = e_selection_model_cursor_row (item->selection);
- cursor_col = e_selection_model_cursor_col (item->selection);
-
- /* check whether is selected already */
- if (model_row == cursor_row && model_col == cursor_col)
- return TRUE;
-
- if (model_row != cursor_row) {
- /* we need to make the item get focus */
- e_canvas_item_grab_focus (GNOME_CANVAS_ITEM (item), TRUE);
-
- /* FIXME, currently we only support single row selection */
- atk_selection_clear_selection (selection);
- atk_table_add_row_selection (table, row);
- }
-
- e_selection_model_change_cursor (item->selection,
- model_row,
- model_col);
- e_selection_model_cursor_changed (item->selection,
- model_row,
- model_col);
- e_selection_model_cursor_activated (item->selection,
- model_row,
- model_col);
- return TRUE;
-}
-
-static gboolean
-selection_clear_selection (AtkSelection *selection)
-{
- ETableItem *item;
-
- item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (selection)));
- if (!item)
- return FALSE;
-
- e_selection_model_clear (item->selection);
- return TRUE;
-}
-
-static AtkObject *
-selection_ref_selection (AtkSelection *selection, gint index)
-{
- AtkTable *table;
- gint row, col;
-
- table = ATK_TABLE (selection);
- row = atk_table_get_row_at_index (table, index);
- col = atk_table_get_column_at_index (table, index);
- if (!atk_table_is_row_selected (table, row))
- return NULL;
-
- return eti_ref_at (table, row, col);
-}
-
-static gint
-selection_get_selection_count (AtkSelection *selection)
-{
- AtkTable *table;
- gint n_selected;
-
- table = ATK_TABLE (selection);
- n_selected = atk_table_get_selected_rows (table, NULL);
- if (n_selected > 0)
- n_selected *= atk_table_get_n_columns (table);
- return n_selected;
-}
-
-static gboolean
-selection_is_child_selected (AtkSelection *selection, gint i)
-{
- gint row;
-
- row = atk_table_get_row_at_index (ATK_TABLE (selection), i);
- return atk_table_is_row_selected (ATK_TABLE (selection), row);
-}
-
-void
-gal_a11y_e_table_item_init (void)
-{
- if (atk_get_root ())
- atk_registry_set_factory_type (atk_get_default_registry (),
- E_TABLE_ITEM_TYPE,
- gal_a11y_e_table_item_factory_get_type ());
-}
-
diff --git a/a11y/e-table/gal-a11y-e-table-item.h b/a11y/e-table/gal-a11y-e-table-item.h
deleted file mode 100644
index 0317132804..0000000000
--- a/a11y/e-table/gal-a11y-e-table-item.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * Authors:
- * Christopher James Lahey <clahey@ximian.com>
- *
- * Copyright (C) 2001 Chris Lahey
- */
-
-#ifndef __GAL_A11Y_E_TABLE_ITEM_H__
-#define __GAL_A11Y_E_TABLE_ITEM_H__
-
-#include <glib-object.h>
-#include <gal/e-table/e-table-item.h>
-#include <atk/atkgobjectaccessible.h>
-
-#define GAL_A11Y_TYPE_E_TABLE_ITEM (gal_a11y_e_table_item_get_type ())
-#define GAL_A11Y_E_TABLE_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_TABLE_ITEM, GalA11yETableItem))
-#define GAL_A11Y_E_TABLE_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_TABLE_ITEM, GalA11yETableItemClass))
-#define GAL_A11Y_IS_E_TABLE_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_TABLE_ITEM))
-#define GAL_A11Y_IS_E_TABLE_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_TABLE_ITEM))
-
-typedef struct _GalA11yETableItem GalA11yETableItem;
-typedef struct _GalA11yETableItemClass GalA11yETableItemClass;
-typedef struct _GalA11yETableItemPrivate GalA11yETableItemPrivate;
-
-/* This struct should actually be larger as this isn't what we derive from.
- * The GalA11yETableItemPrivate comes right after the parent class structure.
- **/
-struct _GalA11yETableItem {
- AtkGObjectAccessible parent;
-};
-
-struct _GalA11yETableItemClass {
- AtkGObjectAccessibleClass parent_class;
-};
-
-
-/* Standard Glib function */
-GType gal_a11y_e_table_item_get_type (void);
-AtkObject *gal_a11y_e_table_item_new (ETableItem *item);
-
-void gal_a11y_e_table_item_init (void);
-
-#endif /* ! __GAL_A11Y_E_TABLE_ITEM_H__ */
diff --git a/a11y/e-table/gal-a11y-e-table.c b/a11y/e-table/gal-a11y-e-table.c
deleted file mode 100644
index b49a8a653a..0000000000
--- a/a11y/e-table/gal-a11y-e-table.c
+++ /dev/null
@@ -1,293 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * Authors:
- * Christopher James Lahey <clahey@ximian.com>
- *
- * Copyright (C) 2002 Ximian, Inc.
- */
-
-#include <config.h>
-#include "gal-a11y-e-table.h"
-#include "gal-a11y-e-table-factory.h"
-#include "gal-a11y-e-table-item.h"
-#include "gal-a11y-util.h"
-#include <gal/e-table/e-table.h>
-#include <gal/e-table/e-table-group.h>
-#include <gal/e-table/e-table-group-container.h>
-#include <gal/e-table/e-table-group-leaf.h>
-#include <gal/e-table/e-table-click-to-add.h>
-
-#define CS_CLASS(a11y) (G_TYPE_INSTANCE_GET_CLASS ((a11y), C_TYPE_STREAM, GalA11yETableClass))
-static AtkObjectClass *parent_class;
-static GType parent_type;
-static gint priv_offset;
-#define GET_PRIVATE(object) ((GalA11yETablePrivate *) (((char *) object) + priv_offset))
-#define PARENT_TYPE (parent_type)
-
-struct _GalA11yETablePrivate {
- AtkObject *child_item;
-};
-
-/* Static functions */
-static ETableItem *
-find_first_table_item (ETableGroup *group)
-{
- GnomeCanvasGroup *cgroup;
- GList *l;
-
- cgroup = GNOME_CANVAS_GROUP (group);
-
- for (l = cgroup->item_list; l; l = l->next) {
- GnomeCanvasItem *i;
-
- i = GNOME_CANVAS_ITEM (l->data);
-
- if (E_IS_TABLE_GROUP (i))
- return find_first_table_item (E_TABLE_GROUP (i));
- else if (E_IS_TABLE_ITEM (i)) {
- return E_TABLE_ITEM (i);
- }
- }
-
- return NULL;
-}
-
-static AtkObject*
-eti_get_accessible (ETableItem *eti, AtkObject *parent)
-{
- AtkObject *a11y = NULL;
-
- g_return_val_if_fail (eti, NULL);
-
- a11y = atk_gobject_accessible_for_object (G_OBJECT (eti));
- g_return_val_if_fail (a11y, NULL);
-
- return a11y;
-}
-
-static gboolean
-init_child_item (GalA11yETable *a11y)
-{
- ETable *table;
-
- if (!a11y || !GTK_IS_ACCESSIBLE (a11y))
- return FALSE;
-
- table = E_TABLE (GTK_ACCESSIBLE (a11y)->widget);
- if (table && GTK_WIDGET_MAPPED (GTK_WIDGET (table)) && table->group && E_IS_TABLE_GROUP_CONTAINER(table->group)) {
- ETableGroupContainer *etgc = (ETableGroupContainer *)table->group;
- GList *list;
-
- for (list = etgc->children; list; list = g_list_next (list)) {
- ETableGroupContainerChildNode *child_node = list->data;
- ETableGroup *child = child_node->child;
- ETableItem *eti = find_first_table_item (child);
-
- eti_get_accessible (eti, ATK_OBJECT (a11y));
- }
- }
- g_object_unref (a11y);
- g_object_unref (table);
-
- return FALSE;
-}
-
-static AtkObject*
-et_ref_accessible_at_point (AtkComponent *component,
- gint x,
- gint y,
- AtkCoordType coord_type)
-{
- GalA11yETable *a11y = GAL_A11Y_E_TABLE (component);
- if (GET_PRIVATE (a11y)->child_item)
- g_object_ref (GET_PRIVATE (a11y)->child_item);
- return GET_PRIVATE (a11y)->child_item;
-}
-
-static gint
-et_get_n_children (AtkObject *accessible)
-{
- GalA11yETable *a11y = GAL_A11Y_E_TABLE (accessible);
- ETable * et;
- int n = 0;
-
- et = E_TABLE(GTK_ACCESSIBLE (a11y)->widget);
-
- if (et->group) {
- if (E_IS_TABLE_GROUP_LEAF (et->group))
- n = 1;
- else if (E_IS_TABLE_GROUP_CONTAINER (et->group)) {
- ETableGroupContainer *etgc = (ETableGroupContainer *)et->group;
- n = g_list_length (etgc->children);
- }
- }
-
- if (et && et->use_click_to_add && et->click_to_add) {
- n++;
- }
- return n;
-}
-
-static AtkObject*
-et_ref_child (AtkObject *accessible,
- gint i)
-{
- GalA11yETable *a11y = GAL_A11Y_E_TABLE (accessible);
- ETable * et;
- gint child_no;
-
- et = E_TABLE(GTK_ACCESSIBLE (a11y)->widget);
-
- child_no = et_get_n_children (accessible);
- if (i == 0 || i < child_no - 1) {
- if (E_IS_TABLE_GROUP_LEAF (et->group)) {
- ETableItem *eti = find_first_table_item (et->group);
- AtkObject *aeti = eti_get_accessible (eti, accessible);
- if (aeti)
- g_object_ref (aeti);
- return aeti;
-
- } else if (E_IS_TABLE_GROUP_CONTAINER (et->group)) {
- ETableGroupContainer *etgc = (ETableGroupContainer *) et->group;
- ETableGroupContainerChildNode *child_node = g_list_nth_data (etgc->children, i);
- if (child_node) {
- ETableGroup *child = child_node->child;
- ETableItem * eti = find_first_table_item (child);
- AtkObject *aeti = eti_get_accessible (eti, accessible);
- if (aeti)
- g_object_ref (aeti);
- return aeti;
- }
- }
- } else if (i == child_no -1) {
- AtkObject * accessible;
- ETableClickToAdd * etcta;
-
- if (et && et->use_click_to_add && et->click_to_add) {
- etcta = E_TABLE_CLICK_TO_ADD(et->click_to_add);
- accessible = atk_gobject_accessible_for_object (G_OBJECT(etcta));
- if (accessible)
- g_object_ref (accessible);
- return accessible;
- }
- }
-
- return NULL;
-}
-
-static AtkLayer
-et_get_layer (AtkComponent *component)
-{
- return ATK_LAYER_WIDGET;
-}
-
-static void
-et_class_init (GalA11yETableClass *klass)
-{
- AtkObjectClass *atk_object_class = ATK_OBJECT_CLASS (klass);
-
- parent_class = g_type_class_ref (PARENT_TYPE);
-
- atk_object_class->get_n_children = et_get_n_children;
- atk_object_class->ref_child = et_ref_child;
-}
-
-static void
-et_atk_component_iface_init (AtkComponentIface *iface)
-{
- iface->ref_accessible_at_point = et_ref_accessible_at_point;
- iface->get_layer = et_get_layer;
-}
-
-static void
-et_init (GalA11yETable *a11y)
-{
- GalA11yETablePrivate *priv;
-
- priv = GET_PRIVATE (a11y);
-
- priv->child_item = NULL;
-}
-
-/**
- * gal_a11y_e_table_get_type:
- * @void:
- *
- * Registers the &GalA11yETable class if necessary, and returns the type ID
- * associated to it.
- *
- * Return value: The type ID of the &GalA11yETable class.
- **/
-GType
-gal_a11y_e_table_get_type (void)
-{
- static GType type = 0;
-
- if (!type) {
- AtkObjectFactory *factory;
-
- GTypeInfo info = {
- sizeof (GalA11yETableClass),
- (GBaseInitFunc) NULL,
- (GBaseFinalizeFunc) NULL,
- (GClassInitFunc) et_class_init,
- (GClassFinalizeFunc) NULL,
- NULL, /* class_data */
- sizeof (GalA11yETable),
- 0,
- (GInstanceInitFunc) et_init,
- NULL /* value_table */
- };
-
- static const GInterfaceInfo atk_component_info = {
- (GInterfaceInitFunc) et_atk_component_iface_init,
- (GInterfaceFinalizeFunc) NULL,
- NULL
- };
-
- factory = atk_registry_get_factory (atk_get_default_registry (), GTK_TYPE_WIDGET);
- parent_type = atk_object_factory_get_accessible_type (factory);
-
- type = gal_a11y_type_register_static_with_private (PARENT_TYPE, "GalA11yETable", &info, 0,
- sizeof (GalA11yETablePrivate), &priv_offset);
- g_type_add_interface_static (type, ATK_TYPE_COMPONENT, &atk_component_info);
- }
-
- return type;
-}
-
-AtkObject *
-gal_a11y_e_table_new (GObject *widget)
-{
- GalA11yETable *a11y;
- ETable *table;
-
- table = E_TABLE (widget);
-
- a11y = g_object_new (gal_a11y_e_table_get_type (), NULL);
-
- GTK_ACCESSIBLE (a11y)->widget = GTK_WIDGET (widget);
-
- /* we need to init all the children for multiple table items */
- if (table && GTK_WIDGET_MAPPED (GTK_WIDGET (table)) && table->group && E_IS_TABLE_GROUP_CONTAINER (table->group)) {
- /* Ref it here so that it is still valid in the idle function */
- /* It will be unrefed in the idle function */
- g_object_ref (a11y);
- g_object_ref (widget);
-
- g_idle_add ((GSourceFunc)init_child_item, a11y);
- }
-
- return ATK_OBJECT (a11y);
-}
-
-void
-gal_a11y_e_table_init (void)
-{
- if (atk_get_root ())
- atk_registry_set_factory_type (atk_get_default_registry (),
- E_TABLE_TYPE,
- gal_a11y_e_table_factory_get_type ());
-
-}
-
diff --git a/a11y/e-table/gal-a11y-e-table.h b/a11y/e-table/gal-a11y-e-table.h
deleted file mode 100644
index 780cff4509..0000000000
--- a/a11y/e-table/gal-a11y-e-table.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * Authors:
- * Christopher James Lahey <clahey@ximian.com>
- *
- * Copyright (C) 2001 Chris Lahey
- */
-
-#ifndef __GAL_A11Y_E_TABLE_H__
-#define __GAL_A11Y_E_TABLE_H__
-
-#include <glib-object.h>
-#include <atk/atkobject.h>
-#include <atk/atkcomponent.h>
-#include <gtk/gtkaccessible.h>
-
-#define GAL_A11Y_TYPE_E_TABLE (gal_a11y_e_table_get_type ())
-#define GAL_A11Y_E_TABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_TABLE, GalA11yETable))
-#define GAL_A11Y_E_TABLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_TABLE, GalA11yETableClass))
-#define GAL_A11Y_IS_E_TABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_TABLE))
-#define GAL_A11Y_IS_E_TABLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_TABLE))
-
-typedef struct _GalA11yETable GalA11yETable;
-typedef struct _GalA11yETableClass GalA11yETableClass;
-typedef struct _GalA11yETablePrivate GalA11yETablePrivate;
-
-/* This struct should actually be larger as this isn't what we derive from.
- * The GalA11yETablePrivate comes right after the parent class structure.
- **/
-struct _GalA11yETable {
- GtkAccessible object;
-};
-
-struct _GalA11yETableClass {
- GtkAccessibleClass parent_class;
-};
-
-
-/* Standard Glib function */
-GType gal_a11y_e_table_get_type (void);
-AtkObject *gal_a11y_e_table_new (GObject *table);
-
-void gal_a11y_e_table_init (void);
-
-#endif /* ! __GAL_A11Y_E_TABLE_H__ */
diff --git a/a11y/e-table/gal-a11y-e-tree-factory.c b/a11y/e-table/gal-a11y-e-tree-factory.c
deleted file mode 100644
index 2fa34c5fbc..0000000000
--- a/a11y/e-table/gal-a11y-e-tree-factory.c
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Authors: Yuedong Du <yuedong.du@sun.com>
- *
- * Copyright (C) 2003 Ximian, Inc.
- */
-
-#include <config.h>
-#include "gal-a11y-e-tree-factory.h"
-#include "gal-a11y-e-tree.h"
-
-#define CS_CLASS(factory) (G_TYPE_INSTANCE_GET_CLASS ((factory), C_TYPE_STREAM, GalA11yETreeFactoryClass))
-static AtkObjectFactoryClass *parent_class;
-#define PARENT_TYPE (ATK_TYPE_OBJECT_FACTORY)
-
-/* Static functions */
-
-static GType
-gal_a11y_e_tree_factory_get_accessible_type (void)
-{
- return GAL_A11Y_TYPE_E_TREE;
-}
-
-static AtkObject*
-gal_a11y_e_tree_factory_create_accessible (GObject *obj)
-{
- AtkObject *accessible;
-
- accessible = gal_a11y_e_tree_new (obj);
-
- return accessible;
-}
-
-static void
-gal_a11y_e_tree_factory_class_init (GalA11yETreeFactoryClass *klass)
-{
- AtkObjectFactoryClass *factory_class = ATK_OBJECT_FACTORY_CLASS (klass);
-
- parent_class = g_type_class_ref (PARENT_TYPE);
-
- factory_class->create_accessible = gal_a11y_e_tree_factory_create_accessible;
- factory_class->get_accessible_type = gal_a11y_e_tree_factory_get_accessible_type;
-}
-
-static void
-gal_a11y_e_tree_factory_init (GalA11yETreeFactory *factory)
-{
-}
-
-/**
- * gal_a11y_e_tree_factory_get_type:
- * @void:
- *
- * Registers the &GalA11yETreeFactory class if necessary, and returns the type ID
- * associated to it.
- *
- * Return value: The type ID of the &GalA11yETreeFactory class.
- **/
-GType
-gal_a11y_e_tree_factory_get_type (void)
-{
- static GType type = 0;
-
- if (!type) {
- GTypeInfo info = {
- sizeof (GalA11yETreeFactoryClass),
- (GBaseInitFunc) NULL,
- (GBaseFinalizeFunc) NULL,
- (GClassInitFunc) gal_a11y_e_tree_factory_class_init,
- (GClassFinalizeFunc) NULL,
- NULL, /* class_data */
- sizeof (GalA11yETreeFactory),
- 0,
- (GInstanceInitFunc) gal_a11y_e_tree_factory_init,
- NULL /* value_tree */
- };
-
- type = g_type_register_static (PARENT_TYPE, "GalA11yETreeFactory", &info, 0);
- }
-
- return type;
-}
diff --git a/a11y/e-table/gal-a11y-e-tree-factory.h b/a11y/e-table/gal-a11y-e-tree-factory.h
deleted file mode 100644
index 434e526db9..0000000000
--- a/a11y/e-table/gal-a11y-e-tree-factory.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Authors: Yuedong Du <yuedong.du@ximian.com>
- *
- * Copyright (C) 2003 Ximian, Inc.
- */
-
-#ifndef __GAL_A11Y_E_TREE_FACTORY_H__
-#define __GAL_A11Y_E_TREE_FACTORY_H__
-
-#include <glib-object.h>
-#include <atk/atkobjectfactory.h>
-
-#define GAL_A11Y_TYPE_E_TREE_FACTORY (gal_a11y_e_table_factory_get_type ())
-#define GAL_A11Y_E_TREE_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_TREE_FACTORY, GalA11yETreeFactory))
-#define GAL_A11Y_E_TREE_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_TREE_FACTORY, GalA11yETreeFactoryClass))
-#define GAL_A11Y_IS_E_TREE_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_TREE_FACTORY))
-#define GAL_A11Y_IS_E_TREE_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_TREE_FACTORY))
-
-typedef struct _GalA11yETreeFactory GalA11yETreeFactory;
-typedef struct _GalA11yETreeFactoryClass GalA11yETreeFactoryClass;
-
-struct _GalA11yETreeFactory {
- AtkObject object;
-};
-
-struct _GalA11yETreeFactoryClass {
- AtkObjectClass parent_class;
-};
-
-
-/* Standard Glib function */
-GType gal_a11y_e_tree_factory_get_type (void);
-
-#endif /* ! __GAL_A11Y_E_TREE_FACTORY_H__ */
diff --git a/a11y/e-table/gal-a11y-e-tree.c b/a11y/e-table/gal-a11y-e-tree.c
deleted file mode 100644
index de468398ea..0000000000
--- a/a11y/e-table/gal-a11y-e-tree.c
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Authors: Yuedong Du <yuedong.du@sun.com>
- *
- * Copyright (C) 2003 Ximian, Inc.
- */
-
-#include <config.h>
-#include "gal-a11y-e-tree.h"
-#include "gal-a11y-e-tree-factory.h"
-#include "gal-a11y-util.h"
-#include "gal-a11y-e-table-item.h"
-#include <gal/e-table/e-tree.h>
-#include <gal/e-table/e-table-item.h>
-
-#define CS_CLASS(a11y) (G_TYPE_INSTANCE_GET_CLASS ((a11y), C_TYPE_STREAM, GalA11yETreeClass))
-static AtkObjectClass *parent_class;
-static GType parent_type;
-static gint priv_offset;
-#define GET_PRIVATE(object) ((GalA11yETreePrivate *) (((char *) object) + priv_offset))
-#define PARENT_TYPE (parent_type)
-
-struct _GalA11yETreePrivate {
- AtkObject *child_item;
-};
-
-/* Static functions */
-
-static void
-init_child_item (GalA11yETree *a11y)
-{
- GalA11yETreePrivate *priv = GET_PRIVATE (a11y);
- ETree *tree = E_TREE (GTK_ACCESSIBLE (a11y)->widget);
- ETableItem * eti;
-
- g_return_if_fail (tree);
- eti = e_tree_get_item (tree);
- if (priv->child_item == NULL) {
- priv->child_item = atk_gobject_accessible_for_object (G_OBJECT (eti));
- }
-}
-
-static AtkObject*
-et_ref_accessible_at_point (AtkComponent *component,
- gint x,
- gint y,
- AtkCoordType coord_type)
-{
- GalA11yETree *a11y = GAL_A11Y_E_TREE (component);
- init_child_item (a11y);
- return GET_PRIVATE (a11y)->child_item;
-}
-
-static gint
-et_get_n_children (AtkObject *accessible)
-{
- return 1;
-}
-
-static AtkObject*
-et_ref_child (AtkObject *accessible,
- gint i)
-{
- GalA11yETree *a11y = GAL_A11Y_E_TREE (accessible);
- if (i != 0)
- return NULL;
- init_child_item (a11y);
- g_object_ref (GET_PRIVATE (a11y)->child_item);
- return GET_PRIVATE (a11y)->child_item;
-}
-
-static AtkLayer
-et_get_layer (AtkComponent *component)
-{
- return ATK_LAYER_WIDGET;
-}
-
-static void
-et_class_init (GalA11yETreeClass *klass)
-{
- AtkObjectClass *atk_object_class = ATK_OBJECT_CLASS (klass);
-
- parent_class = g_type_class_ref (PARENT_TYPE);
-
- atk_object_class->get_n_children = et_get_n_children;
- atk_object_class->ref_child = et_ref_child;
-}
-
-static void
-et_atk_component_iface_init (AtkComponentIface *iface)
-{
- iface->ref_accessible_at_point = et_ref_accessible_at_point;
- iface->get_layer = et_get_layer;
-}
-
-static void
-et_init (GalA11yETree *a11y)
-{
- GalA11yETreePrivate *priv;
-
- priv = GET_PRIVATE (a11y);
-
- priv->child_item = NULL;
-}
-
-/**
- * gal_a11y_e_tree_get_type:
- * @void:
- *
- * Registers the &GalA11yETree class if necessary, and returns the type ID
- * associated to it.
- *
- * Return value: The type ID of the &GalA11yETree class.
- **/
-GType
-gal_a11y_e_tree_get_type (void)
-{
- static GType type = 0;
-
- if (!type) {
- AtkObjectFactory *factory;
-
- GTypeInfo info = {
- sizeof (GalA11yETreeClass),
- (GBaseInitFunc) NULL,
- (GBaseFinalizeFunc) NULL,
- (GClassInitFunc) et_class_init,
- (GClassFinalizeFunc) NULL,
- NULL, /* class_data */
- sizeof (GalA11yETree),
- 0,
- (GInstanceInitFunc) et_init,
- NULL /* value_tree */
- };
-
- static const GInterfaceInfo atk_component_info = {
- (GInterfaceInitFunc) et_atk_component_iface_init,
- (GInterfaceFinalizeFunc) NULL,
- NULL
- };
-
- factory = atk_registry_get_factory (atk_get_default_registry (), GTK_TYPE_WIDGET);
- parent_type = atk_object_factory_get_accessible_type (factory);
-
- type = gal_a11y_type_register_static_with_private (PARENT_TYPE, "GalA11yETree", &info, 0,
- sizeof (GalA11yETreePrivate), &priv_offset);
- g_type_add_interface_static (type, ATK_TYPE_COMPONENT, &atk_component_info);
- }
-
- return type;
-}
-
-AtkObject *
-gal_a11y_e_tree_new (GObject *widget)
-{
- GalA11yETree *a11y;
- ETree *tree;
-
- tree = E_TREE (widget);
-
- a11y = g_object_new (gal_a11y_e_tree_get_type (), NULL);
-
- GTK_ACCESSIBLE (a11y)->widget = GTK_WIDGET (widget);
-
- return ATK_OBJECT (a11y);
-}
-
-void
-gal_a11y_e_tree_init (void)
-{
- if (atk_get_root ())
- atk_registry_set_factory_type (atk_get_default_registry (),
- E_TREE_TYPE,
- gal_a11y_e_tree_factory_get_type ());
-
-}
-
diff --git a/a11y/e-table/gal-a11y-e-tree.h b/a11y/e-table/gal-a11y-e-tree.h
deleted file mode 100644
index a9468ced54..0000000000
--- a/a11y/e-table/gal-a11y-e-tree.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Authors: Yuedong Du <yuedong.du@sun.com>
- *
- * Copyright (C) 2003 Ximian, Inc.
- */
-
-#ifndef __GAL_A11Y_E_TREE_H__
-#define __GAL_A11Y_E_TREE_H__
-
-#include <glib-object.h>
-#include <atk/atkobject.h>
-#include <atk/atkcomponent.h>
-#include <gtk/gtkaccessible.h>
-
-#define GAL_A11Y_TYPE_E_TREE (gal_a11y_e_tree_get_type ())
-#define GAL_A11Y_E_TREE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_TREE, GalA11yETree))
-#define GAL_A11Y_E_TREE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_TREE, GalA11yETreeClass))
-#define GAL_A11Y_IS_E_TREE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_TREE))
-#define GAL_A11Y_IS_E_TREE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_TREE))
-
-typedef struct _GalA11yETree GalA11yETree;
-typedef struct _GalA11yETreeClass GalA11yETreeClass;
-typedef struct _GalA11yETreePrivate GalA11yETreePrivate;
-
-/* This struct should actually be larger as this isn't what we derive from.
- * The GalA11yETablePrivate comes right after the parent class structure.
- **/
-struct _GalA11yETree {
- GtkAccessible object;
-};
-
-struct _GalA11yETreeClass {
- GtkAccessibleClass parent_class;
-};
-
-
-/* Standard Glib function */
-GType gal_a11y_e_tree_get_type (void);
-AtkObject *gal_a11y_e_tree_new (GObject *tree);
-
-void gal_a11y_e_tree_init (void);
-
-#endif /* ! __GAL_A11Y_E_TREE_H__ */
diff --git a/a11y/e-text/.cvsignore b/a11y/e-text/.cvsignore
deleted file mode 100644
index 5b48d3f593..0000000000
--- a/a11y/e-text/.cvsignore
+++ /dev/null
@@ -1,4 +0,0 @@
-.libs
-Makefile.in
-Makefile
-*.la
diff --git a/a11y/e-text/gal-a11y-e-text-factory.c b/a11y/e-text/gal-a11y-e-text-factory.c
deleted file mode 100644
index 24e3c28116..0000000000
--- a/a11y/e-text/gal-a11y-e-text-factory.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * Authors:
- * Christopher James Lahey <clahey@ximian.com>
- *
- * Copyright (C) 2002 Ximian, Inc.
- */
-
-#include <config.h>
-#include "gal/e-text/e-text.h"
-#include "gal-a11y-e-text-factory.h"
-#include "gal-a11y-e-text.h"
-
-#define CS_CLASS(factory) (G_TYPE_INSTANCE_GET_CLASS ((factory), C_TYPE_STREAM, GalA11yETextFactoryClass))
-static AtkObjectFactoryClass *parent_class;
-#define PARENT_TYPE (ATK_TYPE_OBJECT_FACTORY)
-
-/* Static functions */
-
-static GType
-gal_a11y_e_text_factory_get_accessible_type (void)
-{
- return GAL_A11Y_TYPE_E_TEXT;
-}
-
-static AtkObject*
-gal_a11y_e_text_factory_create_accessible (GObject *obj)
-{
- AtkObject *atk_object;
-
- g_return_val_if_fail (E_IS_TEXT (obj), NULL);
-
- atk_object = g_object_new (GAL_A11Y_TYPE_E_TEXT, NULL);
- atk_object_initialize (atk_object, obj);
-
- return atk_object;
-}
-
-static void
-gal_a11y_e_text_factory_class_init (GalA11yETextFactoryClass *klass)
-{
- AtkObjectFactoryClass *factory_class = ATK_OBJECT_FACTORY_CLASS (klass);
-
- parent_class = g_type_class_ref (PARENT_TYPE);
-
- factory_class->create_accessible = gal_a11y_e_text_factory_create_accessible;
- factory_class->get_accessible_type = gal_a11y_e_text_factory_get_accessible_type;
-}
-
-static void
-gal_a11y_e_text_factory_init (GalA11yETextFactory *factory)
-{
-}
-
-/**
- * gal_a11y_e_text_factory_get_type:
- * @void:
- *
- * Registers the &GalA11yETextFactory class if necessary, and returns the type ID
- * associated to it.
- *
- * Return value: The type ID of the &GalA11yETextFactory class.
- **/
-GType
-gal_a11y_e_text_factory_get_type (void)
-{
- static GType type = 0;
-
- if (!type) {
- GTypeInfo info = {
- sizeof (GalA11yETextFactoryClass),
- (GBaseInitFunc) NULL,
- (GBaseFinalizeFunc) NULL,
- (GClassInitFunc) gal_a11y_e_text_factory_class_init,
- (GClassFinalizeFunc) NULL,
- NULL, /* class_data */
- sizeof (GalA11yETextFactory),
- 0,
- (GInstanceInitFunc) gal_a11y_e_text_factory_init,
- NULL /* value_text */
- };
-
- type = g_type_register_static (PARENT_TYPE, "GalA11yETextFactory", &info, 0);
- }
-
- return type;
-}
diff --git a/a11y/e-text/gal-a11y-e-text-factory.h b/a11y/e-text/gal-a11y-e-text-factory.h
deleted file mode 100644
index 56a8d29ab9..0000000000
--- a/a11y/e-text/gal-a11y-e-text-factory.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * Authors:
- * Christopher James Lahey <clahey@ximian.com>
- *
- * Copyright (C) 2001 Chris Lahey
- */
-
-#ifndef __GAL_A11Y_E_TEXT_FACTORY_H__
-#define __GAL_A11Y_E_TEXT_FACTORY_H__
-
-#include <glib-object.h>
-#include <atk/atkobjectfactory.h>
-
-#define GAL_A11Y_TYPE_E_TEXT_FACTORY (gal_a11y_e_text_factory_get_type ())
-#define GAL_A11Y_E_TEXT_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_TEXT_FACTORY, GalA11yETextFactory))
-#define GAL_A11Y_E_TEXT_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_TEXT_FACTORY, GalA11yETextFactoryClass))
-#define GAL_A11Y_IS_E_TEXT_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_TEXT_FACTORY))
-#define GAL_A11Y_IS_E_TEXT_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_TEXT_FACTORY))
-
-typedef struct _GalA11yETextFactory GalA11yETextFactory;
-typedef struct _GalA11yETextFactoryClass GalA11yETextFactoryClass;
-
-struct _GalA11yETextFactory {
- AtkObjectFactory object;
-};
-
-struct _GalA11yETextFactoryClass {
- AtkObjectFactoryClass parent_class;
-};
-
-
-/* Standard Glib function */
-GType gal_a11y_e_text_factory_get_type (void);
-
-#endif /* ! __GAL_A11Y_E_TEXT_FACTORY_H__ */
diff --git a/a11y/e-text/gal-a11y-e-text.c b/a11y/e-text/gal-a11y-e-text.c
deleted file mode 100644
index 2463126afa..0000000000
--- a/a11y/e-text/gal-a11y-e-text.c
+++ /dev/null
@@ -1,1133 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * Authors:
- * Christopher James Lahey <clahey@ximian.com>
- *
- * Copyright (C) 2002 Ximian, Inc.
- */
-
-#include <config.h>
-#include <string.h>
-#include "gal-a11y-e-text.h"
-#include "gal-a11y-e-text-factory.h"
-#include "gal-a11y-util.h"
-#include <atk/atkobject.h>
-#include <atk/atktable.h>
-#include <atk/atkcomponent.h>
-#include <atk/atkobjectfactory.h>
-#include <atk/atkregistry.h>
-#include <atk/atkgobjectaccessible.h>
-#include "gal/e-text/e-text.h"
-#include "gal/e-text/e-text-model-repos.h"
-#include <gtk/gtkmain.h>
-
-#define CS_CLASS(a11y) (G_TYPE_INSTANCE_GET_CLASS ((a11y), C_TYPE_STREAM, GalA11yETextClass))
-static GObjectClass *parent_class;
-static AtkComponentIface *component_parent_iface;
-static GType parent_type;
-static gint priv_offset;
-static GQuark quark_accessible_object = 0;
-#define GET_PRIVATE(object) ((GalA11yETextPrivate *) (((char *) object) + priv_offset))
-#define PARENT_TYPE (parent_type)
-
-struct _GalA11yETextPrivate {
- int dummy;
-};
-
-static void
-et_dispose (GObject *object)
-{
- if (parent_class->dispose)
- parent_class->dispose (object);
-}
-
-/* Static functions */
-
-static void
-et_get_extents (AtkComponent *component,
- gint *x,
- gint *y,
- gint *width,
- gint *height,
- AtkCoordType coord_type)
-{
- EText *item = E_TEXT (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (component)));
- double real_width;
- double real_height;
- int fake_width;
- int fake_height;
-
- if (component_parent_iface &&
- component_parent_iface->get_extents)
- component_parent_iface->get_extents (component,
- x,
- y,
- &fake_width,
- &fake_height,
- coord_type);
-
- gtk_object_get (GTK_OBJECT (item),
- "text_width", &real_width,
- "text_height", &real_height,
- NULL);
-
- if (width)
- *width = real_width;
- if (height)
- *height = real_height;
-}
-
-static const gchar *
-et_get_full_text (AtkText *text)
-{
- EText *etext = E_TEXT (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text)));
- ETextModel *model;
- const char *full_text;
-
- gtk_object_get (GTK_OBJECT (etext),
- "model", &model,
- NULL);
-
- full_text = e_text_model_get_text (model);
-
- return full_text;
-}
-
-static void
-et_set_full_text (AtkEditableText *text,
- const char *full_text)
-{
- EText *etext = E_TEXT (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text)));
- ETextModel *model;
-
- gtk_object_get (GTK_OBJECT (etext),
- "model", &model,
- NULL);
-
- e_text_model_set_text (model, full_text);
-}
-
-static gchar *
-et_get_text (AtkText *text,
- gint start_offset,
- gint end_offset)
-{
- gint start, end, real_start, real_end, len;
- const char *full_text = et_get_full_text (text);
- if (full_text == NULL)
- return NULL;
- len = g_utf8_strlen (full_text, -1);
-
- start = MIN (MAX (0, start_offset), len);
- end = MIN (MAX (-1, end_offset), len);
-
- if (end_offset == -1)
- end = strlen (full_text);
- else
- end = g_utf8_offset_to_pointer (full_text, end) - full_text;
-
- start = g_utf8_offset_to_pointer (full_text, start) - full_text;
-
- real_start = MIN (start, end);
- real_end = MAX (start, end);
-
- return g_strndup (full_text + real_start, real_end - real_start);
-}
-
-static gboolean
-is_a_seperator (gunichar c)
-{
- return g_unichar_ispunct(c) || g_unichar_isspace(c);
-}
-
-static gint
-find_word_start (const char *text,
- gint begin_offset,
- gint step)
-{
- gint offset;
- char *at_offset;
- gunichar current, previous;
- gint len;
-
- offset = begin_offset;
- len = g_utf8_strlen (text, -1);
-
- while (offset > 0 && offset < len) {
- at_offset = g_utf8_offset_to_pointer (text, offset);
- current = g_utf8_get_char_validated (at_offset, -1);
- at_offset = g_utf8_offset_to_pointer (text, offset-1);
- previous = g_utf8_get_char_validated (at_offset, -1);
- if ((! is_a_seperator (current)) && is_a_seperator (previous))
- break;
- offset += step;
- }
-
- return offset;
-}
-
-static gint
-find_word_end (const char *text,
- gint begin_offset,
- gint step)
-{
- gint offset;
- char *at_offset;
- gunichar current, previous;
- gint len;
-
- offset = begin_offset;
- len = g_utf8_strlen (text, -1);
-
- while (offset > 0 && offset < len) {
- at_offset = g_utf8_offset_to_pointer (text, offset);
- current = g_utf8_get_char_validated (at_offset, -1);
- at_offset = g_utf8_offset_to_pointer (text, offset-1);
- previous = g_utf8_get_char_validated (at_offset, -1);
- if (is_a_seperator (current) && (! is_a_seperator (previous)))
- break;
- offset += step;
- }
-
- return offset;
-}
-
-static gint
-find_sentence_start (const char *text,
- gint begin_offset,
- gint step)
-{
- gint offset, last_word_end, len;
- char *at_offset;
- gunichar ch;
- int i;
-
- offset = find_word_start (text, begin_offset, step);
- len = g_utf8_strlen (text, -1);
-
- while (offset>0 && offset <len) {
- last_word_end = find_word_end (text, offset - 1, -1);
- if (last_word_end == 0)
- break;
- for (i = last_word_end; i < offset; i++) {
- at_offset = g_utf8_offset_to_pointer (text, i);
- ch = g_utf8_get_char_validated (at_offset, -1);
- if (ch == '.' || ch == '!' || ch == '?')
- return offset;
- }
-
- offset = find_word_start (text, offset + step, step);
- }
-
- return offset;
-}
-
-static gint
-find_sentence_end (const char *text,
- gint begin_offset,
- gint step)
-{
- gint offset;
- char *at_offset;
- gunichar previous;
- gint len;
-
- offset = begin_offset;
- len = g_utf8_strlen (text, -1);
-
- while (offset > 0 && offset < len) {
- at_offset = g_utf8_offset_to_pointer (text, offset - 1);
- previous = g_utf8_get_char_validated (at_offset, -1);
- if (previous == '.' || previous == '!' || previous == '?')
- break;
- offset += step;
- }
-
- return offset;
-}
-
-static gint
-find_line_start (const char *text,
- gint begin_offset,
- gint step)
-{
- gint offset;
- char *at_offset;
- gunichar previous;
- gint len;
-
- offset = begin_offset;
- len = g_utf8_strlen (text, -1);
-
- while (offset > 0 && offset < len) {
- at_offset = g_utf8_offset_to_pointer (text, offset - 1);
- previous = g_utf8_get_char_validated (at_offset, -1);
- if (previous == '\n' || previous == '\r')
- break;
- offset += step;
- }
-
- return offset;
-}
-
-static gint
-find_line_end (const char *text,
- gint begin_offset,
- gint step)
-{
- gint offset;
- char *at_offset;
- gunichar current;
- gint len;
-
- offset = begin_offset;
- len = g_utf8_strlen (text, -1);
-
- while (offset >= 0 && offset < len) {
- at_offset = g_utf8_offset_to_pointer (text, offset);
- current = g_utf8_get_char_validated (at_offset, -1);
- if (current == '\n' || current == '\r')
- break;
- offset += step;
- }
-
- return offset;
-}
-
-static gchar *
-et_get_text_after_offset (AtkText *text,
- gint offset,
- AtkTextBoundary boundary_type,
- gint *start_offset,
- gint *end_offset)
-{
- gint start, end, len;
- const char *full_text = et_get_full_text (text);
- g_return_val_if_fail (full_text, NULL);
-
- switch (boundary_type)
- {
- case ATK_TEXT_BOUNDARY_CHAR:
- start = offset + 1;
- end = offset + 2;
- break;
- case ATK_TEXT_BOUNDARY_WORD_START:
- start = find_word_start (full_text, offset + 1, 1);
- end = find_word_start (full_text, start + 1, 1);
- break;
- case ATK_TEXT_BOUNDARY_WORD_END:
- start = find_word_end (full_text, offset + 1, 1);
- end = find_word_end (full_text, start + 1, 1);
- break;
- case ATK_TEXT_BOUNDARY_SENTENCE_START:
- start = find_sentence_start (full_text, offset + 1, 1);
- end = find_sentence_start (full_text, start + 1, 1);
- break;
- case ATK_TEXT_BOUNDARY_SENTENCE_END:
- start = find_sentence_end (full_text, offset + 1, 1);
- end = find_sentence_end (full_text, start + 1, 1);
- break;
- case ATK_TEXT_BOUNDARY_LINE_START:
- start = find_line_start (full_text, offset + 1, 1);
- end = find_line_start (full_text, start + 1, 1);
- break;
- case ATK_TEXT_BOUNDARY_LINE_END:
- start = find_line_end (full_text, offset + 1, 1);
- end = find_line_end (full_text, start + 1, 1);
- break;
- default:
- return NULL;
- }
-
- len = g_utf8_strlen (full_text, -1);
- if (start_offset)
- *start_offset = MIN (MAX (0, start), len);
- if (end_offset)
- *end_offset = MIN (MAX (0, end), len);
- return et_get_text (text, start, end);
-}
-
-static gchar *
-et_get_text_at_offset (AtkText *text,
- gint offset,
- AtkTextBoundary boundary_type,
- gint *start_offset,
- gint *end_offset)
-{
- gint start, end, len;
- const char *full_text = et_get_full_text (text);
- g_return_val_if_fail (full_text, NULL);
-
- switch (boundary_type)
- {
- case ATK_TEXT_BOUNDARY_CHAR:
- start = offset;
- end = offset + 1;
- break;
- case ATK_TEXT_BOUNDARY_WORD_START:
- start = find_word_start (full_text, offset - 1, -1);
- end = find_word_start (full_text, offset, 1);
- break;
- case ATK_TEXT_BOUNDARY_WORD_END:
- start = find_word_end (full_text, offset, -1);
- end = find_word_end (full_text, offset + 1, 1);
- break;
- case ATK_TEXT_BOUNDARY_SENTENCE_START:
- start = find_sentence_start (full_text, offset - 1, -1);
- end = find_sentence_start (full_text, offset, 1);
- break;
- case ATK_TEXT_BOUNDARY_SENTENCE_END:
- start = find_sentence_end (full_text, offset, -1);
- end = find_sentence_end (full_text, offset + 1, 1);
- break;
- case ATK_TEXT_BOUNDARY_LINE_START:
- start = find_line_start (full_text, offset - 1, -1);
- end = find_line_start (full_text, offset, 1);
- break;
- case ATK_TEXT_BOUNDARY_LINE_END:
- start = find_line_end (full_text, offset, -1);
- end = find_line_end (full_text, offset + 1, 1);
- break;
- default:
- return NULL;
- }
-
- len = g_utf8_strlen (full_text, -1);
- if (start_offset)
- *start_offset = MIN (MAX (0, start), len);
- if (end_offset)
- *end_offset = MIN (MAX (0, end), len);
- return et_get_text (text, start, end);
-}
-
-static gunichar
-et_get_character_at_offset (AtkText *text,
- gint offset)
-{
- const char *full_text = et_get_full_text (text);
- char *at_offset;
-
- at_offset = g_utf8_offset_to_pointer (full_text, offset);
- return g_utf8_get_char_validated (at_offset, -1);
-}
-
-
-static gchar*
-et_get_text_before_offset (AtkText *text,
- gint offset,
- AtkTextBoundary boundary_type,
- gint *start_offset,
- gint *end_offset)
-{
- gint start, end, len;
- const char *full_text = et_get_full_text (text);
- g_return_val_if_fail (full_text, NULL);
-
- switch (boundary_type)
- {
- case ATK_TEXT_BOUNDARY_CHAR:
- start = offset - 1;
- end = offset;
- break;
- case ATK_TEXT_BOUNDARY_WORD_START:
- end = find_word_start (full_text, offset - 1, -1);
- start = find_word_start (full_text, end - 1, -1) ;
- break;
- case ATK_TEXT_BOUNDARY_WORD_END:
- end = find_word_end (full_text, offset, -1);
- start = find_word_end (full_text, end - 1, -1);
- break;
- case ATK_TEXT_BOUNDARY_SENTENCE_START:
- end = find_sentence_start (full_text, offset, -1);
- start = find_sentence_start (full_text, end - 1, -1);
- break;
- case ATK_TEXT_BOUNDARY_SENTENCE_END:
- end = find_sentence_end (full_text, offset, -1);
- start = find_sentence_end (full_text, end - 1, -1);
- break;
- case ATK_TEXT_BOUNDARY_LINE_START:
- end = find_line_start (full_text, offset, -1);
- start = find_line_start (full_text, end - 1, -1);
- break;
- case ATK_TEXT_BOUNDARY_LINE_END:
- end = find_line_end (full_text, offset, -1);
- start = find_line_end (full_text, end - 1, -1);
- break;
- default:
- return NULL;
- }
-
- len = g_utf8_strlen (full_text, -1);
- if (start_offset)
- *start_offset = MIN (MAX (0, start), len);
- if (end_offset)
- *end_offset = MIN (MAX (0, end), len);
- return et_get_text (text, start, end);
-}
-
-static gint
-et_get_caret_offset (AtkText *text)
-{
- GObject *obj;
- EText *etext;
- int offset;
-
- g_return_val_if_fail (ATK_IS_GOBJECT_ACCESSIBLE(text), -1);
- obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text));
- if (obj == NULL)
- return -1;
-
- g_return_val_if_fail (E_IS_TEXT (obj), -1);
- etext = E_TEXT (obj);
-
- gtk_object_get (GTK_OBJECT (etext),
- "cursor_pos", &offset,
- NULL);
- return offset;
-}
-
-
-static AtkAttributeSet*
-et_get_run_attributes (AtkText *text,
- gint offset,
- gint *start_offset,
- gint *end_offset)
-{
- /* Unimplemented */
- return NULL;
-}
-
-
-static AtkAttributeSet*
-et_get_default_attributes (AtkText *text)
-{
- /* Unimplemented */
- return NULL;
-}
-
-
-static void
-et_get_character_extents (AtkText *text,
- gint offset,
- gint *x,
- gint *y,
- gint *width,
- gint *height,
- AtkCoordType coords)
-{
- GObject *obj;
- EText *etext;
- GnomeCanvas *canvas;
- gint x_widget, y_widget, x_window, y_window;
- GdkWindow *window;
- GtkWidget *widget;
- PangoRectangle pango_pos;
-
- g_return_if_fail (ATK_IS_GOBJECT_ACCESSIBLE(text));
- obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text));
- if (obj == NULL)
- return;
- g_return_if_fail (E_IS_TEXT (obj));
- etext = E_TEXT(obj);
- canvas = GNOME_CANVAS_ITEM(etext)->canvas;
- widget = GTK_WIDGET(canvas);
- window = widget->window;
- gdk_window_get_origin (window, &x_widget, &y_widget);
-
- pango_layout_index_to_pos (etext->layout, offset, &pango_pos);
- pango_pos.x = PANGO_PIXELS (pango_pos.x);
- pango_pos.y = PANGO_PIXELS (pango_pos.y);
- pango_pos.width = (pango_pos.width + PANGO_SCALE / 2) / PANGO_SCALE;
- pango_pos.height = (pango_pos.height + PANGO_SCALE / 2) / PANGO_SCALE;
-
- *x = pango_pos.x + x_widget;
- *y = pango_pos.y + y_widget;
-
- *width = pango_pos.width;
- *height = pango_pos.height;
-
- if (etext->draw_borders) {
- *x += 3; /*BORDER_INDENT;*/
- *y += 3; /*BORDER_INDENT;*/
- }
-
- *x += etext->xofs;
- *y += etext->yofs;
-
- if (etext->editing) {
- *x -= etext->xofs_edit;
- *y -= etext->yofs_edit;
- }
-
- *x += etext->cx;
- *y += etext->cy;
-
- if (coords == ATK_XY_WINDOW) {
- window = gdk_window_get_toplevel (window);
- gdk_window_get_origin (window, &x_window, &y_window);
- *x -= x_window;
- *y -= y_window;
- }
- else if (coords == ATK_XY_SCREEN) {
- }
- else {
- *x = 0;
- *y = 0;
- *height = 0;
- *width = 0;
- }
-}
-
-
-static gint
-et_get_character_count (AtkText *text)
-{
- const char *full_text = et_get_full_text (text);
-
- return g_utf8_strlen (full_text, -1);
-}
-
-
-static gint
-et_get_offset_at_point (AtkText *text,
- gint x,
- gint y,
- AtkCoordType coords)
-{
- GObject *obj;
- EText *etext;
- GnomeCanvas *canvas;
- gint x_widget, y_widget, x_window, y_window;
- GdkWindow *window;
- GtkWidget *widget;
- int index;
- int trailing;
-
- g_return_val_if_fail (ATK_IS_GOBJECT_ACCESSIBLE(text), -1);
- obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text));
- if (obj == NULL)
- return -1;
- g_return_val_if_fail (E_IS_TEXT (obj), -1);
- etext = E_TEXT(obj);
- canvas = GNOME_CANVAS_ITEM(etext)->canvas;
- widget = GTK_WIDGET(canvas);
- window = widget->window;
- gdk_window_get_origin (window, &x_widget, &y_widget);
-
- if (coords == ATK_XY_SCREEN) {
- x = x - x_widget;
- y = y - y_widget;
- }
- else if (coords == ATK_XY_WINDOW) {
- window = gdk_window_get_toplevel (window);
- gdk_window_get_origin (window, &x_window, &y_window);
- x = x - x_widget + x_window;
- y = y - y_widget + y_window;
- }
- else
- return -1;
-
- if (etext->draw_borders) {
- x -= 3; /*BORDER_INDENT;*/
- y -= 3; /*BORDER_INDENT;*/
- }
-
- x -= etext->xofs;
- y -= etext->yofs;
-
- if (etext->editing) {
- x += etext->xofs_edit;
- y += etext->yofs_edit;
- }
-
- x -= etext->cx;
- y -= etext->cy;
-
- pango_layout_xy_to_index (etext->layout,
- x * PANGO_SCALE - PANGO_SCALE / 2,
- y * PANGO_SCALE - PANGO_SCALE / 2,
- &index,
- &trailing);
-
- return g_utf8_pointer_to_offset (etext->text, etext->text + index + trailing);
-}
-
-
-static gint
-et_get_n_selections (AtkText *text)
-{
- EText *etext = E_TEXT (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text)));
- if (etext->selection_start !=
- etext->selection_end)
- return 1;
- return 0;
-}
-
-
-static gchar*
-et_get_selection (AtkText *text,
- gint selection_num,
- gint *start_offset,
- gint *end_offset)
-{
- gint start, end, real_start, real_end, len;
- EText *etext;
- if (selection_num == 0) {
- const char *full_text = et_get_full_text (text);
- if (full_text == NULL)
- return NULL;
- len = g_utf8_strlen (full_text, -1);
- etext = E_TEXT (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text)));
- start = MIN (etext->selection_start, etext->selection_end);
- end = MAX (etext->selection_start, etext->selection_end);
- start = MIN (MAX (0, start), len);
- end = MIN (MAX (0, end), len);
- if (start != end) {
- if (start_offset)
- *start_offset = start;
- if (end_offset)
- *end_offset = end;
- real_start = g_utf8_offset_to_pointer (full_text, start) - full_text;
- real_end = g_utf8_offset_to_pointer (full_text, end) - full_text;
- return g_strndup (full_text + real_start, real_end - real_start);
- }
- }
-
- return NULL;
-}
-
-
-static gboolean
-et_add_selection (AtkText *text,
- gint start_offset,
- gint end_offset)
-{
- GObject *obj;
- EText *etext;
-
- g_return_val_if_fail (ATK_IS_GOBJECT_ACCESSIBLE (text), FALSE);
- obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text));
- if (obj == NULL)
- return FALSE;
- g_return_val_if_fail (E_IS_TEXT (obj), FALSE);
- etext = E_TEXT (obj);
-
- g_return_val_if_fail (start_offset >= 0, FALSE);
- g_return_val_if_fail (start_offset >= -1, FALSE);
- if (end_offset == -1)
- end_offset = et_get_character_count (text);
-
- if (start_offset != end_offset) {
- gint real_start, real_end;
- real_start = MIN (start_offset, end_offset);
- real_end = MAX (start_offset, end_offset);
- etext->selection_start = real_start;
- etext->selection_end = real_end;
-
- gnome_canvas_item_grab_focus (GNOME_CANVAS_ITEM (etext));
- gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (etext));
-
- g_signal_emit_by_name (ATK_OBJECT (text), "text_selection_changed");
-
- return TRUE;
- }
-
- return FALSE;
-}
-
-
-static gboolean
-et_remove_selection (AtkText *text,
- gint selection_num)
-{
- GObject *obj;
- EText *etext;
-
- g_return_val_if_fail (ATK_IS_GOBJECT_ACCESSIBLE (text), FALSE);
- obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text));
- if (obj == NULL)
- return FALSE;
- g_return_val_if_fail (E_IS_TEXT (obj), FALSE);
- etext = E_TEXT (obj);
-
- if (selection_num == 0
- && etext->selection_start != etext->selection_end) {
- etext->selection_end = etext->selection_start;
- g_signal_emit_by_name (ATK_OBJECT(text), "text_selection_changed");
- return TRUE;
- }
-
- return FALSE;
-}
-
-
-static gboolean
-et_set_selection (AtkText *text,
- gint selection_num,
- gint start_offset,
- gint end_offset)
-{
- GObject *obj;
- EText *etext;
-
- g_return_val_if_fail (ATK_IS_GOBJECT_ACCESSIBLE (text), FALSE);
- obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text));
- if (obj == NULL)
- return FALSE;
- g_return_val_if_fail (E_IS_TEXT (obj), FALSE);
- etext = E_TEXT (obj);
- if (selection_num == 0)
- return et_add_selection (text, start_offset, end_offset);
- return FALSE;
-}
-
-
-static gboolean
-et_set_caret_offset (AtkText *text,
- gint offset)
-{
- GObject *obj;
- EText *etext;
-
- g_return_val_if_fail (ATK_IS_GOBJECT_ACCESSIBLE (text), FALSE);
- obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text));
- if (obj == NULL)
- return FALSE;
-
- g_return_val_if_fail (E_IS_TEXT (obj), FALSE);
- etext = E_TEXT (obj);
-
- if (offset < -1)
- return FALSE;
- else {
- ETextEventProcessorCommand command;
-
- if (offset == -1)
- offset = et_get_character_count (text);
-
- command.action = E_TEP_MOVE;
- command.position = E_TEP_VALUE;
- command.value = offset;
- command.time = GDK_CURRENT_TIME;
- g_signal_emit_by_name (etext->tep, "command", &command);
- return TRUE;
- }
-}
-
-static gboolean
-et_set_run_attributes (AtkEditableText *text,
- AtkAttributeSet *attrib_set,
- gint start_offset,
- gint end_offset)
-{
- /* Unimplemented */
- return FALSE;
-}
-
-static void
-et_set_text_contents (AtkEditableText *text,
- const gchar *string)
-{
- et_set_full_text (text, string);
-}
-
-static void
-et_insert_text (AtkEditableText *text,
- const gchar *string,
- gint length,
- gint *position)
-{
- /* Utf8 unimplemented */
- char *result;
-
- const char *full_text = et_get_full_text (ATK_TEXT (text));
- if (full_text == NULL)
- return;
-
- result = g_strdup_printf ("%.*s%.*s%s", *position, full_text, length, string, full_text + *position);
-
- et_set_full_text (text, result);
-
- *position += length;
-
- g_free (result);
-}
-
-static void
-et_copy_text (AtkEditableText *text,
- gint start_pos,
- gint end_pos)
-{
- GObject *obj;
- EText *etext;
-
- g_return_if_fail (ATK_IS_GOBJECT_ACCESSIBLE (text));
- obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text));
- if (obj == NULL)
- return;
-
- g_return_if_fail (E_IS_TEXT (obj));
- etext = E_TEXT (obj);
-
- if (start_pos != end_pos) {
- etext->selection_start = start_pos;
- etext->selection_end = end_pos;
- e_text_copy_clipboard (etext);
- }
-}
-
-static void
-et_delete_text (AtkEditableText *text,
- gint start_pos,
- gint end_pos)
-{
- GObject *obj;
- EText *etext;
-
- g_return_if_fail (ATK_IS_GOBJECT_ACCESSIBLE(text));
- obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text));
- if (obj == NULL)
- return;
-
- g_return_if_fail (E_IS_TEXT (obj));
- etext = E_TEXT (obj);
-
- etext->selection_start = start_pos;
- etext->selection_end = end_pos;
-
- e_text_delete_selection (etext);
-}
-
-static void
-et_cut_text (AtkEditableText *text,
- gint start_pos,
- gint end_pos)
-{
- et_copy_text (text, start_pos, end_pos);
- et_delete_text (text, start_pos, end_pos);
-}
-
-static void
-et_paste_text (AtkEditableText *text,
- gint position)
-{
- GObject *obj;
- EText *etext;
-
- g_return_if_fail (ATK_IS_GOBJECT_ACCESSIBLE (text));
- obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text));
- if (obj == NULL)
- return;
-
- g_return_if_fail (E_IS_TEXT (obj));
- etext = E_TEXT (obj);
-
- gtk_object_set (GTK_OBJECT (etext),
- "cursor_pos", position,
- NULL);
- e_text_paste_clipboard (etext);
-}
-
-static void
-et_atk_component_iface_init (AtkComponentIface *iface)
-{
- iface->get_extents = et_get_extents;
-}
-
-static void
-et_atk_text_iface_init (AtkTextIface *iface)
-{
- iface->get_text = et_get_text;
- iface->get_text_after_offset = et_get_text_after_offset;
- iface->get_text_at_offset = et_get_text_at_offset;
- iface->get_character_at_offset = et_get_character_at_offset;
- iface->get_text_before_offset = et_get_text_before_offset;
- iface->get_caret_offset = et_get_caret_offset;
- iface->get_run_attributes = et_get_run_attributes;
- iface->get_default_attributes = et_get_default_attributes;
- iface->get_character_extents = et_get_character_extents;
- iface->get_character_count = et_get_character_count;
- iface->get_offset_at_point = et_get_offset_at_point;
- iface->get_n_selections = et_get_n_selections;
- iface->get_selection = et_get_selection;
- iface->add_selection = et_add_selection;
- iface->remove_selection = et_remove_selection;
- iface->set_selection = et_set_selection;
- iface->set_caret_offset = et_set_caret_offset;
-}
-
-static void
-et_atk_editable_text_iface_init (AtkEditableTextIface *iface)
-{
- iface->set_run_attributes = et_set_run_attributes;
- iface->set_text_contents = et_set_text_contents;
- iface->insert_text = et_insert_text;
- iface->copy_text = et_copy_text;
- iface->cut_text = et_cut_text;
- iface->delete_text = et_delete_text;
- iface->paste_text = et_paste_text;
-}
-
-static void
-_et_reposition_cb (ETextModel *model,
- ETextModelReposFn fn,
- gpointer repos_data,
- gpointer user_data)
-{
- AtkObject *accessible;
- AtkText *text;
-
- accessible = ATK_OBJECT (user_data);
- text = ATK_TEXT (accessible);
-
- if (fn == e_repos_delete_shift) {
- EReposDeleteShift *info = (EReposDeleteShift *) repos_data;
- g_signal_emit_by_name (text, "text-changed::delete", info->pos, info->len);
- }
- else if (fn == e_repos_insert_shift) {
- EReposInsertShift *info = (EReposInsertShift *) repos_data;
- g_signal_emit_by_name (text, "text-changed::insert", info->pos, info->len);
- }
-}
-
-static void
-_et_command_cb (ETextEventProcessor *tep,
- ETextEventProcessorCommand *command,
- gpointer user_data)
-{
- AtkObject *accessible;
- AtkText *text;
-
- accessible = ATK_OBJECT (user_data);
- text = ATK_TEXT (accessible);
-
- switch (command->action) {
- case E_TEP_MOVE:
- g_signal_emit_by_name (text, "text-caret-moved", et_get_caret_offset (text));
- break;
- case E_TEP_SELECT:
- g_signal_emit_by_name (text, "text-selection-changed");
- break;
- default:
- break;
- }
-}
-
-static void
-et_real_initialize (AtkObject *obj,
- gpointer data)
-{
- GalA11yEText *a11y;
- EText *etext;
-
- ATK_OBJECT_CLASS (parent_class)->initialize (obj, data);
-
- g_return_if_fail (GAL_A11Y_IS_E_TEXT (obj));
- g_return_if_fail (E_IS_TEXT (data));
-
- a11y = GAL_A11Y_E_TEXT (obj);
- etext = E_TEXT (data);
-
- /* Set up signal callbacks */
- g_signal_connect (etext->model, "reposition",
- G_CALLBACK (_et_reposition_cb), obj);
-
- g_signal_connect_after (etext->tep, "command",
- (GCallback) _et_command_cb, obj);
-
- obj->role = ATK_ROLE_TEXT;
-}
-
-static void
-et_class_init (GalA11yETextClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- AtkObjectClass *atk_class = ATK_OBJECT_CLASS (klass);
-
- quark_accessible_object = g_quark_from_static_string ("gtk-accessible-object");
- parent_class = g_type_class_ref (PARENT_TYPE);
- component_parent_iface = g_type_interface_peek(parent_class, ATK_TYPE_COMPONENT);
- object_class->dispose = et_dispose;
- atk_class->initialize = et_real_initialize;
-}
-
-static void
-et_init (GalA11yEText *a11y)
-{
-#if 0
- GalA11yETextPrivate *priv;
-
- priv = GET_PRIVATE (a11y);
-#endif
-}
-
-/**
- * gal_a11y_e_text_get_type:
- * @void:
- *
- * Registers the &GalA11yEText class if necessary, and returns the type ID
- * associated to it.
- *
- * Return value: The type ID of the &GalA11yEText class.
- **/
-GType
-gal_a11y_e_text_get_type (void)
-{
- static GType type = 0;
-
- if (!type) {
- AtkObjectFactory *factory;
-
- GTypeInfo info = {
- sizeof (GalA11yETextClass),
- (GBaseInitFunc) NULL,
- (GBaseFinalizeFunc) NULL,
- (GClassInitFunc) et_class_init,
- (GClassFinalizeFunc) NULL,
- NULL, /* class_data */
- sizeof (GalA11yEText),
- 0,
- (GInstanceInitFunc) et_init,
- NULL /* value_text */
- };
-
- static const GInterfaceInfo atk_component_info = {
- (GInterfaceInitFunc) et_atk_component_iface_init,
- (GInterfaceFinalizeFunc) NULL,
- NULL
- };
- static const GInterfaceInfo atk_text_info = {
- (GInterfaceInitFunc) et_atk_text_iface_init,
- (GInterfaceFinalizeFunc) NULL,
- NULL
- };
- static const GInterfaceInfo atk_editable_text_info = {
- (GInterfaceInitFunc) et_atk_editable_text_iface_init,
- (GInterfaceFinalizeFunc) NULL,
- NULL
- };
-
- factory = atk_registry_get_factory (atk_get_default_registry (), GNOME_TYPE_CANVAS_ITEM);
- parent_type = atk_object_factory_get_accessible_type (factory);
-
- type = gal_a11y_type_register_static_with_private (PARENT_TYPE, "GalA11yEText", &info, 0,
- sizeof (GalA11yETextPrivate), &priv_offset);
-
- g_type_add_interface_static (type, ATK_TYPE_COMPONENT, &atk_component_info);
- g_type_add_interface_static (type, ATK_TYPE_TEXT, &atk_text_info);
- g_type_add_interface_static (type, ATK_TYPE_EDITABLE_TEXT, &atk_editable_text_info);
- }
-
- return type;
-}
-
-void
-gal_a11y_e_text_init (void)
-{
- if (atk_get_root ())
- atk_registry_set_factory_type (atk_get_default_registry (),
- E_TYPE_TEXT,
- gal_a11y_e_text_factory_get_type ());
-
-}
-
diff --git a/a11y/e-text/gal-a11y-e-text.h b/a11y/e-text/gal-a11y-e-text.h
deleted file mode 100644
index a4b204d296..0000000000
--- a/a11y/e-text/gal-a11y-e-text.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * Authors:
- * Christopher James Lahey <clahey@ximian.com>
- *
- * Copyright (C) 2001 Chris Lahey
- */
-
-#ifndef __GAL_A11Y_E_TEXT_H__
-#define __GAL_A11Y_E_TEXT_H__
-
-#include <glib-object.h>
-#include <gal/e-table/e-table-item.h>
-
-#define GAL_A11Y_TYPE_E_TEXT (gal_a11y_e_text_get_type ())
-#define GAL_A11Y_E_TEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_TEXT, GalA11yEText))
-#define GAL_A11Y_E_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_TEXT, GalA11yETextClass))
-#define GAL_A11Y_IS_E_TEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_TEXT))
-#define GAL_A11Y_IS_E_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_TEXT))
-
-typedef struct _GalA11yEText GalA11yEText;
-typedef struct _GalA11yETextClass GalA11yETextClass;
-typedef struct _GalA11yETextPrivate GalA11yETextPrivate;
-
-/* This struct should actually be larger as this isn't what we derive from.
- * The GalA11yETextPrivate comes right after the parent class structure.
- **/
-struct _GalA11yEText {
- AtkObject object;
-};
-
-struct _GalA11yETextClass {
- AtkObject parent_class;
-};
-
-
-/* Standard Glib function */
-GType gal_a11y_e_text_get_type (void);
-
-void gal_a11y_e_text_init (void);
-
-#endif /* ! __GAL_A11Y_E_TEXT_H__ */
diff --git a/a11y/gal-a11y-factory.h b/a11y/gal-a11y-factory.h
deleted file mode 100644
index 22da85eca8..0000000000
--- a/a11y/gal-a11y-factory.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/* GAL A11Y
- * gal-a11y-factory.h
- *
- * Copyright 2003 Ximian Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- *
- * Authors:
- * Gilbert Fang <gilbert.fang@sun.com>, Sun Microsystem Inc. 2003.
- *
- * This file is mainly from the gailfactory.h of GAIL.
- */
-
-#ifndef _GAL_A11Y_FACTORY_H__
-#define _GAL_A11Y_FACTORY_H__
-
-#include <glib-object.h>
-#include <atk/atkobject.h>
-#include <atk/atkobjectfactory.h>
-
-#define GAL_A11Y_FACTORY(type, type_as_function, opt_create_accessible) \
- \
-static GType \
-type_as_function ## _factory_get_accessible_type (void) \
-{ \
- return type; \
-} \
- \
-static AtkObject* \
-type_as_function ## _factory_create_accessible (GObject *obj) \
-{ \
- GtkWidget *widget; \
- AtkObject *accessible; \
- \
- g_return_val_if_fail (GTK_IS_WIDGET (obj), NULL); \
- \
- widget = GTK_WIDGET (obj); \
- \
- accessible = opt_create_accessible (widget); \
- \
- return accessible; \
-} \
- \
-static void \
-type_as_function ## _factory_class_init (AtkObjectFactoryClass *klass) \
-{ \
- klass->create_accessible = type_as_function ## _factory_create_accessible; \
- klass->get_accessible_type = type_as_function ## _factory_get_accessible_type;\
-} \
- \
-static GType \
-type_as_function ## _factory_get_type (void) \
-{ \
- static GType t = 0; \
- \
- if (!t) \
- { \
- char *name; \
- static const GTypeInfo tinfo = \
- { \
- sizeof (AtkObjectFactoryClass), \
- NULL, NULL, (GClassInitFunc) type_as_function ## _factory_class_init, \
- NULL, NULL, sizeof (AtkObjectFactory), 0, NULL, NULL \
- }; \
- \
- name = g_strconcat (g_type_name (type), "Factory", NULL); \
- t = g_type_register_static ( \
- ATK_TYPE_OBJECT_FACTORY, name, &tinfo, 0); \
- g_free (name); \
- } \
- \
- return t; \
-}
-
-#define GAL_A11Y_WIDGET_SET_FACTORY(widget_type, type_as_function) \
- atk_registry_set_factory_type (atk_get_default_registry (), \
- widget_type, \
- type_as_function ## _factory_get_type ())
-
-#endif /* _GAL_A11Y_FACTORY_H__ */
diff --git a/a11y/gal-a11y-util.c b/a11y/gal-a11y-util.c
deleted file mode 100644
index 0cf7c69dbb..0000000000
--- a/a11y/gal-a11y-util.c
+++ /dev/null
@@ -1,31 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * Authors:
- * Christopher James Lahey <clahey@ximian.com>
- *
- * Copyright (C) 2002 Ximian, Inc.
- */
-
-#include <config.h>
-#include "gal-a11y-util.h"
-
-GType
-gal_a11y_type_register_static_with_private (GType parent_type,
- const gchar *type_name,
- GTypeInfo *info,
- GTypeFlags flags,
- gint priv_size,
- gint *priv_offset)
-{
- GTypeQuery query;
-
- g_type_query (parent_type, &query);
-
- info->class_size = query.class_size;
- info->instance_size = query.instance_size + priv_size;
-
- if (priv_offset)
- *priv_offset = query.instance_size;
-
- return g_type_register_static (parent_type, type_name, info, flags);
-}
diff --git a/a11y/gal-a11y-util.h b/a11y/gal-a11y-util.h
deleted file mode 100644
index b7f742b122..0000000000
--- a/a11y/gal-a11y-util.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * Authors:
- * Christopher James Lahey <clahey@ximian.com>
- *
- * Copyright (C) 2001 Chris Lahey
- */
-
-#ifndef __GAL_A11Y_UTIL_H__
-#define __GAL_A11Y_UTIL_H__
-
-#include <glib-object.h>
-
-GType gal_a11y_type_register_static_with_private (GType parent_type,
- const gchar *type_name,
- GTypeInfo *info,
- GTypeFlags flags,
- int priv_size,
- gint *priv_offset);
-
-#endif /* ! __GAL_A11Y_UTIL_H__ */
diff --git a/addressbook/ChangeLog b/addressbook/ChangeLog
index 030ae85cec..89ba3f8664 100644
--- a/addressbook/ChangeLog
+++ b/addressbook/ChangeLog
@@ -1,50 +1,4 @@
-2005-02-09 Sivaiah Nallagatla <snallagatla@novell.com>
-
- * gui/component/addressbook-config.c
- (eabc_details_limit) : connect to "value_changed"
- signal of spin button instead of "changed"
-
- Fixes #72369
-
-2005-02-09 Hans Petter Jansson <hpj@novell.com>
-
- * gui/contact-editor/Makefile.am:
- * gui/contact-list-editor/Makefile.am:
- * util/Makefile.am: Install shared libraries to privlibdir.
-
-2005-02-08 Christophe Fergeau <teuf@users.sourceforge.net>
-
- * importers/evolution-vcard-importer.c (has_bom)
- (fix_utf16_endianness) (utf16_to_utf8)
- guess_vcard_encoding) : New functions which peeks at
- the conents of the file and guesses the encoding and
- to convert UTF-16 strings to UTF-8.
- (load_file_fn) : check the encoding of the file
- and convert UTF-16 and locale encoding to UTF-8
-
- Fixes #54825
-
-2005-02-07 JP Rosevear <jpr@novell.com>
-
- * gui/component/apps_evolution_addressbook.schemas.in.in: clean up
- descriptions
-
-2005-01-06 Sivaiah Nallagatla <snallagatla@novell.com>
-
- * e-minicard.c (remodel) : changed the loop
- termination check to E_CONACT_LAST_SIMPLE_STRING -1
- so that we will avoid displaying revision field
- value in the minicard
-
-2005-01-04 vivek jain <jvivek@novell.com>
-
- * gui/component/addressbook.c (load_source_auth_cb):
- display a warning dialog if the server version is not proper
-
- * addressbook-errors.xml: added warning message for
- invalid server version
-
-2004-02-02 Hans Petter Jansson <hpj@ximian.com>
+2004-02-03 Hans Petter Jansson <hpj@ximian.com>
* gui/component/addressbook-component.c (ensure_sources): Implement
based on the create_groups () function in addressbook-migrate.c.
@@ -52,56 +6,18 @@
the necessary addressbook source groups if they somehow disappeared
from GConf.
- * gui/component/addressbook-config.c (addressbook_config_edit_source):
+ * gui/component/addressbook-config.c (addressbook_add_server_dialog):
If we can't get any source groups, just issue a console warning and
return NULL. Creating sources without groups is meaningless.
+ (addressbook_config_create_new_source): Return NULL if dialog
+ creation failed.
Work around for #67411
-2005-02-02 Rodney Dawes <dobey@novell.com>
-
- * gui/component/ldap-config.glade: Fix a small spacing issue in the
- Display section's children, to be HIG compliant
-
-2005-01-31 Hans Petter Jansson <hpj@novell.com>
-
- * gui/widgets/eab-config.c (_EABConfigPrivate): Use guint instead of
- ulong for signal ID.
-
-2004-01-29 Parthasarathi Susarla <sparthasarathi@novell.com>
-
- * addressbook/gui/contact-list-editor/e-contact-list-editor.c
- (save_contact) : call the eab_merging_* functions instead of
- e_book_sync* directly. The merging function check for duplication.
- The following functions have been called:
- 1. eab_merging_book_add_contact for adding a new entry
- 2. eab_merging_book_commit_contact for commiting a modified entry
-
- Fixes bug #57819
-
-2005-01-29 Sivaiah Nallagatla <snallagatla@novell.com>
-
- * gui/contact-editor/e-contact-editor.c
- (sensitize_im_types) : new function to sensitize
- im types based on supported fields
-
- (sensitize_im_record) : call sensitize_im_types
- for each record
- (sensitize_im) : if none of the im types
- are supported disable the im entries
- Fixes #68799
-
-2005-01-28 Sivaiah Nallagatla <snallagatla@novell.com>
-
- * gui/widgets/eab-vcard-control.c (pstream_load) :
- Changed a string to make it complete and clear
- for transaltion
- Fixes #61067
-
2005-01-26 Sivaiah Nallagatla <snallagatla@novell.com>
-
- * gui/component/addressbook.c (addressbook_authenticate) :
- Remove leading "%s" from the transalatable string
- Fixes #36137
+
+ * gui/component/addressbook.c (addressbook_authenticate) :
+ Remove leading "%s" from the transalatable string
+ Fixes #36137
2005-01-26 Sivaiah Nallagatla <snallagatla@novell.com>
@@ -116,16 +32,6 @@
Fixes #70339
-2005-01-26 Hao Sheng <hao.sheng@sun.com>
-
- * gui/contact-list-editor/e-contact-list-editor.c:
- (setup_name_selector): add access key to 'Member' Button.
-
-2005-01-25 Rodrigo Moya <rodrigo@novell.com>
-
- * gui/contact-editor/e-contact-editor.c (categories_clicked): use the
- new ECategoriesDialog widget.
-
2005-01-21 JP Rosevear <jpr@novell.com>
Fixes #70622
@@ -133,87 +39,6 @@
* gui/widgets/eab-contact-display.c (eab_contact_display_init):
construct the html widget
-2005-01-21 Sivaiah Nallagatla <snallagatla@novell.com>
-
- * gui/widgets/e-addressbook-model.[ch]
- (eab_model_class_init) : renamed the signal
- CONTACT_REMOVED to CONTACTS_REMOVED and chaned
- the param type POINTER from INT
- (remove_contact) : delete all the contacts
- from the model and emit CONATCTS_REMOVED
- signal instead of emitting it many times
-
- * gui/widgets/e-addressbook-reflow-adpater.c
- (e_addressbook_reflow_adapter_construct)
- (remove_contacts) : renamed remove_contact to remove_contacts
- and when number of conacts is more than 1 use _model_changed
- instead of _remove_item
-
- * gui/widgets/e-addressbook-table-adapter.c
- (eab_table_adapter_construct)
- (remove_contacts) : ditto
-
- * gui/widgets/e-addressbook-view.c
- (eab_view_new) :
- (contacts_removed) : renamed contact_removed
- to contacts_removed and traverese over indices
- to find displayed contact indiex
-
- fixes #71448
-
-2005-01-21 Rodney Dawes <dobey@novell.com>
-
- * gui/contact-editor/e-contact-quick-add.c (build_quick_add_dialog):
- Change the xpad and ypad to 0 here, we don't need the extra padding
- Add the GTK_DIALOG_NO_SEPARATOR flag for creating the dialog
- Set proper border widths on some dialog containers for the HIG
- Set the row/column spacings for the table widget
- Create the labels outside of the table packing calls and set the proper
- alignment for them to be HIG compliant
- Set the border width of the table widget to 12 for HIG compliance
-
- * gui/widgets/eab-popup-control.c (edit_contact_info_cb): Removed
- (eab_popup_control_display_contact): Just go ahead and open the
- editor, no need to have an intermittent window with a button for it
- (add_contacts_cb): Remove this as we don't need it any more
- (eab_popup_control_no_matches): Just go straight to the quick-add
- dialog, and don't pop up an intermittent window with a button
-
- Fixes #41210 #60852
-
-2005-01-21 Rodney Dawes <dobey@novell.com>
-
- * gui/contact-editor/e-contact-editor.c (e_contact_editor_init):
- Call gtk_widget_ensure_style to ensure that we set the border widths
- of some dialog containers properly for HIG compliance
-
-2005-01-21 Rodney Dawes <dobey@novell.com>
-
- * gui/merging/eab-contact-duplicate-detected.glade:
- Fix some spacing and remove the separator for HIG compliance
- * gui/merging/eab-contact-merging.c (match_query_callback):
- Set proper border widths on some dialog containers for the HIG
-
- Fixes #41228
-
-2005-01-21 JP Rosevear <jpr@novell.com>
-
- Fixes #46404
-
- * gui/widgets/e-addressbook-view.c (eab_view_print): just show the
- dialog, not show all (margin settings aren't supposed to be used);
- use e_print to get the dialog
- (eab_view_print_preview): use e_print config for previewing
-
- * printing/e-contact-print.c (e_contact_print_preview): get the
- e_print config for previewing
- (e_contact_print_contact_dialog_new): use e_print to get the
- print dialog
-
- * printing/e-contact-print-envelope.c
- (e_contact_print_envelope_dialog_new): use e_print to get the
- print dialog
-
2005-01-21 Hans Petter Jansson <hpj@novell.com>
* gui/contact-editor/e-contact-quick-add.c (quick_add_set_name)
@@ -222,211 +47,22 @@
passing it on. This way, the FULL_NAME will only be set once, and so
the FILE_AS field will be updated here.
-2005-01-21 Sivaiah Nallagatla <snallagatla@novell.com>
-
- * gui/component/addressbook-config.c
- (eabc_commit) : in case of new book
- set the uid of the source as the relative
- uri.
-
-2005-01-19 Hao Sheng <hao.sheng@sun.com>
-
- * gui/contact-editor/contact-editor.glade:
- add accessable key to the contact editor UI.
- * gui/contact-list-editor/contact-list-editor.glade:
- add accessable key to the contact list editor UI.
-
-2005-01-18 Hao Sheng <hao.sheng@sun.com>
-
- * gui/component/addressbook-view.c:
- (addressbook_view_init): add a11y name for the contact's
- treeview.
-
-2005-01-18 Hao Sheng <hao.sheng@sun.com>
-
- * gui/contact-editor/contact-editor.glade:
- add a11y names for widgets named "Image","Anniversary" and "Birthday".
- * gui/contact-editor/e-contact-editor.c:
- (e_contact_editor_create_date): add string1 as entry's a11y name.
-
-2005-01-17 Sivaiah Nallagatla <snallagatla@novell.com>
-
- * gui/contact-editor/e-contact-editor.c
- (fill_in_email_record) : show "other" when email
- does not carry "TYPE"
- (fill_in_email) : pass deafult email
- types instead of -1 when clearing fields
-
- Fixes #70922
-
-2005-01-17 Hao Sheng <hao.sheng@sun.com>
-
- * gui/contact-editor/contact-editor.glade:
- add the a11y name for arrow-button named "Telephone".
-
-2005-01-12 JP Rosevear <jpr@novell.com>
-
- Fixes #61973
-
- * gui/widgets/e-addressbook-view.etspec: add translator comment for TTYTDD
-
-2005-01-11 Not Zed <NotZed@Ximian.com>
+2005-01-21 Not Zed <NotZed@Ximian.com>
* util/eab-book-util.c (eab_name_and_email_query): cast length
- specifier to int.
+ specifier.
-2005-01-10 Hans Petter Jansson <hpj@novell.com>
-
- * gui/widgets/e-minicard.c (e_minicard_activate_editor): When spawning
- an editor, set the initial editability from the target book, not from
- the minicard's own (usually stale, useless) editable state.
-
-2005-01-06 JP Rosevear <jpr@novell.com>
-
- * gui/component/Makefile.am: install schemas properly
-
-2004-12-21 Andre Klapper <a9016009@gmx.de>
-
- * tools/evolution-addressbook-export.c:
- Fixing bug 61068 (removing a white space in a string).
-
-2004-12-23 Sivaiah Nallagatla <snallagatla@novell.com>
-
- Part of merge from offline branch
-
- * gui/widgets/addresbook-config.c (eabc_general_offline) :
- fix some compile warings
- (offline_status_changed_cb) : set "0" instead of NULL
- as e-source property when offline is not checked
-
-2004-11-23 Sivaiah Nallagatla <snallagatla@novell.com>
-
- Part of merge from offline brnach
-
- * gui/widgets/eab-gui-util.c (eab_load_error_dialog) :
- added message which gets prompted when user tries
- to access a book which is not available in offline mode
+2005-01-17 Sivaiah Nallagatla <snallagatla@novell.com>
- * gui/component/addressbook-config.c (eabc_general_offline)
- (offline_status_changed_cb) : added a new check box
- to properties page to mark a book for offline usage
+ * gui/contact-editor/e-contact-editor.c
+ (fill_in_email_record) : show "other" when email
+ does not carry "TYPE"
+ (fill_in_email) : pass deafult email
+ types instead of -1 when clearing fields
- * gui/component/addressbook.c (load_source_cb) : do no try to
- authenticate in case of offline mode.
- (auth_required_cb) : new call back which gets called
- when backend sends notification for password to client
-
-2004-12-23 Hans Petter Jansson <hpj@novell.com>
-
- This is the last we see of ESelectNames.
-
- * gui/component/select-names/Evolution-Addressbook-SelectNames.idl
- * gui/component/select-names/GNOME_Evolution_Addressbook_SelectNames.server.in.in
- * gui/component/select-names/Makefile.am
- * gui/component/select-names/e-select-names-bonobo.c
- * gui/component/select-names/e-select-names-bonobo.h
- * gui/component/select-names/e-select-names-completion.c
- * gui/component/select-names/e-select-names-completion.h
- * gui/component/select-names/e-select-names-config-keys.h
- * gui/component/select-names/e-select-names-config.c
- * gui/component/select-names/e-select-names-config.h
- * gui/component/select-names/e-select-names-factory.c
- * gui/component/select-names/e-select-names-factory.h
- * gui/component/select-names/e-select-names-manager.c
- * gui/component/select-names/e-select-names-manager.h
- * gui/component/select-names/e-select-names-marshal.list
- * gui/component/select-names/e-select-names-model.c
- * gui/component/select-names/e-select-names-model.h
- * gui/component/select-names/e-select-names-popup.c
- * gui/component/select-names/e-select-names-popup.h
- * gui/component/select-names/e-select-names-section.etspec
- * gui/component/select-names/e-select-names-table-model.c
- * gui/component/select-names/e-select-names-table-model.h
- * gui/component/select-names/e-select-names-text-model.c
- * gui/component/select-names/e-select-names-text-model.h
- * gui/component/select-names/e-select-names.c
- * gui/component/select-names/e-select-names.etspec
- * gui/component/select-names/e-select-names.h
- * gui/component/select-names/recipient.glade
- * gui/component/select-names/select-names.glade: Begone.
-
-2004-12-23 Hans Petter Jansson <hpj@novell.com>
+ Fixes #70922
- * gui/component/Makefile.am (SUBDIRS): No more select-names.
- (libevolution_addressbook_la_LIBADD): Remove libeselectnames.la.
-
- * gui/component/component-factory.c (factory): Remove the select-names
- component.
-
- * gui/contact-list-editor/Makefile.am (IDL)
- (IDL_GENERATED_H)
- (selectnamesdir): No longer needed, so removed.
-
-2004-12-22 Hans Petter Jansson <hpj@novell.com>
-
- * gui/contact-list-editor/e-contact-list-editor.c
- (e_contact_list_editor_dispose): Unref the name selector.
- (e_contact_list_editor_save_contact): Fix a warning.
- (add_to_model): Take a list instead of a vector of destinations.
- (select_names_ok_cb): Adapt to new name selector.
- (setup_corba): Renamed to setup_name_selector () and adapted.
- (select_cb): Adapt to new name selector.
-
- * gui/contact-list-editor/e-contact-list-editor.h: Adapt to new
- name selector and remove CORBA/Bonobo.
-
- * gui/widgets/eab-popup.c (eabp_target_free)
- (eabp_popup_target_new_select_names): #ifdef out code that
- depended on the old name selector.
-
-2004-12-17 Not Zed <NotZed@Ximian.com>
-
- * util/ea-popup.c (emp_standard_menu_factory):
-
- * gui/component/select-names/e-select-names.c (section_right_click_cb):
-
- * gui/component/addressbook-view.c (popup_event_callback):
-
- * gui/widgets/e-addressbook-view.c (do_popup_menu): api changes.
-
-2004-12-21 JP Rosevear <jpr@novell.com>
-
- Fixes #61975
-
- * gui/widgets/test-reflow.c: kill translated strings that were #if
- 0'd anyhow
-
-2004-12-21 JP Rosevear <jpr@novell.com>
-
- * gui/search/e-addressbook-search-dialog.c: convert to
- G_DEFINE_TYPE
-
- * gui/widgets/gal-view-factory-minicard.c: ditto
-
- * gui/widgets/gal-view-factory-treeview.c: ditto
-
-2004-12-13 Vivek Jain <jvivek@novell.com>
-
- * gui/component/addressbook-config.c (addressbook_config_edit_source): set the
- window title based upon the source
-
-2004-12-08 Hans Petter Jansson <hpj@novell.com>
-
- * gui/component/addressbook-migrate.c
- * gui/component/select-names/e-select-names-completion.c
- * gui/component/select-names/e-select-names-manager.c
- * gui/component/select-names/e-select-names-model.h
- * gui/contact-list-editor/e-contact-list-editor.h
- * gui/contact-list-editor/e-contact-list-model.h
- * gui/widgets/e-minicard.c
- * gui/widgets/eab-gui-util.c
- * importers/evolution-ldif-importer.c
- * importers/evolution-vcard-importer.c: Include
- <libebook/e-destination.h> from evolution-data-server.
- * util/Makefile.am: Remove e-destination.[ch] from here.
- * util/e-destination.[ch]: Removed.
-
-2004-12-08 S. Caglar Onur <caglar@uludag.org.tr>
+2004-11-28 S.Çaglar Onur <caglar@uludag.org.tr>
* evolution-2.0.2/addressbook/gui/contact-editor/e-contact-editor.c
(get_ui_slot_param)
@@ -434,145 +70,21 @@
g_ascii_strcasecmp() for Turkish character conversiton problems
[ http://www.i18nguy.com/unicode/turkish-i18n.html ]
-2004-12-06 Not Zed <NotZed@Ximian.com>
-
- * gui/component/addressbook-config.c (eabc_general_type): set the
- active item based on the current group.
-
-2004-12-01 Sivaiah Nallagatla <snallagatla@novell.com>
-
- * gui/contact-editor/e-contact-editor.c (save_contact) :
- save the uid and set it again in the contact. Otherwise, there is
- possibility we trying to save the contact wiht out UID, as we destory the
- contact and create new one when data is wrong
-
-
-2004-11-28 Sivaiah Nallagatla <snallagatla@novell.com>
-
- * gui/contact-editor/e-contact-editor.h : Define
- new list for storing required fields
-
- * gui/contact-editor/e-contact-editor.c
- (e_contact_editor_class_init) : install new REQUIRED_FIELDS
- property
- (e_contact_editor_set_property)
- (e_contact_editor_get_property) : added handling
- for new RQUIRED_FIELDS_PROPERTY
- (e_contact_editor_dispose) : unref the new
- required_fields member
- (required_fields_cb) : call back to set required fields into
- contact editor
- (is_non_string_field) : new method to detect
- whether a particular field in contact is a string or not
- (e_contact_editor_is_valid) : check for presence of
- all required fields
- (save_contact) : extract all the data before
- calling e_contact_editor_is_valid so that
- it can check for required fields. Clean up the contact
- if there is an error
-
-2004-11-27 Sushma Rai <rsushma@novell.com>
-
- * gui/widgets/e-minicard-view.c (set_empty_message):
- Checking for the static capability "do-initial-query",
- and setting the relevent empty addressbook message.
-
-2004-11-26 JP Rosevear <jpr@novell.com>
-
- * gui/component/select-names/e-select-names-popup.c
- (populate_popup_contact): get image directly from icon factory
-
- * gui/contact-editor/e-contact-editor-im.c
- (setup_service_optmenu): ditto
-
-2004-11-25 Hao Sheng <hao.sheng@sun.com>
-
- * gui/contact-editor/contact-editor.glade:
- add "labelled by" between entry and label,
- make accessbility work.
- * gui/contact-editor/e-contact-editor.c:
- (e_contact_editor_create_web): add accessible name to e_url_entry.
-
-2004-11-22 Joan Sanfeliu <joan@fibranet.com>
-
- * gui/component/apps_evolution_addressbook.schemas.in.in:
- * gui/component/ldap-config.glade : Evolution product name spelled
- with an uppercase E
-
- Fixes #61065
-
-2004-11-22 Rodney Dawes <dobey@novell.com>
-
- * importers/GNOME_Evolution_Addressbook_VCard_Importer.server.in.in:
- Fix name attribute values to be identical
-
- Fixes #61976
-
-2004-11-21 Sivaiah Nallagatla <snallagatla@novell.com>
-
- * rever last commit , it is supposed to for offline
- branch not to HEAD
-
-2004-11-21 Sivaiah Nallagatla <snallagatla@novell.com>
-
- * gui/widgets/eab-gui-util.c (eab_load_error_dialog) :
- added message which gets prompted when user tries
- to access a book which is not available in offline mode
-
- * gui/component/addressbook-config.c (eabc_general_offline)
- (offline_status_changed_cb) : added a new check box
- to properties page to mark a book for offline usage
-
- * gui/component/addressbook.c (load_source_cb) : do no try to
- authenticate in case of offline mode.
- (auth_required_cb) : new call back which gets called
- when backend sends notification for password to client
-
2004-11-07 Sivaiah Nallagatla <snallagatla@novell.com>
-
+
* util/eab-book-util.c (eab_name_and_email_query) :
When name is NULL query against complete email id instead of
user name part to take care of users@foo.org not matching
against users@bar.org . Also include query based on name always
-
+
Fix for #67656
-
-2004-11-16 Not Zed <NotZed@Ximian.com>
-
- * util/Makefile.am (libeabutil_la_LIBADD): remove camel, add
- ADDRESSBOOK_LIBS.
-
- * conduit/Makefile.am (libeaddress_conduit_la_LIBADD): remove
- camel.
-
- * gui/component/Makefile.am (libevolution_addressbook_la_LIBADD):
- remove camel.
-
-2004-11-15 Not Zed <NotZed@Ximian.com>
-
- * *.c: Moved various things from e-util to libedataserver, where
- appropriate.
-
-2004-11-08 Andre Klapper <a901600@gmx.de>
-
- Fixes bug #61966.
-
- * addressbook-errors.xml: Add a missing word to a string.
-
-2004-11-08 Steven Zhang <steven.zhang@sun.com>
-
- * gui/widgets/e-minicard.c: (e_minicard_activate_editor):
- rename and make it a public function.
- (e_minicard_event): change accordingly.
- * gui/widgets/e-minicard.h: ditto.
-
2004-11-04 Sivaiah Nallagatla <snallagatla@novell.com>
-
- * gui/contact-editor/e-contact-editor.c (save_contact) :
- populate contact only afte we are sure that data is valid
- and we can create that.
- Fixes #69079
+
+ * gui/contact-editor/e-contact-editor.c (save_contact) :
+ populate contact only afte we are sure that data is valid
+ and we can create that.
+ Fixes #69079
2004-11-07 Rodney Dawes <dobey@novell.com>
@@ -583,131 +95,6 @@
Partially fixes bug #66854
-2004-11-04 mengjie yu <meng-jie.yu@sun.com>
-
- fix for bugzilla #44876
-
- * gui/component/select-names/e-select-names-manager.c:
- (e_select_names_manager_entry_new):add a atk name for the entry.
-
-2004-11-2 Hao Sheng <hao.sheng@sun.com>
-
- * gui/widgets/e-minicard-view.c: popup right-click menu after
- pressing Shift+F10.
-
-2004-11-01 Sivaiah Nallagatla <snallagatla@novell.com>
-
- * gui/widgets/eab-gui-util.c
- (added_cb) (_modified_cb) : Don't show
- error dialogs when status code is E_BOOK_ERROR_CANCELLED. We don't
- wabt to show "Error adding contact, Cancelled" dialogs when user
- cancels duplicated contact detected dialog.
-
-2004-10-27 Andre Klapper <a9016009@gmx.de>
-
- * tools/evolution-addressbook-export.c:
- Fixing a typo (bug 61069).
-
-2004-10-26 Andre Klapper <a9016009@gmx.de>
-
- Fixes #61972.
-
- * addressbook/gui/contact-editor/e-contact-editor-address.c:
- Typo in country name: was "Grena-dines", now "Grenadines".
-
-2004-10-25 Nat Friedman <nat@novell.com>
-
- * gui/widgets/eab-contact-display.c (accum_multival_attribute):
- Display mutlivalued contact attributes in the preview.
- (render_contact): Render all IM fields using the new multival
- function.
-
-2004-10-21 JP Rosevear <jpr@novell.com>
-
- * gui/widgets/eab-config.c (ecph_class_init): correct hook name
- typo
-
- * gui/component/addressbook-view.c: add appropriate popup icons
-
-2004-10-21 Not Zed <NotZed@Ximian.com>
-
- * gui/component/addressbook-config.c
- (addressbook_config_edit_source): fix a past-o for no-ldap case.
-
-2004-10-20 Not Zed <NotZed@Ximian.com>
-
- * gui/component/addressbook-component.c
- (addressbook_component_init): register config hook.
-
- * gui/component/addressbook-config.c: mostly re-written to use econfig.
- (query_for_supported_bases): convert to gtktreeview.
-
- * gui/widgets/eab-config.c (ecp_set_target): hook onto source changed.
- (ecp_source_changed): propagate changed state info.
- (ecp_class_init): setup private data.
-
-2004-10-19 Not Zed <NotZed@Ximian.com>
-
- * gui/widgets/eab-menu.c (eabm_target_free): don't unref null
- book.
-
-2004-10-19 JP Rosevear <jpr@novell.com>
-
- * gui/component/addressbook-view.c,
- gui/component/select-names/e-select-names.c,
- gui/widgets/e-addressbook-view.c, gui/widgets/eab-menu.c,
- gui/widgets/eab-popup.c: convert to org.gnome hook names
-
-2004-10-15 Sivaiah Nallagatla <snallagatla@novell.com>
-
- * gui/widgets/e-addressbook-view.c : add EAB_POPUP_SELECT_ANY
- mask instead of EAB_POPUP_SELECT_MANY, so that
- all the options like Save as, Forward etc are enabled even
- single contact is selected.
-
-2004-10-15 Sivaiah Nallagatla <snallagatla@novell.com>
-
- * gui/widgets/eab-contact-display.c : uncomment
- HANDLE_MAILTO_INTERNALLY define so that we will
- launch composer through bonobo instead of using
- gnome_url_show
-
-2004-10-15 Not Zed <NotZed@Ximian.com>
-
- * gui/widgets/eab-popup.c: added an any select mask and updated
- the hook maps.
-
- * gui/component/addressbook-component.c
- (addressbook_component_init): register the addressbook hooks.
-
- * gui/component/addressbook-view.c (addressbook_view_init): setup
- the menu manager.
- (control_activate_cb): activate the menu manager.
- (update_command_state): and update the menu manager.
-
- * gui/widgets/eab-menu.[ch]: Added menu manager class.
-
-2004-10-13 JP Rosevear <jpr@novell.com>
-
- * importers/evolution-vcard-importer.c: find source selector and
- option menu in libedataserverui
-
- * importers/evolution-ldif-importer.c: ditto
-
- * gui/widgets/eab-popup.c: ditto
-
- * gui/widgets/eab-gui-util.c: ditto
-
- * gui/contact-list-editor/e-contact-list-editor.c: ditto
-
- * gui/contact-editor/e-contact-editor.c: ditto
-
- * gui/component/select-names/e-select-names.h: ditto
-
- * gui/component/autocompletion-config.c: ditto
-
- * gui/component/addressbook-view.c: ditto
-
2004-10-11 Hans Petter Jansson <hpj@ximian.com>
* gui/component/addressbook-view.c (source_list_changed_cb): Don't
@@ -716,67 +103,12 @@
(addressbook_view_init): Unref views when removed from the hash
table.
-2004-10-06 Not Zed <NotZed@Ximian.com>
-
- * gui/component/addressbook-view.c (popup_event_callback):
- * gui/component/select-names/e-select-names.c (section_right_click_cb):
- * gui/widgets/e-addressbook-view.c (do_popup_menu): fix for
- e-popup api changes. Moved all mask specifiers to visible rather
- than enable in the menu table.
-
-2004-10-06 Not Zed <NotZed@Ximian.com>
+2004-10-01 William Jon McCann <mccann@jhu.edu>
- * gui/contact-editor/e-contact-editor.c: removed
- gnome-popup-menu.h (unused).
-
- * gui/widgets/e-addressbook-reflow-adapter.c:
- * gui/widgets/eab-popup-control.c: remove e-popup-menu.h (unused).
+ * gui/component/component-factory.c (factory): Quiet debug messages.
- * gui/component/select-names/e-select-names.c
- (section_right_click_cb): use e-popup. Somewhat overengineered
- for this use ...
- (remove_cb): api changes.
-
- * gui/widgets/eab-popup.c (eab_popup_target_new_select_names):
- added pretty useless wrapper for the select names popup. Added to
- hook maps.
-
-2004-10-01 Not Zed <NotZed@Ximian.com>
-
- * gui/widgets/e-addressbook-view.c (do_popup_menu): convert to
- using EABPopup.
- (sources): remove dead code.
- (has_email_address_1, get_has_email_address): removed now
- redundant code.
- (save_as, send_as, send_to, print, copy, paste, cut, delete)
- (copy_to_folder, move_to_folder, new_card, new_list): new api.
- (free_popup_info): dead.
- (print_envelope): not pining.
- (get_contact_list): take a popup target instead, don't ref.
- (get_contact_list_1): not required no more.
- (contact_and_book_free): same.
- (delete): call eab_view_delete_selection.
- (eab_view_delete_selection): do the actual delete here.
-
- * gui/widgets/eab-popup.c (eab_popup_target_new_select): implement.
-
-2004-10-01 Not Zed <NotZed@Ximian.com>
-
- * gui/widgets/eab-popup.[ch]: addressbook popup driver.
-
- * gui/component/addressbook-view.c (delete_addressbook_cb): use
- e-error for the message prompt. don't bother keeping it around,
- it can never be re-sensitised anyway.
- (book_removed): no longer destroy the original dialogue.
-
- * addressbook-errors.xml: add ask-delete for deleting
- addressbooks.
-
- * gui/component/addressbook-view.c (addressbook_view_init):
- connect to popup_event rather than fill_popup_menu now.
- (fill_popup_menu_callback): renamed to popup_event_callback,
- changed to use epopup.
- (add_popup_menu_item): remove, no longer needed.
+ * gui/component/apps_evolution_addressbook.schemas.in.in: Add
+ missing show_preview schema. Add missing long descriptions.
2004-09-29 Not Zed <NotZed@Ximian.com>
@@ -800,52 +132,45 @@
* gui/merging/eab-contact-compare.c (query_cb): Protect against NULL
UIDs, and make fewer calls to e_contact_get_const () as a bonus.
-2004-09-24 Hao Sheng <hao.sheng@sun.com>
-
- Fix for #66523
+2004-09-23 Fazlu & Hannah <hannah_lins@yahoo.co.in>
- * gui/contact-list-editor/e-contact-list-model.c:
- (e_contact_list_model_add_email): estimate the same mail address
- and popup a warning dialog.
- * addressbook-errors.xml: add the question message for the warning
- dialog.
+ Fixes bug #61070
-2004-09-23 Pamplona Hackers <gnome-desarrollo@es.gnome.org>
+ * addressbook/tools/evolution-addressbook-export.c (main):
+ Changed the string into proper grammar 'In normal mode,
+ there should not need size option.' to 'In normal mode, there
+ is no need for the size option.'
- Fixes #61978
+2004-09-23 JP Rosevear <jpr@novell.com>
- * tools/evolution-addressbook-export.c (main): use more
- meaningful error message.
+ * conduit/address-conduit.c (ecard_from_remote_record): only set
+ the file as address to the company if no full name exists
+ (delete_record): don't bail out if the record simply isn't found
-2004-09-23 Fazlu & Hannah <hannah_lins@yahoo.co.in>
+ Fixes #59725
+
+ * conduit/address-conduit.c (local_record_from_uid): remove
+ extraneous semicolon
- * tools/evolution-addressbook-export.c (main):
- Changed the string into proper grammar 'In normal mode, there
- should not need size option.' to 'In normal mode, there is no need
- for the size option.'
+2004-09-13 Rodney Dawes <dobey@novell.com>
-2004-09-23 JP Rosevear <jpr@novell.com>
-
- * conduit/address-conduit.c (ecard_from_remote_record): only set
- the file as address to the company if no full name exists
- (delete_record): don't bail out if the record simply isn't found
-
- Fixes #59725
-
- * conduit/address-conduit.c (local_record_from_uid): remove
- extraneous semicolon
-
-2004-09-21 William Jon McCann <mccann@jhu.edu>
+ * gui/contact-editor/e-contact-editor.c (show_help_cb):
+ Point at the correct XML file for documentation
- * gui/component/component-factory.c (factory): Quiet debug messages.
+2004-09-09 Sivaiah Nallagatla <snallagatla@novell.com>
- * gui/widgets/e-addressbook-view.c (eab_view_new): Remove
- unnecessary label widget placeholder. Make vertical scrollbar
- policy automatic. Use gtk_paned_add2 instead of
- gtk_container_add.
+ Part of fix for #59582.
- * gui/component/apps_evolution_addressbook.schemas.in.in: Add
- missing show_preview schema. Add missing long descriptions.
+ * gui/contact-editor/e-contact-editor.c
+ (sensitize_address): check for _LABEL type address fields also in
+ supported fileds while sensitizing the address fields.
+
+2004-09-08 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #64080.
+
+ * gui/component/Makefile.am (libevolution_addressbook_la_LIBADD):
+ link addressbook to camel.
2004-09-13 Rodney Dawes <dobey@novell.com>
@@ -1263,11 +588,6 @@
Don't set empty default value on an int, this causes gconf warning.
(bug #60859)
-2004-09-04 Not Zed <NotZed@Ximian.com>
-
- * util/e-destination.c: include gnome-i18n.h since camel-object no
- longer does(!).
-
2004-07-02 Hans Petter Jansson <hpj@ximian.com>
* gui/contact-list-editor/e-contact-list-editor.c
@@ -3320,7 +2640,7 @@
* gui/contact-editor/Makefile.am (libecontacteditor_la_SOURCES):
add eab-editor.[ch]
-2004-03-24 Danilo Segan <dsegan@gmx.net>
+2004-03-24 Danilo Å egan <dsegan@gmx.net>
* gui/widgets/e-addressbook-model.c (update_folder_bar_message):
Use ngettext for handling plural forms (fixes bug #53464).
diff --git a/addressbook/gui/component/Makefile.am b/addressbook/gui/component/Makefile.am
index a2798ec665..adf772206c 100644
--- a/addressbook/gui/component/Makefile.am
+++ b/addressbook/gui/component/Makefile.am
@@ -1,3 +1,5 @@
+SUBDIRS = select-names
+
INCLUDES = \
-DG_LOG_DOMAIN=\"evolution-addressbook\" \
-I$(top_srcdir) \
@@ -46,6 +48,7 @@ endif
libevolution_addressbook_la_LIBADD = \
$(SMIME_LIB) \
$(top_builddir)/addressbook/printing/libecontactprint.la \
+ $(top_builddir)/addressbook/gui/component/select-names/libeselectnames.la \
$(top_builddir)/shell/libeshell.la \
$(top_builddir)/addressbook/gui/merging/libeabbookmerging.la \
$(top_builddir)/addressbook/gui/widgets/libeabwidgets.la \
@@ -57,6 +60,7 @@ libevolution_addressbook_la_LIBADD = \
$(top_builddir)/widgets/misc/libemiscwidgets.la \
$(top_builddir)/widgets/menus/libmenus.la \
$(top_builddir)/a11y/addressbook/libevolution-addressbook-a11y.la \
+ $(top_builddir)/camel/libcamel.la \
$(EVOLUTION_ADDRESSBOOK_LIBS) $(LDAP_LIBS)
@@ -76,7 +80,7 @@ schema_DATA = $(schema_in_files:.schemas.in.in=-$(BASE_VERSION).schemas)
install-data-local:
if test -z "$(DESTDIR)" ; then \
for p in $(schema_DATA) ; do \
- GCONF_CONFIG_SOURCE=$(GCONF_SCHEMA_CONFIG_SOURCE) $(GCONFTOOL) --makefile-install-rule $$p; \
+ GCONF_CONFIG_SOURCE=$(GCONF_SCHEMA_CONFIG_SOURCE) $(GCONFTOOL) --makefile-install-rule $(srcdir)/$$p; \
done \
fi
diff --git a/addressbook/gui/component/addressbook-component.c b/addressbook/gui/component/addressbook-component.c
index a0c3c58c04..a82e6db02f 100644
--- a/addressbook/gui/component/addressbook-component.c
+++ b/addressbook/gui/component/addressbook-component.c
@@ -31,10 +31,6 @@
#include "addressbook-view.h"
#include "addressbook/gui/contact-editor/eab-editor.h"
#include "addressbook/gui/widgets/eab-gui-util.h"
-#include "e-util/e-plugin.h"
-#include "addressbook/gui/widgets/eab-popup.h"
-#include "addressbook/gui/widgets/eab-menu.h"
-#include "addressbook/gui/widgets/eab-config.h"
#include "widgets/misc/e-task-bar.h"
#include "widgets/misc/e-info-label.h"
@@ -335,7 +331,6 @@ static void
addressbook_component_init (AddressbookComponent *component)
{
AddressbookComponentPrivate *priv;
- static int first = TRUE;
priv = g_new0 (AddressbookComponentPrivate, 1);
@@ -351,13 +346,6 @@ addressbook_component_init (AddressbookComponent *component)
#ifdef ENABLE_SMIME
smime_component_init ();
#endif
-
- if (first) {
- first = FALSE;
- e_plugin_hook_register_type(eab_popup_hook_get_type());
- e_plugin_hook_register_type(eab_menu_hook_get_type());
- e_plugin_hook_register_type(eab_config_hook_get_type());
- }
}
diff --git a/addressbook/gui/component/addressbook-config.c b/addressbook/gui/component/addressbook-config.c
index be06893c49..e29d58b245 100644
--- a/addressbook/gui/component/addressbook-config.c
+++ b/addressbook/gui/component/addressbook-config.c
@@ -3,8 +3,6 @@
* Authors:
* Chris Toshok <toshok@ximian.com>
* Chris Lahey <clahey@ximian.com>
- * Michael Zucchi <notzed@ximian.com>
- * And no doubt others ...
**/
/*#define STANDALONE*/
@@ -18,19 +16,10 @@
#include <gtk/gtkcombo.h>
#include <gtk/gtkdialog.h>
#include <gtk/gtkentry.h>
-#include <gtk/gtkrange.h>
-#include <gtk/gtktreeview.h>
-#include <gtk/gtkliststore.h>
-#include <gtk/gtkscrolledwindow.h>
-#include <gtk/gtktreeselection.h>
-#include <gtk/gtkcellrenderertext.h>
-#include <gtk/gtkcombobox.h>
-#include <gtk/gtkoptionmenu.h>
-#include <gtk/gtkspinbutton.h>
-#include <gtk/gtkcelllayout.h>
-#include <gtk/gtklabel.h>
-#include <gtk/gtk.h>
+#include <gtk/gtkmessagedialog.h>
#include <libgnome/gnome-i18n.h>
+#include <libgnomeui/gnome-druid.h>
+#include <libgnomeui/gnome-druid-page.h>
#include <bonobo/bonobo-generic-factory.h>
@@ -44,9 +33,9 @@
#include "evolution-config-control.h"
-#include "addressbook/gui/widgets/eab-config.h"
+#include <gal/e-table/e-table-memory-store.h>
+#include <gal/e-table/e-table-scrolled.h>
-#define d(x)
#ifdef HAVE_LDAP
#include "ldap.h"
@@ -72,48 +61,69 @@ GtkWidget* supported_bases_create_table (char *name, char *string1, char *string
#define CALENTRY "calEntry"
+typedef struct {
+ GtkWidget *notebook;
+ int page_num;
+} FocusHelpClosure;
+
typedef struct _AddressbookSourceDialog AddressbookSourceDialog;
+typedef void (*ModifyFunc)(GtkWidget *item, AddressbookSourceDialog *dialog);
struct _AddressbookSourceDialog {
GladeXML *gui;
- EABConfig *config; /* the config manager */
-
GtkWidget *window;
+ GtkWidget *druid; /* only used (obviously) in the druid */
/* Source selection (druid only) */
ESourceList *source_list;
GSList *menu_source_groups;
GtkWidget *group_optionmenu;
- /* ESource we're currently editing */
+ /* ESource we're currently editing (editor only) */
ESource *source;
- /* The original source in edit mode. Also used to flag when we are in edit mode. */
- ESource *original_source;
/* Source group we're creating/editing a source in */
ESourceGroup *source_group;
/* info page fields */
+ ModifyFunc general_modify_func;
GtkWidget *host;
GtkWidget *auth_optionmenu;
AddressbookLDAPAuthType auth;
GtkWidget *auth_principal;
/* connecting page fields */
+ ModifyFunc connecting_modify_func;
GtkWidget *port_combo;
GtkWidget *ssl_optionmenu;
AddressbookLDAPSSLType ssl;
/* searching page fields */
+ ModifyFunc searching_modify_func;
GtkWidget *rootdn;
AddressbookLDAPScopeType scope;
GtkWidget *scope_optionmenu;
GtkWidget *timeout_scale;
GtkWidget *limit_spinbutton;
+ /* new dialog stuff */
+ GtkWidget *auth_frame;
+ GtkWidget *server_frame;
+
/* display name page fields */
GtkWidget *display_name;
+ gboolean display_name_changed; /* only used in the druid */
+
+ gboolean schema_query_successful;
+
+ /* stuff for the account editor window */
+ GtkWidget *ok_button;
+ GtkWidget *cancel_button;
+ GtkWidget *advanced_button_notebook;
+ GtkWidget *notebook; /* the toplevel notebook */
+
+ gboolean advanced;
};
@@ -196,8 +206,98 @@ ldap_parse_ssl (const char *ssl)
return ADDRESSBOOK_LDAP_SSL_WHENEVER_POSSIBLE;
}
+#endif
+
+
+
+static void
+dialog_to_source (AddressbookSourceDialog *dialog, ESource *source, gboolean temporary)
+{
+ gchar *str;
+
+ g_assert (source);
+
+ e_source_set_name (source, gtk_entry_get_text (GTK_ENTRY (dialog->display_name)));
+
+ if (!strcmp ("ldap://", e_source_group_peek_base_uri (dialog->source_group))) {
+#ifdef HAVE_LDAP
+ if (dialog->auth != ADDRESSBOOK_LDAP_AUTH_NONE)
+ e_source_set_property (source,
+ dialog->auth == ADDRESSBOOK_LDAP_AUTH_SIMPLE_EMAIL ? "email_addr" : "binddn",
+ gtk_entry_get_text (GTK_ENTRY (dialog->auth_principal)));
+ str = g_strdup_printf ("%d", gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (dialog->limit_spinbutton)));
+ e_source_set_property (source, "limit", str);
+ g_free (str);
+
+ str = g_strdup_printf ("%f", gtk_adjustment_get_value (GTK_RANGE(dialog->timeout_scale)->adjustment));
+ e_source_set_property (source, "timeout", str);
+ g_free (str);
+
+ e_source_set_property (source, "ssl", ldap_unparse_ssl (dialog->ssl));
+ e_source_set_property (source, "auth", ldap_unparse_auth (dialog->auth));
+ str = g_strdup_printf ("%s:%s/%s?" /* trigraph prevention */ "?%s",
+ gtk_entry_get_text (GTK_ENTRY (dialog->host)),
+ gtk_entry_get_text (GTK_ENTRY (GTK_COMBO (dialog->port_combo)->entry)),
+ gtk_entry_get_text (GTK_ENTRY (dialog->rootdn)),
+ ldap_unparse_scope (dialog->scope));
+ e_source_set_relative_uri (source, str);
+ g_free (str);
+#endif
+ }else if (g_str_has_prefix (e_source_group_peek_base_uri (dialog->source_group), "groupwise://") &&
+ !e_source_peek_group (source)) { /* if this is an existing book we don't change anything else */
+
+ GSList *groupwise_source_list;
+ ESource *existing_source = NULL;
+ const char *property_value = NULL;
+
+ groupwise_source_list = e_source_group_peek_sources(dialog->source_group);
+ if (groupwise_source_list)
+ existing_source = E_SOURCE (groupwise_source_list->data);
+ if (existing_source) {
+ property_value = e_source_get_property (existing_source, "auth");
+ e_source_set_property (source, "auth", property_value);
+ property_value = e_source_get_property (existing_source, "user");
+ e_source_set_property (source, "user", property_value);
+ property_value = e_source_get_property (existing_source, "use_ssl");
+ e_source_set_property (source, "use_ssl", property_value);
+ }
+ e_source_set_property (source, "auth-domain", "Groupwise");
+ str = g_strconcat (";", gtk_entry_get_text (GTK_ENTRY (dialog->display_name)), NULL);
+ e_source_set_relative_uri (source, str);
+ g_free (str);
+
+ } else {
+ const gchar *relative_uri;
+
+ relative_uri = e_source_peek_relative_uri (source);
+ if (!relative_uri || !strlen (relative_uri))
+ e_source_set_relative_uri (source, e_source_peek_uid (source));
+ }
+
+ if (!temporary) {
+ if (!e_source_peek_group (source))
+ e_source_group_add_source (dialog->source_group, source, -1);
+
+ e_source_list_sync (dialog->source_list, NULL);
+ }
+}
+
+static ESource *
+dialog_to_temp_source (AddressbookSourceDialog *dialog)
+{
+ ESource *source;
+
+ source = e_source_new ("", "");
+ e_source_set_group (source, dialog->source_group);
+ dialog_to_source (dialog, source, TRUE);
+
+ return source;
+}
+
+#ifdef HAVE_LDAP
static gboolean
-source_to_uri_parts (ESource *source, gchar **host, gchar **rootdn, AddressbookLDAPScopeType *scope, gint *port)
+source_to_uri_parts (ESource *source, gchar **host, gchar **rootdn,
+ AddressbookLDAPScopeType *scope, gint *port)
{
gchar *uri;
LDAPURLDesc *lud;
@@ -227,13 +327,71 @@ source_to_uri_parts (ESource *source, gchar **host, gchar **rootdn, AddressbookL
ldap_free_urldesc (lud);
return TRUE;
}
+#endif
-static gboolean
-source_group_is_remote (ESourceGroup *group)
+#define SOURCE_PROP_STRING(source, prop) \
+ (source && e_source_get_property (source, prop) ? e_source_get_property (source, prop) : "")
+
+static void
+source_to_dialog (AddressbookSourceDialog *dialog)
{
- return strncmp ("ldap:", e_source_group_peek_base_uri (group), 5) == 0;
+ ESource *source = dialog->source;
+ const char *base_uri;
+
+ gtk_entry_set_text (GTK_ENTRY (dialog->display_name), source ? e_source_peek_name (source) : "");
+ base_uri = e_source_group_peek_base_uri (dialog->source_group);
+ if (source && base_uri && g_str_has_prefix (base_uri, "groupwise://"))
+ gtk_widget_set_sensitive (GTK_WIDGET(dialog->display_name), FALSE);
+
+#ifdef HAVE_LDAP
+ gtk_spin_button_set_value ( GTK_SPIN_BUTTON (dialog->limit_spinbutton),
+ g_strtod ( source && e_source_get_property (source, "limit") ?
+ e_source_get_property (source, "limit") : "100", NULL));
+ gtk_adjustment_set_value (GTK_RANGE(dialog->timeout_scale)->adjustment,
+ g_strtod ( source && e_source_get_property (source, "timeout") ?
+ e_source_get_property (source, "timeout") : "3", NULL));
+
+ dialog->auth = source && e_source_get_property (source, "auth") ?
+ ldap_parse_auth (e_source_get_property (source, "auth")) : ADDRESSBOOK_LDAP_AUTH_NONE;
+ dialog->ssl = source && e_source_get_property (source, "ssl") ?
+ ldap_parse_ssl (e_source_get_property (source, "ssl")) : ADDRESSBOOK_LDAP_SSL_WHENEVER_POSSIBLE;
+
+ if (dialog->auth != ADDRESSBOOK_LDAP_AUTH_NONE)
+ gtk_entry_set_text (GTK_ENTRY (dialog->auth_principal),
+ SOURCE_PROP_STRING (source,
+ dialog->auth == ADDRESSBOOK_LDAP_AUTH_SIMPLE_EMAIL ? "email_addr" : "binddn"));
+
+ if (source && !strcmp ("ldap://", e_source_group_peek_base_uri (dialog->source_group))) {
+ gchar *host;
+ gchar *rootdn;
+ AddressbookLDAPScopeType scope;
+ gint port;
+
+ if (source_to_uri_parts (source, &host, &rootdn, &scope, &port)) {
+ gchar *port_str;
+
+ gtk_entry_set_text (GTK_ENTRY (dialog->host), host);
+ gtk_entry_set_text (GTK_ENTRY (dialog->rootdn), rootdn);
+
+ dialog->scope = scope;
+
+ port_str = g_strdup_printf ("%d", port);
+ gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (dialog->port_combo)->entry), port_str);
+ g_free (port_str);
+
+ g_free (host);
+ g_free (rootdn);
+ }
+ }
+
+ gtk_option_menu_set_history (GTK_OPTION_MENU(dialog->auth_optionmenu), dialog->auth);
+ gtk_option_menu_set_history (GTK_OPTION_MENU(dialog->scope_optionmenu), dialog->scope);
+ gtk_option_menu_set_history (GTK_OPTION_MENU(dialog->ssl_optionmenu), dialog->ssl);
+#endif
}
+#ifdef HAVE_LDAP
+
/* ldap api foo */
static LDAP *
addressbook_ldap_init (GtkWidget *window, ESource *source)
@@ -296,35 +454,203 @@ addressbook_root_dse_query (AddressbookSourceDialog *dialog, LDAP *ldap,
return ldap_error;
}
+#endif
+
+static void
+addressbook_source_dialog_destroy (gpointer data, GObject *where_object_was)
+{
+ AddressbookSourceDialog *dialog = data;
+
+ g_object_unref (dialog->gui);
+ g_object_unref (dialog->source_list);
+ g_slist_free (dialog->menu_source_groups);
+ g_free (dialog);
+}
+
+static void
+addressbook_add_server_dialog_finish (GtkWidget *widget, AddressbookSourceDialog *sdialog)
+{
+ sdialog->source = e_source_new ("", "");
+ dialog_to_source (sdialog, sdialog->source, FALSE);
+
+ /* tear down the widgets */
+ gtk_widget_destroy (sdialog->window);
+}
+
+static void
+addressbook_add_server_dialog_cancel (GtkWidget *widget, AddressbookSourceDialog *dialog)
+{
+ gtk_widget_destroy (dialog->window);
+}
+
+static void
+auth_optionmenu_activated (GtkWidget *item, AddressbookSourceDialog *dialog)
+{
+ dialog->auth = g_list_index (gtk_container_get_children (GTK_CONTAINER (item->parent)),
+ item);
+
+ dialog->general_modify_func (item, dialog);
+}
+
+static void
+add_auth_activate_cb (GtkWidget *item, AddressbookSourceDialog *dialog)
+{
+ g_signal_connect (item, "activate",
+ G_CALLBACK (auth_optionmenu_activated), dialog);
+}
+
+static void
+setup_general_tab (AddressbookSourceDialog *dialog, ModifyFunc modify_func)
+{
+ GtkWidget *menu;
+
+ dialog->general_modify_func = modify_func;
+ dialog->host = glade_xml_get_widget (dialog->gui, "server-name-entry");
+
+ g_signal_connect (dialog->host, "changed",
+ G_CALLBACK (modify_func), dialog);
+
+ dialog->auth_principal = glade_xml_get_widget (dialog->gui, "auth-entry");
+ g_signal_connect (dialog->auth_principal, "changed",
+ G_CALLBACK (modify_func), dialog);
+
+ dialog->auth_optionmenu = glade_xml_get_widget (dialog->gui, "auth-optionmenu");
+ menu = gtk_option_menu_get_menu (GTK_OPTION_MENU(dialog->auth_optionmenu));
+ gtk_container_foreach (GTK_CONTAINER (menu), (GtkCallback)add_auth_activate_cb, dialog);
+}
+
+static gboolean
+general_tab_check (AddressbookSourceDialog *dialog)
+{
+ gboolean valid = TRUE;
+ const char *string;
+
+ if (strcmp ("ldap://", e_source_group_peek_base_uri (dialog->source_group)))
+ return TRUE;
+
+ string = gtk_entry_get_text (GTK_ENTRY (dialog->host));
+ if (!string || !string[0])
+ valid = FALSE;
+
+ if (valid) {
+ if (dialog->auth != ADDRESSBOOK_LDAP_AUTH_NONE) {
+ string = gtk_entry_get_text (GTK_ENTRY (dialog->auth_principal));
+
+ if (!string || !string[0])
+ valid = FALSE;
+ }
+ }
+
+ return valid;
+}
+
+
+/* connecting page */
+static void
+ssl_optionmenu_activated (GtkWidget *item, AddressbookSourceDialog *dialog)
+{
+ dialog->ssl = g_list_index (gtk_container_get_children (GTK_CONTAINER (item->parent)),
+ item);
+
+ dialog->connecting_modify_func (item, dialog);
+}
+
+static void
+add_ssl_activate_cb (GtkWidget *item, AddressbookSourceDialog *dialog)
+{
+ g_signal_connect (item, "activate",
+ G_CALLBACK (ssl_optionmenu_activated), dialog);
+}
+
+static void
+port_changed_func (GtkWidget *item, AddressbookSourceDialog *dialog)
+{
+ /* if the port value is ldaps, set the SSL/TLS option menu to
+ Always and desensitize it */
+ const char *string = gtk_entry_get_text (GTK_ENTRY (item));
+
+ dialog->connecting_modify_func (item, dialog);
+
+ if (!strcmp (string, LDAPS_PORT_STRING)) {
+ dialog->ssl = ADDRESSBOOK_LDAP_SSL_ALWAYS;
+ gtk_option_menu_set_history (GTK_OPTION_MENU(dialog->ssl_optionmenu),
+ dialog->ssl);
+
+ gtk_widget_set_sensitive (dialog->ssl_optionmenu, FALSE);
+ }
+ else {
+ gtk_widget_set_sensitive (dialog->ssl_optionmenu, TRUE);
+ }
+
+}
+
+static void
+setup_connecting_tab (AddressbookSourceDialog *dialog, ModifyFunc modify_func)
+{
+ GtkWidget *menu;
+
+ dialog->connecting_modify_func = modify_func;
+
+ dialog->port_combo = glade_xml_get_widget (dialog->gui, "port-combo");
+
+ g_signal_connect (GTK_COMBO(dialog->port_combo)->entry, "changed",
+ G_CALLBACK (modify_func), dialog);
+ g_signal_connect (GTK_COMBO(dialog->port_combo)->entry, "changed",
+ G_CALLBACK (port_changed_func), dialog);
+ dialog->ssl_optionmenu = glade_xml_get_widget (dialog->gui, "ssl-optionmenu");
+ menu = gtk_option_menu_get_menu (GTK_OPTION_MENU(dialog->ssl_optionmenu));
+ gtk_container_foreach (GTK_CONTAINER (menu), (GtkCallback)add_ssl_activate_cb, dialog);
+}
+
+static gboolean
+connecting_tab_check (AddressbookSourceDialog *dialog)
+{
+ gboolean valid = TRUE;
+ const char *string;
+
+ string = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO(dialog->port_combo)->entry));
+ if (!string || !string[0])
+ valid = FALSE;
+
+ return valid;
+}
+
+
+
+#ifdef HAVE_LDAP
+
/* searching page */
+static ETableMemoryStoreColumnInfo bases_table_columns[] = {
+ E_TABLE_MEMORY_STORE_STRING,
+ E_TABLE_MEMORY_STORE_TERMINATOR
+};
+
+#define BASES_TABLE_SPEC \
+"<ETableSpecification cursor-mode=\"line\" no-headers=\"true\"> \
+ <ETableColumn model_col= \"0\" _title=\"Base\" expansion=\"1.0\" minimum_width=\"20\" resizable=\"true\" cell=\"string\" compare=\"string\"/> \
+ <ETableState> \
+ <column source=\"0\"/> \
+ <grouping></grouping> \
+ </ETableState> \
+</ETableSpecification>"
+
GtkWidget*
supported_bases_create_table (char *name, char *string1, char *string2, int num1, int num2)
{
- GtkWidget *table, *scrolled;
- GtkTreeSelection *selection;
- GtkCellRenderer *renderer;
- GtkListStore *model;
-
- scrolled = gtk_scrolled_window_new (NULL, NULL);
- gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
- gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled), GTK_SHADOW_IN);
-
- model = gtk_list_store_new (1, G_TYPE_STRING);
- table = gtk_tree_view_new_with_model ((GtkTreeModel *) model);
- renderer = gtk_cell_renderer_text_new ();
- gtk_tree_view_insert_column_with_attributes ((GtkTreeView *) table, -1, _("Base"), renderer, "text", 0, NULL);
- gtk_tree_view_set_headers_visible ((GtkTreeView *) table, FALSE);
- selection = gtk_tree_view_get_selection ((GtkTreeView *) table);
- gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
-
- gtk_container_add (GTK_CONTAINER (scrolled), table);
- g_object_set_data((GObject *)scrolled, "table", table);
-
- return scrolled;
+ GtkWidget *table;
+ ETableModel *model;
+
+ model = e_table_memory_store_new (bases_table_columns);
+
+ table = e_table_scrolled_new (model, NULL, BASES_TABLE_SPEC, NULL);
+
+ g_object_set_data (G_OBJECT (table), "model", model);
+
+ return table;
}
static gboolean
-do_ldap_root_dse_query (AddressbookSourceDialog *sdialog, GtkListStore *model, ESource *source)
+do_ldap_root_dse_query (AddressbookSourceDialog *sdialog, ETableModel *model, ESource *source, char ***rvalues)
{
LDAP *ldap;
char *attrs[2];
@@ -354,14 +680,12 @@ do_ldap_root_dse_query (AddressbookSourceDialog *sdialog, GtkListStore *model, E
goto fail;
}
- for (i = 0; values[i]; i++) {
- GtkTreeIter iter;
+ for (i = 0; values[i]; i++)
+ e_table_memory_store_insert (E_TABLE_MEMORY_STORE (model),
+ -1, GINT_TO_POINTER(i), values[i]);
- gtk_list_store_append (model, &iter);
- gtk_list_store_set (model, &iter, 0, values[i], -1);
- }
+ *rvalues = values;
- ldap_value_free (values);
ldap_unbind_s (ldap);
return TRUE;
@@ -371,23 +695,26 @@ do_ldap_root_dse_query (AddressbookSourceDialog *sdialog, GtkListStore *model, E
}
static void
-search_base_selection_model_changed (GtkTreeSelection *selection, GtkWidget *dialog)
+search_base_selection_model_changed (ESelectionModel *selection_model, GtkWidget *dialog)
{
gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog),
GTK_RESPONSE_OK,
- gtk_tree_selection_get_selected(selection, NULL, NULL));
+ e_selection_model_selected_count (selection_model) == 1);
}
static void
query_for_supported_bases (GtkWidget *button, AddressbookSourceDialog *sdialog)
{
- GtkTreeSelection *selection;
- GtkListStore *model;
- GtkTreeView *table;
+ ESelectionModel *selection_model;
+ ESource *source;
GtkWidget *dialog;
GtkWidget *supported_bases_table;
+ ETableModel *model;
GladeXML *gui;
- GtkTreeIter iter;
+ int id;
+ char **values;
+
+ source = dialog_to_temp_source (sdialog);
gui = glade_xml_new (EVOLUTION_GLADEDIR "/" GLADE_FILE_NAME, "supported-bases-dialog", NULL);
dialog = glade_xml_get_widget (gui, "supported-bases-dialog");
@@ -400,730 +727,571 @@ query_for_supported_bases (GtkWidget *button, AddressbookSourceDialog *sdialog)
gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area), 12);
supported_bases_table = glade_xml_get_widget (gui, "supported-bases-table");
- gtk_widget_show_all (supported_bases_table);
+ gtk_widget_show (supported_bases_table);
+ selection_model = e_table_get_selection_model (e_table_scrolled_get_table (E_TABLE_SCROLLED(supported_bases_table)));
+ model = g_object_get_data (G_OBJECT (supported_bases_table), "model");
- table = g_object_get_data((GObject *)supported_bases_table, "table");
- model = (GtkListStore *)gtk_tree_view_get_model(table);
- selection = gtk_tree_view_get_selection (table);
- g_signal_connect (selection, "changed", G_CALLBACK (search_base_selection_model_changed), dialog);
- search_base_selection_model_changed (selection, dialog);
+ g_signal_connect (selection_model, "selection_changed",
+ G_CALLBACK (search_base_selection_model_changed), dialog);
- if (do_ldap_root_dse_query (sdialog, model, sdialog->source)) {
- gtk_widget_show (dialog);
-
- if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK
- && gtk_tree_selection_get_selected(selection, (GtkTreeModel **)&model, &iter)) {
- char *dn;
-
- gtk_tree_model_get ((GtkTreeModel *)model, &iter, 0, &dn, -1);
- gtk_entry_set_text((GtkEntry *)sdialog->rootdn, dn);
- g_free(dn);
- }
- }
+ search_base_selection_model_changed (selection_model, dialog);
- gtk_widget_destroy (dialog);
-}
+ if (do_ldap_root_dse_query (sdialog, model, source, &values)) {
+ gtk_widget_show (dialog);
-#endif /* HAVE_LDAP */
+ id = gtk_dialog_run (GTK_DIALOG (dialog));
-GtkWidget*
-addressbook_config_create_new_source (GtkWidget *parent)
-{
- return addressbook_config_edit_source(parent, NULL);
-}
+ gtk_widget_hide (dialog);
-/* ********************************************************************** */
+ if (id == GTK_RESPONSE_OK) {
+ int i;
+ /* OK was clicked */
-static void
-eabc_type_changed(GtkComboBox *dropdown, AddressbookSourceDialog *sdialog)
-{
- int id = gtk_combo_box_get_active(dropdown);
- GtkTreeModel *model;
- GtkTreeIter iter;
-
- model = gtk_combo_box_get_model(dropdown);
- if (id == -1 || !gtk_tree_model_iter_nth_child(model, &iter, NULL, id))
- return;
-
- /* TODO: when we change the group type, we lose all of the pre-filled dialog info */
-
- gtk_tree_model_get(model, &iter, 1, &sdialog->source_group, -1);
- /* HACK: doesn't work if you don't do this */
- e_source_set_absolute_uri(sdialog->source, NULL);
- e_source_set_group(sdialog->source, sdialog->source_group);
-
- /* BIG HACK: We load the defaults for each type here.
- I guess plugins will have to use the do it in their factory callbacks */
- if (!strncmp(e_source_group_peek_base_uri(sdialog->source_group), "groupwise:", 10)) {
- GSList *l;
- ESource *source;
- char *tmp;
-
- l = e_source_group_peek_sources(sdialog->source_group);
- if (l && l->data ) {
- source = l->data;
- e_source_set_property(sdialog->source, "auth", e_source_get_property(source, "auth"));
- e_source_set_property(sdialog->source, "user", e_source_get_property(source, "user"));
- e_source_set_property(sdialog->source, "user_ssl", e_source_get_property(source, "use_ssl"));
+ /* ugh. */
+ for (i = 0; values[i]; i ++) {
+ if (e_selection_model_is_row_selected (selection_model, i)) {
+ gtk_entry_set_text (GTK_ENTRY (sdialog->rootdn), values[i]);
+ break; /* single selection, so we can quit when we've found it. */
+ }
+ }
}
- e_source_set_property(sdialog->source, "auth-domain", "Groupwise");
- tmp = g_strconcat (";", e_source_peek_name(sdialog->source), NULL);
- e_source_set_relative_uri (sdialog->source, tmp);
- g_free (tmp);
-#ifdef HAVE_LDAP
- } else if (!strncmp(e_source_group_peek_base_uri(sdialog->source_group), "ldap:", 5)) {
- char *tmp;
-
- tmp = g_strdup_printf ("%s:%s/%s?" /* trigraph prevention */ "?%s",
- "", LDAP_PORT_STRING,
- "",
- "one");
- e_source_set_relative_uri (sdialog->source, tmp);
- g_free (tmp);
- e_source_set_property(sdialog->source, "timeout", "3");
- e_source_set_property(sdialog->source, "limit", "100");
-#endif
- } else {
- e_source_set_relative_uri (sdialog->source, e_source_peek_uid (sdialog->source));
- }
-
- e_config_target_changed((EConfig *)sdialog->config, E_CONFIG_TARGET_CHANGED_REBUILD);
-}
+ ldap_value_free (values);
-static GtkWidget *
-eabc_general_type(EConfig *ec, EConfigItem *item, struct _GtkWidget *parent, struct _GtkWidget *old, void *data)
-{
- AddressbookSourceDialog *sdialog = data;
- GtkComboBox *dropdown;
- GtkCellRenderer *cell;
- GtkListStore *store;
- GtkTreeIter iter;
- GSList *l;
- GtkWidget *w, *label;
- int i, row;
-
- if (old)
- return old;
-
- w = gtk_hbox_new(FALSE, 6);
- label = gtk_label_new_with_mnemonic(_("_Type:"));
- gtk_box_pack_start((GtkBox *)w, label, FALSE, FALSE, 0);
-
- dropdown = (GtkComboBox *)gtk_combo_box_new();
- cell = gtk_cell_renderer_text_new();
- store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
- i = 0;
- for (l=sdialog->menu_source_groups;l;l=g_slist_next(l)) {
- ESourceGroup *group = l->data;
-
- gtk_list_store_append(store, &iter);
- gtk_list_store_set(store, &iter, 0, e_source_group_peek_name(group), 1, group, -1);
- if (e_source_peek_group(sdialog->source) == group)
- row = i;
- i++;
+ e_table_memory_store_clear (E_TABLE_MEMORY_STORE (model));
}
- gtk_cell_layout_pack_start((GtkCellLayout *)dropdown, cell, TRUE);
- gtk_cell_layout_set_attributes((GtkCellLayout *)dropdown, cell, "text", 0, NULL);
- gtk_combo_box_set_model(dropdown, (GtkTreeModel *)store);
- gtk_combo_box_set_active(dropdown, -1);
- gtk_combo_box_set_active(dropdown, row);
- g_signal_connect(dropdown, "changed", G_CALLBACK(eabc_type_changed), sdialog);
- gtk_widget_show((GtkWidget *)dropdown);
- gtk_box_pack_start((GtkBox *)w, (GtkWidget *)dropdown, TRUE, TRUE, 0);
- gtk_label_set_mnemonic_widget((GtkLabel *)label, (GtkWidget *)dropdown);
-
- gtk_box_pack_start((GtkBox *)parent, (GtkWidget *)w, FALSE, FALSE, 0);
-
- gtk_widget_show_all(w);
+ gtk_widget_destroy (dialog);
- return (GtkWidget *)w;
+ g_object_unref (source);
}
static void
-name_changed_cb(GtkWidget *w, AddressbookSourceDialog *sdialog)
+scope_optionmenu_activated (GtkWidget *item, AddressbookSourceDialog *dialog)
{
- e_source_set_name (sdialog->source, gtk_entry_get_text (GTK_ENTRY (sdialog->display_name)));
+ dialog->scope = g_list_index (gtk_container_get_children (GTK_CONTAINER (item->parent)),
+ item);
+
+ if (dialog->searching_modify_func)
+ dialog->searching_modify_func (item, dialog);
}
-static void
-offline_status_changed_cb (GtkWidget *widget, AddressbookSourceDialog *sdialog)
+static void
+add_scope_activate_cb (GtkWidget *item, AddressbookSourceDialog *dialog)
{
- if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
- e_source_set_property (sdialog->source, "offline_sync", "1");
- else
- e_source_set_property (sdialog->source, "offline_sync", "0");
-
+ g_signal_connect (item, "activate",
+ G_CALLBACK (scope_optionmenu_activated), dialog);
}
-static GtkWidget *
-eabc_general_name(EConfig *ec, EConfigItem *item, struct _GtkWidget *parent, struct _GtkWidget *old, void *data)
+static void
+setup_searching_tab (AddressbookSourceDialog *dialog, ModifyFunc modify_func)
{
- AddressbookSourceDialog *sdialog = data;
- const char *uri;
- GtkWidget *w;
- GladeXML *gui;
-
+ GtkWidget *menu;
+ GtkWidget *rootdn_button;
- if (old)
- return old;
+ dialog->searching_modify_func = modify_func;
- gui = glade_xml_new (EVOLUTION_GLADEDIR "/" GLADE_FILE_NAME, item->label, NULL);
- w = glade_xml_get_widget(gui, item->label);
- gtk_box_pack_start((GtkBox *)parent, w, FALSE, FALSE, 0);
- sdialog->display_name = glade_xml_get_widget (gui, "account-editor-display-name-entry");
- g_signal_connect(sdialog->display_name, "changed", G_CALLBACK(name_changed_cb), sdialog);
- gtk_entry_set_text((GtkEntry *)sdialog->display_name, e_source_peek_name(sdialog->source));
+ dialog->rootdn = glade_xml_get_widget (dialog->gui, "rootdn-entry");
- /* Hardcoded: groupwise can't edit the name (or anything else) */
- if (sdialog->original_source) {
- uri = e_source_group_peek_base_uri (sdialog->source_group);
- if (uri && strncmp(uri, "groupwise:", 10) == 0) {
- gtk_widget_set_sensitive (GTK_WIDGET(sdialog->display_name), FALSE);
- }
- }
+ if (modify_func)
+ g_signal_connect (dialog->rootdn, "changed",
+ G_CALLBACK (modify_func), dialog);
+
+ dialog->scope_optionmenu = glade_xml_get_widget (dialog->gui, "scope-optionmenu");
- g_object_unref(gui);
+ menu = gtk_option_menu_get_menu (GTK_OPTION_MENU(dialog->scope_optionmenu));
+ gtk_container_foreach (GTK_CONTAINER (menu), (GtkCallback)add_scope_activate_cb, dialog);
- return w;
+ dialog->timeout_scale = glade_xml_get_widget (dialog->gui, "timeout-scale");
+
+ if (modify_func)
+ g_signal_connect (GTK_RANGE(dialog->timeout_scale)->adjustment,
+ "value_changed",
+ G_CALLBACK (modify_func), dialog);
+
+ dialog->limit_spinbutton = glade_xml_get_widget (dialog->gui, "download-limit-spinbutton");
+ if (modify_func)
+ g_signal_connect (dialog->limit_spinbutton, "changed",
+ G_CALLBACK (modify_func), dialog);
+
+ /* special handling for the "Show Supported Bases button" */
+ rootdn_button = glade_xml_get_widget (dialog->gui, "rootdn-button");
+ g_signal_connect (rootdn_button, "clicked",
+ G_CALLBACK(query_for_supported_bases), dialog);
}
-
-static GtkWidget *
-eabc_general_offline(EConfig *ec, EConfigItem *item, struct _GtkWidget *parent, struct _GtkWidget *old, void *data)
+static gboolean
+searching_tab_check (AddressbookSourceDialog *dialog)
{
- AddressbookSourceDialog *sdialog = data;
- GtkWidget *offline_setting;
- const char *offline_sync;
- int row;
- gboolean is_local_book;
-
- is_local_book = g_str_has_prefix (e_source_group_peek_base_uri (sdialog->source_group), "file:");
- offline_sync = e_source_get_property (sdialog->source, "offline_sync");
- if (old)
- return old;
- else {
- row = ((GtkTable*)parent)->nrows;
- offline_setting = gtk_check_button_new_with_label (N_("Copy book content locally for offline operation"));
- gtk_widget_show (offline_setting);
- gtk_container_add (GTK_CONTAINER (parent), offline_setting);
- g_signal_connect (offline_setting, "toggled", G_CALLBACK (offline_status_changed_cb), sdialog);
-
- }
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (offline_setting), (offline_sync && g_str_equal (offline_sync, "1")) ? TRUE : FALSE);
- if (is_local_book)
- gtk_widget_hide (offline_setting);
- return offline_setting;
+ gboolean valid = TRUE;
+ gdouble timeout = 3;
-}
+ timeout = gtk_adjustment_get_value (GTK_RANGE(dialog->timeout_scale)->adjustment);
-#ifdef HAVE_LDAP
-static void
-url_changed(AddressbookSourceDialog *sdialog)
-{
- char *str;
-
- str = g_strdup_printf ("%s:%s/%s?" /* trigraph prevention */ "?%s",
- gtk_entry_get_text (GTK_ENTRY (sdialog->host)),
- gtk_entry_get_text (GTK_ENTRY (GTK_COMBO (sdialog->port_combo)->entry)),
- gtk_entry_get_text (GTK_ENTRY (sdialog->rootdn)),
- ldap_unparse_scope (sdialog->scope));
- e_source_set_relative_uri (sdialog->source, str);
- g_free (str);
+ if(!timeout)
+ return FALSE;
+ return valid;
}
-static void
-host_changed_cb(GtkWidget *w, AddressbookSourceDialog *sdialog)
-{
- url_changed(sdialog);
-}
+#endif
-static void
-port_entry_changed_cb(GtkWidget *w, AddressbookSourceDialog *sdialog)
+
+/* display name page */
+static gboolean
+display_name_check (AddressbookSourceDialog *dialog)
{
- const char *port = gtk_entry_get_text((GtkEntry *)w);
+ gboolean valid = TRUE;
+ const char *string;
- if (!strcmp (port, LDAPS_PORT_STRING)) {
- sdialog->ssl = ADDRESSBOOK_LDAP_SSL_ALWAYS;
- gtk_option_menu_set_history (GTK_OPTION_MENU(sdialog->ssl_optionmenu), sdialog->ssl);
- gtk_widget_set_sensitive (sdialog->ssl_optionmenu, FALSE);
- } else {
- gtk_widget_set_sensitive (sdialog->ssl_optionmenu, TRUE);
- }
+ string = gtk_entry_get_text (GTK_ENTRY (dialog->display_name));
+ if (!string || !string[0])
+ valid = FALSE;
- url_changed(sdialog);
+ return valid;
}
-static void
-ssl_optionmenu_changed_cb(GtkWidget *w, AddressbookSourceDialog *sdialog)
+
+static gboolean
+source_group_is_remote (ESourceGroup *group)
{
- sdialog->ssl = gtk_option_menu_get_history((GtkOptionMenu *)w);
- e_source_set_property (sdialog->source, "ssl", ldap_unparse_ssl (sdialog->ssl));
+ return !strcmp ("ldap://", e_source_group_peek_base_uri (group));
}
-
-static GtkWidget *
-eabc_general_host(EConfig *ec, EConfigItem *item, struct _GtkWidget *parent, struct _GtkWidget *old, void *data)
+static void
+add_folder_modify (GtkWidget *widget, AddressbookSourceDialog *sdialog)
{
- AddressbookSourceDialog *sdialog = data;
- const char *tmp;
- GtkWidget *w;
- char *uri, port[16];
- LDAPURLDesc *lud;
- GladeXML *gui;
+ gboolean valid = TRUE;
+ gboolean remote = FALSE;
- if (!source_group_is_remote(sdialog->source_group))
- return NULL;
+ valid = display_name_check (sdialog);
+ remote = source_group_is_remote (sdialog->source_group);
- gui = glade_xml_new (EVOLUTION_GLADEDIR "/" GLADE_FILE_NAME, item->label, NULL);
- w = glade_xml_get_widget(gui, item->label);
- gtk_box_pack_start((GtkBox *)parent, w, FALSE, FALSE, 0);
- uri = e_source_get_uri(sdialog->source);
- if (ldap_url_parse(uri, &lud) != LDAP_SUCCESS)
- lud = NULL;
- g_free(uri);
+ remote = source_group_is_remote (sdialog->source_group);
+ if (sdialog->server_frame)
+ gtk_widget_set_sensitive (sdialog->server_frame, remote);
+
+ if (sdialog->auth_frame)
+ gtk_widget_set_sensitive (sdialog->auth_frame, remote);
- sdialog->host = glade_xml_get_widget (gui, "server-name-entry");
- gtk_entry_set_text((GtkEntry *)sdialog->host, lud && lud->lud_host ? lud->lud_host : "");
- g_signal_connect (sdialog->host, "changed", G_CALLBACK (host_changed_cb), sdialog);
+#ifdef HAVE_LDAP
+ gtk_widget_set_sensitive (sdialog->auth_principal, sdialog->auth != ADDRESSBOOK_LDAP_AUTH_NONE);
- sdialog->port_combo = glade_xml_get_widget (gui, "port-combo");
- sprintf(port, "%u", lud && lud->lud_port? lud->lud_port : LDAP_PORT);
- gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (sdialog->port_combo)->entry), port);
- g_signal_connect (GTK_COMBO(sdialog->port_combo)->entry, "changed", G_CALLBACK (port_entry_changed_cb), sdialog);
+ if (valid)
+ valid = general_tab_check (sdialog);
+ if (valid)
+ valid = connecting_tab_check (sdialog);
- if (lud)
- ldap_free_urldesc (lud);
+ gtk_widget_set_sensitive (glade_xml_get_widget (sdialog->gui, "details-label"), valid && remote);
- sdialog->ssl_optionmenu = glade_xml_get_widget (gui, "ssl-optionmenu");
- tmp = e_source_get_property (sdialog->source, "ssl");
- sdialog->ssl = tmp ? ldap_parse_ssl (tmp) : ADDRESSBOOK_LDAP_SSL_WHENEVER_POSSIBLE;
- gtk_option_menu_set_history (GTK_OPTION_MENU(sdialog->ssl_optionmenu), sdialog->ssl);
- g_signal_connect(sdialog->ssl_optionmenu, "changed", G_CALLBACK(ssl_optionmenu_changed_cb), sdialog);
+ gtk_widget_set_sensitive (glade_xml_get_widget (sdialog->gui, "details-vbox"), valid && remote);
- g_object_unref(gui);
+ if (valid)
+ valid = searching_tab_check (sdialog);
+#endif
- return w;
+ gtk_widget_set_sensitive (sdialog->ok_button, valid);
}
static void
-auth_entry_changed_cb(GtkWidget *w, AddressbookSourceDialog *sdialog)
+source_group_changed_cb (GtkWidget *widget, AddressbookSourceDialog *sdialog)
{
- const char *principal = gtk_entry_get_text((GtkEntry *)w);
-
- /* seems messy ... but the api is */
- switch (sdialog->auth) {
- case ADDRESSBOOK_LDAP_AUTH_SIMPLE_BINDDN:
- e_source_set_property(sdialog->source, "email_addr", NULL);
- e_source_set_property(sdialog->source, "binddn", principal);
- break;
- case ADDRESSBOOK_LDAP_AUTH_SIMPLE_EMAIL:
- e_source_set_property(sdialog->source, "binddn", NULL);
- e_source_set_property(sdialog->source, "email_addr", principal);
- break;
- case ADDRESSBOOK_LDAP_AUTH_NONE:
- default:
- e_source_set_property(sdialog->source, "email_addr", NULL);
- e_source_set_property(sdialog->source, "binddn", NULL);
- break;
- }
+ sdialog->source_group = g_slist_nth (sdialog->menu_source_groups,
+ gtk_option_menu_get_history (GTK_OPTION_MENU (sdialog->group_optionmenu)))->data;
+ if (sdialog->auth_frame)
+ add_folder_modify (widget, sdialog);
}
static void
-auth_optionmenu_changed_cb(GtkWidget *w, AddressbookSourceDialog *sdialog)
+source_group_menu_add_groups (GtkMenuShell *menu_shell, ESourceList *source_list)
{
- sdialog->auth = gtk_option_menu_get_history((GtkOptionMenu *)w);
- e_source_set_property (sdialog->source, "auth", ldap_unparse_auth (sdialog->auth));
+ GSList *groups, *sl;
+
+ groups = e_source_list_peek_groups (source_list);
+ for (sl = groups; sl; sl = g_slist_next (sl)) {
+ GtkWidget *menu_item;
+ ESourceGroup *group = sl->data;
+
+#ifndef HAVE_LDAP
+ /* If LDAP isn't configured, skip LDAP groups */
+ if (!strcmp ("ldap://", e_source_group_peek_base_uri (group)))
+ continue;
+#endif
+ menu_item = gtk_menu_item_new_with_label (e_source_group_peek_name (group));
+ gtk_widget_show (menu_item);
+ gtk_menu_shell_append (menu_shell, menu_item);
- /* make sure the right property is set for the auth - ugh, funny api */
- auth_entry_changed_cb(sdialog->auth_principal, sdialog);
+ if (!strcmp ("exchange://", e_source_group_peek_base_uri (group)))
+ gtk_widget_set_sensitive (menu_item, FALSE);
+
+ }
}
-static GtkWidget *
-eabc_general_auth(EConfig *ec, EConfigItem *item, struct _GtkWidget *parent, struct _GtkWidget *old, void *data)
+static AddressbookSourceDialog *
+addressbook_add_server_dialog (void)
{
- AddressbookSourceDialog *sdialog = data;
- GtkWidget *w;
- const char *tmp;
- GladeXML *gui;
-
- if (!source_group_is_remote(sdialog->source_group))
+ AddressbookSourceDialog *sdialog = g_new0 (AddressbookSourceDialog, 1);
+ GConfClient *gconf_client;
+ GSList *source_groups;
+
+ gconf_client = gconf_client_get_default ();
+ sdialog->source_list = e_source_list_new_for_gconf (gconf_client, "/apps/evolution/addressbook/sources");
+ g_object_unref (gconf_client);
+
+ source_groups = e_source_list_peek_groups (sdialog->source_list);
+ if (!source_groups) {
+ g_warning ("Addressbook source groups are missing! Check your GConf setup.");
+ g_free (sdialog);
return NULL;
+ }
- gui = glade_xml_new (EVOLUTION_GLADEDIR "/" GLADE_FILE_NAME, item->label, NULL);
- w = glade_xml_get_widget(gui, item->label);
- gtk_box_pack_start((GtkBox *)parent, w, FALSE, FALSE, 0);
+ sdialog->menu_source_groups = g_slist_copy (source_groups);
- sdialog->auth_optionmenu = glade_xml_get_widget (gui, "auth-optionmenu");
- tmp = e_source_get_property(sdialog->source, "auth");
- sdialog->auth = tmp ? ldap_parse_auth(tmp) : ADDRESSBOOK_LDAP_AUTH_NONE;
- gtk_option_menu_set_history (GTK_OPTION_MENU(sdialog->auth_optionmenu), sdialog->auth);
- g_signal_connect(sdialog->auth_optionmenu, "changed", G_CALLBACK(auth_optionmenu_changed_cb), sdialog);
+ sdialog->gui = glade_xml_new (EVOLUTION_GLADEDIR "/" GLADE_FILE_NAME, "account-add-window", NULL);
- sdialog->auth_principal = glade_xml_get_widget (gui, "auth-entry");
- switch (sdialog->auth) {
- case ADDRESSBOOK_LDAP_AUTH_SIMPLE_EMAIL:
- tmp = e_source_get_property(sdialog->source, "email_addr");
- break;
- case ADDRESSBOOK_LDAP_AUTH_SIMPLE_BINDDN:
- tmp = e_source_get_property(sdialog->source, "binddn");
- break;
- case ADDRESSBOOK_LDAP_AUTH_NONE:
- default:
- tmp = "";
- break;
- }
- gtk_entry_set_text((GtkEntry *)sdialog->auth_principal, tmp?tmp:"");
- g_signal_connect (sdialog->auth_principal, "changed", G_CALLBACK (auth_entry_changed_cb), sdialog);
+ sdialog->window = glade_xml_get_widget (sdialog->gui, "account-add-window");
+
+ gtk_widget_ensure_style (sdialog->window);
+ gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (sdialog->window)->vbox), 0);
+ gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (sdialog->window)->action_area), 12);
- g_object_unref(gui);
+ sdialog->display_name = glade_xml_get_widget (sdialog->gui, "display-name-entry");
+ g_signal_connect (sdialog->display_name, "changed",
+ G_CALLBACK (add_folder_modify), sdialog);
- return w;
-}
-
-static void
-rootdn_changed_cb(GtkWidget *w, AddressbookSourceDialog *sdialog)
-{
- url_changed(sdialog);
-}
+#ifndef HAVE_LDAP
+ for ( ; source_groups != NULL; source_groups = g_slist_next (source_groups))
+ if (!strcmp ("ldap://", e_source_group_peek_base_uri (source_groups->data)))
+ sdialog->menu_source_groups = g_slist_remove (sdialog->menu_source_groups, source_groups->data);
+#endif
+
+ sdialog->group_optionmenu = glade_xml_get_widget (sdialog->gui, "group-optionmenu");
+ if (!GTK_IS_MENU (gtk_option_menu_get_menu (GTK_OPTION_MENU (sdialog->group_optionmenu)))) {
+ GtkWidget *menu = gtk_menu_new ();
+ gtk_option_menu_set_menu (GTK_OPTION_MENU (sdialog->group_optionmenu), menu);
+ gtk_widget_show (menu);
+ }
-static void
-scope_optionmenu_changed_cb(GtkWidget *w, AddressbookSourceDialog *sdialog)
-{
- sdialog->scope = gtk_option_menu_get_history((GtkOptionMenu *)w);
- url_changed(sdialog);
-}
+ /* NOTE: This assumes that we have sources. If they don't exist, they're set up
+ * on startup of the Addressbook component. */
+ source_group_menu_add_groups (GTK_MENU_SHELL (gtk_option_menu_get_menu (
+ GTK_OPTION_MENU (sdialog->group_optionmenu))), sdialog->source_list);
+ gtk_option_menu_set_history (GTK_OPTION_MENU (sdialog->group_optionmenu), 0);
+ sdialog->source_group = e_source_list_peek_groups (sdialog->source_list)->data;
+ g_signal_connect (sdialog->group_optionmenu, "changed",
+ G_CALLBACK (source_group_changed_cb), sdialog);
-static GtkWidget *
-eabc_details_search(EConfig *ec, EConfigItem *item, struct _GtkWidget *parent, struct _GtkWidget *old, void *data)
-{
- AddressbookSourceDialog *sdialog = data;
- GtkWidget *w;
- LDAPURLDesc *lud;
- char *uri;
- GladeXML *gui;
+ setup_general_tab (sdialog, add_folder_modify);
+#ifdef HAVE_LDAP
+ setup_connecting_tab (sdialog, add_folder_modify);
- if (!source_group_is_remote(sdialog->source_group))
- return NULL;
+ setup_searching_tab (sdialog, add_folder_modify);
+#endif
- gui = glade_xml_new (EVOLUTION_GLADEDIR "/" GLADE_FILE_NAME, item->label, NULL);
- w = glade_xml_get_widget(gui, item->label);
- gtk_box_pack_start((GtkBox *)parent, w, FALSE, FALSE, 0);
+ sdialog->auth_frame = glade_xml_get_widget (sdialog->gui, "authentication-frame");
+ sdialog->server_frame = glade_xml_get_widget (sdialog->gui, "server-frame");
- uri = e_source_get_uri(sdialog->source);
- if (ldap_url_parse(uri, &lud) != LDAP_SUCCESS)
- lud = NULL;
- g_free(uri);
+ sdialog->ok_button = glade_xml_get_widget (sdialog->gui, "ok-button");
+ g_signal_connect (sdialog->ok_button, "clicked",
+ G_CALLBACK(addressbook_add_server_dialog_finish), sdialog);
- sdialog->rootdn = glade_xml_get_widget (gui, "rootdn-entry");
- gtk_entry_set_text((GtkEntry *)sdialog->rootdn, lud && lud->lud_dn ? lud->lud_dn : "");
- g_signal_connect (sdialog->rootdn, "changed", G_CALLBACK (rootdn_changed_cb), sdialog);
+ sdialog->cancel_button = glade_xml_get_widget (sdialog->gui, "cancel-button");
+ g_signal_connect (sdialog->cancel_button, "clicked",
+ G_CALLBACK(addressbook_add_server_dialog_cancel), sdialog);
- sdialog->scope_optionmenu = glade_xml_get_widget (gui, "scope-optionmenu");
- switch (lud->lud_scope) {
- case LDAP_SCOPE_BASE:
- sdialog->scope = ADDRESSBOOK_LDAP_SCOPE_BASE;
- break;
- default:
- case LDAP_SCOPE_ONELEVEL:
- sdialog->scope = ADDRESSBOOK_LDAP_SCOPE_ONELEVEL;
- break;
- case LDAP_SCOPE_SUBTREE:
- sdialog->scope = ADDRESSBOOK_LDAP_SCOPE_SUBTREE;
- break;
- }
- gtk_option_menu_set_history (GTK_OPTION_MENU(sdialog->scope_optionmenu), sdialog->scope);
- g_signal_connect(sdialog->scope_optionmenu, "changed", G_CALLBACK(scope_optionmenu_changed_cb), sdialog);
+ g_object_weak_ref (G_OBJECT (sdialog->window),
+ addressbook_source_dialog_destroy, sdialog);
- g_signal_connect (glade_xml_get_widget(gui, "rootdn-button"), "clicked",
- G_CALLBACK(query_for_supported_bases), sdialog);
+ /* make sure we fill in the default values */
+ source_to_dialog (sdialog);
- if (lud)
- ldap_free_urldesc (lud);
+ gtk_window_set_type_hint (GTK_WINDOW (sdialog->window), GDK_WINDOW_TYPE_HINT_DIALOG);
+
+ add_folder_modify (sdialog->window, sdialog);
- g_object_unref(gui);
+ gtk_widget_show_all (sdialog->window);
- return w;
+ return sdialog;
}
static void
-timeout_changed_cb(GtkWidget *w, AddressbookSourceDialog *sdialog)
+editor_modify_cb (GtkWidget *item, AddressbookSourceDialog *dialog)
{
- char *timeout;
+ gboolean valid = TRUE;
- timeout = g_strdup_printf("%f", gtk_adjustment_get_value(((GtkRange *)sdialog->timeout_scale)->adjustment));
- e_source_set_property(sdialog->source, "timeout", timeout);
- g_free(timeout);
+ valid = display_name_check (dialog);
+#ifdef HAVE_LDAP
+ if (valid)
+ valid = general_tab_check (dialog);
+ if (valid)
+ valid = connecting_tab_check (dialog);
+ if (valid)
+ valid = searching_tab_check (dialog);
+#endif
+
+ gtk_widget_set_sensitive (dialog->ok_button, valid);
}
static void
-limit_changed_cb(GtkWidget *w, AddressbookSourceDialog *sdialog)
+set_advanced_button_state (AddressbookSourceDialog *dialog)
{
- char limit[16];
+ if (dialog->advanced) {
+ gtk_notebook_set_current_page (GTK_NOTEBOOK(dialog->advanced_button_notebook), 0);
+#ifdef NEW_ADVANCED_UI
+ gtk_notebook_append_page (GTK_NOTEBOOK(dialog->notebook), dialog->objectclasses_tab, dialog->objectclasses_label);
+ gtk_notebook_append_page (GTK_NOTEBOOK(dialog->notebook), dialog->mappings_tab, dialog->mappings_label);
+ gtk_notebook_append_page (GTK_NOTEBOOK(dialog->notebook), dialog->dn_customization_tab, dialog->dn_customization_label);
+#endif
+ }
+ else {
+#ifdef NEW_ADVANCED_UI
+ gtk_notebook_set_current_page (GTK_NOTEBOOK(dialog->advanced_button_notebook), 1);
+
+ /* hide the advanced tabs of the main notebook */
+ gtk_notebook_remove_page (GTK_NOTEBOOK(dialog->notebook), 5);
+ gtk_notebook_remove_page (GTK_NOTEBOOK(dialog->notebook), 4);
+ gtk_notebook_remove_page (GTK_NOTEBOOK(dialog->notebook), 3);
+#endif
+ }
+}
- sprintf(limit, "%d", gtk_spin_button_get_value_as_int((GtkSpinButton *)sdialog->limit_spinbutton));
- e_source_set_property(sdialog->source, "limit", limit);
+#ifdef NEW_ADVANCED_UI
+static void
+advanced_button_clicked (GtkWidget *button, AddressbookSourceDialog *dialog)
+{
+ dialog->advanced = !dialog->advanced;
+ set_advanced_button_state (dialog);
}
-static GtkWidget *
-eabc_details_limit(EConfig *ec, EConfigItem *item, struct _GtkWidget *parent, struct _GtkWidget *old, void *data)
+static gboolean
+do_schema_query (AddressbookSourceDialog *sdialog)
{
- AddressbookSourceDialog *sdialog = data;
- GtkWidget *w;
- const char *tmp;
- GladeXML *gui;
+ LDAP *ldap;
+ int ldap_error;
+ char *schema_dn;
+ char *attrs[3];
+ char **values;
+ int i;
+ AddressbookSource *source = addressbook_dialog_get_source (sdialog);
+ LDAPMessage *resp;
+ struct timeval timeout;
- if (!source_group_is_remote(sdialog->source_group))
- return NULL;
+ ldap = addressbook_ldap_init (sdialog->window, source);
+ if (!ldap)
+ goto fail;
- gui = glade_xml_new (EVOLUTION_GLADEDIR "/" GLADE_FILE_NAME, item->label, NULL);
- w = glade_xml_get_widget(gui, item->label);
- gtk_box_pack_start((GtkBox *)parent, w, FALSE, FALSE, 0);
+ if (LDAP_SUCCESS != addressbook_ldap_auth (sdialog->window, source, ldap))
+ goto fail;
- sdialog->timeout_scale = glade_xml_get_widget (gui, "timeout-scale");
- tmp = e_source_get_property(sdialog->source, "timeout");
- gtk_adjustment_set_value(((GtkRange *)sdialog->timeout_scale)->adjustment, tmp?g_strtod(tmp, NULL):3.0);
- g_signal_connect (GTK_RANGE(sdialog->timeout_scale)->adjustment, "value_changed", G_CALLBACK (timeout_changed_cb), sdialog);
+ attrs[0] = "subschemaSubentry";
+ attrs[1] = NULL;
- sdialog->limit_spinbutton = glade_xml_get_widget (gui, "download-limit-spinbutton");
- tmp = e_source_get_property(sdialog->source, "limit");
- gtk_spin_button_set_value((GtkSpinButton *)sdialog->limit_spinbutton, tmp?g_strtod(tmp, NULL):100.0);
- g_signal_connect (sdialog->limit_spinbutton, "value_changed", G_CALLBACK (limit_changed_cb), sdialog);
+ ldap_error = addressbook_root_dse_query (sdialog->window, source, ldap, attrs, &resp);
- g_object_unref(gui);
+ if (ldap_error != LDAP_SUCCESS)
+ goto fail;
- return w;
-}
-#endif
+ values = ldap_get_values (ldap, resp, "subschemaSubentry");
+ if (!values || values[0] == NULL) {
+ e_error_run ((GtkWindow *) sdialog->window, "addressbook:ldap-v3-schema", NULL);
+ goto fail;
+ }
-static EConfigItem eabc_items[] = {
- { E_CONFIG_BOOK, "", },
- { E_CONFIG_PAGE, "00.general", N_("General") },
- { E_CONFIG_SECTION, "00.general/10.display", N_("Addressbook") },
- { E_CONFIG_ITEM, "00.general/10.display/10.name", "hbox122", eabc_general_name },
- { E_CONFIG_ITEM, "00.general/10.display/20.offline", NULL, eabc_general_offline },
-#ifdef HAVE_LDAP
- { E_CONFIG_SECTION, "00.general/20.server", N_("Server Information") },
- { E_CONFIG_ITEM, "00.general/20.server/00.host", "table31", eabc_general_host },
- { E_CONFIG_SECTION, "00.general/30.auth", N_("Authentication") },
- { E_CONFIG_ITEM, "00.general/30.auth/00.auth", "table32", eabc_general_auth },
-
- { E_CONFIG_PAGE, "10.details", N_("Details") },
- { E_CONFIG_SECTION, "10.details/00.search", N_("Searching") },
- { E_CONFIG_ITEM, "10.details/00.search/00.search", "table33", eabc_details_search },
- { E_CONFIG_SECTION, "10.details/10.limit", N_("Downloading") },
- { E_CONFIG_ITEM, "10.details/10.limit/00.limit", "table34", eabc_details_limit },
-#endif
- { 0 },
-};
+ schema_dn = g_strdup (values[0]);
-/* items needed for the 'new addressbook' window */
-static EConfigItem eabc_new_items[] = {
- { E_CONFIG_ITEM, "00.general/10.display/00.type", NULL, eabc_general_type },
- { 0 },
-};
+ ldap_value_free (values);
+ ldap_msgfree (resp);
-static void
-eabc_commit(EConfig *ec, GSList *items, void *data)
-{
- AddressbookSourceDialog *sdialog = data;
- xmlNodePtr xml;
-#if d(!)0
- char *txt;
-#endif
- if (sdialog->original_source) {
- d(printf("committing addressbook changes\n"));
-
- /* these api's kinda suck */
- xml = xmlNewNode(NULL, "dummy");
- e_source_dump_to_xml_node(sdialog->source, xml);
- e_source_update_from_xml_node(sdialog->original_source, xml->children, NULL);
- xmlFreeNode(xml);
-#if d(!)0
- txt = e_source_to_standalone_xml(sdialog->original_source);
- printf("source is now:\n%s\n", txt);
- g_free(txt);
-#endif
- } else {
- d(printf("committing new source\n"));
- e_source_group_add_source(sdialog->source_group, sdialog->source, -1);
- e_source_list_sync(sdialog->source_list, NULL);
- }
+ attrs[0] = "objectClasses";
+ attrs[1] = NULL;
-#if d(!)0
- txt = e_source_to_standalone_xml(sdialog->source);
- printf("running source is now:\n%s\n", txt);
- g_free(txt);
-#endif
-}
+ timeout.tv_sec = (gint) gtk_adjustment_get_value (GTK_RANGE(sdialog->timeout_scale)->adjustment);
+ timeout.tv_usec = 0;
-static void
-eabc_free(EConfig *ec, GSList *items, void *data)
-{
- AddressbookSourceDialog *sdialog = data;
+ ldap_error = ldap_search_ext_s (ldap, schema_dn, LDAP_SCOPE_BASE,
+ "(objectClass=subschema)", attrs, 0,
+ NULL, NULL, &timeout, LDAP_NO_LIMIT, &resp);
+ if (LDAP_SUCCESS != ldap_error) {
+ e_error_run ((GtkWindow *) sdialog->window, "addressbook:ldap-get-schema", NULL);
+ goto fail;
+ }
- g_slist_free(items);
+ if (!(values = ldap_get_values (ldap, resp, "objectClasses"))) {
+ e_error_run ((GtkWindow *) sdialog->window, "addressbook:ldap-invalid-schema", NULL);
+ goto fail;
+ }
- g_object_unref(sdialog->source);
- if (sdialog->original_source)
- g_object_unref(sdialog->original_source);
- if (sdialog->source_list)
- g_object_unref(sdialog->source_list);
- g_slist_free(sdialog->menu_source_groups);
+ for (i = 0; values[i]; i ++) {
+ int j;
+ int code;
+ const char *err;
+ LDAPObjectClass *oc = ldap_str2objectclass (values[i], &code, &err, 0);
+
+ if (!oc)
+ continue;
+
+ /* we fill in the default list of classes here */
+ for (j = 0; oc->oc_names[j]; j ++) {
+ if (!g_strcasecmp (oc->oc_names[j], EVOLUTIONPERSON) ||
+ !g_strcasecmp (oc->oc_names[j], INETORGPERSON) ||
+ !g_strcasecmp (oc->oc_names[j], ORGANIZATIONALPERSON) ||
+ !g_strcasecmp (oc->oc_names[j], PERSON) ||
+ !g_strcasecmp (oc->oc_names[j], CALENTRY) ||
+ !g_strcasecmp (oc->oc_names[j], TOP))
+ g_ptr_array_add (sdialog->default_objectclasses, oc);
+ }
- g_object_unref(sdialog->gui);
+ g_ptr_array_add (sdialog->server_objectclasses, oc);
+ }
- g_free(sdialog);
+ addressbook_source_free (source);
+ ldap_unbind_s (ldap);
+ return TRUE;
+
+ fail:
+ addressbook_source_free (source);
+ if (ldap)
+ ldap_unbind_s (ldap);
+ return FALSE;
}
-static gboolean
-eabc_check_complete(EConfig *ec, const char *pageid, void *data)
+static void
+edit_dialog_switch_page (GtkNotebook *notebook,
+ GtkNotebookPage *page, guint page_num,
+ AddressbookSourceDialog *sdialog)
{
- AddressbookSourceDialog *sdialog = data;
- int valid = TRUE;
- const char *tmp;
- ESource *source;
+ if (page_num >= 3 && !sdialog->schema_query_successful) {
+ int i;
- d(printf("check complete, pageid = '%s'\n", pageid?pageid:"<all>"));
- /* have name, and unique */
- tmp = e_source_peek_name(sdialog->source);
- valid = tmp && tmp[0] != 0
- && ((source = e_source_group_peek_source_by_name(sdialog->source_group, tmp)) == NULL
- || source == sdialog->original_source);
+ gtk_widget_set_sensitive (GTK_WIDGET (notebook), FALSE);
-#ifdef HAVE_LDAP
- if (valid && source_group_is_remote(sdialog->source_group)) {
- char *uri = e_source_get_uri(sdialog->source);
- LDAPURLDesc *lud;
-
- /* check host and port set */
- if (ldap_url_parse(uri, &lud) == LDAP_SUCCESS) {
- valid = lud->lud_host != NULL
- && lud->lud_host[0] != 0
- && lud->lud_port != 0;
- ldap_free_urldesc (lud);
- } else
- valid = FALSE;
- g_free(uri);
-
- /* check auth name provided if auth set */
- if (valid && (tmp = e_source_get_property(sdialog->source, "auth"))) {
- switch (ldap_parse_auth(tmp)) {
- case ADDRESSBOOK_LDAP_AUTH_SIMPLE_EMAIL:
- tmp = e_source_get_property(sdialog->source, "email_addr");
- break;
- case ADDRESSBOOK_LDAP_AUTH_SIMPLE_BINDDN:
- tmp = e_source_get_property(sdialog->source, "binddn");
- break;
- default:
- tmp = "dummy";
- break;
+ sdialog->schema_query_successful = do_schema_query (sdialog);
+
+ if (sdialog->schema_query_successful) {
+ /* fill in the objectclasses model */
+ for (i = 0; i < sdialog->server_objectclasses->len; i ++) {
+ LDAPObjectClass *oc = g_ptr_array_index (sdialog->server_objectclasses, i);
+ e_table_memory_store_insert (E_TABLE_MEMORY_STORE (sdialog->objectclasses_server_model),
+ -1, oc, oc->oc_names[0]);
}
- valid = tmp && tmp[0];
+ gtk_widget_set_sensitive (page->child, TRUE);
}
-
- /* check timeout isn't too short (why don't we just force it?) */
- if (valid) {
- tmp = e_source_get_property(sdialog->source, "timeout");
- valid = tmp && g_strtod(tmp, NULL) > 0.0;
+ else {
+ gtk_widget_set_sensitive (page->child, FALSE);
}
+
+ gtk_widget_set_sensitive (GTK_WIDGET (notebook), TRUE);
}
+}
#endif
- return valid;
+
+static gboolean
+edit_dialog_store_change (AddressbookSourceDialog *sdialog)
+{
+ dialog_to_source (sdialog, sdialog->source, FALSE);
+
+ /* check the display name for uniqueness */
+ if (FALSE /* XXX */) {
+ return FALSE;
+ }
+
+ return TRUE;
}
-/* debug only: */
-#if d(!)0
static void
-source_changed(ESource *source, AddressbookSourceDialog *sdialog)
+edit_dialog_cancel_clicked (GtkWidget *item, AddressbookSourceDialog *sdialog)
{
- char *xml;
+ gtk_widget_destroy (sdialog->window);
+}
- xml = e_source_to_standalone_xml(source);
- printf("source changed:\n%s\n", xml);
- g_free(xml);
+static void
+edit_dialog_ok_clicked (GtkWidget *item, AddressbookSourceDialog *sdialog)
+{
+ if (edit_dialog_store_change (sdialog)) {
+ gtk_widget_destroy (sdialog->window);
+ }
}
-#endif
GtkWidget*
addressbook_config_edit_source (GtkWidget *parent, ESource *source)
{
AddressbookSourceDialog *sdialog = g_new0 (AddressbookSourceDialog, 1);
- EABConfig *ec;
- int i;
- GSList *items = NULL;
- EABConfigTargetSource *target;
- char *xml;
-
- sdialog->gui = glade_xml_new (EVOLUTION_GLADEDIR "/" GLADE_FILE_NAME, "account-editor-notebook", NULL);
-
- if (source) {
- sdialog->original_source = source;
- g_object_ref(source);
- sdialog->source_group = e_source_peek_group (source);
- xml = e_source_to_standalone_xml(source);
- sdialog->source = e_source_new_from_standalone_xml(xml);
- g_free(xml);
- } else {
- GConfClient *gconf;
- GSList *l;
-
- sdialog->source = e_source_new("", "");
- gconf = gconf_client_get_default();
- sdialog->source_list = e_source_list_new_for_gconf(gconf, "/apps/evolution/addressbook/sources");
- l = e_source_list_peek_groups(sdialog->source_list);
- if (!l) {
- g_warning ("Addressbook source groups are missing! Check your GConf setup.");
- g_free (sdialog);
- return NULL;
- }
+ GConfClient *gconf_client;
- sdialog->menu_source_groups = g_slist_copy(l);
-#ifndef HAVE_LDAP
- for (;l;l = g_slist_next(l))
- if (!strncmp("ldap:", e_source_group_peek_base_uri(l->data), 5))
- sdialog->menu_source_groups = g_slist_remove (sdialog->menu_source_groups, l->data);
-#endif
- sdialog->source_group = (ESourceGroup *)sdialog->menu_source_groups->data;
- for (i=0;eabc_new_items[i].path;i++)
- items = g_slist_prepend(items, &eabc_new_items[i]);
- g_object_unref(gconf);
- }
+ gconf_client = gconf_client_get_default ();
+ sdialog->source_list = e_source_list_new_for_gconf (gconf_client, "/apps/evolution/addressbook/sources");
+ g_object_unref (gconf_client);
+
+ sdialog->gui = glade_xml_new (EVOLUTION_GLADEDIR "/" GLADE_FILE_NAME, "account-editor-window", NULL);
+ sdialog->window = glade_xml_get_widget (sdialog->gui, "account-editor-window");
+ gtk_widget_realize (sdialog->window);
+ gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (sdialog->window)->vbox), 0);
+ gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (sdialog->window)->action_area), 12);
- /* HACK: doesn't work if you don't do this */
- e_source_set_absolute_uri(sdialog->source, NULL);
- e_source_set_group(sdialog->source, sdialog->source_group);
+ sdialog->source = source;
+ sdialog->source_group = e_source_peek_group (source);
-#if d(!)0
- xml = e_source_to_standalone_xml(sdialog->source);
- printf("but working standalone xml: %s\n", xml);
- g_free(xml);
- g_signal_connect(sdialog->source, "changed", source_changed, sdialog);
+ sdialog->display_name = glade_xml_get_widget (sdialog->gui, "account-editor-display-name-entry");
+ g_signal_connect (sdialog->display_name, "changed",
+ G_CALLBACK (editor_modify_cb), sdialog);
+
+ setup_general_tab (sdialog, editor_modify_cb);
+#ifdef HAVE_LDAP
+ setup_connecting_tab (sdialog, editor_modify_cb);
+
+ setup_searching_tab (sdialog, editor_modify_cb);
#endif
- sdialog->config = ec = eab_config_new(E_CONFIG_BOOK, "com.novell.evolution.addressbook.config.accountEditor");
+ sdialog->notebook = glade_xml_get_widget (sdialog->gui, "account-editor-notebook");
- for (i=0;eabc_items[i].path;i++)
- items = g_slist_prepend(items, &eabc_items[i]);
+ sdialog->ok_button = glade_xml_get_widget (sdialog->gui, "account-editor-ok-button");
+ sdialog->cancel_button = glade_xml_get_widget (sdialog->gui, "account-editor-cancel-button");
+
+#ifdef HAVE_LDAP
+ if (strcmp ("ldap://", e_source_group_peek_base_uri (sdialog->source_group))) {
+ gtk_widget_hide (glade_xml_get_widget (sdialog->gui, "account-editor-connecting-vbox"));
+ gtk_widget_hide (glade_xml_get_widget (sdialog->gui, "account-editor-searching-vbox"));
+ gtk_notebook_set_show_tabs (GTK_NOTEBOOK (sdialog->notebook), FALSE);
+ gtk_notebook_set_show_border (GTK_NOTEBOOK (sdialog->notebook), FALSE);
+ gtk_container_set_border_width (GTK_CONTAINER (glade_xml_get_widget (sdialog->gui, "account-editor-general-vbox")), 0);
+ gtk_window_set_default_size (GTK_WINDOW (sdialog->window), 332, 124);
+ } else {
+ gtk_widget_show (glade_xml_get_widget (sdialog->gui, "account-editor-connecting-vbox"));
+ gtk_widget_show (glade_xml_get_widget (sdialog->gui, "account-editor-searching-vbox"));
+ }
+#else
+ gtk_widget_hide (glade_xml_get_widget (sdialog->gui, "account-editor-connecting-vbox"));
+ gtk_widget_hide (glade_xml_get_widget (sdialog->gui, "account-editor-searching-vbox"));
+ gtk_notebook_set_show_tabs (GTK_NOTEBOOK (sdialog->notebook), FALSE);
+ gtk_notebook_set_show_border (GTK_NOTEBOOK (sdialog->notebook), FALSE);
+ gtk_container_set_border_width (GTK_CONTAINER (glade_xml_get_widget (sdialog->gui, "account-editor-general-vbox")), 0);
+#endif
- e_config_add_items((EConfig *)ec, items, eabc_commit, NULL, eabc_free, sdialog);
- e_config_add_page_check((EConfig *)ec, NULL, eabc_check_complete, sdialog);
+ source_to_dialog (sdialog);
- target = eab_config_target_new_source(ec, sdialog->source);
- e_config_set_target((EConfig *)ec, (EConfigTarget *)target);
+ set_advanced_button_state (sdialog);
- if(source)
- sdialog->window = e_config_create_window((EConfig *)ec, NULL, _("Address Book Properties"));
- else
- sdialog->window = e_config_create_window((EConfig *)ec, NULL, _("New Address Book"));
+ g_signal_connect (sdialog->ok_button,
+ "clicked", G_CALLBACK(edit_dialog_ok_clicked), sdialog);
+ g_signal_connect (sdialog->cancel_button,
+ "clicked", G_CALLBACK(edit_dialog_cancel_clicked), sdialog);
+ g_object_weak_ref (G_OBJECT (sdialog->window),
+ addressbook_source_dialog_destroy, sdialog);
+ gtk_widget_set_sensitive (sdialog->ok_button, FALSE);
- /* forces initial validation */
- if (!sdialog->original_source)
- e_config_target_changed((EConfig *)ec, E_CONFIG_TARGET_CHANGED_STATE);
+ gtk_widget_show (sdialog->window);
return sdialog->window;
}
+
+GtkWidget*
+addressbook_config_create_new_source (GtkWidget *parent)
+{
+ AddressbookSourceDialog *dialog;
+
+ dialog = addressbook_add_server_dialog ();
+
+ return dialog ? dialog->window : NULL;
+}
diff --git a/addressbook/gui/component/addressbook-view.c b/addressbook/gui/component/addressbook-view.c
index f8b4802c0d..368c0c4540 100644
--- a/addressbook/gui/component/addressbook-view.c
+++ b/addressbook/gui/component/addressbook-view.c
@@ -21,9 +21,7 @@
* Author: Chris Toshok (toshok@ximian.com)
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-#endif
#include <string.h>
#include <glib.h>
@@ -39,12 +37,11 @@
#include <bonobo/bonobo-ui-util.h>
#include <bonobo/bonobo-exception.h>
#include <gal/util/e-util.h>
-#include <libedataserverui/e-source-selector.h>
#include "widgets/misc/e-error.h"
#include "widgets/misc/e-task-bar.h"
#include "widgets/misc/e-info-label.h"
-
+#include "widgets/misc/e-source-selector.h"
#include "e-util/e-passwords.h"
#include "e-util/e-icon-factory.h"
@@ -63,8 +60,6 @@
#include "addressbook/gui/merging/eab-contact-merging.h"
#include "addressbook/printing/e-contact-print.h"
#include "addressbook/util/eab-book-util.h"
-#include "addressbook/gui/widgets/eab-popup.h"
-#include "addressbook/gui/widgets/eab-menu.h"
#define PARENT_TYPE G_TYPE_OBJECT
static GObjectClass *parent_class = NULL;
@@ -96,8 +91,6 @@ struct _AddressbookViewPrivate {
ESourceList *source_list;
char *passwd;
EUserCreatableItemsHandler *creatable_items_handler;
-
- EABMenu *menu;
};
enum DndTargetType {
@@ -342,20 +335,14 @@ update_command_state (EABView *eav, AddressbookView *view)
{
AddressbookViewPrivate *priv = view->priv;
BonoboUIComponent *uic;
- EABMenuTargetSelect *target;
if (eav != get_current_view (view))
return;
g_object_ref (view);
- target = eab_view_get_menu_target(eav, priv->menu);
- e_menu_update_target((EMenu *)priv->menu, target);
-
uic = bonobo_control_get_ui_component (priv->folder_view_control);
- /* TODO: this stuff can mostly be made to use the target bits instead */
-
if (bonobo_ui_component_get_container (uic) != CORBA_OBJECT_NIL) {
#define SET_SENSITIVE(verb,f) \
bonobo_ui_component_set_prop (uic, (verb), "sensitive", (f)(eav) ? "1" : "0", NULL)
@@ -475,11 +462,9 @@ control_activate_cb (BonoboControl *control,
if (activate) {
control_activate (control, uic, view);
- e_menu_activate((EMenu *)view->priv->menu, uic, activate);
if (activate && v && v->model)
eab_model_force_folder_bar_message (v->model);
} else {
- e_menu_activate((EMenu *)view->priv->menu, uic, activate);
bonobo_ui_component_unset_container (uic, NULL);
eab_view_discard_menus (v);
}
@@ -628,10 +613,45 @@ load_primary_selection (AddressbookView *view)
}
/* Folder popup menu callbacks */
+
+static void
+add_popup_menu_item (GtkMenu *menu, const char *label, const char *pixmap,
+ GCallback callback, gpointer user_data, gboolean sensitive)
+{
+ GtkWidget *item, *image;
+
+ if (pixmap) {
+ item = gtk_image_menu_item_new_with_label (label);
+
+ /* load the image */
+ if (g_file_test (pixmap, G_FILE_TEST_EXISTS))
+ image = gtk_image_new_from_file (pixmap);
+ else
+ image = gtk_image_new_from_stock (pixmap, GTK_ICON_SIZE_MENU);
+
+ if (image) {
+ gtk_widget_show (image);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
+ }
+ } else {
+ item = gtk_menu_item_new_with_label (label);
+ }
+
+ if (callback)
+ g_signal_connect (G_OBJECT (item), "activate", callback, user_data);
+
+ if (!sensitive)
+ gtk_widget_set_sensitive (item, FALSE);
+
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+ gtk_widget_show (item);
+}
+
typedef struct {
AddressbookView *view;
ESource *selected_source;
GtkWidget *toplevel;
+ GtkWidget *dialog;
} BookRemovedClosure;
static void
@@ -641,6 +661,7 @@ book_removed (EBook *book, EBookStatus status, gpointer data)
AddressbookView *view = closure->view;
AddressbookViewPrivate *priv = view->priv;
ESource *source = closure->selected_source;
+ GtkWidget *dialog = closure->dialog;
GtkWidget *toplevel = closure->toplevel;
g_free (closure);
@@ -663,54 +684,73 @@ book_removed (EBook *book, EBookStatus status, gpointer data)
"addressbook:remove-addressbook",
NULL);
}
+
+ gtk_widget_destroy (dialog);
}
static void
-delete_addressbook_cb(EPopup *ep, EPopupItem *pitem, void *data)
+delete_addressbook_cb (GtkWidget *widget, AddressbookView *view)
{
- AddressbookView *view = data;
AddressbookViewPrivate *priv = view->priv;
ESource *selected_source;
+ GtkWidget *dialog;
EBook *book;
GError *error = NULL;
- GtkWindow *toplevel;
selected_source = e_source_selector_peek_primary_selection (E_SOURCE_SELECTOR (priv->selector));
if (!selected_source)
return;
- toplevel = (GtkWindow *)gtk_widget_get_toplevel(ep->target->widget);
+ /* Create the confirmation dialog */
+ dialog = gtk_message_dialog_new (
+ GTK_WINDOW (gtk_widget_get_toplevel (widget)),
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_YES_NO,
+ _("Address book '%s' will be removed. Are you sure you want to continue?"),
+ e_source_peek_name (selected_source));
+#if !GTK_CHECK_VERSION (2,4,0)
+ gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
+#endif
- if (e_error_run(toplevel, "addressbook:ask-delete-addressbook", e_source_peek_name(selected_source)) != GTK_RESPONSE_YES)
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_YES) {
+ gtk_widget_destroy (dialog);
return;
+ }
/* Remove local data */
book = e_book_new (selected_source, &error);
if (book) {
BookRemovedClosure *closure = g_new (BookRemovedClosure, 1);
- closure->toplevel = (GtkWidget *)toplevel;
+ closure->toplevel = gtk_widget_get_toplevel (widget);
closure->view = view;
closure->selected_source = selected_source;
+ closure->dialog = dialog;
if (e_book_async_remove (book, book_removed, closure)) {
- e_error_run (toplevel, "addressbook:remove-addressbook", NULL);
+ e_error_run (GTK_WINDOW (gtk_widget_get_toplevel (widget)),
+ "addressbook:remove-addressbook",
+ NULL);
+
g_free (closure);
+
g_object_unref (book);
}
}
+
+ gtk_widget_set_sensitive (dialog, FALSE);
}
static void
-new_addressbook_cb(EPopup *ep, EPopupItem *pitem, void *data)
+new_addressbook_cb (GtkWidget *widget, AddressbookView *view)
{
- addressbook_config_create_new_source (gtk_widget_get_toplevel(ep->target->widget));
+ addressbook_config_create_new_source (gtk_widget_get_toplevel (widget));
}
static void
-edit_addressbook_cb(EPopup *ep, EPopupItem *pitem, void *data)
+edit_addressbook_cb (GtkWidget *widget, AddressbookView *view)
{
- AddressbookView *view = data;
AddressbookViewPrivate *priv = view->priv;
ESource *selected_source;
const char *uid;
@@ -728,7 +768,7 @@ edit_addressbook_cb(EPopup *ep, EPopupItem *pitem, void *data)
char *uid_copy = g_strdup (uid);
closure = g_new (EditorUidClosure, 1);
- closure->editor = addressbook_config_edit_source (gtk_widget_get_toplevel(ep->target->widget), selected_source);
+ closure->editor = addressbook_config_edit_source (gtk_widget_get_toplevel (widget), selected_source);
closure->uid = uid_copy;
closure->view = view;
@@ -753,41 +793,25 @@ primary_source_selection_changed_callback (ESourceSelector *selector,
save_primary_selection (view);
}
-static EPopupItem abv_source_popups[] = {
- { E_POPUP_ITEM, "10.new", N_("New Address Book"), new_addressbook_cb, NULL, "stock_contact", 0, 0 },
- { E_POPUP_ITEM, "20.delete", N_("Delete"), delete_addressbook_cb, NULL, "stock_delete", 0, EAB_POPUP_SOURCE_USER|EAB_POPUP_SOURCE_PRIMARY },
- { E_POPUP_BAR, "30.bar"},
- { E_POPUP_ITEM, "30.properties", N_("Properties..."), edit_addressbook_cb, NULL,"stock_folder-properties", 0, EAB_POPUP_SOURCE_PRIMARY },
-};
static void
-abv_source_popup_free(EPopup *ep, GSList *list, void *data)
-{
- g_slist_free(list);
-}
-
-static gboolean
-popup_event_callback(ESourceSelector *selector, ESource *source, GdkEventButton *event, AddressbookView *view)
+fill_popup_menu_callback (ESourceSelector *selector, GtkMenu *menu, AddressbookView *view)
{
- EABPopup *ep;
- EABPopupTargetSource *t;
- GSList *menus = NULL;
- int i;
- GtkMenu *menu;
-
- ep = eab_popup_new("org.gnome.evolution.addressbook.source.popup");
- t = eab_popup_target_new_source(ep, selector);
- t->target.widget = (GtkWidget *)view->priv->notebook;
-
- for (i=0;i<sizeof(abv_source_popups)/sizeof(abv_source_popups[0]);i++)
- menus = g_slist_prepend(menus, &abv_source_popups[i]);
-
- e_popup_add_items((EPopup *)ep, menus, NULL, abv_source_popup_free, view);
+ AddressbookViewPrivate *priv = view->priv;
+ gboolean sensitive;
+ gboolean local_addressbook;
+ ESource *selected_source;
+ char *uri;
- menu = e_popup_create_menu_once((EPopup *)ep, (EPopupTarget *)t, 0);
- gtk_menu_popup(menu, NULL, NULL, NULL, NULL, event?event->button:0, event?event->time:gtk_get_current_event_time());
+ selected_source = e_source_selector_peek_primary_selection (E_SOURCE_SELECTOR (priv->selector));
+ sensitive = selected_source ? TRUE : FALSE;
- return TRUE;
+ uri = e_source_peek_relative_uri (selected_source);
+ local_addressbook = (uri && !strcmp ("system", uri));
+
+ add_popup_menu_item (menu, _("New Address Book"), NULL, G_CALLBACK (new_addressbook_cb), view, TRUE);
+ add_popup_menu_item (menu, _("Delete"), GTK_STOCK_DELETE, G_CALLBACK (delete_addressbook_cb), view, sensitive && !local_addressbook);
+ add_popup_menu_item (menu, _("Properties..."), NULL, G_CALLBACK (edit_addressbook_cb), view, sensitive);
}
static gboolean
@@ -953,13 +977,15 @@ selector_tree_drag_data_received (GtkWidget *widget,
{
GtkTreePath *path = NULL;
GtkTreeViewDropPosition pos;
- gpointer target = NULL;
+ gpointer source, target = NULL;
GtkTreeModel *model;
GtkTreeIter iter;
gboolean success = FALSE;
+
EBook *source_book, *target_book;
MergeContext *merge_context;
GList *contactlist;
+ GList *l;
if (!gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (widget),
x, y, &path, &pos))
@@ -1075,7 +1101,6 @@ addressbook_view_init (AddressbookView *view)
{
AddressbookViewPrivate *priv;
GtkWidget *selector_scrolled_window;
- AtkObject *a11y;
view->priv =
priv = g_new0 (AddressbookViewPrivate, 1);
@@ -1102,7 +1127,6 @@ addressbook_view_init (AddressbookView *view)
G_CALLBACK (source_list_changed_cb), view);
priv->creatable_items_handler = e_user_creatable_items_handler_new ("contacts", NULL, NULL);
- priv->menu = eab_menu_new("org.gnome.evolution.addressbook.view");
g_signal_connect (priv->folder_view_control, "activate",
G_CALLBACK (control_activate_cb), view);
@@ -1126,8 +1150,6 @@ addressbook_view_init (AddressbookView *view)
g_signal_connect (priv->selector, "drag-drop", G_CALLBACK (selector_tree_drag_drop), view);
g_signal_connect (priv->selector, "drag-data-received", G_CALLBACK (selector_tree_drag_data_received), view);
gtk_drag_dest_set (priv->selector, GTK_DEST_DEFAULT_ALL, drag_types, num_drag_types, GDK_ACTION_COPY | GDK_ACTION_MOVE);
- a11y = gtk_widget_get_accessible (GTK_WIDGET (priv->selector));
- atk_object_set_name (a11y, _("Contact Source Selector"));
e_source_selector_show_selection (E_SOURCE_SELECTOR (priv->selector), FALSE);
gtk_widget_show (priv->selector);
@@ -1147,8 +1169,8 @@ addressbook_view_init (AddressbookView *view)
g_signal_connect_object (priv->selector, "primary_selection_changed",
G_CALLBACK (primary_source_selection_changed_callback),
G_OBJECT (view), 0);
- g_signal_connect_object (priv->selector, "popup_event",
- G_CALLBACK (popup_event_callback),
+ g_signal_connect_object (priv->selector, "fill_popup_menu",
+ G_CALLBACK (fill_popup_menu_callback),
G_OBJECT (view), 0);
load_primary_selection (view);
@@ -1194,9 +1216,6 @@ addressbook_view_dispose (GObject *object)
if (priv->creatable_items_handler)
g_object_unref (priv->creatable_items_handler);
- if (priv->menu)
- g_object_unref (priv->menu);
-
g_free (view->priv);
view->priv = NULL;
}
diff --git a/addressbook/gui/component/addressbook.c b/addressbook/gui/component/addressbook.c
index b389cfa78c..cbf908c17f 100644
--- a/addressbook/gui/component/addressbook.c
+++ b/addressbook/gui/component/addressbook.c
@@ -29,7 +29,7 @@
#include <libebook/e-book.h>
#include "e-util/e-passwords.h"
-#include "widgets/misc/e-error.h"
+
#include "addressbook.h"
#define d(x)
@@ -82,53 +82,45 @@ load_source_auth_cb (EBook *book, EBookStatus status, gpointer closure)
/* the user clicked cancel in the password dialog */
if (status == E_BOOK_ERROR_CANCELLED) {
-
+
if (e_book_check_static_capability (book, "anon-access")) {
-
- GtkWidget *dialog;
-
- /* XXX "LDAP" has to be removed from the folowing message
- so that it wil valid for other servers which provide
- anonymous access*/
-
- dialog = gtk_message_dialog_new (NULL,
- 0,
- GTK_MESSAGE_WARNING,
- GTK_BUTTONS_OK,
- _("Accessing LDAP Server anonymously"));
- g_signal_connect (dialog, "response", G_CALLBACK(gtk_widget_destroy), NULL);
- gtk_widget_show (dialog);
- data->cb (book, E_BOOK_ERROR_OK, data->closure);
- free_load_source_data (data);
- return;
- }
- } else if (status == E_BOOK_ERROR_INVALID_SERVER_VERSION) {
- e_error_run (NULL, "addressbook:server-version", NULL);
- status = E_BOOK_ERROR_OK;
- if (data->cb)
- data->cb (book, status, data->closure);
+
+ GtkWidget *dialog;
+
+ /* XXX "LDAP" has to be removed from the folowing message
+ so that it wil valid for other servers which provide
+ anonymous access*/
+
+ dialog = gtk_message_dialog_new (NULL,
+ 0,
+ GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_OK,
+ _("Accessing LDAP Server anonymously"));
+ g_signal_connect (dialog, "response", G_CALLBACK(gtk_widget_destroy), NULL);
+ gtk_widget_show (dialog);
+ data->cb (book, E_BOOK_ERROR_OK, data->closure);
free_load_source_data (data);
return;
-
- } else {
+ }
+ }
+ else {
gchar *uri = e_source_get_uri (data->source);
gchar *stripped_uri = remove_parameters_from_uri (uri);
const gchar *auth_domain = e_source_get_property (data->source, "auth-domain");
- const gchar *component_name;
-
+ const gchar *component_name;
+
component_name = auth_domain ? auth_domain : "Addressbook";
-
+
e_passwords_forget_password (component_name, stripped_uri);
addressbook_authenticate (book, TRUE, data->source, load_source_auth_cb, closure);
-
+
g_free (stripped_uri);
g_free (uri);
return;
}
}
- if (data->cb)
- data->cb (book, status, data->closure);
+ data->cb (book, status, data->closure);
free_load_source_data (data);
}
@@ -184,7 +176,6 @@ addressbook_authenticate (EBook *book, gboolean previous_failure, ESource *sourc
if (!password) {
char *prompt;
- char *password_prompt;
gboolean remember;
char *failed_auth;
guint32 flags = E_PASSWORDS_REMEMBER_FOREVER|E_PASSWORDS_SECRET|E_PASSWORDS_ONLINE;
@@ -197,11 +188,8 @@ addressbook_authenticate (EBook *book, gboolean previous_failure, ESource *sourc
failed_auth = "";
}
- password_prompt = g_strdup_printf (_("Enter password for %s (user %s)"),
- e_source_peek_name (source), user);
-
- prompt = g_strconcat (failed_auth, password_prompt, NULL);
- g_free (password_prompt);
+ prompt = g_strdup_printf (_("%sEnter password for %s (user %s)"),
+ failed_auth, e_source_peek_name (source), user);
remember = get_remember_password (source);
pass_dup = e_passwords_ask_password (prompt, component_name, uri, prompt,
@@ -221,28 +209,12 @@ addressbook_authenticate (EBook *book, gboolean previous_failure, ESource *sourc
}
else {
/* they hit cancel */
-
- cb (book, E_BOOK_ERROR_CANCELLED, closure);
+ cb (book, E_BOOK_ERROR_CANCELLED, closure);
}
g_free (uri);
}
-
-
-static void
-auth_required_cb (EBook *book, gpointer data)
-{
- LoadSourceData *load_source_data = g_new0(LoadSourceData, 1);
-
- load_source_data->source = g_object_ref (g_object_ref (e_book_get_source (book)));
- load_source_data->cancelled = FALSE;
- addressbook_authenticate (book, FALSE, load_source_data->source,
- load_source_auth_cb, load_source_data);
-
-
-
-}
static void
load_source_cb (EBook *book, EBookStatus status, gpointer closure)
{
@@ -257,16 +229,17 @@ load_source_cb (EBook *book, EBookStatus status, gpointer closure)
const gchar *auth;
auth = e_source_get_property (load_source_data->source, "auth");
+
+ /* check if the addressbook needs authentication */
+
if (auth && strcmp (auth, "none")) {
- g_signal_connect (book, "auth_required", auth_required_cb, NULL);
-
- if (e_book_is_online (book)) {
- addressbook_authenticate (book, FALSE, load_source_data->source,
- load_source_auth_cb, closure);
- return;
- }
+ addressbook_authenticate (book, FALSE, load_source_data->source,
+ load_source_auth_cb, closure);
+
+ return;
}
}
+
load_source_data->cb (book, status, load_source_data->closure);
free_load_source_data (load_source_data);
}
diff --git a/addressbook/gui/component/apps_evolution_addressbook.schemas.in.in b/addressbook/gui/component/apps_evolution_addressbook.schemas.in.in
index 010073331e..0de9b142f7 100644
--- a/addressbook/gui/component/apps_evolution_addressbook.schemas.in.in
+++ b/addressbook/gui/component/apps_evolution_addressbook.schemas.in.in
@@ -10,8 +10,8 @@
<type>string</type>
<default></default>
<locale name="C">
- <short>EFolderList XML for the list of completion URIs</short>
- <long>EFolderList XML for the list of completion URIs.</long>
+ <short>EFolderList xml for the list of completion uris</short>
+ <long>EFolderList xml for the list of completion uris</long>
</locale>
</schema>
@@ -22,8 +22,8 @@
<type>int</type>
<default>3</default>
<locale name="C">
- <short>Autocomplete length</short>
- <long>The number of characters that must be typed before Evolution will attempt to autocomplete.</long>
+ <short>The number of characters that must be typed before evolution will attempt to autocomplete</short>
+ <long>The number of characters that must be typed before evolution will attempt to autocomplete</long>
</locale>
</schema>
@@ -37,7 +37,7 @@
<default></default>
<locale name="C">
<short>URI for the folder last used in the select names dialog</short>
- <long>URI for the folder last used in the select names dialog.</long>
+ <long>URI for the folder last used in the select names dialog</long>
</locale>
</schema>
@@ -49,8 +49,8 @@
<owner>evolution-addressbook</owner>
<type>int</type>
<locale name="C">
- <short>Vertical pane position</short>
- <long>Position of the vertical pane, between the card and list views and the preview pane, in pixels.</long>
+ <short>Position of the vertical pane in main view</short>
+ <long>Position of the vertical pane in main view</long>
</locale>
</schema>
@@ -61,8 +61,8 @@
<type>bool</type>
<default>true</default>
<locale name="C">
- <short>Show preview pane</short>
- <long>Whether to show the preview pane.</long>
+ <short>Show the "Preview" pane</short>
+ <long>Show the "Preview" pane</long>
</locale>
</schema>
diff --git a/addressbook/gui/component/component-factory.c b/addressbook/gui/component/component-factory.c
index 4aaee9637b..382722785e 100644
--- a/addressbook/gui/component/component-factory.c
+++ b/addressbook/gui/component/component-factory.c
@@ -30,6 +30,7 @@
#include "autocompletion-config.h"
#include "eab-popup-control.h"
#include "eab-vcard-control.h"
+#include "select-names/e-select-names-bonobo.h"
#ifdef ENABLE_SMIME
#include "smime/gui/certificate-manager.h"
#endif
@@ -41,6 +42,7 @@
#define VCARD_CONTROL_ID "OAFIID:GNOME_Evolution_Addressbook_VCard_Control:" BASE_VERSION
#define COMPONENT_ID "OAFIID:GNOME_Evolution_Addressbook_Component:" BASE_VERSION
#define ADDRESS_POPUP_ID "OAFIID:GNOME_Evolution_Addressbook_AddressPopup:" BASE_VERSION
+#define SELECT_NAMES_ID "OAFIID:GNOME_Evolution_Addressbook_SelectNames:" BASE_VERSION
#define COMPLETION_CONFIG_CONTROL_ID "OAFIID:GNOME_Evolution_Addressbook_Autocompletion_ConfigControl:" BASE_VERSION
#define CERTIFICATE_MANAGER_CONFIG_CONTROL_ID "OAFIID:GNOME_Evolution_SMime_CertificateManager_ConfigControl:" BASE_VERSION
@@ -65,6 +67,8 @@ factory (BonoboGenericFactory *factory,
return BONOBO_OBJECT (eab_popup_control_new ());
if (strcmp (component_id, COMPLETION_CONFIG_CONTROL_ID) == 0)
return BONOBO_OBJECT (autocompletion_config_control_new ());
+ if (strcmp (component_id, SELECT_NAMES_ID) == 0)
+ return BONOBO_OBJECT (e_select_names_bonobo_new ());
#ifdef ENABLE_SMIME
if (strcmp (component_id, CERTIFICATE_MANAGER_CONFIG_CONTROL_ID) == 0)
return BONOBO_OBJECT (certificate_manager_config_control_new ());
diff --git a/addressbook/gui/contact-editor/e-contact-editor.c b/addressbook/gui/contact-editor/e-contact-editor.c
index 2cd7984337..6d1e0581a6 100644
--- a/addressbook/gui/contact-editor/e-contact-editor.c
+++ b/addressbook/gui/contact-editor/e-contact-editor.c
@@ -34,18 +34,20 @@
#include <gtk/gtkstock.h>
#include <gtk/gtkentry.h>
#include <gtk/gtklabel.h>
+#include <libgnomeui/gnome-popup-menu.h>
#include <libgnomeui/gnome-window-icon.h>
#include <libgnome/gnome-util.h>
#include <libgnome/gnome-i18n.h>
#include <libgnome/gnome-help.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
-#include <libedataserverui/e-categories-dialog.h>
+#include <gal/widgets/e-categories.h>
#include <gal/widgets/e-gui-utils.h>
#include <gal/e-text/e-entry.h>
#include <libebook/e-address-western.h>
-#include <libedataserverui/e-source-option-menu.h>
+
+#include <e-util/e-categories-master-list-wombat.h>
#include <camel/camel.h>
@@ -58,6 +60,7 @@
#include "widgets/misc/e-dateedit.h"
#include "widgets/misc/e-image-chooser.h"
#include "widgets/misc/e-url-entry.h"
+#include "widgets/misc/e-source-option-menu.h"
#include "shell/evolution-shell-component-utils.h"
#include "e-util/e-icon-factory.h"
@@ -117,8 +120,7 @@ enum {
PROP_IS_NEW_CONTACT,
PROP_EDITABLE,
PROP_CHANGED,
- PROP_WRITABLE_FIELDS,
- PROP_REQUIRED_FIELDS
+ PROP_WRITABLE_FIELDS
};
enum {
@@ -286,13 +288,6 @@ e_contact_editor_class_init (EContactEditorClass *klass)
E_TYPE_LIST,
G_PARAM_READWRITE));
- g_object_class_install_property (object_class, PROP_REQUIRED_FIELDS,
- g_param_spec_object ("required_fields",
- _("Required Fields"),
- /*_( */"XXX blurb" /*)*/,
- E_TYPE_LIST,
- G_PARAM_READWRITE));
-
g_object_class_install_property (object_class, PROP_EDITABLE,
g_param_spec_boolean ("editable",
_("Editable"),
@@ -1538,30 +1533,6 @@ extract_im (EContactEditor *editor)
g_free (service_attr_list);
}
-static void
-sensitize_im_types (EContactEditor *editor, GtkWidget *option_menu)
-{
- GtkWidget *menu;
- GList *item_list, *l;
- gint i;
-
- menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (option_menu));
- l = item_list = gtk_container_get_children (GTK_CONTAINER (menu));
-
- for (i = 0; i < G_N_ELEMENTS (im_service); i++) {
- GtkWidget *widget;
-
- if (!l) {
- g_warning (G_STRLOC ": Unexpected end of im items in option menu");
- return;
- }
-
- widget = l->data;
- gtk_widget_set_sensitive (widget, is_field_supported (editor, im_service [i].field));
-
- l = g_list_next (l);
- }
-}
static void
sensitize_im_record (EContactEditor *editor, gint record, gboolean enabled)
@@ -1592,29 +1563,19 @@ sensitize_im_record (EContactEditor *editor, gint record, gboolean enabled)
gtk_widget_set_sensitive (location_option_menu, enabled);
#endif
gtk_editable_set_editable (GTK_EDITABLE (name_entry), enabled);
- sensitize_im_types (editor, service_option_menu);
}
static void
sensitize_im (EContactEditor *editor)
{
gint i;
- gboolean enabled;
- gboolean no_ims_supported;
-
- enabled = editor->target_editable;
- no_ims_supported = TRUE;
-
- for (i = 0; i < G_N_ELEMENTS (im_service); i++)
- if (is_field_supported (editor, im_service[i].field)) {
- no_ims_supported = FALSE;
- break;
- }
- if (no_ims_supported)
- enabled = FALSE;
-
for (i = 1; i <= IM_SLOTS; i++) {
+ gboolean enabled = TRUE;
+
+ if (!editor->target_editable)
+ enabled = FALSE;
+
sensitize_im_record (editor, i, enabled);
}
}
@@ -2158,6 +2119,7 @@ extract_simple_field (EContactEditor *editor, GtkWidget *widget, gint field_id)
gtk_text_buffer_get_start_iter (buffer, &start);
gtk_text_buffer_get_end_iter (buffer, &end);
text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
+
e_contact_set (contact, field_id, text);
g_free (text);
}
@@ -2478,27 +2440,37 @@ categories_clicked (GtkWidget *button, EContactEditor *editor)
GtkDialog *dialog;
int result;
GtkWidget *entry = glade_xml_get_widget(editor->gui, "entry-categories");
-
+ ECategoriesMasterList *ecml;
if (entry && GTK_IS_ENTRY(entry))
categories = g_strdup (gtk_entry_get_text(GTK_ENTRY(entry)));
else if (editor->contact)
categories = e_contact_get (editor->contact, E_CONTACT_CATEGORIES);
- if (!(dialog = GTK_DIALOG (e_categories_dialog_new (categories)))) {
+ if (!(dialog = GTK_DIALOG (e_categories_new (categories)))) {
e_error_run (NULL, "addressbook:edit-categories", NULL);
g_free (categories);
return;
}
+ ecml = e_categories_master_list_wombat_new ();
+ g_object_set (dialog,
+ "header", _("This contact belongs to these categories:"),
+ "ecml", ecml,
+ NULL);
+ g_object_unref (ecml);
gtk_widget_show(GTK_WIDGET(dialog));
result = gtk_dialog_run (dialog);
g_free (categories);
if (result == GTK_RESPONSE_OK) {
- categories = e_categories_dialog_get_categories (E_CATEGORIES_DIALOG (dialog));
+ g_object_get (dialog,
+ "categories", &categories,
+ NULL);
if (entry && GTK_IS_ENTRY(entry))
gtk_entry_set_text (GTK_ENTRY (entry), categories);
else
e_contact_set (editor->contact, E_CONTACT_CATEGORIES, categories);
+
+ g_free(categories);
}
gtk_widget_destroy(GTK_WIDGET(dialog));
}
@@ -2763,29 +2735,17 @@ real_save_contact (EContactEditor *ce, gboolean should_close)
static void
save_contact (EContactEditor *ce, gboolean should_close)
{
- char *uid;
-
if (!ce->target_book)
return;
-
+
+ if (!e_contact_editor_is_valid (EAB_EDITOR (ce)))
+ return;
if (ce->target_editable && !e_book_is_writable (ce->source_book)) {
if (e_error_run (GTK_WINDOW (ce->app), "addressbook:prompt-move", NULL) == GTK_RESPONSE_NO)
return;
}
extract_all (ce);
-
- if (!e_contact_editor_is_valid (EAB_EDITOR (ce))) {
- uid = e_contact_get (ce->contact, E_CONTACT_UID);
- g_object_unref (ce->contact);
- ce->contact = e_contact_new ();
- if (uid) {
- e_contact_set (ce->contact, E_CONTACT_UID, uid);
- g_free (uid);
- }
- return;
- }
-
real_save_contact (ce, should_close);
}
@@ -2808,42 +2768,6 @@ e_contact_editor_close (EABEditor *editor)
}
}
-EContactField non_string_fields [] = {
- E_CONTACT_FULL_NAME,
- E_CONTACT_ADDRESS,
- E_CONTACT_ADDRESS_HOME,
- E_CONTACT_ADDRESS_WORK,
- E_CONTACT_ADDRESS_OTHER,
- E_CONTACT_EMAIL,
- E_CONTACT_IM_AIM,
- E_CONTACT_IM_GROUPWISE,
- E_CONTACT_IM_JABBER,
- E_CONTACT_IM_YAHOO,
- E_CONTACT_IM_MSN,
- E_CONTACT_IM_ICQ,
- E_CONTACT_PHOTO,
- E_CONTACT_LOGO,
- E_CONTACT_X509_CERT,
- E_CONTACT_CATEGORY_LIST,
- E_CONTACT_BIRTH_DATE,
- E_CONTACT_ANNIVERSARY
-
-
-};
-
-static gboolean
-is_non_string_field (EContactField id)
-{
- int count = sizeof (non_string_fields) / sizeof (EContactField);
- int i;
- for (i = 0; i < count; i++)
- if (id == non_string_fields[i])
- return TRUE;
- return FALSE;
-
-}
-
-
/* insert checks here (date format, for instance, etc.) */
static gboolean
e_contact_editor_is_valid (EABEditor *editor)
@@ -2851,7 +2775,6 @@ e_contact_editor_is_valid (EABEditor *editor)
EContactEditor *ce = E_CONTACT_EDITOR (editor);
GtkWidget *widget;
gboolean validation_error = FALSE;
- EIterator *iter;
GString *errmsg = g_string_new (_("The contact data is invalid:\n\n"));
widget = glade_xml_get_widget (ce->gui, "dateedit-birthday");
@@ -2869,38 +2792,14 @@ e_contact_editor_is_valid (EABEditor *editor)
validation_error = TRUE;
}
- iter = e_list_get_iterator (ce->required_fields);
- for (e_iterator_last (iter);
- e_iterator_is_valid (iter);
- e_iterator_prev (iter)) {
- const char *field_name = e_iterator_get (iter);
- EContactField field_id = e_contact_field_id (field_name);
-
- if (is_non_string_field (field_id)) {
- if (e_contact_get_const (ce->contact, field_id) == NULL) {
- g_string_append_printf (errmsg, "%s'%s' is empty",
- validation_error ? ",\n" : "",
- e_contact_pretty_name (field_id));
- validation_error = TRUE;
- break;
- }
-
- } else {
-
- char *text = e_contact_get_const (ce->contact, field_id);
- if (STRING_IS_EMPTY (text)) {
- g_string_append_printf (errmsg, "%s'%s' is empty",
- validation_error ? ",\n" : "",
- e_contact_pretty_name (field_id));
- validation_error = TRUE;
- break;
- }
-
-
- }
+ widget = glade_xml_get_widget (ce->gui, "entry-file-as");
+ if (STRING_IS_EMPTY (gtk_entry_get_text (GTK_ENTRY (widget)))) {
+ g_string_append_printf (errmsg, "%s'%s' is empty",
+ validation_error ? ",\n" : "",
+ e_contact_pretty_name (E_CONTACT_FILE_AS));
+ validation_error = TRUE;
}
-
-
+
if (validation_error) {
g_string_append (errmsg, ".");
e_error_run (GTK_WINDOW (ce->app), "addressbook:generic-error",
@@ -3064,7 +2963,6 @@ e_contact_editor_init (EContactEditor *e_contact_editor)
e_contact_editor->app = glade_xml_get_widget (gui, "contact editor");
widget = e_contact_editor->app;
- gtk_widget_ensure_style (widget);
gtk_window_set_type_hint (GTK_WINDOW (widget), GDK_WINDOW_TYPE_HINT_NORMAL);
gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (widget)->vbox), 0);
gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (widget)->action_area), 12);
@@ -3123,10 +3021,7 @@ e_contact_editor_dispose (GObject *object)
g_object_unref(e_contact_editor->writable_fields);
e_contact_editor->writable_fields = NULL;
}
- if (e_contact_editor->required_fields) {
- g_object_unref (e_contact_editor->required_fields);
- e_contact_editor->required_fields = NULL;
- }
+
if (e_contact_editor->contact) {
g_object_unref(e_contact_editor->contact);
e_contact_editor->contact = NULL;
@@ -3178,24 +3073,6 @@ supported_fields_cb (EBook *book, EBookStatus status,
}
static void
-required_fields_cb (EBook *book, EBookStatus status,
- EList *fields, EContactEditor *ce)
-{
-
- if (!g_slist_find ((GSList*)eab_editor_get_all_editors (), ce)) {
- g_warning ("supported_fields_cb called for book that's still around, but contact editor that's been destroyed.");
- return;
- }
-
- g_object_set (ce,
- "required_fields", fields,
- NULL);
-
-
-}
-
-
-static void
contact_editor_destroy_notify (void *data,
GObject *where_the_object_was)
{
@@ -3281,8 +3158,6 @@ e_contact_editor_set_property (GObject *object, guint prop_id, const GValue *val
e_book_async_get_supported_fields (editor->target_book,
(EBookEListCallback) supported_fields_cb, editor);
- e_book_async_get_required_fields (editor->target_book,
- (EBookEListCallback) required_fields_cb, editor);
}
writable = e_book_is_writable (editor->target_book);
@@ -3321,8 +3196,6 @@ e_contact_editor_set_property (GObject *object, guint prop_id, const GValue *val
e_book_async_get_supported_fields (editor->target_book,
(EBookEListCallback) supported_fields_cb, editor);
- e_book_async_get_required_fields (editor->target_book,
- (EBookEListCallback) required_fields_cb, editor);
if (!editor->is_new_contact)
editor->changed = TRUE;
@@ -3386,15 +3259,6 @@ e_contact_editor_set_property (GObject *object, guint prop_id, const GValue *val
sensitize_all (editor);
break;
- case PROP_REQUIRED_FIELDS:
- if (editor->required_fields)
- g_object_unref (editor->required_fields);
- editor->required_fields = g_value_get_object (value);
- if (editor->required_fields)
- g_object_ref (editor->required_fields);
- else
- editor->required_fields = e_list_new (NULL, NULL, NULL);
- break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -3440,12 +3304,6 @@ e_contact_editor_get_property (GObject *object, guint prop_id, GValue *value, GP
else
g_value_set_object (value, NULL);
break;
- case PROP_REQUIRED_FIELDS:
- if (e_contact_editor->required_fields)
- g_value_set_object (value, e_list_duplicate (e_contact_editor->required_fields));
- else
- g_value_set_object (value, NULL);
- break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -3491,18 +3349,10 @@ e_contact_editor_create_date(gchar *name,
gint int1, gint int2)
{
GtkWidget *widget = e_date_edit_new ();
- AtkObject *a11y;
-
e_date_edit_set_allow_no_date_set (E_DATE_EDIT (widget),
TRUE);
e_date_edit_set_show_time (E_DATE_EDIT (widget), FALSE);
e_date_edit_set_time (E_DATE_EDIT (widget), -1);
-
- a11y = gtk_widget_get_accessible (e_date_edit_get_entry (E_DATE_EDIT(widget)));
- if (a11y != NULL) {
- atk_object_set_name (a11y, string1);
- }
-
gtk_widget_show (widget);
return widget;
}
@@ -3518,12 +3368,6 @@ e_contact_editor_create_web(gchar *name,
gint int1, gint int2)
{
GtkWidget *widget = e_url_entry_new ();
- AtkObject *a11y = gtk_widget_get_accessible (e_url_entry_get_entry (widget));
-
- if (a11y != NULL) {
- atk_object_set_name (a11y, string1);
- }
-
gtk_widget_show (widget);
return widget;
}
diff --git a/addressbook/gui/contact-editor/e-contact-quick-add.c b/addressbook/gui/contact-editor/e-contact-quick-add.c
index d3765314ba..7a167dc5ff 100644
--- a/addressbook/gui/contact-editor/e-contact-quick-add.c
+++ b/addressbook/gui/contact-editor/e-contact-quick-add.c
@@ -268,26 +268,19 @@ static GtkWidget *
build_quick_add_dialog (QuickAdd *qa)
{
GtkWidget *dialog;
- GtkWidget *label;
GtkTable *table;
- const gint xpad=0, ypad=0;
+ const gint xpad=6, ypad=6;
g_return_val_if_fail (qa != NULL, NULL);
dialog = gtk_dialog_new_with_buttons (_("Contact Quick-Add"),
NULL, /* XXX */
- GTK_DIALOG_NO_SEPARATOR,
+ (GtkDialogFlags) 0,
_("_Edit Full"), QUICK_ADD_RESPONSE_EDIT_FULL,
- GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OK, GTK_RESPONSE_OK,
NULL);
- gtk_widget_ensure_style (dialog);
- gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox),
- 0);
- gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area),
- 12);
-
g_signal_connect (dialog, "response", G_CALLBACK (clicked_cb), qa);
qa->name_entry = gtk_entry_new ();
@@ -300,34 +293,27 @@ build_quick_add_dialog (QuickAdd *qa)
gtk_entry_set_text (GTK_ENTRY (qa->email_entry), qa->email);
table = GTK_TABLE (gtk_table_new (2, 2, FALSE));
- gtk_table_set_row_spacings (table, 6);
- gtk_table_set_col_spacings (table, 12);
- label = gtk_label_new_with_mnemonic (_("_Full name:"));
- gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
-
- gtk_table_attach (table, label,
+ gtk_table_attach (table, gtk_label_new_with_mnemonic (_("_Full Name:")),
0, 1, 0, 1,
- GTK_FILL, 0, xpad, ypad);
+ 0, 0, xpad, ypad);
gtk_table_attach (table, qa->name_entry,
1, 2, 0, 1,
- GTK_EXPAND | GTK_FILL, 0, xpad, ypad);
-
- label = gtk_label_new_with_mnemonic (_("E-_mail:"));
- gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
-
- gtk_table_attach (table, label,
+ GTK_EXPAND | GTK_FILL, GTK_EXPAND, xpad, ypad);
+ gtk_table_attach (table, gtk_label_new_with_mnemonic (_("E-_mail:")),
0, 1, 1, 2,
- GTK_FILL, 0, xpad, ypad);
+ 0, 0, xpad, ypad);
gtk_table_attach (table, qa->email_entry,
1, 2, 1, 2,
- GTK_EXPAND | GTK_FILL, 0, xpad, ypad);
+ GTK_EXPAND | GTK_FILL, GTK_EXPAND, xpad, ypad);
+ gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox),
+ 6);
+
+ gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox),6);
- gtk_container_set_border_width (GTK_CONTAINER (table),
- 12);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
GTK_WIDGET (table),
- FALSE, FALSE, 0);
+ TRUE, TRUE, 6);
gtk_widget_show_all (GTK_WIDGET (table));
diff --git a/addressbook/gui/contact-list-editor/contact-list-editor.glade b/addressbook/gui/contact-list-editor/contact-list-editor.glade
index bc5c2c18ee..30760f6108 100644
--- a/addressbook/gui/contact-list-editor/contact-list-editor.glade
+++ b/addressbook/gui/contact-list-editor/contact-list-editor.glade
@@ -11,11 +11,6 @@
<property name="modal">False</property>
<property name="resizable">True</property>
<property name="destroy_with_parent">False</property>
- <property name="decorated">True</property>
- <property name="skip_taskbar_hint">False</property>
- <property name="skip_pager_hint">False</property>
- <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
- <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
<property name="has_separator">True</property>
<child internal-child="vbox">
@@ -37,7 +32,6 @@
<property name="label">gtk-cancel</property>
<property name="use_stock">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
<property name="response_id">-6</property>
</widget>
</child>
@@ -50,7 +44,6 @@
<property name="label">gtk-ok</property>
<property name="use_stock">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
<property name="response_id">-5</property>
</widget>
</child>
@@ -239,7 +232,6 @@
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
- <property name="mnemonic_widget">email-entry</property>
</widget>
<packing>
<property name="padding">0</property>
@@ -271,6 +263,7 @@
<widget class="Custom" id="contact-list-table">
<property name="visible">True</property>
<property name="creation_function">e_contact_list_editor_create_table</property>
+ <property name="string1"></property>
<property name="int1">0</property>
<property name="int2">0</property>
<property name="last_modification_time">Sat, 23 Jun 2001 06:00:16 GMT</property>
@@ -289,7 +282,6 @@
<property name="label" translatable="yes">_Hide addresses when sending mail to this list</property>
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
<property name="active">False</property>
<property name="inconsistent">False</property>
<property name="draw_indicator">True</property>
@@ -351,7 +343,6 @@
<property name="label">gtk-add</property>
<property name="use_stock">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
</widget>
</child>
@@ -364,7 +355,6 @@
<property name="label">gtk-remove</property>
<property name="use_stock">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
</widget>
</child>
@@ -374,10 +364,9 @@
<property name="tooltip" translatable="yes">Insert email adresses from Adress Book</property>
<property name="can_default">True</property>
<property name="can_focus">True</property>
- <property name="label" translatable="yes">_Select</property>
+ <property name="label" translatable="yes">Select</property>
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
</widget>
</child>
</widget>
diff --git a/addressbook/gui/widgets/e-addressbook-view.c b/addressbook/gui/widgets/e-addressbook-view.c
index 5f8397161b..b9f6b123e6 100644
--- a/addressbook/gui/widgets/e-addressbook-view.c
+++ b/addressbook/gui/widgets/e-addressbook-view.c
@@ -29,6 +29,7 @@
#include <gtk/gtkscrolledwindow.h>
#include <gal/e-table/e-table-scrolled.h>
#include <gal/e-table/e-table-model.h>
+#include <gal/widgets/e-popup-menu.h>
#include <gal/widgets/e-gui-utils.h>
#include <gal/menus/gal-view-factory-etable.h>
#include <gal/menus/gal-view-etable.h>
@@ -43,12 +44,9 @@
#include "addressbook/printing/e-contact-print.h"
#include "addressbook/printing/e-contact-print-envelope.h"
#include "addressbook/gui/search/e-addressbook-search-dialog.h"
-#include "addressbook/gui/widgets/eab-popup.h"
-#include "addressbook/gui/widgets/eab-menu.h"
#include "e-util/e-categories-master-list-wombat.h"
-#include "e-util/e-print.h"
-#include "libedataserver/e-sexp.h"
+#include "e-util/e-sexp.h"
#ifdef WITH_ADDRESSBOOK_VIEW_TREEVIEW
#include <gal/widgets/e-treeview-selection-model.h>
@@ -99,7 +97,7 @@ static void stop_state_changed (GtkObject *object, EABView *eav);
static void writable_status (GtkObject *object, gboolean writable, EABView *eav);
static void backend_died (GtkObject *object, EABView *eav);
static void contact_changed (EABModel *model, gint index, EABView *eav);
-static void contacts_removed (EABModel *model, gpointer data, EABView *eav);
+static void contact_removed (EABModel *model, gint index, EABView *eav);
static GList *get_selected_contacts (EABView *view);
static void command_state_change (EABView *eav);
@@ -436,8 +434,8 @@ eab_view_new (void)
G_CALLBACK (backend_died), eav);
g_signal_connect (eav->model, "contact_changed",
G_CALLBACK (contact_changed), eav);
- g_signal_connect (eav->model, "contacts_removed",
- G_CALLBACK (contacts_removed), eav);
+ g_signal_connect (eav->model, "contact_removed",
+ G_CALLBACK (contact_removed), eav);
eav->editable = FALSE;
eav->query = g_strdup (SHOW_ALL_SEARCH);
@@ -477,12 +475,16 @@ eab_view_new (void)
g_signal_connect_swapped (eav->paned, "button_release_event",
G_CALLBACK (get_paned_position), eav);
+ eav->widget = gtk_label_new ("empty label here");
+ gtk_container_add (GTK_CONTAINER (eav->paned), eav->widget);
+ gtk_widget_show (eav->widget);
+
eav->contact_display = eab_contact_display_new ();
eav->contact_display_window = gtk_scrolled_window_new (NULL, NULL);
- gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (eav->contact_display_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (eav->contact_display_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (eav->contact_display_window), GTK_SHADOW_IN);
gtk_container_add (GTK_CONTAINER (eav->contact_display_window), eav->contact_display);
- gtk_paned_add2 (GTK_PANED (eav->paned), eav->contact_display_window);
+ gtk_container_add (GTK_CONTAINER (eav->paned), eav->contact_display_window);
gtk_widget_show (eav->contact_display);
gtk_widget_show (eav->contact_display_window);
gtk_widget_show (eav->paned);
@@ -773,6 +775,7 @@ get_selection_model (EABView *view)
/* Popup menu stuff */
typedef struct {
EABView *view;
+ EPopupMenu *submenu;
gpointer closure;
} ContactAndBook;
@@ -782,219 +785,371 @@ contact_and_book_get_selection_model (ContactAndBook *contact_and_book)
return get_selection_model (contact_and_book->view);
}
+static void
+contact_and_book_free (ContactAndBook *contact_and_book)
+{
+ EABView *view = contact_and_book->view;
+ ESelectionModel *selection;
+
+ if (contact_and_book->submenu)
+ gal_view_instance_free_popup_menu (view->view_instance,
+ contact_and_book->submenu);
+
+ selection = contact_and_book_get_selection_model (contact_and_book);
+ if (selection)
+ e_selection_model_right_click_up(selection);
+
+ g_object_unref (view);
+}
+
+static void
+get_contact_list_1(gint model_row,
+ gpointer closure)
+{
+ ContactAndBook *contact_and_book;
+ GList **list;
+ EABView *view;
+ EContact *contact;
+
+ contact_and_book = closure;
+ list = contact_and_book->closure;
+ view = contact_and_book->view;
+
+ contact = eab_model_get_contact(view->model, model_row);
+ *list = g_list_prepend(*list, contact);
+}
+
static GList *
-get_contact_list (EABPopupTargetSelect *t)
+get_contact_list (ContactAndBook *contact_and_book)
{
GList *list = NULL;
- int i;
+ ESelectionModel *selection;
- for (i=0;i<t->cards->len;i++)
- list = g_list_prepend(list, t->cards->pdata[i]);
+ selection = contact_and_book_get_selection_model (contact_and_book);
+
+ if (selection) {
+ contact_and_book->closure = &list;
+ e_selection_model_foreach (selection, get_contact_list_1, contact_and_book);
+ }
return list;
}
static void
-save_as (EPopup *ep, EPopupItem *pitem, void *data)
+has_email_address_1(gint model_row,
+ gpointer closure)
{
- /*ContactAndBook *contact_and_book = data;*/
- GList *contacts = get_contact_list ((EABPopupTargetSelect *)ep->target);
+ ContactAndBook *contact_and_book;
+ gboolean *has_email;
+ EABView *view;
+ const EContact *contact;
+ GList *email;
+
+ contact_and_book = closure;
+ has_email = contact_and_book->closure;
+ view = contact_and_book->view;
+
+ if (*has_email)
+ return;
+
+ contact = eab_model_contact_at(view->model, model_row);
+
+ email = e_contact_get (E_CONTACT (contact), E_CONTACT_EMAIL);
+
+ if (g_list_length (email) > 0)
+ *has_email = TRUE;
+
+ g_list_foreach (email, (GFunc)g_free, NULL);
+ g_list_free (email);
+}
+
+static gboolean
+get_has_email_address (ContactAndBook *contact_and_book)
+{
+ ESelectionModel *selection;
+ gboolean has_email = FALSE;
+ selection = contact_and_book_get_selection_model (contact_and_book);
+
+ if (selection) {
+ contact_and_book->closure = &has_email;
+ e_selection_model_foreach (selection, has_email_address_1, contact_and_book);
+ }
+
+ return has_email;
+}
+
+static void
+save_as (GtkWidget *widget, ContactAndBook *contact_and_book)
+{
+ GList *contacts = get_contact_list (contact_and_book);
if (contacts) {
eab_contact_list_save(_("Save as VCard..."), contacts, NULL);
- g_list_free(contacts);
+ e_free_object_list(contacts);
}
}
static void
-send_as (EPopup *ep, EPopupItem *pitem, void *data)
+send_as (GtkWidget *widget, ContactAndBook *contact_and_book)
{
- /*ContactAndBook *contact_and_book = data;*/
- GList *contacts = get_contact_list ((EABPopupTargetSelect *)ep->target);
-
+ GList *contacts = get_contact_list (contact_and_book);
if (contacts) {
eab_send_contact_list(contacts, EAB_DISPOSITION_AS_ATTACHMENT);
- g_list_free(contacts);
+ e_free_object_list(contacts);
}
}
static void
-send_to (EPopup *ep, EPopupItem *pitem, void *data)
+send_to (GtkWidget *widget, ContactAndBook *contact_and_book)
+
{
- /*ContactAndBook *contact_and_book = data;*/
- GList *contacts = get_contact_list ((EABPopupTargetSelect *)ep->target);
+ GList *contacts = get_contact_list (contact_and_book);
if (contacts) {
eab_send_contact_list(contacts, EAB_DISPOSITION_AS_TO);
- g_list_free(contacts);
+ e_free_object_list(contacts);
}
}
static void
-print (EPopup *ep, EPopupItem *pitem, void *data)
+print (GtkWidget *widget, ContactAndBook *contact_and_book)
{
- /*ContactAndBook *contact_and_book = data;*/
- EABPopupTargetSelect *t = (EABPopupTargetSelect *)ep->target;
-
- if (t->cards->len == 1) {
- gtk_widget_show(e_contact_print_contact_dialog_new(t->cards->pdata[0]));
- } else {
- GList *contacts = get_contact_list(t);
-
- gtk_widget_show(e_contact_print_contact_list_dialog_new(contacts));
- g_list_free(contacts);
+ GList *contacts = get_contact_list (contact_and_book);
+ if (contacts) {
+ if (contacts->next)
+ gtk_widget_show(e_contact_print_contact_list_dialog_new(contacts));
+ else
+ gtk_widget_show(e_contact_print_contact_dialog_new(contacts->data));
+ e_free_object_list(contacts);
}
}
+#if 0 /* Envelope printing is disabled for Evolution 1.0. */
static void
-copy (EPopup *ep, EPopupItem *pitem, void *data)
+print_envelope (GtkWidget *widget, ContactAndBook *contact_and_book)
{
- ContactAndBook *contact_and_book = data;
+ GList *cards = get_card_list (contact_and_book);
+ if (cards) {
+ gtk_widget_show(e_contact_list_print_envelope_dialog_new(contact_and_book->card));
+ e_free_object_list(cards);
+ }
+}
+#endif
+static void
+copy (GtkWidget *widget, ContactAndBook *contact_and_book)
+{
eab_view_copy (contact_and_book->view);
}
static void
-paste (EPopup *ep, EPopupItem *pitem, void *data)
+paste (GtkWidget *widget, ContactAndBook *contact_and_book)
{
- ContactAndBook *contact_and_book = data;
-
eab_view_paste (contact_and_book->view);
}
static void
-cut (EPopup *ep, EPopupItem *pitem, void *data)
+cut (GtkWidget *widget, ContactAndBook *contact_and_book)
{
- ContactAndBook *contact_and_book = data;
-
eab_view_cut (contact_and_book->view);
}
static void
-delete (EPopup *ep, EPopupItem *pitem, void *data)
+delete (GtkWidget *widget, ContactAndBook *contact_and_book)
{
- ContactAndBook *contact_and_book = data;
+ if (eab_editor_confirm_delete(GTK_WINDOW(gtk_widget_get_toplevel(contact_and_book->view->widget)))) {
+ EBook *book;
+ GList *list = get_contact_list(contact_and_book);
+ GList *iterator;
+ gboolean bulk_remove = FALSE;
+
+ bulk_remove = e_book_check_static_capability (contact_and_book->view->model->book,
+ "bulk-remove");
+
+ g_object_get(contact_and_book->view->model,
+ "book", &book,
+ NULL);
+
+ if (bulk_remove) {
+ GList *ids = NULL;
+
+ for (iterator = list; iterator; iterator = iterator->next) {
+ EContact *contact = iterator->data;
+ ids = g_list_prepend (ids, (char*)e_contact_get_const (contact, E_CONTACT_UID));
+ }
- eab_view_delete_selection(contact_and_book->view);
+ /* Remove the cards all at once. */
+ /* XXX no callback specified... ugh */
+ e_book_async_remove_contacts (book,
+ ids,
+ NULL,
+ NULL);
+
+ g_list_free (ids);
+ }
+ else {
+ for (iterator = list; iterator; iterator = iterator->next) {
+ EContact *contact = iterator->data;
+ /* Remove the card. */
+ /* XXX no callback specified... ugh */
+ e_book_async_remove_contact (book,
+ contact,
+ NULL,
+ NULL);
+ }
+ }
+ e_free_object_list(list);
+ g_object_unref(book);
+ }
}
static void
-copy_to_folder (EPopup *ep, EPopupItem *pitem, void *data)
+copy_to_folder (GtkWidget *widget, ContactAndBook *contact_and_book)
{
- ContactAndBook *contact_and_book = data;
-
eab_view_copy_to_folder (contact_and_book->view);
}
static void
-move_to_folder (EPopup *ep, EPopupItem *pitem, void *data)
+move_to_folder (GtkWidget *widget, ContactAndBook *contact_and_book)
{
- ContactAndBook *contact_and_book = data;
-
eab_view_move_to_folder (contact_and_book->view);
}
static void
-new_card (EPopup *ep, EPopupItem *pitem, void *data)
+free_popup_info (GtkWidget *w, ContactAndBook *contact_and_book)
{
- /*ContactAndBook *contact_and_book = data;*/
+ contact_and_book_free (contact_and_book);
+}
+
+static void
+new_card (GtkWidget *widget, ContactAndBook *contact_and_book)
+{
+ EBook *book;
EContact *contact = e_contact_new();
- eab_show_contact_editor (((EABPopupTargetSelect *)ep->target)->book, contact, TRUE, TRUE);
+ g_object_get(contact_and_book->view->model,
+ "book", &book,
+ NULL);
+
+ eab_show_contact_editor (book, contact, TRUE, TRUE);
+ g_object_unref (book);
g_object_unref (contact);
}
static void
-new_list (EPopup *ep, EPopupItem *pitem, void *data)
+new_list (GtkWidget *widget, ContactAndBook *contact_and_book)
{
- /*ContactAndBook *contact_and_book = data;*/
+ EBook *book;
EContact *contact = e_contact_new ();
- eab_show_contact_list_editor (((EABPopupTargetSelect *)ep->target)->book, contact, TRUE, TRUE);
+ g_object_get(contact_and_book->view->model,
+ "book", &book,
+ NULL);
+ eab_show_contact_list_editor (book, contact, TRUE, TRUE);
+ g_object_unref(book);
g_object_unref(contact);
}
-static EPopupItem eabv_popup_items[] = {
- { E_POPUP_ITEM, "10.new", N_("New Contact..."), new_card, NULL, "stock_contact", 0, EAB_POPUP_SELECT_EDITABLE},
- { E_POPUP_ITEM, "15.newlist", N_("New Contact List..."), new_list, NULL, "stock_contact-list", 0, EAB_POPUP_SELECT_EDITABLE },
-
- { E_POPUP_BAR, "20.bar" },
- { E_POPUP_ITEM, "30.saveas", N_("Save as VCard..."), save_as, NULL, "stock_save-as", 0, EAB_POPUP_SELECT_ANY },
- { E_POPUP_ITEM, "40.forward", N_("Forward Contact"), send_as, NULL, "stock_mail-forward", 0, EAB_POPUP_SELECT_ANY },
- { E_POPUP_ITEM, "50.mailto", N_("Send Message to Contact"), send_to, NULL, "stock_mail-send", 0, EAB_POPUP_SELECT_ANY|EAB_POPUP_SELECT_EMAIL },
- { E_POPUP_ITEM, "60.print", N_("Print"), print, NULL, "stock_print", 0, EAB_POPUP_SELECT_ANY },
-
- { E_POPUP_BAR, "70.bar" },
- { E_POPUP_ITEM, "80.copyto", N_("Copy to Address Book..."), copy_to_folder, NULL, NULL, 0, EAB_POPUP_SELECT_ANY },
- { E_POPUP_ITEM, "90.moveto", N_("Move to Address Book..."), move_to_folder, NULL, NULL, 0, EAB_POPUP_SELECT_ANY|EAB_POPUP_SELECT_EDITABLE },
-
- { E_POPUP_BAR, "a0.bar" },
- { E_POPUP_BAR, "b0.cut", N_("Cut"), cut, NULL, "stock_cut", 0, EAB_POPUP_SELECT_ANY|EAB_POPUP_SELECT_EDITABLE },
- { E_POPUP_ITEM, "c0.copy", N_("Copy"), copy, NULL, "stock_copy", 0, EAB_POPUP_SELECT_ANY },
- { E_POPUP_ITEM, "d0.paste", N_("Paste"), paste, NULL, "stock_paste", 0, EAB_POPUP_SELECT_EDITABLE },
- { E_POPUP_ITEM, "e0.delete", N_("Delete"), delete, NULL, "stock_delete", 0, EAB_POPUP_SELECT_EDITABLE|EAB_POPUP_SELECT_ANY },
-};
-
+#if 0
static void
-get_card_1(gint model_row, void *data)
+sources (GtkWidget *widget, ContactAndBook *contact_and_book)
{
- ContactAndBook *contact_and_book = data;
- EContact *contact;
+ BonoboControl *control;
+ GNOME_Evolution_ShellView shell_view;
+ CORBA_Environment ev;
- contact = eab_model_get_contact(contact_and_book->view->model, model_row);
- if (contact)
- g_ptr_array_add((GPtrArray *)contact_and_book->closure, contact);
-}
+ control = g_object_get_data (G_OBJECT (gcal), "control");
+ if (control == NULL)
+ return;
-static void
-eabv_popup_free(EPopup *ep, GSList *list, void *data)
-{
- ContactAndBook *cab = data;
- ESelectionModel *selection;
+ shell_view = get_shell_view_interface (control);
+ if (shell_view == CORBA_OBJECT_NIL)
+ return;
- /* NB: this looks strange to me */
- selection = contact_and_book_get_selection_model(cab);
- if (selection)
- e_selection_model_right_click_up(selection);
+ CORBA_exception_init (&ev);
+
+ GNOME_Evolution_ShellView_showSettings (shell_view, &ev);
+
+ if (BONOBO_EX (&ev))
+ g_message ("control_util_show_settings(): Could not show settings");
- g_slist_free(list);
- g_object_unref(cab->view);
- g_free(cab);
+ CORBA_exception_free (&ev);
}
+#endif
+
+#define POPUP_READONLY_MASK 0x1
+#define POPUP_NOSELECTION_MASK 0x2
+#define POPUP_NOEMAIL_MASK 0x4
static void
do_popup_menu(EABView *view, GdkEvent *event)
{
- EABPopup *ep;
- EABPopupTargetSelect *t;
- GSList *menus = NULL;
- int i;
- GtkMenu *menu;
- GPtrArray *cards = g_ptr_array_new();
ContactAndBook *contact_and_book;
+ GtkMenu *popup;
+ EPopupMenu *submenu = NULL;
ESelectionModel *selection_model;
+ gboolean selection = FALSE;
+
+ EPopupMenu menu[] = {
+ E_POPUP_ITEM (N_("New Contact..."), G_CALLBACK(new_card), POPUP_READONLY_MASK),
+ E_POPUP_ITEM (N_("New Contact List..."), G_CALLBACK(new_list), POPUP_READONLY_MASK),
+ E_POPUP_SEPARATOR,
+#if 0
+ E_POPUP_ITEM (N_("Go to Folder..."), G_CALLBACK (goto_folder), 0),
+ E_POPUP_ITEM (N_("Import..."), G_CALLBACK (import), POPUP_READONLY_MASK),
+ E_POPUP_SEPARATOR,
+ E_POPUP_ITEM (N_("Search for Contacts..."), G_CALLBACK (search), 0),
+ E_POPUP_ITEM (N_("Address Book Sources..."), G_CALLBACK (sources), 0),
+ E_POPUP_SEPARATOR,
+ E_POPUP_ITEM (N_("Pilot Settings..."), G_CALLBACK (pilot_settings), 0),
+#endif
+ E_POPUP_SEPARATOR,
+ E_POPUP_ITEM (N_("Save as VCard..."), G_CALLBACK(save_as), POPUP_NOSELECTION_MASK),
+ E_POPUP_ITEM (N_("Forward Contact"), G_CALLBACK(send_as), POPUP_NOSELECTION_MASK),
+ E_POPUP_ITEM (N_("Send Message to Contact"), G_CALLBACK(send_to), POPUP_NOSELECTION_MASK | POPUP_NOEMAIL_MASK),
+ E_POPUP_ITEM (N_("Print"), G_CALLBACK(print), POPUP_NOSELECTION_MASK),
+#if 0 /* Envelope printing is disabled for Evolution 1.0. */
+ E_POPUP_ITEM (N_("Print Envelope"), G_CALLBACK(print_envelope), POPUP_NOSELECTION_MASK),
+#endif
+ E_POPUP_SEPARATOR,
+
+ E_POPUP_ITEM (N_("Copy to Address Book..."), G_CALLBACK(copy_to_folder), POPUP_NOSELECTION_MASK),
+ E_POPUP_ITEM (N_("Move to Address Book..."), G_CALLBACK(move_to_folder), POPUP_READONLY_MASK | POPUP_NOSELECTION_MASK),
+ E_POPUP_SEPARATOR,
+
+ E_POPUP_ITEM (N_("Cut"), G_CALLBACK (cut), POPUP_READONLY_MASK | POPUP_NOSELECTION_MASK),
+ E_POPUP_ITEM (N_("Copy"), G_CALLBACK (copy), POPUP_NOSELECTION_MASK),
+ E_POPUP_ITEM (N_("Paste"), G_CALLBACK (paste), POPUP_READONLY_MASK),
+ E_POPUP_ITEM (N_("Delete"), G_CALLBACK(delete), POPUP_READONLY_MASK | POPUP_NOSELECTION_MASK),
+ E_POPUP_SEPARATOR,
+
+#if 0
+ E_POPUP_SUBMENU (N_("Current View"), submenu = gal_view_instance_get_popup_menu (view->view_instance), 0),
+#endif
+ E_POPUP_TERMINATOR
+ };
contact_and_book = g_new(ContactAndBook, 1);
contact_and_book->view = view;
- g_object_ref(contact_and_book->view);
+ contact_and_book->submenu = submenu;
- selection_model = contact_and_book_get_selection_model(contact_and_book);
- if (selection_model) {
- contact_and_book->closure = cards;
- e_selection_model_foreach(selection_model, get_card_1, contact_and_book);
- }
+ g_object_ref (contact_and_book->view);
- ep = eab_popup_new("org.gnome.evolution.addressbook.view.popup");
- t = eab_popup_target_new_select(ep, view->book, !eab_model_editable(view->model), cards);
- t->target.widget = (GtkWidget *)view;
+ selection_model = contact_and_book_get_selection_model (contact_and_book);
+ if (selection_model)
+ selection = e_selection_model_selected_count (selection_model) > 0;
- for (i=0;i<sizeof(eabv_popup_items)/sizeof(eabv_popup_items[0]);i++)
- menus = g_slist_prepend(menus, &eabv_popup_items[i]);
+ popup = e_popup_menu_create (menu,
+ 0,
+ (eab_model_editable (view->model) ? 0 : POPUP_READONLY_MASK) +
+ (selection ? 0 : POPUP_NOSELECTION_MASK) +
+ (get_has_email_address (contact_and_book) ? 0 : POPUP_NOEMAIL_MASK),
+ contact_and_book);
- e_popup_add_items((EPopup *)ep, menus, NULL, eabv_popup_free, contact_and_book);
+ g_signal_connect (popup, "selection-done",
+ G_CALLBACK (free_popup_info), contact_and_book);
+ e_popup_menu (popup, event);
- menu = e_popup_create_menu_once((EPopup *)ep, (EPopupTarget *)t, 0);
- gtk_menu_popup(menu, NULL, NULL, NULL, NULL, event?event->button.button:0, event?event->button.time:gtk_get_current_event_time());
}
static void
@@ -1189,23 +1344,13 @@ contact_changed (EABModel *model, gint index, EABView *eav)
}
static void
-contacts_removed (EABModel *model, gpointer data, EABView *eav)
+contact_removed (EABModel *model, gint index, EABView *eav)
{
- GArray *indices = (GArray *) data;
- int count = indices->len;
- gint i;
-
- for (i = 0; i < count; i ++) {
-
-
- if (eav->displayed_contact == g_array_index (indices, gint, i)) {
-
- /* if the contact that's presently displayed is changed, clear the display */
- eab_contact_display_render (EAB_CONTACT_DISPLAY (eav->contact_display), NULL,
- EAB_CONTACT_DISPLAY_RENDER_NORMAL);
- eav->displayed_contact = -1;
- break;
- }
+ if (eav->displayed_contact == index) {
+ /* if the contact that's presently displayed is changed, clear the display */
+ eab_contact_display_render (EAB_CONTACT_DISPLAY (eav->contact_display), NULL,
+ EAB_CONTACT_DISPLAY_RENDER_NORMAL);
+ eav->displayed_contact = -1;
}
}
@@ -1739,7 +1884,7 @@ eab_view_print(EABView *view)
NULL);
print = e_contact_print_dialog_new(book, query);
g_free(query);
- gtk_widget_show(print);
+ gtk_widget_show_all(print);
}
else if (view->view_type == EAB_VIEW_TABLE) {
GtkWidget *dialog;
@@ -1747,7 +1892,7 @@ eab_view_print(EABView *view)
ETable *etable;
EContactPrintDialogWeakData *weak_data;
- dialog = e_print_get_dialog (_("Print cards"), GNOME_PRINT_DIALOG_RANGE | GNOME_PRINT_DIALOG_COPIES);
+ dialog = gnome_print_dialog_new(NULL, "Print cards", GNOME_PRINT_DIALOG_RANGE | GNOME_PRINT_DIALOG_COPIES);
gnome_print_dialog_construct_range_any(GNOME_PRINT_DIALOG(dialog), GNOME_PRINT_RANGE_ALL | GNOME_PRINT_RANGE_SELECTION,
NULL, NULL, NULL);
@@ -1807,8 +1952,9 @@ eab_view_print_preview(EABView *view)
g_object_ref (printable);
gtk_object_sink (GTK_OBJECT (printable));
- config = e_print_load_config ();
- master = gnome_print_job_new (config);
+ master = gnome_print_job_new(NULL);
+ config = gnome_print_job_get_config (master);
+ gnome_print_config_set_int (config, GNOME_PRINT_KEY_NUM_COPIES, 1);
pc = gnome_print_job_get_context( master );
e_printable_reset(printable);
while (e_printable_data_left(printable)) {
@@ -1843,43 +1989,12 @@ eab_view_print_preview(EABView *view)
void
eab_view_delete_selection(EABView *view)
{
- GList *list, *l;
-
- if (!eab_editor_confirm_delete(GTK_WINDOW(gtk_widget_get_toplevel(view->widget))))
- return;
-
- list = get_selected_contacts(view);
- if (e_book_check_static_capability (view->book, "bulk-remove")) {
- GList *ids = NULL;
-
- for (l=list;l;l=g_list_next(l)) {
- EContact *contact = l->data;
-
- ids = g_list_prepend (ids, (char*)e_contact_get_const (contact, E_CONTACT_UID));
- }
+ ContactAndBook contact_and_book;
- /* Remove the cards all at once. */
- /* XXX no callback specified... ugh */
- e_book_async_remove_contacts (view->book,
- ids,
- NULL,
- NULL);
-
- g_list_free (ids);
- }
- else {
- for (l=list;l;l=g_list_next(l)) {
- EContact *contact = l->data;
- /* Remove the card. */
- /* XXX no callback specified... ugh */
- e_book_async_remove_contact (view->book,
- contact,
- NULL,
- NULL);
- }
- }
+ memset (&contact_and_book, 0, sizeof (contact_and_book));
+ contact_and_book.view = view;
- e_free_object_list(list);
+ delete (GTK_WIDGET (view), &contact_and_book);
}
static void
@@ -2182,25 +2297,3 @@ eab_view_can_move_to_folder (EABView *view)
{
return view ? eab_view_selection_nonempty (view) && eab_model_editable (view->model) : FALSE;
}
-
-EABMenuTargetSelect *
-eab_view_get_menu_target (EABView *view, EABMenu *menu)
-{
- GPtrArray *cards = g_ptr_array_new();
- ESelectionModel *selection_model;
- EABMenuTargetSelect *t;
-
- selection_model = get_selection_model (view);
- if (selection_model) {
- ContactAndBook cab;
-
- cab.view = view;
- cab.closure = cards;
- e_selection_model_foreach(selection_model, get_card_1, &cab);
- }
-
- t = eab_menu_target_new_select(menu, view->book, !eab_model_editable(view->model), cards);
- t->target.widget = (GtkWidget *)view;
-
- return t;
-}
diff --git a/addressbook/gui/widgets/e-addressbook-view.h b/addressbook/gui/widgets/e-addressbook-view.h
index a55406915e..810252ea6b 100644
--- a/addressbook/gui/widgets/e-addressbook-view.h
+++ b/addressbook/gui/widgets/e-addressbook-view.h
@@ -32,9 +32,6 @@
G_BEGIN_DECLS
-struct _EABMenu;
-struct _EABMenuTargetSelect;
-
/* EABView - A card displaying information about a contact.
*
* The following arguments are available:
@@ -157,8 +154,6 @@ gboolean eab_view_can_stop (EABView *view);
gboolean eab_view_can_copy_to_folder (EABView *view);
gboolean eab_view_can_move_to_folder (EABView *view);
-struct _EABMenuTargetSelect *eab_view_get_menu_target (EABView *view, struct _EABMenu *menu);
-
G_END_DECLS;
#endif /* __EAB_VIEW_H__ */
diff --git a/addressbook/gui/widgets/eab-contact-display.c b/addressbook/gui/widgets/eab-contact-display.c
index 145b755781..464d36ebbe 100644
--- a/addressbook/gui/widgets/eab-contact-display.c
+++ b/addressbook/gui/widgets/eab-contact-display.c
@@ -36,7 +36,7 @@
#include <gtkhtml/gtkhtml.h>
#include <gtkhtml/gtkhtml-stream.h>
-#define HANDLE_MAILTO_INTERNALLY 1
+/*#define HANDLE_MAILTO_INTERNALLY 1*/
#define PARENT_TYPE (GTK_TYPE_HTML)
@@ -248,19 +248,6 @@ accum_attribute (GString *gstr, EContact *contact, const char *html_label, ECont
}
}
-static void
-accum_multival_attribute (GString *gstr, EContact *contact, const char *html_label, EContactField field, const char *icon, unsigned int html_flags)
-{
- GList *val_list, *l;
-
- val_list = e_contact_get (contact, field);
- for (l = val_list; l; l = l->next) {
- const char *str = (const char *) l->data;
- accum_name_value (gstr, html_label, str, icon, html_flags);
- }
- g_list_foreach (val_list, (GFunc) g_free, NULL);
- g_list_free (val_list);
-}
static void
render_contact_list (GtkHTMLStream *html_stream, EContact *contact)
@@ -343,12 +330,12 @@ render_contact (GtkHTMLStream *html_stream, EContact *contact)
g_string_assign (accum, "");
- accum_multival_attribute (accum, contact, _("AIM"), E_CONTACT_IM_AIM, AIM_ICON, 0);
- accum_multival_attribute (accum, contact, _("GroupWise"), E_CONTACT_IM_GROUPWISE, GROUPWISE_ICON, 0);
- accum_multival_attribute (accum, contact, _("ICQ"), E_CONTACT_IM_ICQ, ICQ_ICON, 0);
- accum_multival_attribute (accum, contact, _("Jabber"), E_CONTACT_IM_JABBER, JABBER_ICON, 0);
- accum_multival_attribute (accum, contact, _("MSN"), E_CONTACT_IM_MSN, MSN_ICON, 0);
- accum_multival_attribute (accum, contact, _("Yahoo"), E_CONTACT_IM_YAHOO, YAHOO_ICON, 0);
+ accum_attribute (accum, contact, _("AIM"), E_CONTACT_IM_AIM_HOME_1, AIM_ICON, 0);
+ accum_attribute (accum, contact, _("GroupWise"), E_CONTACT_IM_GROUPWISE_HOME_1, GROUPWISE_ICON, 0);
+ accum_attribute (accum, contact, _("ICQ"), E_CONTACT_IM_ICQ_HOME_1, ICQ_ICON, 0);
+ accum_attribute (accum, contact, _("Jabber"), E_CONTACT_IM_JABBER_HOME_1, JABBER_ICON, 0);
+ accum_attribute (accum, contact, _("MSN"), E_CONTACT_IM_MSN_HOME_1, MSN_ICON, 0);
+ accum_attribute (accum, contact, _("Yahoo"), E_CONTACT_IM_YAHOO_HOME_1, YAHOO_ICON, 0);
if (accum->len > 0)
gtk_html_stream_printf (html_stream, accum->str);
diff --git a/addressbook/tools/evolution-addressbook-export.c b/addressbook/tools/evolution-addressbook-export.c
index 070436dc0d..0793db7aad 100644
--- a/addressbook/tools/evolution-addressbook-export.c
+++ b/addressbook/tools/evolution-addressbook-export.c
@@ -58,9 +58,9 @@ main (int argc, char **argv)
{"list-addressbook-folders", 'l', POPT_ARG_NONE, &list_folders_mode, 0, N_("List local addressbook folders"),
NULL},
{"format", '\0', POPT_ARG_STRING, &output_format, 0, N_("Show cards as vcard or csv file"), N_("[vcard|csv]")},
- {"async", 'a', POPT_ARG_NONE, &async_mode, 0, N_("Export in asynchronous mode"), NULL},
+ {"async", 'a', POPT_ARG_NONE, &async_mode, 0, N_("Export in asynchronous mode "), NULL},
{"size", '\0', POPT_ARG_INT, &file_size, 0,
- N_("The number of cards in one output file in asychronous mode, default size 100."), N_("NUMBER")},
+ N_("The number of cards in one output file in asychronous mode,default size 100."), N_("NUMBER")},
{NULL, '\0', 0, NULL, 0, NULL, NULL}
};
/* popttable end ** */
@@ -150,7 +150,7 @@ main (int argc, char **argv)
action_list_cards_init (&actctx);
} else {
- g_warning (_("Unhandled error"));
+ g_warning (_("Impossible internal error."));
exit (-1);
}
diff --git a/addressbook/util/eab-book-util.c b/addressbook/util/eab-book-util.c
index 473d386f54..04c7d913d2 100644
--- a/addressbook/util/eab-book-util.c
+++ b/addressbook/util/eab-book-util.c
@@ -180,7 +180,7 @@ eab_nickname_query (EBook *book,
/* Copied from camel_strstrcase */
static char *
-eab_strstrcase (const char *haystack, const char *needle)
+strstrcase (const char *haystack, const char *needle)
{
/* find the needle in the haystack neglecting case */
const char *ptr;
@@ -197,7 +197,7 @@ eab_strstrcase (const char *haystack, const char *needle)
return (char *) haystack;
for (ptr = haystack; *(ptr + len - 1) != '\0'; ptr++)
- if (!g_ascii_strncasecmp (ptr, needle, len))
+ if (!strncasecmp (ptr, needle, len))
return (char *) ptr;
return NULL;
@@ -244,20 +244,20 @@ eab_contact_list_from_string (const char *str)
* parsed. Arguably, contact list parsing should all be in libebook's e-vcard.c,
* where we can do proper parsing and validation without code duplication. */
- for (p = eab_strstrcase (p, "BEGIN:VCARD"); p; p = eab_strstrcase (q, "\nBEGIN:VCARD")) {
+ for (p = strstrcase (p, "BEGIN:VCARD"); p; p = strstrcase (q, "\nBEGIN:VCARD")) {
gchar *card_str;
if (*p == '\n')
p++;
- for (q = eab_strstrcase (p, "END:VCARD"); q; q = eab_strstrcase (q, "END:VCARD")) {
+ for (q = strstrcase (p, "END:VCARD"); q; q = strstrcase (q, "END:VCARD")) {
gchar *temp;
q += 9;
temp = q;
temp += strspn (temp, "\r\n\t ");
- if (*temp == '\0' || !g_ascii_strncasecmp (temp, "BEGIN:VCARD", 11))
+ if (*temp == '\0' || !strncasecmp (temp, "BEGIN:VCARD", 11))
break; /* Found the outer END:VCARD */
}
diff --git a/calendar/ChangeLog b/calendar/ChangeLog
index 11ea448a03..32af5c1ad6 100644
--- a/calendar/ChangeLog
+++ b/calendar/ChangeLog
@@ -1,847 +1,41 @@
-2005-02-18 Rodrigo Moya <rodrigo@novell.com>
-
- * gui/alarm-notify/alarm-notify.c (cal_opened_cb): if opening
- the calendar failed, disconnect signals and unref it.
-
-2005-02-18 Chenthill Palanisamy <pchenthill@novell.com>
-
- * _EventPagePrivate: added a boolean variable is_meeting.
- * _TaskPagePrivate: added a boolean variable is_assignment.
- * gui/dialogs/task-page.h:
- * gui/dialogs/event-page.h: Added a function to set
- the is_meeting boolean variable.
- * gui/dialogs/event-editor.c: (show_meeting):
- * gui/dialogs/task-editor.c: (show_assignment): Called
- the function to set the boolean variable.
- * gui/dialogs/event-page.c: (event_page_init),
- (event_page_set_meeting), (source_changed_cb):
- * gui/dialogs/task-page.c: (task_page_init),
- (task_page_set_assignment), (source_changed_cb):
- If the source is changed and only if its a group
- event show the send options frame.
- * gui/gnome-cal.c: (client_cal_opened_cb): Do not
- popup the offline error dialog for tasks.
-
2005-02-15 Rodrigo Moya <rodrigo@novell.com>
* gui/migration.c (migrate_ical_folder_to_source): check return value
from e_cal_new, to display a better warning message.
-2005-02-11 Rodrigo Moya <rodrigo@novell.com>
-
- Fixes #72038
-
- * gui/itip-utils.c (itip_send_comp): when we get no recipients, don't
- send the message and return an error.
-
-2005-02-10 Chenthill Palanisamy <pchenthill@novell.com>
-
- * gui/e-cal-model.c: (e_cal_view_objects_added_cb): Remove
- the component from the view, if its already present before
- adding it.
-
-2005-02-09 Harish Krishnaswamy <kharish@novell.com>
-
- * gui/dialogs/event-editor.c: (event_editor_edit_comp):
- Always remove the meeting and scheduling pages when there are no
- attendees. This allows the sender to be added to the attendees list
- by default while creating new meetings.
-
-2005-02-08 Rodrigo Moya <rodrigo@novell.com>
-
- * gui/e-cal-model.c (set_instance_times): set instance times correctly.
-
-2005-02-07 JP Rosevear <jpr@novell.com>
-
- Fixes #61075
-
- * gui/apps_evolution_calendar.schemas.in.in: add long descriptions
- and clean up short items
-
-2005-02-05 Harish Krishnaswamy <kharish@novell.com>
-
- * calendar-errors.xml:
- * calendar-errors.xml.h:
- * gui/e-tasks.c: (client_cal_opened_cb):
- * gui/gnome-cal.c: (client_cal_opened_cb),
- (default_client_cal_opened_cb): add messages for
- calendar/tasks not marked for offline usage.
-
-
-2005-02-05 Harish Krishnaswamy <kharish@novell.com>
-
- * gui/dialogs/comp-editor.c (attach_message), (drop_action),
- (drop_popup_copy), (drop_popup_move), (drop_popup_cancel),
- (drop_popup_free), (drag_data_received), (drag_motion),
- (comp_editor_class_init), (comp_editor_init), (real_edit_comp):
- fix the dnd woes on calendar attachments.
- * gui/dialogs/cal-attachment-bar.c (add_from_file): reuse
- mail composer's error message.
-
-2005-02-04 Harry Lu <harry.lu@sun.com>
-
- Add a11y name for attachment button and bars.
-
- * gui/dialogs/cal-attachment-bar.c: (cal_attachment_bar_new):
- * gui/dialogs/comp-editor.c: (setup_widgets):
-
-2005-02-04 Rodney Dawes <dobey@novell.com>
-
- * gui/dialogs/comp-editor.[ch]: Add a string to CompEditorPrivate to
- store the name of the help section we need to refer for derived dialogs
- (response_cb): Handle the GTK_RESPONSE_HELP response and show help
- (setup_widgets): Add a button to the dialog for Help
- (comp_editor_init): Default to the "usage-calendar" help section
- (comp_editor_finalize): Free the help_section variable
- (comp_editor_show_help): Add a new method to actually open the help
- (comp_editor_set_help_section): Add a method for derivatives to set the
- help section they want to open
-
- * gui/dialogs/event-editor.c (event_editor_init): Set the help section
- we want to open for the event editor to "usage-calendar-apts"
-
- * gui/dialogs/task-editor.c (task_editor_init): Set the help section
- we want to open for the event editor to "usage-calendar-todo"
-
-2005-02-04 Rodrigo Moya <rodrigo@novell.com>
-
- * gui/e-tasks.c (update_view): clear the component preview when we
- update the view.
-
- * gui/e-cal-model.c (set_instance_times): use the correct timezone.
- Removed commented code.
-
-2005-02-04 Rodrigo Moya <rodrigo@novell.com>
-
- Fixes #71265
-
- * gui/e-week-view.c (e_week_view_remove_event_cb):
- * gui/e-day-view.c (e_day_view_remove_event_cb): if we remove the
- event we were editing, update internal pointers.
-
-2005-02-04 Vivek Jain <jvivek@novell.com>
-
- * calendar-errors.xml.h
- * calendar-errors.xml : changed the warning message string for
- server-version
-
-2005-02-04 Yong Sun <yong.sun@sun.com>
-
- Fix for #56901
-
- * gui/print.c: (bound_text): When the width>maxwidth, the
- pointer 'p' should also be backwarded, same as 'o'.
-
-2005-02-03 Rodney Dawes <dobey@novell.com>
-
- * calendar-errors.xml.h: Update to include new strings from the
- calendar-errors.xml file
-
-2005-02-03 Li Yuan <li.yuan@sun.com>
-
- * gui/dialogs/task-details-page.c: (get_widgets):
- add a11y name to url.
- * gui/dialogs/task-details-page.glade:
- add a11y name to date completed.
- * gui/dialogs/task-page.glade:
- add a11y names to due date and start date.
-
-2005-02-03 Vivek Jain <jvivek@novell.com>
-
- * calendar-errors.xml : added a warning message for invalid server
- version
- * gui/gnome-cal.c (default_client_cal_opened_cb)
- (client_cal_opened_cb): added a case to check the
- call status and display warning
-
-2005-02-02 Rodney Dawes <dobey@novell.com>
-
- * gui/dialogs/alarm-dialog.c (alarm_dialog_run): Set the border width
- for the internal dialog containers to be HIG compliant
-
- * gui/dialogs/alarm-dialog.glade: Remove the separator in the dialog
- and fix some spacing/padding issues to be HIG compliant
-
- * gui/dialogs/alarm-list-dialog.c (alarm_list_dialog_run): Set the
- border width for the internal dialog containers to be HIG compliant
-
- * gui/dialogs/alarm-list-dialog.glade: Remove the separator in the
- dialog and fix some spacing/padding issues to be HIG compliant
-
-2005-02-02 Rodrigo Moya <rodrigo@novell.com>
-
- Fixes #72090
-
- * gui/calendar-component.c (impl_handleURI): don't assume the URI is
- always correct.
-
-2005-02-01 Rodney Dawes <dobey@novell.com>
-
- * gui/dialogs/comp-editor.c (setup_widgets): Clean up the spacing
- and padding, and shove the notebook and expander arrow into a vbox
- so that we can be HIG compliant
- (comp_editor_init): Remove the separator from the "dialog" and set
- the border width for the internal dialog widgets appropriately to
- be compliant with the HIG for dialog borders
-
-2005-02-01 JP Rosevear <jpr@novell.com>
-
- * gui/e-tasks.c (e_tasks_destroy): fix typo
-
- * gui/gnome-cal.c (gnome_calendar_destroy): ditto
-
-2005-02-01 Rodrigo Moya <rodrigo@novell.com>
-
- * gui/e-cal-menu.c (e_cal_menu_target_new_select):
- * gui/e-cal-popup.c (e_cal_popup_target_new_select): add correct mask
- for detached recurrences.
-
-2005-02-01 Rodrigo Moya <rodrigo@novell.com>
-
- * gui/calendar-commands.c
- (calendar_control_sensitize_calendar_commands): only add real data
- to the array.
-
-2005-02-01 JP Rosevear <jpr@novell.com>
-
- Fixes #71944
+2005-02-03 Yong Sun <yong.sun@sun.com>
+
+ Fix for #56901
+
+ * gui/print.c: (bound_text): When the width>maxwidth, the
+ pointer 'p' should also be backwarded, same as 'o'.
- * gui/e-tasks.c: declare config_categories_changed_cb before its
- used
-
-2005-01-31 Hans Petter Jansson <hpj@novell.com>
-
- * common/Makefile.am (libevolution_calendarprivate_la_LDFLAGS):
- Remove the -module flag, this isn't supposed to be a module.
-
-2005-01-31 Hans Petter Jansson <hpj@novell.com>
-
- * idl/evolution-calendar.idl: Remove definition of CalObjUID and
- include that from Evolution-DataServer-Calendar.idl instead. This
- prevents the typecode from being defined twice.
-
-2005-01-31 Hans Petter Jansson <hpj@novell.com>
-
- * gui/e-cal-config.c (_ECalConfigPrivate): Use guint instead of ulong
- for signal ID.
-
-2005-01-31 Priit Laes <amd@tt.ee>
-
- Fixes #61078
-
- * gui/dialogs/task-page.glade: use consistent style for markup.
-
2005-01-31 Chenthill Palanisamy <pchenthill@novell.com>
Fixes #64682
- * gui/e-calendar-view.c: (transfer_item_to): Added an
- X property to identify if the appointment is moved from
+ * gui/e-calendar-view.c: (transfer_item_to): Added an X-property
+ so that the backend could identify if the appointment is moved from
another calendar.
-2005-01-28 JP Rosevear <jpr@novell.com>
-
- Fixes #71452
-
- * gui/dialogs/comp-editor.c (setup_widgets): listen for
- delete_event signal and handle it outside of the response signal
- so that cancel works properly
-
-2005-01-28 Rodrigo Moya <rodrigo@novell.com>
-
- * gui/e-tasks.c (setup_widgets):
- * gui/gnome-cal.c (setup_widgets): use correct key name.
-
-2005-01-28 Rodrigo Moya <rodrigo@novell.com>
-
- Fixes #33078
-
- * gui/gnome-cal.c: deal now with categories entirely here, no more
- "categories_changed" signal from the backends.
- (free_categories, add_categories, append_category_cb,
- client_categories_changed_cb, copy_categories): removed.
- (gnome_calendar_add_source): don't connect to removed signal.
- (gnome_calendar_destroy): destroy the config listener.
- (gnome_calendar_init): create a listener for the categories list
- GConf key.
- (config_categories_changed_cb): callback for configuration changes
- in category list.
- (setup_widgets): initialize the search bar with categories from
- the configuration.
-
- * gui/e-tasks.c (client_categories_changed_cb, e_tasks_add_todo_source,
- e_tasks_init, config_categories_changed_cb, e_tasks_destroy,
- setup_widgets): same as gnome-cal.c.
-
-2005-01-26 JP Rosevear <jpr@novell.com>
-
- Fixes #71485
-
- * calendar-errors.xml: fix paste-o
-
-2005-01-27 Harry Lu <harry.lu@sun.com>
-
- Fix a runtime invalid cast warning.
-
- * gui/e-calendar-table.c: (e_calendar_table_init): only set
- a11y name if atk is enabled.
-
-2005-01-26 Rodrigo Moya <rodrigo@novell.com>
-
- * gui/dialogs/recurrence-page.c (sensitize_buttons): objects returned
- from e_cal_get_objects_for_uid are ECalComponent's, so use
- g_object_unref to free them, not icalcomponent_free.
-
-2005-01-26 Li Yuan <li.yuan@sun.com>
-
- * gui/dialogs/cal-prefs-dialog.glade:
- use full name for the weekday checkbox.
-
- Fixes #71729.
-
-
-2005-01-26 JP Rosevear <jpr@novell.com>
-
- * gui/itip-utils.c (itip_send_comp): make sure we free the user
- list
-
-2005-01-25 Li Yuan <li.yuan@sun.com>
-
- * gui/e-calendar-table.c: (e_calendar_table_init):
- add a11y name to task table.
-
-2005-01-24 Rodrigo Moya <rodrigo@novell.com>
-
- * gui/dialogs/recurrence-page.c (sensitize_buttons): if there are
- detached instances, disable recurrence date widgets.
-
-2005-01-21 JP Rosevear <jpr@novell.com>
-
- Fixes #46404
-
- * gui/tasks-control.c (tasks_control_print_cmd): just call print
- tasks, we don't do the dialog here
-
- * gui/print.h: update protos
-
- * gui/print.c (print_calendar): use e_print routines for config
- and dialog and make copies and range settings properly available
- (print_comp): ditto
- (print_table): bring up dialog here so that printing for calendar
- list view works correctly
-
- * gui/calendar-commands.c (print): pass extra params to print
- table
-
-2005-01-19 Rodrigo Moya <rodrigo@novell.com>
-
- * importers/icalendar-importer.c (update_objects): use receive_objects
- method instead of individually updating objects. Set the method on the
- VCALENDAR object we create.
-
-2005-01-18 Rodrigo Moya <rodrigo@novell.com>
-
- Fixes #71407
-
- * gui/e-week-view.c (process_component): killed warnings.
- (e_week_view_start_editing_event): do nothing if the calendar is
- read only.
-
- * gui/e-day-view.c (e_day_view_start_editing_event): ditto.
-
-2005-01-18 Harish Krishnaswamy <kharish@novell.com>
-
- * gui/dialogs/cal-attachment-bar.c
- (cal_attachment_bar_get_attachment_list): handle error conditions more
- gracefully.
-
-2005-01-17 Rodrigo Moya <rodrigo@novell.com>
-
- * gui/calendar-component.c:
- * gui/calendar-offline-handler.c:
- * gui/comp-editor-factory.c:
- * gui/e-tasks.c:
- * gui/gnome-cal.c:
- * gui/misc.c:
- * gui/alarm-notify/alarm-notify.c: use libedataserver's e-url.
-
-2005-01-17 Nat Friedman <nat@novell.com>
-
- * gui/dialogs/url-editor-dialog.glade: Changed the title for the
- free/busy publishing settings dialog to "Free/Busy Publishing
- Settings" (away from "Free/Busy Editor" which made no sense).
-
-2005-01-17 Rodrigo Moya <rodrigo@novell.com>
-
- * gui/e-calendar-view.c (on_unrecur_appointment): removed the
- e_day_view_... prefix in warning messages.
-
-2005-01-17 Harish Krishnaswamy <kharish@novell.com>
-
- * gui/dialogs/cal-attachment-bar.c (destroy):
- fixed a kludge.
-
-2005-01-12 JP Rosevear <jpr@novell.com>
-
- Fixes #65820
+2004-01-16 JP Rosevear <jpr@novell.com>
+
+ Fixes #41624
+
+ * conduits/calendar/calendar-conduit.c (local_record_from_comp):
+ append the exceptions, don't keep overwriting the first
- * gui/weekday-picker.c (get_day_text): add translator comment
-
2005-01-08 Not Zed <NotZed@Ximian.com>
* gui/e-day-view.c (e_day_view_finish_resize): set
last_Edited_comp_string to NULL, not test it for null.
-2005-01-12 Harish Krishnaswamy <kharish@novell.com>
-
- * gui/dialogs/cal-attachment-bar.c:
- (cal_attachment_bar_set_attachment_list):
- reverting the offset 'hyphen' fix - not required anymore.
-
-2005-01-10 Rodrigo Moya <rodrigo@novell.com>
-
- * gui/e-day-view.c (e_day_view_on_editing_stopped): remove the
- temporary object from the view when stopping editing.
-
- * gui/e-week-view.c (e_week_view_on_editing_stopped): ditto.
-
-2005-01-10 Harish Krishnaswamy <kharish@novell.com>
-
- * gui/dialogs/cal-attachment-bar.c:
- (cal_attachment_bar_set_attachment_list):
- offset the file name to account for the 'hyphen'.
-
-2005-01-10 Chenthill Palanisamy <pchenthill@novell.com>
-
- * gui/dialogs/event-page.glade
- * gui/dialogs/task-page.glade: Showed the send options
- button and label. Hided the Send options Frame.
-
-2005-01-10 Harish Krishnaswamy <kharish@novell.com>
-
- * gui/dialogs/cal-attachment-bar.[ch]: (destroy), (init),
- (cal_attachment_bar_set_local_attachment_store),
- (cal_attachment_bar_get_attachment_list),
- (cal_attachment_bar_get_nth_attachment_filename),
- (cal_attachment_bar_set_attachment_list):
- Modified cal-attachment-bar to allow the path to
- the local attachment store be set externally, thereby
- hiding the storage policy of different backends from it.
- * gui/dialogs/comp-editor.c: (real_edit_comp):
- set the local attachment store after obtaining it from
- the calendar.
-
-2005-01-09 JP Rosevear <jpr@novell.com>
-
- * gui/calendar-component.c (impl_handleURI): handle calendar://
- uris
-
-2005-01-07 JP Rosevear <jpr@novell.com>
-
- * gui/dialogs/event-editor.c (event_editor_edit_comp): clear the
- attendees, somehow I remove this in an earlier commit
-
-2005-01-07 Rodrigo Moya <rodrigo@novell.com>
-
- * gui/dialogs/event-page.glade:
- * gui/dialogs/task-page.glade: put a name to the 'Send options' frame.
-
- * gui/dialogs/event-page.c (event_page_init): initialize reference to
- the 'Send options' frame.
- (get_widgets): get the 'Send options' frame from the .glade file.
- (event_page_hide_options): just hide the frame.
- (event_page_show_options): just show the frame.
-
- * gui/dialogs/task-page.c (task_page_init): initialize reference to the
- 'Send options' frame.
- (get_widgets): get the 'Send options' frame from the .glade file.
- (task_page_hide_options): just hide the frame.
- (task_page_show_options): just show the frame.
-
-2005-01-06 David Trowbridge <trowbrds@cs.colorado.edu>
-
- * gui/e-cal-event[hc]: initial import of ECalEvent targets
-
- * gui/migration.c (migrate_calendars): add component.migration event
-
-2005-01-06 JP Rosevear <jpr@novell.com>
+2004-12-06 Rodrigo Moya <rodrigo@novell.com>
- * gui/Makefile.am: install schemas properly
+ Fixes #68077
-2005-01-06 Chenthill Palanisamy <pchenthill@novell.com>
-
- merging send options
- * gui/dialogs/Makefile.am: Added two new files for send options.
- * gui/dialogs/e-send-options-utils.{ch}:
- (e_sendoptions_utils_set_default_data),
- (e_sendoptions_utils_fill_component): For setting and gettings the
- send options.
- * gui/dialogs/event-editor.c (event_editor_construct): Check for the static
- capabilities before showing send options.
- * gui/dialogs/event-page.c: (event_page_show_options),
- (event_page_fill_component), (e_sendoptions_clicked_cb):
* gui/dialogs/event-page.glade:
- * gui/dialogs/event-page.h: Added function to show/hide the send options button
- and label and run the send options dialog.
- * gui/dialogs/task-editor.c: (task_editor_construct),
- (task_editor_edit_comp):
- * gui/dialogs/task-page.c: (task_page_init), (task_page_finalize),
- (sensitize_widgets), (task_page_hide_options),
- (task_page_show_options), (task_page_fill_widgets),
- (task_page_fill_component), (get_widgets), (source_changed_cb),
- (e_sendoptions_clicked_cb), (init_widgets): Same as event-page.
- * gui/dialogs/task-page.glade: Added the send options button
- * gui/dialogs/task-page.h: Added functions hiding and showing send
- options button
-
-2005-01-05 Rodrigo Moya <rodrigo@novell.com>
-
- * gui/e-day-view.c (e_day_view_find_event_from_uid): added a new
- argument to pass the calendar client, since it might happen to have
- events with the same UID on different calendars.
- (e_day_view_do_key_press, model_rows_deleted_cb): added new argument
- to e_day_view_find_event_from_uid.
-
- * gui/e-week-view.c (e_week_view_find_event_from_uid): same as
- e-day-view.c.
- (e_week_view_do_key_press, model_rows_deleted_cb): added new argument
- to e_week_view_find_event_from_uid.
-
-2005-01-04 Rodrigo Moya <rodrigo@novell.com>
-
- * gui/e-cal-component-preview.c (write_html): use the new e-categories
- API in e-d-s.
-
-2005-01-04 Rodrigo Moya <rodrigo@novell.com>
-
- * gui/e-week-view.c (model_rows_deleted_cb): search our internal data
- for the correct event.
-
-2005-01-04 Harry Lu <harry.lu@sun.com>
-
- * gui/calendar-component.c: (create_component_view): add a11y name
- to calendar sidebar selector.
- * gui/tasks-component.c: (create_component_view): add a11y name
- to task sidebar selector.
-
-2005-01-03 JP Rosevear <jpr@novell.com>
-
- Fixes #69663
-
- * gui/e-cal-model-tasks.c (is_complete): look at the percent
- complete and status properties as well for completeness clues
-
-2005-01-03 Rodrigo Moya <rodrigo@novell.com>
-
- * gui/e-cal-model.c (e_cal_model_set_time_range): redo the queries
- after emitting the 'time_range_changed' signal, since now the
- views will only update their internal data but not redraw the
- events on that signal.
-
- * gui/e-day-view.c (model_changed_cb): removed, no longer needed.
- (e_day_view_recalc_day_starts): no need to call e_day_view_update_query.
- (e_day_view_init): no need to connect to 'model_changed' signal
- on the model, we already connect to the row/cell_changed ones.
-
- * gui/e-week-view.c (time_range_changed_cb): no need to call
- e_week_view_update_query.
- (model_changed_cb): removed, no longer needed.
- (e_week_view_init): no need to connect to 'model_changed' signal
- on the model, we already connect to the row/cell_changed ones.
-
-2004-12-31 JP Rosevear <jpr@novell.com>
-
- * gui/dialogs/schedule-page.c: add necessary include
-
- * gui/dialogs/meeting-page.c (sensitize_widgets): kill warning
-
- * gui/dialogs/cal-prefs-dialog.c (template_url_changed): kill warning
-
- * gui/dialogs/alarm-dialog.c (malarm_widgets_to_alarm): kill warnings
- (init_widgets): ditto
-
- * gui/main.c (initialize): no need to init the config system now
-
- * gui/e-cell-date-edit-config.h: include date edit text header
-
- * gui/e-cal-config.c (ecp_target_free): kill warning
-
- * gui/calendar-config.c: clean up includes, internally initialize
- the config setup to make it easier for others; kill dead functions
-
-2004-12-26 Rodrigo Moya <rodrigo@novell.com>
-
- * gui/e-cal-model.c (search_by_uid_and_client): removed superfluous if
- check.
- (e_cal_view_objects_modified_cb): add all objects at once.
-
- * gui/e-day-view.c (e_day_view_remove_event_cb): set fields we
- free to NULL.
-
-2004-12-24 Harish Krishnaswamy <kharish@novell.com>
-
- * gui/dialogs/event-editor.c (event_editor_edit_comp):
- Check for the existence of the meet/sched pages before
- attempting to remove them.
-
-2004-12-23 Chenthill Palanisamy <pchenthill@novell.com>
-
- Part of merge from offline branch
-
- * gui/dialogs/calendar-setup.c
- (eccp_general_offline): function to add the check box for
- folder offline settings.
- (offline_status_changed_cb): call back function for the same.
- (ECalConfigItem eccp_items[]), (ECalConfigItem ectp_items[]):
- Added the check box function call in both the structures.
-
-2004-12-23 Rodrigo Moya <rodrigo@novell.com>
-
- * gui/e-cal-model.c (set_instance_times): get instance times using
- the correct timezone.
- (redo_queries): emit signals before clearing the array.
-
- * gui/e-day-view.c (process_component):
- * gui/e-week-view.c (process_component): no need to try to update,
- always add.
-
-2004-12-23 Hans Petter Jansson <hpj@novell.com>
-
- * gui/e-select-names-editable.c: Correct bad include.
-
- * gui/dialogs/Makefile.am (IDL_GENERATED_H)
- (IDL_GENERATED)
- (BUILT_SOURCES): No longer needed, removed.
-
-2004-12-22 Hans Petter Jansson <hpj@novell.com>
-
- * gui/Makefile.am (IDLS)
- (SELECT_NAMES_IDL_GENERATED_H)
- (SELECT_NAMES_IDL_GENERATED_C)
- (SELECT_NAMES_IDL_GENERATED)
- (IDL_GENERATED): Remove the addressbook IDL.
-
- * gui/e-meeting-list-view.c (e_meeting_list_finalize)
- (add_section)
- (e_meeting_list_view_init)
- (process_section)
- (name_selector_dialog_close_cb)
- (get_select_name_dialog): Adapt to new ENameSelector.
-
- * gui/e-select-names-editable.c (esne_start_editing)
- (esne_finalize)
- (esne_init)
- (e_select_names_editable_get_type)
- (entry_activate)
- (e_select_names_editable_construct)
- (e_select_names_editable_get_address)
- (e_select_names_editable_get_name)
- (e_select_names_editable_set_address): Adapt to new ENameSelector.
-
- * gui/e-select-names-renderer.c (e_select_names_renderer_editing_done)
- (e_select_names_renderer_activated)
- (e_select_names_renderer_start_editing): Adapt to new ENameSelector.
-
- * gui/dialogs/alarm-dialog.c (malarm_widgets_to_alarm)
- (addressbook_clicked_cb)
- (addressbook_response_cb)
- (setup_select_names)
- (check_custom_email)
- (malarm_addresses_changed_cb): Adapt to new ENameSelector.
-
- * gui/dialogs/e-delegate-dialog.c (e_delegate_dialog_finalize)
- (e_delegate_dialog_construct)
- (addressbook_clicked_cb)
- (addressbook_response_cb)
- (e_delegate_dialog_get_delegate)
- (e_delegate_dialog_get_delegate_name): Adapt to new ENameSelector.
-
-2004-12-22 JP Rosevear <jpr@novell.com>
-
- * gui/e-meeting-store.c (freebusy_async): prevent compare against
- null default_fb_uri and fix thinko
-
-2004-12-22 JP Rosevear <jpr@novell.com>
-
- * gui/e-cal-model.c: Change copyright from ximian to novell
-
-2004-12-17 Not Zed <NotZed@Ximian.com>
-
- * gui/e-calendar-table.c (e_calendar_table_show_popup_menu):
-
- * gui/tasks-component.c (popup_event_cb):
-
- * gui/gnome-cal.c (gnome_calendar_view_popup_factory):
-
- * gui/e-calendar-view.c (e_calendar_view_create_popup_menu):
-
- * gui/alarm-notify/alarm-queue.c (tray_icon_clicked_cb):
-
- * gui/dialogs/meeting-page.c (button_press_event):
-
- * gui/calendar-component.c (popup_event_cb):
-
-2004-12-22 JP Rosevear <jpr@novell.com>
-
- Fixes #61077
-
- * gui/dialogs/task-details-page.glade: remove extraneous tab
-
- * gui/dialogs/alarm-dialog.c: ditto
-
-2004-12-22 JP Rosevear <jpr@novell.com>
-
- Fixes #61076
-
- * gui/comp-editor-factory.c (open_client): don't translate command
- line warnings
-
- * gui/calendar-offline-handler.c (backend_go_online): ditto
- (backend_go_offline): ditto
-
-2004-12-21 JP Rosevear <jpr@novell.com>
-
- Fixes #41624
-
- * conduits/calendar/calendar-conduit.c (local_record_from_comp):
- append the exceptions, don't keep overwriting the first
-
-2004-12-21 Rodrigo Moya <rodrigo@novell.com>
-
- * gui/e-cal-model.c (set_instance_times): no need to convert times now.
- (add_instance_cb): no need to convert here.
-
-2004-12-21 Rodrigo Moya <rodrigo@novell.com>
-
- Merge from recurrences-work-branch
-
- * gui/e-cal-model.c (free_comp_data): renamed to
- e_cal_model_free_component_data and made it public.
- (clear_objects_array, e_cal_view_objects_removed_cb,
- remove_client_objects): use e_cal_model_free_component_data.
- (get_dtstart): get the DTSTART correctly for recurrences.
- (add_instance_cb): initialize all members of ECalModelComponent, and
- use the correct icalcomponent when setting the field.
- (set_instance_times): new function to set the instance_* fields of
- the ECalModelComponent when not expanding recurrences.
- (e_cal_view_objects_added_cb): expand recurrences for all objects when
- the model is set to expand. Call set_instance_times when not
- expanding recurrences.
- (e_cal_view_objects_modified_cb): made it remove objects and re-add
- them.
- (copy_ecdv): check values before using them.
- (e_cal_model_copy_component_data): Added code to copy the instance_* and
- color fields.
-
- * gui/e-cal-model-calendar.c (get_dtend): get the DTEND correctly for
- recurrences.
- (ecmc_set_value_at): ask user which instances to modify.
-
- * gui/e-day-view.c (e_day_view_find_event_from_uid): changed to search
- by UID and RID if given.
- (process_component): changed to not expand recurrences at all, this is
- now done on the model.
- (row_deleted_check_cb, remove_uid_cb): removed these functions.
- (model_rows_deleted_cb): changed to just remove the rows signalled from
- the model, which is the responsible for the recurrence expansion.
- (e_day_view_new): set the model to expand recurrences.
- (e_day_view_remove_event_cb): check the value searched in the array.
- (e_day_view_do_key_press): use e_day_view_find_event_from_uid correctly.
-
- * gui/e-week-view.c (e_week_view_find_event_from_uid): changed to search
- by UID and RID if given.
- (process_component_recur_cb): removed.
- (process_component): changed to not expand recurrences at all, this is
- now done on the model.
- (row_deleted_check_cb, remove_uid_cb): removed these functions.
- (model_rows_deleted_cb): changed to just remove the rows signalled from
- the model, which is the responsible for the recurrence expansion.
- (e_week_view_new): set the model to expand recurrences.
- (e_week_view_remove_event_cb): check the value searched in the array.
- Set the ECalModelComponent field to NULL after freeing it.
- (e_week_view_do_key_press): use e_week_view_find_event_from_uid
- correctly.
-
- * gui/dialogs/recur-comp.c (recur_component_dialog): remove the
- RECURRENCE-ID from the object when modifying all instances.
-
-2004-12-18 James Bowes <bowes@cs.dal.ca>
-
- * gui/apps_evolution_calendar.schemas.in.in: Add schema for Free/Busy
- template uri.
- * gui/calendar-config-keys.h:
- * gui/calendar-config.c: (calendar_config_get_free_busy_template),
- (calendar_config_set_free_busy_template),
- (calendar_config_add_notification_free_busy_template):
- * gui/calendar-config.h: Functions to get, set and monitor the
- Free/Busy template uri gconf setting.
- * gui/dialogs/cal-prefs-dialog.c: (template_url_changed),
- (setup_changes), (get_widgets), (show_fb_config):
- * gui/dialogs/cal-prefs-dialog.glade:
- * gui/dialogs/cal-prefs-dialog.h: Change 'Free/Busy Publish' tab to
- 'Free/Busy'. Add an entry for setting the default Free/Busy uri.
- Only change the gconf setting on 'focus out' event
- * gui/e-meeting-store.c: (refresh_queue_remove): Check the hash using
- the attendee's mailto: address, rather than the memory address of the
- attendee object as the key.
- (e_meeting_store_get_fb_uri), (e_meeting_store_set_fb_uri): Get and set
- the EMeetingStore's Free/Busy template string.
- (process_callbacks_main_thread), (process_callbacks): Process callbacks
- in the main thread, so that widgets can be redrawn properly.
- (replace_string): Utility function for replacing wildcards in the
- default Free/Busy uri.
- (ems_finalize), (ems_init), (freebusy_async), (refresh_busy_periods),
- (refresh_queue_add), (e_meeting_store_refresh_busy_periods): Add the
- ability to check for Free/Busy information from a default location,
- if all else fails.
- (start_async_read): Use gnome-vfs to read the Free/Busy information.
- * gui/e-meeting-store.h: Add function prototypes for get and set fb_uri
- * gui/e-meeting-time-sel.c: (e_meeting_time_selector_init),
- (e_meeting_time_selector_destroy), (free_busy_timeout_refresh),
- (free_busy_template_changed_cb): Watch for a change in the Free/Busy
- template gconf setting, and check for new Free/Busy data if it occurs.
- * gui/e-meeting-time-sel.h: Include variable for notification function
- id on changes to the Free/Busy uri in the EMeetingTimeSelector .
-
-2004-12-17 Rodney Dawes <dobey@novell.com>
-
- * gui/alarm-notify/alarm-notify-dialog.c (an_minutes_update_label):
- Add callback function for doing ngettext on the "minutes" label
- (alarm_notify_dialog): Get the "minutes" label from the glade file
- and set the callback for its "value_changed" signal
-
- Fixes #47535
-
-2004-12-13 Harish Krishnaswamy <kharish@novell.com>
-
- * gui/dialogs/calendar-setup.c : Correct some white space
- ugliness in the previous commit.
-
-2004-12-13 Vivek Jain <jvivek@novell.com>
-
- * gui/dialogs/calendar-setup.c : Changed the window title based upon
- the source.
-
-2003-12-09 Rodrigo Moya <rodrigo@novell.com>
-
- * gui/e-calendar-view.c (on_unrecur_appointment): keep a local copy
- of the ECal.
-
-2004-12-08 Hans Petter Jansson <hpj@novell.com>
-
- * gui/e-meeting-list-view.c
- * gui/e-select-names-editable.c
- * gui/dialogs/alarm-dialog.c
- * gui/dialogs/e-delegate-dialog.c: Include <libebook/e-destination.h>
- from evolution-data-server.
-
-2004-12-08 Harish Krishnaswamy <kharish@novell.com>
-
- * gui/e-week.c (time_range_changed_cb, e_week_view_set_first_day_shown):
- update the query so currently held events can be cleared off.
-
-2004-12-08 David Mosberger <davidm@napali.hpl.hp.com>
-
- * gui/main.c: include plugin headers to fix 64 bit problems.
+ * gui/dialogs/task-page.glade: expand the horizontal box so that it
+ fills all available space.
2004-12-06 Rodrigo Moya <rodrigo@novell.com>
@@ -856,130 +50,11 @@
2004-12-02 Chenthill Palanisamy <pchenthill@novell.com>
- * gui/dialogs/task-editor.[ch] (task_editor_new), (task_editor_construct),
- (show_assignment):
- Add a boolean variable to denote assigned task and construct the
- meeting page only for the assigned task. Set it as a group item
- in component editor.
- (_TaskEditorPrivate): added the boolean variable (is_assigned).
- (task_editor_init): initialized the variable.
- * gui/dialogs/comp-editor.[ch]: Added functions to set and get whether comp
- is a group item or individual item.
- * gui/comp-editor.c (make_title_from_string), (make_title_from_comp):
- Set the Title for the appointment editor window as "Meeting" or "Assigned
- Task" if its a group calendar/task item.
- (_CompEditorPrivate): added a boolean variable (is_group_item).
- (comp_editor_init): initialized the same.
- * gui/dialogs/event-editor.c (event_editor_construct), (show_meeting): Set whether
- the component is a group item or not in comp editor.
- * gui/e-calendar-table.c (e_calendar_table_open_task), (e_calendar_table_open_selected),
- (open_task_by_row): Check whether the component being opened is an assigned task by
- checking for attendees and call open_task with proper value for boolean variable assign.
- * gui/comp-editor-factory.c (edit_existing):
- * gui/e-calendar-table.c (open_task):
- * gui/e-tasks.c (e_tasks_new_task):
- * gui/gnome-cal.c (gnome_calendar_new_task):
- * gui/tasks-component.c (create_new_todo):
- Called the function task_editor_new with a added argument.
-
-2004-12-02 Chenthill Palanisamy <pchenthill@novell.com>
-
- * gui/e-day-view.c (e_day_view_finish_resize), (e_day_view_reshape_day_event)
- (e_day_view_change_event_time): Free the string day_view->last_edited_comp_string
+ * gui/e-day-view.c (e_day_view_finish_resize), (e_day_view_reshape_day_event),
+ (e_day_view_change_event_time): Free the string day_view->last_edited_comp_string
before changing assigning it another value.
* gui/e-week-view.c (e_week_view_change_event_time): Free the string
week_view->last_edited_comp_string for the same reason above.
-
-2004-11-29 Chenthill Palanisamy <pchenthill@novell.com>
-
- * calendar-errors.xml.h: committng this file. Missed to
- commit this one.
-
-2004-11-29 Chenthill Palanisamy <pchenthill@novell.com>
-
- * gui/dialogs/comp-editor.c (response_cb): Moved the call
- for the warning dialog (send_component_prompt_subject) after
- the component is saved (save_comp_with_send).
-
-2004-11-26 JP Rosevear <jpr@novell.com>
-
- * gui/alarm-notify/alarm-queue.c (display_notification): ditto
-
- * gui/e-timezone-entry.c (e_timezone_entry_init): get the image
- directly from the icon factory
-
-2004-11-26 JP Rosevear <jpr@novell.com>
-
- * gui/alarm-notify/alarm-queue.c (display_notification): prevent
- crash if there is no description
-
-2004-11-25 Harish Krishnaswamy <kharish@novell.com>
-
- * gui/calendar-component.c:
- (new_calendar_cb), (edit_calendar_cb): Use modified_setup_edit_calendar call.
- (popup_event_cb): If source is null (Rt click on a source group), show the new
- calendar popup menu item. Else, do not show the new calendar option.
- * gui/dialogs/calendar-setup.[ch] (eccp_get_source_type): Compare the
- source_groups by their uid and not the pointers, so that the correct option
- is activated on the combo box.
- (calendar_setup_edit_calendar) : add a source_group parameter to the function.
- (calendar_setup_new_calendar): Use modified signature of the above function.
- * gui/e-calendar-view.c (on_edit_appointment): check the icalcomponent
- to see if it is a meeting and set the argument to e_calendar_view_edit_appointment
- correctly.
-
-2004-11-25 Chenthill Palanisamy <pchenthill@novell.com>
-
- * gui/dialogs/event-deitor.c (show_meeting): removed the
- call for comp_editor_show_page, so that the event page
- shows up at first instead of meeting page when a meeting
- is opened.
-
-2004-11-25 Chenthill Palanisamy <pchenthill@novell.com>
-
- * calendar-errors.xml: Added two error ids to display use
- it when the meeting is created without a summary.
- * gui/dialogs/send-comp.[ch] (send_component_prompt_subject): Added a
- function to prompt for a dialog when a meeting/assigned task is sent
- without a summary.
- * gui/dialogs/comp-editor.c (response_cb): Called the above mentioned
- function when the summary is not present.
-
-2004-11-23 Rodney Dawes <dobey@novell.com>
-
- * gui/alarm-notify/alarm-notify-dialog.[ch]:
- Add gtkimage.h to includes, and remove gtkhtml headers
- Add and remove some widgets in the AlarmNotify struct
- (dialog_destroy_cb, delete_event_cb, close_clicked_cb):
- (snooze_clicked_cb, edit_clicked_cb, url_requested_cb):
- (make_html_display, write_times, write_html_heading):
- (alarm_notify_dialog_disable_buttons):
- Remove all these unneeded functions (no more GtkHTML in the dialog)
- (alarm_notify_dialog): Add description and location arguments
- Rename message argument to summary
- Update gtk-doc comment block to reflect API changes
- Clean up code to use gtk_dialog_run () and use a HIG compliant dialog
-
- * gui/alarm-notify/alarm-notify.glade: Update the alarm notify
- dialog to be HIG compliant and not use GtkHTML, and display more
- information that is relevant to the appointment we are alerting of
-
- * gui/alarm-notify/alarm-queue.c: Add new variables to the
- TrayIconData structure so we can access the description and location
- (on_dialog_objs_removed_cb): Remove alarm_dialog bits
- (notify_dialog_cb): Remove alarm_dialog bits
- (tray_icon_destroyed_cb): Free the description and location as well
- (open_alarm_dialog): alarm_notify_dialog does all the work now, we
- don't need to trap the dialog widget here
- (display_notification): Add code to get the description and location
- information from the cal component
- Avoid using an alarm component which has less useful API
- Fix a warning when creating the tray_icon widget
-
-2004-11-15 Not Zed <NotZed@Ximian.com>
-
- * gui/dialogs/Makefile.am (libcal_dialogs_la_LIBADD): add
- libeabutil, since we use e-destination.
2004-11-08 Rodney Dawes <dobey@novell.com>
@@ -989,386 +64,28 @@
Fixes #47529
-2004-11-04 Rodrigo Moya <rodrigo@novell.com>
-
- * gui/dialogs/event-page.glade:
- * gui/dialogs/task-page.glade: expand the horizontal box so that it
- fills all available space.
-
-2004-11-03 David Trowbridge <trowbrds@cs.colorado.edu>
-
- * gui/e-cal-config.c: added EConfig subclass for calendars
- * gui/calendar-component.c, gui/tasks-component.c: initialize
- plugin hooks on component startup.
- * gui/dialogs/calendar-setup.c: Converted to use EConfig
-
-2004-11-04 Li Yuan <li.yuan@sun.com>
-
- Fixes #6767
-
- * gui/e-day-view-main-item.c:
- (e_day_view_main_item_draw_day_event):
- use widget->style instead of hard code colors.
- * gui/e-day-view.c: (e_day_view_realize), (e_day_view_set_colors),
- (e_day_view_style_set), (e_day_view_reshape_long_event),
- (e_day_view_reshape_day_event):
- ditto.
- * gui/e-week-view.c: (e_week_view_realize),
- (e_week_view_set_colors), (e_week_view_style_set),
- (e_week_view_reshape_event_span):
- ditto.
-
-2004-11-02 JP Rosevear <jpr@novell.com>
-
- * gui/e-day-view-config.c (set_twentyfour_hour): make sure the day
- view times redraw themselves if we switch 24/12 hour modes
-
2004-11-02 JP Rosevear <jpr@novell.com>
+
+ Fixes #68707
+
+ * gui/e-week-view-event-item.c (e_week_view_event_item_draw):
+ restrict the range to 0-23 (midnight end times became '24')
- Fixes #68707
-
- * gui/e-week-view-event-item.c (e_week_view_event_item_draw):
- restrict the range to 0-23 (midnight end times became '24')
-
-2004-10-28 Not Zed <NotZed@Ximian.com>
-
- * gui/tasks-component.c (popup_event_cb):
- * gui/e-calendar-view.c (e_calendar_view_create_popup_menu):
- * gui/e-calendar-table.c (e_calendar_table_show_popup_menu):
- * gui/calendar-component.c (popup_event_cb): added hook doco.
-
-2004-10-27 Rodrigo Moya <rodrigo@novell.com>
-
- * gui/e-cal-list-view.c (e_cal_list_view_new): don't expand recurrences
- for the list view.
-
-2004-10-21 Harish Krishnaswamy <kharish@novell.com>
-
- * gui/e-cal-popup.[ch]: (e_cal_popup_target_new_source):
- Add status bits to denote if the calendar source is available offline
- so that plugins to calendar popups can use the status qualifier to denote
- their visibility preferences.
-
-2004-10-21 Rodrigo Moya <rodrigo@novell.com>
-
- * gui/dialogs/select-source-dialog.c: use the new source selector
- dialog in libedataserverui.
-
-2004-10-20 JP Rosevear <jpr@novell.com>
-
- * gui/calendar-component.c: put an icon on the properties menu item
-
- * gui/tasks-component.c: ditto
-
- * gui/main.c (initialize): register plugin hooks for tasks and
- calendar
-
-2004-10-20 JP Rosevear <jpr@novell.com>
-
- * gui/e-cal-popup.c (ecalph_class_init): correct classid
-
-2004-10-19 JP Rosevear <jpr@novell.com>
-
- * gui/calendar-component.c, gui/e-cal-menu.c, gui/e-cal-popup.c,
- gui/e-calendar-table.c, gui/e-calendar-view.c, gui/gnome-cal.c,
- gui/tasks-component.c, gui/alarm-notify/alarm-queue.c,
- gui/dialogs/meeting-page.c: convert to org.gnome hook names
-
-2004-10-19 Harish Krishnaswamy <kharish@novell.com>
-
- * gui/comp-editor-factory.c: (edit_existing):
- Use e_cal_component_has_attendees to test if it is a meeting.
- * gui/dialogs/event-editor.c: (event_editor_init):
- By default, the event is not a meeting.
- (event_editor_construct): Do not add the invitation, scheduling pages
- to the editor if it is not a meeting.
- * gui/e-day-view.c: (e_day_view_on_event_double_click):
- check the icalproperty to test if the event is a meeting.
-
-2004-10-19 JP Rosevear <jpr@novell.com>
-
- * gui/gnome-cal.c (connect_list_view_focus): listen to the canvas
- for focus events
- (setup_widgets): listen for listen view selection changes
-
- * gui/e-cal-list-view.c (setup_e_table): listen for the cursor to
- move
- (e_cal_list_view_cursor_change_cb): indicate the selection changed
-
-2004-10-19 Harish Krishnaswamy <kharish@novell.com>
-
- * gui/calendar-component.c (create_new_event):
- * gui/e-calendar-view.c: (e_calendar_view_edit_appointment):
- * gui/comp-editor-factory.c (edit_existing), (edit_new):
- * gui/dialogs/event-editor.c (event_editor_edit_comp),
- (event_editor_new): updated the calls to event_editor_new
- with additional argument.
- * gui/dialogs/event-editor.h: add parameter is_meeting to
- distinguish between events and meetings.
- * gui/dialogs/meeting-page.c: (sensitize_widgets):
- use explicit GError variable so that BUSY_ERROR
- conditions do not lead us to think the calendar is readonly.
- * gui/e-meeting-store.c: (refresh_queue_remove), (ems_init),
- (e_meeting_store_remove_attendee), (freebusy_async),
- (refresh_busy_periods), (refresh_queue_add): Make free-busy calls
- to backends async. Fixed the problem of spurious attendees getting
- added to the refresh_data.
-
-2004-10-14 Not Zed <NotZed@Ximian.com>
-
- * gui/e-cal-menu.c (e_cal_menu_target_new_select): dont access a
- NULL client.
-
- * gui/gnome-cal.c (gnome_calendar_get_taskpad_menu)
- (gnome_calendar_get_calendar_menu): accessors to get the menu
- managers.
- (gnome_calendar_init): setup menu managers.
-
-2004-10-13 Not Zed <NotZed@Ximian.com>
-
- * gui/calendar-commands.c (calendar_control_activate)
- (calendar_control_deactivate): activate and deactivate the
- calendar and taskpad menu handlers.
- (sensitize_items): helper to sensitise items based on target
- masks.
- (calendar_control_sensitize_calendar_commands): update the
- calendar menu manager target appropriately.
- (sensitize_taskpad_commands): same for the taskpad.
-
- * gui/e-cal-menu.[ch]: Targets for main menu management.
-
- * gui/e-cal-popup.c (e_cal_popup_target_new_select): fix cast.
- Also include the tasks stuff in the hook metadata.
-
-2004-10-15 JP Rosevear <jpr@novell.com>
-
- * gui/calendar-commands.c (calendar_control_activate): remove
- useless ifdef'd out statement (its been unused for 3+ years)
-
-2004-10-15 JP Rosevear <jpr@novell.com>
-
- * gui/calendar-commands.h (calendar_goto_today): remove prototype
-
- * gui/calendar-commands.c: remove dead function
-
-2004-10-14 JP Rosevear <jpr@novell.com>
-
- * gui/e-meeting-attendee.c: convert to G_DEFINE_TYPE
-
- * gui/e-meeting-list-view.c: ditto
-
- * gui/e-meeting-time-sel.c: ditto
-
- * gui/e-meeting-time-sel-item.c: ditto
-
- * gui/e-select-names-renderer.c: ditto
-
- * gui/e-timezone-entry.c: ditto
-
- * gui/e-tasks.c: ditto
-
- * gui/gnome-cal.c: ditto
-
- * gui/weekday-picker.c: ditto
-
-2004-10-14 JP Rosevear <jpr@novell.com>
-
- * gui/e-cell-date-edit-config.c: convert to G_DEFINE_TYPE
-
- * gui/e-cell-date-edit-text.c: ditto
-
- * gui/e-comp-editor-registry.c: ditto
-
- * gui/e-date-edit-config.c: ditto
-
- * gui/e-mini-calendar-config.c: ditto
-
-2004-10-14 JP Rosevear <jpr@novell.com>
-
- * gui/e-cal-list-view-config.c: convert to G_DEFINE_TYPE
-
- * gui/e-cal-list-view.c: ditto
-
- * gui/e-cal-model-calendar.c: ditto
-
- * gui/e-cal-model-tasks.c: ditto
-
- * gui/e-cal-model.c: ditto
-
- * gui/e-calendar-table-config.c: ditto
-
- * gui/e-calendar-table.c: ditto
-
- * gui/e-calendar-view.c: ditto
-
-2004-10-14 JP Rosevear <jpr@novell.com>
-
- * gui/calendar-view.c: convert to G_DEFINE_TYPE
-
- * gui/calendar-view-factory.c: ditto
-
- * gui/cal-search-bar.c: ditto
-
- * gui/e-cal-component-preview.c: ditto
-
-2004-10-14 JP Rosevear <jpr@novell.com>
-
- * gui/e-week-view-config.c: convert to G_DEFINE_TYPE
-
- * gui/e-week-view-event-item.c: ditto
-
- * gui/e-week-view-main-item.c: ditto
-
- * gui/e-week-view-titles-item.c: ditto
-
- * gui/e-week-view.c: ditto
-
-2004-10-14 JP Rosevear <jpr@novell.com>
-
- * gui/e-day-view.c: convert to G_DEFINE_TYPE
-
- * gui/e-day-view-config.c: ditto
-
- * gui/e-day-view-main-item.c: ditto
-
- * gui/e-day-view-time-item.c: ditto
-
- * gui/e-day-view-top-item.c: ditto
-
-2004-10-14 JP Rosevear <jpr@novell.com>
-
- * gui/dialogs/comp-editor.c: convert to G_DEFINE_TYPE
-
- * gui/dialogs/meeting-page.c: ditto
-
- * gui/dialogs/recurrence-page.c: ditto
-
- * gui/dialogs/schedule-page.c: ditto
-
- * gui/dialogs/e-delegate-dialog.c: ditto
-
- * gui/dialogs/event-editor.c: ditto
-
- * gui/dialogs/task-editor.c: ditto
-
- * gui/dialogs/task-details-page.c: ditto
-
- * gui/dialogs/select-source-dialog.c
- (primary_selection_changed_cb): fix warning
-
-2004-10-13 JP Rosevear <jpr@novell.com>
-
- * gui/dialogs/task-page.c: ditto
-
- * gui/calendar-component.h: remove e-source-selector include
-
- * gui/tasks-component.h: ditto
-
- * gui/calendar-component.c: update include to libedataserverui for
- source selector and option menus
-
- * gui/e-cal-popup.c: ditto
-
- * gui/dialogs/url-editor-dialog.h: ditto
-
- * gui/dialogs/select-source-dialog.c: ditto
-
- * gui/tasks-component.c: ditto
-
- * importers/icalendar-importer.c: ditto
-
- * gui/e-itip-control.c: ditto; use G_DEFINE_TYPE instead of
- E_MAKE_TYPE
+2004-11-03 JP Rosevear <jpr@novell.com>
+
+ * gui/gnome-cal.c (connect_list_view_focus): listen to the canvas
+ for focus events
+ (setup_widgets): listen for listen view selection changes
+
+ * gui/e-cal-list-view.c (setup_e_table): listen for the cursor to
+ move
+ (e_cal_list_view_cursor_change_cb): indicate the selection changed
- * gui/dialogs/event-page.c: ditto
-
- * gui/dialogs/task-page.c: ditto
+2004-11-02 JP Rosevear <jpr@novell.com>
+
+ * gui/e-day-view-config.c (set_twentyfour_hour): make sure the day
+ view times redraw themselves if we switch 24/12 hour modes
-2004-10-12 Li Yuan <li.yuan@sun.com>
-
- * gui/e-day-view.c: (e_day_view_on_main_canvas_button_press):
- * gui/e-week-view.c: (e_week_view_on_button_press):
- If main_canvas has focus, do not grub it. Emit the
- selected_time_changed signal after the selection day changed.
-
-2004-10-12 Not Zed <NotZed@Ximian.com>
-
- * gui/dialogs/meeting-page.c (button_press_event): convert menu to
- epopup.
-
-2004-10-12 Not Zed <NotZed@Ximian.com>
-
- * gui/e-calendar-table.c (setup_popup_icons): removed.
- (e_calendar_table_show_popup_menu): convert to use e-popup for
- pluggable popup menu.
- (e_calendar_table_on_open_task, e_calendar_table_on_save_as)
- (e_calendar_table_on_print_task, e_calendar_table_on_cut)
- (e_calendar_table_on_copy, e_calendar_table_on_paste)
- (e_calendar_table_on_assign, e_calendar_table_on_forward)
- (delete_cb):
- (mark_as_complete_cb, open_url_cb): convert to epopup callbacks.
- Moved all of the callbacks above the table rather than maintaining
- forward declarations for some of them.
-
- * gui/e-cal-popup.c (e_cal_popup_target_new_select): add the task
- required masks, and make one vs many mutally exclusive.
-
- * gui/e-calendar-view.c (e_calendar_view_create_popup_menu):
- copy/setup the event list here.
-
- * gui/e-cal-popup.c (e_cal_popup_target_new_select): take model +
- events rather than the calendar view.
-
-2004-10-12 Li Yuan <li.yuan@sun.com>
-
- * gui/calendar-commands.c:
- (calendar_get_text_for_folder_bar_label):
- When the start year and the end year are the same, the num should
- be displayed in start time.
- * gui/dialogs/alarm-dialog.glade:
- Add names to comboxes in alarm-dialog page.
- * gui/dialogs/cal-prefs-dialog.glade:
- Add labbled_by relation for e_date_edit.
- Add names to comboxes in general tab and display tab.
- Add shortcut keys to start_of_day_label and end_of_day_label.
- * gui/dialogs/event-page.c: (init_widgets):
- Use the default text_buffer of gtk_text_view instead of
- creating one.
- * gui/dialogs/event-page.glade:
- Add labbled_by relation for e_date_edit.
- * gui/dialogs/meeting-page.glade:
- Set an atk name for organizer widget.
- * gui/dialogs/task-page.c: (init_widgets):
- Use the default text_buffer of gtk_text_view instead of
- creating one.
- * gui/dialogs/task-page.glade:
- Add labbled_by relation for e_date_edit.
- Add a11y names to task description and categories.
- * gui/e-alarm-list.c: (e_alarm_list_iter_n_children):
- Remove the iter checker. The iter can't have a valid value at this time.
- * gui/e-date-time-list.c: (e_date_time_list_iter_n_children):
- Remove the iter checker. The iter can't have a valid value at this time.
- * gui/e-meeting-time-sel.c: (e_meeting_time_selector_construct):
- Add labbled_by relation for e_date_edit.
- * gui/e-timezone-entry.c: (e_timezone_entry_class_init),
- (e_timezone_entry_init), (e_timezone_entry_mnemonic_activate),
- (e_timezone_entry_focus):
- Add a focus handler for e-timezone-entry. Set an atk name for the
- button.
- * gui/e-week-view.c: (e_week_view_do_cursor_key_up),
- (e_week_view_do_cursor_key_down), (e_week_view_do_cursor_key_left),
- (e_week_view_do_cursor_key_right), (e_month_view_do_cursor_key_up),
- (e_month_view_do_cursor_key_down),
- (e_month_view_do_cursor_key_left),
- (e_month_view_do_cursor_key_right):
- Emit the selected_time_changed signal after the selection day changed.
-
-2004-10-11 Not Zed <NotZed@Ximian.com>
-
- * gui/alarm-notify/alarm-queue.c (tray_icon_clicked_cb): convert
- to epopup.
- (add_popup_menu_item): removed, now redundant.
-
2004-10-08 Rodrigo Moya <rodrigo@novell.com>
Fixes #45951
@@ -1381,33 +98,6 @@
* gui/dialogs/comp-editor.c (setup_widgets): no need to create an extra
GtkVBox, just use the GtkDialog's one.
-2004-10-07 JP Rosevear <jpr@novell.com>
-
- * gui/dialogs/cal-prefs-dialog.c: remove useless include
-
- * gui/dialogs/url-editor-dialog.c: ditto
-
-2004-10-07 JP Rosevear <jpr@novell.com>
-
- * gui/print.c: guard config.h
-
- * gui/tasks-control.c: guard config.h, remove useless include
-
- * gui/migration.c: remove useless include
-
- * gui/main.c: remove useless include
-
- * gui/e-calendar-view.h: #define the type
-
- * gui/calendar-offline-handler.c: remove useless include
-
- * gui/calendar-config.c: tidy header
-
-2004-10-07 JP Rosevear <jpr@novell.com>
-
- * gui/calendar-commands.c: guard config.h include, kill warning
- and remove useless include
-
2004-10-06 Rodrigo Moya <rodrigo@novell.com>
Fixes #65932
@@ -1420,86 +110,10 @@
* gui/comp-editor-factory.c (cal_opened_cb): don't assert on error
cases, just display an error dialog.
-2004-10-06 Not Zed <NotZed@Ximian.com>
-
- * gui/gnome-cal.c (gnome_calendar_setup_view_popup): rename to
- view_popup_factory. Make it build an epopup item list directly.
- Can't re-use the galview cruft :-/
- (gnome_calendar_discard_view_popup): no longer needed.
- (gc_set_view, gc_save_custom_view, gc_define_views_response)
- (gc_define_views): implement the gal-view popup menu items.
+2004-10-06 JP Rosevear <jpr@novell.com>
- * gui/gnome-cal.h:
- * gui/e-week-view.h:
- * gui/e-day-view.h:
- * gui/e-cal-list-view.h: removed old e-popup-menu header.
-
- * gui/e-calendar-view.c (setup_popup_icons): removed.
- (e_calendar_view_create_popup_menu): converted to use e-popup.
- (on_paste, on_copy, on_cut, on_delete_occurrence)
- (on_unrecur_appointment, on_delete_appointment, on_publish)
- (on_forward, on_meeting, on_move_to, on_copy_to, on_print_event)
- (on_save_as, on_print, on_edit_appointment, on_goto_today)
- (on_goto_date, on_new_task, on_new_meeting, on_new_event)
- (on_new_appointment): convert to use e-popup stuff.
-
- * gui/tasks-component.c (popup_event_cb): e-popup api changes.
-
- * gui/e-cal-popup.c (e_cal_popup_target_new_select): implement the
- selection target.
- (ecalp_target_free): and free it.
-
- * gui/e-cal-model.h: Make the ECalModel struct non-anonymous so it
- can be forward-declared.
-
- * gui/calendar-component.c (popup_event_cb): e-popup api changes.
-
-2004-10-06 Rodrigo Moya <rodrigo@novell.com>
-
- Revert fix for #60551
-
- * gui/dialogs/task-page.c (task_page_fill_component): start date
- can be after the due date, no need to compare.
-
-2004-10-02 Iván Frade <frade@asturlinux.org>
-
- Fixes #48116
-
- * gui/dialogs/task-details.page.c (task_details_page_fill_component):
- Validation: completed date is not a future date.
-
-2004-10-01 Not Zed <NotZed@Ximian.com>
-
- * gui/tasks-component.c (create_component_view): cast warning
- away.
- (create_component_view): connect to popup_event rather than
- fill_popup_menu.
-
- * gui/calendar-component.c (create_component_view): cast a warning
- away.
-
- * calendar-errors.xml: add prompt-delete-task-list.
-
- * gui/tasks-component.c (fill_popup_menu_cb): renamed to
- popup_event_cb, make use e-cal-popup.
- (edit_task_list_cb, new_task_list_cb, delete_task_list_cb)
- (copy_task_list_cb): deja-vu. update for api.
- (add_popup_menu_item): killed. murdered. drawn and quatered.
- (delete_task_list_cb): use e-error for the delete prompt.
-
- * gui/calendar-component.c (create_component_view): hook onto
- popup event instead of fill_popup_menu.
-
- * calendar-errors.xml: added prompt-delete-calendar.
-
- * gui/calendar-component.c (fill_popup_menu_cb): rename to
- popup_event_cb, make use e-cal-popup.
- (edit_calendar_cb, new_calendar_cb, delete_calendar_cb)
- (copy_calendar_cb): fix for api changes.
- (add_popup_menu_item): removed.
- (delete_calendar_cb): use e-error for the delete thing.
-
- * gui/e-cal-popup.[ch]: calendar popup driver.
+ * gui/itip-utils.c (comp_server_send): pass the variable in
+ correctly
2004-09-29 Rodrigo Moya <rodrigo@novell.com>
@@ -1517,15 +131,15 @@
destroyed (priv == null).
2004-09-28 JP Rosevear <jpr@novell.com>
-
- Fixes #61766
-
- * gui/migration.c (create_calendar_contact_source): set a color
- for the contacts
- (create_calendar_sources): set a color for the personal source and
- make in primary and default if nothing else is either
- (create_task_sources): ditto for tasks personal source
+
+ Fixes #61766
+ * gui/migration.c (create_calendar_contact_source): set a color
+ for the contacts
+ (create_calendar_sources): set a color for the personal source and
+ make in primary and default if nothing else is either
+ (create_task_sources): ditto for tasks personal source
+
2004-09-24 Rodrigo Moya <rodrigo@novell.com>
Fixes #65599
@@ -1536,12 +150,6 @@
instead of auth_new_cal_from_uri().
2004-09-24 JP Rosevear <jpr@novell.com>
-
- Fixes #64955, Vincent Noel <vnoel@cox.net>
-
- * libecal/e-cal.c (e_cal_get_alarms_in_range): fix c99-ism
-
-2004-09-24 JP Rosevear <jpr@novell.com>
Fixes #66344
@@ -1585,14 +193,14 @@
* gui/e-cal-model-tasks.c (e_cal_model_tasks_mark_task_complete):
notify of change so completion status updates immediately
-
-2004-09-21 JP Rosevear <jpr@novell.com>
+2004-09-21 JP Rosevear <jpr@novell.com>
+
Fixes #59194
-
- * gui/e-cal-model-calendar.c (get_location): return "" instead of
- NULL
+ * gui/e-cal-model-calendar.c (get_location): return "" instead of
+ NULL
+
2004-09-21 Chenthill Palanisamy <pchenthill@novell.com>
Fixes #65682
@@ -1600,27 +208,20 @@
(itip_send_comp): check the static capability before
booking the deletion.
-2004-09-15 JP Rosevear <jpr@novell.com>
-
+2004-09-20 JP Rosevear <jpr@novell.com>
+
Fixes #55172
* conduits/calendar/calendar-conduit.c (local_record_from_comp):
handle -1 (last) for monthly recurrences and check both by_set_pos
and by_day since either can indicate this type of recurrence
-
+
2004-09-20 Tony Tsui <ttsui9@gmail.com>
Fixes #66174
* gui/dialogs/meeting-page.c (existing_attendee): fixed memory leak.
-2004-09-10 Hannah & Fazlu <hannah_lins@yahoo.co.in>
-
- Fixes bug #65051
-
- * calendar/gui/dialogs/task-page.c (task_page_fill_component):
- Compared the dates and time
-
2004-09-10 Rodrigo Moya <rodrigo@novell.com>
Fixes #62374
@@ -1636,6 +237,31 @@
only be called once per time range.
2004-09-09 JP Rosevear <jpr@novell.com>
+
+ Fixes #65454
+
+ * gui/e-itip-control.c (class_init): only use a destroy function,
+ no finalize
+ (cleanup_ecal): util function
+ (init): use above for hash table and killed destroyed flag
+ (weren't using it anywhere)
+ (destroy): collapse finalize work into here and guard against
+ multiple destroy calls
+
+2004-08-31 Rodrigo Moya <rodrigo@novell.com>
+
+ Fixes #62392
+
+ * gui/alarm-notify/alarm-queue.c (display_notification): ref the
+ client's query object so that it doesn't disappear on us.
+ (tray_icon_destroyed_cb): unref the query previously ref'ed.
+
+2004-08-31 Rodrigo Moya <rodrigo@novell.com>
+
+ * gui/e-cal-model-tasks.c: include missing string.h, to avoid
+ problems in 64 bit builds.
+
+2004-09-09 JP Rosevear <jpr@novell.com>
Fixes #65454
@@ -1646,7 +272,7 @@
(weren't using it anywhere)
(destroy): collapse finalize work into here and guard against
multiple destroy calls
-
+
2004-09-08 JP Rosevear <jpr@novell.com>
Fixes #62728
@@ -2363,7 +989,7 @@
Partially fixes #56171
-2004-07-11 Jürg Billeter <j@bitron.ch>
+2004-07-11 Jürg Billeter <j@bitron.ch>
* gui/dialogs/event-page.c (event_page_fill_component):
busy should be opaque, not transparent
diff --git a/calendar/gui/alarm-notify/alarm-notify-dialog.c b/calendar/gui/alarm-notify/alarm-notify-dialog.c
index 8d60fb7c70..a84e13f66b 100644
--- a/calendar/gui/alarm-notify/alarm-notify-dialog.c
+++ b/calendar/gui/alarm-notify/alarm-notify-dialog.c
@@ -23,7 +23,6 @@
#include <stdio.h>
#include <string.h>
#include <gtk/gtkdialog.h>
-#include <gtk/gtkimage.h>
#include <gtk/gtklabel.h>
#include <gtk/gtkspinbutton.h>
#include <gtk/gtksignal.h>
@@ -35,6 +34,8 @@
#endif
#include <glade/glade.h>
#include <e-util/e-time-utils.h>
+#include <gtkhtml/gtkhtml.h>
+#include <gtkhtml/gtkhtml-stream.h>
#include <libecal/e-cal-time-util.h>
#include "alarm-notify-dialog.h"
#include "config-data.h"
@@ -42,43 +43,237 @@
#include <e-util/e-icon-factory.h>
+GtkWidget *make_html_display (gchar *widget_name, char *s1, char *s2, int scroll, int shadow);
+
/* The useful contents of the alarm notify dialog */
typedef struct {
GladeXML *xml;
GtkWidget *dialog;
- GtkWidget *title;
+ GtkWidget *close;
+ GtkWidget *snooze;
+ GtkWidget *edit;
GtkWidget *snooze_time;
- GtkWidget *minutes_label;
- GtkWidget *description;
- GtkWidget *location;
- GtkWidget *start;
- GtkWidget *end;
+ GtkWidget *html;
AlarmNotifyFunc func;
gpointer func_data;
} AlarmNotify;
-enum {
- AN_RESPONSE_EDIT = 0,
- AN_RESPONSE_SNOOZE = 1
-};
-
+/* Callback used when the notify dialog is destroyed */
+static void
+dialog_destroy_cb (GtkObject *object, gpointer data)
+{
+ AlarmNotify *an;
+
+ an = data;
+ g_object_unref (an->xml);
+ g_free (an);
+}
+
+/* Delete_event handler for the alarm notify dialog */
+static gint
+delete_event_cb (GtkWidget *widget, GdkEvent *event, gpointer data)
+{
+ AlarmNotify *an;
+
+ an = data;
+ g_assert (an->func != NULL);
+
+ (* an->func) (ALARM_NOTIFY_CLOSE, -1, an->func_data);
+
+ gtk_widget_destroy (widget);
+ return TRUE;
+}
+
+/* Callback for the close button */
+static void
+close_clicked_cb (GtkWidget *widget, gpointer data)
+{
+ AlarmNotify *an;
+
+ an = data;
+ g_assert (an->func != NULL);
+
+ (* an->func) (ALARM_NOTIFY_CLOSE, -1, an->func_data);
+
+ gtk_widget_destroy (an->dialog);
+}
+
+/* Callback for the snooze button */
static void
-an_update_minutes_label (GtkSpinButton *sb, gpointer data)
+snooze_clicked_cb (GtkWidget *widget, gpointer data)
{
AlarmNotify *an;
- char *new_label;
- int snooze_timeout;
+ int snooze_time;
+
+ an = data;
+ g_assert (an->func != NULL);
- an = (AlarmNotify *) data;
+ snooze_time = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (an->snooze_time));
+ (* an->func) (ALARM_NOTIFY_SNOOZE, snooze_time, an->func_data);
- snooze_timeout = gtk_spin_button_get_value_as_int (sb);
- new_label = g_strdup (ngettext ("minute", "minutes", snooze_timeout));
- gtk_label_set_text (GTK_LABEL (an->minutes_label), new_label);
- g_free (new_label);
+ gtk_widget_destroy (an->dialog);
+}
+
+/* Callback for the edit button */
+static void
+edit_clicked_cb (GtkWidget *widget, gpointer data)
+{
+ AlarmNotify *an;
+
+ an = data;
+ g_assert (an->func != NULL);
+
+ (* an->func) (ALARM_NOTIFY_EDIT, -1, an->func_data);
+
+ gtk_widget_destroy (an->dialog);
+}
+
+static void
+url_requested_cb (GtkHTML *html, const char *url, GtkHTMLStream *stream, gpointer data)
+{
+
+ if (!strncmp ("file:///", url, strlen ("file:///"))) {
+ FILE *fp;
+ const char *filename = url + strlen ("file://");
+ char buf[4096];
+ size_t len;
+
+ fp = fopen (filename, "r");
+
+ if (fp == NULL) {
+ g_warning ("Error opening image: %s\n", url);
+ gtk_html_stream_close (stream, GTK_HTML_STREAM_ERROR);
+ return;
+ }
+
+ while ((len = fread (buf, 1, sizeof(buf), fp)) > 0)
+ gtk_html_stream_write (stream, buf, len);
+
+ if (feof (fp)) {
+ fclose (fp);
+ gtk_html_stream_close (stream, GTK_HTML_STREAM_OK);
+ return;
+ }
+
+ fclose (fp);
+ }
+
+ g_warning ("Error loading image");
+ gtk_html_stream_close (stream, GTK_HTML_STREAM_ERROR);
+ return;
+}
+
+GtkWidget *
+make_html_display (gchar *widget_name, char *s1, char *s2, int scroll, int shadow)
+{
+ GtkWidget *html, *scrolled_window;
+
+ gtk_widget_push_colormap (gdk_rgb_get_colormap ());
+
+ html = gtk_html_new();
+
+ gtk_html_set_default_content_type (GTK_HTML (html),
+ "charset=utf-8");
+ gtk_html_load_empty (GTK_HTML (html));
+
+ g_signal_connect (html, "url_requested",
+ G_CALLBACK (url_requested_cb),
+ NULL);
+
+ gtk_widget_pop_colormap();
+
+ scrolled_window = gtk_scrolled_window_new(NULL, NULL);
+
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+
+
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
+ GTK_SHADOW_IN);
+
+ gtk_widget_set_size_request (scrolled_window, 300, 200);
+
+ gtk_container_add(GTK_CONTAINER (scrolled_window), html);
+
+ gtk_widget_show_all(scrolled_window);
+
+ g_object_set_data (G_OBJECT (scrolled_window), "html", html);
+ return scrolled_window;
+}
+
+static void
+write_times (GtkHTMLStream *stream, char *start, char *end)
+{
+ if (start)
+ gtk_html_stream_printf (stream, "<b>%s</b> %s<br>", _("Starting:"), start);
+ if (end)
+ gtk_html_stream_printf (stream, "<b>%s</b> %s<br>", _("Ending:"), end);
+
+}
+
+/* Creates a heading for the alarm notification dialog */
+static void
+write_html_heading (GtkHTMLStream *stream, const char *message,
+ ECalComponentVType vtype, time_t occur_start, time_t occur_end)
+{
+ char *start, *end;
+ char *bg_path = "file://" EVOLUTION_IMAGESDIR "/bcg.png";
+ gchar *image_path;
+ gchar *icon_path;
+ icaltimezone *current_zone;
+
+ icon_path = e_icon_factory_get_icon_filename ("stock_alarm", E_ICON_SIZE_DIALOG);
+ image_path = g_strdup_printf ("file://%s", icon_path);
+ g_free (icon_path);
+
+ /* Stringize the times */
+
+ current_zone = config_data_get_timezone ();
+
+ start = timet_to_str_with_zone (occur_start, current_zone);
+ end = timet_to_str_with_zone (occur_end, current_zone);
+
+ /* Write the header */
+
+ gtk_html_stream_printf (stream,
+ "<HTML><BODY background=\"%s\">"
+ "<TABLE WIDTH=\"100%%\">"
+ "<TR>"
+ "<TD><IMG SRC=\"%s\" ALIGN=\"top\" BORDER=\"0\"></TD>"
+ "<TD><H1>%s</H1></TD>"
+ "</TR>"
+ "</TABLE>",
+ bg_path,
+ image_path,
+ _("Evolution Alarm"));
+
+ gtk_html_stream_printf (stream, "<br><br><font size=\"+2\">%s</font><br><br>", message);
+
+ /* Write the times */
+
+ switch (vtype) {
+ case E_CAL_COMPONENT_EVENT:
+ write_times (stream, start, end);
+ break;
+
+ case E_CAL_COMPONENT_TODO:
+ write_times (stream, start, end);
+ break;
+
+ default:
+ /* Only VEVENTs and VTODOs can have alarms */
+ g_assert_not_reached ();
+ break;
+ }
+
+ g_free (start);
+ g_free (end);
+ g_free (image_path);
}
/**
@@ -87,9 +282,7 @@ an_update_minutes_label (GtkSpinButton *sb, gpointer data)
* @occur_start: Start of occurrence time for the event.
* @occur_end: End of occurrence time for the event.
* @vtype: Type of the component which corresponds to the alarm.
- * @summary: Short summary of the appointment
- * @description: Long description of the appointment
- * @location: Location of the appointment
+ * @message; Message to display in the dialog; usually comes from the component.
* @func: Function to be called when a dialog action is invoked.
* @func_data: Closure data for @func.
*
@@ -98,30 +291,23 @@ an_update_minutes_label (GtkSpinButton *sb, gpointer data)
*
* Return value: a pointer to the dialog structure if successful or NULL if an error occurs.
**/
-void
+gpointer
alarm_notify_dialog (time_t trigger, time_t occur_start, time_t occur_end,
- ECalComponentVType vtype, const char *summary,
- const char *description, const char *location,
+ ECalComponentVType vtype, const char *message,
AlarmNotifyFunc func, gpointer func_data)
{
AlarmNotify *an;
- GtkWidget *image;
+ GtkHTMLStream *stream;
icaltimezone *current_zone;
- char *title;
- char *start, *end;
- char *icon_path;
+ char *buf, *title;
GList *icon_list;
- int snooze_timeout;
- g_return_if_fail (trigger != -1);
+ g_return_val_if_fail (trigger != -1, NULL);
/* Only VEVENTs or VTODOs can have alarms */
- g_return_if_fail (vtype == E_CAL_COMPONENT_EVENT
- || vtype == E_CAL_COMPONENT_TODO);
- g_return_if_fail (summary != NULL);
- g_return_if_fail (description != NULL);
- g_return_if_fail (location != NULL);
- g_return_if_fail (func != NULL);
+ g_return_val_if_fail (vtype == E_CAL_COMPONENT_EVENT || vtype == E_CAL_COMPONENT_TODO, NULL);
+ g_return_val_if_fail (message != NULL, NULL);
+ g_return_val_if_fail (func != NULL, NULL);
an = g_new0 (AlarmNotify, 1);
@@ -132,61 +318,66 @@ alarm_notify_dialog (time_t trigger, time_t occur_start, time_t occur_end,
if (!an->xml) {
g_message ("alarm_notify_dialog(): Could not load the Glade XML file!");
g_free (an);
- return;
+ return NULL;
}
an->dialog = glade_xml_get_widget (an->xml, "alarm-notify");
- an->title = glade_xml_get_widget (an->xml, "title-label");
+ an->close = glade_xml_get_widget (an->xml, "close");
+ an->snooze = glade_xml_get_widget (an->xml, "snooze");
+ an->edit = glade_xml_get_widget (an->xml, "edit");
an->snooze_time = glade_xml_get_widget (an->xml, "snooze-time");
- an->minutes_label = glade_xml_get_widget (an->xml, "minutes-label");
- an->description = glade_xml_get_widget (an->xml, "description-label");
- an->location = glade_xml_get_widget (an->xml, "location-label");
- an->start = glade_xml_get_widget (an->xml, "start-label");
- an->end = glade_xml_get_widget (an->xml, "end-label");
-
- if (!(an->dialog && an->title && an->snooze_time
- && an->description && an->location && an->start && an->end)) {
+ an->html = g_object_get_data (G_OBJECT (glade_xml_get_widget (an->xml, "frame")), "html");
+
+ if (!(an->dialog && an->close && an->snooze && an->edit
+ && an->snooze_time)) {
g_message ("alarm_notify_dialog(): Could not find all widgets in Glade file!");
g_object_unref (an->xml);
g_free (an);
- return;
+ return NULL;
}
gtk_widget_realize (an->dialog);
gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (an->dialog)->vbox), 0);
gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (an->dialog)->action_area), 12);
- image = glade_xml_get_widget (an->xml, "alarm-image");
- icon_path = e_icon_factory_get_icon_filename ("stock_alarm", E_ICON_SIZE_DIALOG);
- gtk_image_set_from_file (GTK_IMAGE (image), icon_path);
- g_free (icon_path);
+ g_signal_connect (G_OBJECT (an->dialog), "destroy",
+ G_CALLBACK (dialog_destroy_cb),
+ an);
/* Title */
- gtk_window_set_title (GTK_WINDOW (an->dialog), summary);
+ current_zone = config_data_get_timezone ();
- /* Set the widget contents */
+ buf = timet_to_str_with_zone (trigger, current_zone);
+ title = g_strdup_printf (_("Alarm on %s"), buf);
+ g_free (buf);
- title = g_strdup_printf ("<big><b>%s</b></big>", summary);
- gtk_label_set_markup (GTK_LABEL (an->title), title);
+ gtk_window_set_title (GTK_WINDOW (an->dialog), title);
g_free (title);
- gtk_label_set_text (GTK_LABEL (an->description), description);
- gtk_label_set_text (GTK_LABEL (an->location), location);
+ /* html heading */
+ stream = gtk_html_begin (GTK_HTML (an->html));
+ write_html_heading (stream, message, vtype, occur_start, occur_end);
+ gtk_html_stream_close (stream, GTK_HTML_STREAM_OK);
- /* Stringize the times */
+ /* Connect actions */
- current_zone = config_data_get_timezone ();
+ g_signal_connect (an->dialog, "delete_event",
+ G_CALLBACK (delete_event_cb),
+ an);
- start = timet_to_str_with_zone (occur_start, current_zone);
- gtk_label_set_text (GTK_LABEL (an->start), start);
+ g_signal_connect (an->close, "clicked",
+ G_CALLBACK (close_clicked_cb),
+ an);
- end = timet_to_str_with_zone (occur_end, current_zone);
- gtk_label_set_text (GTK_LABEL (an->end), end);
+ g_signal_connect (an->snooze, "clicked",
+ G_CALLBACK (snooze_clicked_cb),
+ an);
+
+ g_signal_connect (an->edit, "clicked",
+ G_CALLBACK (edit_clicked_cb),
+ an);
- /* Set callback for updating the snooze "minutes" label */
- g_signal_connect (G_OBJECT (an->snooze_time), "value_changed",
- G_CALLBACK (an_update_minutes_label), an);
/* Run! */
if (!GTK_WIDGET_REALIZED (an->dialog))
@@ -199,20 +390,15 @@ alarm_notify_dialog (time_t trigger, time_t occur_start, time_t occur_end,
g_list_free (icon_list);
}
- switch (gtk_dialog_run (GTK_DIALOG (an->dialog))) {
- case AN_RESPONSE_EDIT:
- (* an->func) (ALARM_NOTIFY_EDIT, -1, an->func_data);
- break;
- case AN_RESPONSE_SNOOZE:
- snooze_timeout = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (an->snooze_time));
- (* an->func) (ALARM_NOTIFY_SNOOZE, snooze_timeout, an->func_data);
- break;
- case GTK_RESPONSE_CLOSE:
- case GTK_RESPONSE_DELETE_EVENT:
- break;
- }
- gtk_widget_destroy (an->dialog);
-
- g_object_unref (an->xml);
- g_free (an);
+ gtk_widget_show (an->dialog);
+ return an;
+}
+
+void
+alarm_notify_dialog_disable_buttons (gpointer dialog)
+{
+ AlarmNotify *an = dialog;
+
+ gtk_widget_set_sensitive (an->snooze, FALSE);
+ gtk_widget_set_sensitive (an->edit, FALSE);
}
diff --git a/calendar/gui/alarm-notify/alarm-queue.c b/calendar/gui/alarm-notify/alarm-queue.c
index 9e1519d1a6..223fd6fa9f 100644
--- a/calendar/gui/alarm-notify/alarm-queue.c
+++ b/calendar/gui/alarm-notify/alarm-queue.c
@@ -51,7 +51,6 @@
#include "alarm-queue.h"
#include "config-data.h"
#include "util.h"
-#include "e-util/e-popup.h"
@@ -699,9 +698,7 @@ edit_component (ECal *client, ECalComponent *comp)
}
typedef struct {
- char *summary;
- char *description;
- char *location;
+ char *message;
gboolean blink_state;
gint blink_id;
time_t trigger;
@@ -732,6 +729,8 @@ on_dialog_objs_removed_cb (ECal *client, GList *objects, gpointer data)
continue;
if (!strcmp (uid, our_uid)) {
+ if (tray_data->alarm_dialog)
+ alarm_notify_dialog_disable_buttons (tray_data->alarm_dialog);
tray_data->cqa = NULL;
tray_data->alarm_id = NULL;
@@ -767,6 +766,7 @@ notify_dialog_cb (AlarmNotifyResult result, int snooze_mins, gpointer data)
g_assert_not_reached ();
}
+ tray_data->alarm_dialog = NULL;
gtk_widget_destroy (tray_data->tray_icon);
}
@@ -781,19 +781,9 @@ tray_icon_destroyed_cb (GtkWidget *tray, gpointer user_data)
if (tray_data->cqa != NULL)
remove_queued_alarm (tray_data->cqa, tray_data->alarm_id, TRUE, TRUE);
- if (tray_data->summary != NULL) {
- g_free (tray_data->summary);
- tray_data->summary = NULL;
- }
-
- if (tray_data->description != NULL) {
- g_free (tray_data->description);
- tray_data->description = NULL;
- }
-
- if (tray_data->location != NULL) {
- g_free (tray_data->location);
- tray_data->location = NULL;
+ if (tray_data->message != NULL) {
+ g_free (tray_data->message);
+ tray_data->message = NULL;
}
if (tray_data->blink_id)
@@ -810,37 +800,67 @@ tray_icon_destroyed_cb (GtkWidget *tray, gpointer user_data)
}
/* Callbacks. */
+static void
+add_popup_menu_item (GtkMenu *menu, const char *label, const char *pixmap,
+ GCallback callback, gpointer user_data)
+{
+ GtkWidget *item, *image;
+
+ if (pixmap) {
+ item = gtk_image_menu_item_new_with_label (label);
+
+ /* load the image */
+ if (g_file_test (pixmap, G_FILE_TEST_EXISTS))
+ image = gtk_image_new_from_file (pixmap);
+ else
+ image = gtk_image_new_from_stock (pixmap, GTK_ICON_SIZE_MENU);
+
+ if (image) {
+ gtk_widget_show (image);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
+ }
+ } else {
+ item = gtk_menu_item_new_with_label (label);
+ }
+
+ if (callback)
+ g_signal_connect (G_OBJECT (item), "activate", callback, user_data);
+
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+ gtk_widget_show (item);
+}
+
static gboolean
open_alarm_dialog (TrayIconData *tray_data)
{
QueuedAlarm *qa;
+ if (tray_data->alarm_dialog != NULL)
+ return FALSE;
+
qa = lookup_queued_alarm (tray_data->cqa, tray_data->alarm_id);
if (qa) {
gtk_widget_hide (tray_data->tray_icon);
- alarm_notify_dialog (tray_data->trigger,
- qa->instance->occur_start,
- qa->instance->occur_end,
- e_cal_component_get_vtype (tray_data->comp),
- tray_data->summary,
- tray_data->description,
- tray_data->location,
- notify_dialog_cb, tray_data);
+ tray_data->alarm_dialog = alarm_notify_dialog (
+ tray_data->trigger,
+ qa->instance->occur_start,
+ qa->instance->occur_end,
+ e_cal_component_get_vtype (tray_data->comp),
+ tray_data->message,
+ notify_dialog_cb, tray_data);
}
return TRUE;
}
static void
-popup_dismiss_cb (EPopup *ep, EPopupItem *pitem, void *data)
+popup_dismiss_cb (GtkWidget *widget, TrayIconData *tray_data)
{
- TrayIconData *tray_data = data;
-
gtk_widget_destroy (tray_data->tray_icon);
}
static void
-popup_dismiss_all_cb (EPopup *ep, EPopupItem *pitem, void *data)
+popup_dismiss_all_cb (GtkWidget *widget, TrayIconData *tray_data)
{
while (tray_icons_list != NULL) {
TrayIconData *tray_data = tray_icons_list->data;
@@ -852,25 +872,11 @@ popup_dismiss_all_cb (EPopup *ep, EPopupItem *pitem, void *data)
}
static void
-popup_open_cb (EPopup *ep, EPopupItem *pitem, void *data)
+popup_open_cb (GtkWidget *widget, TrayIconData *tray_data)
{
- TrayIconData *tray_data = data;
-
open_alarm_dialog (tray_data);
}
-static EPopupItem tray_items[] = {
- { E_POPUP_ITEM, "00.open", N_("Open"), popup_open_cb, NULL, GTK_STOCK_OPEN },
- { E_POPUP_ITEM, "10.dismiss", N_("Dismiss"), popup_dismiss_cb, NULL, NULL },
- { E_POPUP_ITEM, "20.dismissall", N_("Dismiss All"), popup_dismiss_all_cb, NULL, NULL },
-};
-
-static void
-tray_popup_free(EPopup *ep, GSList *items, void *data)
-{
- g_slist_free(items);
-}
-
static gint
tray_icon_clicked_cb (GtkWidget *widget, GdkEventButton *event, gpointer user_data)
{
@@ -880,17 +886,17 @@ tray_icon_clicked_cb (GtkWidget *widget, GdkEventButton *event, gpointer user_da
if (event->button == 1) {
return open_alarm_dialog (tray_data);
} else if (event->button == 3) {
- GtkMenu *menu;
- GSList *menus = NULL;
- EPopup *ep;
- int i;
-
- ep = e_popup_new("org.gnome.evolution.alarmNotify.popup");
- for (i=0;i<sizeof(tray_items)/sizeof(tray_items[0]);i++)
- menus = g_slist_prepend(menus, &tray_items[i]);
- e_popup_add_items(ep, menus, NULL, tray_popup_free, tray_data);
- menu = e_popup_create_menu_once(ep, NULL, 0);
- gtk_menu_popup(menu, NULL, NULL, NULL, NULL, event->button, event->time);
+ GtkWidget *menu;
+
+ /* display popup menu */
+ menu = gtk_menu_new ();
+ add_popup_menu_item (GTK_MENU (menu), _("Open"), GTK_STOCK_OPEN,
+ G_CALLBACK (popup_open_cb), tray_data);
+ add_popup_menu_item (GTK_MENU (menu), _("Dismiss"), NULL,
+ G_CALLBACK (popup_dismiss_cb), tray_data);
+ add_popup_menu_item (GTK_MENU (menu), _("Dismiss All"), NULL,
+ G_CALLBACK (popup_dismiss_all_cb), tray_data);
+ gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, event->button, event->time);
return TRUE;
}
@@ -924,14 +930,15 @@ display_notification (time_t trigger, CompQueuedAlarms *cqa,
{
QueuedAlarm *qa;
ECalComponent *comp;
- const char *summary, *description, *location;
+ const char *message;
+ ECalComponentAlarm *alarm;
GtkWidget *tray_icon, *image, *ebox;
GtkTooltips *tooltips;
TrayIconData *tray_data;
ECalComponentText text;
- GSList *text_list;
char *str, *start_str, *end_str, *alarm_str;
icaltimezone *current_zone;
+ GdkPixbuf *pixbuf;
comp = cqa->alarms->comp;
qa = lookup_queued_alarm (cqa, alarm_id);
@@ -939,37 +946,29 @@ display_notification (time_t trigger, CompQueuedAlarms *cqa,
return;
/* get a sensible description for the event */
- e_cal_component_get_summary (comp, &text);
-
- if (text.value)
- summary = text.value;
- else
- summary = _("No summary available.");
+ alarm = e_cal_component_get_alarm (comp, qa->instance->auid);
+ g_assert (alarm != NULL);
- e_cal_component_get_description_list (comp, &text_list);
+ e_cal_component_alarm_get_description (alarm, &text);
+ e_cal_component_alarm_free (alarm);
- if (text_list) {
- text = *((ECalComponentText *)text_list->data);
- if (text.value)
- description = text.value;
- else
- description = _("No description available.");
- } else {
- description = _("No description available.");
+ if (text.value)
+ message = text.value;
+ else {
+ e_cal_component_get_summary (comp, &text);
+ if (text.value)
+ message = text.value;
+ else
+ message = _("No description available.");
}
- e_cal_component_free_text_list (text_list);
-
- e_cal_component_get_location (comp, &location);
-
- if (!location)
- location = _("No location information available.");
-
/* create the tray icon */
tooltips = gtk_tooltips_new ();
- tray_icon = GTK_WIDGET (egg_tray_icon_new (qa->instance->auid));
- image = e_icon_factory_get_image ("stock_appointment-reminder", E_ICON_SIZE_LARGE_TOOLBAR);
+ tray_icon = egg_tray_icon_new (qa->instance->auid);
+ pixbuf = e_icon_factory_get_icon ("stock_appointment-reminder", E_ICON_SIZE_LARGE_TOOLBAR);
+ image = gtk_image_new_from_pixbuf (pixbuf);
+ gdk_pixbuf_unref (pixbuf);
ebox = gtk_event_box_new ();
gtk_widget_show (image);
@@ -980,7 +979,7 @@ display_notification (time_t trigger, CompQueuedAlarms *cqa,
start_str = timet_to_str_with_zone (qa->instance->occur_start, current_zone);
end_str = timet_to_str_with_zone (qa->instance->occur_end, current_zone);
str = g_strdup_printf (_("Alarm on %s\n%s\nStarting at %s\nEnding at %s"),
- alarm_str, summary, start_str, end_str);
+ alarm_str, message, start_str, end_str);
gtk_tooltips_set_tip (GTK_TOOLTIPS (tooltips), ebox, str, str);
g_free (start_str);
g_free (end_str);
@@ -995,9 +994,7 @@ display_notification (time_t trigger, CompQueuedAlarms *cqa,
/* create the private structure */
tray_data = g_new0 (TrayIconData, 1);
- tray_data->summary = g_strdup (summary);
- tray_data->description = g_strdup (description);
- tray_data->location = g_strdup (location);
+ tray_data->message = g_strdup (message);
tray_data->trigger = trigger;
tray_data->cqa = cqa;
tray_data->alarm_id = alarm_id;
diff --git a/calendar/gui/calendar-component.c b/calendar/gui/calendar-component.c
index 2f641bcd4b..41d5a0c8ab 100644
--- a/calendar/gui/calendar-component.c
+++ b/calendar/gui/calendar-component.c
@@ -31,9 +31,7 @@
#include <bonobo/bonobo-i18n.h>
#include <bonobo/bonobo-exception.h>
#include <libical/icalvcal.h>
-#include <libedataserver/e-url.h>
#include <libecal/e-cal-time-util.h>
-#include <libedataserverui/e-source-selector.h>
#include <shell/e-user-creatable-items-handler.h>
#include "e-pub-utils.h"
#include "e-calendar-view.h"
@@ -51,11 +49,9 @@
#include "dialogs/comp-editor.h"
#include "dialogs/copy-source-dialog.h"
#include "dialogs/event-editor.h"
+#include "widgets/misc/e-source-selector.h"
#include "widgets/misc/e-info-label.h"
-#include "widgets/misc/e-error.h"
#include "e-util/e-icon-factory.h"
-#include "e-cal-menu.h"
-#include "e-cal-popup.h"
/* IDs for user creatable items */
#define CREATE_EVENT_ID "event"
@@ -312,127 +308,133 @@ update_primary_task_selection (CalendarComponentView *component_view)
/* Callbacks. */
static void
-copy_calendar_cb (EPopup *ep, EPopupItem *pitem, void *data)
+add_popup_menu_item (GtkMenu *menu, const char *label, const char *icon_name,
+ GCallback callback, gpointer user_data, gboolean sensitive)
+{
+ GtkWidget *item, *image;
+ GdkPixbuf *pixbuf;
+
+ if (icon_name) {
+ item = gtk_image_menu_item_new_with_label (label);
+
+ /* load the image */
+ pixbuf = e_icon_factory_get_icon (icon_name, E_ICON_SIZE_MENU);
+ image = gtk_image_new_from_pixbuf (pixbuf);
+
+ if (image) {
+ gtk_widget_show (image);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
+ }
+ } else {
+ item = gtk_menu_item_new_with_label (label);
+ }
+
+ if (callback)
+ g_signal_connect (G_OBJECT (item), "activate", callback, user_data);
+
+ if (!sensitive)
+ gtk_widget_set_sensitive (item, FALSE);
+
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+ gtk_widget_show (item);
+}
+
+static void
+copy_calendar_cb (GtkWidget *widget, CalendarComponentView *component_view)
{
- CalendarComponentView *component_view = data;
ESource *selected_source;
selected_source = e_source_selector_peek_primary_selection (E_SOURCE_SELECTOR (component_view->source_selector));
if (!selected_source)
return;
- copy_source_dialog (GTK_WINDOW (gtk_widget_get_toplevel (ep->target->widget)), selected_source, E_CAL_SOURCE_TYPE_EVENT);
+ copy_source_dialog (GTK_WINDOW (gtk_widget_get_toplevel (widget)), selected_source, E_CAL_SOURCE_TYPE_EVENT);
}
static void
-delete_calendar_cb (EPopup *ep, EPopupItem *pitem, void *data)
+delete_calendar_cb (GtkWidget *widget, CalendarComponentView *component_view)
{
- CalendarComponentView *component_view = data;
ESource *selected_source;
- ECal *cal;
- char *uri;
+ GtkWidget *dialog;
selected_source = e_source_selector_peek_primary_selection (E_SOURCE_SELECTOR (component_view->source_selector));
if (!selected_source)
return;
- if (e_error_run((GtkWindow *)gtk_widget_get_toplevel(ep->target->widget),
- "calendar:prompt-delete-calendar", e_source_peek_name(selected_source)) != GTK_RESPONSE_YES)
- return;
-
- /* first, ask the backend to remove the calendar */
- uri = e_source_get_uri (selected_source);
- cal = e_cal_model_get_client_for_uri (gnome_calendar_get_calendar_model (component_view->calendar), uri);
- if (!cal)
- cal = e_cal_new_from_uri (uri, E_CAL_SOURCE_TYPE_EVENT);
- g_free (uri);
- if (cal) {
- if (e_cal_remove (cal, NULL)) {
- if (e_source_selector_source_is_selected (E_SOURCE_SELECTOR (component_view->source_selector),
- selected_source)) {
- gnome_calendar_remove_source (component_view->calendar, E_CAL_SOURCE_TYPE_EVENT, selected_source);
- e_source_selector_unselect_source (E_SOURCE_SELECTOR (component_view->source_selector),
- selected_source);
+ /* create the confirmation dialog */
+ dialog = gtk_message_dialog_new (
+ GTK_WINDOW (gtk_widget_get_toplevel (widget)),
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_YES_NO,
+ _("Calendar '%s' will be removed. Are you sure you want to continue?"),
+ e_source_peek_name (selected_source));
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_YES) {
+ ECal *cal;
+ char *uri;
+
+ /* first, ask the backend to remove the calendar */
+ uri = e_source_get_uri (selected_source);
+ cal = e_cal_model_get_client_for_uri (gnome_calendar_get_calendar_model (component_view->calendar), uri);
+ if (!cal)
+ cal = e_cal_new_from_uri (uri, E_CAL_SOURCE_TYPE_EVENT);
+ g_free (uri);
+ if (cal) {
+ if (e_cal_remove (cal, NULL)) {
+ if (e_source_selector_source_is_selected (E_SOURCE_SELECTOR (component_view->source_selector),
+ selected_source)) {
+ gnome_calendar_remove_source (component_view->calendar, E_CAL_SOURCE_TYPE_EVENT, selected_source);
+ e_source_selector_unselect_source (E_SOURCE_SELECTOR (component_view->source_selector),
+ selected_source);
+ }
+
+ e_source_group_remove_source (e_source_peek_group (selected_source), selected_source);
+ e_source_list_sync (component_view->source_list, NULL);
}
-
- e_source_group_remove_source (e_source_peek_group (selected_source), selected_source);
- e_source_list_sync (component_view->source_list, NULL);
}
}
+
+ gtk_widget_destroy (dialog);
}
static void
-new_calendar_cb (EPopup *ep, EPopupItem *pitem, void *data)
+new_calendar_cb (GtkWidget *widget, CalendarComponentView *component_view)
{
- calendar_setup_edit_calendar (GTK_WINDOW (gtk_widget_get_toplevel(ep->target->widget)), NULL, pitem->user_data);
+ calendar_setup_new_calendar (GTK_WINDOW (gtk_widget_get_toplevel (widget)));
}
static void
-edit_calendar_cb (EPopup *ep, EPopupItem *pitem, void *data)
+edit_calendar_cb (GtkWidget *widget, CalendarComponentView *component_view)
{
- CalendarComponentView *component_view = data;
ESource *selected_source;
selected_source = e_source_selector_peek_primary_selection (E_SOURCE_SELECTOR (component_view->source_selector));
if (!selected_source)
return;
- calendar_setup_edit_calendar (GTK_WINDOW (gtk_widget_get_toplevel(ep->target->widget)), selected_source, NULL);
+ calendar_setup_edit_calendar (GTK_WINDOW (gtk_widget_get_toplevel (widget)), selected_source);
}
-static EPopupItem ecc_source_popups[] = {
- { E_POPUP_ITEM, "10.new", N_("New Calendar"), new_calendar_cb, NULL, "stock_calendar", 0, 0 },
- { E_POPUP_ITEM, "15.copy", N_("Copy"), copy_calendar_cb, NULL, "stock_folder-copy", 0, E_CAL_POPUP_SOURCE_PRIMARY },
- { E_POPUP_ITEM, "20.delete", N_("Delete"), delete_calendar_cb, NULL, "stock_delete", 0, E_CAL_POPUP_SOURCE_USER|E_CAL_POPUP_SOURCE_PRIMARY },
- { E_POPUP_ITEM, "30.properties", N_("Properties..."), edit_calendar_cb, NULL, "stock_folder-properties", 0, E_CAL_POPUP_SOURCE_PRIMARY },
-};
-
static void
-ecc_source_popup_free(EPopup *ep, GSList *list, void *data)
+fill_popup_menu_cb (ESourceSelector *selector, GtkMenu *menu, CalendarComponentView *component_view)
{
- g_slist_free(list);
-}
-
-static gboolean
-popup_event_cb(ESourceSelector *selector, ESource *insource, GdkEventButton *event, CalendarComponentView *component_view)
-{
- ECalPopup *ep;
- ECalPopupTargetSource *t;
- GSList *menus = NULL;
- int i;
- GtkMenu *menu;
-
- /** @HookPoint-ECalPopup: Calendar Source Selector Context Menu
- * @Id: org.gnome.evolution.calendar.source.popup
- * @Class: org.gnome.evolution.calendar.popup:1.0
- * @Target: ECalPopupTargetSource
- *
- * The context menu on the source selector in the calendar window.
- */
- ep = e_cal_popup_new("org.gnome.evolution.calendar.source.popup");
- t = e_cal_popup_target_new_source(ep, selector);
- t->target.widget = (GtkWidget *)component_view->calendar;
-
- if (!insource) {
-
- ESourceGroup *group;
-
- group = e_source_selector_get_primary_source_group (selector);
- g_object_ref (group);
- ((EPopupItem) ecc_source_popups [0]).user_data = group;
- menus = g_slist_prepend (menus, &ecc_source_popups [0]);
- }
- else {
- for (i=1;i<sizeof(ecc_source_popups)/sizeof(ecc_source_popups[0]);i++)
- menus = g_slist_prepend(menus, &ecc_source_popups[i]);
- }
-
- e_popup_add_items((EPopup *)ep, menus, NULL, ecc_source_popup_free, component_view);
-
- menu = e_popup_create_menu_once((EPopup *)ep, (EPopupTarget *)t, 0);
- gtk_menu_popup(menu, NULL, NULL, NULL, NULL, event?event->button:0, event?event->time:gtk_get_current_event_time());
+ ESource *source;
+ gboolean sensitive, system;
+ const char *source_uri;
+
+ source = e_source_selector_peek_primary_selection (E_SOURCE_SELECTOR (component_view->source_selector));
+ sensitive = source ? TRUE : FALSE;
- return TRUE;
+ /* FIXME Gross hack, should have a property or something */
+ source_uri = e_source_peek_relative_uri (source);
+ system = source_uri && !strcmp ("system", source_uri);
+
+ add_popup_menu_item (menu, _("New Calendar"), "stock_calendar",
+ G_CALLBACK (new_calendar_cb), component_view, TRUE);
+ add_popup_menu_item (menu, _("Copy"), "stock_folder-copy",
+ G_CALLBACK (copy_calendar_cb), component_view, sensitive);
+ add_popup_menu_item (menu, _("Delete"), "stock_delete", G_CALLBACK (delete_calendar_cb), component_view, sensitive && !system);
+ add_popup_menu_item (menu, _("Properties..."), NULL, G_CALLBACK (edit_calendar_cb), component_view, sensitive);
}
static void
@@ -618,73 +620,9 @@ conf_changed_callback (GConfClient *client,
e_pub_publish (TRUE);
}
-/* Evolution::Component CORBA methods. */
-static void
-impl_handleURI (PortableServer_Servant servant, const char *uri, CORBA_Environment *ev)
-{
- CalendarComponent *calendar_component = CALENDAR_COMPONENT (bonobo_object_from_servant (servant));
- CalendarComponentPrivate *priv;
-
- priv = calendar_component->priv;
- if (!strncmp (uri, "calendar:", 9)) {
- EUri *euri = e_uri_new (uri);
- const char *p;
- char *header, *content;
- size_t len, clen;
- time_t start = -1, end = -1;
-
- p = euri->query;
- if (p) {
- while (*p) {
- len = strcspn (p, "=&");
-
- /* If it's malformed, give up. */
- if (p[len] != '=')
- break;
-
- header = (char *) p;
- header[len] = '\0';
- p += len + 1;
-
- clen = strcspn (p, "&");
-
- content = g_strndup (p, clen);
- if (!g_ascii_strcasecmp (header, "startdate")) {
- start = time_from_isodate (content);
- } else if (!g_ascii_strcasecmp (header, "enddate")) {
- end = time_from_isodate (content);
- }
-
- g_free (content);
-
- p += clen;
- if (*p == '&') {
- p++;
- if (!strcmp (p, "amp;"))
- p += 4;
- }
- }
-
- if (start != -1) {
- GList *l;
-
- if (end == -1)
- end = start;
-
- l = g_list_last (priv->views);
- if (l) {
- CalendarComponentView *view = l->data;
-
- gnome_calendar_set_selected_time_range (view->calendar, start, end);
- }
- }
- }
-
- e_uri_free (euri);
- }
-}
+/* Evolution::Component CORBA methods. */
static void
impl_upgradeFromVersion (PortableServer_Servant servant,
@@ -1055,7 +993,7 @@ create_new_event (CalendarComponent *calendar_component, CalendarComponentView *
ECalComponent *comp;
EventEditor *editor;
- editor = event_editor_new (ecal, is_meeting);
+ editor = event_editor_new (ecal);
comp = cal_comp_event_new_with_current_time (ecal, is_allday);
e_cal_component_commit_sequence (comp);
@@ -1107,7 +1045,6 @@ create_component_view (CalendarComponent *calendar_component)
GtkWidget *selector_scrolled_window, *vbox;
GtkWidget *statusbar_widget;
guint not;
- AtkObject *a11y;
priv = calendar_component->priv;
@@ -1120,9 +1057,7 @@ create_component_view (CalendarComponent *calendar_component)
/* Create sidebar selector */
component_view->source_selector = e_source_selector_new (calendar_component->priv->source_list);
- e_source_selector_set_select_new ((ESourceSelector *)component_view->source_selector, TRUE);
- a11y = gtk_widget_get_accessible (GTK_WIDGET (component_view->source_selector));
- atk_object_set_name (a11y, _("Calendar Source Selector"));
+ e_source_selector_set_select_new (component_view->source_selector, TRUE);
g_signal_connect (component_view->source_selector, "drag-motion", G_CALLBACK (selector_tree_drag_motion),
calendar_component);
@@ -1189,8 +1124,8 @@ create_component_view (CalendarComponent *calendar_component)
G_CALLBACK (source_selection_changed_cb), component_view);
g_signal_connect (component_view->source_selector, "primary_selection_changed",
G_CALLBACK (primary_source_selection_changed_cb), component_view);
- g_signal_connect (component_view->source_selector, "popup_event",
- G_CALLBACK (popup_event_cb), component_view);
+ g_signal_connect (component_view->source_selector, "fill_popup_menu",
+ G_CALLBACK (fill_popup_menu_cb), component_view);
/* Set up the "new" item handler */
component_view->creatable_items_handler = e_user_creatable_items_handler_new ("calendar", create_local_item_cb, calendar_component);
@@ -1443,7 +1378,6 @@ calendar_component_class_init (CalendarComponentClass *class)
epv->createControls = impl_createControls;
epv->_get_userCreatableItems = impl__get_userCreatableItems;
epv->requestCreateItem = impl_requestCreateItem;
- epv->handleURI = impl_handleURI;
object_class->dispose = impl_dispose;
object_class->finalize = impl_finalize;
diff --git a/calendar/gui/comp-editor-factory.c b/calendar/gui/comp-editor-factory.c
index 62d24f4467..71470ee648 100644
--- a/calendar/gui/comp-editor-factory.c
+++ b/calendar/gui/comp-editor-factory.c
@@ -26,7 +26,7 @@
#include <bonobo/bonobo-exception.h>
#include <bonobo/bonobo-i18n.h>
#include <evolution-calendar.h>
-#include <libedataserver/e-url.h>
+#include <e-util/e-url.h>
#include <libecal/e-cal.h>
#include "calendar-config.h"
#include "e-comp-editor-registry.h"
@@ -269,11 +269,11 @@ edit_existing (OpenClient *oc, const char *uid)
switch (vtype) {
case E_CAL_COMPONENT_EVENT:
- editor = COMP_EDITOR (event_editor_new (oc->client, e_cal_component_has_attendees (comp)));
+ editor = COMP_EDITOR (event_editor_new (oc->client));
break;
case E_CAL_COMPONENT_TODO:
- editor = COMP_EDITOR (task_editor_new (oc->client, e_cal_component_has_attendees (comp)));
+ editor = COMP_EDITOR (task_editor_new (oc->client));
break;
default:
@@ -311,19 +311,16 @@ edit_new (OpenClient *oc, const GNOME_Evolution_Calendar_CompEditorFactory_CompE
switch (type) {
case GNOME_Evolution_Calendar_CompEditorFactory_EDITOR_MODE_EVENT:
- editor = COMP_EDITOR (event_editor_new (oc->client, FALSE));
- comp = cal_comp_event_new_with_current_time (oc->client, FALSE);
- break;
case GNOME_Evolution_Calendar_CompEditorFactory_EDITOR_MODE_MEETING:
- editor = COMP_EDITOR (event_editor_new (oc->client, TRUE));
+ editor = COMP_EDITOR (event_editor_new (oc->client));
comp = cal_comp_event_new_with_current_time (oc->client, FALSE);
break;
case GNOME_Evolution_Calendar_CompEditorFactory_EDITOR_MODE_ALLDAY_EVENT:
- editor = COMP_EDITOR (event_editor_new (oc->client, FALSE));
+ editor = COMP_EDITOR (event_editor_new (oc->client));
comp = cal_comp_event_new_with_current_time (oc->client, TRUE);
break;
case GNOME_Evolution_Calendar_CompEditorFactory_EDITOR_MODE_TODO:
- editor = COMP_EDITOR (task_editor_new (oc->client, FALSE));
+ editor = COMP_EDITOR (task_editor_new (oc->client));
comp = get_default_task (oc->client);
break;
default:
@@ -478,7 +475,7 @@ open_client (CompEditorFactory *factory, ECalSourceType source_type, const char
g_hash_table_insert (priv->uri_client_hash, oc->uri, oc);
if (!e_cal_open (oc->client, FALSE, &error)) {
- g_warning (G_STRLOC ": %s", error->message);
+ g_warning (_("open_client(): %s"), error->message);
g_free (oc->uri);
g_object_unref (oc->client);
g_free (oc);
diff --git a/calendar/gui/dialogs/alarm-list-dialog.c b/calendar/gui/dialogs/alarm-list-dialog.c
index 88460e0935..31d98e6087 100644
--- a/calendar/gui/dialogs/alarm-list-dialog.c
+++ b/calendar/gui/dialogs/alarm-list-dialog.c
@@ -237,10 +237,6 @@ alarm_list_dialog_run (GtkWidget *parent, ECal *ecal, EAlarmList *list_store)
sensitize_buttons (&dialog);
- gtk_widget_ensure_style (dialog.toplevel);
- gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dialog.toplevel)->vbox), 0);
- gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dialog.toplevel)->action_area), 12);
-
icon_list = e_icon_factory_get_icon_list ("stock_calendar");
if (icon_list) {
gtk_window_set_icon_list (GTK_WINDOW (dialog.toplevel), icon_list);
diff --git a/calendar/gui/dialogs/comp-editor.c b/calendar/gui/dialogs/comp-editor.c
index 4ba8900b3a..49b0a43715 100644
--- a/calendar/gui/dialogs/comp-editor.c
+++ b/calendar/gui/dialogs/comp-editor.c
@@ -29,7 +29,6 @@
#include <glib.h>
#include <gdk/gdkkeysyms.h>
#include <gtk/gtkstock.h>
-#include <libgnome/libgnome.h>
#include <libgnome/gnome-i18n.h>
#include <libgnomeui/gnome-uidefs.h>
#include <libgnomeui/gnome-dialog.h>
@@ -38,16 +37,6 @@
#include <e-util/e-dialog-utils.h>
#include <e-util/e-icon-factory.h>
#include <evolution-shell-component-utils.h>
-
-#include <camel/camel-url.h>
-#include <camel/camel-exception.h>
-#include <camel/camel-folder.h>
-#include <camel/camel-stream-mem.h>
-#include <camel/camel-mime-message.h>
-
-#include "mail/mail-tools.h"
-#include "mail/em-popup.h"
-
#include "../print.h"
#include "../comp-util.h"
#include "save-comp.h"
@@ -58,13 +47,6 @@
#include "recur-comp.h"
#include "comp-editor.h"
-#include "cal-attachment-bar.h"
-#include "widgets/misc/e-expander.h"
-#include "widgets/misc/e-error.h"
-
-
-#define d(x) x
-
/* Private part of the CompEditor structure */
@@ -86,17 +68,6 @@ struct _CompEditorPrivate {
/* Notebook to hold the pages */
GtkNotebook *notebook;
-
- /* Attachment handling */
- GtkWidget *attachment_bar;
- GtkWidget *attachment_scrolled_window;
- GtkWidget *attachment_expander;
- GtkWidget *attachment_expander_label;
- GtkWidget *attachment_expander_icon;
- GtkWidget *attachment_expander_num;
-
- guint32 attachment_bar_visible : 1;
-
gboolean changed;
gboolean needs_send;
@@ -105,18 +76,16 @@ struct _CompEditorPrivate {
gboolean existing_org;
gboolean user_org;
- gboolean is_group_item;
gboolean warned;
-
- char *help_section;
};
+static void comp_editor_class_init (CompEditorClass *class);
+static void comp_editor_init (CompEditor *editor);
static gint comp_editor_key_press_event (GtkWidget *d, GdkEventKey *e);
static void comp_editor_finalize (GObject *object);
-static void comp_editor_show_help (CompEditor *editor);
static void real_set_e_cal (CompEditor *editor, ECal *client);
static void real_edit_comp (CompEditor *editor, ECalComponent *comp);
@@ -133,366 +102,12 @@ static void page_dates_changed_cb (GtkObject *obj, CompEditorPageDates *dates, g
static void obj_modified_cb (ECal *client, GList *objs, gpointer data);
static void obj_removed_cb (ECal *client, GList *uids, gpointer data);
-G_DEFINE_TYPE (CompEditor, comp_editor, GTK_TYPE_DIALOG);
-
-enum {
- DND_TYPE_MESSAGE_RFC822,
- DND_TYPE_X_UID_LIST,
- DND_TYPE_TEXT_URI_LIST,
- DND_TYPE_NETSCAPE_URL,
- DND_TYPE_TEXT_VCARD,
- DND_TYPE_TEXT_CALENDAR,
-};
-
-static GtkTargetEntry drop_types[] = {
- { "message/rfc822", 0, DND_TYPE_MESSAGE_RFC822 },
- { "x-uid-list", 0, DND_TYPE_X_UID_LIST },
- { "text/uri-list", 0, DND_TYPE_TEXT_URI_LIST },
- { "_NETSCAPE_URL", 0, DND_TYPE_NETSCAPE_URL },
- { "text/x-vcard", 0, DND_TYPE_TEXT_VCARD },
- { "text/calendar", 0, DND_TYPE_TEXT_CALENDAR },
-};
-
-#define num_drop_types (sizeof (drop_types) / sizeof (drop_types[0]))
-
-static struct {
- char *target;
- GdkAtom atom;
- guint32 actions;
-} drag_info[] = {
- { "message/rfc822", 0, GDK_ACTION_COPY },
- { "x-uid-list", 0, GDK_ACTION_ASK|GDK_ACTION_MOVE|GDK_ACTION_COPY },
- { "text/uri-list", 0, GDK_ACTION_COPY },
- { "_NETSCAPE_URL", 0, GDK_ACTION_COPY },
- { "text/x-vcard", 0, GDK_ACTION_COPY },
- { "text/calendar", 0, GDK_ACTION_COPY },
-};
-
-static void
-attach_message(CompEditor *editor, CamelMimeMessage *msg)
-{
- CamelMimePart *mime_part;
- const char *subject;
-
- mime_part = camel_mime_part_new();
- camel_mime_part_set_disposition(mime_part, "inline");
- subject = camel_mime_message_get_subject(msg);
- if (subject) {
- char *desc = g_strdup_printf(_("Attached message - %s"), subject);
-
- camel_mime_part_set_description(mime_part, desc);
- g_free(desc);
- } else
- camel_mime_part_set_description(mime_part, _("Attached message"));
-
- camel_medium_set_content_object((CamelMedium *)mime_part, (CamelDataWrapper *)msg);
- camel_mime_part_set_content_type(mime_part, "message/rfc822");
- cal_attachment_bar_attach_mime_part(CAL_ATTACHMENT_BAR(editor->priv->attachment_bar), mime_part);
- camel_object_unref(mime_part);
-}
-
-struct _drop_data {
- CompEditor *editor;
-
- GdkDragContext *context;
- /* Only selection->data and selection->length are valid */
- GtkSelectionData *selection;
-
- guint32 action;
- guint info;
- guint time;
-
- unsigned int move:1;
- unsigned int moved:1;
- unsigned int aborted:1;
-};
-
-static void
-drop_action(CompEditor *editor, GdkDragContext *context, guint32 action, GtkSelectionData *selection, guint info, guint time)
-{
- char *tmp, *str, **urls;
- CamelMimePart *mime_part;
- CamelStream *stream;
- CamelURL *url;
- CamelMimeMessage *msg;
- char *content_type;
- int i, success=FALSE, delete=FALSE;
-
- switch (info) {
- case DND_TYPE_MESSAGE_RFC822:
- d(printf ("dropping a message/rfc822\n"));
- /* write the message(s) out to a CamelStream so we can use it */
- stream = camel_stream_mem_new ();
- camel_stream_write (stream, selection->data, selection->length);
- camel_stream_reset (stream);
-
- msg = camel_mime_message_new ();
- if (camel_data_wrapper_construct_from_stream((CamelDataWrapper *)msg, stream) != -1) {
- attach_message(editor, msg);
- success = TRUE;
- delete = action == GDK_ACTION_MOVE;
- }
-
- camel_object_unref(msg);
- camel_object_unref(stream);
- break;
- case DND_TYPE_TEXT_URI_LIST:
- case DND_TYPE_NETSCAPE_URL:
- d(printf ("dropping a text/uri-list\n"));
- tmp = g_strndup (selection->data, selection->length);
- urls = g_strsplit (tmp, "\n", 0);
- g_free (tmp);
-
- for (i = 0; urls[i] != NULL; i++) {
- str = g_strstrip (urls[i]);
- if (urls[i][0] == '#') {
- g_free(str);
- continue;
- }
-
- if (!g_ascii_strncasecmp (str, "mailto:", 7)) {
- /* TODO does not handle mailto now */
- g_free (str);
- } else {
- url = camel_url_new (str, NULL);
- g_free (str);
-
- if (url == NULL)
- continue;
-
- if (!g_ascii_strcasecmp (url->protocol, "file"))
- cal_attachment_bar_attach
- (CAL_ATTACHMENT_BAR (editor->priv->attachment_bar),
- url->path);
-
- camel_url_free (url);
- }
- }
-
- g_free (urls);
- success = TRUE;
- break;
- case DND_TYPE_TEXT_VCARD:
- case DND_TYPE_TEXT_CALENDAR:
- content_type = gdk_atom_name (selection->type);
- d(printf ("dropping a %s\n", content_type));
-
- mime_part = camel_mime_part_new ();
- camel_mime_part_set_content (mime_part, selection->data, selection->length, content_type);
- camel_mime_part_set_disposition (mime_part, "inline");
-
- cal_attachment_bar_attach_mime_part
- (CAL_ATTACHMENT_BAR (editor->priv->attachment_bar),
- mime_part);
-
- camel_object_unref (mime_part);
- g_free (content_type);
-
- success = TRUE;
- break;
- case DND_TYPE_X_UID_LIST: {
- GPtrArray *uids;
- char *inptr, *inend;
- CamelFolder *folder;
- CamelException ex = CAMEL_EXCEPTION_INITIALISER;
-
- /* NB: This all runs synchronously, could be very slow/hang/block the ui */
-
- uids = g_ptr_array_new();
-
- inptr = selection->data;
- inend = selection->data + selection->length;
- while (inptr < inend) {
- char *start = inptr;
-
- while (inptr < inend && *inptr)
- inptr++;
-
- if (start > (char *)selection->data)
- g_ptr_array_add(uids, g_strndup(start, inptr-start));
-
- inptr++;
- }
-
- if (uids->len > 0) {
- folder = mail_tool_uri_to_folder(selection->data, 0, &ex);
- if (folder) {
- if (uids->len == 1) {
- msg = camel_folder_get_message(folder, uids->pdata[0], &ex);
- if (msg == NULL)
- goto fail;
- attach_message(editor, msg);
- } else {
- CamelMultipart *mp = camel_multipart_new();
- char *desc;
-
- camel_data_wrapper_set_mime_type((CamelDataWrapper *)mp, "multipart/digest");
- camel_multipart_set_boundary(mp, NULL);
- for (i=0;i<uids->len;i++) {
- msg = camel_folder_get_message(folder, uids->pdata[i], &ex);
- if (msg) {
- mime_part = camel_mime_part_new();
- camel_mime_part_set_disposition(mime_part, "inline");
- camel_medium_set_content_object((CamelMedium *)mime_part, (CamelDataWrapper *)msg);
- camel_mime_part_set_content_type(mime_part, "message/rfc822");
- camel_multipart_add_part(mp, mime_part);
- camel_object_unref(mime_part);
- camel_object_unref(msg);
- } else {
- camel_object_unref(mp);
- goto fail;
- }
- }
- mime_part = camel_mime_part_new();
- camel_medium_set_content_object((CamelMedium *)mime_part, (CamelDataWrapper *)mp);
- /* translators, this count will always be >1 */
- desc = g_strdup_printf(ngettext("Attached message", "%d attached messages", uids->len), uids->len);
- camel_mime_part_set_description(mime_part, desc);
- g_free(desc);
- cal_attachment_bar_attach_mime_part
- (CAL_ATTACHMENT_BAR(editor->priv->attachment_bar), mime_part);
- camel_object_unref(mime_part);
- camel_object_unref(mp);
- }
- success = TRUE;
- delete = action == GDK_ACTION_MOVE;
- fail:
- if (camel_exception_is_set(&ex)) {
- char *name;
-
- camel_object_get(folder, NULL, CAMEL_FOLDER_NAME, &name, NULL);
- e_error_run((GtkWindow *)editor, "mail-editor:attach-nomessages",
- name?name:(char *)selection->data, camel_exception_get_description(&ex), NULL);
- camel_object_free(folder, CAMEL_FOLDER_NAME, name);
- }
- camel_object_unref(folder);
- } else {
- e_error_run((GtkWindow *)editor, "mail-editor:attach-nomessages",
- selection->data, camel_exception_get_description(&ex), NULL);
- }
-
- camel_exception_clear(&ex);
- }
-
- g_ptr_array_free(uids, TRUE);
-
- break; }
- default:
- d(printf ("dropping an unknown\n"));
- break;
- }
-
- printf("Drag finished, success %d delete %d\n", success, delete);
-
- gtk_drag_finish(context, success, delete, time);
-}
-
-static void
-drop_popup_copy (EPopup *ep, EPopupItem *item, void *data)
-{
- struct _drop_data *m = data;
- drop_action(m->editor, m->context, GDK_ACTION_COPY, m->selection, m->info, m->time);
-}
-
-static void
-drop_popup_move (EPopup *ep, EPopupItem *item, void *data)
-{
- struct _drop_data *m = data;
- drop_action(m->editor, m->context, GDK_ACTION_MOVE, m->selection, m->info, m->time);
-}
-
-static void
-drop_popup_cancel(EPopup *ep, EPopupItem *item, void *data)
-{
- struct _drop_data *m = data;
- gtk_drag_finish(m->context, FALSE, FALSE, m->time);
-}
-
-static EPopupItem drop_popup_menu[] = {
- { E_POPUP_ITEM, "00.emc.02", N_("_Copy"), drop_popup_copy, NULL, "stock_mail-copy", 0 },
- { E_POPUP_ITEM, "00.emc.03", N_("_Move"), drop_popup_move, NULL, "stock_mail-move", 0 },
- { E_POPUP_BAR, "10.emc" },
- { E_POPUP_ITEM, "99.emc.00", N_("Cancel _Drag"), drop_popup_cancel, NULL, NULL, 0 },
-};
-
-static void
-drop_popup_free(EPopup *ep, GSList *items, void *data)
-{
- struct _drop_data *m = data;
-
- g_slist_free(items);
-
- g_object_unref(m->context);
- g_object_unref(m->editor);
- g_free(m->selection->data);
- g_free(m->selection);
- g_free(m);
-}
-
-static void
-drag_data_received (CompEditor *editor, GdkDragContext *context,
- int x, int y, GtkSelectionData *selection,
- guint info, guint time)
-{
- if (selection->data == NULL || selection->length == -1)
- return;
-
- if (context->action == GDK_ACTION_ASK) {
- EMPopup *emp;
- GSList *menus = NULL;
- GtkMenu *menu;
- int i;
- struct _drop_data *m;
-
- m = g_malloc0(sizeof(*m));
- m->context = context;
- g_object_ref(context);
- m->editor = editor;
- g_object_ref(editor);
- m->action = context->action;
- m->info = info;
- m->time = time;
- m->selection = g_malloc0(sizeof(*m->selection));
- m->selection->data = g_malloc(selection->length);
- memcpy(m->selection->data, selection->data, selection->length);
- m->selection->length = selection->length;
-
- emp = em_popup_new("org.gnome.evolution.mail.editor.popup.drop");
- for (i=0;i<sizeof(drop_popup_menu)/sizeof(drop_popup_menu[0]);i++)
- menus = g_slist_append(menus, &drop_popup_menu[i]);
-
- e_popup_add_items((EPopup *)emp, menus, NULL, drop_popup_free, m);
- menu = e_popup_create_menu_once((EPopup *)emp, NULL, 0);
- gtk_menu_popup(menu, NULL, NULL, NULL, NULL, 0, time);
- } else {
- drop_action(editor, context, context->action, selection, info, time);
- }
-}
+static GtkObjectClass *parent_class;
-static gboolean
-drag_motion(GObject *o, GdkDragContext *context, gint x, gint y, guint time, CompEditor *editor)
-{
- GList *targets;
- GdkDragAction action, actions = 0;
-
- for (targets = context->targets; targets; targets = targets->next) {
- int i;
-
- for (i=0;i<sizeof(drag_info)/sizeof(drag_info[0]);i++)
- if (targets->data == (void *)drag_info[i].atom)
- actions |= drag_info[i].actions;
- }
-
- actions &= context->actions;
- action = context->suggested_action;
- /* we default to copy */
- if (action == GDK_ACTION_ASK && (actions & (GDK_ACTION_MOVE|GDK_ACTION_COPY)) != (GDK_ACTION_MOVE|GDK_ACTION_COPY))
- action = GDK_ACTION_COPY;
+
- gdk_drag_status(context, action, time);
-
- return action != 0;
-}
+E_MAKE_TYPE (comp_editor, "CompEditor", CompEditor, comp_editor_class_init, comp_editor_init,
+ GTK_TYPE_DIALOG);
/* Class initialization function for the calendar component editor */
static void
@@ -500,13 +115,8 @@ comp_editor_class_init (CompEditorClass *klass)
{
GObjectClass *object_class;
GtkWidgetClass *widget_class;
- GObjectClass *gobject_class;
- int i;
-
- for (i=0;i<sizeof(drag_info)/sizeof(drag_info[0]);i++)
- drag_info[i].atom = gdk_atom_intern(drag_info[i].target, FALSE);
- gobject_class = G_OBJECT_CLASS(klass);
+ parent_class = g_type_class_peek_parent (klass);
object_class = G_OBJECT_CLASS (klass);
widget_class = GTK_WIDGET_CLASS (klass);
@@ -639,11 +249,6 @@ save_comp (CompEditor *editor)
/* send timezones */
g_hash_table_foreach (timezones, (GHFunc) send_timezone, editor);
g_hash_table_destroy (timezones);
-
- /* Attachments*/
-
- e_cal_component_set_attachment_list (priv->comp,
- cal_attachment_bar_get_attachment_list ((CalAttachmentBar *) priv->attachment_bar));
/* send the component to the server */
if (!cal_comp_is_on_server (priv->comp, priv->client)) {
@@ -730,7 +335,7 @@ prompt_to_save_changes (CompEditor *editor, gboolean send)
if (e_cal_component_is_instance (priv->comp))
if (!recur_component_dialog (priv->client, priv->comp, &priv->mod, GTK_WINDOW (editor)))
return FALSE;
-
+
if (send && save_comp_with_send (editor))
return TRUE;
else if (!send && save_comp (editor))
@@ -750,10 +355,9 @@ response_cb (GtkWidget *widget, int response, gpointer data)
{
CompEditor *editor = COMP_EDITOR (data);
CompEditorPrivate *priv;
- ECalComponentText text;
priv = editor->priv;
-
+
switch (response) {
case GTK_RESPONSE_OK:
commit_all_fields (editor);
@@ -761,206 +365,40 @@ response_cb (GtkWidget *widget, int response, gpointer data)
if (e_cal_component_is_instance (priv->comp))
if (!recur_component_dialog (priv->client, priv->comp, &priv->mod, GTK_WINDOW (editor)))
return;
-
- if (save_comp_with_send (editor)) {
-
- e_cal_component_get_summary (priv->comp, &text);
- if (!text.value) {
- if (!send_component_prompt_subject ((GtkWindow *) editor, priv->client, priv->comp))
- return;
- }
+ if (save_comp_with_send (editor))
close_dialog (editor);
- }
-
- break;
- case GTK_RESPONSE_HELP:
- comp_editor_show_help (editor);
-
break;
case GTK_RESPONSE_CANCEL:
+ case GTK_RESPONSE_DELETE_EVENT:
commit_all_fields (editor);
if (prompt_to_save_changes (editor, TRUE))
close_dialog (editor);
break;
- default:
- /* We handle delete event below */
- break;
}
}
-static int
-delete_event_cb (GtkWidget *widget, GdkEvent *event, gpointer data)
-{
- CompEditor *editor = COMP_EDITOR (data);
- CompEditorPrivate *priv;
- ECalComponentText text;
-
- priv = editor->priv;
-
- commit_all_fields (editor);
-
- if (prompt_to_save_changes (editor, TRUE))
- close_dialog (editor);
-
- return TRUE;
-}
-
-static void
-attachment_bar_changed_cb (CalAttachmentBar *bar,
- void *data)
-{
- CompEditor *editor = COMP_EDITOR (data);
-
- guint attachment_num = cal_attachment_bar_get_num_attachments (
- CAL_ATTACHMENT_BAR (editor->priv->attachment_bar));
- if (attachment_num) {
- gchar *num_text = g_strdup_printf (
- ngettext ("<b>%d</b> File Attached", "<b>%d</b> Files Attached", attachment_num),
- attachment_num);
- gtk_label_set_markup (GTK_LABEL (editor->priv->attachment_expander_num),
- num_text);
- g_free (num_text);
-
- gtk_widget_show (editor->priv->attachment_expander_icon);
-
- } else {
- gtk_label_set_text (GTK_LABEL (editor->priv->attachment_expander_num), "");
- gtk_widget_hide (editor->priv->attachment_expander_icon);
- }
-
-
- /* Mark the editor as changed so it prompts about unsaved
- changes on close */
- comp_editor_set_changed (editor, TRUE);
-
-}
-
-static void
-attachment_bar_icon_clicked_cb (CalAttachmentBar *bar, void *data)
-{
- GnomeIconList *icon_list;
- GList *p;
- int num;
- char *attach_file_url;
- GError *error = NULL;
-
- icon_list = GNOME_ICON_LIST (bar);
- p = gnome_icon_list_get_selection (icon_list);
- if (p) {
- num = GPOINTER_TO_INT (p->data);
- attach_file_url = cal_attachment_bar_get_nth_attachment_filename (bar, num);
- /* launch the url now */
- /* TODO should send GError and handle error conditions
- * here */
- gnome_url_show (attach_file_url, &error);
- if (error)
- g_message ("DEBUG: Launch failed :(\n");
- g_free (attach_file_url); }
-}
-
-static void
-attachment_expander_activate_cb (EExpander *expander,
- void *data)
-{
- CompEditor *editor = COMP_EDITOR (data);
- gboolean show = e_expander_get_expanded (expander);
-
- /* Update the expander label */
- if (show)
- gtk_label_set_text_with_mnemonic (GTK_LABEL (editor->priv->attachment_expander_label),
- _("Hide _Attachment Bar (drop attachments here)"));
- else
- gtk_label_set_text_with_mnemonic (GTK_LABEL (editor->priv->attachment_expander_label),
- _("Show _Attachment Bar (drop attachments here)"));
-
-}
-
/* Creates the basic in the editor */
static void
setup_widgets (CompEditor *editor)
{
CompEditorPrivate *priv;
- GtkWidget *expander_hbox, *vbox;
- GdkPixbuf *attachment_pixbuf;
priv = editor->priv;
- /* Useful vbox */
- vbox = gtk_vbox_new (FALSE, 12);
- gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
- gtk_box_pack_start (GTK_BOX (GTK_DIALOG (editor)->vbox), vbox, TRUE, TRUE, 0);
- gtk_widget_show (vbox);
-
/* Notebook */
priv->notebook = GTK_NOTEBOOK (gtk_notebook_new ());
gtk_widget_show (GTK_WIDGET (priv->notebook));
- gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET (priv->notebook),
- TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (GTK_DIALOG (editor)->vbox), GTK_WIDGET (priv->notebook),
+ TRUE, TRUE, 6);
/* Buttons */
gtk_dialog_add_button (GTK_DIALOG (editor), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
gtk_dialog_add_button (GTK_DIALOG (editor), GTK_STOCK_OK, GTK_RESPONSE_OK);
- gtk_dialog_add_button (GTK_DIALOG (editor), GTK_STOCK_HELP, GTK_RESPONSE_HELP);
gtk_dialog_set_response_sensitive (GTK_DIALOG (editor), GTK_RESPONSE_OK, FALSE);
g_signal_connect (editor, "response", G_CALLBACK (response_cb), editor);
- g_signal_connect (editor, "delete_event", G_CALLBACK (delete_event_cb), editor);
-
- /*Attachments */
- priv->attachment_scrolled_window = gtk_scrolled_window_new (NULL, NULL);
- gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->attachment_scrolled_window),
- GTK_SHADOW_IN);
- gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->attachment_scrolled_window),
- GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
-
- priv->attachment_bar = cal_attachment_bar_new (NULL);
- GTK_WIDGET_SET_FLAGS (priv->attachment_bar, GTK_CAN_FOCUS);
- gtk_container_add (GTK_CONTAINER (priv->attachment_scrolled_window),
- priv->attachment_bar);
- gtk_widget_show (priv->attachment_bar);
- g_signal_connect (priv->attachment_bar, "changed",
- G_CALLBACK (attachment_bar_changed_cb), editor);
- g_signal_connect (GNOME_ICON_LIST (priv->attachment_bar), "button-release-event",
- G_CALLBACK (attachment_bar_icon_clicked_cb), NULL);
- priv->attachment_expander_label =
- gtk_label_new_with_mnemonic (_("Show _Attachment Bar (drop attachments here)"));
- priv->attachment_expander_num = gtk_label_new ("");
- gtk_label_set_use_markup (GTK_LABEL (priv->attachment_expander_num), TRUE);
- gtk_misc_set_alignment (GTK_MISC (priv->attachment_expander_label), 0.0, 0.5);
- gtk_misc_set_alignment (GTK_MISC (priv->attachment_expander_num), 1.0, 0.5);
- expander_hbox = gtk_hbox_new (FALSE, 0);
-
- attachment_pixbuf = e_icon_factory_get_icon ("stock_attach", E_ICON_SIZE_MENU);
- priv->attachment_expander_icon = gtk_image_new_from_pixbuf (attachment_pixbuf);
- gtk_misc_set_alignment (GTK_MISC (priv->attachment_expander_icon), 1, 0.5);
- gtk_widget_set_size_request (priv->attachment_expander_icon, 100, -1);
- g_object_unref (attachment_pixbuf);
-
- gtk_box_pack_start (GTK_BOX (expander_hbox), priv->attachment_expander_label,
- TRUE, TRUE, 0);
- gtk_box_pack_start (GTK_BOX (expander_hbox), priv->attachment_expander_icon,
- TRUE, TRUE, 0);
- gtk_box_pack_start (GTK_BOX (expander_hbox), priv->attachment_expander_num,
- TRUE, TRUE, 0);
- gtk_widget_show_all (expander_hbox);
- gtk_widget_hide (priv->attachment_expander_icon);
-
- priv->attachment_expander = e_expander_new ("");
- e_expander_set_label_widget (E_EXPANDER (priv->attachment_expander), expander_hbox);
- atk_object_set_name (gtk_widget_get_accessible (priv->attachment_expander), _("Attachment Button: Press space key to toggle attachment bar"));
-
- gtk_container_add (GTK_CONTAINER (priv->attachment_expander),
- priv->attachment_scrolled_window);
- gtk_box_pack_start (GTK_BOX (vbox), priv->attachment_expander,
- FALSE, FALSE, GNOME_PAD_SMALL);
- gtk_widget_show (priv->attachment_expander);
- e_expander_set_expanded (E_EXPANDER (priv->attachment_expander), FALSE);
- g_signal_connect_after (priv->attachment_expander, "activate",
- G_CALLBACK (attachment_expander_activate_cb), editor);
-
-
}
/* Object initialization function for the calendar component editor */
@@ -981,20 +419,8 @@ comp_editor_init (CompEditor *editor)
priv->existing_org = FALSE;
priv->user_org = FALSE;
priv->warned = FALSE;
- priv->is_group_item = FALSE;
- priv->help_section = g_strdup ("usage-calendar");
-
- /* DND support */
- gtk_drag_dest_set (GTK_WIDGET (editor), GTK_DEST_DEFAULT_ALL, drop_types, num_drop_types, GDK_ACTION_COPY|GDK_ACTION_ASK|GDK_ACTION_MOVE);
- g_signal_connect(editor, "drag_data_received", G_CALLBACK (drag_data_received), NULL);
- g_signal_connect(editor, "drag-motion", G_CALLBACK(drag_motion), editor);
gtk_window_set_type_hint (GTK_WINDOW (editor), GDK_WINDOW_TYPE_HINT_NORMAL);
- gtk_dialog_set_has_separator (GTK_DIALOG (editor), FALSE);
-
- gtk_widget_ensure_style (GTK_WIDGET (editor));
- gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (editor)->vbox), 0);
- gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (editor)->action_area), 12);
}
@@ -1009,8 +435,8 @@ comp_editor_key_press_event (GtkWidget *d, GdkEventKey *e)
}
#endif
- if (GTK_WIDGET_CLASS (comp_editor_parent_class)->key_press_event)
- return (* GTK_WIDGET_CLASS (comp_editor_parent_class)->key_press_event) (d, e);
+ if (GTK_WIDGET_CLASS (parent_class)->key_press_event)
+ return (* GTK_WIDGET_CLASS (parent_class)->key_press_event) (d, e);
return FALSE;
}
@@ -1026,8 +452,6 @@ comp_editor_finalize (GObject *object)
editor = COMP_EDITOR (object);
priv = editor->priv;
- g_free (priv->help_section);
-
if (priv->client) {
g_object_unref (priv->client);
priv->client = NULL;
@@ -1062,25 +486,8 @@ comp_editor_finalize (GObject *object)
g_free (priv);
editor->priv = NULL;
- if (G_OBJECT_CLASS (comp_editor_parent_class)->finalize)
- (* G_OBJECT_CLASS (comp_editor_parent_class)->finalize) (object);
-}
-
-static void
-comp_editor_show_help (CompEditor *editor)
-{
- GError *error = NULL;
- CompEditorPrivate *priv;
-
- priv = editor->priv;
-
- gnome_help_display_desktop (NULL,
- "evolution-" BASE_VERSION,
- "evolution-" BASE_VERSION ".xml",
- priv->help_section,
- &error);
- if (error != NULL)
- g_warning ("%s", error->message);
+ if (G_OBJECT_CLASS (parent_class)->finalize)
+ (* G_OBJECT_CLASS (parent_class)->finalize) (object);
}
@@ -1169,31 +576,6 @@ comp_editor_get_user_org (CompEditor *editor)
return priv->user_org;
}
-void
-comp_editor_set_group_item (CompEditor *editor, gboolean group_item)
-{
- CompEditorPrivate *priv;
-
- g_return_if_fail (editor != NULL);
- g_return_if_fail (IS_COMP_EDITOR (editor));
-
- priv = editor->priv;
-
- priv->is_group_item = group_item;
-}
-
-gboolean
-comp_editor_get_is_group_item (CompEditor *editor)
-{
- CompEditorPrivate *priv;
-
- g_return_val_if_fail (editor != NULL, FALSE);
- g_return_val_if_fail (IS_COMP_EDITOR (editor), FALSE);
-
- priv = editor->priv;
-
- return priv->is_group_item;
-}
/**
* comp_editor_set_changed:
@@ -1475,20 +857,9 @@ comp_editor_get_e_cal (CompEditor *editor)
return priv->client;
}
-void
-comp_editor_set_help_section (CompEditor *editor, const char *section)
-{
- CompEditorPrivate *priv;
-
- priv = editor->priv;
-
- g_free (priv->help_section);
- priv->help_section = g_strdup (section);
-}
-
/* Creates an appropriate title for the event editor dialog */
static char *
-make_title_from_comp (ECalComponent *comp, gboolean is_group_item)
+make_title_from_comp (ECalComponent *comp)
{
char *title;
const char *type_string;
@@ -1501,16 +872,10 @@ make_title_from_comp (ECalComponent *comp, gboolean is_group_item)
type = e_cal_component_get_vtype (comp);
switch (type) {
case E_CAL_COMPONENT_EVENT:
- if (is_group_item)
- type_string = _("Meeting - %s");
- else
- type_string = _("Appointment - %s");
+ type_string = _("Appointment - %s");
break;
case E_CAL_COMPONENT_TODO:
- if (is_group_item)
- type_string = _("Assigned Task - %s");
- else
- type_string = _("Task - %s");
+ type_string = _("Task - %s");
break;
case E_CAL_COMPONENT_JOURNAL:
type_string = _("Journal entry - %s");
@@ -1532,7 +897,7 @@ make_title_from_comp (ECalComponent *comp, gboolean is_group_item)
/* Creates an appropriate title for the event editor dialog */
static char *
-make_title_from_string (ECalComponent *comp, const char *str, gboolean is_group_item)
+make_title_from_string (ECalComponent *comp, const char *str)
{
char *title;
const char *type_string;
@@ -1544,16 +909,10 @@ make_title_from_string (ECalComponent *comp, const char *str, gboolean is_group_
type = e_cal_component_get_vtype (comp);
switch (type) {
case E_CAL_COMPONENT_EVENT:
- if (is_group_item)
- type_string = _("Meeting - %s");
- else
- type_string = _("Appointment - %s");
+ type_string = _("Appointment - %s");
break;
case E_CAL_COMPONENT_TODO:
- if (is_group_item)
- type_string = _("Assigned Task - %s");
- else
- type_string = _("Task - %s");
+ type_string = _("Task - %s");
break;
case E_CAL_COMPONENT_JOURNAL:
type_string = _("Journal entry - %s");
@@ -1601,7 +960,7 @@ set_title_from_comp (CompEditor *editor)
char *title;
priv = editor->priv;
- title = make_title_from_comp (priv->comp, priv->is_group_item);
+ title = make_title_from_comp (priv->comp);
gtk_window_set_title (GTK_WINDOW (editor), title);
g_free (title);
}
@@ -1613,7 +972,7 @@ set_title_from_string (CompEditor *editor, const char *str)
char *title;
priv = editor->priv;
- title = make_title_from_string (priv->comp, str, priv->is_group_item);
+ title = make_title_from_string (priv->comp, str);
gtk_window_set_title (GTK_WINDOW (editor), title);
g_free (title);
}
@@ -1644,15 +1003,6 @@ fill_widgets (CompEditor *editor)
priv = editor->priv;
- /*Check if attachments are available here and set them*/
- if (e_cal_component_has_attachments (priv->comp)) {
- GSList *attachment_list = NULL;
- e_cal_component_get_attachment_list (priv->comp, &attachment_list);
- cal_attachment_bar_set_attachment_list
- ((CalAttachmentBar *)priv->attachment_bar, attachment_list);
- e_expander_set_expanded (E_EXPANDER (priv->attachment_expander), TRUE);
- }
-
for (l = priv->pages; l != NULL; l = l->next)
comp_editor_page_fill_widgets (l->data, priv->comp);
}
@@ -1694,7 +1044,6 @@ static void
real_edit_comp (CompEditor *editor, ECalComponent *comp)
{
CompEditorPrivate *priv;
- const char *uid;
g_return_if_fail (editor != NULL);
g_return_if_fail (IS_COMP_EDITOR (editor));
@@ -1715,11 +1064,6 @@ real_edit_comp (CompEditor *editor, ECalComponent *comp)
set_title_from_comp (editor);
set_icon_from_comp (editor);
- e_cal_component_get_uid (comp, &uid);
- cal_attachment_bar_set_local_attachment_store ((CalAttachmentBar *) priv->attachment_bar,
- e_cal_get_local_attachment_store (priv->client));
- cal_attachment_bar_set_comp_uid (priv->attachment_bar, g_strdup (uid));
-
fill_widgets (editor);
listen_for_changes (editor);
@@ -1737,56 +1081,21 @@ real_send_comp (CompEditor *editor, ECalComponentItipMethod method)
priv = editor->priv;
- if (!e_cal_component_has_attachments (priv->comp)) {
- if (itip_send_comp (method, priv->comp, priv->client,
- NULL, NULL)) {
- tmp_comp = priv->comp;
- g_object_ref (tmp_comp);
- comp_editor_edit_comp (editor, tmp_comp);
- g_object_unref (tmp_comp);
-
- comp_editor_set_changed (editor, TRUE);
- save_comp (editor);
-
- return TRUE;
- }
-
- } else {
- /* Clone the component with attachments set to CID:... */
- ECalComponent *send_comp;
- int num_attachments, i;
- GSList *attach_list = NULL;
- GSList *mime_attach_list;
-
- send_comp = e_cal_component_clone (priv->comp);
- num_attachments = e_cal_component_get_num_attachments (send_comp);
+ if (itip_send_comp (method, priv->comp, priv->client, NULL)) {
+ tmp_comp = priv->comp;
+ g_object_ref (tmp_comp);
+ comp_editor_edit_comp (editor, tmp_comp);
+ g_object_unref (tmp_comp);
+
+ comp_editor_set_changed (editor, TRUE);
+ save_comp (editor);
- for (i = 0; i < num_attachments ; i++) {
- attach_list = g_slist_append (attach_list, g_strdup ("CID:..."));
- }
- e_cal_component_set_attachment_list (send_comp, attach_list);
-
- /* mime_attach_list is freed by itip_send_comp */
- mime_attach_list = comp_editor_get_mime_attach_list (editor);
- if (itip_send_comp (method, send_comp, priv->client,
- NULL, mime_attach_list)) {
- tmp_comp = priv->comp;
- g_object_ref (tmp_comp);
- comp_editor_edit_comp (editor, tmp_comp);
- g_object_unref (tmp_comp);
-
- comp_editor_set_changed (editor, TRUE);
- save_comp (editor);
- g_object_unref (send_comp);
- return TRUE;
- }
- g_object_unref (send_comp);
+ return TRUE;
}
comp_editor_set_changed (editor, TRUE);
-
- return FALSE;
+ return FALSE;
}
@@ -1911,22 +1220,6 @@ comp_editor_close (CompEditor *editor)
return close;
}
-
-/* Utility function to get the mime-attachment list from the attachment
- * bar for sending the comp via itip. The list and its contents must
- * be freed by the caller.
- */
-GSList *
-comp_editor_get_mime_attach_list (CompEditor *editor)
-{
- GSList *mime_attach_list;
-
- mime_attach_list = cal_attachment_bar_get_mime_attach_list
- ((CalAttachmentBar *)editor->priv->attachment_bar);
-
- return mime_attach_list;
-}
-
/* Brings attention to a window by raising it and giving it focus */
static void
raise_and_focus (GtkWidget *widget)
@@ -2099,4 +1392,3 @@ obj_removed_cb (ECal *client, GList *uids, gpointer data)
if (changed_component_dialog ((GtkWindow *) editor, priv->comp, TRUE, priv->changed))
close_dialog (editor);
}
-
diff --git a/calendar/gui/dialogs/event-page.c b/calendar/gui/dialogs/event-page.c
index f659ad71fe..6ae83fa6f0 100644
--- a/calendar/gui/dialogs/event-page.c
+++ b/calendar/gui/dialogs/event-page.c
@@ -33,12 +33,11 @@
#include <libgnome/gnome-i18n.h>
#include <glade/glade.h>
#include <gal/widgets/e-categories.h>
-#include <libedataserverui/e-source-option-menu.h>
#include "common/authentication.h"
#include "e-util/e-categories-config.h"
#include "e-util/e-dialog-widgets.h"
#include "widgets/misc/e-dateedit.h"
-#include "widgets/misc/e-send-options.h"
+#include "widgets/misc/e-source-option-menu.h"
#include <libecal/e-cal-time-util.h>
#include "../calendar-config.h"
#include "../e-timezone-entry.h"
@@ -47,7 +46,6 @@
#include "../e-alarm-list.h"
#include "alarm-list-dialog.h"
#include "event-page.h"
-#include "e-send-options-utils.h"
@@ -86,16 +84,11 @@ struct _EventPagePrivate {
GtkWidget *categories;
GtkWidget *source_selector;
-
- GtkWidget *sendoptions_frame;
- GtkWidget *sendoptions_button;
EAlarmList *alarm_list_store;
gboolean updating;
- gboolean sendoptions_shown;
- ESendOptionsDialog *sod;
char *old_summary;
CalUnits alarm_units;
int alarm_interval;
@@ -104,11 +97,12 @@ struct _EventPagePrivate {
start timezone is then changed, we updated the end timezone to the
same value, since 99% of events start and end in one timezone. */
gboolean sync_timezones;
- gboolean is_meeting;
};
+static void event_page_class_init (EventPageClass *class);
+static void event_page_init (EventPage *epage);
static void event_page_finalize (GObject *object);
static GtkWidget *event_page_get_widget (CompEditorPage *page);
@@ -119,7 +113,21 @@ static gboolean event_page_fill_timezones (CompEditorPage *page, GHashTable *tim
static void event_page_set_summary (CompEditorPage *page, const char *summary);
static void event_page_set_dates (CompEditorPage *page, CompEditorPageDates *dates);
-G_DEFINE_TYPE (EventPage, event_page, TYPE_COMP_EDITOR_PAGE);
+static CompEditorPageClass *parent_class = NULL;
+
+
+
+/**
+ * event_page_get_type:
+ *
+ * Registers the #EventPage class if necessary, and returns the type ID
+ * associated to it.
+ *
+ * Return value: The type ID of the #EventPage class.
+ **/
+
+E_MAKE_TYPE (event_page, "EventPage", EventPage, event_page_class_init, event_page_init,
+ TYPE_COMP_EDITOR_PAGE);
/* Class initialization function for the event page */
static void
@@ -131,6 +139,8 @@ event_page_class_init (EventPageClass *class)
editor_page_class = (CompEditorPageClass *) class;
object_class = (GObjectClass *) class;
+ parent_class = g_type_class_ref (TYPE_COMP_EDITOR_PAGE);
+
editor_page_class->get_widget = event_page_get_widget;
editor_page_class->focus_main_widget = event_page_focus_main_widget;
editor_page_class->fill_widgets = event_page_fill_widgets;
@@ -171,17 +181,11 @@ event_page_init (EventPage *epage)
priv->alarm_custom = NULL;
priv->categories_btn = NULL;
priv->categories = NULL;
- priv->sendoptions_frame = NULL;
- priv->sendoptions_button = NULL;
- priv->sod = NULL;
priv->alarm_interval = -1;
priv->updating = FALSE;
- priv->sendoptions_shown = FALSE;
- priv->is_meeting = FALSE;
priv->sync_timezones = FALSE;
-
}
/* Destroy handler for the event page */
@@ -210,17 +214,13 @@ event_page_finalize (GObject *object)
priv->alarm_list_store = NULL;
}
- if (priv->sod) {
- g_object_unref (priv->sod);
- priv->sod = NULL;
- }
g_free (priv->old_summary);
g_free (priv);
epage->priv = NULL;
- if (G_OBJECT_CLASS (event_page_parent_class)->finalize)
- (* G_OBJECT_CLASS (event_page_parent_class)->finalize) (object);
+ if (G_OBJECT_CLASS (parent_class)->finalize)
+ (* G_OBJECT_CLASS (parent_class)->finalize) (object);
}
@@ -635,41 +635,9 @@ sensitize_widgets (EventPage *epage)
else
gtk_widget_hide (priv->alarm_warning);
gtk_widget_set_sensitive (priv->categories_btn, !read_only);
- gtk_widget_set_sensitive (priv->sendoptions_button, !read_only);
gtk_entry_set_editable (GTK_ENTRY (priv->categories), !read_only);
}
-void
-event_page_hide_options (EventPage *page)
-{
- g_return_if_fail (IS_EVENT_PAGE (page));
-
- gtk_widget_hide (page->priv->sendoptions_frame);
-
- page->priv->sendoptions_shown = FALSE;
-}
-
-void
-event_page_show_options (EventPage *page)
-{
- g_return_if_fail (IS_EVENT_PAGE (page));
-
- gtk_widget_show (page->priv->sendoptions_frame);
-
- if (e_cal_get_static_capability (COMP_EDITOR_PAGE (page)->client, CAL_STATIC_CAPABILITY_NO_GEN_OPTIONS))
- e_sendoptions_set_need_general_options (page->priv->sod, FALSE);
-
- page->priv->sendoptions_shown = TRUE;
-}
-
-void
-event_page_set_meeting (EventPage *page, gboolean set)
-{
- g_return_if_fail (IS_EVENT_PAGE (page));
-
- page->priv->is_meeting = set;
-}
-
/* fill_widgets handler for the event page */
static gboolean
event_page_fill_widgets (CompEditorPage *page, ECalComponent *comp)
@@ -680,8 +648,7 @@ event_page_fill_widgets (CompEditorPage *page, ECalComponent *comp)
ECalComponentClassification cl;
ECalComponentTransparency transparency;
ECalComponentDateTime start_date, end_date;
- icalcomponent *icalcomp;
- const char *location, *uid = NULL;
+ const char *location;
const char *categories;
ESource *source;
GSList *l;
@@ -798,12 +765,6 @@ event_page_fill_widgets (CompEditorPage *page, ECalComponent *comp)
source = e_cal_get_source (page->client);
e_source_option_menu_select (E_SOURCE_OPTION_MENU (priv->source_selector), source);
- e_cal_component_get_uid (comp, &uid);
- if (e_cal_get_object (COMP_EDITOR_PAGE (epage)->client, uid, NULL, &icalcomp, NULL)) {
- icalcomponent_free (icalcomp);
- event_page_hide_options (epage);
- }
-
priv->updating = FALSE;
sensitize_widgets (epage);
@@ -967,10 +928,6 @@ event_page_fill_component (CompEditorPage *page, ECalComponent *comp)
busy = e_dialog_toggle_get (priv->show_time_as_busy);
e_cal_component_set_transparency (comp, busy ? E_CAL_COMPONENT_TRANSP_OPAQUE : E_CAL_COMPONENT_TRANSP_TRANSPARENT);
- /* send options */
- if (priv->sendoptions_shown && priv->sod)
- e_sendoptions_utils_fill_component (priv->sod, comp);
-
/* Alarm */
e_cal_component_remove_all_alarms (comp);
if (e_dialog_toggle_get (priv->alarm)) {
@@ -1181,9 +1138,6 @@ get_widgets (EventPage *epage)
priv->source_selector = GW ("source");
- priv->sendoptions_frame = GW ("send-options-frame");
- priv->sendoptions_button = GW ("send-options-button");
-
#undef GW
return (priv->summary
@@ -1201,9 +1155,7 @@ get_widgets (EventPage *epage)
&& priv->alarm_warning
&& priv->alarm_custom
&& priv->categories_btn
- && priv->categories
- && priv->sendoptions_frame
- && priv->sendoptions_button);
+ && priv->categories);
}
/* Callback used when the summary changes; we emit the notification signal. */
@@ -1612,28 +1564,6 @@ categories_clicked_cb (GtkWidget *button, gpointer data)
e_categories_config_open_dialog_for_entry (GTK_ENTRY (entry));
}
-static void
-e_sendoptions_clicked_cb (GtkWidget *button, gpointer data)
-{
- EventPage *epage;
- EventPagePrivate *priv;
- GtkWidget *toplevel;
- ESource *source;
-
- epage = EVENT_PAGE (data);
- priv = epage->priv;
-
- if (!priv->sod) {
- priv->sod = e_sendoptions_dialog_new ();
- source = e_source_option_menu_peek_selected (E_SOURCE_OPTION_MENU (priv->source_selector));
- e_sendoptions_utils_set_default_data (priv->sod, source, "calendar");
- priv->sod->data->initialized = TRUE;
- }
-
- toplevel = gtk_widget_get_toplevel (priv->main);
- e_sendoptions_dialog_run (priv->sod, toplevel, E_ITEM_CALENDAR);
-}
-
/* This is called when any field is changed; it notifies upstream. */
static void
field_changed_cb (GtkWidget *widget, gpointer data)
@@ -1685,11 +1615,6 @@ source_changed_cb (GtkWidget *widget, ESource *source, gpointer data)
comp_editor_notify_client_changed (
COMP_EDITOR (gtk_widget_get_toplevel (priv->main)),
client);
- if (e_cal_get_static_capability (client, CAL_STATIC_CAPABILITY_REQ_SEND_OPTIONS) && priv->is_meeting)
- event_page_show_options (epage);
- else
- event_page_hide_options (epage);
-
sensitize_widgets (epage);
}
}
@@ -1838,7 +1763,9 @@ init_widgets (EventPage *epage)
G_CALLBACK (summary_changed_cb), epage);
/* Description */
- text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->description));
+ text_buffer = gtk_text_buffer_new (NULL);
+ gtk_text_view_set_buffer (GTK_TEXT_VIEW (priv->description), text_buffer);
+ g_object_unref (text_buffer);
gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->description), GTK_WRAP_WORD);
@@ -1860,10 +1787,6 @@ init_widgets (EventPage *epage)
g_signal_connect((priv->categories_btn), "clicked",
G_CALLBACK (categories_clicked_cb), epage);
- /* send options button */
- g_signal_connect((priv->sendoptions_button), "clicked",
- G_CALLBACK (e_sendoptions_clicked_cb), epage);
-
/* Source selector */
g_signal_connect((priv->source_selector), "source_selected",
G_CALLBACK (source_changed_cb), epage);
diff --git a/calendar/gui/dialogs/event-page.glade b/calendar/gui/dialogs/event-page.glade
index 38dd6576cc..0cf8ad20df 100644
--- a/calendar/gui/dialogs/event-page.glade
+++ b/calendar/gui/dialogs/event-page.glade
@@ -197,9 +197,6 @@
<property name="right_margin">0</property>
<property name="indent">0</property>
<property name="text" translatable="yes"></property>
- <accessibility>
- <atkproperty name="AtkObject::accessible_name" translatable="yes">Event Description</atkproperty>
- </accessibility>
</widget>
</child>
</widget>
@@ -478,9 +475,6 @@
<property name="int1">0</property>
<property name="int2">0</property>
<property name="last_modification_time">Tue, 16 May 2000 19:11:05 GMT</property>
- <accessibility>
- <atkrelation target="start-time-label" type="labelled-by"/>
- </accessibility>
</widget>
<packing>
<property name="left_attach">1</property>
@@ -499,9 +493,6 @@
<property name="int1">0</property>
<property name="int2">0</property>
<property name="last_modification_time">Tue, 16 May 2000 19:11:10 GMT</property>
- <accessibility>
- <atkrelation target="end-time-label" type="labelled-by"/>
- </accessibility>
</widget>
<packing>
<property name="left_attach">1</property>
@@ -531,7 +522,7 @@
</child>
<child>
- <widget class="GtkLabel" id="start-time-label">
+ <widget class="GtkLabel" id="label57">
<property name="visible">True</property>
<property name="label" translatable="yes">_Start time:</property>
<property name="use_underline">True</property>
@@ -556,7 +547,7 @@
</child>
<child>
- <widget class="GtkLabel" id="end-time-label">
+ <widget class="GtkLabel" id="label58">
<property name="visible">True</property>
<property name="label" translatable="yes">_End time:</property>
<property name="use_underline">True</property>
@@ -831,64 +822,6 @@
<property name="fill">False</property>
</packing>
</child>
-
- <child>
- <widget class="GtkFrame" id="send-options-frame">
- <property name="label_xalign">0</property>
- <property name="label_yalign">0.5</property>
- <property name="shadow_type">GTK_SHADOW_NONE</property>
-
- <child>
- <widget class="GtkAlignment" id="alignment2">
- <property name="border_width">12</property>
- <property name="visible">True</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xscale">0.06</property>
- <property name="yscale">1</property>
- <property name="top_padding">0</property>
- <property name="bottom_padding">0</property>
- <property name="left_padding">0</property>
- <property name="right_padding">253</property>
-
- <child>
- <widget class="GtkButton" id="send-options-button">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Ad_vanced send options</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- </widget>
- </child>
- </widget>
- </child>
-
- <child>
- <widget class="GtkLabel" id="send-options-label">
- <property name="visible">True</property>
- <property name="label" translatable="yes">&lt;b&gt;Send Options&lt;/b&gt;</property>
- <property name="use_underline">False</property>
- <property name="use_markup">True</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="type">label_item</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
</widget>
</child>
</widget>
diff --git a/calendar/gui/dialogs/meeting-page.c b/calendar/gui/dialogs/meeting-page.c
index de66095724..c721f474a8 100644
--- a/calendar/gui/dialogs/meeting-page.c
+++ b/calendar/gui/dialogs/meeting-page.c
@@ -35,6 +35,8 @@
#include <libgnome/gnome-i18n.h>
#include <glade/glade.h>
#include <libgnomeui/gnome-stock-icons.h>
+#include <gal/util/e-util.h>
+#include <gal/widgets/e-popup-menu.h>
#include <gal/widgets/e-gui-utils.h>
#include <widgets/misc/e-dateedit.h>
#include <e-util/e-dialog-utils.h>
@@ -48,7 +50,7 @@
#include "comp-editor-util.h"
#include "e-delegate-dialog.h"
#include "meeting-page.h"
-#include "../e-cal-popup.h"
+
/* Private part of the MeetingPage structure */
struct _MeetingPagePrivate {
@@ -93,6 +95,8 @@ struct _MeetingPagePrivate {
+static void meeting_page_class_init (MeetingPageClass *class);
+static void meeting_page_init (MeetingPage *mpage);
static void meeting_page_finalize (GObject *object);
static GtkWidget *meeting_page_get_widget (CompEditorPage *page);
@@ -100,7 +104,21 @@ static void meeting_page_focus_main_widget (CompEditorPage *page);
static gboolean meeting_page_fill_widgets (CompEditorPage *page, ECalComponent *comp);
static gboolean meeting_page_fill_component (CompEditorPage *page, ECalComponent *comp);
-G_DEFINE_TYPE (MeetingPage, meeting_page, TYPE_COMP_EDITOR_PAGE);
+static CompEditorPageClass *parent_class = NULL;
+
+
+
+/**
+ * meeting_page_get_type:
+ *
+ * Registers the #MeetingPage class if necessary, and returns the type ID
+ * associated to it.
+ *
+ * Return value: The type ID of the #MeetingPage class.
+ **/
+
+E_MAKE_TYPE (meeting_page, "MeetingPage", MeetingPage, meeting_page_class_init, meeting_page_init,
+ TYPE_COMP_EDITOR_PAGE);
/* Class initialization function for the task page */
static void
@@ -112,6 +130,8 @@ meeting_page_class_init (MeetingPageClass *class)
editor_page_class = (CompEditorPageClass *) class;
object_class = (GObjectClass *) class;
+ parent_class = g_type_class_ref (TYPE_COMP_EDITOR_PAGE);
+
editor_page_class->get_widget = meeting_page_get_widget;
editor_page_class->focus_main_widget = meeting_page_focus_main_widget;
editor_page_class->fill_widgets = meeting_page_fill_widgets;
@@ -252,8 +272,8 @@ meeting_page_finalize (GObject *object)
g_free (priv);
mpage->priv = NULL;
- if (G_OBJECT_CLASS (meeting_page_parent_class)->finalize)
- (* G_OBJECT_CLASS (meeting_page_parent_class)->finalize) (object);
+ if (G_OBJECT_CLASS (parent_class)->finalize)
+ (* G_OBJECT_CLASS (parent_class)->finalize) (object);
}
@@ -305,15 +325,12 @@ clear_widgets (MeetingPage *mpage)
static void
sensitize_widgets (MeetingPage *mpage)
{
- gboolean read_only = FALSE;
+ gboolean read_only, user_org;
MeetingPagePrivate *priv = mpage->priv;
- GError *error = NULL;
-
- if (!e_cal_is_read_only (COMP_EDITOR_PAGE (mpage)->client, &read_only, &error)) {
- if (error->code != E_CALENDAR_STATUS_BUSY)
- read_only = TRUE;
- g_error_free (error);
- }
+
+ if (!e_cal_is_read_only (COMP_EDITOR_PAGE (mpage)->client, &read_only, NULL))
+ read_only = TRUE;
+
gtk_widget_set_sensitive (priv->organizer, !read_only);
gtk_widget_set_sensitive (priv->existing_organizer_btn, !read_only);
gtk_widget_set_sensitive (priv->add, !read_only && priv->user_org);
@@ -758,9 +775,9 @@ client_changed_cb (CompEditorPage *page, ECal *client, gpointer user_data)
}
static void
-popup_delete_cb (EPopup *ep, EPopupItem *pitem, void *data)
+popup_delete_cb (GtkWidget *widget, gpointer data)
{
- MeetingPage *mpage = data;
+ MeetingPage *mpage = MEETING_PAGE (data);
MeetingPagePrivate *priv;
priv = mpage->priv;
@@ -773,20 +790,17 @@ enum {
CAN_DELETE = 4
};
-static EPopupItem context_menu_items[] = {
+static EPopupMenu context_menu[] = {
#if 0
- { E_POPUP_ITEM, "00.delegate", N_("_Delegate To..."), popup_delegate_cb, NULL, NULL, CAN_DELEGATE },
- { E_POPUP_BAR, "05.bar" },
+ E_POPUP_ITEM (N_("_Delegate To..."), G_CALLBACK (popup_delegate_cb), CAN_DELEGATE),
+
+ E_POPUP_SEPARATOR,
#endif
- { E_POPUP_ITEM, "10.delete", N_("_Remove"), popup_delete_cb, NULL, GTK_STOCK_REMOVE, CAN_DELETE },
+ E_POPUP_ITEM (N_("_Remove"), G_CALLBACK (popup_delete_cb), CAN_DELETE),
+
+ E_POPUP_TERMINATOR
};
-static void
-context_popup_free(EPopup *ep, GSList *items, void *data)
-{
- g_slist_free(items);
-}
-
static gint
button_press_event (GtkWidget *widget, GdkEventButton *event, MeetingPage *mpage)
{
@@ -796,11 +810,8 @@ button_press_event (GtkWidget *widget, GdkEventButton *event, MeetingPage *mpage
GtkTreePath *path;
GtkTreeIter iter;
char *address;
- int disable_mask = 0;
- GSList *menus = NULL;
- ECalPopup *ep;
- int i;
-
+ int disable_mask = 0, hide_mask = 0;
+
priv = mpage->priv;
/* only process right-clicks */
@@ -821,13 +832,16 @@ button_press_event (GtkWidget *widget, GdkEventButton *event, MeetingPage *mpage
if (e_meeting_attendee_get_edit_level (ia) != E_MEETING_ATTENDEE_EDIT_FULL)
disable_mask = CAN_DELETE;
+
+ /* FIXME: if you enable Delegate, then change index to '1'.
+ * (This has now been enabled). */
+ /* context_menu[1].pixmap_widget = gnome_stock_new_with_icon (GNOME_STOCK_MENU_TRASH); */
+ context_menu[0].pixmap_widget =
+ gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU);
- ep = e_cal_popup_new("org.gnome.evolution.calendar.meeting.popup");
- for (i=0;i<sizeof(context_menu_items)/sizeof(context_menu_items[0]);i++)
- menus = g_slist_prepend(menus, &context_menu_items[i]);
-
- e_popup_add_items((EPopup *)ep, menus, NULL, context_popup_free, mpage);
- menu = e_popup_create_menu_once((EPopup *)ep, NULL, disable_mask);
+ menu = e_popup_menu_create (context_menu, disable_mask, hide_mask, mpage);
+ e_auto_kill_popup_menu_on_selection_done (menu);
+
gtk_menu_popup (menu, NULL, NULL, NULL, NULL, event->button, event->time);
return TRUE;
@@ -923,7 +937,8 @@ meeting_page_construct (MeetingPage *mpage, EMeetingStore *ems,
gtk_box_pack_start (GTK_BOX (priv->list_box), sw, TRUE, TRUE, 0);
/* Set the mnemonic widget for the Attendees label */
- gtk_label_set_mnemonic_widget (GTK_LABEL (priv->att_label), GTK_WIDGET (priv->list_view));
+ gtk_label_set_mnemonic_widget (GTK_LABEL (priv->att_label),
+ priv->list_view);
/* Init the widget signals */
init_widgets (mpage);
diff --git a/calendar/gui/dialogs/recurrence-page.c b/calendar/gui/dialogs/recurrence-page.c
index 07e3b6164b..921f3d32bd 100644
--- a/calendar/gui/dialogs/recurrence-page.c
+++ b/calendar/gui/dialogs/recurrence-page.c
@@ -198,6 +198,8 @@ struct _RecurrencePagePrivate {
+static void recurrence_page_class_init (RecurrencePageClass *class);
+static void recurrence_page_init (RecurrencePage *rpage);
static void recurrence_page_finalize (GObject *object);
static GtkWidget *recurrence_page_get_widget (CompEditorPage *page);
@@ -208,7 +210,21 @@ static void recurrence_page_set_dates (CompEditorPage *page, CompEditorPageDates
static void field_changed (RecurrencePage *apage);
-G_DEFINE_TYPE (RecurrencePage, recurrence_page, TYPE_COMP_EDITOR_PAGE);
+static CompEditorPageClass *parent_class = NULL;
+
+
+
+/**
+ * recurrence_page_get_type:
+ *
+ * Registers the #RecurrencePage class if necessary, and returns the type ID
+ * associated to it.
+ *
+ * Return value: The type ID of the #RecurrencePage class.
+ **/
+
+E_MAKE_TYPE (recurrence_page, "RecurrencePage", RecurrencePage, recurrence_page_class_init,
+ recurrence_page_init, TYPE_COMP_EDITOR_PAGE);
/* Class initialization function for the recurrence page */
static void
@@ -220,6 +236,8 @@ recurrence_page_class_init (RecurrencePageClass *class)
editor_page_class = (CompEditorPageClass *) class;
object_class = (GObjectClass *) class;
+ parent_class = g_type_class_ref(TYPE_COMP_EDITOR_PAGE);
+
editor_page_class->get_widget = recurrence_page_get_widget;
editor_page_class->focus_main_widget = recurrence_page_focus_main_widget;
editor_page_class->fill_widgets = recurrence_page_fill_widgets;
@@ -304,8 +322,8 @@ recurrence_page_finalize (GObject *object)
g_free (priv);
rpage->priv = NULL;
- if (G_OBJECT_CLASS (recurrence_page_parent_class)->finalize)
- (* G_OBJECT_CLASS (recurrence_page_parent_class)->finalize) (object);
+ if (G_OBJECT_CLASS (parent_class)->finalize)
+ (* G_OBJECT_CLASS (parent_class)->finalize) (object);
}
@@ -514,7 +532,7 @@ sensitize_buttons (RecurrencePage *rpage)
gint selected_rows;
RecurrencePagePrivate *priv;
icalcomponent *icalcomp;
- const char *uid;
+ char *uid;
priv = rpage->priv;
@@ -531,19 +549,6 @@ sensitize_buttons (RecurrencePage *rpage)
read_only = TRUE;
icalcomponent_free (icalcomp);
}
-
- if (!read_only) {
- GList *list;
-
- /* see if we have detached instances */
- if (e_cal_get_objects_for_uid (COMP_EDITOR_PAGE (rpage)->client, uid, &list, NULL)) {
- if (list && g_list_length (list) > 1)
- read_only = TRUE;
-
- g_list_foreach (list, (GFunc) g_object_unref, NULL);
- g_list_free (list);
- }
- }
}
if (!read_only)
diff --git a/calendar/gui/dialogs/task-page.glade b/calendar/gui/dialogs/task-page.glade
index 3415672ec2..cacc411a9e 100644
--- a/calendar/gui/dialogs/task-page.glade
+++ b/calendar/gui/dialogs/task-page.glade
@@ -26,7 +26,7 @@
<child>
<widget class="GtkLabel" id="label21">
<property name="visible">True</property>
- <property name="label" translatable="yes">&lt;b&gt;Basics&lt;/b&gt;</property>
+ <property name="label" translatable="yes">&lt;span weight=&quot;bold&quot;&gt;Basics&lt;/span&gt;</property>
<property name="use_underline">False</property>
<property name="use_markup">True</property>
<property name="justify">GTK_JUSTIFY_LEFT</property>
@@ -89,7 +89,7 @@
<property name="max_length">0</property>
<property name="text" translatable="yes"></property>
<property name="has_frame">True</property>
- <property name="invisible_char">*</property>
+ <property name="invisible_char" translatable="yes">*</property>
<property name="activates_default">False</property>
</widget>
<packing>
@@ -274,11 +274,8 @@
<property name="max_length">0</property>
<property name="text" translatable="yes"></property>
<property name="has_frame">True</property>
- <property name="invisible_char">*</property>
+ <property name="invisible_char" translatable="yes">*</property>
<property name="activates_default">False</property>
- <accessibility>
- <atkproperty name="AtkObject::accessible_name" translatable="yes">Categories</atkproperty>
- </accessibility>
</widget>
<packing>
<property name="left_attach">1</property>
@@ -314,9 +311,6 @@
<property name="right_margin">0</property>
<property name="indent">0</property>
<property name="text" translatable="yes"></property>
- <accessibility>
- <atkproperty name="AtkObject::accessible_name" translatable="yes">Task Description</atkproperty>
- </accessibility>
</widget>
</child>
</widget>
@@ -372,7 +366,7 @@
<child>
<widget class="GtkLabel" id="label24">
<property name="visible">True</property>
- <property name="label" translatable="yes">&lt;b&gt;Date and Time&lt;/b&gt;</property>
+ <property name="label" translatable="yes">&lt;span weight=&quot;bold&quot;&gt;Date and Time&lt;/span&gt;</property>
<property name="use_underline">False</property>
<property name="use_markup">True</property>
<property name="justify">GTK_JUSTIFY_LEFT</property>
@@ -427,7 +421,7 @@
<property name="column_spacing">12</property>
<child>
- <widget class="GtkLabel" id="due-date-label">
+ <widget class="GtkLabel" id="label29">
<property name="visible">True</property>
<property name="label" translatable="yes">_Due date:</property>
<property name="use_underline">True</property>
@@ -452,7 +446,7 @@
</child>
<child>
- <widget class="GtkLabel" id="start-date-label">
+ <widget class="GtkLabel" id="label30">
<property name="visible">True</property>
<property name="label" translatable="yes">Sta_rt date:</property>
<property name="use_underline">True</property>
@@ -489,9 +483,6 @@
<property name="int1">0</property>
<property name="int2">0</property>
<property name="last_modification_time">Mon, 14 Jun 2004 18:16:07 GMT</property>
- <accessibility>
- <atkrelation target="due-date-label" type="labelled-by"/>
- </accessibility>
</widget>
<packing>
<property name="padding">0</property>
@@ -538,9 +529,6 @@
<property name="int1">0</property>
<property name="int2">0</property>
<property name="last_modification_time">Mon, 14 Jun 2004 18:16:13 GMT</property>
- <accessibility>
- <atkrelation target="start-date-label" type="labelled-by"/>
- </accessibility>
</widget>
<packing>
<property name="padding">0</property>
@@ -587,64 +575,6 @@
<property name="fill">False</property>
</packing>
</child>
-
- <child>
- <widget class="GtkFrame" id="send-options-frame">
- <property name="label_xalign">0</property>
- <property name="label_yalign">0.5</property>
- <property name="shadow_type">GTK_SHADOW_NONE</property>
-
- <child>
- <widget class="GtkAlignment" id="alignment1">
- <property name="border_width">12</property>
- <property name="visible">True</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xscale">0.11</property>
- <property name="yscale">1</property>
- <property name="top_padding">0</property>
- <property name="bottom_padding">0</property>
- <property name="left_padding">12</property>
- <property name="right_padding">0</property>
-
- <child>
- <widget class="GtkButton" id="send-options-button">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Ad_vanced send options</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- </widget>
- </child>
- </widget>
- </child>
-
- <child>
- <widget class="GtkLabel" id="send-options-label">
- <property name="visible">True</property>
- <property name="label" translatable="yes">&lt;b&gt;Send Options&lt;/b&gt;</property>
- <property name="use_underline">False</property>
- <property name="use_markup">True</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="type">label_item</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
</widget>
</child>
</widget>
diff --git a/calendar/gui/e-cal-list-view.c b/calendar/gui/e-cal-list-view.c
index d17f26889c..9ef25b92df 100644
--- a/calendar/gui/e-cal-list-view.c
+++ b/calendar/gui/e-cal-list-view.c
@@ -25,9 +25,7 @@
* ECalListView - display calendar events in an ETable.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-#endif
#include "e-cal-list-view.h"
#include "ea-calendar.h"
@@ -43,6 +41,7 @@
#include <gtk/gtkvscrollbar.h>
#include <gtk/gtkwindow.h>
#include <gal/widgets/e-gui-utils.h>
+#include <gal/util/e-util.h>
#include <gal/e-table/e-table-memory-store.h>
#include <gal/e-table/e-cell-checkbox.h>
#include <gal/e-table/e-cell-toggle.h>
@@ -71,6 +70,8 @@
#include "goto.h"
#include "misc.h"
+static void e_cal_list_view_class_init (ECalListViewClass *class);
+static void e_cal_list_view_init (ECalListView *cal_list_view);
static void e_cal_list_view_destroy (GtkObject *object);
static GList *e_cal_list_view_get_selected_events (ECalendarView *cal_view);
@@ -88,7 +89,10 @@ static gboolean e_cal_list_view_on_table_right_click (GtkWidget *table, gint
GdkEvent *event, gpointer data);
static void e_cal_list_view_cursor_change_cb (ETable *etable, gint row, gpointer data);
-G_DEFINE_TYPE (ECalListView, e_cal_list_view, E_TYPE_CALENDAR_VIEW);
+static GtkTableClass *parent_class; /* Should be ECalendarViewClass? */
+
+E_MAKE_TYPE (e_cal_list_view, "ECalListView", ECalListView, e_cal_list_view_class_init,
+ e_cal_list_view_init, e_calendar_view_get_type ());
static void
e_cal_list_view_class_init (ECalListViewClass *class)
@@ -97,6 +101,7 @@ e_cal_list_view_class_init (ECalListViewClass *class)
GtkWidgetClass *widget_class;
ECalendarViewClass *view_class;
+ parent_class = g_type_class_peek_parent (class);
object_class = (GtkObjectClass *) class;
widget_class = (GtkWidgetClass *) class;
view_class = (ECalendarViewClass *) class;
@@ -316,6 +321,7 @@ e_cal_list_view_new (void)
ECalModel *model;
model = E_CAL_MODEL (e_cal_model_calendar_new ());
+ e_cal_model_set_flags (model, E_CAL_MODEL_FLAGS_EXPAND_RECURRENCES);
cal_list_view = g_object_new (e_cal_list_view_get_type (), "model", model, NULL);
if (!e_cal_list_view_construct (cal_list_view)) {
@@ -358,16 +364,16 @@ e_cal_list_view_destroy (GtkObject *object)
cal_list_view->table_scrolled = NULL;
}
- GTK_OBJECT_CLASS (e_cal_list_view_parent_class)->destroy (object);
+ GTK_OBJECT_CLASS (parent_class)->destroy (object);
}
static void
e_cal_list_view_show_popup_menu (ECalListView *cal_list_view, gint row, GdkEvent *gdk_event)
{
- GtkMenu *menu;
+ GtkMenu *popup;
- menu = e_calendar_view_create_popup_menu (E_CALENDAR_VIEW (cal_list_view));
- gtk_menu_popup(menu, NULL, NULL, NULL, NULL, gdk_event?gdk_event->button.button:0, gdk_event?gdk_event->button.time:gtk_get_current_event_time());
+ popup = e_calendar_view_create_popup_menu (E_CALENDAR_VIEW (cal_list_view));
+ e_popup_menu (popup, gdk_event);
}
static gboolean
diff --git a/calendar/gui/e-cal-model-calendar.c b/calendar/gui/e-cal-model-calendar.c
index b64dce21c6..63532c5be8 100644
--- a/calendar/gui/e-cal-model-calendar.c
+++ b/calendar/gui/e-cal-model-calendar.c
@@ -1,6 +1,7 @@
/* Evolution calendar - Data model for ETable
*
- * Copyright (C) 2004 Ximian, Inc.
+ * Copyright (C) 2000 Ximian, Inc.
+ * Copyright (C) 2000 Ximian, Inc.
*
* Authors: Rodrigo Moya <rodrigo@ximian.com>
*
@@ -18,23 +19,20 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-#endif
-
#include <string.h>
#include <libgnome/gnome-i18n.h>
+#include <gal/util/e-util.h>
#include "e-cal-model-calendar.h"
#include "e-cell-date-edit-text.h"
-#include "itip-utils.h"
#include "misc.h"
-#include "dialogs/recur-comp.h"
-#include "dialogs/send-comp.h"
struct _ECalModelCalendarPrivate {
};
-static void e_cal_model_calendar_finalize (GObject *object);
+static void ecmc_class_init (ECalModelCalendarClass *klass);
+static void ecmc_init (ECalModelCalendar *model, ECalModelCalendarClass *klass);
+static void ecmc_finalize (GObject *object);
static int ecmc_column_count (ETableModel *etm);
static void *ecmc_value_at (ETableModel *etm, int col, int row);
static void ecmc_set_value_at (ETableModel *etm, int col, int row, const void *value);
@@ -48,16 +46,21 @@ static char *ecmc_value_to_string (ETableModel *etm, int col, const void *value)
static void ecmc_fill_component_from_model (ECalModel *model, ECalModelComponent *comp_data,
ETableModel *source_model, gint row);
-G_DEFINE_TYPE (ECalModelCalendar, e_cal_model_calendar, E_TYPE_CAL_MODEL);
+static GObjectClass *parent_class = NULL;
+
+E_MAKE_TYPE (e_cal_model_calendar, "ECalModelCalendar", ECalModelCalendar, ecmc_class_init,
+ ecmc_init, E_TYPE_CAL_MODEL);
static void
-e_cal_model_calendar_class_init (ECalModelCalendarClass *klass)
+ecmc_class_init (ECalModelCalendarClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
ETableModelClass *etm_class = E_TABLE_MODEL_CLASS (klass);
ECalModelClass *model_class = E_CAL_MODEL_CLASS (klass);
- object_class->finalize = e_cal_model_calendar_finalize;
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = ecmc_finalize;
etm_class->column_count = ecmc_column_count;
etm_class->value_at = ecmc_value_at;
@@ -73,7 +76,7 @@ e_cal_model_calendar_class_init (ECalModelCalendarClass *klass)
}
static void
-e_cal_model_calendar_init (ECalModelCalendar *model)
+ecmc_init (ECalModelCalendar *model, ECalModelCalendarClass *klass)
{
ECalModelCalendarPrivate *priv;
@@ -84,7 +87,7 @@ e_cal_model_calendar_init (ECalModelCalendar *model)
}
static void
-e_cal_model_calendar_finalize (GObject *object)
+ecmc_finalize (GObject *object)
{
ECalModelCalendarPrivate *priv;
ECalModelCalendar *model = (ECalModelCalendar *) object;
@@ -97,8 +100,8 @@ e_cal_model_calendar_finalize (GObject *object)
model->priv = NULL;
}
- if (G_OBJECT_CLASS (e_cal_model_calendar_parent_class)->finalize)
- G_OBJECT_CLASS (e_cal_model_calendar_parent_class)->finalize (object);
+ if (parent_class->finalize)
+ parent_class->finalize (object);
}
/* ETableModel methods */
@@ -115,7 +118,7 @@ get_dtend (ECalModelCalendar *model, ECalModelComponent *comp_data)
if (!comp_data->dtend) {
icalproperty *prop;
- icaltimezone *zone, *model_zone;
+ icaltimezone *zone;
gboolean got_zone = FALSE;
prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_DTEND_PROPERTY);
@@ -128,12 +131,11 @@ get_dtend (ECalModelCalendar *model, ECalModelComponent *comp_data)
&& e_cal_get_timezone (comp_data->client, icaltime_get_tzid (tt_end), &zone, NULL))
got_zone = TRUE;
- if (e_cal_model_get_flags (E_CAL_MODEL (model)) & E_CAL_MODEL_FLAGS_EXPAND_RECURRENCES) {
- if (got_zone) {
+ if ((e_cal_model_get_flags (E_CAL_MODEL (model)) & E_CAL_MODEL_FLAGS_EXPAND_RECURRENCES) &&
+ (e_cal_util_component_has_recurrences (comp_data->icalcomp))) {
+ if (got_zone)
tt_end = icaltime_from_timet_with_zone (comp_data->instance_end, tt_end.is_date, zone);
- if ((model_zone = e_cal_model_get_timezone (E_CAL_MODEL (model))))
- icaltimezone_convert_time (&tt_end, zone, model_zone);
- } else
+ else
tt_end = icaltime_from_timet (comp_data->instance_end, tt_end.is_date);
}
@@ -200,7 +202,7 @@ ecmc_value_at (ETableModel *etm, int col, int row)
g_return_val_if_fail (row >= 0 && row < e_table_model_row_count (etm), NULL);
if (col < E_CAL_MODEL_FIELD_LAST)
- return E_TABLE_MODEL_CLASS (e_cal_model_calendar_parent_class)->value_at (etm, col, row);
+ return E_TABLE_MODEL_CLASS (parent_class)->value_at (etm, col, row);
comp_data = e_cal_model_get_component_at (E_CAL_MODEL (model), row);
if (!comp_data)
@@ -333,8 +335,6 @@ static void
ecmc_set_value_at (ETableModel *etm, int col, int row, const void *value)
{
ECalModelComponent *comp_data;
- CalObjModType mod = CALOBJ_MOD_ALL;
- ECalComponent *comp;
ECalModelCalendar *model = (ECalModelCalendar *) etm;
g_return_if_fail (E_IS_CAL_MODEL_CALENDAR (model));
@@ -342,7 +342,7 @@ ecmc_set_value_at (ETableModel *etm, int col, int row, const void *value)
g_return_if_fail (row >= 0 && row < e_table_model_row_count (etm));
if (col < E_CAL_MODEL_FIELD_LAST) {
- E_TABLE_MODEL_CLASS (e_cal_model_calendar_parent_class)->set_value_at (etm, col, row, value);
+ E_TABLE_MODEL_CLASS (parent_class)->set_value_at (etm, col, row, value);
return;
}
@@ -350,20 +350,6 @@ ecmc_set_value_at (ETableModel *etm, int col, int row, const void *value)
if (!comp_data)
return;
- comp = e_cal_component_new ();
- if (!e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (comp_data->icalcomp))) {
- g_object_unref (comp);
- return;
- }
-
- /* ask about mod type */
- if (e_cal_component_is_instance (comp)) {
- if (!recur_component_dialog (comp_data->client, comp, &mod, NULL)) {
- g_object_unref (comp);
- return;
- }
- }
-
switch (col) {
case E_CAL_MODEL_CALENDAR_FIELD_DTEND :
set_dtend (comp_data, value);
@@ -376,18 +362,12 @@ ecmc_set_value_at (ETableModel *etm, int col, int row, const void *value)
break;
}
- if (e_cal_modify_object (comp_data->client, comp_data->icalcomp, CALOBJ_MOD_ALL, NULL)) {
- if (itip_organizer_is_user (comp, comp_data->client) &&
- send_component_dialog (NULL, comp_data->client, comp, FALSE))
- itip_send_comp (E_CAL_COMPONENT_METHOD_REQUEST, comp,
- comp_data->client, NULL, NULL);
- } else {
+ /* FIXME ask about mod type */
+ if (!e_cal_modify_object (comp_data->client, comp_data->icalcomp, CALOBJ_MOD_ALL, NULL)) {
g_warning (G_STRLOC ": Could not modify the object!");
/* FIXME Show error dialog */
}
-
- g_object_unref (comp);
}
static gboolean
@@ -400,7 +380,7 @@ ecmc_is_cell_editable (ETableModel *etm, int col, int row)
g_return_val_if_fail (row >= -1 || (row >= 0 && row < e_table_model_row_count (etm)), FALSE);
if (col < E_CAL_MODEL_FIELD_LAST)
- return E_TABLE_MODEL_CLASS (e_cal_model_calendar_parent_class)->is_cell_editable (etm, col, row);
+ return E_TABLE_MODEL_CLASS (parent_class)->is_cell_editable (etm, col, row);
switch (col) {
case E_CAL_MODEL_CALENDAR_FIELD_DTEND :
@@ -418,7 +398,7 @@ ecmc_duplicate_value (ETableModel *etm, int col, const void *value)
g_return_val_if_fail (col >= 0 && col < E_CAL_MODEL_CALENDAR_FIELD_LAST, NULL);
if (col < E_CAL_MODEL_FIELD_LAST)
- return E_TABLE_MODEL_CLASS (e_cal_model_calendar_parent_class)->duplicate_value (etm, col, value);
+ return E_TABLE_MODEL_CLASS (parent_class)->duplicate_value (etm, col, value);
switch (col) {
case E_CAL_MODEL_CALENDAR_FIELD_DTEND :
@@ -446,7 +426,7 @@ ecmc_free_value (ETableModel *etm, int col, void *value)
g_return_if_fail (col >= 0 && col < E_CAL_MODEL_CALENDAR_FIELD_LAST);
if (col < E_CAL_MODEL_FIELD_LAST) {
- E_TABLE_MODEL_CLASS (e_cal_model_calendar_parent_class)->free_value (etm, col, value);
+ E_TABLE_MODEL_CLASS (parent_class)->free_value (etm, col, value);
return;
}
@@ -466,7 +446,7 @@ ecmc_initialize_value (ETableModel *etm, int col)
g_return_val_if_fail (col >= 0 && col < E_CAL_MODEL_CALENDAR_FIELD_LAST, NULL);
if (col < E_CAL_MODEL_FIELD_LAST)
- return E_TABLE_MODEL_CLASS (e_cal_model_calendar_parent_class)->initialize_value (etm, col);
+ return E_TABLE_MODEL_CLASS (parent_class)->initialize_value (etm, col);
switch (col) {
case E_CAL_MODEL_CALENDAR_FIELD_DTEND :
@@ -485,7 +465,7 @@ ecmc_value_is_empty (ETableModel *etm, int col, const void *value)
g_return_val_if_fail (col >= 0 && col < E_CAL_MODEL_CALENDAR_FIELD_LAST, TRUE);
if (col < E_CAL_MODEL_FIELD_LAST)
- return E_TABLE_MODEL_CLASS (e_cal_model_calendar_parent_class)->value_is_empty (etm, col, value);
+ return E_TABLE_MODEL_CLASS (parent_class)->value_is_empty (etm, col, value);
switch (col) {
case E_CAL_MODEL_CALENDAR_FIELD_DTEND :
@@ -504,7 +484,7 @@ ecmc_value_to_string (ETableModel *etm, int col, const void *value)
g_return_val_if_fail (col >= 0 && col < E_CAL_MODEL_CALENDAR_FIELD_LAST, g_strdup (""));
if (col < E_CAL_MODEL_FIELD_LAST)
- return E_TABLE_MODEL_CLASS (e_cal_model_calendar_parent_class)->value_to_string (etm, col, value);
+ return E_TABLE_MODEL_CLASS (parent_class)->value_to_string (etm, col, value);
switch (col) {
case E_CAL_MODEL_CALENDAR_FIELD_DTEND :
diff --git a/calendar/gui/e-cal-model-tasks.c b/calendar/gui/e-cal-model-tasks.c
index 2ef9420788..508406c80d 100644
--- a/calendar/gui/e-cal-model-tasks.c
+++ b/calendar/gui/e-cal-model-tasks.c
@@ -1,6 +1,7 @@
/* Evolution calendar - Data model for ETable
*
- * Copyright (C) 2004 Ximian, Inc.
+ * Copyright (C) 2000 Ximian, Inc.
+ * Copyright (C) 2000 Ximian, Inc.
*
* Authors: Rodrigo Moya <rodrigo@ximian.com>
*
@@ -18,14 +19,12 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-#endif
-
#include <math.h>
#include <string.h>
#include <gtk/gtkmessagedialog.h>
#include <libgnome/gnome-i18n.h>
+#include <gal/util/e-util.h>
#include "calendar-config.h"
#include "e-cal-model-tasks.h"
#include "e-cell-date-edit-text.h"
@@ -34,7 +33,9 @@
struct _ECalModelTasksPrivate {
};
-static void e_cal_model_tasks_finalize (GObject *object);
+static void ecmt_class_init (ECalModelTasksClass *klass);
+static void ecmt_init (ECalModelTasks *model, ECalModelTasksClass *klass);
+static void ecmt_finalize (GObject *object);
static int ecmt_column_count (ETableModel *etm);
static void *ecmt_value_at (ETableModel *etm, int col, int row);
@@ -50,16 +51,21 @@ static const char *ecmt_get_color_for_component (ECalModel *model, ECalModelComp
static void ecmt_fill_component_from_model (ECalModel *model, ECalModelComponent *comp_data,
ETableModel *source_model, gint row);
-G_DEFINE_TYPE (ECalModelTasks, e_cal_model_tasks, E_TYPE_CAL_MODEL);
+static GObjectClass *parent_class = NULL;
+
+E_MAKE_TYPE (e_cal_model_tasks, "ECalModelTasks", ECalModelTasks, ecmt_class_init,
+ ecmt_init, E_TYPE_CAL_MODEL);
static void
-e_cal_model_tasks_class_init (ECalModelTasksClass *klass)
+ecmt_class_init (ECalModelTasksClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
ETableModelClass *etm_class = E_TABLE_MODEL_CLASS (klass);
ECalModelClass *model_class = E_CAL_MODEL_CLASS (klass);
- object_class->finalize = e_cal_model_tasks_finalize;
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = ecmt_finalize;
etm_class->column_count = ecmt_column_count;
etm_class->value_at = ecmt_value_at;
@@ -76,7 +82,7 @@ e_cal_model_tasks_class_init (ECalModelTasksClass *klass)
}
static void
-e_cal_model_tasks_init (ECalModelTasks *model)
+ecmt_init (ECalModelTasks *model, ECalModelTasksClass *klass)
{
ECalModelTasksPrivate *priv;
@@ -87,7 +93,7 @@ e_cal_model_tasks_init (ECalModelTasks *model)
}
static void
-e_cal_model_tasks_finalize (GObject *object)
+ecmt_finalize (GObject *object)
{
ECalModelTasksPrivate *priv;
ECalModelTasks *model = (ECalModelTasks *) object;
@@ -100,8 +106,8 @@ e_cal_model_tasks_finalize (GObject *object)
model->priv = NULL;
}
- if (G_OBJECT_CLASS (e_cal_model_tasks_parent_class)->finalize)
- G_OBJECT_CLASS (e_cal_model_tasks_parent_class)->finalize (object);
+ if (parent_class->finalize)
+ parent_class->finalize (object);
}
/* ETableModel methods */
@@ -371,18 +377,8 @@ is_complete (ECalModelComponent *comp_data)
icalproperty *prop;
prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_COMPLETED_PROPERTY);
- if (prop)
- return TRUE;
-
- prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_PERCENTCOMPLETE_PROPERTY);
- if (prop && icalproperty_get_percentcomplete (prop) == 100)
- return TRUE;
- prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_STATUS_PROPERTY);
- if (prop && icalproperty_get_status (prop) == ICAL_STATUS_COMPLETED)
- return TRUE;
-
- return FALSE;
+ return prop ? TRUE : FALSE;
}
typedef enum {
@@ -476,7 +472,7 @@ ecmt_value_at (ETableModel *etm, int col, int row)
g_return_val_if_fail (row >= 0 && row < e_table_model_row_count (etm), NULL);
if (col < E_CAL_MODEL_FIELD_LAST)
- return E_TABLE_MODEL_CLASS (e_cal_model_tasks_parent_class)->value_at (etm, col, row);
+ return E_TABLE_MODEL_CLASS (parent_class)->value_at (etm, col, row);
comp_data = e_cal_model_get_component_at (E_CAL_MODEL (model), row);
if (!comp_data)
@@ -793,7 +789,7 @@ ecmt_set_value_at (ETableModel *etm, int col, int row, const void *value)
g_return_if_fail (row >= 0 && row < e_table_model_row_count (etm));
if (col < E_CAL_MODEL_FIELD_LAST) {
- E_TABLE_MODEL_CLASS (e_cal_model_tasks_parent_class)->set_value_at (etm, col, row, value);
+ E_TABLE_MODEL_CLASS (parent_class)->set_value_at (etm, col, row, value);
return;
}
@@ -850,7 +846,7 @@ ecmt_is_cell_editable (ETableModel *etm, int col, int row)
g_return_val_if_fail (row >= -1 || (row >= 0 && row < e_table_model_row_count (etm)), FALSE);
if (col < E_CAL_MODEL_FIELD_LAST)
- return E_TABLE_MODEL_CLASS (e_cal_model_tasks_parent_class)->is_cell_editable (etm, col, row);
+ return E_TABLE_MODEL_CLASS (parent_class)->is_cell_editable (etm, col, row);
switch (col) {
case E_CAL_MODEL_TASKS_FIELD_COMPLETED :
@@ -873,7 +869,7 @@ ecmt_duplicate_value (ETableModel *etm, int col, const void *value)
g_return_val_if_fail (col >= 0 && col < E_CAL_MODEL_TASKS_FIELD_LAST, NULL);
if (col < E_CAL_MODEL_FIELD_LAST)
- return E_TABLE_MODEL_CLASS (e_cal_model_tasks_parent_class)->duplicate_value (etm, col, value);
+ return E_TABLE_MODEL_CLASS (parent_class)->duplicate_value (etm, col, value);
switch (col) {
case E_CAL_MODEL_TASKS_FIELD_GEO :
@@ -909,7 +905,7 @@ ecmt_free_value (ETableModel *etm, int col, void *value)
g_return_if_fail (col >= 0 && col < E_CAL_MODEL_TASKS_FIELD_LAST);
if (col < E_CAL_MODEL_FIELD_LAST) {
- E_TABLE_MODEL_CLASS (e_cal_model_tasks_parent_class)->free_value (etm, col, value);
+ E_TABLE_MODEL_CLASS (parent_class)->free_value (etm, col, value);
return;
}
@@ -939,7 +935,7 @@ ecmt_initialize_value (ETableModel *etm, int col)
g_return_val_if_fail (col >= 0 && col < E_CAL_MODEL_TASKS_FIELD_LAST, NULL);
if (col < E_CAL_MODEL_FIELD_LAST)
- return E_TABLE_MODEL_CLASS (e_cal_model_tasks_parent_class)->initialize_value (etm, col);
+ return E_TABLE_MODEL_CLASS (parent_class)->initialize_value (etm, col);
switch (col) {
case E_CAL_MODEL_TASKS_FIELD_GEO :
@@ -971,7 +967,7 @@ ecmt_value_is_empty (ETableModel *etm, int col, const void *value)
priv = model->priv;
if (col < E_CAL_MODEL_FIELD_LAST)
- return E_TABLE_MODEL_CLASS (e_cal_model_tasks_parent_class)->value_is_empty (etm, col, value);
+ return E_TABLE_MODEL_CLASS (parent_class)->value_is_empty (etm, col, value);
switch (col) {
case E_CAL_MODEL_TASKS_FIELD_GEO :
@@ -1001,7 +997,7 @@ ecmt_value_to_string (ETableModel *etm, int col, const void *value)
g_return_val_if_fail (col >= 0 && col < E_CAL_MODEL_TASKS_FIELD_LAST, g_strdup (""));
if (col < E_CAL_MODEL_FIELD_LAST)
- return E_TABLE_MODEL_CLASS (e_cal_model_tasks_parent_class)->value_to_string (etm, col, value);
+ return E_TABLE_MODEL_CLASS (parent_class)->value_to_string (etm, col, value);
switch (col) {
case E_CAL_MODEL_TASKS_FIELD_GEO :
@@ -1044,7 +1040,7 @@ ecmt_get_color_for_component (ECalModel *model, ECalModelComponent *comp_data)
break;
}
- return E_CAL_MODEL_CLASS (e_cal_model_tasks_parent_class)->get_color_for_component (model, comp_data);
+ return E_CAL_MODEL_CLASS (parent_class)->get_color_for_component (model, comp_data);
}
static void
diff --git a/calendar/gui/e-cal-model.c b/calendar/gui/e-cal-model.c
index f9e7de2003..87f23b2f45 100644
--- a/calendar/gui/e-cal-model.c
+++ b/calendar/gui/e-cal-model.c
@@ -1,6 +1,7 @@
/* Evolution calendar - Data model for ETable
*
- * Copyright (C) 2004 Novell, Inc.
+ * Copyright (C) 2000 Ximian, Inc.
+ * Copyright (C) 2000 Ximian, Inc.
*
* Authors: Rodrigo Moya <rodrigo@ximian.com>
*
@@ -25,6 +26,7 @@
#include <string.h>
#include <glib/garray.h>
#include <libgnome/gnome-i18n.h>
+#include <gal/util/e-util.h>
#include <e-util/e-time-utils.h>
#include <libecal/e-cal-time-util.h>
#include "comp-util.h"
@@ -74,6 +76,8 @@ struct _ECalModelPrivate {
gboolean use_24_hour_format;
};
+static void e_cal_model_class_init (ECalModelClass *klass);
+static void e_cal_model_init (ECalModel *model, ECalModelClass *klass);
static void e_cal_model_dispose (GObject *object);
static void e_cal_model_finalize (GObject *object);
@@ -105,7 +109,10 @@ enum {
static guint signals[LAST_SIGNAL] = { 0 };
-G_DEFINE_TYPE (ECalModel, e_cal_model, E_TABLE_MODEL_TYPE);
+static GObjectClass *parent_class = NULL;
+
+E_MAKE_TYPE (e_cal_model, "ECalModel", ECalModel, e_cal_model_class_init,
+ e_cal_model_init, E_TABLE_MODEL_TYPE);
static void
e_cal_model_class_init (ECalModelClass *klass)
@@ -113,6 +120,8 @@ e_cal_model_class_init (ECalModelClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
ETableModelClass *etm_class = E_TABLE_MODEL_CLASS (klass);
+ parent_class = g_type_class_peek_parent (klass);
+
object_class->dispose = e_cal_model_dispose;
object_class->finalize = e_cal_model_finalize;
@@ -151,7 +160,7 @@ e_cal_model_class_init (ECalModelClass *klass)
}
static void
-e_cal_model_init (ECalModel *model)
+e_cal_model_init (ECalModel *model, ECalModelClass *klass)
{
ECalModelPrivate *priv;
@@ -174,6 +183,46 @@ e_cal_model_init (ECalModel *model)
}
static void
+free_comp_data (ECalModelComponent *comp_data)
+{
+ g_return_if_fail (comp_data != NULL);
+
+ comp_data->client = NULL;
+
+ if (comp_data->icalcomp) {
+ icalcomponent_free (comp_data->icalcomp);
+ comp_data->icalcomp = NULL;
+ }
+
+ if (comp_data->dtstart) {
+ g_free (comp_data->dtstart);
+ comp_data->dtstart = NULL;
+ }
+
+ if (comp_data->dtend) {
+ g_free (comp_data->dtend);
+ comp_data->dtend = NULL;
+ }
+
+ if (comp_data->due) {
+ g_free (comp_data->due);
+ comp_data->due = NULL;
+ }
+
+ if (comp_data->completed) {
+ g_free (comp_data->completed);
+ comp_data->completed = NULL;
+ }
+
+ if (comp_data->color) {
+ g_free (comp_data->color);
+ comp_data->color = NULL;
+ }
+
+ g_free (comp_data);
+}
+
+static void
clear_objects_array (ECalModelPrivate *priv)
{
gint i;
@@ -183,9 +232,10 @@ clear_objects_array (ECalModelPrivate *priv)
comp_data = g_ptr_array_index (priv->objects, i);
g_assert (comp_data != NULL);
- e_cal_model_free_component_data (comp_data);
+ free_comp_data (comp_data);
}
+
g_ptr_array_set_size (priv->objects, 0);
}
@@ -221,8 +271,8 @@ e_cal_model_dispose (GObject *object)
priv->clients = NULL;
}
- if (G_OBJECT_CLASS (e_cal_model_parent_class)->dispose)
- G_OBJECT_CLASS (e_cal_model_parent_class)->dispose (object);
+ if (parent_class->dispose)
+ parent_class->dispose (object);
}
static void
@@ -245,8 +295,8 @@ e_cal_model_finalize (GObject *object)
g_free (priv);
- if (G_OBJECT_CLASS (e_cal_model_parent_class)->finalize)
- G_OBJECT_CLASS (e_cal_model_parent_class)->finalize (object);
+ if (parent_class->finalize)
+ parent_class->finalize (object);
}
/* ETableModel methods */
@@ -365,12 +415,11 @@ get_dtstart (ECalModel *model, ECalModelComponent *comp_data)
&& e_cal_get_timezone (comp_data->client, icaltime_get_tzid (tt_start), &zone, NULL))
got_zone = TRUE;
- if (e_cal_model_get_flags (model) & E_CAL_MODEL_FLAGS_EXPAND_RECURRENCES) {
- if (got_zone) {
+ if ((priv->flags & E_CAL_MODEL_FLAGS_EXPAND_RECURRENCES) &&
+ (e_cal_util_component_has_recurrences (comp_data->icalcomp))) {
+ if (got_zone)
tt_start = icaltime_from_timet_with_zone (comp_data->instance_start, tt_start.is_date, zone);
- if (priv->zone)
- icaltimezone_convert_time (&tt_start, zone, priv->zone);
- } else
+ else
tt_start = icaltime_from_timet (comp_data->instance_start, tt_start.is_date);
}
@@ -718,7 +767,7 @@ ecm_append_row (ETableModel *etm, ETableModel *source, int row)
g_return_if_fail (E_IS_CAL_MODEL (model));
g_return_if_fail (E_IS_TABLE_MODEL (source));
- memset (&comp_data, 0, sizeof (ECalModelComponent));
+ memset (&comp_data, 0, sizeof (comp_data));
comp_data.client = e_cal_model_get_default_client (model);
/* guard against saving before the calendar is open */
@@ -740,6 +789,7 @@ ecm_append_row (ETableModel *etm, ETableModel *source, int row)
model_class->fill_component_from_model (model, &comp_data, source, row);
}
+
if (!e_cal_create_object (comp_data.client, comp_data.icalcomp, NULL, NULL)) {
g_warning (G_STRLOC ": Could not create the object!");
@@ -1238,7 +1288,7 @@ search_by_uid_and_client (ECalModelPrivate *priv, ECal *client, const char *uid)
tmp_uid = icalcomponent_get_uid (comp_data->icalcomp);
if (tmp_uid && *tmp_uid) {
- if (comp_data->client == client && !strcmp (uid, tmp_uid))
+ if ((!client || comp_data->client == client) && !strcmp (uid, tmp_uid))
return comp_data;
}
}
@@ -1279,12 +1329,10 @@ add_instance_cb (ECalComponent *comp, time_t instance_start, time_t instance_end
e_table_model_pre_change (E_TABLE_MODEL (rdata->model));
comp_data = g_new0 (ECalModelComponent, 1);
- comp_data->client = g_object_ref (rdata->client);
- comp_data->icalcomp = icalcomponent_new_clone (e_cal_component_get_icalcomponent (comp));
+ comp_data->client = g_object_ref (e_cal_view_get_client (rdata->query));
+ comp_data->icalcomp = icalcomponent_new_clone (rdata->icalcomp);
comp_data->instance_start = instance_start;
comp_data->instance_end = instance_end;
- comp_data->dtstart = comp_data->dtend = comp_data->due = comp_data->completed = NULL;
- comp_data->color = NULL;
g_ptr_array_add (priv->objects, comp_data);
e_table_model_row_inserted (E_TABLE_MODEL (rdata->model), priv->objects->len - 1);
@@ -1293,26 +1341,6 @@ add_instance_cb (ECalComponent *comp, time_t instance_start, time_t instance_end
}
static void
-set_instance_times (ECalModelComponent *comp_data, icaltimezone *zone)
-{
- struct icaltimetype recur_time, start_time, end_time, itt;
-
- recur_time = icalcomponent_get_recurrenceid (comp_data->icalcomp);
- start_time = icalcomponent_get_dtstart (comp_data->icalcomp);
- end_time = icalcomponent_get_dtend (comp_data->icalcomp);
-
- if (e_cal_util_component_is_instance (comp_data->icalcomp)) {
- itt = icaltime_convert_to_zone (recur_time, icaltimezone_get_utc_timezone ());
- comp_data->instance_start = icaltime_as_timet (itt);
- } else {
- comp_data->instance_start = icaltime_as_timet (start_time);
- }
-
- comp_data->instance_end = comp_data->instance_start +
- (icaltime_as_timet (end_time) - icaltime_as_timet (start_time));
-}
-
-static void
e_cal_view_objects_added_cb (ECalView *query, GList *objects, gpointer user_data)
{
ECalModel *model = (ECalModel *) user_data;
@@ -1322,21 +1350,8 @@ e_cal_view_objects_added_cb (ECalView *query, GList *objects, gpointer user_data
priv = model->priv;
for (l = objects; l; l = l->next) {
- ECalModelComponent *comp_data;
-
- /* remove the components if they are already present and re-add them */
- while ((comp_data = search_by_uid_and_client (priv, e_cal_view_get_client (query),
- icalcomponent_get_uid (l->data)))) {
- int pos;
-
- pos = get_position_in_array (priv->objects, comp_data);
- e_table_model_row_deleted (E_TABLE_MODEL (model), pos);
-
- g_ptr_array_remove (priv->objects, comp_data);
- e_cal_model_free_component_data (comp_data);
- }
-
- if ((priv->flags & E_CAL_MODEL_FLAGS_EXPAND_RECURRENCES)) {
+ if ((priv->flags & E_CAL_MODEL_FLAGS_EXPAND_RECURRENCES) &&
+ e_cal_util_component_has_recurrences (l->data)) {
RecurrenceExpansionData rdata;
rdata.client = e_cal_view_get_client (query);
@@ -1348,14 +1363,13 @@ e_cal_view_objects_added_cb (ECalView *query, GList *objects, gpointer user_data
(ECalRecurInstanceFn) add_instance_cb,
&rdata);
} else {
+ ECalModelComponent *comp_data;
+
e_table_model_pre_change (E_TABLE_MODEL (model));
comp_data = g_new0 (ECalModelComponent, 1);
comp_data->client = g_object_ref (e_cal_view_get_client (query));
comp_data->icalcomp = icalcomponent_new_clone (l->data);
- set_instance_times (comp_data, priv->zone);
- comp_data->dtstart = comp_data->dtend = comp_data->due = comp_data->completed = NULL;
- comp_data->color = NULL;
g_ptr_array_add (priv->objects, comp_data);
e_table_model_row_inserted (E_TABLE_MODEL (model), priv->objects->len - 1);
@@ -1375,21 +1389,62 @@ e_cal_view_objects_modified_cb (ECalView *query, GList *objects, gpointer user_d
for (l = objects; l; l = l->next) {
ECalModelComponent *comp_data;
- /* remove all recurrences and re-add them after generating them */
- while ((comp_data = search_by_uid_and_client (priv, e_cal_view_get_client (query),
- icalcomponent_get_uid (l->data)))) {
- int pos;
+ if ((priv->flags & E_CAL_MODEL_FLAGS_EXPAND_RECURRENCES) &&
+ e_cal_util_component_has_recurrences (l->data)) {
+ GList node;
- pos = get_position_in_array (priv->objects, comp_data);
- e_table_model_row_deleted (E_TABLE_MODEL (model), pos);
+ /* remove all recurrences and re-add them after generating them */
+ while ((comp_data = search_by_uid_and_client (priv, e_cal_view_get_client (query),
+ icalcomponent_get_uid (l->data)))) {
+ int pos;
- g_ptr_array_remove (priv->objects, comp_data);
- e_cal_model_free_component_data (comp_data);
+ pos = get_position_in_array (priv->objects, comp_data);
+
+ g_ptr_array_remove (priv->objects, comp_data);
+ free_comp_data (comp_data);
+
+ e_table_model_row_deleted (E_TABLE_MODEL (model), pos);
+ }
+
+ node.prev = node.next = NULL;
+ node.data = l->data;
+ e_cal_view_objects_added_cb (query, &node, model);
+ } else {
+ e_table_model_pre_change (E_TABLE_MODEL (model));
+
+ comp_data = search_by_uid_and_client (priv, e_cal_view_get_client (query),
+ icalcomponent_get_uid (l->data));
+ if (!comp_data)
+ continue;
+
+ if (comp_data->icalcomp)
+ icalcomponent_free (comp_data->icalcomp);
+ if (comp_data->dtstart) {
+ g_free (comp_data->dtstart);
+ comp_data->dtstart = NULL;
+ }
+ if (comp_data->dtend) {
+ g_free (comp_data->dtend);
+ comp_data->dtend = NULL;
+ }
+ if (comp_data->due) {
+ g_free (comp_data->due);
+ comp_data->due = NULL;
+ }
+ if (comp_data->completed) {
+ g_free (comp_data->completed);
+ comp_data->completed = NULL;
+ }
+ if (comp_data->color) {
+ g_free (comp_data->color);
+ comp_data->color = NULL;
+ }
+
+ comp_data->icalcomp = icalcomponent_new_clone (l->data);
+
+ e_table_model_row_changed (E_TABLE_MODEL (model), get_position_in_array (priv->objects, comp_data));
}
}
-
- /* now re-add all objects */
- e_cal_view_objects_added_cb (query, objects, model);
}
static void
@@ -1410,10 +1465,11 @@ e_cal_view_objects_removed_cb (ECalView *query, GList *uids, gpointer user_data)
/* make sure we remove all objects with this UID */
while ((comp_data = search_by_uid_and_client (priv, e_cal_view_get_client (query), l->data))) {
pos = get_position_in_array (priv->objects, comp_data);
- e_table_model_row_deleted (E_TABLE_MODEL (model), pos);
-
+
g_ptr_array_remove (priv->objects, comp_data);
- e_cal_model_free_component_data (comp_data);
+ free_comp_data (comp_data);
+
+ e_table_model_row_deleted (E_TABLE_MODEL (model), pos);
}
}
}
@@ -1581,10 +1637,11 @@ remove_client_objects (ECalModel *model, ECalModelClient *client_data)
if (comp_data->client == client_data->client) {
e_table_model_pre_change (E_TABLE_MODEL (model));
- e_table_model_row_deleted (E_TABLE_MODEL (model), i - 1);
-
+
g_ptr_array_remove (model->priv->objects, comp_data);
- e_cal_model_free_component_data (comp_data);
+ free_comp_data (comp_data);
+
+ e_table_model_row_deleted (E_TABLE_MODEL (model), i - 1);
}
}
}
@@ -1684,8 +1741,8 @@ redo_queries (ECalModel *model)
/* clean up the current contents */
e_table_model_pre_change (E_TABLE_MODEL (model));
len = priv->objects->len;
- e_table_model_rows_deleted (E_TABLE_MODEL (model), 0, len);
clear_objects_array (priv);
+ e_table_model_rows_deleted (E_TABLE_MODEL (model), 0, len);
/* update the query for all clients */
for (l = priv->clients; l != NULL; l = l->next) {
@@ -1943,9 +2000,10 @@ copy_ecdv (ECellDateEditValue *ecdv)
{
ECellDateEditValue *new_ecdv;
+
new_ecdv = g_new0 (ECellDateEditValue, 1);
- new_ecdv->tt = ecdv ? ecdv->tt : icaltime_null_time ();
- new_ecdv->zone = ecdv ? ecdv->zone : NULL;
+ new_ecdv->tt = ecdv->tt;
+ new_ecdv->zone = ecdv->zone;
return new_ecdv;
}
@@ -1962,8 +2020,6 @@ e_cal_model_copy_component_data (ECalModelComponent *comp_data)
new_data = g_new0 (ECalModelComponent, 1);
- new_data->instance_start = comp_data->instance_start;
- new_data->instance_end = comp_data->instance_end;
if (comp_data->icalcomp)
new_data->icalcomp = icalcomponent_new_clone (comp_data->icalcomp);
if (comp_data->client)
@@ -1976,8 +2032,6 @@ e_cal_model_copy_component_data (ECalModelComponent *comp_data)
new_data->due = copy_ecdv (comp_data->due);
if (comp_data->completed)
new_data->completed = copy_ecdv (comp_data->completed);
- if (comp_data->color)
- new_data->color = g_strdup (comp_data->color);
return new_data;
}
@@ -1990,34 +2044,20 @@ e_cal_model_free_component_data (ECalModelComponent *comp_data)
{
g_return_if_fail (comp_data != NULL);
- if (comp_data->client) {
+ if (comp_data->client)
g_object_unref (comp_data->client);
- comp_data->client = NULL;
- }
- if (comp_data->icalcomp) {
+ if (comp_data->icalcomp)
icalcomponent_free (comp_data->icalcomp);
- comp_data->icalcomp = NULL;
- }
- if (comp_data->dtstart) {
+ if (comp_data->dtstart)
g_free (comp_data->dtstart);
- comp_data->dtstart = NULL;
- }
- if (comp_data->dtend) {
+ if (comp_data->dtend)
g_free (comp_data->dtend);
- comp_data->dtend = NULL;
- }
- if (comp_data->due) {
+ if (comp_data->due)
g_free (comp_data->due);
- comp_data->due = NULL;
- }
- if (comp_data->completed) {
+ if (comp_data->completed)
g_free (comp_data->completed);
- comp_data->completed = NULL;
- }
- if (comp_data->color) {
+ if (comp_data->color)
g_free (comp_data->color);
- comp_data->color = NULL;
- }
g_free (comp_data);
}
diff --git a/calendar/gui/e-calendar-table.c b/calendar/gui/e-calendar-table.c
index a3d50bb475..7eec950039 100644
--- a/calendar/gui/e-calendar-table.c
+++ b/calendar/gui/e-calendar-table.c
@@ -27,10 +27,7 @@
* Used for calendar events and tasks.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-#endif
-
#include <sys/stat.h>
#include <unistd.h>
#include <gnome.h>
@@ -39,6 +36,7 @@
#include <gal/e-table/e-cell-toggle.h>
#include <gal/e-table/e-cell-text.h>
#include <gal/e-table/e-cell-combo.h>
+#include <gal/widgets/e-popup-menu.h>
#include <e-util/e-dialog-utils.h>
#include <widgets/misc/e-cell-date-edit.h>
#include <widgets/misc/e-cell-percent.h>
@@ -54,7 +52,6 @@
#include "e-comp-editor-registry.h"
#include "print.h"
#include <e-util/e-icon-factory.h>
-#include "e-cal-popup.h"
extern ECompEditorRegistry *comp_editor_registry;
@@ -79,6 +76,22 @@ static gint e_calendar_table_on_right_click (ETable *table,
static gboolean e_calendar_table_on_popup_menu (GtkWidget *widget,
gpointer data);
+static void e_calendar_table_on_open_task (GtkWidget *menuitem,
+ gpointer data);
+static void e_calendar_table_on_save_as (GtkWidget *menuitem,
+ gpointer data);
+static void e_calendar_table_on_print_task (GtkWidget *menuitem,
+ gpointer data);
+static void e_calendar_table_on_cut (GtkWidget *menuitem,
+ gpointer data);
+static void e_calendar_table_on_copy (GtkWidget *menuitem,
+ gpointer data);
+static void e_calendar_table_on_paste (GtkWidget *menuitem,
+ gpointer data);
+static void e_calendar_table_on_assign (GtkWidget *menuitem,
+ gpointer data);
+static void e_calendar_table_on_forward (GtkWidget *menuitem,
+ gpointer data);
static gint e_calendar_table_on_key_press (ETable *table,
gint row,
gint col,
@@ -106,9 +119,11 @@ static const char* icon_names[E_CALENDAR_MODEL_NUM_ICONS] = {
};
static GdkPixbuf* icon_pixbufs[E_CALENDAR_MODEL_NUM_ICONS] = { 0 };
+static GtkTableClass *parent_class;
static GdkAtom clipboard_atom = GDK_NONE;
-G_DEFINE_TYPE (ECalendarTable, e_calendar_table, GTK_TYPE_TABLE);
+E_MAKE_TYPE (e_calendar_table, "ECalendarTable", ECalendarTable, e_calendar_table_class_init,
+ e_calendar_table_init, GTK_TYPE_TABLE);
static void
e_calendar_table_class_init (ECalendarTableClass *class)
@@ -116,6 +131,7 @@ e_calendar_table_class_init (ECalendarTableClass *class)
GtkObjectClass *object_class;
GtkWidgetClass *widget_class;
+ parent_class = g_type_class_peek_parent (class);
object_class = (GtkObjectClass *) class;
widget_class = (GtkWidgetClass *) class;
@@ -294,7 +310,6 @@ e_calendar_table_init (ECalendarTable *cal_table)
gint i;
GdkPixbuf *pixbuf;
GList *strings;
- AtkObject *a11y;
/* Create the model */
@@ -510,10 +525,6 @@ e_calendar_table_init (ECalendarTable *cal_table)
g_signal_connect (e_table, "right_click", G_CALLBACK (e_calendar_table_on_right_click), cal_table);
g_signal_connect (e_table, "key_press", G_CALLBACK (e_calendar_table_on_key_press), cal_table);
g_signal_connect (e_table, "popup_menu", G_CALLBACK (e_calendar_table_on_popup_menu), cal_table);
-
- a11y = gtk_widget_get_accessible (e_table);
- if (a11y)
- atk_object_set_name (a11y, _("Task Table"));
}
@@ -564,7 +575,7 @@ e_calendar_table_destroy (GtkObject *object)
cal_table->model = NULL;
}
- GTK_OBJECT_CLASS (e_calendar_table_parent_class)->destroy (object);
+ GTK_OBJECT_CLASS (parent_class)->destroy (object);
}
/**
@@ -589,12 +600,10 @@ void
e_calendar_table_open_selected (ECalendarTable *cal_table)
{
ECalModelComponent *comp_data;
- icalproperty *prop;
comp_data = get_selected_comp (cal_table);
- prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_ATTENDEE_PROPERTY);
if (comp_data != NULL)
- open_task (cal_table, comp_data, prop ? TRUE : FALSE);
+ open_task (cal_table, comp_data, FALSE);
}
/**
@@ -753,21 +762,6 @@ e_calendar_table_delete_selected (ECalendarTable *cal_table)
}
/**
- * e_calendar_table_get_selected:
- * @cal_table:
- *
- * Get the currently selected ECalModelComponent's on the table.
- *
- * Return value: A GSList of the components, which should be
- * g_slist_free'd when finished with.
- **/
-GSList *
-e_calendar_table_get_selected (ECalendarTable *cal_table)
-{
- return get_selected_objects(cal_table);
-}
-
-/**
* e_calendar_table_cut_clipboard:
* @cal_table: A calendar table.
*
@@ -947,7 +941,7 @@ open_task (ECalendarTable *cal_table, ECalModelComponent *comp_data, gboolean as
if (tedit == NULL) {
ECalComponent *comp;
- tedit = COMP_EDITOR (task_editor_new (comp_data->client, assign));
+ tedit = COMP_EDITOR (task_editor_new (comp_data->client));
comp = e_cal_component_new ();
e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (comp_data->icalcomp));
@@ -966,11 +960,9 @@ static void
open_task_by_row (ECalendarTable *cal_table, int row)
{
ECalModelComponent *comp_data;
- icalproperty *prop;
comp_data = e_cal_model_get_component_at (cal_table->model, row);
- prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_ATTENDEE_PROPERTY);
- open_task (cal_table, comp_data, prop ? TRUE : FALSE);
+ open_task (cal_table, comp_data, FALSE);
}
static void
@@ -983,30 +975,223 @@ e_calendar_table_on_double_click (ETable *table,
open_task_by_row (cal_table, row);
}
-/* popup menu callbacks */
+/* Used from e_table_selected_row_foreach() */
+static void
+mark_row_complete_cb (int model_row, gpointer data)
+{
+ ECalendarTable *cal_table;
+
+ cal_table = E_CALENDAR_TABLE (data);
+ e_cal_model_tasks_mark_task_complete (E_CAL_MODEL_TASKS (cal_table->model), model_row);
+}
+/* Callback used for the "mark tasks as complete" menu item */
static void
-e_calendar_table_on_open_task (EPopup *ep, EPopupItem *pitem, void *data)
+mark_as_complete_cb (GtkWidget *menuitem, gpointer data)
{
- ECalendarTable *cal_table = data;
+ ECalendarTable *cal_table;
+ ETable *etable;
+
+ cal_table = E_CALENDAR_TABLE (data);
+
+ etable = e_table_scrolled_get_table (E_TABLE_SCROLLED (cal_table->etable));
+ e_table_selected_row_foreach (etable, mark_row_complete_cb, cal_table);
+}
+
+/* Opens the URL of the task */
+static void
+open_url_cb (GtkWidget *menuitem, gpointer data)
+{
+ ECalendarTable *cal_table;
ECalModelComponent *comp_data;
icalproperty *prop;
+ cal_table = E_CALENDAR_TABLE (data);
+
+ comp_data = get_selected_comp (cal_table);
+ if (!comp_data)
+ return;
+
+ prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_URL_PROPERTY);
+ if (!prop)
+ return;
+
+ gnome_url_show (icalproperty_get_url (prop), NULL);
+}
+
+/* Callback for the "delete tasks" menu item */
+static void
+delete_cb (GtkWidget *menuitem, gpointer data)
+{
+ ECalendarTable *cal_table;
+
+ cal_table = E_CALENDAR_TABLE (data);
+ e_calendar_table_delete_selected (cal_table);
+}
+
+
+enum {
+ MASK_SINGLE = 1 << 0, /* For commands that work on 1 task. */
+ MASK_MULTIPLE = 1 << 1, /* For commands for multiple tasks. */
+ MASK_EDITABLE = 1 << 2, /* For commands disabled in read-only folders */
+ MASK_ASSIGNABLE = 1 << 3, /* For non-task assignable backends */
+ MASK_LACKS_URL = 1 << 4 /* For tasks that don't have the URL property set */
+};
+
+
+static EPopupMenu tasks_popup_menu [] = {
+ E_POPUP_ITEM (N_("_Open"), GTK_SIGNAL_FUNC (e_calendar_table_on_open_task), MASK_SINGLE),
+ E_POPUP_ITEM (N_("Open _Web Page"), GTK_SIGNAL_FUNC (open_url_cb), MASK_SINGLE | MASK_LACKS_URL),
+ E_POPUP_ITEM (N_("_Save As..."), GTK_SIGNAL_FUNC (e_calendar_table_on_save_as), MASK_SINGLE),
+ E_POPUP_ITEM (N_("_Print..."), GTK_SIGNAL_FUNC (e_calendar_table_on_print_task), MASK_SINGLE),
+
+ E_POPUP_SEPARATOR,
+
+ E_POPUP_ITEM (N_("C_ut"), GTK_SIGNAL_FUNC (e_calendar_table_on_cut), MASK_EDITABLE),
+ E_POPUP_ITEM (N_("_Copy"), GTK_SIGNAL_FUNC (e_calendar_table_on_copy), 0),
+ E_POPUP_ITEM (N_("_Paste"), GTK_SIGNAL_FUNC (e_calendar_table_on_paste), MASK_EDITABLE),
+
+ E_POPUP_SEPARATOR,
+
+ E_POPUP_ITEM (N_("_Assign Task"), GTK_SIGNAL_FUNC (e_calendar_table_on_assign), MASK_SINGLE | MASK_EDITABLE | MASK_ASSIGNABLE),
+ E_POPUP_ITEM (N_("_Forward as iCalendar"), GTK_SIGNAL_FUNC (e_calendar_table_on_forward), MASK_SINGLE),
+ E_POPUP_ITEM (N_("_Mark as Complete"), GTK_SIGNAL_FUNC (mark_as_complete_cb), MASK_SINGLE | MASK_EDITABLE),
+ E_POPUP_ITEM (N_("_Mark Selected Tasks as Complete"), GTK_SIGNAL_FUNC (mark_as_complete_cb), MASK_MULTIPLE | MASK_EDITABLE),
+
+ E_POPUP_SEPARATOR,
+
+ E_POPUP_ITEM (N_("_Delete"), GTK_SIGNAL_FUNC (delete_cb), MASK_SINGLE | MASK_EDITABLE),
+ E_POPUP_ITEM (N_("_Delete Selected Tasks"), GTK_SIGNAL_FUNC (delete_cb), MASK_MULTIPLE | MASK_EDITABLE),
+
+ E_POPUP_TERMINATOR
+};
+
+static void
+setup_popup_icons (EPopupMenu *context_menu)
+{
+ gint i;
+
+ for (i = 0; context_menu[i].name; i++) {
+ GtkWidget *pixmap_widget = NULL;
+
+ if (!strcmp (context_menu[i].name, _("_Copy")))
+ pixmap_widget = gtk_image_new_from_stock (GTK_STOCK_COPY, GTK_ICON_SIZE_MENU);
+ else if (!strcmp (context_menu[i].name, _("C_ut")))
+ pixmap_widget = gtk_image_new_from_stock (GTK_STOCK_CUT, GTK_ICON_SIZE_MENU);
+ else if (!strcmp (context_menu[i].name, _("_Delete")) ||
+ !strcmp (context_menu[i].name, _("_Delete Selected Tasks")))
+ pixmap_widget = gtk_image_new_from_stock (GTK_STOCK_DELETE, GTK_ICON_SIZE_MENU);
+ else if (!strcmp (context_menu[i].name, _("_Open")))
+ pixmap_widget = gtk_image_new_from_stock (GTK_STOCK_OPEN, GTK_ICON_SIZE_MENU);
+ else if (!strcmp (context_menu[i].name, _("_Paste")))
+ pixmap_widget = gtk_image_new_from_stock (GTK_STOCK_PASTE, GTK_ICON_SIZE_MENU);
+ else if (!strcmp (context_menu[i].name, _("_Print...")))
+ pixmap_widget = gtk_image_new_from_stock (GTK_STOCK_PRINT, GTK_ICON_SIZE_MENU);
+ else if (!strcmp (context_menu[i].name, _("_Save As...")))
+ pixmap_widget = gtk_image_new_from_stock (GTK_STOCK_SAVE_AS, GTK_ICON_SIZE_MENU);
+
+ if (pixmap_widget)
+ gtk_widget_show (pixmap_widget);
+ context_menu[i].pixmap_widget = pixmap_widget;
+ }
+}
+
+static gint
+e_calendar_table_show_popup_menu (ETable *table,
+ GdkEvent *gdk_event,
+ ECalendarTable *cal_table)
+{
+ int n_selected;
+ int hide_mask = 0;
+ int disable_mask = 0;
+ GtkMenu *gtk_menu;
+ icalproperty *prop;
+ GSList *selection;
+ ECalModelComponent *comp_data;
+ gboolean read_only = TRUE;
+
+ selection = get_selected_objects (cal_table);
+ if (!selection)
+ return TRUE;
+
+ comp_data = selection->data;
+ n_selected = g_slist_length (selection);
+ if (n_selected == 1) {
+ hide_mask = MASK_MULTIPLE;
+
+ /* See if the task has the URL property set */
+ prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_URL_PROPERTY);
+ if (!prop)
+ disable_mask |= MASK_LACKS_URL;
+ } else
+ hide_mask = MASK_SINGLE;
+
+ e_cal_is_read_only (comp_data->client, &read_only, NULL);
+ if (read_only)
+ disable_mask |= MASK_EDITABLE;
+
+ if (e_cal_get_static_capability (comp_data->client, CAL_STATIC_CAPABILITY_NO_TASK_ASSIGNMENT))
+ disable_mask |= MASK_ASSIGNABLE;
+
+ if (e_cal_get_static_capability (comp_data->client, CAL_STATIC_CAPABILITY_NO_CONV_TO_ASSIGN_TASK))
+ disable_mask |= MASK_ASSIGNABLE;
+
+ setup_popup_icons (tasks_popup_menu);
+ gtk_menu = e_popup_menu_create (tasks_popup_menu, disable_mask,
+ hide_mask, cal_table);
+
+ e_popup_menu (gtk_menu, gdk_event);
+
+ g_slist_free (selection);
+
+ return TRUE;
+}
+
+static gint
+e_calendar_table_on_right_click (ETable *table,
+ gint row,
+ gint col,
+ GdkEvent *event,
+ ECalendarTable *cal_table)
+{
+ return e_calendar_table_show_popup_menu (table, event, cal_table);
+}
+
+static gboolean
+e_calendar_table_on_popup_menu (GtkWidget *widget, gpointer data)
+{
+ ETable *table = E_TABLE(widget);
+ g_return_val_if_fail(table, FALSE);
+
+ return e_calendar_table_show_popup_menu (table, NULL,
+ E_CALENDAR_TABLE(data));
+}
+
+static void
+e_calendar_table_on_open_task (GtkWidget *menuitem,
+ gpointer data)
+{
+ ECalendarTable *cal_table;
+ ECalModelComponent *comp_data;
+
+ cal_table = E_CALENDAR_TABLE (data);
+
comp_data = get_selected_comp (cal_table);
- prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_ATTENDEE_PROPERTY);
if (comp_data)
- open_task (cal_table, comp_data, prop ? TRUE : FALSE);
+ open_task (cal_table, comp_data, FALSE);
}
static void
-e_calendar_table_on_save_as (EPopup *ep, EPopupItem *pitem, void *data)
+e_calendar_table_on_save_as (GtkWidget *widget, gpointer data)
{
- ECalendarTable *cal_table = data;
+ ECalendarTable *cal_table;
ECalModelComponent *comp_data;
char *filename;
char *ical_string;
FILE *file;
+ cal_table = E_CALENDAR_TABLE (data);
+
comp_data = get_selected_comp (cal_table);
if (comp_data == NULL)
return;
@@ -1033,12 +1218,14 @@ e_calendar_table_on_save_as (EPopup *ep, EPopupItem *pitem, void *data)
}
static void
-e_calendar_table_on_print_task (EPopup *ep, EPopupItem *pitem, void *data)
+e_calendar_table_on_print_task (GtkWidget *widget, gpointer data)
{
- ECalendarTable *cal_table = data;
+ ECalendarTable *cal_table;
ECalModelComponent *comp_data;
ECalComponent *comp;
+ cal_table = E_CALENDAR_TABLE (data);
+
comp_data = get_selected_comp (cal_table);
if (comp_data == NULL)
return;
@@ -1051,203 +1238,65 @@ e_calendar_table_on_print_task (EPopup *ep, EPopupItem *pitem, void *data)
}
static void
-e_calendar_table_on_cut (EPopup *ep, EPopupItem *pitem, void *data)
+e_calendar_table_on_cut (GtkWidget *menuitem, gpointer data)
{
- ECalendarTable *cal_table = data;
+ ECalendarTable *cal_table;
+ cal_table = E_CALENDAR_TABLE (data);
e_calendar_table_cut_clipboard (cal_table);
}
static void
-e_calendar_table_on_copy (EPopup *ep, EPopupItem *pitem, void *data)
+e_calendar_table_on_copy (GtkWidget *menuitem, gpointer data)
{
- ECalendarTable *cal_table = data;
+ ECalendarTable *cal_table;
+ cal_table = E_CALENDAR_TABLE (data);
e_calendar_table_copy_clipboard (cal_table);
}
static void
-e_calendar_table_on_paste (EPopup *ep, EPopupItem *pitem, void *data)
+e_calendar_table_on_paste (GtkWidget *menuitem, gpointer data)
{
- ECalendarTable *cal_table = data;
+ ECalendarTable *cal_table;
+ cal_table = E_CALENDAR_TABLE (data);
e_calendar_table_paste_clipboard (cal_table);
}
static void
-e_calendar_table_on_assign (EPopup *ep, EPopupItem *pitem, void *data)
+e_calendar_table_on_assign (GtkWidget *widget, gpointer data)
{
- ECalendarTable *cal_table = data;
+ ECalendarTable *cal_table;
ECalModelComponent *comp_data;
+ cal_table = E_CALENDAR_TABLE (data);
+
comp_data = get_selected_comp (cal_table);
if (comp_data)
open_task (cal_table, comp_data, TRUE);
}
static void
-e_calendar_table_on_forward (EPopup *ep, EPopupItem *pitem, void *data)
+e_calendar_table_on_forward (GtkWidget *widget, gpointer data)
{
- ECalendarTable *cal_table = data;
+ ECalendarTable *cal_table;
ECalModelComponent *comp_data;
+ cal_table = E_CALENDAR_TABLE (data);
+
comp_data = get_selected_comp (cal_table);
if (comp_data) {
ECalComponent *comp;
comp = e_cal_component_new ();
e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (comp_data->icalcomp));
- itip_send_comp (E_CAL_COMPONENT_METHOD_PUBLISH, comp, comp_data->client, NULL, NULL);
+ itip_send_comp (E_CAL_COMPONENT_METHOD_PUBLISH, comp, comp_data->client, NULL);
g_object_unref (comp);
}
}
-/* Used from e_table_selected_row_foreach() */
-static void
-mark_row_complete_cb (int model_row, gpointer data)
-{
- ECalendarTable *cal_table;
-
- cal_table = E_CALENDAR_TABLE (data);
- e_cal_model_tasks_mark_task_complete (E_CAL_MODEL_TASKS (cal_table->model), model_row);
-}
-
-/* Callback used for the "mark tasks as complete" menu item */
-static void
-mark_as_complete_cb (EPopup *ep, EPopupItem *pitem, void *data)
-{
- ECalendarTable *cal_table = data;
- ETable *etable;
-
- etable = e_table_scrolled_get_table (E_TABLE_SCROLLED (cal_table->etable));
- e_table_selected_row_foreach (etable, mark_row_complete_cb, cal_table);
-}
-
-/* Opens the URL of the task */
-static void
-open_url_cb (EPopup *ep, EPopupItem *pitem, void *data)
-{
- ECalendarTable *cal_table = data;
- ECalModelComponent *comp_data;
- icalproperty *prop;
-
- comp_data = get_selected_comp (cal_table);
- if (!comp_data)
- return;
-
- prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_URL_PROPERTY);
- if (!prop)
- return;
-
- gnome_url_show (icalproperty_get_url (prop), NULL);
-}
-
-/* Callback for the "delete tasks" menu item */
-static void
-delete_cb (EPopup *ep, EPopupItem *pitem, void *data)
-{
- ECalendarTable *cal_table = data;
-
- e_calendar_table_delete_selected (cal_table);
-}
-
-static EPopupItem tasks_popup_items [] = {
- { E_POPUP_ITEM, "00.open", N_("_Open"), e_calendar_table_on_open_task, NULL, GTK_STOCK_OPEN, E_CAL_POPUP_SELECT_ONE },
- { E_POPUP_ITEM, "05.openweb", N_("Open _Web Page"), open_url_cb, NULL, NULL, E_CAL_POPUP_SELECT_ONE, E_CAL_POPUP_SELECT_HASURL },
- { E_POPUP_ITEM, "10.saveas", N_("_Save As..."), e_calendar_table_on_save_as, NULL, GTK_STOCK_SAVE_AS, E_CAL_POPUP_SELECT_ONE },
- { E_POPUP_ITEM, "20.print", N_("_Print..."), e_calendar_table_on_print_task, NULL, GTK_STOCK_PRINT, E_CAL_POPUP_SELECT_ONE },
-
- { E_POPUP_BAR, "30.bar" },
-
- { E_POPUP_ITEM, "40.cut", N_("C_ut"), e_calendar_table_on_cut, NULL, GTK_STOCK_CUT, 0, E_CAL_POPUP_SELECT_EDITABLE },
- { E_POPUP_ITEM, "50.copy", N_("_Copy"), e_calendar_table_on_copy, NULL, GTK_STOCK_COPY, 0, 0 },
- { E_POPUP_ITEM, "60.paste", N_("_Paste"), e_calendar_table_on_paste, NULL, GTK_STOCK_PASTE, 0, E_CAL_POPUP_SELECT_EDITABLE },
-
- { E_POPUP_BAR, "70.bar" },
-
- { E_POPUP_ITEM, "80.assign", N_("_Assign Task"), e_calendar_table_on_assign, NULL, NULL, E_CAL_POPUP_SELECT_ONE, E_CAL_POPUP_SELECT_EDITABLE|E_CAL_POPUP_SELECT_ASSIGNABLE },
- { E_POPUP_ITEM, "90.forward", N_("_Forward as iCalendar"), e_calendar_table_on_forward, NULL, "stock_mail-forward", E_CAL_POPUP_SELECT_ONE },
- { E_POPUP_ITEM, "a0.markonecomplete", N_("_Mark as Complete"), mark_as_complete_cb, NULL, NULL, E_CAL_POPUP_SELECT_ONE, E_CAL_POPUP_SELECT_EDITABLE },
- { E_POPUP_ITEM, "b0.markmanycomplete", N_("_Mark Selected Tasks as Complete"), mark_as_complete_cb, NULL, NULL, E_CAL_POPUP_SELECT_MANY, E_CAL_POPUP_SELECT_EDITABLE },
-
- { E_POPUP_BAR, "c0.bar" },
-
- { E_POPUP_ITEM, "d0.delete", N_("_Delete"), delete_cb, NULL, GTK_STOCK_DELETE, E_CAL_POPUP_SELECT_ONE, E_CAL_POPUP_SELECT_EDITABLE },
- { E_POPUP_ITEM, "e0.deletemany", N_("_Delete Selected Tasks"), delete_cb, NULL, GTK_STOCK_DELETE, E_CAL_POPUP_SELECT_MANY, E_CAL_POPUP_SELECT_EDITABLE },
-};
-
-static void
-ect_popup_free(EPopup *ep, GSList *items, void *data)
-{
- g_slist_free(items);
-}
-
-static gint
-e_calendar_table_show_popup_menu (ETable *table,
- GdkEvent *gdk_event,
- ECalendarTable *cal_table)
-{
- GtkMenu *menu;
- GSList *selection, *l, *menus = NULL;
- GPtrArray *events;
- ECalPopup *ep;
- ECalPopupTargetSelect *t;
- int i;
-
- selection = get_selected_objects (cal_table);
- if (!selection)
- return TRUE;
-
- /** @HookPoint-ECalPopup: Tasks Table Context Menu
- * @Id: org.gnome.evolution.tasks.table.popup
- * @Class: org.gnome.evolution.calendar.popup:1.0
- * @Target: ECalPopupTargetSelect
- *
- * The context menu on the tasks table.
- */
- ep = e_cal_popup_new("org.gnome.evolution.tasks.table.popup");
-
- events = g_ptr_array_new();
- for (l=selection;l;l=g_slist_next(l))
- g_ptr_array_add(events, e_cal_model_copy_component_data((ECalModelComponent *)l->data));
- g_slist_free(selection);
-
- t = e_cal_popup_target_new_select(ep, cal_table->model, events);
- t->target.widget = (GtkWidget *)cal_table;
-
- for (i=0;i<sizeof(tasks_popup_items)/sizeof(tasks_popup_items[0]);i++)
- menus = g_slist_prepend(menus, &tasks_popup_items[i]);
- e_popup_add_items((EPopup *)ep, menus, NULL, ect_popup_free, cal_table);
-
- menu = e_popup_create_menu_once((EPopup *)ep, (EPopupTarget *)t, 0);
-
- gtk_menu_popup(menu, NULL, NULL, NULL, NULL, gdk_event?gdk_event->button.button:0,
- gdk_event?gdk_event->button.time:gtk_get_current_event_time());
-
- return TRUE;
-}
-
-static gint
-e_calendar_table_on_right_click (ETable *table,
- gint row,
- gint col,
- GdkEvent *event,
- ECalendarTable *cal_table)
-{
- return e_calendar_table_show_popup_menu (table, event, cal_table);
-}
-
-static gboolean
-e_calendar_table_on_popup_menu (GtkWidget *widget, gpointer data)
-{
- ETable *table = E_TABLE(widget);
- g_return_val_if_fail(table, FALSE);
-
- return e_calendar_table_show_popup_menu (table, NULL,
- E_CALENDAR_TABLE(data));
-}
-
static gint
e_calendar_table_on_key_press (ETable *table,
gint row,
@@ -1256,7 +1305,7 @@ e_calendar_table_on_key_press (ETable *table,
ECalendarTable *cal_table)
{
if (event->keyval == GDK_Delete) {
- delete_cb (NULL, NULL, cal_table);
+ delete_cb (NULL, cal_table);
return TRUE;
} else if ((event->keyval == GDK_o)
&&(event->state & GDK_CONTROL_MASK)) {
diff --git a/calendar/gui/e-calendar-view.c b/calendar/gui/e-calendar-view.c
index 6c03060dda..169bac6131 100644
--- a/calendar/gui/e-calendar-view.c
+++ b/calendar/gui/e-calendar-view.c
@@ -21,10 +21,7 @@
* USA
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-#endif
-
#include <string.h>
#include <time.h>
#include <gtk/gtkimage.h>
@@ -32,6 +29,7 @@
#include <gdk/gdkkeysyms.h>
#include <gtk/gtkbindings.h>
#include <libgnome/gnome-i18n.h>
+#include <gal/util/e-util.h>
#include <e-util/e-dialog-utils.h>
#include <e-util/e-icon-factory.h>
#include "e-calendar-marshal.h"
@@ -58,7 +56,6 @@
#include "print.h"
#include "goto.h"
#include "ea-calendar.h"
-#include "e-cal-popup.h"
/* Used for the status bar messages */
#define EVOLUTION_CALENDAR_PROGRESS_IMAGE "stock_calendar"
@@ -75,14 +72,20 @@ struct _ECalendarViewPrivate {
EActivityHandler *activity_handler;
guint activity_id;
+ /* The popup menu */
+ EPopupMenu *view_menu;
+
/* The default category */
char *default_category;
};
+static void e_calendar_view_class_init (ECalendarViewClass *klass);
+static void e_calendar_view_init (ECalendarView *cal_view, ECalendarViewClass *klass);
static void e_calendar_view_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
static void e_calendar_view_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
static void e_calendar_view_destroy (GtkObject *object);
+static GObjectClass *parent_class = NULL;
static GdkAtom clipboard_atom = GDK_NONE;
extern ECompEditorRegistry *comp_editor_registry;
@@ -107,8 +110,6 @@ enum {
static guint e_calendar_view_signals[LAST_SIGNAL] = { 0 };
-G_DEFINE_TYPE (ECalendarView, e_calendar_view, GTK_TYPE_TABLE);
-
static void
e_calendar_view_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
{
@@ -155,6 +156,8 @@ e_calendar_view_class_init (ECalendarViewClass *klass)
GtkBindingSet *binding_set;
+ parent_class = g_type_class_peek_parent (klass);
+
/* Method override */
gobject_class->set_property = e_calendar_view_set_property;
gobject_class->get_property = e_calendar_view_get_property;
@@ -370,7 +373,7 @@ e_calendar_view_add_event (ECalendarView *cal_view, ECal *client, time_t dtstart
send_component_dialog ((GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (cal_view)),
client, comp, TRUE)) {
itip_send_comp (E_CAL_COMPONENT_METHOD_REQUEST, comp,
- client, NULL, NULL);
+ client, NULL);
}
} else {
g_message (G_STRLOC ": Could not create the object!");
@@ -380,7 +383,7 @@ e_calendar_view_add_event (ECalendarView *cal_view, ECal *client, time_t dtstart
}
static void
-e_calendar_view_init (ECalendarView *cal_view)
+e_calendar_view_init (ECalendarView *cal_view, ECalendarViewClass *klass)
{
cal_view->priv = g_new0 (ECalendarViewPrivate, 1);
@@ -412,10 +415,13 @@ e_calendar_view_destroy (GtkObject *object)
cal_view->priv = NULL;
}
- if (GTK_OBJECT_CLASS (e_calendar_view_parent_class)->destroy)
- GTK_OBJECT_CLASS (e_calendar_view_parent_class)->destroy (object);
+ if (GTK_OBJECT_CLASS (parent_class)->destroy)
+ GTK_OBJECT_CLASS (parent_class)->destroy (object);
}
+E_MAKE_TYPE (e_calendar_view, "ECalendarView", ECalendarView, e_calendar_view_class_init,
+ e_calendar_view_init, GTK_TYPE_TABLE);
+
GnomeCalendar *
e_calendar_view_get_calendar (ECalendarView *cal_view)
{
@@ -667,7 +673,7 @@ e_calendar_view_cut_clipboard (ECalendarView *cal_view)
&& cancel_component_dialog ((GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (cal_view)),
event->comp_data->client, comp, TRUE))
itip_send_comp (E_CAL_COMPONENT_METHOD_CANCEL, comp,
- event->comp_data->client, NULL, NULL);
+ event->comp_data->client, NULL);
e_cal_component_get_uid (comp, &uid);
e_cal_remove_object (event->comp_data->client, uid, &error);
@@ -823,14 +829,14 @@ delete_event (ECalendarView *cal_view, ECalendarViewEvent *event)
event->comp_data->client,
comp, TRUE))
itip_send_comp (E_CAL_COMPONENT_METHOD_CANCEL, comp,
- event->comp_data->client, NULL, NULL);
+ event->comp_data->client, NULL);
e_cal_component_get_uid (comp, &uid);
if (!uid || !*uid) {
g_object_unref (comp);
return;
}
-
+
e_cal_remove_object (event->comp_data->client, uid, &error);
delete_error_dialog (error, E_CAL_COMPONENT_EVENT);
g_clear_error (&error);
@@ -921,20 +927,8 @@ e_calendar_view_delete_selected_occurrence (ECalendarView *cal_view)
if (itip_organizer_is_user (comp, event->comp_data->client)
&& cancel_component_dialog ((GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (cal_view)),
event->comp_data->client,
- comp, TRUE)) {
- if (!e_cal_component_is_instance (comp)) {
- ECalComponentRange range;
-
- /* set the recurrence ID of the object we send */
- range.type = E_CAL_COMPONENT_RANGE_SINGLE;
- e_cal_component_get_dtstart (comp, &range.datetime);
- range.datetime.value->is_date = 1;
- e_cal_component_set_recurid (comp, &range);
-
- e_cal_component_free_datetime (&range.datetime);
- }
- itip_send_comp (E_CAL_COMPONENT_METHOD_CANCEL, comp, event->comp_data->client, NULL, NULL);
- }
+ comp, TRUE))
+ itip_send_comp (E_CAL_COMPONENT_METHOD_CANCEL, comp, event->comp_data->client, NULL);
e_cal_remove_object_with_mod (event->comp_data->client, uid, rid, CALOBJ_MOD_THIS, &error);
delete_error_dialog (error, E_CAL_COMPONENT_EVENT);
@@ -948,58 +942,57 @@ e_calendar_view_delete_selected_occurrence (ECalendarView *cal_view)
}
static void
-on_new_appointment (EPopup *ep, EPopupItem *pitem, void *data)
+on_new_appointment (GtkWidget *widget, gpointer user_data)
{
- ECalendarView *cal_view = data;
+ ECalendarView *cal_view = (ECalendarView *) user_data;
e_calendar_view_new_appointment (cal_view);
}
static void
-on_new_event (EPopup *ep, EPopupItem *pitem, void *data)
+on_new_event (GtkWidget *widget, gpointer user_data)
{
- ECalendarView *cal_view = data;
+ ECalendarView *cal_view = (ECalendarView *) user_data;
e_calendar_view_new_appointment_full (cal_view, TRUE, FALSE);
}
static void
-on_new_meeting (EPopup *ep, EPopupItem *pitem, void *data)
+on_new_meeting (GtkWidget *widget, gpointer user_data)
{
- ECalendarView *cal_view = data;
+ ECalendarView *cal_view = (ECalendarView *) user_data;
e_calendar_view_new_appointment_full (cal_view, FALSE, TRUE);
}
static void
-on_new_task (EPopup *ep, EPopupItem *pitem, void *data)
+on_new_task (GtkWidget *widget, gpointer user_data)
{
- ECalendarView *cal_view = data;
-
+ ECalendarView *cal_view = (ECalendarView *) user_data;
gnome_calendar_new_task (cal_view->priv->calendar);
}
static void
-on_goto_date (EPopup *ep, EPopupItem *pitem, void *data)
+on_goto_date (GtkWidget *widget, gpointer user_data)
{
- ECalendarView *cal_view = data;
+ ECalendarView *cal_view = E_CALENDAR_VIEW (user_data);
goto_dialog (cal_view->priv->calendar);
}
static void
-on_goto_today (EPopup *ep, EPopupItem *pitem, void *data)
+on_goto_today (GtkWidget *widget, gpointer user_data)
{
- ECalendarView *cal_view = data;
+ ECalendarView *cal_view = E_CALENDAR_VIEW (user_data);
calendar_goto_today (cal_view->priv->calendar);
}
static void
-on_edit_appointment (EPopup *ep, EPopupItem *pitem, void *data)
+on_edit_appointment (GtkWidget *widget, gpointer user_data)
{
- ECalendarView *cal_view = data;
GList *selected;
+ ECalendarView *cal_view = E_CALENDAR_VIEW (user_data);
selected = e_calendar_view_get_selected_events (cal_view);
if (selected) {
@@ -1007,21 +1000,22 @@ on_edit_appointment (EPopup *ep, EPopupItem *pitem, void *data)
if (event)
e_calendar_view_edit_appointment (cal_view, event->comp_data->client,
- event->comp_data->icalcomp,
- icalcomponent_get_first_property(event->comp_data->icalcomp, ICAL_ATTENDEE_PROPERTY));
+ event->comp_data->icalcomp, FALSE);
g_list_free (selected);
}
}
static void
-on_print (EPopup *ep, EPopupItem *pitem, void *data)
+on_print (GtkWidget *widget, gpointer user_data)
{
- ECalendarView *cal_view = data;
+ ECalendarView *cal_view;
time_t start, end;
GnomeCalendarViewType view_type;
PrintView print_view;
+ cal_view = E_CALENDAR_VIEW (user_data);
+
e_calendar_view_get_visible_time_range (cal_view, &start, &end);
view_type = gnome_calendar_get_view (cal_view->priv->calendar);
@@ -1048,15 +1042,17 @@ on_print (EPopup *ep, EPopupItem *pitem, void *data)
}
static void
-on_save_as (EPopup *ep, EPopupItem *pitem, void *data)
+on_save_as (GtkWidget *widget, gpointer user_data)
{
- ECalendarView *cal_view = data;
+ ECalendarView *cal_view;
GList *selected;
char *filename;
char *ical_string;
FILE *file;
ECalendarViewEvent *event;
+ cal_view = E_CALENDAR_VIEW (user_data);
+
selected = e_calendar_view_get_selected_events (cal_view);
if (!selected)
return;
@@ -1086,13 +1082,14 @@ on_save_as (EPopup *ep, EPopupItem *pitem, void *data)
}
static void
-on_print_event (EPopup *ep, EPopupItem *pitem, void *data)
+on_print_event (GtkWidget *widget, gpointer user_data)
{
- ECalendarView *cal_view = data;
+ ECalendarView *cal_view;
GList *selected;
ECalendarViewEvent *event;
ECalComponent *comp;
+ cal_view = E_CALENDAR_VIEW (user_data);
selected = e_calendar_view_get_selected_events (cal_view);
if (!selected)
return;
@@ -1114,23 +1111,22 @@ transfer_item_to (ECalendarViewEvent *event, ECal *dest_client, gboolean remove_
char *new_uid;
icalcomponent *orig_icalcomp;
icalproperty *icalprop;
-
+
uid = icalcomponent_get_uid (event->comp_data->icalcomp);
/* put the new object into the destination calendar */
if (e_cal_get_object (dest_client, uid, NULL, &orig_icalcomp, NULL)) {
icalcomponent_free (orig_icalcomp);
-
-
+
if (!e_cal_modify_object (dest_client, event->comp_data->icalcomp, CALOBJ_MOD_ALL, NULL))
return;
} else {
orig_icalcomp = icalcomponent_new_clone (event->comp_data->icalcomp);
-
+
icalprop = icalproperty_new_x ("1");
icalproperty_set_x_name (icalprop, "X-EVOLUTION-MOVE-CALENDAR");
icalcomponent_add_property (orig_icalcomp, icalprop);
-
+
if (!remove_item) {
/* change the UID to avoid problems with duplicated UIDs */
new_uid = e_cal_component_gen_uid ();
@@ -1198,26 +1194,26 @@ transfer_selected_items (ECalendarView *cal_view, gboolean remove_item)
}
static void
-on_copy_to (EPopup *ep, EPopupItem *pitem, void *data)
+on_copy_to (GtkWidget *widget, gpointer user_data)
{
- ECalendarView *cal_view = data;
+ ECalendarView *cal_view = E_CALENDAR_VIEW (user_data);
transfer_selected_items (cal_view, FALSE);
}
static void
-on_move_to (EPopup *ep, EPopupItem *pitem, void *data)
+on_move_to (GtkWidget *widget, gpointer user_data)
{
- ECalendarView *cal_view = data;
+ ECalendarView *cal_view = E_CALENDAR_VIEW (user_data);
transfer_selected_items (cal_view, TRUE);
}
static void
-on_meeting (EPopup *ep, EPopupItem *pitem, void *data)
+on_meeting (GtkWidget *widget, gpointer user_data)
{
- ECalendarView *cal_view = data;
GList *selected;
+ ECalendarView *cal_view = E_CALENDAR_VIEW (user_data);
selected = e_calendar_view_get_selected_events (cal_view);
if (selected) {
@@ -1229,10 +1225,10 @@ on_meeting (EPopup *ep, EPopupItem *pitem, void *data)
}
static void
-on_forward (EPopup *ep, EPopupItem *pitem, void *data)
+on_forward (GtkWidget *widget, gpointer user_data)
{
- ECalendarView *cal_view = data;
GList *selected;
+ ECalendarView *cal_view = E_CALENDAR_VIEW (user_data);
selected = e_calendar_view_get_selected_events (cal_view);
if (selected) {
@@ -1241,7 +1237,7 @@ on_forward (EPopup *ep, EPopupItem *pitem, void *data)
comp = e_cal_component_new ();
e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (event->comp_data->icalcomp));
- itip_send_comp (E_CAL_COMPONENT_METHOD_PUBLISH, comp, event->comp_data->client, NULL, NULL);
+ itip_send_comp (E_CAL_COMPONENT_METHOD_PUBLISH, comp, event->comp_data->client, NULL);
g_list_free (selected);
g_object_unref (comp);
@@ -1249,37 +1245,38 @@ on_forward (EPopup *ep, EPopupItem *pitem, void *data)
}
static void
-on_publish (EPopup *ep, EPopupItem *pitem, void *data)
+on_publish (GtkWidget *widget, gpointer user_data)
{
e_pub_publish (TRUE);
}
static void
-on_delete_appointment (EPopup *ep, EPopupItem *pitem, void *data)
+on_delete_appointment (GtkWidget *widget, gpointer user_data)
{
- ECalendarView *cal_view = data;
+ ECalendarView *cal_view;
+ cal_view = E_CALENDAR_VIEW (user_data);
e_calendar_view_delete_selected_event (cal_view);
}
static void
-on_unrecur_appointment (EPopup *ep, EPopupItem *pitem, void *data)
+on_unrecur_appointment (GtkWidget *widget, gpointer user_data)
{
- ECalendarView *cal_view = data;
+ ECalendarView *cal_view;
ECalendarViewEvent *event;
ECalComponent *comp, *new_comp;
ECalComponentDateTime date;
struct icaltimetype itt;
GList *selected;
- ECal *client;
char *new_uid;
+ cal_view = E_CALENDAR_VIEW (user_data);
+
selected = e_calendar_view_get_selected_events (cal_view);
if (!selected)
return;
event = (ECalendarViewEvent *) selected->data;
- client = g_object_ref (event->comp_data->client);
date.value = &itt;
date.tzid = NULL;
@@ -1319,165 +1316,281 @@ on_unrecur_appointment (EPopup *ep, EPopupItem *pitem, void *data)
/* Now update both ECalComponents. Note that we do this last since at
* present the updates happen synchronously so our event may disappear.
*/
- if (!e_cal_modify_object (client, e_cal_component_get_icalcomponent (comp), CALOBJ_MOD_THIS, NULL))
- g_message ("on_unrecur_appointment(): Could not update the object!");
+ if (!e_cal_modify_object (event->comp_data->client, e_cal_component_get_icalcomponent (comp), CALOBJ_MOD_THIS, NULL))
+ g_message ("e_day_view_on_unrecur_appointment(): Could not update the object!");
g_object_unref (comp);
- if (!e_cal_create_object (client, e_cal_component_get_icalcomponent (new_comp), &new_uid, NULL))
- g_message ("on_unrecur_appointment(): Could not update the object!");
+ if (!e_cal_create_object (event->comp_data->client, e_cal_component_get_icalcomponent (new_comp), &new_uid, NULL))
+ g_message ("e_day_view_on_unrecur_appointment(): Could not update the object!");
else
g_free (new_uid);
g_object_unref (new_comp);
- g_object_unref (client);
g_list_free (selected);
}
static void
-on_delete_occurrence (EPopup *ep, EPopupItem *pitem, void *data)
+on_delete_occurrence (GtkWidget *widget, gpointer user_data)
{
- ECalendarView *cal_view = data;
+ ECalendarView *cal_view;
+ cal_view = E_CALENDAR_VIEW (user_data);
e_calendar_view_delete_selected_occurrence (cal_view);
}
static void
-on_cut (EPopup *ep, EPopupItem *pitem, void *data)
+on_cut (GtkWidget *widget, gpointer user_data)
{
- ECalendarView *cal_view = data;
+ ECalendarView *cal_view = E_CALENDAR_VIEW (user_data);
e_calendar_view_cut_clipboard (cal_view);
}
static void
-on_copy (EPopup *ep, EPopupItem *pitem, void *data)
+on_copy (GtkWidget *widget, gpointer user_data)
{
- ECalendarView *cal_view = data;
+ ECalendarView *cal_view = E_CALENDAR_VIEW (user_data);
e_calendar_view_copy_clipboard (cal_view);
}
static void
-on_paste (EPopup *ep, EPopupItem *pitem, void *data)
+on_paste (GtkWidget *widget, gpointer user_data)
{
- ECalendarView *cal_view = data;
+ ECalendarView *cal_view = E_CALENDAR_VIEW (user_data);
e_calendar_view_paste_clipboard (cal_view);
}
-static EPopupItem ecv_main_items [] = {
- { E_POPUP_ITEM, "00.new", N_("New _Appointment..."), on_new_appointment, NULL, "stock_new-appointment", 0, 0 },
- { E_POPUP_ITEM, "10.newallday", N_("New All Day _Event"), on_new_event, NULL, "stock_new-24h-appointment", 0, 0},
- { E_POPUP_ITEM, "20.meeting", N_("New Meeting"), on_new_meeting, NULL, "stock_new-meeting", 0, 0},
- { E_POPUP_ITEM, "30.task", N_("New Task"), on_new_task, NULL, "stock_task", 0, 0},
+enum {
+ /*
+ * This is used to "flag" events that can not be editted
+ */
+ MASK_EDITABLE = 1,
- { E_POPUP_BAR, "40."},
- { E_POPUP_ITEM, "40.print", N_("_Print..."), on_print, NULL, GTK_STOCK_PRINT, 0, 0 },
+ /*
+ * To disable recurring actions to be displayed
+ */
+ MASK_RECURRING = 2,
- { E_POPUP_BAR, "50." },
- { E_POPUP_ITEM, "50.paste", N_("_Paste"), on_paste, NULL, GTK_STOCK_PASTE, 0, E_CAL_POPUP_SELECT_EDITABLE },
+ /*
+ * To disable actions for non-recurring items to be displayed
+ */
+ MASK_SINGLE = 4,
+
+ /*
+ * This is used to when an event is currently being edited
+ * in another window and we want to disable the event
+ * from being edited twice
+ */
+ MASK_EDITING = 8,
+
+ /*
+ * This is used to when an event is already a meeting and
+ * we want to disable the schedule meeting command
+ */
+ MASK_MEETING = 16,
+
+ /*
+ * To disable cut and copy for meetings the user is not the
+ * organizer of
+ */
+ MASK_MEETING_ORGANIZER = 32,
+
+ /*
+ * To disable things not valid for instances
+ */
+ MASK_INSTANCE = 64
+};
- { E_POPUP_BAR, "60." },
- /* FIXME: hook in this somehow */
- { E_POPUP_SUBMENU, "60.view", N_("Current View") },
+static EPopupMenu main_items [] = {
+ E_POPUP_ITEM (N_("New _Appointment..."), GTK_SIGNAL_FUNC (on_new_appointment), 0),
+ E_POPUP_ITEM (N_("New All Day _Event"), GTK_SIGNAL_FUNC (on_new_event), 0),
+ E_POPUP_ITEM (N_("New Meeting"), GTK_SIGNAL_FUNC (on_new_meeting), 0),
+ E_POPUP_ITEM (N_("New Task"), GTK_SIGNAL_FUNC (on_new_task), 0),
+
+ E_POPUP_SEPARATOR,
+
+ E_POPUP_ITEM (N_("_Print..."), GTK_SIGNAL_FUNC (on_print), 0),
+
+ E_POPUP_SEPARATOR,
+
+ E_POPUP_ITEM (N_("_Paste"), GTK_SIGNAL_FUNC (on_paste), MASK_EDITABLE),
+
+ E_POPUP_SEPARATOR,
+
+ E_POPUP_SUBMENU (N_("Current View"), NULL, 0),
- { E_POPUP_ITEM, "61.today", N_("Select _Today"), on_goto_today, NULL, GTK_STOCK_HOME },
- { E_POPUP_ITEM, "62.todate", N_("_Select Date..."), on_goto_date, NULL, GTK_STOCK_JUMP_TO },
+ E_POPUP_ITEM (N_("Select _Today"), GTK_SIGNAL_FUNC (on_goto_today), 0),
+ E_POPUP_ITEM (N_("_Select Date..."), GTK_SIGNAL_FUNC (on_goto_date), 0),
- { E_POPUP_BAR, "70." },
+ E_POPUP_SEPARATOR,
- /* TODO: Why is this in a context menu when it applies globally? */
- { E_POPUP_ITEM, "70.publish", N_("_Publish Free/Busy Information"), on_publish, },
+ E_POPUP_ITEM (N_("_Publish Free/Busy Information"), GTK_SIGNAL_FUNC (on_publish), 0),
+
+ E_POPUP_TERMINATOR
};
-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_("_Print..."), on_print_event, NULL, GTK_STOCK_PRINT, 0, E_CAL_POPUP_SELECT_NOTEDITING },
+static EPopupMenu child_items [] = {
+ E_POPUP_ITEM (N_("_Open"), GTK_SIGNAL_FUNC (on_edit_appointment), MASK_EDITING),
+ E_POPUP_ITEM (N_("_Save As..."), GTK_SIGNAL_FUNC (on_save_as), MASK_EDITING),
+ E_POPUP_ITEM (N_("_Print..."), GTK_SIGNAL_FUNC (on_print_event), MASK_EDITING),
+
+ /* Only show this separator if one of the above is shown. */
+ E_POPUP_SEPARATOR,
- { E_POPUP_BAR, "30." },
+ E_POPUP_ITEM (N_("C_ut"), GTK_SIGNAL_FUNC (on_cut), MASK_EDITING | MASK_EDITABLE | MASK_MEETING_ORGANIZER),
+ E_POPUP_ITEM (N_("_Copy"), GTK_SIGNAL_FUNC (on_copy), MASK_EDITING | MASK_MEETING_ORGANIZER),
+ E_POPUP_ITEM (N_("_Paste"), GTK_SIGNAL_FUNC (on_paste), MASK_EDITABLE),
- { 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_SEPARATOR,
- { E_POPUP_BAR, "40." },
+ E_POPUP_ITEM (N_("Cop_y to Calendar..."), GTK_SIGNAL_FUNC (on_copy_to), MASK_EDITING),
+ E_POPUP_ITEM (N_("Mo_ve to Calendar..."), GTK_SIGNAL_FUNC (on_move_to), MASK_EDITING | MASK_EDITABLE),
+ E_POPUP_ITEM (N_("_Schedule Meeting..."), GTK_SIGNAL_FUNC (on_meeting), MASK_EDITABLE | MASK_EDITING | MASK_MEETING),
+ E_POPUP_ITEM (N_("_Forward as iCalendar..."), GTK_SIGNAL_FUNC (on_forward), MASK_EDITING),
- { E_POPUP_ITEM, "41.copyto", N_("Cop_y to Calendar..."), on_copy_to, NULL, NULL, 0, E_CAL_POPUP_SELECT_NOTEDITING },
- { E_POPUP_ITEM, "42.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, "43.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, "44.forward", N_("_Forward as iCalendar..."), on_forward, NULL, "stock_mail-forward", 0, E_CAL_POPUP_SELECT_NOTEDITING },
+ E_POPUP_SEPARATOR,
- { E_POPUP_BAR, "50." },
+ E_POPUP_ITEM (N_("_Delete"), GTK_SIGNAL_FUNC (on_delete_appointment), MASK_EDITABLE | MASK_SINGLE | MASK_EDITING),
+ E_POPUP_ITEM (N_("Make this Occurrence _Movable"), GTK_SIGNAL_FUNC (on_unrecur_appointment), MASK_EDITABLE | MASK_RECURRING | MASK_EDITING | MASK_INSTANCE),
+ E_POPUP_ITEM (N_("Delete this _Occurrence"), GTK_SIGNAL_FUNC (on_delete_occurrence), MASK_RECURRING | MASK_EDITING | MASK_EDITABLE),
+ E_POPUP_ITEM (N_("Delete _All Occurrences"), GTK_SIGNAL_FUNC (on_delete_appointment), MASK_RECURRING | MASK_EDITING | MASK_EDITABLE),
- { 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_TERMINATOR
};
static void
-ecv_popup_free (EPopup *ep, GSList *list, void *data)
+free_view_popup (GtkWidget *widget, gpointer data)
{
- g_slist_free(list);
+ ECalendarView *cal_view = E_CALENDAR_VIEW (data);
+
+ if (cal_view->priv->view_menu == NULL)
+ return;
+
+ gnome_calendar_discard_view_popup (cal_view->priv->calendar, cal_view->priv->view_menu);
+ cal_view->priv->view_menu = NULL;
+}
+
+static void
+setup_popup_icons (EPopupMenu *context_menu)
+{
+ gint i;
+
+ for (i = 0; context_menu[i].name; i++) {
+ GtkWidget *pixmap_widget = NULL;
+ GdkPixbuf *pixbuf;
+
+ if (!strcmp (context_menu[i].name, _("_Copy")))
+ pixmap_widget = gtk_image_new_from_stock (GTK_STOCK_COPY, GTK_ICON_SIZE_MENU);
+ else if (!strcmp (context_menu[i].name, _("C_ut")))
+ pixmap_widget = gtk_image_new_from_stock (GTK_STOCK_CUT, GTK_ICON_SIZE_MENU);
+ else if (!strcmp (context_menu[i].name, _("_Delete")) ||
+ !strcmp (context_menu[i].name, _("Delete this _Occurrence")) ||
+ !strcmp (context_menu[i].name, _("Delete _All Occurrences")))
+ pixmap_widget = gtk_image_new_from_stock (GTK_STOCK_DELETE, GTK_ICON_SIZE_MENU);
+ else if (!strcmp (context_menu[i].name, _("Go to _Today")))
+ pixmap_widget = gtk_image_new_from_stock (GTK_STOCK_HOME, GTK_ICON_SIZE_MENU);
+ else if (!strcmp (context_menu[i].name, _("_Go to Date...")))
+ pixmap_widget = gtk_image_new_from_stock (GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_MENU);
+ else if (!strcmp (context_menu[i].name, _("New _Appointment..."))) {
+ pixbuf = e_icon_factory_get_icon ("stock_new-appointment", E_ICON_SIZE_MENU);
+ pixmap_widget = gtk_image_new_from_pixbuf (pixbuf);
+ gdk_pixbuf_unref (pixbuf);
+ }
+ else if (!strcmp (context_menu[i].name, _("New All Day _Event"))) {
+ pixbuf = e_icon_factory_get_icon ("stock_new-24h-appointment", E_ICON_SIZE_MENU);
+ pixmap_widget = gtk_image_new_from_pixbuf (pixbuf);
+ gdk_pixbuf_unref (pixbuf);
+ }
+ else if (!strcmp (context_menu[i].name, _("New Meeting"))) {
+ pixbuf = e_icon_factory_get_icon ("stock_new-meeting", E_ICON_SIZE_MENU);
+ pixmap_widget = gtk_image_new_from_pixbuf (pixbuf);
+ gdk_pixbuf_unref (pixbuf);
+ }
+ else if (!strcmp (context_menu[i].name, _("New Task"))) {
+ pixbuf = e_icon_factory_get_icon ("stock_task", E_ICON_SIZE_MENU);
+ pixmap_widget = gtk_image_new_from_pixbuf (pixbuf);
+ gdk_pixbuf_unref (pixbuf);
+ }
+ else if (!strcmp (context_menu[i].name, _("_Open")))
+ pixmap_widget = gtk_image_new_from_stock (GTK_STOCK_OPEN, GTK_ICON_SIZE_MENU);
+ else if (!strcmp (context_menu[i].name, _("_Paste")))
+ pixmap_widget = gtk_image_new_from_stock (GTK_STOCK_PASTE, GTK_ICON_SIZE_MENU);
+ else if (!strcmp (context_menu[i].name, _("_Print...")))
+ pixmap_widget = gtk_image_new_from_stock (GTK_STOCK_PRINT, GTK_ICON_SIZE_MENU);
+ else if (!strcmp (context_menu[i].name, _("_Save As...")))
+ pixmap_widget = gtk_image_new_from_stock (GTK_STOCK_SAVE_AS, GTK_ICON_SIZE_MENU);
+ else if (!strcmp (context_menu[i].name, _("_Settings...")))
+ pixmap_widget = gtk_image_new_from_stock (GTK_STOCK_PREFERENCES, GTK_ICON_SIZE_MENU);
+
+ if (pixmap_widget)
+ gtk_widget_show (pixmap_widget);
+ context_menu[i].pixmap_widget = pixmap_widget;
+ }
}
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;
-
+ GList *selected;
+ EPopupMenu *context_menu;
+ guint32 disable_mask = 0, hide_mask = 0;
+ GtkMenu *popup;
+ ECal *client = NULL;
+ gboolean read_only = TRUE;
+
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");
+ /* get the selection */
+ selected = e_calendar_view_get_selected_events (cal_view);
- 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 (selected == NULL) {
+ cal_view->priv->view_menu = gnome_calendar_setup_view_popup (cal_view->priv->calendar);
+ main_items[9].submenu = cal_view->priv->view_menu;
+ context_menu = main_items;
- if (event)
- g_ptr_array_add(events, e_cal_model_copy_component_data(event->comp_data));
- }
- g_list_free(selected);
+ client = e_cal_model_get_default_client (cal_view->priv->model);
+ } else {
+ ECalendarViewEvent *event;
- t = e_cal_popup_target_new_select(ep, model, events);
- t->target.widget = (GtkWidget *)cal_view;
+ context_menu = child_items;
- 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]);
+ event = (ECalendarViewEvent *) selected->data;
+ if (e_cal_util_component_has_recurrences (event->comp_data->icalcomp))
+ hide_mask |= MASK_SINGLE;
+ else
+ hide_mask |= MASK_RECURRING;
- 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]);
+ if (e_cal_util_component_is_instance (event->comp_data->icalcomp))
+ hide_mask |= MASK_INSTANCE;
+
+ if (e_cal_util_component_has_organizer (event->comp_data->icalcomp)) {
+ ECalComponent *comp;
+
+ disable_mask |= MASK_MEETING;
+
+ comp = e_cal_component_new ();
+ e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (event->comp_data->icalcomp));
+ if (!itip_organizer_is_user (comp, event->comp_data->client))
+ disable_mask |= MASK_MEETING_ORGANIZER;
+
+ g_object_unref (comp);
+ }
+
+ client = event->comp_data->client;
}
- e_popup_add_items((EPopup *)ep, menus, NULL, ecv_popup_free, cal_view);
+ e_cal_is_read_only (client, &read_only, NULL);
+ if (read_only)
+ disable_mask |= MASK_EDITABLE;
+
+ setup_popup_icons (context_menu);
+ popup = e_popup_menu_create (context_menu, disable_mask, hide_mask, cal_view);
+ g_signal_connect (popup, "selection-done", G_CALLBACK (free_view_popup), cal_view);
- return e_popup_create_menu_once((EPopup *)ep, (EPopupTarget *)t, 0);
+ return popup;
}
void
@@ -1640,7 +1753,7 @@ e_calendar_view_edit_appointment (ECalendarView *cal_view,
if (!ce) {
EventEditor *ee;
- ee = event_editor_new (client, meeting);
+ ee = event_editor_new (client);
ce = COMP_EDITOR (ee);
comp = e_cal_component_new ();
@@ -1667,7 +1780,7 @@ e_calendar_view_modify_and_send (ECalComponent *comp,
if (e_cal_modify_object (client, e_cal_component_get_icalcomponent (comp), mod, NULL)) {
if (itip_organizer_is_user (comp, client) &&
send_component_dialog (toplevel, client, comp, new))
- itip_send_comp (E_CAL_COMPONENT_METHOD_REQUEST, comp, client, NULL, NULL);
+ itip_send_comp (E_CAL_COMPONENT_METHOD_REQUEST, comp, client, NULL);
} else {
g_message (G_STRLOC ": Could not update the object!");
}
diff --git a/calendar/gui/e-day-view-config.c b/calendar/gui/e-day-view-config.c
index 50d4d8eeea..6fa8bd2081 100644
--- a/calendar/gui/e-day-view-config.c
+++ b/calendar/gui/e-day-view-config.c
@@ -30,14 +30,14 @@ struct _EDayViewConfigPrivate {
GList *notifications;
};
+static GObjectClass *parent_class = NULL;
+
/* Property IDs */
enum props {
PROP_0,
PROP_VIEW,
};
-G_DEFINE_TYPE (EDayViewConfig, e_day_view_config, G_TYPE_OBJECT);
-
static void
e_day_view_config_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
{
@@ -86,8 +86,8 @@ e_day_view_config_dispose (GObject *object)
e_day_view_config_set_view (view_config, NULL);
- if (G_OBJECT_CLASS (e_day_view_config_parent_class)->dispose)
- G_OBJECT_CLASS (e_day_view_config_parent_class)->dispose (object);
+ if (G_OBJECT_CLASS (parent_class)->dispose)
+ G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void
@@ -100,8 +100,8 @@ e_day_view_config_finalize (GObject *object)
g_free (priv);
- if (G_OBJECT_CLASS (e_day_view_config_parent_class)->finalize)
- G_OBJECT_CLASS (e_day_view_config_parent_class)->finalize (object);
+ if (G_OBJECT_CLASS (parent_class)->finalize)
+ G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
@@ -110,6 +110,8 @@ e_day_view_config_class_init (EDayViewConfigClass *klass)
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GParamSpec *spec;
+ parent_class = g_type_class_peek_parent (klass);
+
/* Method override */
gobject_class->set_property = e_day_view_config_set_property;
gobject_class->get_property = e_day_view_config_get_property;
@@ -122,12 +124,15 @@ e_day_view_config_class_init (EDayViewConfigClass *klass)
}
static void
-e_day_view_config_init (EDayViewConfig *view_config)
+e_day_view_config_init (EDayViewConfig *view_config, EDayViewConfigClass *klass)
{
view_config->priv = g_new0 (EDayViewConfigPrivate, 1);
}
+E_MAKE_TYPE (e_day_view_config, "EDayViewConfig", EDayViewConfig, e_day_view_config_class_init,
+ e_day_view_config_init, G_TYPE_OBJECT);
+
EDayViewConfig *
e_day_view_config_new (EDayView *day_view)
{
diff --git a/calendar/gui/e-day-view.c b/calendar/gui/e-day-view.c
index 73b57432cf..68b0abcdab 100644
--- a/calendar/gui/e-day-view.c
+++ b/calendar/gui/e-day-view.c
@@ -47,6 +47,7 @@
#include <gal/widgets/e-popup-menu.h>
#include <gal/widgets/e-gui-utils.h>
#include <gal/widgets/e-unicode.h>
+#include <gal/util/e-util.h>
#include <libgnomecanvas/gnome-canvas-rect-ellipse.h>
#include <libgnome/gnome-i18n.h>
#include <libgnome/gnome-exec.h>
@@ -121,9 +122,10 @@ static GtkTargetEntry target_table[] = {
};
static guint n_targets = sizeof(target_table) / sizeof(target_table[0]);
+static void e_day_view_class_init (EDayViewClass *class);
+static void e_day_view_init (EDayView *day_view);
static void e_day_view_destroy (GtkObject *object);
static void e_day_view_realize (GtkWidget *widget);
-static void e_day_view_set_colors(EDayView *day_view, GtkWidget *widget);
static void e_day_view_unrealize (GtkWidget *widget);
static void e_day_view_style_set (GtkWidget *widget,
GtkStyle *previous_style);
@@ -285,9 +287,7 @@ static ECalendarViewPosition e_day_view_convert_position_in_main_canvas (EDayVie
gint *row_return,
gint *event_num_return);
static gboolean e_day_view_find_event_from_uid (EDayView *day_view,
- ECal *client,
const gchar *uid,
- const gchar *rid,
gint *day_return,
gint *event_num_return);
@@ -441,7 +441,10 @@ static void e_day_view_queue_layout (EDayView *day_view);
static void e_day_view_cancel_layout (EDayView *day_view);
static gboolean e_day_view_layout_timeout_cb (gpointer data);
-G_DEFINE_TYPE (EDayView, e_day_view, E_TYPE_CALENDAR_VIEW);
+static GtkTableClass *parent_class;
+
+E_MAKE_TYPE (e_day_view, "EDayView", EDayView, e_day_view_class_init,
+ e_day_view_init, e_calendar_view_get_type ());
static void
e_day_view_class_init (EDayViewClass *class)
@@ -450,6 +453,7 @@ e_day_view_class_init (EDayViewClass *class)
GtkWidgetClass *widget_class;
ECalendarViewClass *view_class;
+ parent_class = g_type_class_peek_parent (class);
object_class = (GtkObjectClass *) class;
widget_class = (GtkWidgetClass *) class;
view_class = (ECalendarViewClass *) class;
@@ -509,7 +513,7 @@ process_component (EDayView *day_view, ECalModelComponent *comp_data)
{
EDayViewEvent *event;
gint day, event_num;
- const char *uid, *rid;
+ const char *uid;
ECalComponent *comp;
AddEventData add_event_data;
@@ -526,20 +530,65 @@ process_component (EDayView *day_view, ECalModelComponent *comp_data)
}
e_cal_component_get_uid (comp, &uid);
- if (e_cal_component_is_instance (comp))
- rid = e_cal_component_get_recurid_as_string (comp);
- else
- rid = NULL;
- /* Add the object */
+ /* If the event already exists and the dates didn't change, we can
+ update the event fairly easily without changing the events arrays
+ or computing a new layout. */
+ if (e_day_view_find_event_from_uid (day_view, uid, &day, &event_num)) {
+ ECalComponent *tmp_comp;
+
+ if (day == E_DAY_VIEW_LONG_EVENT)
+ event = &g_array_index (day_view->long_events,
+ EDayViewEvent, event_num);
+ else
+ event = &g_array_index (day_view->events[day],
+ EDayViewEvent, event_num);
+
+ tmp_comp = e_cal_component_new ();
+ e_cal_component_set_icalcomponent (tmp_comp, icalcomponent_new_clone (event->comp_data->icalcomp));
+ if (!e_cal_util_component_has_recurrences (comp_data->icalcomp)
+ && !e_cal_component_has_recurrences (tmp_comp)
+ && e_cal_component_event_dates_match (comp, tmp_comp)) {
+#if 0
+ g_print ("updated object's dates unchanged\n");
+#endif
+ e_day_view_foreach_event_with_uid (day_view, uid, e_day_view_update_event_cb, comp_data);
+ gtk_widget_queue_draw (day_view->top_canvas);
+ gtk_widget_queue_draw (day_view->main_canvas);
+ return;
+ }
+
+ /* The dates have changed, so we need to remove the
+ old occurrrences before adding the new ones. */
+#if 0
+ g_print ("dates changed - removing occurrences\n");
+#endif
+ e_day_view_foreach_event_with_uid (day_view, uid,
+ e_day_view_remove_event_cb,
+ NULL);
+
+ g_object_unref (tmp_comp);
+ }
+
+ /* Add the occurrences of the event */
add_event_data.day_view = day_view;
add_event_data.comp_data = comp_data;
- e_day_view_add_event (comp, comp_data->instance_start, comp_data->instance_end, &add_event_data);
+ e_cal_generate_instances_for_object (comp_data->client, comp_data->icalcomp, day_view->lower,
+ day_view->upper,
+ e_day_view_add_event, &add_event_data);
g_object_unref (comp);
}
static void
+model_changed_cb (ETableModel *etm, gpointer user_data)
+{
+ EDayView *day_view = E_DAY_VIEW (user_data);
+
+ e_day_view_update_query (day_view);
+}
+
+static void
update_row (EDayView *day_view, int row)
{
ECalModelComponent *comp_data;
@@ -597,35 +646,55 @@ model_rows_inserted_cb (ETableModel *etm, int row, int count, gpointer user_data
}
+static gboolean
+row_deleted_check_cb (EDayView *day_view, gint day, gint event_num, gpointer data)
+{
+ GHashTable *uids = data;
+ EDayViewEvent *event;
+ ECalModel *model;
+ const char *uid;
+
+ if (day == E_DAY_VIEW_LONG_EVENT) {
+ event = &g_array_index (day_view->long_events, EDayViewEvent,
+ event_num);
+ } else {
+ event = &g_array_index (day_view->events[day], EDayViewEvent,
+ event_num);
+ }
+
+ uid = icalcomponent_get_uid (event->comp_data->icalcomp);
+ model = e_calendar_view_get_model (E_CALENDAR_VIEW (day_view));
+
+ if (!e_cal_model_get_component_for_uid (model, uid))
+ g_hash_table_insert (uids, g_strdup(uid), GINT_TO_POINTER (1));
+
+ return TRUE;
+}
+
+static void
+remove_uid_cb (gpointer key, gpointer value, gpointer data)
+{
+ EDayView *day_view = data;
+ char *uid = key;
+
+ e_day_view_foreach_event_with_uid (day_view, uid, e_day_view_remove_event_cb, NULL);
+ g_free(uid);
+}
+
static void
model_rows_deleted_cb (ETableModel *etm, int row, int count, gpointer user_data)
{
EDayView *day_view = E_DAY_VIEW (user_data);
- int i;
+ GHashTable *uids;
e_day_view_stop_editing_event (day_view);
- for (i = row + count; i > row; i--) {
- gint day, event_num;
- const char *uid, *rid = NULL;
- ECalModelComponent *comp_data;
-
- comp_data = e_cal_model_get_component_at (E_CAL_MODEL (etm), i - 1);
- if (!comp_data)
- continue;
-
- uid = icalcomponent_get_uid (comp_data->icalcomp);
- if (e_cal_util_component_is_instance (comp_data->icalcomp)) {
- icalproperty *prop;
-
- prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_RECURRENCEID_PROPERTY);
- if (prop)
- rid = icaltime_as_ical_string (icalcomponent_get_recurrenceid (comp_data->icalcomp));
- }
+ uids = g_hash_table_new (g_str_hash, g_str_equal);
+
+ e_day_view_foreach_event (day_view, row_deleted_check_cb, uids);
+ g_hash_table_foreach (uids, remove_uid_cb, day_view);
- if (e_day_view_find_event_from_uid (day_view, comp_data->client, uid, rid, &day, &event_num))
- e_day_view_remove_event_cb (day_view, day, event_num, NULL);
- }
+ g_hash_table_destroy (uids);
gtk_widget_queue_draw (day_view->top_canvas);
gtk_widget_queue_draw (day_view->main_canvas);
@@ -977,6 +1046,8 @@ e_day_view_init (EDayView *day_view)
/* connect to ECalModel's signals */
g_signal_connect (G_OBJECT (model), "time_range_changed",
G_CALLBACK (time_range_changed_cb), day_view);
+ g_signal_connect (G_OBJECT (model), "model_changed",
+ G_CALLBACK (model_changed_cb), day_view);
g_signal_connect (G_OBJECT (model), "model_row_changed",
G_CALLBACK (model_row_changed_cb), day_view);
g_signal_connect (G_OBJECT (model), "model_cell_changed",
@@ -1015,7 +1086,6 @@ e_day_view_new (void)
GObject *day_view;
day_view = g_object_new (e_day_view_get_type (), NULL);
- e_cal_model_set_flags (e_calendar_view_get_model (E_CALENDAR_VIEW (day_view)), E_CAL_MODEL_FLAGS_EXPAND_RECURRENCES);
return GTK_WIDGET (day_view);
}
@@ -1067,7 +1137,7 @@ e_day_view_destroy (GtkObject *object)
}
}
- GTK_OBJECT_CLASS (e_day_view_parent_class)->destroy (object);
+ GTK_OBJECT_CLASS (parent_class)->destroy (object);
}
@@ -1079,8 +1149,8 @@ e_day_view_realize (GtkWidget *widget)
gboolean success[E_DAY_VIEW_COLOR_LAST];
gint nfailed;
- if (GTK_WIDGET_CLASS (e_day_view_parent_class)->realize)
- (*GTK_WIDGET_CLASS (e_day_view_parent_class)->realize)(widget);
+ if (GTK_WIDGET_CLASS (parent_class)->realize)
+ (*GTK_WIDGET_CLASS (parent_class)->realize)(widget);
day_view = E_DAY_VIEW (widget);
day_view->main_gc = gdk_gc_new (widget->window);
@@ -1088,9 +1158,64 @@ e_day_view_realize (GtkWidget *widget)
colormap = gtk_widget_get_colormap (widget);
/* Allocate the colors. */
-
- e_day_view_set_colors(day_view, widget);
-
+ day_view->colors[E_DAY_VIEW_COLOR_BG_WORKING].red = 247 * 257;
+ day_view->colors[E_DAY_VIEW_COLOR_BG_WORKING].green = 247 * 257;
+ day_view->colors[E_DAY_VIEW_COLOR_BG_WORKING].blue = 244 * 257;
+
+ day_view->colors[E_DAY_VIEW_COLOR_BG_NOT_WORKING].red = 216 * 257;
+ day_view->colors[E_DAY_VIEW_COLOR_BG_NOT_WORKING].green = 216 * 257;
+ day_view->colors[E_DAY_VIEW_COLOR_BG_NOT_WORKING].blue = 214 * 257;
+
+ day_view->colors[E_DAY_VIEW_COLOR_BG_SELECTED].red = 0 * 257;
+ day_view->colors[E_DAY_VIEW_COLOR_BG_SELECTED].green = 0 * 257;
+ day_view->colors[E_DAY_VIEW_COLOR_BG_SELECTED].blue = 156 * 257;
+
+ day_view->colors[E_DAY_VIEW_COLOR_BG_SELECTED_UNFOCUSSED].red = 16 * 257;
+ day_view->colors[E_DAY_VIEW_COLOR_BG_SELECTED_UNFOCUSSED].green = 78 * 257;
+ day_view->colors[E_DAY_VIEW_COLOR_BG_SELECTED_UNFOCUSSED].blue = 139 * 257;
+
+ day_view->colors[E_DAY_VIEW_COLOR_BG_GRID].red = 0x8000;
+ day_view->colors[E_DAY_VIEW_COLOR_BG_GRID].green = 0x8000;
+ day_view->colors[E_DAY_VIEW_COLOR_BG_GRID].blue = 0x8000;
+
+ day_view->colors[E_DAY_VIEW_COLOR_BG_TOP_CANVAS].red = 0x8000;
+ day_view->colors[E_DAY_VIEW_COLOR_BG_TOP_CANVAS].green = 0x8000;
+ day_view->colors[E_DAY_VIEW_COLOR_BG_TOP_CANVAS].blue = 0x8000;
+
+ day_view->colors[E_DAY_VIEW_COLOR_BG_TOP_CANVAS_SELECTED].red = 65535;
+ day_view->colors[E_DAY_VIEW_COLOR_BG_TOP_CANVAS_SELECTED].green = 65535;
+ day_view->colors[E_DAY_VIEW_COLOR_BG_TOP_CANVAS_SELECTED].blue = 65535;
+
+ day_view->colors[E_DAY_VIEW_COLOR_BG_TOP_CANVAS_GRID].red = 0;
+ day_view->colors[E_DAY_VIEW_COLOR_BG_TOP_CANVAS_GRID].green = 0;
+ day_view->colors[E_DAY_VIEW_COLOR_BG_TOP_CANVAS_GRID].blue = 0;
+
+ day_view->colors[E_DAY_VIEW_COLOR_EVENT_VBAR].red = 0;
+ day_view->colors[E_DAY_VIEW_COLOR_EVENT_VBAR].green = 0;
+ day_view->colors[E_DAY_VIEW_COLOR_EVENT_VBAR].blue = 65535;
+
+ day_view->colors[E_DAY_VIEW_COLOR_EVENT_BACKGROUND].red = 65535;
+ day_view->colors[E_DAY_VIEW_COLOR_EVENT_BACKGROUND].green = 65535;
+ day_view->colors[E_DAY_VIEW_COLOR_EVENT_BACKGROUND].blue = 65535;
+
+ day_view->colors[E_DAY_VIEW_COLOR_EVENT_BORDER].red = 0;
+ day_view->colors[E_DAY_VIEW_COLOR_EVENT_BORDER].green = 0;
+ day_view->colors[E_DAY_VIEW_COLOR_EVENT_BORDER].blue = 0;
+
+ day_view->colors[E_DAY_VIEW_COLOR_LONG_EVENT_BACKGROUND].red = 213 * 257;
+ day_view->colors[E_DAY_VIEW_COLOR_LONG_EVENT_BACKGROUND].green = 213 * 257;
+ day_view->colors[E_DAY_VIEW_COLOR_LONG_EVENT_BACKGROUND].blue = 213 * 257;
+
+ day_view->colors[E_DAY_VIEW_COLOR_LONG_EVENT_BORDER].red = 0;
+ day_view->colors[E_DAY_VIEW_COLOR_LONG_EVENT_BORDER].green = 0;
+ day_view->colors[E_DAY_VIEW_COLOR_LONG_EVENT_BORDER].blue = 0;
+
+ nfailed = gdk_colormap_alloc_colors (colormap, day_view->colors,
+ E_DAY_VIEW_COLOR_LAST, FALSE,
+ TRUE, success);
+ if (nfailed)
+ g_warning ("Failed to allocate all colors");
+
gdk_gc_set_colormap (day_view->main_gc, colormap);
/* Create the pixmaps. */
@@ -1098,7 +1223,6 @@ e_day_view_realize (GtkWidget *widget)
day_view->recurrence_icon = e_icon_factory_get_icon ("stock_refresh", E_ICON_SIZE_MENU);
day_view->timezone_icon = e_icon_factory_get_icon ("stock_timezone", E_ICON_SIZE_MENU);
day_view->meeting_icon = e_icon_factory_get_icon ("stock_people", E_ICON_SIZE_MENU);
- day_view->attach_icon = e_icon_factory_get_icon ("stock_attach", E_ICON_SIZE_MENU);
/* Set the canvas item colors. */
@@ -1145,23 +1269,6 @@ e_day_view_realize (GtkWidget *widget)
NULL);
}
-static void
-e_day_view_set_colors(EDayView *day_view, GtkWidget *widget)
-{
- day_view->colors[E_DAY_VIEW_COLOR_BG_WORKING] = widget->style->base[GTK_STATE_NORMAL];
- day_view->colors[E_DAY_VIEW_COLOR_BG_NOT_WORKING] = widget->style->bg[GTK_STATE_ACTIVE];
- day_view->colors[E_DAY_VIEW_COLOR_BG_SELECTED] = widget->style->base[GTK_STATE_SELECTED];
- day_view->colors[E_DAY_VIEW_COLOR_BG_SELECTED_UNFOCUSSED] = widget->style->bg[GTK_STATE_SELECTED];
- day_view->colors[E_DAY_VIEW_COLOR_BG_GRID] = widget->style->dark[GTK_STATE_NORMAL];
- day_view->colors[E_DAY_VIEW_COLOR_BG_TOP_CANVAS] = widget->style->dark[GTK_STATE_NORMAL];
- day_view->colors[E_DAY_VIEW_COLOR_BG_TOP_CANVAS_SELECTED] = widget->style->bg[GTK_STATE_SELECTED];
- day_view->colors[E_DAY_VIEW_COLOR_BG_TOP_CANVAS_GRID] = widget->style->light[GTK_STATE_NORMAL];
- day_view->colors[E_DAY_VIEW_COLOR_EVENT_VBAR] = widget->style->base[GTK_STATE_SELECTED];
- day_view->colors[E_DAY_VIEW_COLOR_EVENT_BACKGROUND] = widget->style->base[GTK_STATE_NORMAL];
- day_view->colors[E_DAY_VIEW_COLOR_EVENT_BORDER] = widget->style->dark[GTK_STATE_NORMAL];
- day_view->colors[E_DAY_VIEW_COLOR_LONG_EVENT_BACKGROUND] = widget->style->bg[GTK_STATE_ACTIVE];
- day_view->colors[E_DAY_VIEW_COLOR_LONG_EVENT_BORDER] = widget->style->dark[GTK_STATE_NORMAL];
-}
static void
e_day_view_unrealize (GtkWidget *widget)
@@ -1185,11 +1292,9 @@ e_day_view_unrealize (GtkWidget *widget)
day_view->timezone_icon = NULL;
g_object_unref (day_view->meeting_icon);
day_view->meeting_icon = NULL;
- g_object_unref (day_view->attach_icon);
- day_view->attach_icon = NULL;
- if (GTK_WIDGET_CLASS (e_day_view_parent_class)->unrealize)
- (*GTK_WIDGET_CLASS (e_day_view_parent_class)->unrealize)(widget);
+ if (GTK_WIDGET_CLASS (parent_class)->unrealize)
+ (*GTK_WIDGET_CLASS (parent_class)->unrealize)(widget);
}
@@ -1211,39 +1316,11 @@ e_day_view_style_set (GtkWidget *widget,
PangoContext *pango_context;
PangoFontMetrics *font_metrics;
PangoLayout *layout;
- gint week_day, event_num;
- EDayViewEvent *event;
- if (GTK_WIDGET_CLASS (e_day_view_parent_class)->style_set)
- (*GTK_WIDGET_CLASS (e_day_view_parent_class)->style_set)(widget, previous_style);
+ if (GTK_WIDGET_CLASS (parent_class)->style_set)
+ (*GTK_WIDGET_CLASS (parent_class)->style_set)(widget, previous_style);
day_view = E_DAY_VIEW (widget);
- e_day_view_set_colors(day_view, widget);
-
- for (week_day = 0; week_day < E_DAY_VIEW_MAX_DAYS; week_day++){
- for (event_num = 0; event_num < day_view->events[week_day]->len; event_num++) {
- event = &g_array_index (day_view->events[week_day], EDayViewEvent, event_num);
- if (event->canvas_item)
- gnome_canvas_item_set (event->canvas_item,
- "fill_color_gdk", &widget->style->text[GTK_STATE_NORMAL],
- NULL);
- }
- }
- for (event_num = 0; event_num < day_view->long_events->len; event_num++) {
- event = &g_array_index (day_view->long_events, EDayViewEvent, event_num);
- if (event->canvas_item)
- gnome_canvas_item_set (event->canvas_item,
- "fill_color_gdk", &widget->style->text[GTK_STATE_NORMAL],
- NULL);
- }
- gnome_canvas_item_set (day_view->main_canvas_top_resize_bar_item,
- "fill_color_gdk", &day_view->colors[E_DAY_VIEW_COLOR_EVENT_VBAR],
- "outline_color_gdk", &day_view->colors[E_DAY_VIEW_COLOR_EVENT_BORDER],
- NULL);
- gnome_canvas_item_set (day_view->main_canvas_bottom_resize_bar_item,
- "fill_color_gdk", &day_view->colors[E_DAY_VIEW_COLOR_EVENT_VBAR],
- "outline_color_gdk", &day_view->colors[E_DAY_VIEW_COLOR_EVENT_BORDER],
- NULL);
/* Set up Pango prerequisites */
font_desc = gtk_widget_get_style (widget)->font_desc;
@@ -1399,7 +1476,7 @@ e_day_view_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
#endif
day_view = E_DAY_VIEW (widget);
- (*GTK_WIDGET_CLASS (e_day_view_parent_class)->size_allocate) (widget, allocation);
+ (*GTK_WIDGET_CLASS (parent_class)->size_allocate) (widget, allocation);
e_day_view_recalc_cell_sizes (day_view);
@@ -1717,26 +1794,16 @@ e_day_view_remove_event_cb (EDayView *day_view,
event = &g_array_index (day_view->events[day],
EDayViewEvent, event_num);
- if (!event)
- return TRUE;
-
/* If we were editing this event, set editing_event_day to -1 so
on_editing_stopped doesn't try to update the event. */
- if (day_view->editing_event_num == event_num && day_view->editing_event_day == day) {
- day_view->editing_event_num = -1;
+ if (day_view->editing_event_day == day
+ && day_view->editing_event_num == event_num)
day_view->editing_event_day = -1;
- }
-
- if (day_view->popup_event_num == event_num && day_view->popup_event_day == day) {
- day_view->popup_event_num = -1;
- day_view->popup_event_day = -1;
- }
if (event->canvas_item)
gtk_object_destroy (GTK_OBJECT (event->canvas_item));
e_cal_model_free_component_data (event->comp_data);
- event->comp_data = NULL;
if (day == E_DAY_VIEW_LONG_EVENT) {
g_array_remove_index (day_view->long_events, event_num);
@@ -1918,15 +1985,13 @@ e_day_view_find_event_from_item (EDayView *day_view,
see if any events with the uid exist. */
static gboolean
e_day_view_find_event_from_uid (EDayView *day_view,
- ECal *client,
const gchar *uid,
- const gchar *rid,
gint *day_return,
gint *event_num_return)
{
EDayViewEvent *event;
gint day, event_num;
- const char *u, *r;
+ const char *u;
if (!uid)
return FALSE;
@@ -1937,19 +2002,8 @@ e_day_view_find_event_from_uid (EDayView *day_view,
event = &g_array_index (day_view->events[day],
EDayViewEvent, event_num);
- if (event->comp_data->client != client)
- continue;
-
u = icalcomponent_get_uid (event->comp_data->icalcomp);
if (u && !strcmp (uid, u)) {
- if (rid && *rid) {
- r = icaltime_as_ical_string (icalcomponent_get_recurrenceid (event->comp_data->icalcomp));
- if (!r || !*r)
- continue;
- if (strcmp (rid, r) != 0)
- continue;
- }
-
*day_return = day;
*event_num_return = event_num;
return TRUE;
@@ -2252,6 +2306,8 @@ e_day_view_recalc_day_starts (EDayView *day_view,
day_view->lower = start_time;
day_view->upper = day_view->day_starts[day_view->days_shown];
+
+ e_day_view_update_query (day_view);
}
@@ -2810,7 +2866,7 @@ e_day_view_on_main_canvas_button_press (GtkWidget *widget,
return TRUE;
}
- if (!GTK_WIDGET_HAS_FOCUS (day_view) && !GTK_WIDGET_HAS_FOCUS (day_view->main_canvas))
+ if (!GTK_WIDGET_HAS_FOCUS (day_view))
gtk_widget_grab_focus (GTK_WIDGET (day_view));
if (gdk_pointer_grab (GTK_LAYOUT (widget)->bin_window, FALSE,
@@ -2818,7 +2874,6 @@ e_day_view_on_main_canvas_button_press (GtkWidget *widget,
| GDK_BUTTON_RELEASE_MASK,
FALSE, NULL, event->time) == 0) {
e_day_view_start_selection (day_view, day, row);
- g_signal_emit_by_name (day_view, "selected_time_changed");
}
} else if (event->button == 3) {
if (!GTK_WIDGET_HAS_FOCUS (day_view))
@@ -3197,7 +3252,6 @@ e_day_view_on_event_double_click (EDayView *day_view,
gint event_num)
{
EDayViewEvent *event;
- icalproperty *attendee_prop = NULL;
if (day == -1)
event = &g_array_index (day_view->long_events, EDayViewEvent,
@@ -3208,11 +3262,9 @@ e_day_view_on_event_double_click (EDayView *day_view,
e_day_view_stop_editing_event (day_view);
-
- attendee_prop = icalcomponent_get_first_property (event->comp_data->icalcomp, ICAL_ATTENDEE_PROPERTY);
e_calendar_view_edit_appointment (E_CALENDAR_VIEW (day_view),
event->comp_data->client,
- event->comp_data->icalcomp, attendee_prop ? TRUE:FALSE);
+ event->comp_data->icalcomp, FALSE);
}
static void
@@ -3237,7 +3289,7 @@ e_day_view_show_popup_menu (EDayView *day_view,
popup = e_calendar_view_create_popup_menu (E_CALENDAR_VIEW (day_view));
g_object_weak_ref (G_OBJECT (popup), popup_destroyed_cb, day_view);
- gtk_menu_popup (popup, NULL, NULL, NULL, NULL, gdk_event?gdk_event->button.button:0, gdk_event?gdk_event->button.time:gtk_get_current_event_time());
+ e_popup_menu (popup, gdk_event);
}
static gboolean
@@ -4291,8 +4343,7 @@ e_day_view_reshape_long_event (EDayView *day_view,
num_icons++;
if (e_cal_component_has_organizer (comp))
num_icons++;
- if (e_cal_component_has_attachments (comp))
- num_icons++;
+
e_cal_component_get_categories_list (comp, &categories_list);
for (elem = categories_list; elem; elem = elem->next) {
char *category;
@@ -4307,9 +4358,6 @@ e_day_view_reshape_long_event (EDayView *day_view,
}
if (!event->canvas_item) {
- GtkWidget *widget;
-
- widget = (GtkWidget *)day_view;
event->canvas_item =
gnome_canvas_item_new (GNOME_CANVAS_GROUP (GNOME_CANVAS (day_view->top_canvas)->root),
e_text_get_type (),
@@ -4319,7 +4367,7 @@ e_day_view_reshape_long_event (EDayView *day_view,
"editable", TRUE,
"use_ellipsis", TRUE,
"draw_background", FALSE,
- "fill_color_gdk", &widget->style->text[GTK_STATE_NORMAL],
+ "fill_color_rgba", GNOME_CANVAS_COLOR (0, 0, 0),
"im_context", E_CANVAS (day_view->top_canvas)->im_context,
NULL);
g_signal_connect (event->canvas_item, "event",
@@ -4457,8 +4505,6 @@ e_day_view_reshape_day_event (EDayView *day_view,
num_icons++;
if (e_cal_component_has_recurrences (comp))
num_icons++;
- if (e_cal_component_has_attachments (comp))
- num_icons++;
if (event->different_timezone)
num_icons++;
if (e_cal_component_has_organizer (comp))
@@ -4487,9 +4533,6 @@ e_day_view_reshape_day_event (EDayView *day_view,
}
if (!event->canvas_item) {
- GtkWidget *widget;
-
- widget = (GtkWidget *)day_view;
event->canvas_item =
gnome_canvas_item_new (GNOME_CANVAS_GROUP (GNOME_CANVAS (day_view->main_canvas)->root),
e_text_get_type (),
@@ -4499,7 +4542,7 @@ e_day_view_reshape_day_event (EDayView *day_view,
"clip", TRUE,
"use_ellipsis", TRUE,
"draw_background", FALSE,
- "fill_color_gdk", &widget->style->text[GTK_STATE_NORMAL],
+ "fill_color_rgba", GNOME_CANVAS_COLOR(0, 0, 0),
"im_context", E_CANVAS (day_view->main_canvas)->im_context,
NULL);
g_signal_connect (event->canvas_item, "event",
@@ -4829,7 +4872,7 @@ e_day_view_do_key_press (GtkWidget *widget, GdkEventKey *event)
gtk_widget_queue_draw (day_view->top_canvas);
gtk_widget_queue_draw (day_view->main_canvas);
- if (e_day_view_find_event_from_uid (day_view, ecal, uid, NULL, &day, &event_num)) {
+ if (e_day_view_find_event_from_uid (day_view, uid, &day, &event_num)) {
e_day_view_start_editing_event (day_view, day, event_num,
initial_text);
} else {
@@ -4852,7 +4895,7 @@ e_day_view_key_press (GtkWidget *widget, GdkEventKey *event)
/* if not handled, try key bindings */
if (!handled)
- handled = GTK_WIDGET_CLASS (e_day_view_parent_class)->key_press_event (widget, event);
+ handled = GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event);
return handled;
}
@@ -5525,7 +5568,6 @@ e_day_view_start_editing_event (EDayView *day_view,
EDayViewEvent *event;
ETextEventProcessor *event_processor = NULL;
ETextEventProcessorCommand command;
- gboolean read_only;
#if 0
g_print ("In e_day_view_start_editing_event\n");
@@ -5544,9 +5586,6 @@ e_day_view_start_editing_event (EDayView *day_view,
event_num);
}
- if (!e_cal_is_read_only (event->comp_data->client, &read_only, NULL) || read_only)
- return;
-
/* If the event is not shown, don't try to edit it. */
if (!event->canvas_item)
return;
@@ -6028,9 +6067,6 @@ e_day_view_on_editing_stopped (EDayView *day_view,
g_message (G_STRLOC ": Could not create the object!");
else
g_signal_emit_by_name (day_view, "user_created");
-
- /* we remove the object since we either got the update from the server or failed */
- e_day_view_remove_event_cb (day_view, day, event_num, NULL);
} else {
CalObjModType mod = CALOBJ_MOD_ALL;
GtkWindow *toplevel;
diff --git a/calendar/gui/e-itip-control.c b/calendar/gui/e-itip-control.c
index 77116834a1..82d90c36fb 100644
--- a/calendar/gui/e-itip-control.c
+++ b/calendar/gui/e-itip-control.c
@@ -43,7 +43,6 @@
#include <gtkhtml/gtkhtml-embedded.h>
#include <gtkhtml/gtkhtml-stream.h>
#include <libedataserver/e-source-list.h>
-#include <libedataserverui/e-source-option-menu.h>
#include <libical/ical.h>
#include <libecal/e-cal-component.h>
#include <libecal/e-cal-time-util.h>
@@ -51,6 +50,7 @@
#include <e-util/e-time-utils.h>
#include <e-util/e-dialog-widgets.h>
#include <e-util/e-html-utils.h>
+#include <widgets/misc/e-source-option-menu.h>
#include "dialogs/delete-error.h"
#include "calendar-config.h"
#include "itip-utils.h"
@@ -104,17 +104,22 @@ struct _EItipControlPrivate {
#define HTML_BODY_END "</body>"
#define HTML_FOOTER "</html>"
-static void e_itip_control_destroy (GtkObject *obj);
+static void class_init (EItipControlClass *klass);
+static void init (EItipControl *itip);
+static void destroy (GtkObject *obj);
static void find_my_address (EItipControl *itip, icalcomponent *ical_comp, icalparameter_partstat *status);
static void url_requested_cb (GtkHTML *html, const gchar *url, GtkHTMLStream *handle, gpointer data);
static gboolean object_requested_cb (GtkHTML *html, GtkHTMLEmbedded *eb, gpointer data);
static void ok_clicked_cb (GtkWidget *widget, gpointer data);
-G_DEFINE_TYPE (EItipControl, e_itip_control, GTK_TYPE_VBOX);
+static GtkVBoxClass *parent_class = NULL;
+
+E_MAKE_TYPE (e_itip_control, "EItipControl", EItipControl, class_init, init,
+ GTK_TYPE_VBOX);
static void
-e_itip_control_class_init (EItipControlClass *klass)
+class_init (EItipControlClass *klass)
{
GObjectClass *object_class;
GtkObjectClass *gtkobject_class;
@@ -122,7 +127,9 @@ e_itip_control_class_init (EItipControlClass *klass)
object_class = G_OBJECT_CLASS (klass);
gtkobject_class = GTK_OBJECT_CLASS (klass);
- gtkobject_class->destroy = e_itip_control_destroy;
+ parent_class = g_type_class_peek_parent (klass);
+
+ gtkobject_class->destroy = destroy;
}
static void
@@ -382,7 +389,7 @@ html_destroyed (gpointer data)
}
static void
-e_itip_control_init (EItipControl *itip)
+init (EItipControl *itip)
{
EItipControlPrivate *priv;
GtkWidget *scrolled_window;
@@ -482,7 +489,7 @@ clean_up (EItipControl *itip)
}
static void
-e_itip_control_destroy (GtkObject *obj)
+destroy (GtkObject *obj)
{
EItipControl *itip = E_ITIP_CONTROL (obj);
EItipControlPrivate *priv;
@@ -512,7 +519,7 @@ e_itip_control_destroy (GtkObject *obj)
itip->priv = NULL;
}
- (* GTK_OBJECT_CLASS (e_itip_control_parent_class)->destroy) (obj);
+ (* GTK_OBJECT_CLASS (parent_class)->destroy) (obj);
}
GtkWidget *
@@ -2024,7 +2031,7 @@ send_item (EItipControl *itip)
comp = get_real_item (itip);
if (comp != NULL) {
- itip_send_comp (E_CAL_COMPONENT_METHOD_REQUEST, comp, priv->current_ecal, NULL, NULL);
+ itip_send_comp (E_CAL_COMPONENT_METHOD_REQUEST, comp, priv->current_ecal, NULL);
g_object_unref (comp);
dialog = gnome_ok_dialog (_("Item sent!\n"));
} else {
@@ -2070,7 +2077,7 @@ send_freebusy (EItipControl *itip)
for (l = comp_list; l; l = l->next) {
ECalComponent *comp = E_CAL_COMPONENT (l->data);
- itip_send_comp (E_CAL_COMPONENT_METHOD_REPLY, comp, priv->current_ecal, NULL, NULL);
+ itip_send_comp (E_CAL_COMPONENT_METHOD_REPLY, comp, priv->current_ecal, NULL);
g_object_unref (comp);
}
@@ -2510,7 +2517,7 @@ ok_clicked_cb (GtkWidget *widget, gpointer data)
g_slist_free (list);
e_cal_component_rescan (comp);
- itip_send_comp (E_CAL_COMPONENT_METHOD_REPLY, comp, priv->current_ecal, priv->top_level, NULL);
+ itip_send_comp (E_CAL_COMPONENT_METHOD_REPLY, comp, priv->current_ecal, priv->top_level);
g_object_unref (comp);
}
diff --git a/calendar/gui/e-meeting-time-sel.c b/calendar/gui/e-meeting-time-sel.c
index 5f92ab6a63..5335fca5d3 100644
--- a/calendar/gui/e-meeting-time-sel.c
+++ b/calendar/gui/e-meeting-time-sel.c
@@ -103,6 +103,8 @@ enum {
static gint mts_signals [LAST_SIGNAL] = { 0 };
+static void e_meeting_time_selector_class_init (EMeetingTimeSelectorClass * klass);
+static void e_meeting_time_selector_init (EMeetingTimeSelector * mts);
static void e_meeting_time_selector_destroy (GtkObject *object);
static void e_meeting_time_selector_alloc_named_color (EMeetingTimeSelector * mts,
const char *name, GdkColor *c);
@@ -207,10 +209,11 @@ static void row_inserted_cb (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter
static void row_changed_cb (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data);
static void row_deleted_cb (GtkTreeModel *model, GtkTreePath *path, gpointer data);
-static void free_busy_template_changed_cb (GConfClient *client, guint cnxn_id,
- GConfEntry *entry, gpointer user_data);
+static GtkTableClass *parent_class;
-G_DEFINE_TYPE (EMeetingTimeSelector, e_meeting_time_selector, GTK_TYPE_TABLE);
+E_MAKE_TYPE (e_meeting_time_selector, "EMeetingTimeSelector", EMeetingTimeSelector,
+ e_meeting_time_selector_class_init, e_meeting_time_selector_init,
+ GTK_TYPE_TABLE);
static void
e_meeting_time_selector_class_init (EMeetingTimeSelectorClass * klass)
@@ -218,6 +221,7 @@ e_meeting_time_selector_class_init (EMeetingTimeSelectorClass * klass)
GtkObjectClass *object_class;
GtkWidgetClass *widget_class;
+ parent_class = g_type_class_peek_parent (klass);
object_class = (GtkObjectClass *) klass;
widget_class = (GtkWidgetClass *) klass;
@@ -255,12 +259,6 @@ e_meeting_time_selector_init (EMeetingTimeSelector * mts)
mts->dragging_position = E_MEETING_TIME_SELECTOR_POS_NONE;
mts->list_view = NULL;
-
- mts->fb_uri_not =
- calendar_config_add_notification_free_busy_template ((GConfClientNotifyFunc) free_busy_template_changed_cb,
- mts);
-
- mts->fb_refresh_not = 0;
}
@@ -279,7 +277,6 @@ e_meeting_time_selector_construct (EMeetingTimeSelector * mts, EMeetingStore *em
guchar stipple_bits[] = {
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
};
- AtkObject *a11y_label, *a11y_date_edit;
/* The default meeting time is the nearest half-hour interval in the
future, in working hours. */
@@ -594,14 +591,6 @@ e_meeting_time_selector_construct (EMeetingTimeSelector * mts, EMeetingStore *em
gtk_widget_show (table);
mts->start_date_edit = e_date_edit_new ();
- gtk_label_set_mnemonic_widget (GTK_LABEL (label), mts->start_date_edit);
- a11y_label = gtk_widget_get_accessible (label);
- a11y_date_edit = gtk_widget_get_accessible (mts->start_date_edit);
- if (a11y_label != NULL && a11y_date_edit != NULL) {
- atk_object_add_relationship (a11y_date_edit,
- ATK_RELATION_LABELLED_BY,
- a11y_label);
- }
e_date_edit_set_show_time (E_DATE_EDIT (mts->start_date_edit), TRUE);
e_date_edit_set_use_24_hour_format (E_DATE_EDIT (mts->start_date_edit),
calendar_config_get_24_hour_format ());
@@ -621,14 +610,6 @@ e_meeting_time_selector_construct (EMeetingTimeSelector * mts, EMeetingStore *em
gtk_widget_show (label);
mts->end_date_edit = e_date_edit_new ();
- gtk_label_set_mnemonic_widget (GTK_LABEL (label), mts->end_date_edit);
- a11y_label = gtk_widget_get_accessible (label);
- a11y_date_edit = gtk_widget_get_accessible (mts->end_date_edit);
- if (a11y_label != NULL && a11y_date_edit != NULL) {
- atk_object_add_relationship (a11y_date_edit,
- ATK_RELATION_LABELLED_BY,
- a11y_label);
- }
e_date_edit_set_show_time (E_DATE_EDIT (mts->end_date_edit), TRUE);
e_date_edit_set_use_24_hour_format (E_DATE_EDIT (mts->end_date_edit),
calendar_config_get_24_hour_format ());
@@ -834,15 +815,9 @@ e_meeting_time_selector_destroy (GtkObject *object)
mts->display_top = NULL;
mts->display_main = NULL;
-
- calendar_config_remove_notification (mts->fb_uri_not);
-
- if (mts->fb_refresh_not != 0) {
- g_source_remove (mts->fb_refresh_not);
- }
- if (GTK_OBJECT_CLASS (e_meeting_time_selector_parent_class)->destroy)
- (*GTK_OBJECT_CLASS (e_meeting_time_selector_parent_class)->destroy)(object);
+ if (GTK_OBJECT_CLASS (parent_class)->destroy)
+ (*GTK_OBJECT_CLASS (parent_class)->destroy)(object);
}
@@ -851,8 +826,8 @@ e_meeting_time_selector_realize (GtkWidget *widget)
{
EMeetingTimeSelector *mts;
- if (GTK_WIDGET_CLASS (e_meeting_time_selector_parent_class)->realize)
- (*GTK_WIDGET_CLASS (e_meeting_time_selector_parent_class)->realize)(widget);
+ if (GTK_WIDGET_CLASS (parent_class)->realize)
+ (*GTK_WIDGET_CLASS (parent_class)->realize)(widget);
mts = E_MEETING_TIME_SELECTOR (widget);
@@ -870,8 +845,8 @@ e_meeting_time_selector_unrealize (GtkWidget *widget)
gdk_gc_unref (mts->color_key_gc);
mts->color_key_gc = NULL;
- if (GTK_WIDGET_CLASS (e_meeting_time_selector_parent_class)->unrealize)
- (*GTK_WIDGET_CLASS (e_meeting_time_selector_parent_class)->unrealize)(widget);
+ if (GTK_WIDGET_CLASS (parent_class)->unrealize)
+ (*GTK_WIDGET_CLASS (parent_class)->unrealize)(widget);
}
static int
@@ -903,8 +878,8 @@ e_meeting_time_selector_style_set (GtkWidget *widget,
GtkTreePath *path;
GdkRectangle cell_area;
- if (GTK_WIDGET_CLASS (e_meeting_time_selector_parent_class)->style_set)
- (*GTK_WIDGET_CLASS (e_meeting_time_selector_parent_class)->style_set)(widget, previous_style);
+ if (GTK_WIDGET_CLASS (parent_class)->style_set)
+ (*GTK_WIDGET_CLASS (parent_class)->style_set)(widget, previous_style);
mts = E_MEETING_TIME_SELECTOR (widget);
@@ -968,8 +943,8 @@ e_meeting_time_selector_expose_event (GtkWidget *widget,
e_meeting_time_selector_draw_shadow (mts);
- if (GTK_WIDGET_CLASS (e_meeting_time_selector_parent_class)->expose_event)
- (*GTK_WIDGET_CLASS (e_meeting_time_selector_parent_class)->expose_event)(widget, event);
+ if (GTK_WIDGET_CLASS (parent_class)->expose_event)
+ (*GTK_WIDGET_CLASS (parent_class)->expose_event)(widget, event);
return FALSE;
}
@@ -2892,42 +2867,3 @@ row_deleted_cb (GtkTreeModel *model, GtkTreePath *path, gpointer data)
gtk_widget_queue_draw (mts->display_main);
}
-
-#define REFRESH_PAUSE 5000
-
-static gboolean
-free_busy_timeout_refresh (gpointer data)
-{
- char *fb_uri;
-
- EMeetingTimeSelector *mts = E_MEETING_TIME_SELECTOR (data);
-
- fb_uri = calendar_config_get_free_busy_template ();
- e_meeting_store_set_fb_uri (mts->model, fb_uri);
- g_free (fb_uri);
-
- /* Update all free/busy info, so we use the new template uri */
- e_meeting_time_selector_refresh_free_busy (mts, 0, TRUE);
-
- mts->fb_refresh_not = 0;
-
- return FALSE;
-}
-
-static void
-free_busy_template_changed_cb (GConfClient *client,
- guint cnxn_id,
- GConfEntry *entry,
- gpointer data)
-{
- EMeetingTimeSelector *mts = E_MEETING_TIME_SELECTOR (data);
-
- /* Wait REFRESH_PAUSE before refreshing, using the latest uri value */
- if (mts->fb_refresh_not != 0) {
- g_source_remove (mts->fb_refresh_not);
- }
-
- mts->fb_refresh_not = g_timeout_add (REFRESH_PAUSE,
- free_busy_timeout_refresh,
- data);
-}
diff --git a/calendar/gui/e-week-view-event-item.c b/calendar/gui/e-week-view-event-item.c
index e4ace7961e..abecb745ac 100644
--- a/calendar/gui/e-week-view-event-item.c
+++ b/calendar/gui/e-week-view-event-item.c
@@ -28,9 +28,7 @@
* edit the text.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-#endif
#include "e-util/e-categories-config.h"
#include "e-week-view-event-item.h"
@@ -38,6 +36,9 @@
#include <gtk/gtksignal.h>
#include <gal/e-text/e-text.h>
+static void e_week_view_event_item_class_init (EWeekViewEventItemClass *class);
+static void e_week_view_event_item_init (EWeekViewEventItem *wveitem);
+
static void e_week_view_event_item_set_arg (GtkObject *o,
GtkArg *arg,
guint arg_id);
@@ -88,6 +89,8 @@ static ECalendarViewPosition e_week_view_event_item_get_position (EWeekViewEvent
gdouble y);
+static GnomeCanvasItemClass *parent_class;
+
/* The arguments we take */
enum {
ARG_0,
@@ -95,7 +98,9 @@ enum {
ARG_SPAN_NUM
};
-G_DEFINE_TYPE (EWeekViewEventItem, e_week_view_event_item, GNOME_TYPE_CANVAS_ITEM);
+E_MAKE_TYPE (e_week_view_event_item, "EWeekViewEventItem", EWeekViewEventItem,
+ e_week_view_event_item_class_init, e_week_view_event_item_init,
+ GNOME_TYPE_CANVAS_ITEM);
static void
e_week_view_event_item_class_init (EWeekViewEventItemClass *class)
@@ -103,6 +108,8 @@ e_week_view_event_item_class_init (EWeekViewEventItemClass *class)
GtkObjectClass *object_class;
GnomeCanvasItemClass *item_class;
+ parent_class = g_type_class_peek_parent (class);
+
object_class = (GtkObjectClass *) class;
item_class = (GnomeCanvasItemClass *) class;
@@ -175,8 +182,8 @@ e_week_view_event_item_update (GnomeCanvasItem *item,
week_view = E_WEEK_VIEW (GTK_WIDGET (item->canvas)->parent);
g_return_if_fail (E_IS_WEEK_VIEW (week_view));
- if (GNOME_CANVAS_ITEM_CLASS (e_week_view_event_item_parent_class)->update)
- (* GNOME_CANVAS_ITEM_CLASS (e_week_view_event_item_parent_class)->update) (item, affine, clip_path, flags);
+ if (GNOME_CANVAS_ITEM_CLASS (parent_class)->update)
+ (* GNOME_CANVAS_ITEM_CLASS (parent_class)->update) (item, affine, clip_path, flags);
item->x1 = 0;
item->y1 = 0;
@@ -596,7 +603,7 @@ e_week_view_event_item_draw_icons (EWeekViewEventItem *wveitem,
GdkGC *gc;
gint num_icons = 0, icon_x_inc;
gboolean draw_reminder_icon = FALSE, draw_recurrence_icon = FALSE;
- gboolean draw_timezone_icon = FALSE, draw_attach_icon = FALSE;
+ gboolean draw_timezone_icon = FALSE;
GSList *categories_list, *elem;
week_view = E_WEEK_VIEW (GTK_WIDGET (GNOME_CANVAS_ITEM (wveitem)->canvas)->parent);
@@ -619,12 +626,7 @@ e_week_view_event_item_draw_icons (EWeekViewEventItem *wveitem,
draw_recurrence_icon = TRUE;
num_icons++;
}
-
- if (e_cal_component_has_attachments (comp)) {
- draw_attach_icon = TRUE;
- num_icons++;
- }
-
+
if (event->different_timezone) {
draw_timezone_icon = TRUE;
num_icons++;
@@ -658,18 +660,6 @@ e_week_view_event_item_draw_icons (EWeekViewEventItem *wveitem,
icon_x += icon_x_inc;
}
- if (draw_attach_icon && icon_x + E_WEEK_VIEW_ICON_WIDTH <= x2) {
- gdk_gc_set_clip_mask (gc, NULL);
- gdk_draw_pixbuf (drawable, gc,
- week_view->attach_icon,
- 0, 0, icon_x, icon_y,
- E_WEEK_VIEW_ICON_WIDTH,
- E_WEEK_VIEW_ICON_HEIGHT,
- GDK_RGB_DITHER_NORMAL,
- 0, 0);
- icon_x += icon_x_inc;
- }
-
if (draw_recurrence_icon && icon_x + E_WEEK_VIEW_ICON_WIDTH <= x2) {
gdk_gc_set_clip_mask (gc, NULL);
gdk_draw_pixbuf (drawable, gc,
diff --git a/calendar/gui/e-week-view.c b/calendar/gui/e-week-view.c
index 684d278d84..19455ea9a5 100644
--- a/calendar/gui/e-week-view.c
+++ b/calendar/gui/e-week-view.c
@@ -94,9 +94,10 @@ typedef struct {
ECalModelComponent *comp_data;
} AddEventData;
+static void e_week_view_class_init (EWeekViewClass *class);
+static void e_week_view_init (EWeekView *week_view);
static void e_week_view_destroy (GtkObject *object);
static void e_week_view_realize (GtkWidget *widget);
-static void e_week_view_set_colors(EWeekView *week_view, GtkWidget *widget);
static void e_week_view_unrealize (GtkWidget *widget);
static void e_week_view_style_set (GtkWidget *widget,
GtkStyle *previous_style);
@@ -156,14 +157,14 @@ static void e_week_view_reshape_event_span (EWeekView *week_view,
gint span_num);
static void e_week_view_recalc_day_starts (EWeekView *week_view,
time_t lower);
+static void e_week_view_on_adjustment_changed (GtkAdjustment *adjustment,
+ EWeekView *week_view);
static void e_week_view_on_editing_started (EWeekView *week_view,
GnomeCanvasItem *item);
static void e_week_view_on_editing_stopped (EWeekView *week_view,
GnomeCanvasItem *item);
static gboolean e_week_view_find_event_from_uid (EWeekView *week_view,
- ECal *client,
const gchar *uid,
- const gchar *rid,
gint *event_num_return);
typedef gboolean (* EWeekViewForeachEventCallback) (EWeekView *week_view,
gint event_num,
@@ -208,7 +209,10 @@ static void e_week_view_queue_layout (EWeekView *week_view);
static void e_week_view_cancel_layout (EWeekView *week_view);
static gboolean e_week_view_layout_timeout_cb (gpointer data);
-G_DEFINE_TYPE (EWeekView, e_week_view, E_TYPE_CALENDAR_VIEW);
+static ECalendarViewClass *parent_class;
+
+E_MAKE_TYPE (e_week_view, "EWeekView", EWeekView, e_week_view_class_init,
+ e_week_view_init, e_calendar_view_get_type ());
static void
e_week_view_class_init (EWeekViewClass *class)
@@ -217,6 +221,7 @@ e_week_view_class_init (EWeekViewClass *class)
GtkWidgetClass *widget_class;
ECalendarViewClass *view_class;
+ parent_class = g_type_class_peek_parent (class);
object_class = (GtkObjectClass *) class;
widget_class = (GtkWidgetClass *) class;
view_class = (ECalendarViewClass *) class;
@@ -303,13 +308,24 @@ time_range_changed_cb (ECalModel *model, time_t start_time, time_t end_time, gpo
e_week_view_set_selected_time_range (E_CALENDAR_VIEW (week_view), start_time, start_time);
}
+static gboolean
+process_component_recur_cb (ECalComponent *comp, time_t start, time_t end, gpointer data)
+{
+ AddEventData *add_event_data;
+
+ add_event_data = data;
+
+ return e_week_view_add_event (comp, start, end, FALSE, add_event_data);
+}
+
static void
process_component (EWeekView *week_view, ECalModelComponent *comp_data)
{
- gint num_days;
+ EWeekViewEvent *event;
+ gint event_num, num_days;
ECalComponent *comp = NULL;
AddEventData add_event_data;
- const char *uid, *rid;
+ const char *uid;
/* If we don't have a valid date set yet, just return. */
if (!g_date_valid (&week_view->first_day_shown))
@@ -324,22 +340,65 @@ process_component (EWeekView *week_view, ECalModelComponent *comp_data)
}
e_cal_component_get_uid (comp, &uid);
- if (e_cal_component_is_instance (comp))
- rid = e_cal_component_get_recurid_as_string (comp);
- else
- rid = NULL;
- /* Add the object */
+ /* If the event already exists and the dates didn't change, we can
+ update the event fairly easily without changing the events arrays
+ or computing a new layout. */
+ if (e_week_view_find_event_from_uid (week_view, uid, &event_num)) {
+ ECalComponent *tmp_comp;
+
+ event = &g_array_index (week_view->events, EWeekViewEvent,
+ event_num);
+
+ tmp_comp = e_cal_component_new ();
+ e_cal_component_set_icalcomponent (tmp_comp, icalcomponent_new_clone (event->comp_data->icalcomp));
+ if (!e_cal_component_has_recurrences (comp)
+ && !e_cal_component_has_recurrences (tmp_comp)
+ && e_cal_component_event_dates_match (comp, tmp_comp)) {
+#if 0
+ g_print ("updated object's dates unchanged\n");
+#endif
+ e_week_view_foreach_event_with_uid (week_view, uid, e_week_view_update_event_cb, comp_data);
+ g_object_unref (comp);
+ g_object_unref (tmp_comp);
+ gtk_widget_queue_draw (week_view->main_canvas);
+ return;
+ }
+
+ /* The dates have changed, so we need to remove the
+ old occurrrences before adding the new ones. */
+#if 0
+ g_print ("dates changed - removing occurrences\n");
+#endif
+ e_week_view_foreach_event_with_uid (week_view, uid,
+ e_week_view_remove_event_cb,
+ NULL);
+
+ g_object_unref (tmp_comp);
+ }
+
+ /* Add the occurrences of the event */
num_days = week_view->multi_week_view ? week_view->weeks_shown * 7 : 7;
add_event_data.week_view = week_view;
add_event_data.comp_data = comp_data;
- e_week_view_add_event (comp, comp_data->instance_start, comp_data->instance_end, FALSE, &add_event_data);
+ e_cal_generate_instances_for_object (comp_data->client, comp_data->icalcomp,
+ week_view->day_starts[0],
+ week_view->day_starts[num_days],
+ process_component_recur_cb, &add_event_data);
g_object_unref (comp);
}
static void
+model_changed_cb (ETableModel *etm, gpointer user_data)
+{
+ EWeekView *week_view = E_WEEK_VIEW (user_data);
+
+ e_week_view_update_query (week_view);
+}
+
+static void
update_row (EWeekView *week_view, int row)
{
ECalModelComponent *comp_data;
@@ -378,7 +437,6 @@ model_rows_inserted_cb (ETableModel *etm, int row, int count, gpointer user_data
int i;
model = e_calendar_view_get_model (E_CALENDAR_VIEW (week_view));
-
for (i = 0; i < count; i++) {
ECalModelComponent *comp_data;
@@ -391,36 +449,49 @@ model_rows_inserted_cb (ETableModel *etm, int row, int count, gpointer user_data
e_week_view_queue_layout (week_view);
}
+static gboolean
+row_deleted_check_cb (EWeekView *week_view, gint event_num, gpointer data)
+{
+ GHashTable *uids = data;
+ EWeekViewEvent *event;
+ ECalModel *model;
+ const char *uid;
+
+ event = &g_array_index (week_view->events, EWeekViewEvent, event_num);
+ uid = icalcomponent_get_uid (event->comp_data->icalcomp);
+ model = e_calendar_view_get_model (E_CALENDAR_VIEW (week_view));
+
+ if (!e_cal_model_get_component_for_uid (model, uid))
+ g_hash_table_insert (uids, g_strdup(uid), GINT_TO_POINTER (1));
+
+ return TRUE;
+}
+
+static void
+remove_uid_cb (gpointer key, gpointer value, gpointer data)
+{
+ EWeekView *week_view = data;
+ char *uid = key;
+
+ e_week_view_foreach_event_with_uid (week_view, uid, e_week_view_remove_event_cb, NULL);
+ g_free(uid);
+}
+
static void
model_rows_deleted_cb (ETableModel *etm, int row, int count, gpointer user_data)
{
EWeekView *week_view = E_WEEK_VIEW (user_data);
- int i;
+ GHashTable *uids;
/* FIXME Stop editing? */
-
- for (i = row + count; i > row; i--) {
- gint event_num;
- const char *uid, *rid = NULL;
- ECalModelComponent *comp_data;
- comp_data = e_cal_model_get_component_at (E_CAL_MODEL (etm), i - 1);
- if (!comp_data)
- continue;
-
- uid = icalcomponent_get_uid (comp_data->icalcomp);
- if (e_cal_util_component_is_instance (comp_data->icalcomp)) {
- icalproperty *prop;
-
- prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_RECURRENCEID_PROPERTY);
- if (prop)
- rid = icaltime_as_ical_string (icalcomponent_get_recurrenceid (comp_data->icalcomp));
- }
-
- if (e_week_view_find_event_from_uid (week_view, comp_data->client, uid, rid, &event_num))
- e_week_view_remove_event_cb (week_view, event_num, NULL);
- }
+ uids = g_hash_table_new (g_str_hash, g_str_equal);
+
+ e_week_view_foreach_event (week_view, row_deleted_check_cb, uids);
+ g_hash_table_foreach (uids, remove_uid_cb, week_view);
+ g_hash_table_destroy (uids);
+
gtk_widget_queue_draw (week_view->main_canvas);
e_week_view_queue_layout (week_view);
}
@@ -596,6 +667,8 @@ e_week_view_init (EWeekView *week_view)
/* connect to ECalModel's signals */
g_signal_connect (G_OBJECT (model), "time_range_changed",
G_CALLBACK (time_range_changed_cb), week_view);
+ g_signal_connect (G_OBJECT (model), "model_changed",
+ G_CALLBACK (model_changed_cb), week_view);
g_signal_connect (G_OBJECT (model), "model_row_changed",
G_CALLBACK (model_row_changed_cb), week_view);
g_signal_connect (G_OBJECT (model), "model_cell_changed",
@@ -623,7 +696,6 @@ e_week_view_new (void)
GtkWidget *week_view;
week_view = GTK_WIDGET (g_object_new (e_week_view_get_type (), NULL));
- e_cal_model_set_flags (e_calendar_view_get_model (E_CALENDAR_VIEW (week_view)), E_CAL_MODEL_FLAGS_EXPAND_RECURRENCES);
return week_view;
}
@@ -669,7 +741,7 @@ e_week_view_destroy (GtkObject *object)
week_view->resize_width_cursor = NULL;
}
- GTK_OBJECT_CLASS (e_week_view_parent_class)->destroy (object);
+ GTK_OBJECT_CLASS (parent_class)->destroy (object);
}
@@ -681,8 +753,8 @@ e_week_view_realize (GtkWidget *widget)
gboolean success[E_WEEK_VIEW_COLOR_LAST];
gint nfailed;
- if (GTK_WIDGET_CLASS (e_week_view_parent_class)->realize)
- (*GTK_WIDGET_CLASS (e_week_view_parent_class)->realize)(widget);
+ if (GTK_WIDGET_CLASS (parent_class)->realize)
+ (*GTK_WIDGET_CLASS (parent_class)->realize)(widget);
week_view = E_WEEK_VIEW (widget);
week_view->main_gc = gdk_gc_new (widget->window);
@@ -690,32 +762,64 @@ e_week_view_realize (GtkWidget *widget)
colormap = gtk_widget_get_colormap (widget);
/* Allocate the colors. */
- e_week_view_set_colors(week_view, widget);
-
+ week_view->colors[E_WEEK_VIEW_COLOR_EVEN_MONTHS].red = 0xe0e0;
+ week_view->colors[E_WEEK_VIEW_COLOR_EVEN_MONTHS].green = 0xe0e0;
+ week_view->colors[E_WEEK_VIEW_COLOR_EVEN_MONTHS].blue = 0xe0e0;
+
+ week_view->colors[E_WEEK_VIEW_COLOR_ODD_MONTHS].red = 65535;
+ week_view->colors[E_WEEK_VIEW_COLOR_ODD_MONTHS].green = 65535;
+ week_view->colors[E_WEEK_VIEW_COLOR_ODD_MONTHS].blue = 65535;
+
+ week_view->colors[E_WEEK_VIEW_COLOR_EVENT_BACKGROUND].red = 213 * 257;
+ week_view->colors[E_WEEK_VIEW_COLOR_EVENT_BACKGROUND].green = 213 * 257;
+ week_view->colors[E_WEEK_VIEW_COLOR_EVENT_BACKGROUND].blue = 213 * 257;
+
+ week_view->colors[E_WEEK_VIEW_COLOR_EVENT_BORDER].red = 0;
+ week_view->colors[E_WEEK_VIEW_COLOR_EVENT_BORDER].green = 0;
+ week_view->colors[E_WEEK_VIEW_COLOR_EVENT_BORDER].blue = 0;
+
+ week_view->colors[E_WEEK_VIEW_COLOR_EVENT_TEXT].red = 0;
+ week_view->colors[E_WEEK_VIEW_COLOR_EVENT_TEXT].green = 0;
+ week_view->colors[E_WEEK_VIEW_COLOR_EVENT_TEXT].blue = 0;
+
+ week_view->colors[E_WEEK_VIEW_COLOR_GRID].red = 0 * 257;
+ week_view->colors[E_WEEK_VIEW_COLOR_GRID].green = 0 * 257;
+ week_view->colors[E_WEEK_VIEW_COLOR_GRID].blue = 0 * 257;
+
+ week_view->colors[E_WEEK_VIEW_COLOR_SELECTED].red = 0 * 257;
+ week_view->colors[E_WEEK_VIEW_COLOR_SELECTED].green = 0 * 257;
+ week_view->colors[E_WEEK_VIEW_COLOR_SELECTED].blue = 156 * 257;
+
+ week_view->colors[E_WEEK_VIEW_COLOR_SELECTED_UNFOCUSSED].red = 16 * 257;
+ week_view->colors[E_WEEK_VIEW_COLOR_SELECTED_UNFOCUSSED].green = 78 * 257;
+ week_view->colors[E_WEEK_VIEW_COLOR_SELECTED_UNFOCUSSED].blue = 139 * 257;
+
+ week_view->colors[E_WEEK_VIEW_COLOR_DATES].red = 0 * 257;
+ week_view->colors[E_WEEK_VIEW_COLOR_DATES].green = 0 * 257;
+ week_view->colors[E_WEEK_VIEW_COLOR_DATES].blue = 0 * 257;
+
+ week_view->colors[E_WEEK_VIEW_COLOR_DATES_SELECTED].red = 65535;
+ week_view->colors[E_WEEK_VIEW_COLOR_DATES_SELECTED].green = 65535;
+ week_view->colors[E_WEEK_VIEW_COLOR_DATES_SELECTED].blue = 65535;
+
+ week_view->colors[E_WEEK_VIEW_COLOR_TODAY].red = 65535;
+ week_view->colors[E_WEEK_VIEW_COLOR_TODAY].green = 0;
+ week_view->colors[E_WEEK_VIEW_COLOR_TODAY].blue = 0;
+
+ nfailed = gdk_colormap_alloc_colors (colormap, week_view->colors,
+ E_WEEK_VIEW_COLOR_LAST, FALSE,
+ TRUE, success);
+ if (nfailed)
+ g_warning ("Failed to allocate all colors");
+
gdk_gc_set_colormap (week_view->main_gc, colormap);
/* Create the pixmaps. */
week_view->reminder_icon = e_icon_factory_get_icon ("stock_bell", E_ICON_SIZE_MENU);
week_view->recurrence_icon = e_icon_factory_get_icon ("stock_refresh", E_ICON_SIZE_MENU);
week_view->timezone_icon = e_icon_factory_get_icon ("stock_timezone", E_ICON_SIZE_MENU);
- week_view->attach_icon = e_icon_factory_get_icon ("stock_attach", E_ICON_SIZE_MENU);
}
-static void
-e_week_view_set_colors(EWeekView *week_view, GtkWidget *widget)
-{
- week_view->colors[E_WEEK_VIEW_COLOR_EVEN_MONTHS] = widget->style->base[GTK_STATE_INSENSITIVE];
- week_view->colors[E_WEEK_VIEW_COLOR_ODD_MONTHS] = widget->style->base[GTK_STATE_NORMAL];
- week_view->colors[E_WEEK_VIEW_COLOR_EVENT_BACKGROUND] = widget->style->base[GTK_STATE_NORMAL];
- week_view->colors[E_WEEK_VIEW_COLOR_EVENT_BORDER] = widget->style->dark[GTK_STATE_NORMAL];
- week_view->colors[E_WEEK_VIEW_COLOR_EVENT_TEXT] = widget->style->text[GTK_STATE_NORMAL];
- week_view->colors[E_WEEK_VIEW_COLOR_GRID] = widget->style->dark[GTK_STATE_NORMAL];
- week_view->colors[E_WEEK_VIEW_COLOR_SELECTED] = widget->style->base[GTK_STATE_SELECTED];
- week_view->colors[E_WEEK_VIEW_COLOR_SELECTED_UNFOCUSSED] = widget->style->bg[GTK_STATE_SELECTED];
- week_view->colors[E_WEEK_VIEW_COLOR_DATES] = widget->style->text[GTK_STATE_NORMAL];
- week_view->colors[E_WEEK_VIEW_COLOR_DATES_SELECTED] = widget->style->text[GTK_STATE_SELECTED];
- week_view->colors[E_WEEK_VIEW_COLOR_TODAY] = widget->style->base[GTK_STATE_SELECTED];
-}
static void
e_week_view_unrealize (GtkWidget *widget)
@@ -737,11 +841,9 @@ e_week_view_unrealize (GtkWidget *widget)
week_view->recurrence_icon = NULL;
g_object_unref (week_view->timezone_icon);
week_view->timezone_icon = NULL;
- g_object_unref (week_view->attach_icon);
- week_view->attach_icon = NULL;
- if (GTK_WIDGET_CLASS (e_week_view_parent_class)->unrealize)
- (*GTK_WIDGET_CLASS (e_week_view_parent_class)->unrealize)(widget);
+ if (GTK_WIDGET_CLASS (parent_class)->unrealize)
+ (*GTK_WIDGET_CLASS (parent_class)->unrealize)(widget);
}
static gint
@@ -786,35 +888,19 @@ e_week_view_style_set (GtkWidget *widget,
GtkStyle *style;
gint day, day_width, max_day_width, max_abbr_day_width;
gint month, month_width, max_month_width, max_abbr_month_width;
- gint span_num;
GDate date;
gchar buffer[128];
PangoFontDescription *font_desc;
PangoContext *pango_context;
PangoFontMetrics *font_metrics;
PangoLayout *layout;
- EWeekViewEventSpan *span;
- if (GTK_WIDGET_CLASS (e_week_view_parent_class)->style_set)
- (*GTK_WIDGET_CLASS (e_week_view_parent_class)->style_set)(widget, previous_style);
+ if (GTK_WIDGET_CLASS (parent_class)->style_set)
+ (*GTK_WIDGET_CLASS (parent_class)->style_set)(widget, previous_style);
week_view = E_WEEK_VIEW (widget);
style = gtk_widget_get_style (widget);
- e_week_view_set_colors(week_view, widget);
- if (week_view->spans) {
- for (span_num = 0; span_num < week_view->spans->len;
- span_num++) {
- span = &g_array_index (week_view->spans,
- EWeekViewEventSpan, span_num);
- if (span->text_item){
- gnome_canvas_item_set (span->text_item,
- "fill_color_gdk", &widget->style->text[GTK_STATE_NORMAL],
- NULL);
- }
- }
- }
-
/* Set up Pango prerequisites */
font_desc = style->font_desc;
pango_context = gtk_widget_get_pango_context (widget);
@@ -912,7 +998,7 @@ e_week_view_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
week_view = E_WEEK_VIEW (widget);
- (*GTK_WIDGET_CLASS (e_week_view_parent_class)->size_allocate) (widget, allocation);
+ (*GTK_WIDGET_CLASS (parent_class)->size_allocate) (widget, allocation);
e_week_view_recalc_cell_sizes (week_view);
@@ -1114,8 +1200,8 @@ e_week_view_expose_event (GtkWidget *widget,
e_week_view_draw_shadow (week_view);
- if (GTK_WIDGET_CLASS (e_week_view_parent_class)->expose_event)
- (*GTK_WIDGET_CLASS (e_week_view_parent_class)->expose_event)(widget, event);
+ if (GTK_WIDGET_CLASS (parent_class)->expose_event)
+ (*GTK_WIDGET_CLASS (parent_class)->expose_event)(widget, event);
return FALSE;
}
@@ -1548,7 +1634,6 @@ e_week_view_set_first_day_shown (EWeekView *week_view,
if (update_adjustment_value)
gtk_adjustment_set_value (GTK_RANGE (week_view->vscrollbar)->adjustment, 0);
- e_week_view_update_query (week_view);
gtk_widget_queue_draw (week_view->main_canvas);
}
@@ -1905,17 +1990,12 @@ e_week_view_remove_event_cb (EWeekView *week_view,
gint span_num;
event = &g_array_index (week_view->events, EWeekViewEvent, event_num);
- if (!event)
- return TRUE;
/* If we were editing this event, set editing_event_num to -1 so
on_editing_stopped doesn't try to update the event. */
if (week_view->editing_event_num == event_num)
week_view->editing_event_num = -1;
- if (week_view->popup_event_num == event_num)
- week_view->popup_event_num = -1;
-
/* We leave the span elements in the array, but set the canvas item
pointers to NULL. */
for (span_num = 0; span_num < event->num_spans; span_num++) {
@@ -1933,7 +2013,6 @@ e_week_view_remove_event_cb (EWeekView *week_view,
}
e_cal_model_free_component_data (event->comp_data);
- event->comp_data = NULL;
g_array_remove_index (week_view->events, event_num);
week_view->events_need_layout = TRUE;
@@ -2065,7 +2144,7 @@ e_week_view_on_button_press (GtkWidget *widget,
if (event->button == 1) {
/* Start the selection drag. */
- if (!GTK_WIDGET_HAS_FOCUS (week_view) && !GTK_WIDGET_HAS_FOCUS (week_view->main_canvas))
+ if (!GTK_WIDGET_HAS_FOCUS (week_view))
gtk_widget_grab_focus (GTK_WIDGET (week_view));
if (gdk_pointer_grab (GTK_LAYOUT (widget)->bin_window, FALSE,
@@ -2075,7 +2154,6 @@ e_week_view_on_button_press (GtkWidget *widget,
week_view->selection_start_day = day;
week_view->selection_end_day = day;
week_view->selection_drag_pos = E_WEEK_VIEW_DRAG_END;
- g_signal_emit_by_name (week_view, "selected_time_changed");
/* FIXME: Optimise? */
gtk_widget_queue_draw (week_view->main_canvas);
@@ -2583,8 +2661,6 @@ e_week_view_reshape_event_span (EWeekView *week_view,
num_icons++;
if (e_cal_component_has_recurrences (comp))
num_icons++;
- if (e_cal_component_has_attachments (comp))
- num_icons++;
if (event->different_timezone)
num_icons++;
@@ -2618,9 +2694,7 @@ e_week_view_reshape_event_span (EWeekView *week_view,
/* Create the text item if necessary. */
if (!span->text_item) {
ECalComponentText text;
- GtkWidget *widget;
- widget = (GtkWidget *)week_view;
e_cal_component_get_summary (comp, &text);
span->text_item =
gnome_canvas_item_new (GNOME_CANVAS_GROUP (GNOME_CANVAS (week_view->main_canvas)->root),
@@ -2631,7 +2705,7 @@ e_week_view_reshape_event_span (EWeekView *week_view,
"editable", TRUE,
"text", text.value ? text.value : "",
"use_ellipsis", TRUE,
- "fill_color_gdk", &widget->style->text[GTK_STATE_NORMAL],
+ "fill_color_rgba", GNOME_CANVAS_COLOR(0, 0, 0),
"im_context", E_CANVAS (week_view->main_canvas)->im_context,
NULL);
@@ -2794,7 +2868,6 @@ e_week_view_start_editing_event (EWeekView *week_view,
ETextEventProcessor *event_processor = NULL;
ETextEventProcessorCommand command;
ECalModelComponent *comp_data;
- gboolean read_only;
/* If we are already editing the event, just return. */
if (event_num == week_view->editing_event_num
@@ -2805,9 +2878,6 @@ e_week_view_start_editing_event (EWeekView *week_view,
span = &g_array_index (week_view->spans, EWeekViewEventSpan,
event->spans_index + span_num);
- if (!e_cal_is_read_only (event->comp_data->client, &read_only, NULL) || read_only)
- return FALSE;
-
/* If the event is not shown, don't try to edit it. */
if (!span->text_item)
return FALSE;
@@ -3308,10 +3378,7 @@ e_week_view_on_editing_stopped (EWeekView *week_view,
if (!e_cal_create_object (client, icalcomp, NULL, NULL))
g_message (G_STRLOC ": Could not create the object!");
else
- g_signal_emit_by_name (week_view, "user_created");
-
- /* we remove the object since we either got the update from the server or failed */
- e_week_view_remove_event_cb (week_view, event_num, NULL);
+ g_signal_emit_by_name (week_view, "user_created");
} else {
CalObjModType mod = CALOBJ_MOD_ALL;
GtkWindow *toplevel;
@@ -3375,9 +3442,7 @@ e_week_view_find_event_from_item (EWeekView *week_view,
see if any events with the uid exist. */
static gboolean
e_week_view_find_event_from_uid (EWeekView *week_view,
- ECal *client,
const gchar *uid,
- const gchar *rid,
gint *event_num_return)
{
EWeekViewEvent *event;
@@ -3389,24 +3454,13 @@ e_week_view_find_event_from_uid (EWeekView *week_view,
num_events = week_view->events->len;
for (event_num = 0; event_num < num_events; event_num++) {
- const char *u, *r;
+ const char *u;
event = &g_array_index (week_view->events, EWeekViewEvent,
event_num);
- if (event->comp_data->client != client)
- continue;
-
u = icalcomponent_get_uid (event->comp_data->icalcomp);
if (u && !strcmp (uid, u)) {
- if (rid && *rid) {
- r = icaltime_as_ical_string (icalcomponent_get_recurrenceid (event->comp_data->icalcomp));
- if (!r || !*r)
- continue;
- if (strcmp (rid, r) != 0)
- continue;
- }
-
*event_num_return = event_num;
return TRUE;
}
@@ -3451,9 +3505,9 @@ e_week_view_do_cursor_key_up (EWeekView *week_view)
if (week_view->selection_start_day <= 0)
return;
+ g_signal_emit_by_name (week_view, "selected_time_changed");
week_view->selection_start_day--;
week_view->selection_end_day = week_view->selection_start_day;
- g_signal_emit_by_name (week_view, "selected_time_changed");
gtk_widget_queue_draw (week_view->main_canvas);
}
@@ -3464,9 +3518,9 @@ e_week_view_do_cursor_key_down (EWeekView *week_view)
week_view->selection_start_day >= 6)
return;
+ g_signal_emit_by_name (week_view, "selected_time_changed");
week_view->selection_start_day++;
week_view->selection_end_day = week_view->selection_start_day;
- g_signal_emit_by_name (week_view, "selected_time_changed");
gtk_widget_queue_draw (week_view->main_canvas);
}
@@ -3476,9 +3530,9 @@ e_week_view_do_cursor_key_left (EWeekView *week_view)
if (week_view->selection_start_day == -1)
return;
+ g_signal_emit_by_name (week_view, "selected_time_changed");
week_view->selection_start_day = map_left[week_view->selection_start_day];
week_view->selection_end_day = week_view->selection_start_day;
- g_signal_emit_by_name (week_view, "selected_time_changed");
gtk_widget_queue_draw (week_view->main_canvas);
}
@@ -3488,9 +3542,9 @@ e_week_view_do_cursor_key_right (EWeekView *week_view)
if (week_view->selection_start_day == -1)
return;
+ g_signal_emit_by_name (week_view, "selected_time_changed");
week_view->selection_start_day = map_right[week_view->selection_start_day];
week_view->selection_end_day = week_view->selection_start_day;
- g_signal_emit_by_name (week_view, "selected_time_changed");
gtk_widget_queue_draw (week_view->main_canvas);
}
@@ -3500,9 +3554,9 @@ e_month_view_do_cursor_key_up (EWeekView *week_view)
if (week_view->selection_start_day < 7)
return;
+ g_signal_emit_by_name (week_view, "selected_time_changed");
week_view->selection_start_day -= 7;
week_view->selection_end_day = week_view->selection_start_day;
- g_signal_emit_by_name (week_view, "selected_time_changed");
gtk_widget_queue_draw (week_view->main_canvas);
}
@@ -3515,9 +3569,9 @@ e_month_view_do_cursor_key_down (EWeekView *week_view)
week_view->selection_start_day >= (weeks_shown - 1) * 7)
return;
+ g_signal_emit_by_name (week_view, "selected_time_changed");
week_view->selection_start_day += 7;
week_view->selection_end_day = week_view->selection_start_day;
- g_signal_emit_by_name (week_view, "selected_time_changed");
gtk_widget_queue_draw (week_view->main_canvas);
}
@@ -3527,9 +3581,9 @@ e_month_view_do_cursor_key_left (EWeekView *week_view)
if (week_view->selection_start_day <= 0)
return;
+ g_signal_emit_by_name (week_view, "selected_time_changed");
week_view->selection_start_day--;
week_view->selection_end_day = week_view->selection_start_day;
- g_signal_emit_by_name (week_view, "selected_time_changed");
gtk_widget_queue_draw (week_view->main_canvas);
}
@@ -3542,9 +3596,9 @@ e_month_view_do_cursor_key_right (EWeekView *week_view)
week_view->selection_start_day >= weeks_shown * 7 - 1)
return;
+ g_signal_emit_by_name (week_view, "selected_time_changed");
week_view->selection_start_day++;
week_view->selection_end_day = week_view->selection_start_day;
- g_signal_emit_by_name (week_view, "selected_time_changed");
gtk_widget_queue_draw (week_view->main_canvas);
}
@@ -3744,7 +3798,7 @@ e_week_view_do_key_press (GtkWidget *widget, GdkEventKey *event)
e_week_view_check_layout (week_view);
gtk_widget_queue_draw (week_view->main_canvas);
- if (e_week_view_find_event_from_uid (week_view, ecal, uid, NULL, &event_num)) {
+ if (e_week_view_find_event_from_uid (week_view, uid, &event_num)) {
EWeekViewEvent *event;
EWeekViewEventSpan *span;
@@ -3864,7 +3918,7 @@ e_week_view_key_press (GtkWidget *widget, GdkEventKey *event)
/* if not handled, try key bindings */
if (!handled)
- handled = GTK_WIDGET_CLASS (e_week_view_parent_class)->key_press_event (widget, event);
+ handled = GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event);
return handled;
}
@@ -3887,7 +3941,7 @@ e_week_view_show_popup_menu (EWeekView *week_view,
popup = e_calendar_view_create_popup_menu (E_CALENDAR_VIEW (week_view));
g_object_weak_ref (G_OBJECT (popup), popup_destroyed_cb, week_view);
- gtk_menu_popup (popup, NULL, NULL, NULL, NULL, bevent?bevent->button:0, bevent?bevent->time:gtk_get_current_event_time());
+ e_popup_menu (popup, (GdkEvent *) bevent);
}
static gboolean
diff --git a/calendar/gui/gnome-cal.c b/calendar/gui/gnome-cal.c
index 3a85a4a89f..1eecebf491 100644
--- a/calendar/gui/gnome-cal.c
+++ b/calendar/gui/gnome-cal.c
@@ -42,14 +42,11 @@
#include <libgnomeui/gnome-dialog.h>
#include <libgnomeui/gnome-dialog-util.h>
#include <bonobo/bonobo-exception.h>
-#include <libedataserver/e-categories.h>
-#include <libedataserver/e-url.h>
-#include "e-util/e-config-listener.h"
+#include "e-util/e-url.h"
#include "shell/e-user-creatable-items-handler.h"
#include <libecal/e-cal-time-util.h>
#include <gal/menus/gal-view-factory-etable.h>
#include <gal/menus/gal-view-etable.h>
-#include <gal/menus/gal-define-views-dialog.h>
#include "widgets/menus/gal-view-menus.h"
#include "widgets/misc/e-error.h"
#include "e-comp-editor-registry.h"
@@ -80,8 +77,6 @@
#include "misc.h"
#include "ea-calendar.h"
#include "common/authentication.h"
-#include "e-cal-popup.h"
-#include "e-cal-menu.h"
/* FIXME glib 2.4 and above has this */
#ifndef G_MAXINT32
@@ -97,8 +92,10 @@ struct _GnomeCalendarPrivate {
GHashTable *clients[E_CAL_SOURCE_TYPE_LAST];
GList *clients_list[E_CAL_SOURCE_TYPE_LAST];
ECal *default_client[E_CAL_SOURCE_TYPE_LAST];
-
- EConfigListener *config_listener;
+
+ /* Categories from the calendar clients */
+ /* FIXME are we getting all the categories? */
+ GPtrArray *categories[E_CAL_SOURCE_TYPE_LAST];
/*
* Fields for the calendar view
@@ -128,11 +125,7 @@ struct _GnomeCalendarPrivate {
/* Activity */
EActivityHandler *activity_handler;
-
- /* plugin menu managers */
- ECalMenu *calendar_menu;
- ECalMenu *taskpad_menu;
-
+
/* Calendar query for the date navigator */
GList *dn_queries; /* list of CalQueries */
char *sexp;
@@ -203,6 +196,8 @@ static guint gnome_calendar_signals[LAST_SIGNAL];
+static void gnome_calendar_class_init (GnomeCalendarClass *class);
+static void gnome_calendar_init (GnomeCalendar *gcal);
static void gnome_calendar_destroy (GtkObject *object);
static void gnome_calendar_goto_date (GnomeCalendar *gcal,
GnomeCalendarGotoDateType goto_date);
@@ -226,7 +221,14 @@ static void update_query (GnomeCalendar *gcal);
static void update_todo_view (GnomeCalendar *gcal);
-G_DEFINE_TYPE (GnomeCalendar, gnome_calendar, GTK_TYPE_VBOX);
+
+static GtkVBoxClass *parent_class;
+
+
+
+
+E_MAKE_TYPE (gnome_calendar, "GnomeCalendar", GnomeCalendar, gnome_calendar_class_init,
+ gnome_calendar_init, GTK_TYPE_VBOX);
/* Class initialization function for the gnome calendar */
static void
@@ -237,6 +239,8 @@ gnome_calendar_class_init (GnomeCalendarClass *class)
object_class = (GtkObjectClass *) class;
+ parent_class = g_type_class_peek_parent (class);
+
gnome_calendar_signals[DATES_SHOWN_CHANGED] =
gtk_signal_new ("dates_shown_changed",
GTK_RUN_LAST,
@@ -715,7 +719,7 @@ update_query (GnomeCalendar *gcal)
priv = gcal->priv;
- e_calendar_view_set_status_message (E_CALENDAR_VIEW (priv->week_view), _("Updating query"));
+ e_calendar_view_set_status_message (priv->week_view, _("Updating query"));
e_calendar_item_clear_marks (priv->date_navigator->calitem);
/* free the previous queries */
@@ -736,7 +740,7 @@ update_query (GnomeCalendar *gcal)
real_sexp = adjust_e_cal_view_sexp (gcal, priv->sexp);
if (!real_sexp) {
- e_calendar_view_set_status_message (E_CALENDAR_VIEW (priv->week_view), NULL);
+ e_calendar_view_set_status_message (priv->week_view, NULL);
return; /* No time range is set, so don't start a query */
}
@@ -767,9 +771,8 @@ update_query (GnomeCalendar *gcal)
e_cal_view_start (old_query);
}
- /* free memory */
g_free (real_sexp);
- e_calendar_view_set_status_message (E_CALENDAR_VIEW (priv->week_view), NULL);
+ e_calendar_view_set_status_message (priv->week_view, NULL);
update_todo_view (gcal);
}
@@ -1182,29 +1185,6 @@ month_view_adjustment_changed_cb (GtkAdjustment *adjustment, GnomeCalendar *gcal
}
static void
-config_categories_changed_cb (EConfigListener *config_listener, const char *key, gpointer user_data)
-{
- GList *cat_list;
- GPtrArray *cat_array;
- GnomeCalendarPrivate *priv;
- GnomeCalendar *gcal = user_data;
-
- priv = gcal->priv;
-
- cat_array = g_ptr_array_new ();
- cat_list = e_categories_get_list ();
- while (cat_list != NULL) {
- if (e_categories_is_searchable ((const char *) cat_list->data))
- g_ptr_array_add (cat_array, cat_list->data);
- cat_list = g_list_remove (cat_list, cat_list->data);
- }
-
- cal_search_bar_set_categories (priv->search_bar, cat_array);
-
- g_ptr_array_free (cat_array, TRUE);
-}
-
-static void
setup_widgets (GnomeCalendar *gcal)
{
GnomeCalendarPrivate *priv;
@@ -1221,7 +1201,6 @@ setup_widgets (GnomeCalendar *gcal)
G_CALLBACK (search_bar_sexp_changed_cb), gcal);
g_signal_connect (priv->search_bar, "category_changed",
G_CALLBACK (search_bar_category_changed_cb), gcal);
- config_categories_changed_cb (priv->config_listener, "/apps/evolution/general/category_master_list", gcal);
gtk_widget_show (priv->search_bar);
gtk_box_pack_start (GTK_BOX (gcal), priv->search_bar, FALSE, FALSE, 6);
@@ -1391,18 +1370,12 @@ gnome_calendar_init (GnomeCalendar *gcal)
for (i = 0; i < E_CAL_SOURCE_TYPE_LAST; i++)
priv->clients[i] = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
- priv->config_listener = e_config_listener_new ();
- g_signal_connect (priv->config_listener, "key_changed", G_CALLBACK (config_categories_changed_cb), gcal);
-
priv->current_view_type = GNOME_CAL_DAY_VIEW;
priv->range_selected = FALSE;
setup_config (gcal);
setup_widgets (gcal);
- priv->calendar_menu = e_cal_menu_new("org.gnome.evolution.calendar.view");
- priv->taskpad_menu = e_cal_menu_new("org.gnome.evolution.calendar.taskpad");
-
priv->dn_queries = NULL;
priv->sexp = g_strdup ("#t"); /* Match all */
priv->todo_sexp = g_strdup ("#t");
@@ -1414,6 +1387,21 @@ gnome_calendar_init (GnomeCalendar *gcal)
priv->visible_end = -1;
}
+/* Frees a set of categories */
+static void
+free_categories (GPtrArray *categories)
+{
+ int i;
+
+ if (!categories)
+ return;
+
+ for (i = 0; i < categories->len; i++)
+ g_free (categories->pdata[i]);
+
+ g_ptr_array_free (categories, TRUE);
+}
+
static void
gnome_calendar_destroy (GtkObject *object)
{
@@ -1430,16 +1418,7 @@ gnome_calendar_destroy (GtkObject *object)
if (priv) {
GList *l;
int i;
-
- /* unset the config listener */
- if (priv->config_listener) {
- g_signal_handlers_disconnect_matched (priv->config_listener,
- G_SIGNAL_MATCH_DATA,
- 0, 0, NULL, NULL, gcal);
- g_object_unref (priv->config_listener);
- priv->config_listener = NULL;
- }
-
+
/* 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) {
@@ -1461,6 +1440,11 @@ gnome_calendar_destroy (GtkObject *object)
}
priv->default_client[i] = NULL;
}
+
+ for (i = 0; i < E_CAL_SOURCE_TYPE_LAST; i++) {
+ free_categories (priv->categories[i]);
+ priv->categories[i] = NULL;
+ }
for (i = 0; i < GNOME_CAL_LAST_VIEW; i++) {
if (priv->configs[i])
@@ -1517,22 +1501,12 @@ gnome_calendar_destroy (GtkObject *object)
priv->view_menus = NULL;
}
- if (priv->calendar_menu) {
- g_object_unref (priv->calendar_menu);
- priv->calendar_menu = NULL;
- }
-
- if (priv->taskpad_menu) {
- g_object_unref (priv->taskpad_menu);
- priv->taskpad_menu = NULL;
- }
-
g_free (priv);
gcal->priv = NULL;
}
- if (GTK_OBJECT_CLASS (gnome_calendar_parent_class)->destroy)
- (* GTK_OBJECT_CLASS (gnome_calendar_parent_class)->destroy) (object);
+ if (GTK_OBJECT_CLASS (parent_class)->destroy)
+ (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
}
static void
@@ -2014,137 +1988,36 @@ gnome_calendar_discard_view_menus (GnomeCalendar *gcal)
priv->view_menus = NULL;
}
-/* This is copied/moved from gal-view-instance, only the calendar uses this for a popup menu */
-static void
-gc_set_view(EPopup *ep, EPopupItem *pitem, void *data)
-{
- GnomeCalendar *gcal = data;
-
- if (pitem->type & E_POPUP_ACTIVE)
- gal_view_instance_set_current_view_id(gcal->priv->view_instance, (char *)pitem->user_data);
-}
-
-static void
-gc_save_custom_view(EPopup *ep, EPopupItem *pitem, void *data)
-{
- GnomeCalendar *gcal = data;
-
- gal_view_instance_save_as(gcal->priv->view_instance);
-}
-
-static void
-gc_define_views_response(GtkWidget *d, int id, GnomeCalendar *gcal)
+EPopupMenu *
+gnome_calendar_setup_view_popup (GnomeCalendar *gcal)
{
- if (id == GTK_RESPONSE_OK)
- gal_view_collection_save(gcal->priv->view_instance->collection);
-
- gtk_widget_destroy(d);
-}
-
-static void
-gc_define_views(EPopup *ep, EPopupItem *pitem, void *data)
-{
- GnomeCalendar *gcal = data;
- GtkWidget *dialog = gal_define_views_dialog_new(gcal->priv->view_instance->collection);
-
- g_signal_connect(dialog, "response", G_CALLBACK(gc_define_views_response), data);
- gtk_widget_show(dialog);
-}
+ GnomeCalendarPrivate *priv;
-static EPopupItem gc_popups[] = {
- /* Code generates the path to fit */
- { E_POPUP_BAR, NULL },
- { E_POPUP_RADIO|E_POPUP_ACTIVE, NULL, N_("Custom View"), },
- { E_POPUP_ITEM, NULL, N_("Save Custom View"), gc_save_custom_view },
+ g_return_val_if_fail (gcal != NULL, NULL);
+ g_return_val_if_fail (GNOME_IS_CALENDAR (gcal), NULL);
- /* index == 3, when we have non-custom view */
+ priv = gcal->priv;
- { E_POPUP_BAR, NULL },
- { E_POPUP_ITEM, NULL, N_("Define Views..."), gc_define_views },
-};
+ g_return_val_if_fail (priv->view_instance != NULL, NULL);
-static void
-gc_popup_free (EPopup *ep, GSList *list, void *data)
-{
- 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;
- }
+ return gal_view_instance_get_popup_menu (priv->view_instance);
}
-static void
-gc_popup_free_static (EPopup *ep, GSList *list, void *data)
+void
+gnome_calendar_discard_view_popup (GnomeCalendar *gcal, EPopupMenu *popup)
{
- while (list) {
- GSList *n = list->next;
- EPopupItem *pitem = list->data;
- g_free(pitem->path);
- g_free(pitem);
- g_slist_free_1(list);
- list = n;
- }
-}
-void
-gnome_calendar_view_popup_factory (GnomeCalendar *gcal, EPopup *ep, const char *prefix)
-{
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);
-
- 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);
- }
-
- e_popup_add_items(ep, menus, NULL, gc_popup_free_static, gcal);
+ gal_view_instance_free_popup_menu (priv->view_instance, popup);
}
static void
@@ -2163,6 +2036,22 @@ gnome_calendar_set_pane_positions (GnomeCalendar *gcal)
}
}
+/* Duplicates an array of categories */
+static GPtrArray *
+copy_categories (GPtrArray *categories)
+{
+ GPtrArray *c;
+ int i;
+
+ c = g_ptr_array_new ();
+ g_ptr_array_set_size (c, categories->len);
+
+ for (i = 0; i < categories->len; i++)
+ c->pdata[i] = g_strdup (categories->pdata[i]);
+
+ return c;
+}
+
static void
client_cal_opened_cb (ECal *ecal, ECalendarStatus status, GnomeCalendar *gcal)
{
@@ -2177,39 +2066,24 @@ client_cal_opened_cb (ECal *ecal, ECalendarStatus status, GnomeCalendar *gcal)
source_type = e_cal_get_source_type (ecal);
source = e_cal_get_source (ecal);
- switch (source_type) {
- case E_CAL_SOURCE_TYPE_EVENT:
- e_calendar_view_set_status_message (E_CALENDAR_VIEW (priv->week_view), NULL);
- break;
- case E_CAL_SOURCE_TYPE_TODO:
+ if (source_type == E_CAL_SOURCE_TYPE_EVENT)
+ e_calendar_view_set_status_message (priv->week_view, NULL);
+ else
e_calendar_table_set_status_message (E_CALENDAR_TABLE (priv->todo), NULL);
- break;
- default:
- break;
- }
- switch (status) {
- case E_CALENDAR_STATUS_OK:
- break;
- case E_CALENDAR_STATUS_BUSY:
+
+ if (status == E_CALENDAR_STATUS_BUSY)
return;
- case E_CALENDAR_STATUS_INVALID_SERVER_VERSION:
- e_error_run (NULL, "calendar:server-version", NULL);
- status = E_CALENDAR_STATUS_OK;
- break;
- case E_CALENDAR_STATUS_REPOSITORY_OFFLINE:
- if (source_type == E_CAL_SOURCE_TYPE_EVENT)
- e_error_run (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (gcal))),
- "calendar:prompt-no-contents-offline-calendar", NULL);
- default:
+ if (status != E_CALENDAR_STATUS_OK) {
/* Make sure the source doesn't disappear on us */
g_object_ref (source);
-
+
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));
gtk_signal_emit (GTK_OBJECT (gcal), gnome_calendar_signals[SOURCE_REMOVED], source_type, source);
+
g_object_unref (source);
-
+
return;
}
@@ -2220,7 +2094,7 @@ client_cal_opened_cb (ECal *ecal, ECalendarStatus status, GnomeCalendar *gcal)
switch (source_type) {
case E_CAL_SOURCE_TYPE_EVENT :
msg = g_strdup_printf (_("Loading appointments at %s"), e_cal_get_uri (ecal));
- e_calendar_view_set_status_message (E_CALENDAR_VIEW (priv->week_view), msg);
+ e_calendar_view_set_status_message (priv->week_view, msg);
g_free (msg);
/* add client to the views */
@@ -2234,7 +2108,7 @@ client_cal_opened_cb (ECal *ecal, ECalendarStatus status, GnomeCalendar *gcal)
/* update date navigator query */
update_query (gcal);
- e_calendar_view_set_status_message (E_CALENDAR_VIEW (priv->week_view), NULL);
+ e_calendar_view_set_status_message (priv->week_view, NULL);
break;
case E_CAL_SOURCE_TYPE_TODO :
@@ -2268,7 +2142,7 @@ default_client_cal_opened_cb (ECal *ecal, ECalendarStatus status, GnomeCalendar
switch (source_type) {
case E_CAL_SOURCE_TYPE_EVENT:
- e_calendar_view_set_status_message (E_CALENDAR_VIEW (priv->week_view), NULL);
+ e_calendar_view_set_status_message (priv->week_view, NULL);
break;
case E_CAL_SOURCE_TYPE_TODO:
e_calendar_table_set_status_message (E_CALENDAR_TABLE (priv->todo), NULL);
@@ -2277,18 +2151,13 @@ default_client_cal_opened_cb (ECal *ecal, ECalendarStatus status, GnomeCalendar
break;
}
- switch (status) {
- case E_CALENDAR_STATUS_OK:
- break;
- case E_CALENDAR_STATUS_BUSY:
+ if (status == E_CALENDAR_STATUS_BUSY)
return;
- case E_CALENDAR_STATUS_INVALID_SERVER_VERSION :
- e_error_run (NULL, "calendar:server-version", NULL);
- status = E_CALENDAR_STATUS_OK;
- default:
+
+ if (status != E_CALENDAR_STATUS_OK) {
/* Make sure the source doesn't disappear on us */
g_object_ref (source);
-
+
/* 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));
@@ -2296,10 +2165,11 @@ default_client_cal_opened_cb (ECal *ecal, ECalendarStatus status, GnomeCalendar
/* FIXME Is there a better way to handle this? */
g_object_unref (priv->default_client[source_type]);
priv->default_client[source_type] = NULL;
-
+
gtk_signal_emit (GTK_OBJECT (gcal), gnome_calendar_signals[SOURCE_REMOVED], source_type, source);
+
g_object_unref (source);
-
+
return;
}
@@ -2338,7 +2208,7 @@ open_ecal (GnomeCalendar *gcal, ECal *cal, gboolean only_if_exists, open_func of
msg = g_strdup_printf (_("Opening %s"), e_cal_get_uri (cal));
switch (e_cal_get_source_type (cal)) {
case E_CAL_SOURCE_TYPE_EVENT :
- e_calendar_view_set_status_message (E_CALENDAR_VIEW (priv->week_view), msg);
+ e_calendar_view_set_status_message (priv->week_view, msg);
break;
case E_CAL_SOURCE_TYPE_TODO :
e_calendar_table_set_status_message (E_CALENDAR_TABLE (priv->todo), msg);
@@ -2356,6 +2226,83 @@ open_ecal (GnomeCalendar *gcal, ECal *cal, gboolean only_if_exists, open_func of
return TRUE;
}
+/* Adds the categories from an array to a hash table if they don't exist there
+ * already.
+ */
+static void
+add_categories (GHashTable *categories, GPtrArray *c)
+{
+ int i;
+
+ if (!c)
+ return;
+
+ for (i = 0; i < c->len; i++) {
+ const char *cat;
+ const char *str;
+
+ cat = c->pdata[i];
+ str = g_hash_table_lookup (categories, cat);
+
+ if (!str)
+ g_hash_table_insert (categories, (char *) cat, NULL);
+ }
+}
+
+/* Appends a category from the hash table to the array */
+static void
+append_category_cb (gpointer key, gpointer value, gpointer data)
+{
+ GPtrArray *c;
+ const char *category;
+
+ category = key;
+ c = data;
+
+ g_ptr_array_set_size (c, c->len + 1);
+ c->pdata[c->len - 1] = g_strdup (category);
+
+}
+
+/* Callback from the calendar client when the set of categories changes. We
+ * have to merge the categories of the calendar and tasks clients.
+ */
+static void
+client_categories_changed_cb (ECal *ecal, GPtrArray *categories, gpointer data)
+{
+ GnomeCalendar *gcal;
+ GnomeCalendarPrivate *priv;
+ ECalSourceType source_type;
+ GHashTable *cat_hash;
+ GPtrArray *merged;
+ int i;
+
+ gcal = GNOME_CALENDAR (data);
+ priv = gcal->priv;
+
+ source_type = e_cal_get_source_type (ecal);
+
+ free_categories (priv->categories[source_type]);
+ priv->categories[source_type] = copy_categories (categories);
+
+ /* Build a non-duplicate list of the categories */
+ cat_hash = g_hash_table_new (g_str_hash, g_str_equal);
+ for (i = 0; i < E_CAL_SOURCE_TYPE_LAST; i++) {
+ add_categories (cat_hash, priv->categories[i]);
+ }
+
+ /* Build the pointer array */
+ /* We size it maximally and then to 0 to pre-allocate memory */
+ merged = g_ptr_array_sized_new (g_hash_table_size (cat_hash));
+ g_ptr_array_set_size (merged, 0);
+
+ g_hash_table_foreach (cat_hash, append_category_cb, merged);
+ g_hash_table_destroy (cat_hash);
+
+ cal_search_bar_set_categories (CAL_SEARCH_BAR (priv->search_bar), merged);
+ free_categories (merged);
+}
+
/* Callback when we get an error message from the backend */
static void
backend_error_cb (ECal *client, const char *message, gpointer data)
@@ -2384,6 +2331,7 @@ backend_died_cb (ECal *ecal, gpointer data)
ECalSourceType source_type;
ESource *source;
const char *id;
+ int i;
gcal = GNOME_CALENDAR (data);
priv = gcal->priv;
@@ -2401,7 +2349,7 @@ backend_died_cb (ECal *ecal, gpointer data)
case E_CAL_SOURCE_TYPE_EVENT:
id = "calendar:calendar-crashed";
- e_calendar_view_set_status_message (E_CALENDAR_VIEW (priv->week_view), NULL);
+ e_calendar_view_set_status_message (priv->week_view, NULL);
gtk_signal_emit (GTK_OBJECT (gcal), gnome_calendar_signals[SOURCE_REMOVED], source_type, source);
break;
@@ -2566,6 +2514,7 @@ gnome_calendar_add_source (GnomeCalendar *gcal, ECalSourceType source_type, ESou
}
g_signal_connect (G_OBJECT (client), "backend_error", G_CALLBACK (backend_error_cb), gcal);
+ g_signal_connect (G_OBJECT (client), "categories_changed", G_CALLBACK (client_categories_changed_cb), gcal);
g_signal_connect (G_OBJECT (client), "backend_died", G_CALLBACK (backend_died_cb), gcal);
/* add the client to internal structure */
@@ -2775,7 +2724,7 @@ gnome_calendar_new_task (GnomeCalendar *gcal)
if (!ecal)
return;
- tedit = task_editor_new (ecal, FALSE);
+ tedit = task_editor_new (ecal);
icalcomp = e_cal_model_create_component_with_defaults (model);
comp = e_cal_component_new ();
@@ -3298,17 +3247,3 @@ gnome_calendar_get_view_notebook_widget (GnomeCalendar *gcal)
return GTK_WIDGET(gcal->priv->notebook);
}
-
-ECalMenu *gnome_calendar_get_taskpad_menu (GnomeCalendar *gcal)
-{
- g_return_val_if_fail (GNOME_IS_CALENDAR (gcal), NULL);
-
- return gcal->priv->taskpad_menu;
-}
-
-ECalMenu *gnome_calendar_get_calendar_menu (GnomeCalendar *gcal)
-{
- g_return_val_if_fail (GNOME_IS_CALENDAR (gcal), NULL);
-
- return gcal->priv->calendar_menu;
-}
diff --git a/calendar/gui/itip-utils.c b/calendar/gui/itip-utils.c
index 5b5091206b..b7309a21e8 100644
--- a/calendar/gui/itip-utils.c
+++ b/calendar/gui/itip-utils.c
@@ -30,6 +30,7 @@
#include <libgnome/gnome-i18n.h>
#include <gtk/gtkmessagedialog.h>
#include <gtk/gtkwidget.h>
+#include <gal/util/e-util.h>
#include <libical/ical.h>
#include <Evolution-Composer.h>
#include <e-util/e-dialog-utils.h>
@@ -42,7 +43,6 @@
#include "e-util/e-passwords.h"
#include "calendar-config.h"
#include "itip-utils.h"
-#include "dialogs/cal-attachment.h"
#define GNOME_EVOLUTION_COMPOSER_OAFIID "OAFIID:GNOME_Evolution_Mail_Composer:" BASE_VERSION
@@ -824,64 +824,9 @@ comp_compliant (ECalComponentItipMethod method, ECalComponent *comp, ECal *clien
return clone;
}
-static gboolean
-append_cal_attachments (GNOME_Evolution_Composer composer_server, ECalComponent
- *comp, GSList *attach_list)
-{
- CORBA_char *content_type = NULL, *filename = NULL, *description = NULL;
- CORBA_Environment ev;
- GNOME_Evolution_Composer_AttachmentData *attach_data = NULL;
- struct CalMimeAttach *mime_attach;
- GSList *l;
- gboolean retval = TRUE;
-
- CORBA_exception_init (&ev);
-
- for (l = attach_list; l ; l = l->next) {
- mime_attach = (struct CalMimeAttach *) l->data;
-
- filename = CORBA_string_dup (mime_attach->filename);
- content_type = CORBA_string_dup (mime_attach->content_type);
- description = CORBA_string_dup (mime_attach->description);
-
- attach_data = GNOME_Evolution_Composer_AttachmentData__alloc ();
- attach_data->_length = mime_attach->length;
- attach_data->_maximum = attach_data->_length;
- attach_data->_buffer = CORBA_sequence_CORBA_char_allocbuf (attach_data->_length);
- memcpy (attach_data->_buffer, mime_attach->encoded_data, attach_data->_length);
-
- GNOME_Evolution_Composer_attachData (composer_server,
- content_type, filename, description,
- TRUE, attach_data,
- &ev);
- if (BONOBO_EX (&ev)) {
- g_warning ("Unable to add attachments in composer");
- retval = FALSE;
- }
-
- CORBA_exception_free (&ev);
- if (content_type != NULL)
- CORBA_free (content_type);
- if (filename != NULL)
- CORBA_free (filename);
- if (description != NULL)
- CORBA_free (description);
- if (attach_data != NULL) {
- CORBA_free (attach_data->_buffer);
- CORBA_free (attach_data);
- }
- g_free (mime_attach->filename);
- g_free (mime_attach->content_type);
- g_free (mime_attach->description);
- g_free (mime_attach->encoded_data);
- }
-
- return retval;
-}
-
gboolean
itip_send_comp (ECalComponentItipMethod method, ECalComponent *send_comp,
- ECal *client, icalcomponent *zones, GSList *attachments_list)
+ ECal *client, icalcomponent *zones)
{
GNOME_Evolution_Composer composer_server;
ECalComponent *comp = NULL;
@@ -918,10 +863,6 @@ itip_send_comp (ECalComponentItipMethod method, ECalComponent *send_comp,
retval = TRUE;
goto cleanup;
}
- } else if (to_list == NULL || to_list->_length == 0) {
- /* if we don't have recipients, return */
- retval = FALSE;
- goto cleanup;
}
cc_list = GNOME_Evolution_Composer_RecipientList__alloc ();
@@ -992,12 +933,7 @@ itip_send_comp (ECalComponentItipMethod method, ECalComponent *send_comp,
g_warning ("Unable to place iTip message in composer");
goto cleanup;
}
-
- if (attachments_list) {
- if (append_cal_attachments (composer_server, comp, attachments_list))
- retval = TRUE;
- }
-
+
if (method == E_CAL_COMPONENT_METHOD_PUBLISH) {
GNOME_Evolution_Composer_show (composer_server, &ev);
if (BONOBO_EX (&ev))
@@ -1020,11 +956,6 @@ itip_send_comp (ECalComponentItipMethod method, ECalComponent *send_comp,
if (top_level != NULL)
icalcomponent_free (top_level);
- if (users) {
- g_list_foreach (users, (GFunc) g_free, NULL);
- g_list_free (users);
- }
-
if (to_list != NULL)
CORBA_free (to_list);
if (cc_list != NULL)
@@ -1207,6 +1138,8 @@ itip_publish_comp (ECal *client, gchar *uri, gchar *username,
SoupMessage *msg;
SoupUri *real_uri;
char *ical_string;
+ char *prompt;
+ gboolean remember = FALSE;
toplevel = e_cal_util_new_top_level ();
icalcomponent_set_method (toplevel, ICAL_METHOD_PUBLISH);
diff --git a/calendar/gui/migration.c b/calendar/gui/migration.c
index fb8f0b2f8c..1764c2f6e1 100644
--- a/calendar/gui/migration.c
+++ b/calendar/gui/migration.c
@@ -40,6 +40,7 @@
#include <gtk/gtkmain.h>
#include <gtk/gtklabel.h>
#include <gtk/gtkprogressbar.h>
+#include <gal/util/e-util.h>
#include <libecal/e-cal.h>
#include <e-util/e-bconf-map.h>
#include <e-util/e-folder-map.h>
@@ -47,7 +48,6 @@
#include <libedataserver/e-xml-hash-utils.h>
#include "calendar-config.h"
#include "calendar-config-keys.h"
-#include "e-cal-event.h"
#include "migration.h"
static e_gconf_map_t calendar_display_map[] = {
@@ -708,8 +708,6 @@ migrate_calendars (CalendarComponent *component, int major, int minor, int revis
{
ESourceGroup *on_this_computer = NULL, *on_the_web = NULL, *contacts = NULL;
ESource *personal_source = NULL;
- ECalEvent *ece;
- ECalEventTargetComponent *target;
gboolean retval = FALSE;
/* we call this unconditionally now - create_groups either
@@ -843,21 +841,6 @@ migrate_calendars (CalendarComponent *component, int major, int minor, int revis
}
e_source_list_sync (calendar_component_peek_source_list (component), 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_component (ece, calendar_component_peek (), 0);
- e_event_emit ((EEvent *) ece, "component.migration", (EEventTarget *) target);
-
retval = TRUE;
fail:
if (on_this_computer)
diff --git a/calendar/gui/print.c b/calendar/gui/print.c
index 9991f2e7cc..68dcd8cba8 100644
--- a/calendar/gui/print.c
+++ b/calendar/gui/print.c
@@ -22,10 +22,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-#endif
-
#include <sys/stat.h>
#include <sys/time.h>
#include <math.h>
@@ -47,7 +44,6 @@
#include <gal/util/e-util.h>
#include <e-util/e-dialog-widgets.h>
#include <e-util/e-time-utils.h>
-#include <e-util/e-print.h>
#include <libecal/e-cal-time-util.h>
#include "calendar-commands.h"
#include "calendar-config.h"
@@ -70,7 +66,6 @@
* gnome-print keys, but it's commented out. The corresponding code here
* doesn't seem to work either (getting zero margins), so we adopt
* gtkhtml's cheat. */
-
#define TEMP_MARGIN .05
/* The fonts to use */
@@ -177,6 +172,8 @@ struct einfo
int count;
};
+static GnomePrintConfig *print_config = NULL;
+
/* Convenience function to help the transition to timezone functions.
It converts a time_t to a struct tm. */
static struct tm*
@@ -2459,34 +2456,28 @@ void
print_calendar (GnomeCalendar *gcal, gboolean preview, time_t date,
PrintView default_view)
{
- GnomePrintConfig *print_config;
GnomePrintJob *gpm;
GnomePrintContext *pc;
+ int copies, collate;
double l, r, t, b;
- char *old_orientation;
-
+
g_return_if_fail (gcal != NULL);
g_return_if_fail (GNOME_IS_CALENDAR (gcal));
- print_config = e_print_load_config ();
+ if (!print_config)
+ print_config = gnome_print_config_default ();
- /* Don't save the orientation if we guessed it to be nice to the user */
- old_orientation = gnome_print_config_get (print_config, GNOME_PRINT_KEY_PAGE_ORIENTATION);
- if (default_view == PRINT_VIEW_MONTH) {
- if (old_orientation && !strcmp (old_orientation, "R90")) {
- g_free (old_orientation);
- old_orientation = NULL;
- }
-
- gnome_print_config_set (print_config, GNOME_PRINT_KEY_PAGE_ORIENTATION, "R90");
- }
+ copies = 1;
+ collate = FALSE;
+
+ gpm = gnome_print_job_new (print_config);
if (!preview) {
GtkWidget *gpd;
GtkWidget *range;
int view;
- gpd = e_print_get_dialog_with_config (_("Print"), GNOME_PRINT_DIALOG_COPIES | GNOME_PRINT_DIALOG_RANGE, print_config);
+ gpd = gnome_print_dialog_new (gpm, _("Print"), 0);
view = (int) default_view;
range = range_selector_new (gpd, date, &view);
@@ -2519,7 +2510,10 @@ print_calendar (GnomeCalendar *gcal, gboolean preview, time_t date,
gtk_widget_destroy (gpd);
}
- gpm = gnome_print_job_new (print_config);
+ if (default_view == PRINT_VIEW_MONTH)
+ gnome_print_config_set (print_config, GNOME_PRINT_KEY_PAGE_ORIENTATION, "R90");
+ else
+ gnome_print_config_set (print_config, GNOME_PRINT_KEY_PAGE_ORIENTATION, "R0");
pc = gnome_print_job_get_context (gpm);
gnome_print_config_get_page_size (print_config, &r, &t);
@@ -2533,7 +2527,7 @@ print_calendar (GnomeCalendar *gcal, gboolean preview, time_t date,
* gnome_print_config_get_double (print_config, GNOME_PRINT_KEY_PAGE_MARGIN_BOTTOM, &b);
* gnome_print_config_get_double (print_config, GNOME_PRINT_KEY_PAGE_MARGIN_LEFT, &l);
* b = l = TEMP_MARGIN; */
-
+
b = t * TEMP_MARGIN;
l = r * TEMP_MARGIN;
t *= (1.0 - TEMP_MARGIN);
@@ -2568,15 +2562,6 @@ print_calendar (GnomeCalendar *gcal, gboolean preview, time_t date,
gnome_print_job_print (gpm);
}
- /* Don't save the orientation if we guessed it to be nice to the user */
- if (old_orientation) {
- gnome_print_config_set (print_config, GNOME_PRINT_KEY_PAGE_ORIENTATION, old_orientation);
-
- e_print_save_config (print_config);
- g_free (old_orientation);
- }
-
- g_object_unref (print_config);
g_object_unref (gpm);
}
@@ -2584,20 +2569,29 @@ print_calendar (GnomeCalendar *gcal, gboolean preview, time_t date,
void
print_comp (ECalComponent *comp, ECal *client, gboolean preview)
{
- GnomePrintConfig *print_config;
GnomePrintJob *gpm;
GnomePrintContext *pc;
+ int copies, collate;
double l, r, t, b;
g_return_if_fail (comp != NULL);
g_return_if_fail (E_IS_CAL_COMPONENT (comp));
- print_config = e_print_load_config ();
+ if (!print_config)
+ print_config = gnome_print_config_default ();
+
+ gnome_print_config_set (print_config, GNOME_PRINT_KEY_PAGE_ORIENTATION, "R0");
+
+ copies = 1;
+ collate = FALSE;
+
+ gpm = gnome_print_job_new (print_config);
if (!preview) {
GtkWidget *gpd;
- gpd = e_print_get_dialog_with_config (_("Print Item"), GNOME_PRINT_DIALOG_COPIES, print_config);
+ gpd = gnome_print_dialog_new (gpm, _("Print Item"),
+ GNOME_PRINT_DIALOG_COPIES);
gtk_dialog_set_default_response (GTK_DIALOG (gpd),
GNOME_PRINT_DIALOG_RESPONSE_PRINT);
@@ -2624,8 +2618,6 @@ print_comp (ECalComponent *comp, ECal *client, gboolean preview)
gtk_widget_destroy (gpd);
}
- gpm = gnome_print_job_new (print_config);
-
pc = gnome_print_job_get_context (gpm);
gnome_print_config_get_page_size (print_config, &r, &t);
@@ -2656,7 +2648,6 @@ print_comp (ECalComponent *comp, ECal *client, gboolean preview)
gnome_print_job_print (gpm);
}
- g_object_unref (print_config);
g_object_unref (gpm);
}
@@ -2683,60 +2674,27 @@ print_title (GnomePrintContext *pc, const char *title,
}
void
-print_table (ETable *etable, const char *dialog_title, const char *print_header, gboolean preview)
+print_table (ETable *etable, const char *title, gboolean preview)
{
EPrintable *printable;
- GnomePrintConfig *print_config;
GnomePrintContext *pc;
GnomePrintJob *gpm;
double l, r, t, b, page_width, page_height, left_margin, bottom_margin;
- print_config = e_print_load_config ();
+ if (!print_config)
+ print_config = gnome_print_config_default ();
+ gnome_print_config_set (print_config, GNOME_PRINT_KEY_PAGE_ORIENTATION, "R0");
printable = e_table_get_printable (etable);
g_object_ref (printable);
gtk_object_sink (GTK_OBJECT (printable));
e_printable_reset (printable);
- if (!preview) {
- GtkWidget *gpd;
-
- gpd = e_print_get_dialog_with_config (dialog_title, GNOME_PRINT_DIALOG_COPIES, print_config);
-
- gtk_dialog_set_default_response (GTK_DIALOG (gpd),
- GNOME_PRINT_DIALOG_RESPONSE_PRINT);
-
- /* Run dialog */
-
- switch (gtk_dialog_run (GTK_DIALOG (gpd))) {
- case GNOME_PRINT_DIALOG_RESPONSE_PRINT:
- break;
-
- case GNOME_PRINT_DIALOG_RESPONSE_PREVIEW:
- preview = TRUE;
- break;
-
- case -1:
- return;
-
- default:
- gtk_widget_destroy (gpd);
- return;
- }
-
- e_dialog_get_values (gpd);
-
- gtk_widget_destroy (gpd);
- }
-
gpm = gnome_print_job_new (print_config);
-
pc = gnome_print_job_get_context (gpm);
gnome_print_config_get_page_size (print_config, &r, &t);
- /* See top of source for an explanation of this */
-
#if 0
gnome_print_config_get_double (print_config, GNOME_PRINT_KEY_PAGE_MARGIN_TOP, &temp_d);
t -= temp_d;
@@ -2762,7 +2720,7 @@ print_table (ETable *etable, const char *dialog_title, const char *print_header,
gnome_print_translate (pc, left_margin, bottom_margin);
- print_title (pc, print_header, page_width, page_height);
+ print_title (pc, title, page_width, page_height);
if (e_printable_data_left (printable))
e_printable_print_page (printable, pc,
@@ -2782,7 +2740,40 @@ print_table (ETable *etable, const char *dialog_title, const char *print_header,
gnome_print_job_print (gpm);
}
- g_object_unref (print_config);
g_object_unref (gpm);
g_object_unref (printable);
}
+
+void
+print_setup (void)
+{
+ GtkWidget *ps;
+
+ if (!print_config)
+ print_config = gnome_print_config_default ();
+
+ ps = gnome_paper_selector_new (print_config);
+ gtk_widget_show (ps);
+
+#if 0
+ dlg = gtk_dialog_new_with_buttons (_("Print Setup"),
+ NULL, /* FIXME: Set a sensible parent */
+ 0,
+ GNOME_STOCK_BUTTON_OK,
+ GNOME_STOCK_BUTTON_CANCEL,
+ NULL);
+ gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), ps, TRUE, TRUE, 2);
+
+ btn = gtk_dialog_run (GTK_DIALOG (dlg));
+ if (btn == 0) {
+ gchar *name;
+
+ print_config = gnome_paper_selector_get_config (ps);
+
+ name = gnome_paper_selector_get_name (GNOME_PAPER_SELECTOR (ps));
+ paper_info = gnome_paper_with_name (name);
+ }
+
+ gtk_widget_destroy (dlg);
+#endif
+}
diff --git a/calendar/gui/tasks-component.c b/calendar/gui/tasks-component.c
index 60ac1cd868..a817ca8546 100644
--- a/calendar/gui/tasks-component.c
+++ b/calendar/gui/tasks-component.c
@@ -31,7 +31,6 @@
#include <bonobo/bonobo-exception.h>
#include <gconf/gconf-client.h>
#include <libecal/e-cal.h>
-#include <libedataserverui/e-source-selector.h>
#include <shell/e-user-creatable-items-handler.h>
#include "e-cal-model.h"
#include "e-tasks.h"
@@ -41,14 +40,13 @@
#include "migration.h"
#include "comp-util.h"
#include "calendar-config.h"
-#include "e-cal-popup.h"
#include "common/authentication.h"
#include "dialogs/calendar-setup.h"
#include "dialogs/comp-editor.h"
#include "dialogs/copy-source-dialog.h"
#include "dialogs/task-editor.h"
+#include "widgets/misc/e-source-selector.h"
#include "widgets/misc/e-info-label.h"
-#include "widgets/misc/e-error.h"
#include "e-util/e-icon-factory.h"
#define CREATE_TASK_ID "task"
@@ -254,118 +252,137 @@ update_primary_selection (TasksComponentView *component_view)
/* Callbacks. */
static void
-copy_task_list_cb (EPopup *ep, EPopupItem *pitem, void *data)
+add_popup_menu_item (GtkMenu *menu, const char *label, const char *icon_name,
+ GCallback callback, gpointer user_data, gboolean sensitive)
+{
+ GtkWidget *item, *image;
+ GdkPixbuf *pixbuf;
+
+ if (icon_name) {
+ item = gtk_image_menu_item_new_with_label (label);
+
+ /* load the image */
+ pixbuf = e_icon_factory_get_icon (icon_name, E_ICON_SIZE_MENU);
+ image = gtk_image_new_from_pixbuf (pixbuf);
+
+ if (image) {
+ gtk_widget_show (image);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
+ }
+ } else {
+ item = gtk_menu_item_new_with_label (label);
+ }
+
+ if (callback)
+ g_signal_connect (G_OBJECT (item), "activate", callback, user_data);
+
+ if (!sensitive)
+ gtk_widget_set_sensitive (item, FALSE);
+
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+ gtk_widget_show (item);
+}
+
+static void
+copy_task_list_cb (GtkWidget *widget, TasksComponentView *component_view)
{
- TasksComponentView *component_view = data;
ESource *selected_source;
selected_source = e_source_selector_peek_primary_selection (E_SOURCE_SELECTOR (component_view->source_selector));
if (!selected_source)
return;
- copy_source_dialog (GTK_WINDOW (gtk_widget_get_toplevel(ep->target->widget)), selected_source, E_CAL_SOURCE_TYPE_TODO);
+ copy_source_dialog (GTK_WINDOW (gtk_widget_get_toplevel (widget)), selected_source, E_CAL_SOURCE_TYPE_TODO);
}
static void
-delete_task_list_cb (EPopup *ep, EPopupItem *pitem, void *data)
+delete_task_list_cb (GtkWidget *widget, TasksComponentView *component_view)
{
- TasksComponentView *component_view = data;
ESource *selected_source;
- ECal *cal;
- char *uri;
+ GtkWidget *dialog;
selected_source = e_source_selector_peek_primary_selection (E_SOURCE_SELECTOR (component_view->source_selector));
if (!selected_source)
return;
- if (e_error_run((GtkWindow *)gtk_widget_get_toplevel(ep->target->widget),
- "calendar:prompt-delete-task-list", e_source_peek_name(selected_source)) != GTK_RESPONSE_YES)
- return;
-
- /* first, ask the backend to remove the task list */
- uri = e_source_get_uri (selected_source);
- cal = e_cal_model_get_client_for_uri (
- e_calendar_table_get_model (E_CALENDAR_TABLE (e_tasks_get_calendar_table (component_view->tasks))),
- uri);
- if (!cal)
- cal = e_cal_new_from_uri (uri, E_CAL_SOURCE_TYPE_TODO);
- g_free (uri);
- if (cal) {
- if (e_cal_remove (cal, NULL)) {
- if (e_source_selector_source_is_selected (E_SOURCE_SELECTOR (component_view->source_selector),
- selected_source)) {
- e_tasks_remove_todo_source (component_view->tasks, selected_source);
- e_source_selector_unselect_source (E_SOURCE_SELECTOR (component_view->source_selector),
- selected_source);
+ /* create the confirmation dialog */
+ dialog = gtk_message_dialog_new (
+ GTK_WINDOW (gtk_widget_get_toplevel (widget)),
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_YES_NO,
+ _("Task List '%s' will be removed. Are you sure you want to continue?"),
+ e_source_peek_name (selected_source));
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_YES) {
+ ECal *cal;
+ char *uri;
+
+ /* first, ask the backend to remove the task list */
+ uri = e_source_get_uri (selected_source);
+ cal = e_cal_model_get_client_for_uri (
+ e_calendar_table_get_model (E_CALENDAR_TABLE (e_tasks_get_calendar_table (component_view->tasks))),
+ uri);
+ if (!cal)
+ cal = e_cal_new_from_uri (uri, E_CAL_SOURCE_TYPE_TODO);
+ g_free (uri);
+ if (cal) {
+ if (e_cal_remove (cal, NULL)) {
+ if (e_source_selector_source_is_selected (E_SOURCE_SELECTOR (component_view->source_selector),
+ selected_source)) {
+ e_tasks_remove_todo_source (component_view->tasks, selected_source);
+ e_source_selector_unselect_source (E_SOURCE_SELECTOR (component_view->source_selector),
+ selected_source);
+ }
+
+ e_source_group_remove_source (e_source_peek_group (selected_source), selected_source);
+ e_source_list_sync (component_view->source_list, NULL);
}
-
- e_source_group_remove_source (e_source_peek_group (selected_source), selected_source);
- e_source_list_sync (component_view->source_list, NULL);
}
}
+
+ gtk_widget_destroy (dialog);
}
static void
-new_task_list_cb (EPopup *ep, EPopupItem *pitem, void *data)
+new_task_list_cb (GtkWidget *widget, TasksComponentView *component_view)
{
- calendar_setup_new_task_list (GTK_WINDOW (gtk_widget_get_toplevel(ep->target->widget)));
+ calendar_setup_new_task_list (GTK_WINDOW (gtk_widget_get_toplevel (widget)));
}
static void
-edit_task_list_cb (EPopup *ep, EPopupItem *pitem, void *data)
+edit_task_list_cb (GtkWidget *widget, TasksComponentView *component_view)
{
- TasksComponentView *component_view = data;
ESource *selected_source;
selected_source = e_source_selector_peek_primary_selection (E_SOURCE_SELECTOR (component_view->source_selector));
if (!selected_source)
return;
- calendar_setup_edit_task_list (GTK_WINDOW (gtk_widget_get_toplevel(ep->target->widget)), selected_source);
+ calendar_setup_edit_task_list (GTK_WINDOW (gtk_widget_get_toplevel (widget)), selected_source);
}
-static EPopupItem etc_source_popups[] = {
- { E_POPUP_ITEM, "10.new", N_("New Task List"), new_task_list_cb, NULL, "stock_todo", 0, 0 },
- { E_POPUP_ITEM, "15.copy", N_("Copy"), copy_task_list_cb, NULL, "stock_folder-copy", 0, E_CAL_POPUP_SOURCE_PRIMARY },
- { E_POPUP_ITEM, "20.delete", N_("Delete"), delete_task_list_cb, NULL, "stock_delete", 0, E_CAL_POPUP_SOURCE_USER|E_CAL_POPUP_SOURCE_PRIMARY },
- { E_POPUP_ITEM, "30.properties", N_("Properties..."), edit_task_list_cb, NULL, "stock_folder-properties", 0, E_CAL_POPUP_SOURCE_PRIMARY },
-};
-
static void
-etc_source_popup_free(EPopup *ep, GSList *list, void *data)
+fill_popup_menu_cb (ESourceSelector *selector, GtkMenu *menu, TasksComponentView *component_view)
{
- g_slist_free(list);
-}
-
-static gboolean
-popup_event_cb(ESourceSelector *selector, ESource *insource, GdkEventButton *event, TasksComponentView *component_view)
-{
- ECalPopup *ep;
- ECalPopupTargetSource *t;
- GSList *menus = NULL;
- int i;
- GtkMenu *menu;
-
- /** @HookPoint-ECalPopup: Tasks Source Selector Context Menu
- * @Id: org.gnome.evolution.tasks.source.popup
- * @Class: org.gnome.evolution.calendar.popup:1.0
- * @Target: ECalPopupTargetSource
- *
- * The context menu on the source selector in the tasks window.
- */
- ep = e_cal_popup_new("org.gnome.evolution.tasks.source.popup");
- t = e_cal_popup_target_new_source(ep, selector);
- t->target.widget = (GtkWidget *)component_view->tasks;
-
- for (i=0;i<sizeof(etc_source_popups)/sizeof(etc_source_popups[0]);i++)
- menus = g_slist_prepend(menus, &etc_source_popups[i]);
-
- e_popup_add_items((EPopup *)ep, menus, NULL,etc_source_popup_free, component_view);
-
- menu = e_popup_create_menu_once((EPopup *)ep, (EPopupTarget *)t, 0);
- gtk_menu_popup(menu, NULL, NULL, NULL, NULL, event?event->button:0, event?event->time:gtk_get_current_event_time());
-
- return TRUE;
+ ESource *source;
+ gboolean sensitive, system;
+ const char *source_uri;
+
+ source = e_source_selector_peek_primary_selection (E_SOURCE_SELECTOR (component_view->source_selector));
+ sensitive = source ? TRUE : FALSE;
+
+ /* FIXME Gross hack, should have a property or something */
+ source_uri = e_source_peek_relative_uri (source);
+ system = source_uri && !strcmp ("system", source_uri);
+
+ add_popup_menu_item (menu, _("New Task List"), "stock_todo",
+ G_CALLBACK (new_task_list_cb), component_view, TRUE);
+ add_popup_menu_item (menu, _("Copy"), "stock_folder-copy",
+ G_CALLBACK (copy_task_list_cb), component_view, sensitive);
+ add_popup_menu_item (menu, _("Delete"), "stock_delete", G_CALLBACK (delete_task_list_cb),
+ component_view, sensitive && !system);
+ add_popup_menu_item (menu, _("Properties..."), NULL, G_CALLBACK (edit_task_list_cb),
+ component_view, sensitive);
}
static void
@@ -791,7 +808,7 @@ create_new_todo (TasksComponent *task_component, gboolean is_assigned, TasksComp
if (!ecal)
return FALSE;
- editor = task_editor_new (ecal, is_assigned);
+ editor = task_editor_new (ecal);
comp = cal_comp_task_new_with_defaults (ecal);
comp_editor_edit_comp (COMP_EDITOR (editor), comp);
@@ -839,7 +856,6 @@ create_component_view (TasksComponent *tasks_component)
TasksComponentView *component_view;
GtkWidget *selector_scrolled_window, *vbox;
GtkWidget *statusbar_widget;
- AtkObject *a11y;
priv = tasks_component->priv;
@@ -851,9 +867,7 @@ create_component_view (TasksComponent *tasks_component)
/* Create sidebar selector */
component_view->source_selector = e_source_selector_new (tasks_component->priv->source_list);
- e_source_selector_set_select_new ((ESourceSelector *)component_view->source_selector, TRUE);
- a11y = gtk_widget_get_accessible (GTK_WIDGET (component_view->source_selector));
- atk_object_set_name (a11y, _("Task Source Selector"));
+ e_source_selector_set_select_new (component_view->source_selector, TRUE);
g_signal_connect (component_view->source_selector, "drag-motion", G_CALLBACK (selector_tree_drag_motion),
tasks_component);
@@ -922,8 +936,8 @@ create_component_view (TasksComponent *tasks_component)
G_CALLBACK (source_selection_changed_cb), component_view);
g_signal_connect (component_view->source_selector, "primary_selection_changed",
G_CALLBACK (primary_source_selection_changed_cb), component_view);
- g_signal_connect (component_view->source_selector, "popup_event",
- G_CALLBACK (popup_event_cb), component_view);
+ g_signal_connect (component_view->source_selector, "fill_popup_menu",
+ G_CALLBACK (fill_popup_menu_cb), component_view);
/* Set up the "new" item handler */
component_view->creatable_items_handler = e_user_creatable_items_handler_new ("tasks", create_local_item_cb, tasks_component);
diff --git a/camel/ChangeLog b/camel/ChangeLog
new file mode 100644
index 0000000000..329528c6ee
--- /dev/null
+++ b/camel/ChangeLog
@@ -0,0 +1,4865 @@
+2005-02-01 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #72020.
+
+ * camel-filter-driver.c (do_score): don't use
+ camel_folder_set_message_user_tag anymore, use the messageinfo
+ interface.
+ (do_adjust_score): implement missing function.
+
+2005-02-01 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #65329
+
+ * camel-vtrash-folder.c (camel_vtrash_folder_new): api chagne and
+ translate the short name.
+
+ * camel-vee-folder.c (camel_vee_folder_construct): take full-name
+ argument separately from short-name.
+ (camel_vee_folder_new): calculate short-name.
+
+2005-02-01 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #38791 and bug #36142.
+
+ * camel-gpg-context.c (gpg_ctx_op_step): use poll rather than
+ select, and listen to the cancellation fd as well. perform all
+ cancellation here.
+ (gpg_sign): remove cancellation check/processing.
+ (gpg_verify): same.
+ (gpg_encrypt): same.
+ (gpg_decrypt): same.
+ (gpg_ctx_op_step): remove the messy execption handling stuff, it
+ wasn't useful.
+ (gpg_import_keys, gpg_export_keys): clean up exception case.
+
+2005-01-31 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #70303.
+
+ * tests/mime-filter/test1.c: added new test for
+ camel-mime-filter-canon.c
+
+ * camel-mime-filter-canon.c (filter_run): separated out from
+ filter. Fix a case when it finds an embedded "From " not to
+ create "=46rom rom".
+ (complete): Properly canonicalise \n -> \r\n rather than just
+ copying it across (use filter_run now).
+
+2005-01-31 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #69757.
+
+ * providers/imap/camel-imap-store.c (create_folder)
+ (parse_list_response_as_folder_info): free the
+ folder from parse_list_response.
+
+2005-01-28 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #22496.
+
+ * providers/imap/camel-imap-command.c
+ (camel_imap_command_response): check for no and bad [alert] as
+ well as ok [alert].
+
+2005-01-17 Not Zed <NotZed@Ximian.com>
+
+ * tests/lib/folders.c (test_folder_basic): dont enforce local
+ store == no inbox; maildir implements one now.
+
+2005-01-14 Not Zed <NotZed@Ximian.com>
+
+ ** Better fix for #65178.
+
+ * tests/folder/test11.c: new maildir test.
+
+ * camel-store.c (camel_store_folder_uri_equal): dont pass NULL
+ values to compare_folder_name.
+
+ * providers/local/camel-maildir-store.c (get_folder_info):
+ reimplemented, now everything isn't a subfolder of INBOX ('.')
+ anymore.
+ (get_inbox): call main entry point so we don't create multiple
+ inboxes each call.
+ (scan_dirs): re-implemented using non-recursive implementation.
+ (scan_fi, scan_free, scan_equal, scan_hash): helpers for above.
+ (md_canon_name): helper to canonicalise old-format names to new
+ ones.
+ (maildir_hash_folder_name, maildir_compare_folder_name): implement
+ custom folder hash functions so canonicalisation works.
+ (get_folder): canoncalise name before using it. special case '.'
+ aka 'inbox', so that it is implicitly created if accessed.
+ (delete_folder): don't let the caller delete ".".
+ (camel_folder_info_new): removed.
+
+2005-01-24 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #71427.
+
+ * providers/pop3/camel-pop3-store.c (pop3_connect): fix the
+ exception case for re-prompting for the password.
+
+ ** See bug #71625, and bug #56110.
+
+ * providers/imap/camel-imap-folder.c (get_content): when getting a
+ simple content for a message, don't get .TEXT, as that is the full
+ content of a message, not the part itself.
+
+2005-01-17 Not Zed <NotZed@Ximian.com>
+
+ * camel-multipart-signed.c (skip_content): in the message state
+ skip a state, otherwise we go nowhere but down an overflowed stack drain.
+
+2005-01-13 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #69024.
+
+ * providers/nntp/camel-nntp-store.c
+ (nntp_store_get_subscribed_folder_info): emit a folder_changed
+ event if refreshing it added any changes.
+
+2005-01-12 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #47824.
+
+ * camel-multipart-signed.c (parse_content): re-implemented to use
+ camel-mime-parser. For the annoying pathalogical case of re-used
+ multipart boundary markers.
+
+ * camel-mime-parser.c (folder_scan_step): modified the multipart
+ state so that we don't try to match the same boundary again if
+ we've already seen an end boundary for this part. This is for the
+ annoying case of a multipart inside a multipart which shares an
+ identical boundary marker (groupwise!).
+ (camel_mime_parser_tell_start_boundary): new function to indicate
+ the offset of the start of the last boundary.
+
+ * tests/lib/folders.c (test_folder_message_ops): fix test case for
+ deleting message - marks message read too.
+ (test_folder_counts): fix typo.
+
+ * tests/message/test3.c (main): remove the nonfatal fixme & put
+ extra null check for pre/postface text checks.
+
+ * tests/message/test2.c (convert): use size_t for iconv length
+ types.
+
+2005-01-08 Not Zed <NotZed@Ximian.com>
+
+ * camel-sasl-ntlm.c: convert all the unsigned long/long stuff to
+ guint32 since it seems to need 32 bit integers.
+
+ * camel-url.c (camel_url_new_with_base): cast length to int.
+
+ * providers/imap/camel-imap-command.c
+ (imap_command_strdup_vprintf): cast strlen to int.
+
+ * camel-mime-utils.c (append_quoted_pair, header_decode_text): use
+ gssize for length to match dumb g-api.
+
+
+2005-01-20 Not Zed <NotZed@Ximian.com>
+
+ * camel-lock-helper.c (main): since malloc(MAXINT+1) returns a
+ valid pointer, validate the length of the path before using it.
+ set maximum path to 65000 characters. Spotted by Max Vozeler
+ <max@hinterhof.net>
+
+2005-01-11 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #70919.
+
+ * camel-multipart-signed.c (parse_content): treat the post pointer
+ as binary, not 0 terminated.
+
+2004-12-23 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #70556.
+
+ * providers/imap/camel-imap-command.c (imap_read_untagged): scan
+ the non-literal contnet for s-expression brackets, and if we seem
+ to be outside of one, don't try the 'blank line after literal'
+ hack.
+
+2004-12-23 Not Zed <NotZed@Ximian.com>
+
+ * camel-folder-search.c (check_header): treat a missing header as
+ if it was set to "".
+
+2004-12-02 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #69533.
+
+ * providers/imap/camel-imap-command.c (imap_read_untagged): gross
+ hack, if we get a blank line after a literal, assume the server
+ (read: groupwise) made a mistake. Given the complexity of this
+ code i'm not sure it is the server anyway but what can you do.
+
+2004-12-01 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #69776.
+
+ * camel-multipart-signed.c (parse_boundary): take end of data
+ argument, so it handles binary data. Use a binary data string
+ search rather than strstr.
+ (parse_content): dont bother to append a \0 on the end of the
+ data, not binary capable.
+
+2004-11-23 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #69615.
+
+ * camel-smime-context.c (sm_get_passwd): removed. All callers
+ that passed it now pass NULL. This is so we don't override the
+ password function set by e-cert-db. Seems to work ok, I think.
+
+2004-11-22 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #69109.
+
+ * providers/smtp/camel-smtp-transport.c (smtp_helo): if we have
+ ipv6 address and it is numeric, prefix it with "IPv6:"
+
+2004-11-30 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #69982 (maybe).
+
+ * providers/nntp/camel-nntp-stream.c (CAMEL_NNTP_STREAM_LINE):
+ rename to STREAM_LINE_SIZE so it doesn't override the STREAM_LINE
+ enum. Sigh.
+ (camel_nntp_stream_init): fix for above change.
+
+2004-11-28 S.Çağlar Onur <caglar@uludag.org.tr>
+
+ ** See bug #69446.
+
+ * evolution-2.0.2/camel/camel-charset-map.c (camel_charset_iso_to_windows)
+ * evolution-2.0.2/camel/camel-filter-search.c (check_header)
+ * evolution-2.0.2/camel/camel-folder-search.c (check_header)
+ * evolution-2.0.2/camel/camel-folder-summary.c (message_info_new,summary_build_content_info,camel_system_flag)
+ * evolution-2.0.2/camel/camel-html-parser.c (camel_html_parser_attr)
+ * evolution-2.0.2/camel/camel-mime-filter-enriched.c (param_parse,camel_mime_filter_enriched_init)
+ * evolution-2.0.2/camel/camel-mime-parser.c (folder_scan_step,main)
+ * evolution-2.0.2/camel/camel-mime-utils.c (camel_header_param,camel_header_set_param,camel_content_type_is,camel_transfer_encoding_from_string,camel_content_type_format,camel_content_type_simple,camel_header_decode_date,header_raw_find_node)
+ * evolution-2.0.2/camel/camel-sasl-digest-md5.c (decode_data_type)
+ * evolution-2.0.2/camel/providers/imap/camel-imap-command.c (camel_imap_response_free)
+ * evolution-2.0.2/camel/providers/imap/camel-imap-folder.c (camel_imap_folder_new,camel_imap_folder_selected,imap_refresh_info,camel_imap_folder_new,camel_imap_folder_selected)
+ * evolution-2.0.2/camel/providers/imap/camel-imap-store.c (imap_get_capability,imap_connect_online,get_folder_online,get_folder_offline,get_subscribed_folders,folder_hash,get_folders)
+ * evolution-2.0.2/camel/providers/imap4/camel-imap4-engine.c (engine_parse_capability)
+ * evolution-2.0.2/camel/providers/pop3/camel-pop3-store.c (get_folder)
+ * evolution-2.0.2/camel/tests/lib/folders.c: (test_folder_message_ops)
+ some strcasecmp() calls changed with g_ascii_strcasecmp() for Turkish
+ character conversiton problems [ http://www.i18nguy.com/unicode/turkish-i18n.html ]
+
+2004-11-10 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #69109.
+
+ * camel-service.c (cs_getnameinfo): honour the NI_NAMEREQD flag.
+
+ * providers/smtp/camel-smtp-transport.c (smtp_helo): change the
+ nameinfo flags a bit so we know when we got a numeric name and
+ need to wrap it in [].
+
+2004-11-19 Not Zed <NotZed@Ximian.com>
+
+ * providers/imap/camel-imap-store.c (connect_to_server): if we
+ have CAMEL_IMAP_BRAINDAMAGED set, then treat the server as
+ braindamaged ok. Testing for #69533.
+
+2004-11-18 Not Zed <NotZed@Ximian.com>
+
+ * providers/nntp/camel-nntp-stream.c:
+ * providers/nntp/camel-nntp-store.c:
+ * providers/nntp/camel-nntp-summary.c: Make debug run based on
+ 'nntp' debug option.
+
+ * providers/nntp/camel-nntp-store.c (camel_nntp_try_authenticate):
+ retry if the password attempt failed.
+
+ ** See bug #68556.
+
+ * providers/nntp/camel-nntp-store.c (xover_setup): don't overwrite
+ exception if we get a failure.
+ (camel_nntp_command): if we continue, then set the return code to
+ -1, so we re-loop rather than abort.
+
+2004-11-09 Not Zed <NotZed@Ximian.com>
+
+ * providers/imap/camel-imap-folder.c (imap_get_message): before
+ short-circuiting the check for child content, check the child
+ content info is actually correct.
+
+2004-11-08 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #69145.
+
+ * providers/imap/camel-imap-folder.c (get_message): remove spec
+ argument, always calculate it from the content-info.
+ (content_info_incomplete): recursively check the content-info for
+ completeness, not just one level.
+
+2004-11-08 Jeffrey Stedfast <fejj@novell.com>
+
+ Fix for bug #69241.
+
+ * camel-gpg-context.c (gpg_decrypt): We need to extract just the
+ application/pgp-encrypted part from the multipart/encrypted that
+ gets passed in. Added checks to verify that the input part is the
+ correct type as well. Once we have the application/pgp-encrypted
+ part, we need to use camel_data_wrapper_decode_to_stream() in case
+ the part was encoded in any way.
+
+2004-10-27 Julio M. Merino Vidal <jmmv@menta.net>
+
+ * camel-operation.c (camel_operation_shutdown): fix the arguments
+ to pthread_key_delete.
+
+2004-10-12 Not Zed <NotZed@Ximian.com>
+
+ ** See bug ???
+
+ * providers/nntp/camel-nntp-store.c (connect_to_server): if we
+ have a username, try to authenticate before doing anything else.
+
+ ** See bug #67895.
+
+ * providers/nntp/camel-nntp-summary.c (add_range_xover)
+ (add_range_head): use raw_command_auth since we might need auth
+ here.
+
+ * providers/nntp/camel-nntp-store.c (camel_nntp_raw_command_auth):
+ new almost-raw command that also does auth.
+ (xover_setup, connect_to_server, camel_nntp_command): use
+ raw_command_auth since we might need auth here.
+
+2004-10-12 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #67898 and probably others.
+
+ * providers/imapp/camel-imapp-store.c (connect_to_server):
+ * providers/pop3/camel-pop3-store.c (connect_to_server):
+ * providers/imap4/camel-imap4-store.c (connect_to_server_wrapper):
+ * providers/imap/camel-imap-store.c (connect_to_server):
+ * providers/nntp/camel-nntp-store.c (connect_to_server):
+ * providers/smtp/camel-smtp-transport.c (connect_to_server):
+ Fallback to hard-coded port number if the name lookup fails and no
+ port was supplied.
+
+2004-10-11 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #67211.
+
+ * camel-mime-utils.c (camel_header_raw_check_mailing_list):
+ initialise the match start/end pointers, since some regexec's
+ don't seem to do it.
+
+2004-10-09 Sivaiah Nallagatla <snallagatla@novell.com>
+
+ * providers/groupwise/camel-gw-listner.c (add_esource) :
+ add the source uid to list of selected calendar and tasks
+ so that groupwise calendar and tasks are automatically selected
+ (remove_esource) : remove the uids from corresponding gconf keys
+ Fixes #62053
+
+2004-10-08 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #67170.
+
+ * providers/nntp/camel-nntp-store.c
+ (nntp_store_get_cached_folder_info): compare newsgroup names case
+ sensitively.
+
+2004-10-05 Jeffrey Stedfast <fejj@novell.com>
+
+ * camel-service.c (camel_getaddrinfo): Check msg->result for error
+ and set an exception if appropriate.
+ (camel_getnameinfo): Same.
+
+2004-10-04 Jeffrey Stedfast <fejj@novell.com>
+
+ * camel-service.c (camel_getaddrinfo): Add a non-const cast for
+ hints when changing the ai_family member in the IPv6-disabled
+ case. Fixes bug #67028.
+
+2004-10-05 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #67527.
+
+ * camel-service.c (cs_getaddrinfo, cs_getnameinfo): don't loop on
+ EAI_AGAIN, it doesn't appear to mean the same as EAGAIN does with
+ system calls (i guess 'no shit sherlock' really).
+
+2004-09-28 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #66509.
+
+ * providers/nntp/camel-nntp-store.c (camel_nntp_command): if we
+ get an error selecting the folder, disconnect/include it in the
+ re-try loop.
+ (camel_nntp_command): don't set the exception based on errno,
+ exception processing is already done. don't clear it if we're on
+ the 3rd retry.
+
+2004-09-27 Not Zed <NotZed@Ximian.com>
+
+ * providers/nntp/camel-nntp-store.c (nntp_get_folder_info): don't
+ do any locking here.
+ (nntp_store_get_folder_info_all): move the locking here.
+ (nntp_store_get_subscribed_folder_info): and some here too.
+
+ * providers/nntp/camel-nntp-store.c:
+ * providers/nntp/camel-nntp-folder.c: Remove nntp command_lock and
+ just use the service connect lock for serialisation.
+
+2004-09-14 Jeffrey Stedfast <fejj@novell.com>
+
+ * providers/nntp/camel-nntp-store.c (camel_nntp_try_authenticate):
+ s/not/no/ in the error string. Fixes bug #65828.
+
+2004-09-24 Not Zed <NotZed@Ximian.com>
+
+ * camel-vee-store.c (camel_vee_store_finalise): free the unmatched
+ uid values as well.
+
+ * camel-vee-folder.c (vee_folder_remove_folder): lock main folder
+ summary lock before doing the unmatched stuff, so the order is
+ right.
+
+2004-08-25 Ed Catmur <ed@catmur.co.uk>
+
+ ** See bug #63881.
+
+ * camel-vee-store.c:
+ * camel-vee-folder.c: move the unmatched
+ folder onto the camel-vee-store object. Removede the global
+ unmatched folder and associated locks/etc, fixed all the code up
+ to work with the new unmatched folder, if present.
+
+2004-09-27 Not Zed <NotZed@Ximian.com>
+
+ * providers/local/camel-spool-folder.c (camel_spool_folder_new):
+ make sure body indexing is turned off always, missed the ~ bit.
+
+ * providers/local/camel-spool-store.c (camel_folder_info_new):
+ dont take unread count.
+ (spool_fill_fi): copied from mbox more or less.
+ (scan_dir): use fill_fi to setup counts.
+ (spool_new_fi): replace camel_foldeR_info_new with one that does
+ most of the work, also generates uri's properly.
+ (get_folder_info_mbox): make the 'system' inbox name translatable.
+
+ * providers/local/camel-mbox-folder.h: make the
+ camel_mbox_folder_get* functions properly public.
+
+ * providers/local/camel-local-folder.h: pass the object to the
+ virtual methods now, fix all callers.
+
+ * providers/local/camel-spool-folder.c (spool_get_full_path)
+ (spool_get_meta_path): implement, this needs to work differnetly
+ to the parent classes implementations :-/.
+
+2004-09-21 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #63521.
+
+ * camel-movemail.c (camel_movemail): don't clear exception on entry.
+
+ * camel-folder-search.c (match_words_message): use local exception.
+
+ * camel-operation.c (camel_operation_cancel_check): soak up all
+ cancellation requests as soon as we get one.
+ (camel_operation_uncancel): soak up all cancellation reqeusts when
+ we uncancel.
+
+ * camel-uid-cache.c (camel_uid_cache_save): open the file O_TRUNC
+ rather than O_EXCL, otherwise a crash would mean this file never
+ gets updated.
+ (camel_uid_cache_save): block cancellation around writes otherwise
+ we could be interupted from old cancellation.
+
+ * providers/local/camel-local-folder.c
+ (camel_local_folder_construct): don't clear exception here, just
+ don't pass it to summary load.
+
+ * providers/pop3/camel-pop3-store.c (pop3_connect): only clear the
+ exception when we received one we handled.
+
+ * camel-filter-driver.c (close_folder): if exception is already
+ set, don't pass it to folder.sync().
+
+ * camel-lock.c (camel_lock_folder): don't clear the exception
+ here, if it came in set its a programming error.
+
+ * camel-filter-driver.c (camel_filter_driver_filter_message): if
+ the exception is set after evaluating the expression, stop
+ immediately.
+
+2004-09-13 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #47821.
+
+ * camel-service.c: removed the old hostent based hostname interfaces.
+
+ * camel-sasl-kerberos4.c (krb4_challenge): new hostname interfaces.
+
+ * camel-sasl-gssapi.c (gssapi_challenge): new hostname interfaces.
+
+ * camel-sasl-digest-md5.c (digest_md5_challenge): use new hostname
+ interfaces.
+ (generate_response): just take hostname directly, not hostent.
+
+ * camel-mime-utils.c (camel_header_msgid_generate): use new
+ hostname interfaces.
+
+ * providers/smtp/camel-smtp-transport.c (connect_to_server): fixed
+ to use new addrinfo apis.
+
+ * providers/pop3/camel-pop3-store.c (connect_to_server): fixed to
+ use new addrinfo apis.
+
+ * camel-tcp-stream-ssl.c (stream_connect): try all addresses
+ supplied.
+
+ * camel-tcp-stream.c (camel_tcp_stream_get_remote_address)
+ (camel_tcp_stream_get_local_address): return a sockaddr now, and
+ also the address length. Fixed all implementations and callers.
+ (camel_tcp_stream_connect): use addrinfo rather than hostent for
+ host AND port info. Fixed all implementations and callers.
+
+2004-09-22 Not Zed <NotZed@Ximian.com>
+
+ * camel-folder-summary.c (camel_folder_summary_decode_token):
+ handle a zero-length token read rather than failing.
+
+2004-09-21 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #66199.
+
+ * camel-http-stream.c (stream_read): handle relative url's in
+ redirect.
+ (camel_http_stream_set_proxy): generate the basic auth token for
+ basic proxy auth if we have a user and password.
+
+ * camel-http-stream.c: turn off debug.
+
+2004-09-15 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #0xffff.
+
+ * providers/local/camel-local-folder.c
+ (camel_local_folder_construct): only emit folder_created if we
+ actually created it.
+
+2004-09-03 Not Zed <NotZed@Ximian.com>
+
+ * camel-tcp-stream-ssl.c (stream_connect): make ssl connection
+ async and cancellable, and minor api update to async connection.
+
+2004-08-27 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #64023.
+
+ * providers/nntp/camel-nntp-store.c (camel_nntp_try_authenticate):
+ forget the password if it was wrong.
+
+2004-08-26 Sivaiah Nallagatla <snallagatla@novell.com>
+
+ * providers/groupwise/camel-gw-listner.c
+ (add_calendar_tasks_sources) : change the "CheckList" to "Tasks"
+ as there is another foder called chekclist in groupwise not
+ related to tasks Fixes #64092
+
+2004-08-25 Frederic Crozat <fcrozat@mandrakesoft.com>
+
+ * camel-folder.c (folder_getv): Init one variable (remove warning)
+ and don't redefine it.
+
+2004-08-23 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #63189.
+
+ * providers/imap/camel-imap-store.c (get_subscribed_folders): only
+ LSUB folders we're interested in, and check full name of each path
+ element.
+ (imap_is_subfolder): helper for above.
+
+2004-08-23 Jeffrey Stedfast <fejj@novell.com>
+
+ * providers/imap/camel-imap-store.c (get_folders): Check for an
+ exception from get_folders_online() here so that we don't send
+ commands to an IMAP server after a disconnect for example. See bug
+ #63504 for an example.
+
+2004-08-23 Jeffrey Stedfast <fejj@novell.com>
+
+ * camel-tcp-stream-openssl.c (open_ssl_connection): Call
+ SSL_CTX_set_default_verify_paths() to initialise the certificate
+ database paths. Thanks to Anton Altaparmakov for this fix.
+
+2004-08-21 Sivaiah Nallagatla <snallagatla@novell.com>
+
+ * providers/groupwise/camel-gw-listener.c (account_changed) :
+ if any of the settings required for soap interaction changes
+ try connecting to server and resetup the ESources
+ * providers/groupwise/camel-groupwise-provider.c ": don't
+ check soap ssl setting by default to be in consistent with
+ IMAP
+
+2004-08-16 Not Zed <NotZed@Ximian.com>
+
+ * providers/groupwise/camel-groupwise-provider.c
+ (camel_provider_module_init): pass an exception handle to
+ camel_provider_get.
+
+2004-08-13 Jeffrey Stedfast <fejj@novell.com>
+
+ * providers/imap4/camel-imap4-summary.c (imap4_summary_fetch_all):
+ Use g_ptr_array_sized_new() rather than using set_size() after
+ creating a GPtrArray so that array->len starts out at 0.
+ (imap4_summary_fetch_flags): Same.
+
+2004-08-13 Sivaiah Nallagatla <snallagatla@novell.com>
+
+ * providers/groupwise/camel-gw-listener.c (account_changed):
+ remove the cal/taksks sources when account is disbaled. Also do
+ not try to to create sources when a disabled account is changed to
+ Novell Groupwise
+ (camel_gw_listener_construct): do not add the disbaled accounts
+ to exitsting groupwise accounts list
+
+2004-08-13 Sivaiah Nallagatla <snallagatla@novell.com>
+
+ * providers/groupwise/camel-groupwise-provider.c: update ssl
+ setting label and title of the soap settings section. Fixes #62747
+
+2004-08-13 Rodney Dawes <dobey@novell.com>
+
+ * camel-sasl-gssapi.c: Handle et/comm_err.h as well as the
+ normal comm_err.h
+
+2004-08-11 Jeffrey Stedfast <fejj@novell.com>
+
+ Fix for bug #62771
+
+ * camel-mime-utils.c (append_quoted_pair): New function to append
+ a string of text that may contain quoted-pairs.
+ (header_decode_text): Now takes a ctext argument specifying
+ whether or not to expect comments and to handle them.
+ (camel_header_decode_string): Pass FALSE as ctext argument.
+ (camel_header_format_ctext): New function to format text|comment
+ header field bodies.
+
+2004-08-10 Not Zed <NotZed@Ximian.com>
+
+ * providers/groupwise/camel-gw-listener.c
+ (get_addressbook_names_from_server): fix for e_passwords api
+ change, and handle reprompting as well.
+
+2004-08-06 Jeffrey Stedfast <fejj@novell.com>
+
+ * providers/imap4/camel-imap4-summary.c (untagged_fetch_all): Call
+ camel_operation_progress().
+ (imap4_summary_fetch_all): Setup info we need for progress
+ reporting.
+ (imap4_summary_fetch_flags): Same.
+
+2004-08-04 Rodney Dawes <dobey@novell.com>
+
+ * camel-charset-map.c: #include <gal/util/e-iconv.h>
+
+2004-08-03 Jeffrey Stedfast <fejj@novell.com>
+
+ * camel-url-scanner.c (camel_url_scanner_scan): In the case of
+ start() or end() failing, loop starting with the first character
+ immediately following the failed match position. Fixes bug #62136.
+
+2004-08-03 Jeffrey Stedfast <fejj@novell.com>
+
+ * providers/imap4/camel-imap4-store.c (imap4_construct): Pass a
+ reconnect func.
+
+ * providers/imap4/camel-imap4-engine.c
+ (camel_imap4_engine_iterate): Reconnect if needed.
+ (camel_imap4_engine_new): Now takes a reconnect func.
+
+2004-07-30 Jeffrey Stedfast <fejj@novell.com>
+
+ * providers/imap4/camel-imap4-engine.c
+ (camel_imap4_engine_capability): This needs to prequeue the
+ CAPABILITY command rather than queue it normally for the case of
+ reconnecting.
+ (camel_imap4_engine_namespace): Same.
+
+2004-07-30 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-mime-utils.c (camel_header_encode_string): Similar fix as
+ below in a later if-statement. Thanks to Suresh for spotting this
+ one.
+
+2004-07-28 Jeffrey Stedfast <fejj@novell.com>
+
+ * camel-mime-utils.c (camel_header_encode_string): Fixed an ABR
+ that may have been responsible for bug #62029.
+
+2004-07-29 Sivaiah Nallagatla <snallagatla@novell.com>
+
+ * proivders/groupwise/camel-groupwise-provider.c: Add an entry to
+ specify POA address and a check box to say whehter ssl has to be
+ used for SOAP or not
+ (groupwise_auto_detect_cb): new function to automatically fill POA
+ address with host specified in receiving mail page
+ (camel_provider_module_init): use the new auto_detect funcntion
+
+ * providers/groupwise/camel-gw-listener.c (modify_esource)
+ (account_changed, add_calendar_tasks_sources)
+ (remove_calendar_tasks_sources, get_addressbook_names_from_server)
+ (add_addressbook_sources, modify_addressbook_sources)
+ (remove_addressbook_sources): while forming the uri, use the value
+ from new poa_address setting instead of url->host. Also use ssl
+ setting from the new check box provider instaed of imap one
+ (get_addressbook_names_from_server): display an error to user when
+ connection cpuld not be established with server during account
+ setup
+
+2004-07-26 Jeffrey Stedfast <fejj@novell.com>
+
+ * camel-charset-map.c (camel_charset_best_mask): Changed the logic
+ slightly to only match certain charsets if the locale matches
+ (Macedonians don't want to use koi8-r for example).
+
+2004-07-27 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #61841.
+
+ * providers/groupwise/camel-groupwise-provider.c: added junk settings.
+
+2004-07-27 Jeffrey Stedfast <fejj@novell.com>
+
+ * providers/imap4/camel-imap4-engine.c
+ (camel_imap4_engine_prequeue): Changed to be the same prototype as
+ engine_queue().
+ (engine_prequeue_folder_select): Updated.
+
+ * providers/imap4/camel-imap4-store.c (connect_to_server): Use
+ engine_prequeue() for STARTTLS in case we are reconnecting and
+ already have a command queue.
+ (imap4_try_authenticate): Use prequeue() here too.
+ (imap4_reconnect): Moved all the connect logic in here.
+ (imap4_connect): just lock and call reconnect().
+
+2004-07-27 Sivaiah Nallagatla <snallagatla@novell.com>
+
+ Fixes #61454
+
+ * providers/groupwise/camel-groupwise-provider.c
+ (camel_provider_module_init): do not set transport object for
+ groupwise provider. We want user to use SMTP itself instead of
+ "Novell Groupwise"
+
+2004-07-26 Jeffrey Stedfast <fejj@novell.com>
+
+ * providers/imap4/camel-imap4-store.c (connect_to_server): Don't
+ instantiate an engine here. Instead, take an engine as an argument
+ (it has a service pointer) and connect using that. Also, if
+ connect fails, don't unref the engine.
+ (connect_to_server_wrapper): Now also takes an engine argument
+ rather than a service argument.
+ (imap4_try_authenticate): Now also takes an engine argument.
+ (imap4_connect): Pass the engine to connect/auth functions rather
+ than the store.
+ (imap4_query_auth_types): Updated.
+ (imap4_disconnect): Don't unref the engine here.
+ (camel_imap4_store_init): Create the engine here.
+ (imap4_get_folder_info): Can't check engine == NULL to know to
+ connect (that was a broken check anyway).
+
+ * providers/imap4/camel-imap4-engine.c (camel_imap4_engine_new):
+ Now simply takes a service argument rather than a session and url.
+ (camel_imap4_engine_next_token): Set the state to DISCONNECTED.
+ (camel_imap4_engine_eat_line): Same.
+ (camel_imap4_engine_line): Same.
+ (camel_imap4_engine_literal): Same.
+
+2004-07-22 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #61761.
+
+ * providers/pop3/camel-pop3-engine.c (camel_pop3_engine_iterate):
+ if we get an io error, move every current/active and queued
+ command to the done queue and mark as failed.
+
+2004-07-19 Jeffrey Stedfast <fejj@novell.com>
+
+ * providers/imap/camel-imap-store.c (get_subscribed_folders): Free
+ result after parsing it. Fixes a leak.
+
+2004-07-19 Not Zed <NotZed@Ximian.com>
+
+ * camel-mime-filter-canon.c (filter): only copy 5 chars after the
+ F if we actually have "From ", otherwise we might have F.{,4}\n
+ instead and break eol canonicalisation. For #53355.
+
+2004-07-16 Not Zed <NotZed@Ximian.com>
+
+ * camel-gpg-context.c: Added some debug stuff.
+
+2004-07-15 Jeffrey Stedfast <fejj@novell.com>
+
+ * providers/imap/camel-imap-folder.c (imap_transfer_online): Don't
+ grab the connect_lock before calling refresh_info so that we avoid
+ the deadlock in bug #61551.
+
+2004-07-14 Jeffrey Stedfast <fejj@novell.com>
+
+ Fix for bug #61538
+
+ * camel-process.c (camel_process_fork): Same.
+
+ * camel-filter-driver.c (pipe_to_system): Fixed strings
+
+2004-07-12 Sivaiah Nallagatla <snallagatla@novell.com>
+
+ * providers/groupwise/camel-gw-listener.c (add_esource)
+ (modify_esource, add_addressbook_source)
+ (modify_addressbook_sources): pass "use_ssl" value to these
+ functions and set it on e-source
+ (add_calendar_tasks_source): read the "use_ssl" param from camel
+ url and pass it to add_esource) calls
+ (get_addressbook_names_from_server): use "https" or http depending
+ upon whther ssl is enabled or not
+ (account_changed): compare urls from account instead of uris
+ formed to know wheter somehting in the account changed
+
+2004-07-09 Not Zed <NotZed@Ximian.com>
+
+ ** This is no guarantee of security, but its just a helper to
+ prevent old memory accidentally being included/used elsewhere.
+
+ * camel-smime-context.c (sm_decrypt): mark the output stream
+ 'secure'.
+
+ * camel-gpg-context.c (gpg_decrypt): set the output stream to
+ secured, so we automagically blank it out on finalise.
+
+ * camel-stream-mem.c (camel_stream_mem_set_secure): set the
+ memory-stream 'secured', all we do at the moment is blank out the
+ buffer on finalise.
+ (camel_stream_mem_set_byte_array, camel_stream_mem_finalize):
+ clear memory if owner and secured. kill dead comment.
+ (clear_mem): utilitiy to set memory to 0xABADF00D
+
+2004-07-08 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #61186.
+
+ * camel-cipher-context.c (camel_cipher_sign):
+ (camel_cipher_verify, camel_cipher_encrypt, camel_cipher_decrypt):
+ Add preliminary progress reporting.
+
+2004-07-07 Chris Toshok <toshok@ximian.com>
+
+ * providers/groupwise/Makefile.am (INCLUDES): use
+ CAMEL_GROUPWISE_CFLAGS.
+ (libcamelgroupwise_la_LIBADD): use CAMEL_GROUPWISE_LIBS.
+
+2004-07-02 Christian Neumair <chris@gnome-de.org>
+
+ * camel-smime-context.c: s/Can't/Cannot/.
+
+2004-06-30 Jeffrey Stedfast <fejj@novell.com>
+
+ * providers/imap4/camel-imap4-search.c (imap4_body_contains): Set
+ the size of the ptrarray to prevent potentially realloc'ing
+ several times.
+
+2004-06-29 Jeffrey Stedfast <fejj@novell.com>
+
+ * providers/imap4/camel-imap4-command.c
+ (camel_imap4_command_newv): Aded a new %formatter 'V' which takes
+ a string vector (needed for SEARCH).
+
+ * providers/imap4/camel-imap4-search.[c,h]: New source files
+ implementing search functionality.
+
+ * providers/imap4/camel-imap4-folder.c (imap4_sync_flag): Use the
+ new public version of imap4_get_uid_set().
+ (imap4_transfer_messages_to): Same.
+ (camel_imap4_folder_new): Create a search context.
+ (camel_imap4_folder_finalize): Unref the search context.
+ (camel_imap4_folder_class_init): Override the search methods.
+ (imap4_search_by_expression): New.
+ (imap4_search_by_uids): New.
+ (imap4_search_free): New.
+
+ * providers/imap4/camel-imap4-utils.c (camel_imap4_get_uid_set):
+ Moved here from camel-imap4-folder.c
+
+2004-06-29 Not Zed <NotZed@Ximian.com>
+
+ * camel-vee-store.c (vee_rename_folder): add any parents of the
+ new name before we actually do the rename so the rename has
+ somewhere to go to. #60775.
+
+2004-06-28 Not Zed <NotZed@Ximian.com>
+
+ * providers/local/camel-maildir-folder.c (maildir_folder_getv):
+ override CAMEL_FOLDER_NAME arg so we can translate "." into
+ "Inbox".
+
+ * providers/local/camel-maildir-store.c (camel_folder_info_new):
+ take url argument directly, fixes a memleak.
+ (camel_folder_info_new): make the toplevel "." into "Inbox"
+ always.
+ (maildir_rename_folder): dont let users rename inbox.
+
+2004-06-27 Jeffrey Stedfast <fejj@novell.com>
+
+ * camel-url-scanner.c (camel_url_web_end): More fixes.
+
+2004-06-25 Jeffrey Stedfast <fejj@novell.com>
+
+ * camel-url-scanner.c (camel_url_web_end): Fixed to handle :pass
+ in proto://user:pass@host. Fixes bug #60104.
+
+2004-06-24 Jeffrey Stedfast <fejj@novell.com>
+
+ * providers/pop3/camel-pop3-store.c (connect_to_server): Error out
+ and set an exception if camel_pop3_engine_new() returns NULL
+ (which it can do now).
+
+ * providers/pop3/camel-pop3-engine.c (get_capabilities): No longer
+ reads the greeting.
+ (camel_pop3_engine_new): Reads the greeting itself and returns
+ NULL if an error occurs (like stupid braindamaged piece of shit
+ POP servers that spew debug prinfs).
+
+ * providers/local/camel-spool-folder.c (spool_lock): If we fail to
+ lock the folder, close the lockfd and reset it to -1. Fixes bug
+ #54680.
+
+2004-06-23 Jeffrey Stedfast <fejj@novell.com>
+
+ * providers/imap4/camel-imap4-store.c (imap4_get_folder_info):
+ First LIST/LSUB the toplevel folder, and then LIST/LSUB the
+ subfolders (it needs to be 2 commands to work properly).
+ (imap4_delete_folder): CLOSE the folder we are about to DELETE if
+ it is currently SELECTED.
+
+ * providers/imap/camel-imap-provider.c (imap_url_equal): Same.
+
+ * providers/imap4/camel-imap4-provider.c (imap4_url_equal): Check
+ the protocol.
+
+ * providers/imap4/camel-imap4-store.c (imap4_build_folder_info):
+ Hide password, etc info in the fi->uri's.
+ (imap4_create_folder): Don't bother to use
+ imap4_get_folder_info(), we can construct the fi ourselves.
+ (imap4_delete_folder): Emit the folder_deleted signal and
+ construct an fi ourselves.
+ (imap4_subscribe_folder): Same.
+ (imap4_unsubscribe_folder): Same.
+
+ * providers/imap4/camel-imap4-provider.c: Specify that the
+ fragment is the path.
+
+2004-06-21 Christian Kellner <gicmo@xatom.net>
+
+ * camel-service.c (service_setv): Really set the path if tag is
+ CAMEL_SERVICE_PATH.
+
+2004-06-21 Jeffrey Stedfast <fejj@novell.com>
+
+ * camel-mime-filter-enriched.c (enriched_to_html): Fixed a number
+ of issues described in bug #49497.
+
+2004-06-18 Jeffrey Stedfast <fejj@novell.com>
+
+ * camel.c (camel_shutdown): Call camel_mime_utils_shutdown() and
+ camel_operation_shutdown().
+
+ * camel-operation.c (camel_operation_shutdown): New function.
+
+ * camel-mime-utils.c (camel_mime_utils_shutdown): New function to
+ clean up the compiled regexes.
+
+ * camel-stream-buffer.c (set_vbuf): Need to re-init sbf->ptr and
+ sbf->end too, or we'll be sorrryy!
+
+2004-06-18 Not Zed <NotZed@Ximian.com>
+
+ * camel-exception.h (CAMEL_EXCEPTION_INITIALISER): setup for
+ static inititialisation.
+
+2004-06-17 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/imap4/camel-imap4-folder.c (uidset_init): init
+ tail->last to (guint32) -1, so that index = tail->last + 1 will
+ start at 0 at the top of uidset_add() :-)
+
+2004-06-17 Rodney Dawes <dobey@novell.com>
+
+ * camel-mime-filter-tohtml.c: Add support for the webcal, callto, and
+ h323 URIs when we get them in mails
+
+2004-06-17 Jeffrey Stedfast <fejj@novell.com>
+
+ * camel-mime-filter-tohtml.c: Don't foolishly unmunge From_
+ lines. First off, we don't even know if our input stream came from
+ an mbox file and secondly, the ">From " may have been intentional
+ by the author. We Just Don't Know (tm).
+
+2004-06-15 Jeffrey Stedfast <fejj@novell.com>
+
+ * providers/imap4/camel-imap4-store.c (imap4_build_folder_info):
+ Make sure we have elements in the array, if not then we're done
+ (return a NULL fi).
+
+2004-06-17 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/imap4/camel-imap4-folder.c (imap4_get_uid_set): Fixed
+ to work properly. It was getting ranges wrong before sometimes
+ which was making me lose mail! Ugh.
+
+ Thanks to Christian Kellner for pointing out these bugs (and
+ submitting the original patch for service_setv)
+
+ * camel-service.c (service_setv): Don't use (tag &
+ CAMEL_ARG_IGNORE) to determine if we should ignore this
+ tag. CAMEL_ARG_IGNORE is not a bit flag.
+
+ * providers/imap/camel-imap-store.c (imap_setv): Don't use (tag &
+ CAMEL_ARG_IGNORE) to determine if we should ignore this
+ tag. CAMEL_ARG_IGNORE is not a bit flag.
+
+2004-06-16 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/imap4/camel-imap4-folder.c (imap4_refresh_info): Only
+ force a re-update of all FLAGS if this folder wasn't in the
+ SELECTED state. Otherwise, simply send a NOOP.
+
+ * providers/imap4/camel-imap4-summary.c: Added a 'first' member to
+ the imap_fetch_all_t struct so we can use that as a base offset in
+ our GPtrArray, allowing us to limit resource consumption which
+ could otherwise get quite large. Also added a ChangeInfo member
+ that was needed for changes to untagged_fetch_all().
+ (imap4_fetch_all_add): Use fetch->first as a base offset and
+ change int i to guint32 i. Also updated to sue the fetch->changes.
+ (imap4_fetch_all_update): Same.
+ (untagged_fetch_all): Same - this is where it is really valuable,
+ since we can avoid adding elements to the GPtrArray that we won't
+ even use. Also needed to change code a big in case index <
+ fetch->first (which could happen if a server notified us of a
+ FLAGS change for a message we didn't request info about).
+ (imap4_fetch_all_free): Free the ChangeInfo.
+ (imap4_summary_fetch_all): Init fetch->changes and fetch->first.
+ (imap4_summary_fetch_flags): Same.
+ (camel_imap4_summary_flush_updates): Only request envelope info if
+ first <= summary->exists. Avoids needless queries.
+ (info_uid_sort): #if 0'd
+ (camel_imap4_summary_flush_updates): No need to sort the summary -
+ this should never have been needed. I can't remember why I did
+ this...
+
+2004-06-15 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-gpg-context.c (gpg_verify): Use
+ camel_multipart_signed_get_content_stream() rather than getting
+ the first part and canonicalising it ourselves. Fixes bug #60159.
+
+ * providers/imap4/camel-imap4-stream.c (camel_imap4_stream_init):
+ Init have_unget to FALSE. Don't set unget to NULL, it's no longer
+ a pointer.
+ (camel_imap4_stream_finalize): No need to g_free() unget anymore.
+ (camel_imap4_stream_next_token): Check have_unget rather than
+ unget != NULL. Set have_unget to FALSE if we get an unget'd token.
+ (camel_imap4_stream_unget_token): Don't malloc space for an unget
+ token. The unget token is no longer a pointer.
+
+2004-06-14 Not Zed <NotZed@Ximian.com>
+
+ * providers/smtp/camel-smtp-transport.c (smtp_data): use
+ g_ascii_strcasecmp.
+ (smtp_connect): do not re-helo after we've authenticated. This
+ was a misreading of the spec. We must only re-helo after a
+ transport layer negotiation.
+
+2004-06-12 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/imap4/camel-imap4-store.c (imap4_noop): Flush summary
+ updates for the currently selected folder.
+ (imap4_noop): Sync the currently selected folder before sending
+ NOOP.
+
+ * providers/imap4/camel-imap4-summary.c
+ (camel_imap4_summary_set_exists): Don't bother with
+ exists_changed. We don't need it afterall.
+ (camel_imap4_summary_flush_updates): Instead of updating flags if
+ update_flags or exists_changed is set, only bother if update_flags
+ is set or if exists is smaller than the summary count (since
+ updating flags is also sueful for determining which messages have
+ been removed).
+
+2004-06-11 Jeffrey Stedfast <fejj@novell.com>
+
+ * providers/imap4/camel-imap4-folder.c (imap4_refresh_info): Force
+ updating of the emsage flags (normally this only happens if
+ something has changed that warrants rescanning them).
+
+2004-06-11 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/imap4/camel-imap4-folder.c (untagged_fetch): Handle
+ getting FLAGS even though we didn't request it (server can send us
+ FLAGS info if another client changed them recently, for
+ example). Also fixed to handle the fact that not every bit of info
+ has to be in a single untagged FETCH response - it may come in
+ several untagged responses.
+
+ * providers/imap4/camel-imap4-summary.c (envelope_decode_address):
+ Decode the email address name token.
+ (envelope_decode_nstring): rfc2047 decode strings if requested.
+ (decode_envelope): Request that the subject string be rfc2047
+ decoded.
+
+2004-06-11 Not Zed <NotZed@Ximian.com>
+
+ * providers/local/camel-maildir-store.c (get_folder_info): if we
+ scan from "" or top == NULL, then we really want to scan from "."
+ instead.
+
+ * camel-url.c (camel_url_new_with_base): don't check the for a
+ character after the # before extracting the fragment. An empty
+ fragment is still allowed and # should never be added to the path.
+ See Rfc1808 2.4.1.
+
+2004-06-11 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/imap4/camel-imap4-summary.c
+ (camel_imap4_summary_flush_updates): Don't bother scanning summary
+ info if EXISTS was 0.
+ (camel_imap4_summary_set_uidvalidity): Emit the folder_changed
+ event after clearing the summary.
+ (camel_imap4_summary_expunge): Emit the folder_changed event after
+ removing the message from the summary.
+ (camel_imap4_summary_set_exists): Only set exists_changed if the
+ new and old exists values are different.
+ (imap4_fetch_all_add): Emit a folder_changed signal if any new
+ info's were added.
+ (imap4_fetch_all_update): Emit a folder_changed event if any uids
+ were removed or otherwise updated.
+ (camel_imap4_summary_expunge): Use seqid-1 to determine the actual
+ summary index.
+ (camel_imap4_summary_flush_updates): Added some logic to
+ distinguish between EXISTS value changing because it changed and
+ because messages got expunged.
+
+ * providers/imap4/camel-imap4-folder.c (imap4_sync): Flush updates
+ after an EXPUNGE and don't unset expunge if we didn't delete
+ anything (the logic was wrong anyway).
+ (imap4_refresh_info): Implemented.
+
+2004-06-10 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/imap4/camel-imap4-engine.c
+ (camel_imap4_engine_handle_untagged_1): Don't always try and parse
+ a RESP-CODE in the BYE case as the RESP-CODE is optional.
+
+2004-06-10 Jeffrey Stedfast <fejj@novell.com>
+
+ * providers/imap4/camel-imap4-store.c (imap4_build_folder_info):
+ If flags does not include FOLDER_INFO_FAST, get the total/unread
+ counts for the folder-info.
+
+ * providers/imap4/camel-imap4-engine.c (engine_parse_status):
+ Removed.
+ (camel_imap4_engine_handle_untagged_1): Don't handle untagged
+ STATUS responses anymore. Let the STATUS requestor handle them
+ instead.
+
+ * providers/imap4/camel-imap4-utils.c
+ (camel_imap4_untagged_status): New function to parse untagged
+ status events.
+
+2004-06-10 Not Zed <NotZed@Ximian.com>
+
+ * camel-filter-driver.c (camel_filter_driver_filter_message): add
+ some :filter debug.
+ (open_folder): only ignore the get_folder exception if we have a
+ default folder, otherwise don't. See #59727.
+
+ * providers/nntp/camel-nntp-store.c (camel_nntp_command): move the
+ stream based checking into the loop, after we connect. Fixes a
+ crash.
+
+2004-06-09 Jeffrey Stedfast <fejj@novell.com>
+
+ * camel-gpg-context.c (gpg_verify): Fixed a case where it was
+ possible to double-free the gpg context.
+ (gpg_verify): If we don't have a public key, then the signature is
+ just BAD always.
+
+2004-06-09 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-gpg-context.c (gpg_verify): Don't assign trust to be
+ UNKNOWN if gpg sent us a NODATA status.
+
+2004-06-07 Jeffrey Stedfast <fejj@novell.com>
+
+ * providers/imap4/camel-imap4-folder.c (camel_imap4_folder_new):
+ Load the entire summary, not just the summary header. This way
+ when the user opens the folder, we don't do a complete re-sync
+ with the server unnecessarily.
+
+ * providers/imap4/camel-imap4-summary.c (untagged_fetch_all): New
+ info's always have a uid of "", so don't checkagainst NULL.
+
+2004-06-06 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/imap4/camel-imap4-store.c (imap4_rename_folder):
+ Implemented, mostly. Still need to update state on the renamed
+ folder object if instantiated and rename the on-disk cache
+ directory.
+
+ * providers/imap4/camel-imap4-folder.c
+ (camel_imap4_folder_finalize): Free the cachedir.
+ (camel_imap4_folder_new): Init the cachedir and load the saved
+ summary before updating it against the server summary.
+
+ * providers/imap4/camel-imap4-store.c
+ (camel_imap4_store_finalize): Free the storage_path.
+ (imap4_construct): Init the storage_path.
+
+2004-06-04 Jeffrey Stedfast <fejj@novell.com>
+
+ * providers/imap4/camel-imap4-folder.c (camel_imap4_folder_new):
+ Initialise the folder->summary and force an update of the message
+ info cache by selecting the folder and flushing the updates to the
+ imap4 summary object.
+
+ * providers/imap4/camel-imap4-store.c (imap4_get_folder_info):
+ Lock the connect_lock before we check if the engine is NULL and
+ after we connect (assuming we need to), initialise the engine
+ pointer again.
+ (imap4_get_folder_info): Doh. Need to escape the "'s in the LIST
+ command string.
+ (imap4_get_folder): Same.
+
+ * camel-stream-buffer.c (stream_flush): Fixed to work
+ properly. After we've flushed the buffer, we want to set sbf->ptr
+ to sbf->buf, we don't want to do sbf->ptr += written, that'll just
+ corrupt our next write.
+
+ * providers/imap4/camel-imap4-store.c (connect_to_server_wrapper):
+ Duh. If the user doesn't care about SSL/TLS - use USE_SSL_NEVER,
+ not USE_SSL_ALWAYS.
+
+ * camel-tcp-stream-ssl.c (stream_flush): Always just return 0,
+ don't try to PR_Sync() - fsync on a socket causes an error.
+
+ * providers/imap4/camel-imap4-command.c
+ (camel_imap4_command_step): Set exceptions when write/flush fail.
+
+ * providers/imap4/camel-imap4-engine.c
+ (camel_imap4_engine_take_stream): Set an exception in the case
+ where we get an unexpected greeting from the server.
+
+ * providers/imap4/camel-imap4-store.c (imap4_create_folder):
+ store->dir_sep no longer exists, so query the engine for the
+ directory separator for the parent_folder.
+ (imap4_build_folder_info): CamelFolderInfo no longer has a path
+ component.
+
+2004-06-03 Not Zed <NotZed@Ximian.com>
+
+ * providers/nntp/camel-nntp-store.c (camel_nntp_command):
+ disconnect if we get an io error or user cancellation.
+ (nntp_disconnect_online): reset current folder.
+ (connect_to_server): and here too just to make sure.
+
+ * providers/nntp/camel-nntp-folder.c (nntp_folder_sync_online):
+ only save the summary, don't update from server, thats what
+ refresh info does.
+ (nntp_folder_download_message): fix exception handling.
+ (nntp_folder_cache_message): same.
+ (nntp_folder_get_message): ditto, plus major cleanup.
+ (nntp_folder_download_message): take combined uid so it can cache
+ and lookup properly. duh.
+
+ * providers/nntp/camel-nntp-store.c
+ (nntp_store_get_subscribed_folder_info): if not fast, then open
+ the folder, and update it. Yeah i've given up trying to worry
+ about performance vs usability.
+
+ * providers/nntp/camel-nntp-summary.c (camel_nntp_summary_check):
+ update the storesummary if we update the folder summary. Hmm,
+ isn't duplicated data meant to be a bad thing? :P
+
+ * providers/nntp/camel-nntp-store.c (camel_nntp_store_set_folder):
+ removed, now handled by nntp_command.
+ (nntp_connected): removed, now handled by nntp_command.
+
+ * camel-string-utils.c (camel_tolower): added ascii to-lower
+ function.
+ (camel_toupper): and upper, for completeness.
+
+ * camel-store-summary.c (CAMEL_STORE_SUMMARY_VERSION): bumped file
+ version by 1. This is a mess, version 1 files treated the
+ bitfield 'flags' with bit number values not bits. Messy.
+
+ * providers/nntp/camel-nntp-store-summary.c (store_info_save):
+ write last/first count.
+ (CAMEL_NNTP_STORE_SUMMARY_VERSION): bump version to 1.
+ (store_info_load): if we're loading >= version 1, then load
+ last/first counts.
+
+ * providers/nntp/camel-nntp-store.c
+ (nntp_store_get_folder_info_all): pass the whole line to
+ store_info_from_line, dont strip last/first info.
+ (nntp_store_info_update): renamed from info_new_from_line. only
+ add if not present. handle updates, try and handle unread counts
+ and readonly status.
+
+2004-06-02 Not Zed <NotZed@Ximian.com>
+
+ * providers/nntp/camel-nntp-store.c: setup xover once we've
+ started.
+
+ * providers/nntp/camel-nntp-summary.c: (xover_setup): moved to
+ nntp store.
+
+ * providers/nntp/camel-nntp-folder.c (folder_check)
+ (folder_check_free, camel_nntp_folder_new): remove async summary
+ stuff.
+
+ * providers/nntp/camel-nntp-store.c (camel_nntp_command): take
+ exception argument again, and folder argument. do retry logic and
+ auth logic differently.
+ (camel_nntp_raw_command): raw command interface, dont try
+ reconnect or anything fancy. pass i/o errors straight out, etc.
+ (camel_nntp_try_authenticate): change to return return codes &
+ take exception.
+
+ * providers/nntp/camel-nntp-summary.c (camel_nntp_summary_new):
+ just take path argument.
+ (camel_nntp_summary_check): take a store, and a folder name.
+ (add_range_head, add_range_xover): remove the time based update
+ events, they never had any effect anyway. Take store argument.
+ (xover_setup): take store argument.
+
+ * camel-folder-search.c (search_match_threads): remove debug.
+
+2004-06-01 Not Zed <NotZed@Ximian.com>
+
+ ** A few fixes for better rfc compliance, and cleaner code.
+
+ * camel-mime-utils.c (header_encode_param): a bunch of logic
+ cleanups with new util functions.
+ (header_decode_init): setup a new type ATTR_CHAR, for
+ attribute-char.
+
+ * tests/misc/test2.c (main): new test for rfc2184 stuff.
+
+ * camel-mime-utils.c (header_convert): helper to convert between
+ charsets.
+ (rfc2184_decode): fix a bunch of logic problems and use the helper
+ above to simplify code.
+ (decode_param_token): removed, not needed.
+ (header_decode_rfc2184_param): removed, not needed.
+ (header_decode_param): removed, not needed. ugh.
+ (header_decode_param_list): completely rewritten, hence lack of
+ need of above.
+
+2004-05-31 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-mime-filter-gzip.c (camel_mime_filter_gzip_finalize):
+ Don't leak the zlib stream internals.
+
+2004-05-27 Jeffrey Stedfast <fejj@novell.com>
+
+ Fixes bug #59191.
+
+ * providers/imap/camel-imap-store.c (camel_imap_store_readline):
+ Don't override the exception with g_strerror() since presumably
+ camel_imap_store_is_connected() will have set that for us (and
+ will have a much more accurate exception anyway).
+
+2004-05-26 Dan Winship <danw@novell.com>
+
+ * camel-store.c (camel_store_get_trash): If the store is not a
+ vtrash store, just invoke the virtual method. (In particular,
+ don't assume that the trash folder's name is CAMEL_VTRASH_NAME).
+ If it is a vtrash store, just let camel_store_get_folder() do the
+ work since it's duplicated there anyway. #57114
+ (camel_store_get_junk): Likewise.
+
+2004-05-25 Sivaiah nallagatla <snallagatla@novell.com>
+ * providers/groupwise/came;-gw-listener.c (add_addressbook_sources):
+ set port property on e-source
+
+2004-05-25 Sivaiah Nallagatla <snallagatla@novell.com>
+
+ * providers/groupwise/camel-gw-listener.c (lookup_account_info):
+ return NULL when there is no existing gw account with same uid
+
+2004-05-25 Not Zed <NotZed@Ximian.com>
+
+ * camel-store.c (camel_folder_info_build_path): removed.
+
+ * camel-store.h (CamelFolderInfo): removed 'path', fixed all
+ callers.
+ (struct _CamelStore): removed 'dir_sep' fixed all uses.
+
+2004-05-25 Sivaiah Nallagatla <snallagatla@novell.com>
+
+ * providers/groupwise/camel-gw-listener.c (add_addressbook_sources)
+ (add_calendar_tasks_sources) : remove /soap part from uri.
+ make port as a e-source property instead of putting it in uri
+ to amek the uris same as that of mail for password sharing
+
+2004-05-24 Not Zed <NotZed@Ximian.com>
+
+ * camel-mime-utils.c (camel_header_newsgroups_decode):
+ fix/rearrange logic. It was using the wrong working pointer.
+
+2004-05-24 Sivaiah Nallagatla <snallagatla@novell.com>
+
+ * camel-provider.h: Added CAMEL_PROVIDER_CONF_HIDDEN to
+ conf item type enum. This is used by groupwise provider
+
+ * providers/groupwise/camel-groupwise-provider.c: Added
+ CAMEL_PROVIDER_CONF_HIDDEN to groupwise_conf_entries to pass the
+ auth-domain value
+
+ * providers/imap/camel-imap-store.c (imap_auth_loop): Read the
+ auth-domain property from imap url and pass it camel sesstion apis
+
+2004-05-22 Not Zed <NotZed@Ximian.com>
+
+ * camel-store.c: oops, forgot folder_created. Removed locking, the
+ object bag serialises stuff for us.
+ (camel_store_get_junk): same.
+
+ ** Another unread count bug, #58814.
+
+ * camel-store.c (camel_store_class_init): added a folder_opened
+ event.
+ (camel_store_get_folder): emit a folder_opened event whenever we
+ [re] open the physical folder.
+
+2004-05-21 Jeffrey Stedfast <fejj@novell.com>
+
+ * providers/imap/camel-imap-store.c (connect_to_server): Added a
+ workaround for broken IMAP. Hopefully by forcing only the IMAP4
+ command subset, we can work around their suckage.
+
+2004-05-21 Not Zed <NotZed@Ximian.com>
+
+ * camel-session.c (camel_session_get_password): added a 'domain'
+ argument, and rearragned arguments to be prettier and more
+ consistent. Fixed all callers.
+ (camel_session_forget_password): added a domain argument. Fixed
+ all callers.
+
+ ** See #58376.
+
+ * camel-folder.c (set_message_flags): if system flags change, then
+ don't trigger a folder changed event.
+
+ * camel-folder-summary.h (CAMEL_MESSAGE_SYSTEM_MASK): added this
+ to indicate which flags are internal/apps not interested in.
+
+ * camel-folder.c (filter_free): rearrange and use some helpers.
+ (folder_changed): if we're frozen, dont go firing off threads to
+ do any processing on each change, wait until we're called
+ unfrozen. Slight code rearragnement.
+ (filter_filter): add progress to junk learn/unlearn, and separate
+ them.
+
+2004-05-19 Suresh Chandrasekharan <suresh.chandrasekharan@sun.com>
+
+ Fix for #58738 ja_JP.UTF-8: Evolution crashes when certain
+ ASCII/non-ASCII combination is used in mail subject
+
+ * camel-mime-utils.c (camel_header_encode_string) Use
+ camel_mime_is_lwsp for determining word separators,
+ according to rfc822 (which's also same for rfc2047).
+ g_unichar_isspace as word separator is illegal.
+
+2004-05-20 Jeffrey Stedfast <fejj@novell.com>
+
+ Fixes bug #42295 and the infinite loop part of bug #58766 (these 2
+ bugs are almost identical, except the server responses are broken
+ in different ways).
+
+ * providers/imap/camel-imap-folder.c (imap_update_summary): Remove
+ the kludge to re-SELECT the folder to force a re-FETCH of
+ message-info's. This 1) doesn't do what it was meant to do and 2)
+ has a tendency to cause infinite loops with broken servers such as
+ Courier-IMAP.
+ (imap_update_summary): Rework the loop that adds messages to the
+ summary such that if we encounetr an error, we break out and set
+ an exception (we can keep the messages up to the point of failure,
+ but none after that because otherwise our uid-to-seqid mapping
+ would be inconsistant with that of the server and could
+ potentially cause data loss).
+
+2004-05-20 Not Zed <NotZed@Ximian.com>
+
+ * camel-exception.c (camel_exception_setv): re-arrange the code so
+ exception debug will print the expanded description.
+ (camel_exception_set): print exception debug.
+
+ * providers/pop3/camel-pop3-folder.c (pop3_get_message): same.
+
+ * providers/local/camel-mh-folder.c (mh_get_message) *
+ providers/local/camel-mbox-folder.c (mbox_get_message): *
+ providers/local/camel-maildir-folder.c (maildir_get_message):
+ Don't use INVALID_UID for errors which are more system related.
+ And sync up all the error messages.
+
+ * providers/nntp/camel-nntp-folder.c (nntp_folder_get_message):
+ oops, poke the right uid to get the article number.
+ (nntp_folder_cache_message): & here too. Somehow fixes #58700,
+ but i don't know why.
+
+2004-05-19 Not Zed <NotZed@Ximian.com>
+
+ * camel-folder.c (transfer_message_to): copy the messageinfo
+ rather than reference the source folder's one, we poke its flags
+ variable if the message is deleted. And dont re-delete the
+ message if its already deleted.
+
+ * providers/nntp/camel-nntp-folder.c (nntp_folder_get_message):
+ use the article number instead of the messageid. Some servers are
+ just broken.
+ (nntp_folder_cache_message): same. See #58655.
+
+ * camel-smime-context.c (sm_verify_cmsg): import the certs as
+ UsageEmailRecipient as well as signer, and also save the certs
+ always.
+
+ ** See #58641.
+
+ * camel-vee-folder.c (vee_sync): don't rebuild auto-type vfolders.
+ they should always be consistent and it saves a lot of unecessary
+ work.
+
+ * camel-store.c (store_sync): we don't want to sync any vfolders
+ as part of the store sync call. its used for a different purpose
+ in vFolders. oh well its a hack.
+
+2004-05-18 Not Zed <NotZed@Ximian.com>
+
+ * providers/local/camel-maildir-store.c (fill_fi): do the same
+ load of mailbox if we're in slow mode as we did for maildir.
+ #58294.
+
+ * camel-disco-folder.c (disco_expunge_uids): check for NULL
+ implementation before calling it.
+ (disco_sync): similar. Fixes crash #58278.
+
+2004-05-17 Jeffrey Stedfast <fejj@novell.com>
+
+ * camel-folder-search.c (search_match_threads): Fixed a string type-o.
+
+ * camel-smime-context.c (sm_verify_cmsg): Fixed some spelling mistakes.
+
+ * camel-gpg-context.c (gpg_decrypt): If the encrypted block was
+ also signed, set the signature verification status on the Validity
+ structure as well.
+
+2004-05-17 Not Zed <NotZed@Ximian.com>
+
+ ** Bug #56050.
+
+ * providers/imap/camel-imap-store.c (imap_get_trash)
+ (imap_get_junk): similar to below.
+
+ * providers/local/camel-local-store.c (local_get_trash)
+ (local_get_junk): set state file on trash/junk to something we know
+ about.
+
+2004-05-17 Not Zed <NotZed@Ximian.com>
+ * providers/local/camel-mh-store.c (fill_fi): if we have no folder
+ in-memory, load it if we're not doing it fast to get really up to
+ date unread counts. #57616.
+
+2004-05-14 Not Zed <NotZed@Ximian.com>
+
+ * camel-store.c (camel_store_create_folder): don't allow creation
+ of Trash or Junk folders.
+ (camel_store_rename_folder): similar for rename. #57250.
+
+2004-05-13 Not Zed <NotZed@Ximian.com>
+
+ * camel-folder-summary.c (summary_build_content_info): set secure
+ flag if we have a known security type.
+ (flag_names[]): Added secure bit.
+ (summary_build_content_info_message): set secure flag as
+ appropriate.
+ (summary_build_content_info_message): dont set attachments for
+ simple types (non text), only base it on multipart/* stuff.
+ (summary_build_content_info): same.
+
+ * camel-folder-summary.h: added SECURE flag. Indicates signed or
+ encrypted content.
+
+2004-05-12 Jeffrey Stedfast <fejj@novell.com>
+
+ * providers/imap/camel-imap-folder.c (camel_imap_folder_selected):
+ Ignore PERMANENTFLAGS if it gives us an empty set. Works around
+ broken IMAP servers like the one in bug #58355.
+
+2004-05-12 Not Zed <NotZed@Ximian.com>
+
+ * camel-folder-search.c (search_threads): changed to match_threads.
+ (camel_folder_search_search): remove thread matching stuff from here.
+
+2004-05-11 Jeffrey Stedfast <fejj@novell.com>
+
+ * camel-smime-context.c (sm_signing_cmsmessage): Fixed a
+ type-o. Fixes bug #58348.
+
+2004-05-10 Jeffrey Stedfast <fejj@novell.com>
+
+ * camel-mime-filter-gzip.[c,h]: New class for zipping/unzipping
+ gzip streams.
+
+ * camel-mime-filter-yenc.[c,h]: New class for encoding/decoding
+ the crack known as YEncode.
+
+2004-05-07 Not Zed <NotZed@Ximian.com>
+
+ * camel-folder-thread.c (thread_summary): properly set the parent
+ nodes for the re-parented phantom-node children. Wasn't that fun
+ to debug!
+
+ * camel-folder-thread.h: make order and re bitfields, saves 4
+ bytes/node.
+
+2004-05-06 Not Zed <NotZed@Ximian.com>
+
+ * camel-digest-folder.c (digest_search_by_expression)
+ (digest_search_by_uids):
+ * providers/nntp/camel-nntp-folder.c (nntp_folder_search_by_expression)
+ (nntp_folder_search_by_uids):
+ * providers/imap/camel-imap-folder.c (imap_search_by_expression)
+ (imap_search_by_uids):
+ * providers/local/camel-local-folder.c (local_search_by_expression)
+ (local_search_by_uids): use camel_folder_search_search & some minor cleanups.
+
+ * camel-folder-search.c (search_threads): keep track of the match
+ threads option for this search.
+ (camel_folder_search_match_expression): Removed, not used anymore.
+ (camel_folder_search_search): new api entry point for searching, a
+ bit easier to use and needed for thread matching.
+
+ * camel-folder-search.c (camel_folder_search_search): new search
+ api entry point, take a full summary and optionally a subset of
+ uids to match against.
+ (search_match_all): use the uids' passed in to only search a
+ subset of uid's.
+
+ * providers/imap/camel-imap-store.c (connect_to_server): set
+ nodelay and keepalive on the socket.
+
+ * camel-file-utils.c (camel_read): put a timeout on the select.
+ Logic shuffle to match the ssl stuff.
+ (camel_write): Similar.
+
+ * camel-tcp-stream-ssl.c (stream_connect): remove timeout, use
+ CONNECT_TIMEOUT directly.
+ (stream_read): put a timeout on the poll. IO_TIMEOUT. And a
+ little logic shuffle.
+ (stream_write): similar.
+ (CONNECT_TIMEOUT): make this 4 minutes === tcp-raw timeout.
+
+2004-05-05 Not Zed <NotZed@Ximian.com>
+
+ * providers/imap/camel-imap-folder.c (get_message_simple): dont
+ set X-Evolution-Source here anymore, set in caller.
+ (imap_get_message): move the busted server get into the retry
+ loop. only leave the simple cache test outside of it.
+
+2004-05-04 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-session.h: Get rid of #ifdef ENABLE_THREADS stuff, that
+ was done away with a while back and is causing problems for 3rd
+ parties trying to use camel unless they explicityly #define
+ ENABLE_THREADS in their code.
+
+2004-05-04 Christian Kellner <gicmo@xatom.net>
+
+ * providers/groupwise/camel-gw-listener.h: Fixed typo.
+
+2004-05-04 Not Zed <NotZed@Ximian.com>
+
+ ** See #57979.
+
+ * camel-vee-folder.c (subfolder_renamed_update): when the
+ subfolder gets renamed, remove all the old uid's and add the new
+ ones (since the uid is based on the subordinate folder name).
+ (subfolder_renamed): listen to renamed folder events.
+
+ * providers/local/camel-mbox-store.c (get_folder_info): if we're
+ getting a single folder with no children, make sure we fill the
+ counts out. Fixes some rename strangeness.
+
+ * camel-vee-folder.c (camel_vee_folder_add_folder): hook onto the
+ folder renamed signal.
+ (camel_vee_folder_finalise): unhook folder_renamed signal.
+ (camel_vee_folder_remove_folder): same.
+
+2004-05-03 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #57881.
+
+ * camel-vee-folder.c (camel_vee_folder_add_folder): use the
+ folder's change log and frozen count, not our copy.
+ (vee_thaw): dont maintain our frozen count.
+ (vee_freeze): same.
+ (folder_changed_change): if we get changed messages that dont
+ match, make sure they're also propagated as a change too.
+
+ * camel-private.h: remove the freeze_count from
+ camelveefolderprivate. We already have that in the camel folder
+ private.
+
+2004-04-30 Priit Laes <amd@tt.ee>
+
+ * providers/nntp/camel-nntp-summary.c: Fix typo. #53466.
+
+2004-04-28 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/imap/camel-imap-folder.c: Change the UID_SET_LIMIT to
+ 768 (something <1000 octets as suggested by rfc2683). Fixes bug
+ #57389.
+
+ * camel-smime-context.c: Mark exception strings for translation
+ and fixed a spelling mistake.
+
+2004-04-27 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #57659.
+
+ * camel-vee-store.c (vee_get_folder_info): translate Unmatched in
+ the folder display name.
+
+ * camel-store.c (add_special_info): dont translate full_name or
+ path, only do that for name.
+
+2004-04-23 Sarfraaz Ahmed <asarfraaz@novell.com>
+
+ * camel-provider.h: Added HAS_LICENSE flag for allowing camel
+ providers to display license file.
+
+2004-04-22 Not Zed <NotZed@Ximian.com>
+
+ * providers/imap/camel-imap-folder.c (imap_expunge_uids_online)
+ (imap_expunge_uids_resyncing): Send a flag list rather than
+ \Deleted by itself. See #57381.
+
+2004-04-21 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/imap4/camel-imap4-folder.c (imap4_sync_changes): Don't
+ bother doing any work if perm_flags is 0.
+
+2004-04-21 Sivaiah Nallagatla <snallagatla@novell.com>
+
+ * providers/groupwise/Makefile.am: added CAMEL_LIBS to LIBADD
+
+ * providers/groupwise/camel-gw-listener.c
+ (get_addressbook_names_from_server): added new function to get
+ addres book names from server.
+ (add_addressbook_sources) (modify_addressbook_sources) : changed
+ the implementation to use address book returned form above call
+ while creating e-sources
+
+2004-04-21 Not Zed <NotZed@Ximian.com>
+
+ * providers/nntp/camel-nntp-folder.c (camel_nntp_folder_new): set
+ the meta data file on nntp folders.
+
+ * camel-disco-folder.c (disco_refresh_info_online): implement
+ dummy virtual method.
+
+ * providers/nntp/camel-nntp-folder.c
+ (nntp_folder_refresh_info_online): implement. Fixes #57280.
+
+2004-04-19 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/imap4/camel-imap4-folder.c (untagged_fetch): Fixed to
+ not expect ]'s as part of the BODY atom token.
+
+2004-04-16 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-vee-store.c (change_folder): (flags & 0) will never be
+ true. Fixes bug #56982.
+
+2004-04-15 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/imap/camel-imap-utils.c: Changed imap_atom_specials[]
+ to not treat ']' as an atom char (as per rfc3501). Fixes bug
+ #50985.
+
+2004-04-14 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/imap/camel-imap-store.c
+ (imap_check_folder_still_extant): Use %F instead of %S so that the
+ folder name gets properly converted from using '/' path delimeters
+ to whatever the native character the server uses. Should fix bug
+ #56715.
+
+2004-04-14 Not Zed <NotZed@Ximian.com>
+
+ * camel-disco-store.c (set_status): do offline mail syncing (only
+ for open folders so far). If we fail doing syncing or store sync,
+ don't abort.
+
+2004-04-13 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/imap/camel-imap-store.c (get_folder_online):
+ Rearranged some error checking code to fix bug #56405.
+
+2004-04-13 Not Zed <NotZed@Ximian.com>
+
+ * camel-folder.c (folder_getv): implement the new counts, and get
+ them all atomically so they're only calculated once and can return
+ consistent results.
+
+ * camel-folder.h: Added CAMEL_FOLDER_DELETED, CAMEL_FOLDER_JUNKED,
+ and CAMEL_FOLDER_VISIBLE args, to support client display of
+ various values.
+
+2004-04-13 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-folder.h (camel_folder_delete_message): Fix NotZed's fix
+ to not mark messages as unseen. Fixes bug #56879.
+
+2004-04-13 Sivaiah Nallagatla <snallagatla@novell.com>
+
+ * providers/groupwise/camel-gw-listener.c
+ (add_addressbook_sources): change the auth type string from
+ Password to plain/password
+
+2004-04-12 Jeffrey Stedfast <fejj@ximian.com>
+
+ Fix for bug #56878.
+
+ * camel-gpg-context.c (gpg_verify): Don't rely on the exit code of
+ gpg, we already save enough state to decide if the sig is valid
+ without it. Modified to only set BAD if gpg->validsig and
+ gpg->nopubkey are both FALSE. If we get a NO_PUBKEY status
+ message, then it simply means that the the sender could not be
+ verified.
+ (gpg_ctx_parse_status): Listen for NO_PUBKEY status messages.
+
+2004-04-11 Sivaiah Nallagatla <snallagatla@novell.com>
+
+ * providers/groupwise/camel-gw-listener.c
+ (add_addressbook_sources) (modify_addressbook_sources) : add
+ bookname to uri
+
+2004-04-09 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/imap/camel-imap-provider.c: Fix capitalisation of the
+ "mailcheck" section title and move it to the top (so it matches
+ with the UI).
+
+ * providers/imap/camel-imap-folder.c (imap_get_message): Fetch the
+ entire message in one fell swoop even if the message size is
+ larger than 5k *if* the message is a single part. Fixes bug #56686.
+
+2004-04-08 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/imap/camel-imap-store.c (get_folder_online): Changed
+ (!flags & _CREATE) to (!(flags & _CREATE))
+ (get_folder_online): Do what create_folder() does and if the
+ parent folder has \NoInferiors set but contains no messages,
+ delete the parent folder and recreate it before creating the child
+ folder. Fixes bug #56651.
+
+2004-04-08 Not Zed <NotZed@Ximian.com>
+
+ * camel-folder.h (camel_folder_delete_message): always set the
+ seen flag when we delete a message. I demand that this may, or
+ may not, fix #56549.
+
+ * camel-folder.c: include camel-debug.h
+ (camel_folder_set_message_flags): fixed the doco slightly (well
+ reversed the flag and set explanation) and give an example.
+
+ * providers/local/camel-mbox-folder.c
+ (mbox_set_message_user_flag): message changed to folder_changed.
+ (mbox_set_message_user_tag): ditto.
+
+ * camel-vee-folder.c (camel_vee_folder_finalise): dont hook onto
+ message_changed.
+ (camel_vee_folder_add_folder): or unhook.
+ (camel_vee_folder_remove_folder): "
+ (message_changed): or proxy.
+
+ * camel-folder.c (camel_folder_class_init): removed the
+ message_changed event - its redundant, and covered by
+ folder_changed, and just makes life difficult for everything using
+ message_changed/folder_changed (and nothing uses it anyway).
+ (message_changed): removed.
+ (set_message_user_flag): emit a folder_changed event instead of
+ message changed.
+ (set_message_user_tag): "
+ (set_message_flags): "
+
+ * camel-object.h: revered the CAMEL_OBJECT_TYPE change, it should
+ be a global variable access.
+
+2004-04-06 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/imap4/camel-imap4-folder.c: Added mutex locking where
+ appropriate.
+
+ * providers/imap4/camel-imap4-store.c: Added mutex locking where
+ appropriate.
+
+ * camel-folder-summary.h (CAMEL_FOLDER_SUMMARY_TYPE): Defined.
+
+ * camel-object.h (CAMEL_OBJECT_TYPE): Fixed.
+
+ * providers/imap4/camel-imap4-folder.c
+ (camel_imap4_folder_utf7_name): Implemented.
+
+ * providers/imap4/camel-imap4-store.c (imap4_build_folder_info):
+ Use camel_folder_info_build() to build the folder-info tree.
+
+2004-04-06 Not Zed <NotZed@Ximian.com>
+
+ * camel-debug.c: #if 0 out the sys/debugreg stuff.
+
+ ** See bug #56110.
+
+ * providers/imap/camel-imap-folder.c (get_content): more debug!
+ (get_content): if we have no content-type header set on a sub-part
+ of a multipart/digest, then we need to set it to message/rfc822 as
+ in the multipart/digest rfc (2046 or so?).
+
+ * camel-folder.c (camel_folder_get_message): output this stuff as
+ folder debug.
+
+ * providers/imap/camel-imap-folder.c (imap_get_message): add some
+ imap:folder debug.
+ (get_content): get xx.TEXT rather than xx if we're from a message
+ parent part.
+
+ ** See bug #56464.
+
+ * camel-folder.c (camel_folder_transfer_messages_to): do not lock
+ the source here.
+ (transfer_message_to): call the main entry point for get message
+ and append message.
+
+ ** See bug #56050.
+
+ * camel-vee-store.c (vee_delete_folder): delete the state file if
+ it exists.
+
+ * camel-object.c (camel_object_state_write): create the parent dir
+ if we need to. Also spit a warning if we fail in the end.
+
+ * camel-vee-folder.c (camel_vee_folder_new): set the persistent
+ state file location.
+ (vee_sync): write the state file when we sync.
+
+2004-04-05 Not Zed <NotZed@Ximian.com>
+
+ * providers/imap/camel-imap-store.c (get_folders): dont add
+ folders to folders_out here, only in get_folders_add_folders.
+
+ * camel-store.c (camel_folder_info_build): simplify 'list append'
+ since we have next pointer at the head of the struct.
+
+ * providers/imap/camel-imap-store.c (create_folder): fixed
+ "containes" spelling count.
+ (get_folder_online): "
+ (get_folders_add_folders): duh, add the folder info to the
+ folders_out array.
+
+2004-04-02 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-folder.c (camel_folder_get_deleted_message_count): New
+ function to get the deleted message count (used for Outbox count
+ which is total minus deleted).
+
+2004-04-02 Not Zed <NotZed@Ximian.com>
+
+ * camel-exception.c (w): turn this on, this should always be on,
+ it points to real bugs in the code.
+
+ * camel-folder-summary.c (summary_build_content_info): dont set
+ attachments if its a signature block.
+ (summary_build_content_info_message): same.
+
+2004-04-01 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-exception.c (w): Wrap annoying exeption warnings with w().
+
+2004-03-30 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/imap4/camel-imap4-store.c (imap4_get_folder_info):
+ Partially implemented.
+ (imap4_get_folder): Implemented.
+
+2004-03-30 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-mime-utils.c (header_decode_param): Use
+ header_decode_text() rather than rfc2047_decode_word() to decode
+ the brokenly rfc2047 encoded param value string in case it is
+ actually made up of multiple rfc2047 encoded words. Thanks to
+ Andrei Nigmatulin for the fix.
+
+2004-03-30 Not Zed <NotZed@Ximian.com>
+
+ * camel-store.c (camel_store_get_folder_info): added some debug to
+ dump the whole folderinfo tree if store:folder_info is set.
+
+ * providers/imapp/camel-imapp-driver.c: #if 0 out some code, to
+ kill warnings.
+
+ * camel-url-scanner.c: include ctype.h for isspace (wonder if it
+ should use utf8 funcs?).
+
+2004-03-29 Not Zed <NotZed@Ximian.com>
+
+ ** See #56146.
+
+ * providers/imap/camel-imap-store.c (get_folders): check the
+ top-level folders list for duplicates as well.
+ (get_folders_add_folders): split out the folder return merging
+ code from get_folders. Absolute mess of crap to deal with more
+ busted servers.
+
+ * camel-debug.c (camel_debug_start, camel_debug_end): some helpers
+ to wrap debug output for atomicicity.
+
+2004-03-29 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/imap4/camel-imap4-folder.c (camel_imap4_folder_new):
+ Implemented.
+
+ * providers/imap4/camel-imap4-engine.c (engine_parse_namespace):
+ If the namespace begins with "INBOX", canonicalise the INBOX
+ portion (ie, make it all caps).
+
+ * providers/imap4/camel-imap4-store.c (imap4_noop): Implemented.
+
+2004-03-29 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/imap/camel-imap-store.c (get_folder_status): Updated
+ to actually parse the STATUS response into a list of item/value
+ pairs.
+ (create_folder): Updated for above change.
+ (get_folder_counts): Only call get_folder_status() once (we can
+ get both values with a single call now). Fixes a FIXME and might
+ also fix bug #55784.
+
+ * providers/local/camel-mbox-store.c (get_folder_info): Removed
+ debugging printfs.
+
+ * providers/local/camel-local-folder.c
+ (camel_local_folder_construct): Since the folder was *just*
+ created, it shouldn't have any subfolders so set the
+ CAMEL_FOLDER_NOCHILDREN flag (altho, ideally, we wouldn't be
+ guessing these flags at all - rather we'd call get_folder_info()
+ or some such). Fixes bug #56010.
+
+2004-03-29 Radek Doulik <rodo@ximian.com>
+
+ * camel-mime-filter-tohtml.c (html_convert): close pre tag in case
+ we just flush. I am not sure if it's still worth to check for
+ inlen == 0 and handle it specially, but didn't want to make too
+ big changes.
+
+ Fixes #55817
+
+2004-03-29 Not Zed <NotZed@Ximian.com>
+
+ * providers/imap/camel-imap-store.c (get_folder_counts): use
+ object_bag_peek instead of _get, since we dont want to clash/wait
+ for reservations. More #56045 related fixes.
+ (get_folder_counts): revert the lookup/hashtable stuff for the
+ folder, and use object_bag_peek.
+
+ * camel-object.c (camel_object_bag_peek): new method to get an
+ object bag entry without worrying about if its reserved or not.
+
+ * camel-gpg-context.c (gpg_verify): get the content-type off of
+ the multipart-signed, not its container. This seems wrong
+ ... but might fix #56084.
+
+ * providers/imap/camel-imap-store.c (get_folder_counts): remove
+ locking here, we're locked whne we enter.
+ (fill_fi): call refresh_info unlocked. More for #56045.
+
+2004-03-28 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/imap4/camel-imap-folder.[c,h]: New source files
+ implementing the CamelFolder class for the new IMAP4
+ implementation.
+
+ * providers/imap4/camel-imap-summary.[c,h]: New source files
+ implementing the CamelFolderSummary class for the new IMAP4
+ implementation.
+
+2004-03-26 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/imap/camel-imap-folder.c (imap_update_summary):
+ Reverted imap.web.de fix.
+
+2004-03-26 Not Zed <NotZed@Ximian.com>
+
+ * providers/local/camel-maildir-summary.c (flagbits[]): Added new
+ maildir flags D for draft and commented P for forwarded.
+
+ * providers/imap/camel-imap-store.c (get_folder_counts): Instead
+ of looking up the folder in the object bag which will handle
+ reservations and perhaps deadlock, just get the list of opened
+ folders and use them if they're available. Should fix #56045.
+
+2004-03-25 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/imap4/camel-imap-engine.c
+ (camel_imap_engine_parse_resp_code): No longer need to split ']'
+ tokens from atom tokens due to a fixup in the ABNF grammar in
+ rfc3501.
+
+ * providers/imap4/camel-imap-specials.c: Changed ATOM_SPECIALS to
+ include ']' (this is an addition in rfc3501).
+
+ * providers/imap4/camel-imap-store.[c,h]: New Store class for
+ IMAP. Implemnted a bunch of but still got a ways to go.
+
+2004-03-25 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/imap/camel-imap-folder.c (imap_update_summary): If the
+ server is imap.web.de, just ask for all the headers rather than
+ "HEADER.FIELDS.NOT (RECEIVED)". Actually, maybe we should always
+ just query for the entire header block?
+ (imap_get_message): If the server is brain-damaged (that's a
+ technical term), always fetch the message in whole, never bother
+ to try and fetch partial messages (Courier-IMAP gives us the wrong
+ BODY responses fairly often).
+
+ * providers/imap/camel-imap-store.c (connect_to_server): Set
+ store->braindamaged to TRUE if we find the string "Courier-IMAP"
+ in the greeting.
+
+2004-03-25 Jeffrey Stedfast <fejj@ximian.com>
+
+ Fix for bug #55018.
+
+ * providers/imap/camel-imap-store.c (create_folder): Don't allow
+ the user to create folders with #, %, * or the directory separator
+ in the folder name (added the checks for %, * and #).
+ (get_folder_online): Add a check to make sure the folder name is
+ sane before sending a CREATE (ie. we want to allow getting of
+ folders with discouraged characters in them if they exist, but we
+ don't want to allow the user to create them).
+
+2004-03-25 Martyn Russell <ginxd@btopenworld.com>
+
+ * providers/smtp/camel-smtp-provider.c: Removed newline character
+ from the provider description
+
+2004-03-25 Sivaiah Nallagatla <snallagatla@novell.com>
+
+ * providers/groupwise/camel-groupwise-provider.c: removed ldap
+ seetings and added a settng for SOAP port
+
+ * providers/groupwise/camel-gw-listner.h
+ (add_calendar_tasks_sources, remove_calendar_tasks_sources),
+ (modify_calendar_tasks_sources): read port number from url instead
+ of hardcoding. Also removed code for adding e-sources for ldap
+ address book and adding now e-sources for groupwise address book
+
+2004-03-24 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/imap4/camel-imap-engine.c (camel_imap_engine_literal):
+ New convenience wrapper function.
+ (engine_parse_status): Fixed to handle literal mailbox strings.
+
+ * providers/imap4/camel-imap-command.c (camel_imap_command_newv):
+ Changed how %L works - create the CamelIMAPLiteral for our caller
+ instead of expecting them to create it for us. We can autodetect
+ what type of object (stream vs data-wrapper) the literal is, so
+ it's trivial to do.
+
+2004-03-23 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/imap/camel-imap-folder.c (imap_get_message): Reworked
+ the else bit to fix a bug where if we had the BODY structure, we simply
+ wouldn't try fetching the actual message.
+
+2004-03-23 Not Zed <NotZed@Ximian.com>
+
+ * camel-exception.c (camel_exception_setv): use camel debug to add
+ some debug here.
+
+ * camel.c (camel_init): call camel_debug_init().
+
+ * camel-debug.c (camel_debug_init, camel_debug): new util stuff
+ for extended debug options.
+
+ * providers/imap/camel-imap-folder.c (imap_get_message): if we're
+ supposed to be online, check we are online before proceeding.
+ Actually major restructure so we re-try the fetch a couple of
+ times first before failing. i.e. silent reconnect. See #55381.
+
+ * providers/imap/camel-imap-store.c (get_folder_info_online):
+ connect lock around this. was getting a race with mem corruption
+ otherwise.
+
+2004-03-22 Not Zed <NotZed@Ximian.com>
+
+ * camel-mime-utils.c (camel_header_newsgroups_decode)
+ (camel_header_newsgroups_free): decode newsgroups header into a
+ list of newsgroups.
+
+ ** See #55887.
+
+ * providers/nntp/camel-nntp-summary.c (camel_nntp_summary_check):
+ NOOP if we're offline.
+
+ * providers/nntp/camel-nntp-store.c (nntp_connected): spit a
+ warning if we try to do stuff whilst offline, rather than crash.
+
+2004-03-19 Not Zed <NotZed@Ximian.com>
+
+ * camel-disco-store.c (disco_connect): ref the diary before
+ replaying it. it could get unreffed during replay if there's an
+ error and we disconnect.
+
+ * camel-store.c (camel_store_get_folder): no longer use
+ folder_lock, we already have adequate serialisation code here or
+ below here. I hope.
+ (camel_store_get_folder_info): same here.
+
+ * providers/imap/camel-imap-store.h: remove async_thread thing.
+
+2004-03-17 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/imap/camel-imap-folder.c (imap_get_message): Checking
+ that mi->content->type != NULL is no longer good enough to tell if
+ a ContentInfo is complete (ie. contains the parsed BODY
+ response). We need to check that th ContentInfo has children if
+ the part is a multipart of message/rfc822 part. Apparently Zucchi
+ didn't test his camel-folder-summary changes using IMAP.
+
+2004-03-17 Radek Doulik <rodo@ximian.com>
+
+ * camel-folder-summary.h: use 1<<30 for CAMEL_MESSAGE_JUNK_LEARN,
+ 1<<17 was already used by imap provider and maybe others
+
+2004-03-17 Not Zed <NotZed@Ximian.com>
+
+ * providers/local/camel-maildir-store.c: Reverted jeff's fix for
+ #55018, since it wasn't tested, and doesn't work. Wrote an
+ alternate implementation, and tested it at least once. Turns out
+ it was a one line error, it still wasn't tested. Oh well, its
+ rewritten now.
+
+ * See bug #55618.
+
+ * camel-disco-diary.c (camel_disco_diary_new): seek to the end of
+ the file after we open it. c99 apparently says the file merely
+ adds to the end of the file when you write, not that it is opened
+ and positioned at the end of the file (linux's man pages are out
+ of date).
+
+ * camel-folder-summary.c (content_info_new): setup the content
+ type as well, from the headers.
+
+ * providers/imap/camel-imap-summary.c
+ (camel_imap_summary_add_offline): copy size from the source info.
+
+2004-03-15 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-folder.c (folder_rename): Always use '/' to derive the
+ basename of the folder. folder->full_name is always the UNIX-path
+ evrsion of the folder name, no matter what the actual path
+ delimeter is on the underlying store.
+
+ * providers/imap/camel-imap-store.c (get_folder_online): If the
+ initial SELECT fails and CREATE is specified, clear the exception
+ before attempting to CREATE, this way we don't have an exception
+ set even if the CREATE passes. Fixes bug #55607.
+
+2004-03-16 Not Zed <NotZed@Ximian.com>
+
+ * camel-mime-message.c (camel_mime_message_init): rever previous
+ patch. We don't want to set the default mime/type, it'll break
+ stuff.
+
+2004-03-15 Not Zed <NotZed@Ximian.com>
+
+ * providers/local/camel-mbox-store.c (delete_folder): same as
+ below for path.
+
+ * providers/local/camel-local-store.c (delete_folder): NULL out
+ str before looking up the state file using it. Otherwise we
+ double-free str.
+
+ * camel-mime-parser.c (folder_scan_skip_line): we want to scan
+ till in-end-1. If we've been called we're either at the end of
+ data, or we know we have an end of line character within memory.
+ Another case in Bug #53355.
+
+ * providers/imap/camel-imap-folder.c (get_content, get_message):
+ set the mime-type field on the content the same way as
+ construct_from_stream does. Bug #55472.
+
+ * camel-mime-message.c (camel_mime_message_dump): utility function
+ to dump message content to stdout.
+ (camel_mime_message_init): default mime type to message/rfc822.
+
+ * camel.c (camel_init): change camel verbose debug to be an int, a
+ bitmask of debug options.
+
+ * camel-mime-utils.c (camel_header_location_decode): drop embedded
+ whitespace characters, and don't do unquoting, etc. See rfc2557
+ 4.4.2 and rfc2017 3.1.
+
+2004-03-12 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/smtp/camel-smtp-transport.c (smtp_set_exception): Now
+ takes an argument to specify whether disconnecting when respbuf is
+ NULL is safe (to prevent us from recursively disconnecting or
+ disconnecting during a connect).
+
+2004-03-12 Jeffrey Stedfast <fejj@ximian.com>
+
+ Fix for bug #53497.
+
+ * providers/smtp/camel-smtp-transport.c (smtp_helo): Instead of
+ unreffing the streams, call camel_service_disconnect().
+ (smtp_mail): Same.
+ (smtp_rcpt): Same.
+ (smtp_data): Same.
+ (smtp_send_to): Ignore exceptions for smtp_rset(). Also, check
+ that we are connected before we try to send (in Evolution's
+ current usage scenario, this isn't a problem but in the future if
+ we ever try to fire off several messages via the same smtp
+ connection, it may be - especially if RSET failed during the
+ previous send).
+
+2004-03-12 Radek Doulik <rodo@ximian.com>
+
+ * camel-folder.c (folder_changed): clearn the learn bit only if
+ set.
+
+2004-03-12 Jeffrey Stedfast <fejj@ximian.com>
+
+ Fixes for bug #55018.
+
+ * providers/local/camel-local-folder.c
+ (camel_local_folder_construct): Use camel_url_to_string() here
+ too, so we properly encode the fragment.
+
+ * providers/local/camel-mbox-store.c (get_folder_info): Use
+ CamelURL to properly encode the fi->uri. Pass the CamelURL into
+ scan_dir() so that scan_dir() can re-use it (rather than having to
+ malloc/parse/free for each file/dir)
+ (scan_dir): Use camel_url_to_string().
+
+ * providers/local/camel-maildir-store.c (get_folder_info): Same as
+ mbox.
+ (scan_dir): Same as mbox. We also need to set the
+ CAMEL_FOLDER_NOSELECT flag if appropriate.
+
+ * providers/local/camel-mh-store.c (get_folder_info): Same as mbox
+ and maildir.
+ (folders_scan): Now takes a url argument which we pass off to
+ folder_info_new().
+ (recursive_scan): Same.
+ (folder_info_new): Use camel_url_to_string().
+
+2004-03-11 Radek Doulik <rodo@ximian.com>
+
+ * camel-folder.c (camel_folder_set_message_flags): watch for
+ setting JUNK flag, if JUNK_LEARN is not set as well then reset
+ JUNK_LEARN bit
+ (folder_changed): look for junk changes in uid_changed's messages,
+ if these changes request junk filter learning
+ (CAMEL_MESSAGE_JUNK_LEARN bit set) then prepare junk and nonjunk
+ uid arrays, clear CAMEL_MESSAGE_JUNK_LEARN bit so that we don't
+ process it again
+ (folder_changed): start filter thread if there's junk and/or
+ nonjunk arrays
+ (filter_filter): if junk/nonjunk arrays are non-NULL, call junk
+ filter report to learn junk/non-junk messages
+ (filter_free): free junk/nonjunk uids and arrays
+
+ * camel-folder-summary.h: added CAMEL_MESSAGE_JUNK_LEARN to
+ CamelMessageFlags, used when setting CAMEL_MESSAGE_JUNK flag to
+ say that we request junk plugin to learn that message as
+ junk/non-junk
+
+2004-03-12 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/smtp/camel-smtp-transport.c (connect_to_server): If
+ errno is EINTR, set USER_CANCEL instead of SERVICE_UNAVAILABLE or
+ whatever.
+ (smtp_helo): Same.
+ (smtp_auth): Same.
+ (smtp_mail): Same.
+ (smtp_rcpt): Same.
+ (smtp_data): Same.
+ (smtp_rset): Same.
+ (smtp_quit): Same.
+ (smtp_set_exception): Here too.
+ (smtp_auth): If the AUTH response code is not 334, then use
+ smtp_set_exception() to get the most accurate error report we can.
+
+2004-03-11 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-object.c (cobject_state_read): Sanity check that count is
+ <1024 and also use g_try_malloc so that we can recover if malloc
+ fails.
+
+2004-03-11 Not Zed <NotZed@Ximian.com>
+
+ * providers/imap/camel-imap-store.c (no_such_folder): removed
+ this. not sure what it was doing there, a 1 line funciton used
+ once.
+ (get_folder_online): pass exception to camel_imap_command. if we
+ got a user cancel, pass it up. See #55388.
+ (hash_folder_name, compare_folder_name): more g_ascii_strcasecmp
+ stuff.
+
+2004-03-11 Not Zed <NotZed@Ximian.com>
+
+ * camel-vee-store.c (vee_get_folder_info): we need to add the
+ folderinfo always if we're recursive from top. Should fix #52965
+ and maybe the other vfolders not showing on startup bug.
+
+ * providers/imap/camel-imap-store.c (get_one_folder_offline):
+ (parse_list_response_as_folder_info): turn off NOINFERIORS always,
+ translate to nochildren.
+ (imap_store_refresh_folders): check we're updating an imap folder,
+ we could also have trash folders in the store too.
+
+2004-03-08 Not Zed <NotZed@Ximian.com>
+
+ * camel-vee-store.c (vee_get_folder_info): setup virtual/system
+ flags as appropriate.
+ (change_folder): setup flags properly.
+
+ * providers/nntp/camel-nntp-store.c
+ (nntp_store_get_subscribed_folder_info): mark all folders as
+ system folders.
+
+ * providers/local/camel-mh-store.c (fill_fi): add this to setup
+ folderinfo.
+ (folder_info_new): call fill_fi to fill unread/total.
+ (recursive_scan, folders_scan): ahh yeah, so wtf was i thinking,
+ store->flags != get_folder_info flags!!!!
+
+ * providers/local/camel-maildir-store.c (camel_folder_info_new):
+ remove unread count arg & setup total.
+ (fill_fi): setup total field.
+ (scan_dir): remove the code that checked the directory directly -
+ use fill_fi instead. It will more accurately reflect what you get
+ when you visit the folder.
+ (camel_folder_info_new): mark "." as a system folder.
+ (scan_dir): try to setup children/no children flags properly.
+
+ * providers/local/camel-mbox-store.c (fill_fi): setup total field.
+ (scan_dir): init total.
+ (get_folder_info): "
+
+2004-03-05 Not Zed <NotZed@Ximian.com>
+
+ * providers/imap/camel-imap-store.c
+ (parse_list_response_as_folder_info): mark INBOX as a system
+ folder. Can't be renamed/deleted.
+ (fill_fi): setup total field.
+ (get_folder_counts): ditto.
+
+ * camel-store.c (add_special_info): set the system folder flag.
+
+ * camel-store.h: time to fix up the camelfolderinfo mess. fix
+ some member names, and add some type fields. Fixed all uses.
+
+2004-03-04 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #53355.
+
+ * providers/imap/camel-imap-folder.c (get_content): if the parent
+ isn't a message/rfc822 type, we don't want to get the section.TEXT
+ for multipart/signed, we just want to get section.
+
+2004-03-03 Rodrigo Moya <rodrigo@ximian.com>
+
+ * providers/groupwise/camel-gw-listener.c
+ (add_calendar_tasks_sources): use "Calendar" and "Checklist" for the
+ folder names, instead of "Default".
+ (remove_calendar_tasks_sources): remove the correct folder.
+
+2004-03-03 Not Zed <NotZed@Ximian.com>
+
+ * camel-operation.c (camel_operation_uncancel): attempt at
+ uncancelling a cancelled operation.
+
+ * camel-stream-filter.c (do_write, do_write): fun dun diddley un
+ fun. Since we're writing a const buffer, we need to copy it
+ first. See #54937.
+
+2004-02-27 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #54755.
+
+ * camel-vtrash-folder.c (vtrash_append_message)
+ (vtrash_transfer_messages_to): error/fail out if the user tries to
+ copy messages to the trash.
+ (vtrash_transfer_messages_to): use the destination bit not the
+ source bit for moving messages to a vtrash folder.
+
+ * camel-gpg-context.c (gpg_ctx_parse_status): ignore NODATA
+ response, otherwise we abort in a meaningless way. See #52939.
+
+ * providers/imap/camel-imap-utils.c: use g_ascii_str[n]casecmp
+ everywhere.
+ * providers/imap/camel-imap-utils.c (imap_body_decode): fix the
+ sense of the nil check for the subtype of a mutlipart. See
+ #53355.
+
+2004-02-26 Not Zed <NotZed@Ximian.com>
+
+ * camel-session.c (camel_session_check_junk_for_imap)
+ (camel_session_set_check_junk_for_imap): removed.
+
+ * providers/imap/camel-imap-provider.c: Add filter_junk and
+ filter_junk_inbox options to the receive option page.
+
+ * providers/imap/camel-imap-store.c (imap_setv, imap_getv): handle
+ FILTER_JUNK and FILTER_JUNK_INBOX parameters.
+ (imap_setv): conver to switch rather than if statement.
+ (construct): handle url args for filter_junk and
+ filter_junk_inbox.
+
+ * providers/imap/camel-imap-folder.c (camel_imap_folder_new): Set
+ the folder's flags based on the stores junk settings.
+ (imap_update_summary): remove the test for
+ session_check_junk_for_imap, its handled per-store now.
+
+ * camel-folder.c (folder_changed): only check for FILTER_RECENT or
+ FILTER_JUNK to see if we need to do filtering.
+
+ * camel-folder.h (CAMEL_FOLDER_FILTER_JUNK): renamed from
+ CAMEL_FOLDER_SUPRESS_JUNK_TEST (and obviously inverted logic).
+
+2004-03-02 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/local/camel-mbox-summary.c
+ (mbox_summary_encode_x_evolution): Overrides the parent method. We
+ don't want to encode user flags/tags or the size of the header
+ will change and force a complete rewrite of the mbox file.
+
+2004-02-25 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-filter-driver.c (camel_filter_driver_filter_folder): Free
+ the uids *after* reporting Complete, otherwise we get an FMR if
+ our caller didn't pass in the uids.
+
+ * camel-sasl-gssapi.c (gssapi_challenge): #ifdef out another
+ gss_release_buffer() call as this function causes memory
+ corruption if using Heimdal's implementation of Kerberos5. Yay
+ Heimdal.
+
+2004-02-25 Radek Doulik <rodo@ximian.com>
+
+ * camel-folder.c (get_unread_message_count): do not avoid junk
+ mails in unread count
+
+2004-02-25 Not Zed <NotZed@Ximian.com>
+
+ * providers/imap/camel-imap-summary.h (CAMEL_IMAP_MESSAGE_RECENT):
+ moved the RECNET flag into the folder area (bit 17-30).
+
+2004-02-24 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #53876.
+
+ * providers/imap/camel-imap-command.c (camel_imap_command): ref
+ the folder before unreffing store->current_folder, incase they're
+ the same. Do a select anyway.
+
+ * providers/imap/camel-imap-folder.c (imap_refresh_info): keep the
+ connect_lock for longer, imap_rescan for one assumes its locked.
+ Fixes a race selecting the folder for refresh.
+
+2004-02-24 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-stream-process.c: #include <signal.h>, we don't need limits.h
+
+ * camel-store.c (camel_store_folder_uri_equal): New function to do
+ what camel_store_uri_cmp() was supposed to do.
+
+2004-02-23 Rodney Dawes <dobey@ximian.com>
+
+ * providers/local/camel-mbox-store.c (scan_dir): If our folder has
+ a subdir, but no actual children, then we need to unset the flag for
+ CAMEL_FOLDER_CHILDREN
+
+ Fixes #54470
+
+2004-02-23 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-store.c (camel_store_uri_cmp): Removed. Useless/broken
+ function.
+
+2004-02-20 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-provider.c (camel_provider_list): Init list to NULL to
+ prevent the crash in bug #54574.
+
+2004-02-19 Chris Toshok <toshok@ximian.com>
+
+ * camel-smime-context.c: wrap this file with #ifdef ENABLE_SMIME
+ instead of #ifdef HAVE_NSS.
+
+2004-02-19 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/local/camel-mbox-store.c (get_folder): Add sanity
+ checking to the folder name if we are going to create it, just
+ like we do in create_folder().
+
+2004-02-19 Not Zed <NotZed@Ximian.com>
+
+ * providers/*/camel-*-provider.c
+ (camel_provider_module_init): Fixes for api changes.
+
+ * camel-provider.c (camel_provider_load): no longer take session
+ argument. the providers are global resources.
+ (camel_provider_init): dont return anything anymore. (error?)
+ call from camel_init now. Use a recursive lock too.
+
+ * camel-session.c (camel_session_register_provider)
+ (camel_session_list_providers, camel_session_get_provider): Moved
+ to camel-provider, camel_provider_register/list/get.
+ (vee_provider): moved to camel-provider.c
+
+2004-02-18 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-gpg-context.c (gpg_verify): Use the trust to decide the
+ validity signature status. (Better way of solving yesterday's
+ problem)
+
+ * camel-cipher-context.h: Revert change from yesterday.
+
+2004-02-17 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-gpg-context.c (gpg_verify): Set the trust.
+
+ * camel-cipher-context.h: Add a trust metric to signatures.
+
+2004-02-17 Not Zed <NotZed@Ximian.com>
+
+ * camel-vee-store.c (vee_sync): implment, make sync a noop on vee
+ stores. Speeds up exit, so we don't try and sync and re-sync
+ folders multiple times.
+
+ ** See bug #53861.
+
+ * providers/nntp/camel-nntp-summary.c (add_range_xover): Fix from
+ Edd Dumbill <edd@usefulinc.com> to avoid aborting on irrelevently
+ truncated lines.
+
+2004-02-16 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #51045.
+
+ * providers/imap/camel-imap-store.c (fill_fi): similar to mbox
+ version.
+ (get_folder_counts): use fill_fi to try and get folder counts if
+ we're not doing the hard slog.
+ (get_one_folder_offline): use fill_fi to try to get folder counts
+ from open folders or summaries.
+
+ * providers/local/camel-maildir-store.c (fill_fi): similar to mbox
+ version.
+ (scan_dir): use fill_fi to get the unread count now.
+
+ * providers/local/camel-mbox-store.c (fill_fi): helper to lookup
+ unread count either from active folder or from summary file, if
+ it's available.
+ (scan_dir, get_folder_info): use helper above to get folder info.
+
+ * devel-docs/camel-folder-summary.txt: New document describing the
+ format/conventions in the CamelFolderSummary file.
+
+ * providers/nntp/camel-nntp-summary.c (summary_header_load/save):
+ * providers/imapp/camel-imapp-summary.c (summary_header_load/save):
+ * providers/imap/camel-imap-summary.c (summary_header_load/save):
+ Handle versions, per-class version number (1).
+
+ * providers/local/camel-mbox-summary.c (summary_header_load/save):
+ Handle versions properly, add a per-class version (1). Write out the
+ folder size as a size_t rather than 32 bit int.
+
+ * providers/local/camel-local-summary.c (summary_header_load/save):
+ read/write the per-class version number (1).
+
+ * camel-folder-summary.c (summary_header_load): do version
+ checking differently, allow the version to be bumped without
+ aborting the load. Added unread/deleted/junk counts to base
+ header.
+ (summary_header_save): Save out the new-format header. Version
+ bumped to 13.
+
+ * camel.c (camel_init): return 0 rather than spit a compiler warning.
+
+ * camel-file-utils.c (camel_file_util_encode_*_t): macro-ise the
+ type encoder/decoders. Also add size_t encoder/decoder.
+
+2004-02-13 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/imap/camel-imap-store.c (get_folder_online): Same.
+
+ * providers/local/camel-mh-store.c (get_folder): Same as maildir
+ changes.
+
+ * providers/local/camel-maildir-store.c (get_folder): Make
+ exceptions strings consistanmt with the mbox exception strings
+ (and vise versa). Also handle the CAMEL_STORE_FOLDER_EXCL flag.
+
+ * providers/local/camel-mbox-store.c (get_folder): Check
+ CAMEL_STORE_FOLDER_EXCL flag.
+
+ * providers/local/camel-local-store.c (get_folder): Simplified by
+ using camel_mkdir instead of doing it manually.
+
+ * camel-store.c (camel_store_get_folder): If the folder exists in
+ the cache and the O_EXCL flag was passed, return NULL and set an
+ exception.
+
+ * camel-store.h: Added a new CAMEL_STORE_FOLDER_EXCL flag for use
+ with get_folder().
+
+2004-02-12 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-file-utils.c (camel_file_util_encode_string): Since
+ decoding a string doesn't allow strings longer than 65536,
+ truncate strings that are longer than 65536 here. Fixes bug
+ #54319.
+
+2004-02-09 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #53978.
+
+ * providers/local/camel-mbox-store.c: added ".lock" to the list of
+ ignored extensions.
+ (ignore_file): ignore anything ending in ~ too.
+
+ ** See bug #51319.
+
+ * providers/local/camel-local-folder.c
+ (camel_local_folder_construct): re-enable indexing when folder is
+ first opened. Also load defaults if no meta-data present.
+
+2004-02-06 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-provider.c (camel_provider_init): Use strrchr, not strchr.
+
+ * camel-gpg-context.c (gpg_ctx_parse_status): Forget the need_id,
+ not the userid. Fixes bug #53908.
+
+ * camel-store.c (add_special_info): Set a CAMEL_FOLDER_VIRTUAL bit
+ on the special folder info so our UI can know if it is virtual or
+ not (meant for vTrash/vJunk).
+ (camel_store_get_folder_info): Don't add vTrash/vJunk if the
+ NO_VIRTUAL flag bit is set. Used by the subscriptions editor.
+
+2004-02-06 Not Zed <NotZed@Ximian.com>
+
+ * camel-folder.c (camel_folder_set_message_flags): changed to
+ return a boolean to indicate if the flags were actually changed or
+ not. Fixed all implementors.
+
+2004-02-05 Not Zed <NotZed@Ximian.com>
+
+ * providers/local/camel-mbox-store.c (rename_folder): rename
+ .cmeta file too, and fix the recovery order.
+
+ * providers/local/camel-local-store.c (rename_folder): rename the
+ .cmeta file too.
+
+ * providers/local/camel-local-folder.c (local_rename): fix this to
+ use local_get_full_path stuff.
+
+ * camel-store.c (camel_store_rename_folder): fix umr's comparing
+ old and new names.
+
+2004-02-05 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #53553.
+
+ * camel-provider.c (camel_provider_init): changed to return a
+ hashtable of url protocols to CamelProviderModule structs, rather
+ than simple strings.
+
+ * camel-session.c (get_provider): if we load a provider module,
+ mark it as loaded.
+ (ensure_loaded): Check the module loaded flag before trying to
+ load it.
+
+ * providers/local/libcamellocal.urls: Remove spoold from the list,
+ since it doesn't exist anymore. Actually fixes #53553, the rest
+ is to robustify the code.
+
+2004-02-05 Not Zed <NotZed@Ximian.com>
+
+ * camel-session.c (CS_CLASS): dont typecheck cast.
+
+ * camel-store.c (camel_vjunk_folder_new): removed, use
+ vtrash_new(junk).
+ (setup_special): changed to get_special, with a type now, and
+ dont add vtrash folders to the sources.
+ (get_trash, get_junk): down to 1 liners, call get_special
+
+ * camel-vtrash-folder.c (CF_CLASS): dont use cast typecheck macros
+ here, makes debugging easier and removes redundant checks.
+ (camel_vtrash_folder_init): dont set flags here.
+ (camel_vtrash_folder_new): takes a new argument, type, for junk
+ folders too, removed name arg (taken from type).
+ (vtrash_transfer_messages_to): parameterise flag processing.
+
+2004-02-04 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/imap/camel-imap-store.c: Get rid of some unnecessary
+ CAMEL_OBJECT() casts.
+
+ * providers/imap/camel-imap-folder.c (camel_imap_folder_new): The
+ folder_name argument passed to this function is ALWAYS in the UNIX
+ path form (ie. using '/' as the dir sep) and so when getting the
+ short_name, don't use imap_store->dir_sep as the dir sep, always
+ use '/'. Fixes bug #53755 for the IMAP case.
+
+2004-02-04 Jeffrey Stedfast <fejj@ximian.com>
+
+ Fix for bug #53755 (local folders case)
+
+ * providers/local/camel-mbox-store.c (xrename): No longer takes an
+ exception arg, we just set errno. Our caller can take care of
+ setting an exception.
+ (rename_folder): Don't pass an exception to xrename(), we always
+ overwrote if an error occured it anyway.
+ (rename_folder): Rename the .sbd as well.
+
+2004-02-04 Not Zed <NotZed@Ximian.com>
+
+ * camel-store.c (camel_store_sync): added 'expunge' parameter,
+ easier 'empty trash on exit' call.
+ (store_sync): duh, actually pass expunge to folder_sync.
+
+2004-02-04 Not Zed <NotZed@Ximian.com>
+
+ * providers/imap/camel-imap-store.c
+ (parse_list_response_as_folder_info): if we can't add the folder
+ to the summary {i.e. duplicate}, then ignore it. See #53836.
+
+ * camel-store.c (camel_store_delete_folder): changed order around,
+ first try to delete and only remove from the object bag if the
+ delete worked. If vjunk/vtrash enabled, don't allow those to be
+ deleted.
+ (cs_delete_cached_folder): helper to delete the folder if its in
+ the cache, remove it from trash/junk, etc.
+ (camel_store_unsubscribe_folder): changed similarly to
+ delete_folder.
+
+ * camel-vee-store.c (vee_delete_folder): dont do any trash/junk
+ processing anymore.
+
+2004-02-03 Not Zed <NotZed@Ximian.com>
+
+ * camel-store.c: use the folders object bag to manage the trash
+ folder and junk folders. Remove the init_trash and init_junk
+ stuff, just use get_trash and get_junk to mean the same thing.
+ Get rid of the hacked up vjunk and vtrash "uri" stuff too.
+
+ * camel-object.c (camel_object_bag_add): null out the pair->func,
+ otherwise we get an uninitalised memory read during unhook event.
+
+2004-02-03 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-vee-folder.c (vee_folder_build_folder): Use macro casts
+ from int to pointer.
+
+ * camel-folder.c (camel_folder_change_info_add_source): Same as below.
+ (camel_folder_change_info_add_source_list): Same.
+
+ * camel-folder-search.c (camel_folder_search_execute_expression):
+ Use GINT_TO_POINTER() to cast 1 to a pointer for
+ g_hash_table_insert().
+
+ * camel-vee-folder.c (vee_folder_remove_folder): 64bit fixes.
+ (folder_added_uid): Same.
+ (vee_folder_build_folder): Here too.
+ (folder_changed_add_uid): And here.
+ (folder_changed_remove_uid): Same.
+
+2004-02-03 Jeffrey Stedfast <fejj@ximian.com>
+
+ * tests/misc/url-scan.c: New test suite for url scanning.
+
+ * camel-url-scanner.c: Added single/double quotes to url_braces[]
+ in case the user is quoting the url.
+ (camel_url_web_end): Add "-;:" to list of punctuation to strip off
+ the end of urls. Also fixed to handle user@domain's
+ (camel_url_addrspec_start): Strip open brace characters from the
+ beginning of the addr.
+ (camel_url_web_start): Make sure "www" wasn't part of something
+ not a url (like "Ewww.Gross") by check that pos[-1] is either an
+ open brace or whitespace.
+ (camel_url_addrspec_end): Don't allow toplevel domain addr-specs
+ (if we encounter something that looks like it is a toplevel domain
+ addr, it is more likely to be bogus than correct).
+
+2004-02-02 Jeffrey Stedfast <fejj@ximian.com>
+
+ Fixes for bug #53091.
+
+ * providers/imap/camel-imap-store.c (create_folder): Set the new
+ folder's fi->flags to CAMEL_FOLDER_NOCHILDREN since we know it
+ doesn't have any (we just created it!).
+ (subscribe_folder): Same.
+
+ * camel-store.c (folder_info_clone_rec): Copy the flags too. Fixes
+ the local folder case of bug #53091.
+
+2004-01-31 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/pop3/camel-pop3-store.c (pop3_try_authenticate): Same
+ as below.
+
+ * providers/smtp/camel-smtp-transport.c (smtp_connect): Instead of
+ using the form %s@%s in the password prompt, use %s on host %s,
+ hopefully this will be less confusing to users who have usernames
+ of the form user@vhost.
+
+2004-01-30 Rodney Dawes <dobey@ximian.com>
+
+ * providers/groupwise/camel-groupwise-provider.c: Fix spelling error in
+ provider description
+
+ Fixes #53572
+
+2004-01-30 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel.c (camel_init): Protect against multiple camel_init()
+ calls. Remember if we've already been called.
+
+2004-01-30 Not Zed <NotZed@Ximian.com>
+
+ * camel-store.c (camel_store_rename_folder): copy the old_name
+ that comes in, since it might be the actual folder_name, which
+ will go away during processing. Related to #53123.
+
+2004-01-29 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #53269.
+
+ * providers/nntp/camel-nntp-store.c
+ (nntp_store_get_cached_folder_info): don't dereference last before
+ checking if its null.
+
+ * camel-object.c (camel_object_bag_rekey): added a doc comment.
+
+ ** See bug #53520.
+
+ * camel-session.c (get_service): free the url once done, it now
+ gets copied by the service.
+
+ * camel-service.c (construct): copy the url that comes in, don't
+ just '0Wn34z' it. clena up exception handling too.
+
+2004-01-29 Not Zed <NotZed@Ximian.com>
+
+ * camel-object.c (cobject_state_write): output scan->name and
+ scan->value for writing metadata, rather than meta->name/value
+ which just duplicates the last entry, related to #53195.
+
+ * camel-url.c (camel_url_free): zero out passwd/user/host before
+ freeing them.
+
+2004-01-28 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/local/camel-mbox-store.c (rename_folder): Make sure
+ the new dir path exists before trying to rename files to avoid
+ ENOENT errors. Also save errno when we encounter errors so that we
+ can report the true error later rather than an error we may get
+ while reverting changes. Also, it is OK if the ibex files don't
+ exist, so check for that errno case.
+
+2004-01-28 Sivaih Nallagatla <snallagatla@novell.com>
+
+ * providers/groupwise/camel-gw-listener.c (account_changed)
+ (modify_esources) : add port and /soap parts to relative uri while
+ updating it when account changed
+
+2004-01-27 Radek Doulik <rodo@ximian.com>
+
+ * providers/imap/camel-imap-folder.c (camel_imap_folder_new): set
+ CAMEL_FOLDER_SUPRESS_JUNK_TEST flag
+ (imap_update_summary): update CAMEL_FOLDER_SUPRESS_JUNK_TEST flag
+
+ * camel-folder.c (folder_changed): use
+ CAMEL_FOLDER_SUPRESS_JUNK_TEST flag instead of check_junk_for_imap
+
+ * camel-folder.h (CAMEL_FOLDER_SUPRESS_JUNK_TEST): added new flag
+
+2004-01-27 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #53373.
+
+ * camel-store.c (camel_store_rename_folder): use object_bag_rekey
+ to rename the object. object_bag use was broken.
+
+ * camel-object.c (camel_object_bag_rekey): new api to atomically
+ re-key
+
+2004-01-23 Radek Doulik <rodo@ximian.com>
+
+ * camel-folder.c (folder_changed): use check_junk_for_imap flag
+
+ * camel-session.c: add check_junk_for_imap flag
+
+2004-01-23 Not Zed <NotZed@Ximian.com>
+
+ * providers/imap/camel-imap-folder.c (IMAP_SMALL_BODY_SIZE):
+ removed the meaningless fixme, a butt-retrieved-number is as good
+ as any in this case.
+ (imap_get_message): revert peterw's change of 2002-07-15, instead
+ of checking for online mode here, let get_message do it when you
+ retrieve the parts. This lets a multi-fetch (i.e. large) message
+ work more betterer in offline mode.
+
+2004-01-22 Jeremy Katz <katzj@redhat.com>
+
+ * camel-mime-part.c: Fix prototype to be consistent.
+
+2004-01-21 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #52996.
+
+ * camel-data-cache.c (camel_data_cache_add): put a do-loop around
+ the object_bag_reserve stuff, otherwise we can add/abort out of
+ sync (i.e. when object_bag_reserve returned a pointer we mustn't
+ call add/abort).
+
+ * camel-object.c (camel_object_bag_*): Added some inline doco.
+
+2004-01-20 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #52817.
+
+ * camel-session.c (camel_session_get_password): merged reprompt
+ and secret into a flags field, and add more options. Fixed all
+ callers.
+
+ ** See bug #52899.
+
+ * camel-gpg-context.c (gpg_ctx_parse_status): use need_id as the
+ password key, not userid.
+
+2004-01-19 Siviaah Nallagatla <snallagatla@novell.com>
+
+ * providers/groupwise/camel-gw-listener.c
+ (remove_calender_tasks_sources, modify_calender_tasks_sources):
+ add port and "/soap" to source uri
+
+2004-01-19 Not Zed <NotZed@Ximian.com>
+
+ * camel-vee-store.c (change_folder): use a CamelURL to properly
+ encode the url we generate.
+ (vee_get_folder_info): ditto.
+ (vee_get_folder_info): removed unused variable/warning.
+
+ * camel-session.c (vee_provider): Update the provider flags for
+ URL_FRAGMENT_IS_PATH.
+
+ * providers/imapp/camel-imapp-utils.c (imap_parse_addfress_list):
+ namespaces fixes for HEADER_ADDRESS*
+
+2004-01-17 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/imap/camel-imap-folder.c (imap_sync_online): Limit the
+ flags we set (or unset) to the folder's permanent flags.
+
+2004-01-16 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-mime-message.c (camel_mime_message_build_mbox_from): Same.
+
+ * camel-internet-address.c (internet_decode): Same.
+
+ * camel-mime-utils.[c,h]: Namespaced camel_header_address_t enums
+ s/HEADER_ADDRESS_/CAMEL_HEADER_ADDRESS_/g
+
+2004-01-16 Sivaiah Nallagatla <snallagatla@novell.com>
+
+ * providers/groupwise/camel-groupwise-provider.c: added some conf
+ entries for LDAP address setup
+
+ * providers/groupwise/camel-gw-listener.c: added
+ add_ldap_addressbook_source, modify_ldap_addressbook_source,
+ remove_ldap_addressbook_source functions for setting up LDAP
+ address book. Also setting "username" property on cal/tasks
+ ESources
+
+2004-01-15 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #52881.
+
+ * camel-object.c (camel_object_bag*): Support reserving different
+ keys from the same thread. Oh the pain.
+
+ * camel-vee-store.c (vee_get_folder_info): implement child flags
+ properly. Changed to build tree itself rather than calling
+ camel_folder_info_build.
+ (vee_get_folder): if we're adding a folder with dummy parents,
+ create and add the dummy parent folders too (as real folder
+ objects). We are the only owner of the ref, so this sort of leaks
+ the folder, but they're small.
+
+2004-01-14 Rodrigo Moya <rodrigo@ximian.com>
+
+ * providers/groupwise/camel-groupwise-provider.c
+ (camel_provider_module_init): missing renaming.
+
+2004-01-14 Rodrigo Moya <rodrigo@ximian.com>
+
+ * providers/groupwise/camel-gw-listener.c (add_esource): set the
+ "auth" property on the ESource's we create, to get authentication.
+
+2004-01-14 Not Zed <NotZed@Ximian.com>
+
+ ** Patch from Timo Sirainen <tss@iki.fi> to honour read-only
+ status for imap folders.
+
+ * providers/imap/camel-imap-folder.c (camel_imap_folder_selected):
+ check for read-only status response.
+ (imap_sync_online): only call sync_offline if we're read-only.
+ (imap_expunge_uids_resyncing): NOOP for read-only.
+
+2004-01-14 Not Zed <NotZed@Ximian.com>
+
+ * providers/local/camel-local-folder.c (local_getv): remove debug
+ printf.
+
+ ** See bug #52835.
+
+ * camel-smime-context.c (sm_get_passwd): removed debugging. If we
+ get called multiple times in a row, then forget the old password
+ and re-prompt - it was a bad password. Zero out password memory
+ too.
+
+2004-01-13 Rodrigo Moya <rodrigo@ximian.com>
+
+ * providers/groupwise/camel-groupwise-provider.c: missing renaming.
+
+2004-01-13 Sivaiah Nallagatla <snallagatla@novell.com>
+
+ * providers/groupwise/camel-gw-listener.[ch]: renamed
+ groupwise-config-listener.[ch] to these file names and also
+ changed code to use CamelURL insted of EUri
+
+ * providers/groupwise/camel-groupwise-provider.c: use the renamed
+ config listener apis
+
+ * providers/groupwise/Makefile.am: changed the source file names
+
+2004-01-12 Meilof Veeningen <meilof@wanadoo.nl>
+
+ * providers/nntp/camel-nntp-folder.[ch]: now based on discofolder,
+ cache_message and append_message implemented, only retrieve messages
+ when we are subscribed, some stubs
+
+ * providers/nntp/camel-nntp-provider.c: newsgroup name display
+ settings, password authentication, fix for check_equal where the
+ protocols wouldn't be checked
+
+ * providers/nntp/camel-nntp-store.[ch]: base on discostore with
+ online/offline support, subscriptions, downloading changed parts of
+ the newsgroup list, some stubs, authentication, automatic reconnect
+
+ * providers/nntp/camel-nntp-store-summary.[ch]: NNTP store
+ summary based on IMAP code
+
+ * providers/nntp/camel-nntp-summary.c: save summary after xover
+
+ * providers/nntp/camel-nntp-grouplist.h: added CamelNNTPGroupList
+ structs
+
+ * providers/nntp/Makefile.am: added store summary
+
+2004-01-12 Not Zed <NotZed@Ximian.com>
+
+ ** See bug 52725.
+
+ * providers/imap/camel-imap-folder.c (get_content): pass in
+ transfer encoding when setting up wrapper part.
+
+ * providers/imap/camel-imap-wrapper.c (camel_imap_wrapper_new):
+ Added an encoding type parameter, set on data wrapper.
+
+2004-01-10 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-mime-utils.c (rfc2047_encode_word): if e_iconv() returns
+ -1, check that errno != EINVAL - if errno *is* EINVAL, it just
+ means that our convlen wasn't long enough to include the whole
+ sequence. This is fine, we'll just start where we left off next
+ loop thru. Fixes bug #52593 (the buffer was duplicated because
+ state wasn't flushed).
+ (camel_header_encode_string): Fixed a type-o in loop where
+ encoding=0, don't g_string_append_len starting at 'word'
+ inptr-start bytes long - 'word' could be NULL and/or inptr-start
+ could be longer than inptr-word.
+
+2004-01-09 Rodney Dawes <dobey@ximian.com>
+
+ * providers/groupwise/Makefile.am (EXTRA_DIST): libcamelgroupwise.urls
+ instead of libcamelimap.urls
+
+2004-01-09 Sivaiah Nallagatla <snallagatla@novell.com>
+
+ * providers/groupwise/groupwise-config-listener.c
+ (is_groupwise_account): added null check for source url to take
+ care of accounts with Server Types as "None"
+
+2004-01-09 Not Zed <NotZed@Ximian.com>
+
+ * providers/imap/camel-imap-store.c (imap_forget_folder): fix
+ removal of journal file, and remove the cmeta state file too.
+
+ * providers/imap/camel-imap-folder.c (imap_getv): count up so we
+ call parent class if we missed any, rather than only if we didn't
+ miss any.
+ (imap_rename): rename the object state file.
+ (camel_imap_folder_new): set the object state file for persistent
+ properties.
+
+ * camel-disco-folder.c (disco_getv): support
+ (PERSISTENT_)PROPERTIES & OFFLINE_SYNC.
+ (disco_setv): implement OFFLINE_SYNC.
+ (camel_disco_folder_get_type): setup disco properties list.
+ (cdf_folder_changed): honour the offline_sync setting on the
+ current folder.
+ (disco_sync): save object state.
+ (disco_setv): save object state if it changed.
+
+ * camel-data-wrapper.c (camel_data_wrapper_set_mime_type_field):
+ move assertions here.
+ (set_mime_type_field): change order slightly to properly handle
+ setting the same object. removed assertions from internal method.
+
+2004-01-08 Sivaiah Nallagatla <snallagatla@novell.com>
+
+ * providers/Makefile.am : add groupwise to SUBDIRS
+
+ * providers/groupwise/camel-groupwise-provider.c: new camel
+ provider for groupwise
+
+ * providers/groupwise/groupwise-config-listener.[ch] : new class
+ to add e-sources for groupwise calender and tasks
+
+ * providers/groupwise/Makefile.am : added new files to Makefile.am
+
+2004-01-05 JP Rosevear <jpr@ximian.com>
+
+ * camel-utf8.c: include sys/types.h for freebsd
+
+2004-01-05 Rodrigo Moya <rodrigo@ximian.com>
+
+ * providers/groupwise/camel-groupwise-provider.c (groupwise_url_hash,
+ groupwise_url_equal): renamed from imap_*.
+
+2004-01-05 Not Zed <NotZed@Ximian.com>
+
+ * camel-tcp-stream-raw.c (socket_connect): check the right return
+ of the socket call, dont set fd to the value of the -1 check!
+
+2003-12-27 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-tcp-stream-raw.c (socket_connect): Save errno and check
+ the return of the socket() call.
+
+2003-12-24 Rodrigo Moya <rodrigo@ximian.com>
+
+ * providers/groupwise/camel-groupwise-provider.c
+ (camel_provider_module_init): g_module_open the other providers we
+ depend on to avoid load ordering problems.
+
+2003-12-22 Rodrigo Moya <rodrigo@ximian.com>
+
+ * providers/groupwise/camel-groupwise-provider.c: removed useless
+ configuration options, and added other options from the IMAP
+ provider.
+ (camel_provider_module_init): register a SMTP transport object
+ also, and removed SASL registration, since we don't support it.
+
+2003-12-19 Sivaiah Nallagatla <snallagatla@novell.com>
+
+ * providers/groupwise/Makefile.am:
+ * providers/groupwise/libcamelgroupwise.urls:
+ * providers/groupwise/camel-groupwise-provider.c: added Camel
+ provider for Groupwise accounts, based on the IMAP one.
+
+2003-12-11 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-gpg-context.c (gpg_ctx_parse_status): Don't immediately
+ prompt for a passwd after receiving the NEED_PASSPHRASE status
+ message. Instead, parse the userid that gpg needs a passwd for and
+ store it on our context. Wait for a GET_HIDDEN status message
+ before prompting, this way if the user has their gpg configured to
+ use gpg-agent, the user won't get 2 passwd prompts.
+ (gpg_sign): Fixed to not free a gpg context that we have not
+ allocated (could happen in a fail case).
+
+2003-12-10 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/local/camel-mbox-store.c (get_folder_info): Use
+ CAMEL_FODLER_NOCHILDREN rather than NOINFERIORS because
+ NOINFERIORS means the folder cannot contain subfolders. However,
+ our mbox structure always allows subfolders.
+ (scan_dir): Same.
+
+ * camel-store.h: Add a CAMEL_FOLDER_NOCHILDREN flag.
+
+ * providers/imap/camel-imap-store.c (get_folders): Same as below.
+
+ * providers/imap/camel-imap-utils.c (imap_parse_list_response):
+ s/CAMEL_IMAP_FOLDER_NOCHILDREN/CAMEL_FOLDER_NOCHILDREN/
+
+2003-12-10 Not Zed <NotZed@Ximian.com>
+
+ * camel-smime-context.c (sm_verify): also check
+ application/pkcs7-signature (bloody applemail).
+ (camel_smime_context_describe_part): as above, and fix the logic.
+ dont think its used anyway. Bug #51750.
+
+2003-12-10 Not Zed <NotZed@Ximian.com>
+
+ * Makefile.am (libcamel_la_SOURCES): put the
+ camel-smime-context.[ch] back in here, remove it from EXTRA_DIST,
+ and make it compile optinally the same way camel-tcp-stream-ssl.c
+ does (#ifdef ...).
+
+ * camel-smime-context.c (sm_verify_cmsg): add signer info to
+ certvalidity.
+
+ * camel-cipher-context.c (CamelCipherValidity): Added certinfo to
+ validity for signing and encrypting, so we can find the keys later
+ for a gui.
+ (camel_cipher_validity_add_certinfo): add signer or
+ encrypter info to the validity.
+ (camel_cipher_validity_envelope): add sign/encrypt keys.
+
+2003-12-10 Not Zed <NotZed@Ximian.com>
+
+ * camel-stream-process.c (do_exec_command): remove dthe clearenv
+ stuff, not sure why its there. s/setenv/putenv/ for portability.
+ See Bug #51767.
+
+2003-12-08 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-mime-utils.c (header_decode_rfc2184_param): Revert the
+ s/is_/camel_mime_is_/ changes or we get really long variable
+ names.
+ (header_decode_param): Same.
+ (header_decode_param_list): Here too.
+
+2003-12-09 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #51899.
+
+ * providers/imap/camel-imap-store.c (get_folders): add the first
+ fi to the info's hash, so we dont duplicate it if we come across
+ it again (which we generally will).
+
+2003-12-09 Not Zed <NotZed@Ximian.com>
+
+ * providers/smtp/camel-smtp-transport.c (smtp_send_to): encode the
+ address before sending it out, rather than using the raw/utf8
+ version.
+
+ * camel-internet-address.c
+ (camel_internet_address_encode_address): check for quoting the
+ local part of the address before outputting it.
+ (cia_encode_addrspec): quote local part if need be.
+ (camel_internet_address_encode_address): make folding optional
+ based on whether inlen is null or not.
+
+ * camel-mime-utils.[ch]: rename is_* to camel_mime_is_* and export
+ the type functions.
+
+2003-12-08 Not Zed <NotZed@Ximian.com>
+
+ * providers/imap/camel-imap-utils.c (imap_atom_specials): add } to
+ the atom specials list. This isn't correct, but some busted
+ servers expect it. Bug #50728.
+
+2003-12-08 Jeffrey Stedfast <fejj@ximian.com>
+
+ Fixes bug #51881
+
+ * providers/local/camel-mbox-store.c (delete_folder): Same.
+
+ * providers/local/camel-local-store.c (delete_folder): Unlink the
+ cmeta file too.
+
+2003-12-06 JP Rosevear <jpr@ximian.com>
+
+ * */Makefile.am: Remove hard coded disable deprecated flags
+
+2003-12-05 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-gpg-context.c (gpg_ctx_op_start): Properly set the
+ O_NONBLOCK flag along with any previously set flags.
+
+ * camel-filter-search.c (run_command): Don't set O_NONBLOCK on the
+ pipe (1. we don't need to, and 2. we should have been setting
+ O_NONBLOCK|prev_flags but we weren't, and so the pipe got
+ O_RDONLY|O_NONBLOCK even tho we wanted to write to it).
+
+ * camel-filter-driver.c (pipe_to_system): Same.
+
+2003-12-04 Radek Doulik <rodo@ximian.com>
+
+ * camel-folder.c (folder_changed): check recent messages for junk
+ mail
+
+ * camel-session.c (camel_session_check_junk): new wrapper method
+ for check_junk flag
+ (camel_session_set_check_junk): ditto
+
+ * camel-session.h (struct _CamelSession): added check_junk flag
+ (if to check incoming mail for junk messages)
+
+2003-12-03 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-store.c (add_special_info): Free fi->path if we are gonna
+ replace it with the vinfo path.
+
+ * providers/local/camel-mbox-store.c (create_folder): Treat
+ parent_name == NULL and parent_name == "" the same.
+
+ * camel-store.c (camel_store_get_folder_info): Only add
+ vTrash/vJunk info's if we've requested the toplevel folder tree,
+ otherwise we get vTrash/vJunk folders in odd places in the folder
+ tree.
+ (add_special_info): Use the provider->url_flags to determine if
+ the url uses the fragment or not for the path.
+
+2003-12-02 Not Zed <NotZed@Ximian.com>
+
+ * providers/local/camel-local-folder.c (local_setv): remove some
+ debug printfs.
+
+ ** See bug #51576.
+
+ * camel-url.c (camel_url_decode): robustify url decoding for bad
+ input, addresses a crash.
+
+ ** See bug #51478.
+
+ * camel-gpg-context.c (gpg_ctx_free): handle the context being
+ NULL, and exit silently.
+
+2003-12-01 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-process.c (camel_process_fork): Start at fd = 3.
+
+ * camel-gpg-context.c (gpg_ctx_op_start): Same.
+
+ * camel-filter-driver.c (pipe_to_system): Same.
+
+ * camel-filter-search.c (run_command): Start at fd = 3.
+
+2003-12-01 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-stream-process.c (do_exec_command): Same.
+
+ * camel-process.c (camel_process_fork): Same.
+
+ * camel-filter-search.c (run_command): Same as below.
+
+ * camel-filter-driver.c (pipe_to_system): Same as below.
+
+ * camel-gpg-context.c (gpg_ctx_op_start): Use fcntl() to set
+ FD_CLOEXEC on each fd rather than close()ing it. Apparently
+ Linux's older pthread implementations use sockets and so this
+ fouls threading up. GO LINUX! GO!
+
+2003-12-01 Radek Doulik <rodo@ximian.com>
+
+ * camel-store.c (add_special_info): set SUBSCRIBED and NOINFERIORS
+ flags to special folders, renamed method from
+ add_vtrash_or_vjunk_info
+ (camel_store_get_folder_info): call add_special_info directly
+
+2003-11-28 Radek Doulik <rodo@ximian.com>
+
+ * camel-store.c (camel_store_get_folder_info): use old code from
+ mail-ops to add vtrash/vjunk info
+
+2003-11-28 David Woodhouse <dwmw2@redhat.com>
+
+ * providers/imap/camel-imap-provider.c: Enable GUI option for
+ 'custom command' connection.
+ * providers/imap/camel-imap-store.c: Don't g_free strings in
+ .rodata. It's considered rude.
+
+2003-11-28 Not Zed <NotZed@Ximian.com>
+
+ * camel-mime-utils.c (mail_list_magic[]): Added list-unsubscribe
+ header match.
+
+2003-11-26 Not Zed <NotZed@Ximian.com>
+
+ * camel-smime-context.c (sm_verify_cmsg): take a stream rather
+ than a part for the content.
+ (sm_verify): get the content directly as a stream.
+
+ * camel-multipart-signed.c
+ (camel_multipart_signed_get_content_stream): new api to get the
+ content stream which will match the signed version.
+
+2003-11-26 JP Rosevear <jpr@ximian.com>
+
+ * Makefile.am: make sure we always dist the smime stuff
+
+2003-11-26 JP Rosevear <jpr@ximian.com>
+
+ * Makefile.am (libcamelinclude_HEADERS): conditionally compile
+ s/mime support
+
+2003-11-25 Not Zed <NotZed@Ximian.com>
+
+ * camel-cipher-context.c (camel_cipher_validity_envelope): change
+ args to make it suit storing the validity in a tree.
+ (camel_cipher_validity_init): init the list header.
+ (camel_cipher_validity_clone): call validity_new so it gets init
+ properly.
+ (camel_cipher_validity_free): free any children nodes recursively.
+
+ * camel-cipher-context.h (CamelCipherValidity): added next/prev
+ and list header.
+
+2003-11-18 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-session.c (camel_session_finalise): Don't destroy the
+ providers as it mans we can never ever have more than 1 session
+ object. See bug #51119 for details.
+
+2003-11-17 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/local/camel-mbox-store.c (create_folder): Fixed an
+ exception to give a more meaningful description.
+ (get_folder_info): We always want to scan at least one level deep.
+
+2003-11-14 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/local/camel-mbox-store.c (get_folder_info): Handle ""
+ as a request for a full dirscan as well (not just NULL). Makes it
+ consistant with other stores.
+ (scan_dir): Set the fi->flags appropriately.
+
+ * providers/local/camel-mbox-folder.c
+ (camel_mbox_folder_get_full_path): Removed temporary hack.
+
+2003-11-14 Not Zed <NotZed@Ximian.com>
+
+ * camel-mime-parser.c (SCAN_BUF): oops, put the mempool stuff
+ back, we don't use e-memory afterall. Damn plane hacking.
+
+2003-11-13 Not Zed <NotZed@Ximian.com>
+
+ * camel-mime-parser.c: Remove mempool code, we use the stuff in
+ e-util.
+ (PRESERVE_HEADERS): new compile option, if on, we preserve headers
+ and folding exactly rather than unfolding all input. THIS BREAKS
+ EVERYTHING right now, so don't turn it on.
+
+ * camel-gpg-context.c (gpg_decrypt): reset the input memstream
+ before passing it to the gpg engine.
+
+ * tests/smime/pgp-mime.c (main): redirect /dev/null to stdin so it
+ doesn't hang waiting for input.
+ (main): removed from build - this tests multipart/signed
+ explictly, but now the details of this is handled directly by the
+ cipher context.
+
+ * tests/smime/pgp.c (main): fixes for api changes.
+ (main): redirect /dev/null to stdin so it doesn't hang waiting for
+ input.
+
+ * tests/message/test1.c (main): update for api changes.
+
+ * camel-smime-context.c (sm_verify): look at the content object's
+ mime type, not the container's type.
+
+2003-11-11 Not Zed <NotZed@Ximian.com>
+
+ * camel-cipher-context.c (camel_cipher_validity_set_valid): take
+ into account the @valid argument and set validity properly.
+ (camel_cipher_validity_clone): new method to copy validities.
+
+ * camel-smime-context.c (sm_signing_cmsmessage): removed a todo.
+
+2003-11-10 Not Zed <NotZed@Ximian.com>
+
+ * camel-smime-context.c (sm_verify_cmsg): split out the CMSMessage
+ verification code so it can be used from enveloped or externally
+ signed data.
+
+ * camel-cipher-context.c (camel_cipher_verify): only take a
+ mimepart, internally handle multiparts and the hash.
+
+2003-11-07 Not Zed <NotZed@Ximian.com>
+
+ * camel-cipher-context.c: make ciphervalidity a public structure,
+ added encrypt status.
+ (camel_cipher_decrypt): changed to return a ciphervalidity. fixed
+ implementations.
+ (camel_cipher_validity_*): Fixed implementations to match new
+ structure, some of this is now redundant.
+
+2003-11-06 Not Zed <NotZed@Ximian.com>
+
+ * camel-smime-context.c (camel_smime_context_describe_part):
+ implement.
+
+2003-11-05 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/smtp/camel-smtp-transport.c (connect_to_server): Don't
+ bother trying to see if the server advertises EHLO. Simply always
+ try EHLO and fall back to HELO if EHLO fails. Fixes bug #50535.
+
+2003-11-05 Not Zed <NotZed@Ximian.com>
+
+ * camel-smime-context.c (camel_smime_context_describe_part): new
+ (unfinished) api to peek inside smime parts to tell us whats in
+ it.
+
+2003-11-03 Not Zed <NotZed@Ximian.com>
+
+ * camel-gpg-context.c (gpg_encrypt): Make this output the
+ full multipart/encrypted part, not just the encrypted content part.
+
+ * camel-cipher-context.c (camel_cipher_sign): change to output
+ full mime part, not just a stream.
+ (camel_cipher_canonical_to_stream): utility function to
+ canonicalise a mimepart to a stream.
+
+ * camel-smime-context.c (sm_encode_cmsmessage): removed.
+ (sm_sign): change interface to output a full mime-part, not just a
+ part of a mime part in multipart/signed mode.
+
+2003-11-04 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-gpg-context.c (gpg_ctx_parse_status): We might need to
+ convert the passwd from UTF-8 into the locale charset. Fixes bug
+ #50485.
+
+2003-10-31 Not Zed <NotZed@Ximian.com>
+
+ * camel-cms-context.[ch]: removed, now redundant.
+
+2003-10-30 Not Zed <NotZed@Ximian.com>
+
+ * camel-smime-context.c (sm_get_passwd): implement something basic.
+
+ * camel-cipher-context.h: Added a note about api inconsistencies.
+
+2003-10-30 Not Zed <NotZed@Ximian.com>
+
+ * camel-multipart-encrypted.c (camel_multipart_encrypted_decrypt):
+ fix for cipher_decrypt changes.
+
+ * camel-gpg-context.c, camel-cipher-context.c: moved all the init
+ code to the end to save having to keep forward declarations
+ around.
+ (camel_cipher_decrypt): changed to take mimepart input and return
+ a mimepart.
+ (gpg_decrypt): fix for changed args.
+
+2003-10-29 Not Zed <NotZed@Ximian.com>
+
+ * camel-smime-context.[ch]: replaced entirely with a new
+ implementation which inherits from camel-cipher-context, and add
+ to build.
+
+ * camel-multipart-encrypted.c (camel_multipart_encrypted_encrypt):
+ fix for cipher_encrypt api changes.
+ (camel_multipart_encrypted_decrypt): use g_ascii_strcasecmp.
+
+ * camel-gpg-context.c (gpg_encrypt): Fix to handle input/output as
+ parts not streams
+
+ * camel-cipher-context.c (camel_cipher_encrypt): change to take
+ mimeparts rather than streams as input/output. And remove the
+ 'sign' argument, it is implied if userid is supplied.
+
+2003-10-28 Not Zed <NotZed@Ximian.com>
+
+ * tests/smime/pgp.c (main): fix for ciphercontext api changes.
+
+ * camel-multipart-signed.c (camel_multipart_signed_verify): pass
+ in the part to cipher_verify directly.
+ (camel_multipart_signed_sign): let the cipher context setup the
+ part details.
+
+ * camel-gpg-context.c (gpg_sign): put the signature stream into a
+ mimepart, with appropriate headers/encoding.
+ (swrite): write out a mimepart rather than a stream.
+ (gpg_verify): handle changed args.
+
+ * camel-cipher-context.c (camel_cipher_sign): write the signature
+ to a mimepart rather than a simple stream.
+ (camel_cipher_verify): take the signature as a mimepart not a
+ stream.
+
+2003-10-22 Not Zed <NotZed@Ximian.com>
+
+ * camel-utf8.c (camel_ucs2_utf8, camel_utf8_ucs2): helpers for
+ ucs2 stuff. ucs2 is 16 bit truncated unicode.
+
+2003-10-28 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-mime-utils.c: We should check List-Post before List-Id
+ (List-Post has to contain the mailing-list posting address,
+ whereas List-Id does not.) WAlso moved X-Loop to after List-Id to
+ make FreeBSD lusers happy. Fixes bug #32297.
+
+2003-10-28 Jeffrey Stedfast <fejj@ximian.com>
+
+ * Fixes bug #35083
+
+ * providers/imap/camel-imap-store.c (connect_to_server): Same
+ here.
+
+ * providers/pop3/camel-pop3-store.c (connect_to_server): Same as
+ the smtp changes.
+
+ * providers/smtp/camel-smtp-transport.c (connect_to_server): If
+ HAVE_SSL is undefined, don't default to raw connections if the
+ option to connect via ssl is set. Instead set an exception and
+ return fail.
+
+2003-10-27 Frederic Crozat <fcrozat@mandrakesoft.com>
+
+ * camel-mime-utils.c: (camel_header_decode_date):
+ better detection of broken date to give to broken_date_parser.
+
+2003-10-24 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-text-index.c (text_index_name_add_buffer): If a word is
+ longer than CAMEL_TEXT_INDEX_MAX_WORDLEN, then ignore it. This
+ fixes bug #50096.
+
+2003-10-23 Jeffrey Stedfast <fejj@ximian.com>
+
+ * *.c: Removed unneeded CAMEL_OBJECT() casts.
+
+2003-10-21 Not Zed <NotZed@Ximian.com>
+
+ * providers/local/camel-local-folder.c (local_getv, local_setv):
+ use the right tag name for the index_body arg.
+ (local_sync): write any persistent metadata - to make it
+ persistent.
+ (camel_local_folder_construct): turn off indexing, for now, it
+ should be done in local_setv.
+
+ * providers/local/camel-local-folder.h: change body_index to a bool
+ type.
+
+ * camel-object.c (cobject_state_read, cobject_state_write): handle
+ bool types
+ (cobject_state_write): make sure we free all arg types.
+
+ * camel-arg.c (camel_argv_build):
+ (camel_arggetv_build): handle bool type.
+
+ * camel-arg.h: Added BOO (bool) type.
+
+2003-10-15 Not Zed <NotZed@Ximian.com>
+
+ * camel-store.c (camel_folder_info_build): Fix so we output the
+ tree in sorted depth-first order, rather in reverse.
+
+2003-10-16 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-sasl-kerberos4.c: Fixed a #include.
+
+2003-10-10 Not Zed <NotZed@Ximian.com>
+
+ * providers/local/camel-local-provider.c: set the url fragment
+ flag for local providers.
+
+ * camel-provider.h: Move the URL_PART_NEED bits to the high 16
+ bits, to allow for easier changes in the future. Added a
+ URL_PART_FRAGMENT flag for providers that use fragment = folder
+ path.
+
+2003-10-09 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-mime-utils.c (header_decode_date): Allow timezone offsets
+ to be up to 14 hours ahead of UTC. Fixes bug #49357.
+
+ * broken-date-parser.c (get_tzone): Same.
+
+2003-10-08 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/smtp/camel-smtp-transport.c (smtp_helo): Removed an
+ unused variable.
+
+2003-09-25 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/smtp/camel-smtp-transport.c (smtp_helo): If the
+ localhost lookup results in a numeric IPv6 host, use the form
+ "[IPv6:<addr>]" as specified in rfc2821. Fixes bug #46006.
+
+2003-09-23 Ettore Perazzoli <ettore@ximian.com>
+
+ * providers/local/camel-local-provider.c: Set the IS_STORAGE bit
+ in the mbox provider, since it can now contain a hierarchy of
+ folders.
+
+2003-09-23 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/local/camel-mbox-store.c (get_folder): If the CREATE
+ flag is set and the parent .sbd directory does not exist, create
+ it.
+
+ * camel-mime-utils.c (append_8bit): Don't forget to flush the
+ iconv conversion.
+
+ * tests/message/test4.c (main): Don't try dot-files.
+
+2003-09-22 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #41610
+
+ * providers/pop3/camel-pop3-folder.c (cmd_tocache): protect a
+ divide by 0 for 0 length messages.
+
+2003-09-22 Not Zed <NotZed@Ximian.com>
+
+ * providers/imap/camel-imap-provider.c: Added "offline_sync"
+ option, which lets you synchronise all mail to local storage
+ automagically.
+
+ * camel-disco-folder.c (cdf_folder_changed): hook onto the folder
+ changed single, for all new messages, check that they are online
+ using another thread, if the offline_sync option has been enabled
+ for this store.
+
+2003-09-21 Not Zed <NotZed@Ximian.com>
+
+ * camel-session.c (session_thread_destroy): call proper entry
+ point for freeing the message.
+
+2003-09-18 Not Zed <NotZed@Ximian.com>
+
+ * camel-folder.c (filter_filter): register the filtering process
+ for progress, and do progress of the filtering process.
+
+2003-09-17 Not Zed <NotZed@Ximian.com>
+
+ * camel.c (camel_init): init camel operation.
+
+ * camel-operation.c (camel_operation_reset): removed, not used,
+ not worth it.
+ (camel_operation_mute): new method to stop all status updates
+ permanently.
+ (*): Changed to use thread specific data and a list rather than a
+ hashtable.
+ (cancel_thread): removed.
+ (camel_operation_register): return the previously registered op.
+
+2003-09-22 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/nntp/camel-nntp-store.c (connect_to_server): Fix the
+ code that creates a new ssl stream to pass the correct arguments
+ and the proper flags.
+
+ * providers/imapp/camel-imapp-folder.c (imap_sync): Cast the
+ CamelFolder to a CamelIMAPPFolder to hush some compiler warnings.
+
+ * camel-mime-utils.h: Define a struct _CamelContentDisposition
+ (allows the imapp code to compile)
+
+ * providers/imapp/camel-imapp-driver.c: #include <string.h>
+
+2003-09-18 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-mime-utils.c (camel_transfer_encoding_to_string): New
+ function to replace the one from camel-mime-part.c
+ (camel_transfer_encoding_from_string): Same.
+ (camel_content_transfer_encoding_decode): Renamed from
+ camel_header_content_encoding_decode().
+
+ * camel-mime-part.c (camel_mime_part_encoding_to_string): Removed.
+ (camel_mime_part_encoding_from_string): Removed.
+
+ * camel-data-wrapper.[c,h]: updated for CamelTransferEncoding
+ namespace changes
+
+ * camel-folder-summary.c: updated for CamelTransferEncoding
+ namespace changes
+
+ * camel-mime-filter-bestenc.[c,h]: updated for CamelTransferEncoding
+ namespace changes
+
+ * camel-mime-message.c: updated for CamelTransferEncoding
+ namespace changes
+
+ * camel-mime-part-utils.c: updated for CamelTransferEncoding
+ namespace changes
+
+ * camel-multipart-signed.c: updated for CamelTransferEncoding
+ namespace changes
+
+ * camel-smime-context.c: updated for CamelTransferEncoding
+ namespace changes
+
+ * providers/imapp/camel-imapp-utils.c: updated for
+ CamelTransferEncoding namespace changes
+
+ * tests/lib/messages.c: updated for CamelTransferEncoding
+ namespace changes
+
+ * tests/message/test1.c: updated for CamelTransferEncoding
+ namespace changes
+
+2003-09-18 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-mime-utils.[c,h]: namespaced the encoding/decoding
+ routines.
+
+ * camel-mime-filter-basic.c: updated for namespace changes to the
+ encoding/decoding routines in camel-mime-utils.c
+
+ * camel-multipart.c: updated for namespace changes to the
+ encoding/decoding routines in camel-mime-utils.c
+
+ * camel-sasl-digest-md5.c: updated for namespace changes to the
+ encoding/decoding routines in camel-mime-utils.c
+
+ * camel-sasl.c: updated for namespace changes to the
+ encoding/decoding routines in camel-mime-utils.c
+
+ * camel-vee-folder.c: updated for namespace changes to the
+ encoding/decoding routines in camel-mime-utils.c
+
+ * providers/imap/camel-imap-search.c: updated for namespace
+ changes to the encoding/decoding routines in camel-mime-utils.c
+
+ * providers/pop3/camel-pop3-folder.c: updated for namespace
+ changes to the encoding/decoding routines in camel-mime-utils.c
+
+2003-08-26 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-mime-parser.[c,h]: s/HSCAN_/CAMEL_MIME_PARSER_STATE_/g and
+ s/_header_state/_camel_mime_parser_state/g
+
+ * camel-filter-driver.c: Same.
+
+ * camel-folder-summary.c: Here too.
+
+ * camel-http-stream.c: And here.
+
+ * camel-mime-message.c: ...
+
+ * camel-mime-part-utils.c: ...
+
+ * camel-mime-part.c: ...
+
+ * camel-movemail.c: ...
+
+ * camel-multipart-signed.c: ...
+
+ * camel-multipart.c: ...
+
+ * providers/local/camel-mbox-folder.c: ...
+
+ * providers/local/camel-mbox-summary.c: ...
+
+ * providers/local/camel-mh-summary.c: ...
+
+ * providers/nntp/camel-nntp-summary.c: ...
+
+ * providers/pop3/camel-pop3-folder.c: ...
+
+2003-08-25 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-mime-utils.[c,h]: Namespaced.
+
+ * camel-data-wrapper.c: updated for namespace changed made to
+ camel-mime-utils.[c,h]
+
+ * camel-digest-folder.c: updated for namespace changed made to
+ camel-mime-utils.[c,h]
+
+ * camel-filter-driver.c: updated for namespace changed made to
+ camel-mime-utils.[c,h]
+
+ * camel-filter-search.c: updated for namespace changed made to
+ camel-mime-utils.[c,h]
+
+ * camel-folder-search.c: updated for namespace changed made to
+ camel-mime-utils.[c,h]
+
+ * camel-folder-summary.[c,h]: updated for namespace changed made
+ to camel-mime-utils.[c,h]
+
+ * camel-http-stream.c: updated for namespace changed made to
+ camel-mime-utils.[c,h]
+
+ * camel-http-stream.h: updated for namespace changed made to
+ camel-mime-utils.[c,h]
+
+ * camel-internet-address.c: updated for namespace changed made to
+ camel-mime-utils.[c,h]
+
+ * camel-medium.[c,h]: updated for namespace changed made to
+ camel-mime-utils.[c,h]
+
+ * camel-mime-message.c: updated for namespace changed made to
+ camel-mime-utils.[c,h]
+
+ * camel-mime-parser.[c,h]: updated for namespace changed made to
+ camel-mime-utils.[c,h]
+
+ * camel-mime-part-utils.c: updated for namespace changed made to
+ camel-mime-utils.[c,h]
+
+ * camel-mime-part.[c,h]: updated for namespace changed made to
+ camel-mime-utils.[c,h]
+
+ * camel-movemail.c: updated for namespace changed made to
+ camel-mime-utils.[c,h]
+
+ * camel-multipart-encrypted.c: updated for namespace changed made
+ to camel-mime-utils.[c,h]
+
+ * camel-multipart-signed.c: updated for namespace changed made to
+ camel-mime-utils.[c,h]
+
+ * camel-multipart.c: updated for namespace changed made to
+ camel-mime-utils.[c,h]
+
+ * camel-search-private.[c,h]: updated for namespace changed made
+ to camel-mime-utils.[c,h]
+
+ * camel-types.h: updated for namespace changed made to
+ camel-mime-utils.[c,h]
+
+ * providers/imap/camel-imap-folder.c: updated for namespace
+ changed made to camel-mime-utils.[c,h]
+
+ * providers/imap/camel-imap-store-summary.c: updated for namespace
+ changed made to camel-mime-utils.[c,h]
+
+ * providers/imap/camel-imap-utils.c: updated for namespace changed
+ made to camel-mime-utils.[c,h]
+
+ * providers/imapp/camel-imapp-utils.[c,h]: updated for namespace
+ changed made to camel-mime-utils.[c,h]
+
+ * providers/local/camel-local-summary.[c,h]: updated for namespace
+ changed made to camel-mime-utils.[c,h]
+
+ * providers/local/camel-maildir-summary.c: updated for namespace
+ changed made to camel-mime-utils.[c,h]
+
+ * providers/local/camel-mbox-summary.c: updated for namespace
+ changed made to camel-mime-utils.[c,h]
+
+ * providers/local/camel-spool-summary.h: updated for namespace
+ changed made to camel-mime-utils.[c,h]
+
+ * providers/nntp/camel-nntp-summary.c: updated for namespace
+ changed made to camel-mime-utils.[c,h]
+
+ * providers/nntp/camel-nntp-utils.c: updated for namespace changed
+ made to camel-mime-utils.[c,h]
+
+ * providers/pop3/camel-pop3-folder.c: updated for namespace
+ changed made to camel-mime-utils.[c,h]
+
+ * providers/sendmail/camel-sendmail-transport.c: updated for
+ namespace changed made to camel-mime-utils.[c,h]
+
+ * providers/smtp/camel-smtp-transport.c: updated for namespace
+ changed made to camel-mime-utils.[c,h]
+
+2003-09-16 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/local/camel-mbox-folder.c
+ (camel_mbox_folder_get_full_path): Implement a temp hack so trunk
+ works until we merge in new-ui-branch.
+
+ * camel-stream-filter.c (do_flush): Don't warning about how we
+ haven't written anything to the stream, this is not an
+ error. fflush() doesn't care if you try to fflush() a stream
+ without writing to it, so we shouldn't care either.
+
+2003-09-15 Not Zed <NotZed@Ximian.com>
+
+ * providers/imapp/camel-imapp-store.c (store_resp_list)
+ (imap_login, try_sasl, imap_try_authenticate): removed dead code.
+
+ * providers/imapp/camel-imapp-stream.c: return -1 if stream not
+ set.
+
+ * providers/imapp/camel-imapp-engine.c (iterate_completion): put
+ done request on the done queue, so all requests are always
+ somewhere.
+ (camel_imapp_engine_command_free): just spit warnings of active
+ messages being freed, but abort if the item isn't in any list.
+ Also remove the node from its list before going on.
+ (iterate_untagged, iterate_continuation, iterate_completion):
+ staticifiy.
+
+ * providers/imapp/camel-imapp-provider.c
+ (camel_imapp_module_init): move camel_exception_setup call here.
+
+ * providers/imapp/camel-imapp-driver.c
+ (camel_imapp_driver_get_type): remove execption setup here, it
+ isn't early enough.
+ (camel_imapp_driver_list): handle exceptions.
+
+2003-09-12 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/local/camel-mbox-folder.c
+ (camel_mbox_folder_get_full_path): Implements
+ CamelLocalFolder::get_full_path() (publicly namespaced so that
+ CamelMboxStore can re-use them).
+ (camel_mbox_folder_get_meta_path): Same.
+
+ * providers/local/camel-mbox-store.c (get_folder): Changed the way
+ the path is constructed, since we now handle subdirectories and
+ stuff.
+ (delete_folder): Try deleting the Folder.sbd directory. We also
+ need to manage our own meta files since CamelLocalStore's impl
+ constructs paths differently than what we need.
+ (create_folder): Implemented.
+ (rename_folder): Implemented.
+ (scan_dir): Scan an mbox tree
+ (get_folder_info): Implemented using scan_dir().
+
+ * providers/local/camel-local-store.c (delete_folder): Set fi->url
+ to the correct value, meaning we need to prefix it with the
+ protocol and the folder_name is not actually part of the path, it
+ is a separate component to the url.
+
+ * providers/local/camel-local-folder.c
+ (camel_local_folder_construct): Use the new class virtual method
+ to construct the full folder path and all the meta files.
+ (local_get_full_path): Implemented default get_full_path method.
+ (local_get_meta_path): Implemented default get_meta_path method.
+
+2003-09-11 Dan Winship <danw@ximian.com>
+
+ * Makefile.am (noinst_LTLIBRARIES): Remove libcamel-static.la
+
+2003-09-05 Not Zed <NotZed@Ximian.com>
+
+ * providers/imap/camel-imap-store.c (imap_noop): call
+ camel_folder_sync bypassing the folder lock. See
+ imap_store_refresh_folders too.
+
+2003-09-04 David Woodhouse <dwmw2@infradead.org>
+
+ * providers/camel-imap-store.[ch]: Add PREAUTH handling and
+ pine/mutt/etpan/etc.-style 'ssh <mailhost> exec imapd' support.
+
+2003-09-03 David Woodhouse <dwmw2@infradead.org>
+
+ * camel-stream-process.[ch]: New stream implementation for running
+ commands.
+ * Makefile.am: Compile the above
+
+2003-08-20 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #47765.
+
+ * camel-folder-search.h: Removed match1 member.
+
+ * camel-folder-search.c (camel_folder_search_match_expression):
+ use current directly rather than match1. This method isn't used
+ anywhere anyway.
+ (search_not): remove match1 stuff.
+ (search_match_all): properly handle the match-all against 1
+ message as a scalar result, not an array result.
+
+2003-09-03 Not Zed <NotZed@Ximian.com>
+
+ * camel-http-stream.c (camel_http_stream_set_proxy): handle NULL
+ proxy_url - unset the proxy.
+
+2003-08-29 Not Zed <NotZed@Ximian.com>
+
+ * camel-object.c (camel_object_state_write):
+ (cobject_getv):
+ (cobject_setv, cobject_state_read, cobject_state_read)
+ (cobject_state_write): removed debug printfs.
+
+ * providers/local/camel-local-folder.c (local_getv): Need to copy
+ the local properties list before passing it out, since it's freed.
+
+2003-08-27 Not Zed <NotZed@Ximian.com>
+
+ * providers/local/camel-local-folder.c (local_getv): implement
+ PERSISTENT_PROPERTIES, for index mode.
+
+ * camel-object.c (cobject_state_read): Also add property reading,
+ and bump version to 1.
+ (cobject_state_write): add persistent property writing.
+
+2003-08-26 Not Zed <NotZed@Ximian.com>
+
+ * camel-folder.c (folder_getv): chain up properly.
+
+ * camel-file-utils.c (camel_file_util_savename): helper to create
+ a .#filename filename.
+
+ * providers/local/camel-local-folder.c
+ (camel_local_folder_construct): init meta-data for local folders.
+ (local_getv): chain up properly, if args are not processed, rather
+ than don't if they aren't.
+
+2003-08-23 Not Zed <NotZed@Ximian.com>
+
+ * camel-object.c (cobject_class_init): added a new event,
+ meta_changed.
+ (camel_object_meta_set, camel_object_meta_get): meta-data api.
+ (camel_object_free_hooks): Free meta-data if it is set on the
+ object.
+
+ * providers/local/camel-local-folder.c
+ (camel_local_folder_get_type): setup a property list for local
+ folders, just 'index_body' at present.
+
+2003-08-25 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-filter-driver.c (pipe_to_system): Added some more error
+ checking for reading/writing to the pipes. Fixes bug #47880.
+
+2003-08-21 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-data-wrapper.c (decode_to_stream): Don't poke
+ wrapper->stream directly, use camel_data_wrapper_write_to_stream()
+ instead as this simplifies things and makes the imap data wrapper
+ implementation Just Work (tm).
+
+ * providers/imap/camel-imap-wrapper.c: changed prototype of
+ write_to_stream() to return ssize_t.
+
+2003-08-20 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/imap/camel-imap-wrapper.c (imap_wrapper_hydrate): Make
+ sure to ref the stream. Fixes bug #47749.
+
+2003-08-18 Not Zed <NotZed@Ximian.com>
+
+ * camel-http-stream.c: Various fixes to make it work.
+
+ * tests/smime/pgp-mime.c (main): added missing 'ret' variable.
+
+ * providers/smtp/camel-smtp-transport.c (connect_to_server):
+ * providers/imapp/camel-imapp-store.c (connect_to_server:
+ * providers/imap/camel-imap-store.c (connect_to_server):
+ * providers/pop3/camel-pop3-store.c (connect_to_server):
+ * camel-http-stream.c (http_connect): change service->session for
+ tcp_stream_ssl_new.
+
+ * camel-tcp-stream-ssl.c: Changed service to session, and fix some
+ refcounting of it.
+ include camel-operation.h
+
+2003-08-15 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #47634.
+
+ * tests/lib/messages.c (test_message_compare): check
+ write_to_stream returns.
+ (message_dump_rec): helper to dump message structure.
+
+ * camel-mime-part-utils.c
+ (simple_data_wrapper_construct_from_parser): dont set content
+ encoding here.
+ (camel_mime_part_construct_content_from_parser): set it here
+ instead, on every part. basically same as setting the
+ mime_type_field always.
+
+ * camel-multipart-signed.c (camel_multipart_signed_class_init):
+ * camel-mime-message.c (camel_mime_message_class_init):
+ * camel-multipart.c (camel_multipart_class_init): override
+ decode_to_stream to always do the same as write_to_stream, since
+ we can never be encoded.
+
+2003-08-15 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/imap/camel-imap-wrapper.c (imap_wrapper_hydrate):
+ Don't attach any filters to decode base64/qp/etc.
+
+2003-08-14 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-mime-part.c (write_to_stream): Save errno when
+ flushing/unreffing the filter stream.
+
+2003-08-13 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-mime-part.c (write_to_stream): If the content is
+ base64/qp/uu/etc encoded but the part is 7bit/8bit/(or otherwise
+ non-encoded), set reencode to TRUE so that we decode the original
+ content stream. Fixes a bug noticed on
+ evolution-patches@ximian.com where a patch had a
+ Content-Transfer-Encoding of 7bit but was base64 encoded.
+
+2003-08-13 Not Zed <NotZed@Ximian.com>
+
+ * camel-folder-summary.c (camel_folder_summary_remove_range): Fix
+ the range check, we were stopping removal of 1 or 2 removals, for
+ some odd and completely uncomprehensible reason. Perhaps debug
+ left in?
+
+2003-08-13 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #47517.
+
+ * camel-vee-folder.c (vee_sync): Always rebuild folder on any
+ sync, not just expunge ones.
+
+2003-08-11 Not Zed <NotZed@Ximian.com>
+
+ * providers/imapp/camel-imapp-store.c (imap_get_folder_info):
+ force connect manually so basics work.
+
+ ** See bug #45505.
+
+ * camel-service.c (camel_gethostbyname): duh, pthread_create
+ returns the error code directly, not via errno.
+ (camel_gethostbyaddr): Same, also properly handle the failure
+ case.
+
+2003-08-01 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #47208.
+
+ * camel-filter-search.c (match_all): match-all with no arguments
+ should always return TRUE.
+
+ * camel-folder-search.c (camel_folder_search_execute_expression):
+ print a warning when we get an invalid result type & fixed a leak
+ for that case.
+
+2003-08-08 Jeffrey Stedfast <fejj@ximian.com>
+
+ * tests/message/test4.c: New test suite for the mime parser (which
+ is where the below 2 fixes were noticed).
+
+ * camel-mime-parser.c (folder_boundary_check): Calculate 'len' by
+ subtracting the boundary start from inend rather than 'atleast'.
+ (folder_scan_content): Calculate 'inend' differently depending on
+ the EOF state.
+
+2003-08-08 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-mime-filter-tohtml.c (html_convert): Rather than checking
+ *inptr == '\n', check inptr >= inend - this gets rid of an Invalid
+ Read report from valgrind.
+
+ * camel-mime-part.c (write_to_stream): Don't necessarily re-encode
+ just because the encodings differ. Need to look into making it so
+ that message/rfc822 and multipart parts ignore the
+ Content-Transfer-Encoding header and just keep their 'encoding'
+ bits set to DEFAULT.
+
+2003-08-05 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/imap/camel-imap-folder.c (get_content): Updated.
+
+ * camel-mime-message.c (camel_mime_message_init): Don't override
+ the mime_type here.
+ (process_header): Updated to use CamelDataWrapper's mime_type
+ field.
+ (find_best_encoding): Same.
+ (best_encoding): Here too.
+
+ * camel-digest-folder.c (camel_digest_folder_new): Updated for
+ CamelMimePart::content_type change.
+
+ * camel-mime-part.c (camel_mime_part_init): Override our parent
+ class's default mime_type.
+ (camel_mime_part_finalize): Don't need to unref the content_type
+ anymore.
+ (process_header): Updated to use CamelDataWrapper's mime_type
+ field.
+ (camel_mime_part_set_filename): Same.
+ (camel_mime_part_get_filename): Same.
+ (camel_mime_part_get_content_type): Same.
+ (set_content_object): Here too.
+ (write_to_stream): Updated.
+ (construct_from_parser): Updated.
+
+ * camel-mime-part.h: Remove the content_type field.
+
+2003-07-31 Jeffrey Stedfast <fejj@ximian.com>
+
+ * tests/lib/messages.c (test_message_compare_content): If the
+ chunks differ, perform a hexdump on the data being compared so
+ that we may analyse it easier.
+
+ * camel-multipart-signed.c (write_to_stream): Return ssize_t.
+
+ * camel-mime-utils.h: Added the CamelMimePartEncodingType enum
+ here.
+
+ * camel-mime-part.h: Removed the CamelMimePartEncodingType enum
+ from here.
+
+ * camel-mime-part.c (write_to_stream): Updated to return
+ ssize_t. Also minor changes to only re-encode the content stream
+ if the charset or encoding changed (this way we write it out in
+ the original raw form if nothing changed).
+
+ * camel-mime-part-utils.c
+ (simple_data_wrapper_construct_from_parser): Drastically
+ simplify. We no longer scan html content to try and find the
+ charset, nor do we care about converting the content to UTF-8 and
+ handling broken windows charsets.
+
+ * camel-mime-message.c (find_best_encoding): Use
+ decode_to_stream() here. Also updated to not assume the content
+ charset is UTF-8 since it is very likely not the case anymore
+ since data-wrappers no longer are converted to UTF-8 at parse
+ time.
+
+ * camel-folder-summary.c (summary_build_content_info_message): Use
+ decode_to_stream instead here too.
+
+ * camel-folder-search.c (match_words_1message): Use
+ decode_to_stream instead of write_to_stream so we can search the
+ contents.
+
+ * camel-data-wrapper.c (camel_data_wrapper_init): Set the default
+ encoding to DEFAULT.
+ (write_to_stream): Updated to return ssize_t
+ (camel_data_wrapper_decode_to_stream): New virtual function to
+ decode a data wrapper to a stream (results in nearly identical
+ behaviour to the old write_to_stream method).
+ (decode_to_stream): Default implementation of above virtual
+ method. Decodes base64/qp/etc streams.
+
+ * camel-data-wrapper.h: Removed the rawtext bit and added an
+ encoding member.
+
+2003-08-01 Jeffrey Stedfast <fejj@ximian.com>
+
+ * tests/smime/pgp-mime.c: Same.
+
+ * tests/smime/pgp.c: Updated to build and to import some custom
+ gpg keys for use with testing.
+
+2003-07-30 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-mime-message.c (write_to_stream): Also updated.
+
+ * camel-data-wrapper.c (write_to_stream): This should return ssize_t
+
+ * camel-multipart-signed.c (write_to_stream): Updated.
+
+ * camel-multipart.c (write_to_stream): Same.
+
+ * camel-mime-part.c (write_to_stream): Here too.
+
+2003-07-11 Suresh Chandrasekharan <suresh.chandrasekharan@sun.com>
+
+ * camel-iconv.c: Fix for #46168 'some additional locale aliases
+ required for chinese support'.
+
+2003-07-25 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-mime-utils.c (header_decode_word): Revert NotZed's fix for
+ bug #42170 - this causes even more problems than it solves. See
+ bug #46331 for info. Basically, each address header would be
+ converted to UTF-8 twice which means no raw 8bit address header
+ would render correctly.
+ (header_decode_mailbox): Perform a sanity check on the resultant
+ addr->str to make sure that it is valid UTF-8, if not convert it
+ to UTF-8. Fixes bug #42170.
+
+2003-07-23 Ettore Perazzoli <ettore@ximian.com>
+
+ * camel-provider.c (camel_provider_init): Print the provider
+ directory as well, for debugging.
+
+2003-07-23 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-mime-message.c (find_best_encoding): Revert my previous
+ changes to this function.
+
+ * camel-mime-utils.h: Revert previous changes.
+
+ * camel-mime-part.h: Revert previous changes.
+
+ * camel-mime-part-utils.c: Revert previous changes.
+
+ * camel-data-wrapper.c (camel_data_wrapper_init): Revert previous
+ changes.
+ (write_to_stream): Revert previous changes.
+
+2003-07-23 Dan Winship <danw@ximian.com>
+
+ * camel-block-file.c: #include camel-file-utils.h for camel_read()
+
+ * camel-uid-cache.c (camel_uid_cache_save): Remove unused variable
+ and label.
+
+ * camel-url.c: #include camel-string-utils.h for camel_strdown
+
+ * providers/pop3/camel-pop3-store.c (pop3_try_authenticate): Cast
+ an (unsigned char *) to (char *) to fix a warning
+
+2003-07-17 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-mime-message.c (find_best_encoding): Updated to convert
+ to/from the correct charset (since content is no longer
+ necessarily in UTF-8).
+ (best_encoding): Free the charset string when we're done with it.
+
+ * camel-stream-fs.c (stream_read): Increment the seekable stream
+ position by the number of bytes read. Oops.
+ (stream_write): Same here.
+
+2003-07-17 Timo Sirainen <tss@iki.fi>
+
+ ** See bug #42573
+
+ * providers/imap/camel-imap-folder.c (do_append): Only free the
+ response after we have finished the literal request, otherwise we
+ could try processing folder updates incorrectly.
+
+2003-07-14 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-mime-utils.h: Add the CamelMimePartEncodingType definition
+ here.
+
+ * camel-mime-part.h: Remove the CamelMimePartEncodingType
+ definition.
+
+ * camel-mime-part-utils.c
+ (simple_data_wrapper_construct_from_parser): Don't do any of the
+ auto-detection we used to do here anymore. Just read the content
+ into a memory buffer and record the encoding type.
+ (camel_mime_part_construct_content_from_parser): Don't mangle the
+ Content-Type struct here anymore.
+
+ * camel-data-wrapper.c (camel_data_wrapper_init): Init encoding to
+ DEFAULT.
+ (write_to_stream): If the stream needs to be decoded, decode it.
+
+2003-07-15 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-stream-fs.c (stream_read): If we read 0 bytes, then set
+ eos to TRUE.
+
+2003-07-09 Jeffrey Stedfast <fejj@ximian.com>
+
+ Get rid of the #ifdef ENABLE_THREADS since we no longer plan to
+ support/maintain this.
+
+ * providers/nntp/camel-nntp-store.c: Here.
+
+ * providers/nntp/camel-nntp-newsrc.c: And here.
+
+ * providers/nntp/camel-nntp-folder.c: Same.
+
+ * providers/local/camel-local-folder.c: And here.
+
+ * camel-block-file.c: Here too.
+
+ * camel.c: Same.
+
+ * camel-certdb.c: Here too.
+
+ * camel-charset-map.c: And here.
+
+ * camel-cipher-context.c: "
+
+ * camel-data-wrapper.c: "
+
+ * camel-digest-folder.c: "
+
+ * camel-exception.c: "
+
+ * camel-folder.c: "
+
+ * camel-folder-summary.c: "
+
+ * camel-lock-client.c: "
+
+ * camel-mime-utils.c: "
+
+ * camel-object.c: "
+
+ * camel-operation.c: "
+
+ * camel-partition-table.c: "
+
+ * camel-sasl-popb4smtp.c: "
+
+ * camel-service.c: "
+
+ * camel-session.c: "
+
+ * camel-store.c: "
+
+ * camel-store-summary.c: "
+
+ * camel-text-index.c: "
+
+ * camel-transport.c: "
+
+ * camel-vee-folder.c: "
+
+ * camel-tcp-stream-openssl.c: Removed pthread.h, it isn't needed.
+
+2003-07-09 Larry Ewing <lewing@ximian.com>
+
+ * camel.h: remove reference to camel-pgp-mime.h
+
+2003-07-08 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-pgp-mime.[c,h]: Removed.
+
+ * camel-iconv.c: Updated (new copy/paste from e-iconv).
+
+ * camel-block-file.c (camel_block_file_get_block): Use
+ camel_read() rather than libc read.
+
+ * camel-tcp-stream-raw.c (stream_read): Use camel_read().
+ (stream_write): Use camel_write().
+
+ * camel-stream-fs.c (stream_read): Use camel_read().
+ (stream_write): Use camel_write().
+
+2003-07-07 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/nntp/camel-nntp-folder.c (camel_nntp_folder_new): Use
+ camel_mkdir().
+
+ * providers/imap/camel-imap-folder.c (camel_imap_folder_new): Use
+ camel_mkdir().
+
+ * camel-session.c (get_storage_path): Use camel_mkdir().
+
+ * camel-store.c (camel_mkdir_hier): Removed.
+
+ * camel-data-cache.c (camel_data_cache_new): Updated to use
+ camel_mkdir().
+ (data_cache_path): Same.
+
+ * camel-file-utils.c (camel_mkdir): Renamed and documented.
+ (camel_file_util_safe_filename): Documented.
+ (camel_read): Moved here from camel-io.c
+ (camel_write): Same.
+
+ * camel-io.[c,h]: Removed.
+
+ * camel-uid-cache.c (camel_uid_cache_new): Use the
+ camel-file-utils.c version of mkdir.
+
+2003-07-07 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-session.c (camel_session_init): Updated for string-utils
+ namespace changes.
+
+ * camel-provider.c: Updated for string-utils namespace changes.
+
+ * camel-mime-part.c (init_header_name_table): Updated for
+ string-utils namespace changes.
+
+ * camel-mime-message.c (camel_mime_message_class_init): Updated
+ for string-utils namespace changes.
+ (camel_mime_message_init): Same.
+
+ * camel-mime-filter-enriched.c
+ (camel_mime_filter_enriched_class_init): Updated for string-utils
+ namespace changes.
+
+ * camel-folder-summary.c (camel_folder_summary_init): Updated for
+ string-utils namespace changes.
+
+ * camel-string-utils.[c,h]: Renamed from string-utils.[c,h] and
+ also namespaced all functions.
+
+2003-07-01 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-sasl-digest-md5.c (digest_response): Don't quote the
+ charset value, the qop value, nor the response value. Fixes bug
+ #45712.
+
+2003-07-01 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-mime-utils.c (header_format_date): Use gmtime_r() instead
+ of using gmtime() and memcpy() to try and be "atomic".
+
+2003-06-30 Dan Winship <danw@ximian.com>
+
+ * camel-folder-search.c (camel_folder_search_finalize): free the
+ summary hash
+
+2003-06-24 David Woodhouse <dwmw2@infradead.org>
+
+ * camel-mime-utils.c (header_format_date): Put day of week into
+ outgoing email.
+
+
+2003-06-25 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-folder-summary.h: Added prototype for
+ camel_folder_summary_remove_range().
+
+2003-06-25 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #45386
+
+ * camel-service.c (camel_gethostbyname, camel_gethostbyaddr): Make
+ sure we have an exception that we test against.
+
+2003-06-20 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #43887
+
+ * camel-mime-filter-enriched.c (camel_enriched_to_html): simple
+ wrapper to convert enriched to html in one go.
+
+2003-06-18 Not Zed <NotZed@Ximian.com>
+
+ * camel-service.c (get_hostbyaddr, get_hostbyname): if we got
+ cancelled, the message is floating, so free it.
+ (struct _lookup_msg): Add a cancelled tag.
+ (camel_gethostbyname, camel_gethostbyaddr): if we get a
+ failure/cancel, cancel the lookup thread and detach, so we dont
+ have to wait for it to return. cleanup changed to handle the case
+ where we didn't get a reply message.
+
+2003-06-13 Jeffrey Stedfast <fejj@ximian.com>
+
+ * providers/pop3/camel-pop3-folder.c (pop3_finalize): Made static
+ (to match the prototype).
+
+2003-06-13 Larry Ewing <lewing@ximian.com>
+
+ * camel-folder-thread.c (camel_folder_thread_messages_apply):
+ don't leak the summary when reloading it. Fixes a very large
+ leak.
+
+2003-06-17 Not Zed <NotZed@Ximian.com>
+
+ * camel-vee-folder.c (vee_folder_remove_folder): Calculate ranges
+ to remove folder info's more efficiently. affects shutdown
+ performance on big vfolders signifinantly.
+ (vee_folder_build_folder): do the same here, when rebuilding a
+ folder's definition.
+
+ * camel-folder-summary.c (camel_folder_summary_remove_index): new
+ function to drop a range of index entries in one hit.
+
+2003-06-16 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #31745
+
+ * providers/imap/camel-imap-store-summary.c
+ (camel_imap_store_summary_namespace_new): Workaround a shell bug -
+ if the namespace has '#' in it, then strip it.
+
+2003-06-16 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #44322
+
+ * providers/imap/camel-imap-command.c (imap_command_strdup_vprintf):
+ If we are outputting a folder name, make sure we calculate buffer
+ size based on the raw/utf7 version
+
+ ** See bug #44121
+
+ * camel-multipart-signed.c (signed_get_part): If we can't parse
+ the content, but we have a stream, just use that as the content.
+
+2003-06-05 Jeffrey Stedfast <fejj@ximian.com>
+
+ Fix for bug #40788.
+
+ * providers/pop3/camel-pop3-engine.c (camel_pop3_engine_new): Now
+ takes a flags argument. Currently there is only 1 flag which can
+ be used to disable Pop3 server extensions.
+ (get_capabilities): Don't check for Pop3 server extensions if the
+ DISABLE_EXTENSIONS flag is set on the engine.
+ (camel_pop3_engine_iterate): If we get a response that is neither
+ +OK nor -ERR, default to treating it like a -ERR.
+
+ * providers/pop3/camel-pop3-store.c (connect_to_server): Check for
+ the disable_extensions param.
+
+ * providers/pop3/camel-pop3-provider.c: Define a checkbox to
+ disable all POP3 extension support.
+
+2003-06-11 Jeffrey Stedfast <fejj@ximian.com>
+
+ Partial fix for bug #44457.
+
+ * camel-mime-part-utils.c
+ (simple_data_wrapper_construct_from_parser): Make sure to set
+ rawtext to FALSE if we successfully convert the text to UTF-8.
+
+ * camel-data-wrapper.c (camel_data_wrapper_init): Default the
+ value of rawtext to TRUE instead of FALSE. This way if the mailer
+ decides to try displaying a non-textual part as text, it knows
+ that it needs to convert the content to UTF-8.
+
+2003-06-04 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-uid-cache.c (camel_uid_cache_new): Create the directory
+ with mode 0777 and the cache file itself with mode 0666. Let the
+ user's umask filter the permissions. Instead of saving the fd on
+ the Cache object, instead save the filename. Use camel_read()
+ instead of expecting read() to just always work without getting an
+ EINTR/etc.
+ (maybe_write_uid): Don't do anything if cache->fd == -1, this
+ means an error has occured in a previous callback. Replace the 2
+ calls to write() with camel_write() and check their return
+ values. If either of them fails, set cache->fd to -1 (GHashTable
+ doesn't give us a way to abort foreach'ing thru the table).
+ (camel_uid_cache_save): Save to a temp file instead of overwriting
+ the original. Do proper error checking, etc. Also added some
+ smarts about whether to try and overwrite the old cache even if we
+ haven't successfully saved all the uids in the cache.
+ (camel_uid_cache_destroy): Free the cache->filename, no longer
+ need to close (cache->fd).
+
+2003-06-11 Larry Ewing <lewing@ximian.com>
+
+ * camel-text-index.c (text_index_normalise): use g_utf8_strdown
+ properly.
+
+2003-06-09 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-mime-message.c (find_best_encoding): Add the
+ CAMEL_BESTENC_TEXT bit to enctype if the part is a text part.
+
+ * camel-mime-filter-bestenc.c
+ (camel_mime_filter_bestenc_get_best_encoding): If we have any
+ nul-bytes or if the content is non-text and contains any 8bit
+ octets, we need to use base64. Fixes bug #44344.
diff --git a/camel/camel-charset-map.c b/camel/camel-charset-map.c
new file mode 100644
index 0000000000..59f916c700
--- /dev/null
+++ b/camel/camel-charset-map.c
@@ -0,0 +1,361 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; -*- */
+/*
+ * Authors:
+ * Michael Zucchi <notzed@ximian.com>
+ * Jeffrey Stedfast <fejj@ximian.com>
+ * Dan Winship <danw@ximian.com>
+ *
+ * Copyright 2000-2003 Ximian, Inc. (www.ximian.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+/*
+ if you want to build the charset map, compile this with something like:
+ gcc -DBUILD_MAP camel-charset-map.c `glib-config --cflags`
+ (plus any -I/-L/-l flags you need for iconv), then run it as
+ ./a.out > camel-charset-map-private.h
+
+ Note that the big-endian variant isn't tested...
+
+ The tables genereated work like this:
+
+ An indirect array for each page of unicode character
+ Each array element has an indirect pointer to one of the bytes of
+ the generated bitmask.
+*/
+
+#ifdef BUILD_MAP
+#include <iconv.h>
+#include <glib.h>
+
+static struct {
+ char *name;
+ unsigned int bit; /* assigned bit */
+} tables[] = {
+ /* These are the 8bit character sets (other than iso-8859-1,
+ * which is special-cased) which are supported by both other
+ * mailers and the GNOME environment. Note that the order
+ * they're listed in is the order they'll be tried in, so put
+ * the more-popular ones first.
+ */
+ { "iso-8859-2", 0 }, /* Central/Eastern European */
+ { "iso-8859-4", 0 }, /* Baltic */
+ { "koi8-r", 0 }, /* Russian */
+ { "koi8-u", 0 }, /* Ukranian */
+ { "iso-8859-5", 0 }, /* Least-popular Russian encoding */
+ { "iso-8859-7", 0 }, /* Greek */
+ { "iso-8859-8", 0 }, /* Hebrew; Visual */
+ { "iso-8859-9", 0 }, /* Turkish */
+ { "iso-8859-13", 0 }, /* Baltic again */
+ { "iso-8859-15", 0 }, /* New-and-improved iso-8859-1, but most
+ * programs that support this support UTF8
+ */
+ { "windows-1251", 0 }, /* Russian */
+ { 0, 0 }
+};
+
+unsigned int encoding_map[256 * 256];
+
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+#define UCS "UCS-4BE"
+#else
+#define UCS "UCS-4LE"
+#endif
+
+int main (void)
+{
+ int i, j;
+ int max, min;
+ int bit = 0x01;
+ int k;
+ int bytes;
+ iconv_t cd;
+ char in[128];
+ guint32 out[128];
+ char *inptr, *outptr;
+ size_t inlen, outlen;
+
+ /* dont count the terminator */
+ bytes = ((sizeof(tables)/sizeof(tables[0]))+7-1)/8;
+
+ for (i = 0; i < 128; i++)
+ in[i] = i + 128;
+
+ for (j = 0; tables[j].name; j++) {
+ cd = iconv_open (UCS, tables[j].name);
+ inptr = in;
+ outptr = (char *)(out);
+ inlen = sizeof (in);
+ outlen = sizeof (out);
+ while (iconv (cd, &inptr, &inlen, &outptr, &outlen) == -1) {
+ if (errno == EILSEQ) {
+ inptr++;
+ inlen--;
+ } else {
+ printf ("%s\n", strerror (errno));
+ exit (1);
+ }
+ }
+ iconv_close (cd);
+
+ for (i = 0; i < 128 - outlen / 4; i++) {
+ encoding_map[i] |= bit;
+ encoding_map[out[i]] |= bit;
+ }
+
+ tables[j].bit = bit;
+ bit <<= 1;
+ }
+
+ printf("/* This file is automatically generated: DO NOT EDIT */\n\n");
+
+ for (i=0;i<256;i++) {
+ /* first, do we need this block? */
+ for (k=0;k<bytes;k++) {
+ for (j=0;j<256;j++) {
+ if ((encoding_map[i*256 + j] & (0xff << (k*8))) != 0)
+ break;
+ }
+ if (j < 256) {
+ /* yes, dump it */
+ printf("static unsigned char m%02x%x[256] = {\n\t", i, k);
+ for (j=0;j<256;j++) {
+ printf("0x%02x, ", (encoding_map[i*256+j] >> (k*8)) & 0xff );
+ if (((j+1)&7) == 0 && j<255)
+ printf("\n\t");
+ }
+ printf("\n};\n\n");
+ }
+ }
+ }
+
+ printf("struct {\n");
+ for (k=0;k<bytes;k++) {
+ printf("\tunsigned char *bits%d;\n", k);
+ }
+ printf("} camel_charmap[256] = {\n\t");
+ for (i=0;i<256;i++) {
+ /* first, do we need this block? */
+ printf("{ ");
+ for (k=0;k<bytes;k++) {
+ for (j=0;j<256;j++) {
+ if ((encoding_map[i*256 + j] & (0xff << (k*8))) != 0)
+ break;
+ }
+ if (j < 256) {
+ printf("m%02x%x, ", i, k);
+ } else {
+ printf("0, ");
+ }
+ }
+ printf("}, ");
+ if (((i+1)&7) == 0 && i<255)
+ printf("\n\t");
+ }
+ printf("\n};\n\n");
+
+ printf("struct {\n\tconst char *name;\n\tunsigned int bit;\n} camel_charinfo[] = {\n");
+ for (j=0;tables[j].name;j++) {
+ printf("\t{ \"%s\", 0x%04x },\n", tables[j].name, tables[j].bit);
+ }
+ printf("};\n\n");
+
+ printf("#define charset_mask(x) \\\n");
+ for (k=0;k<bytes;k++) {
+ if (k!=0)
+ printf("\t| ");
+ else
+ printf("\t");
+ printf("(camel_charmap[(x)>>8].bits%d?camel_charmap[(x)>>8].bits%d[(x)&0xff]<<%d:0)", k, k, k*8);
+ if (k<bytes-1)
+ printf("\t\\\n");
+ }
+ printf("\n\n");
+
+ return 0;
+}
+
+#else
+
+#include "camel-charset-map.h"
+#include "camel-charset-map-private.h"
+
+#include <gal/util/e-iconv.h>
+
+#include <glib.h>
+#include <locale.h>
+#include <ctype.h>
+#include <pthread.h>
+#ifdef HAVE_CODESET
+#include <langinfo.h>
+#endif
+
+void
+camel_charset_init (CamelCharset *c)
+{
+ c->mask = (unsigned int) ~0;
+ c->level = 0;
+}
+
+void
+camel_charset_step (CamelCharset *c, const char *in, int len)
+{
+ register unsigned int mask;
+ register int level;
+ const char *inptr = in, *inend = in+len;
+
+ mask = c->mask;
+ level = c->level;
+
+ /* check what charset a given string will fit in */
+ while (inptr < inend) {
+ gunichar c;
+ const char *newinptr;
+ newinptr = g_utf8_next_char(inptr);
+ c = g_utf8_get_char(inptr);
+ if (newinptr == NULL || !g_unichar_validate (c)) {
+ inptr++;
+ continue;
+ }
+
+ inptr = newinptr;
+ if (c<=0xffff) {
+ mask &= charset_mask(c);
+
+ if (c>=128 && c<256)
+ level = MAX(level, 1);
+ else if (c>=256)
+ level = MAX(level, 2);
+ } else {
+ mask = 0;
+ level = MAX(level, 2);
+ }
+ }
+
+ c->mask = mask;
+ c->level = level;
+}
+
+/* gets the best charset from the mask of chars in it */
+static const char *
+camel_charset_best_mask(unsigned int mask)
+{
+ const char *locale_lang, *lang;
+ int i;
+
+ locale_lang = e_iconv_locale_language ();
+ for (i = 0; i < G_N_ELEMENTS (camel_charinfo); i++) {
+ if (camel_charinfo[i].bit & mask) {
+ lang = e_iconv_charset_language (camel_charinfo[i].name);
+
+ if (!lang || (locale_lang && !strncmp (locale_lang, lang, 2)))
+ return camel_charinfo[i].name;
+ }
+ }
+
+ return "UTF-8";
+}
+
+const char *
+camel_charset_best_name (CamelCharset *charset)
+{
+ if (charset->level == 1)
+ return "ISO-8859-1";
+ else if (charset->level == 2)
+ return camel_charset_best_mask (charset->mask);
+ else
+ return NULL;
+
+}
+
+/* finds the minimum charset for this string NULL means US-ASCII */
+const char *
+camel_charset_best (const char *in, int len)
+{
+ CamelCharset charset;
+
+ camel_charset_init (&charset);
+ camel_charset_step (&charset, in, len);
+ return camel_charset_best_name (&charset);
+}
+
+
+/**
+ * camel_charset_iso_to_windows:
+ * @isocharset: a canonicalised ISO charset
+ *
+ * Returns the equivalent Windows charset.
+ **/
+const char *
+camel_charset_iso_to_windows (const char *isocharset)
+{
+ /* According to http://czyborra.com/charsets/codepages.html,
+ * the charset mapping is as follows:
+ *
+ * us-ascii maps to windows-cp1252
+ * iso-8859-1 maps to windows-cp1252
+ * iso-8859-2 maps to windows-cp1250
+ * iso-8859-3 maps to windows-cp????
+ * iso-8859-4 maps to windows-cp????
+ * iso-8859-5 maps to windows-cp1251
+ * iso-8859-6 maps to windows-cp1256
+ * iso-8859-7 maps to windows-cp1253
+ * iso-8859-8 maps to windows-cp1255
+ * iso-8859-9 maps to windows-cp1254
+ * iso-8859-10 maps to windows-cp????
+ * iso-8859-11 maps to windows-cp????
+ * iso-8859-12 maps to windows-cp????
+ * iso-8859-13 maps to windows-cp1257
+ *
+ * Assumptions:
+ * - I'm going to assume that since iso-8859-4 and
+ * iso-8859-13 are Baltic that it also maps to
+ * windows-cp1257.
+ */
+
+ if (!g_ascii_strcasecmp (isocharset, "iso-8859-1") || !g_ascii_strcasecmp (isocharset, "us-ascii"))
+ return "windows-cp1252";
+ else if (!g_ascii_strcasecmp (isocharset, "iso-8859-2"))
+ return "windows-cp1250";
+ else if (!g_ascii_strcasecmp (isocharset, "iso-8859-4"))
+ return "windows-cp1257";
+ else if (!g_ascii_strcasecmp (isocharset, "iso-8859-5"))
+ return "windows-cp1251";
+ else if (!g_ascii_strcasecmp (isocharset, "iso-8859-6"))
+ return "windows-cp1256";
+ else if (!g_ascii_strcasecmp (isocharset, "iso-8859-7"))
+ return "windows-cp1253";
+ else if (!g_ascii_strcasecmp (isocharset, "iso-8859-8"))
+ return "windows-cp1255";
+ else if (!g_ascii_strcasecmp (isocharset, "iso-8859-9"))
+ return "windows-cp1254";
+ else if (!g_ascii_strcasecmp (isocharset, "iso-8859-13"))
+ return "windows-cp1257";
+
+ return isocharset;
+}
+
+#endif /* !BUILD_MAP */
diff --git a/camel/camel-filter-driver.c b/camel/camel-filter-driver.c
new file mode 100644
index 0000000000..af65d5ba7f
--- /dev/null
+++ b/camel/camel-filter-driver.c
@@ -0,0 +1,1526 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2000 Ximian Inc.
+ *
+ * Authors: Michael Zucchi <notzed@ximian.com>
+ * Jeffrey Stedfast <fejj@ximian.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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <string.h>
+#include <time.h>
+
+#include <glib.h>
+
+#include "camel-filter-driver.h"
+#include "camel-filter-search.h"
+
+#include "camel-service.h"
+#include "camel-stream-fs.h"
+#include "camel-stream-mem.h"
+#include "camel-mime-message.h"
+
+#include "camel-debug.h"
+
+#include "e-util/e-sexp.h"
+#include "e-util/e-memory.h"
+#include "e-util/e-msgport.h" /* for edlist */
+
+#define d(x)
+
+/* an invalid pointer */
+#define FOLDER_INVALID ((void *)~0)
+
+/* type of status for a log report */
+enum filter_log_t {
+ FILTER_LOG_NONE,
+ FILTER_LOG_START, /* start of new log entry */
+ FILTER_LOG_ACTION, /* an action performed */
+ FILTER_LOG_END, /* end of log */
+};
+
+/* list of rule nodes */
+struct _filter_rule {
+ struct _filter_rule *next;
+ struct _filter_rule *prev;
+
+ char *match;
+ char *action;
+ char *name;
+};
+
+struct _CamelFilterDriverPrivate {
+ GHashTable *globals; /* global variables */
+
+ CamelSession *session;
+
+ CamelFolder *defaultfolder; /* defualt folder */
+
+ CamelFilterStatusFunc *statusfunc; /* status callback */
+ void *statusdata; /* status callback data */
+
+ CamelFilterShellFunc *shellfunc; /* execute shell command callback */
+ void *shelldata; /* execute shell command callback data */
+
+ CamelFilterPlaySoundFunc *playfunc; /* play-sound command callback */
+ void *playdata; /* play-sound command callback data */
+
+ CamelFilterSystemBeepFunc *beep; /* system beep callback */
+ void *beepdata; /* system beep callback data */
+
+ /* for callback */
+ CamelFilterGetFolderFunc get_folder;
+ void *data;
+
+ /* run-time data */
+ GHashTable *folders; /* folders that message has been copied to */
+ int closed; /* close count */
+ GHashTable *forwards; /* addresses that have been forwarded the message */
+ GHashTable *only_once; /* actions to run only-once */
+
+ gboolean terminated; /* message processing was terminated */
+ gboolean deleted; /* message was marked for deletion */
+ gboolean copied; /* message was copied to some folder or another */
+
+ CamelMimeMessage *message; /* input message */
+ CamelMessageInfo *info; /* message summary info */
+ const char *uid; /* message uid */
+ CamelFolder *source; /* message source folder */
+ gboolean modified; /* has the input message been modified? */
+
+ FILE *logfile; /* log file */
+
+ EDList rules; /* list of _filter_rule structs */
+
+ CamelException *ex;
+
+ /* evaluator */
+ ESExp *eval;
+};
+
+#define _PRIVATE(o) (((CamelFilterDriver *)(o))->priv)
+
+static void camel_filter_driver_class_init (CamelFilterDriverClass *klass);
+static void camel_filter_driver_init (CamelFilterDriver *obj);
+static void camel_filter_driver_finalise (CamelObject *obj);
+
+static void camel_filter_driver_log (CamelFilterDriver *driver, enum filter_log_t status, const char *desc, ...);
+
+static CamelFolder *open_folder (CamelFilterDriver *d, const char *folder_url);
+static int close_folders (CamelFilterDriver *d);
+
+static ESExpResult *do_delete (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFilterDriver *);
+static ESExpResult *mark_forward (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFilterDriver *);
+static ESExpResult *do_copy (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFilterDriver *);
+static ESExpResult *do_move (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFilterDriver *);
+static ESExpResult *do_stop (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFilterDriver *);
+static ESExpResult *do_colour (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFilterDriver *);
+static ESExpResult *do_score (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFilterDriver *);
+static ESExpResult *do_adjust_score(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFilterDriver *);
+static ESExpResult *set_flag (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFilterDriver *);
+static ESExpResult *unset_flag (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFilterDriver *);
+static ESExpResult *do_shell (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFilterDriver *);
+static ESExpResult *do_beep (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFilterDriver *);
+static ESExpResult *play_sound (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFilterDriver *);
+static ESExpResult *do_only_once (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFilterDriver *);
+static ESExpResult *pipe_message (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFilterDriver *);
+
+/* these are our filter actions - each must have a callback */
+static struct {
+ char *name;
+ ESExpFunc *func;
+ int type; /* set to 1 if a function can perform shortcut evaluation, or
+ doesn't execute everything, 0 otherwise */
+} symbols[] = {
+ { "delete", (ESExpFunc *) do_delete, 0 },
+ { "forward-to", (ESExpFunc *) mark_forward, 0 },
+ { "copy-to", (ESExpFunc *) do_copy, 0 },
+ { "move-to", (ESExpFunc *) do_move, 0 },
+ { "stop", (ESExpFunc *) do_stop, 0 },
+ { "set-colour", (ESExpFunc *) do_colour, 0 },
+ { "set-score", (ESExpFunc *) do_score, 0 },
+ { "adjust-score", (ESExpFunc *) do_adjust_score, 0 },
+ { "set-system-flag", (ESExpFunc *) set_flag, 0 },
+ { "unset-system-flag", (ESExpFunc *) unset_flag, 0 },
+ { "pipe-message", (ESExpFunc *) pipe_message, 0 },
+ { "shell", (ESExpFunc *) do_shell, 0 },
+ { "beep", (ESExpFunc *) do_beep, 0 },
+ { "play-sound", (ESExpFunc *) play_sound, 0 },
+ { "only-once", (ESExpFunc *) do_only_once, 0 }
+};
+
+static CamelObjectClass *camel_filter_driver_parent;
+
+CamelType
+camel_filter_driver_get_type (void)
+{
+ static CamelType type = CAMEL_INVALID_TYPE;
+
+ if (type == CAMEL_INVALID_TYPE) {
+ type = camel_type_register (CAMEL_OBJECT_TYPE,
+ "CamelFilterDriver",
+ sizeof (CamelFilterDriver),
+ sizeof (CamelFilterDriverClass),
+ (CamelObjectClassInitFunc) camel_filter_driver_class_init,
+ NULL,
+ (CamelObjectInitFunc) camel_filter_driver_init,
+ (CamelObjectFinalizeFunc) camel_filter_driver_finalise);
+ }
+
+ return type;
+}
+
+static void
+camel_filter_driver_class_init (CamelFilterDriverClass *klass)
+{
+ /*CamelObjectClass *object_class = (CamelObjectClass *) klass;*/
+
+ camel_filter_driver_parent = camel_type_get_global_classfuncs(camel_object_get_type());
+}
+
+static void
+camel_filter_driver_init (CamelFilterDriver *obj)
+{
+ struct _CamelFilterDriverPrivate *p;
+ int i;
+
+ p = _PRIVATE (obj) = g_malloc0 (sizeof (*p));
+
+ e_dlist_init(&p->rules);
+
+ p->eval = e_sexp_new ();
+ /* Load in builtin symbols */
+ for (i = 0; i < sizeof (symbols) / sizeof (symbols[0]); i++) {
+ if (symbols[i].type == 1) {
+ e_sexp_add_ifunction (p->eval, 0, symbols[i].name, (ESExpIFunc *)symbols[i].func, obj);
+ } else {
+ e_sexp_add_function (p->eval, 0, symbols[i].name, symbols[i].func, obj);
+ }
+ }
+
+ p->globals = g_hash_table_new (g_str_hash, g_str_equal);
+
+ p->folders = g_hash_table_new (g_str_hash, g_str_equal);
+
+ p->only_once = g_hash_table_new (g_str_hash, g_str_equal);
+}
+
+static void
+free_hash_strings (void *key, void *value, void *data)
+{
+ g_free (key);
+ g_free (value);
+}
+
+static void
+camel_filter_driver_finalise (CamelObject *obj)
+{
+ CamelFilterDriver *driver = (CamelFilterDriver *) obj;
+ struct _CamelFilterDriverPrivate *p = _PRIVATE (driver);
+ struct _filter_rule *node;
+
+ /* close all folders that were opened for appending */
+ close_folders (driver);
+ g_hash_table_destroy (p->folders);
+
+ g_hash_table_foreach (p->globals, free_hash_strings, driver);
+ g_hash_table_destroy (p->globals);
+
+ g_hash_table_foreach (p->only_once, free_hash_strings, driver);
+ g_hash_table_destroy (p->only_once);
+
+ e_sexp_unref(p->eval);
+
+ if (p->defaultfolder) {
+ camel_folder_thaw (p->defaultfolder);
+ camel_object_unref (p->defaultfolder);
+ }
+
+ while ((node = (struct _filter_rule *)e_dlist_remhead(&p->rules))) {
+ g_free(node->match);
+ g_free(node->action);
+ g_free(node->name);
+ g_free(node);
+ }
+
+ camel_object_unref(p->session);
+
+ g_free (p);
+}
+
+/**
+ * camel_filter_driver_new:
+ *
+ * Return value: A new CamelFilterDriver object
+ **/
+CamelFilterDriver *
+camel_filter_driver_new (CamelSession *session)
+{
+ CamelFilterDriver *d = (CamelFilterDriver *)camel_object_new(camel_filter_driver_get_type());
+
+ d->priv->session = session;
+ camel_object_ref((CamelObject *)session);
+
+ return d;
+}
+
+void
+camel_filter_driver_set_folder_func (CamelFilterDriver *d, CamelFilterGetFolderFunc get_folder, void *data)
+{
+ struct _CamelFilterDriverPrivate *p = _PRIVATE (d);
+
+ p->get_folder = get_folder;
+ p->data = data;
+}
+
+void
+camel_filter_driver_set_logfile (CamelFilterDriver *d, FILE *logfile)
+{
+ struct _CamelFilterDriverPrivate *p = _PRIVATE (d);
+
+ p->logfile = logfile;
+}
+
+void
+camel_filter_driver_set_status_func (CamelFilterDriver *d, CamelFilterStatusFunc *func, void *data)
+{
+ struct _CamelFilterDriverPrivate *p = _PRIVATE (d);
+
+ p->statusfunc = func;
+ p->statusdata = data;
+}
+
+void
+camel_filter_driver_set_shell_func (CamelFilterDriver *d, CamelFilterShellFunc *func, void *data)
+{
+ struct _CamelFilterDriverPrivate *p = _PRIVATE (d);
+
+ p->shellfunc = func;
+ p->shelldata = data;
+}
+
+void
+camel_filter_driver_set_play_sound_func (CamelFilterDriver *d, CamelFilterPlaySoundFunc *func, void *data)
+{
+ struct _CamelFilterDriverPrivate *p = _PRIVATE (d);
+
+ p->playfunc = func;
+ p->playdata = data;
+}
+
+void
+camel_filter_driver_set_system_beep_func (CamelFilterDriver *d, CamelFilterSystemBeepFunc *func, void *data)
+{
+ struct _CamelFilterDriverPrivate *p = _PRIVATE (d);
+
+ p->beep = func;
+ p->beepdata = data;
+}
+
+void
+camel_filter_driver_set_default_folder (CamelFilterDriver *d, CamelFolder *def)
+{
+ struct _CamelFilterDriverPrivate *p = _PRIVATE (d);
+
+ if (p->defaultfolder) {
+ camel_folder_thaw (p->defaultfolder);
+ camel_object_unref (p->defaultfolder);
+ }
+
+ p->defaultfolder = def;
+
+ if (p->defaultfolder) {
+ camel_folder_freeze (p->defaultfolder);
+ camel_object_ref (p->defaultfolder);
+ }
+}
+
+void
+camel_filter_driver_add_rule(CamelFilterDriver *d, const char *name, const char *match, const char *action)
+{
+ struct _CamelFilterDriverPrivate *p = _PRIVATE (d);
+ struct _filter_rule *node;
+
+ node = g_malloc(sizeof(*node));
+ node->match = g_strdup(match);
+ node->action = g_strdup(action);
+ node->name = g_strdup(name);
+ e_dlist_addtail(&p->rules, (EDListNode *)node);
+}
+
+int
+camel_filter_driver_remove_rule_by_name (CamelFilterDriver *d, const char *name)
+{
+ struct _CamelFilterDriverPrivate *p = _PRIVATE (d);
+ struct _filter_rule *node;
+
+ node = (struct _filter_rule *) p->rules.head;
+ while (node->next) {
+ if (!strcmp (node->name, name)) {
+ e_dlist_remove ((EDListNode *) node);
+ g_free (node->match);
+ g_free (node->action);
+ g_free (node->name);
+ g_free (node);
+
+ return 0;
+ }
+
+ node = node->next;
+ }
+
+ return -1;
+}
+
+static void
+report_status (CamelFilterDriver *driver, enum camel_filter_status_t status, int pc, const char *desc, ...)
+{
+ /* call user-defined status report function */
+ struct _CamelFilterDriverPrivate *p = _PRIVATE (driver);
+ va_list ap;
+ char *str;
+
+ if (p->statusfunc) {
+ va_start (ap, desc);
+ str = g_strdup_vprintf (desc, ap);
+ p->statusfunc (driver, status, pc, str, p->statusdata);
+ g_free (str);
+ }
+}
+
+
+#if 0
+void
+camel_filter_driver_set_global (CamelFilterDriver *d, const char *name, const char *value)
+{
+ struct _CamelFilterDriverPrivate *p = _PRIVATE (d);
+ char *oldkey, *oldvalue;
+
+ if (g_hash_table_lookup_extended (p->globals, name, (void *)&oldkey, (void *)&oldvalue)) {
+ g_free (oldvalue);
+ g_hash_table_insert (p->globals, oldkey, g_strdup (value));
+ } else {
+ g_hash_table_insert (p->globals, g_strdup (name), g_strdup (value));
+ }
+}
+#endif
+
+static ESExpResult *
+do_delete (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFilterDriver *driver)
+{
+ struct _CamelFilterDriverPrivate *p = _PRIVATE (driver);
+
+ d(fprintf (stderr, "doing delete\n"));
+ p->deleted = TRUE;
+ camel_filter_driver_log (driver, FILTER_LOG_ACTION, "Delete");
+
+ return NULL;
+}
+
+static ESExpResult *
+mark_forward (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFilterDriver *driver)
+{
+ /*struct _CamelFilterDriverPrivate *p = _PRIVATE (driver);*/
+
+ d(fprintf (stderr, "marking message for forwarding\n"));
+ /* FIXME: do stuff here */
+ camel_filter_driver_log (driver, FILTER_LOG_ACTION, "Forward");
+
+ return NULL;
+}
+
+static ESExpResult *
+do_copy (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFilterDriver *driver)
+{
+ struct _CamelFilterDriverPrivate *p = _PRIVATE (driver);
+ int i;
+
+ d(fprintf (stderr, "copying message...\n"));
+
+ for (i = 0; i < argc; i++) {
+ if (argv[i]->type == ESEXP_RES_STRING) {
+ /* open folders we intent to copy to */
+ char *folder = argv[i]->value.string;
+ CamelFolder *outbox;
+
+ outbox = open_folder (driver, folder);
+ if (!outbox)
+ break;
+
+ if (outbox == p->source)
+ break;
+
+ if (!p->modified && p->uid && p->source && camel_folder_has_summary_capability (p->source)) {
+ GPtrArray *uids;
+
+ uids = g_ptr_array_new ();
+ g_ptr_array_add (uids, (char *) p->uid);
+ camel_folder_transfer_messages_to (p->source, uids, outbox, NULL, FALSE, p->ex);
+ g_ptr_array_free (uids, TRUE);
+ } else {
+ if (p->message == NULL)
+ p->message = camel_folder_get_message (p->source, p->uid, p->ex);
+
+ if (!p->message)
+ continue;
+
+ camel_folder_append_message (outbox, p->message, p->info, NULL, p->ex);
+ }
+
+ if (!camel_exception_is_set (p->ex))
+ p->copied = TRUE;
+
+ camel_filter_driver_log (driver, FILTER_LOG_ACTION, "Copy to folder %s",
+ folder);
+ }
+ }
+
+ return NULL;
+}
+
+static ESExpResult *
+do_move (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFilterDriver *driver)
+{
+ struct _CamelFilterDriverPrivate *p = _PRIVATE (driver);
+ int i;
+
+ d(fprintf (stderr, "moving message...\n"));
+
+ for (i = 0; i < argc; i++) {
+ if (argv[i]->type == ESEXP_RES_STRING) {
+ /* open folders we intent to move to */
+ char *folder = argv[i]->value.string;
+ CamelFolder *outbox;
+
+ outbox = open_folder (driver, folder);
+ if (!outbox)
+ break;
+
+ if (outbox == p->source)
+ break;
+
+ if (!p->modified && p->uid && p->source && camel_folder_has_summary_capability (p->source)) {
+ GPtrArray *uids;
+
+ uids = g_ptr_array_new ();
+ g_ptr_array_add (uids, (char *) p->uid);
+ camel_folder_transfer_messages_to (p->source, uids, outbox, NULL, FALSE, p->ex);
+ g_ptr_array_free (uids, TRUE);
+ } else {
+ if (p->message == NULL)
+ p->message = camel_folder_get_message (p->source, p->uid, p->ex);
+
+ if (!p->message)
+ continue;
+
+ camel_folder_append_message (outbox, p->message, p->info, NULL, p->ex);
+ }
+
+ if (!camel_exception_is_set (p->ex)) {
+ /* a 'move' is a copy & delete */
+ p->copied = TRUE;
+ p->deleted = TRUE;
+ }
+
+ camel_filter_driver_log (driver, FILTER_LOG_ACTION, "Move to folder %s",
+ folder);
+ }
+ }
+
+ return NULL;
+}
+
+static ESExpResult *
+do_stop (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFilterDriver *driver)
+{
+ struct _CamelFilterDriverPrivate *p = _PRIVATE (driver);
+
+ camel_filter_driver_log (driver, FILTER_LOG_ACTION, "Stopped processing");
+ d(fprintf (stderr, "terminating message processing\n"));
+ p->terminated = TRUE;
+
+ return NULL;
+}
+
+static ESExpResult *
+do_colour (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFilterDriver *driver)
+{
+ struct _CamelFilterDriverPrivate *p = _PRIVATE (driver);
+
+ d(fprintf (stderr, "setting colour tag\n"));
+ if (argc > 0 && argv[0]->type == ESEXP_RES_STRING) {
+ if (p->source && p->uid && camel_folder_has_summary_capability (p->source))
+ camel_folder_set_message_user_tag (p->source, p->uid, "colour", argv[0]->value.string);
+ else
+ camel_tag_set (&p->info->user_tags, "colour", argv[0]->value.string);
+ camel_filter_driver_log (driver, FILTER_LOG_ACTION, "Set colour to %s", argv[0]->value.string);
+ }
+
+ return NULL;
+}
+
+static ESExpResult *
+do_score (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFilterDriver *driver)
+{
+ struct _CamelFilterDriverPrivate *p = _PRIVATE (driver);
+
+ d(fprintf (stderr, "setting score tag\n"));
+ if (argc > 0 && argv[0]->type == ESEXP_RES_INT) {
+ char *value;
+
+ value = g_strdup_printf ("%d", argv[0]->value.number);
+ if (p->source && p->uid && camel_folder_has_summary_capability (p->source))
+ camel_folder_set_message_user_tag (p->source, p->uid, "score", value);
+ else
+ camel_tag_set (&p->info->user_tags, "score", value);
+ camel_filter_driver_log (driver, FILTER_LOG_ACTION, "Set score to %d", argv[0]->value.number);
+ g_free (value);
+ }
+
+ return NULL;
+}
+
+static ESExpResult *
+do_adjust_score(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFilterDriver *driver)
+{
+ struct _CamelFilterDriverPrivate *p = _PRIVATE(driver);
+
+ d(fprintf (stderr, "adjusting score tag\n"));
+ if (argc > 0 && argv[0]->type == ESEXP_RES_INT) {
+ char *value;
+ int old;
+
+ if (p->source && p->uid && camel_folder_has_summary_capability (p->source))
+ value = (char *)camel_folder_get_message_user_tag (p->source, p->uid, "score");
+ else
+ value = (char *)camel_tag_get(&p->info->user_tags, "score");
+ old = value?atoi(value):0;
+ value = g_strdup_printf ("%d", old+argv[0]->value.number);
+ if (p->source && p->uid && camel_folder_has_summary_capability (p->source))
+ camel_folder_set_message_user_tag (p->source, p->uid, "score", value);
+ else
+ camel_tag_set (&p->info->user_tags, "score", value);
+ camel_filter_driver_log (driver, FILTER_LOG_ACTION, "Adjust score (%d) to %s", argv[0]->value.number, value);
+ g_free (value);
+ }
+
+ return NULL;
+}
+
+static ESExpResult *
+set_flag (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFilterDriver *driver)
+{
+ struct _CamelFilterDriverPrivate *p = _PRIVATE (driver);
+ guint32 flags;
+
+ d(fprintf (stderr, "setting flag\n"));
+ if (argc == 1 && argv[0]->type == ESEXP_RES_STRING) {
+ flags = camel_system_flag (argv[0]->value.string);
+ if (p->source && p->uid && camel_folder_has_summary_capability (p->source))
+ camel_folder_set_message_flags (p->source, p->uid, flags, ~0);
+ else
+ p->info->flags |= flags | CAMEL_MESSAGE_FOLDER_FLAGGED;
+ camel_filter_driver_log (driver, FILTER_LOG_ACTION, "Set %s flag", argv[0]->value.string);
+ }
+
+ return NULL;
+}
+
+static ESExpResult *
+unset_flag (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFilterDriver *driver)
+{
+ struct _CamelFilterDriverPrivate *p = _PRIVATE (driver);
+ guint32 flags;
+
+ d(fprintf (stderr, "unsetting flag\n"));
+ if (argc == 1 && argv[0]->type == ESEXP_RES_STRING) {
+ flags = camel_system_flag (argv[0]->value.string);
+ if (p->source && p->uid && camel_folder_has_summary_capability (p->source))
+ camel_folder_set_message_flags (p->source, p->uid, flags, 0);
+ else
+ p->info->flags = (p->info->flags & ~flags) | CAMEL_MESSAGE_FOLDER_FLAGGED;
+ camel_filter_driver_log (driver, FILTER_LOG_ACTION, "Unset %s flag", argv[0]->value.string);
+ }
+
+ return NULL;
+}
+
+static int
+pipe_to_system (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFilterDriver *driver)
+{
+ struct _CamelFilterDriverPrivate *p = _PRIVATE (driver);
+ int result, status, fds[4], i;
+ CamelMimeMessage *message = NULL;
+ CamelMimeParser *parser;
+ CamelStream *stream, *mem;
+ pid_t pid;
+
+ if (argc < 1 || argv[0]->value.string[0] == '\0')
+ return 0;
+
+ /* make sure we have the message... */
+ if (p->message == NULL) {
+ if (!(p->message = camel_folder_get_message (p->source, p->uid, p->ex)))
+ return -1;
+ }
+
+ for (i = 0; i < 4; i++)
+ fds[i] = -1;
+
+ for (i = 0; i < 4; i += 2) {
+ if (pipe (fds + i) == -1) {
+ camel_exception_setv (p->ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Failed to create pipe to '%s': %s"),
+ argv[0]->value.string, g_strerror (errno));
+
+ for (i = 0; i < 4; i++) {
+ if (fds[i] == -1)
+ break;
+ close (fds[i]);
+ }
+
+ return -1;
+ }
+ }
+
+ if (!(pid = fork ())) {
+ /* child process */
+ GPtrArray *args;
+ int maxfd, fd;
+
+ fd = open ("/dev/null", O_WRONLY);
+
+ if (dup2 (fds[0], STDIN_FILENO) < 0 ||
+ dup2 (fds[3], STDOUT_FILENO) < 0 ||
+ dup2 (fd, STDERR_FILENO) < 0)
+ _exit (255);
+
+ setsid ();
+
+ maxfd = sysconf (_SC_OPEN_MAX);
+ for (fd = 3; fd < maxfd; fd++)
+ fcntl (fd, F_SETFD, FD_CLOEXEC);
+
+ args = g_ptr_array_new ();
+ for (i = 0; i < argc; i++)
+ g_ptr_array_add (args, argv[i]->value.string);
+ g_ptr_array_add (args, NULL);
+
+ execvp (argv[0]->value.string, (char **) args->pdata);
+
+ g_ptr_array_free (args, TRUE);
+
+ d(printf ("Could not execute %s: %s\n", argv[0]->value.string, g_strerror (errno)));
+ _exit (255);
+ } else if (pid < 0) {
+ camel_exception_setv (p->ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Failed to create child process '%s': %s"),
+ argv[0]->value.string, g_strerror (errno));
+ return -1;
+ }
+
+ /* parent process */
+ close (fds[0]);
+ close (fds[3]);
+
+ stream = camel_stream_fs_new_with_fd (fds[1]);
+ if (camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (p->message), stream) == -1) {
+ camel_object_unref (stream);
+ close (fds[2]);
+ goto wait;
+ }
+
+ if (camel_stream_flush (stream) == -1) {
+ camel_object_unref (stream);
+ close (fds[2]);
+ goto wait;
+ }
+
+ camel_object_unref (stream);
+
+ stream = camel_stream_fs_new_with_fd (fds[2]);
+ mem = camel_stream_mem_new ();
+ if (camel_stream_write_to_stream (stream, mem) == -1) {
+ camel_object_unref (stream);
+ camel_object_unref (mem);
+ goto wait;
+ }
+
+ camel_object_unref (stream);
+ camel_stream_reset (mem);
+
+ parser = camel_mime_parser_new ();
+ camel_mime_parser_init_with_stream (parser, mem);
+ camel_mime_parser_scan_from (parser, FALSE);
+ camel_object_unref (mem);
+
+ message = camel_mime_message_new ();
+ if (camel_mime_part_construct_from_parser ((CamelMimePart *) message, parser) == -1) {
+ camel_exception_setv (p->ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Invalid message stream received from %s: %s"),
+ argv[0]->value.string,
+ g_strerror (camel_mime_parser_errno (parser)));
+ camel_object_unref (message);
+ message = NULL;
+ } else {
+ camel_object_unref (p->message);
+ p->message = message;
+ p->modified = TRUE;
+ }
+
+ camel_object_unref (parser);
+
+ wait:
+
+ 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);
+ }
+ }
+
+ if (message && result != -1 && WIFEXITED (status))
+ return WEXITSTATUS (status);
+ else
+ return -1;
+}
+
+static ESExpResult *
+pipe_message (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFilterDriver *driver)
+{
+ int i;
+
+ /* make sure all args are strings */
+ for (i = 0; i < argc; i++) {
+ if (argv[i]->type != ESEXP_RES_STRING)
+ return NULL;
+ }
+
+ camel_filter_driver_log (driver, FILTER_LOG_ACTION, "Piping message to %s", argv[0]->value.string);
+ pipe_to_system (f, argc, argv, driver);
+
+ return NULL;
+}
+
+static ESExpResult *
+do_shell (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFilterDriver *driver)
+{
+ struct _CamelFilterDriverPrivate *p = _PRIVATE (driver);
+ GString *command;
+ GPtrArray *args;
+ int i;
+
+ d(fprintf (stderr, "executing shell command\n"));
+
+ command = g_string_new ("");
+
+ args = g_ptr_array_new ();
+
+ /* make sure all args are strings */
+ for (i = 0; i < argc; i++) {
+ if (argv[i]->type != ESEXP_RES_STRING)
+ goto done;
+
+ g_ptr_array_add (args, argv[i]->value.string);
+
+ g_string_append (command, argv[i]->value.string);
+ g_string_append_c (command, ' ');
+ }
+
+ g_string_truncate (command, command->len - 1);
+
+ if (p->shellfunc && argc >= 1) {
+ p->shellfunc (driver, argc, (char **) args->pdata, p->shelldata);
+ camel_filter_driver_log (driver, FILTER_LOG_ACTION, "Executing shell command: [%s]",
+ command->str);
+ }
+
+ done:
+
+ g_ptr_array_free (args, TRUE);
+ g_string_free (command, TRUE);
+
+ return NULL;
+}
+
+static ESExpResult *
+do_beep (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFilterDriver *driver)
+{
+ struct _CamelFilterDriverPrivate *p = _PRIVATE (driver);
+
+ d(fprintf (stderr, "beep\n"));
+
+ if (p->beep) {
+ p->beep (driver, p->beepdata);
+ camel_filter_driver_log (driver, FILTER_LOG_ACTION, "Beep");
+ }
+
+ return NULL;
+}
+
+static ESExpResult *
+play_sound (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFilterDriver *driver)
+{
+ struct _CamelFilterDriverPrivate *p = _PRIVATE (driver);
+
+ d(fprintf (stderr, "play sound\n"));
+
+ if (p->playfunc && argc == 1 && argv[0]->type == ESEXP_RES_STRING) {
+ p->playfunc (driver, argv[0]->value.string, p->playdata);
+ camel_filter_driver_log (driver, FILTER_LOG_ACTION, "Play sound");
+ }
+
+ return NULL;
+}
+
+static ESExpResult *
+do_only_once (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFilterDriver *driver)
+{
+ struct _CamelFilterDriverPrivate *p = _PRIVATE (driver);
+
+ d(fprintf (stderr, "only once\n"));
+
+ if (argc == 2 && !g_hash_table_lookup (p->only_once, argv[0]->value.string))
+ g_hash_table_insert (p->only_once, g_strdup (argv[0]->value.string),
+ g_strdup (argv[1]->value.string));
+
+ return NULL;
+}
+
+static CamelFolder *
+open_folder (CamelFilterDriver *driver, const char *folder_url)
+{
+ struct _CamelFilterDriverPrivate *p = _PRIVATE (driver);
+ CamelFolder *camelfolder;
+
+ /* we have a lookup table of currently open folders */
+ camelfolder = g_hash_table_lookup (p->folders, folder_url);
+ if (camelfolder)
+ return camelfolder == FOLDER_INVALID?NULL:camelfolder;
+
+ /* if we have a default folder, ignore exceptions. This is so
+ a bad filter rule on pop or local delivery doesn't result
+ in duplicate mails, just mail going to inbox. Otherwise,
+ we want to know about exceptions and abort processing */
+ if (p->defaultfolder) {
+ CamelException ex;
+
+ camel_exception_init (&ex);
+ camelfolder = p->get_folder (driver, folder_url, p->data, &ex);
+ camel_exception_clear (&ex);
+ } else {
+ camelfolder = p->get_folder (driver, folder_url, p->data, p->ex);
+ }
+
+ if (camelfolder) {
+ g_hash_table_insert (p->folders, g_strdup (folder_url), camelfolder);
+ camel_folder_freeze (camelfolder);
+ } else {
+ g_hash_table_insert (p->folders, g_strdup (folder_url), FOLDER_INVALID);
+ }
+
+ return camelfolder;
+}
+
+static void
+close_folder (void *key, void *value, void *data)
+{
+ CamelFolder *folder = value;
+ CamelFilterDriver *driver = data;
+ struct _CamelFilterDriverPrivate *p = _PRIVATE (driver);
+
+ p->closed++;
+ g_free (key);
+
+ if (folder != FOLDER_INVALID) {
+ camel_folder_sync (folder, FALSE, camel_exception_is_set(p->ex)?NULL : p->ex);
+ camel_folder_thaw (folder);
+ camel_object_unref (folder);
+ }
+
+ report_status(driver, CAMEL_FILTER_STATUS_PROGRESS, g_hash_table_size(p->folders)* 100 / p->closed, _("Syncing folders"));
+}
+
+/* flush/close all folders */
+static int
+close_folders (CamelFilterDriver *driver)
+{
+ struct _CamelFilterDriverPrivate *p = _PRIVATE (driver);
+
+ report_status(driver, CAMEL_FILTER_STATUS_PROGRESS, 0, _("Syncing folders"));
+
+ p->closed = 0;
+ g_hash_table_foreach (p->folders, close_folder, driver);
+ g_hash_table_destroy (p->folders);
+ p->folders = g_hash_table_new (g_str_hash, g_str_equal);
+
+ /* FIXME: status from driver */
+ return 0;
+}
+
+#if 0
+static void
+free_key (gpointer key, gpointer value, gpointer user_data)
+{
+ g_free (key);
+}
+#endif
+
+
+static void
+camel_filter_driver_log (CamelFilterDriver *driver, enum filter_log_t status, const char *desc, ...)
+{
+ struct _CamelFilterDriverPrivate *p = _PRIVATE (driver);
+
+ if (p->logfile) {
+ char *str = NULL;
+
+ if (desc) {
+ va_list ap;
+
+ va_start (ap, desc);
+ str = g_strdup_vprintf (desc, ap);
+ }
+
+ switch (status) {
+ case FILTER_LOG_START: {
+ /* write log header */
+ const char *subject = NULL;
+ const char *from = NULL;
+ char date[50];
+ time_t t;
+
+ /* FIXME: does this need locking? Probably */
+
+ from = camel_message_info_from (p->info);
+ subject = camel_message_info_subject (p->info);
+
+ time (&t);
+ strftime (date, 49, "%a, %d %b %Y %H:%M:%S", localtime (&t));
+ fprintf (p->logfile, "Applied filter \"%s\" to message from %s - \"%s\" at %s\n",
+ str, from ? from : "unknown", subject ? subject : "", date);
+
+ break;
+ }
+ case FILTER_LOG_ACTION:
+ fprintf (p->logfile, "Action: %s\n", str);
+ break;
+ case FILTER_LOG_END:
+ fprintf (p->logfile, "\n");
+ break;
+ default:
+ /* nothing else is loggable */
+ break;
+ }
+
+ g_free (str);
+ }
+}
+
+
+struct _run_only_once {
+ CamelFilterDriver *driver;
+ CamelException *ex;
+};
+
+static gboolean
+run_only_once (gpointer key, char *action, struct _run_only_once *data)
+{
+ struct _CamelFilterDriverPrivate *p = _PRIVATE (data->driver);
+ CamelException *ex = data->ex;
+ ESExpResult *r;
+
+ d(printf ("evaluating: %s\n\n", action));
+
+ e_sexp_input_text (p->eval, action, strlen (action));
+ if (e_sexp_parse (p->eval) == -1) {
+ if (!camel_exception_is_set (ex))
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Error parsing filter: %s: %s"),
+ e_sexp_error (p->eval), action);
+ goto done;
+ }
+
+ r = e_sexp_eval (p->eval);
+ if (r == NULL) {
+ if (!camel_exception_is_set (ex))
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Error executing filter: %s: %s"),
+ e_sexp_error (p->eval), action);
+ goto done;
+ }
+
+ e_sexp_result_free (p->eval, r);
+
+ done:
+
+ g_free (key);
+ g_free (action);
+
+ return TRUE;
+}
+
+
+/**
+ * camel_filter_driver_flush:
+ * @driver:
+ * @ex:
+ *
+ * Flush all of the only-once filter actions.
+ **/
+void
+camel_filter_driver_flush (CamelFilterDriver *driver, CamelException *ex)
+{
+ struct _CamelFilterDriverPrivate *p = _PRIVATE (driver);
+ struct _run_only_once data;
+
+ if (!p->only_once)
+ return;
+
+ data.driver = driver;
+ data.ex = ex;
+
+ g_hash_table_foreach_remove (p->only_once, (GHRFunc) run_only_once, &data);
+}
+
+/**
+ * camel_filter_driver_filter_mbox:
+ * @driver: CamelFilterDriver
+ * @mbox: mbox filename to be filtered
+ * @ex: exception
+ *
+ * Filters an mbox file based on rules defined in the FilterDriver
+ * object. Is more efficient as it doesn't need to open the folder
+ * through Camel directly.
+ *
+ * Returns -1 if errors were encountered during filtering,
+ * otherwise returns 0.
+ *
+ **/
+int
+camel_filter_driver_filter_mbox (CamelFilterDriver *driver, const char *mbox, const char *original_source_url, CamelException *ex)
+{
+ struct _CamelFilterDriverPrivate *p = _PRIVATE (driver);
+ CamelMimeParser *mp = NULL;
+ char *source_url = NULL;
+ int fd = -1;
+ int i = 0;
+ struct stat st;
+ int status;
+ off_t last = 0;
+ int ret = -1;
+
+ fd = open (mbox, O_RDONLY);
+ if (fd == -1) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Unable to open spool folder"));
+ goto fail;
+ }
+ /* to get the filesize */
+ fstat (fd, &st);
+
+ mp = camel_mime_parser_new ();
+ camel_mime_parser_scan_from (mp, TRUE);
+ if (camel_mime_parser_init_with_fd (mp, fd) == -1) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Unable to process spool folder"));
+ goto fail;
+ }
+ fd = -1;
+
+ source_url = g_strdup_printf ("file://%s", mbox);
+
+ while (camel_mime_parser_step (mp, 0, 0) == CAMEL_MIME_PARSER_STATE_FROM) {
+ CamelMessageInfo *info;
+ CamelMimeMessage *msg;
+ int pc = 0;
+
+ if (st.st_size > 0)
+ pc = (int)(100.0 * ((double)camel_mime_parser_tell (mp) / (double)st.st_size));
+
+ report_status (driver, CAMEL_FILTER_STATUS_START, pc, _("Getting message %d (%d%%)"), i, pc);
+
+ msg = camel_mime_message_new ();
+ if (camel_mime_part_construct_from_parser (CAMEL_MIME_PART (msg), mp) == -1) {
+ camel_exception_set (ex, (errno==EINTR)?CAMEL_EXCEPTION_USER_CANCEL:CAMEL_EXCEPTION_SYSTEM, _("Cannot open message"));
+ report_status (driver, CAMEL_FILTER_STATUS_END, 100, _("Failed on message %d"), i);
+ camel_object_unref (msg);
+ goto fail;
+ }
+
+ info = camel_message_info_new_from_header(((CamelMimePart *)msg)->headers);
+ info->size = camel_mime_parser_tell(mp) - last;
+ last = camel_mime_parser_tell(mp);
+ status = camel_filter_driver_filter_message (driver, msg, info, NULL, NULL, source_url,
+ original_source_url ? original_source_url : source_url, ex);
+ camel_object_unref (msg);
+ if (camel_exception_is_set (ex) || status == -1) {
+ report_status (driver, CAMEL_FILTER_STATUS_END, 100, _("Failed on message %d"), i);
+ camel_message_info_free (info);
+ goto fail;
+ }
+
+ i++;
+
+ /* skip over the FROM_END state */
+ camel_mime_parser_step (mp, 0, 0);
+
+ camel_message_info_free (info);
+ }
+
+ if (p->defaultfolder) {
+ report_status(driver, CAMEL_FILTER_STATUS_PROGRESS, 100, _("Syncing folder"));
+ camel_folder_sync(p->defaultfolder, FALSE, camel_exception_is_set (ex) ? NULL : ex);
+ }
+
+ report_status (driver, CAMEL_FILTER_STATUS_END, 100, _("Complete"));
+
+ ret = 0;
+fail:
+ g_free (source_url);
+ if (fd != -1)
+ close (fd);
+ if (mp)
+ camel_object_unref (mp);
+
+ return -1;
+}
+
+
+/**
+ * camel_filter_driver_filter_folder:
+ * @driver: CamelFilterDriver
+ * @folder: CamelFolder to be filtered
+ * @cache: UID cache (needed for POP folders)
+ * @uids: message uids to be filtered or NULL (as a shortcut to filter all messages)
+ * @remove: TRUE to mark filtered messages as deleted
+ * @ex: exception
+ *
+ * Filters a folder based on rules defined in the FilterDriver
+ * object.
+ *
+ * Returns -1 if errors were encountered during filtering,
+ * otherwise returns 0.
+ *
+ **/
+int
+camel_filter_driver_filter_folder (CamelFilterDriver *driver, CamelFolder *folder, CamelUIDCache *cache,
+ GPtrArray *uids, gboolean remove, CamelException *ex)
+{
+ struct _CamelFilterDriverPrivate *p = _PRIVATE (driver);
+ gboolean freeuids = FALSE;
+ CamelMessageInfo *info;
+ char *source_url, *service_url;
+ int status = 0;
+ CamelURL *url;
+ int i;
+
+ service_url = camel_service_get_url (CAMEL_SERVICE (camel_folder_get_parent_store (folder)));
+ url = camel_url_new (service_url, NULL);
+ g_free (service_url);
+
+ source_url = camel_url_to_string (url, CAMEL_URL_HIDE_ALL);
+ camel_url_free (url);
+
+ if (uids == NULL) {
+ uids = camel_folder_get_uids (folder);
+ freeuids = TRUE;
+ }
+
+ for (i = 0; i < uids->len; i++) {
+ int pc = (100 * i)/uids->len;
+
+ report_status (driver, CAMEL_FILTER_STATUS_START, pc, _("Getting message %d of %d"), i+1,
+ uids->len);
+
+ if (camel_folder_has_summary_capability (folder))
+ info = camel_folder_get_message_info (folder, uids->pdata[i]);
+ else
+ info = NULL;
+
+ status = camel_filter_driver_filter_message (driver, NULL, info, uids->pdata[i],
+ folder, source_url, source_url, ex);
+
+ if (camel_folder_has_summary_capability (folder))
+ camel_folder_free_message_info (folder, info);
+
+ if (camel_exception_is_set (ex) || status == -1) {
+ report_status (driver, CAMEL_FILTER_STATUS_END, 100, _("Failed at message %d of %d"),
+ i+1, uids->len);
+ status = -1;
+ break;
+ }
+
+ if (remove)
+ camel_folder_set_message_flags (folder, uids->pdata[i],
+ CAMEL_MESSAGE_DELETED | CAMEL_MESSAGE_SEEN, ~0);
+
+ if (cache)
+ camel_uid_cache_save_uid (cache, uids->pdata[i]);
+ }
+
+ if (p->defaultfolder) {
+ report_status (driver, CAMEL_FILTER_STATUS_PROGRESS, 100, _("Syncing folder"));
+ camel_folder_sync (p->defaultfolder, FALSE, camel_exception_is_set (ex) ? NULL : ex);
+ }
+
+ if (i == uids->len)
+ report_status (driver, CAMEL_FILTER_STATUS_END, 100, _("Complete"));
+
+ if (freeuids)
+ camel_folder_free_uids (folder, uids);
+
+ g_free (source_url);
+
+ return status;
+}
+
+
+struct _get_message {
+ struct _CamelFilterDriverPrivate *p;
+ const char *source_url;
+};
+
+
+static CamelMimeMessage *
+get_message_cb (void *data, CamelException *ex)
+{
+ struct _get_message *msgdata = data;
+ struct _CamelFilterDriverPrivate *p = msgdata->p;
+ const char *source_url = msgdata->source_url;
+ CamelMimeMessage *message;
+
+ if (p->message) {
+ message = p->message;
+ camel_object_ref (message);
+ } else {
+ const char *uid;
+
+ if (p->uid)
+ uid = p->uid;
+ else
+ uid = camel_message_info_uid (p->info);
+
+ message = camel_folder_get_message (p->source, uid, ex);
+ }
+
+ if (source_url && message && camel_mime_message_get_source (message) == NULL)
+ camel_mime_message_set_source (message, source_url);
+
+ return message;
+}
+
+/**
+ * camel_filter_driver_filter_message:
+ * @driver: CamelFilterDriver
+ * @message: message to filter or NULL
+ * @info: message info or NULL
+ * @uid: message uid or NULL
+ * @source: source folder or NULL
+ * @source_url: url of source folder or NULL
+ * @original_source_url: url of original source folder (pre-movemail) or NULL
+ * @ex: exception
+ *
+ * Filters a message based on rules defined in the FilterDriver
+ * object. If the source folder (@source) and the uid (@uid) are
+ * provided, the filter will operate on the CamelFolder (which in
+ * certain cases is more efficient than using the default
+ * camel_folder_append_message() function).
+ *
+ * Returns -1 if errors were encountered during filtering,
+ * otherwise returns 0.
+ *
+ **/
+int
+camel_filter_driver_filter_message (CamelFilterDriver *driver, CamelMimeMessage *message,
+ CamelMessageInfo *info, const char *uid,
+ CamelFolder *source, const char *source_url,
+ const char *original_source_url,
+ CamelException *ex)
+{
+ struct _CamelFilterDriverPrivate *p = _PRIVATE (driver);
+ struct _filter_rule *node;
+ gboolean freeinfo = FALSE;
+ gboolean filtered = FALSE;
+ ESExpResult *r;
+ int result;
+
+ /* FIXME: make me into a g_return_if_fail/g_assert or whatever... */
+ if (message == NULL && (source == NULL || uid == NULL)) {
+ g_warning ("there is no way to fetch the message using the information provided...");
+ return -1;
+ }
+
+ if (info == NULL) {
+ struct _camel_header_raw *h;
+
+ if (message) {
+ camel_object_ref (message);
+ } else {
+ message = camel_folder_get_message (source, uid, ex);
+ if (!message)
+ return -1;
+ }
+
+ h = CAMEL_MIME_PART (message)->headers;
+ info = camel_message_info_new_from_header (h);
+ freeinfo = TRUE;
+ } else {
+ if (info->flags & CAMEL_MESSAGE_DELETED)
+ return 0;
+
+ uid = camel_message_info_uid (info);
+
+ if (message)
+ camel_object_ref (message);
+ }
+
+ p->ex = ex;
+ p->terminated = FALSE;
+ p->deleted = FALSE;
+ p->copied = FALSE;
+ p->message = message;
+ p->info = info;
+ p->uid = uid;
+ p->source = source;
+
+ if (message && original_source_url && camel_mime_message_get_source (message) == NULL)
+ camel_mime_message_set_source (message, original_source_url);
+
+ node = (struct _filter_rule *) p->rules.head;
+ result = CAMEL_SEARCH_NOMATCH;
+ while (node->next && !p->terminated) {
+ struct _get_message data;
+
+ d(printf("applying rule %s\naction %s\n", node->match, node->action));
+
+ data.p = p;
+ data.source_url = original_source_url;
+
+ result = camel_filter_search_match (p->session, get_message_cb, &data, p->info,
+ original_source_url ? original_source_url : source_url,
+ node->match, p->ex);
+
+ switch (result) {
+ case CAMEL_SEARCH_ERROR:
+ goto error;
+ case CAMEL_SEARCH_MATCHED:
+ filtered = TRUE;
+ camel_filter_driver_log (driver, FILTER_LOG_START, node->name);
+
+ if (camel_debug(":filter"))
+ printf("filtering '%s' applying rule %s\n",
+ camel_message_info_subject(info)?camel_message_info_subject(info):"?no subject?", node->name);
+
+ /* perform necessary filtering actions */
+ e_sexp_input_text (p->eval, node->action, strlen (node->action));
+ if (e_sexp_parse (p->eval) == -1) {
+ camel_exception_setv (ex, 1, _("Error parsing filter: %s: %s"),
+ e_sexp_error (p->eval), node->action);
+ goto error;
+ }
+ r = e_sexp_eval (p->eval);
+ if (camel_exception_is_set(p->ex))
+ goto error;
+
+ if (r == NULL) {
+ camel_exception_setv (ex, 1, _("Error executing filter: %s: %s"),
+ e_sexp_error (p->eval), node->action);
+ goto error;
+ }
+ e_sexp_result_free (p->eval, r);
+ default:
+ break;
+ }
+
+ node = node->next;
+ }
+
+ /* *Now* we can set the DELETED flag... */
+ if (p->deleted) {
+ if (p->source && p->uid && camel_folder_has_summary_capability (p->source))
+ camel_folder_set_message_flags(p->source, p->uid, CAMEL_MESSAGE_DELETED|CAMEL_MESSAGE_SEEN, ~0);
+ else
+ info->flags |= CAMEL_MESSAGE_DELETED|CAMEL_MESSAGE_SEEN|CAMEL_MESSAGE_FOLDER_FLAGGED;
+ }
+
+ /* Logic: if !Moved and there exists a default folder... */
+ if (!(p->copied && p->deleted) && p->defaultfolder) {
+ /* copy it to the default inbox */
+ filtered = TRUE;
+ camel_filter_driver_log (driver, FILTER_LOG_ACTION, "Copy to default folder");
+
+ if (camel_debug(":filter"))
+ printf("filtering '%s' copy %s to default folder\n",
+ camel_message_info_subject(info)?camel_message_info_subject(info):"?no subject?",
+ p->modified?"modified message":"");
+
+ if (!p->modified && p->uid && p->source && camel_folder_has_summary_capability (p->source)) {
+ GPtrArray *uids;
+
+ uids = g_ptr_array_new ();
+ g_ptr_array_add (uids, (char *) p->uid);
+ camel_folder_transfer_messages_to (p->source, uids, p->defaultfolder, NULL, FALSE, p->ex);
+ g_ptr_array_free (uids, TRUE);
+ } else {
+ if (p->message == NULL) {
+ p->message = camel_folder_get_message (source, uid, ex);
+ if (!p->message)
+ goto error;
+ }
+
+ camel_folder_append_message (p->defaultfolder, p->message, p->info, NULL, p->ex);
+ }
+ }
+
+ if (p->message)
+ camel_object_unref (p->message);
+
+ if (freeinfo)
+ camel_message_info_free (info);
+
+ return 0;
+
+ error:
+ if (filtered)
+ camel_filter_driver_log (driver, FILTER_LOG_END, NULL);
+
+ if (p->message)
+ camel_object_unref (p->message);
+
+ if (freeinfo)
+ camel_message_info_free (info);
+
+ return -1;
+}
diff --git a/camel/camel-filter-search.c b/camel/camel-filter-search.c
new file mode 100644
index 0000000000..9999b0ad2c
--- /dev/null
+++ b/camel/camel-filter-search.c
@@ -0,0 +1,704 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Jeffrey Stedfast <fejj@ximian.com>
+ * Michael Zucchi <NotZed@Ximian.com>
+ *
+ * Copyright 2000 Ximian, Inc. (www.ximian.com)
+ * Copyright 2001 Ximian Inc. (www.ximian.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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* (from glibc headers:
+ POSIX says that <sys/types.h> must be included (by the caller) before <regex.h>. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <regex.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <signal.h>
+#include <sys/wait.h>
+
+#include <e-util/e-sexp.h>
+
+#include <gal/util/e-iconv.h>
+
+#include "camel-mime-message.h"
+#include "camel-provider.h"
+#include "camel-session.h"
+#include "camel-filter-search.h"
+#include "camel-exception.h"
+#include "camel-multipart.h"
+#include "camel-stream-mem.h"
+#include "camel-stream-fs.h"
+#include "camel-search-private.h"
+
+#include "camel-url.h"
+
+#define d(x)
+
+typedef struct {
+ CamelSession *session;
+ CamelFilterSearchGetMessageFunc get_message;
+ void *get_message_data;
+ CamelMimeMessage *message;
+ CamelMessageInfo *info;
+ const char *source;
+ CamelException *ex;
+} FilterMessageSearch;
+
+/* ESExp callbacks */
+static ESExpResult *header_contains (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms);
+static ESExpResult *header_matches (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms);
+static ESExpResult *header_starts_with (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms);
+static ESExpResult *header_ends_with (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms);
+static ESExpResult *header_exists (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms);
+static ESExpResult *header_soundex (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms);
+static ESExpResult *header_regex (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms);
+static ESExpResult *header_full_regex (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms);
+static ESExpResult *match_all (struct _ESExp *f, int argc, struct _ESExpTerm **argv, FilterMessageSearch *fms);
+static ESExpResult *body_contains (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms);
+static ESExpResult *body_regex (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms);
+static ESExpResult *user_flag (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms);
+static ESExpResult *user_tag (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms);
+static ESExpResult *system_flag (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms);
+static ESExpResult *get_sent_date (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms);
+static ESExpResult *get_received_date (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms);
+static ESExpResult *get_current_date (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms);
+static ESExpResult *header_source (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms);
+static ESExpResult *get_size (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms);
+static ESExpResult *pipe_message (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms);
+static ESExpResult *junk_test (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms);
+
+/* builtin functions */
+static struct {
+ char *name;
+ ESExpFunc *func;
+ int type; /* set to 1 if a function can perform shortcut evaluation, or
+ doesn't execute everything, 0 otherwise */
+} symbols[] = {
+ { "match-all", (ESExpFunc *) match_all, 1 },
+ { "body-contains", (ESExpFunc *) body_contains, 0 },
+ { "body-regex", (ESExpFunc *) body_regex, 0 },
+ { "header-contains", (ESExpFunc *) header_contains, 0 },
+ { "header-matches", (ESExpFunc *) header_matches, 0 },
+ { "header-starts-with", (ESExpFunc *) header_starts_with, 0 },
+ { "header-ends-with", (ESExpFunc *) header_ends_with, 0 },
+ { "header-exists", (ESExpFunc *) header_exists, 0 },
+ { "header-soundex", (ESExpFunc *) header_soundex, 0 },
+ { "header-regex", (ESExpFunc *) header_regex, 0 },
+ { "header-full-regex", (ESExpFunc *) header_full_regex, 0 },
+ { "user-tag", (ESExpFunc *) user_tag, 0 },
+ { "user-flag", (ESExpFunc *) user_flag, 0 },
+ { "system-flag", (ESExpFunc *) system_flag, 0 },
+ { "get-sent-date", (ESExpFunc *) get_sent_date, 0 },
+ { "get-received-date", (ESExpFunc *) get_received_date, 0 },
+ { "get-current-date", (ESExpFunc *) get_current_date, 0 },
+ { "header-source", (ESExpFunc *) header_source, 0 },
+ { "get-size", (ESExpFunc *) get_size, 0 },
+ { "pipe-message", (ESExpFunc *) pipe_message, 0 },
+ { "junk-test", (ESExpFunc *) junk_test, 0 },
+};
+
+
+static CamelMimeMessage *
+camel_filter_search_get_message (FilterMessageSearch *fms, struct _ESExp *sexp)
+{
+ if (fms->message)
+ return fms->message;
+
+ fms->message = fms->get_message (fms->get_message_data, fms->ex);
+
+ if (fms->message == NULL)
+ e_sexp_fatal_error (sexp, _("Failed to retrieve message"));
+
+ return fms->message;
+}
+
+static ESExpResult *
+check_header (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms, camel_search_match_t how)
+{
+ gboolean matched = FALSE;
+ ESExpResult *r;
+ int i;
+
+ if (argc > 1 && argv[0]->type == ESEXP_RES_STRING) {
+ char *name = argv[0]->value.string;
+ const char *header;
+ camel_search_t type = CAMEL_SEARCH_TYPE_ENCODED;
+ CamelContentType *ct;
+ const char *charset = NULL;
+
+ if (g_ascii_strcasecmp(name, "x-camel-mlist") == 0) {
+ header = camel_message_info_mlist(fms->info);
+ type = CAMEL_SEARCH_TYPE_MLIST;
+ } else {
+ CamelMimeMessage *message = camel_filter_search_get_message (fms, f);
+
+ header = camel_medium_get_header (CAMEL_MEDIUM (message), argv[0]->value.string);
+ /* FIXME: what about Resent-To, Resent-Cc and Resent-From? */
+ if (g_ascii_strcasecmp("to", name) == 0 || g_ascii_strcasecmp("cc", name) == 0 || g_ascii_strcasecmp("from", name) == 0)
+ type = CAMEL_SEARCH_TYPE_ADDRESS_ENCODED;
+ else {
+ ct = camel_mime_part_get_content_type (CAMEL_MIME_PART (message));
+ if (ct) {
+ charset = camel_content_type_param (ct, "charset");
+ charset = e_iconv_charset_name (charset);
+ }
+ }
+ }
+
+ if (header) {
+ for (i=1; i<argc && !matched; i++) {
+ if (argv[i]->type == ESEXP_RES_STRING)
+ matched = camel_search_header_match(header, argv[i]->value.string, how, type, charset);
+ }
+ }
+ }
+
+ r = e_sexp_result_new (f, ESEXP_RES_BOOL);
+ r->value.bool = matched;
+
+ return r;
+}
+
+static ESExpResult *
+header_contains (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms)
+{
+ return check_header (f, argc, argv, fms, CAMEL_SEARCH_MATCH_CONTAINS);
+}
+
+
+static ESExpResult *
+header_matches (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms)
+{
+ return check_header (f, argc, argv, fms, CAMEL_SEARCH_MATCH_EXACT);
+}
+
+static ESExpResult *
+header_starts_with (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms)
+{
+ return check_header (f, argc, argv, fms, CAMEL_SEARCH_MATCH_STARTS);
+}
+
+static ESExpResult *
+header_ends_with (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms)
+{
+ return check_header (f, argc, argv, fms, CAMEL_SEARCH_MATCH_ENDS);
+}
+
+static ESExpResult *
+header_soundex (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms)
+{
+ return check_header (f, argc, argv, fms, CAMEL_SEARCH_MATCH_SOUNDEX);
+}
+
+static ESExpResult *
+header_exists (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms)
+{
+ CamelMimeMessage *message;
+ gboolean matched = FALSE;
+ ESExpResult *r;
+ int i;
+
+ message = camel_filter_search_get_message (fms, f);
+
+ for (i = 0; i < argc && !matched; i++) {
+ if (argv[i]->type == ESEXP_RES_STRING)
+ matched = camel_medium_get_header (CAMEL_MEDIUM (message), argv[i]->value.string) != NULL;
+ }
+
+ r = e_sexp_result_new (f, ESEXP_RES_BOOL);
+ r->value.bool = matched;
+
+ return r;
+}
+
+static ESExpResult *
+header_regex (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms)
+{
+ ESExpResult *r = e_sexp_result_new (f, ESEXP_RES_BOOL);
+ CamelMimeMessage *message;
+ regex_t pattern;
+ const char *contents;
+
+ message = camel_filter_search_get_message (fms, f);
+
+ if (argc > 1 && argv[0]->type == ESEXP_RES_STRING
+ && (contents = camel_medium_get_header (CAMEL_MEDIUM (message), argv[0]->value.string))
+ && camel_search_build_match_regex(&pattern, CAMEL_SEARCH_MATCH_REGEX|CAMEL_SEARCH_MATCH_ICASE, argc-1, argv+1, fms->ex) == 0) {
+ r->value.bool = regexec (&pattern, contents, 0, NULL, 0) == 0;
+ regfree (&pattern);
+ } else
+ r->value.bool = FALSE;
+
+ return r;
+}
+
+static gchar *
+get_full_header (CamelMimeMessage *message)
+{
+ CamelMimePart *mp = CAMEL_MIME_PART (message);
+ GString *str = g_string_new ("");
+ char *ret;
+ struct _camel_header_raw *h;
+
+ for (h = mp->headers; h; h = h->next) {
+ if (h->value != NULL) {
+ g_string_append (str, h->name);
+ if (isspace (h->value[0]))
+ g_string_append (str, ":");
+ else
+ g_string_append (str, ": ");
+ g_string_append (str, h->value);
+ g_string_append_c(str, '\n');
+ }
+ }
+
+ ret = str->str;
+ g_string_free (str, FALSE);
+
+ return ret;
+}
+
+static ESExpResult *
+header_full_regex (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms)
+{
+ ESExpResult *r = e_sexp_result_new (f, ESEXP_RES_BOOL);
+ CamelMimeMessage *message;
+ regex_t pattern;
+ char *contents;
+
+ if (camel_search_build_match_regex(&pattern, CAMEL_SEARCH_MATCH_REGEX|CAMEL_SEARCH_MATCH_ICASE|CAMEL_SEARCH_MATCH_NEWLINE,
+ argc, argv, fms->ex) == 0) {
+ message = camel_filter_search_get_message (fms, f);
+ contents = get_full_header (message);
+ r->value.bool = regexec (&pattern, contents, 0, NULL, 0) == 0;
+ g_free (contents);
+ regfree (&pattern);
+ } else
+ r->value.bool = FALSE;
+
+ return r;
+}
+
+static ESExpResult *
+match_all (struct _ESExp *f, int argc, struct _ESExpTerm **argv, FilterMessageSearch *fms)
+{
+ /* match-all: when dealing with single messages is a no-op */
+ ESExpResult *r;
+
+ if (argc > 0)
+ return e_sexp_term_eval (f, argv[0]);
+
+ r = e_sexp_result_new (f, ESEXP_RES_BOOL);
+ r->value.bool = TRUE;
+
+ return r;
+}
+
+static ESExpResult *
+body_contains (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms)
+{
+ ESExpResult *r = e_sexp_result_new (f, ESEXP_RES_BOOL);
+ CamelMimeMessage *message;
+ regex_t pattern;
+
+ if (camel_search_build_match_regex (&pattern, CAMEL_SEARCH_MATCH_ICASE, argc, argv, fms->ex) == 0) {
+ message = camel_filter_search_get_message (fms, f);
+ r->value.bool = camel_search_message_body_contains ((CamelDataWrapper *) message, &pattern);
+ regfree (&pattern);
+ } else
+ r->value.bool = FALSE;
+
+ return r;
+}
+
+static ESExpResult *
+body_regex (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms)
+{
+ ESExpResult *r = e_sexp_result_new(f, ESEXP_RES_BOOL);
+ CamelMimeMessage *message;
+ regex_t pattern;
+
+ if (camel_search_build_match_regex(&pattern, CAMEL_SEARCH_MATCH_ICASE|CAMEL_SEARCH_MATCH_REGEX|CAMEL_SEARCH_MATCH_NEWLINE,
+ argc, argv, fms->ex) == 0) {
+ message = camel_filter_search_get_message (fms, f);
+ r->value.bool = camel_search_message_body_contains ((CamelDataWrapper *) message, &pattern);
+ regfree (&pattern);
+ } else
+ r->value.bool = FALSE;
+
+ return r;
+}
+
+static ESExpResult *
+user_flag (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms)
+{
+ ESExpResult *r;
+ gboolean truth = FALSE;
+ int i;
+
+ /* performs an OR of all words */
+ for (i = 0; i < argc && !truth; i++) {
+ if (argv[i]->type == ESEXP_RES_STRING
+ && camel_flag_get (&fms->info->user_flags, argv[i]->value.string)) {
+ truth = TRUE;
+ break;
+ }
+ }
+
+ r = e_sexp_result_new (f, ESEXP_RES_BOOL);
+ r->value.bool = truth;
+
+ return r;
+}
+
+static ESExpResult *
+system_flag (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms)
+{
+ ESExpResult *r;
+
+ if (argc != 1 || argv[0]->type != ESEXP_RES_STRING)
+ e_sexp_fatal_error(f, _("Invalid arguments to (system-flag)"));
+
+ r = e_sexp_result_new (f, ESEXP_RES_BOOL);
+ r->value.bool = camel_system_flag_get (fms->info->flags, argv[0]->value.string);
+
+ return r;
+}
+
+static ESExpResult *
+user_tag (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms)
+{
+ ESExpResult *r;
+ const char *tag;
+
+ if (argc != 1 || argv[0]->type != ESEXP_RES_STRING)
+ e_sexp_fatal_error(f, _("Invalid arguments to (user-tag)"));
+
+ tag = camel_tag_get (&fms->info->user_tags, argv[0]->value.string);
+
+ r = e_sexp_result_new (f, ESEXP_RES_STRING);
+ r->value.string = g_strdup (tag ? tag : "");
+
+ return r;
+}
+
+static ESExpResult *
+get_sent_date (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms)
+{
+ CamelMimeMessage *message;
+ ESExpResult *r;
+
+ message = camel_filter_search_get_message (fms, f);
+ r = e_sexp_result_new (f, ESEXP_RES_INT);
+ r->value.number = camel_mime_message_get_date (message, NULL);
+
+ return r;
+}
+
+static ESExpResult *
+get_received_date (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms)
+{
+ CamelMimeMessage *message;
+ ESExpResult *r;
+
+ message = camel_filter_search_get_message (fms, f);
+ r = e_sexp_result_new (f, ESEXP_RES_INT);
+ r->value.number = camel_mime_message_get_date_received (message, NULL);
+
+ return r;
+}
+
+static ESExpResult *
+get_current_date (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms)
+{
+ ESExpResult *r;
+
+ r = e_sexp_result_new (f, ESEXP_RES_INT);
+ r->value.number = time (NULL);
+
+ return r;
+}
+
+static ESExpResult *
+header_source (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms)
+{
+ CamelMimeMessage *message;
+ ESExpResult *r;
+ const char *src;
+ int truth = FALSE, i;
+ CamelProvider *provider;
+ CamelURL *uria, *urib;
+
+ if (fms->source) {
+ src = fms->source;
+ } else {
+ message = camel_filter_search_get_message(fms, f);
+ src = camel_mime_message_get_source(message);
+ }
+
+ if (src
+ && (provider = camel_provider_get(src, NULL))
+ && provider->url_equal) {
+ uria = camel_url_new(src, NULL);
+ if (uria) {
+ for (i=0;i<argc && !truth;i++) {
+ if (argv[i]->type == ESEXP_RES_STRING
+ && (urib = camel_url_new(argv[i]->value.string, NULL))) {
+ truth = provider->url_equal(uria, urib);
+ camel_url_free(urib);
+ }
+ }
+ camel_url_free(uria);
+ }
+ }
+
+ r = e_sexp_result_new(f, ESEXP_RES_BOOL);
+ r->value.bool = truth;
+
+ return r;
+}
+
+/* remember, the size comparisons are done at Kbytes */
+static ESExpResult *
+get_size (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms)
+{
+ ESExpResult *r;
+
+ r = e_sexp_result_new(f, ESEXP_RES_INT);
+ r->value.number = fms->info->size / 1024;
+
+ return r;
+}
+
+static int
+run_command (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms)
+{
+ CamelMimeMessage *message;
+ CamelStream *stream;
+ int result, status;
+ int in_fds[2];
+ pid_t pid;
+
+ if (argc < 1 || argv[0]->value.string[0] == '\0')
+ return 0;
+
+ if (pipe (in_fds) == -1) {
+ camel_exception_setv (fms->ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Failed to create pipe to '%s': %s"),
+ argv[0]->value.string, g_strerror (errno));
+ return -1;
+ }
+
+ if (!(pid = fork ())) {
+ /* child process */
+ GPtrArray *args;
+ int maxfd, fd, i;
+
+ fd = open ("/dev/null", O_WRONLY);
+
+ if (dup2 (in_fds[0], STDIN_FILENO) < 0 ||
+ dup2 (fd, STDOUT_FILENO) < 0 ||
+ dup2 (fd, STDERR_FILENO) < 0)
+ _exit (255);
+
+ setsid ();
+
+ maxfd = sysconf (_SC_OPEN_MAX);
+ for (fd = 3; fd < maxfd; fd++)
+ fcntl (fd, F_SETFD, FD_CLOEXEC);
+
+ args = g_ptr_array_new ();
+ for (i = 0; i < argc; i++)
+ g_ptr_array_add (args, argv[i]->value.string);
+ g_ptr_array_add (args, NULL);
+
+ execvp (argv[0]->value.string, (char **) args->pdata);
+
+ g_ptr_array_free (args, TRUE);
+
+ d(printf ("Could not execute %s: %s\n", argv[0]->value.string, g_strerror (errno)));
+ _exit (255);
+ } else if (pid < 0) {
+ camel_exception_setv (fms->ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Failed to create create child process '%s': %s"),
+ argv[0]->value.string, g_strerror (errno));
+ return -1;
+ }
+
+ /* parent process */
+ close (in_fds[0]);
+
+ message = camel_filter_search_get_message (fms, f);
+
+ stream = camel_stream_fs_new_with_fd (in_fds[1]);
+ camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (message), stream);
+ camel_stream_flush (stream);
+ camel_object_unref (stream);
+
+ 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);
+ }
+ }
+
+ if (result != -1 && WIFEXITED (status))
+ return WEXITSTATUS (status);
+ else
+ return -1;
+}
+
+static ESExpResult *
+pipe_message (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms)
+{
+ ESExpResult *r;
+ int retval, i;
+
+ /* make sure all args are strings */
+ for (i = 0; i < argc; i++) {
+ if (argv[i]->type != ESEXP_RES_STRING) {
+ retval = -1;
+ goto done;
+ }
+ }
+
+ retval = run_command (f, argc, argv, fms);
+
+ done:
+ r = e_sexp_result_new (f, ESEXP_RES_INT);
+ r->value.number = retval;
+
+ return r;
+}
+
+static ESExpResult *
+junk_test (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms)
+{
+ ESExpResult *r;
+ gboolean retval = FALSE;
+
+ if (fms->session->junk_plugin != NULL) {
+ retval = camel_junk_plugin_check_junk (fms->session->junk_plugin, camel_filter_search_get_message (fms, f));
+
+ printf("junk filter => %s\n", retval ? "*JUNK*" : "clean");
+ }
+
+ r = e_sexp_result_new (f, ESEXP_RES_BOOL);
+ r->value.number = retval;
+
+ return r;
+}
+
+/**
+ * camel_filter_search_match:
+ * @session:
+ * @get_message: function to retrieve the message if necessary
+ * @data: data for above
+ * @info:
+ * @source:
+ * @expression:
+ * @ex:
+ *
+ * Returns one of CAMEL_SEARCH_MATCHED, CAMEL_SEARCH_NOMATCH, or CAMEL_SEARCH_ERROR.
+ **/
+int
+camel_filter_search_match (CamelSession *session,
+ CamelFilterSearchGetMessageFunc get_message, void *data,
+ CamelMessageInfo *info, const char *source,
+ const char *expression, CamelException *ex)
+{
+ FilterMessageSearch fms;
+ ESExp *sexp;
+ ESExpResult *result;
+ gboolean retval;
+ int i;
+
+ fms.session = session;
+ fms.get_message = get_message;
+ fms.get_message_data = data;
+ fms.message = NULL;
+ fms.info = info;
+ fms.source = source;
+ fms.ex = ex;
+
+ sexp = e_sexp_new ();
+
+ for (i = 0; i < sizeof (symbols) / sizeof (symbols[0]); i++) {
+ if (symbols[i].type == 1)
+ e_sexp_add_ifunction (sexp, 0, symbols[i].name, (ESExpIFunc *)symbols[i].func, &fms);
+ else
+ e_sexp_add_function (sexp, 0, symbols[i].name, symbols[i].func, &fms);
+ }
+
+ e_sexp_input_text (sexp, expression, strlen (expression));
+ if (e_sexp_parse (sexp) == -1) {
+ if (!camel_exception_is_set (ex))
+ /* A filter search is a search through your filters, ie. your filters is the corpus being searched thru. */
+ camel_exception_setv (ex, 1, _("Error executing filter search: %s: %s"),
+ e_sexp_error (sexp), expression);
+ goto error;
+ }
+
+ result = e_sexp_eval (sexp);
+ if (result == NULL) {
+ if (!camel_exception_is_set (ex))
+ camel_exception_setv (ex, 1, _("Error executing filter search: %s: %s"),
+ e_sexp_error (sexp), expression);
+ goto error;
+ }
+
+ if (result->type == ESEXP_RES_BOOL)
+ retval = result->value.bool ? CAMEL_SEARCH_MATCHED : CAMEL_SEARCH_NOMATCH;
+ else
+ retval = CAMEL_SEARCH_NOMATCH;
+
+ e_sexp_result_free (sexp, result);
+ e_sexp_unref (sexp);
+
+ if (fms.message)
+ camel_object_unref (fms.message);
+
+ return retval;
+
+ error:
+ if (fms.message)
+ camel_object_unref (fms.message);
+
+ e_sexp_unref (sexp);
+
+ return CAMEL_SEARCH_ERROR;
+}
diff --git a/camel/camel-folder-search.c b/camel/camel-folder-search.c
new file mode 100644
index 0000000000..a0bc3345fe
--- /dev/null
+++ b/camel/camel-folder-search.c
@@ -0,0 +1,1409 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2000-2003 Ximian Inc.
+ *
+ * Authors: Michael Zucchi <notzed@ximian.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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* This is a helper class for folders to implement the search function.
+ It implements enough to do basic searches on folders that can provide
+ an in-memory summary and a body index. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <regex.h>
+
+#include <glib.h>
+
+#include "camel-folder-search.h"
+#include "camel-folder-thread.h"
+
+#include "camel-exception.h"
+#include "camel-medium.h"
+#include "camel-multipart.h"
+#include "camel-mime-message.h"
+#include "camel-stream-mem.h"
+#include "e-util/e-memory.h"
+#include "camel-search-private.h"
+
+#define d(x)
+#define r(x)
+
+struct _CamelFolderSearchPrivate {
+ GHashTable *mempool_hash;
+ CamelException *ex;
+
+ CamelFolderThread *threads;
+ GHashTable *threads_hash;
+};
+
+#define _PRIVATE(o) (((CamelFolderSearch *)(o))->priv)
+
+static ESExpResult *search_not(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search);
+
+static ESExpResult *search_header_contains(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search);
+static ESExpResult *search_header_matches(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search);
+static ESExpResult *search_header_starts_with(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search);
+static ESExpResult *search_header_ends_with(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search);
+static ESExpResult *search_header_exists(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search);
+static ESExpResult *search_match_all(struct _ESExp *f, int argc, struct _ESExpTerm **argv, CamelFolderSearch *search);
+static ESExpResult *search_match_threads(struct _ESExp *f, int argc, struct _ESExpTerm **argv, CamelFolderSearch *s);
+static ESExpResult *search_body_contains(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search);
+static ESExpResult *search_user_flag(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *s);
+static ESExpResult *search_user_tag(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *s);
+static ESExpResult *search_system_flag(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *s);
+static ESExpResult *search_get_sent_date(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *s);
+static ESExpResult *search_get_received_date(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *s);
+static ESExpResult *search_get_current_date(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *s);
+static ESExpResult *search_get_size(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *s);
+static ESExpResult *search_uid(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *s);
+
+static ESExpResult *search_dummy(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search);
+
+static void camel_folder_search_class_init (CamelFolderSearchClass *klass);
+static void camel_folder_search_init (CamelFolderSearch *obj);
+static void camel_folder_search_finalize (CamelObject *obj);
+
+static CamelObjectClass *camel_folder_search_parent;
+
+static void
+camel_folder_search_class_init (CamelFolderSearchClass *klass)
+{
+ camel_folder_search_parent = camel_type_get_global_classfuncs (camel_object_get_type ());
+
+ klass->not = search_not;
+
+ klass->match_all = search_match_all;
+ klass->match_threads = search_match_threads;
+ klass->body_contains = search_body_contains;
+ klass->header_contains = search_header_contains;
+ klass->header_matches = search_header_matches;
+ klass->header_starts_with = search_header_starts_with;
+ klass->header_ends_with = search_header_ends_with;
+ klass->header_exists = search_header_exists;
+ klass->user_tag = search_user_tag;
+ klass->user_flag = search_user_flag;
+ klass->system_flag = search_system_flag;
+ klass->get_sent_date = search_get_sent_date;
+ klass->get_received_date = search_get_received_date;
+ klass->get_current_date = search_get_current_date;
+ klass->get_size = search_get_size;
+ klass->uid = search_uid;
+}
+
+static void
+camel_folder_search_init (CamelFolderSearch *obj)
+{
+ struct _CamelFolderSearchPrivate *p;
+
+ p = _PRIVATE(obj) = g_malloc0(sizeof(*p));
+
+ obj->sexp = e_sexp_new();
+
+ /* use a hash of mempools to associate the returned uid lists with
+ the backing mempool. yes pretty weird, but i didn't want to change
+ the api just yet */
+
+ p->mempool_hash = g_hash_table_new(0, 0);
+}
+
+static void
+free_mempool(void *key, void *value, void *data)
+{
+ GPtrArray *uids = key;
+ EMemPool *pool = value;
+
+ g_warning("Search closed with outstanding result unfreed: %p", uids);
+
+ g_ptr_array_free(uids, TRUE);
+ e_mempool_destroy(pool);
+}
+
+static void
+camel_folder_search_finalize (CamelObject *obj)
+{
+ CamelFolderSearch *search = (CamelFolderSearch *)obj;
+ struct _CamelFolderSearchPrivate *p = _PRIVATE(obj);
+
+ if (search->sexp)
+ e_sexp_unref(search->sexp);
+ if (search->summary_hash)
+ g_hash_table_destroy(search->summary_hash);
+
+ g_free(search->last_search);
+ g_hash_table_foreach(p->mempool_hash, free_mempool, obj);
+ g_hash_table_destroy(p->mempool_hash);
+ g_free(p);
+}
+
+CamelType
+camel_folder_search_get_type (void)
+{
+ static CamelType type = CAMEL_INVALID_TYPE;
+
+ if (type == CAMEL_INVALID_TYPE) {
+ type = camel_type_register (camel_object_get_type (), "CamelFolderSearch",
+ sizeof (CamelFolderSearch),
+ sizeof (CamelFolderSearchClass),
+ (CamelObjectClassInitFunc) camel_folder_search_class_init,
+ NULL,
+ (CamelObjectInitFunc) camel_folder_search_init,
+ (CamelObjectFinalizeFunc) camel_folder_search_finalize);
+ }
+
+ return type;
+}
+
+#ifdef offsetof
+#define CAMEL_STRUCT_OFFSET(type, field) ((gint) offsetof (type, field))
+#else
+#define CAMEL_STRUCT_OFFSET(type, field) ((gint) ((gchar*) &((type *) 0)->field))
+#endif
+
+struct {
+ char *name;
+ int offset;
+ int flags; /* 0x02 = immediate, 0x01 = always enter */
+} builtins[] = {
+ /* these have default implementations in e-sexp */
+ { "and", CAMEL_STRUCT_OFFSET(CamelFolderSearchClass, and), 2 },
+ { "or", CAMEL_STRUCT_OFFSET(CamelFolderSearchClass, or), 2 },
+ /* we need to override this one though to implement an 'array not' */
+ { "not", CAMEL_STRUCT_OFFSET(CamelFolderSearchClass, not), 0 },
+ { "<", CAMEL_STRUCT_OFFSET(CamelFolderSearchClass, lt), 2 },
+ { ">", CAMEL_STRUCT_OFFSET(CamelFolderSearchClass, gt), 2 },
+ { "=", CAMEL_STRUCT_OFFSET(CamelFolderSearchClass, eq), 2 },
+
+ /* these we have to use our own default if there is none */
+ /* they should all be defined in the language? so it parses, or should they not?? */
+ { "match-all", CAMEL_STRUCT_OFFSET(CamelFolderSearchClass, match_all), 3 },
+ { "match-threads", CAMEL_STRUCT_OFFSET(CamelFolderSearchClass, match_threads), 3 },
+ { "body-contains", CAMEL_STRUCT_OFFSET(CamelFolderSearchClass, body_contains), 1 },
+ { "header-contains", CAMEL_STRUCT_OFFSET(CamelFolderSearchClass, header_contains), 1 },
+ { "header-matches", CAMEL_STRUCT_OFFSET(CamelFolderSearchClass, header_matches), 1 },
+ { "header-starts-with", CAMEL_STRUCT_OFFSET(CamelFolderSearchClass, header_starts_with), 1 },
+ { "header-ends-with", CAMEL_STRUCT_OFFSET(CamelFolderSearchClass, header_ends_with), 1 },
+ { "header-exists", CAMEL_STRUCT_OFFSET(CamelFolderSearchClass, header_exists), 1 },
+ { "user-tag", CAMEL_STRUCT_OFFSET(CamelFolderSearchClass, user_tag), 1 },
+ { "user-flag", CAMEL_STRUCT_OFFSET(CamelFolderSearchClass, user_flag), 1 },
+ { "system-flag", CAMEL_STRUCT_OFFSET(CamelFolderSearchClass, system_flag), 1 },
+ { "get-sent-date", CAMEL_STRUCT_OFFSET(CamelFolderSearchClass, get_sent_date), 1 },
+ { "get-received-date", CAMEL_STRUCT_OFFSET(CamelFolderSearchClass, get_received_date), 1 },
+ { "get-current-date", CAMEL_STRUCT_OFFSET(CamelFolderSearchClass, get_current_date), 1 },
+ { "get-size", CAMEL_STRUCT_OFFSET(CamelFolderSearchClass, get_size), 1 },
+ { "uid", CAMEL_STRUCT_OFFSET(CamelFolderSearchClass, uid), 1 },
+};
+
+void
+camel_folder_search_construct (CamelFolderSearch *search)
+{
+ int i;
+ CamelFolderSearchClass *klass = (CamelFolderSearchClass *)CAMEL_OBJECT_GET_CLASS(search);
+
+ for (i=0;i<sizeof(builtins)/sizeof(builtins[0]);i++) {
+ void *func;
+ /* c is sure messy sometimes */
+ func = *((void **)(((char *)klass)+builtins[i].offset));
+ if (func == NULL && builtins[i].flags&1) {
+ g_warning("Search class doesn't implement '%s' method: %s", builtins[i].name, camel_type_to_name(CAMEL_OBJECT_GET_CLASS(search)));
+ func = (void *)search_dummy;
+ }
+ if (func != NULL) {
+ if (builtins[i].flags&2) {
+ e_sexp_add_ifunction(search->sexp, 0, builtins[i].name, (ESExpIFunc *)func, search);
+ } else {
+ e_sexp_add_function(search->sexp, 0, builtins[i].name, (ESExpFunc *)func, search);
+ }
+ }
+ }
+}
+
+/**
+ * camel_folder_search_new:
+ *
+ * Create a new CamelFolderSearch object.
+ *
+ * A CamelFolderSearch is a subclassable, extensible s-exp
+ * evaluator which enforces a particular set of s-expressions.
+ * Particular methods may be overriden by an implementation to
+ * implement a search for any sort of backend.
+ *
+ * Return value: A new CamelFolderSearch widget.
+ **/
+CamelFolderSearch *
+camel_folder_search_new (void)
+{
+ CamelFolderSearch *new = CAMEL_FOLDER_SEARCH (camel_object_new (camel_folder_search_get_type ()));
+
+ camel_folder_search_construct(new);
+ return new;
+}
+
+/**
+ * camel_folder_search_set_folder:
+ * @search:
+ * @folder: A folder.
+ *
+ * Set the folder attribute of the search. This is currently unused, but
+ * could be used to perform a slow-search when indexes and so forth are not
+ * available. Or for use by subclasses.
+ **/
+void
+camel_folder_search_set_folder(CamelFolderSearch *search, CamelFolder *folder)
+{
+ search->folder = folder;
+}
+
+/**
+ * camel_folder_search_set_summary:
+ * @search:
+ * @summary: An array of CamelMessageInfo pointers.
+ *
+ * Set the array of summary objects representing the span of the search.
+ *
+ * If this is not set, then a subclass must provide the functions
+ * for searching headers and for the match-all operator.
+ **/
+void
+camel_folder_search_set_summary(CamelFolderSearch *search, GPtrArray *summary)
+{
+ int i;
+
+ search->summary = summary;
+ if (search->summary_hash)
+ g_hash_table_destroy(search->summary_hash);
+ search->summary_hash = g_hash_table_new(g_str_hash, g_str_equal);
+ for (i=0;i<summary->len;i++)
+ g_hash_table_insert(search->summary_hash, (char *)camel_message_info_uid(summary->pdata[i]), summary->pdata[i]);
+}
+
+/**
+ * camel_folder_search_set_body_index:
+ * @search:
+ * @index:
+ *
+ * Set the index representing the contents of all messages
+ * in this folder. If this is not set, then the folder implementation
+ * should sub-class the CamelFolderSearch and provide its own
+ * body-contains function.
+ **/
+void
+camel_folder_search_set_body_index(CamelFolderSearch *search, CamelIndex *index)
+{
+ if (search->body_index)
+ camel_object_unref((CamelObject *)search->body_index);
+ search->body_index = index;
+ if (index)
+ camel_object_ref((CamelObject *)index);
+}
+
+/**
+ * camel_folder_search_execute_expression:
+ * @search:
+ * @expr:
+ * @ex:
+ *
+ * Execute the search expression @expr, returning an array of
+ * all matches as a GPtrArray of uid's of matching messages.
+ *
+ * Note that any settings such as set_body_index(), set_folder(),
+ * and so on are reset to #NULL once the search has completed.
+ *
+ * TODO: The interface should probably return summary items instead
+ * (since they are much more useful to any client).
+ *
+ * Return value: A GPtrArray of strings of all matching messages.
+ * This must only be freed by camel_folder_search_free_result.
+ **/
+GPtrArray *
+camel_folder_search_execute_expression(CamelFolderSearch *search, const char *expr, CamelException *ex)
+{
+ ESExpResult *r;
+ GPtrArray *matches;
+ int i;
+ GHashTable *results;
+ EMemPool *pool;
+ struct _CamelFolderSearchPrivate *p = _PRIVATE(search);
+
+ p->ex = ex;
+
+ /* only re-parse if the search has changed */
+ if (search->last_search == NULL
+ || strcmp(search->last_search, expr)) {
+ e_sexp_input_text(search->sexp, expr, strlen(expr));
+ if (e_sexp_parse(search->sexp) == -1) {
+ camel_exception_setv(ex, 1, _("Cannot parse search expression: %s:\n%s"), e_sexp_error(search->sexp), expr);
+ return NULL;
+ }
+
+ g_free(search->last_search);
+ search->last_search = g_strdup(expr);
+ }
+ r = e_sexp_eval(search->sexp);
+ if (r == NULL) {
+ if (!camel_exception_is_set(ex))
+ camel_exception_setv(ex, 1, _("Error executing search expression: %s:\n%s"), e_sexp_error(search->sexp), expr);
+ return NULL;
+ }
+
+ matches = g_ptr_array_new();
+
+ /* now create a folder summary to return?? */
+ if (r->type == ESEXP_RES_ARRAY_PTR) {
+ d(printf("got result ...\n"));
+ /* we use a mempool to store the strings, packed in tight as possible, and freed together */
+ /* because the strings are often short (like <8 bytes long), we would be wasting appx 50%
+ of memory just storing the size tag that malloc assigns us and alignment padding, so this
+ gets around that (and is faster to allocate and free as a bonus) */
+ pool = e_mempool_new(512, 256, E_MEMPOOL_ALIGN_BYTE);
+ if (search->summary) {
+ /* reorder result in summary order */
+ results = g_hash_table_new(g_str_hash, g_str_equal);
+ for (i=0;i<r->value.ptrarray->len;i++) {
+ d(printf("adding match: %s\n", (char *)g_ptr_array_index(r->value.ptrarray, i)));
+ g_hash_table_insert(results, g_ptr_array_index(r->value.ptrarray, i), GINT_TO_POINTER (1));
+ }
+ for (i=0;i<search->summary->len;i++) {
+ CamelMessageInfo *info = g_ptr_array_index(search->summary, i);
+ char *uid = (char *)camel_message_info_uid(info);
+ if (g_hash_table_lookup(results, uid)) {
+ g_ptr_array_add(matches, e_mempool_strdup(pool, uid));
+ }
+ }
+ g_hash_table_destroy(results);
+ } else {
+ for (i=0;i<r->value.ptrarray->len;i++) {
+ d(printf("adding match: %s\n", (char *)g_ptr_array_index(r->value.ptrarray, i)));
+ g_ptr_array_add(matches, e_mempool_strdup(pool, g_ptr_array_index(r->value.ptrarray, i)));
+ }
+ }
+ /* instead of putting the mempool_hash in the structure, we keep the api clean by
+ putting a reference to it in a hashtable. Lets us do some debugging and catch
+ unfree'd results as well. */
+ g_hash_table_insert(p->mempool_hash, matches, pool);
+ } else {
+ g_warning("Search returned an invalid result type");
+ }
+
+ e_sexp_result_free(search->sexp, r);
+
+ if (p->threads)
+ camel_folder_thread_messages_unref(p->threads);
+ if (p->threads_hash)
+ g_hash_table_destroy(p->threads_hash);
+
+ p->threads = NULL;
+ p->threads_hash = NULL;
+ search->folder = NULL;
+ search->summary = NULL;
+ search->current = NULL;
+ search->body_index = NULL;
+
+ return matches;
+}
+
+/**
+ * camel_folder_search_search:
+ * @search:
+ * @expr:
+ * @uids: to search against, NULL for all uid's.
+ * @ex:
+ *
+ * Run a search. Search must have had Folder already set on it, and
+ * it must implement summaries.
+ *
+ * Return value:
+ **/
+GPtrArray *
+camel_folder_search_search(CamelFolderSearch *search, const char *expr, GPtrArray *uids, CamelException *ex)
+{
+ ESExpResult *r;
+ GPtrArray *matches = NULL, *summary_set;
+ int i;
+ GHashTable *results;
+ EMemPool *pool;
+ struct _CamelFolderSearchPrivate *p = _PRIVATE(search);
+
+ g_assert(search->folder);
+
+ p->ex = ex;
+
+ /* setup our search list, summary_hash only contains those we're interested in */
+ search->summary = camel_folder_get_summary(search->folder);
+ search->summary_hash = g_hash_table_new(g_str_hash, g_str_equal);
+
+ if (uids) {
+ GHashTable *uids_hash = g_hash_table_new(g_str_hash, g_str_equal);
+
+ summary_set = search->summary_set = g_ptr_array_new();
+ for (i=0;i<uids->len;i++)
+ g_hash_table_insert(uids_hash, uids->pdata[i], uids->pdata[i]);
+ for (i=0;i<search->summary->len;i++)
+ if (g_hash_table_lookup(uids_hash, camel_message_info_uid(search->summary->pdata[i])))
+ g_ptr_array_add(search->summary_set, search->summary->pdata[i]);
+ } else {
+ summary_set = search->summary;
+ }
+
+ for (i=0;i<summary_set->len;i++)
+ g_hash_table_insert(search->summary_hash, (char *)camel_message_info_uid(summary_set->pdata[i]), summary_set->pdata[i]);
+
+ /* only re-parse if the search has changed */
+ if (search->last_search == NULL
+ || strcmp(search->last_search, expr)) {
+ e_sexp_input_text(search->sexp, expr, strlen(expr));
+ if (e_sexp_parse(search->sexp) == -1) {
+ camel_exception_setv(ex, 1, _("Cannot parse search expression: %s:\n%s"), e_sexp_error(search->sexp), expr);
+ goto fail;
+ }
+
+ g_free(search->last_search);
+ search->last_search = g_strdup(expr);
+ }
+ r = e_sexp_eval(search->sexp);
+ if (r == NULL) {
+ if (!camel_exception_is_set(ex))
+ camel_exception_setv(ex, 1, _("Error executing search expression: %s:\n%s"), e_sexp_error(search->sexp), expr);
+ goto fail;
+ }
+
+ matches = g_ptr_array_new();
+
+ /* now create a folder summary to return?? */
+ if (r->type == ESEXP_RES_ARRAY_PTR) {
+ d(printf("got result ...\n"));
+
+ /* we use a mempool to store the strings, packed in tight as possible, and freed together */
+ /* because the strings are often short (like <8 bytes long), we would be wasting appx 50%
+ of memory just storing the size tag that malloc assigns us and alignment padding, so this
+ gets around that (and is faster to allocate and free as a bonus) */
+ pool = e_mempool_new(512, 256, E_MEMPOOL_ALIGN_BYTE);
+ /* reorder result in summary order */
+ results = g_hash_table_new(g_str_hash, g_str_equal);
+ for (i=0;i<r->value.ptrarray->len;i++) {
+ d(printf("adding match: %s\n", (char *)g_ptr_array_index(r->value.ptrarray, i)));
+ g_hash_table_insert(results, g_ptr_array_index(r->value.ptrarray, i), GINT_TO_POINTER (1));
+ }
+
+ for (i=0;i<summary_set->len;i++) {
+ CamelMessageInfo *info = g_ptr_array_index(summary_set, i);
+ char *uid = (char *)camel_message_info_uid(info);
+ if (g_hash_table_lookup(results, uid))
+ g_ptr_array_add(matches, e_mempool_strdup(pool, uid));
+ }
+ g_hash_table_destroy(results);
+
+ /* instead of putting the mempool_hash in the structure, we keep the api clean by
+ putting a reference to it in a hashtable. Lets us do some debugging and catch
+ unfree'd results as well. */
+ g_hash_table_insert(p->mempool_hash, matches, pool);
+ } else {
+ g_warning("Search returned an invalid result type");
+ }
+
+ e_sexp_result_free(search->sexp, r);
+fail:
+ /* these might be allocated by match-threads */
+ if (p->threads)
+ camel_folder_thread_messages_unref(p->threads);
+ if (p->threads_hash)
+ g_hash_table_destroy(p->threads_hash);
+ if (search->summary_set)
+ g_ptr_array_free(search->summary_set, TRUE);
+ g_hash_table_destroy(search->summary_hash);
+ camel_folder_free_summary(search->folder, search->summary);
+
+ p->threads = NULL;
+ p->threads_hash = NULL;
+ search->folder = NULL;
+ search->summary = NULL;
+ search->summary_hash = NULL;
+ search->summary_set = NULL;
+ search->current = NULL;
+ search->body_index = NULL;
+
+ return matches;
+}
+
+void camel_folder_search_free_result(CamelFolderSearch *search, GPtrArray *result)
+{
+ int i;
+ struct _CamelFolderSearchPrivate *p = _PRIVATE(search);
+ EMemPool *pool;
+
+ pool = g_hash_table_lookup(p->mempool_hash, result);
+ if (pool) {
+ e_mempool_destroy(pool);
+ g_hash_table_remove(p->mempool_hash, result);
+ } else {
+ for (i=0;i<result->len;i++)
+ g_free(g_ptr_array_index(result, i));
+ }
+ g_ptr_array_free(result, TRUE);
+}
+
+/* dummy function, returns false always, or an empty match array */
+static ESExpResult *
+search_dummy(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search)
+{
+ ESExpResult *r;
+
+ if (search->current == NULL) {
+ r = e_sexp_result_new(f, ESEXP_RES_BOOL);
+ r->value.bool = FALSE;
+ } else {
+ r = e_sexp_result_new(f, ESEXP_RES_ARRAY_PTR);
+ r->value.ptrarray = g_ptr_array_new();
+ }
+
+ return r;
+}
+
+/* impelemnt an 'array not', i.e. everything in the summary, not in the supplied array */
+static ESExpResult *
+search_not(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search)
+{
+ ESExpResult *r;
+ int i;
+
+ if (argc>0) {
+ if (argv[0]->type == ESEXP_RES_ARRAY_PTR) {
+ GPtrArray *v = argv[0]->value.ptrarray;
+ const char *uid;
+
+ r = e_sexp_result_new(f, ESEXP_RES_ARRAY_PTR);
+ r->value.ptrarray = g_ptr_array_new();
+
+ /* not against a single message?*/
+ if (search->current) {
+ int found = FALSE;
+
+ uid = camel_message_info_uid(search->current);
+ for (i=0;!found && i<v->len;i++) {
+ if (strcmp(uid, v->pdata[i]) == 0)
+ found = TRUE;
+ }
+
+ if (!found)
+ g_ptr_array_add(r->value.ptrarray, (char *)uid);
+ } else if (search->summary == NULL) {
+ g_warning("No summary set, 'not' against an array requires a summary");
+ } else {
+ /* 'not' against the whole summary */
+ GHashTable *have = g_hash_table_new(g_str_hash, g_str_equal);
+ char **s;
+ CamelMessageInfo **m;
+
+ s = (char **)v->pdata;
+ for (i=0;i<v->len;i++)
+ g_hash_table_insert(have, s[i], s[i]);
+
+ v = search->summary_set?search->summary_set:search->summary;
+ m = (CamelMessageInfo **)v->pdata;
+ for (i=0;i<v->len;i++) {
+ char *uid = (char *)camel_message_info_uid(m[i]);
+
+ if (g_hash_table_lookup(have, uid) == NULL)
+ g_ptr_array_add(r->value.ptrarray, uid);
+ }
+ g_hash_table_destroy(have);
+ }
+ } else {
+ int res = TRUE;
+
+ if (argv[0]->type == ESEXP_RES_BOOL)
+ res = ! argv[0]->value.bool;
+
+ r = e_sexp_result_new(f, ESEXP_RES_BOOL);
+ r->value.bool = res;
+ }
+ } else {
+ r = e_sexp_result_new(f, ESEXP_RES_BOOL);
+ r->value.bool = TRUE;
+ }
+
+ return r;
+}
+
+static ESExpResult *
+search_match_all(struct _ESExp *f, int argc, struct _ESExpTerm **argv, CamelFolderSearch *search)
+{
+ int i;
+ ESExpResult *r, *r1;
+ GPtrArray *v;
+
+ if (argc>1) {
+ g_warning("match-all only takes a single argument, other arguments ignored");
+ }
+
+ /* we are only matching a single message? or already inside a match-all? */
+ if (search->current) {
+ d(printf("matching against 1 message: %s\n", camel_message_info_subject(search->current)));
+
+ r = e_sexp_result_new(f, ESEXP_RES_BOOL);
+ r->value.bool = FALSE;
+
+ if (argc>0) {
+ r1 = e_sexp_term_eval(f, argv[0]);
+ if (r1->type == ESEXP_RES_BOOL) {
+ r->value.bool = r1->value.bool;
+ } else {
+ g_warning("invalid syntax, matches require a single bool result");
+ e_sexp_fatal_error(f, _("(match-all) requires a single bool result"));
+ }
+ e_sexp_result_free(f, r1);
+ } else {
+ r->value.bool = TRUE;
+ }
+ return r;
+ }
+
+ r = e_sexp_result_new(f, ESEXP_RES_ARRAY_PTR);
+ r->value.ptrarray = g_ptr_array_new();
+
+ if (search->summary == NULL) {
+ /* TODO: make it work - e.g. use the folder and so forth for a slower search */
+ g_warning("No summary supplied, match-all doesn't work with no summary");
+ g_assert(0);
+ return r;
+ }
+
+ v = search->summary_set?search->summary_set:search->summary;
+ for (i=0;i<v->len;i++) {
+ const char *uid;
+
+ search->current = g_ptr_array_index(v, i);
+ uid = camel_message_info_uid(search->current);
+
+ if (argc>0) {
+ r1 = e_sexp_term_eval(f, argv[0]);
+ if (r1->type == ESEXP_RES_BOOL) {
+ if (r1->value.bool)
+ g_ptr_array_add(r->value.ptrarray, (char *)uid);
+ } else {
+ g_warning("invalid syntax, matches require a single bool result");
+ e_sexp_fatal_error(f, _("(match-all) requires a single bool result"));
+ }
+ e_sexp_result_free(f, r1);
+ } else {
+ g_ptr_array_add(r->value.ptrarray, (char *)uid);
+ }
+ }
+ search->current = NULL;
+
+ return r;
+}
+
+static void
+fill_thread_table(struct _CamelFolderThreadNode *root, GHashTable *id_hash)
+{
+ while (root) {
+ g_hash_table_insert(id_hash, (char *)camel_message_info_uid(root->message), root);
+ if (root->child)
+ fill_thread_table(root->child, id_hash);
+ root = root->next;
+ }
+}
+
+static void
+add_thread_results(struct _CamelFolderThreadNode *root, GHashTable *result_hash)
+{
+ while (root) {
+ g_hash_table_insert(result_hash, (char *)camel_message_info_uid(root->message), GINT_TO_POINTER (1));
+ if (root->child)
+ add_thread_results(root->child, result_hash);
+ root = root->next;
+ }
+}
+
+static void
+add_results(char *uid, void *dummy, GPtrArray *result)
+{
+ g_ptr_array_add(result, uid);
+}
+
+static ESExpResult *
+search_match_threads(struct _ESExp *f, int argc, struct _ESExpTerm **argv, CamelFolderSearch *search)
+{
+ ESExpResult *r;
+ struct _CamelFolderSearchPrivate *p = search->priv;
+ int i, type;
+ GHashTable *results;
+
+ /* not supported in match-all */
+ if (search->current)
+ e_sexp_fatal_error(f, _("(match-threads) not allowed inside match-all"));
+
+ if (argc == 0)
+ e_sexp_fatal_error(f, _("(match-threads) requires a match type string"));
+
+ r = e_sexp_term_eval(f, argv[0]);
+ if (r->type != ESEXP_RES_STRING)
+ e_sexp_fatal_error(f, _("(match-threads) requires a match type string"));
+
+ type = 0;
+ if (!strcmp(r->value.string, "none"))
+ type = 0;
+ else if (!strcmp(r->value.string, "all"))
+ type = 1;
+ else if (!strcmp(r->value.string, "replies"))
+ type = 2;
+ else if (!strcmp(r->value.string, "replies_parents"))
+ type = 3;
+ e_sexp_result_free(f, r);
+
+ /* behave as (begin does */
+ r = NULL;
+ for (i=1;i<argc;i++) {
+ if (r)
+ e_sexp_result_free(f, r);
+ r = e_sexp_term_eval(f, argv[i]);
+ }
+
+ if (r == NULL || r->type != ESEXP_RES_ARRAY_PTR)
+ e_sexp_fatal_error(f, _("(match-threads) expects an array result"));
+
+ if (type == 0)
+ return r;
+
+ if (search->folder == NULL)
+ e_sexp_fatal_error(f, _("(match-threads) requires the folder set"));
+
+ /* cache this, so we only have to re-calculate once per search at most */
+ if (p->threads == NULL) {
+ p->threads = camel_folder_thread_messages_new(search->folder, NULL, TRUE);
+ p->threads_hash = g_hash_table_new(g_str_hash, g_str_equal);
+
+ fill_thread_table(p->threads->tree, p->threads_hash);
+ }
+
+ results = g_hash_table_new(g_str_hash, g_str_equal);
+ for (i=0;i<r->value.ptrarray->len;i++) {
+ d(printf("adding match: %s\n", (char *)g_ptr_array_index(r->value.ptrarray, i)));
+ g_hash_table_insert(results, g_ptr_array_index(r->value.ptrarray, i), GINT_TO_POINTER (1));
+ }
+
+ for (i=0;i<r->value.ptrarray->len;i++) {
+ struct _CamelFolderThreadNode *node, *scan;
+
+ node = g_hash_table_lookup(p->threads_hash, (char *)g_ptr_array_index(r->value.ptrarray, i));
+ if (node == NULL) /* this shouldn't happen but why cry over spilt milk */
+ continue;
+
+ /* select messages in thread according to search criteria */
+ if (type == 3) {
+ scan = node;
+ while (scan && scan->parent) {
+ scan = scan->parent;
+ g_hash_table_insert(results, (char *)camel_message_info_uid(scan->message), GINT_TO_POINTER(1));
+ }
+ } else if (type == 1) {
+ while (node && node->parent)
+ node = node->parent;
+ }
+ g_hash_table_insert(results, (char *)camel_message_info_uid(node->message), GINT_TO_POINTER(1));
+ if (node->child)
+ add_thread_results(node->child, results);
+ }
+ e_sexp_result_free(f, r);
+
+ r = e_sexp_result_new(f, ESEXP_RES_ARRAY_PTR);
+ r->value.ptrarray = g_ptr_array_new();
+
+ g_hash_table_foreach(results, (GHFunc)add_results, r->value.ptrarray);
+ g_hash_table_destroy(results);
+
+ return r;
+}
+
+static ESExpResult *
+check_header(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search, camel_search_match_t how)
+{
+ ESExpResult *r;
+ int truth = FALSE;
+
+ r(printf("executing check-header %d\n", how));
+
+ /* are we inside a match-all? */
+ if (search->current && argc>1
+ && argv[0]->type == ESEXP_RES_STRING) {
+ char *headername;
+ const char *header = NULL;
+ char strbuf[32];
+ int i, j;
+ camel_search_t type = CAMEL_SEARCH_TYPE_ASIS;
+ struct _camel_search_words *words;
+
+ /* only a subset of headers are supported .. */
+ headername = argv[0]->value.string;
+ if (!strcasecmp(headername, "subject")) {
+ header = camel_message_info_subject(search->current);
+ } else if (!strcasecmp(headername, "date")) {
+ /* FIXME: not a very useful form of the date */
+ sprintf(strbuf, "%d", (int)search->current->date_sent);
+ header = strbuf;
+ } else if (!strcasecmp(headername, "from")) {
+ header = camel_message_info_from(search->current);
+ type = CAMEL_SEARCH_TYPE_ADDRESS;
+ } else if (!strcasecmp(headername, "to")) {
+ header = camel_message_info_to(search->current);
+ type = CAMEL_SEARCH_TYPE_ADDRESS;
+ } else if (!strcasecmp(headername, "cc")) {
+ header = camel_message_info_cc(search->current);
+ type = CAMEL_SEARCH_TYPE_ADDRESS;
+ } else if (!g_ascii_strcasecmp(headername, "x-camel-mlist")) {
+ header = camel_message_info_mlist(search->current);
+ type = CAMEL_SEARCH_TYPE_MLIST;
+ } else {
+ e_sexp_resultv_free(f, argc, argv);
+ e_sexp_fatal_error(f, _("Performing query on unknown header: %s"), headername);
+ }
+
+ if (header == NULL)
+ header = "";
+
+ /* performs an OR of all words */
+ for (i=1;i<argc && !truth;i++) {
+ if (argv[i]->type == ESEXP_RES_STRING) {
+ if (argv[i]->value.string[0] == 0) {
+ truth = TRUE;
+ } else if (how == CAMEL_SEARCH_MATCH_CONTAINS) {
+ /* doesn't make sense to split words on anything but contains i.e. we can't have an ending match different words */
+ words = camel_search_words_split(argv[i]->value.string);
+ truth = TRUE;
+ for (j=0;j<words->len && truth;j++) {
+ truth = camel_search_header_match(header, words->words[j]->word, how, type, NULL);
+ }
+ camel_search_words_free(words);
+ } else {
+ truth = camel_search_header_match(header, argv[i]->value.string, how, type, NULL);
+ }
+ }
+ }
+ }
+ /* TODO: else, find all matches */
+
+ r = e_sexp_result_new(f, ESEXP_RES_BOOL);
+ r->value.bool = truth;
+
+ return r;
+}
+
+static ESExpResult *
+search_header_contains(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search)
+{
+ return check_header(f, argc, argv, search, CAMEL_SEARCH_MATCH_CONTAINS);
+}
+
+static ESExpResult *
+search_header_matches(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search)
+{
+ return check_header(f, argc, argv, search, CAMEL_SEARCH_MATCH_EXACT);
+}
+
+static ESExpResult *
+search_header_starts_with (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search)
+{
+ return check_header(f, argc, argv, search, CAMEL_SEARCH_MATCH_STARTS);
+}
+
+static ESExpResult *
+search_header_ends_with (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search)
+{
+ return check_header(f, argc, argv, search, CAMEL_SEARCH_MATCH_ENDS);
+}
+
+static ESExpResult *
+search_header_exists (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search)
+{
+ ESExpResult *r;
+
+ r(printf ("executing header-exists\n"));
+
+ if (search->current) {
+ r = e_sexp_result_new(f, ESEXP_RES_BOOL);
+ if (argc == 1 && argv[0]->type == ESEXP_RES_STRING)
+ r->value.bool = camel_medium_get_header(CAMEL_MEDIUM(search->current), argv[0]->value.string) != NULL;
+
+ } else {
+ r = e_sexp_result_new(f, ESEXP_RES_ARRAY_PTR);
+ r->value.ptrarray = g_ptr_array_new();
+ }
+
+ return r;
+}
+
+/* this is just to OR results together */
+struct _glib_sux_donkeys {
+ int count;
+ GPtrArray *uids;
+};
+
+/* or, store all unique values */
+static void
+g_lib_sux_htor(char *key, int value, struct _glib_sux_donkeys *fuckup)
+{
+ g_ptr_array_add(fuckup->uids, key);
+}
+
+/* and, only store duplicates */
+static void
+g_lib_sux_htand(char *key, int value, struct _glib_sux_donkeys *fuckup)
+{
+ if (value == fuckup->count)
+ g_ptr_array_add(fuckup->uids, key);
+}
+
+static int
+match_message_index(CamelIndex *idx, const char *uid, const char *match, CamelException *ex)
+{
+ CamelIndexCursor *wc, *nc;
+ const char *word, *name;
+ int truth = FALSE;
+
+ wc = camel_index_words(idx);
+ if (wc) {
+ while (!truth && (word = camel_index_cursor_next(wc))) {
+ if (camel_ustrstrcase(word,match) != NULL) {
+ /* perf: could have the wc cursor return the name cursor */
+ nc = camel_index_find(idx, word);
+ if (nc) {
+ while (!truth && (name = camel_index_cursor_next(nc)))
+ truth = strcmp(name, uid) == 0;
+ camel_object_unref((CamelObject *)nc);
+ }
+ }
+ }
+ camel_object_unref((CamelObject *)wc);
+ }
+
+ return truth;
+}
+
+/*
+ "one two" "three" "four five"
+
+ one and two
+or
+ three
+or
+ four and five
+*/
+
+/* returns messages which contain all words listed in words */
+static GPtrArray *
+match_words_index(CamelFolderSearch *search, struct _camel_search_words *words, CamelException *ex)
+{
+ GPtrArray *result = g_ptr_array_new();
+ GHashTable *ht = g_hash_table_new(g_str_hash, g_str_equal);
+ struct _glib_sux_donkeys lambdafoo;
+ CamelIndexCursor *wc, *nc;
+ const char *word, *name;
+ CamelMessageInfo *mi;
+ int i;
+
+ /* we can have a maximum of 32 words, as we use it as the AND mask */
+
+ wc = camel_index_words(search->body_index);
+ if (wc) {
+ while ((word = camel_index_cursor_next(wc))) {
+ for (i=0;i<words->len;i++) {
+ if (camel_ustrstrcase(word, words->words[i]->word) != NULL) {
+ /* perf: could have the wc cursor return the name cursor */
+ nc = camel_index_find(search->body_index, word);
+ if (nc) {
+ while ((name = camel_index_cursor_next(nc))) {
+ mi = g_hash_table_lookup(search->summary_hash, name);
+ if (mi) {
+ int mask;
+ const char *uid = camel_message_info_uid(mi);
+
+ mask = (GPOINTER_TO_INT(g_hash_table_lookup(ht, uid))) | (1<<i);
+ g_hash_table_insert(ht, (char *)uid, GINT_TO_POINTER(mask));
+ }
+ }
+ camel_object_unref((CamelObject *)nc);
+ }
+ }
+ }
+ }
+ camel_object_unref((CamelObject *)wc);
+
+ lambdafoo.uids = result;
+ lambdafoo.count = (1<<words->len) - 1;
+ g_hash_table_foreach(ht, (GHFunc)g_lib_sux_htand, &lambdafoo);
+ g_hash_table_destroy(ht);
+ }
+
+ return result;
+}
+
+static gboolean
+match_words_1message (CamelDataWrapper *object, struct _camel_search_words *words, guint32 *mask)
+{
+ CamelDataWrapper *containee;
+ int truth = FALSE;
+ int parts, i;
+
+ containee = camel_medium_get_content_object (CAMEL_MEDIUM (object));
+
+ if (containee == NULL)
+ return FALSE;
+
+ /* using the object types is more accurate than using the mime/types */
+ if (CAMEL_IS_MULTIPART (containee)) {
+ parts = camel_multipart_get_number (CAMEL_MULTIPART (containee));
+ for (i = 0; i < parts && truth == FALSE; i++) {
+ CamelDataWrapper *part = (CamelDataWrapper *)camel_multipart_get_part (CAMEL_MULTIPART (containee), i);
+ if (part)
+ truth = match_words_1message(part, words, mask);
+ }
+ } else if (CAMEL_IS_MIME_MESSAGE (containee)) {
+ /* for messages we only look at its contents */
+ truth = match_words_1message((CamelDataWrapper *)containee, words, mask);
+ } else if (camel_content_type_is(CAMEL_DATA_WRAPPER (containee)->mime_type, "text", "*")) {
+ /* for all other text parts, we look inside, otherwise we dont care */
+ CamelStreamMem *mem = (CamelStreamMem *)camel_stream_mem_new ();
+
+ /* FIXME: The match should be part of a stream op */
+ camel_data_wrapper_decode_to_stream (containee, CAMEL_STREAM (mem));
+ camel_stream_write (CAMEL_STREAM (mem), "", 1);
+ for (i=0;i<words->len;i++) {
+ /* FIXME: This is horridly slow, and should use a real search algorithm */
+ if (camel_ustrstrcase(mem->buffer->data, words->words[i]->word) != NULL) {
+ *mask |= (1<<i);
+ /* shortcut a match */
+ if (*mask == (1<<(words->len))-1)
+ return TRUE;
+ }
+ }
+
+ camel_object_unref (mem);
+ }
+
+ return truth;
+}
+
+static gboolean
+match_words_message(CamelFolder *folder, const char *uid, struct _camel_search_words *words, CamelException *ex)
+{
+ guint32 mask;
+ CamelMimeMessage *msg;
+ CamelException x = CAMEL_EXCEPTION_INITIALISER;
+ int truth;
+
+ msg = camel_folder_get_message(folder, uid, &x);
+ if (msg) {
+ mask = 0;
+ truth = match_words_1message((CamelDataWrapper *)msg, words, &mask);
+ camel_object_unref((CamelObject *)msg);
+ } else {
+ camel_exception_clear(&x);
+ truth = FALSE;
+ }
+
+ return truth;
+}
+
+static GPtrArray *
+match_words_messages(CamelFolderSearch *search, struct _camel_search_words *words, CamelException *ex)
+{
+ int i;
+ GPtrArray *matches = g_ptr_array_new();
+
+ if (search->body_index) {
+ GPtrArray *indexed;
+ struct _camel_search_words *simple;
+
+ simple = camel_search_words_simple(words);
+ indexed = match_words_index(search, simple, ex);
+ camel_search_words_free(simple);
+
+ for (i=0;i<indexed->len;i++) {
+ const char *uid = g_ptr_array_index(indexed, i);
+
+ if (match_words_message(search->folder, uid, words, ex))
+ g_ptr_array_add(matches, (char *)uid);
+ }
+
+ g_ptr_array_free(indexed, TRUE);
+ } else {
+ GPtrArray *v = search->summary_set?search->summary_set:search->summary;
+
+ for (i=0;i<v->len;i++) {
+ CamelMessageInfo *info = g_ptr_array_index(v, i);
+ const char *uid = camel_message_info_uid(info);
+
+ if (match_words_message(search->folder, uid, words, ex))
+ g_ptr_array_add(matches, (char *)uid);
+ }
+ }
+
+ return matches;
+}
+
+static ESExpResult *
+search_body_contains(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search)
+{
+ int i, j;
+ CamelException *ex = search->priv->ex;
+ struct _camel_search_words *words;
+ ESExpResult *r;
+ struct _glib_sux_donkeys lambdafoo;
+
+ if (search->current) {
+ int truth = FALSE;
+
+ if (argc == 1 && argv[0]->value.string[0] == 0) {
+ truth = TRUE;
+ } else {
+ for (i=0;i<argc && !truth;i++) {
+ if (argv[i]->type == ESEXP_RES_STRING) {
+ words = camel_search_words_split(argv[i]->value.string);
+ truth = TRUE;
+ if ((words->type & CAMEL_SEARCH_WORD_COMPLEX) == 0 && search->body_index) {
+ for (j=0;j<words->len && truth;j++)
+ truth = match_message_index(search->body_index, camel_message_info_uid(search->current), words->words[j]->word, ex);
+ } else {
+ /* TODO: cache current message incase of multiple body search terms */
+ truth = match_words_message(search->folder, camel_message_info_uid(search->current), words, ex);
+ }
+ camel_search_words_free(words);
+ }
+ }
+ }
+ r = e_sexp_result_new(f, ESEXP_RES_BOOL);
+ r->value.bool = truth;
+ } else {
+ r = e_sexp_result_new(f, ESEXP_RES_ARRAY_PTR);
+ r->value.ptrarray = g_ptr_array_new();
+
+ if (argc == 1 && argv[0]->value.string[0] == 0) {
+ GPtrArray *v = search->summary_set?search->summary_set:search->summary;
+
+ for (i=0;i<v->len;i++) {
+ CamelMessageInfo *info = g_ptr_array_index(v, i);
+
+ g_ptr_array_add(r->value.ptrarray, (char *)camel_message_info_uid(info));
+ }
+ } else {
+ GHashTable *ht = g_hash_table_new(g_str_hash, g_str_equal);
+ GPtrArray *matches;
+
+ for (i=0;i<argc;i++) {
+ if (argv[i]->type == ESEXP_RES_STRING) {
+ words = camel_search_words_split(argv[i]->value.string);
+ if ((words->type & CAMEL_SEARCH_WORD_COMPLEX) == 0 && search->body_index) {
+ matches = match_words_index(search, words, ex);
+ } else {
+ matches = match_words_messages(search, words, ex);
+ }
+ for (j=0;j<matches->len;j++)
+ g_hash_table_insert(ht, matches->pdata[j], matches->pdata[j]);
+ g_ptr_array_free(matches, TRUE);
+ camel_search_words_free(words);
+ }
+ }
+ lambdafoo.uids = r->value.ptrarray;
+ g_hash_table_foreach(ht, (GHFunc)g_lib_sux_htor, &lambdafoo);
+ g_hash_table_destroy(ht);
+ }
+ }
+
+ return r;
+}
+
+static ESExpResult *
+search_user_flag(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search)
+{
+ ESExpResult *r;
+ int i;
+
+ r(printf("executing user-flag\n"));
+
+ /* are we inside a match-all? */
+ if (search->current) {
+ int truth = FALSE;
+ /* performs an OR of all words */
+ for (i=0;i<argc && !truth;i++) {
+ if (argv[i]->type == ESEXP_RES_STRING
+ && camel_flag_get(&search->current->user_flags, argv[i]->value.string)) {
+ truth = TRUE;
+ break;
+ }
+ }
+ r = e_sexp_result_new(f, ESEXP_RES_BOOL);
+ r->value.bool = truth;
+ } else {
+ r = e_sexp_result_new(f, ESEXP_RES_ARRAY_PTR);
+ r->value.ptrarray = g_ptr_array_new();
+ }
+
+ return r;
+}
+
+static ESExpResult *
+search_system_flag (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search)
+{
+ ESExpResult *r;
+
+ r(printf ("executing system-flag\n"));
+
+ if (search->current) {
+ gboolean truth = FALSE;
+
+ if (argc == 1)
+ truth = camel_system_flag_get (search->current->flags, argv[0]->value.string);
+
+ r = e_sexp_result_new(f, ESEXP_RES_BOOL);
+ r->value.bool = truth;
+ } else {
+ r = e_sexp_result_new(f, ESEXP_RES_ARRAY_PTR);
+ r->value.ptrarray = g_ptr_array_new ();
+ }
+
+ return r;
+}
+
+static ESExpResult *
+search_user_tag(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search)
+{
+ const char *value = NULL;
+ ESExpResult *r;
+
+ r(printf("executing user-tag\n"));
+
+ if (argc == 1)
+ value = camel_tag_get (&search->current->user_tags, argv[0]->value.string);
+
+ r = e_sexp_result_new(f, ESEXP_RES_STRING);
+ r->value.string = g_strdup (value ? value : "");
+
+ return r;
+}
+
+static ESExpResult *
+search_get_sent_date(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *s)
+{
+ ESExpResult *r;
+
+ r(printf("executing get-sent-date\n"));
+
+ /* are we inside a match-all? */
+ if (s->current) {
+ r = e_sexp_result_new(f, ESEXP_RES_INT);
+
+ r->value.number = s->current->date_sent;
+ } else {
+ r = e_sexp_result_new(f, ESEXP_RES_ARRAY_PTR);
+ r->value.ptrarray = g_ptr_array_new ();
+ }
+
+ return r;
+}
+
+static ESExpResult *
+search_get_received_date(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *s)
+{
+ ESExpResult *r;
+
+ r(printf("executing get-received-date\n"));
+
+ /* are we inside a match-all? */
+ if (s->current) {
+ r = e_sexp_result_new(f, ESEXP_RES_INT);
+
+ r->value.number = s->current->date_received;
+ } else {
+ r = e_sexp_result_new(f, ESEXP_RES_ARRAY_PTR);
+ r->value.ptrarray = g_ptr_array_new ();
+ }
+
+ return r;
+}
+
+static ESExpResult *
+search_get_current_date(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *s)
+{
+ ESExpResult *r;
+
+ r(printf("executing get-current-date\n"));
+
+ r = e_sexp_result_new(f, ESEXP_RES_INT);
+ r->value.number = time (NULL);
+ return r;
+}
+
+static ESExpResult *
+search_get_size (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *s)
+{
+ ESExpResult *r;
+
+ r(printf("executing get-size\n"));
+
+ /* are we inside a match-all? */
+ if (s->current) {
+ r = e_sexp_result_new (f, ESEXP_RES_INT);
+ r->value.number = s->current->size / 1024;
+ } else {
+ r = e_sexp_result_new (f, ESEXP_RES_ARRAY_PTR);
+ r->value.ptrarray = g_ptr_array_new ();
+ }
+
+ return r;
+}
+
+static ESExpResult *
+search_uid(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search)
+{
+ ESExpResult *r;
+ int i;
+
+ r(printf("executing uid\n"));
+
+ /* are we inside a match-all? */
+ if (search->current) {
+ int truth = FALSE;
+ const char *uid = camel_message_info_uid(search->current);
+
+ /* performs an OR of all words */
+ for (i=0;i<argc && !truth;i++) {
+ if (argv[i]->type == ESEXP_RES_STRING
+ && !strcmp(uid, argv[i]->value.string)) {
+ truth = TRUE;
+ break;
+ }
+ }
+ r = e_sexp_result_new(f, ESEXP_RES_BOOL);
+ r->value.bool = truth;
+ } else {
+ r = e_sexp_result_new(f, ESEXP_RES_ARRAY_PTR);
+ r->value.ptrarray = g_ptr_array_new();
+ for (i=0;i<argc;i++) {
+ if (argv[i]->type == ESEXP_RES_STRING)
+ g_ptr_array_add(r->value.ptrarray, argv[i]->value.string);
+ }
+ }
+
+ return r;
+}
diff --git a/camel/camel-folder-summary.c b/camel/camel-folder-summary.c
new file mode 100644
index 0000000000..bf58f4a47e
--- /dev/null
+++ b/camel/camel-folder-summary.c
@@ -0,0 +1,2888 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2000-2003 Ximian Inc.
+ *
+ * Authors: Michael Zucchi <notzed@ximian.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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include <gal/util/e-iconv.h>
+
+#include "camel-folder-summary.h"
+
+#include <camel/camel-file-utils.h>
+#include <camel/camel-mime-filter.h>
+#include <camel/camel-mime-filter-index.h>
+#include <camel/camel-mime-filter-charset.h>
+#include <camel/camel-mime-filter-basic.h>
+#include <camel/camel-mime-filter-html.h>
+#include <camel/camel-mime-message.h>
+#include <camel/camel-multipart.h>
+#include <camel/camel-stream-mem.h>
+
+#include <camel/camel-stream-null.h>
+#include <camel/camel-stream-filter.h>
+
+#include <camel/camel-string-utils.h>
+
+#include "e-util/md5-utils.h"
+#include "e-util/e-memory.h"
+
+#include "camel-private.h"
+
+
+static pthread_mutex_t info_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* this lock is ONLY for the standalone messageinfo stuff */
+#define GLOBAL_INFO_LOCK(i) pthread_mutex_lock(&info_lock)
+#define GLOBAL_INFO_UNLOCK(i) pthread_mutex_unlock(&info_lock)
+
+
+/* this should probably be conditional on it existing */
+#define USE_BSEARCH
+
+#define d(x)
+#define io(x) /* io debug */
+
+#if 0
+extern int strdup_count, malloc_count, free_count;
+#endif
+
+#define CAMEL_FOLDER_SUMMARY_VERSION (13)
+
+#define _PRIVATE(o) (((CamelFolderSummary *)(o))->priv)
+
+/* trivial lists, just because ... */
+struct _node {
+ struct _node *next;
+};
+
+static struct _node *my_list_append(struct _node **list, struct _node *n);
+static int my_list_size(struct _node **list);
+
+static int summary_header_load(CamelFolderSummary *, FILE *);
+static int summary_header_save(CamelFolderSummary *, FILE *);
+
+static CamelMessageInfo * message_info_new(CamelFolderSummary *, struct _camel_header_raw *);
+static CamelMessageInfo * message_info_new_from_parser(CamelFolderSummary *, CamelMimeParser *);
+static CamelMessageInfo * message_info_new_from_message(CamelFolderSummary *s, CamelMimeMessage *msg);
+static CamelMessageInfo * message_info_load(CamelFolderSummary *, FILE *);
+static int message_info_save(CamelFolderSummary *, FILE *, CamelMessageInfo *);
+static void message_info_free(CamelFolderSummary *, CamelMessageInfo *);
+
+static CamelMessageContentInfo * content_info_new(CamelFolderSummary *, struct _camel_header_raw *);
+static CamelMessageContentInfo * content_info_new_from_parser(CamelFolderSummary *, CamelMimeParser *);
+static CamelMessageContentInfo * content_info_new_from_message(CamelFolderSummary *s, CamelMimePart *mp);
+static CamelMessageContentInfo * content_info_load(CamelFolderSummary *, FILE *);
+static int content_info_save(CamelFolderSummary *, FILE *, CamelMessageContentInfo *);
+static void content_info_free(CamelFolderSummary *, CamelMessageContentInfo *);
+
+static char *next_uid_string(CamelFolderSummary *s);
+
+static CamelMessageContentInfo * summary_build_content_info(CamelFolderSummary *s, CamelMessageInfo *msginfo, CamelMimeParser *mp);
+static CamelMessageContentInfo * summary_build_content_info_message(CamelFolderSummary *s, CamelMessageInfo *msginfo, CamelMimePart *object);
+
+static void camel_folder_summary_class_init (CamelFolderSummaryClass *klass);
+static void camel_folder_summary_init (CamelFolderSummary *obj);
+static void camel_folder_summary_finalize (CamelObject *obj);
+
+static CamelObjectClass *camel_folder_summary_parent;
+
+static void
+camel_folder_summary_class_init (CamelFolderSummaryClass *klass)
+{
+ camel_folder_summary_parent = camel_type_get_global_classfuncs (camel_object_get_type ());
+
+ klass->summary_header_load = summary_header_load;
+ klass->summary_header_save = summary_header_save;
+
+ klass->message_info_new = message_info_new;
+ klass->message_info_new_from_parser = message_info_new_from_parser;
+ klass->message_info_new_from_message = message_info_new_from_message;
+ klass->message_info_load = message_info_load;
+ klass->message_info_save = message_info_save;
+ klass->message_info_free = message_info_free;
+
+ klass->content_info_new = content_info_new;
+ klass->content_info_new_from_parser = content_info_new_from_parser;
+ klass->content_info_new_from_message = content_info_new_from_message;
+ klass->content_info_load = content_info_load;
+ klass->content_info_save = content_info_save;
+ klass->content_info_free = content_info_free;
+
+ klass->next_uid_string = next_uid_string;
+}
+
+static void
+camel_folder_summary_init (CamelFolderSummary *s)
+{
+ struct _CamelFolderSummaryPrivate *p;
+
+ p = _PRIVATE(s) = g_malloc0(sizeof(*p));
+
+ p->filter_charset = g_hash_table_new (camel_strcase_hash, camel_strcase_equal);
+
+ s->message_info_size = sizeof(CamelMessageInfo);
+ s->content_info_size = sizeof(CamelMessageContentInfo);
+
+ s->message_info_chunks = NULL;
+ s->content_info_chunks = NULL;
+
+#if defined (DOESTRV) || defined (DOEPOOLV)
+ s->message_info_strings = CAMEL_MESSAGE_INFO_LAST;
+#endif
+
+ s->version = CAMEL_FOLDER_SUMMARY_VERSION;
+ s->flags = 0;
+ s->time = 0;
+ s->nextuid = 1;
+
+ s->messages = g_ptr_array_new();
+ s->messages_uid = g_hash_table_new(g_str_hash, g_str_equal);
+
+ p->summary_lock = g_mutex_new();
+ p->io_lock = g_mutex_new();
+ p->filter_lock = g_mutex_new();
+ p->alloc_lock = g_mutex_new();
+ p->ref_lock = g_mutex_new();
+}
+
+static void free_o_name(void *key, void *value, void *data)
+{
+ camel_object_unref((CamelObject *)value);
+ g_free(key);
+}
+
+static void
+camel_folder_summary_finalize (CamelObject *obj)
+{
+ struct _CamelFolderSummaryPrivate *p;
+ CamelFolderSummary *s = (CamelFolderSummary *)obj;
+
+ p = _PRIVATE(obj);
+
+ camel_folder_summary_clear(s);
+ g_ptr_array_free(s->messages, TRUE);
+ g_hash_table_destroy(s->messages_uid);
+
+ g_hash_table_foreach(p->filter_charset, free_o_name, 0);
+ g_hash_table_destroy(p->filter_charset);
+
+ g_free(s->summary_path);
+
+ if (s->message_info_chunks)
+ e_memchunk_destroy(s->message_info_chunks);
+ if (s->content_info_chunks)
+ e_memchunk_destroy(s->content_info_chunks);
+
+ if (p->filter_index)
+ camel_object_unref((CamelObject *)p->filter_index);
+ if (p->filter_64)
+ camel_object_unref((CamelObject *)p->filter_64);
+ if (p->filter_qp)
+ camel_object_unref((CamelObject *)p->filter_qp);
+ if (p->filter_uu)
+ camel_object_unref((CamelObject *)p->filter_uu);
+ if (p->filter_save)
+ camel_object_unref((CamelObject *)p->filter_save);
+ if (p->filter_html)
+ camel_object_unref((CamelObject *)p->filter_html);
+
+ if (p->filter_stream)
+ camel_object_unref((CamelObject *)p->filter_stream);
+ if (p->index)
+ camel_object_unref((CamelObject *)p->index);
+
+ g_mutex_free(p->summary_lock);
+ g_mutex_free(p->io_lock);
+ g_mutex_free(p->filter_lock);
+ g_mutex_free(p->alloc_lock);
+ g_mutex_free(p->ref_lock);
+
+ g_free(p);
+}
+
+CamelType
+camel_folder_summary_get_type (void)
+{
+ static CamelType type = CAMEL_INVALID_TYPE;
+
+ if (type == CAMEL_INVALID_TYPE) {
+ type = camel_type_register (camel_object_get_type (), "CamelFolderSummary",
+ sizeof (CamelFolderSummary),
+ sizeof (CamelFolderSummaryClass),
+ (CamelObjectClassInitFunc) camel_folder_summary_class_init,
+ NULL,
+ (CamelObjectInitFunc) camel_folder_summary_init,
+ (CamelObjectFinalizeFunc) camel_folder_summary_finalize);
+ }
+
+ return type;
+}
+
+/**
+ * camel_folder_summary_new:
+ *
+ * Create a new CamelFolderSummary object.
+ *
+ * Return value: A new CamelFolderSummary widget.
+ **/
+CamelFolderSummary *
+camel_folder_summary_new (void)
+{
+ CamelFolderSummary *new = CAMEL_FOLDER_SUMMARY ( camel_object_new (camel_folder_summary_get_type ())); return new;
+}
+
+
+/**
+ * camel_folder_summary_set_filename:
+ * @s:
+ * @name:
+ *
+ * Set the filename where the summary will be loaded to/saved from.
+ **/
+void camel_folder_summary_set_filename(CamelFolderSummary *s, const char *name)
+{
+ CAMEL_SUMMARY_LOCK(s, summary_lock);
+
+ g_free(s->summary_path);
+ s->summary_path = g_strdup(name);
+
+ CAMEL_SUMMARY_UNLOCK(s, summary_lock);
+}
+
+/**
+ * camel_folder_summary_set_index:
+ * @s:
+ * @index:
+ *
+ * Set the index used to index body content. If the index is NULL, or
+ * not set (the default), no indexing of body content will take place.
+ *
+ * Unlike earlier behaviour, build_content need not be set to perform indexing.
+ **/
+void camel_folder_summary_set_index(CamelFolderSummary *s, CamelIndex *index)
+{
+ struct _CamelFolderSummaryPrivate *p = _PRIVATE(s);
+
+ if (p->index)
+ camel_object_unref((CamelObject *)p->index);
+
+ p->index = index;
+ if (index)
+ camel_object_ref((CamelObject *)index);
+}
+
+/**
+ * camel_folder_summary_set_build_content:
+ * @s:
+ * @state:
+ *
+ * Set a flag to tell the summary to build the content info summary
+ * (CamelMessageInfo.content). The default is not to build content info
+ * summaries.
+ **/
+void camel_folder_summary_set_build_content(CamelFolderSummary *s, gboolean state)
+{
+ s->build_content = state;
+}
+
+/**
+ * camel_folder_summary_count:
+ * @s:
+ *
+ * Get the number of summary items stored in this summary.
+ *
+ * Return value: The number of items int he summary.
+ **/
+int
+camel_folder_summary_count(CamelFolderSummary *s)
+{
+ return s->messages->len;
+}
+
+/**
+ * camel_folder_summary_index:
+ * @s:
+ * @i:
+ *
+ * Retrieve a summary item by index number.
+ *
+ * A referenced to the summary item is returned, which may be
+ * ref'd or free'd as appropriate.
+ *
+ * Return value: The summary item, or NULL if the index @i is out
+ * of range.
+ * It must be freed using camel_folder_summary_info_free().
+ **/
+CamelMessageInfo *
+camel_folder_summary_index(CamelFolderSummary *s, int i)
+{
+ CamelMessageInfo *info = NULL;
+
+ CAMEL_SUMMARY_LOCK(s, summary_lock);
+ CAMEL_SUMMARY_LOCK(s, ref_lock);
+
+ if (i<s->messages->len)
+ info = g_ptr_array_index(s->messages, i);
+
+ if (info)
+ info->refcount++;
+
+ CAMEL_SUMMARY_UNLOCK(s, ref_lock);
+ CAMEL_SUMMARY_UNLOCK(s, summary_lock);
+
+ return info;
+}
+
+/**
+ * camel_folder_summary_index:
+ * @s:
+ * @i:
+ *
+ * Obtain a copy of the summary array. This is done atomically,
+ * so cannot contain empty entries.
+ *
+ * It must be freed using camel_folder_summary_array_free().
+ **/
+GPtrArray *
+camel_folder_summary_array(CamelFolderSummary *s)
+{
+ CamelMessageInfo *info;
+ GPtrArray *res = g_ptr_array_new();
+ int i;
+
+ CAMEL_SUMMARY_LOCK(s, summary_lock);
+ CAMEL_SUMMARY_LOCK(s, ref_lock);
+
+ g_ptr_array_set_size(res, s->messages->len);
+ for (i=0;i<s->messages->len;i++) {
+ info = res->pdata[i] = g_ptr_array_index(s->messages, i);
+ info->refcount++;
+ }
+
+ CAMEL_SUMMARY_UNLOCK(s, ref_lock);
+ CAMEL_SUMMARY_UNLOCK(s, summary_lock);
+
+ return res;
+}
+
+/**
+ * camel_folder_summary_array_free:
+ * @s:
+ * @array:
+ *
+ * Free the folder summary array.
+ **/
+void
+camel_folder_summary_array_free(CamelFolderSummary *s, GPtrArray *array)
+{
+ int i;
+
+ for (i=0;i<array->len;i++)
+ camel_folder_summary_info_free(s, array->pdata[i]);
+
+ g_ptr_array_free(array, TRUE);
+}
+
+/**
+ * camel_folder_summary_uid:
+ * @s:
+ * @uid:
+ *
+ * Retrieve a summary item by uid.
+ *
+ * A referenced to the summary item is returned, which may be
+ * ref'd or free'd as appropriate.
+ *
+ * Return value: The summary item, or NULL if the uid @uid
+ * is not available.
+ * It must be freed using camel_folder_summary_info_free().
+ **/
+CamelMessageInfo *
+camel_folder_summary_uid(CamelFolderSummary *s, const char *uid)
+{
+ CamelMessageInfo *info;
+
+ CAMEL_SUMMARY_LOCK(s, summary_lock);
+ CAMEL_SUMMARY_LOCK(s, ref_lock);
+
+ info = g_hash_table_lookup(s->messages_uid, uid);
+
+ if (info)
+ info->refcount++;
+
+ CAMEL_SUMMARY_UNLOCK(s, ref_lock);
+ CAMEL_SUMMARY_UNLOCK(s, summary_lock);
+
+ return info;
+}
+
+/**
+ * camel_folder_summary_next_uid:
+ * @s:
+ *
+ * Generate a new unique uid value as an integer. This
+ * may be used to create a unique sequence of numbers.
+ *
+ * Return value: The next unique uid value.
+ **/
+guint32 camel_folder_summary_next_uid(CamelFolderSummary *s)
+{
+ guint32 uid;
+
+
+ CAMEL_SUMMARY_LOCK(s, summary_lock);
+
+ uid = s->nextuid++;
+
+ CAMEL_SUMMARY_UNLOCK(s, summary_lock);
+
+ /* FIXME: sync this to disk */
+/* summary_header_save(s);*/
+ return uid;
+}
+
+/**
+ * camel_folder_summary_set_uid:
+ * @s:
+ * @uid: The next minimum uid to assign. To avoid clashing
+ * uid's, set this to the uid of a given messages + 1.
+ *
+ * Set the next minimum uid available. This can be used to
+ * ensure new uid's do not clash with existing uid's.
+ **/
+void camel_folder_summary_set_uid(CamelFolderSummary *s, guint32 uid)
+{
+ /* TODO: sync to disk? */
+ CAMEL_SUMMARY_LOCK(s, summary_lock);
+
+ s->nextuid = MAX(s->nextuid, uid);
+
+ CAMEL_SUMMARY_UNLOCK(s, summary_lock);
+}
+
+/**
+ * camel_folder_summary_next_uid_string:
+ * @s:
+ *
+ * Retrieve the next uid, but as a formatted string.
+ *
+ * Return value: The next uid as an unsigned integer string.
+ * This string must be freed by the caller.
+ **/
+char *
+camel_folder_summary_next_uid_string(CamelFolderSummary *s)
+{
+ return ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->next_uid_string(s);
+}
+
+/* loads the content descriptions, recursively */
+static CamelMessageContentInfo *
+perform_content_info_load(CamelFolderSummary *s, FILE *in)
+{
+ int i;
+ guint32 count;
+ CamelMessageContentInfo *ci, *part;
+
+ ci = ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->content_info_load(s, in);
+ if (ci == NULL)
+ return NULL;
+
+ if (camel_file_util_decode_uint32(in, &count) == -1 || count > 500) {
+ camel_folder_summary_content_info_free(s, ci);
+ return NULL;
+ }
+
+ for (i=0;i<count;i++) {
+ part = perform_content_info_load(s, in);
+ if (part) {
+ my_list_append((struct _node **)&ci->childs, (struct _node *)part);
+ part->parent = ci;
+ } else {
+ d(fprintf (stderr, "Summary file format messed up?"));
+ camel_folder_summary_content_info_free(s, ci);
+ return NULL;
+ }
+ }
+ return ci;
+}
+
+int
+camel_folder_summary_load(CamelFolderSummary *s)
+{
+ FILE *in;
+ int i;
+ CamelMessageInfo *mi;
+
+ if (s->summary_path == NULL)
+ return 0;
+
+ in = fopen(s->summary_path, "r");
+ if (in == NULL)
+ return -1;
+
+ CAMEL_SUMMARY_LOCK(s, io_lock);
+ if ( ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->summary_header_load(s, in) == -1)
+ goto error;
+
+ /* now read in each message ... */
+ for (i=0;i<s->saved_count;i++) {
+ mi = ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->message_info_load(s, in);
+
+ if (mi == NULL)
+ goto error;
+
+ if (s->build_content) {
+ mi->content = perform_content_info_load(s, in);
+ if (mi->content == NULL) {
+ camel_folder_summary_info_free(s, mi);
+ goto error;
+ }
+ }
+
+ camel_folder_summary_add(s, mi);
+ }
+
+ CAMEL_SUMMARY_UNLOCK(s, io_lock);
+
+ if (fclose (in) != 0)
+ return -1;
+
+ s->flags &= ~CAMEL_SUMMARY_DIRTY;
+
+ return 0;
+
+error:
+ if (errno != EINVAL)
+ g_warning ("Cannot load summary file: `%s': %s", s->summary_path, g_strerror (errno));
+
+ CAMEL_SUMMARY_UNLOCK(s, io_lock);
+ fclose (in);
+ s->flags |= ~CAMEL_SUMMARY_DIRTY;
+
+ return -1;
+}
+
+/* saves the content descriptions, recursively */
+static int
+perform_content_info_save(CamelFolderSummary *s, FILE *out, CamelMessageContentInfo *ci)
+{
+ CamelMessageContentInfo *part;
+
+ if (((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS (s)))->content_info_save (s, out, ci) == -1)
+ return -1;
+
+ if (camel_file_util_encode_uint32 (out, my_list_size ((struct _node **)&ci->childs)) == -1)
+ return -1;
+
+ part = ci->childs;
+ while (part) {
+ if (perform_content_info_save (s, out, part) == -1)
+ return -1;
+ part = part->next;
+ }
+
+ return 0;
+}
+
+/**
+ * camel_folder_summary_save:
+ * @s:
+ *
+ * Writes the summary to disk. The summary is only written if changes
+ * have occured.
+ *
+ * Return value: Returns -1 on error.
+ **/
+int
+camel_folder_summary_save(CamelFolderSummary *s)
+{
+ FILE *out;
+ int fd, i;
+ guint32 count;
+ CamelMessageInfo *mi;
+ char *path;
+
+ if (s->summary_path == NULL
+ || (s->flags & CAMEL_SUMMARY_DIRTY) == 0)
+ return 0;
+
+ path = alloca(strlen(s->summary_path)+4);
+ sprintf(path, "%s~", s->summary_path);
+ fd = open(path, O_RDWR|O_CREAT|O_TRUNC, 0600);
+ if (fd == -1)
+ return -1;
+ out = fdopen(fd, "w");
+ if (out == NULL) {
+ i = errno;
+ unlink(path);
+ close(fd);
+ errno = i;
+ return -1;
+ }
+
+ io(printf("saving header\n"));
+
+ CAMEL_SUMMARY_LOCK(s, io_lock);
+
+ if (((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->summary_header_save(s, out) == -1)
+ goto exception;
+
+ /* now write out each message ... */
+ /* we check ferorr when done for i/o errors */
+ count = s->messages->len;
+ for (i = 0; i < count; i++) {
+ mi = s->messages->pdata[i];
+ if (((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS (s)))->message_info_save (s, out, mi) == -1)
+ goto exception;
+
+ if (s->build_content) {
+ if (perform_content_info_save (s, out, mi->content) == -1)
+ goto exception;
+ }
+ }
+
+ if (fflush (out) != 0 || fsync (fileno (out)) == -1)
+ goto exception;
+
+ fclose (out);
+
+ CAMEL_SUMMARY_UNLOCK(s, io_lock);
+
+ if (rename(path, s->summary_path) == -1) {
+ i = errno;
+ unlink(path);
+ errno = i;
+ return -1;
+ }
+
+ s->flags &= ~CAMEL_SUMMARY_DIRTY;
+ return 0;
+
+ exception:
+
+ i = errno;
+
+ fclose (out);
+
+ CAMEL_SUMMARY_UNLOCK(s, io_lock);
+
+ unlink (path);
+ errno = i;
+
+ return -1;
+}
+
+/**
+ * camel_folder_summary_header_load:
+ * @s: Summary object.
+ *
+ * Only load the header information from the summary,
+ * keep the rest on disk. This should only be done on
+ * a fresh summary object.
+ *
+ * Return value: -1 on error.
+ **/
+int camel_folder_summary_header_load(CamelFolderSummary *s)
+{
+ FILE *in;
+ int ret;
+
+ if (s->summary_path == NULL)
+ return 0;
+
+ in = fopen(s->summary_path, "r");
+ if (in == NULL)
+ return -1;
+
+ CAMEL_SUMMARY_LOCK(s, io_lock);
+ ret = ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->summary_header_load(s, in);
+ CAMEL_SUMMARY_UNLOCK(s, io_lock);
+
+ fclose(in);
+ s->flags &= ~CAMEL_SUMMARY_DIRTY;
+ return ret;
+}
+
+static int
+summary_assign_uid(CamelFolderSummary *s, CamelMessageInfo *info)
+{
+ const char *uid;
+ CamelMessageInfo *mi;
+
+ uid = camel_message_info_uid(info);
+ if (uid == NULL || uid[0] == 0) {
+ camel_message_info_set_uid(info, camel_folder_summary_next_uid_string(s));
+ uid = camel_message_info_uid(info);
+ }
+
+ CAMEL_SUMMARY_LOCK(s, summary_lock);
+
+ while ((mi = g_hash_table_lookup(s->messages_uid, uid))) {
+ CAMEL_SUMMARY_UNLOCK(s, summary_lock);
+ if (mi == info)
+ return 0;
+ d(printf ("Trying to insert message with clashing uid (%s). new uid re-assigned", camel_message_info_uid(info)));
+ camel_message_info_set_uid(info, camel_folder_summary_next_uid_string(s));
+ uid = camel_message_info_uid(info);
+ info->flags |= CAMEL_MESSAGE_FOLDER_FLAGGED;
+ CAMEL_SUMMARY_LOCK(s, summary_lock);
+ }
+
+ CAMEL_SUMMARY_UNLOCK(s, summary_lock);
+ return 1;
+}
+
+/**
+ * camel_folder_summary_add:
+ * @s:
+ * @info:
+ *
+ * Adds a new @info record to the summary. If @info->uid is NULL, then a new
+ * uid is automatically re-assigned by calling :next_uid_string().
+ *
+ * The @info record should have been generated by calling one of the
+ * info_new_*() functions, as it will be free'd based on the summary
+ * class. And MUST NOT be allocated directly using malloc.
+ **/
+void camel_folder_summary_add(CamelFolderSummary *s, CamelMessageInfo *info)
+{
+ if (info == NULL)
+ return;
+
+ if (summary_assign_uid(s, info) == 0)
+ return;
+
+ CAMEL_SUMMARY_LOCK(s, summary_lock);
+
+/* unnecessary for pooled vectors */
+#ifdef DOESTRV
+ /* this is vitally important, and also if this is ever modified, then
+ the hash table needs to be resynced */
+ info->strings = e_strv_pack(info->strings);
+#endif
+
+ g_ptr_array_add(s->messages, info);
+ g_hash_table_insert(s->messages_uid, (char *)camel_message_info_uid(info), info);
+ s->flags |= CAMEL_SUMMARY_DIRTY;
+
+ CAMEL_SUMMARY_UNLOCK(s, summary_lock);
+}
+
+/**
+ * camel_folder_summary_add_from_header:
+ * @s:
+ * @h:
+ *
+ * Build a new info record based on a set of headers, and add it to the
+ * summary.
+ *
+ * Note that this function should not be used if build_content_info has
+ * been specified for this summary.
+ *
+ * Return value: The newly added record.
+ **/
+CamelMessageInfo *camel_folder_summary_add_from_header(CamelFolderSummary *s, struct _camel_header_raw *h)
+{
+ CamelMessageInfo *info = camel_folder_summary_info_new_from_header(s, h);
+
+ camel_folder_summary_add(s, info);
+
+ return info;
+}
+
+/**
+ * camel_folder_summary_add_from_parser:
+ * @s:
+ * @mp:
+ *
+ * Build a new info record based on the current position of a CamelMimeParser.
+ *
+ * The parser should be positioned before the start of the message to summarise.
+ * This function may be used if build_contnet_info or an index has been
+ * specified for the summary.
+ *
+ * Return value: The newly added record.
+ **/
+CamelMessageInfo *camel_folder_summary_add_from_parser(CamelFolderSummary *s, CamelMimeParser *mp)
+{
+ CamelMessageInfo *info = camel_folder_summary_info_new_from_parser(s, mp);
+
+ camel_folder_summary_add(s, info);
+
+ return info;
+}
+
+/**
+ * camel_folder_summary_add_from_message:
+ * @s:
+ * @msg:
+ *
+ * Add a summary item from an existing message.
+ *
+ * Return value:
+ **/
+CamelMessageInfo *camel_folder_summary_add_from_message(CamelFolderSummary *s, CamelMimeMessage *msg)
+{
+ CamelMessageInfo *info = camel_folder_summary_info_new_from_message(s, msg);
+
+ camel_folder_summary_add(s, info);
+
+ return info;
+}
+
+/**
+ * camel_folder_summary_info_new_from_header:
+ * @s:
+ * @h:
+ *
+ * Create a new info record from a header.
+ *
+ * Return value: Guess? This info record MUST be freed using
+ * camel_folder_summary_info_free(), camel_message_info_free() will not work.
+ **/
+CamelMessageInfo *camel_folder_summary_info_new_from_header(CamelFolderSummary *s, struct _camel_header_raw *h)
+{
+ return ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s))) -> message_info_new(s, h);
+}
+
+/**
+ * camel_folder_summary_info_new_from_parser:
+ * @s:
+ * @mp:
+ *
+ * Create a new info record from a parser. If the parser cannot
+ * determine a uid, then none will be assigned.
+
+ * If indexing is enabled, and the parser cannot determine a new uid, then
+ * one is automatically assigned.
+ *
+ * If indexing is enabled, then the content will be indexed based
+ * on this new uid. In this case, the message info MUST be
+ * added using :add().
+ *
+ * Once complete, the parser will be positioned at the end of
+ * the message.
+ *
+ * Return value: Guess? This info record MUST be freed using
+ * camel_folder_summary_info_free(), camel_message_info_free() will not work.
+ **/
+CamelMessageInfo *camel_folder_summary_info_new_from_parser(CamelFolderSummary *s, CamelMimeParser *mp)
+{
+ CamelMessageInfo *info = NULL;
+ char *buffer;
+ size_t len;
+ struct _CamelFolderSummaryPrivate *p = _PRIVATE(s);
+ off_t start;
+ CamelIndexName *name = NULL;
+
+ /* should this check the parser is in the right state, or assume it is?? */
+
+ start = camel_mime_parser_tell(mp);
+ if (camel_mime_parser_step(mp, &buffer, &len) != CAMEL_MIME_PARSER_STATE_EOF) {
+ info = ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->message_info_new_from_parser(s, mp);
+
+ camel_mime_parser_unstep(mp);
+
+ /* assign a unique uid, this is slightly 'wrong' as we do not really
+ * know if we are going to store this in the summary, but no matter */
+ if (p->index)
+ summary_assign_uid(s, info);
+
+ CAMEL_SUMMARY_LOCK(s, filter_lock);
+
+ if (p->index) {
+ if (p->filter_index == NULL)
+ p->filter_index = camel_mime_filter_index_new_index(p->index);
+ camel_index_delete_name(p->index, camel_message_info_uid(info));
+ name = camel_index_add_name(p->index, camel_message_info_uid(info));
+ camel_mime_filter_index_set_name(p->filter_index, name);
+ }
+
+ /* always scan the content info, even if we dont save it */
+ info->content = summary_build_content_info(s, info, mp);
+
+ if (name) {
+ camel_index_write_name(p->index, name);
+ camel_object_unref((CamelObject *)name);
+ camel_mime_filter_index_set_name(p->filter_index, NULL);
+ }
+
+ CAMEL_SUMMARY_UNLOCK(s, filter_lock);
+
+ info->size = camel_mime_parser_tell(mp) - start;
+ }
+ return info;
+}
+
+/**
+ * camel_folder_summary_info_new_from_message:
+ * @:
+ * @:
+ *
+ * Create a summary item from a message.
+ *
+ * Return value:
+ **/
+CamelMessageInfo *camel_folder_summary_info_new_from_message(CamelFolderSummary *s, CamelMimeMessage *msg)
+{
+ CamelMessageInfo *info;
+ struct _CamelFolderSummaryPrivate *p = _PRIVATE(s);
+ CamelIndexName *name = NULL;
+
+ info = ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->message_info_new_from_message(s, msg);
+
+ /* assign a unique uid, this is slightly 'wrong' as we do not really
+ * know if we are going to store this in the summary, but we need it set for indexing */
+ if (p->index)
+ summary_assign_uid(s, info);
+
+ CAMEL_SUMMARY_LOCK(s, filter_lock);
+
+ if (p->index) {
+ if (p->filter_index == NULL)
+ p->filter_index = camel_mime_filter_index_new_index(p->index);
+ camel_index_delete_name(p->index, camel_message_info_uid(info));
+ name = camel_index_add_name(p->index, camel_message_info_uid(info));
+ camel_mime_filter_index_set_name(p->filter_index, name);
+
+ if (p->filter_stream == NULL) {
+ CamelStream *null = camel_stream_null_new();
+
+ p->filter_stream = camel_stream_filter_new_with_stream(null);
+ camel_object_unref((CamelObject *)null);
+ }
+ }
+
+ info->content = summary_build_content_info_message(s, info, (CamelMimePart *)msg);
+
+ if (name) {
+ camel_index_write_name(p->index, name);
+ camel_object_unref((CamelObject *)name);
+ camel_mime_filter_index_set_name(p->filter_index, NULL);
+ }
+
+ CAMEL_SUMMARY_UNLOCK(s, filter_lock);
+
+ return info;
+}
+
+/**
+ * camel_folder_summary_content_info_free:
+ * @s:
+ * @ci:
+ *
+ * Free the content info @ci, and all associated memory.
+ **/
+void
+camel_folder_summary_content_info_free(CamelFolderSummary *s, CamelMessageContentInfo *ci)
+{
+ CamelMessageContentInfo *pw, *pn;
+
+ pw = ci->childs;
+ ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->content_info_free(s, ci);
+ while (pw) {
+ pn = pw->next;
+ camel_folder_summary_content_info_free(s, pw);
+ pw = pn;
+ }
+}
+
+/**
+ * camel_folder_summary_info_free:
+ * @s:
+ * @mi:
+ *
+ * Unref and potentially free the message info @mi, and all associated memory.
+ **/
+void camel_folder_summary_info_free(CamelFolderSummary *s, CamelMessageInfo *mi)
+{
+ CamelMessageContentInfo *ci;
+
+ g_assert(mi);
+ g_assert(s);
+
+ CAMEL_SUMMARY_LOCK(s, ref_lock);
+
+ g_assert(mi->refcount >= 1);
+
+ mi->refcount--;
+ if (mi->refcount > 0) {
+ CAMEL_SUMMARY_UNLOCK(s, ref_lock);
+ return;
+ }
+
+ CAMEL_SUMMARY_UNLOCK(s, ref_lock);
+
+ ci = mi->content;
+
+ ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->message_info_free(s, mi);
+ if (s->build_content && ci) {
+ camel_folder_summary_content_info_free(s, ci);
+ }
+}
+
+/**
+ * camel_folder_summary_info_ref:
+ * @s:
+ * @mi:
+ *
+ * Add an extra reference to @mi.
+ **/
+void camel_folder_summary_info_ref(CamelFolderSummary *s, CamelMessageInfo *mi)
+{
+ g_assert(mi);
+ g_assert(s);
+
+ CAMEL_SUMMARY_LOCK(s, ref_lock);
+ g_assert(mi->refcount >= 1);
+ mi->refcount++;
+ CAMEL_SUMMARY_UNLOCK(s, ref_lock);
+}
+
+/**
+ * camel_folder_summary_touch:
+ * @s:
+ *
+ * Mark the summary as changed, so that a save will save it.
+ **/
+void
+camel_folder_summary_touch(CamelFolderSummary *s)
+{
+ CAMEL_SUMMARY_LOCK(s, summary_lock);
+ s->flags |= CAMEL_SUMMARY_DIRTY;
+ CAMEL_SUMMARY_UNLOCK(s, summary_lock);
+}
+
+/**
+ * camel_folder_summary_clear:
+ * @s:
+ *
+ * Empty the summary contents.
+ **/
+void
+camel_folder_summary_clear(CamelFolderSummary *s)
+{
+ int i;
+
+ CAMEL_SUMMARY_LOCK(s, summary_lock);
+ if (camel_folder_summary_count(s) == 0) {
+ CAMEL_SUMMARY_UNLOCK(s, summary_lock);
+ return;
+ }
+
+ for (i=0;i<s->messages->len;i++)
+ camel_folder_summary_info_free(s, s->messages->pdata[i]);
+
+ g_ptr_array_set_size(s->messages, 0);
+ g_hash_table_destroy(s->messages_uid);
+ s->messages_uid = g_hash_table_new(g_str_hash, g_str_equal);
+ s->flags |= CAMEL_SUMMARY_DIRTY;
+ CAMEL_SUMMARY_UNLOCK(s, summary_lock);
+}
+
+/**
+ * camel_folder_summary_remove:
+ * @s:
+ * @info:
+ *
+ * Remove a specific @info record from the summary.
+ **/
+void camel_folder_summary_remove(CamelFolderSummary *s, CamelMessageInfo *info)
+{
+ CAMEL_SUMMARY_LOCK(s, summary_lock);
+ g_hash_table_remove(s->messages_uid, camel_message_info_uid(info));
+ g_ptr_array_remove(s->messages, info);
+ s->flags |= CAMEL_SUMMARY_DIRTY;
+ CAMEL_SUMMARY_UNLOCK(s, summary_lock);
+
+ camel_folder_summary_info_free(s, info);
+}
+
+/**
+ * camel_folder_summary_remove_uid:
+ * @s:
+ * @uid:
+ *
+ * Remove a specific info record from the summary, by @uid.
+ **/
+void camel_folder_summary_remove_uid(CamelFolderSummary *s, const char *uid)
+{
+ CamelMessageInfo *oldinfo;
+ char *olduid;
+
+ CAMEL_SUMMARY_LOCK(s, summary_lock);
+ CAMEL_SUMMARY_LOCK(s, ref_lock);
+ if (g_hash_table_lookup_extended(s->messages_uid, uid, (void *)&olduid, (void *)&oldinfo)) {
+ /* make sure it doesn't vanish while we're removing it */
+ oldinfo->refcount++;
+ CAMEL_SUMMARY_UNLOCK(s, ref_lock);
+ CAMEL_SUMMARY_UNLOCK(s, summary_lock);
+ camel_folder_summary_remove(s, oldinfo);
+ camel_folder_summary_info_free(s, oldinfo);
+ } else {
+ CAMEL_SUMMARY_UNLOCK(s, ref_lock);
+ CAMEL_SUMMARY_UNLOCK(s, summary_lock);
+ }
+}
+
+/**
+ * camel_folder_summary_remove_index:
+ * @s:
+ * @index:
+ *
+ * Remove a specific info record from the summary, by index.
+ **/
+void camel_folder_summary_remove_index(CamelFolderSummary *s, int index)
+{
+ CAMEL_SUMMARY_LOCK(s, summary_lock);
+ if (index < s->messages->len) {
+ CamelMessageInfo *info = s->messages->pdata[index];
+
+ g_hash_table_remove(s->messages_uid, camel_message_info_uid(info));
+ g_ptr_array_remove_index(s->messages, index);
+ s->flags |= CAMEL_SUMMARY_DIRTY;
+
+ CAMEL_SUMMARY_UNLOCK(s, summary_lock);
+ camel_folder_summary_info_free(s, info);
+ } else {
+ CAMEL_SUMMARY_UNLOCK(s, summary_lock);
+ }
+}
+
+/**
+ * camel_folder_summary_remove_range:
+ * @s:
+ * @start: initial index
+ * @end: last index to remove
+ *
+ * Removes an indexed range of info records.
+ **/
+void camel_folder_summary_remove_range(CamelFolderSummary *s, int start, int end)
+{
+ if (end < start)
+ return;
+
+ CAMEL_SUMMARY_LOCK(s, summary_lock);
+ if (start < s->messages->len) {
+ CamelMessageInfo **infos;
+ int i;
+
+ end = MIN(end+1, s->messages->len);
+ infos = g_malloc((end-start)*sizeof(infos[0]));
+
+ for (i=start;i<end;i++) {
+ CamelMessageInfo *info = s->messages->pdata[i];
+
+ infos[i-start] = info;
+ g_hash_table_remove(s->messages_uid, camel_message_info_uid(info));
+ }
+
+ memmove(s->messages->pdata+start, s->messages->pdata+end, (s->messages->len-end)*sizeof(s->messages->pdata[0]));
+ g_ptr_array_set_size(s->messages, s->messages->len - (end - start));
+ s->flags |= CAMEL_SUMMARY_DIRTY;
+
+ CAMEL_SUMMARY_UNLOCK(s, summary_lock);
+
+ for (i=start;i<end;i++)
+ camel_folder_summary_info_free(s, infos[i-start]);
+ g_free(infos);
+ } else {
+ CAMEL_SUMMARY_UNLOCK(s, summary_lock);
+ }
+}
+
+/* should be sorted, for binary search */
+/* This is a tokenisation mechanism for strings written to the
+ summary - to save space.
+ This list can have at most 31 words. */
+static char * tokens[] = {
+ "7bit",
+ "8bit",
+ "alternative",
+ "application",
+ "base64",
+ "boundary",
+ "charset",
+ "filename",
+ "html",
+ "image",
+ "iso-8859-1",
+ "iso-8859-8",
+ "message",
+ "mixed",
+ "multipart",
+ "name",
+ "octet-stream",
+ "parallel",
+ "plain",
+ "postscript",
+ "quoted-printable",
+ "related",
+ "rfc822",
+ "text",
+ "us-ascii", /* 25 words */
+};
+
+#define tokens_len (sizeof(tokens)/sizeof(tokens[0]))
+
+/* baiscally ...
+ 0 = null
+ 1-tokens_len == tokens[id-1]
+ >=32 string, length = n-32
+*/
+
+#ifdef USE_BSEARCH
+static int
+token_search_cmp(char *key, char **index)
+{
+ d(printf("comparing '%s' to '%s'\n", key, *index));
+ return strcmp(key, *index);
+}
+#endif
+
+/**
+ * camel_folder_summary_encode_token:
+ * @out:
+ * @str:
+ *
+ * Encode a string value, but use tokenisation and compression
+ * to reduce the size taken for common mailer words. This
+ * can still be used to encode normal strings as well.
+ *
+ * Return value: -1 on error.
+ **/
+int
+camel_folder_summary_encode_token(FILE *out, const char *str)
+{
+ io(printf("Encoding token: '%s'\n", str));
+
+ if (str == NULL) {
+ return camel_file_util_encode_uint32(out, 0);
+ } else {
+ int len = strlen(str);
+ int i, token=-1;
+
+ if (len <= 16) {
+ char lower[32];
+ char **match;
+
+ for (i=0;i<len;i++)
+ lower[i] = tolower(str[i]);
+ lower[i] = 0;
+#ifdef USE_BSEARCH
+ match = bsearch(lower, tokens, tokens_len, sizeof(char *), (int (*)(const void *, const void *))token_search_cmp);
+ if (match)
+ token = match-tokens;
+#else
+ for (i=0;i<tokens_len;i++) {
+ if (!strcmp(tokens[i], lower)) {
+ token = i;
+ break;
+ }
+ }
+#endif
+ }
+ if (token != -1) {
+ return camel_file_util_encode_uint32(out, token+1);
+ } else {
+ if (camel_file_util_encode_uint32(out, len+32) == -1)
+ return -1;
+ if (fwrite(str, len, 1, out) != 1)
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/**
+ * camel_folder_summary_decode_token:
+ * @in:
+ * @str:
+ *
+ * Decode a token value.
+ *
+ * Return value: -1 on error.
+ **/
+int
+camel_folder_summary_decode_token(FILE *in, char **str)
+{
+ char *ret;
+ guint32 len;
+
+ io(printf("Decode token ...\n"));
+
+ if (camel_file_util_decode_uint32(in, &len) == -1) {
+ io(printf ("Could not decode token from file"));
+ *str = NULL;
+ return -1;
+ }
+
+ if (len<32) {
+ if (len <= 0) {
+ ret = NULL;
+ } else if (len<= tokens_len) {
+ ret = g_strdup(tokens[len-1]);
+ } else {
+ io(printf ("Invalid token encountered: %d", len));
+ *str = NULL;
+ return -1;
+ }
+ } else if (len > 10240) {
+ io(printf ("Got broken string header length: %d bytes", len));
+ *str = NULL;
+ return -1;
+ } else {
+ len -= 32;
+ ret = g_malloc(len+1);
+ if (len > 0 && fread(ret, len, 1, in) != 1) {
+ g_free(ret);
+ *str = NULL;
+ return -1;
+ }
+ ret[len]=0;
+ }
+
+ io(printf("Token = '%s'\n", ret));
+
+ *str = ret;
+ return 0;
+}
+
+static struct _node *
+my_list_append(struct _node **list, struct _node *n)
+{
+ struct _node *ln = (struct _node *)list;
+ while (ln->next)
+ ln = ln->next;
+ n->next = 0;
+ ln->next = n;
+ return n;
+}
+
+static int
+my_list_size(struct _node **list)
+{
+ int len = 0;
+ struct _node *ln = (struct _node *)list;
+ while (ln->next) {
+ ln = ln->next;
+ len++;
+ }
+ return len;
+}
+
+static int
+summary_header_load(CamelFolderSummary *s, FILE *in)
+{
+ fseek(in, 0, SEEK_SET);
+
+ io(printf("Loading header\n"));
+
+ if (camel_file_util_decode_fixed_int32(in, &s->version) == -1)
+ return -1;
+
+ /* Legacy version check, before version 12 we have no upgrade knowledge */
+ if ((s->version > 0xff) && (s->version & 0xff) < 12) {
+ io(printf ("Summary header version mismatch"));
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!(s->version < 0x100 && s->version >= 13))
+ io(printf("Loading legacy summary\n"));
+ else
+ io(printf("loading new-format summary\n"));
+
+ /* legacy version */
+ if (camel_file_util_decode_fixed_int32(in, &s->flags) == -1
+ || camel_file_util_decode_fixed_int32(in, &s->nextuid) == -1
+ || camel_file_util_decode_time_t(in, &s->time) == -1
+ || camel_file_util_decode_fixed_int32(in, &s->saved_count) == -1) {
+ return -1;
+ }
+
+ /* version 13 */
+ if (s->version < 0x100 && s->version >= 13
+ && (camel_file_util_decode_fixed_int32(in, &s->unread_count) == -1
+ || camel_file_util_decode_fixed_int32(in, &s->deleted_count) == -1
+ || camel_file_util_decode_fixed_int32(in, &s->junk_count) == -1)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+summary_header_save(CamelFolderSummary *s, FILE *out)
+{
+ int unread = 0, deleted = 0, junk = 0, count, i;
+
+ fseek(out, 0, SEEK_SET);
+
+ io(printf("Savining header\n"));
+
+ /* we always write out the current version */
+ camel_file_util_encode_fixed_int32(out, CAMEL_FOLDER_SUMMARY_VERSION);
+ camel_file_util_encode_fixed_int32(out, s->flags);
+ camel_file_util_encode_fixed_int32(out, s->nextuid);
+ camel_file_util_encode_time_t(out, s->time);
+
+ count = camel_folder_summary_count(s);
+ for (i=0; i<count; i++) {
+ CamelMessageInfo *info = camel_folder_summary_index(s, i);
+
+ if (info == NULL)
+ continue;
+
+ if ((info->flags & CAMEL_MESSAGE_SEEN) == 0)
+ unread++;
+ if ((info->flags & CAMEL_MESSAGE_DELETED) != 0)
+ deleted++;
+ if ((info->flags & CAMEL_MESSAGE_JUNK) != 0)
+ junk++;
+
+ camel_folder_summary_info_free(s, info);
+ }
+
+ camel_file_util_encode_fixed_int32(out, count);
+ camel_file_util_encode_fixed_int32(out, unread);
+ camel_file_util_encode_fixed_int32(out, deleted);
+
+ return camel_file_util_encode_fixed_int32(out, junk);
+}
+
+/* are these even useful for anything??? */
+static CamelMessageInfo * message_info_new_from_parser(CamelFolderSummary *s, CamelMimeParser *mp)
+{
+ CamelMessageInfo *mi = NULL;
+ int state;
+
+ state = camel_mime_parser_state(mp);
+ switch (state) {
+ case CAMEL_MIME_PARSER_STATE_HEADER:
+ case CAMEL_MIME_PARSER_STATE_MESSAGE:
+ case CAMEL_MIME_PARSER_STATE_MULTIPART:
+ mi = ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->message_info_new(s, camel_mime_parser_headers_raw(mp));
+ break;
+ default:
+ g_error("Invalid parser state");
+ }
+
+ return mi;
+}
+
+static CamelMessageContentInfo * content_info_new_from_parser(CamelFolderSummary *s, CamelMimeParser *mp)
+{
+ CamelMessageContentInfo *ci = NULL;
+
+ switch (camel_mime_parser_state(mp)) {
+ case CAMEL_MIME_PARSER_STATE_HEADER:
+ case CAMEL_MIME_PARSER_STATE_MESSAGE:
+ case CAMEL_MIME_PARSER_STATE_MULTIPART:
+ ci = ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->content_info_new(s, camel_mime_parser_headers_raw(mp));
+ if (ci) {
+ ci->type = camel_mime_parser_content_type(mp);
+ camel_content_type_ref(ci->type);
+ }
+ break;
+ default:
+ g_error("Invalid parser state");
+ }
+
+ return ci;
+}
+
+static CamelMessageInfo * message_info_new_from_message(CamelFolderSummary *s, CamelMimeMessage *msg)
+{
+ CamelMessageInfo *mi;
+
+ mi = ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->message_info_new(s, ((CamelMimePart *)msg)->headers);
+
+ return mi;
+}
+
+static CamelMessageContentInfo * content_info_new_from_message(CamelFolderSummary *s, CamelMimePart *mp)
+{
+ CamelMessageContentInfo *ci;
+
+ ci = ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->content_info_new(s, mp->headers);
+
+ return ci;
+}
+
+static char *
+summary_format_address(struct _camel_header_raw *h, const char *name, const char *charset)
+{
+ struct _camel_header_address *addr;
+ const char *text;
+ char *ret;
+
+ text = camel_header_raw_find (&h, name, NULL);
+ addr = camel_header_address_decode (text, charset);
+ if (addr) {
+ ret = camel_header_address_list_format (addr);
+ camel_header_address_list_clear (&addr);
+ } else {
+ ret = g_strdup (text);
+ }
+
+ return ret;
+}
+
+static char *
+summary_format_string (struct _camel_header_raw *h, const char *name, const char *charset)
+{
+ const char *text;
+
+ text = camel_header_raw_find (&h, name, NULL);
+ if (text) {
+ while (isspace ((unsigned) *text))
+ text++;
+ return camel_header_decode_string (text, charset);
+ } else {
+ return NULL;
+ }
+}
+
+/**
+ * camel_folder_summary_info_new:
+ * @s:
+ *
+ * Allocate a new camel message info, suitable for adding
+ * to this summary.
+ *
+ * Return value:
+ **/
+CamelMessageInfo *
+camel_folder_summary_info_new(CamelFolderSummary *s)
+{
+ CamelMessageInfo *mi;
+
+ CAMEL_SUMMARY_LOCK(s, alloc_lock);
+ if (s->message_info_chunks == NULL)
+ s->message_info_chunks = e_memchunk_new(32, s->message_info_size);
+ mi = e_memchunk_alloc(s->message_info_chunks);
+ CAMEL_SUMMARY_UNLOCK(s, alloc_lock);
+
+ memset(mi, 0, s->message_info_size);
+#ifdef DOEPOOLV
+ mi->strings = e_poolv_new (s->message_info_strings);
+#endif
+#ifdef DOESTRV
+ mi->strings = e_strv_new(s->message_info_strings);
+#endif
+ mi->refcount = 1;
+ return mi;
+}
+
+/**
+ * camel_folder_summary_content_info_new:
+ * @s:
+ *
+ * Allocate a new camel message content info, suitable for adding
+ * to this summary.
+ *
+ * Return value:
+ **/
+CamelMessageContentInfo *
+camel_folder_summary_content_info_new(CamelFolderSummary *s)
+{
+ CamelMessageContentInfo *ci;
+
+ CAMEL_SUMMARY_LOCK(s, alloc_lock);
+ if (s->content_info_chunks == NULL)
+ s->content_info_chunks = e_memchunk_new(32, s->content_info_size);
+ ci = e_memchunk_alloc(s->content_info_chunks);
+ CAMEL_SUMMARY_UNLOCK(s, alloc_lock);
+
+ memset(ci, 0, s->content_info_size);
+ return ci;
+}
+
+static CamelMessageInfo *
+message_info_new(CamelFolderSummary *s, struct _camel_header_raw *h)
+{
+ CamelMessageInfo *mi;
+ const char *received;
+ guchar digest[16];
+ struct _camel_header_references *refs, *irt, *scan;
+ char *msgid;
+ int count;
+ char *subject, *from, *to, *cc, *mlist;
+ CamelContentType *ct = NULL;
+ const char *content, *charset = NULL;
+
+ mi = camel_folder_summary_info_new(s);
+
+ if ((content = camel_header_raw_find(&h, "Content-Type", NULL))
+ && (ct = camel_content_type_decode(content))
+ && (charset = camel_content_type_param(ct, "charset"))
+ && (g_ascii_strcasecmp(charset, "us-ascii") == 0))
+ charset = NULL;
+
+ charset = charset ? e_iconv_charset_name (charset) : NULL;
+
+ subject = summary_format_string(h, "subject", charset);
+ from = summary_format_address(h, "from", charset);
+ to = summary_format_address(h, "to", charset);
+ cc = summary_format_address(h, "cc", charset);
+ mlist = camel_header_raw_check_mailing_list(&h);
+
+ if (ct)
+ camel_content_type_unref(ct);
+
+#ifdef DOEPOOLV
+ e_poolv_set(mi->strings, CAMEL_MESSAGE_INFO_SUBJECT, subject, TRUE);
+ e_poolv_set(mi->strings, CAMEL_MESSAGE_INFO_FROM, from, TRUE);
+ e_poolv_set(mi->strings, CAMEL_MESSAGE_INFO_TO, to, TRUE);
+ e_poolv_set(mi->strings, CAMEL_MESSAGE_INFO_CC, cc, TRUE);
+ e_poolv_set(mi->strings, CAMEL_MESSAGE_INFO_MLIST, mlist, TRUE);
+#elif defined (DOESTRV)
+ e_strv_set_ref_free(mi->strings, CAMEL_MESSAGE_INFO_SUBJECT, subject);
+ e_strv_set_ref_free(mi->strings, CAMEL_MESSAGE_INFO_FROM, from);
+ e_strv_set_ref_free(mi->strings, CAMEL_MESSAGE_INFO_TO, to);
+ e_strv_set_ref_free(mi->strings, CAMEL_MESSAGE_INFO_CC, cc);
+ e_strv_set_ref_free(mi->strings, CAMEL_MESSAGE_INFO_MLIST, mlist);
+#else
+ mi->subject = subject;
+ mi->from = from;
+ mi->to = to;
+ mi->cc = cc;
+ mi->mlist = mlist;
+#endif
+
+ mi->user_flags = NULL;
+ mi->user_tags = NULL;
+ mi->date_sent = camel_header_decode_date(camel_header_raw_find(&h, "date", NULL), NULL);
+ received = camel_header_raw_find(&h, "received", NULL);
+ if (received)
+ received = strrchr(received, ';');
+ if (received)
+ mi->date_received = camel_header_decode_date(received + 1, NULL);
+ else
+ mi->date_received = 0;
+
+ msgid = camel_header_msgid_decode(camel_header_raw_find(&h, "message-id", NULL));
+ if (msgid) {
+ md5_get_digest(msgid, strlen(msgid), digest);
+ memcpy(mi->message_id.id.hash, digest, sizeof(mi->message_id.id.hash));
+ g_free(msgid);
+ }
+
+ /* decode our references and in-reply-to headers */
+ refs = camel_header_references_decode (camel_header_raw_find (&h, "references", NULL));
+ irt = camel_header_references_inreplyto_decode (camel_header_raw_find (&h, "in-reply-to", NULL));
+ if (refs || irt) {
+ if (irt) {
+ /* The References field is populated from the ``References'' and/or ``In-Reply-To''
+ headers. If both headers exist, take the first thing in the In-Reply-To header
+ that looks like a Message-ID, and append it to the References header. */
+
+ if (refs)
+ irt->next = refs;
+
+ refs = irt;
+ }
+
+ count = camel_header_references_list_size(&refs);
+ mi->references = g_malloc(sizeof(*mi->references) + ((count-1) * sizeof(mi->references->references[0])));
+ count = 0;
+ scan = refs;
+ while (scan) {
+ md5_get_digest(scan->id, strlen(scan->id), digest);
+ memcpy(mi->references->references[count].id.hash, digest, sizeof(mi->message_id.id.hash));
+ count++;
+ scan = scan->next;
+ }
+ mi->references->size = count;
+ camel_header_references_list_clear(&refs);
+ }
+
+ return mi;
+}
+
+
+static CamelMessageInfo *
+message_info_load(CamelFolderSummary *s, FILE *in)
+{
+ CamelMessageInfo *mi;
+ guint count;
+ int i;
+ char *subject, *from, *to, *cc, *mlist, *uid;;
+
+ mi = camel_folder_summary_info_new(s);
+
+ io(printf("Loading message info\n"));
+
+ camel_file_util_decode_string(in, &uid);
+ camel_file_util_decode_uint32(in, &mi->flags);
+ camel_file_util_decode_uint32(in, &mi->size);
+ camel_file_util_decode_time_t(in, &mi->date_sent);
+ camel_file_util_decode_time_t(in, &mi->date_received);
+ camel_file_util_decode_string(in, &subject);
+ camel_file_util_decode_string(in, &from);
+ camel_file_util_decode_string(in, &to);
+ camel_file_util_decode_string(in, &cc);
+ camel_file_util_decode_string(in, &mlist);
+
+#ifdef DOEPOOLV
+ e_poolv_set(mi->strings, CAMEL_MESSAGE_INFO_UID, uid, TRUE);
+ e_poolv_set(mi->strings, CAMEL_MESSAGE_INFO_SUBJECT, subject, TRUE);
+ e_poolv_set(mi->strings, CAMEL_MESSAGE_INFO_FROM, from, TRUE);
+ e_poolv_set(mi->strings, CAMEL_MESSAGE_INFO_TO, to, TRUE);
+ e_poolv_set(mi->strings, CAMEL_MESSAGE_INFO_CC, cc, TRUE);
+ e_poolv_set(mi->strings, CAMEL_MESSAGE_INFO_MLIST, mlist, TRUE);
+#elif defined (DOESTRV)
+ e_strv_set_ref_free(mi->strings, CAMEL_MESSAGE_INFO_UID, uid);
+ e_strv_set_ref_free(mi->strings, CAMEL_MESSAGE_INFO_SUBJECT, subject);
+ e_strv_set_ref_free(mi->strings, CAMEL_MESSAGE_INFO_FROM, from);
+ e_strv_set_ref_free(mi->strings, CAMEL_MESSAGE_INFO_TO, to);
+ e_strv_set_ref_free(mi->strings, CAMEL_MESSAGE_INFO_CC, cc);
+ e_strv_set_ref_free(mi->strings, CAMEL_MESSAGE_INFO_MLIST, mlist);
+#else
+ mi->uid = uid;
+ mi->subject = subject;
+ mi->from = from;
+ mi->to = to;
+ mi->cc = cc;
+ mi->mlist = mlist;
+#endif
+
+ mi->content = NULL;
+
+ camel_file_util_decode_fixed_int32(in, &mi->message_id.id.part.hi);
+ camel_file_util_decode_fixed_int32(in, &mi->message_id.id.part.lo);
+
+ if (camel_file_util_decode_uint32(in, &count) == -1 || count > 500)
+ goto error;
+
+ if (count > 0) {
+ mi->references = g_malloc(sizeof(*mi->references) + ((count-1) * sizeof(mi->references->references[0])));
+ mi->references->size = count;
+ for (i=0;i<count;i++) {
+ camel_file_util_decode_fixed_int32(in, &mi->references->references[i].id.part.hi);
+ camel_file_util_decode_fixed_int32(in, &mi->references->references[i].id.part.lo);
+ }
+ }
+
+ if (camel_file_util_decode_uint32(in, &count) == -1 || count > 500)
+ goto error;
+
+ for (i=0;i<count;i++) {
+ char *name;
+ if (camel_file_util_decode_string(in, &name) == -1 || name == NULL)
+ goto error;
+ camel_flag_set(&mi->user_flags, name, TRUE);
+ g_free(name);
+ }
+
+ if (camel_file_util_decode_uint32(in, &count) == -1 || count > 500)
+ goto error;
+
+ for (i=0;i<count;i++) {
+ char *name, *value;
+ if (camel_file_util_decode_string(in, &name) == -1 || name == NULL
+ || camel_file_util_decode_string(in, &value) == -1)
+ goto error;
+ camel_tag_set(&mi->user_tags, name, value);
+ g_free(name);
+ g_free(value);
+ }
+
+ if (!ferror(in))
+ return mi;
+
+error:
+ camel_folder_summary_info_free(s, mi);
+
+ return NULL;
+}
+
+static int
+message_info_save(CamelFolderSummary *s, FILE *out, CamelMessageInfo *mi)
+{
+ guint32 count;
+ CamelFlag *flag;
+ CamelTag *tag;
+ int i;
+
+ io(printf("Saving message info\n"));
+
+ camel_file_util_encode_string(out, camel_message_info_uid(mi));
+ camel_file_util_encode_uint32(out, mi->flags);
+ camel_file_util_encode_uint32(out, mi->size);
+ camel_file_util_encode_time_t(out, mi->date_sent);
+ camel_file_util_encode_time_t(out, mi->date_received);
+ camel_file_util_encode_string(out, camel_message_info_subject(mi));
+ camel_file_util_encode_string(out, camel_message_info_from(mi));
+ camel_file_util_encode_string(out, camel_message_info_to(mi));
+ camel_file_util_encode_string(out, camel_message_info_cc(mi));
+ camel_file_util_encode_string(out, camel_message_info_mlist(mi));
+
+ camel_file_util_encode_fixed_int32(out, mi->message_id.id.part.hi);
+ camel_file_util_encode_fixed_int32(out, mi->message_id.id.part.lo);
+
+ if (mi->references) {
+ camel_file_util_encode_uint32(out, mi->references->size);
+ for (i=0;i<mi->references->size;i++) {
+ camel_file_util_encode_fixed_int32(out, mi->references->references[i].id.part.hi);
+ camel_file_util_encode_fixed_int32(out, mi->references->references[i].id.part.lo);
+ }
+ } else {
+ camel_file_util_encode_uint32(out, 0);
+ }
+
+ count = camel_flag_list_size(&mi->user_flags);
+ camel_file_util_encode_uint32(out, count);
+ flag = mi->user_flags;
+ while (flag) {
+ camel_file_util_encode_string(out, flag->name);
+ flag = flag->next;
+ }
+
+ count = camel_tag_list_size(&mi->user_tags);
+ camel_file_util_encode_uint32(out, count);
+ tag = mi->user_tags;
+ while (tag) {
+ camel_file_util_encode_string(out, tag->name);
+ camel_file_util_encode_string(out, tag->value);
+ tag = tag->next;
+ }
+
+ return ferror(out);
+}
+
+static void
+message_info_free(CamelFolderSummary *s, CamelMessageInfo *mi)
+{
+#ifdef DOEPOOLV
+ e_poolv_destroy(mi->strings);
+#elif defined (DOESTRV)
+ e_strv_destroy(mi->strings);
+#else
+ g_free(mi->uid);
+ g_free(mi->subject);
+ g_free(mi->from);
+ g_free(mi->to);
+ g_free(mi->cc);
+ g_free(mi->mlist);
+#endif
+ g_free(mi->references);
+ camel_flag_list_free(&mi->user_flags);
+ camel_tag_list_free(&mi->user_tags);
+ e_memchunk_free(s->message_info_chunks, mi);
+}
+
+static CamelMessageContentInfo *
+content_info_new (CamelFolderSummary *s, struct _camel_header_raw *h)
+{
+ CamelMessageContentInfo *ci;
+ const char *charset;
+
+ ci = camel_folder_summary_content_info_new (s);
+
+ charset = e_iconv_locale_charset ();
+ ci->id = camel_header_msgid_decode (camel_header_raw_find (&h, "content-id", NULL));
+ ci->description = camel_header_decode_string (camel_header_raw_find (&h, "content-description", NULL), NULL);
+ ci->encoding = camel_content_transfer_encoding_decode (camel_header_raw_find (&h, "content-transfer-encoding", NULL));
+ ci->type = camel_content_type_decode(camel_header_raw_find(&h, "content-type", NULL));
+
+ return ci;
+}
+
+static CamelMessageContentInfo *
+content_info_load(CamelFolderSummary *s, FILE *in)
+{
+ CamelMessageContentInfo *ci;
+ char *type, *subtype;
+ guint32 count, i;
+ CamelContentType *ct;
+
+ io(printf("Loading content info\n"));
+
+ ci = camel_folder_summary_content_info_new(s);
+
+ camel_folder_summary_decode_token(in, &type);
+ camel_folder_summary_decode_token(in, &subtype);
+ ct = camel_content_type_new(type, subtype);
+ g_free(type); /* can this be removed? */
+ g_free(subtype);
+ if (camel_file_util_decode_uint32(in, &count) == -1 || count > 500)
+ goto error;
+
+ for (i=0;i<count;i++) {
+ char *name, *value;
+ camel_folder_summary_decode_token(in, &name);
+ camel_folder_summary_decode_token(in, &value);
+ if (!(name && value))
+ goto error;
+
+ camel_content_type_set_param(ct, name, value);
+ /* TODO: do this so we dont have to double alloc/free */
+ g_free(name);
+ g_free(value);
+ }
+ ci->type = ct;
+
+ camel_folder_summary_decode_token(in, &ci->id);
+ camel_folder_summary_decode_token(in, &ci->description);
+ camel_folder_summary_decode_token(in, &ci->encoding);
+
+ camel_file_util_decode_uint32(in, &ci->size);
+
+ ci->childs = NULL;
+
+ if (!ferror(in))
+ return ci;
+
+ error:
+ camel_folder_summary_content_info_free(s, ci);
+ return NULL;
+}
+
+static int
+content_info_save(CamelFolderSummary *s, FILE *out, CamelMessageContentInfo *ci)
+{
+ CamelContentType *ct;
+ struct _camel_header_param *hp;
+
+ io(printf("Saving content info\n"));
+
+ ct = ci->type;
+ if (ct) {
+ camel_folder_summary_encode_token(out, ct->type);
+ camel_folder_summary_encode_token(out, ct->subtype);
+ camel_file_util_encode_uint32(out, my_list_size((struct _node **)&ct->params));
+ hp = ct->params;
+ while (hp) {
+ camel_folder_summary_encode_token(out, hp->name);
+ camel_folder_summary_encode_token(out, hp->value);
+ hp = hp->next;
+ }
+ } else {
+ camel_folder_summary_encode_token(out, NULL);
+ camel_folder_summary_encode_token(out, NULL);
+ camel_file_util_encode_uint32(out, 0);
+ }
+ camel_folder_summary_encode_token(out, ci->id);
+ camel_folder_summary_encode_token(out, ci->description);
+ camel_folder_summary_encode_token(out, ci->encoding);
+ return camel_file_util_encode_uint32(out, ci->size);
+}
+
+static void
+content_info_free(CamelFolderSummary *s, CamelMessageContentInfo *ci)
+{
+ camel_content_type_unref(ci->type);
+ g_free(ci->id);
+ g_free(ci->description);
+ g_free(ci->encoding);
+ e_memchunk_free(s->content_info_chunks, ci);
+}
+
+static char *
+next_uid_string(CamelFolderSummary *s)
+{
+ return g_strdup_printf("%u", camel_folder_summary_next_uid(s));
+}
+
+/*
+ OK
+ Now this is where all the "smarts" happen, where the content info is built,
+ and any indexing and what not is performed
+*/
+
+/* must have filter_lock before calling this function */
+static CamelMessageContentInfo *
+summary_build_content_info(CamelFolderSummary *s, CamelMessageInfo *msginfo, CamelMimeParser *mp)
+{
+ int state;
+ size_t len;
+ char *buffer;
+ CamelMessageContentInfo *info = NULL;
+ CamelContentType *ct;
+ int body;
+ int enc_id = -1, chr_id = -1, html_id = -1, idx_id = -1;
+ struct _CamelFolderSummaryPrivate *p = _PRIVATE(s);
+ CamelMimeFilterCharset *mfc;
+ CamelMessageContentInfo *part;
+
+ d(printf("building content info\n"));
+
+ /* start of this part */
+ state = camel_mime_parser_step(mp, &buffer, &len);
+ body = camel_mime_parser_tell(mp);
+
+ if (s->build_content)
+ info = ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->content_info_new_from_parser(s, mp);
+
+ switch(state) {
+ case CAMEL_MIME_PARSER_STATE_HEADER:
+ /* check content type for indexing, then read body */
+ ct = camel_mime_parser_content_type(mp);
+ /* update attachments flag as we go */
+ if (camel_content_type_is(ct, "application", "pgp-signature")
+#ifdef ENABLE_SMIME
+ || camel_content_type_is(ct, "application", "x-pkcs7-signature")
+ || camel_content_type_is(ct, "application", "pkcs7-signature")
+#endif
+ )
+ msginfo->flags |= CAMEL_MESSAGE_SECURE;
+
+ if (p->index && camel_content_type_is(ct, "text", "*")) {
+ char *encoding;
+ const char *charset;
+
+ d(printf("generating index:\n"));
+
+ encoding = camel_content_transfer_encoding_decode(camel_mime_parser_header(mp, "content-transfer-encoding", NULL));
+ if (encoding) {
+ if (!strcasecmp(encoding, "base64")) {
+ d(printf(" decoding base64\n"));
+ if (p->filter_64 == NULL)
+ p->filter_64 = camel_mime_filter_basic_new_type(CAMEL_MIME_FILTER_BASIC_BASE64_DEC);
+ else
+ camel_mime_filter_reset((CamelMimeFilter *)p->filter_64);
+ enc_id = camel_mime_parser_filter_add(mp, (CamelMimeFilter *)p->filter_64);
+ } else if (!g_ascii_strcasecmp(encoding, "quoted-printable")) {
+ d(printf(" decoding quoted-printable\n"));
+ if (p->filter_qp == NULL)
+ p->filter_qp = camel_mime_filter_basic_new_type(CAMEL_MIME_FILTER_BASIC_QP_DEC);
+ else
+ camel_mime_filter_reset((CamelMimeFilter *)p->filter_qp);
+ enc_id = camel_mime_parser_filter_add(mp, (CamelMimeFilter *)p->filter_qp);
+ } else if (!strcasecmp (encoding, "x-uuencode")) {
+ d(printf(" decoding x-uuencode\n"));
+ if (p->filter_uu == NULL)
+ p->filter_uu = camel_mime_filter_basic_new_type(CAMEL_MIME_FILTER_BASIC_UU_DEC);
+ else
+ camel_mime_filter_reset((CamelMimeFilter *)p->filter_uu);
+ enc_id = camel_mime_parser_filter_add(mp, (CamelMimeFilter *)p->filter_uu);
+ } else {
+ d(printf(" ignoring encoding %s\n", encoding));
+ }
+ g_free(encoding);
+ }
+
+ charset = camel_content_type_param(ct, "charset");
+ if (charset!=NULL
+ && !(g_ascii_strcasecmp(charset, "us-ascii")==0
+ || strcasecmp(charset, "utf-8")==0)) {
+ d(printf(" Adding conversion filter from %s to UTF-8\n", charset));
+ mfc = g_hash_table_lookup(p->filter_charset, charset);
+ if (mfc == NULL) {
+ mfc = camel_mime_filter_charset_new_convert(charset, "UTF-8");
+ if (mfc)
+ g_hash_table_insert(p->filter_charset, g_strdup(charset), mfc);
+ } else {
+ camel_mime_filter_reset((CamelMimeFilter *)mfc);
+ }
+ if (mfc) {
+ chr_id = camel_mime_parser_filter_add(mp, (CamelMimeFilter *)mfc);
+ } else {
+ g_warning("Cannot convert '%s' to 'UTF-8', message index may be corrupt", charset);
+ }
+ }
+
+ /* we do charset conversions before this filter, which isn't strictly correct,
+ but works in most cases */
+ if (camel_content_type_is(ct, "text", "html")) {
+ if (p->filter_html == NULL)
+ p->filter_html = camel_mime_filter_html_new();
+ else
+ camel_mime_filter_reset((CamelMimeFilter *)p->filter_html);
+ html_id = camel_mime_parser_filter_add(mp, (CamelMimeFilter *)p->filter_html);
+ }
+
+ /* and this filter actually does the indexing */
+ idx_id = camel_mime_parser_filter_add(mp, (CamelMimeFilter *)p->filter_index);
+ }
+ /* and scan/index everything */
+ while (camel_mime_parser_step(mp, &buffer, &len) != CAMEL_MIME_PARSER_STATE_BODY_END)
+ ;
+ /* and remove the filters */
+ camel_mime_parser_filter_remove(mp, enc_id);
+ camel_mime_parser_filter_remove(mp, chr_id);
+ camel_mime_parser_filter_remove(mp, html_id);
+ camel_mime_parser_filter_remove(mp, idx_id);
+ break;
+ case CAMEL_MIME_PARSER_STATE_MULTIPART:
+ d(printf("Summarising multipart\n"));
+ /* update attachments flag as we go */
+ ct = camel_mime_parser_content_type(mp);
+ if (camel_content_type_is(ct, "multipart", "mixed"))
+ msginfo->flags |= CAMEL_MESSAGE_ATTACHMENTS;
+ if (camel_content_type_is(ct, "multipart", "signed")
+ || camel_content_type_is(ct, "multipart", "encrypted"))
+ msginfo->flags |= CAMEL_MESSAGE_SECURE;
+
+ while (camel_mime_parser_step(mp, &buffer, &len) != CAMEL_MIME_PARSER_STATE_MULTIPART_END) {
+ camel_mime_parser_unstep(mp);
+ part = summary_build_content_info(s, msginfo, mp);
+ if (part) {
+ part->parent = info;
+ my_list_append((struct _node **)&info->childs, (struct _node *)part);
+ }
+ }
+ break;
+ case CAMEL_MIME_PARSER_STATE_MESSAGE:
+ d(printf("Summarising message\n"));
+ /* update attachments flag as we go */
+ msginfo->flags |= CAMEL_MESSAGE_ATTACHMENTS;
+
+ part = summary_build_content_info(s, msginfo, mp);
+ if (part) {
+ part->parent = info;
+ my_list_append((struct _node **)&info->childs, (struct _node *)part);
+ }
+ state = camel_mime_parser_step(mp, &buffer, &len);
+ if (state != CAMEL_MIME_PARSER_STATE_MESSAGE_END) {
+ g_error("Bad parser state: Expecing MESSAGE_END or MESSAGE_EOF, got: %d", state);
+ camel_mime_parser_unstep(mp);
+ }
+ break;
+ }
+
+ d(printf("finished building content info\n"));
+
+ return info;
+}
+
+/* build the content-info, from a message */
+/* this needs the filter lock since it uses filters to perform indexing */
+static CamelMessageContentInfo *
+summary_build_content_info_message(CamelFolderSummary *s, CamelMessageInfo *msginfo, CamelMimePart *object)
+{
+ CamelDataWrapper *containee;
+ int parts, i;
+ struct _CamelFolderSummaryPrivate *p = _PRIVATE(s);
+ CamelMessageContentInfo *info = NULL, *child;
+ CamelContentType *ct;
+
+ if (s->build_content)
+ info = ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->content_info_new_from_message(s, object);
+
+ containee = camel_medium_get_content_object(CAMEL_MEDIUM(object));
+
+ if (containee == NULL)
+ return info;
+
+ /* TODO: I find it odd that get_part and get_content_object do not
+ add a reference, probably need fixing for multithreading */
+
+ /* check for attachments */
+ ct = ((CamelDataWrapper *)containee)->mime_type;
+ if (camel_content_type_is(ct, "multipart", "*")) {
+ if (camel_content_type_is(ct, "multipart", "mixed"))
+ msginfo->flags |= CAMEL_MESSAGE_ATTACHMENTS;
+ if (camel_content_type_is(ct, "multipart", "signed")
+ || camel_content_type_is(ct, "multipart", "encrypted"))
+ msginfo->flags |= CAMEL_MESSAGE_SECURE;
+ } else if (camel_content_type_is(ct, "application", "pgp-signature")
+#ifdef ENABLE_SMIME
+ || camel_content_type_is(ct, "application", "x-pkcs7-signature")
+ || camel_content_type_is(ct, "application", "pkcs7-signature")
+#endif
+ ) {
+ msginfo->flags |= CAMEL_MESSAGE_SECURE;
+ }
+
+ /* using the object types is more accurate than using the mime/types */
+ if (CAMEL_IS_MULTIPART(containee)) {
+ parts = camel_multipart_get_number(CAMEL_MULTIPART(containee));
+ for (i=0;i<parts;i++) {
+ CamelMimePart *part = camel_multipart_get_part(CAMEL_MULTIPART(containee), i);
+ g_assert(part);
+ child = summary_build_content_info_message(s, msginfo, part);
+ if (child) {
+ child->parent = info;
+ my_list_append((struct _node **)&info->childs, (struct _node *)child);
+ }
+ }
+ } else if (CAMEL_IS_MIME_MESSAGE(containee)) {
+ /* for messages we only look at its contents */
+ child = summary_build_content_info_message(s, msginfo, (CamelMimePart *)containee);
+ if (child) {
+ child->parent = info;
+ my_list_append((struct _node **)&info->childs, (struct _node *)child);
+ }
+ } else if (p->filter_stream
+ && camel_content_type_is(ct, "text", "*")) {
+ int html_id = -1, idx_id = -1;
+
+ /* pre-attach html filter if required, otherwise just index filter */
+ if (camel_content_type_is(ct, "text", "html")) {
+ if (p->filter_html == NULL)
+ p->filter_html = camel_mime_filter_html_new();
+ else
+ camel_mime_filter_reset((CamelMimeFilter *)p->filter_html);
+ html_id = camel_stream_filter_add(p->filter_stream, (CamelMimeFilter *)p->filter_html);
+ }
+ idx_id = camel_stream_filter_add(p->filter_stream, (CamelMimeFilter *)p->filter_index);
+
+ camel_data_wrapper_decode_to_stream(containee, (CamelStream *)p->filter_stream);
+ camel_stream_flush((CamelStream *)p->filter_stream);
+
+ camel_stream_filter_remove(p->filter_stream, idx_id);
+ camel_stream_filter_remove(p->filter_stream, html_id);
+ }
+
+ return info;
+}
+
+/**
+ * camel_flag_get:
+ * @list:
+ * @name:
+ *
+ * Find the state of the flag @name in @list.
+ *
+ * Return value: The state of the flag (TRUE or FALSE).
+ **/
+gboolean
+camel_flag_get(CamelFlag **list, const char *name)
+{
+ CamelFlag *flag;
+ flag = *list;
+ while (flag) {
+ if (!strcmp(flag->name, name))
+ return TRUE;
+ flag = flag->next;
+ }
+ return FALSE;
+}
+
+/**
+ * camel_flag_set:
+ * @list:
+ * @name:
+ * @value:
+ *
+ * Set the state of a flag @name in the list @list to @value.
+ *
+ * Return value: Whether or not it changed.
+ **/
+gboolean
+camel_flag_set(CamelFlag **list, const char *name, gboolean value)
+{
+ CamelFlag *flag, *tmp;
+
+ /* this 'trick' works because flag->next is the first element */
+ flag = (CamelFlag *)list;
+ while (flag->next) {
+ tmp = flag->next;
+ if (!strcmp(flag->next->name, name)) {
+ if (!value) {
+ flag->next = tmp->next;
+ g_free(tmp);
+ }
+ return !value;
+ }
+ flag = tmp;
+ }
+
+ if (value) {
+ tmp = g_malloc(sizeof(*tmp) + strlen(name));
+ strcpy(tmp->name, name);
+ tmp->next = 0;
+ flag->next = tmp;
+ }
+ return value;
+}
+
+/**
+ * camel_flag_list_size:
+ * @list:
+ *
+ * Get the length of the flag list.
+ *
+ * Return value: The number of TRUE flags in the list.
+ **/
+int
+camel_flag_list_size(CamelFlag **list)
+{
+ int count=0;
+ CamelFlag *flag;
+
+ flag = *list;
+ while (flag) {
+ count++;
+ flag = flag->next;
+ }
+ return count;
+}
+
+/**
+ * camel_flag_list_free:
+ * @list:
+ *
+ * Free the memory associated with the flag list @list.
+ **/
+void
+camel_flag_list_free(CamelFlag **list)
+{
+ CamelFlag *flag, *tmp;
+ flag = *list;
+ while (flag) {
+ tmp = flag->next;
+ g_free(flag);
+ flag = tmp;
+ }
+ *list = NULL;
+}
+
+/**
+ * camel_flag_list_copy:
+ * @to:
+ * @from:
+ *
+ * Copy a flag list, return true if the destination list @to changed.
+ *
+ * Return value:
+ **/
+gboolean
+camel_flag_list_copy(CamelFlag **to, CamelFlag **from)
+{
+ CamelFlag *flag, *tmp;
+ int changed = FALSE;
+
+ if (*to == NULL && from == NULL)
+ return FALSE;
+
+ /* Remove any now-missing flags */
+ flag = (CamelFlag *)to;
+ while (flag->next) {
+ tmp = flag->next;
+ if (!camel_flag_get(from, tmp->name)) {
+ flag->next = tmp->next;
+ g_free(tmp);
+ changed = TRUE;
+ } else {
+ flag = tmp;
+ }
+ }
+
+ /* Add any new flags */
+ flag = *from;
+ while (flag) {
+ changed |= camel_flag_set(to, flag->name, TRUE);
+ flag = flag->next;
+ }
+
+ return changed;
+}
+
+const char *
+camel_tag_get(CamelTag **list, const char *name)
+{
+ CamelTag *tag;
+
+ tag = *list;
+ while (tag) {
+ if (!strcmp(tag->name, name))
+ return (const char *)tag->value;
+ tag = tag->next;
+ }
+ return NULL;
+}
+
+/**
+ * camel_tag_set:
+ * @list:
+ * @name:
+ * @value:
+ *
+ * Set the tag @name in the tag list @list to @value.
+ *
+ * Return value: whether or not it changed
+ **/
+gboolean
+camel_tag_set(CamelTag **list, const char *name, const char *value)
+{
+ CamelTag *tag, *tmp;
+
+ /* this 'trick' works because tag->next is the first element */
+ tag = (CamelTag *)list;
+ while (tag->next) {
+ tmp = tag->next;
+ if (!strcmp(tmp->name, name)) {
+ if (value == NULL) { /* clear it? */
+ tag->next = tmp->next;
+ g_free(tmp->value);
+ g_free(tmp);
+ return TRUE;
+ } else if (strcmp(tmp->value, value)) { /* has it changed? */
+ g_free(tmp->value);
+ tmp->value = g_strdup(value);
+ return TRUE;
+ }
+ return FALSE;
+ }
+ tag = tmp;
+ }
+
+ if (value) {
+ tmp = g_malloc(sizeof(*tmp)+strlen(name));
+ strcpy(tmp->name, name);
+ tmp->value = g_strdup(value);
+ tmp->next = 0;
+ tag->next = tmp;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * camel_tag_list_size:
+ * @list:
+ *
+ * Get the number of tags present in the tag list @list.
+ *
+ * Return value: The number of tags.
+ **/
+int camel_tag_list_size(CamelTag **list)
+{
+ int count=0;
+ CamelTag *tag;
+
+ tag = *list;
+ while (tag) {
+ count++;
+ tag = tag->next;
+ }
+ return count;
+}
+
+static void
+rem_tag(char *key, char *value, CamelTag **to)
+{
+ camel_tag_set(to, key, NULL);
+}
+
+/**
+ * camel_tag_list_copy:
+ * @to:
+ * @from:
+ *
+ * Copy a list of tags.
+ *
+ * Return value:
+ **/
+gboolean
+camel_tag_list_copy(CamelTag **to, CamelTag **from)
+{
+ int changed = FALSE;
+ CamelTag *tag;
+ GHashTable *left;
+
+ if (*to == NULL && from == NULL)
+ return FALSE;
+
+ left = g_hash_table_new(g_str_hash, g_str_equal);
+ tag = *to;
+ while (tag) {
+ g_hash_table_insert(left, tag->name, tag);
+ tag = tag->next;
+ }
+
+ tag = *from;
+ while (tag) {
+ changed |= camel_tag_set(to, tag->name, tag->value);
+ g_hash_table_remove(left, tag->name);
+ tag = tag->next;
+ }
+
+ if (g_hash_table_size(left)>0) {
+ g_hash_table_foreach(left, (GHFunc)rem_tag, to);
+ changed = TRUE;
+ }
+ g_hash_table_destroy(left);
+
+ return changed;
+}
+
+/**
+ * camel_tag_list_free:
+ * @list:
+ *
+ * Free the tag list @list.
+ **/
+void camel_tag_list_free(CamelTag **list)
+{
+ CamelTag *tag, *tmp;
+ tag = *list;
+ while (tag) {
+ tmp = tag->next;
+ g_free(tag->value);
+ g_free(tag);
+ tag = tmp;
+ }
+ *list = NULL;
+}
+
+struct flag_names_t {
+ char *name;
+ guint32 value;
+} flag_names[] = {
+ { "answered", CAMEL_MESSAGE_ANSWERED },
+ { "deleted", CAMEL_MESSAGE_DELETED },
+ { "draft", CAMEL_MESSAGE_DELETED },
+ { "flagged", CAMEL_MESSAGE_FLAGGED },
+ { "seen", CAMEL_MESSAGE_SEEN },
+ { "attachments", CAMEL_MESSAGE_ATTACHMENTS },
+ { "junk", CAMEL_MESSAGE_JUNK },
+ { "secure", CAMEL_MESSAGE_SECURE },
+ { NULL, 0 }
+};
+
+/**
+ * camel_system_flag:
+ * @name:
+ *
+ * Returns the integer value of the flag string.
+ **/
+guint32
+camel_system_flag (const char *name)
+{
+ struct flag_names_t *flag;
+
+ g_return_val_if_fail (name != NULL, 0);
+
+ for (flag = flag_names; *flag->name; flag++)
+ if (!g_ascii_strcasecmp (name, flag->name))
+ return flag->value;
+
+ return 0;
+}
+
+/**
+ * camel_system_flag_get:
+ * @flags:
+ * @name:
+ *
+ * Find the state of the flag @name in @flags.
+ *
+ * Return value: The state of the flag (TRUE or FALSE).
+ **/
+gboolean
+camel_system_flag_get (guint32 flags, const char *name)
+{
+ g_return_val_if_fail (name != NULL, FALSE);
+
+ return flags & camel_system_flag (name);
+}
+
+
+/**
+ * camel_message_info_new:
+ *
+ * Returns a new CamelMessageInfo structure.
+ **/
+CamelMessageInfo *
+camel_message_info_new (void)
+{
+ CamelMessageInfo *info;
+
+ info = g_malloc0(sizeof(*info));
+#ifdef DOEPOOLV
+ info->strings = e_poolv_new(CAMEL_MESSAGE_INFO_LAST);
+#endif
+#ifdef DOESTRV
+ info->strings = e_strv_new (CAMEL_MESSAGE_INFO_LAST);
+#endif
+ info->refcount = 1;
+
+ return info;
+}
+
+/**
+ * camel_message_info_ref:
+ * @info:
+ *
+ * Reference an info.
+ *
+ * NOTE: This interface is not MT-SAFE, like the others.
+ **/
+void camel_message_info_ref(CamelMessageInfo *info)
+{
+ GLOBAL_INFO_LOCK(info);
+ info->refcount++;
+ GLOBAL_INFO_UNLOCK(info);
+}
+
+/**
+ * camel_message_info_new_from_header:
+ * @header: raw header
+ *
+ * Returns a new CamelMessageInfo structure populated by the header.
+ **/
+CamelMessageInfo *
+camel_message_info_new_from_header (struct _camel_header_raw *header)
+{
+ CamelMessageInfo *info;
+ char *subject, *from, *to, *cc, *mlist;
+ CamelContentType *ct = NULL;
+ const char *content, *date, *charset = NULL;
+
+ if ((content = camel_header_raw_find(&header, "Content-Type", NULL))
+ && (ct = camel_content_type_decode(content))
+ && (charset = camel_content_type_param(ct, "charset"))
+ && (g_ascii_strcasecmp(charset, "us-ascii") == 0))
+ charset = NULL;
+
+ charset = charset ? e_iconv_charset_name (charset) : NULL;
+
+ subject = summary_format_string(header, "subject", charset);
+ from = summary_format_address(header, "from", charset);
+ to = summary_format_address(header, "to", charset);
+ cc = summary_format_address(header, "cc", charset);
+ date = camel_header_raw_find(&header, "date", NULL);
+ mlist = camel_header_raw_check_mailing_list(&header);
+
+ if (ct)
+ camel_content_type_unref(ct);
+
+ info = camel_message_info_new();
+
+ camel_message_info_set_subject(info, subject);
+ camel_message_info_set_from(info, from);
+ camel_message_info_set_to(info, to);
+ camel_message_info_set_cc(info, cc);
+ camel_message_info_set_mlist(info, mlist);
+
+ if (date)
+ info->date_sent = camel_header_decode_date (date, NULL);
+ else
+ info->date_sent = time (NULL);
+
+ date = camel_header_raw_find (&header, "received", NULL);
+ if (date && (date = strrchr (date, ';')))
+ date++;
+
+ if (date)
+ info->date_received = camel_header_decode_date (date, NULL);
+ else
+ info->date_received = time (NULL);
+
+ return info;
+}
+
+/**
+ * camel_message_info_dup_to:
+ * @from: source message info
+ * @to: destination message info
+ *
+ * Duplicates the contents of one CamelMessageInfo structure into another.
+ * (The destination is assumed to be empty: its contents are not freed.)
+ * The slightly odd interface is to allow this to be used to initialize
+ * "subclasses" of CamelMessageInfo.
+ **/
+void
+camel_message_info_dup_to(const CamelMessageInfo *from, CamelMessageInfo *to)
+{
+ CamelFlag *flag;
+ CamelTag *tag;
+
+ /* Copy numbers */
+ to->flags = from->flags;
+ to->size = from->size;
+ to->date_sent = from->date_sent;
+ to->date_received = from->date_received;
+ to->refcount = 1;
+
+ /* Copy strings */
+#ifdef DOEPOOLV
+ to->strings = e_poolv_cpy (to->strings, from->strings);
+#elif defined (DOESTRV)
+ /* to->strings = e_strv_new(CAMEL_MESSAGE_INFO_LAST); */
+ e_strv_set(to->strings, CAMEL_MESSAGE_INFO_SUBJECT, camel_message_info_subject(from));
+ e_strv_set(to->strings, CAMEL_MESSAGE_INFO_FROM, camel_message_info_from(from));
+ e_strv_set(to->strings, CAMEL_MESSAGE_INFO_TO, camel_message_info_to(from));
+ e_strv_set(to->strings, CAMEL_MESSAGE_INFO_CC, camel_message_info_cc(from));
+ e_strv_set(to->strings, CAMEL_MESSAGE_INFO_UID, camel_message_info_uid(from));
+ e_strv_set(to->strings, CAMEL_MESSAGE_INFO_UID, camel_message_info_mlist(from));
+#else
+ to->subject = g_strdup(from->subject);
+ to->from = g_strdup(from->from);
+ to->to = g_strdup(from->to);
+ to->cc = g_strdup(from->cc);
+ to->uid = g_strdup(from->uid);
+ to->mlist = g_strdup(from->mlist);
+#endif
+ memcpy(&to->message_id, &from->message_id, sizeof(from->message_id));
+
+ /* Copy structures */
+ if (from->references) {
+ int len = sizeof(*from->references) + ((from->references->size-1) * sizeof(from->references->references[0]));
+
+ to->references = g_malloc(len);
+ memcpy(to->references, from->references, len);
+ } else {
+ to->references = NULL;
+ }
+
+ flag = from->user_flags;
+ while (flag) {
+ camel_flag_set(&to->user_flags, flag->name, TRUE);
+ flag = flag->next;
+ }
+
+ tag = from->user_tags;
+ while (tag) {
+ camel_tag_set(&to->user_tags, tag->name, tag->value);
+ tag = tag->next;
+ }
+
+ /* No, this is impossible without knowing the class of summary we came from */
+ /* FIXME some day */
+ to->content = NULL;
+}
+
+/**
+ * camel_message_info_free:
+ * @mi: the message info
+ *
+ * Unref's and potentially frees a CamelMessageInfo and its contents.
+ *
+ * Can only be used to free CamelMessageInfo's created with
+ * camel_message_info_dup_to.
+ *
+ * NOTE: This interface is not MT-SAFE, like the others.
+ *
+ **/
+void
+camel_message_info_free(CamelMessageInfo *mi)
+{
+ g_return_if_fail(mi != NULL);
+
+ GLOBAL_INFO_LOCK(info);
+ mi->refcount--;
+ if (mi->refcount > 0) {
+ GLOBAL_INFO_UNLOCK(info);
+ return;
+ }
+ GLOBAL_INFO_UNLOCK(info);
+
+#ifdef DOEPOOLV
+ e_poolv_destroy(mi->strings);
+#elif defined (DOESTRV)
+ e_strv_destroy(mi->strings);
+#else
+ g_free(mi->uid);
+ g_free(mi->subject);
+ g_free(mi->from);
+ g_free(mi->to);
+ g_free(mi->cc);
+ g_free(mi->mlist);
+#endif
+ g_free(mi->references);
+ camel_flag_list_free(&mi->user_flags);
+ camel_tag_list_free(&mi->user_tags);
+ /* FIXME: content info? */
+ g_free(mi);
+}
+
+#if defined (DOEPOOLV) || defined (DOESTRV)
+const char *
+camel_message_info_string (const CamelMessageInfo *mi, int type)
+{
+ g_assert (mi != NULL);
+
+ if (mi->strings == NULL)
+ return "";
+#ifdef DOEPOOLV
+ return e_poolv_get (mi->strings, type);
+#else
+ return e_strv_get (mi->strings, type);
+#endif
+}
+
+void
+camel_message_info_set_string (CamelMessageInfo *mi, int type, char *str)
+{
+ g_assert (mi != NULL);
+ g_assert (mi->strings != NULL);
+#ifdef DOEPOOLV
+ e_poolv_set (mi->strings, type, str, TRUE);
+#else
+ mi->strings = e_strv_set_ref_free (mi->strings, type, str);
+#endif
+}
+#endif
+
+
+void
+camel_content_info_dump (CamelMessageContentInfo *ci, int depth)
+{
+ char *p;
+
+ p = alloca (depth * 4 + 1);
+ memset (p, ' ', depth * 4);
+ p[depth * 4] = 0;
+
+ if (ci == NULL) {
+ printf ("%s<empty>\n", p);
+ return;
+ }
+
+ if (ci->type)
+ printf ("%scontent-type: %s/%s\n", p, ci->type->type ? ci->type->type : "(null)",
+ ci->type->subtype ? ci->type->subtype : "(null)");
+ else
+ printf ("%scontent-type: <unset>\n", p);
+ printf ("%scontent-transfer-encoding: %s\n", p, ci->encoding ? ci->encoding : "(null)");
+ printf ("%scontent-description: %s\n", p, ci->description ? ci->description : "(null)");
+ printf ("%ssize: %lu\n", p, (unsigned long) ci->size);
+ ci = ci->childs;
+ while (ci) {
+ camel_content_info_dump (ci, depth + 1);
+ ci = ci->next;
+ }
+}
+
+void
+camel_message_info_dump (CamelMessageInfo *mi)
+{
+ if (mi == NULL) {
+ printf("No message?\n");
+ return;
+ }
+
+ printf("Subject: %s\n", camel_message_info_subject(mi));
+ printf("To: %s\n", camel_message_info_to(mi));
+ printf("Cc: %s\n", camel_message_info_cc(mi));
+ printf("mailing list: %s\n", camel_message_info_mlist(mi));
+ printf("From: %s\n", camel_message_info_from(mi));
+ printf("UID: %s\n", camel_message_info_uid(mi));
+ printf("Flags: %04x\n", mi->flags & 0xffff);
+ camel_content_info_dump(mi->content, 0);
+}
diff --git a/camel/camel-gpg-context.c b/camel/camel-gpg-context.c
new file mode 100644
index 0000000000..acd00494ae
--- /dev/null
+++ b/camel/camel-gpg-context.c
@@ -0,0 +1,1817 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Jeffrey Stedfast <fejj@ximian.com>
+ *
+ * Copyright 2002 Ximian, Inc. (www.ximian.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+/* Debug states:
+ gpg:sign dump canonicalised to-be-signed data to a file
+ gpg:verify dump canonicalised verification and signature data to file
+ gpg:status print gpg status-fd output to stdout
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/poll.h>
+#include <termios.h>
+#include <signal.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "gal/util/e-iconv.h"
+
+#include "camel-gpg-context.h"
+#include "camel-mime-filter-charset.h"
+#include "camel-stream-filter.h"
+#include "camel-stream-mem.h"
+#include "camel-stream-fs.h"
+#include "camel-operation.h"
+#include "camel-mime-part.h"
+#include "camel-mime-filter-canon.h"
+
+#include "camel-multipart-signed.h"
+#include "camel-multipart-encrypted.h"
+
+#define d(x)
+
+#define GPG_LOG
+
+#ifdef GPG_LOG
+#include "camel-debug.h"
+static int logid;
+#endif
+
+static CamelCipherContextClass *parent_class = NULL;
+
+/**
+ * camel_gpg_context_new:
+ * @session: session
+ *
+ * Creates a new gpg cipher context object.
+ *
+ * Returns a new gpg cipher context object.
+ **/
+CamelCipherContext *
+camel_gpg_context_new (CamelSession *session)
+{
+ CamelCipherContext *cipher;
+ CamelGpgContext *ctx;
+
+ g_return_val_if_fail (CAMEL_IS_SESSION (session), NULL);
+
+ ctx = (CamelGpgContext *) camel_object_new (camel_gpg_context_get_type ());
+
+ cipher = (CamelCipherContext *) ctx;
+ cipher->session = session;
+ camel_object_ref (session);
+
+ return cipher;
+}
+
+
+/**
+ * camel_gpg_context_set_always_trust:
+ * @ctx: gpg context
+ * @always_trust always truct flag
+ *
+ * Sets the @always_trust flag on the gpg context which is used for
+ * encryption.
+ **/
+void
+camel_gpg_context_set_always_trust (CamelGpgContext *ctx, gboolean always_trust)
+{
+ g_return_if_fail (CAMEL_IS_GPG_CONTEXT (ctx));
+
+ ctx->always_trust = always_trust;
+}
+
+
+static const char *
+gpg_hash_to_id (CamelCipherContext *context, CamelCipherHash hash)
+{
+ switch (hash) {
+ case CAMEL_CIPHER_HASH_MD2:
+ return "pgp-md2";
+ case CAMEL_CIPHER_HASH_MD5:
+ return "pgp-md5";
+ case CAMEL_CIPHER_HASH_SHA1:
+ case CAMEL_CIPHER_HASH_DEFAULT:
+ return "pgp-sha1";
+ case CAMEL_CIPHER_HASH_RIPEMD160:
+ return "pgp-ripemd160";
+ case CAMEL_CIPHER_HASH_TIGER192:
+ return "pgp-tiger192";
+ case CAMEL_CIPHER_HASH_HAVAL5160:
+ return "pgp-haval-5-160";
+ }
+
+ return NULL;
+}
+
+static CamelCipherHash
+gpg_id_to_hash (CamelCipherContext *context, const char *id)
+{
+ if (id) {
+ if (!strcmp (id, "pgp-md2"))
+ return CAMEL_CIPHER_HASH_MD2;
+ else if (!strcmp (id, "pgp-md5"))
+ return CAMEL_CIPHER_HASH_MD5;
+ else if (!strcmp (id, "pgp-sha1"))
+ return CAMEL_CIPHER_HASH_SHA1;
+ else if (!strcmp (id, "pgp-ripemd160"))
+ return CAMEL_CIPHER_HASH_RIPEMD160;
+ else if (!strcmp (id, "tiger192"))
+ return CAMEL_CIPHER_HASH_TIGER192;
+ else if (!strcmp (id, "haval-5-160"))
+ return CAMEL_CIPHER_HASH_HAVAL5160;
+ }
+
+ return CAMEL_CIPHER_HASH_DEFAULT;
+}
+
+
+enum _GpgCtxMode {
+ GPG_CTX_MODE_SIGN,
+ GPG_CTX_MODE_VERIFY,
+ GPG_CTX_MODE_ENCRYPT,
+ GPG_CTX_MODE_DECRYPT,
+ GPG_CTX_MODE_IMPORT,
+ GPG_CTX_MODE_EXPORT,
+};
+
+enum _GpgTrustMetric {
+ GPG_TRUST_NONE,
+ GPG_TRUST_NEVER,
+ GPG_TRUST_UNDEFINED,
+ GPG_TRUST_MARGINAL,
+ GPG_TRUST_FULLY,
+ GPG_TRUST_ULTIMATE
+};
+
+struct _GpgCtx {
+ enum _GpgCtxMode mode;
+ CamelSession *session;
+ GHashTable *userid_hint;
+ pid_t pid;
+
+ char *userid;
+ char *sigfile;
+ GPtrArray *recipients;
+ CamelCipherHash hash;
+
+ int stdin_fd;
+ int stdout_fd;
+ int stderr_fd;
+ int status_fd;
+ int passwd_fd; /* only needed for sign/decrypt */
+
+ /* status-fd buffer */
+ unsigned char *statusbuf;
+ unsigned char *statusptr;
+ unsigned int statusleft;
+
+ char *need_id;
+ char *passwd;
+
+ CamelStream *istream;
+ CamelStream *ostream;
+
+ GByteArray *diagbuf;
+ CamelStream *diagnostics;
+
+ int exit_status;
+
+ unsigned int exited:1;
+ unsigned int complete:1;
+ unsigned int seen_eof1:1;
+ unsigned int seen_eof2:1;
+ unsigned int always_trust:1;
+ unsigned int armor:1;
+ unsigned int need_passwd:1;
+ unsigned int send_passwd:1;
+
+ unsigned int bad_passwds:2;
+
+ unsigned int hadsig:1;
+ unsigned int badsig:1;
+ unsigned int errsig:1;
+ unsigned int goodsig:1;
+ unsigned int validsig:1;
+ unsigned int nopubkey:1;
+ unsigned int nodata:1;
+ unsigned int trust:3;
+
+ unsigned int diagflushed:1;
+
+ unsigned int utf8:1;
+
+ unsigned int padding:10;
+};
+
+static struct _GpgCtx *
+gpg_ctx_new (CamelSession *session)
+{
+ struct _GpgCtx *gpg;
+ const char *charset;
+ CamelStream *stream;
+
+ gpg = g_new (struct _GpgCtx, 1);
+ gpg->mode = GPG_CTX_MODE_SIGN;
+ gpg->session = session;
+ camel_object_ref (session);
+ gpg->userid_hint = g_hash_table_new (g_str_hash, g_str_equal);
+ gpg->complete = FALSE;
+ gpg->seen_eof1 = TRUE;
+ gpg->seen_eof2 = FALSE;
+ gpg->pid = (pid_t) -1;
+ gpg->exit_status = 0;
+ gpg->exited = FALSE;
+
+ gpg->userid = NULL;
+ gpg->sigfile = NULL;
+ gpg->recipients = NULL;
+ gpg->hash = CAMEL_CIPHER_HASH_DEFAULT;
+ gpg->always_trust = FALSE;
+ gpg->armor = FALSE;
+
+ gpg->stdin_fd = -1;
+ gpg->stdout_fd = -1;
+ gpg->stderr_fd = -1;
+ gpg->status_fd = -1;
+ gpg->passwd_fd = -1;
+
+ gpg->statusbuf = g_malloc (128);
+ gpg->statusptr = gpg->statusbuf;
+ gpg->statusleft = 128;
+
+ gpg->bad_passwds = 0;
+ gpg->need_passwd = FALSE;
+ gpg->send_passwd = FALSE;
+ gpg->need_id = NULL;
+ gpg->passwd = NULL;
+
+ gpg->nodata = FALSE;
+ gpg->hadsig = FALSE;
+ gpg->badsig = FALSE;
+ gpg->errsig = FALSE;
+ gpg->goodsig = FALSE;
+ gpg->validsig = FALSE;
+ gpg->nopubkey = FALSE;
+ gpg->trust = GPG_TRUST_NONE;
+
+ gpg->istream = NULL;
+ gpg->ostream = NULL;
+
+ stream = camel_stream_mem_new ();
+ gpg->diagbuf = CAMEL_STREAM_MEM (stream)->buffer;
+ gpg->diagflushed = FALSE;
+
+ if ((charset = e_iconv_locale_charset ()) && strcasecmp (charset, "UTF-8") != 0) {
+ CamelMimeFilterCharset *filter;
+ CamelStreamFilter *fstream;
+
+ gpg->utf8 = FALSE;
+
+ if ((filter = camel_mime_filter_charset_new_convert (charset, "UTF-8"))) {
+ fstream = camel_stream_filter_new_with_stream (stream);
+ camel_stream_filter_add (fstream, (CamelMimeFilter *) filter);
+ camel_object_unref (filter);
+ camel_object_unref (stream);
+
+ stream = (CamelStream *) fstream;
+ }
+ } else {
+ gpg->utf8 = TRUE;
+ }
+
+ gpg->diagnostics = stream;
+
+ return gpg;
+}
+
+static void
+gpg_ctx_set_mode (struct _GpgCtx *gpg, enum _GpgCtxMode mode)
+{
+ gpg->mode = mode;
+ gpg->need_passwd = ((gpg->mode == GPG_CTX_MODE_SIGN) || (gpg->mode == GPG_CTX_MODE_DECRYPT));
+}
+
+static void
+gpg_ctx_set_hash (struct _GpgCtx *gpg, CamelCipherHash hash)
+{
+ gpg->hash = hash;
+}
+
+static void
+gpg_ctx_set_always_trust (struct _GpgCtx *gpg, gboolean trust)
+{
+ gpg->always_trust = trust;
+}
+
+static void
+gpg_ctx_set_userid (struct _GpgCtx *gpg, const char *userid)
+{
+ g_free (gpg->userid);
+ gpg->userid = g_strdup (userid);
+}
+
+static void
+gpg_ctx_add_recipient (struct _GpgCtx *gpg, const char *keyid)
+{
+ if (gpg->mode != GPG_CTX_MODE_ENCRYPT && gpg->mode != GPG_CTX_MODE_EXPORT)
+ return;
+
+ if (!gpg->recipients)
+ gpg->recipients = g_ptr_array_new ();
+
+ g_ptr_array_add (gpg->recipients, g_strdup (keyid));
+}
+
+static void
+gpg_ctx_set_sigfile (struct _GpgCtx *gpg, const char *sigfile)
+{
+ g_free (gpg->sigfile);
+ gpg->sigfile = g_strdup (sigfile);
+}
+
+static void
+gpg_ctx_set_armor (struct _GpgCtx *gpg, gboolean armor)
+{
+ gpg->armor = armor;
+}
+
+static void
+gpg_ctx_set_istream (struct _GpgCtx *gpg, CamelStream *istream)
+{
+ camel_object_ref (istream);
+ if (gpg->istream)
+ camel_object_unref (gpg->istream);
+ gpg->istream = istream;
+}
+
+static void
+gpg_ctx_set_ostream (struct _GpgCtx *gpg, CamelStream *ostream)
+{
+ camel_object_ref (ostream);
+ if (gpg->ostream)
+ camel_object_unref (gpg->ostream);
+ gpg->ostream = ostream;
+ gpg->seen_eof1 = FALSE;
+}
+
+static const char *
+gpg_ctx_get_diagnostics (struct _GpgCtx *gpg)
+{
+ if (!gpg->diagflushed) {
+ gpg->diagflushed = TRUE;
+ camel_stream_flush (gpg->diagnostics);
+ if (gpg->diagbuf->len == 0)
+ return NULL;
+
+ g_byte_array_append (gpg->diagbuf, "", 1);
+ }
+
+ return gpg->diagbuf->data;
+}
+
+static void
+userid_hint_free (gpointer key, gpointer value, gpointer user_data)
+{
+ g_free (key);
+ g_free (value);
+}
+
+static void
+gpg_ctx_free (struct _GpgCtx *gpg)
+{
+ int i;
+
+ if (gpg == NULL)
+ return;
+
+ if (gpg->session)
+ camel_object_unref (gpg->session);
+
+ g_hash_table_foreach (gpg->userid_hint, userid_hint_free, NULL);
+ g_hash_table_destroy (gpg->userid_hint);
+
+ g_free (gpg->userid);
+
+ g_free (gpg->sigfile);
+
+ if (gpg->recipients) {
+ for (i = 0; i < gpg->recipients->len; i++)
+ g_free (gpg->recipients->pdata[i]);
+
+ g_ptr_array_free (gpg->recipients, TRUE);
+ }
+
+ if (gpg->stdin_fd != -1)
+ close (gpg->stdin_fd);
+ if (gpg->stdout_fd != -1)
+ close (gpg->stdout_fd);
+ if (gpg->stderr_fd != -1)
+ close (gpg->stderr_fd);
+ if (gpg->status_fd != -1)
+ close (gpg->status_fd);
+ if (gpg->passwd_fd != -1)
+ close (gpg->passwd_fd);
+
+ g_free (gpg->statusbuf);
+
+ g_free (gpg->need_id);
+
+ if (gpg->passwd) {
+ memset (gpg->passwd, 0, strlen (gpg->passwd));
+ g_free (gpg->passwd);
+ }
+
+ if (gpg->istream)
+ camel_object_unref (gpg->istream);
+
+ if (gpg->ostream)
+ camel_object_unref (gpg->ostream);
+
+ camel_object_unref (gpg->diagnostics);
+
+ g_free (gpg);
+}
+
+static const char *
+gpg_hash_str (CamelCipherHash hash)
+{
+ switch (hash) {
+ case CAMEL_CIPHER_HASH_MD2:
+ return "--digest-algo=MD2";
+ case CAMEL_CIPHER_HASH_MD5:
+ return "--digest-algo=MD5";
+ case CAMEL_CIPHER_HASH_SHA1:
+ return "--digest-algo=SHA1";
+ case CAMEL_CIPHER_HASH_RIPEMD160:
+ return "--digest-algo=RIPEMD160";
+ default:
+ return NULL;
+ }
+}
+
+static GPtrArray *
+gpg_ctx_get_argv (struct _GpgCtx *gpg, int status_fd, char **sfd, int passwd_fd, char **pfd)
+{
+ const char *hash_str;
+ GPtrArray *argv;
+ char *buf;
+ int i;
+
+ argv = g_ptr_array_new ();
+ g_ptr_array_add (argv, "gpg");
+
+ g_ptr_array_add (argv, "--verbose");
+ g_ptr_array_add (argv, "--no-secmem-warning");
+ g_ptr_array_add (argv, "--no-greeting");
+ g_ptr_array_add (argv, "--no-tty");
+ if (passwd_fd == -1) {
+ /* only use batch mode if we don't intend on using the
+ interactive --command-fd option */
+ g_ptr_array_add (argv, "--batch");
+ g_ptr_array_add (argv, "--yes");
+ }
+
+ *sfd = buf = g_strdup_printf ("--status-fd=%d", status_fd);
+ g_ptr_array_add (argv, buf);
+
+ if (passwd_fd != -1) {
+ *pfd = buf = g_strdup_printf ("--command-fd=%d", passwd_fd);
+ g_ptr_array_add (argv, buf);
+ }
+
+ switch (gpg->mode) {
+ case GPG_CTX_MODE_SIGN:
+ g_ptr_array_add (argv, "--sign");
+ g_ptr_array_add (argv, "--detach");
+ if (gpg->armor)
+ g_ptr_array_add (argv, "--armor");
+ hash_str = gpg_hash_str (gpg->hash);
+ if (hash_str)
+ g_ptr_array_add (argv, (char *) hash_str);
+ if (gpg->userid) {
+ g_ptr_array_add (argv, "-u");
+ g_ptr_array_add (argv, (char *) gpg->userid);
+ }
+ g_ptr_array_add (argv, "--output");
+ g_ptr_array_add (argv, "-");
+ break;
+ case GPG_CTX_MODE_VERIFY:
+ if (!camel_session_is_online (gpg->session)) {
+ /* this is a deprecated flag to gpg since 1.0.7 */
+ /*g_ptr_array_add (argv, "--no-auto-key-retrieve");*/
+ g_ptr_array_add (argv, "--keyserver-options");
+ g_ptr_array_add (argv, "no-auto-key-retrieve");
+ }
+ g_ptr_array_add (argv, "--verify");
+ if (gpg->sigfile)
+ g_ptr_array_add (argv, gpg->sigfile);
+ g_ptr_array_add (argv, "-");
+ break;
+ case GPG_CTX_MODE_ENCRYPT:
+ g_ptr_array_add (argv, "--encrypt");
+ if (gpg->armor)
+ g_ptr_array_add (argv, "--armor");
+ if (gpg->always_trust)
+ g_ptr_array_add (argv, "--always-trust");
+ if (gpg->userid) {
+ g_ptr_array_add (argv, "-u");
+ g_ptr_array_add (argv, (char *) gpg->userid);
+ }
+ if (gpg->recipients) {
+ for (i = 0; i < gpg->recipients->len; i++) {
+ g_ptr_array_add (argv, "-r");
+ g_ptr_array_add (argv, gpg->recipients->pdata[i]);
+ }
+ }
+ g_ptr_array_add (argv, "--output");
+ g_ptr_array_add (argv, "-");
+ break;
+ case GPG_CTX_MODE_DECRYPT:
+ g_ptr_array_add (argv, "--decrypt");
+ g_ptr_array_add (argv, "--output");
+ g_ptr_array_add (argv, "-");
+ break;
+ case GPG_CTX_MODE_IMPORT:
+ g_ptr_array_add (argv, "--import");
+ g_ptr_array_add (argv, "-");
+ break;
+ case GPG_CTX_MODE_EXPORT:
+ if (gpg->armor)
+ g_ptr_array_add (argv, "--armor");
+ g_ptr_array_add (argv, "--export");
+ for (i = 0; i < gpg->recipients->len; i++)
+ g_ptr_array_add (argv, gpg->recipients->pdata[i]);
+ break;
+ }
+
+ g_ptr_array_add (argv, NULL);
+
+ return argv;
+}
+
+static int
+gpg_ctx_op_start (struct _GpgCtx *gpg)
+{
+ char *status_fd = NULL, *passwd_fd = NULL;
+ int i, maxfd, errnosave, fds[10];
+ GPtrArray *argv;
+ int flags;
+
+ for (i = 0; i < 10; i++)
+ fds[i] = -1;
+
+ maxfd = gpg->need_passwd ? 10 : 8;
+ for (i = 0; i < maxfd; i += 2) {
+ if (pipe (fds + i) == -1)
+ goto exception;
+ }
+
+ argv = gpg_ctx_get_argv (gpg, fds[7], &status_fd, fds[8], &passwd_fd);
+
+ if (!(gpg->pid = fork ())) {
+ /* child process */
+
+ if ((dup2 (fds[0], STDIN_FILENO) < 0 ) ||
+ (dup2 (fds[3], STDOUT_FILENO) < 0 ) ||
+ (dup2 (fds[5], STDERR_FILENO) < 0 )) {
+ _exit (255);
+ }
+
+ /* Dissociate from camel's controlling terminal so
+ * that gpg won't be able to read from it.
+ */
+ setsid ();
+
+ maxfd = sysconf (_SC_OPEN_MAX);
+ /* Loop over all fds. */
+ for (i = 3; i < maxfd; i++) {
+ /* don't close the status-fd or passwd-fd */
+ if (i != fds[7] && i != fds[8])
+ fcntl (i, F_SETFD, FD_CLOEXEC);
+ }
+
+ /* run gpg */
+ execvp ("gpg", (char **) argv->pdata);
+ _exit (255);
+ } else if (gpg->pid < 0) {
+ g_ptr_array_free (argv, TRUE);
+ g_free (status_fd);
+ g_free (passwd_fd);
+ goto exception;
+ }
+
+ g_ptr_array_free (argv, TRUE);
+ g_free (status_fd);
+ g_free (passwd_fd);
+
+ /* Parent */
+ close (fds[0]);
+ gpg->stdin_fd = fds[1];
+ gpg->stdout_fd = fds[2];
+ close (fds[3]);
+ gpg->stderr_fd = fds[4];
+ close (fds[5]);
+ gpg->status_fd = fds[6];
+ close (fds[7]);
+ if (gpg->need_passwd) {
+ close (fds[8]);
+ gpg->passwd_fd = fds[9];
+ flags = fcntl (gpg->passwd_fd, F_GETFL);
+ fcntl (gpg->passwd_fd, F_SETFL, flags | O_NONBLOCK);
+ }
+
+ flags = fcntl (gpg->stdin_fd, F_GETFL);
+ fcntl (gpg->stdin_fd, F_SETFL, flags | O_NONBLOCK);
+
+ flags = fcntl (gpg->stdout_fd, F_GETFL);
+ fcntl (gpg->stdout_fd, F_SETFL, flags | O_NONBLOCK);
+
+ flags = fcntl (gpg->stderr_fd, F_GETFL);
+ fcntl (gpg->stderr_fd, F_SETFL, flags | O_NONBLOCK);
+
+ flags = fcntl (gpg->status_fd, F_GETFL);
+ fcntl (gpg->status_fd, F_SETFL, flags | O_NONBLOCK);
+
+ return 0;
+
+ exception:
+
+ errnosave = errno;
+
+ for (i = 0; i < 10; i++) {
+ if (fds[i] != -1)
+ close (fds[i]);
+ }
+
+ errno = errnosave;
+
+ return -1;
+}
+
+static const char *
+next_token (const char *in, char **token)
+{
+ const char *start, *inptr = in;
+
+ while (*inptr == ' ')
+ inptr++;
+
+ if (*inptr == '\0' || *inptr == '\n') {
+ if (token)
+ *token = NULL;
+ return inptr;
+ }
+
+ start = inptr;
+ while (*inptr && *inptr != ' ' && *inptr != '\n')
+ inptr++;
+
+ if (token)
+ *token = g_strndup (start, inptr - start);
+
+ return inptr;
+}
+
+static int
+gpg_ctx_parse_status (struct _GpgCtx *gpg, CamelException *ex)
+{
+ register unsigned char *inptr;
+ const unsigned char *status;
+ size_t nread, nwritten;
+ int len;
+
+ parse:
+
+ inptr = gpg->statusbuf;
+ while (inptr < gpg->statusptr && *inptr != '\n')
+ inptr++;
+
+ if (*inptr != '\n') {
+ /* we don't have enough data buffered to parse this status line */
+ return 0;
+ }
+
+ *inptr++ = '\0';
+ status = gpg->statusbuf;
+
+ if (camel_debug("gpg:status"))
+ printf ("status: %s\n", status);
+
+ if (strncmp (status, "[GNUPG:] ", 9) != 0) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Unexpected GnuPG status message encountered:\n\n%s"),
+ status);
+ return -1;
+ }
+
+ status += 9;
+
+ if (!strncmp (status, "USERID_HINT ", 12)) {
+ char *hint, *user;
+
+ status += 12;
+ status = next_token (status, &hint);
+ if (!hint) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Failed to parse gpg userid hint."));
+ return -1;
+ }
+
+ if (g_hash_table_lookup (gpg->userid_hint, hint)) {
+ /* we already have this userid hint... */
+ g_free (hint);
+ goto recycle;
+ }
+
+ if (gpg->utf8 || !(user = g_locale_to_utf8 (status, -1, &nread, &nwritten, NULL)))
+ user = g_strdup (status);
+
+ g_strstrip (user);
+
+ g_hash_table_insert (gpg->userid_hint, hint, user);
+ } else if (!strncmp (status, "NEED_PASSPHRASE ", 16)) {
+ char *userid;
+
+ status += 16;
+
+ status = next_token (status, &userid);
+ if (!userid) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Failed to parse gpg passphrase request."));
+ return -1;
+ }
+
+ g_free (gpg->need_id);
+ gpg->need_id = userid;
+ } else if (!strncmp (status, "GET_HIDDEN passphrase.enter", 27)) {
+ char *prompt, *passwd;
+ const char *name;
+
+ name = g_hash_table_lookup (gpg->userid_hint, gpg->need_id);
+ if (!name)
+ name = gpg->need_id;
+
+ prompt = g_strdup_printf (_("You need a passphrase to unlock the key for\n"
+ "user: \"%s\""), name);
+
+ if ((passwd = camel_session_get_password (gpg->session, NULL, NULL, prompt, gpg->need_id, CAMEL_SESSION_PASSWORD_SECRET, ex)) && !gpg->utf8) {
+ char *opasswd = passwd;
+
+ if ((passwd = g_locale_to_utf8 (passwd, -1, &nread, &nwritten, NULL))) {
+ memset (opasswd, 0, strlen (opasswd));
+ g_free (opasswd);
+ } else {
+ passwd = opasswd;
+ }
+ }
+ g_free (prompt);
+
+ if (passwd == NULL) {
+ if (!camel_exception_is_set (ex))
+ camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL, _("Cancelled."));
+ return -1;
+ }
+
+ gpg->passwd = g_strdup_printf ("%s\n", passwd);
+ memset (passwd, 0, strlen (passwd));
+ g_free (passwd);
+
+ gpg->send_passwd = TRUE;
+ } else if (!strncmp (status, "GOOD_PASSPHRASE", 15)) {
+ gpg->bad_passwds = 0;
+ } else if (!strncmp (status, "BAD_PASSPHRASE", 14)) {
+ gpg->bad_passwds++;
+
+ camel_session_forget_password (gpg->session, NULL, NULL, gpg->need_id, ex);
+
+ if (gpg->bad_passwds == 3) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
+ _("Failed to unlock secret key: 3 bad passphrases given."));
+ return -1;
+ }
+ } else if (!strncmp (status, "UNEXPECTED ", 11)) {
+ /* this is an error */
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Unexpected response from GnuPG: %s"),
+ status + 11);
+ return -1;
+ } else if (!strncmp (status, "NODATA", 6)) {
+ /* this is an error */
+ /* But we ignore it anyway, we should get other response codes to say why */
+ gpg->nodata = TRUE;
+ } else {
+ /* check to see if we are complete */
+ switch (gpg->mode) {
+ case GPG_CTX_MODE_SIGN:
+ if (!strncmp (status, "SIG_CREATED ", 12)) {
+ /* FIXME: save this state? */
+ }
+ break;
+ case GPG_CTX_MODE_VERIFY:
+ if (!strncmp (status, "TRUST_", 6)) {
+ status += 6;
+ if (!strncmp (status, "NEVER", 5)) {
+ gpg->trust = GPG_TRUST_NEVER;
+ } else if (!strncmp (status, "MARGINAL", 8)) {
+ gpg->trust = GPG_TRUST_MARGINAL;
+ } else if (!strncmp (status, "FULLY", 5)) {
+ gpg->trust = GPG_TRUST_FULLY;
+ } else if (!strncmp (status, "ULTIMATE", 8)) {
+ gpg->trust = GPG_TRUST_ULTIMATE;
+ } else if (!strncmp (status, "UNDEFINED", 9)) {
+ gpg->trust = GPG_TRUST_UNDEFINED;
+ }
+ } else if (!strncmp (status, "GOODSIG ", 8)) {
+ gpg->goodsig = TRUE;
+ gpg->hadsig = TRUE;
+ } else if (!strncmp (status, "VALIDSIG ", 9)) {
+ gpg->validsig = TRUE;
+ } else if (!strncmp (status, "BADSIG ", 7)) {
+ gpg->badsig = FALSE;
+ gpg->hadsig = TRUE;
+ } else if (!strncmp (status, "ERRSIG ", 7)) {
+ /* Note: NO_PUBKEY often comes after an ERRSIG */
+ gpg->errsig = FALSE;
+ gpg->hadsig = TRUE;
+ } else if (!strncmp (status, "NO_PUBKEY ", 10)) {
+ gpg->nopubkey = TRUE;
+ }
+ break;
+ case GPG_CTX_MODE_ENCRYPT:
+ if (!strncmp (status, "BEGIN_ENCRYPTION", 16)) {
+ /* nothing to do... but we know to expect data on stdout soon */
+ } else if (!strncmp (status, "END_ENCRYPTION", 14)) {
+ /* nothing to do, but we know the end is near? */
+ } else if (!strncmp (status, "NO_RECP", 7)) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Failed to encrypt: No valid recipients specified."));
+ return -1;
+ }
+ break;
+ case GPG_CTX_MODE_DECRYPT:
+ if (!strncmp (status, "BEGIN_DECRYPTION", 16)) {
+ /* nothing to do... but we know to expect data on stdout soon */
+ } else if (!strncmp (status, "END_DECRYPTION", 14)) {
+ /* nothing to do, but we know the end is near? */
+ }
+ break;
+ case GPG_CTX_MODE_IMPORT:
+ /* noop */
+ break;
+ case GPG_CTX_MODE_EXPORT:
+ /* noop */
+ break;
+ }
+ }
+
+ recycle:
+
+ /* recycle our statusbuf by moving inptr to the beginning of statusbuf */
+ len = gpg->statusptr - inptr;
+ memmove (gpg->statusbuf, inptr, len);
+
+ len = inptr - gpg->statusbuf;
+ gpg->statusleft += len;
+ gpg->statusptr -= len;
+
+ /* if we have more data, try parsing the next line? */
+ if (gpg->statusptr > gpg->statusbuf)
+ goto parse;
+
+ return 0;
+}
+
+#define status_backup(gpg, start, len) G_STMT_START { \
+ if (gpg->statusleft <= len) { \
+ unsigned int slen, soff; \
+ \
+ slen = soff = gpg->statusptr - gpg->statusbuf; \
+ slen = slen ? slen : 1; \
+ \
+ while (slen < soff + len) \
+ slen <<= 1; \
+ \
+ gpg->statusbuf = g_realloc (gpg->statusbuf, slen + 1); \
+ gpg->statusptr = gpg->statusbuf + soff; \
+ gpg->statusleft = slen - soff; \
+ } \
+ \
+ memcpy (gpg->statusptr, start, len); \
+ gpg->statusptr += len; \
+ gpg->statusleft -= len; \
+} G_STMT_END
+
+static void
+gpg_ctx_op_cancel (struct _GpgCtx *gpg)
+{
+ pid_t retval;
+ int status;
+
+ if (gpg->exited)
+ return;
+
+ kill (gpg->pid, SIGTERM);
+ sleep (1);
+ retval = waitpid (gpg->pid, &status, WNOHANG);
+ if (retval == (pid_t) 0) {
+ /* no more mr nice guy... */
+ kill (gpg->pid, SIGKILL);
+ sleep (1);
+ waitpid (gpg->pid, &status, WNOHANG);
+ }
+}
+
+static int
+gpg_ctx_op_step (struct _GpgCtx *gpg, CamelException *ex)
+{
+ struct pollfd polls[6];
+ int status, i, cancel_fd;
+
+ for (i=0;i<6;i++)
+ polls[i].fd = -1;
+
+ if (!gpg->seen_eof1) {
+ polls[0].fd = gpg->stdout_fd;
+ polls[0].events = POLLIN;
+ }
+
+ if (!gpg->seen_eof2) {
+ polls[1].fd = gpg->stderr_fd;
+ polls[1].events = POLLIN;
+ }
+
+ if (!gpg->complete) {
+ polls[2].fd = gpg->status_fd;
+ polls[2].events = POLLIN;
+ }
+
+ polls[3].fd = gpg->stdin_fd;
+ polls[3].events = POLLOUT;
+ polls[4].fd = gpg->passwd_fd;
+ polls[4].events = POLLOUT;
+ cancel_fd = camel_operation_cancel_fd(NULL);
+ polls[5].fd = cancel_fd;
+ polls[5].events = POLLIN;
+
+ do {
+ for (i=0;i<6;i++)
+ polls[i].revents = 0;
+ status = poll(polls, 6, 30*1000);
+ } while (status == -1 && errno == EINTR);
+
+ if (status == 0)
+ return 0; /* timed out */
+ else if (status == -1)
+ goto exception;
+
+ if ((polls[5].revents & POLLIN) && camel_operation_cancel_check(NULL)) {
+ camel_exception_set(ex, CAMEL_EXCEPTION_USER_CANCEL, _("Cancelled."));
+ gpg_ctx_op_cancel(gpg);
+ return -1;
+ }
+
+ /* Test each and every file descriptor to see if it's 'ready',
+ and if so - do what we can with it and then drop through to
+ the next file descriptor and so on until we've done what we
+ can to all of them. If one fails along the way, return
+ -1. */
+
+ if (polls[2].revents & (POLLIN|POLLHUP)) {
+ /* read the status message and decide what to do... */
+ char buffer[4096];
+ ssize_t nread;
+
+ d(printf ("reading from gpg's status-fd...\n"));
+
+ do {
+ nread = read (gpg->status_fd, buffer, sizeof (buffer));
+ } while (nread == -1 && (errno == EINTR || errno == EAGAIN));
+ if (nread == -1)
+ goto exception;
+
+ if (nread > 0) {
+ status_backup (gpg, buffer, nread);
+
+ if (gpg_ctx_parse_status (gpg, ex) == -1)
+ return -1;
+ } else {
+ gpg->complete = TRUE;
+ }
+ }
+
+ if ((polls[0].revents & (POLLIN|POLLHUP)) && gpg->ostream) {
+ char buffer[4096];
+ ssize_t nread;
+
+ d(printf ("reading gpg's stdout...\n"));
+
+ do {
+ nread = read (gpg->stdout_fd, buffer, sizeof (buffer));
+ } while (nread == -1 && (errno == EINTR || errno == EAGAIN));
+ if (nread == -1)
+ goto exception;
+
+ if (nread > 0) {
+ if (camel_stream_write (gpg->ostream, buffer, (size_t) nread) == -1)
+ goto exception;
+ } else {
+ gpg->seen_eof1 = TRUE;
+ }
+ }
+
+ if (polls[1].revents & (POLLIN|POLLHUP)) {
+ char buffer[4096];
+ ssize_t nread;
+
+ d(printf ("reading gpg's stderr...\n"));
+
+ do {
+ nread = read (gpg->stderr_fd, buffer, sizeof (buffer));
+ } while (nread == -1 && (errno == EINTR || errno == EAGAIN));
+ if (nread == -1)
+ goto exception;
+
+ if (nread > 0) {
+ camel_stream_write (gpg->diagnostics, buffer, nread);
+ } else {
+ gpg->seen_eof2 = TRUE;
+ }
+ }
+
+ if ((polls[4].revents & (POLLOUT|POLLHUP)) && gpg->need_passwd && gpg->send_passwd) {
+ ssize_t w, nwritten = 0;
+ size_t n;
+
+ d(printf ("sending gpg our passphrase...\n"));
+
+ /* send the passphrase to gpg */
+ n = strlen (gpg->passwd);
+ do {
+ do {
+ w = write (gpg->passwd_fd, gpg->passwd + nwritten, n - nwritten);
+ } while (w == -1 && (errno == EINTR || errno == EAGAIN));
+
+ if (w > 0)
+ nwritten += w;
+ } while (nwritten < n && w != -1);
+
+ /* zero and free our passwd buffer */
+ memset (gpg->passwd, 0, n);
+ g_free (gpg->passwd);
+ gpg->passwd = NULL;
+
+ if (w == -1)
+ goto exception;
+
+ gpg->send_passwd = FALSE;
+ }
+
+ if ((polls[3].revents & (POLLOUT|POLLHUP)) && gpg->istream) {
+ char buffer[4096];
+ ssize_t nread;
+
+ d(printf ("writing to gpg's stdin...\n"));
+
+ /* write our stream to gpg's stdin */
+ nread = camel_stream_read (gpg->istream, buffer, sizeof (buffer));
+ if (nread > 0) {
+ ssize_t w, nwritten = 0;
+
+ do {
+ do {
+ w = write (gpg->stdin_fd, buffer + nwritten, nread - nwritten);
+ } while (w == -1 && (errno == EINTR || errno == EAGAIN));
+
+ if (w > 0)
+ nwritten += w;
+ } while (nwritten < nread && w != -1);
+
+ if (w == -1)
+ goto exception;
+
+ d(printf ("wrote %d (out of %d) bytes to gpg's stdin\n", nwritten, nread));
+ }
+
+ if (camel_stream_eos (gpg->istream)) {
+ d(printf ("closing gpg's stdin\n"));
+ close (gpg->stdin_fd);
+ gpg->stdin_fd = -1;
+ }
+ }
+
+ return 0;
+
+exception:
+ /* always called on an i/o error */
+ camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, _("Failed to execute gpg: %s"), g_strerror(errno));
+ gpg_ctx_op_cancel(gpg);
+
+ return -1;
+}
+
+static gboolean
+gpg_ctx_op_complete (struct _GpgCtx *gpg)
+{
+ return gpg->complete && gpg->seen_eof1 && gpg->seen_eof2;}
+
+
+#if 0
+static gboolean
+gpg_ctx_op_exited (struct _GpgCtx *gpg)
+{
+ pid_t retval;
+ int status;
+
+ if (gpg->exited)
+ return TRUE;
+
+ retval = waitpid (gpg->pid, &status, WNOHANG);
+ if (retval == gpg->pid) {
+ gpg->exit_status = status;
+ gpg->exited = TRUE;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+#endif
+
+static int
+gpg_ctx_op_wait (struct _GpgCtx *gpg)
+{
+ sigset_t mask, omask;
+ pid_t retval;
+ int status;
+
+ if (!gpg->exited) {
+ sigemptyset (&mask);
+ sigaddset (&mask, SIGALRM);
+ sigprocmask (SIG_BLOCK, &mask, &omask);
+ alarm (1);
+ retval = waitpid (gpg->pid, &status, 0);
+ alarm (0);
+ sigprocmask (SIG_SETMASK, &omask, NULL);
+
+ if (retval == (pid_t) -1 && errno == EINTR) {
+ /* The child is hanging: send a friendly reminder. */
+ kill (gpg->pid, SIGTERM);
+ sleep (1);
+ retval = waitpid (gpg->pid, &status, WNOHANG);
+ if (retval == (pid_t) 0) {
+ /* Still hanging; use brute force. */
+ kill (gpg->pid, SIGKILL);
+ sleep (1);
+ retval = waitpid (gpg->pid, &status, WNOHANG);
+ }
+ }
+ } else {
+ status = gpg->exit_status;
+ retval = gpg->pid;
+ }
+
+ if (retval != (pid_t) -1 && WIFEXITED (status))
+ return WEXITSTATUS (status);
+ else
+ return -1;
+}
+
+
+
+static int
+gpg_sign (CamelCipherContext *context, const char *userid, CamelCipherHash hash, CamelMimePart *ipart, CamelMimePart *opart, CamelException *ex)
+{
+ struct _GpgCtx *gpg = NULL;
+ CamelStream *ostream = camel_stream_mem_new(), *istream;
+ CamelDataWrapper *dw;
+ CamelContentType *ct;
+ int res = -1;
+ CamelMimePart *sigpart;
+ CamelMultipartSigned *mps;
+
+ /* Note: see rfc2015 or rfc3156, section 5 */
+
+ /* FIXME: stream this, we stream output at least */
+ istream = camel_stream_mem_new();
+ if (camel_cipher_canonical_to_stream(ipart, CAMEL_MIME_FILTER_CANON_STRIP|CAMEL_MIME_FILTER_CANON_CRLF|CAMEL_MIME_FILTER_CANON_FROM,
+ istream) == -1) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Could not generate signing data: %s"), g_strerror(errno));
+ goto fail;
+ }
+
+#ifdef GPG_LOG
+ if (camel_debug_start("gpg:sign")) {
+ char *name;
+ CamelStream *out;
+
+ name = g_strdup_printf("camel-gpg.%d.sign-data", logid++);
+ out = camel_stream_fs_new_with_name(name, O_CREAT|O_TRUNC|O_WRONLY, 0666);
+ if (out) {
+ printf("Writing gpg signing data to '%s'\n", name);
+ camel_stream_write_to_stream(istream, out);
+ camel_stream_reset(istream);
+ camel_object_unref(out);
+ }
+ g_free(name);
+ camel_debug_end();
+ }
+#endif
+
+ gpg = gpg_ctx_new (context->session);
+ gpg_ctx_set_mode (gpg, GPG_CTX_MODE_SIGN);
+ gpg_ctx_set_hash (gpg, hash);
+ gpg_ctx_set_armor (gpg, TRUE);
+ gpg_ctx_set_userid (gpg, userid);
+ gpg_ctx_set_istream (gpg, istream);
+ gpg_ctx_set_ostream (gpg, ostream);
+
+ if (gpg_ctx_op_start (gpg) == -1) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Failed to execute gpg: %s"), g_strerror (errno));
+ goto fail;
+ }
+
+ while (!gpg_ctx_op_complete (gpg)) {
+ if (gpg_ctx_op_step (gpg, ex) == -1)
+ goto fail;
+ }
+
+ if (gpg_ctx_op_wait (gpg) != 0) {
+ const char *diagnostics;
+
+ diagnostics = gpg_ctx_get_diagnostics (gpg);
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
+ diagnostics && *diagnostics ? diagnostics :
+ _("Failed to execute gpg."));
+ goto fail;
+ }
+
+ res = 0;
+
+ dw = camel_data_wrapper_new();
+ camel_stream_reset(ostream);
+ camel_data_wrapper_construct_from_stream(dw, ostream);
+
+ sigpart = camel_mime_part_new();
+ ct = camel_content_type_new("application", "pgp-signature");
+ camel_content_type_set_param(ct, "name", "signature.asc");
+ camel_data_wrapper_set_mime_type_field(dw, ct);
+ camel_content_type_unref(ct);
+
+ camel_medium_set_content_object((CamelMedium *)sigpart, dw);
+ camel_object_unref(dw);
+
+ camel_mime_part_set_description(sigpart, _("This is a digitally signed message part"));
+
+ mps = camel_multipart_signed_new();
+ ct = camel_content_type_new("multipart", "signed");
+ camel_content_type_set_param(ct, "micalg", camel_cipher_hash_to_id(context, hash));
+ camel_content_type_set_param(ct, "protocol", context->sign_protocol);
+ camel_data_wrapper_set_mime_type_field((CamelDataWrapper *)mps, ct);
+ camel_content_type_unref(ct);
+ camel_multipart_set_boundary((CamelMultipart *)mps, NULL);
+
+ mps->signature = sigpart;
+ mps->contentraw = istream;
+ camel_stream_reset(istream);
+ camel_object_ref(istream);
+
+ camel_medium_set_content_object((CamelMedium *)opart, (CamelDataWrapper *)mps);
+fail:
+ camel_object_unref(ostream);
+
+ if (gpg)
+ gpg_ctx_free (gpg);
+
+ return res;
+}
+
+
+static char *
+swrite (CamelMimePart *sigpart)
+{
+ CamelStream *ostream;
+ char *template;
+ int fd, ret;
+
+ template = g_strdup ("/tmp/evolution-pgp.XXXXXX");
+ fd = mkstemp (template);
+ if (fd == -1) {
+ g_free (template);
+ return NULL;
+ }
+
+ /* TODO: This should probably just write the decoded message content out, not the part + headers */
+
+ ostream = camel_stream_fs_new_with_fd (fd);
+ ret = camel_data_wrapper_write_to_stream((CamelDataWrapper *)sigpart, ostream);
+ if (ret != -1) {
+ ret = camel_stream_flush (ostream);
+ if (ret != -1)
+ ret = camel_stream_close (ostream);
+ }
+
+ camel_object_unref(ostream);
+
+ if (ret == -1) {
+ unlink (template);
+ g_free (template);
+ return NULL;
+ }
+
+ return template;
+}
+
+static CamelCipherValidity *
+gpg_verify (CamelCipherContext *context, CamelMimePart *ipart, CamelException *ex)
+{
+ CamelCipherValidity *validity;
+ const char *diagnostics = NULL, *tmp;
+ struct _GpgCtx *gpg = NULL;
+ char *sigfile = NULL;
+ CamelContentType *ct;
+ CamelMimePart *sigpart;
+ CamelStream *istream = NULL;
+ CamelMultipart *mps;
+
+ mps = (CamelMultipart *)camel_medium_get_content_object((CamelMedium *)ipart);
+ ct = ((CamelDataWrapper *)mps)->mime_type;
+ tmp = camel_content_type_param(ct, "protocol");
+ if (!camel_content_type_is(ct, "multipart", "signed")
+ || !CAMEL_IS_MULTIPART_SIGNED(mps)
+ || tmp == NULL
+ || g_ascii_strcasecmp(tmp, context->sign_protocol) != 0) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot verify message signature: Incorrect message format"));
+ return NULL;
+ }
+
+ if (!(istream = camel_multipart_signed_get_content_stream ((CamelMultipartSigned *) mps, NULL))) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot verify message signature: Incorrect message format"));
+ return NULL;
+ }
+
+ if (!(sigpart = camel_multipart_get_part (mps, CAMEL_MULTIPART_SIGNED_SIGNATURE))) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot verify message signature: Incorrect message format"));
+ camel_object_unref (istream);
+ return NULL;
+ }
+
+#ifdef GPG_LOG
+ if (camel_debug_start("gpg:sign")) {
+ char *name;
+ CamelStream *out;
+
+ name = g_strdup_printf("camel-gpg.%d.verify.data", logid);
+ out = camel_stream_fs_new_with_name(name, O_CREAT|O_TRUNC|O_WRONLY, 0666);
+ if (out) {
+ printf("Writing gpg verify data to '%s'\n", name);
+ camel_stream_write_to_stream(istream, out);
+ camel_stream_reset(istream);
+ camel_object_unref(out);
+ }
+ g_free(name);
+ name = g_strdup_printf("camel-gpg.%d.verify.signature", logid++);
+ out = camel_stream_fs_new_with_name(name, O_CREAT|O_TRUNC|O_WRONLY, 0666);
+ if (out) {
+ printf("Writing gpg verify signature to '%s'\n", name);
+ camel_data_wrapper_write_to_stream((CamelDataWrapper *)sigpart, out);
+ camel_object_unref(out);
+ }
+ g_free(name);
+ camel_debug_end();
+ }
+#endif
+
+ sigfile = swrite (sigpart);
+ if (sigfile == NULL) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot verify message signature: could not create temp file: %s"),
+ g_strerror (errno));
+ goto exception;
+ }
+
+ camel_stream_reset(istream);
+ gpg = gpg_ctx_new (context->session);
+ gpg_ctx_set_mode (gpg, GPG_CTX_MODE_VERIFY);
+ gpg_ctx_set_hash (gpg, camel_cipher_id_to_hash(context, camel_content_type_param(ct, "micalg")));
+ gpg_ctx_set_sigfile (gpg, sigfile);
+ gpg_ctx_set_istream (gpg, istream);
+
+ if (gpg_ctx_op_start (gpg) == -1) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Failed to execute gpg."));
+ goto exception;
+ }
+
+ while (!gpg_ctx_op_complete (gpg)) {
+ if (gpg_ctx_op_step (gpg, ex) == -1)
+ goto exception;
+ }
+
+ gpg_ctx_op_wait (gpg);
+ validity = camel_cipher_validity_new ();
+ diagnostics = gpg_ctx_get_diagnostics (gpg);
+ camel_cipher_validity_set_description (validity, diagnostics);
+ if (gpg->validsig) {
+ if (gpg->trust == GPG_TRUST_UNDEFINED || gpg->trust == GPG_TRUST_NONE)
+ validity->sign.status = CAMEL_CIPHER_VALIDITY_SIGN_UNKNOWN;
+ else if (gpg->trust != GPG_TRUST_NEVER)
+ validity->sign.status = CAMEL_CIPHER_VALIDITY_SIGN_GOOD;
+ else
+ validity->sign.status = CAMEL_CIPHER_VALIDITY_SIGN_BAD;
+ } else {
+ validity->sign.status = CAMEL_CIPHER_VALIDITY_SIGN_BAD;
+ }
+
+ gpg_ctx_free (gpg);
+
+ if (sigfile) {
+ unlink (sigfile);
+ g_free (sigfile);
+ }
+
+ return validity;
+
+ exception:
+
+ if (gpg != NULL)
+ gpg_ctx_free (gpg);
+
+ if (istream)
+ camel_object_unref(istream);
+
+ if (sigfile) {
+ unlink (sigfile);
+ g_free (sigfile);
+ }
+
+ return NULL;
+}
+
+static int
+gpg_encrypt (CamelCipherContext *context, const char *userid, GPtrArray *recipients, struct _CamelMimePart *ipart, struct _CamelMimePart *opart, CamelException *ex)
+{
+ CamelGpgContext *ctx = (CamelGpgContext *) context;
+ struct _GpgCtx *gpg;
+ int i, res = -1;
+ CamelStream *istream, *ostream, *vstream;
+ CamelMimePart *encpart, *verpart;
+ CamelDataWrapper *dw;
+ CamelContentType *ct;
+ CamelMultipartEncrypted *mpe;
+
+ ostream = camel_stream_mem_new();
+ istream = camel_stream_mem_new();
+ if (camel_cipher_canonical_to_stream(ipart, CAMEL_MIME_FILTER_CANON_CRLF, istream) == -1) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Could not generate encrypting data: %s"), g_strerror(errno));
+ goto fail1;
+ }
+
+ gpg = gpg_ctx_new (context->session);
+ gpg_ctx_set_mode (gpg, GPG_CTX_MODE_ENCRYPT);
+ gpg_ctx_set_armor (gpg, TRUE);
+ gpg_ctx_set_userid (gpg, userid);
+ gpg_ctx_set_istream (gpg, istream);
+ gpg_ctx_set_ostream (gpg, ostream);
+ gpg_ctx_set_always_trust (gpg, ctx->always_trust);
+
+ for (i = 0; i < recipients->len; i++) {
+ gpg_ctx_add_recipient (gpg, recipients->pdata[i]);
+ }
+
+ if (gpg_ctx_op_start (gpg) == -1) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Failed to execute gpg."));
+ goto fail;
+ }
+
+ /* FIXME: move tihs to a common routine */
+ while (!gpg_ctx_op_complete(gpg)) {
+ if (gpg_ctx_op_step (gpg, ex) == -1)
+ goto fail;
+ }
+
+ if (gpg_ctx_op_wait (gpg) != 0) {
+ const char *diagnostics;
+
+ diagnostics = gpg_ctx_get_diagnostics (gpg);
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
+ diagnostics && *diagnostics ? diagnostics : _("Failed to execute gpg."));
+ goto fail;
+ }
+
+ res = 0;
+
+ dw = camel_data_wrapper_new();
+ camel_data_wrapper_construct_from_stream(dw, ostream);
+
+ encpart = camel_mime_part_new();
+ ct = camel_content_type_new("application", "octet-stream");
+ camel_content_type_set_param(ct, "name", "encrypted.asc");
+ camel_data_wrapper_set_mime_type_field(dw, ct);
+ camel_content_type_unref(ct);
+
+ camel_medium_set_content_object((CamelMedium *)encpart, dw);
+ camel_object_unref(dw);
+
+ camel_mime_part_set_description(encpart, _("This is a digitally encrypted message part"));
+
+ vstream = camel_stream_mem_new();
+ camel_stream_write(vstream, "Version: 1\n", strlen("Version: 1\n"));
+ camel_stream_reset(vstream);
+
+ verpart = camel_mime_part_new();
+ dw = camel_data_wrapper_new();
+ camel_data_wrapper_set_mime_type(dw, context->encrypt_protocol);
+ camel_data_wrapper_construct_from_stream(dw, vstream);
+ camel_object_unref(vstream);
+ camel_medium_set_content_object((CamelMedium *)verpart, dw);
+ camel_object_unref(dw);
+
+ mpe = camel_multipart_encrypted_new();
+ ct = camel_content_type_new("multipart", "encrypted");
+ camel_content_type_set_param(ct, "protocol", context->encrypt_protocol);
+ camel_data_wrapper_set_mime_type_field((CamelDataWrapper *)mpe, ct);
+ camel_content_type_unref(ct);
+ camel_multipart_set_boundary((CamelMultipart *)mpe, NULL);
+
+ mpe->decrypted = ipart;
+ camel_object_ref(ipart);
+
+ camel_multipart_add_part((CamelMultipart *)mpe, verpart);
+ camel_object_unref(verpart);
+ camel_multipart_add_part((CamelMultipart *)mpe, encpart);
+ camel_object_unref(encpart);
+
+ camel_medium_set_content_object((CamelMedium *)opart, (CamelDataWrapper *)mpe);
+fail:
+ gpg_ctx_free(gpg);
+fail1:
+ camel_object_unref(istream);
+ camel_object_unref(ostream);
+
+ return res;
+}
+
+static CamelCipherValidity *
+gpg_decrypt(CamelCipherContext *context, CamelMimePart *ipart, CamelMimePart *opart, CamelException *ex)
+{
+ struct _GpgCtx *gpg;
+ CamelCipherValidity *valid = NULL;
+ CamelStream *ostream, *istream;
+ CamelDataWrapper *content;
+ CamelMimePart *encrypted;
+ CamelMultipart *mp;
+
+ mp = (CamelMultipart *) camel_medium_get_content_object ((CamelMedium *) ipart);
+ if (!(encrypted = camel_multipart_get_part (mp, CAMEL_MULTIPART_ENCRYPTED_CONTENT))) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Failed to decrypt MIME part: protocol error"));
+ return NULL;
+ }
+
+ content = camel_medium_get_content_object ((CamelMedium *) encrypted);
+
+ istream = camel_stream_mem_new();
+ camel_data_wrapper_decode_to_stream (content, istream);
+ camel_stream_reset(istream);
+
+ ostream = camel_stream_mem_new();
+ camel_stream_mem_set_secure((CamelStreamMem *)ostream);
+
+ gpg = gpg_ctx_new (context->session);
+ gpg_ctx_set_mode (gpg, GPG_CTX_MODE_DECRYPT);
+ gpg_ctx_set_istream (gpg, istream);
+ gpg_ctx_set_ostream (gpg, ostream);
+
+ if (gpg_ctx_op_start (gpg) == -1) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Failed to execute gpg."));
+ goto fail;
+ }
+
+ while (!gpg_ctx_op_complete (gpg)) {
+ if (gpg_ctx_op_step (gpg, ex) == -1)
+ goto fail;
+ }
+
+ if (gpg_ctx_op_wait (gpg) != 0) {
+ const char *diagnostics;
+
+ diagnostics = gpg_ctx_get_diagnostics (gpg);
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
+ diagnostics && *diagnostics ? diagnostics :
+ _("Failed to execute gpg."));
+ goto fail;
+ }
+
+ camel_stream_reset(ostream);
+ if (camel_data_wrapper_construct_from_stream((CamelDataWrapper *)opart, ostream) != -1) {
+ valid = camel_cipher_validity_new();
+ valid->encrypt.description = g_strdup(_("Encrypted content"));
+ valid->encrypt.status = CAMEL_CIPHER_VALIDITY_ENCRYPT_ENCRYPTED;
+
+ if (gpg->hadsig) {
+ if (gpg->validsig) {
+ if (gpg->trust == GPG_TRUST_UNDEFINED || gpg->trust == GPG_TRUST_NONE)
+ valid->sign.status = CAMEL_CIPHER_VALIDITY_SIGN_UNKNOWN;
+ else if (gpg->trust != GPG_TRUST_NEVER)
+ valid->sign.status = CAMEL_CIPHER_VALIDITY_SIGN_GOOD;
+ else
+ valid->sign.status = CAMEL_CIPHER_VALIDITY_SIGN_BAD;
+ } else if (gpg->nopubkey) {
+ valid->sign.status = CAMEL_CIPHER_VALIDITY_SIGN_UNKNOWN;
+ } else {
+ valid->sign.status = CAMEL_CIPHER_VALIDITY_SIGN_BAD;
+ }
+ }
+ } else {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Unable to parse message content"));
+ }
+
+ fail:
+ camel_object_unref(ostream);
+ camel_object_unref(istream);
+ gpg_ctx_free (gpg);
+
+ return valid;
+}
+
+static int
+gpg_import_keys (CamelCipherContext *context, CamelStream *istream, CamelException *ex)
+{
+ struct _GpgCtx *gpg;
+ int res = -1;
+
+ gpg = gpg_ctx_new (context->session);
+ gpg_ctx_set_mode (gpg, GPG_CTX_MODE_IMPORT);
+ gpg_ctx_set_istream (gpg, istream);
+
+ if (gpg_ctx_op_start (gpg) == -1) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Failed to execute gpg: %s"),
+ errno ? g_strerror (errno) : _("Unknown"));
+ goto fail;
+ }
+
+ while (!gpg_ctx_op_complete (gpg)) {
+ if (gpg_ctx_op_step (gpg, ex) == -1)
+ goto fail;
+ }
+
+ if (gpg_ctx_op_wait (gpg) != 0) {
+ const char *diagnostics;
+
+ diagnostics = gpg_ctx_get_diagnostics (gpg);
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
+ diagnostics && *diagnostics ? diagnostics :
+ _("Failed to execute gpg."));
+ goto fail;
+ }
+
+ res = 0;
+fail:
+ gpg_ctx_free (gpg);
+
+ return res;
+}
+
+static int
+gpg_export_keys (CamelCipherContext *context, GPtrArray *keys, CamelStream *ostream, CamelException *ex)
+{
+ struct _GpgCtx *gpg;
+ int i;
+ int res = -1;
+
+ gpg = gpg_ctx_new (context->session);
+ gpg_ctx_set_mode (gpg, GPG_CTX_MODE_EXPORT);
+ gpg_ctx_set_armor (gpg, TRUE);
+ gpg_ctx_set_ostream (gpg, ostream);
+
+ for (i = 0; i < keys->len; i++) {
+ gpg_ctx_add_recipient (gpg, keys->pdata[i]);
+ }
+
+ if (gpg_ctx_op_start (gpg) == -1) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Failed to execute gpg: %s"),
+ errno ? g_strerror (errno) : _("Unknown"));
+ goto fail;
+ }
+
+ while (!gpg_ctx_op_complete (gpg)) {
+ if (gpg_ctx_op_step (gpg, ex) == -1)
+ goto fail;
+ }
+
+ if (gpg_ctx_op_wait (gpg) != 0) {
+ const char *diagnostics;
+
+ diagnostics = gpg_ctx_get_diagnostics (gpg);
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
+ diagnostics && *diagnostics ? diagnostics :
+ _("Failed to execute gpg."));
+ goto fail;
+ }
+
+ res = 0;
+fail:
+ gpg_ctx_free (gpg);
+
+ return res;
+}
+
+/* ********************************************************************** */
+
+static void
+camel_gpg_context_class_init (CamelGpgContextClass *klass)
+{
+ CamelCipherContextClass *cipher_class = CAMEL_CIPHER_CONTEXT_CLASS (klass);
+
+ parent_class = CAMEL_CIPHER_CONTEXT_CLASS (camel_type_get_global_classfuncs (camel_cipher_context_get_type ()));
+
+ cipher_class->hash_to_id = gpg_hash_to_id;
+ cipher_class->id_to_hash = gpg_id_to_hash;
+ cipher_class->sign = gpg_sign;
+ cipher_class->verify = gpg_verify;
+ cipher_class->encrypt = gpg_encrypt;
+ cipher_class->decrypt = gpg_decrypt;
+ cipher_class->import_keys = gpg_import_keys;
+ cipher_class->export_keys = gpg_export_keys;
+}
+
+static void
+camel_gpg_context_init (CamelGpgContext *context)
+{
+ CamelCipherContext *cipher = (CamelCipherContext *) context;
+
+ context->always_trust = FALSE;
+
+ cipher->sign_protocol = "application/pgp-signature";
+ cipher->encrypt_protocol = "application/pgp-encrypted";
+ cipher->key_protocol = "application/pgp-keys";
+}
+
+static void
+camel_gpg_context_finalise (CamelObject *object)
+{
+ ;
+}
+
+CamelType
+camel_gpg_context_get_type (void)
+{
+ static CamelType type = CAMEL_INVALID_TYPE;
+
+ if (type == CAMEL_INVALID_TYPE) {
+ type = camel_type_register (camel_cipher_context_get_type (),
+ "CamelGpgContext",
+ sizeof (CamelGpgContext),
+ sizeof (CamelGpgContextClass),
+ (CamelObjectClassInitFunc) camel_gpg_context_class_init,
+ NULL,
+ (CamelObjectInitFunc) camel_gpg_context_init,
+ (CamelObjectFinalizeFunc) camel_gpg_context_finalise);
+ }
+
+ return type;
+}
+
+
diff --git a/camel/camel-html-parser.c b/camel/camel-html-parser.c
new file mode 100644
index 0000000000..17bf52f04c
--- /dev/null
+++ b/camel/camel-html-parser.c
@@ -0,0 +1,807 @@
+/*
+ * Copyright (C) 2001 Ximian Inc.
+ *
+ * Authors: Michael Zucchi <notzed@ximian.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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/** WARNING
+ **
+ ** DO NOT USE THIS CODE OUTSIDE OF CAMEL
+ **
+ ** IT IS SUBJECT TO CHANGE OR MAY VANISH AT ANY TIME
+ **/
+
+#include "camel-html-parser.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <glib/gunicode.h>
+#include <ctype.h>
+
+/* if defined, must also compile in dump_tag() below somewhere */
+#define d(x)
+
+static void camel_html_parser_class_init (CamelHTMLParserClass *klass);
+static void camel_html_parser_init (CamelObject *o);
+static void camel_html_parser_finalize (CamelObject *o);
+
+static CamelObjectClass *camel_html_parser_parent;
+
+/* Parser definitions, see below object code for details */
+
+typedef struct _CamelHTMLParserPrivate CamelHTMLParserPrivate;
+
+struct _CamelHTMLParserPrivate {
+ char *inbuf,
+ *inptr,
+ *inend,
+ *start;
+ enum _camel_html_parser_t state;
+ char *charset;
+ int eof;
+ GString *tag;
+ GString *ent;
+ char ent_utf8[8];
+ int attr;
+ GPtrArray *attrs;
+ GPtrArray *values;
+ int quote;
+};
+
+static void tokenise_setup(void);
+static CamelHTMLParserPrivate *tokenise_init(void);
+static void tokenise_free(CamelHTMLParserPrivate *p);
+static int tokenise_step(CamelHTMLParserPrivate *p, char **datap, int *lenp);
+
+/* ********************************************************************** */
+
+CamelType
+camel_html_parser_get_type (void)
+{
+ static CamelType type = CAMEL_INVALID_TYPE;
+
+ if (type == CAMEL_INVALID_TYPE) {
+ type = camel_type_register (camel_object_get_type (), "CamelHTMLParser",
+ sizeof (CamelHTMLParser),
+ sizeof (CamelHTMLParserClass),
+ (CamelObjectClassInitFunc) camel_html_parser_class_init,
+ NULL,
+ (CamelObjectInitFunc) camel_html_parser_init,
+ (CamelObjectFinalizeFunc) camel_html_parser_finalize);
+ }
+
+ return type;
+}
+
+static void
+camel_html_parser_finalize(CamelObject *o)
+{
+ CamelHTMLParser *f = (CamelHTMLParser *)o;
+
+ tokenise_free(f->priv);
+}
+
+static void
+camel_html_parser_init (CamelObject *o)
+{
+ CamelHTMLParser *f = (CamelHTMLParser *)o;
+
+ f->priv = tokenise_init();
+}
+
+static void
+camel_html_parser_class_init (CamelHTMLParserClass *klass)
+{
+ camel_html_parser_parent = CAMEL_OBJECT_CLASS (camel_type_get_global_classfuncs (camel_object_get_type ()));
+
+ tokenise_setup();
+}
+
+/**
+ * camel_html_parser_new:
+ *
+ * Create a new CamelHTMLParser object.
+ *
+ * Return value: A new CamelHTMLParser widget.
+ **/
+CamelHTMLParser *
+camel_html_parser_new (void)
+{
+ CamelHTMLParser *new = CAMEL_HTML_PARSER ( camel_object_new (camel_html_parser_get_type ()));
+ return new;
+}
+
+
+void camel_html_parser_set_data(CamelHTMLParser *hp, const char *start, int len, int last)
+{
+ CamelHTMLParserPrivate *p = hp->priv;
+
+ p->inptr = p->inbuf = (char *)start;
+ p->inend = (char *)start+len;
+ p->eof = last;
+}
+
+camel_html_parser_t camel_html_parser_step(CamelHTMLParser *hp, const char **datap, int *lenp)
+{
+ return tokenise_step(hp->priv, (char **)datap, lenp);
+}
+
+const char *camel_html_parser_left(CamelHTMLParser *hp, int *lenp)
+{
+ CamelHTMLParserPrivate *p = hp->priv;
+
+ if (lenp)
+ *lenp = p->inend - p->inptr;
+
+ return p->inptr;
+}
+
+const char *camel_html_parser_tag(CamelHTMLParser *hp)
+{
+ return hp->priv->tag->str;
+}
+
+const char *camel_html_parser_attr(CamelHTMLParser *hp, const char *name)
+{
+ int i;
+ CamelHTMLParserPrivate *p = hp->priv;
+
+ for (i=0;i<p->attrs->len;i++) {
+ if (!g_ascii_strcasecmp(((GString *)p->attrs->pdata[i])->str, name)) {
+ return ((GString *)p->values->pdata[i])->str;
+ }
+ }
+
+ return NULL;
+}
+
+const GPtrArray *camel_html_parser_attr_list(CamelHTMLParser *hp, const GPtrArray **values)
+{
+ if (values)
+ *values = hp->priv->values;
+
+ return hp->priv->attrs;
+}
+
+/* this map taken out of libxml */
+static struct {
+ unsigned int val;
+ const char *name;
+} entity_map[] = {
+/*
+ * the 4 absolute ones,
+ */
+ { 34, "quot", /* quotation mark = APL quote, U+0022 ISOnum */ },
+ { 38, "amp", /* ampersand, U+0026 ISOnum */ },
+ { 60, "lt", /* less-than sign, U+003C ISOnum */ },
+ { 62, "gt", /* greater-than sign, U+003E ISOnum */ },
+
+/*
+ * A bunch still in the 128-255 range
+ * Replacing them depend really on the charset used.
+ */
+ { 39, "apos", /* single quote */ },
+ { 160, "nbsp", /* no-break space = non-breaking space, U+00A0 ISOnum */ },
+ { 161, "iexcl",/* inverted exclamation mark, U+00A1 ISOnum */ },
+ { 162, "cent", /* cent sign, U+00A2 ISOnum */ },
+ { 163, "pound",/* pound sign, U+00A3 ISOnum */ },
+ { 164, "curren",/* currency sign, U+00A4 ISOnum */ },
+ { 165, "yen", /* yen sign = yuan sign, U+00A5 ISOnum */ },
+ { 166, "brvbar",/* broken bar = broken vertical bar, U+00A6 ISOnum */ },
+ { 167, "sect", /* section sign, U+00A7 ISOnum */ },
+ { 168, "uml", /* diaeresis = spacing diaeresis, U+00A8 ISOdia */ },
+ { 169, "copy", /* copyright sign, U+00A9 ISOnum */ },
+ { 170, "ordf", /* feminine ordinal indicator, U+00AA ISOnum */ },
+ { 171, "laquo",/* left-pointing double angle quotation mark = left pointing guillemet, U+00AB ISOnum */ },
+ { 172, "not", /* not sign, U+00AC ISOnum */ },
+ { 173, "shy", /* soft hyphen = discretionary hyphen, U+00AD ISOnum */ },
+ { 174, "reg", /* registered sign = registered trade mark sign, U+00AE ISOnum */ },
+ { 175, "macr", /* macron = spacing macron = overline = APL overbar, U+00AF ISOdia */ },
+ { 176, "deg", /* degree sign, U+00B0 ISOnum */ },
+ { 177, "plusmn",/* plus-minus sign = plus-or-minus sign, U+00B1 ISOnum */ },
+ { 178, "sup2", /* superscript two = superscript digit two = squared, U+00B2 ISOnum */ },
+ { 179, "sup3", /* superscript three = superscript digit three = cubed, U+00B3 ISOnum */ },
+ { 180, "acute",/* acute accent = spacing acute, U+00B4 ISOdia */ },
+ { 181, "micro",/* micro sign, U+00B5 ISOnum */ },
+ { 182, "para", /* pilcrow sign = paragraph sign, U+00B6 ISOnum */ },
+ { 183, "middot",/* middle dot = Georgian comma Greek middle dot, U+00B7 ISOnum */ },
+ { 184, "cedil",/* cedilla = spacing cedilla, U+00B8 ISOdia */ },
+ { 185, "sup1", /* superscript one = superscript digit one, U+00B9 ISOnum */ },
+ { 186, "ordm", /* masculine ordinal indicator, U+00BA ISOnum */ },
+ { 187, "raquo",/* right-pointing double angle quotation mark right pointing guillemet, U+00BB ISOnum */ },
+ { 188, "frac14",/* vulgar fraction one quarter = fraction one quarter, U+00BC ISOnum */ },
+ { 189, "frac12",/* vulgar fraction one half = fraction one half, U+00BD ISOnum */ },
+ { 190, "frac34",/* vulgar fraction three quarters = fraction three quarters, U+00BE ISOnum */ },
+ { 191, "iquest",/* inverted question mark = turned question mark, U+00BF ISOnum */ },
+ { 192, "Agrave",/* latin capital letter A with grave = latin capital letter A grave, U+00C0 ISOlat1 */ },
+ { 193, "Aacute",/* latin capital letter A with acute, U+00C1 ISOlat1 */ },
+ { 194, "Acirc",/* latin capital letter A with circumflex, U+00C2 ISOlat1 */ },
+ { 195, "Atilde",/* latin capital letter A with tilde, U+00C3 ISOlat1 */ },
+ { 196, "Auml", /* latin capital letter A with diaeresis, U+00C4 ISOlat1 */ },
+ { 197, "Aring",/* latin capital letter A with ring above = latin capital letter A ring, U+00C5 ISOlat1 */ },
+ { 198, "AElig",/* latin capital letter AE = latin capital ligature AE, U+00C6 ISOlat1 */ },
+ { 199, "Ccedil",/* latin capital letter C with cedilla, U+00C7 ISOlat1 */ },
+ { 200, "Egrave",/* latin capital letter E with grave, U+00C8 ISOlat1 */ },
+ { 201, "Eacute",/* latin capital letter E with acute, U+00C9 ISOlat1 */ },
+ { 202, "Ecirc",/* latin capital letter E with circumflex, U+00CA ISOlat1 */ },
+ { 203, "Euml", /* latin capital letter E with diaeresis, U+00CB ISOlat1 */ },
+ { 204, "Igrave",/* latin capital letter I with grave, U+00CC ISOlat1 */ },
+ { 205, "Iacute",/* latin capital letter I with acute, U+00CD ISOlat1 */ },
+ { 206, "Icirc",/* latin capital letter I with circumflex, U+00CE ISOlat1 */ },
+ { 207, "Iuml", /* latin capital letter I with diaeresis, U+00CF ISOlat1 */ },
+ { 208, "ETH", /* latin capital letter ETH, U+00D0 ISOlat1 */ },
+ { 209, "Ntilde",/* latin capital letter N with tilde, U+00D1 ISOlat1 */ },
+ { 210, "Ograve",/* latin capital letter O with grave, U+00D2 ISOlat1 */ },
+ { 211, "Oacute",/* latin capital letter O with acute, U+00D3 ISOlat1 */ },
+ { 212, "Ocirc",/* latin capital letter O with circumflex, U+00D4 ISOlat1 */ },
+ { 213, "Otilde",/* latin capital letter O with tilde, U+00D5 ISOlat1 */ },
+ { 214, "Ouml", /* latin capital letter O with diaeresis, U+00D6 ISOlat1 */ },
+ { 215, "times",/* multiplication sign, U+00D7 ISOnum */ },
+ { 216, "Oslash",/* latin capital letter O with stroke latin capital letter O slash, U+00D8 ISOlat1 */ },
+ { 217, "Ugrave",/* latin capital letter U with grave, U+00D9 ISOlat1 */ },
+ { 218, "Uacute",/* latin capital letter U with acute, U+00DA ISOlat1 */ },
+ { 219, "Ucirc",/* latin capital letter U with circumflex, U+00DB ISOlat1 */ },
+ { 220, "Uuml", /* latin capital letter U with diaeresis, U+00DC ISOlat1 */ },
+ { 221, "Yacute",/* latin capital letter Y with acute, U+00DD ISOlat1 */ },
+ { 222, "THORN",/* latin capital letter THORN, U+00DE ISOlat1 */ },
+ { 223, "szlig",/* latin small letter sharp s = ess-zed, U+00DF ISOlat1 */ },
+ { 224, "agrave",/* latin small letter a with grave = latin small letter a grave, U+00E0 ISOlat1 */ },
+ { 225, "aacute",/* latin small letter a with acute, U+00E1 ISOlat1 */ },
+ { 226, "acirc",/* latin small letter a with circumflex, U+00E2 ISOlat1 */ },
+ { 227, "atilde",/* latin small letter a with tilde, U+00E3 ISOlat1 */ },
+ { 228, "auml", /* latin small letter a with diaeresis, U+00E4 ISOlat1 */ },
+ { 229, "aring",/* latin small letter a with ring above = latin small letter a ring, U+00E5 ISOlat1 */ },
+ { 230, "aelig",/* latin small letter ae = latin small ligature ae, U+00E6 ISOlat1 */ },
+ { 231, "ccedil",/* latin small letter c with cedilla, U+00E7 ISOlat1 */ },
+ { 232, "egrave",/* latin small letter e with grave, U+00E8 ISOlat1 */ },
+ { 233, "eacute",/* latin small letter e with acute, U+00E9 ISOlat1 */ },
+ { 234, "ecirc",/* latin small letter e with circumflex, U+00EA ISOlat1 */ },
+ { 235, "euml", /* latin small letter e with diaeresis, U+00EB ISOlat1 */ },
+ { 236, "igrave",/* latin small letter i with grave, U+00EC ISOlat1 */ },
+ { 237, "iacute",/* latin small letter i with acute, U+00ED ISOlat1 */ },
+ { 238, "icirc",/* latin small letter i with circumflex, U+00EE ISOlat1 */ },
+ { 239, "iuml", /* latin small letter i with diaeresis, U+00EF ISOlat1 */ },
+ { 240, "eth", /* latin small letter eth, U+00F0 ISOlat1 */ },
+ { 241, "ntilde",/* latin small letter n with tilde, U+00F1 ISOlat1 */ },
+ { 242, "ograve",/* latin small letter o with grave, U+00F2 ISOlat1 */ },
+ { 243, "oacute",/* latin small letter o with acute, U+00F3 ISOlat1 */ },
+ { 244, "ocirc",/* latin small letter o with circumflex, U+00F4 ISOlat1 */ },
+ { 245, "otilde",/* latin small letter o with tilde, U+00F5 ISOlat1 */ },
+ { 246, "ouml", /* latin small letter o with diaeresis, U+00F6 ISOlat1 */ },
+ { 247, "divide",/* division sign, U+00F7 ISOnum */ },
+ { 248, "oslash",/* latin small letter o with stroke, = latin small letter o slash, U+00F8 ISOlat1 */ },
+ { 249, "ugrave",/* latin small letter u with grave, U+00F9 ISOlat1 */ },
+ { 250, "uacute",/* latin small letter u with acute, U+00FA ISOlat1 */ },
+ { 251, "ucirc",/* latin small letter u with circumflex, U+00FB ISOlat1 */ },
+ { 252, "uuml", /* latin small letter u with diaeresis, U+00FC ISOlat1 */ },
+ { 253, "yacute",/* latin small letter y with acute, U+00FD ISOlat1 */ },
+ { 254, "thorn",/* latin small letter thorn with, U+00FE ISOlat1 */ },
+ { 255, "yuml", /* latin small letter y with diaeresis, U+00FF ISOlat1 */ },
+
+/*
+ * Anything below should really be kept as entities references
+ */
+ { 402, "fnof", /* latin small f with hook = function = florin, U+0192 ISOtech */ },
+
+ { 913, "Alpha",/* greek capital letter alpha, U+0391 */ },
+ { 914, "Beta", /* greek capital letter beta, U+0392 */ },
+ { 915, "Gamma",/* greek capital letter gamma, U+0393 ISOgrk3 */ },
+ { 916, "Delta",/* greek capital letter delta, U+0394 ISOgrk3 */ },
+ { 917, "Epsilon",/* greek capital letter epsilon, U+0395 */ },
+ { 918, "Zeta", /* greek capital letter zeta, U+0396 */ },
+ { 919, "Eta", /* greek capital letter eta, U+0397 */ },
+ { 920, "Theta",/* greek capital letter theta, U+0398 ISOgrk3 */ },
+ { 921, "Iota", /* greek capital letter iota, U+0399 */ },
+ { 922, "Kappa",/* greek capital letter kappa, U+039A */ },
+ { 923, "Lambda"/* greek capital letter lambda, U+039B ISOgrk3 */ },
+ { 924, "Mu", /* greek capital letter mu, U+039C */ },
+ { 925, "Nu", /* greek capital letter nu, U+039D */ },
+ { 926, "Xi", /* greek capital letter xi, U+039E ISOgrk3 */ },
+ { 927, "Omicron",/* greek capital letter omicron, U+039F */ },
+ { 928, "Pi", /* greek capital letter pi, U+03A0 ISOgrk3 */ },
+ { 929, "Rho", /* greek capital letter rho, U+03A1 */ },
+ { 931, "Sigma",/* greek capital letter sigma, U+03A3 ISOgrk3 */ },
+ { 932, "Tau", /* greek capital letter tau, U+03A4 */ },
+ { 933, "Upsilon",/* greek capital letter upsilon, U+03A5 ISOgrk3 */ },
+ { 934, "Phi", /* greek capital letter phi, U+03A6 ISOgrk3 */ },
+ { 935, "Chi", /* greek capital letter chi, U+03A7 */ },
+ { 936, "Psi", /* greek capital letter psi, U+03A8 ISOgrk3 */ },
+ { 937, "Omega",/* greek capital letter omega, U+03A9 ISOgrk3 */ },
+
+ { 945, "alpha",/* greek small letter alpha, U+03B1 ISOgrk3 */ },
+ { 946, "beta", /* greek small letter beta, U+03B2 ISOgrk3 */ },
+ { 947, "gamma",/* greek small letter gamma, U+03B3 ISOgrk3 */ },
+ { 948, "delta",/* greek small letter delta, U+03B4 ISOgrk3 */ },
+ { 949, "epsilon",/* greek small letter epsilon, U+03B5 ISOgrk3 */ },
+ { 950, "zeta", /* greek small letter zeta, U+03B6 ISOgrk3 */ },
+ { 951, "eta", /* greek small letter eta, U+03B7 ISOgrk3 */ },
+ { 952, "theta",/* greek small letter theta, U+03B8 ISOgrk3 */ },
+ { 953, "iota", /* greek small letter iota, U+03B9 ISOgrk3 */ },
+ { 954, "kappa",/* greek small letter kappa, U+03BA ISOgrk3 */ },
+ { 955, "lambda",/* greek small letter lambda, U+03BB ISOgrk3 */ },
+ { 956, "mu", /* greek small letter mu, U+03BC ISOgrk3 */ },
+ { 957, "nu", /* greek small letter nu, U+03BD ISOgrk3 */ },
+ { 958, "xi", /* greek small letter xi, U+03BE ISOgrk3 */ },
+ { 959, "omicron",/* greek small letter omicron, U+03BF NEW */ },
+ { 960, "pi", /* greek small letter pi, U+03C0 ISOgrk3 */ },
+ { 961, "rho", /* greek small letter rho, U+03C1 ISOgrk3 */ },
+ { 962, "sigmaf",/* greek small letter final sigma, U+03C2 ISOgrk3 */ },
+ { 963, "sigma",/* greek small letter sigma, U+03C3 ISOgrk3 */ },
+ { 964, "tau", /* greek small letter tau, U+03C4 ISOgrk3 */ },
+ { 965, "upsilon",/* greek small letter upsilon, U+03C5 ISOgrk3 */ },
+ { 966, "phi", /* greek small letter phi, U+03C6 ISOgrk3 */ },
+ { 967, "chi", /* greek small letter chi, U+03C7 ISOgrk3 */ },
+ { 968, "psi", /* greek small letter psi, U+03C8 ISOgrk3 */ },
+ { 969, "omega",/* greek small letter omega, U+03C9 ISOgrk3 */ },
+ { 977, "thetasym",/* greek small letter theta symbol, U+03D1 NEW */ },
+ { 978, "upsih",/* greek upsilon with hook symbol, U+03D2 NEW */ },
+ { 982, "piv", /* greek pi symbol, U+03D6 ISOgrk3 */ },
+
+ { 8226, "bull", /* bullet = black small circle, U+2022 ISOpub */ },
+ { 8230, "hellip",/* horizontal ellipsis = three dot leader, U+2026 ISOpub */ },
+ { 8242, "prime",/* prime = minutes = feet, U+2032 ISOtech */ },
+ { 8243, "Prime",/* double prime = seconds = inches, U+2033 ISOtech */ },
+ { 8254, "oline",/* overline = spacing overscore, U+203E NEW */ },
+ { 8260, "frasl",/* fraction slash, U+2044 NEW */ },
+
+ { 8472, "weierp",/* script capital P = power set = Weierstrass p, U+2118 ISOamso */ },
+ { 8465, "image",/* blackletter capital I = imaginary part, U+2111 ISOamso */ },
+ { 8476, "real", /* blackletter capital R = real part symbol, U+211C ISOamso */ },
+ { 8482, "trade",/* trade mark sign, U+2122 ISOnum */ },
+ { 8501, "alefsym",/* alef symbol = first transfinite cardinal, U+2135 NEW */ },
+ { 8592, "larr", /* leftwards arrow, U+2190 ISOnum */ },
+ { 8593, "uarr", /* upwards arrow, U+2191 ISOnum */ },
+ { 8594, "rarr", /* rightwards arrow, U+2192 ISOnum */ },
+ { 8595, "darr", /* downwards arrow, U+2193 ISOnum */ },
+ { 8596, "harr", /* left right arrow, U+2194 ISOamsa */ },
+ { 8629, "crarr",/* downwards arrow with corner leftwards = carriage return, U+21B5 NEW */ },
+ { 8656, "lArr", /* leftwards double arrow, U+21D0 ISOtech */ },
+ { 8657, "uArr", /* upwards double arrow, U+21D1 ISOamsa */ },
+ { 8658, "rArr", /* rightwards double arrow, U+21D2 ISOtech */ },
+ { 8659, "dArr", /* downwards double arrow, U+21D3 ISOamsa */ },
+ { 8660, "hArr", /* left right double arrow, U+21D4 ISOamsa */ },
+
+
+ { 8704, "forall",/* for all, U+2200 ISOtech */ },
+ { 8706, "part", /* partial differential, U+2202 ISOtech */ },
+ { 8707, "exist",/* there exists, U+2203 ISOtech */ },
+ { 8709, "empty",/* empty set = null set = diameter, U+2205 ISOamso */ },
+ { 8711, "nabla",/* nabla = backward difference, U+2207 ISOtech */ },
+ { 8712, "isin", /* element of, U+2208 ISOtech */ },
+ { 8713, "notin",/* not an element of, U+2209 ISOtech */ },
+ { 8715, "ni", /* contains as member, U+220B ISOtech */ },
+ { 8719, "prod", /* n-ary product = product sign, U+220F ISOamsb */ },
+ { 8721, "sum", /* n-ary sumation, U+2211 ISOamsb */ },
+ { 8722, "minus",/* minus sign, U+2212 ISOtech */ },
+ { 8727, "lowast",/* asterisk operator, U+2217 ISOtech */ },
+ { 8730, "radic",/* square root = radical sign, U+221A ISOtech */ },
+ { 8733, "prop", /* proportional to, U+221D ISOtech */ },
+ { 8734, "infin",/* infinity, U+221E ISOtech */ },
+ { 8736, "ang", /* angle, U+2220 ISOamso */ },
+ { 8743, "and", /* logical and = wedge, U+2227 ISOtech */ },
+ { 8744, "or", /* logical or = vee, U+2228 ISOtech */ },
+ { 8745, "cap", /* intersection = cap, U+2229 ISOtech */ },
+ { 8746, "cup", /* union = cup, U+222A ISOtech */ },
+ { 8747, "int", /* integral, U+222B ISOtech */ },
+ { 8756, "there4",/* therefore, U+2234 ISOtech */ },
+ { 8764, "sim", /* tilde operator = varies with = similar to, U+223C ISOtech */ },
+ { 8773, "cong", /* approximately equal to, U+2245 ISOtech */ },
+ { 8776, "asymp",/* almost equal to = asymptotic to, U+2248 ISOamsr */ },
+ { 8800, "ne", /* not equal to, U+2260 ISOtech */ },
+ { 8801, "equiv",/* identical to, U+2261 ISOtech */ },
+ { 8804, "le", /* less-than or equal to, U+2264 ISOtech */ },
+ { 8805, "ge", /* greater-than or equal to, U+2265 ISOtech */ },
+ { 8834, "sub", /* subset of, U+2282 ISOtech */ },
+ { 8835, "sup", /* superset of, U+2283 ISOtech */ },
+ { 8836, "nsub", /* not a subset of, U+2284 ISOamsn */ },
+ { 8838, "sube", /* subset of or equal to, U+2286 ISOtech */ },
+ { 8839, "supe", /* superset of or equal to, U+2287 ISOtech */ },
+ { 8853, "oplus",/* circled plus = direct sum, U+2295 ISOamsb */ },
+ { 8855, "otimes",/* circled times = vector product, U+2297 ISOamsb */ },
+ { 8869, "perp", /* up tack = orthogonal to = perpendicular, U+22A5 ISOtech */ },
+ { 8901, "sdot", /* dot operator, U+22C5 ISOamsb */ },
+ { 8968, "lceil",/* left ceiling = apl upstile, U+2308 ISOamsc */ },
+ { 8969, "rceil",/* right ceiling, U+2309 ISOamsc */ },
+ { 8970, "lfloor",/* left floor = apl downstile, U+230A ISOamsc */ },
+ { 8971, "rfloor",/* right floor, U+230B ISOamsc */ },
+ { 9001, "lang", /* left-pointing angle bracket = bra, U+2329 ISOtech */ },
+ { 9002, "rang", /* right-pointing angle bracket = ket, U+232A ISOtech */ },
+ { 9674, "loz", /* lozenge, U+25CA ISOpub */ },
+
+ { 9824, "spades",/* black spade suit, U+2660 ISOpub */ },
+ { 9827, "clubs",/* black club suit = shamrock, U+2663 ISOpub */ },
+ { 9829, "hearts",/* black heart suit = valentine, U+2665 ISOpub */ },
+ { 9830, "diams",/* black diamond suit, U+2666 ISOpub */ },
+
+ { 338, "OElig",/* latin capital ligature OE, U+0152 ISOlat2 */ },
+ { 339, "oelig",/* latin small ligature oe, U+0153 ISOlat2 */ },
+ { 352, "Scaron",/* latin capital letter S with caron, U+0160 ISOlat2 */ },
+ { 353, "scaron",/* latin small letter s with caron, U+0161 ISOlat2 */ },
+ { 376, "Yuml", /* latin capital letter Y with diaeresis, U+0178 ISOlat2 */ },
+ { 710, "circ", /* modifier letter circumflex accent, U+02C6 ISOpub */ },
+ { 732, "tilde",/* small tilde, U+02DC ISOdia */ },
+
+ { 8194, "ensp", /* en space, U+2002 ISOpub */ },
+ { 8195, "emsp", /* em space, U+2003 ISOpub */ },
+ { 8201, "thinsp",/* thin space, U+2009 ISOpub */ },
+ { 8204, "zwnj", /* zero width non-joiner, U+200C NEW RFC 2070 */ },
+ { 8205, "zwj", /* zero width joiner, U+200D NEW RFC 2070 */ },
+ { 8206, "lrm", /* left-to-right mark, U+200E NEW RFC 2070 */ },
+ { 8207, "rlm", /* right-to-left mark, U+200F NEW RFC 2070 */ },
+ { 8211, "ndash",/* en dash, U+2013 ISOpub */ },
+ { 8212, "mdash",/* em dash, U+2014 ISOpub */ },
+ { 8216, "lsquo",/* left single quotation mark, U+2018 ISOnum */ },
+ { 8217, "rsquo",/* right single quotation mark, U+2019 ISOnum */ },
+ { 8218, "sbquo",/* single low-9 quotation mark, U+201A NEW */ },
+ { 8220, "ldquo",/* left double quotation mark, U+201C ISOnum */ },
+ { 8221, "rdquo",/* right double quotation mark, U+201D ISOnum */ },
+ { 8222, "bdquo",/* double low-9 quotation mark, U+201E NEW */ },
+ { 8224, "dagger",/* dagger, U+2020 ISOpub */ },
+ { 8225, "Dagger",/* double dagger, U+2021 ISOpub */ },
+ { 8240, "permil",/* per mille sign, U+2030 ISOtech */ },
+ { 8249, "lsaquo",/* single left-pointing angle quotation mark, U+2039 ISO proposed */ },
+ { 8250, "rsaquo",/* single right-pointing angle quotation mark, U+203A ISO proposed */ },
+ { 8364, "euro", /* euro sign, U+20AC NEW */ }
+};
+
+static GHashTable *entities;
+
+/* this cannot be called in a thread context */
+static void tokenise_setup(void)
+{
+ int i;
+
+ if (entities == NULL) {
+ entities = g_hash_table_new(g_str_hash, g_str_equal);
+ for (i=0;i<sizeof(entity_map)/sizeof(entity_map[0]);i++) {
+ g_hash_table_insert(entities, (char *)entity_map[i].name, GUINT_TO_POINTER(entity_map[i].val));
+ }
+ }
+}
+
+static CamelHTMLParserPrivate *tokenise_init(void)
+{
+ CamelHTMLParserPrivate *p;
+
+ p = g_malloc(sizeof(*p));
+ p->state = CAMEL_HTML_PARSER_DATA;
+
+ p->attr = 0;
+ p->attrs = g_ptr_array_new();
+ p->values = g_ptr_array_new();
+ p->tag = g_string_new("");
+ p->ent = g_string_new("");
+ p->charset = NULL;
+
+ if (entities == NULL)
+ tokenise_setup();
+
+ return p;
+}
+
+static void tokenise_free(CamelHTMLParserPrivate *p)
+{
+ int i;
+
+ g_string_free(p->tag, TRUE);
+ g_string_free(p->ent, TRUE);
+ g_free(p->charset);
+
+ for (i=0;i<p->attrs->len;i++)
+ g_string_free(p->attrs->pdata[i], TRUE);
+
+ for (i=0;i<p->values->len;i++)
+ g_string_free(p->values->pdata[i], TRUE);
+
+ g_free(p);
+}
+
+static int convert_entity(const char *e, char *ent)
+{
+ unsigned int val;
+
+ if (e[0] == '#')
+ return g_unichar_to_utf8(atoi(e+1), ent);
+
+ val = GPOINTER_TO_UINT(g_hash_table_lookup(entities, e));
+ if (ent)
+ return g_unichar_to_utf8(val, ent);
+ else
+ return 0;
+}
+
+#if 0
+static void dump_tag(CamelHTMLParserPrivate *p)
+{
+ int i;
+
+ printf("got tag: %s\n", p->tag->str);
+ printf("%d attributes:\n", p->attr);
+ for (i=0;i<p->attr;i++) {
+ printf(" %s = '%s'\n", ((GString *)p->attrs->pdata[i])->str, ((GString *)p->values->pdata[i])->str);
+ }
+}
+#endif
+
+static int tokenise_step(CamelHTMLParserPrivate *p, char **datap, int *lenp)
+{
+ char *in = p->inptr;
+ char *inend = p->inend;
+ char c;
+ int state = p->state, ret, len;
+ char *start = p->inptr;
+
+ d(printf("Tokenise step\n"));
+
+ while (in < inend) {
+ c = *in++;
+ switch (state) {
+ case CAMEL_HTML_PARSER_DATA:
+ if (c == '<') {
+ ret = state;
+ state = CAMEL_HTML_PARSER_TAG;
+ p->attr = 0;
+ g_string_truncate(p->tag, 0);
+ d(printf("got data '%.*s'\n", in-start-1, start));
+ *datap = start;
+ *lenp = in-start-1;
+ goto done;
+ } else if (c=='&') {
+ ret = state;
+ state = CAMEL_HTML_PARSER_ENT;
+ g_string_truncate(p->ent, 0);
+ g_string_append_c(p->ent, c);
+ d(printf("got data '%.*s'\n", in-start-1, start));
+ *datap = start;
+ *lenp = in-start-1;
+ goto done;
+ }
+ break;
+ case CAMEL_HTML_PARSER_ENT:
+ if (c==';') {
+ len = convert_entity(p->ent->str+1, p->ent_utf8);
+ if (len == 0) {
+ /* handle broken entity */
+ g_string_append_c(p->ent, c);
+ ret = state = CAMEL_HTML_PARSER_DATA;
+ *datap = p->ent->str;
+ *lenp = p->ent->len;
+ goto done;
+ } else {
+ d(printf("got entity: %s = %s\n", p->ent->str, p->ent_utf8));
+ ret = state;
+ state = CAMEL_HTML_PARSER_DATA;
+ *datap = p->ent_utf8;
+ *lenp = len;
+ goto done;
+ }
+ } else if (isalnum(c) || c=='#') { /* FIXME: right type */
+ g_string_append_c(p->ent, c);
+ } else {
+ /* handle broken entity */
+ g_string_append_c(p->ent, c);
+ ret = state = CAMEL_HTML_PARSER_DATA;
+ *datap = p->ent->str;
+ *lenp = p->ent->len;
+ goto done;
+ }
+ break;
+ case CAMEL_HTML_PARSER_TAG:
+ if (c == '!') {
+ state = CAMEL_HTML_PARSER_COMMENT0;
+ g_string_append_c(p->tag, c);
+ } else if (c == '>') {
+ d(dump_tag(p));
+ ret = CAMEL_HTML_PARSER_ELEMENT;
+ state = CAMEL_HTML_PARSER_DATA;
+ goto done;
+ } else if (c == ' ' || c=='\n' || c=='\t') {
+ state = CAMEL_HTML_PARSER_ATTR0;
+ } else {
+ g_string_append_c(p->tag, c);
+ }
+ break;
+ /* check for <!-- */
+ case CAMEL_HTML_PARSER_COMMENT0:
+ if (c == '-') {
+ g_string_append_c(p->tag, c);
+ if (p->tag->len == 3) {
+ g_string_truncate(p->tag, 0);
+ state = CAMEL_HTML_PARSER_COMMENT;
+ }
+ } else {
+ /* got something else, probbly dtd entity */
+ state = CAMEL_HTML_PARSER_DTDENT;
+ }
+ break;
+ case CAMEL_HTML_PARSER_DTDENT:
+ if (c == '>') {
+ ret = CAMEL_HTML_PARSER_DTDENT;
+ state = CAMEL_HTML_PARSER_DATA;
+ *datap = start;
+ *lenp = in-start-1;
+ goto done;
+ }
+ break;
+ case CAMEL_HTML_PARSER_COMMENT:
+ if (c == '>' && p->tag->len == 2) {
+ ret = CAMEL_HTML_PARSER_COMMENT;
+ state = CAMEL_HTML_PARSER_DATA;
+ *datap = start;
+ *lenp = in-start-1;
+ goto done;
+ } else if (c=='-') {
+ /* we dont care if we get 'n' --'s before the > */
+ if (p->tag->len < 2)
+ g_string_append_c(p->tag, c);
+ } else {
+ g_string_truncate(p->tag, 0);
+ }
+ break;
+ case CAMEL_HTML_PARSER_ATTR0: /* pre-attribute whitespace */
+ if (c == '>') {
+ d(dump_tag(p));
+ ret = CAMEL_HTML_PARSER_ELEMENT;
+ state = CAMEL_HTML_PARSER_DATA;
+ goto done;
+ } else if (c == ' ' || c=='\n' || c=='\t') {
+ } else {
+ if (p->attrs->len <= p->attr) {
+ g_ptr_array_add(p->attrs, g_string_new(""));
+ g_ptr_array_add(p->values, g_string_new(""));
+ } else {
+ g_string_truncate(p->attrs->pdata[p->attr], 0);
+ g_string_truncate(p->values->pdata[p->attr], 0);
+ }
+ g_string_append_c(p->attrs->pdata[p->attr], c);
+ state = CAMEL_HTML_PARSER_ATTR;
+ }
+ break;
+ case CAMEL_HTML_PARSER_ATTR:
+ if (c == '>') {
+ d(dump_tag(p));
+ ret = CAMEL_HTML_PARSER_ELEMENT;
+ state = CAMEL_HTML_PARSER_DATA;
+ goto done;
+ } else if (c == '=') {
+ state = CAMEL_HTML_PARSER_VAL0;
+ } else if (c == ' ' || c=='\n' || c=='\t') {
+ state = CAMEL_HTML_PARSER_ATTR0;
+ p->attr++;
+ } else {
+ g_string_append_c(p->attrs->pdata[p->attr], c);
+ }
+ break;
+ case CAMEL_HTML_PARSER_VAL0:
+ if (c == '>') {
+ d(printf("value truncated\n"));
+ d(dump_tag(p));
+ ret = CAMEL_HTML_PARSER_ELEMENT;
+ state = CAMEL_HTML_PARSER_DATA;
+ goto done;
+ } else if (c == '\'' || c == '\"') {
+ p->quote = c;
+ state = CAMEL_HTML_PARSER_VAL;
+ } else if (c == ' ' || c=='\n' || c=='\t') {
+ } else {
+ g_string_append_c(p->values->pdata[p->attr], c);
+ p->quote = 0;
+ state = CAMEL_HTML_PARSER_VAL;
+ }
+ break;
+ case CAMEL_HTML_PARSER_VAL:
+ do_val:
+ if (p->quote) {
+ if (c == '>') {
+ d(printf("value truncated\n"));
+ d(dump_tag(p));
+ ret = CAMEL_HTML_PARSER_ELEMENT;
+ state = CAMEL_HTML_PARSER_DATA;
+ p->attr++;
+ goto done;
+ } else if (c == p->quote) {
+ state = CAMEL_HTML_PARSER_ATTR0;
+ p->attr++;
+ } else if (c=='&') {
+ state = CAMEL_HTML_PARSER_VAL_ENT;
+ g_string_truncate(p->ent, 0);
+ } else {
+ g_string_append_c(p->values->pdata[p->attr], c);
+ }
+ } else if (c == '>') {
+ d(dump_tag(p));
+ ret = CAMEL_HTML_PARSER_ELEMENT;
+ state = CAMEL_HTML_PARSER_DATA;
+ p->attr++;
+ goto done;
+ } else if (c == ' ' || c=='\n' || c=='\t') {
+ state = CAMEL_HTML_PARSER_ATTR0;
+ p->attr++;
+ } else if (c=='&') {
+ state = CAMEL_HTML_PARSER_VAL_ENT;
+ g_string_truncate(p->ent, 0);
+ } else {
+ g_string_append_c(p->values->pdata[p->attr], c);
+ }
+ break;
+ case CAMEL_HTML_PARSER_VAL_ENT:
+ if (c==';') {
+ state = CAMEL_HTML_PARSER_VAL;
+ len = convert_entity(p->ent->str+1, p->ent_utf8);
+ if (len == 0) {
+ /* fallback; broken entity, just output it and see why we ended */
+ g_string_append(p->values->pdata[p->attr], p->ent->str);
+ g_string_append_c(p->values->pdata[p->attr], ';');
+ } else {
+ d(printf("got entity: %s = %s\n", p->ent->str, p->ent_utf8));
+ g_string_append(p->values->pdata[p->attr], p->ent_utf8);
+ }
+ } else if (isalnum(c) || c=='#') { /* FIXME: right type */
+ g_string_append_c(p->ent, c);
+ } else {
+ /* fallback; broken entity, just output it and see why we ended */
+ g_string_append(p->values->pdata[p->attr], p->ent->str);
+ goto do_val;
+ }
+ break;
+ }
+ }
+
+ if (p->eof) {
+ /* FIXME: what about other truncated states? */
+ switch (state) {
+ case CAMEL_HTML_PARSER_DATA:
+ case CAMEL_HTML_PARSER_COMMENT:
+ if (in > start) {
+ ret = state;
+ *datap = start;
+ *lenp = in-start-1;
+ } else {
+ ret = CAMEL_HTML_PARSER_EOF;
+ state = CAMEL_HTML_PARSER_EOF;
+ }
+ break;
+ default:
+ ret = CAMEL_HTML_PARSER_EOF;
+ state = CAMEL_HTML_PARSER_EOF;
+ }
+ } else {
+ /* we only care about remaining data for this buffer, everything else has its own copy */
+ switch (state) {
+ case CAMEL_HTML_PARSER_DATA:
+ case CAMEL_HTML_PARSER_COMMENT:
+ if (in > start) {
+ ret = state;
+ *datap = start;
+ *lenp = in-start-1;
+ } else {
+ ret = CAMEL_HTML_PARSER_EOD;
+ }
+ break;
+ default:
+ ret = CAMEL_HTML_PARSER_EOD;
+ }
+ }
+
+done:
+ p->start = start;
+ p->state = state;
+ p->inptr = in;
+
+ return ret;
+}
diff --git a/camel/camel-http-stream.c b/camel/camel-http-stream.c
new file mode 100644
index 0000000000..53c0241a2b
--- /dev/null
+++ b/camel/camel-http-stream.c
@@ -0,0 +1,612 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Jeffrey Stedfast <fejj@ximian.com>
+ *
+ * Copyright 2002 Ximian, Inc. (www.ximian.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "camel-http-stream.h"
+
+#include "camel-mime-utils.h"
+#include "camel-stream-buffer.h"
+#include "camel-tcp-stream-raw.h"
+#ifdef HAVE_SSL
+#include "camel-tcp-stream-ssl.h"
+#endif
+#include "camel-exception.h"
+#include "camel-session.h"
+#include "camel-service.h" /* for hostname stuff */
+
+#define d(x)
+
+static CamelStreamClass *parent_class = NULL;
+
+static ssize_t stream_read (CamelStream *stream, char *buffer, size_t n);
+static ssize_t stream_write (CamelStream *stream, const char *buffer, size_t n);
+static int stream_flush (CamelStream *stream);
+static int stream_close (CamelStream *stream);
+static int stream_reset (CamelStream *stream);
+
+static void
+camel_http_stream_class_init (CamelHttpStreamClass *camel_http_stream_class)
+{
+ CamelStreamClass *camel_stream_class =
+ CAMEL_STREAM_CLASS (camel_http_stream_class);
+
+ parent_class = CAMEL_STREAM_CLASS (camel_type_get_global_classfuncs (camel_stream_get_type ()));
+
+ /* virtual method overload */
+ camel_stream_class->read = stream_read;
+ camel_stream_class->write = stream_write;
+ camel_stream_class->flush = stream_flush;
+ camel_stream_class->close = stream_close;
+ camel_stream_class->reset = stream_reset;
+}
+
+static void
+camel_http_stream_init (gpointer object, gpointer klass)
+{
+ CamelHttpStream *http = CAMEL_HTTP_STREAM (object);
+
+ http->parser = NULL;
+ http->content_type = NULL;
+ http->headers = NULL;
+ http->session = NULL;
+ http->url = NULL;
+ http->proxy = NULL;
+ http->authrealm = NULL;
+ http->authpass = NULL;
+ http->statuscode = 0;
+ http->raw = NULL;
+}
+
+static void
+camel_http_stream_finalize (CamelObject *object)
+{
+ CamelHttpStream *http = CAMEL_HTTP_STREAM (object);
+
+ if (http->parser)
+ camel_object_unref(http->parser);
+
+ if (http->content_type)
+ camel_content_type_unref (http->content_type);
+
+ if (http->headers)
+ camel_header_raw_clear (&http->headers);
+
+ if (http->session)
+ camel_object_unref(http->session);
+
+ if (http->url)
+ camel_url_free (http->url);
+
+ if (http->proxy)
+ camel_url_free (http->proxy);
+
+ g_free (http->authrealm);
+ g_free (http->authpass);
+
+ if (http->raw)
+ camel_object_unref(http->raw);
+ if (http->read)
+ camel_object_unref(http->read);
+}
+
+CamelType
+camel_http_stream_get_type (void)
+{
+ static CamelType type = CAMEL_INVALID_TYPE;
+
+ if (type == CAMEL_INVALID_TYPE) {
+ type = camel_type_register (camel_stream_get_type (),
+ "CamelHttpStream",
+ sizeof (CamelHttpStream),
+ sizeof (CamelHttpStreamClass),
+ (CamelObjectClassInitFunc) camel_http_stream_class_init,
+ NULL,
+ (CamelObjectInitFunc) camel_http_stream_init,
+ (CamelObjectFinalizeFunc) camel_http_stream_finalize);
+ }
+
+ return type;
+}
+
+/**
+ * camel_http_stream_new:
+ * @method: HTTP method
+ * @session: active session
+ * @url: URL to act upon
+ *
+ * Return value: a http stream
+ **/
+CamelStream *
+camel_http_stream_new (CamelHttpMethod method, struct _CamelSession *session, CamelURL *url)
+{
+ CamelHttpStream *stream;
+ char *str;
+
+ g_return_val_if_fail(CAMEL_IS_SESSION(session), NULL);
+ g_return_val_if_fail(url != NULL, NULL);
+
+ stream = CAMEL_HTTP_STREAM (camel_object_new (camel_http_stream_get_type ()));
+
+ stream->method = method;
+ stream->session = session;
+ camel_object_ref(session);
+
+ str = camel_url_to_string (url, 0);
+ stream->url = camel_url_new (str, NULL);
+ g_free (str);
+
+ return (CamelStream *)stream;
+}
+
+#define SSL_FLAGS (CAMEL_TCP_STREAM_SSL_ENABLE_SSL2 | CAMEL_TCP_STREAM_SSL_ENABLE_SSL3)
+
+static CamelStream *
+http_connect (CamelHttpStream *http, CamelURL *url)
+{
+ CamelStream *stream = NULL;
+ struct addrinfo *ai, hints = { 0 };
+ int errsave;
+ char *serv;
+
+ d(printf("connecting to http stream @ '%s'\n", url->host));
+
+ if (!strcasecmp (url->protocol, "https")) {
+#ifdef HAVE_SSL
+ stream = camel_tcp_stream_ssl_new (http->session, url->host, SSL_FLAGS);
+#endif
+ } else {
+ stream = camel_tcp_stream_raw_new ();
+ }
+
+ if (stream == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if (url->port) {
+ serv = g_alloca(16);
+ sprintf(serv, "%d", url->port);
+ } else {
+ serv = url->protocol;
+ }
+ hints.ai_socktype = SOCK_STREAM;
+
+ ai = camel_getaddrinfo(url->host, serv, &hints, NULL);
+ if (ai == NULL) {
+ camel_object_unref (stream);
+ return NULL;
+ }
+
+ if (camel_tcp_stream_connect (CAMEL_TCP_STREAM (stream), ai) == -1) {
+ errsave = errno;
+ camel_object_unref (stream);
+ camel_freeaddrinfo(ai);
+ errno = errsave;
+ return NULL;
+ }
+
+ camel_freeaddrinfo(ai);
+
+ http->raw = stream;
+ http->read = camel_stream_buffer_new (stream, CAMEL_STREAM_BUFFER_READ);
+
+ return stream;
+}
+
+static void
+http_disconnect(CamelHttpStream *http)
+{
+ if (http->raw) {
+ camel_object_unref(http->raw);
+ http->raw = NULL;
+ }
+
+ if (http->read) {
+ camel_object_unref(http->read);
+ http->read = NULL;
+ }
+
+ if (http->parser) {
+ camel_object_unref(http->parser);
+ http->parser = NULL;
+ }
+}
+
+static const char *
+http_next_token (const unsigned char *in)
+{
+ const unsigned char *inptr = in;
+
+ while (*inptr && !isspace ((int) *inptr))
+ inptr++;
+
+ while (*inptr && isspace ((int) *inptr))
+ inptr++;
+
+ return (const char *) inptr;
+}
+
+static int
+http_get_statuscode (CamelHttpStream *http)
+{
+ const char *token;
+ char buffer[4096];
+
+ if (camel_stream_buffer_gets ((CamelStreamBuffer *)http->read, buffer, sizeof (buffer)) <= 0)
+ return -1;
+
+ d(printf("HTTP Status: %s\n", buffer));
+
+ /* parse the HTTP status code */
+ if (!strncasecmp (buffer, "HTTP/", 5)) {
+ token = http_next_token (buffer);
+ http->statuscode = camel_header_decode_int (&token);
+ return http->statuscode;
+ }
+
+ http_disconnect(http);
+
+ return -1;
+}
+
+static int
+http_get_headers (CamelHttpStream *http)
+{
+ struct _camel_header_raw *headers, *node, *tail;
+ const char *type;
+ char *buf;
+ size_t len;
+ int err;
+
+ if (http->parser)
+ camel_object_unref (http->parser);
+
+ http->parser = camel_mime_parser_new ();
+ camel_mime_parser_init_with_stream (http->parser, http->read);
+
+ switch (camel_mime_parser_step (http->parser, &buf, &len)) {
+ case CAMEL_MIME_PARSER_STATE_MESSAGE:
+ case CAMEL_MIME_PARSER_STATE_HEADER:
+ headers = camel_mime_parser_headers_raw (http->parser);
+ if (http->content_type)
+ camel_content_type_unref (http->content_type);
+ type = camel_header_raw_find (&headers, "Content-Type", NULL);
+ if (type)
+ http->content_type = camel_content_type_decode (type);
+ else
+ http->content_type = NULL;
+
+ if (http->headers)
+ camel_header_raw_clear (&http->headers);
+
+ http->headers = NULL;
+ tail = (struct _camel_header_raw *) &http->headers;
+
+ d(printf("HTTP Headers:\n"));
+ while (headers) {
+ d(printf(" %s:%s\n", headers->name, headers->value));
+ node = g_new (struct _camel_header_raw, 1);
+ node->next = NULL;
+ node->name = g_strdup (headers->name);
+ node->value = g_strdup (headers->value);
+ node->offset = headers->offset;
+ tail->next = node;
+ tail = node;
+ headers = headers->next;
+ }
+
+ break;
+ default:
+ g_warning ("Invalid state encountered???: %d", camel_mime_parser_state (http->parser));
+ }
+
+ err = camel_mime_parser_errno (http->parser);
+
+ if (err != 0) {
+ camel_object_unref (http->parser);
+ http->parser = NULL;
+ goto exception;
+ }
+
+ camel_mime_parser_drop_step (http->parser);
+
+ return 0;
+
+ exception:
+ http_disconnect(http);
+
+ return -1;
+}
+
+static int
+http_method_invoke (CamelHttpStream *http)
+{
+ const char *method = NULL;
+ char *url;
+
+ switch (http->method) {
+ case CAMEL_HTTP_METHOD_GET:
+ method = "GET";
+ break;
+ case CAMEL_HTTP_METHOD_HEAD:
+ method = "HEAD";
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ url = camel_url_to_string (http->url, 0);
+ d(printf("HTTP Stream Sending: %s %s HTTP/1.0\r\nUser-Agent: %s\r\nHost: %s\r\n",
+ method,
+ http->proxy ? url : http->url->path,
+ http->user_agent ? http->user_agent : "CamelHttpStream/1.0",
+ http->url->host));
+ if (camel_stream_printf (http->raw, "%s %s HTTP/1.0\r\nUser-Agent: %s\r\nHost: %s\r\n",
+ method,
+ http->proxy ? url : http->url->path,
+ http->user_agent ? http->user_agent : "CamelHttpStream/1.0",
+ http->url->host) == -1) {
+ http_disconnect(http);
+ g_free (url);
+ return -1;
+ }
+ g_free (url);
+
+ if (http->authrealm)
+ d(printf("HTTP Stream Sending: WWW-Authenticate: %s\n", http->authrealm));
+
+ if (http->authrealm && camel_stream_printf (http->raw, "WWW-Authenticate: %s\r\n", http->authrealm) == -1) {
+ http_disconnect(http);
+ return -1;
+ }
+
+ if (http->authpass && http->proxy)
+ d(printf("HTTP Stream Sending: Proxy-Aurhorization: Basic %s\n", http->authpass));
+
+ if (http->authpass && http->proxy && camel_stream_printf (http->raw, "Proxy-Authorization: Basic %s\r\n",
+ http->authpass) == -1) {
+ http_disconnect(http);
+ return -1;
+ }
+
+ /* end the headers */
+ if (camel_stream_write (http->raw, "\r\n", 2) == -1 || camel_stream_flush (http->raw) == -1) {
+ http_disconnect(http);
+ return -1;
+ }
+
+ return 0;
+}
+
+static ssize_t
+stream_read (CamelStream *stream, char *buffer, size_t n)
+{
+ CamelHttpStream *http = CAMEL_HTTP_STREAM (stream);
+ const char *parser_buf;
+ ssize_t nread;
+
+ if (http->method != CAMEL_HTTP_METHOD_GET && http->method != CAMEL_HTTP_METHOD_HEAD) {
+ errno = EIO;
+ return -1;
+ }
+
+ redirect:
+
+ if (!http->raw) {
+ if (http_connect (http, http->proxy ? http->proxy : http->url) == NULL)
+ return -1;
+
+ if (http_method_invoke (http) == -1)
+ return -1;
+
+ if (http_get_statuscode (http) == -1)
+ return -1;
+
+ if (http_get_headers (http) == -1)
+ return -1;
+
+ switch (http->statuscode) {
+ case 200:
+ case 206:
+ /* we are OK to go... */
+ break;
+ case 301:
+ case 302: {
+ char *loc;
+ CamelURL *url;
+
+ camel_content_type_unref (http->content_type);
+ http->content_type = NULL;
+ http_disconnect(http);
+
+ loc = g_strdup(camel_header_raw_find(&http->headers, "Location", NULL));
+ if (loc == NULL) {
+ camel_header_raw_clear(&http->headers);
+ return -1;
+ }
+
+ /* redirect... */
+ g_strstrip(loc);
+ d(printf("HTTP redirect, location = %s\n", loc));
+ url = camel_url_new_with_base(http->url, loc);
+ camel_url_free (http->url);
+ http->url = url;
+ if (url == NULL)
+ http->url = camel_url_new(loc, NULL);
+ g_free(loc);
+ if (http->url == NULL) {
+ camel_header_raw_clear (&http->headers);
+ return -1;
+ }
+ d(printf(" redirect url = %p\n", http->url));
+ camel_header_raw_clear (&http->headers);
+
+ goto redirect;
+ break; }
+ case 407:
+ /* failed proxy authentication? */
+ default:
+ /* unknown error */
+ http_disconnect(http);
+ return -1;
+ }
+ }
+
+ nread = camel_mime_parser_read (http->parser, &parser_buf, n);
+
+ if (nread > 0)
+ memcpy (buffer, parser_buf, nread);
+ else if (nread == 0)
+ stream->eos = TRUE;
+
+ return nread;
+}
+
+static ssize_t
+stream_write (CamelStream *stream, const char *buffer, size_t n)
+{
+ return -1;
+}
+
+static int
+stream_flush (CamelStream *stream)
+{
+ CamelHttpStream *http = (CamelHttpStream *) stream;
+
+ if (http->raw)
+ return camel_stream_flush (http->raw);
+ else
+ return 0;
+}
+
+static int
+stream_close (CamelStream *stream)
+{
+ CamelHttpStream *http = (CamelHttpStream *) stream;
+
+ if (http->raw) {
+ if (camel_stream_close (http->raw) == -1)
+ return -1;
+
+ http_disconnect(http);
+ }
+
+ return 0;
+}
+
+static int
+stream_reset (CamelStream *stream)
+{
+ CamelHttpStream *http = CAMEL_HTTP_STREAM (stream);
+
+ if (http->raw)
+ http_disconnect(http);
+
+ return 0;
+};
+
+CamelContentType *
+camel_http_stream_get_content_type (CamelHttpStream *http_stream)
+{
+ g_return_val_if_fail (CAMEL_IS_HTTP_STREAM (http_stream), NULL);
+
+ if (!http_stream->content_type && !http_stream->raw) {
+ if (http_connect (http_stream, http_stream->url) == NULL)
+ return NULL;
+
+ if (http_method_invoke (http_stream) == -1)
+ return NULL;
+
+ if (http_get_headers (http_stream) == -1)
+ return NULL;
+ }
+
+ if (http_stream->content_type)
+ camel_content_type_ref (http_stream->content_type);
+
+ return http_stream->content_type;
+}
+
+void
+camel_http_stream_set_user_agent (CamelHttpStream *http_stream, const char *user_agent)
+{
+ g_return_if_fail (CAMEL_IS_HTTP_STREAM (http_stream));
+
+ g_free (http_stream->user_agent);
+ http_stream->user_agent = g_strdup (user_agent);
+}
+
+void
+camel_http_stream_set_proxy (CamelHttpStream *http_stream, const char *proxy_url)
+{
+ g_return_if_fail (CAMEL_IS_HTTP_STREAM (http_stream));
+
+ if (http_stream->proxy)
+ camel_url_free (http_stream->proxy);
+
+ if (proxy_url == NULL)
+ http_stream->proxy = NULL;
+ else
+ http_stream->proxy = camel_url_new (proxy_url, NULL);
+
+ if (http_stream->proxy) {
+ char *basic, *basic64;
+
+ basic = g_strdup_printf("%s:%s", http_stream->proxy->user?http_stream->proxy->user:"",
+ http_stream->proxy->passwd?http_stream->proxy->passwd:"");
+ basic64 = camel_base64_encode_simple(basic, strlen(basic));
+ memset(basic, 0, strlen(basic));
+ g_free(basic);
+ camel_http_stream_set_proxy_authpass(http_stream, basic64);
+ memset(basic64, 0, strlen(basic64));
+ g_free(basic64);
+ } else {
+ camel_http_stream_set_proxy_authpass(http_stream, NULL);
+ }
+}
+
+void
+camel_http_stream_set_proxy_authrealm (CamelHttpStream *http_stream, const char *proxy_authrealm)
+{
+ g_return_if_fail (CAMEL_IS_HTTP_STREAM (http_stream));
+
+ g_free (http_stream->authrealm);
+ http_stream->authrealm = g_strdup (proxy_authrealm);
+}
+
+void
+camel_http_stream_set_proxy_authpass (CamelHttpStream *http_stream, const char *proxy_authpass)
+{
+ g_return_if_fail (CAMEL_IS_HTTP_STREAM (http_stream));
+
+ g_free (http_stream->authpass);
+ http_stream->authpass = g_strdup (proxy_authpass);
+}
diff --git a/camel/camel-lock-helper.c b/camel/camel-lock-helper.c
new file mode 100644
index 0000000000..9c97c83565
--- /dev/null
+++ b/camel/camel-lock-helper.c
@@ -0,0 +1,391 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2001 Ximian Inc.
+ *
+ * Authors: Michael Zucchi <notzed@ximian.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+/* lock helper process */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <errno.h>
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <signal.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <utime.h>
+
+#include <time.h>
+
+#include <string.h>
+
+#define SETEUID_SAVES (1)
+
+/* we try and include as little as possible */
+
+#include "camel-lock-helper.h"
+#include "camel-lock.h"
+
+#define d(x)
+
+/* keeps track of open locks */
+struct _lock_info {
+ struct _lock_info *next;
+ uid_t uid;
+ int id;
+ int depth;
+ time_t stamp; /* when last updated */
+ char path[1];
+};
+
+static int lock_id = 0;
+static struct _lock_info *lock_info_list;
+static uid_t lock_root_uid = -1;
+static uid_t lock_real_uid = -1;
+
+/* utility functions */
+
+static int read_n(int fd, void *buffer, int inlen)
+{
+ char *p = buffer;
+ int len, left = inlen;
+
+ do {
+ len = read(fd, p, left);
+ if (len == -1) {
+ if (errno != EINTR)
+ return -1;
+ } else {
+ left -= len;
+ p += len;
+ }
+ } while (left > 0 && len != 0);
+
+ return inlen - left;
+}
+
+static int write_n(int fd, void *buffer, int inlen)
+{
+ char *p = buffer;
+ int len, left = inlen;
+
+ do {
+ len = write(fd, p, left);
+ if (len == -1) {
+ if (errno != EINTR)
+ return -1;
+ } else {
+ left -= len;
+ p += len;
+ }
+ } while (left > 0);
+
+ return inlen;
+}
+
+void
+camel_exception_setv (CamelException *ex, ExceptionId id, const char *format, ...)
+{
+ ;
+}
+
+void
+camel_exception_clear (CamelException *exception)
+{
+ ;
+}
+
+char *gettext (const char *msgid);
+
+char *
+gettext (const char *msgid)
+{
+ return NULL;
+}
+
+static int lock_path(const char *path, guint32 *lockid)
+{
+ struct _lock_info *info = NULL;
+ int res = CAMEL_LOCK_HELPER_STATUS_OK;
+ struct stat st;
+
+ d(fprintf(stderr, "locking path '%s' id = %d\n", path, lock_id));
+
+ /* check to see if we have it locked already, make the lock 'recursive' */
+ /* we could also error i suppose, but why bother */
+ info = lock_info_list;
+ while (info) {
+ if (!strcmp(info->path, path)) {
+ info->depth++;
+ return CAMEL_LOCK_HELPER_STATUS_OK;
+ }
+ info = info->next;
+ }
+
+ /* check we are allowed to lock it, we must own it, be able to write to it, and it has to exist */
+ if (stat(path, &st) == -1
+ || st.st_uid != getuid()
+ || !S_ISREG(st.st_mode)
+ || (st.st_mode & 0400) == 0) {
+ return CAMEL_LOCK_HELPER_STATUS_INVALID;
+ }
+
+ info = malloc(sizeof(*info) + strlen(path));
+ if (info == NULL) {
+ res = CAMEL_LOCK_HELPER_STATUS_NOMEM;
+ goto fail;
+ }
+
+ /* we try the real uid first, and if that fails, try the 'root id' */
+ if (camel_lock_dot(path, NULL) == -1) {
+#ifdef SETEUID_SAVES
+ if (lock_real_uid != lock_root_uid) {
+ if (seteuid(lock_root_uid) != -1) {
+ if (camel_lock_dot(path, NULL) == -1) {
+ seteuid(lock_real_uid);
+ res = CAMEL_LOCK_HELPER_STATUS_SYSTEM;
+ goto fail;
+ }
+ seteuid(lock_real_uid);
+ } else {
+ res = CAMEL_LOCK_HELPER_STATUS_SYSTEM;
+ goto fail;
+ }
+ } else {
+ res = CAMEL_LOCK_HELPER_STATUS_SYSTEM;
+ goto fail;
+ }
+#else
+ res = CAMEL_LOCK_HELPER_STATUS_SYSTEM;
+ goto fail;
+#endif
+ } else {
+ info->uid = lock_real_uid;
+ }
+
+ strcpy(info->path, path);
+ info->id = lock_id;
+ info->depth = 1;
+ info->next = lock_info_list;
+ info->stamp = time(0);
+ lock_info_list = info;
+
+ if (lockid)
+ *lockid = lock_id;
+
+ lock_id++;
+
+ d(fprintf(stderr, "lock ok\n"));
+
+ return res;
+fail:
+ d(fprintf(stderr, "lock failed\n"));
+
+ if (info)
+ free(info);
+
+ return res;
+}
+
+static int unlock_id(guint32 lockid)
+{
+ struct _lock_info *info, *p;
+
+ d(fprintf(stderr, "unlocking id '%d'\n", lockid));
+
+ p = (struct _lock_info *)&lock_info_list;
+ info = p->next;
+ while (info) {
+ if (info->id == lockid) {
+ d(fprintf(stderr, "found id %d path '%s'\n", lockid, info->path));
+ info->depth--;
+ if (info->depth <= 0) {
+#ifdef SETEUID_SAVES
+ if (info->uid != lock_real_uid) {
+ seteuid(lock_root_uid);
+ camel_unlock_dot(info->path);
+ seteuid(lock_real_uid);
+ } else
+#endif
+ camel_unlock_dot(info->path);
+
+ p->next = info->next;
+ free(info);
+ }
+
+ return CAMEL_LOCK_HELPER_STATUS_OK;
+ }
+ p = info;
+ info = info->next;
+ }
+
+ d(fprintf(stderr, "unknown id asked to be unlocked %d\n", lockid));
+ return CAMEL_LOCK_HELPER_STATUS_PROTOCOL;
+}
+
+static void lock_touch(const char *path)
+{
+ char *name;
+
+ /* we could also check that we haven't had our lock stolen from us here */
+
+ name = alloca(strlen(path) + 10);
+ sprintf(name, "%s.lock", path);
+
+ d(fprintf(stderr, "Updating lock %s\n", name));
+ utime(name, NULL);
+}
+
+static void setup_process(void)
+{
+ struct sigaction sa;
+ sigset_t sigset;
+
+ /* ignore sigint/sigio */
+ sa.sa_handler = SIG_IGN;
+ sigemptyset (&sa.sa_mask);
+ sa.sa_flags = 0;
+
+ sigemptyset(&sigset);
+ sigaddset(&sigset, SIGIO);
+ sigaddset(&sigset, SIGINT);
+ sigprocmask(SIG_UNBLOCK, &sigset, NULL);
+
+ sigaction (SIGIO, &sa, NULL);
+ sigaction (SIGINT, &sa, NULL);
+
+ /* FIXME: add more sanity checks/setup here */
+
+#ifdef SETEUID_SAVES
+ /* here we change to the real user id, this is probably not particularly
+ portable so may need configure checks */
+ lock_real_uid = getuid();
+ lock_root_uid = geteuid();
+ if (lock_real_uid != lock_root_uid)
+ seteuid(lock_real_uid);
+#endif
+}
+
+int main(int argc, char **argv)
+{
+ struct _CamelLockHelperMsg msg;
+ int len;
+ int res;
+ char *path;
+ fd_set rset;
+ struct timeval tv;
+ struct _lock_info *info;
+
+ setup_process();
+
+ do {
+ /* do a poll/etc, so we can refresh the .locks as required ... */
+ FD_ZERO(&rset);
+ FD_SET(STDIN_FILENO, &rset);
+
+ /* check the minimum timeout we need to refresh the next oldest lock */
+ if (lock_info_list) {
+ time_t now = time(0);
+ time_t left;
+ time_t delay = CAMEL_DOT_LOCK_REFRESH;
+
+ info = lock_info_list;
+ while (info) {
+ left = CAMEL_DOT_LOCK_REFRESH - (now - info->stamp);
+ left = MAX(left, 0);
+ delay = MIN(left, delay);
+ info = info->next;
+ }
+
+ tv.tv_sec = delay;
+ tv.tv_usec = 0;
+ }
+
+ d(fprintf(stderr, "lock helper waiting for input\n"));
+ if (select(STDIN_FILENO+1, &rset, NULL, NULL, lock_info_list?&tv:NULL) == -1) {
+ if (errno == EINTR)
+ break;
+
+ continue;
+ }
+
+ /* did we get a timeout? scan for any locks that need updating */
+ if (!FD_ISSET(STDIN_FILENO, &rset)) {
+ time_t now = time(0);
+ time_t left;
+
+ d(fprintf(stderr, "Got a timeout, checking locks\n"));
+
+ info = lock_info_list;
+ while (info) {
+ left = (now - info->stamp);
+ if (left >= CAMEL_DOT_LOCK_REFRESH) {
+ lock_touch(info->path);
+ info->stamp = now;
+ }
+ info = info->next;
+ }
+
+ continue;
+ }
+
+
+ len = read_n(STDIN_FILENO, &msg, sizeof(msg));
+ if (len == 0)
+ break;
+
+ res = CAMEL_LOCK_HELPER_STATUS_PROTOCOL;
+ if (len == sizeof(msg) && msg.magic == CAMEL_LOCK_HELPER_MAGIC) {
+ switch(msg.id) {
+ case CAMEL_LOCK_HELPER_LOCK:
+ res = CAMEL_LOCK_HELPER_STATUS_NOMEM;
+ if (msg.data > 0xffff) {
+ res = CAMEL_LOCK_HELPER_STATUS_PROTOCOL;
+ } else if ((path = malloc(msg.data+1)) != NULL) {
+ res = CAMEL_LOCK_HELPER_STATUS_PROTOCOL;
+ len = read_n(STDIN_FILENO, path, msg.data);
+ if (len == msg.data) {
+ path[len] = 0;
+ res = lock_path(path, &msg.data);
+ }
+ free(path);
+ }
+ break;
+ case CAMEL_LOCK_HELPER_UNLOCK:
+ res = unlock_id(msg.data);
+ break;
+ }
+ }
+ d(fprintf(stderr, "returning result %d\n", res));
+ msg.id = res;
+ msg.magic = CAMEL_LOCK_HELPER_RETURN_MAGIC;
+ write_n(STDOUT_FILENO, &msg, sizeof(msg));
+ } while (1);
+
+ d(fprintf(stderr, "parent exited, clsoing down remaining id's\n"));
+ while (lock_info_list)
+ unlock_id(lock_info_list->id);
+
+ return 0;
+}
diff --git a/camel/camel-lock.c b/camel/camel-lock.c
new file mode 100644
index 0000000000..eeae181f5b
--- /dev/null
+++ b/camel/camel-lock.c
@@ -0,0 +1,423 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Author: Michael Zucchi <notzed@ximian.com>
+ *
+ * Copyright (C) 1999 Ximian (www.ximian.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#endif
+#include <time.h>
+
+#ifdef USE_DOT
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#endif
+
+#ifdef USE_FCNTL
+#include <unistd.h>
+#include <fcntl.h>
+#endif
+
+#ifdef USE_FLOCK
+#include <sys/file.h>
+#endif
+
+#include <glib.h>
+
+#include "camel-lock.h"
+#include "camel-i18n.h"
+
+#define d(x) /*(printf("%s(%d): ", __FILE__, __LINE__),(x))*/
+
+/**
+ * camel_lock_dot:
+ * @path:
+ * @ex:
+ *
+ * Create an exclusive lock using .lock semantics.
+ * All locks are equivalent to write locks (exclusive).
+ *
+ * Return value: -1 on error, sets @ex appropriately.
+ **/
+int
+camel_lock_dot(const char *path, CamelException *ex)
+{
+#ifdef USE_DOT
+ char *locktmp, *lock;
+ int retry = 0;
+ int fdtmp;
+ struct stat st;
+
+ /* TODO: Is there a reliable way to refresh the lock, if we're still busy with it?
+ Does it matter? We will normally also use fcntl too ... */
+
+ /* use alloca, save cleaning up afterwards */
+ lock = alloca(strlen(path) + strlen(".lock") + 1);
+ sprintf(lock, "%s.lock", path);
+ locktmp = alloca(strlen(path) + strlen("XXXXXX") + 1);
+
+#ifndef HAVE_MKSTEMP
+ sprintf(locktmp, "%sXXXXXX", path);
+ if (mktemp(locktmp) == NULL) {
+ /* well, this is really only a programatic error */
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Could not create lock file for %s: %s"),
+ path, g_strerror (errno));
+ return -1;
+ }
+#endif
+
+ while (retry < CAMEL_LOCK_DOT_RETRY) {
+
+ d(printf("trying to lock '%s', attempt %d\n", lock, retry));
+
+ if (retry > 0)
+ sleep(CAMEL_LOCK_DOT_DELAY);
+
+#ifdef HAVE_MKSTEMP
+ sprintf(locktmp, "%sXXXXXX", path);
+ fdtmp = mkstemp(locktmp);
+#else
+ fdtmp = open(locktmp, O_RDWR|O_CREAT|O_EXCL, 0600);
+#endif
+ if (fdtmp == -1) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Could not create lock file for %s: %s"),
+ path, g_strerror (errno));
+ return -1;
+ }
+ close(fdtmp);
+
+ /* apparently return code from link can be unreliable for nfs (see link(2)), so we ignore it */
+ link(locktmp, lock);
+
+ /* but we check stat instead (again, see link(2)) */
+ if (stat(locktmp, &st) == -1) {
+ d(printf("Our lock file %s vanished!?\n", locktmp));
+
+ /* well that was unexpected, try cleanup/retry */
+ unlink(locktmp);
+ unlink(lock);
+ } else {
+ d(printf("tmp lock created, link count is %d\n", st.st_nlink));
+
+ unlink(locktmp);
+
+ /* if we had 2 links, we have created the .lock, return ok, otherwise we need to keep trying */
+ if (st.st_nlink == 2)
+ return 0;
+ }
+
+ /* check for stale lock, kill it */
+ if (stat(lock, &st) == 0) {
+ time_t now = time(0);
+ (printf("There is an existing lock %ld seconds old\n", now-st.st_ctime));
+ if (st.st_ctime < now - CAMEL_LOCK_DOT_STALE) {
+ d(printf("Removing it now\n"));
+ unlink(lock);
+ }
+ }
+
+ retry++;
+ }
+
+ d(printf("failed to get lock after %d retries\n", retry));
+
+ camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, _("Timed out trying to get lock file on %s. Try again later."), path);
+ return -1;
+#else /* ! USE_DOT */
+ return 0;
+#endif
+}
+
+/**
+ * camel_unlock_dot:
+ * @path:
+ *
+ * Attempt to unlock a .lock lock.
+ **/
+void
+camel_unlock_dot(const char *path)
+{
+#ifdef USE_DOT
+ char *lock;
+
+ lock = alloca(strlen(path) + strlen(".lock") + 1);
+ sprintf(lock, "%s.lock", path);
+ d(printf("unlocking %s\n", lock));
+ (void)unlink(lock);
+#endif
+}
+
+/**
+ * camel_lock_fcntl:
+ * @fd:
+ * @type:
+ * @ex:
+ *
+ * Create a lock using fcntl(2).
+ *
+ * @type is CAMEL_LOCK_WRITE or CAMEL_LOCK_READ,
+ * to create exclusive or shared read locks
+ *
+ * Return value: -1 on error.
+ **/
+int
+camel_lock_fcntl(int fd, CamelLockType type, CamelException *ex)
+{
+#ifdef USE_FCNTL
+ struct flock lock;
+
+ d(printf("fcntl locking %d\n", fd));
+
+ memset(&lock, 0, sizeof(lock));
+ lock.l_type = type==CAMEL_LOCK_READ?F_RDLCK:F_WRLCK;
+ if (fcntl(fd, F_SETLK, &lock) == -1) {
+ /* If we get a 'locking not vailable' type error,
+ we assume the filesystem doesn't support fcntl() locking */
+ /* this is somewhat system-dependent */
+ if (errno != EINVAL && errno != ENOLCK) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Failed to get lock using fcntl(2): %s"),
+ g_strerror (errno));
+ return -1;
+ } else {
+ static int failed = 0;
+
+ if (failed == 0)
+ fprintf(stderr, "fcntl(2) locking appears not to work on this filesystem");
+ failed++;
+ }
+ }
+#endif
+ return 0;
+}
+
+/**
+ * camel_unlock_fcntl:
+ * @fd:
+ *
+ * Unlock an fcntl lock.
+ **/
+void
+camel_unlock_fcntl(int fd)
+{
+#ifdef USE_FCNTL
+ struct flock lock;
+
+ d(printf("fcntl unlocking %d\n", fd));
+
+ memset(&lock, 0, sizeof(lock));
+ lock.l_type = F_UNLCK;
+ fcntl(fd, F_SETLK, &lock);
+#endif
+}
+
+/**
+ * camel_lock_flock:
+ * @fd:
+ * @type:
+ * @ex:
+ *
+ * Create a lock using flock(2).
+ *
+ * @type is CAMEL_LOCK_WRITE or CAMEL_LOCK_READ,
+ * to create exclusive or shared read locks
+ *
+ * Return value: -1 on error.
+ **/
+int
+camel_lock_flock(int fd, CamelLockType type, CamelException *ex)
+{
+#ifdef USE_FLOCK
+ int op;
+
+ d(printf("flock locking %d\n", fd));
+
+ if (type == CAMEL_LOCK_READ)
+ op = LOCK_SH|LOCK_NB;
+ else
+ op = LOCK_EX|LOCK_NB;
+
+ if (flock(fd, op) == -1) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Failed to get lock using flock(2): %s"),
+ g_strerror (errno));
+ return -1;
+ }
+#endif
+ return 0;
+}
+
+/**
+ * camel_unlock_flock:
+ * @fd:
+ *
+ * Unlock an flock lock.
+ **/
+void
+camel_unlock_flock(int fd)
+{
+#ifdef USE_FLOCK
+ d(printf("flock unlocking %d\n", fd));
+
+ (void)flock(fd, LOCK_UN);
+#endif
+}
+
+/**
+ * camel_lock_folder:
+ * @path: Path to the file to lock (used for .locking only).
+ * @fd: Open file descriptor of the right type to lock.
+ * @type: Type of lock, CAMEL_LOCK_READ or CAMEL_LOCK_WRITE.
+ * @ex:
+ *
+ * Attempt to lock a folder, multiple attempts will be made using all
+ * locking strategies available.
+ *
+ * Return value: -1 on error, @ex will describe the locking system that failed.
+ **/
+int
+camel_lock_folder(const char *path, int fd, CamelLockType type, CamelException *ex)
+{
+ int retry = 0;
+
+ while (retry < CAMEL_LOCK_RETRY) {
+ if (retry > 0)
+ sleep(CAMEL_LOCK_DELAY);
+
+ if (camel_lock_fcntl(fd, type, ex) == 0) {
+ if (camel_lock_flock(fd, type, ex) == 0) {
+ if (camel_lock_dot(path, ex) == 0)
+ return 0;
+ camel_unlock_flock(fd);
+ }
+ camel_unlock_fcntl(fd);
+ }
+ retry++;
+ }
+
+ return -1;
+}
+
+/**
+ * camel_unlock_folder:
+ * @path: Filename of folder.
+ * @fd: Open descrptor on which locks were placed.
+ *
+ * Free a lock on a folder.
+ **/
+void
+camel_unlock_folder(const char *path, int fd)
+{
+ camel_unlock_dot(path);
+ camel_unlock_flock(fd);
+ camel_unlock_fcntl(fd);
+}
+
+#if 0
+int main(int argc, char **argv)
+{
+ CamelException *ex;
+ int fd1, fd2;
+
+ ex = camel_exception_new();
+
+#if 0
+ if (camel_lock_dot("mylock", ex) == 0) {
+ if (camel_lock_dot("mylock", ex) == 0) {
+ printf("Got lock twice?\n");
+ } else {
+ printf("failed to get lock 2: %s\n", camel_exception_get_description(ex));
+ }
+ camel_unlock_dot("mylock");
+ } else {
+ printf("failed to get lock 1: %s\n", camel_exception_get_description(ex));
+ }
+
+ camel_exception_clear(ex);
+#endif
+
+ fd1 = open("mylock", O_RDWR);
+ fd2 = open("mylock", O_RDWR);
+
+ if (camel_lock_fcntl(fd1, CAMEL_LOCK_WRITE, ex) == 0) {
+ printf("got fcntl write lock once\n");
+ sleep(5);
+ if (camel_lock_fcntl(fd2, CAMEL_LOCK_WRITE, ex) == 0) {
+ printf("got fcntl write lock twice!\n");
+ } else {
+ printf("failed to get write lock: %s\n", camel_exception_get_description(ex));
+ }
+
+ camel_exception_clear(ex);
+
+ if (camel_lock_fcntl(fd2, CAMEL_LOCK_READ, ex) == 0) {
+ printf("got fcntl read lock as well?\n");
+ camel_unlock_fcntl(fd2);
+ } else {
+ printf("failed to get read lock: %s\n", camel_exception_get_description(ex));
+ }
+
+ camel_exception_clear(ex);
+ camel_unlock_fcntl(fd1);
+ } else {
+ printf("failed to get write lock at all: %s\n", camel_exception_get_description(ex));
+ }
+
+ if (camel_lock_fcntl(fd1, CAMEL_LOCK_READ, ex) == 0) {
+ printf("got fcntl read lock once\n");
+ sleep(5);
+ if (camel_lock_fcntl(fd2, CAMEL_LOCK_WRITE, ex) == 0) {
+ printf("got fcntl write lock too?!\n");
+ } else {
+ printf("failed to get write lock: %s\n", camel_exception_get_description(ex));
+ }
+
+ camel_exception_clear(ex);
+
+ if (camel_lock_fcntl(fd2, CAMEL_LOCK_READ, ex) == 0) {
+ printf("got fcntl read lock twice\n");
+ camel_unlock_fcntl(fd2);
+ } else {
+ printf("failed to get read lock: %s\n", camel_exception_get_description(ex));
+ }
+
+ camel_exception_clear(ex);
+ camel_unlock_fcntl(fd1);
+ }
+
+ close(fd1);
+ close(fd2);
+
+ return 0;
+}
+#endif
diff --git a/camel/camel-mime-filter-canon.c b/camel/camel-mime-filter-canon.c
new file mode 100644
index 0000000000..121d49311e
--- /dev/null
+++ b/camel/camel-mime-filter-canon.c
@@ -0,0 +1,190 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2002 Ximian, Inc.
+ *
+ * Authors: Jeffrey Stedfast <fejj@ximian.com>
+ * Michael Zucchi <notzed@ximian.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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* canonicalisation filter, used for secure mime incoming and outgoing */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <ctype.h>
+
+#include "camel-mime-filter-canon.h"
+
+static void filter (CamelMimeFilter *f, char *in, size_t len, size_t prespace,
+ char **out, size_t *outlen, size_t *outprespace);
+static void complete (CamelMimeFilter *f, char *in, size_t len,
+ size_t prespace, char **out, size_t *outlen,
+ size_t *outprespace);
+static void reset (CamelMimeFilter *f);
+
+
+static void
+camel_mime_filter_canon_class_init (CamelMimeFilterCanonClass *klass)
+{
+ CamelMimeFilterClass *mime_filter_class = (CamelMimeFilterClass *) klass;
+
+ mime_filter_class->filter = filter;
+ mime_filter_class->complete = complete;
+ mime_filter_class->reset = reset;
+}
+
+CamelType
+camel_mime_filter_canon_get_type (void)
+{
+ static CamelType type = CAMEL_INVALID_TYPE;
+
+ if (type == CAMEL_INVALID_TYPE) {
+ type = camel_type_register (camel_mime_filter_get_type(), "CamelMimeFilterCanon",
+ sizeof (CamelMimeFilterCanon),
+ sizeof (CamelMimeFilterCanonClass),
+ (CamelObjectClassInitFunc) camel_mime_filter_canon_class_init,
+ NULL,
+ NULL,
+ NULL);
+ }
+
+ return type;
+}
+
+static void
+filter_run(CamelMimeFilter *f, char *in, size_t len, size_t prespace, char **out, size_t *outlen, size_t *outprespace, int last)
+{
+ register unsigned char *inptr, c;
+ const unsigned char *inend, *start;
+ char *starto;
+ register char *o;
+ int lf = 0;
+ guint32 flags;
+
+ flags = ((CamelMimeFilterCanon *)f)->flags;
+
+ /* first, work out how much space we need */
+ inptr = in;
+ inend = in+len;
+ while (inptr < inend)
+ if (*inptr++ == '\n')
+ lf++;
+
+ /* worst case, extra 3 chars per line
+ "From \n" -> "=46rom \r\n"
+ We add 1 extra incase we're called from complete, when we didn't end in \n */
+
+ camel_mime_filter_set_size(f, len+lf*3+4, FALSE);
+
+ o = f->outbuf;
+ inptr = in;
+ start = inptr;
+ starto = o;
+ while (inptr < inend) {
+ /* first, check start of line, we always start at the start of the line */
+ c = *inptr;
+ if (flags & CAMEL_MIME_FILTER_CANON_FROM && c == 'F') {
+ inptr++;
+ if (inptr < inend-4) {
+ if (strncmp(inptr, "rom ", 4) == 0) {
+ strcpy(o, "=46rom ");
+ inptr+=4;
+ o+= 7;
+ } else
+ *o++ = 'F';
+ } else if (last)
+ *o++ = 'F';
+ else
+ break;
+ }
+
+ /* now scan for end of line */
+ while (inptr < inend) {
+ c = *inptr++;
+ if (c == '\n') {
+ /* check to strip trailing space */
+ if (flags & CAMEL_MIME_FILTER_CANON_STRIP) {
+ while (o>starto && (o[-1] == ' ' || o[-1] == '\t' || o[-1]=='\r'))
+ o--;
+ }
+ /* check end of line canonicalisation */
+ if (o>starto) {
+ if (flags & CAMEL_MIME_FILTER_CANON_CRLF) {
+ if (o[-1] != '\r')
+ *o++ = '\r';
+ } else {
+ if (o[-1] == '\r')
+ o--;
+ }
+ } else if (flags & CAMEL_MIME_FILTER_CANON_CRLF) {
+ /* empty line */
+ *o++ = '\r';
+ }
+
+ *o++ = c;
+ start = inptr;
+ starto = o;
+ break;
+ } else
+ *o++ = c;
+ }
+ }
+
+ /* TODO: We should probably track if we end somewhere in the middle of a line,
+ otherwise we potentially backup a full line, which could be large */
+
+ /* we got to the end of the data without finding anything, backup to start and re-process next time around */
+ if (last) {
+ *outlen = o - f->outbuf;
+ } else {
+ camel_mime_filter_backup(f, start, inend - start);
+ *outlen = starto - f->outbuf;
+ }
+
+ *out = f->outbuf;
+ *outprespace = f->outpre;
+}
+
+static void
+filter(CamelMimeFilter *f, char *in, size_t len, size_t prespace, char **out, size_t *outlen, size_t *outprespace)
+{
+ filter_run(f, in, len, prespace, out, outlen, outprespace, FALSE);
+}
+
+static void
+complete(CamelMimeFilter *f, char *in, size_t len, size_t prespace, char **out, size_t *outlen, size_t *outprespace)
+{
+ filter_run(f, in, len, prespace, out, outlen, outprespace, TRUE);
+}
+
+static void
+reset (CamelMimeFilter *f)
+{
+ /* no-op */
+}
+
+CamelMimeFilter *
+camel_mime_filter_canon_new(guint32 flags)
+{
+ CamelMimeFilterCanon *chomp = CAMEL_MIME_FILTER_CANON (camel_object_new (CAMEL_MIME_FILTER_CANON_TYPE));
+
+ chomp->flags = flags;
+
+ return (CamelMimeFilter *) chomp;
+}
diff --git a/camel/camel-mime-filter-enriched.c b/camel/camel-mime-filter-enriched.c
new file mode 100644
index 0000000000..4a679e3ced
--- /dev/null
+++ b/camel/camel-mime-filter-enriched.c
@@ -0,0 +1,603 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Jeffrey Stedfast <fejj@ximian.com>
+ *
+ * Copyright 2002 Ximian, Inc. (www.ximian.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include <camel/camel-string-utils.h>
+
+#include "camel-mime-filter-enriched.h"
+
+/* text/enriched is rfc1896 */
+
+typedef char * (*EnrichedParamParser) (const char *inptr, int inlen);
+
+static char *param_parse_colour (const char *inptr, int inlen);
+static char *param_parse_font (const char *inptr, int inlen);
+static char *param_parse_lang (const char *inptr, int inlen);
+
+static struct {
+ char *enriched;
+ char *html;
+ gboolean needs_param;
+ EnrichedParamParser parse_param; /* parses *and* validates the input */
+} enriched_tags[] = {
+ { "bold", "<b>", FALSE, NULL },
+ { "/bold", "</b>", FALSE, NULL },
+ { "italic", "<i>", FALSE, NULL },
+ { "/italic", "</i>", FALSE, NULL },
+ { "fixed", "<tt>", FALSE, NULL },
+ { "/fixed", "</tt>", FALSE, NULL },
+ { "smaller", "<font size=-1>", FALSE, NULL },
+ { "/smaller", "</font>", FALSE, NULL },
+ { "bigger", "<font size=+1>", FALSE, NULL },
+ { "/bigger", "</font>", FALSE, NULL },
+ { "underline", "<u>", FALSE, NULL },
+ { "/underline", "</u>", FALSE, NULL },
+ { "center", "<p align=center>", FALSE, NULL },
+ { "/center", "</p>", FALSE, NULL },
+ { "flushleft", "<p align=left>", FALSE, NULL },
+ { "/flushleft", "</p>", FALSE, NULL },
+ { "flushright", "<p align=right>", FALSE, NULL },
+ { "/flushright", "</p>", FALSE, NULL },
+ { "excerpt", "<blockquote>", FALSE, NULL },
+ { "/excerpt", "</blockquote>", FALSE, NULL },
+ { "paragraph", "<p>", FALSE, NULL },
+ { "signature", "<address>", FALSE, NULL },
+ { "/signature", "</address>", FALSE, NULL },
+ { "comment", "<!-- ", FALSE, NULL },
+ { "/comment", " -->", FALSE, NULL },
+ { "np", "<hr>", FALSE, NULL },
+ { "fontfamily", "<font face=\"%s\">", TRUE, param_parse_font },
+ { "/fontfamily", "</font>", FALSE, NULL },
+ { "color", "<font color=\"%s\">", TRUE, param_parse_colour },
+ { "/color", "</font>", FALSE, NULL },
+ { "lang", "<span lang=\"%s\">", TRUE, param_parse_lang },
+ { "/lang", "</span>", FALSE, NULL },
+
+ /* don't handle this tag yet... */
+ { "paraindent", "<!-- ", /* TRUE */ FALSE, NULL },
+ { "/paraindent", " -->", FALSE, NULL },
+
+ /* as soon as we support all the tags that can have a param
+ * tag argument, these should be unnecessary, but we'll keep
+ * them anyway just in case? */
+ { "param", "<!-- ", FALSE, NULL },
+ { "/param", " -->", FALSE, NULL },
+};
+
+#define NUM_ENRICHED_TAGS (sizeof (enriched_tags) / sizeof (enriched_tags[0]))
+
+static GHashTable *enriched_hash = NULL;
+
+
+static void camel_mime_filter_enriched_class_init (CamelMimeFilterEnrichedClass *klass);
+static void camel_mime_filter_enriched_init (CamelMimeFilterEnriched *filter);
+static void camel_mime_filter_enriched_finalize (CamelObject *obj);
+
+static void filter_filter (CamelMimeFilter *filter, char *in, size_t len, size_t prespace,
+ char **out, size_t *outlen, size_t *outprespace);
+static void filter_complete (CamelMimeFilter *filter, char *in, size_t len, size_t prespace,
+ char **out, size_t *outlen, size_t *outprespace);
+static void filter_reset (CamelMimeFilter *filter);
+
+
+static CamelMimeFilterClass *parent_class = NULL;
+
+
+CamelType
+camel_mime_filter_enriched_get_type (void)
+{
+ static CamelType type = CAMEL_INVALID_TYPE;
+
+ if (type == CAMEL_INVALID_TYPE) {
+ type = camel_type_register (camel_mime_filter_get_type (),
+ "CamelMimeFilterEnriched",
+ sizeof (CamelMimeFilterEnriched),
+ sizeof (CamelMimeFilterEnrichedClass),
+ (CamelObjectClassInitFunc) camel_mime_filter_enriched_class_init,
+ NULL,
+ (CamelObjectInitFunc) camel_mime_filter_enriched_init,
+ (CamelObjectFinalizeFunc) camel_mime_filter_enriched_finalize);
+ }
+
+ return type;
+}
+
+static void
+camel_mime_filter_enriched_class_init (CamelMimeFilterEnrichedClass *klass)
+{
+ CamelMimeFilterClass *filter_class = (CamelMimeFilterClass *) klass;
+ int i;
+
+ parent_class = CAMEL_MIME_FILTER_CLASS (camel_mime_filter_get_type ());
+
+ filter_class->reset = filter_reset;
+ filter_class->filter = filter_filter;
+ filter_class->complete = filter_complete;
+
+ if (!enriched_hash) {
+ enriched_hash = g_hash_table_new (camel_strcase_hash, camel_strcase_equal);
+ for (i = 0; i < NUM_ENRICHED_TAGS; i++)
+ g_hash_table_insert (enriched_hash, enriched_tags[i].enriched,
+ enriched_tags[i].html);
+ }
+}
+
+static void
+camel_mime_filter_enriched_finalize (CamelObject *obj)
+{
+ ;
+}
+
+static void
+camel_mime_filter_enriched_init (CamelMimeFilterEnriched *filter)
+{
+ filter->flags = 0;
+ filter->nofill = 0;
+}
+
+
+#if 0
+static gboolean
+enriched_tag_needs_param (const char *tag)
+{
+ int i;
+
+ for (i = 0; i < NUM_ENRICHED_TAGS; i++)
+ if (!g_ascii_strcasecmp (tag, enriched_tags[i].enriched))
+ return enriched_tags[i].needs_param;
+
+ return FALSE;
+}
+#endif
+
+static gboolean
+html_tag_needs_param (const char *tag)
+{
+ return strstr (tag, "%s") != NULL;
+}
+
+static const char *valid_colours[] = {
+ "red", "green", "blue", "yellow", "cyan", "magenta", "black", "white"
+};
+
+#define NUM_VALID_COLOURS (sizeof (valid_colours) / sizeof (valid_colours[0]))
+
+static char *
+param_parse_colour (const char *inptr, int inlen)
+{
+ const char *inend, *end;
+ guint32 rgb = 0;
+ guint v;
+ int i;
+
+ for (i = 0; i < NUM_VALID_COLOURS; i++) {
+ if (!strncasecmp (inptr, valid_colours[i], inlen))
+ return g_strdup (valid_colours[i]);
+ }
+
+ /* check for numeric r/g/b in the format: ####,####,#### */
+ if (inptr[4] != ',' || inptr[9] != ',') {
+ /* okay, mailer must have used a string name that
+ * rfc1896 did not specify? do some simple scanning
+ * action, a colour name MUST be [a-zA-Z] */
+ end = inptr;
+ inend = inptr + inlen;
+ while (end < inend && ((*end >= 'a' && *end <= 'z') || (*end >= 'A' && *end <= 'Z')))
+ end++;
+
+ return g_strndup (inptr, end - inptr);
+ }
+
+ for (i = 0; i < 3; i++) {
+ v = strtoul (inptr, (char **) &end, 16);
+ if (end != inptr + 4)
+ goto invalid_format;
+
+ v >>= 8;
+ rgb = (rgb << 8) | (v & 0xff);
+
+ inptr += 5;
+ }
+
+ return g_strdup_printf ("#%.6X", rgb);
+
+ invalid_format:
+
+ /* default colour? */
+ return g_strdup ("black");
+}
+
+static char *
+param_parse_font (const char *fontfamily, int inlen)
+{
+ register const char *inptr = fontfamily;
+ const char *inend = inptr + inlen;
+
+ /* don't allow any of '"', '<', nor '>' */
+ while (inptr < inend && *inptr != '"' && *inptr != '<' && *inptr != '>')
+ inptr++;
+
+ return g_strndup (fontfamily, inptr - fontfamily);
+}
+
+static char *
+param_parse_lang (const char *lang, int inlen)
+{
+ register const char *inptr = lang;
+ const char *inend = inptr + inlen;
+
+ /* don't allow any of '"', '<', nor '>' */
+ while (inptr < inend && *inptr != '"' && *inptr != '<' && *inptr != '>')
+ inptr++;
+
+ return g_strndup (lang, inptr - lang);
+}
+
+static char *
+param_parse (const char *enriched, const char *inptr, int inlen)
+{
+ int i;
+
+ for (i = 0; i < NUM_ENRICHED_TAGS; i++) {
+ if (!g_ascii_strcasecmp (enriched, enriched_tags[i].enriched))
+ return enriched_tags[i].parse_param (inptr, inlen);
+ }
+
+ g_assert_not_reached ();
+
+ return NULL;
+}
+
+#define IS_RICHTEXT CAMEL_MIME_FILTER_ENRICHED_IS_RICHTEXT
+
+static void
+enriched_to_html (CamelMimeFilter *filter, char *in, size_t inlen, size_t prespace,
+ char **out, size_t *outlen, size_t *outprespace, gboolean flush)
+{
+ CamelMimeFilterEnriched *enriched = (CamelMimeFilterEnriched *) filter;
+ const char *tag, *inend, *outend;
+ register const char *inptr;
+ register char *outptr;
+
+ camel_mime_filter_set_size (filter, inlen * 2 + 6, FALSE);
+
+ inptr = in;
+ inend = in + inlen;
+ outptr = filter->outbuf;
+ outend = filter->outbuf + filter->outsize;
+
+ retry:
+ do {
+ while (inptr < inend && outptr < outend && !strchr (" <>&\n", *inptr))
+ *outptr++ = *inptr++;
+
+ if (outptr == outend)
+ goto backup;
+
+ if ((inptr + 1) >= inend)
+ break;
+
+ switch (*inptr++) {
+ case ' ':
+ while (inptr < inend && (outptr + 7) < outend && *inptr == ' ') {
+ memcpy (outptr, "&nbsp;", 6);
+ outptr += 6;
+ inptr++;
+ }
+
+ if (outptr < outend)
+ *outptr++ = ' ';
+
+ break;
+ case '\n':
+ if (!(enriched->flags & IS_RICHTEXT)) {
+ /* text/enriched */
+ if (enriched->nofill > 0) {
+ if ((outptr + 4) < outend) {
+ memcpy (outptr, "<br>", 4);
+ outptr += 4;
+ } else {
+ inptr--;
+ goto backup;
+ }
+ } else if (*inptr == '\n') {
+ if ((outptr + 4) >= outend) {
+ inptr--;
+ goto backup;
+ }
+
+ while (inptr < inend && (outptr + 4) < outend && *inptr == '\n') {
+ memcpy (outptr, "<br>", 4);
+ outptr += 4;
+ inptr++;
+ }
+ } else {
+ *outptr++ = ' ';
+ }
+ } else {
+ /* text/richtext */
+ *outptr++ = ' ';
+ }
+ break;
+ case '>':
+ if ((outptr + 4) < outend) {
+ memcpy (outptr, "&gt;", 4);
+ outptr += 4;
+ } else {
+ inptr--;
+ goto backup;
+ }
+ break;
+ case '&':
+ if ((outptr + 5) < outend) {
+ memcpy (outptr, "&amp;", 5);
+ outptr += 5;
+ } else {
+ inptr--;
+ goto backup;
+ }
+ break;
+ case '<':
+ if (!(enriched->flags & IS_RICHTEXT)) {
+ /* text/enriched */
+ if (*inptr == '<') {
+ if ((outptr + 4) < outend) {
+ memcpy (outptr, "&lt;", 4);
+ outptr += 4;
+ inptr++;
+ break;
+ } else {
+ inptr--;
+ goto backup;
+ }
+ }
+ } else {
+ /* text/richtext */
+ if ((inend - inptr) >= 3 && (outptr + 4) < outend) {
+ if (strncmp (inptr, "lt>", 3) == 0) {
+ memcpy (outptr, "&lt;", 4);
+ outptr += 4;
+ inptr += 3;
+ break;
+ } else if (strncmp (inptr, "nl>", 3) == 0) {
+ memcpy (outptr, "<br>", 4);
+ outptr += 4;
+ inptr += 3;
+ break;
+ }
+ } else {
+ inptr--;
+ goto backup;
+ }
+ }
+
+ tag = inptr;
+ while (inptr < inend && *inptr != '>')
+ inptr++;
+
+ if (inptr == inend) {
+ inptr = tag - 1;
+ goto need_input;
+ }
+
+ if (!strncasecmp (tag, "nofill>", 7)) {
+ if ((outptr + 5) < outend) {
+ enriched->nofill++;
+ } else {
+ inptr = tag - 1;
+ goto backup;
+ }
+ } else if (!strncasecmp (tag, "/nofill>", 8)) {
+ if ((outptr + 6) < outend) {
+ enriched->nofill--;
+ } else {
+ inptr = tag - 1;
+ goto backup;
+ }
+ } else {
+ const char *html_tag;
+ char *enriched_tag;
+ int len;
+
+ len = inptr - tag;
+ enriched_tag = g_alloca (len + 1);
+ memcpy (enriched_tag, tag, len);
+ enriched_tag[len] = '\0';
+
+ html_tag = g_hash_table_lookup (enriched_hash, enriched_tag);
+
+ if (html_tag) {
+ if (html_tag_needs_param (html_tag)) {
+ const char *start;
+ char *param;
+
+ while (inptr < inend && *inptr != '<')
+ inptr++;
+
+ if (inptr == inend || (inend - inptr) <= 15) {
+ inptr = tag - 1;
+ goto need_input;
+ }
+
+ if (strncasecmp (inptr, "<param>", 7) != 0) {
+ /* ignore the enriched command tag... */
+ inptr -= 1;
+ goto loop;
+ }
+
+ inptr += 7;
+ start = inptr;
+
+ while (inptr < inend && *inptr != '<')
+ inptr++;
+
+ if (inptr == inend || (inend - inptr) <= 8) {
+ inptr = tag - 1;
+ goto need_input;
+ }
+
+ if (strncasecmp (inptr, "</param>", 8) != 0) {
+ /* ignore the enriched command tag... */
+ inptr += 7;
+ goto loop;
+ }
+
+ len = inptr - start;
+ param = param_parse (enriched_tag, start, len);
+ len = strlen (param);
+
+ inptr += 7;
+
+ len += strlen (html_tag);
+
+ if ((outptr + len) < outend) {
+ outptr += snprintf (outptr, len, html_tag, param);
+ g_free (param);
+ } else {
+ g_free (param);
+ inptr = tag - 1;
+ goto backup;
+ }
+ } else {
+ len = strlen (html_tag);
+ if ((outptr + len) < outend) {
+ memcpy (outptr, html_tag, len);
+ outptr += len;
+ } else {
+ inptr = tag - 1;
+ goto backup;
+ }
+ }
+ }
+ }
+
+ loop:
+ inptr++;
+ break;
+ default:
+ break;
+ }
+ } while (inptr < inend);
+
+ need_input:
+
+ /* the reason we ignore @flush here is because if there isn't
+ enough input to parse a tag, then there's nothing we can
+ do. */
+
+ if (inptr < inend)
+ camel_mime_filter_backup (filter, inptr, (unsigned) (inend - inptr));
+
+ *out = filter->outbuf;
+ *outlen = outptr - filter->outbuf;
+ *outprespace = filter->outpre;
+
+ return;
+
+ backup:
+
+ if (flush) {
+ size_t offset, grow;
+
+ grow = (inend - inptr) * 2 + 20;
+ offset = outptr - filter->outbuf;
+ camel_mime_filter_set_size (filter, filter->outsize + grow, TRUE);
+ outend = filter->outbuf + filter->outsize;
+ outptr = filter->outbuf + offset;
+
+ goto retry;
+ } else {
+ camel_mime_filter_backup (filter, inptr, (unsigned) (inend - inptr));
+ }
+
+ *out = filter->outbuf;
+ *outlen = outptr - filter->outbuf;
+ *outprespace = filter->outpre;
+}
+
+static void
+filter_filter (CamelMimeFilter *filter, char *in, size_t len, size_t prespace,
+ char **out, size_t *outlen, size_t *outprespace)
+{
+ enriched_to_html (filter, in, len, prespace, out, outlen, outprespace, FALSE);
+}
+
+static void
+filter_complete (CamelMimeFilter *filter, char *in, size_t len, size_t prespace,
+ char **out, size_t *outlen, size_t *outprespace)
+{
+ enriched_to_html (filter, in, len, prespace, out, outlen, outprespace, TRUE);
+}
+
+static void
+filter_reset (CamelMimeFilter *filter)
+{
+ CamelMimeFilterEnriched *enriched = (CamelMimeFilterEnriched *) filter;
+
+ enriched->nofill = 0;
+}
+
+
+/**
+ * camel_mime_filter_enriched_new:
+ * @flags:
+ *
+ * Creates a new CamelMimeFilterEnriched object.
+ *
+ * Returns a new CamelMimeFilter object.
+ **/
+CamelMimeFilter *
+camel_mime_filter_enriched_new (guint32 flags)
+{
+ CamelMimeFilterEnriched *new;
+
+ new = (CamelMimeFilterEnriched *) camel_object_new (CAMEL_TYPE_MIME_FILTER_ENRICHED);
+ new->flags = flags;
+
+ return CAMEL_MIME_FILTER (new);
+}
+
+char *
+camel_enriched_to_html(const char *in, guint32 flags)
+{
+ CamelMimeFilter *filter;
+ size_t outlen, outpre;
+ char *outbuf;
+
+ if (in == NULL)
+ return NULL;
+
+ filter = camel_mime_filter_enriched_new(flags);
+
+ camel_mime_filter_complete(filter, (char *)in, strlen(in), 0, &outbuf, &outlen, &outpre);
+ outbuf = g_strndup (outbuf, outlen);
+ camel_object_unref (filter);
+
+ return outbuf;
+}
diff --git a/camel/camel-mime-parser.c b/camel/camel-mime-parser.c
new file mode 100644
index 0000000000..ddf1b6b4a9
--- /dev/null
+++ b/camel/camel-mime-parser.c
@@ -0,0 +1,1930 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2000-2003 Ximian Inc.
+ *
+ * Authors: Michael Zucchi <notzed@ximian.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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* What should hopefully be a fast mail parser */
+
+/* Do not change this code without asking me (Michael Zucchi) first
+
+ There is almost always a reason something was done a certain way.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <string.h>
+
+#include <stdio.h>
+#include <errno.h>
+
+#include <regex.h>
+#include <ctype.h>
+
+#include <glib.h>
+#include "camel-mime-parser.h"
+#include "camel-mime-utils.h"
+#include "camel-mime-filter.h"
+#include "camel-stream.h"
+#include "camel-seekable-stream.h"
+
+#include "e-util/e-memory.h"
+
+#define r(x)
+#define h(x)
+#define c(x)
+#define d(x)
+
+/*#define PRESERVE_HEADERS*/
+
+/*#define PURIFY*/
+
+#define MEMPOOL
+
+#ifdef PURIFY
+int inend_id = -1,
+ inbuffer_id = -1;
+#endif
+
+#define SCAN_BUF 4096 /* size of read buffer */
+#define SCAN_HEAD 128 /* headroom guaranteed to be before each read buffer */
+
+/* a little hacky, but i couldn't be bothered renaming everything */
+#define _header_scan_state _CamelMimeParserPrivate
+#define _PRIVATE(o) (((CamelMimeParser *)(o))->priv)
+
+struct _header_scan_state {
+
+ /* global state */
+
+ enum _camel_mime_parser_state state;
+
+ /* for building headers during scanning */
+ char *outbuf;
+ char *outptr;
+ char *outend;
+
+ int fd; /* input for a fd input */
+ CamelStream *stream; /* or for a stream */
+
+ int ioerrno; /* io error state */
+
+ /* for scanning input buffers */
+ char *realbuf; /* the real buffer, SCAN_HEAD*2 + SCAN_BUF bytes */
+ char *inbuf; /* points to a subset of the allocated memory, the underflow */
+ char *inptr; /* (upto SCAN_HEAD) is for use by filters so they dont copy all data */
+ char *inend;
+
+ int atleast;
+
+ off_t seek; /* current offset to start of buffer */
+ int unstep; /* how many states to 'unstep' (repeat the current state) */
+
+ unsigned int midline:1; /* are we mid-line interrupted? */
+ unsigned int scan_from:1; /* do we care about From lines? */
+ unsigned int scan_pre_from:1; /* do we return pre-from data? */
+ unsigned int eof:1; /* reached eof? */
+
+ off_t start_of_from; /* where from started */
+ off_t start_of_boundary; /* where the last boundary started */
+ off_t start_of_headers; /* where headers started from the last scan */
+
+ off_t header_start; /* start of last header, or -1 */
+
+ /* filters to apply to all content before output */
+ int filterid; /* id of next filter */
+ struct _header_scan_filter *filters;
+
+ /* per message/part info */
+ struct _header_scan_stack *parts;
+
+};
+
+struct _header_scan_stack {
+ struct _header_scan_stack *parent;
+
+ enum _camel_mime_parser_state savestate; /* state at invocation of this part */
+
+#ifdef MEMPOOL
+ EMemPool *pool; /* memory pool to keep track of headers/etc at this level */
+#endif
+ struct _camel_header_raw *headers; /* headers for this part */
+
+ CamelContentType *content_type;
+
+ /* I dont use GString's casue you can't efficiently append a buffer to them */
+ GByteArray *pretext; /* for multipart types, save the pre-boundary data here */
+ GByteArray *posttext; /* for multipart types, save the post-boundary data here */
+ int prestage; /* used to determine if it is a pre-boundary or post-boundary data segment */
+
+ GByteArray *from_line; /* the from line */
+
+ char *boundary; /* for multipart/ * boundaries, including leading -- and trailing -- for the final part */
+ int boundarylen; /* actual length of boundary, including leading -- if there is one */
+ int boundarylenfinal; /* length of boundary, including trailing -- if there is one */
+ int atleast; /* the biggest boundary from here to the parent */
+};
+
+struct _header_scan_filter {
+ struct _header_scan_filter *next;
+ int id;
+ CamelMimeFilter *filter;
+};
+
+static void folder_scan_step(struct _header_scan_state *s, char **databuffer, size_t *datalength);
+static void folder_scan_drop_step(struct _header_scan_state *s);
+static int folder_scan_init_with_fd(struct _header_scan_state *s, int fd);
+static int folder_scan_init_with_stream(struct _header_scan_state *s, CamelStream *stream);
+static struct _header_scan_state *folder_scan_init(void);
+static void folder_scan_close(struct _header_scan_state *s);
+static struct _header_scan_stack *folder_scan_content(struct _header_scan_state *s, int *lastone, char **data, size_t *length);
+static struct _header_scan_stack *folder_scan_header(struct _header_scan_state *s, int *lastone);
+static int folder_scan_skip_line(struct _header_scan_state *s, GByteArray *save);
+static off_t folder_seek(struct _header_scan_state *s, off_t offset, int whence);
+static off_t folder_tell(struct _header_scan_state *s);
+static int folder_read(struct _header_scan_state *s);
+static void folder_push_part(struct _header_scan_state *s, struct _header_scan_stack *h);
+
+#ifdef MEMPOOL
+static void header_append_mempool(struct _header_scan_state *s, struct _header_scan_stack *h, char *header, int offset);
+#endif
+
+static void camel_mime_parser_class_init (CamelMimeParserClass *klass);
+static void camel_mime_parser_init (CamelMimeParser *obj);
+
+#if d(!)0
+static char *states[] = {
+ "CAMEL_MIME_PARSER_STATE_INITIAL",
+ "CAMEL_MIME_PARSER_STATE_PRE_FROM", /* pre-from data */
+ "CAMEL_MIME_PARSER_STATE_FROM", /* got 'From' line */
+ "CAMEL_MIME_PARSER_STATE_HEADER", /* toplevel header */
+ "CAMEL_MIME_PARSER_STATE_BODY", /* scanning body of message */
+ "CAMEL_MIME_PARSER_STATE_MULTIPART", /* got multipart header */
+ "CAMEL_MIME_PARSER_STATE_MESSAGE", /* rfc822/news message */
+
+ "CAMEL_MIME_PARSER_STATE_PART", /* part of a multipart */
+
+ "CAMEL_MIME_PARSER_STATE_EOF", /* end of file */
+ "CAMEL_MIME_PARSER_STATE_PRE_FROM_END",
+ "CAMEL_MIME_PARSER_STATE_FROM_END",
+ "CAMEL_MIME_PARSER_STATE_HEAER_END",
+ "CAMEL_MIME_PARSER_STATE_BODY_END",
+ "CAMEL_MIME_PARSER_STATE_MULTIPART_END",
+ "CAMEL_MIME_PARSER_STATE_MESSAGE_END",
+};
+#endif
+
+static CamelObjectClass *camel_mime_parser_parent;
+
+static void
+camel_mime_parser_class_init (CamelMimeParserClass *klass)
+{
+ camel_mime_parser_parent = camel_type_get_global_classfuncs (camel_object_get_type ());
+}
+
+static void
+camel_mime_parser_init (CamelMimeParser *obj)
+{
+ struct _header_scan_state *s;
+
+ s = folder_scan_init();
+ _PRIVATE(obj) = s;
+}
+
+static void
+camel_mime_parser_finalise(CamelObject *o)
+{
+ struct _header_scan_state *s = _PRIVATE(o);
+#ifdef PURIFY
+ purify_watch_remove_all();
+#endif
+ folder_scan_close(s);
+}
+
+CamelType
+camel_mime_parser_get_type (void)
+{
+ static CamelType type = CAMEL_INVALID_TYPE;
+
+ if (type == CAMEL_INVALID_TYPE) {
+ type = camel_type_register (camel_object_get_type (), "CamelMimeParser",
+ sizeof (CamelMimeParser),
+ sizeof (CamelMimeParserClass),
+ (CamelObjectClassInitFunc) camel_mime_parser_class_init,
+ NULL,
+ (CamelObjectInitFunc) camel_mime_parser_init,
+ (CamelObjectFinalizeFunc) camel_mime_parser_finalise);
+ }
+
+ return type;
+}
+
+/**
+ * camel_mime_parser_new:
+ *
+ * Create a new CamelMimeParser object.
+ *
+ * Return value: A new CamelMimeParser widget.
+ **/
+CamelMimeParser *
+camel_mime_parser_new (void)
+{
+ CamelMimeParser *new = CAMEL_MIME_PARSER ( camel_object_new (camel_mime_parser_get_type ()));
+ return new;
+}
+
+
+/**
+ * camel_mime_parser_filter_add:
+ * @m:
+ * @mf:
+ *
+ * Add a filter that will be applied to any body content before it is passed
+ * to the caller. Filters may be pipelined to perform multi-pass operations
+ * on the content, and are applied in the order they were added.
+ *
+ * Note that filters are only applied to the body content of messages, and once
+ * a filter has been set, all content returned by a filter_step() with a state
+ * of CAMEL_MIME_PARSER_STATE_BODY will have passed through the filter.
+ *
+ * Return value: An id that may be passed to filter_remove() to remove
+ * the filter, or -1 if the operation failed.
+ **/
+int
+camel_mime_parser_filter_add(CamelMimeParser *m, CamelMimeFilter *mf)
+{
+ struct _header_scan_state *s = _PRIVATE(m);
+ struct _header_scan_filter *f, *new;
+
+ new = g_malloc(sizeof(*new));
+ new->filter = mf;
+ new->id = s->filterid++;
+ if (s->filterid == -1)
+ s->filterid++;
+ new->next = 0;
+ camel_object_ref((CamelObject *)mf);
+
+ /* yes, this is correct, since 'next' is the first element of the struct */
+ f = (struct _header_scan_filter *)&s->filters;
+ while (f->next)
+ f = f->next;
+ f->next = new;
+ return new->id;
+}
+
+/**
+ * camel_mime_parser_filter_remove:
+ * @m:
+ * @id:
+ *
+ * Remove a processing filter from the pipeline. There is no
+ * restriction on the order the filters can be removed.
+ **/
+void
+camel_mime_parser_filter_remove(CamelMimeParser *m, int id)
+{
+ struct _header_scan_state *s = _PRIVATE(m);
+ struct _header_scan_filter *f, *old;
+
+ f = (struct _header_scan_filter *)&s->filters;
+ while (f && f->next) {
+ old = f->next;
+ if (old->id == id) {
+ camel_object_unref((CamelObject *)old->filter);
+ f->next = old->next;
+ g_free(old);
+ /* there should only be a single matching id, but
+ scan the whole lot anyway */
+ }
+ f = f->next;
+ }
+}
+
+/**
+ * camel_mime_parser_header:
+ * @m:
+ * @name: Name of header.
+ * @offset: Pointer that can receive the offset of the header in
+ * the stream from the start of parsing.
+ *
+ * Lookup a header by name.
+ *
+ * Return value: The header value, or NULL if the header is not
+ * defined.
+ **/
+const char *
+camel_mime_parser_header(CamelMimeParser *m, const char *name, int *offset)
+{
+ struct _header_scan_state *s = _PRIVATE(m);
+
+ if (s->parts &&
+ s->parts->headers) {
+ return camel_header_raw_find(&s->parts->headers, name, offset);
+ }
+ return NULL;
+}
+
+/**
+ * camel_mime_parser_headers_raw:
+ * @m:
+ *
+ * Get the list of the raw headers which are defined for the
+ * current state of the parser. These headers are valid
+ * until the next call to parser_step(), or parser_drop_step().
+ *
+ * Return value: The raw headers, or NULL if there are no headers
+ * defined for the current part or state. These are READ ONLY.
+ **/
+struct _camel_header_raw *
+camel_mime_parser_headers_raw(CamelMimeParser *m)
+{
+ struct _header_scan_state *s = _PRIVATE(m);
+
+ if (s->parts)
+ return s->parts->headers;
+ return NULL;
+}
+
+static const char *
+byte_array_to_string(GByteArray *array)
+{
+ if (array == NULL)
+ return NULL;
+
+ if (array->len == 0 || array->data[array->len-1] != '\0')
+ g_byte_array_append(array, "", 1);
+
+ return array->data;
+}
+
+/**
+ * camel_mime_parser_preface:
+ * @m:
+ *
+ * Retrieve the preface text for the current multipart.
+ * Can only be used when the state is CAMEL_MIME_PARSER_STATE_MULTIPART_END.
+ *
+ * Return value: The preface text, or NULL if there wasn't any.
+ **/
+const char *
+camel_mime_parser_preface(CamelMimeParser *m)
+{
+ struct _header_scan_state *s = _PRIVATE(m);
+
+ if (s->parts)
+ return byte_array_to_string(s->parts->pretext);
+
+ return NULL;
+}
+
+/**
+ * camel_mime_parser_postface:
+ * @m:
+ *
+ * Retrieve the postface text for the current multipart.
+ * Only returns valid data when the current state if
+ * CAMEL_MIME_PARSER_STATE_MULTIPART_END.
+ *
+ * Return value: The postface text, or NULL if there wasn't any.
+ **/
+const char *
+camel_mime_parser_postface(CamelMimeParser *m)
+{
+ struct _header_scan_state *s = _PRIVATE(m);
+
+ if (s->parts)
+ return byte_array_to_string(s->parts->posttext);
+
+ return NULL;
+}
+
+/**
+ * camel_mime_parser_from_line:
+ * @m:
+ *
+ * Get the last scanned "From " line, from a recently scanned from.
+ * This should only be called in the CAMEL_MIME_PARSER_STATE_FROM state. The
+ * from line will include the closing \n found (if there was one).
+ *
+ * The return value will remain valid while in the CAMEL_MIME_PARSER_STATE_FROM
+ * state, or any deeper state.
+ *
+ * Return value: The From line, or NULL if called out of context.
+ **/
+const char *
+camel_mime_parser_from_line(CamelMimeParser *m)
+{
+ struct _header_scan_state *s = _PRIVATE(m);
+
+ if (s->parts)
+ return byte_array_to_string(s->parts->from_line);
+
+ return NULL;
+}
+
+/**
+ * camel_mime_parser_init_with_fd:
+ * @m:
+ * @fd: A valid file descriptor.
+ *
+ * Initialise the scanner with an fd. The scanner's offsets
+ * will be relative to the current file position of the file
+ * descriptor. As a result, seekable descritors should
+ * be seeked using the parser seek functions.
+ *
+ * Return value: Returns -1 on error.
+ **/
+int
+camel_mime_parser_init_with_fd(CamelMimeParser *m, int fd)
+{
+ struct _header_scan_state *s = _PRIVATE(m);
+
+ return folder_scan_init_with_fd(s, fd);
+}
+
+/**
+ * camel_mime_parser_init_with_stream:
+ * @m:
+ * @stream:
+ *
+ * Initialise the scanner with a source stream. The scanner's
+ * offsets will be relative to the current file position of
+ * the stream. As a result, seekable streams should only
+ * be seeked using the parser seek function.
+ *
+ * Return value: -1 on error.
+ **/
+int
+camel_mime_parser_init_with_stream(CamelMimeParser *m, CamelStream *stream)
+{
+ struct _header_scan_state *s = _PRIVATE(m);
+
+ return folder_scan_init_with_stream(s, stream);
+}
+
+/**
+ * camel_mime_parser_scan_from:
+ * @parser: MIME parser object
+ * @scan_from: #TRUE if the scanner should scan From lines.
+ *
+ * Tell the scanner if it should scan "^From " lines or not.
+ *
+ * If the scanner is scanning from lines, two additional
+ * states CAMEL_MIME_PARSER_STATE_FROM and CAMEL_MIME_PARSER_STATE_FROM_END will be returned
+ * to the caller during parsing.
+ *
+ * This may also be preceeded by an optional
+ * CAMEL_MIME_PARSER_STATE_PRE_FROM state which contains the scanned data
+ * found before the From line is encountered. See also
+ * scan_pre_from().
+ **/
+void
+camel_mime_parser_scan_from (CamelMimeParser *parser, gboolean scan_from)
+{
+ struct _header_scan_state *s = _PRIVATE (parser);
+
+ s->scan_from = scan_from;
+}
+
+/**
+ * camel_mime_parser_scan_pre_from:
+ * @parser: MIME parser object
+ * @scan_pre_from: #TRUE if we want to get pre-from data.
+ *
+ * Tell the scanner whether we want to know abou the pre-from
+ * data during a scan. If we do, then we may get an additional
+ * state CAMEL_MIME_PARSER_STATE_PRE_FROM which returns the specified data.
+ **/
+void
+camel_mime_parser_scan_pre_from (CamelMimeParser *parser, gboolean scan_pre_from)
+{
+ struct _header_scan_state *s = _PRIVATE (parser);
+
+ s->scan_pre_from = scan_pre_from;
+}
+
+/**
+ * camel_mime_parser_content_type:
+ * @parser: MIME parser object
+ *
+ * Get the content type defined in the current part.
+ *
+ * Return value: A content_type structure, or NULL if there
+ * is no content-type defined for this part of state of the
+ * parser.
+ **/
+CamelContentType *
+camel_mime_parser_content_type (CamelMimeParser *parser)
+{
+ struct _header_scan_state *s = _PRIVATE (parser);
+
+ /* FIXME: should this search up until it's found the 'right'
+ content-type? can it? */
+ if (s->parts)
+ return s->parts->content_type;
+
+ return NULL;
+}
+
+/**
+ * camel_mime_parser_unstep:
+ * @parser: MIME parser object
+ *
+ * Cause the last step operation to repeat itself. If this is
+ * called repeated times, then the same step will be repeated
+ * that many times.
+ *
+ * Note that it is not possible to scan back using this function,
+ * only to have a way of peeking the next state.
+ **/
+void
+camel_mime_parser_unstep (CamelMimeParser *parser)
+{
+ struct _header_scan_state *s = _PRIVATE (parser);
+
+ s->unstep++;
+}
+
+/**
+ * camel_mime_parser_drop_step:
+ * @parser: MIME parser object
+ *
+ * Drop the last step call. This should only be used
+ * in conjunction with seeking of the stream as the
+ * stream may be in an undefined state relative to the
+ * state of the parser.
+ *
+ * Use this call with care.
+ **/
+void
+camel_mime_parser_drop_step (CamelMimeParser *parser)
+{
+ struct _header_scan_state *s = _PRIVATE (parser);
+
+ s->unstep = 0;
+ folder_scan_drop_step(s);
+}
+
+/**
+ * camel_mime_parser_step:
+ * @parser: MIME parser object
+ * @databuffer: Pointer to accept a pointer to the data
+ * associated with this step (if any). May be #NULL,
+ * in which case datalength is also ingored.
+ * @datalength: Pointer to accept a pointer to the data
+ * length associated with this step (if any).
+ *
+ * Parse the next part of the MIME message. If _unstep()
+ * has been called, then continue to return the same state
+ * for that many calls.
+ *
+ * If the step is CAMEL_MIME_PARSER_STATE_BODY then the databuffer and datalength
+ * pointers will be setup to point to the internal data buffer
+ * of the scanner and may be processed as required. Any
+ * filters will have already been applied to this data.
+ *
+ * Refer to the state diagram elsewhere for a full listing of
+ * the states an application is gauranteed to get from the
+ * scanner.
+ *
+ * Return value: The current new state of the parser
+ * is returned.
+ **/
+enum _camel_mime_parser_state
+camel_mime_parser_step (CamelMimeParser *parser, char **databuffer, size_t *datalength)
+{
+ struct _header_scan_state *s = _PRIVATE (parser);
+
+ d(printf("OLD STATE: '%s' :\n", states[s->state]));
+
+ if (s->unstep <= 0) {
+ char *dummy;
+ size_t dummylength;
+
+ if (databuffer == NULL) {
+ databuffer = &dummy;
+ datalength = &dummylength;
+ }
+
+ folder_scan_step(s, databuffer, datalength);
+ } else
+ s->unstep--;
+
+ d(printf("NEW STATE: '%s' :\n", states[s->state]));
+
+ return s->state;
+}
+
+/**
+ * camel_mime_parser_read:
+ * @parser: MIME parser object
+ * @databuffer:
+ * @len:
+ *
+ * Read at most @len bytes from the internal mime parser buffer.
+ *
+ * Returns the address of the internal buffer in @databuffer,
+ * and the length of useful data.
+ *
+ * @len may be specified as INT_MAX, in which case you will
+ * get the full remainder of the buffer at each call.
+ *
+ * Note that no parsing of the data read through this function
+ * occurs, so no state changes occur, but the seek position
+ * is updated appropriately.
+ *
+ * Return value: The number of bytes available, or -1 on error.
+ **/
+int
+camel_mime_parser_read (CamelMimeParser *parser, const char **databuffer, int len)
+{
+ struct _header_scan_state *s = _PRIVATE (parser);
+ int there;
+
+ if (len == 0)
+ return 0;
+
+ d(printf("parser::read() reading %d bytes\n", len));
+
+ there = MIN(s->inend - s->inptr, len);
+ d(printf("parser::read() there = %d bytes\n", there));
+ if (there > 0) {
+ *databuffer = s->inptr;
+ s->inptr += there;
+ return there;
+ }
+
+ if (folder_read(s) == -1)
+ return -1;
+
+ there = MIN(s->inend - s->inptr, len);
+ d(printf("parser::read() had to re-read, now there = %d bytes\n", there));
+
+ *databuffer = s->inptr;
+ s->inptr += there;
+
+ return there;
+}
+
+/**
+ * camel_mime_parser_tell:
+ * @parser: MIME parser object
+ *
+ * Return the current scanning offset. The meaning of this
+ * value will depend on the current state of the parser.
+ *
+ * An incomplete listing of the states:
+ *
+ * CAMEL_MIME_PARSER_STATE_INITIAL, The start of the current message.
+ * CAMEL_MIME_PARSER_STATE_HEADER, CAMEL_MIME_PARSER_STATE_MESSAGE, CAMEL_MIME_PARSER_STATE_MULTIPART, the character
+ * position immediately after the end of the header.
+ * CAMEL_MIME_PARSER_STATE_BODY, Position within the message of the start
+ * of the current data block.
+ * CAMEL_MIME_PARSER_STATE_*_END, The position of the character starting
+ * the next section of the scan (the last position + 1 of
+ * the respective current state).
+ *
+ * Return value: See above.
+ **/
+off_t
+camel_mime_parser_tell (CamelMimeParser *parser)
+{
+ struct _header_scan_state *s = _PRIVATE (parser);
+
+ return folder_tell(s);
+}
+
+/**
+ * camel_mime_parser_tell_start_headers:
+ * @parser: MIME parser object
+ *
+ * Find out the position within the file of where the
+ * headers started, this is cached by the parser
+ * at the time.
+ *
+ * Return value: The header start position, or -1 if
+ * no headers were scanned in the current state.
+ **/
+off_t
+camel_mime_parser_tell_start_headers (CamelMimeParser *parser)
+{
+ struct _header_scan_state *s = _PRIVATE (parser);
+
+ return s->start_of_headers;
+}
+
+/**
+ * camel_mime_parser_tell_start_from:
+ * @parser: MIME parser object
+ *
+ * If the parser is scanning From lines, then this returns
+ * the position of the start of the From line.
+ *
+ * Return value: The start of the from line, or -1 if there
+ * was no From line, or From lines are not being scanned.
+ **/
+off_t
+camel_mime_parser_tell_start_from (CamelMimeParser *parser)
+{
+ struct _header_scan_state *s = _PRIVATE (parser);
+
+ return s->start_of_from;
+}
+
+/**
+ * camel_mime_parser_tell_start_boundary:
+ * @parser: MIME parser object
+ *
+ * When parsing a multipart, this returns the start of the last
+ * boundary.
+ *
+ * Return value: The start of the boundary, or -1 if there
+ * was no boundary encountered yet.
+ **/
+off_t
+camel_mime_parser_tell_start_boundary(CamelMimeParser *parser)
+{
+ struct _header_scan_state *s = _PRIVATE (parser);
+
+ return s->start_of_boundary;
+}
+
+/**
+ * camel_mime_parser_seek:
+ * @parser: MIME parser object
+ * @offset: Number of bytes to offset the seek by.
+ * @whence: SEEK_SET, SEEK_CUR, SEEK_END
+ *
+ * Reset the source position to a known value.
+ *
+ * Note that if the source stream/descriptor was not
+ * positioned at 0 to begin with, and an absolute seek
+ * is specified (whence != SEEK_CUR), then the seek
+ * position may not match the desired seek position.
+ *
+ * Return value: The new seek offset, or -1 on
+ * an error (for example, trying to seek on a non-seekable
+ * stream or file descriptor).
+ **/
+off_t
+camel_mime_parser_seek(CamelMimeParser *parser, off_t offset, int whence)
+{
+ struct _header_scan_state *s = _PRIVATE (parser);
+
+ return folder_seek(s, offset, whence);
+}
+
+/**
+ * camel_mime_parser_state:
+ * @parser: MIME parser object
+ *
+ * Get the current parser state.
+ *
+ * Return value: The current parser state.
+ **/
+enum _camel_mime_parser_state
+camel_mime_parser_state (CamelMimeParser *parser)
+{
+ struct _header_scan_state *s = _PRIVATE (parser);
+
+ return s->state;
+}
+
+/**
+ * camel_mime_parser_push_state:
+ * @mp: MIME parser object
+ * @newstate: New state
+ * @boundary: Boundary marker for state.
+ *
+ * Pre-load a new parser state. Used to post-parse multipart content
+ * without headers.
+ **/
+void
+camel_mime_parser_push_state(CamelMimeParser *mp, enum _camel_mime_parser_state newstate, const char *boundary)
+{
+ struct _header_scan_stack *h;
+ struct _header_scan_state *s = _PRIVATE(mp);
+
+ h = g_malloc0(sizeof(*h));
+ h->boundarylen = strlen(boundary)+2;
+ h->boundarylenfinal = h->boundarylen+2;
+ h->boundary = g_malloc(h->boundarylen+3);
+ sprintf(h->boundary, "--%s--", boundary);
+ folder_push_part(s, h);
+ s->state = newstate;
+}
+
+/**
+ * camel_mime_parser_stream:
+ * @parser: MIME parser object
+ *
+ * Get the stream, if any, the parser has been initialised
+ * with. May be used to setup sub-streams, but should not
+ * be read from directly (without saving and restoring
+ * the seek position in between).
+ *
+ * Return value: The stream from _init_with_stream(), or NULL
+ * if the parser is reading from a file descriptor or is
+ * uninitialised.
+ **/
+CamelStream *
+camel_mime_parser_stream (CamelMimeParser *parser)
+{
+ struct _header_scan_state *s = _PRIVATE (parser);
+
+ return s->stream;
+}
+
+/**
+ * camel_mime_parser_fd:
+ * @parser: MIME parser object
+ *
+ * Return the file descriptor, if any, the parser has been
+ * initialised with.
+ *
+ * Should not be read from unless the parser it to terminate,
+ * or the seek offset can be reset before the next parse
+ * step.
+ *
+ * Return value: The file descriptor or -1 if the parser
+ * is reading from a stream or has not been initialised.
+ **/
+int
+camel_mime_parser_fd (CamelMimeParser *parser)
+{
+ struct _header_scan_state *s = _PRIVATE (parser);
+
+ return s->fd;
+}
+
+/* Return errno of the parser, incase any error occured during processing */
+int
+camel_mime_parser_errno (CamelMimeParser *parser)
+{
+ struct _header_scan_state *s = _PRIVATE (parser);
+
+ return s->ioerrno;
+}
+
+/* ********************************************************************** */
+/* Implementation */
+/* ********************************************************************** */
+
+/* read the next bit of data, ensure there is enough room 'atleast' bytes */
+static int
+folder_read(struct _header_scan_state *s)
+{
+ int len;
+ int inoffset;
+
+ if (s->inptr<s->inend-s->atleast || s->eof)
+ return s->inend-s->inptr;
+#ifdef PURIFY
+ purify_watch_remove(inend_id);
+ purify_watch_remove(inbuffer_id);
+#endif
+ /* check for any remaning bytes (under the atleast limit( */
+ inoffset = s->inend - s->inptr;
+ if (inoffset>0) {
+ memcpy(s->inbuf, s->inptr, inoffset);
+ }
+ if (s->stream) {
+ len = camel_stream_read(s->stream, s->inbuf+inoffset, SCAN_BUF-inoffset);
+ } else {
+ len = read(s->fd, s->inbuf+inoffset, SCAN_BUF-inoffset);
+ }
+ r(printf("read %d bytes, offset = %d\n", len, inoffset));
+ if (len>=0) {
+ /* add on the last read block */
+ s->seek += s->inptr - s->inbuf;
+ s->inptr = s->inbuf;
+ s->inend = s->inbuf+len+inoffset;
+ s->eof = (len == 0);
+ r(printf("content = %d '%.*s'\n",s->inend - s->inptr, s->inend - s->inptr, s->inptr));
+ } else {
+ s->ioerrno = errno?errno:EIO;
+ }
+
+ g_assert(s->inptr<=s->inend);
+#ifdef PURIFY
+ inend_id = purify_watch(&s->inend);
+ inbuffer_id = purify_watch_n(s->inend+1, SCAN_HEAD-1, "rw");
+#endif
+ r(printf("content = %d '%.*s'\n", s->inend - s->inptr, s->inend - s->inptr, s->inptr));
+ /* set a sentinal, for the inner loops to check against */
+ s->inend[0] = '\n';
+ return s->inend-s->inptr;
+}
+
+/* return the current absolute position of the data pointer */
+static off_t
+folder_tell(struct _header_scan_state *s)
+{
+ return s->seek + (s->inptr - s->inbuf);
+}
+
+/*
+ need some way to prime the parser state, so this actually works for
+ other than top-level messages
+*/
+static off_t
+folder_seek(struct _header_scan_state *s, off_t offset, int whence)
+{
+ off_t newoffset;
+
+ if (s->stream) {
+ if (CAMEL_IS_SEEKABLE_STREAM(s->stream)) {
+ /* NOTE: assumes whence seekable stream == whence libc, which is probably
+ the case (or bloody well should've been) */
+ newoffset = camel_seekable_stream_seek((CamelSeekableStream *)s->stream, offset, whence);
+ } else {
+ newoffset = -1;
+ errno = EINVAL;
+ }
+ } else {
+ newoffset = lseek(s->fd, offset, whence);
+ }
+#ifdef PURIFY
+ purify_watch_remove(inend_id);
+ purify_watch_remove(inbuffer_id);
+#endif
+ if (newoffset != -1) {
+ s->seek = newoffset;
+ s->inptr = s->inbuf;
+ s->inend = s->inbuf;
+ s->eof = FALSE;
+ } else {
+ s->ioerrno = errno?errno:EIO;
+ }
+#ifdef PURIFY
+ inend_id = purify_watch(&s->inend);
+ inbuffer_id = purify_watch_n(s->inend+1, SCAN_HEAD-1, "rw");
+#endif
+ return newoffset;
+}
+
+static void
+folder_push_part(struct _header_scan_state *s, struct _header_scan_stack *h)
+{
+ if (s->parts && s->parts->atleast > h->boundarylenfinal)
+ h->atleast = s->parts->atleast;
+ else
+ h->atleast = MAX(h->boundarylenfinal, 1);
+
+ h->parent = s->parts;
+ s->parts = h;
+}
+
+static void
+folder_pull_part(struct _header_scan_state *s)
+{
+ struct _header_scan_stack *h;
+
+ h = s->parts;
+ if (h) {
+ s->parts = h->parent;
+ g_free(h->boundary);
+#ifdef MEMPOOL
+ e_mempool_destroy(h->pool);
+#else
+ camel_header_raw_clear(&h->headers);
+#endif
+ camel_content_type_unref(h->content_type);
+ if (h->pretext)
+ g_byte_array_free(h->pretext, TRUE);
+ if (h->posttext)
+ g_byte_array_free(h->posttext, TRUE);
+ if (h->from_line)
+ g_byte_array_free(h->from_line, TRUE);
+ g_free(h);
+ } else {
+ g_warning("Header stack underflow!\n");
+ }
+}
+
+static int
+folder_scan_skip_line(struct _header_scan_state *s, GByteArray *save)
+{
+ int atleast = s->atleast;
+ register char *inptr, *inend, c;
+ int len;
+
+ s->atleast = 1;
+
+ d(printf("skipping line\n"));
+
+ while ( (len = folder_read(s)) > 0 && len > s->atleast) { /* ensure we have at least enough room here */
+ inptr = s->inptr;
+ inend = s->inend;
+
+ c = -1;
+ while (inptr<inend
+ && (c = *inptr++)!='\n') {
+ d(printf("(%2x,%c)", c, isprint(c)?c:'.'));
+ ;
+ }
+
+ if (save)
+ g_byte_array_append(save, s->inptr, inptr-s->inptr);
+
+ s->inptr = inptr;
+
+ if (c=='\n') {
+ s->atleast = atleast;
+ return 0;
+ }
+ }
+
+ d(printf("couldn't find end of line?\n"));
+
+ s->atleast = atleast;
+
+ return -1; /* not found */
+}
+
+/* TODO: Is there any way to make this run faster? It gets called a lot ... */
+static struct _header_scan_stack *
+folder_boundary_check(struct _header_scan_state *s, const char *boundary, int *lastone)
+{
+ struct _header_scan_stack *part;
+ int len = s->inend - boundary; /* make sure we dont access past the buffer */
+
+ h(printf("checking boundary marker upto %d bytes\n", len));
+ part = s->parts;
+ while (part) {
+ h(printf(" boundary: %s\n", part->boundary));
+ h(printf(" against: '%.*s'\n", part->boundarylen, boundary));
+ if (part->boundary
+ && part->boundarylen <= len
+ && memcmp(boundary, part->boundary, part->boundarylen)==0) {
+ h(printf("matched boundary: %s\n", part->boundary));
+ /* again, make sure we're in range */
+ if (part->boundarylenfinal <= len) {
+ int extra = part->boundarylenfinal - part->boundarylen;
+
+ /* check the extra stuff on an final boundary, normally -- for mime parts */
+ if (extra>0) {
+ *lastone = memcmp(&boundary[part->boundarylen],
+ &part->boundary[part->boundarylen],
+ extra) == 0;
+ } else {
+ *lastone = TRUE;
+ }
+ h(printf("checking lastone = %s\n", *lastone?"TRUE":"FALSE"));
+ } else {
+ h(printf("not enough room to check last one?\n"));
+ *lastone = FALSE;
+ }
+ /*printf("ok, we found it! : %s \n", (*lastone)?"Last one":"More to come?");*/
+ return part;
+ }
+ part = part->parent;
+ }
+ return NULL;
+}
+
+#ifdef MEMPOOL
+static void
+header_append_mempool(struct _header_scan_state *s, struct _header_scan_stack *h, char *header, int offset)
+{
+ struct _camel_header_raw *l, *n;
+ char *content;
+
+ content = strchr(header, ':');
+ if (content) {
+ register int len;
+ n = e_mempool_alloc(h->pool, sizeof(*n));
+ n->next = NULL;
+
+ len = content-header;
+ n->name = e_mempool_alloc(h->pool, len+1);
+ memcpy(n->name, header, len);
+ n->name[len] = 0;
+
+ content++;
+
+ len = s->outptr - content;
+ n->value = e_mempool_alloc(h->pool, len+1);
+ memcpy(n->value, content, len);
+ n->value[len] = 0;
+
+ n->offset = offset;
+
+ l = (struct _camel_header_raw *)&h->headers;
+ while (l->next) {
+ l = l->next;
+ }
+ l->next = n;
+ }
+
+}
+
+#define header_raw_append_parse(a, b, c) (header_append_mempool(s, h, b, c))
+
+#endif
+
+/* Copy the string start->inptr into the header buffer (s->outbuf),
+ grow if necessary
+ remove trailing \r chars (\n's assumed already removed)
+ and track the start offset of the header */
+/* Basically an optimised version of g_byte_array_append() */
+#define header_append(s, start, inptr) \
+{ \
+ register int headerlen = inptr-start; \
+ \
+ if (headerlen > 0) { \
+ if (headerlen >= (s->outend - s->outptr)) { \
+ register char *outnew; \
+ register int len = ((s->outend - s->outbuf)+headerlen)*2+1; \
+ outnew = g_realloc(s->outbuf, len); \
+ s->outptr = s->outptr - s->outbuf + outnew; \
+ s->outbuf = outnew; \
+ s->outend = outnew + len; \
+ } \
+ if (start[headerlen-1] == '\r') \
+ headerlen--; \
+ memcpy(s->outptr, start, headerlen); \
+ s->outptr += headerlen; \
+ } \
+ if (s->header_start == -1) \
+ s->header_start = (start-s->inbuf) + s->seek; \
+}
+
+static struct _header_scan_stack *
+folder_scan_header(struct _header_scan_state *s, int *lastone)
+{
+ int atleast = s->atleast, newatleast;
+ char *start = NULL;
+ int len;
+ struct _header_scan_stack *h;
+ char *inend;
+ register char *inptr;
+
+ h(printf("scanning first bit\n"));
+
+ h = g_malloc0(sizeof(*h));
+#ifdef MEMPOOL
+ h->pool = e_mempool_new(8192, 4096, E_MEMPOOL_ALIGN_STRUCT);
+#endif
+
+ if (s->parts)
+ newatleast = s->parts->atleast;
+ else
+ newatleast = 1;
+ *lastone = FALSE;
+
+ do {
+ s->atleast = newatleast;
+
+ h(printf("atleast = %d\n", s->atleast));
+
+ while ((len = folder_read(s))>0 && len >= s->atleast) { /* ensure we have at least enough room here */
+ inptr = s->inptr;
+ inend = s->inend-s->atleast+1;
+
+ while (inptr<inend) {
+ if (!s->midline) {
+ if (folder_boundary_check(s, inptr, lastone)) {
+ if ((s->outptr>s->outbuf))
+ goto header_truncated; /* may not actually be truncated */
+
+ goto header_done;
+ }
+ }
+
+ start = inptr;
+
+ /* goto next line/sentinal */
+ while ((*inptr++)!='\n')
+ ;
+
+ g_assert(inptr<=s->inend+1);
+
+ /* check for sentinal or real end of line */
+ if (inptr > inend) {
+ h(printf("not at end of line yet, going further\n"));
+ /* didn't find end of line within our allowed area */
+ inptr = inend;
+ s->midline = TRUE;
+ header_append(s, start, inptr);
+ } else {
+ h(printf("got line part: '%.*s'\n", inptr-1-start, start));
+ /* got a line, strip and add it, process it */
+ s->midline = FALSE;
+#ifdef PRESERVE_HEADERS
+ header_append(s, start, inptr);
+#else
+ header_append(s, start, inptr-1);
+#endif
+ /* check for end of headers */
+ if (s->outbuf == s->outptr)
+ goto header_done;
+
+ /* check for continuation/compress headers, we have atleast 1 char here to work with */
+ if (inptr[0] == ' ' || inptr[0] == '\t') {
+ h(printf("continuation\n"));
+#ifndef PRESERVE_HEADERS
+ /* TODO: this wont catch multiple space continuation across a read boundary, but
+ that is assumed rare, and not fatal anyway */
+ do
+ inptr++;
+ while (*inptr == ' ' || *inptr == '\t');
+ inptr--;
+ *inptr = ' ';
+#endif
+ } else {
+ /* otherwise, complete header, add it */
+#ifdef PRESERVE_HEADERS
+ s->outptr--;
+ if (s->outptr[-1] == '\r')
+ s->outptr--;
+#endif
+ s->outptr[0] = 0;
+
+ h(printf("header '%s' at %d\n", s->outbuf, (int)s->header_start));
+
+ header_raw_append_parse(&h->headers, s->outbuf, s->header_start);
+ s->outptr = s->outbuf;
+ s->header_start = -1;
+ }
+ }
+ }
+ s->inptr = inptr;
+ }
+ h(printf("end of file? read %d bytes\n", len));
+ newatleast = 1;
+ } while (s->atleast > 1);
+
+ if ((s->outptr > s->outbuf) || s->inend > s->inptr) {
+ start = s->inptr;
+ inptr = s->inend;
+ if (inptr > start) {
+ if (inptr[-1] == '\n')
+ inptr--;
+ }
+ goto header_truncated;
+ }
+
+ s->atleast = atleast;
+
+ return h;
+
+header_truncated:
+ header_append(s, start, inptr);
+
+ s->outptr[0] = 0;
+ if (s->outbuf == s->outptr)
+ goto header_done;
+
+ header_raw_append_parse(&h->headers, s->outbuf, s->header_start);
+
+ s->outptr = s->outbuf;
+header_done:
+ s->inptr = inptr;
+ s->atleast = atleast;
+ s->header_start = -1;
+ return h;
+}
+
+static struct _header_scan_stack *
+folder_scan_content(struct _header_scan_state *s, int *lastone, char **data, size_t *length)
+{
+ int atleast = s->atleast, newatleast;
+ register char *inptr;
+ char *inend;
+ char *start;
+ int len;
+ struct _header_scan_stack *part;
+ int onboundary = FALSE;
+
+ c(printf("scanning content\n"));
+
+ part = s->parts;
+ if (part)
+ newatleast = part->atleast;
+ else
+ newatleast = 1;
+ *lastone = FALSE;
+
+ c(printf("atleast = %d\n", newatleast));
+
+ do {
+ s->atleast = newatleast;
+
+ while ((len = folder_read(s))>0 && len >= s->atleast) { /* ensure we have at least enough room here */
+ inptr = s->inptr;
+ if (s->eof)
+ inend = s->inend;
+ else
+ inend = s->inend-s->atleast+1;
+ start = inptr;
+
+ c(printf("inptr = %p, inend = %p\n", inptr, inend));
+
+ while (inptr<inend) {
+ if (!s->midline
+ && (part = folder_boundary_check(s, inptr, lastone))) {
+ onboundary = TRUE;
+
+ /* since we truncate the boundary data, we need at least 1 char here spare,
+ to remain in the same state */
+ if ( (inptr-start) > 1)
+ goto content;
+
+ /* otherwise, jump to the state of the boundary we actually found */
+ goto normal_exit;
+ }
+
+ /* goto the next line */
+ while ((*inptr++)!='\n')
+ ;
+
+ /* check the sentinal, if we went past the atleast limit, and reset it to there */
+ if (inptr > inend) {
+ s->midline = TRUE;
+ inptr = inend;
+ } else {
+ s->midline = FALSE;
+ }
+ }
+
+ c(printf("ran out of input, dumping what i have (%d) bytes midline = %s\n",
+ inptr-start, s->midline?"TRUE":"FALSE"));
+ goto content;
+ }
+ newatleast = 1;
+ } while (s->atleast > 1);
+
+ c(printf("length read = %d\n", len));
+
+ if (s->inend > s->inptr) {
+ start = s->inptr;
+ inptr = s->inend;
+ goto content;
+ }
+
+ *length = 0;
+ s->atleast = atleast;
+ return NULL;
+
+content:
+ /* treat eof as the last boundary in From mode */
+ if (s->scan_from && s->eof && s->atleast <= 1) {
+ onboundary = TRUE;
+ part = NULL;
+ } else {
+ part = s->parts;
+ }
+normal_exit:
+ s->atleast = atleast;
+ s->inptr = inptr;
+
+ *data = start;
+ /* if we hit a boundary, we should not include the closing \n */
+ if (onboundary && (inptr-start)>0)
+ *length = inptr-start-1;
+ else
+ *length = inptr-start;
+
+ /*printf("got %scontent: '%.*s'\n", s->midline?"partial ":"", inptr-start, start);*/
+
+ return part;
+}
+
+
+static void
+folder_scan_close(struct _header_scan_state *s)
+{
+ g_free(s->realbuf);
+ g_free(s->outbuf);
+ while (s->parts)
+ folder_pull_part(s);
+ if (s->fd != -1)
+ close(s->fd);
+ if (s->stream) {
+ camel_object_unref((CamelObject *)s->stream);
+ }
+ g_free(s);
+}
+
+
+static struct _header_scan_state *
+folder_scan_init(void)
+{
+ struct _header_scan_state *s;
+
+ s = g_malloc(sizeof(*s));
+
+ s->fd = -1;
+ s->stream = NULL;
+ s->ioerrno = 0;
+
+ s->outbuf = g_malloc(1024);
+ s->outptr = s->outbuf;
+ s->outend = s->outbuf+1024;
+
+ s->realbuf = g_malloc(SCAN_BUF + SCAN_HEAD*2);
+ s->inbuf = s->realbuf + SCAN_HEAD;
+ s->inptr = s->inbuf;
+ s->inend = s->inbuf;
+ s->atleast = 0;
+
+ s->seek = 0; /* current character position in file of the last read block */
+ s->unstep = 0;
+
+ s->header_start = -1;
+
+ s->start_of_from = -1;
+ s->start_of_headers = -1;
+ s->start_of_boundary = -1;
+
+ s->midline = FALSE;
+ s->scan_from = FALSE;
+ s->scan_pre_from = FALSE;
+ s->eof = FALSE;
+
+ s->filters = NULL;
+ s->filterid = 1;
+
+ s->parts = NULL;
+
+ s->state = CAMEL_MIME_PARSER_STATE_INITIAL;
+ return s;
+}
+
+static void
+drop_states(struct _header_scan_state *s)
+{
+ while (s->parts) {
+ folder_scan_drop_step(s);
+ }
+ s->unstep = 0;
+ s->state = CAMEL_MIME_PARSER_STATE_INITIAL;
+}
+
+static void
+folder_scan_reset(struct _header_scan_state *s)
+{
+ drop_states(s);
+ s->inend = s->inbuf;
+ s->inptr = s->inbuf;
+ s->inend[0] = '\n';
+ if (s->fd != -1) {
+ close(s->fd);
+ s->fd = -1;
+ }
+ if (s->stream) {
+ camel_object_unref((CamelObject *)s->stream);
+ s->stream = NULL;
+ }
+ s->ioerrno = 0;
+ s->eof = FALSE;
+}
+
+static int
+folder_scan_init_with_fd(struct _header_scan_state *s, int fd)
+{
+ folder_scan_reset(s);
+ s->fd = fd;
+
+ return 0;
+}
+
+static int
+folder_scan_init_with_stream(struct _header_scan_state *s, CamelStream *stream)
+{
+ folder_scan_reset(s);
+ s->stream = stream;
+ camel_object_ref((CamelObject *)stream);
+
+ return 0;
+}
+
+#define USE_FROM
+
+static void
+folder_scan_step(struct _header_scan_state *s, char **databuffer, size_t *datalength)
+{
+ struct _header_scan_stack *h, *hb;
+ const char *content;
+ const char *bound;
+ int type, state, seenlast;
+ CamelContentType *ct = NULL;
+ struct _header_scan_filter *f;
+ size_t presize;
+
+/* printf("\nSCAN PASS: state = %d '%s'\n", s->state, states[s->state]);*/
+
+tail_recurse:
+ d({
+ printf("\nSCAN STACK:\n");
+ printf(" '%s' :\n", states[s->state]);
+ hb = s->parts;
+ while (hb) {
+ printf(" '%s' : %s ", states[hb->savestate], hb->boundary);
+ if (hb->content_type) {
+ printf("(%s/%s)", hb->content_type->type, hb->content_type->subtype);
+ } else {
+ printf("(default)");
+ }
+ printf("\n");
+ hb = hb->parent;
+ }
+ printf("\n");
+ });
+
+ switch (s->state) {
+
+#ifdef USE_FROM
+ case CAMEL_MIME_PARSER_STATE_INITIAL:
+ if (s->scan_from) {
+ h = g_malloc0(sizeof(*h));
+ h->boundary = g_strdup("From ");
+ h->boundarylen = strlen(h->boundary);
+ h->boundarylenfinal = h->boundarylen;
+ h->from_line = g_byte_array_new();
+ folder_push_part(s, h);
+ s->state = CAMEL_MIME_PARSER_STATE_PRE_FROM;
+ } else {
+ s->start_of_from = -1;
+ goto scan_header;
+ }
+
+ case CAMEL_MIME_PARSER_STATE_PRE_FROM:
+
+ h = s->parts;
+ do {
+ hb = folder_scan_content(s, &state, databuffer, datalength);
+ if (s->scan_pre_from && *datalength > 0) {
+ d(printf("got pre-from content %d bytes\n", *datalength));
+ return;
+ }
+ } while (hb==h && *datalength>0);
+
+ if (*datalength==0 && hb==h) {
+ d(printf("found 'From '\n"));
+ s->start_of_from = folder_tell(s);
+ folder_scan_skip_line(s, h->from_line);
+ h->savestate = CAMEL_MIME_PARSER_STATE_INITIAL;
+ s->state = CAMEL_MIME_PARSER_STATE_FROM;
+ } else {
+ folder_pull_part(s);
+ s->state = CAMEL_MIME_PARSER_STATE_EOF;
+ }
+ return;
+#else
+ case CAMEL_MIME_PARSER_STATE_INITIAL:
+ case CAMEL_MIME_PARSER_STATE_PRE_FROM:
+#endif /* !USE_FROM */
+
+ scan_header:
+ case CAMEL_MIME_PARSER_STATE_FROM:
+ s->start_of_headers = folder_tell(s);
+ h = folder_scan_header(s, &state);
+#ifdef USE_FROM
+ if (s->scan_from)
+ h->savestate = CAMEL_MIME_PARSER_STATE_FROM_END;
+ else
+#endif
+ h->savestate = CAMEL_MIME_PARSER_STATE_EOF;
+
+ /* FIXME: should this check for MIME-Version: 1.0 as well? */
+
+ type = CAMEL_MIME_PARSER_STATE_HEADER;
+ if ( (content = camel_header_raw_find(&h->headers, "Content-Type", NULL))
+ && (ct = camel_content_type_decode(content))) {
+ if (!g_ascii_strcasecmp(ct->type, "multipart")) {
+ if (!camel_content_type_is(ct, "multipart", "signed")
+ && (bound = camel_content_type_param(ct, "boundary"))) {
+ d(printf("multipart, boundary = %s\n", bound));
+ h->boundarylen = strlen(bound)+2;
+ h->boundarylenfinal = h->boundarylen+2;
+ h->boundary = g_malloc(h->boundarylen+3);
+ sprintf(h->boundary, "--%s--", bound);
+ type = CAMEL_MIME_PARSER_STATE_MULTIPART;
+ } else {
+ /*camel_content_type_unref(ct);
+ ct = camel_content_type_decode("text/plain");*/
+/* We can't quite do this, as it will mess up all the offsets ... */
+/* camel_header_raw_replace(&h->headers, "Content-Type", "text/plain", offset);*/
+ /*g_warning("Multipart with no boundary, treating as text/plain");*/
+ }
+ } else if (!strcasecmp(ct->type, "message")) {
+ if (!strcasecmp(ct->subtype, "rfc822")
+ || !strcasecmp(ct->subtype, "news")
+ /*|| !g_ascii_strcasecmp(ct->subtype, "partial")*/) {
+ type = CAMEL_MIME_PARSER_STATE_MESSAGE;
+ }
+ }
+ } else {
+ /* make the default type for multipart/digest be message/rfc822 */
+ if ((s->parts
+ && camel_content_type_is(s->parts->content_type, "multipart", "digest"))) {
+ ct = camel_content_type_decode("message/rfc822");
+ type = CAMEL_MIME_PARSER_STATE_MESSAGE;
+ d(printf("parent was multipart/digest, autoupgrading to message/rfc822?\n"));
+ /* maybe we should do this too?
+ header_raw_append_parse(&h->headers, "Content-Type: message/rfc822", -1);*/
+ } else {
+ ct = camel_content_type_decode("text/plain");
+ }
+ }
+ h->content_type = ct;
+ folder_push_part(s, h);
+ s->state = type;
+ return;
+
+ case CAMEL_MIME_PARSER_STATE_HEADER:
+ s->state = CAMEL_MIME_PARSER_STATE_BODY;
+
+ case CAMEL_MIME_PARSER_STATE_BODY:
+ h = s->parts;
+ *datalength = 0;
+ presize = SCAN_HEAD;
+ f = s->filters;
+
+ do {
+ hb = folder_scan_content (s, &state, databuffer, datalength);
+
+ d(printf ("\n\nOriginal content: '"));
+ d(fwrite(*databuffer, sizeof(char), *datalength, stdout));
+ d(printf("'\n"));
+
+ if (*datalength > 0) {
+ while (f) {
+ camel_mime_filter_filter(f->filter, *databuffer, *datalength, presize,
+ databuffer, datalength, &presize);
+ d(printf("Filtered content (%s): '", ((CamelObject *)f->filter)->klass->name));
+ d(fwrite(*databuffer, sizeof(char), *datalength, stdout));
+ d(printf("'\n"));
+ f = f->next;
+ }
+ return;
+ }
+ } while (hb == h && *datalength > 0);
+
+ /* check for any filter completion data */
+ while (f) {
+ camel_mime_filter_complete(f->filter, *databuffer, *datalength, presize,
+ databuffer, datalength, &presize);
+ f = f->next;
+ }
+
+ if (*datalength > 0)
+ return;
+
+ s->state = CAMEL_MIME_PARSER_STATE_BODY_END;
+ break;
+
+ case CAMEL_MIME_PARSER_STATE_MULTIPART:
+ h = s->parts;
+ /* This mess looks for the next boundary on this
+ level. Once it finds the last one, it keeps going,
+ looking for post-multipart content ('postface').
+ Because messages might have duplicate boundaries for
+ different parts, it makes sure it stops if its already
+ found an end boundary for this part. It handles
+ truncated and missing boundaries appropriately too. */
+ seenlast = FALSE;
+ do {
+ do {
+ hb = folder_scan_content(s, &state, databuffer, datalength);
+ if (*datalength>0) {
+ /* instead of a new state, we'll just store it locally and provide
+ an accessor function */
+ d(printf("Multipart %s Content %p: '%.*s'\n",
+ h->prestage>0?"post":"pre", h, *datalength, *databuffer));
+ if (h->prestage > 0) {
+ if (h->posttext == NULL)
+ h->posttext = g_byte_array_new();
+ g_byte_array_append(h->posttext, *databuffer, *datalength);
+ } else {
+ if (h->pretext == NULL)
+ h->pretext = g_byte_array_new();
+ g_byte_array_append(h->pretext, *databuffer, *datalength);
+ }
+ }
+ } while (hb==h && *datalength>0);
+ h->prestage++;
+ if (*datalength==0 && hb==h && !seenlast) {
+ d(printf("got boundary: %s last=%d\n", hb->boundary, state));
+ s->start_of_boundary = folder_tell(s);
+ folder_scan_skip_line(s, NULL);
+ if (!state) {
+ s->state = CAMEL_MIME_PARSER_STATE_FROM;
+ folder_scan_step(s, databuffer, datalength);
+ s->parts->savestate = CAMEL_MIME_PARSER_STATE_MULTIPART; /* set return state for the new head part */
+ return;
+ } else
+ seenlast = TRUE;
+ } else {
+ break;
+ }
+ } while (1);
+
+ s->state = CAMEL_MIME_PARSER_STATE_MULTIPART_END;
+ break;
+
+ case CAMEL_MIME_PARSER_STATE_MESSAGE:
+ s->state = CAMEL_MIME_PARSER_STATE_FROM;
+ folder_scan_step(s, databuffer, datalength);
+ s->parts->savestate = CAMEL_MIME_PARSER_STATE_MESSAGE_END;
+ break;
+
+ case CAMEL_MIME_PARSER_STATE_FROM_END:
+ case CAMEL_MIME_PARSER_STATE_BODY_END:
+ case CAMEL_MIME_PARSER_STATE_MULTIPART_END:
+ case CAMEL_MIME_PARSER_STATE_MESSAGE_END:
+ s->state = s->parts->savestate;
+ folder_pull_part(s);
+ if (s->state & CAMEL_MIME_PARSER_STATE_END)
+ return;
+ goto tail_recurse;
+
+ case CAMEL_MIME_PARSER_STATE_EOF:
+ return;
+
+ default:
+ g_warning("Invalid state in camel-mime-parser: %d", s->state);
+ break;
+ }
+
+ return;
+}
+
+/* drops the current state back one */
+static void
+folder_scan_drop_step(struct _header_scan_state *s)
+{
+ switch (s->state) {
+ case CAMEL_MIME_PARSER_STATE_EOF:
+ s->state = CAMEL_MIME_PARSER_STATE_INITIAL;
+ case CAMEL_MIME_PARSER_STATE_INITIAL:
+ return;
+
+ case CAMEL_MIME_PARSER_STATE_FROM:
+ case CAMEL_MIME_PARSER_STATE_PRE_FROM:
+ s->state = CAMEL_MIME_PARSER_STATE_INITIAL;
+ folder_pull_part(s);
+ return;
+
+ case CAMEL_MIME_PARSER_STATE_MESSAGE:
+ case CAMEL_MIME_PARSER_STATE_HEADER:
+ case CAMEL_MIME_PARSER_STATE_MULTIPART:
+
+ case CAMEL_MIME_PARSER_STATE_FROM_END:
+ case CAMEL_MIME_PARSER_STATE_BODY_END:
+ case CAMEL_MIME_PARSER_STATE_MULTIPART_END:
+ case CAMEL_MIME_PARSER_STATE_MESSAGE_END:
+
+ s->state = s->parts->savestate;
+ folder_pull_part(s);
+ if (s->state & CAMEL_MIME_PARSER_STATE_END) {
+ s->state &= ~CAMEL_MIME_PARSER_STATE_END;
+ }
+ return;
+ default:
+ /* FIXME: not sure if this is entirely right */
+ break;
+ }
+}
+
+#ifdef STANDALONE
+int main(int argc, char **argv)
+{
+ int fd;
+ struct _header_scan_state *s;
+ char *data;
+ size_t len;
+ int state;
+ char *name = "/tmp/evmail/Inbox";
+ struct _header_scan_stack *h;
+ int i;
+ int attach = 0;
+
+ if (argc==2)
+ name = argv[1];
+
+ printf("opening: %s", name);
+
+ for (i=1;i<argc;i++) {
+ const char *encoding = NULL, *charset = NULL;
+ char *attachname;
+
+ name = argv[i];
+ printf("opening: %s", name);
+
+ fd = open(name, O_RDONLY);
+ if (fd==-1) {
+ perror("Cannot open mailbox");
+ exit(1);
+ }
+ s = folder_scan_init();
+ folder_scan_init_with_fd(s, fd);
+ s->scan_from = FALSE;
+#if 0
+ h = g_malloc0(sizeof(*h));
+ h->savestate = CAMEL_MIME_PARSER_STATE_EOF;
+ folder_push_part(s, h);
+#endif
+ while (s->state != CAMEL_MIME_PARSER_STATE_EOF) {
+ folder_scan_step(s, &data, &len);
+ printf("\n -- PARSER STEP RETURN -- %d '%s'\n\n", s->state, states[s->state]);
+ switch (s->state) {
+ case CAMEL_MIME_PARSER_STATE_HEADER:
+ if (s->parts->content_type
+ && (charset = camel_content_type_param(s->parts->content_type, "charset"))) {
+ if (g_ascii_strcasecmp(charset, "us-ascii")) {
+#if 0
+ folder_push_filter_charset(s, "UTF-8", charset);
+#endif
+ } else {
+ charset = NULL;
+ }
+ } else {
+ charset = NULL;
+ }
+
+ encoding = camel_header_raw_find(&s->parts->headers, "Content-transfer-encoding", 0);
+ printf("encoding = '%s'\n", encoding);
+ if (encoding && !strncasecmp(encoding, " base64", 7)) {
+ printf("adding base64 filter\n");
+ attachname = g_strdup_printf("attach.%d.%d", i, attach++);
+#if 0
+ folder_push_filter_save(s, attachname);
+#endif
+ g_free(attachname);
+#if 0
+ folder_push_filter_mime(s, 0);
+#endif
+ }
+ if (encoding && !strncasecmp(encoding, " quoted-printable", 17)) {
+ printf("adding quoted-printable filter\n");
+ attachname = g_strdup_printf("attach.%d.%d", i, attach++);
+#if 0
+ folder_push_filter_save(s, attachname);
+#endif
+ g_free(attachname);
+#if 0
+ folder_push_filter_mime(s, 1);
+#endif
+ }
+
+ break;
+ case CAMEL_MIME_PARSER_STATE_BODY:
+ printf("got body %d '%.*s'\n", len, len, data);
+ break;
+ case CAMEL_MIME_PARSER_STATE_BODY_END:
+ printf("end body %d '%.*s'\n", len, len, data);
+ if (encoding && !strncasecmp(encoding, " base64", 7)) {
+ printf("removing filters\n");
+#if 0
+ folder_filter_pull(s);
+ folder_filter_pull(s);
+#endif
+ }
+ if (encoding && !strncasecmp(encoding, " quoted-printable", 17)) {
+ printf("removing filters\n");
+#if 0
+ folder_filter_pull(s);
+ folder_filter_pull(s);
+#endif
+ }
+ if (charset) {
+#if 0
+ folder_filter_pull(s);
+#endif
+ charset = NULL;
+ }
+ encoding = NULL;
+ break;
+ default:
+ break;
+ }
+ }
+ folder_scan_close(s);
+ close(fd);
+ }
+ return 0;
+}
+
+#endif /* STANDALONE */
+
diff --git a/camel/camel-mime-parser.h b/camel/camel-mime-parser.h
new file mode 100644
index 0000000000..34cf36ac16
--- /dev/null
+++ b/camel/camel-mime-parser.h
@@ -0,0 +1,148 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2000-2003 Ximian Inc.
+ *
+ * Authors: Michael Zucchi <notzed@ximian.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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef _CAMEL_MIME_PARSER_H
+#define _CAMEL_MIME_PARSER_H
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif /* __cplusplus */
+
+#include <camel/camel-object.h>
+
+#include <camel/camel-mime-utils.h>
+#include <camel/camel-mime-filter.h>
+#include <camel/camel-stream.h>
+
+#define CAMEL_MIME_PARSER(obj) CAMEL_CHECK_CAST (obj, camel_mime_parser_get_type (), CamelMimeParser)
+#define CAMEL_MIME_PARSER_CLASS(klass) CAMEL_CHECK_CLASS_CAST (klass, camel_mime_parser_get_type (), CamelMimeParserClass)
+#define CAMEL_IS_MIME_PARSER(obj) CAMEL_CHECK_TYPE (obj, camel_mime_parser_get_type ())
+
+typedef struct _CamelMimeParserClass CamelMimeParserClass;
+
+/* NOTE: if you add more states, you may need to bump the
+ start of the END tags to 16 or 32, etc - so they are
+ the same as the matching start tag, with a bit difference */
+enum _camel_mime_parser_state {
+ CAMEL_MIME_PARSER_STATE_INITIAL,
+ CAMEL_MIME_PARSER_STATE_PRE_FROM, /* data before a 'From' line */
+ CAMEL_MIME_PARSER_STATE_FROM, /* got 'From' line */
+ CAMEL_MIME_PARSER_STATE_HEADER, /* toplevel header */
+ CAMEL_MIME_PARSER_STATE_BODY, /* scanning body of message */
+ CAMEL_MIME_PARSER_STATE_MULTIPART, /* got multipart header */
+ CAMEL_MIME_PARSER_STATE_MESSAGE, /* rfc822 message */
+
+ CAMEL_MIME_PARSER_STATE_PART, /* part of a multipart */
+
+ CAMEL_MIME_PARSER_STATE_END = 8, /* bit mask for 'end' flags */
+
+ CAMEL_MIME_PARSER_STATE_EOF = 8, /* end of file */
+ CAMEL_MIME_PARSER_STATE_PRE_FROM_END, /* pre from end */
+ CAMEL_MIME_PARSER_STATE_FROM_END, /* end of whole from bracket */
+ CAMEL_MIME_PARSER_STATE_HEADER_END, /* dummy value */
+ CAMEL_MIME_PARSER_STATE_BODY_END, /* end of message */
+ CAMEL_MIME_PARSER_STATE_MULTIPART_END, /* end of multipart */
+ CAMEL_MIME_PARSER_STATE_MESSAGE_END, /* end of message */
+};
+
+struct _CamelMimeParser {
+ CamelObject parent;
+
+ struct _CamelMimeParserPrivate *priv;
+};
+
+struct _CamelMimeParserClass {
+ CamelObjectClass parent_class;
+
+ void (*message) (CamelMimeParser *parser, void *headers);
+ void (*part) (CamelMimeParser *parser);
+ void (*content) (CamelMimeParser *parser);
+};
+
+CamelType camel_mime_parser_get_type (void);
+CamelMimeParser *camel_mime_parser_new (void);
+
+/* quick-fix for parser not erroring, we can find out if it had an error afterwards */
+int camel_mime_parser_errno (CamelMimeParser *parser);
+
+/* using an fd will be a little faster, but not much (over a simple stream) */
+int camel_mime_parser_init_with_fd (CamelMimeParser *parser, int fd);
+int camel_mime_parser_init_with_stream (CamelMimeParser *parser, CamelStream *stream);
+
+/* get the stream or fd back of the parser */
+CamelStream *camel_mime_parser_stream (CamelMimeParser *parser);
+int camel_mime_parser_fd (CamelMimeParser *parser);
+
+/* scan 'From' separators? */
+void camel_mime_parser_scan_from (CamelMimeParser *parser, gboolean scan_from);
+/* Do we want to know about the pre-from data? */
+void camel_mime_parser_scan_pre_from (CamelMimeParser *parser, gboolean scan_pre_from);
+
+/* what headers to save, MUST include ^Content-Type: */
+int camel_mime_parser_set_header_regex (CamelMimeParser *parser, char *matchstr);
+
+/* normal interface */
+enum _camel_mime_parser_state camel_mime_parser_step (CamelMimeParser *parser, char **buf, size_t *buflen);
+void camel_mime_parser_unstep (CamelMimeParser *parser);
+void camel_mime_parser_drop_step (CamelMimeParser *parser);
+enum _camel_mime_parser_state camel_mime_parser_state (CamelMimeParser *parser);
+void camel_mime_parser_push_state(CamelMimeParser *mp, enum _camel_mime_parser_state newstate, const char *boundary);
+
+/* read through the parser */
+int camel_mime_parser_read (CamelMimeParser *parser, const char **databuffer, int len);
+
+/* get content type for the current part/header */
+CamelContentType *camel_mime_parser_content_type (CamelMimeParser *parser);
+
+/* get/change raw header by name */
+const char *camel_mime_parser_header (CamelMimeParser *parser, const char *name, int *offset);
+
+/* get all raw headers. READ ONLY! */
+struct _camel_header_raw *camel_mime_parser_headers_raw (CamelMimeParser *parser);
+
+/* get multipart pre/postface */
+const char *camel_mime_parser_preface (CamelMimeParser *parser);
+const char *camel_mime_parser_postface (CamelMimeParser *parser);
+
+/* return the from line content */
+const char *camel_mime_parser_from_line (CamelMimeParser *parser);
+
+/* add a processing filter for body contents */
+int camel_mime_parser_filter_add (CamelMimeParser *parser, CamelMimeFilter *filter);
+void camel_mime_parser_filter_remove (CamelMimeParser *parser, int id);
+
+/* these should be used with caution, because the state will not
+ track the seeked position */
+/* FIXME: something to bootstrap the state? */
+off_t camel_mime_parser_tell (CamelMimeParser *parser);
+off_t camel_mime_parser_seek (CamelMimeParser *parser, off_t offset, int whence);
+
+off_t camel_mime_parser_tell_start_headers (CamelMimeParser *parser);
+off_t camel_mime_parser_tell_start_from (CamelMimeParser *parser);
+off_t camel_mime_parser_tell_start_boundary(CamelMimeParser *parser);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* ! _CAMEL_MIME_PARSER_H */
diff --git a/camel/camel-mime-utils.c b/camel/camel-mime-utils.c
new file mode 100644
index 0000000000..4702afbf94
--- /dev/null
+++ b/camel/camel-mime-utils.c
@@ -0,0 +1,4320 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2000-2003 Ximian Inc.
+ *
+ * Authors: Michael Zucchi <notzed@ximian.com>
+ * Jeffrey Stedfast <fejj@ximian.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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* dont touch this file without my permission - Michael */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/param.h> /* for MAXHOSTNAMELEN */
+#include <sys/stat.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <regex.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+#include <time.h>
+
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 1024
+#endif
+
+#include <glib.h>
+#include <gal/util/e-iconv.h>
+#include <e-util/e-time-utils.h>
+
+#include "camel-mime-utils.h"
+#include "camel-charset-map.h"
+#include "camel-service.h" /* for camel_gethostbyname() */
+#include "camel-utf8.h"
+
+#ifndef CLEAN_DATE
+#include "broken-date-parser.h"
+#endif
+
+#if 0
+int strdup_count = 0;
+int malloc_count = 0;
+int free_count = 0;
+
+#define g_strdup(x) (strdup_count++, g_strdup(x))
+#define g_malloc(x) (malloc_count++, g_malloc(x))
+#define g_free(x) (free_count++, g_free(x))
+#endif
+
+/* for all non-essential warnings ... */
+#define w(x)
+
+#define d(x)
+#define d2(x)
+
+#define CAMEL_UUENCODE_CHAR(c) ((c) ? (c) + ' ' : '`')
+#define CAMEL_UUDECODE_CHAR(c) (((c) - ' ') & 077)
+
+static char *base64_alphabet =
+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+static unsigned char tohex[16] = {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+};
+
+unsigned short camel_mime_special_table[256];
+static unsigned char camel_mime_base64_rank[256];
+
+/* Used by table initialisation code for special characters */
+#define CHARS_LWSP " \t\n\r"
+#define CHARS_TSPECIAL "()<>@,;:\\\"/[]?="
+#define CHARS_SPECIAL "()<>@,;:\\\".[]"
+#define CHARS_CSPECIAL "()\\\r" /* not in comments */
+#define CHARS_DSPECIAL "[]\\\r \t" /* not in domains */
+#define CHARS_ESPECIAL "()<>@,;:\"/[]?.=_" /* list of characters that must be encoded.
+ encoded word in text specials: rfc 2047 5(1)*/
+#define CHARS_PSPECIAL "!*+-/" /* list of additional characters that can be left unencoded.
+ encoded word in phrase specials: rfc 2047 5(3) */
+#define CHARS_ATTRCHAR "*\'% " /* extra non-included attribute-chars */
+
+static void
+header_remove_bits(unsigned short bit, unsigned char *vals)
+{
+ int i;
+
+ for (i=0;vals[i];i++)
+ camel_mime_special_table[vals[i]] &= ~ bit;
+}
+
+static void
+header_init_bits(unsigned short bit, unsigned short bitcopy, int remove, unsigned char *vals)
+{
+ int i;
+ int len = strlen(vals);
+
+ if (!remove) {
+ for (i=0;i<len;i++) {
+ camel_mime_special_table[vals[i]] |= bit;
+ }
+ if (bitcopy) {
+ for (i=0;i<256;i++) {
+ if (camel_mime_special_table[i] & bitcopy)
+ camel_mime_special_table[i] |= bit;
+ }
+ }
+ } else {
+ for (i=0;i<256;i++)
+ camel_mime_special_table[i] |= bit;
+ for (i=0;i<len;i++) {
+ camel_mime_special_table[vals[i]] &= ~bit;
+ }
+ if (bitcopy) {
+ for (i=0;i<256;i++) {
+ if (camel_mime_special_table[i] & bitcopy)
+ camel_mime_special_table[i] &= ~bit;
+ }
+ }
+ }
+}
+
+static void
+header_decode_init(void)
+{
+ int i;
+
+ for (i=0;i<256;i++) {
+ camel_mime_special_table[i] = 0;
+ if (i<32 || i==127)
+ camel_mime_special_table[i] |= CAMEL_MIME_IS_CTRL;
+ else if (i < 127)
+ camel_mime_special_table[i] |= CAMEL_MIME_IS_ATTRCHAR;
+ if ((i>=32 && i<=60) || (i>=62 && i<=126) || i==9)
+ camel_mime_special_table[i] |= (CAMEL_MIME_IS_QPSAFE|CAMEL_MIME_IS_ESAFE);
+ if ((i>='0' && i<='9') || (i>='a' && i<='z') || (i>='A' && i<= 'Z'))
+ camel_mime_special_table[i] |= CAMEL_MIME_IS_PSAFE;
+ }
+ camel_mime_special_table[' '] |= CAMEL_MIME_IS_SPACE;
+ header_init_bits(CAMEL_MIME_IS_LWSP, 0, 0, CHARS_LWSP);
+ header_init_bits(CAMEL_MIME_IS_TSPECIAL, CAMEL_MIME_IS_CTRL, 0, CHARS_TSPECIAL);
+ header_init_bits(CAMEL_MIME_IS_SPECIAL, 0, 0, CHARS_SPECIAL);
+ header_init_bits(CAMEL_MIME_IS_DSPECIAL, 0, FALSE, CHARS_DSPECIAL);
+ header_remove_bits(CAMEL_MIME_IS_ESAFE, CHARS_ESPECIAL);
+ header_remove_bits(CAMEL_MIME_IS_ATTRCHAR, CHARS_TSPECIAL CHARS_ATTRCHAR);
+ header_init_bits(CAMEL_MIME_IS_PSAFE, 0, 0, CHARS_PSPECIAL);
+}
+
+static void
+base64_init(void)
+{
+ int i;
+
+ memset(camel_mime_base64_rank, 0xff, sizeof(camel_mime_base64_rank));
+ for (i=0;i<64;i++) {
+ camel_mime_base64_rank[(unsigned int)base64_alphabet[i]] = i;
+ }
+ camel_mime_base64_rank['='] = 0;
+}
+
+/* call this when finished encoding everything, to
+ flush off the last little bit */
+size_t
+camel_base64_encode_close(unsigned char *in, size_t inlen, gboolean break_lines, unsigned char *out, int *state, int *save)
+{
+ int c1, c2;
+ unsigned char *outptr = out;
+
+ if (inlen>0)
+ outptr += camel_base64_encode_step(in, inlen, break_lines, outptr, state, save);
+
+ c1 = ((unsigned char *)save)[1];
+ c2 = ((unsigned char *)save)[2];
+
+ d(printf("mode = %d\nc1 = %c\nc2 = %c\n",
+ (int)((char *)save)[0],
+ (int)((char *)save)[1],
+ (int)((char *)save)[2]));
+
+ switch (((char *)save)[0]) {
+ case 2:
+ outptr[2] = base64_alphabet[ ( (c2 &0x0f) << 2 ) ];
+ g_assert(outptr[2] != 0);
+ goto skip;
+ case 1:
+ outptr[2] = '=';
+ skip:
+ outptr[0] = base64_alphabet[ c1 >> 2 ];
+ outptr[1] = base64_alphabet[ c2 >> 4 | ( (c1&0x3) << 4 )];
+ outptr[3] = '=';
+ outptr += 4;
+ break;
+ }
+ if (break_lines)
+ *outptr++ = '\n';
+
+ *save = 0;
+ *state = 0;
+
+ return outptr-out;
+}
+
+/*
+ performs an 'encode step', only encodes blocks of 3 characters to the
+ output at a time, saves left-over state in state and save (initialise to
+ 0 on first invocation).
+*/
+size_t
+camel_base64_encode_step(unsigned char *in, size_t len, gboolean break_lines, unsigned char *out, int *state, int *save)
+{
+ register unsigned char *inptr, *outptr;
+
+ if (len<=0)
+ return 0;
+
+ inptr = in;
+ outptr = out;
+
+ d(printf("we have %d chars, and %d saved chars\n", len, ((char *)save)[0]));
+
+ if (len + ((char *)save)[0] > 2) {
+ unsigned char *inend = in+len-2;
+ register int c1, c2, c3;
+ register int already;
+
+ already = *state;
+
+ switch (((char *)save)[0]) {
+ case 1: c1 = ((unsigned char *)save)[1]; goto skip1;
+ case 2: c1 = ((unsigned char *)save)[1];
+ c2 = ((unsigned char *)save)[2]; goto skip2;
+ }
+
+ /* yes, we jump into the loop, no i'm not going to change it, it's beautiful! */
+ while (inptr < inend) {
+ c1 = *inptr++;
+ skip1:
+ c2 = *inptr++;
+ skip2:
+ c3 = *inptr++;
+ *outptr++ = base64_alphabet[ c1 >> 2 ];
+ *outptr++ = base64_alphabet[ c2 >> 4 | ( (c1&0x3) << 4 ) ];
+ *outptr++ = base64_alphabet[ ( (c2 &0x0f) << 2 ) | (c3 >> 6) ];
+ *outptr++ = base64_alphabet[ c3 & 0x3f ];
+ /* this is a bit ugly ... */
+ if (break_lines && (++already)>=19) {
+ *outptr++='\n';
+ already = 0;
+ }
+ }
+
+ ((char *)save)[0] = 0;
+ len = 2-(inptr-inend);
+ *state = already;
+ }
+
+ d(printf("state = %d, len = %d\n",
+ (int)((char *)save)[0],
+ len));
+
+ if (len>0) {
+ register char *saveout;
+
+ /* points to the slot for the next char to save */
+ saveout = & (((char *)save)[1]) + ((char *)save)[0];
+
+ /* len can only be 0 1 or 2 */
+ switch(len) {
+ case 2: *saveout++ = *inptr++;
+ case 1: *saveout++ = *inptr++;
+ }
+ ((char *)save)[0]+=len;
+ }
+
+ d(printf("mode = %d\nc1 = %c\nc2 = %c\n",
+ (int)((char *)save)[0],
+ (int)((char *)save)[1],
+ (int)((char *)save)[2]));
+
+ return outptr-out;
+}
+
+
+/**
+ * camel_base64_decode_step: decode a chunk of base64 encoded data
+ * @in: input stream
+ * @len: max length of data to decode
+ * @out: output stream
+ * @state: holds the number of bits that are stored in @save
+ * @save: leftover bits that have not yet been decoded
+ *
+ * Decodes a chunk of base64 encoded data
+ **/
+size_t
+camel_base64_decode_step(unsigned char *in, size_t len, unsigned char *out, int *state, unsigned int *save)
+{
+ register unsigned char *inptr, *outptr;
+ unsigned char *inend, c;
+ register unsigned int v;
+ int i;
+
+ inend = in+len;
+ outptr = out;
+
+ /* convert 4 base64 bytes to 3 normal bytes */
+ v=*save;
+ i=*state;
+ inptr = in;
+ while (inptr<inend) {
+ c = camel_mime_base64_rank[*inptr++];
+ if (c != 0xff) {
+ v = (v<<6) | c;
+ i++;
+ if (i==4) {
+ *outptr++ = v>>16;
+ *outptr++ = v>>8;
+ *outptr++ = v;
+ i=0;
+ }
+ }
+ }
+
+ *save = v;
+ *state = i;
+
+ /* quick scan back for '=' on the end somewhere */
+ /* fortunately we can drop 1 output char for each trailing = (upto 2) */
+ i=2;
+ while (inptr>in && i) {
+ inptr--;
+ if (camel_mime_base64_rank[*inptr] != 0xff) {
+ if (*inptr == '=' && outptr>out)
+ outptr--;
+ i--;
+ }
+ }
+
+ /* if i!= 0 then there is a truncation error! */
+ return outptr-out;
+}
+
+char *
+camel_base64_encode_simple (const char *data, size_t len)
+{
+ unsigned char *out;
+ int state = 0, outlen;
+ unsigned int save = 0;
+
+ out = g_malloc (len * 4 / 3 + 5);
+ outlen = camel_base64_encode_close ((unsigned char *)data, len, FALSE,
+ out, &state, &save);
+ out[outlen] = '\0';
+ return (char *)out;
+}
+
+size_t
+camel_base64_decode_simple (char *data, size_t len)
+{
+ int state = 0;
+ unsigned int save = 0;
+
+ return camel_base64_decode_step ((unsigned char *)data, len,
+ (unsigned char *)data, &state, &save);
+}
+
+/**
+ * camel_uuencode_close: uuencode a chunk of data
+ * @in: input stream
+ * @len: input stream length
+ * @out: output stream
+ * @uubuf: temporary buffer of 60 bytes
+ * @state: holds the number of bits that are stored in @save
+ * @save: leftover bits that have not yet been encoded
+ *
+ * Returns the number of bytes encoded. Call this when finished
+ * encoding data with camel_uuencode_step to flush off the last little
+ * bit.
+ **/
+size_t
+camel_uuencode_close (unsigned char *in, size_t len, unsigned char *out, unsigned char *uubuf, int *state, guint32 *save)
+{
+ register unsigned char *outptr, *bufptr;
+ register guint32 saved;
+ int uulen, uufill, i;
+
+ outptr = out;
+
+ if (len > 0)
+ outptr += camel_uuencode_step (in, len, out, uubuf, state, save);
+
+ uufill = 0;
+
+ saved = *save;
+ i = *state & 0xff;
+ uulen = (*state >> 8) & 0xff;
+
+ bufptr = uubuf + ((uulen / 3) * 4);
+
+ if (i > 0) {
+ while (i < 3) {
+ saved <<= 8 | 0;
+ uufill++;
+ i++;
+ }
+
+ if (i == 3) {
+ /* convert 3 normal bytes into 4 uuencoded bytes */
+ unsigned char b0, b1, b2;
+
+ b0 = saved >> 16;
+ b1 = saved >> 8 & 0xff;
+ b2 = saved & 0xff;
+
+ *bufptr++ = CAMEL_UUENCODE_CHAR ((b0 >> 2) & 0x3f);
+ *bufptr++ = CAMEL_UUENCODE_CHAR (((b0 << 4) | ((b1 >> 4) & 0xf)) & 0x3f);
+ *bufptr++ = CAMEL_UUENCODE_CHAR (((b1 << 2) | ((b2 >> 6) & 0x3)) & 0x3f);
+ *bufptr++ = CAMEL_UUENCODE_CHAR (b2 & 0x3f);
+
+ i = 0;
+ saved = 0;
+ uulen += 3;
+ }
+ }
+
+ if (uulen > 0) {
+ int cplen = ((uulen / 3) * 4);
+
+ *outptr++ = CAMEL_UUENCODE_CHAR ((uulen - uufill) & 0xff);
+ memcpy (outptr, uubuf, cplen);
+ outptr += cplen;
+ *outptr++ = '\n';
+ uulen = 0;
+ }
+
+ *outptr++ = CAMEL_UUENCODE_CHAR (uulen & 0xff);
+ *outptr++ = '\n';
+
+ *save = 0;
+ *state = 0;
+
+ return outptr - out;
+}
+
+
+/**
+ * camel_uuencode_step: uuencode a chunk of data
+ * @in: input stream
+ * @len: input stream length
+ * @out: output stream
+ * @uubuf: temporary buffer of 60 bytes
+ * @state: holds the number of bits that are stored in @save
+ * @save: leftover bits that have not yet been encoded
+ *
+ * Returns the number of bytes encoded. Performs an 'encode step',
+ * only encodes blocks of 45 characters to the output at a time, saves
+ * left-over state in @uubuf, @state and @save (initialize to 0 on first
+ * invocation).
+ **/
+size_t
+camel_uuencode_step (unsigned char *in, size_t len, unsigned char *out, unsigned char *uubuf, int *state, guint32 *save)
+{
+ register unsigned char *inptr, *outptr, *bufptr;
+ unsigned char *inend;
+ register guint32 saved;
+ int uulen, i;
+
+ saved = *save;
+ i = *state & 0xff;
+ uulen = (*state >> 8) & 0xff;
+
+ inptr = in;
+ inend = in + len;
+
+ outptr = out;
+
+ bufptr = uubuf + ((uulen / 3) * 4);
+
+ while (inptr < inend) {
+ while (uulen < 45 && inptr < inend) {
+ while (i < 3 && inptr < inend) {
+ saved = (saved << 8) | *inptr++;
+ i++;
+ }
+
+ if (i == 3) {
+ /* convert 3 normal bytes into 4 uuencoded bytes */
+ unsigned char b0, b1, b2;
+
+ b0 = saved >> 16;
+ b1 = saved >> 8 & 0xff;
+ b2 = saved & 0xff;
+
+ *bufptr++ = CAMEL_UUENCODE_CHAR ((b0 >> 2) & 0x3f);
+ *bufptr++ = CAMEL_UUENCODE_CHAR (((b0 << 4) | ((b1 >> 4) & 0xf)) & 0x3f);
+ *bufptr++ = CAMEL_UUENCODE_CHAR (((b1 << 2) | ((b2 >> 6) & 0x3)) & 0x3f);
+ *bufptr++ = CAMEL_UUENCODE_CHAR (b2 & 0x3f);
+
+ i = 0;
+ saved = 0;
+ uulen += 3;
+ }
+ }
+
+ if (uulen >= 45) {
+ *outptr++ = CAMEL_UUENCODE_CHAR (uulen & 0xff);
+ memcpy (outptr, uubuf, ((uulen / 3) * 4));
+ outptr += ((uulen / 3) * 4);
+ *outptr++ = '\n';
+ uulen = 0;
+ bufptr = uubuf;
+ }
+ }
+
+ *save = saved;
+ *state = ((uulen & 0xff) << 8) | (i & 0xff);
+
+ return outptr - out;
+}
+
+
+/**
+ * camel_uudecode_step: uudecode a chunk of data
+ * @in: input stream
+ * @inlen: max length of data to decode ( normally strlen(in) ??)
+ * @out: output stream
+ * @state: holds the number of bits that are stored in @save
+ * @save: leftover bits that have not yet been decoded
+ *
+ * Returns the number of bytes decoded. Performs a 'decode step' on
+ * a chunk of uuencoded data. Assumes the "begin <mode> <file name>"
+ * line has been stripped off.
+ **/
+size_t
+camel_uudecode_step (unsigned char *in, size_t len, unsigned char *out, int *state, guint32 *save)
+{
+ register unsigned char *inptr, *outptr;
+ unsigned char *inend, ch;
+ register guint32 saved;
+ gboolean last_was_eoln;
+ int uulen, i;
+
+ if (*state & CAMEL_UUDECODE_STATE_END)
+ return 0;
+
+ saved = *save;
+ i = *state & 0xff;
+ uulen = (*state >> 8) & 0xff;
+ if (uulen == 0)
+ last_was_eoln = TRUE;
+ else
+ last_was_eoln = FALSE;
+
+ inend = in + len;
+ outptr = out;
+
+ inptr = in;
+ while (inptr < inend) {
+ if (*inptr == '\n' || last_was_eoln) {
+ if (last_was_eoln && *inptr != '\n') {
+ uulen = CAMEL_UUDECODE_CHAR (*inptr);
+ last_was_eoln = FALSE;
+ if (uulen == 0) {
+ *state |= CAMEL_UUDECODE_STATE_END;
+ break;
+ }
+ } else {
+ last_was_eoln = TRUE;
+ }
+
+ inptr++;
+ continue;
+ }
+
+ ch = *inptr++;
+
+ if (uulen > 0) {
+ /* save the byte */
+ saved = (saved << 8) | ch;
+ i++;
+ if (i == 4) {
+ /* convert 4 uuencoded bytes to 3 normal bytes */
+ unsigned char b0, b1, b2, b3;
+
+ b0 = saved >> 24;
+ b1 = saved >> 16 & 0xff;
+ b2 = saved >> 8 & 0xff;
+ b3 = saved & 0xff;
+
+ if (uulen >= 3) {
+ *outptr++ = CAMEL_UUDECODE_CHAR (b0) << 2 | CAMEL_UUDECODE_CHAR (b1) >> 4;
+ *outptr++ = CAMEL_UUDECODE_CHAR (b1) << 4 | CAMEL_UUDECODE_CHAR (b2) >> 2;
+ *outptr++ = CAMEL_UUDECODE_CHAR (b2) << 6 | CAMEL_UUDECODE_CHAR (b3);
+ } else {
+ if (uulen >= 1) {
+ *outptr++ = CAMEL_UUDECODE_CHAR (b0) << 2 | CAMEL_UUDECODE_CHAR (b1) >> 4;
+ }
+ if (uulen >= 2) {
+ *outptr++ = CAMEL_UUDECODE_CHAR (b1) << 4 | CAMEL_UUDECODE_CHAR (b2) >> 2;
+ }
+ }
+
+ i = 0;
+ saved = 0;
+ uulen -= 3;
+ }
+ } else {
+ break;
+ }
+ }
+
+ *save = saved;
+ *state = (*state & CAMEL_UUDECODE_STATE_MASK) | ((uulen & 0xff) << 8) | (i & 0xff);
+
+ return outptr - out;
+}
+
+
+/* complete qp encoding */
+size_t
+camel_quoted_decode_close(unsigned char *in, size_t len, unsigned char *out, int *state, int *save)
+{
+ register unsigned char *outptr = out;
+ int last;
+
+ if (len>0)
+ outptr += camel_quoted_encode_step(in, len, outptr, state, save);
+
+ last = *state;
+ if (last != -1) {
+ /* space/tab must be encoded if it's the last character on
+ the line */
+ if (camel_mime_is_qpsafe(last) && last!=' ' && last!=9) {
+ *outptr++ = last;
+ } else {
+ *outptr++ = '=';
+ *outptr++ = tohex[(last>>4) & 0xf];
+ *outptr++ = tohex[last & 0xf];
+ }
+ }
+
+ *save = 0;
+ *state = -1;
+
+ return outptr-out;
+}
+
+/* perform qp encoding, initialise state to -1 and save to 0 on first invocation */
+size_t
+camel_quoted_encode_step (unsigned char *in, size_t len, unsigned char *out, int *statep, int *save)
+{
+ register guchar *inptr, *outptr, *inend;
+ unsigned char c;
+ register int sofar = *save; /* keeps track of how many chars on a line */
+ register int last = *statep; /* keeps track if last char to end was a space cr etc */
+
+ inptr = in;
+ inend = in + len;
+ outptr = out;
+ while (inptr < inend) {
+ c = *inptr++;
+ if (c == '\r') {
+ if (last != -1) {
+ *outptr++ = '=';
+ *outptr++ = tohex[(last >> 4) & 0xf];
+ *outptr++ = tohex[last & 0xf];
+ sofar += 3;
+ }
+ last = c;
+ } else if (c == '\n') {
+ if (last != -1 && last != '\r') {
+ *outptr++ = '=';
+ *outptr++ = tohex[(last >> 4) & 0xf];
+ *outptr++ = tohex[last & 0xf];
+ }
+ *outptr++ = '\n';
+ sofar = 0;
+ last = -1;
+ } else {
+ if (last != -1) {
+ if (camel_mime_is_qpsafe(last)) {
+ *outptr++ = last;
+ sofar++;
+ } else {
+ *outptr++ = '=';
+ *outptr++ = tohex[(last >> 4) & 0xf];
+ *outptr++ = tohex[last & 0xf];
+ sofar += 3;
+ }
+ }
+
+ if (camel_mime_is_qpsafe(c)) {
+ if (sofar > 74) {
+ *outptr++ = '=';
+ *outptr++ = '\n';
+ sofar = 0;
+ }
+
+ /* delay output of space char */
+ if (c==' ' || c=='\t') {
+ last = c;
+ } else {
+ *outptr++ = c;
+ sofar++;
+ last = -1;
+ }
+ } else {
+ if (sofar > 72) {
+ *outptr++ = '=';
+ *outptr++ = '\n';
+ sofar = 3;
+ } else
+ sofar += 3;
+
+ *outptr++ = '=';
+ *outptr++ = tohex[(c >> 4) & 0xf];
+ *outptr++ = tohex[c & 0xf];
+ last = -1;
+ }
+ }
+ }
+ *save = sofar;
+ *statep = last;
+
+ return (outptr - out);
+}
+
+/*
+ FIXME: this does not strip trailing spaces from lines (as it should, rfc 2045, section 6.7)
+ Should it also canonicalise the end of line to CR LF??
+
+ Note: Trailing rubbish (at the end of input), like = or =x or =\r will be lost.
+*/
+
+size_t
+camel_quoted_decode_step(unsigned char *in, size_t len, unsigned char *out, int *savestate, int *saveme)
+{
+ register unsigned char *inptr, *outptr;
+ unsigned char *inend, c;
+ int state, save;
+
+ inend = in+len;
+ outptr = out;
+
+ d(printf("quoted-printable, decoding text '%.*s'\n", len, in));
+
+ state = *savestate;
+ save = *saveme;
+ inptr = in;
+ while (inptr<inend) {
+ switch (state) {
+ case 0:
+ while (inptr<inend) {
+ c = *inptr++;
+ if (c=='=') {
+ state = 1;
+ break;
+ }
+#ifdef CANONICALISE_EOL
+ /*else if (c=='\r') {
+ state = 3;
+ } else if (c=='\n') {
+ *outptr++ = '\r';
+ *outptr++ = c;
+ } */
+#endif
+ else {
+ *outptr++ = c;
+ }
+ }
+ break;
+ case 1:
+ c = *inptr++;
+ if (c=='\n') {
+ /* soft break ... unix end of line */
+ state = 0;
+ } else {
+ save = c;
+ state = 2;
+ }
+ break;
+ case 2:
+ c = *inptr++;
+ if (isxdigit(c) && isxdigit(save)) {
+ c = toupper(c);
+ save = toupper(save);
+ *outptr++ = (((save>='A'?save-'A'+10:save-'0')&0x0f) << 4)
+ | ((c>='A'?c-'A'+10:c-'0')&0x0f);
+ } else if (c=='\n' && save == '\r') {
+ /* soft break ... canonical end of line */
+ } else {
+ /* just output the data */
+ *outptr++ = '=';
+ *outptr++ = save;
+ *outptr++ = c;
+ }
+ state = 0;
+ break;
+#ifdef CANONICALISE_EOL
+ case 3:
+ /* convert \r -> to \r\n, leaves \r\n alone */
+ c = *inptr++;
+ if (c=='\n') {
+ *outptr++ = '\r';
+ *outptr++ = c;
+ } else {
+ *outptr++ = '\r';
+ *outptr++ = '\n';
+ *outptr++ = c;
+ }
+ state = 0;
+ break;
+#endif
+ }
+ }
+
+ *savestate = state;
+ *saveme = save;
+
+ return outptr-out;
+}
+
+/*
+ this is for the "Q" encoding of international words,
+ which is slightly different than plain quoted-printable (mainly by allowing 0x20 <> _)
+*/
+static size_t
+quoted_decode(const unsigned char *in, size_t len, unsigned char *out)
+{
+ register const unsigned char *inptr;
+ register unsigned char *outptr;
+ unsigned const char *inend;
+ unsigned char c, c1;
+ int ret = 0;
+
+ inend = in+len;
+ outptr = out;
+
+ d(printf("decoding text '%.*s'\n", len, in));
+
+ inptr = in;
+ while (inptr<inend) {
+ c = *inptr++;
+ if (c=='=') {
+ /* silently ignore truncated data? */
+ if (inend-in>=2) {
+ c = toupper(*inptr++);
+ c1 = toupper(*inptr++);
+ *outptr++ = (((c>='A'?c-'A'+10:c-'0')&0x0f) << 4)
+ | ((c1>='A'?c1-'A'+10:c1-'0')&0x0f);
+ } else {
+ ret = -1;
+ break;
+ }
+ } else if (c=='_') {
+ *outptr++ = 0x20;
+ } else if (c==' ' || c==0x09) {
+ /* FIXME: this is an error! ignore for now ... */
+ ret = -1;
+ break;
+ } else {
+ *outptr++ = c;
+ }
+ }
+ if (ret==0) {
+ return outptr-out;
+ }
+ return 0;
+}
+
+/* rfc2047 version of quoted-printable */
+/* safemask is the mask to apply to the camel_mime_special_table to determine what
+ characters can safely be included without encoding */
+static size_t
+quoted_encode (const unsigned char *in, size_t len, unsigned char *out, unsigned short safemask)
+{
+ register const unsigned char *inptr, *inend;
+ unsigned char *outptr;
+ unsigned char c;
+
+ inptr = in;
+ inend = in + len;
+ outptr = out;
+ while (inptr < inend) {
+ c = *inptr++;
+ if (c==' ') {
+ *outptr++ = '_';
+ } else if (camel_mime_special_table[c] & safemask) {
+ *outptr++ = c;
+ } else {
+ *outptr++ = '=';
+ *outptr++ = tohex[(c >> 4) & 0xf];
+ *outptr++ = tohex[c & 0xf];
+ }
+ }
+
+ d(printf("encoding '%.*s' = '%.*s'\n", len, in, outptr-out, out));
+
+ return (outptr - out);
+}
+
+
+static void
+header_decode_lwsp(const char **in)
+{
+ const char *inptr = *in;
+ char c;
+
+ d2(printf("is ws: '%s'\n", *in));
+
+ while (camel_mime_is_lwsp(*inptr) || (*inptr =='(' && *inptr != '\0')) {
+ while (camel_mime_is_lwsp(*inptr) && inptr != '\0') {
+ d2(printf("(%c)", *inptr));
+ inptr++;
+ }
+ d2(printf("\n"));
+
+ /* check for comments */
+ if (*inptr == '(') {
+ int depth = 1;
+ inptr++;
+ while (depth && (c=*inptr) && *inptr != '\0') {
+ if (c=='\\' && inptr[1]) {
+ inptr++;
+ } else if (c=='(') {
+ depth++;
+ } else if (c==')') {
+ depth--;
+ }
+ inptr++;
+ }
+ }
+ }
+ *in = inptr;
+}
+
+/* decode rfc 2047 encoded string segment */
+static char *
+rfc2047_decode_word(const char *in, size_t len)
+{
+ const char *inptr = in+2;
+ const char *inend = in+len-2;
+ const char *inbuf;
+ const char *charset;
+ char *encname, *p;
+ int tmplen;
+ size_t ret;
+ char *decword = NULL;
+ char *decoded = NULL;
+ char *outbase = NULL;
+ char *outbuf;
+ size_t inlen, outlen;
+ gboolean retried = FALSE;
+ iconv_t ic;
+
+ d(printf("rfc2047: decoding '%.*s'\n", len, in));
+
+ /* quick check to see if this could possibly be a real encoded word */
+ if (len < 8 || !(in[0] == '=' && in[1] == '?' && in[len-1] == '=' && in[len-2] == '?')) {
+ d(printf("invalid\n"));
+ return NULL;
+ }
+
+ /* skip past the charset to the encoding type */
+ inptr = memchr (inptr, '?', inend-inptr);
+ if (inptr != NULL && inptr < inend + 2 && inptr[2] == '?') {
+ d(printf("found ?, encoding is '%c'\n", inptr[0]));
+ inptr++;
+ tmplen = inend-inptr-2;
+ decword = g_alloca (tmplen); /* this will always be more-than-enough room */
+ switch(toupper(inptr[0])) {
+ case 'Q':
+ inlen = quoted_decode(inptr+2, tmplen, decword);
+ break;
+ case 'B': {
+ int state = 0;
+ unsigned int save = 0;
+
+ inlen = camel_base64_decode_step((char *)inptr+2, tmplen, decword, &state, &save);
+ /* if state != 0 then error? */
+ break;
+ }
+ default:
+ /* uhhh, unknown encoding type - probably an invalid encoded word string */
+ return NULL;
+ }
+ d(printf("The encoded length = %d\n", inlen));
+ if (inlen > 0) {
+ /* yuck, all this snot is to setup iconv! */
+ tmplen = inptr - in - 3;
+ encname = g_alloca (tmplen + 1);
+ memcpy (encname, in + 2, tmplen);
+ encname[tmplen] = '\0';
+
+ /* rfc2231 updates rfc2047 encoded words...
+ * The ABNF given in RFC 2047 for encoded-words is:
+ * encoded-word := "=?" charset "?" encoding "?" encoded-text "?="
+ * This specification changes this ABNF to:
+ * encoded-word := "=?" charset ["*" language] "?" encoding "?" encoded-text "?="
+ */
+
+ /* trim off the 'language' part if it's there... */
+ p = strchr (encname, '*');
+ if (p)
+ *p = '\0';
+
+ charset = e_iconv_charset_name (encname);
+
+ inbuf = decword;
+
+ outlen = inlen * 6 + 16;
+ outbase = g_alloca (outlen);
+ outbuf = outbase;
+
+ retry:
+ ic = e_iconv_open ("UTF-8", charset);
+ if (ic != (iconv_t) -1) {
+ ret = e_iconv (ic, &inbuf, &inlen, &outbuf, &outlen);
+ if (ret != (size_t) -1) {
+ e_iconv (ic, NULL, 0, &outbuf, &outlen);
+ *outbuf = 0;
+ decoded = g_strdup (outbase);
+ }
+ e_iconv_close (ic);
+ } else {
+ w(g_warning ("Cannot decode charset, header display may be corrupt: %s: %s",
+ charset, strerror (errno)));
+
+ if (!retried) {
+ charset = e_iconv_locale_charset ();
+ if (!charset)
+ charset = "iso-8859-1";
+
+ retried = TRUE;
+ goto retry;
+ }
+
+ /* we return the encoded word here because we've got to return valid utf8 */
+ decoded = g_strndup (in, inlen);
+ }
+ }
+ }
+
+ d(printf("decoded '%s'\n", decoded));
+
+ return decoded;
+}
+
+/* ok, a lot of mailers are BROKEN, and send iso-latin1 encoded
+ headers, when they should just be sticking to US-ASCII
+ according to the rfc's. Anyway, since the conversion to utf-8
+ is trivial, just do it here without iconv */
+static GString *
+append_latin1 (GString *out, const char *in, size_t len)
+{
+ unsigned int c;
+
+ while (len) {
+ c = (unsigned int)*in++;
+ len--;
+ if (c & 0x80) {
+ out = g_string_append_c (out, 0xc0 | ((c >> 6) & 0x3)); /* 110000xx */
+ out = g_string_append_c (out, 0x80 | (c & 0x3f)); /* 10xxxxxx */
+ } else {
+ out = g_string_append_c (out, c);
+ }
+ }
+ return out;
+}
+
+static int
+append_8bit (GString *out, const char *inbuf, size_t inlen, const char *charset)
+{
+ char *outbase, *outbuf;
+ size_t outlen;
+ iconv_t ic;
+
+ ic = e_iconv_open ("UTF-8", charset);
+ if (ic == (iconv_t) -1)
+ return FALSE;
+
+ outlen = inlen * 6 + 16;
+ outbuf = outbase = g_malloc(outlen);
+
+ if (e_iconv (ic, &inbuf, &inlen, &outbuf, &outlen) == (size_t) -1) {
+ w(g_warning("Conversion to '%s' failed: %s", charset, strerror (errno)));
+ g_free(outbase);
+ e_iconv_close (ic);
+ return FALSE;
+ }
+
+ e_iconv (ic, NULL, NULL, &outbuf, &outlen);
+
+ *outbuf = 0;
+ g_string_append(out, outbase);
+ g_free(outbase);
+ e_iconv_close (ic);
+
+ return TRUE;
+
+}
+
+static GString *
+append_quoted_pair (GString *str, const char *in, gssize inlen)
+{
+ register const char *inptr = in;
+ const char *inend = in + inlen;
+ char c;
+
+ while (inptr < inend) {
+ c = *inptr++;
+ if (c == '\\' && inptr < inend)
+ g_string_append_c (str, *inptr++);
+ else
+ g_string_append_c (str, c);
+ }
+
+ return str;
+}
+
+/* decodes a simple text, rfc822 + rfc2047 */
+static char *
+header_decode_text (const char *in, size_t inlen, int ctext, const char *default_charset)
+{
+ GString *out;
+ const char *inptr, *inend, *start, *chunk, *locale_charset;
+ GString *(* append) (GString *, const char *, gssize);
+ char *dword = NULL;
+ guint32 mask;
+
+ locale_charset = e_iconv_locale_charset ();
+
+ if (ctext) {
+ mask = (CAMEL_MIME_IS_SPECIAL | CAMEL_MIME_IS_SPACE | CAMEL_MIME_IS_CTRL);
+ append = append_quoted_pair;
+ } else {
+ mask = (CAMEL_MIME_IS_LWSP);
+ append = g_string_append_len;
+ }
+
+ out = g_string_new ("");
+ inptr = in;
+ inend = inptr + inlen;
+ chunk = NULL;
+
+ while (inptr < inend) {
+ start = inptr;
+ while (inptr < inend && camel_mime_is_type (*inptr, mask))
+ inptr++;
+
+ if (inptr == inend) {
+ append (out, start, inptr - start);
+ break;
+ } else if (dword == NULL) {
+ append (out, start, inptr - start);
+ } else {
+ chunk = start;
+ }
+
+ start = inptr;
+ while (inptr < inend && !camel_mime_is_type (*inptr, mask))
+ inptr++;
+
+ dword = rfc2047_decode_word(start, inptr-start);
+ if (dword) {
+ g_string_append(out, dword);
+ g_free(dword);
+ } else {
+ if (!chunk)
+ chunk = start;
+
+ if ((default_charset == NULL || !append_8bit (out, chunk, inptr-chunk, default_charset))
+ && (locale_charset == NULL || !append_8bit(out, chunk, inptr-chunk, locale_charset)))
+ append_latin1(out, chunk, inptr-chunk);
+ }
+
+ chunk = NULL;
+ }
+
+ dword = out->str;
+ g_string_free (out, FALSE);
+
+ return dword;
+}
+
+char *
+camel_header_decode_string (const char *in, const char *default_charset)
+{
+ if (in == NULL)
+ return NULL;
+ return header_decode_text (in, strlen (in), FALSE, default_charset);
+}
+
+char *
+camel_header_format_ctext (const char *in, const char *default_charset)
+{
+ if (in == NULL)
+ return NULL;
+ return header_decode_text (in, strlen (in), TRUE, default_charset);
+}
+
+/* how long a sequence of pre-encoded words should be less than, to attempt to
+ fit into a properly folded word. Only a guide. */
+#define CAMEL_FOLD_PREENCODED (24)
+
+/* FIXME: needs a way to cache iconv opens for different charsets? */
+static void
+rfc2047_encode_word(GString *outstring, const char *in, size_t len, const char *type, unsigned short safemask)
+{
+ iconv_t ic = (iconv_t) -1;
+ char *buffer, *out, *ascii;
+ size_t inlen, outlen, enclen, bufflen;
+ const char *inptr, *p;
+ int first = 1;
+
+ d(printf("Converting [%d] '%.*s' to %s\n", len, len, in, type));
+
+ /* convert utf8->encoding */
+ bufflen = len * 6 + 16;
+ buffer = g_alloca (bufflen);
+ inlen = len;
+ inptr = in;
+
+ ascii = g_alloca (bufflen);
+
+ if (strcasecmp (type, "UTF-8") != 0)
+ ic = e_iconv_open (type, "UTF-8");
+
+ while (inlen) {
+ size_t convlen, proclen;
+ int i;
+
+ /* break up words into smaller bits, what we really want is encoded + overhead < 75,
+ but we'll just guess what that means in terms of input chars, and assume its good enough */
+
+ out = buffer;
+ outlen = bufflen;
+
+ if (ic == (iconv_t) -1) {
+ /* native encoding case, the easy one (?) */
+ /* we work out how much we can convert, and still be in length */
+ /* proclen will be the result of input characters that we can convert, to the nearest
+ (approximated) valid utf8 char */
+ convlen = 0;
+ proclen = 0;
+ p = inptr;
+ i = 0;
+ while (p < (in+len) && convlen < (75 - strlen("=?utf-8?q\?\?="))) {
+ unsigned char c = *p++;
+
+ if (c >= 0xc0)
+ proclen = i;
+ i++;
+ if (c < 0x80)
+ proclen = i;
+ if (camel_mime_special_table[c] & safemask)
+ convlen += 1;
+ else
+ convlen += 3;
+ }
+ /* well, we probably have broken utf8, just copy it anyway what the heck */
+ if (proclen == 0) {
+ w(g_warning("Appear to have truncated utf8 sequence"));
+ proclen = inlen;
+ }
+ memcpy(out, inptr, proclen);
+ inptr += proclen;
+ inlen -= proclen;
+ out += proclen;
+ } else {
+ /* well we could do similar, but we can't (without undue effort), we'll just break it up into
+ hopefully-small-enough chunks, and leave it at that */
+ convlen = MIN(inlen, CAMEL_FOLD_PREENCODED);
+ p = inptr;
+ if (e_iconv (ic, &inptr, &convlen, &out, &outlen) == (size_t) -1 && errno != EINVAL) {
+ w(g_warning("Conversion problem: conversion truncated: %s", strerror (errno)));
+ /* blah, we include it anyway, better than infinite loop ... */
+ inptr = p + convlen;
+ } else {
+ /* make sure we flush out any shift state */
+ e_iconv (ic, NULL, 0, &out, &outlen);
+ }
+ inlen -= (inptr - p);
+ }
+
+ enclen = out-buffer;
+
+ if (enclen) {
+ /* create token */
+ out = ascii;
+ if (first)
+ first = 0;
+ else
+ *out++ = ' ';
+ out += sprintf (out, "=?%s?Q?", type);
+ out += quoted_encode (buffer, enclen, out, safemask);
+ sprintf (out, "?=");
+
+ d(printf("converted part = %s\n", ascii));
+
+ g_string_append (outstring, ascii);
+ }
+ }
+
+ if (ic != (iconv_t) -1)
+ e_iconv_close (ic);
+}
+
+
+/* TODO: Should this worry about quotes?? */
+char *
+camel_header_encode_string (const unsigned char *in)
+{
+ const unsigned char *inptr = in, *start, *word;
+ gboolean last_was_encoded = FALSE;
+ gboolean last_was_space = FALSE;
+ int encoding;
+ GString *out;
+ char *outstr;
+
+ g_return_val_if_fail (g_utf8_validate (in, -1, NULL), NULL);
+
+ if (in == NULL)
+ return NULL;
+
+ /* do a quick us-ascii check (the common case?) */
+ while (*inptr) {
+ if (*inptr > 127)
+ break;
+ inptr++;
+ }
+ if (*inptr == '\0')
+ return g_strdup (in);
+
+ /* This gets each word out of the input, and checks to see what charset
+ can be used to encode it. */
+ /* TODO: Work out when to merge subsequent words, or across word-parts */
+ out = g_string_new ("");
+ inptr = in;
+ encoding = 0;
+ word = NULL;
+ start = inptr;
+ while (inptr && *inptr) {
+ gunichar c;
+ const char *newinptr;
+
+ newinptr = g_utf8_next_char (inptr);
+ c = g_utf8_get_char (inptr);
+ if (newinptr == NULL || !g_unichar_validate (c)) {
+ w(g_warning ("Invalid UTF-8 sequence encountered (pos %d, char '%c'): %s",
+ (inptr-in), inptr[0], in));
+ inptr++;
+ continue;
+ }
+
+ if (c < 256 && camel_mime_is_lwsp (c) && !last_was_space) {
+ /* we've reached the end of a 'word' */
+ if (word && !(last_was_encoded && encoding)) {
+ /* output lwsp between non-encoded words */
+ g_string_append_len (out, start, word - start);
+ start = word;
+ }
+
+ switch (encoding) {
+ case 0:
+ g_string_append_len (out, start, inptr - start);
+ last_was_encoded = FALSE;
+ break;
+ case 1:
+ if (last_was_encoded)
+ g_string_append_c (out, ' ');
+
+ rfc2047_encode_word (out, start, inptr - start, "ISO-8859-1", CAMEL_MIME_IS_ESAFE);
+ last_was_encoded = TRUE;
+ break;
+ case 2:
+ if (last_was_encoded)
+ g_string_append_c (out, ' ');
+
+ rfc2047_encode_word (out, start, inptr - start,
+ camel_charset_best (start, inptr - start), CAMEL_MIME_IS_ESAFE);
+ last_was_encoded = TRUE;
+ break;
+ }
+
+ last_was_space = TRUE;
+ start = inptr;
+ word = NULL;
+ encoding = 0;
+ } else if (c > 127 && c < 256) {
+ encoding = MAX (encoding, 1);
+ last_was_space = FALSE;
+ } else if (c >= 256) {
+ encoding = MAX (encoding, 2);
+ last_was_space = FALSE;
+ } else if (!camel_mime_is_lwsp (c)) {
+ last_was_space = FALSE;
+ }
+
+ if (!(c < 256 && camel_mime_is_lwsp (c)) && !word)
+ word = inptr;
+
+ inptr = newinptr;
+ }
+
+ if (inptr - start) {
+ if (word && !(last_was_encoded && encoding)) {
+ g_string_append_len (out, start, word - start);
+ start = word;
+ }
+
+ switch (encoding) {
+ case 0:
+ g_string_append_len (out, start, inptr - start);
+ break;
+ case 1:
+ if (last_was_encoded)
+ g_string_append_c (out, ' ');
+
+ rfc2047_encode_word (out, start, inptr - start, "ISO-8859-1", CAMEL_MIME_IS_ESAFE);
+ break;
+ case 2:
+ if (last_was_encoded)
+ g_string_append_c (out, ' ');
+
+ rfc2047_encode_word (out, start, inptr - start,
+ camel_charset_best (start, inptr - start - 1), CAMEL_MIME_IS_ESAFE);
+ break;
+ }
+ }
+
+ outstr = out->str;
+ g_string_free (out, FALSE);
+
+ return outstr;
+}
+
+/* apply quoted-string rules to a string */
+static void
+quote_word(GString *out, gboolean do_quotes, const char *start, size_t len)
+{
+ int i, c;
+
+ /* TODO: What about folding on long lines? */
+ if (do_quotes)
+ g_string_append_c(out, '"');
+ for (i=0;i<len;i++) {
+ c = *start++;
+ if (c == '\"' || c=='\\' || c=='\r')
+ g_string_append_c(out, '\\');
+ g_string_append_c(out, c);
+ }
+ if (do_quotes)
+ g_string_append_c(out, '"');
+}
+
+/* incrementing possibility for the word type */
+enum _phrase_word_t {
+ WORD_ATOM,
+ WORD_QSTRING,
+ WORD_2047
+};
+
+struct _phrase_word {
+ const unsigned char *start, *end;
+ enum _phrase_word_t type;
+ int encoding;
+};
+
+static gboolean
+word_types_compatable (enum _phrase_word_t type1, enum _phrase_word_t type2)
+{
+ switch (type1) {
+ case WORD_ATOM:
+ return type2 == WORD_QSTRING;
+ case WORD_QSTRING:
+ return type2 != WORD_2047;
+ case WORD_2047:
+ return type2 == WORD_2047;
+ default:
+ return FALSE;
+ }
+}
+
+/* split the input into words with info about each word
+ * merge common word types clean up */
+static GList *
+header_encode_phrase_get_words (const unsigned char *in)
+{
+ const unsigned char *inptr = in, *start, *last;
+ struct _phrase_word *word;
+ enum _phrase_word_t type;
+ int encoding, count = 0;
+ GList *words = NULL;
+
+ /* break the input into words */
+ type = WORD_ATOM;
+ last = inptr;
+ start = inptr;
+ encoding = 0;
+ while (inptr && *inptr) {
+ gunichar c;
+ const char *newinptr;
+
+ newinptr = g_utf8_next_char (inptr);
+ c = g_utf8_get_char (inptr);
+
+ if (!g_unichar_validate (c)) {
+ w(g_warning ("Invalid UTF-8 sequence encountered (pos %d, char '%c'): %s",
+ (inptr - in), inptr[0], in));
+ inptr++;
+ continue;
+ }
+
+ inptr = newinptr;
+ if (g_unichar_isspace (c)) {
+ if (count > 0) {
+ word = g_new0 (struct _phrase_word, 1);
+ word->start = start;
+ word->end = last;
+ word->type = type;
+ word->encoding = encoding;
+ words = g_list_append (words, word);
+ count = 0;
+ }
+
+ start = inptr;
+ type = WORD_ATOM;
+ encoding = 0;
+ } else {
+ count++;
+ if (c < 128) {
+ if (!camel_mime_is_atom (c))
+ type = MAX (type, WORD_QSTRING);
+ } else if (c > 127 && c < 256) {
+ type = WORD_2047;
+ encoding = MAX (encoding, 1);
+ } else if (c >= 256) {
+ type = WORD_2047;
+ encoding = MAX (encoding, 2);
+ }
+ }
+
+ last = inptr;
+ }
+
+ if (count > 0) {
+ word = g_new0 (struct _phrase_word, 1);
+ word->start = start;
+ word->end = last;
+ word->type = type;
+ word->encoding = encoding;
+ words = g_list_append (words, word);
+ }
+
+ return words;
+}
+
+#define MERGED_WORD_LT_FOLDLEN(wordlen, type) ((type) == WORD_2047 ? (wordlen) < CAMEL_FOLD_PREENCODED : (wordlen) < (CAMEL_FOLD_SIZE - 8))
+
+static gboolean
+header_encode_phrase_merge_words (GList **wordsp)
+{
+ GList *wordl, *nextl, *words = *wordsp;
+ struct _phrase_word *word, *next;
+ gboolean merged = FALSE;
+
+ /* scan the list, checking for words of similar types that can be merged */
+ wordl = words;
+ while (wordl) {
+ word = wordl->data;
+ nextl = g_list_next (wordl);
+
+ while (nextl) {
+ next = nextl->data;
+ /* merge nodes of the same type AND we are not creating too long a string */
+ if (word_types_compatable (word->type, next->type)) {
+ if (MERGED_WORD_LT_FOLDLEN (next->end - word->start, MAX (word->type, next->type))) {
+ /* the resulting word type is the MAX of the 2 types */
+ word->type = MAX(word->type, next->type);
+
+ word->end = next->end;
+ words = g_list_remove_link (words, nextl);
+ g_list_free_1 (nextl);
+ g_free (next);
+
+ nextl = g_list_next (wordl);
+
+ merged = TRUE;
+ } else {
+ /* if it is going to be too long, make sure we include the
+ separating whitespace */
+ word->end = next->start;
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+
+ wordl = g_list_next (wordl);
+ }
+
+ *wordsp = words;
+
+ return merged;
+}
+
+/* encodes a phrase sequence (different quoting/encoding rules to strings) */
+char *
+camel_header_encode_phrase (const unsigned char *in)
+{
+ struct _phrase_word *word = NULL, *last_word = NULL;
+ GList *words, *wordl;
+ GString *out;
+ char *outstr;
+
+ if (in == NULL)
+ return NULL;
+
+ words = header_encode_phrase_get_words (in);
+ if (!words)
+ return NULL;
+
+ while (header_encode_phrase_merge_words (&words))
+ ;
+
+ out = g_string_new ("");
+
+ /* output words now with spaces between them */
+ wordl = words;
+ while (wordl) {
+ const char *start;
+ size_t len;
+
+ word = wordl->data;
+
+ /* append correct number of spaces between words */
+ if (last_word && !(last_word->type == WORD_2047 && word->type == WORD_2047)) {
+ /* one or both of the words are not encoded so we write the spaces out untouched */
+ len = word->start - last_word->end;
+ out = g_string_append_len (out, last_word->end, len);
+ }
+
+ switch (word->type) {
+ case WORD_ATOM:
+ out = g_string_append_len (out, word->start, word->end - word->start);
+ break;
+ case WORD_QSTRING:
+ quote_word (out, TRUE, word->start, word->end - word->start);
+ break;
+ case WORD_2047:
+ if (last_word && last_word->type == WORD_2047) {
+ /* include the whitespace chars between these 2 words in the
+ resulting rfc2047 encoded word. */
+ len = word->end - last_word->end;
+ start = last_word->end;
+
+ /* encoded words need to be separated by linear whitespace */
+ g_string_append_c (out, ' ');
+ } else {
+ len = word->end - word->start;
+ start = word->start;
+ }
+
+ if (word->encoding == 1)
+ rfc2047_encode_word (out, start, len, "ISO-8859-1", CAMEL_MIME_IS_PSAFE);
+ else
+ rfc2047_encode_word (out, start, len,
+ camel_charset_best (start, len), CAMEL_MIME_IS_PSAFE);
+ break;
+ }
+
+ g_free (last_word);
+ wordl = g_list_next (wordl);
+
+ last_word = word;
+ }
+
+ /* and we no longer need the list */
+ g_free (word);
+ g_list_free (words);
+
+ outstr = out->str;
+ g_string_free (out, FALSE);
+
+ return outstr;
+}
+
+
+/* these are all internal parser functions */
+
+static char *
+decode_token (const char **in)
+{
+ const char *inptr = *in;
+ const char *start;
+
+ header_decode_lwsp (&inptr);
+ start = inptr;
+ while (camel_mime_is_ttoken (*inptr))
+ inptr++;
+ if (inptr > start) {
+ *in = inptr;
+ return g_strndup (start, inptr - start);
+ } else {
+ return NULL;
+ }
+}
+
+char *
+camel_header_token_decode(const char *in)
+{
+ if (in == NULL)
+ return NULL;
+
+ return decode_token(&in);
+}
+
+/*
+ <"> * ( <any char except <"> \, cr / \ <any char> ) <">
+*/
+static char *
+header_decode_quoted_string(const char **in)
+{
+ const char *inptr = *in;
+ char *out = NULL, *outptr;
+ size_t outlen;
+ int c;
+
+ header_decode_lwsp(&inptr);
+ if (*inptr == '"') {
+ const char *intmp;
+ int skip = 0;
+
+ /* first, calc length */
+ inptr++;
+ intmp = inptr;
+ while ( (c = *intmp++) && c!= '"') {
+ if (c=='\\' && *intmp) {
+ intmp++;
+ skip++;
+ }
+ }
+ outlen = intmp-inptr-skip;
+ out = outptr = g_malloc(outlen+1);
+ while ( (c = *inptr++) && c!= '"') {
+ if (c=='\\' && *inptr) {
+ c = *inptr++;
+ }
+ *outptr++ = c;
+ }
+ *outptr = '\0';
+ }
+ *in = inptr;
+ return out;
+}
+
+static char *
+header_decode_atom(const char **in)
+{
+ const char *inptr = *in, *start;
+
+ header_decode_lwsp(&inptr);
+ start = inptr;
+ while (camel_mime_is_atom(*inptr))
+ inptr++;
+ *in = inptr;
+ if (inptr > start)
+ return g_strndup(start, inptr-start);
+ else
+ return NULL;
+}
+
+static char *
+header_decode_word (const char **in)
+{
+ const char *inptr = *in;
+
+ header_decode_lwsp (&inptr);
+ if (*inptr == '"') {
+ *in = inptr;
+ return header_decode_quoted_string (in);
+ } else {
+ *in = inptr;
+ return header_decode_atom (in);
+ }
+}
+
+static char *
+header_decode_value(const char **in)
+{
+ const char *inptr = *in;
+
+ header_decode_lwsp(&inptr);
+ if (*inptr == '"') {
+ d(printf("decoding quoted string\n"));
+ return header_decode_quoted_string(in);
+ } else if (camel_mime_is_ttoken(*inptr)) {
+ d(printf("decoding token\n"));
+ /* this may not have the right specials for all params? */
+ return decode_token(in);
+ }
+ return NULL;
+}
+
+/* should this return -1 for no int? */
+int
+camel_header_decode_int(const char **in)
+{
+ const char *inptr = *in;
+ int c, v=0;
+
+ header_decode_lwsp(&inptr);
+ while ( (c=*inptr++ & 0xff)
+ && isdigit(c) ) {
+ v = v*10+(c-'0');
+ }
+ *in = inptr-1;
+ return v;
+}
+
+#define HEXVAL(c) (isdigit (c) ? (c) - '0' : tolower (c) - 'a' + 10)
+
+static char *
+hex_decode (const char *in, size_t len)
+{
+ const unsigned char *inend = in + len;
+ unsigned char *inptr, *outptr;
+ char *outbuf;
+
+ outptr = outbuf = g_malloc (len + 1);
+
+ inptr = (unsigned char *) in;
+ while (inptr < inend) {
+ if (*inptr == '%') {
+ if (isxdigit (inptr[1]) && isxdigit (inptr[2])) {
+ *outptr++ = HEXVAL (inptr[1]) * 16 + HEXVAL (inptr[2]);
+ inptr += 3;
+ } else
+ *outptr++ = *inptr++;
+ } else
+ *outptr++ = *inptr++;
+ }
+
+ *outptr = '\0';
+
+ return outbuf;
+}
+
+/* Tries to convert @in @from charset @to charset. Any failure, we get no data out rather than partial conversion */
+static char *
+header_convert(const char *to, const char *from, const char *in, size_t inlen)
+{
+ iconv_t ic;
+ size_t outlen, ret;
+ char *outbuf, *outbase, *result = NULL;
+
+ ic = e_iconv_open(to, from);
+ if (ic == (iconv_t) -1)
+ return NULL;
+
+ outlen = inlen * 6 + 16;
+ outbuf = outbase = g_malloc(outlen);
+
+ ret = e_iconv(ic, &in, &inlen, &outbuf, &outlen);
+ if (ret != (size_t) -1) {
+ e_iconv(ic, NULL, 0, &outbuf, &outlen);
+ *outbuf = '\0';
+ result = g_strdup(outbase);
+ }
+ e_iconv_close(ic);
+ g_free(outbase);
+
+ return result;
+}
+
+/* an rfc2184 encoded string looks something like:
+ * us-ascii'en'This%20is%20even%20more%20
+ */
+
+static char *
+rfc2184_decode (const char *in, size_t len)
+{
+ const char *inptr = in;
+ const char *inend = in + len;
+ const char *charset;
+ char *decoded, *decword, *encoding;
+
+ inptr = memchr (inptr, '\'', len);
+ if (!inptr)
+ return NULL;
+
+ encoding = g_alloca(inptr-in+1);
+ memcpy(encoding, in, inptr-in);
+ encoding[inptr-in] = 0;
+ charset = e_iconv_charset_name (encoding);
+
+ inptr = memchr (inptr + 1, '\'', inend - inptr - 1);
+ if (!inptr)
+ return NULL;
+ inptr++;
+ if (inptr >= inend)
+ return NULL;
+
+ decword = hex_decode (inptr, inend - inptr);
+ decoded = header_convert("UTF-8", charset, decword, strlen(decword));
+ g_free(decword);
+
+ return decoded;
+}
+
+char *
+camel_header_param (struct _camel_header_param *p, const char *name)
+{
+ while (p && g_ascii_strcasecmp (p->name, name) != 0)
+ p = p->next;
+ if (p)
+ return p->value;
+ return NULL;
+}
+
+struct _camel_header_param *
+camel_header_set_param (struct _camel_header_param **l, const char *name, const char *value)
+{
+ struct _camel_header_param *p = (struct _camel_header_param *)l, *pn;
+
+ if (name == NULL)
+ return NULL;
+
+ while (p->next) {
+ pn = p->next;
+ if (!g_ascii_strcasecmp (pn->name, name)) {
+ g_free (pn->value);
+ if (value) {
+ pn->value = g_strdup (value);
+ return pn;
+ } else {
+ p->next = pn->next;
+ g_free (pn->name);
+ g_free (pn);
+ return NULL;
+ }
+ }
+ p = pn;
+ }
+
+ if (value == NULL)
+ return NULL;
+
+ pn = g_malloc (sizeof (*pn));
+ pn->next = 0;
+ pn->name = g_strdup (name);
+ pn->value = g_strdup (value);
+ p->next = pn;
+
+ return pn;
+}
+
+const char *
+camel_content_type_param (CamelContentType *t, const char *name)
+{
+ if (t==NULL)
+ return NULL;
+ return camel_header_param (t->params, name);
+}
+
+void
+camel_content_type_set_param (CamelContentType *t, const char *name, const char *value)
+{
+ camel_header_set_param (&t->params, name, value);
+}
+
+/**
+ * camel_content_type_is:
+ * @ct: A content type specifier, or #NULL.
+ * @type: A type to check against.
+ * @subtype: A subtype to check against, or "*" to match any subtype.
+ *
+ * Returns #TRUE if the content type @ct is of type @type/@subtype.
+ * The subtype of "*" will match any subtype. If @ct is #NULL, then
+ * it will match the type "text/plain".
+ *
+ * Return value: #TRUE or #FALSE depending on the matching of the type.
+ **/
+int
+camel_content_type_is(CamelContentType *ct, const char *type, const char *subtype)
+{
+ /* no type == text/plain or text/"*" */
+ if (ct==NULL || (ct->type == NULL && ct->subtype == NULL)) {
+ return (!strcasecmp(type, "text")
+ && (!g_ascii_strcasecmp(subtype, "plain")
+ || !strcasecmp(subtype, "*")));
+ }
+
+ return (ct->type != NULL
+ && (!g_ascii_strcasecmp(ct->type, type)
+ && ((ct->subtype != NULL
+ && !g_ascii_strcasecmp(ct->subtype, subtype))
+ || !strcasecmp("*", subtype))));
+}
+
+void
+camel_header_param_list_free(struct _camel_header_param *p)
+{
+ struct _camel_header_param *n;
+
+ while (p) {
+ n = p->next;
+ g_free(p->name);
+ g_free(p->value);
+ g_free(p);
+ p = n;
+ }
+}
+
+CamelContentType *
+camel_content_type_new(const char *type, const char *subtype)
+{
+ CamelContentType *t = g_malloc(sizeof(*t));
+
+ t->type = g_strdup(type);
+ t->subtype = g_strdup(subtype);
+ t->params = NULL;
+ t->refcount = 1;
+ return t;
+}
+
+void
+camel_content_type_ref(CamelContentType *ct)
+{
+ if (ct)
+ ct->refcount++;
+}
+
+
+void
+camel_content_type_unref(CamelContentType *ct)
+{
+ if (ct) {
+ if (ct->refcount <= 1) {
+ camel_header_param_list_free(ct->params);
+ g_free(ct->type);
+ g_free(ct->subtype);
+ g_free(ct);
+ } else {
+ ct->refcount--;
+ }
+ }
+}
+
+/* for decoding email addresses, canonically */
+static char *
+header_decode_domain(const char **in)
+{
+ const char *inptr = *in, *start;
+ int go = TRUE;
+ char *ret;
+ GString *domain = g_string_new("");
+
+ /* domain ref | domain literal */
+ header_decode_lwsp(&inptr);
+ while (go) {
+ if (*inptr == '[') { /* domain literal */
+ domain = g_string_append_c(domain, '[');
+ inptr++;
+ header_decode_lwsp(&inptr);
+ start = inptr;
+ while (camel_mime_is_dtext(*inptr)) {
+ domain = g_string_append_c(domain, *inptr);
+ inptr++;
+ }
+ if (*inptr == ']') {
+ domain = g_string_append_c(domain, ']');
+ inptr++;
+ } else {
+ w(g_warning("closing ']' not found in domain: %s", *in));
+ }
+ } else {
+ char *a = header_decode_atom(&inptr);
+ if (a) {
+ domain = g_string_append(domain, a);
+ g_free(a);
+ } else {
+ w(g_warning("missing atom from domain-ref"));
+ break;
+ }
+ }
+ header_decode_lwsp(&inptr);
+ if (*inptr == '.') { /* next sub-domain? */
+ domain = g_string_append_c(domain, '.');
+ inptr++;
+ header_decode_lwsp(&inptr);
+ } else
+ go = FALSE;
+ }
+
+ *in = inptr;
+
+ ret = domain->str;
+ g_string_free(domain, FALSE);
+ return ret;
+}
+
+static char *
+header_decode_addrspec(const char **in)
+{
+ const char *inptr = *in;
+ char *word;
+ GString *addr = g_string_new("");
+
+ header_decode_lwsp(&inptr);
+
+ /* addr-spec */
+ word = header_decode_word (&inptr);
+ if (word) {
+ addr = g_string_append(addr, word);
+ header_decode_lwsp(&inptr);
+ g_free(word);
+ while (*inptr == '.' && word) {
+ inptr++;
+ addr = g_string_append_c(addr, '.');
+ word = header_decode_word (&inptr);
+ if (word) {
+ addr = g_string_append(addr, word);
+ header_decode_lwsp(&inptr);
+ g_free(word);
+ } else {
+ w(g_warning("Invalid address spec: %s", *in));
+ }
+ }
+ if (*inptr == '@') {
+ inptr++;
+ addr = g_string_append_c(addr, '@');
+ word = header_decode_domain(&inptr);
+ if (word) {
+ addr = g_string_append(addr, word);
+ g_free(word);
+ } else {
+ w(g_warning("Invalid address, missing domain: %s", *in));
+ }
+ } else {
+ w(g_warning("Invalid addr-spec, missing @: %s", *in));
+ }
+ } else {
+ w(g_warning("invalid addr-spec, no local part"));
+ }
+
+ /* FIXME: return null on error? */
+
+ *in = inptr;
+ word = addr->str;
+ g_string_free(addr, FALSE);
+ return word;
+}
+
+/*
+ address:
+ word *('.' word) @ domain |
+ *(word) '<' [ *('@' domain ) ':' ] word *( '.' word) @ domain |
+
+ 1*word ':' [ word ... etc (mailbox, as above) ] ';'
+ */
+
+/* mailbox:
+ word *( '.' word ) '@' domain
+ *(word) '<' [ *('@' domain ) ':' ] word *( '.' word) @ domain
+ */
+
+static struct _camel_header_address *
+header_decode_mailbox(const char **in, const char *charset)
+{
+ const char *inptr = *in;
+ char *pre;
+ int closeme = FALSE;
+ GString *addr;
+ GString *name = NULL;
+ struct _camel_header_address *address = NULL;
+ const char *comment = NULL;
+
+ addr = g_string_new("");
+
+ /* for each address */
+ pre = header_decode_word (&inptr);
+ header_decode_lwsp(&inptr);
+ if (!(*inptr == '.' || *inptr == '@' || *inptr==',' || *inptr=='\0')) {
+ /* ',' and '\0' required incase it is a simple address, no @ domain part (buggy writer) */
+ name = g_string_new ("");
+ while (pre) {
+ char *text, *last;
+
+ /* perform internationalised decoding, and append */
+ text = camel_header_decode_string (pre, charset);
+ g_string_append (name, text);
+ last = pre;
+ g_free(text);
+
+ pre = header_decode_word (&inptr);
+ if (pre) {
+ size_t l = strlen (last);
+ size_t p = strlen (pre);
+
+ /* dont append ' ' between sucsessive encoded words */
+ if ((l>6 && last[l-2] == '?' && last[l-1] == '=')
+ && (p>6 && pre[0] == '=' && pre[1] == '?')) {
+ /* dont append ' ' */
+ } else {
+ name = g_string_append_c(name, ' ');
+ }
+ } else {
+ /* Fix for stupidly-broken-mailers that like to put '.''s in names unquoted */
+ /* see bug #8147 */
+ while (!pre && *inptr && *inptr != '<') {
+ w(g_warning("Working around stupid mailer bug #5: unescaped characters in names"));
+ name = g_string_append_c(name, *inptr++);
+ pre = header_decode_word (&inptr);
+ }
+ }
+ g_free(last);
+ }
+ header_decode_lwsp(&inptr);
+ if (*inptr == '<') {
+ closeme = TRUE;
+ try_address_again:
+ inptr++;
+ header_decode_lwsp(&inptr);
+ if (*inptr == '@') {
+ while (*inptr == '@') {
+ inptr++;
+ header_decode_domain(&inptr);
+ header_decode_lwsp(&inptr);
+ if (*inptr == ',') {
+ inptr++;
+ header_decode_lwsp(&inptr);
+ }
+ }
+ if (*inptr == ':') {
+ inptr++;
+ } else {
+ w(g_warning("broken route-address, missing ':': %s", *in));
+ }
+ }
+ pre = header_decode_word (&inptr);
+ header_decode_lwsp(&inptr);
+ } else {
+ w(g_warning("broken address? %s", *in));
+ }
+ }
+
+ if (pre) {
+ addr = g_string_append(addr, pre);
+ } else {
+ w(g_warning("No local-part for email address: %s", *in));
+ }
+
+ /* should be at word '.' localpart */
+ while (*inptr == '.' && pre) {
+ inptr++;
+ g_free(pre);
+ pre = header_decode_word (&inptr);
+ addr = g_string_append_c(addr, '.');
+ if (pre)
+ addr = g_string_append(addr, pre);
+ comment = inptr;
+ header_decode_lwsp(&inptr);
+ }
+ g_free(pre);
+
+ /* now at '@' domain part */
+ if (*inptr == '@') {
+ char *dom;
+
+ inptr++;
+ addr = g_string_append_c(addr, '@');
+ comment = inptr;
+ dom = header_decode_domain(&inptr);
+ addr = g_string_append(addr, dom);
+ g_free(dom);
+ } else if (*inptr != '>' || !closeme) {
+ /* If we get a <, the address was probably a name part, lets try again shall we? */
+ /* Another fix for seriously-broken-mailers */
+ if (*inptr && *inptr != ',') {
+ char *text;
+
+ w(g_warning("We didn't get an '@' where we expected in '%s', trying again", *in));
+ w(g_warning("Name is '%s', Addr is '%s' we're at '%s'\n", name?name->str:"<UNSET>", addr->str, inptr));
+
+ /* need to keep *inptr, as try_address_again will drop the current character */
+ if (*inptr == '<')
+ closeme = TRUE;
+ else
+ g_string_append_c(addr, *inptr);
+
+ /* check for address is encoded word ... */
+ text = camel_header_decode_string(addr->str, charset);
+ if (name == NULL) {
+ name = addr;
+ addr = g_string_new("");
+ if (text) {
+ g_string_truncate(name, 0);
+ g_string_append(name, text);
+ }
+ } else {
+ g_string_append(name, text?text:addr->str);
+ g_string_truncate(addr, 0);
+ }
+ g_free(text);
+
+ /* or maybe that we've added up a bunch of broken bits to make an encoded word */
+ text = rfc2047_decode_word(name->str, name->len);
+ if (text) {
+ g_string_truncate(name, 0);
+ g_string_append(name, text);
+ g_free(text);
+ }
+
+ goto try_address_again;
+ }
+ w(g_warning("invalid address, no '@' domain part at %c: %s", *inptr, *in));
+ }
+
+ if (closeme) {
+ header_decode_lwsp(&inptr);
+ if (*inptr == '>') {
+ inptr++;
+ } else {
+ w(g_warning("invalid route address, no closing '>': %s", *in));
+ }
+ } else if (name == NULL && comment != NULL && inptr>comment) { /* check for comment after address */
+ char *text, *tmp;
+ const char *comstart, *comend;
+
+ /* this is a bit messy, we go from the last known position, because
+ decode_domain/etc skip over any comments on the way */
+ /* FIXME: This wont detect comments inside the domain itself,
+ but nobody seems to use that feature anyway ... */
+
+ d(printf("checking for comment from '%s'\n", comment));
+
+ comstart = strchr(comment, '(');
+ if (comstart) {
+ comstart++;
+ header_decode_lwsp(&inptr);
+ comend = inptr-1;
+ while (comend > comstart && comend[0] != ')')
+ comend--;
+
+ if (comend > comstart) {
+ d(printf(" looking at subset '%.*s'\n", comend-comstart, comstart));
+ tmp = g_strndup (comstart, comend-comstart);
+ text = camel_header_decode_string (tmp, charset);
+ name = g_string_new (text);
+ g_free (tmp);
+ g_free (text);
+ }
+ }
+ }
+
+ *in = inptr;
+
+ if (addr->len > 0) {
+ if (!g_utf8_validate (addr->str, addr->len, NULL)) {
+ /* workaround for invalid addr-specs containing 8bit chars (see bug #42170 for details) */
+ const char *locale_charset;
+ GString *out;
+
+ locale_charset = e_iconv_locale_charset ();
+
+ out = g_string_new ("");
+
+ if ((charset == NULL || !append_8bit (out, addr->str, addr->len, charset))
+ && (locale_charset == NULL || !append_8bit (out, addr->str, addr->len, locale_charset)))
+ append_latin1 (out, addr->str, addr->len);
+
+ g_string_free (addr, TRUE);
+ addr = out;
+ }
+
+ address = camel_header_address_new_name(name ? name->str : "", addr->str);
+ }
+
+ d(printf("got mailbox: %s\n", addr->str));
+
+ g_string_free(addr, TRUE);
+ if (name)
+ g_string_free(name, TRUE);
+
+ return address;
+}
+
+static struct _camel_header_address *
+header_decode_address(const char **in, const char *charset)
+{
+ const char *inptr = *in;
+ char *pre;
+ GString *group = g_string_new("");
+ struct _camel_header_address *addr = NULL, *member;
+
+ /* pre-scan, trying to work out format, discard results */
+ header_decode_lwsp(&inptr);
+ while ((pre = header_decode_word (&inptr))) {
+ group = g_string_append(group, pre);
+ group = g_string_append(group, " ");
+ g_free(pre);
+ }
+ header_decode_lwsp(&inptr);
+ if (*inptr == ':') {
+ d(printf("group detected: %s\n", group->str));
+ addr = camel_header_address_new_group(group->str);
+ /* that was a group spec, scan mailbox's */
+ inptr++;
+ /* FIXME: check rfc 2047 encodings of words, here or above in the loop */
+ header_decode_lwsp(&inptr);
+ if (*inptr != ';') {
+ int go = TRUE;
+ do {
+ member = header_decode_mailbox(&inptr, charset);
+ if (member)
+ camel_header_address_add_member(addr, member);
+ header_decode_lwsp(&inptr);
+ if (*inptr == ',')
+ inptr++;
+ else
+ go = FALSE;
+ } while (go);
+ if (*inptr == ';') {
+ inptr++;
+ } else {
+ w(g_warning("Invalid group spec, missing closing ';': %s", *in));
+ }
+ } else {
+ inptr++;
+ }
+ *in = inptr;
+ } else {
+ addr = header_decode_mailbox(in, charset);
+ }
+
+ g_string_free(group, TRUE);
+
+ return addr;
+}
+
+static char *
+header_msgid_decode_internal(const char **in)
+{
+ const char *inptr = *in;
+ char *msgid = NULL;
+
+ d(printf("decoding Message-ID: '%s'\n", *in));
+
+ header_decode_lwsp(&inptr);
+ if (*inptr == '<') {
+ inptr++;
+ header_decode_lwsp(&inptr);
+ msgid = header_decode_addrspec(&inptr);
+ if (msgid) {
+ header_decode_lwsp(&inptr);
+ if (*inptr == '>') {
+ inptr++;
+ } else {
+ w(g_warning("Missing closing '>' on message id: %s", *in));
+ }
+ } else {
+ w(g_warning("Cannot find message id in: %s", *in));
+ }
+ } else {
+ w(g_warning("missing opening '<' on message id: %s", *in));
+ }
+ *in = inptr;
+
+ return msgid;
+}
+
+char *
+camel_header_msgid_decode(const char *in)
+{
+ if (in == NULL)
+ return NULL;
+
+ return header_msgid_decode_internal(&in);
+}
+
+char *
+camel_header_contentid_decode (const char *in)
+{
+ const char *inptr = in;
+ gboolean at = FALSE;
+ GString *addr;
+ char *buf;
+
+ d(printf("decoding Content-ID: '%s'\n", in));
+
+ header_decode_lwsp (&inptr);
+
+ /* some lame mailers quote the Content-Id */
+ if (*inptr == '"')
+ inptr++;
+
+ /* make sure the content-id is not "" which can happen if we get a
+ * content-id such as <.@> (which Eudora likes to use...) */
+ if ((buf = camel_header_msgid_decode (inptr)) != NULL && *buf)
+ return buf;
+
+ g_free (buf);
+
+ /* ugh, not a valid msg-id - try to get something useful out of it then? */
+ inptr = in;
+ header_decode_lwsp (&inptr);
+ if (*inptr == '<') {
+ inptr++;
+ header_decode_lwsp (&inptr);
+ }
+
+ /* Eudora has been known to use <.@> as a content-id */
+ if (!(buf = header_decode_word (&inptr)) && !strchr (".@", *inptr))
+ return NULL;
+
+ addr = g_string_new ("");
+ header_decode_lwsp (&inptr);
+ while (buf != NULL || *inptr == '.' || (*inptr == '@' && !at)) {
+ if (buf != NULL) {
+ g_string_append (addr, buf);
+ g_free (buf);
+ buf = NULL;
+ }
+
+ if (!at) {
+ if (*inptr == '.') {
+ g_string_append_c (addr, *inptr++);
+ buf = header_decode_word (&inptr);
+ } else if (*inptr == '@') {
+ g_string_append_c (addr, *inptr++);
+ buf = header_decode_word (&inptr);
+ at = TRUE;
+ }
+ } else if (strchr (".[]", *inptr)) {
+ g_string_append_c (addr, *inptr++);
+ buf = header_decode_atom (&inptr);
+ }
+
+ header_decode_lwsp (&inptr);
+ }
+
+ buf = addr->str;
+ g_string_free (addr, FALSE);
+
+ return buf;
+}
+
+void
+camel_header_references_list_append_asis(struct _camel_header_references **list, char *ref)
+{
+ struct _camel_header_references *w = (struct _camel_header_references *)list, *n;
+ while (w->next)
+ w = w->next;
+ n = g_malloc(sizeof(*n));
+ n->id = ref;
+ n->next = 0;
+ w->next = n;
+}
+
+int
+camel_header_references_list_size(struct _camel_header_references **list)
+{
+ int count = 0;
+ struct _camel_header_references *w = *list;
+ while (w) {
+ count++;
+ w = w->next;
+ }
+ return count;
+}
+
+void
+camel_header_references_list_clear(struct _camel_header_references **list)
+{
+ struct _camel_header_references *w = *list, *n;
+ while (w) {
+ n = w->next;
+ g_free(w->id);
+ g_free(w);
+ w = n;
+ }
+ *list = NULL;
+}
+
+static void
+header_references_decode_single (const char **in, struct _camel_header_references **head)
+{
+ struct _camel_header_references *ref;
+ const char *inptr = *in;
+ char *id, *word;
+
+ while (*inptr) {
+ header_decode_lwsp (&inptr);
+ if (*inptr == '<') {
+ id = header_msgid_decode_internal (&inptr);
+ if (id) {
+ ref = g_malloc (sizeof (struct _camel_header_references));
+ ref->next = *head;
+ ref->id = id;
+ *head = ref;
+ break;
+ }
+ } else {
+ word = header_decode_word (&inptr);
+ if (word)
+ g_free (word);
+ else if (*inptr != '\0')
+ inptr++; /* Stupid mailer tricks */
+ }
+ }
+
+ *in = inptr;
+}
+
+/* TODO: why is this needed? Can't the other interface also work? */
+struct _camel_header_references *
+camel_header_references_inreplyto_decode (const char *in)
+{
+ struct _camel_header_references *ref = NULL;
+
+ if (in == NULL || in[0] == '\0')
+ return NULL;
+
+ header_references_decode_single (&in, &ref);
+
+ return ref;
+}
+
+/* generate a list of references, from most recent up */
+struct _camel_header_references *
+camel_header_references_decode (const char *in)
+{
+ struct _camel_header_references *refs = NULL;
+
+ if (in == NULL || in[0] == '\0')
+ return NULL;
+
+ while (*in)
+ header_references_decode_single (&in, &refs);
+
+ return refs;
+}
+
+struct _camel_header_references *
+camel_header_references_dup(const struct _camel_header_references *list)
+{
+ struct _camel_header_references *new = NULL, *tmp;
+
+ while (list) {
+ tmp = g_new(struct _camel_header_references, 1);
+ tmp->next = new;
+ tmp->id = g_strdup(list->id);
+ new = tmp;
+ list = list->next;
+ }
+ return new;
+}
+
+struct _camel_header_address *
+camel_header_mailbox_decode(const char *in, const char *charset)
+{
+ if (in == NULL)
+ return NULL;
+
+ return header_decode_mailbox(&in, charset);
+}
+
+struct _camel_header_address *
+camel_header_address_decode(const char *in, const char *charset)
+{
+ const char *inptr = in, *last;
+ struct _camel_header_address *list = NULL, *addr;
+
+ d(printf("decoding To: '%s'\n", in));
+
+ if (in == NULL)
+ return NULL;
+
+ header_decode_lwsp(&inptr);
+ if (*inptr == 0)
+ return NULL;
+
+ do {
+ last = inptr;
+ addr = header_decode_address(&inptr, charset);
+ if (addr)
+ camel_header_address_list_append(&list, addr);
+ header_decode_lwsp(&inptr);
+ if (*inptr == ',')
+ inptr++;
+ else
+ break;
+ } while (inptr != last);
+
+ if (*inptr) {
+ w(g_warning("Invalid input detected at %c (%d): %s\n or at: %s", *inptr, inptr-in, in, inptr));
+ }
+
+ if (inptr == last) {
+ w(g_warning("detected invalid input loop at : %s", last));
+ }
+
+ return list;
+}
+
+struct _camel_header_newsgroup *
+camel_header_newsgroups_decode(const char *in)
+{
+ const char *inptr = in;
+ register char c;
+ struct _camel_header_newsgroup *head, *last, *ng;
+ const char *start;
+
+ head = NULL;
+ last = (struct _camel_header_newsgroup *)&head;
+
+ do {
+ header_decode_lwsp(&inptr);
+ start = inptr;
+ while ((c = *inptr++) && !camel_mime_is_lwsp(c) && c != ',')
+ ;
+ if (start != inptr-1) {
+ ng = g_malloc(sizeof(*ng));
+ ng->newsgroup = g_strndup(start, inptr-start-1);
+ ng->next = NULL;
+ last->next = ng;
+ last = ng;
+ }
+ } while (c);
+
+ return head;
+}
+
+void
+camel_header_newsgroups_free(struct _camel_header_newsgroup *ng)
+{
+ while (ng) {
+ struct _camel_header_newsgroup *nng = ng->next;
+
+ g_free(ng->newsgroup);
+ g_free(ng);
+ ng = nng;
+ }
+}
+
+/* this must be kept in sync with the header */
+static const char *encodings[] = {
+ "",
+ "7bit",
+ "8bit",
+ "base64",
+ "quoted-printable",
+ "binary",
+ "x-uuencode",
+};
+
+const char *
+camel_transfer_encoding_to_string (CamelTransferEncoding encoding)
+{
+ if (encoding >= sizeof (encodings) / sizeof (encodings[0]))
+ encoding = 0;
+
+ return encodings[encoding];
+}
+
+CamelTransferEncoding
+camel_transfer_encoding_from_string (const char *string)
+{
+ int i;
+
+ if (string != NULL) {
+ for (i = 0; i < sizeof (encodings) / sizeof (encodings[0]); i++)
+ if (!g_ascii_strcasecmp (string, encodings[i]))
+ return i;
+ }
+
+ return CAMEL_TRANSFER_ENCODING_DEFAULT;
+}
+
+void
+camel_header_mime_decode(const char *in, int *maj, int *min)
+{
+ const char *inptr = in;
+ int major=-1, minor=-1;
+
+ d(printf("decoding MIME-Version: '%s'\n", in));
+
+ if (in != NULL) {
+ header_decode_lwsp(&inptr);
+ if (isdigit(*inptr)) {
+ major = camel_header_decode_int(&inptr);
+ header_decode_lwsp(&inptr);
+ if (*inptr == '.') {
+ inptr++;
+ header_decode_lwsp(&inptr);
+ if (isdigit(*inptr))
+ minor = camel_header_decode_int(&inptr);
+ }
+ }
+ }
+
+ if (maj)
+ *maj = major;
+ if (min)
+ *min = minor;
+
+ d(printf("major = %d, minor = %d\n", major, minor));
+}
+
+struct _rfc2184_param {
+ struct _camel_header_param param;
+ int index;
+};
+
+static int
+rfc2184_param_cmp(const void *ap, const void *bp)
+{
+ const struct _rfc2184_param *a = *(void **)ap;
+ const struct _rfc2184_param *b = *(void **)bp;
+ int res;
+
+ res = strcmp(a->param.name, b->param.name);
+ if (res == 0) {
+ if (a->index > b->index)
+ res = 1;
+ else if (a->index < b->index)
+ res = -1;
+ }
+
+ return res;
+}
+
+/* NB: Steals name and value */
+static struct _camel_header_param *
+header_append_param(struct _camel_header_param *last, char *name, char *value)
+{
+ struct _camel_header_param *node;
+
+ /* This handles -
+ 8 bit data in parameters, illegal, tries to convert using locale, or just safens it up.
+ rfc2047 ecoded parameters, illegal, decodes them anyway. Some Outlook & Mozilla do this?
+ */
+ node = g_malloc(sizeof(*node));
+ last->next = node;
+ node->next = NULL;
+ node->name = name;
+ if (strncmp(value, "=?", 2) == 0
+ && (node->value = header_decode_text(value, strlen(value), FALSE, NULL))) {
+ g_free(value);
+ } else if (!g_utf8_validate(value, -1, NULL)) {
+ const char * charset = e_iconv_locale_charset();
+
+ if ((node->value = header_convert("UTF-8", charset?charset:"ISO-8859-1", value, strlen(value)))) {
+ g_free(value);
+ } else {
+ node->value = value;
+ for (;*value;value++)
+ if (!isascii((unsigned char)*value))
+ *value = '_';
+ }
+ } else
+ node->value = value;
+
+ return node;
+}
+
+static struct _camel_header_param *
+header_decode_param_list (const char **in)
+{
+ struct _camel_header_param *head = NULL, *last = (struct _camel_header_param *)&head;
+ GPtrArray *split = NULL;
+ const char *inptr = *in;
+ struct _rfc2184_param *work;
+ char *tmp;
+
+ /* Dump parameters into the output list, in the order found. RFC 2184 split parameters are kept in an array */
+ header_decode_lwsp(&inptr);
+ while (*inptr == ';') {
+ char *name;
+ char *value = NULL;
+
+ inptr++;
+ name = decode_token(&inptr);
+ header_decode_lwsp(&inptr);
+ if (*inptr == '=') {
+ inptr++;
+ value = header_decode_value(&inptr);
+ }
+
+ if (name && value) {
+ char *index = strchr(name, '*');
+
+ if (index) {
+ if (index[1] == 0) {
+ /* VAL*="foo", decode immediately and append */
+ *index = 0;
+ tmp = rfc2184_decode(value, strlen(value));
+ if (tmp) {
+ g_free(value);
+ value = tmp;
+ }
+ last = header_append_param(last, name, value);
+ } else {
+ /* VAL*1="foo", save for later */
+ *index++ = 0;
+ work = g_malloc(sizeof(*work));
+ work->param.name = name;
+ work->param.value = value;
+ work->index = atoi(index);
+ if (split == NULL)
+ split = g_ptr_array_new();
+ g_ptr_array_add(split, work);
+ }
+ } else {
+ last = header_append_param(last, name, value);
+ }
+ } else {
+ g_free(name);
+ g_free(value);
+ }
+
+ header_decode_lwsp(&inptr);
+ }
+
+ /* Rejoin any RFC 2184 split parameters in the proper order */
+ /* Parameters with the same index will be concatenated in undefined order */
+ if (split) {
+ GString *value = g_string_new("");
+ struct _rfc2184_param *first;
+ int i;
+
+ qsort(split->pdata, split->len, sizeof(split->pdata[0]), rfc2184_param_cmp);
+ first = split->pdata[0];
+ for (i=0;i<split->len;i++) {
+ work = split->pdata[i];
+ if (split->len-1 == i)
+ g_string_append(value, work->param.value);
+ if (split->len-1 == i || strcmp(work->param.name, first->param.name) != 0) {
+ tmp = rfc2184_decode(value->str, value->len);
+ if (tmp == NULL)
+ tmp = g_strdup(value->str);
+
+ last = header_append_param(last, g_strdup(first->param.name), tmp);
+ g_string_truncate(value, 0);
+ first = work;
+ }
+ if (split->len-1 != i)
+ g_string_append(value, work->param.value);
+ }
+ g_string_free(value, TRUE);
+ for (i=0;i<split->len;i++) {
+ work = split->pdata[i];
+ g_free(work->param.name);
+ g_free(work->param.value);
+ g_free(work);
+ }
+ g_ptr_array_free(split, TRUE);
+ }
+
+ *in = inptr;
+
+ return head;
+}
+
+struct _camel_header_param *
+camel_header_param_list_decode(const char *in)
+{
+ if (in == NULL)
+ return NULL;
+
+ return header_decode_param_list(&in);
+}
+
+static char *
+header_encode_param (const unsigned char *in, gboolean *encoded)
+{
+ const unsigned char *inptr = in;
+ unsigned char *outbuf = NULL;
+ const char *charset;
+ int encoding;
+ GString *out;
+ guint32 c;
+
+ *encoded = FALSE;
+
+ g_return_val_if_fail (in != NULL, NULL);
+
+ /* do a quick us-ascii check (the common case?) */
+ while (*inptr) {
+ if (*inptr > 127)
+ break;
+ inptr++;
+ }
+
+ if (*inptr == '\0')
+ return g_strdup (in);
+
+ inptr = in;
+ encoding = 0;
+ while ( encoding !=2 && (c = camel_utf8_getc(&inptr)) ) {
+ if (c > 127 && c < 256)
+ encoding = MAX (encoding, 1);
+ else if (c >= 256)
+ encoding = MAX (encoding, 2);
+ }
+
+ if (encoding == 2)
+ charset = camel_charset_best(in, strlen(in));
+ else
+ charset = "iso-8859-1";
+
+ if (strcasecmp(charset, "UTF-8") != 0
+ && (outbuf = header_convert(charset, "UTF-8", in, strlen(in)))) {
+ inptr = outbuf;
+ } else {
+ charset = "UTF-8";
+ inptr = in;
+ }
+
+ /* FIXME: set the 'language' as well, assuming we can get that info...? */
+ out = g_string_new (charset);
+ g_string_append(out, "''");
+
+ while ( (c = *inptr++) ) {
+ if (camel_mime_is_attrchar(c))
+ g_string_append_c (out, c);
+ else
+ g_string_append_printf (out, "%%%c%c", tohex[(c >> 4) & 0xf], tohex[c & 0xf]);
+ }
+ g_free (outbuf);
+
+ outbuf = out->str;
+ g_string_free (out, FALSE);
+ *encoded = TRUE;
+
+ return outbuf;
+}
+
+void
+camel_header_param_list_format_append (GString *out, struct _camel_header_param *p)
+{
+ int used = out->len;
+
+ while (p) {
+ gboolean encoded = FALSE;
+ gboolean quote = FALSE;
+ int here = out->len;
+ size_t nlen, vlen;
+ char *value;
+
+ if (!p->value) {
+ p = p->next;
+ continue;
+ }
+
+ value = header_encode_param (p->value, &encoded);
+ if (!value) {
+ w(g_warning ("appending parameter %s=%s violates rfc2184", p->name, p->value));
+ value = g_strdup (p->value);
+ }
+
+ if (!encoded) {
+ char *ch;
+
+ for (ch = value; *ch; ch++) {
+ if (camel_mime_is_tspecial (*ch) || camel_mime_is_lwsp (*ch))
+ break;
+ }
+
+ quote = ch && *ch;
+ }
+
+ nlen = strlen (p->name);
+ vlen = strlen (value);
+
+ if (used + nlen + vlen > CAMEL_FOLD_SIZE - 8) {
+ out = g_string_append (out, ";\n\t");
+ here = out->len;
+ used = 0;
+ } else
+ out = g_string_append (out, "; ");
+
+ if (nlen + vlen > CAMEL_FOLD_SIZE - 8) {
+ /* we need to do special rfc2184 parameter wrapping */
+ int maxlen = CAMEL_FOLD_SIZE - (nlen + 8);
+ char *inptr, *inend;
+ int i = 0;
+
+ inptr = value;
+ inend = value + vlen;
+
+ while (inptr < inend) {
+ char *ptr = inptr + MIN (inend - inptr, maxlen);
+
+ if (encoded && ptr < inend) {
+ /* be careful not to break an encoded char (ie %20) */
+ char *q = ptr;
+ int j = 2;
+
+ for ( ; j > 0 && q > inptr && *q != '%'; j--, q--);
+ if (*q == '%')
+ ptr = q;
+ }
+
+ if (i != 0) {
+ g_string_append (out, ";\n\t");
+ here = out->len;
+ used = 0;
+ }
+
+ g_string_append_printf (out, "%s*%d%s=", p->name, i++, encoded ? "*" : "");
+ if (encoded || !quote)
+ g_string_append_len (out, inptr, ptr - inptr);
+ else
+ quote_word (out, TRUE, inptr, ptr - inptr);
+
+ d(printf ("wrote: %s\n", out->str + here));
+
+ used += (out->len - here);
+
+ inptr = ptr;
+ }
+ } else {
+ g_string_append_printf (out, "%s%s=", p->name, encoded ? "*" : "");
+
+ if (encoded || !quote)
+ g_string_append (out, value);
+ else
+ quote_word (out, TRUE, value, vlen);
+
+ used += (out->len - here);
+ }
+
+ g_free (value);
+
+ p = p->next;
+ }
+}
+
+char *
+camel_header_param_list_format(struct _camel_header_param *p)
+{
+ GString *out = g_string_new("");
+ char *ret;
+
+ camel_header_param_list_format_append(out, p);
+ ret = out->str;
+ g_string_free(out, FALSE);
+ return ret;
+}
+
+CamelContentType *
+camel_content_type_decode(const char *in)
+{
+ const char *inptr = in;
+ char *type, *subtype = NULL;
+ CamelContentType *t = NULL;
+
+ if (in==NULL)
+ return NULL;
+
+ type = decode_token(&inptr);
+ header_decode_lwsp(&inptr);
+ if (type) {
+ if (*inptr == '/') {
+ inptr++;
+ subtype = decode_token(&inptr);
+ }
+ if (subtype == NULL && (!strcasecmp(type, "text"))) {
+ w(g_warning("text type with no subtype, resorting to text/plain: %s", in));
+ subtype = g_strdup("plain");
+ }
+ if (subtype == NULL) {
+ w(g_warning("MIME type with no subtype: %s", in));
+ }
+
+ t = camel_content_type_new(type, subtype);
+ t->params = header_decode_param_list(&inptr);
+ g_free(type);
+ g_free(subtype);
+ } else {
+ g_free(type);
+ d(printf("cannot find MIME type in header (2) '%s'", in));
+ }
+ return t;
+}
+
+void
+camel_content_type_dump(CamelContentType *ct)
+{
+ struct _camel_header_param *p;
+
+ printf("Content-Type: ");
+ if (ct==NULL) {
+ printf("<NULL>\n");
+ return;
+ }
+ printf("%s / %s", ct->type, ct->subtype);
+ p = ct->params;
+ if (p) {
+ while (p) {
+ printf(";\n\t%s=\"%s\"", p->name, p->value);
+ p = p->next;
+ }
+ }
+ printf("\n");
+}
+
+char *
+camel_content_type_format (CamelContentType *ct)
+{
+ GString *out;
+ char *ret;
+
+ if (ct == NULL)
+ return NULL;
+
+ out = g_string_new ("");
+ if (ct->type == NULL) {
+ g_string_append_printf (out, "text/plain");
+ w(g_warning ("Content-Type with no main type"));
+ } else if (ct->subtype == NULL) {
+ w(g_warning ("Content-Type with no sub type: %s", ct->type));
+ if (!g_ascii_strcasecmp (ct->type, "multipart"))
+ g_string_append_printf (out, "%s/mixed", ct->type);
+ else
+ g_string_append_printf (out, "%s", ct->type);
+ } else {
+ g_string_append_printf (out, "%s/%s", ct->type, ct->subtype);
+ }
+ camel_header_param_list_format_append (out, ct->params);
+
+ ret = out->str;
+ g_string_free (out, FALSE);
+
+ return ret;
+}
+
+char *
+camel_content_type_simple (CamelContentType *ct)
+{
+ if (ct->type == NULL) {
+ w(g_warning ("Content-Type with no main type"));
+ return g_strdup ("text/plain");
+ } else if (ct->subtype == NULL) {
+ w(g_warning ("Content-Type with no sub type: %s", ct->type));
+ if (!g_ascii_strcasecmp (ct->type, "multipart"))
+ return g_strdup_printf ("%s/mixed", ct->type);
+ else
+ return g_strdup (ct->type);
+ } else
+ return g_strdup_printf ("%s/%s", ct->type, ct->subtype);
+}
+
+char *
+camel_content_transfer_encoding_decode (const char *in)
+{
+ if (in)
+ return decode_token (&in);
+
+ return NULL;
+}
+
+CamelContentDisposition *
+camel_content_disposition_decode(const char *in)
+{
+ CamelContentDisposition *d = NULL;
+ const char *inptr = in;
+
+ if (in == NULL)
+ return NULL;
+
+ d = g_malloc(sizeof(*d));
+ d->refcount = 1;
+ d->disposition = decode_token(&inptr);
+ if (d->disposition == NULL)
+ w(g_warning("Empty disposition type"));
+ d->params = header_decode_param_list(&inptr);
+ return d;
+}
+
+void
+camel_content_disposition_ref(CamelContentDisposition *d)
+{
+ if (d)
+ d->refcount++;
+}
+
+void
+camel_content_disposition_unref(CamelContentDisposition *d)
+{
+ if (d) {
+ if (d->refcount<=1) {
+ camel_header_param_list_free(d->params);
+ g_free(d->disposition);
+ g_free(d);
+ } else {
+ d->refcount--;
+ }
+ }
+}
+
+char *
+camel_content_disposition_format(CamelContentDisposition *d)
+{
+ GString *out;
+ char *ret;
+
+ if (d==NULL)
+ return NULL;
+
+ out = g_string_new("");
+ if (d->disposition)
+ out = g_string_append(out, d->disposition);
+ else
+ out = g_string_append(out, "attachment");
+ camel_header_param_list_format_append(out, d->params);
+
+ ret = out->str;
+ g_string_free(out, FALSE);
+ return ret;
+}
+
+/* hrm, is there a library for this shit? */
+static struct {
+ char *name;
+ int offset;
+} tz_offsets [] = {
+ { "UT", 0 },
+ { "GMT", 0 },
+ { "EST", -500 }, /* these are all US timezones. bloody yanks */
+ { "EDT", -400 },
+ { "CST", -600 },
+ { "CDT", -500 },
+ { "MST", -700 },
+ { "MDT", -600 },
+ { "PST", -800 },
+ { "PDT", -700 },
+ { "Z", 0 },
+ { "A", -100 },
+ { "M", -1200 },
+ { "N", 100 },
+ { "Y", 1200 },
+};
+
+static char *tz_months [] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+};
+
+static char *tz_days [] = {
+ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+};
+
+char *
+camel_header_format_date(time_t time, int offset)
+{
+ struct tm tm;
+
+ d(printf("offset = %d\n", offset));
+
+ d(printf("converting date %s", ctime(&time)));
+
+ time += ((offset / 100) * (60*60)) + (offset % 100)*60;
+
+ d(printf("converting date %s", ctime(&time)));
+
+ gmtime_r (&time, &tm);
+
+ return g_strdup_printf("%s, %02d %s %04d %02d:%02d:%02d %+05d",
+ tz_days[tm.tm_wday],
+ tm.tm_mday, tz_months[tm.tm_mon],
+ tm.tm_year + 1900,
+ tm.tm_hour, tm.tm_min, tm.tm_sec,
+ offset);
+}
+
+/* convert a date to time_t representation */
+/* this is an awful mess oh well */
+time_t
+camel_header_decode_date(const char *in, int *saveoffset)
+{
+ const char *inptr = in;
+ char *monthname;
+ gboolean foundmonth;
+ int year, offset = 0;
+ struct tm tm;
+ int i;
+ time_t t;
+
+ if (in == NULL) {
+ if (saveoffset)
+ *saveoffset = 0;
+ return 0;
+ }
+
+ d(printf ("\ndecoding date '%s'\n", inptr));
+
+ memset (&tm, 0, sizeof(tm));
+
+ header_decode_lwsp (&inptr);
+ if (!isdigit (*inptr)) {
+ char *day = decode_token (&inptr);
+ /* we dont really care about the day, it's only for display */
+ if (day) {
+ d(printf ("got day: %s\n", day));
+ g_free (day);
+ header_decode_lwsp (&inptr);
+ if (*inptr == ',') {
+ inptr++;
+ } else {
+#ifndef CLEAN_DATE
+ return parse_broken_date (in, saveoffset);
+#else
+ if (saveoffset)
+ *saveoffset = 0;
+ return 0;
+#endif /* ! CLEAN_DATE */
+ }
+ }
+ }
+ tm.tm_mday = camel_header_decode_int(&inptr);
+#ifndef CLEAN_DATE
+ if (tm.tm_mday == 0) {
+ return parse_broken_date (in, saveoffset);
+ }
+#endif /* ! CLEAN_DATE */
+
+ monthname = decode_token(&inptr);
+ foundmonth = FALSE;
+ if (monthname) {
+ for (i=0;i<sizeof(tz_months)/sizeof(tz_months[0]);i++) {
+ if (!g_ascii_strcasecmp(tz_months[i], monthname)) {
+ tm.tm_mon = i;
+ foundmonth = TRUE;
+ break;
+ }
+ }
+ g_free(monthname);
+ }
+#ifndef CLEAN_DATE
+ if (!foundmonth) {
+ return parse_broken_date (in, saveoffset);
+ }
+#endif /* ! CLEAN_DATE */
+
+ year = camel_header_decode_int(&inptr);
+ if (year < 69) {
+ tm.tm_year = 100 + year;
+ } else if (year < 100) {
+ tm.tm_year = year;
+ } else if (year >= 100 && year < 1900) {
+ tm.tm_year = year;
+ } else {
+ tm.tm_year = year - 1900;
+ }
+ /* get the time ... yurck */
+ tm.tm_hour = camel_header_decode_int(&inptr);
+ header_decode_lwsp(&inptr);
+ if (*inptr == ':')
+ inptr++;
+ tm.tm_min = camel_header_decode_int(&inptr);
+ header_decode_lwsp(&inptr);
+ if (*inptr == ':')
+ inptr++;
+ tm.tm_sec = camel_header_decode_int(&inptr);
+ header_decode_lwsp(&inptr);
+ if (*inptr == '+'
+ || *inptr == '-') {
+ offset = (*inptr++)=='-'?-1:1;
+ offset = offset * camel_header_decode_int(&inptr);
+ d(printf("abs signed offset = %d\n", offset));
+ if (offset < -1200 || offset > 1400)
+ offset = 0;
+ } else if (isdigit(*inptr)) {
+ offset = camel_header_decode_int(&inptr);
+ d(printf("abs offset = %d\n", offset));
+ if (offset < -1200 || offset > 1400)
+ offset = 0;
+ } else {
+ char *tz = decode_token(&inptr);
+
+ if (tz) {
+ for (i=0;i<sizeof(tz_offsets)/sizeof(tz_offsets[0]);i++) {
+ if (!g_ascii_strcasecmp(tz_offsets[i].name, tz)) {
+ offset = tz_offsets[i].offset;
+ break;
+ }
+ }
+ g_free(tz);
+ }
+ /* some broken mailers seem to put in things like GMT+1030 instead of just +1030 */
+ header_decode_lwsp(&inptr);
+ if (*inptr == '+' || *inptr == '-') {
+ int sign = (*inptr++)=='-'?-1:1;
+ offset = offset + (camel_header_decode_int(&inptr)*sign);
+ }
+ d(printf("named offset = %d\n", offset));
+ }
+
+ t = e_mktime_utc(&tm);
+
+ /* t is now GMT of the time we want, but not offset by the timezone ... */
+
+ d(printf(" gmt normalized? = %s\n", ctime(&t)));
+
+ /* this should convert the time to the GMT equiv time */
+ t -= ( (offset/100) * 60*60) + (offset % 100)*60;
+
+ d(printf(" gmt normalized for timezone? = %s\n", ctime(&t)));
+
+ d({
+ char *tmp;
+ tmp = camel_header_format_date(t, offset);
+ printf(" encoded again: %s\n", tmp);
+ g_free(tmp);
+ });
+
+ if (saveoffset)
+ *saveoffset = offset;
+
+ return t;
+}
+
+char *
+camel_header_location_decode(const char *in)
+{
+ int quote = 0;
+ GString *out = g_string_new("");
+ char c, *res;
+
+ /* Sigh. RFC2557 says:
+ * content-location = "Content-Location:" [CFWS] URI [CFWS]
+ * where URI is restricted to the syntax for URLs as
+ * defined in Uniform Resource Locators [URL] until
+ * IETF specifies other kinds of URIs.
+ *
+ * But Netscape puts quotes around the URI when sending web
+ * pages.
+ *
+ * Which is required as defined in rfc2017 [3.1]. Although
+ * outlook doesn't do this.
+ *
+ * Since we get headers already unfolded, we need just drop
+ * all whitespace. URL's cannot contain whitespace or quoted
+ * characters, even when included in quotes.
+ */
+
+ header_decode_lwsp(&in);
+ if (*in == '"') {
+ in++;
+ quote = 1;
+ }
+
+ while ( (c = *in++) ) {
+ if (quote && c=='"')
+ break;
+ if (!camel_mime_is_lwsp(c))
+ g_string_append_c(out, c);
+ }
+
+ res = g_strdup(out->str);
+ g_string_free(out, TRUE);
+
+ return res;
+}
+
+/* extra rfc checks */
+#define CHECKS
+
+#ifdef CHECKS
+static void
+check_header(struct _camel_header_raw *h)
+{
+ unsigned char *p;
+
+ p = h->value;
+ while (p && *p) {
+ if (!isascii(*p)) {
+ w(g_warning("Appending header violates rfc: %s: %s", h->name, h->value));
+ return;
+ }
+ p++;
+ }
+}
+#endif
+
+void
+camel_header_raw_append_parse(struct _camel_header_raw **list, const char *header, int offset)
+{
+ register const char *in;
+ size_t fieldlen;
+ char *name;
+
+ in = header;
+ while (camel_mime_is_fieldname(*in) || *in==':')
+ in++;
+ fieldlen = in-header-1;
+ while (camel_mime_is_lwsp(*in))
+ in++;
+ if (fieldlen == 0 || header[fieldlen] != ':') {
+ printf("Invalid header line: '%s'\n", header);
+ return;
+ }
+ name = g_alloca (fieldlen + 1);
+ memcpy(name, header, fieldlen);
+ name[fieldlen] = 0;
+
+ camel_header_raw_append(list, name, in, offset);
+}
+
+void
+camel_header_raw_append(struct _camel_header_raw **list, const char *name, const char *value, int offset)
+{
+ struct _camel_header_raw *l, *n;
+
+ d(printf("Header: %s: %s\n", name, value));
+
+ n = g_malloc(sizeof(*n));
+ n->next = NULL;
+ n->name = g_strdup(name);
+ n->value = g_strdup(value);
+ n->offset = offset;
+#ifdef CHECKS
+ check_header(n);
+#endif
+ l = (struct _camel_header_raw *)list;
+ while (l->next) {
+ l = l->next;
+ }
+ l->next = n;
+
+ /* debug */
+#if 0
+ if (!strcasecmp(name, "To")) {
+ printf("- Decoding To\n");
+ camel_header_to_decode(value);
+ } else if (!strcasecmp(name, "Content-type")) {
+ printf("- Decoding content-type\n");
+ camel_content_type_dump(camel_content_type_decode(value));
+ } else if (!strcasecmp(name, "MIME-Version")) {
+ printf("- Decoding mime version\n");
+ camel_header_mime_decode(value);
+ }
+#endif
+}
+
+static struct _camel_header_raw *
+header_raw_find_node(struct _camel_header_raw **list, const char *name)
+{
+ struct _camel_header_raw *l;
+
+ l = *list;
+ while (l) {
+ if (!g_ascii_strcasecmp(l->name, name))
+ break;
+ l = l->next;
+ }
+ return l;
+}
+
+const char *
+camel_header_raw_find(struct _camel_header_raw **list, const char *name, int *offset)
+{
+ struct _camel_header_raw *l;
+
+ l = header_raw_find_node(list, name);
+ if (l) {
+ if (offset)
+ *offset = l->offset;
+ return l->value;
+ } else
+ return NULL;
+}
+
+const char *
+camel_header_raw_find_next(struct _camel_header_raw **list, const char *name, int *offset, const char *last)
+{
+ struct _camel_header_raw *l;
+
+ if (last == NULL || name == NULL)
+ return NULL;
+
+ l = *list;
+ while (l && l->value != last)
+ l = l->next;
+ return camel_header_raw_find(&l, name, offset);
+}
+
+static void
+header_raw_free(struct _camel_header_raw *l)
+{
+ g_free(l->name);
+ g_free(l->value);
+ g_free(l);
+}
+
+void
+camel_header_raw_remove(struct _camel_header_raw **list, const char *name)
+{
+ struct _camel_header_raw *l, *p;
+
+ /* the next pointer is at the head of the structure, so this is safe */
+ p = (struct _camel_header_raw *)list;
+ l = *list;
+ while (l) {
+ if (!g_ascii_strcasecmp(l->name, name)) {
+ p->next = l->next;
+ header_raw_free(l);
+ l = p->next;
+ } else {
+ p = l;
+ l = l->next;
+ }
+ }
+}
+
+void
+camel_header_raw_replace(struct _camel_header_raw **list, const char *name, const char *value, int offset)
+{
+ camel_header_raw_remove(list, name);
+ camel_header_raw_append(list, name, value, offset);
+}
+
+void
+camel_header_raw_clear(struct _camel_header_raw **list)
+{
+ struct _camel_header_raw *l, *n;
+ l = *list;
+ while (l) {
+ n = l->next;
+ header_raw_free(l);
+ l = n;
+ }
+ *list = NULL;
+}
+
+char *
+camel_header_msgid_generate (void)
+{
+ static pthread_mutex_t count_lock = PTHREAD_MUTEX_INITIALIZER;
+#define COUNT_LOCK() pthread_mutex_lock (&count_lock)
+#define COUNT_UNLOCK() pthread_mutex_unlock (&count_lock)
+ char host[MAXHOSTNAMELEN];
+ char *name;
+ static int count = 0;
+ char *msgid;
+ int retval;
+ struct addrinfo *ai = NULL, hints = { 0 };
+
+ retval = gethostname (host, sizeof (host));
+ if (retval == 0 && *host) {
+ hints.ai_flags = AI_CANONNAME;
+ ai = camel_getaddrinfo(host, NULL, &hints, NULL);
+ if (ai && ai->ai_canonname)
+ name = ai->ai_canonname;
+ else
+ name = host;
+ } else
+ name = "localhost.localdomain";
+
+ COUNT_LOCK ();
+ msgid = g_strdup_printf ("%d.%d.%d.camel@%s", (int) time (NULL), getpid (), count++, name);
+ COUNT_UNLOCK ();
+
+ if (ai)
+ camel_freeaddrinfo(ai);
+
+ return msgid;
+}
+
+
+static struct {
+ char *name;
+ char *pattern;
+ regex_t regex;
+} mail_list_magic[] = {
+ /* List-Post: <mailto:gnome-hackers@gnome.org> */
+ /* List-Post: <mailto:gnome-hackers> */
+ { "List-Post", "[ \t]*<mailto:([^@>]+)@?([^ \n\t\r>]*)" },
+ /* List-Id: GNOME stuff <gnome-hackers.gnome.org> */
+ /* List-Id: <gnome-hackers.gnome.org> */
+ /* List-Id: <gnome-hackers> */
+ /* This old one wasn't very useful: { "List-Id", " *([^<]+)" },*/
+ { "List-Id", "[^<]*<([^\\.>]+)\\.?([^ \n\t\r>]*)" },
+ /* Mailing-List: list gnome-hackers@gnome.org; contact gnome-hackers-owner@gnome.org */
+ { "Mailing-List", "[ \t]*list ([^@]+)@?([^ \n\t\r>;]*)" },
+ /* Originator: gnome-hackers@gnome.org */
+ { "Originator", "[ \t]*([^@]+)@?([^ \n\t\r>]*)" },
+ /* X-Mailing-List: <gnome-hackers@gnome.org> arcive/latest/100 */
+ /* X-Mailing-List: gnome-hackers@gnome.org */
+ /* X-Mailing-List: gnome-hackers */
+ /* X-Mailing-List: <gnome-hackers> */
+ { "X-Mailing-List", "[ \t]*<?([^@>]+)@?([^ \n\t\r>]*)" },
+ /* X-Loop: gnome-hackers@gnome.org */
+ { "X-Loop", "[ \t]*([^@]+)@?([^ \n\t\r>]*)" },
+ /* X-List: gnome-hackers */
+ /* X-List: gnome-hackers@gnome.org */
+ { "X-List", "[ \t]*([^@]+)@?([^ \n\t\r>]*)" },
+ /* Sender: owner-gnome-hackers@gnome.org */
+ /* Sender: owner-gnome-hacekrs */
+ { "Sender", "[ \t]*owner-([^@]+)@?([^ @\n\t\r>]*)" },
+ /* Sender: gnome-hackers-owner@gnome.org */
+ /* Sender: gnome-hackers-owner */
+ { "Sender", "[ \t]*([^@]+)-owner@?([^ @\n\t\r>]*)" },
+ /* Delivered-To: mailing list gnome-hackers@gnome.org */
+ /* Delivered-To: mailing list gnome-hackers */
+ { "Delivered-To", "[ \t]*mailing list ([^@]+)@?([^ \n\t\r>]*)" },
+ /* Sender: owner-gnome-hackers@gnome.org */
+ /* Sender: <owner-gnome-hackers@gnome.org> */
+ /* Sender: owner-gnome-hackers */
+ /* Sender: <owner-gnome-hackers> */
+ { "Return-Path", "[ \t]*<?owner-([^@>]+)@?([^ \n\t\r>]*)" },
+ /* X-BeenThere: gnome-hackers@gnome.org */
+ /* X-BeenThere: gnome-hackers */
+ { "X-BeenThere", "[ \t]*([^@]+)@?([^ \n\t\r>]*)" },
+ /* List-Unsubscribe: <mailto:gnome-hackers-unsubscribe@gnome.org> */
+ { "List-Unsubscribe", "<mailto:(.+)-unsubscribe@([^ \n\t\r>]*)" },
+};
+
+char *
+camel_header_raw_check_mailing_list(struct _camel_header_raw **list)
+{
+ const char *v;
+ regmatch_t match[3];
+ int i, j;
+
+ for (i = 0; i < sizeof (mail_list_magic) / sizeof (mail_list_magic[0]); i++) {
+ v = camel_header_raw_find (list, mail_list_magic[i].name, NULL);
+ for (j=0;j<3;j++) {
+ match[j].rm_so = -1;
+ match[j].rm_eo = -1;
+ }
+ if (v != NULL && regexec (&mail_list_magic[i].regex, v, 3, match, 0) == 0 && match[1].rm_so != -1) {
+ char *list;
+ int len1, len2;
+
+ len1 = match[1].rm_eo - match[1].rm_so;
+ len2 = match[2].rm_eo - match[2].rm_so;
+
+ list = g_malloc(len1+len2+2);
+ memcpy(list, v + match[1].rm_so, len1);
+ if (len2) {
+ list[len1] = '@';
+ memcpy(list+len1+1, v+match[2].rm_so, len2);
+ list[len1+len2+1]=0;
+ } else {
+ list[len1] = 0;
+ }
+
+ return list;
+ }
+ }
+
+ return NULL;
+}
+
+/* ok, here's the address stuff, what a mess ... */
+struct _camel_header_address *
+camel_header_address_new (void)
+{
+ struct _camel_header_address *h;
+ h = g_malloc0(sizeof(*h));
+ h->type = CAMEL_HEADER_ADDRESS_NONE;
+ h->refcount = 1;
+ return h;
+}
+
+struct _camel_header_address *
+camel_header_address_new_name(const char *name, const char *addr)
+{
+ struct _camel_header_address *h;
+ h = camel_header_address_new();
+ h->type = CAMEL_HEADER_ADDRESS_NAME;
+ h->name = g_strdup(name);
+ h->v.addr = g_strdup(addr);
+ return h;
+}
+
+struct _camel_header_address *
+camel_header_address_new_group (const char *name)
+{
+ struct _camel_header_address *h;
+
+ h = camel_header_address_new();
+ h->type = CAMEL_HEADER_ADDRESS_GROUP;
+ h->name = g_strdup(name);
+ return h;
+}
+
+void
+camel_header_address_ref(struct _camel_header_address *h)
+{
+ if (h)
+ h->refcount++;
+}
+
+void
+camel_header_address_unref(struct _camel_header_address *h)
+{
+ if (h) {
+ if (h->refcount <= 1) {
+ if (h->type == CAMEL_HEADER_ADDRESS_GROUP) {
+ camel_header_address_list_clear(&h->v.members);
+ } else if (h->type == CAMEL_HEADER_ADDRESS_NAME) {
+ g_free(h->v.addr);
+ }
+ g_free(h->name);
+ g_free(h);
+ } else {
+ h->refcount--;
+ }
+ }
+}
+
+void
+camel_header_address_set_name(struct _camel_header_address *h, const char *name)
+{
+ if (h) {
+ g_free(h->name);
+ h->name = g_strdup(name);
+ }
+}
+
+void
+camel_header_address_set_addr(struct _camel_header_address *h, const char *addr)
+{
+ if (h) {
+ if (h->type == CAMEL_HEADER_ADDRESS_NAME
+ || h->type == CAMEL_HEADER_ADDRESS_NONE) {
+ h->type = CAMEL_HEADER_ADDRESS_NAME;
+ g_free(h->v.addr);
+ h->v.addr = g_strdup(addr);
+ } else {
+ g_warning("Trying to set the address on a group");
+ }
+ }
+}
+
+void
+camel_header_address_set_members(struct _camel_header_address *h, struct _camel_header_address *group)
+{
+ if (h) {
+ if (h->type == CAMEL_HEADER_ADDRESS_GROUP
+ || h->type == CAMEL_HEADER_ADDRESS_NONE) {
+ h->type = CAMEL_HEADER_ADDRESS_GROUP;
+ camel_header_address_list_clear(&h->v.members);
+ /* should this ref them? */
+ h->v.members = group;
+ } else {
+ g_warning("Trying to set the members on a name, not group");
+ }
+ }
+}
+
+void
+camel_header_address_add_member(struct _camel_header_address *h, struct _camel_header_address *member)
+{
+ if (h) {
+ if (h->type == CAMEL_HEADER_ADDRESS_GROUP
+ || h->type == CAMEL_HEADER_ADDRESS_NONE) {
+ h->type = CAMEL_HEADER_ADDRESS_GROUP;
+ camel_header_address_list_append(&h->v.members, member);
+ }
+ }
+}
+
+void
+camel_header_address_list_append_list(struct _camel_header_address **l, struct _camel_header_address **h)
+{
+ if (l) {
+ struct _camel_header_address *n = (struct _camel_header_address *)l;
+
+ while (n->next)
+ n = n->next;
+ n->next = *h;
+ }
+}
+
+
+void
+camel_header_address_list_append(struct _camel_header_address **l, struct _camel_header_address *h)
+{
+ if (h) {
+ camel_header_address_list_append_list(l, &h);
+ h->next = NULL;
+ }
+}
+
+void
+camel_header_address_list_clear(struct _camel_header_address **l)
+{
+ struct _camel_header_address *a, *n;
+ a = *l;
+ while (a) {
+ n = a->next;
+ camel_header_address_unref(a);
+ a = n;
+ }
+ *l = NULL;
+}
+
+/* if encode is true, then the result is suitable for mailing, otherwise
+ the result is suitable for display only (and may not even be re-parsable) */
+static void
+header_address_list_encode_append (GString *out, int encode, struct _camel_header_address *a)
+{
+ char *text;
+
+ while (a) {
+ switch (a->type) {
+ case CAMEL_HEADER_ADDRESS_NAME:
+ if (encode)
+ text = camel_header_encode_phrase (a->name);
+ else
+ text = a->name;
+ if (text && *text)
+ g_string_append_printf (out, "%s <%s>", text, a->v.addr);
+ else
+ g_string_append (out, a->v.addr);
+ if (encode)
+ g_free (text);
+ break;
+ case CAMEL_HEADER_ADDRESS_GROUP:
+ if (encode)
+ text = camel_header_encode_phrase (a->name);
+ else
+ text = a->name;
+ g_string_append_printf (out, "%s: ", text);
+ header_address_list_encode_append (out, encode, a->v.members);
+ g_string_append_printf (out, ";");
+ if (encode)
+ g_free (text);
+ break;
+ default:
+ g_warning ("Invalid address type");
+ break;
+ }
+ a = a->next;
+ if (a)
+ g_string_append (out, ", ");
+ }
+}
+
+char *
+camel_header_address_list_encode (struct _camel_header_address *a)
+{
+ GString *out;
+ char *ret;
+
+ if (a == NULL)
+ return NULL;
+
+ out = g_string_new ("");
+ header_address_list_encode_append (out, TRUE, a);
+ ret = out->str;
+ g_string_free (out, FALSE);
+
+ return ret;
+}
+
+char *
+camel_header_address_list_format (struct _camel_header_address *a)
+{
+ GString *out;
+ char *ret;
+
+ if (a == NULL)
+ return NULL;
+
+ out = g_string_new ("");
+
+ header_address_list_encode_append (out, FALSE, a);
+ ret = out->str;
+ g_string_free (out, FALSE);
+
+ return ret;
+}
+
+char *
+camel_header_address_fold (const char *in, size_t headerlen)
+{
+ size_t len, outlen;
+ const char *inptr = in, *space, *p, *n;
+ GString *out;
+ char *ret;
+ int i, needunfold = FALSE;
+
+ if (in == NULL)
+ return NULL;
+
+ /* first, check to see if we even need to fold */
+ len = headerlen + 2;
+ p = in;
+ while (*p) {
+ n = strchr (p, '\n');
+ if (n == NULL) {
+ len += strlen (p);
+ break;
+ }
+
+ needunfold = TRUE;
+ len += n-p;
+
+ if (len >= CAMEL_FOLD_SIZE)
+ break;
+ len = 0;
+ p = n + 1;
+ }
+ if (len < CAMEL_FOLD_SIZE)
+ return g_strdup (in);
+
+ /* we need to fold, so first unfold (if we need to), then process */
+ if (needunfold)
+ inptr = in = camel_header_unfold (in);
+
+ out = g_string_new ("");
+ outlen = headerlen + 2;
+ while (*inptr) {
+ space = strchr (inptr, ' ');
+ if (space) {
+ len = space - inptr + 1;
+ } else {
+ len = strlen (inptr);
+ }
+
+ d(printf("next word '%.*s'\n", len, inptr));
+
+ if (outlen + len > CAMEL_FOLD_SIZE) {
+ d(printf("outlen = %d wordlen = %d\n", outlen, len));
+ /* strip trailing space */
+ if (out->len > 0 && out->str[out->len-1] == ' ')
+ g_string_truncate (out, out->len-1);
+ g_string_append (out, "\n\t");
+ outlen = 1;
+ }
+
+ outlen += len;
+ for (i = 0; i < len; i++) {
+ g_string_append_c (out, inptr[i]);
+ }
+
+ inptr += len;
+ }
+ ret = out->str;
+ g_string_free (out, FALSE);
+
+ if (needunfold)
+ g_free ((char *)in);
+
+ return ret;
+}
+
+/* simple header folding */
+/* will work even if the header is already folded */
+char *
+camel_header_fold(const char *in, size_t headerlen)
+{
+ size_t len, outlen, i;
+ const char *inptr = in, *space, *p, *n;
+ GString *out;
+ char *ret;
+ int needunfold = FALSE;
+
+ if (in == NULL)
+ return NULL;
+
+ /* first, check to see if we even need to fold */
+ len = headerlen + 2;
+ p = in;
+ while (*p) {
+ n = strchr(p, '\n');
+ if (n == NULL) {
+ len += strlen (p);
+ break;
+ }
+
+ needunfold = TRUE;
+ len += n-p;
+
+ if (len >= CAMEL_FOLD_SIZE)
+ break;
+ len = 0;
+ p = n + 1;
+ }
+ if (len < CAMEL_FOLD_SIZE)
+ return g_strdup(in);
+
+ /* we need to fold, so first unfold (if we need to), then process */
+ if (needunfold)
+ inptr = in = camel_header_unfold(in);
+
+ out = g_string_new("");
+ outlen = headerlen+2;
+ while (*inptr) {
+ space = strchr(inptr, ' ');
+ if (space) {
+ len = space-inptr+1;
+ } else {
+ len = strlen(inptr);
+ }
+ d(printf("next word '%.*s'\n", len, inptr));
+ if (outlen + len > CAMEL_FOLD_SIZE) {
+ d(printf("outlen = %d wordlen = %d\n", outlen, len));
+ /* strip trailing space */
+ if (out->len > 0 && out->str[out->len-1] == ' ')
+ g_string_truncate(out, out->len-1);
+ g_string_append(out, "\n\t");
+ outlen = 1;
+ /* check for very long words, just cut them up */
+ while (outlen+len > CAMEL_FOLD_MAX_SIZE) {
+ for (i=0;i<CAMEL_FOLD_MAX_SIZE-outlen;i++)
+ g_string_append_c(out, inptr[i]);
+ inptr += CAMEL_FOLD_MAX_SIZE-outlen;
+ len -= CAMEL_FOLD_MAX_SIZE-outlen;
+ g_string_append(out, "\n\t");
+ outlen = 1;
+ }
+ }
+ outlen += len;
+ for (i=0;i<len;i++) {
+ g_string_append_c(out, inptr[i]);
+ }
+ inptr += len;
+ }
+ ret = out->str;
+ g_string_free(out, FALSE);
+
+ if (needunfold)
+ g_free((char *)in);
+
+ return ret;
+}
+
+char *
+camel_header_unfold(const char *in)
+{
+ char *out = g_malloc(strlen(in)+1);
+ const char *inptr = in;
+ char c, *o = out;
+
+ o = out;
+ while ((c = *inptr++)) {
+ if (c == '\n') {
+ if (camel_mime_is_lwsp(*inptr)) {
+ do {
+ inptr++;
+ } while (camel_mime_is_lwsp(*inptr));
+ *o++ = ' ';
+ } else {
+ *o++ = c;
+ }
+ } else {
+ *o++ = c;
+ }
+ }
+ *o = 0;
+
+ return out;
+}
+
+void
+camel_mime_utils_init(void)
+{
+ int i, errcode, regex_compilation_failed=0;
+
+ /* Init tables */
+ header_decode_init();
+ base64_init();
+
+ /* precompile regex's for speed at runtime */
+ for (i = 0; i < G_N_ELEMENTS (mail_list_magic); i++) {
+ errcode = regcomp(&mail_list_magic[i].regex, mail_list_magic[i].pattern, REG_EXTENDED|REG_ICASE);
+ if (errcode != 0) {
+ char *errstr;
+ size_t len;
+
+ len = regerror(errcode, &mail_list_magic[i].regex, NULL, 0);
+ errstr = g_malloc0(len + 1);
+ regerror(errcode, &mail_list_magic[i].regex, errstr, len);
+
+ g_warning("Internal error, compiling regex failed: %s: %s", mail_list_magic[i].pattern, errstr);
+ g_free(errstr);
+ regex_compilation_failed++;
+ }
+ }
+
+ g_assert(regex_compilation_failed == 0);
+}
+
+
+void
+camel_mime_utils_shutdown (void)
+{
+ int i;
+
+ for (i = 0; i < G_N_ELEMENTS (mail_list_magic); i++)
+ regfree (&mail_list_magic[i].regex);
+}
diff --git a/camel/camel-movemail.c b/camel/camel-movemail.c
new file mode 100644
index 0000000000..9684bf25e6
--- /dev/null
+++ b/camel/camel-movemail.c
@@ -0,0 +1,540 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* camel-movemail.c: mbox copying function */
+
+/*
+ * Author:
+ * Dan Winship <danw@ximian.com>
+ *
+ * Copyright 2000 Ximian, Inc. (www.ximian.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/stat.h>
+#include <sys/uio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#endif
+
+#include "camel-movemail.h"
+#include "camel-exception.h"
+
+#include "camel-mime-parser.h"
+#include "camel-mime-filter.h"
+#include "camel-mime-filter-from.h"
+
+#include "camel-lock-client.h"
+
+#define d(x)
+
+#ifdef MOVEMAIL_PATH
+#include <sys/wait.h>
+
+static void movemail_external (const char *source, const char *dest,
+ CamelException *ex);
+#endif
+
+#ifdef HAVE_BROKEN_SPOOL
+static int camel_movemail_copy_filter(int fromfd, int tofd, off_t start, size_t bytes, CamelMimeFilter *filter);
+static int camel_movemail_solaris (int oldsfd, int dfd, CamelException *ex);
+#else
+/* these could probably be exposed as a utility? (but only mbox needs it) */
+static int camel_movemail_copy_file(int sfd, int dfd, CamelException *ex);
+#endif
+
+#if 0
+static int camel_movemail_copy(int fromfd, int tofd, off_t start, size_t bytes);
+#endif
+
+/**
+ * camel_movemail: Copy an mbox file from a shared spool directory to a
+ * new folder in a Camel store
+ * @source: source file
+ * @dest: destination file
+ * @ex: a CamelException
+ *
+ * This copies an mbox file from a shared directory with multiple
+ * readers and writers into a private (presumably Camel-controlled)
+ * directory. Dot locking is used on the source file (but not the
+ * destination).
+ *
+ * Return Value: Returns -1 on error.
+ **/
+int
+camel_movemail(const char *source, const char *dest, CamelException *ex)
+{
+ int lockid = -1;
+ int res = -1;
+ int sfd, dfd;
+ struct stat st;
+
+ /* Stat and then open the spool file. If it doesn't exist or
+ * is empty, the user has no mail. (There's technically a race
+ * condition here in that an MDA might have just now locked it
+ * to deliver a message, but we don't care. In that case,
+ * assuming it's unlocked is equivalent to pretending we were
+ * called a fraction earlier.)
+ */
+ if (stat (source, &st) == -1) {
+ if (errno != ENOENT) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Could not check mail file %s: %s"),
+ source, g_strerror (errno));
+ }
+ return -1;
+ }
+
+ if (st.st_size == 0)
+ return 0;
+
+ /* open files */
+ sfd = open (source, O_RDWR);
+ if (sfd == -1) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Could not open mail file %s: %s"),
+ source, g_strerror (errno));
+ return -1;
+ }
+
+ dfd = open (dest, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
+ if (dfd == -1) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Could not open temporary mail "
+ "file %s: %s"), dest,
+ g_strerror (errno));
+ close (sfd);
+ return -1;
+ }
+
+ /* lock our source mailbox */
+ lockid = camel_lock_helper_lock(source, ex);
+ if (lockid == -1) {
+ close(sfd);
+ close(dfd);
+ return -1;
+ }
+
+#ifdef HAVE_BROKEN_SPOOL
+ res = camel_movemail_solaris(sfd, dfd, ex);
+#else
+ res = camel_movemail_copy_file(sfd, dfd, ex);
+#endif
+
+ /* If no errors occurred copying the data, and we successfully
+ * close the destination file, then truncate the source file.
+ */
+ if (res != -1) {
+ if (close (dfd) == 0) {
+ ftruncate (sfd, 0);
+ } else {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Failed to store mail in temp file %s: %s"),
+ dest, g_strerror (errno));
+ res = -1;
+ }
+ } else
+ close (dfd);
+ close (sfd);
+
+ camel_lock_helper_unlock(lockid);
+
+ return res;
+}
+
+#ifdef MOVEMAIL_PATH
+static void
+movemail_external (const char *source, const char *dest, CamelException *ex)
+{
+ sigset_t mask, omask;
+ pid_t pid;
+ int fd[2], len = 0, nread, status;
+ char buf[BUFSIZ], *output = NULL;
+
+ /* Block SIGCHLD so the app can't mess us up. */
+ sigemptyset (&mask);
+ sigaddset (&mask, SIGCHLD);
+ sigprocmask (SIG_BLOCK, &mask, &omask);
+
+ if (pipe (fd) == -1) {
+ sigprocmask (SIG_SETMASK, &omask, NULL);
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Could not create pipe: %s"),
+ g_strerror (errno));
+ return;
+ }
+
+ pid = fork ();
+ switch (pid) {
+ case -1:
+ close (fd[0]);
+ close (fd[1]);
+ sigprocmask (SIG_SETMASK, &omask, NULL);
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Could not fork: %s"),
+ g_strerror (errno));
+ return;
+
+ case 0:
+ /* Child */
+ close (fd[0]);
+ close (STDIN_FILENO);
+ dup2 (fd[1], STDOUT_FILENO);
+ dup2 (fd[1], STDERR_FILENO);
+
+ execl (MOVEMAIL_PATH, MOVEMAIL_PATH, source, dest, NULL);
+ _exit (255);
+ break;
+
+ default:
+ break;
+ }
+
+ /* Parent */
+ close (fd[1]);
+
+ /* Read movemail's output. */
+ while ((nread = read (fd[0], buf, sizeof (buf))) > 0) {
+ output = g_realloc (output, len + nread + 1);
+ memcpy (output + len, buf, nread);
+ len += nread;
+ output[len] = '\0';
+ }
+ close (fd[0]);
+
+ /* Now get the exit status. */
+ while (waitpid (pid, &status, 0) == -1 && errno == EINTR)
+ ;
+ sigprocmask (SIG_SETMASK, &omask, NULL);
+
+ if (!WIFEXITED (status) || WEXITSTATUS (status) != 0) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Movemail program failed: %s"),
+ output ? output : _("(Unknown error)"));
+ }
+ g_free (output);
+}
+#endif
+
+#ifndef HAVE_BROKEN_SPOOL
+static int
+camel_movemail_copy_file(int sfd, int dfd, CamelException *ex)
+{
+ int nread, nwrote;
+ char buf[4096];
+
+ while (1) {
+ int written = 0;
+
+ nread = read (sfd, buf, sizeof (buf));
+ if (nread == 0)
+ break;
+ else if (nread == -1) {
+ if (errno == EINTR)
+ continue;
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Error reading mail file: %s"),
+ g_strerror (errno));
+ return -1;
+ }
+
+ while (nread) {
+ nwrote = write (dfd, buf + written, nread);
+ if (nwrote == -1) {
+ if (errno == EINTR)
+ continue; /* continues inner loop */
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Error writing mail temp file: %s"),
+ g_strerror (errno));
+ return -1;
+ }
+ written += nwrote;
+ nread -= nwrote;
+ }
+ }
+
+ return 0;
+}
+#endif
+
+#if 0
+static int
+camel_movemail_copy(int fromfd, int tofd, off_t start, size_t bytes)
+{
+ char buffer[4096];
+ int written = 0;
+
+ d(printf("writing %d bytes ... ", bytes));
+
+ if (lseek(fromfd, start, SEEK_SET) != start)
+ return -1;
+
+ while (bytes>0) {
+ int toread, towrite;
+
+ toread = bytes;
+ if (bytes>4096)
+ toread = 4096;
+ else
+ toread = bytes;
+ do {
+ towrite = read(fromfd, buffer, toread);
+ } while (towrite == -1 && errno == EINTR);
+
+ if (towrite == -1)
+ return -1;
+
+ /* check for 'end of file' */
+ if (towrite == 0) {
+ d(printf("end of file?\n"));
+ break;
+ }
+
+ do {
+ toread = write(tofd, buffer, towrite);
+ } while (toread == -1 && errno == EINTR);
+
+ if (toread == -1)
+ return -1;
+
+ written += toread;
+ bytes -= toread;
+ }
+
+ d(printf("written %d bytes\n", written));
+
+ return written;
+}
+#endif
+
+#define PRE_SIZE (32)
+
+#ifdef HAVE_BROKEN_SPOOL
+static int
+camel_movemail_copy_filter(int fromfd, int tofd, off_t start, size_t bytes, CamelMimeFilter *filter)
+{
+ char buffer[4096+PRE_SIZE];
+ int written = 0;
+ char *filterbuffer;
+ int filterlen, filterpre;
+
+ d(printf("writing %d bytes ... ", bytes));
+
+ camel_mime_filter_reset(filter);
+
+ if (lseek(fromfd, start, SEEK_SET) != start)
+ return -1;
+
+ while (bytes>0) {
+ int toread, towrite;
+
+ toread = bytes;
+ if (bytes>4096)
+ toread = 4096;
+ else
+ toread = bytes;
+ do {
+ towrite = read(fromfd, buffer+PRE_SIZE, toread);
+ } while (towrite == -1 && errno == EINTR);
+
+ if (towrite == -1)
+ return -1;
+
+ d(printf("read %d unfiltered bytes\n", towrite));
+
+ /* check for 'end of file' */
+ if (towrite == 0) {
+ d(printf("end of file?\n"));
+ camel_mime_filter_complete(filter, buffer+PRE_SIZE, towrite, PRE_SIZE,
+ &filterbuffer, &filterlen, &filterpre);
+ towrite = filterlen;
+ if (towrite == 0)
+ break;
+ } else {
+ camel_mime_filter_filter(filter, buffer+PRE_SIZE, towrite, PRE_SIZE,
+ &filterbuffer, &filterlen, &filterpre);
+ towrite = filterlen;
+ }
+
+ d(printf("writing %d filtered bytes\n", towrite));
+
+ do {
+ toread = write(tofd, filterbuffer, towrite);
+ } while (toread == -1 && errno == EINTR);
+
+ if (toread == -1)
+ return -1;
+
+ written += toread;
+ bytes -= toread;
+ }
+
+ d(printf("written %d bytes\n", written));
+
+ return written;
+}
+
+/* write the headers back out again, but not he Content-Length header, because we dont
+ want to maintain it! */
+static int
+solaris_header_write(int fd, struct _camel_header_raw *header)
+{
+ struct iovec iv[4];
+ int outlen = 0, len;
+
+ iv[1].iov_base = ":";
+ iv[1].iov_len = 1;
+ iv[3].iov_base = "\n";
+ iv[3].iov_len = 1;
+
+ while (header) {
+ if (strcasecmp(header->name, "Content-Length")) {
+ iv[0].iov_base = header->name;
+ iv[0].iov_len = strlen(header->name);
+ iv[2].iov_base = header->value;
+ iv[2].iov_len = strlen(header->value);
+
+ do {
+ len = writev(fd, iv, 4);
+ } while (len == -1 && errno == EINTR);
+
+ if (len == -1)
+ return -1;
+ outlen += len;
+ }
+ header = header->next;
+ }
+
+ do {
+ len = write(fd, "\n", 1);
+ } while (len == -1 && errno == EINTR);
+
+ if (len == -1)
+ return -1;
+
+ outlen += 1;
+
+ d(printf("Wrote %d bytes of headers\n", outlen));
+
+ return outlen;
+}
+
+/* Well, since Solaris is a tad broken wrt its 'mbox' folder format,
+ we must convert it to a real mbox format. Thankfully this is
+ mostly pretty easy */
+static int
+camel_movemail_solaris (int oldsfd, int dfd, CamelException *ex)
+{
+ CamelMimeParser *mp;
+ char *buffer;
+ int len;
+ int sfd;
+ CamelMimeFilterFrom *ffrom;
+ int ret = 1;
+ char *from = NULL;
+
+ /* need to dup as the mime parser will close on finish */
+ sfd = dup(oldsfd);
+ if (sfd == -1) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Error copying mail temp file: %s"),
+ g_strerror (errno));
+ return -1;
+ }
+
+ mp = camel_mime_parser_new();
+ camel_mime_parser_scan_from(mp, TRUE);
+ camel_mime_parser_init_with_fd(mp, sfd);
+
+ ffrom = camel_mime_filter_from_new();
+
+ while (camel_mime_parser_step(mp, &buffer, &len) == CAMEL_MIME_PARSER_STATE_FROM) {
+ g_assert(camel_mime_parser_from_line(mp));
+ from = g_strdup(camel_mime_parser_from_line(mp));
+ if (camel_mime_parser_step(mp, &buffer, &len) != CAMEL_MIME_PARSER_STATE_FROM_END) {
+ const char *cl;
+ int length;
+ int start, body;
+ off_t newpos;
+
+ ret = 0;
+
+ start = camel_mime_parser_tell_start_from(mp);
+ body = camel_mime_parser_tell(mp);
+
+ if (write(dfd, from, strlen(from)) != strlen(from))
+ goto fail;
+
+ /* write out headers, but NOT content-length header */
+ if (solaris_header_write(dfd, camel_mime_parser_headers_raw(mp)) == -1)
+ goto fail;
+
+ cl = camel_mime_parser_header(mp, "content-length", NULL);
+ if (cl == NULL) {
+ g_warning("Required Content-Length header is missing from solaris mail box @ %d", (int)camel_mime_parser_tell(mp));
+ camel_mime_parser_drop_step(mp);
+ camel_mime_parser_drop_step(mp);
+ camel_mime_parser_step(mp, &buffer, &len);
+ camel_mime_parser_unstep(mp);
+ length = camel_mime_parser_tell_start_from(mp) - body;
+ newpos = -1;
+ } else {
+ length = atoi(cl);
+ camel_mime_parser_drop_step(mp);
+ camel_mime_parser_drop_step(mp);
+ newpos = length+body;
+ }
+ /* copy body->length converting From lines */
+ if (camel_movemail_copy_filter(sfd, dfd, body, length, (CamelMimeFilter *)ffrom) == -1)
+ goto fail;
+ if (newpos != -1)
+ camel_mime_parser_seek(mp, newpos, SEEK_SET);
+ } else {
+ g_error("Inalid parser state: %d", camel_mime_parser_state(mp));
+ }
+ g_free(from);
+ }
+
+ camel_object_unref((CamelObject *)mp);
+ camel_object_unref((CamelObject *)ffrom);
+
+ return ret;
+
+fail:
+ g_free(from);
+
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Error copying mail temp file: %s"),
+ g_strerror (errno));
+
+
+ camel_object_unref((CamelObject *)mp);
+ camel_object_unref((CamelObject *)ffrom);
+
+ return -1;
+}
+#endif /* HAVE_BROKEN_SPOOL */
+
diff --git a/camel/camel-multipart-signed.c b/camel/camel-multipart-signed.c
new file mode 100644
index 0000000000..1a5092ba27
--- /dev/null
+++ b/camel/camel-multipart-signed.c
@@ -0,0 +1,794 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ * camel-multipart.c : Abstract class for a multipart
+ *
+ * Authors: Michael Zucchi <notzed@ximian.com>
+ *
+ * Copyright 2002 Ximian, Inc. (www.ximian.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#endif
+
+#include <stdio.h>
+
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+
+#include <errno.h>
+
+#include "camel-mime-part.h"
+#include "camel-mime-message.h"
+#include "camel-mime-parser.h"
+#include "camel-stream-mem.h"
+#include "camel-multipart-signed.h"
+#include "camel-mime-part.h"
+#include "camel-exception.h"
+#include "md5-utils.h"
+
+#include "camel-stream-filter.h"
+#include "camel-seekable-substream.h"
+#include "camel-mime-filter-crlf.h"
+#include "camel-mime-filter-canon.h"
+
+#define d(x) /*(printf("%s(%d): ", __FILE__, __LINE__),(x))
+ #include <stdio.h>;*/
+
+static void signed_add_part (CamelMultipart *multipart, CamelMimePart *part);
+static void signed_add_part_at (CamelMultipart *multipart, CamelMimePart *part, guint index);
+static void signed_remove_part (CamelMultipart *multipart, CamelMimePart *part);
+static CamelMimePart *signed_remove_part_at (CamelMultipart *multipart, guint index);
+static CamelMimePart *signed_get_part (CamelMultipart *multipart, guint index);
+static guint signed_get_number (CamelMultipart *multipart);
+
+static ssize_t write_to_stream (CamelDataWrapper *data_wrapper, CamelStream *stream);
+static void set_mime_type_field (CamelDataWrapper *data_wrapper, CamelContentType *mime_type);
+static int construct_from_stream (CamelDataWrapper *data_wrapper, CamelStream *stream);
+static int signed_construct_from_parser (CamelMultipart *multipart, struct _CamelMimeParser *mp);
+
+static CamelMultipartClass *parent_class = NULL;
+
+/* Returns the class for a CamelMultipartSigned */
+#define CMP_CLASS(so) CAMEL_MULTIPART_SIGNED_CLASS (CAMEL_OBJECT_GET_CLASS(so))
+
+/* Returns the class for a CamelDataWrapper */
+#define CDW_CLASS(so) CAMEL_DATA_WRAPPER_CLASS (CAMEL_OBJECT_GET_CLASS(so))
+
+static void
+camel_multipart_signed_class_init (CamelMultipartSignedClass *camel_multipart_signed_class)
+{
+ CamelDataWrapperClass *camel_data_wrapper_class = CAMEL_DATA_WRAPPER_CLASS(camel_multipart_signed_class);
+ CamelMultipartClass *mpclass = (CamelMultipartClass *)camel_multipart_signed_class;
+
+ parent_class = (CamelMultipartClass *)camel_multipart_get_type();
+
+ /* virtual method overload */
+ camel_data_wrapper_class->construct_from_stream = construct_from_stream;
+ camel_data_wrapper_class->write_to_stream = write_to_stream;
+ camel_data_wrapper_class->decode_to_stream = write_to_stream;
+ camel_data_wrapper_class->set_mime_type_field = set_mime_type_field;
+
+ mpclass->add_part = signed_add_part;
+ mpclass->add_part_at = signed_add_part_at;
+ mpclass->remove_part = signed_remove_part;
+ mpclass->remove_part_at = signed_remove_part_at;
+ mpclass->get_part = signed_get_part;
+ mpclass->get_number = signed_get_number;
+ mpclass->construct_from_parser = signed_construct_from_parser;
+
+/*
+ mpclass->get_boundary = signed_get_boundary;
+ mpclass->set_boundary = signed_set_boundary;
+*/
+}
+
+static void
+camel_multipart_signed_init (gpointer object, gpointer klass)
+{
+ CamelMultipartSigned *multipart = (CamelMultipartSigned *)object;
+
+ camel_data_wrapper_set_mime_type(CAMEL_DATA_WRAPPER(multipart), "multipart/signed");
+ multipart->start1 = -1;
+}
+
+static void
+camel_multipart_signed_finalize (CamelObject *object)
+{
+ CamelMultipartSigned *mps = (CamelMultipartSigned *)object;
+
+ g_free(mps->protocol);
+ g_free(mps->micalg);
+ if (mps->signature)
+ camel_object_unref((CamelObject *)mps->signature);
+ if (mps->content)
+ camel_object_unref((CamelObject *)mps->content);
+ if (mps->contentraw)
+ camel_object_unref((CamelObject *)mps->contentraw);
+}
+
+CamelType
+camel_multipart_signed_get_type (void)
+{
+ static CamelType camel_multipart_signed_type = CAMEL_INVALID_TYPE;
+
+ if (camel_multipart_signed_type == CAMEL_INVALID_TYPE) {
+ camel_multipart_signed_type = camel_type_register (camel_multipart_get_type (), "CamelMultipartSigned",
+ sizeof (CamelMultipartSigned),
+ sizeof (CamelMultipartSignedClass),
+ (CamelObjectClassInitFunc) camel_multipart_signed_class_init,
+ NULL,
+ (CamelObjectInitFunc) camel_multipart_signed_init,
+ (CamelObjectFinalizeFunc) camel_multipart_signed_finalize);
+ }
+
+ return camel_multipart_signed_type;
+}
+
+/**
+ * camel_multipart_signed_new:
+ *
+ * Create a new CamelMultipartSigned object.
+ *
+ * A MultipartSigned should be used to store and create parts of
+ * type "multipart/signed". This is because multipart/signed is
+ * entirely broken-by-design (tm) and uses completely
+ * different semantics to other mutlipart types. It must be treated
+ * as opaque data by any transport. See rfc 3156 for details.
+ *
+ * There are 3 ways to create the part:
+ * Use construct_from_stream. If this is used, then you must
+ * set the mime_type appropriately to match the data uses, so
+ * that the multiple parts my be extracted.
+ *
+ * Use construct_from_parser. The parser MUST be in the CAMEL_MIME_PARSER_STATE_HEADER
+ * state, and the current content_type MUST be "multipart/signed" with
+ * the appropriate boundary and it SHOULD include the appropriate protocol
+ * and hash specifiers.
+ *
+ * Use sign_part. A signature part will automatically be created
+ * and the whole part may be written using write_to_stream to
+ * create a 'transport-safe' version (as safe as can be expected with
+ * such a broken specification).
+ *
+ * Return value: a new CamelMultipartSigned
+ **/
+CamelMultipartSigned *
+camel_multipart_signed_new (void)
+{
+ CamelMultipartSigned *multipart;
+
+ multipart = (CamelMultipartSigned *)camel_object_new(CAMEL_MULTIPART_SIGNED_TYPE);
+
+ return multipart;
+}
+
+static int
+skip_content(CamelMimeParser *cmp)
+{
+ char *buf;
+ size_t len;
+ int state;
+
+ switch (camel_mime_parser_state(cmp)) {
+ case CAMEL_MIME_PARSER_STATE_HEADER:
+ /* body part */
+ while (camel_mime_parser_step(cmp, &buf, &len) != CAMEL_MIME_PARSER_STATE_BODY_END)
+ /* NOOP */ ;
+ break;
+ case CAMEL_MIME_PARSER_STATE_MESSAGE:
+ /* message body part */
+ (void)camel_mime_parser_step(cmp, &buf, &len);
+ skip_content(cmp);
+
+ /* clean up followon state if any, see camel-mime-message.c */
+ state = camel_mime_parser_step(cmp, &buf, &len);
+ switch (state) {
+ case CAMEL_MIME_PARSER_STATE_EOF:
+ case CAMEL_MIME_PARSER_STATE_FROM_END: /* these doesn't belong to us */
+ camel_mime_parser_unstep(cmp);
+ case CAMEL_MIME_PARSER_STATE_MESSAGE_END:
+ break;
+ default:
+ g_error ("Bad parser state: Expecing MESSAGE_END or EOF or EOM, got: %d", camel_mime_parser_state (cmp));
+ camel_mime_parser_unstep(cmp);
+ return -1;
+ }
+ break;
+ case CAMEL_MIME_PARSER_STATE_MULTIPART:
+ /* embedded multipart */
+ while ((state = camel_mime_parser_step(cmp, &buf, &len)) != CAMEL_MIME_PARSER_STATE_MULTIPART_END)
+ skip_content(cmp);
+ break;
+ default:
+ g_warning("Invalid state encountered???: %d", camel_mime_parser_state(cmp));
+ }
+
+ return 0;
+}
+
+static int
+parse_content(CamelMultipartSigned *mps)
+{
+ CamelMimeParser *cmp;
+ CamelMultipart *mp = (CamelMultipart *)mps;
+ CamelStreamMem *mem;
+ const char *boundary;
+ char *buf;
+ size_t len;
+ off_t head = -1, tail = -1;
+ int state;
+
+ boundary = camel_multipart_get_boundary(mp);
+ if (boundary == NULL) {
+ g_warning("Trying to get multipart/signed content without setting boundary first");
+ return -1;
+ }
+
+ mem = (CamelStreamMem *)((CamelDataWrapper *)mps)->stream;
+ if (mem == NULL) {
+ g_warning("Trying to parse multipart/signed without constructing first");
+ return -1;
+ }
+
+ /* This is all seriously complex.
+ This is so we can parse all cases properly, without altering the content.
+ All we are doing is finding part offsets. */
+
+ camel_stream_reset((CamelStream *)mem);
+ cmp = camel_mime_parser_new();
+ camel_mime_parser_init_with_stream(cmp, (CamelStream *)mem);
+ camel_mime_parser_push_state(cmp, CAMEL_MIME_PARSER_STATE_MULTIPART, boundary);
+
+ mps->start1 = -1;
+ mps->end1 = -1;
+ mps->start2 = -1;
+ mps->end2 = -1;
+
+ while ((state = camel_mime_parser_step(cmp, &buf, &len)) != CAMEL_MIME_PARSER_STATE_MULTIPART_END) {
+ if (mps->start1 == -1) {
+ head = camel_mime_parser_tell_start_boundary(cmp);
+ mps->start1 = camel_mime_parser_tell_start_headers(cmp);
+ } else if (mps->start2 == -1) {
+ mps->start2 = camel_mime_parser_tell_start_headers(cmp);
+ mps->end1 = camel_mime_parser_tell_start_boundary(cmp);
+ if (mps->end1 > mps->start1 && mem->buffer->data[mps->end1-1] == '\n')
+ mps->end1--;
+ if (mps->end1 > mps->start1 && mem->buffer->data[mps->end1-1] == '\r')
+ mps->end1--;
+ } else {
+ g_warning("multipart/signed has more than 2 parts, remaining parts ignored");
+ break;
+ }
+
+ if (skip_content(cmp) == -1)
+ break;
+ }
+
+ if (state == CAMEL_MIME_PARSER_STATE_MULTIPART_END) {
+ mps->end2 = camel_mime_parser_tell_start_boundary(cmp);
+ tail = camel_mime_parser_tell(cmp);
+
+ camel_multipart_set_preface(mp, camel_mime_parser_preface(cmp));
+ camel_multipart_set_postface(mp, camel_mime_parser_postface(cmp));
+ }
+
+ camel_object_unref(cmp);
+
+ if (mps->end2 == -1 || mps->start2 == -1) {
+ return -1;
+ }
+
+ return 0;
+}
+
+/* we snoop the mime type to get boundary and hash info */
+static void
+set_mime_type_field(CamelDataWrapper *data_wrapper, CamelContentType *mime_type)
+{
+ CamelMultipartSigned *mps = (CamelMultipartSigned *)data_wrapper;
+
+ ((CamelDataWrapperClass *)parent_class)->set_mime_type_field(data_wrapper, mime_type);
+ if (mime_type) {
+ const char *micalg, *protocol;
+
+ protocol = camel_content_type_param(mime_type, "protocol");
+ g_free(mps->protocol);
+ mps->protocol = g_strdup(protocol);
+
+ micalg = camel_content_type_param(mime_type, "micalg");
+ g_free(mps->micalg);
+ mps->micalg = g_strdup(micalg);
+ }
+}
+
+static void
+signed_add_part(CamelMultipart *multipart, CamelMimePart *part)
+{
+ g_warning("Cannot add parts to a signed part using add_part");
+}
+
+static void
+signed_add_part_at(CamelMultipart *multipart, CamelMimePart *part, guint index)
+{
+ g_warning("Cannot add parts to a signed part using add_part_at");
+}
+
+static void
+signed_remove_part(CamelMultipart *multipart, CamelMimePart *part)
+{
+ g_warning("Cannot remove parts from a signed part using remove_part");
+}
+
+static CamelMimePart *
+signed_remove_part_at (CamelMultipart *multipart, guint index)
+{
+ g_warning("Cannot remove parts from a signed part using remove_part");
+ return NULL;
+}
+
+static CamelMimePart *
+signed_get_part(CamelMultipart *multipart, guint index)
+{
+ CamelMultipartSigned *mps = (CamelMultipartSigned *)multipart;
+ CamelDataWrapper *dw = (CamelDataWrapper *)multipart;
+ CamelStream *stream;
+
+ switch (index) {
+ case CAMEL_MULTIPART_SIGNED_CONTENT:
+ if (mps->content)
+ return mps->content;
+ if (mps->contentraw) {
+ stream = mps->contentraw;
+ camel_object_ref((CamelObject *)stream);
+ } else if (mps->start1 == -1
+ && parse_content(mps) == -1
+ && (stream = ((CamelDataWrapper *)mps)->stream) == NULL) {
+ g_warning("Trying to get content on an invalid multipart/signed");
+ return NULL;
+ } else if (dw->stream == NULL) {
+ return NULL;
+ } else if (mps->start1 == -1) {
+ stream = dw->stream;
+ camel_object_ref(stream);
+ } else {
+ stream = camel_seekable_substream_new((CamelSeekableStream *)dw->stream, mps->start1, mps->end1);
+ }
+ camel_stream_reset(stream);
+ mps->content = camel_mime_part_new();
+ camel_data_wrapper_construct_from_stream((CamelDataWrapper *)mps->content, stream);
+ camel_object_unref(stream);
+ return mps->content;
+ case CAMEL_MULTIPART_SIGNED_SIGNATURE:
+ if (mps->signature)
+ return mps->signature;
+ if (mps->start1 == -1
+ && parse_content(mps) == -1) {
+ g_warning("Trying to get signature on invalid multipart/signed");
+ return NULL;
+ } else if (dw->stream == NULL) {
+ return NULL;
+ }
+ stream = camel_seekable_substream_new((CamelSeekableStream *)dw->stream, mps->start2, mps->end2);
+ camel_stream_reset(stream);
+ mps->signature = camel_mime_part_new();
+ camel_data_wrapper_construct_from_stream((CamelDataWrapper *)mps->signature, stream);
+ camel_object_unref((CamelObject *)stream);
+ return mps->signature;
+ default:
+ g_warning("trying to get object out of bounds for multipart");
+ }
+
+ return NULL;
+}
+
+static guint
+signed_get_number(CamelMultipart *multipart)
+{
+ CamelDataWrapper *dw = (CamelDataWrapper *)multipart;
+ CamelMultipartSigned *mps = (CamelMultipartSigned *)multipart;
+
+ /* check what we have, so we return something reasonable */
+
+ if ((mps->content || mps->contentraw) && mps->signature)
+ return 2;
+
+ if (mps->start1 == -1 && parse_content(mps) == -1) {
+ if (dw->stream == NULL)
+ return 0;
+ else
+ return 1;
+ } else {
+ return 2;
+ }
+}
+
+static void
+set_stream(CamelMultipartSigned *mps, CamelStream *mem)
+{
+ CamelDataWrapper *dw = (CamelDataWrapper *)mps;
+
+ if (dw->stream)
+ camel_object_unref((CamelObject *)dw->stream);
+ dw->stream = (CamelStream *)mem;
+
+ mps->start1 = -1;
+ if (mps->content) {
+ camel_object_unref((CamelObject *)mps->content);
+ mps->content = NULL;
+ }
+ if (mps->contentraw) {
+ camel_object_unref((CamelObject *)mps->contentraw);
+ mps->contentraw = NULL;
+ }
+ if (mps->signature) {
+ camel_object_unref((CamelObject *)mps->signature);
+ mps->signature = NULL;
+ }
+}
+
+static int
+construct_from_stream(CamelDataWrapper *data_wrapper, CamelStream *stream)
+{
+ CamelMultipartSigned *mps = (CamelMultipartSigned *)data_wrapper;
+ CamelStream *mem = camel_stream_mem_new();
+
+ if (camel_stream_write_to_stream(stream, mem) == -1)
+ return -1;
+
+ set_stream(mps, mem);
+
+ return 0;
+}
+
+static int
+signed_construct_from_parser(CamelMultipart *multipart, struct _CamelMimeParser *mp)
+{
+ int err;
+ CamelContentType *content_type;
+ CamelMultipartSigned *mps = (CamelMultipartSigned *)multipart;
+ char *buf;
+ size_t len;
+ CamelStream *mem;
+
+ /* we *must not* be in multipart state, otherwise the mime parser will
+ parse the headers which is a no no @#$@# stupid multipart/signed spec */
+ g_assert(camel_mime_parser_state(mp) == CAMEL_MIME_PARSER_STATE_HEADER);
+
+ /* All we do is copy it to a memstream */
+ content_type = camel_mime_parser_content_type(mp);
+ camel_multipart_set_boundary(multipart, camel_content_type_param(content_type, "boundary"));
+
+ mem = camel_stream_mem_new();
+ while (camel_mime_parser_step(mp, &buf, &len) != CAMEL_MIME_PARSER_STATE_BODY_END)
+ camel_stream_write(mem, buf, len);
+
+ set_stream(mps, mem);
+
+ err = camel_mime_parser_errno(mp);
+ if (err != 0) {
+ errno = err;
+ return -1;
+ } else
+ return 0;
+}
+
+static ssize_t
+write_to_stream (CamelDataWrapper *data_wrapper, CamelStream *stream)
+{
+ CamelMultipartSigned *mps = (CamelMultipartSigned *)data_wrapper;
+ CamelMultipart *mp = (CamelMultipart *)mps;
+ const char *boundary;
+ ssize_t total = 0;
+ ssize_t count;
+
+ /* we have 3 basic cases:
+ 1. constructed, we write out the data wrapper stream we got
+ 2. signed content, we create and write out a new stream
+ 3. invalid
+ */
+
+ /* 1 */
+ /* FIXME: locking? */
+ if (data_wrapper->stream) {
+ camel_stream_reset(data_wrapper->stream);
+ return camel_stream_write_to_stream(data_wrapper->stream, stream);
+ }
+
+ /* 3 */
+ if (mps->signature == NULL || mps->contentraw == NULL)
+ return -1;
+
+ /* 2 */
+ boundary = camel_multipart_get_boundary(mp);
+ if (mp->preface) {
+ count = camel_stream_write_string(stream, mp->preface);
+ if (count == -1)
+ return -1;
+ total += count;
+ }
+
+ /* first boundary */
+ count = camel_stream_printf(stream, "\n--%s\n", boundary);
+ if (count == -1)
+ return -1;
+ total += count;
+
+ /* output content part */
+ camel_stream_reset(mps->contentraw);
+ count = camel_stream_write_to_stream(mps->contentraw, stream);
+ if (count == -1)
+ return -1;
+ total += count;
+
+ /* boundary */
+ count = camel_stream_printf(stream, "\n--%s\n", boundary);
+ if (count == -1)
+ return -1;
+ total += count;
+
+ /* signature */
+ count = camel_data_wrapper_write_to_stream((CamelDataWrapper *)mps->signature, stream);
+ if (count == -1)
+ return -1;
+ total += count;
+
+ /* write the terminating boudary delimiter */
+ count = camel_stream_printf(stream, "\n--%s--\n", boundary);
+ if (count == -1)
+ return -1;
+ total += count;
+
+ /* and finally the postface */
+ if (mp->postface) {
+ count = camel_stream_write_string(stream, mp->postface);
+ if (count == -1)
+ return -1;
+ total += count;
+ }
+
+ return total;
+}
+
+/* See rfc3156, section 2 and others */
+/* We do this simply: Anything not base64 must be qp
+ This is so that we can safely translate any occurance of "From "
+ into the quoted-printable escaped version safely. */
+static void
+prepare_sign(CamelMimePart *mime_part)
+{
+ CamelDataWrapper *wrapper;
+ CamelTransferEncoding encoding;
+ int parts, i;
+
+ wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (mime_part));
+ if (!wrapper)
+ return;
+
+ if (CAMEL_IS_MULTIPART (wrapper)) {
+ parts = camel_multipart_get_number((CamelMultipart *)wrapper);
+ for (i = 0; i < parts; i++)
+ prepare_sign(camel_multipart_get_part((CamelMultipart *)wrapper, i));
+ } else if (CAMEL_IS_MIME_MESSAGE (wrapper)) {
+ prepare_sign((CamelMimePart *)wrapper);
+ } else {
+ encoding = camel_mime_part_get_encoding(mime_part);
+
+ if (encoding != CAMEL_TRANSFER_ENCODING_BASE64
+ && encoding != CAMEL_TRANSFER_ENCODING_QUOTEDPRINTABLE) {
+ camel_mime_part_set_encoding(mime_part, CAMEL_TRANSFER_ENCODING_QUOTEDPRINTABLE);
+ }
+ }
+}
+
+/**
+ * camel_multipart_signed_sign:
+ * @mps:
+ * @context: The CipherContext to use for signing.
+ * @content: CamelMimePart content you wish to sign/transport.
+ * @userid: The id of the signing key to use.
+ * @hash: The algorithm to use.
+ * @ex:
+ *
+ * Sign the part @content, and attach it as the first part
+ * (CAMEL_MULTIPART_SIGNED_CONTENT) of the multipart @mps. A
+ * signature object will be created and setup as the second part
+ * (CAMEL_MULTIPART_SIGNED_SIGNATURE) of the object. Once a part has
+ * been successfully signed the mutlipart is ready for transmission.
+ *
+ * This method should be used to create multipart/signed objects
+ * which are properly canoncalised before signing, etc.
+ *
+ * Return value: -1 on error, setting @ex appropriately. On error
+ * neither the content or signature parts will be setup.
+ **/
+int
+camel_multipart_signed_sign(CamelMultipartSigned *mps, CamelCipherContext *context, CamelMimePart *content, const char *userid, CamelCipherHash hash, CamelException *ex)
+{
+ abort();
+#if 0
+ CamelMimeFilter *canon_filter;
+ CamelStream *mem;
+ CamelStreamFilter *filter;
+ CamelContentType *mime_type;
+ CamelMimePart *sigpart;
+
+ /* this needs to be set */
+ g_return_val_if_fail(context->sign_protocol != NULL, -1);
+
+ prepare_sign(content);
+
+ mem = camel_stream_mem_new();
+ filter = camel_stream_filter_new_with_stream(mem);
+
+ /* Note: see rfc2015 or rfc3156, section 5 */
+ canon_filter = camel_mime_filter_canon_new(CAMEL_MIME_FILTER_CANON_STRIP|CAMEL_MIME_FILTER_CANON_CRLF|CAMEL_MIME_FILTER_CANON_FROM);
+ camel_stream_filter_add(filter, (CamelMimeFilter *)canon_filter);
+ camel_object_unref((CamelObject *)canon_filter);
+
+ camel_data_wrapper_write_to_stream((CamelDataWrapper *)content, (CamelStream *)filter);
+ camel_stream_flush((CamelStream *)filter);
+ camel_object_unref((CamelObject *)filter);
+ camel_stream_reset(mem);
+
+#if 0
+ printf("-- Signing:\n");
+ fwrite(((CamelStreamMem *)mem)->buffer->data, ((CamelStreamMem *)mem)->buffer->len, 1, stdout);
+ printf("-- end\n");
+#endif
+
+ sigpart = camel_mime_part_new();
+
+ if (camel_cipher_sign(context, userid, hash, mem, sigpart, ex) == -1) {
+ camel_object_unref(mem);
+ camel_object_unref(sigpart);
+ return -1;
+ }
+
+ /* setup our mime type and boundary */
+ mime_type = camel_content_type_new("multipart", "signed");
+ camel_content_type_set_param(mime_type, "micalg", camel_cipher_hash_to_id(context, hash));
+ camel_content_type_set_param(mime_type, "protocol", context->sign_protocol);
+ camel_data_wrapper_set_mime_type_field(CAMEL_DATA_WRAPPER (mps), mime_type);
+ camel_content_type_unref(mime_type);
+ camel_multipart_set_boundary((CamelMultipart *)mps, NULL);
+
+ /* just keep the whole raw content. We dont *really* need to do this because
+ we know how we just proccessed it, but, well, better to be safe than sorry */
+ mps->signature = sigpart;
+ mps->contentraw = mem;
+ camel_stream_reset(mem);
+
+ /* clear the data-wrapper stream - tells write_to_stream to use the right object */
+ if (((CamelDataWrapper *)mps)->stream) {
+ camel_object_unref((CamelObject *) ((CamelDataWrapper *)mps)->stream);
+ ((CamelDataWrapper *)mps)->stream = NULL;
+ }
+#endif
+ return 0;
+}
+
+CamelStream *
+camel_multipart_signed_get_content_stream(CamelMultipartSigned *mps, CamelException *ex)
+{
+ CamelStream *constream;
+
+ /* we need to be able to verify stuff we just signed as well as stuff we loaded from a stream/parser */
+
+ if (mps->contentraw) {
+ constream = mps->contentraw;
+ camel_object_ref((CamelObject *)constream);
+ } else {
+ CamelStream *sub;
+ CamelMimeFilter *canon_filter;
+
+ if (mps->start1 == -1 && parse_content(mps) == -1) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, _("parse error"));
+ return NULL;
+ }
+
+ /* first, prepare our parts */
+ sub = camel_seekable_substream_new((CamelSeekableStream *)((CamelDataWrapper *)mps)->stream, mps->start1, mps->end1);
+ constream = (CamelStream *)camel_stream_filter_new_with_stream(sub);
+ camel_object_unref((CamelObject *)sub);
+
+ /* Note: see rfc2015 or rfc3156, section 5 */
+ canon_filter = camel_mime_filter_canon_new (CAMEL_MIME_FILTER_CANON_CRLF);
+ camel_stream_filter_add((CamelStreamFilter *)constream, (CamelMimeFilter *)canon_filter);
+ camel_object_unref((CamelObject *)canon_filter);
+ }
+
+ return constream;
+}
+
+/**
+ * camel_multipart_signed_verify:
+ * @mps:
+ * @context:
+ * @ex:
+ *
+ * Verify a signed object. This may be used to verify newly signed
+ * objects as well as those created from external streams or parsers.
+ *
+ * Return value: A validity value, or NULL on error, setting @ex
+ * appropriately.
+ **/
+CamelCipherValidity *
+camel_multipart_signed_verify(CamelMultipartSigned *mps, CamelCipherContext *context, CamelException *ex)
+{
+ abort();
+
+ return NULL;
+#if 0
+ CamelCipherValidity *valid;
+ CamelMimePart *sigpart;
+ CamelStream *constream;
+
+ /* we need to be able to verify stuff we just signed as well as stuff we loaded from a stream/parser */
+
+ if (mps->contentraw) {
+ constream = mps->contentraw;
+ camel_object_ref((CamelObject *)constream);
+ } else {
+ CamelStream *sub;
+ CamelMimeFilter *canon_filter;
+
+ if (mps->start1 == -1 && parse_content(mps) == -1) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, _("parse error"));
+ return NULL;
+ }
+
+ /* first, prepare our parts */
+ sub = camel_seekable_substream_new((CamelSeekableStream *)((CamelDataWrapper *)mps)->stream, mps->start1, mps->end1);
+ constream = (CamelStream *)camel_stream_filter_new_with_stream(sub);
+ camel_object_unref((CamelObject *)sub);
+
+ /* Note: see rfc2015 or rfc3156, section 5 */
+ canon_filter = camel_mime_filter_canon_new (CAMEL_MIME_FILTER_CANON_CRLF);
+ camel_stream_filter_add((CamelStreamFilter *)constream, (CamelMimeFilter *)canon_filter);
+ camel_object_unref((CamelObject *)canon_filter);
+ }
+
+ /* we do this as a normal mime part so we can have it handle transfer encoding etc */
+ sigpart = camel_multipart_get_part((CamelMultipart *)mps, CAMEL_MULTIPART_SIGNED_SIGNATURE);
+
+ /* do the magic, the caller must supply the right context for this kind of object */
+ valid = camel_cipher_verify(context, camel_cipher_id_to_hash(context, mps->micalg), constream, sigpart, ex);
+
+#if 0
+ {
+ CamelStream *sout = camel_stream_fs_new_with_fd(dup(0));
+
+ camel_stream_printf(sout, "-- Verifying:\n");
+ camel_stream_reset(constream);
+ camel_stream_write_to_stream(constream, sout);
+ camel_stream_printf(sout, "-- end\n");
+ camel_object_unref((CamelObject *)sout);
+ }
+#endif
+
+ camel_object_unref(constream);
+
+ return valid;
+#endif
+}
+
+
diff --git a/camel/camel-operation.c b/camel/camel-operation.c
new file mode 100644
index 0000000000..406d576597
--- /dev/null
+++ b/camel/camel-operation.c
@@ -0,0 +1,730 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Michael Zucchi <NotZed@ximian.com>
+ *
+ * Copyright 2003 Ximian, Inc. (www.ximian.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+
+#include <stdio.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <pthread.h>
+#ifdef HAVE_NSS
+#include <nspr.h>
+#endif
+
+#include "camel-operation.h"
+#include "e-util/e-msgport.h"
+
+#define d(x)
+
+/* ********************************************************************** */
+
+struct _status_stack {
+ guint32 flags;
+ char *msg;
+ int pc; /* last pc reported */
+ unsigned int stamp; /* last stamp reported */
+};
+
+struct _CamelOperation {
+ struct _CamelOperation *next;
+ struct _CamelOperation *prev;
+
+ pthread_t id; /* id of running thread */
+ guint32 flags; /* cancelled ? */
+ int blocked; /* cancellation blocked depth */
+ int refcount;
+
+ CamelOperationStatusFunc status;
+ void *status_data;
+ unsigned int status_update;
+
+ /* stack of status messages (struct _status_stack *) */
+ GSList *status_stack;
+ struct _status_stack *lastreport;
+
+ EMsgPort *cancel_port;
+ int cancel_fd;
+#ifdef HAVE_NSS
+ PRFileDesc *cancel_prfd;
+#endif
+};
+
+#define CAMEL_OPERATION_CANCELLED (1<<0)
+#define CAMEL_OPERATION_TRANSIENT (1<<1)
+
+/* Delay before a transient operation has any effect on the status */
+#define CAMEL_OPERATION_TRANSIENT_DELAY (5)
+
+static pthread_mutex_t operation_lock = PTHREAD_MUTEX_INITIALIZER;
+#define LOCK() pthread_mutex_lock(&operation_lock)
+#define UNLOCK() pthread_mutex_unlock(&operation_lock)
+
+
+static unsigned int stamp (void);
+static EDList operation_list = E_DLIST_INITIALISER(operation_list);
+static pthread_key_t operation_key;
+
+typedef struct _CamelOperationMsg {
+ EMsg msg;
+} CamelOperationMsg ;
+
+/**
+ * camel_operation_init:
+ * @void:
+ *
+ * Init internal variables. Only call this once.
+ **/
+void
+camel_operation_init(void)
+{
+ pthread_key_create(&operation_key, NULL);
+}
+
+/**
+ * camel_operation_shutdown:
+ *
+ * Cleans up internal variables.
+ **/
+void
+camel_operation_shutdown (void)
+{
+ pthread_key_delete (operation_key);
+}
+
+/**
+ * camel_operation_new:
+ * @status: Callback for receiving status messages. This will always
+ * be called with an internal lock held.
+ * @status_data: User data.
+ *
+ * Create a new camel operation handle. Camel operation handles can
+ * be used in a multithreaded application (or a single operation
+ * handle can be used in a non threaded appliation) to cancel running
+ * operations and to obtain notification messages of the internal
+ * status of messages.
+ *
+ * Return value: A new operation handle.
+ **/
+CamelOperation *
+camel_operation_new (CamelOperationStatusFunc status, void *status_data)
+{
+ CamelOperation *cc;
+
+ cc = g_malloc0(sizeof(*cc));
+
+ cc->flags = 0;
+ cc->blocked = 0;
+ cc->refcount = 1;
+ cc->status = status;
+ cc->status_data = status_data;
+ cc->cancel_port = e_msgport_new();
+ cc->cancel_fd = -1;
+
+ LOCK();
+ e_dlist_addtail(&operation_list, (EDListNode *)cc);
+ UNLOCK();
+
+ return cc;
+}
+
+/**
+ * camel_operation_mute:
+ * @cc:
+ *
+ * mutes a camel operation permanently. from this point on you will never
+ * receive operation updates, even if more are sent.
+ **/
+void
+camel_operation_mute(CamelOperation *cc)
+{
+ LOCK();
+ cc->status = NULL;
+ cc->status_data = NULL;
+ UNLOCK();
+}
+
+/**
+ * camel_operation_registered:
+ *
+ * Returns the registered operation, or %NULL if none registered.
+ **/
+CamelOperation *
+camel_operation_registered (void)
+{
+ CamelOperation *cc = (CamelOperation *)pthread_getspecific(operation_key);
+
+ if (cc)
+ camel_operation_ref(cc);
+
+ return cc;
+}
+
+/**
+ * camel_operation_ref:
+ * @cc: operation context
+ *
+ * Add a reference to the CamelOperation @cc.
+ **/
+void
+camel_operation_ref (CamelOperation *cc)
+{
+ g_assert(cc->refcount > 0);
+
+ LOCK();
+ cc->refcount++;
+ UNLOCK();
+}
+
+/**
+ * camel_operation_unref:
+ * @cc: operation context
+ *
+ * Unref and potentially free @cc.
+ **/
+void
+camel_operation_unref (CamelOperation *cc)
+{
+ GSList *n;
+
+ g_assert(cc->refcount > 0);
+
+ LOCK();
+ if (cc->refcount == 1) {
+ CamelOperationMsg *msg;
+
+ e_dlist_remove((EDListNode *)cc);
+
+ while ((msg = (CamelOperationMsg *)e_msgport_get(cc->cancel_port)))
+ g_free(msg);
+
+ e_msgport_destroy(cc->cancel_port);
+
+ n = cc->status_stack;
+ while (n) {
+ g_warning("Camel operation status stack non empty: %s", (char *)n->data);
+ g_free(n->data);
+ n = n->next;
+ }
+ g_slist_free(cc->status_stack);
+
+ g_free(cc);
+ } else {
+ cc->refcount--;
+ }
+ UNLOCK();
+}
+
+/**
+ * camel_operation_cancel_block:
+ * @cc: operation context
+ *
+ * Block cancellation for this operation. If @cc is NULL, then the
+ * current thread is blocked.
+ **/
+void
+camel_operation_cancel_block (CamelOperation *cc)
+{
+ if (cc == NULL)
+ cc = (CamelOperation *)pthread_getspecific(operation_key);
+
+ if (cc) {
+ LOCK();
+ cc->blocked++;
+ UNLOCK();
+ }
+}
+
+/**
+ * camel_operation_cancel_unblock:
+ * @cc: operation context
+ *
+ * Unblock cancellation, when the unblock count reaches the block
+ * count, then this operation can be cancelled. If @cc is NULL, then
+ * the current thread is unblocked.
+ **/
+void
+camel_operation_cancel_unblock (CamelOperation *cc)
+{
+ if (cc == NULL)
+ cc = (CamelOperation *)pthread_getspecific(operation_key);
+
+ if (cc) {
+ LOCK();
+ cc->blocked--;
+ UNLOCK();
+ }
+}
+
+/**
+ * camel_operation_cancel:
+ * @cc: operation context
+ *
+ * Cancel a given operation. If @cc is NULL then all outstanding
+ * operations are cancelled.
+ **/
+void
+camel_operation_cancel (CamelOperation *cc)
+{
+ CamelOperationMsg *msg;
+
+ LOCK();
+
+ if (cc == NULL) {
+ CamelOperation *cn;
+
+ cc = (CamelOperation *)operation_list.head;
+ cn = cc->next;
+ while (cn) {
+ cc->flags |= CAMEL_OPERATION_CANCELLED;
+ msg = g_malloc0(sizeof(*msg));
+ e_msgport_put(cc->cancel_port, (EMsg *)msg);
+ cc = cn;
+ cn = cn->next;
+ }
+ } else if ((cc->flags & CAMEL_OPERATION_CANCELLED) == 0) {
+ d(printf("cancelling thread %d\n", cc->id));
+
+ cc->flags |= CAMEL_OPERATION_CANCELLED;
+ msg = g_malloc0(sizeof(*msg));
+ e_msgport_put(cc->cancel_port, (EMsg *)msg);
+ }
+
+ UNLOCK();
+}
+
+/**
+ * camel_operation_uncancel:
+ * @cc: operation context
+ *
+ * Uncancel a cancelled operation. If @cc is NULL then the current
+ * operation is uncancelled.
+ *
+ * This is useful, if e.g. you need to do some cleaning up where a
+ * cancellation lying around in the same thread will abort any
+ * processing.
+ **/
+void
+camel_operation_uncancel(CamelOperation *cc)
+{
+ if (cc == NULL)
+ cc = (CamelOperation *)pthread_getspecific(operation_key);
+
+ if (cc) {
+ CamelOperationMsg *msg;
+
+ LOCK();
+ while ((msg = (CamelOperationMsg *)e_msgport_get(cc->cancel_port)))
+ g_free(msg);
+
+ cc->flags &= ~CAMEL_OPERATION_CANCELLED;
+ UNLOCK();
+ }
+}
+
+/**
+ * camel_operation_register:
+ * @cc: operation context
+ *
+ * Register a thread or the main thread for cancellation through @cc.
+ * If @cc is NULL, then a new cancellation is created for this thread.
+ *
+ * All calls to operation_register() should save their value and call
+ * operation_register again with that, to automatically stack
+ * registrations.
+ *
+ * Return Value: Returns the previously registered operatoin.
+ *
+ **/
+CamelOperation *
+camel_operation_register (CamelOperation *cc)
+{
+ CamelOperation *oldcc = pthread_getspecific(operation_key);
+
+ pthread_setspecific(operation_key, cc);
+
+ return oldcc;
+}
+
+/**
+ * camel_operation_unregister:
+ * @cc: operation context
+ *
+ * Unregister the current thread for all cancellations.
+ **/
+void
+camel_operation_unregister (CamelOperation *cc)
+{
+ pthread_setspecific(operation_key, NULL);
+}
+
+/**
+ * camel_operation_cancel_check:
+ * @cc: operation context
+ *
+ * Check if cancellation has been applied to @cc. If @cc is NULL,
+ * then the CamelOperation registered for the current thread is used.
+ *
+ * Return value: TRUE if the operation has been cancelled.
+ **/
+gboolean
+camel_operation_cancel_check (CamelOperation *cc)
+{
+ CamelOperationMsg *msg;
+ int cancelled;
+
+ d(printf("checking for cancel in thread %d\n", pthread_self()));
+
+ if (cc == NULL)
+ cc = (CamelOperation *)pthread_getspecific(operation_key);
+
+ LOCK();
+
+ if (cc == NULL || cc->blocked > 0) {
+ d(printf("ahah! cancellation is blocked\n"));
+ cancelled = FALSE;
+ } else if (cc->flags & CAMEL_OPERATION_CANCELLED) {
+ d(printf("previously cancelled\n"));
+ cancelled = TRUE;
+ } else if ((msg = (CamelOperationMsg *)e_msgport_get(cc->cancel_port))) {
+ d(printf("Got cancellation message\n"));
+ do {
+ g_free(msg);
+ } while ((msg = (CamelOperationMsg *)e_msgport_get(cc->cancel_port)));
+ cc->flags |= CAMEL_OPERATION_CANCELLED;
+ cancelled = TRUE;
+ } else
+ cancelled = FALSE;
+
+ UNLOCK();
+
+ return cancelled;
+}
+
+/**
+ * camel_operation_cancel_fd:
+ * @cc: operation context
+ *
+ * Retrieve a file descriptor that can be waited on (select, or poll)
+ * for read, to asynchronously detect cancellation.
+ *
+ * Return value: The fd, or -1 if cancellation is not available
+ * (blocked, or has not been registered for this thread).
+ **/
+int
+camel_operation_cancel_fd (CamelOperation *cc)
+{
+ if (cc == NULL)
+ cc = (CamelOperation *)pthread_getspecific(operation_key);
+
+ if (cc == NULL || cc->blocked)
+ return -1;
+
+ LOCK();
+
+ if (cc->cancel_fd == -1)
+ cc->cancel_fd = e_msgport_fd(cc->cancel_port);
+
+ UNLOCK();
+
+ return cc->cancel_fd;
+}
+
+#ifdef HAVE_NSS
+/**
+ * camel_operation_cancel_prfd:
+ * @cc: operation context
+ *
+ * Retrieve a file descriptor that can be waited on (select, or poll)
+ * for read, to asynchronously detect cancellation.
+ *
+ * Return value: The fd, or NULL if cancellation is not available
+ * (blocked, or has not been registered for this thread).
+ **/
+PRFileDesc *
+camel_operation_cancel_prfd (CamelOperation *cc)
+{
+ if (cc == NULL)
+ cc = (CamelOperation *)pthread_getspecific(operation_key);
+
+ if (cc == NULL || cc->blocked)
+ return NULL;
+
+ LOCK();
+
+ if (cc->cancel_prfd == NULL)
+ cc->cancel_prfd = e_msgport_prfd(cc->cancel_port);
+
+ UNLOCK();
+
+ return cc->cancel_prfd;
+}
+#endif /* HAVE_NSS */
+
+/**
+ * camel_operation_start:
+ * @cc: operation context
+ * @what: action being performed (printf-style format string)
+ * @Varargs: varargs
+ *
+ * Report the start of an operation. All start operations should have
+ * similar end operations.
+ **/
+void
+camel_operation_start (CamelOperation *cc, char *what, ...)
+{
+ va_list ap;
+ char *msg;
+ struct _status_stack *s;
+
+ if (cc == NULL)
+ cc = (CamelOperation *)pthread_getspecific(operation_key);
+
+ if (cc == NULL)
+ return;
+
+ LOCK();
+
+ if (cc->status == NULL) {
+ UNLOCK();
+ return;
+ }
+
+ va_start(ap, what);
+ msg = g_strdup_vprintf(what, ap);
+ va_end(ap);
+ cc->status_update = 0;
+ s = g_malloc0(sizeof(*s));
+ s->msg = msg;
+ s->flags = 0;
+ cc->lastreport = s;
+ cc->status_stack = g_slist_prepend(cc->status_stack, s);
+
+ UNLOCK();
+
+ cc->status(cc, msg, CAMEL_OPERATION_START, cc->status_data);
+
+ d(printf("start '%s'\n", msg, pc));
+}
+
+/**
+ * camel_operation_start_transient:
+ * @cc: operation context
+ * @what: printf-style format string describing the action being performed
+ * @Varargs: varargs
+ *
+ * Start a transient event. We only update this to the display if it
+ * takes very long to process, and if we do, we then go back to the
+ * previous state when finished.
+ **/
+void
+camel_operation_start_transient (CamelOperation *cc, char *what, ...)
+{
+ va_list ap;
+ char *msg;
+ struct _status_stack *s;
+
+ if (cc == NULL)
+ cc = (CamelOperation *)pthread_getspecific(operation_key);
+
+ if (cc == NULL || cc->status == NULL)
+ return;
+
+ LOCK();
+
+ va_start(ap, what);
+ msg = g_strdup_vprintf(what, ap);
+ va_end(ap);
+ cc->status_update = 0;
+ s = g_malloc0(sizeof(*s));
+ s->msg = msg;
+ s->flags = CAMEL_OPERATION_TRANSIENT;
+ s->stamp = stamp();
+ cc->status_stack = g_slist_prepend(cc->status_stack, s);
+ d(printf("start '%s'\n", msg, pc));
+
+ UNLOCK();
+
+ /* we dont report it yet */
+ /*cc->status(cc, msg, CAMEL_OPERATION_START, cc->status_data);*/
+}
+
+static unsigned int stamp(void)
+{
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+ /* update 4 times/second */
+ return (tv.tv_sec * 4) + tv.tv_usec / (1000000/4);
+}
+
+/**
+ * camel_operation_progress:
+ * @cc: Operation to report to.
+ * @pc: Percent complete, 0 to 100.
+ *
+ * Report progress on the current operation. If @cc is NULL, then the
+ * currently registered operation is used. @pc reports the current
+ * percentage of completion, which should be in the range of 0 to 100.
+ *
+ * If the total percentage is not know, then use
+ * camel_operation_progress_count().
+ **/
+void
+camel_operation_progress (CamelOperation *cc, int pc)
+{
+ unsigned int now;
+ struct _status_stack *s;
+ char *msg = NULL;
+
+ if (cc == NULL)
+ cc = (CamelOperation *)pthread_getspecific(operation_key);
+
+ if (cc == NULL)
+ return;
+
+ LOCK();
+
+ if (cc->status == NULL || cc->status_stack == NULL) {
+ UNLOCK();
+ return;
+ }
+
+ s = cc->status_stack->data;
+ s->pc = pc;
+
+ /* Transient messages dont start updating till 4 seconds after
+ they started, then they update every second */
+ now = stamp();
+ if (cc->status_update == now) {
+ cc = NULL;
+ } else if (s->flags & CAMEL_OPERATION_TRANSIENT) {
+ if (s->stamp + CAMEL_OPERATION_TRANSIENT_DELAY > now) {
+ cc = NULL;
+ } else {
+ cc->status_update = now;
+ cc->lastreport = s;
+ msg = g_strdup(s->msg);
+ }
+ } else {
+ s->stamp = cc->status_update = now;
+ cc->lastreport = s;
+ msg = g_strdup(s->msg);
+ }
+
+ UNLOCK();
+
+ if (cc) {
+ cc->status(cc, msg, pc, cc->status_data);
+ g_free(msg);
+ }
+}
+
+/**
+ * camel_operation_progress_count:
+ * @cc: operation context
+ * @sofar:
+ *
+ **/
+void
+camel_operation_progress_count (CamelOperation *cc, int sofar)
+{
+ camel_operation_progress(cc, sofar);
+}
+
+/**
+ * camel_operation_end:
+ * @cc: operation context
+ * @what: Format string.
+ * @Varargs: varargs
+ *
+ * Report the end of an operation. If @cc is NULL, then the currently
+ * registered operation is notified.
+ **/
+void
+camel_operation_end (CamelOperation *cc)
+{
+ struct _status_stack *s, *p;
+ unsigned int now;
+ char *msg = NULL;
+ int pc = 0;
+
+ if (cc == NULL)
+ cc = (CamelOperation *)pthread_getspecific(operation_key);
+
+ if (cc == NULL)
+ return;
+
+ LOCK();
+
+ if (cc->status == NULL || cc->status_stack == NULL) {
+ UNLOCK();
+ return;
+ }
+
+ /* so what we do here is this. If the operation that just
+ * ended was transient, see if we have any other transient
+ * messages that haven't been updated yet above us, otherwise,
+ * re-update as a non-transient at the last reported pc */
+ now = stamp();
+ s = cc->status_stack->data;
+ if (s->flags & CAMEL_OPERATION_TRANSIENT) {
+ if (cc->lastreport == s) {
+ GSList *l = cc->status_stack->next;
+ while (l) {
+ p = l->data;
+ if (p->flags & CAMEL_OPERATION_TRANSIENT) {
+ if (p->stamp + CAMEL_OPERATION_TRANSIENT_DELAY < now) {
+ msg = g_strdup(p->msg);
+ pc = p->pc;
+ cc->lastreport = p;
+ break;
+ }
+ } else {
+ msg = g_strdup(p->msg);
+ pc = p->pc;
+ cc->lastreport = p;
+ break;
+ }
+ l = l->next;
+ }
+ }
+ g_free(s->msg);
+ } else {
+ msg = s->msg;
+ pc = CAMEL_OPERATION_END;
+ cc->lastreport = s;
+ }
+ g_free(s);
+ cc->status_stack = g_slist_remove_link(cc->status_stack, cc->status_stack);
+
+ UNLOCK();
+
+ if (msg) {
+ cc->status(cc, msg, pc, cc->status_data);
+ g_free(msg);
+ }
+}
diff --git a/camel/camel-sasl-digest-md5.c b/camel/camel-sasl-digest-md5.c
new file mode 100644
index 0000000000..47b3339520
--- /dev/null
+++ b/camel/camel-sasl-digest-md5.c
@@ -0,0 +1,906 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Jeffrey Stedfast <fejj@ximian.com>
+ *
+ * Copyright 2001-2003 Ximian, Inc. (www.ximian.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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+
+#include <e-util/md5-utils.h>
+
+#include <gal/util/e-iconv.h>
+
+#include "camel-charset-map.h"
+#include "camel-mime-utils.h"
+#include "camel-sasl-digest-md5.h"
+
+#define d(x)
+
+#define PARANOID(x) x
+
+/* Implements rfc2831 */
+
+CamelServiceAuthType camel_sasl_digest_md5_authtype = {
+ N_("DIGEST-MD5"),
+
+ N_("This option will connect to the server using a "
+ "secure DIGEST-MD5 password, if the server supports it."),
+
+ "DIGEST-MD5",
+ TRUE
+};
+
+static CamelSaslClass *parent_class = NULL;
+
+/* Returns the class for a CamelSaslDigestMd5 */
+#define CSCM_CLASS(so) CAMEL_SASL_DIGEST_MD5_CLASS (CAMEL_OBJECT_GET_CLASS (so))
+
+static GByteArray *digest_md5_challenge (CamelSasl *sasl, GByteArray *token, CamelException *ex);
+
+enum {
+ STATE_AUTH,
+ STATE_FINAL
+};
+
+typedef struct {
+ char *name;
+ guint type;
+} DataType;
+
+enum {
+ DIGEST_REALM,
+ DIGEST_NONCE,
+ DIGEST_QOP,
+ DIGEST_STALE,
+ DIGEST_MAXBUF,
+ DIGEST_CHARSET,
+ DIGEST_ALGORITHM,
+ DIGEST_CIPHER,
+ DIGEST_UNKNOWN
+};
+
+static DataType digest_args[] = {
+ { "realm", DIGEST_REALM },
+ { "nonce", DIGEST_NONCE },
+ { "qop", DIGEST_QOP },
+ { "stale", DIGEST_STALE },
+ { "maxbuf", DIGEST_MAXBUF },
+ { "charset", DIGEST_CHARSET },
+ { "algorithm", DIGEST_ALGORITHM },
+ { "cipher", DIGEST_CIPHER },
+ { NULL, DIGEST_UNKNOWN }
+};
+
+#define QOP_AUTH (1<<0)
+#define QOP_AUTH_INT (1<<1)
+#define QOP_AUTH_CONF (1<<2)
+#define QOP_INVALID (1<<3)
+
+static DataType qop_types[] = {
+ { "auth", QOP_AUTH },
+ { "auth-int", QOP_AUTH_INT },
+ { "auth-conf", QOP_AUTH_CONF },
+ { NULL, QOP_INVALID }
+};
+
+#define CIPHER_DES (1<<0)
+#define CIPHER_3DES (1<<1)
+#define CIPHER_RC4 (1<<2)
+#define CIPHER_RC4_40 (1<<3)
+#define CIPHER_RC4_56 (1<<4)
+#define CIPHER_INVALID (1<<5)
+
+static DataType cipher_types[] = {
+ { "des", CIPHER_DES },
+ { "3des", CIPHER_3DES },
+ { "rc4", CIPHER_RC4 },
+ { "rc4-40", CIPHER_RC4_40 },
+ { "rc4-56", CIPHER_RC4_56 },
+ { NULL, CIPHER_INVALID }
+};
+
+struct _param {
+ char *name;
+ char *value;
+};
+
+struct _DigestChallenge {
+ GPtrArray *realms;
+ char *nonce;
+ guint qop;
+ gboolean stale;
+ gint32 maxbuf;
+ char *charset;
+ char *algorithm;
+ guint cipher;
+ GList *params;
+};
+
+struct _DigestURI {
+ char *type;
+ char *host;
+ char *name;
+};
+
+struct _DigestResponse {
+ char *username;
+ char *realm;
+ char *nonce;
+ char *cnonce;
+ char nc[9];
+ guint qop;
+ struct _DigestURI *uri;
+ char resp[33];
+ guint32 maxbuf;
+ char *charset;
+ guint cipher;
+ char *authzid;
+ char *param;
+};
+
+struct _CamelSaslDigestMd5Private {
+ struct _DigestChallenge *challenge;
+ struct _DigestResponse *response;
+ int state;
+};
+
+static void
+camel_sasl_digest_md5_class_init (CamelSaslDigestMd5Class *camel_sasl_digest_md5_class)
+{
+ CamelSaslClass *camel_sasl_class = CAMEL_SASL_CLASS (camel_sasl_digest_md5_class);
+
+ parent_class = CAMEL_SASL_CLASS (camel_type_get_global_classfuncs (camel_sasl_get_type ()));
+
+ /* virtual method overload */
+ camel_sasl_class->challenge = digest_md5_challenge;
+}
+
+static void
+camel_sasl_digest_md5_init (gpointer object, gpointer klass)
+{
+ CamelSaslDigestMd5 *sasl_digest = CAMEL_SASL_DIGEST_MD5 (object);
+
+ sasl_digest->priv = g_new0 (struct _CamelSaslDigestMd5Private, 1);
+}
+
+static void
+camel_sasl_digest_md5_finalize (CamelObject *object)
+{
+ CamelSaslDigestMd5 *sasl = CAMEL_SASL_DIGEST_MD5 (object);
+ struct _DigestChallenge *c = sasl->priv->challenge;
+ struct _DigestResponse *r = sasl->priv->response;
+ GList *p;
+ int i;
+
+ for (i = 0; i < c->realms->len; i++)
+ g_free (c->realms->pdata[i]);
+ g_ptr_array_free (c->realms, TRUE);
+ g_free (c->nonce);
+ g_free (c->charset);
+ g_free (c->algorithm);
+ for (p = c->params; p; p = p->next) {
+ struct _param *param = p->data;
+
+ g_free (param->name);
+ g_free (param->value);
+ g_free (param);
+ }
+ g_list_free (c->params);
+ g_free (c);
+
+ g_free (r->username);
+ g_free (r->realm);
+ g_free (r->nonce);
+ g_free (r->cnonce);
+ if (r->uri) {
+ g_free (r->uri->type);
+ g_free (r->uri->host);
+ g_free (r->uri->name);
+ }
+ g_free (r->charset);
+ g_free (r->authzid);
+ g_free (r->param);
+ g_free (r);
+
+ g_free (sasl->priv);
+}
+
+
+CamelType
+camel_sasl_digest_md5_get_type (void)
+{
+ static CamelType type = CAMEL_INVALID_TYPE;
+
+ if (type == CAMEL_INVALID_TYPE) {
+ type = camel_type_register (camel_sasl_get_type (),
+ "CamelSaslDigestMd5",
+ sizeof (CamelSaslDigestMd5),
+ sizeof (CamelSaslDigestMd5Class),
+ (CamelObjectClassInitFunc) camel_sasl_digest_md5_class_init,
+ NULL,
+ (CamelObjectInitFunc) camel_sasl_digest_md5_init,
+ (CamelObjectFinalizeFunc) camel_sasl_digest_md5_finalize);
+ }
+
+ return type;
+}
+
+static void
+decode_lwsp (const char **in)
+{
+ const char *inptr = *in;
+
+ while (isspace (*inptr))
+ inptr++;
+
+ *in = inptr;
+}
+
+static char *
+decode_quoted_string (const char **in)
+{
+ const char *inptr = *in;
+ char *out = NULL, *outptr;
+ int outlen;
+ int c;
+
+ decode_lwsp (&inptr);
+ if (*inptr == '"') {
+ const char *intmp;
+ int skip = 0;
+
+ /* first, calc length */
+ inptr++;
+ intmp = inptr;
+ while ((c = *intmp++) && c != '"') {
+ if (c == '\\' && *intmp) {
+ intmp++;
+ skip++;
+ }
+ }
+
+ outlen = intmp - inptr - skip;
+ out = outptr = g_malloc (outlen + 1);
+
+ while ((c = *inptr++) && c != '"') {
+ if (c == '\\' && *inptr) {
+ c = *inptr++;
+ }
+ *outptr++ = c;
+ }
+ *outptr = '\0';
+ }
+
+ *in = inptr;
+
+ return out;
+}
+
+static char *
+decode_token (const char **in)
+{
+ const char *inptr = *in;
+ const char *start;
+
+ decode_lwsp (&inptr);
+ start = inptr;
+
+ while (*inptr && *inptr != '=' && *inptr != ',')
+ inptr++;
+
+ if (inptr > start) {
+ *in = inptr;
+ return g_strndup (start, inptr - start);
+ } else {
+ return NULL;
+ }
+}
+
+static char *
+decode_value (const char **in)
+{
+ const char *inptr = *in;
+
+ decode_lwsp (&inptr);
+ if (*inptr == '"') {
+ d(printf ("decoding quoted string token\n"));
+ return decode_quoted_string (in);
+ } else {
+ d(printf ("decoding string token\n"));
+ return decode_token (in);
+ }
+}
+
+static GList *
+parse_param_list (const char *tokens)
+{
+ GList *params = NULL;
+ struct _param *param;
+ const char *ptr;
+
+ for (ptr = tokens; ptr && *ptr; ) {
+ param = g_new0 (struct _param, 1);
+ param->name = decode_token (&ptr);
+ if (*ptr == '=') {
+ ptr++;
+ param->value = decode_value (&ptr);
+ }
+
+ params = g_list_prepend (params, param);
+
+ if (*ptr == ',')
+ ptr++;
+ }
+
+ return params;
+}
+
+static guint
+decode_data_type (DataType *dtype, const char *name)
+{
+ int i;
+
+ for (i = 0; dtype[i].name; i++) {
+ if (!g_ascii_strcasecmp (dtype[i].name, name))
+ break;
+ }
+
+ return dtype[i].type;
+}
+
+#define get_digest_arg(name) decode_data_type (digest_args, name)
+#define decode_qop(name) decode_data_type (qop_types, name)
+#define decode_cipher(name) decode_data_type (cipher_types, name)
+
+static const char *
+type_to_string (DataType *dtype, guint type)
+{
+ int i;
+
+ for (i = 0; dtype[i].name; i++) {
+ if (dtype[i].type == type)
+ break;
+ }
+
+ return dtype[i].name;
+}
+
+#define qop_to_string(type) type_to_string (qop_types, type)
+#define cipher_to_string(type) type_to_string (cipher_types, type)
+
+static void
+digest_abort (gboolean *have_type, gboolean *abort)
+{
+ if (*have_type)
+ *abort = TRUE;
+ *have_type = TRUE;
+}
+
+static struct _DigestChallenge *
+parse_server_challenge (const char *tokens, gboolean *abort)
+{
+ struct _DigestChallenge *challenge = NULL;
+ GList *params, *p;
+ const char *ptr;
+#ifdef PARANOID
+ gboolean got_algorithm = FALSE;
+ gboolean got_stale = FALSE;
+ gboolean got_maxbuf = FALSE;
+ gboolean got_charset = FALSE;
+#endif /* PARANOID */
+
+ params = parse_param_list (tokens);
+ if (!params) {
+ *abort = TRUE;
+ return NULL;
+ }
+
+ *abort = FALSE;
+
+ challenge = g_new0 (struct _DigestChallenge, 1);
+ challenge->realms = g_ptr_array_new ();
+ challenge->maxbuf = 65536;
+
+ for (p = params; p; p = p->next) {
+ struct _param *param = p->data;
+ int type;
+
+ type = get_digest_arg (param->name);
+ switch (type) {
+ case DIGEST_REALM:
+ for (ptr = param->value; ptr && *ptr; ) {
+ char *token;
+
+ token = decode_token (&ptr);
+ if (token)
+ g_ptr_array_add (challenge->realms, token);
+
+ if (*ptr == ',')
+ ptr++;
+ }
+ g_free (param->value);
+ g_free (param->name);
+ g_free (param);
+ break;
+ case DIGEST_NONCE:
+ g_free (challenge->nonce);
+ challenge->nonce = param->value;
+ g_free (param->name);
+ g_free (param);
+ break;
+ case DIGEST_QOP:
+ for (ptr = param->value; ptr && *ptr; ) {
+ char *token;
+
+ token = decode_token (&ptr);
+ if (token)
+ challenge->qop |= decode_qop (token);
+
+ if (*ptr == ',')
+ ptr++;
+ }
+
+ if (challenge->qop & QOP_INVALID)
+ challenge->qop = QOP_INVALID;
+ g_free (param->value);
+ g_free (param->name);
+ g_free (param);
+ break;
+ case DIGEST_STALE:
+ PARANOID (digest_abort (&got_stale, abort));
+ if (!g_ascii_strcasecmp (param->value, "true"))
+ challenge->stale = TRUE;
+ else
+ challenge->stale = FALSE;
+ g_free (param->value);
+ g_free (param->name);
+ g_free (param);
+ break;
+ case DIGEST_MAXBUF:
+ PARANOID (digest_abort (&got_maxbuf, abort));
+ challenge->maxbuf = atoi (param->value);
+ g_free (param->value);
+ g_free (param->name);
+ g_free (param);
+ break;
+ case DIGEST_CHARSET:
+ PARANOID (digest_abort (&got_charset, abort));
+ g_free (challenge->charset);
+ if (param->value && *param->value)
+ challenge->charset = param->value;
+ else
+ challenge->charset = NULL;
+ g_free (param->name);
+ g_free (param);
+ break;
+ case DIGEST_ALGORITHM:
+ PARANOID (digest_abort (&got_algorithm, abort));
+ g_free (challenge->algorithm);
+ challenge->algorithm = param->value;
+ g_free (param->name);
+ g_free (param);
+ break;
+ case DIGEST_CIPHER:
+ for (ptr = param->value; ptr && *ptr; ) {
+ char *token;
+
+ token = decode_token (&ptr);
+ if (token)
+ challenge->cipher |= decode_cipher (token);
+
+ if (*ptr == ',')
+ ptr++;
+ }
+ if (challenge->cipher & CIPHER_INVALID)
+ challenge->cipher = CIPHER_INVALID;
+ g_free (param->value);
+ g_free (param->name);
+ g_free (param);
+ break;
+ default:
+ challenge->params = g_list_prepend (challenge->params, param);
+ break;
+ }
+ }
+
+ g_list_free (params);
+
+ return challenge;
+}
+
+static void
+digest_hex (guchar *digest, guchar hex[33])
+{
+ guchar *s, *p;
+
+ /* lowercase hexify that bad-boy... */
+ for (s = digest, p = hex; p < hex + 32; s++, p += 2)
+ sprintf (p, "%.2x", *s);
+}
+
+static char *
+digest_uri_to_string (struct _DigestURI *uri)
+{
+ if (uri->name)
+ return g_strdup_printf ("%s/%s/%s", uri->type, uri->host, uri->name);
+ else
+ return g_strdup_printf ("%s/%s", uri->type, uri->host);
+}
+
+static void
+compute_response (struct _DigestResponse *resp, const char *passwd, gboolean client, guchar out[33])
+{
+ guchar hex_a1[33], hex_a2[33];
+ guchar digest[16];
+ MD5Context ctx;
+ char *buf;
+
+ /* compute A1 */
+ md5_init (&ctx);
+ md5_update (&ctx, resp->username, strlen (resp->username));
+ md5_update (&ctx, ":", 1);
+ md5_update (&ctx, resp->realm, strlen (resp->realm));
+ md5_update (&ctx, ":", 1);
+ md5_update (&ctx, passwd, strlen (passwd));
+ md5_final (&ctx, digest);
+
+ md5_init (&ctx);
+ md5_update (&ctx, digest, 16);
+ md5_update (&ctx, ":", 1);
+ md5_update (&ctx, resp->nonce, strlen (resp->nonce));
+ md5_update (&ctx, ":", 1);
+ md5_update (&ctx, resp->cnonce, strlen (resp->cnonce));
+ if (resp->authzid) {
+ md5_update (&ctx, ":", 1);
+ md5_update (&ctx, resp->authzid, strlen (resp->authzid));
+ }
+
+ /* hexify A1 */
+ md5_final (&ctx, digest);
+ digest_hex (digest, hex_a1);
+
+ /* compute A2 */
+ md5_init (&ctx);
+ if (client) {
+ /* we are calculating the client response */
+ md5_update (&ctx, "AUTHENTICATE:", strlen ("AUTHENTICATE:"));
+ } else {
+ /* we are calculating the server rspauth */
+ md5_update (&ctx, ":", 1);
+ }
+
+ buf = digest_uri_to_string (resp->uri);
+ md5_update (&ctx, buf, strlen (buf));
+ g_free (buf);
+
+ if (resp->qop == QOP_AUTH_INT || resp->qop == QOP_AUTH_CONF)
+ md5_update (&ctx, ":00000000000000000000000000000000", 33);
+
+ /* now hexify A2 */
+ md5_final (&ctx, digest);
+ digest_hex (digest, hex_a2);
+
+ /* compute KD */
+ md5_init (&ctx);
+ md5_update (&ctx, hex_a1, 32);
+ md5_update (&ctx, ":", 1);
+ md5_update (&ctx, resp->nonce, strlen (resp->nonce));
+ md5_update (&ctx, ":", 1);
+ md5_update (&ctx, resp->nc, 8);
+ md5_update (&ctx, ":", 1);
+ md5_update (&ctx, resp->cnonce, strlen (resp->cnonce));
+ md5_update (&ctx, ":", 1);
+ md5_update (&ctx, qop_to_string (resp->qop), strlen (qop_to_string (resp->qop)));
+ md5_update (&ctx, ":", 1);
+ md5_update (&ctx, hex_a2, 32);
+ md5_final (&ctx, digest);
+
+ digest_hex (digest, out);
+}
+
+static struct _DigestResponse *
+generate_response (struct _DigestChallenge *challenge, const char *host,
+ const char *protocol, const char *user, const char *passwd)
+{
+ struct _DigestResponse *resp;
+ struct _DigestURI *uri;
+ char *bgen, digest[16];
+
+ resp = g_new0 (struct _DigestResponse, 1);
+ resp->username = g_strdup (user);
+ /* FIXME: we should use the preferred realm */
+ if (challenge->realms && challenge->realms->len > 0)
+ resp->realm = g_strdup (challenge->realms->pdata[0]);
+ else
+ resp->realm = g_strdup ("");
+
+ resp->nonce = g_strdup (challenge->nonce);
+
+ /* generate the cnonce */
+ bgen = g_strdup_printf ("%p:%lu:%lu", resp,
+ (unsigned long) getpid (),
+ (unsigned long) time (0));
+ md5_get_digest (bgen, strlen (bgen), digest);
+ g_free (bgen);
+ /* take our recommended 64 bits of entropy */
+ resp->cnonce = camel_base64_encode_simple (digest, 8);
+
+ /* we don't support re-auth so the nonce count is always 1 */
+ strcpy (resp->nc, "00000001");
+
+ /* choose the QOP */
+ /* FIXME: choose - probably choose "auth" ??? */
+ resp->qop = QOP_AUTH;
+
+ /* create the URI */
+ uri = g_new0 (struct _DigestURI, 1);
+ uri->type = g_strdup (protocol);
+ uri->host = g_strdup (host);
+ uri->name = NULL;
+ resp->uri = uri;
+
+ /* charsets... yay */
+ if (challenge->charset) {
+ /* I believe that this is only ever allowed to be
+ * UTF-8. We strdup the charset specified by the
+ * challenge anyway, just in case it's not UTF-8.
+ */
+ resp->charset = g_strdup (challenge->charset);
+ }
+
+ resp->cipher = CIPHER_INVALID;
+ if (resp->qop == QOP_AUTH_CONF) {
+ /* FIXME: choose a cipher? */
+ resp->cipher = CIPHER_INVALID;
+ }
+
+ /* we don't really care about this... */
+ resp->authzid = NULL;
+
+ compute_response (resp, passwd, TRUE, resp->resp);
+
+ return resp;
+}
+
+static GByteArray *
+digest_response (struct _DigestResponse *resp)
+{
+ GByteArray *buffer;
+ const char *str;
+ char *buf;
+
+ buffer = g_byte_array_new ();
+ g_byte_array_append (buffer, "username=\"", 10);
+ if (resp->charset) {
+ /* Encode the username using the requested charset */
+ char *username, *outbuf;
+ const char *charset;
+ size_t len, outlen;
+ const char *inbuf;
+ iconv_t cd;
+
+ charset = e_iconv_locale_charset ();
+ if (!charset)
+ charset = "iso-8859-1";
+
+ cd = e_iconv_open (resp->charset, charset);
+
+ len = strlen (resp->username);
+ outlen = 2 * len; /* plenty of space */
+
+ outbuf = username = g_malloc0 (outlen + 1);
+ inbuf = resp->username;
+ if (cd == (iconv_t) -1 || e_iconv (cd, &inbuf, &len, &outbuf, &outlen) == (size_t) -1) {
+ /* We can't convert to UTF-8 - pretend we never got a charset param? */
+ g_free (resp->charset);
+ resp->charset = NULL;
+
+ /* Set the username to the non-UTF-8 version */
+ g_free (username);
+ username = g_strdup (resp->username);
+ }
+
+ if (cd != (iconv_t) -1)
+ e_iconv_close (cd);
+
+ g_byte_array_append (buffer, username, strlen (username));
+ g_free (username);
+ } else {
+ g_byte_array_append (buffer, resp->username, strlen (resp->username));
+ }
+
+ g_byte_array_append (buffer, "\",realm=\"", 9);
+ g_byte_array_append (buffer, resp->realm, strlen (resp->realm));
+
+ g_byte_array_append (buffer, "\",nonce=\"", 9);
+ g_byte_array_append (buffer, resp->nonce, strlen (resp->nonce));
+
+ g_byte_array_append (buffer, "\",cnonce=\"", 10);
+ g_byte_array_append (buffer, resp->cnonce, strlen (resp->cnonce));
+
+ g_byte_array_append (buffer, "\",nc=", 5);
+ g_byte_array_append (buffer, resp->nc, 8);
+
+ g_byte_array_append (buffer, ",qop=", 5);
+ str = qop_to_string (resp->qop);
+ g_byte_array_append (buffer, str, strlen (str));
+
+ g_byte_array_append (buffer, ",digest-uri=\"", 13);
+ buf = digest_uri_to_string (resp->uri);
+ g_byte_array_append (buffer, buf, strlen (buf));
+ g_free (buf);
+
+ g_byte_array_append (buffer, "\",response=", 11);
+ g_byte_array_append (buffer, resp->resp, 32);
+
+ if (resp->maxbuf > 0) {
+ g_byte_array_append (buffer, ",maxbuf=", 8);
+ buf = g_strdup_printf ("%d", resp->maxbuf);
+ g_byte_array_append (buffer, buf, strlen (buf));
+ g_free (buf);
+ }
+
+ if (resp->charset) {
+ g_byte_array_append (buffer, ",charset=", 9);
+ g_byte_array_append (buffer, resp->charset, strlen (resp->charset));
+ }
+
+ if (resp->cipher != CIPHER_INVALID) {
+ str = cipher_to_string (resp->cipher);
+ if (str) {
+ g_byte_array_append (buffer, ",cipher=\"", 9);
+ g_byte_array_append (buffer, str, strlen (str));
+ g_byte_array_append (buffer, "\"", 1);
+ }
+ }
+
+ if (resp->authzid) {
+ g_byte_array_append (buffer, ",authzid=\"", 10);
+ g_byte_array_append (buffer, resp->authzid, strlen (resp->authzid));
+ g_byte_array_append (buffer, "\"", 1);
+ }
+
+ return buffer;
+}
+
+static GByteArray *
+digest_md5_challenge (CamelSasl *sasl, GByteArray *token, CamelException *ex)
+{
+ CamelSaslDigestMd5 *sasl_digest = CAMEL_SASL_DIGEST_MD5 (sasl);
+ struct _CamelSaslDigestMd5Private *priv = sasl_digest->priv;
+ struct _param *rspauth;
+ GByteArray *ret = NULL;
+ gboolean abort = FALSE;
+ const char *ptr;
+ guchar out[33];
+ char *tokens;
+ struct addrinfo *ai, hints;
+
+ /* Need to wait for the server */
+ if (!token)
+ return NULL;
+
+ g_return_val_if_fail (sasl->service->url->passwd != NULL, NULL);
+
+ switch (priv->state) {
+ case STATE_AUTH:
+ if (token->len > 2048) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
+ _("Server challenge too long (>2048 octets)\n"));
+ return NULL;
+ }
+
+ tokens = g_strndup (token->data, token->len);
+ priv->challenge = parse_server_challenge (tokens, &abort);
+ g_free (tokens);
+ if (!priv->challenge || abort) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
+ _("Server challenge invalid\n"));
+ return NULL;
+ }
+
+ if (priv->challenge->qop == QOP_INVALID) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
+ _("Server challenge contained invalid "
+ "\"Quality of Protection\" token\n"));
+ return NULL;
+ }
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_CANONNAME;
+ ai = camel_getaddrinfo(sasl->service->url->host?sasl->service->url->host:"localhost", NULL, &hints, NULL);
+ if (ai && ai->ai_canonname)
+ ptr = ai->ai_canonname;
+ else
+ ptr = "localhost.localdomain";
+
+ priv->response = generate_response (priv->challenge, ptr, sasl->service_name,
+ sasl->service->url->user,
+ sasl->service->url->passwd);
+ if (ai)
+ camel_freeaddrinfo(ai);
+ ret = digest_response (priv->response);
+
+ break;
+ case STATE_FINAL:
+ if (token->len)
+ tokens = g_strndup (token->data, token->len);
+ else
+ tokens = NULL;
+
+ if (!tokens || !*tokens) {
+ g_free (tokens);
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
+ _("Server response did not contain authorization data\n"));
+ return NULL;
+ }
+
+ rspauth = g_new0 (struct _param, 1);
+
+ ptr = tokens;
+ rspauth->name = decode_token (&ptr);
+ if (*ptr == '=') {
+ ptr++;
+ rspauth->value = decode_value (&ptr);
+ }
+ g_free (tokens);
+
+ if (!rspauth->value) {
+ g_free (rspauth->name);
+ g_free (rspauth);
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
+ _("Server response contained incomplete authorization data\n"));
+ return NULL;
+ }
+
+ compute_response (priv->response, sasl->service->url->passwd, FALSE, out);
+ if (memcmp (out, rspauth->value, 32) != 0) {
+ g_free (rspauth->name);
+ g_free (rspauth->value);
+ g_free (rspauth);
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
+ _("Server response does not match\n"));
+ sasl->authenticated = TRUE;
+
+ return NULL;
+ }
+
+ g_free (rspauth->name);
+ g_free (rspauth->value);
+ g_free (rspauth);
+
+ ret = g_byte_array_new ();
+
+ sasl->authenticated = TRUE;
+ default:
+ break;
+ }
+
+ priv->state++;
+
+ return ret;
+}
diff --git a/camel/camel-sasl-gssapi.c b/camel/camel-sasl-gssapi.c
new file mode 100644
index 0000000000..1efbefee16
--- /dev/null
+++ b/camel/camel-sasl-gssapi.c
@@ -0,0 +1,346 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Jeffrey Stedfast <fejj@ximian.com>
+ *
+ * Copyright 2003 Ximian, Inc. (www.ximian.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_KRB5
+
+#include <string.h>
+#ifdef HAVE_ET_COM_ERR_H
+#include <et/com_err.h>
+#else
+#include <com_err.h>
+#endif
+#ifdef HAVE_MIT_KRB5
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_generic.h>
+#else /* HAVE_HEIMDAL_KRB5 */
+#include <gssapi.h>
+#define gss_nt_service_name GSS_C_NT_HOSTBASED_SERVICE
+#endif
+#include <errno.h>
+
+#ifndef GSS_C_OID_KRBV5_DES
+#define GSS_C_OID_KRBV5_DES GSS_C_NO_OID
+#endif
+
+#include "camel-sasl-gssapi.h"
+
+CamelServiceAuthType camel_sasl_gssapi_authtype = {
+ N_("GSSAPI"),
+
+ N_("This option will connect to the server using "
+ "Kerberos 5 authentication."),
+
+ "GSSAPI",
+ FALSE
+};
+
+enum {
+ GSSAPI_STATE_INIT,
+ GSSAPI_STATE_CONTINUE_NEEDED,
+ GSSAPI_STATE_COMPLETE,
+ GSSAPI_STATE_AUTHENTICATED
+};
+
+#define GSSAPI_SECURITY_LAYER_NONE (1 << 0)
+#define GSSAPI_SECURITY_LAYER_INTEGRITY (1 << 1)
+#define GSSAPI_SECURITY_LAYER_PRIVACY (1 << 2)
+
+#define DESIRED_SECURITY_LAYER GSSAPI_SECURITY_LAYER_NONE
+
+struct _CamelSaslGssapiPrivate {
+ int state;
+ gss_ctx_id_t ctx;
+ gss_name_t target;
+};
+
+
+static GByteArray *gssapi_challenge (CamelSasl *sasl, GByteArray *token, CamelException *ex);
+
+
+static CamelSaslClass *parent_class = NULL;
+
+
+static void
+camel_sasl_gssapi_class_init (CamelSaslGssapiClass *klass)
+{
+ CamelSaslClass *camel_sasl_class = CAMEL_SASL_CLASS (klass);
+
+ parent_class = CAMEL_SASL_CLASS (camel_type_get_global_classfuncs (camel_sasl_get_type ()));
+
+ /* virtual method overload */
+ camel_sasl_class->challenge = gssapi_challenge;
+}
+
+static void
+camel_sasl_gssapi_init (gpointer object, gpointer klass)
+{
+ CamelSaslGssapi *gssapi = CAMEL_SASL_GSSAPI (object);
+
+ gssapi->priv = g_new (struct _CamelSaslGssapiPrivate, 1);
+ gssapi->priv->state = GSSAPI_STATE_INIT;
+ gssapi->priv->ctx = GSS_C_NO_CONTEXT;
+ gssapi->priv->target = GSS_C_NO_NAME;
+}
+
+static void
+camel_sasl_gssapi_finalize (CamelObject *object)
+{
+ CamelSaslGssapi *gssapi = CAMEL_SASL_GSSAPI (object);
+ guint32 status;
+
+ if (gssapi->priv->ctx != GSS_C_NO_CONTEXT)
+ gss_delete_sec_context (&status, &gssapi->priv->ctx, GSS_C_NO_BUFFER);
+
+ if (gssapi->priv->target != GSS_C_NO_NAME)
+ gss_release_name (&status, &gssapi->priv->target);
+
+ g_free (gssapi->priv);
+}
+
+
+CamelType
+camel_sasl_gssapi_get_type (void)
+{
+ static CamelType type = CAMEL_INVALID_TYPE;
+
+ if (type == CAMEL_INVALID_TYPE) {
+ type = camel_type_register (
+ camel_sasl_get_type (),
+ "CamelSaslGssapi",
+ sizeof (CamelSaslGssapi),
+ sizeof (CamelSaslGssapiClass),
+ (CamelObjectClassInitFunc) camel_sasl_gssapi_class_init,
+ NULL,
+ (CamelObjectInitFunc) camel_sasl_gssapi_init,
+ (CamelObjectFinalizeFunc) camel_sasl_gssapi_finalize);
+ }
+
+ return type;
+}
+
+static void
+gssapi_set_exception (OM_uint32 major, OM_uint32 minor, CamelException *ex)
+{
+ const char *str;
+
+ switch (major) {
+ case GSS_S_BAD_MECH:
+ str = _("The specified mechanism is not supported by the "
+ "provided credential, or is unrecognized by the "
+ "implementation.");
+ break;
+ case GSS_S_BAD_NAME:
+ str = _("The provided target_name parameter was ill-formed.");
+ break;
+ case GSS_S_BAD_NAMETYPE:
+ str = _("The provided target_name parameter contained an "
+ "invalid or unsupported type of name.");
+ break;
+ case GSS_S_BAD_BINDINGS:
+ str = _("The input_token contains different channel "
+ "bindings to those specified via the "
+ "input_chan_bindings parameter.");
+ break;
+ case GSS_S_BAD_SIG:
+ str = _("The input_token contains an invalid signature, or a "
+ "signature that could not be verified.");
+ break;
+ case GSS_S_NO_CRED:
+ str = _("The supplied credentials were not valid for context "
+ "initiation, or the credential handle did not "
+ "reference any credentials.");
+ break;
+ case GSS_S_NO_CONTEXT:
+ str = _("The supplied context handle did not refer to a valid context.");
+ break;
+ case GSS_S_DEFECTIVE_TOKEN:
+ str = _("The consistency checks performed on the input_token failed.");
+ break;
+ case GSS_S_DEFECTIVE_CREDENTIAL:
+ str = _("The consistency checks performed on the credential failed.");
+ break;
+ case GSS_S_CREDENTIALS_EXPIRED:
+ str = _("The referenced credentials have expired.");
+ break;
+ case GSS_S_FAILURE:
+ str = error_message (minor);
+ break;
+ default:
+ str = _("Bad authentication response from server.");
+ }
+
+ camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE, str);
+}
+
+static GByteArray *
+gssapi_challenge (CamelSasl *sasl, GByteArray *token, CamelException *ex)
+{
+ struct _CamelSaslGssapiPrivate *priv = CAMEL_SASL_GSSAPI (sasl)->priv;
+ OM_uint32 major, minor, flags, time;
+ gss_buffer_desc inbuf, outbuf;
+ GByteArray *challenge = NULL;
+ gss_buffer_t input_token;
+ struct hostent *h;
+ int conf_state;
+ gss_qop_t qop;
+ gss_OID mech;
+ char *str;
+ struct addrinfo *ai, hints;
+
+ switch (priv->state) {
+ case GSSAPI_STATE_INIT:
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_CANONNAME;
+ ai = camel_getaddrinfo(sasl->service->url->host?sasl->service->url->host:"localhost", NULL, &hints, ex);
+ if (ai == NULL)
+ return NULL;
+
+ str = g_strdup_printf("%s@%s", sasl->service_name, ai->ai_canonname);
+ camel_freeaddrinfo(ai);
+
+ inbuf.value = str;
+ inbuf.length = strlen (str);
+ major = gss_import_name (&minor, &inbuf, gss_nt_service_name, &priv->target);
+ g_free (str);
+
+ if (major != GSS_S_COMPLETE) {
+ gssapi_set_exception (major, minor, ex);
+ return NULL;
+ }
+
+ input_token = GSS_C_NO_BUFFER;
+
+ goto challenge;
+ break;
+ case GSSAPI_STATE_CONTINUE_NEEDED:
+ if (token == NULL) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
+ _("Bad authentication response from server."));
+ return NULL;
+ }
+
+ inbuf.value = token->data;
+ inbuf.length = token->len;
+ input_token = &inbuf;
+
+ challenge:
+ major = gss_init_sec_context (&minor, GSS_C_NO_CREDENTIAL, &priv->ctx, priv->target,
+ GSS_C_OID_KRBV5_DES, GSS_C_MUTUAL_FLAG |
+ GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG,
+ 0, GSS_C_NO_CHANNEL_BINDINGS,
+ input_token, &mech, &outbuf, &flags, &time);
+
+ switch (major) {
+ case GSS_S_COMPLETE:
+ priv->state = GSSAPI_STATE_COMPLETE;
+ break;
+ case GSS_S_CONTINUE_NEEDED:
+ priv->state = GSSAPI_STATE_CONTINUE_NEEDED;
+ break;
+ default:
+ gssapi_set_exception (major, minor, ex);
+ return NULL;
+ }
+
+ challenge = g_byte_array_new ();
+ g_byte_array_append (challenge, outbuf.value, outbuf.length);
+#ifndef HAVE_HEIMDAL_KRB5
+ gss_release_buffer (&minor, &outbuf);
+#endif
+ break;
+ case GSSAPI_STATE_COMPLETE:
+ if (token == NULL) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
+ _("Bad authentication response from server."));
+ return NULL;
+ }
+
+ inbuf.value = token->data;
+ inbuf.length = token->len;
+
+ major = gss_unwrap (&minor, priv->ctx, &inbuf, &outbuf, &conf_state, &qop);
+ if (major != GSS_S_COMPLETE) {
+ gssapi_set_exception (major, minor, ex);
+ return NULL;
+ }
+
+ if (outbuf.length < 4) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
+ _("Bad authentication response from server."));
+#ifndef HAVE_HEIMDAL_KRB5
+ gss_release_buffer (&minor, &outbuf);
+#endif
+ return NULL;
+ }
+
+ /* check that our desired security layer is supported */
+ if ((((unsigned char *) outbuf.value)[0] & DESIRED_SECURITY_LAYER) != DESIRED_SECURITY_LAYER) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
+ _("Unsupported security layer."));
+#ifndef HAVE_HEIMDAL_KRB5
+ gss_release_buffer (&minor, &outbuf);
+#endif
+ return NULL;
+ }
+
+ inbuf.length = 4 + strlen (sasl->service->url->user);
+ inbuf.value = str = g_malloc (inbuf.length);
+ memcpy (inbuf.value, outbuf.value, 4);
+ str[0] = DESIRED_SECURITY_LAYER;
+ memcpy (str + 4, sasl->service->url->user, inbuf.length - 4);
+
+#ifndef HAVE_HEIMDAL_KRB5
+ gss_release_buffer (&minor, &outbuf);
+#endif
+
+ major = gss_wrap (&minor, priv->ctx, FALSE, qop, &inbuf, &conf_state, &outbuf);
+ if (major != GSS_S_COMPLETE) {
+ gssapi_set_exception (major, minor, ex);
+ g_free (str);
+ return NULL;
+ }
+
+ g_free (str);
+ challenge = g_byte_array_new ();
+ g_byte_array_append (challenge, outbuf.value, outbuf.length);
+
+#ifndef HAVE_HEIMDAL_KRB5
+ gss_release_buffer (&minor, &outbuf);
+#endif
+
+ priv->state = GSSAPI_STATE_AUTHENTICATED;
+
+ sasl->authenticated = TRUE;
+ break;
+ default:
+ return NULL;
+ }
+
+ return challenge;
+}
+
+#endif /* HAVE_KRB5 */
diff --git a/camel/camel-sasl-kerberos4.c b/camel/camel-sasl-kerberos4.c
new file mode 100644
index 0000000000..fd366e61db
--- /dev/null
+++ b/camel/camel-sasl-kerberos4.c
@@ -0,0 +1,230 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Jeffrey Stedfast <fejj@ximian.com>
+ *
+ * Copyright 2001 Ximian, Inc. (www.ximian.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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_KRB4
+
+#include <krb.h>
+/* MIT krb4 des.h #defines _. Sigh. We don't need it. #undef it here
+ * so we get the gettexty _ definition later.
+ */
+#undef _
+
+#include <string.h>
+#include "camel-string-utils.h"
+#include "camel-sasl-kerberos4.h"
+#include "camel-service.h"
+
+CamelServiceAuthType camel_sasl_kerberos4_authtype = {
+ N_("Kerberos 4"),
+
+ N_("This option will connect to the server using "
+ "Kerberos 4 authentication."),
+
+ "KERBEROS_V4",
+ FALSE
+};
+
+#define KERBEROS_V4_PROTECTION_NONE 1
+#define KERBEROS_V4_PROTECTION_INTEGRITY 2
+#define KERBEROS_V4_PROTECTION_PRIVACY 4
+
+static CamelSaslClass *parent_class = NULL;
+
+/* Returns the class for a CamelSaslKerberos4 */
+#define CSK4_CLASS(so) CAMEL_SASL_KERBEROS4_CLASS (CAMEL_OBJECT_GET_CLASS (so))
+
+static GByteArray *krb4_challenge (CamelSasl *sasl, GByteArray *token, CamelException *ex);
+
+struct _CamelSaslKerberos4Private {
+ int state;
+
+ guint32 nonce_n;
+ guint32 nonce_h;
+
+ des_cblock session;
+ des_key_schedule schedule;
+};
+
+static void
+camel_sasl_kerberos4_class_init (CamelSaslKerberos4Class *camel_sasl_kerberos4_class)
+{
+ CamelSaslClass *camel_sasl_class = CAMEL_SASL_CLASS (camel_sasl_kerberos4_class);
+
+ parent_class = CAMEL_SASL_CLASS (camel_type_get_global_classfuncs (camel_sasl_get_type ()));
+
+ /* virtual method overload */
+ camel_sasl_class->challenge = krb4_challenge;
+}
+
+static void
+camel_sasl_kerberos4_init (gpointer object, gpointer klass)
+{
+ CamelSaslKerberos4 *sasl_krb4 = CAMEL_SASL_KERBEROS4 (object);
+
+ sasl_krb4->priv = g_new0 (struct _CamelSaslKerberos4Private, 1);
+}
+
+static void
+camel_sasl_kerberos4_finalize (CamelObject *object)
+{
+ CamelSaslKerberos4 *sasl = CAMEL_SASL_KERBEROS4 (object);
+
+ if (sasl->priv) {
+ memset (sasl->priv, 0, sizeof (sasl->priv));
+ g_free (sasl->priv);
+ }
+}
+
+
+CamelType
+camel_sasl_kerberos4_get_type (void)
+{
+ static CamelType type = CAMEL_INVALID_TYPE;
+
+ if (type == CAMEL_INVALID_TYPE) {
+ type = camel_type_register (camel_sasl_get_type (),
+ "CamelSaslKerberos4",
+ sizeof (CamelSaslKerberos4),
+ sizeof (CamelSaslKerberos4Class),
+ (CamelObjectClassInitFunc) camel_sasl_kerberos4_class_init,
+ NULL,
+ (CamelObjectInitFunc) camel_sasl_kerberos4_init,
+ (CamelObjectFinalizeFunc) camel_sasl_kerberos4_finalize);
+ }
+
+ return type;
+}
+
+static GByteArray *
+krb4_challenge (CamelSasl *sasl, GByteArray *token, CamelException *ex)
+{
+ struct _CamelSaslKerberos4Private *priv = CAMEL_SASL_KERBEROS4 (sasl)->priv;
+ GByteArray *ret = NULL;
+ char *inst, *realm, *username;
+ struct hostent *h;
+ int status, len;
+ KTEXT_ST authenticator;
+ CREDENTIALS credentials;
+ guint32 plus1;
+ struct addrinfo *ai, hints;
+
+ /* Need to wait for the server */
+ if (!token)
+ return NULL;
+
+ switch (priv->state) {
+ case 0:
+ if (token->len != 4)
+ goto lose;
+
+ memcpy (&priv->nonce_n, token->data, 4);
+ priv->nonce_h = ntohl (priv->nonce_n);
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_CANONNAME;
+ ai = camel_getaddrinfo(sasl->service->url->host?sasl->service->url->host:"localhost", NULL, &hints, ex);
+ if (ai == NULL)
+ goto lose;
+
+ /* Our response is an authenticator including that number. */
+ inst = g_strndup (ai->ai_canonname, strcspn (ai->ai_canonname, "."));
+ camel_strdown (inst);
+ realm = g_strdup (krb_realmofhost (ai->ai_canonname));
+ camel_freeaddrinfo(ai);
+ status = krb_mk_req (&authenticator, sasl->service_name, inst, realm, priv->nonce_h);
+ if (status == KSUCCESS) {
+ status = krb_get_cred (sasl->service_name, inst, realm, &credentials);
+ memcpy (priv->session, credentials.session, sizeof (priv->session));
+ memset (&credentials, 0, sizeof (credentials));
+ }
+ g_free (inst);
+ g_free (realm);
+
+ if (status != KSUCCESS) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
+ _("Could not get Kerberos ticket:\n%s"),
+ krb_err_txt[status]);
+ goto lose;
+ }
+ des_key_sched (&priv->session, priv->schedule);
+
+ ret = g_byte_array_new ();
+ g_byte_array_append (ret, (const guint8 *)authenticator.dat, authenticator.length);
+ break;
+
+ case 1:
+ if (token->len != 8)
+ goto lose;
+
+ /* This one is encrypted. */
+ des_ecb_encrypt ((des_cblock *)token->data, (des_cblock *)token->data, priv->schedule, 0);
+
+ /* Check that the returned value is the original nonce plus one. */
+ memcpy (&plus1, token->data, 4);
+ if (ntohl (plus1) != priv->nonce_h + 1)
+ goto lose;
+
+ /* "the fifth octet contain[s] a bit-mask specifying the
+ * protection mechanisms supported by the server"
+ */
+ if (!(token->data[4] & KERBEROS_V4_PROTECTION_NONE)) {
+ g_warning ("Server does not support `no protection' :-(");
+ goto lose;
+ }
+
+ username = sasl->service->url->user;
+ len = strlen (username) + 9;
+ len += 8 - len % 8;
+ ret = g_byte_array_new ();
+ g_byte_array_set_size (ret, len);
+ memset (ret->data, 0, len);
+ memcpy (ret->data, &priv->nonce_n, 4);
+ ret->data[4] = KERBEROS_V4_PROTECTION_NONE;
+ ret->data[5] = ret->data[6] = ret->data[7] = 0;
+ strcpy (ret->data + 8, username);
+
+ des_pcbc_encrypt ((void *)ret->data, (void *)ret->data, len,
+ priv->schedule, &priv->session, 1);
+ memset (&priv->session, 0, sizeof (priv->session));
+
+ sasl->authenticated = TRUE;
+ break;
+ }
+
+ priv->state++;
+ return ret;
+
+ lose:
+ memset (&priv->session, 0, sizeof (priv->session));
+
+ if (!camel_exception_is_set (ex)) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
+ _("Bad authentication response from server."));
+ }
+ return NULL;
+}
+
+#endif /* HAVE_KRB4 */
diff --git a/camel/camel-sasl-ntlm.c b/camel/camel-sasl-ntlm.c
new file mode 100644
index 0000000000..81ad5ce2af
--- /dev/null
+++ b/camel/camel-sasl-ntlm.c
@@ -0,0 +1,706 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright 2002 Ximian, Inc. (www.ximian.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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "camel-sasl-ntlm.h"
+
+#include <ctype.h>
+#include <string.h>
+
+CamelServiceAuthType camel_sasl_ntlm_authtype = {
+ N_("NTLM / SPA"),
+
+ N_("This option will connect to a Windows-based server using "
+ "NTLM / Secure Password Authentication."),
+
+ "NTLM",
+ TRUE
+};
+
+static CamelSaslClass *parent_class = NULL;
+
+static GByteArray *ntlm_challenge (CamelSasl *sasl, GByteArray *token, CamelException *ex);
+
+static void
+camel_sasl_ntlm_class_init (CamelSaslNTLMClass *camel_sasl_ntlm_class)
+{
+ CamelSaslClass *camel_sasl_class = CAMEL_SASL_CLASS (camel_sasl_ntlm_class);
+
+ parent_class = CAMEL_SASL_CLASS (camel_type_get_global_classfuncs (camel_sasl_get_type ()));
+
+ /* virtual method overload */
+ camel_sasl_class->challenge = ntlm_challenge;
+}
+
+CamelType
+camel_sasl_ntlm_get_type (void)
+{
+ static CamelType type = CAMEL_INVALID_TYPE;
+
+ if (type == CAMEL_INVALID_TYPE) {
+ type = camel_type_register (
+ camel_sasl_get_type (), "CamelSaslNTLM",
+ sizeof (CamelSaslNTLM),
+ sizeof (CamelSaslNTLMClass),
+ (CamelObjectClassInitFunc) camel_sasl_ntlm_class_init,
+ NULL, NULL, NULL);
+ }
+
+ return type;
+}
+
+#define NTLM_REQUEST "NTLMSSP\x00\x01\x00\x00\x00\x06\x82\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x30\x00\x00\x00\x00\x00\x00\x00\x30\x00\x00\x00"
+
+#define NTLM_CHALLENGE_NONCE_OFFSET 24
+#define NTLM_CHALLENGE_DOMAIN_OFFSET 48
+#define NTLM_CHALLENGE_DOMAIN_LEN_OFFSET 44
+
+#define NTLM_RESPONSE_HEADER "NTLMSSP\x00\x03\x00\x00\x00"
+#define NTLM_RESPONSE_FLAGS "\x82\x01"
+#define NTLM_RESPONSE_BASE_SIZE 64
+#define NTLM_RESPONSE_LM_RESP_OFFSET 12
+#define NTLM_RESPONSE_NT_RESP_OFFSET 20
+#define NTLM_RESPONSE_DOMAIN_OFFSET 28
+#define NTLM_RESPONSE_USER_OFFSET 36
+#define NTLM_RESPONSE_HOST_OFFSET 44
+#define NTLM_RESPONSE_FLAGS_OFFSET 60
+
+static void ntlm_calc_response (const guchar key[21],
+ const guchar plaintext[8],
+ guchar results[24]);
+static void ntlm_lanmanager_hash (const char *password, char hash[21]);
+static void ntlm_nt_hash (const char *password, char hash[21]);
+static void ntlm_set_string (GByteArray *ba, int offset,
+ const char *data, int len);
+
+static GByteArray *
+ntlm_challenge (CamelSasl *sasl, GByteArray *token, CamelException *ex)
+{
+ GByteArray *ret;
+ guchar nonce[8], hash[21], lm_resp[24], nt_resp[24];
+
+ ret = g_byte_array_new ();
+
+ if (!token || !token->len) {
+ g_byte_array_append (ret, NTLM_REQUEST,
+ sizeof (NTLM_REQUEST) - 1);
+ return ret;
+ }
+
+ memcpy (nonce, token->data + NTLM_CHALLENGE_NONCE_OFFSET, 8);
+ ntlm_lanmanager_hash (sasl->service->url->passwd, hash);
+ ntlm_calc_response (hash, nonce, lm_resp);
+ ntlm_nt_hash (sasl->service->url->passwd, hash);
+ ntlm_calc_response (hash, nonce, nt_resp);
+
+ ret = g_byte_array_new ();
+ g_byte_array_set_size (ret, NTLM_RESPONSE_BASE_SIZE);
+ memset (ret->data, 0, NTLM_RESPONSE_BASE_SIZE);
+ memcpy (ret->data, NTLM_RESPONSE_HEADER,
+ sizeof (NTLM_RESPONSE_HEADER) - 1);
+ memcpy (ret->data + NTLM_RESPONSE_FLAGS_OFFSET,
+ NTLM_RESPONSE_FLAGS, sizeof (NTLM_RESPONSE_FLAGS) - 1);
+
+ ntlm_set_string (ret, NTLM_RESPONSE_DOMAIN_OFFSET,
+ token->data + NTLM_CHALLENGE_DOMAIN_OFFSET,
+ atoi (token->data + NTLM_CHALLENGE_DOMAIN_LEN_OFFSET));
+ ntlm_set_string (ret, NTLM_RESPONSE_USER_OFFSET,
+ sasl->service->url->user,
+ strlen (sasl->service->url->user));
+ ntlm_set_string (ret, NTLM_RESPONSE_HOST_OFFSET,
+ "UNKNOWN", sizeof ("UNKNOWN") - 1);
+ ntlm_set_string (ret, NTLM_RESPONSE_LM_RESP_OFFSET,
+ lm_resp, sizeof (lm_resp));
+ ntlm_set_string (ret, NTLM_RESPONSE_NT_RESP_OFFSET,
+ nt_resp, sizeof (nt_resp));
+
+ sasl->authenticated = TRUE;
+ return ret;
+}
+
+/* MD4 */
+static void md4sum (const unsigned char *in,
+ int nbytes,
+ unsigned char digest[16]);
+
+/* DES */
+typedef guint32 DES_KS[16][2]; /* Single-key DES key schedule */
+
+static void deskey (DES_KS, unsigned char *, int);
+
+static void des (DES_KS, unsigned char *);
+
+static void setup_schedule (const guchar *key_56, DES_KS ks);
+
+
+
+#define LM_PASSWORD_MAGIC "\x4B\x47\x53\x21\x40\x23\x24\x25" \
+ "\x4B\x47\x53\x21\x40\x23\x24\x25" \
+ "\x00\x00\x00\x00\x00"
+
+static void
+ntlm_lanmanager_hash (const char *password, char hash[21])
+{
+ guchar lm_password [15];
+ DES_KS ks;
+ int i;
+
+ for (i = 0; i < 14 && password [i]; i++)
+ lm_password [i] = toupper ((unsigned char) password [i]);
+
+ for (; i < 15; i++)
+ lm_password [i] = '\0';
+
+ memcpy (hash, LM_PASSWORD_MAGIC, 21);
+
+ setup_schedule (lm_password, ks);
+ des (ks, hash);
+
+ setup_schedule (lm_password + 7, ks);
+ des (ks, hash + 8);
+}
+
+static void
+ntlm_nt_hash (const char *password, char hash[21])
+{
+ unsigned char *buf, *p;
+
+ p = buf = g_malloc (strlen (password) * 2);
+
+ while (*password) {
+ *p++ = *password++;
+ *p++ = '\0';
+ }
+
+ md4sum (buf, p - buf, hash);
+ memset (hash + 16, 0, 5);
+
+ g_free (buf);
+}
+
+static void
+ntlm_set_string (GByteArray *ba, int offset, const char *data, int len)
+{
+ ba->data[offset ] = ba->data[offset + 2] = len & 0xFF;
+ ba->data[offset + 1] = ba->data[offset + 3] = (len >> 8) & 0xFF;
+ ba->data[offset + 4] = ba->len & 0xFF;
+ ba->data[offset + 5] = (ba->len >> 8) & 0xFF;
+ g_byte_array_append (ba, data, len);
+}
+
+
+#define KEYBITS(k,s) \
+ (((k[(s)/8] << ((s)%8)) & 0xFF) | (k[(s)/8+1] >> (8-(s)%8)))
+
+/* DES utils */
+/* Set up a key schedule based on a 56bit key */
+static void
+setup_schedule (const guchar *key_56, DES_KS ks)
+{
+ guchar key[8];
+ int i, c, bit;
+
+ for (i = 0; i < 8; i++) {
+ key [i] = KEYBITS (key_56, i * 7);
+
+ /* Fix parity */
+ for (c = bit = 0; bit < 8; bit++)
+ if (key [i] & (1 << bit))
+ c++;
+ if (!(c & 1))
+ key [i] ^= 0x01;
+ }
+
+ deskey (ks, key, 0);
+}
+
+static void
+ntlm_calc_response (const guchar key[21], const guchar plaintext[8],
+ guchar results[24])
+{
+ DES_KS ks;
+
+ memcpy (results, plaintext, 8);
+ memcpy (results + 8, plaintext, 8);
+ memcpy (results + 16, plaintext, 8);
+
+ setup_schedule (key, ks);
+ des (ks, results);
+
+ setup_schedule (key + 7, ks);
+ des (ks, results + 8);
+
+ setup_schedule (key + 14, ks);
+ des (ks, results + 16);
+}
+
+
+/*
+ * MD4 encoder. (The one everyone else uses is not GPL-compatible;
+ * this is a reimplementation from spec.) This doesn't need to be
+ * efficient for our purposes, although it would be nice to fix
+ * it to not malloc()...
+ */
+
+#define F(X,Y,Z) ( ((X)&(Y)) | ((~(X))&(Z)) )
+#define G(X,Y,Z) ( ((X)&(Y)) | ((X)&(Z)) | ((Y)&(Z)) )
+#define H(X,Y,Z) ( (X)^(Y)^(Z) )
+#define ROT(val, n) ( ((val) << (n)) | ((val) >> (32 - (n))) )
+
+static void
+md4sum (const unsigned char *in, int nbytes, unsigned char digest[16])
+{
+ unsigned char *M;
+ guint32 A, B, C, D, AA, BB, CC, DD, X[16];
+ int pbytes, nbits = nbytes * 8, i, j;
+
+ pbytes = (120 - (nbytes % 64)) % 64;
+ M = alloca (nbytes + pbytes + 8);
+ memcpy (M, in, nbytes);
+ memset (M + nbytes, 0, pbytes + 8);
+ M[nbytes] = 0x80;
+ M[nbytes + pbytes] = nbits & 0xFF;
+ M[nbytes + pbytes + 1] = (nbits >> 8) & 0xFF;
+ M[nbytes + pbytes + 2] = (nbits >> 16) & 0xFF;
+ M[nbytes + pbytes + 3] = (nbits >> 24) & 0xFF;
+
+ A = 0x67452301;
+ B = 0xEFCDAB89;
+ C = 0x98BADCFE;
+ D = 0x10325476;
+
+ for (i = 0; i < nbytes + pbytes + 8; i += 64) {
+ for (j = 0; j < 16; j++) {
+ X[j] = (M[i + j*4]) |
+ (M[i + j*4 + 1] << 8) |
+ (M[i + j*4 + 2] << 16) |
+ (M[i + j*4 + 3] << 24);
+ }
+
+ AA = A;
+ BB = B;
+ CC = C;
+ DD = D;
+
+ A = ROT (A + F(B, C, D) + X[0], 3);
+ D = ROT (D + F(A, B, C) + X[1], 7);
+ C = ROT (C + F(D, A, B) + X[2], 11);
+ B = ROT (B + F(C, D, A) + X[3], 19);
+ A = ROT (A + F(B, C, D) + X[4], 3);
+ D = ROT (D + F(A, B, C) + X[5], 7);
+ C = ROT (C + F(D, A, B) + X[6], 11);
+ B = ROT (B + F(C, D, A) + X[7], 19);
+ A = ROT (A + F(B, C, D) + X[8], 3);
+ D = ROT (D + F(A, B, C) + X[9], 7);
+ C = ROT (C + F(D, A, B) + X[10], 11);
+ B = ROT (B + F(C, D, A) + X[11], 19);
+ A = ROT (A + F(B, C, D) + X[12], 3);
+ D = ROT (D + F(A, B, C) + X[13], 7);
+ C = ROT (C + F(D, A, B) + X[14], 11);
+ B = ROT (B + F(C, D, A) + X[15], 19);
+
+ A = ROT (A + G(B, C, D) + X[0] + 0x5A827999, 3);
+ D = ROT (D + G(A, B, C) + X[4] + 0x5A827999, 5);
+ C = ROT (C + G(D, A, B) + X[8] + 0x5A827999, 9);
+ B = ROT (B + G(C, D, A) + X[12] + 0x5A827999, 13);
+ A = ROT (A + G(B, C, D) + X[1] + 0x5A827999, 3);
+ D = ROT (D + G(A, B, C) + X[5] + 0x5A827999, 5);
+ C = ROT (C + G(D, A, B) + X[9] + 0x5A827999, 9);
+ B = ROT (B + G(C, D, A) + X[13] + 0x5A827999, 13);
+ A = ROT (A + G(B, C, D) + X[2] + 0x5A827999, 3);
+ D = ROT (D + G(A, B, C) + X[6] + 0x5A827999, 5);
+ C = ROT (C + G(D, A, B) + X[10] + 0x5A827999, 9);
+ B = ROT (B + G(C, D, A) + X[14] + 0x5A827999, 13);
+ A = ROT (A + G(B, C, D) + X[3] + 0x5A827999, 3);
+ D = ROT (D + G(A, B, C) + X[7] + 0x5A827999, 5);
+ C = ROT (C + G(D, A, B) + X[11] + 0x5A827999, 9);
+ B = ROT (B + G(C, D, A) + X[15] + 0x5A827999, 13);
+
+ A = ROT (A + H(B, C, D) + X[0] + 0x6ED9EBA1, 3);
+ D = ROT (D + H(A, B, C) + X[8] + 0x6ED9EBA1, 9);
+ C = ROT (C + H(D, A, B) + X[4] + 0x6ED9EBA1, 11);
+ B = ROT (B + H(C, D, A) + X[12] + 0x6ED9EBA1, 15);
+ A = ROT (A + H(B, C, D) + X[2] + 0x6ED9EBA1, 3);
+ D = ROT (D + H(A, B, C) + X[10] + 0x6ED9EBA1, 9);
+ C = ROT (C + H(D, A, B) + X[6] + 0x6ED9EBA1, 11);
+ B = ROT (B + H(C, D, A) + X[14] + 0x6ED9EBA1, 15);
+ A = ROT (A + H(B, C, D) + X[1] + 0x6ED9EBA1, 3);
+ D = ROT (D + H(A, B, C) + X[9] + 0x6ED9EBA1, 9);
+ C = ROT (C + H(D, A, B) + X[5] + 0x6ED9EBA1, 11);
+ B = ROT (B + H(C, D, A) + X[13] + 0x6ED9EBA1, 15);
+ A = ROT (A + H(B, C, D) + X[3] + 0x6ED9EBA1, 3);
+ D = ROT (D + H(A, B, C) + X[11] + 0x6ED9EBA1, 9);
+ C = ROT (C + H(D, A, B) + X[7] + 0x6ED9EBA1, 11);
+ B = ROT (B + H(C, D, A) + X[15] + 0x6ED9EBA1, 15);
+
+ A += AA;
+ B += BB;
+ C += CC;
+ D += DD;
+ }
+
+ digest[0] = A & 0xFF;
+ digest[1] = (A >> 8) & 0xFF;
+ digest[2] = (A >> 16) & 0xFF;
+ digest[3] = (A >> 24) & 0xFF;
+ digest[4] = B & 0xFF;
+ digest[5] = (B >> 8) & 0xFF;
+ digest[6] = (B >> 16) & 0xFF;
+ digest[7] = (B >> 24) & 0xFF;
+ digest[8] = C & 0xFF;
+ digest[9] = (C >> 8) & 0xFF;
+ digest[10] = (C >> 16) & 0xFF;
+ digest[11] = (C >> 24) & 0xFF;
+ digest[12] = D & 0xFF;
+ digest[13] = (D >> 8) & 0xFF;
+ digest[14] = (D >> 16) & 0xFF;
+ digest[15] = (D >> 24) & 0xFF;
+}
+
+
+/* Public domain DES implementation from Phil Karn */
+static guint32 Spbox[8][64] = {
+ { 0x01010400, 0x00000000, 0x00010000, 0x01010404,
+ 0x01010004, 0x00010404, 0x00000004, 0x00010000,
+ 0x00000400, 0x01010400, 0x01010404, 0x00000400,
+ 0x01000404, 0x01010004, 0x01000000, 0x00000004,
+ 0x00000404, 0x01000400, 0x01000400, 0x00010400,
+ 0x00010400, 0x01010000, 0x01010000, 0x01000404,
+ 0x00010004, 0x01000004, 0x01000004, 0x00010004,
+ 0x00000000, 0x00000404, 0x00010404, 0x01000000,
+ 0x00010000, 0x01010404, 0x00000004, 0x01010000,
+ 0x01010400, 0x01000000, 0x01000000, 0x00000400,
+ 0x01010004, 0x00010000, 0x00010400, 0x01000004,
+ 0x00000400, 0x00000004, 0x01000404, 0x00010404,
+ 0x01010404, 0x00010004, 0x01010000, 0x01000404,
+ 0x01000004, 0x00000404, 0x00010404, 0x01010400,
+ 0x00000404, 0x01000400, 0x01000400, 0x00000000,
+ 0x00010004, 0x00010400, 0x00000000, 0x01010004 },
+ { 0x80108020, 0x80008000, 0x00008000, 0x00108020,
+ 0x00100000, 0x00000020, 0x80100020, 0x80008020,
+ 0x80000020, 0x80108020, 0x80108000, 0x80000000,
+ 0x80008000, 0x00100000, 0x00000020, 0x80100020,
+ 0x00108000, 0x00100020, 0x80008020, 0x00000000,
+ 0x80000000, 0x00008000, 0x00108020, 0x80100000,
+ 0x00100020, 0x80000020, 0x00000000, 0x00108000,
+ 0x00008020, 0x80108000, 0x80100000, 0x00008020,
+ 0x00000000, 0x00108020, 0x80100020, 0x00100000,
+ 0x80008020, 0x80100000, 0x80108000, 0x00008000,
+ 0x80100000, 0x80008000, 0x00000020, 0x80108020,
+ 0x00108020, 0x00000020, 0x00008000, 0x80000000,
+ 0x00008020, 0x80108000, 0x00100000, 0x80000020,
+ 0x00100020, 0x80008020, 0x80000020, 0x00100020,
+ 0x00108000, 0x00000000, 0x80008000, 0x00008020,
+ 0x80000000, 0x80100020, 0x80108020, 0x00108000 },
+ { 0x00000208, 0x08020200, 0x00000000, 0x08020008,
+ 0x08000200, 0x00000000, 0x00020208, 0x08000200,
+ 0x00020008, 0x08000008, 0x08000008, 0x00020000,
+ 0x08020208, 0x00020008, 0x08020000, 0x00000208,
+ 0x08000000, 0x00000008, 0x08020200, 0x00000200,
+ 0x00020200, 0x08020000, 0x08020008, 0x00020208,
+ 0x08000208, 0x00020200, 0x00020000, 0x08000208,
+ 0x00000008, 0x08020208, 0x00000200, 0x08000000,
+ 0x08020200, 0x08000000, 0x00020008, 0x00000208,
+ 0x00020000, 0x08020200, 0x08000200, 0x00000000,
+ 0x00000200, 0x00020008, 0x08020208, 0x08000200,
+ 0x08000008, 0x00000200, 0x00000000, 0x08020008,
+ 0x08000208, 0x00020000, 0x08000000, 0x08020208,
+ 0x00000008, 0x00020208, 0x00020200, 0x08000008,
+ 0x08020000, 0x08000208, 0x00000208, 0x08020000,
+ 0x00020208, 0x00000008, 0x08020008, 0x00020200 },
+ { 0x00802001, 0x00002081, 0x00002081, 0x00000080,
+ 0x00802080, 0x00800081, 0x00800001, 0x00002001,
+ 0x00000000, 0x00802000, 0x00802000, 0x00802081,
+ 0x00000081, 0x00000000, 0x00800080, 0x00800001,
+ 0x00000001, 0x00002000, 0x00800000, 0x00802001,
+ 0x00000080, 0x00800000, 0x00002001, 0x00002080,
+ 0x00800081, 0x00000001, 0x00002080, 0x00800080,
+ 0x00002000, 0x00802080, 0x00802081, 0x00000081,
+ 0x00800080, 0x00800001, 0x00802000, 0x00802081,
+ 0x00000081, 0x00000000, 0x00000000, 0x00802000,
+ 0x00002080, 0x00800080, 0x00800081, 0x00000001,
+ 0x00802001, 0x00002081, 0x00002081, 0x00000080,
+ 0x00802081, 0x00000081, 0x00000001, 0x00002000,
+ 0x00800001, 0x00002001, 0x00802080, 0x00800081,
+ 0x00002001, 0x00002080, 0x00800000, 0x00802001,
+ 0x00000080, 0x00800000, 0x00002000, 0x00802080 },
+ { 0x00000100, 0x02080100, 0x02080000, 0x42000100,
+ 0x00080000, 0x00000100, 0x40000000, 0x02080000,
+ 0x40080100, 0x00080000, 0x02000100, 0x40080100,
+ 0x42000100, 0x42080000, 0x00080100, 0x40000000,
+ 0x02000000, 0x40080000, 0x40080000, 0x00000000,
+ 0x40000100, 0x42080100, 0x42080100, 0x02000100,
+ 0x42080000, 0x40000100, 0x00000000, 0x42000000,
+ 0x02080100, 0x02000000, 0x42000000, 0x00080100,
+ 0x00080000, 0x42000100, 0x00000100, 0x02000000,
+ 0x40000000, 0x02080000, 0x42000100, 0x40080100,
+ 0x02000100, 0x40000000, 0x42080000, 0x02080100,
+ 0x40080100, 0x00000100, 0x02000000, 0x42080000,
+ 0x42080100, 0x00080100, 0x42000000, 0x42080100,
+ 0x02080000, 0x00000000, 0x40080000, 0x42000000,
+ 0x00080100, 0x02000100, 0x40000100, 0x00080000,
+ 0x00000000, 0x40080000, 0x02080100, 0x40000100 },
+ { 0x20000010, 0x20400000, 0x00004000, 0x20404010,
+ 0x20400000, 0x00000010, 0x20404010, 0x00400000,
+ 0x20004000, 0x00404010, 0x00400000, 0x20000010,
+ 0x00400010, 0x20004000, 0x20000000, 0x00004010,
+ 0x00000000, 0x00400010, 0x20004010, 0x00004000,
+ 0x00404000, 0x20004010, 0x00000010, 0x20400010,
+ 0x20400010, 0x00000000, 0x00404010, 0x20404000,
+ 0x00004010, 0x00404000, 0x20404000, 0x20000000,
+ 0x20004000, 0x00000010, 0x20400010, 0x00404000,
+ 0x20404010, 0x00400000, 0x00004010, 0x20000010,
+ 0x00400000, 0x20004000, 0x20000000, 0x00004010,
+ 0x20000010, 0x20404010, 0x00404000, 0x20400000,
+ 0x00404010, 0x20404000, 0x00000000, 0x20400010,
+ 0x00000010, 0x00004000, 0x20400000, 0x00404010,
+ 0x00004000, 0x00400010, 0x20004010, 0x00000000,
+ 0x20404000, 0x20000000, 0x00400010, 0x20004010 },
+ { 0x00200000, 0x04200002, 0x04000802, 0x00000000,
+ 0x00000800, 0x04000802, 0x00200802, 0x04200800,
+ 0x04200802, 0x00200000, 0x00000000, 0x04000002,
+ 0x00000002, 0x04000000, 0x04200002, 0x00000802,
+ 0x04000800, 0x00200802, 0x00200002, 0x04000800,
+ 0x04000002, 0x04200000, 0x04200800, 0x00200002,
+ 0x04200000, 0x00000800, 0x00000802, 0x04200802,
+ 0x00200800, 0x00000002, 0x04000000, 0x00200800,
+ 0x04000000, 0x00200800, 0x00200000, 0x04000802,
+ 0x04000802, 0x04200002, 0x04200002, 0x00000002,
+ 0x00200002, 0x04000000, 0x04000800, 0x00200000,
+ 0x04200800, 0x00000802, 0x00200802, 0x04200800,
+ 0x00000802, 0x04000002, 0x04200802, 0x04200000,
+ 0x00200800, 0x00000000, 0x00000002, 0x04200802,
+ 0x00000000, 0x00200802, 0x04200000, 0x00000800,
+ 0x04000002, 0x04000800, 0x00000800, 0x00200002 },
+ { 0x10001040, 0x00001000, 0x00040000, 0x10041040,
+ 0x10000000, 0x10001040, 0x00000040, 0x10000000,
+ 0x00040040, 0x10040000, 0x10041040, 0x00041000,
+ 0x10041000, 0x00041040, 0x00001000, 0x00000040,
+ 0x10040000, 0x10000040, 0x10001000, 0x00001040,
+ 0x00041000, 0x00040040, 0x10040040, 0x10041000,
+ 0x00001040, 0x00000000, 0x00000000, 0x10040040,
+ 0x10000040, 0x10001000, 0x00041040, 0x00040000,
+ 0x00041040, 0x00040000, 0x10041000, 0x00001000,
+ 0x00000040, 0x10040040, 0x00001000, 0x00041040,
+ 0x10001000, 0x00000040, 0x10000040, 0x10040000,
+ 0x10040040, 0x10000000, 0x00040000, 0x10001040,
+ 0x00000000, 0x10041040, 0x00040040, 0x10000040,
+ 0x10040000, 0x10001000, 0x10001040, 0x00000000,
+ 0x10041040, 0x00041000, 0x00041000, 0x00001040,
+ 0x00001040, 0x00040040, 0x10000000, 0x10041000 }
+};
+
+#undef F
+#define F(l,r,key){\
+ work = ((r >> 4) | (r << 28)) ^ key[0];\
+ l ^= Spbox[6][work & 0x3f];\
+ l ^= Spbox[4][(work >> 8) & 0x3f];\
+ l ^= Spbox[2][(work >> 16) & 0x3f];\
+ l ^= Spbox[0][(work >> 24) & 0x3f];\
+ work = r ^ key[1];\
+ l ^= Spbox[7][work & 0x3f];\
+ l ^= Spbox[5][(work >> 8) & 0x3f];\
+ l ^= Spbox[3][(work >> 16) & 0x3f];\
+ l ^= Spbox[1][(work >> 24) & 0x3f];\
+}
+/* Encrypt or decrypt a block of data in ECB mode */
+static void
+des(ks,block)
+guint32 ks[16][2]; /* Key schedule */
+unsigned char block[8]; /* Data block */
+{
+ guint32 left,right,work;
+
+ /* Read input block and place in left/right in big-endian order */
+ left = ((guint32)block[0] << 24)
+ | ((guint32)block[1] << 16)
+ | ((guint32)block[2] << 8)
+ | (guint32)block[3];
+ right = ((guint32)block[4] << 24)
+ | ((guint32)block[5] << 16)
+ | ((guint32)block[6] << 8)
+ | (guint32)block[7];
+
+ /* Hoey's clever initial permutation algorithm, from Outerbridge
+ * (see Schneier p 478)
+ *
+ * The convention here is the same as Outerbridge: rotate each
+ * register left by 1 bit, i.e., so that "left" contains permuted
+ * input bits 2, 3, 4, ... 1 and "right" contains 33, 34, 35, ... 32
+ * (using origin-1 numbering as in the FIPS). This allows us to avoid
+ * one of the two rotates that would otherwise be required in each of
+ * the 16 rounds.
+ */
+ work = ((left >> 4) ^ right) & 0x0f0f0f0f;
+ right ^= work;
+ left ^= work << 4;
+ work = ((left >> 16) ^ right) & 0xffff;
+ right ^= work;
+ left ^= work << 16;
+ work = ((right >> 2) ^ left) & 0x33333333;
+ left ^= work;
+ right ^= (work << 2);
+ work = ((right >> 8) ^ left) & 0xff00ff;
+ left ^= work;
+ right ^= (work << 8);
+ right = (right << 1) | (right >> 31);
+ work = (left ^ right) & 0xaaaaaaaa;
+ left ^= work;
+ right ^= work;
+ left = (left << 1) | (left >> 31);
+
+ /* Now do the 16 rounds */
+ F(left,right,ks[0]);
+ F(right,left,ks[1]);
+ F(left,right,ks[2]);
+ F(right,left,ks[3]);
+ F(left,right,ks[4]);
+ F(right,left,ks[5]);
+ F(left,right,ks[6]);
+ F(right,left,ks[7]);
+ F(left,right,ks[8]);
+ F(right,left,ks[9]);
+ F(left,right,ks[10]);
+ F(right,left,ks[11]);
+ F(left,right,ks[12]);
+ F(right,left,ks[13]);
+ F(left,right,ks[14]);
+ F(right,left,ks[15]);
+
+ /* Inverse permutation, also from Hoey via Outerbridge and Schneier */
+ right = (right << 31) | (right >> 1);
+ work = (left ^ right) & 0xaaaaaaaa;
+ left ^= work;
+ right ^= work;
+ left = (left >> 1) | (left << 31);
+ work = ((left >> 8) ^ right) & 0xff00ff;
+ right ^= work;
+ left ^= work << 8;
+ work = ((left >> 2) ^ right) & 0x33333333;
+ right ^= work;
+ left ^= work << 2;
+ work = ((right >> 16) ^ left) & 0xffff;
+ left ^= work;
+ right ^= work << 16;
+ work = ((right >> 4) ^ left) & 0x0f0f0f0f;
+ left ^= work;
+ right ^= work << 4;
+
+ /* Put the block back into the user's buffer with final swap */
+ block[0] = right >> 24;
+ block[1] = right >> 16;
+ block[2] = right >> 8;
+ block[3] = right;
+ block[4] = left >> 24;
+ block[5] = left >> 16;
+ block[6] = left >> 8;
+ block[7] = left;
+}
+
+/* Key schedule-related tables from FIPS-46 */
+
+/* permuted choice table (key) */
+static unsigned char pc1[] = {
+ 57, 49, 41, 33, 25, 17, 9,
+ 1, 58, 50, 42, 34, 26, 18,
+ 10, 2, 59, 51, 43, 35, 27,
+ 19, 11, 3, 60, 52, 44, 36,
+
+ 63, 55, 47, 39, 31, 23, 15,
+ 7, 62, 54, 46, 38, 30, 22,
+ 14, 6, 61, 53, 45, 37, 29,
+ 21, 13, 5, 28, 20, 12, 4
+};
+
+/* number left rotations of pc1 */
+static unsigned char totrot[] = {
+ 1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28
+};
+
+/* permuted choice key (table) */
+static unsigned char pc2[] = {
+ 14, 17, 11, 24, 1, 5,
+ 3, 28, 15, 6, 21, 10,
+ 23, 19, 12, 4, 26, 8,
+ 16, 7, 27, 20, 13, 2,
+ 41, 52, 31, 37, 47, 55,
+ 30, 40, 51, 45, 33, 48,
+ 44, 49, 39, 56, 34, 53,
+ 46, 42, 50, 36, 29, 32
+};
+
+/* End of DES-defined tables */
+
+
+/* bit 0 is left-most in byte */
+static int bytebit[] = {
+ 0200,0100,040,020,010,04,02,01
+};
+
+
+/* Generate key schedule for encryption or decryption
+ * depending on the value of "decrypt"
+ */
+static void
+deskey(k,key,decrypt)
+DES_KS k; /* Key schedule array */
+unsigned char *key; /* 64 bits (will use only 56) */
+int decrypt; /* 0 = encrypt, 1 = decrypt */
+{
+ unsigned char pc1m[56]; /* place to modify pc1 into */
+ unsigned char pcr[56]; /* place to rotate pc1 into */
+ register int i,j,l;
+ int m;
+ unsigned char ks[8];
+
+ for (j=0; j<56; j++) { /* convert pc1 to bits of key */
+ l=pc1[j]-1; /* integer bit location */
+ m = l & 07; /* find bit */
+ pc1m[j]=(key[l>>3] & /* find which key byte l is in */
+ bytebit[m]) /* and which bit of that byte */
+ ? 1 : 0; /* and store 1-bit result */
+ }
+ for (i=0; i<16; i++) { /* key chunk for each iteration */
+ memset(ks,0,sizeof(ks)); /* Clear key schedule */
+ for (j=0; j<56; j++) /* rotate pc1 the right amount */
+ pcr[j] = pc1m[(l=j+totrot[decrypt? 15-i : i])<(j<28? 28 : 56) ? l: l-28];
+ /* rotate left and right halves independently */
+ for (j=0; j<48; j++){ /* select bits individually */
+ /* check bit that goes to ks[j] */
+ if (pcr[pc2[j]-1]){
+ /* mask it in if it's there */
+ l= j % 6;
+ ks[j/6] |= bytebit[l] >> 2;
+ }
+ }
+ /* Now convert to packed odd/even interleaved form */
+ k[i][0] = ((guint32)ks[0] << 24)
+ | ((guint32)ks[2] << 16)
+ | ((guint32)ks[4] << 8)
+ | ((guint32)ks[6]);
+ k[i][1] = ((guint32)ks[1] << 24)
+ | ((guint32)ks[3] << 16)
+ | ((guint32)ks[5] << 8)
+ | ((guint32)ks[7]);
+ }
+}
diff --git a/camel/camel-service.c b/camel/camel-service.c
new file mode 100644
index 0000000000..13190844e6
--- /dev/null
+++ b/camel/camel-service.c
@@ -0,0 +1,1060 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* camel-service.c : Abstract class for an email service */
+
+/*
+ *
+ * Author :
+ * Bertrand Guiheneuf <bertrand@helixcode.com>
+ *
+ * Copyright 1999-2003 Ximian, Inc. (www.ximian.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <netdb.h>
+#include <errno.h>
+
+#include <sys/poll.h>
+
+#include "e-util/e-msgport.h"
+
+#include "e-util/e-host-utils.h"
+
+#include "camel-service.h"
+#include "camel-session.h"
+#include "camel-exception.h"
+#include "camel-operation.h"
+#include "camel-private.h"
+
+#define d(x)
+#define w(x)
+
+static CamelObjectClass *parent_class = NULL;
+
+/* Returns the class for a CamelService */
+#define CSERV_CLASS(so) CAMEL_SERVICE_CLASS (CAMEL_OBJECT_GET_CLASS(so))
+
+static void construct (CamelService *service, CamelSession *session,
+ CamelProvider *provider, CamelURL *url,
+ CamelException *ex);
+static gboolean service_connect(CamelService *service, CamelException *ex);
+static gboolean service_disconnect(CamelService *service, gboolean clean,
+ CamelException *ex);
+static void cancel_connect (CamelService *service);
+static GList *query_auth_types (CamelService *service, CamelException *ex);
+static char *get_name (CamelService *service, gboolean brief);
+static char *get_path (CamelService *service);
+
+static int service_setv (CamelObject *object, CamelException *ex, CamelArgV *args);
+static int service_getv (CamelObject *object, CamelException *ex, CamelArgGetV *args);
+
+
+static void
+camel_service_class_init (CamelServiceClass *camel_service_class)
+{
+ CamelObjectClass *object_class = CAMEL_OBJECT_CLASS (camel_service_class);
+
+ parent_class = camel_type_get_global_classfuncs (CAMEL_OBJECT_TYPE);
+
+ /* virtual method overloading */
+ object_class->setv = service_setv;
+ object_class->getv = service_getv;
+
+ /* virtual method definition */
+ camel_service_class->construct = construct;
+ camel_service_class->connect = service_connect;
+ camel_service_class->disconnect = service_disconnect;
+ camel_service_class->cancel_connect = cancel_connect;
+ camel_service_class->query_auth_types = query_auth_types;
+ camel_service_class->get_name = get_name;
+ camel_service_class->get_path = get_path;
+}
+
+static void
+camel_service_init (void *o, void *k)
+{
+ CamelService *service = o;
+
+ service->priv = g_malloc0(sizeof(*service->priv));
+ service->priv->connect_lock = e_mutex_new(E_MUTEX_REC);
+ service->priv->connect_op_lock = e_mutex_new(E_MUTEX_SIMPLE);
+}
+
+static void
+camel_service_finalize (CamelObject *object)
+{
+ CamelService *service = CAMEL_SERVICE (object);
+
+ if (service->status == CAMEL_SERVICE_CONNECTED) {
+ CamelException ex;
+
+ camel_exception_init (&ex);
+ CSERV_CLASS (service)->disconnect (service, TRUE, &ex);
+ if (camel_exception_is_set (&ex)) {
+ w(g_warning ("camel_service_finalize: silent disconnect failure: %s",
+ camel_exception_get_description (&ex)));
+ }
+ camel_exception_clear (&ex);
+ }
+
+ if (service->url)
+ camel_url_free (service->url);
+ if (service->session)
+ camel_object_unref (service->session);
+
+ e_mutex_destroy (service->priv->connect_lock);
+ e_mutex_destroy (service->priv->connect_op_lock);
+
+ g_free (service->priv);
+}
+
+
+
+CamelType
+camel_service_get_type (void)
+{
+ static CamelType type = CAMEL_INVALID_TYPE;
+
+ if (type == CAMEL_INVALID_TYPE) {
+ type =
+ camel_type_register (CAMEL_OBJECT_TYPE,
+ "CamelService",
+ sizeof (CamelService),
+ sizeof (CamelServiceClass),
+ (CamelObjectClassInitFunc) camel_service_class_init,
+ NULL,
+ (CamelObjectInitFunc) camel_service_init,
+ camel_service_finalize );
+ }
+
+ return type;
+}
+
+
+static int
+service_setv (CamelObject *object, CamelException *ex, CamelArgV *args)
+{
+ CamelService *service = (CamelService *) object;
+ CamelURL *url = service->url;
+ gboolean reconnect = FALSE;
+ guint32 tag;
+ int i;
+
+ for (i = 0; i < args->argc; i++) {
+ tag = args->argv[i].tag;
+
+ /* make sure this is an arg we're supposed to handle */
+ if ((tag & CAMEL_ARG_TAG) <= CAMEL_SERVICE_ARG_FIRST ||
+ (tag & CAMEL_ARG_TAG) >= CAMEL_SERVICE_ARG_FIRST + 100)
+ continue;
+
+ if (tag == CAMEL_SERVICE_USERNAME) {
+ /* set the username */
+ if (strcmp (url->user, args->argv[i].ca_str) != 0) {
+ camel_url_set_user (url, args->argv[i].ca_str);
+ reconnect = TRUE;
+ }
+ } else if (tag == CAMEL_SERVICE_AUTH) {
+ /* set the auth mechanism */
+ if (strcmp (url->authmech, args->argv[i].ca_str) != 0) {
+ camel_url_set_authmech (url, args->argv[i].ca_str);
+ reconnect = TRUE;
+ }
+ } else if (tag == CAMEL_SERVICE_HOSTNAME) {
+ /* set the hostname */
+ if (strcmp (url->host, args->argv[i].ca_str) != 0) {
+ camel_url_set_host (url, args->argv[i].ca_str);
+ reconnect = TRUE;
+ }
+ } else if (tag == CAMEL_SERVICE_PORT) {
+ /* set the port */
+ if (url->port != args->argv[i].ca_int) {
+ camel_url_set_port (url, args->argv[i].ca_int);
+ reconnect = TRUE;
+ }
+ } else if (tag == CAMEL_SERVICE_PATH) {
+ /* set the path */
+ if (strcmp (url->path, args->argv[i].ca_str) != 0) {
+ camel_url_set_path (url, args->argv[i].ca_str);
+ reconnect = TRUE;
+ }
+ } else {
+ /* error? */
+ continue;
+ }
+
+ /* let our parent know that we've handled this arg */
+ camel_argv_ignore (args, i);
+ }
+
+ /* FIXME: what if we are in the process of connecting? */
+ if (reconnect && service->status == CAMEL_SERVICE_CONNECTED) {
+ /* reconnect the service using the new URL */
+ if (camel_service_disconnect (service, TRUE, ex))
+ camel_service_connect (service, ex);
+ }
+
+ return CAMEL_OBJECT_CLASS (parent_class)->setv (object, ex, args);
+}
+
+static int
+service_getv (CamelObject *object, CamelException *ex, CamelArgGetV *args)
+{
+ CamelService *service = (CamelService *) object;
+ CamelURL *url = service->url;
+ guint32 tag;
+ int i;
+
+ for (i = 0; i < args->argc; i++) {
+ tag = args->argv[i].tag;
+
+ /* make sure this is an arg we're supposed to handle */
+ if ((tag & CAMEL_ARG_TAG) <= CAMEL_SERVICE_ARG_FIRST ||
+ (tag & CAMEL_ARG_TAG) >= CAMEL_SERVICE_ARG_FIRST + 100)
+ continue;
+
+ switch (tag) {
+ case CAMEL_SERVICE_USERNAME:
+ /* get the username */
+ *args->argv[i].ca_str = url->user;
+ break;
+ case CAMEL_SERVICE_AUTH:
+ /* get the auth mechanism */
+ *args->argv[i].ca_str = url->authmech;
+ break;
+ case CAMEL_SERVICE_HOSTNAME:
+ /* get the hostname */
+ *args->argv[i].ca_str = url->host;
+ break;
+ case CAMEL_SERVICE_PORT:
+ /* get the port */
+ *args->argv[i].ca_int = url->port;
+ break;
+ case CAMEL_SERVICE_PATH:
+ /* get the path */
+ *args->argv[i].ca_str = url->path;
+ break;
+ default:
+ /* error? */
+ break;
+ }
+ }
+
+ return CAMEL_OBJECT_CLASS (parent_class)->getv (object, ex, args);
+}
+
+static void
+construct (CamelService *service, CamelSession *session, CamelProvider *provider, CamelURL *url, CamelException *ex)
+{
+ char *err, *url_string;
+
+ if (CAMEL_PROVIDER_NEEDS (provider, CAMEL_URL_PART_USER) &&
+ (url->user == NULL || url->user[0] == '\0')) {
+ err = _("URL '%s' needs a username component");
+ goto fail;
+ } else if (CAMEL_PROVIDER_NEEDS (provider, CAMEL_URL_PART_HOST) &&
+ (url->host == NULL || url->host[0] == '\0')) {
+ err = _("URL '%s' needs a host component");
+ goto fail;
+ } else if (CAMEL_PROVIDER_NEEDS (provider, CAMEL_URL_PART_PATH) &&
+ (url->path == NULL || url->path[0] == '\0')) {
+ err = _("URL '%s' needs a path component");
+ goto fail;
+ }
+
+ service->provider = provider;
+ service->url = camel_url_copy(url);
+ service->session = session;
+ camel_object_ref (session);
+
+ service->status = CAMEL_SERVICE_DISCONNECTED;
+
+ return;
+
+fail:
+ url_string = camel_url_to_string(url, CAMEL_URL_HIDE_PASSWORD);
+ camel_exception_setv(ex, CAMEL_EXCEPTION_SERVICE_URL_INVALID, err, url_string);
+ g_free(url_string);
+}
+
+/**
+ * camel_service_construct:
+ * @service: the CamelService
+ * @session: the session for the service
+ * @provider: the service's provider
+ * @url: the default URL for the service (may be NULL)
+ * @ex: a CamelException
+ *
+ * Constructs a CamelService initialized with the given parameters.
+ **/
+void
+camel_service_construct (CamelService *service, CamelSession *session,
+ CamelProvider *provider, CamelURL *url,
+ CamelException *ex)
+{
+ g_return_if_fail (CAMEL_IS_SERVICE (service));
+ g_return_if_fail (CAMEL_IS_SESSION (session));
+
+ CSERV_CLASS (service)->construct (service, session, provider, url, ex);
+}
+
+
+static gboolean
+service_connect (CamelService *service, CamelException *ex)
+{
+ /* Things like the CamelMboxStore can validly
+ * not define a connect function.
+ */
+ return TRUE;
+}
+
+/**
+ * camel_service_connect:
+ * @service: CamelService object
+ * @ex: a CamelException
+ *
+ * Connect to the service using the parameters it was initialized
+ * with.
+ *
+ * Return value: whether or not the connection succeeded
+ **/
+
+gboolean
+camel_service_connect (CamelService *service, CamelException *ex)
+{
+ gboolean ret = FALSE;
+ gboolean unreg = FALSE;
+
+ g_return_val_if_fail (CAMEL_IS_SERVICE (service), FALSE);
+ g_return_val_if_fail (service->session != NULL, FALSE);
+ g_return_val_if_fail (service->url != NULL, FALSE);
+
+ CAMEL_SERVICE_LOCK (service, connect_lock);
+
+ if (service->status == CAMEL_SERVICE_CONNECTED) {
+ CAMEL_SERVICE_UNLOCK (service, connect_lock);
+ return TRUE;
+ }
+
+ /* Register a separate operation for connecting, so that
+ * the offline code can cancel it.
+ */
+ CAMEL_SERVICE_LOCK (service, connect_op_lock);
+ service->connect_op = camel_operation_registered ();
+ if (!service->connect_op) {
+ service->connect_op = camel_operation_new (NULL, NULL);
+ camel_operation_register (service->connect_op);
+ unreg = TRUE;
+ }
+ CAMEL_SERVICE_UNLOCK (service, connect_op_lock);
+
+ service->status = CAMEL_SERVICE_CONNECTING;
+ ret = CSERV_CLASS (service)->connect (service, ex);
+ service->status = ret ? CAMEL_SERVICE_CONNECTED : CAMEL_SERVICE_DISCONNECTED;
+
+ CAMEL_SERVICE_LOCK (service, connect_op_lock);
+ if (service->connect_op) {
+ if (unreg)
+ camel_operation_unregister (service->connect_op);
+
+ camel_operation_unref (service->connect_op);
+ service->connect_op = NULL;
+ }
+ CAMEL_SERVICE_UNLOCK (service, connect_op_lock);
+
+ CAMEL_SERVICE_UNLOCK (service, connect_lock);
+
+ return ret;
+}
+
+static gboolean
+service_disconnect (CamelService *service, gboolean clean, CamelException *ex)
+{
+ /*service->connect_level--;*/
+
+ /* We let people get away with not having a disconnect
+ * function -- CamelMboxStore, for example.
+ */
+
+ return TRUE;
+}
+
+/**
+ * camel_service_disconnect:
+ * @service: CamelService object
+ * @clean: whether or not to try to disconnect cleanly.
+ * @ex: a CamelException
+ *
+ * Disconnect from the service. If @clean is %FALSE, it should not
+ * try to do any synchronizing or other cleanup of the connection.
+ *
+ * Return value: whether or not the disconnection succeeded without
+ * errors. (Consult @ex if %FALSE.)
+ **/
+gboolean
+camel_service_disconnect (CamelService *service, gboolean clean,
+ CamelException *ex)
+{
+ gboolean res = TRUE;
+ int unreg = FALSE;
+
+ CAMEL_SERVICE_LOCK (service, connect_lock);
+
+ if (service->status != CAMEL_SERVICE_DISCONNECTED
+ && service->status != CAMEL_SERVICE_DISCONNECTING) {
+ CAMEL_SERVICE_LOCK (service, connect_op_lock);
+ service->connect_op = camel_operation_registered ();
+ if (!service->connect_op) {
+ service->connect_op = camel_operation_new (NULL, NULL);
+ camel_operation_register (service->connect_op);
+ unreg = TRUE;
+ }
+ CAMEL_SERVICE_UNLOCK (service, connect_op_lock);
+
+ service->status = CAMEL_SERVICE_DISCONNECTING;
+ res = CSERV_CLASS (service)->disconnect (service, clean, ex);
+ service->status = CAMEL_SERVICE_DISCONNECTED;
+
+ CAMEL_SERVICE_LOCK (service, connect_op_lock);
+ if (unreg)
+ camel_operation_unregister (service->connect_op);
+
+ camel_operation_unref (service->connect_op);
+ service->connect_op = NULL;
+ CAMEL_SERVICE_UNLOCK (service, connect_op_lock);
+ }
+
+ CAMEL_SERVICE_UNLOCK (service, connect_lock);
+
+ return res;
+}
+
+static void
+cancel_connect (CamelService *service)
+{
+ camel_operation_cancel (service->connect_op);
+}
+
+/**
+ * camel_service_cancel_connect:
+ * @service: a service
+ *
+ * If @service is currently attempting to connect to or disconnect
+ * from a server, this causes it to stop and fail. Otherwise it is a
+ * no-op.
+ **/
+void
+camel_service_cancel_connect (CamelService *service)
+{
+ CAMEL_SERVICE_LOCK (service, connect_op_lock);
+ if (service->connect_op)
+ CSERV_CLASS (service)->cancel_connect (service);
+ CAMEL_SERVICE_UNLOCK (service, connect_op_lock);
+}
+
+/**
+ * camel_service_get_url:
+ * @service: a service
+ *
+ * Returns the URL representing a service. The returned URL must be
+ * freed when it is no longer needed. For security reasons, this
+ * routine does not return the password.
+ *
+ * Return value: the url name
+ **/
+char *
+camel_service_get_url (CamelService *service)
+{
+ return camel_url_to_string (service->url, CAMEL_URL_HIDE_PASSWORD);
+}
+
+
+static char *
+get_name (CamelService *service, gboolean brief)
+{
+ w(g_warning ("CamelService::get_name not implemented for `%s'",
+ camel_type_to_name (CAMEL_OBJECT_GET_TYPE (service))));
+ return g_strdup ("???");
+}
+
+/**
+ * camel_service_get_name:
+ * @service: the service
+ * @brief: whether or not to use a briefer form
+ *
+ * This gets the name of the service in a "friendly" (suitable for
+ * humans) form. If @brief is %TRUE, this should be a brief description
+ * such as for use in the folder tree. If @brief is %FALSE, it should
+ * be a more complete and mostly unambiguous description.
+ *
+ * Return value: the description, which the caller must free.
+ **/
+char *
+camel_service_get_name (CamelService *service, gboolean brief)
+{
+ g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL);
+ g_return_val_if_fail (service->url, NULL);
+
+ return CSERV_CLASS (service)->get_name (service, brief);
+}
+
+
+static char *
+get_path (CamelService *service)
+{
+ CamelProvider *prov = service->provider;
+ CamelURL *url = service->url;
+ GString *gpath;
+ char *path;
+
+ /* A sort of ad-hoc default implementation that works for our
+ * current set of services.
+ */
+
+ gpath = g_string_new (service->provider->protocol);
+ if (CAMEL_PROVIDER_ALLOWS (prov, CAMEL_URL_PART_USER)) {
+ if (CAMEL_PROVIDER_ALLOWS (prov, CAMEL_URL_PART_HOST)) {
+ g_string_append_printf (gpath, "/%s@%s",
+ url->user ? url->user : "",
+ url->host ? url->host : "");
+
+ if (url->port)
+ g_string_append_printf (gpath, ":%d", url->port);
+ } else {
+ g_string_append_printf (gpath, "/%s%s", url->user ? url->user : "",
+ CAMEL_PROVIDER_NEEDS (prov, CAMEL_URL_PART_USER) ? "" : "@");
+ }
+ } else if (CAMEL_PROVIDER_ALLOWS (prov, CAMEL_URL_PART_HOST)) {
+ g_string_append_printf (gpath, "/%s%s",
+ CAMEL_PROVIDER_NEEDS (prov, CAMEL_URL_PART_HOST) ? "" : "@",
+ url->host ? url->host : "");
+
+ if (url->port)
+ g_string_append_printf (gpath, ":%d", url->port);
+ }
+
+ if (CAMEL_PROVIDER_NEEDS (prov, CAMEL_URL_PART_PATH))
+ g_string_append_printf (gpath, "%s%s", *url->path == '/' ? "" : "/", url->path);
+
+ path = gpath->str;
+ g_string_free (gpath, FALSE);
+
+ return path;
+}
+
+/**
+ * camel_service_get_path:
+ * @service: the service
+ *
+ * This gets a valid UNIX relative path describing the service, which
+ * is guaranteed to be different from the path returned for any
+ * different service. This path MUST start with the name of the
+ * provider, followed by a "/", but after that, it is up to the
+ * provider.
+ *
+ * Return value: the path, which the caller must free.
+ **/
+char *
+camel_service_get_path (CamelService *service)
+{
+ g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL);
+ g_return_val_if_fail (service->url, NULL);
+
+ return CSERV_CLASS (service)->get_path (service);
+}
+
+
+/**
+ * camel_service_get_session:
+ * @service: a service
+ *
+ * Returns the CamelSession associated with the service.
+ *
+ * Return value: the session
+ **/
+CamelSession *
+camel_service_get_session (CamelService *service)
+{
+ return service->session;
+}
+
+/**
+ * camel_service_get_provider:
+ * @service: a service
+ *
+ * Returns the CamelProvider associated with the service.
+ *
+ * Return value: the provider
+ **/
+CamelProvider *
+camel_service_get_provider (CamelService *service)
+{
+ return service->provider;
+}
+
+static GList *
+query_auth_types (CamelService *service, CamelException *ex)
+{
+ return NULL;
+}
+
+/**
+ * camel_service_query_auth_types:
+ * @service: a CamelService
+ * @ex: a CamelException
+ *
+ * This is used by the mail source wizard to get the list of
+ * authentication types supported by the protocol, and information
+ * about them.
+ *
+ * Return value: a list of CamelServiceAuthType records. The caller
+ * must free the list with g_list_free() when it is done with it.
+ **/
+GList *
+camel_service_query_auth_types (CamelService *service, CamelException *ex)
+{
+ GList *ret;
+
+ /* note that we get the connect lock here, which means the callee
+ must not call the connect functions itself */
+ CAMEL_SERVICE_LOCK (service, connect_lock);
+ ret = CSERV_CLASS (service)->query_auth_types (service, ex);
+ CAMEL_SERVICE_UNLOCK (service, connect_lock);
+
+ return ret;
+}
+
+/* ********************************************************************** */
+struct _addrinfo_msg {
+ EMsg msg;
+ unsigned int cancelled:1;
+
+ /* for host lookup */
+ const char *name;
+ const char *service;
+ int result;
+ const struct addrinfo *hints;
+ struct addrinfo **res;
+
+ /* for host lookup emulation */
+#ifdef NEED_ADDRINFO
+ struct hostent hostbuf;
+ int hostbuflen;
+ char *hostbufmem;
+#endif
+
+ /* for name lookup */
+ const struct sockaddr *addr;
+ socklen_t addrlen;
+ char *host;
+ int hostlen;
+ char *serv;
+ int servlen;
+ int flags;
+};
+
+static void
+cs_freeinfo(struct _addrinfo_msg *msg)
+{
+ g_free(msg->host);
+ g_free(msg->serv);
+#ifdef NEED_ADDRINFO
+ g_free(msg->hostbufmem);
+#endif
+ g_free(msg);
+}
+
+/* returns -1 if cancelled */
+static int
+cs_waitinfo(void *(worker)(void *), struct _addrinfo_msg *msg, const char *error, CamelException *ex)
+{
+ EMsgPort *reply_port;
+ pthread_t id;
+ int err, cancel_fd, cancel = 0, fd;
+
+ cancel_fd = camel_operation_cancel_fd(NULL);
+ if (cancel_fd == -1) {
+ worker(msg);
+ return 0;
+ }
+
+ reply_port = msg->msg.reply_port = e_msgport_new();
+ fd = e_msgport_fd(msg->msg.reply_port);
+ if ((err = pthread_create(&id, NULL, worker, msg)) == 0) {
+ struct pollfd polls[2];
+ int status;
+
+ polls[0].fd = fd;
+ polls[0].events = POLLIN;
+ polls[1].fd = cancel_fd;
+ polls[1].events = POLLIN;
+
+ d(printf("waiting for name return/cancellation in main process\n"));
+ do {
+ polls[0].revents = 0;
+ polls[1].revents = 0;
+ status = poll(polls, 2, -1);
+ } while (status == -1 && errno == EINTR);
+
+ if (status == -1 || (polls[1].revents & POLLIN)) {
+ if (status == -1)
+ camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, "%s: %s", error, g_strerror(errno));
+ else
+ camel_exception_setv(ex, CAMEL_EXCEPTION_USER_CANCEL, _("Cancelled"));
+
+ /* We cancel so if the thread impl is decent it causes immediate exit.
+ We detach so we dont need to wait for it to exit if it isn't.
+ We check the reply port incase we had a reply in the mean time, which we free later */
+ d(printf("Cancelling lookup thread and leaving it\n"));
+ msg->cancelled = 1;
+ pthread_detach(id);
+ pthread_cancel(id);
+ cancel = 1;
+ } else {
+ struct _addrinfo_msg *reply = (struct _addrinfo_msg *)e_msgport_get(reply_port);
+
+ g_assert(reply == msg);
+ d(printf("waiting for child to exit\n"));
+ pthread_join(id, NULL);
+ d(printf("child done\n"));
+ }
+ } else {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, "%s: %s: %s", error, _("cannot create thread"), g_strerror(err));
+ }
+ e_msgport_destroy(reply_port);
+
+ return cancel;
+}
+
+#ifdef NEED_ADDRINFO
+static void *
+cs_getaddrinfo(void *data)
+{
+ struct _addrinfo_msg *msg = data;
+ int herr;
+ struct hostent h;
+ struct addrinfo *res, *last = NULL;
+ struct sockaddr_in *sin;
+ in_port_t port = 0;
+ int i;
+
+ /* This is a pretty simplistic emulation of getaddrinfo */
+
+ while ((msg->result = e_gethostbyname_r(msg->name, &h, msg->hostbufmem, msg->hostbuflen, &herr)) == ERANGE) {
+ pthread_testcancel();
+ msg->hostbuflen *= 2;
+ msg->hostbufmem = g_realloc(msg->hostbufmem, msg->hostbuflen);
+ }
+
+ /* If we got cancelled, dont reply, just free it */
+ if (msg->cancelled)
+ goto cancel;
+
+ /* FIXME: map error numbers across */
+ if (msg->result != 0)
+ goto reply;
+
+ /* check hints matched */
+ if (msg->hints && msg->hints->ai_family && msg->hints->ai_family != h.h_addrtype) {
+ msg->result = EAI_FAMILY;
+ goto reply;
+ }
+
+ /* we only support ipv4 for this interface, even if it could supply ipv6 */
+ if (h.h_addrtype != AF_INET) {
+ msg->result = EAI_FAMILY;
+ goto reply;
+ }
+
+ /* check service mapping */
+ if (msg->service) {
+ const char *p = msg->service;
+
+ while (*p) {
+ if (*p < '0' || *p > '9')
+ break;
+ p++;
+ }
+
+ if (*p) {
+ const char *socktype = NULL;
+ struct servent *serv;
+
+ if (msg->hints && msg->hints->ai_socktype) {
+ if (msg->hints->ai_socktype == SOCK_STREAM)
+ socktype = "tcp";
+ else if (msg->hints->ai_socktype == SOCK_DGRAM)
+ socktype = "udp";
+ }
+
+ serv = getservbyname(msg->service, socktype);
+ if (serv == NULL) {
+ msg->result = EAI_NONAME;
+ goto reply;
+ }
+ port = serv->s_port;
+ } else {
+ port = htons(strtoul(msg->service, NULL, 10));
+ }
+ }
+
+ for (i=0;h.h_addr_list[i];i++) {
+ res = g_malloc0(sizeof(*res));
+ if (msg->hints) {
+ res->ai_flags = msg->hints->ai_flags;
+ if (msg->hints->ai_flags & AI_CANONNAME)
+ res->ai_canonname = g_strdup(h.h_name);
+ res->ai_socktype = msg->hints->ai_socktype;
+ res->ai_protocol = msg->hints->ai_protocol;
+ } else {
+ res->ai_flags = 0;
+ res->ai_socktype = SOCK_STREAM; /* fudge */
+ res->ai_protocol = 0; /* fudge */
+ }
+ res->ai_family = AF_INET;
+ res->ai_addrlen = sizeof(*sin);
+ res->ai_addr = g_malloc(sizeof(*sin));
+ sin = (struct sockaddr_in *)res->ai_addr;
+ sin->sin_family = AF_INET;
+ sin->sin_port = port;
+ memcpy(&sin->sin_addr, h.h_addr_list[i], sizeof(sin->sin_addr));
+
+ if (last == NULL) {
+ *msg->res = last = res;
+ } else {
+ last->ai_next = res;
+ last = res;
+ }
+ }
+reply:
+ e_msgport_reply((EMsg *)msg);
+ return NULL;
+cancel:
+ cs_freeinfo(msg);
+ return NULL;
+}
+#else
+static void *
+cs_getaddrinfo(void *data)
+{
+ struct _addrinfo_msg *info = data;
+
+ info->result = getaddrinfo(info->name, info->service, info->hints, info->res);
+
+ if (info->cancelled) {
+ g_free(info);
+ } else {
+ e_msgport_reply((EMsg *)info);
+ }
+
+ return NULL;
+}
+#endif /* NEED_ADDRINFO */
+
+struct addrinfo *
+camel_getaddrinfo(const char *name, const char *service, const struct addrinfo *hints, CamelException *ex)
+{
+ struct _addrinfo_msg *msg;
+ struct addrinfo *res = NULL;
+#ifndef ENABLE_IPv6
+ struct addrinfo myhints;
+#endif
+ g_return_val_if_fail(name != NULL, NULL);
+
+ if (camel_operation_cancel_check(NULL)) {
+ camel_exception_set(ex, CAMEL_EXCEPTION_USER_CANCEL, _("Cancelled"));
+ return NULL;
+ }
+
+ camel_operation_start_transient(NULL, _("Resolving: %s"), name);
+
+ /* force ipv4 addresses only */
+#ifndef ENABLE_IPv6
+ if (hints == NULL)
+ memset(&myhints, 0, sizeof(myhints));
+ else
+ memcpy (&myhints, hints, sizeof (myhints));
+
+ myhints.ai_family = AF_INET;
+ hints = &myhints;
+#endif
+
+ msg = g_malloc0(sizeof(*msg));
+ msg->name = name;
+ msg->service = service;
+ msg->hints = hints;
+ msg->res = &res;
+#ifdef NEED_ADDRINFO
+ msg->hostbuflen = 1024;
+ msg->hostbufmem = g_malloc(msg->hostbuflen);
+#endif
+ if (cs_waitinfo(cs_getaddrinfo, msg, _("Host lookup failed"), ex) == 0) {
+ if (msg->result != 0)
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, _("Host lookup failed: %s: %s"),
+ name, gai_strerror (msg->result));
+
+ cs_freeinfo(msg);
+ } else
+ res = NULL;
+
+ camel_operation_end(NULL);
+
+ return res;
+}
+
+void
+camel_freeaddrinfo(struct addrinfo *host)
+{
+#ifdef NEED_ADDRINFO
+ while (host) {
+ struct addrinfo *next = host->ai_next;
+
+ g_free(host->ai_canonname);
+ g_free(host->ai_addr);
+ g_free(host);
+ host = next;
+ }
+#else
+ freeaddrinfo(host);
+#endif
+}
+
+#ifdef NEED_ADDRINFO
+static void *
+cs_getnameinfo(void *data)
+{
+ struct _addrinfo_msg *msg = data;
+ int herr;
+ struct hostent h;
+ struct sockaddr_in *sin = (struct sockaddr_in *)msg->addr;
+
+ /* FIXME: error code */
+ if (msg->addr->sa_family != AF_INET) {
+ msg->result = -1;
+ return NULL;
+ }
+
+ /* FIXME: honour getnameinfo flags: do we care, not really */
+
+ while ((msg->result = e_gethostbyaddr_r((const char *)&sin->sin_addr, sizeof(sin->sin_addr), AF_INET, &h,
+ msg->hostbufmem, msg->hostbuflen, &herr)) == ERANGE) {
+ pthread_testcancel ();
+ msg->hostbuflen *= 2;
+ msg->hostbufmem = g_realloc(msg->hostbufmem, msg->hostbuflen);
+ }
+
+ if (msg->cancelled)
+ goto cancel;
+
+ if (msg->host) {
+ g_free(msg->host);
+ if (msg->result == 0 && h.h_name && h.h_name[0]) {
+ msg->host = g_strdup(h.h_name);
+ } else {
+ unsigned char *in = (unsigned char *)&sin->sin_addr;
+
+ /* sin_addr is always network order which is big-endian */
+ msg->host = g_strdup_printf("%u.%u.%u.%u", in[0], in[1], in[2], in[3]);
+ }
+ }
+
+ /* we never actually use this anyway */
+ if (msg->serv)
+ sprintf(msg->serv, "%d", sin->sin_port);
+
+ e_msgport_reply((EMsg *)msg);
+ return NULL;
+cancel:
+ cs_freeinfo(msg);
+ return NULL;
+}
+#else
+static void *
+cs_getnameinfo(void *data)
+{
+ struct _addrinfo_msg *msg = data;
+
+ /* there doens't appear to be a return code which says host or serv buffers are too short, lengthen them */
+ msg->result = getnameinfo(msg->addr, msg->addrlen, msg->host, msg->hostlen, msg->serv, msg->servlen, msg->flags);
+
+ if (msg->cancelled)
+ cs_freeinfo(msg);
+ else
+ e_msgport_reply((EMsg *)msg);
+
+ return NULL;
+}
+#endif
+
+int
+camel_getnameinfo(const struct sockaddr *sa, socklen_t salen, char **host, char **serv, int flags, CamelException *ex)
+{
+ struct _addrinfo_msg *msg;
+ int result;
+
+ if (camel_operation_cancel_check(NULL)) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL, _("Cancelled"));
+ return -1;
+ }
+
+ camel_operation_start_transient(NULL, _("Resolving address"));
+
+ msg = g_malloc0(sizeof(*msg));
+ msg->addr = sa;
+ msg->addrlen = salen;
+ if (host) {
+ msg->hostlen = NI_MAXHOST;
+ msg->host = g_malloc(msg->hostlen);
+ msg->host[0] = 0;
+ }
+ if (serv) {
+ msg->servlen = NI_MAXSERV;
+ msg->serv = g_malloc(msg->servlen);
+ msg->serv[0] = 0;
+ }
+ msg->flags = flags;
+#ifdef NEED_ADDRINFO
+ msg->hostbuflen = 1024;
+ msg->hostbufmem = g_malloc(msg->hostbuflen);
+#endif
+ cs_waitinfo(cs_getnameinfo, msg, _("Name lookup failed"), ex);
+
+ if ((result = msg->result) != 0)
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, _("Name lookup failed: %s"),
+ gai_strerror (result));
+
+ if (host)
+ *host = g_strdup(msg->host);
+ if (serv)
+ *serv = g_strdup(msg->serv);
+
+ g_free(msg->host);
+ g_free(msg->serv);
+ g_free(msg);
+
+ camel_operation_end(NULL);
+
+ return result;
+}
+
diff --git a/camel/camel-service.h b/camel/camel-service.h
new file mode 100644
index 0000000000..f49472cc5a
--- /dev/null
+++ b/camel/camel-service.h
@@ -0,0 +1,202 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* camel-service.h : Abstract class for an email service */
+
+/*
+ *
+ * Author :
+ * Bertrand Guiheneuf <bertrand@helixcode.com>
+ *
+ * Copyright 1999, 2000 Ximian, Inc. (www.ximian.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+
+#ifndef CAMEL_SERVICE_H
+#define CAMEL_SERVICE_H 1
+
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif /* __cplusplus }*/
+
+#include <netdb.h>
+#include <camel/camel-object.h>
+#include <camel/camel-url.h>
+#include <camel/camel-provider.h>
+#include <camel/camel-operation.h>
+
+#define CAMEL_SERVICE_TYPE (camel_service_get_type ())
+#define CAMEL_SERVICE(obj) (CAMEL_CHECK_CAST((obj), CAMEL_SERVICE_TYPE, CamelService))
+#define CAMEL_SERVICE_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), CAMEL_SERVICE_TYPE, CamelServiceClass))
+#define CAMEL_IS_SERVICE(o) (CAMEL_CHECK_TYPE((o), CAMEL_SERVICE_TYPE))
+
+enum {
+ CAMEL_SERVICE_ARG_FIRST = CAMEL_ARG_FIRST + 100,
+ CAMEL_SERVICE_ARG_USERNAME,
+ CAMEL_SERVICE_ARG_AUTH,
+ CAMEL_SERVICE_ARG_HOSTNAME,
+ CAMEL_SERVICE_ARG_PORT,
+ CAMEL_SERVICE_ARG_PATH,
+};
+
+#define CAMEL_SERVICE_USERNAME (CAMEL_SERVICE_ARG_USERNAME | CAMEL_ARG_STR)
+#define CAMEL_SERVICE_AUTH (CAMEL_SERVICE_ARG_AUTH | CAMEL_ARG_STR)
+#define CAMEL_SERVICE_HOSTNAME (CAMEL_SERVICE_ARG_HOSTNAME | CAMEL_ARG_STR)
+#define CAMEL_SERVICE_PORT (CAMEL_SERVICE_ARG_PORT | CAMEL_ARG_INT)
+#define CAMEL_SERVICE_PATH (CAMEL_SERVICE_ARG_PATH | CAMEL_ARG_STR)
+
+typedef enum {
+ CAMEL_SERVICE_DISCONNECTED,
+ CAMEL_SERVICE_CONNECTING,
+ CAMEL_SERVICE_CONNECTED,
+ CAMEL_SERVICE_DISCONNECTING
+} CamelServiceConnectionStatus;
+
+struct _CamelService {
+ CamelObject parent_object;
+ struct _CamelServicePrivate *priv;
+
+ CamelSession *session;
+ CamelProvider *provider;
+ CamelServiceConnectionStatus status;
+ CamelOperation *connect_op;
+ CamelURL *url;
+};
+
+
+typedef struct {
+ CamelObjectClass parent_class;
+
+ void (*construct) (CamelService *service,
+ CamelSession *session,
+ CamelProvider *provider,
+ CamelURL *url,
+ CamelException *ex);
+
+ gboolean (*connect) (CamelService *service,
+ CamelException *ex);
+ gboolean (*disconnect) (CamelService *service,
+ gboolean clean,
+ CamelException *ex);
+ void (*cancel_connect) (CamelService *service);
+
+ GList * (*query_auth_types) (CamelService *service,
+ CamelException *ex);
+
+ char * (*get_name) (CamelService *service,
+ gboolean brief);
+ char * (*get_path) (CamelService *service);
+
+} CamelServiceClass;
+
+
+/* query_auth_types returns a GList of these */
+typedef struct {
+ char *name; /* user-friendly name */
+ char *description;
+ char *authproto;
+
+ gboolean need_password; /* needs a password to authenticate */
+} CamelServiceAuthType;
+
+
+/* public methods */
+void camel_service_construct (CamelService *service,
+ CamelSession *session,
+ CamelProvider *provider,
+ CamelURL *url,
+ CamelException *ex);
+gboolean camel_service_connect (CamelService *service,
+ CamelException *ex);
+gboolean camel_service_disconnect (CamelService *service,
+ gboolean clean,
+ CamelException *ex);
+void camel_service_cancel_connect (CamelService *service);
+char * camel_service_get_url (CamelService *service);
+char * camel_service_get_name (CamelService *service,
+ gboolean brief);
+char * camel_service_get_path (CamelService *service);
+CamelSession * camel_service_get_session (CamelService *service);
+CamelProvider * camel_service_get_provider (CamelService *service);
+GList * camel_service_query_auth_types (CamelService *service,
+ CamelException *ex);
+
+#ifdef NEED_ADDRINFO
+/* Some of this is copied from GNU's netdb.h
+
+ Copyright (C) 1996-2002, 2003, 2004 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+*/
+struct addrinfo {
+ int ai_flags;
+ int ai_family;
+ int ai_socktype;
+ int ai_protocol;
+ size_t ai_addrlen;
+ struct sockaddr *ai_addr;
+ char *ai_canonname;
+ struct addrinfo *ai_next;
+};
+
+#define AI_CANONNAME 0x0002 /* Request for canonical name. */
+#define AI_NUMERICHOST 0x0004 /* Don't use name resolution. */
+
+/* Error values for `getaddrinfo' function. */
+#define EAI_BADFLAGS -1 /* Invalid value for `ai_flags' field. */
+#define EAI_NONAME -2 /* NAME or SERVICE is unknown. */
+#define EAI_AGAIN -3 /* Temporary failure in name resolution. */
+#define EAI_FAIL -4 /* Non-recoverable failure in name res. */
+#define EAI_NODATA -5 /* No address associated with NAME. */
+#define EAI_FAMILY -6 /* `ai_family' not supported. */
+#define EAI_SOCKTYPE -7 /* `ai_socktype' not supported. */
+#define EAI_SERVICE -8 /* SERVICE not supported for `ai_socktype'. */
+#define EAI_ADDRFAMILY -9 /* Address family for NAME not supported. */
+#define EAI_MEMORY -10 /* Memory allocation failure. */
+#define EAI_SYSTEM -11 /* System error returned in `errno'. */
+#define EAI_OVERFLOW -12 /* Argument buffer overflow. */
+
+#define NI_MAXHOST 1025
+#define NI_MAXSERV 32
+
+#define NI_NUMERICHOST 1 /* Don't try to look up hostname. */
+#define NI_NUMERICSERV 2 /* Don't convert port number to name. */
+#define NI_NOFQDN 4 /* Only return nodename portion. */
+#define NI_NAMEREQD 8 /* Don't return numeric addresses. */
+#define NI_DGRAM 16 /* Look up UDP service rather than TCP. */
+#endif
+
+/* new hostname interfaces */
+struct addrinfo *camel_getaddrinfo(const char *name, const char *service,
+ const struct addrinfo *hints, CamelException *ex);
+void camel_freeaddrinfo(struct addrinfo *host);
+int camel_getnameinfo(const struct sockaddr *sa, socklen_t salen, char **host, char **serv,
+ int flags, CamelException *ex);
+
+/* Standard Camel function */
+CamelType camel_service_get_type (void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* CAMEL_SERVICE_H */
+
diff --git a/camel/camel-smime-context.c b/camel/camel-smime-context.c
new file mode 100644
index 0000000000..80b10081a5
--- /dev/null
+++ b/camel/camel-smime-context.c
@@ -0,0 +1,1054 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Jeffrey Stedfast <fejj@ximian.com>
+ * Michael Zucchi <notzed@ximian.com>
+ *
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1994-2000 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Copyright 2003 Ximian, Inc. (www.ximian.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef ENABLE_SMIME
+
+#include "nss.h"
+#include <cms.h>
+#include <cert.h>
+#include <certdb.h>
+#include <pkcs11.h>
+#include <smime.h>
+#include <pkcs11t.h>
+#include <pk11func.h>
+
+#include <errno.h>
+
+#include <camel/camel-exception.h>
+#include <camel/camel-stream-mem.h>
+#include <camel/camel-data-wrapper.h>
+
+#include <camel/camel-mime-part.h>
+#include <camel/camel-multipart-signed.h>
+#include <camel/camel-stream-fs.h>
+#include <camel/camel-stream-filter.h>
+#include <camel/camel-mime-filter-basic.h>
+#include <camel/camel-mime-filter-canon.h>
+
+#include "camel-smime-context.h"
+#include "camel-operation.h"
+
+#define d(x)
+
+struct _CamelSMIMEContextPrivate {
+ CERTCertDBHandle *certdb;
+
+ char *encrypt_key;
+ camel_smime_sign_t sign_mode;
+
+ int password_tries;
+ unsigned int send_encrypt_key_prefs:1;
+};
+
+static CamelCipherContextClass *parent_class = NULL;
+
+/* used for decode content callback, for streaming decode */
+static void
+sm_write_stream(void *arg, const char *buf, unsigned long len)
+{
+ camel_stream_write((CamelStream *)arg, buf, len);
+}
+
+static PK11SymKey *
+sm_decrypt_key(void *arg, SECAlgorithmID *algid)
+{
+ printf("Decrypt key called\n");
+ return (PK11SymKey *)arg;
+}
+
+/**
+ * camel_smime_context_new:
+ * @session: session
+ *
+ * Creates a new sm cipher context object.
+ *
+ * Returns a new sm cipher context object.
+ **/
+CamelCipherContext *
+camel_smime_context_new(CamelSession *session)
+{
+ CamelCipherContext *cipher;
+ CamelSMIMEContext *ctx;
+
+ g_return_val_if_fail(CAMEL_IS_SESSION(session), NULL);
+
+ ctx =(CamelSMIMEContext *) camel_object_new(camel_smime_context_get_type());
+
+ cipher =(CamelCipherContext *) ctx;
+ cipher->session = session;
+ camel_object_ref(session);
+
+ return cipher;
+}
+
+void
+camel_smime_context_set_encrypt_key(CamelSMIMEContext *context, gboolean use, const char *key)
+{
+ context->priv->send_encrypt_key_prefs = use;
+ g_free(context->priv->encrypt_key);
+ context->priv->encrypt_key = g_strdup(key);
+}
+
+/* set signing mode, clearsigned multipart/signed or enveloped */
+void
+camel_smime_context_set_sign_mode(CamelSMIMEContext *context, camel_smime_sign_t type)
+{
+ context->priv->sign_mode = type;
+}
+
+/* TODO: This is suboptimal, but the only other solution is to pass around NSSCMSMessages */
+guint32
+camel_smime_context_describe_part(CamelSMIMEContext *context, CamelMimePart *part)
+{
+ guint32 flags = 0;
+ CamelContentType *ct;
+ const char *tmp;
+
+ ct = camel_mime_part_get_content_type(part);
+
+ if (camel_content_type_is(ct, "multipart", "signed")) {
+ tmp = camel_content_type_param(ct, "protocol");
+ if (tmp &&
+ (g_ascii_strcasecmp(tmp, ((CamelCipherContext *)context)->sign_protocol) == 0
+ || g_ascii_strcasecmp(tmp, "application/pkcs7-signature") == 0))
+ flags = CAMEL_SMIME_SIGNED;
+ } else if (camel_content_type_is(ct, "application", "x-pkcs7-mime")) {
+ CamelStreamMem *istream;
+ NSSCMSMessage *cmsg;
+ NSSCMSDecoderContext *dec;
+
+ /* FIXME: stream this to the decoder incrementally */
+ istream = (CamelStreamMem *)camel_stream_mem_new();
+ camel_data_wrapper_decode_to_stream(camel_medium_get_content_object((CamelMedium *)part), (CamelStream *)istream);
+ camel_stream_reset((CamelStream *)istream);
+
+ dec = NSS_CMSDecoder_Start(NULL,
+ NULL, NULL,
+ NULL, NULL, /* password callback */
+ NULL, NULL); /* decrypt key callback */
+
+ NSS_CMSDecoder_Update(dec, istream->buffer->data, istream->buffer->len);
+ camel_object_unref(istream);
+
+ cmsg = NSS_CMSDecoder_Finish(dec);
+ if (cmsg) {
+ if (NSS_CMSMessage_IsSigned(cmsg)) {
+ printf("message is signed\n");
+ flags |= CAMEL_SMIME_SIGNED;
+ }
+
+ if (NSS_CMSMessage_IsEncrypted(cmsg)) {
+ printf("message is encrypted\n");
+ flags |= CAMEL_SMIME_ENCRYPTED;
+ }
+#if 0
+ if (NSS_CMSMessage_ContainsCertsOrCrls(cmsg)) {
+ printf("message contains certs or crls\n");
+ flags |= CAMEL_SMIME_CERTS;
+ }
+#endif
+ NSS_CMSMessage_Destroy(cmsg);
+ } else {
+ printf("Message could not be parsed\n");
+ }
+ }
+
+ return flags;
+}
+
+static const char *
+sm_hash_to_id(CamelCipherContext *context, CamelCipherHash hash)
+{
+ switch(hash) {
+ case CAMEL_CIPHER_HASH_MD5:
+ return "md5";
+ case CAMEL_CIPHER_HASH_SHA1:
+ case CAMEL_CIPHER_HASH_DEFAULT:
+ return "sha1";
+ default:
+ return NULL;
+ }
+}
+
+static CamelCipherHash
+sm_id_to_hash(CamelCipherContext *context, const char *id)
+{
+ if (id) {
+ if (!strcmp(id, "md5"))
+ return CAMEL_CIPHER_HASH_MD5;
+ else if (!strcmp(id, "sha1"))
+ return CAMEL_CIPHER_HASH_SHA1;
+ }
+
+ return CAMEL_CIPHER_HASH_DEFAULT;
+}
+
+static NSSCMSMessage *
+sm_signing_cmsmessage(CamelSMIMEContext *context, const char *nick, SECOidTag hash, int detached, CamelException *ex)
+{
+ struct _CamelSMIMEContextPrivate *p = context->priv;
+ NSSCMSMessage *cmsg = NULL;
+ NSSCMSContentInfo *cinfo;
+ NSSCMSSignedData *sigd;
+ NSSCMSSignerInfo *signerinfo;
+ CERTCertificate *cert= NULL, *ekpcert = NULL;
+
+ if ((cert = CERT_FindUserCertByUsage(p->certdb,
+ (char *)nick,
+ certUsageEmailSigner,
+ PR_FALSE,
+ NULL)) == NULL) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot find certificate for '%s'"), nick);
+ return NULL;
+ }
+
+ cmsg = NSS_CMSMessage_Create(NULL); /* create a message on its own pool */
+ if (cmsg == NULL) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot create CMS message"));
+ goto fail;
+ }
+
+ if ((sigd = NSS_CMSSignedData_Create(cmsg)) == NULL) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot create CMS signedData"));
+ goto fail;
+ }
+
+ cinfo = NSS_CMSMessage_GetContentInfo(cmsg);
+ if (NSS_CMSContentInfo_SetContent_SignedData(cmsg, cinfo, sigd) != SECSuccess) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot attach CMS signedData"));
+ goto fail;
+ }
+
+ /* if !detatched, the contentinfo will alloc a data item for us */
+ cinfo = NSS_CMSSignedData_GetContentInfo(sigd);
+ if (NSS_CMSContentInfo_SetContent_Data(cmsg, cinfo, NULL, detached) != SECSuccess) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot attach CMS data"));
+ goto fail;
+ }
+
+ signerinfo = NSS_CMSSignerInfo_Create(cmsg, cert, hash);
+ if (signerinfo == NULL) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot create CMS SignerInfo"));
+ goto fail;
+ }
+
+ /* we want the cert chain included for this one */
+ if (NSS_CMSSignerInfo_IncludeCerts(signerinfo, NSSCMSCM_CertChain, certUsageEmailSigner) != SECSuccess) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot find cert chain"));
+ goto fail;
+ }
+
+ /* SMIME RFC says signing time should always be added */
+ if (NSS_CMSSignerInfo_AddSigningTime(signerinfo, PR_Now()) != SECSuccess) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot add CMS SigningTime"));
+ goto fail;
+ }
+
+#if 0
+ /* this can but needn't be added. not sure what general usage is */
+ if (NSS_CMSSignerInfo_AddSMIMECaps(signerinfo) != SECSuccess) {
+ fprintf(stderr, "ERROR: cannot add SMIMECaps attribute.\n");
+ goto loser;
+ }
+#endif
+
+ /* Check if we need to send along our return encrypt cert, rfc2633 2.5.3 */
+ if (p->send_encrypt_key_prefs) {
+ CERTCertificate *enccert = NULL;
+
+ if (p->encrypt_key) {
+ /* encrypt key has its own nick */
+ if ((ekpcert = CERT_FindUserCertByUsage(
+ p->certdb,
+ p->encrypt_key,
+ certUsageEmailRecipient, PR_FALSE, NULL)) == NULL) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, _("Encryption cert for '%s' does not exist"), p->encrypt_key);
+ goto fail;
+ }
+ enccert = ekpcert;
+ } else if (CERT_CheckCertUsage(cert, certUsageEmailRecipient) == SECSuccess) {
+ /* encrypt key is signing key */
+ enccert = cert;
+ } else {
+ /* encrypt key uses same nick */
+ if ((ekpcert = CERT_FindUserCertByUsage(
+ p->certdb, (char *)nick,
+ certUsageEmailRecipient, PR_FALSE, NULL)) == NULL) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, _("Encryption cert for '%s' does not exist"), nick);
+ goto fail;
+ }
+ enccert = ekpcert;
+ }
+
+ if (NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs(signerinfo, enccert, p->certdb) != SECSuccess) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot add SMIMEEncKeyPrefs attribute"));
+ goto fail;
+ }
+
+ if (NSS_CMSSignerInfo_AddMSSMIMEEncKeyPrefs(signerinfo, enccert, p->certdb) != SECSuccess) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot add MS SMIMEEncKeyPrefs attribute"));
+ goto fail;
+ }
+
+ if (ekpcert != NULL && NSS_CMSSignedData_AddCertificate(sigd, ekpcert) != SECSuccess) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot add encryption certificate"));
+ goto fail;
+ }
+ }
+
+ if (NSS_CMSSignedData_AddSignerInfo(sigd, signerinfo) != SECSuccess) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot add CMS SignerInfo"));
+ goto fail;
+ }
+
+ if (ekpcert)
+ CERT_DestroyCertificate(ekpcert);
+
+ if (cert)
+ CERT_DestroyCertificate(cert);
+
+ return cmsg;
+fail:
+ if (ekpcert)
+ CERT_DestroyCertificate(ekpcert);
+
+ if (cert)
+ CERT_DestroyCertificate(cert);
+
+ NSS_CMSMessage_Destroy(cmsg);
+
+ return NULL;
+}
+
+static int
+sm_sign(CamelCipherContext *context, const char *userid, CamelCipherHash hash, CamelMimePart *ipart, CamelMimePart *opart, CamelException *ex)
+{
+ int res = -1;
+ NSSCMSMessage *cmsg;
+ CamelStream *ostream, *istream;
+ SECOidTag sechash;
+ NSSCMSEncoderContext *enc;
+ CamelDataWrapper *dw;
+ CamelContentType *ct;
+
+ switch (hash) {
+ case CAMEL_CIPHER_HASH_SHA1:
+ case CAMEL_CIPHER_HASH_DEFAULT:
+ default:
+ sechash = SEC_OID_SHA1;
+ break;
+ case CAMEL_CIPHER_HASH_MD5:
+ sechash = SEC_OID_MD5;
+ break;
+ }
+
+ cmsg = sm_signing_cmsmessage((CamelSMIMEContext *)context, userid, sechash,
+ ((CamelSMIMEContext *)context)->priv->sign_mode == CAMEL_SMIME_SIGN_CLEARSIGN, ex);
+ if (cmsg == NULL)
+ return -1;
+
+ ostream = camel_stream_mem_new();
+
+ /* FIXME: stream this, we stream output at least */
+ istream = camel_stream_mem_new();
+ if (camel_cipher_canonical_to_stream(ipart,
+ CAMEL_MIME_FILTER_CANON_STRIP
+ |CAMEL_MIME_FILTER_CANON_CRLF
+ |CAMEL_MIME_FILTER_CANON_FROM, istream) == -1) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Could not generate signing data: %s"), g_strerror(errno));
+ goto fail;
+ }
+
+ enc = NSS_CMSEncoder_Start(cmsg,
+ sm_write_stream, ostream, /* DER output callback */
+ NULL, NULL, /* destination storage */
+ NULL, NULL, /* password callback */
+ NULL, NULL, /* decrypt key callback */
+ NULL, NULL ); /* detached digests */
+ if (!enc) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot create encoder context"));
+ goto fail;
+ }
+
+ if (NSS_CMSEncoder_Update(enc, ((CamelStreamMem *)istream)->buffer->data, ((CamelStreamMem *)istream)->buffer->len) != SECSuccess) {
+ NSS_CMSEncoder_Cancel(enc);
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Failed to add data to CMS encoder"));
+ goto fail;
+ }
+
+ if (NSS_CMSEncoder_Finish(enc) != SECSuccess) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Failed to encode data"));
+ goto fail;
+ }
+
+ res = 0;
+
+ dw = camel_data_wrapper_new();
+ camel_stream_reset(ostream);
+ camel_data_wrapper_construct_from_stream(dw, ostream);
+ dw->encoding = CAMEL_TRANSFER_ENCODING_BINARY;
+
+ if (((CamelSMIMEContext *)context)->priv->sign_mode == CAMEL_SMIME_SIGN_CLEARSIGN) {
+ CamelMultipartSigned *mps;
+ CamelMimePart *sigpart;
+
+ sigpart = camel_mime_part_new();
+ ct = camel_content_type_new("application", "x-pkcs7-signature");
+ camel_content_type_set_param(ct, "name", "smime.p7s");
+ camel_data_wrapper_set_mime_type_field(dw, ct);
+ camel_content_type_unref(ct);
+
+ camel_medium_set_content_object((CamelMedium *)sigpart, dw);
+
+ camel_mime_part_set_filename(sigpart, "smime.p7s");
+ camel_mime_part_set_disposition(sigpart, "attachment");
+ camel_mime_part_set_encoding(sigpart, CAMEL_TRANSFER_ENCODING_BASE64);
+
+ mps = camel_multipart_signed_new();
+ ct = camel_content_type_new("multipart", "signed");
+ camel_content_type_set_param(ct, "micalg", camel_cipher_hash_to_id(context, hash));
+ camel_content_type_set_param(ct, "protocol", context->sign_protocol);
+ camel_data_wrapper_set_mime_type_field((CamelDataWrapper *)mps, ct);
+ camel_content_type_unref(ct);
+ camel_multipart_set_boundary((CamelMultipart *)mps, NULL);
+
+ mps->signature = sigpart;
+ mps->contentraw = istream;
+ camel_stream_reset(istream);
+ camel_object_ref(istream);
+
+ camel_medium_set_content_object((CamelMedium *)opart, (CamelDataWrapper *)mps);
+ } else {
+ ct = camel_content_type_new("application", "x-pkcs7-mime");
+ camel_content_type_set_param(ct, "name", "smime.p7m");
+ camel_content_type_set_param(ct, "smime-type", "signed-data");
+ camel_data_wrapper_set_mime_type_field(dw, ct);
+ camel_content_type_unref(ct);
+
+ camel_medium_set_content_object((CamelMedium *)opart, dw);
+
+ camel_mime_part_set_filename(opart, "smime.p7m");
+ camel_mime_part_set_description(opart, "S/MIME Signed Message");
+ camel_mime_part_set_disposition(opart, "attachment");
+ camel_mime_part_set_encoding(opart, CAMEL_TRANSFER_ENCODING_BASE64);
+ }
+
+ camel_object_unref(dw);
+fail:
+ camel_object_unref(ostream);
+ camel_object_unref(istream);
+
+ return res;
+}
+
+static const char *
+sm_status_description(NSSCMSVerificationStatus status)
+{
+ /* could use this but then we can't control i18n? */
+ /*NSS_CMSUtil_VerificationStatusToString(status));*/
+
+ switch(status) {
+ case NSSCMSVS_Unverified:
+ default:
+ return _("Unverified");
+ case NSSCMSVS_GoodSignature:
+ return _("Good signature");
+ case NSSCMSVS_BadSignature:
+ return _("Bad signature");
+ case NSSCMSVS_DigestMismatch:
+ return _("Content tampered with or altered in transit");
+ case NSSCMSVS_SigningCertNotFound:
+ return _("Signing certificate not found");
+ case NSSCMSVS_SigningCertNotTrusted:
+ return _("Signing certificate not trusted");
+ case NSSCMSVS_SignatureAlgorithmUnknown:
+ return _("Signature algorithm unknown");
+ case NSSCMSVS_SignatureAlgorithmUnsupported:
+ return _("Signature algorithm unsupported");
+ case NSSCMSVS_MalformedSignature:
+ return _("Malformed signature");
+ case NSSCMSVS_ProcessingError:
+ return _("Processing error");
+ }
+}
+
+static CamelCipherValidity *
+sm_verify_cmsg(CamelCipherContext *context, NSSCMSMessage *cmsg, CamelStream *extstream, CamelException *ex)
+{
+ struct _CamelSMIMEContextPrivate *p = ((CamelSMIMEContext *)context)->priv;
+ NSSCMSSignedData *sigd = NULL;
+ NSSCMSEnvelopedData *envd;
+ NSSCMSEncryptedData *encd;
+ SECAlgorithmID **digestalgs;
+ NSSCMSDigestContext *digcx;
+ int count, i, nsigners, j;
+ SECItem **digests;
+ PLArenaPool *poolp = NULL;
+ CamelStreamMem *mem;
+ NSSCMSVerificationStatus status;
+ CamelCipherValidity *valid;
+ GString *description;
+
+ description = g_string_new("");
+ valid = camel_cipher_validity_new();
+ camel_cipher_validity_set_valid(valid, TRUE);
+ status = NSSCMSVS_Unverified;
+
+ /* NB: this probably needs to go into a decoding routine that can be used for processing
+ enveloped data too */
+ count = NSS_CMSMessage_ContentLevelCount(cmsg);
+ for (i = 0; i < count; i++) {
+ NSSCMSContentInfo *cinfo = NSS_CMSMessage_ContentLevel(cmsg, i);
+ SECOidTag typetag = NSS_CMSContentInfo_GetContentTypeTag(cinfo);
+
+ switch (typetag) {
+ case SEC_OID_PKCS7_SIGNED_DATA:
+ sigd = (NSSCMSSignedData *)NSS_CMSContentInfo_GetContent(cinfo);
+ if (sigd == NULL) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("No signedData in signature"));
+ goto fail;
+ }
+
+ /* need to build digests of the content */
+ if (!NSS_CMSSignedData_HasDigests(sigd)) {
+ if (extstream == NULL) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Digests missing from enveloped data"));
+ goto fail;
+ }
+
+ if ((poolp = PORT_NewArena(1024)) == NULL) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, g_strerror (ENOMEM));
+ goto fail;
+ }
+
+ digestalgs = NSS_CMSSignedData_GetDigestAlgs(sigd);
+
+ digcx = NSS_CMSDigestContext_StartMultiple(digestalgs);
+ if (digcx == NULL) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot calculate digests"));
+ goto fail;
+ }
+
+ mem = (CamelStreamMem *)camel_stream_mem_new();
+ camel_stream_write_to_stream(extstream, (CamelStream *)mem);
+ NSS_CMSDigestContext_Update(digcx, mem->buffer->data, mem->buffer->len);
+ camel_object_unref(mem);
+
+ if (NSS_CMSDigestContext_FinishMultiple(digcx, poolp, &digests) != SECSuccess) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot calculate digests"));
+ goto fail;
+ }
+
+ if (NSS_CMSSignedData_SetDigests(sigd, digestalgs, digests) != SECSuccess) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot set message digests"));
+ goto fail;
+ }
+
+ PORT_FreeArena(poolp, PR_FALSE);
+ poolp = NULL;
+ }
+
+ /* import all certificates present */
+ if (NSS_CMSSignedData_ImportCerts(sigd, p->certdb, certUsageEmailSigner, PR_TRUE) != SECSuccess) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Certificate import failed"));
+ goto fail;
+ }
+
+ if (NSS_CMSSignedData_ImportCerts(sigd, p->certdb, certUsageEmailRecipient, PR_TRUE) != SECSuccess) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Certificate import failed"));
+ goto fail;
+ }
+
+ /* check for certs-only message */
+ nsigners = NSS_CMSSignedData_SignerInfoCount(sigd);
+ if (nsigners == 0) {
+ /* already imported certs above, not sure what usage we should use here or if this isn't handled above */
+ if (NSS_CMSSignedData_VerifyCertsOnly(sigd, p->certdb, certUsageEmailSigner) != SECSuccess) {
+ g_string_printf(description, _("Certificate only message, cannot verify certificates"));
+ } else {
+ status = NSSCMSVS_GoodSignature;
+ g_string_printf(description, _("Certificate only message, certificates imported and verified"));
+ }
+ } else {
+ if (!NSS_CMSSignedData_HasDigests(sigd)) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot find signature digests"));
+ goto fail;
+ }
+
+ for (j = 0; j < nsigners; j++) {
+ NSSCMSSignerInfo *si;
+ char *cn, *em;
+
+ si = NSS_CMSSignedData_GetSignerInfo(sigd, j);
+ NSS_CMSSignedData_VerifySignerInfo(sigd, j, p->certdb, certUsageEmailSigner);
+
+ status = NSS_CMSSignerInfo_GetVerificationStatus(si);
+
+ cn = NSS_CMSSignerInfo_GetSignerCommonName(si);
+ em = NSS_CMSSignerInfo_GetSignerEmailAddress(si);
+
+ g_string_append_printf(description, _("Signer: %s <%s>: %s\n"),
+ cn?cn:"<unknown>", em?em:"<unknown>",
+ sm_status_description(status));
+
+ camel_cipher_validity_add_certinfo(valid, CAMEL_CIPHER_VALIDITY_SIGN, cn, em);
+
+ if (cn)
+ PORT_Free(cn);
+ if (em)
+ PORT_Free(em);
+
+ if (status != NSSCMSVS_GoodSignature)
+ camel_cipher_validity_set_valid(valid, FALSE);
+ }
+ }
+ break;
+ case SEC_OID_PKCS7_ENVELOPED_DATA:
+ envd = (NSSCMSEnvelopedData *)NSS_CMSContentInfo_GetContent(cinfo);
+ break;
+ case SEC_OID_PKCS7_ENCRYPTED_DATA:
+ encd = (NSSCMSEncryptedData *)NSS_CMSContentInfo_GetContent(cinfo);
+ break;
+ case SEC_OID_PKCS7_DATA:
+ break;
+ default:
+ break;
+ }
+ }
+
+ camel_cipher_validity_set_valid(valid, status == NSSCMSVS_GoodSignature);
+ camel_cipher_validity_set_description(valid, description->str);
+ g_string_free(description, TRUE);
+
+ return valid;
+
+fail:
+ camel_cipher_validity_free(valid);
+ g_string_free(description, TRUE);
+
+ return NULL;
+}
+
+static CamelCipherValidity *
+sm_verify(CamelCipherContext *context, CamelMimePart *ipart, CamelException *ex)
+{
+ NSSCMSDecoderContext *dec;
+ NSSCMSMessage *cmsg;
+ CamelStreamMem *mem;
+ CamelStream *constream;
+ CamelCipherValidity *valid = NULL;
+ CamelContentType *ct;
+ const char *tmp;
+ CamelMimePart *sigpart;
+ CamelDataWrapper *dw;
+
+ dw = camel_medium_get_content_object((CamelMedium *)ipart);
+ ct = dw->mime_type;
+
+ /* FIXME: we should stream this to the decoder */
+ mem = (CamelStreamMem *)camel_stream_mem_new();
+
+ if (camel_content_type_is(ct, "multipart", "signed")) {
+ CamelMultipart *mps = (CamelMultipart *)dw;
+
+ tmp = camel_content_type_param(ct, "protocol");
+ if (!CAMEL_IS_MULTIPART_SIGNED(mps)
+ || tmp == NULL
+ || (g_ascii_strcasecmp(tmp, context->sign_protocol) != 0
+ && g_ascii_strcasecmp(tmp, "application/pkcs7-signature") != 0)) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot verify message signature: Incorrect message format"));
+ goto fail;
+ }
+
+ constream = camel_multipart_signed_get_content_stream((CamelMultipartSigned *)mps, ex);
+ if (constream == NULL)
+ goto fail;
+
+ sigpart = camel_multipart_get_part(mps, CAMEL_MULTIPART_SIGNED_SIGNATURE);
+ if (sigpart == NULL) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot verify message signature: Incorrect message format"));
+ goto fail;
+ }
+ } else if (camel_content_type_is(ct, "application", "x-pkcs7-mime")) {
+ sigpart = ipart;
+ } else {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot verify message signature: Incorrect message format"));
+ goto fail;
+ }
+
+ dec = NSS_CMSDecoder_Start(NULL,
+ NULL, NULL, /* content callback */
+ NULL, NULL, /* password callback */
+ NULL, NULL); /* decrypt key callback */
+
+ camel_data_wrapper_decode_to_stream(camel_medium_get_content_object((CamelMedium *)sigpart), (CamelStream *)mem);
+ (void)NSS_CMSDecoder_Update(dec, mem->buffer->data, mem->buffer->len);
+ cmsg = NSS_CMSDecoder_Finish(dec);
+ if (cmsg == NULL) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Decoder failed"));
+ goto fail;
+ }
+
+ valid = sm_verify_cmsg(context, cmsg, constream, ex);
+
+ NSS_CMSMessage_Destroy(cmsg);
+fail:
+ camel_object_unref(mem);
+ if (constream)
+ camel_object_unref(constream);
+
+ return valid;
+}
+
+static int
+sm_encrypt(CamelCipherContext *context, const char *userid, GPtrArray *recipients, CamelMimePart *ipart, CamelMimePart *opart, CamelException *ex)
+{
+ struct _CamelSMIMEContextPrivate *p = ((CamelSMIMEContext *)context)->priv;
+ /*NSSCMSRecipientInfo **recipient_infos;*/
+ CERTCertificate **recipient_certs = NULL;
+ NSSCMSContentInfo *cinfo;
+ PK11SymKey *bulkkey = NULL;
+ SECOidTag bulkalgtag;
+ int bulkkeysize, i;
+ CK_MECHANISM_TYPE type;
+ PK11SlotInfo *slot;
+ PLArenaPool *poolp;
+ NSSCMSMessage *cmsg = NULL;
+ NSSCMSEnvelopedData *envd;
+ NSSCMSEncoderContext *enc = NULL;
+ CamelStreamMem *mem;
+ CamelStream *ostream = NULL;
+ CamelDataWrapper *dw;
+ CamelContentType *ct;
+
+ poolp = PORT_NewArena(1024);
+ if (poolp == NULL) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, g_strerror (ENOMEM));
+ return -1;
+ }
+
+ /* Lookup all recipients certs, for later working */
+ recipient_certs = (CERTCertificate **)PORT_ArenaZAlloc(poolp, sizeof(*recipient_certs[0])*(recipients->len + 1));
+ if (recipient_certs == NULL) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, g_strerror (ENOMEM));
+ goto fail;
+ }
+
+ for (i=0;i<recipients->len;i++) {
+ recipient_certs[i] = CERT_FindCertByNicknameOrEmailAddr(p->certdb, recipients->pdata[i]);
+ if (recipient_certs[i] == NULL) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot find certificate for `%s'"), recipients->pdata[i]);
+ goto fail;
+ }
+ }
+
+ /* Find a common algorithm, probably 3DES anyway ... */
+ if (NSS_SMIMEUtil_FindBulkAlgForRecipients(recipient_certs, &bulkalgtag, &bulkkeysize) != SECSuccess) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot find common bulk encryption algorithm"));
+ goto fail;
+ }
+
+ /* Generate a new bulk key based on the common algorithm - expensive */
+ type = PK11_AlgtagToMechanism(bulkalgtag);
+ slot = PK11_GetBestSlot(type, context);
+ if (slot == NULL) {
+ /* PORT_GetError(); ?? */
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot allocate slot for encryption bulk key"));
+ goto fail;
+ }
+
+ bulkkey = PK11_KeyGen(slot, type, NULL, bulkkeysize/8, context);
+ PK11_FreeSlot(slot);
+
+ /* Now we can start building the message */
+ /* msg->envelopedData->data */
+ cmsg = NSS_CMSMessage_Create(NULL);
+ if (cmsg == NULL) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot create CMS Message"));
+ goto fail;
+ }
+
+ envd = NSS_CMSEnvelopedData_Create(cmsg, bulkalgtag, bulkkeysize);
+ if (envd == NULL) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot create CMS EnvelopedData"));
+ goto fail;
+ }
+
+ cinfo = NSS_CMSMessage_GetContentInfo(cmsg);
+ if (NSS_CMSContentInfo_SetContent_EnvelopedData(cmsg, cinfo, envd) != SECSuccess) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot attach CMS EnvelopedData"));
+ goto fail;
+ }
+
+ cinfo = NSS_CMSEnvelopedData_GetContentInfo(envd);
+ if (NSS_CMSContentInfo_SetContent_Data(cmsg, cinfo, NULL, PR_FALSE) != SECSuccess) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot attach CMS data object"));
+ goto fail;
+ }
+
+ /* add recipient certs */
+ for (i=0;recipient_certs[i];i++) {
+ NSSCMSRecipientInfo *ri = NSS_CMSRecipientInfo_Create(cmsg, recipient_certs[i]);
+
+ if (ri == NULL) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot create CMS RecipientInfo"));
+ goto fail;
+ }
+
+ if (NSS_CMSEnvelopedData_AddRecipient(envd, ri) != SECSuccess) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot add CMS RecipientInfo"));
+ goto fail;
+ }
+ }
+
+ /* dump it out */
+ ostream = camel_stream_mem_new();
+ enc = NSS_CMSEncoder_Start(cmsg,
+ sm_write_stream, ostream,
+ NULL, NULL,
+ NULL, NULL,
+ sm_decrypt_key, bulkkey,
+ NULL, NULL);
+ if (enc == NULL) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot create encoder context"));
+ goto fail;
+ }
+
+ /* FIXME: Stream the input */
+ /* FIXME: Canonicalise the input? */
+ mem = (CamelStreamMem *)camel_stream_mem_new();
+ camel_data_wrapper_write_to_stream((CamelDataWrapper *)ipart, (CamelStream *)mem);
+ if (NSS_CMSEncoder_Update(enc, mem->buffer->data, mem->buffer->len) != SECSuccess) {
+ NSS_CMSEncoder_Cancel(enc);
+ camel_object_unref(mem);
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Failed to add data to encoder"));
+ goto fail;
+ }
+ camel_object_unref(mem);
+
+ if (NSS_CMSEncoder_Finish(enc) != SECSuccess) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Failed to encode data"));
+ goto fail;
+ }
+
+ PK11_FreeSymKey(bulkkey);
+ NSS_CMSMessage_Destroy(cmsg);
+ for (i=0;recipient_certs[i];i++)
+ CERT_DestroyCertificate(recipient_certs[i]);
+ PORT_FreeArena(poolp, PR_FALSE);
+
+ dw = camel_data_wrapper_new();
+ camel_data_wrapper_construct_from_stream(dw, ostream);
+ camel_object_unref(ostream);
+ dw->encoding = CAMEL_TRANSFER_ENCODING_BINARY;
+
+ ct = camel_content_type_new("application", "x-pkcs7-mime");
+ camel_content_type_set_param(ct, "name", "smime.p7m");
+ camel_content_type_set_param(ct, "smime-type", "enveloped-data");
+ camel_data_wrapper_set_mime_type_field(dw, ct);
+ camel_content_type_unref(ct);
+
+ camel_medium_set_content_object((CamelMedium *)opart, dw);
+ camel_object_unref(dw);
+
+ camel_mime_part_set_disposition(opart, "attachment");
+ camel_mime_part_set_filename(opart, "smime.p7m");
+ camel_mime_part_set_description(opart, "S/MIME Encrypted Message");
+ camel_mime_part_set_encoding(opart, CAMEL_TRANSFER_ENCODING_BASE64);
+
+ return 0;
+
+fail:
+ if (ostream)
+ camel_object_unref(ostream);
+ if (cmsg)
+ NSS_CMSMessage_Destroy(cmsg);
+ if (bulkkey)
+ PK11_FreeSymKey(bulkkey);
+
+ if (recipient_certs) {
+ for (i=0;recipient_certs[i];i++)
+ CERT_DestroyCertificate(recipient_certs[i]);
+ }
+
+ PORT_FreeArena(poolp, PR_FALSE);
+
+ return -1;
+}
+
+static CamelCipherValidity *
+sm_decrypt(CamelCipherContext *context, CamelMimePart *ipart, CamelMimePart *opart, CamelException *ex)
+{
+ NSSCMSDecoderContext *dec;
+ NSSCMSMessage *cmsg;
+ CamelStreamMem *istream;
+ CamelStream *ostream;
+ CamelCipherValidity *valid = NULL;
+
+ /* FIXME: This assumes the content is only encrypted. Perhaps its ok for
+ this api to do this ... */
+
+ ostream = camel_stream_mem_new();
+ camel_stream_mem_set_secure((CamelStreamMem *)ostream);
+
+ /* FIXME: stream this to the decoder incrementally */
+ istream = (CamelStreamMem *)camel_stream_mem_new();
+ camel_data_wrapper_decode_to_stream(camel_medium_get_content_object((CamelMedium *)ipart), (CamelStream *)istream);
+ camel_stream_reset((CamelStream *)istream);
+
+ dec = NSS_CMSDecoder_Start(NULL,
+ sm_write_stream, ostream, /* content callback */
+ NULL, NULL,
+ NULL, NULL); /* decrypt key callback */
+
+ if (NSS_CMSDecoder_Update(dec, istream->buffer->data, istream->buffer->len) != SECSuccess) {
+ printf("decoder update failed\n");
+ }
+ camel_object_unref(istream);
+
+ cmsg = NSS_CMSDecoder_Finish(dec);
+ if (cmsg == NULL) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, _("Decoder failed, error %d"), PORT_GetError());
+ goto fail;
+ }
+
+#if 0
+ /* not sure if we really care about this? */
+ if (!NSS_CMSMessage_IsEncrypted(cmsg)) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("S/MIME Decrypt: No encrypted content found"));
+ NSS_CMSMessage_Destroy(cmsg);
+ goto fail;
+ }
+#endif
+
+ camel_stream_reset(ostream);
+ camel_data_wrapper_construct_from_stream((CamelDataWrapper *)opart, ostream);
+
+ if (NSS_CMSMessage_IsSigned(cmsg)) {
+ valid = sm_verify_cmsg(context, cmsg, NULL, ex);
+ } else {
+ valid = camel_cipher_validity_new();
+ valid->encrypt.description = g_strdup(_("Encrypted content"));
+ valid->encrypt.status = CAMEL_CIPHER_VALIDITY_ENCRYPT_ENCRYPTED;
+ }
+
+ NSS_CMSMessage_Destroy(cmsg);
+fail:
+ camel_object_unref(ostream);
+
+ return valid;
+}
+
+static int
+sm_import_keys(CamelCipherContext *context, CamelStream *istream, CamelException *ex)
+{
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("import keys: unimplemented"));
+
+ return -1;
+}
+
+static int
+sm_export_keys(CamelCipherContext *context, GPtrArray *keys, CamelStream *ostream, CamelException *ex)
+{
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("export keys: unimplemented"));
+
+ return -1;
+}
+
+/* ********************************************************************** */
+
+static void
+camel_smime_context_class_init(CamelSMIMEContextClass *klass)
+{
+ CamelCipherContextClass *cipher_class = CAMEL_CIPHER_CONTEXT_CLASS(klass);
+
+ parent_class = CAMEL_CIPHER_CONTEXT_CLASS(camel_type_get_global_classfuncs(camel_cipher_context_get_type()));
+
+ cipher_class->hash_to_id = sm_hash_to_id;
+ cipher_class->id_to_hash = sm_id_to_hash;
+ cipher_class->sign = sm_sign;
+ cipher_class->verify = sm_verify;
+ cipher_class->encrypt = sm_encrypt;
+ cipher_class->decrypt = sm_decrypt;
+ cipher_class->import_keys = sm_import_keys;
+ cipher_class->export_keys = sm_export_keys;
+}
+
+static void
+camel_smime_context_init(CamelSMIMEContext *context)
+{
+ CamelCipherContext *cipher =(CamelCipherContext *) context;
+
+ cipher->sign_protocol = "application/x-pkcs7-signature";
+ cipher->encrypt_protocol = "application/x-pkcs7-mime";
+ cipher->key_protocol = "application/x-pkcs7-signature";
+
+ context->priv = g_malloc0(sizeof(*context->priv));
+ context->priv->certdb = CERT_GetDefaultCertDB();
+ context->priv->sign_mode = CAMEL_SMIME_SIGN_CLEARSIGN;
+ context->priv->password_tries = 0;
+}
+
+static void
+camel_smime_context_finalise(CamelObject *object)
+{
+ CamelSMIMEContext *context = (CamelSMIMEContext *)object;
+
+ /* FIXME: do we have to free the certdb? */
+
+ g_free(context->priv);
+}
+
+CamelType
+camel_smime_context_get_type(void)
+{
+ static CamelType type = CAMEL_INVALID_TYPE;
+
+ if (type == CAMEL_INVALID_TYPE) {
+ type = camel_type_register(camel_cipher_context_get_type(),
+ "CamelSMIMEContext",
+ sizeof(CamelSMIMEContext),
+ sizeof(CamelSMIMEContextClass),
+ (CamelObjectClassInitFunc) camel_smime_context_class_init,
+ NULL,
+ (CamelObjectInitFunc) camel_smime_context_init,
+ (CamelObjectFinalizeFunc) camel_smime_context_finalise);
+ }
+
+ return type;
+}
+
+#endif /* ENABLE_SMIME */
diff --git a/camel/camel-store.c b/camel/camel-store.c
new file mode 100644
index 0000000000..e523d16443
--- /dev/null
+++ b/camel/camel-store.c
@@ -0,0 +1,1205 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* camel-store.c : Abstract class for an email store */
+
+/*
+ * Authors:
+ * Bertrand Guiheneuf <bertrand@helixcode.com>
+ * Dan Winship <danw@ximian.com>
+ *
+ * Copyright 1999-2003 Ximian, Inc. (www.ximian.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "camel-debug.h"
+
+#include "camel-session.h"
+#include "camel-store.h"
+#include "camel-folder.h"
+#include "camel-vtrash-folder.h"
+#include "camel-exception.h"
+#include "camel-private.h"
+
+#define d(x)
+#define w(x)
+
+static CamelServiceClass *parent_class = NULL;
+
+/* Returns the class for a CamelStore */
+#define CS_CLASS(so) ((CamelStoreClass *)((CamelObject *)(so))->klass)
+
+static CamelFolder *get_folder (CamelStore *store, const char *folder_name,
+ guint32 flags, CamelException *ex);
+static CamelFolder *get_inbox (CamelStore *store, CamelException *ex);
+
+static CamelFolder *get_trash (CamelStore *store, CamelException *ex);
+static CamelFolder *get_junk (CamelStore *store, CamelException *ex);
+
+static CamelFolderInfo *create_folder (CamelStore *store,
+ const char *parent_name,
+ const char *folder_name,
+ CamelException *ex);
+static void delete_folder (CamelStore *store, const char *folder_name,
+ CamelException *ex);
+static void rename_folder (CamelStore *store, const char *old_name,
+ const char *new_name, CamelException *ex);
+
+static void store_sync (CamelStore *store, int expunge, CamelException *ex);
+static CamelFolderInfo *get_folder_info (CamelStore *store, const char *top,
+ guint32 flags, CamelException *ex);
+static void free_folder_info (CamelStore *store, CamelFolderInfo *tree);
+
+static gboolean folder_subscribed (CamelStore *store, const char *folder_name);
+static void subscribe_folder (CamelStore *store, const char *folder_name, CamelException *ex);
+static void unsubscribe_folder (CamelStore *store, const char *folder_name, CamelException *ex);
+
+static void noop (CamelStore *store, CamelException *ex);
+
+static void construct (CamelService *service, CamelSession *session,
+ CamelProvider *provider, CamelURL *url,
+ CamelException *ex);
+
+static int store_setv (CamelObject *object, CamelException *ex, CamelArgV *args);
+static int store_getv (CamelObject *object, CamelException *ex, CamelArgGetV *args);
+
+static void
+camel_store_class_init (CamelStoreClass *camel_store_class)
+{
+ CamelObjectClass *camel_object_class = CAMEL_OBJECT_CLASS (camel_store_class);
+ CamelServiceClass *camel_service_class = CAMEL_SERVICE_CLASS(camel_store_class);
+
+ parent_class = CAMEL_SERVICE_CLASS (camel_type_get_global_classfuncs (camel_service_get_type ()));
+
+ /* virtual method definition */
+ camel_store_class->hash_folder_name = g_str_hash;
+ camel_store_class->compare_folder_name = g_str_equal;
+ camel_store_class->get_folder = get_folder;
+ camel_store_class->get_inbox = get_inbox;
+ camel_store_class->get_trash = get_trash;
+ camel_store_class->get_junk = get_junk;
+ camel_store_class->create_folder = create_folder;
+ camel_store_class->delete_folder = delete_folder;
+ camel_store_class->rename_folder = rename_folder;
+ camel_store_class->sync = store_sync;
+ camel_store_class->get_folder_info = get_folder_info;
+ camel_store_class->free_folder_info = free_folder_info;
+ camel_store_class->folder_subscribed = folder_subscribed;
+ camel_store_class->subscribe_folder = subscribe_folder;
+ camel_store_class->unsubscribe_folder = unsubscribe_folder;
+ camel_store_class->noop = noop;
+
+ /* virtual method overload */
+ camel_service_class->construct = construct;
+
+ camel_object_class->setv = store_setv;
+ camel_object_class->getv = store_getv;
+
+ camel_object_class_add_event(camel_object_class, "folder_opened", NULL);
+ camel_object_class_add_event(camel_object_class, "folder_created", NULL);
+ camel_object_class_add_event(camel_object_class, "folder_deleted", NULL);
+ camel_object_class_add_event(camel_object_class, "folder_renamed", NULL);
+ camel_object_class_add_event(camel_object_class, "folder_subscribed", NULL);
+ camel_object_class_add_event(camel_object_class, "folder_unsubscribed", NULL);
+}
+
+static void
+camel_store_init (void *o)
+{
+ CamelStore *store = o;
+ CamelStoreClass *store_class = (CamelStoreClass *)CAMEL_OBJECT_GET_CLASS (o);
+
+ if (store_class->hash_folder_name) {
+ store->folders = camel_object_bag_new(store_class->hash_folder_name,
+ store_class->compare_folder_name,
+ (CamelCopyFunc)g_strdup, g_free);
+ } else
+ store->folders = NULL;
+
+ /* set vtrash and vjunk on by default */
+ store->flags = CAMEL_STORE_VTRASH | CAMEL_STORE_VJUNK;
+
+ store->priv = g_malloc0 (sizeof (*store->priv));
+ store->priv->folder_lock = e_mutex_new (E_MUTEX_REC);
+}
+
+static void
+camel_store_finalize (CamelObject *object)
+{
+ CamelStore *store = CAMEL_STORE (object);
+
+ if (store->folders)
+ camel_object_bag_destroy(store->folders);
+
+ e_mutex_destroy (store->priv->folder_lock);
+
+ g_free (store->priv);
+}
+
+
+CamelType
+camel_store_get_type (void)
+{
+ static CamelType camel_store_type = CAMEL_INVALID_TYPE;
+
+ if (camel_store_type == CAMEL_INVALID_TYPE) {
+ camel_store_type = camel_type_register (CAMEL_SERVICE_TYPE, "CamelStore",
+ sizeof (CamelStore),
+ sizeof (CamelStoreClass),
+ (CamelObjectClassInitFunc) camel_store_class_init,
+ NULL,
+ (CamelObjectInitFunc) camel_store_init,
+ (CamelObjectFinalizeFunc) camel_store_finalize );
+ }
+
+ return camel_store_type;
+}
+
+static int
+store_setv (CamelObject *object, CamelException *ex, CamelArgV *args)
+{
+ /* CamelStore doesn't currently have anything to set */
+ return CAMEL_OBJECT_CLASS (parent_class)->setv (object, ex, args);
+}
+
+static int
+store_getv (CamelObject *object, CamelException *ex, CamelArgGetV *args)
+{
+ /* CamelStore doesn't currently have anything to get */
+ return CAMEL_OBJECT_CLASS (parent_class)->getv (object, ex, args);
+}
+
+static void
+construct (CamelService *service, CamelSession *session,
+ CamelProvider *provider, CamelURL *url,
+ CamelException *ex)
+{
+ CamelStore *store = CAMEL_STORE(service);
+
+ parent_class->construct(service, session, provider, url, ex);
+ if (camel_exception_is_set (ex))
+ return;
+
+ if (camel_url_get_param(url, "filter"))
+ store->flags |= CAMEL_STORE_FILTER_INBOX;
+}
+
+static CamelFolder *
+get_folder (CamelStore *store, const char *folder_name, guint32 flags, CamelException *ex)
+{
+ w(g_warning ("CamelStore::get_folder not implemented for `%s'",
+ camel_type_to_name (CAMEL_OBJECT_GET_TYPE (store))));
+
+ camel_exception_setv (ex, CAMEL_EXCEPTION_STORE_INVALID,
+ _("Cannot get folder: Invalid operation on this store"));
+
+ return NULL;
+}
+
+/**
+ * camel_store_get_folder: Return the folder corresponding to a path.
+ * @store: a CamelStore
+ * @folder_name: name of the folder to get
+ * @flags: folder flags (create, save body index, etc)
+ * @ex: a CamelException
+ *
+ * Return value: the folder corresponding to the path @folder_name.
+ **/
+CamelFolder *
+camel_store_get_folder (CamelStore *store, const char *folder_name, guint32 flags, CamelException *ex)
+{
+ CamelFolder *folder = NULL;
+
+ g_return_val_if_fail (folder_name != NULL, NULL);
+
+ /* O_EXCL doesn't make sense if we aren't requesting to also create the folder if it doesn't exist */
+ if (!(flags & CAMEL_STORE_FOLDER_CREATE))
+ flags &= ~CAMEL_STORE_FOLDER_EXCL;
+
+ if (store->folders) {
+ /* Try cache first. */
+ folder = camel_object_bag_reserve(store->folders, folder_name);
+ if (folder && (flags & CAMEL_STORE_FOLDER_EXCL)) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot create folder `%s': folder exists"),
+ folder_name);
+
+ camel_object_unref (folder);
+ return NULL;
+ }
+ }
+
+ if (!folder) {
+ if ((store->flags & CAMEL_STORE_VTRASH) && strcmp(folder_name, CAMEL_VTRASH_NAME) == 0) {
+ folder = CS_CLASS(store)->get_trash(store, ex);
+ } else if ((store->flags & CAMEL_STORE_VJUNK) && strcmp(folder_name, CAMEL_VJUNK_NAME) == 0) {
+ folder = CS_CLASS(store)->get_junk(store, ex);
+ } else {
+ folder = CS_CLASS (store)->get_folder(store, folder_name, flags, ex);
+ if (folder) {
+ CamelVeeFolder *vfolder;
+
+ if ((store->flags & CAMEL_STORE_VTRASH)
+ && (vfolder = camel_object_bag_get(store->folders, CAMEL_VTRASH_NAME))) {
+ camel_vee_folder_add_folder(vfolder, folder);
+ camel_object_unref(vfolder);
+ }
+
+ if ((store->flags & CAMEL_STORE_VJUNK)
+ && (vfolder = camel_object_bag_get(store->folders, CAMEL_VJUNK_NAME))) {
+ camel_vee_folder_add_folder(vfolder, folder);
+ camel_object_unref(vfolder);
+ }
+ }
+ }
+
+ if (store->folders) {
+ if (folder)
+ camel_object_bag_add(store->folders, folder_name, folder);
+ else
+ camel_object_bag_abort(store->folders, folder_name);
+ }
+
+ if (folder)
+ camel_object_trigger_event(store, "folder_opened", folder);
+ }
+
+ return folder;
+}
+
+static CamelFolderInfo *
+create_folder (CamelStore *store, const char *parent_name,
+ const char *folder_name, CamelException *ex)
+{
+ w(g_warning ("CamelStore::create_folder not implemented for `%s'",
+ camel_type_to_name (CAMEL_OBJECT_GET_TYPE (store))));
+
+ camel_exception_setv (ex, CAMEL_EXCEPTION_STORE_INVALID,
+ _("Cannot create folder: Invalid operation on this store"));
+
+ return NULL;
+}
+
+/**
+ * camel_store_create_folder:
+ * @store: a CamelStore
+ * @parent_name: name of the new folder's parent, or %NULL
+ * @folder_name: name of the folder to create
+ * @ex: a CamelException
+ *
+ * Creates a new folder as a child of an existing folder.
+ * @parent_name can be %NULL to create a new top-level folder.
+ *
+ * Return value: info about the created folder, which the caller must
+ * free with camel_store_free_folder_info().
+ **/
+CamelFolderInfo *
+camel_store_create_folder (CamelStore *store, const char *parent_name,
+ const char *folder_name, CamelException *ex)
+{
+ CamelFolderInfo *fi;
+
+ if ((parent_name == NULL || parent_name[0] == 0)
+ && (((store->flags & CAMEL_STORE_VTRASH) && strcmp(folder_name, CAMEL_VTRASH_NAME) == 0)
+ || ((store->flags & CAMEL_STORE_VJUNK) && strcmp(folder_name, CAMEL_VJUNK_NAME) == 0))) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_STORE_INVALID,
+ _("Cannot create folder: %s: folder exists"), folder_name);
+ return NULL;
+ }
+
+ CAMEL_STORE_LOCK(store, folder_lock);
+ fi = CS_CLASS (store)->create_folder (store, parent_name, folder_name, ex);
+ CAMEL_STORE_UNLOCK(store, folder_lock);
+
+ return fi;
+}
+
+/* deletes folder/removes it from the folder cache, if it's there */
+static void
+cs_delete_cached_folder(CamelStore *store, const char *folder_name)
+{
+ CamelFolder *folder;
+
+ if (store->folders
+ && (folder = camel_object_bag_get(store->folders, folder_name))) {
+ CamelVeeFolder *vfolder;
+
+ if ((store->flags & CAMEL_STORE_VTRASH)
+ && (vfolder = camel_object_bag_get(store->folders, CAMEL_VTRASH_NAME))) {
+ camel_vee_folder_remove_folder(vfolder, folder);
+ camel_object_unref(vfolder);
+ }
+
+ if ((store->flags & CAMEL_STORE_VJUNK)
+ && (vfolder = camel_object_bag_get(store->folders, CAMEL_VJUNK_NAME))) {
+ camel_vee_folder_remove_folder(vfolder, folder);
+ camel_object_unref(vfolder);
+ }
+
+ camel_folder_delete(folder);
+
+ camel_object_bag_remove(store->folders, folder);
+ camel_object_unref(folder);
+ }
+}
+
+static void
+delete_folder (CamelStore *store, const char *folder_name, CamelException *ex)
+{
+ w(g_warning ("CamelStore::delete_folder not implemented for `%s'",
+ camel_type_to_name (CAMEL_OBJECT_GET_TYPE (store))));
+}
+
+/**
+ * camel_store_delete_folder: Delete the folder corresponding to a path.
+ * @store: a CamelStore
+ * @folder_name: name of the folder to delete
+ * @ex: a CamelException
+ *
+ * Deletes the named folder. The folder must be empty.
+ **/
+void
+camel_store_delete_folder (CamelStore *store, const char *folder_name, CamelException *ex)
+{
+ CamelException local;
+
+ /* TODO: should probably be a parameter/bit on the storeinfo */
+ if (((store->flags & CAMEL_STORE_VTRASH) && strcmp(folder_name, CAMEL_VTRASH_NAME) == 0)
+ || ((store->flags & CAMEL_STORE_VJUNK) && strcmp(folder_name, CAMEL_VJUNK_NAME) == 0)) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER,
+ _("Cannot delete folder: %s: Invalid operation"), folder_name);
+ return;
+ }
+
+ camel_exception_init(&local);
+
+ CAMEL_STORE_LOCK(store, folder_lock);
+
+ CS_CLASS(store)->delete_folder(store, folder_name, &local);
+
+ if (!camel_exception_is_set(&local))
+ cs_delete_cached_folder(store, folder_name);
+ else
+ camel_exception_xfer(ex, &local);
+
+ CAMEL_STORE_UNLOCK(store, folder_lock);
+}
+
+static void
+rename_folder (CamelStore *store, const char *old_name, const char *new_name, CamelException *ex)
+{
+ w(g_warning ("CamelStore::rename_folder not implemented for `%s'",
+ camel_type_to_name (CAMEL_OBJECT_GET_TYPE (store))));
+}
+
+/**
+ * camel_store_rename_folder:
+ * @store: a CamelStore
+ * @old_name: the current name of the folder
+ * @new_name: the new name of the folder
+ * @ex: a CamelException
+ *
+ * Rename a named folder to a new name.
+ **/
+void
+camel_store_rename_folder (CamelStore *store, const char *old_namein, const char *new_name, CamelException *ex)
+{
+ CamelFolder *folder;
+ int i, oldlen, namelen;
+ GPtrArray *folders;
+ char *old_name;
+
+ d(printf("store rename folder %s '%s' '%s'\n", ((CamelService *)store)->url->protocol, old_name, new_name));
+
+ if (strcmp(old_namein, new_name) == 0)
+ return;
+
+ if (((store->flags & CAMEL_STORE_VTRASH) && strcmp(old_namein, CAMEL_VTRASH_NAME) == 0)
+ || ((store->flags & CAMEL_STORE_VJUNK) && strcmp(old_namein, CAMEL_VJUNK_NAME) == 0)) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER,
+ _("Cannot rename folder: %s: Invalid operation"), old_namein);
+ return;
+ }
+
+ /* need to save this, since old_namein might be folder->full_name, which could go away */
+ old_name = g_strdup(old_namein);
+ oldlen = strlen(old_name);
+
+ CAMEL_STORE_LOCK(store, folder_lock);
+
+ /* If the folder is open (or any subfolders of the open folder)
+ We need to rename them atomically with renaming the actual folder path */
+ if (store->folders) {
+ folders = camel_object_bag_list(store->folders);
+ for (i=0;i<folders->len;i++) {
+ folder = folders->pdata[i];
+ namelen = strlen(folder->full_name);
+ if ((namelen == oldlen &&
+ strcmp(folder->full_name, old_name) == 0)
+ || ((namelen > oldlen)
+ && strncmp(folder->full_name, old_name, oldlen) == 0
+ && folder->full_name[oldlen] == '/')) {
+ d(printf("Found subfolder of '%s' == '%s'\n", old_name, folder->full_name));
+ CAMEL_FOLDER_LOCK(folder, lock);
+ } else {
+ g_ptr_array_remove_index_fast(folders, i);
+ i--;
+ camel_object_unref(folder);
+ }
+ }
+ }
+
+ /* Now try the real rename (will emit renamed event) */
+ CS_CLASS (store)->rename_folder (store, old_name, new_name, ex);
+
+ /* If it worked, update all open folders/unlock them */
+ if (!camel_exception_is_set(ex)) {
+ guint32 flags = CAMEL_STORE_FOLDER_INFO_RECURSIVE;
+ CamelRenameInfo reninfo;
+
+ for (i=0;i<folders->len;i++) {
+ char *new;
+
+ folder = folders->pdata[i];
+
+ new = g_strdup_printf("%s%s", new_name, folder->full_name+strlen(old_name));
+ camel_object_bag_rekey(store->folders, folder, new);
+ camel_folder_rename(folder, new);
+ g_free(new);
+
+ CAMEL_FOLDER_UNLOCK(folder, lock);
+ camel_object_unref(folder);
+ }
+
+ /* Emit renamed signal */
+ if (store->flags & CAMEL_STORE_SUBSCRIPTIONS)
+ flags |= CAMEL_STORE_FOLDER_INFO_SUBSCRIBED;
+
+ reninfo.old_base = (char *)old_name;
+ reninfo.new = ((CamelStoreClass *)((CamelObject *)store)->klass)->get_folder_info(store, new_name, flags, ex);
+ if (reninfo.new != NULL) {
+ camel_object_trigger_event (store, "folder_renamed", &reninfo);
+ ((CamelStoreClass *)((CamelObject *)store)->klass)->free_folder_info(store, reninfo.new);
+ }
+ } else {
+ /* Failed, just unlock our folders for re-use */
+ for (i=0;i<folders->len;i++) {
+ folder = folders->pdata[i];
+ CAMEL_FOLDER_UNLOCK(folder, lock);
+ camel_object_unref(folder);
+ }
+ }
+
+ CAMEL_STORE_UNLOCK(store, folder_lock);
+
+ g_ptr_array_free(folders, TRUE);
+ g_free(old_name);
+}
+
+
+static CamelFolder *
+get_inbox (CamelStore *store, CamelException *ex)
+{
+ /* Default: assume the inbox's name is "inbox"
+ * and open with default flags.
+ */
+ return CS_CLASS (store)->get_folder (store, "inbox", 0, ex);
+}
+
+/**
+ * camel_store_get_inbox:
+ * @store: a CamelStore
+ * @ex: a CamelException
+ *
+ * Return value: the folder in the store into which new mail is
+ * delivered, or %NULL if no such folder exists.
+ **/
+CamelFolder *
+camel_store_get_inbox (CamelStore *store, CamelException *ex)
+{
+ CamelFolder *folder;
+
+ CAMEL_STORE_LOCK(store, folder_lock);
+ folder = CS_CLASS (store)->get_inbox (store, ex);
+ CAMEL_STORE_UNLOCK(store, folder_lock);
+
+ return folder;
+}
+
+static CamelFolder *
+get_special(CamelStore *store, enum _camel_vtrash_folder_t type)
+{
+ CamelFolder *folder;
+ GPtrArray *folders;
+ int i;
+
+ folder = camel_vtrash_folder_new(store, type);
+ folders = camel_object_bag_list(store->folders);
+ for (i=0;i<folders->len;i++) {
+ if (!CAMEL_IS_VTRASH_FOLDER(folders->pdata[i]))
+ camel_vee_folder_add_folder((CamelVeeFolder *)folder, (CamelFolder *)folders->pdata[i]);
+ camel_object_unref(folders->pdata[i]);
+ }
+ g_ptr_array_free(folders, TRUE);
+
+ return folder;
+}
+
+static CamelFolder *
+get_trash(CamelStore *store, CamelException *ex)
+{
+ return get_special(store, CAMEL_VTRASH_FOLDER_TRASH);
+}
+
+static CamelFolder *
+get_junk(CamelStore *store, CamelException *ex)
+{
+ return get_special(store, CAMEL_VTRASH_FOLDER_JUNK);
+}
+
+/**
+ * camel_store_get_trash:
+ * @store: a CamelStore
+ * @ex: a CamelException
+ *
+ * Return value: the folder in the store into which trash is
+ * delivered, or %NULL if no such folder exists.
+ **/
+CamelFolder *
+camel_store_get_trash (CamelStore *store, CamelException *ex)
+{
+ if ((store->flags & CAMEL_STORE_VTRASH) == 0)
+ return CS_CLASS(store)->get_trash(store, ex);
+ else
+ return camel_store_get_folder(store, CAMEL_VTRASH_NAME, 0, ex);
+}
+
+/**
+ * camel_store_get_junk:
+ * @store: a CamelStore
+ * @ex: a CamelException
+ *
+ * Return value: the folder in the store into which junk is
+ * delivered, or %NULL if no such folder exists.
+ **/
+CamelFolder *
+camel_store_get_junk (CamelStore *store, CamelException *ex)
+{
+ if ((store->flags & CAMEL_STORE_VJUNK) == 0)
+ return CS_CLASS(store)->get_junk(store, ex);
+ else
+ return camel_store_get_folder(store, CAMEL_VJUNK_NAME, 0, ex);
+}
+
+static void
+store_sync (CamelStore *store, int expunge, CamelException *ex)
+{
+ if (store->folders) {
+ GPtrArray *folders;
+ CamelFolder *folder;
+ CamelException x;
+ int i;
+
+ /* we don't sync any vFolders, that is used to update certain vfolder queries mainly,
+ and we're really only interested in storing/expunging the physical mails */
+ camel_exception_init(&x);
+ folders = camel_object_bag_list(store->folders);
+ for (i=0;i<folders->len;i++) {
+ folder = folders->pdata[i];
+ if (!CAMEL_IS_VEE_FOLDER(folder)
+ && !camel_exception_is_set(&x))
+ camel_folder_sync(folder, expunge, &x);
+ camel_object_unref(folder);
+ }
+ camel_exception_xfer(ex, &x);
+ g_ptr_array_free(folders, TRUE);
+ }
+}
+
+/**
+ * camel_store_sync:
+ * @store: a CamelStore
+ * @expunge: do we expunge deleted messages too?
+ * @ex: a CamelException
+ *
+ * Syncs any changes that have been made to the store object and its
+ * folders with the real store.
+ **/
+void
+camel_store_sync(CamelStore *store, int expunge, CamelException *ex)
+{
+ g_return_if_fail (CAMEL_IS_STORE (store));
+
+ CS_CLASS(store)->sync(store, expunge, ex);
+}
+
+static CamelFolderInfo *
+get_folder_info (CamelStore *store, const char *top, guint32 flags, CamelException *ex)
+{
+ w(g_warning ("CamelStore::get_folder_info not implemented for `%s'",
+ camel_type_to_name (CAMEL_OBJECT_GET_TYPE (store))));
+
+ return NULL;
+}
+
+static void
+add_special_info (CamelStore *store, CamelFolderInfo *info, const char *name, const char *translated, gboolean unread_count)
+{
+ CamelFolderInfo *fi, *vinfo, *parent;
+ char *uri, *path;
+ CamelURL *url;
+
+ g_return_if_fail (info != NULL);
+
+ parent = NULL;
+ for (fi = info; fi; fi = fi->next) {
+ if (!strcmp (fi->name, name))
+ break;
+ parent = fi;
+ }
+
+ /* create our vTrash/vJunk URL */
+ url = camel_url_new (info->uri, NULL);
+ if (((CamelService *) store)->provider->url_flags & CAMEL_URL_FRAGMENT_IS_PATH) {
+ camel_url_set_fragment (url, name);
+ } else {
+ path = g_strdup_printf ("/%s", name);
+ camel_url_set_path (url, path);
+ g_free (path);
+ }
+
+ uri = camel_url_to_string (url, CAMEL_URL_HIDE_ALL);
+ camel_url_free (url);
+
+ if (fi) {
+ /* We're going to replace the physical Trash/Junk folder with our vTrash/vJunk folder */
+ vinfo = fi;
+ g_free (vinfo->full_name);
+ g_free (vinfo->name);
+ g_free (vinfo->uri);
+ } else {
+ /* There wasn't a Trash/Junk folder so create a new folder entry */
+ vinfo = g_new0 (CamelFolderInfo, 1);
+
+ g_assert(parent != NULL);
+
+ vinfo->flags |= CAMEL_FOLDER_NOINFERIORS | CAMEL_FOLDER_SUBSCRIBED;
+
+ /* link it into the right spot */
+ vinfo->next = parent->next;
+ parent->next = vinfo;
+ }
+
+ /* Fill in the new fields */
+ vinfo->flags |= CAMEL_FOLDER_VIRTUAL|CAMEL_FOLDER_SYSTEM|CAMEL_FOLDER_VTRASH;
+ vinfo->full_name = g_strdup (name);
+ vinfo->name = g_strdup (translated);
+ vinfo->uri = uri;
+ if (!unread_count)
+ vinfo->unread = -1;
+}
+
+static void
+dump_fi(CamelFolderInfo *fi, int depth)
+{
+ char *s;
+
+ s = g_alloca(depth+1);
+ memset(s, ' ', depth);
+ s[depth] = 0;
+
+ while (fi) {
+ printf("%suri: %s\n", s, fi->uri);
+ printf("%sfull_name: %s\n", s, fi->full_name);
+ printf("%sflags: %08x\n", s, fi->flags);
+ dump_fi(fi->child, depth+2);
+ fi = fi->next;
+ }
+}
+
+/**
+ * camel_store_get_folder_info:
+ * @store: a CamelStore
+ * @top: the name of the folder to start from
+ * @flags: various CAMEL_STORE_FOLDER_INFO_* flags to control behavior
+ * @ex: a CamelException
+ *
+ * This fetches information about the folder structure of @store,
+ * starting with @top, and returns a tree of CamelFolderInfo
+ * structures. If @flags includes %CAMEL_STORE_FOLDER_INFO_SUBSCRIBED,
+ * only subscribed folders will be listed. (This flag can only be used
+ * for stores that support subscriptions.) If @flags includes
+ * %CAMEL_STORE_FOLDER_INFO_RECURSIVE, the returned tree will include
+ * all levels of hierarchy below @top. If not, it will only include
+ * the immediate subfolders of @top. If @flags includes
+ * %CAMEL_STORE_FOLDER_INFO_FAST, the unread_message_count fields of
+ * some or all of the structures may be set to -1, if the store cannot
+ * determine that information quickly. If @flags includes
+ * %CAMEL_STORE_FOLDER_INFO_NO_VIRTUAL, don't include special virtual
+ * folders (such as vTrash or vJunk).
+ *
+ * Return value: a CamelFolderInfo tree, which must be freed with
+ * camel_store_free_folder_info.
+ **/
+CamelFolderInfo *
+camel_store_get_folder_info(CamelStore *store, const char *top, guint32 flags, CamelException *ex)
+{
+ CamelFolderInfo *info;
+
+ g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
+ g_return_val_if_fail ((store->flags & CAMEL_STORE_SUBSCRIPTIONS) ||
+ !(flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED),
+ NULL);
+
+ info = CS_CLASS (store)->get_folder_info (store, top, flags, ex);
+
+ if (info && (top == NULL || *top == '\0') && (flags & CAMEL_STORE_FOLDER_INFO_NO_VIRTUAL) == 0) {
+ if (info->uri && (store->flags & CAMEL_STORE_VTRASH))
+ add_special_info (store, info, CAMEL_VTRASH_NAME, _("Trash"), FALSE);
+ if (info->uri && (store->flags & CAMEL_STORE_VJUNK))
+ add_special_info (store, info, CAMEL_VJUNK_NAME, _("Junk"), TRUE);
+ }
+
+ if (camel_debug_start("store:folder_info")) {
+ char *url = camel_url_to_string(((CamelService *)store)->url, CAMEL_URL_HIDE_ALL);
+ printf("Get folder info(%p:%s, '%s') =\n", store, url, top?top:"<null>");
+ g_free(url);
+ dump_fi(info, 2);
+ camel_debug_end();
+ }
+
+ return info;
+}
+
+static void
+free_folder_info (CamelStore *store, CamelFolderInfo *fi)
+{
+ w(g_warning ("CamelStore::free_folder_info not implemented for `%s'",
+ camel_type_to_name (CAMEL_OBJECT_GET_TYPE (store))));
+}
+
+/**
+ * camel_store_free_folder_info:
+ * @store: a CamelStore
+ * @tree: the tree returned by camel_store_get_folder_info()
+ *
+ * Frees the data returned by camel_store_get_folder_info().
+ **/
+void
+camel_store_free_folder_info (CamelStore *store, CamelFolderInfo *fi)
+{
+ g_return_if_fail (CAMEL_IS_STORE (store));
+
+ CS_CLASS (store)->free_folder_info (store, fi);
+}
+
+/**
+ * camel_store_free_folder_info_full:
+ * @store: a CamelStore
+ * @tree: the tree returned by camel_store_get_folder_info()
+ *
+ * An implementation for CamelStore::free_folder_info. Frees all
+ * of the data.
+ **/
+void
+camel_store_free_folder_info_full (CamelStore *store, CamelFolderInfo *fi)
+{
+ camel_folder_info_free (fi);
+}
+
+/**
+ * camel_store_free_folder_info_nop:
+ * @store: a CamelStore
+ * @tree: the tree returned by camel_store_get_folder_info()
+ *
+ * An implementation for CamelStore::free_folder_info. Does nothing.
+ **/
+void
+camel_store_free_folder_info_nop (CamelStore *store, CamelFolderInfo *fi)
+{
+ ;
+}
+
+/**
+ * camel_folder_info_free:
+ * @fi: the CamelFolderInfo
+ *
+ * Frees @fi.
+ **/
+void
+camel_folder_info_free (CamelFolderInfo *fi)
+{
+ if (fi) {
+ camel_folder_info_free (fi->next);
+ camel_folder_info_free (fi->child);
+ g_free (fi->name);
+ g_free (fi->full_name);
+ g_free (fi->uri);
+ g_free (fi);
+ }
+}
+
+static int
+folder_info_cmp (const void *ap, const void *bp)
+{
+ const CamelFolderInfo *a = ((CamelFolderInfo **)ap)[0];
+ const CamelFolderInfo *b = ((CamelFolderInfo **)bp)[0];
+
+ return strcmp (a->full_name, b->full_name);
+}
+
+static void
+free_name(void *key, void *data, void *user)
+{
+ g_free(key);
+}
+
+/**
+ * camel_folder_info_build:
+ * @folders: an array of CamelFolderInfo
+ * @namespace: an ignorable prefix on the folder names
+ * @separator: the hieararchy separator character
+ * @short_names: %TRUE if the (short) name of a folder is the part after
+ * the last @separator in the full name. %FALSE if it is the full name.
+ *
+ * This takes an array of folders and attaches them together according
+ * to the hierarchy described by their full_names and @separator. If
+ * @namespace is non-%NULL, then it will be ignored as a full_name
+ * prefix, for purposes of comparison. If necessary,
+ * camel_folder_info_build will create additional CamelFolderInfo with
+ * %NULL urls to fill in gaps in the tree. The value of @short_names
+ * is used in constructing the names of these intermediate folders.
+ *
+ * NOTE: This is deprected, do not use this.
+ * FIXME: remove this/move it to imap, which is the only user of it now.
+ *
+ * Return value: the top level of the tree of linked folder info.
+ **/
+CamelFolderInfo *
+camel_folder_info_build (GPtrArray *folders, const char *namespace,
+ char separator, gboolean short_names)
+{
+ CamelFolderInfo *fi, *pfi, *top = NULL, *tail = NULL;
+ GHashTable *hash;
+ char *name, *p, *pname;
+ int i, nlen;
+
+ if (!namespace)
+ namespace = "";
+ nlen = strlen (namespace);
+
+ qsort (folders->pdata, folders->len, sizeof (folders->pdata[0]), folder_info_cmp);
+
+ /* Hash the folders. */
+ hash = g_hash_table_new (g_str_hash, g_str_equal);
+ for (i = 0; i < folders->len; i++) {
+ fi = folders->pdata[i];
+ if (!strncmp (namespace, fi->full_name, nlen))
+ name = fi->full_name + nlen;
+ else
+ name = fi->full_name;
+ if (*name == separator)
+ name++;
+
+ g_hash_table_insert (hash, g_strdup(name), fi);
+ }
+
+ /* Now find parents. */
+ for (i = 0; i < folders->len; i++) {
+ fi = folders->pdata[i];
+ if (!strncmp (namespace, fi->full_name, nlen))
+ name = fi->full_name + nlen;
+ else
+ name = fi->full_name;
+ if (*name == separator)
+ name++;
+
+ p = strrchr (name, separator);
+ if (p) {
+ pname = g_strndup (name, p - name);
+ pfi = g_hash_table_lookup (hash, pname);
+ if (pfi) {
+ g_free (pname);
+ } else {
+ /* we are missing a folder in the heirarchy so
+ create a fake folder node */
+ CamelURL *url;
+ char *sep;
+
+ pfi = g_new0 (CamelFolderInfo, 1);
+ if (short_names) {
+ pfi->name = strrchr (pname, separator);
+ if (pfi->name)
+ pfi->name = g_strdup (pfi->name + 1);
+ else
+ pfi->name = g_strdup (pname);
+ } else
+ pfi->name = g_strdup (pname);
+
+ /* FIXME: url's with fragments should have the fragment truncated, not path */
+ url = camel_url_new (fi->uri, NULL);
+ sep = strrchr (url->path, separator);
+ if (sep)
+ *sep = '\0';
+ else
+ d(g_warning ("huh, no \"%c\" in \"%s\"?", separator, fi->url));
+
+ pfi->full_name = g_strdup(url->path+1);
+
+ /* since this is a "fake" folder node, it is not selectable */
+ camel_url_set_param (url, "noselect", "yes");
+ pfi->uri = camel_url_to_string (url, 0);
+ camel_url_free (url);
+
+ g_hash_table_insert (hash, pname, pfi);
+ g_ptr_array_add (folders, pfi);
+ }
+ tail = (CamelFolderInfo *)&pfi->child;
+ while (tail->next)
+ tail = tail->next;
+ tail->next = fi;
+ fi->parent = pfi;
+ } else if (!top)
+ top = fi;
+ }
+ g_hash_table_foreach(hash, free_name, NULL);
+ g_hash_table_destroy (hash);
+
+ /* Link together the top-level folders */
+ tail = top;
+ for (i = 0; i < folders->len; i++) {
+ fi = folders->pdata[i];
+ if (fi->parent || fi == top)
+ continue;
+ if (tail == NULL) {
+ tail = fi;
+ top = fi;
+ } else {
+ tail->next = fi;
+ tail = fi;
+ }
+ }
+
+ return top;
+}
+
+static CamelFolderInfo *folder_info_clone_rec(CamelFolderInfo *fi, CamelFolderInfo *parent)
+{
+ CamelFolderInfo *info;
+
+ info = g_malloc(sizeof(*info));
+ info->parent = parent;
+ info->uri = g_strdup(fi->uri);
+ info->name = g_strdup(fi->name);
+ info->full_name = g_strdup(fi->full_name);
+ info->unread = fi->unread;
+ info->flags = fi->flags;
+
+ if (fi->next)
+ info->next = folder_info_clone_rec(fi->next, parent);
+ else
+ info->next = NULL;
+
+ if (fi->child)
+ info->child = folder_info_clone_rec(fi->child, info);
+ else
+ info->child = NULL;
+
+ return info;
+}
+
+CamelFolderInfo *
+camel_folder_info_clone(CamelFolderInfo *fi)
+{
+ if (fi == NULL)
+ return NULL;
+
+ return folder_info_clone_rec(fi, NULL);
+}
+
+gboolean
+camel_store_supports_subscriptions (CamelStore *store)
+{
+ return (store->flags & CAMEL_STORE_SUBSCRIPTIONS);
+}
+
+static gboolean
+folder_subscribed(CamelStore *store, const char *folder_name)
+{
+ w(g_warning ("CamelStore::folder_subscribed not implemented for `%s'",
+ camel_type_to_name (CAMEL_OBJECT_GET_TYPE (store))));
+
+ return FALSE;
+}
+
+/**
+ * camel_store_folder_subscribed: Tell whether or not a folder has been subscribed to.
+ * @store: a CamelStore
+ * @folder_name: the folder on which we're querying subscribed status.
+ * Return value: TRUE if folder is subscribed, FALSE if not.
+ **/
+gboolean
+camel_store_folder_subscribed(CamelStore *store, const char *folder_name)
+{
+ gboolean ret;
+
+ g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE);
+ g_return_val_if_fail (store->flags & CAMEL_STORE_SUBSCRIPTIONS, FALSE);
+
+ CAMEL_STORE_LOCK(store, folder_lock);
+
+ ret = CS_CLASS (store)->folder_subscribed (store, folder_name);
+
+ CAMEL_STORE_UNLOCK(store, folder_lock);
+
+ return ret;
+}
+
+static void
+subscribe_folder(CamelStore *store, const char *folder_name, CamelException *ex)
+{
+ w(g_warning ("CamelStore::subscribe_folder not implemented for `%s'",
+ camel_type_to_name (CAMEL_OBJECT_GET_TYPE (store))));
+}
+
+/**
+ * camel_store_subscribe_folder: marks a folder as subscribed.
+ * @store: a CamelStore
+ * @folder_name: the folder to subscribe to.
+ **/
+void
+camel_store_subscribe_folder(CamelStore *store, const char *folder_name, CamelException *ex)
+{
+ g_return_if_fail (CAMEL_IS_STORE (store));
+ g_return_if_fail (store->flags & CAMEL_STORE_SUBSCRIPTIONS);
+
+ CAMEL_STORE_LOCK(store, folder_lock);
+
+ CS_CLASS (store)->subscribe_folder (store, folder_name, ex);
+
+ CAMEL_STORE_UNLOCK(store, folder_lock);
+}
+
+static void
+unsubscribe_folder(CamelStore *store, const char *folder_name, CamelException *ex)
+{
+ w(g_warning ("CamelStore::unsubscribe_folder not implemented for `%s'",
+ camel_type_to_name (CAMEL_OBJECT_GET_TYPE (store))));
+}
+
+/**
+ * camel_store_unsubscribe_folder: marks a folder as unsubscribed.
+ * @store: a CamelStore
+ * @folder_name: the folder to unsubscribe from.
+ **/
+void
+camel_store_unsubscribe_folder(CamelStore *store, const char *folder_name, CamelException *ex)
+{
+ CamelException local;
+
+ g_return_if_fail (CAMEL_IS_STORE (store));
+ g_return_if_fail (store->flags & CAMEL_STORE_SUBSCRIPTIONS);
+
+ camel_exception_init(&local);
+
+ CAMEL_STORE_LOCK(store, folder_lock);
+
+ CS_CLASS (store)->unsubscribe_folder (store, folder_name, ex);
+
+ if (!camel_exception_is_set(&local))
+ cs_delete_cached_folder(store, folder_name);
+ else
+ camel_exception_xfer(ex, &local);
+
+ CAMEL_STORE_UNLOCK(store, folder_lock);
+}
+
+static void
+noop (CamelStore *store, CamelException *ex)
+{
+ /* no-op */
+ ;
+}
+
+/**
+ * camel_store_noop:
+ * @store: CamelStore
+ * @ex: exception
+ *
+ * Pings @store so that its connection doesn't timeout.
+ **/
+void
+camel_store_noop (CamelStore *store, CamelException *ex)
+{
+ CS_CLASS (store)->noop (store, ex);
+}
+
+
+/**
+ * camel_store_folder_uri_equal:
+ * @store: CamelStore
+ * @uri0: a uri
+ * @uri1: another uri
+ *
+ * Compares 2 folder uris to check that they are equal.
+ *
+ * Returns %TRUE if they are equal or %FALSE otherwise.
+ **/
+int
+camel_store_folder_uri_equal (CamelStore *store, const char *uri0, const char *uri1)
+{
+ CamelProvider *provider;
+ CamelURL *url0, *url1;
+ int equal;
+
+ g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE);
+ g_return_val_if_fail (uri0 && uri1, FALSE);
+
+ provider = ((CamelService *) store)->provider;
+
+ if (!(url0 = camel_url_new (uri0, NULL)))
+ return FALSE;
+
+ if (!(url1 = camel_url_new (uri1, NULL))) {
+ camel_url_free (url0);
+ return FALSE;
+ }
+
+ if ((equal = provider->url_equal (url0, url1))) {
+ const char *name0, *name1;
+
+ if (provider->url_flags & CAMEL_URL_FRAGMENT_IS_PATH) {
+ name0 = url0->fragment;
+ name1 = url1->fragment;
+ } else {
+ name0 = url0->path[0] == '/' ? url0->path + 1 : url0->path;
+ name1 = url1->path[0] == '/' ? url1->path + 1 : url1->path;
+ }
+
+ equal = name0 && name1 && CS_CLASS (store)->compare_folder_name (name0, name1);
+ }
+
+ camel_url_free (url0);
+ camel_url_free (url1);
+
+ return equal;
+}
diff --git a/camel/camel-tcp-stream-raw.c b/camel/camel-tcp-stream-raw.c
new file mode 100644
index 0000000000..93f3fbdbab
--- /dev/null
+++ b/camel/camel-tcp-stream-raw.c
@@ -0,0 +1,518 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Jeffrey Stedfast <fejj@ximian.com>
+ *
+ * Copyright 2001-2003 Ximian, Inc. (www.ximian.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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "camel-tcp-stream-raw.h"
+#include "camel-file-utils.h"
+#include "camel-operation.h"
+
+static CamelTcpStreamClass *parent_class = NULL;
+
+/* Returns the class for a CamelTcpStreamRaw */
+#define CTSR_CLASS(so) CAMEL_TCP_STREAM_RAW_CLASS (CAMEL_OBJECT_GET_CLASS (so))
+
+static ssize_t stream_read (CamelStream *stream, char *buffer, size_t n);
+static ssize_t stream_write (CamelStream *stream, const char *buffer, size_t n);
+static int stream_flush (CamelStream *stream);
+static int stream_close (CamelStream *stream);
+
+static int stream_connect (CamelTcpStream *stream, struct addrinfo *host);
+static int stream_getsockopt (CamelTcpStream *stream, CamelSockOptData *data);
+static int stream_setsockopt (CamelTcpStream *stream, const CamelSockOptData *data);
+static struct sockaddr *stream_get_local_address (CamelTcpStream *stream, socklen_t *len);
+static struct sockaddr *stream_get_remote_address (CamelTcpStream *stream, socklen_t *len);
+
+static void
+camel_tcp_stream_raw_class_init (CamelTcpStreamRawClass *camel_tcp_stream_raw_class)
+{
+ CamelTcpStreamClass *camel_tcp_stream_class =
+ CAMEL_TCP_STREAM_CLASS (camel_tcp_stream_raw_class);
+ CamelStreamClass *camel_stream_class =
+ CAMEL_STREAM_CLASS (camel_tcp_stream_raw_class);
+
+ parent_class = CAMEL_TCP_STREAM_CLASS (camel_type_get_global_classfuncs (camel_tcp_stream_get_type ()));
+
+ /* virtual method overload */
+ camel_stream_class->read = stream_read;
+ camel_stream_class->write = stream_write;
+ camel_stream_class->flush = stream_flush;
+ camel_stream_class->close = stream_close;
+
+ camel_tcp_stream_class->connect = stream_connect;
+ camel_tcp_stream_class->getsockopt = stream_getsockopt;
+ camel_tcp_stream_class->setsockopt = stream_setsockopt;
+ camel_tcp_stream_class->get_local_address = stream_get_local_address;
+ camel_tcp_stream_class->get_remote_address = stream_get_remote_address;
+}
+
+static void
+camel_tcp_stream_raw_init (gpointer object, gpointer klass)
+{
+ CamelTcpStreamRaw *stream = CAMEL_TCP_STREAM_RAW (object);
+
+ stream->sockfd = -1;
+}
+
+static void
+camel_tcp_stream_raw_finalize (CamelObject *object)
+{
+ CamelTcpStreamRaw *stream = CAMEL_TCP_STREAM_RAW (object);
+
+ if (stream->sockfd != -1)
+ close (stream->sockfd);
+}
+
+
+CamelType
+camel_tcp_stream_raw_get_type (void)
+{
+ static CamelType type = CAMEL_INVALID_TYPE;
+
+ if (type == CAMEL_INVALID_TYPE) {
+ type = camel_type_register (camel_tcp_stream_get_type (),
+ "CamelTcpStreamRaw",
+ sizeof (CamelTcpStreamRaw),
+ sizeof (CamelTcpStreamRawClass),
+ (CamelObjectClassInitFunc) camel_tcp_stream_raw_class_init,
+ NULL,
+ (CamelObjectInitFunc) camel_tcp_stream_raw_init,
+ (CamelObjectFinalizeFunc) camel_tcp_stream_raw_finalize);
+ }
+
+ return type;
+}
+
+#ifdef SIMULATE_FLAKY_NETWORK
+static ssize_t
+flaky_tcp_write (int fd, const char *buffer, size_t buflen)
+{
+ size_t len = buflen;
+ ssize_t nwritten;
+ int val;
+
+ if (buflen == 0)
+ return 0;
+
+ val = 1 + (int) (10.0 * rand () / (RAND_MAX + 1.0));
+
+ switch (val) {
+ case 1:
+ printf ("flaky_tcp_write (%d, ..., %d): (-1) EINTR\n", fd, buflen);
+ errno = EINTR;
+ return -1;
+ case 2:
+ printf ("flaky_tcp_write (%d, ..., %d): (-1) EAGAIN\n", fd, buflen);
+ errno = EAGAIN;
+ return -1;
+ case 3:
+ printf ("flaky_tcp_write (%d, ..., %d): (-1) EWOULDBLOCK\n", fd, buflen);
+ errno = EWOULDBLOCK;
+ return -1;
+ case 4:
+ case 5:
+ case 6:
+ len = 1 + (size_t) (buflen * rand () / (RAND_MAX + 1.0));
+ len = MIN (len, buflen);
+ /* fall through... */
+ default:
+ printf ("flaky_tcp_write (%d, ..., %d): (%d) '%.*s'", fd, buflen, len, (int) len, buffer);
+ nwritten = write (fd, buffer, len);
+ if (nwritten < 0)
+ printf (" errno => %s\n", strerror (errno));
+ else if (nwritten < len)
+ printf (" only wrote %d bytes\n", nwritten);
+ else
+ printf ("\n");
+
+ return nwritten;
+ }
+}
+
+#define write(fd, buffer, buflen) flaky_tcp_write (fd, buffer, buflen)
+
+static ssize_t
+flaky_tcp_read (int fd, char *buffer, size_t buflen)
+{
+ size_t len = buflen;
+ ssize_t nread;
+ int val;
+
+ if (buflen == 0)
+ return 0;
+
+ val = 1 + (int) (10.0 * rand () / (RAND_MAX + 1.0));
+
+ switch (val) {
+ case 1:
+ printf ("flaky_tcp_read (%d, ..., %d): (-1) EINTR\n", fd, buflen);
+ errno = EINTR;
+ return -1;
+ case 2:
+ printf ("flaky_tcp_read (%d, ..., %d): (-1) EAGAIN\n", fd, buflen);
+ errno = EAGAIN;
+ return -1;
+ case 3:
+ printf ("flaky_tcp_read (%d, ..., %d): (-1) EWOULDBLOCK\n", fd, buflen);
+ errno = EWOULDBLOCK;
+ return -1;
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ len = 1 + (size_t) (10.0 * rand () / (RAND_MAX + 1.0));
+ len = MIN (len, buflen);
+ /* fall through... */
+ default:
+ printf ("flaky_tcp_read (%d, ..., %d): (%d)", fd, buflen, len);
+ nread = read (fd, buffer, len);
+ if (nread < 0)
+ printf (" errno => %s\n", strerror (errno));
+ else if (nread < len)
+ printf (" only read %d bytes\n", nread);
+ else
+ printf ("\n");
+
+ return nread;
+ }
+}
+
+#define read(fd, buffer, buflen) flaky_tcp_read (fd, buffer, buflen)
+
+#endif /* SIMULATE_FLAKY_NETWORK */
+
+
+
+/**
+ * camel_tcp_stream_raw_new:
+ *
+ * Return value: a tcp stream
+ **/
+CamelStream *
+camel_tcp_stream_raw_new ()
+{
+ CamelTcpStreamRaw *stream;
+
+ stream = CAMEL_TCP_STREAM_RAW (camel_object_new (camel_tcp_stream_raw_get_type ()));
+
+ return CAMEL_STREAM (stream);
+}
+
+static ssize_t
+stream_read (CamelStream *stream, char *buffer, size_t n)
+{
+ CamelTcpStreamRaw *raw = CAMEL_TCP_STREAM_RAW (stream);
+
+ return camel_read (raw->sockfd, buffer, n);
+}
+
+static ssize_t
+stream_write (CamelStream *stream, const char *buffer, size_t n)
+{
+ CamelTcpStreamRaw *raw = CAMEL_TCP_STREAM_RAW (stream);
+
+ return camel_write (raw->sockfd, buffer, n);
+}
+
+static int
+stream_flush (CamelStream *stream)
+{
+ return 0;
+}
+
+static int
+stream_close (CamelStream *stream)
+{
+ if (close (((CamelTcpStreamRaw *)stream)->sockfd) == -1)
+ return -1;
+
+ ((CamelTcpStreamRaw *)stream)->sockfd = -1;
+ return 0;
+}
+
+/* this is a 'cancellable' connect, cancellable from camel_operation_cancel etc */
+/* returns -1 & errno == EINTR if the connection was cancelled */
+static int
+socket_connect(struct addrinfo *h)
+{
+ struct timeval tv;
+ socklen_t len;
+ int cancel_fd;
+ int errnosav;
+ int ret, fd;
+
+ /* see if we're cancelled yet */
+ if (camel_operation_cancel_check (NULL)) {
+ errno = EINTR;
+ return -1;
+ }
+
+ if (h->ai_socktype != SOCK_STREAM) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if ((fd = socket (h->ai_family, SOCK_STREAM, 0)) == -1)
+ return -1;
+
+ cancel_fd = camel_operation_cancel_fd (NULL);
+ if (cancel_fd == -1) {
+ if (connect (fd, h->ai_addr, h->ai_addrlen) == -1) {
+ errnosav = errno;
+ close (fd);
+ errno = errnosav;
+ return -1;
+ }
+
+ return fd;
+ } else {
+ int flags, fdmax, status;
+ fd_set rdset, wrset;
+
+ flags = fcntl (fd, F_GETFL);
+ fcntl (fd, F_SETFL, flags | O_NONBLOCK);
+
+ if (connect (fd, h->ai_addr, h->ai_addrlen) == 0) {
+ fcntl (fd, F_SETFL, flags);
+ return fd;
+ }
+
+ if (errno != EINPROGRESS) {
+ errnosav = errno;
+ close (fd);
+ errno = errnosav;
+ return -1;
+ }
+
+ do {
+ FD_ZERO (&rdset);
+ FD_ZERO (&wrset);
+ FD_SET (fd, &wrset);
+ FD_SET (cancel_fd, &rdset);
+ fdmax = MAX (fd, cancel_fd) + 1;
+ tv.tv_sec = 60 * 4;
+ tv.tv_usec = 0;
+
+ status = select (fdmax, &rdset, &wrset, 0, &tv);
+ } while (status == -1 && errno == EINTR);
+
+ if (status <= 0) {
+ close (fd);
+ errno = ETIMEDOUT;
+ return -1;
+ }
+
+ if (cancel_fd != -1 && FD_ISSET (cancel_fd, &rdset)) {
+ close (fd);
+ errno = EINTR;
+ return -1;
+ } else {
+ len = sizeof (int);
+
+ if (getsockopt (fd, SOL_SOCKET, SO_ERROR, &ret, &len) == -1) {
+ errnosav = errno;
+ close (fd);
+ errno = errnosav;
+ return -1;
+ }
+
+ if (ret != 0) {
+ close (fd);
+ errno = ret;
+ return -1;
+ }
+ }
+
+ fcntl (fd, F_SETFL, flags);
+ }
+
+ return fd;
+}
+
+static int
+stream_connect (CamelTcpStream *stream, struct addrinfo *host)
+{
+ CamelTcpStreamRaw *raw = CAMEL_TCP_STREAM_RAW (stream);
+
+ g_return_val_if_fail (host != NULL, -1);
+
+ while (host) {
+ raw->sockfd = socket_connect(host);
+ if (raw->sockfd != -1)
+ return 0;
+
+ host = host->ai_next;
+ }
+
+ return -1;
+}
+
+static int
+get_sockopt_level (const CamelSockOptData *data)
+{
+ switch (data->option) {
+ case CAMEL_SOCKOPT_MAXSEGMENT:
+ case CAMEL_SOCKOPT_NODELAY:
+ return IPPROTO_TCP;
+ default:
+ return SOL_SOCKET;
+ }
+}
+
+static int
+get_sockopt_optname (const CamelSockOptData *data)
+{
+ switch (data->option) {
+ case CAMEL_SOCKOPT_MAXSEGMENT:
+ return TCP_MAXSEG;
+ case CAMEL_SOCKOPT_NODELAY:
+ return TCP_NODELAY;
+ case CAMEL_SOCKOPT_BROADCAST:
+ return SO_BROADCAST;
+ case CAMEL_SOCKOPT_KEEPALIVE:
+ return SO_KEEPALIVE;
+ case CAMEL_SOCKOPT_LINGER:
+ return SO_LINGER;
+ case CAMEL_SOCKOPT_RECVBUFFERSIZE:
+ return SO_RCVBUF;
+ case CAMEL_SOCKOPT_SENDBUFFERSIZE:
+ return SO_SNDBUF;
+ case CAMEL_SOCKOPT_REUSEADDR:
+ return SO_REUSEADDR;
+ case CAMEL_SOCKOPT_IPTYPEOFSERVICE:
+ return SO_TYPE;
+ default:
+ return -1;
+ }
+}
+
+static int
+stream_getsockopt (CamelTcpStream *stream, CamelSockOptData *data)
+{
+ int optname, optlen;
+
+ if ((optname = get_sockopt_optname (data)) == -1)
+ return -1;
+
+ if (data->option == CAMEL_SOCKOPT_NONBLOCKING) {
+ int flags;
+
+ flags = fcntl (((CamelTcpStreamRaw *)stream)->sockfd, F_GETFL);
+ if (flags == -1)
+ return -1;
+
+ data->value.non_blocking = flags & O_NONBLOCK ? TRUE : FALSE;
+
+ return 0;
+ }
+
+ return getsockopt (((CamelTcpStreamRaw *)stream)->sockfd,
+ get_sockopt_level (data),
+ optname,
+ (void *) &data->value,
+ &optlen);
+}
+
+static int
+stream_setsockopt (CamelTcpStream *stream, const CamelSockOptData *data)
+{
+ int optname;
+
+ if ((optname = get_sockopt_optname (data)) == -1)
+ return -1;
+
+ if (data->option == CAMEL_SOCKOPT_NONBLOCKING) {
+ int flags, set;
+
+ flags = fcntl (((CamelTcpStreamRaw *)stream)->sockfd, F_GETFL);
+ if (flags == -1)
+ return -1;
+
+ set = data->value.non_blocking ? O_NONBLOCK : 0;
+ flags = (flags & ~O_NONBLOCK) | set;
+
+ if (fcntl (((CamelTcpStreamRaw *)stream)->sockfd, F_SETFL, flags) == -1)
+ return -1;
+
+ return 0;
+ }
+
+ return setsockopt (((CamelTcpStreamRaw *)stream)->sockfd,
+ get_sockopt_level (data),
+ optname,
+ (void *) &data->value,
+ sizeof (data->value));
+}
+
+static struct sockaddr *
+stream_get_local_address (CamelTcpStream *stream, socklen_t *len)
+{
+#ifdef ENABLE_IPv6
+ struct sockaddr_in6 sin;
+#else
+ struct sockaddr_in sin;
+#endif
+ struct sockaddr *saddr = (struct sockaddr *)&sin;
+
+ *len = sizeof(sin);
+ if (getsockname (CAMEL_TCP_STREAM_RAW (stream)->sockfd, saddr, len) == -1)
+ return NULL;
+
+ saddr = g_malloc(*len);
+ memcpy(saddr, &sin, *len);
+
+ return saddr;
+}
+
+static struct sockaddr *
+stream_get_remote_address (CamelTcpStream *stream, socklen_t *len)
+{
+#ifdef ENABLE_IPv6
+ struct sockaddr_in6 sin;
+#else
+ struct sockaddr_in sin;
+#endif
+ struct sockaddr *saddr = (struct sockaddr *)&sin;
+
+ *len = sizeof(sin);
+ if (getpeername (CAMEL_TCP_STREAM_RAW (stream)->sockfd, saddr, len) == -1)
+ return NULL;
+
+ saddr = g_malloc(*len);
+ memcpy(saddr, &sin, *len);
+
+ return saddr;
+}
diff --git a/camel/camel-tcp-stream-ssl.c b/camel/camel-tcp-stream-ssl.c
new file mode 100644
index 0000000000..39bf89d468
--- /dev/null
+++ b/camel/camel-tcp-stream-ssl.c
@@ -0,0 +1,1256 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Jeffrey Stedfast <fejj@ximian.com>
+ *
+ * Copyright 2001 Ximian, Inc. (www.ximian.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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+/* NOTE: This is the default implementation of CamelTcpStreamSSL,
+ * used when the Mozilla NSS libraries are used. If you configured
+ * OpenSSL support instead, then this file won't be compiled and
+ * the CamelTcpStreamSSL implementation in camel-tcp-stream-openssl.c
+ * will be used instead.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_NSS
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+
+#include <nspr.h>
+#include <prio.h>
+#include <prerror.h>
+#include <prerr.h>
+#include <secerr.h>
+#include <sslerr.h>
+#include "nss.h" /* Don't use <> here or it will include the system nss.h instead */
+#include <ssl.h>
+#include <cert.h>
+#include <certdb.h>
+#include <pk11func.h>
+
+/* this is commented because otherwise we get an error about the
+ redefinition of MD5Context...yay */
+/*#include <e-util/md5-utils.h>*/
+
+#include "camel-tcp-stream-ssl.h"
+#include "camel-stream-fs.h"
+#include "camel-session.h"
+#include "camel-certdb.h"
+#include "camel-operation.h"
+
+/* from md5-utils.h */
+void md5_get_digest (const char *buffer, int buffer_size, unsigned char digest[16]);
+
+#define IO_TIMEOUT (PR_TicksPerSecond() * 4 * 60)
+#define CONNECT_TIMEOUT (PR_TicksPerSecond () * 4 * 60)
+
+static CamelTcpStreamClass *parent_class = NULL;
+
+/* Returns the class for a CamelTcpStreamSSL */
+#define CTSS_CLASS(so) CAMEL_TCP_STREAM_SSL_CLASS (CAMEL_OBJECT_GET_CLASS (so))
+
+static ssize_t stream_read (CamelStream *stream, char *buffer, size_t n);
+static ssize_t stream_write (CamelStream *stream, const char *buffer, size_t n);
+static int stream_flush (CamelStream *stream);
+static int stream_close (CamelStream *stream);
+
+static PRFileDesc *enable_ssl (CamelTcpStreamSSL *ssl, PRFileDesc *fd);
+
+static int stream_connect (CamelTcpStream *stream, struct addrinfo *host);
+static int stream_getsockopt (CamelTcpStream *stream, CamelSockOptData *data);
+static int stream_setsockopt (CamelTcpStream *stream, const CamelSockOptData *data);
+static struct sockaddr *stream_get_local_address (CamelTcpStream *stream, socklen_t *len);
+static struct sockaddr *stream_get_remote_address (CamelTcpStream *stream, socklen_t *len);
+
+struct _CamelTcpStreamSSLPrivate {
+ PRFileDesc *sockfd;
+
+ struct _CamelSession *session;
+ char *expected_host;
+ gboolean ssl_mode;
+ guint32 flags;
+};
+
+static void
+camel_tcp_stream_ssl_class_init (CamelTcpStreamSSLClass *camel_tcp_stream_ssl_class)
+{
+ CamelTcpStreamClass *camel_tcp_stream_class =
+ CAMEL_TCP_STREAM_CLASS (camel_tcp_stream_ssl_class);
+ CamelStreamClass *camel_stream_class =
+ CAMEL_STREAM_CLASS (camel_tcp_stream_ssl_class);
+
+ parent_class = CAMEL_TCP_STREAM_CLASS (camel_type_get_global_classfuncs (camel_tcp_stream_get_type ()));
+
+ /* virtual method overload */
+ camel_stream_class->read = stream_read;
+ camel_stream_class->write = stream_write;
+ camel_stream_class->flush = stream_flush;
+ camel_stream_class->close = stream_close;
+
+ camel_tcp_stream_class->connect = stream_connect;
+ camel_tcp_stream_class->getsockopt = stream_getsockopt;
+ camel_tcp_stream_class->setsockopt = stream_setsockopt;
+ camel_tcp_stream_class->get_local_address = stream_get_local_address;
+ camel_tcp_stream_class->get_remote_address = stream_get_remote_address;
+}
+
+static void
+camel_tcp_stream_ssl_init (gpointer object, gpointer klass)
+{
+ CamelTcpStreamSSL *stream = CAMEL_TCP_STREAM_SSL (object);
+
+ stream->priv = g_new0 (struct _CamelTcpStreamSSLPrivate, 1);
+}
+
+static void
+camel_tcp_stream_ssl_finalize (CamelObject *object)
+{
+ CamelTcpStreamSSL *stream = CAMEL_TCP_STREAM_SSL (object);
+
+ if (stream->priv->sockfd != NULL)
+ PR_Close (stream->priv->sockfd);
+
+ if (stream->priv->session)
+ camel_object_unref(stream->priv->session);
+
+ g_free (stream->priv->expected_host);
+
+ g_free (stream->priv);
+}
+
+
+CamelType
+camel_tcp_stream_ssl_get_type (void)
+{
+ static CamelType type = CAMEL_INVALID_TYPE;
+
+ if (type == CAMEL_INVALID_TYPE) {
+ type = camel_type_register (camel_tcp_stream_get_type (),
+ "CamelTcpStreamSSL",
+ sizeof (CamelTcpStreamSSL),
+ sizeof (CamelTcpStreamSSLClass),
+ (CamelObjectClassInitFunc) camel_tcp_stream_ssl_class_init,
+ NULL,
+ (CamelObjectInitFunc) camel_tcp_stream_ssl_init,
+ (CamelObjectFinalizeFunc) camel_tcp_stream_ssl_finalize);
+ }
+
+ return type;
+}
+
+
+/**
+ * camel_tcp_stream_ssl_new:
+ * @session: active session
+ * @expected_host: host that the stream is expected to connect with.
+ * @flags: ENABLE_SSL2, ENABLE_SSL3 and/or ENABLE_TLS
+ *
+ * Since the SSL certificate authenticator may need to prompt the
+ * user, a CamelSession is needed. @expected_host is needed as a
+ * protection against an MITM attack.
+ *
+ * Return value: a ssl stream (in ssl mode)
+ **/
+CamelStream *
+camel_tcp_stream_ssl_new (CamelSession *session, const char *expected_host, guint32 flags)
+{
+ CamelTcpStreamSSL *stream;
+
+ g_assert(CAMEL_IS_SESSION(session));
+
+ stream = CAMEL_TCP_STREAM_SSL (camel_object_new (camel_tcp_stream_ssl_get_type ()));
+
+ stream->priv->session = session;
+ camel_object_ref(session);
+ stream->priv->expected_host = g_strdup (expected_host);
+ stream->priv->ssl_mode = TRUE;
+ stream->priv->flags = flags;
+
+ return CAMEL_STREAM (stream);
+}
+
+
+/**
+ * camel_tcp_stream_ssl_new_raw:
+ * @session: active session
+ * @expected_host: host that the stream is expected to connect with.
+ * @flags: ENABLE_SSL2, ENABLE_SSL3 and/or ENABLE_TLS
+ *
+ * Since the SSL certificate authenticator may need to prompt the
+ * user, a CamelSession is needed. @expected_host is needed as a
+ * protection against an MITM attack.
+ *
+ * Return value: a ssl-capable stream (in non ssl mode)
+ **/
+CamelStream *
+camel_tcp_stream_ssl_new_raw (CamelSession *session, const char *expected_host, guint32 flags)
+{
+ CamelTcpStreamSSL *stream;
+
+ g_assert(CAMEL_IS_SESSION(session));
+
+ stream = CAMEL_TCP_STREAM_SSL (camel_object_new (camel_tcp_stream_ssl_get_type ()));
+
+ stream->priv->session = session;
+ camel_object_ref(session);
+ stream->priv->expected_host = g_strdup (expected_host);
+ stream->priv->ssl_mode = FALSE;
+ stream->priv->flags = flags;
+
+ return CAMEL_STREAM (stream);
+}
+
+
+static void
+set_errno (int code)
+{
+ /* FIXME: this should handle more. */
+ switch (code) {
+ case PR_INVALID_ARGUMENT_ERROR:
+ errno = EINVAL;
+ break;
+ case PR_PENDING_INTERRUPT_ERROR:
+ errno = EINTR;
+ break;
+ case PR_IO_PENDING_ERROR:
+ errno = EAGAIN;
+ break;
+ case PR_WOULD_BLOCK_ERROR:
+ errno = EWOULDBLOCK;
+ break;
+ case PR_IN_PROGRESS_ERROR:
+ errno = EINPROGRESS;
+ break;
+ case PR_ALREADY_INITIATED_ERROR:
+ errno = EALREADY;
+ break;
+ case PR_NETWORK_UNREACHABLE_ERROR:
+ errno = EHOSTUNREACH;
+ break;
+ case PR_CONNECT_REFUSED_ERROR:
+ errno = ECONNREFUSED;
+ break;
+ case PR_CONNECT_TIMEOUT_ERROR:
+ case PR_IO_TIMEOUT_ERROR:
+ errno = ETIMEDOUT;
+ break;
+ case PR_NOT_CONNECTED_ERROR:
+ errno = ENOTCONN;
+ break;
+ case PR_CONNECT_RESET_ERROR:
+ errno = ECONNRESET;
+ break;
+ case PR_IO_ERROR:
+ default:
+ errno = EIO;
+ break;
+ }
+}
+
+
+/**
+ * camel_tcp_stream_ssl_enable_ssl:
+ * @ssl: ssl stream
+ *
+ * Toggles an ssl-capable stream into ssl mode (if it isn't already).
+ *
+ * Returns 0 on success or -1 on fail.
+ **/
+int
+camel_tcp_stream_ssl_enable_ssl (CamelTcpStreamSSL *ssl)
+{
+ PRFileDesc *fd;
+
+ g_return_val_if_fail (CAMEL_IS_TCP_STREAM_SSL (ssl), -1);
+
+ if (ssl->priv->sockfd && !ssl->priv->ssl_mode) {
+ if (!(fd = enable_ssl (ssl, NULL))) {
+ set_errno (PR_GetError ());
+ return -1;
+ }
+
+ ssl->priv->sockfd = fd;
+
+ if (SSL_ResetHandshake (fd, FALSE) == SECFailure) {
+ set_errno (PR_GetError ());
+ return -1;
+ }
+
+ if (SSL_ForceHandshake (fd) == -1) {
+ set_errno (PR_GetError ());
+ return -1;
+ }
+ }
+
+ ssl->priv->ssl_mode = TRUE;
+
+ return 0;
+}
+
+
+static ssize_t
+stream_read (CamelStream *stream, char *buffer, size_t n)
+{
+ CamelTcpStreamSSL *tcp_stream_ssl = CAMEL_TCP_STREAM_SSL (stream);
+ PRFileDesc *cancel_fd;
+ ssize_t nread;
+
+ if (camel_operation_cancel_check (NULL)) {
+ errno = EINTR;
+ return -1;
+ }
+
+ cancel_fd = camel_operation_cancel_prfd (NULL);
+ if (cancel_fd == NULL) {
+ do {
+ nread = PR_Read (tcp_stream_ssl->priv->sockfd, buffer, n);
+ if (nread == -1)
+ set_errno (PR_GetError ());
+ } while (nread == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
+ } else {
+ PRSocketOptionData sockopts;
+ PRPollDesc pollfds[2];
+ gboolean nonblock;
+ int error;
+
+ /* get O_NONBLOCK options */
+ sockopts.option = PR_SockOpt_Nonblocking;
+ PR_GetSocketOption (tcp_stream_ssl->priv->sockfd, &sockopts);
+ sockopts.option = PR_SockOpt_Nonblocking;
+ nonblock = sockopts.value.non_blocking;
+ sockopts.value.non_blocking = TRUE;
+ PR_SetSocketOption (tcp_stream_ssl->priv->sockfd, &sockopts);
+
+ pollfds[0].fd = tcp_stream_ssl->priv->sockfd;
+ pollfds[0].in_flags = PR_POLL_READ;
+ pollfds[1].fd = cancel_fd;
+ pollfds[1].in_flags = PR_POLL_READ;
+
+ do {
+ PRInt32 res;
+
+ pollfds[0].out_flags = 0;
+ pollfds[1].out_flags = 0;
+ nread = -1;
+
+ res = PR_Poll(pollfds, 2, IO_TIMEOUT);
+ if (res == -1)
+ set_errno(PR_GetError());
+ else if (res == 0)
+ errno = ETIMEDOUT;
+ else if (pollfds[1].out_flags == PR_POLL_READ) {
+ errno = EINTR;
+ goto failed;
+ } else {
+ do {
+ nread = PR_Read (tcp_stream_ssl->priv->sockfd, buffer, n);
+ if (nread == -1)
+ set_errno (PR_GetError ());
+ } while (nread == -1 && errno == EINTR);
+ }
+ } while (nread == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
+
+ /* restore O_NONBLOCK options */
+ failed:
+ error = errno;
+ sockopts.option = PR_SockOpt_Nonblocking;
+ sockopts.value.non_blocking = nonblock;
+ PR_SetSocketOption (tcp_stream_ssl->priv->sockfd, &sockopts);
+ errno = error;
+ }
+
+ return nread;
+}
+
+static ssize_t
+stream_write (CamelStream *stream, const char *buffer, size_t n)
+{
+ CamelTcpStreamSSL *tcp_stream_ssl = CAMEL_TCP_STREAM_SSL (stream);
+ ssize_t w, written = 0;
+ PRFileDesc *cancel_fd;
+
+ if (camel_operation_cancel_check (NULL)) {
+ errno = EINTR;
+ return -1;
+ }
+
+ cancel_fd = camel_operation_cancel_prfd (NULL);
+ if (cancel_fd == NULL) {
+ do {
+ do {
+ w = PR_Write (tcp_stream_ssl->priv->sockfd, buffer + written, n - written);
+ if (w == -1)
+ set_errno (PR_GetError ());
+ } while (w == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
+
+ if (w > 0)
+ written += w;
+ } while (w != -1 && written < n);
+ } else {
+ PRSocketOptionData sockopts;
+ PRPollDesc pollfds[2];
+ gboolean nonblock;
+ int error;
+
+ /* get O_NONBLOCK options */
+ sockopts.option = PR_SockOpt_Nonblocking;
+ PR_GetSocketOption (tcp_stream_ssl->priv->sockfd, &sockopts);
+ sockopts.option = PR_SockOpt_Nonblocking;
+ nonblock = sockopts.value.non_blocking;
+ sockopts.value.non_blocking = TRUE;
+ PR_SetSocketOption (tcp_stream_ssl->priv->sockfd, &sockopts);
+
+ pollfds[0].fd = tcp_stream_ssl->priv->sockfd;
+ pollfds[0].in_flags = PR_POLL_WRITE;
+ pollfds[1].fd = cancel_fd;
+ pollfds[1].in_flags = PR_POLL_READ;
+
+ do {
+ PRInt32 res;
+
+ pollfds[0].out_flags = 0;
+ pollfds[1].out_flags = 0;
+ w = -1;
+
+ res = PR_Poll (pollfds, 2, IO_TIMEOUT);
+ if (res == -1) {
+ set_errno(PR_GetError());
+ if (errno == EINTR)
+ w = 0;
+ } else if (res == 0)
+ errno = ETIMEDOUT;
+ else if (pollfds[1].out_flags == PR_POLL_READ) {
+ errno = EINTR;
+ } else {
+ do {
+ w = PR_Write (tcp_stream_ssl->priv->sockfd, buffer + written, n - written);
+ if (w == -1)
+ set_errno (PR_GetError ());
+ } while (w == -1 && errno == EINTR);
+
+ if (w == -1) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ w = 0;
+ } else
+ written += w;
+ }
+ } while (w != -1 && written < n);
+
+ /* restore O_NONBLOCK options */
+ error = errno;
+ sockopts.option = PR_SockOpt_Nonblocking;
+ sockopts.value.non_blocking = nonblock;
+ PR_SetSocketOption (tcp_stream_ssl->priv->sockfd, &sockopts);
+ errno = error;
+ }
+
+ if (w == -1)
+ return -1;
+
+ return written;
+}
+
+static int
+stream_flush (CamelStream *stream)
+{
+ /*return PR_Sync (((CamelTcpStreamSSL *)stream)->priv->sockfd);*/
+ return 0;
+}
+
+static int
+stream_close (CamelStream *stream)
+{
+ if (PR_Close (((CamelTcpStreamSSL *)stream)->priv->sockfd) == PR_FAILURE)
+ return -1;
+
+ ((CamelTcpStreamSSL *)stream)->priv->sockfd = NULL;
+
+ return 0;
+}
+
+#if 0
+/* Since this is default implementation, let NSS handle it. */
+static SECStatus
+ssl_get_client_auth (void *data, PRFileDesc *sockfd,
+ struct CERTDistNamesStr *caNames,
+ struct CERTCertificateStr **pRetCert,
+ struct SECKEYPrivateKeyStr **pRetKey)
+{
+ SECStatus status = SECFailure;
+ SECKEYPrivateKey *privkey;
+ CERTCertificate *cert;
+ void *proto_win;
+
+ proto_win = SSL_RevealPinArg (sockfd);
+
+ if ((char *) data) {
+ cert = PK11_FindCertFromNickname ((char *) data, proto_win);
+ if (cert) {
+ privKey = PK11_FindKeyByAnyCert (cert, proto_win);
+ if (privkey) {
+ status = SECSuccess;
+ } else {
+ CERT_DestroyCertificate (cert);
+ }
+ }
+ } else {
+ /* no nickname given, automatically find the right cert */
+ CERTCertNicknames *names;
+ int i;
+
+ names = CERT_GetCertNicknames (CERT_GetDefaultCertDB (),
+ SEC_CERT_NICKNAMES_USER,
+ proto_win);
+
+ if (names != NULL) {
+ for (i = 0; i < names->numnicknames; i++) {
+ cert = PK11_FindCertFromNickname (names->nicknames[i],
+ proto_win);
+ if (!cert)
+ continue;
+
+ /* Only check unexpired certs */
+ if (CERT_CheckCertValidTimes (cert, PR_Now (), PR_FALSE) != secCertTimeValid) {
+ CERT_DestroyCertificate (cert);
+ continue;
+ }
+
+ status = NSS_CmpCertChainWCANames (cert, caNames);
+ if (status == SECSuccess) {
+ privkey = PK11_FindKeyByAnyCert (cert, proto_win);
+ if (privkey)
+ break;
+
+ status = SECFailure;
+ break;
+ }
+
+ CERT_FreeNicknames (names);
+ }
+ }
+ }
+
+ if (status == SECSuccess) {
+ *pRetCert = cert;
+ *pRetKey = privkey;
+ }
+
+ return status;
+}
+#endif
+
+#if 0
+/* Since this is the default NSS implementation, no need for us to use this. */
+static SECStatus
+ssl_auth_cert (void *data, PRFileDesc *sockfd, PRBool checksig, PRBool is_server)
+{
+ CERTCertificate *cert;
+ SECStatus status;
+ void *pinarg;
+ char *host;
+
+ cert = SSL_PeerCertificate (sockfd);
+ pinarg = SSL_RevealPinArg (sockfd);
+ status = CERT_VerifyCertNow ((CERTCertDBHandle *)data, cert,
+ checksig, certUsageSSLClient, pinarg);
+
+ if (status != SECSuccess)
+ return SECFailure;
+
+ /* Certificate is OK. Since this is the client side of an SSL
+ * connection, we need to verify that the name field in the cert
+ * matches the desired hostname. This is our defense against
+ * man-in-the-middle attacks.
+ */
+
+ /* SSL_RevealURL returns a hostname, not a URL. */
+ host = SSL_RevealURL (sockfd);
+
+ if (host && *host) {
+ status = CERT_VerifyCertName (cert, host);
+ } else {
+ PR_SetError (SSL_ERROR_BAD_CERT_DOMAIN, 0);
+ status = SECFailure;
+ }
+
+ if (host)
+ PR_Free (host);
+
+ return secStatus;
+}
+#endif
+
+CamelCert *camel_certdb_nss_cert_get(CamelCertDB *certdb, CERTCertificate *cert);
+CamelCert *camel_certdb_nss_cert_add(CamelCertDB *certdb, CERTCertificate *cert);
+void camel_certdb_nss_cert_set(CamelCertDB *certdb, CamelCert *ccert, CERTCertificate *cert);
+
+static char *
+cert_fingerprint(CERTCertificate *cert)
+{
+ unsigned char md5sum[16], fingerprint[50], *f;
+ int i;
+ const char tohex[16] = "0123456789abcdef";
+
+ md5_get_digest (cert->derCert.data, cert->derCert.len, md5sum);
+ for (i=0,f = fingerprint; i<16; i++) {
+ unsigned int c = md5sum[i];
+
+ *f++ = tohex[(c >> 4) & 0xf];
+ *f++ = tohex[c & 0xf];
+ *f++ = ':';
+ }
+
+ fingerprint[47] = 0;
+
+ return g_strdup(fingerprint);
+}
+
+/* lookup a cert uses fingerprint to index an on-disk file */
+CamelCert *
+camel_certdb_nss_cert_get(CamelCertDB *certdb, CERTCertificate *cert)
+{
+ char *fingerprint, *path;
+ CamelCert *ccert;
+ struct stat st;
+ size_t nread;
+ ssize_t n;
+ int fd;
+
+ fingerprint = cert_fingerprint (cert);
+ ccert = camel_certdb_get_cert (certdb, fingerprint);
+ if (ccert == NULL) {
+ g_free (fingerprint);
+ return ccert;
+ }
+
+ if (ccert->rawcert == NULL) {
+ path = g_strdup_printf ("%s/.camel_certs/%s", getenv ("HOME"), fingerprint);
+ if (stat (path, &st) == -1
+ || (fd = open (path, O_RDONLY)) == -1) {
+ g_warning ("could not load cert %s: %s", path, strerror (errno));
+ g_free (fingerprint);
+ g_free (path);
+ camel_cert_set_trust (certdb, ccert, CAMEL_CERT_TRUST_UNKNOWN);
+ camel_certdb_touch (certdb);
+
+ return ccert;
+ }
+ g_free(path);
+
+ ccert->rawcert = g_byte_array_new ();
+ g_byte_array_set_size (ccert->rawcert, st.st_size);
+
+ nread = 0;
+ do {
+ do {
+ n = read (fd, ccert->rawcert->data + nread, st.st_size - nread);
+ } while (n == -1 && errno == EINTR);
+
+ if (n > 0)
+ nread += n;
+ } while (nread < st.st_size && n != -1);
+
+ close (fd);
+
+ if (nread != st.st_size) {
+ g_warning ("cert size read truncated %s: %d != %ld", path, nread, st.st_size);
+ g_byte_array_free(ccert->rawcert, TRUE);
+ ccert->rawcert = NULL;
+ g_free(fingerprint);
+ camel_cert_set_trust(certdb, ccert, CAMEL_CERT_TRUST_UNKNOWN);
+ camel_certdb_touch(certdb);
+
+ return ccert;
+ }
+ }
+
+ g_free(fingerprint);
+ if (ccert->rawcert->len != cert->derCert.len
+ || memcmp(ccert->rawcert->data, cert->derCert.data, cert->derCert.len) != 0) {
+ g_warning("rawcert != derCer");
+ camel_cert_set_trust(certdb, ccert, CAMEL_CERT_TRUST_UNKNOWN);
+ camel_certdb_touch(certdb);
+ }
+
+ return ccert;
+}
+
+/* add a cert to the certdb */
+CamelCert *
+camel_certdb_nss_cert_add(CamelCertDB *certdb, CERTCertificate *cert)
+{
+ CamelCert *ccert;
+ char *fingerprint;
+
+ fingerprint = cert_fingerprint(cert);
+
+ ccert = camel_certdb_cert_new(certdb);
+ camel_cert_set_issuer(certdb, ccert, CERT_NameToAscii(&cert->issuer));
+ camel_cert_set_subject(certdb, ccert, CERT_NameToAscii(&cert->subject));
+ /* hostname is set in caller */
+ /*camel_cert_set_hostname(certdb, ccert, ssl->priv->expected_host);*/
+ camel_cert_set_fingerprint(certdb, ccert, fingerprint);
+ camel_cert_set_trust(certdb, ccert, CAMEL_CERT_TRUST_UNKNOWN);
+ g_free(fingerprint);
+
+ camel_certdb_nss_cert_set(certdb, ccert, cert);
+
+ camel_certdb_add(certdb, ccert);
+
+ return ccert;
+}
+
+/* set the 'raw' cert (& save it) */
+void
+camel_certdb_nss_cert_set(CamelCertDB *certdb, CamelCert *ccert, CERTCertificate *cert)
+{
+ char *dir, *path, *fingerprint;
+ CamelStream *stream;
+ struct stat st;
+
+ fingerprint = ccert->fingerprint;
+
+ if (ccert->rawcert == NULL)
+ ccert->rawcert = g_byte_array_new ();
+
+ g_byte_array_set_size (ccert->rawcert, cert->derCert.len);
+ memcpy (ccert->rawcert->data, cert->derCert.data, cert->derCert.len);
+
+ dir = g_strdup_printf ("%s/.camel_certs", getenv ("HOME"));
+ if (stat (dir, &st) == -1 && mkdir (dir, 0700) == -1) {
+ g_warning ("Could not create cert directory '%s': %s", dir, strerror (errno));
+ g_free (dir);
+ return;
+ }
+
+ path = g_strdup_printf ("%s/%s", dir, fingerprint);
+ g_free (dir);
+
+ stream = camel_stream_fs_new_with_name (path, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+ if (stream != NULL) {
+ if (camel_stream_write (stream, ccert->rawcert->data, ccert->rawcert->len) == -1) {
+ g_warning ("Could not save cert: %s: %s", path, strerror (errno));
+ unlink (path);
+ }
+ camel_stream_close (stream);
+ camel_object_unref (stream);
+ } else {
+ g_warning ("Could not save cert: %s: %s", path, strerror (errno));
+ }
+
+ g_free (path);
+}
+
+
+#if 0
+/* used by the mozilla-like code below */
+static char *
+get_nickname(CERTCertificate *cert)
+{
+ char *server, *nick = NULL;
+ int i;
+ PRBool status = PR_TRUE;
+
+ server = CERT_GetCommonName(&cert->subject);
+ if (server == NULL)
+ return NULL;
+
+ for (i=1;status == PR_TRUE;i++) {
+ if (nick) {
+ g_free(nick);
+ nick = g_strdup_printf("%s #%d", server, i);
+ } else {
+ nick = g_strdup(server);
+ }
+ status = SEC_CertNicknameConflict(server, &cert->derSubject, cert->dbhandle);
+ }
+
+ return nick;
+}
+#endif
+
+static SECStatus
+ssl_bad_cert (void *data, PRFileDesc *sockfd)
+{
+ gboolean accept;
+ CamelCertDB *certdb = NULL;
+ CamelCert *ccert = NULL;
+ char *prompt, *cert_str, *fingerprint;
+ CamelTcpStreamSSL *ssl;
+ CERTCertificate *cert;
+ SECStatus status = SECFailure;
+
+ g_return_val_if_fail (data != NULL, SECFailure);
+ g_return_val_if_fail (CAMEL_IS_TCP_STREAM_SSL (data), SECFailure);
+
+ ssl = data;
+
+ cert = SSL_PeerCertificate (sockfd);
+ if (cert == NULL)
+ return SECFailure;
+
+ certdb = camel_certdb_get_default();
+ ccert = camel_certdb_nss_cert_get(certdb, cert);
+ if (ccert == NULL) {
+ ccert = camel_certdb_nss_cert_add(certdb, cert);
+ camel_cert_set_hostname(certdb, ccert, ssl->priv->expected_host);
+ }
+
+ if (ccert->trust == CAMEL_CERT_TRUST_UNKNOWN) {
+ status = CERT_VerifyCertNow(cert->dbhandle, cert, TRUE, certUsageSSLClient, NULL);
+ fingerprint = cert_fingerprint(cert);
+ cert_str = g_strdup_printf (_("Issuer: %s\n"
+ "Subject: %s\n"
+ "Fingerprint: %s\n"
+ "Signature: %s"),
+ CERT_NameToAscii (&cert->issuer),
+ CERT_NameToAscii (&cert->subject),
+ fingerprint, status == SECSuccess?_("GOOD"):_("BAD"));
+ g_free(fingerprint);
+
+ /* construct our user prompt */
+ prompt = g_strdup_printf (_("SSL Certificate check for %s:\n\n%s\n\nDo you wish to accept?"),
+ ssl->priv->expected_host, cert_str);
+ g_free (cert_str);
+
+ /* query the user to find out if we want to accept this certificate */
+ accept = camel_session_alert_user (ssl->priv->session, CAMEL_SESSION_ALERT_WARNING, prompt, TRUE);
+ g_free(prompt);
+ if (accept) {
+ camel_certdb_nss_cert_set(certdb, ccert, cert);
+ camel_cert_set_trust(certdb, ccert, CAMEL_CERT_TRUST_FULLY);
+ camel_certdb_touch(certdb);
+ }
+ } else {
+ accept = ccert->trust != CAMEL_CERT_TRUST_NEVER;
+ }
+
+ camel_certdb_cert_unref(certdb, ccert);
+ camel_object_unref(certdb);
+
+ return accept ? SECSuccess : SECFailure;
+
+#if 0
+ int i, error;
+ CERTCertTrust trust;
+ SECItem *certs[1];
+ int go = 1;
+ char *host, *nick;
+
+ error = PR_GetError();
+
+ /* This code is basically what mozilla does - however it doesn't seem to work here
+ very reliably :-/ */
+ while (go && status != SECSuccess) {
+ char *prompt = NULL;
+
+ printf("looping, error '%d'\n", error);
+
+ switch(error) {
+ case SEC_ERROR_UNKNOWN_ISSUER:
+ case SEC_ERROR_CA_CERT_INVALID:
+ case SEC_ERROR_UNTRUSTED_ISSUER:
+ case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
+ /* add certificate */
+ printf("unknown issuer, adding ... \n");
+ prompt = g_strdup_printf(_("Certificate problem: %s\nIssuer: %s"), cert->subjectName, cert->issuerName);
+
+ if (camel_session_alert_user(ssl->priv->session, CAMEL_SESSION_ALERT_WARNING, prompt, TRUE)) {
+
+ nick = get_nickname(cert);
+ if (NULL == nick) {
+ g_free(prompt);
+ status = SECFailure;
+ break;
+ }
+
+ printf("adding cert '%s'\n", nick);
+
+ if (!cert->trust) {
+ cert->trust = (CERTCertTrust*)PORT_ArenaZAlloc(cert->arena, sizeof(CERTCertTrust));
+ CERT_DecodeTrustString(cert->trust, "P");
+ }
+
+ certs[0] = &cert->derCert;
+ /*CERT_ImportCerts (cert->dbhandle, certUsageSSLServer, 1, certs, NULL, TRUE, FALSE, nick);*/
+ CERT_ImportCerts(cert->dbhandle, certUsageUserCertImport, 1, certs, NULL, TRUE, FALSE, nick);
+ g_free(nick);
+
+ printf(" cert type %08x\n", cert->nsCertType);
+
+ memset((void*)&trust, 0, sizeof(trust));
+ if (CERT_GetCertTrust(cert, &trust) != SECSuccess) {
+ CERT_DecodeTrustString(&trust, "P");
+ }
+ trust.sslFlags |= CERTDB_VALID_PEER | CERTDB_TRUSTED;
+ if (CERT_ChangeCertTrust(cert->dbhandle, cert, &trust) != SECSuccess) {
+ printf("couldn't change cert trust?\n");
+ }
+
+ /*status = SECSuccess;*/
+#if 1
+ /* re-verify? */
+ status = CERT_VerifyCertNow(cert->dbhandle, cert, TRUE, certUsageSSLServer, NULL);
+ error = PR_GetError();
+ printf("re-verify status %d, error %d\n", status, error);
+#endif
+
+ printf(" cert type %08x\n", cert->nsCertType);
+ } else {
+ printf("failed/cancelled\n");
+ go = 0;
+ }
+
+ break;
+ case SSL_ERROR_BAD_CERT_DOMAIN:
+ printf("bad domain\n");
+
+ prompt = g_strdup_printf(_("Bad certificate domain: %s\nIssuer: %s"), cert->subjectName, cert->issuerName);
+
+ if (camel_session_alert_user (ssl->priv->session, CAMEL_SESSION_ALERT_WARNING, prompt, TRUE)) {
+ host = SSL_RevealURL(sockfd);
+ status = CERT_AddOKDomainName(cert, host);
+ printf("add ok domain name : %s\n", status == SECFailure?"fail":"ok");
+ error = PR_GetError();
+ if (status == SECFailure)
+ go = 0;
+ } else {
+ go = 0;
+ }
+
+ break;
+
+ case SEC_ERROR_EXPIRED_CERTIFICATE:
+ printf("expired\n");
+
+ prompt = g_strdup_printf(_("Certificate expired: %s\nIssuer: %s"), cert->subjectName, cert->issuerName);
+
+ if (camel_session_alert_user(ssl->priv->session, CAMEL_SESSION_ALERT_WARNING, prompt, TRUE)) {
+ cert->timeOK = PR_TRUE;
+ status = CERT_VerifyCertNow(cert->dbhandle, cert, TRUE, certUsageSSLClient, NULL);
+ error = PR_GetError();
+ if (status == SECFailure)
+ go = 0;
+ } else {
+ go = 0;
+ }
+
+ break;
+
+ case SEC_ERROR_CRL_EXPIRED:
+ printf("crl expired\n");
+
+ prompt = g_strdup_printf(_("Certificate revocation list expired: %s\nIssuer: %s"), cert->subjectName, cert->issuerName);
+
+ if (camel_session_alert_user(ssl->priv->session, CAMEL_SESSION_ALERT_WARNING, prompt, TRUE)) {
+ host = SSL_RevealURL(sockfd);
+ status = CERT_AddOKDomainName(cert, host);
+ }
+
+ go = 0;
+ break;
+
+ default:
+ printf("generic error\n");
+ go = 0;
+ break;
+ }
+
+ g_free(prompt);
+ }
+
+ CERT_DestroyCertificate(cert);
+
+ return status;
+#endif
+}
+
+static PRFileDesc *
+enable_ssl (CamelTcpStreamSSL *ssl, PRFileDesc *fd)
+{
+ PRFileDesc *ssl_fd;
+
+ ssl_fd = SSL_ImportFD (NULL, fd ? fd : ssl->priv->sockfd);
+ if (!ssl_fd)
+ return NULL;
+
+ SSL_OptionSet (ssl_fd, SSL_SECURITY, PR_TRUE);
+ if (ssl->priv->flags & CAMEL_TCP_STREAM_SSL_ENABLE_SSL2)
+ SSL_OptionSet (ssl_fd, SSL_ENABLE_SSL2, PR_TRUE);
+ else
+ SSL_OptionSet (ssl_fd, SSL_ENABLE_SSL2, PR_FALSE);
+ if (ssl->priv->flags & CAMEL_TCP_STREAM_SSL_ENABLE_SSL3)
+ SSL_OptionSet (ssl_fd, SSL_ENABLE_SSL3, PR_TRUE);
+ else
+ SSL_OptionSet (ssl_fd, SSL_ENABLE_SSL3, PR_FALSE);
+ if (ssl->priv->flags & CAMEL_TCP_STREAM_SSL_ENABLE_TLS)
+ SSL_OptionSet (ssl_fd, SSL_ENABLE_TLS, PR_TRUE);
+ else
+ SSL_OptionSet (ssl_fd, SSL_ENABLE_TLS, PR_FALSE);
+
+ SSL_SetURL (ssl_fd, ssl->priv->expected_host);
+
+ /*SSL_GetClientAuthDataHook (sslSocket, ssl_get_client_auth, (void *) certNickname);*/
+ /*SSL_AuthCertificateHook (ssl_fd, ssl_auth_cert, (void *) CERT_GetDefaultCertDB ());*/
+ SSL_BadCertHook (ssl_fd, ssl_bad_cert, ssl);
+
+ ssl->priv->ssl_mode = TRUE;
+
+ return ssl_fd;
+}
+
+static int
+sockaddr_to_praddr(struct sockaddr *s, int len, PRNetAddr *addr)
+{
+ /* We assume the ip addresses are the same size - they have to be anyway.
+ We could probably just use memcpy *shrug* */
+
+ memset(addr, 0, sizeof(*addr));
+
+ if (s->sa_family == AF_INET) {
+ struct sockaddr_in *sin = (struct sockaddr_in *)s;
+
+ if (len < sizeof(*sin))
+ return -1;
+
+ addr->inet.family = PR_AF_INET;
+ addr->inet.port = sin->sin_port;
+ memcpy(&addr->inet.ip, &sin->sin_addr, sizeof(addr->inet.ip));
+
+ return 0;
+ }
+#ifdef ENABLE_IPv6
+ else if (s->sa_family == PR_AF_INET6) {
+ struct sockaddr_in6 *sin = (struct sockaddr_in6 *)s;
+
+ if (len < sizeof(*sin))
+ return -1;
+
+ addr->ipv6.family = PR_AF_INET6;
+ addr->ipv6.port = sin->sin6_port;
+ addr->ipv6.flowinfo = sin->sin6_flowinfo;
+ memcpy(&addr->ipv6.ip, &sin->sin6_addr, sizeof(addr->ipv6.ip));
+ addr->ipv6.scope_id = sin->sin6_scope_id;
+
+ return 0;
+ }
+#endif
+
+ return -1;
+}
+
+static int
+socket_connect(CamelTcpStream *stream, struct addrinfo *host)
+{
+ CamelTcpStreamSSL *ssl = CAMEL_TCP_STREAM_SSL (stream);
+ PRNetAddr netaddr;
+ PRFileDesc *fd, *cancel_fd;
+
+ if (sockaddr_to_praddr(host->ai_addr, host->ai_addrlen, &netaddr) != 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ fd = PR_OpenTCPSocket(netaddr.raw.family);
+ if (fd == NULL) {
+ set_errno (PR_GetError ());
+ return -1;
+ }
+
+ if (ssl->priv->ssl_mode) {
+ PRFileDesc *ssl_fd;
+
+ ssl_fd = enable_ssl (ssl, fd);
+ if (ssl_fd == NULL) {
+ int errnosave;
+
+ set_errno (PR_GetError ());
+ errnosave = errno;
+ PR_Close (fd);
+ errno = errnosave;
+
+ return -1;
+ }
+
+ fd = ssl_fd;
+ }
+
+ cancel_fd = camel_operation_cancel_prfd(NULL);
+
+ if (PR_Connect (fd, &netaddr, cancel_fd?0:CONNECT_TIMEOUT) == PR_FAILURE) {
+ int errnosave;
+
+ set_errno (PR_GetError ());
+ if (errno == EINPROGRESS || (cancel_fd && errno == ETIMEDOUT)) {
+ gboolean connected = FALSE;
+ PRPollDesc poll[2];
+
+ poll[0].fd = fd;
+ poll[0].in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT;
+ poll[1].fd = cancel_fd;
+ poll[1].in_flags = PR_POLL_READ;
+
+ do {
+ poll[0].out_flags = 0;
+ poll[1].out_flags = 0;
+
+ if (PR_Poll (poll, cancel_fd?2:1, CONNECT_TIMEOUT) == PR_FAILURE) {
+ set_errno (PR_GetError ());
+ goto exception;
+ }
+
+ if (poll[1].out_flags == PR_POLL_READ) {
+ errno = EINTR;
+ goto exception;
+ }
+
+ if (PR_ConnectContinue(fd, poll[0].out_flags) == PR_FAILURE) {
+ set_errno (PR_GetError ());
+ if (errno != EINPROGRESS)
+ goto exception;
+ } else {
+ connected = TRUE;
+ }
+ } while (!connected);
+ } else {
+ exception:
+ errnosave = errno;
+ PR_Close (fd);
+ ssl->priv->sockfd = NULL;
+ errno = errnosave;
+
+ return -1;
+ }
+
+ errno = 0;
+ }
+
+ ssl->priv->sockfd = fd;
+
+ return 0;
+}
+
+static int
+stream_connect(CamelTcpStream *stream, struct addrinfo *host)
+{
+ while (host) {
+ if (socket_connect(stream, host) == 0)
+ return 0;
+ host = host->ai_next;
+ }
+
+ return -1;
+}
+
+static int
+stream_getsockopt (CamelTcpStream *stream, CamelSockOptData *data)
+{
+ PRSocketOptionData sodata;
+
+ memset ((void *) &sodata, 0, sizeof (sodata));
+ memcpy ((void *) &sodata, (void *) data, sizeof (CamelSockOptData));
+
+ if (PR_GetSocketOption (((CamelTcpStreamSSL *)stream)->priv->sockfd, &sodata) == PR_FAILURE)
+ return -1;
+
+ memcpy ((void *) data, (void *) &sodata, sizeof (CamelSockOptData));
+
+ return 0;
+}
+
+static int
+stream_setsockopt (CamelTcpStream *stream, const CamelSockOptData *data)
+{
+ PRSocketOptionData sodata;
+
+ memset ((void *) &sodata, 0, sizeof (sodata));
+ memcpy ((void *) &sodata, (void *) data, sizeof (CamelSockOptData));
+
+ if (PR_SetSocketOption (((CamelTcpStreamSSL *)stream)->priv->sockfd, &sodata) == PR_FAILURE)
+ return -1;
+
+ return 0;
+}
+
+static struct sockaddr *
+sockaddr_from_praddr(PRNetAddr *addr, socklen_t *len)
+{
+ /* We assume the ip addresses are the same size - they have to be anyway */
+
+ if (addr->raw.family == PR_AF_INET) {
+ struct sockaddr_in *sin = g_malloc0(sizeof(*sin));
+
+ sin->sin_family = AF_INET;
+ sin->sin_port = addr->inet.port;
+ memcpy(&sin->sin_addr, &addr->inet.ip, sizeof(sin->sin_addr));
+ *len = sizeof(*sin);
+
+ return (struct sockaddr *)sin;
+ }
+#ifdef ENABLE_IPv6
+ else if (addr->raw.family == PR_AF_INET6) {
+ struct sockaddr_in6 *sin = g_malloc0(sizeof(*sin));
+
+ sin->sin6_family = AF_INET6;
+ sin->sin6_port = addr->ipv6.port;
+ sin->sin6_flowinfo = addr->ipv6.flowinfo;
+ memcpy(&sin->sin6_addr, &addr->ipv6.ip, sizeof(sin->sin6_addr));
+ sin->sin6_scope_id = addr->ipv6.scope_id;
+ *len = sizeof(*sin);
+
+ return (struct sockaddr *)sin;
+ }
+#endif
+
+ return NULL;
+}
+
+static struct sockaddr *
+stream_get_local_address(CamelTcpStream *stream, socklen_t *len)
+{
+ PRFileDesc *sockfd = CAMEL_TCP_STREAM_SSL (stream)->priv->sockfd;
+ PRNetAddr addr;
+
+ if (PR_GetSockName(sockfd, &addr) != PR_SUCCESS)
+ return NULL;
+
+ return sockaddr_from_praddr(&addr, len);
+}
+
+static struct sockaddr *
+stream_get_remote_address (CamelTcpStream *stream, socklen_t *len)
+{
+ PRFileDesc *sockfd = CAMEL_TCP_STREAM_SSL (stream)->priv->sockfd;
+ PRNetAddr addr;
+
+ if (PR_GetPeerName(sockfd, &addr) != PR_SUCCESS)
+ return NULL;
+
+ return sockaddr_from_praddr(&addr, len);
+}
+
+#endif /* HAVE_NSS */
diff --git a/camel/camel-tcp-stream.c b/camel/camel-tcp-stream.c
new file mode 100644
index 0000000000..3aa2d0d368
--- /dev/null
+++ b/camel/camel-tcp-stream.c
@@ -0,0 +1,208 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Jeffrey Stedfast <fejj@ximian.com>
+ *
+ * Copyright 2001 Ximian, Inc. (www.ximian.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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include "camel-tcp-stream.h"
+
+#define w(x)
+
+static CamelStreamClass *parent_class = NULL;
+
+/* Returns the class for a CamelTcpStream */
+#define CTS_CLASS(so) CAMEL_TCP_STREAM_CLASS (CAMEL_OBJECT_GET_CLASS(so))
+
+static int tcp_connect (CamelTcpStream *stream, struct addrinfo *host);
+static int tcp_getsockopt (CamelTcpStream *stream, CamelSockOptData *data);
+static int tcp_setsockopt (CamelTcpStream *stream, const CamelSockOptData *data);
+static struct sockaddr *tcp_get_local_address (CamelTcpStream *stream, socklen_t *len);
+static struct sockaddr *tcp_get_remote_address (CamelTcpStream *stream, socklen_t *len);
+
+static void
+camel_tcp_stream_class_init (CamelTcpStreamClass *camel_tcp_stream_class)
+{
+ /*CamelStreamClass *camel_stream_class = CAMEL_STREAM_CLASS (camel_tcp_stream_class);*/
+
+ parent_class = CAMEL_STREAM_CLASS (camel_type_get_global_classfuncs (CAMEL_STREAM_TYPE));
+
+ /* tcp stream methods */
+ camel_tcp_stream_class->connect = tcp_connect;
+ camel_tcp_stream_class->getsockopt = tcp_getsockopt;
+ camel_tcp_stream_class->setsockopt = tcp_setsockopt;
+ camel_tcp_stream_class->get_local_address = tcp_get_local_address;
+ camel_tcp_stream_class->get_remote_address = tcp_get_remote_address;
+}
+
+static void
+camel_tcp_stream_init (void *o)
+{
+ ;
+}
+
+CamelType
+camel_tcp_stream_get_type (void)
+{
+ static CamelType type = CAMEL_INVALID_TYPE;
+
+ if (type == CAMEL_INVALID_TYPE) {
+ type = camel_type_register (CAMEL_STREAM_TYPE,
+ "CamelTcpStream",
+ sizeof (CamelTcpStream),
+ sizeof (CamelTcpStreamClass),
+ (CamelObjectClassInitFunc) camel_tcp_stream_class_init,
+ NULL,
+ (CamelObjectInitFunc) camel_tcp_stream_init,
+ NULL);
+ }
+
+ return type;
+}
+
+
+static int
+tcp_connect (CamelTcpStream *stream, struct addrinfo *host)
+{
+ w(g_warning ("CamelTcpStream::connect called on default implementation"));
+ return -1;
+}
+
+/**
+ * camel_tcp_stream_connect:
+ * @stream: a CamelTcpStream object.
+ * @host: A linked list of addrinfo structures to try to connect, in
+ * the order of most likely to least likely to work.
+ *
+ * Create a socket and connect based upon the data provided.
+ *
+ * Return value: zero on success or -1 on fail.
+ **/
+int
+camel_tcp_stream_connect (CamelTcpStream *stream, struct addrinfo *host)
+{
+ g_return_val_if_fail (CAMEL_IS_TCP_STREAM (stream), -1);
+
+ return CTS_CLASS (stream)->connect (stream, host);
+}
+
+static int
+tcp_getsockopt (CamelTcpStream *stream, CamelSockOptData *data)
+{
+ w(g_warning ("CamelTcpStream::getsockopt called on default implementation"));
+ return -1;
+}
+
+/**
+ * camel_tcp_stream_getsockopt:
+ * @stream: tcp stream object
+ * @data: socket option data
+ *
+ * Get the socket options set on the stream and populate #data.
+ *
+ * Return value: zero on success or -1 on fail.
+ **/
+int
+camel_tcp_stream_getsockopt (CamelTcpStream *stream, CamelSockOptData *data)
+{
+ g_return_val_if_fail (CAMEL_IS_TCP_STREAM (stream), -1);
+
+ return CTS_CLASS (stream)->getsockopt (stream, data);
+}
+
+static int
+tcp_setsockopt (CamelTcpStream *stream, const CamelSockOptData *data)
+{
+ w(g_warning ("CamelTcpStream::setsockopt called on default implementation"));
+ return -1;
+}
+
+/**
+ * camel_tcp_stream_setsockopt:
+ * @stream: tcp stream object
+ * @data: socket option data
+ *
+ * Set the socket options contained in #data on the stream.
+ *
+ * Return value: zero on success or -1 on fail.
+ **/
+int
+camel_tcp_stream_setsockopt (CamelTcpStream *stream, const CamelSockOptData *data)
+{
+ g_return_val_if_fail (CAMEL_IS_TCP_STREAM (stream), -1);
+
+ return CTS_CLASS (stream)->setsockopt (stream, data);
+}
+
+static struct sockaddr *
+tcp_get_local_address (CamelTcpStream *stream, socklen_t *len)
+{
+ w(g_warning ("CamelTcpStream::get_local_address called on default implementation"));
+ return NULL;
+}
+
+/**
+ * camel_tcp_stream_get_local_address:
+ * @stream: tcp stream object
+ * @len: Pointer to address length which must be supplied.
+ *
+ * Get the local address of @stream.
+ *
+ * Return value: the stream's local address (which must be freed with
+ * g_free()) if the stream is connected, or %NULL if not.
+ **/
+struct sockaddr *
+camel_tcp_stream_get_local_address (CamelTcpStream *stream, socklen_t *len)
+{
+ g_return_val_if_fail (CAMEL_IS_TCP_STREAM (stream), NULL);
+ g_return_val_if_fail(len != NULL, NULL);
+
+ return CTS_CLASS (stream)->get_local_address (stream, len);
+}
+
+static struct sockaddr *
+tcp_get_remote_address (CamelTcpStream *stream, socklen_t *len)
+{
+ w(g_warning ("CamelTcpStream::get_remote_address called on default implementation"));
+ return NULL;
+}
+
+/**
+ * camel_tcp_stream_get_remote_address:
+ * @stream: tcp stream object
+ * @len: Pointer to address length, which must be supplied.
+ *
+ * Get the remote address of @stream.
+ *
+ * Return value: the stream's remote address (which must be freed with
+ * g_free()) if the stream is connected, or %NULL if not.
+ **/
+struct sockaddr *
+camel_tcp_stream_get_remote_address (CamelTcpStream *stream, socklen_t *len)
+{
+ g_return_val_if_fail (CAMEL_IS_TCP_STREAM (stream), NULL);
+ g_return_val_if_fail(len != NULL, NULL);
+
+ return CTS_CLASS (stream)->get_remote_address (stream, len);
+}
diff --git a/camel/camel-tcp-stream.h b/camel/camel-tcp-stream.h
new file mode 100644
index 0000000000..b7be61dbec
--- /dev/null
+++ b/camel/camel-tcp-stream.h
@@ -0,0 +1,123 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Jeffrey Stedfast <fejj@ximian.com>
+ *
+ * Copyright 2001 Ximian, Inc. (www.ximian.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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+
+#ifndef CAMEL_TCP_STREAM_H
+#define CAMEL_TCP_STREAM_H
+
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif /* __cplusplus }*/
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+#include <unistd.h>
+
+#include <camel/camel-stream.h>
+
+#define CAMEL_TCP_STREAM_TYPE (camel_tcp_stream_get_type ())
+#define CAMEL_TCP_STREAM(obj) (CAMEL_CHECK_CAST((obj), CAMEL_TCP_STREAM_TYPE, CamelTcpStream))
+#define CAMEL_TCP_STREAM_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), CAMEL_TCP_STREAM_TYPE, CamelTcpStreamClass))
+#define CAMEL_IS_TCP_STREAM(o) (CAMEL_CHECK_TYPE((o), CAMEL_TCP_STREAM_TYPE))
+
+typedef enum {
+ CAMEL_SOCKOPT_NONBLOCKING, /* nonblocking io */
+ CAMEL_SOCKOPT_LINGER, /* linger on close if data present */
+ CAMEL_SOCKOPT_REUSEADDR, /* allow local address reuse */
+ CAMEL_SOCKOPT_KEEPALIVE, /* keep connections alive */
+ CAMEL_SOCKOPT_RECVBUFFERSIZE, /* receive buffer size */
+ CAMEL_SOCKOPT_SENDBUFFERSIZE, /* send buffer size */
+
+ CAMEL_SOCKOPT_IPTIMETOLIVE, /* time to live */
+ CAMEL_SOCKOPT_IPTYPEOFSERVICE, /* type of service and precedence */
+
+ CAMEL_SOCKOPT_ADDMEMBER, /* add an IP group membership */
+ CAMEL_SOCKOPT_DROPMEMBER, /* drop an IP group membership */
+ CAMEL_SOCKOPT_MCASTINTERFACE, /* multicast interface address */
+ CAMEL_SOCKOPT_MCASTTIMETOLIVE, /* multicast timetolive */
+ CAMEL_SOCKOPT_MCASTLOOPBACK, /* multicast loopback */
+
+ CAMEL_SOCKOPT_NODELAY, /* don't delay send to coalesce packets */
+ CAMEL_SOCKOPT_MAXSEGMENT, /* maximum segment size */
+ CAMEL_SOCKOPT_BROADCAST, /* enable broadcast */
+ CAMEL_SOCKOPT_LAST
+} CamelSockOpt;
+
+typedef struct linger CamelLinger;
+
+typedef struct _CamelSockOptData {
+ CamelSockOpt option;
+ union {
+ guint ip_ttl; /* IP time to live */
+ guint mcast_ttl; /* IP multicast time to live */
+ guint tos; /* IP type of service and precedence */
+ gboolean non_blocking; /* Non-blocking (network) I/O */
+ gboolean reuse_addr; /* Allow local address reuse */
+ gboolean keep_alive; /* Keep connections alive */
+ gboolean mcast_loopback; /* IP multicast loopback */
+ gboolean no_delay; /* Don't delay send to coalesce packets */
+ gboolean broadcast; /* Enable broadcast */
+ size_t max_segment; /* Maximum segment size */
+ size_t recv_buffer_size; /* Receive buffer size */
+ size_t send_buffer_size; /* Send buffer size */
+ CamelLinger linger; /* Time to linger on close if data present */
+ } value;
+} CamelSockOptData;
+
+struct _CamelTcpStream {
+ CamelStream parent_object;
+
+};
+
+typedef struct {
+ CamelStreamClass parent_class;
+
+ /* Virtual methods */
+ int (*connect) (CamelTcpStream *stream, struct addrinfo *host);
+ int (*getsockopt) (CamelTcpStream *stream, CamelSockOptData *data);
+ int (*setsockopt) (CamelTcpStream *stream, const CamelSockOptData *data);
+
+ struct sockaddr * (*get_local_address) (CamelTcpStream *stream, socklen_t *len);
+ struct sockaddr * (*get_remote_address) (CamelTcpStream *stream, socklen_t *len);
+} CamelTcpStreamClass;
+
+/* Standard Camel function */
+CamelType camel_tcp_stream_get_type (void);
+
+/* public methods */
+int camel_tcp_stream_connect (CamelTcpStream *stream, struct addrinfo *host);
+int camel_tcp_stream_getsockopt (CamelTcpStream *stream, CamelSockOptData *data);
+int camel_tcp_stream_setsockopt (CamelTcpStream *stream, const CamelSockOptData *data);
+
+struct sockaddr *camel_tcp_stream_get_local_address (CamelTcpStream *stream, socklen_t *len);
+struct sockaddr *camel_tcp_stream_get_remote_address (CamelTcpStream *stream, socklen_t *len);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* CAMEL_TCP_STREAM_H */
diff --git a/camel/camel-uid-cache.c b/camel/camel-uid-cache.c
new file mode 100644
index 0000000000..f884c11851
--- /dev/null
+++ b/camel/camel-uid-cache.c
@@ -0,0 +1,334 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* camel-uid-cache.c: UID caching code. */
+
+/*
+ * Authors:
+ * Dan Winship <danw@ximian.com>
+ *
+ * Copyright 2000 Ximian, Inc. (www.ximian.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "camel-uid-cache.h"
+#include "camel-file-utils.h"
+
+struct _uid_state {
+ int level;
+ gboolean save;
+};
+
+
+/**
+ * camel_uid_cache_new:
+ * @filename: path to load the cache from
+ *
+ * Creates a new UID cache, initialized from @filename. If @filename
+ * doesn't already exist, the UID cache will be empty. Otherwise, if
+ * it does exist but can't be read, the function will return %NULL.
+ *
+ * Return value: a new UID cache, or %NULL
+ **/
+CamelUIDCache *
+camel_uid_cache_new (const char *filename)
+{
+ CamelUIDCache *cache;
+ struct stat st;
+ char *dirname, *buf, **uids;
+ int fd, i;
+
+ dirname = g_path_get_dirname (filename);
+ if (camel_mkdir (dirname, 0777) == -1) {
+ g_free (dirname);
+ return NULL;
+ }
+
+ g_free (dirname);
+
+ if ((fd = open (filename, O_RDONLY | O_CREAT, 0666)) == -1)
+ return NULL;
+
+ if (fstat (fd, &st) == -1) {
+ close (fd);
+ return NULL;
+ }
+
+ buf = g_malloc (st.st_size + 1);
+
+ if (st.st_size > 0 && camel_read (fd, buf, st.st_size) == -1) {
+ close (fd);
+ g_free (buf);
+ return NULL;
+ }
+
+ buf[st.st_size] = '\0';
+
+ close (fd);
+
+ cache = g_new (CamelUIDCache, 1);
+ cache->uids = g_hash_table_new (g_str_hash, g_str_equal);
+ cache->filename = g_strdup (filename);
+ cache->level = 1;
+ cache->expired = 0;
+ cache->size = 0;
+ cache->fd = -1;
+
+ uids = g_strsplit (buf, "\n", 0);
+ g_free (buf);
+ for (i = 0; uids[i]; i++) {
+ struct _uid_state *state;
+
+ state = g_new (struct _uid_state, 1);
+ state->level = cache->level;
+ state->save = TRUE;
+
+ g_hash_table_insert (cache->uids, uids[i], state);
+ }
+
+ g_free (uids);
+
+ return cache;
+}
+
+
+static void
+maybe_write_uid (gpointer key, gpointer value, gpointer data)
+{
+ CamelUIDCache *cache = data;
+ struct _uid_state *state = value;
+
+ if (cache->fd == -1)
+ return;
+
+ if (state && state->level == cache->level && state->save) {
+ if (camel_write (cache->fd, key, strlen (key)) == -1 ||
+ camel_write (cache->fd, "\n", 1) == -1) {
+ cache->fd = -1;
+ } else {
+ cache->size += strlen (key) + 1;
+ }
+ } else {
+ /* keep track of how much space the expired uids would
+ * have taken up in the cache */
+ cache->expired += strlen (key) + 1;
+ }
+}
+
+
+/**
+ * camel_uid_cache_save:
+ * @cache: a CamelUIDCache
+ *
+ * Attempts to save @cache back to disk.
+ *
+ * Return value: success or failure
+ **/
+gboolean
+camel_uid_cache_save (CamelUIDCache *cache)
+{
+ char *filename;
+ int errnosav;
+ int fd;
+
+ filename = g_strdup_printf ("%s~", cache->filename);
+ if ((fd = open (filename, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) {
+ g_free (filename);
+ return FALSE;
+ }
+
+ cache->fd = fd;
+ cache->size = 0;
+ cache->expired = 0;
+ g_hash_table_foreach (cache->uids, maybe_write_uid, cache);
+
+ if (cache->fd == -1)
+ goto exception;
+
+ if (fsync (fd) == -1)
+ goto exception;
+
+ close (fd);
+ fd = -1;
+
+ if (rename (filename, cache->filename) == -1)
+ goto exception;
+
+ g_free (filename);
+
+ return TRUE;
+
+ exception:
+
+ errnosav = errno;
+
+#ifdef ENABLE_SPASMOLYTIC
+ if (fd != -1) {
+ /**
+ * If our new cache size is larger than the old cache,
+ * even if we haven't finished writing it out
+ * successfully, we should still attempt to replace
+ * the old cache with the new cache because it will at
+ * least avoid re-downloading a few extra messages
+ * than if we just kept the old cache.
+ *
+ * Similarly, even if the new cache size is smaller
+ * than the old cache size, but we've expired enough
+ * uids to make up for the difference in size (or
+ * more), then we should replace the old cache with
+ * the new cache as well.
+ **/
+
+ if (stat (cache->filename, &st) == 0 &&
+ (cache->size > st.st_size || cache->size + cache->expired > st.st_size)) {
+ if (ftruncate (fd, (off_t) cache->size) != -1) {
+ cache->size = 0;
+ cache->expired = 0;
+ goto overwrite;
+ }
+ }
+
+ close (fd);
+ }
+#endif
+
+ unlink (filename);
+ g_free (filename);
+
+ errno = errnosav;
+
+ return FALSE;
+}
+
+
+static void
+free_uid (gpointer key, gpointer value, gpointer data)
+{
+ g_free (key);
+ g_free (value);
+}
+
+
+/**
+ * camel_uid_cache_destroy:
+ * @cache: a CamelUIDCache
+ *
+ * Destroys @cache and frees its data.
+ **/
+void
+camel_uid_cache_destroy (CamelUIDCache *cache)
+{
+ g_hash_table_foreach (cache->uids, free_uid, NULL);
+ g_hash_table_destroy (cache->uids);
+ g_free (cache->filename);
+ g_free (cache);
+}
+
+
+/**
+ * camel_uid_cache_get_new_uids:
+ * @cache: a CamelUIDCache
+ * @uids: an array of UIDs
+ *
+ * Returns an array of UIDs from @uids that are not in @cache, and
+ * removes UIDs from @cache that aren't in @uids.
+ *
+ * Return value: an array of new UIDs, which must be freed with
+ * camel_uid_cache_free_uids().
+ **/
+GPtrArray *
+camel_uid_cache_get_new_uids (CamelUIDCache *cache, GPtrArray *uids)
+{
+ GPtrArray *new_uids;
+ gpointer old_uid;
+ char *uid;
+ int i;
+
+ new_uids = g_ptr_array_new ();
+ cache->level++;
+
+ for (i = 0; i < uids->len; i++) {
+ struct _uid_state *state;
+
+ uid = uids->pdata[i];
+ if (g_hash_table_lookup_extended (cache->uids, uid, (void **)&old_uid, (void **)&state)) {
+ g_hash_table_remove (cache->uids, uid);
+ g_free (old_uid);
+ } else {
+ g_ptr_array_add (new_uids, g_strdup (uid));
+ state = g_new (struct _uid_state, 1);
+ state->save = FALSE;
+ }
+
+ state->level = cache->level;
+ g_hash_table_insert (cache->uids, g_strdup (uid), state);
+ }
+
+ return new_uids;
+}
+
+
+/**
+ * camel_uid_cache_save_uid:
+ * @cache: a CamelUIDCache
+ * @uid: a uid to save
+ *
+ * Marks a uid for saving.
+ **/
+void
+camel_uid_cache_save_uid (CamelUIDCache *cache, const char *uid)
+{
+ struct _uid_state *state;
+ gpointer old_uid;
+
+ g_return_if_fail (uid != NULL);
+
+ if (g_hash_table_lookup_extended (cache->uids, uid, (void **)&old_uid, (void **)&state)) {
+ state->save = TRUE;
+ state->level = cache->level;
+ } else {
+ state = g_new (struct _uid_state, 1);
+ state->save = TRUE;
+ state->level = cache->level;
+
+ g_hash_table_insert (cache->uids, g_strdup (uid), state);
+ }
+}
+
+
+/**
+ * camel_uid_cache_free_uids:
+ * @uids: an array returned from camel_uid_cache_get_new_uids()
+ *
+ * Frees the array of UIDs.
+ **/
+void
+camel_uid_cache_free_uids (GPtrArray *uids)
+{
+ int i;
+
+ for (i = 0; i < uids->len; i++)
+ g_free (uids->pdata[i]);
+ g_ptr_array_free (uids, TRUE);
+}
diff --git a/camel/camel-url.c b/camel/camel-url.c
new file mode 100644
index 0000000000..f5df28da95
--- /dev/null
+++ b/camel/camel-url.c
@@ -0,0 +1,592 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* camel-url.c : utility functions to parse URLs */
+
+/*
+ * Authors:
+ * Dan Winship <danw@ximian.com>
+ * Jeffrey Stedfast <fejj@ximian.com>
+ *
+ * Copyright 1999-2001 Ximian, Inc. (www.ximian.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "camel-url.h"
+#include "camel-exception.h"
+#include "camel-mime-utils.h"
+#include "camel-object.h"
+#include "camel-string-utils.h"
+
+static void copy_param (GQuark key_id, gpointer data, gpointer user_data);
+static void output_param (GQuark key_id, gpointer data, gpointer user_data);
+
+static void append_url_encoded (GString *str, const char *in, const char *extra_enc_chars);
+
+/**
+ * camel_url_new_with_base:
+ * @base: a base URL
+ * @url_string: the URL
+ *
+ * Parses @url_string relative to @base.
+ *
+ * Return value: a parsed CamelURL.
+ **/
+CamelURL *
+camel_url_new_with_base (CamelURL *base, const char *url_string)
+{
+ CamelURL *url;
+ const char *end, *hash, *colon, *semi, *at, *slash, *question;
+ const char *p;
+
+ url = g_new0 (CamelURL, 1);
+
+ /* See RFC1808 for details. IF YOU CHANGE ANYTHING IN THIS
+ * FUNCTION, RUN tests/misc/url AFTERWARDS.
+ */
+
+ /* Find fragment. RFC 1808 2.4.1 */
+ end = hash = strchr (url_string, '#');
+ if (hash) {
+ if (hash[1]) {
+ url->fragment = g_strdup (hash + 1);
+ camel_url_decode (url->fragment);
+ }
+ } else
+ end = url_string + strlen (url_string);
+
+ /* Find protocol: initial [a-z+.-]* substring until ":" */
+ p = url_string;
+ while (p < end && (isalnum ((unsigned char)*p) ||
+ *p == '.' || *p == '+' || *p == '-'))
+ p++;
+
+ if (p > url_string && *p == ':') {
+ url->protocol = g_strndup (url_string, p - url_string);
+ camel_strdown (url->protocol);
+ url_string = p + 1;
+ }
+
+ if (!*url_string && !base)
+ return url;
+
+ /* Check for authority */
+ if (strncmp (url_string, "//", 2) == 0) {
+ url_string += 2;
+
+ slash = url_string + strcspn (url_string, "/#");
+ at = strchr (url_string, '@');
+ if (at && at < slash) {
+ colon = strchr (url_string, ':');
+ if (colon && colon < at) {
+ url->passwd = g_strndup (colon + 1,
+ at - colon - 1);
+ camel_url_decode (url->passwd);
+ } else {
+ url->passwd = NULL;
+ colon = at;
+ }
+
+ semi = strchr(url_string, ';');
+ if (semi && semi < colon &&
+ !strncasecmp (semi, ";auth=", 6)) {
+ url->authmech = g_strndup (semi + 6,
+ colon - semi - 6);
+ camel_url_decode (url->authmech);
+ } else {
+ url->authmech = NULL;
+ semi = colon;
+ }
+
+ url->user = g_strndup (url_string, semi - url_string);
+ camel_url_decode (url->user);
+ url_string = at + 1;
+ } else
+ url->user = url->passwd = url->authmech = NULL;
+
+ /* Find host and port. */
+ colon = strchr (url_string, ':');
+ if (colon && colon < slash) {
+ url->host = g_strndup (url_string, colon - url_string);
+ url->port = strtoul (colon + 1, NULL, 10);
+ } else {
+ url->host = g_strndup (url_string, slash - url_string);
+ camel_url_decode (url->host);
+ url->port = 0;
+ }
+
+ url_string = slash;
+ }
+
+ /* Find query */
+ question = memchr (url_string, '?', end - url_string);
+ if (question) {
+ if (question[1]) {
+ url->query = g_strndup (question + 1,
+ end - (question + 1));
+ camel_url_decode (url->query);
+ }
+ end = question;
+ }
+
+ /* Find parameters */
+ semi = memchr (url_string, ';', end - url_string);
+ if (semi) {
+ if (semi[1]) {
+ const char *cur, *p, *eq;
+ char *name, *value;
+
+ for (cur = semi + 1; cur < end; cur = p + 1) {
+ p = memchr (cur, ';', end - cur);
+ if (!p)
+ p = end;
+ eq = memchr (cur, '=', p - cur);
+ if (eq) {
+ name = g_strndup (cur, eq - cur);
+ value = g_strndup (eq + 1, p - (eq + 1));
+ camel_url_decode (value);
+ } else {
+ name = g_strndup (cur, p - cur);
+ value = g_strdup ("");
+ }
+ camel_url_decode (name);
+ g_datalist_set_data_full (&url->params, name,
+ value, g_free);
+ g_free (name);
+ }
+ }
+ end = semi;
+ }
+
+ if (end != url_string) {
+ url->path = g_strndup (url_string, end - url_string);
+ camel_url_decode (url->path);
+ }
+
+ /* Apply base URL. Again, this is spelled out in RFC 1808. */
+ if (base && !url->protocol && url->host)
+ url->protocol = g_strdup (base->protocol);
+ else if (base && !url->protocol) {
+ if (!url->user && !url->authmech && !url->passwd &&
+ !url->host && !url->port && !url->path &&
+ !url->params && !url->query && !url->fragment)
+ url->fragment = g_strdup (base->fragment);
+
+ url->protocol = g_strdup (base->protocol);
+ url->user = g_strdup (base->user);
+ url->authmech = g_strdup (base->authmech);
+ url->passwd = g_strdup (base->passwd);
+ url->host = g_strdup (base->host);
+ url->port = base->port;
+
+ if (!url->path) {
+ url->path = g_strdup (base->path);
+ if (!url->params) {
+ g_datalist_foreach (&base->params, copy_param,
+ &url->params);
+ if (!url->query)
+ url->query = g_strdup (base->query);
+ }
+ } else if (*url->path != '/') {
+ char *newpath, *last, *p, *q;
+
+ last = strrchr (base->path, '/');
+ if (last) {
+ newpath = g_strdup_printf ("%.*s/%s",
+ (int)(last - base->path),
+ base->path,
+ url->path);
+ } else
+ newpath = g_strdup_printf ("/%s", url->path);
+
+ /* Remove "./" where "." is a complete segment. */
+ for (p = newpath + 1; *p; ) {
+ if (*(p - 1) == '/' &&
+ *p == '.' && *(p + 1) == '/')
+ memmove (p, p + 2, strlen (p + 2) + 1);
+ else
+ p++;
+ }
+ /* Remove "." at end. */
+ if (p > newpath + 2 &&
+ *(p - 1) == '.' && *(p - 2) == '/')
+ *(p - 1) = '\0';
+ /* Remove "<segment>/../" where <segment> != ".." */
+ for (p = newpath + 1; *p; ) {
+ if (!strncmp (p, "../", 3)) {
+ p += 3;
+ continue;
+ }
+ q = strchr (p + 1, '/');
+ if (!q)
+ break;
+ if (strncmp (q, "/../", 4) != 0) {
+ p = q + 1;
+ continue;
+ }
+ memmove (p, q + 4, strlen (q + 4) + 1);
+ p = newpath + 1;
+ }
+ /* Remove "<segment>/.." at end */
+ q = strrchr (newpath, '/');
+ if (q && !strcmp (q, "/..")) {
+ p = q - 1;
+ while (p > newpath && *p != '/')
+ p--;
+ if (strncmp (p, "/../", 4) != 0)
+ *(p + 1) = 0;
+ }
+ g_free (url->path);
+ url->path = newpath;
+ }
+ }
+
+ return url;
+}
+
+static void
+copy_param (GQuark key_id, gpointer data, gpointer user_data)
+{
+ GData **copy = user_data;
+
+ g_datalist_id_set_data_full (copy, key_id, g_strdup (data), g_free);
+}
+
+/**
+ * camel_url_new:
+ * @url_string: a URL
+ * @ex: a CamelException
+ *
+ * Parses an absolute URL.
+ *
+ * Return value: a CamelURL, or %NULL.
+ **/
+CamelURL *
+camel_url_new (const char *url_string, CamelException *ex)
+{
+ CamelURL *url = camel_url_new_with_base (NULL, url_string);
+
+ if (!url->protocol) {
+ camel_url_free (url);
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_URL_INVALID,
+ _("Could not parse URL `%s'"),
+ url_string);
+ return NULL;
+ }
+ return url;
+}
+
+/**
+ * camel_url_to_string:
+ * @url: a CamelURL
+ * @flags: additional translation options.
+ *
+ * Return value: a string representing @url, which the caller must free.
+ **/
+char *
+camel_url_to_string (CamelURL *url, guint32 flags)
+{
+ GString *str;
+ char *return_result;
+
+ /* IF YOU CHANGE ANYTHING IN THIS FUNCTION, RUN
+ * tests/misc/url AFTERWARD.
+ */
+
+ str = g_string_sized_new (20);
+
+ if (url->protocol)
+ g_string_append_printf (str, "%s:", url->protocol);
+
+ if (url->host) {
+ g_string_append (str, "//");
+ if (url->user) {
+ append_url_encoded (str, url->user, ":;@/");
+ if (url->authmech && *url->authmech) {
+ g_string_append (str, ";auth=");
+ append_url_encoded (str, url->authmech, ":@/");
+ }
+ if (url->passwd && !(flags & CAMEL_URL_HIDE_PASSWORD)) {
+ g_string_append_c (str, ':');
+ append_url_encoded (str, url->passwd, "@/");
+ }
+ g_string_append_c (str, '@');
+ }
+ append_url_encoded (str, url->host, ":/");
+ if (url->port)
+ g_string_append_printf (str, ":%d", url->port);
+ if (!url->path && (url->params || url->query || url->fragment))
+ g_string_append_c (str, '/');
+ }
+
+ if (url->path)
+ append_url_encoded (str, url->path, ";?");
+ if (url->params && !(flags & CAMEL_URL_HIDE_PARAMS))
+ g_datalist_foreach (&url->params, output_param, str);
+ if (url->query) {
+ g_string_append_c (str, '?');
+ append_url_encoded (str, url->query, NULL);
+ }
+ if (url->fragment) {
+ g_string_append_c (str, '#');
+ append_url_encoded (str, url->fragment, NULL);
+ }
+
+ return_result = str->str;
+ g_string_free (str, FALSE);
+
+ return return_result;
+}
+
+static void
+output_param (GQuark key_id, gpointer data, gpointer user_data)
+{
+ GString *str = user_data;
+
+ g_string_append_c (str, ';');
+ append_url_encoded (str, g_quark_to_string (key_id), "?=");
+ if (*(char *)data) {
+ g_string_append_c (str, '=');
+ append_url_encoded (str, data, "?");
+ }
+}
+
+/**
+ * camel_url_free:
+ * @url: a CamelURL
+ *
+ * Frees @url
+ **/
+void
+camel_url_free (CamelURL *url)
+{
+ if (url) {
+ if (url->passwd)
+ memset(url->passwd, 0, strlen(url->passwd));
+ if (url->user)
+ memset(url->user, 0, strlen(url->user));
+ if (url->host)
+ memset(url->host, 0, strlen(url->host));
+ g_free (url->protocol);
+ g_free (url->user);
+ g_free (url->authmech);
+ g_free (url->passwd);
+ g_free (url->host);
+ g_free (url->path);
+ g_datalist_clear (&url->params);
+ g_free (url->query);
+ g_free (url->fragment);
+
+ g_free (url);
+ }
+}
+
+
+#define DEFINE_CAMEL_URL_SET(part) \
+void \
+camel_url_set_##part (CamelURL *url, const char *part) \
+{ \
+ g_free (url->part); \
+ url->part = g_strdup (part); \
+}
+
+DEFINE_CAMEL_URL_SET (protocol)
+DEFINE_CAMEL_URL_SET (user)
+DEFINE_CAMEL_URL_SET (authmech)
+DEFINE_CAMEL_URL_SET (passwd)
+DEFINE_CAMEL_URL_SET (host)
+DEFINE_CAMEL_URL_SET (path)
+DEFINE_CAMEL_URL_SET (query)
+DEFINE_CAMEL_URL_SET (fragment)
+
+void
+camel_url_set_port (CamelURL *url, int port)
+{
+ url->port = port;
+}
+
+void
+camel_url_set_param (CamelURL *url, const char *name, const char *value)
+{
+ g_datalist_set_data_full (&url->params, name, value ? g_strdup (value) : NULL, g_free);
+}
+
+const char *
+camel_url_get_param (CamelURL *url, const char *name)
+{
+ return g_datalist_get_data (&url->params, name);
+}
+
+/* From RFC 2396 2.4.3, the characters that should always be encoded */
+static const char url_encoded_char[] = {
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x00 - 0x0f */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x10 - 0x1f */
+ 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ' ' - '/' */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, /* '0' - '?' */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* '@' - 'O' */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, /* 'P' - '_' */
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* '`' - 'o' */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* 'p' - 0x7f */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
+};
+
+static void
+append_url_encoded (GString *str, const char *in, const char *extra_enc_chars)
+{
+ const unsigned char *s = (const unsigned char *)in;
+
+ while (*s) {
+ if (url_encoded_char[*s] ||
+ (extra_enc_chars && strchr (extra_enc_chars, *s)))
+ g_string_append_printf (str, "%%%02x", (int)*s++);
+ else
+ g_string_append_c (str, *s++);
+ }
+}
+
+/**
+ * camel_url_encode:
+ * @part: a URL part
+ * @escape_extra: additional characters beyond " \"%#<>{}|\^[]`"
+ * to escape (or %NULL)
+ *
+ * This %-encodes the given URL part and returns the escaped version
+ * in allocated memory, which the caller must free when it is done.
+ **/
+char *
+camel_url_encode (const char *part, const char *escape_extra)
+{
+ GString *str;
+ char *encoded;
+
+ str = g_string_new (NULL);
+ append_url_encoded (str, part, escape_extra);
+ encoded = str->str;
+ g_string_free (str, FALSE);
+
+ return encoded;
+}
+
+/**
+ * camel_url_decode:
+ * @part: a URL part
+ *
+ * %-decodes the passed-in URL *in place*. The decoded version is
+ * never longer than the encoded version, so there does not need to
+ * be any additional space at the end of the string.
+ */
+void
+camel_url_decode (char *part)
+{
+ unsigned char *s, *d;
+
+#define XDIGIT(c) ((c) <= '9' ? (c) - '0' : ((c) & 0x4F) - 'A' + 10)
+
+ s = d = (unsigned char *)part;
+ do {
+ if (*s == '%' && isxdigit(s[1]) && isxdigit(s[2])) {
+ *d++ = (XDIGIT (s[1]) << 4) + XDIGIT (s[2]);
+ s += 2;
+ } else
+ *d++ = *s;
+ } while (*s++);
+}
+
+
+guint
+camel_url_hash (const void *v)
+{
+ const CamelURL *u = v;
+ guint hash = 0;
+
+#define ADD_HASH(s) if (s) hash ^= g_str_hash (s);
+
+ ADD_HASH (u->protocol);
+ ADD_HASH (u->user);
+ ADD_HASH (u->authmech);
+ ADD_HASH (u->host);
+ ADD_HASH (u->path);
+ ADD_HASH (u->query);
+ hash ^= u->port;
+
+ return hash;
+}
+
+static int
+check_equal (char *s1, char *s2)
+{
+ if (s1 == NULL) {
+ if (s2 == NULL)
+ return TRUE;
+ else
+ return FALSE;
+ }
+
+ if (s2 == NULL)
+ return FALSE;
+
+ return strcmp (s1, s2) == 0;
+}
+
+int
+camel_url_equal(const void *v, const void *v2)
+{
+ const CamelURL *u1 = v, *u2 = v2;
+
+ return check_equal(u1->protocol, u2->protocol)
+ && check_equal(u1->user, u2->user)
+ && check_equal(u1->authmech, u2->authmech)
+ && check_equal(u1->host, u2->host)
+ && check_equal(u1->path, u2->path)
+ && check_equal(u1->query, u2->query)
+ && u1->port == u2->port;
+}
+
+CamelURL *
+camel_url_copy(const CamelURL *in)
+{
+ CamelURL *out;
+
+ out = g_malloc(sizeof(*out));
+ out->protocol = g_strdup(in->protocol);
+ out->user = g_strdup(in->user);
+ out->authmech = g_strdup(in->authmech);
+ out->passwd = g_strdup(in->passwd);
+ out->host = g_strdup(in->host);
+ out->port = in->port;
+ out->path = g_strdup(in->path);
+ out->params = NULL;
+ if (in->params)
+ g_datalist_foreach(&((CamelURL *)in)->params, copy_param, &out->params);
+ out->query = g_strdup(in->query);
+ out->fragment = g_strdup(in->fragment);
+
+ return out;
+}
diff --git a/camel/camel-vee-folder.c b/camel/camel-vee-folder.c
new file mode 100644
index 0000000000..75beefa288
--- /dev/null
+++ b/camel/camel-vee-folder.c
@@ -0,0 +1,1789 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2000-2003 Ximian Inc.
+ *
+ * Authors: Michael Zucchi <notzed@ximian.com>
+ * Jeffrey Stedfast <fejj@ximian.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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <pthread.h>
+
+#include "camel-exception.h"
+#include "camel-vee-folder.h"
+#include "camel-store.h"
+#include "camel-folder-summary.h"
+#include "camel-mime-message.h"
+#include "camel-folder-search.h"
+
+#include "camel-session.h"
+#include "camel-vee-store.h" /* for open flags */
+#include "camel-private.h"
+#include "camel-debug.h"
+
+#include "e-util/md5-utils.h"
+
+#if defined (DOEPOOLV) || defined (DOESTRV)
+#include "e-util/e-memory.h"
+#endif
+
+#define d(x)
+#define dd(x) (camel_debug("vfolder")?(x):0)
+
+#define _PRIVATE(o) (((CamelVeeFolder *)(o))->priv)
+
+static void vee_refresh_info(CamelFolder *folder, CamelException *ex);
+
+static void vee_sync (CamelFolder *folder, gboolean expunge, CamelException *ex);
+static void vee_expunge (CamelFolder *folder, CamelException *ex);
+
+static void vee_freeze(CamelFolder *folder);
+static void vee_thaw(CamelFolder *folder);
+
+static CamelMimeMessage *vee_get_message (CamelFolder *folder, const gchar *uid, CamelException *ex);
+static void vee_append_message(CamelFolder *folder, CamelMimeMessage *message, const CamelMessageInfo *info, char **appended_uid, CamelException *ex);
+static void vee_transfer_messages_to(CamelFolder *source, GPtrArray *uids, CamelFolder *dest, GPtrArray **transferred_uids, gboolean delete_originals, CamelException *ex);
+
+static GPtrArray *vee_search_by_expression(CamelFolder *folder, const char *expression, CamelException *ex);
+static GPtrArray *vee_search_by_uids(CamelFolder *folder, const char *expression, GPtrArray *uids, CamelException *ex);
+
+static gboolean vee_set_message_flags (CamelFolder *folder, const char *uid, guint32 flags, guint32 set);
+static void vee_set_message_user_flag (CamelFolder *folder, const char *uid, const char *name, gboolean value);
+static void vee_set_message_user_tag(CamelFolder *folder, const char *uid, const char *name, const char *value);
+static void vee_rename(CamelFolder *folder, const char *new);
+
+static void camel_vee_folder_class_init (CamelVeeFolderClass *klass);
+static void camel_vee_folder_init (CamelVeeFolder *obj);
+static void camel_vee_folder_finalise (CamelObject *obj);
+
+static int vee_folder_build_folder(CamelVeeFolder *vf, CamelFolder *source, CamelException *ex);
+static void vee_folder_remove_folder(CamelVeeFolder *vf, CamelFolder *source, int killun);
+
+static void folder_changed(CamelFolder *sub, CamelFolderChangeInfo *changes, CamelVeeFolder *vf);
+static void subfolder_deleted(CamelFolder *f, void *event_data, CamelVeeFolder *vf);
+static void subfolder_renamed(CamelFolder *f, void *event_data, CamelVeeFolder *vf);
+
+static void folder_changed_remove_uid(CamelFolder *sub, const char *uid, const char hash[8], int keep, CamelVeeFolder *vf);
+
+static CamelFolderClass *camel_vee_folder_parent;
+
+CamelType
+camel_vee_folder_get_type (void)
+{
+ static CamelType type = CAMEL_INVALID_TYPE;
+
+ if (type == CAMEL_INVALID_TYPE) {
+ type = camel_type_register (camel_folder_get_type (), "CamelVeeFolder",
+ sizeof (CamelVeeFolder),
+ sizeof (CamelVeeFolderClass),
+ (CamelObjectClassInitFunc) camel_vee_folder_class_init,
+ NULL,
+ (CamelObjectInitFunc) camel_vee_folder_init,
+ (CamelObjectFinalizeFunc) camel_vee_folder_finalise);
+ }
+
+ return type;
+}
+
+static void
+camel_vee_folder_class_init (CamelVeeFolderClass *klass)
+{
+ CamelFolderClass *folder_class = (CamelFolderClass *) klass;
+
+ camel_vee_folder_parent = CAMEL_FOLDER_CLASS(camel_type_get_global_classfuncs (camel_folder_get_type ()));
+
+ folder_class->refresh_info = vee_refresh_info;
+ folder_class->sync = vee_sync;
+ folder_class->expunge = vee_expunge;
+
+ folder_class->get_message = vee_get_message;
+ folder_class->append_message = vee_append_message;
+ folder_class->transfer_messages_to = vee_transfer_messages_to;
+
+ folder_class->search_by_expression = vee_search_by_expression;
+ folder_class->search_by_uids = vee_search_by_uids;
+
+ folder_class->set_message_flags = vee_set_message_flags;
+ folder_class->set_message_user_flag = vee_set_message_user_flag;
+ folder_class->set_message_user_tag = vee_set_message_user_tag;
+
+ folder_class->rename = vee_rename;
+
+ folder_class->freeze = vee_freeze;
+ folder_class->thaw = vee_thaw;
+}
+
+static void
+camel_vee_folder_init (CamelVeeFolder *obj)
+{
+ struct _CamelVeeFolderPrivate *p;
+ CamelFolder *folder = (CamelFolder *)obj;
+
+ p = _PRIVATE(obj) = g_malloc0(sizeof(*p));
+
+ folder->folder_flags |= (CAMEL_FOLDER_HAS_SUMMARY_CAPABILITY |
+ CAMEL_FOLDER_HAS_SEARCH_CAPABILITY);
+
+ /* FIXME: what to do about user flags if the subfolder doesn't support them? */
+ folder->permanent_flags = CAMEL_MESSAGE_ANSWERED |
+ CAMEL_MESSAGE_DELETED |
+ CAMEL_MESSAGE_DRAFT |
+ CAMEL_MESSAGE_FLAGGED |
+ CAMEL_MESSAGE_SEEN;
+
+ obj->changes = camel_folder_change_info_new();
+ obj->search = camel_folder_search_new();
+
+ p->summary_lock = g_mutex_new();
+ p->subfolder_lock = g_mutex_new();
+ p->changed_lock = g_mutex_new();
+}
+
+static void
+camel_vee_folder_finalise (CamelObject *obj)
+{
+ CamelVeeFolder *vf = (CamelVeeFolder *)obj;
+ struct _CamelVeeFolderPrivate *p = _PRIVATE(vf);
+ GList *node;
+ CamelVeeFolder *folder_unmatched = vf->parent_vee_store ? vf->parent_vee_store->folder_unmatched : NULL;
+
+ /* FIXME: check leaks */
+ node = p->folders;
+ while (node) {
+ CamelFolder *f = node->data;
+
+ if (vf != folder_unmatched) {
+ camel_object_unhook_event((CamelObject *)f, "folder_changed", (CamelObjectEventHookFunc) folder_changed, vf);
+ camel_object_unhook_event((CamelObject *)f, "deleted", (CamelObjectEventHookFunc) subfolder_deleted, vf);
+ camel_object_unhook_event((CamelObject *)f, "renamed", (CamelObjectEventHookFunc) subfolder_renamed, vf);
+ /* this updates the vfolder */
+ if ((vf->flags & CAMEL_STORE_FOLDER_PRIVATE) == 0)
+ vee_folder_remove_folder(vf, f, FALSE);
+ }
+ camel_object_unref((CamelObject *)f);
+
+ node = g_list_next(node);
+ }
+
+ g_free(vf->expression);
+ g_free(vf->vname);
+
+ g_list_free(p->folders);
+ g_list_free(p->folders_changed);
+
+ camel_folder_change_info_free(vf->changes);
+ camel_object_unref((CamelObject *)vf->search);
+
+ g_mutex_free(p->summary_lock);
+ g_mutex_free(p->subfolder_lock);
+ g_mutex_free(p->changed_lock);
+
+ g_free(p);
+}
+
+void
+camel_vee_folder_construct (CamelVeeFolder *vf, CamelStore *parent_store, const char *full, const char *name, guint32 flags)
+{
+ CamelFolder *folder = (CamelFolder *)vf;
+
+ vf->flags = flags;
+ vf->vname = g_strdup(full);
+ camel_folder_construct(folder, parent_store, full, name);
+
+ /* should CamelVeeMessageInfo be subclassable ..? */
+ folder->summary = camel_folder_summary_new();
+ folder->summary->message_info_size = sizeof(CamelVeeMessageInfo);
+
+ if (CAMEL_IS_VEE_STORE(parent_store))
+ vf->parent_vee_store = (CamelVeeStore *)parent_store;
+}
+
+/**
+ * camel_vee_folder_new:
+ * @parent_store: the parent CamelVeeStore
+ * @full: the full path to the vfolder.
+ * @ex: a CamelException
+ *
+ * Create a new CamelVeeFolder object.
+ *
+ * Return value: A new CamelVeeFolder widget.
+ **/
+CamelFolder *
+camel_vee_folder_new(CamelStore *parent_store, const char *full, guint32 flags)
+{
+ CamelVeeFolder *vf;
+ char *tmp;
+
+ if (CAMEL_IS_VEE_STORE(parent_store) && strcmp(full, CAMEL_UNMATCHED_NAME) == 0) {
+ vf = ((CamelVeeStore *)parent_store)->folder_unmatched;
+ camel_object_ref(vf);
+ } else {
+ const char *name = strrchr(full, '/');
+
+ if (name == NULL)
+ name = full;
+ else
+ name++;
+ vf = (CamelVeeFolder *)camel_object_new(camel_vee_folder_get_type());
+ camel_vee_folder_construct(vf, parent_store, full, name, flags);
+ }
+
+ d(printf("returning folder %s %p, count = %d\n", name, vf, camel_folder_get_message_count((CamelFolder *)vf)));
+
+ tmp = g_strdup_printf("%s/%s.cmeta", ((CamelService *)parent_store)->url->path, full);
+ camel_object_set(vf, NULL, CAMEL_OBJECT_STATE_FILE, tmp, NULL);
+ g_free(tmp);
+ if (camel_object_state_read(vf) == -1) {
+ /* setup defaults: we have none currently */
+ }
+
+ return (CamelFolder *)vf;
+}
+
+void
+camel_vee_folder_set_expression(CamelVeeFolder *vf, const char *query)
+{
+ struct _CamelVeeFolderPrivate *p = _PRIVATE(vf);
+ GList *node;
+
+ CAMEL_VEE_FOLDER_LOCK(vf, subfolder_lock);
+
+ /* no change, do nothing */
+ if ((vf->expression && query && strcmp(vf->expression, query) == 0)
+ || (vf->expression == NULL && query == NULL)) {
+ CAMEL_VEE_FOLDER_UNLOCK(vf, subfolder_lock);
+ return;
+ }
+
+ g_free(vf->expression);
+ if (query)
+ vf->expression = g_strdup(query);
+
+ node = p->folders;
+ while (node) {
+ CamelFolder *f = node->data;
+
+ if (vee_folder_build_folder(vf, f, NULL) == -1)
+ break;
+
+ node = node->next;
+ }
+
+ CAMEL_VEE_FOLDER_LOCK(vf, changed_lock);
+ g_list_free(p->folders_changed);
+ p->folders_changed = NULL;
+ CAMEL_VEE_FOLDER_UNLOCK(vf, changed_lock);
+
+ CAMEL_VEE_FOLDER_UNLOCK(vf, subfolder_lock);
+}
+
+/**
+ * camel_vee_folder_add_folder:
+ * @vf: Virtual Folder object
+ * @sub: source CamelFolder to add to @vf
+ *
+ * Adds @sub as a source folder to @vf.
+ **/
+void
+camel_vee_folder_add_folder(CamelVeeFolder *vf, CamelFolder *sub)
+{
+ struct _CamelVeeFolderPrivate *p = _PRIVATE(vf);
+ int i;
+ CamelVeeFolder *folder_unmatched = vf->parent_vee_store ? vf->parent_vee_store->folder_unmatched : NULL;
+
+ if (vf == (CamelVeeFolder *)sub) {
+ g_warning("Adding a virtual folder to itself as source, ignored");
+ return;
+ }
+
+ CAMEL_VEE_FOLDER_LOCK(vf, subfolder_lock);
+
+ /* for normal vfolders we want only unique ones, for unmatched we want them all recorded */
+ if (g_list_find(p->folders, sub) == NULL) {
+ camel_object_ref((CamelObject *)sub);
+ p->folders = g_list_append(p->folders, sub);
+
+ CAMEL_FOLDER_LOCK(vf, change_lock);
+
+ /* update the freeze state of 'sub' to match our freeze state */
+ for (i = 0; i < ((CamelFolder *)vf)->priv->frozen; i++)
+ camel_folder_freeze(sub);
+
+ CAMEL_FOLDER_UNLOCK(vf, change_lock);
+ }
+ if ((vf->flags & CAMEL_STORE_FOLDER_PRIVATE) == 0 && !CAMEL_IS_VEE_FOLDER(sub) && folder_unmatched != NULL) {
+ struct _CamelVeeFolderPrivate *up = _PRIVATE(folder_unmatched);
+ camel_object_ref((CamelObject *)sub);
+ up->folders = g_list_append(up->folders, sub);
+
+ CAMEL_FOLDER_LOCK(folder_unmatched, change_lock);
+
+ /* update the freeze state of 'sub' to match Unmatched's freeze state */
+ for (i = 0; i < ((CamelFolder *)folder_unmatched)->priv->frozen; i++)
+ camel_folder_freeze(sub);
+
+ CAMEL_FOLDER_UNLOCK(folder_unmatched, change_lock);
+ }
+
+ CAMEL_VEE_FOLDER_UNLOCK(vf, subfolder_lock);
+
+ d(printf("camel_vee_folder_add_folde(%p, %p)\n", vf, sub));
+
+ camel_object_hook_event((CamelObject *)sub, "folder_changed", (CamelObjectEventHookFunc)folder_changed, vf);
+ camel_object_hook_event((CamelObject *)sub, "deleted", (CamelObjectEventHookFunc)subfolder_deleted, vf);
+ camel_object_hook_event((CamelObject *)sub, "renamed", (CamelObjectEventHookFunc)subfolder_renamed, vf);
+
+ vee_folder_build_folder(vf, sub, NULL);
+}
+
+/**
+ * camel_vee_folder_remove_folder:
+ * @vf: Virtual Folder object
+ * @sub: source CamelFolder to remove from @vf
+ *
+ * Removed the source folder, @sub, from the virtual folder, @vf.
+ **/
+void
+camel_vee_folder_remove_folder(CamelVeeFolder *vf, CamelFolder *sub)
+{
+ struct _CamelVeeFolderPrivate *p = _PRIVATE(vf);
+ int killun = FALSE;
+ int i;
+ CamelVeeFolder *folder_unmatched = vf->parent_vee_store ? vf->parent_vee_store->folder_unmatched : NULL;
+
+ CAMEL_VEE_FOLDER_LOCK(vf, subfolder_lock);
+
+ CAMEL_VEE_FOLDER_LOCK(vf, changed_lock);
+ p->folders_changed = g_list_remove(p->folders_changed, sub);
+ CAMEL_VEE_FOLDER_UNLOCK(vf, changed_lock);
+
+ if (g_list_find(p->folders, sub) == NULL) {
+ CAMEL_VEE_FOLDER_UNLOCK(vf, subfolder_lock);
+ return;
+ }
+
+ camel_object_unhook_event((CamelObject *)sub, "folder_changed", (CamelObjectEventHookFunc) folder_changed, vf);
+ camel_object_unhook_event((CamelObject *)sub, "deleted", (CamelObjectEventHookFunc) subfolder_deleted, vf);
+ camel_object_unhook_event((CamelObject *)sub, "renamed", (CamelObjectEventHookFunc) subfolder_renamed, vf);
+
+ p->folders = g_list_remove(p->folders, sub);
+
+ /* undo the freeze state that we have imposed on this source folder */
+ CAMEL_FOLDER_LOCK(vf, change_lock);
+ for (i = 0; i < ((CamelFolder *)vf)->priv->frozen; i++)
+ camel_folder_thaw(sub);
+ CAMEL_FOLDER_UNLOCK(vf, change_lock);
+
+ CAMEL_VEE_FOLDER_UNLOCK(vf, subfolder_lock);
+
+ if (folder_unmatched != NULL) {
+ struct _CamelVeeFolderPrivate *up = _PRIVATE(folder_unmatched);
+
+ CAMEL_VEE_FOLDER_LOCK(folder_unmatched, subfolder_lock);
+ /* if folder deleted, then blow it away from unmatched always, and remove all refs to it */
+ if (sub->folder_flags & CAMEL_FOLDER_HAS_BEEN_DELETED) {
+ while (g_list_find(up->folders, sub)) {
+ killun = TRUE;
+ up->folders = g_list_remove(up->folders, sub);
+ camel_object_unref((CamelObject *)sub);
+
+ /* undo the freeze state that Unmatched has imposed on this source folder */
+ CAMEL_FOLDER_LOCK(folder_unmatched, change_lock);
+ for (i = 0; i < ((CamelFolder *)folder_unmatched)->priv->frozen; i++)
+ camel_folder_thaw(sub);
+ CAMEL_FOLDER_UNLOCK(folder_unmatched, change_lock);
+ }
+ } else if ((vf->flags & CAMEL_STORE_FOLDER_PRIVATE) == 0) {
+ if (g_list_find(up->folders, sub) != NULL) {
+ up->folders = g_list_remove(up->folders, sub);
+ camel_object_unref((CamelObject *)sub);
+
+ /* undo the freeze state that Unmatched has imposed on this source folder */
+ CAMEL_FOLDER_LOCK(folder_unmatched, change_lock);
+ for (i = 0; i < ((CamelFolder *)folder_unmatched)->priv->frozen; i++)
+ camel_folder_thaw(sub);
+ CAMEL_FOLDER_UNLOCK(folder_unmatched, change_lock);
+ }
+ if (g_list_find(up->folders, sub) == NULL) {
+ killun = TRUE;
+ }
+ }
+ CAMEL_VEE_FOLDER_UNLOCK(folder_unmatched, subfolder_lock);
+ }
+
+ vee_folder_remove_folder(vf, sub, killun);
+
+ camel_object_unref((CamelObject *)sub);
+}
+
+static void
+remove_folders(CamelFolder *folder, CamelFolder *foldercopy, CamelVeeFolder *vf)
+{
+ camel_vee_folder_remove_folder(vf, folder);
+ camel_object_unref((CamelObject *)folder);
+}
+
+/**
+ * camel_vee_folder_set_folders:
+ * @vf:
+ * @folders:
+ *
+ * Set the whole list of folder sources on a vee folder.
+ **/
+void
+camel_vee_folder_set_folders(CamelVeeFolder *vf, GList *folders)
+{
+ struct _CamelVeeFolderPrivate *p = _PRIVATE(vf);
+ GHashTable *remove = g_hash_table_new(NULL, NULL);
+ GList *l;
+ CamelFolder *folder;
+ int changed;
+
+ /* setup a table of all folders we have currently */
+ CAMEL_VEE_FOLDER_LOCK(vf, subfolder_lock);
+ l = p->folders;
+ while (l) {
+ g_hash_table_insert(remove, l->data, l->data);
+ camel_object_ref((CamelObject *)l->data);
+ l = l->next;
+ }
+ CAMEL_VEE_FOLDER_UNLOCK(vf, subfolder_lock);
+
+ /* if we already have the folder, ignore it, otherwise add it */
+ l = folders;
+ while (l) {
+ if ((folder = g_hash_table_lookup(remove, l->data))) {
+ g_hash_table_remove(remove, folder);
+ camel_object_unref((CamelObject *)folder);
+
+ /* if this was a changed folder, re-update it while we're here */
+ CAMEL_VEE_FOLDER_LOCK(vf, changed_lock);
+ changed = g_list_find(p->folders_changed, folder) != NULL;
+ if (changed)
+ p->folders_changed = g_list_remove(p->folders_changed, folder);
+ CAMEL_VEE_FOLDER_UNLOCK(vf, changed_lock);
+ if (changed)
+ vee_folder_build_folder(vf, folder, NULL);
+ } else {
+ camel_vee_folder_add_folder(vf, l->data);
+ }
+ l = l->next;
+ }
+
+ /* then remove any we still have */
+ g_hash_table_foreach(remove, (GHFunc)remove_folders, vf);
+ g_hash_table_destroy(remove);
+}
+
+/**
+ * camel_vee_folder_hash_folder:
+ * @folder:
+ * @:
+ *
+ * Create a hash string representing the folder name, which should be
+ * unique, and remain static for a given folder.
+ **/
+void
+camel_vee_folder_hash_folder(CamelFolder *folder, char buffer[8])
+{
+ MD5Context ctx;
+ unsigned char digest[16];
+ unsigned int state = 0, save = 0;
+ char *tmp;
+ int i;
+
+ md5_init(&ctx);
+ tmp = camel_service_get_url((CamelService *)folder->parent_store);
+ md5_update(&ctx, tmp, strlen(tmp));
+ g_free(tmp);
+ md5_update(&ctx, folder->full_name, strlen(folder->full_name));
+ md5_final(&ctx, digest);
+ camel_base64_encode_close(digest, 6, FALSE, buffer, &state, &save);
+
+ for (i=0;i<8;i++) {
+ if (buffer[i] == '+')
+ buffer[i] = '.';
+ if (buffer[i] == '/')
+ buffer[i] = '_';
+ }
+}
+
+/**
+ * camel_vee_folder_get_location:
+ * @vf:
+ * @vinfo:
+ * @realuid: if not NULL, set to the uid of the real message, must be
+ * g_free'd by caller.
+ *
+ * Find the real folder (and uid)
+ *
+ * Return value:
+ **/
+CamelFolder *
+camel_vee_folder_get_location(CamelVeeFolder *vf, const CamelVeeMessageInfo *vinfo, char **realuid)
+{
+ /* locking? yes? no? although the vfolderinfo is valid when obtained
+ the folder in it might not necessarily be so ...? */
+ if (CAMEL_IS_VEE_FOLDER(vinfo->folder)) {
+ CamelFolder *folder;
+ const CamelVeeMessageInfo *vfinfo;
+
+ vfinfo = (CamelVeeMessageInfo *)camel_folder_get_message_info(vinfo->folder, camel_message_info_uid(vinfo)+8);
+ folder = camel_vee_folder_get_location((CamelVeeFolder *)vinfo->folder, vfinfo, realuid);
+ camel_folder_free_message_info(vinfo->folder, (CamelMessageInfo *)vfinfo);
+ return folder;
+ } else {
+ if (realuid)
+ *realuid = g_strdup(camel_message_info_uid(vinfo)+8);
+
+ return vinfo->folder;
+ }
+}
+
+static void vee_refresh_info(CamelFolder *folder, CamelException *ex)
+{
+ CamelVeeFolder *vf = (CamelVeeFolder *)folder;
+ struct _CamelVeeFolderPrivate *p = _PRIVATE(vf);
+ GList *node, *list;
+
+ CAMEL_VEE_FOLDER_LOCK(vf, changed_lock);
+ list = p->folders_changed;
+ p->folders_changed = NULL;
+ CAMEL_VEE_FOLDER_UNLOCK(vf, changed_lock);
+
+ node = list;
+ while (node) {
+ CamelFolder *f = node->data;
+
+ if (vee_folder_build_folder(vf, f, ex) == -1)
+ break;
+
+ node = node->next;
+ }
+
+ g_list_free(list);
+}
+
+static void
+vee_sync(CamelFolder *folder, gboolean expunge, CamelException *ex)
+{
+ CamelVeeFolder *vf = (CamelVeeFolder *)folder;
+ struct _CamelVeeFolderPrivate *p = _PRIVATE(vf);
+ GList *node;
+
+ CAMEL_VEE_FOLDER_LOCK(vf, subfolder_lock);
+
+ node = p->folders;
+ while (node) {
+ CamelFolder *f = node->data;
+
+ camel_folder_sync(f, expunge, ex);
+ if (camel_exception_is_set(ex)) {
+ char *desc;
+
+ camel_object_get(f, NULL, CAMEL_OBJECT_DESCRIPTION, &desc, NULL);
+ camel_exception_setv(ex, ex->id, _("Error storing `%s': %s"), desc, ex->desc);
+ break;
+ }
+
+ /* auto update vfolders shouldn't need a rebuild */
+ if ((vf->flags & CAMEL_STORE_VEE_FOLDER_AUTO) == 0
+ && vee_folder_build_folder(vf, f, ex) == -1)
+ break;
+
+ node = node->next;
+ }
+
+ if (node == NULL) {
+ CAMEL_VEE_FOLDER_LOCK(vf, changed_lock);
+ g_list_free(p->folders_changed);
+ p->folders_changed = NULL;
+ CAMEL_VEE_FOLDER_UNLOCK(vf, changed_lock);
+ }
+
+ CAMEL_VEE_FOLDER_UNLOCK(vf, subfolder_lock);
+
+ camel_object_state_write(vf);
+}
+
+static void
+vee_expunge (CamelFolder *folder, CamelException *ex)
+{
+ ((CamelFolderClass *)((CamelObject *)folder)->klass)->sync(folder, TRUE, ex);
+}
+
+static CamelMimeMessage *
+vee_get_message(CamelFolder *folder, const char *uid, CamelException *ex)
+{
+ CamelVeeMessageInfo *mi;
+ CamelMimeMessage *msg = NULL;
+
+ mi = (CamelVeeMessageInfo *)camel_folder_summary_uid(folder->summary, uid);
+ if (mi) {
+ msg = camel_folder_get_message(mi->folder, camel_message_info_uid(mi)+8, ex);
+ camel_folder_summary_info_free(folder->summary, (CamelMessageInfo *)mi);
+ } else {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_FOLDER_INVALID_UID,
+ _("No such message %s in %s"), uid,
+ folder->name);
+ }
+
+ return msg;
+}
+
+static GPtrArray *
+vee_search_by_expression(CamelFolder *folder, const char *expression, CamelException *ex)
+{
+ GList *node;
+ GPtrArray *matches, *result = g_ptr_array_new ();
+ char *expr;
+ CamelVeeFolder *vf = (CamelVeeFolder *)folder;
+ struct _CamelVeeFolderPrivate *p = _PRIVATE(vf);
+ GHashTable *searched = g_hash_table_new(NULL, NULL);
+ CamelVeeFolder *folder_unmatched = vf->parent_vee_store ? vf->parent_vee_store->folder_unmatched : NULL;
+
+ CAMEL_VEE_FOLDER_LOCK(vf, subfolder_lock);
+
+ if (vf != folder_unmatched)
+ expr = g_strdup_printf ("(and %s %s)", vf->expression, expression);
+ else
+ expr = g_strdup (expression);
+
+ node = p->folders;
+ while (node) {
+ CamelFolder *f = node->data;
+ int i;
+ char hash[8];
+
+ /* make sure we only search each folder once - for unmatched folder to work right */
+ if (g_hash_table_lookup(searched, f) == NULL) {
+ camel_vee_folder_hash_folder(f, hash);
+ /* FIXME: shouldn't ignore search exception */
+ matches = camel_folder_search_by_expression(f, expression, NULL);
+ if (matches) {
+ for (i = 0; i < matches->len; i++) {
+ char *uid = matches->pdata[i], *vuid;
+
+ vuid = g_malloc(strlen(uid)+9);
+ memcpy(vuid, hash, 8);
+ strcpy(vuid+8, uid);
+ g_ptr_array_add(result, vuid);
+ }
+ camel_folder_search_free(f, matches);
+ }
+ g_hash_table_insert(searched, f, f);
+ }
+ node = g_list_next(node);
+ }
+
+ g_free(expr);
+ CAMEL_VEE_FOLDER_UNLOCK(vf, subfolder_lock);
+
+ g_hash_table_destroy(searched);
+
+ return result;
+}
+
+static GPtrArray *
+vee_search_by_uids(CamelFolder *folder, const char *expression, GPtrArray *uids, CamelException *ex)
+{
+ GList *node;
+ GPtrArray *matches, *result = g_ptr_array_new ();
+ GPtrArray *folder_uids = g_ptr_array_new();
+ char *expr;
+ CamelVeeFolder *vf = (CamelVeeFolder *)folder;
+ struct _CamelVeeFolderPrivate *p = _PRIVATE(vf);
+ GHashTable *searched = g_hash_table_new(NULL, NULL);
+
+ CAMEL_VEE_FOLDER_LOCK(vf, subfolder_lock);
+
+ expr = g_strdup_printf("(and %s %s)", vf->expression, expression);
+ node = p->folders;
+ while (node) {
+ CamelFolder *f = node->data;
+ int i;
+ char hash[8];
+
+ /* make sure we only search each folder once - for unmatched folder to work right */
+ if (g_hash_table_lookup(searched, f) == NULL) {
+ camel_vee_folder_hash_folder(f, hash);
+
+ /* map the vfolder uid's to the source folder uid's first */
+ g_ptr_array_set_size(folder_uids, 0);
+ for (i=0;i<uids->len;i++) {
+ char *uid = uids->pdata[i];
+
+ if (strlen(uid) >= 8 && strncmp(uid, hash, 8) == 0)
+ g_ptr_array_add(folder_uids, uid+8);
+ }
+ if (folder_uids->len > 0) {
+ matches = camel_folder_search_by_uids(f, expression, folder_uids, ex);
+ if (matches) {
+ for (i = 0; i < matches->len; i++) {
+ char *uid = matches->pdata[i], *vuid;
+
+ vuid = g_malloc(strlen(uid)+9);
+ memcpy(vuid, hash, 8);
+ strcpy(vuid+8, uid);
+ g_ptr_array_add(result, vuid);
+ }
+ camel_folder_search_free(f, matches);
+ } else {
+ g_warning("Search failed: %s", camel_exception_get_description(ex));
+ }
+ }
+ g_hash_table_insert(searched, f, f);
+ }
+ node = g_list_next(node);
+ }
+
+ g_free(expr);
+ CAMEL_VEE_FOLDER_UNLOCK(vf, subfolder_lock);
+
+ g_hash_table_destroy(searched);
+ g_ptr_array_free(folder_uids, 0);
+
+ return result;
+}
+
+static gboolean
+vee_set_message_flags(CamelFolder *folder, const char *uid, guint32 flags, guint32 set)
+{
+ CamelVeeMessageInfo *mi;
+ int res = FALSE;
+
+ mi = (CamelVeeMessageInfo *)camel_folder_summary_uid(folder->summary, uid);
+ if (mi) {
+ res = camel_folder_set_message_flags(mi->folder, camel_message_info_uid(mi) + 8, flags, set);
+ camel_folder_summary_info_free(folder->summary, (CamelMessageInfo *)mi);
+ res = res || ((CamelFolderClass *)camel_vee_folder_parent)->set_message_flags(folder, uid, flags, set);
+ }
+
+ return res;
+}
+
+static void
+vee_set_message_user_flag(CamelFolder *folder, const char *uid, const char *name, gboolean value)
+{
+ CamelVeeMessageInfo *mi;
+
+ mi = (CamelVeeMessageInfo *)camel_folder_summary_uid(folder->summary, uid);
+ if (mi) {
+ camel_folder_set_message_user_flag(mi->folder, camel_message_info_uid(mi) + 8, name, value);
+ camel_folder_summary_info_free(folder->summary, (CamelMessageInfo *)mi);
+ ((CamelFolderClass *)camel_vee_folder_parent)->set_message_user_flag(folder, uid, name, value);
+ }
+}
+
+static void
+vee_set_message_user_tag(CamelFolder *folder, const char *uid, const char *name, const char *value)
+{
+ CamelVeeMessageInfo *mi;
+
+ mi = (CamelVeeMessageInfo *)camel_folder_summary_uid(folder->summary, uid);
+ if (mi) {
+ camel_folder_set_message_user_tag(mi->folder, camel_message_info_uid(mi) + 8, name, value);
+ camel_folder_summary_info_free(folder->summary, (CamelMessageInfo *)mi);
+ ((CamelFolderClass *)camel_vee_folder_parent)->set_message_user_tag(folder, uid, name, value);
+ }
+}
+
+static void
+vee_append_message(CamelFolder *folder, CamelMimeMessage *message, const CamelMessageInfo *info, char **appended_uid, CamelException *ex)
+{
+ camel_exception_set(ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot copy or move messages into a Virtual Folder"));
+}
+
+static void
+vee_transfer_messages_to (CamelFolder *folder, GPtrArray *uids, CamelFolder *dest, GPtrArray **transferred_uids, gboolean delete_originals, CamelException *ex)
+{
+ camel_exception_set(ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot copy or move messages into a Virtual Folder"));
+}
+
+static void vee_rename(CamelFolder *folder, const char *new)
+{
+ CamelVeeFolder *vf = (CamelVeeFolder *)folder;
+
+ g_free(vf->vname);
+ vf->vname = g_strdup(new);
+
+ ((CamelFolderClass *)camel_vee_folder_parent)->rename(folder, new);
+}
+
+/* ********************************************************************** *
+ utility functions */
+
+/* must be called with summary_lock held */
+static CamelVeeMessageInfo *
+vee_folder_add_info(CamelVeeFolder *vf, CamelFolder *f, CamelMessageInfo *info, const char hash[8])
+{
+ CamelVeeMessageInfo *mi;
+ char *vuid;
+ const char *uid;
+ CamelFolder *folder = (CamelFolder *)vf;
+ CamelMessageInfo *dinfo;
+
+ uid = camel_message_info_uid(info);
+ vuid = alloca(strlen(uid)+9);
+ memcpy(vuid, hash, 8);
+ strcpy(vuid+8, uid);
+ dinfo = camel_folder_summary_uid(folder->summary, vuid);
+ if (dinfo) {
+ d(printf("w:clash, we already have '%s' in summary\n", vuid));
+ camel_folder_summary_info_free(folder->summary, dinfo);
+ return NULL;
+ }
+
+ d(printf("adding vuid %s to %s\n", vuid, vf->vname));
+
+ mi = (CamelVeeMessageInfo *)camel_folder_summary_info_new(folder->summary);
+ camel_message_info_dup_to(info, (CamelMessageInfo *)mi);
+#ifdef DOEPOOLV
+ mi->info.strings = e_poolv_set(mi->info.strings, CAMEL_MESSAGE_INFO_UID, vuid, FALSE);
+#elif defined (DOESTRV)
+ mi->info.strings = e_strv_set_ref(mi->info.strings, CAMEL_MESSAGE_INFO_UID, vuid);
+ mi->info.strings = e_strv_pack(mi->info.strings);
+#else
+ g_free(mi->info.uid);
+ mi->info.uid = g_strdup(vuid);
+#endif
+ mi->folder = f;
+ camel_folder_summary_add(folder->summary, (CamelMessageInfo *)mi);
+
+ return mi;
+}
+
+/* must be called with summary_lock held */
+static CamelVeeMessageInfo *
+vee_folder_add_uid(CamelVeeFolder *vf, CamelFolder *f, const char *inuid, const char hash[8])
+{
+ CamelMessageInfo *info;
+ CamelVeeMessageInfo *mi = NULL;
+
+ info = camel_folder_get_message_info(f, inuid);
+ if (info) {
+ mi = vee_folder_add_info(vf, f, info, hash);
+ camel_folder_free_message_info(f, info);
+ }
+ return mi;
+}
+
+static void
+vee_folder_remove_folder(CamelVeeFolder *vf, CamelFolder *source, int killun)
+{
+ int i, count, n, still = FALSE, start, last;
+ char *oldkey;
+ CamelFolder *folder = (CamelFolder *)vf;
+ char hash[8];
+ /*struct _CamelVeeFolderPrivate *p = _PRIVATE(vf);*/
+ CamelFolderChangeInfo *vf_changes = NULL, *unmatched_changes = NULL;
+ void *oldval;
+ CamelVeeFolder *folder_unmatched = vf->parent_vee_store ? vf->parent_vee_store->folder_unmatched : NULL;
+ GHashTable *unmatched_uids = vf->parent_vee_store ? vf->parent_vee_store->unmatched_uids : NULL;
+
+ if (vf == folder_unmatched)
+ return;
+
+ CAMEL_VEE_FOLDER_LOCK(vf, summary_lock);
+
+ if (folder_unmatched != NULL) {
+ /* check if this folder is still to be part of unmatched */
+ if ((vf->flags & CAMEL_STORE_FOLDER_PRIVATE) == 0 && !killun) {
+ CAMEL_VEE_FOLDER_LOCK(folder_unmatched, subfolder_lock);
+ still = g_list_find(_PRIVATE(folder_unmatched)->folders, source) != NULL;
+ CAMEL_VEE_FOLDER_UNLOCK(folder_unmatched, subfolder_lock);
+ camel_vee_folder_hash_folder(source, hash);
+ }
+
+ CAMEL_VEE_FOLDER_LOCK(folder_unmatched, summary_lock);
+
+ /* See if we just blow all uid's from this folder away from unmatched, regardless */
+ if (killun) {
+ start = -1;
+ last = -1;
+ count = camel_folder_summary_count(((CamelFolder *)folder_unmatched)->summary);
+ for (i=0;i<count;i++) {
+ CamelVeeMessageInfo *mi = (CamelVeeMessageInfo *)camel_folder_summary_index(((CamelFolder *)folder_unmatched)->summary, i);
+
+ if (mi) {
+ if (mi->folder == source) {
+ camel_folder_change_info_remove_uid(folder_unmatched->changes, camel_message_info_uid(mi));
+ if (last == -1) {
+ last = start = i;
+ } else if (last+1 == i) {
+ last = i;
+ } else {
+ camel_folder_summary_remove_range(((CamelFolder *)folder_unmatched)->summary, start, last);
+ i -= (last-start)+1;
+ start = last = i;
+ }
+ }
+ camel_folder_summary_info_free(((CamelFolder *)folder_unmatched)->summary, (CamelMessageInfo *)mi);
+ }
+ }
+ if (last != -1)
+ camel_folder_summary_remove_range(((CamelFolder *)folder_unmatched)->summary, start, last);
+ }
+ }
+
+ start = -1;
+ last = -1;
+ count = camel_folder_summary_count(folder->summary);
+ for (i=0;i<count;i++) {
+ CamelVeeMessageInfo *mi = (CamelVeeMessageInfo *)camel_folder_summary_index(folder->summary, i);
+ if (mi) {
+ if (mi->folder == source) {
+ const char *uid = camel_message_info_uid(mi);
+
+ camel_folder_change_info_remove_uid(vf->changes, uid);
+
+ if (last == -1) {
+ last = start = i;
+ } else if (last+1 == i) {
+ last = i;
+ } else {
+ camel_folder_summary_remove_range(folder->summary, start, last);
+ i -= (last-start)+1;
+ start = last = i;
+ }
+ if ((vf->flags & CAMEL_STORE_FOLDER_PRIVATE) == 0 && folder_unmatched != NULL) {
+ if (still) {
+ if (g_hash_table_lookup_extended(unmatched_uids, uid, (void **)&oldkey, &oldval)) {
+ n = GPOINTER_TO_INT (oldval);
+ if (n == 1) {
+ g_hash_table_remove(unmatched_uids, oldkey);
+ if (vee_folder_add_uid(folder_unmatched, source, oldkey+8, hash))
+ camel_folder_change_info_add_uid(folder_unmatched->changes, oldkey);
+ g_free(oldkey);
+ } else {
+ g_hash_table_insert(unmatched_uids, oldkey, GINT_TO_POINTER(n-1));
+ }
+ }
+ } else {
+ if (g_hash_table_lookup_extended(unmatched_uids, camel_message_info_uid(mi), (void **)&oldkey, &oldval)) {
+ g_hash_table_remove(unmatched_uids, oldkey);
+ g_free(oldkey);
+ }
+ }
+ }
+ }
+ camel_folder_summary_info_free(folder->summary, (CamelMessageInfo *)mi);
+ }
+ }
+
+ if (last != -1)
+ camel_folder_summary_remove_range(folder->summary, start, last);
+
+ if (folder_unmatched) {
+ if (camel_folder_change_info_changed(folder_unmatched->changes)) {
+ unmatched_changes = folder_unmatched->changes;
+ folder_unmatched->changes = camel_folder_change_info_new();
+ }
+
+ CAMEL_VEE_FOLDER_UNLOCK(folder_unmatched, summary_lock);
+ }
+
+ if (camel_folder_change_info_changed(vf->changes)) {
+ vf_changes = vf->changes;
+ vf->changes = camel_folder_change_info_new();
+ }
+
+ CAMEL_VEE_FOLDER_UNLOCK(vf, summary_lock);
+
+ if (unmatched_changes) {
+ camel_object_trigger_event((CamelObject *)folder_unmatched, "folder_changed", unmatched_changes);
+ camel_folder_change_info_free(unmatched_changes);
+ }
+
+ if (vf_changes) {
+ camel_object_trigger_event((CamelObject *)vf, "folder_changed", vf_changes);
+ camel_folder_change_info_free(vf_changes);
+ }
+}
+
+struct _update_data {
+ CamelFolder *source;
+ CamelVeeFolder *vf;
+ char hash[8];
+ CamelVeeFolder *folder_unmatched;
+ GHashTable *unmatched_uids;
+};
+
+static void
+unmatched_check_uid(char *uidin, void *value, struct _update_data *u)
+{
+ char *uid;
+ int n;
+
+ uid = alloca(strlen(uidin)+9);
+ memcpy(uid, u->hash, 8);
+ strcpy(uid+8, uidin);
+ n = GPOINTER_TO_INT(g_hash_table_lookup(u->unmatched_uids, uid));
+ if (n == 0) {
+ if (vee_folder_add_uid(u->folder_unmatched, u->source, uidin, u->hash))
+ camel_folder_change_info_add_uid(u->folder_unmatched->changes, uid);
+ } else {
+ CamelVeeMessageInfo *mi = (CamelVeeMessageInfo *)camel_folder_summary_uid(((CamelFolder *)u->folder_unmatched)->summary, uid);
+ if (mi) {
+ camel_folder_summary_remove(((CamelFolder *)u->folder_unmatched)->summary, (CamelMessageInfo *)mi);
+ camel_folder_change_info_remove_uid(u->folder_unmatched->changes, uid);
+ camel_folder_summary_info_free(((CamelFolder *)u->folder_unmatched)->summary, (CamelMessageInfo *)mi);
+ }
+ }
+}
+
+static void
+folder_added_uid(char *uidin, void *value, struct _update_data *u)
+{
+ CamelVeeMessageInfo *mi;
+ char *oldkey;
+ void *oldval;
+ int n;
+
+ if ( (mi = vee_folder_add_uid(u->vf, u->source, uidin, u->hash)) ) {
+ camel_folder_change_info_add_uid(u->vf->changes, camel_message_info_uid(mi));
+
+ if (!CAMEL_IS_VEE_FOLDER(u->source) && u->unmatched_uids != NULL) {
+ if (g_hash_table_lookup_extended(u->unmatched_uids, camel_message_info_uid(mi), (void **)&oldkey, &oldval)) {
+ n = GPOINTER_TO_INT (oldval);
+ g_hash_table_insert(u->unmatched_uids, oldkey, GINT_TO_POINTER(n+1));
+ } else {
+ g_hash_table_insert(u->unmatched_uids, g_strdup(camel_message_info_uid(mi)), GINT_TO_POINTER(1));
+ }
+ }
+ }
+}
+
+/* build query contents for a single folder */
+static int
+vee_folder_build_folder(CamelVeeFolder *vf, CamelFolder *source, CamelException *ex)
+{
+ GPtrArray *match, *all;
+ GHashTable *allhash, *matchhash;
+ CamelFolder *f = source;
+ CamelFolder *folder = (CamelFolder *)vf;
+ int i, n, count, start, last;
+ struct _update_data u;
+ CamelFolderChangeInfo *vf_changes = NULL, *unmatched_changes = NULL;
+ CamelVeeFolder *folder_unmatched = vf->parent_vee_store ? vf->parent_vee_store->folder_unmatched : NULL;
+ GHashTable *unmatched_uids = vf->parent_vee_store ? vf->parent_vee_store->unmatched_uids : NULL;
+
+ if (vf == folder_unmatched)
+ return 0;
+
+ /* if we have no expression, or its been cleared, then act as if no matches */
+ if (vf->expression == NULL) {
+ match = g_ptr_array_new();
+ } else {
+ match = camel_folder_search_by_expression(f, vf->expression, ex);
+ if (match == NULL)
+ return -1;
+ }
+
+ u.source = source;
+ u.vf = vf;
+ u.folder_unmatched = folder_unmatched;
+ u.unmatched_uids = unmatched_uids;
+ camel_vee_folder_hash_folder(source, u.hash);
+
+ CAMEL_VEE_FOLDER_LOCK(vf, summary_lock);
+
+ /* we build 2 hash tables, one for all uid's not matched, the other for all matched uid's,
+ we just ref the real memory */
+ matchhash = g_hash_table_new(g_str_hash, g_str_equal);
+ for (i=0;i<match->len;i++)
+ g_hash_table_insert(matchhash, match->pdata[i], GINT_TO_POINTER (1));
+
+ allhash = g_hash_table_new(g_str_hash, g_str_equal);
+ all = camel_folder_get_uids(f);
+ for (i=0;i<all->len;i++)
+ if (g_hash_table_lookup(matchhash, all->pdata[i]) == NULL)
+ g_hash_table_insert(allhash, all->pdata[i], GINT_TO_POINTER (1));
+
+ if (folder_unmatched != NULL)
+ CAMEL_VEE_FOLDER_LOCK(folder_unmatched, summary_lock);
+
+ /* scan, looking for "old" uid's to be removed */
+ start = -1;
+ last = -1;
+ count = camel_folder_summary_count(folder->summary);
+ for (i=0;i<count;i++) {
+ CamelVeeMessageInfo *mi = (CamelVeeMessageInfo *)camel_folder_summary_index(folder->summary, i);
+
+ if (mi) {
+ if (mi->folder == source) {
+ char *uid = (char *)camel_message_info_uid(mi), *oldkey;
+ void *oldval;
+
+ if (g_hash_table_lookup(matchhash, uid+8) == NULL) {
+ if (last == -1) {
+ last = start = i;
+ } else if (last+1 == i) {
+ last = i;
+ } else {
+ camel_folder_summary_remove_range(folder->summary, start, last);
+ i -= (last-start)+1;
+ start = last = i;
+ }
+ camel_folder_change_info_remove_uid(vf->changes, camel_message_info_uid(mi));
+ if (!CAMEL_IS_VEE_FOLDER(source)
+ && unmatched_uids != NULL
+ && g_hash_table_lookup_extended(unmatched_uids, uid, (void **)&oldkey, &oldval)) {
+ n = GPOINTER_TO_INT (oldval);
+ if (n == 1) {
+ g_hash_table_remove(unmatched_uids, oldkey);
+ g_free(oldkey);
+ } else {
+ g_hash_table_insert(unmatched_uids, oldkey, GINT_TO_POINTER(n-1));
+ }
+ }
+ } else {
+ g_hash_table_remove(matchhash, uid+8);
+ }
+ }
+ camel_folder_summary_info_free(folder->summary, (CamelMessageInfo *)mi);
+ }
+ }
+ if (last != -1)
+ camel_folder_summary_remove_range(folder->summary, start, last);
+
+ /* now matchhash contains any new uid's, add them, etc */
+ g_hash_table_foreach(matchhash, (GHFunc)folder_added_uid, &u);
+
+ if (folder_unmatched != NULL) {
+ /* scan unmatched, remove any that have vanished, etc */
+ count = camel_folder_summary_count(((CamelFolder *)folder_unmatched)->summary);
+ for (i=0;i<count;i++) {
+ CamelVeeMessageInfo *mi = (CamelVeeMessageInfo *)camel_folder_summary_index(((CamelFolder *)folder_unmatched)->summary, i);
+
+ if (mi) {
+ if (mi->folder == source) {
+ char *uid = (char *)camel_message_info_uid(mi);
+
+ if (g_hash_table_lookup(allhash, uid+8) == NULL) {
+ /* no longer exists at all, just remove it entirely */
+ camel_folder_summary_remove_index(((CamelFolder *)folder_unmatched)->summary, i);
+ camel_folder_change_info_remove_uid(folder_unmatched->changes, camel_message_info_uid(mi));
+ i--;
+ } else {
+ g_hash_table_remove(allhash, uid+8);
+ }
+ }
+ camel_folder_summary_info_free(((CamelFolder *)folder_unmatched)->summary, (CamelMessageInfo *)mi);
+ }
+ }
+
+ /* now allhash contains all potentially new uid's for the unmatched folder, process */
+ if (!CAMEL_IS_VEE_FOLDER(source))
+ g_hash_table_foreach(allhash, (GHFunc)unmatched_check_uid, &u);
+
+ /* copy any changes so we can raise them outside the lock */
+ if (camel_folder_change_info_changed(folder_unmatched->changes)) {
+ unmatched_changes = folder_unmatched->changes;
+ folder_unmatched->changes = camel_folder_change_info_new();
+ }
+
+ CAMEL_VEE_FOLDER_UNLOCK(folder_unmatched, summary_lock);
+ }
+
+ if (camel_folder_change_info_changed(vf->changes)) {
+ vf_changes = vf->changes;
+ vf->changes = camel_folder_change_info_new();
+ }
+
+ CAMEL_VEE_FOLDER_UNLOCK(vf, summary_lock);
+
+ g_hash_table_destroy(matchhash);
+ g_hash_table_destroy(allhash);
+ /* if expression not set, we only had a null list */
+ if (vf->expression == NULL)
+ g_ptr_array_free(match, TRUE);
+ else
+ camel_folder_search_free(f, match);
+ camel_folder_free_uids(f, all);
+
+ if (unmatched_changes) {
+ camel_object_trigger_event((CamelObject *)folder_unmatched, "folder_changed", unmatched_changes);
+ camel_folder_change_info_free(unmatched_changes);
+ }
+
+ if (vf_changes) {
+ camel_object_trigger_event((CamelObject *)vf, "folder_changed", vf_changes);
+ camel_folder_change_info_free(vf_changes);
+ }
+
+ return 0;
+}
+
+/*
+
+ (match-folder "folder1" "folder2")
+
+ */
+
+
+/* Hold all these with summary lock and unmatched summary lock held */
+static void
+folder_changed_add_uid(CamelFolder *sub, const char *uid, const char hash[8], CamelVeeFolder *vf)
+{
+ CamelVeeMessageInfo *vinfo;
+ const char *vuid;
+ char *oldkey;
+ void *oldval;
+ int n;
+ CamelVeeFolder *folder_unmatched = vf->parent_vee_store ? vf->parent_vee_store->folder_unmatched : NULL;
+ GHashTable *unmatched_uids = vf->parent_vee_store ? vf->parent_vee_store->unmatched_uids : NULL;
+
+ vinfo = vee_folder_add_uid(vf, sub, uid, hash);
+ if (vinfo == NULL)
+ return;
+
+ vuid = camel_message_info_uid(vinfo);
+ camel_folder_change_info_add_uid(vf->changes, vuid);
+
+ if ((vf->flags & CAMEL_STORE_FOLDER_PRIVATE) == 0 && !CAMEL_IS_VEE_FOLDER(sub) && folder_unmatched != NULL) {
+ if (g_hash_table_lookup_extended(unmatched_uids, vuid, (void **)&oldkey, &oldval)) {
+ n = GPOINTER_TO_INT (oldval);
+ g_hash_table_insert(unmatched_uids, oldkey, GINT_TO_POINTER(n+1));
+ } else {
+ g_hash_table_insert(unmatched_uids, g_strdup(vuid), GINT_TO_POINTER (1));
+ }
+ vinfo = (CamelVeeMessageInfo *)camel_folder_get_message_info((CamelFolder *)folder_unmatched, vuid);
+ if (vinfo) {
+ camel_folder_change_info_remove_uid(folder_unmatched->changes, vuid);
+ camel_folder_summary_remove(((CamelFolder *)folder_unmatched)->summary, (CamelMessageInfo *)vinfo);
+ camel_folder_free_message_info((CamelFolder *)folder_unmatched, (CamelMessageInfo *)vinfo);
+ }
+ }
+}
+
+static void
+folder_changed_remove_uid(CamelFolder *sub, const char *uid, const char hash[8], int keep, CamelVeeFolder *vf)
+{
+ CamelFolder *folder = (CamelFolder *)vf;
+ char *vuid, *oldkey;
+ void *oldval;
+ int n;
+ CamelVeeMessageInfo *vinfo;
+ CamelVeeFolder *folder_unmatched = vf->parent_vee_store ? vf->parent_vee_store->folder_unmatched : NULL;
+ GHashTable *unmatched_uids = vf->parent_vee_store ? vf->parent_vee_store->unmatched_uids : NULL;
+
+ vuid = alloca(strlen(uid)+9);
+ memcpy(vuid, hash, 8);
+ strcpy(vuid+8, uid);
+
+ vinfo = (CamelVeeMessageInfo *)camel_folder_summary_uid(folder->summary, vuid);
+ if (vinfo) {
+ camel_folder_change_info_remove_uid(vf->changes, vuid);
+ camel_folder_summary_remove(folder->summary, (CamelMessageInfo *)vinfo);
+ camel_folder_summary_info_free(folder->summary, (CamelMessageInfo *)vinfo);
+ }
+
+ if ((vf->flags & CAMEL_STORE_FOLDER_PRIVATE) == 0 && !CAMEL_IS_VEE_FOLDER(sub) && folder_unmatched != NULL) {
+ if (keep) {
+ if (g_hash_table_lookup_extended(unmatched_uids, vuid, (void **)&oldkey, &oldval)) {
+ n = GPOINTER_TO_INT (oldval);
+ if (n == 1) {
+ g_hash_table_remove(unmatched_uids, oldkey);
+ if (vee_folder_add_uid(folder_unmatched, sub, uid, hash))
+ camel_folder_change_info_add_uid(folder_unmatched->changes, oldkey);
+ g_free(oldkey);
+ } else {
+ g_hash_table_insert(unmatched_uids, oldkey, GINT_TO_POINTER(n-1));
+ }
+ } else {
+ if (vee_folder_add_uid(folder_unmatched, sub, uid, hash))
+ camel_folder_change_info_add_uid(folder_unmatched->changes, oldkey);
+ }
+ } else {
+ if (g_hash_table_lookup_extended(unmatched_uids, vuid, (void **)&oldkey, &oldval)) {
+ g_hash_table_remove(unmatched_uids, oldkey);
+ g_free(oldkey);
+ }
+
+ vinfo = (CamelVeeMessageInfo *)camel_folder_get_message_info((CamelFolder *)folder_unmatched, vuid);
+ if (vinfo) {
+ camel_folder_change_info_remove_uid(folder_unmatched->changes, vuid);
+ camel_folder_summary_remove_uid(((CamelFolder *)folder_unmatched)->summary, vuid);
+ camel_folder_free_message_info((CamelFolder *)folder_unmatched, (CamelMessageInfo *)vinfo);
+ }
+ }
+ }
+}
+
+static void
+folder_changed_change_uid(CamelFolder *sub, const char *uid, const char hash[8], CamelVeeFolder *vf)
+{
+ char *vuid;
+ CamelVeeMessageInfo *vinfo, *uinfo = NULL;
+ CamelMessageInfo *info;
+ CamelFolder *folder = (CamelFolder *)vf;
+ CamelVeeFolder *folder_unmatched = vf->parent_vee_store ? vf->parent_vee_store->folder_unmatched : NULL;
+
+ vuid = alloca(strlen(uid)+9);
+ memcpy(vuid, hash, 8);
+ strcpy(vuid+8, uid);
+
+ vinfo = (CamelVeeMessageInfo *)camel_folder_summary_uid(folder->summary, vuid);
+ if (folder_unmatched != NULL)
+ uinfo = (CamelVeeMessageInfo *)camel_folder_summary_uid(((CamelFolder *)folder_unmatched)->summary, vuid);
+ if (vinfo || uinfo) {
+ info = camel_folder_get_message_info(sub, uid);
+ if (info) {
+ if (vinfo) {
+ int changed = FALSE;
+
+ if (vinfo->info.flags != info->flags){
+ vinfo->info.flags = info->flags;
+ changed = TRUE;
+ }
+
+ changed |= camel_flag_list_copy(&vinfo->info.user_flags, &info->user_flags);
+ changed |= camel_tag_list_copy(&vinfo->info.user_tags, &info->user_tags);
+ if (changed)
+ camel_folder_change_info_change_uid(vf->changes, vuid);
+
+ camel_folder_summary_info_free(folder->summary, (CamelMessageInfo *)vinfo);
+ }
+
+ if (uinfo) {
+ int changed = FALSE;
+
+ if (uinfo->info.flags != info->flags){
+ uinfo->info.flags = info->flags;
+ changed = TRUE;
+ }
+
+ changed |= camel_flag_list_copy(&uinfo->info.user_flags, &info->user_flags);
+ changed |= camel_tag_list_copy(&uinfo->info.user_tags, &info->user_tags);
+ if (changed)
+ camel_folder_change_info_change_uid(folder_unmatched->changes, vuid);
+
+ camel_folder_summary_info_free(((CamelFolder *)folder_unmatched)->summary, (CamelMessageInfo *)uinfo);
+ }
+
+ camel_folder_free_message_info(sub, info);
+ } else {
+ if (vinfo) {
+ folder_changed_remove_uid(sub, uid, hash, FALSE, vf);
+ camel_folder_summary_info_free(folder->summary, (CamelMessageInfo *)vinfo);
+ }
+ if (uinfo)
+ camel_folder_summary_info_free(((CamelFolder *)folder_unmatched)->summary, (CamelMessageInfo *)uinfo);
+ }
+ }
+}
+
+struct _folder_changed_msg {
+ CamelSessionThreadMsg msg;
+ CamelFolderChangeInfo *changes;
+ CamelFolder *sub;
+ CamelVeeFolder *vf;
+};
+
+static void
+folder_changed_change(CamelSession *session, CamelSessionThreadMsg *msg)
+{
+ struct _folder_changed_msg *m = (struct _folder_changed_msg *)msg;
+ CamelFolder *sub = m->sub;
+ CamelFolder *folder = (CamelFolder *)m->vf;
+ CamelVeeFolder *vf = m->vf;
+ CamelFolderChangeInfo *changes = m->changes;
+ char *vuid = NULL, hash[8];
+ const char *uid;
+ CamelVeeMessageInfo *vinfo;
+ int i, vuidlen = 0;
+ CamelFolderChangeInfo *vf_changes = NULL, *unmatched_changes = NULL;
+ GPtrArray *matches_added = NULL, /* newly added, that match */
+ *matches_changed = NULL, /* newly changed, that now match */
+ *newchanged = NULL,
+ *changed;
+ GPtrArray *always_changed = NULL;
+ GHashTable *matches_hash;
+ CamelVeeFolder *folder_unmatched = vf->parent_vee_store ? vf->parent_vee_store->folder_unmatched : NULL;
+ GHashTable *unmatched_uids = vf->parent_vee_store ? vf->parent_vee_store->unmatched_uids : NULL;
+
+ /* Check the folder hasn't beem removed while we weren't watching */
+ CAMEL_VEE_FOLDER_LOCK(vf, subfolder_lock);
+ if (g_list_find(_PRIVATE(vf)->folders, sub) == NULL) {
+ CAMEL_VEE_FOLDER_UNLOCK(vf, subfolder_lock);
+ return;
+ }
+
+ camel_vee_folder_hash_folder(sub, hash);
+
+ /* Lookup anything before we lock anything, to avoid deadlock with build_folder */
+
+ /* Find newly added that match */
+ if (changes->uid_added->len > 0) {
+ dd(printf(" Searching for added matches '%s'\n", vf->expression));
+ matches_added = camel_folder_search_by_uids(sub, vf->expression, changes->uid_added, NULL);
+ }
+
+ /* TODO:
+ In this code around here, we can work out if the search will affect the changes
+ we had, and only re-search against them if they might have */
+
+ /* Search for changed items that newly match, but only if we dont have them */
+ changed = changes->uid_changed;
+ if (changed->len > 0) {
+ dd(printf(" Searching for changed matches '%s'\n", vf->expression));
+
+ if ((vf->flags & CAMEL_STORE_VEE_FOLDER_AUTO) == 0) {
+ newchanged = g_ptr_array_new();
+ always_changed = g_ptr_array_new();
+ for (i=0;i<changed->len;i++) {
+ uid = changed->pdata[i];
+ if (strlen(uid)+9 > vuidlen) {
+ vuidlen = strlen(uid)+64;
+ vuid = g_realloc(vuid, vuidlen);
+ }
+ memcpy(vuid, hash, 8);
+ strcpy(vuid+8, uid);
+ vinfo = (CamelVeeMessageInfo *)camel_folder_summary_uid(folder->summary, vuid);
+ if (vinfo == NULL) {
+ g_ptr_array_add(newchanged, (char *)uid);
+ } else {
+ g_ptr_array_add(always_changed, (char *)uid);
+ camel_folder_summary_info_free(folder->summary, (CamelMessageInfo *)vinfo);
+ }
+ }
+ changed = newchanged;
+ }
+
+ if (changed->len)
+ matches_changed = camel_folder_search_by_uids(sub, vf->expression, changed, NULL);
+ }
+
+ CAMEL_VEE_FOLDER_LOCK(vf, summary_lock);
+ if (folder_unmatched != NULL)
+ CAMEL_VEE_FOLDER_LOCK(folder_unmatched, summary_lock);
+
+ dd(printf("Vfolder '%s' subfolder changed '%s'\n", folder->full_name, sub->full_name));
+ dd(printf(" changed %d added %d removed %d\n", changes->uid_changed->len, changes->uid_added->len, changes->uid_removed->len));
+
+ /* Always remove removed uid's, in any case */
+ for (i=0;i<changes->uid_removed->len;i++) {
+ dd(printf(" removing uid '%s'\n", (char *)changes->uid_removed->pdata[i]));
+ folder_changed_remove_uid(sub, changes->uid_removed->pdata[i], hash, FALSE, vf);
+ }
+
+ /* Add any newly matched or to unmatched folder if they dont */
+ if (matches_added) {
+ matches_hash = g_hash_table_new(g_str_hash, g_str_equal);
+ for (i=0;i<matches_added->len;i++) {
+ dd(printf(" %s", (char *)matches_added->pdata[i]));
+ g_hash_table_insert(matches_hash, matches_added->pdata[i], matches_added->pdata[i]);
+ }
+ for (i=0;i<changes->uid_added->len;i++) {
+ uid = changes->uid_added->pdata[i];
+ if (g_hash_table_lookup(matches_hash, uid)) {
+ dd(printf(" adding uid '%s' [newly matched]\n", (char *)uid));
+ folder_changed_add_uid(sub, uid, hash, vf);
+ } else if ((vf->flags & CAMEL_STORE_FOLDER_PRIVATE) == 0) {
+ if (strlen(uid)+9 > vuidlen) {
+ vuidlen = strlen(uid)+64;
+ vuid = g_realloc(vuid, vuidlen);
+ }
+ memcpy(vuid, hash, 8);
+ strcpy(vuid+8, uid);
+
+ if (!CAMEL_IS_VEE_FOLDER(sub) && folder_unmatched != NULL && g_hash_table_lookup(unmatched_uids, vuid) == NULL) {
+ dd(printf(" adding uid '%s' to Unmatched [newly unmatched]\n", (char *)uid));
+ vinfo = (CamelVeeMessageInfo *)camel_folder_get_message_info((CamelFolder *)folder_unmatched, vuid);
+ if (vinfo == NULL) {
+ if (vee_folder_add_uid(folder_unmatched, sub, uid, hash))
+ camel_folder_change_info_add_uid(folder_unmatched->changes, vuid);
+ } else {
+ camel_folder_free_message_info((CamelFolder *)folder_unmatched, (CamelMessageInfo *)vinfo);
+ }
+ }
+ }
+ }
+ g_hash_table_destroy(matches_hash);
+ }
+
+ /* Change any newly changed */
+ if (always_changed) {
+ for (i=0;i<always_changed->len;i++)
+ folder_changed_change_uid(sub, always_changed->pdata[i], hash, vf);
+ g_ptr_array_free(always_changed, TRUE);
+ }
+
+ /* Change/add/remove any changed */
+ if (matches_changed) {
+ /* If we are auto-updating, then re-check changed uids still match */
+ dd(printf(" Vfolder %supdate\nuids match:", (vf->flags & CAMEL_STORE_VEE_FOLDER_AUTO)?"auto-":""));
+ matches_hash = g_hash_table_new(g_str_hash, g_str_equal);
+ for (i=0;i<matches_changed->len;i++) {
+ dd(printf(" %s", (char *)matches_changed->pdata[i]));
+ g_hash_table_insert(matches_hash, matches_changed->pdata[i], matches_changed->pdata[i]);
+ }
+ dd(printf("\n"));
+ for (i=0;i<changed->len;i++) {
+ uid = changed->pdata[i];
+ if (strlen(uid)+9 > vuidlen) {
+ vuidlen = strlen(uid)+64;
+ vuid = g_realloc(vuid, vuidlen);
+ }
+ memcpy(vuid, hash, 8);
+ strcpy(vuid+8, uid);
+ vinfo = (CamelVeeMessageInfo *)camel_folder_summary_uid(folder->summary, vuid);
+ if (vinfo == NULL) {
+ if (g_hash_table_lookup(matches_hash, uid)) {
+ /* A uid we dont have, but now it matches, add it */
+ dd(printf(" adding uid '%s' [newly matched]\n", uid));
+ folder_changed_add_uid(sub, uid, hash, vf);
+ } else {
+ /* A uid we still don't have, just change it (for unmatched) */
+ folder_changed_change_uid(sub, uid, hash, vf);
+ }
+ } else {
+ if ((vf->flags & CAMEL_STORE_VEE_FOLDER_AUTO) == 0
+ || g_hash_table_lookup(matches_hash, uid)) {
+ /* still match, or we're not auto-updating, change event, (if it changed) */
+ dd(printf(" changing uid '%s' [still matches]\n", uid));
+ folder_changed_change_uid(sub, uid, hash, vf);
+ } else {
+ /* No longer matches, remove it, but keep it in unmatched (potentially) */
+ dd(printf(" removing uid '%s' [did match]\n", uid));
+ folder_changed_remove_uid(sub, uid, hash, TRUE, vf);
+ }
+ camel_folder_summary_info_free(folder->summary, (CamelMessageInfo *)vinfo);
+ }
+ }
+ g_hash_table_destroy(matches_hash);
+ } else {
+ /* stuff didn't match but it changed - check unmatched folder for changes */
+ for (i=0;i<changed->len;i++)
+ folder_changed_change_uid(sub, changed->pdata[i], hash, vf);
+ }
+
+ if (folder_unmatched != NULL) {
+ if (camel_folder_change_info_changed(folder_unmatched->changes)) {
+ unmatched_changes = folder_unmatched->changes;
+ folder_unmatched->changes = camel_folder_change_info_new();
+ }
+
+ CAMEL_VEE_FOLDER_UNLOCK(folder_unmatched, summary_lock);
+ }
+
+ if (camel_folder_change_info_changed(vf->changes)) {
+ vf_changes = vf->changes;
+ vf->changes = camel_folder_change_info_new();
+ }
+
+ CAMEL_VEE_FOLDER_UNLOCK(vf, summary_lock);
+
+ /* Cleanup stuff on our folder */
+ if (matches_added)
+ camel_folder_search_free(sub, matches_added);
+
+ if (matches_changed)
+ camel_folder_search_free(sub, matches_changed);
+
+ CAMEL_VEE_FOLDER_UNLOCK(vf, subfolder_lock);
+
+ /* cleanup the rest */
+ if (newchanged)
+ g_ptr_array_free(newchanged, TRUE);
+
+ g_free(vuid);
+
+ if (unmatched_changes) {
+ camel_object_trigger_event((CamelObject *)folder_unmatched, "folder_changed", unmatched_changes);
+ camel_folder_change_info_free(unmatched_changes);
+ }
+
+ if (vf_changes) {
+ /* If not auto-updating, keep track of changed folders for later re-sync */
+ if ((vf->flags & CAMEL_STORE_VEE_FOLDER_AUTO) == 0) {
+ CAMEL_VEE_FOLDER_LOCK(vf, changed_lock);
+ if (g_list_find(vf->priv->folders_changed, sub) != NULL)
+ vf->priv->folders_changed = g_list_prepend(vf->priv->folders_changed, sub);
+ CAMEL_VEE_FOLDER_UNLOCK(vf, changed_lock);
+ }
+
+ camel_object_trigger_event((CamelObject *)vf, "folder_changed", vf_changes);
+ camel_folder_change_info_free(vf_changes);
+ }
+}
+
+static void
+folder_changed_free(CamelSession *session, CamelSessionThreadMsg *msg)
+{
+ struct _folder_changed_msg *m = (struct _folder_changed_msg *)msg;
+
+ camel_folder_change_info_free(m->changes);
+ camel_object_unref((CamelObject *)m->vf);
+ camel_object_unref((CamelObject *)m->sub);
+}
+
+static CamelSessionThreadOps folder_changed_ops = {
+ folder_changed_change,
+ folder_changed_free,
+};
+
+static void
+folder_changed(CamelFolder *sub, CamelFolderChangeInfo *changes, CamelVeeFolder *vf)
+{
+ struct _folder_changed_msg *m;
+ CamelSession *session = ((CamelService *)((CamelFolder *)vf)->parent_store)->session;
+
+ m = camel_session_thread_msg_new(session, &folder_changed_ops, sizeof(*m));
+ m->changes = camel_folder_change_info_new();
+ camel_folder_change_info_cat(m->changes, changes);
+ m->sub = sub;
+ camel_object_ref((CamelObject *)sub);
+ m->vf = vf;
+ camel_object_ref((CamelObject *)vf);
+ camel_session_thread_queue(session, &m->msg, 0);
+}
+
+/* track vanishing folders */
+static void
+subfolder_deleted(CamelFolder *f, void *event_data, CamelVeeFolder *vf)
+{
+ camel_vee_folder_remove_folder(vf, f);
+}
+
+static void
+subfolder_renamed_update(CamelVeeFolder *vf, CamelFolder *sub, char hash[8])
+{
+ int count, i;
+ CamelFolderChangeInfo *changes = NULL;
+ CamelVeeFolder *folder_unmatched = vf->parent_vee_store ? vf->parent_vee_store->folder_unmatched : NULL;
+ GHashTable *unmatched_uids = vf->parent_vee_store ? vf->parent_vee_store->unmatched_uids : NULL;
+
+ CAMEL_VEE_FOLDER_LOCK(vf, summary_lock);
+
+ count = camel_folder_summary_count(((CamelFolder *)vf)->summary);
+ for (i=0;i<count;i++) {
+ CamelVeeMessageInfo *mi = (CamelVeeMessageInfo *)camel_folder_summary_index(((CamelFolder *)vf)->summary, i);
+ CamelVeeMessageInfo *vinfo;
+
+ if (mi == NULL)
+ continue;
+
+ if (mi->folder == sub) {
+ char *uid = (char *)camel_message_info_uid(mi);
+ char *oldkey;
+ void *oldval;
+
+ camel_folder_change_info_remove_uid(vf->changes, uid);
+ camel_folder_summary_remove(((CamelFolder *)vf)->summary, (CamelMessageInfo *)mi);
+
+ /* works since we always append on the end */
+ i--;
+ count--;
+
+ vinfo = vee_folder_add_uid(vf, sub, uid+8, hash);
+ if (vinfo)
+ camel_folder_change_info_add_uid(vf->changes, camel_message_info_uid(vinfo));
+
+ /* check unmatched uid's table for any matches */
+ if (vf == folder_unmatched
+ && g_hash_table_lookup_extended(unmatched_uids, uid, (void **)&oldkey, &oldval)) {
+ g_hash_table_remove(unmatched_uids, oldkey);
+ g_hash_table_insert(unmatched_uids, g_strdup(camel_message_info_uid(vinfo)), oldval);
+ g_free(oldkey);
+ }
+ }
+
+ camel_folder_summary_info_free(((CamelFolder *)vf)->summary, (CamelMessageInfo *)mi);
+ }
+
+ if (camel_folder_change_info_changed(vf->changes)) {
+ changes = vf->changes;
+ vf->changes = camel_folder_change_info_new();
+ }
+
+ CAMEL_VEE_FOLDER_UNLOCK(vf, summary_lock);
+
+ if (changes) {
+ camel_object_trigger_event((CamelObject *)vf, "folder_changed", changes);
+ camel_folder_change_info_free(changes);
+ }
+}
+
+static void
+subfolder_renamed(CamelFolder *f, void *event_data, CamelVeeFolder *vf)
+{
+ char hash[8];
+ CamelVeeFolder *folder_unmatched = vf->parent_vee_store ? vf->parent_vee_store->folder_unmatched : NULL;
+
+ /* TODO: This could probably be done in another thread, tho it is pretty quick/memory bound */
+
+ /* Life just got that little bit harder, if the folder is renamed, it means it breaks all of our uid's.
+ We need to remove the old uid's, fix them up, then release the new uid's, for the uid's that match this folder */
+
+ camel_vee_folder_hash_folder(f, hash);
+
+ subfolder_renamed_update(vf, f, hash);
+ if (folder_unmatched != NULL)
+ subfolder_renamed_update(folder_unmatched, f, hash);
+}
+
+static void
+vee_freeze (CamelFolder *folder)
+{
+ CamelVeeFolder *vfolder = (CamelVeeFolder *)folder;
+ struct _CamelVeeFolderPrivate *p = _PRIVATE(vfolder);
+ GList *node;
+
+ CAMEL_VEE_FOLDER_LOCK(vfolder, subfolder_lock);
+
+ node = p->folders;
+ while (node) {
+ CamelFolder *f = node->data;
+
+ camel_folder_freeze(f);
+ node = node->next;
+ }
+
+ CAMEL_VEE_FOLDER_UNLOCK(vfolder, subfolder_lock);
+
+ /* call parent implementation */
+ CAMEL_FOLDER_CLASS (camel_vee_folder_parent)->freeze(folder);
+}
+
+static void
+vee_thaw(CamelFolder *folder)
+{
+ CamelVeeFolder *vfolder = (CamelVeeFolder *)folder;
+ struct _CamelVeeFolderPrivate *p = _PRIVATE(vfolder);
+ GList *node;
+
+ CAMEL_VEE_FOLDER_LOCK(vfolder, subfolder_lock);
+
+ node = p->folders;
+ while (node) {
+ CamelFolder *f = node->data;
+
+ camel_folder_thaw(f);
+ node = node->next;
+ }
+
+ CAMEL_VEE_FOLDER_UNLOCK(vfolder, subfolder_lock);
+
+ /* call parent implementation */
+ CAMEL_FOLDER_CLASS (camel_vee_folder_parent)->thaw(folder);
+}
diff --git a/camel/camel-vee-folder.h b/camel/camel-vee-folder.h
new file mode 100644
index 0000000000..fc1a9f3571
--- /dev/null
+++ b/camel/camel-vee-folder.h
@@ -0,0 +1,88 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2000 Ximian Inc.
+ *
+ * Authors: Michael Zucchi <notzed@ximian.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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef _CAMEL_VEE_FOLDER_H
+#define _CAMEL_VEE_FOLDER_H
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif /* __cplusplus */
+
+#include <glib.h>
+#include <camel/camel-folder.h>
+
+#define CAMEL_VEE_FOLDER(obj) CAMEL_CHECK_CAST (obj, camel_vee_folder_get_type (), CamelVeeFolder)
+#define CAMEL_VEE_FOLDER_CLASS(klass) CAMEL_CHECK_CLASS_CAST (klass, camel_vee_folder_get_type (), CamelVeeFolderClass)
+#define CAMEL_IS_VEE_FOLDER(obj) CAMEL_CHECK_TYPE (obj, camel_vee_folder_get_type ())
+
+typedef struct _CamelVeeFolder CamelVeeFolder;
+typedef struct _CamelVeeFolderClass CamelVeeFolderClass;
+
+/* our message info includes the parent folder */
+typedef struct _CamelVeeMessageInfo {
+ CamelMessageInfo info;
+ CamelFolder *folder;
+} CamelVeeMessageInfo;
+
+struct _CamelVeeFolder {
+ CamelFolder parent;
+
+ struct _CamelVeeFolderPrivate *priv;
+
+ char *expression; /* query expression */
+ char *vname; /* local name */
+
+ guint32 flags; /* folder open flags */
+
+ CamelFolderChangeInfo *changes;
+ CamelFolderSearch *search;
+
+ /* only set-up if our parent is a vee-store, used also as a flag to
+ * say that this folder is part of the unmatched folder */
+ struct _CamelVeeStore *parent_vee_store;
+};
+
+struct _CamelVeeFolderClass {
+ CamelFolderClass parent_class;
+};
+
+#define CAMEL_UNMATCHED_NAME "UNMATCHED"
+
+CamelType camel_vee_folder_get_type (void);
+CamelFolder *camel_vee_folder_new (CamelStore *parent_store, const char *name, guint32 flags);
+void camel_vee_folder_construct (CamelVeeFolder *vf, CamelStore *parent_store, const char *full, const char *name, guint32 flags);
+
+CamelFolder *camel_vee_folder_get_location(CamelVeeFolder *vf, const CamelVeeMessageInfo *vinfo, char **realuid);
+
+void camel_vee_folder_add_folder (CamelVeeFolder *vf, CamelFolder *sub);
+void camel_vee_folder_remove_folder (CamelVeeFolder *vf, CamelFolder *sub);
+void camel_vee_folder_set_folders (CamelVeeFolder *vf, GList *folders);
+void camel_vee_folder_set_expression (CamelVeeFolder *vf, const char *expr);
+
+void camel_vee_folder_hash_folder (CamelFolder *folder, char buffer[8]);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* ! _CAMEL_VEE_FOLDER_H */
diff --git a/camel/camel-vee-store.c b/camel/camel-vee-store.c
new file mode 100644
index 0000000000..c3570b50de
--- /dev/null
+++ b/camel/camel-vee-store.c
@@ -0,0 +1,436 @@
+/*
+ * Copyright (C) 2000 Ximian Inc.
+ *
+ * Authors: Michael Zucchi <notzed@ximian.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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "camel-exception.h"
+#include "camel-vee-store.h"
+#include "camel-vee-folder.h"
+
+#include "camel-private.h"
+
+#include <string.h>
+
+#define d(x)
+
+static CamelFolder *vee_get_folder (CamelStore *store, const char *folder_name, guint32 flags, CamelException *ex);
+static void vee_delete_folder(CamelStore *store, const char *folder_name, CamelException *ex);
+static void vee_rename_folder(CamelStore *store, const char *old, const char *new, CamelException *ex);
+
+static void vee_sync (CamelStore *store, int expunge, CamelException *ex);
+static CamelFolder *vee_get_trash (CamelStore *store, CamelException *ex);
+static CamelFolder *vee_get_junk (CamelStore *store, CamelException *ex);
+
+static CamelFolderInfo *vee_get_folder_info(CamelStore *store, const char *top, guint32 flags, CamelException *ex);
+
+static void camel_vee_store_class_init (CamelVeeStoreClass *klass);
+static void camel_vee_store_init (CamelVeeStore *obj);
+static void camel_vee_store_finalise (CamelObject *obj);
+
+static CamelStoreClass *camel_vee_store_parent;
+
+CamelType
+camel_vee_store_get_type (void)
+{
+ static CamelType type = CAMEL_INVALID_TYPE;
+
+ if (type == CAMEL_INVALID_TYPE) {
+ type = camel_type_register (camel_store_get_type (), "CamelVeeStore",
+ sizeof (CamelVeeStore),
+ sizeof (CamelVeeStoreClass),
+ (CamelObjectClassInitFunc) camel_vee_store_class_init,
+ NULL,
+ (CamelObjectInitFunc) camel_vee_store_init,
+ (CamelObjectFinalizeFunc) camel_vee_store_finalise);
+ }
+
+ return type;
+}
+
+static void
+camel_vee_store_class_init (CamelVeeStoreClass *klass)
+{
+ CamelStoreClass *store_class = (CamelStoreClass *) klass;
+
+ camel_vee_store_parent = (CamelStoreClass *)camel_store_get_type();
+
+ /* virtual method overload */
+ store_class->get_folder = vee_get_folder;
+ store_class->rename_folder = vee_rename_folder;
+ store_class->delete_folder = vee_delete_folder;
+ store_class->get_folder_info = vee_get_folder_info;
+ store_class->free_folder_info = camel_store_free_folder_info_full;
+
+ store_class->sync = vee_sync;
+ store_class->get_trash = vee_get_trash;
+ store_class->get_junk = vee_get_junk;
+}
+
+static void
+camel_vee_store_init (CamelVeeStore *obj)
+{
+ CamelStore *store = (CamelStore *)obj;
+
+ /* we dont want a vtrash/vjunk on this one */
+ store->flags &= ~(CAMEL_STORE_VTRASH | CAMEL_STORE_VJUNK);
+
+ /* Set up unmatched folder */
+ obj->unmatched_uids = g_hash_table_new (g_str_hash, g_str_equal);
+ obj->folder_unmatched = (CamelVeeFolder *)camel_object_new (camel_vee_folder_get_type ());
+ camel_vee_folder_construct (obj->folder_unmatched, store, CAMEL_UNMATCHED_NAME, _("Unmatched"), CAMEL_STORE_FOLDER_PRIVATE);
+}
+
+static void
+cvs_free_unmatched(void *key, void *value, void *data)
+{
+ g_free(key);
+}
+
+static void
+camel_vee_store_finalise (CamelObject *obj)
+{
+ CamelVeeStore *vstore = (CamelVeeStore *)obj;
+
+ g_hash_table_foreach(vstore->unmatched_uids, cvs_free_unmatched, NULL);
+ g_hash_table_destroy(vstore->unmatched_uids);
+ camel_object_unref(vstore->folder_unmatched);
+}
+
+/**
+ * camel_vee_store_new:
+ *
+ * Create a new CamelVeeStore object.
+ *
+ * Return value: A new CamelVeeStore widget.
+ **/
+CamelVeeStore *
+camel_vee_store_new (void)
+{
+ CamelVeeStore *new = CAMEL_VEE_STORE(camel_object_new(camel_vee_store_get_type ()));
+ return new;
+}
+
+/* flags
+ 1 = delete (0 = add)
+ 2 = noselect
+*/
+#define CHANGE_ADD (0)
+#define CHANGE_DELETE (1)
+#define CHANGE_NOSELECT (2)
+
+static void
+change_folder(CamelStore *store, const char *name, guint32 flags, int count)
+{
+ CamelFolderInfo *fi;
+ const char *tmp;
+ CamelURL *url;
+
+ fi = g_malloc0(sizeof(*fi));
+ fi->full_name = g_strdup(name);
+ tmp = strrchr(name, '/');
+ if (tmp == NULL)
+ tmp = name;
+ else
+ tmp++;
+ fi->name = g_strdup(tmp);
+ url = camel_url_new("vfolder:", 0);
+ camel_url_set_path(url, ((CamelService *)store)->url->path);
+ if (flags & CHANGE_NOSELECT)
+ camel_url_set_param(url, "noselect", "yes");
+ camel_url_set_fragment(url, name);
+ fi->uri = camel_url_to_string(url, 0);
+ camel_url_free(url);
+ /*fi->url = g_strdup_printf("vfolder:%s%s#%s", ((CamelService *)store)->url->path, (flags&CHANGE_NOSELECT)?";noselect=yes":"", name);*/
+ fi->unread = count;
+ fi->flags = CAMEL_FOLDER_VIRTUAL;
+ if (!(flags & CHANGE_DELETE))
+ fi->flags |= CAMEL_FOLDER_NOCHILDREN;
+ camel_object_trigger_event(store, (flags&CHANGE_DELETE)?"folder_deleted":"folder_created", fi);
+ camel_folder_info_free(fi);
+}
+
+static CamelFolder *
+vee_get_folder (CamelStore *store, const char *folder_name, guint32 flags, CamelException *ex)
+{
+ CamelVeeFolder *vf;
+ CamelFolder *folder;
+ char *name, *p;
+
+ vf = (CamelVeeFolder *)camel_vee_folder_new(store, folder_name, flags);
+ if ((vf->flags & CAMEL_STORE_FOLDER_PRIVATE) == 0) {
+ /* Check that parents exist, if not, create dummy ones */
+ name = alloca(strlen(vf->vname)+1);
+ strcpy(name, vf->vname);
+ p = name;
+ while ( (p = strchr(p, '/'))) {
+ *p = 0;
+
+ folder = camel_object_bag_reserve(store->folders, name);
+ if (folder == NULL) {
+ /* create a dummy vFolder for this, makes get_folder_info simpler */
+ folder = camel_vee_folder_new(store, name, flags);
+ camel_object_bag_add(store->folders, name, folder);
+ change_folder(store, name, CHANGE_ADD|CHANGE_NOSELECT, 0);
+ /* FIXME: this sort of leaks folder, nobody owns a ref to it but us */
+ } else {
+ camel_object_unref(folder);
+ }
+ *p++='/';
+ }
+
+ change_folder(store, vf->vname, CHANGE_ADD, camel_folder_get_message_count((CamelFolder *)vf));
+ }
+
+ return (CamelFolder *)vf;
+}
+
+static void
+vee_sync(CamelStore *store, int expunge, CamelException *ex)
+{
+ /* noop */;
+}
+
+static CamelFolder *
+vee_get_trash (CamelStore *store, CamelException *ex)
+{
+ return NULL;
+}
+
+static CamelFolder *
+vee_get_junk (CamelStore *store, CamelException *ex)
+{
+ return NULL;
+}
+
+static int
+vee_folder_cmp(const void *ap, const void *bp)
+{
+ return strcmp(((CamelFolder **)ap)[0]->full_name, ((CamelFolder **)bp)[0]->full_name);
+}
+
+static CamelFolderInfo *
+vee_get_folder_info(CamelStore *store, const char *top, guint32 flags, CamelException *ex)
+{
+ CamelFolderInfo *info, *res = NULL, *tail;
+ GPtrArray *folders;
+ GHashTable *infos_hash;
+ CamelURL *url;
+ int i;
+
+ d(printf("Get folder info '%s'\n", top?top:"<null>"));
+
+ infos_hash = g_hash_table_new(g_str_hash, g_str_equal);
+ folders = camel_object_bag_list(store->folders);
+ qsort(folders->pdata, folders->len, sizeof(folders->pdata[0]), vee_folder_cmp);
+ for (i=0;i<folders->len;i++) {
+ CamelVeeFolder *folder = folders->pdata[i];
+ int add = FALSE;
+ char *name = ((CamelFolder *)folder)->full_name, *pname, *tmp;
+ CamelFolderInfo *pinfo;
+
+ d(printf("folder '%s'\n", name));
+
+ /* check we have to include this one */
+ if (top) {
+ int namelen = strlen(name);
+ int toplen = strlen(top);
+
+ add = ((namelen == toplen
+ && strcmp(name, top) == 0)
+ || ((namelen > toplen)
+ && strncmp(name, top, toplen) == 0
+ && name[toplen] == '/'
+ && ((flags & CAMEL_STORE_FOLDER_INFO_RECURSIVE)
+ || strchr(name+toplen+1, '/') == NULL)));
+ } else {
+ add = (flags & CAMEL_STORE_FOLDER_INFO_RECURSIVE)
+ || strchr(name, '/') == NULL;
+ }
+
+ d(printf("%sadding '%s'\n", add?"":"not ", name));
+
+ if (add) {
+ /* ensures unread is correct */
+ if ((flags & CAMEL_STORE_FOLDER_INFO_FAST) == 0)
+ camel_folder_refresh_info((CamelFolder *)folder, NULL);
+
+ info = g_malloc0(sizeof(*info));
+ url = camel_url_new("vfolder:", NULL);
+ camel_url_set_path(url, ((CamelService *)((CamelFolder *)folder)->parent_store)->url->path);
+ camel_url_set_fragment(url, ((CamelFolder *)folder)->full_name);
+ info->uri = camel_url_to_string(url, 0);
+ camel_url_free(url);
+/*
+ info->url = g_strdup_printf("vfolder:%s#%s", ((CamelService *)((CamelFolder *)folder)->parent_store)->url->path,
+ ((CamelFolder *)folder)->full_name);*/
+ info->full_name = g_strdup(((CamelFolder *)folder)->full_name);
+ info->name = g_strdup(((CamelFolder *)folder)->name);
+ info->unread = camel_folder_get_unread_message_count((CamelFolder *)folder);
+ info->flags = CAMEL_FOLDER_NOCHILDREN|CAMEL_FOLDER_VIRTUAL;
+ g_hash_table_insert(infos_hash, info->full_name, info);
+
+ if (res == NULL)
+ res = info;
+ } else {
+ info = NULL;
+ }
+
+ /* check for parent, if present, update flags and if adding, update parent linkage */
+ pname = g_strdup(((CamelFolder *)folder)->full_name);
+ d(printf("looking up parent of '%s'\n", pname));
+ tmp = strrchr(pname, '/');
+ if (tmp) {
+ *tmp = 0;
+ pinfo = g_hash_table_lookup(infos_hash, pname);
+ } else
+ pinfo = NULL;
+
+ if (pinfo) {
+ pinfo->flags = (pinfo->flags & ~(CAMEL_FOLDER_CHILDREN|CAMEL_FOLDER_NOCHILDREN))|CAMEL_FOLDER_CHILDREN;
+ d(printf("updating parent flags for children '%s' %08x\n", pinfo->full_name, pinfo->flags));
+ tail = pinfo->child;
+ if (tail == NULL)
+ pinfo->child = info;
+ } else if (info != res) {
+ tail = res;
+ } else {
+ tail = NULL;
+ }
+
+ if (info && tail) {
+ while (tail->next)
+ tail = tail->next;
+ tail->next = info;
+ info->parent = pinfo;
+ }
+
+ g_free(pname);
+ camel_object_unref(folder);
+ }
+ g_ptr_array_free(folders, TRUE);
+ g_hash_table_destroy(infos_hash);
+
+ /* and always add UNMATCHED, if scanning from top/etc */
+ if (top == NULL || top[0] == 0 || strncmp(top, CAMEL_UNMATCHED_NAME, strlen(CAMEL_UNMATCHED_NAME)) == 0) {
+ info = g_malloc0(sizeof(*info));
+ url = camel_url_new("vfolder:", NULL);
+ camel_url_set_path(url, ((CamelService *)store)->url->path);
+ camel_url_set_fragment(url, CAMEL_UNMATCHED_NAME);
+ info->uri = camel_url_to_string(url, 0);
+ camel_url_free(url);
+ /*info->url = g_strdup_printf("vfolder:%s#%s", ((CamelService *)store)->url->path, CAMEL_UNMATCHED_NAME);*/
+ info->full_name = g_strdup(CAMEL_UNMATCHED_NAME);
+ info->name = g_strdup(_("Unmatched"));
+ info->unread = -1;
+ info->flags = CAMEL_FOLDER_NOCHILDREN|CAMEL_FOLDER_NOINFERIORS|CAMEL_FOLDER_SYSTEM|CAMEL_FOLDER_VIRTUAL;
+
+ if (res == NULL)
+ res = info;
+ else {
+ tail = res;
+ while (tail->next)
+ tail = tail->next;
+ tail->next = info;
+ }
+ }
+
+ return res;
+}
+
+static void
+vee_delete_folder(CamelStore *store, const char *folder_name, CamelException *ex)
+{
+ CamelFolder *folder;
+
+ if (strcmp(folder_name, CAMEL_UNMATCHED_NAME) == 0) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER,
+ _("Cannot delete folder: %s: Invalid operation"), folder_name);
+ return;
+ }
+
+ folder = camel_object_bag_get(store->folders, folder_name);
+ if (folder) {
+ char *statefile;
+
+ camel_object_get(folder, NULL, CAMEL_OBJECT_STATE_FILE, &statefile, NULL);
+ if (statefile) {
+ unlink(statefile);
+ camel_object_free(folder, CAMEL_OBJECT_STATE_FILE, statefile);
+ camel_object_set(folder, NULL, CAMEL_OBJECT_STATE_FILE, NULL, NULL);
+ }
+
+ if ((((CamelVeeFolder *)folder)->flags & CAMEL_STORE_FOLDER_PRIVATE) == 0) {
+ /* what about now-empty parents? ignore? */
+ change_folder(store, folder_name, CHANGE_DELETE, -1);
+ }
+
+ camel_object_unref(folder);
+ } else {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER,
+ _("Cannot delete folder: %s: No such folder"), folder_name);
+ }
+}
+
+static void
+vee_rename_folder(CamelStore *store, const char *old, const char *new, CamelException *ex)
+{
+ CamelFolder *folder, *oldfolder;
+ char *p, *name;
+
+ d(printf("vee rename folder '%s' '%s'\n", old, new));
+
+ if (strcmp(old, CAMEL_UNMATCHED_NAME) == 0) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER,
+ _("Cannot rename folder: %s: Invalid operation"), old);
+ return;
+ }
+
+ /* See if it exists, for vfolders, all folders are in the folders hash */
+ oldfolder = camel_object_bag_get(store->folders, old);
+ if (oldfolder == NULL) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER,
+ _("Cannot rename folder: %s: No such folder"), old);
+ return;
+ }
+
+ /* Check that new parents exist, if not, create dummy ones */
+ name = alloca(strlen(new)+1);
+ strcpy(name, new);
+ p = name;
+ while ( (p = strchr(p, '/'))) {
+ *p = 0;
+
+ folder = camel_object_bag_reserve(store->folders, name);
+ if (folder == NULL) {
+ /* create a dummy vFolder for this, makes get_folder_info simpler */
+ folder = camel_vee_folder_new(store, name, ((CamelVeeFolder *)oldfolder)->flags);
+ camel_object_bag_add(store->folders, name, folder);
+ change_folder(store, name, CHANGE_ADD|CHANGE_NOSELECT, 0);
+ /* FIXME: this sort of leaks folder, nobody owns a ref to it but us */
+ } else {
+ camel_object_unref(folder);
+ }
+ *p++='/';
+ }
+
+ camel_object_unref(oldfolder);
+}
diff --git a/camel/camel-vee-store.h b/camel/camel-vee-store.h
new file mode 100644
index 0000000000..a5a9864a56
--- /dev/null
+++ b/camel/camel-vee-store.h
@@ -0,0 +1,63 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2000 Ximian Inc.
+ *
+ * Authors: Michael Zucchi <notzed@ximian.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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef _CAMEL_VEE_STORE_H
+#define _CAMEL_VEE_STORE_H
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif /* __cplusplus */
+
+#include <glib.h>
+#include <camel/camel-store.h>
+
+#define CAMEL_VEE_STORE(obj) CAMEL_CHECK_CAST (obj, camel_vee_store_get_type (), CamelVeeStore)
+#define CAMEL_VEE_STORE_CLASS(klass) CAMEL_CHECK_CLASS_CAST (klass, camel_vee_store_get_type (), CamelVeeStoreClass)
+#define CAMEL_IS_VEE_STORE(obj) CAMEL_CHECK_TYPE (obj, camel_vee_store_get_type ())
+
+typedef struct _CamelVeeStore CamelVeeStore;
+typedef struct _CamelVeeStoreClass CamelVeeStoreClass;
+
+/* open mode for folder, vee folder auto-update */
+#define CAMEL_STORE_VEE_FOLDER_AUTO (1<<16)
+
+struct _CamelVeeStore {
+ CamelStore parent;
+
+ /* Unmatched folder, set up in camel_vee_store_init */
+ struct _CamelVeeFolder *folder_unmatched;
+ GHashTable *unmatched_uids;
+};
+
+struct _CamelVeeStoreClass {
+ CamelStoreClass parent_class;
+};
+
+CamelType camel_vee_store_get_type (void);
+CamelVeeStore *camel_vee_store_new (void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* ! _CAMEL_VEE_STORE_H */
diff --git a/camel/camel-vtrash-folder.c b/camel/camel-vtrash-folder.c
new file mode 100644
index 0000000000..e0da46f7c3
--- /dev/null
+++ b/camel/camel-vtrash-folder.c
@@ -0,0 +1,230 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Jeffrey Stedfast <fejj@ximian.com>
+ *
+ * Copyright 2001 Ximian, Inc. (www.ximian.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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include <config.h>
+
+#include "camel-exception.h"
+#include "camel-vtrash-folder.h"
+#include "camel-store.h"
+#include "camel-vee-store.h"
+#include "camel-mime-message.h"
+
+#include <string.h>
+
+/* Returns the class for a CamelFolder */
+#define CF_CLASS(so) ((CamelFolderClass *)((CamelObject *)(so))->klass)
+
+static struct {
+ const char *full_name;
+ const char *name;
+ const char *expr;
+ guint32 bit;
+ guint32 flags;
+ const char *error_copy;
+} vdata[] = {
+ { CAMEL_VTRASH_NAME, N_("Trash"), "(match-all (system-flag \"Deleted\"))", CAMEL_MESSAGE_DELETED, CAMEL_FOLDER_IS_TRASH,
+ N_("Cannot copy messages to the Trash folder") },
+ { CAMEL_VJUNK_NAME, N_("Junk"), "(match-all (system-flag \"Junk\"))", CAMEL_MESSAGE_JUNK, CAMEL_FOLDER_IS_JUNK,
+ N_("Cannot copy messages to the Junk folder") },
+};
+
+static CamelVeeFolderClass *camel_vtrash_folder_parent;
+
+static void vtrash_append_message (CamelFolder *folder, CamelMimeMessage *message,
+ const CamelMessageInfo *info, char **appended_uid,
+ CamelException *ex);
+static void vtrash_transfer_messages_to (CamelFolder *folder, GPtrArray *uids,
+ CamelFolder *dest, GPtrArray **transferred_uids,
+ gboolean delete_originals, CamelException *ex);
+
+static void
+camel_vtrash_folder_class_init (CamelVTrashFolderClass *klass)
+{
+ CamelFolderClass *folder_class = (CamelFolderClass *) klass;
+
+ camel_vtrash_folder_parent = CAMEL_VEE_FOLDER_CLASS(camel_vee_folder_get_type());
+
+ folder_class->append_message = vtrash_append_message;
+ folder_class->transfer_messages_to = vtrash_transfer_messages_to;
+}
+
+static void
+camel_vtrash_folder_init (CamelVTrashFolder *vtrash)
+{
+ /*CamelFolder *folder = CAMEL_FOLDER (vtrash);*/
+}
+
+CamelType
+camel_vtrash_folder_get_type (void)
+{
+ static CamelType type = CAMEL_INVALID_TYPE;
+
+ if (type == CAMEL_INVALID_TYPE) {
+ type = camel_type_register (camel_vee_folder_get_type (),
+ "CamelVTrashFolder",
+ sizeof (CamelVTrashFolder),
+ sizeof (CamelVTrashFolderClass),
+ (CamelObjectClassInitFunc) camel_vtrash_folder_class_init,
+ NULL,
+ (CamelObjectInitFunc) camel_vtrash_folder_init,
+ NULL);
+ }
+
+ return type;
+}
+
+/**
+ * camel_vtrash_folder_new:
+ * @parent_store: the parent CamelVeeStore
+ * @type: type of vfolder, CAMEL_VTRASH_FOLDER_TRASH or CAMEL_VTRASH_FOLDER_JUNK currently.
+ * @ex: a CamelException
+ *
+ * Create a new CamelVeeFolder object.
+ *
+ * Return value: A new CamelVeeFolder widget.
+ **/
+CamelFolder *
+camel_vtrash_folder_new (CamelStore *parent_store, enum _camel_vtrash_folder_t type)
+{
+ CamelVTrashFolder *vtrash;
+
+ g_assert(type < CAMEL_VTRASH_FOLDER_LAST);
+
+ vtrash = (CamelVTrashFolder *)camel_object_new(camel_vtrash_folder_get_type());
+ camel_vee_folder_construct(CAMEL_VEE_FOLDER (vtrash), parent_store, vdata[type].full_name, _(vdata[type].name),
+ CAMEL_STORE_FOLDER_PRIVATE|CAMEL_STORE_FOLDER_CREATE|CAMEL_STORE_VEE_FOLDER_AUTO);
+
+ ((CamelFolder *)vtrash)->folder_flags |= vdata[type].flags;
+ camel_vee_folder_set_expression((CamelVeeFolder *)vtrash, vdata[type].expr);
+ vtrash->bit = vdata[type].bit;
+ vtrash->type = type;
+
+ return (CamelFolder *)vtrash;
+}
+
+static void
+vtrash_append_message (CamelFolder *folder, CamelMimeMessage *message,
+ const CamelMessageInfo *info, char **appended_uid,
+ CamelException *ex)
+{
+ camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM,
+ _(vdata[((CamelVTrashFolder *)folder)->type].error_copy));
+}
+
+struct _transfer_data {
+ CamelFolder *folder;
+ CamelFolder *dest;
+ GPtrArray *uids;
+ gboolean delete;
+};
+
+static void
+transfer_messages(CamelFolder *folder, struct _transfer_data *md, CamelException *ex)
+{
+ int i;
+
+ if (!camel_exception_is_set (ex))
+ camel_folder_transfer_messages_to(md->folder, md->uids, md->dest, NULL, md->delete, ex);
+
+ for (i=0;i<md->uids->len;i++)
+ g_free(md->uids->pdata[i]);
+ g_ptr_array_free(md->uids, TRUE);
+ camel_object_unref((CamelObject *)md->folder);
+ g_free(md);
+}
+
+static void
+vtrash_transfer_messages_to (CamelFolder *source, GPtrArray *uids,
+ CamelFolder *dest, GPtrArray **transferred_uids,
+ gboolean delete_originals, CamelException *ex)
+{
+ CamelVeeMessageInfo *mi;
+ int i;
+ GHashTable *batch = NULL;
+ const char *tuid;
+ struct _transfer_data *md;
+ guint32 sbit = ((CamelVTrashFolder *)source)->bit;
+
+ /* This is a special case of transfer_messages_to: Either the
+ * source or the destination is a vtrash folder (but not both
+ * since a store should never have more than one).
+ */
+
+ if (transferred_uids)
+ *transferred_uids = NULL;
+
+ if (CAMEL_IS_VTRASH_FOLDER (dest)) {
+ /* Copy to trash is meaningless. */
+ if (!delete_originals) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM,
+ _(vdata[((CamelVTrashFolder *)dest)->type].error_copy));
+ return;
+ }
+
+ /* Move to trash is the same as setting the message flag */
+ for (i = 0; i < uids->len; i++)
+ camel_folder_set_message_flags(source, uids->pdata[i], ((CamelVTrashFolder *)dest)->bit, ~0);
+ return;
+ }
+
+ /* Moving/Copying from the trash to the original folder = undelete.
+ * Moving/Copying from the trash to a different folder = move/copy.
+ *
+ * Need to check this uid by uid, but we batch up the copies.
+ */
+
+ for (i = 0; i < uids->len; i++) {
+ mi = (CamelVeeMessageInfo *)camel_folder_get_message_info (source, uids->pdata[i]);
+ if (mi == NULL) {
+ g_warning ("Cannot find uid %s in source folder during transfer", (char *) uids->pdata[i]);
+ continue;
+ }
+
+ if (dest == mi->folder) {
+ /* Just unset the flag on the original message */
+ camel_folder_set_message_flags (source, uids->pdata[i], sbit, 0);
+ } else {
+ if (batch == NULL)
+ batch = g_hash_table_new(NULL, NULL);
+ md = g_hash_table_lookup(batch, mi->folder);
+ if (md == NULL) {
+ md = g_malloc0(sizeof(*md));
+ md->folder = mi->folder;
+ camel_object_ref((CamelObject *)md->folder);
+ md->uids = g_ptr_array_new();
+ md->dest = dest;
+ g_hash_table_insert(batch, mi->folder, md);
+ }
+
+ tuid = uids->pdata[i];
+ if (strlen(tuid)>8)
+ tuid += 8;
+ g_ptr_array_add(md->uids, g_strdup(tuid));
+ }
+ camel_folder_free_message_info (source, (CamelMessageInfo *)mi);
+ }
+
+ if (batch) {
+ g_hash_table_foreach(batch, (GHFunc)transfer_messages, ex);
+ g_hash_table_destroy(batch);
+ }
+}
diff --git a/plugins/groupwise-account-setup/camel-gw-listener.c b/camel/providers/groupwise/camel-gw-listener.c
index 70b720d506..9da66d6b6d 100644
--- a/plugins/groupwise-account-setup/camel-gw-listener.c
+++ b/camel/providers/groupwise/camel-gw-listener.c
@@ -27,9 +27,9 @@
#include "camel-gw-listener.h"
#include <string.h>
-#include <camel/camel-i18n.h>
+#include "camel-i18n.h"
#include <e-gw-connection.h>
-#include <e-util/e-passwords.h>
+#include <e-passwords.h>
#include "widgets/misc/e-error.h"
/*stores some info about all currently existing groupwise accounts
@@ -162,7 +162,7 @@ lookup_account_info (const char *key)
#define SELECTED_TASKS "/apps/evolution/calendar/tasks/selected_tasks"
static void
-add_esource (const char *conf_key, const char *group_name, const char *source_name, CamelURL *url)
+add_esource (const char *conf_key, const char *group_name, const char* source_name, const char *username, const char* relative_uri, const char *soap_port, const char *use_ssl)
{
ESourceList *source_list;
ESourceGroup *group;
@@ -170,41 +170,20 @@ add_esource (const char *conf_key, const char *group_name, const char *source_n
GConfClient* client;
GSList *ids, *temp ;
char *source_selection_key;
- 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");
-
client = gconf_client_get_default();
source_list = e_source_list_new_for_gconf (client, conf_key);
group = e_source_group_new (group_name, GROUPWISE_URI_PREFIX);
- if (!e_source_list_add_group (source_list, group, -1))
+ 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, "username", username);
+ e_source_set_property (source, "port", 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_group_add_source (group, source, -1);
e_source_list_sync (source_list, NULL);
@@ -227,7 +206,6 @@ add_esource (const char *conf_key, const char *group_name, const char *source_n
g_object_unref (group);
g_object_unref (source_list);
g_object_unref (client);
- g_free (relative_uri);
}
@@ -304,7 +282,7 @@ remove_esource (const char *conf_key, const char *group_name, char* source_name,
/* looks up for e-source with having same info as old_account_info and changes its values passed in new values */
static void
-modify_esource (const char* conf_key, GwAccountInfo *old_account_info, const char* new_group_name, CamelURL *new_url)
+modify_esource (const char* conf_key, GwAccountInfo *old_account_info, const char* new_group_name, const char *username, const char* new_relative_uri, const char *soap_port, const char *use_ssl)
{
ESourceList *list;
ESourceGroup *group;
@@ -316,15 +294,11 @@ modify_esource (const char* conf_key, GwAccountInfo *old_account_info, const cha
gboolean found_group;
GConfClient* client;
const char *poa_address;
- char *new_relative_uri;
- const char *new_poa_address;
-
+
url = camel_url_new (old_account_info->source_url, NULL);
- poa_address = url->host;
+ poa_address = camel_url_get_param (url, "poa");
if (!poa_address || strlen (poa_address) ==0)
return;
- new_poa_address = new_url->host;
-
old_relative_uri = g_strdup_printf ("%s@%s/", url->user, poa_address);
client = gconf_client_get_default ();
list = e_source_list_new_for_gconf (client, conf_key);
@@ -347,16 +321,13 @@ modify_esource (const char* conf_key, GwAccountInfo *old_account_info, const cha
if (strcmp (e_source_peek_relative_uri (source), old_relative_uri) == 0) {
- new_relative_uri = g_strdup_printf ("%s@%s/", new_url->user, new_poa_address);
e_source_group_set_name (group, new_group_name);
e_source_set_relative_uri (source, new_relative_uri);
- e_source_set_property (source, "username", new_url->user);
- e_source_set_property (source, "port", camel_url_get_param (new_url,"soap_port"));
- e_source_set_property (source, "use_ssl", camel_url_get_param (url, "use_ssl"));
- e_source_set_property (source, "offline_sync", camel_url_get_param (url, "offline_sync") ? "1" : "0");
+ e_source_set_property (source, "username", username);
+ e_source_set_property (source, "port", soap_port);
+ e_source_set_property (source, "use_ssl", use_ssl);
e_source_list_sync (list, NULL);
found_group = TRUE;
- g_free (new_relative_uri);
break;
}
}
@@ -367,7 +338,6 @@ modify_esource (const char* conf_key, GwAccountInfo *old_account_info, const cha
g_object_unref (client);
camel_url_free (url);
g_free (old_relative_uri);
-
}
/* add sources for calendar and tasks if the account added is groupwise account
@@ -377,13 +347,32 @@ static void
add_calendar_tasks_sources (GwAccountInfo *info)
{
CamelURL *url;
+ char *relative_uri;
+ const char *soap_port;
+ const char * use_ssl;
+ const char *poa_address;
url = camel_url_new (info->source_url, NULL);
- add_esource ("/apps/evolution/calendar/sources", info->name, _("Calendar"), url);
- add_esource ("/apps/evolution/tasks/sources", info->name, _("Tasks"), url);
+ poa_address = camel_url_get_param (url, "poa");
+ 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 = "7181";
+
+ use_ssl = camel_url_get_param (url, "soap_ssl");
+ if (use_ssl)
+ use_ssl = "always";
+ else
+ use_ssl = NULL;
+
+ relative_uri = g_strdup_printf ("%s@%s/", url->user, poa_address);
+ add_esource ("/apps/evolution/calendar/sources", info->name, _("Calendar"), url->user, relative_uri, soap_port, use_ssl);
+ add_esource ("/apps/evolution/tasks/sources", info->name, _("Tasks"), url->user, relative_uri, soap_port, use_ssl);
camel_url_free (url);
-
+ g_free (relative_uri);
}
@@ -400,13 +389,13 @@ remove_calendar_tasks_sources (GwAccountInfo *info)
url = camel_url_new (info->source_url, NULL);
- poa_address = url->host;
+ poa_address = camel_url_get_param (url, "poa");
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";
+ soap_port = "7181";
relative_uri = g_strdup_printf ("%s@%s/", url->user, poa_address);
remove_esource ("/apps/evolution/calendar/sources", info->name, _("Calendar"), relative_uri);
@@ -429,7 +418,6 @@ get_addressbook_names_from_server (char *source_url)
gboolean remember;
char *failed_auth;
char *prompt;
- char *password_prompt;
char *uri;
const char *use_ssl;
const char *poa_address;
@@ -439,18 +427,18 @@ get_addressbook_names_from_server (char *source_url)
if (url == NULL) {
return NULL;
}
- poa_address = url->host;
+ poa_address = camel_url_get_param (url, "poa");
if (!poa_address || strlen (poa_address) ==0)
return NULL;
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");
-
+ soap_port = "7181";
+ use_ssl = camel_url_get_param (url, "soap_ssl");
+ if(use_ssl)
+ use_ssl = "always";
key = g_strdup_printf ("groupwise://%s@%s/", url->user, poa_address);
-
- if (!g_str_equal (use_ssl, "never"))
+ if (use_ssl)
uri = g_strdup_printf ("https://%s:%s/soap", poa_address, soap_port);
else
uri = g_strdup_printf ("http://%s:%s/soap", poa_address, soap_port);
@@ -458,10 +446,9 @@ get_addressbook_names_from_server (char *source_url)
failed_auth = "";
cnc = NULL;
do {
- password_prompt = g_strdup_printf (_("Enter password for %s (user %s)"),
- poa_address, url->user);
- prompt = g_strconcat (failed_auth, password_prompt, NULL);
- g_free (password_prompt);
+ prompt = g_strdup_printf (_("%sEnter password for %s (user %s)"),
+ failed_auth, poa_address, url->user);
+
password = e_passwords_ask_password (prompt, "Groupwise", key, prompt,
E_PASSWORDS_REMEMBER_FOREVER|E_PASSWORDS_SECRET, &remember,
NULL);
@@ -470,11 +457,6 @@ get_addressbook_names_from_server (char *source_url)
if (!password)
break;
cnc = e_gw_connection_new (uri, url->user, password);
- if (!E_IS_GW_CONNECTION(cnc) && use_ssl && g_str_equal (use_ssl, "when-possible")) {
- char *http_uri = g_strconcat ("http://", uri + 8, NULL);
- cnc = e_gw_connection_new (http_uri, url->user, password);
- g_free (http_uri);
- }
failed_auth = _("Failed to authenticate.\n");
flags |= E_PASSWORDS_REPROMPT;
} while (cnc == NULL);
@@ -512,14 +494,14 @@ add_addressbook_sources (EAccount *account)
return FALSE;
}
- poa_address = url->host;
+ poa_address = camel_url_get_param (url, "poa");
if (!poa_address || strlen (poa_address) ==0)
return FALSE;
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");
+ soap_port = "7181";
+ use_ssl = camel_url_get_param (url, "soap_ssl");
base_uri = g_strdup_printf ("groupwise://%s@%s", url->user, poa_address);
client = gconf_client_get_default ();
list = e_source_list_new_for_gconf (client, "/apps/evolution/addressbook/sources" );
@@ -535,7 +517,7 @@ add_addressbook_sources (EAccount *account)
e_source_set_property (source, "auth-domain", "Groupwise");
e_source_set_property (source, "port", soap_port);
e_source_set_property(source, "user", url->user);
- e_source_set_property (source, "offline_sync", camel_url_get_param (url, "offline_sync") ? "1" : "0");
+
if (!e_gw_container_get_is_writable (E_GW_CONTAINER(temp_list->data)))
e_source_set_property (source, "completion", "true");
if (e_gw_container_get_is_frequent_contacts (E_GW_CONTAINER(temp_list->data)))
@@ -577,14 +559,13 @@ modify_addressbook_sources ( EAccount *account, GwAccountInfo *existing_account_
ESource *source;
GConfClient *client;
const char *poa_address;
-
url = camel_url_new (existing_account_info->source_url, NULL);
if (url == NULL) {
return;
}
- poa_address = url->host;
+ poa_address = camel_url_get_param (url, "poa");
if (!poa_address || strlen (poa_address) ==0)
return;
@@ -594,14 +575,14 @@ modify_addressbook_sources ( EAccount *account, GwAccountInfo *existing_account_
url = camel_url_new (account->source->url, NULL);
if (url == NULL)
return ;
- poa_address = url->host;
+ poa_address = camel_url_get_param (url, "poa");
if (!poa_address || strlen (poa_address) ==0)
return;
new_base_uri = g_strdup_printf ("groupwise://%s@%s", url->user, poa_address);
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");
+ soap_port = "7181";
+ use_ssl = camel_url_get_param (url, "soap_ssl");
client = gconf_client_get_default ();
list = e_source_list_new_for_gconf (client, "/apps/evolution/addressbook/sources" );
@@ -664,13 +645,13 @@ remove_addressbook_sources (GwAccountInfo *existing_account_info)
return;
}
- poa_address = url->host;
+ poa_address = camel_url_get_param (url, "poa");
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";
+ soap_port = "7181";
base_uri = g_strdup_printf ("groupwise://%s@%s", url->user, poa_address);
client = gconf_client_get_default ();
list = e_source_list_new_for_gconf (client, "/apps/evolution/addressbook/sources" );
@@ -750,9 +731,11 @@ account_changed (EAccountList *account_listener, EAccount *account)
{
gboolean is_gw_account;
CamelURL *old_url, *new_url;
+ char *relative_uri;
const char *old_soap_port, *new_soap_port;
GwAccountInfo *existing_account_info;
const char *old_use_ssl, *new_use_ssl;
+ gboolean old_ssl, new_ssl;
const char *old_poa_address, *new_poa_address;
is_gw_account = is_groupwise_account (account);
@@ -784,35 +767,43 @@ account_changed (EAccountList *account_listener, EAccount *account)
account_removed (account_listener, account);
return;
}
-
+ old_ssl = new_ssl = FALSE;
/* some info of groupwise account is changed . update the sources with new info if required */
old_url = camel_url_new (existing_account_info->source_url, NULL);
- old_poa_address = old_url->host;
+ old_poa_address = camel_url_get_param (old_url, "poa");
old_soap_port = camel_url_get_param (old_url, "soap_port");
- old_use_ssl = camel_url_get_param (old_url, "use_ssl");
+ old_use_ssl = camel_url_get_param (old_url, "soap_ssl");
+ if (old_use_ssl)
+ old_ssl = TRUE;
new_url = camel_url_new (account->source->url, NULL);
- new_poa_address = new_url->host;
+
+ new_poa_address = camel_url_get_param (new_url, "poa");
if (!new_poa_address || strlen (new_poa_address) ==0)
return;
new_soap_port = camel_url_get_param (new_url, "soap_port");
if (!new_soap_port || strlen (new_soap_port) == 0)
- new_soap_port = "7191";
+ new_soap_port = "7181";
- new_use_ssl = camel_url_get_param (new_url, "use_ssl");
-
+ new_use_ssl = camel_url_get_param (new_url, "soap_ssl");
+ if (new_use_ssl){
+ new_use_ssl = "always";
+ new_ssl = TRUE;
+ }
if ((old_poa_address && strcmp (old_poa_address, new_poa_address))
|| (old_soap_port && strcmp (old_soap_port, new_soap_port))
|| strcmp (old_url->user, new_url->user)
- || strcmp (old_use_ssl, new_use_ssl)) {
+ || ( old_ssl ^ new_ssl)) {
account_removed (account_listener, account);
account_added (account_listener, account);
} else if (strcmp (existing_account_info->name, account->name)) {
- modify_esource ("/apps/evolution/calendar/sources", existing_account_info, account->name, new_url);
- modify_esource ("/apps/evolution/tasks/sources", existing_account_info, account->name, new_url);
+ relative_uri = g_strdup_printf ("%s@%s/", new_url->user, new_poa_address);
+ modify_esource ("/apps/evolution/calendar/sources", existing_account_info, account->name, new_url->user, relative_uri, new_soap_port, new_use_ssl);
+ modify_esource ("/apps/evolution/tasks/sources", existing_account_info, account->name, new_url->user, relative_uri, new_soap_port, new_use_ssl);
modify_addressbook_sources (account, existing_account_info);
+ g_free (relative_uri);
}
diff --git a/camel/providers/imap/camel-imap-command.c b/camel/providers/imap/camel-imap-command.c
new file mode 100644
index 0000000000..207ce64be6
--- /dev/null
+++ b/camel/providers/imap/camel-imap-command.c
@@ -0,0 +1,847 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* camel-imap-command.c: IMAP command sending/parsing routines */
+
+/*
+ * Authors:
+ * Dan Winship <danw@ximian.com>
+ * Jeffrey Stedfast <fejj@ximian.com>
+ *
+ * Copyright 2000, 2001 Ximian, Inc.
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "camel-imap-command.h"
+#include "camel-imap-utils.h"
+#include "camel-imap-folder.h"
+#include "camel-imap-store.h"
+#include "camel-imap-store-summary.h"
+#include "camel-imap-private.h"
+#include <camel/camel-exception.h>
+#include <camel/camel-private.h>
+#include <camel/camel-utf8.h>
+#include <camel/camel-session.h>
+#include <camel/camel-debug.h>
+
+extern int camel_verbose_debug;
+
+static gboolean imap_command_start (CamelImapStore *store, CamelFolder *folder,
+ const char *cmd, CamelException *ex);
+CamelImapResponse *imap_read_response (CamelImapStore *store,
+ CamelException *ex);
+static char *imap_read_untagged (CamelImapStore *store, char *line,
+ CamelException *ex);
+static char *imap_command_strdup_vprintf (CamelImapStore *store,
+ const char *fmt, va_list ap);
+static char *imap_command_strdup_printf (CamelImapStore *store,
+ const char *fmt, ...);
+
+/**
+ * camel_imap_command:
+ * @store: the IMAP store
+ * @folder: The folder to perform the operation in (or %NULL if not
+ * relevant).
+ * @ex: a CamelException
+ * @fmt: a sort of printf-style format string, followed by arguments
+ *
+ * This function calls camel_imap_command_start() to send the
+ * command, then reads the complete response to it using
+ * camel_imap_command_response() and returns a CamelImapResponse
+ * structure.
+ *
+ * As a special case, if @fmt is %NULL, it will just select @folder
+ * and return the response from doing so.
+ *
+ * See camel_imap_command_start() for details on @fmt.
+ *
+ * On success, the store's connect_lock will be locked. It will be freed
+ * when you call camel_imap_response_free. (The lock is recursive, so
+ * callers can grab and release it themselves if they need to run
+ * multiple commands atomically.)
+ *
+ * Return value: %NULL if an error occurred (in which case @ex will
+ * be set). Otherwise, a CamelImapResponse describing the server's
+ * response, which the caller must free with camel_imap_response_free().
+ **/
+CamelImapResponse *
+camel_imap_command (CamelImapStore *store, CamelFolder *folder,
+ CamelException *ex, const char *fmt, ...)
+{
+ va_list ap;
+ char *cmd;
+
+ CAMEL_SERVICE_LOCK (store, connect_lock);
+
+ if (fmt) {
+ va_start (ap, fmt);
+ cmd = imap_command_strdup_vprintf (store, fmt, ap);
+ va_end (ap);
+ } else {
+ camel_object_ref(folder);
+ if (store->current_folder)
+ camel_object_unref(store->current_folder);
+ store->current_folder = folder;
+ cmd = imap_command_strdup_printf (store, "SELECT %F", folder->full_name);
+ }
+
+ if (!imap_command_start (store, folder, cmd, ex)) {
+ g_free (cmd);
+ CAMEL_SERVICE_UNLOCK (store, connect_lock);
+ return NULL;
+ }
+ g_free (cmd);
+
+ return imap_read_response (store, ex);
+}
+
+/**
+ * camel_imap_command_start:
+ * @store: the IMAP store
+ * @folder: The folder to perform the operation in (or %NULL if not
+ * relevant).
+ * @ex: a CamelException
+ * @fmt: a sort of printf-style format string, followed by arguments
+ *
+ * This function makes sure that @folder (if non-%NULL) is the
+ * currently-selected folder on @store and then sends the IMAP command
+ * specified by @fmt and the following arguments.
+ *
+ * @fmt can include the following %-escapes ONLY:
+ * %s, %d, %%: as with printf
+ * %S: an IMAP "string" (quoted string or literal)
+ * %F: an IMAP folder name
+ *
+ * %S strings will be passed as literals if the server supports LITERAL+
+ * and quoted strings otherwise. (%S does not support strings that
+ * contain newlines.)
+ *
+ * %F will have the imap store's namespace prepended and then be processed
+ * like %S.
+ *
+ * On success, the store's connect_lock will be locked. It will be
+ * freed when %CAMEL_IMAP_RESPONSE_TAGGED or %CAMEL_IMAP_RESPONSE_ERROR
+ * is returned from camel_imap_command_response(). (The lock is
+ * recursive, so callers can grab and release it themselves if they
+ * need to run multiple commands atomically.)
+ *
+ * Return value: %TRUE if the command was sent successfully, %FALSE if
+ * an error occurred (in which case @ex will be set).
+ **/
+gboolean
+camel_imap_command_start (CamelImapStore *store, CamelFolder *folder,
+ CamelException *ex, const char *fmt, ...)
+{
+ va_list ap;
+ char *cmd;
+ gboolean ok;
+
+ va_start (ap, fmt);
+ cmd = imap_command_strdup_vprintf (store, fmt, ap);
+ va_end (ap);
+
+ CAMEL_SERVICE_LOCK (store, connect_lock);
+ ok = imap_command_start (store, folder, cmd, ex);
+ g_free (cmd);
+
+ if (!ok)
+ CAMEL_SERVICE_UNLOCK (store, connect_lock);
+ return ok;
+}
+
+static gboolean
+imap_command_start (CamelImapStore *store, CamelFolder *folder,
+ const char *cmd, CamelException *ex)
+{
+ ssize_t nwritten;
+
+ /* Check for current folder */
+ if (folder && folder != store->current_folder) {
+ CamelImapResponse *response;
+ CamelException internal_ex;
+
+ response = camel_imap_command (store, folder, ex, NULL);
+ if (!response)
+ return FALSE;
+ camel_exception_init (&internal_ex);
+ camel_imap_folder_selected (folder, response, &internal_ex);
+ camel_imap_response_free (store, response);
+ if (camel_exception_is_set (&internal_ex)) {
+ camel_exception_xfer (ex, &internal_ex);
+ return FALSE;
+ }
+ }
+
+ /* Send the command */
+ if (camel_verbose_debug) {
+ const char *mask;
+
+ if (!strncmp ("LOGIN \"", cmd, 7))
+ mask = "LOGIN \"xxx\" xxx";
+ else if (!strncmp ("LOGIN {", cmd, 7))
+ mask = "LOGIN {N+}\r\nxxx {N+}\r\nxxx";
+ else if (!strncmp ("LOGIN ", cmd, 6))
+ mask = "LOGIN xxx xxx";
+ else
+ mask = cmd;
+
+ fprintf (stderr, "sending : %c%.5d %s\r\n", store->tag_prefix, store->command, mask);
+ }
+
+ nwritten = camel_stream_printf (store->ostream, "%c%.5d %s\r\n",
+ store->tag_prefix, store->command++, cmd);
+
+ if (nwritten == -1) {
+ if (errno == EINTR)
+ camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL,
+ _("Operation cancelled"));
+ else
+ camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ g_strerror (errno));
+
+ camel_service_disconnect (CAMEL_SERVICE (store), FALSE, NULL);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ * camel_imap_command_continuation:
+ * @store: the IMAP store
+ * @cmd: buffer containing the response/request data
+ * @cmdlen: command length
+ * @ex: a CamelException
+ *
+ * This method is for sending continuing responses to the IMAP server
+ * after camel_imap_command() or camel_imap_command_response() returns
+ * a continuation response.
+ *
+ * This function assumes you have an exclusive lock on the imap stream.
+ *
+ * Return value: as for camel_imap_command(). On failure, the store's
+ * connect_lock will be released.
+ **/
+CamelImapResponse *
+camel_imap_command_continuation (CamelImapStore *store, const char *cmd,
+ size_t cmdlen, CamelException *ex)
+{
+ if (!camel_imap_store_connected (store, ex))
+ return NULL;
+
+ if (camel_stream_write (store->ostream, cmd, cmdlen) == -1 ||
+ camel_stream_write (store->ostream, "\r\n", 2) == -1) {
+ if (errno == EINTR)
+ camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL,
+ _("Operation cancelled"));
+ else
+ camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ g_strerror (errno));
+ camel_service_disconnect (CAMEL_SERVICE (store), FALSE, NULL);
+ CAMEL_SERVICE_UNLOCK (store, connect_lock);
+ return NULL;
+ }
+
+ return imap_read_response (store, ex);
+}
+
+/**
+ * camel_imap_command_response:
+ * @store: the IMAP store
+ * @response: a pointer to pass back the response data in
+ * @ex: a CamelException
+ *
+ * This reads a single tagged, untagged, or continuation response from
+ * @store into *@response. The caller must free the string when it is
+ * done with it.
+ *
+ * Return value: One of %CAMEL_IMAP_RESPONSE_CONTINUATION,
+ * %CAMEL_IMAP_RESPONSE_UNTAGGED, %CAMEL_IMAP_RESPONSE_TAGGED, or
+ * %CAMEL_IMAP_RESPONSE_ERROR. If either of the last two, @store's
+ * command lock will be unlocked.
+ **/
+CamelImapResponseType
+camel_imap_command_response (CamelImapStore *store, char **response,
+ CamelException *ex)
+{
+ CamelImapResponseType type;
+ char *respbuf;
+
+ if (camel_imap_store_readline (store, &respbuf, ex) < 0) {
+ CAMEL_SERVICE_UNLOCK (store, connect_lock);
+ return CAMEL_IMAP_RESPONSE_ERROR;
+ }
+
+ switch (*respbuf) {
+ case '*':
+ if (!strncasecmp (respbuf, "* BYE", 5)) {
+ /* Connection was lost, no more data to fetch */
+ camel_service_disconnect (CAMEL_SERVICE (store), FALSE, NULL);
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ _("Server unexpectedly disconnected: %s"),
+ _("Unknown error")); /* g_strerror (104)); FIXME after 1.0 is released */
+ store->connected = FALSE;
+ g_free (respbuf);
+ respbuf = NULL;
+ type = CAMEL_IMAP_RESPONSE_ERROR;
+ break;
+ }
+
+ /* Read the rest of the response. */
+ type = CAMEL_IMAP_RESPONSE_UNTAGGED;
+ respbuf = imap_read_untagged (store, respbuf, ex);
+ if (!respbuf)
+ type = CAMEL_IMAP_RESPONSE_ERROR;
+ else if (!g_ascii_strncasecmp (respbuf, "* OK [ALERT]", 12)
+ || !g_ascii_strncasecmp (respbuf, "* NO [ALERT]", 12)
+ || !g_ascii_strncasecmp (respbuf, "* BAD [ALERT]", 13)) {
+ char *msg;
+
+ /* for imap ALERT codes, account user@host */
+ /* we might get a ']' from a BAD response since we +12, but who cares? */
+ msg = g_strdup_printf(_("Alert from IMAP server %s@%s:\n%s"),
+ ((CamelService *)store)->url->user, ((CamelService *)store)->url->host, respbuf+12);
+ camel_session_alert_user(((CamelService *)store)->session, CAMEL_SESSION_ALERT_WARNING, msg, FALSE);
+ g_free(msg);
+ }
+
+ break;
+ case '+':
+ type = CAMEL_IMAP_RESPONSE_CONTINUATION;
+ break;
+ default:
+ type = CAMEL_IMAP_RESPONSE_TAGGED;
+ break;
+ }
+ *response = respbuf;
+
+ if (type == CAMEL_IMAP_RESPONSE_ERROR ||
+ type == CAMEL_IMAP_RESPONSE_TAGGED)
+ CAMEL_SERVICE_UNLOCK (store, connect_lock);
+
+ return type;
+}
+
+CamelImapResponse *
+imap_read_response (CamelImapStore *store, CamelException *ex)
+{
+ CamelImapResponse *response;
+ CamelImapResponseType type;
+ char *respbuf, *p;
+
+ /* Get another lock so that when we reach the tagged
+ * response and camel_imap_command_response unlocks,
+ * we're still locked. This lock is owned by response
+ * and gets unlocked when response is freed.
+ */
+ CAMEL_SERVICE_LOCK (store, connect_lock);
+
+ response = g_new0 (CamelImapResponse, 1);
+ if (store->current_folder && camel_disco_store_status (CAMEL_DISCO_STORE (store)) != CAMEL_DISCO_STORE_RESYNCING) {
+ response->folder = store->current_folder;
+ camel_object_ref (CAMEL_OBJECT (response->folder));
+ }
+
+ response->untagged = g_ptr_array_new ();
+ while ((type = camel_imap_command_response (store, &respbuf, ex))
+ == CAMEL_IMAP_RESPONSE_UNTAGGED)
+ g_ptr_array_add (response->untagged, respbuf);
+
+ if (type == CAMEL_IMAP_RESPONSE_ERROR) {
+ camel_imap_response_free_without_processing (store, response);
+ return NULL;
+ }
+
+ response->status = respbuf;
+
+ /* Check for OK or continuation response. */
+ if (*respbuf == '+')
+ return response;
+ p = strchr (respbuf, ' ');
+ if (p && !strncasecmp (p, " OK", 3))
+ return response;
+
+ /* We should never get BAD, or anything else but +, OK, or NO
+ * for that matter.
+ */
+ if (!p || strncasecmp (p, " NO", 3) != 0) {
+ g_warning ("Unexpected response from IMAP server: %s",
+ respbuf);
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ _("Unexpected response from IMAP "
+ "server: %s"), respbuf);
+ camel_imap_response_free_without_processing (store, response);
+ return NULL;
+ }
+
+ p += 3;
+ if (!*p++)
+ p = NULL;
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("IMAP command failed: %s"),
+ p ? p : _("Unknown error"));
+ camel_imap_response_free_without_processing (store, response);
+ return NULL;
+}
+
+/* Given a line that is the start of an untagged response, read and
+ * return the complete response, which may include an arbitrary number
+ * of literals.
+ */
+static char *
+imap_read_untagged (CamelImapStore *store, char *line, CamelException *ex)
+{
+ int fulllen, ldigits, nread, i, sexp = 0;
+ unsigned int length;
+ GPtrArray *data;
+ GString *str;
+ char *end, *p, *s, *d;
+
+ p = strrchr (line, '{');
+ if (!p)
+ return line;
+
+ data = g_ptr_array_new ();
+ fulllen = 0;
+
+ while (1) {
+ str = g_string_new (line);
+ g_free (line);
+ fulllen += str->len;
+ g_ptr_array_add (data, str);
+
+ p = strrchr (str->str, '{');
+ if (!p)
+ break;
+
+ /* HACK ALERT: We scan the non-literal part of the string, looking for possible s expression braces.
+ This assumes we're getting s-expressions, which we should be.
+ This is so if we get a blank line after a literal, in an s-expression, we can keep going, since
+ we do no other parsing at this level.
+ TODO: handle quoted strings? */
+ for (s=str->str; s<p; s++) {
+ if (*s == '(')
+ sexp++;
+ else if (*s == ')')
+ sexp--;
+ }
+
+ length = strtoul (p + 1, &end, 10);
+ if (*end != '}' || *(end + 1) || end == p + 1 || length >= UINT_MAX - 2)
+ break;
+ ldigits = end - (p + 1);
+
+ /* Read the literal */
+ str = g_string_sized_new (length + 2);
+ str->str[0] = '\n';
+ nread = camel_stream_read (store->istream, str->str + 1, length);
+ if (nread == -1) {
+ if (errno == EINTR)
+ camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL,
+ _("Operation cancelled"));
+ else
+ camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ g_strerror (errno));
+ camel_service_disconnect (CAMEL_SERVICE (store), FALSE, NULL);
+ g_string_free (str, TRUE);
+ goto lose;
+ }
+ if (nread < length) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ _("Server response ended too soon."));
+ camel_service_disconnect (CAMEL_SERVICE (store), FALSE, NULL);
+ g_string_free (str, TRUE);
+ goto lose;
+ }
+ str->str[length + 1] = '\0';
+
+ if (camel_debug("imap")) {
+ printf("Literal: -->");
+ fwrite(str->str+1, 1, length, stdout);
+ printf("<--\n");
+ }
+
+ /* Fix up the literal, turning CRLFs into LF. Also, if
+ * we find any embedded NULs, strip them. This is
+ * dubious, but:
+ * - The IMAP grammar says you can't have NULs here
+ * anyway, so this will not affect our behavior
+ * against any completely correct server.
+ * - WU-imapd 12.264 (at least) will cheerily pass
+ * NULs along if they are embedded in the message
+ */
+
+ s = d = str->str + 1;
+ end = str->str + 1 + length;
+ while (s < end) {
+ while (s < end && *s == '\0') {
+ s++;
+ length--;
+ }
+ if (*s == '\r' && *(s + 1) == '\n') {
+ s++;
+ length--;
+ }
+ *d++ = *s++;
+ }
+ *d = '\0';
+ str->len = length + 1;
+
+ /* p points to the "{" in the line that starts the
+ * literal. The length of the CR-less response must be
+ * less than or equal to the length of the response
+ * with CRs, therefore overwriting the old value with
+ * the new value cannot cause an overrun. However, we
+ * don't want it to be shorter either, because then the
+ * GString's length would be off...
+ */
+ sprintf (p, "{%0*d}", ldigits, length);
+
+ fulllen += str->len;
+ g_ptr_array_add (data, str);
+
+ /* Read the next line. */
+ do {
+ if (camel_imap_store_readline (store, &line, ex) < 0)
+ goto lose;
+
+ /* MAJOR HACK ALERT, gropuwise sometimes sends an extra blank line after literals, check that here
+ But only do it if we're inside an sexpression */
+ if (line[0] == 0 && sexp > 0)
+ g_warning("Server sent empty line after a literal, assuming in error");
+ } while (line[0] == 0 && sexp > 0);
+ }
+
+ /* Now reassemble the data. */
+ p = line = g_malloc (fulllen + 1);
+ for (i = 0; i < data->len; i++) {
+ str = data->pdata[i];
+ memcpy (p, str->str, str->len);
+ p += str->len;
+ g_string_free (str, TRUE);
+ }
+ *p = '\0';
+ g_ptr_array_free (data, TRUE);
+ return line;
+
+ lose:
+ for (i = 0; i < data->len; i++)
+ g_string_free (data->pdata[i], TRUE);
+ g_ptr_array_free (data, TRUE);
+ return NULL;
+}
+
+
+/**
+ * camel_imap_response_free:
+ * @store: the CamelImapStore the response is from
+ * @response: a CamelImapResponse
+ *
+ * Frees all of the data in @response and processes any untagged
+ * EXPUNGE and EXISTS responses in it. Releases @store's connect_lock.
+ **/
+void
+camel_imap_response_free (CamelImapStore *store, CamelImapResponse *response)
+{
+ int i, number, exists = 0;
+ GArray *expunged = NULL;
+ char *resp, *p;
+
+ if (!response)
+ return;
+
+ for (i = 0; i < response->untagged->len; i++) {
+ resp = response->untagged->pdata[i];
+
+ if (response->folder) {
+ /* Check if it's something we need to handle. */
+ number = strtoul (resp + 2, &p, 10);
+ if (!g_ascii_strcasecmp (p, " EXISTS")) {
+ exists = number;
+ } else if (!strcasecmp (p, " EXPUNGE")) {
+ if (!expunged) {
+ expunged = g_array_new (FALSE, FALSE,
+ sizeof (int));
+ }
+ g_array_append_val (expunged, number);
+ }
+ }
+ g_free (resp);
+ }
+
+ g_ptr_array_free (response->untagged, TRUE);
+ g_free (response->status);
+
+ if (response->folder) {
+ if (exists > 0 || expunged) {
+ /* Update the summary */
+ camel_imap_folder_changed (response->folder,
+ exists, expunged, NULL);
+ if (expunged)
+ g_array_free (expunged, TRUE);
+ }
+
+ camel_object_unref (CAMEL_OBJECT (response->folder));
+ }
+
+ g_free (response);
+ CAMEL_SERVICE_UNLOCK (store, connect_lock);
+}
+
+/**
+ * camel_imap_response_free_without_processing:
+ * @store: the CamelImapStore the response is from.
+ * @response: a CamelImapResponse:
+ *
+ * Frees all of the data in @response without processing any untagged
+ * responses. Releases @store's command lock.
+ **/
+void
+camel_imap_response_free_without_processing (CamelImapStore *store,
+ CamelImapResponse *response)
+{
+ if (!response)
+ return;
+
+ if (response->folder) {
+ camel_object_unref (CAMEL_OBJECT (response->folder));
+ response->folder = NULL;
+ }
+ camel_imap_response_free (store, response);
+}
+
+/**
+ * camel_imap_response_extract:
+ * @store: the store the response came from
+ * @response: the response data returned from camel_imap_command
+ * @type: the response type to extract
+ * @ex: a CamelException
+ *
+ * This checks that @response contains a single untagged response of
+ * type @type and returns just that response data. If @response
+ * doesn't contain the right information, the function will set @ex
+ * and return %NULL. Either way, @response will be freed and the
+ * store's connect_lock released.
+ *
+ * Return value: the desired response string, which the caller must free.
+ **/
+char *
+camel_imap_response_extract (CamelImapStore *store,
+ CamelImapResponse *response,
+ const char *type,
+ CamelException *ex)
+{
+ int len = strlen (type), i;
+ char *resp;
+
+ len = strlen (type);
+
+ for (i = 0; i < response->untagged->len; i++) {
+ resp = response->untagged->pdata[i];
+ /* Skip "* ", and initial sequence number, if present */
+ strtoul (resp + 2, &resp, 10);
+ if (*resp == ' ')
+ resp = (char *) imap_next_word (resp);
+
+ if (!strncasecmp (resp, type, len))
+ break;
+ }
+
+ if (i < response->untagged->len) {
+ resp = response->untagged->pdata[i];
+ g_ptr_array_remove_index (response->untagged, i);
+ } else {
+ resp = NULL;
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ _("IMAP server response did not contain "
+ "%s information"), type);
+ }
+
+ camel_imap_response_free (store, response);
+ return resp;
+}
+
+/**
+ * camel_imap_response_extract_continuation:
+ * @store: the store the response came from
+ * @response: the response data returned from camel_imap_command
+ * @ex: a CamelException
+ *
+ * This checks that @response contains a continuation response, and
+ * returns just that data. If @response doesn't contain a continuation
+ * response, the function will set @ex, release @store's connect_lock,
+ * and return %NULL. Either way, @response will be freed.
+ *
+ * Return value: the desired response string, which the caller must free.
+ **/
+char *
+camel_imap_response_extract_continuation (CamelImapStore *store,
+ CamelImapResponse *response,
+ CamelException *ex)
+{
+ char *status;
+
+ if (response->status && *response->status == '+') {
+ status = response->status;
+ response->status = NULL;
+ camel_imap_response_free (store, response);
+ return status;
+ }
+
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ _("Unexpected OK response from IMAP server: %s"),
+ response->status);
+ camel_imap_response_free (store, response);
+ return NULL;
+}
+
+static char *
+imap_command_strdup_vprintf (CamelImapStore *store, const char *fmt,
+ va_list ap)
+{
+ GPtrArray *args;
+ const char *p, *start;
+ char *out, *outptr, *string;
+ int num, len, i, arglen;
+
+ args = g_ptr_array_new ();
+
+ /* Determine the length of the data */
+ len = strlen (fmt);
+ p = start = fmt;
+ while (*p) {
+ p = strchr (start, '%');
+ if (!p)
+ break;
+
+ switch (*++p) {
+ case 'd':
+ num = va_arg (ap, int);
+ g_ptr_array_add (args, GINT_TO_POINTER (num));
+ start = p + 1;
+ len += 10;
+ break;
+ case 's':
+ string = va_arg (ap, char *);
+ g_ptr_array_add (args, string);
+ start = p + 1;
+ len += strlen (string);
+ break;
+ case 'S':
+ case 'F':
+ string = va_arg (ap, char *);
+ if (*p == 'F') {
+ /* NB: this is freed during output */
+ char *s = camel_imap_store_summary_full_from_path(store->summary, string);
+ string = s?s:camel_utf8_utf7(string);
+ }
+ arglen = strlen (string);
+ g_ptr_array_add (args, string);
+ if (imap_is_atom (string)) {
+ len += arglen;
+ } else {
+ if (store->capabilities & IMAP_CAPABILITY_LITERALPLUS)
+ len += arglen + 15;
+ else
+ len += arglen * 2;
+ }
+ start = p + 1;
+ break;
+ case '%':
+ start = p;
+ break;
+ default:
+ g_warning ("camel-imap-command is not printf. I don't "
+ "know what '%%%c' means.", *p);
+ start = *p ? p + 1 : p;
+ break;
+ }
+ }
+
+ /* Now write out the string */
+ outptr = out = g_malloc (len + 1);
+ p = start = fmt;
+ i = 0;
+ while (*p) {
+ p = strchr (start, '%');
+ if (!p) {
+ strcpy (outptr, start);
+ break;
+ } else {
+ strncpy (outptr, start, p - start);
+ outptr += p - start;
+ }
+
+ switch (*++p) {
+ case 'd':
+ num = GPOINTER_TO_INT (args->pdata[i++]);
+ outptr += sprintf (outptr, "%d", num);
+ break;
+
+ case 's':
+ string = args->pdata[i++];
+ outptr += sprintf (outptr, "%s", string);
+ break;
+ case 'S':
+ case 'F':
+ string = args->pdata[i++];
+ if (imap_is_atom (string)) {
+ outptr += sprintf (outptr, "%s", string);
+ } else {
+ if (store->capabilities & IMAP_CAPABILITY_LITERALPLUS) {
+ outptr += sprintf (outptr, "{%d+}\r\n%s", (int)strlen(string), string);
+ } else {
+ char *quoted = imap_quote_string (string);
+
+ outptr += sprintf (outptr, "%s", quoted);
+ g_free (quoted);
+ }
+ }
+
+ if (*p == 'F')
+ g_free (string);
+ break;
+ default:
+ *outptr++ = '%';
+ *outptr++ = *p;
+ }
+
+ start = *p ? p + 1 : p;
+ }
+
+ return out;
+}
+
+static char *
+imap_command_strdup_printf (CamelImapStore *store, const char *fmt, ...)
+{
+ va_list ap;
+ char *result;
+
+ va_start (ap, fmt);
+ result = imap_command_strdup_vprintf (store, fmt, ap);
+ va_end (ap);
+
+ return result;
+}
diff --git a/camel/providers/imap/camel-imap-folder.c b/camel/providers/imap/camel-imap-folder.c
new file mode 100644
index 0000000000..0132f4e536
--- /dev/null
+++ b/camel/providers/imap/camel-imap-folder.c
@@ -0,0 +1,2814 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* camel-imap-folder.c: class for an imap folder */
+
+/*
+ * Authors:
+ * Dan Winship <danw@ximian.com>
+ * Jeffrey Stedfast <fejj@ximian.com>
+ *
+ * Copyright (C) 2000, 2001 Ximian, Inc.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <ctype.h>
+
+#include "e-util/e-path.h"
+#include "e-util/e-time-utils.h"
+
+#include "camel-imap-folder.h"
+#include "camel-imap-command.h"
+#include "camel-imap-message-cache.h"
+#include "camel-imap-private.h"
+#include "camel-imap-search.h"
+#include "camel-imap-store.h"
+#include "camel-imap-summary.h"
+#include "camel-imap-utils.h"
+#include "camel-imap-wrapper.h"
+#include "camel-data-wrapper.h"
+#include "camel-disco-diary.h"
+#include "camel-exception.h"
+#include "camel-mime-filter-crlf.h"
+#include "camel-mime-filter-from.h"
+#include "camel-mime-message.h"
+#include "camel-mime-utils.h"
+#include "camel-multipart.h"
+#include "camel-multipart-signed.h"
+#include "camel-multipart-encrypted.h"
+#include "camel-operation.h"
+#include "camel-session.h"
+#include "camel-stream-buffer.h"
+#include "camel-stream-filter.h"
+#include "camel-stream-mem.h"
+#include "camel-stream.h"
+#include "camel-private.h"
+#include "camel-string-utils.h"
+#include "camel-file-utils.h"
+#include "camel-debug.h"
+
+#define d(x)
+
+/* set to -1 for infinite size (suggested max command-line length is
+ * 1000 octets (see rfc2683), so we should keep the uid-set length to
+ * something under that so that our command-lines don't exceed 1000
+ * octets) */
+#define UID_SET_LIMIT (768)
+
+
+#define CF_CLASS(o) (CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(o)))
+static CamelDiscoFolderClass *disco_folder_class = NULL;
+
+static void imap_finalize (CamelObject *object);
+static int imap_getv(CamelObject *object, CamelException *ex, CamelArgGetV *args);
+
+static void imap_rescan (CamelFolder *folder, int exists, CamelException *ex);
+static void imap_refresh_info (CamelFolder *folder, CamelException *ex);
+static void imap_sync_online (CamelFolder *folder, CamelException *ex);
+static void imap_sync_offline (CamelFolder *folder, CamelException *ex);
+static void imap_expunge_uids_online (CamelFolder *folder, GPtrArray *uids, CamelException *ex);
+static void imap_expunge_uids_offline (CamelFolder *folder, GPtrArray *uids, CamelException *ex);
+static void imap_expunge_uids_resyncing (CamelFolder *folder, GPtrArray *uids, CamelException *ex);
+static void imap_cache_message (CamelDiscoFolder *disco_folder, const char *uid, CamelException *ex);
+static void imap_rename (CamelFolder *folder, const char *new);
+
+/* message manipulation */
+static CamelMimeMessage *imap_get_message (CamelFolder *folder, const gchar *uid,
+ CamelException *ex);
+static void imap_append_online (CamelFolder *folder, CamelMimeMessage *message,
+ const CamelMessageInfo *info, char **appended_uid,
+ CamelException *ex);
+static void imap_append_offline (CamelFolder *folder, CamelMimeMessage *message,
+ const CamelMessageInfo *info, char **appended_uid,
+ CamelException *ex);
+static void imap_append_resyncing (CamelFolder *folder, CamelMimeMessage *message,
+ const CamelMessageInfo *info, char **appended_uid,
+ CamelException *ex);
+
+static void imap_transfer_online (CamelFolder *source, GPtrArray *uids,
+ CamelFolder *dest, GPtrArray **transferred_uids,
+ gboolean delete_originals,
+ CamelException *ex);
+static void imap_transfer_offline (CamelFolder *source, GPtrArray *uids,
+ CamelFolder *dest, GPtrArray **transferred_uids,
+ gboolean delete_originals,
+ CamelException *ex);
+static void imap_transfer_resyncing (CamelFolder *source, GPtrArray *uids,
+ CamelFolder *dest, GPtrArray **transferred_uids,
+ gboolean delete_originals,
+ CamelException *ex);
+
+/* searching */
+static GPtrArray *imap_search_by_expression (CamelFolder *folder, const char *expression, CamelException *ex);
+static GPtrArray *imap_search_by_uids (CamelFolder *folder, const char *expression, GPtrArray *uids, CamelException *ex);
+static void imap_search_free (CamelFolder *folder, GPtrArray *uids);
+
+static void imap_thaw (CamelFolder *folder);
+
+static CamelObjectClass *parent_class;
+
+static GData *parse_fetch_response (CamelImapFolder *imap_folder, char *msg_att);
+
+static void
+camel_imap_folder_class_init (CamelImapFolderClass *camel_imap_folder_class)
+{
+ CamelFolderClass *camel_folder_class = CAMEL_FOLDER_CLASS (camel_imap_folder_class);
+ CamelDiscoFolderClass *camel_disco_folder_class = CAMEL_DISCO_FOLDER_CLASS (camel_imap_folder_class);
+
+ disco_folder_class = CAMEL_DISCO_FOLDER_CLASS (camel_type_get_global_classfuncs (camel_disco_folder_get_type ()));
+
+ /* virtual method overload */
+ ((CamelObjectClass *)camel_imap_folder_class)->getv = imap_getv;
+
+ camel_folder_class->get_message = imap_get_message;
+ camel_folder_class->rename = imap_rename;
+ camel_folder_class->search_by_expression = imap_search_by_expression;
+ camel_folder_class->search_by_uids = imap_search_by_uids;
+ camel_folder_class->search_free = imap_search_free;
+ camel_folder_class->thaw = imap_thaw;
+
+ camel_disco_folder_class->refresh_info_online = imap_refresh_info;
+ camel_disco_folder_class->sync_online = imap_sync_online;
+ camel_disco_folder_class->sync_offline = imap_sync_offline;
+ /* We don't sync flags at resync time: the online code will
+ * deal with it eventually.
+ */
+ camel_disco_folder_class->sync_resyncing = imap_sync_offline;
+ camel_disco_folder_class->expunge_uids_online = imap_expunge_uids_online;
+ camel_disco_folder_class->expunge_uids_offline = imap_expunge_uids_offline;
+ camel_disco_folder_class->expunge_uids_resyncing = imap_expunge_uids_resyncing;
+ camel_disco_folder_class->append_online = imap_append_online;
+ camel_disco_folder_class->append_offline = imap_append_offline;
+ camel_disco_folder_class->append_resyncing = imap_append_resyncing;
+ camel_disco_folder_class->transfer_online = imap_transfer_online;
+ camel_disco_folder_class->transfer_offline = imap_transfer_offline;
+ camel_disco_folder_class->transfer_resyncing = imap_transfer_resyncing;
+ camel_disco_folder_class->cache_message = imap_cache_message;
+}
+
+static void
+camel_imap_folder_init (gpointer object, gpointer klass)
+{
+ CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (object);
+ CamelFolder *folder = CAMEL_FOLDER (object);
+
+ folder->permanent_flags = CAMEL_MESSAGE_ANSWERED | CAMEL_MESSAGE_DELETED |
+ CAMEL_MESSAGE_DRAFT | CAMEL_MESSAGE_FLAGGED | CAMEL_MESSAGE_SEEN;
+
+ folder->folder_flags |= (CAMEL_FOLDER_HAS_SUMMARY_CAPABILITY |
+ CAMEL_FOLDER_HAS_SEARCH_CAPABILITY);
+
+ imap_folder->priv = g_malloc0(sizeof(*imap_folder->priv));
+#ifdef ENABLE_THREADS
+ imap_folder->priv->search_lock = e_mutex_new(E_MUTEX_SIMPLE);
+ imap_folder->priv->cache_lock = e_mutex_new(E_MUTEX_REC);
+#endif
+
+ imap_folder->need_rescan = TRUE;
+}
+
+CamelType
+camel_imap_folder_get_type (void)
+{
+ static CamelType camel_imap_folder_type = CAMEL_INVALID_TYPE;
+
+ if (camel_imap_folder_type == CAMEL_INVALID_TYPE) {
+ parent_class = camel_disco_folder_get_type();
+ camel_imap_folder_type =
+ camel_type_register (parent_class, "CamelImapFolder",
+ sizeof (CamelImapFolder),
+ sizeof (CamelImapFolderClass),
+ (CamelObjectClassInitFunc) camel_imap_folder_class_init,
+ NULL,
+ (CamelObjectInitFunc) camel_imap_folder_init,
+ (CamelObjectFinalizeFunc) imap_finalize);
+ }
+
+ return camel_imap_folder_type;
+}
+
+CamelFolder *
+camel_imap_folder_new (CamelStore *parent, const char *folder_name,
+ const char *folder_dir, CamelException *ex)
+{
+ CamelImapStore *imap_store = CAMEL_IMAP_STORE (parent);
+ CamelFolder *folder;
+ CamelImapFolder *imap_folder;
+ const char *short_name;
+ char *summary_file, *state_file;
+
+ if (camel_mkdir (folder_dir, S_IRWXU) != 0) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Could not create directory %s: %s"),
+ folder_dir, g_strerror (errno));
+ return NULL;
+ }
+
+ folder = CAMEL_FOLDER (camel_object_new (camel_imap_folder_get_type ()));
+ short_name = strrchr (folder_name, '/');
+ if (short_name)
+ short_name++;
+ else
+ short_name = folder_name;
+ camel_folder_construct (folder, parent, folder_name, short_name);
+
+ summary_file = g_strdup_printf ("%s/summary", folder_dir);
+ folder->summary = camel_imap_summary_new (summary_file);
+ g_free (summary_file);
+ if (!folder->summary) {
+ camel_object_unref (CAMEL_OBJECT (folder));
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Could not load summary for %s"),
+ folder_name);
+ return NULL;
+ }
+
+ /* set/load persistent state */
+ state_file = g_strdup_printf ("%s/cmeta", folder_dir);
+ camel_object_set(folder, NULL, CAMEL_OBJECT_STATE_FILE, state_file, NULL);
+ g_free(state_file);
+ camel_object_state_read(folder);
+
+ imap_folder = CAMEL_IMAP_FOLDER (folder);
+ imap_folder->cache = camel_imap_message_cache_new (folder_dir, folder->summary, ex);
+ if (!imap_folder->cache) {
+ camel_object_unref (CAMEL_OBJECT (folder));
+ return NULL;
+ }
+
+ if (!g_ascii_strcasecmp (folder_name, "INBOX")) {
+ if ((imap_store->parameters & IMAP_PARAM_FILTER_INBOX))
+ folder->folder_flags |= CAMEL_FOLDER_FILTER_RECENT;
+ if ((imap_store->parameters & IMAP_PARAM_FILTER_JUNK))
+ folder->folder_flags |= CAMEL_FOLDER_FILTER_JUNK;
+ } else {
+ if ((imap_store->parameters & (IMAP_PARAM_FILTER_JUNK|IMAP_PARAM_FILTER_JUNK_INBOX)) == (IMAP_PARAM_FILTER_JUNK))
+ folder->folder_flags |= CAMEL_FOLDER_FILTER_JUNK;
+ }
+
+ imap_folder->search = camel_imap_search_new(folder_dir);
+
+ return folder;
+}
+
+/* Called with the store's connect_lock locked */
+void
+camel_imap_folder_selected (CamelFolder *folder, CamelImapResponse *response,
+ CamelException *ex)
+{
+ CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
+ CamelImapSummary *imap_summary = CAMEL_IMAP_SUMMARY (folder->summary);
+ unsigned long exists = 0, validity = 0, val, uid;
+ CamelMessageInfo *info;
+ guint32 perm_flags = 0;
+ GData *fetch_data;
+ int i, count;
+ char *resp;
+
+ CAMEL_SERVICE_ASSERT_LOCKED (folder->parent_store, connect_lock);
+
+ count = camel_folder_summary_count (folder->summary);
+
+ for (i = 0; i < response->untagged->len; i++) {
+ resp = response->untagged->pdata[i] + 2;
+ if (!strncasecmp (resp, "FLAGS ", 6) && !perm_flags) {
+ resp += 6;
+ folder->permanent_flags = imap_parse_flag_list (&resp);
+ } else if (!strncasecmp (resp, "OK [PERMANENTFLAGS ", 19)) {
+ resp += 19;
+
+ /* workaround for broken IMAP servers that send "* OK [PERMANENTFLAGS ()] Permanent flags"
+ * even tho they do allow storing flags. *Sigh* So many fucking broken IMAP servers out there. */
+ if ((perm_flags = imap_parse_flag_list (&resp)) != 0)
+ folder->permanent_flags = perm_flags;
+ } else if (!strncasecmp (resp, "OK [UIDVALIDITY ", 16)) {
+ validity = strtoul (resp + 16, NULL, 10);
+ } else if (isdigit ((unsigned char)*resp)) {
+ unsigned long num = strtoul (resp, &resp, 10);
+
+ if (!strncasecmp (resp, " EXISTS", 7)) {
+ exists = num;
+ /* Remove from the response so nothing
+ * else tries to interpret it.
+ */
+ g_free (response->untagged->pdata[i]);
+ g_ptr_array_remove_index (response->untagged, i--);
+ }
+ }
+ }
+
+ if (camel_strstrcase (response->status, "OK [READ-ONLY]"))
+ imap_folder->read_only = TRUE;
+
+ if (camel_disco_store_status (CAMEL_DISCO_STORE (folder->parent_store)) == CAMEL_DISCO_STORE_RESYNCING) {
+ if (validity != imap_summary->validity) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_SUMMARY_INVALID,
+ _("Folder was destroyed and recreated on server."));
+ return;
+ }
+
+ /* FIXME: find missing UIDs ? */
+ return;
+ }
+
+ if (!imap_summary->validity)
+ imap_summary->validity = validity;
+ else if (validity != imap_summary->validity) {
+ imap_summary->validity = validity;
+ camel_folder_summary_clear (folder->summary);
+ CAMEL_IMAP_FOLDER_LOCK (imap_folder, cache_lock);
+ camel_imap_message_cache_clear (imap_folder->cache);
+ CAMEL_IMAP_FOLDER_UNLOCK (imap_folder, cache_lock);
+ imap_folder->need_rescan = FALSE;
+ camel_imap_folder_changed (folder, exists, NULL, ex);
+ return;
+ }
+
+ /* If we've lost messages, we have to rescan everything */
+ if (exists < count)
+ imap_folder->need_rescan = TRUE;
+ else if (count != 0 && !imap_folder->need_rescan) {
+ CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
+
+ /* Similarly, if the UID of the highest message we
+ * know about has changed, then that indicates that
+ * messages have been both added and removed, so we
+ * have to rescan to find the removed ones. (We pass
+ * NULL for the folder since we know that this folder
+ * is selected, and we don't want camel_imap_command
+ * to worry about it.)
+ */
+ response = camel_imap_command (store, NULL, ex, "FETCH %d UID", count);
+ if (!response)
+ return;
+ uid = 0;
+ for (i = 0; i < response->untagged->len; i++) {
+ resp = response->untagged->pdata[i];
+ val = strtoul (resp + 2, &resp, 10);
+ if (val == 0)
+ continue;
+ if (!g_ascii_strcasecmp (resp, " EXISTS")) {
+ /* Another one?? */
+ exists = val;
+ continue;
+ }
+ if (uid != 0 || val != count || strncasecmp (resp, " FETCH (", 8) != 0)
+ continue;
+
+ fetch_data = parse_fetch_response (imap_folder, resp + 7);
+ uid = strtoul (g_datalist_get_data (&fetch_data, "UID"), NULL, 10);
+ g_datalist_clear (&fetch_data);
+ }
+ camel_imap_response_free_without_processing (store, response);
+
+ info = camel_folder_summary_index (folder->summary, count - 1);
+ val = strtoul (camel_message_info_uid (info), NULL, 10);
+ camel_folder_summary_info_free (folder->summary, info);
+ if (uid == 0 || uid != val)
+ imap_folder->need_rescan = TRUE;
+ }
+
+ /* Now rescan if we need to */
+ if (imap_folder->need_rescan) {
+ imap_rescan (folder, exists, ex);
+ return;
+ }
+
+ /* If we don't need to rescan completely, but new messages
+ * have been added, find out about them.
+ */
+ if (exists > count)
+ camel_imap_folder_changed (folder, exists, NULL, ex);
+
+ /* And we're done. */
+}
+
+static void
+imap_finalize (CamelObject *object)
+{
+ CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (object);
+
+ if (imap_folder->search)
+ camel_object_unref (CAMEL_OBJECT (imap_folder->search));
+ if (imap_folder->cache)
+ camel_object_unref (CAMEL_OBJECT (imap_folder->cache));
+
+#ifdef ENABLE_THREADS
+ e_mutex_destroy(imap_folder->priv->search_lock);
+ e_mutex_destroy(imap_folder->priv->cache_lock);
+#endif
+ g_free(imap_folder->priv);
+}
+
+static int
+imap_getv(CamelObject *object, CamelException *ex, CamelArgGetV *args)
+{
+ CamelFolder *folder = (CamelFolder *)object;
+ int i, count=0;
+ guint32 tag;
+
+ for (i=0;i<args->argc;i++) {
+ CamelArgGet *arg = &args->argv[i];
+
+ tag = arg->tag;
+
+ switch (tag & CAMEL_ARG_TAG) {
+ /* CamelObject args */
+ case CAMEL_OBJECT_ARG_DESCRIPTION:
+ if (folder->description == NULL) {
+ CamelURL *uri = ((CamelService *)folder->parent_store)->url;
+
+ /* what if the full name doesn't incclude /'s? does it matter? */
+ folder->description = g_strdup_printf("%s@%s:%s", uri->user, uri->host, folder->full_name);
+ }
+ *arg->ca_str = folder->description;
+ break;
+ default:
+ count++;
+ continue;
+ }
+
+ arg->tag = (tag & CAMEL_ARG_TYPE) | CAMEL_ARG_IGNORE;
+ }
+
+ if (count)
+ return ((CamelObjectClass *)parent_class)->getv(object, ex, args);
+
+ return 0;
+}
+
+static void
+imap_rename (CamelFolder *folder, const char *new)
+{
+ CamelImapFolder *imap_folder = (CamelImapFolder *)folder;
+ CamelImapStore *imap_store = (CamelImapStore *)folder->parent_store;
+ char *folder_dir, *summary_path, *state_file;
+ char *folders;
+
+ folders = g_strconcat (imap_store->storage_path, "/folders", NULL);
+ folder_dir = e_path_to_physical (folders, new);
+ g_free (folders);
+ summary_path = g_strdup_printf("%s/summary", folder_dir);
+
+ CAMEL_IMAP_FOLDER_LOCK (folder, cache_lock);
+ camel_imap_message_cache_set_path(imap_folder->cache, folder_dir);
+ CAMEL_IMAP_FOLDER_UNLOCK (folder, cache_lock);
+
+ camel_folder_summary_set_filename(folder->summary, summary_path);
+
+ state_file = g_strdup_printf ("%s/cmeta", folder_dir);
+ camel_object_set(folder, NULL, CAMEL_OBJECT_STATE_FILE, state_file, NULL);
+ g_free(state_file);
+
+ g_free(summary_path);
+ g_free(folder_dir);
+
+ ((CamelFolderClass *)disco_folder_class)->rename(folder, new);
+}
+
+static void
+imap_refresh_info (CamelFolder *folder, CamelException *ex)
+{
+ CamelImapStore *imap_store = CAMEL_IMAP_STORE (folder->parent_store);
+ CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
+ CamelImapResponse *response;
+
+ if (camel_disco_store_status (CAMEL_DISCO_STORE (imap_store)) == CAMEL_DISCO_STORE_OFFLINE)
+ return;
+
+ if (camel_folder_is_frozen (folder)) {
+ imap_folder->need_refresh = TRUE;
+ return;
+ }
+
+ /* If the folder isn't selected, select it (which will force
+ * a rescan if one is needed).
+ * Also, if this is the INBOX, some servers (cryus) wont tell
+ * us with a NOOP of new messages, so force a reselect which
+ * should do it. */
+ CAMEL_SERVICE_LOCK (imap_store, connect_lock);
+ if (imap_store->current_folder != folder
+ || g_ascii_strcasecmp(folder->full_name, "INBOX") == 0) {
+ response = camel_imap_command (imap_store, folder, ex, NULL);
+ if (response) {
+ camel_imap_folder_selected (folder, response, ex);
+ camel_imap_response_free (imap_store, response);
+ }
+ } else if (imap_folder->need_rescan) {
+ /* Otherwise, if we need a rescan, do it, and if not, just do
+ * a NOOP to give the server a chance to tell us about new
+ * messages.
+ */
+ imap_rescan (folder, camel_folder_summary_count (folder->summary), ex);
+ } else {
+#if 0
+ /* on some servers need to CHECKpoint INBOX to recieve new messages?? */
+ /* rfc2060 suggests this, but havent seen a server that requires it */
+ if (g_ascii_strcasecmp(folder->full_name, "INBOX") == 0) {
+ response = camel_imap_command (imap_store, folder, ex, "CHECK");
+ camel_imap_response_free (imap_store, response);
+ }
+#endif
+ response = camel_imap_command (imap_store, folder, ex, "NOOP");
+ camel_imap_response_free (imap_store, response);
+ }
+
+ CAMEL_SERVICE_UNLOCK (imap_store, connect_lock);
+}
+
+/* Called with the store's connect_lock locked */
+static void
+imap_rescan (CamelFolder *folder, int exists, CamelException *ex)
+{
+ CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
+ CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
+ struct {
+ char *uid;
+ guint32 flags;
+ } *new;
+ char *resp;
+ CamelImapResponseType type;
+ int i, seq, summary_len, summary_got;
+ CamelMessageInfo *info;
+ CamelImapMessageInfo *iinfo;
+ GArray *removed;
+ gboolean ok;
+ CamelFolderChangeInfo *changes = NULL;
+
+ CAMEL_SERVICE_ASSERT_LOCKED (store, connect_lock);
+ imap_folder->need_rescan = FALSE;
+
+ summary_len = camel_folder_summary_count (folder->summary);
+ if (summary_len == 0) {
+ if (exists)
+ camel_imap_folder_changed (folder, exists, NULL, ex);
+ return;
+ }
+
+ /* Check UIDs and flags of all messages we already know of. */
+ camel_operation_start (NULL, _("Scanning for changed messages"));
+ info = camel_folder_summary_index (folder->summary, summary_len - 1);
+ ok = camel_imap_command_start (store, folder, ex,
+ "UID FETCH 1:%s (FLAGS)",
+ camel_message_info_uid (info));
+ camel_folder_summary_info_free (folder->summary, info);
+ if (!ok) {
+ camel_operation_end (NULL);
+ return;
+ }
+
+ new = g_malloc0 (summary_len * sizeof (*new));
+ summary_got = 0;
+ while ((type = camel_imap_command_response (store, &resp, ex)) == CAMEL_IMAP_RESPONSE_UNTAGGED) {
+ GData *data;
+ char *uid;
+ guint32 flags;
+
+ data = parse_fetch_response (imap_folder, resp);
+ g_free (resp);
+ if (!data)
+ continue;
+
+ seq = GPOINTER_TO_INT (g_datalist_get_data (&data, "SEQUENCE"));
+ uid = g_datalist_get_data (&data, "UID");
+ flags = GPOINTER_TO_UINT (g_datalist_get_data (&data, "FLAGS"));
+
+ if (!uid || !seq || seq > summary_len) {
+ g_datalist_clear (&data);
+ continue;
+ }
+
+ camel_operation_progress (NULL, ++summary_got * 100 / summary_len);
+ new[seq - 1].uid = g_strdup (uid);
+ new[seq - 1].flags = flags;
+ g_datalist_clear (&data);
+ }
+
+ camel_operation_end (NULL);
+ if (type == CAMEL_IMAP_RESPONSE_ERROR) {
+ for (i = 0; i < summary_len && new[i].uid; i++)
+ g_free (new[i].uid);
+ g_free (new);
+ return;
+ }
+
+ /* Free the final tagged response */
+ g_free (resp);
+
+ /* If we find a UID in the summary that doesn't correspond to
+ * the UID in the folder, then either: (a) it's a real UID,
+ * but the message was deleted on the server, or (b) it's a
+ * fake UID, and needs to be removed from the summary in order
+ * to sync up with the server. So either way, we remove it
+ * from the summary.
+ */
+ removed = g_array_new (FALSE, FALSE, sizeof (int));
+ for (i = 0; i < summary_len && new[i].uid; i++) {
+ info = camel_folder_summary_index (folder->summary, i);
+ iinfo = (CamelImapMessageInfo *)info;
+
+ if (strcmp (camel_message_info_uid (info), new[i].uid) != 0) {
+ camel_folder_summary_info_free(folder->summary, info);
+ seq = i + 1;
+ g_array_append_val (removed, seq);
+ i--;
+ summary_len--;
+ continue;
+ }
+
+ /* Update summary flags */
+ if (new[i].flags != iinfo->server_flags) {
+ guint32 server_set, server_cleared;
+
+ server_set = new[i].flags & ~iinfo->server_flags;
+ server_cleared = iinfo->server_flags & ~new[i].flags;
+
+ info->flags = (info->flags | server_set) & ~server_cleared;
+ iinfo->server_flags = new[i].flags;
+
+ if (changes == NULL)
+ changes = camel_folder_change_info_new();
+ camel_folder_change_info_change_uid(changes, new[i].uid);
+ }
+
+ camel_folder_summary_info_free (folder->summary, info);
+ g_free (new[i].uid);
+ }
+
+ if (changes) {
+ camel_object_trigger_event(CAMEL_OBJECT (folder), "folder_changed", changes);
+ camel_folder_change_info_free(changes);
+ }
+
+ seq = i + 1;
+
+ /* Free remaining memory. */
+ while (i < summary_len && new[i].uid)
+ g_free (new[i++].uid);
+ g_free (new);
+
+ /* Remove any leftover cached summary messages. (Yes, we
+ * repeatedly add the same number to the removed array.
+ * See RFC2060 7.4.1)
+ */
+
+ for (i = seq; i <= summary_len; i++)
+ g_array_append_val (removed, seq);
+
+ /* And finally update the summary. */
+ camel_imap_folder_changed (folder, exists, removed, ex);
+ g_array_free (removed, TRUE);
+}
+
+/* the max number of chars that an unsigned 32-bit int can be is 10 chars plus 1 for a possible : */
+#define UID_SET_FULL(setlen, maxlen) (maxlen > 0 ? setlen + 11 >= maxlen : FALSE)
+
+/* Find all messages in @folder with flags matching @flags and @mask.
+ * If no messages match, returns %NULL. Otherwise, returns an array of
+ * CamelMessageInfo and sets *@set to a message set corresponding the
+ * UIDs of the matched messages (up to @UID_SET_LIMIT bytes). The
+ * caller must free the infos, the array, and the set string.
+ */
+static GPtrArray *
+get_matching (CamelFolder *folder, guint32 flags, guint32 mask, char **set)
+{
+ GPtrArray *matches;
+ CamelMessageInfo *info;
+ int i, max, range;
+ GString *gset;
+
+ matches = g_ptr_array_new ();
+ gset = g_string_new ("");
+ max = camel_folder_summary_count (folder->summary);
+ range = -1;
+ for (i = 0; i < max && !UID_SET_FULL (gset->len, UID_SET_LIMIT); i++) {
+ info = camel_folder_summary_index (folder->summary, i);
+ if (!info)
+ continue;
+ if ((info->flags & mask) != flags) {
+ camel_folder_summary_info_free (folder->summary, info);
+ if (range != -1) {
+ if (range != i - 1) {
+ info = matches->pdata[matches->len - 1];
+ g_string_append_printf (gset, ":%s", camel_message_info_uid (info));
+ }
+ range = -1;
+ }
+ continue;
+ }
+
+ g_ptr_array_add (matches, info);
+ if (range != -1)
+ continue;
+ range = i;
+ if (gset->len)
+ g_string_append_c (gset, ',');
+ g_string_append_printf (gset, "%s", camel_message_info_uid (info));
+ }
+
+ if (range != -1 && range != max - 1) {
+ info = matches->pdata[matches->len - 1];
+ g_string_append_printf (gset, ":%s", camel_message_info_uid (info));
+ }
+
+ if (matches->len) {
+ *set = gset->str;
+ g_string_free (gset, FALSE);
+ return matches;
+ } else {
+ *set = NULL;
+ g_string_free (gset, TRUE);
+ g_ptr_array_free (matches, TRUE);
+ return NULL;
+ }
+}
+
+static void
+imap_sync_offline (CamelFolder *folder, CamelException *ex)
+{
+ camel_folder_summary_save (folder->summary);
+}
+
+static void
+imap_sync_online (CamelFolder *folder, CamelException *ex)
+{
+ CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
+ CamelImapResponse *response = NULL;
+ CamelMessageInfo *info;
+ CamelException local_ex;
+ GPtrArray *matches;
+ char *set, *flaglist;
+ gboolean unset;
+ int i, j, max;
+
+ if (((CamelImapFolder *)folder)->read_only) {
+ imap_sync_offline (folder, ex);
+ return;
+ }
+
+ camel_exception_init (&local_ex);
+ CAMEL_SERVICE_LOCK (store, connect_lock);
+
+ /* Find a message with changed flags, find all of the other
+ * messages like it, sync them as a group, mark them as
+ * updated, and continue.
+ */
+ max = camel_folder_summary_count (folder->summary);
+ for (i = 0; i < max; i++) {
+ if (!(info = camel_folder_summary_index (folder->summary, i)))
+ continue;
+
+ if (!(info->flags & CAMEL_MESSAGE_FOLDER_FLAGGED)) {
+ camel_folder_summary_info_free (folder->summary, info);
+ continue;
+ }
+
+ /* Note: Cyrus is broken and will not accept an
+ empty-set of flags so... if this is true then we
+ want to unset the previously set flags.*/
+ unset = !(info->flags & folder->permanent_flags);
+
+ /* Note: get_matching() uses UID_SET_LIMIT to limit
+ the size of the uid-set string. We don't have to
+ loop here to flush all the matching uids because
+ they will be scooped up later by our parent loop (I
+ think?). -- Jeff */
+ matches = get_matching (folder, info->flags & (folder->permanent_flags | CAMEL_MESSAGE_FOLDER_FLAGGED),
+ folder->permanent_flags | CAMEL_MESSAGE_FOLDER_FLAGGED, &set);
+ camel_folder_summary_info_free (folder->summary, info);
+ if (matches == NULL)
+ continue;
+
+ /* FIXME: since we don't know the previously set flags,
+ if unset is TRUE then just unset all the flags? */
+ flaglist = imap_create_flag_list (unset ? folder->permanent_flags : info->flags & folder->permanent_flags);
+
+ /* Note: to `unset' flags, use -FLAGS.SILENT (<flag list>) */
+ response = camel_imap_command (store, folder, &local_ex,
+ "UID STORE %s %sFLAGS.SILENT %s",
+ set, unset ? "-" : "", flaglist);
+ g_free (set);
+ g_free (flaglist);
+
+ if (response)
+ camel_imap_response_free (store, response);
+
+ if (!camel_exception_is_set (&local_ex)) {
+ for (j = 0; j < matches->len; j++) {
+ info = matches->pdata[j];
+ info->flags &= ~CAMEL_MESSAGE_FOLDER_FLAGGED;
+ ((CamelImapMessageInfo *) info)->server_flags =
+ info->flags & CAMEL_IMAP_SERVER_FLAGS;
+ }
+ camel_folder_summary_touch (folder->summary);
+ }
+
+ for (j = 0; j < matches->len; j++) {
+ info = matches->pdata[j];
+ camel_folder_summary_info_free (folder->summary, info);
+ }
+ g_ptr_array_free (matches, TRUE);
+
+ /* We unlock here so that other threads can have a chance to grab the connect_lock */
+ CAMEL_SERVICE_UNLOCK (store, connect_lock);
+
+ /* check for an exception */
+ if (camel_exception_is_set (&local_ex)) {
+ camel_exception_xfer (ex, &local_ex);
+ return;
+ }
+
+ /* Re-lock the connect_lock */
+ CAMEL_SERVICE_LOCK (store, connect_lock);
+ }
+
+ /* Save the summary */
+ imap_sync_offline (folder, ex);
+
+ CAMEL_SERVICE_UNLOCK (store, connect_lock);
+}
+
+static int
+uid_compar (const void *va, const void *vb)
+{
+ const char **sa = (const char **)va, **sb = (const char **)vb;
+ unsigned long a, b;
+
+ a = strtoul (*sa, NULL, 10);
+ b = strtoul (*sb, NULL, 10);
+ if (a < b)
+ return -1;
+ else if (a == b)
+ return 0;
+ else
+ return 1;
+}
+
+static void
+imap_expunge_uids_offline (CamelFolder *folder, GPtrArray *uids, CamelException *ex)
+{
+ CamelFolderChangeInfo *changes;
+ int i;
+
+ qsort (uids->pdata, uids->len, sizeof (void *), uid_compar);
+
+ changes = camel_folder_change_info_new ();
+
+ for (i = 0; i < uids->len; i++) {
+ camel_folder_summary_remove_uid (folder->summary, uids->pdata[i]);
+ camel_folder_change_info_remove_uid (changes, uids->pdata[i]);
+ /* We intentionally don't remove it from the cache because
+ * the cached data may be useful in replaying a COPY later.
+ */
+ }
+ camel_folder_summary_save (folder->summary);
+
+ camel_disco_diary_log (CAMEL_DISCO_STORE (folder->parent_store)->diary,
+ CAMEL_DISCO_DIARY_FOLDER_EXPUNGE, folder, uids);
+
+ camel_object_trigger_event (CAMEL_OBJECT (folder), "folder_changed", changes);
+ camel_folder_change_info_free (changes);
+}
+
+static void
+imap_expunge_uids_online (CamelFolder *folder, GPtrArray *uids, CamelException *ex)
+{
+ CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
+ CamelImapResponse *response;
+ int uid = 0;
+ char *set;
+
+ CAMEL_SERVICE_LOCK (store, connect_lock);
+
+ if ((store->capabilities & IMAP_CAPABILITY_UIDPLUS) == 0) {
+ ((CamelFolderClass *)CAMEL_OBJECT_GET_CLASS(folder))->sync(folder, 0, ex);
+ if (camel_exception_is_set(ex)) {
+ CAMEL_SERVICE_UNLOCK (store, connect_lock);
+ return;
+ }
+ }
+
+ qsort (uids->pdata, uids->len, sizeof (void *), uid_compar);
+
+ while (uid < uids->len) {
+ set = imap_uid_array_to_set (folder->summary, uids, uid, UID_SET_LIMIT, &uid);
+ response = camel_imap_command (store, folder, ex,
+ "UID STORE %s +FLAGS.SILENT (\\Deleted)",
+ set);
+ if (response)
+ camel_imap_response_free (store, response);
+ if (camel_exception_is_set (ex)) {
+ CAMEL_SERVICE_UNLOCK (store, connect_lock);
+ g_free (set);
+ return;
+ }
+
+ if (store->capabilities & IMAP_CAPABILITY_UIDPLUS) {
+ response = camel_imap_command (store, folder, ex,
+ "UID EXPUNGE %s", set);
+ } else
+ response = camel_imap_command (store, folder, ex, "EXPUNGE");
+
+ if (response)
+ camel_imap_response_free (store, response);
+ }
+
+ CAMEL_SERVICE_UNLOCK (store, connect_lock);
+}
+
+static void
+imap_expunge_uids_resyncing (CamelFolder *folder, GPtrArray *uids, CamelException *ex)
+{
+ CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
+ CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
+ GPtrArray *keep_uids, *mark_uids;
+ CamelImapResponse *response;
+ char *result;
+
+ if (imap_folder->read_only)
+ return;
+
+ if (store->capabilities & IMAP_CAPABILITY_UIDPLUS) {
+ imap_expunge_uids_online (folder, uids, ex);
+ return;
+ }
+
+ /* If we don't have UID EXPUNGE we need to avoid expunging any
+ * of the wrong messages. So we search for deleted messages,
+ * and any that aren't in our to-expunge list get temporarily
+ * marked un-deleted.
+ */
+
+ CAMEL_SERVICE_LOCK (store, connect_lock);
+
+ ((CamelFolderClass *)CAMEL_OBJECT_GET_CLASS(folder))->sync(folder, 0, ex);
+ if (camel_exception_is_set(ex)) {
+ CAMEL_SERVICE_UNLOCK (store, connect_lock);
+ return;
+ }
+
+ response = camel_imap_command (store, folder, ex, "UID SEARCH DELETED");
+ if (!response) {
+ CAMEL_SERVICE_UNLOCK (store, connect_lock);
+ return;
+ }
+ result = camel_imap_response_extract (store, response, "SEARCH", ex);
+ if (!result) {
+ CAMEL_SERVICE_UNLOCK (store, connect_lock);
+ return;
+ }
+
+ if (result[8] == ' ') {
+ char *uid, *lasts = NULL;
+ unsigned long euid, kuid;
+ int ei, ki;
+
+ keep_uids = g_ptr_array_new ();
+ mark_uids = g_ptr_array_new ();
+
+ /* Parse SEARCH response */
+ for (uid = strtok_r (result + 9, " ", &lasts); uid; uid = strtok_r (NULL, " ", &lasts))
+ g_ptr_array_add (keep_uids, uid);
+ qsort (keep_uids->pdata, keep_uids->len,
+ sizeof (void *), uid_compar);
+
+ /* Fill in "mark_uids", empty out "keep_uids" as needed */
+ for (ei = ki = 0; ei < uids->len; ei++) {
+ euid = strtoul (uids->pdata[ei], NULL, 10);
+
+ for (kuid = 0; ki < keep_uids->len; ki++) {
+ kuid = strtoul (keep_uids->pdata[ki], NULL, 10);
+
+ if (kuid >= euid)
+ break;
+ }
+
+ if (euid == kuid)
+ g_ptr_array_remove_index (keep_uids, ki);
+ else
+ g_ptr_array_add (mark_uids, uids->pdata[ei]);
+ }
+ } else {
+ /* Empty SEARCH result, meaning nothing is marked deleted
+ * on server.
+ */
+
+ keep_uids = NULL;
+ mark_uids = uids;
+ }
+
+ /* Unmark messages to be kept */
+
+ if (keep_uids) {
+ char *uidset;
+ int uid = 0;
+
+ while (uid < keep_uids->len) {
+ uidset = imap_uid_array_to_set (folder->summary, keep_uids, uid, UID_SET_LIMIT, &uid);
+
+ response = camel_imap_command (store, folder, ex,
+ "UID STORE %s -FLAGS.SILENT (\\Deleted)",
+ uidset);
+
+ g_free (uidset);
+
+ if (!response) {
+ g_ptr_array_free (keep_uids, TRUE);
+ g_ptr_array_free (mark_uids, TRUE);
+ CAMEL_SERVICE_UNLOCK (store, connect_lock);
+ return;
+ }
+ camel_imap_response_free (store, response);
+ }
+ }
+
+ /* Mark any messages that still need to be marked */
+ if (mark_uids) {
+ char *uidset;
+ int uid = 0;
+
+ while (uid < mark_uids->len) {
+ uidset = imap_uid_array_to_set (folder->summary, mark_uids, uid, UID_SET_LIMIT, &uid);
+
+ response = camel_imap_command (store, folder, ex,
+ "UID STORE %s +FLAGS.SILENT (\\Deleted)",
+ uidset);
+
+ g_free (uidset);
+
+ if (!response) {
+ g_ptr_array_free (keep_uids, TRUE);
+ g_ptr_array_free (mark_uids, TRUE);
+ CAMEL_SERVICE_UNLOCK (store, connect_lock);
+ return;
+ }
+ camel_imap_response_free (store, response);
+ }
+
+ if (mark_uids != uids)
+ g_ptr_array_free (mark_uids, TRUE);
+ }
+
+ /* Do the actual expunging */
+ response = camel_imap_command (store, folder, ex, "EXPUNGE");
+ if (response)
+ camel_imap_response_free (store, response);
+
+ /* And fix the remaining messages if we mangled them */
+ if (keep_uids) {
+ char *uidset;
+ int uid = 0;
+
+ while (uid < keep_uids->len) {
+ uidset = imap_uid_array_to_set (folder->summary, keep_uids, uid, UID_SET_LIMIT, &uid);
+
+ /* Don't pass ex if it's already been set */
+ response = camel_imap_command (store, folder,
+ camel_exception_is_set (ex) ? NULL : ex,
+ "UID STORE %s +FLAGS.SILENT (\\Deleted)",
+ uidset);
+
+ g_free (uidset);
+ if (response)
+ camel_imap_response_free (store, response);
+ }
+
+ g_ptr_array_free (keep_uids, TRUE);
+ }
+
+ /* now we can free this, now that we're done with keep_uids */
+ g_free (result);
+
+ CAMEL_SERVICE_UNLOCK (store, connect_lock);
+}
+
+static gchar *
+get_temp_uid (void)
+{
+ gchar *res;
+
+ static int counter = 0;
+ G_LOCK_DEFINE_STATIC (lock);
+
+ G_LOCK (lock);
+ res = g_strdup_printf ("tempuid-%lx-%d",
+ (unsigned long) time (NULL),
+ counter++);
+ G_UNLOCK (lock);
+
+ return res;
+}
+
+static void
+imap_append_offline (CamelFolder *folder, CamelMimeMessage *message,
+ const CamelMessageInfo *info, char **appended_uid,
+ CamelException *ex)
+{
+ CamelImapStore *imap_store = CAMEL_IMAP_STORE (folder->parent_store);
+ CamelImapMessageCache *cache = CAMEL_IMAP_FOLDER (folder)->cache;
+ CamelFolderChangeInfo *changes;
+ char *uid;
+
+ uid = get_temp_uid ();
+
+ camel_imap_summary_add_offline (folder->summary, uid, message, info);
+ CAMEL_IMAP_FOLDER_LOCK (folder, cache_lock);
+ camel_imap_message_cache_insert_wrapper (cache, uid, "",
+ CAMEL_DATA_WRAPPER (message), ex);
+ CAMEL_IMAP_FOLDER_UNLOCK (folder, cache_lock);
+
+ changes = camel_folder_change_info_new ();
+ camel_folder_change_info_add_uid (changes, uid);
+ camel_object_trigger_event (CAMEL_OBJECT (folder), "folder_changed",
+ changes);
+ camel_folder_change_info_free (changes);
+
+ camel_disco_diary_log (CAMEL_DISCO_STORE (imap_store)->diary,
+ CAMEL_DISCO_DIARY_FOLDER_APPEND, folder, uid);
+ if (appended_uid)
+ *appended_uid = uid;
+ else
+ g_free (uid);
+}
+
+static CamelImapResponse *
+do_append (CamelFolder *folder, CamelMimeMessage *message,
+ const CamelMessageInfo *info, char **uid,
+ CamelException *ex)
+{
+ CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
+ CamelImapResponse *response, *response2;
+ CamelStream *memstream;
+ CamelMimeFilter *crlf_filter;
+ CamelStreamFilter *streamfilter;
+ GByteArray *ba;
+ char *flagstr, *end;
+
+ /* create flag string param */
+ if (info && info->flags)
+ flagstr = imap_create_flag_list (info->flags);
+ else
+ flagstr = NULL;
+
+ /* encode any 8bit parts so we avoid sending embedded nul-chars and such */
+ camel_mime_message_encode_8bit_parts (message);
+
+ /* FIXME: We could avoid this if we knew how big the message was. */
+ memstream = camel_stream_mem_new ();
+ ba = g_byte_array_new ();
+ camel_stream_mem_set_byte_array (CAMEL_STREAM_MEM (memstream), ba);
+
+ streamfilter = camel_stream_filter_new_with_stream (memstream);
+ crlf_filter = camel_mime_filter_crlf_new (CAMEL_MIME_FILTER_CRLF_ENCODE,
+ CAMEL_MIME_FILTER_CRLF_MODE_CRLF_ONLY);
+ camel_stream_filter_add (streamfilter, crlf_filter);
+ camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (message),
+ CAMEL_STREAM (streamfilter));
+ camel_object_unref (CAMEL_OBJECT (streamfilter));
+ camel_object_unref (CAMEL_OBJECT (crlf_filter));
+ camel_object_unref (CAMEL_OBJECT (memstream));
+
+ response = camel_imap_command (store, NULL, ex, "APPEND %F%s%s {%d}",
+ folder->full_name, flagstr ? " " : "",
+ flagstr ? flagstr : "", ba->len);
+ g_free (flagstr);
+
+ if (!response) {
+ g_byte_array_free (ba, TRUE);
+ return NULL;
+ }
+
+ if (*response->status != '+') {
+ camel_imap_response_free (store, response);
+ g_byte_array_free (ba, TRUE);
+ return NULL;
+ }
+
+ /* send the rest of our data - the mime message */
+ response2 = camel_imap_command_continuation (store, ba->data, ba->len, ex);
+ g_byte_array_free (ba, TRUE);
+
+ /* free it only after message is sent. This may cause more FETCHes. */
+ camel_imap_response_free (store, response);
+ if (!response2)
+ return response2;
+
+ if (store->capabilities & IMAP_CAPABILITY_UIDPLUS) {
+ *uid = camel_strstrcase (response2->status, "[APPENDUID ");
+ if (*uid)
+ *uid = strchr (*uid + 11, ' ');
+ if (*uid) {
+ *uid = g_strndup (*uid + 1, strcspn (*uid + 1, "]"));
+ /* Make sure it's a number */
+ if (strtoul (*uid, &end, 10) == 0 || *end) {
+ g_free (*uid);
+ *uid = NULL;
+ }
+ }
+ } else
+ *uid = NULL;
+
+ return response2;
+}
+
+static void
+imap_append_online (CamelFolder *folder, CamelMimeMessage *message,
+ const CamelMessageInfo *info, char **appended_uid,
+ CamelException *ex)
+{
+ CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
+ CamelImapResponse *response;
+ char *uid;
+ int count;
+
+ count = camel_folder_summary_count (folder->summary);
+ response = do_append (folder, message, info, &uid, ex);
+ if (!response)
+ return;
+
+ if (uid) {
+ /* Cache first, since freeing response may trigger a
+ * summary update that will want this information.
+ */
+ CAMEL_IMAP_FOLDER_LOCK (folder, cache_lock);
+ camel_imap_message_cache_insert_wrapper (
+ CAMEL_IMAP_FOLDER (folder)->cache, uid,
+ "", CAMEL_DATA_WRAPPER (message), ex);
+ CAMEL_IMAP_FOLDER_UNLOCK (folder, cache_lock);
+ if (appended_uid)
+ *appended_uid = uid;
+ else
+ g_free (uid);
+ } else if (appended_uid)
+ *appended_uid = NULL;
+
+ camel_imap_response_free (store, response);
+
+ /* Make sure a "folder_changed" is emitted. */
+ CAMEL_SERVICE_LOCK (store, connect_lock);
+ if (store->current_folder != folder ||
+ camel_folder_summary_count (folder->summary) == count)
+ imap_refresh_info (folder, ex);
+ CAMEL_SERVICE_UNLOCK (store, connect_lock);
+}
+
+static void
+imap_append_resyncing (CamelFolder *folder, CamelMimeMessage *message,
+ const CamelMessageInfo *info, char **appended_uid,
+ CamelException *ex)
+{
+ CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
+ CamelImapResponse *response;
+ char *uid;
+
+ response = do_append (folder, message, info, &uid, ex);
+ if (!response)
+ return;
+
+ if (uid) {
+ CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
+ const char *olduid = camel_message_info_uid (info);
+
+ CAMEL_IMAP_FOLDER_LOCK (imap_folder, cache_lock);
+ camel_imap_message_cache_copy (imap_folder->cache, olduid,
+ imap_folder->cache, uid, ex);
+ CAMEL_IMAP_FOLDER_UNLOCK (imap_folder, cache_lock);
+
+ if (appended_uid)
+ *appended_uid = uid;
+ else
+ g_free (uid);
+ } else if (appended_uid)
+ *appended_uid = NULL;
+
+ camel_imap_response_free (store, response);
+}
+
+
+static void
+imap_transfer_offline (CamelFolder *source, GPtrArray *uids,
+ CamelFolder *dest, GPtrArray **transferred_uids,
+ gboolean delete_originals, CamelException *ex)
+{
+ CamelImapStore *store = CAMEL_IMAP_STORE (source->parent_store);
+ CamelImapMessageCache *sc = CAMEL_IMAP_FOLDER (source)->cache;
+ CamelImapMessageCache *dc = CAMEL_IMAP_FOLDER (dest)->cache;
+ CamelFolderChangeInfo *changes;
+ CamelMimeMessage *message;
+ CamelMessageInfo *mi;
+ char *uid, *destuid;
+ int i;
+
+ /* We grab the store's command lock first, and then grab the
+ * source and destination cache_locks. This way we can't
+ * deadlock in the case where we're simultaneously also trying
+ * to copy messages in the other direction from another thread.
+ */
+ CAMEL_SERVICE_LOCK (store, connect_lock);
+ CAMEL_IMAP_FOLDER_LOCK (source, cache_lock);
+ CAMEL_IMAP_FOLDER_LOCK (dest, cache_lock);
+ CAMEL_SERVICE_UNLOCK (store, connect_lock);
+
+ if (transferred_uids) {
+ *transferred_uids = g_ptr_array_new ();
+ g_ptr_array_set_size (*transferred_uids, uids->len);
+ }
+
+ changes = camel_folder_change_info_new ();
+
+ for (i = 0; i < uids->len; i++) {
+ uid = uids->pdata[i];
+
+ destuid = get_temp_uid ();
+
+ mi = camel_folder_summary_uid (source->summary, uid);
+ g_return_if_fail (mi != NULL);
+
+ message = camel_folder_get_message (source, uid, NULL);
+
+ if (message) {
+ camel_imap_summary_add_offline (dest->summary, destuid, message, mi);
+ camel_object_unref (CAMEL_OBJECT (message));
+ } else
+ camel_imap_summary_add_offline_uncached (dest->summary, destuid, mi);
+
+ camel_imap_message_cache_copy (sc, uid, dc, destuid, ex);
+ camel_folder_summary_info_free (source->summary, mi);
+
+ camel_folder_change_info_add_uid (changes, destuid);
+ if (transferred_uids)
+ (*transferred_uids)->pdata[i] = destuid;
+ else
+ g_free (destuid);
+
+ if (delete_originals)
+ camel_folder_delete_message (source, uid);
+ }
+
+ CAMEL_IMAP_FOLDER_UNLOCK (dest, cache_lock);
+ CAMEL_IMAP_FOLDER_UNLOCK (source, cache_lock);
+
+ camel_object_trigger_event (CAMEL_OBJECT (dest), "folder_changed", changes);
+ camel_folder_change_info_free (changes);
+
+ camel_disco_diary_log (CAMEL_DISCO_STORE (store)->diary,
+ CAMEL_DISCO_DIARY_FOLDER_TRANSFER,
+ source, dest, uids, delete_originals);
+}
+
+static void
+handle_copyuid (CamelImapResponse *response, CamelFolder *source,
+ CamelFolder *destination)
+{
+ CamelImapMessageCache *scache = CAMEL_IMAP_FOLDER (source)->cache;
+ CamelImapMessageCache *dcache = CAMEL_IMAP_FOLDER (destination)->cache;
+ char *validity, *srcset, *destset;
+ GPtrArray *src, *dest;
+ int i;
+
+ validity = camel_strstrcase (response->status, "[COPYUID ");
+ if (!validity)
+ return;
+ validity += 9;
+ if (strtoul (validity, NULL, 10) !=
+ CAMEL_IMAP_SUMMARY (destination->summary)->validity)
+ return;
+
+ srcset = strchr (validity, ' ');
+ if (!srcset++)
+ goto lose;
+ destset = strchr (srcset, ' ');
+ if (!destset++)
+ goto lose;
+
+ src = imap_uid_set_to_array (source->summary, srcset);
+ dest = imap_uid_set_to_array (destination->summary, destset);
+
+ if (src && dest && src->len == dest->len) {
+ /* We don't have to worry about deadlocking on the
+ * cache locks here, because we've got the store's
+ * command lock too, so no one else could be here.
+ */
+ CAMEL_IMAP_FOLDER_LOCK (source, cache_lock);
+ CAMEL_IMAP_FOLDER_LOCK (destination, cache_lock);
+ for (i = 0; i < src->len; i++) {
+ camel_imap_message_cache_copy (scache, src->pdata[i],
+ dcache, dest->pdata[i],
+ NULL);
+ }
+ CAMEL_IMAP_FOLDER_UNLOCK (source, cache_lock);
+ CAMEL_IMAP_FOLDER_UNLOCK (destination, cache_lock);
+
+ imap_uid_array_free (src);
+ imap_uid_array_free (dest);
+ return;
+ }
+
+ imap_uid_array_free (src);
+ imap_uid_array_free (dest);
+ lose:
+ g_warning ("Bad COPYUID response from server");
+}
+
+static void
+do_copy (CamelFolder *source, GPtrArray *uids,
+ CamelFolder *destination, CamelException *ex)
+{
+ CamelImapStore *store = CAMEL_IMAP_STORE (source->parent_store);
+ CamelImapResponse *response;
+ char *uidset;
+ int uid = 0;
+
+ while (uid < uids->len && !camel_exception_is_set (ex)) {
+ uidset = imap_uid_array_to_set (source->summary, uids, uid, UID_SET_LIMIT, &uid);
+
+ response = camel_imap_command (store, source, ex, "UID COPY %s %F",
+ uidset, destination->full_name);
+
+ g_free (uidset);
+
+ if (response && (store->capabilities & IMAP_CAPABILITY_UIDPLUS))
+ handle_copyuid (response, source, destination);
+
+ camel_imap_response_free (store, response);
+ }
+}
+
+static void
+imap_transfer_online (CamelFolder *source, GPtrArray *uids,
+ CamelFolder *dest, GPtrArray **transferred_uids,
+ gboolean delete_originals, CamelException *ex)
+{
+ CamelImapStore *store = CAMEL_IMAP_STORE (source->parent_store);
+ int count, i;
+
+ /* Sync message flags if needed. */
+ imap_sync_online (source, ex);
+ if (camel_exception_is_set (ex))
+ return;
+
+ count = camel_folder_summary_count (dest->summary);
+
+ qsort (uids->pdata, uids->len, sizeof (void *), uid_compar);
+
+ /* Now copy the messages */
+ do_copy (source, uids, dest, ex);
+ if (camel_exception_is_set (ex))
+ return;
+
+ /* Make the destination notice its new messages */
+ if (store->current_folder != dest ||
+ camel_folder_summary_count (dest->summary) == count)
+ camel_folder_refresh_info (dest, ex);
+
+ if (delete_originals) {
+ for (i = 0; i < uids->len; i++)
+ camel_folder_delete_message (source, uids->pdata[i]);
+ }
+
+ /* FIXME */
+ if (transferred_uids)
+ *transferred_uids = NULL;
+}
+
+static void
+imap_transfer_resyncing (CamelFolder *source, GPtrArray *uids,
+ CamelFolder *dest, GPtrArray **transferred_uids,
+ gboolean delete_originals, CamelException *ex)
+{
+ CamelDiscoDiary *diary = CAMEL_DISCO_STORE (source->parent_store)->diary;
+ GPtrArray *realuids;
+ int first, i;
+ const char *uid;
+ CamelMimeMessage *message;
+ CamelMessageInfo *info;
+
+ qsort (uids->pdata, uids->len, sizeof (void *), uid_compar);
+
+ /* This is trickier than append_resyncing, because some of
+ * the messages we are copying may have been copied or
+ * appended into @source while we were offline, in which case
+ * if we don't have UIDPLUS, we won't know their real UIDs,
+ * so we'll have to append them rather than copying.
+ */
+
+ realuids = g_ptr_array_new ();
+
+ i = 0;
+ while (i < uids->len) {
+ /* Skip past real UIDs */
+ for (first = i; i < uids->len; i++) {
+ uid = uids->pdata[i];
+
+ if (!isdigit ((unsigned char)*uid)) {
+ uid = camel_disco_diary_uidmap_lookup (diary, uid);
+ if (!uid)
+ break;
+ }
+ g_ptr_array_add (realuids, (char *)uid);
+
+ if (delete_originals)
+ camel_folder_delete_message (source, uid);
+ }
+
+ /* If we saw any real UIDs, do a COPY */
+ if (i != first) {
+ do_copy (source, realuids, dest, ex);
+ g_ptr_array_set_size (realuids, 0);
+ if (i == uids->len || camel_exception_is_set (ex))
+ break;
+ }
+
+ /* Deal with fake UIDs */
+ while (i < uids->len &&
+ !isdigit (*(unsigned char *)(uids->pdata[i])) &&
+ !camel_exception_is_set (ex)) {
+ uid = uids->pdata[i];
+ message = camel_folder_get_message (source, uid, NULL);
+ if (!message) {
+ /* Message must have been expunged */
+ continue;
+ }
+ info = camel_folder_get_message_info (source, uid);
+ g_return_if_fail (info != NULL);
+
+ imap_append_online (dest, message, info, NULL, ex);
+ camel_folder_free_message_info (source, info);
+ camel_object_unref (CAMEL_OBJECT (message));
+ if (delete_originals)
+ camel_folder_delete_message (source, uid);
+ i++;
+ }
+ }
+
+ g_ptr_array_free (realuids, FALSE);
+
+ /* FIXME */
+ if (transferred_uids)
+ *transferred_uids = NULL;
+}
+
+static GPtrArray *
+imap_search_by_expression (CamelFolder *folder, const char *expression, CamelException *ex)
+{
+ CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
+ GPtrArray *matches;
+
+ /* we could get around this by creating a new search object each time,
+ but i doubt its worth it since any long operation would lock the
+ command channel too */
+ CAMEL_IMAP_FOLDER_LOCK(folder, search_lock);
+
+ camel_folder_search_set_folder (imap_folder->search, folder);
+ matches = camel_folder_search_search(imap_folder->search, expression, NULL, ex);
+
+ CAMEL_IMAP_FOLDER_UNLOCK(folder, search_lock);
+
+ return matches;
+}
+
+static GPtrArray *
+imap_search_by_uids(CamelFolder *folder, const char *expression, GPtrArray *uids, CamelException *ex)
+{
+ CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER(folder);
+ GPtrArray *matches;
+
+ if (uids->len == 0)
+ return g_ptr_array_new();
+
+ CAMEL_IMAP_FOLDER_LOCK(folder, search_lock);
+
+ camel_folder_search_set_folder(imap_folder->search, folder);
+ matches = camel_folder_search_search(imap_folder->search, expression, uids, ex);
+
+ CAMEL_IMAP_FOLDER_UNLOCK(folder, search_lock);
+
+ return matches;
+}
+
+static void
+imap_search_free (CamelFolder *folder, GPtrArray *uids)
+{
+ CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
+
+ g_return_if_fail (imap_folder->search);
+
+ CAMEL_IMAP_FOLDER_LOCK(folder, search_lock);
+
+ camel_folder_search_free_result (imap_folder->search, uids);
+
+ CAMEL_IMAP_FOLDER_UNLOCK(folder, search_lock);
+}
+
+static CamelMimeMessage *get_message (CamelImapFolder *imap_folder,
+ const char *uid,
+ CamelMessageContentInfo *ci,
+ CamelException *ex);
+
+struct _part_spec_stack {
+ struct _part_spec_stack *parent;
+ int part;
+};
+
+static void
+part_spec_push (struct _part_spec_stack **stack, int part)
+{
+ struct _part_spec_stack *node;
+
+ node = g_new (struct _part_spec_stack, 1);
+ node->parent = *stack;
+ node->part = part;
+
+ *stack = node;
+}
+
+static int
+part_spec_pop (struct _part_spec_stack **stack)
+{
+ struct _part_spec_stack *node;
+ int part;
+
+ g_return_val_if_fail (*stack != NULL, 0);
+
+ node = *stack;
+ *stack = node->parent;
+
+ part = node->part;
+ g_free (node);
+
+ return part;
+}
+
+static char *
+content_info_get_part_spec (CamelMessageContentInfo *ci)
+{
+ struct _part_spec_stack *stack = NULL;
+ CamelMessageContentInfo *node;
+ char *part_spec, *buf;
+ size_t len = 1;
+ int part;
+
+ node = ci;
+ while (node->parent) {
+ CamelMessageContentInfo *child;
+
+ /* FIXME: is this only supposed to apply if 'node' is a multipart? */
+ if (node->parent->parent && camel_content_type_is (node->parent->type, "message", "*")) {
+ node = node->parent;
+ continue;
+ }
+
+ child = node->parent->childs;
+ for (part = 1; child; part++) {
+ if (child == node)
+ break;
+
+ child = child->next;
+ }
+
+ part_spec_push (&stack, part);
+
+ len += 2;
+ while ((part = part / 10))
+ len++;
+
+ node = node->parent;
+ }
+
+ buf = part_spec = g_malloc (len);
+ part_spec[0] = '\0';
+
+ while (stack) {
+ part = part_spec_pop (&stack);
+ buf += sprintf (buf, "%d%s", part, stack ? "." : "");
+ }
+
+ return part_spec;
+}
+
+/* Fetch the contents of the MIME part indicated by @ci, which is part
+ * of message @uid in @folder.
+ */
+static CamelDataWrapper *
+get_content (CamelImapFolder *imap_folder, const char *uid,
+ CamelMimePart *part, CamelMessageContentInfo *ci,
+ int frommsg,
+ CamelException *ex)
+{
+ CamelDataWrapper *content = NULL;
+ CamelStream *stream;
+ char *part_spec;
+
+ part_spec = content_info_get_part_spec (ci);
+
+ d(printf("get content '%s' '%s' (frommsg = %d)\n", part_spec, camel_content_type_format(ci->type), frommsg));
+
+ /* There are three cases: multipart/signed, multipart, message/rfc822, and "other" */
+ if (camel_content_type_is (ci->type, "multipart", "signed")) {
+ CamelMultipartSigned *body_mp;
+ char *spec;
+ int ret;
+
+ /* Note: because we get the content parts uninterpreted anyway, we could potentially
+ just use the normalmultipart code, except that multipart/signed wont let you yet! */
+
+ body_mp = camel_multipart_signed_new ();
+ /* need to set this so it grabs the boundary and other info about the signed type */
+ /* we assume that part->content_type is more accurate/full than ci->type */
+ camel_data_wrapper_set_mime_type_field (CAMEL_DATA_WRAPPER (body_mp), CAMEL_DATA_WRAPPER (part)->mime_type);
+
+ spec = g_alloca(strlen(part_spec) + 6);
+ if (frommsg)
+ sprintf(spec, part_spec[0] ? "%s.TEXT" : "TEXT", part_spec);
+ else
+ strcpy(spec, part_spec);
+ g_free(part_spec);
+
+ stream = camel_imap_folder_fetch_data (imap_folder, uid, spec, FALSE, ex);
+ if (stream) {
+ ret = camel_data_wrapper_construct_from_stream (CAMEL_DATA_WRAPPER (body_mp), stream);
+ camel_object_unref (CAMEL_OBJECT (stream));
+ if (ret == -1) {
+ camel_object_unref ((CamelObject *) body_mp);
+ return NULL;
+ }
+ }
+
+ return (CamelDataWrapper *) body_mp;
+ } else if (camel_content_type_is (ci->type, "multipart", "*")) {
+ CamelMultipart *body_mp;
+ char *child_spec;
+ int speclen, num, isdigest;
+
+ if (camel_content_type_is (ci->type, "multipart", "encrypted"))
+ body_mp = (CamelMultipart *) camel_multipart_encrypted_new ();
+ else
+ body_mp = camel_multipart_new ();
+
+ /* need to set this so it grabs the boundary and other info about the multipart */
+ /* we assume that part->content_type is more accurate/full than ci->type */
+ camel_data_wrapper_set_mime_type_field (CAMEL_DATA_WRAPPER (body_mp), CAMEL_DATA_WRAPPER (part)->mime_type);
+ isdigest = camel_content_type_is(((CamelDataWrapper *)part)->mime_type, "multipart", "digest");
+
+ speclen = strlen (part_spec);
+ child_spec = g_malloc (speclen + 17); /* dot + 10 + dot + MIME + nul */
+ memcpy (child_spec, part_spec, speclen);
+ if (speclen > 0)
+ child_spec[speclen++] = '.';
+ g_free (part_spec);
+
+ ci = ci->childs;
+ num = 1;
+ while (ci) {
+ sprintf (child_spec + speclen, "%d.MIME", num++);
+ stream = camel_imap_folder_fetch_data (imap_folder, uid, child_spec, FALSE, ex);
+ if (stream) {
+ int ret;
+
+ part = camel_mime_part_new ();
+ ret = camel_data_wrapper_construct_from_stream (CAMEL_DATA_WRAPPER (part), stream);
+ camel_object_unref (CAMEL_OBJECT (stream));
+ if (ret == -1) {
+ camel_object_unref (CAMEL_OBJECT (part));
+ camel_object_unref (CAMEL_OBJECT (body_mp));
+ g_free (child_spec);
+ return NULL;
+ }
+
+ content = get_content (imap_folder, uid, part, ci, FALSE, ex);
+ }
+
+ if (!stream || !content) {
+ camel_object_unref (CAMEL_OBJECT (body_mp));
+ g_free (child_spec);
+ return NULL;
+ }
+
+ if (camel_debug("imap:folder")) {
+ char *ct = camel_content_type_format(camel_mime_part_get_content_type((CamelMimePart *)part));
+ char *ct2 = camel_content_type_format(ci->type);
+
+ printf("Setting part content type to '%s' contentinfo type is '%s'\n", ct, ct2);
+ g_free(ct);
+ g_free(ct2);
+ }
+
+ /* if we had no content-type header on a multipart/digest sub-part, then we need to
+ treat it as message/rfc822 instead */
+ if (isdigest && camel_medium_get_header((CamelMedium *)part, "content-type") == NULL) {
+ CamelContentType *ct = camel_content_type_new("message", "rfc822");
+
+ camel_data_wrapper_set_mime_type_field(content, ct);
+ camel_content_type_unref(ct);
+ } else {
+ camel_data_wrapper_set_mime_type_field(content, camel_mime_part_get_content_type(part));
+ }
+
+ camel_medium_set_content_object (CAMEL_MEDIUM (part), content);
+ camel_object_unref(content);
+
+ camel_multipart_add_part (body_mp, part);
+ camel_object_unref(part);
+
+ ci = ci->next;
+ }
+
+ g_free (child_spec);
+
+ return (CamelDataWrapper *) body_mp;
+ } else if (camel_content_type_is (ci->type, "message", "rfc822")) {
+ content = (CamelDataWrapper *) get_message (imap_folder, uid, ci->childs, ex);
+ g_free (part_spec);
+ return content;
+ } else {
+ CamelTransferEncoding enc;
+ char *spec;
+
+ /* NB: we need this differently to multipart/signed case above on purpose */
+ spec = g_alloca(strlen(part_spec) + 6);
+ if (frommsg)
+ sprintf(spec, part_spec[0] ? "%s.1" : "1", part_spec);
+ else
+ strcpy(spec, part_spec[0]?part_spec:"1");
+
+ enc = ci->encoding?camel_transfer_encoding_from_string(ci->encoding):CAMEL_TRANSFER_ENCODING_DEFAULT;
+ content = camel_imap_wrapper_new (imap_folder, ci->type, enc, uid, spec, part);
+ g_free (part_spec);
+ return content;
+ }
+}
+
+static CamelMimeMessage *
+get_message (CamelImapFolder *imap_folder, const char *uid,
+ CamelMessageContentInfo *ci,
+ CamelException *ex)
+{
+ CamelImapStore *store = CAMEL_IMAP_STORE (CAMEL_FOLDER (imap_folder)->parent_store);
+ CamelDataWrapper *content;
+ CamelMimeMessage *msg;
+ CamelStream *stream;
+ char *section_text, *part_spec;
+ int ret;
+
+ part_spec = content_info_get_part_spec(ci);
+ d(printf("get message '%s'\n", part_spec));
+ section_text = g_strdup_printf ("%s%s%s", part_spec, *part_spec ? "." : "",
+ store->server_level >= IMAP_LEVEL_IMAP4REV1 ? "HEADER" : "0");
+
+ stream = camel_imap_folder_fetch_data (imap_folder, uid, section_text, FALSE, ex);
+ g_free (section_text);
+ g_free(part_spec);
+ if (!stream)
+ return NULL;
+
+ msg = camel_mime_message_new ();
+ ret = camel_data_wrapper_construct_from_stream (CAMEL_DATA_WRAPPER (msg), stream);
+ camel_object_unref (CAMEL_OBJECT (stream));
+ if (ret == -1) {
+ camel_object_unref (CAMEL_OBJECT (msg));
+ return NULL;
+ }
+
+ content = get_content (imap_folder, uid, CAMEL_MIME_PART (msg), ci, TRUE, ex);
+ if (!content) {
+ camel_object_unref (CAMEL_OBJECT (msg));
+ return NULL;
+ }
+
+ if (camel_debug("imap:folder")) {
+ char *ct = camel_content_type_format(camel_mime_part_get_content_type((CamelMimePart *)msg));
+ char *ct2 = camel_content_type_format(ci->type);
+
+ printf("Setting message content type to '%s' contentinfo type is '%s'\n", ct, ct2);
+ g_free(ct);
+ g_free(ct2);
+ }
+
+ camel_data_wrapper_set_mime_type_field(content, camel_mime_part_get_content_type((CamelMimePart *)msg));
+ camel_medium_set_content_object (CAMEL_MEDIUM (msg), content);
+ camel_object_unref (CAMEL_OBJECT (content));
+
+ return msg;
+}
+
+#define IMAP_SMALL_BODY_SIZE 5120
+
+static CamelMimeMessage *
+get_message_simple (CamelImapFolder *imap_folder, const char *uid,
+ CamelStream *stream, CamelException *ex)
+{
+ CamelMimeMessage *msg;
+ int ret;
+
+ if (!stream) {
+ stream = camel_imap_folder_fetch_data (imap_folder, uid, "",
+ FALSE, ex);
+ if (!stream)
+ return NULL;
+ }
+
+ msg = camel_mime_message_new ();
+ ret = camel_data_wrapper_construct_from_stream (CAMEL_DATA_WRAPPER (msg),
+ stream);
+ camel_object_unref (CAMEL_OBJECT (stream));
+ if (ret == -1) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ _("Unable to retrieve message: %s"),
+ g_strerror (errno));
+ camel_object_unref (CAMEL_OBJECT (msg));
+ return NULL;
+ }
+
+ return msg;
+}
+
+static gboolean
+content_info_incomplete (CamelMessageContentInfo *ci)
+{
+ if (!ci->type)
+ return TRUE;
+
+ if (camel_content_type_is (ci->type, "multipart", "*")
+ || camel_content_type_is (ci->type, "message", "rfc822")) {
+ if (!ci->childs)
+ return TRUE;
+ for (ci = ci->childs;ci;ci=ci->next)
+ if (content_info_incomplete(ci))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static CamelMimeMessage *
+imap_get_message (CamelFolder *folder, const char *uid, CamelException *ex)
+{
+ CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
+ CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
+ CamelMessageInfo *mi;
+ CamelMimeMessage *msg = NULL;
+ CamelStream *stream = NULL;
+ int retry;
+
+ mi = camel_folder_summary_uid (folder->summary, uid);
+ if (mi == NULL) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_FOLDER_INVALID_UID,
+ _("Cannot get message: %s\n %s"), uid, _("No such message"));
+ return NULL;
+ }
+
+ /* If its cached in full, just get it as is, this is only a shortcut,
+ since we get stuff from the cache anyway. It affects a busted connection though. */
+ if ( (stream = camel_imap_folder_fetch_data(imap_folder, uid, "", TRUE, NULL))
+ && (msg = get_message_simple(imap_folder, uid, stream, ex)))
+ goto done;
+
+ /* All this mess is so we silently retry a fetch if we fail with
+ service_unavailable, without an (equivalent) mess of gotos */
+ retry = 0;
+ do {
+ retry++;
+ camel_exception_clear(ex);
+
+ /* If we are online, make sure we're also connected */
+ if (camel_disco_store_status((CamelDiscoStore *)store) == CAMEL_DISCO_STORE_ONLINE
+ && !camel_imap_store_connected(store, ex))
+ goto fail;
+
+ /* If the message is small or only 1 part, or server doesn't do 4v1 (properly) fetch it in one piece. */
+ if (store->server_level < IMAP_LEVEL_IMAP4REV1
+ || store->braindamaged
+ || mi->size < IMAP_SMALL_BODY_SIZE
+ || (!content_info_incomplete(mi->content) && !mi->content->childs)) {
+ msg = get_message_simple (imap_folder, uid, NULL, ex);
+ } else {
+ if (content_info_incomplete (mi->content)) {
+ /* For larger messages, fetch the structure and build a message
+ * with offline parts. (We check mi->content->type rather than
+ * mi->content because camel_folder_summary_info_new always creates
+ * an empty content struct.)
+ */
+ CamelImapResponse *response;
+ GData *fetch_data = NULL;
+ char *body, *found_uid;
+ int i;
+
+ if (camel_disco_store_status (CAMEL_DISCO_STORE (store)) == CAMEL_DISCO_STORE_OFFLINE) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ _("This message is not currently available"));
+ goto fail;
+ }
+
+ response = camel_imap_command (store, folder, ex, "UID FETCH %s BODY", uid);
+ if (response) {
+ for (i = 0, body = NULL; i < response->untagged->len; i++) {
+ fetch_data = parse_fetch_response (imap_folder, response->untagged->pdata[i]);
+ if (fetch_data) {
+ found_uid = g_datalist_get_data (&fetch_data, "UID");
+ body = g_datalist_get_data (&fetch_data, "BODY");
+ if (found_uid && body && !strcmp (found_uid, uid))
+ break;
+ g_datalist_clear (&fetch_data);
+ fetch_data = NULL;
+ body = NULL;
+ }
+ }
+
+ if (body)
+ imap_parse_body ((const char **) &body, folder, mi->content);
+
+ if (fetch_data)
+ g_datalist_clear (&fetch_data);
+
+ camel_imap_response_free (store, response);
+ }
+ }
+
+ if (camel_debug_start("imap:folder")) {
+ printf("Folder get message '%s' folder info ->\n", uid);
+ camel_message_info_dump(mi);
+ camel_debug_end();
+ }
+
+ /* FETCH returned OK, but we didn't parse a BODY
+ * response. Courier will return invalid BODY
+ * responses for invalidly MIMEd messages, so
+ * fall back to fetching the entire thing and
+ * let the mailer's "bad MIME" code handle it.
+ */
+ if (content_info_incomplete (mi->content))
+ msg = get_message_simple (imap_folder, uid, NULL, ex);
+ else
+ msg = get_message (imap_folder, uid, mi->content, ex);
+ }
+ } while (msg == NULL
+ && retry < 2
+ && camel_exception_get_id(ex) == CAMEL_EXCEPTION_SERVICE_UNAVAILABLE);
+
+done: /* FIXME, this shouldn't be done this way. */
+ if (msg)
+ camel_medium_set_header (CAMEL_MEDIUM (msg), "X-Evolution-Source", store->base_url);
+fail:
+ camel_folder_summary_info_free (folder->summary, mi);
+
+ return msg;
+}
+
+static void
+imap_cache_message (CamelDiscoFolder *disco_folder, const char *uid,
+ CamelException *ex)
+{
+ CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (disco_folder);
+ CamelStream *stream;
+
+ stream = camel_imap_folder_fetch_data (imap_folder, uid, "", FALSE, ex);
+ if (stream)
+ camel_object_unref (CAMEL_OBJECT (stream));
+}
+
+/* We pretend that a FLAGS or RFC822.SIZE response is always exactly
+ * 20 bytes long, and a BODY[HEADERS] response is always 2000 bytes
+ * long. Since we know how many of each kind of response we're
+ * expecting, we can find the total (pretend) amount of server traffic
+ * to expect and then count off the responses as we read them to update
+ * the progress bar.
+ */
+#define IMAP_PRETEND_SIZEOF_FLAGS 20
+#define IMAP_PRETEND_SIZEOF_SIZE 20
+#define IMAP_PRETEND_SIZEOF_HEADERS 2000
+
+static char *tm_months[] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+};
+
+static gboolean
+decode_time (const unsigned char **in, int *hour, int *min, int *sec)
+{
+ register const unsigned char *inptr;
+ int *val, colons = 0;
+
+ *hour = *min = *sec = 0;
+
+ val = hour;
+ for (inptr = *in; *inptr && !isspace ((int) *inptr); inptr++) {
+ if (*inptr == ':') {
+ colons++;
+ switch (colons) {
+ case 1:
+ val = min;
+ break;
+ case 2:
+ val = sec;
+ break;
+ default:
+ return FALSE;
+ }
+ } else if (!isdigit ((int) *inptr))
+ return FALSE;
+ else
+ *val = (*val * 10) + (*inptr - '0');
+ }
+
+ *in = inptr;
+
+ return TRUE;
+}
+
+static time_t
+decode_internaldate (const unsigned char *in)
+{
+ const unsigned char *inptr = in;
+ int hour, min, sec, n;
+ unsigned char *buf;
+ struct tm tm;
+ time_t date;
+
+ memset ((void *) &tm, 0, sizeof (struct tm));
+
+ tm.tm_mday = strtoul (inptr, (char **) &buf, 10);
+ if (buf == inptr || *buf != '-')
+ return (time_t) -1;
+
+ inptr = buf + 1;
+ if (inptr[3] != '-')
+ return (time_t) -1;
+
+ for (n = 0; n < 12; n++) {
+ if (!strncasecmp (inptr, tm_months[n], 3))
+ break;
+ }
+
+ if (n >= 12)
+ return (time_t) -1;
+
+ tm.tm_mon = n;
+
+ inptr += 4;
+
+ n = strtoul (inptr, (char **) &buf, 10);
+ if (buf == inptr || *buf != ' ')
+ return (time_t) -1;
+
+ tm.tm_year = n - 1900;
+
+ inptr = buf + 1;
+ if (!decode_time (&inptr, &hour, &min, &sec))
+ return (time_t) -1;
+
+ tm.tm_hour = hour;
+ tm.tm_min = min;
+ tm.tm_sec = sec;
+
+ n = strtol (inptr, NULL, 10);
+
+ date = e_mktime_utc (&tm);
+
+ /* date is now GMT of the time we want, but not offset by the timezone ... */
+
+ /* this should convert the time to the GMT equiv time */
+ date -= ((n / 100) * 60 * 60) + (n % 100) * 60;
+
+ return date;
+}
+
+static void
+add_message_from_data (CamelFolder *folder, GPtrArray *messages,
+ int first, GData *data)
+{
+ CamelMimeMessage *msg;
+ CamelStream *stream;
+ CamelMessageInfo *mi;
+ const char *idate;
+ int seq;
+
+ seq = GPOINTER_TO_INT (g_datalist_get_data (&data, "SEQUENCE"));
+ if (seq < first)
+ return;
+ stream = g_datalist_get_data (&data, "BODY_PART_STREAM");
+ if (!stream)
+ return;
+
+ if (seq - first >= messages->len)
+ g_ptr_array_set_size (messages, seq - first + 1);
+
+ msg = camel_mime_message_new ();
+ if (camel_data_wrapper_construct_from_stream (CAMEL_DATA_WRAPPER (msg), stream) == -1) {
+ camel_object_unref (CAMEL_OBJECT (msg));
+ return;
+ }
+
+ mi = camel_folder_summary_info_new_from_message (folder->summary, msg);
+ camel_object_unref (CAMEL_OBJECT (msg));
+
+ if ((idate = g_datalist_get_data (&data, "INTERNALDATE")))
+ mi->date_received = decode_internaldate (idate);
+
+ if (mi->date_received == -1)
+ mi->date_received = mi->date_sent;
+
+ messages->pdata[seq - first] = mi;
+}
+
+
+#define CAMEL_MESSAGE_INFO_HEADERS "DATE FROM TO CC SUBJECT REFERENCES IN-REPLY-TO MESSAGE-ID MIME-VERSION CONTENT-TYPE"
+
+/* FIXME: this needs to be kept in sync with camel-mime-utils.c's list
+ of mailing-list headers and so might be best if this were
+ auto-generated? */
+#define MAILING_LIST_HEADERS "X-MAILING-LIST X-LOOP LIST-ID LIST-POST MAILING-LIST ORIGINATOR X-LIST SENDER RETURN-PATH X-BEENTHERE"
+
+static void
+imap_update_summary (CamelFolder *folder, int exists,
+ CamelFolderChangeInfo *changes,
+ CamelException *ex)
+{
+ CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
+ CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
+ GPtrArray *fetch_data = NULL, *messages = NULL, *needheaders;
+ guint32 flags, uidval;
+ int i, seq, first, size, got;
+ CamelImapResponseType type;
+ const char *header_spec;
+ CamelMessageInfo *mi, *info;
+ CamelStream *stream;
+ char *uid, *resp;
+ GData *data;
+
+ CAMEL_SERVICE_ASSERT_LOCKED (store, connect_lock);
+ if (store->server_level >= IMAP_LEVEL_IMAP4REV1)
+ header_spec = "HEADER.FIELDS.NOT (RECEIVED)";
+ else
+ header_spec = "0";
+
+ /* Figure out if any of the new messages are already cached (which
+ * may be the case if we're re-syncing after disconnected operation).
+ * If so, get their UIDs, FLAGS, and SIZEs. If not, get all that
+ * and ask for the headers too at the same time.
+ */
+ seq = camel_folder_summary_count (folder->summary);
+ first = seq + 1;
+ if (seq > 0) {
+ mi = camel_folder_summary_index (folder->summary, seq - 1);
+ uidval = strtoul(camel_message_info_uid (mi), NULL, 10);
+ camel_folder_summary_info_free (folder->summary, mi);
+ } else
+ uidval = 0;
+
+ size = (exists - seq) * (IMAP_PRETEND_SIZEOF_FLAGS + IMAP_PRETEND_SIZEOF_SIZE + IMAP_PRETEND_SIZEOF_HEADERS);
+ got = 0;
+ if (!camel_imap_command_start (store, folder, ex,
+ "UID FETCH %d:* (FLAGS RFC822.SIZE INTERNALDATE BODY.PEEK[%s])",
+ uidval + 1, header_spec))
+ return;
+ camel_operation_start (NULL, _("Fetching summary information for new messages"));
+
+ /* Parse the responses. We can't add a message to the summary
+ * until we've gotten its headers, and there's no guarantee
+ * the server will send the responses in a useful order...
+ */
+ fetch_data = g_ptr_array_new ();
+ messages = g_ptr_array_new ();
+ while ((type = camel_imap_command_response (store, &resp, ex)) ==
+ CAMEL_IMAP_RESPONSE_UNTAGGED) {
+ data = parse_fetch_response (imap_folder, resp);
+ g_free (resp);
+ if (!data)
+ continue;
+
+ seq = GPOINTER_TO_INT (g_datalist_get_data (&data, "SEQUENCE"));
+ if (seq < first) {
+ g_datalist_clear (&data);
+ continue;
+ }
+
+ if (g_datalist_get_data (&data, "FLAGS"))
+ got += IMAP_PRETEND_SIZEOF_FLAGS;
+ if (g_datalist_get_data (&data, "RFC822.SIZE"))
+ got += IMAP_PRETEND_SIZEOF_SIZE;
+ stream = g_datalist_get_data (&data, "BODY_PART_STREAM");
+ if (stream) {
+ got += IMAP_PRETEND_SIZEOF_HEADERS;
+
+ /* Use the stream now so we don't tie up many
+ * many fds if we're fetching many many messages.
+ */
+ add_message_from_data (folder, messages, first, data);
+ g_datalist_set_data (&data, "BODY_PART_STREAM", NULL);
+ }
+
+ camel_operation_progress (NULL, got * 100 / size);
+ g_ptr_array_add (fetch_data, data);
+ }
+ camel_operation_end (NULL);
+
+ if (type == CAMEL_IMAP_RESPONSE_ERROR)
+ goto lose;
+
+ /* Free the final tagged response */
+ g_free (resp);
+
+ /* Figure out which headers we still need to fetch. */
+ needheaders = g_ptr_array_new ();
+ size = got = 0;
+ for (i = 0; i < fetch_data->len; i++) {
+ data = fetch_data->pdata[i];
+ if (g_datalist_get_data (&data, "BODY_PART_LEN"))
+ continue;
+
+ uid = g_datalist_get_data (&data, "UID");
+ if (uid) {
+ g_ptr_array_add (needheaders, uid);
+ size += IMAP_PRETEND_SIZEOF_HEADERS;
+ }
+ }
+
+ /* And fetch them */
+ if (needheaders->len) {
+ char *uidset;
+ int uid = 0;
+
+ qsort (needheaders->pdata, needheaders->len,
+ sizeof (void *), uid_compar);
+
+ camel_operation_start (NULL, _("Fetching summary information for new messages"));
+
+ while (uid < needheaders->len) {
+ uidset = imap_uid_array_to_set (folder->summary, needheaders, uid, UID_SET_LIMIT, &uid);
+ if (!camel_imap_command_start (store, folder, ex,
+ "UID FETCH %s BODY.PEEK[%s]",
+ uidset, header_spec)) {
+ g_ptr_array_free (needheaders, TRUE);
+ camel_operation_end (NULL);
+ g_free (uidset);
+ goto lose;
+ }
+ g_free (uidset);
+
+ while ((type = camel_imap_command_response (store, &resp, ex))
+ == CAMEL_IMAP_RESPONSE_UNTAGGED) {
+ data = parse_fetch_response (imap_folder, resp);
+ g_free (resp);
+ if (!data)
+ continue;
+
+ stream = g_datalist_get_data (&data, "BODY_PART_STREAM");
+ if (stream) {
+ add_message_from_data (folder, messages, first, data);
+ got += IMAP_PRETEND_SIZEOF_HEADERS;
+ camel_operation_progress (NULL, got * 100 / size);
+ }
+ g_datalist_clear (&data);
+ }
+
+ if (type == CAMEL_IMAP_RESPONSE_ERROR) {
+ g_ptr_array_free (needheaders, TRUE);
+ camel_operation_end (NULL);
+ goto lose;
+ }
+ }
+
+ g_ptr_array_free (needheaders, TRUE);
+ camel_operation_end (NULL);
+ }
+
+ /* Now finish up summary entries (fix UIDs, set flags and size) */
+ for (i = 0; i < fetch_data->len; i++) {
+ data = fetch_data->pdata[i];
+
+ seq = GPOINTER_TO_INT (g_datalist_get_data (&data, "SEQUENCE"));
+ if (seq >= first + messages->len) {
+ g_datalist_clear (&data);
+ continue;
+ }
+
+ mi = messages->pdata[seq - first];
+ if (mi == NULL) {
+ CamelMessageInfo *pmi = NULL;
+ int j;
+
+ /* This is a kludge around a bug in Exchange
+ * 5.5 that sometimes claims multiple messages
+ * have the same UID. See bug #17694 for
+ * details. The "solution" is to create a fake
+ * message-info with the same details as the
+ * previously valid message. Yes, the user
+ * will have a clone in his/her message-list,
+ * but at least we don't crash.
+ */
+
+ /* find the previous valid message info */
+ for (j = seq - first - 1; j >= 0; j--) {
+ pmi = messages->pdata[j];
+ if (pmi != NULL)
+ break;
+ }
+
+ if (pmi == NULL) {
+ /* Server response is *really* fucked up,
+ I guess we just pretend it never happened? */
+ continue;
+ }
+
+ mi = camel_message_info_new ();
+ camel_message_info_dup_to (pmi, mi);
+ }
+
+ uid = g_datalist_get_data (&data, "UID");
+ if (uid)
+ camel_message_info_set_uid (mi, g_strdup (uid));
+ flags = GPOINTER_TO_INT (g_datalist_get_data (&data, "FLAGS"));
+ if (flags) {
+ ((CamelImapMessageInfo *)mi)->server_flags = flags;
+ /* "or" them in with the existing flags that may
+ * have been set by summary_info_new_from_message.
+ */
+ mi->flags |= flags;
+ }
+ size = GPOINTER_TO_INT (g_datalist_get_data (&data, "RFC822.SIZE"));
+ if (size)
+ mi->size = size;
+
+ g_datalist_clear (&data);
+ }
+ g_ptr_array_free (fetch_data, TRUE);
+
+ /* And add the entries to the summary, etc. */
+ for (i = 0; i < messages->len; i++) {
+ mi = messages->pdata[i];
+ if (!mi) {
+ g_warning ("No information for message %d", i + first);
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Incomplete server response: no information provided for message %d"),
+ i + first);
+ break;
+ }
+ uid = (char *)camel_message_info_uid(mi);
+ if (uid[0] == 0) {
+ g_warning("Server provided no uid: message %d", i + first);
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Incomplete server response: no UID provided for message %d"),
+ i + first);
+ break;
+ }
+ info = camel_folder_summary_uid(folder->summary, uid);
+ if (info) {
+ for (seq = 0; seq < camel_folder_summary_count (folder->summary); seq++) {
+ if (folder->summary->messages->pdata[seq] == info)
+ break;
+ }
+
+ g_warning("Message already present? %s", camel_message_info_uid(mi));
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Unexpected server response: Identical UIDs provided for messages %d and %d"),
+ seq + 1, i + first);
+
+ camel_folder_summary_info_free(folder->summary, info);
+ break;
+ }
+
+ camel_folder_summary_add (folder->summary, mi);
+ camel_folder_change_info_add_uid (changes, camel_message_info_uid (mi));
+
+ if ((mi->flags & CAMEL_IMAP_MESSAGE_RECENT))
+ camel_folder_change_info_recent_uid(changes, camel_message_info_uid (mi));
+ }
+
+ for ( ; i < messages->len; i++) {
+ if ((mi = messages->pdata[i]))
+ camel_folder_summary_info_free(folder->summary, mi);
+ }
+
+ g_ptr_array_free (messages, TRUE);
+
+ return;
+
+ lose:
+ if (fetch_data) {
+ for (i = 0; i < fetch_data->len; i++) {
+ data = fetch_data->pdata[i];
+ g_datalist_clear (&data);
+ }
+ g_ptr_array_free (fetch_data, TRUE);
+ }
+ if (messages) {
+ for (i = 0; i < messages->len; i++) {
+ if (messages->pdata[i])
+ camel_folder_summary_info_free (folder->summary, messages->pdata[i]);
+ }
+ g_ptr_array_free (messages, TRUE);
+ }
+}
+
+/* Called with the store's connect_lock locked */
+void
+camel_imap_folder_changed (CamelFolder *folder, int exists,
+ GArray *expunged, CamelException *ex)
+{
+ CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
+ CamelFolderChangeInfo *changes;
+ CamelMessageInfo *info;
+ int len;
+
+ CAMEL_SERVICE_ASSERT_LOCKED (folder->parent_store, connect_lock);
+
+ changes = camel_folder_change_info_new ();
+ if (expunged) {
+ int i, id;
+
+ for (i = 0; i < expunged->len; i++) {
+ id = g_array_index (expunged, int, i);
+ info = camel_folder_summary_index (folder->summary, id - 1);
+ if (info == NULL) {
+ /* FIXME: danw: does this mean that the summary is corrupt? */
+ /* I guess a message that we never retrieved got expunged? */
+ continue;
+ }
+
+ camel_folder_change_info_remove_uid (changes, camel_message_info_uid (info));
+ CAMEL_IMAP_FOLDER_LOCK (imap_folder, cache_lock);
+ camel_imap_message_cache_remove (imap_folder->cache, camel_message_info_uid (info));
+ CAMEL_IMAP_FOLDER_UNLOCK (imap_folder, cache_lock);
+ camel_folder_summary_remove (folder->summary, info);
+ camel_folder_summary_info_free(folder->summary, info);
+ }
+ }
+
+ len = camel_folder_summary_count (folder->summary);
+ if (exists > len)
+ imap_update_summary (folder, exists, changes, ex);
+
+ if (camel_folder_change_info_changed (changes))
+ camel_object_trigger_event (CAMEL_OBJECT (folder), "folder_changed", changes);
+
+ camel_folder_change_info_free (changes);
+ camel_folder_summary_save (folder->summary);
+}
+
+static void
+imap_thaw (CamelFolder *folder)
+{
+ CamelImapFolder *imap_folder;
+
+ CAMEL_FOLDER_CLASS (disco_folder_class)->thaw (folder);
+ if (camel_folder_is_frozen (folder))
+ return;
+
+ imap_folder = CAMEL_IMAP_FOLDER (folder);
+ if (imap_folder->need_refresh) {
+ imap_folder->need_refresh = FALSE;
+ imap_refresh_info (folder, NULL);
+ }
+}
+
+
+CamelStream *
+camel_imap_folder_fetch_data (CamelImapFolder *imap_folder, const char *uid,
+ const char *section_text, gboolean cache_only,
+ CamelException *ex)
+{
+ CamelFolder *folder = CAMEL_FOLDER (imap_folder);
+ CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
+ CamelImapResponse *response;
+ CamelStream *stream;
+ GData *fetch_data;
+ char *found_uid;
+ int i;
+
+ /* EXPUNGE responses have to modify the cache, which means
+ * they have to grab the cache_lock while holding the
+ * connect_lock. So we grab the connect_lock now, in case
+ * we're going to need it below, since we can't grab it
+ * after the cache_lock.
+ */
+ CAMEL_SERVICE_LOCK (store, connect_lock);
+
+ CAMEL_IMAP_FOLDER_LOCK (imap_folder, cache_lock);
+ stream = camel_imap_message_cache_get (imap_folder->cache, uid, section_text, ex);
+ if (!stream && (!strcmp (section_text, "HEADER") || !strcmp (section_text, "0"))) {
+ camel_exception_clear (ex);
+ stream = camel_imap_message_cache_get (imap_folder->cache, uid, "", ex);
+ }
+
+ if (stream || cache_only) {
+ CAMEL_IMAP_FOLDER_UNLOCK (imap_folder, cache_lock);
+ CAMEL_SERVICE_UNLOCK (store, connect_lock);
+ return stream;
+ }
+
+ if (camel_disco_store_status (CAMEL_DISCO_STORE (store)) == CAMEL_DISCO_STORE_OFFLINE) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ _("This message is not currently available"));
+ CAMEL_IMAP_FOLDER_UNLOCK (imap_folder, cache_lock);
+ CAMEL_SERVICE_UNLOCK (store, connect_lock);
+ return NULL;
+ }
+
+ camel_exception_clear (ex);
+ if (store->server_level < IMAP_LEVEL_IMAP4REV1 && !*section_text) {
+ response = camel_imap_command (store, folder, ex,
+ "UID FETCH %s RFC822.PEEK",
+ uid);
+ } else {
+ response = camel_imap_command (store, folder, ex,
+ "UID FETCH %s BODY.PEEK[%s]",
+ uid, section_text);
+ }
+ /* We won't need the connect_lock again after this. */
+ CAMEL_SERVICE_UNLOCK (store, connect_lock);
+
+ if (!response) {
+ CAMEL_IMAP_FOLDER_UNLOCK (imap_folder, cache_lock);
+ return NULL;
+ }
+
+ for (i = 0; i < response->untagged->len; i++) {
+ fetch_data = parse_fetch_response (imap_folder, response->untagged->pdata[i]);
+ found_uid = g_datalist_get_data (&fetch_data, "UID");
+ stream = g_datalist_get_data (&fetch_data, "BODY_PART_STREAM");
+ if (found_uid && stream && !strcmp (uid, found_uid))
+ break;
+
+ g_datalist_clear (&fetch_data);
+ stream = NULL;
+ }
+ camel_imap_response_free (store, response);
+ CAMEL_IMAP_FOLDER_UNLOCK (imap_folder, cache_lock);
+ if (!stream) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ _("Could not find message body in FETCH response."));
+ } else {
+ camel_object_ref (CAMEL_OBJECT (stream));
+ g_datalist_clear (&fetch_data);
+ }
+
+ return stream;
+}
+
+static GData *
+parse_fetch_response (CamelImapFolder *imap_folder, char *response)
+{
+ GData *data = NULL;
+ char *start, *part_spec = NULL, *body = NULL, *uid = NULL, *idate = NULL;
+ gboolean cache_header = TRUE, header = FALSE;
+ size_t body_len = 0;
+
+ if (*response != '(') {
+ long seq;
+
+ if (*response != '*' || *(response + 1) != ' ')
+ return NULL;
+ seq = strtol (response + 2, &response, 10);
+ if (seq == 0)
+ return NULL;
+ if (strncasecmp (response, " FETCH (", 8) != 0)
+ return NULL;
+ response += 7;
+
+ g_datalist_set_data (&data, "SEQUENCE", GINT_TO_POINTER (seq));
+ }
+
+ do {
+ /* Skip the initial '(' or the ' ' between elements */
+ response++;
+
+ if (!strncasecmp (response, "FLAGS ", 6)) {
+ guint32 flags;
+
+ response += 6;
+ /* FIXME user flags */
+ flags = imap_parse_flag_list (&response);
+
+ g_datalist_set_data (&data, "FLAGS", GUINT_TO_POINTER (flags));
+ } else if (!strncasecmp (response, "RFC822.SIZE ", 12)) {
+ unsigned long size;
+
+ response += 12;
+ size = strtoul (response, &response, 10);
+ g_datalist_set_data (&data, "RFC822.SIZE", GUINT_TO_POINTER (size));
+ } else if (!strncasecmp (response, "BODY[", 5) ||
+ !strncasecmp (response, "RFC822 ", 7)) {
+ char *p;
+
+ if (*response == 'B') {
+ response += 5;
+
+ /* HEADER], HEADER.FIELDS (...)], or 0] */
+ if (!strncasecmp (response, "HEADER", 6)) {
+ header = TRUE;
+ if (!strncasecmp (response + 6, ".FIELDS", 7))
+ cache_header = FALSE;
+ } else if (!strncasecmp (response, "0]", 2))
+ header = TRUE;
+
+ p = strchr (response, ']');
+ if (!p || *(p + 1) != ' ')
+ break;
+
+ if (cache_header)
+ part_spec = g_strndup (response, p - response);
+ else
+ part_spec = g_strdup ("HEADER.FIELDS");
+
+ response = p + 2;
+ } else {
+ part_spec = g_strdup ("");
+ response += 7;
+
+ if (!strncasecmp (response, "HEADER", 6))
+ header = TRUE;
+ }
+
+ body = imap_parse_nstring ((const char **) &response, &body_len);
+ if (!response) {
+ g_free (part_spec);
+ break;
+ }
+
+ if (!body)
+ body = g_strdup ("");
+ g_datalist_set_data_full (&data, "BODY_PART_SPEC", part_spec, g_free);
+ g_datalist_set_data_full (&data, "BODY_PART_DATA", body, g_free);
+ g_datalist_set_data (&data, "BODY_PART_LEN", GINT_TO_POINTER (body_len));
+ } else if (!strncasecmp (response, "BODY ", 5) ||
+ !strncasecmp (response, "BODYSTRUCTURE ", 14)) {
+ response = strchr (response, ' ') + 1;
+ start = response;
+ imap_skip_list ((const char **) &response);
+ g_datalist_set_data_full (&data, "BODY", g_strndup (start, response - start), g_free);
+ } else if (!strncasecmp (response, "UID ", 4)) {
+ int len;
+
+ len = strcspn (response + 4, " )");
+ uid = g_strndup (response + 4, len);
+ g_datalist_set_data_full (&data, "UID", uid, g_free);
+ response += 4 + len;
+ } else if (!strncasecmp (response, "INTERNALDATE ", 13)) {
+ int len;
+
+ response += 13;
+ if (*response == '"') {
+ response++;
+ len = strcspn (response, "\"");
+ idate = g_strndup (response, len);
+ g_datalist_set_data_full (&data, "INTERNALDATE", idate, g_free);
+ response += len + 1;
+ }
+ } else {
+ g_warning ("Unexpected FETCH response from server: (%s", response);
+ break;
+ }
+ } while (response && *response != ')');
+
+ if (!response || *response != ')') {
+ g_datalist_clear (&data);
+ return NULL;
+ }
+
+ if (uid && body) {
+ CamelStream *stream;
+
+ if (header && !cache_header) {
+ stream = camel_stream_mem_new_with_buffer (body, body_len);
+ } else {
+ CAMEL_IMAP_FOLDER_LOCK (imap_folder, cache_lock);
+ stream = camel_imap_message_cache_insert (imap_folder->cache,
+ uid, part_spec,
+ body, body_len, NULL);
+ CAMEL_IMAP_FOLDER_UNLOCK (imap_folder, cache_lock);
+ if (stream == NULL)
+ stream = camel_stream_mem_new_with_buffer (body, body_len);
+ }
+
+ if (stream)
+ g_datalist_set_data_full (&data, "BODY_PART_STREAM", stream,
+ (GDestroyNotify) camel_object_unref);
+ }
+
+ return data;
+}
+
diff --git a/camel/providers/imap/camel-imap-store.c b/camel/providers/imap/camel-imap-store.c
new file mode 100644
index 0000000000..29f56a9da6
--- /dev/null
+++ b/camel/providers/imap/camel-imap-store.c
@@ -0,0 +1,3271 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* camel-imap-store.c : class for an imap store */
+
+/*
+ * Authors:
+ * Dan Winship <danw@ximian.com>
+ * Jeffrey Stedfast <fejj@ximian.com>
+ *
+ * Copyright 2000, 2003 Ximian, Inc.
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "e-util/e-path.h"
+
+#include "camel-imap-store.h"
+#include "camel-imap-store-summary.h"
+#include "camel-imap-folder.h"
+#include "camel-imap-utils.h"
+#include "camel-imap-command.h"
+#include "camel-imap-summary.h"
+#include "camel-imap-message-cache.h"
+#include "camel-disco-diary.h"
+#include "camel-file-utils.h"
+#include "camel-folder.h"
+#include "camel-exception.h"
+#include "camel-session.h"
+#include "camel-stream.h"
+#include "camel-stream-buffer.h"
+#include "camel-stream-fs.h"
+#include "camel-stream-process.h"
+#include "camel-tcp-stream-raw.h"
+#include "camel-tcp-stream-ssl.h"
+#include "camel-url.h"
+#include "camel-sasl.h"
+#include "camel-utf8.h"
+#include "camel-string-utils.h"
+
+#include "camel-imap-private.h"
+#include "camel-private.h"
+
+#include "camel-debug.h"
+
+#define d(x)
+
+/* Specified in RFC 2060 */
+#define IMAP_PORT "143"
+#define IMAPS_PORT "993"
+
+static CamelDiscoStoreClass *parent_class = NULL;
+
+static char imap_tag_prefix = 'A';
+
+static void construct (CamelService *service, CamelSession *session,
+ CamelProvider *provider, CamelURL *url,
+ CamelException *ex);
+
+static int imap_setv (CamelObject *object, CamelException *ex, CamelArgV *args);
+static int imap_getv (CamelObject *object, CamelException *ex, CamelArgGetV *args);
+
+static char *imap_get_name (CamelService *service, gboolean brief);
+
+static gboolean can_work_offline (CamelDiscoStore *disco_store);
+static gboolean imap_connect_online (CamelService *service, CamelException *ex);
+static gboolean imap_connect_offline (CamelService *service, CamelException *ex);
+static gboolean imap_disconnect_online (CamelService *service, gboolean clean, CamelException *ex);
+static gboolean imap_disconnect_offline (CamelService *service, gboolean clean, CamelException *ex);
+static void imap_noop (CamelStore *store, CamelException *ex);
+static CamelFolder *imap_get_junk(CamelStore *store, CamelException *ex);
+static CamelFolder *imap_get_trash(CamelStore *store, CamelException *ex);
+static GList *query_auth_types (CamelService *service, CamelException *ex);
+static guint hash_folder_name (gconstpointer key);
+static gint compare_folder_name (gconstpointer a, gconstpointer b);
+static CamelFolder *get_folder_online (CamelStore *store, const char *folder_name, guint32 flags, CamelException *ex);
+static CamelFolder *get_folder_offline (CamelStore *store, const char *folder_name, guint32 flags, CamelException *ex);
+
+static CamelFolderInfo *create_folder (CamelStore *store, const char *parent_name, const char *folder_name, CamelException *ex);
+static void delete_folder (CamelStore *store, const char *folder_name, CamelException *ex);
+static void rename_folder (CamelStore *store, const char *old_name, const char *new_name, CamelException *ex);
+static CamelFolderInfo *get_folder_info_online (CamelStore *store,
+ const char *top,
+ guint32 flags,
+ CamelException *ex);
+static CamelFolderInfo *get_folder_info_offline (CamelStore *store,
+ const char *top,
+ guint32 flags,
+ CamelException *ex);
+static gboolean folder_subscribed (CamelStore *store, const char *folder_name);
+static void subscribe_folder (CamelStore *store, const char *folder_name,
+ CamelException *ex);
+static void unsubscribe_folder (CamelStore *store, const char *folder_name,
+ CamelException *ex);
+
+static void get_folders_online (CamelImapStore *imap_store, const char *pattern,
+ GPtrArray *folders, gboolean lsub, CamelException *ex);
+
+
+static void imap_folder_effectively_unsubscribed(CamelImapStore *imap_store, const char *folder_name, CamelException *ex);
+static gboolean imap_check_folder_still_extant (CamelImapStore *imap_store, const char *full_name, CamelException *ex);
+static void imap_forget_folder(CamelImapStore *imap_store, const char *folder_name, CamelException *ex);
+static void imap_set_server_level (CamelImapStore *store);
+
+static void
+camel_imap_store_class_init (CamelImapStoreClass *camel_imap_store_class)
+{
+ CamelObjectClass *camel_object_class =
+ CAMEL_OBJECT_CLASS (camel_imap_store_class);
+ CamelServiceClass *camel_service_class =
+ CAMEL_SERVICE_CLASS (camel_imap_store_class);
+ CamelStoreClass *camel_store_class =
+ CAMEL_STORE_CLASS (camel_imap_store_class);
+ CamelDiscoStoreClass *camel_disco_store_class =
+ CAMEL_DISCO_STORE_CLASS (camel_imap_store_class);
+
+ parent_class = CAMEL_DISCO_STORE_CLASS (camel_type_get_global_classfuncs (camel_disco_store_get_type ()));
+
+ /* virtual method overload */
+ camel_object_class->setv = imap_setv;
+ camel_object_class->getv = imap_getv;
+
+ camel_service_class->construct = construct;
+ camel_service_class->query_auth_types = query_auth_types;
+ camel_service_class->get_name = imap_get_name;
+
+ camel_store_class->hash_folder_name = hash_folder_name;
+ camel_store_class->compare_folder_name = compare_folder_name;
+ camel_store_class->create_folder = create_folder;
+ camel_store_class->delete_folder = delete_folder;
+ camel_store_class->rename_folder = rename_folder;
+ camel_store_class->free_folder_info = camel_store_free_folder_info_full;
+ camel_store_class->folder_subscribed = folder_subscribed;
+ camel_store_class->subscribe_folder = subscribe_folder;
+ camel_store_class->unsubscribe_folder = unsubscribe_folder;
+ camel_store_class->noop = imap_noop;
+ camel_store_class->get_trash = imap_get_trash;
+ camel_store_class->get_junk = imap_get_junk;
+
+ camel_disco_store_class->can_work_offline = can_work_offline;
+ camel_disco_store_class->connect_online = imap_connect_online;
+ camel_disco_store_class->connect_offline = imap_connect_offline;
+ camel_disco_store_class->disconnect_online = imap_disconnect_online;
+ camel_disco_store_class->disconnect_offline = imap_disconnect_offline;
+ camel_disco_store_class->get_folder_online = get_folder_online;
+ camel_disco_store_class->get_folder_offline = get_folder_offline;
+ camel_disco_store_class->get_folder_resyncing = get_folder_online;
+ camel_disco_store_class->get_folder_info_online = get_folder_info_online;
+ camel_disco_store_class->get_folder_info_offline = get_folder_info_offline;
+ camel_disco_store_class->get_folder_info_resyncing = get_folder_info_online;
+}
+
+static gboolean
+free_key (gpointer key, gpointer value, gpointer user_data)
+{
+ g_free (key);
+ return TRUE;
+}
+
+static void
+camel_imap_store_finalize (CamelObject *object)
+{
+ CamelImapStore *imap_store = CAMEL_IMAP_STORE (object);
+
+ /* This frees current_folder, folders, authtypes, streams, and namespace. */
+ camel_service_disconnect((CamelService *)imap_store, TRUE, NULL);
+
+ if (imap_store->summary) {
+ camel_store_summary_save((CamelStoreSummary *)imap_store->summary);
+ camel_object_unref(imap_store->summary);
+ }
+
+ if (imap_store->base_url)
+ g_free (imap_store->base_url);
+ if (imap_store->storage_path)
+ g_free (imap_store->storage_path);
+}
+
+static void
+camel_imap_store_init (gpointer object, gpointer klass)
+{
+ CamelImapStore *imap_store = CAMEL_IMAP_STORE (object);
+
+ imap_store->istream = NULL;
+ imap_store->ostream = NULL;
+
+ imap_store->dir_sep = '\0';
+ imap_store->current_folder = NULL;
+ imap_store->connected = FALSE;
+ imap_store->preauthed = FALSE;
+
+ imap_store->tag_prefix = imap_tag_prefix++;
+ if (imap_tag_prefix > 'Z')
+ imap_tag_prefix = 'A';
+}
+
+CamelType
+camel_imap_store_get_type (void)
+{
+ static CamelType camel_imap_store_type = CAMEL_INVALID_TYPE;
+
+ if (camel_imap_store_type == CAMEL_INVALID_TYPE) {
+ camel_imap_store_type =
+ camel_type_register (CAMEL_DISCO_STORE_TYPE,
+ "CamelImapStore",
+ sizeof (CamelImapStore),
+ sizeof (CamelImapStoreClass),
+ (CamelObjectClassInitFunc) camel_imap_store_class_init,
+ NULL,
+ (CamelObjectInitFunc) camel_imap_store_init,
+ (CamelObjectFinalizeFunc) camel_imap_store_finalize);
+ }
+
+ return camel_imap_store_type;
+}
+
+static void
+construct (CamelService *service, CamelSession *session,
+ CamelProvider *provider, CamelURL *url,
+ CamelException *ex)
+{
+ CamelImapStore *imap_store = CAMEL_IMAP_STORE (service);
+ CamelStore *store = CAMEL_STORE (service);
+ char *tmp;
+ CamelURL *summary_url;
+
+ CAMEL_SERVICE_CLASS (parent_class)->construct (service, session, provider, url, ex);
+ if (camel_exception_is_set (ex))
+ return;
+
+ imap_store->storage_path = camel_session_get_storage_path (session, service, ex);
+ if (!imap_store->storage_path)
+ return;
+
+ /* FIXME */
+ imap_store->base_url = camel_url_to_string (service->url, (CAMEL_URL_HIDE_PASSWORD |
+ CAMEL_URL_HIDE_PARAMS |
+ CAMEL_URL_HIDE_AUTH));
+
+ imap_store->parameters = 0;
+ if (camel_url_get_param (url, "use_lsub"))
+ store->flags |= CAMEL_STORE_SUBSCRIPTIONS;
+ if (camel_url_get_param (url, "namespace")) {
+ imap_store->parameters |= IMAP_PARAM_OVERRIDE_NAMESPACE;
+ g_free(imap_store->namespace);
+ imap_store->namespace = g_strdup (camel_url_get_param (url, "namespace"));
+ }
+ if (camel_url_get_param (url, "check_all"))
+ imap_store->parameters |= IMAP_PARAM_CHECK_ALL;
+ if (camel_url_get_param (url, "filter")) {
+ imap_store->parameters |= IMAP_PARAM_FILTER_INBOX;
+ store->flags |= CAMEL_STORE_FILTER_INBOX;
+ }
+ if (camel_url_get_param (url, "filter_junk"))
+ imap_store->parameters |= IMAP_PARAM_FILTER_JUNK;
+ if (camel_url_get_param (url, "filter_junk_inbox"))
+ imap_store->parameters |= IMAP_PARAM_FILTER_JUNK_INBOX;
+
+ /* setup/load the store summary */
+ tmp = alloca(strlen(imap_store->storage_path)+32);
+ sprintf(tmp, "%s/.ev-store-summary", imap_store->storage_path);
+ imap_store->summary = camel_imap_store_summary_new();
+ camel_store_summary_set_filename((CamelStoreSummary *)imap_store->summary, tmp);
+ summary_url = camel_url_new(imap_store->base_url, NULL);
+ camel_store_summary_set_uri_base((CamelStoreSummary *)imap_store->summary, summary_url);
+ camel_url_free(summary_url);
+ if (camel_store_summary_load((CamelStoreSummary *)imap_store->summary) == 0) {
+ CamelImapStoreSummary *is = imap_store->summary;
+
+ if (is->namespace) {
+ /* if namespace has changed, clear folder list */
+ if (imap_store->namespace && strcmp(imap_store->namespace, is->namespace->full_name) != 0) {
+ camel_store_summary_clear((CamelStoreSummary *)is);
+ } else {
+ imap_store->namespace = g_strdup(is->namespace->full_name);
+ imap_store->dir_sep = is->namespace->sep;
+ }
+ }
+
+ imap_store->capabilities = is->capabilities;
+ imap_set_server_level(imap_store);
+ }
+}
+
+static int
+imap_setv (CamelObject *object, CamelException *ex, CamelArgV *args)
+{
+ CamelImapStore *store = (CamelImapStore *) object;
+ guint32 tag, flags;
+ int i;
+
+ for (i = 0; i < args->argc; i++) {
+ tag = args->argv[i].tag;
+
+ /* make sure this is an arg we're supposed to handle */
+ if ((tag & CAMEL_ARG_TAG) <= CAMEL_IMAP_STORE_ARG_FIRST ||
+ (tag & CAMEL_ARG_TAG) >= CAMEL_IMAP_STORE_ARG_FIRST + 100)
+ continue;
+
+ switch (tag) {
+ case CAMEL_IMAP_STORE_NAMESPACE:
+ if (strcmp (store->namespace, args->argv[i].ca_str) != 0) {
+ g_free (store->namespace);
+ store->namespace = g_strdup (args->argv[i].ca_str);
+ /* the current imap code will need to do a reconnect for this to take effect */
+ /*reconnect = TRUE;*/
+ }
+ break;
+ case CAMEL_IMAP_STORE_OVERRIDE_NAMESPACE:
+ flags = args->argv[i].ca_int ? IMAP_PARAM_OVERRIDE_NAMESPACE : 0;
+ flags |= (store->parameters & ~IMAP_PARAM_OVERRIDE_NAMESPACE);
+
+ if (store->parameters != flags) {
+ store->parameters = flags;
+ /* the current imap code will need to do a reconnect for this to take effect */
+ /*reconnect = TRUE;*/
+ }
+ break;
+ case CAMEL_IMAP_STORE_CHECK_ALL:
+ flags = args->argv[i].ca_int ? IMAP_PARAM_CHECK_ALL : 0;
+ flags |= (store->parameters & ~IMAP_PARAM_CHECK_ALL);
+ store->parameters = flags;
+ /* no need to reconnect for this option to take effect... */
+ break;
+ case CAMEL_IMAP_STORE_FILTER_INBOX:
+ flags = args->argv[i].ca_int ? IMAP_PARAM_FILTER_INBOX : 0;
+ flags |= (store->parameters & ~IMAP_PARAM_FILTER_INBOX);
+ store->parameters = flags;
+ /* no need to reconnect for this option to take effect... */
+ break;
+ case CAMEL_IMAP_STORE_FILTER_JUNK:
+ flags = args->argv[i].ca_int ? IMAP_PARAM_FILTER_JUNK : 0;
+ store->parameters = flags | (store->parameters & ~IMAP_PARAM_FILTER_JUNK);
+ break;
+ case CAMEL_IMAP_STORE_FILTER_JUNK_INBOX:
+ flags = args->argv[i].ca_int ? IMAP_PARAM_FILTER_JUNK_INBOX : 0;
+ store->parameters = flags | (store->parameters & ~IMAP_PARAM_FILTER_JUNK_INBOX);
+ break;
+ default:
+ /* error?? */
+ continue;
+ }
+
+ /* let our parent know that we've handled this arg */
+ camel_argv_ignore (args, i);
+ }
+
+ /* FIXME: if we need to reconnect for a change to take affect,
+ we need to do it here... or, better yet, somehow chain it
+ up to CamelService's setv implementation. */
+
+ return CAMEL_OBJECT_CLASS (parent_class)->setv (object, ex, args);
+}
+
+static int
+imap_getv (CamelObject *object, CamelException *ex, CamelArgGetV *args)
+{
+ CamelImapStore *store = (CamelImapStore *) object;
+ guint32 tag;
+ int i;
+
+ for (i = 0; i < args->argc; i++) {
+ tag = args->argv[i].tag;
+
+ /* make sure this is an arg we're supposed to handle */
+ if ((tag & CAMEL_ARG_TAG) <= CAMEL_IMAP_STORE_ARG_FIRST ||
+ (tag & CAMEL_ARG_TAG) >= CAMEL_IMAP_STORE_ARG_FIRST + 100)
+ continue;
+
+ switch (tag) {
+ case CAMEL_IMAP_STORE_NAMESPACE:
+ *args->argv[i].ca_str = store->namespace;
+ break;
+ case CAMEL_IMAP_STORE_OVERRIDE_NAMESPACE:
+ *args->argv[i].ca_int = store->parameters & IMAP_PARAM_OVERRIDE_NAMESPACE ? TRUE : FALSE;
+ break;
+ case CAMEL_IMAP_STORE_CHECK_ALL:
+ *args->argv[i].ca_int = store->parameters & IMAP_PARAM_CHECK_ALL ? TRUE : FALSE;
+ break;
+ case CAMEL_IMAP_STORE_FILTER_INBOX:
+ *args->argv[i].ca_int = store->parameters & IMAP_PARAM_FILTER_INBOX ? TRUE : FALSE;
+ break;
+ case CAMEL_IMAP_STORE_FILTER_JUNK:
+ *args->argv[i].ca_int = store->parameters & IMAP_PARAM_FILTER_JUNK ? TRUE : FALSE;
+ break;
+ case CAMEL_IMAP_STORE_FILTER_JUNK_INBOX:
+ *args->argv[i].ca_int = store->parameters & IMAP_PARAM_FILTER_JUNK_INBOX ? TRUE : FALSE;
+ break;
+ default:
+ /* error? */
+ break;
+ }
+ }
+
+ return CAMEL_OBJECT_CLASS (parent_class)->getv (object, ex, args);
+}
+
+static char *
+imap_get_name (CamelService *service, gboolean brief)
+{
+ if (brief)
+ return g_strdup_printf (_("IMAP server %s"), service->url->host);
+ else
+ return g_strdup_printf (_("IMAP service for %s on %s"),
+ service->url->user, service->url->host);
+}
+
+static void
+imap_set_server_level (CamelImapStore *store)
+{
+ if (store->capabilities & IMAP_CAPABILITY_IMAP4REV1) {
+ store->server_level = IMAP_LEVEL_IMAP4REV1;
+ store->capabilities |= IMAP_CAPABILITY_STATUS;
+ } else if (store->capabilities & IMAP_CAPABILITY_IMAP4)
+ store->server_level = IMAP_LEVEL_IMAP4;
+ else
+ store->server_level = IMAP_LEVEL_UNKNOWN;
+}
+
+static struct {
+ const char *name;
+ guint32 flag;
+} capabilities[] = {
+ { "IMAP4", IMAP_CAPABILITY_IMAP4 },
+ { "IMAP4REV1", IMAP_CAPABILITY_IMAP4REV1 },
+ { "STATUS", IMAP_CAPABILITY_STATUS },
+ { "NAMESPACE", IMAP_CAPABILITY_NAMESPACE },
+ { "UIDPLUS", IMAP_CAPABILITY_UIDPLUS },
+ { "LITERAL+", IMAP_CAPABILITY_LITERALPLUS },
+ { "STARTTLS", IMAP_CAPABILITY_STARTTLS },
+ { NULL, 0 }
+};
+
+static gboolean
+imap_get_capability (CamelService *service, CamelException *ex)
+{
+ CamelImapStore *store = CAMEL_IMAP_STORE (service);
+ CamelImapResponse *response;
+ char *result, *capa, *lasts;
+ int i;
+
+ CAMEL_SERVICE_ASSERT_LOCKED (store, connect_lock);
+
+ /* Find out the IMAP capabilities */
+ /* We assume we have utf8 capable search until a failed search tells us otherwise */
+ store->capabilities = IMAP_CAPABILITY_utf8_search;
+ store->authtypes = g_hash_table_new (g_str_hash, g_str_equal);
+ response = camel_imap_command (store, NULL, ex, "CAPABILITY");
+ if (!response)
+ return FALSE;
+ result = camel_imap_response_extract (store, response, "CAPABILITY ", ex);
+ if (!result)
+ return FALSE;
+
+ /* Skip over "* CAPABILITY ". */
+ capa = result + 13;
+ for (capa = strtok_r (capa, " ", &lasts); capa;
+ capa = strtok_r (NULL, " ", &lasts)) {
+ if (!strncmp (capa, "AUTH=", 5)) {
+ g_hash_table_insert (store->authtypes,
+ g_strdup (capa + 5),
+ GINT_TO_POINTER (1));
+ continue;
+ }
+ for (i = 0; capabilities[i].name; i++) {
+ if (g_ascii_strcasecmp (capa, capabilities[i].name) == 0) {
+ store->capabilities |= capabilities[i].flag;
+ break;
+ }
+ }
+ }
+ g_free (result);
+
+ imap_set_server_level (store);
+
+ if (store->summary->capabilities != store->capabilities) {
+ store->summary->capabilities = store->capabilities;
+ camel_store_summary_touch((CamelStoreSummary *)store->summary);
+ camel_store_summary_save((CamelStoreSummary *)store->summary);
+ }
+
+ return TRUE;
+}
+
+enum {
+ USE_SSL_NEVER,
+ USE_SSL_ALWAYS,
+ USE_SSL_WHEN_POSSIBLE
+};
+
+#define SSL_PORT_FLAGS (CAMEL_TCP_STREAM_SSL_ENABLE_SSL2 | CAMEL_TCP_STREAM_SSL_ENABLE_SSL3)
+#define STARTTLS_FLAGS (CAMEL_TCP_STREAM_SSL_ENABLE_TLS)
+
+static gboolean
+connect_to_server (CamelService *service, int ssl_mode, int try_starttls, CamelException *ex)
+{
+ CamelImapStore *store = (CamelImapStore *) service;
+ CamelImapResponse *response;
+ CamelStream *tcp_stream;
+ CamelSockOptData sockopt;
+ gboolean force_imap4 = FALSE;
+ int clean_quit;
+ int ret;
+ char *buf;
+ struct addrinfo *ai, hints = { 0 };
+ char *serv;
+ const char *port = NULL;
+
+ /* FIXME: this connect stuff is duplicated everywhere */
+
+ if (service->url->port) {
+ serv = g_alloca(16);
+ sprintf(serv, "%d", service->url->port);
+ } else {
+ serv = "imap";
+ port = IMAP_PORT;
+ }
+
+ if (ssl_mode != USE_SSL_NEVER) {
+#ifdef HAVE_SSL
+ if (try_starttls) {
+ tcp_stream = camel_tcp_stream_ssl_new_raw (service->session, service->url->host, STARTTLS_FLAGS);
+ } else {
+ if (service->url->port == 0) {
+ serv = "imaps";
+ port = IMAPS_PORT;
+ }
+ tcp_stream = camel_tcp_stream_ssl_new (service->session, service->url->host, SSL_PORT_FLAGS);
+ }
+#else
+ if (!try_starttls && service->url->port == 0) {
+ serv = "imaps";
+ port = IMAPS_PORT;
+ }
+
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ _("Could not connect to %s (port %s): %s"),
+ service->url->host, serv,
+ _("SSL unavailable"));
+ return FALSE;
+#endif /* HAVE_SSL */
+ } else {
+ tcp_stream = camel_tcp_stream_raw_new ();
+ }
+
+ hints.ai_socktype = SOCK_STREAM;
+ ai = camel_getaddrinfo(service->url->host, serv, &hints, ex);
+ if (ai == NULL && port != NULL && camel_exception_get_id(ex) != CAMEL_EXCEPTION_USER_CANCEL) {
+ camel_exception_clear(ex);
+ ai = camel_getaddrinfo(service->url->host, port, &hints, ex);
+ }
+ if (ai == NULL) {
+ camel_object_unref(tcp_stream);
+ return FALSE;
+ }
+
+ ret = camel_tcp_stream_connect(CAMEL_TCP_STREAM(tcp_stream), ai);
+ camel_freeaddrinfo(ai);
+ if (ret == -1) {
+ if (errno == EINTR)
+ camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL,
+ _("Connection cancelled"));
+ else
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ _("Could not connect to %s (port %s): %s"),
+ service->url->host, serv, g_strerror (errno));
+
+ camel_object_unref (tcp_stream);
+
+ return FALSE;
+ }
+
+ store->ostream = tcp_stream;
+ store->istream = camel_stream_buffer_new (tcp_stream, CAMEL_STREAM_BUFFER_READ);
+
+ store->connected = TRUE;
+ store->preauthed = FALSE;
+ store->command = 0;
+
+ /* Disable Nagle - we send a lot of small requests which nagle slows down */
+ sockopt.option = CAMEL_SOCKOPT_NODELAY;
+ sockopt.value.no_delay = TRUE;
+ camel_tcp_stream_setsockopt((CamelTcpStream *)tcp_stream, &sockopt);
+
+ /* Set keepalive - needed for some hosts/router configurations, we're idle a lot */
+ sockopt.option = CAMEL_SOCKOPT_KEEPALIVE;
+ sockopt.value.keep_alive = TRUE;
+ camel_tcp_stream_setsockopt((CamelTcpStream *)tcp_stream, &sockopt);
+
+ /* Read the greeting, if any, and deal with PREAUTH */
+ if (camel_imap_store_readline (store, &buf, ex) < 0) {
+ if (store->istream) {
+ camel_object_unref (store->istream);
+ store->istream = NULL;
+ }
+
+ if (store->ostream) {
+ camel_object_unref (store->ostream);
+ store->ostream = NULL;
+ }
+
+ store->connected = FALSE;
+
+ return FALSE;
+ }
+
+ if (!strncmp(buf, "* PREAUTH", 9))
+ store->preauthed = TRUE;
+
+ if (strstr (buf, "Courier-IMAP") || getenv("CAMEL_IMAP_BRAINDAMAGED")) {
+ /* Courier-IMAP is braindamaged. So far this flag only
+ * works around the fact that Courier-IMAP is known to
+ * give invalid BODY responses seemingly because its
+ * MIME parser sucks. In any event, we can't rely on
+ * them so we always have to request the full messages
+ * rather than getting individual parts. */
+ store->braindamaged = TRUE;
+ } else if (strstr (buf, "WEB.DE") || strstr (buf, "Mail2World")) {
+ /* This is a workaround for servers which advertise
+ * IMAP4rev1 but which can sometimes subtly break in
+ * various ways if we try to use IMAP4rev1 queries.
+ *
+ * WEB.DE: when querying for HEADER.FIELDS.NOT, it
+ * returns an empty literal for the headers. Many
+ * complaints about empty message-list fields on the
+ * mailing lists and probably a few bugzilla bugs as
+ * well.
+ *
+ * Mail2World (aka NamePlanet): When requesting
+ * message info's, it ignores the fact that we
+ * requested BODY.PEEK[HEADER.FIELDS.NOT (RECEIVED)]
+ * and so the responses are incomplete. See bug #58766
+ * for details.
+ **/
+ force_imap4 = TRUE;
+ }
+
+ g_free (buf);
+
+ /* get the imap server capabilities */
+ if (!imap_get_capability (service, ex)) {
+ if (store->istream) {
+ camel_object_unref (store->istream);
+ store->istream = NULL;
+ }
+
+ if (store->ostream) {
+ camel_object_unref (store->ostream);
+ store->ostream = NULL;
+ }
+
+ store->connected = FALSE;
+ return FALSE;
+ }
+
+ if (force_imap4) {
+ store->capabilities &= ~IMAP_CAPABILITY_IMAP4REV1;
+ store->server_level = IMAP_LEVEL_IMAP4;
+ }
+
+#ifdef HAVE_SSL
+ if (ssl_mode == USE_SSL_WHEN_POSSIBLE) {
+ if (store->capabilities & IMAP_CAPABILITY_STARTTLS)
+ goto starttls;
+ } else if (ssl_mode == USE_SSL_ALWAYS) {
+ if (try_starttls) {
+ if (store->capabilities & IMAP_CAPABILITY_STARTTLS) {
+ /* attempt to toggle STARTTLS mode */
+ goto starttls;
+ } else {
+ /* server doesn't support STARTTLS, abort */
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Failed to connect to IMAP server %s in secure mode: %s"),
+ service->url->host, _("SSL/TLS extension not supported."));
+ /* we have the possibility of quitting cleanly here */
+ clean_quit = TRUE;
+ goto exception;
+ }
+ }
+ }
+#endif /* HAVE_SSL */
+
+ return TRUE;
+
+#ifdef HAVE_SSL
+ starttls:
+
+ /* as soon as we send a STARTTLS command, all hope is lost of a clean QUIT if problems arise */
+ clean_quit = FALSE;
+
+ response = camel_imap_command (store, NULL, ex, "STARTTLS");
+ if (!response) {
+ camel_object_unref (store->istream);
+ camel_object_unref (store->ostream);
+ store->istream = store->ostream = NULL;
+ return FALSE;
+ }
+
+ camel_imap_response_free_without_processing (store, response);
+
+ /* Okay, now toggle SSL/TLS mode */
+ if (camel_tcp_stream_ssl_enable_ssl (CAMEL_TCP_STREAM_SSL (tcp_stream)) == -1) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Failed to connect to IMAP server %s in secure mode: %s"),
+ service->url->host, _("SSL negotiations failed"));
+ goto exception;
+ }
+
+ /* rfc2595, section 4 states that after a successful STLS
+ command, the client MUST discard prior CAPA responses */
+ if (!imap_get_capability (service, ex)) {
+ if (store->istream) {
+ camel_object_unref (store->istream);
+ store->istream = NULL;
+ }
+
+ if (store->ostream) {
+ camel_object_unref (store->ostream);
+ store->ostream = NULL;
+ }
+
+ store->connected = FALSE;
+
+ return FALSE;
+ }
+
+ return TRUE;
+
+ exception:
+
+ if (clean_quit && store->connected) {
+ /* try to disconnect cleanly */
+ response = camel_imap_command (store, NULL, ex, "LOGOUT");
+ if (response)
+ camel_imap_response_free_without_processing (store, response);
+ }
+
+ if (store->istream) {
+ camel_object_unref (store->istream);
+ store->istream = NULL;
+ }
+
+ if (store->ostream) {
+ camel_object_unref (store->ostream);
+ store->ostream = NULL;
+ }
+
+ store->connected = FALSE;
+
+ return FALSE;
+#endif /* HAVE_SSL */
+}
+
+static gboolean
+connect_to_server_process (CamelService *service, const char *cmd, CamelException *ex)
+{
+ CamelImapStore *store = (CamelImapStore *) service;
+ CamelStream *cmd_stream;
+ int ret, i = 0;
+ char *buf;
+ char *cmd_copy;
+ char *full_cmd;
+ char *child_env[7];
+
+ /* Put full details in the environment, in case the connection
+ program needs them */
+ buf = camel_url_to_string(service->url, 0);
+ child_env[i++] = g_strdup_printf("URL=%s", buf);
+ g_free(buf);
+
+ child_env[i++] = g_strdup_printf("URLHOST=%s", service->url->host);
+ if (service->url->port)
+ child_env[i++] = g_strdup_printf("URLPORT=%d", service->url->port);
+ if (service->url->user)
+ child_env[i++] = g_strdup_printf("URLUSER=%s", service->url->user);
+ if (service->url->passwd)
+ child_env[i++] = g_strdup_printf("URLPASSWD=%s", service->url->passwd);
+ if (service->url->path)
+ child_env[i++] = g_strdup_printf("URLPATH=%s", service->url->path);
+ child_env[i] = NULL;
+
+ /* Now do %h, %u, etc. substitution in cmd */
+ buf = cmd_copy = g_strdup(cmd);
+
+ full_cmd = g_strdup("");
+
+ for(;;) {
+ char *pc;
+ char *tmp;
+ char *var;
+ int len;
+
+ pc = strchr(buf, '%');
+ ignore:
+ if (!pc) {
+ tmp = g_strdup_printf("%s%s", full_cmd, buf);
+ g_free(full_cmd);
+ full_cmd = tmp;
+ break;
+ }
+
+ len = pc - buf;
+
+ var = NULL;
+
+ switch(pc[1]) {
+ case 'h':
+ var = service->url->host;
+ break;
+ case 'u':
+ var = service->url->user;
+ break;
+ }
+ if (!var) {
+ /* If there wasn't a valid %-code, with an actual
+ variable to insert, pretend we didn't see the % */
+ pc = strchr(pc + 1, '%');
+ goto ignore;
+ }
+ tmp = g_strdup_printf("%s%.*s%s", full_cmd, len, buf, var);
+ g_free(full_cmd);
+ full_cmd = tmp;
+ buf = pc + 2;
+ }
+
+ g_free(cmd_copy);
+
+ cmd_stream = camel_stream_process_new ();
+
+ ret = camel_stream_process_connect (CAMEL_STREAM_PROCESS(cmd_stream),
+ full_cmd, (const char **)child_env);
+
+ while (i)
+ g_free(child_env[--i]);
+
+ if (ret == -1) {
+ if (errno == EINTR)
+ camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL,
+ _("Connection cancelled"));
+ else
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ _("Could not connect with command \"%s\": %s"),
+ full_cmd, g_strerror (errno));
+
+ camel_object_unref (cmd_stream);
+ g_free (full_cmd);
+ return FALSE;
+ }
+ g_free (full_cmd);
+
+ store->ostream = cmd_stream;
+ store->istream = camel_stream_buffer_new (cmd_stream, CAMEL_STREAM_BUFFER_READ);
+
+ store->connected = TRUE;
+ store->preauthed = FALSE;
+ store->command = 0;
+
+ /* Read the greeting, if any, and deal with PREAUTH */
+ if (camel_imap_store_readline (store, &buf, ex) < 0) {
+ if (store->istream) {
+ camel_object_unref (store->istream);
+ store->istream = NULL;
+ }
+
+ if (store->ostream) {
+ camel_object_unref (store->ostream);
+ store->ostream = NULL;
+ }
+
+ store->connected = FALSE;
+ return FALSE;
+ }
+ if (!strncmp(buf, "* PREAUTH", 9))
+ store->preauthed = TRUE;
+ g_free (buf);
+
+ /* get the imap server capabilities */
+ if (!imap_get_capability (service, ex)) {
+ if (store->istream) {
+ camel_object_unref (store->istream);
+ store->istream = NULL;
+ }
+
+ if (store->ostream) {
+ camel_object_unref (store->ostream);
+ store->ostream = NULL;
+ }
+
+ store->connected = FALSE;
+ return FALSE;
+ }
+
+ return TRUE;
+
+}
+
+static struct {
+ char *value;
+ int mode;
+} ssl_options[] = {
+ { "", USE_SSL_ALWAYS },
+ { "always", USE_SSL_ALWAYS },
+ { "when-possible", USE_SSL_WHEN_POSSIBLE },
+ { "never", USE_SSL_NEVER },
+ { NULL, USE_SSL_NEVER },
+};
+
+static gboolean
+connect_to_server_wrapper (CamelService *service, CamelException *ex)
+{
+ const char *command;
+#ifdef HAVE_SSL
+ const char *use_ssl;
+ int i, ssl_mode;
+#endif
+ command = camel_url_get_param (service->url, "command");
+ if (command)
+ return connect_to_server_process (service, command, ex);
+
+#ifdef HAVE_SSL
+ use_ssl = camel_url_get_param (service->url, "use_ssl");
+ if (use_ssl) {
+ for (i = 0; ssl_options[i].value; i++)
+ if (!strcmp (ssl_options[i].value, use_ssl))
+ break;
+ ssl_mode = ssl_options[i].mode;
+ } else
+ ssl_mode = USE_SSL_NEVER;
+
+ if (ssl_mode == USE_SSL_ALWAYS) {
+ /* First try the ssl port */
+ if (!connect_to_server (service, ssl_mode, FALSE, ex)) {
+ if (camel_exception_get_id (ex) == CAMEL_EXCEPTION_SERVICE_UNAVAILABLE) {
+ /* The ssl port seems to be unavailable, lets try STARTTLS */
+ camel_exception_clear (ex);
+ return connect_to_server (service, ssl_mode, TRUE, ex);
+ } else {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+ } else if (ssl_mode == USE_SSL_WHEN_POSSIBLE) {
+ /* If the server supports STARTTLS, use it */
+ return connect_to_server (service, ssl_mode, TRUE, ex);
+ } else {
+ /* User doesn't care about SSL */
+ return connect_to_server (service, ssl_mode, FALSE, ex);
+ }
+#else
+ return connect_to_server (service, USE_SSL_NEVER, FALSE, ex);
+#endif
+}
+
+extern CamelServiceAuthType camel_imap_password_authtype;
+
+static GList *
+query_auth_types (CamelService *service, CamelException *ex)
+{
+ CamelImapStore *store = CAMEL_IMAP_STORE (service);
+ CamelServiceAuthType *authtype;
+ GList *sasl_types, *t, *next;
+ gboolean connected;
+
+ if (!camel_disco_store_check_online (CAMEL_DISCO_STORE (store), ex))
+ return NULL;
+
+ CAMEL_SERVICE_LOCK (store, connect_lock);
+ connected = connect_to_server_wrapper (service, ex);
+ CAMEL_SERVICE_UNLOCK (store, connect_lock);
+ if (!connected)
+ return NULL;
+
+ sasl_types = camel_sasl_authtype_list (FALSE);
+ for (t = sasl_types; t; t = next) {
+ authtype = t->data;
+ next = t->next;
+
+ if (!g_hash_table_lookup (store->authtypes, authtype->authproto)) {
+ sasl_types = g_list_remove_link (sasl_types, t);
+ g_list_free_1 (t);
+ }
+ }
+
+ return g_list_prepend (sasl_types, &camel_imap_password_authtype);
+}
+
+/* folder_name is path name */
+static CamelFolderInfo *
+imap_build_folder_info(CamelImapStore *imap_store, const char *folder_name)
+{
+ CamelURL *url;
+ const char *name;
+ CamelFolderInfo *fi;
+
+ fi = g_malloc0(sizeof(*fi));
+
+ fi->full_name = g_strdup(folder_name);
+ fi->unread = 0;
+ fi->total = 0;
+
+ url = camel_url_new (imap_store->base_url, NULL);
+ g_free (url->path);
+ url->path = g_strdup_printf ("/%s", folder_name);
+ fi->uri = camel_url_to_string (url, CAMEL_URL_HIDE_ALL);
+ camel_url_free(url);
+ name = strrchr (fi->full_name, '/');
+ if (name == NULL)
+ name = fi->full_name;
+ else
+ name++;
+ fi->name = g_strdup (name);
+
+ return fi;
+}
+
+static void
+imap_folder_effectively_unsubscribed(CamelImapStore *imap_store,
+ const char *folder_name, CamelException *ex)
+{
+ CamelFolderInfo *fi;
+ CamelStoreInfo *si;
+
+ si = camel_store_summary_path((CamelStoreSummary *)imap_store->summary, folder_name);
+ if (si) {
+ if (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) {
+ si->flags &= ~CAMEL_STORE_INFO_FOLDER_SUBSCRIBED;
+ camel_store_summary_touch((CamelStoreSummary *)imap_store->summary);
+ camel_store_summary_save((CamelStoreSummary *)imap_store->summary);
+ }
+ camel_store_summary_info_free((CamelStoreSummary *)imap_store->summary, si);
+ }
+
+ if (imap_store->renaming) {
+ /* we don't need to emit a "folder_unsubscribed" signal
+ if we are in the process of renaming folders, so we
+ are done here... */
+ return;
+
+ }
+
+ fi = imap_build_folder_info(imap_store, folder_name);
+ camel_object_trigger_event (CAMEL_OBJECT (imap_store), "folder_unsubscribed", fi);
+ camel_folder_info_free (fi);
+}
+
+static void
+imap_forget_folder (CamelImapStore *imap_store, const char *folder_name, CamelException *ex)
+{
+ CamelFolderSummary *summary;
+ CamelImapMessageCache *cache;
+ char *summary_file, *state_file;
+ char *journal_file;
+ char *folder_dir, *storage_path;
+ CamelFolderInfo *fi;
+ const char *name;
+
+ name = strrchr (folder_name, imap_store->dir_sep);
+ if (name)
+ name++;
+ else
+ name = folder_name;
+
+ storage_path = g_strdup_printf ("%s/folders", imap_store->storage_path);
+ folder_dir = e_path_to_physical (storage_path, folder_name);
+ g_free (storage_path);
+ if (access (folder_dir, F_OK) != 0) {
+ g_free (folder_dir);
+ goto event;
+ }
+
+ summary_file = g_strdup_printf ("%s/summary", folder_dir);
+ summary = camel_imap_summary_new (summary_file);
+ if (!summary) {
+ g_free (summary_file);
+ g_free (folder_dir);
+ goto event;
+ }
+
+ cache = camel_imap_message_cache_new (folder_dir, summary, ex);
+ if (cache)
+ camel_imap_message_cache_clear (cache);
+
+ camel_object_unref (cache);
+ camel_object_unref (summary);
+
+ unlink (summary_file);
+ g_free (summary_file);
+
+ journal_file = g_strdup_printf ("%s/journal", folder_dir);
+ unlink (journal_file);
+ g_free (journal_file);
+
+ state_file = g_strdup_printf ("%s/cmeta", folder_dir);
+ unlink (state_file);
+ g_free (state_file);
+
+ rmdir (folder_dir);
+ g_free (folder_dir);
+
+ event:
+
+ camel_store_summary_remove_path((CamelStoreSummary *)imap_store->summary, folder_name);
+ camel_store_summary_save((CamelStoreSummary *)imap_store->summary);
+
+ fi = imap_build_folder_info(imap_store, folder_name);
+ camel_object_trigger_event (CAMEL_OBJECT (imap_store), "folder_deleted", fi);
+ camel_folder_info_free (fi);
+}
+
+static gboolean
+imap_check_folder_still_extant (CamelImapStore *imap_store, const char *full_name,
+ CamelException *ex)
+{
+ CamelImapResponse *response;
+
+ response = camel_imap_command (imap_store, NULL, ex, "LIST \"\" %F",
+ full_name);
+
+ if (response) {
+ gboolean stillthere = response->untagged->len != 0;
+
+ camel_imap_response_free_without_processing (imap_store, response);
+
+ return stillthere;
+ }
+
+ /* if the command was rejected, there must be some other error,
+ assume it worked so we dont blow away the folder unecessarily */
+ return TRUE;
+}
+
+/* This is a little 'hack' to avoid the deadlock conditions that would otherwise
+ ensue when calling camel_folder_refresh_info from inside a lock */
+/* NB: on second thougts this is probably not entirely safe, but it'll do for now */
+/* No, its definetly not safe. So its been changed to copy the folders first */
+/* the alternative is to:
+ make the camel folder->lock recursive (which should probably be done)
+ or remove it from camel_folder_refresh_info, and use another locking mechanism */
+/* also see get_folder_info_online() for the same hack repeated */
+static void
+imap_store_refresh_folders (CamelImapStore *store, CamelException *ex)
+{
+ GPtrArray *folders;
+ int i;
+
+ folders = camel_object_bag_list(CAMEL_STORE (store)->folders);
+
+ for (i = 0; i <folders->len; i++) {
+ CamelFolder *folder = folders->pdata[i];
+
+ /* NB: we can have vtrash folders also in our store ... bit hacky */
+ if (!CAMEL_IS_IMAP_FOLDER(folder)) {
+ camel_object_unref(folder);
+ continue;
+ }
+
+ CAMEL_IMAP_FOLDER (folder)->need_rescan = TRUE;
+ if (!camel_exception_is_set(ex))
+ CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(folder))->refresh_info(folder, ex);
+
+ if (camel_exception_is_set (ex) &&
+ imap_check_folder_still_extant (store, folder->full_name, ex) == FALSE) {
+ gchar *namedup;
+
+ /* the folder was deleted (may happen when we come back online
+ * after being offline */
+
+ namedup = g_strdup (folder->full_name);
+ camel_object_unref(folder);
+ imap_folder_effectively_unsubscribed (store, namedup, ex);
+ imap_forget_folder (store, namedup, ex);
+ g_free (namedup);
+ } else
+ camel_object_unref(folder);
+ }
+
+ g_ptr_array_free (folders, TRUE);
+}
+
+static gboolean
+try_auth (CamelImapStore *store, const char *mech, CamelException *ex)
+{
+ CamelSasl *sasl;
+ CamelImapResponse *response;
+ char *resp;
+ char *sasl_resp;
+
+ CAMEL_SERVICE_ASSERT_LOCKED (store, connect_lock);
+
+ response = camel_imap_command (store, NULL, ex, "AUTHENTICATE %s", mech);
+ if (!response)
+ return FALSE;
+
+ sasl = camel_sasl_new ("imap", mech, CAMEL_SERVICE (store));
+ while (!camel_sasl_authenticated (sasl)) {
+ resp = camel_imap_response_extract_continuation (store, response, ex);
+ if (!resp)
+ goto lose;
+
+ sasl_resp = camel_sasl_challenge_base64 (sasl, imap_next_word (resp), ex);
+ g_free (resp);
+ if (camel_exception_is_set (ex))
+ goto break_and_lose;
+
+ response = camel_imap_command_continuation (store, sasl_resp, strlen (sasl_resp), ex);
+ g_free (sasl_resp);
+ if (!response)
+ goto lose;
+ }
+
+ resp = camel_imap_response_extract_continuation (store, response, NULL);
+ if (resp) {
+ /* Oops. SASL claims we're done, but the IMAP server
+ * doesn't think so...
+ */
+ g_free (resp);
+ goto lose;
+ }
+
+ camel_object_unref (sasl);
+
+ return TRUE;
+
+ break_and_lose:
+ /* Get the server out of "waiting for continuation data" mode. */
+ response = camel_imap_command_continuation (store, "*", 1, NULL);
+ if (response)
+ camel_imap_response_free (store, response);
+
+ lose:
+ if (!camel_exception_is_set (ex)) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
+ _("Bad authentication response from server."));
+ }
+
+ camel_object_unref (sasl);
+
+ return FALSE;
+}
+
+static gboolean
+imap_auth_loop (CamelService *service, CamelException *ex)
+{
+ CamelImapStore *store = CAMEL_IMAP_STORE (service);
+ CamelSession *session = camel_service_get_session (service);
+ CamelServiceAuthType *authtype = NULL;
+ CamelImapResponse *response;
+ char *errbuf = NULL;
+ gboolean authenticated = FALSE;
+ const char *auth_domain;
+
+ CAMEL_SERVICE_ASSERT_LOCKED (store, connect_lock);
+ auth_domain = camel_url_get_param (service->url, "auth-domain");
+
+ if (store->preauthed) {
+ if (camel_verbose_debug)
+ fprintf(stderr, "Server %s has preauthenticated us.\n",
+ service->url->host);
+ return TRUE;
+ }
+
+ if (service->url->authmech) {
+ if (!g_hash_table_lookup (store->authtypes, service->url->authmech)) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
+ _("IMAP server %s does not support requested "
+ "authentication type %s"),
+ service->url->host,
+ service->url->authmech);
+ return FALSE;
+ }
+
+ authtype = camel_sasl_authtype (service->url->authmech);
+ if (!authtype) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
+ _("No support for authentication type %s"),
+ service->url->authmech);
+ return FALSE;
+ }
+
+ if (!authtype->need_password) {
+ authenticated = try_auth (store, authtype->authproto, ex);
+ if (!authenticated)
+ return FALSE;
+ }
+ }
+
+ while (!authenticated) {
+ if (errbuf) {
+ /* We need to un-cache the password before prompting again */
+ camel_session_forget_password (session, service, auth_domain, "password", ex);
+ g_free (service->url->passwd);
+ service->url->passwd = NULL;
+ }
+
+ if (!service->url->passwd) {
+ char *prompt;
+
+ prompt = g_strdup_printf (_("%sPlease enter the IMAP "
+ "password for %s@%s"),
+ errbuf ? errbuf : "",
+ service->url->user,
+ service->url->host);
+ service->url->passwd =
+ camel_session_get_password (session, service, auth_domain,
+ prompt, "password", CAMEL_SESSION_PASSWORD_SECRET, ex);
+ g_free (prompt);
+ g_free (errbuf);
+ errbuf = NULL;
+
+ if (!service->url->passwd) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL,
+ _("You didn't enter a password."));
+ return FALSE;
+ }
+ }
+
+ if (!store->connected) {
+ /* Some servers (eg, courier) will disconnect on
+ * a bad password. So reconnect here.
+ */
+ if (!connect_to_server_wrapper (service, ex))
+ return FALSE;
+ }
+
+ if (authtype)
+ authenticated = try_auth (store, authtype->authproto, ex);
+ else {
+ response = camel_imap_command (store, NULL, ex,
+ "LOGIN %S %S",
+ service->url->user,
+ service->url->passwd);
+ if (response) {
+ camel_imap_response_free (store, response);
+ authenticated = TRUE;
+ }
+ }
+ if (!authenticated) {
+ if (camel_exception_get_id(ex) == CAMEL_EXCEPTION_USER_CANCEL)
+ return FALSE;
+
+ errbuf = g_strdup_printf (_("Unable to authenticate "
+ "to IMAP server.\n%s\n\n"),
+ camel_exception_get_description (ex));
+ camel_exception_clear (ex);
+ }
+ }
+
+ return TRUE;
+}
+
+static gboolean
+can_work_offline (CamelDiscoStore *disco_store)
+{
+ CamelImapStore *store = CAMEL_IMAP_STORE (disco_store);
+
+ return camel_store_summary_count((CamelStoreSummary *)store->summary) != 0;
+}
+
+static gboolean
+imap_connect_online (CamelService *service, CamelException *ex)
+{
+ CamelImapStore *store = CAMEL_IMAP_STORE (service);
+ CamelDiscoStore *disco_store = CAMEL_DISCO_STORE (service);
+ CamelImapResponse *response;
+ /*struct _namespaces *namespaces;*/
+ char *result, *name, *path;
+ int i;
+ size_t len;
+ CamelImapStoreNamespace *ns;
+
+ CAMEL_SERVICE_LOCK (store, connect_lock);
+ if (!connect_to_server_wrapper (service, ex) ||
+ !imap_auth_loop (service, ex)) {
+ CAMEL_SERVICE_UNLOCK (store, connect_lock);
+ camel_service_disconnect (service, TRUE, NULL);
+ return FALSE;
+ }
+
+ /* Get namespace and hierarchy separator */
+ if ((store->capabilities & IMAP_CAPABILITY_NAMESPACE) &&
+ !(store->parameters & IMAP_PARAM_OVERRIDE_NAMESPACE)) {
+ response = camel_imap_command (store, NULL, ex, "NAMESPACE");
+ if (!response)
+ goto done;
+
+ result = camel_imap_response_extract (store, response, "NAMESPACE", ex);
+ if (!result)
+ goto done;
+
+#if 0
+ /* new code... */
+ namespaces = imap_parse_namespace_response (result);
+ imap_namespaces_destroy (namespaces);
+ /* end new code */
+#endif
+
+ name = camel_strstrcase (result, "NAMESPACE ((");
+ if (name) {
+ char *sep;
+
+ name += 12;
+ store->namespace = imap_parse_string ((const char **) &name, &len);
+ if (name && *name++ == ' ') {
+ sep = imap_parse_string ((const char **) &name, &len);
+ if (sep) {
+ store->dir_sep = *sep;
+ g_free (sep);
+ }
+ }
+ }
+ g_free (result);
+ }
+
+ if (!store->namespace)
+ store->namespace = g_strdup ("");
+
+ if (!store->dir_sep) {
+ if (store->server_level >= IMAP_LEVEL_IMAP4REV1) {
+ /* This idiom means "tell me the hierarchy separator
+ * for the given path, even if that path doesn't exist.
+ */
+ response = camel_imap_command (store, NULL, ex,
+ "LIST %S \"\"",
+ store->namespace);
+ } else {
+ /* Plain IMAP4 doesn't have that idiom, so we fall back
+ * to "tell me about this folder", which will fail if
+ * the folder doesn't exist (eg, if namespace is "").
+ */
+ response = camel_imap_command (store, NULL, ex,
+ "LIST \"\" %S",
+ store->namespace);
+ }
+ if (!response)
+ goto done;
+
+ result = camel_imap_response_extract (store, response, "LIST", NULL);
+ if (result) {
+ imap_parse_list_response (store, result, NULL, &store->dir_sep, NULL);
+ g_free (result);
+ }
+ if (!store->dir_sep) {
+ store->dir_sep = '/'; /* Guess */
+ }
+ }
+
+ /* canonicalize the namespace to end with dir_sep */
+ len = strlen (store->namespace);
+ if (len && store->namespace[len - 1] != store->dir_sep) {
+ gchar *tmp;
+
+ tmp = g_strdup_printf ("%s%c", store->namespace, store->dir_sep);
+ g_free (store->namespace);
+ store->namespace = tmp;
+ }
+
+ ns = camel_imap_store_summary_namespace_new(store->summary, store->namespace, store->dir_sep);
+ camel_imap_store_summary_namespace_set(store->summary, ns);
+
+ if (CAMEL_STORE (store)->flags & CAMEL_STORE_SUBSCRIPTIONS) {
+ gboolean haveinbox = FALSE;
+ GPtrArray *folders;
+ char *pattern;
+
+ /* this pre-fills the summary, and checks that lsub is useful */
+ folders = g_ptr_array_new ();
+ pattern = g_strdup_printf ("%s*", store->namespace);
+ get_folders_online (store, pattern, folders, TRUE, ex);
+ g_free (pattern);
+
+ for (i = 0; i < folders->len; i++) {
+ CamelFolderInfo *fi = folders->pdata[i];
+
+ haveinbox = haveinbox || !g_ascii_strcasecmp (fi->full_name, "INBOX");
+
+ if (fi->flags & (CAMEL_IMAP_FOLDER_MARKED | CAMEL_IMAP_FOLDER_UNMARKED))
+ store->capabilities |= IMAP_CAPABILITY_useful_lsub;
+ camel_folder_info_free (fi);
+ }
+
+ /* if the namespace is under INBOX, check INBOX explicitly */
+ if (!g_ascii_strncasecmp (store->namespace, "INBOX", 5) && !camel_exception_is_set (ex)) {
+ gboolean just_subscribed = FALSE;
+ gboolean need_subscribe = FALSE;
+
+ recheck:
+ g_ptr_array_set_size (folders, 0);
+ get_folders_online (store, "INBOX", folders, TRUE, ex);
+
+ for (i = 0; i < folders->len; i++) {
+ CamelFolderInfo *fi = folders->pdata[i];
+
+ /* this should always be TRUE if folders->len > 0 */
+ if (!g_ascii_strcasecmp (fi->full_name, "INBOX")) {
+ haveinbox = TRUE;
+
+ /* if INBOX is marked as \NoSelect then it is probably
+ because it has not been subscribed to */
+ if (!need_subscribe)
+ need_subscribe = fi->flags & CAMEL_FOLDER_NOSELECT;
+ }
+
+ camel_folder_info_free (fi);
+ }
+
+ need_subscribe = !haveinbox || need_subscribe;
+ if (need_subscribe && !just_subscribed && !camel_exception_is_set (ex)) {
+ /* in order to avoid user complaints, force a subscription to INBOX */
+ response = camel_imap_command (store, NULL, ex, "SUBSCRIBE INBOX");
+ if (response != NULL) {
+ /* force a re-check which will pre-fill the summary and
+ also get any folder flags present on the INBOX */
+ camel_imap_response_free (store, response);
+ just_subscribed = TRUE;
+ goto recheck;
+ }
+ }
+ }
+
+ g_ptr_array_free (folders, TRUE);
+ }
+
+ path = g_strdup_printf ("%s/journal", store->storage_path);
+ disco_store->diary = camel_disco_diary_new (disco_store, path, ex);
+ g_free (path);
+
+ done:
+ /* save any changes we had */
+ camel_store_summary_save((CamelStoreSummary *)store->summary);
+
+ CAMEL_SERVICE_UNLOCK (store, connect_lock);
+
+ if (camel_exception_is_set (ex))
+ camel_service_disconnect (service, TRUE, NULL);
+ else if (camel_disco_diary_empty (disco_store->diary))
+ imap_store_refresh_folders (store, ex);
+
+ return !camel_exception_is_set (ex);
+}
+
+static gboolean
+imap_connect_offline (CamelService *service, CamelException *ex)
+{
+ CamelImapStore *store = CAMEL_IMAP_STORE (service);
+ CamelDiscoStore *disco_store = CAMEL_DISCO_STORE (service);
+ char *path;
+
+ path = g_strdup_printf ("%s/journal", store->storage_path);
+ disco_store->diary = camel_disco_diary_new (disco_store, path, ex);
+ g_free (path);
+ if (!disco_store->diary)
+ return FALSE;
+
+ imap_store_refresh_folders (store, ex);
+
+ store->connected = !camel_exception_is_set (ex);
+ return store->connected;
+}
+
+static gboolean
+imap_disconnect_offline (CamelService *service, gboolean clean, CamelException *ex)
+{
+ CamelImapStore *store = CAMEL_IMAP_STORE (service);
+ CamelDiscoStore *disco = CAMEL_DISCO_STORE (service);
+
+ store->connected = FALSE;
+ if (store->current_folder) {
+ camel_object_unref (store->current_folder);
+ store->current_folder = NULL;
+ }
+
+ if (store->authtypes) {
+ g_hash_table_foreach_remove (store->authtypes,
+ free_key, NULL);
+ g_hash_table_destroy (store->authtypes);
+ store->authtypes = NULL;
+ }
+
+ if (store->namespace && !(store->parameters & IMAP_PARAM_OVERRIDE_NAMESPACE)) {
+ g_free (store->namespace);
+ store->namespace = NULL;
+ }
+
+ if (disco->diary) {
+ camel_object_unref (disco->diary);
+ disco->diary = NULL;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+imap_disconnect_online (CamelService *service, gboolean clean, CamelException *ex)
+{
+ CamelImapStore *store = CAMEL_IMAP_STORE (service);
+ CamelImapResponse *response;
+
+ if (store->connected && clean) {
+ response = camel_imap_command (store, NULL, NULL, "LOGOUT");
+ camel_imap_response_free (store, response);
+ }
+
+ if (store->istream) {
+ camel_object_unref (store->istream);
+ store->istream = NULL;
+ }
+
+ if (store->ostream) {
+ camel_object_unref (store->ostream);
+ store->ostream = NULL;
+ }
+
+ imap_disconnect_offline (service, clean, ex);
+
+ return TRUE;
+}
+
+
+static gboolean
+imap_summary_is_dirty (CamelFolderSummary *summary)
+{
+ CamelMessageInfo *info;
+ int max, i;
+
+ max = camel_folder_summary_count (summary);
+ for (i = 0; i < max; i++) {
+ info = camel_folder_summary_index (summary, i);
+ if (info && (info->flags & CAMEL_MESSAGE_FOLDER_FLAGGED))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+imap_noop (CamelStore *store, CamelException *ex)
+{
+ CamelImapStore *imap_store = (CamelImapStore *) store;
+ CamelDiscoStore *disco = (CamelDiscoStore *) store;
+ CamelImapResponse *response;
+ CamelFolder *current_folder;
+
+ if (camel_disco_store_status (disco) != CAMEL_DISCO_STORE_ONLINE)
+ return;
+
+ CAMEL_SERVICE_LOCK (imap_store, connect_lock);
+
+ current_folder = imap_store->current_folder;
+ if (current_folder && imap_summary_is_dirty (current_folder->summary)) {
+ /* let's sync the flags instead. NB: must avoid folder lock */
+ ((CamelFolderClass *)((CamelObject *)current_folder)->klass)->sync(current_folder, FALSE, ex);
+ } else {
+ response = camel_imap_command (imap_store, NULL, ex, "NOOP");
+ if (response)
+ camel_imap_response_free (imap_store, response);
+ }
+
+ CAMEL_SERVICE_UNLOCK (imap_store, connect_lock);
+}
+
+static CamelFolder *
+imap_get_trash(CamelStore *store, CamelException *ex)
+{
+ CamelFolder *folder = CAMEL_STORE_CLASS(parent_class)->get_trash(store, ex);
+
+ if (folder) {
+ char *state = g_build_filename(((CamelImapStore *)store)->storage_path, "system", "Trash.cmeta", NULL);
+
+ camel_object_set(folder, NULL, CAMEL_OBJECT_STATE_FILE, state, NULL);
+ g_free(state);
+ /* no defaults? */
+ camel_object_state_read(folder);
+ }
+
+ return folder;
+}
+
+static CamelFolder *
+imap_get_junk(CamelStore *store, CamelException *ex)
+{
+ CamelFolder *folder = CAMEL_STORE_CLASS(parent_class)->get_junk(store, ex);
+
+ if (folder) {
+ char *state = g_build_filename(((CamelImapStore *)store)->storage_path, "system", "Junk.cmeta", NULL);
+
+ camel_object_set(folder, NULL, CAMEL_OBJECT_STATE_FILE, state, NULL);
+ g_free(state);
+ /* no defaults? */
+ camel_object_state_read(folder);
+ }
+
+ return folder;
+}
+
+static guint
+hash_folder_name (gconstpointer key)
+{
+ if (g_ascii_strcasecmp (key, "INBOX") == 0)
+ return g_str_hash ("INBOX");
+ else
+ return g_str_hash (key);
+}
+
+static gint
+compare_folder_name (gconstpointer a, gconstpointer b)
+{
+ gconstpointer aname = a, bname = b;
+
+ if (g_ascii_strcasecmp (a, "INBOX") == 0)
+ aname = "INBOX";
+ if (g_ascii_strcasecmp (b, "INBOX") == 0)
+ bname = "INBOX";
+ return g_str_equal (aname, bname);
+}
+
+struct imap_status_item {
+ struct imap_status_item *next;
+ char *name;
+ guint32 value;
+};
+
+static void
+imap_status_item_free (struct imap_status_item *items)
+{
+ struct imap_status_item *next;
+
+ while (items != NULL) {
+ next = items->next;
+ g_free (items->name);
+ g_free (items);
+ items = next;
+ }
+}
+
+static struct imap_status_item *
+get_folder_status (CamelImapStore *imap_store, const char *folder_name, const char *type)
+{
+ struct imap_status_item *items, *item, *tail;
+ CamelImapResponse *response;
+ char *status, *name, *p;
+
+ /* FIXME: we assume the server is STATUS-capable */
+
+ response = camel_imap_command (imap_store, NULL, NULL,
+ "STATUS %F (%s)",
+ folder_name,
+ type);
+
+ if (!response) {
+ CamelException ex;
+
+ camel_exception_init (&ex);
+ if (imap_check_folder_still_extant (imap_store, folder_name, &ex) == FALSE) {
+ imap_folder_effectively_unsubscribed (imap_store, folder_name, &ex);
+ imap_forget_folder (imap_store, folder_name, &ex);
+ }
+ camel_exception_clear (&ex);
+ return NULL;
+ }
+
+ if (!(status = camel_imap_response_extract (imap_store, response, "STATUS", NULL)))
+ return NULL;
+
+ p = status + strlen ("* STATUS ");
+ while (*p == ' ')
+ p++;
+
+ /* skip past the mailbox string */
+ if (*p == '"') {
+ p++;
+ while (*p != '\0') {
+ if (*p == '"' && p[-1] != '\\') {
+ p++;
+ break;
+ }
+
+ p++;
+ }
+ } else {
+ while (*p != ' ')
+ p++;
+ }
+
+ while (*p == ' ')
+ p++;
+
+ if (*p++ != '(') {
+ g_free (status);
+ return NULL;
+ }
+
+ while (*p == ' ')
+ p++;
+
+ if (*p == ')') {
+ g_free (status);
+ return NULL;
+ }
+
+ items = NULL;
+ tail = (struct imap_status_item *) &items;
+
+ do {
+ name = p;
+ while (*p != ' ')
+ p++;
+
+ item = g_malloc (sizeof (struct imap_status_item));
+ item->next = NULL;
+ item->name = g_strndup (name, p - name);
+ item->value = strtoul (p, &p, 10);
+
+ tail->next = item;
+ tail = item;
+
+ while (*p == ' ')
+ p++;
+ } while (*p != ')');
+
+ g_free (status);
+
+ return items;
+}
+
+static CamelFolder *
+get_folder_online (CamelStore *store, const char *folder_name, guint32 flags, CamelException *ex)
+{
+ CamelImapStore *imap_store = CAMEL_IMAP_STORE (store);
+ CamelImapResponse *response;
+ CamelFolder *new_folder;
+ char *folder_dir, *storage_path;
+
+ if (!camel_imap_store_connected (imap_store, ex))
+ return NULL;
+
+ if (!g_ascii_strcasecmp (folder_name, "INBOX"))
+ folder_name = "INBOX";
+
+ /* Lock around the whole lot to check/create atomically */
+ CAMEL_SERVICE_LOCK (imap_store, connect_lock);
+ if (imap_store->current_folder) {
+ camel_object_unref (imap_store->current_folder);
+ imap_store->current_folder = NULL;
+ }
+ response = camel_imap_command (imap_store, NULL, ex, "SELECT %F", folder_name);
+ if (!response) {
+ char *folder_real, *parent_name, *parent_real;
+ const char *c;
+
+ if (camel_exception_get_id(ex) == CAMEL_EXCEPTION_USER_CANCEL) {
+ CAMEL_SERVICE_UNLOCK (imap_store, connect_lock);
+ return NULL;
+ }
+
+ camel_exception_clear (ex);
+
+ if (!(flags & CAMEL_STORE_FOLDER_CREATE)) {
+ CAMEL_SERVICE_UNLOCK (imap_store, connect_lock);
+ camel_exception_setv (ex, CAMEL_EXCEPTION_STORE_NO_FOLDER,
+ _("No such folder %s"), folder_name);
+ return NULL;
+ }
+
+ if ((parent_name = strrchr (folder_name, '/'))) {
+ parent_name = g_strndup (folder_name, parent_name - folder_name);
+ parent_real = camel_imap_store_summary_path_to_full (imap_store->summary, parent_name, imap_store->dir_sep);
+ } else {
+ parent_real = NULL;
+ }
+
+ c = parent_name ? parent_name : folder_name;
+ while (*c && *c != imap_store->dir_sep && !strchr ("#%*", *c))
+ c++;
+
+ if (*c != '\0') {
+ CAMEL_SERVICE_UNLOCK (imap_store, connect_lock);
+ camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_INVALID_PATH,
+ _("The folder name \"%s\" is invalid because it contains the character \"%c\""),
+ folder_name, *c);
+ g_free (parent_name);
+ g_free (parent_real);
+ return NULL;
+ }
+
+ if (parent_real != NULL) {
+ gboolean need_convert = FALSE;
+ char *resp, *thisone;
+ guint32 flags;
+ int i;
+
+ if (!(response = camel_imap_command (imap_store, NULL, ex, "LIST \"\" %S", parent_real))) {
+ CAMEL_SERVICE_UNLOCK (imap_store, connect_lock);
+ g_free (parent_name);
+ g_free (parent_real);
+ return NULL;
+ }
+
+ /* FIXME: does not handle unexpected circumstances very well */
+ for (i = 0; i < response->untagged->len; i++) {
+ resp = response->untagged->pdata[i];
+
+ if (!imap_parse_list_response (imap_store, resp, &flags, NULL, &thisone))
+ continue;
+
+ if (!strcmp (parent_name, thisone)) {
+ if (flags & CAMEL_FOLDER_NOINFERIORS)
+ need_convert = TRUE;
+ }
+
+ g_free (thisone);
+ }
+
+ camel_imap_response_free (imap_store, response);
+
+ /* if not, check if we can delete it and recreate it */
+ if (need_convert) {
+ struct imap_status_item *items, *item;
+ guint32 messages = 0;
+ CamelException lex;
+ char *name;
+
+ item = items = get_folder_status (imap_store, parent_name, "MESSAGES");
+ while (item != NULL) {
+ if (!g_ascii_strcasecmp (item->name, "MESSAGES")) {
+ messages = item->value;
+ break;
+ }
+
+ item = item->next;
+ }
+
+ imap_status_item_free (items);
+
+ if (messages > 0) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_FOLDER_INVALID_STATE,
+ _("The parent folder is not allowed to contain subfolders"));
+ CAMEL_SERVICE_UNLOCK (imap_store, connect_lock);
+ g_free (parent_name);
+ g_free (parent_real);
+ return NULL;
+ }
+
+ /* delete the old parent and recreate it */
+ camel_exception_init (&lex);
+ delete_folder (store, parent_name, &lex);
+ if (camel_exception_is_set (&lex)) {
+ CAMEL_SERVICE_UNLOCK (imap_store, connect_lock);
+ camel_exception_xfer (ex, &lex);
+ g_free (parent_name);
+ g_free (parent_real);
+ return NULL;
+ }
+
+ /* add the dirsep to the end of parent_name */
+ name = g_strdup_printf ("%s%c", parent_real, imap_store->dir_sep);
+ response = camel_imap_command (imap_store, NULL, ex, "CREATE %S",
+ name);
+ g_free (name);
+
+ if (!response) {
+ CAMEL_SERVICE_UNLOCK (imap_store, connect_lock);
+ g_free (parent_name);
+ g_free (parent_real);
+ return NULL;
+ } else
+ camel_imap_response_free (imap_store, response);
+ }
+
+ g_free (parent_real);
+ }
+
+ g_free (parent_name);
+
+ folder_real = camel_imap_store_summary_path_to_full(imap_store->summary, folder_name, imap_store->dir_sep);
+ response = camel_imap_command (imap_store, NULL, ex, "CREATE %S", folder_real);
+
+ if (response) {
+ camel_imap_store_summary_add_from_full(imap_store->summary, folder_real, imap_store->dir_sep);
+
+ camel_imap_response_free (imap_store, response);
+
+ response = camel_imap_command (imap_store, NULL, NULL, "SELECT %F", folder_name);
+ }
+ g_free(folder_real);
+ if (!response) {
+ CAMEL_SERVICE_UNLOCK (imap_store, connect_lock);
+ return NULL;
+ }
+ } else if (flags & CAMEL_STORE_FOLDER_EXCL) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot create folder `%s': folder exists."),
+ folder_name);
+
+ camel_imap_response_free_without_processing (imap_store, response);
+
+ CAMEL_SERVICE_UNLOCK (imap_store, connect_lock);
+
+ return NULL;
+ }
+
+ storage_path = g_strdup_printf("%s/folders", imap_store->storage_path);
+ folder_dir = e_path_to_physical (storage_path, folder_name);
+ g_free(storage_path);
+ new_folder = camel_imap_folder_new (store, folder_name, folder_dir, ex);
+ g_free (folder_dir);
+ if (new_folder) {
+ CamelException local_ex;
+
+ imap_store->current_folder = new_folder;
+ camel_object_ref (new_folder);
+ camel_exception_init (&local_ex);
+ camel_imap_folder_selected (new_folder, response, &local_ex);
+
+ if (camel_exception_is_set (&local_ex)) {
+ camel_exception_xfer (ex, &local_ex);
+ camel_object_unref (imap_store->current_folder);
+ imap_store->current_folder = NULL;
+ camel_object_unref (new_folder);
+ new_folder = NULL;
+ }
+ }
+ camel_imap_response_free_without_processing (imap_store, response);
+
+ CAMEL_SERVICE_UNLOCK (imap_store, connect_lock);
+
+ return new_folder;
+}
+
+static CamelFolder *
+get_folder_offline (CamelStore *store, const char *folder_name,
+ guint32 flags, CamelException *ex)
+{
+ CamelImapStore *imap_store = CAMEL_IMAP_STORE (store);
+ CamelFolder *new_folder;
+ char *folder_dir, *storage_path;
+
+ if (!imap_store->connected &&
+ !camel_service_connect (CAMEL_SERVICE (store), ex))
+ return NULL;
+
+ if (!g_ascii_strcasecmp (folder_name, "INBOX"))
+ folder_name = "INBOX";
+
+ storage_path = g_strdup_printf("%s/folders", imap_store->storage_path);
+ folder_dir = e_path_to_physical (storage_path, folder_name);
+ g_free(storage_path);
+ if (!folder_dir || access (folder_dir, F_OK) != 0) {
+ g_free (folder_dir);
+ camel_exception_setv (ex, CAMEL_EXCEPTION_STORE_NO_FOLDER,
+ _("No such folder %s"), folder_name);
+ return NULL;
+ }
+
+ new_folder = camel_imap_folder_new (store, folder_name, folder_dir, ex);
+ g_free (folder_dir);
+
+ return new_folder;
+}
+
+static void
+delete_folder (CamelStore *store, const char *folder_name, CamelException *ex)
+{
+ CamelImapStore *imap_store = CAMEL_IMAP_STORE (store);
+ CamelImapResponse *response;
+
+ if (!camel_disco_store_check_online (CAMEL_DISCO_STORE (store), ex))
+ return;
+
+ /* make sure this folder isn't currently SELECTed */
+ response = camel_imap_command (imap_store, NULL, ex, "SELECT INBOX");
+ if (response) {
+ camel_imap_response_free_without_processing (imap_store, response);
+
+ CAMEL_SERVICE_LOCK (imap_store, connect_lock);
+
+ if (imap_store->current_folder)
+ camel_object_unref (imap_store->current_folder);
+ /* no need to actually create a CamelFolder for INBOX */
+ imap_store->current_folder = NULL;
+
+ CAMEL_SERVICE_UNLOCK (imap_store, connect_lock);
+ } else
+ return;
+
+ response = camel_imap_command (imap_store, NULL, ex, "DELETE %F",
+ folder_name);
+
+ if (response) {
+ camel_imap_response_free (imap_store, response);
+ imap_forget_folder (imap_store, folder_name, ex);
+ }
+}
+
+static void
+manage_subscriptions (CamelStore *store, const char *old_name, gboolean subscribe)
+{
+ CamelImapStore *imap_store = CAMEL_IMAP_STORE (store);
+ CamelStoreInfo *si;
+ int olen = strlen(old_name);
+ const char *path;
+ int i, count;
+
+ count = camel_store_summary_count((CamelStoreSummary *)imap_store->summary);
+ for (i=0;i<count;i++) {
+ si = camel_store_summary_index((CamelStoreSummary *)imap_store->summary, i);
+ if (si) {
+ path = camel_store_info_path(imap_store->summary, si);
+ if (strncmp(path, old_name, olen) == 0) {
+ if (subscribe)
+ subscribe_folder(store, path, NULL);
+ else
+ unsubscribe_folder(store, path, NULL);
+ }
+ camel_store_summary_info_free((CamelStoreSummary *)imap_store->summary, si);
+ }
+ }
+}
+
+static void
+rename_folder_info (CamelImapStore *imap_store, const char *old_name, const char *new_name)
+{
+ int i, count;
+ CamelStoreInfo *si;
+ int olen = strlen(old_name);
+ const char *path;
+ char *npath, *nfull;
+
+ count = camel_store_summary_count((CamelStoreSummary *)imap_store->summary);
+ for (i=0;i<count;i++) {
+ si = camel_store_summary_index((CamelStoreSummary *)imap_store->summary, i);
+ if (si == NULL)
+ continue;
+ path = camel_store_info_path(imap_store->summary, si);
+ if (strncmp(path, old_name, olen) == 0) {
+ if (strlen(path) > olen)
+ npath = g_strdup_printf("%s/%s", new_name, path+olen+1);
+ else
+ npath = g_strdup(new_name);
+ nfull = camel_imap_store_summary_path_to_full(imap_store->summary, npath, imap_store->dir_sep);
+
+ /* workaround for broken server (courier uses '.') that doesn't rename
+ subordinate folders as required by rfc 2060 */
+ if (imap_store->dir_sep == '.') {
+ CamelImapResponse *response;
+
+ response = camel_imap_command (imap_store, NULL, NULL, "RENAME %F %S", path, nfull);
+ if (response)
+ camel_imap_response_free (imap_store, response);
+ }
+
+ camel_store_info_set_string((CamelStoreSummary *)imap_store->summary, si, CAMEL_STORE_INFO_PATH, npath);
+ camel_store_info_set_string((CamelStoreSummary *)imap_store->summary, si, CAMEL_IMAP_STORE_INFO_FULL_NAME, nfull);
+
+ camel_store_summary_touch((CamelStoreSummary *)imap_store->summary);
+ g_free(nfull);
+ g_free(npath);
+ }
+ camel_store_summary_info_free((CamelStoreSummary *)imap_store->summary, si);
+ }
+}
+
+static void
+rename_folder (CamelStore *store, const char *old_name, const char *new_name_in, CamelException *ex)
+{
+ CamelImapStore *imap_store = CAMEL_IMAP_STORE (store);
+ CamelImapResponse *response;
+ char *oldpath, *newpath, *storage_path, *new_name;
+
+ if (!camel_disco_store_check_online (CAMEL_DISCO_STORE (store), ex))
+ return;
+
+ /* make sure this folder isn't currently SELECTed - it's
+ actually possible to rename INBOX but if you do another
+ INBOX will immediately be created by the server */
+ response = camel_imap_command (imap_store, NULL, ex, "SELECT INBOX");
+ if (response) {
+ camel_imap_response_free_without_processing (imap_store, response);
+
+ CAMEL_SERVICE_LOCK (imap_store, connect_lock);
+
+ if (imap_store->current_folder)
+ camel_object_unref (imap_store->current_folder);
+ /* no need to actually create a CamelFolder for INBOX */
+ imap_store->current_folder = NULL;
+
+ CAMEL_SERVICE_UNLOCK (imap_store, connect_lock);
+ } else
+ return;
+
+ imap_store->renaming = TRUE;
+
+ if (store->flags & CAMEL_STORE_SUBSCRIPTIONS)
+ manage_subscriptions(store, old_name, FALSE);
+
+ new_name = camel_imap_store_summary_path_to_full(imap_store->summary, new_name_in, imap_store->dir_sep);
+ response = camel_imap_command (imap_store, NULL, ex, "RENAME %F %S", old_name, new_name);
+
+ if (!response) {
+ if (store->flags & CAMEL_STORE_SUBSCRIPTIONS)
+ manage_subscriptions(store, old_name, TRUE);
+ g_free(new_name);
+ imap_store->renaming = FALSE;
+ return;
+ }
+
+ camel_imap_response_free (imap_store, response);
+
+ /* rename summary, and handle broken server */
+ rename_folder_info(imap_store, old_name, new_name_in);
+
+ if (store->flags & CAMEL_STORE_SUBSCRIPTIONS)
+ manage_subscriptions(store, new_name_in, TRUE);
+
+ storage_path = g_strdup_printf("%s/folders", imap_store->storage_path);
+ oldpath = e_path_to_physical (storage_path, old_name);
+ newpath = e_path_to_physical (storage_path, new_name_in);
+ g_free(storage_path);
+
+ /* So do we care if this didn't work? Its just a cache? */
+ if (rename (oldpath, newpath) == -1) {
+ g_warning ("Could not rename message cache '%s' to '%s': %s: cache reset",
+ oldpath, newpath, strerror (errno));
+ }
+
+ g_free (oldpath);
+ g_free (newpath);
+ g_free(new_name);
+
+ imap_store->renaming = FALSE;
+}
+
+static CamelFolderInfo *
+create_folder (CamelStore *store, const char *parent_name,
+ const char *folder_name, CamelException *ex)
+{
+ CamelImapStore *imap_store = CAMEL_IMAP_STORE (store);
+ char *full_name, *resp, *thisone, *parent_real, *real_name;
+ CamelImapResponse *response;
+ CamelException internal_ex;
+ CamelFolderInfo *root = NULL;
+ gboolean need_convert;
+ int i = 0, flags;
+ const char *c;
+
+ if (!camel_disco_store_check_online (CAMEL_DISCO_STORE (store), ex))
+ return NULL;
+ if (!parent_name)
+ parent_name = "";
+
+ c = folder_name;
+ while (*c && *c != imap_store->dir_sep && !strchr ("#%*", *c))
+ c++;
+
+ if (*c != '\0') {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_INVALID_PATH,
+ _("The folder name \"%s\" is invalid because it contains the character \"%c\""),
+ folder_name, *c);
+ return NULL;
+ }
+
+ /* check if the parent allows inferiors */
+
+ /* FIXME: use storesummary directly */
+ parent_real = camel_imap_store_summary_full_from_path(imap_store->summary, parent_name);
+ if (parent_real == NULL) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_FOLDER_INVALID_STATE,
+ _("Unknown parent folder: %s"), parent_name);
+ return NULL;
+ }
+
+ need_convert = FALSE;
+ response = camel_imap_command (imap_store, NULL, ex, "LIST \"\" %S",
+ parent_real);
+ if (!response) /* whoa, this is bad */ {
+ g_free(parent_real);
+ return NULL;
+ }
+
+ /* FIXME: does not handle unexpected circumstances very well */
+ for (i = 0; i < response->untagged->len && !need_convert; i++) {
+ resp = response->untagged->pdata[i];
+
+ if (!imap_parse_list_response (imap_store, resp, &flags, NULL, &thisone))
+ continue;
+
+ if (strcmp (thisone, parent_name) == 0) {
+ if (flags & CAMEL_FOLDER_NOINFERIORS)
+ need_convert = TRUE;
+ }
+
+ g_free(thisone);
+ }
+
+ camel_imap_response_free (imap_store, response);
+
+ camel_exception_init (&internal_ex);
+
+ /* if not, check if we can delete it and recreate it */
+ if (need_convert) {
+ struct imap_status_item *items, *item;
+ guint32 messages = 0;
+ char *name;
+
+ item = items = get_folder_status (imap_store, parent_name, "MESSAGES");
+ while (item != NULL) {
+ if (!g_ascii_strcasecmp (item->name, "MESSAGES")) {
+ messages = item->value;
+ break;
+ }
+
+ item = item->next;
+ }
+
+ imap_status_item_free (items);
+
+ if (messages > 0) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_FOLDER_INVALID_STATE,
+ _("The parent folder is not allowed to contain subfolders"));
+ g_free(parent_real);
+ return NULL;
+ }
+
+ /* delete the old parent and recreate it */
+ delete_folder (store, parent_name, &internal_ex);
+ if (camel_exception_is_set (&internal_ex)) {
+ camel_exception_xfer (ex, &internal_ex);
+ return NULL;
+ }
+
+ /* add the dirsep to the end of parent_name */
+ name = g_strdup_printf ("%s%c", parent_real, imap_store->dir_sep);
+ response = camel_imap_command (imap_store, NULL, ex, "CREATE %S",
+ name);
+ g_free (name);
+
+ if (!response) {
+ g_free(parent_real);
+ return NULL;
+ } else
+ camel_imap_response_free (imap_store, response);
+
+ root = imap_build_folder_info(imap_store, parent_name);
+ }
+
+ /* ok now we can create the folder */
+ real_name = camel_imap_store_summary_path_to_full(imap_store->summary, folder_name, imap_store->dir_sep);
+ full_name = imap_concat (imap_store, parent_real, real_name);
+ g_free(real_name);
+ response = camel_imap_command (imap_store, NULL, ex, "CREATE %S", full_name);
+
+ if (response) {
+ CamelImapStoreInfo *si;
+ CamelFolderInfo *fi;
+
+ camel_imap_response_free (imap_store, response);
+
+ si = camel_imap_store_summary_add_from_full(imap_store->summary, full_name, imap_store->dir_sep);
+ camel_store_summary_save((CamelStoreSummary *)imap_store->summary);
+ fi = imap_build_folder_info(imap_store, camel_store_info_path(imap_store->summary, si));
+ fi->flags |= CAMEL_FOLDER_NOCHILDREN;
+ if (root) {
+ root->child = fi;
+ fi->parent = root;
+ } else {
+ root = fi;
+ }
+ camel_object_trigger_event (CAMEL_OBJECT (store), "folder_created", root);
+ } else if (root) {
+ /* need to re-recreate the folder we just deleted */
+ camel_object_trigger_event (CAMEL_OBJECT (store), "folder_created", root);
+ camel_folder_info_free(root);
+ root = NULL;
+ }
+
+ g_free (full_name);
+ g_free(parent_real);
+
+ return root;
+}
+
+static CamelFolderInfo *
+parse_list_response_as_folder_info (CamelImapStore *imap_store,
+ const char *response)
+{
+ CamelFolderInfo *fi;
+ int flags;
+ char sep, *dir, *path;
+ CamelURL *url;
+ CamelImapStoreInfo *si;
+ guint32 newflags;
+
+ if (!imap_parse_list_response (imap_store, response, &flags, &sep, &dir))
+ return NULL;
+
+ /* FIXME: should use imap_build_folder_info, note the differences with param setting tho */
+
+ si = camel_imap_store_summary_add_from_full(imap_store->summary, dir, sep?sep:'/');
+ g_free(dir);
+ if (si == NULL)
+ return NULL;
+
+ newflags = (si->info.flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) | (flags & ~CAMEL_STORE_INFO_FOLDER_SUBSCRIBED);
+ if (si->info.flags != newflags) {
+ si->info.flags = newflags;
+ camel_store_summary_touch((CamelStoreSummary *)imap_store->summary);
+ }
+
+ fi = g_new0 (CamelFolderInfo, 1);
+ fi->name = g_strdup(camel_store_info_name(imap_store->summary, si));
+ fi->full_name = g_strdup(camel_store_info_path(imap_store->summary, si));
+ if (!g_ascii_strcasecmp(fi->full_name, "inbox"))
+ flags |= CAMEL_FOLDER_SYSTEM;
+ /* HACK: some servers report noinferiors for all folders (uw-imapd)
+ We just translate this into nochildren, and let the imap layer enforce
+ it. See create folder */
+ if (flags & CAMEL_FOLDER_NOINFERIORS)
+ flags = (fi->flags & ~CAMEL_FOLDER_NOINFERIORS) | CAMEL_FOLDER_NOCHILDREN;
+ fi->flags = flags;
+
+ url = camel_url_new (imap_store->base_url, NULL);
+ path = alloca(strlen(fi->full_name)+2);
+ sprintf(path, "/%s", fi->full_name);
+ camel_url_set_path(url, path);
+
+ if (flags & CAMEL_FOLDER_NOSELECT || fi->name[0] == 0)
+ camel_url_set_param (url, "noselect", "yes");
+ fi->uri = camel_url_to_string (url, 0);
+ camel_url_free (url);
+
+ /* FIXME: redundant */
+ if (flags & CAMEL_IMAP_FOLDER_UNMARKED)
+ fi->unread = -1;
+
+ return fi;
+}
+
+/* returns true if full_name is a sub-folder of top, or is top */
+static int
+imap_is_subfolder(const char *full_name, const char *top)
+{
+ size_t len = strlen(top);
+
+ /* Looks for top being a full-path subset of full_name.
+ Handle IMAP Inbox case insensitively */
+
+ if (g_ascii_strncasecmp(top, "inbox", 5) == 0
+ && (top[5] == 0 || top[5] == '/')
+ && g_ascii_strncasecmp(full_name, "inbox", 5) == 0
+ && (full_name[5] == 0 || full_name[5] == '/')) {
+ full_name += 5;
+ top += 5;
+ len -= 5;
+ }
+
+ return top[0] == 0
+ || (strncmp(full_name, top, len) == 0
+ && (full_name[len] == 0
+ || full_name[len] == '/'));
+}
+
+/* this is used when lsub doesn't provide very useful information */
+static GPtrArray *
+get_subscribed_folders (CamelImapStore *imap_store, const char *top, CamelException *ex)
+{
+ GPtrArray *names, *folders;
+ int i;
+ CamelStoreInfo *si;
+ CamelImapResponse *response;
+ CamelFolderInfo *fi;
+ char *result;
+ int haveinbox = FALSE;
+
+ if (camel_debug("imap:folder_info"))
+ printf(" get_subscribed folders\n");
+
+ folders = g_ptr_array_new ();
+ names = g_ptr_array_new ();
+ for (i=0;(si = camel_store_summary_index((CamelStoreSummary *)imap_store->summary, i));i++) {
+ if (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED
+ && imap_is_subfolder(camel_store_info_path(imap_store->summary, si), top)) {
+ g_ptr_array_add(names, (char *)camel_imap_store_info_full_name(imap_store->summary, si));
+ haveinbox = haveinbox || g_ascii_strcasecmp(camel_imap_store_info_full_name(imap_store->summary, si), "INBOX") == 0;
+ }
+ camel_store_summary_info_free((CamelStoreSummary *)imap_store->summary, si);
+ }
+
+ if (!haveinbox)
+ g_ptr_array_add (names, "INBOX");
+
+ for (i = 0; i < names->len; i++) {
+ response = camel_imap_command (imap_store, NULL, ex,
+ "LIST \"\" %S",
+ names->pdata[i]);
+ if (!response)
+ break;
+
+ result = camel_imap_response_extract (imap_store, response, "LIST", NULL);
+ if (!result) {
+ camel_store_summary_remove_path((CamelStoreSummary *)imap_store->summary, names->pdata[i]);
+ g_ptr_array_remove_index_fast (names, i);
+ i--;
+ continue;
+ }
+
+ fi = parse_list_response_as_folder_info (imap_store, result);
+ g_free (result);
+ if (!fi)
+ continue;
+
+ if (!imap_is_subfolder(fi->full_name, top)) {
+ camel_folder_info_free (fi);
+ continue;
+ }
+
+ g_ptr_array_add (folders, fi);
+ }
+
+ g_ptr_array_free (names, TRUE);
+
+ return folders;
+}
+
+static int imap_match_pattern(char dir_sep, const char *pattern, const char *name)
+{
+ char p, n;
+
+ p = *pattern++;
+ n = *name++;
+ while (n && p) {
+ if (n == p) {
+ p = *pattern++;
+ n = *name++;
+ } else if (p == '%') {
+ if (n != dir_sep) {
+ n = *name++;
+ } else {
+ p = *pattern++;
+ }
+ } else if (p == '*') {
+ return TRUE;
+ } else
+ return FALSE;
+ }
+
+ return n == 0 && (p == '%' || p == 0);
+}
+
+static void
+get_folders_online (CamelImapStore *imap_store, const char *pattern,
+ GPtrArray *folders, gboolean lsub, CamelException *ex)
+{
+ CamelImapResponse *response;
+ CamelFolderInfo *fi;
+ char *list;
+ int i, count;
+ GHashTable *present;
+ CamelStoreInfo *si;
+
+ response = camel_imap_command (imap_store, NULL, ex,
+ "%s \"\" %S", lsub ? "LSUB" : "LIST",
+ pattern);
+ if (!response)
+ return;
+
+ present = g_hash_table_new(g_str_hash, g_str_equal);
+ for (i = 0; i < response->untagged->len; i++) {
+ list = response->untagged->pdata[i];
+ fi = parse_list_response_as_folder_info (imap_store, list);
+ if (fi) {
+ g_ptr_array_add(folders, fi);
+ g_hash_table_insert(present, fi->full_name, fi);
+ }
+ }
+ camel_imap_response_free (imap_store, response);
+
+ /* update our summary to match the server */
+ count = camel_store_summary_count((CamelStoreSummary *)imap_store->summary);
+ for (i=0;i<count;i++) {
+ si = camel_store_summary_index((CamelStoreSummary *)imap_store->summary, i);
+ if (si == NULL)
+ continue;
+
+ if (imap_match_pattern(imap_store->dir_sep, pattern, camel_imap_store_info_full_name(imap_store->summary, si))) {
+ if (g_hash_table_lookup(present, camel_store_info_path(imap_store->summary, si)) != NULL) {
+ if (lsub && (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) == 0) {
+ si->flags |= CAMEL_STORE_INFO_FOLDER_SUBSCRIBED;
+ camel_store_summary_touch((CamelStoreSummary *)imap_store->summary);
+ }
+ } else {
+ if (lsub) {
+ if (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) {
+ si->flags &= ~CAMEL_STORE_INFO_FOLDER_SUBSCRIBED;
+ camel_store_summary_touch((CamelStoreSummary *)imap_store->summary);
+ }
+ } else {
+ camel_store_summary_remove((CamelStoreSummary *)imap_store->summary, si);
+ count--;
+ i--;
+ }
+ }
+ }
+ camel_store_summary_info_free((CamelStoreSummary *)imap_store->summary, si);
+ }
+ g_hash_table_destroy(present);
+}
+
+#if 0
+static void
+dumpfi(CamelFolderInfo *fi)
+{
+ int depth;
+ CamelFolderInfo *n = fi;
+
+ if (fi == NULL)
+ return;
+
+ depth = 0;
+ while (n->parent) {
+ depth++;
+ n = n->parent;
+ }
+
+ while (fi) {
+ printf("%-40s %-30s %*s\n", fi->path, fi->full_name, depth*2+strlen(fi->url), fi->url);
+ if (fi->child)
+ dumpfi(fi->child);
+ fi = fi->sibling;
+ }
+}
+#endif
+
+static void
+fill_fi(CamelStore *store, CamelFolderInfo *fi, guint32 flags)
+{
+ CamelFolder *folder;
+
+ fi->unread = -1;
+ fi->total = -1;
+ folder = camel_object_bag_peek(store->folders, fi->full_name);
+ if (folder) {
+ if ((flags & CAMEL_STORE_FOLDER_INFO_FAST) == 0)
+ /* we use connect lock for everything, so this should be safe */
+ CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(folder))->refresh_info(folder, NULL);
+ fi->unread = camel_folder_get_unread_message_count(folder);
+ fi->total = camel_folder_get_message_count(folder);
+ camel_object_unref(folder);
+ } else {
+ char *storage_path, *folder_dir, *path;
+ CamelFolderSummary *s;
+
+ /* This is a lot of work for one path! */
+ storage_path = g_strdup_printf("%s/folders", ((CamelImapStore *)store)->storage_path);
+ folder_dir = e_path_to_physical(storage_path, fi->full_name);
+ path = g_strdup_printf("%s/summary", folder_dir);
+ s = (CamelFolderSummary *)camel_object_new(camel_imap_summary_get_type());
+ camel_folder_summary_set_build_content(s, TRUE);
+ camel_folder_summary_set_filename(s, path);
+ if (camel_folder_summary_header_load(s) != -1) {
+ fi->unread = s->unread_count;
+ fi->total = s->saved_count;
+ }
+ g_free(storage_path);
+ g_free(folder_dir);
+ g_free(path);
+
+ camel_object_unref(s);
+ }
+}
+
+/* NB: We should have connect_lock at this point */
+static void
+get_folder_counts(CamelImapStore *imap_store, CamelFolderInfo *fi, CamelException *ex)
+{
+ GSList *q;
+ CamelFolder *folder;
+
+ /* non-recursive breath first search */
+
+ q = g_slist_append(NULL, fi);
+
+ while (q) {
+ fi = q->data;
+ q = g_slist_remove_link(q, q);
+
+ while (fi) {
+ /* ignore noselect folders, and check only inbox if we only check inbox */
+ if ((fi->flags & CAMEL_FOLDER_NOSELECT) == 0
+ && ( (imap_store->parameters & IMAP_PARAM_CHECK_ALL)
+ || g_ascii_strcasecmp(fi->full_name, "inbox") == 0) ) {
+
+ /* For the current folder, poke it to check for new
+ * messages and then report that number, rather than
+ * doing a STATUS command.
+ */
+ if (imap_store->current_folder && strcmp(imap_store->current_folder->full_name, fi->full_name) == 0) {
+ /* we bypass the folder locking otherwise we can deadlock. we use the command lock for
+ any operations anyway so this is 'safe'. See comment above imap_store_refresh_folders() for info */
+ CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(imap_store->current_folder))->refresh_info(imap_store->current_folder, ex);
+ fi->unread = camel_folder_get_unread_message_count (imap_store->current_folder);
+ fi->total = camel_folder_get_message_count(imap_store->current_folder);
+ } else {
+ struct imap_status_item *items, *item;
+
+ fi->unread = -1;
+ fi->total = -1;
+
+ item = items = get_folder_status (imap_store, fi->full_name, "MESSAGES UNSEEN");
+ while (item != NULL) {
+ if (!g_ascii_strcasecmp (item->name, "MESSAGES")) {
+ fi->total = item->value;
+ } else if (!g_ascii_strcasecmp (item->name, "UNSEEN")) {
+ fi->unread = item->value;
+ }
+
+ item = item->next;
+ }
+
+ imap_status_item_free (items);
+
+ /* if we have this folder open, and the unread count has changed, update */
+ folder = camel_object_bag_peek(CAMEL_STORE(imap_store)->folders, fi->full_name);
+ if (folder) {
+ if (fi->unread != camel_folder_get_unread_message_count(folder)) {
+ CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(folder))->refresh_info(folder, ex);
+ fi->unread = camel_folder_get_unread_message_count(folder);
+ fi->total = camel_folder_get_message_count(folder);
+ }
+ camel_object_unref(folder);
+ }
+ }
+ } else {
+ /* since its cheap, get it if they're open/consult summary file */
+ fill_fi((CamelStore *)imap_store, fi, 0);
+ }
+
+ if (fi->child)
+ q = g_slist_append(q, fi->child);
+ fi = fi->next;
+ }
+ }
+}
+
+/* imap needs to treat inbox case insensitive */
+/* we'll assume the names are normalised already */
+static guint folder_hash(const void *ap)
+{
+ const char *a = ap;
+
+ if (g_ascii_strcasecmp(a, "INBOX") == 0)
+ a = "INBOX";
+
+ return g_str_hash(a);
+}
+
+static int folder_eq(const void *ap, const void *bp)
+{
+ const char *a = ap;
+ const char *b = bp;
+
+ if (g_ascii_strcasecmp(a, "INBOX") == 0)
+ a = "INBOX";
+ if (g_ascii_strcasecmp(b, "INBOX") == 0)
+ b = "INBOX";
+
+ return g_str_equal(a, b);
+}
+
+static GSList *
+get_folders_add_folders(GSList *p, int recurse, GHashTable *infos, GPtrArray *folders, GPtrArray *folders_out)
+{
+ CamelFolderInfo *oldfi, *fi;
+ int i;
+
+ /* This is a nasty mess, because some servers will return
+ broken results from LIST or LSUB if you use '%'. e.g. you
+ may get (many) duplicate names, and worse, names may have
+ conflicting flags. */
+ for (i=0; i<folders->len; i++) {
+ fi = folders->pdata[i];
+ oldfi = g_hash_table_lookup(infos, fi->full_name);
+ if (oldfi == NULL) {
+ d(printf(" new folder '%s'\n", fi->full_name));
+ g_hash_table_insert(infos, fi->full_name, fi);
+ if (recurse)
+ p = g_slist_prepend(p, fi);
+ g_ptr_array_add(folders_out, fi);
+ } else {
+ d(printf(" old folder '%s', old flags %08x new flags %08x\n", fi->full_name, oldfi->flags, fi->flags));
+
+ /* need to special-case noselect, since it also affects the uri */
+ if ((oldfi->flags & CAMEL_FOLDER_NOSELECT) != 0
+ && (fi->flags & CAMEL_FOLDER_NOSELECT) == 0) {
+ g_free(oldfi->uri);
+ oldfi->uri = fi->uri;
+ fi->uri = NULL;
+ }
+
+ /* some flags are anded together, some are or'd */
+
+ oldfi->flags = (oldfi->flags & fi->flags & (CAMEL_FOLDER_NOSELECT|CAMEL_FOLDER_NOINFERIORS))
+ | ((oldfi->flags | fi->flags) & ~(CAMEL_FOLDER_NOSELECT|CAMEL_FOLDER_NOINFERIORS));
+
+ camel_folder_info_free(fi);
+ }
+ }
+
+ g_ptr_array_set_size(folders, 0);
+
+ return p;
+}
+
+static GPtrArray *
+get_folders(CamelStore *store, const char *top, guint32 flags, CamelException *ex)
+{
+ CamelImapStore *imap_store = CAMEL_IMAP_STORE (store);
+ GSList *q, *p = NULL;
+ GHashTable *infos;
+ int i;
+ GPtrArray *folders, *folders_out;
+ CamelFolderInfo *fi;
+ char *name;
+ int depth = 0;
+ int haveinbox = 0;
+ static int imap_max_depth = 0;
+
+ if (!camel_imap_store_connected (imap_store, ex))
+ return NULL;
+
+ if (camel_debug("imap:folder_info"))
+ printf(" get_folders\n");
+
+ /* allow megalomaniacs to override the max of 10 */
+ if (imap_max_depth == 0) {
+ name = getenv("CAMEL_IMAP_MAX_DEPTH");
+ if (name) {
+ imap_max_depth = atoi (name);
+ imap_max_depth = MIN (MAX (imap_max_depth, 0), 2);
+ } else
+ imap_max_depth = 10;
+ }
+
+ infos = g_hash_table_new(folder_hash, folder_eq);
+
+ /* get starting point & strip trailing '/' */
+ if (top[0] == 0) {
+ if (imap_store->namespace) {
+ top = imap_store->namespace;
+ i = strlen(top)-1;
+ name = g_malloc(i+2);
+ strcpy(name, top);
+ while (i>0 && name[i] == imap_store->dir_sep)
+ name[i--] = 0;
+ } else
+ name = g_strdup("");
+ } else {
+ name = camel_imap_store_summary_full_from_path(imap_store->summary, top);
+ if (name == NULL)
+ name = camel_imap_store_summary_path_to_full(imap_store->summary, top, imap_store->dir_sep);
+ }
+
+ d(printf("\n\nList '%s' %s\n", name, flags&CAMEL_STORE_FOLDER_INFO_RECURSIVE?"RECURSIVE":"NON-RECURSIVE"));
+
+ folders_out = g_ptr_array_new();
+ folders = g_ptr_array_new();
+
+ /* first get working list of names */
+ get_folders_online (imap_store, name[0]?name:"%", folders, flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED, ex);
+ if (camel_exception_is_set(ex))
+ goto fail;
+ for (i=0; i<folders->len && !haveinbox; i++) {
+ fi = folders->pdata[i];
+ haveinbox = (g_ascii_strcasecmp(fi->full_name, "INBOX")) == 0;
+ }
+
+ if (!haveinbox && top == imap_store->namespace) {
+ get_folders_online (imap_store, "INBOX", folders,
+ flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED, ex);
+
+ if (camel_exception_is_set (ex))
+ goto fail;
+ }
+
+ p = get_folders_add_folders(p, TRUE, infos, folders, folders_out);
+
+ /* p is a reversed list of pending folders for the next level, q is the list of folders for this */
+ while (p) {
+ q = g_slist_reverse(p);
+
+ p = NULL;
+ while (q) {
+ fi = q->data;
+
+ q = g_slist_remove_link(q, q);
+
+ d(printf("Checking parent folder '%s'\n", fi->full_name));
+
+ /* First if we're not recursive mode on the top level, and we know it has or doesn't
+ or can't have children, no need to go further - a bit ugly */
+ if ( top == imap_store->namespace
+ && (flags & CAMEL_STORE_FOLDER_INFO_RECURSIVE) == 0
+ && (fi->flags & (CAMEL_FOLDER_CHILDREN|CAMEL_FOLDER_NOCHILDREN|CAMEL_FOLDER_NOINFERIORS)) != 0) {
+ /* do nothing */
+ d(printf(" not interested in folder right now ...\n"));
+ }
+ /* Otherwise, if this has (or might have) children, scan it */
+ else if ( (fi->flags & (CAMEL_FOLDER_NOCHILDREN|CAMEL_FOLDER_NOINFERIORS)) == 0
+ || (fi->flags & CAMEL_FOLDER_CHILDREN) != 0) {
+ char *n, *real;
+
+ real = camel_imap_store_summary_full_from_path(imap_store->summary, fi->full_name);
+ n = imap_concat(imap_store, real?real:fi->full_name, "%");
+ get_folders_online(imap_store, n, folders, flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED, ex);
+ g_free(n);
+ g_free(real);
+
+ if (camel_exception_is_set (ex))
+ goto fail;
+
+ if (folders->len > 0)
+ fi->flags |= CAMEL_FOLDER_CHILDREN;
+
+ p = get_folders_add_folders(p, (flags & CAMEL_STORE_FOLDER_INFO_RECURSIVE) && depth<imap_max_depth,
+ infos, folders, folders_out);
+ }
+ }
+ depth++;
+ }
+
+ g_ptr_array_free(folders, TRUE);
+ g_hash_table_destroy(infos);
+ g_free(name);
+
+ return folders_out;
+fail:
+ g_ptr_array_free(folders, TRUE);
+ g_ptr_array_free(folders_out, TRUE);
+ g_hash_table_destroy(infos);
+ g_slist_free (p);
+ g_free(name);
+
+ return NULL;
+}
+
+static CamelFolderInfo *
+get_folder_info_online (CamelStore *store, const char *top, guint32 flags, CamelException *ex)
+{
+ CamelImapStore *imap_store = CAMEL_IMAP_STORE (store);
+ CamelFolderInfo *tree = NULL;
+ GPtrArray *folders;
+
+ if (top == NULL)
+ top = "";
+
+ if (camel_debug("imap:folder_info"))
+ printf("get folder info online\n");
+
+ CAMEL_SERVICE_LOCK(store, connect_lock);
+
+ if ((flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED)
+ && !(imap_store->capabilities & IMAP_CAPABILITY_useful_lsub)
+ && (imap_store->parameters & IMAP_PARAM_CHECK_ALL))
+ folders = get_subscribed_folders(imap_store, top, ex);
+ else
+ folders = get_folders(store, top, flags, ex);
+
+ if (folders == NULL)
+ goto done;
+
+ tree = camel_folder_info_build(folders, top, '/', TRUE);
+ g_ptr_array_free(folders, TRUE);
+
+ if (!(flags & CAMEL_STORE_FOLDER_INFO_FAST))
+ get_folder_counts(imap_store, tree, ex);
+
+ d(dumpfi(tree));
+ camel_store_summary_save((CamelStoreSummary *)imap_store->summary);
+done:
+ CAMEL_SERVICE_UNLOCK(store, connect_lock);
+
+ return tree;
+}
+
+static gboolean
+get_one_folder_offline (const char *physical_path, const char *path, gpointer data)
+{
+ GPtrArray *folders = data;
+ CamelImapStore *imap_store = folders->pdata[0];
+ CamelFolderInfo *fi;
+ CamelStoreInfo *si;
+
+ if (*path != '/')
+ return TRUE;
+
+ /* folder_info_build will insert parent nodes as necessary and mark
+ * them as noselect, which is information we actually don't have at
+ * the moment. So let it do the right thing by bailing out if it's
+ * not a folder we're explicitly interested in.
+ */
+
+ si = camel_store_summary_path((CamelStoreSummary *)imap_store->summary, path+1);
+ if (si) {
+ if ((((CamelStore *)imap_store)->flags & CAMEL_STORE_SUBSCRIPTIONS) == 0
+ || (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED)) {
+ fi = imap_build_folder_info(imap_store, path+1);
+ fi->flags = si->flags;
+ /* HACK: some servers report noinferiors for all folders (uw-imapd)
+ We just translate this into nochildren, and let the imap layer enforce
+ it. See create folder */
+ if (fi->flags & CAMEL_FOLDER_NOINFERIORS)
+ fi->flags = (fi->flags & ~CAMEL_FOLDER_NOINFERIORS) | CAMEL_FOLDER_NOCHILDREN;
+
+ if (si->flags & CAMEL_FOLDER_NOSELECT) {
+ CamelURL *url = camel_url_new(fi->uri, NULL);
+
+ camel_url_set_param (url, "noselect", "yes");
+ g_free(fi->uri);
+ fi->uri = camel_url_to_string (url, 0);
+ camel_url_free (url);
+ } else {
+ fill_fi((CamelStore *)imap_store, fi, 0);
+ }
+ g_ptr_array_add (folders, fi);
+ }
+ camel_store_summary_info_free((CamelStoreSummary *)imap_store->summary, si);
+ }
+
+ return TRUE;
+}
+
+static CamelFolderInfo *
+get_folder_info_offline (CamelStore *store, const char *top,
+ guint32 flags, CamelException *ex)
+{
+ CamelImapStore *imap_store = CAMEL_IMAP_STORE (store);
+ CamelFolderInfo *fi;
+ GPtrArray *folders;
+ char *storage_path;
+
+ if (camel_debug("imap:folder_info"))
+ printf("get folder info offline\n");
+
+ if (!imap_store->connected &&
+ !camel_service_connect (CAMEL_SERVICE (store), ex))
+ return NULL;
+
+ if ((store->flags & CAMEL_STORE_SUBSCRIPTIONS) &&
+ !(flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED)) {
+ camel_disco_store_check_online (CAMEL_DISCO_STORE (store), ex);
+ return NULL;
+ }
+
+ /* FIXME: obey other flags */
+
+ folders = g_ptr_array_new ();
+
+ /* A kludge to avoid having to pass a struct to the callback */
+ g_ptr_array_add (folders, imap_store);
+ storage_path = g_strdup_printf("%s/folders", imap_store->storage_path);
+ if (!e_path_find_folders (storage_path, get_one_folder_offline, folders)) {
+ camel_disco_store_check_online (CAMEL_DISCO_STORE (imap_store), ex);
+ fi = NULL;
+ } else {
+ g_ptr_array_remove_index_fast (folders, 0);
+ fi = camel_folder_info_build (folders, "", '/', TRUE);
+ }
+ g_free(storage_path);
+
+ g_ptr_array_free (folders, TRUE);
+ return fi;
+}
+
+static gboolean
+folder_subscribed (CamelStore *store, const char *folder_name)
+{
+ CamelImapStore *imap_store = CAMEL_IMAP_STORE (store);
+ CamelStoreInfo *si;
+ int truth = FALSE;
+
+ si = camel_store_summary_path((CamelStoreSummary *)imap_store->summary, folder_name);
+ if (si) {
+ truth = (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) != 0;
+ camel_store_summary_info_free((CamelStoreSummary *)imap_store->summary, si);
+ }
+
+ return truth;
+}
+
+/* Note: folder_name must match a folder as listed with get_folder_info() -> full_name */
+static void
+subscribe_folder (CamelStore *store, const char *folder_name,
+ CamelException *ex)
+{
+ CamelImapStore *imap_store = CAMEL_IMAP_STORE (store);
+ CamelImapResponse *response;
+ CamelFolderInfo *fi;
+ CamelStoreInfo *si;
+
+ if (!camel_disco_store_check_online (CAMEL_DISCO_STORE (store), ex))
+ return;
+ if (!camel_imap_store_connected (imap_store, ex))
+ return;
+
+ response = camel_imap_command (imap_store, NULL, ex,
+ "SUBSCRIBE %F", folder_name);
+ if (!response)
+ return;
+ camel_imap_response_free (imap_store, response);
+
+ si = camel_store_summary_path((CamelStoreSummary *)imap_store->summary, folder_name);
+ if (si) {
+ if ((si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) == 0) {
+ si->flags |= CAMEL_STORE_INFO_FOLDER_SUBSCRIBED;
+ camel_store_summary_touch((CamelStoreSummary *)imap_store->summary);
+ camel_store_summary_save((CamelStoreSummary *)imap_store->summary);
+ }
+ camel_store_summary_info_free((CamelStoreSummary *)imap_store->summary, si);
+ }
+
+ if (imap_store->renaming) {
+ /* we don't need to emit a "folder_subscribed" signal
+ if we are in the process of renaming folders, so we
+ are done here... */
+ return;
+ }
+
+ fi = imap_build_folder_info(imap_store, folder_name);
+ fi->flags |= CAMEL_FOLDER_NOCHILDREN;
+
+ camel_object_trigger_event (CAMEL_OBJECT (store), "folder_subscribed", fi);
+ camel_folder_info_free (fi);
+}
+
+static void
+unsubscribe_folder (CamelStore *store, const char *folder_name,
+ CamelException *ex)
+{
+ CamelImapStore *imap_store = CAMEL_IMAP_STORE (store);
+ CamelImapResponse *response;
+
+ if (!camel_disco_store_check_online (CAMEL_DISCO_STORE (store), ex))
+ return;
+ if (!camel_imap_store_connected (imap_store, ex))
+ return;
+
+ response = camel_imap_command (imap_store, NULL, ex,
+ "UNSUBSCRIBE %F", folder_name);
+ if (!response)
+ return;
+ camel_imap_response_free (imap_store, response);
+
+ imap_folder_effectively_unsubscribed (imap_store, folder_name, ex);
+}
+
+#if 0
+static gboolean
+folder_flags_have_changed (CamelFolder *folder)
+{
+ CamelMessageInfo *info;
+ int i, max;
+
+ max = camel_folder_summary_count (folder->summary);
+ for (i = 0; i < max; i++) {
+ info = camel_folder_summary_index (folder->summary, i);
+ if (!info)
+ continue;
+ if (info->flags & CAMEL_MESSAGE_FOLDER_FLAGGED) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+#endif
+
+
+gboolean
+camel_imap_store_connected (CamelImapStore *store, CamelException *ex)
+{
+ if (store->istream == NULL || !store->connected)
+ return camel_service_connect (CAMEL_SERVICE (store), ex);
+ return TRUE;
+}
+
+
+/* FIXME: please god, when will the hurting stop? Thus function is so
+ fucking broken it's not even funny. */
+ssize_t
+camel_imap_store_readline (CamelImapStore *store, char **dest, CamelException *ex)
+{
+ CamelStreamBuffer *stream;
+ char linebuf[1024];
+ GByteArray *ba;
+ ssize_t nread;
+
+ g_return_val_if_fail (CAMEL_IS_IMAP_STORE (store), -1);
+ g_return_val_if_fail (dest, -1);
+
+ *dest = NULL;
+
+ /* Check for connectedness. Failed (or cancelled) operations will
+ * close the connection. We can't expect a read to have any
+ * meaning if we reconnect, so always set an exception.
+ */
+
+ if (!camel_imap_store_connected (store, ex))
+ return -1;
+
+ stream = CAMEL_STREAM_BUFFER (store->istream);
+
+ ba = g_byte_array_new ();
+ while ((nread = camel_stream_buffer_gets (stream, linebuf, sizeof (linebuf))) > 0) {
+ g_byte_array_append (ba, linebuf, nread);
+ if (linebuf[nread - 1] == '\n')
+ break;
+ }
+
+ if (nread <= 0) {
+ if (errno == EINTR)
+ camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL, _("Operation cancelled"));
+ else
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ _("Server unexpectedly disconnected: %s"),
+ g_strerror (errno));
+
+ camel_service_disconnect (CAMEL_SERVICE (store), FALSE, NULL);
+ g_byte_array_free (ba, TRUE);
+ return -1;
+ }
+
+ if (camel_verbose_debug) {
+ fprintf (stderr, "received: ");
+ fwrite (ba->data, 1, ba->len, stderr);
+ }
+
+ /* camel-imap-command.c:imap_read_untagged expects the CRLFs
+ to be stripped off and be nul-terminated *sigh* */
+ nread = ba->len - 1;
+ ba->data[nread] = '\0';
+ if (ba->data[nread - 1] == '\r') {
+ ba->data[nread - 1] = '\0';
+ nread--;
+ }
+
+ *dest = ba->data;
+ g_byte_array_free (ba, FALSE);
+
+ return nread;
+}
diff --git a/camel/providers/imap4/camel-imap4-engine.c b/camel/providers/imap4/camel-imap4-engine.c
new file mode 100644
index 0000000000..adbf862747
--- /dev/null
+++ b/camel/providers/imap4/camel-imap4-engine.c
@@ -0,0 +1,1550 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* Camel
+ * Copyright (C) 1999-2004 Jeffrey Stedfast
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include <camel/camel-sasl.h>
+#include <camel/camel-stream-buffer.h>
+
+#include "camel-imap4-summary.h"
+#include "camel-imap4-command.h"
+#include "camel-imap4-stream.h"
+#include "camel-imap4-folder.h"
+#include "camel-imap4-utils.h"
+
+#include "camel-imap4-engine.h"
+
+#define d(x) x
+
+
+static void camel_imap4_engine_class_init (CamelIMAP4EngineClass *klass);
+static void camel_imap4_engine_init (CamelIMAP4Engine *engine, CamelIMAP4EngineClass *klass);
+static void camel_imap4_engine_finalize (CamelObject *object);
+
+
+static CamelObjectClass *parent_class = NULL;
+
+
+CamelType
+camel_imap4_engine_get_type (void)
+{
+ static CamelType type = 0;
+
+ if (!type) {
+ type = camel_type_register (camel_object_get_type (),
+ "CamelIMAP4Engine",
+ sizeof (CamelIMAP4Engine),
+ sizeof (CamelIMAP4EngineClass),
+ (CamelObjectClassInitFunc) camel_imap4_engine_class_init,
+ NULL,
+ (CamelObjectInitFunc) camel_imap4_engine_init,
+ (CamelObjectFinalizeFunc) camel_imap4_engine_finalize);
+ }
+
+ return type;
+}
+
+static void
+camel_imap4_engine_class_init (CamelIMAP4EngineClass *klass)
+{
+ parent_class = camel_type_get_global_classfuncs (CAMEL_OBJECT_TYPE);
+
+ klass->tagprefix = 'A';
+}
+
+static void
+camel_imap4_engine_init (CamelIMAP4Engine *engine, CamelIMAP4EngineClass *klass)
+{
+ engine->state = CAMEL_IMAP4_ENGINE_DISCONNECTED;
+ engine->level = CAMEL_IMAP4_LEVEL_UNKNOWN;
+
+ engine->session = NULL;
+ engine->service = NULL;
+ engine->url = NULL;
+
+ engine->istream = NULL;
+ engine->ostream = NULL;
+
+ engine->authtypes = g_hash_table_new (g_str_hash, g_str_equal);
+
+ engine->capa = 0;
+
+ /* this is the suggested default, impacts the max command line length we'll send */
+ engine->maxlentype = CAMEL_IMAP4_ENGINE_MAXLEN_LINE;
+ engine->maxlen = 1000;
+
+ engine->namespaces.personal = NULL;
+ engine->namespaces.other = NULL;
+ engine->namespaces.shared = NULL;
+
+ if (klass->tagprefix > 'Z')
+ klass->tagprefix = 'A';
+
+ engine->tagprefix = klass->tagprefix++;
+ engine->tag = 0;
+
+ engine->nextid = 1;
+
+ engine->folder = NULL;
+
+ e_dlist_init (&engine->queue);
+}
+
+static void
+imap4_namespace_clear (CamelIMAP4Namespace **namespace)
+{
+ CamelIMAP4Namespace *node, *next;
+
+ node = *namespace;
+ while (node != NULL) {
+ next = node->next;
+ g_free (node->path);
+ g_free (node);
+ node = next;
+ }
+
+ *namespace = NULL;
+}
+
+static void
+camel_imap4_engine_finalize (CamelObject *object)
+{
+ CamelIMAP4Engine *engine = (CamelIMAP4Engine *) object;
+ EDListNode *node;
+
+ if (engine->istream)
+ camel_object_unref (engine->istream);
+
+ if (engine->ostream)
+ camel_object_unref (engine->ostream);
+
+ g_hash_table_foreach (engine->authtypes, (GHFunc) g_free, NULL);
+ g_hash_table_destroy (engine->authtypes);
+
+ imap4_namespace_clear (&engine->namespaces.personal);
+ imap4_namespace_clear (&engine->namespaces.other);
+ imap4_namespace_clear (&engine->namespaces.shared);
+
+ if (engine->folder)
+ camel_object_unref (engine->folder);
+
+ while ((node = e_dlist_remhead (&engine->queue))) {
+ node->next = NULL;
+ node->prev = NULL;
+
+ camel_imap4_command_unref ((CamelIMAP4Command *) node);
+ }
+}
+
+
+/**
+ * camel_imap4_engine_new:
+ * @service: service
+ *
+ * Returns a new imap4 engine
+ **/
+CamelIMAP4Engine *
+camel_imap4_engine_new (CamelService *service, CamelIMAP4ReconnectFunc reconnect)
+{
+ CamelIMAP4Engine *engine;
+
+ g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL);
+
+ engine = (CamelIMAP4Engine *) camel_object_new (CAMEL_TYPE_IMAP4_ENGINE);
+ engine->session = service->session;
+ engine->url = service->url;
+ engine->service = service;
+ engine->reconnect = reconnect;
+
+ return engine;
+}
+
+
+/**
+ * camel_imap4_engine_take_stream:
+ * @engine: imap4 engine
+ * @stream: tcp stream
+ * @ex: exception
+ *
+ * Gives ownership of @stream to @engine and reads the greeting from
+ * the stream.
+ *
+ * Returns 0 on success or -1 on fail.
+ *
+ * Note: on error, @stream will be unref'd.
+ **/
+int
+camel_imap4_engine_take_stream (CamelIMAP4Engine *engine, CamelStream *stream, CamelException *ex)
+{
+ camel_imap4_token_t token;
+ int code;
+
+ g_return_val_if_fail (CAMEL_IS_IMAP4_ENGINE (engine), -1);
+ g_return_val_if_fail (CAMEL_IS_STREAM (stream), -1);
+
+ if (engine->istream)
+ camel_object_unref (engine->istream);
+
+ if (engine->ostream)
+ camel_object_unref (engine->ostream);
+
+ engine->istream = (CamelIMAP4Stream *) camel_imap4_stream_new (stream);
+ engine->ostream = camel_stream_buffer_new (stream, CAMEL_STREAM_BUFFER_WRITE);
+ engine->state = CAMEL_IMAP4_ENGINE_CONNECTED;
+ camel_object_unref (stream);
+
+ if (camel_imap4_engine_next_token (engine, &token, ex) == -1)
+ goto exception;
+
+ if (token.token != '*') {
+ camel_imap4_utils_set_unexpected_token_error (ex, engine, &token);
+ goto exception;
+ }
+
+ if ((code = camel_imap4_engine_handle_untagged_1 (engine, &token, ex)) == -1) {
+ goto exception;
+ } else if (code != CAMEL_IMAP4_UNTAGGED_OK && code != CAMEL_IMAP4_UNTAGGED_PREAUTH) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, _("Unexpected greeting from IMAP server %s."),
+ engine->url->host);
+ goto exception;
+ }
+
+ return 0;
+
+ exception:
+
+ engine->state = CAMEL_IMAP4_ENGINE_DISCONNECTED;
+
+ camel_object_unref (engine->istream);
+ engine->istream = NULL;
+ camel_object_unref (engine->ostream);
+ engine->ostream = NULL;
+
+ return -1;
+}
+
+
+/**
+ * camel_imap4_engine_capability:
+ * @engine: IMAP4 engine
+ * @ex: exception
+ *
+ * Forces the IMAP4 engine to query the IMAP4 server for a list of capabilities.
+ *
+ * Returns 0 on success or -1 on fail.
+ **/
+int
+camel_imap4_engine_capability (CamelIMAP4Engine *engine, CamelException *ex)
+{
+ CamelIMAP4Command *ic;
+ int id, retval = 0;
+
+ ic = camel_imap4_engine_prequeue (engine, NULL, "CAPABILITY\r\n");
+
+ while ((id = camel_imap4_engine_iterate (engine)) < ic->id && id != -1)
+ ;
+
+ if (id == -1 || ic->status != CAMEL_IMAP4_COMMAND_COMPLETE) {
+ camel_exception_xfer (ex, &ic->ex);
+ retval = -1;
+ }
+
+ camel_imap4_command_unref (ic);
+
+ return retval;
+}
+
+
+/**
+ * camel_imap4_engine_namespace:
+ * @engine: IMAP4 engine
+ * @ex: exception
+ *
+ * Forces the IMAP4 engine to query the IMAP4 server for a list of namespaces.
+ *
+ * Returns 0 on success or -1 on fail.
+ **/
+int
+camel_imap4_engine_namespace (CamelIMAP4Engine *engine, CamelException *ex)
+{
+ camel_imap4_list_t *list;
+ GPtrArray *array = NULL;
+ CamelIMAP4Command *ic;
+ int id, i;
+
+ if (engine->capa & CAMEL_IMAP4_CAPABILITY_NAMESPACE) {
+ ic = camel_imap4_engine_prequeue (engine, NULL, "NAMESPACE\r\n");
+ } else {
+ ic = camel_imap4_engine_prequeue (engine, NULL, "LIST \"\" \"\"\r\n");
+ camel_imap4_command_register_untagged (ic, "LIST", camel_imap4_untagged_list);
+ ic->user_data = array = g_ptr_array_new ();
+ }
+
+ while ((id = camel_imap4_engine_iterate (engine)) < ic->id && id != -1)
+ ;
+
+ if (id == -1 || ic->status != CAMEL_IMAP4_COMMAND_COMPLETE) {
+ camel_exception_xfer (ex, &ic->ex);
+ camel_imap4_command_unref (ic);
+
+ if (array != NULL)
+ g_ptr_array_free (array, TRUE);
+
+ return -1;
+ }
+
+ if (array != NULL) {
+ if (ic->result == CAMEL_IMAP4_RESULT_OK) {
+ CamelIMAP4Namespace *namespace;
+
+ g_assert (array->len == 1);
+ list = array->pdata[0];
+
+ namespace = g_new (CamelIMAP4Namespace, 1);
+ namespace->next = NULL;
+ namespace->path = g_strdup ("");
+ namespace->sep = list->delim;
+
+ engine->namespaces.personal = namespace;
+ } else {
+ /* should never *ever* happen */
+ }
+
+ for (i = 0; i < array->len; i++) {
+ list = array->pdata[i];
+ g_free (list->name);
+ g_free (list);
+ }
+
+ g_ptr_array_free (array, TRUE);
+ }
+
+ camel_imap4_command_unref (ic);
+
+ return 0;
+}
+
+
+int
+camel_imap4_engine_select_folder (CamelIMAP4Engine *engine, CamelFolder *folder, CamelException *ex)
+{
+ CamelIMAP4RespCode *resp;
+ CamelIMAP4Command *ic;
+ int id, retval = 0;
+ int i;
+
+ g_return_val_if_fail (CAMEL_IS_IMAP4_ENGINE (engine), -1);
+ g_return_val_if_fail (CAMEL_IS_IMAP4_FOLDER (folder), -1);
+
+ /* POSSIBLE FIXME: if the folder to be selected will already
+ * be selected by the time the queue is emptied, simply
+ * no-op? */
+
+ ic = camel_imap4_engine_queue (engine, folder, "SELECT %F\r\n", folder);
+ while ((id = camel_imap4_engine_iterate (engine)) < ic->id && id != -1)
+ ;
+
+ if (id == -1 || ic->status != CAMEL_IMAP4_COMMAND_COMPLETE) {
+ camel_exception_xfer (ex, &ic->ex);
+ camel_imap4_command_unref (ic);
+ return -1;
+ }
+
+ switch (ic->result) {
+ case CAMEL_IMAP4_RESULT_OK:
+ /*folder->mode = 0;*/
+ for (i = 0; i < ic->resp_codes->len; i++) {
+ resp = ic->resp_codes->pdata[i];
+ switch (resp->code) {
+ case CAMEL_IMAP4_RESP_CODE_PERM_FLAGS:
+ folder->permanent_flags = resp->v.flags;
+ break;
+ case CAMEL_IMAP4_RESP_CODE_READONLY:
+ /*folder->mode = CAMEL_FOLDER_MODE_READ_ONLY;*/
+ break;
+ case CAMEL_IMAP4_RESP_CODE_READWRITE:
+ /*folder->mode = CAMEL_FOLDER_MODE_READ_WRITE;*/
+ break;
+ case CAMEL_IMAP4_RESP_CODE_UIDNEXT:
+ camel_imap4_summary_set_uidnext (folder->summary, resp->v.uidnext);
+ break;
+ case CAMEL_IMAP4_RESP_CODE_UIDVALIDITY:
+ camel_imap4_summary_set_uidvalidity (folder->summary, resp->v.uidvalidity);
+ break;
+ case CAMEL_IMAP4_RESP_CODE_UNSEEN:
+ camel_imap4_summary_set_unseen (folder->summary, resp->v.unseen);
+ break;
+ default:
+ break;
+ }
+ }
+
+ /*if (folder->mode == 0) {
+ folder->mode = CAMEL_FOLDER_MODE_READ_ONLY;
+ g_warning ("Expected to find [READ-ONLY] or [READ-WRITE] in SELECT response");
+ }*/
+
+ break;
+ case CAMEL_IMAP4_RESULT_NO:
+ /* FIXME: would be good to save the NO reason into the err message */
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot select folder `%s': Invalid mailbox name"),
+ folder->full_name);
+ retval = -1;
+ break;
+ case CAMEL_IMAP4_RESULT_BAD:
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot select folder `%s': Bad command"),
+ folder->full_name);
+ retval = -1;
+ break;
+ default:
+ g_assert_not_reached ();
+ retval = -1;
+ }
+
+ camel_imap4_command_unref (ic);
+
+ return retval;
+}
+
+
+static struct {
+ const char *name;
+ guint32 flag;
+} imap4_capabilities[] = {
+ { "IMAP4", CAMEL_IMAP4_CAPABILITY_IMAP4 },
+ { "IMAP4REV1", CAMEL_IMAP4_CAPABILITY_IMAP4REV1 },
+ { "STATUS", CAMEL_IMAP4_CAPABILITY_STATUS },
+ { "NAMESPACE", CAMEL_IMAP4_CAPABILITY_NAMESPACE },
+ { "UIDPLUS", CAMEL_IMAP4_CAPABILITY_UIDPLUS },
+ { "LITERAL+", CAMEL_IMAP4_CAPABILITY_LITERALPLUS },
+ { "LOGINDISABLED", CAMEL_IMAP4_CAPABILITY_LOGINDISABLED },
+ { "STARTTLS", CAMEL_IMAP4_CAPABILITY_STARTTLS },
+ { NULL, 0 }
+};
+
+static gboolean
+auth_free (gpointer key, gpointer value, gpointer user_data)
+{
+ g_free (key);
+ return TRUE;
+}
+
+static int
+engine_parse_capability (CamelIMAP4Engine *engine, int sentinel, CamelException *ex)
+{
+ camel_imap4_token_t token;
+ int i;
+
+ engine->capa = CAMEL_IMAP4_CAPABILITY_utf8_search;
+ engine->level = 0;
+
+ g_hash_table_foreach_remove (engine->authtypes, (GHRFunc) auth_free, NULL);
+
+ if (camel_imap4_engine_next_token (engine, &token, ex) == -1)
+ return -1;
+
+ while (token.token == CAMEL_IMAP4_TOKEN_ATOM) {
+ if (!strncasecmp ("AUTH=", token.v.atom, 5)) {
+ CamelServiceAuthType *auth;
+
+ if ((auth = camel_sasl_authtype (token.v.atom + 5)) != NULL)
+ g_hash_table_insert (engine->authtypes, g_strdup (token.v.atom + 5), auth);
+ } else {
+ for (i = 0; imap4_capabilities[i].name; i++) {
+ if (!g_ascii_strcasecmp (imap4_capabilities[i].name, token.v.atom))
+ engine->capa |= imap4_capabilities[i].flag;
+ }
+ }
+
+ if (camel_imap4_engine_next_token (engine, &token, ex) == -1)
+ return -1;
+ }
+
+ if (token.token != sentinel) {
+ camel_imap4_utils_set_unexpected_token_error (ex, engine, &token);
+ return -1;
+ }
+
+ /* unget our sentinel token */
+ camel_imap4_stream_unget_token (engine->istream, &token);
+
+ /* figure out which version of IMAP4 we are dealing with */
+ if (engine->capa & CAMEL_IMAP4_CAPABILITY_IMAP4REV1) {
+ engine->level = CAMEL_IMAP4_LEVEL_IMAP4REV1;
+ engine->capa |= CAMEL_IMAP4_CAPABILITY_STATUS;
+ } else if (engine->capa & CAMEL_IMAP4_CAPABILITY_IMAP4) {
+ engine->level = CAMEL_IMAP4_LEVEL_IMAP4;
+ } else {
+ engine->level = CAMEL_IMAP4_LEVEL_UNKNOWN;
+ }
+
+ return 0;
+}
+
+static int
+engine_parse_flags_list (CamelIMAP4Engine *engine, CamelIMAP4RespCode *resp, int perm, CamelException *ex)
+{
+ guint32 flags = 0;
+
+ if (camel_imap4_parse_flags_list (engine, &flags, ex) == -1)
+ return-1;
+
+ if (resp != NULL)
+ resp->v.flags = flags;
+
+ if (engine->current && engine->current->folder) {
+ if (perm)
+ ((CamelFolder *) engine->current->folder)->permanent_flags = flags;
+ /*else
+ ((CamelFolder *) engine->current->folder)->folder_flags = flags;*/
+ } else if (engine->folder) {
+ if (perm)
+ ((CamelFolder *) engine->folder)->permanent_flags = flags;
+ /*else
+ ((CamelFolder *) engine->folder)->folder_flags = flags;*/
+ } else {
+ fprintf (stderr, "We seem to be in a bit of a pickle. we've just parsed an untagged %s\n"
+ "response for a folder, yet we do not currently have a folder selected?\n",
+ perm ? "PERMANENTFLAGS" : "FLAGS");
+ }
+
+ return 0;
+}
+
+static int
+engine_parse_flags (CamelIMAP4Engine *engine, CamelException *ex)
+{
+ camel_imap4_token_t token;
+
+ if (engine_parse_flags_list (engine, NULL, FALSE, ex) == -1)
+ return -1;
+
+ if (camel_imap4_engine_next_token (engine, &token, ex) == -1)
+ return -1;
+
+ if (token.token != '\n') {
+ d(fprintf (stderr, "Expected to find a '\\n' token after the FLAGS response\n"));
+ camel_imap4_utils_set_unexpected_token_error (ex, engine, &token);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+engine_parse_namespace (CamelIMAP4Engine *engine, CamelException *ex)
+{
+ CamelIMAP4Namespace *namespaces[3], *node, *tail;
+ camel_imap4_token_t token;
+ int i, n = 0;
+
+ imap4_namespace_clear (&engine->namespaces.personal);
+ imap4_namespace_clear (&engine->namespaces.other);
+ imap4_namespace_clear (&engine->namespaces.shared);
+
+ if (camel_imap4_engine_next_token (engine, &token, ex) == -1)
+ return -1;
+
+ do {
+ namespaces[n] = NULL;
+ tail = (CamelIMAP4Namespace *) &namespaces[n];
+
+ if (token.token == '(') {
+ /* decode the list of namespace pairs */
+ if (camel_imap4_engine_next_token (engine, &token, ex) == -1)
+ goto exception;
+
+ while (token.token == '(') {
+ /* decode a namespace pair */
+
+ /* get the path name token */
+ if (camel_imap4_engine_next_token (engine, &token, ex) == -1)
+ goto exception;
+
+ if (token.token != CAMEL_IMAP4_TOKEN_QSTRING) {
+ d(fprintf (stderr, "Expected to find a qstring token as first element in NAMESPACE pair\n"));
+ camel_imap4_utils_set_unexpected_token_error (ex, engine, &token);
+ goto exception;
+ }
+
+ node = g_new (CamelIMAP4Namespace, 1);
+ node->next = NULL;
+ node->path = g_strdup (token.v.qstring);
+
+ /* get the path delimiter token */
+ if (camel_imap4_engine_next_token (engine, &token, ex) == -1) {
+ g_free (node->path);
+ g_free (node);
+
+ goto exception;
+ }
+
+ if (token.token != CAMEL_IMAP4_TOKEN_QSTRING || strlen (token.v.qstring) > 1) {
+ d(fprintf (stderr, "Expected to find a qstring token as second element in NAMESPACE pair\n"));
+ camel_imap4_utils_set_unexpected_token_error (ex, engine, &token);
+ g_free (node->path);
+ g_free (node);
+
+ goto exception;
+ }
+
+ node->sep = *token.v.qstring;
+ tail->next = node;
+ tail = node;
+
+ /* canonicalise the namespace path */
+ if (node->path[strlen (node->path) - 1] == node->sep)
+ node->path[strlen (node->path) - 1] = '\0';
+
+ /* canonicalise if this is an INBOX namespace */
+ if (!g_ascii_strncasecmp (node->path, "INBOX", 5) &&
+ (node->path[6] == '\0' || node->path[6] == node->sep))
+ memcpy (node->path, "INBOX", 5);
+
+ /* get the closing ')' for this namespace pair */
+ if (camel_imap4_engine_next_token (engine, &token, ex) == -1)
+ goto exception;
+
+ if (token.token != ')') {
+ d(fprintf (stderr, "Expected to find a ')' token to close the current namespace pair\n"));
+ camel_imap4_utils_set_unexpected_token_error (ex, engine, &token);
+
+ goto exception;
+ }
+
+ /* get the next token (should be either '(' or ')') */
+ if (camel_imap4_engine_next_token (engine, &token, ex) == -1)
+ goto exception;
+ }
+
+ if (token.token != ')') {
+ d(fprintf (stderr, "Expected to find a ')' to close the current namespace list\n"));
+ camel_imap4_utils_set_unexpected_token_error (ex, engine, &token);
+ goto exception;
+ }
+ } else if (token.token == CAMEL_IMAP4_TOKEN_NIL) {
+ /* namespace list is NIL */
+ namespaces[n] = NULL;
+ } else {
+ d(fprintf (stderr, "Expected to find either NIL or '(' token in untagged NAMESPACE response\n"));
+ camel_imap4_utils_set_unexpected_token_error (ex, engine, &token);
+ goto exception;
+ }
+
+ /* get the next token (should be either '(', NIL, or '\n') */
+ if (camel_imap4_engine_next_token (engine, &token, ex) == -1)
+ goto exception;
+
+ n++;
+ } while (n < 3);
+
+ engine->namespaces.personal = namespaces[0];
+ engine->namespaces.other = namespaces[1];
+ engine->namespaces.shared = namespaces[2];
+
+ return 0;
+
+ exception:
+
+ for (i = 0; i <= n; i++)
+ imap4_namespace_clear (&namespaces[i]);
+
+ return -1;
+}
+
+
+/**
+ *
+ * resp-text-code = "ALERT" /
+ * "BADCHARSET" [SP "(" astring *(SP astring) ")" ] /
+ * capability-data / "PARSE" /
+ * "PERMANENTFLAGS" SP "(" [flag-perm *(SP flag-perm)] ")" /
+ * "READ-ONLY" / "READ-WRITE" / "TRYCREATE" /
+ * "UIDNEXT" SP nz-number / "UIDVALIDITY" SP nz-number /
+ * "UNSEEN" SP nz-number /
+ * atom [SP 1*<any TEXT-CHAR except "]">]
+ **/
+
+static struct {
+ const char *name;
+ camel_imap4_resp_code_t code;
+ int save;
+} imap4_resp_codes[] = {
+ { "ALERT", CAMEL_IMAP4_RESP_CODE_ALERT, 0 },
+ { "BADCHARSET", CAMEL_IMAP4_RESP_CODE_BADCHARSET, 0 },
+ { "CAPABILITY", CAMEL_IMAP4_RESP_CODE_CAPABILITY, 0 },
+ { "PARSE", CAMEL_IMAP4_RESP_CODE_PARSE, 1 },
+ { "PERMANENTFLAGS", CAMEL_IMAP4_RESP_CODE_PERM_FLAGS, 1 },
+ { "READ-ONLY", CAMEL_IMAP4_RESP_CODE_READONLY, 1 },
+ { "READ-WRITE", CAMEL_IMAP4_RESP_CODE_READWRITE, 1 },
+ { "TRYCREATE", CAMEL_IMAP4_RESP_CODE_TRYCREATE, 1 },
+ { "UIDNEXT", CAMEL_IMAP4_RESP_CODE_UIDNEXT, 1 },
+ { "UIDVALIDITY", CAMEL_IMAP4_RESP_CODE_UIDVALIDITY, 1 },
+ { "UNSEEN", CAMEL_IMAP4_RESP_CODE_UNSEEN, 1 },
+ { "NEWNAME", CAMEL_IMAP4_RESP_CODE_NEWNAME, 1 },
+ { "APPENDUID", CAMEL_IMAP4_RESP_CODE_APPENDUID, 1 },
+ { "COPYUID", CAMEL_IMAP4_RESP_CODE_COPYUID, 1 },
+ { NULL, CAMEL_IMAP4_RESP_CODE_UNKNOWN, 0 }
+};
+
+
+int
+camel_imap4_engine_parse_resp_code (CamelIMAP4Engine *engine, CamelException *ex)
+{
+ CamelIMAP4RespCode *resp = NULL;
+ camel_imap4_resp_code_t code;
+ camel_imap4_token_t token;
+ unsigned char *linebuf;
+ size_t len;
+
+ if (camel_imap4_engine_next_token (engine, &token, ex) == -1)
+ return -1;
+
+ if (token.token != '[') {
+ d(fprintf (stderr, "Expected a '[' token (followed by a RESP-CODE)\n"));
+ camel_imap4_utils_set_unexpected_token_error (ex, engine, &token);
+ return -1;
+ }
+
+ if (camel_imap4_engine_next_token (engine, &token, ex) == -1)
+ return -1;
+
+ if (token.token != CAMEL_IMAP4_TOKEN_ATOM) {
+ d(fprintf (stderr, "Expected an atom token containing a RESP-CODE\n"));
+ camel_imap4_utils_set_unexpected_token_error (ex, engine, &token);
+ return -1;
+ }
+
+ for (code = 0; imap4_resp_codes[code].name; code++) {
+ if (!strcmp (imap4_resp_codes[code].name, token.v.atom)) {
+ if (engine->current && imap4_resp_codes[code].save) {
+ resp = g_new0 (CamelIMAP4RespCode, 1);
+ resp->code = code;
+ }
+ break;
+ }
+ }
+
+ switch (code) {
+ case CAMEL_IMAP4_RESP_CODE_BADCHARSET:
+ /* apparently we don't support UTF-8 afterall */
+ engine->capa &= ~CAMEL_IMAP4_CAPABILITY_utf8_search;
+ break;
+ case CAMEL_IMAP4_RESP_CODE_CAPABILITY:
+ /* capability list follows */
+ if (engine_parse_capability (engine, ']', ex) == -1)
+ goto exception;
+ break;
+ case CAMEL_IMAP4_RESP_CODE_PERM_FLAGS:
+ /* flag list follows */
+ if (engine_parse_flags_list (engine, resp, TRUE, ex) == -1)
+ goto exception;
+ break;
+ case CAMEL_IMAP4_RESP_CODE_READONLY:
+ break;
+ case CAMEL_IMAP4_RESP_CODE_READWRITE:
+ break;
+ case CAMEL_IMAP4_RESP_CODE_TRYCREATE:
+ break;
+ case CAMEL_IMAP4_RESP_CODE_UIDNEXT:
+ if (camel_imap4_engine_next_token (engine, &token, ex) == -1)
+ goto exception;
+
+ if (token.token != CAMEL_IMAP4_TOKEN_NUMBER) {
+ d(fprintf (stderr, "Expected an nz_number token as an argument to the UIDNEXT RESP-CODE\n"));
+ camel_imap4_utils_set_unexpected_token_error (ex, engine, &token);
+ goto exception;
+ }
+
+ if (resp != NULL)
+ resp->v.uidnext = token.v.number;
+
+ break;
+ case CAMEL_IMAP4_RESP_CODE_UIDVALIDITY:
+ if (camel_imap4_engine_next_token (engine, &token, ex) == -1)
+ goto exception;
+
+ if (token.token != CAMEL_IMAP4_TOKEN_NUMBER) {
+ d(fprintf (stderr, "Expected an nz_number token as an argument to the UIDVALIDITY RESP-CODE\n"));
+ camel_imap4_utils_set_unexpected_token_error (ex, engine, &token);
+ goto exception;
+ }
+
+ if (resp != NULL)
+ resp->v.uidvalidity = token.v.number;
+
+ break;
+ case CAMEL_IMAP4_RESP_CODE_UNSEEN:
+ if (camel_imap4_engine_next_token (engine, &token, ex) == -1)
+ return -1;
+
+ if (token.token != CAMEL_IMAP4_TOKEN_NUMBER) {
+ d(fprintf (stderr, "Expected an nz_number token as an argument to the UNSEEN RESP-CODE\n"));
+ camel_imap4_utils_set_unexpected_token_error (ex, engine, &token);
+ goto exception;
+ }
+
+ if (resp != NULL)
+ resp->v.unseen = token.v.number;
+
+ break;
+ case CAMEL_IMAP4_RESP_CODE_NEWNAME:
+ /* this RESP-CODE may actually be removed - see here:
+ * http://www.washington.edu/imap4/listarch/2001/msg00058.html */
+
+ if (camel_imap4_engine_next_token (engine, &token, ex) == -1)
+ return -1;
+
+ if (token.token != CAMEL_IMAP4_TOKEN_ATOM && token.token != CAMEL_IMAP4_TOKEN_QSTRING) {
+ d(fprintf (stderr, "Expected an atom or qstring token as the first argument to the NEWNAME RESP-CODE\n"));
+ camel_imap4_utils_set_unexpected_token_error (ex, engine, &token);
+ goto exception;
+ }
+
+ if (resp != NULL)
+ resp->v.newname[0] = g_strdup (token.v.atom);
+
+ if (token.token != CAMEL_IMAP4_TOKEN_ATOM && token.token != CAMEL_IMAP4_TOKEN_QSTRING) {
+ d(fprintf (stderr, "Expected an atom or qstring token as the second argument to the NEWNAME RESP-CODE\n"));
+ camel_imap4_utils_set_unexpected_token_error (ex, engine, &token);
+ goto exception;
+ }
+
+ if (resp != NULL)
+ resp->v.newname[1] = g_strdup (token.v.atom);
+
+ break;
+ case CAMEL_IMAP4_RESP_CODE_APPENDUID:
+ if (camel_imap4_engine_next_token (engine, &token, ex) == -1)
+ return -1;
+
+ if (token.token != CAMEL_IMAP4_TOKEN_NUMBER) {
+ d(fprintf (stderr, "Expected an nz_number token as the first argument to the APPENDUID RESP-CODE\n"));
+ camel_imap4_utils_set_unexpected_token_error (ex, engine, &token);
+ goto exception;
+ }
+
+ if (resp != NULL)
+ resp->v.appenduid.uidvalidity = token.v.number;
+
+ if (camel_imap4_engine_next_token (engine, &token, ex) == -1)
+ return -1;
+
+ if (token.token != CAMEL_IMAP4_TOKEN_NUMBER) {
+ d(fprintf (stderr, "Expected an nz_number token as the second argument to the APPENDUID RESP-CODE\n"));
+ camel_imap4_utils_set_unexpected_token_error (ex, engine, &token);
+ goto exception;
+ }
+
+ if (resp != NULL)
+ resp->v.appenduid.uid = token.v.number;
+
+ break;
+ case CAMEL_IMAP4_RESP_CODE_COPYUID:
+ if (camel_imap4_engine_next_token (engine, &token, ex) == -1)
+ return -1;
+
+ if (token.token != CAMEL_IMAP4_TOKEN_NUMBER) {
+ d(fprintf (stderr, "Expected an nz_number token as the first argument to the COPYUID RESP-CODE\n"));
+ camel_imap4_utils_set_unexpected_token_error (ex, engine, &token);
+ goto exception;
+ }
+
+ if (resp != NULL)
+ resp->v.copyuid.uidvalidity = token.v.number;
+
+ if (camel_imap4_engine_next_token (engine, &token, ex) == -1)
+ return -1;
+
+ if (token.token != CAMEL_IMAP4_TOKEN_ATOM) {
+ d(fprintf (stderr, "Expected an atom token as the second argument to the COPYUID RESP-CODE\n"));
+ camel_imap4_utils_set_unexpected_token_error (ex, engine, &token);
+ goto exception;
+ }
+
+ if (resp != NULL)
+ resp->v.copyuid.srcset = g_strdup (token.v.atom);
+
+ if (camel_imap4_engine_next_token (engine, &token, ex) == -1)
+ return -1;
+
+ if (token.token != CAMEL_IMAP4_TOKEN_ATOM) {
+ d(fprintf (stderr, "Expected an atom token as the third argument to the APPENDUID RESP-CODE\n"));
+ camel_imap4_utils_set_unexpected_token_error (ex, engine, &token);
+ goto exception;
+ }
+
+ if (resp != NULL)
+ resp->v.copyuid.destset = g_strdup (token.v.atom);
+
+ break;
+ default:
+ d(fprintf (stderr, "Unknown RESP-CODE encountered: %s\n", token.v.atom));
+
+ /* extensions are of the form: "[" atom [SPACE 1*<any TEXT_CHAR except "]">] "]" */
+
+ /* eat up the TEXT_CHARs */
+ while (token.token != ']' && token.token != '\n') {
+ if (camel_imap4_engine_next_token (engine, &token, ex) == -1)
+ goto exception;
+ }
+
+ break;
+ }
+
+ while (token.token != ']' && token.token != '\n') {
+ if (camel_imap4_engine_next_token (engine, &token, ex) == -1)
+ goto exception;
+ }
+
+ if (token.token != ']') {
+ camel_imap4_utils_set_unexpected_token_error (ex, engine, &token);
+ d(fprintf (stderr, "Expected to find a ']' token after the RESP-CODE\n"));
+ return -1;
+ }
+
+ if (code == CAMEL_IMAP4_RESP_CODE_ALERT) {
+ if (camel_imap4_engine_line (engine, &linebuf, &len, ex) == -1)
+ goto exception;
+
+ camel_session_alert_user (engine->session, CAMEL_SESSION_ALERT_INFO, linebuf, FALSE);
+ g_free (linebuf);
+ } else if (resp != NULL && code == CAMEL_IMAP4_RESP_CODE_PARSE) {
+ if (camel_imap4_engine_line (engine, &linebuf, &len, ex) == -1)
+ goto exception;
+
+ resp->v.parse = linebuf;
+ } else {
+ /* eat up the rest of the response */
+ if (camel_imap4_engine_line (engine, NULL, NULL, ex) == -1)
+ goto exception;
+ }
+
+ if (resp != NULL)
+ g_ptr_array_add (engine->current->resp_codes, resp);
+
+ return 0;
+
+ exception:
+
+ if (resp != NULL)
+ camel_imap4_resp_code_free (resp);
+
+ return -1;
+}
+
+
+
+/* returns -1 on error, or one of CAMEL_IMAP4_UNTAGGED_[OK,NO,BAD,PREAUTH,HANDLED] on success */
+int
+camel_imap4_engine_handle_untagged_1 (CamelIMAP4Engine *engine, camel_imap4_token_t *token, CamelException *ex)
+{
+ int code = CAMEL_IMAP4_UNTAGGED_HANDLED;
+ CamelIMAP4Command *ic = engine->current;
+ CamelIMAP4UntaggedCallback untagged;
+ CamelFolder *folder;
+ unsigned int v;
+
+ if (camel_imap4_engine_next_token (engine, token, ex) == -1)
+ return -1;
+
+ if (token->token == CAMEL_IMAP4_TOKEN_ATOM) {
+ if (!strcmp ("BYE", token->v.atom)) {
+ /* we don't care if we fail here, either way we've been disconnected */
+ if (camel_imap4_engine_next_token (engine, token, NULL) == 0) {
+ if (token->token == '[') {
+ camel_imap4_stream_unget_token (engine->istream, token);
+ camel_imap4_engine_parse_resp_code (engine, NULL);
+ } else {
+ camel_imap4_engine_line (engine, NULL, NULL, NULL);
+ }
+ }
+
+ engine->state = CAMEL_IMAP4_ENGINE_DISCONNECTED;
+
+ /* we don't return -1 here because there may be more untagged responses after the BYE */
+ } else if (!strcmp ("CAPABILITY", token->v.atom)) {
+ /* capability tokens follow */
+ if (engine_parse_capability (engine, '\n', ex) == -1)
+ return -1;
+
+ /* find the eoln token */
+ if (camel_imap4_engine_next_token (engine, token, ex) == -1)
+ return -1;
+
+ if (token->token != '\n') {
+ camel_imap4_utils_set_unexpected_token_error (ex, engine, token);
+ return -1;
+ }
+ } else if (!strcmp ("FLAGS", token->v.atom)) {
+ /* flags list follows */
+ if (engine_parse_flags (engine, ex) == -1)
+ return -1;
+ } else if (!strcmp ("NAMESPACE", token->v.atom)) {
+ if (engine_parse_namespace (engine, ex) == -1)
+ return -1;
+ } else if (!strcmp ("NO", token->v.atom) || !strcmp ("BAD", token->v.atom)) {
+ code = !strcmp ("NO", token->v.atom) ? CAMEL_IMAP4_UNTAGGED_NO : CAMEL_IMAP4_UNTAGGED_BAD;
+
+ /* our command has been rejected */
+ if (camel_imap4_engine_next_token (engine, token, ex) == -1)
+ return -1;
+
+ if (token->token == '[') {
+ /* we have a resp code */
+ camel_imap4_stream_unget_token (engine->istream, token);
+ if (camel_imap4_engine_parse_resp_code (engine, ex) == -1)
+ return -1;
+ } else if (token->token != '\n') {
+ /* we just have resp text */
+ if (camel_imap4_engine_line (engine, NULL, NULL, ex) == -1)
+ return -1;
+ }
+ } else if (!strcmp ("OK", token->v.atom)) {
+ code = CAMEL_IMAP4_UNTAGGED_OK;
+
+ if (engine->state == CAMEL_IMAP4_ENGINE_CONNECTED) {
+ /* initial server greeting */
+ engine->state = CAMEL_IMAP4_ENGINE_PREAUTH;
+ }
+
+ if (camel_imap4_engine_next_token (engine, token, ex) == -1)
+ return -1;
+
+ if (token->token == '[') {
+ /* we have a resp code */
+ camel_imap4_stream_unget_token (engine->istream, token);
+ if (camel_imap4_engine_parse_resp_code (engine, ex) == -1)
+ return -1;
+ } else {
+ /* we just have resp text */
+ if (camel_imap4_engine_line (engine, NULL, NULL, ex) == -1)
+ return -1;
+ }
+ } else if (!strcmp ("PREAUTH", token->v.atom)) {
+ code = CAMEL_IMAP4_UNTAGGED_PREAUTH;
+
+ if (engine->state == CAMEL_IMAP4_ENGINE_CONNECTED)
+ engine->state = CAMEL_IMAP4_ENGINE_AUTHENTICATED;
+
+ if (camel_imap4_engine_parse_resp_code (engine, ex) == -1)
+ return -1;
+ } else if (ic && (untagged = g_hash_table_lookup (ic->untagged, token->v.atom))) {
+ /* registered untagged handler for imap4 command */
+ if (untagged (engine, ic, 0, token, ex) == -1)
+ return -1;
+ } else {
+ d(fprintf (stderr, "Unhandled atom token in untagged response: %s", token->v.atom));
+
+ if (camel_imap4_engine_eat_line (engine, ex) == -1)
+ return -1;
+ }
+ } else if (token->token == CAMEL_IMAP4_TOKEN_NUMBER) {
+ /* we probably have something like "* 1 EXISTS" */
+ v = token->v.number;
+
+ if (camel_imap4_engine_next_token (engine, token, ex) == -1)
+ return -1;
+
+ if (token->token != CAMEL_IMAP4_TOKEN_ATOM) {
+ camel_imap4_utils_set_unexpected_token_error (ex, engine, token);
+
+ return -1;
+ }
+
+ /* which folder is this EXISTS/EXPUNGE/RECENT acting on? */
+ if (engine->current && engine->current->folder)
+ folder = (CamelFolder *) engine->current->folder;
+ else if (engine->folder)
+ folder = (CamelFolder *) engine->folder;
+ else
+ folder = NULL;
+
+ /* NOTE: these can be over-ridden by a registered untagged response handler */
+ if (!strcmp ("EXISTS", token->v.atom)) {
+ camel_imap4_summary_set_exists (folder->summary, v);
+ } else if (!strcmp ("EXPUNGE", token->v.atom)) {
+ camel_imap4_summary_expunge (folder->summary, (int) v);
+ } else if (!strcmp ("RECENT", token->v.atom)) {
+ camel_imap4_summary_set_recent (folder->summary, v);
+ } else if (ic && (untagged = g_hash_table_lookup (ic->untagged, token->v.atom))) {
+ /* registered untagged handler for imap4 command */
+ if (untagged (engine, ic, v, token, ex) == -1)
+ return -1;
+ } else {
+ d(fprintf (stderr, "Unrecognized untagged response: * %u %s\n", v, token->v.atom));
+ }
+
+ /* find the eoln token */
+ if (camel_imap4_engine_eat_line (engine, ex) == -1)
+ return -1;
+ } else {
+ camel_imap4_utils_set_unexpected_token_error (ex, engine, token);
+
+ return -1;
+ }
+
+ return code;
+}
+
+
+void
+camel_imap4_engine_handle_untagged (CamelIMAP4Engine *engine, CamelException *ex)
+{
+ camel_imap4_token_t token;
+
+ g_return_if_fail (CAMEL_IS_IMAP4_ENGINE (engine));
+
+ do {
+ if (camel_imap4_engine_next_token (engine, &token, ex) == -1)
+ goto exception;
+
+ if (token.token != '*')
+ break;
+
+ if (camel_imap4_engine_handle_untagged_1 (engine, &token, ex) == -1)
+ goto exception;
+ } while (1);
+
+ camel_imap4_stream_unget_token (engine->istream, &token);
+
+ return;
+
+ exception:
+
+ engine->state = CAMEL_IMAP4_ENGINE_DISCONNECTED;
+}
+
+
+static int
+imap4_process_command (CamelIMAP4Engine *engine, CamelIMAP4Command *ic)
+{
+ int retval;
+
+ while ((retval = camel_imap4_command_step (ic)) == 0)
+ ;
+
+ if (retval == -1) {
+ engine->state = CAMEL_IMAP4_ENGINE_DISCONNECTED;
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static void
+engine_prequeue_folder_select (CamelIMAP4Engine *engine)
+{
+ CamelIMAP4Command *ic;
+ const char *cmd;
+
+ ic = (CamelIMAP4Command *) engine->queue.head;
+ cmd = (const char *) ic->parts->buffer;
+
+ if (!ic->folder || ic->folder == engine->folder ||
+ !strncmp (cmd, "SELECT ", 7) || !strncmp (cmd, "EXAMINE ", 8)) {
+ /* no need to pre-queue a SELECT */
+ return;
+ }
+
+ /* we need to pre-queue a SELECT */
+ ic = camel_imap4_engine_prequeue (engine, (CamelFolder *) ic->folder, "SELECT %F\r\n", ic->folder);
+ ic->user_data = engine;
+
+ camel_imap4_command_unref (ic);
+}
+
+
+static int
+engine_state_change (CamelIMAP4Engine *engine, CamelIMAP4Command *ic)
+{
+ const char *cmd;
+ int retval = 0;
+
+ cmd = ic->parts->buffer;
+ if (!strncmp (cmd, "SELECT ", 7) || !strncmp (cmd, "EXAMINE ", 8)) {
+ if (ic->result == CAMEL_IMAP4_RESULT_OK) {
+ /* Update the selected folder */
+ camel_object_ref (ic->folder);
+ if (engine->folder)
+ camel_object_unref (engine->folder);
+ engine->folder = ic->folder;
+
+ engine->state = CAMEL_IMAP4_ENGINE_SELECTED;
+ } else if (ic->user_data == engine) {
+ /* the engine pre-queued this SELECT command */
+ retval = -1;
+ }
+ } else if (!strncmp (cmd, "CLOSE", 5)) {
+ if (ic->result == CAMEL_IMAP4_RESULT_OK)
+ engine->state = CAMEL_IMAP4_ENGINE_AUTHENTICATED;
+ } else if (!strncmp (cmd, "LOGOUT", 6)) {
+ engine->state = CAMEL_IMAP4_ENGINE_DISCONNECTED;
+ }
+
+ return retval;
+}
+
+/**
+ * camel_imap4_engine_iterate:
+ * @engine: IMAP4 engine
+ *
+ * Processes the first command in the queue.
+ *
+ * Returns the id of the processed command, 0 if there were no
+ * commands to process, or -1 on error.
+ *
+ * Note: more details on the error will be held on the
+ * CamelIMAP4Command that failed.
+ **/
+int
+camel_imap4_engine_iterate (CamelIMAP4Engine *engine)
+{
+ CamelIMAP4Command *ic, *nic;
+ GPtrArray *resp_codes;
+ int retval = -1;
+
+ if (e_dlist_empty (&engine->queue))
+ return 0;
+
+ /* This sucks... it would be nicer if we didn't have to check the stream's disconnected status */
+ if ((engine->state == CAMEL_IMAP4_ENGINE_DISCONNECTED || engine->istream->disconnected) && !engine->reconnecting) {
+ CamelException rex;
+ gboolean connected;
+
+ camel_exception_init (&rex);
+ engine->reconnecting = TRUE;
+ connected = engine->reconnect (engine, &rex);
+ engine->reconnecting = FALSE;
+
+ if (!connected) {
+ /* pop the first command and act as tho it failed (which, technically, it did...) */
+ ic = (CamelIMAP4Command *) e_dlist_remhead (&engine->queue);
+ ic->status = CAMEL_IMAP4_COMMAND_ERROR;
+ camel_exception_xfer (&ic->ex, &rex);
+ return -1;
+ }
+ }
+
+ /* check to see if we need to pre-queue a SELECT, if so do it */
+ engine_prequeue_folder_select (engine);
+
+ engine->current = ic = (CamelIMAP4Command *) e_dlist_remhead (&engine->queue);
+ ic->status = CAMEL_IMAP4_COMMAND_ACTIVE;
+
+ if (imap4_process_command (engine, ic) != -1) {
+ if (engine_state_change (engine, ic) == -1) {
+ /* This can ONLY happen if @ic was the pre-queued SELECT command
+ * and it got a NO or BAD response.
+ *
+ * We have to pop the next imap4 command or we'll get into an
+ * infinite loop. In order to provide @nic's owner with as much
+ * information as possible, we move all @ic status information
+ * over to @nic and pretend we just processed @nic.
+ **/
+
+ nic = (CamelIMAP4Command *) e_dlist_remhead (&engine->queue);
+
+ nic->status = ic->status;
+ nic->result = ic->result;
+ resp_codes = nic->resp_codes;
+ nic->resp_codes = ic->resp_codes;
+ ic->resp_codes = resp_codes;
+
+ camel_exception_xfer (&nic->ex, &ic->ex);
+
+ camel_imap4_command_unref (ic);
+ ic = nic;
+ }
+
+ retval = ic->id;
+ }
+
+ camel_imap4_command_unref (ic);
+
+ return retval;
+}
+
+
+/**
+ * camel_imap4_engine_queue:
+ * @engine: IMAP4 engine
+ * @folder: IMAP4 folder that the command will affect (or %NULL if it doesn't matter)
+ * @format: command format
+ * @Varargs: arguments
+ *
+ * Basically the same as camel_imap4_command_new() except that this
+ * function also places the command in the engine queue.
+ *
+ * Returns the CamelIMAP4Command.
+ **/
+CamelIMAP4Command *
+camel_imap4_engine_queue (CamelIMAP4Engine *engine, CamelFolder *folder, const char *format, ...)
+{
+ CamelIMAP4Command *ic;
+ va_list args;
+
+ g_return_val_if_fail (CAMEL_IS_IMAP4_ENGINE (engine), NULL);
+
+ va_start (args, format);
+ ic = camel_imap4_command_newv (engine, (CamelIMAP4Folder *) folder, format, args);
+ va_end (args);
+
+ ic->id = engine->nextid++;
+ e_dlist_addtail (&engine->queue, (EDListNode *) ic);
+ camel_imap4_command_ref (ic);
+
+ return ic;
+}
+
+
+/**
+ * camel_imap4_engine_prequeue:
+ * @engine: IMAP4 engine
+ * @folder: IMAP4 folder that the command will affect (or %NULL if it doesn't matter)
+ * @format: command format
+ * @Varargs: arguments
+ *
+ * Same as camel_imap4_engine_queue() except this places the new
+ * command at the head of the queue.
+ *
+ * Returns the CamelIMAP4Command.
+ **/
+CamelIMAP4Command *
+camel_imap4_engine_prequeue (CamelIMAP4Engine *engine, CamelFolder *folder, const char *format, ...)
+{
+ CamelIMAP4Command *ic;
+ va_list args;
+
+ g_return_val_if_fail (CAMEL_IS_IMAP4_ENGINE (engine), NULL);
+
+ va_start (args, format);
+ ic = camel_imap4_command_newv (engine, (CamelIMAP4Folder *) folder, format, args);
+ va_end (args);
+
+ if (e_dlist_empty (&engine->queue)) {
+ e_dlist_addtail (&engine->queue, (EDListNode *) ic);
+ ic->id = engine->nextid++;
+ } else {
+ CamelIMAP4Command *nic;
+ EDListNode *node;
+
+ node = (EDListNode *) ic;
+ e_dlist_addhead (&engine->queue, node);
+ nic = (CamelIMAP4Command *) node->next;
+ ic->id = nic->id - 1;
+
+ if (ic->id == 0) {
+ /* increment all command ids */
+ node = engine->queue.head;
+ while (node->next) {
+ nic = (CamelIMAP4Command *) node;
+ node = node->next;
+ nic->id++;
+ }
+ }
+ }
+
+ camel_imap4_command_ref (ic);
+
+ return ic;
+}
+
+
+void
+camel_imap4_engine_dequeue (CamelIMAP4Engine *engine, CamelIMAP4Command *ic)
+{
+ EDListNode *node = (EDListNode *) ic;
+
+ if (node->next == NULL && node->prev == NULL)
+ return;
+
+ e_dlist_remove (node);
+ node->next = NULL;
+ node->prev = NULL;
+
+ camel_imap4_command_unref (ic);
+}
+
+
+int
+camel_imap4_engine_next_token (CamelIMAP4Engine *engine, camel_imap4_token_t *token, CamelException *ex)
+{
+ if (camel_imap4_stream_next_token (engine->istream, token) == -1) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("IMAP4 server %s unexpectedly disconnected: %s"),
+ engine->url->host, errno ? g_strerror (errno) : _("Unknown"));
+
+ engine->state = CAMEL_IMAP4_ENGINE_DISCONNECTED;
+
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int
+camel_imap4_engine_eat_line (CamelIMAP4Engine *engine, CamelException *ex)
+{
+ camel_imap4_token_t token;
+ unsigned char *literal;
+ int retval;
+ size_t n;
+
+ do {
+ if (camel_imap4_engine_next_token (engine, &token, ex) == -1)
+ return -1;
+
+ if (token.token == CAMEL_IMAP4_TOKEN_LITERAL) {
+ while ((retval = camel_imap4_stream_literal (engine->istream, &literal, &n)) == 1)
+ ;
+
+ if (retval == -1) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("IMAP4 server %s unexpectedly disconnected: %s"),
+ engine->url->host, errno ? g_strerror (errno) : _("Unknown"));
+
+ engine->state = CAMEL_IMAP4_ENGINE_DISCONNECTED;
+
+ return -1;
+ }
+ }
+ } while (token.token != '\n');
+
+ return 0;
+}
+
+
+int
+camel_imap4_engine_line (CamelIMAP4Engine *engine, unsigned char **line, size_t *len, CamelException *ex)
+{
+ GByteArray *linebuf = NULL;
+ unsigned char *buf;
+ size_t buflen;
+ int retval;
+
+ if (line != NULL)
+ linebuf = g_byte_array_new ();
+
+ while ((retval = camel_imap4_stream_line (engine->istream, &buf, &buflen)) > 0) {
+ if (linebuf != NULL)
+ g_byte_array_append (linebuf, buf, buflen);
+ }
+
+ if (retval == -1) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("IMAP4 server %s unexpectedly disconnected: %s"),
+ engine->url->host, errno ? g_strerror (errno) : _("Unknown"));
+
+ if (linebuf != NULL)
+ g_byte_array_free (linebuf, TRUE);
+
+ engine->state = CAMEL_IMAP4_ENGINE_DISCONNECTED;
+
+ return -1;
+ }
+
+ if (linebuf != NULL) {
+ g_byte_array_append (linebuf, buf, buflen);
+
+ *line = linebuf->data;
+ *len = linebuf->len;
+
+ g_byte_array_free (linebuf, FALSE);
+ }
+
+ return 0;
+}
+
+
+int
+camel_imap4_engine_literal (CamelIMAP4Engine *engine, unsigned char **literal, size_t *len, CamelException *ex)
+{
+ GByteArray *literalbuf = NULL;
+ unsigned char *buf;
+ size_t buflen;
+ int retval;
+
+ if (literal != NULL)
+ literalbuf = g_byte_array_new ();
+
+ while ((retval = camel_imap4_stream_literal (engine->istream, &buf, &buflen)) > 0) {
+ if (literalbuf != NULL)
+ g_byte_array_append (literalbuf, buf, buflen);
+ }
+
+ if (retval == -1) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("IMAP4 server %s unexpectedly disconnected: %s"),
+ engine->url->host, errno ? g_strerror (errno) : _("Unknown"));
+
+ if (literalbuf != NULL)
+ g_byte_array_free (literalbuf, TRUE);
+
+ engine->state = CAMEL_IMAP4_ENGINE_DISCONNECTED;
+
+ return -1;
+ }
+
+ if (literalbuf != NULL) {
+ g_byte_array_append (literalbuf, buf, buflen);
+ g_byte_array_append (literalbuf, "", 1);
+
+ *literal = literalbuf->data;
+ *len = literalbuf->len - 1;
+
+ g_byte_array_free (literalbuf, FALSE);
+ }
+
+ return 0;
+}
+
+
+void
+camel_imap4_resp_code_free (CamelIMAP4RespCode *rcode)
+{
+ switch (rcode->code) {
+ case CAMEL_IMAP4_RESP_CODE_PARSE:
+ g_free (rcode->v.parse);
+ break;
+ case CAMEL_IMAP4_RESP_CODE_NEWNAME:
+ g_free (rcode->v.newname[0]);
+ g_free (rcode->v.newname[1]);
+ break;
+ case CAMEL_IMAP4_RESP_CODE_COPYUID:
+ g_free (rcode->v.copyuid.srcset);
+ g_free (rcode->v.copyuid.destset);
+ break;
+ default:
+ break;
+ }
+
+ g_free (rcode);
+}
diff --git a/camel/providers/imap4/camel-imap4-store.c b/camel/providers/imap4/camel-imap4-store.c
new file mode 100644
index 0000000000..0d33f43c5d
--- /dev/null
+++ b/camel/providers/imap4/camel-imap4-store.c
@@ -0,0 +1,1391 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* Camel
+ * Copyright (C) 1999-2004 Jeffrey Stedfast
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include <camel/camel-sasl.h>
+#include <camel/camel-utf8.h>
+#include <camel/camel-tcp-stream-raw.h>
+#include <camel/camel-tcp-stream-ssl.h>
+
+#include <camel/camel-private.h>
+
+#include "camel-imap4-store.h"
+#include "camel-imap4-engine.h"
+#include "camel-imap4-folder.h"
+#include "camel-imap4-stream.h"
+#include "camel-imap4-command.h"
+#include "camel-imap4-utils.h"
+#include "camel-imap4-summary.h"
+
+
+static void camel_imap4_store_class_init (CamelIMAP4StoreClass *klass);
+static void camel_imap4_store_init (CamelIMAP4Store *store, CamelIMAP4StoreClass *klass);
+static void camel_imap4_store_finalize (CamelObject *object);
+
+/* service methods */
+static void imap4_construct (CamelService *service, CamelSession *session,
+ CamelProvider *provider, CamelURL *url,
+ CamelException *ex);
+static char *imap4_get_name (CamelService *service, gboolean brief);
+static gboolean imap4_connect (CamelService *service, CamelException *ex);
+static gboolean imap4_reconnect (CamelIMAP4Engine *engine, CamelException *ex);
+static gboolean imap4_disconnect (CamelService *service, gboolean clean, CamelException *ex);
+static GList *imap4_query_auth_types (CamelService *service, CamelException *ex);
+
+/* store methods */
+static CamelFolder *imap4_get_folder (CamelStore *store, const char *folder_name, guint32 flags, CamelException *ex);
+static CamelFolderInfo *imap4_create_folder (CamelStore *store, const char *parent_name, const char *folder_name, CamelException *ex);
+static void imap4_delete_folder (CamelStore *store, const char *folder_name, CamelException *ex);
+static void imap4_rename_folder (CamelStore *store, const char *old_name, const char *new_name, CamelException *ex);
+static CamelFolderInfo *imap4_get_folder_info (CamelStore *store, const char *top, guint32 flags, CamelException *ex);
+static void imap4_subscribe_folder (CamelStore *store, const char *folder_name, CamelException *ex);
+static void imap4_unsubscribe_folder (CamelStore *store, const char *folder_name, CamelException *ex);
+static void imap4_noop (CamelStore *store, CamelException *ex);
+
+
+static CamelStoreClass *parent_class = NULL;
+
+
+CamelType
+camel_imap4_store_get_type (void)
+{
+ static CamelType type = 0;
+
+ if (!type) {
+ type = camel_type_register (CAMEL_STORE_TYPE,
+ "CamelIMAP4Store",
+ sizeof (CamelIMAP4Store),
+ sizeof (CamelIMAP4StoreClass),
+ (CamelObjectClassInitFunc) camel_imap4_store_class_init,
+ NULL,
+ (CamelObjectInitFunc) camel_imap4_store_init,
+ (CamelObjectFinalizeFunc) camel_imap4_store_finalize);
+ }
+
+ return type;
+}
+
+static guint
+imap4_hash_folder_name (gconstpointer key)
+{
+ if (g_ascii_strcasecmp (key, "INBOX") == 0)
+ return g_str_hash ("INBOX");
+ else
+ return g_str_hash (key);
+}
+
+static int
+imap4_compare_folder_name (gconstpointer a, gconstpointer b)
+{
+ gconstpointer aname = a, bname = b;
+
+ if (g_ascii_strcasecmp (a, "INBOX") == 0)
+ aname = "INBOX";
+ if (g_ascii_strcasecmp (b, "INBOX") == 0)
+ bname = "INBOX";
+
+ return g_str_equal (aname, bname);
+}
+
+static void
+camel_imap4_store_class_init (CamelIMAP4StoreClass *klass)
+{
+ CamelServiceClass *service_class = (CamelServiceClass *) klass;
+ CamelStoreClass *store_class = (CamelStoreClass *) klass;
+
+ parent_class = (CamelStoreClass *) camel_type_get_global_classfuncs (CAMEL_STORE_TYPE);
+
+ service_class->construct = imap4_construct;
+ service_class->get_name = imap4_get_name;
+ service_class->connect = imap4_connect;
+ service_class->disconnect = imap4_disconnect;
+ service_class->query_auth_types = imap4_query_auth_types;
+
+ store_class->hash_folder_name = imap4_hash_folder_name;
+ store_class->compare_folder_name = imap4_compare_folder_name;
+
+ store_class->get_folder = imap4_get_folder;
+ store_class->create_folder = imap4_create_folder;
+ store_class->delete_folder = imap4_delete_folder;
+ store_class->rename_folder = imap4_rename_folder;
+ store_class->get_folder_info = imap4_get_folder_info;
+ store_class->subscribe_folder = imap4_subscribe_folder;
+ store_class->unsubscribe_folder = imap4_unsubscribe_folder;
+ store_class->noop = imap4_noop;
+}
+
+static void
+camel_imap4_store_init (CamelIMAP4Store *store, CamelIMAP4StoreClass *klass)
+{
+ store->engine = NULL;
+}
+
+static void
+camel_imap4_store_finalize (CamelObject *object)
+{
+ CamelIMAP4Store *store = (CamelIMAP4Store *) object;
+
+ if (store->engine)
+ camel_object_unref (store->engine);
+
+ g_free (store->storage_path);
+}
+
+
+static void
+imap4_construct (CamelService *service, CamelSession *session, CamelProvider *provider, CamelURL *url, CamelException *ex)
+{
+ CamelIMAP4Store *store = (CamelIMAP4Store *) service;
+
+ CAMEL_SERVICE_CLASS (parent_class)->construct (service, session, provider, url, ex);
+ if (camel_exception_is_set (ex))
+ return;
+
+ store->storage_path = camel_session_get_storage_path (session, service, ex);
+ store->engine = camel_imap4_engine_new (service, imap4_reconnect);
+}
+
+static char *
+imap4_get_name (CamelService *service, gboolean brief)
+{
+ if (brief)
+ return g_strdup_printf (_("IMAP server %s"), service->url->host);
+ else
+ return g_strdup_printf (_("IMAP service for %s on %s"),
+ service->url->user, service->url->host);
+}
+
+enum {
+ MODE_CLEAR,
+ MODE_SSL,
+ MODE_TLS,
+};
+
+#define SSL_PORT_FLAGS (CAMEL_TCP_STREAM_SSL_ENABLE_SSL2 | CAMEL_TCP_STREAM_SSL_ENABLE_SSL3)
+#define STARTTLS_FLAGS (CAMEL_TCP_STREAM_SSL_ENABLE_TLS)
+
+static gboolean
+connect_to_server (CamelIMAP4Engine *engine, struct addrinfo *ai, int ssl_mode, CamelException *ex)
+{
+ CamelService *service = engine->service;
+ CamelStream *tcp_stream;
+ CamelIMAP4Command *ic;
+ int id, ret;
+
+ if (ssl_mode != MODE_CLEAR) {
+#ifdef HAVE_SSL
+ if (ssl_mode == MODE_TLS) {
+ tcp_stream = camel_tcp_stream_ssl_new (service->session, service->url->host, STARTTLS_FLAGS);
+ } else {
+ tcp_stream = camel_tcp_stream_ssl_new (service->session, service->url->host, SSL_PORT_FLAGS);
+ }
+#else
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ _("Could not connect to %s: %s"),
+ service->url->host, _("SSL unavailable"));
+
+ return FALSE;
+#endif /* HAVE_SSL */
+ } else {
+ tcp_stream = camel_tcp_stream_raw_new ();
+ }
+
+ if ((ret = camel_tcp_stream_connect ((CamelTcpStream *) tcp_stream, ai)) == -1) {
+ if (errno == EINTR)
+ camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL,
+ _("Connection cancelled"));
+ else
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ _("Could not connect to %s: %s"),
+ service->url->host,
+ g_strerror (errno));
+
+ camel_object_unref (tcp_stream);
+
+ return FALSE;
+ }
+
+ if (camel_imap4_engine_take_stream (engine, tcp_stream, ex) == -1)
+ return FALSE;
+
+ if (camel_imap4_engine_capability (engine, ex) == -1)
+ return FALSE;
+
+ if (ssl_mode != MODE_TLS) {
+ /* we're done */
+ return TRUE;
+ }
+
+ if (!(engine->capa & CAMEL_IMAP4_CAPABILITY_STARTTLS)) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Failed to connect to IMAP server %s in secure mode: %s"),
+ service->url->host, _("SSL negotiations failed"));
+
+ return FALSE;
+ }
+
+ ic = camel_imap4_engine_prequeue (engine, NULL, "STARTTLS\r\n");
+ while ((id = camel_imap4_engine_iterate (engine)) < ic->id && id != -1)
+ ;
+
+ if (id == -1 || ic->result != CAMEL_IMAP4_RESULT_OK) {
+ if (ic->result != CAMEL_IMAP4_RESULT_OK) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Failed to connect to IMAP server %s in secure mode: %s"),
+ service->url->host, _("Unknown error"));
+ } else {
+ camel_exception_xfer (ex, &ic->ex);
+ }
+
+ camel_imap4_command_unref (ic);
+
+ return FALSE;
+ }
+
+ camel_imap4_command_unref (ic);
+
+ return TRUE;
+}
+
+static struct {
+ char *value;
+ char *serv;
+ char *port;
+ int mode;
+} ssl_options[] = {
+ { "", "imaps", "993", MODE_SSL }, /* really old (1.x) */
+ { "always", "imaps", "993", MODE_SSL },
+ { "when-possible", "imap", "143", MODE_TLS },
+ { "never", "imap", "143", MODE_CLEAR },
+ { NULL, "imap", "143", MODE_CLEAR },
+};
+
+static gboolean
+connect_to_server_wrapper (CamelIMAP4Engine *engine, CamelException *ex)
+{
+ CamelService *service = engine->service;
+ struct addrinfo *ai, hints;
+ const char *ssl_mode;
+ int mode, ret, i;
+ char *serv;
+ const char *port;
+
+ if ((ssl_mode = camel_url_get_param (service->url, "use_ssl"))) {
+ for (i = 0; ssl_options[i].value; i++)
+ if (!strcmp (ssl_options[i].value, ssl_mode))
+ break;
+ mode = ssl_options[i].mode;
+ serv = ssl_options[i].serv;
+ port = ssl_options[i].port;
+ } else {
+ mode = MODE_CLEAR;
+ serv = "imap";
+ port = "143";
+ }
+
+ if (service->url->port) {
+ serv = g_alloca (16);
+ sprintf (serv, "%d", service->url->port);
+ port = NULL;
+ }
+
+ memset (&hints, 0, sizeof (hints));
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_family = PF_UNSPEC;
+ ai = camel_getaddrinfo (service->url->host, serv, &hints, ex);
+ if (ai == NULL && port != NULL && camel_exception_get_id(ex) != CAMEL_EXCEPTION_USER_CANCEL) {
+ camel_exception_clear (ex);
+ ai = camel_getaddrinfo (service->url->host, port, &hints, ex);
+ }
+ if (ai == NULL)
+ return FALSE;
+
+ ret = connect_to_server (engine, ai, mode, ex);
+
+ camel_freeaddrinfo (ai);
+
+ return ret;
+}
+
+static int
+sasl_auth (CamelIMAP4Engine *engine, CamelIMAP4Command *ic, const unsigned char *linebuf, size_t linelen, CamelException *ex)
+{
+ /* Perform a single challenge iteration */
+ CamelSasl *sasl = ic->user_data;
+ char *challenge;
+
+ if (camel_sasl_authenticated (sasl)) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
+ _("Cannot authenticate to IMAP server %s using the %s authentication mechanism"),
+ engine->url->host, engine->url->authmech);
+ return -1;
+ }
+
+ while (isspace (*linebuf))
+ linebuf++;
+
+ if (*linebuf == '\0')
+ linebuf = NULL;
+
+ if (!(challenge = camel_sasl_challenge_base64 (sasl, (const char *) linebuf, ex)))
+ return -1;
+
+ fprintf (stderr, "sending : %s\r\n", challenge);
+
+ if (camel_stream_printf (engine->ostream, "%s\r\n", challenge) == -1) {
+ g_free (challenge);
+ return -1;
+ }
+
+ g_free (challenge);
+
+ if (camel_stream_flush (engine->ostream) == -1)
+ return -1;
+
+ return 0;
+}
+
+static int
+imap4_try_authenticate (CamelIMAP4Engine *engine, gboolean reprompt, const char *errmsg, CamelException *ex)
+{
+ CamelService *service = engine->service;
+ CamelSession *session = service->session;
+ CamelSasl *sasl = NULL;
+ CamelIMAP4Command *ic;
+ int id;
+
+ if (!service->url->passwd) {
+ guint32 flags = CAMEL_SESSION_PASSWORD_SECRET;
+ char *prompt;
+
+ if (reprompt)
+ flags |= CAMEL_SESSION_PASSWORD_REPROMPT;
+
+ prompt = g_strdup_printf (_("%sPlease enter the IMAP password for %s on host %s"),
+ errmsg ? errmsg : "",
+ service->url->user,
+ service->url->host);
+
+ service->url->passwd = camel_session_get_password (session, service, NULL, prompt, "password", flags, ex);
+
+ g_free (prompt);
+
+ if (!service->url->passwd)
+ return FALSE;
+ }
+
+ if (service->url->authmech) {
+ CamelServiceAuthType *mech;
+
+ mech = g_hash_table_lookup (engine->authtypes, service->url->authmech);
+ sasl = camel_sasl_new ("imap4", mech->authproto, service);
+
+ ic = camel_imap4_engine_prequeue (engine, NULL, "AUTHENTICATE %s\r\n", service->url->authmech);
+ ic->plus = sasl_auth;
+ ic->user_data = sasl;
+ } else {
+ ic = camel_imap4_engine_prequeue (engine, NULL, "LOGIN %S %S\r\n",
+ service->url->user, service->url->passwd);
+ }
+
+ while ((id = camel_imap4_engine_iterate (engine)) < ic->id && id != -1)
+ ;
+
+ if (sasl != NULL)
+ camel_object_unref (sasl);
+
+ if (id == -1 || ic->status == CAMEL_IMAP4_COMMAND_ERROR) {
+ /* unrecoverable error */
+ camel_exception_xfer (ex, &ic->ex);
+ camel_imap4_command_unref (ic);
+
+ return FALSE;
+ }
+
+ if (ic->result != CAMEL_IMAP4_RESULT_OK) {
+ camel_imap4_command_unref (ic);
+
+ /* try again */
+
+ return TRUE;
+ }
+
+ camel_imap4_command_unref (ic);
+
+ return FALSE;
+}
+
+static gboolean
+imap4_reconnect (CamelIMAP4Engine *engine, CamelException *ex)
+{
+ CamelService *service = engine->service;
+ CamelServiceAuthType *mech;
+ gboolean reprompt = FALSE;
+ char *errmsg = NULL;
+ CamelException lex;
+
+ if (!connect_to_server_wrapper (engine, ex))
+ return FALSE;
+
+#define CANT_USE_AUTHMECH (!(mech = g_hash_table_lookup (engine->authtypes, service->url->authmech)))
+ if (service->url->authmech && CANT_USE_AUTHMECH) {
+ /* Oops. We can't AUTH using the requested mechanism */
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
+ _("Cannot authenticate to IMAP server %s using %s"),
+ service->url->host, service->url->authmech);
+
+ return FALSE;
+ }
+
+ camel_exception_init (&lex);
+ while (imap4_try_authenticate (engine, reprompt, errmsg, &lex)) {
+ g_free (errmsg);
+ errmsg = g_strdup (lex.desc);
+ camel_exception_clear (&lex);
+ reprompt = TRUE;
+ }
+ g_free (errmsg);
+
+ if (camel_exception_is_set (&lex)) {
+ camel_exception_xfer (ex, &lex);
+ return FALSE;
+ }
+
+ if (camel_imap4_engine_namespace (engine, ex) == -1)
+ return FALSE;
+
+ return TRUE;
+}
+
+static gboolean
+imap4_connect (CamelService *service, CamelException *ex)
+{
+ gboolean retval;
+
+ CAMEL_SERVICE_LOCK (service, connect_lock);
+ retval = imap4_reconnect (((CamelIMAP4Store *) service)->engine, ex);
+ CAMEL_SERVICE_UNLOCK (service, connect_lock);
+
+ return retval;
+}
+
+static gboolean
+imap4_disconnect (CamelService *service, gboolean clean, CamelException *ex)
+{
+ CamelIMAP4Store *store = (CamelIMAP4Store *) service;
+ CamelIMAP4Command *ic;
+ int id;
+
+ if (clean && !store->engine->istream->disconnected) {
+ ic = camel_imap4_engine_queue (store->engine, NULL, "LOGOUT\r\n");
+ while ((id = camel_imap4_engine_iterate (store->engine)) < ic->id && id != -1)
+ ;
+
+ camel_imap4_command_unref (ic);
+ }
+
+ return 0;
+}
+
+extern CamelServiceAuthType camel_imap4_password_authtype;
+
+static GList *
+imap4_query_auth_types (CamelService *service, CamelException *ex)
+{
+ CamelIMAP4Store *store = (CamelIMAP4Store *) service;
+ CamelServiceAuthType *authtype;
+ GList *sasl_types, *t, *next;
+ gboolean connected;
+
+ CAMEL_SERVICE_LOCK (store, connect_lock);
+ connected = connect_to_server_wrapper (store->engine, ex);
+ CAMEL_SERVICE_UNLOCK (store, connect_lock);
+ if (!connected)
+ return NULL;
+
+ sasl_types = camel_sasl_authtype_list (FALSE);
+ for (t = sasl_types; t; t = next) {
+ authtype = t->data;
+ next = t->next;
+
+ if (!g_hash_table_lookup (store->engine->authtypes, authtype->authproto)) {
+ sasl_types = g_list_remove_link (sasl_types, t);
+ g_list_free_1 (t);
+ }
+ }
+
+ return g_list_prepend (sasl_types, &camel_imap4_password_authtype);
+}
+
+
+static char
+imap4_get_path_delim (CamelIMAP4Engine *engine, const char *full_name)
+{
+ /* FIXME: move this to utils so imap4-folder.c can share */
+ CamelIMAP4Namespace *namespace;
+ const char *slash;
+ size_t len;
+ char *top;
+
+ if ((slash = strchr (full_name, '/')))
+ len = (slash - full_name);
+ else
+ len = strlen (full_name);
+
+ top = g_alloca (len + 1);
+ memcpy (top, full_name, len);
+ top[len] = '\0';
+
+ if (!g_ascii_strcasecmp (top, "INBOX"))
+ top = "INBOX";
+
+ retry:
+ namespace = engine->namespaces.personal;
+ while (namespace != NULL) {
+ if (!strcmp (namespace->path, top))
+ return namespace->sep;
+ namespace = namespace->next;
+ }
+
+ namespace = engine->namespaces.other;
+ while (namespace != NULL) {
+ if (!strcmp (namespace->path, top))
+ return namespace->sep;
+ namespace = namespace->next;
+ }
+
+ namespace = engine->namespaces.shared;
+ while (namespace != NULL) {
+ if (!strcmp (namespace->path, top))
+ return namespace->sep;
+ namespace = namespace->next;
+ }
+
+ if (top[0] != '\0') {
+ /* look for a default namespace? */
+ top[0] = '\0';
+ goto retry;
+ }
+
+ return '/';
+}
+
+static char *
+imap4_folder_utf7_name (CamelStore *store, const char *folder_name, char wildcard)
+{
+ char *real_name, *p;
+ char sep;
+ int len;
+
+ sep = imap4_get_path_delim (((CamelIMAP4Store *) store)->engine, folder_name);
+
+ if (sep != '/') {
+ p = real_name = g_alloca (strlen (folder_name) + 1);
+ strcpy (real_name, folder_name);
+ while (*p != '\0') {
+ if (*p == '/')
+ *p = sep;
+ p++;
+ }
+
+ folder_name = real_name;
+ }
+
+ if (*folder_name)
+ real_name = camel_utf8_utf7 (folder_name);
+ else
+ real_name = g_strdup ("");
+
+ if (wildcard) {
+ len = strlen (real_name);
+ real_name = g_realloc (real_name, len + 3);
+
+ if (len > 0)
+ real_name[len++] = sep;
+
+ real_name[len++] = wildcard;
+ real_name[len] = '\0';
+ }
+
+ return real_name;
+}
+
+static CamelFolder *
+imap4_get_folder (CamelStore *store, const char *folder_name, guint32 flags, CamelException *ex)
+{
+ CamelIMAP4Engine *engine = ((CamelIMAP4Store *) store)->engine;
+ CamelFolder *folder = NULL;
+ camel_imap4_list_t *list;
+ CamelIMAP4Command *ic;
+ CamelFolderInfo *fi;
+ GPtrArray *array;
+ char *utf7_name;
+ int create;
+ int id, i;
+
+ CAMEL_SERVICE_LOCK (store, connect_lock);
+
+ /* make sure the folder exists - try LISTing it? */
+ utf7_name = imap4_folder_utf7_name (store, folder_name, '\0');
+ ic = camel_imap4_engine_queue (engine, NULL, "LIST \"\" %S\r\n", utf7_name);
+ camel_imap4_command_register_untagged (ic, "LIST", camel_imap4_untagged_list);
+ ic->user_data = array = g_ptr_array_new ();
+ g_free (utf7_name);
+
+ while ((id = camel_imap4_engine_iterate (engine)) < ic->id && id != -1)
+ ;
+
+ if (id == -1 || ic->status != CAMEL_IMAP4_COMMAND_COMPLETE) {
+ camel_exception_xfer (ex, &ic->ex);
+ camel_imap4_command_unref (ic);
+ g_ptr_array_free (array, TRUE);
+ goto done;
+ }
+
+ create = array->len == 0;
+
+ for (i = 0; i < array->len; i++) {
+ list = array->pdata[i];
+ g_free (list->name);
+ g_free (list);
+ }
+
+ g_ptr_array_free (array, TRUE);
+
+ if (ic->result != CAMEL_IMAP4_RESULT_OK) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot get folder `%s' on IMAP server %s: Unknown"),
+ folder_name, ((CamelService *) store)->url->host);
+ camel_imap4_command_unref (ic);
+ goto done;
+ }
+
+ camel_imap4_command_unref (ic);
+
+ if (create) {
+ const char *basename;
+ char *parent;
+ int len;
+
+ if (!(flags & CAMEL_STORE_FOLDER_CREATE))
+ goto done;
+
+ if (!(basename = strrchr (folder_name, '/')))
+ basename = folder_name;
+ else
+ basename++;
+
+ len = basename > folder_name ? (basename - folder_name) - 1 : 0;
+ parent = g_alloca (len + 1);
+ memcpy (parent, folder_name, len);
+ parent[len] = '\0';
+
+ if (!(fi = imap4_create_folder (store, parent, basename, ex)))
+ goto done;
+
+ camel_store_free_folder_info (store, fi);
+ }
+
+ folder = camel_imap4_folder_new (store, folder_name, ex);
+
+ done:
+
+ CAMEL_SERVICE_UNLOCK (store, connect_lock);
+
+ return folder;
+}
+
+static CamelFolderInfo *
+imap4_create_folder (CamelStore *store, const char *parent_name, const char *folder_name, CamelException *ex)
+{
+ /* FIXME: also need to deal with parent folders that can't
+ * contain subfolders - delete them and re-create with the
+ * proper hint */
+ CamelIMAP4Engine *engine = ((CamelIMAP4Store *) store)->engine;
+ CamelFolderInfo *fi = NULL;
+ CamelIMAP4Command *ic;
+ char *utf7_name;
+ CamelURL *url;
+ const char *c;
+ char *name;
+ char sep;
+ int id;
+
+ sep = imap4_get_path_delim (engine, parent_name);
+
+ c = folder_name;
+ while (*c != '\0') {
+ if (*c == sep || strchr ("/#%*", *c)) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_INVALID_PATH,
+ _("The folder name \"%s\" is invalid because "
+ "it contains the character \"%c\""),
+ folder_name, *c);
+ return NULL;
+ }
+
+ c++;
+ }
+
+ if (parent_name != NULL && *parent_name)
+ name = g_strdup_printf ("%s/%s", parent_name, folder_name);
+ else
+ name = g_strdup (folder_name);
+
+ CAMEL_SERVICE_LOCK (store, connect_lock);
+
+ utf7_name = imap4_folder_utf7_name (store, name, '\0');
+ ic = camel_imap4_engine_queue (engine, NULL, "CREATE %S\r\n", utf7_name);
+ g_free (utf7_name);
+
+ while ((id = camel_imap4_engine_iterate (engine)) < ic->id && id != -1)
+ ;
+
+ if (id == -1 || ic->status != CAMEL_IMAP4_COMMAND_COMPLETE) {
+ camel_exception_xfer (ex, &ic->ex);
+ camel_imap4_command_unref (ic);
+ g_free (name);
+ goto done;
+ }
+
+ switch (ic->result) {
+ case CAMEL_IMAP4_RESULT_OK:
+ url = camel_url_copy (engine->url);
+ camel_url_set_fragment (url, name);
+
+ c = strrchr (name, '/');
+
+ fi = g_malloc0 (sizeof (CamelFolderInfo));
+ fi->full_name = name;
+ fi->name = g_strdup (c ? c + 1: name);
+ fi->uri = camel_url_to_string (url, CAMEL_URL_HIDE_ALL);
+ camel_url_free (url);
+ fi->flags = 0;
+ fi->unread = -1;
+ fi->total = -1;
+
+ camel_object_trigger_event (store, "folder_created", fi);
+ break;
+ case CAMEL_IMAP4_RESULT_NO:
+ /* FIXME: would be good to save the NO reason into the err message */
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot create folder `%s': Invalid mailbox name"),
+ name);
+ g_free (name);
+ break;
+ case CAMEL_IMAP4_RESULT_BAD:
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot create folder `%s': Bad command"),
+ name);
+ g_free (name);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ camel_imap4_command_unref (ic);
+
+ done:
+
+ CAMEL_SERVICE_UNLOCK (store, connect_lock);
+
+ return fi;
+}
+
+static void
+imap4_delete_folder (CamelStore *store, const char *folder_name, CamelException *ex)
+{
+ CamelIMAP4Engine *engine = ((CamelIMAP4Store *) store)->engine;
+ CamelFolder *selected = (CamelFolder *) engine->folder;
+ CamelIMAP4Command *ic, *ic0 = NULL;
+ CamelFolderInfo *fi;
+ char *utf7_name;
+ CamelURL *url;
+ const char *p;
+ int id;
+
+ if (!g_ascii_strcasecmp (folder_name, "INBOX")) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot delete folder `%s': Special folder"),
+ folder_name);
+
+ return;
+ }
+
+ CAMEL_SERVICE_LOCK (store, connect_lock);
+
+ if (selected && !strcmp (folder_name, selected->full_name))
+ ic0 = camel_imap4_engine_queue (engine, NULL, "CLOSE\r\n");
+
+ utf7_name = imap4_folder_utf7_name (store, folder_name, '\0');
+ ic = camel_imap4_engine_queue (engine, NULL, "DELETE %S\r\n", utf7_name);
+ g_free (utf7_name);
+
+ while ((id = camel_imap4_engine_iterate (engine)) < ic->id && id != -1)
+ ;
+
+ if (id == -1 || ic->status != CAMEL_IMAP4_COMMAND_COMPLETE) {
+ if (ic0 && ic0->status != CAMEL_IMAP4_COMMAND_COMPLETE)
+ camel_exception_xfer (ex, &ic0->ex);
+ else
+ camel_exception_xfer (ex, &ic->ex);
+
+ if (ic0 != NULL)
+ camel_imap4_command_unref (ic0);
+
+ camel_imap4_command_unref (ic);
+ CAMEL_SERVICE_UNLOCK (store, connect_lock);
+ return;
+ }
+
+ if (ic0 != NULL)
+ camel_imap4_command_unref (ic0);
+
+ switch (ic->result) {
+ case CAMEL_IMAP4_RESULT_OK:
+ /* deleted */
+ url = camel_url_copy (engine->url);
+ camel_url_set_fragment (url, folder_name);
+
+ p = strrchr (folder_name, '/');
+
+ fi = g_malloc0 (sizeof (CamelFolderInfo));
+ fi->full_name = g_strdup (folder_name);
+ fi->name = g_strdup (p ? p + 1: folder_name);
+ fi->uri = camel_url_to_string (url, CAMEL_URL_HIDE_ALL);
+ camel_url_free (url);
+ fi->flags = 0;
+ fi->unread = -1;
+ fi->total = -1;
+
+ camel_object_trigger_event (store, "folder_deleted", fi);
+
+ camel_folder_info_free (fi);
+ break;
+ case CAMEL_IMAP4_RESULT_NO:
+ /* FIXME: would be good to save the NO reason into the err message */
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot delete folder `%s': Invalid mailbox name"),
+ folder_name);
+ break;
+ case CAMEL_IMAP4_RESULT_BAD:
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot delete folder `%s': Bad command"),
+ folder_name);
+ break;
+ }
+
+ camel_imap4_command_unref (ic);
+
+ CAMEL_SERVICE_UNLOCK (store, connect_lock);
+}
+
+static void
+imap4_rename_folder (CamelStore *store, const char *old_name, const char *new_name, CamelException *ex)
+{
+ CamelIMAP4Engine *engine = ((CamelIMAP4Store *) store)->engine;
+ char *old_uname, *new_uname;
+ CamelIMAP4Command *ic;
+ int id;
+
+ if (!g_ascii_strcasecmp (old_name, "INBOX")) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot rename folder `%s' to `%s': Special folder"),
+ old_name, new_name);
+
+ return;
+ }
+
+ CAMEL_SERVICE_LOCK (store, connect_lock);
+
+ old_uname = imap4_folder_utf7_name (store, old_name, '\0');
+ new_uname = imap4_folder_utf7_name (store, new_name, '\0');
+
+ ic = camel_imap4_engine_queue (engine, NULL, "RENAME %S %S\r\n", old_uname, new_uname);
+ g_free (old_uname);
+ g_free (new_uname);
+
+ while ((id = camel_imap4_engine_iterate (engine)) < ic->id && id != -1)
+ ;
+
+ if (id == -1 || ic->status != CAMEL_IMAP4_COMMAND_COMPLETE) {
+ camel_exception_xfer (ex, &ic->ex);
+ camel_imap4_command_unref (ic);
+ CAMEL_SERVICE_UNLOCK (store, connect_lock);
+ return;
+ }
+
+ switch (ic->result) {
+ case CAMEL_IMAP4_RESULT_OK:
+ /* FIXME: need to update state on the renamed folder object */
+ break;
+ case CAMEL_IMAP4_RESULT_NO:
+ /* FIXME: would be good to save the NO reason into the err message */
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot rename folder `%s' to `%s': Invalid mailbox name"),
+ old_name, new_name);
+ break;
+ case CAMEL_IMAP4_RESULT_BAD:
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot rename folder `%s' to `%s': Bad command"),
+ old_name, new_name);
+ break;
+ }
+
+ camel_imap4_command_unref (ic);
+
+ CAMEL_SERVICE_UNLOCK (store, connect_lock);
+}
+
+static int
+list_sort (const camel_imap4_list_t **list0, const camel_imap4_list_t **list1)
+{
+ return strcmp ((*list0)->name, (*list1)->name);
+}
+
+static void
+list_remove_duplicates (GPtrArray *array)
+{
+ camel_imap4_list_t *list, *last;
+ int i;
+
+ last = array->pdata[0];
+ for (i = 1; i < array->len; i++) {
+ list = array->pdata[i];
+ if (!strcmp (list->name, last->name)) {
+ g_ptr_array_remove_index (array, i--);
+ last->flags |= list->flags;
+ g_free (list->name);
+ g_free (list);
+ }
+ }
+}
+
+static void
+imap4_status (CamelStore *store, CamelFolderInfo *fi)
+{
+ CamelIMAP4Engine *engine = ((CamelIMAP4Store *) store)->engine;
+ camel_imap4_status_attr_t *attr, *next;
+ camel_imap4_status_t *status;
+ CamelIMAP4Command *ic;
+ GPtrArray *array;
+ char *mailbox;
+ int id, i;
+
+ mailbox = imap4_folder_utf7_name (store, fi->full_name, '\0');
+ ic = camel_imap4_engine_queue (engine, NULL, "STATUS %S (MESSAGES UNSEEN)\r\n", mailbox);
+ g_free (mailbox);
+
+ camel_imap4_command_register_untagged (ic, "STATUS", camel_imap4_untagged_status);
+ ic->user_data = array = g_ptr_array_new ();
+
+ while ((id = camel_imap4_engine_iterate (engine)) < ic->id && id != -1)
+ ;
+
+ if (id == -1 || ic->status != CAMEL_IMAP4_COMMAND_COMPLETE) {
+ camel_imap4_command_unref (ic);
+ g_ptr_array_free (array, TRUE);
+ return;
+ }
+
+ for (i = 0; i < array->len; i++) {
+ status = array->pdata[i];
+ attr = status->attr_list;
+ while (attr != NULL) {
+ next = attr->next;
+ if (attr->type == CAMEL_IMAP4_STATUS_MESSAGES)
+ fi->total = attr->value;
+ else if (attr->type == CAMEL_IMAP4_STATUS_UNSEEN)
+ fi->unread = attr->value;
+ g_free (attr);
+ attr = next;
+ }
+
+ g_free (status->mailbox);
+ g_free (status);
+ }
+
+ camel_imap4_command_unref (ic);
+ g_ptr_array_free (array, TRUE);
+}
+
+static CamelFolderInfo *
+imap4_build_folder_info (CamelStore *store, const char *top, guint32 flags, GPtrArray *array)
+{
+ CamelIMAP4Engine *engine = ((CamelIMAP4Store *) store)->engine;
+ CamelFolder *folder = (CamelFolder *) engine->folder;
+ camel_imap4_list_t *list;
+ CamelFolderInfo *fi;
+ char *name, *p;
+ CamelURL *url;
+ int i;
+
+ if (array->len == 0) {
+ g_ptr_array_free (array, TRUE);
+ return NULL;
+ }
+
+ g_ptr_array_sort (array, (GCompareFunc) list_sort);
+
+ list_remove_duplicates (array);
+
+ url = camel_url_copy (engine->url);
+
+ for (i = 0; i < array->len; i++) {
+ list = array->pdata[i];
+ fi = g_malloc0 (sizeof (CamelFolderInfo));
+
+ p = name = camel_utf7_utf8 (list->name);
+ while (*p != '\0') {
+ if (*p == list->delim)
+ *p = '/';
+ p++;
+ }
+
+ p = strrchr (name, '/');
+ camel_url_set_fragment (url, name);
+
+ fi->full_name = name;
+ fi->name = g_strdup (p ? p + 1: name);
+ fi->uri = camel_url_to_string (url, CAMEL_URL_HIDE_ALL);
+ fi->flags = list->flags;
+ fi->unread = -1;
+ fi->total = -1;
+
+ if (!(flags & CAMEL_STORE_FOLDER_INFO_FAST)) {
+ if (folder && !strcmp (folder->full_name, fi->full_name)) {
+ /* can't STATUS this folder since it is SELECTED, besides - it would be wasteful */
+ CamelMessageInfo *info;
+ int index;
+
+ fi->total = camel_folder_summary_count (folder->summary);
+
+ fi->unread = 0;
+ for (index = 0; index < fi->total; index++) {
+ if (!(info = camel_folder_summary_index (folder->summary, index)))
+ continue;
+
+ if ((info->flags & CAMEL_MESSAGE_SEEN) == 0)
+ fi->unread++;
+
+ camel_folder_summary_info_free (folder->summary, info);
+ }
+ } else {
+ imap4_status (store, fi);
+ }
+ }
+
+ g_free (list->name);
+ g_free (list);
+
+ array->pdata[i] = fi;
+ }
+
+ fi = camel_folder_info_build (array, top, '/', TRUE);
+
+ camel_url_free (url);
+
+ g_ptr_array_free (array, TRUE);
+
+ return fi;
+}
+
+static CamelFolderInfo *
+imap4_get_folder_info (CamelStore *store, const char *top, guint32 flags, CamelException *ex)
+{
+ CamelIMAP4Engine *engine = ((CamelIMAP4Store *) store)->engine;
+ CamelIMAP4Command *ic, *ic0 = NULL;
+ CamelFolderInfo *fi = NULL;
+ camel_imap4_list_t *list;
+ GPtrArray *array;
+ const char *cmd;
+ char *pattern;
+ char wildcard;
+ int id, i;
+
+ CAMEL_SERVICE_LOCK (store, connect_lock);
+
+ if (engine->state == CAMEL_IMAP4_ENGINE_DISCONNECTED) {
+ if (!camel_service_connect ((CamelService *) store, ex))
+ return NULL;
+
+ engine = ((CamelIMAP4Store *) store)->engine;
+ }
+
+ if (flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED)
+ cmd = "LSUB";
+ else
+ cmd = "LIST";
+
+ if (top == NULL)
+ top = "";
+
+ wildcard = (flags & CAMEL_STORE_FOLDER_INFO_RECURSIVE) ? '*' : '%';
+ pattern = imap4_folder_utf7_name (store, top, wildcard);
+ array = g_ptr_array_new ();
+
+ if (*top != '\0') {
+ size_t len;
+ char sep;
+
+ len = strlen (pattern);
+ sep = pattern[len - 2];
+ pattern[len - 2] = '\0';
+
+ ic0 = camel_imap4_engine_queue (engine, NULL, "%s \"\" %S\r\n", cmd, pattern);
+ camel_imap4_command_register_untagged (ic0, cmd, camel_imap4_untagged_list);
+ ic0->user_data = array;
+
+ pattern[len - 2] = sep;
+ }
+
+ ic = camel_imap4_engine_queue (engine, NULL, "%s \"\" %S\r\n", cmd, pattern);
+ camel_imap4_command_register_untagged (ic, cmd, camel_imap4_untagged_list);
+ ic->user_data = array;
+
+ while ((id = camel_imap4_engine_iterate (engine)) < ic->id && id != -1)
+ ;
+
+ if (id == -1 || ic->status != CAMEL_IMAP4_COMMAND_COMPLETE) {
+ if (ic0 && ic0->status != CAMEL_IMAP4_COMMAND_COMPLETE)
+ camel_exception_xfer (ex, &ic0->ex);
+ else
+ camel_exception_xfer (ex, &ic->ex);
+
+ if (ic0 != NULL)
+ camel_imap4_command_unref (ic0);
+ camel_imap4_command_unref (ic);
+
+ for (i = 0; i < array->len; i++) {
+ list = array->pdata[i];
+ g_free (list->name);
+ g_free (list);
+ }
+
+ g_ptr_array_free (array, TRUE);
+ g_free (pattern);
+
+ goto done;
+ }
+
+ if (ic0 != NULL)
+ camel_imap4_command_unref (ic0);
+
+ if (ic->result != CAMEL_IMAP4_RESULT_OK) {
+ camel_imap4_command_unref (ic);
+
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot get %s information for pattern `%s' on IMAP server %s: %s"),
+ cmd, pattern, engine->url->host, ic->result == CAMEL_IMAP4_RESULT_BAD ?
+ _("Bad command") : _("Unknown"));
+
+ for (i = 0; i < array->len; i++) {
+ list = array->pdata[i];
+ g_free (list->name);
+ g_free (list);
+ }
+
+ g_ptr_array_free (array, TRUE);
+
+ g_free (pattern);
+
+ goto done;
+ }
+
+ g_free (pattern);
+
+ fi = imap4_build_folder_info (store, top, flags, array);
+
+ done:
+
+ CAMEL_SERVICE_UNLOCK (store, connect_lock);
+
+ return fi;
+}
+
+static void
+imap4_subscribe_folder (CamelStore *store, const char *folder_name, CamelException *ex)
+{
+ CamelIMAP4Engine *engine = ((CamelIMAP4Store *) store)->engine;
+ CamelIMAP4Command *ic;
+ CamelFolderInfo *fi;
+ char *utf7_name;
+ CamelURL *url;
+ const char *p;
+ int id;
+
+ CAMEL_SERVICE_LOCK (store, connect_lock);
+
+ utf7_name = imap4_folder_utf7_name (store, folder_name, '\0');
+ ic = camel_imap4_engine_queue (engine, NULL, "SUBSCRIBE %S\r\n", utf7_name);
+ g_free (utf7_name);
+
+ while ((id = camel_imap4_engine_iterate (engine)) < ic->id && id != -1)
+ ;
+
+ if (id == -1 || ic->status != CAMEL_IMAP4_COMMAND_COMPLETE) {
+ camel_exception_xfer (ex, &ic->ex);
+ camel_imap4_command_unref (ic);
+ CAMEL_SERVICE_UNLOCK (store, connect_lock);
+ return;
+ }
+
+ switch (ic->result) {
+ case CAMEL_IMAP4_RESULT_OK:
+ /* subscribed */
+ url = camel_url_copy (engine->url);
+ camel_url_set_fragment (url, folder_name);
+
+ p = strrchr (folder_name, '/');
+
+ fi = g_malloc0 (sizeof (CamelFolderInfo));
+ fi->full_name = g_strdup (folder_name);
+ fi->name = g_strdup (p ? p + 1: folder_name);
+ fi->uri = camel_url_to_string (url, CAMEL_URL_HIDE_ALL);
+ camel_url_free (url);
+ fi->flags = CAMEL_FOLDER_NOCHILDREN;
+ fi->unread = -1;
+ fi->total = -1;
+
+ camel_object_trigger_event (store, "folder_subscribed", fi);
+ camel_folder_info_free (fi);
+ break;
+ case CAMEL_IMAP4_RESULT_NO:
+ /* FIXME: would be good to save the NO reason into the err message */
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot subscribe to folder `%s': Invalid mailbox name"),
+ folder_name);
+ break;
+ case CAMEL_IMAP4_RESULT_BAD:
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot subscribe to folder `%s': Bad command"),
+ folder_name);
+ break;
+ }
+
+ camel_imap4_command_unref (ic);
+
+ CAMEL_SERVICE_UNLOCK (store, connect_lock);
+}
+
+static void
+imap4_unsubscribe_folder (CamelStore *store, const char *folder_name, CamelException *ex)
+{
+ CamelIMAP4Engine *engine = ((CamelIMAP4Store *) store)->engine;
+ CamelIMAP4Command *ic;
+ CamelFolderInfo *fi;
+ char *utf7_name;
+ CamelURL *url;
+ const char *p;
+ int id;
+
+ CAMEL_SERVICE_LOCK (store, connect_lock);
+
+ utf7_name = imap4_folder_utf7_name (store, folder_name, '\0');
+ ic = camel_imap4_engine_queue (engine, NULL, "UNSUBSCRIBE %S\r\n", utf7_name);
+ g_free (utf7_name);
+
+ while ((id = camel_imap4_engine_iterate (engine)) < ic->id && id != -1)
+ ;
+
+ if (id == -1 || ic->status != CAMEL_IMAP4_COMMAND_COMPLETE) {
+ camel_exception_xfer (ex, &ic->ex);
+ camel_imap4_command_unref (ic);
+ CAMEL_SERVICE_UNLOCK (store, connect_lock);
+ return;
+ }
+
+ switch (ic->result) {
+ case CAMEL_IMAP4_RESULT_OK:
+ /* unsubscribed */
+ url = camel_url_copy (engine->url);
+ camel_url_set_fragment (url, folder_name);
+
+ p = strrchr (folder_name, '/');
+
+ fi = g_malloc0 (sizeof (CamelFolderInfo));
+ fi->full_name = g_strdup (folder_name);
+ fi->name = g_strdup (p ? p + 1: folder_name);
+ fi->uri = camel_url_to_string (url, CAMEL_URL_HIDE_ALL);
+ camel_url_free (url);
+ fi->flags = 0;
+ fi->unread = -1;
+ fi->total = -1;
+
+ camel_object_trigger_event (store, "folder_unsubscribed", fi);
+ camel_folder_info_free (fi);
+ break;
+ case CAMEL_IMAP4_RESULT_NO:
+ /* FIXME: would be good to save the NO reason into the err message */
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot unsubscribe from folder `%s': Invalid mailbox name"),
+ folder_name);
+ break;
+ case CAMEL_IMAP4_RESULT_BAD:
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot unsubscribe from folder `%s': Bad command"),
+ folder_name);
+ break;
+ }
+
+ camel_imap4_command_unref (ic);
+
+ CAMEL_SERVICE_UNLOCK (store, connect_lock);
+}
+
+static void
+imap4_noop (CamelStore *store, CamelException *ex)
+{
+ CamelIMAP4Engine *engine = ((CamelIMAP4Store *) store)->engine;
+ CamelFolder *folder = (CamelFolder *) engine->folder;
+ CamelIMAP4Command *ic;
+ int id;
+
+ CAMEL_SERVICE_LOCK (store, connect_lock);
+
+ if (folder) {
+ camel_folder_sync (folder, FALSE, ex);
+ if (camel_exception_is_set (ex)) {
+ CAMEL_SERVICE_UNLOCK (store, connect_lock);
+ return;
+ }
+ }
+
+ ic = camel_imap4_engine_queue (engine, NULL, "NOOP\r\n");
+ while ((id = camel_imap4_engine_iterate (engine)) < ic->id && id != -1)
+ ;
+
+ if (id == -1 || ic->status != CAMEL_IMAP4_COMMAND_COMPLETE)
+ camel_exception_xfer (ex, &ic->ex);
+
+ camel_imap4_command_unref (ic);
+
+ if (folder && !camel_exception_is_set (ex))
+ camel_imap4_summary_flush_updates (folder->summary, ex);
+
+ CAMEL_SERVICE_UNLOCK (store, connect_lock);
+}
diff --git a/camel/providers/imapp/camel-imapp-store.c b/camel/providers/imapp/camel-imapp-store.c
new file mode 100644
index 0000000000..c1c9f50649
--- /dev/null
+++ b/camel/providers/imapp/camel-imapp-store.c
@@ -0,0 +1,1016 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* camel-imap-store.c : class for a imap store */
+
+/*
+ * Authors: Michael Zucchi <notzed@ximian.com>
+ *
+ * Copyright (C) 2000-2002 Ximian, Inc. (www.ximian.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "camel/camel-operation.h"
+
+#include "camel/camel-stream-buffer.h"
+#include "camel/camel-session.h"
+#include "camel/camel-exception.h"
+#include "camel/camel-url.h"
+#include "camel/camel-sasl.h"
+#include "camel/camel-data-cache.h"
+#include "camel/camel-tcp-stream.h"
+#include "camel/camel-tcp-stream-raw.h"
+#ifdef HAVE_SSL
+#include "camel/camel-tcp-stream-ssl.h"
+#endif
+
+#include "camel-imapp-store-summary.h"
+#include "camel-imapp-store.h"
+#include "camel-imapp-folder.h"
+#include "camel-imapp-engine.h"
+#include "camel-imapp-exception.h"
+#include "camel-imapp-utils.h"
+#include "camel-imapp-driver.h"
+
+/* Specified in RFC 2060 section 2.1 */
+#define IMAP_PORT 143
+
+static CamelStoreClass *parent_class = NULL;
+
+static void finalize (CamelObject *object);
+
+static void imap_construct(CamelService *service, CamelSession *session, CamelProvider *provider, CamelURL *url, CamelException *ex);
+/* static char *imap_get_name(CamelService *service, gboolean brief);*/
+static gboolean imap_connect (CamelService *service, CamelException *ex);
+static gboolean imap_disconnect (CamelService *service, gboolean clean, CamelException *ex);
+static GList *imap_query_auth_types (CamelService *service, CamelException *ex);
+
+static CamelFolder *imap_get_trash (CamelStore *store, CamelException *ex);
+
+static CamelFolder *imap_get_folder(CamelStore * store, const char *folder_name, guint32 flags, CamelException * ex);
+static CamelFolder *imap_get_inbox (CamelStore *store, CamelException *ex);
+static void imap_rename_folder(CamelStore *store, const char *old_name, const char *new_name, CamelException *ex);
+static CamelFolderInfo *imap_get_folder_info (CamelStore *store, const char *top, guint32 flags, CamelException *ex);
+static void imap_delete_folder(CamelStore *store, const char *folder_name, CamelException *ex);
+static void imap_rename_folder(CamelStore *store, const char *old, const char *new, CamelException *ex);
+static CamelFolderInfo *imap_create_folder(CamelStore *store, const char *parent_name, const char *folder_name, CamelException *ex);
+
+/* yet to see if this should go global or not */
+void camel_imapp_store_folder_selected(CamelIMAPPStore *store, CamelIMAPPFolder *folder, CamelIMAPPSelectResponse *select);
+
+static void
+camel_imapp_store_class_init (CamelIMAPPStoreClass *camel_imapp_store_class)
+{
+ CamelServiceClass *camel_service_class = CAMEL_SERVICE_CLASS(camel_imapp_store_class);
+ CamelStoreClass *camel_store_class = CAMEL_STORE_CLASS(camel_imapp_store_class);
+
+ parent_class = CAMEL_STORE_CLASS(camel_type_get_global_classfuncs(camel_store_get_type()));
+
+ /* virtual method overload */
+ camel_service_class->construct = imap_construct;
+ /*camel_service_class->get_name = imap_get_name;*/
+ camel_service_class->query_auth_types = imap_query_auth_types;
+ camel_service_class->connect = imap_connect;
+ camel_service_class->disconnect = imap_disconnect;
+
+ camel_store_class->get_trash = imap_get_trash;
+ camel_store_class->get_folder = imap_get_folder;
+ camel_store_class->get_inbox = imap_get_inbox;
+
+ camel_store_class->create_folder = imap_create_folder;
+ camel_store_class->rename_folder = imap_rename_folder;
+ camel_store_class->delete_folder = imap_delete_folder;
+ camel_store_class->get_folder_info = imap_get_folder_info;
+}
+
+static void
+camel_imapp_store_init (gpointer object, gpointer klass)
+{
+ /*CamelIMAPPStore *istore = object;*/
+}
+
+CamelType
+camel_imapp_store_get_type (void)
+{
+ static CamelType camel_imapp_store_type = CAMEL_INVALID_TYPE;
+
+ if (!camel_imapp_store_type) {
+ camel_imapp_store_type = camel_type_register(CAMEL_STORE_TYPE,
+ "CamelIMAPPStore",
+ sizeof (CamelIMAPPStore),
+ sizeof (CamelIMAPPStoreClass),
+ (CamelObjectClassInitFunc) camel_imapp_store_class_init,
+ NULL,
+ (CamelObjectInitFunc) camel_imapp_store_init,
+ finalize);
+ }
+
+ return camel_imapp_store_type;
+}
+
+static void
+finalize (CamelObject *object)
+{
+ CamelIMAPPStore *imap_store = CAMEL_IMAPP_STORE (object);
+
+ /* force disconnect so we dont have it run later, after we've cleaned up some stuff */
+ /* SIGH */
+
+ camel_service_disconnect((CamelService *)imap_store, TRUE, NULL);
+
+ if (imap_store->driver)
+ camel_object_unref(imap_store->driver);
+ if (imap_store->cache)
+ camel_object_unref(imap_store->cache);
+}
+
+static void imap_construct(CamelService *service, CamelSession *session, CamelProvider *provider, CamelURL *url, CamelException *ex)
+{
+ char *root, *summary;
+ CamelIMAPPStore *store = (CamelIMAPPStore *)service;
+
+ CAMEL_SERVICE_CLASS (parent_class)->construct (service, session, provider, url, ex);
+ if (camel_exception_is_set(ex))
+ return;
+
+ CAMEL_TRY {
+ store->summary = camel_imapp_store_summary_new();
+ root = camel_session_get_storage_path(service->session, service, ex);
+ if (root) {
+ summary = g_build_filename(root, ".ev-store-summary", NULL);
+ camel_store_summary_set_filename((CamelStoreSummary *)store->summary, summary);
+ /* FIXME: need to remove params, passwords, etc */
+ camel_store_summary_set_uri_base((CamelStoreSummary *)store->summary, service->url);
+ camel_store_summary_load((CamelStoreSummary *)store->summary);
+ }
+ } CAMEL_CATCH(e) {
+ camel_exception_xfer(ex, e);
+ } CAMEL_DONE;
+}
+
+enum {
+ USE_SSL_NEVER,
+ USE_SSL_ALWAYS,
+ USE_SSL_WHEN_POSSIBLE
+};
+
+#define SSL_PORT_FLAGS (CAMEL_TCP_STREAM_SSL_ENABLE_SSL2 | CAMEL_TCP_STREAM_SSL_ENABLE_SSL3)
+#define STARTTLS_FLAGS (CAMEL_TCP_STREAM_SSL_ENABLE_TLS)
+
+static void
+connect_to_server (CamelService *service, int ssl_mode, int try_starttls)
+/* throws IO exception */
+{
+ CamelIMAPPStore *store = CAMEL_IMAPP_STORE (service);
+ CamelStream * volatile tcp_stream = NULL;
+ CamelIMAPPStream * volatile imap_stream = NULL;
+ int ret;
+ CamelException *ex;
+
+ ex = camel_exception_new();
+ CAMEL_TRY {
+ char *serv;
+ const char *port = NULL;
+ struct addrinfo *ai, hints = { 0 };
+
+ /* parent class connect initialization */
+ CAMEL_SERVICE_CLASS (parent_class)->connect (service, ex);
+ if (ex->id)
+ camel_exception_throw_ex(ex);
+
+ if (service->url->port) {
+ serv = g_alloca(16);
+ sprintf(serv, "%d", service->url->port);
+ } else {
+ serv = "imap";
+ port = "143";
+ }
+
+#ifdef HAVE_SSL
+ if (camel_url_get_param (service->url, "use_ssl")) {
+ if (try_starttls)
+ tcp_stream = camel_tcp_stream_ssl_new_raw (service->session, service->url->host, STARTTLS_FLAGS);
+ else {
+ if (service->url->port == 0) {
+ serv = "imaps";
+ port = "993";
+ }
+ tcp_stream = camel_tcp_stream_ssl_new (service->session, service->url->host, SSL_PORT_FLAGS);
+ }
+ } else {
+ tcp_stream = camel_tcp_stream_raw_new ();
+ }
+#else
+ tcp_stream = camel_tcp_stream_raw_new ();
+#endif /* HAVE_SSL */
+
+ hints.ai_socktype = SOCK_STREAM;
+ ai = camel_getaddrinfo(service->url->host, serv, &hints, ex);
+ if (ex->id && ex->id != CAMEL_EXCEPTION_USER_CANCEL && port != NULL) {
+ camel_exception_clear(ex);
+ ai = camel_getaddrinfo(service->url->host, port, &hints, ex);
+ }
+
+ if (ex->id)
+ camel_exception_throw_ex(ex);
+
+ ret = camel_tcp_stream_connect(CAMEL_TCP_STREAM(tcp_stream), ai);
+ camel_freeaddrinfo(ai);
+ if (ret == -1) {
+ if (errno == EINTR)
+ camel_exception_throw(CAMEL_EXCEPTION_USER_CANCEL, _("Connection cancelled"));
+ else
+ camel_exception_throw(CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ _("Could not connect to %s (port %s): %s"),
+ service->url->host, serv, strerror(errno));
+ }
+
+ imap_stream = (CamelIMAPPStream *)camel_imapp_stream_new(tcp_stream);
+ store->driver = camel_imapp_driver_new(imap_stream);
+
+ camel_object_unref(imap_stream);
+ camel_object_unref(tcp_stream);
+ } CAMEL_CATCH(e) {
+ if (tcp_stream)
+ camel_object_unref(tcp_stream);
+ if (imap_stream)
+ camel_object_unref((CamelObject *)imap_stream);
+ camel_exception_throw_ex(e);
+ } CAMEL_DONE;
+
+ camel_exception_free(ex);
+}
+
+#if 0
+
+/* leave this stuff out for now */
+
+
+static struct {
+ char *value;
+ int mode;
+} ssl_options[] = {
+ { "", USE_SSL_ALWAYS },
+ { "always", USE_SSL_ALWAYS },
+ { "when-possible", USE_SSL_WHEN_POSSIBLE },
+ { "never", USE_SSL_NEVER },
+ { NULL, USE_SSL_NEVER },
+};
+
+static gboolean
+connect_to_server_wrapper (CamelService *service, CamelException *ex)
+{
+#ifdef HAVE_SSL
+ const char *use_ssl;
+ int i, ssl_mode;
+
+ use_ssl = camel_url_get_param (service->url, "use_ssl");
+ if (use_ssl) {
+ for (i = 0; ssl_options[i].value; i++)
+ if (!strcmp (ssl_options[i].value, use_ssl))
+ break;
+ ssl_mode = ssl_options[i].mode;
+ } else
+ ssl_mode = USE_SSL_NEVER;
+
+ if (ssl_mode == USE_SSL_ALWAYS) {
+ /* First try the ssl port */
+ if (!connect_to_server (service, ssl_mode, FALSE, ex)) {
+ if (camel_exception_get_id (ex) == CAMEL_EXCEPTION_SERVICE_UNAVAILABLE) {
+ /* The ssl port seems to be unavailable, lets try STARTTLS */
+ camel_exception_clear (ex);
+ return connect_to_server (service, ssl_mode, TRUE, ex);
+ } else {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+ } else if (ssl_mode == USE_SSL_WHEN_POSSIBLE) {
+ /* If the server supports STARTTLS, use it */
+ return connect_to_server (service, ssl_mode, TRUE, ex);
+ } else {
+ /* User doesn't care about SSL */
+ return connect_to_server (service, ssl_mode, FALSE, ex);
+ }
+#else
+ return connect_to_server (service, USE_SSL_NEVER, FALSE, ex);
+#endif
+}
+#endif
+
+extern CamelServiceAuthType camel_imapp_password_authtype;
+extern CamelServiceAuthType camel_imapp_apop_authtype;
+
+static GList *
+imap_query_auth_types (CamelService *service, CamelException *ex)
+{
+ /*CamelIMAPPStore *store = CAMEL_IMAPP_STORE (service);*/
+ GList *types = NULL;
+
+ types = CAMEL_SERVICE_CLASS (parent_class)->query_auth_types (service, ex);
+ if (types == NULL)
+ return NULL;
+
+#if 0
+ if (connect_to_server_wrapper (service, NULL)) {
+ types = g_list_concat(types, g_list_copy(store->engine->auth));
+ imap_disconnect (service, TRUE, NULL);
+ } else {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ _("Could not connect to POP server on %s"),
+ service->url->host);
+ }
+#endif
+ return types;
+}
+
+static void
+store_get_pass(CamelIMAPPStore *store)
+{
+ if (((CamelService *)store)->url->passwd == NULL) {
+ char *prompt;
+ CamelException ex;
+
+ camel_exception_init(&ex);
+
+ prompt = g_strdup_printf (_("%sPlease enter the IMAP password for %s@%s"),
+ store->login_error?store->login_error:"",
+ ((CamelService *)store)->url->user,
+ ((CamelService *)store)->url->host);
+ ((CamelService *)store)->url->passwd = camel_session_get_password(camel_service_get_session((CamelService *)store),
+ (CamelService *)store, NULL,
+ prompt, "password", CAMEL_SESSION_PASSWORD_SECRET, &ex);
+ g_free (prompt);
+ if (camel_exception_is_set(&ex))
+ camel_exception_throw_ex(&ex);
+ }
+}
+
+static struct _CamelSasl *
+store_get_sasl(struct _CamelIMAPPDriver *driver, CamelIMAPPStore *store)
+{
+ store_get_pass(store);
+
+ if (((CamelService *)store)->url->authmech)
+ return camel_sasl_new("imap", ((CamelService *)store)->url->authmech, (CamelService *)store);
+
+ return NULL;
+}
+
+static void
+store_get_login(struct _CamelIMAPPDriver *driver, char **login, char **pass, CamelIMAPPStore *store)
+{
+ store_get_pass(store);
+
+ *login = g_strdup(((CamelService *)store)->url->user);
+ *pass = g_strdup(((CamelService *)store)->url->passwd);
+}
+
+static gboolean
+imap_connect (CamelService *service, CamelException *ex)
+{
+ CamelIMAPPStore *store = (CamelIMAPPStore *)service;
+ volatile int ret = FALSE;
+
+ CAMEL_TRY {
+ volatile int retry = TRUE;
+
+ if (store->cache == NULL) {
+ char *root;
+
+ root = camel_session_get_storage_path(service->session, service, ex);
+ if (root) {
+ store->cache = camel_data_cache_new(root, 0, ex);
+ g_free(root);
+ if (store->cache) {
+ /* Default cache expiry - 1 week or not visited in a day */
+ camel_data_cache_set_expire_age(store->cache, 60*60*24*7);
+ camel_data_cache_set_expire_access(store->cache, 60*60*24);
+ }
+ }
+ if (camel_exception_is_set(ex))
+ camel_exception_throw_ex(ex);
+ }
+
+ connect_to_server(service, USE_SSL_NEVER, FALSE);
+
+ camel_imapp_driver_set_sasl_factory(store->driver, (CamelIMAPPSASLFunc)store_get_sasl, store);
+ camel_imapp_driver_set_login_query(store->driver, (CamelIMAPPLoginFunc)store_get_login, store);
+ store->login_error = NULL;
+
+ do {
+ CAMEL_TRY {
+ if (store->driver->engine->state != IMAP_ENGINE_AUTH)
+ camel_imapp_driver_login(store->driver);
+ ret = TRUE;
+ retry = FALSE;
+ } CAMEL_CATCH(e) {
+ g_free(store->login_error);
+ store->login_error = NULL;
+ switch (e->id) {
+ case CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE:
+ store->login_error = g_strdup_printf("%s\n\n", e->desc);
+ camel_session_forget_password(service->session, service, NULL, "password", ex);
+ camel_url_set_passwd(service->url, NULL);
+ break;
+ default:
+ camel_exception_throw_ex(e);
+ break;
+ }
+ } CAMEL_DONE;
+ } while (retry);
+ } CAMEL_CATCH(e) {
+ camel_exception_xfer(ex, e);
+ camel_service_disconnect(service, TRUE, NULL);
+ ret = FALSE;
+ } CAMEL_DONE;
+
+ g_free(store->login_error);
+ store->login_error = NULL;
+
+ return ret;
+}
+
+static gboolean
+imap_disconnect (CamelService *service, gboolean clean, CamelException *ex)
+{
+ CamelIMAPPStore *store = CAMEL_IMAPP_STORE (service);
+
+ /* FIXME: logout */
+
+ if (!CAMEL_SERVICE_CLASS (parent_class)->disconnect (service, clean, ex))
+ return FALSE;
+
+ /* logout/disconnect */
+ if (store->driver) {
+ camel_object_unref(store->driver);
+ store->driver = NULL;
+ }
+
+ return TRUE;
+}
+
+static CamelFolder *
+imap_get_trash (CamelStore *store, CamelException *ex)
+{
+ /* no-op */
+ return NULL;
+}
+
+static CamelFolder *
+imap_get_folder (CamelStore *store, const char *folder_name, guint32 flags, CamelException *ex)
+{
+ CamelIMAPPStore *istore = (CamelIMAPPStore *)store;
+ CamelIMAPPFolder * volatile folder = NULL;
+
+ /* ??? */
+
+ /* 1. create the folder */
+ /* 2. run select? */
+ /* 3. update the folder */
+
+ CAMEL_TRY {
+ folder = (CamelIMAPPFolder *)camel_imapp_folder_new(store, folder_name);
+ camel_imapp_driver_select(istore->driver, folder);
+ } CAMEL_CATCH (e) {
+ if (folder) {
+ camel_object_unref(folder);
+ folder = NULL;
+ }
+ camel_exception_xfer(ex, e);
+ } CAMEL_DONE;
+
+ return (CamelFolder *)folder;
+}
+
+static CamelFolder *
+imap_get_inbox(CamelStore *store, CamelException *ex)
+{
+ camel_exception_setv(ex, 1, "get_inbox::unimplemented");
+
+ return NULL;
+}
+
+/* 8 bit, string compare */
+static int folders_build_cmp(const void *app, const void *bpp)
+{
+ struct _list_info *a = *((struct _list_info **)app);
+ struct _list_info *b = *((struct _list_info **)bpp);
+ unsigned char *ap = (unsigned char *)(a->name);
+ unsigned char *bp = (unsigned char *)(b->name);
+
+ printf("qsort, cmp '%s' <> '%s'\n", ap, bp);
+
+ while (*ap && *ap == *bp) {
+ ap++;
+ bp++;
+ }
+
+ if (*ap < *bp)
+ return -1;
+ else if (*ap > *bp)
+ return 1;
+ return 0;
+}
+
+/* FIXME: this should go via storesummary? */
+static CamelFolderInfo *
+folders_build_info(CamelURL *base, struct _list_info *li)
+{
+ char *path, *full_name, *name;
+ CamelFolderInfo *fi;
+
+ full_name = imapp_list_get_path(li);
+ name = strrchr(full_name, '/');
+ if (name)
+ name++;
+ else
+ name = full_name;
+
+ path = alloca(strlen(full_name)+2);
+ sprintf(path, "/%s", full_name);
+ camel_url_set_path(base, path);
+
+ fi = g_malloc0(sizeof(*fi));
+ fi->uri = camel_url_to_string(base, CAMEL_URL_HIDE_ALL);
+ fi->name = g_strdup(name);
+ fi->full_name = full_name;
+ fi->unread = -1;
+ fi->total = -1;
+ fi->flags = li->flags;
+
+ if (!g_ascii_strcasecmp(fi->full_name, "inbox"))
+ fi->flags |= CAMEL_FOLDER_SYSTEM;
+
+ /* TODO: could look up count here ... */
+ /* ?? */
+ /*folder = camel_object_bag_get(store->folders, "INBOX");*/
+
+ return fi;
+}
+
+/*
+ a
+ a/b
+ a/b/c
+ a/d
+ b
+ c/d
+
+*/
+
+/* note, pname is the raw name, not the folderinfo name */
+/* note also this free's as we go, since we never go 'backwards' */
+static CamelFolderInfo *
+folders_build_rec(CamelURL *base, GPtrArray *folders, int *ip, CamelFolderInfo *pfi, char *pname)
+{
+ int plen = 0;
+ CamelFolderInfo *last = NULL, *first = NULL;
+
+ if (pfi)
+ plen = strlen(pname);
+
+ for(;(*ip)<(int)folders->len;) {
+ CamelFolderInfo *fi;
+ struct _list_info *li;
+
+ li = folders->pdata[*ip];
+ printf("checking '%s' is child of '%s'\n", li->name, pname);
+
+ /* is this a child of the parent? */
+ if (pfi != NULL
+ && (strncmp(pname, li->name, strlen(pname)) != 0
+ || li->name[plen] != li->separator)) {
+ printf(" nope\n");
+ break;
+ }
+ printf(" yep\n");
+
+ /* is this not an immediate child of the parent? */
+#if 0
+ char *p;
+ if (pfi != NULL
+ && li->separator != 0
+ && (p = strchr(li->name + plen + 1, li->separator)) != NULL) {
+ if (last == NULL) {
+ struct _list_info tli;
+
+ tli.flags = CAMEL_FOLDER_NOSELECT|CAMEL_FOLDER_CHILDREN;
+ tli.separator = li->separator;
+ tli.name = g_strndup(li->name, p-li->name+1);
+ fi = folders_build_info(base, &tli);
+ fi->parent = pfi;
+ if (pfi && pfi->child == NULL)
+ pfi->child = fi;
+ i = folders_build_rec(folders, i, fi, tli.name);
+ break;
+ }
+ }
+#endif
+
+ fi = folders_build_info(base, li);
+ fi->parent = pfi;
+ if (last != NULL)
+ last->next = fi;
+ last = fi;
+ if (first == NULL)
+ first = fi;
+
+ (*ip)++;
+ fi->child = folders_build_rec(base, folders, ip, fi, li->name);
+ imap_free_list(li);
+ }
+
+ return first;
+}
+
+static void
+folder_info_dump(CamelFolderInfo *fi, int depth)
+{
+ char *s;
+
+ s = alloca(depth+1);
+ memset(s, ' ', depth);
+ s[depth] = 0;
+ while (fi) {
+ printf("%s%s (%s)\n", s, fi->name, fi->uri);
+ if (fi->child)
+ folder_info_dump(fi->child, depth+2);
+ fi = fi->next;
+ }
+
+}
+
+static CamelFolderInfo *
+imap_get_folder_info(CamelStore *store, const char *top, guint32 flags, CamelException *ex)
+{
+ CamelIMAPPStore *istore = (CamelIMAPPStore *)store;
+ CamelFolderInfo * fi= NULL;
+ char *name;
+
+ /* FIXME: temporary, since this is not a disco store */
+ if (istore->driver == NULL
+ && !camel_service_connect((CamelService *)store, ex))
+ return NULL;
+
+ name = (char *)top;
+ if (name == NULL || name[0] == 0) {
+ /* namespace? */
+ name = "";
+ }
+
+ name = "";
+
+ CAMEL_TRY {
+ CamelURL *base;
+ int i;
+ GPtrArray *folders;
+
+ /* FIXME: subscriptions? lsub? */
+ folders = camel_imapp_driver_list(istore->driver, name, flags);
+
+ /* this greatly simplifies the tree algorithm ... but it might
+ be faster just to use a hashtable to find parents? */
+ qsort(folders->pdata, folders->len, sizeof(folders->pdata[0]), folders_build_cmp);
+
+ i = 0;
+ base = camel_url_copy(((CamelService *)store)->url);
+ fi = folders_build_rec(base, folders, &i, NULL, NULL);
+ camel_url_free(base);
+ g_ptr_array_free(folders, TRUE);
+ } CAMEL_CATCH(e) {
+ camel_exception_xfer(ex, e);
+ } CAMEL_DONE;
+
+ printf("built folder info:\n");
+ folder_info_dump(fi, 2);
+
+ return fi;
+
+#if 0
+ if (top == NULL || !g_ascii_strcasecmp(top, "inbox")) {
+ CamelURL *uri = camel_url_copy(((CamelService *)store)->url);
+
+ camel_url_set_path(uri, "/INBOX");
+ fi = g_malloc0(sizeof(*fi));
+ fi->url = camel_url_to_string(uri, CAMEL_URL_HIDE_ALL);
+ camel_url_free(uri);
+ fi->name = g_strdup("INBOX");
+ fi->full_name = g_strdup("INBOX");
+ fi->path = g_strdup("/INBOX");
+ fi->unread_message_count = -1;
+ fi->flags = 0;
+
+ folder = camel_object_bag_get(store->folders, "INBOX");
+ if (folder) {
+ /*if (!cflags & FAST)*/
+ camel_imapp_driver_update(istore->driver, (CamelIMAPPFolder *)folder);
+ fi->unread_message_count = camel_folder_get_unread_message_count(folder);
+ camel_object_unref(folder);
+ }
+ } else {
+ camel_exception_setv(ex, 1, "not implemented");
+ }
+#endif
+ return fi;
+
+#if 0
+ istore->pending_list = g_ptr_array_new();
+
+ CAMEL_TRY {
+ ic = camel_imapp_engine_command_new(istore->driver->engine, "LIST", NULL, "LIST \"\" %f", top);
+ camel_imapp_engine_command_queue(istore->driver->engine, ic);
+ while (camel_imapp_engine_iterate(istore->driver->engine, ic) > 0)
+ ;
+
+ if (ic->status->result != IMAP_OK)
+ camel_exception_throw(1, "list failed: %s", ic->status->text);
+ } CAMEL_CATCH (e) {
+ camel_exception_xfer(ex, e);
+ } CAMEL_DONE;
+
+ camel_imapp_engine_command_free(istore->driver->engine, ic);
+
+ printf("got folder list:\n");
+ for (i=0;i<(int)istore->pending_list->len;i++) {
+ struct _list_info *linfo = istore->pending_list->pdata[i];
+
+ printf("%s (%c)\n", linfo->name, linfo->separator);
+ imap_free_list(linfo);
+ }
+ istore->pending_list = NULL;
+
+ return NULL;
+#endif
+}
+
+static void
+imap_delete_folder(CamelStore *store, const char *folder_name, CamelException *ex)
+{
+ camel_exception_setv(ex, 1, "delete_folder::unimplemented");
+}
+
+static void
+imap_rename_folder(CamelStore *store, const char *old, const char *new, CamelException *ex)
+{
+ camel_exception_setv(ex, 1, "rename_folder::unimplemented");
+}
+
+static CamelFolderInfo *
+imap_create_folder(CamelStore *store, const char *parent_name, const char *folder_name, CamelException *ex)
+{
+ camel_exception_setv(ex, 1, "create_folder::unimplemented");
+ return NULL;
+}
+
+/* ********************************************************************** */
+#if 0
+static int store_resp_fetch(CamelIMAPPEngine *ie, guint32 id, void *data)
+{
+ struct _fetch_info *finfo;
+ CamelIMAPPStore *istore = data;
+ CamelMessageInfo *info;
+ struct _pending_fetch *pending;
+
+ finfo = imap_parse_fetch(ie->stream);
+ if (istore->selected) {
+ if ((finfo->got & FETCH_UID) == 0) {
+ printf("didn't get uid in fetch response?\n");
+ } else {
+ info = camel_folder_summary_index(((CamelFolder *)istore->selected)->summary, id-1);
+ /* exists, check/update */
+ if (info) {
+ if (strcmp(finfo->uid, camel_message_info_uid(info)) != 0) {
+ printf("summary at index %d has uid %s expected %s\n", id, camel_message_info_uid(info), finfo->uid);
+ /* uid mismatch??? try do it based on uid instead? try to reorder? i dont know? */
+ camel_folder_summary_info_free(((CamelFolder *)istore->selected)->summary, info);
+ info = camel_folder_summary_uid(((CamelFolder *)istore->selected)->summary, finfo->uid);
+ }
+ }
+
+ if (info) {
+ if (finfo->got & (FETCH_FLAGS)) {
+ printf("updating flags for uid '%s'\n", finfo->uid);
+ info->flags = finfo->flags;
+ camel_folder_change_info_change_uid(istore->selected->changes, finfo->uid);
+ }
+ if (finfo->got & FETCH_MINFO) {
+ printf("got envelope unexpectedly?\n");
+ }
+ /* other things go here, like body fetches */
+ } else {
+ pending = g_hash_table_lookup(istore->pending_fetch_table, finfo->uid);
+
+ /* we need to create a new info, we only care about flags and minfo */
+
+ if (pending)
+ info = pending->info;
+ else {
+ info = camel_folder_summary_info_new(((CamelFolder *)istore->selected)->summary);
+ camel_message_info_set_uid(info, g_strdup(finfo->uid));
+ }
+
+ if (finfo->got & FETCH_FLAGS)
+ info->flags = finfo->flags;
+
+ if (finfo->got & FETCH_MINFO) {
+ /* if we only use ENVELOPE? */
+ camel_message_info_set_subject(info, g_strdup(camel_message_info_subject(finfo->minfo)));
+ camel_message_info_set_from(info, g_strdup(camel_message_info_from(finfo->minfo)));
+ camel_message_info_set_to(info, g_strdup(camel_message_info_to(finfo->minfo)));
+ camel_message_info_set_cc(info, g_strdup(camel_message_info_cc(finfo->minfo)));
+ info->date_sent = finfo->minfo->date_sent;
+ camel_folder_summary_add(((CamelFolder *)istore->selected)->summary, info);
+ camel_folder_change_info_add_uid(istore->selected->changes, finfo->uid);
+ if (pending) {
+ e_dlist_remove((EDListNode *)pending);
+ g_hash_table_remove(istore->pending_fetch_table, finfo->uid);
+ /*e_memchunk_free(istore->pending_fetch_chunks, pending);*/
+ }
+ } else if (finfo->got & FETCH_HEADER) {
+ /* if we only use HEADER? */
+ CamelMimeParser *mp;
+
+ if (pending == NULL)
+ camel_folder_summary_info_free(((CamelFolder *)istore->selected)->summary, info);
+ mp = camel_mime_parser_new();
+ camel_mime_parser_init_with_stream(mp, finfo->header);
+ info = camel_folder_summary_info_new_from_parser(((CamelFolder *)istore->selected)->summary, mp);
+ camel_object_unref(mp);
+ camel_message_info_set_uid(info, g_strdup(finfo->uid));
+
+ camel_folder_summary_add(((CamelFolder *)istore->selected)->summary, info);
+ camel_folder_change_info_add_uid(istore->selected->changes, finfo->uid);
+ if (pending) {
+ /* FIXME: use a dlist */
+ e_dlist_remove((EDListNode *)pending);
+ g_hash_table_remove(istore->pending_fetch_table, camel_message_info_uid(pending->info));
+ camel_folder_summary_info_free(((CamelFolder *)istore->selected)->summary, pending->info);
+ /*e_memchunk_free(istore->pending_fetch_chunks, pending);*/
+ }
+ } else if (finfo->got & FETCH_FLAGS) {
+ if (pending == NULL) {
+ pending = e_memchunk_alloc(istore->pending_fetch_chunks);
+ pending->info = info;
+ g_hash_table_insert(istore->pending_fetch_table, (char *)camel_message_info_uid(info), pending);
+ e_dlist_addtail(&istore->pending_fetch_list, (EDListNode *)pending);
+ }
+ } else {
+ if (pending == NULL)
+ camel_folder_summary_info_free(((CamelFolder *)istore->selected)->summary, info);
+ printf("got unexpected fetch response?\n");
+ imap_dump_fetch(finfo);
+ }
+ }
+ }
+ } else {
+ printf("unexpected fetch response, no folder selected?\n");
+ }
+ /*imap_dump_fetch(finfo);*/
+ imap_free_fetch(finfo);
+
+ return camel_imapp_engine_skip(ie);
+}
+#endif
+
+/* ********************************************************************** */
+
+/* should be moved to imapp-utils?
+ stuff in imapp-utils should be moved to imapp-parse? */
+
+/* ********************************************************************** */
+
+#if 0
+void
+camel_imapp_store_folder_selected(CamelIMAPPStore *store, CamelIMAPPFolder *folder, CamelIMAPPSelectResponse *select)
+{
+ CamelIMAPPCommand * volatile ic = NULL;
+ CamelIMAPPStore *istore = (CamelIMAPPStore *)store;
+ int i;
+ struct _uidset_state ss;
+ GPtrArray *fetch;
+ CamelMessageInfo *info;
+ struct _pending_fetch *fw, *fn;
+
+ printf("imap folder selected\n");
+
+ if (select->uidvalidity == folder->uidvalidity
+ && select->exists == folder->exists
+ && select->recent == folder->recent
+ && select->unseen == folder->unseen) {
+ /* no work to do? */
+ return;
+ }
+
+ istore->pending_fetch_table = g_hash_table_new(g_str_hash, g_str_equal);
+ istore->pending_fetch_chunks = e_memchunk_new(256, sizeof(struct _pending_fetch));
+
+ /* perform an update - flags first (and see what we have) */
+ CAMEL_TRY {
+ ic = camel_imapp_engine_command_new(istore->engine, "FETCH", NULL, "FETCH 1:%d (UID FLAGS)", select->exists);
+ camel_imapp_engine_command_queue(istore->engine, ic);
+ while (camel_imapp_engine_iterate(istore->engine, ic) > 0)
+ ;
+
+ if (ic->status->result != IMAP_OK)
+ camel_exception_throw(1, "fetch failed: %s", ic->status->text);
+
+ /* pending_fetch_list now contains any new messages */
+ /* FIXME: how do we work out no-longer present messages? */
+ printf("now fetching info for messages?\n");
+ uidset_init(&ss, store->engine);
+ ic = camel_imapp_engine_command_new(istore->engine, "FETCH", NULL, "UID FETCH ");
+ fw = (struct _pending_fetch *)istore->pending_fetch_list.head;
+ fn = fw->next;
+ while (fn) {
+ info = fw->info;
+ /* if the uid set fills, then flush the command out */
+ if (uidset_add(&ss, ic, camel_message_info_uid(info))
+ || (fn->next == NULL && uidset_done(&ss, ic))) {
+ camel_imapp_engine_command_add(istore->engine, ic, " (FLAGS RFC822.HEADER)");
+ camel_imapp_engine_command_queue(istore->engine, ic);
+ while (camel_imapp_engine_iterate(istore->engine, ic) > 0)
+ ;
+ if (ic->status->result != IMAP_OK)
+ camel_exception_throw(1, "fetch failed: %s", ic->status->text);
+ /* if not end ... */
+ camel_imapp_engine_command_free(istore->engine, ic);
+ ic = camel_imapp_engine_command_new(istore->engine, "FETCH", NULL, "UID FETCH ");
+ }
+ fw = fn;
+ fn = fn->next;
+ }
+
+ printf("The pending list should now be empty: %s\n", e_dlist_empty(&istore->pending_fetch_list)?"TRUE":"FALSE");
+ for (i=0;i<10;i++) {
+ info = camel_folder_summary_index(((CamelFolder *)istore->selected)->summary, i);
+ if (info) {
+ printf("message info [%d] =\n", i);
+ camel_message_info_dump(info);
+ camel_folder_summary_info_free(((CamelFolder *)istore->selected)->summary, info);
+ }
+ }
+ } CAMEL_CATCH (e) {
+ /* FIXME: cleanup */
+ camel_exception_throw_ex(e);
+ } CAMEL_DONE;
+
+ g_hash_table_destroy(istore->pending_fetch_table);
+ istore->pending_fetch_table = NULL;
+ e_memchunk_destroy(istore->pending_fetch_chunks);
+
+ camel_imapp_engine_command_free(istore->engine, ic);
+}
+#endif
+
+#if 0
+/*char *uids[] = {"1", "2", "4", "5", "6", "7", "9", "11", "12", 0};*/
+/*char *uids[] = {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", 0};*/
+char *uids[] = {"1", "3", "5", "7", "9", "11", "12", "13", "14", "15", "20", "21", "24", "25", "26", 0};
+
+void
+uidset_test(CamelIMAPPEngine *ie)
+{
+ struct _uidset_state ss;
+ CamelIMAPPCommand *ic;
+ int i;
+
+ /*ic = camel_imapp_engine_command_new(ie, 0, "FETCH", NULL, "FETCH ");*/
+ uidset_init(&ss, 0, 0);
+ for (i=0;uids[i];i++) {
+ if (uidset_add(&ss, uids[i])) {
+ printf("\n[%d] flushing uids\n", i);
+ }
+ }
+
+ if (uidset_done(&ss)) {
+ printf("\nflushing uids\n");
+ }
+}
+#endif
diff --git a/camel/providers/local/camel-local-folder.c b/camel/providers/local/camel-local-folder.c
new file mode 100644
index 0000000000..b86d23221a
--- /dev/null
+++ b/camel/providers/local/camel-local-folder.c
@@ -0,0 +1,631 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Michael Zucchi <notzed@ximian.com>
+ *
+ * Copyright 1999-2003 Ximian, Inc. (www.ximian.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+
+#ifndef _POSIX_PATH_MAX
+#include <posix1_lim.h>
+#endif
+
+#include "camel-local-folder.h"
+#include "camel-local-store.h"
+#include "camel-stream-fs.h"
+#include "camel-local-summary.h"
+#include "camel-data-wrapper.h"
+#include "camel-mime-message.h"
+#include "camel-stream-filter.h"
+#include "camel-mime-filter-from.h"
+#include "camel-exception.h"
+
+#include "camel-local-private.h"
+
+#include "camel-text-index.h"
+
+#define d(x) /*(printf("%s(%d): ", __FILE__, __LINE__),(x))*/
+
+#ifndef PATH_MAX
+#define PATH_MAX _POSIX_PATH_MAX
+#endif
+
+static CamelFolderClass *parent_class;
+static GSList *local_folder_properties;
+
+/* Returns the class for a CamelLocalFolder */
+#define CLOCALF_CLASS(so) CAMEL_LOCAL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so))
+#define CF_CLASS(so) CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so))
+#define CLOCALS_CLASS(so) CAMEL_STORE_CLASS (CAMEL_OBJECT_GET_CLASS(so))
+
+static int local_getv(CamelObject *object, CamelException *ex, CamelArgGetV *args);
+static int local_setv(CamelObject *object, CamelException *ex, CamelArgV *args);
+
+static int local_lock(CamelLocalFolder *lf, CamelLockType type, CamelException *ex);
+static void local_unlock(CamelLocalFolder *lf);
+
+static char *local_get_full_path(CamelLocalFolder *lf, const char *toplevel_dir, const char *full_name);
+static char *local_get_meta_path(CamelLocalFolder *lf, const char *toplevel_dir, const char *full_name, const char *ext);
+
+static void local_refresh_info(CamelFolder *folder, CamelException *ex);
+
+static void local_sync(CamelFolder *folder, gboolean expunge, CamelException *ex);
+static void local_expunge(CamelFolder *folder, CamelException *ex);
+
+static GPtrArray *local_search_by_expression(CamelFolder *folder, const char *expression, CamelException *ex);
+static GPtrArray *local_search_by_uids(CamelFolder *folder, const char *expression, GPtrArray *uids, CamelException *ex);
+static void local_search_free(CamelFolder *folder, GPtrArray * result);
+
+static void local_delete(CamelFolder *folder);
+static void local_rename(CamelFolder *folder, const char *newname);
+
+static void local_finalize(CamelObject * object);
+
+static void
+camel_local_folder_class_init(CamelLocalFolderClass * camel_local_folder_class)
+{
+ CamelFolderClass *camel_folder_class = CAMEL_FOLDER_CLASS(camel_local_folder_class);
+ CamelObjectClass *oklass = (CamelObjectClass *)camel_local_folder_class;
+
+ /* virtual method definition */
+
+ /* virtual method overload */
+ oklass->getv = local_getv;
+ oklass->setv = local_setv;
+
+ camel_folder_class->refresh_info = local_refresh_info;
+ camel_folder_class->sync = local_sync;
+ camel_folder_class->expunge = local_expunge;
+
+ camel_folder_class->search_by_expression = local_search_by_expression;
+ camel_folder_class->search_by_uids = local_search_by_uids;
+ camel_folder_class->search_free = local_search_free;
+
+ camel_folder_class->delete = local_delete;
+ camel_folder_class->rename = local_rename;
+
+ camel_local_folder_class->get_full_path = local_get_full_path;
+ camel_local_folder_class->get_meta_path = local_get_meta_path;
+
+ camel_local_folder_class->lock = local_lock;
+ camel_local_folder_class->unlock = local_unlock;
+}
+
+static void
+local_init(gpointer object, gpointer klass)
+{
+ CamelFolder *folder = object;
+ CamelLocalFolder *local_folder = object;
+
+ folder->folder_flags |= (CAMEL_FOLDER_HAS_SUMMARY_CAPABILITY |
+ CAMEL_FOLDER_HAS_SEARCH_CAPABILITY);
+
+ folder->permanent_flags = CAMEL_MESSAGE_ANSWERED |
+ CAMEL_MESSAGE_DELETED | CAMEL_MESSAGE_DRAFT |
+ CAMEL_MESSAGE_FLAGGED | CAMEL_MESSAGE_SEEN |
+ CAMEL_MESSAGE_ANSWERED_ALL | CAMEL_MESSAGE_USER;
+
+ folder->summary = NULL;
+ local_folder->search = NULL;
+
+ local_folder->priv = g_malloc0(sizeof(*local_folder->priv));
+ local_folder->priv->search_lock = g_mutex_new();
+}
+
+static void
+local_finalize(CamelObject * object)
+{
+ CamelLocalFolder *local_folder = CAMEL_LOCAL_FOLDER(object);
+ CamelFolder *folder = (CamelFolder *)object;
+
+ if (folder->summary) {
+ camel_local_summary_sync((CamelLocalSummary *)folder->summary, FALSE, local_folder->changes, NULL);
+ camel_object_unref((CamelObject *)folder->summary);
+ folder->summary = NULL;
+ }
+
+ if (local_folder->search) {
+ camel_object_unref((CamelObject *)local_folder->search);
+ }
+
+ if (local_folder->index)
+ camel_object_unref((CamelObject *)local_folder->index);
+
+ while (local_folder->locked> 0)
+ camel_local_folder_unlock(local_folder);
+
+ g_free(local_folder->base_path);
+ g_free(local_folder->folder_path);
+ g_free(local_folder->summary_path);
+ g_free(local_folder->index_path);
+
+ camel_folder_change_info_free(local_folder->changes);
+
+ g_mutex_free(local_folder->priv->search_lock);
+
+ g_free(local_folder->priv);
+}
+
+static CamelProperty local_property_list[] = {
+ { CAMEL_LOCAL_FOLDER_INDEX_BODY, "index_body", N_("Index message body data") },
+};
+
+CamelType
+camel_local_folder_get_type(void)
+{
+ static CamelType camel_local_folder_type = CAMEL_INVALID_TYPE;
+
+ if (camel_local_folder_type == CAMEL_INVALID_TYPE) {
+ int i;
+
+ parent_class = (CamelFolderClass *)camel_folder_get_type();
+ camel_local_folder_type = camel_type_register(camel_folder_get_type(), "CamelLocalFolder",
+ sizeof(CamelLocalFolder),
+ sizeof(CamelLocalFolderClass),
+ (CamelObjectClassInitFunc) camel_local_folder_class_init,
+ NULL,
+ (CamelObjectInitFunc) local_init,
+ (CamelObjectFinalizeFunc) local_finalize);
+
+ for (i=0;i<sizeof(local_property_list)/sizeof(local_property_list[0]);i++) {
+ local_property_list[i].description = _(local_property_list[i].description);
+ local_folder_properties = g_slist_prepend(local_folder_properties, &local_property_list[i]);
+ }
+ }
+
+ return camel_local_folder_type;
+}
+
+CamelLocalFolder *
+camel_local_folder_construct(CamelLocalFolder *lf, CamelStore *parent_store, const char *full_name, guint32 flags, CamelException *ex)
+{
+ CamelFolderInfo *fi;
+ CamelFolder *folder;
+ const char *root_dir_path, *name;
+ char *tmp, *statepath;
+ char folder_path[PATH_MAX];
+ struct stat st;
+ int forceindex, len;
+ CamelURL *url;
+
+ folder = (CamelFolder *)lf;
+
+ name = strrchr(full_name, '/');
+ if (name)
+ name++;
+ else
+ name = full_name;
+
+ camel_folder_construct(folder, parent_store, full_name, name);
+
+ root_dir_path = camel_local_store_get_toplevel_dir(CAMEL_LOCAL_STORE(folder->parent_store));
+ /* strip the trailing '/' which is always present */
+ len = strlen (root_dir_path);
+ tmp = g_alloca (len + 1);
+ strcpy (tmp, root_dir_path);
+ if (len>1 && tmp[len-1] == '/')
+ tmp[len-1] = 0;
+
+ lf->base_path = g_strdup(root_dir_path);
+
+ /* if the base store points to a file, then use that */
+ if (stat(tmp, &st) != -1 && S_ISREG(st.st_mode)) {
+ lf->folder_path = g_strdup(tmp);
+ /* not really sure to do with these for now? */
+ lf->summary_path = g_strdup_printf("%s.ev-summary", tmp);
+ lf->index_path = g_strdup_printf("%s.ibex", tmp);
+ statepath = g_strdup_printf("%s.cmeta", tmp);
+ } else {
+ lf->folder_path = CLOCALF_CLASS(lf)->get_full_path(lf, root_dir_path, full_name);
+ lf->summary_path = CLOCALF_CLASS(lf)->get_meta_path(lf, root_dir_path, full_name, ".ev-summary");
+ lf->index_path = CLOCALF_CLASS(lf)->get_meta_path(lf, root_dir_path, full_name, ".ibex");
+ statepath = CLOCALF_CLASS(lf)->get_meta_path(lf, root_dir_path, full_name, ".cmeta");
+ }
+ camel_object_set(lf, NULL, CAMEL_OBJECT_STATE_FILE, statepath, NULL);
+ g_free(statepath);
+
+ lf->flags = flags;
+
+ if (camel_object_state_read(lf) == -1) {
+ /* No metadata - load defaults and persitify */
+ camel_object_set(lf, NULL, CAMEL_LOCAL_FOLDER_INDEX_BODY, TRUE, 0);
+ camel_object_state_write(lf);
+ }
+
+ /* follow any symlinks to the mailbox */
+ if (lstat (lf->folder_path, &st) != -1 && S_ISLNK (st.st_mode) &&
+ realpath (lf->folder_path, folder_path) != NULL) {
+ g_free (lf->folder_path);
+ lf->folder_path = g_strdup (folder_path);
+ }
+
+ lf->changes = camel_folder_change_info_new();
+
+ /* TODO: Remove the following line, it is a temporary workaround to remove
+ the old-format 'ibex' files that might be lying around */
+ unlink(lf->index_path);
+
+ /* FIXME: Need to run indexing off of the setv method */
+
+ /* if we have no/invalid index file, force it */
+ forceindex = camel_text_index_check(lf->index_path) == -1;
+ if (lf->flags & CAMEL_STORE_FOLDER_BODY_INDEX) {
+ int flag = O_RDWR|O_CREAT;
+
+ if (forceindex)
+ flag |= O_TRUNC;
+
+ lf->index = (CamelIndex *)camel_text_index_new(lf->index_path, flag);
+ if (lf->index == NULL) {
+ /* yes, this isn't fatal at all */
+ g_warning("Could not open/create index file: %s: indexing not performed", strerror (errno));
+ forceindex = FALSE;
+ /* record that we dont have an index afterall */
+ lf->flags &= ~CAMEL_STORE_FOLDER_BODY_INDEX;
+ }
+ } else {
+ /* if we do have an index file, remove it (?) */
+ if (forceindex == FALSE)
+ camel_text_index_remove(lf->index_path);
+ forceindex = FALSE;
+ }
+
+ folder->summary = (CamelFolderSummary *)CLOCALF_CLASS(lf)->create_summary(lf, lf->summary_path, lf->folder_path, lf->index);
+ if (camel_local_summary_load((CamelLocalSummary *)folder->summary, forceindex, NULL) == -1) {
+ /* ? */
+ }
+
+ /*if (camel_local_summary_check((CamelLocalSummary *)folder->summary, lf->changes, ex) == -1) {*/
+ /* we sync here so that any hard work setting up the folder isn't lost */
+ if (camel_local_summary_sync((CamelLocalSummary *)folder->summary, FALSE, lf->changes, ex) == -1) {
+ camel_object_unref (CAMEL_OBJECT (folder));
+ return NULL;
+ }
+
+ /* TODO: This probably shouldn't be here? */
+ if ((flags & CAMEL_STORE_FOLDER_CREATE) != 0) {
+ url = camel_url_copy (((CamelService *) parent_store)->url);
+ camel_url_set_fragment (url, full_name);
+
+ fi = g_new0 (CamelFolderInfo, 1);
+ fi->full_name = g_strdup (full_name);
+ fi->name = g_strdup (name);
+ fi->uri = camel_url_to_string (url, 0);
+ fi->unread = camel_folder_get_unread_message_count(folder);
+ fi->flags = CAMEL_FOLDER_NOCHILDREN;
+
+ camel_url_free (url);
+
+ camel_object_trigger_event(CAMEL_OBJECT (parent_store), "folder_created", fi);
+ camel_folder_info_free(fi);
+ }
+
+ return lf;
+}
+
+/* lock the folder, may be called repeatedly (with matching unlock calls),
+ with type the same or less than the first call */
+int camel_local_folder_lock(CamelLocalFolder *lf, CamelLockType type, CamelException *ex)
+{
+ if (lf->locked > 0) {
+ /* lets be anal here - its important the code knows what its doing */
+ g_assert(lf->locktype == type || lf->locktype == CAMEL_LOCK_WRITE);
+ } else {
+ if (CLOCALF_CLASS(lf)->lock(lf, type, ex) == -1)
+ return -1;
+ lf->locktype = type;
+ }
+
+ lf->locked++;
+
+ return 0;
+}
+
+/* unlock folder */
+int camel_local_folder_unlock(CamelLocalFolder *lf)
+{
+ g_assert(lf->locked>0);
+ lf->locked--;
+ if (lf->locked == 0)
+ CLOCALF_CLASS(lf)->unlock(lf);
+
+ return 0;
+}
+
+static int
+local_getv(CamelObject *object, CamelException *ex, CamelArgGetV *args)
+{
+ CamelFolder *folder = (CamelFolder *)object;
+ int i;
+ guint32 tag;
+
+ for (i=0;i<args->argc;i++) {
+ CamelArgGet *arg = &args->argv[i];
+
+ tag = arg->tag;
+
+ switch (tag & CAMEL_ARG_TAG) {
+ case CAMEL_OBJECT_ARG_DESCRIPTION:
+ if (folder->description == NULL) {
+ char *tmp, *path;
+
+ /* check some common prefixes to shorten the name */
+ tmp = ((CamelService *)folder->parent_store)->url->path;
+ if (tmp == NULL)
+ goto skip;
+
+ path = g_alloca (strlen (tmp) + strlen (folder->full_name) + 1);
+ sprintf (path, "%s/%s", tmp, folder->full_name);
+
+ if ((tmp = getenv("HOME")) && strncmp(tmp, path, strlen(tmp)) == 0)
+ /* $HOME relative path + protocol string */
+ folder->description = g_strdup_printf(_("~%s (%s)"), path+strlen(tmp),
+ ((CamelService *)folder->parent_store)->url->protocol);
+ else if ((tmp = "/var/spool/mail") && strncmp(tmp, path, strlen(tmp)) == 0)
+ /* /var/spool/mail relative path + protocol */
+ folder->description = g_strdup_printf(_("mailbox:%s (%s)"), path+strlen(tmp),
+ ((CamelService *)folder->parent_store)->url->protocol);
+ else if ((tmp = "/var/mail") && strncmp(tmp, path, strlen(tmp)) == 0)
+ folder->description = g_strdup_printf(_("mailbox:%s (%s)"), path+strlen(tmp),
+ ((CamelService *)folder->parent_store)->url->protocol);
+ else
+ /* a full path + protocol */
+ folder->description = g_strdup_printf(_("%s (%s)"), path,
+ ((CamelService *)folder->parent_store)->url->protocol);
+ }
+ *arg->ca_str = folder->description;
+ break;
+
+ case CAMEL_OBJECT_ARG_PERSISTENT_PROPERTIES:
+ case CAMEL_FOLDER_ARG_PROPERTIES: {
+ CamelArgGetV props;
+
+ props.argc = 1;
+ props.argv[0] = *arg;
+ ((CamelObjectClass *)parent_class)->getv(object, ex, &props);
+ *arg->ca_ptr = g_slist_concat(*arg->ca_ptr, g_slist_copy(local_folder_properties));
+
+ break; }
+
+ case CAMEL_LOCAL_FOLDER_ARG_INDEX_BODY:
+ /* FIXME: remove this from sotre flags */
+ *arg->ca_int = (((CamelLocalFolder *)folder)->flags & CAMEL_STORE_FOLDER_BODY_INDEX) != 0;
+ break;
+
+ default: skip:
+ continue;
+ }
+
+ arg->tag = (tag & CAMEL_ARG_TYPE) | CAMEL_ARG_IGNORE;
+ }
+
+ return ((CamelObjectClass *)parent_class)->getv(object, ex, args);
+}
+
+static int
+local_setv(CamelObject *object, CamelException *ex, CamelArgV *args)
+{
+ int i;
+ guint32 tag;
+
+ for (i=0;i<args->argc;i++) {
+ CamelArg *arg = &args->argv[i];
+
+ tag = arg->tag;
+
+ switch (tag & CAMEL_ARG_TAG) {
+ case CAMEL_LOCAL_FOLDER_ARG_INDEX_BODY:
+ /* FIXME: implement */
+ /* TODO: When turning on (off?) the index, we want to launch a task for it,
+ and make sure we dont have multiple tasks doing the same job */
+ if (arg->ca_int)
+ ((CamelLocalFolder *)object)->flags |= CAMEL_STORE_FOLDER_BODY_INDEX;
+ else
+ ((CamelLocalFolder *)object)->flags &= ~CAMEL_STORE_FOLDER_BODY_INDEX;
+ break;
+ default:
+ continue;
+ }
+
+ arg->tag = (tag & CAMEL_ARG_TYPE) | CAMEL_ARG_IGNORE;
+ }
+
+ return ((CamelObjectClass *)parent_class)->setv(object, ex, args);
+}
+
+static char *
+local_get_full_path(CamelLocalFolder *lf, const char *toplevel_dir, const char *full_name)
+{
+ return g_strdup_printf("%s/%s", toplevel_dir, full_name);
+}
+
+static char *
+local_get_meta_path(CamelLocalFolder *lf, const char *toplevel_dir, const char *full_name, const char *ext)
+{
+ return g_strdup_printf("%s/%s%s", toplevel_dir, full_name, ext);
+}
+
+static int
+local_lock(CamelLocalFolder *lf, CamelLockType type, CamelException *ex)
+{
+ return 0;
+}
+
+static void
+local_unlock(CamelLocalFolder *lf)
+{
+ /* nothing */
+}
+
+/* for auto-check to work */
+static void
+local_refresh_info(CamelFolder *folder, CamelException *ex)
+{
+ CamelLocalFolder *lf = (CamelLocalFolder *)folder;
+
+ if (camel_local_summary_check((CamelLocalSummary *)folder->summary, lf->changes, ex) == -1)
+ return;
+
+ if (camel_folder_change_info_changed(lf->changes)) {
+ camel_object_trigger_event((CamelObject *)folder, "folder_changed", lf->changes);
+ camel_folder_change_info_clear(lf->changes);
+ }
+}
+
+static void
+local_sync(CamelFolder *folder, gboolean expunge, CamelException *ex)
+{
+ CamelLocalFolder *lf = CAMEL_LOCAL_FOLDER(folder);
+
+ d(printf("local sync '%s' , expunge=%s\n", folder->full_name, expunge?"true":"false"));
+
+ if (camel_local_folder_lock(lf, CAMEL_LOCK_WRITE, ex) == -1)
+ return;
+
+ camel_object_state_write(lf);
+
+ /* if sync fails, we'll pass it up on exit through ex */
+ camel_local_summary_sync((CamelLocalSummary *)folder->summary, expunge, lf->changes, ex);
+ camel_local_folder_unlock(lf);
+
+ if (camel_folder_change_info_changed(lf->changes)) {
+ camel_object_trigger_event(CAMEL_OBJECT(folder), "folder_changed", lf->changes);
+ camel_folder_change_info_clear(lf->changes);
+ }
+}
+
+static void
+local_expunge(CamelFolder *folder, CamelException *ex)
+{
+ d(printf("expunge\n"));
+
+ /* Just do a sync with expunge, serves the same purpose */
+ /* call the callback directly, to avoid locking problems */
+ CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(folder))->sync(folder, TRUE, ex);
+}
+
+static void
+local_delete(CamelFolder *folder)
+{
+ CamelLocalFolder *lf = (CamelLocalFolder *)folder;
+
+ if (lf->index)
+ camel_index_delete(lf->index);
+
+ parent_class->delete(folder);
+}
+
+static void
+local_rename(CamelFolder *folder, const char *newname)
+{
+ CamelLocalFolder *lf = (CamelLocalFolder *)folder;
+ char *statepath;
+
+ d(printf("renaming local folder paths to '%s'\n", newname));
+
+ /* Sync? */
+
+ g_free(lf->folder_path);
+ g_free(lf->summary_path);
+ g_free(lf->index_path);
+
+ lf->folder_path = CLOCALF_CLASS(lf)->get_full_path(lf, lf->base_path, newname);
+ lf->summary_path = CLOCALF_CLASS(lf)->get_meta_path(lf, lf->base_path, newname, ".ev-summary");
+ lf->index_path = CLOCALF_CLASS(lf)->get_meta_path(lf, lf->base_path, newname, ".ibex");
+ statepath = CLOCALF_CLASS(lf)->get_meta_path(lf, lf->base_path, newname, ".cmeta");
+ camel_object_set(lf, NULL, CAMEL_OBJECT_STATE_FILE, statepath, NULL);
+ g_free(statepath);
+
+ /* FIXME: Poke some internals, sigh */
+ camel_folder_summary_set_filename(folder->summary, lf->summary_path);
+ g_free(((CamelLocalSummary *)folder->summary)->folder_path);
+ ((CamelLocalSummary *)folder->summary)->folder_path = g_strdup(lf->folder_path);
+
+ parent_class->rename(folder, newname);
+}
+
+static GPtrArray *
+local_search_by_expression(CamelFolder *folder, const char *expression, CamelException *ex)
+{
+ CamelLocalFolder *local_folder = CAMEL_LOCAL_FOLDER(folder);
+ GPtrArray *matches;
+
+ CAMEL_LOCAL_FOLDER_LOCK(folder, search_lock);
+
+ if (local_folder->search == NULL)
+ local_folder->search = camel_folder_search_new();
+
+ camel_folder_search_set_folder(local_folder->search, folder);
+ camel_folder_search_set_body_index(local_folder->search, local_folder->index);
+ matches = camel_folder_search_search(local_folder->search, expression, NULL, ex);
+
+ CAMEL_LOCAL_FOLDER_UNLOCK(folder, search_lock);
+
+ return matches;
+}
+
+static GPtrArray *
+local_search_by_uids(CamelFolder *folder, const char *expression, GPtrArray *uids, CamelException *ex)
+{
+ CamelLocalFolder *local_folder = CAMEL_LOCAL_FOLDER(folder);
+ GPtrArray *matches;
+
+ if (uids->len == 0)
+ return g_ptr_array_new();
+
+ CAMEL_LOCAL_FOLDER_LOCK(folder, search_lock);
+
+ if (local_folder->search == NULL)
+ local_folder->search = camel_folder_search_new();
+
+ camel_folder_search_set_folder(local_folder->search, folder);
+ camel_folder_search_set_body_index(local_folder->search, local_folder->index);
+ matches = camel_folder_search_search(local_folder->search, expression, uids, ex);
+
+ CAMEL_LOCAL_FOLDER_UNLOCK(folder, search_lock);
+
+ return matches;
+}
+
+static void
+local_search_free(CamelFolder *folder, GPtrArray * result)
+{
+ CamelLocalFolder *local_folder = CAMEL_LOCAL_FOLDER(folder);
+
+ /* we need to lock this free because of the way search_free_result works */
+ /* FIXME: put the lock inside search_free_result */
+ CAMEL_LOCAL_FOLDER_LOCK(folder, search_lock);
+
+ camel_folder_search_free_result(local_folder->search, result);
+
+ CAMEL_LOCAL_FOLDER_UNLOCK(folder, search_lock);
+}
diff --git a/camel/providers/local/camel-local-folder.h b/camel/providers/local/camel-local-folder.h
new file mode 100644
index 0000000000..4aec420813
--- /dev/null
+++ b/camel/providers/local/camel-local-folder.h
@@ -0,0 +1,109 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Author: Michael Zucchi <notzed@ximian.com>
+ *
+ * Copyright (C) 1999 Ximian (www.ximian.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#ifndef CAMEL_LOCAL_FOLDER_H
+#define CAMEL_LOCAL_FOLDER_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif /* __cplusplus }*/
+
+#include <camel/camel-folder.h>
+#include <camel/camel-folder-search.h>
+#include <camel/camel-index.h>
+#include "camel-local-summary.h"
+#include "camel-lock.h"
+
+/* #include "camel-store.h" */
+
+#define CAMEL_LOCAL_FOLDER_TYPE (camel_local_folder_get_type ())
+#define CAMEL_LOCAL_FOLDER(obj) (CAMEL_CHECK_CAST((obj), CAMEL_LOCAL_FOLDER_TYPE, CamelLocalFolder))
+#define CAMEL_LOCAL_FOLDER_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), CAMEL_LOCAL_FOLDER_TYPE, CamelLocalFolderClass))
+#define CAMEL_IS_LOCAL_FOLDER(o) (CAMEL_CHECK_TYPE((o), CAMEL_LOCAL_FOLDER_TYPE))
+
+enum {
+ CAMEL_LOCAL_FOLDER_ARG_INDEX_BODY = CAMEL_FOLDER_ARG_LAST,
+
+ CAMEL_LOCAL_FOLDER_ARG_LAST = CAMEL_FOLDER_ARG_LAST + 0x100
+};
+
+enum {
+ CAMEL_LOCAL_FOLDER_INDEX_BODY = CAMEL_LOCAL_FOLDER_ARG_INDEX_BODY | CAMEL_ARG_BOO,
+};
+
+typedef struct {
+ CamelFolder parent_object;
+ struct _CamelLocalFolderPrivate *priv;
+
+ guint32 flags; /* open mode flags */
+
+ int locked; /* lock counter */
+ CamelLockType locktype; /* what type of lock we have */
+
+ char *base_path; /* base path of the local folder */
+ char *folder_path; /* the path to the folder itself */
+ char *summary_path; /* where the summary lives */
+ char *index_path; /* where the index file lives */
+
+ CamelIndex *index; /* index for this folder */
+ CamelFolderSearch *search; /* used to run searches, we just use the real thing (tm) */
+ CamelFolderChangeInfo *changes; /* used to store changes to the folder during processing */
+} CamelLocalFolder;
+
+typedef struct {
+ CamelFolderClass parent_class;
+
+ /* Virtual methods */
+
+ /* path construction, only used at init */
+ char * (* get_full_path)(CamelLocalFolder *lf, const char *toplevel_dir, const char *full_name);
+ char * (* get_meta_path)(CamelLocalFolder *lf, const char *toplevel_dir, const char *full_name, const char *ext);
+
+ /* summary factory, only used at init */
+ CamelLocalSummary *(*create_summary)(CamelLocalFolder *lf, const char *path, const char *folder, CamelIndex *index);
+
+ /* Lock the folder for my operations */
+ int (*lock)(CamelLocalFolder *, CamelLockType type, CamelException *ex);
+
+ /* Unlock the folder for my operations */
+ void (*unlock)(CamelLocalFolder *);
+} CamelLocalFolderClass;
+
+
+/* public methods */
+/* flags are taken from CAMEL_STORE_FOLDER_* flags */
+CamelLocalFolder *camel_local_folder_construct(CamelLocalFolder *lf, CamelStore *parent_store,
+ const char *full_name, guint32 flags, CamelException *ex);
+
+/* Standard Camel function */
+CamelType camel_local_folder_get_type(void);
+
+/* Lock the folder for internal use. May be called repeatedly */
+/* UNIMPLEMENTED */
+int camel_local_folder_lock(CamelLocalFolder *lf, CamelLockType type, CamelException *ex);
+int camel_local_folder_unlock(CamelLocalFolder *lf);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* CAMEL_LOCAL_FOLDER_H */
diff --git a/camel/providers/local/camel-maildir-folder.c b/camel/providers/local/camel-maildir-folder.c
new file mode 100644
index 0000000000..ba42b75f28
--- /dev/null
+++ b/camel/providers/local/camel-maildir-folder.c
@@ -0,0 +1,278 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; fill-column: 160 -*-
+ *
+ * Authors: Michael Zucchi <notzed@ximian.com>
+ *
+ * Copyright (C) 1999, 2003 Ximian Inc.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include "camel-maildir-folder.h"
+#include "camel-maildir-store.h"
+#include "camel-stream-fs.h"
+#include "camel-maildir-summary.h"
+#include "camel-data-wrapper.h"
+#include "camel-mime-message.h"
+#include "camel-exception.h"
+
+#define d(x) /*(printf("%s(%d): ", __FILE__, __LINE__),(x))*/
+
+static CamelLocalFolderClass *parent_class = NULL;
+
+/* Returns the class for a CamelMaildirFolder */
+#define CMAILDIRF_CLASS(so) CAMEL_MAILDIR_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so))
+#define CF_CLASS(so) CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so))
+#define CMAILDIRS_CLASS(so) CAMEL_STORE_CLASS (CAMEL_OBJECT_GET_CLASS(so))
+
+static CamelLocalSummary *maildir_create_summary(CamelLocalFolder *lf, const char *path, const char *folder, CamelIndex *index);
+
+static void maildir_append_message(CamelFolder * folder, CamelMimeMessage * message, const CamelMessageInfo *info, char **appended_uid, CamelException * ex);
+static CamelMimeMessage *maildir_get_message(CamelFolder * folder, const gchar * uid, CamelException * ex);
+
+static void maildir_finalize(CamelObject * object);
+
+static int
+maildir_folder_getv(CamelObject *object, CamelException *ex, CamelArgGetV *args)
+{
+ CamelFolder *folder = (CamelFolder *)object;
+ int i;
+ guint32 tag;
+
+ for (i=0;i<args->argc;i++) {
+ CamelArgGet *arg = &args->argv[i];
+
+ tag = arg->tag;
+
+ switch (tag & CAMEL_ARG_TAG) {
+ case CAMEL_FOLDER_ARG_NAME:
+ if (!strcmp(folder->full_name, "."))
+ *arg->ca_str = _("Inbox");
+ else
+ *arg->ca_str = folder->name;
+ break;
+ default:
+ continue;
+ }
+
+ arg->tag = (tag & CAMEL_ARG_TYPE) | CAMEL_ARG_IGNORE;
+ }
+
+ return ((CamelObjectClass *)parent_class)->getv(object, ex, args);
+}
+
+static void camel_maildir_folder_class_init(CamelObjectClass * camel_maildir_folder_class)
+{
+ CamelFolderClass *camel_folder_class = CAMEL_FOLDER_CLASS(camel_maildir_folder_class);
+ CamelLocalFolderClass *lclass = (CamelLocalFolderClass *)camel_maildir_folder_class;
+
+ parent_class = CAMEL_LOCAL_FOLDER_CLASS (camel_type_get_global_classfuncs(camel_local_folder_get_type()));
+
+ /* virtual method definition */
+
+ /* virtual method overload */
+ ((CamelObjectClass *)camel_folder_class)->getv = maildir_folder_getv;
+
+ camel_folder_class->append_message = maildir_append_message;
+ camel_folder_class->get_message = maildir_get_message;
+
+ lclass->create_summary = maildir_create_summary;
+}
+
+static void maildir_init(gpointer object, gpointer klass)
+{
+ /*CamelFolder *folder = object;
+ CamelMaildirFolder *maildir_folder = object;*/
+}
+
+static void maildir_finalize(CamelObject * object)
+{
+ /*CamelMaildirFolder *maildir_folder = CAMEL_MAILDIR_FOLDER(object);*/
+}
+
+CamelType camel_maildir_folder_get_type(void)
+{
+ static CamelType camel_maildir_folder_type = CAMEL_INVALID_TYPE;
+
+ if (camel_maildir_folder_type == CAMEL_INVALID_TYPE) {
+ camel_maildir_folder_type = camel_type_register(CAMEL_LOCAL_FOLDER_TYPE, "CamelMaildirFolder",
+ sizeof(CamelMaildirFolder),
+ sizeof(CamelMaildirFolderClass),
+ (CamelObjectClassInitFunc) camel_maildir_folder_class_init,
+ NULL,
+ (CamelObjectInitFunc) maildir_init,
+ (CamelObjectFinalizeFunc) maildir_finalize);
+ }
+
+ return camel_maildir_folder_type;
+}
+
+CamelFolder *
+camel_maildir_folder_new(CamelStore *parent_store, const char *full_name, guint32 flags, CamelException *ex)
+{
+ CamelFolder *folder;
+
+ d(printf("Creating maildir folder: %s\n", full_name));
+
+ folder = (CamelFolder *)camel_object_new(CAMEL_MAILDIR_FOLDER_TYPE);
+
+ if (parent_store->flags & CAMEL_STORE_FILTER_INBOX
+ && strcmp(full_name, ".") == 0)
+ folder->folder_flags |= CAMEL_FOLDER_FILTER_RECENT;
+
+ folder = (CamelFolder *)camel_local_folder_construct((CamelLocalFolder *)folder,
+ parent_store, full_name, flags, ex);
+
+ return folder;
+}
+
+static CamelLocalSummary *maildir_create_summary(CamelLocalFolder *lf, const char *path, const char *folder, CamelIndex *index)
+{
+ return (CamelLocalSummary *)camel_maildir_summary_new(path, folder, index);
+}
+
+static void
+maildir_append_message (CamelFolder *folder, CamelMimeMessage *message, const CamelMessageInfo *info, char **appended_uid, CamelException *ex)
+{
+ CamelMaildirFolder *maildir_folder = (CamelMaildirFolder *)folder;
+ CamelLocalFolder *lf = (CamelLocalFolder *)folder;
+ CamelStream *output_stream;
+ CamelMessageInfo *mi;
+ CamelMaildirMessageInfo *mdi;
+ char *name, *dest = NULL;
+
+ d(printf("Appending message\n"));
+
+ /* add it to the summary/assign the uid, etc */
+ mi = camel_local_summary_add((CamelLocalSummary *)folder->summary, message, info, lf->changes, ex);
+ if (camel_exception_is_set (ex))
+ return;
+
+ mdi = (CamelMaildirMessageInfo *)mi;
+
+ d(printf("Appending message: uid is %s filename is %s\n", camel_message_info_uid(mi), mdi->filename));
+
+ /* write it out to tmp, use the uid we got from the summary */
+ name = g_strdup_printf ("%s/tmp/%s", lf->folder_path, camel_message_info_uid(mi));
+ output_stream = camel_stream_fs_new_with_name (name, O_WRONLY|O_CREAT, 0600);
+ if (output_stream == NULL)
+ goto fail_write;
+
+ if (camel_data_wrapper_write_to_stream ((CamelDataWrapper *)message, output_stream) == -1
+ || camel_stream_close (output_stream) == -1)
+ goto fail_write;
+
+ /* now move from tmp to cur (bypass new, does it matter?) */
+ dest = g_strdup_printf("%s/cur/%s", lf->folder_path, camel_maildir_info_filename (mdi));
+ if (rename (name, dest) == 1)
+ goto fail_write;
+
+ g_free (dest);
+ g_free (name);
+
+ camel_object_trigger_event (CAMEL_OBJECT (folder), "folder_changed",
+ ((CamelLocalFolder *)maildir_folder)->changes);
+ camel_folder_change_info_clear (((CamelLocalFolder *)maildir_folder)->changes);
+
+ if (appended_uid)
+ *appended_uid = g_strdup(camel_message_info_uid(mi));
+
+ return;
+
+ fail_write:
+
+ /* remove the summary info so we are not out-of-sync with the mh folder */
+ camel_folder_summary_remove_uid (CAMEL_FOLDER_SUMMARY (folder->summary),
+ camel_message_info_uid (mi));
+
+ if (errno == EINTR)
+ camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL,
+ _("Maildir append message cancelled"));
+ else
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot append message to maildir folder: %s: %s"),
+ name, g_strerror (errno));
+
+ if (output_stream) {
+ camel_object_unref (CAMEL_OBJECT (output_stream));
+ unlink (name);
+ }
+
+ g_free (name);
+ g_free (dest);
+}
+
+static CamelMimeMessage *maildir_get_message(CamelFolder * folder, const gchar * uid, CamelException * ex)
+{
+ CamelLocalFolder *lf = (CamelLocalFolder *)folder;
+ CamelStream *message_stream = NULL;
+ CamelMimeMessage *message = NULL;
+ CamelMessageInfo *info;
+ char *name;
+ CamelMaildirMessageInfo *mdi;
+
+ d(printf("getting message: %s\n", uid));
+
+ /* get the message summary info */
+ if ((info = camel_folder_summary_uid(folder->summary, uid)) == NULL) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_FOLDER_INVALID_UID,
+ _("Cannot get message: %s from folder %s\n %s"),
+ uid, lf->folder_path, _("No such message"));
+ return NULL;
+ }
+
+ mdi = (CamelMaildirMessageInfo *)info;
+
+ /* what do we do if the message flags (and :info data) changes? filename mismatch - need to recheck I guess */
+ name = g_strdup_printf("%s/cur/%s", lf->folder_path, camel_maildir_info_filename(mdi));
+
+ camel_folder_summary_info_free(folder->summary, info);
+
+ if ((message_stream = camel_stream_fs_new_with_name(name, O_RDONLY, 0)) == NULL) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot get message: %s from folder %s\n %s"),
+ uid, lf->folder_path, g_strerror(errno));
+ g_free(name);
+ return NULL;
+ }
+
+ message = camel_mime_message_new();
+ if (camel_data_wrapper_construct_from_stream((CamelDataWrapper *)message, message_stream) == -1) {
+ camel_exception_setv(ex, (errno==EINTR)?CAMEL_EXCEPTION_USER_CANCEL:CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot get message: %s from folder %s\n %s"),
+ uid, lf->folder_path, _("Invalid message contents"));
+ g_free(name);
+ camel_object_unref((CamelObject *)message_stream);
+ camel_object_unref((CamelObject *)message);
+ return NULL;
+
+ }
+ camel_object_unref((CamelObject *)message_stream);
+ g_free(name);
+
+ return message;
+}
diff --git a/camel/providers/local/camel-maildir-store.c b/camel/providers/local/camel-maildir-store.c
new file mode 100644
index 0000000000..21ad98694f
--- /dev/null
+++ b/camel/providers/local/camel-maildir-store.c
@@ -0,0 +1,544 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2000 Ximian, Inc.
+ *
+ * Authors: Michael Zucchi <notzed@ximian.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <dirent.h>
+
+#include "camel-maildir-store.h"
+#include "camel-maildir-folder.h"
+#include "camel-exception.h"
+#include "camel-url.h"
+#include "camel-private.h"
+#include "camel-maildir-summary.h"
+
+#define d(x)
+
+static CamelLocalStoreClass *parent_class = NULL;
+
+/* Returns the class for a CamelMaildirStore */
+#define CMAILDIRS_CLASS(so) CAMEL_MAILDIR_STORE_CLASS (CAMEL_OBJECT_GET_CLASS(so))
+#define CF_CLASS(so) CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so))
+#define CMAILDIRF_CLASS(so) CAMEL_MAILDIR_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so))
+
+static CamelFolder *get_folder(CamelStore * store, const char *folder_name, guint32 flags, CamelException * ex);
+static CamelFolder *get_inbox (CamelStore *store, CamelException *ex);
+static void delete_folder(CamelStore * store, const char *folder_name, CamelException * ex);
+static void maildir_rename_folder(CamelStore *store, const char *old, const char *new, CamelException *ex);
+
+static CamelFolderInfo * get_folder_info (CamelStore *store, const char *top, guint32 flags, CamelException *ex);
+
+static gboolean maildir_compare_folder_name(const void *a, const void *b);
+static guint maildir_hash_folder_name(const void *a);
+
+static void camel_maildir_store_class_init(CamelObjectClass * camel_maildir_store_class)
+{
+ CamelStoreClass *camel_store_class = CAMEL_STORE_CLASS(camel_maildir_store_class);
+ /*CamelServiceClass *camel_service_class = CAMEL_SERVICE_CLASS(camel_maildir_store_class);*/
+
+ parent_class = (CamelLocalStoreClass *)camel_type_get_global_classfuncs(camel_local_store_get_type());
+
+ /* virtual method overload, use defaults for most */
+ camel_store_class->hash_folder_name = maildir_hash_folder_name;
+ camel_store_class->compare_folder_name = maildir_compare_folder_name;
+ camel_store_class->get_folder = get_folder;
+ camel_store_class->get_inbox = get_inbox;
+ camel_store_class->delete_folder = delete_folder;
+ camel_store_class->rename_folder = maildir_rename_folder;
+
+ camel_store_class->get_folder_info = get_folder_info;
+ camel_store_class->free_folder_info = camel_store_free_folder_info_full;
+}
+
+CamelType camel_maildir_store_get_type(void)
+{
+ static CamelType camel_maildir_store_type = CAMEL_INVALID_TYPE;
+
+ if (camel_maildir_store_type == CAMEL_INVALID_TYPE) {
+ camel_maildir_store_type = camel_type_register(CAMEL_LOCAL_STORE_TYPE, "CamelMaildirStore",
+ sizeof(CamelMaildirStore),
+ sizeof(CamelMaildirStoreClass),
+ (CamelObjectClassInitFunc) camel_maildir_store_class_init,
+ NULL,
+ NULL,
+ NULL);
+ }
+
+ return camel_maildir_store_type;
+}
+
+/* This fixes up some historical cruft of names starting with "./" */
+static const char *
+md_canon_name(const char *a)
+{
+ if (a != NULL) {
+ if (a[0] == '/')
+ a++;
+ if (a[0] == '.' && a[1] == '/')
+ a+=2;
+ }
+ return a;
+}
+
+static guint maildir_hash_folder_name(const void *a)
+{
+ return g_str_hash(md_canon_name(a));
+}
+
+static gboolean maildir_compare_folder_name(const void *a, const void *b)
+{
+ return g_str_equal(md_canon_name(a), md_canon_name(b));
+}
+
+static CamelFolder *
+get_folder(CamelStore * store, const char *folder_name, guint32 flags, CamelException * ex)
+{
+ char *name, *tmp, *cur, *new;
+ struct stat st;
+ CamelFolder *folder = NULL;
+
+ folder_name = md_canon_name(folder_name);
+
+ if (!((CamelStoreClass *)parent_class)->get_folder(store, folder_name, flags, ex))
+ return NULL;
+
+ name = g_strdup_printf("%s%s", CAMEL_LOCAL_STORE(store)->toplevel_dir, folder_name);
+ tmp = g_strdup_printf("%s/tmp", name);
+ cur = g_strdup_printf("%s/cur", name);
+ new = g_strdup_printf("%s/new", name);
+
+ if (!strcmp(folder_name, ".")) {
+ /* special case "." (aka inbox), may need to be created */
+ if (stat(tmp, &st) != 0 || !S_ISDIR(st.st_mode)
+ || stat(cur, &st) != 0 || !S_ISDIR(st.st_mode)
+ || stat(new, &st) != 0 || !S_ISDIR(st.st_mode)) {
+ if (mkdir(tmp, 0700) != 0
+ || mkdir(cur, 0700) != 0
+ || mkdir(new, 0700) != 0) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot create folder `%s': %s"),
+ folder_name, g_strerror(errno));
+ rmdir(tmp);
+ rmdir(cur);
+ rmdir(new);
+ goto fail;
+ }
+ }
+ folder = camel_maildir_folder_new(store, folder_name, flags, ex);
+ } else if (stat(name, &st) == -1) {
+ /* folder doesn't exist, see if we should create it */
+ if (errno != ENOENT) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot get folder `%s': %s"),
+ folder_name, g_strerror (errno));
+ } else if ((flags & CAMEL_STORE_FOLDER_CREATE) == 0) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_STORE_NO_FOLDER,
+ _("Cannot get folder `%s': folder does not exist."),
+ folder_name);
+ } else {
+ if (mkdir(name, 0700) != 0
+ || mkdir(tmp, 0700) != 0
+ || mkdir(cur, 0700) != 0
+ || mkdir(new, 0700) != 0) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot create folder `%s': %s"),
+ folder_name, g_strerror (errno));
+ rmdir(tmp);
+ rmdir(cur);
+ rmdir(new);
+ rmdir(name);
+ } else {
+ folder = camel_maildir_folder_new(store, folder_name, flags, ex);
+ }
+ }
+ } else if (!S_ISDIR(st.st_mode)
+ || stat(tmp, &st) != 0 || !S_ISDIR(st.st_mode)
+ || stat(cur, &st) != 0 || !S_ISDIR(st.st_mode)
+ || stat(new, &st) != 0 || !S_ISDIR(st.st_mode)) {
+ /* folder exists, but not maildir */
+ camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot get folder `%s': not a maildir directory."), name);
+ } else if (flags & CAMEL_STORE_FOLDER_EXCL) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot create folder `%s': folder exists."),
+ folder_name);
+ } else {
+ folder = camel_maildir_folder_new(store, folder_name, flags, ex);
+ }
+fail:
+ g_free(name);
+ g_free(tmp);
+ g_free(cur);
+ g_free(new);
+
+ return folder;
+}
+
+static CamelFolder *
+get_inbox (CamelStore *store, CamelException *ex)
+{
+ return camel_store_get_folder(store, ".", CAMEL_STORE_FOLDER_CREATE, ex);
+}
+
+static void delete_folder(CamelStore * store, const char *folder_name, CamelException * ex)
+{
+ char *name, *tmp, *cur, *new;
+ struct stat st;
+
+ if (strcmp(folder_name, ".") == 0) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER,
+ _("Cannot delete folder: %s: Invalid operation"), _("Inbox"));
+ return;
+ }
+
+ name = g_strdup_printf("%s%s", CAMEL_LOCAL_STORE(store)->toplevel_dir, folder_name);
+
+ tmp = g_strdup_printf("%s/tmp", name);
+ cur = g_strdup_printf("%s/cur", name);
+ new = g_strdup_printf("%s/new", name);
+
+ if (stat(name, &st) == -1 || !S_ISDIR(st.st_mode)
+ || stat(tmp, &st) == -1 || !S_ISDIR(st.st_mode)
+ || stat(cur, &st) == -1 || !S_ISDIR(st.st_mode)
+ || stat(new, &st) == -1 || !S_ISDIR(st.st_mode)) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Could not delete folder `%s': %s"),
+ folder_name, errno ? g_strerror (errno) :
+ _("not a maildir directory"));
+ } else {
+ int err = 0;
+
+ /* remove subdirs first - will fail if not empty */
+ if (rmdir(cur) == -1 || rmdir(new) == -1) {
+ err = errno;
+ } else {
+ DIR *dir;
+ struct dirent *d;
+
+ /* for tmp (only), its contents is irrelevant */
+ dir = opendir(tmp);
+ if (dir) {
+ while ( (d=readdir(dir)) ) {
+ char *name = d->d_name, *file;
+
+ if (!strcmp(name, ".") || !strcmp(name, ".."))
+ continue;
+ file = g_strdup_printf("%s/%s", tmp, name);
+ unlink(file);
+ g_free(file);
+ }
+ closedir(dir);
+ }
+ if (rmdir(tmp) == -1 || rmdir(name) == -1)
+ err = errno;
+ }
+
+ if (err != 0) {
+ /* easier just to mkdir all (and let them fail), than remember what we got to */
+ mkdir(name, 0700);
+ mkdir(cur, 0700);
+ mkdir(new, 0700);
+ mkdir(tmp, 0700);
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Could not delete folder `%s': %s"),
+ folder_name, g_strerror (err));
+ } else {
+ /* and remove metadata */
+ ((CamelStoreClass *)parent_class)->delete_folder(store, folder_name, ex);
+ }
+ }
+
+ g_free(name);
+ g_free(tmp);
+ g_free(cur);
+ g_free(new);
+}
+
+static void
+maildir_rename_folder(CamelStore *store, const char *old, const char *new, CamelException *ex)
+{
+ if (strcmp(old, ".") == 0) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER,
+ _("Cannot rename folder: %s: Invalid operation"), _("Inbox"));
+ return;
+ }
+
+ ((CamelStoreClass *)parent_class)->rename_folder(store, old, new, ex);
+}
+
+static void
+fill_fi(CamelStore *store, CamelFolderInfo *fi, guint32 flags)
+{
+ CamelFolder *folder;
+
+ folder = camel_object_bag_get(store->folders, fi->full_name);
+
+ if (folder == NULL
+ && (flags & CAMEL_STORE_FOLDER_INFO_FAST) == 0)
+ folder = camel_store_get_folder(store, fi->full_name, 0, NULL);
+
+ if (folder) {
+ if ((flags & CAMEL_STORE_FOLDER_INFO_FAST) == 0)
+ camel_folder_refresh_info(folder, NULL);
+ fi->unread = camel_folder_get_unread_message_count(folder);
+ fi->total = camel_folder_get_message_count(folder);
+ camel_object_unref(folder);
+ } else {
+ char *path, *folderpath;
+ CamelFolderSummary *s;
+ const char *root;
+
+ /* This should be fast enough not to have to test for INFO_FAST */
+ root = camel_local_store_get_toplevel_dir((CamelLocalStore *)store);
+ path = g_strdup_printf("%s/%s.ev-summary", root, fi->full_name);
+ folderpath = g_strdup_printf("%s/%s", root, fi->full_name);
+ s = (CamelFolderSummary *)camel_maildir_summary_new(path, folderpath, NULL);
+ if (camel_folder_summary_header_load(s) != -1) {
+ fi->unread = s->unread_count;
+ fi->total = s->saved_count;
+ }
+ camel_object_unref(s);
+ g_free(folderpath);
+ g_free(path);
+ }
+}
+
+struct _scan_node {
+ struct _scan_node *next;
+ struct _scan_node *prev;
+
+ CamelFolderInfo *fi;
+
+ dev_t dnode;
+ ino_t inode;
+};
+
+static guint scan_hash(const void *d)
+{
+ const struct _scan_node *v = d;
+
+ return v->inode ^ v->dnode;
+}
+
+static gboolean scan_equal(const void *a, const void *b)
+{
+ const struct _scan_node *v1 = a, *v2 = b;
+
+ return v1->inode == v2->inode && v1->dnode == v2->dnode;
+}
+
+static void scan_free(void *k, void *v, void *d)
+{
+ g_free(k);
+}
+
+static CamelFolderInfo *scan_fi(CamelStore *store, guint32 flags, CamelURL *url, const char *full, const char *name)
+{
+ CamelFolderInfo *fi;
+ char *tmp, *cur, *new;
+ struct stat st;
+
+ fi = g_malloc0(sizeof(*fi));
+ fi->full_name = g_strdup(full);
+ fi->name = g_strdup(name);
+ camel_url_set_fragment(url, fi->full_name);
+ fi->uri = camel_url_to_string(url, 0);
+ fi->unread = -1;
+ fi->total = -1;
+ /* we only calculate nochildren properly if we're recursive */
+ if (((flags & CAMEL_STORE_FOLDER_INFO_RECURSIVE) != 0))
+ fi->flags = CAMEL_FOLDER_NOCHILDREN;
+
+ d(printf("Adding maildir info: '%s' '%s' '%s'\n", fi->name, fi->full_name, fi->uri));
+
+ tmp = g_build_filename(url->path, fi->full_name, "tmp", NULL);
+ cur = g_build_filename(url->path, fi->full_name, "cur", NULL);
+ new = g_build_filename(url->path, fi->full_name, "new", NULL);
+
+ if (!(stat(tmp, &st) == 0 && S_ISDIR(st.st_mode)
+ && stat(cur, &st) == 0 && S_ISDIR(st.st_mode)
+ && stat(new, &st) == 0 && S_ISDIR(st.st_mode)))
+ fi->flags |= CAMEL_FOLDER_NOSELECT;
+
+ g_free(new);
+ g_free(cur);
+ g_free(tmp);
+
+ fill_fi(store, fi, flags);
+
+ return fi;
+}
+
+static int
+scan_dirs(CamelStore *store, guint32 flags, CamelFolderInfo *topfi, CamelURL *url, CamelException *ex)
+{
+ EDList queue = E_DLIST_INITIALISER(queue);
+ struct _scan_node *sn;
+ const char *root = ((CamelService *)store)->url->path;
+ char *tmp;
+ GHashTable *visited;
+ struct stat st;
+ int res = -1;
+
+ visited = g_hash_table_new(scan_hash, scan_equal);
+
+ sn = g_malloc0(sizeof(*sn));
+ sn->fi = topfi;
+ e_dlist_addtail(&queue, (EDListNode *)sn);
+ g_hash_table_insert(visited, sn, sn);
+
+ while (!e_dlist_empty(&queue)) {
+ char *name;
+ DIR *dir;
+ struct dirent *d;
+ CamelFolderInfo *last;
+
+ sn = (struct _scan_node *)e_dlist_remhead(&queue);
+
+ last = (CamelFolderInfo *)&sn->fi->child;
+
+ if (!strcmp(sn->fi->full_name, "."))
+ name = g_strdup(root);
+ else
+ name = g_build_filename(root, sn->fi->full_name, NULL);
+
+ dir = opendir(name);
+ if (dir == NULL) {
+ g_free(name);
+ camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Could not scan folder `%s': %s"),
+ root, g_strerror(errno));
+ goto fail;
+ }
+
+ while ( (d = readdir(dir)) ) {
+ if (strcmp(d->d_name, "tmp") == 0
+ || strcmp(d->d_name, "cur") == 0
+ || strcmp(d->d_name, "new") == 0
+ || strcmp(d->d_name, ".") == 0
+ || strcmp(d->d_name, "..") == 0)
+ continue;
+
+ tmp = g_build_filename(name, d->d_name, NULL);
+ if (stat(tmp, &st) == 0 && S_ISDIR(st.st_mode)) {
+ struct _scan_node in;
+
+ in.dnode = st.st_dev;
+ in.inode = st.st_ino;
+
+ /* see if we've visited already */
+ if (g_hash_table_lookup(visited, &in) == NULL) {
+ struct _scan_node *snew = g_malloc(sizeof(*snew));
+ char *full;
+
+ snew->dnode = in.dnode;
+ snew->inode = in.inode;
+
+ if (!strcmp(sn->fi->full_name, "."))
+ full = g_strdup(d->d_name);
+ else
+ full = g_strdup_printf("%s/%s", sn->fi->full_name, d->d_name);
+ snew->fi = scan_fi(store, flags, url, full, d->d_name);
+ g_free(full);
+
+ last->next = snew->fi;
+ last = snew->fi;
+ snew->fi->parent = sn->fi;
+
+ sn->fi->flags &= ~CAMEL_FOLDER_NOCHILDREN;
+ sn->fi->flags |= CAMEL_FOLDER_CHILDREN;
+
+ g_hash_table_insert(visited, snew, snew);
+
+ if (((flags & CAMEL_STORE_FOLDER_INFO_RECURSIVE) != 0))
+ e_dlist_addtail(&queue, (EDListNode *)snew);
+ }
+ }
+ g_free(tmp);
+ }
+ closedir(dir);
+ }
+
+ res = 0;
+fail:
+ g_hash_table_foreach(visited, scan_free, NULL);
+ g_hash_table_destroy(visited);
+
+ return res;
+}
+
+static CamelFolderInfo *
+get_folder_info (CamelStore *store, const char *top, guint32 flags, CamelException *ex)
+{
+ CamelFolderInfo *fi = NULL;
+ CamelLocalStore *local_store = (CamelLocalStore *)store;
+ CamelURL *url;
+
+ url = camel_url_new("maildir:", NULL);
+ camel_url_set_path(url, ((CamelService *)local_store)->url->path);
+
+ if (top == NULL || top[0] == 0) {
+ CamelFolderInfo *scan;
+
+ /* create a dummy "." parent inbox, use to scan, then put back at the top level */
+ fi = scan_fi(store, flags, url, ".", _("Inbox"));
+ if (scan_dirs(store, flags, fi, url, ex) == -1)
+ goto fail;
+ fi->next = fi->child;
+ scan = fi->child;
+ fi->child = NULL;
+ while (scan) {
+ scan->parent = NULL;
+ scan = scan->next;
+ }
+ fi->flags &= ~CAMEL_FOLDER_CHILDREN;
+ fi->flags |= CAMEL_FOLDER_SYSTEM|CAMEL_FOLDER_NOCHILDREN|CAMEL_FOLDER_NOINFERIORS;
+ } else if (!strcmp(top, ".")) {
+ fi = scan_fi(store, flags, url, ".", _("Inbox"));
+ fi->flags |= CAMEL_FOLDER_SYSTEM|CAMEL_FOLDER_NOCHILDREN|CAMEL_FOLDER_NOINFERIORS;
+ } else {
+ const char *name = strrchr(top, '/');
+
+ fi = scan_fi(store, flags, url, top, name?name+1:top);
+ if (scan_dirs(store, flags, fi, url, ex) == -1)
+ goto fail;
+ }
+
+ camel_url_free(url);
+
+ return fi;
+
+fail:
+ if (fi)
+ camel_store_free_folder_info_full(store, fi);
+
+ camel_url_free(url);
+
+ return NULL;
+}
diff --git a/camel/providers/local/camel-mbox-folder.c b/camel/providers/local/camel-mbox-folder.c
new file mode 100644
index 0000000000..fa8f0b645d
--- /dev/null
+++ b/camel/providers/local/camel-mbox-folder.c
@@ -0,0 +1,557 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; fill-column: 160 -*-
+ *
+ * Authors: Michael Zucchi <notzed@ximian.com>
+ * Jeffrey Stedfast <fejj@ximian.com>
+ *
+ * Copyright (C) 1999, 2003 Ximian Inc.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include "camel-mbox-folder.h"
+#include "camel-mbox-store.h"
+#include "camel-stream-fs.h"
+#include "camel-mbox-summary.h"
+#include "camel-data-wrapper.h"
+#include "camel-mime-message.h"
+#include "camel-stream-filter.h"
+#include "camel-mime-filter-from.h"
+#include "camel-exception.h"
+
+#define d(x) /*(printf("%s(%d): ", __FILE__, __LINE__),(x))*/
+
+static CamelLocalFolderClass *parent_class = NULL;
+
+/* Returns the class for a CamelMboxFolder */
+#define CMBOXF_CLASS(so) CAMEL_MBOX_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so))
+#define CF_CLASS(so) CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so))
+#define CMBOXS_CLASS(so) CAMEL_STORE_CLASS (CAMEL_OBJECT_GET_CLASS(so))
+
+static int mbox_lock(CamelLocalFolder *lf, CamelLockType type, CamelException *ex);
+static void mbox_unlock(CamelLocalFolder *lf);
+
+#ifdef STATUS_PINE
+static gboolean mbox_set_message_flags(CamelFolder *folder, const char *uid, guint32 flags, guint32 set);
+#endif
+
+static void mbox_set_message_user_flag(CamelFolder *folder, const char *uid, const char *name, gboolean value);
+static void mbox_set_message_user_tag(CamelFolder *folder, const char *uid, const char *name, const char *value);
+
+static void mbox_append_message(CamelFolder *folder, CamelMimeMessage * message, const CamelMessageInfo * info, char **appended_uid, CamelException *ex);
+static CamelMimeMessage *mbox_get_message(CamelFolder *folder, const gchar * uid, CamelException *ex);
+static CamelLocalSummary *mbox_create_summary(CamelLocalFolder *lf, const char *path, const char *folder, CamelIndex *index);
+
+static void mbox_finalise(CamelObject * object);
+
+static void
+camel_mbox_folder_class_init(CamelMboxFolderClass * camel_mbox_folder_class)
+{
+ CamelFolderClass *camel_folder_class = CAMEL_FOLDER_CLASS(camel_mbox_folder_class);
+ CamelLocalFolderClass *lclass = (CamelLocalFolderClass *)camel_mbox_folder_class;
+
+ parent_class = (CamelLocalFolderClass *)camel_type_get_global_classfuncs(camel_local_folder_get_type());
+
+ /* virtual method definition */
+
+ /* virtual method overload */
+ camel_folder_class->append_message = mbox_append_message;
+ camel_folder_class->get_message = mbox_get_message;
+
+#ifdef STATUS_PINE
+ camel_folder_class->set_message_flags = mbox_set_message_flags;
+#endif
+ camel_folder_class->set_message_user_flag = mbox_set_message_user_flag;
+ camel_folder_class->set_message_user_tag = mbox_set_message_user_tag;
+
+ lclass->get_full_path = camel_mbox_folder_get_full_path;
+ lclass->get_meta_path = camel_mbox_folder_get_meta_path;
+ lclass->create_summary = mbox_create_summary;
+ lclass->lock = mbox_lock;
+ lclass->unlock = mbox_unlock;
+}
+
+static void
+mbox_init(gpointer object, gpointer klass)
+{
+ /*CamelFolder *folder = object;*/
+ CamelMboxFolder *mbox_folder = object;
+
+ mbox_folder->lockfd = -1;
+}
+
+static void
+mbox_finalise(CamelObject * object)
+{
+ CamelMboxFolder *mbox_folder = (CamelMboxFolder *)object;
+
+ g_assert(mbox_folder->lockfd == -1);
+}
+
+CamelType camel_mbox_folder_get_type(void)
+{
+ static CamelType camel_mbox_folder_type = CAMEL_INVALID_TYPE;
+
+ if (camel_mbox_folder_type == CAMEL_INVALID_TYPE) {
+ camel_mbox_folder_type = camel_type_register(CAMEL_LOCAL_FOLDER_TYPE, "CamelMboxFolder",
+ sizeof(CamelMboxFolder),
+ sizeof(CamelMboxFolderClass),
+ (CamelObjectClassInitFunc) camel_mbox_folder_class_init,
+ NULL,
+ (CamelObjectInitFunc) mbox_init,
+ (CamelObjectFinalizeFunc) mbox_finalise);
+ }
+
+ return camel_mbox_folder_type;
+}
+
+CamelFolder *
+camel_mbox_folder_new(CamelStore *parent_store, const char *full_name, guint32 flags, CamelException *ex)
+{
+ CamelFolder *folder;
+
+ d(printf("Creating mbox folder: %s in %s\n", full_name, camel_local_store_get_toplevel_dir((CamelLocalStore *)parent_store)));
+
+ folder = (CamelFolder *)camel_object_new(CAMEL_MBOX_FOLDER_TYPE);
+ folder = (CamelFolder *)camel_local_folder_construct((CamelLocalFolder *)folder,
+ parent_store, full_name, flags, ex);
+
+ return folder;
+}
+
+char *
+camel_mbox_folder_get_full_path (CamelLocalFolder *lf, const char *toplevel_dir, const char *full_name)
+{
+ const char *inptr = full_name;
+ int subdirs = 0;
+ char *path, *p;
+
+ while (*inptr != '\0') {
+ if (*inptr == '/')
+ subdirs++;
+ inptr++;
+ }
+
+ path = g_malloc (strlen (toplevel_dir) + (inptr - full_name) + (4 * subdirs) + 1);
+ p = g_stpcpy (path, toplevel_dir);
+
+ inptr = full_name;
+ while (*inptr != '\0') {
+ while (*inptr != '/' && *inptr != '\0')
+ *p++ = *inptr++;
+
+ if (*inptr == '/') {
+ p = g_stpcpy (p, ".sbd/");
+ inptr++;
+
+ /* strip extranaeous '/'s */
+ while (*inptr == '/')
+ inptr++;
+ }
+ }
+
+ *p = '\0';
+
+ return path;
+}
+
+char *
+camel_mbox_folder_get_meta_path (CamelLocalFolder *lf, const char *toplevel_dir, const char *full_name, const char *ext)
+{
+/*#define USE_HIDDEN_META_FILES*/
+#ifdef USE_HIDDEN_META_FILES
+ char *name, *slash;
+
+ name = g_alloca (strlen (full_name) + strlen (ext) + 2);
+ if ((slash = strrchr (full_name, '/')))
+ sprintf (name, "%.*s.%s%s", slash - full_name + 1, full_name, slash + 1, ext);
+ else
+ sprintf (name, ".%s%s", full_name, ext);
+
+ return camel_mbox_folder_get_full_path (lf, toplevel_dir, name);
+#else
+ char *full_path, *path;
+
+ full_path = camel_mbox_folder_get_full_path (lf, toplevel_dir, full_name);
+ path = g_strdup_printf ("%s%s", full_path, ext);
+ g_free (full_path);
+
+ return path;
+#endif
+}
+
+static CamelLocalSummary *mbox_create_summary(CamelLocalFolder *lf, const char *path, const char *folder, CamelIndex *index)
+{
+ return (CamelLocalSummary *)camel_mbox_summary_new(path, folder, index);
+}
+
+static int mbox_lock(CamelLocalFolder *lf, CamelLockType type, CamelException *ex)
+{
+ CamelMboxFolder *mf = (CamelMboxFolder *)lf;
+
+ /* make sure we have matching unlocks for locks, camel-local-folder class should enforce this */
+ g_assert(mf->lockfd == -1);
+
+ mf->lockfd = open(lf->folder_path, O_RDWR, 0);
+ if (mf->lockfd == -1) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot create folder lock on %s: %s"),
+ lf->folder_path, g_strerror (errno));
+ return -1;
+ }
+
+ if (camel_lock_folder(lf->folder_path, mf->lockfd, type, ex) == -1) {
+ close(mf->lockfd);
+ mf->lockfd = -1;
+ return -1;
+ }
+
+ return 0;
+}
+
+static void mbox_unlock(CamelLocalFolder *lf)
+{
+ CamelMboxFolder *mf = (CamelMboxFolder *)lf;
+
+ g_assert(mf->lockfd != -1);
+ camel_unlock_folder(lf->folder_path, mf->lockfd);
+ close(mf->lockfd);
+ mf->lockfd = -1;
+}
+
+static void
+mbox_append_message(CamelFolder *folder, CamelMimeMessage * message, const CamelMessageInfo * info, char **appended_uid, CamelException *ex)
+{
+ CamelLocalFolder *lf = (CamelLocalFolder *)folder;
+ CamelStream *output_stream = NULL, *filter_stream = NULL;
+ CamelMimeFilter *filter_from = NULL;
+ CamelMboxSummary *mbs = (CamelMboxSummary *)folder->summary;
+ CamelMessageInfo *mi;
+ char *fromline = NULL;
+ int fd, retval;
+ struct stat st;
+#if 0
+ char *xev;
+#endif
+ /* If we can't lock, dont do anything */
+ if (camel_local_folder_lock(lf, CAMEL_LOCK_WRITE, ex) == -1)
+ return;
+
+ d(printf("Appending message\n"));
+
+ /* first, check the summary is correct (updates folder_size too) */
+ retval = camel_local_summary_check ((CamelLocalSummary *)folder->summary, lf->changes, ex);
+ if (retval == -1)
+ goto fail;
+
+ /* add it to the summary/assign the uid, etc */
+ mi = camel_local_summary_add((CamelLocalSummary *)folder->summary, message, info, lf->changes, ex);
+ if (mi == NULL)
+ goto fail;
+
+ d(printf("Appending message: uid is %s\n", camel_message_info_uid(mi)));
+
+ output_stream = camel_stream_fs_new_with_name(lf->folder_path, O_WRONLY|O_APPEND, 0600);
+ if (output_stream == NULL) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot open mailbox: %s: %s\n"),
+ lf->folder_path, g_strerror (errno));
+ goto fail;
+ }
+
+ /* and we need to set the frompos/XEV explicitly */
+ ((CamelMboxMessageInfo *)mi)->frompos = mbs->folder_size;
+#if 0
+ xev = camel_local_summary_encode_x_evolution((CamelLocalSummary *)folder->summary, mi);
+ if (xev) {
+ /* the x-ev header should match the 'current' flags, no problem, so store as much */
+ camel_medium_set_header((CamelMedium *)message, "X-Evolution", xev);
+ mi->flags &= ~ CAMEL_MESSAGE_FOLDER_NOXEV|CAMEL_MESSAGE_FOLDER_FLAGGED;
+ g_free(xev);
+ }
+#endif
+
+ /* we must write this to the non-filtered stream ... */
+ fromline = camel_mime_message_build_mbox_from(message);
+ if (camel_stream_write(output_stream, fromline, strlen(fromline)) == -1)
+ goto fail_write;
+
+ /* and write the content to the filtering stream, that translates '\nFrom' into '\n>From' */
+ filter_stream = (CamelStream *) camel_stream_filter_new_with_stream(output_stream);
+ filter_from = (CamelMimeFilter *) camel_mime_filter_from_new();
+ camel_stream_filter_add((CamelStreamFilter *) filter_stream, filter_from);
+ if (camel_data_wrapper_write_to_stream((CamelDataWrapper *)message, filter_stream) == -1
+ || camel_stream_write(filter_stream, "\n", 1) == -1
+ || camel_stream_close(filter_stream) == -1)
+ goto fail_write;
+
+ /* filter stream ref's the output stream itself, so we need to unref it too */
+ camel_object_unref((CamelObject *)filter_from);
+ camel_object_unref((CamelObject *)filter_stream);
+ camel_object_unref((CamelObject *)output_stream);
+ g_free(fromline);
+
+ /* now we 'fudge' the summary to tell it its uptodate, because its idea of uptodate has just changed */
+ /* the stat really shouldn't fail, we just wrote to it */
+ if (stat(lf->folder_path, &st) == 0) {
+ mbs->folder_size = st.st_size;
+ ((CamelFolderSummary *)mbs)->time = st.st_mtime;
+ }
+
+ /* unlock as soon as we can */
+ camel_local_folder_unlock(lf);
+
+ if (camel_folder_change_info_changed(lf->changes)) {
+ camel_object_trigger_event((CamelObject *)folder, "folder_changed", lf->changes);
+ camel_folder_change_info_clear(lf->changes);
+ }
+
+ if (appended_uid)
+ *appended_uid = g_strdup(camel_message_info_uid(mi));
+
+ return;
+
+fail_write:
+ if (errno == EINTR)
+ camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL,
+ _("Mail append cancelled"));
+ else
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot append message to mbox file: %s: %s"),
+ lf->folder_path, g_strerror (errno));
+
+ if (filter_stream)
+ camel_object_unref(CAMEL_OBJECT(filter_stream));
+
+ if (output_stream)
+ camel_object_unref(CAMEL_OBJECT(output_stream));
+
+ if (filter_from)
+ camel_object_unref(CAMEL_OBJECT(filter_from));
+
+ g_free(fromline);
+
+ /* reset the file to original size */
+ fd = open(lf->folder_path, O_WRONLY, 0600);
+ if (fd != -1) {
+ ftruncate(fd, mbs->folder_size);
+ close(fd);
+ }
+
+ /* remove the summary info so we are not out-of-sync with the mbox */
+ camel_folder_summary_remove_uid (CAMEL_FOLDER_SUMMARY (mbs), camel_message_info_uid (mi));
+
+ /* and tell the summary its uptodate */
+ if (stat(lf->folder_path, &st) == 0) {
+ mbs->folder_size = st.st_size;
+ ((CamelFolderSummary *)mbs)->time = st.st_mtime;
+ }
+
+fail:
+ /* make sure we unlock the folder - before we start triggering events into appland */
+ camel_local_folder_unlock(lf);
+
+ /* cascade the changes through, anyway, if there are any outstanding */
+ if (camel_folder_change_info_changed(lf->changes)) {
+ camel_object_trigger_event((CamelObject *)folder, "folder_changed", lf->changes);
+ camel_folder_change_info_clear(lf->changes);
+ }
+}
+
+static CamelMimeMessage *
+mbox_get_message(CamelFolder *folder, const gchar * uid, CamelException *ex)
+{
+ CamelLocalFolder *lf = (CamelLocalFolder *)folder;
+ CamelMimeMessage *message = NULL;
+ CamelMboxMessageInfo *info;
+ CamelMimeParser *parser = NULL;
+ int fd, retval;
+ int retried = FALSE;
+ off_t frompos;
+
+ d(printf("Getting message %s\n", uid));
+
+ /* lock the folder first, burn if we can't, need write lock for summary check */
+ if (camel_local_folder_lock(lf, CAMEL_LOCK_WRITE, ex) == -1)
+ return NULL;
+
+ /* check for new messages always */
+ if (camel_local_summary_check((CamelLocalSummary *)folder->summary, lf->changes, ex) == -1) {
+ camel_local_folder_unlock(lf);
+ return NULL;
+ }
+
+retry:
+ /* get the message summary info */
+ info = (CamelMboxMessageInfo *) camel_folder_summary_uid(folder->summary, uid);
+
+ if (info == NULL) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_FOLDER_INVALID_UID,
+ _("Cannot get message: %s from folder %s\n %s"),
+ uid, lf->folder_path, _("No such message"));
+ goto fail;
+ }
+
+ /* no frompos, its an error in the library (and we can't do anything with it) */
+ g_assert(info->frompos != -1);
+
+ frompos = info->frompos;
+ camel_folder_summary_info_free(folder->summary, (CamelMessageInfo *)info);
+
+ /* we use an fd instead of a normal stream here - the reason is subtle, camel_mime_part will cache
+ the whole message in memory if the stream is non-seekable (which it is when built from a parser
+ with no stream). This means we dont have to lock the mbox for the life of the message, but only
+ while it is being created. */
+
+ fd = open(lf->folder_path, O_RDONLY);
+ if (fd == -1) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot get message: %s from folder %s\n %s"),
+ uid, lf->folder_path, g_strerror (errno));
+ goto fail;
+ }
+
+ /* we use a parser to verify the message is correct, and in the correct position */
+ parser = camel_mime_parser_new();
+ camel_mime_parser_init_with_fd(parser, fd);
+ camel_mime_parser_scan_from(parser, TRUE);
+
+ camel_mime_parser_seek(parser, frompos, SEEK_SET);
+ if (camel_mime_parser_step(parser, NULL, NULL) != CAMEL_MIME_PARSER_STATE_FROM
+ || camel_mime_parser_tell_start_from(parser) != frompos) {
+
+ g_warning("Summary doesn't match the folder contents! eek!\n"
+ " expecting offset %ld got %ld, state = %d", (long int)frompos,
+ (long int)camel_mime_parser_tell_start_from(parser),
+ camel_mime_parser_state(parser));
+
+ camel_object_unref((CamelObject *)parser);
+ parser = NULL;
+
+ if (!retried) {
+ retried = TRUE;
+ camel_local_summary_check_force((CamelLocalSummary *)folder->summary);
+ retval = camel_local_summary_check((CamelLocalSummary *)folder->summary, lf->changes, ex);
+ if (retval != -1)
+ goto retry;
+ }
+
+ camel_exception_setv(ex, CAMEL_EXCEPTION_FOLDER_INVALID,
+ _("Cannot get message: %s from folder %s\n %s"), uid, lf->folder_path,
+ _("The folder appears to be irrecoverably corrupted."));
+ goto fail;
+ }
+
+ message = camel_mime_message_new();
+ if (camel_mime_part_construct_from_parser((CamelMimePart *)message, parser) == -1) {
+ camel_exception_setv(ex, errno==EINTR?CAMEL_EXCEPTION_USER_CANCEL:CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot get message: %s from folder %s\n %s"), uid, lf->folder_path,
+ _("Message construction failed."));
+ camel_object_unref((CamelObject *)message);
+ message = NULL;
+ goto fail;
+ }
+
+ camel_medium_remove_header((CamelMedium *)message, "X-Evolution");
+fail:
+ /* and unlock now we're finished with it */
+ camel_local_folder_unlock(lf);
+
+ if (parser)
+ camel_object_unref((CamelObject *)parser);
+
+ /* use the opportunity to notify of changes (particularly if we had a rebuild) */
+ if (camel_folder_change_info_changed(lf->changes)) {
+ camel_object_trigger_event((CamelObject *)folder, "folder_changed", lf->changes);
+ camel_folder_change_info_clear(lf->changes);
+ }
+
+ return message;
+}
+
+#ifdef STATUS_PINE
+static gboolean
+mbox_set_message_flags(CamelFolder *folder, const char *uid, guint32 flags, guint32 set)
+{
+ /* Basically, if anything could change the Status line, presume it does */
+ if (((CamelMboxSummary *)folder->summary)->xstatus
+ && (flags & (CAMEL_MESSAGE_SEEN|CAMEL_MESSAGE_FLAGGED|CAMEL_MESSAGE_ANSWERED|CAMEL_MESSAGE_DELETED))) {
+ flags |= CAMEL_MESSAGE_FOLDER_XEVCHANGE|CAMEL_MESSAGE_FOLDER_FLAGGED;
+ set |= CAMEL_MESSAGE_FOLDER_XEVCHANGE|CAMEL_MESSAGE_FOLDER_FLAGGED;
+ }
+
+ return ((CamelFolderClass *)parent_class)->set_message_flags(folder, uid, flags, set);
+}
+#endif
+
+static void
+mbox_set_message_user_flag(CamelFolder *folder, const char *uid, const char *name, gboolean value)
+{
+ CamelMessageInfo *info;
+
+ g_return_if_fail(folder->summary != NULL);
+
+ info = camel_folder_summary_uid(folder->summary, uid);
+ if (info == NULL)
+ return;
+
+ if (camel_flag_set(&info->user_flags, name, value)) {
+ CamelFolderChangeInfo *changes = camel_folder_change_info_new();
+
+ info->flags |= CAMEL_MESSAGE_FOLDER_FLAGGED|CAMEL_MESSAGE_FOLDER_XEVCHANGE;
+ camel_folder_summary_touch(folder->summary);
+
+ camel_folder_change_info_change_uid(changes, uid);
+ camel_object_trigger_event(folder, "folder_changed", changes);
+ camel_folder_change_info_free(changes);
+ }
+ camel_folder_summary_info_free(folder->summary, info);
+}
+
+static void
+mbox_set_message_user_tag(CamelFolder *folder, const char *uid, const char *name, const char *value)
+{
+ CamelMessageInfo *info;
+
+ g_return_if_fail(folder->summary != NULL);
+
+ info = camel_folder_summary_uid(folder->summary, uid);
+ if (info == NULL)
+ return;
+
+ if (camel_tag_set(&info->user_tags, name, value)) {
+ CamelFolderChangeInfo *changes = camel_folder_change_info_new();
+
+ info->flags |= CAMEL_MESSAGE_FOLDER_FLAGGED|CAMEL_MESSAGE_FOLDER_XEVCHANGE;
+ camel_folder_summary_touch(folder->summary);
+
+ camel_folder_change_info_change_uid(changes, uid);
+ camel_object_trigger_event (folder, "folder_changed", changes);
+ camel_folder_change_info_free(changes);
+ }
+ camel_folder_summary_info_free(folder->summary, info);
+}
diff --git a/camel/providers/local/camel-mbox-folder.h b/camel/providers/local/camel-mbox-folder.h
new file mode 100644
index 0000000000..fa76001849
--- /dev/null
+++ b/camel/providers/local/camel-mbox-folder.h
@@ -0,0 +1,66 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Authors: Michael Zucchi <notzed@ximian.com>
+ *
+ * Copyright (C) 1999 Ximian .
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#ifndef CAMEL_MBOX_FOLDER_H
+#define CAMEL_MBOX_FOLDER_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif /* __cplusplus }*/
+
+#include "camel-local-folder.h"
+#include "camel-mbox-summary.h"
+
+#define CAMEL_MBOX_FOLDER_TYPE (camel_mbox_folder_get_type ())
+#define CAMEL_MBOX_FOLDER(obj) (CAMEL_CHECK_CAST((obj), CAMEL_MBOX_FOLDER_TYPE, CamelMboxFolder))
+#define CAMEL_MBOX_FOLDER_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), CAMEL_MBOX_FOLDER_TYPE, CamelMboxFolderClass))
+#define CAMEL_IS_MBOX_FOLDER(o) (CAMEL_CHECK_TYPE((o), CAMEL_MBOX_FOLDER_TYPE))
+
+typedef struct {
+ CamelLocalFolder parent_object;
+
+ int lockfd; /* for when we have a lock on the folder */
+} CamelMboxFolder;
+
+typedef struct {
+ CamelLocalFolderClass parent_class;
+
+ /* Virtual methods */
+
+} CamelMboxFolderClass;
+
+/* public methods */
+/* flags are taken from CAMEL_STORE_FOLDER_* flags */
+CamelFolder *camel_mbox_folder_new(CamelStore *parent_store, const char *full_name, guint32 flags, CamelException *ex);
+
+/* Standard Camel function */
+CamelType camel_mbox_folder_get_type(void);
+
+/* utilities */
+char *camel_mbox_folder_get_full_path (CamelLocalFolder *lf, const char *toplevel_dir, const char *full_name);
+char *camel_mbox_folder_get_meta_path (CamelLocalFolder *lf, const char *toplevel_dir, const char *full_name, const char *ext);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* CAMEL_MBOX_FOLDER_H */
diff --git a/camel/providers/local/camel-mbox-store.c b/camel/providers/local/camel-mbox-store.c
new file mode 100644
index 0000000000..1277407dbb
--- /dev/null
+++ b/camel/providers/local/camel-mbox-store.c
@@ -0,0 +1,837 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Authors: Michael Zucchi <notzed@ximian.com>
+ *
+ * Copyright(C) 2000 Ximian, Inc.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "camel-mbox-store.h"
+#include "camel-mbox-folder.h"
+#include "camel-file-utils.h"
+#include "camel-text-index.h"
+#include "camel-exception.h"
+#include "camel-url.h"
+
+#define d(x)
+
+static CamelLocalStoreClass *parent_class = NULL;
+
+/* Returns the class for a CamelMboxStore */
+#define CMBOXS_CLASS(so) CAMEL_MBOX_STORE_CLASS(CAMEL_OBJECT_GET_CLASS(so))
+#define CF_CLASS(so) CAMEL_FOLDER_CLASS(CAMEL_OBJECT_GET_CLASS(so))
+#define CMBOXF_CLASS(so) CAMEL_MBOX_FOLDER_CLASS(CAMEL_OBJECT_GET_CLASS(so))
+
+static CamelFolder *get_folder(CamelStore *store, const char *folder_name, guint32 flags, CamelException *ex);
+static void delete_folder(CamelStore *store, const char *folder_name, CamelException *ex);
+static void rename_folder(CamelStore *store, const char *old, const char *new, CamelException *ex);
+static CamelFolderInfo *create_folder(CamelStore *store, const char *parent_name, const char *folder_name, CamelException *ex);
+static CamelFolderInfo *get_folder_info(CamelStore *store, const char *top, guint32 flags, CamelException *ex);
+
+static void
+camel_mbox_store_class_init(CamelMboxStoreClass *camel_mbox_store_class)
+{
+ CamelStoreClass *camel_store_class = CAMEL_STORE_CLASS(camel_mbox_store_class);
+
+ parent_class =(CamelLocalStoreClass *)camel_type_get_global_classfuncs(camel_local_store_get_type());
+
+ /* virtual method overload */
+ camel_store_class->get_folder = get_folder;
+ camel_store_class->delete_folder = delete_folder;
+ camel_store_class->rename_folder = rename_folder;
+ camel_store_class->create_folder = create_folder;
+
+ camel_store_class->get_folder_info = get_folder_info;
+ camel_store_class->free_folder_info = camel_store_free_folder_info_full;
+}
+
+CamelType
+camel_mbox_store_get_type(void)
+{
+ static CamelType camel_mbox_store_type = CAMEL_INVALID_TYPE;
+
+ if (camel_mbox_store_type == CAMEL_INVALID_TYPE) {
+ camel_mbox_store_type = camel_type_register(CAMEL_LOCAL_STORE_TYPE, "CamelMboxStore",
+ sizeof(CamelMboxStore),
+ sizeof(CamelMboxStoreClass),
+ (CamelObjectClassInitFunc) camel_mbox_store_class_init,
+ NULL,
+ NULL,
+ NULL);
+ }
+
+ return camel_mbox_store_type;
+}
+
+static char *
+mbox_folder_name_to_path(CamelStore *store, const char *folder_name)
+{
+ const char *toplevel_dir = CAMEL_LOCAL_STORE(store)->toplevel_dir;
+
+ return camel_mbox_folder_get_full_path(NULL, toplevel_dir, folder_name);
+}
+
+static char *
+mbox_folder_name_to_meta_path(CamelStore *store, const char *folder_name, const char *ext)
+{
+ const char *toplevel_dir = CAMEL_LOCAL_STORE(store)->toplevel_dir;
+
+ return camel_mbox_folder_get_meta_path(NULL, toplevel_dir, folder_name, ext);
+}
+
+static char *extensions[] = {
+ ".msf", ".ev-summary", ".ibex.index", ".ibex.index.data", ".cmeta", ".lock"
+};
+
+static gboolean
+ignore_file(const char *filename, gboolean sbd)
+{
+ int flen, len, i;
+
+ /* TODO: Should probably just be 1 regex */
+ flen = strlen(filename);
+ if (flen > 0 && filename[flen-1] == '~')
+ return TRUE;
+
+ for (i = 0; i <(sizeof(extensions) / sizeof(extensions[0])); i++) {
+ len = strlen(extensions[i]);
+ if (len < flen && !strcmp(filename + flen - len, extensions[i]))
+ return TRUE;
+ }
+
+ if (sbd && flen > 4 && !strcmp(filename + flen - 4, ".sbd"))
+ return TRUE;
+
+ return FALSE;
+}
+
+static CamelFolder *
+get_folder(CamelStore *store, const char *folder_name, guint32 flags, CamelException *ex)
+{
+ struct stat st;
+ char *name;
+
+ if (!((CamelStoreClass *) parent_class)->get_folder(store, folder_name, flags, ex))
+ return NULL;
+
+ name = mbox_folder_name_to_path(store, folder_name);
+
+ if (stat(name, &st) == -1) {
+ const char *basename;
+ char *dirname;
+ int fd;
+
+ if (errno != ENOENT) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot get folder `%s': %s"),
+ folder_name, g_strerror (errno));
+ g_free(name);
+ return NULL;
+ }
+
+ if ((flags & CAMEL_STORE_FOLDER_CREATE) == 0) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER,
+ _("Cannot get folder `%s': folder does not exist."),
+ folder_name);
+ g_free(name);
+ return NULL;
+ }
+
+ /* sanity check the folder name */
+ if (!(basename = strrchr (folder_name, '/')))
+ basename = folder_name;
+ else
+ basename++;
+
+ if (basename[0] == '.' || ignore_file (basename, TRUE)) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot create a folder by this name."));
+ g_free (name);
+ return NULL;
+ }
+
+ dirname = g_path_get_dirname(name);
+ if (camel_mkdir(dirname, 0777) == -1 && errno != EEXIST) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot create folder `%s': %s"),
+ folder_name, g_strerror (errno));
+ g_free(dirname);
+ g_free(name);
+ return NULL;
+ }
+
+ g_free(dirname);
+
+ fd = open(name, O_WRONLY | O_CREAT | O_APPEND, 0666);
+ if (fd == -1) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot create folder `%s': %s"),
+ folder_name, g_strerror (errno));
+ g_free(name);
+ return NULL;
+ }
+
+ g_free(name);
+ close(fd);
+ } else if (!S_ISREG(st.st_mode)) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot get folder `%s': not a regular file."),
+ folder_name);
+ g_free(name);
+ return NULL;
+ } else if (flags & CAMEL_STORE_FOLDER_EXCL) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot create folder `%s': folder exists."),
+ folder_name);
+ g_free (name);
+ return NULL;
+ } else
+ g_free(name);
+
+ return camel_mbox_folder_new(store, folder_name, flags, ex);
+}
+
+static void
+delete_folder(CamelStore *store, const char *folder_name, CamelException *ex)
+{
+ CamelFolderInfo *fi;
+ CamelException lex;
+ CamelFolder *lf;
+ char *name, *path;
+ struct stat st;
+
+ name = mbox_folder_name_to_path(store, folder_name);
+ path = g_strdup_printf("%s.sbd", name);
+
+ if (rmdir(path) == -1 && errno != ENOENT) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Could not delete folder `%s':\n%s"),
+ folder_name, g_strerror(errno));
+ g_free(path);
+ g_free(name);
+ return;
+ }
+
+ g_free(path);
+
+ if (stat(name, &st) == -1) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Could not delete folder `%s':\n%s"),
+ folder_name, g_strerror(errno));
+ g_free(name);
+ return;
+ }
+
+ if (!S_ISREG(st.st_mode)) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER,
+ _("`%s' is not a regular file."), name);
+ g_free(name);
+ return;
+ }
+
+ if (st.st_size != 0) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_FOLDER_NON_EMPTY,
+ _("Folder `%s' is not empty. Not deleted."),
+ folder_name);
+ g_free(name);
+ return;
+ }
+
+ if (unlink(name) == -1 && errno != ENOENT) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Could not delete folder `%s':\n%s"),
+ name, g_strerror(errno));
+ g_free(name);
+ return;
+ }
+
+ /* FIXME: we have to do our own meta cleanup here rather than
+ * calling our parent class' delete_folder() method since our
+ * naming convention is different. Need to find a way for
+ * CamelLocalStore to be able to construct the folder & meta
+ * paths itself */
+ path = mbox_folder_name_to_meta_path(store, folder_name, ".ev-summary");
+ if (unlink(path) == -1 && errno != ENOENT) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Could not delete folder summary file `%s': %s"),
+ path, g_strerror(errno));
+ g_free(path);
+ g_free(name);
+ return;
+ }
+
+ g_free(path);
+
+ path = mbox_folder_name_to_meta_path(store, folder_name, ".ibex");
+ if (camel_text_index_remove(path) == -1 && errno != ENOENT) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Could not delete folder index file `%s': %s"),
+ path, g_strerror(errno));
+ g_free(path);
+ g_free(name);
+ return;
+ }
+
+ g_free(path);
+
+ path = NULL;
+ camel_exception_init(&lex);
+ if ((lf = camel_store_get_folder(store, folder_name, 0, &lex))) {
+ camel_object_get(lf, NULL, CAMEL_OBJECT_STATE_FILE, &path, NULL);
+ camel_object_set(lf, NULL, CAMEL_OBJECT_STATE_FILE, NULL, NULL);
+ camel_object_unref(lf);
+ } else {
+ camel_exception_clear(&lex);
+ }
+
+ if (path == NULL)
+ path = mbox_folder_name_to_meta_path(store, folder_name, ".cmeta");
+
+ if (unlink(path) == -1 && errno != ENOENT) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Could not delete folder meta file `%s': %s"),
+ path, g_strerror(errno));
+
+ g_free(path);
+ g_free(name);
+ return;
+ }
+
+ g_free(path);
+ g_free(name);
+
+ fi = g_new0(CamelFolderInfo, 1);
+ fi->full_name = g_strdup(folder_name);
+ fi->name = g_path_get_basename(folder_name);
+ fi->uri = g_strdup_printf("mbox:%s#%s",((CamelService *) store)->url->path, folder_name);
+ fi->unread = -1;
+
+ camel_object_trigger_event(store, "folder_deleted", fi);
+
+ camel_folder_info_free(fi);
+}
+
+static CamelFolderInfo *
+create_folder(CamelStore *store, const char *parent_name, const char *folder_name, CamelException *ex)
+{
+ /* FIXME: this is almost an exact copy of CamelLocalStore::create_folder() except that we use
+ * different path schemes... need to find a way to share parent's code? */
+ const char *toplevel_dir =((CamelLocalStore *) store)->toplevel_dir;
+ CamelFolderInfo *info = NULL;
+ char *path, *name, *dir;
+ CamelFolder *folder;
+ struct stat st;
+
+ if (toplevel_dir[0] != '/') {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER,
+ _("Store root %s is not an absolute path"), toplevel_dir);
+ return NULL;
+ }
+
+ if (folder_name[0] == '.' || ignore_file(folder_name, TRUE)) {
+ camel_exception_set(ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot create a folder by this name."));
+ return NULL;
+ }
+
+ if (parent_name && *parent_name)
+ name = g_strdup_printf("%s/%s", parent_name, folder_name);
+ else
+ name = g_strdup(folder_name);
+
+ path = mbox_folder_name_to_path(store, name);
+
+ dir = g_path_get_dirname(path);
+ if (camel_mkdir(dir, 0777) == -1 && errno != EEXIST) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot create directory `%s': %s."),
+ dir, g_strerror(errno));
+
+ g_free(path);
+ g_free(name);
+ g_free(dir);
+
+ return NULL;
+ }
+
+ g_free(dir);
+
+ if (stat(path, &st) == 0 || errno != ENOENT) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER,
+ _("Cannot create folder: %s: %s"),
+ path, errno ? g_strerror(errno) :
+ _("Folder already exists"));
+
+ g_free(path);
+ g_free(name);
+
+ return NULL;
+ }
+
+ g_free(path);
+
+ folder =((CamelStoreClass *)((CamelObject *) store)->klass)->get_folder(store, name, CAMEL_STORE_FOLDER_CREATE, ex);
+ if (folder) {
+ camel_object_unref(folder);
+ info =((CamelStoreClass *)((CamelObject *) store)->klass)->get_folder_info(store, name, 0, ex);
+ }
+
+ g_free(name);
+
+ return info;
+}
+
+static int
+xrename(CamelStore *store, const char *old_name, const char *new_name, const char *ext, gboolean missingok)
+{
+ const char *toplevel_dir =((CamelLocalStore *) store)->toplevel_dir;
+ char *oldpath, *newpath;
+ struct stat st;
+ int ret = -1;
+ int err = 0;
+
+ if (ext != NULL) {
+ oldpath = camel_mbox_folder_get_meta_path(NULL, toplevel_dir, old_name, ext);
+ newpath = camel_mbox_folder_get_meta_path(NULL, toplevel_dir, new_name, ext);
+ } else {
+ oldpath = camel_mbox_folder_get_full_path(NULL, toplevel_dir, old_name);
+ newpath = camel_mbox_folder_get_full_path(NULL, toplevel_dir, new_name);
+ }
+
+ if (stat(oldpath, &st) == -1) {
+ if (missingok && errno == ENOENT) {
+ ret = 0;
+ } else {
+ err = errno;
+ ret = -1;
+ }
+ } else if (S_ISDIR(st.st_mode)) {
+ /* use rename for dirs */
+ if (rename(oldpath, newpath) == 0 || stat(newpath, &st) == 0) {
+ ret = 0;
+ } else {
+ err = errno;
+ ret = -1;
+ }
+ } else if (link(oldpath, newpath) == 0 /* and link for files */
+ ||(stat(newpath, &st) == 0 && st.st_nlink == 2)) {
+ if (unlink(oldpath) == 0) {
+ ret = 0;
+ } else {
+ err = errno;
+ unlink(newpath);
+ ret = -1;
+ }
+ } else {
+ err = errno;
+ ret = -1;
+ }
+
+ g_free(oldpath);
+ g_free(newpath);
+
+ return ret;
+}
+
+static void
+rename_folder(CamelStore *store, const char *old, const char *new, CamelException *ex)
+{
+ CamelLocalFolder *folder = NULL;
+ char *oldibex, *newibex, *newdir;
+ int errnosav;
+
+ if (new[0] == '.' || ignore_file(new, TRUE)) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM,
+ _("The new folder name is illegal."));
+ return;
+ }
+
+ /* try to rollback failures, has obvious races */
+
+ oldibex = mbox_folder_name_to_meta_path(store, old, ".ibex");
+ newibex = mbox_folder_name_to_meta_path(store, new, ".ibex");
+
+ newdir = g_path_get_dirname(newibex);
+ if (camel_mkdir(newdir, 0777) == -1) {
+ if (errno != EEXIST) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Could not rename `%s': `%s': %s"),
+ old, new, g_strerror(errno));
+ g_free(oldibex);
+ g_free(newibex);
+ g_free(newdir);
+
+ return;
+ }
+
+ g_free(newdir);
+ newdir = NULL;
+ }
+
+ folder = camel_object_bag_get(store->folders, old);
+ if (folder && folder->index) {
+ if (camel_index_rename(folder->index, newibex) == -1 && errno != ENOENT) {
+ errnosav = errno;
+ goto ibex_failed;
+ }
+ } else {
+ /* TODO: camel_text_index_rename should find out if we have an active index itself? */
+ if (camel_text_index_rename(oldibex, newibex) == -1 && errno != ENOENT) {
+ errnosav = errno;
+ goto ibex_failed;
+ }
+ }
+
+ if (xrename(store, old, new, ".ev-summary", TRUE) == -1) {
+ errnosav = errno;
+ goto summary_failed;
+ }
+
+ if (xrename(store, old, new, ".cmeta", TRUE) == -1) {
+ errnosav = errno;
+ goto cmeta_failed;
+ }
+
+ if (xrename(store, old, new, ".sbd", TRUE) == -1) {
+ errnosav = errno;
+ goto subdir_failed;
+ }
+
+ if (xrename(store, old, new, NULL, FALSE) == -1) {
+ errnosav = errno;
+ goto base_failed;
+ }
+
+ g_free(oldibex);
+ g_free(newibex);
+
+ if (folder)
+ camel_object_unref(folder);
+
+ return;
+
+base_failed:
+ xrename(store, new, old, ".sbd", TRUE);
+subdir_failed:
+ xrename(store, new, old, ".cmeta", TRUE);
+cmeta_failed:
+ xrename(store, new, old, ".ev-summary", TRUE);
+summary_failed:
+ if (folder) {
+ if (folder->index)
+ camel_index_rename(folder->index, oldibex);
+ } else
+ camel_text_index_rename(newibex, oldibex);
+ibex_failed:
+ if (newdir) {
+ /* newdir is only non-NULL if we needed to mkdir */
+ rmdir(newdir);
+ g_free(newdir);
+ }
+
+ camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Could not rename '%s' to %s: %s"),
+ old, new, g_strerror(errnosav));
+
+ g_free(newibex);
+ g_free(oldibex);
+
+ if (folder)
+ camel_object_unref(folder);
+}
+
+/* used to find out where we've visited already */
+struct _inode {
+ dev_t dnode;
+ ino_t inode;
+};
+
+static guint
+inode_hash(const void *d)
+{
+ const struct _inode *v = d;
+
+ return v->inode ^ v->dnode;
+}
+
+static gboolean
+inode_equal(const void *a, const void *b)
+{
+ const struct _inode *v1 = a, *v2 = b;
+
+ return v1->inode == v2->inode && v1->dnode == v2->dnode;
+}
+
+static void
+inode_free(void *k, void *v, void *d)
+{
+ g_free(k);
+}
+
+/* NB: duplicated in maildir store */
+static void
+fill_fi(CamelStore *store, CamelFolderInfo *fi, guint32 flags)
+{
+ CamelFolder *folder;
+
+ fi->unread = -1;
+ fi->total = -1;
+ folder = camel_object_bag_get(store->folders, fi->full_name);
+ if (folder) {
+ if ((flags & CAMEL_STORE_FOLDER_INFO_FAST) == 0)
+ camel_folder_refresh_info(folder, NULL);
+ fi->unread = camel_folder_get_unread_message_count(folder);
+ fi->total = camel_folder_get_message_count(folder);
+ camel_object_unref(folder);
+ } else {
+ char *path, *folderpath;
+ CamelMboxSummary *mbs;
+ const char *root;
+
+ /* This should be fast enough not to have to test for INFO_FAST */
+ root = camel_local_store_get_toplevel_dir((CamelLocalStore *)store);
+ path = camel_mbox_folder_get_meta_path(NULL, root, fi->full_name, ".ev-summary");
+ folderpath = camel_mbox_folder_get_full_path(NULL, root, fi->full_name);
+
+ mbs = (CamelMboxSummary *)camel_mbox_summary_new(path, folderpath, NULL);
+ if (camel_folder_summary_header_load((CamelFolderSummary *)mbs) != -1) {
+ fi->unread = ((CamelFolderSummary *)mbs)->unread_count;
+ fi->total = ((CamelFolderSummary *)mbs)->saved_count;
+ }
+
+ camel_object_unref(mbs);
+ g_free(folderpath);
+ g_free(path);
+ }
+}
+
+static CamelFolderInfo *
+scan_dir(CamelStore *store, CamelURL *url, GHashTable *visited, CamelFolderInfo *parent, const char *root,
+ const char *name, guint32 flags, CamelException *ex)
+{
+ CamelFolderInfo *folders, *tail, *fi;
+ GHashTable *folder_hash;
+ struct dirent *dent;
+ DIR *dir;
+
+ tail = folders = NULL;
+
+ if (!(dir = opendir(root)))
+ return NULL;
+
+ folder_hash = g_hash_table_new(g_str_hash, g_str_equal);
+
+ /* FIXME: it would be better if we queue'd up the recursive
+ * scans till the end so that we can limit the number of
+ * directory descriptors open at any given time... */
+
+ while ((dent = readdir(dir))) {
+ char *short_name, *full_name, *path, *ext;
+ struct stat st;
+
+ if (dent->d_name[0] == '.')
+ continue;
+
+ if (ignore_file(dent->d_name, FALSE))
+ continue;
+
+ path = g_strdup_printf("%s/%s", root, dent->d_name);
+ if (stat(path, &st) == -1) {
+ g_free(path);
+ continue;
+ }
+
+ if (S_ISDIR(st.st_mode)) {
+ struct _inode in = { st.st_dev, st.st_ino };
+
+ if (g_hash_table_lookup(visited, &in)) {
+ g_free(path);
+ continue;
+ }
+ }
+
+ short_name = g_strdup(dent->d_name);
+ if ((ext = strrchr(short_name, '.')) && !strcmp(ext, ".sbd"))
+ *ext = '\0';
+
+ if (name != NULL)
+ full_name = g_strdup_printf("%s/%s", name, short_name);
+ else
+ full_name = g_strdup(short_name);
+
+ if ((fi = g_hash_table_lookup(folder_hash, short_name)) != NULL) {
+ g_free(short_name);
+ g_free(full_name);
+
+ if (S_ISDIR(st.st_mode)) {
+ fi->flags =(fi->flags & ~CAMEL_FOLDER_NOCHILDREN) | CAMEL_FOLDER_CHILDREN;
+ } else {
+ fi->flags &= ~CAMEL_FOLDER_NOSELECT;
+ }
+ } else {
+ fi = g_new0(CamelFolderInfo, 1);
+ fi->parent = parent;
+
+ camel_url_set_fragment (url, full_name);
+
+ fi->uri = camel_url_to_string (url, 0);
+ fi->name = short_name;
+ fi->full_name = full_name;
+ fi->unread = -1;
+ fi->total = -1;
+
+ if (S_ISDIR(st.st_mode))
+ fi->flags = CAMEL_FOLDER_NOSELECT;
+ else
+ fi->flags = CAMEL_FOLDER_NOCHILDREN;
+
+ if (tail == NULL)
+ folders = fi;
+ else
+ tail->next = fi;
+
+ tail = fi;
+
+ g_hash_table_insert(folder_hash, fi->name, fi);
+ }
+
+ if (!S_ISDIR(st.st_mode)) {
+ fill_fi(store, fi, flags);
+ } else if ((flags & CAMEL_STORE_FOLDER_INFO_RECURSIVE)) {
+ struct _inode in = { st.st_dev, st.st_ino };
+
+ if (g_hash_table_lookup(visited, &in) == NULL) {
+ struct _inode *inew = g_new(struct _inode, 1);
+
+ *inew = in;
+
+ g_hash_table_insert(visited, inew, inew);
+
+ if ((fi->child = scan_dir (store, url, visited, fi, path, fi->full_name, flags, ex)))
+ fi->flags |= CAMEL_FOLDER_CHILDREN;
+ else
+ fi->flags =(fi->flags & ~CAMEL_FOLDER_CHILDREN) | CAMEL_FOLDER_NOCHILDREN;
+ }
+ }
+
+ g_free(path);
+ }
+
+ closedir(dir);
+
+ g_hash_table_destroy(folder_hash);
+
+ return folders;
+}
+
+static CamelFolderInfo *
+get_folder_info(CamelStore *store, const char *top, guint32 flags, CamelException *ex)
+{
+ GHashTable *visited;
+ struct _inode *inode;
+ char *path, *subdir;
+ CamelFolderInfo *fi;
+ const char *base;
+ struct stat st;
+ CamelURL *url;
+
+ top = top ? top : "";
+ path = mbox_folder_name_to_path(store, top);
+
+ if (*top == '\0') {
+ /* requesting root dir scan */
+ if (stat(path, &st) == -1 || !S_ISDIR(st.st_mode)) {
+ g_free(path);
+ return NULL;
+ }
+
+ visited = g_hash_table_new(inode_hash, inode_equal);
+
+ inode = g_malloc0(sizeof(*inode));
+ inode->dnode = st.st_dev;
+ inode->inode = st.st_ino;
+
+ g_hash_table_insert(visited, inode, inode);
+
+ url = camel_url_copy (((CamelService *) store)->url);
+ fi = scan_dir (store, url, visited, NULL, path, NULL, flags, ex);
+ g_hash_table_foreach(visited, inode_free, NULL);
+ g_hash_table_destroy(visited);
+ camel_url_free (url);
+ g_free (path);
+
+ return fi;
+ }
+
+ /* requesting scan of specific folder */
+ if (stat(path, &st) == -1 || !S_ISREG(st.st_mode)) {
+ g_free(path);
+ return NULL;
+ }
+
+ visited = g_hash_table_new(inode_hash, inode_equal);
+
+ if (!(base = strrchr(top, '/')))
+ base = top;
+ else
+ base++;
+
+ url = camel_url_copy (((CamelService *) store)->url);
+ camel_url_set_fragment (url, top);
+
+ fi = g_new0(CamelFolderInfo, 1);
+ fi->parent = NULL;
+ fi->uri = camel_url_to_string (url, 0);
+ fi->name = g_strdup(base);
+ fi->full_name = g_strdup(top);
+ fi->unread = -1;
+ fi->total = -1;
+
+ subdir = g_strdup_printf("%s.sbd", path);
+ if (stat(subdir, &st) == 0) {
+ if (S_ISDIR(st.st_mode))
+ fi->child = scan_dir (store, url, visited, fi, subdir, top, flags, ex);
+ else
+ fill_fi(store, fi, flags);
+ } else
+ fill_fi(store, fi, flags);
+
+ camel_url_free (url);
+
+ if (fi->child)
+ fi->flags |= CAMEL_FOLDER_CHILDREN;
+ else
+ fi->flags |= CAMEL_FOLDER_NOCHILDREN;
+
+ g_free(subdir);
+
+ g_hash_table_foreach(visited, inode_free, NULL);
+ g_hash_table_destroy(visited);
+ g_free(path);
+
+ return fi;
+}
diff --git a/camel/providers/local/camel-mh-folder.c b/camel/providers/local/camel-mh-folder.c
new file mode 100644
index 0000000000..78456b6daf
--- /dev/null
+++ b/camel/providers/local/camel-mh-folder.c
@@ -0,0 +1,233 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; fill-column: 160 -*-
+ *
+ * Authors: Michael Zucchi <notzed@ximian.com>
+ *
+ * Copyright (C) 1999, 2003 Ximian Inc.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include "camel-mh-folder.h"
+#include "camel-mh-store.h"
+#include "camel-stream-fs.h"
+#include "camel-mh-summary.h"
+#include "camel-data-wrapper.h"
+#include "camel-mime-message.h"
+#include "camel-exception.h"
+
+#define d(x) /*(printf("%s(%d): ", __FILE__, __LINE__),(x))*/
+
+static CamelLocalFolderClass *parent_class = NULL;
+
+/* Returns the class for a CamelMhFolder */
+#define CMHF_CLASS(so) CAMEL_MH_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so))
+#define CF_CLASS(so) CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so))
+#define CMHS_CLASS(so) CAMEL_STORE_CLASS (CAMEL_OBJECT_GET_CLASS(so))
+
+static CamelLocalSummary *mh_create_summary(CamelLocalFolder *lf, const char *path, const char *folder, CamelIndex *index);
+
+static void mh_append_message(CamelFolder * folder, CamelMimeMessage * message, const CamelMessageInfo *info, char **appended_uid, CamelException * ex);
+static CamelMimeMessage *mh_get_message(CamelFolder * folder, const gchar * uid, CamelException * ex);
+
+static void mh_finalize(CamelObject * object);
+
+static void camel_mh_folder_class_init(CamelObjectClass * camel_mh_folder_class)
+{
+ CamelFolderClass *camel_folder_class = CAMEL_FOLDER_CLASS(camel_mh_folder_class);
+ CamelLocalFolderClass *lclass = (CamelLocalFolderClass *)camel_mh_folder_class;
+
+ parent_class = CAMEL_LOCAL_FOLDER_CLASS (camel_type_get_global_classfuncs(camel_local_folder_get_type()));
+
+ /* virtual method definition */
+
+ /* virtual method overload */
+ camel_folder_class->append_message = mh_append_message;
+ camel_folder_class->get_message = mh_get_message;
+
+ lclass->create_summary = mh_create_summary;
+}
+
+static void mh_init(gpointer object, gpointer klass)
+{
+ /*CamelFolder *folder = object;
+ CamelMhFolder *mh_folder = object;*/
+}
+
+static void mh_finalize(CamelObject * object)
+{
+ /*CamelMhFolder *mh_folder = CAMEL_MH_FOLDER(object);*/
+}
+
+CamelType camel_mh_folder_get_type(void)
+{
+ static CamelType camel_mh_folder_type = CAMEL_INVALID_TYPE;
+
+ if (camel_mh_folder_type == CAMEL_INVALID_TYPE) {
+ camel_mh_folder_type = camel_type_register(CAMEL_LOCAL_FOLDER_TYPE, "CamelMhFolder",
+ sizeof(CamelMhFolder),
+ sizeof(CamelMhFolderClass),
+ (CamelObjectClassInitFunc) camel_mh_folder_class_init,
+ NULL,
+ (CamelObjectInitFunc) mh_init,
+ (CamelObjectFinalizeFunc) mh_finalize);
+ }
+
+ return camel_mh_folder_type;
+}
+
+CamelFolder *
+camel_mh_folder_new(CamelStore *parent_store, const char *full_name, guint32 flags, CamelException *ex)
+{
+ CamelFolder *folder;
+
+ d(printf("Creating mh folder: %s\n", full_name));
+
+ folder = (CamelFolder *)camel_object_new(CAMEL_MH_FOLDER_TYPE);
+ folder = (CamelFolder *)camel_local_folder_construct((CamelLocalFolder *)folder,
+ parent_store, full_name, flags, ex);
+
+ return folder;
+}
+
+static CamelLocalSummary *mh_create_summary(CamelLocalFolder *lf, const char *path, const char *folder, CamelIndex *index)
+{
+ return (CamelLocalSummary *)camel_mh_summary_new(path, folder, index);
+}
+
+static void
+mh_append_message (CamelFolder *folder, CamelMimeMessage *message, const CamelMessageInfo *info, char **appended_uid, CamelException *ex)
+{
+ CamelMhFolder *mh_folder = (CamelMhFolder *)folder;
+ CamelLocalFolder *lf = (CamelLocalFolder *)folder;
+ CamelStream *output_stream;
+ CamelMessageInfo *mi;
+ char *name;
+
+ /* FIXME: probably needs additional locking (although mh doesn't appear do do it) */
+
+ d(printf("Appending message\n"));
+
+ /* add it to the summary/assign the uid, etc */
+ mi = camel_local_summary_add((CamelLocalSummary *)folder->summary, message, info, lf->changes, ex);
+ if (camel_exception_is_set (ex))
+ return;
+
+ d(printf("Appending message: uid is %s\n", camel_message_info_uid(mi)));
+
+ /* write it out, use the uid we got from the summary */
+ name = g_strdup_printf("%s/%s", lf->folder_path, camel_message_info_uid(mi));
+ output_stream = camel_stream_fs_new_with_name(name, O_WRONLY|O_CREAT, 0600);
+ if (output_stream == NULL)
+ goto fail_write;
+
+ if (camel_data_wrapper_write_to_stream ((CamelDataWrapper *)message, output_stream) == -1
+ || camel_stream_close (output_stream) == -1)
+ goto fail_write;
+
+ /* close this? */
+ camel_object_unref (CAMEL_OBJECT (output_stream));
+
+ g_free(name);
+
+ camel_object_trigger_event (CAMEL_OBJECT (folder), "folder_changed",
+ ((CamelLocalFolder *)mh_folder)->changes);
+ camel_folder_change_info_clear (((CamelLocalFolder *)mh_folder)->changes);
+
+ if (appended_uid)
+ *appended_uid = g_strdup(camel_message_info_uid(mi));
+
+ return;
+
+ fail_write:
+
+ /* remove the summary info so we are not out-of-sync with the mh folder */
+ camel_folder_summary_remove_uid (CAMEL_FOLDER_SUMMARY (folder->summary),
+ camel_message_info_uid (mi));
+
+ if (errno == EINTR)
+ camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL,
+ _("MH append message cancelled"));
+ else
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot append message to mh folder: %s: %s"),
+ name, g_strerror (errno));
+
+ if (output_stream) {
+ camel_object_unref (CAMEL_OBJECT (output_stream));
+ unlink (name);
+ }
+
+ g_free (name);
+}
+
+static CamelMimeMessage *mh_get_message(CamelFolder * folder, const gchar * uid, CamelException * ex)
+{
+ CamelLocalFolder *lf = (CamelLocalFolder *)folder;
+ CamelStream *message_stream = NULL;
+ CamelMimeMessage *message = NULL;
+ CamelMessageInfo *info;
+ char *name;
+
+ d(printf("getting message: %s\n", uid));
+
+ /* get the message summary info */
+ if ((info = camel_folder_summary_uid(folder->summary, uid)) == NULL) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_FOLDER_INVALID_UID,
+ _("Cannot get message: %s from folder %s\n %s"), uid, lf->folder_path,
+ _("No such message"));
+ return NULL;
+ }
+
+ /* we only need it to check the message exists */
+ camel_folder_summary_info_free(folder->summary, info);
+
+ name = g_strdup_printf("%s/%s", lf->folder_path, uid);
+ if ((message_stream = camel_stream_fs_new_with_name(name, O_RDONLY, 0)) == NULL) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot get message: %s from folder %s\n %s"), name, lf->folder_path,
+ g_strerror (errno));
+ g_free(name);
+ return NULL;
+ }
+
+ message = camel_mime_message_new();
+ if (camel_data_wrapper_construct_from_stream((CamelDataWrapper *)message, message_stream) == -1) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot get message: %s from folder %s\n %s"), name, lf->folder_path,
+ _("Message construction failed."));
+ g_free(name);
+ camel_object_unref((CamelObject *)message_stream);
+ camel_object_unref((CamelObject *)message);
+ return NULL;
+
+ }
+ camel_object_unref((CamelObject *)message_stream);
+ g_free(name);
+
+ return message;
+}
diff --git a/camel/providers/local/camel-spool-folder.c b/camel/providers/local/camel-spool-folder.c
new file mode 100644
index 0000000000..6a1bbf798a
--- /dev/null
+++ b/camel/providers/local/camel-spool-folder.c
@@ -0,0 +1,217 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; fill-column: 160 -*-
+ *
+ * Authors: Michael Zucchi <notzed@ximian.com>
+ *
+ * Copyright (C) 2001-2003 Ximian, Inc. (www.ximian.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include "camel-spool-folder.h"
+#include "camel-spool-store.h"
+#include "camel-stream-fs.h"
+#include "camel-spool-summary.h"
+#include "camel-data-wrapper.h"
+#include "camel-mime-message.h"
+#include "camel-stream-filter.h"
+#include "camel-mime-filter-from.h"
+#include "camel-exception.h"
+#include "camel-session.h"
+#include "camel-file-utils.h"
+#include "camel-lock-client.h"
+
+#include "camel-local-private.h"
+
+#define d(x) /*(printf("%s(%d): ", __FILE__, __LINE__),(x))*/
+
+static CamelFolderClass *parent_class = NULL;
+
+/* Returns the class for a CamelSpoolFolder */
+#define CSPOOLF_CLASS(so) CAMEL_SPOOL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so))
+#define CF_CLASS(so) CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so))
+#define CSPOOLS_CLASS(so) CAMEL_STORE_CLASS (CAMEL_OBJECT_GET_CLASS(so))
+
+static char *spool_get_full_path(CamelLocalFolder *lf, const char *toplevel_dir, const char *full_name);
+static char *spool_get_meta_path(CamelLocalFolder *lf, const char *toplevel_dir, const char *full_name, const char *ext);
+static CamelLocalSummary *spool_create_summary(CamelLocalFolder *lf, const char *path, const char *folder, CamelIndex *index);
+
+static int spool_lock(CamelLocalFolder *lf, CamelLockType type, CamelException *ex);
+static void spool_unlock(CamelLocalFolder *lf);
+
+static void spool_finalize(CamelObject * object);
+
+static void
+camel_spool_folder_class_init(CamelSpoolFolderClass *klass)
+{
+ CamelLocalFolderClass *lklass = (CamelLocalFolderClass *)klass;
+
+ parent_class = (CamelFolderClass *)camel_mbox_folder_get_type();
+
+ lklass->get_full_path = spool_get_full_path;
+ lklass->get_meta_path = spool_get_meta_path;
+ lklass->create_summary = spool_create_summary;
+ lklass->lock = spool_lock;
+ lklass->unlock = spool_unlock;
+}
+
+static void
+spool_init(gpointer object, gpointer klass)
+{
+ CamelSpoolFolder *spool_folder = object;
+
+ spool_folder->lockid = -1;
+}
+
+static void
+spool_finalize(CamelObject * object)
+{
+ /*CamelSpoolFolder *spool_folder = CAMEL_SPOOL_FOLDER(object);*/
+}
+
+CamelType camel_spool_folder_get_type(void)
+{
+ static CamelType camel_spool_folder_type = CAMEL_INVALID_TYPE;
+
+ if (camel_spool_folder_type == CAMEL_INVALID_TYPE) {
+ camel_spool_folder_type = camel_type_register(camel_mbox_folder_get_type(), "CamelSpoolFolder",
+ sizeof(CamelSpoolFolder),
+ sizeof(CamelSpoolFolderClass),
+ (CamelObjectClassInitFunc) camel_spool_folder_class_init,
+ NULL,
+ (CamelObjectInitFunc) spool_init,
+ (CamelObjectFinalizeFunc) spool_finalize);
+ }
+
+ return camel_spool_folder_type;
+}
+
+CamelFolder *
+camel_spool_folder_new(CamelStore *parent_store, const char *full_name, guint32 flags, CamelException *ex)
+{
+ CamelFolder *folder;
+
+ d(printf("Creating spool folder: %s in %s\n", full_name, camel_local_store_get_toplevel_dir((CamelLocalStore *)parent_store)));
+
+ folder = (CamelFolder *)camel_object_new(CAMEL_SPOOL_FOLDER_TYPE);
+
+ if (parent_store->flags & CAMEL_STORE_FILTER_INBOX
+ && strcmp(full_name, "INBOX") == 0)
+ folder->folder_flags |= CAMEL_FOLDER_FILTER_RECENT;
+ flags &= ~CAMEL_STORE_FOLDER_BODY_INDEX;
+
+ folder = (CamelFolder *)camel_local_folder_construct((CamelLocalFolder *)folder, parent_store, full_name, flags, ex);
+ if (folder) {
+ if (camel_url_get_param(((CamelService *)parent_store)->url, "xstatus"))
+ camel_mbox_summary_xstatus((CamelMboxSummary *)folder->summary, TRUE);
+ }
+
+ return folder;
+}
+
+static char *
+spool_get_full_path(CamelLocalFolder *lf, const char *toplevel_dir, const char *full_name)
+{
+ return g_strdup_printf ("%s/%s", toplevel_dir, full_name);
+}
+
+static char *
+spool_get_meta_path(CamelLocalFolder *lf, const char *toplevel_dir, const char *full_name, const char *ext)
+{
+ CamelService *service = (CamelService *)((CamelFolder *)lf)->parent_store;
+ char *root = camel_session_get_storage_path(service->session, service, NULL);
+ char *path;
+
+ if (root == NULL)
+ return NULL;
+
+
+ camel_mkdir(root, 0777);
+ path = g_strdup_printf("%s/%s%s", root, full_name, ext);
+ g_free(root);
+
+ return path;
+}
+
+static CamelLocalSummary *
+spool_create_summary(CamelLocalFolder *lf, const char *path, const char *folder, CamelIndex *index)
+{
+ return (CamelLocalSummary *)camel_spool_summary_new(folder);
+}
+
+static int
+spool_lock(CamelLocalFolder *lf, CamelLockType type, CamelException *ex)
+{
+ int retry = 0;
+ CamelMboxFolder *mf = (CamelMboxFolder *)lf;
+ CamelSpoolFolder *sf = (CamelSpoolFolder *)lf;
+
+ mf->lockfd = open(lf->folder_path, O_RDWR, 0);
+ if (mf->lockfd == -1) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot create folder lock on %s: %s"),
+ lf->folder_path, g_strerror (errno));
+ return -1;
+ }
+
+ while (retry < CAMEL_LOCK_RETRY) {
+ if (retry > 0)
+ sleep(CAMEL_LOCK_DELAY);
+
+ camel_exception_clear(ex);
+
+ if (camel_lock_fcntl(mf->lockfd, type, ex) == 0) {
+ if (camel_lock_flock(mf->lockfd, type, ex) == 0) {
+ if ((sf->lockid = camel_lock_helper_lock(lf->folder_path, ex)) != -1)
+ return 0;
+ camel_unlock_flock(mf->lockfd);
+ }
+ camel_unlock_fcntl(mf->lockfd);
+ }
+ retry++;
+ }
+
+ close (mf->lockfd);
+ mf->lockfd = -1;
+
+ return -1;
+}
+
+static void
+spool_unlock(CamelLocalFolder *lf)
+{
+ CamelMboxFolder *mf = (CamelMboxFolder *)lf;
+ CamelSpoolFolder *sf = (CamelSpoolFolder *)lf;
+
+ camel_lock_helper_unlock(sf->lockid);
+ sf->lockid = -1;
+ camel_unlock_flock(mf->lockfd);
+ camel_unlock_fcntl(mf->lockfd);
+
+ close(mf->lockfd);
+ mf->lockfd = -1;
+}
diff --git a/camel/providers/local/camel-spool-store.c b/camel/providers/local/camel-spool-store.c
new file mode 100644
index 0000000000..2e3d9ea777
--- /dev/null
+++ b/camel/providers/local/camel-spool-store.c
@@ -0,0 +1,465 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Authors: Michael Zucchi <notzed@ximian.com>
+ *
+ * Copyright (C) 2001 Ximian Inc (www.ximian.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <dirent.h>
+
+#include "camel-spool-store.h"
+#include "camel-spool-folder.h"
+#include "camel-exception.h"
+#include "camel-url.h"
+#include "camel-private.h"
+
+#define d(x)
+
+/* Returns the class for a CamelSpoolStore */
+#define CSPOOLS_CLASS(so) CAMEL_SPOOL_STORE_CLASS (CAMEL_OBJECT_GET_CLASS(so))
+#define CF_CLASS(so) CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so))
+
+static void construct (CamelService *service, CamelSession *session, CamelProvider *provider, CamelURL *url, CamelException *ex);
+static CamelFolder *get_folder(CamelStore * store, const char *folder_name, guint32 flags, CamelException * ex);
+static char *get_name(CamelService *service, gboolean brief);
+static CamelFolder *get_inbox (CamelStore *store, CamelException *ex);
+static void rename_folder(CamelStore *store, const char *old_name, const char *new_name, CamelException *ex);
+static CamelFolderInfo *get_folder_info (CamelStore *store, const char *top, guint32 flags, CamelException *ex);
+static void free_folder_info (CamelStore *store, CamelFolderInfo *fi);
+
+static void delete_folder(CamelStore *store, const char *folder_name, CamelException *ex);
+static void rename_folder(CamelStore *store, const char *old, const char *new, CamelException *ex);
+
+static CamelStoreClass *parent_class = NULL;
+
+static void
+camel_spool_store_class_init (CamelSpoolStoreClass *camel_spool_store_class)
+{
+ CamelStoreClass *camel_store_class = CAMEL_STORE_CLASS (camel_spool_store_class);
+ CamelServiceClass *camel_service_class = CAMEL_SERVICE_CLASS (camel_spool_store_class);
+
+ parent_class = CAMEL_STORE_CLASS(camel_mbox_store_get_type());
+
+ /* virtual method overload */
+ camel_service_class->construct = construct;
+ camel_service_class->get_name = get_name;
+ camel_store_class->get_folder = get_folder;
+ camel_store_class->get_inbox = get_inbox;
+ camel_store_class->get_folder_info = get_folder_info;
+ camel_store_class->free_folder_info = free_folder_info;
+
+ camel_store_class->delete_folder = delete_folder;
+ camel_store_class->rename_folder = rename_folder;
+}
+
+CamelType
+camel_spool_store_get_type (void)
+{
+ static CamelType camel_spool_store_type = CAMEL_INVALID_TYPE;
+
+ if (camel_spool_store_type == CAMEL_INVALID_TYPE) {
+ camel_spool_store_type = camel_type_register (camel_mbox_store_get_type(), "CamelSpoolStore",
+ sizeof (CamelSpoolStore),
+ sizeof (CamelSpoolStoreClass),
+ (CamelObjectClassInitFunc) camel_spool_store_class_init,
+ NULL,
+ NULL,
+ NULL);
+ }
+
+ return camel_spool_store_type;
+}
+
+static void
+construct (CamelService *service, CamelSession *session, CamelProvider *provider, CamelURL *url, CamelException *ex)
+{
+ struct stat st;
+
+ d(printf("constructing store of type %s '%s:%s'\n",
+ camel_type_to_name(((CamelObject *)service)->s.type), url->protocol, url->path));
+
+ CAMEL_SERVICE_CLASS (parent_class)->construct (service, session, provider, url, ex);
+ if (camel_exception_is_set (ex))
+ return;
+
+ if (service->url->path[0] != '/') {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER,
+ _("Store root %s is not an absolute path"), service->url->path);
+ return;
+ }
+
+ if (stat(service->url->path, &st) == -1) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_STORE_NO_FOLDER,
+ _("Spool `%s' cannot be opened: %s"),
+ service->url->path, g_strerror (errno));
+ return;
+ }
+
+ if (S_ISREG(st.st_mode))
+ ((CamelSpoolStore *)service)->type = CAMEL_SPOOL_STORE_MBOX;
+ else if (S_ISDIR(st.st_mode))
+ /* we could check here for slight variations */
+ ((CamelSpoolStore *)service)->type = CAMEL_SPOOL_STORE_ELM;
+ else {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER,
+ _("Spool `%s' is not a regular file or directory"),
+ service->url->path);
+ return;
+ }
+}
+
+static CamelFolder *
+get_folder(CamelStore * store, const char *folder_name, guint32 flags, CamelException * ex)
+{
+ CamelFolder *folder = NULL;
+ struct stat st;
+ char *name;
+
+ d(printf("opening folder %s on path %s\n", folder_name, path));
+
+ /* we only support an 'INBOX' in mbox mode */
+ if (((CamelSpoolStore *)store)->type == CAMEL_SPOOL_STORE_MBOX) {
+ if (strcmp(folder_name, "INBOX") != 0) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER,
+ _("Folder `%s/%s' does not exist."),
+ ((CamelService *)store)->url->path, folder_name);
+ } else {
+ folder = camel_spool_folder_new(store, folder_name, flags, ex);
+ }
+ } else {
+ name = g_strdup_printf("%s%s", CAMEL_LOCAL_STORE(store)->toplevel_dir, folder_name);
+ if (stat(name, &st) == -1) {
+ if (errno != ENOENT) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Could not open folder `%s':\n%s"),
+ folder_name, g_strerror (errno));
+ } else if ((flags & CAMEL_STORE_FOLDER_CREATE) == 0) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_STORE_NO_FOLDER,
+ _("Folder `%s' does not exist."),
+ folder_name);
+ } else {
+ if (creat (name, 0600) == -1) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Could not create folder `%s':\n%s"),
+ folder_name, g_strerror (errno));
+ } else {
+ folder = camel_spool_folder_new(store, folder_name, flags, ex);
+ }
+ }
+ } else if (!S_ISREG(st.st_mode)) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER,
+ _("`%s' is not a mailbox file."), name);
+ } else {
+ folder = camel_spool_folder_new(store, folder_name, flags, ex);
+ }
+ g_free(name);
+ }
+
+ return folder;
+}
+
+static CamelFolder *
+get_inbox(CamelStore *store, CamelException *ex)
+{
+ if (((CamelSpoolStore *)store)->type == CAMEL_SPOOL_STORE_MBOX)
+ return get_folder (store, "INBOX", CAMEL_STORE_FOLDER_CREATE, ex);
+ else {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER,
+ _("Store does not support an INBOX"));
+ return NULL;
+ }
+}
+
+static char *
+get_name (CamelService *service, gboolean brief)
+{
+ if (brief)
+ return g_strdup(service->url->path);
+ else
+ return g_strdup_printf(((CamelSpoolStore *)service)->type == CAMEL_SPOOL_STORE_MBOX?
+ _("Spool mail file %s"):_("Spool folder tree %s"), service->url->path);
+}
+
+/* default implementation, rename all */
+static void
+rename_folder(CamelStore *store, const char *old, const char *new, CamelException *ex)
+{
+ camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Spool folders cannot be renamed"));
+}
+
+/* default implementation, only delete metadata */
+static void
+delete_folder(CamelStore *store, const char *folder_name, CamelException *ex)
+{
+ camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Spool folders cannot be deleted"));
+}
+
+static void free_folder_info (CamelStore *store, CamelFolderInfo *fi)
+{
+ if (fi) {
+ g_free(fi->uri);
+ g_free(fi->name);
+ g_free(fi->full_name);
+ g_free(fi);
+ }
+}
+
+/* partially copied from mbox */
+static void
+spool_fill_fi(CamelStore *store, CamelFolderInfo *fi, guint32 flags)
+{
+ CamelFolder *folder;
+
+ fi->unread = -1;
+ fi->total = -1;
+ folder = camel_object_bag_get(store->folders, fi->full_name);
+ if (folder) {
+ if ((flags & CAMEL_STORE_FOLDER_INFO_FAST) == 0)
+ camel_folder_refresh_info(folder, NULL);
+ fi->unread = camel_folder_get_unread_message_count(folder);
+ fi->total = camel_folder_get_message_count(folder);
+ camel_object_unref(folder);
+ }
+}
+
+static CamelFolderInfo *
+spool_new_fi(CamelStore *store, CamelFolderInfo *parent, CamelFolderInfo **fip, const char *full, guint32 flags)
+{
+ CamelFolderInfo *fi;
+ const char *name;
+ CamelURL *url;
+
+ name = strrchr(full, '/');
+ if (name)
+ name++;
+ else
+ name = full;
+
+ fi = g_malloc0(sizeof(*fi));
+ url = camel_url_copy(((CamelService *)store)->url);
+ camel_url_set_fragment(url, full);
+ fi->uri = camel_url_to_string(url, 0);
+ camel_url_free(url);
+ fi->full_name = g_strdup(full);
+ fi->name = g_strdup(name);
+ fi->unread = -1;
+ fi->total = -1;
+ fi->flags = flags;
+
+ fi->parent = parent;
+ fi->next = *fip;
+ *fip = fi;
+
+ d(printf("Adding spoold info: '%s' '%s' '%s' '%s'\n", fi->path, fi->name, fi->full_name, fi->url));
+
+ return fi;
+}
+
+/* used to find out where we've visited already */
+struct _inode {
+ dev_t dnode;
+ ino_t inode;
+};
+
+/* returns number of records found at or below this level */
+static int scan_dir(CamelStore *store, GHashTable *visited, char *root, const char *path, guint32 flags, CamelFolderInfo *parent, CamelFolderInfo **fip, CamelException *ex)
+{
+ DIR *dir;
+ struct dirent *d;
+ char *name, *tmp, *fname;
+ CamelFolderInfo *fi = NULL;
+ struct stat st;
+ CamelFolder *folder;
+ char from[80];
+ FILE *fp;
+
+ d(printf("checking dir '%s' part '%s' for mbox content\n", root, path));
+
+ /* look for folders matching the right structure, recursively */
+ if (path) {
+ name = alloca(strlen(root) + strlen(path) + 2);
+ sprintf(name, "%s/%s", root, path);
+ } else
+ name = root;
+
+ if (stat(name, &st) == -1) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Could not scan folder `%s': %s"),
+ name, g_strerror (errno));
+ } else if (S_ISREG(st.st_mode)) {
+ /* incase we start scanning from a file. messy duplication :-/ */
+ if (path) {
+ fi = spool_new_fi(store, parent, fip, path, CAMEL_FOLDER_NOINFERIORS|CAMEL_FOLDER_NOCHILDREN);
+ spool_fill_fi(store, fi, flags);
+ }
+ return 0;
+ }
+
+ dir = opendir(name);
+ if (dir == NULL) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Could not scan folder `%s': %s"),
+ name, g_strerror (errno));
+ return -1;
+ }
+
+ if (path != NULL) {
+ fi = spool_new_fi(store, parent, fip, path, CAMEL_FOLDER_NOSELECT);
+ fip = &fi->child;
+ parent = fi;
+ }
+
+ while ( (d = readdir(dir)) ) {
+ if (strcmp(d->d_name, ".") == 0
+ || strcmp(d->d_name, "..") == 0)
+ continue;
+
+ tmp = g_strdup_printf("%s/%s", name, d->d_name);
+ if (stat(tmp, &st) == 0) {
+ if (path)
+ fname = g_strdup_printf("%s/%s", path, d->d_name);
+ else
+ fname = g_strdup(d->d_name);
+
+ if (S_ISREG(st.st_mode)) {
+ int isfolder = FALSE;
+
+ /* first, see if we already have it open */
+ folder = camel_object_bag_get(store->folders, fname);
+ if (folder == NULL) {
+ fp = fopen(tmp, "r");
+ if (fp != NULL) {
+ isfolder = (st.st_size == 0
+ || (fgets(from, sizeof(from), fp) != NULL
+ && strncmp(from, "From ", 5) == 0));
+ fclose(fp);
+ }
+ }
+
+ if (folder != NULL || isfolder) {
+ fi = spool_new_fi(store, parent, fip, fname, CAMEL_FOLDER_NOINFERIORS|CAMEL_FOLDER_NOCHILDREN);
+ spool_fill_fi(store, fi, flags);
+ }
+ if (folder)
+ camel_object_unref(folder);
+
+ } else if (S_ISDIR(st.st_mode)) {
+ struct _inode in = { st.st_dev, st.st_ino };
+
+ /* see if we've visited already */
+ if (g_hash_table_lookup(visited, &in) == NULL) {
+ struct _inode *inew = g_malloc(sizeof(*inew));
+
+ *inew = in;
+ g_hash_table_insert(visited, inew, inew);
+
+ if (scan_dir(store, visited, root, fname, flags, parent, fip, ex) == -1) {
+ g_free(tmp);
+ g_free(fname);
+ closedir(dir);
+ return -1;
+ }
+ }
+ }
+ g_free(fname);
+
+ }
+ g_free(tmp);
+ }
+ closedir(dir);
+
+ return 0;
+}
+
+static guint inode_hash(const void *d)
+{
+ const struct _inode *v = d;
+
+ return v->inode ^ v->dnode;
+}
+
+static gboolean inode_equal(const void *a, const void *b)
+{
+ const struct _inode *v1 = a, *v2 = b;
+
+ return v1->inode == v2->inode && v1->dnode == v2->dnode;
+}
+
+static void inode_free(void *k, void *v, void *d)
+{
+ g_free(k);
+}
+
+static CamelFolderInfo *
+get_folder_info_elm(CamelStore *store, const char *top, guint32 flags, CamelException *ex)
+{
+ CamelFolderInfo *fi = NULL;
+ GHashTable *visited;
+
+ visited = g_hash_table_new(inode_hash, inode_equal);
+
+ if (scan_dir(store, visited, ((CamelService *)store)->url->path, top, flags, NULL, &fi, ex) == -1 && fi != NULL) {
+ camel_store_free_folder_info_full(store, fi);
+ fi = NULL;
+ }
+
+ g_hash_table_foreach(visited, inode_free, NULL);
+ g_hash_table_destroy(visited);
+
+ return fi;
+}
+
+static CamelFolderInfo *
+get_folder_info_mbox(CamelStore *store, const char *top, guint32 flags, CamelException *ex)
+{
+ CamelFolderInfo *fi = NULL, *fip = NULL;
+
+ if (top == NULL || strcmp(top, "INBOX") == 0) {
+ fi = spool_new_fi(store, NULL, &fip, "INBOX", CAMEL_FOLDER_NOINFERIORS|CAMEL_FOLDER_NOCHILDREN|CAMEL_FOLDER_SYSTEM);
+ g_free(fi->name);
+ fi->name = g_strdup(_("Inbox"));
+ spool_fill_fi(store, fi, flags);
+ }
+
+ return fi;
+}
+
+static CamelFolderInfo *
+get_folder_info(CamelStore *store, const char *top, guint32 flags, CamelException *ex)
+{
+ if (((CamelSpoolStore *)store)->type == CAMEL_SPOOL_STORE_MBOX)
+ return get_folder_info_mbox(store, top, flags, ex);
+ else
+ return get_folder_info_elm(store, top, flags, ex);
+}
diff --git a/camel/providers/nntp/camel-nntp-folder.c b/camel/providers/nntp/camel-nntp-folder.c
new file mode 100644
index 0000000000..ffb1b29742
--- /dev/null
+++ b/camel/providers/nntp/camel-nntp-folder.c
@@ -0,0 +1,532 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* camel-nntp-folder.c : Class for a news folder
+ *
+ * Authors : Chris Toshok <toshok@ximian.com>
+ * Michael Zucchi <notzed@ximian.com>
+ *
+ * Copyright (C) 2001-2003 Ximian, Inc. (www.ximian.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "camel/camel-file-utils.h"
+#include "camel/camel-stream-mem.h"
+#include "camel/camel-data-wrapper.h"
+#include "camel/camel-mime-message.h"
+#include "camel/camel-folder-search.h"
+#include "camel/camel-exception.h"
+#include "camel/camel-session.h"
+#include "camel/camel-data-cache.h"
+
+#include "camel/camel-mime-filter-crlf.h"
+#include "camel/camel-stream-filter.h"
+#include "camel/camel-mime-message.h"
+#include "camel/camel-multipart.h"
+#include "camel/camel-mime-part.h"
+#include "camel/camel-stream-buffer.h"
+#include "camel/camel-private.h"
+
+#include "camel-nntp-summary.h"
+#include "camel-nntp-store.h"
+#include "camel-nntp-folder.h"
+#include "camel-nntp-store.h"
+#include "camel-nntp-private.h"
+
+static CamelFolderClass *folder_class = NULL;
+static CamelDiscoFolderClass *parent_class = NULL;
+
+/* Returns the class for a CamelNNTPFolder */
+#define CNNTPF_CLASS(so) CAMEL_NNTP_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so))
+#define CF_CLASS(so) CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so))
+#define CNNTPS_CLASS(so) CAMEL_STORE_CLASS (CAMEL_OBJECT_GET_CLASS(so))
+
+void
+camel_nntp_folder_selected(CamelNNTPFolder *folder, char *line, CamelException *ex)
+{
+ camel_nntp_summary_check((CamelNNTPSummary *)((CamelFolder *)folder)->summary,
+ (CamelNNTPStore *)((CamelFolder *)folder)->parent_store,
+ line, folder->changes, ex);
+}
+
+static void
+nntp_folder_refresh_info_online (CamelFolder *folder, CamelException *ex)
+{
+ CamelNNTPStore *nntp_store;
+ CamelFolderChangeInfo *changes = NULL;
+ CamelNNTPFolder *nntp_folder;
+ char *line;
+
+ nntp_store = (CamelNNTPStore *) folder->parent_store;
+ nntp_folder = (CamelNNTPFolder *) folder;
+
+ CAMEL_SERVICE_LOCK(nntp_store, connect_lock);
+
+ camel_nntp_command(nntp_store, ex, nntp_folder, &line, NULL);
+
+ if (camel_folder_change_info_changed(nntp_folder->changes)) {
+ changes = nntp_folder->changes;
+ nntp_folder->changes = camel_folder_change_info_new();
+ }
+
+ CAMEL_SERVICE_UNLOCK(nntp_store, connect_lock);
+
+ if (changes) {
+ camel_object_trigger_event ((CamelObject *) folder, "folder_changed", changes);
+ camel_folder_change_info_free (changes);
+ }
+}
+
+static void
+nntp_folder_sync_online (CamelFolder *folder, CamelException *ex)
+{
+ CAMEL_SERVICE_LOCK(folder->parent_store, connect_lock);
+ camel_folder_summary_save (folder->summary);
+ CAMEL_SERVICE_UNLOCK(folder->parent_store, connect_lock);
+}
+
+static void
+nntp_folder_sync_offline (CamelFolder *folder, CamelException *ex)
+{
+ CAMEL_SERVICE_LOCK(folder->parent_store, connect_lock);
+ camel_folder_summary_save (folder->summary);
+ CAMEL_SERVICE_UNLOCK(folder->parent_store, connect_lock);
+}
+
+static gboolean
+nntp_folder_set_message_flags (CamelFolder *folder, const char *uid, guint32 flags, guint32 set)
+{
+ return ((CamelFolderClass *) folder_class)->set_message_flags (folder, uid, flags, set);
+}
+
+static CamelStream *
+nntp_folder_download_message (CamelNNTPFolder *nntp_folder, const char *id, const char *msgid, CamelException *ex)
+{
+ CamelNNTPStore *nntp_store = (CamelNNTPStore *) ((CamelFolder *) nntp_folder)->parent_store;
+ CamelStream *stream = NULL;
+ int ret;
+ char *line;
+
+ ret = camel_nntp_command (nntp_store, ex, nntp_folder, &line, "article %s", id);
+ if (ret == 220) {
+ stream = camel_data_cache_add (nntp_store->cache, "cache", msgid, NULL);
+ if (stream) {
+ if (camel_stream_write_to_stream ((CamelStream *) nntp_store->stream, stream) == -1)
+ goto fail;
+ if (camel_stream_reset (stream) == -1)
+ goto fail;
+ } else {
+ stream = (CamelStream *) nntp_store->stream;
+ camel_object_ref (stream);
+ }
+ } else if (ret == 423 || ret == 430) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_INVALID_UID, _("Cannot get message %s: %s"), msgid, line);
+ } else if (ret != -1) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot get message %s: %s"), msgid, line);
+ }
+
+ return stream;
+
+ fail:
+ if (errno == EINTR)
+ camel_exception_setv (ex, CAMEL_EXCEPTION_USER_CANCEL, _("User cancelled"));
+ else
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot get message %s: %s"), msgid, g_strerror (errno));
+
+ return NULL;
+}
+
+
+static void
+nntp_folder_cache_message (CamelDiscoFolder *disco_folder, const char *uid, CamelException *ex)
+{
+ CamelNNTPStore *nntp_store = (CamelNNTPStore *)((CamelFolder *) disco_folder)->parent_store;
+ CamelStream *stream;
+ char *article, *msgid;
+
+ article = alloca(strlen(uid)+1);
+ strcpy(article, uid);
+ msgid = strchr(article, ',');
+ if (!msgid) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Internal error: uid in invalid format: %s"), uid);
+ return;
+ }
+ *msgid++ = 0;
+
+ CAMEL_SERVICE_LOCK(nntp_store, connect_lock);
+
+ stream = nntp_folder_download_message ((CamelNNTPFolder *) disco_folder, article, msgid, ex);
+ if (stream)
+ camel_object_unref (stream);
+
+ CAMEL_SERVICE_UNLOCK(nntp_store, connect_lock);
+}
+
+static CamelMimeMessage *
+nntp_folder_get_message (CamelFolder *folder, const char *uid, CamelException *ex)
+{
+ CamelMimeMessage *message = NULL;
+ CamelNNTPStore *nntp_store;
+ CamelFolderChangeInfo *changes;
+ CamelNNTPFolder *nntp_folder;
+ CamelStream *stream = NULL;
+ char *article, *msgid;
+
+ nntp_store = (CamelNNTPStore *) folder->parent_store;
+ nntp_folder = (CamelNNTPFolder *) folder;
+
+ article = alloca(strlen(uid)+1);
+ strcpy(article, uid);
+ msgid = strchr (article, ',');
+ if (msgid == NULL) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Internal error: uid in invalid format: %s"), uid);
+ return NULL;
+ }
+ *msgid++ = 0;
+
+ CAMEL_SERVICE_LOCK(nntp_store, connect_lock);
+
+ /* Lookup in cache, NEWS is global messageid's so use a global cache path */
+ stream = camel_data_cache_get (nntp_store->cache, "cache", msgid, NULL);
+ if (stream == NULL) {
+ if (camel_disco_store_status ((CamelDiscoStore *) nntp_store) == CAMEL_DISCO_STORE_OFFLINE) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ _("This message is not currently available"));
+ goto fail;
+ }
+
+ stream = nntp_folder_download_message (nntp_folder, article, msgid, ex);
+ if (stream == NULL)
+ goto fail;
+ }
+
+ message = camel_mime_message_new ();
+ if (camel_data_wrapper_construct_from_stream ((CamelDataWrapper *) message, stream) == -1) {
+ if (errno == EINTR)
+ camel_exception_setv (ex, CAMEL_EXCEPTION_USER_CANCEL, _("User cancelled"));
+ else
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot get message %s: %s"), uid, g_strerror (errno));
+ camel_object_unref(message);
+ message = NULL;
+ }
+
+ camel_object_unref (stream);
+fail:
+ if (camel_folder_change_info_changed (nntp_folder->changes)) {
+ changes = nntp_folder->changes;
+ nntp_folder->changes = camel_folder_change_info_new ();
+ } else {
+ changes = NULL;
+ }
+
+ CAMEL_SERVICE_UNLOCK(nntp_store, connect_lock);
+
+ if (changes) {
+ camel_object_trigger_event ((CamelObject *) folder, "folder_changed", changes);
+ camel_folder_change_info_free (changes);
+ }
+
+ return message;
+}
+
+static GPtrArray*
+nntp_folder_search_by_expression (CamelFolder *folder, const char *expression, CamelException *ex)
+{
+ CamelNNTPFolder *nntp_folder = CAMEL_NNTP_FOLDER (folder);
+ GPtrArray *matches;
+
+ CAMEL_NNTP_FOLDER_LOCK(nntp_folder, search_lock);
+
+ if (nntp_folder->search == NULL)
+ nntp_folder->search = camel_folder_search_new ();
+
+ camel_folder_search_set_folder (nntp_folder->search, folder);
+ matches = camel_folder_search_search(nntp_folder->search, expression, NULL, ex);
+
+ CAMEL_NNTP_FOLDER_UNLOCK(nntp_folder, search_lock);
+
+ return matches;
+}
+
+static GPtrArray *
+nntp_folder_search_by_uids (CamelFolder *folder, const char *expression, GPtrArray *uids, CamelException *ex)
+{
+ CamelNNTPFolder *nntp_folder = (CamelNNTPFolder *) folder;
+ GPtrArray *matches;
+
+ if (uids->len == 0)
+ return g_ptr_array_new();
+
+ CAMEL_NNTP_FOLDER_LOCK(folder, search_lock);
+
+ if (nntp_folder->search == NULL)
+ nntp_folder->search = camel_folder_search_new ();
+
+ camel_folder_search_set_folder (nntp_folder->search, folder);
+ matches = camel_folder_search_search(nntp_folder->search, expression, uids, ex);
+
+ CAMEL_NNTP_FOLDER_UNLOCK(folder, search_lock);
+
+ return matches;
+}
+
+static void
+nntp_folder_search_free (CamelFolder *folder, GPtrArray *result)
+{
+ CamelNNTPFolder *nntp_folder = CAMEL_NNTP_FOLDER (folder);
+
+ camel_folder_search_free_result (nntp_folder->search, result);
+}
+
+static void
+nntp_folder_append_message_online (CamelFolder *folder, CamelMimeMessage *mime_message,
+ const CamelMessageInfo *info, char **appended_uid,
+ CamelException *ex)
+{
+ CamelNNTPStore *nntp_store = (CamelNNTPStore *) folder->parent_store;
+ CamelStream *stream = (CamelStream*)nntp_store->stream;
+ CamelStreamFilter *filtered_stream;
+ CamelMimeFilter *crlffilter;
+ int ret;
+ unsigned int u;
+ struct _camel_header_raw *header, *savedhdrs, *n, *tail;
+ char *group, *line;
+
+ CAMEL_SERVICE_LOCK(nntp_store, connect_lock);
+
+ /* send 'POST' command */
+ ret = camel_nntp_command (nntp_store, ex, NULL, &line, "post");
+ if (ret != 340) {
+ if (ret == 440)
+ camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_INSUFFICIENT_PERMISSION,
+ _("Posting failed: %s"), line);
+ else if (ret != -1)
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Posting failed: %s"), line);
+ CAMEL_SERVICE_UNLOCK(nntp_store, connect_lock);
+ return;
+ }
+
+ /* the 'Newsgroups: ' header */
+ group = g_strdup_printf ("Newsgroups: %s\r\n", folder->full_name);
+
+ /* setup stream filtering */
+ crlffilter = camel_mime_filter_crlf_new (CAMEL_MIME_FILTER_CRLF_ENCODE, CAMEL_MIME_FILTER_CRLF_MODE_CRLF_DOTS);
+ filtered_stream = camel_stream_filter_new_with_stream (stream);
+ camel_stream_filter_add (filtered_stream, crlffilter);
+ camel_object_unref (crlffilter);
+
+ /* remove mail 'To', 'CC', and 'BCC' headers */
+ savedhdrs = NULL;
+ tail = (struct _camel_header_raw *) &savedhdrs;
+
+ header = (struct _camel_header_raw *) &CAMEL_MIME_PART (mime_message)->headers;
+ n = header->next;
+ while (n != NULL) {
+ if (!g_ascii_strcasecmp (n->name, "To") || !g_ascii_strcasecmp (n->name, "Cc") || !g_ascii_strcasecmp (n->name, "Bcc")) {
+ header->next = n->next;
+ tail->next = n;
+ n->next = NULL;
+ tail = n;
+ } else {
+ header = n;
+ }
+
+ n = header->next;
+ }
+
+ /* write the message */
+ if (camel_stream_write(stream, group, strlen(group)) == -1
+ || camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (mime_message), CAMEL_STREAM (filtered_stream)) == -1
+ || camel_stream_flush (CAMEL_STREAM (filtered_stream)) == -1
+ || camel_stream_write (stream, "\r\n.\r\n", 5) == -1
+ || (ret = camel_nntp_stream_line (nntp_store->stream, (unsigned char **)&line, &u)) == -1) {
+ if (errno == EINTR)
+ camel_exception_setv (ex, CAMEL_EXCEPTION_USER_CANCEL, _("User cancelled"));
+ else
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, _("Posting failed: %s"), g_strerror (errno));
+ } else if (atoi(line) != 240) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, _("Posting failed: %s"), line);
+ }
+
+ camel_object_unref (filtered_stream);
+ g_free(group);
+ header->next = savedhdrs;
+
+ CAMEL_SERVICE_UNLOCK(nntp_store, connect_lock);
+
+ return;
+}
+
+static void
+nntp_folder_append_message_offline (CamelFolder *folder, CamelMimeMessage *mime_message,
+ const CamelMessageInfo *info, char **appended_uid,
+ CamelException *ex)
+{
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ _("You cannot post NNTP messages while working offline!"));
+}
+
+/* I do not know what to do this exactly. Looking at the IMAP implementation for this, it
+ seems to assume the message is copied to a folder on the same store. In that case, an
+ NNTP implementation doesn't seem to make any sense. */
+static void
+nntp_folder_transfer_message (CamelFolder *source, GPtrArray *uids, CamelFolder *dest,
+ GPtrArray **transferred_uids, gboolean delete_orig, CamelException *ex)
+{
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ _("You cannot copy messages from a NNTP folder!"));
+}
+
+static void
+nntp_folder_init (CamelNNTPFolder *nntp_folder, CamelNNTPFolderClass *klass)
+{
+ struct _CamelNNTPFolderPrivate *p;
+
+ nntp_folder->changes = camel_folder_change_info_new ();
+ p = nntp_folder->priv = g_malloc0 (sizeof (*nntp_folder->priv));
+ p->search_lock = g_mutex_new ();
+ p->cache_lock = g_mutex_new ();
+}
+
+static void
+nntp_folder_finalise (CamelNNTPFolder *nntp_folder)
+{
+ struct _CamelNNTPFolderPrivate *p;
+
+ camel_folder_summary_save (((CamelFolder*) nntp_folder)->summary);
+
+ p = nntp_folder->priv;
+ g_mutex_free (p->search_lock);
+ g_mutex_free (p->cache_lock);
+ g_free (p);
+}
+
+static void
+nntp_folder_class_init (CamelNNTPFolderClass *camel_nntp_folder_class)
+{
+ CamelDiscoFolderClass *camel_disco_folder_class = CAMEL_DISCO_FOLDER_CLASS (camel_nntp_folder_class);
+ CamelFolderClass *camel_folder_class = CAMEL_FOLDER_CLASS (camel_nntp_folder_class);
+
+ parent_class = CAMEL_DISCO_FOLDER_CLASS (camel_type_get_global_classfuncs (camel_disco_folder_get_type ()));
+ folder_class = CAMEL_FOLDER_CLASS (camel_type_get_global_classfuncs (camel_folder_get_type ()));
+
+ /* virtual method definition */
+
+ /* virtual method overload */
+ camel_disco_folder_class->sync_online = nntp_folder_sync_online;
+ camel_disco_folder_class->sync_resyncing = nntp_folder_sync_offline;
+ camel_disco_folder_class->sync_offline = nntp_folder_sync_offline;
+ camel_disco_folder_class->cache_message = nntp_folder_cache_message;
+ camel_disco_folder_class->append_online = nntp_folder_append_message_online;
+ camel_disco_folder_class->append_resyncing = nntp_folder_append_message_online;
+ camel_disco_folder_class->append_offline = nntp_folder_append_message_offline;
+ camel_disco_folder_class->transfer_online = nntp_folder_transfer_message;
+ camel_disco_folder_class->transfer_resyncing = nntp_folder_transfer_message;
+ camel_disco_folder_class->transfer_offline = nntp_folder_transfer_message;
+ camel_disco_folder_class->refresh_info_online = nntp_folder_refresh_info_online;
+
+ camel_folder_class->set_message_flags = nntp_folder_set_message_flags;
+ camel_folder_class->get_message = nntp_folder_get_message;
+ camel_folder_class->search_by_expression = nntp_folder_search_by_expression;
+ camel_folder_class->search_by_uids = nntp_folder_search_by_uids;
+ camel_folder_class->search_free = nntp_folder_search_free;
+}
+
+CamelType
+camel_nntp_folder_get_type (void)
+{
+ static CamelType camel_nntp_folder_type = CAMEL_INVALID_TYPE;
+
+ if (camel_nntp_folder_type == CAMEL_INVALID_TYPE) {
+ camel_nntp_folder_type = camel_type_register (CAMEL_DISCO_FOLDER_TYPE, "CamelNNTPFolder",
+ sizeof (CamelNNTPFolder),
+ sizeof (CamelNNTPFolderClass),
+ (CamelObjectClassInitFunc) nntp_folder_class_init,
+ NULL,
+ (CamelObjectInitFunc) nntp_folder_init,
+ (CamelObjectFinalizeFunc) nntp_folder_finalise);
+ }
+
+ return camel_nntp_folder_type;
+}
+
+CamelFolder *
+camel_nntp_folder_new (CamelStore *parent, const char *folder_name, CamelException *ex)
+{
+ CamelFolder *folder;
+ CamelNNTPFolder *nntp_folder;
+ char *root;
+ CamelService *service;
+ CamelStoreInfo *si;
+ gboolean subscribed = TRUE;
+
+ service = (CamelService *) parent;
+ root = camel_session_get_storage_path (service->session, service, ex);
+ if (root == NULL)
+ return NULL;
+
+ /* If this doesn't work, stuff wont save, but let it continue anyway */
+ camel_mkdir (root, 0777);
+
+ folder = (CamelFolder *) camel_object_new (CAMEL_NNTP_FOLDER_TYPE);
+ nntp_folder = (CamelNNTPFolder *)folder;
+
+ camel_folder_construct (folder, parent, folder_name, folder_name);
+ folder->folder_flags |= CAMEL_FOLDER_HAS_SUMMARY_CAPABILITY|CAMEL_FOLDER_HAS_SEARCH_CAPABILITY;
+
+ nntp_folder->storage_path = g_build_filename (root, folder->full_name, NULL);
+ g_free (root);
+
+ root = g_strdup_printf ("%s.cmeta", nntp_folder->storage_path);
+ camel_object_set(nntp_folder, NULL, CAMEL_OBJECT_STATE_FILE, root, NULL);
+ camel_object_state_read(nntp_folder);
+ g_free(root);
+
+ root = g_strdup_printf("%s.ev-summary", nntp_folder->storage_path);
+ folder->summary = (CamelFolderSummary *) camel_nntp_summary_new (root);
+ g_free(root);
+ camel_folder_summary_load (folder->summary);
+
+ si = camel_store_summary_path ((CamelStoreSummary *) ((CamelNNTPStore*) parent)->summary, folder_name);
+ if (si) {
+ subscribed = (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) != 0;
+ camel_store_summary_info_free ((CamelStoreSummary *) ((CamelNNTPStore*) parent)->summary, si);
+ }
+
+ if (subscribed) {
+ camel_folder_refresh_info(folder, ex);
+ if (camel_exception_is_set(ex)) {
+ camel_object_unref (folder);
+ folder = NULL;
+ }
+ }
+
+ return folder;
+}
diff --git a/camel/providers/nntp/camel-nntp-private.h b/camel/providers/nntp/camel-nntp-private.h
new file mode 100644
index 0000000000..253d4e2031
--- /dev/null
+++ b/camel/providers/nntp/camel-nntp-private.h
@@ -0,0 +1,64 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ * camel-nntp-private.h: Private info for nntp.
+ *
+ * Authors: Michael Zucchi <notzed@ximian.com>
+ *
+ * Copyright 1999, 2000 Ximian, Inc. (www.ximian.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#ifndef CAMEL_NNTP_PRIVATE_H
+#define CAMEL_NNTP_PRIVATE_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif /* __cplusplus */
+
+/* need a way to configure and save this data, if this header is to
+ be installed. For now, dont install it */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-util/e-msgport.h"
+
+struct _CamelNNTPStorePrivate {
+ int dummy;
+};
+
+#define CAMEL_NNTP_STORE_LOCK(f, l) (e_mutex_lock(((CamelNNTPStore *)f)->priv->l))
+#define CAMEL_NNTP_STORE_UNLOCK(f, l) (e_mutex_unlock(((CamelNNTPStore *)f)->priv->l))
+
+
+struct _CamelNNTPFolderPrivate {
+ GMutex *search_lock; /* for locking the search object */
+ GMutex *cache_lock; /* for locking the cache object */
+};
+
+#define CAMEL_NNTP_FOLDER_LOCK(f, l) (g_mutex_lock(((CamelNNTPFolder *)f)->priv->l))
+#define CAMEL_NNTP_FOLDER_UNLOCK(f, l) (g_mutex_unlock(((CamelNNTPFolder *)f)->priv->l))
+#else
+#define CAMEL_NNTP_FOLDER_LOCK(f, l)
+#define CAMEL_NNTP_FOLDER_UNLOCK(f, l)
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* CAMEL_NNTP_PRIVATE_H */
+
diff --git a/camel/providers/nntp/camel-nntp-store.c b/camel/providers/nntp/camel-nntp-store.c
new file mode 100644
index 0000000000..aa8541dc97
--- /dev/null
+++ b/camel/providers/nntp/camel-nntp-store.c
@@ -0,0 +1,1408 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ *
+ * Copyright (C) 2001-2003 Ximian, Inc. <www.ximain.com>
+ *
+ * Authors: Christopher Toshok <toshok@ximian.com>
+ * Michael Zucchi <notzed@ximian.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <errno.h>
+
+#include <camel/camel-url.h>
+#include <camel/camel-string-utils.h>
+#include <camel/camel-session.h>
+#include <camel/camel-tcp-stream-raw.h>
+#include <camel/camel-tcp-stream-ssl.h>
+
+#include <camel/camel-stream-mem.h>
+#include <camel/camel-data-cache.h>
+
+#include <camel/camel-disco-store.h>
+#include <camel/camel-disco-diary.h>
+#include "camel/camel-private.h"
+#include <camel/camel-debug.h>
+
+#include "camel-nntp-summary.h"
+#include "camel-nntp-store.h"
+#include "camel-nntp-store-summary.h"
+#include "camel-nntp-folder.h"
+#include "camel-nntp-private.h"
+#include "camel-nntp-resp-codes.h"
+
+#define w(x)
+#define dd(x) (camel_debug("nntp")?(x):0)
+
+#define NNTP_PORT "119"
+#define NNTPS_PORT "563"
+
+#define DUMP_EXTENSIONS
+
+static CamelDiscoStoreClass *parent_class = NULL;
+static CamelServiceClass *service_class = NULL;
+
+/* Returns the class for a CamelNNTPStore */
+#define CNNTPS_CLASS(so) CAMEL_NNTP_STORE_CLASS (CAMEL_OBJECT_GET_CLASS(so))
+#define CF_CLASS(so) CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so))
+#define CNNTPF_CLASS(so) CAMEL_NNTP_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so))
+
+static int camel_nntp_try_authenticate (CamelNNTPStore *store, CamelException *ex);
+
+static void nntp_construct (CamelService *service, CamelSession *session,
+ CamelProvider *provider, CamelURL *url,
+ CamelException *ex);
+
+
+static gboolean
+nntp_can_work_offline(CamelDiscoStore *store)
+{
+ return TRUE;
+}
+
+enum {
+ USE_SSL_NEVER,
+ USE_SSL_ALWAYS,
+ USE_SSL_WHEN_POSSIBLE
+};
+
+static struct {
+ const char *name;
+ int type;
+} headers[] = {
+ { "subject", 0 },
+ { "from", 0 },
+ { "date", 0 },
+ { "message-id", 1 },
+ { "references", 0 },
+ { "bytes", 2 },
+};
+
+static int
+xover_setup(CamelNNTPStore *store, CamelException *ex)
+{
+ int ret, i;
+ char *line;
+ unsigned int len;
+ unsigned char c, *p;
+ struct _xover_header *xover, *last;
+
+ /* manual override */
+ if (store->xover || getenv("CAMEL_NNTP_DISABLE_XOVER") != NULL)
+ return 0;
+
+ ret = camel_nntp_raw_command_auth(store, ex, &line, "list overview.fmt");
+ if (ret == -1) {
+ return -1;
+ } else if (ret != 215)
+ /* unsupported command? ignore */
+ return 0;
+
+ last = (struct _xover_header *)&store->xover;
+
+ /* supported command */
+ while ((ret = camel_nntp_stream_line(store->stream, (unsigned char **)&line, &len)) > 0) {
+ p = line;
+ xover = g_malloc0(sizeof(*xover));
+ last->next = xover;
+ last = xover;
+ while ((c = *p++)) {
+ if (c == ':') {
+ p[-1] = 0;
+ for (i=0;i<sizeof(headers)/sizeof(headers[0]);i++) {
+ if (strcmp(line, headers[i].name) == 0) {
+ xover->name = headers[i].name;
+ if (strncmp(p, "full", 4) == 0)
+ xover->skip = strlen(xover->name)+1;
+ else
+ xover->skip = 0;
+ xover->type = headers[i].type;
+ break;
+ }
+ }
+ break;
+ } else {
+ p[-1] = camel_tolower(c);
+ }
+ }
+ }
+
+ return ret;
+}
+
+static gboolean
+connect_to_server (CamelService *service, int ssl_mode, CamelException *ex)
+{
+ CamelNNTPStore *store = (CamelNNTPStore *) service;
+ CamelDiscoStore *disco_store = (CamelDiscoStore*) service;
+ CamelStream *tcp_stream;
+ gboolean retval = FALSE;
+ unsigned char *buf;
+ unsigned int len;
+ int ret;
+ char *path;
+ struct addrinfo *ai, hints = { 0 };
+ char *serv;
+ const char *port = NULL;
+
+ CAMEL_SERVICE_LOCK(store, connect_lock);
+
+ /* setup store-wide cache */
+ if (store->cache == NULL) {
+ if (store->storage_path == NULL)
+ goto fail;
+
+ store->cache = camel_data_cache_new (store->storage_path, 0, ex);
+ if (store->cache == NULL)
+ goto fail;
+
+ /* Default cache expiry - 2 weeks old, or not visited in 5 days */
+ camel_data_cache_set_expire_age (store->cache, 60*60*24*14);
+ camel_data_cache_set_expire_access (store->cache, 60*60*24*5);
+ }
+
+ if (service->url->port) {
+ serv = g_alloca(16);
+ sprintf(serv, "%d", service->url->port);
+ } else {
+ serv = "nntp";
+ port = NNTP_PORT;
+ }
+
+#ifdef HAVE_SSL
+ if (ssl_mode != USE_SSL_NEVER) {
+ if (service->url->port == 0) {
+ serv = "nntps";
+ port = NNTPS_PORT;
+ }
+ tcp_stream = camel_tcp_stream_ssl_new (service->session, service->url->host, CAMEL_TCP_STREAM_SSL_ENABLE_SSL2 | CAMEL_TCP_STREAM_SSL_ENABLE_SSL3);
+ } else {
+ tcp_stream = camel_tcp_stream_raw_new ();
+ }
+#else
+ tcp_stream = camel_tcp_stream_raw_new ();
+#endif /* HAVE_SSL */
+
+ hints.ai_socktype = SOCK_STREAM;
+ ai = camel_getaddrinfo(service->url->host, serv, &hints, ex);
+ if (ai == NULL && port != NULL && camel_exception_get_id(ex) != CAMEL_EXCEPTION_USER_CANCEL) {
+ camel_exception_clear(ex);
+ ai = camel_getaddrinfo(service->url->host, port, &hints, ex);
+ }
+ if (ai == NULL) {
+ camel_object_unref(tcp_stream);
+ goto fail;
+ }
+
+ ret = camel_tcp_stream_connect(CAMEL_TCP_STREAM(tcp_stream), ai);
+ camel_freeaddrinfo(ai);
+ if (ret == -1) {
+ if (errno == EINTR)
+ camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL,
+ _("Connection cancelled"));
+ else
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ _("Could not connect to %s (port %s): %s"),
+ service->url->host, serv, g_strerror (errno));
+
+ camel_object_unref (tcp_stream);
+
+ goto fail;
+ }
+
+ store->stream = (CamelNNTPStream *) camel_nntp_stream_new (tcp_stream);
+ camel_object_unref (tcp_stream);
+
+ /* Read the greeting, if any. */
+ if (camel_nntp_stream_line (store->stream, &buf, &len) == -1) {
+ if (errno == EINTR)
+ camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL,
+ _("Connection cancelled"));
+ else
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ _("Could not read greeting from %s: %s"),
+ service->url->host, g_strerror (errno));
+
+ camel_object_unref (store->stream);
+ store->stream = NULL;
+
+ goto fail;
+ }
+
+ len = strtoul (buf, (char **) &buf, 10);
+ if (len != 200 && len != 201) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("NNTP server %s returned error code %d: %s"),
+ service->url->host, len, buf);
+
+ camel_object_unref (store->stream);
+ store->stream = NULL;
+
+ goto fail;
+ }
+
+ /* if we have username, try it here */
+ if (service->url->user != NULL
+ && camel_nntp_try_authenticate(store, ex) != NNTP_AUTH_ACCEPTED)
+ goto fail;
+
+ /* set 'reader' mode & ignore return code, also ping the server, inn goes offline very quickly otherwise */
+ if (camel_nntp_raw_command_auth (store, ex, (char **) &buf, "mode reader") == -1
+ || camel_nntp_raw_command_auth (store, ex, (char **) &buf, "date") == -1)
+ goto fail;
+
+ if (xover_setup(store, ex) == -1)
+ goto fail;
+
+ path = g_build_filename (store->storage_path, ".ev-journal", NULL);
+ disco_store->diary = camel_disco_diary_new (disco_store, path, ex);
+ g_free (path);
+
+ retval = TRUE;
+
+ g_free(store->current_folder);
+ store->current_folder = NULL;
+
+ fail:
+ CAMEL_SERVICE_UNLOCK(store, connect_lock);
+ return retval;
+}
+
+static struct {
+ char *value;
+ int mode;
+} ssl_options[] = {
+ { "", USE_SSL_ALWAYS },
+ { "always", USE_SSL_ALWAYS },
+ { "when-possible", USE_SSL_WHEN_POSSIBLE },
+ { "never", USE_SSL_NEVER },
+ { NULL, USE_SSL_NEVER },
+};
+
+static gboolean
+nntp_connect_online (CamelService *service, CamelException *ex)
+{
+#ifdef HAVE_SSL
+ const char *use_ssl;
+ int i, ssl_mode;
+
+ use_ssl = camel_url_get_param (service->url, "use_ssl");
+ if (use_ssl) {
+ for (i = 0; ssl_options[i].value; i++)
+ if (!strcmp (ssl_options[i].value, use_ssl))
+ break;
+ ssl_mode = ssl_options[i].mode;
+ } else
+ ssl_mode = USE_SSL_NEVER;
+
+ if (ssl_mode == USE_SSL_ALWAYS) {
+ /* Connect via SSL */
+ return connect_to_server (service, ssl_mode, ex);
+ } else if (ssl_mode == USE_SSL_WHEN_POSSIBLE) {
+ /* If the server supports SSL, use it */
+ if (!connect_to_server (service, ssl_mode, ex)) {
+ if (camel_exception_get_id (ex) == CAMEL_EXCEPTION_SERVICE_UNAVAILABLE) {
+ /* The ssl port seems to be unavailable, fall back to plain NNTP */
+ camel_exception_clear (ex);
+ return connect_to_server (service, USE_SSL_NEVER, ex);
+ } else {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+ } else {
+ /* User doesn't care about SSL */
+ return connect_to_server (service, ssl_mode, ex);
+ }
+#else
+ return connect_to_server (service, USE_SSL_NEVER, ex);
+#endif
+}
+
+static gboolean
+nntp_connect_offline (CamelService *service, CamelException *ex)
+{
+ CamelNNTPStore *nntp_store = CAMEL_NNTP_STORE(service);
+ CamelDiscoStore *disco_store = (CamelDiscoStore *) nntp_store;
+ char *path;
+
+ if (nntp_store->storage_path == NULL)
+ return FALSE;
+
+ /* setup store-wide cache */
+ if (nntp_store->cache == NULL) {
+ nntp_store->cache = camel_data_cache_new (nntp_store->storage_path, 0, ex);
+ if (nntp_store->cache == NULL)
+ return FALSE;
+
+ /* Default cache expiry - 2 weeks old, or not visited in 5 days */
+ camel_data_cache_set_expire_age (nntp_store->cache, 60*60*24*14);
+ camel_data_cache_set_expire_access (nntp_store->cache, 60*60*24*5);
+ }
+
+ path = g_build_filename (nntp_store->storage_path, ".ev-journal", NULL);
+ disco_store->diary = camel_disco_diary_new (disco_store, path, ex);
+ g_free (path);
+
+ if (!disco_store->diary)
+ return FALSE;
+
+ return TRUE;
+}
+
+static gboolean
+nntp_disconnect_online (CamelService *service, gboolean clean, CamelException *ex)
+{
+ CamelNNTPStore *store = CAMEL_NNTP_STORE (service);
+ char *line;
+
+ CAMEL_SERVICE_LOCK(store, connect_lock);
+
+ if (clean) {
+ camel_nntp_raw_command (store, ex, &line, "quit");
+ camel_exception_clear(ex);
+ }
+
+ if (!service_class->disconnect (service, clean, ex)) {
+ CAMEL_SERVICE_UNLOCK(store, connect_lock);
+ return FALSE;
+ }
+
+ camel_object_unref (store->stream);
+ store->stream = NULL;
+ g_free(store->current_folder);
+ store->current_folder = NULL;
+
+ CAMEL_SERVICE_UNLOCK(store, connect_lock);
+
+ return TRUE;
+}
+
+static gboolean
+nntp_disconnect_offline (CamelService *service, gboolean clean, CamelException *ex)
+{
+ CamelDiscoStore *disco = CAMEL_DISCO_STORE(service);
+
+ if (!service_class->disconnect (service, clean, ex))
+ return FALSE;
+
+ if (disco->diary) {
+ camel_object_unref (disco->diary);
+ disco->diary = NULL;
+ }
+
+ return TRUE;
+}
+
+static char *
+nntp_store_get_name (CamelService *service, gboolean brief)
+{
+ if (brief)
+ return g_strdup_printf ("%s", service->url->host);
+ else
+ return g_strdup_printf (_("USENET News via %s"), service->url->host);
+
+}
+
+extern CamelServiceAuthType camel_nntp_password_authtype;
+
+static GList *
+nntp_store_query_auth_types (CamelService *service, CamelException *ex)
+{
+ return g_list_append (NULL, &camel_nntp_password_authtype);
+}
+
+static CamelFolder *
+nntp_get_folder(CamelStore *store, const char *folder_name, guint32 flags, CamelException *ex)
+{
+ CamelNNTPStore *nntp_store = CAMEL_NNTP_STORE (store);
+ CamelFolder *folder;
+
+ CAMEL_SERVICE_LOCK(nntp_store, connect_lock);
+
+ folder = camel_nntp_folder_new(store, folder_name, ex);
+
+ CAMEL_SERVICE_UNLOCK(nntp_store, connect_lock);
+
+ return folder;
+}
+
+/*
+ * Converts a fully-fledged newsgroup name to a name in short dotted notation,
+ * e.g. nl.comp.os.linux.programmeren becomes n.c.o.l.programmeren
+ */
+
+static char *
+nntp_newsgroup_name_short (const char *name)
+{
+ char *resptr, *tmp;
+ const char *ptr2;
+
+ resptr = tmp = g_malloc0 (strlen (name) + 1);
+
+ while ((ptr2 = strchr (name, '.'))) {
+ if (ptr2 == name) {
+ name++;
+ continue;
+ }
+
+ *resptr++ = *name;
+ *resptr++ = '.';
+ name = ptr2 + 1;
+ }
+
+ strcpy (resptr, name);
+ return tmp;
+}
+
+/*
+ * This function converts a NNTPStoreSummary item to a FolderInfo item that
+ * can be returned by the get_folders() call to the store. Both structs have
+ * essentially the same fields.
+ */
+
+static CamelFolderInfo *
+nntp_folder_info_from_store_info (CamelNNTPStore *store, gboolean short_notation, CamelStoreInfo *si)
+{
+ CamelURL *base_url = ((CamelService *) store)->url;
+ CamelFolderInfo *fi = g_malloc0(sizeof(*fi));
+ CamelURL *url;
+ char *path;
+
+ fi->full_name = g_strdup (si->path);
+
+ if (short_notation)
+ fi->name = nntp_newsgroup_name_short (si->path);
+ else
+ fi->name = g_strdup (si->path);
+
+ fi->unread = si->unread;
+ fi->total = si->total;
+ path = alloca(strlen(fi->full_name)+2);
+ sprintf(path, "/%s", fi->full_name);
+ url = camel_url_new_with_base (base_url, path);
+ fi->uri = camel_url_to_string (url, CAMEL_URL_HIDE_ALL);
+ camel_url_free (url);
+
+ return fi;
+}
+
+static CamelFolderInfo *
+nntp_folder_info_from_name (CamelNNTPStore *store, gboolean short_notation, const char *name)
+{
+ CamelFolderInfo *fi = g_malloc0(sizeof(*fi));
+ CamelURL *base_url = ((CamelService *)store)->url;
+ CamelURL *url;
+ char *path;
+
+ fi->full_name = g_strdup (name);
+
+ if (short_notation)
+ fi->name = nntp_newsgroup_name_short (name);
+ else
+ fi->name = g_strdup (name);
+
+ fi->unread = -1;
+
+ path = alloca(strlen(fi->full_name)+2);
+ sprintf(path, "/%s", fi->full_name);
+ url = camel_url_new_with_base (base_url, path);
+ fi->uri = camel_url_to_string (url, CAMEL_URL_HIDE_ALL);
+ camel_url_free (url);
+
+ return fi;
+}
+
+/* handle list/newgroups response */
+static CamelNNTPStoreInfo *
+nntp_store_info_update(CamelNNTPStore *store, char *line)
+{
+ CamelStoreSummary *summ = (CamelStoreSummary *)store->summary;
+ CamelURL *base_url = ((CamelService *)store)->url;
+ CamelNNTPStoreInfo *si, *fsi;
+ CamelURL *url;
+ char *relpath, *tmp;
+ guint32 last = 0, first = 0, new = 0;
+
+ tmp = strchr(line, ' ');
+ if (tmp)
+ *tmp++ = 0;
+
+ fsi = si = (CamelNNTPStoreInfo *)camel_store_summary_path((CamelStoreSummary *)store->summary, line);
+ if (si == NULL) {
+ si = (CamelNNTPStoreInfo*)camel_store_summary_info_new(summ);
+
+ relpath = g_alloca(strlen(line)+2);
+ sprintf(relpath, "/%s", line);
+ url = camel_url_new_with_base (base_url, relpath);
+ si->info.uri = camel_url_to_string (url, CAMEL_URL_HIDE_ALL);
+ camel_url_free (url);
+
+ si->info.path = g_strdup (line);
+ si->full_name = g_strdup (line); /* why do we keep this? */
+ camel_store_summary_add((CamelStoreSummary *)store->summary, &si->info);
+ } else {
+ first = si->first;
+ last = si->last;
+ }
+
+ if (tmp && *tmp >= '0' && *tmp <= '9') {
+ last = strtoul(tmp, &tmp, 10);
+ if (*tmp == ' ' && tmp[1] >= '0' && tmp[1] <= '9') {
+ first = strtoul(tmp+1, &tmp, 10);
+ if (*tmp == ' ' && tmp[1] != 'y')
+ si->info.flags |= CAMEL_STORE_INFO_FOLDER_READONLY;
+ }
+ }
+
+ printf("store info update '%s' first '%d' last '%d'\n", line, first, last);
+
+ if (si->last) {
+ if (last > si->last)
+ new = last-si->last;
+ } else {
+ if (last > first)
+ new = last - first;
+ }
+
+ si->info.total = last > first?last-first:0;
+ si->info.unread += new; /* this is a _guess_ */
+ si->last = last;
+ si->first = first;
+
+ if (fsi)
+ camel_store_summary_info_free((CamelStoreSummary *)store->summary, &fsi->info);
+ else /* TODO see if we really did touch it */
+ camel_store_summary_touch ((CamelStoreSummary *)store->summary);
+
+ return si;
+}
+
+static CamelFolderInfo *
+nntp_store_get_subscribed_folder_info (CamelNNTPStore *store, const char *top, guint flags, CamelException *ex)
+{
+ int i;
+ CamelStoreInfo *si;
+ CamelFolderInfo *first = NULL, *last = NULL, *fi = NULL;
+
+ /* since we do not do a tree, any request that is not for root is sure to give no results */
+ if (top != NULL && top[0] != 0)
+ return NULL;
+
+ for (i=0;(si = camel_store_summary_index ((CamelStoreSummary *) store->summary, i));i++) {
+ if (si == NULL)
+ continue;
+
+ if (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) {
+ /* slow mode? open and update the folder, always! this will implictly update
+ our storeinfo too; in a very round-about way */
+ if ((flags & CAMEL_STORE_FOLDER_INFO_FAST) == 0) {
+ CamelNNTPFolder *folder;
+ char *line;
+
+ folder = (CamelNNTPFolder *)camel_store_get_folder((CamelStore *)store, si->path, 0, ex);
+ if (folder) {
+ CamelFolderChangeInfo *changes = NULL;
+
+ CAMEL_SERVICE_LOCK(store, connect_lock);
+ camel_nntp_command(store, ex, folder, &line, NULL);
+ if (camel_folder_change_info_changed(folder->changes)) {
+ changes = folder->changes;
+ folder->changes = camel_folder_change_info_new();
+ }
+ CAMEL_SERVICE_UNLOCK(store, connect_lock);
+ if (changes) {
+ camel_object_trigger_event((CamelObject *) folder, "folder_changed", changes);
+ camel_folder_change_info_free(changes);
+ }
+ camel_object_unref(folder);
+ }
+ camel_exception_clear(ex);
+ }
+ fi = nntp_folder_info_from_store_info (store, store->do_short_folder_notation, si);
+ fi->flags |= CAMEL_FOLDER_NOINFERIORS | CAMEL_FOLDER_NOCHILDREN | CAMEL_FOLDER_SYSTEM;
+ if (last)
+ last->next = fi;
+ else
+ first = fi;
+ last = fi;
+ }
+ camel_store_summary_info_free ((CamelStoreSummary *) store->summary, si);
+ }
+
+ return first;
+}
+
+/*
+ * get folder info, using the information in our StoreSummary
+ */
+static CamelFolderInfo *
+nntp_store_get_cached_folder_info (CamelNNTPStore *store, const char *orig_top, guint flags, CamelException *ex)
+{
+ int i;
+ int subscribed_or_flag = (flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED) ? 0 : 1,
+ root_or_flag = (orig_top == NULL || orig_top[0] == '\0') ? 1 : 0,
+ recursive_flag = flags & CAMEL_STORE_FOLDER_INFO_RECURSIVE;
+ CamelStoreInfo *si;
+ CamelFolderInfo *first = NULL, *last = NULL, *fi = NULL;
+ char *tmpname;
+ char *top = g_strconcat(orig_top?orig_top:"", ".", NULL);
+ int toplen = strlen(top);
+
+ for (i = 0; (si = camel_store_summary_index ((CamelStoreSummary *) store->summary, i)); i++) {
+ if ((subscribed_or_flag || (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED))
+ && (root_or_flag || strncmp (si->path, top, toplen) == 0)) {
+ if (recursive_flag || strchr (si->path + toplen, '.') == NULL) {
+ /* add the item */
+ fi = nntp_folder_info_from_store_info(store, FALSE, si);
+ if (!fi)
+ continue;
+ if (store->folder_hierarchy_relative) {
+ g_free (fi->name);
+ fi->name = g_strdup (si->path + ((toplen == 1) ? 0 : toplen));
+ }
+ } else {
+ /* apparently, this is an indirect subitem. if it's not a subitem of
+ the item we added last, we need to add a portion of this item to
+ the list as a placeholder */
+ if (!last ||
+ strncmp(si->path, last->full_name, strlen(last->full_name)) != 0 ||
+ si->path[strlen(last->full_name)] != '.') {
+ tmpname = g_strdup(si->path);
+ *(strchr(tmpname + toplen, '.')) = '\0';
+ fi = nntp_folder_info_from_name(store, FALSE, tmpname);
+ fi->flags |= CAMEL_FOLDER_NOSELECT;
+ if (store->folder_hierarchy_relative) {
+ g_free(fi->name);
+ fi->name = g_strdup(tmpname + ((toplen==1) ? 0 : toplen));
+ }
+ g_free(tmpname);
+ } else {
+ continue;
+ }
+ }
+ if (last)
+ last->next = fi;
+ else
+ first = fi;
+ last = fi;
+ } else if (subscribed_or_flag && first) {
+ /* we have already added subitems, but this item is no longer a subitem */
+ camel_store_summary_info_free((CamelStoreSummary *)store->summary, si);
+ break;
+ }
+ camel_store_summary_info_free((CamelStoreSummary *)store->summary, si);
+ }
+
+ g_free(top);
+ return first;
+}
+
+/* retrieves the date from the NNTP server */
+static gboolean
+nntp_get_date(CamelNNTPStore *nntp_store, CamelException *ex)
+{
+ unsigned char *line;
+ int ret = camel_nntp_command(nntp_store, ex, NULL, (char **)&line, "date");
+ char *ptr;
+
+ nntp_store->summary->last_newslist[0] = 0;
+
+ if (ret == 111) {
+ ptr = line + 3;
+ while (*ptr == ' ' || *ptr == '\t')
+ ptr++;
+
+ if (strlen (ptr) == NNTP_DATE_SIZE) {
+ memcpy (nntp_store->summary->last_newslist, ptr, NNTP_DATE_SIZE);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static void
+store_info_remove(void *key, void *value, void *data)
+{
+ CamelStoreSummary *summary = data;
+ CamelStoreInfo *si = value;
+
+ camel_store_summary_remove(summary, si);
+}
+
+static gint
+store_info_sort (gconstpointer a, gconstpointer b)
+{
+ return strcmp ((*(CamelNNTPStoreInfo**) a)->full_name, (*(CamelNNTPStoreInfo**) b)->full_name);
+}
+
+static CamelFolderInfo *
+nntp_store_get_folder_info_all(CamelNNTPStore *nntp_store, const char *top, guint32 flags, gboolean online, CamelException *ex)
+{
+ CamelNNTPStoreSummary *summary = nntp_store->summary;
+ CamelNNTPStoreInfo *si;
+ unsigned int len;
+ unsigned char *line;
+ int ret = -1;
+ CamelFolderInfo *fi = NULL;
+
+ CAMEL_SERVICE_LOCK(nntp_store, connect_lock);
+
+ if (top == NULL)
+ top = "";
+
+ if (online && (top == NULL || top[0] == 0)) {
+ /* we may need to update */
+ if (summary->last_newslist[0] != 0) {
+ char date[14];
+ memcpy(date, summary->last_newslist + 2, 6); /* YYMMDDD */
+ date[6] = ' ';
+ memcpy(date + 7, summary->last_newslist + 8, 6); /* HHMMSS */
+ date[13] = '\0';
+
+ if (!nntp_get_date (nntp_store, ex))
+ goto error;
+
+ ret = camel_nntp_command (nntp_store, ex, NULL, (char **) &line, "newgroups %s", date);
+ if (ret == -1)
+ goto error;
+ else if (ret != 231) {
+ /* newgroups not supported :S so reload the complete list */
+ summary->last_newslist[0] = 0;
+ goto do_complete_list;
+ }
+
+ while ((ret = camel_nntp_stream_line (nntp_store->stream, &line, &len)) > 0)
+ nntp_store_info_update(nntp_store, line);
+ } else {
+ GHashTable *all;
+ int i;
+
+ do_complete_list:
+ /* seems we do need a complete list */
+ /* at first, we do a DATE to find out the last load occasion */
+ if (!nntp_get_date (nntp_store, ex))
+ goto error;
+
+ ret = camel_nntp_command (nntp_store, ex, NULL, (char **)&line, "list");
+ if (ret == -1)
+ goto error;
+ else if (ret != 215) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_INVALID,
+ _("Error retrieving newsgroups:\n\n%s"), line);
+ goto error;
+ }
+
+ all = g_hash_table_new(g_str_hash, g_str_equal);
+ for (i = 0; (si = (CamelNNTPStoreInfo *)camel_store_summary_index ((CamelStoreSummary *)nntp_store->summary, i)); i++)
+ g_hash_table_insert(all, si->info.path, si);
+
+ while ((ret = camel_nntp_stream_line(nntp_store->stream, &line, &len)) > 0) {
+ si = nntp_store_info_update(nntp_store, line);
+ g_hash_table_remove(all, si->info.path);
+ }
+
+ g_hash_table_foreach(all, store_info_remove, nntp_store->summary);
+ g_hash_table_destroy(all);
+ }
+
+ /* sort the list */
+ g_ptr_array_sort (CAMEL_STORE_SUMMARY (nntp_store->summary)->folders, store_info_sort);
+ if (ret < 0)
+ goto error;
+
+ camel_store_summary_save ((CamelStoreSummary *) nntp_store->summary);
+ }
+
+ fi = nntp_store_get_cached_folder_info (nntp_store, top, flags, ex);
+ error:
+ CAMEL_SERVICE_UNLOCK(nntp_store, connect_lock);
+
+ return fi;
+}
+
+static CamelFolderInfo *
+nntp_get_folder_info (CamelStore *store, const char *top, guint32 flags, gboolean online, CamelException *ex)
+{
+ CamelNNTPStore *nntp_store = CAMEL_NNTP_STORE(store);
+ CamelFolderInfo *first = NULL;
+
+ dd(printf("g_f_i: fast %d subscr %d recursive %d online %d top \"%s\"\n",
+ flags & CAMEL_STORE_FOLDER_INFO_FAST,
+ flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED,
+ flags & CAMEL_STORE_FOLDER_INFO_RECURSIVE,
+ online,
+ top?top:""));
+
+ if (flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED)
+ first = nntp_store_get_subscribed_folder_info (nntp_store, top, flags, ex);
+ else
+ first = nntp_store_get_folder_info_all (nntp_store, top, flags, online, ex);
+
+ return first;
+}
+
+static CamelFolderInfo *
+nntp_get_folder_info_online (CamelStore *store, const char *top, guint32 flags, CamelException *ex)
+{
+ return nntp_get_folder_info (store, top, flags, TRUE, ex);
+}
+
+static CamelFolderInfo *
+nntp_get_folder_info_offline(CamelStore *store, const char *top, guint32 flags, CamelException *ex)
+{
+ return nntp_get_folder_info (store, top, flags, FALSE, ex);
+}
+
+static gboolean
+nntp_store_folder_subscribed (CamelStore *store, const char *folder_name)
+{
+ CamelNNTPStore *nntp_store = CAMEL_NNTP_STORE (store);
+ CamelStoreInfo *si;
+ int truth = FALSE;
+
+ si = camel_store_summary_path ((CamelStoreSummary *) nntp_store->summary, folder_name);
+ if (si) {
+ truth = (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) != 0;
+ camel_store_summary_info_free ((CamelStoreSummary *) nntp_store->summary, si);
+ }
+
+ return truth;
+}
+
+static void
+nntp_store_subscribe_folder (CamelStore *store, const char *folder_name,
+ CamelException *ex)
+{
+ CamelNNTPStore *nntp_store = CAMEL_NNTP_STORE(store);
+ CamelStoreInfo *si;
+ CamelFolderInfo *fi;
+
+ CAMEL_SERVICE_LOCK(nntp_store, connect_lock);
+
+ si = camel_store_summary_path(CAMEL_STORE_SUMMARY(nntp_store->summary), folder_name);
+ if (!si) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_INVALID,
+ _("You cannot subscribe to this newsgroup:\n\n"
+ "No such newsgroup. The selected item is a probably a parent folder."));
+ } else {
+ if (!(si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED)) {
+ si->flags |= CAMEL_STORE_INFO_FOLDER_SUBSCRIBED;
+ fi = nntp_folder_info_from_store_info(nntp_store, nntp_store->do_short_folder_notation, si);
+ fi->flags |= CAMEL_FOLDER_NOINFERIORS | CAMEL_FOLDER_NOCHILDREN;
+ camel_store_summary_touch ((CamelStoreSummary *) nntp_store->summary);
+ camel_store_summary_save ((CamelStoreSummary *) nntp_store->summary);
+ CAMEL_SERVICE_UNLOCK(nntp_store, connect_lock);
+ camel_object_trigger_event ((CamelObject *) nntp_store, "folder_subscribed", fi);
+ camel_folder_info_free (fi);
+ return;
+ }
+ }
+
+ CAMEL_SERVICE_UNLOCK(nntp_store, connect_lock);
+}
+
+static void
+nntp_store_unsubscribe_folder (CamelStore *store, const char *folder_name,
+ CamelException *ex)
+{
+ CamelNNTPStore *nntp_store = CAMEL_NNTP_STORE(store);
+ CamelFolderInfo *fi;
+ CamelStoreInfo *fitem;
+ CAMEL_SERVICE_LOCK(nntp_store, connect_lock);
+
+ fitem = camel_store_summary_path(CAMEL_STORE_SUMMARY(nntp_store->summary), folder_name);
+
+ if (!fitem) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_INVALID,
+ _("You cannot unsubscribe to this newsgroup:\n\n"
+ "newsgroup does not exist!"));
+ } else {
+ if (fitem->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) {
+ fitem->flags &= ~CAMEL_STORE_INFO_FOLDER_SUBSCRIBED;
+ fi = nntp_folder_info_from_store_info (nntp_store, nntp_store->do_short_folder_notation, fitem);
+ camel_store_summary_touch ((CamelStoreSummary *) nntp_store->summary);
+ camel_store_summary_save ((CamelStoreSummary *) nntp_store->summary);
+ CAMEL_SERVICE_UNLOCK(nntp_store, connect_lock);
+ camel_object_trigger_event ((CamelObject *) nntp_store, "folder_unsubscribed", fi);
+ camel_folder_info_free (fi);
+ return;
+ }
+ }
+
+ CAMEL_SERVICE_UNLOCK(nntp_store, connect_lock);
+}
+
+/* stubs for various folder operations we're not implementing */
+
+static CamelFolderInfo *
+nntp_create_folder (CamelStore *store, const char *parent_name,
+ const char *folder_name, CamelException *ex)
+{
+ camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_INVALID,
+ _("You cannot create a folder in a News store: subscribe instead."));
+ return NULL;
+}
+
+static void
+nntp_rename_folder (CamelStore *store, const char *old_name, const char *new_name_in, CamelException *ex)
+{
+ camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_INVALID,
+ _("You cannot rename a folder in a News store."));
+}
+
+static void
+nntp_delete_folder (CamelStore *store, const char *folder_name, CamelException *ex)
+{
+ nntp_store_subscribe_folder (store, folder_name, ex);
+ camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_INVALID,
+ _("You cannot remove a folder in a News store: unsubscribe instead."));
+ return;
+}
+
+static void
+nntp_store_finalize (CamelObject *object)
+{
+ /* call base finalize */
+ CamelNNTPStore *nntp_store = CAMEL_NNTP_STORE (object);
+ struct _CamelNNTPStorePrivate *p = nntp_store->priv;
+ struct _xover_header *xover, *xn;
+
+ camel_service_disconnect ((CamelService *)object, TRUE, NULL);
+
+ if (nntp_store->summary) {
+ camel_store_summary_save ((CamelStoreSummary *) nntp_store->summary);
+ camel_object_unref (nntp_store->summary);
+ }
+
+ camel_object_unref (nntp_store->mem);
+ nntp_store->mem = NULL;
+ if (nntp_store->stream)
+ camel_object_unref (nntp_store->stream);
+
+ if (nntp_store->base_url)
+ g_free (nntp_store->base_url);
+ if (nntp_store->storage_path)
+ g_free (nntp_store->storage_path);
+
+ xover = nntp_store->xover;
+ while (xover) {
+ xn = xover->next;
+ g_free(xover);
+ xover = xn;
+ }
+
+ g_free(p);
+}
+
+static void
+nntp_store_class_init (CamelNNTPStoreClass *camel_nntp_store_class)
+{
+ CamelDiscoStoreClass *camel_disco_store_class = CAMEL_DISCO_STORE_CLASS (camel_nntp_store_class);
+ CamelStoreClass *camel_store_class = CAMEL_STORE_CLASS (camel_nntp_store_class);
+ CamelServiceClass *camel_service_class = CAMEL_SERVICE_CLASS (camel_nntp_store_class);
+
+ parent_class = CAMEL_DISCO_STORE_CLASS (camel_type_get_global_classfuncs (camel_disco_store_get_type ()));
+ service_class = CAMEL_SERVICE_CLASS (camel_type_get_global_classfuncs (camel_service_get_type ()));
+
+ /* virtual method overload */
+ camel_service_class->construct = nntp_construct;
+ camel_service_class->query_auth_types = nntp_store_query_auth_types;
+ camel_service_class->get_name = nntp_store_get_name;
+
+ camel_disco_store_class->can_work_offline = nntp_can_work_offline;
+ camel_disco_store_class->connect_online = nntp_connect_online;
+ camel_disco_store_class->connect_offline = nntp_connect_offline;
+ camel_disco_store_class->disconnect_online = nntp_disconnect_online;
+ camel_disco_store_class->disconnect_offline = nntp_disconnect_offline;
+ camel_disco_store_class->get_folder_online = nntp_get_folder;
+ camel_disco_store_class->get_folder_resyncing = nntp_get_folder;
+ camel_disco_store_class->get_folder_offline = nntp_get_folder;
+
+ camel_disco_store_class->get_folder_info_online = nntp_get_folder_info_online;
+ camel_disco_store_class->get_folder_info_resyncing = nntp_get_folder_info_online;
+ camel_disco_store_class->get_folder_info_offline = nntp_get_folder_info_offline;
+
+ camel_store_class->free_folder_info = camel_store_free_folder_info_full;
+
+ camel_store_class->folder_subscribed = nntp_store_folder_subscribed;
+ camel_store_class->subscribe_folder = nntp_store_subscribe_folder;
+ camel_store_class->unsubscribe_folder = nntp_store_unsubscribe_folder;
+
+ camel_store_class->create_folder = nntp_create_folder;
+ camel_store_class->delete_folder = nntp_delete_folder;
+ camel_store_class->rename_folder = nntp_rename_folder;
+}
+
+/* construction function in which we set some basic store properties */
+static void
+nntp_construct (CamelService *service, CamelSession *session,
+ CamelProvider *provider, CamelURL *url,
+ CamelException *ex)
+{
+ CamelNNTPStore *nntp_store = CAMEL_NNTP_STORE(service);
+ CamelURL *summary_url;
+ char *tmp;
+
+ /* construct the parent first */
+ CAMEL_SERVICE_CLASS (parent_class)->construct (service, session, provider, url, ex);
+ if (camel_exception_is_set (ex))
+ return;
+
+ /* find out the storage path, base url */
+ nntp_store->storage_path = camel_session_get_storage_path (session, service, ex);
+ if (!nntp_store->storage_path)
+ return;
+
+ /* FIXME */
+ nntp_store->base_url = camel_url_to_string (service->url, (CAMEL_URL_HIDE_PASSWORD |
+ CAMEL_URL_HIDE_PARAMS |
+ CAMEL_URL_HIDE_AUTH));
+
+ tmp = g_build_filename (nntp_store->storage_path, ".ev-store-summary", NULL);
+ nntp_store->summary = camel_nntp_store_summary_new ();
+ camel_store_summary_set_filename ((CamelStoreSummary *) nntp_store->summary, tmp);
+ summary_url = camel_url_new (nntp_store->base_url, NULL);
+ camel_store_summary_set_uri_base ((CamelStoreSummary *) nntp_store->summary, summary_url);
+ g_free (tmp);
+
+ camel_url_free (summary_url);
+ if (camel_store_summary_load ((CamelStoreSummary *)nntp_store->summary) == 0)
+ ;
+
+ /* get options */
+ if (camel_url_get_param (url, "show_short_notation"))
+ nntp_store->do_short_folder_notation = TRUE;
+ else
+ nntp_store->do_short_folder_notation = FALSE;
+ if (camel_url_get_param (url, "folder_hierarchy_relative"))
+ nntp_store->folder_hierarchy_relative = TRUE;
+ else
+ nntp_store->folder_hierarchy_relative = FALSE;
+}
+
+
+static void
+nntp_store_init (gpointer object, gpointer klass)
+{
+ CamelNNTPStore *nntp_store = CAMEL_NNTP_STORE(object);
+ CamelStore *store = CAMEL_STORE (object);
+ struct _CamelNNTPStorePrivate *p;
+
+ store->flags = CAMEL_STORE_SUBSCRIPTIONS;
+
+ nntp_store->mem = (CamelStreamMem *)camel_stream_mem_new();
+
+ p = nntp_store->priv = g_malloc0(sizeof(*p));
+}
+
+CamelType
+camel_nntp_store_get_type (void)
+{
+ static CamelType camel_nntp_store_type = CAMEL_INVALID_TYPE;
+
+ if (camel_nntp_store_type == CAMEL_INVALID_TYPE) {
+ camel_nntp_store_type =
+ camel_type_register (CAMEL_DISCO_STORE_TYPE,
+ "CamelNNTPStore",
+ sizeof (CamelNNTPStore),
+ sizeof (CamelNNTPStoreClass),
+ (CamelObjectClassInitFunc) nntp_store_class_init,
+ NULL,
+ (CamelObjectInitFunc) nntp_store_init,
+ (CamelObjectFinalizeFunc) nntp_store_finalize);
+ }
+
+ return camel_nntp_store_type;
+}
+
+static int
+camel_nntp_try_authenticate (CamelNNTPStore *store, CamelException *ex)
+{
+ CamelService *service = (CamelService *) store;
+ CamelSession *session = camel_service_get_session (service);
+ int ret;
+ char *line = NULL;
+
+ if (!service->url->user) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_INVALID_PARAM,
+ _("Authentication requested but no username provided"));
+ return -1;
+ }
+
+ /* if nessecary, prompt for the password */
+ if (!service->url->passwd) {
+ char *prompt, *base;
+ retry:
+ base = g_strdup_printf (_("Please enter the NNTP password for %s@%s"),
+ service->url->user,
+ service->url->host);
+ if (line) {
+ char *top = g_strdup_printf(_("Cannot authenticate to server: %s"), line);
+
+ prompt = g_strdup_printf("%s\n\n%s", top, base);
+ g_free(top);
+ } else {
+ prompt = base;
+ base = NULL;
+ }
+
+ service->url->passwd =
+ camel_session_get_password (session, service, NULL,
+ prompt, "password", CAMEL_SESSION_PASSWORD_SECRET, ex);
+ g_free(prompt);
+ g_free(base);
+
+ if (!service->url->passwd)
+ return -1;
+ }
+
+ /* now, send auth info (currently, only authinfo user/pass is supported) */
+ ret = camel_nntp_raw_command(store, ex, &line, "authinfo user %s", service->url->user);
+ if (ret == NNTP_AUTH_CONTINUE)
+ ret = camel_nntp_raw_command(store, ex, &line, "authinfo pass %s", service->url->passwd);
+
+ if (ret != NNTP_AUTH_ACCEPTED) {
+ if (ret != -1) {
+ /* Need to forget the password here since we have no context on it */
+ camel_session_forget_password(session, service, NULL, "password", ex);
+ goto retry;
+ }
+ return -1;
+ }
+
+ return ret;
+}
+
+/* Enter owning lock */
+int
+camel_nntp_raw_commandv (CamelNNTPStore *store, CamelException *ex, char **line, const char *fmt, va_list ap)
+{
+ const unsigned char *p, *ps;
+ unsigned char c;
+ char *s;
+ int d;
+ unsigned int u, u2;
+
+ e_mutex_assert_locked(((CamelService *)store)->priv->connect_lock);
+ g_assert(store->stream->mode != CAMEL_NNTP_STREAM_DATA);
+
+ camel_nntp_stream_set_mode(store->stream, CAMEL_NNTP_STREAM_LINE);
+
+ ps = p = fmt;
+ while ((c = *p++)) {
+ switch (c) {
+ case '%':
+ c = *p++;
+ camel_stream_write ((CamelStream *) store->mem, ps, p - ps - (c == '%' ? 1 : 2));
+ ps = p;
+ switch (c) {
+ case 's':
+ s = va_arg(ap, char *);
+ camel_stream_write((CamelStream *)store->mem, s, strlen(s));
+ break;
+ case 'd':
+ d = va_arg(ap, int);
+ camel_stream_printf((CamelStream *)store->mem, "%d", d);
+ break;
+ case 'u':
+ u = va_arg(ap, unsigned int);
+ camel_stream_printf((CamelStream *)store->mem, "%u", u);
+ break;
+ case 'm':
+ s = va_arg(ap, char *);
+ camel_stream_printf((CamelStream *)store->mem, "<%s>", s);
+ break;
+ case 'r':
+ u = va_arg(ap, unsigned int);
+ u2 = va_arg(ap, unsigned int);
+ if (u == u2)
+ camel_stream_printf((CamelStream *)store->mem, "%u", u);
+ else
+ camel_stream_printf((CamelStream *)store->mem, "%u-%u", u, u2);
+ break;
+ default:
+ g_warning("Passing unknown format to nntp_command: %c\n", c);
+ g_assert(0);
+ }
+ }
+ }
+
+ camel_stream_write ((CamelStream *) store->mem, ps, p-ps-1);
+ dd(printf("NNTP_COMMAND: '%.*s'\n", (int)store->mem->buffer->len, store->mem->buffer->data));
+ camel_stream_write ((CamelStream *) store->mem, "\r\n", 2);
+
+ if (camel_stream_write((CamelStream *) store->stream, store->mem->buffer->data, store->mem->buffer->len) == -1)
+ goto ioerror;
+
+ /* FIXME: hack */
+ camel_stream_reset ((CamelStream *) store->mem);
+ g_byte_array_set_size (store->mem->buffer, 0);
+
+ if (camel_nntp_stream_line (store->stream, (unsigned char **) line, &u) == -1)
+ goto ioerror;
+
+ u = strtoul (*line, NULL, 10);
+
+ /* Handle all switching to data mode here, to make callers job easier */
+ if (u == 215 || (u >= 220 && u <=224) || (u >= 230 && u <= 231))
+ camel_nntp_stream_set_mode(store->stream, CAMEL_NNTP_STREAM_DATA);
+
+ return u;
+
+ioerror:
+ if (errno == EINTR)
+ camel_exception_setv(ex, CAMEL_EXCEPTION_USER_CANCEL, _("Cancelled."));
+ else
+ camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, _("NNTP Command failed: %s"), g_strerror(errno));
+ return -1;
+}
+
+int
+camel_nntp_raw_command(CamelNNTPStore *store, CamelException *ex, char **line, const char *fmt, ...)
+{
+ int ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = camel_nntp_raw_commandv(store, ex, line, fmt, ap);
+ va_end(ap);
+
+ return ret;
+}
+
+/* use this where you also need auth to be handled, i.e. most cases where you'd try raw command */
+int
+camel_nntp_raw_command_auth(CamelNNTPStore *store, CamelException *ex, char **line, const char *fmt, ...)
+{
+ int ret, retry, go;
+ va_list ap;
+
+ retry = 0;
+
+ do {
+ go = FALSE;
+ retry++;
+
+ va_start(ap, fmt);
+ ret = camel_nntp_raw_commandv(store, ex, line, fmt, ap);
+ va_end(ap);
+
+ if (ret == NNTP_AUTH_REQUIRED) {
+ if (camel_nntp_try_authenticate(store, ex) != NNTP_AUTH_ACCEPTED)
+ return -1;
+ go = TRUE;
+ }
+ } while (retry < 3 && go);
+
+ return ret;
+}
+
+int
+camel_nntp_command (CamelNNTPStore *store, CamelException *ex, CamelNNTPFolder *folder, char **line, const char *fmt, ...)
+{
+ const unsigned char *p;
+ va_list ap;
+ int ret, retry;
+ unsigned int u;
+
+ e_mutex_assert_locked(((CamelService *)store)->priv->connect_lock);
+
+ if (((CamelDiscoStore *)store)->status == CAMEL_DISCO_STORE_OFFLINE) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_SERVICE_NOT_CONNECTED,
+ _("Not connected."));
+ return -1;
+ }
+
+ retry = 0;
+ do {
+ retry ++;
+
+ if (store->stream == NULL
+ && !camel_service_connect (CAMEL_SERVICE (store), ex))
+ return -1;
+
+ /* Check for unprocessed data, ! */
+ if (store->stream->mode == CAMEL_NNTP_STREAM_DATA) {
+ g_warning("Unprocessed data left in stream, flushing");
+ while (camel_nntp_stream_getd(store->stream, (unsigned char **)&p, &u) > 0)
+ ;
+ }
+ camel_nntp_stream_set_mode(store->stream, CAMEL_NNTP_STREAM_LINE);
+
+ if (folder != NULL
+ && (store->current_folder == NULL || strcmp(store->current_folder, ((CamelFolder *)folder)->full_name) != 0)) {
+ ret = camel_nntp_raw_command_auth(store, ex, line, "group %s", ((CamelFolder *)folder)->full_name);
+ if (ret == 211) {
+ g_free(store->current_folder);
+ store->current_folder = g_strdup(((CamelFolder *)folder)->full_name);
+ camel_nntp_folder_selected(folder, *line, ex);
+ if (camel_exception_is_set(ex)) {
+ ret = -1;
+ goto error;
+ }
+ } else {
+ goto error;
+ }
+ }
+
+ /* dummy fmt, we just wanted to select the folder */
+ if (fmt == NULL)
+ return 0;
+
+ va_start(ap, fmt);
+ ret = camel_nntp_raw_commandv(store, ex, line, fmt, ap);
+ va_end(ap);
+ error:
+ switch (ret) {
+ case NNTP_AUTH_REQUIRED:
+ if (camel_nntp_try_authenticate(store, ex) != NNTP_AUTH_ACCEPTED)
+ return -1;
+ retry--;
+ ret = -1;
+ continue;
+ case 411: /* no such group */
+ camel_exception_setv(ex, CAMEL_EXCEPTION_FOLDER_INVALID,
+ _("No such folder: %s"), line);
+ return -1;
+ case 400: /* service discontinued */
+ case 401: /* wrong client state - this should quit but this is what the old code did */
+ case 503: /* information not available - this should quit but this is what the old code did (?) */
+ camel_service_disconnect (CAMEL_SERVICE (store), FALSE, NULL);
+ ret = -1;
+ continue;
+ case -1: /* i/o error */
+ camel_service_disconnect (CAMEL_SERVICE (store), FALSE, NULL);
+ if (camel_exception_get_id(ex) == CAMEL_EXCEPTION_USER_CANCEL || retry >= 3)
+ return -1;
+ camel_exception_clear(ex);
+ break;
+ }
+ } while (ret == -1 && retry < 3);
+
+ return ret;
+}
diff --git a/camel/providers/nntp/camel-nntp-store.h b/camel/providers/nntp/camel-nntp-store.h
new file mode 100644
index 0000000000..a9bd682cbd
--- /dev/null
+++ b/camel/providers/nntp/camel-nntp-store.h
@@ -0,0 +1,114 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* camel-nntp-store.h : class for an nntp store */
+
+/*
+ *
+ * Copyright (C) 2000 Ximian, Inc. <toshok@ximian.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+
+#ifndef CAMEL_NNTP_STORE_H
+#define CAMEL_NNTP_STORE_H 1
+
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif /* __cplusplus */
+
+#include <camel/camel-disco-store.h>
+
+#include "camel-nntp-stream.h"
+#include "camel-nntp-store-summary.h"
+
+struct _CamelNNTPFolder;
+struct _CamelException;
+
+#define CAMEL_NNTP_STORE_TYPE (camel_nntp_store_get_type ())
+#define CAMEL_NNTP_STORE(obj) (CAMEL_CHECK_CAST((obj), CAMEL_NNTP_STORE_TYPE, CamelNNTPStore))
+#define CAMEL_NNTP_STORE_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), CAMEL_NNTP_STORE_TYPE, CamelNNTPStoreClass))
+#define CAMEL_IS_NNTP_STORE(o) (CAMEL_CHECK_TYPE((o), CAMEL_NNTP_STORE_TYPE))
+
+#define CAMEL_NNTP_EXT_SEARCH (1<<0)
+#define CAMEL_NNTP_EXT_SETGET (1<<1)
+#define CAMEL_NNTP_EXT_OVER (1<<2)
+#define CAMEL_NNTP_EXT_XPATTEXT (1<<3)
+#define CAMEL_NNTP_EXT_XACTIVE (1<<4)
+#define CAMEL_NNTP_EXT_LISTMOTD (1<<5)
+#define CAMEL_NNTP_EXT_LISTSUBSCR (1<<6)
+#define CAMEL_NNTP_EXT_LISTPNAMES (1<<7)
+
+typedef struct _CamelNNTPStore CamelNNTPStore;
+typedef struct _CamelNNTPStoreClass CamelNNTPStoreClass;
+
+enum _xover_t {
+ XOVER_STRING = 0,
+ XOVER_MSGID,
+ XOVER_SIZE,
+};
+
+struct _xover_header {
+ struct _xover_header *next;
+
+ const char *name;
+ unsigned int skip:8;
+ enum _xover_t type:8;
+};
+
+struct _CamelNNTPStore {
+ CamelDiscoStore parent_object;
+
+ struct _CamelNNTPStorePrivate *priv;
+
+ guint32 extensions;
+
+ unsigned int posting_allowed:1;
+ unsigned int do_short_folder_notation:1;
+ unsigned int folder_hierarchy_relative:1;
+
+ struct _CamelNNTPStoreSummary *summary;
+
+ struct _CamelNNTPStream *stream;
+ struct _CamelStreamMem *mem;
+
+ struct _CamelDataCache *cache;
+
+ char *current_folder, *storage_path, *base_url;
+
+ struct _xover_header *xover;
+};
+
+struct _CamelNNTPStoreClass {
+ CamelDiscoStoreClass parent_class;
+
+};
+
+/* Standard Camel function */
+CamelType camel_nntp_store_get_type (void);
+
+int camel_nntp_raw_commandv (CamelNNTPStore *store, struct _CamelException *ex, char **line, const char *fmt, va_list ap);
+int camel_nntp_raw_command(CamelNNTPStore *store, struct _CamelException *ex, char **line, const char *fmt, ...);
+int camel_nntp_raw_command_auth(CamelNNTPStore *store, struct _CamelException *ex, char **line, const char *fmt, ...);
+int camel_nntp_command (CamelNNTPStore *store, struct _CamelException *ex, struct _CamelNNTPFolder *folder, char **line, const char *fmt, ...);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* CAMEL_NNTP_STORE_H */
+
+
diff --git a/camel/providers/nntp/camel-nntp-stream.c b/camel/providers/nntp/camel-nntp-stream.c
new file mode 100644
index 0000000000..74bee9ced5
--- /dev/null
+++ b/camel/providers/nntp/camel-nntp-stream.c
@@ -0,0 +1,462 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; fill-column: 160 -*-
+ *
+ * Author:
+ * Michael Zucchi <notzed@ximian.com>
+ *
+ * Copyright 1999, 2000 Ximian, Inc. (www.ximian.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+
+#include <string.h>
+#include <stdio.h>
+
+#include <glib.h>
+
+#include "camel-nntp-stream.h"
+#include "camel-debug.h"
+
+#define dd(x) (camel_debug("nntp:stream")?(x):0)
+
+static CamelObjectClass *parent_class = NULL;
+
+/* Returns the class for a CamelStream */
+#define CS_CLASS(so) CAMEL_NNTP_STREAM_CLASS(CAMEL_OBJECT_GET_CLASS(so))
+
+#define CAMEL_NNTP_STREAM_SIZE (4096)
+#define CAMEL_NNTP_STREAM_LINE_SIZE (1024) /* maximum line size */
+
+static int
+stream_fill(CamelNNTPStream *is)
+{
+ int left = 0;
+
+ if (is->source) {
+ left = is->end - is->ptr;
+ memcpy(is->buf, is->ptr, left);
+ is->end = is->buf + left;
+ is->ptr = is->buf;
+ left = camel_stream_read(is->source, is->end, CAMEL_NNTP_STREAM_SIZE - (is->end - is->buf));
+ if (left > 0) {
+ is->end += left;
+ is->end[0] = '\n';
+ return is->end - is->ptr;
+ } else {
+ dd(printf("NNTP_STREAM_FILL(ERROR): %d - '%s'\n", left, strerror(errno)));
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static ssize_t
+stream_read(CamelStream *stream, char *buffer, size_t n)
+{
+ CamelNNTPStream *is = (CamelNNTPStream *)stream;
+ char *o, *oe;
+ unsigned char *p, *e, c;
+ int state;
+
+ if (is->mode != CAMEL_NNTP_STREAM_DATA || n == 0)
+ return 0;
+
+ o = buffer;
+ oe = buffer + n;
+ state = is->state;
+
+ /* Need to copy/strip '.'s and whatnot */
+ p = is->ptr;
+ e = is->end;
+
+ switch(state) {
+ state_0:
+ case 0: /* start of line, always read at least 3 chars */
+ while (e - p < 3) {
+ is->ptr = p;
+ if (stream_fill(is) == -1)
+ return -1;
+ p = is->ptr;
+ e = is->end;
+ }
+ if (p[0] == '.') {
+ if (p[1] == '\r' && p[2] == '\n') {
+ is->ptr = p+3;
+ is->mode = CAMEL_NNTP_STREAM_EOD;
+ is->state = 0;
+ dd(printf("NNTP_STREAM_READ(%d):\n%.*s\n", o-buffer, o-buffer, buffer));
+ return o-buffer;
+ }
+ p++;
+ }
+ state = 1;
+ /* FALLS THROUGH */
+ case 1: /* looking for next sol */
+ while (o < oe) {
+ c = *p++;
+ if (c == '\n') {
+ /* end of input sentinal check */
+ if (p > e) {
+ is->ptr = e;
+ if (stream_fill(is) == -1)
+ return -1;
+ p = is->ptr;
+ e = is->end;
+ } else {
+ *o++ = '\n';
+ state = 0;
+ goto state_0;
+ }
+ } else if (c != '\r') {
+ *o++ = c;
+ }
+ }
+ break;
+ }
+
+ is->ptr = p;
+ is->state = state;
+
+ dd(printf("NNTP_STREAM_READ(%d):\n%.*s\n", o-buffer, o-buffer, buffer));
+
+ return o-buffer;
+}
+
+static ssize_t
+stream_write(CamelStream *stream, const char *buffer, size_t n)
+{
+ CamelNNTPStream *is = (CamelNNTPStream *)stream;
+
+ return camel_stream_write(is->source, buffer, n);
+}
+
+static int
+stream_close(CamelStream *stream)
+{
+ /* nop? */
+ return 0;
+}
+
+static int
+stream_flush(CamelStream *stream)
+{
+ /* nop? */
+ return 0;
+}
+
+static gboolean
+stream_eos(CamelStream *stream)
+{
+ CamelNNTPStream *is = (CamelNNTPStream *)stream;
+
+ return is->mode != CAMEL_NNTP_STREAM_DATA;
+}
+
+static int
+stream_reset(CamelStream *stream)
+{
+ /* nop? reset literal mode? */
+ return 0;
+}
+
+static void
+camel_nntp_stream_class_init (CamelStreamClass *camel_nntp_stream_class)
+{
+ CamelStreamClass *camel_stream_class = (CamelStreamClass *)camel_nntp_stream_class;
+
+ parent_class = camel_type_get_global_classfuncs( CAMEL_OBJECT_TYPE );
+
+ /* virtual method definition */
+ camel_stream_class->read = stream_read;
+ camel_stream_class->write = stream_write;
+ camel_stream_class->close = stream_close;
+ camel_stream_class->flush = stream_flush;
+ camel_stream_class->eos = stream_eos;
+ camel_stream_class->reset = stream_reset;
+}
+
+static void
+camel_nntp_stream_init(CamelNNTPStream *is, CamelNNTPStreamClass *isclass)
+{
+ /* +1 is room for appending a 0 if we need to for a line */
+ is->ptr = is->end = is->buf = g_malloc(CAMEL_NNTP_STREAM_SIZE+1);
+ is->lineptr = is->linebuf = g_malloc(CAMEL_NNTP_STREAM_LINE_SIZE+1);
+ is->lineend = is->linebuf + CAMEL_NNTP_STREAM_LINE_SIZE;
+
+ /* init sentinal */
+ is->ptr[0] = '\n';
+
+ is->state = 0;
+ is->mode = CAMEL_NNTP_STREAM_LINE;
+}
+
+static void
+camel_nntp_stream_finalise(CamelNNTPStream *is)
+{
+ g_free(is->buf);
+ g_free(is->linebuf);
+ if (is->source)
+ camel_object_unref((CamelObject *)is->source);
+}
+
+CamelType
+camel_nntp_stream_get_type (void)
+{
+ static CamelType camel_nntp_stream_type = CAMEL_INVALID_TYPE;
+
+ if (camel_nntp_stream_type == CAMEL_INVALID_TYPE) {
+ camel_nntp_stream_type = camel_type_register( camel_stream_get_type(),
+ "CamelNNTPStream",
+ sizeof( CamelNNTPStream ),
+ sizeof( CamelNNTPStreamClass ),
+ (CamelObjectClassInitFunc) camel_nntp_stream_class_init,
+ NULL,
+ (CamelObjectInitFunc) camel_nntp_stream_init,
+ (CamelObjectFinalizeFunc) camel_nntp_stream_finalise );
+ }
+
+ return camel_nntp_stream_type;
+}
+
+/**
+ * camel_nntp_stream_new:
+ *
+ * Returns a NULL stream. A null stream is always at eof, and
+ * always returns success for all reads and writes.
+ *
+ * Return value: the stream
+ **/
+CamelStream *
+camel_nntp_stream_new(CamelStream *source)
+{
+ CamelNNTPStream *is;
+
+ is = (CamelNNTPStream *)camel_object_new(camel_nntp_stream_get_type ());
+ camel_object_ref((CamelObject *)source);
+ is->source = source;
+
+ return (CamelStream *)is;
+}
+
+/* Get one line from the nntp stream */
+int
+camel_nntp_stream_line(CamelNNTPStream *is, unsigned char **data, unsigned int *len)
+{
+ register unsigned char c, *p, *o, *oe;
+ int newlen, oldlen;
+ unsigned char *e;
+
+ if (is->mode == CAMEL_NNTP_STREAM_EOD) {
+ *data = is->linebuf;
+ *len = 0;
+ return 0;
+ }
+
+ o = is->linebuf;
+ oe = is->lineend - 1;
+ p = is->ptr;
+ e = is->end;
+
+ /* Data mode, convert leading '..' to '.', and stop when we reach a solitary '.' */
+ if (is->mode == CAMEL_NNTP_STREAM_DATA) {
+ /* need at least 3 chars in buffer */
+ while (e-p < 3) {
+ is->ptr = p;
+ if (stream_fill(is) == -1)
+ return -1;
+ p = is->ptr;
+ e = is->end;
+ }
+
+ /* check for isolated '.\r\n' or begging of line '.' */
+ if (p[0] == '.') {
+ if (p[1] == '\r' && p[2] == '\n') {
+ is->ptr = p+3;
+ is->mode = CAMEL_NNTP_STREAM_EOD;
+ *data = is->linebuf;
+ *len = 0;
+ is->linebuf[0] = 0;
+
+ dd(printf("NNTP_STREAM_LINE(END)\n"));
+
+ return 0;
+ }
+ p++;
+ }
+ }
+
+ while (1) {
+ while (o < oe) {
+ c = *p++;
+ if (c == '\n') {
+ /* sentinal? */
+ if (p> e) {
+ is->ptr = e;
+ if (stream_fill(is) == -1)
+ return -1;
+ p = is->ptr;
+ e = is->end;
+ } else {
+ is->ptr = p;
+ *data = is->linebuf;
+ *len = o - is->linebuf;
+ *o = 0;
+
+ dd(printf("NNTP_STREAM_LINE(%d): '%s'\n", *len, *data));
+
+ return 1;
+ }
+ } else if (c != '\r') {
+ *o++ = c;
+ }
+ }
+
+ /* limit this for bad server data? */
+ oldlen = o - is->linebuf;
+ newlen = (is->lineend - is->linebuf) * 3 / 2;
+ is->lineptr = is->linebuf = g_realloc(is->linebuf, newlen);
+ is->lineend = is->linebuf + newlen;
+ oe = is->lineend - 1;
+ o = is->linebuf + oldlen;
+ }
+
+ return -1;
+}
+
+/* returns -1 on error, 0 if last lot of data, >0 if more remaining */
+int camel_nntp_stream_gets(CamelNNTPStream *is, unsigned char **start, unsigned int *len)
+{
+ int max;
+ unsigned char *end;
+
+ *len = 0;
+
+ max = is->end - is->ptr;
+ if (max == 0) {
+ max = stream_fill(is);
+ if (max <= 0)
+ return max;
+ }
+
+ *start = is->ptr;
+ end = memchr(is->ptr, '\n', max);
+ if (end)
+ max = (end - is->ptr) + 1;
+ *start = is->ptr;
+ *len = max;
+ is->ptr += max;
+
+ dd(printf("NNTP_STREAM_GETS(%s,%d): '%.*s'\n", end==NULL?"more":"last", *len, (int)*len, *start));
+
+ return end == NULL?1:0;
+}
+
+void camel_nntp_stream_set_mode(CamelNNTPStream *is, camel_nntp_stream_mode_t mode)
+{
+ is->mode = mode;
+}
+
+/* returns -1 on erorr, 0 if last data, >0 if more data left */
+int camel_nntp_stream_getd(CamelNNTPStream *is, unsigned char **start, unsigned int *len)
+{
+ unsigned char *p, *e, *s;
+ int state;
+
+ *len = 0;
+
+ if (is->mode == CAMEL_NNTP_STREAM_EOD)
+ return 0;
+
+ if (is->mode == CAMEL_NNTP_STREAM_LINE) {
+ g_warning("nntp_stream reading data in line mode\n");
+ return 0;
+ }
+
+ state = is->state;
+ p = is->ptr;
+ e = is->end;
+
+ while (e - p < 3) {
+ is->ptr = p;
+ if (stream_fill(is) == -1)
+ return -1;
+ p = is->ptr;
+ e = is->end;
+ }
+
+ s = p;
+
+ do {
+ switch(state) {
+ case 0:
+ /* check leading '.', ... */
+ if (p[0] == '.') {
+ if (p[1] == '\r' && p[2] == '\n') {
+ is->ptr = p+3;
+ *len = p-s;
+ *start = s;
+ is->mode = CAMEL_NNTP_STREAM_EOD;
+ is->state = 0;
+
+ dd(printf("NNTP_STREAM_GETD(%s,%d): '%.*s'\n", "last", *len, (int)*len, *start));
+
+ return 0;
+ }
+
+ /* If at start, just skip '.', else return data upto '.' but skip it */
+ if (p == s) {
+ s++;
+ p++;
+ } else {
+ is->ptr = p+1;
+ *len = p-s;
+ *start = s;
+ is->state = 1;
+
+ dd(printf("NNTP_STREAM_GETD(%s,%d): '%.*s'\n", "more", *len, (int)*len, *start));
+
+ return 1;
+ }
+ }
+ state = 1;
+ case 1:
+ /* Scan for sentinal */
+ while ((*p++)!='\n')
+ ;
+
+ if (p > e) {
+ p = e;
+ } else {
+ state = 0;
+ }
+ break;
+ }
+ } while ((e-p) >= 3);
+
+ is->state = state;
+ is->ptr = p;
+ *len = p-s;
+ *start = s;
+
+ dd(printf("NNTP_STREAM_GETD(%s,%d): '%.*s'\n", "more", *len, (int)*len, *start));
+ return 1;
+}
+
diff --git a/camel/providers/nntp/camel-nntp-summary.c b/camel/providers/nntp/camel-nntp-summary.c
new file mode 100644
index 0000000000..02589e632e
--- /dev/null
+++ b/camel/providers/nntp/camel-nntp-summary.c
@@ -0,0 +1,504 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; fill-column: 160 -*- */
+/*
+ * Copyright (C) 2000 Ximian Inc.
+ *
+ * Authors: Michael Zucchi <notzed@ximian.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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ctype.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "camel/camel-file-utils.h"
+#include "camel/camel-mime-message.h"
+#include "camel/camel-stream-null.h"
+#include "camel/camel-operation.h"
+#include "camel/camel-data-cache.h"
+#include "camel/camel-debug.h"
+
+#include "camel-nntp-summary.h"
+#include "camel-nntp-folder.h"
+#include "camel-nntp-store.h"
+#include "camel-nntp-stream.h"
+
+#define w(x)
+#define io(x)
+#define d(x) /*(printf("%s(%d): ", __FILE__, __LINE__),(x))*/
+#define dd(x) (camel_debug("nntp")?(x):0)
+
+#define CAMEL_NNTP_SUMMARY_VERSION (1)
+
+struct _CamelNNTPSummaryPrivate {
+ char *uid;
+
+ struct _xover_header *xover; /* xoverview format */
+ int xover_setup;
+};
+
+#define _PRIVATE(o) (((CamelNNTPSummary *)(o))->priv)
+
+static CamelMessageInfo * message_info_new (CamelFolderSummary *, struct _camel_header_raw *);
+static int summary_header_load(CamelFolderSummary *, FILE *);
+static int summary_header_save(CamelFolderSummary *, FILE *);
+
+static void camel_nntp_summary_class_init (CamelNNTPSummaryClass *klass);
+static void camel_nntp_summary_init (CamelNNTPSummary *obj);
+static void camel_nntp_summary_finalise (CamelObject *obj);
+static CamelFolderSummaryClass *camel_nntp_summary_parent;
+
+CamelType
+camel_nntp_summary_get_type(void)
+{
+ static CamelType type = CAMEL_INVALID_TYPE;
+
+ if (type == CAMEL_INVALID_TYPE) {
+ type = camel_type_register(camel_folder_summary_get_type(), "CamelNNTPSummary",
+ sizeof (CamelNNTPSummary),
+ sizeof (CamelNNTPSummaryClass),
+ (CamelObjectClassInitFunc) camel_nntp_summary_class_init,
+ NULL,
+ (CamelObjectInitFunc) camel_nntp_summary_init,
+ (CamelObjectFinalizeFunc) camel_nntp_summary_finalise);
+ }
+
+ return type;
+}
+
+static void
+camel_nntp_summary_class_init(CamelNNTPSummaryClass *klass)
+{
+ CamelFolderSummaryClass *sklass = (CamelFolderSummaryClass *) klass;
+
+ camel_nntp_summary_parent = CAMEL_FOLDER_SUMMARY_CLASS(camel_type_get_global_classfuncs(camel_folder_summary_get_type()));
+
+ sklass->message_info_new = message_info_new;
+ sklass->summary_header_load = summary_header_load;
+ sklass->summary_header_save = summary_header_save;
+}
+
+static void
+camel_nntp_summary_init(CamelNNTPSummary *obj)
+{
+ struct _CamelNNTPSummaryPrivate *p;
+ struct _CamelFolderSummary *s = (CamelFolderSummary *)obj;
+
+ p = _PRIVATE(obj) = g_malloc0(sizeof(*p));
+
+ /* subclasses need to set the right instance data sizes */
+ s->message_info_size = sizeof(CamelMessageInfo);
+ s->content_info_size = sizeof(CamelMessageContentInfo);
+
+ /* and a unique file version */
+ s->version += CAMEL_NNTP_SUMMARY_VERSION;
+}
+
+static void
+camel_nntp_summary_finalise(CamelObject *obj)
+{
+ CamelNNTPSummary *cns = CAMEL_NNTP_SUMMARY(obj);
+
+ g_free(cns->priv);
+}
+
+CamelNNTPSummary *
+camel_nntp_summary_new(const char *path)
+{
+ CamelNNTPSummary *cns = (CamelNNTPSummary *)camel_object_new(camel_nntp_summary_get_type());
+
+ camel_folder_summary_set_filename((CamelFolderSummary *)cns, path);
+ camel_folder_summary_set_build_content((CamelFolderSummary *)cns, FALSE);
+
+ return cns;
+}
+
+static CamelMessageInfo *
+message_info_new(CamelFolderSummary *s, struct _camel_header_raw *h)
+{
+ CamelMessageInfo *mi;
+ CamelNNTPSummary *cns = (CamelNNTPSummary *)s;
+
+ /* error to call without this setup */
+ if (cns->priv->uid == NULL)
+ return NULL;
+
+ /* we shouldn't be here if we already have this uid */
+ g_assert(camel_folder_summary_uid(s, cns->priv->uid) == NULL);
+
+ mi = ((CamelFolderSummaryClass *)camel_nntp_summary_parent)->message_info_new(s, h);
+ if (mi) {
+ camel_message_info_set_uid(mi, cns->priv->uid);
+ cns->priv->uid = NULL;
+ }
+
+ return mi;
+}
+
+static int
+summary_header_load(CamelFolderSummary *s, FILE *in)
+{
+ CamelNNTPSummary *cns = CAMEL_NNTP_SUMMARY(s);
+
+ if (((CamelFolderSummaryClass *)camel_nntp_summary_parent)->summary_header_load(s, in) == -1)
+ return -1;
+
+ /* Legacy version */
+ if (s->version == 0x20c) {
+ camel_file_util_decode_fixed_int32(in, &cns->high);
+ return camel_file_util_decode_fixed_int32(in, &cns->low);
+ }
+
+ if (camel_file_util_decode_fixed_int32(in, &cns->version) == -1)
+ return -1;
+
+ if (cns->version > CAMEL_NNTP_SUMMARY_VERSION) {
+ g_warning("Unknown NNTP summary version");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (camel_file_util_decode_fixed_int32(in, &cns->high) == -1
+ || camel_file_util_decode_fixed_int32(in, &cns->low) == -1)
+ return -1;
+
+ return 0;
+}
+
+static int
+summary_header_save(CamelFolderSummary *s, FILE *out)
+{
+ CamelNNTPSummary *cns = CAMEL_NNTP_SUMMARY(s);
+
+ if (((CamelFolderSummaryClass *)camel_nntp_summary_parent)->summary_header_save(s, out) == -1
+ || camel_file_util_encode_fixed_int32(out, CAMEL_NNTP_SUMMARY_VERSION) == -1
+ || camel_file_util_encode_fixed_int32(out, cns->high) == -1
+ || camel_file_util_encode_fixed_int32(out, cns->low) == -1)
+ return -1;
+
+ return 0;
+}
+
+/* ********************************************************************** */
+
+/* Note: This will be called from camel_nntp_command, so only use camel_nntp_raw_command */
+static int
+add_range_xover(CamelNNTPSummary *cns, CamelNNTPStore *store, unsigned int high, unsigned int low, CamelFolderChangeInfo *changes, CamelException *ex)
+{
+ CamelFolderSummary *s;
+ CamelMessageInfo *mi;
+ struct _camel_header_raw *headers = NULL;
+ char *line, *tab;
+ int len, ret;
+ unsigned int n, count, total, size;
+ struct _xover_header *xover;
+
+ s = (CamelFolderSummary *)cns;
+
+ camel_operation_start(NULL, _("%s: Scanning new messages"), ((CamelService *)store)->url->host);
+
+ ret = camel_nntp_raw_command_auth(store, ex, &line, "xover %r", low, high);
+ if (ret != 224) {
+ camel_operation_end(NULL);
+ if (ret != -1)
+ camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Unexpected server response from xover: %s"), line);
+ return -1;
+ }
+
+ count = 0;
+ total = high-low+1;
+ while ((ret = camel_nntp_stream_line(store->stream, (unsigned char **)&line, &len)) > 0) {
+ camel_operation_progress(NULL, (count * 100) / total);
+ count++;
+ n = strtoul(line, &tab, 10);
+ if (*tab != '\t')
+ continue;
+ tab++;
+ xover = store->xover;
+ size = 0;
+ for (;tab[0] && xover;xover = xover->next) {
+ line = tab;
+ tab = strchr(line, '\t');
+ if (tab)
+ *tab++ = 0;
+ else
+ tab = line+strlen(line);
+
+ /* do we care about this column? */
+ if (xover->name) {
+ line += xover->skip;
+ if (line < tab) {
+ camel_header_raw_append(&headers, xover->name, line, -1);
+ switch(xover->type) {
+ case XOVER_STRING:
+ break;
+ case XOVER_MSGID:
+ cns->priv->uid = g_strdup_printf("%u,%s", n, line);
+ break;
+ case XOVER_SIZE:
+ size = strtoul(line, NULL, 10);
+ break;
+ }
+ }
+ }
+ }
+
+ /* skip headers we don't care about, incase the server doesn't actually send some it said it would. */
+ while (xover && xover->name == NULL)
+ xover = xover->next;
+
+ /* truncated line? ignore? */
+ if (xover == NULL) {
+ mi = camel_folder_summary_uid(s, cns->priv->uid);
+ if (mi == NULL) {
+ mi = camel_folder_summary_add_from_header(s, headers);
+ if (mi) {
+ mi->size = size;
+ cns->high = n;
+ camel_folder_change_info_add_uid(changes, camel_message_info_uid(mi));
+ }
+ } else {
+ camel_folder_summary_info_free(s, mi);
+ }
+ }
+
+ if (cns->priv->uid) {
+ g_free(cns->priv->uid);
+ cns->priv->uid = NULL;
+ }
+
+ camel_header_raw_clear(&headers);
+ }
+
+ camel_operation_end(NULL);
+
+ return ret;
+}
+
+/* Note: This will be called from camel_nntp_command, so only use camel_nntp_raw_command */
+static int
+add_range_head(CamelNNTPSummary *cns, CamelNNTPStore *store, unsigned int high, unsigned int low, CamelFolderChangeInfo *changes, CamelException *ex)
+{
+ CamelFolderSummary *s;
+ int i, ret = -1;
+ char *line, *msgid;
+ unsigned int n, count, total;
+ CamelMessageInfo *mi;
+ CamelMimeParser *mp;
+
+ s = (CamelFolderSummary *)cns;
+
+ mp = camel_mime_parser_new();
+
+ camel_operation_start(NULL, _("%s: Scanning new messages"), ((CamelService *)store)->url->host);
+
+ count = 0;
+ total = high-low+1;
+ for (i=low;i<high+1;i++) {
+ camel_operation_progress(NULL, (count * 100) / total);
+ count++;
+ ret = camel_nntp_raw_command_auth(store, ex, &line, "head %u", i);
+ /* unknown article, ignore */
+ if (ret == 423)
+ continue;
+ else if (ret == -1)
+ goto ioerror;
+ else if (ret != 221) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, _("Unexpected server response from head: %s"), line);
+ goto ioerror;
+ }
+ line += 3;
+ n = strtoul(line, &line, 10);
+ if (n != i)
+ g_warning("retrieved message '%d' when i expected '%d'?\n", n, i);
+
+ /* FIXME: use camel-mime-utils.c function for parsing msgid? */
+ if ((msgid = strchr(line, '<')) && (line = strchr(msgid+1, '>'))){
+ line[1] = 0;
+ cns->priv->uid = g_strdup_printf("%u,%s\n", n, msgid);
+ mi = camel_folder_summary_uid(s, cns->priv->uid);
+ if (mi == NULL) {
+ if (camel_mime_parser_init_with_stream(mp, (CamelStream *)store->stream) == -1)
+ goto error;
+ mi = camel_folder_summary_add_from_parser(s, mp);
+ while (camel_mime_parser_step(mp, NULL, NULL) != CAMEL_MIME_PARSER_STATE_EOF)
+ ;
+ if (mi == NULL) {
+ goto error;
+ }
+ cns->high = i;
+ camel_folder_change_info_add_uid(changes, camel_message_info_uid(mi));
+ } else {
+ /* already have, ignore */
+ camel_folder_summary_info_free(s, mi);
+ }
+ if (cns->priv->uid) {
+ g_free(cns->priv->uid);
+ cns->priv->uid = NULL;
+ }
+ }
+ }
+
+ ret = 0;
+error:
+
+ if (ret == -1) {
+ if (errno == EINTR)
+ camel_exception_setv(ex, CAMEL_EXCEPTION_USER_CANCEL, _("Use cancel"));
+ else
+ camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, _("Operation failed: %s"), strerror(errno));
+ }
+ioerror:
+
+ if (cns->priv->uid) {
+ g_free(cns->priv->uid);
+ cns->priv->uid = NULL;
+ }
+ camel_object_unref((CamelObject *)mp);
+
+ camel_operation_end(NULL);
+
+ return ret;
+}
+
+/* Assumes we have the stream */
+/* Note: This will be called from camel_nntp_command, so only use camel_nntp_raw_command */
+int
+camel_nntp_summary_check(CamelNNTPSummary *cns, CamelNNTPStore *store, char *line, CamelFolderChangeInfo *changes, CamelException *ex)
+{
+ CamelFolderSummary *s;
+ int ret = 0, i;
+ unsigned int n, f, l;
+ int count;
+ char *folder = NULL;
+ CamelNNTPStoreInfo *si;
+
+ s = (CamelFolderSummary *)cns;
+
+ line +=3;
+ n = strtoul(line, &line, 10);
+ f = strtoul(line, &line, 10);
+ l = strtoul(line, &line, 10);
+ if (line[0] == ' ') {
+ char *tmp;
+
+ folder = line+1;
+ tmp = strchr(folder, ' ');
+ if (tmp)
+ *tmp = 0;
+ tmp = g_alloca(strlen(folder)+1);
+ strcpy(tmp, folder);
+ folder = tmp;
+ }
+
+ if (cns->low == f && cns->high == l) {
+ dd(printf("nntp_summary: no work to do!\n"));
+ goto update;
+ }
+
+ /* Need to work out what to do with our messages */
+
+ /* Check for messages no longer on the server */
+ if (cns->low != f) {
+ count = camel_folder_summary_count(s);
+ for (i = 0; i < count; i++) {
+ CamelMessageInfo *mi = camel_folder_summary_index(s, i);
+
+ if (mi) {
+ const char *uid = camel_message_info_uid(mi);
+ const char *msgid;
+
+ n = strtoul(uid, NULL, 10);
+ if (n < f || n > l) {
+ dd(printf("nntp_summary: %u is lower/higher than lowest/highest article, removed\n", n));
+ /* Since we use a global cache this could prematurely remove
+ a cached message that might be in another folder - not that important as
+ it is a true cache */
+ msgid = strchr(uid, ',');
+ if (msgid)
+ camel_data_cache_remove(store->cache, "cache", msgid+1, NULL);
+ camel_folder_change_info_remove_uid(changes, uid);
+ camel_folder_summary_remove(s, mi);
+ count--;
+ i--;
+ }
+
+ camel_folder_summary_info_free(s, mi);
+ }
+ }
+ cns->low = f;
+ }
+
+ if (cns->high < l) {
+ if (cns->high < f)
+ cns->high = f-1;
+
+ if (store->xover) {
+ ret = add_range_xover(cns, store, l, cns->high+1, changes, ex);
+ } else {
+ ret = add_range_head(cns, store, l, cns->high+1, changes, ex);
+ }
+ }
+
+ /* TODO: not from here */
+ camel_folder_summary_touch(s);
+ camel_folder_summary_save(s);
+update:
+ /* update store summary if we have it */
+ if (folder
+ && (si = (CamelNNTPStoreInfo *)camel_store_summary_path((CamelStoreSummary *)store->summary, folder))) {
+ int unread = 0;
+
+ count = camel_folder_summary_count(s);
+ for (i = 0; i < count; i++) {
+ CamelMessageInfo *mi = camel_folder_summary_index(s, i);
+
+ if (mi) {
+ if ((mi->flags & CAMEL_MESSAGE_SEEN) == 0)
+ unread++;
+ camel_folder_summary_info_free(s, mi);
+ }
+ }
+
+ if (si->info.unread != unread
+ || si->info.total != count
+ || si->first != f
+ || si->last != l) {
+ si->info.unread = unread;
+ si->info.total = count;
+ si->first = f;
+ si->last = l;
+ camel_store_summary_touch((CamelStoreSummary *)store->summary);
+ camel_store_summary_save((CamelStoreSummary *)store->summary);
+ }
+ camel_store_summary_info_free ((CamelStoreSummary *)store->summary, (CamelStoreInfo *)si);
+ } else {
+ if (folder)
+ g_warning("Group '%s' not present in summary", folder);
+ else
+ g_warning("Missing group from group response");
+ }
+
+ return ret;
+}
diff --git a/camel/providers/pop3/camel-pop3-store.c b/camel/providers/pop3/camel-pop3-store.c
new file mode 100644
index 0000000000..96db912efc
--- /dev/null
+++ b/camel/providers/pop3/camel-pop3-store.c
@@ -0,0 +1,682 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* camel-pop3-store.c : class for a pop3 store */
+
+/*
+ * Authors:
+ * Dan Winship <danw@ximian.com>
+ * Michael Zucchi <notzed@ximian.com>
+ *
+ * Copyright (C) 2000-2002 Ximian, Inc. (www.ximian.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "camel-operation.h"
+
+#include "camel-pop3-store.h"
+#include "camel-pop3-folder.h"
+#include "camel-stream-buffer.h"
+#include "camel-session.h"
+#include "camel-exception.h"
+#include "camel-url.h"
+#include "e-util/md5-utils.h"
+#include "camel-pop3-engine.h"
+#include "camel-sasl.h"
+#include "camel-data-cache.h"
+#include "camel-tcp-stream.h"
+#include "camel-tcp-stream-raw.h"
+#ifdef HAVE_SSL
+#include "camel-tcp-stream-ssl.h"
+#endif
+
+/* Specified in RFC 1939 */
+#define POP3_PORT 110
+
+static CamelStoreClass *parent_class = NULL;
+
+static void finalize (CamelObject *object);
+
+static gboolean pop3_connect (CamelService *service, CamelException *ex);
+static gboolean pop3_disconnect (CamelService *service, gboolean clean, CamelException *ex);
+static GList *query_auth_types (CamelService *service, CamelException *ex);
+
+static CamelFolder *get_folder (CamelStore *store, const char *folder_name,
+ guint32 flags, CamelException *ex);
+
+static CamelFolder *get_trash (CamelStore *store, CamelException *ex);
+
+static void
+camel_pop3_store_class_init (CamelPOP3StoreClass *camel_pop3_store_class)
+{
+ CamelServiceClass *camel_service_class =
+ CAMEL_SERVICE_CLASS (camel_pop3_store_class);
+ CamelStoreClass *camel_store_class =
+ CAMEL_STORE_CLASS (camel_pop3_store_class);
+
+ parent_class = CAMEL_STORE_CLASS (camel_type_get_global_classfuncs (camel_store_get_type ()));
+
+ /* virtual method overload */
+ camel_service_class->query_auth_types = query_auth_types;
+ camel_service_class->connect = pop3_connect;
+ camel_service_class->disconnect = pop3_disconnect;
+
+ camel_store_class->get_folder = get_folder;
+ camel_store_class->get_trash = get_trash;
+}
+
+
+
+static void
+camel_pop3_store_init (gpointer object, gpointer klass)
+{
+ ;
+}
+
+CamelType
+camel_pop3_store_get_type (void)
+{
+ static CamelType camel_pop3_store_type = CAMEL_INVALID_TYPE;
+
+ if (!camel_pop3_store_type) {
+ camel_pop3_store_type = camel_type_register (CAMEL_STORE_TYPE,
+ "CamelPOP3Store",
+ sizeof (CamelPOP3Store),
+ sizeof (CamelPOP3StoreClass),
+ (CamelObjectClassInitFunc) camel_pop3_store_class_init,
+ NULL,
+ (CamelObjectInitFunc) camel_pop3_store_init,
+ finalize);
+ }
+
+ return camel_pop3_store_type;
+}
+
+static void
+finalize (CamelObject *object)
+{
+ CamelPOP3Store *pop3_store = CAMEL_POP3_STORE (object);
+
+ /* force disconnect so we dont have it run later, after we've cleaned up some stuff */
+ /* SIGH */
+
+ camel_service_disconnect((CamelService *)pop3_store, TRUE, NULL);
+
+ if (pop3_store->engine)
+ camel_object_unref((CamelObject *)pop3_store->engine);
+ if (pop3_store->cache)
+ camel_object_unref((CamelObject *)pop3_store->cache);
+}
+
+enum {
+ USE_SSL_NEVER,
+ USE_SSL_ALWAYS,
+ USE_SSL_WHEN_POSSIBLE
+};
+
+#define SSL_PORT_FLAGS (CAMEL_TCP_STREAM_SSL_ENABLE_SSL2 | CAMEL_TCP_STREAM_SSL_ENABLE_SSL3)
+#define STARTTLS_FLAGS (CAMEL_TCP_STREAM_SSL_ENABLE_TLS)
+
+static gboolean
+connect_to_server (CamelService *service, int ssl_mode, int try_starttls, CamelException *ex)
+{
+ CamelPOP3Store *store = CAMEL_POP3_STORE (service);
+ CamelStream *tcp_stream;
+ CamelPOP3Command *pc;
+ guint32 flags = 0;
+ int clean_quit;
+ int ret;
+ struct addrinfo *ai, hints = { 0 };
+ char *serv;
+ const char *port = NULL;
+
+ if (service->url->port) {
+ serv = g_alloca(16);
+ sprintf(serv, "%d", service->url->port);
+ } else {
+ serv = "pop3";
+ port = "110";
+ }
+
+ if (ssl_mode != USE_SSL_NEVER) {
+#ifdef HAVE_SSL
+ if (try_starttls) {
+ tcp_stream = camel_tcp_stream_ssl_new_raw (service->session, service->url->host, STARTTLS_FLAGS);
+ } else {
+ if (service->url->port == 0) {
+ serv = "pop3s";
+ port = "995";
+ }
+ tcp_stream = camel_tcp_stream_ssl_new (service->session, service->url->host, SSL_PORT_FLAGS);
+ }
+#else
+ if (!try_starttls && service->url->port == 0) {
+ serv = "pop3s";
+ port = "995";
+ }
+
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ _("Could not connect to %s (port %s): %s"),
+ service->url->host, serv,
+ _("SSL unavailable"));
+
+ return FALSE;
+#endif /* HAVE_SSL */
+ } else {
+ tcp_stream = camel_tcp_stream_raw_new ();
+ }
+
+ hints.ai_socktype = SOCK_STREAM;
+ ai = camel_getaddrinfo(service->url->host, serv, &hints, ex);
+ if (ai == NULL && port != NULL && camel_exception_get_id(ex) != CAMEL_EXCEPTION_USER_CANCEL) {
+ camel_exception_clear(ex);
+ ai = camel_getaddrinfo(service->url->host, port, &hints, ex);
+ }
+ if (ai == NULL) {
+ camel_object_unref(tcp_stream);
+ return FALSE;
+ }
+
+ ret = camel_tcp_stream_connect(CAMEL_TCP_STREAM(tcp_stream), ai);
+ camel_freeaddrinfo(ai);
+ if (ret == -1) {
+ if (errno == EINTR)
+ camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL,
+ _("Connection cancelled"));
+ else
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ _("Could not connect to POP server %s (port %s): %s"),
+ service->url->host, serv, g_strerror (errno));
+
+ camel_object_unref (tcp_stream);
+
+ return FALSE;
+ }
+
+ /* parent class connect initialization */
+ if (CAMEL_SERVICE_CLASS (parent_class)->connect (service, ex) == FALSE) {
+ camel_object_unref (tcp_stream);
+ return FALSE;
+ }
+
+ if (camel_url_get_param (service->url, "disable_extensions"))
+ flags |= CAMEL_POP3_ENGINE_DISABLE_EXTENSIONS;
+
+ if (!(store->engine = camel_pop3_engine_new (tcp_stream, flags))) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Failed to read a valid greeting from POP server %s (port %s)"),
+ service->url->host, serv);
+ return FALSE;
+ }
+
+#ifdef HAVE_SSL
+ if (store->engine) {
+ if (ssl_mode == USE_SSL_WHEN_POSSIBLE) {
+ if (store->engine->capa & CAMEL_POP3_CAP_STLS)
+ goto starttls;
+ } else if (ssl_mode == USE_SSL_ALWAYS) {
+ if (try_starttls) {
+ if (store->engine->capa & CAMEL_POP3_CAP_STLS) {
+ /* attempt to toggle STARTTLS mode */
+ goto starttls;
+ } else {
+ /* server doesn't support STARTTLS, abort */
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Failed to connect to POP server %s in secure mode: %s"),
+ service->url->host, _("SSL/TLS extension not supported."));
+ /* we have the possibility of quitting cleanly here */
+ clean_quit = TRUE;
+ goto stls_exception;
+ }
+ }
+ }
+ }
+#endif /* HAVE_SSL */
+
+ camel_object_unref (tcp_stream);
+
+ return store->engine != NULL;
+
+#ifdef HAVE_SSL
+ starttls:
+ /* as soon as we send a STLS command, all hope is lost of a clean QUIT if problems arise */
+ clean_quit = FALSE;
+
+ pc = camel_pop3_engine_command_new (store->engine, 0, NULL, NULL, "STLS\r\n");
+ while (camel_pop3_engine_iterate (store->engine, NULL) > 0)
+ ;
+
+ ret = pc->state == CAMEL_POP3_COMMAND_OK;
+ camel_pop3_engine_command_free (store->engine, pc);
+
+ if (ret == FALSE) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Failed to connect to POP server %s in secure mode: %s"),
+ service->url->host, store->engine->line);
+ goto stls_exception;
+ }
+
+ /* Okay, now toggle SSL/TLS mode */
+ ret = camel_tcp_stream_ssl_enable_ssl (CAMEL_TCP_STREAM_SSL (tcp_stream));
+
+ camel_object_unref (CAMEL_OBJECT (tcp_stream));
+
+ if (ret == -1) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Failed to connect to POP server %s in secure mode: %s"),
+ service->url->host, _("SSL negotiations failed"));
+ goto stls_exception;
+ }
+
+ /* rfc2595, section 4 states that after a successful STLS
+ command, the client MUST discard prior CAPA responses */
+ camel_pop3_engine_reget_capabilities (store->engine);
+
+ return TRUE;
+
+ stls_exception:
+ if (clean_quit) {
+ /* try to disconnect cleanly */
+ pc = camel_pop3_engine_command_new (store->engine, 0, NULL, NULL, "QUIT\r\n");
+ while (camel_pop3_engine_iterate (store->engine, NULL) > 0)
+ ;
+ camel_pop3_engine_command_free (store->engine, pc);
+ }
+
+ camel_object_unref (CAMEL_OBJECT (store->engine));
+ camel_object_unref (CAMEL_OBJECT (tcp_stream));
+ store->engine = NULL;
+
+ return FALSE;
+#endif /* HAVE_SSL */
+}
+
+static struct {
+ char *value;
+ int mode;
+} ssl_options[] = {
+ { "", USE_SSL_ALWAYS },
+ { "always", USE_SSL_ALWAYS },
+ { "when-possible", USE_SSL_WHEN_POSSIBLE },
+ { "never", USE_SSL_NEVER },
+ { NULL, USE_SSL_NEVER },
+};
+
+static gboolean
+connect_to_server_wrapper (CamelService *service, CamelException *ex)
+{
+#ifdef HAVE_SSL
+ const char *use_ssl;
+ int i, ssl_mode;
+
+ use_ssl = camel_url_get_param (service->url, "use_ssl");
+ if (use_ssl) {
+ for (i = 0; ssl_options[i].value; i++)
+ if (!strcmp (ssl_options[i].value, use_ssl))
+ break;
+ ssl_mode = ssl_options[i].mode;
+ } else
+ ssl_mode = USE_SSL_NEVER;
+
+ if (ssl_mode == USE_SSL_ALWAYS) {
+ /* First try the ssl port */
+ if (!connect_to_server (service, ssl_mode, FALSE, ex)) {
+ if (camel_exception_get_id (ex) == CAMEL_EXCEPTION_SERVICE_UNAVAILABLE) {
+ /* The ssl port seems to be unavailable, lets try STARTTLS */
+ camel_exception_clear (ex);
+ return connect_to_server (service, ssl_mode, TRUE, ex);
+ } else {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+ } else if (ssl_mode == USE_SSL_WHEN_POSSIBLE) {
+ /* If the server supports STARTTLS, use it */
+ return connect_to_server (service, ssl_mode, TRUE, ex);
+ } else {
+ /* User doesn't care about SSL */
+ return connect_to_server (service, ssl_mode, FALSE, ex);
+ }
+#else
+ return connect_to_server (service, USE_SSL_NEVER, FALSE, ex);
+#endif
+}
+
+extern CamelServiceAuthType camel_pop3_password_authtype;
+extern CamelServiceAuthType camel_pop3_apop_authtype;
+
+static GList *
+query_auth_types (CamelService *service, CamelException *ex)
+{
+ CamelPOP3Store *store = CAMEL_POP3_STORE (service);
+ GList *types = NULL;
+
+ types = CAMEL_SERVICE_CLASS (parent_class)->query_auth_types (service, ex);
+ if (camel_exception_is_set (ex))
+ return NULL;
+
+ if (connect_to_server_wrapper (service, NULL)) {
+ types = g_list_concat(types, g_list_copy(store->engine->auth));
+ pop3_disconnect (service, TRUE, NULL);
+ } else {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ _("Could not connect to POP server %s"),
+ service->url->host);
+ }
+
+ return types;
+}
+
+/**
+ * camel_pop3_store_expunge:
+ * @store: the store
+ * @ex: a CamelException
+ *
+ * Expunge messages from the store. This will result in the connection
+ * being closed, which may cause later commands to fail if they can't
+ * reconnect.
+ **/
+void
+camel_pop3_store_expunge (CamelPOP3Store *store, CamelException *ex)
+{
+ CamelPOP3Command *pc;
+
+ pc = camel_pop3_engine_command_new(store->engine, 0, NULL, NULL, "QUIT\r\n");
+ while (camel_pop3_engine_iterate(store->engine, NULL) > 0)
+ ;
+ camel_pop3_engine_command_free(store->engine, pc);
+
+ camel_service_disconnect (CAMEL_SERVICE (store), FALSE, ex);
+}
+
+static int
+try_sasl(CamelPOP3Store *store, const char *mech, CamelException *ex)
+{
+ CamelPOP3Stream *stream = store->engine->stream;
+ unsigned char *line, *resp;
+ CamelSasl *sasl;
+ unsigned int len;
+ int ret;
+
+ sasl = camel_sasl_new("pop3", mech, (CamelService *)store);
+ if (sasl == NULL) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_URL_INVALID,
+ _("Unable to connect to POP server %s: "
+ "No support for requested authentication mechanism."),
+ CAMEL_SERVICE (store)->url->host);
+ return -1;
+ }
+
+ if (camel_stream_printf((CamelStream *)stream, "AUTH %s\r\n", mech) == -1)
+ goto ioerror;
+
+ while (1) {
+ if (camel_pop3_stream_line(stream, &line, &len) == -1)
+ goto ioerror;
+ if (strncmp(line, "+OK", 3) == 0)
+ break;
+ if (strncmp(line, "-ERR", 4) == 0) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
+ _("SASL `%s' Login failed for POP server %s: %s"),
+ mech, CAMEL_SERVICE (store)->url->host, line);
+ goto done;
+ }
+ /* If we dont get continuation, or the sasl object's run out of work, or we dont get a challenge,
+ its a protocol error, so fail, and try reset the server */
+ if (strncmp(line, "+ ", 2) != 0
+ || camel_sasl_authenticated(sasl)
+ || (resp = camel_sasl_challenge_base64(sasl, line+2, ex)) == NULL) {
+ camel_stream_printf((CamelStream *)stream, "*\r\n");
+ camel_pop3_stream_line(stream, &line, &len);
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
+ _("Cannot login to POP server %s: SASL Protocol error"),
+ CAMEL_SERVICE (store)->url->host);
+ goto done;
+ }
+
+ ret = camel_stream_printf((CamelStream *)stream, "%s\r\n", resp);
+ g_free(resp);
+ if (ret == -1)
+ goto ioerror;
+
+ }
+ camel_object_unref((CamelObject *)sasl);
+ return 0;
+
+ ioerror:
+ if (errno == EINTR) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL, _("Cancelled"));
+ } else {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Failed to authenticate on POP server %s: %s"),
+ CAMEL_SERVICE (store)->url->host, g_strerror (errno));
+ }
+ done:
+ camel_object_unref((CamelObject *)sasl);
+ return -1;
+}
+
+static int
+pop3_try_authenticate (CamelService *service, gboolean reprompt, const char *errmsg, CamelException *ex)
+{
+ CamelPOP3Store *store = (CamelPOP3Store *)service;
+ CamelPOP3Command *pcu = NULL, *pcp = NULL;
+ int status;
+
+ /* override, testing only */
+ /*printf("Forcing authmech to 'login'\n");
+ service->url->authmech = g_strdup("LOGIN");*/
+
+ if (!service->url->passwd) {
+ char *prompt;
+ guint32 flags = CAMEL_SESSION_PASSWORD_SECRET;
+
+ if (reprompt)
+ flags |= CAMEL_SESSION_PASSWORD_REPROMPT;
+
+ prompt = g_strdup_printf (_("%sPlease enter the POP password for %s on host %s"),
+ errmsg ? errmsg : "",
+ service->url->user,
+ service->url->host);
+ service->url->passwd = camel_session_get_password (camel_service_get_session (service), service, NULL,
+ prompt, "password", flags, ex);
+ g_free (prompt);
+ if (!service->url->passwd)
+ return FALSE;
+ }
+
+ if (!service->url->authmech) {
+ /* pop engine will take care of pipelining ability */
+ pcu = camel_pop3_engine_command_new(store->engine, 0, NULL, NULL, "USER %s\r\n", service->url->user);
+ pcp = camel_pop3_engine_command_new(store->engine, 0, NULL, NULL, "PASS %s\r\n", service->url->passwd);
+ } else if (strcmp(service->url->authmech, "+APOP") == 0 && store->engine->apop) {
+ char *secret, md5asc[33], *d;
+ unsigned char md5sum[16], *s;
+
+ secret = g_alloca(strlen(store->engine->apop)+strlen(service->url->passwd)+1);
+ sprintf(secret, "%s%s", store->engine->apop, service->url->passwd);
+ md5_get_digest(secret, strlen (secret), md5sum);
+
+ for (s = md5sum, d = md5asc; d < md5asc + 32; s++, d += 2)
+ sprintf (d, "%.2x", *s);
+
+ pcp = camel_pop3_engine_command_new(store->engine, 0, NULL, NULL, "APOP %s %s\r\n",
+ service->url->user, md5asc);
+ } else {
+ CamelServiceAuthType *auth;
+ GList *l;
+
+ l = store->engine->auth;
+ while (l) {
+ auth = l->data;
+ if (strcmp(auth->authproto, service->url->authmech) == 0)
+ return try_sasl(store, service->url->authmech, ex) == -1;
+ l = l->next;
+ }
+
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_URL_INVALID,
+ _("Unable to connect to POP server %s: "
+ "No support for requested authentication mechanism."),
+ CAMEL_SERVICE (store)->url->host);
+ return FALSE;
+ }
+
+ while ((status = camel_pop3_engine_iterate(store->engine, pcp)) > 0)
+ ;
+
+ if (status == -1) {
+ if (errno == EINTR) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL, _("Cancelled"));
+ } else {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Unable to connect to POP server %s.\n"
+ "Error sending password: %s"),
+ CAMEL_SERVICE (store)->url->host,
+ errno ? g_strerror (errno) : _("Unknown error"));
+ }
+ } else if (pcu && pcu->state != CAMEL_POP3_COMMAND_OK) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
+ _("Unable to connect to POP server %s.\n"
+ "Error sending username: %s"),
+ CAMEL_SERVICE (store)->url->host,
+ store->engine->line ? (char *)store->engine->line : _("Unknown error"));
+ } else if (pcp->state != CAMEL_POP3_COMMAND_OK)
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
+ _("Unable to connect to POP server %s.\n"
+ "Error sending password: %s"),
+ CAMEL_SERVICE (store)->url->host,
+ store->engine->line ? (char *)store->engine->line : _("Unknown error"));
+
+ camel_pop3_engine_command_free(store->engine, pcp);
+
+ if (pcu)
+ camel_pop3_engine_command_free(store->engine, pcu);
+
+ return status;
+}
+
+static gboolean
+pop3_connect (CamelService *service, CamelException *ex)
+{
+ CamelPOP3Store *store = (CamelPOP3Store *)service;
+ gboolean reprompt = FALSE;
+ CamelSession *session;
+ char *errbuf = NULL;
+ int status;
+
+ session = camel_service_get_session (service);
+
+ if (store->cache == NULL) {
+ char *root;
+
+ root = camel_session_get_storage_path (session, service, ex);
+ if (root) {
+ store->cache = camel_data_cache_new(root, 0, ex);
+ g_free(root);
+ if (store->cache) {
+ /* Default cache expiry - 1 week or not visited in a day */
+ camel_data_cache_set_expire_age(store->cache, 60*60*24*7);
+ camel_data_cache_set_expire_access(store->cache, 60*60*24);
+ }
+ }
+ }
+
+ if (!connect_to_server_wrapper (service, ex))
+ return FALSE;
+
+ while (1) {
+ status = pop3_try_authenticate (service, reprompt, errbuf, ex);
+ g_free (errbuf);
+ errbuf = NULL;
+
+ /* we only re-prompt if we failed to authenticate, any other error and we just abort */
+ if (status == 0 && camel_exception_get_id (ex) == CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE) {
+ errbuf = g_strdup_printf ("%s\n\n", camel_exception_get_description (ex));
+ g_free (service->url->passwd);
+ service->url->passwd = NULL;
+ reprompt = TRUE;
+ camel_exception_clear (ex);
+ } else
+ break;
+ }
+
+ g_free (errbuf);
+
+ if (status == -1 || camel_exception_is_set(ex)) {
+ camel_service_disconnect(service, TRUE, ex);
+ return FALSE;
+ }
+
+ /* Now that we are in the TRANSACTION state, try regetting the capabilities */
+ store->engine->state = CAMEL_POP3_ENGINE_TRANSACTION;
+ camel_pop3_engine_reget_capabilities (store->engine);
+
+ return TRUE;
+}
+
+static gboolean
+pop3_disconnect (CamelService *service, gboolean clean, CamelException *ex)
+{
+ CamelPOP3Store *store = CAMEL_POP3_STORE (service);
+
+ if (clean) {
+ CamelPOP3Command *pc;
+
+ pc = camel_pop3_engine_command_new(store->engine, 0, NULL, NULL, "QUIT\r\n");
+ while (camel_pop3_engine_iterate(store->engine, NULL) > 0)
+ ;
+ camel_pop3_engine_command_free(store->engine, pc);
+ }
+
+ if (!CAMEL_SERVICE_CLASS (parent_class)->disconnect (service, clean, ex))
+ return FALSE;
+
+ camel_object_unref((CamelObject *)store->engine);
+ store->engine = NULL;
+
+ return TRUE;
+}
+
+static CamelFolder *
+get_folder (CamelStore *store, const char *folder_name, guint32 flags, CamelException *ex)
+{
+ if (g_ascii_strcasecmp (folder_name, "inbox") != 0) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_INVALID,
+ _("No such folder `%s'."), folder_name);
+ return NULL;
+ }
+ return camel_pop3_folder_new (store, ex);
+}
+
+static CamelFolder *
+get_trash (CamelStore *store, CamelException *ex)
+{
+ /* no-op */
+ return NULL;
+}
diff --git a/camel/providers/smtp/camel-smtp-transport.c b/camel/providers/smtp/camel-smtp-transport.c
new file mode 100644
index 0000000000..ea8ca26e49
--- /dev/null
+++ b/camel/providers/smtp/camel-smtp-transport.c
@@ -0,0 +1,1413 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* camel-smtp-transport.c : class for a smtp transport */
+
+/*
+ * Authors: Jeffrey Stedfast <fejj@ximian.com>
+ *
+ * Copyright (C) 2000 Ximian, Inc. (www.ximian.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#undef MIN
+#undef MAX
+#include "camel-mime-filter-crlf.h"
+#include "camel-stream-filter.h"
+#include "camel-smtp-transport.h"
+#include "camel-mime-message.h"
+#include "camel-multipart.h"
+#include "camel-mime-part.h"
+#include "camel-operation.h"
+#include "camel-stream-buffer.h"
+#include "camel-tcp-stream.h"
+#include "camel-tcp-stream-raw.h"
+#ifdef HAVE_SSL
+#include "camel-tcp-stream-ssl.h"
+#endif
+#include "camel-session.h"
+#include "camel-exception.h"
+#include "camel-sasl.h"
+
+
+extern int camel_verbose_debug;
+#define d(x) (camel_verbose_debug ? (x) : 0)
+
+/* Specified in RFC 821 */
+#define SMTP_PORT 25
+
+/* camel smtp transport class prototypes */
+static gboolean smtp_send_to (CamelTransport *transport, CamelMimeMessage *message,
+ CamelAddress *from, CamelAddress *recipients, CamelException *ex);
+
+/* support prototypes */
+static void smtp_construct (CamelService *service, CamelSession *session,
+ CamelProvider *provider, CamelURL *url,
+ CamelException *ex);
+static gboolean smtp_connect (CamelService *service, CamelException *ex);
+static gboolean smtp_disconnect (CamelService *service, gboolean clean, CamelException *ex);
+static GHashTable *esmtp_get_authtypes (const unsigned char *buffer);
+static GList *query_auth_types (CamelService *service, CamelException *ex);
+static char *get_name (CamelService *service, gboolean brief);
+
+static gboolean smtp_helo (CamelSmtpTransport *transport, CamelException *ex);
+static gboolean smtp_auth (CamelSmtpTransport *transport, const char *mech, CamelException *ex);
+static gboolean smtp_mail (CamelSmtpTransport *transport, const char *sender,
+ gboolean has_8bit_parts, CamelException *ex);
+static gboolean smtp_rcpt (CamelSmtpTransport *transport, const char *recipient, CamelException *ex);
+static gboolean smtp_data (CamelSmtpTransport *transport, CamelMimeMessage *message, CamelException *ex);
+static gboolean smtp_rset (CamelSmtpTransport *transport, CamelException *ex);
+static gboolean smtp_quit (CamelSmtpTransport *transport, CamelException *ex);
+
+static void smtp_set_exception (CamelSmtpTransport *transport, gboolean disconnect, const char *respbuf,
+ const char *message, CamelException *ex);
+
+/* private data members */
+static CamelTransportClass *parent_class = NULL;
+
+static void
+camel_smtp_transport_class_init (CamelSmtpTransportClass *camel_smtp_transport_class)
+{
+ CamelTransportClass *camel_transport_class =
+ CAMEL_TRANSPORT_CLASS (camel_smtp_transport_class);
+ CamelServiceClass *camel_service_class =
+ CAMEL_SERVICE_CLASS (camel_smtp_transport_class);
+
+ parent_class = CAMEL_TRANSPORT_CLASS (camel_type_get_global_classfuncs (camel_transport_get_type ()));
+
+ /* virtual method overload */
+ camel_service_class->construct = smtp_construct;
+ camel_service_class->connect = smtp_connect;
+ camel_service_class->disconnect = smtp_disconnect;
+ camel_service_class->query_auth_types = query_auth_types;
+ camel_service_class->get_name = get_name;
+
+ camel_transport_class->send_to = smtp_send_to;
+}
+
+static void
+camel_smtp_transport_init (gpointer object)
+{
+ CamelSmtpTransport *smtp = CAMEL_SMTP_TRANSPORT (object);
+
+ smtp->flags = 0;
+ smtp->connected = FALSE;
+}
+
+CamelType
+camel_smtp_transport_get_type (void)
+{
+ static CamelType type = CAMEL_INVALID_TYPE;
+
+ if (type == CAMEL_INVALID_TYPE) {
+ type = camel_type_register (CAMEL_TRANSPORT_TYPE,
+ "CamelSmtpTransport",
+ sizeof (CamelSmtpTransport),
+ sizeof (CamelSmtpTransportClass),
+ (CamelObjectClassInitFunc) camel_smtp_transport_class_init,
+ NULL,
+ (CamelObjectInitFunc) camel_smtp_transport_init,
+ NULL);
+ }
+
+ return type;
+}
+
+static void
+smtp_construct (CamelService *service, CamelSession *session,
+ CamelProvider *provider, CamelURL *url,
+ CamelException *ex)
+{
+ CamelSmtpTransport *smtp_transport = CAMEL_SMTP_TRANSPORT (service);
+ const char *use_ssl;
+
+ CAMEL_SERVICE_CLASS (parent_class)->construct (service, session, provider, url, ex);
+
+ if ((use_ssl = camel_url_get_param (url, "use_ssl"))) {
+ /* Note: previous versions would use "" to toggle use_ssl to 'on' */
+ if (!*use_ssl || !strcmp (use_ssl, "always"))
+ smtp_transport->flags |= CAMEL_SMTP_TRANSPORT_USE_SSL_ALWAYS;
+ else if (!strcmp (use_ssl, "when-possible"))
+ smtp_transport->flags |= CAMEL_SMTP_TRANSPORT_USE_SSL_WHEN_POSSIBLE;
+ }
+}
+
+static const char *
+smtp_error_string (int error)
+{
+ /* SMTP error codes grabbed from rfc821 */
+ switch (error) {
+ case 0:
+ /* looks like a read problem, check errno */
+ if (errno)
+ return g_strerror (errno);
+ else
+ return _("Unknown");
+ case 500:
+ return _("Syntax error, command unrecognized");
+ case 501:
+ return _("Syntax error in parameters or arguments");
+ case 502:
+ return _("Command not implemented");
+ case 504:
+ return _("Command parameter not implemented");
+ case 211:
+ return _("System status, or system help reply");
+ case 214:
+ return _("Help message");
+ case 220:
+ return _("Service ready");
+ case 221:
+ return _("Service closing transmission channel");
+ case 421:
+ return _("Service not available, closing transmission channel");
+ case 250:
+ return _("Requested mail action okay, completed");
+ case 251:
+ return _("User not local; will forward to <forward-path>");
+ case 450:
+ return _("Requested mail action not taken: mailbox unavailable");
+ case 550:
+ return _("Requested action not taken: mailbox unavailable");
+ case 451:
+ return _("Requested action aborted: error in processing");
+ case 551:
+ return _("User not local; please try <forward-path>");
+ case 452:
+ return _("Requested action not taken: insufficient system storage");
+ case 552:
+ return _("Requested mail action aborted: exceeded storage allocation");
+ case 553:
+ return _("Requested action not taken: mailbox name not allowed");
+ case 354:
+ return _("Start mail input; end with <CRLF>.<CRLF>");
+ case 554:
+ return _("Transaction failed");
+
+ /* AUTH error codes: */
+ case 432:
+ return _("A password transition is needed");
+ case 534:
+ return _("Authentication mechanism is too weak");
+ case 538:
+ return _("Encryption required for requested authentication mechanism");
+ case 454:
+ return _("Temporary authentication failure");
+ case 530:
+ return _("Authentication required");
+
+ default:
+ return _("Unknown");
+ }
+}
+
+#define SSL_PORT_FLAGS (CAMEL_TCP_STREAM_SSL_ENABLE_SSL2 | CAMEL_TCP_STREAM_SSL_ENABLE_SSL3)
+#define STARTTLS_FLAGS (CAMEL_TCP_STREAM_SSL_ENABLE_TLS)
+
+static gboolean
+connect_to_server (CamelService *service, int try_starttls, CamelException *ex)
+{
+ CamelSmtpTransport *transport = CAMEL_SMTP_TRANSPORT (service);
+ CamelStream *tcp_stream;
+ char *respbuf = NULL;
+ int ret;
+ struct addrinfo *ai, hints = { 0 };
+ char *serv;
+ const char *port = NULL;
+
+ if (!CAMEL_SERVICE_CLASS (parent_class)->connect (service, ex))
+ return FALSE;
+
+ /* set some smtp transport defaults */
+ transport->flags &= CAMEL_SMTP_TRANSPORT_USE_SSL; /* reset all but ssl flags */
+ transport->authtypes = NULL;
+
+ if (service->url->port) {
+ serv = g_alloca(16);
+ sprintf(serv, "%d", service->url->port);
+ } else {
+ serv = "smtp";
+ port = "25";
+ }
+
+ if (transport->flags & CAMEL_SMTP_TRANSPORT_USE_SSL) {
+#ifdef HAVE_SSL
+ if (try_starttls) {
+ tcp_stream = camel_tcp_stream_ssl_new_raw (service->session, service->url->host, STARTTLS_FLAGS);
+ } else {
+ if (service->url->port == 0) {
+ serv = "smtps";
+ port = "465";
+ }
+ tcp_stream = camel_tcp_stream_ssl_new (service->session, service->url->host, SSL_PORT_FLAGS);
+ }
+#else
+ if (!try_starttls && service->url->port == 0) {
+ serv = "smtps";
+ port = "465";
+ }
+
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ _("Could not connect to %s (port %s): %s"),
+ service->url->host, serv,
+ _("SSL unavailable"));
+
+ return FALSE;
+#endif /* HAVE_SSL */
+ } else {
+ tcp_stream = camel_tcp_stream_raw_new ();
+ }
+
+ hints.ai_socktype = SOCK_STREAM;
+ ai = camel_getaddrinfo(service->url->host, serv, &hints, ex);
+ /* fallback to numerical port if the system is misconfigured */
+ if (ai == NULL && port != NULL && camel_exception_get_id(ex) != CAMEL_EXCEPTION_USER_CANCEL) {
+ camel_exception_clear(ex);
+ ai = camel_getaddrinfo(service->url->host, port, &hints, ex);
+ }
+ if (ai == NULL) {
+ camel_object_unref(tcp_stream);
+ return FALSE;
+ }
+
+ ret = camel_tcp_stream_connect(CAMEL_TCP_STREAM(tcp_stream), ai);
+ camel_freeaddrinfo(ai);
+ if (ret == -1) {
+ camel_exception_setv (ex, errno == EINTR ? CAMEL_EXCEPTION_USER_CANCEL : CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ _("Could not connect to %s (port %s): %s"),
+ service->url->host, serv,
+ g_strerror (errno));
+
+ camel_object_unref (tcp_stream);
+
+ return FALSE;
+ }
+
+ transport->connected = TRUE;
+
+ /* get the localaddr - needed later by smtp_helo */
+ transport->localaddr = camel_tcp_stream_get_local_address (CAMEL_TCP_STREAM (tcp_stream), &transport->localaddrlen);
+
+ transport->ostream = tcp_stream;
+ transport->istream = camel_stream_buffer_new (tcp_stream, CAMEL_STREAM_BUFFER_READ);
+
+ /* Read the greeting, note whether the server is ESMTP or not. */
+ do {
+ /* Check for "220" */
+ g_free (respbuf);
+ respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream));
+ if (!respbuf || strncmp (respbuf, "220", 3)) {
+ smtp_set_exception (transport, FALSE, respbuf, _("Welcome response error"), ex);
+ g_free (respbuf);
+ return FALSE;
+ }
+ } while (*(respbuf+3) == '-'); /* if we got "220-" then loop again */
+ g_free (respbuf);
+
+ /* Try sending EHLO */
+ transport->flags |= CAMEL_SMTP_TRANSPORT_IS_ESMTP;
+ if (!smtp_helo (transport, ex)) {
+ if (!transport->connected)
+ return FALSE;
+
+ /* Fall back to HELO */
+ camel_exception_clear (ex);
+ transport->flags &= ~CAMEL_SMTP_TRANSPORT_IS_ESMTP;
+ if (!smtp_helo (transport, ex) && !transport->connected)
+ return FALSE;
+ }
+
+ /* clear any EHLO/HELO exception and assume that any SMTP errors encountered were non-fatal */
+ camel_exception_clear (ex);
+
+#ifdef HAVE_SSL
+ if (transport->flags & CAMEL_SMTP_TRANSPORT_USE_SSL_WHEN_POSSIBLE) {
+ /* try_starttls is always TRUE here */
+ if (transport->flags & CAMEL_SMTP_TRANSPORT_STARTTLS)
+ goto starttls;
+ } else if (transport->flags & CAMEL_SMTP_TRANSPORT_USE_SSL_ALWAYS) {
+ if (try_starttls) {
+ if (transport->flags & CAMEL_SMTP_TRANSPORT_STARTTLS) {
+ goto starttls;
+ } else {
+ /* server doesn't support STARTTLS, abort */
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Failed to connect to SMTP server %s in secure mode: %s"),
+ service->url->host, _("server does not appear to support SSL"));
+ goto exception_cleanup;
+ }
+ }
+ }
+#endif /* HAVE_SSL */
+
+ return TRUE;
+
+#ifdef HAVE_SSL
+ starttls:
+ d(fprintf (stderr, "sending : STARTTLS\r\n"));
+ if (camel_stream_write (tcp_stream, "STARTTLS\r\n", 10) == -1) {
+ camel_exception_setv (ex, errno == EINTR ? CAMEL_EXCEPTION_USER_CANCEL : CAMEL_EXCEPTION_SYSTEM,
+ _("STARTTLS command failed: %s"),
+ g_strerror (errno));
+ goto exception_cleanup;
+ }
+
+ respbuf = NULL;
+
+ do {
+ /* Check for "220 Ready for TLS" */
+ g_free (respbuf);
+ respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream));
+
+ d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)"));
+
+ if (!respbuf || strncmp (respbuf, "220", 3)) {
+ smtp_set_exception (transport, FALSE, respbuf, _("STARTTLS command failed"), ex);
+ g_free (respbuf);
+ goto exception_cleanup;
+ }
+ } while (*(respbuf+3) == '-'); /* if we got "220-" then loop again */
+
+ /* Okay, now toggle SSL/TLS mode */
+ if (camel_tcp_stream_ssl_enable_ssl (CAMEL_TCP_STREAM_SSL (tcp_stream)) == -1) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Failed to connect to SMTP server %s in secure mode: %s"),
+ service->url->host, g_strerror (errno));
+ goto exception_cleanup;
+ }
+
+ /* We are supposed to re-EHLO after a successful STARTTLS to
+ re-fetch any supported extensions. */
+ if (!smtp_helo (transport, ex) && !transport->connected)
+ return FALSE;
+
+ return TRUE;
+
+ exception_cleanup:
+
+ camel_object_unref (transport->istream);
+ transport->istream = NULL;
+ camel_object_unref (transport->ostream);
+ transport->ostream = NULL;
+
+ transport->connected = FALSE;
+
+ return FALSE;
+#endif /* HAVE_SSL */
+}
+
+static gboolean
+connect_to_server_wrapper (CamelService *service, CamelException *ex)
+{
+#ifdef HAVE_SSL
+ CamelSmtpTransport *transport = (CamelSmtpTransport *) service;
+
+ if (transport->flags & CAMEL_SMTP_TRANSPORT_USE_SSL_ALWAYS) {
+ /* First try connecting to the SSL port */
+ if (!connect_to_server (service, FALSE, ex)) {
+ if (camel_exception_get_id (ex) == CAMEL_EXCEPTION_SERVICE_UNAVAILABLE) {
+ /* Seems the SSL port is unavailable, lets try STARTTLS */
+ camel_exception_clear (ex);
+ return connect_to_server (service, TRUE, ex);
+ } else {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+ } else if (transport->flags & CAMEL_SMTP_TRANSPORT_USE_SSL_WHEN_POSSIBLE) {
+ /* If the server supports STARTTLS, use it */
+ return connect_to_server (service, TRUE, ex);
+ } else {
+ /* User doesn't care about SSL */
+ return connect_to_server (service, FALSE, ex);
+ }
+#else
+ return connect_to_server (service, FALSE, ex);
+#endif
+}
+
+static gboolean
+smtp_connect (CamelService *service, CamelException *ex)
+{
+ CamelSmtpTransport *transport = CAMEL_SMTP_TRANSPORT (service);
+ gboolean has_authtypes;
+
+ /* We (probably) need to check popb4smtp before we connect ... */
+ if (service->url->authmech && !strcmp (service->url->authmech, "POPB4SMTP")) {
+ int truth;
+ GByteArray *chal;
+ CamelSasl *sasl;
+
+ sasl = camel_sasl_new ("smtp", "POPB4SMTP", service);
+ chal = camel_sasl_challenge (sasl, NULL, ex);
+ truth = camel_sasl_authenticated (sasl);
+ if (chal)
+ g_byte_array_free (chal, TRUE);
+ camel_object_unref (sasl);
+
+ if (!truth)
+ return FALSE;
+
+ return connect_to_server_wrapper (service, ex);
+ }
+
+ if (!connect_to_server_wrapper (service, ex))
+ return FALSE;
+
+ /* check to see if AUTH is required, if so...then AUTH ourselves */
+ has_authtypes = transport->authtypes ? g_hash_table_size (transport->authtypes) > 0 : FALSE;
+ if (service->url->authmech && (transport->flags & CAMEL_SMTP_TRANSPORT_IS_ESMTP) && has_authtypes) {
+ CamelSession *session = camel_service_get_session (service);
+ CamelServiceAuthType *authtype;
+ gboolean authenticated = FALSE;
+ char *errbuf = NULL;
+
+ if (!g_hash_table_lookup (transport->authtypes, service->url->authmech)) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
+ _("SMTP server %s does not support requested "
+ "authentication type %s."),
+ service->url->host, service->url->authmech);
+ camel_service_disconnect (service, TRUE, NULL);
+ return FALSE;
+ }
+
+ authtype = camel_sasl_authtype (service->url->authmech);
+ if (!authtype) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
+ _("No support for authentication type %s"),
+ service->url->authmech);
+ camel_service_disconnect (service, TRUE, NULL);
+ return FALSE;
+ }
+
+ if (!authtype->need_password) {
+ /* authentication mechanism doesn't need a password,
+ so if it fails there's nothing we can do */
+ authenticated = smtp_auth (transport, authtype->authproto, ex);
+ if (!authenticated) {
+ camel_service_disconnect (service, TRUE, NULL);
+ return FALSE;
+ }
+ }
+
+ /* keep trying to login until either we succeed or the user cancels */
+ while (!authenticated) {
+ if (errbuf) {
+ /* We need to un-cache the password before prompting again */
+ camel_session_forget_password (session, service, NULL, "password", NULL);
+ g_free (service->url->passwd);
+ service->url->passwd = NULL;
+ }
+
+ if (!service->url->passwd) {
+ char *prompt;
+
+ prompt = g_strdup_printf (_("%sPlease enter the SMTP password for %s on host %s"),
+ errbuf ? errbuf : "", service->url->user,
+ service->url->host);
+
+ service->url->passwd = camel_session_get_password (session, service, NULL,
+ prompt, "password", CAMEL_SESSION_PASSWORD_SECRET, ex);
+
+ g_free (prompt);
+ g_free (errbuf);
+ errbuf = NULL;
+
+ if (!service->url->passwd) {
+ camel_service_disconnect (service, TRUE, NULL);
+ return FALSE;
+ }
+ }
+
+ authenticated = smtp_auth (transport, authtype->authproto, ex);
+ if (!authenticated) {
+ errbuf = g_strdup_printf (_("Unable to authenticate "
+ "to SMTP server.\n%s\n\n"),
+ camel_exception_get_description (ex));
+ camel_exception_clear (ex);
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+static void
+authtypes_free (gpointer key, gpointer value, gpointer data)
+{
+ g_free (value);
+}
+
+static gboolean
+smtp_disconnect (CamelService *service, gboolean clean, CamelException *ex)
+{
+ CamelSmtpTransport *transport = CAMEL_SMTP_TRANSPORT (service);
+
+ /*if (!service->connected)
+ * return TRUE;
+ */
+
+ if (transport->connected && clean) {
+ /* send the QUIT command to the SMTP server */
+ smtp_quit (transport, ex);
+ }
+
+ if (!CAMEL_SERVICE_CLASS (parent_class)->disconnect (service, clean, ex))
+ return FALSE;
+
+ if (transport->authtypes) {
+ g_hash_table_foreach (transport->authtypes, authtypes_free, NULL);
+ g_hash_table_destroy (transport->authtypes);
+ transport->authtypes = NULL;
+ }
+
+ if (transport->istream) {
+ camel_object_unref (transport->istream);
+ transport->istream = NULL;
+ }
+
+ if (transport->ostream) {
+ camel_object_unref (transport->ostream);
+ transport->ostream = NULL;
+ }
+
+ g_free(transport->localaddr);
+ transport->localaddr = NULL;
+
+ transport->connected = FALSE;
+
+ return TRUE;
+}
+
+static GHashTable *
+esmtp_get_authtypes (const unsigned char *buffer)
+{
+ const unsigned char *start, *end;
+ GHashTable *table = NULL;
+
+ /* advance to the first token */
+ start = buffer;
+ while (isspace ((int) *start) || *start == '=')
+ start++;
+
+ if (!*start)
+ return NULL;
+
+ table = g_hash_table_new (g_str_hash, g_str_equal);
+
+ for ( ; *start; ) {
+ char *type;
+
+ /* advance to the end of the token */
+ end = start;
+ while (*end && !isspace ((int) *end))
+ end++;
+
+ type = g_strndup (start, end - start);
+ g_hash_table_insert (table, type, type);
+
+ /* advance to the next token */
+ start = end;
+ while (isspace ((int) *start))
+ start++;
+ }
+
+ return table;
+}
+
+static GList *
+query_auth_types (CamelService *service, CamelException *ex)
+{
+ CamelSmtpTransport *transport = CAMEL_SMTP_TRANSPORT (service);
+ CamelServiceAuthType *authtype;
+ GList *types, *t, *next;
+
+ if (!connect_to_server_wrapper (service, ex))
+ return NULL;
+
+ types = g_list_copy (service->provider->authtypes);
+ for (t = types; t; t = next) {
+ authtype = t->data;
+ next = t->next;
+
+ if (!g_hash_table_lookup (transport->authtypes, authtype->authproto)) {
+ types = g_list_remove_link (types, t);
+ g_list_free_1 (t);
+ }
+ }
+
+ smtp_disconnect (service, TRUE, NULL);
+
+ return types;
+}
+
+static char *
+get_name (CamelService *service, gboolean brief)
+{
+ if (brief)
+ return g_strdup_printf (_("SMTP server %s"), service->url->host);
+ else {
+ return g_strdup_printf (_("SMTP mail delivery via %s"),
+ service->url->host);
+ }
+}
+
+static gboolean
+smtp_send_to (CamelTransport *transport, CamelMimeMessage *message,
+ CamelAddress *from, CamelAddress *recipients,
+ CamelException *ex)
+{
+ CamelSmtpTransport *smtp_transport = CAMEL_SMTP_TRANSPORT (transport);
+ const CamelInternetAddress *cia;
+ gboolean has_8bit_parts;
+ const char *addr;
+ int i, len;
+
+ if (!smtp_transport->connected) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_NOT_CONNECTED,
+ _("Cannot send message: service not connected."));
+ return FALSE;
+ }
+
+ if (!camel_internet_address_get (CAMEL_INTERNET_ADDRESS (from), 0, NULL, &addr)) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot send message: sender address not valid."));
+ return FALSE;
+ }
+
+ camel_operation_start (NULL, _("Sending message"));
+
+ /* find out if the message has 8bit mime parts */
+ has_8bit_parts = camel_mime_message_has_8bit_parts (message);
+
+ /* rfc1652 (8BITMIME) requires that you notify the ESMTP daemon that
+ you'll be sending an 8bit mime message at "MAIL FROM:" time. */
+ if (!smtp_mail (smtp_transport, addr, has_8bit_parts, ex)) {
+ camel_operation_end (NULL);
+ return FALSE;
+ }
+
+ len = camel_address_length (recipients);
+ if (len == 0) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot send message: no recipients defined."));
+ camel_operation_end (NULL);
+ return FALSE;
+ }
+
+ cia = CAMEL_INTERNET_ADDRESS (recipients);
+ for (i = 0; i < len; i++) {
+ char *enc;
+
+ if (!camel_internet_address_get (cia, i, NULL, &addr)) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot send message: one or more invalid recipients"));
+ camel_operation_end (NULL);
+ return FALSE;
+ }
+
+ enc = camel_internet_address_encode_address(NULL, NULL, addr);
+ if (!smtp_rcpt (smtp_transport, enc, ex)) {
+ g_free(enc);
+ camel_operation_end (NULL);
+ return FALSE;
+ }
+ g_free(enc);
+ }
+
+ if (!smtp_data (smtp_transport, message, ex)) {
+ camel_operation_end (NULL);
+ return FALSE;
+ }
+
+ /* reset the service for our next transfer session */
+ if (!smtp_rset (smtp_transport, ex))
+ camel_exception_clear (ex);
+
+ camel_operation_end (NULL);
+
+ return TRUE;
+}
+
+static const char *
+smtp_next_token (const char *buf)
+{
+ const unsigned char *token;
+
+ token = (const unsigned char *) buf;
+ while (*token && !isspace ((int) *token))
+ token++;
+
+ while (*token && isspace ((int) *token))
+ token++;
+
+ return (const char *) token;
+}
+
+#define HEXVAL(c) (isdigit (c) ? (c) - '0' : (c) - 'A' + 10)
+
+/**
+ * example (rfc2034):
+ * 5.1.1 Mailbox "nosuchuser" does not exist
+ *
+ * The human-readable status code is what we want. Since this text
+ * could possibly be encoded, we must decode it.
+ *
+ * "xtext" is formally defined as follows:
+ *
+ * xtext = *( xchar / hexchar / linear-white-space / comment )
+ *
+ * xchar = any ASCII CHAR between "!" (33) and "~" (126) inclusive,
+ * except for "+", "\" and "(".
+ *
+ * "hexchar"s are intended to encode octets that cannot be represented
+ * as plain text, either because they are reserved, or because they are
+ * non-printable. However, any octet value may be represented by a
+ * "hexchar".
+ *
+ * hexchar = ASCII "+" immediately followed by two upper case
+ * hexadecimal digits
+ **/
+static char *
+smtp_decode_status_code (const char *in, size_t len)
+{
+ unsigned char *inptr, *outptr;
+ const unsigned char *inend;
+ char *outbuf;
+
+ outptr = outbuf = g_malloc (len + 1);
+
+ inptr = (unsigned char *) in;
+ inend = inptr + len;
+ while (inptr < inend) {
+ if (*inptr == '+') {
+ if (isxdigit (inptr[1]) && isxdigit (inptr[2])) {
+ *outptr++ = HEXVAL (inptr[1]) * 16 + HEXVAL (inptr[2]);
+ inptr += 3;
+ } else
+ *outptr++ = *inptr++;
+ } else
+ *outptr++ = *inptr++;
+ }
+
+ *outptr = '\0';
+
+ return outbuf;
+}
+
+static void
+smtp_set_exception (CamelSmtpTransport *transport, gboolean disconnect, const char *respbuf, const char *message, CamelException *ex)
+{
+ const char *token, *rbuf = respbuf;
+ char *buffer = NULL;
+ GString *string;
+ int error;
+
+ if (!respbuf || !(transport->flags & CAMEL_SMTP_TRANSPORT_ENHANCEDSTATUSCODES)) {
+ fake_status_code:
+ error = respbuf ? atoi (respbuf) : 0;
+ camel_exception_setv (ex, error == 0 && errno == EINTR ? CAMEL_EXCEPTION_USER_CANCEL : CAMEL_EXCEPTION_SYSTEM,
+ "%s: %s", message, smtp_error_string (error));
+ } else {
+ string = g_string_new ("");
+ do {
+ token = smtp_next_token (rbuf + 4);
+ if (*token == '\0') {
+ g_free (buffer);
+ g_string_free (string, TRUE);
+ goto fake_status_code;
+ }
+
+ g_string_append (string, token);
+ if (*(rbuf + 3) == '-') {
+ g_free (buffer);
+ buffer = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream));
+ g_string_append_c (string, '\n');
+ } else {
+ g_free (buffer);
+ buffer = NULL;
+ }
+
+ rbuf = buffer;
+ } while (rbuf);
+
+ buffer = smtp_decode_status_code (string->str, string->len);
+ g_string_free (string, TRUE);
+ if (!buffer)
+ goto fake_status_code;
+
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ "%s: %s", message, buffer);
+
+ g_free (buffer);
+ }
+
+ if (!respbuf) {
+ /* we got disconnected */
+ if (disconnect)
+ camel_service_disconnect ((CamelService *) transport, FALSE, NULL);
+ else
+ transport->connected = FALSE;
+ }
+}
+
+static gboolean
+smtp_helo (CamelSmtpTransport *transport, CamelException *ex)
+{
+ /* say hello to the server */
+ char *name = NULL, *cmdbuf = NULL, *respbuf = NULL;
+ const char *token, *numeric = NULL;
+
+ /* these are flags that we set, so unset them in case we
+ are being called a second time (ie, after a STARTTLS) */
+ transport->flags &= ~(CAMEL_SMTP_TRANSPORT_8BITMIME |
+ CAMEL_SMTP_TRANSPORT_ENHANCEDSTATUSCODES |
+ CAMEL_SMTP_TRANSPORT_STARTTLS);
+
+ if (transport->authtypes) {
+ g_hash_table_foreach (transport->authtypes, authtypes_free, NULL);
+ g_hash_table_destroy (transport->authtypes);
+ transport->authtypes = NULL;
+ }
+
+ camel_operation_start_transient (NULL, _("SMTP Greeting"));
+
+ /* force name resolution first, fallback to numerical, we need to know when it falls back */
+ if (camel_getnameinfo(transport->localaddr, transport->localaddrlen, &name, NULL, NI_NAMEREQD, NULL) != 0) {
+ if (camel_getnameinfo(transport->localaddr, transport->localaddrlen, &name, NULL, NI_NUMERICHOST, NULL) != 0)
+ name = g_strdup("localhost.localdomain");
+ else {
+ if (transport->localaddr->sa_family == AF_INET6)
+ numeric = "IPv6:";
+ else
+ numeric = "";
+ }
+ }
+
+ /* hiya server! how are you today? */
+ token = (transport->flags & CAMEL_SMTP_TRANSPORT_IS_ESMTP) ? "EHLO" : "HELO";
+ if (numeric)
+ cmdbuf = g_strdup_printf("%s [%s%s]\r\n", token, numeric, name);
+ else
+ cmdbuf = g_strdup_printf("%s %s\r\n", token, name);
+ g_free (name);
+
+ d(fprintf (stderr, "sending : %s", cmdbuf));
+ if (camel_stream_write (transport->ostream, cmdbuf, strlen (cmdbuf)) == -1) {
+ g_free (cmdbuf);
+ camel_exception_setv (ex, errno == EINTR ? CAMEL_EXCEPTION_USER_CANCEL : CAMEL_EXCEPTION_SYSTEM,
+ _("HELO command failed: %s"), g_strerror (errno));
+ camel_operation_end (NULL);
+
+ camel_service_disconnect ((CamelService *) transport, FALSE, NULL);
+
+ return FALSE;
+ }
+ g_free (cmdbuf);
+
+ do {
+ /* Check for "250" */
+ g_free (respbuf);
+ respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream));
+
+ d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)"));
+
+ if (!respbuf || strncmp (respbuf, "250", 3)) {
+ smtp_set_exception (transport, FALSE, respbuf, _("HELO command failed"), ex);
+ camel_operation_end (NULL);
+ g_free (respbuf);
+
+ return FALSE;
+ }
+
+ token = respbuf + 4;
+
+ if (transport->flags & CAMEL_SMTP_TRANSPORT_IS_ESMTP) {
+ if (!strncmp (token, "8BITMIME", 8)) {
+ d(fprintf (stderr, "This server supports 8bit MIME\n"));
+ transport->flags |= CAMEL_SMTP_TRANSPORT_8BITMIME;
+ } else if (!strncmp (token, "ENHANCEDSTATUSCODES", 19)) {
+ d(fprintf (stderr, "This server supports enhanced status codes\n"));
+ transport->flags |= CAMEL_SMTP_TRANSPORT_ENHANCEDSTATUSCODES;
+ } else if (!strncmp (token, "STARTTLS", 8)) {
+ d(fprintf (stderr, "This server supports STARTTLS\n"));
+ transport->flags |= CAMEL_SMTP_TRANSPORT_STARTTLS;
+ } else if (!strncmp (token, "AUTH", 4)) {
+ if (!transport->authtypes || transport->flags & CAMEL_SMTP_TRANSPORT_AUTH_EQUAL) {
+ /* Don't bother parsing any authtypes if we already have a list.
+ * Some servers will list AUTH twice, once the standard way and
+ * once the way Microsoft Outlook requires them to be:
+ *
+ * 250-AUTH LOGIN PLAIN DIGEST-MD5 CRAM-MD5
+ * 250-AUTH=LOGIN PLAIN DIGEST-MD5 CRAM-MD5
+ *
+ * Since they can come in any order, parse each list that we get
+ * until we parse an authtype list that does not use the AUTH=
+ * format. We want to let the standard way have priority over the
+ * broken way.
+ **/
+
+ if (token[4] == '=')
+ transport->flags |= CAMEL_SMTP_TRANSPORT_AUTH_EQUAL;
+ else
+ transport->flags &= ~CAMEL_SMTP_TRANSPORT_AUTH_EQUAL;
+
+ /* parse for supported AUTH types */
+ token += 5;
+
+ if (transport->authtypes) {
+ g_hash_table_foreach (transport->authtypes, authtypes_free, NULL);
+ g_hash_table_destroy (transport->authtypes);
+ }
+
+ transport->authtypes = esmtp_get_authtypes (token);
+ }
+ }
+ }
+ } while (*(respbuf+3) == '-'); /* if we got "250-" then loop again */
+ g_free (respbuf);
+
+ camel_operation_end (NULL);
+
+ return TRUE;
+}
+
+static gboolean
+smtp_auth (CamelSmtpTransport *transport, const char *mech, CamelException *ex)
+{
+ char *cmdbuf, *respbuf = NULL, *challenge;
+ gboolean auth_challenge = FALSE;
+ CamelSasl *sasl = NULL;
+
+ camel_operation_start_transient (NULL, _("SMTP Authentication"));
+
+ sasl = camel_sasl_new ("smtp", mech, CAMEL_SERVICE (transport));
+ if (!sasl) {
+ camel_operation_end (NULL);
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Error creating SASL authentication object."));
+ return FALSE;
+ }
+
+ challenge = camel_sasl_challenge_base64 (sasl, NULL, ex);
+ if (challenge) {
+ auth_challenge = TRUE;
+ cmdbuf = g_strdup_printf ("AUTH %s %s\r\n", mech, challenge);
+ g_free (challenge);
+ } else {
+ cmdbuf = g_strdup_printf ("AUTH %s\r\n", mech);
+ }
+
+ d(fprintf (stderr, "sending : %s", cmdbuf));
+ if (camel_stream_write (transport->ostream, cmdbuf, strlen (cmdbuf)) == -1) {
+ g_free (cmdbuf);
+ camel_exception_setv (ex, errno == EINTR ? CAMEL_EXCEPTION_USER_CANCEL : CAMEL_EXCEPTION_SYSTEM,
+ _("AUTH command failed: %s"), g_strerror (errno));
+ goto lose;
+ }
+ g_free (cmdbuf);
+
+ respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream));
+ d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)"));
+
+ while (!camel_sasl_authenticated (sasl)) {
+ if (!respbuf) {
+ camel_exception_setv (ex, errno == EINTR ? CAMEL_EXCEPTION_USER_CANCEL : CAMEL_EXCEPTION_SYSTEM,
+ _("AUTH command failed: %s"), g_strerror (errno));
+ goto lose;
+ }
+
+ /* the server challenge/response should follow a 334 code */
+ if (strncmp (respbuf, "334", 3) != 0) {
+ smtp_set_exception (transport, FALSE, respbuf, _("AUTH command failed"), ex);
+ g_free (respbuf);
+ goto lose;
+ }
+
+ if (FALSE) {
+ broken_smtp_server:
+ d(fprintf (stderr, "Your SMTP server's implementation of the %s SASL\n"
+ "authentication mechanism is broken. Please report this to the\n"
+ "appropriate vendor and suggest that they re-read rfc2554 again\n"
+ "for the first time (specifically Section 4).\n",
+ mech));
+ }
+
+ /* eat whtspc */
+ for (challenge = respbuf + 4; isspace (*challenge); challenge++);
+
+ challenge = camel_sasl_challenge_base64 (sasl, challenge, ex);
+ g_free (respbuf);
+ if (challenge == NULL)
+ goto break_and_lose;
+
+ /* send our challenge */
+ cmdbuf = g_strdup_printf ("%s\r\n", challenge);
+ g_free (challenge);
+ d(fprintf (stderr, "sending : %s", cmdbuf));
+ if (camel_stream_write (transport->ostream, cmdbuf, strlen (cmdbuf)) == -1) {
+ g_free (cmdbuf);
+ goto lose;
+ }
+ g_free (cmdbuf);
+
+ /* get the server's response */
+ respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream));
+ d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)"));
+ }
+
+ /* check that the server says we are authenticated */
+ if (!respbuf || strncmp (respbuf, "235", 3)) {
+ if (respbuf && auth_challenge && !strncmp (respbuf, "334", 3)) {
+ /* broken server, but lets try and work around it anyway... */
+ goto broken_smtp_server;
+ }
+ g_free (respbuf);
+ goto lose;
+ }
+
+ camel_object_unref (sasl);
+ camel_operation_end (NULL);
+
+ return TRUE;
+
+ break_and_lose:
+ /* Get the server out of "waiting for continuation data" mode. */
+ d(fprintf (stderr, "sending : *\n"));
+ camel_stream_write (transport->ostream, "*\r\n", 3);
+ respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream));
+ d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)"));
+
+ lose:
+ if (!camel_exception_is_set (ex)) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
+ _("Bad authentication response from server.\n"));
+ }
+
+ camel_object_unref (sasl);
+ camel_operation_end (NULL);
+
+ return FALSE;
+}
+
+static gboolean
+smtp_mail (CamelSmtpTransport *transport, const char *sender, gboolean has_8bit_parts, CamelException *ex)
+{
+ /* we gotta tell the smtp server who we are. (our email addy) */
+ char *cmdbuf, *respbuf = NULL;
+
+ if (transport->flags & CAMEL_SMTP_TRANSPORT_8BITMIME && has_8bit_parts)
+ cmdbuf = g_strdup_printf ("MAIL FROM:<%s> BODY=8BITMIME\r\n", sender);
+ else
+ cmdbuf = g_strdup_printf ("MAIL FROM:<%s>\r\n", sender);
+
+ d(fprintf (stderr, "sending : %s", cmdbuf));
+
+ if (camel_stream_write (transport->ostream, cmdbuf, strlen (cmdbuf)) == -1) {
+ g_free (cmdbuf);
+ camel_exception_setv (ex, errno == EINTR ? CAMEL_EXCEPTION_USER_CANCEL : CAMEL_EXCEPTION_SYSTEM,
+ _("MAIL FROM command failed: %s: mail not sent"),
+ g_strerror (errno));
+
+ camel_service_disconnect ((CamelService *) transport, FALSE, NULL);
+
+ return FALSE;
+ }
+ g_free (cmdbuf);
+
+ do {
+ /* Check for "250 Sender OK..." */
+ g_free (respbuf);
+ respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream));
+
+ d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)"));
+
+ if (!respbuf || strncmp (respbuf, "250", 3)) {
+ smtp_set_exception (transport, TRUE, respbuf, _("MAIL FROM command failed"), ex);
+ g_free (respbuf);
+ return FALSE;
+ }
+ } while (*(respbuf+3) == '-'); /* if we got "250-" then loop again */
+ g_free (respbuf);
+
+ return TRUE;
+}
+
+static gboolean
+smtp_rcpt (CamelSmtpTransport *transport, const char *recipient, CamelException *ex)
+{
+ /* we gotta tell the smtp server who we are going to be sending
+ * our email to */
+ char *cmdbuf, *respbuf = NULL;
+
+ cmdbuf = g_strdup_printf ("RCPT TO:<%s>\r\n", recipient);
+
+ d(fprintf (stderr, "sending : %s", cmdbuf));
+
+ if (camel_stream_write (transport->ostream, cmdbuf, strlen (cmdbuf)) == -1) {
+ g_free (cmdbuf);
+ camel_exception_setv (ex, errno == EINTR ? CAMEL_EXCEPTION_USER_CANCEL : CAMEL_EXCEPTION_SYSTEM,
+ _("RCPT TO command failed: %s: mail not sent"),
+ g_strerror (errno));
+
+ camel_service_disconnect ((CamelService *) transport, FALSE, NULL);
+
+ return FALSE;
+ }
+ g_free (cmdbuf);
+
+ do {
+ /* Check for "250 Recipient OK..." */
+ g_free (respbuf);
+ respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream));
+
+ d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)"));
+
+ if (!respbuf || strncmp (respbuf, "250", 3)) {
+ char *message;
+
+ message = g_strdup_printf (_("RCPT TO <%s> failed"), recipient);
+ smtp_set_exception (transport, TRUE, respbuf, message, ex);
+ g_free (message);
+ g_free (respbuf);
+ return FALSE;
+ }
+ } while (*(respbuf+3) == '-'); /* if we got "250-" then loop again */
+ g_free (respbuf);
+
+ return TRUE;
+}
+
+static gboolean
+smtp_data (CamelSmtpTransport *transport, CamelMimeMessage *message, CamelException *ex)
+{
+ CamelBestencEncoding enctype = CAMEL_BESTENC_8BIT;
+ struct _camel_header_raw *header, *savedbcc, *n, *tail;
+ char *cmdbuf, *respbuf = NULL;
+ CamelStreamFilter *filtered_stream;
+ CamelMimeFilter *crlffilter;
+ int ret;
+
+ /* If the server doesn't support 8BITMIME, set our required encoding to be 7bit */
+ if (!(transport->flags & CAMEL_SMTP_TRANSPORT_8BITMIME))
+ enctype = CAMEL_BESTENC_7BIT;
+
+ /* FIXME: should we get the best charset too?? */
+ /* Changes the encoding of all mime parts to fit within our required
+ encoding type and also force any text parts with long lines (longer
+ than 998 octets) to wrap by QP or base64 encoding them. */
+ camel_mime_message_set_best_encoding (message, CAMEL_BESTENC_GET_ENCODING, enctype);
+
+ cmdbuf = g_strdup ("DATA\r\n");
+
+ d(fprintf (stderr, "sending : %s", cmdbuf));
+
+ if (camel_stream_write (transport->ostream, cmdbuf, strlen (cmdbuf)) == -1) {
+ g_free (cmdbuf);
+ camel_exception_setv (ex, errno == EINTR ? CAMEL_EXCEPTION_USER_CANCEL : CAMEL_EXCEPTION_SYSTEM,
+ _("DATA command failed: %s: mail not sent"),
+ g_strerror (errno));
+
+ camel_service_disconnect ((CamelService *) transport, FALSE, NULL);
+
+ return FALSE;
+ }
+ g_free (cmdbuf);
+
+ respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream));
+
+ d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)"));
+
+ if (!respbuf || strncmp (respbuf, "354", 3)) {
+ /* we should have gotten instructions on how to use the DATA command:
+ * 354 Enter mail, end with "." on a line by itself
+ */
+ smtp_set_exception (transport, TRUE, respbuf, _("DATA command failed"), ex);
+ g_free (respbuf);
+ return FALSE;
+ }
+
+ g_free (respbuf);
+ respbuf = NULL;
+
+ /* setup stream filtering */
+ crlffilter = camel_mime_filter_crlf_new (CAMEL_MIME_FILTER_CRLF_ENCODE, CAMEL_MIME_FILTER_CRLF_MODE_CRLF_DOTS);
+ filtered_stream = camel_stream_filter_new_with_stream (transport->ostream);
+ camel_stream_filter_add (filtered_stream, CAMEL_MIME_FILTER (crlffilter));
+ camel_object_unref (crlffilter);
+
+ /* unlink the bcc headers */
+ savedbcc = NULL;
+ tail = (struct _camel_header_raw *) &savedbcc;
+
+ header = (struct _camel_header_raw *) &CAMEL_MIME_PART (message)->headers;
+ n = header->next;
+ while (n != NULL) {
+ if (!g_ascii_strcasecmp (n->name, "Bcc")) {
+ header->next = n->next;
+ tail->next = n;
+ n->next = NULL;
+ tail = n;
+ } else {
+ header = n;
+ }
+
+ n = header->next;
+ }
+
+ /* write the message */
+ ret = camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (message), CAMEL_STREAM (filtered_stream));
+
+ /* restore the bcc headers */
+ header->next = savedbcc;
+
+ if (ret == -1) {
+ camel_exception_setv (ex, errno == EINTR ? CAMEL_EXCEPTION_USER_CANCEL : CAMEL_EXCEPTION_SYSTEM,
+ _("DATA command failed: %s: mail not sent"),
+ g_strerror (errno));
+
+ camel_object_unref (filtered_stream);
+
+ camel_service_disconnect ((CamelService *) transport, FALSE, NULL);
+
+ return FALSE;
+ }
+
+ camel_stream_flush (CAMEL_STREAM (filtered_stream));
+ camel_object_unref (filtered_stream);
+
+ /* terminate the message body */
+
+ d(fprintf (stderr, "sending : \\r\\n.\\r\\n\n"));
+
+ if (camel_stream_write (transport->ostream, "\r\n.\r\n", 5) == -1) {
+ camel_exception_setv (ex, errno == EINTR ? CAMEL_EXCEPTION_USER_CANCEL : CAMEL_EXCEPTION_SYSTEM,
+ _("DATA command failed: %s: mail not sent"),
+ g_strerror (errno));
+
+ camel_service_disconnect ((CamelService *) transport, FALSE, NULL);
+
+ return FALSE;
+ }
+
+ do {
+ /* Check for "250 Sender OK..." */
+ g_free (respbuf);
+ respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream));
+
+ d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)"));
+
+ if (!respbuf || strncmp (respbuf, "250", 3)) {
+ smtp_set_exception (transport, TRUE, respbuf, _("DATA command failed"), ex);
+ g_free (respbuf);
+ return FALSE;
+ }
+ } while (*(respbuf+3) == '-'); /* if we got "250-" then loop again */
+ g_free (respbuf);
+
+ return TRUE;
+}
+
+static gboolean
+smtp_rset (CamelSmtpTransport *transport, CamelException *ex)
+{
+ /* we are going to reset the smtp server (just to be nice) */
+ char *cmdbuf, *respbuf = NULL;
+
+ cmdbuf = g_strdup ("RSET\r\n");
+
+ d(fprintf (stderr, "sending : %s", cmdbuf));
+
+ if (camel_stream_write (transport->ostream, cmdbuf, strlen (cmdbuf)) == -1) {
+ g_free (cmdbuf);
+ camel_exception_setv (ex, errno == EINTR ? CAMEL_EXCEPTION_USER_CANCEL : CAMEL_EXCEPTION_SYSTEM,
+ _("RSET command failed: %s"), g_strerror (errno));
+
+ camel_service_disconnect ((CamelService *) transport, FALSE, NULL);
+
+ return FALSE;
+ }
+ g_free (cmdbuf);
+
+ do {
+ /* Check for "250" */
+ g_free (respbuf);
+ respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream));
+
+ d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)"));
+
+ if (!respbuf || strncmp (respbuf, "250", 3)) {
+ smtp_set_exception (transport, TRUE, respbuf, _("RSET command failed"), ex);
+ g_free (respbuf);
+ return FALSE;
+ }
+ } while (*(respbuf+3) == '-'); /* if we got "250-" then loop again */
+ g_free (respbuf);
+
+ return TRUE;
+}
+
+static gboolean
+smtp_quit (CamelSmtpTransport *transport, CamelException *ex)
+{
+ /* we are going to reset the smtp server (just to be nice) */
+ char *cmdbuf, *respbuf = NULL;
+
+ cmdbuf = g_strdup ("QUIT\r\n");
+
+ d(fprintf (stderr, "sending : %s", cmdbuf));
+
+ if (camel_stream_write (transport->ostream, cmdbuf, strlen (cmdbuf)) == -1) {
+ g_free (cmdbuf);
+ camel_exception_setv (ex, errno == EINTR ? CAMEL_EXCEPTION_USER_CANCEL : CAMEL_EXCEPTION_SYSTEM,
+ _("QUIT command failed: %s"), g_strerror (errno));
+
+ return FALSE;
+ }
+ g_free (cmdbuf);
+
+ do {
+ /* Check for "221" */
+ g_free (respbuf);
+ respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream));
+
+ d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)"));
+
+ if (!respbuf || strncmp (respbuf, "221", 3)) {
+ smtp_set_exception (transport, FALSE, respbuf, _("QUIT command failed"), ex);
+ g_free (respbuf);
+ return FALSE;
+ }
+ } while (*(respbuf+3) == '-'); /* if we got "221-" then loop again */
+ g_free (respbuf);
+
+ return TRUE;
+}
diff --git a/camel/providers/smtp/camel-smtp-transport.h b/camel/providers/smtp/camel-smtp-transport.h
new file mode 100644
index 0000000000..87fcafb58b
--- /dev/null
+++ b/camel/providers/smtp/camel-smtp-transport.h
@@ -0,0 +1,80 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* camel-smtp-transport.h : class for an smtp transfer */
+
+/*
+ * Authors:
+ * Jeffrey Stedfast <fejj@stampede.org>
+ *
+ * Copyright (C) 2000 Ximian, Inc. (www.ximian.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#ifndef CAMEL_SMTP_TRANSPORT_H
+#define CAMEL_SMTP_TRANSPORT_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif /* __cplusplus */
+
+#include "camel-transport.h"
+#include "camel-tcp-stream.h"
+
+#define CAMEL_SMTP_TRANSPORT_TYPE (camel_smtp_transport_get_type ())
+#define CAMEL_SMTP_TRANSPORT(obj) (CAMEL_CHECK_CAST((obj), CAMEL_SMTP_TRANSPORT_TYPE, CamelSmtpTransport))
+#define CAMEL_SMTP_TRANSPORT_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), CAMEL_SMTP_TRANSPORT_TYPE, CamelSmtpTransportClass))
+#define CAMEL_IS_SMTP_TRANSPORT(o) (CAMEL_CHECK_TYPE((o), CAMEL_SMTP_TRANSPORT_TYPE))
+
+#define CAMEL_SMTP_TRANSPORT_IS_ESMTP (1 << 0)
+#define CAMEL_SMTP_TRANSPORT_8BITMIME (1 << 1)
+#define CAMEL_SMTP_TRANSPORT_ENHANCEDSTATUSCODES (1 << 2)
+#define CAMEL_SMTP_TRANSPORT_STARTTLS (1 << 3)
+
+#define CAMEL_SMTP_TRANSPORT_USE_SSL_ALWAYS (1 << 4)
+#define CAMEL_SMTP_TRANSPORT_USE_SSL_WHEN_POSSIBLE (1 << 5)
+
+#define CAMEL_SMTP_TRANSPORT_USE_SSL (CAMEL_SMTP_TRANSPORT_USE_SSL_ALWAYS | \
+ CAMEL_SMTP_TRANSPORT_USE_SSL_WHEN_POSSIBLE)
+
+#define CAMEL_SMTP_TRANSPORT_AUTH_EQUAL (1 << 6) /* set if we are using authtypes from a broken AUTH= */
+
+typedef struct {
+ CamelTransport parent_object;
+
+ CamelStream *istream, *ostream;
+
+ guint32 flags;
+
+ gboolean connected;
+ struct sockaddr *localaddr;
+ socklen_t localaddrlen;
+
+ GHashTable *authtypes;
+} CamelSmtpTransport;
+
+typedef struct {
+ CamelTransportClass parent_class;
+
+} CamelSmtpTransportClass;
+
+/* Standard Camel function */
+CamelType camel_smtp_transport_get_type (void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* CAMEL_SMTP_TRANSPORT_H */
diff --git a/camel/tests/folder/Makefile.am b/camel/tests/folder/Makefile.am
new file mode 100644
index 0000000000..28b16007c1
--- /dev/null
+++ b/camel/tests/folder/Makefile.am
@@ -0,0 +1,28 @@
+
+INCLUDES = \
+ -I$(includedir) \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/intl \
+ -I$(top_srcdir)/e-util \
+ -I$(top_srcdir)/camel \
+ -I$(top_srcdir)/camel/tests/lib \
+ -DG_LOG_DOMAIN=\"evolution-tests\" \
+ $(CAMEL_CFLAGS)
+
+LDADD = \
+ $(top_builddir)/camel/libcamel.la \
+ $(top_builddir)/e-util/libeutil.la \
+ $(top_builddir)/camel/tests/lib/libcameltest.a \
+ $(INTLLIBS) \
+ $(EVOLUTION_MAIL_LIBS)
+
+check_PROGRAMS = \
+ test1 test2 test3 \
+ test4 test5 test6 \
+ test7 test8 test9 \
+ test10 test11
+
+TESTS = test1 test2 test3 \
+ test4 test5 test6 \
+ test7 test8 test9 \
+ test10 test11
diff --git a/camel/tests/folder/README b/camel/tests/folder/README
new file mode 100644
index 0000000000..1d6b0cf240
--- /dev/null
+++ b/camel/tests/folder/README
@@ -0,0 +1,14 @@
+
+test1 camel store folder operations (local only)
+test2 basic folder operations, local
+test3 folder searching and indexing, local
+test4 camel store folder operations, IMAP
+test5 camel store folder operations, NNTP
+test6 basic folder operations, IMAP
+test7 basic folder operations, NNTP
+
+test8 multithreaded folder torture test, local
+test9 filtering
+test10 multithreaded folder/store object bag torture test
+
+test11 old format maildir name compatability
diff --git a/camel/tests/folder/test11.c b/camel/tests/folder/test11.c
new file mode 100644
index 0000000000..4c60ee632e
--- /dev/null
+++ b/camel/tests/folder/test11.c
@@ -0,0 +1,188 @@
+
+/* threaded folder testing */
+
+#include <string.h>
+#include <pthread.h>
+
+#include "camel-test.h"
+#include "session.h"
+
+#include <camel/camel-exception.h>
+#include <camel/camel-service.h>
+#include <camel/camel-store.h>
+
+#define MAX_LOOP (10000)
+#define MAX_THREADS (5)
+
+#define d(x)
+
+#define ARRAY_LEN(x) (sizeof(x)/sizeof(x[0]))
+
+static CamelSession *session;
+
+/* FIXME: flags aren't really right yet */
+/* ASCII sorted on full_name */
+static CamelFolderInfo fi_list_1[] = {
+ { NULL, NULL, NULL, "maildir:/tmp/camel-test/maildir#.", "Inbox", ".", CAMEL_FOLDER_SYSTEM|CAMEL_FOLDER_NOCHILDREN, -1, -1 },
+ { NULL, NULL, NULL, "maildir:/tmp/camel-test/maildir#Junk", "Junk", "Junk", CAMEL_FOLDER_SYSTEM|CAMEL_FOLDER_NOCHILDREN, -1, -1 },
+ { NULL, NULL, NULL, "maildir:/tmp/camel-test/maildir#Trash", "Trash", "Trash", CAMEL_FOLDER_SYSTEM|CAMEL_FOLDER_NOCHILDREN, -1, -1 },
+ { NULL, NULL, NULL, "maildir:/tmp/camel-test/maildir#testbox", "testbox", "testbox", CAMEL_FOLDER_CHILDREN, -1, -1 },
+ { NULL, NULL, NULL, "maildir:/tmp/camel-test/maildir#testbox/foo", "foo", "testbox/foo", CAMEL_FOLDER_NOCHILDREN, -1, -1 },
+ { NULL, NULL, NULL, "maildir:/tmp/camel-test/maildir#testbox2", "testbox2", "testbox2", CAMEL_FOLDER_NOCHILDREN, -1, -1 },
+};
+
+static CamelFolderInfo fi_list_2[] = {
+ { NULL, NULL, NULL, "maildir:/tmp/camel-test/maildir#.", "Inbox", ".", CAMEL_FOLDER_SYSTEM|CAMEL_FOLDER_NOCHILDREN, -1, -1 },
+ { NULL, NULL, NULL, "maildir:/tmp/camel-test/maildir#Junk", "Junk", "Junk", CAMEL_FOLDER_SYSTEM|CAMEL_FOLDER_NOCHILDREN, -1, -1 },
+ { NULL, NULL, NULL, "maildir:/tmp/camel-test/maildir#Trash", "Trash", "Trash", CAMEL_FOLDER_SYSTEM|CAMEL_FOLDER_NOCHILDREN, -1, -1 },
+ { NULL, NULL, NULL, "maildir:/tmp/camel-test/maildir#testbox", "testbox", "testbox", CAMEL_FOLDER_NOCHILDREN, -1, -1 },
+ { NULL, NULL, NULL, "maildir:/tmp/camel-test/maildir#testbox2", "testbox2", "testbox2", CAMEL_FOLDER_NOCHILDREN, -1, -1 },
+};
+
+static CamelFolderInfo fi_list_3[] = {
+ { NULL, NULL, NULL, "maildir:/tmp/camel-test/maildir#testbox", "testbox", "testbox", CAMEL_FOLDER_CHILDREN, -1, -1 },
+ { NULL, NULL, NULL, "maildir:/tmp/camel-test/maildir#testbox/foo", "foo", "testbox/foo", CAMEL_FOLDER_NOCHILDREN, -1, -1 },
+};
+
+static int
+cmp_fi(const void *a, const void *b)
+{
+ const CamelFolderInfo *fa = ((const CamelFolderInfo **)a)[0];
+ const CamelFolderInfo *fb = ((const CamelFolderInfo **)b)[0];
+
+ return strcmp(fa->full_name, fb->full_name);
+}
+
+static void
+add_fi(GPtrArray *folders, CamelFolderInfo *fi)
+{
+ while (fi) {
+ g_ptr_array_add(folders, fi);
+ if (fi->child)
+ add_fi(folders, fi->child);
+ fi = fi->next;
+ }
+}
+
+static void
+check_fi(CamelFolderInfo *fi, CamelFolderInfo *list, int len)
+{
+ GPtrArray *folders = g_ptr_array_new();
+ int i;
+
+ add_fi(folders, fi);
+ check_msg(folders->len == len, "unexpected number of folders returned from folderinfo");
+ qsort(folders->pdata, folders->len, sizeof(folders->pdata[0]), cmp_fi);
+ for (i=0;i<len;i++) {
+ CamelFolderInfo *f = folders->pdata[i];
+
+ camel_test_push("checking folder '%s'", list[i].uri);
+
+ check_msg(!strcmp(f->uri, list[i].uri), "got '%s' expecting '%s'", f->uri, list[i].uri);
+ check(!strcmp(f->full_name, list[i].full_name));
+
+ /* this might be translated, but we can't know */
+ camel_test_nonfatal("Inbox not english");
+ check(!strcmp(f->name, list[i].name));
+ camel_test_fatal();
+
+ camel_test_nonfatal("Flags mismatch");
+ check(f->flags == list[i].flags);
+ camel_test_fatal();
+
+ camel_test_pull();
+ }
+
+ g_ptr_array_free(folders, TRUE);
+}
+
+int main(int argc, char **argv)
+{
+ CamelException *ex;
+ CamelFolder *f1, *f2;
+ CamelStore *store;
+ CamelFolderInfo *fi;
+
+ camel_test_init(argc, argv);
+
+ ex = camel_exception_new();
+
+ /* clear out any camel-test data */
+ system("/bin/rm -rf /tmp/camel-test");
+
+ session = camel_test_session_new("/tmp/camel-test");
+ store = camel_session_get_store(session, "maildir:///tmp/camel-test/maildir", ex);
+ camel_exception_clear(ex);
+
+ camel_test_start("Maildir backward compatability tests");
+
+ camel_test_push("./ prefix path, one level");
+ f1 = camel_store_get_folder(store, "testbox", CAMEL_STORE_FOLDER_CREATE, ex);
+ check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex));
+ f2 = camel_store_get_folder(store, "./testbox", CAMEL_STORE_FOLDER_CREATE, ex);
+ check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex));
+ check(f1 == f2);
+ check_unref(f2, 2);
+ check_unref(f1, 1);
+ camel_test_pull();
+
+ camel_test_push("./ prefix path, one level, no create");
+ f1 = camel_store_get_folder(store, "testbox2", CAMEL_STORE_FOLDER_CREATE, ex);
+ check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex));
+ f2 = camel_store_get_folder(store, "./testbox2", 0, ex);
+ check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex));
+ check(f1 == f2);
+ check_unref(f2, 2);
+ check_unref(f1, 1);
+ camel_test_pull();
+
+ camel_test_push("./ prefix path, two levels");
+ f1 = camel_store_get_folder(store, "testbox/foo", CAMEL_STORE_FOLDER_CREATE, ex);
+ check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex));
+ f2 = camel_store_get_folder(store, "./testbox/foo", CAMEL_STORE_FOLDER_CREATE, ex);
+ check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex));
+ check(f1 == f2);
+ check_unref(f2, 2);
+ check_unref(f1, 1);
+ camel_test_pull();
+
+ camel_test_push("'.' == Inbox");
+ f2 = camel_store_get_inbox(store, ex);
+ check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex));
+ f1 = camel_store_get_folder(store, ".", 0, ex);
+ check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex));
+ check(f1 == f2);
+ check_unref(f2, 2);
+ check_unref(f1, 1);
+ camel_test_pull();
+
+ camel_test_push("folder info, recursive");
+ fi = camel_store_get_folder_info(store, "", CAMEL_STORE_FOLDER_INFO_RECURSIVE, ex);
+ check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex));
+ check(fi != NULL);
+ check_fi(fi, fi_list_1, ARRAY_LEN(fi_list_1));
+ camel_test_pull();
+
+ camel_test_push("folder info, flat");
+ fi = camel_store_get_folder_info(store, "", 0, ex);
+ check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex));
+ check(fi != NULL);
+ check_fi(fi, fi_list_2, ARRAY_LEN(fi_list_2));
+ camel_test_pull();
+
+ camel_test_push("folder info, recursive, non root");
+ fi = camel_store_get_folder_info(store, "testbox", CAMEL_STORE_FOLDER_INFO_RECURSIVE, ex);
+ check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex));
+ check(fi != NULL);
+ check_fi(fi, fi_list_3, ARRAY_LEN(fi_list_3));
+ camel_test_pull();
+
+ check_unref(store, 1);
+ check_unref(session, 1);
+
+ camel_exception_free(ex);
+
+ camel_test_end();
+
+ return 0;
+}
diff --git a/camel/tests/lib/folders.c b/camel/tests/lib/folders.c
new file mode 100644
index 0000000000..527f1622d8
--- /dev/null
+++ b/camel/tests/lib/folders.c
@@ -0,0 +1,580 @@
+#include <string.h>
+
+#include "camel-test.h"
+#include "folders.h"
+#include "messages.h"
+
+#include "camel/camel-exception.h"
+
+/* check the total/unread is what we think it should be */
+void
+test_folder_counts(CamelFolder *folder, int total, int unread)
+{
+ GPtrArray *s;
+ int i, myunread;
+ guint32 gottotal, gotunread;
+ CamelMessageInfo *info;
+
+ push("test folder counts %d total %d unread", total, unread);
+
+ /* first, use the standard functions */
+ check(camel_folder_get_message_count(folder) == total);
+ check(camel_folder_get_unread_message_count(folder) == unread);
+
+ /* accessors */
+ camel_object_get(folder, NULL, CAMEL_FOLDER_TOTAL, &gottotal, CAMEL_FOLDER_UNREAD, &gotunread, 0);
+ check(gottotal == total);
+ check(gotunread == unread);
+
+ /* next, use the summary */
+ s = camel_folder_get_summary(folder);
+ check(s != NULL);
+ check(s->len == total);
+ myunread = s->len;
+ for (i=0;i<s->len;i++) {
+ info = s->pdata[i];
+ if (info->flags & CAMEL_MESSAGE_SEEN)
+ myunread--;
+ }
+ check(unread == myunread);
+ camel_folder_free_summary(folder, s);
+
+ /* last, use the uid list */
+ s = camel_folder_get_uids(folder);
+ check(s != NULL);
+ check(s->len == total);
+ myunread = s->len;
+ for (i=0;i<s->len;i++) {
+ info = camel_folder_get_message_info(folder, s->pdata[i]);
+ if (info->flags & CAMEL_MESSAGE_SEEN)
+ myunread--;
+ camel_folder_free_message_info(folder, info);
+ }
+ check(unread == myunread);
+ camel_folder_free_uids(folder, s);
+
+ pull();
+}
+
+static int
+safe_strcmp(const char *a, const char *b)
+{
+ if (a == NULL && b == NULL)
+ return 0;
+ if (a == NULL)
+ return 1;
+ if (b == NULL)
+ return -1;
+ return strcmp(a, b);
+}
+
+void
+test_message_info(CamelMimeMessage *msg, const CamelMessageInfo *info)
+{
+ check_msg(safe_strcmp(camel_message_info_subject(info), camel_mime_message_get_subject(msg)) == 0,
+ "info->subject = '%s', get_subject() = '%s'", camel_message_info_subject(info), camel_mime_message_get_subject(msg));
+
+ /* FIXME: testing from/cc/to, etc is more tricky */
+
+ check(info->date_sent == camel_mime_message_get_date(msg, NULL));
+
+ /* date received isn't set for messages that haven't been sent anywhere ... */
+ /*check(info->date_received == camel_mime_message_get_date_received(msg, NULL));*/
+
+ /* so is messageid/references, etc */
+}
+
+/* check a message is present */
+void
+test_folder_message(CamelFolder *folder, const char *uid)
+{
+ CamelMimeMessage *msg;
+ CamelMessageInfo *info;
+ GPtrArray *s;
+ int i;
+ CamelException *ex = camel_exception_new();
+ int found;
+
+ push("uid %s is in folder", uid);
+
+ /* first try getting info */
+ info = camel_folder_get_message_info(folder, uid);
+ check(info != NULL);
+ check(strcmp(camel_message_info_uid(info), uid) == 0);
+ camel_folder_free_message_info(folder, info);
+
+ /* then, getting message */
+ msg = camel_folder_get_message(folder, uid, ex);
+ check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex));
+ check(msg != NULL);
+
+ /* cross check with info */
+ test_message_info(msg, info);
+
+ camel_object_unref((CamelObject *)msg);
+
+ /* see if it is in the summary (only once) */
+ s = camel_folder_get_summary(folder);
+ check(s != NULL);
+ found = 0;
+ for (i=0;i<s->len;i++) {
+ info = s->pdata[i];
+ if (strcmp(camel_message_info_uid(info), uid) == 0)
+ found++;
+ }
+ check(found == 1);
+ camel_folder_free_summary(folder, s);
+
+ /* check it is in the uid list */
+ s = camel_folder_get_uids(folder);
+ check(s != NULL);
+ found = 0;
+ for (i=0;i<s->len;i++) {
+ if (strcmp(s->pdata[i], uid) == 0)
+ found++;
+ }
+ check(found == 1);
+ camel_folder_free_uids(folder, s);
+
+ camel_exception_free(ex);
+
+ pull();
+}
+
+/* check message not present */
+void
+test_folder_not_message(CamelFolder *folder, const char *uid)
+{
+ CamelMimeMessage *msg;
+ CamelMessageInfo *info;
+ GPtrArray *s;
+ int i;
+ CamelException *ex = camel_exception_new();
+ int found;
+
+ push("uid '%s' is not in folder", uid);
+
+ /* first try getting info */
+ push("no message info");
+ info = camel_folder_get_message_info(folder, uid);
+ check(info == NULL);
+ pull();
+
+ /* then, getting message */
+ push("no message");
+ msg = camel_folder_get_message(folder, uid, ex);
+ check(camel_exception_is_set(ex));
+ check(msg == NULL);
+ camel_exception_clear(ex);
+ pull();
+
+ /* see if it is not in the summary (only once) */
+ push("not in summary list");
+ s = camel_folder_get_summary(folder);
+ check(s != NULL);
+ found = 0;
+ for (i=0;i<s->len;i++) {
+ info = s->pdata[i];
+ if (strcmp(camel_message_info_uid(info), uid) == 0)
+ found++;
+ }
+ check(found == 0);
+ camel_folder_free_summary(folder, s);
+ pull();
+
+ /* check it is not in the uid list */
+ push("not in uid list");
+ s = camel_folder_get_uids(folder);
+ check(s != NULL);
+ found = 0;
+ for (i=0;i<s->len;i++) {
+ if (strcmp(s->pdata[i], uid) == 0)
+ found++;
+ }
+ check(found == 0);
+ camel_folder_free_uids(folder, s);
+ pull();
+
+ camel_exception_free(ex);
+
+ pull();
+}
+
+/* test basic store operations on folders */
+/* TODO: Add subscription stuff */
+void
+test_folder_basic(CamelSession *session, const char *storename, int local, int spool)
+{
+ CamelStore *store;
+ CamelException *ex = camel_exception_new();
+ CamelFolder *folder;
+ char *what = g_strdup_printf("testing store: %s", storename);
+
+ camel_test_start(what);
+ test_free(what);
+
+ push("getting store");
+ store = camel_session_get_store(session, storename, ex);
+ check_msg(!camel_exception_is_set(ex), "getting store: %s", camel_exception_get_description(ex));
+ check(store != NULL);
+ pull();
+
+ /* local providers == no inbox */
+ push("getting inbox folder");
+ folder = camel_store_get_inbox(store, ex);
+ if (local) {
+ /* Well, maildir can have an inbox */
+ if (folder) {
+ check(!camel_exception_is_set(ex));
+ check_unref(folder, 1);
+ } else {
+ check(camel_exception_is_set(ex));
+ camel_exception_clear(ex);
+ }
+ } else {
+ check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex));
+ check(folder != NULL);
+ check_unref(folder, 2);
+ }
+ pull();
+
+ push("getting a non-existant folder, no create");
+ folder = camel_store_get_folder(store, "unknown", 0, ex);
+ check(camel_exception_is_set(ex));
+ check(folder == NULL);
+ camel_exception_clear(ex);
+ pull();
+
+ if (!spool) {
+ push("getting a non-existant folder, with create");
+ folder = camel_store_get_folder(store, "testbox", CAMEL_STORE_FOLDER_CREATE, ex);
+ check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex));
+ check(folder != NULL);
+ if (local)
+ check_unref(folder, 1);
+ else
+ check_unref(folder, 2);
+ pull();
+
+ push("getting an existing folder");
+ folder = camel_store_get_folder(store, "testbox", 0, ex);
+ check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex));
+ check(folder != NULL);
+ if (local)
+ check_unref(folder, 1);
+ else
+ check_unref(folder, 2);
+ pull();
+
+ push("renaming a non-existant folder");
+ camel_store_rename_folder(store, "unknown1", "unknown2", ex);
+ check(camel_exception_is_set(ex));
+ camel_exception_clear(ex);
+ pull();
+
+ push("renaming an existing folder");
+ camel_store_rename_folder(store, "testbox", "testbox2", ex);
+ check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex));
+ pull();
+
+ push("opening the old name of a renamed folder");
+ folder = camel_store_get_folder(store, "testbox", 0, ex);
+ check(camel_exception_is_set(ex));
+ check(folder == NULL);
+ camel_exception_clear(ex);
+ pull();
+
+ push("opening the new name of a renamed folder");
+ folder = camel_store_get_folder(store, "testbox2", 0, ex);
+ check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex));
+ check(folder != NULL);
+ if (local)
+ check_unref(folder, 1);
+ else
+ check_unref(folder, 2);
+ pull();
+ }
+
+ push("deleting a non-existant folder");
+ camel_store_delete_folder(store, "unknown", ex);
+ check(camel_exception_is_set(ex));
+ camel_exception_clear(ex);
+ pull();
+
+ if (!spool) {
+ push("deleting an existing folder");
+ camel_store_delete_folder(store, "testbox2", ex);
+ check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex));
+ pull();
+ }
+
+ push("opening a folder that has been deleted");
+ folder = camel_store_get_folder(store, "testbox2", 0, ex);
+ check(camel_exception_is_set(ex));
+ check(folder == NULL);
+ camel_exception_clear(ex);
+ pull();
+
+ check_unref(store, 1);
+
+ camel_test_end();
+
+ camel_exception_free(ex);
+}
+
+
+/* todo: cross-check everything with folder_info checks as well */
+/* this should probably take a folder instead of a session ... */
+void
+test_folder_message_ops(CamelSession *session, const char *name, int local, const char *mailbox)
+{
+ CamelStore *store;
+ CamelException *ex = camel_exception_new();
+ CamelFolder *folder;
+ CamelMimeMessage *msg;
+ int j;
+ int indexed, max;
+ GPtrArray *uids;
+ CamelMessageInfo *info;
+
+ max=local?2:1;
+
+ for (indexed = 0;indexed<max;indexed++) {
+ char *what = g_strdup_printf("folder ops: %s %s", name, local?(indexed?"indexed":"non-indexed"):"");
+ int flags;
+
+ camel_test_start(what);
+ test_free(what);
+
+ push("getting store");
+ store = camel_session_get_store(session, name, ex);
+ check_msg(!camel_exception_is_set(ex), "getting store: %s", camel_exception_get_description(ex));
+ check(store != NULL);
+ pull();
+
+ push("creating %sindexed folder", indexed?"":"non-");
+ if (indexed)
+ flags = CAMEL_STORE_FOLDER_CREATE|CAMEL_STORE_FOLDER_BODY_INDEX;
+ else
+ flags = CAMEL_STORE_FOLDER_CREATE;
+ folder = camel_store_get_folder(store, mailbox, flags, ex);
+
+ /* we can't create mailbox outside of namespace, since we have no api for it, try
+ using inbox namespace, works for courier */
+ if (folder == NULL) {
+ char *mbox = g_strdup_printf("INBOX/%s", mailbox);
+ mailbox = mbox;
+ camel_exception_clear(ex);
+ folder = camel_store_get_folder(store, mailbox, flags, ex);
+ }
+
+ check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex));
+ check(folder != NULL);
+
+ /* verify empty/can't get nonexistant stuff */
+ test_folder_counts(folder, 0, 0);
+ test_folder_not_message(folder, "0");
+ test_folder_not_message(folder, "");
+
+ for (j=0;j<10;j++) {
+ char *content, *subject;
+
+ push("creating test message");
+ msg = test_message_create_simple();
+ content = g_strdup_printf("Test message %d contents\n\n", j);
+ test_message_set_content_simple((CamelMimePart *)msg, 0, "text/plain",
+ content, strlen(content));
+ test_free(content);
+ subject = g_strdup_printf("Test message %d", j);
+ camel_mime_message_set_subject(msg, subject);
+ pull();
+
+ push("appending simple message %d", j);
+ camel_folder_append_message(folder, msg, NULL, NULL, ex);
+ check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex));
+
+#if 0
+ /* sigh, this shouldn't be required, but the imap code is too dumb to do it itself */
+ if (!local) {
+ push("forcing a refresh of folder updates");
+ camel_folder_refresh_info(folder, ex);
+ check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex));
+ pull();
+ }
+#endif
+ /*if (!local)
+ camel_test_nonfatal("unread counts dont seem right for imap");*/
+
+ test_folder_counts(folder, j+1, j+1);
+
+ /*if (!local)
+ camel_test_fatal();*/
+
+ push("checking it is in the right uid slot & exists");
+ uids = camel_folder_get_uids(folder);
+ check(uids != NULL);
+ check(uids->len == j+1);
+ if (uids->len > j)
+ test_folder_message(folder, uids->pdata[j]);
+ pull();
+
+ push("checking it is the right message (subject): %s", subject);
+ if (uids->len > j) {
+ info = camel_folder_get_message_info(folder, uids->pdata[j]);
+ check(info != NULL);
+ check_msg(strcmp(camel_message_info_subject(info), subject)==0,
+ "info->subject %s", camel_message_info_subject(info));
+ camel_folder_free_message_info(folder, info);
+ }
+ camel_folder_free_uids(folder, uids);
+ pull();
+
+ test_free(subject);
+
+ /*if (!local)
+ camel_test_fatal();*/
+
+ check_unref(msg, 1);
+ pull();
+ }
+
+ if (local)
+ check_unref(folder, 1);
+ else
+ check_unref(folder, 2);
+ pull();
+
+#if 0
+ push("deleting test folder, with messages in it");
+ camel_store_delete_folder(store, mailbox, ex);
+ check(camel_exception_is_set(ex));
+ camel_exception_clear(ex);
+ pull();
+#endif
+
+ push("re-opening folder");
+ folder = camel_store_get_folder(store, mailbox, flags, ex);
+ check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex));
+ check(folder != NULL);
+
+ /* verify counts */
+ test_folder_counts(folder, 10, 10);
+
+ /* re-check uid's, after a reload */
+ uids = camel_folder_get_uids(folder);
+ check(uids != NULL);
+ check(uids->len == 10);
+ for (j=0;j<10;j++) {
+ char *subject = g_strdup_printf("Test message %d", j);
+
+ push("verify reload of %s", subject);
+ test_folder_message(folder, uids->pdata[j]);
+
+ info = camel_folder_get_message_info(folder, uids->pdata[j]);
+ check_msg(strcmp(camel_message_info_subject(info), subject)==0,
+ "info->subject %s", camel_message_info_subject(info));
+ test_free(subject);
+ camel_folder_free_message_info(folder, info);
+ pull();
+ }
+
+ push("deleting first message & expunging");
+ camel_folder_delete_message(folder, uids->pdata[0]);
+ /* deleting marks message read implictly */
+ test_folder_counts(folder, 10, 9);
+ camel_folder_expunge(folder, ex);
+ check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex));
+ test_folder_not_message(folder, uids->pdata[0]);
+ test_folder_counts(folder, 9, 9);
+
+ camel_folder_free_uids(folder, uids);
+
+ uids = camel_folder_get_uids(folder);
+ check(uids != NULL);
+ check(uids->len == 9);
+ for (j=0;j<9;j++) {
+ char *subject = g_strdup_printf("Test message %d", j+1);
+
+ push("verify after expunge of %s", subject);
+ test_folder_message(folder, uids->pdata[j]);
+
+ info = camel_folder_get_message_info(folder, uids->pdata[j]);
+ check_msg(strcmp(camel_message_info_subject(info), subject)==0,
+ "info->subject %s", camel_message_info_subject(info));
+ test_free(subject);
+ camel_folder_free_message_info(folder, info);
+ pull();
+ }
+ pull();
+
+ push("deleting last message & expunging");
+ camel_folder_delete_message(folder, uids->pdata[8]);
+ /* sync? */
+ test_folder_counts(folder, 9, 8);
+ camel_folder_expunge(folder, ex);
+ check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex));
+ test_folder_not_message(folder, uids->pdata[8]);
+ test_folder_counts(folder, 8, 8);
+
+ camel_folder_free_uids(folder, uids);
+
+ uids = camel_folder_get_uids(folder);
+ check(uids != NULL);
+ check(uids->len == 8);
+ for (j=0;j<8;j++) {
+ char *subject = g_strdup_printf("Test message %d", j+1);
+
+ push("verify after expunge of %s", subject);
+ test_folder_message(folder, uids->pdata[j]);
+
+ info = camel_folder_get_message_info(folder, uids->pdata[j]);
+ check_msg(strcmp(camel_message_info_subject(info), subject)==0,
+ "info->subject %s", camel_message_info_subject(info));
+ test_free(subject);
+ camel_folder_free_message_info(folder, info);
+ pull();
+ }
+ pull();
+
+ push("deleting all messages & expunging");
+ for (j=0;j<8;j++) {
+ camel_folder_delete_message(folder, uids->pdata[j]);
+ }
+ /* sync? */
+ test_folder_counts(folder, 8, 0);
+ camel_folder_expunge(folder, ex);
+ check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex));
+ for (j=0;j<8;j++) {
+ test_folder_not_message(folder, uids->pdata[j]);
+ }
+ test_folder_counts(folder, 0, 0);
+
+ camel_folder_free_uids(folder, uids);
+ pull();
+
+ if (local)
+ check_unref(folder, 1);
+ else
+ check_unref(folder, 2);
+ pull(); /* re-opening folder */
+
+ if (g_ascii_strcasecmp(mailbox, "INBOX") != 0) {
+ push("deleting test folder, with no messages in it");
+ camel_store_delete_folder(store, mailbox, ex);
+ check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex));
+ pull();
+ }
+
+ if (!local) {
+ push("disconneect service");
+ camel_service_disconnect((CamelService *)store, TRUE, ex);
+ check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex));
+ pull();
+ }
+
+ check_unref(store, 1);
+ camel_test_end();
+ }
+
+ camel_exception_free(ex);
+}
diff --git a/camel/tests/message/test2.c b/camel/tests/message/test2.c
new file mode 100644
index 0000000000..4584eace6a
--- /dev/null
+++ b/camel/tests/message/test2.c
@@ -0,0 +1,326 @@
+#include "camel-test.h"
+#include "messages.h"
+#include "addresses.h"
+
+/* for stat */
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <iconv.h>
+
+#include <camel/camel-internet-address.h>
+#include <camel/camel-address.h>
+
+#include "address-data.h"
+
+static char *convert(const char *in, const char *from, const char *to)
+{
+ iconv_t ic = iconv_open(to, from);
+ char *out, *outp;
+ const char *inp;
+ size_t inlen, outlen;
+
+ if (ic == (iconv_t)-1)
+ return g_strdup(in);
+
+ inlen = strlen(in);
+ outlen = inlen*5 + 16;
+
+ outp = out = g_malloc(outlen);
+ inp = in;
+
+ if (iconv(ic, &inp, &inlen, &outp, &outlen) == -1) {
+ test_free(out);
+ iconv_close(ic);
+ return g_strdup(in);
+ }
+
+ if (iconv(ic, NULL, 0, &outp, &outlen) == -1) {
+ test_free(out);
+ iconv_close(ic);
+ return g_strdup(in);
+ }
+
+ iconv_close(ic);
+
+ *outp = 0;
+
+#if 0
+ /* lets see if we can convert back again? */
+ {
+ char *nout, *noutp;
+ iconv_t ic = iconv_open(from, to);
+
+ inp = out;
+ inlen = strlen(out);
+ outlen = inlen*5 + 16;
+ noutp = nout = g_malloc(outlen);
+ if (iconv(ic, &inp, &inlen, &noutp, &outlen) == -1
+ || iconv(ic, NULL, 0, &noutp, &outlen) == -1) {
+ g_warning("Cannot convert '%s' \n from %s to %s: %s\n", in, to, from, strerror(errno));
+ }
+ iconv_close(ic);
+ }
+
+ /* and lets see what camel thinks out optimal charset is */
+ {
+ printf("Camel thinks the best encoding of '%s' is %s, although we converted from %s\n",
+ in, camel_charset_best(out, strlen(out)), from);
+ }
+#endif
+
+ return out;
+}
+
+#define to_utf8(in, type) convert(in, type, "utf-8")
+#define from_utf8(in, type) convert(in, "utf-8", type)
+
+#define ARRAY_LEN(x) (sizeof(x)/sizeof(x[0]))
+
+int main(int argc, char **argv)
+{
+ int i;
+ CamelInternetAddress *addr, *addr2;
+ char *name;
+ char *charset;
+ const char *real, *where;
+ char *enc, *enc2, *format, *format2;
+
+ camel_test_init(argc, argv);
+
+ camel_test_start("CamelInternetAddress, basics");
+
+ addr = camel_internet_address_new();
+
+ push("Test blank address");
+ check(camel_address_length(CAMEL_ADDRESS(addr)) == 0);
+ check(camel_internet_address_get(addr, 0, &real, &where) == FALSE);
+ pull();
+
+ push("Test blank clone");
+ addr2 = CAMEL_INTERNET_ADDRESS(camel_address_new_clone(CAMEL_ADDRESS(addr)));
+ test_address_compare(addr, addr2);
+ check_unref(addr2, 1);
+ pull();
+
+ push("Test add 1");
+ camel_internet_address_add(addr, "Zed", "nowhere@here.com.au");
+ check(camel_address_length(CAMEL_ADDRESS(addr)) == 1);
+ check(camel_internet_address_get(addr, 0, &real, &where) == TRUE);
+ check_msg(string_equal("Zed", real), "real = '%s'", real);
+ check(strcmp(where, "nowhere@here.com.au") == 0);
+ pull();
+
+ push("Test clone 1");
+ addr2 = CAMEL_INTERNET_ADDRESS(camel_address_new_clone(CAMEL_ADDRESS(addr)));
+ test_address_compare(addr, addr2);
+ check_unref(addr2, 1);
+ pull();
+
+ push("Test add many");
+ for (i=1;i<10;i++) {
+ char name[16], a[32];
+ sprintf(name, "Zed %d", i);
+ sprintf(a, "nowhere@here-%d.com.au", i);
+ camel_internet_address_add(addr, name, a);
+ check(camel_address_length(CAMEL_ADDRESS(addr)) == i+1);
+ check(camel_internet_address_get(addr, i, &real, &where) == TRUE);
+ check_msg(string_equal(name, real), "name = '%s' real = '%s'", name, real);
+ check(strcmp(where, a) == 0);
+ }
+ pull();
+
+ /* put a few of these in to make it look like its doing something impressive ... :) */
+ camel_test_end();
+ camel_test_start("CamelInternetAddress, search");
+
+ push("Test search");
+ camel_test_nonfatal("Address comparisons should ignore whitespace??");
+ check(camel_internet_address_find_name(addr, "Zed 1", &where) == 1);
+ check(camel_internet_address_find_name(addr, "Zed 9", &where) == 9);
+ check(camel_internet_address_find_name(addr, "Zed", &where) == 0);
+ check(camel_internet_address_find_name(addr, " Zed", &where) == 0);
+ check(camel_internet_address_find_name(addr, "Zed ", &where) == 0);
+ check(camel_internet_address_find_name(addr, " Zed ", &where) == 0);
+ check(camel_internet_address_find_name(addr, "Zed 20", &where) == -1);
+ check(camel_internet_address_find_name(addr, "", &where) == -1);
+ /* interface dont handle nulls :) */
+ /*check(camel_internet_address_find_name(addr, NULL, &where) == -1);*/
+
+ check(camel_internet_address_find_address(addr, "nowhere@here-1.com.au", &where) == 1);
+ check(camel_internet_address_find_address(addr, "nowhere@here-1 . com.au", &where) == 1);
+ check(camel_internet_address_find_address(addr, "nowhere@here-2 .com.au ", &where) == 2);
+ check(camel_internet_address_find_address(addr, " nowhere @here-3.com.au", &where) == 3);
+ check(camel_internet_address_find_address(addr, "nowhere@here-20.com.au ", &where) == -1);
+ check(camel_internet_address_find_address(addr, "", &where) == -1);
+ /*check(camel_internet_address_find_address(addr, NULL, &where) == -1);*/
+ camel_test_fatal();
+ pull();
+
+ camel_test_end();
+ camel_test_start("CamelInternetAddress, copy/cat/clone");
+
+ push("Test clone many");
+ addr2 = CAMEL_INTERNET_ADDRESS(camel_address_new_clone(CAMEL_ADDRESS(addr)));
+ test_address_compare(addr, addr2);
+ pull();
+
+ push("Test remove items");
+ camel_address_remove(CAMEL_ADDRESS(addr2), 0);
+ check(camel_address_length(CAMEL_ADDRESS(addr2)) == 9);
+ camel_address_remove(CAMEL_ADDRESS(addr2), 0);
+ check(camel_address_length(CAMEL_ADDRESS(addr2)) == 8);
+ camel_address_remove(CAMEL_ADDRESS(addr2), 5);
+ check(camel_address_length(CAMEL_ADDRESS(addr2)) == 7);
+ camel_address_remove(CAMEL_ADDRESS(addr2), 10);
+ check(camel_address_length(CAMEL_ADDRESS(addr2)) == 7);
+ camel_address_remove(CAMEL_ADDRESS(addr2), -1);
+ check(camel_address_length(CAMEL_ADDRESS(addr2)) == 0);
+ check_unref(addr2, 1);
+ pull();
+
+ push("Testing copy/cat");
+ push("clone + cat");
+ addr2 = CAMEL_INTERNET_ADDRESS(camel_address_new_clone(CAMEL_ADDRESS(addr)));
+ camel_address_cat(CAMEL_ADDRESS(addr2), CAMEL_ADDRESS(addr));
+ check(camel_address_length(CAMEL_ADDRESS(addr)) == 10);
+ check(camel_address_length(CAMEL_ADDRESS(addr2)) == 20);
+ check_unref(addr2, 1);
+ pull();
+
+ push("cat + cat + copy");
+ addr2 = camel_internet_address_new();
+ camel_address_cat(CAMEL_ADDRESS(addr2), CAMEL_ADDRESS(addr));
+ test_address_compare(addr, addr2);
+ camel_address_cat(CAMEL_ADDRESS(addr2), CAMEL_ADDRESS(addr));
+ check(camel_address_length(CAMEL_ADDRESS(addr)) == 10);
+ check(camel_address_length(CAMEL_ADDRESS(addr2)) == 20);
+ camel_address_copy(CAMEL_ADDRESS(addr2), CAMEL_ADDRESS(addr));
+ test_address_compare(addr, addr2);
+ check_unref(addr2, 1);
+ pull();
+
+ push("copy");
+ addr2 = camel_internet_address_new();
+ camel_address_copy(CAMEL_ADDRESS(addr2), CAMEL_ADDRESS(addr));
+ test_address_compare(addr, addr2);
+ check_unref(addr2, 1);
+ pull();
+
+ pull();
+
+ check_unref(addr, 1);
+
+ camel_test_end();
+
+ camel_test_start("CamelInternetAddress, I18N");
+
+ for (i=0;i<ARRAY_LEN(test_lines);i++) {
+ push("Testing text line %d (%s) '%s'", i, test_lines[i].type, test_lines[i].line);
+
+ addr = camel_internet_address_new();
+
+ /* first, convert to api format (utf-8) */
+ charset = test_lines[i].type;
+ name = to_utf8(test_lines[i].line, charset);
+
+ push("Address setup");
+ camel_internet_address_add(addr, name, "nobody@nowhere.com");
+ check(camel_internet_address_get(addr, 0, &real, &where) == TRUE);
+ check_msg(string_equal(name, real), "name = '%s' real = '%s'", name, real);
+ check(strcmp(where, "nobody@nowhere.com") == 0);
+ test_free(name);
+
+ check(camel_internet_address_get(addr, 1, &real, &where) == FALSE);
+ check(camel_address_length(CAMEL_ADDRESS(addr)) == 1);
+ pull();
+
+ push("Address encode/decode");
+ enc = camel_address_encode(CAMEL_ADDRESS(addr));
+
+ addr2 = camel_internet_address_new();
+ check(camel_address_decode(CAMEL_ADDRESS(addr2), enc) == 1);
+ check(camel_address_length(CAMEL_ADDRESS(addr2)) == 1);
+
+ enc2 = camel_address_encode(CAMEL_ADDRESS(addr2));
+ check_msg(string_equal(enc, enc2), "enc = '%s' enc2 = '%s'", enc, enc2);
+ test_free(enc2);
+
+ push("Compare addresses");
+ test_address_compare(addr, addr2);
+ pull();
+ check_unref(addr2, 1);
+ test_free(enc);
+ pull();
+
+ /* FIXME: format/unformat arne't guaranteed to be reversible, at least at the moment */
+ camel_test_nonfatal("format/unformat not (yet) reversible for all cases");
+
+ push("Address format/unformat");
+ format = camel_address_format(CAMEL_ADDRESS(addr));
+
+ addr2 = camel_internet_address_new();
+ check(camel_address_unformat(CAMEL_ADDRESS(addr2), format) == 1);
+ check(camel_address_length(CAMEL_ADDRESS(addr2)) == 1);
+
+ format2 = camel_address_format(CAMEL_ADDRESS(addr2));
+ check_msg(string_equal(format, format2), "format = '%s\n\tformat2 = '%s'", format, format2);
+ test_free(format2);
+
+ /* currently format/unformat doesn't handle ,'s and other special chars at all */
+ if (camel_address_length(CAMEL_ADDRESS(addr2)) == 1) {
+ push("Compare addresses");
+ test_address_compare(addr, addr2);
+ pull();
+ }
+
+ test_free(format);
+ pull();
+
+ camel_test_fatal();
+
+ check_unref(addr2, 1);
+
+ check_unref(addr, 1);
+ pull();
+
+ }
+
+ camel_test_end();
+
+ camel_test_start("CamelInternetAddress, I18N decode");
+
+ for (i=0;i<ARRAY_LEN(test_address);i++) {
+ push("Testing address line %d '%s'", i, test_address[i].addr);
+
+ addr = camel_internet_address_new();
+ push("checking decoded");
+ check(camel_address_decode(CAMEL_ADDRESS(addr), test_address[i].addr) == test_address[i].count);
+ format = camel_address_format(CAMEL_ADDRESS(addr));
+ check(strcmp(format, test_address[i].utf8) == 0);
+ test_free(format);
+ pull();
+
+ push("Comparing re-encoded output");
+ addr2 = CAMEL_INTERNET_ADDRESS(camel_internet_address_new());
+ enc = camel_address_encode(CAMEL_ADDRESS(addr));
+ check_msg(camel_address_decode(CAMEL_ADDRESS(addr2), enc) == test_address[i].count, "enc = '%s'", enc);
+ test_free(enc);
+ test_address_compare(addr, addr2);
+ check_unref(addr2, 1);
+ pull();
+
+ check_unref(addr, 1);
+
+ pull();
+ }
+
+ camel_test_end();
+
+ /* FIXME: Add test of decoding of broken addresses */
+
+ return 0;
+}
+
+
diff --git a/camel/tests/message/test3.c b/camel/tests/message/test3.c
new file mode 100644
index 0000000000..ac82895435
--- /dev/null
+++ b/camel/tests/message/test3.c
@@ -0,0 +1,196 @@
+/*
+ Multipart.
+*/
+
+#include "camel-test.h"
+#include "messages.h"
+
+/* for stat */
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <camel/camel-mime-message.h>
+#include <camel/camel-stream-fs.h>
+#include <camel/camel-stream-mem.h>
+#include "camel/camel-multipart.h"
+
+int main(int argc, char **argv)
+{
+ CamelMimeMessage *msg, *msg2, *msg3;
+ CamelMultipart *mp, *mp2;
+ CamelMimePart *part, *part2, *part3;
+
+ camel_test_init(argc, argv);
+
+ camel_test_start("multipart message");
+
+ push("building message");
+ msg = test_message_create_simple();
+ mp = camel_multipart_new();
+
+ /* Hrm, this should be able to set its own boundary, no? */
+ camel_multipart_set_boundary(mp, "_=,.XYZ_Kangaroo_Meat_is_!_ABADF00D");
+ check(strcmp(camel_multipart_get_boundary(mp), "_=,.XYZ_Kangaroo_Meat_is_!_ABADF00D") == 0);
+
+ camel_medium_set_content_object((CamelMedium *)msg, (CamelDataWrapper *)mp);
+ check(camel_multipart_get_number(mp) == 0);
+ check(camel_multipart_get_part(mp, 0) == NULL);
+ check(camel_multipart_get_part(mp, 1) == NULL);
+
+ push("adding/removing parts");
+ part = camel_mime_part_new();
+ test_message_set_content_simple(part, 0, "text/plain", "content part 1", strlen("content part 1"));
+ camel_multipart_add_part(mp, part);
+ check(CAMEL_OBJECT(part)->ref_count == 2);
+ check(camel_multipart_get_number(mp) == 1);
+ check(camel_multipart_get_part(mp, 0) == part);
+ check(camel_multipart_get_part(mp, 1) == NULL);
+
+ camel_multipart_remove_part(mp, part);
+ check(CAMEL_OBJECT(part)->ref_count == 1);
+ check(camel_multipart_get_number(mp) == 0);
+ check(camel_multipart_get_part(mp, 0) == NULL);
+ check(camel_multipart_get_part(mp, 1) == NULL);
+
+ camel_multipart_add_part_at(mp, part, 0);
+ check(CAMEL_OBJECT(part)->ref_count == 2);
+ check(camel_multipart_get_number(mp) == 1);
+ check(camel_multipart_get_part(mp, 0) == part);
+ check(camel_multipart_get_part(mp, 1) == NULL);
+
+ check(camel_multipart_remove_part_at(mp, 1) == NULL);
+ check(CAMEL_OBJECT(part)->ref_count == 2);
+ check(camel_multipart_get_number(mp) == 1);
+ check(camel_multipart_get_part(mp, 0) == part);
+ check(camel_multipart_get_part(mp, 1) == NULL);
+
+ check(camel_multipart_remove_part_at(mp, 0) == part);
+ check(CAMEL_OBJECT(part)->ref_count == 1);
+ check(camel_multipart_get_number(mp) == 0);
+ check(camel_multipart_get_part(mp, 0) == NULL);
+ check(camel_multipart_get_part(mp, 1) == NULL);
+
+ camel_multipart_add_part(mp, part);
+ check(CAMEL_OBJECT(part)->ref_count == 2);
+ check(camel_multipart_get_number(mp) == 1);
+ check(camel_multipart_get_part(mp, 0) == part);
+ check(camel_multipart_get_part(mp, 1) == NULL);
+
+ part2 = camel_mime_part_new();
+ test_message_set_content_simple(part2, 0, "text/plain", "content part 2", strlen("content part 2"));
+ camel_multipart_add_part(mp, part2);
+ check(CAMEL_OBJECT(part2)->ref_count == 2);
+ check(camel_multipart_get_number(mp) == 2);
+ check(camel_multipart_get_part(mp, 0) == part);
+ check(camel_multipart_get_part(mp, 1) == part2);
+
+ part3 = camel_mime_part_new();
+ test_message_set_content_simple(part3, 0, "text/plain", "content part 3", strlen("content part 3"));
+ camel_multipart_add_part_at(mp, part3, 1);
+ check(CAMEL_OBJECT(part3)->ref_count == 2);
+ check(camel_multipart_get_number(mp) == 3);
+ check(camel_multipart_get_part(mp, 0) == part);
+ check(camel_multipart_get_part(mp, 1) == part3);
+ check(camel_multipart_get_part(mp, 2) == part2);
+ pull();
+
+ push("save message to test3.msg");
+ unlink("test3.msg");
+ test_message_write_file(msg, "test3.msg");
+ pull();
+
+ push("read from test3.msg");
+ msg2 = test_message_read_file("test3.msg");
+ pull();
+
+ push("compre content of multipart");
+ mp2 = (CamelMultipart *)camel_medium_get_content_object((CamelMedium *)msg2);
+ check(mp2 != NULL);
+ check(CAMEL_IS_MULTIPART(mp2));
+ check(camel_multipart_get_number(mp2) == 3);
+
+ check(strcmp(camel_multipart_get_boundary(mp2), "_=,.XYZ_Kangaroo_Meat_is_!_ABADF00D") == 0);
+ check(mp2->preface == NULL || strlen(mp2->preface) == 0);
+
+ /* FIXME */
+ camel_test_nonfatal("postface may gain a single \\n?");
+ check_msg(mp2->postface == NULL || strlen(mp2->postface) == 0, "postface: '%s'", mp2->postface);
+ camel_test_fatal();
+
+ test_message_compare_content(camel_medium_get_content_object(CAMEL_MEDIUM(camel_multipart_get_part(mp2, 0))),
+ "content part 1", strlen("content part 1"));
+ test_message_compare_content(camel_medium_get_content_object(CAMEL_MEDIUM(camel_multipart_get_part(mp2, 1))),
+ "content part 3", strlen("content part 3"));
+ test_message_compare_content(camel_medium_get_content_object(CAMEL_MEDIUM(camel_multipart_get_part(mp2, 2))),
+ "content part 2", strlen("content part 2"));
+ pull();
+
+ push("writing again, & re-reading");
+ unlink("test3-2.msg");
+ test_message_write_file(msg2, "test3-2.msg");
+ msg3 = test_message_read_file("test3-2.msg");
+
+ push("comparing again");
+ mp2 = (CamelMultipart *)camel_medium_get_content_object((CamelMedium *)msg3);
+ check(mp2 != NULL);
+ check(CAMEL_IS_MULTIPART(mp2));
+ check(camel_multipart_get_number(mp2) == 3);
+
+ check(strcmp(camel_multipart_get_boundary(mp2), "_=,.XYZ_Kangaroo_Meat_is_!_ABADF00D") == 0);
+ check(mp2->preface == NULL || strlen(mp2->preface) == 0);
+
+ check_msg(mp2->postface == NULL || strlen(mp2->postface) == 0, "postface: '%s'", mp2->postface);
+
+ test_message_compare_content(camel_medium_get_content_object(CAMEL_MEDIUM(camel_multipart_get_part(mp2, 0))),
+ "content part 1", strlen("content part 1"));
+ test_message_compare_content(camel_medium_get_content_object(CAMEL_MEDIUM(camel_multipart_get_part(mp2, 1))),
+ "content part 3", strlen("content part 3"));
+ test_message_compare_content(camel_medium_get_content_object(CAMEL_MEDIUM(camel_multipart_get_part(mp2, 2))),
+ "content part 2", strlen("content part 2"));
+ pull();
+ pull();
+
+ check_unref(msg2, 1);
+ check_unref(msg3, 1);
+
+ push("testing pre/post text");
+ camel_multipart_set_preface(mp, "pre-text\nLines.");
+ camel_multipart_set_postface(mp, "post-text, no lines.\nOne line.\n");
+
+ check(strcmp(mp->preface, "pre-text\nLines.") == 0);
+ check(strcmp(mp->postface, "post-text, no lines.\nOne line.\n") == 0);
+
+ push("writing /re-reading");
+ unlink("test3-3.msg");
+ test_message_write_file(msg, "test3-3.msg");
+ msg2 = test_message_read_file("test3-3.msg");
+
+ mp2 = (CamelMultipart *)camel_medium_get_content_object((CamelMedium *)msg2);
+ check(mp2 != NULL);
+ check(CAMEL_IS_MULTIPART(mp2));
+ check(camel_multipart_get_number(mp2) == 3);
+
+ check(strcmp(camel_multipart_get_boundary(mp2), "_=,.XYZ_Kangaroo_Meat_is_!_ABADF00D") == 0);
+ check(mp2->preface && strcmp(mp2->preface, "pre-text\nLines.") == 0);
+ check(mp2->postface && strcmp(mp2->postface, "post-text, no lines.\nOne line.\n") == 0);
+ test_message_compare_content(camel_medium_get_content_object(CAMEL_MEDIUM(camel_multipart_get_part(mp2, 0))),
+ "content part 1", strlen("content part 1"));
+ test_message_compare_content(camel_medium_get_content_object(CAMEL_MEDIUM(camel_multipart_get_part(mp2, 1))),
+ "content part 3", strlen("content part 3"));
+ test_message_compare_content(camel_medium_get_content_object(CAMEL_MEDIUM(camel_multipart_get_part(mp2, 2))),
+ "content part 2", strlen("content part 2"));
+ pull();
+ check_unref(msg2, 1);
+ pull();
+
+ check_unref(msg, 1);
+ check_unref(mp, 1);
+ check_unref(part, 1);
+ check_unref(part2, 1);
+ check_unref(part3, 1);
+
+ camel_test_end();
+
+ return 0;
+}
diff --git a/camel/tests/mime-filter/Makefile.am b/camel/tests/mime-filter/Makefile.am
new file mode 100644
index 0000000000..91da15ca2b
--- /dev/null
+++ b/camel/tests/mime-filter/Makefile.am
@@ -0,0 +1,38 @@
+
+INCLUDES = \
+ -I$(includedir) \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/intl \
+ -I$(top_srcdir)/e-util \
+ -I$(top_srcdir)/camel \
+ -I$(top_srcdir)/camel/tests/lib \
+ -DG_LOG_DOMAIN=\"evolution-tests\" \
+ -DSOURCEDIR=\"$(srcdir)\" \
+ $(CAMEL_CFLAGS)
+
+LDADD = \
+ $(top_builddir)/camel/libcamel.la \
+ $(top_builddir)/e-util/libeutil.la \
+ $(top_builddir)/camel/tests/lib/libcameltest.a \
+ $(INTLLIBS) \
+ $(EVOLUTION_MAIL_LIBS)
+
+EXTRA_DIST = \
+ crlf-1.in \
+ crlf-1.out \
+ charset-iso-2022-jp.0.in \
+ charset-iso-2022-jp.0.out \
+ charset-gb2312.0.in \
+ charset-gb2312.0.out
+
+check_PROGRAMS = \
+ test1 \
+ test-crlf \
+ test-charset \
+ test-tohtml
+
+TESTS = test1 \
+ test-crlf test-charset test-tohtml
+
+
+
diff --git a/camel/tests/mime-filter/test1.c b/camel/tests/mime-filter/test1.c
new file mode 100644
index 0000000000..a0a68db3c3
--- /dev/null
+++ b/camel/tests/mime-filter/test1.c
@@ -0,0 +1,108 @@
+/*
+ test-crlf.c
+
+ Test the CamelMimeFilterCanon class
+*/
+
+#include <stdio.h>
+#include <string.h>
+
+#include "camel-test.h"
+
+#include <camel/camel-stream-fs.h>
+#include <camel/camel-stream-mem.h>
+#include <camel/camel-stream-filter.h>
+#include <camel/camel-mime-filter-canon.h>
+
+#define d(x) x
+
+#define NUM_CASES 1
+#define CHUNK_SIZE 4096
+
+struct {
+ int flags;
+ char *in;
+ char *out;
+} tests[] = {
+ { CAMEL_MIME_FILTER_CANON_FROM|CAMEL_MIME_FILTER_CANON_CRLF,
+ "From \nRussia - with love.\n\n",
+ "=46rom \r\nRussia - with love.\r\n\r\n" },
+ { CAMEL_MIME_FILTER_CANON_FROM|CAMEL_MIME_FILTER_CANON_CRLF,
+ "From \r\nRussia - with love.\r\n\n",
+ "=46rom \r\nRussia - with love.\r\n\r\n" },
+ { CAMEL_MIME_FILTER_CANON_FROM|CAMEL_MIME_FILTER_CANON_CRLF,
+ "Tasmiania with fur \nFrom",
+ "Tasmiania with fur \r\nFrom" },
+ { CAMEL_MIME_FILTER_CANON_FROM,
+ "Tasmiania with fur \nFrom",
+ "Tasmiania with fur \nFrom" },
+ { CAMEL_MIME_FILTER_CANON_CRLF,
+ "Tasmiania with fur \nFrom",
+ "Tasmiania with fur \r\nFrom" },
+ { CAMEL_MIME_FILTER_CANON_FROM|CAMEL_MIME_FILTER_CANON_CRLF,
+ "Tasmiania with fur \nFrom here",
+ "Tasmiania with fur \r\n=46rom here" },
+ { CAMEL_MIME_FILTER_CANON_FROM|CAMEL_MIME_FILTER_CANON_CRLF|CAMEL_MIME_FILTER_CANON_STRIP,
+ "Tasmiania with fur \nFrom here",
+ "Tasmiania with fur\r\n=46rom here" },
+ { CAMEL_MIME_FILTER_CANON_FROM|CAMEL_MIME_FILTER_CANON_CRLF|CAMEL_MIME_FILTER_CANON_STRIP,
+ "Tasmiania with fur \nFrom here\n",
+ "Tasmiania with fur\r\n=46rom here\r\n" },
+ { CAMEL_MIME_FILTER_CANON_FROM|CAMEL_MIME_FILTER_CANON_CRLF|CAMEL_MIME_FILTER_CANON_STRIP,
+ "Tasmiania with fur \nFrom here or there ? \n",
+ "Tasmiania with fur\r\n=46rom here or there ?\r\n" },
+};
+
+int
+main (int argc, char **argv)
+{
+ CamelStreamFilter *filter;
+ CamelMimeFilter *sh;
+ int i;
+
+ camel_test_init(argc, argv);
+
+ camel_test_start("canonicalisation filter tests");
+
+ for (i=0;i<sizeof(tests)/sizeof(tests[0]);i++) {
+ int step;
+
+ camel_test_push("Data test %d '%s'\n", i, tests[i].in);
+
+ /* try all write sizes */
+ for (step=1;step<20;step++) {
+ CamelStreamMem *out;
+ char *p;
+
+ camel_test_push("Chunk size %d\n", step);
+
+ out = (CamelStreamMem *)camel_stream_mem_new();
+ filter = camel_stream_filter_new_with_stream((CamelStream *)out);
+ sh = camel_mime_filter_canon_new(tests[i].flags);
+ check(camel_stream_filter_add(filter, sh) != -1);
+ check_unref(sh, 2);
+
+ p = tests[i].in;
+ while (*p) {
+ int w = MIN(strlen(p), step);
+
+ check(camel_stream_write((CamelStream *)filter, p, w) == w);
+ p += w;
+ }
+ camel_stream_flush((CamelStream *)filter);
+
+ check_msg(out->buffer->len == strlen(tests[i].out), "Buffer length mismatch: expected %d got %d\n or '%s' got '%.*s'", strlen(tests[i].out), out->buffer->len, tests[i].out, out->buffer->len, out->buffer->data);
+ check_msg(0 == memcmp(out->buffer->data, tests[i].out, out->buffer->len), "Buffer mismatch: expected '%s' got '%.*s'", tests[i].out, out->buffer->len, out->buffer->data);
+ check_unref(filter, 1);
+ check_unref(out, 1);
+
+ camel_test_pull();
+ }
+
+ camel_test_pull();
+ }
+
+ camel_test_end();
+
+ return 0;
+}
diff --git a/composer/ChangeLog b/composer/ChangeLog
index ddd7bf10dc..6d1cb98596 100644
--- a/composer/ChangeLog
+++ b/composer/ChangeLog
@@ -1,144 +1,7 @@
-2005-02-15 Jeffrey Stedfast <fejj@novell.com>
+2005-01-08 Not Zed <NotZed@Ximian.com>
- * e-msg-composer-select-file.c (select_attach_response): Fix
- previous patch for the !USE_GTKFILECHOOSER case.
-
-2005-02-16 Harry Lu <harry.lu@sun.com>
-
- Add a11y name for attachment button and bars
-
- * e-msg-composer-attachment-bar.c:
- (e_msg_composer_attachment_bar_new):
- * e-msg-composer.c: (create_composer):
-
-2005-02-10 Not Zed <NotZed@Ximian.com>
-
- ** See bug #66126.
-
- * e-msg-composer-attachment-bar.c (destroy): destroy async file
- requesters.
- (add_from_user_response, add_from_user): use async file
- requesters.
-
- * e-msg-composer.c (save): don't fallback to saveas if the
- filename is null.
- (saveas, saveas_response): new functions for async file
- requesters.
- (menu_file_save_cb): call saveas if we have no filename.
- (menu_file_save_as_cb): call saveas.
- (menu_file_open_cb, file_open_response): change for async file
- loading (which doesn't appear to be used anymore).
- (destroy): destroy async requesters.
-
- * e-msg-composer-select-file.c (get_selector): make it no longer
- modal, no longer show the window.
- (select_file_response, e_msg_composer_select_file): make it async.
- (select_attach_response, e_msg_composer_select_file_attachments):
- same.
-
-2005-01-24 Hans Petter Jansson <hpj@novell.com>
-
- * e-msg-composer-hdrs.c (create_addressbook_entry): Set pointers to the
- contact editor creation functions in the entries, so they can pop up
- said editors.
-
-2005-01-12 Not Zed <NotZed@Ximian.com>
-
- * e-msg-composer.c (destroy): initialise composer before using it.
- sigh.
-
-2005-01-05 Not Zed <NotZed@Ximian.com>
-
- * e-msg-composer.c (d): turn off debug, setup g private instance
- data structure.
- (setup_ui): activate the composer plugin menu.
- (destroy): clean up the composer plugin menu.
- (class_init, init): init private instance data & plugin menu.
-
-2004-12-24 JP Rosevear <jpr@novell.com>
-
- * e-msg-composer.c (setup_signatures_menu): kill warnings
- (map_default_cb): the to entry widget is now just a gtk entry at
- its core, so check for text that way
-
-2004-12-23 Hans Petter Jansson <hpj@novell.com>
-
- * Makefile.am (selectnamesdir)
- (IDL_GENERATED)
- (INCLUDES): Remove select-names from here.
-
- * Composer.idl: Remove Evolution-Addressbook-SelectNames.idl include.
-
-2004-12-22 Hans Petter Jansson <hpj@novell.com>
-
- * e-msg-composer-hdrs.c (addressbook_dialog_response)
- (setup_corba)
- (setup_name_selector)
- (address_button_clicked_cb)
- (addressbook_entry_changed)
- (create_addressbook_entry)
- (destroy)
- (e_msg_composer_hdrs_new)
- (destinations_to_name_selector_entry)
- (e_msg_composer_hdrs_set_to)
- (e_msg_composer_hdrs_set_cc)
- (e_msg_composer_hdrs_set_bcc)
- (destination_list_to_destv)
- (e_msg_composer_hdrs_get_to)
- (e_msg_composer_hdrs_get_cc)
- (e_msg_composer_hdrs_get_bcc): Adapt to new ENameSelector.
-
-2004-12-17 Not Zed <NotZed@Ximian.com>
-
- * e-msg-composer-attachment-bar.c (emcab_popup):
-
- * e-msg-composer.c (drag_data_received):
-
-2004-12-08 Hans Petter Jansson <hpj@novell.com>
-
- * e-msg-composer-hdrs.h: Include <libebook/e-destination.h> from
- evolution-data-server.
-
-2004-12-07 Not Zed <NotZed@Ximian.com>
-
- * e-msg-composer.c: include camel-cipher-context.h so we build if
- nss isn't available.
-
-2004-11-26 JP Rosevear <jpr@novell.com>
-
- * e-msg-composer.c (create_composer): get image from icon factory
- directly
-
-2004-11-15 Not Zed <NotZed@Ximian.com>
-
- * e-msg-composer.c (handle_multipart_encrypted): remove the old
- camel_multipart_encrypted api.
-
-2004-10-28 Not Zed <NotZed@Ximian.com>
-
- * e-msg-composer.c (drag_data_received): fix the popup id.
-
- * e-msg-composer-attachment-bar.c (emcab_popup): added popup doco.
-
-2004-10-27 Jeffrey Stedfast <fejj@ximian.com>
-
- * e-msg-composer.c (composer_key_pressed): Close on Esc.
- (create_composer): Connect to the key-press-event signal.
-
-2004-10-26 mengjie yu <meng-jie.yu@sun.com>
-
- fix for bugzilla #44876
-
- * e-msg-composer-hdrs.c (header_new_recipient, create_headers):
- add access key for Reply_to, From, Subject, To, Cc, Bcc, Post_to
-
- * e-msg-composer.c (setup_signatures_menu): Add accesss key for
- Signature.
-
-2004-10-19 JP Rosevear <jpr@novell.com>
-
- * e-msg-composer.c, e-msg-composer-attachment-bar.c: convert to
- org.gnome hook names
+ * e-msg-composer-attachment-bar.c (popup_menu_placement_callback):
+ use cast macro to cast index.
2004-10-08 Jeffrey Stedfast <fejj@novell.com>
@@ -146,31 +9,10 @@
into the recipients list or else we end up free'ing them later
when we shouldn't. Fixes bug #66703
-2004-10-06 Not Zed <NotZed@Ximian.com>
-
- * e-msg-composer.c (drag_data_received):
- * e-msg-composer-attachment-bar.c (emcab_popup): e-popup api changes.
-
-2004-10-01 JP Rosevear <jpr@novell.com>
-
- * e-msg-composer.c: uses GTKHTML_API_VERSION for the bonobo server
- look up
-
-2004-10-01 Not Zed <NotZed@Ximian.com>
+2004-10-08 JP Rosevear <jpr@novell.com>
- * e-msg-composer.c (create_composer): enable ask drop action and
- hook onto drag motion.
- (drag_motion): implement.
- (drop_action): do the work here now.
- (drag_data_received): popup a menu if the action is ask.
- (drop_popup_copy, drop_popup_move, drop_popup_cancel):
- (drop_popup_free): Popup callbacks.
-
-2004-09-30 Kjartan Maraas <kmaraas@gnome.org>
-
- * e-msg-composer.c: (autosave_manager_start),
- (autosave_manager_stop), (create_composer): Use non-deprecated
- functions.
+ * mail-composer-errors.xml: remove acceleratoer from _Save Message
+ to not break string freeze
2004-08-17 Michael Meeks <michael@ximian.com>
@@ -225,17 +67,6 @@
* e-msg-composer-attachment.c: include config.h. See #61395.
-2004-09-04 Not Zed <NotZed@Ximian.com>
-
- * e-msg-composer-*.c: include gnome-i18n.h if required.
-
-2004-08-30 Not Zed <NotZed@Ximian.com>
-
- * e-msg-composer-attachment-bar.c (emcab_popup): em-popup based
- popup menu to replace the gnome one.
- (popup_menu_event): use new func above.
- (button_press_event): ", some cleanup.
-
2004-06-18 Not Zed <NotZed@Ximian.com>
** Fix for #60387.
diff --git a/composer/e-msg-composer-attachment-bar.c b/composer/e-msg-composer-attachment-bar.c
index 8a7b4357f4..1007cde4cd 100644
--- a/composer/e-msg-composer-attachment-bar.c
+++ b/composer/e-msg-composer-attachment-bar.c
@@ -31,15 +31,18 @@
#include <gconf/gconf.h>
#include <gconf/gconf-client.h>
#include <gdk/gdkkeysyms.h>
+#include <libgnome/gnome-util.h>
+#include <libgnomeui/gnome-app.h>
+#include <libgnomeui/gnome-app-helper.h>
+#include <libgnomeui/gnome-popup-menu.h>
#include <libgnomevfs/gnome-vfs-mime-handlers.h>
-#include <libgnome/gnome-i18n.h>
#include "e-msg-composer.h"
#include "e-msg-composer-select-file.h"
#include "e-msg-composer-attachment.h"
#include "e-msg-composer-attachment-bar.h"
-#include <libedataserver/e-iconv.h>
+#include <gal/util/e-iconv.h>
#include <camel/camel-data-wrapper.h>
#include <camel/camel-stream-fs.h>
@@ -52,7 +55,6 @@
#include "e-util/e-gui-utils.h"
#include "e-util/e-icon-factory.h"
#include "widgets/misc/e-error.h"
-#include "mail/em-popup.h"
#define ICON_WIDTH 64
#define ICON_SEPARATORS " /-_"
@@ -66,10 +68,11 @@
static GnomeIconListClass *parent_class = NULL;
struct _EMsgComposerAttachmentBarPrivate {
- GtkWidget *attach; /* attachment file dialogue, if active */
-
GList *attachments;
guint num_attachments;
+
+ GtkWidget *context_menu;
+ GtkWidget *icon_context_menu;
};
@@ -372,159 +375,151 @@ static void
edit_selected (EMsgComposerAttachmentBar *bar)
{
GnomeIconList *icon_list;
- GList *selection, *attach;
+ EMsgComposerAttachment *attachment;
+ GList *selection;
int num;
icon_list = GNOME_ICON_LIST (bar);
selection = gnome_icon_list_get_selection (icon_list);
- if (selection) {
- num = GPOINTER_TO_INT (selection->data);
- attach = g_list_nth (bar->priv->attachments, num);
- if (attach)
- e_msg_composer_attachment_edit ((EMsgComposerAttachment *)attach->data, GTK_WIDGET (bar));
- }
+ num = GPOINTER_TO_INT (selection->data);
+ attachment = g_list_nth (bar->priv->attachments, num)->data;
+
+ e_msg_composer_attachment_edit (attachment, GTK_WIDGET (bar));
}
+
/* "Attach" dialog. */
-static void
-add_from_user_response(EMsgComposer *composer, GSList *names, int is_inline)
-{
- while (names) {
- add_from_file((EMsgComposerAttachmentBar *)composer->attachment_bar, names->data, is_inline ? "inline" : "attachment");
- names = g_slist_next(names);
- }
-}
static void
add_from_user (EMsgComposerAttachmentBar *bar)
{
EMsgComposer *composer;
+ GPtrArray *file_list;
+ gboolean is_inline = FALSE;
+ int i;
composer = E_MSG_COMPOSER (gtk_widget_get_toplevel (GTK_WIDGET (bar)));
- e_msg_composer_select_file_attachments(composer, &bar->priv->attach, add_from_user_response);
+
+ file_list = e_msg_composer_select_file_attachments (composer, &is_inline);
+ if (!file_list)
+ return;
+
+ for (i = 0; i < file_list->len; i++) {
+ add_from_file (bar, file_list->pdata[i], is_inline ? "inline" : "attachment");
+ g_free (file_list->pdata[i]);
+ }
+
+ g_ptr_array_free (file_list, TRUE);
}
/* Callbacks. */
static void
-emcab_add(EPopup *ep, EPopupItem *item, void *data)
+add_cb (GtkWidget *widget, gpointer data, GtkWidget *for_widget)
{
- EMsgComposerAttachmentBar *bar = data;
-
- add_from_user(bar);
+ g_return_if_fail (E_IS_MSG_COMPOSER_ATTACHMENT_BAR (data));
+
+ add_from_user (E_MSG_COMPOSER_ATTACHMENT_BAR (data));
}
static void
-emcab_properties(EPopup *ep, EPopupItem *item, void *data)
+properties_cb (GtkWidget *widget, gpointer data, GtkWidget *for_widget)
{
- EMsgComposerAttachmentBar *bar = data;
+ EMsgComposerAttachmentBar *bar;
+
+ g_return_if_fail (E_IS_MSG_COMPOSER_ATTACHMENT_BAR (data));
- edit_selected(bar);
+ bar = E_MSG_COMPOSER_ATTACHMENT_BAR (data);
+ edit_selected (data);
}
static void
-emcab_remove(EPopup *ep, EPopupItem *item, void *data)
+remove_cb (GtkWidget *widget, gpointer data, GtkWidget *for_widget)
{
- EMsgComposerAttachmentBar *bar = data;
-
- remove_selected(bar);
+ EMsgComposerAttachmentBar *bar;
+
+ g_return_if_fail (E_IS_MSG_COMPOSER_ATTACHMENT_BAR (data));
+
+ bar = E_MSG_COMPOSER_ATTACHMENT_BAR (data);
+ remove_selected (bar);
}
+
/* Popup menu handling. */
-static EPopupItem emcab_popups[] = {
- { E_POPUP_ITEM, "10.attach", N_("_Remove"), emcab_remove, NULL, GTK_STOCK_REMOVE, EM_POPUP_ATTACHMENTS_MANY },
- { E_POPUP_ITEM, "20.attach", N_("_Properties"), emcab_properties, NULL, GTK_STOCK_PROPERTIES, EM_POPUP_ATTACHMENTS_ONE },
- { E_POPUP_BAR, "30.attach.00", NULL, NULL, NULL, NULL, EM_POPUP_ATTACHMENTS_MANY|EM_POPUP_ATTACHMENTS_ONE },
- { E_POPUP_ITEM, "30.attach.01", N_("_Add attachment..."), emcab_add, NULL, GTK_STOCK_ADD, 0 },
+
+static GnomeUIInfo icon_context_menu_info[] = {
+ GNOMEUIINFO_ITEM_STOCK (N_("_Remove"),
+ N_("Remove selected items from the attachment list"),
+ remove_cb,
+ GTK_STOCK_REMOVE),
+ GNOMEUIINFO_MENU_PROPERTIES_ITEM (properties_cb, NULL),
+ GNOMEUIINFO_END
};
-static void
-emcab_popup_position(GtkMenu *menu, int *x, int *y, gboolean *push_in, gpointer user_data)
+#define ICON_CONTEXT_MENU_PROPERTIES (1)
+
+static GtkWidget *
+get_icon_context_menu (EMsgComposerAttachmentBar *bar)
{
- EMsgComposerAttachmentBar *bar = user_data;
- GnomeIconList *icon_list = user_data;
- GList *selection;
- GnomeCanvasPixbuf *image;
-
- gdk_window_get_origin (((GtkWidget*) bar)->window, x, y);
-
- selection = gnome_icon_list_get_selection (icon_list);
- if (selection == NULL)
- return;
+ EMsgComposerAttachmentBarPrivate *priv;
- image = gnome_icon_list_get_icon_pixbuf_item (icon_list, (gint)selection->data);
- if (image == NULL)
- return;
+ priv = bar->priv;
+ if (priv->icon_context_menu == NULL)
+ priv->icon_context_menu = gnome_popup_menu_new (icon_context_menu_info);
- /* Put menu to the center of icon. */
- *x += (int)(image->item.x1 + image->item.x2) / 2;
- *y += (int)(image->item.y1 + image->item.y2) / 2;
+ return priv->icon_context_menu;
}
static void
-emcab_popups_free(EPopup *ep, GSList *l, void *data)
+popup_icon_context_menu (EMsgComposerAttachmentBar *bar,
+ gint num,
+ GdkEventButton *event)
{
- g_slist_free(l);
-}
+ GtkWidget *menu;
+ GnomeIconList *icon_list;
+ GList *selection;
-/* if id != -1, then use it as an index for target of the popup */
-static void
-emcab_popup(EMsgComposerAttachmentBar *bar, GdkEventButton *event, int id)
-{
- GList *p;
- GSList *attachments = NULL, *menus = NULL;
- int i;
- EMPopup *emp;
- EMPopupTargetAttachments *t;
- GtkMenu *menu;
- EMsgComposerAttachment *attachment;
+ menu = get_icon_context_menu (bar);
+ icon_list = GNOME_ICON_LIST (bar);
+ selection = gnome_icon_list_get_selection (icon_list);
- /* We need to check if there are duplicated index in the return list of
- gnome_icon_list_get_selection() because of gnome bugzilla bug #122356.
- FIXME in the future. */
+ gtk_widget_set_sensitive (icon_context_menu_info[ICON_CONTEXT_MENU_PROPERTIES].widget, g_list_length (selection) == 1);
- if (id == -1
- || (attachment = g_list_nth_data(bar->priv->attachments, id)) == NULL) {
- p = gnome_icon_list_get_selection((GnomeIconList *)bar);
- for ( ; p != NULL; p = p->next) {
- int num = GPOINTER_TO_INT(p->data);
- EMsgComposerAttachment *attachment = g_list_nth_data(bar->priv->attachments, num);
-
- if (attachment && g_slist_find(attachments, attachment) == NULL) {
- g_object_ref(attachment);
- attachments = g_slist_prepend(attachments, attachment);
- }
- }
- attachments = g_slist_reverse(attachments);
- } else {
- g_object_ref(attachment);
- attachments = g_slist_prepend(attachments, attachment);
- }
+ gnome_popup_menu_do_popup (menu, NULL, NULL, event, bar, NULL);
+}
- for (i=0;i<sizeof(emcab_popups)/sizeof(emcab_popups[0]);i++)
- menus = g_slist_prepend(menus, &emcab_popups[i]);
-
- /** @HookPoint-EMPopup: Composer Attachment Bar Context Menu
- * @Id: org.gnome.evolution.mail.composer.attachmentbar.popup
- * @Class: org.gnome.evolution.mail.popup:1.0
- * @Target: EMPopupTargetAttachments
- *
- * This is the context menu on the composer attachment bar.
- */
- emp = em_popup_new("org.gnome.evolution.mail.composer.attachmentbar.popup");
- e_popup_add_items((EPopup *)emp, menus, NULL,emcab_popups_free, bar);
- t = em_popup_target_new_attachments(emp, attachments);
- t->target.widget = (GtkWidget *)bar;
- menu = e_popup_create_menu_once((EPopup *)emp, (EPopupTarget *)t, 0);
-
- if (event == NULL)
- gtk_menu_popup(menu, NULL, NULL, emcab_popup_position, bar, 0, gtk_get_current_event_time());
- else
- gtk_menu_popup(menu, NULL, NULL, NULL, NULL, event->button, event->time);
+static GnomeUIInfo context_menu_info[] = {
+ GNOMEUIINFO_ITEM (N_("Add attachment..."),
+ N_("Attach a file to the message"),
+ add_cb, NULL),
+ GNOMEUIINFO_END
+};
+
+static GtkWidget *
+get_context_menu (EMsgComposerAttachmentBar *bar)
+{
+ EMsgComposerAttachmentBarPrivate *priv;
+
+ priv = bar->priv;
+ if (priv->context_menu == NULL)
+ priv->context_menu = gnome_popup_menu_new (context_menu_info);
+
+ return priv->context_menu;
+}
+
+static void
+popup_context_menu (EMsgComposerAttachmentBar *bar,
+ GdkEventButton *event)
+{
+ GtkWidget *menu;
+
+ menu = get_context_menu (bar);
+ gnome_popup_menu_do_popup (menu, NULL, NULL, event, bar, NULL);
}
+
/* GtkObject methods. */
static void
@@ -536,10 +531,6 @@ destroy (GtkObject *object)
if (bar->priv) {
free_attachment_list (bar);
-
- if (bar->priv->attach)
- gtk_widget_destroy(bar->priv->attach);
-
g_free (bar->priv);
bar->priv = NULL;
}
@@ -548,42 +539,91 @@ destroy (GtkObject *object)
(* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
}
+
/* GtkWidget methods. */
+
+static void
+popup_menu_placement_callback (GtkMenu *menu, int *x, int *y, gboolean *push_in, gpointer user_data)
+{
+ EMsgComposerAttachmentBar *bar;
+ GnomeIconList *icon_list;
+ GList *selection;
+ GnomeCanvasPixbuf *image;
+
+ bar = E_MSG_COMPOSER_ATTACHMENT_BAR (user_data);
+ icon_list = GNOME_ICON_LIST (user_data);
+
+ gdk_window_get_origin (((GtkWidget*) bar)->window, x, y);
+
+ selection = gnome_icon_list_get_selection (icon_list);
+ if (selection == NULL)
+ return;
+
+ image = gnome_icon_list_get_icon_pixbuf_item (icon_list, GPOINTER_TO_INT(selection->data));
+ if (image == NULL)
+ return;
+
+ /* Put menu to the center of icon. */
+ *x += (int)(image->item.x1 + image->item.x2) / 2;
+ *y += (int)(image->item.y1 + image->item.y2) / 2;
+}
+
static gboolean
popup_menu_event (GtkWidget *widget)
{
- emcab_popup((EMsgComposerAttachmentBar *)widget, NULL, -1);
+ EMsgComposerAttachmentBar *bar = E_MSG_COMPOSER_ATTACHMENT_BAR (widget);
+ GnomeIconList *icon_list = GNOME_ICON_LIST (widget);
+ GList *selection = gnome_icon_list_get_selection (icon_list);
+ GtkWidget *menu;
+
+ if (selection == NULL)
+ menu = get_context_menu (bar);
+ else
+ menu = get_icon_context_menu (bar);
+
+ gnome_popup_menu_do_popup (menu, popup_menu_placement_callback,
+ widget, NULL, widget, NULL);
+
return TRUE;
}
static int
-button_press_event (GtkWidget *widget, GdkEventButton *event)
+button_press_event (GtkWidget *widget,
+ GdkEventButton *event)
{
- EMsgComposerAttachmentBar *bar = (EMsgComposerAttachmentBar *)widget;
- GnomeIconList *icon_list = GNOME_ICON_LIST(widget);
+ EMsgComposerAttachmentBar *bar;
+ GnomeIconList *icon_list;
int icon_number;
+ bar = E_MSG_COMPOSER_ATTACHMENT_BAR (widget);
+ icon_list = GNOME_ICON_LIST (widget);
+
if (event->button != 3)
return GTK_WIDGET_CLASS (parent_class)->button_press_event (widget, event);
icon_number = gnome_icon_list_get_icon_at (icon_list, event->x, event->y);
+
if (icon_number >= 0) {
- gnome_icon_list_unselect_all(icon_list);
gnome_icon_list_select_icon (icon_list, icon_number);
+ popup_icon_context_menu (bar, icon_number, event);
+ } else {
+ popup_context_menu (bar, event);
}
-
- emcab_popup(bar, event, icon_number);
return TRUE;
}
static gint
-key_press_event(GtkWidget *widget, GdkEventKey *event)
+key_press_event (GtkWidget *widget, GdkEventKey *event)
{
- EMsgComposerAttachmentBar *bar = E_MSG_COMPOSER_ATTACHMENT_BAR(widget);
-
+ EMsgComposerAttachmentBar *bar;
+ GnomeIconList *icon_list;
+
+ bar = E_MSG_COMPOSER_ATTACHMENT_BAR (widget);
+ icon_list = GNOME_ICON_LIST (bar);
+
if (event->keyval == GDK_Delete) {
remove_selected (bar);
return TRUE;
@@ -634,8 +674,10 @@ init (EMsgComposerAttachmentBar *bar)
priv = g_new (EMsgComposerAttachmentBarPrivate, 1);
- priv->attach = NULL;
priv->attachments = NULL;
+ priv->context_menu = NULL;
+ priv->icon_context_menu = NULL;
+
priv->num_attachments = 0;
bar->priv = priv;
@@ -698,9 +740,6 @@ e_msg_composer_attachment_bar_new (GtkAdjustment *adj)
gnome_icon_list_set_icon_border (icon_list, ICON_BORDER);
gnome_icon_list_set_text_spacing (icon_list, ICON_TEXT_SPACING);
gnome_icon_list_set_selection_mode (icon_list, GTK_SELECTION_MULTIPLE);
-
- atk_object_set_name (gtk_widget_get_accessible (GTK_WIDGET (new)),
- _("Attachment Bar"));
return GTK_WIDGET (new);
}
diff --git a/composer/e-msg-composer.c b/composer/e-msg-composer.c
index 76483c76b6..5012637c67 100644
--- a/composer/e-msg-composer.c
+++ b/composer/e-msg-composer.c
@@ -70,7 +70,6 @@
#include <gconf/gconf-client.h>
#include <libgnome/gnome-exec.h>
-#include <libgnome/gnome-i18n.h>
#include <libgnomeui/gnome-uidefs.h>
#include <libgnomeui/gnome-window-icon.h>
@@ -86,7 +85,7 @@
#include <glade/glade.h>
-#include <libedataserver/e-iconv.h>
+#include <gal/util/e-iconv.h>
#include <gal/e-text/e-entry.h>
#include "e-util/e-dialog-utils.h"
@@ -105,7 +104,6 @@
#include <camel/camel-multipart-signed.h>
#include <camel/camel-multipart-encrypted.h>
#include <camel/camel-string-utils.h>
-#include <camel/camel-cipher-context.h>
#if defined (HAVE_NSS) && defined (SMIME_SUPPORTED)
#include <camel/camel-smime-context.h>
#endif
@@ -118,8 +116,6 @@
#include "mail/mail-ops.h"
#include "mail/mail-mt.h"
#include "mail/mail-session.h"
-#include "mail/em-popup.h"
-#include "mail/em-menu.h"
#include "e-msg-composer.h"
#include "e-msg-composer-attachment-bar.h"
@@ -132,18 +128,9 @@
#include "Editor.h"
#include "listener.h"
-#define GNOME_GTKHTML_EDITOR_CONTROL_ID "OAFIID:GNOME_GtkHTML_Editor:" GTKHTML_API_VERSION
+#define GNOME_GTKHTML_EDITOR_CONTROL_ID "OAFIID:GNOME_GtkHTML_Editor:3.1"
-#define d(x)
-
-#define _PRIVATE(o) (g_type_instance_get_private ((GTypeInstance *)o, e_msg_composer_get_type()))
-
-typedef struct _EMsgComposerPrivate {
- EMMenu *menu;
-
- GtkWidget *saveas; /* saveas async file requester */
- GtkWidget *load; /* same for load - not used */
-} EMsgComposerPrivate;
+#define d(x) x
enum {
SEND,
@@ -173,19 +160,6 @@ static GtkTargetEntry drop_types[] = {
#define num_drop_types (sizeof (drop_types) / sizeof (drop_types[0]))
-static struct {
- char *target;
- GdkAtom atom;
- guint32 actions;
-} drag_info[] = {
- { "message/rfc822", 0, GDK_ACTION_COPY },
- { "x-uid-list", 0, GDK_ACTION_ASK|GDK_ACTION_MOVE|GDK_ACTION_COPY },
- { "text/uri-list", 0, GDK_ACTION_COPY },
- { "_NETSCAPE_URL", 0, GDK_ACTION_COPY },
- { "text/x-vcard", 0, GDK_ACTION_COPY },
- { "text/calendar", 0, GDK_ACTION_COPY },
-};
-
static const char *emc_draft_format_names[] = { "pgp-sign", "pgp-encrypt", "smime-sign", "smime-encrypt" };
@@ -1192,22 +1166,36 @@ show_attachments (EMsgComposer *composer,
}
static void
-save (EMsgComposer *composer, const char *filename)
+save (EMsgComposer *composer, const char *default_filename)
{
CORBA_Environment ev;
+ char *filename;
int fd;
+ if (default_filename != NULL)
+ filename = g_strdup (default_filename);
+ else
+ filename = e_msg_composer_select_file (composer, _("Save as..."), TRUE);
+
+ if (filename == NULL)
+ return;
+
/* check to see if we already have the file and that we can create it */
if ((fd = open (filename, O_RDONLY | O_CREAT | O_EXCL, 0777)) == -1) {
int resp, errnosav = errno;
struct stat st;
if (stat (filename, &st) == 0 && S_ISREG (st.st_mode)) {
- resp = e_error_run((GtkWindow *)composer, E_ERROR_ASK_FILE_EXISTS_OVERWRITE, filename, NULL);
- if (resp != GTK_RESPONSE_OK)
+ resp = e_error_run((GtkWindow *)composer, E_ERROR_ASK_FILE_EXISTS_OVERWRITE,
+ filename, NULL);
+ if (resp != GTK_RESPONSE_OK) {
+ g_free (filename);
return;
+ }
} else {
- e_error_run((GtkWindow *)composer, E_ERROR_NO_SAVE_FILE, filename, g_strerror(errnosav));
+ e_error_run((GtkWindow *)composer, E_ERROR_NO_SAVE_FILE,
+ filename, g_strerror(errnosav));
+ g_free (filename);
return;
}
} else
@@ -1225,20 +1213,8 @@ save (EMsgComposer *composer, const char *filename)
e_msg_composer_unset_autosaved (composer);
}
CORBA_exception_free (&ev);
-}
-
-static void
-saveas_response(EMsgComposer *composer, const char *name)
-{
- save(composer, name);
-}
-
-static void
-saveas(EMsgComposer *composer)
-{
- EMsgComposerPrivate *p = _PRIVATE(composer);
-
- e_msg_composer_select_file (composer, &p->saveas, saveas_response, _("Save as..."), TRUE);
+
+ g_free (filename);
}
static void
@@ -1467,14 +1443,14 @@ static void
autosave_manager_start (AutosaveManager *am)
{
if (am->id == 0)
- am->id = g_timeout_add (AUTOSAVE_INTERVAL, autosave_run, am);
+ am->id = gtk_timeout_add (AUTOSAVE_INTERVAL, autosave_run, am);
}
static void
autosave_manager_stop (AutosaveManager *am)
{
if (am->id) {
- g_source_remove (am->id);
+ gtk_timeout_remove (am->id);
am->id = 0;
}
}
@@ -1586,22 +1562,24 @@ do_exit (EMsgComposer *composer)
}
/* Menu callbacks. */
-static void
-file_open_response(EMsgComposer *composer, const char *name)
-{
- load (composer, name);
-}
static void
menu_file_open_cb (BonoboUIComponent *uic,
void *data,
const char *path)
{
- EMsgComposerPrivate *p = _PRIVATE(data);
-
- /* NB: This function is never used anymore */
-
- e_msg_composer_select_file(E_MSG_COMPOSER (data), &p->load, file_open_response, _("Open File"), FALSE);
+ EMsgComposer *composer;
+ char *file_name;
+
+ composer = E_MSG_COMPOSER (data);
+
+ file_name = e_msg_composer_select_file (composer, _("Open file"), FALSE);
+ if (file_name == NULL)
+ return;
+
+ load (composer, file_name);
+
+ g_free (file_name);
}
static void
@@ -1620,7 +1598,7 @@ menu_file_save_cb (BonoboUIComponent *uic,
file_name = Bonobo_PersistFile_getCurrentFile (composer->persist_file_interface, &ev);
if (ev._major != CORBA_NO_EXCEPTION) {
- saveas (composer);
+ save (composer, NULL);
} else {
save (composer, file_name);
CORBA_free (file_name);
@@ -1633,7 +1611,11 @@ menu_file_save_as_cb (BonoboUIComponent *uic,
void *data,
const char *path)
{
- saveas (E_MSG_COMPOSER(data));
+ EMsgComposer *composer;
+
+ composer = E_MSG_COMPOSER (data);
+
+ save (composer, NULL);
}
static void
@@ -2096,14 +2078,12 @@ setup_signatures_menu (EMsgComposer *composer)
EIterator *it;
hbox = e_msg_composer_hdrs_get_from_hbox (E_MSG_COMPOSER_HDRS (composer->hdrs));
-
- label = gtk_label_new_with_mnemonic (_("Si_gnature:"));
+
+ label = gtk_label_new (_("Signature:"));
gtk_widget_show (label);
-
+
composer->sig_menu = (GtkOptionMenu *) gtk_option_menu_new ();
-
- gtk_label_set_mnemonic_widget ((GtkLabel *) label, (GtkWidget *)composer->sig_menu);
-
+
gtk_box_pack_end_defaults (GTK_BOX (hbox), (GtkWidget *) composer->sig_menu);
gtk_box_pack_end (GTK_BOX (hbox), label, FALSE, TRUE, 0);
hspace = gtk_hbox_new (FALSE, 0);
@@ -2142,8 +2122,6 @@ setup_signatures_menu (EMsgComposer *composer)
static void
setup_ui (EMsgComposer *composer)
{
- EMMenuTargetWidget *target;
- EMsgComposerPrivate *p = _PRIVATE(composer);
BonoboUIContainer *container;
gboolean hide_smime;
char *charset;
@@ -2287,11 +2265,6 @@ setup_ui (EMsgComposer *composer)
/* Create the UIComponent for the non-control entries */
composer->entry_uic = bonobo_ui_component_new_default ();
-
- /* Setup main menu plugin mechanism */
- target = em_menu_target_new_widget(p->menu, (GtkWidget *)composer);
- e_menu_update_target((EMenu *)p->menu, target);
- e_menu_activate((EMenu *)p->menu, composer->uic, TRUE);
}
@@ -2554,29 +2527,14 @@ composer_dispose(GObject *object)
static void
destroy (GtkObject *object)
{
- EMsgComposer *composer = (EMsgComposer *)object;
+ EMsgComposer *composer;
CORBA_Environment ev;
ESignatureList *signatures;
- EMsgComposerPrivate *p = _PRIVATE(composer);
-
+
+ composer = E_MSG_COMPOSER (object);
+
CORBA_exception_init (&ev);
-
- if (p->menu) {
- e_menu_update_target((EMenu *)p->menu, NULL);
- g_object_unref(p->menu);
- p->menu = NULL;
- }
-
- if (p->load) {
- gtk_widget_destroy(p->load);
- p->load = NULL;
- }
-
- if (p->saveas) {
- gtk_widget_destroy(p->saveas);
- p->saveas = NULL;
- }
-
+
if (composer->uic) {
bonobo_object_unref (BONOBO_OBJECT (composer->uic));
composer->uic = NULL;
@@ -2646,7 +2604,7 @@ destroy (GtkObject *object)
g_signal_handler_disconnect (signatures, composer->sig_changed_id);
composer->sig_changed_id = 0;
}
-
+
if (GTK_OBJECT_CLASS (parent_class)->destroy != NULL)
(* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
}
@@ -2686,24 +2644,10 @@ attach_message(EMsgComposer *composer, CamelMimeMessage *msg)
camel_object_unref(mime_part);
}
-struct _drop_data {
- EMsgComposer *composer;
-
- GdkDragContext *context;
- /* Only selection->data and selection->length are valid */
- GtkSelectionData *selection;
-
- guint32 action;
- guint info;
- guint time;
-
- unsigned int move:1;
- unsigned int moved:1;
- unsigned int aborted:1;
-};
-
static void
-drop_action(EMsgComposer *composer, GdkDragContext *context, guint32 action, GtkSelectionData *selection, guint info, guint time)
+drag_data_received (EMsgComposer *composer, GdkDragContext *context,
+ int x, int y, GtkSelectionData *selection,
+ guint info, guint time)
{
char *tmp, *str, **urls;
CamelMimePart *mime_part;
@@ -2711,8 +2655,8 @@ drop_action(EMsgComposer *composer, GdkDragContext *context, guint32 action, Gtk
CamelURL *url;
CamelMimeMessage *msg;
char *content_type;
- int i, success=FALSE, delete=FALSE;
-
+ int i;
+
switch (info) {
case DND_TYPE_MESSAGE_RFC822:
d(printf ("dropping a message/rfc822\n"));
@@ -2722,11 +2666,8 @@ drop_action(EMsgComposer *composer, GdkDragContext *context, guint32 action, Gtk
camel_stream_reset (stream);
msg = camel_mime_message_new ();
- if (camel_data_wrapper_construct_from_stream((CamelDataWrapper *)msg, stream) != -1) {
+ if (camel_data_wrapper_construct_from_stream((CamelDataWrapper *)msg, stream) != -1)
attach_message(composer, msg);
- success = TRUE;
- delete = action == GDK_ACTION_MOVE;
- }
camel_object_unref(msg);
camel_object_unref(stream);
@@ -2765,7 +2706,6 @@ drop_action(EMsgComposer *composer, GdkDragContext *context, guint32 action, Gtk
}
g_free (urls);
- success = TRUE;
break;
case DND_TYPE_TEXT_VCARD:
case DND_TYPE_TEXT_CALENDAR:
@@ -2783,7 +2723,6 @@ drop_action(EMsgComposer *composer, GdkDragContext *context, guint32 action, Gtk
camel_object_unref (mime_part);
g_free (content_type);
- success = TRUE;
break;
case DND_TYPE_X_UID_LIST: {
GPtrArray *uids;
@@ -2848,8 +2787,6 @@ drop_action(EMsgComposer *composer, GdkDragContext *context, guint32 action, Gtk
camel_object_unref(mime_part);
camel_object_unref(mp);
}
- success = TRUE;
- delete = action == GDK_ACTION_MOVE;
fail:
if (camel_exception_is_set(&ex)) {
char *name;
@@ -2875,117 +2812,6 @@ drop_action(EMsgComposer *composer, GdkDragContext *context, guint32 action, Gtk
d(printf ("dropping an unknown\n"));
break;
}
-
- printf("Drag finished, success %d delete %d\n", success, delete);
-
- gtk_drag_finish(context, success, delete, time);
-}
-
-static void
-drop_popup_copy(EPopup *ep, EPopupItem *item, void *data)
-{
- struct _drop_data *m = data;
- drop_action(m->composer, m->context, GDK_ACTION_COPY, m->selection, m->info, m->time);
-}
-
-static void
-drop_popup_move(EPopup *ep, EPopupItem *item, void *data)
-{
- struct _drop_data *m = data;
- drop_action(m->composer, m->context, GDK_ACTION_MOVE, m->selection, m->info, m->time);
-}
-
-static void
-drop_popup_cancel(EPopup *ep, EPopupItem *item, void *data)
-{
- struct _drop_data *m = data;
- gtk_drag_finish(m->context, FALSE, FALSE, m->time);
-}
-
-static EPopupItem drop_popup_menu[] = {
- { E_POPUP_ITEM, "00.emc.02", N_("_Copy"), drop_popup_copy, NULL, "stock_mail-copy", 0 },
- { E_POPUP_ITEM, "00.emc.03", N_("_Move"), drop_popup_move, NULL, "stock_mail-move", 0 },
- { E_POPUP_BAR, "10.emc" },
- { E_POPUP_ITEM, "99.emc.00", N_("Cancel _Drag"), drop_popup_cancel, NULL, NULL, 0 },
-};
-
-static void
-drop_popup_free(EPopup *ep, GSList *items, void *data)
-{
- struct _drop_data *m = data;
-
- g_slist_free(items);
-
- g_object_unref(m->context);
- g_object_unref(m->composer);
- g_free(m->selection->data);
- g_free(m->selection);
- g_free(m);
-}
-
-static void
-drag_data_received (EMsgComposer *composer, GdkDragContext *context,
- int x, int y, GtkSelectionData *selection,
- guint info, guint time)
-{
- if (selection->data == NULL || selection->length == -1)
- return;
-
- if (context->action == GDK_ACTION_ASK) {
- EMPopup *emp;
- GSList *menus = NULL;
- GtkMenu *menu;
- int i;
- struct _drop_data *m;
-
- m = g_malloc0(sizeof(*m));
- m->context = context;
- g_object_ref(context);
- m->composer = composer;
- g_object_ref(composer);
- m->action = context->action;
- m->info = info;
- m->time = time;
- m->selection = g_malloc0(sizeof(*m->selection));
- m->selection->data = g_malloc(selection->length);
- memcpy(m->selection->data, selection->data, selection->length);
- m->selection->length = selection->length;
-
- emp = em_popup_new("org.gnome.evolution.mail.composer.popup.drop");
- for (i=0;i<sizeof(drop_popup_menu)/sizeof(drop_popup_menu[0]);i++)
- menus = g_slist_append(menus, &drop_popup_menu[i]);
-
- e_popup_add_items((EPopup *)emp, menus, NULL, drop_popup_free, m);
- menu = e_popup_create_menu_once((EPopup *)emp, NULL, 0);
- gtk_menu_popup(menu, NULL, NULL, NULL, NULL, 0, time);
- } else {
- drop_action(composer, context, context->action, selection, info, time);
- }
-}
-
-static gboolean
-drag_motion(GObject *o, GdkDragContext *context, gint x, gint y, guint time, EMsgComposer *composer)
-{
- GList *targets;
- GdkDragAction action, actions = 0;
-
- for (targets = context->targets; targets; targets = targets->next) {
- int i;
-
- for (i=0;i<sizeof(drag_info)/sizeof(drag_info[0]);i++)
- if (targets->data == (void *)drag_info[i].atom)
- actions |= drag_info[i].actions;
- }
-
- actions &= context->actions;
- action = context->suggested_action;
- /* we default to copy */
- if (action == GDK_ACTION_ASK && (actions & (GDK_ACTION_MOVE|GDK_ACTION_COPY)) != (GDK_ACTION_MOVE|GDK_ACTION_COPY))
- action = GDK_ACTION_COPY;
-
- gdk_drag_status(context, action, time);
-
- return action != 0;
}
static void
@@ -2994,16 +2820,10 @@ class_init (EMsgComposerClass *klass)
GtkObjectClass *object_class;
GtkWidgetClass *widget_class;
GObjectClass *gobject_class;
- int i;
-
- for (i=0;i<sizeof(drag_info)/sizeof(drag_info[0]);i++)
- drag_info[i].atom = gdk_atom_intern(drag_info[i].target, FALSE);
gobject_class = G_OBJECT_CLASS(klass);
object_class = GTK_OBJECT_CLASS (klass);
widget_class = GTK_WIDGET_CLASS (klass);
-
- g_type_class_add_private(gobject_class, sizeof(struct _EMsgComposerPrivate));
gobject_class->finalize = composer_finalise;
gobject_class->dispose = composer_dispose;
@@ -3035,8 +2855,6 @@ class_init (EMsgComposerClass *klass)
static void
init (EMsgComposer *composer)
{
- EMsgComposerPrivate *p = _PRIVATE(composer);
-
composer->uic = NULL;
composer->hdrs = NULL;
@@ -3077,16 +2895,6 @@ init (EMsgComposer *composer)
composer->enable_autosave = TRUE;
composer->autosave_file = NULL;
composer->autosave_fd = -1;
-
- /** @HookPoint-EMMenu: Main Mail Menu
- * @Id: org.gnome.evolution.mail.composer
- * @Class: org.gnome.evolution.mail.bonobomenu:1.0
- * @Target: EMMenuTargetWidget
- *
- * The main menu of the composer window. The widget of the
- * target will point to the EMsgComposer object.
- */
- p->menu = em_menu_new("org.gnome.evolution.mail.composer");
}
@@ -3191,20 +2999,27 @@ static void
map_default_cb (EMsgComposer *composer, gpointer user_data)
{
GtkWidget *widget;
+ BonoboControlFrame *cf;
+ Bonobo_PropertyBag pb = CORBA_OBJECT_NIL;
CORBA_Environment ev;
const char *subject;
- const char *text;
-
- /* If the 'To:' field is empty, focus it */
+ char *text;
+ /* If the 'To:' field is empty, focus it (This is ridiculously complicated) */
+
widget = e_msg_composer_hdrs_get_to_entry (E_MSG_COMPOSER_HDRS (composer->hdrs));
- text = gtk_entry_get_text (GTK_ENTRY (widget));
+ cf = bonobo_widget_get_control_frame (BONOBO_WIDGET (widget));
+ pb = bonobo_control_frame_get_control_property_bag (cf, NULL);
+ text = bonobo_pbclient_get_string (pb, "text", NULL);
+ bonobo_object_release_unref (pb, NULL);
if (!text || text[0] == '\0') {
- gtk_widget_grab_focus (widget);
+ bonobo_control_frame_control_activate (cf);
+ g_free (text);
return;
}
+ g_free (text);
/* If not, check the subject field */
@@ -3231,19 +3046,6 @@ msg_composer_destroy_notify (void *data)
all_composers = g_slist_remove (all_composers, composer);
}
-static int
-composer_key_pressed (EMsgComposer *composer, GdkEventKey *event, void *user_data)
-{
- if (event->keyval == GDK_Escape) {
- do_exit (composer);
- g_signal_stop_emission_by_name (composer, "key-press-event");
- return TRUE;
- }
-
- return FALSE;
-}
-
-
/* Verbs for non-control entries */
static BonoboUIVerb entry_verbs [] = {
BONOBO_UI_VERB ("EditCut", menu_edit_cut_cb),
@@ -3356,16 +3158,13 @@ create_composer (int visible_mask)
int vis;
GList *icon_list;
BonoboControlFrame *control_frame;
+ GdkPixbuf *attachment_pixbuf;
composer = g_object_new (E_TYPE_MSG_COMPOSER, "win_name", _("Compose a message"), NULL);
gtk_window_set_title ((GtkWindow *) composer, _("Compose a message"));
all_composers = g_slist_prepend (all_composers, composer);
- g_signal_connect (composer, "key-press-event",
- G_CALLBACK (composer_key_pressed),
- NULL);
-
g_signal_connect (composer, "destroy",
G_CALLBACK (msg_composer_destroy_notify),
NULL);
@@ -3378,9 +3177,10 @@ create_composer (int visible_mask)
}
/* DND support */
- gtk_drag_dest_set (GTK_WIDGET (composer), GTK_DEST_DEFAULT_ALL, drop_types, num_drop_types, GDK_ACTION_COPY|GDK_ACTION_ASK|GDK_ACTION_MOVE);
- g_signal_connect(composer, "drag_data_received", G_CALLBACK (drag_data_received), NULL);
- g_signal_connect(composer, "drag-motion", G_CALLBACK(drag_motion), composer);
+ gtk_drag_dest_set (GTK_WIDGET (composer), GTK_DEST_DEFAULT_ALL,
+ drop_types, num_drop_types, GDK_ACTION_COPY);
+ g_signal_connect (composer, "drag_data_received",
+ G_CALLBACK (drag_data_received), NULL);
e_msg_composer_load_config (composer, visible_mask);
setup_ui (composer);
@@ -3475,9 +3275,11 @@ create_composer (int visible_mask)
gtk_misc_set_alignment (GTK_MISC (composer->attachment_expander_num), 1.0, 0.5);
expander_hbox = gtk_hbox_new (FALSE, 0);
- composer->attachment_expander_icon = e_icon_factory_get_image ("stock_attach", E_ICON_SIZE_MENU);
+ attachment_pixbuf = e_icon_factory_get_icon ("stock_attach", E_ICON_SIZE_MENU);
+ composer->attachment_expander_icon = gtk_image_new_from_pixbuf (attachment_pixbuf);
gtk_misc_set_alignment (GTK_MISC (composer->attachment_expander_icon), 1, 0.5);
gtk_widget_set_size_request (composer->attachment_expander_icon, 100, -1);
+ gdk_pixbuf_unref (attachment_pixbuf);
gtk_box_pack_start (GTK_BOX (expander_hbox), composer->attachment_expander_label,
TRUE, TRUE, 0);
@@ -3490,7 +3292,6 @@ create_composer (int visible_mask)
composer->attachment_expander = e_expander_new ("");
e_expander_set_label_widget (E_EXPANDER (composer->attachment_expander), expander_hbox);
- atk_object_set_name (gtk_widget_get_accessible (composer->attachment_expander), _("Attachment Button: Press space key to toggle attachment bar"));
gtk_container_add (GTK_CONTAINER (composer->attachment_expander),
composer->attachment_scrolled_window);
@@ -3777,25 +3578,24 @@ handle_multipart_signed (EMsgComposer *composer, CamelMultipart *multipart, int
static void
handle_multipart_encrypted (EMsgComposer *composer, CamelMultipart *multipart, int depth)
{
+ CamelMultipartEncrypted *mpe = (CamelMultipartEncrypted *) multipart;
CamelContentType *content_type;
CamelCipherContext *cipher;
CamelDataWrapper *content;
CamelMimePart *mime_part;
CamelException ex;
- CamelCipherValidity *valid;
-
+
/* FIXME: make sure this is a PGP/MIME encrypted part?? */
e_msg_composer_set_pgp_encrypt (composer, TRUE);
camel_exception_init (&ex);
cipher = mail_crypto_get_pgp_cipher_context (NULL);
- mime_part = camel_mime_part_new();
- valid = camel_cipher_decrypt(cipher, (CamelMimePart *)multipart, mime_part, &ex);
- camel_object_unref(cipher);
+ mime_part = camel_multipart_encrypted_decrypt (mpe, cipher, &ex);
+ camel_object_unref (cipher);
camel_exception_clear (&ex);
- if (valid == NULL)
- return;
- camel_cipher_validity_free(valid);
+
+ if (!mime_part)
+ return;
content_type = camel_mime_part_get_content_type (mime_part);
diff --git a/composer/mail-composer-errors.xml b/composer/mail-composer-errors.xml
index 1a52225ca3..dc696a5f02 100644
--- a/composer/mail-composer-errors.xml
+++ b/composer/mail-composer-errors.xml
@@ -39,7 +39,7 @@
<secondary>Closing this composer window will discard the message permanently, unless you choose to save the message in your Drafts folder. This will allow you to continue the message at a later date.</secondary>
<button label="_Discard Changes" response="GTK_RESPONSE_NO"/>
<button stock="gtk-cancel" response="GTK_RESPONSE_CANCEL"/>
- <button label="_Save Message" response="GTK_RESPONSE_YES"/>
+ <button label="Save Message" response="GTK_RESPONSE_YES"/>
</error>
<error id="no-build-message" type="error" modal="true">
diff --git a/composer/mail-composer-errors.xml.h b/composer/mail-composer-errors.xml.h
index 30f0005258..1f6668c58f 100644
--- a/composer/mail-composer-errors.xml.h
+++ b/composer/mail-composer-errors.xml.h
@@ -31,7 +31,7 @@ char *s = N_("Are you sure you want to discard the message, titled '{0}', you ar
/* mail-composer:exit-unsaved secondary */
char *s = N_("Closing this composer window will discard the message permanently, unless you choose to save the message in your Drafts folder. This will allow you to continue the message at a later date.");
char *s = N_("_Discard Changes");
-char *s = N_("_Save Message");
+char *s = N_("Save Message");
/* mail-composer:no-build-message primary */
char *s = N_("Could not create message.");
/* mail-composer:no-build-message secondary */
diff --git a/configure.in b/configure.in
index 469d3f709e..7f768ac2f5 100644
--- a/configure.in
+++ b/configure.in
@@ -1,7 +1,7 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.52)
-AC_INIT(evolution, 2.1.5, http://bugzilla.ximian.com/enter_bug.cgi?product=Evolution)
+AC_INIT(evolution, 2.0.4, http://bugzilla.ximian.com/enter_bug.cgi?product=Evolution)
AC_CONFIG_SRCDIR(README)
AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION)
@@ -16,38 +16,6 @@ ACLOCAL="$ACLOCAL $ACLOCAL_FLAGS"
dnl Initialize maintainer mode
AM_MAINTAINER_MODE
-dnl *************************************************************************************************
-dnl Base Version
-dnl
-dnl This is for api/versioning tracking for things like bonobo .server files
-dnl
-dnl This should always be the major/minor of the stable version or stable version to be
-dnl *************************************************************************************************
-BASE_VERSION=2.2
-AC_SUBST(BASE_VERSION)
-AC_DEFINE_UNQUOTED(BASE_VERSION, "$BASE_VERSION", [Base version (Major.Minor)])
-
-dnl *************************************************************************************************
-dnl Upgrade Revision
-dnl
-dnl This is for triggering migration calls between varying versions.
-dnl
-dnl This should be reset to 0 whenever BASE_VERSION changes
-dnl *************************************************************************************************
-UPGRADE_REVISION=1
-AC_SUBST(UPGRADE_REVISION)
-AC_DEFINE_UNQUOTED(UPGRADE_REVISION, "$UPGRADE_REVISION", [The number of times we've upgraded since the BASE_VERSION release])
-
-dnl *************************************************************************************************
-dnl Development mode
-dnl
-dnl The controls whether things like the development warning in shell/main.c are displayed.
-dnl
-dnl This should be set to 0 for stable releases and 1 for unstable releases
-dnl *************************************************************************************************
-AC_DEFINE(DEVELOPMENT, 1, [If we are in development mode or not])
-AC_SUBST(DEVELOPMENT)
-
AC_ISC_POSIX
AC_PROG_CC
AC_PROG_CPP
@@ -78,10 +46,20 @@ AC_SUBST(HAVE_JW)
dnl I18N stuff
AC_PROG_INTLTOOL([0.30])
-ALL_LINGUAS="am ar az be bg bs ca cs cy da de el en_AU en_CA en_GB es et eu fa fi fr ga gl gu he hr hu is it ja ko lt lv mn ms nb nl nn no pa pl pt pt_BR ro ru sk sl sq sr sr@Latn sv tr uk vi wa zh_CN zh_TW"
+ALL_LINGUAS="am ar az be bg bn bs ca cs cy da de el en_AU en_CA en_GB es et eu fa fi fr ga gl gu he hi hr hu id is it ja ko lt lv mk ml mn ms nb nl nn no pa pl pt pt_BR ro ru sk sl sq sr sr@Latn sv ta tr uk vi wa zh_CN zh_TW"
AM_GLIB_GNU_GETTEXT
-GETTEXT_PACKAGE=evolution-2.2
+dnl The base version for OAFIIDs, install dirs, binary names
+BASE_VERSION=2.0
+AC_SUBST(BASE_VERSION)
+AC_DEFINE_UNQUOTED(BASE_VERSION, "$BASE_VERSION", [Base version (Major.Minor)])
+
+dnl Update/migration version
+UPGRADE_REVISION=0
+AC_SUBST(UPGRADE_REVISION)
+AC_DEFINE_UNQUOTED(UPGRADE_REVISION, "$UPGRADE_REVISION", [The number of times we've upgraded since the BASE_VERSION release])
+
+GETTEXT_PACKAGE=evolution-$BASE_VERSION
AC_SUBST(GETTEXT_PACKAGE)
AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE", [Package name for gettext])
@@ -122,7 +100,7 @@ AC_ARG_ENABLE(test-component, [ --enable-test-component=[no/yes] Enable te
AM_CONDITIONAL(ENABLE_TEST_COMPONENT, test "x$enable_test_comp" = "xyes")
dnl
-dnl system mail stuff (tbd?)
+dnl system mail stuff
dnl
AC_PATH_PROG(SENDMAIL, sendmail, /usr/sbin/sendmail, /usr/sbin:/usr/lib)
AC_DEFINE_UNQUOTED(SENDMAIL_PATH, "$SENDMAIL", [Path to a sendmail binary, or equivalent])
@@ -425,7 +403,7 @@ dnl **************************************************
dnl New IMAP code support.
dnl **************************************************
AC_ARG_ENABLE(imap4,
-[ --enable-imap4=[no/yes] Attempt to compile yet another, incomplete, very unsupported IMAPv4r1 implementation],,enable_imap4="yes")
+[ --enable-imap4=[no/yes] Attempt to compile yet another, incomplete, very unsupported IMAPv4r1 implementation],,enable_imap4=no)
if test "x$enable_imap4" = "xyes"; then
AC_DEFINE(ENABLE_IMAP4,1,[Really don't try this at home])
msg_imap4=yes
@@ -511,15 +489,11 @@ dnl *********
dnl Libraries
dnl *********
-PKG_CHECK_MODULES(GTKHTML, libgtkhtml-3.6)
+PKG_CHECK_MODULES(GTKHTML, libgtkhtml-3.1)
AC_SUBST(GTKHTML_CFLAGS)
AC_SUBST(GTKHTML_LIBS)
-GTKHTML_DATADIR=`$PKG_CONFIG --variable gtkhtml_datadir libgtkhtml-3.6`
+GTKHTML_DATADIR=`$PKG_CONFIG --variable gtkhtml_datadir libgtkhtml-3.1`
AC_SUBST(GTKHTML_DATADIR)
-GTKHTML_API_VERSION=`$PKG_CONFIG --variable gtkhtml_apiversion libgtkhtml-3.6`
-AC_DEFINE_UNQUOTED(GTKHTML_API_VERSION, "$GTKHTML_API_VERSION", [The gtkhtml api version])
-
-
dnl ******************************
@@ -687,16 +661,6 @@ AC_SUBST(KRB5_LDFLAGS)
AC_SUBST(KRB4_CFLAGS)
AC_SUBST(KRB4_LDFLAGS)
-dnl Mono hooks
-
-AC_ARG_ENABLE(mono, [ --enable-mono=[yes,no] Add Mono embedded hooks.],
- enable_mono="$enableval", enable_mono="no")
-
-if test "x${enable_mono}" = "xyes"; then
- AC_DEFINE(ENABLE_MONO,1,[Define if Mono embedding should be enabled])
- mono_package="mono"
-fi
-AM_CONDITIONAL(ENABLE_MONO, test x$enable_mono = xyes)
dnl ********************************************************************************
dnl security extension support (SSL and S/MIME)
@@ -1074,7 +1038,7 @@ esac
AM_PATH_ORBIT2(2.9.8)
AC_MSG_CHECKING(for CORBA include paths)
-IDL_INCLUDES="-I "`pkg-config --variable=idldir libbonobo-2.0`" -I "`pkg-config --variable=idldir bonobo-activation-2.0`" -I "`pkg-config --variable=idldir evolution-data-server-1.2`
+IDL_INCLUDES="-I "`pkg-config --variable=idldir libbonobo-2.0`" -I "`pkg-config --variable=idldir bonobo-activation-2.0`" -I "`pkg-config --variable=idldir evolution-data-server-1.0`
AC_MSG_RESULT($IDL_INCLUDES)
AC_SUBST(IDL_INCLUDES)
@@ -1098,25 +1062,19 @@ fi
dnl --- Required version numbers
-GAL_REQUIRED=2.3.4
-GAL_PACKAGE=2.4
-GTKHTML_REQUIRED=3.5.6
-GTKHTML_PACKAGE=3.6
-EDS_REQUIRED=1.1.5
-EDS_PACKAGE=1.2
+GAL_REQUIRED=2.2.5
+GTKHTML_REQUIRED=3.2.5
+EDS_REQUIRED=1.0.4
BONOBOUI_REQUIRED=2.4.2
AC_SUBST(GAL_REQUIRED)
-AC_SUBST(GAL_PACKAGE)
AC_SUBST(GTKHTML_REQUIRED)
-AC_SUBST(GTKHTML_PACKAGE)
AC_SUBST(EDS_REQUIRED)
-AC_SUBST(EDS_PACKAGE)
AC_SUBST(BONOBOUI_REQUIRED)
dnl --- Flags to get all the GNOME stuff
-FULL_GNOME_DEPS="glib-2.0 libbonoboui-2.0 >= $BONOBOUI_REQUIRED gnome-vfs-2.0 libgnomeui-2.0 libglade-2.0 libgnomecanvas-2.0 libxml-2.0 gconf-2.0 gal-$GAL_PACKAGE >= $GAL_REQUIRED"
+FULL_GNOME_DEPS="glib-2.0 libbonoboui-2.0 >= $BONOBOUI_REQUIRED gnome-vfs-2.0 libgnomeui-2.0 libglade-2.0 libgnomecanvas-2.0 libxml-2.0 gconf-2.0 gal-2.2 >= $GAL_REQUIRED"
EVO_SET_COMPILE_FLAGS(GNOME_FULL, $FULL_GNOME_DEPS)
AC_SUBST(GNOME_FULL_CFLAGS)
@@ -1130,11 +1088,15 @@ CPPFLAGS="$CPPFLAGS_save"
dnl --- Flags for the various libraries we build
-EVO_SET_COMPILE_FLAGS(CAMEL, camel-provider-$EDS_PACKAGE)
+EVO_SET_COMPILE_FLAGS(CAMEL, glib-2.0 gthread-2.0 gal-2.2 >= $GAL_REQUIRED $mozilla_nss,
+ $THREADS_CFLAGS $KRB4_CFLAGS $KRB5_CFLAGS $MANUAL_NSS_CFLAGS $OPENSSL_CFLAGS,
+ $THREADS_LIBS $KRB4_LDFLAGS $KRB5_LDFLAGS $MANUAL_NSS_LIBS $OPENSSL_LDFLAGS)
AC_SUBST(CAMEL_CFLAGS)
AC_SUBST(CAMEL_LIBS)
-EVO_SET_COMPILE_FLAGS(CAMEL_GROUPWISE, camel-provider-$EDS_PACKAGE libedataserver-$EDS_PACKAGE libegroupwise-$EDS_PACKAGE >= $EDS_REQUIRED)
+EVO_SET_COMPILE_FLAGS(CAMEL_GROUPWISE, libegroupwise-1.0 >= $EDS_REQUIRED,
+ $CAMEL_CFLAGS,
+ $CAMEL_LIBS)
AC_SUBST(CAMEL_GROUPWISE_CFLAGS)
AC_SUBST(CAMEL_GROUPWISE_LIBS)
@@ -1153,39 +1115,45 @@ EVO_SET_COMPILE_FLAGS(CERT_UI, glib-2.0 gobject-2.0 gthread-2.0,
AC_SUBST(CERT_UI_CFLAGS)
AC_SUBST(CERT_UI_LIBS)
-EVO_SET_COMPILE_FLAGS(E_NAME, libgnomeui-2.0 libbonoboui-2.0 >= $BONOBOUI_REQUIRED gal-$GAL_PACKAGE >= $GAL_REQUIRED)
+EVO_SET_COMPILE_FLAGS(E_NAME, libgnomeui-2.0 libbonoboui-2.0 >= $BONOBOUI_REQUIRED gal-2.2 >= $GAL_REQUIRED)
AC_SUBST(E_NAME_CFLAGS)
AC_SUBST(E_NAME_LIBS)
-EVO_SET_COMPILE_FLAGS(E_UTIL, gthread-2.0 gconf-2.0 libxml-2.0 libbonoboui-2.0 >= $BONOBOUI_REQUIRED libglade-2.0 gal-$GAL_PACKAGE >= $GAL_REQUIRED libgnomeui-2.0 libgnome-2.0 libgnomecanvas-2.0 libgnomeprintui-2.2 libedataserver-$EDS_PACKAGE libedataserverui-$EDS_PACKAGE >= $EDS_REQUIRED $mozilla_nspr $mono_package, $THREADS_CFLAGS $MANUAL_NSPR_CFLAGS, $THREADS_LIBS $MANUAL_NSPR_LIBS)
+EVO_SET_COMPILE_FLAGS(E_UTIL, gthread-2.0 gconf-2.0 libxml-2.0 libbonoboui-2.0 >= $BONOBOUI_REQUIRED libglade-2.0 gal-2.2 >= $GAL_REQUIRED libgnomeui-2.0 libgnome-2.0 libgnomecanvas-2.0 libedataserver-1.0 >= $EDS_REQUIRED $mozilla_nspr, $THREADS_CFLAGS $MANUAL_NSPR_CFLAGS, $THREADS_LIBS $MANUAL_NSPR_LIBS)
AC_SUBST(E_UTIL_CFLAGS)
AC_SUBST(E_UTIL_LIBS)
-EVO_SET_COMPILE_FLAGS(TZDIALOG, libecal-$EDS_PACKAGE >= $EDS_REQUIRED, $GNOME_FULL_CFLAGS, $GNOME_FULL_LIBS)
+EVO_SET_COMPILE_FLAGS(TZDIALOG, libecal-1.0 >= $EDS_REQUIRED, $GNOME_FULL_CFLAGS, $GNOME_FULL_LIBS)
AC_SUBST(TZDIALOG_CFLAGS)
AC_SUBST(TZDIALOG_LIBS)
-EVO_SET_COMPILE_FLAGS(E_WIDGETS, glib-2.0 libbonoboui-2.0 >= $BONOBOUI_REQUIRED gnome-vfs-2.0 libgnomeui-2.0 libglade-2.0 libgnomecanvas-2.0 libxml-2.0 gconf-2.0 gal-$GAL_PACKAGE >= $GAL_REQUIRED libedataserverui-$EDS_PACKAGE)
-AC_SUBST(E_WIDGETS_CFLAGS)
-AC_SUBST(E_WIDGETS_LIBS)
-
-EVO_SET_COMPILE_FLAGS(IMPORTERS, camel-$EDS_PACKAGE gconf-2.0 libglade-2.0 libbonoboui-2.0 >= $BONOBOUI_REQUIRED libgnomeui-2.0 libebook-$EDS_PACKAGE >= $EDS_REQUIRED)
+EVO_SET_COMPILE_FLAGS(SOURCE_SEL, libedataserver-1.0 >= $EDS_REQUIRED, $GNOME_FULL_CFLAGS, $GNOME_FULL_LIBS)
+AC_SUBST(SOURCE_SEL_CFLAGS)
+AC_SUBST(SOURCE_SEL_LIBS)
+
+
+dnl
+dnl EVO_SET_COMPILE_FLAGS(E_WIDGETS, bonobo_conf bonobox_print gdk_pixbuf gnomecanvaspixbuf gnomeui libglade oaf vfs)
+dnl AC_SUBST(E_WIDGETS_CFLAGS)
+dnl AC_SUBST(E_WIDGETS_LIBS)
+dnl
+EVO_SET_COMPILE_FLAGS(IMPORTERS, gconf-2.0 libglade-2.0 libbonoboui-2.0 >= $BONOBOUI_REQUIRED libgnomeui-2.0 libebook-1.0 >= $EDS_REQUIRED)
AC_SUBST(IMPORTERS_CFLAGS)
AC_SUBST(IMPORTERS_LIBS)
-EVO_SET_COMPILE_FLAGS(LIBFILTER, libgnome-2.0 libgnomeui-2.0 libglade-2.0 libxml-2.0 gconf-2.0 gal-$GAL_PACKAGE >= $GAL_REQUIRED libedataserver-$EDS_PACKAGE >= $EDS_REQUIRED)
+EVO_SET_COMPILE_FLAGS(LIBFILTER, libgnome-2.0 libgnomeui-2.0 libglade-2.0 libxml-2.0 gconf-2.0 gal-2.2 >= $GAL_REQUIRED)
AC_SUBST(LIBFILTER_CFLAGS)
AC_SUBST(LIBFILTER_LIBS)
dnl --- evolution (shell) flags
-EVO_SET_COMPILE_FLAGS(SHELL, libgnome-2.0 libgnomeui-2.0 libbonoboui-2.0 >= $BONOBOUI_REQUIRED gal-$GAL_PACKAGE >= $GAL_REQUIRED libglade-2.0 gnome-vfs-2.0 libgtkhtml-$GTKHTML_PACKAGE >= $GTKHTML_REQUIRED)
+EVO_SET_COMPILE_FLAGS(SHELL, libgnome-2.0 libgnomeui-2.0 libbonoboui-2.0 >= $BONOBOUI_REQUIRED gal-2.2 >= $GAL_REQUIRED libglade-2.0 gnome-vfs-2.0 libgtkhtml-3.1 >= $GTKHTML_REQUIRED)
AC_SUBST(SHELL_CFLAGS)
AC_SUBST(SHELL_LIBS)
dnl --- evolution-addressbook flags
-EVOLUTION_ADDRESSBOOK_DEPS="gconf-2.0 libbonoboui-2.0 >= $BONOBOUI_REQUIRED libglade-2.0 gal-$GAL_PACKAGE >= $GAL_REQUIRED libgnomeui-2.0 libgnome-2.0 libgnomecanvas-2.0 gnome-vfs-2.0 libgnomeprintui-2.2 libgtkhtml-$GTKHTML_PACKAGE >= $GTKHTML_REQUIRED libebook-$EDS_PACKAGE >= $EDS_REQUIRED libedataserverui-$EDS_PACKAGE >= $EDS_REQUIRED camel-$EDS_PACKAGE"
+EVOLUTION_ADDRESSBOOK_DEPS="gconf-2.0 libbonoboui-2.0 >= $BONOBOUI_REQUIRED libglade-2.0 gal-2.2 >= $GAL_REQUIRED libgnomeui-2.0 libgnome-2.0 libgnomecanvas-2.0 gnome-vfs-2.0 libgnomeprintui-2.2 libgtkhtml-3.1 >= $GTKHTML_REQUIRED libebook-1.0 >= $EDS_REQUIRED"
EVO_SET_COMPILE_FLAGS(EVOLUTION_ADDRESSBOOK, $EVOLUTION_ADDRESSBOOK_DEPS)
AC_SUBST(EVOLUTION_ADDRESSBOOK_CFLAGS)
@@ -1198,11 +1166,11 @@ AC_SUBST(EVOLUTION_ADDRESSBOOK_CONDUIT_LIBS)
fi
dnl --- evolution-calendar flags
-EVO_SET_COMPILE_FLAGS(LIBSOUP, libsoup-2.2 >= 2.2.0)
+EVO_SET_COMPILE_FLAGS(LIBSOUP, libsoup-2.2 >= 2.2.1)
AC_SUBST(LIBSOUP_CFLAGS)
AC_SUBST(LIBSOUP_LIBS)
-EVO_SET_COMPILE_FLAGS(EVOLUTION_CALENDAR, libgnome-2.0 libgnomeui-2.0 libbonoboui-2.0 gal-$GAL_PACKAGE >= $GAL_REQUIRED libglade-2.0 gnome-vfs-2.0 libgnomeprint-2.2 libgnomeprintui-2.2 gnome-vfs-module-2.0 libgtkhtml-$GTKHTML_PACKAGE >= $GTKHTML_REQUIRED libebook-$EDS_PACKAGE >= $EDS_REQUIRED libecal-$EDS_PACKAGE >= $EDS_REQUIRED libedataserverui-$EDS_PACKAGE >= $EDS_REQUIRED)
+EVO_SET_COMPILE_FLAGS(EVOLUTION_CALENDAR, libgnome-2.0 libgnomeui-2.0 libbonoboui-2.0 gal-2.2 >= $GAL_REQUIRED libglade-2.0 gnome-vfs-2.0 libgnomeprint-2.2 libgnomeprintui-2.2 libgtkhtml-3.1 >= $GTKHTML_REQUIRED libebook-1.0 >= $EDS_REQUIRED libecal-1.0 >= $EDS_REQUIRED)
AC_SUBST(EVOLUTION_CALENDAR_CFLAGS)
AC_SUBST(EVOLUTION_CALENDAR_LIBS)
@@ -1214,17 +1182,17 @@ fi
dnl --- evolution-mail flags
-EVO_SET_COMPILE_FLAGS(EVOLUTION_MAIL, camel-provider-$EDS_PACKAGE libgnome-2.0 libgnomeui-2.0 libbonoboui-2.0 >= $BONOBOUI_REQUIRED gal-$GAL_PACKAGE >= $GAL_REQUIRED libglade-2.0 gnome-vfs-module-2.0 libgnomeprint-2.2 libgnomeprintui-2.2 libgtkhtml-$GTKHTML_PACKAGE >= $GTKHTML_REQUIRED libxml-2.0 bonobo-activation-2.0 gthread-2.0 gconf-2.0 $mozilla_nss libebook-$EDS_PACKAGE >= $EDS_REQUIRED)
+EVO_SET_COMPILE_FLAGS(EVOLUTION_MAIL, libgnome-2.0 libgnomeui-2.0 libbonoboui-2.0 >= $BONOBOUI_REQUIRED gal-2.2 >= $GAL_REQUIRED libglade-2.0 gnome-vfs-module-2.0 libgnomeprint-2.2 libgnomeprintui-2.2 libgtkhtml-3.1 >= $GTKHTML_REQUIRED libxml-2.0 bonobo-activation-2.0 gthread-2.0 gconf-2.0 $mozilla_nss libebook-1.0 >= $EDS_REQUIRED)
AC_SUBST(EVOLUTION_MAIL_CFLAGS)
AC_SUBST(EVOLUTION_MAIL_LIBS)
dnl -- evolution-data-server IDL and version
-AC_DEFINE(DATASERVER_API_VERSION, "1.2", evolution-data-server API version)
-AC_DEFINE_UNQUOTED(DATASERVER_VERSION, "`pkg-config --modversion evolution-data-server-1.2`", evolution-data-server version)
+AC_DEFINE(DATASERVER_API_VERSION, "1.0", evolution-data-server API version)
+AC_DEFINE_UNQUOTED(DATASERVER_VERSION, "`pkg-config --modversion evolution-data-server-1.0`", evolution-data-server version)
AC_MSG_CHECKING(for evolution-data-server IDL)
-DATASERVER_IDL=`pkg-config --variable=idldir evolution-data-server-1.2`/Evolution-DataServer.idl
+DATASERVER_IDL=`pkg-config --variable=idldir evolution-data-server-1.0`/Evolution-DataServer.idl
if test -f "$DATASERVER_IDL"; then
AC_MSG_RESULT($DATASERVER_IDL)
AC_SUBST(DATASERVER_IDL)
@@ -1258,6 +1226,9 @@ AC_SUBST(privdatadir)
privincludedir='${includedir}'/evolution-$BASE_VERSION
AC_SUBST(privincludedir)
+camel_providerdir="$privlibdir/camel-providers"
+AC_SUBST(camel_providerdir)
+
componentdir="$privlibdir/components"
AC_SUBST(componentdir)
@@ -1320,76 +1291,6 @@ AC_DEFINE_UNQUOTED(INTERFACE_VERSION, "$INTERFACE_VERSION", [IDL interface versi
EVO_SERVER_RULE=$srcdir/server.mk
AC_SUBST_FILE(EVO_SERVER_RULE)
-dnl ************************
-dnl Plugins
-dnl ************************
-
-plugindir="$privlibdir/plugins"
-AC_SUBST(plugindir)
-
-EVO_PLUGIN_RULE=$srcdir/plugin.mk
-AC_SUBST_FILE(EVO_PLUGIN_RULE)
-
-AC_ARG_ENABLE(plugins, [ --enable-plugins=[no/all/list] Enable plugins.],enable_plugins="$enableval",enable_plugins=base)
-
-dnl Add any new plugins here
-plugins_base="calendar-file calendar-http calendar-weather groupwise-account-setup itip-formatter plugin-manager send-options shared-folder groupwise-send-options exchange-account-setup groupwise-status-tracking default-source addressbook-file addressbook-groupwise"
-
-plugins_all="bbdb subject-thread save-attachments prefer-plain save-calendar select-one-source copy-tool mail-to-meeting mail-to-task folder-unsubscribe mark-calendar-offline audio-inline mailing-list-actions backup-restore new-mail-notify"
-
-case x"$enable_plugins" in
-xno)
- plugins_enabled=""
- msg_plugins="no (some core functionality will not be available)"
- ;;
-xall | x | xyes)
- plugins_enabled="$plugins_base $plugins_all"
- msg_plugins="yes (all)"
- ;;
-xbase)
- plugins_enabled="$plugins_base"
- msg_plugins="yes ($plugins_base)"
- ;;
-*)
- plugins_enabled="$enable_plugins"
- msg_plugins="yes ($enable_plugins)"
- ;;
-esac
-AC_SUBST(plugins_enabled)
-AC_SUBST(plugins_all)
-AC_SUBST(plugins_base)
-
-if echo ${plugins_enabled} | grep -q "audio-inline"
-then
- if ${PKG_CONFIG} --exists gstreamer-0.8
- then
- dnl *********************
- dnl gstreamer
- dnl *********************
- PKG_CHECK_MODULES(GSTREAMER, gstreamer-0.8)
- AC_SUBST(GSTREAMER_CFLAGS)
- AC_SUBST(GSTREAMER_LIBS)
- else
- plugins_enabled=`echo $plugins_enabled | sed -e "s/audio-inline//g"`
- echo "warning: gstreamer was not found, audio-inline plugin will not be built."
- echo "you are probably missing gstreamer-devel package."
- fi
-fi
-
-if echo ${plugins_enabled} | grep -q "new-mail-notify" ; then
- if ${PKG_CONFIG} --exists dbus-glib-1 ; then
- dnl **************************************************
- dnl * New Mail Notify plugin
- dnl **************************************************
- PKG_CHECK_MODULES(NMN, dbus-glib-1)
- AC_SUBST(NMN_CFLAGS)
- AC_SUBST(NMN_LIBS)
- else
- plugins_enabled=`echo $plugins_enabled | sed -e "s/new-mail-notify//g"`
- echo "warning: dbus-glib-1 was not found, new-mail-notify plugin will not be built."
- fi
-fi
-
##################################################
# Check for gtk-doc.
##################################################
@@ -1474,7 +1375,6 @@ dnl ******************************
export privlibdir
export privincludedir
export privdatadir
-export plugindir
EVOLUTION_DIR=`(cd $srcdir; pwd)`
AC_SUBST(EVOLUTION_DIR)
@@ -1489,6 +1389,7 @@ addressbook/Makefile
addressbook/conduit/Makefile
addressbook/gui/Makefile
addressbook/gui/component/Makefile
+addressbook/gui/component/select-names/Makefile
addressbook/gui/contact-editor/Makefile
addressbook/gui/contact-list-editor/Makefile
addressbook/gui/merging/Makefile
@@ -1499,6 +1400,25 @@ addressbook/printing/Makefile
addressbook/tools/Makefile
addressbook/util/Makefile
art/Makefile
+camel/Makefile
+camel/providers/Makefile
+camel/providers/groupwise/Makefile
+camel/providers/imap/Makefile
+camel/providers/imapp/Makefile
+camel/providers/imap4/Makefile
+camel/providers/local/Makefile
+camel/providers/nntp/Makefile
+camel/providers/pop3/Makefile
+camel/providers/sendmail/Makefile
+camel/providers/smtp/Makefile
+camel/tests/Makefile
+camel/tests/folder/Makefile
+camel/tests/lib/Makefile
+camel/tests/message/Makefile
+camel/tests/mime-filter/Makefile
+camel/tests/misc/Makefile
+camel/tests/smime/Makefile
+camel/tests/stream/Makefile
data/Makefile
data/cde_app_root/Makefile
data/cde_app_root/dt/Makefile
@@ -1544,47 +1464,13 @@ composer/Makefile
mail/Makefile
mail/default/Makefile
mail/default/C/Makefile
-mail/default/zh_CN/Makefile
-mail/default/ja/Makefile
-mail/default/nl/Makefile
-mail/default/pt/Makefile
mail/importers/Makefile
-plugins/Makefile
-plugins/send-options/Makefile
-plugins/calendar-file/Makefile
-plugins/calendar-http/Makefile
-plugins/calendar-weather/Makefile
-plugins/plugin-manager/Makefile
-plugins/bbdb/Makefile
-plugins/audio-inline/Makefile
-plugins/mail-to-meeting/Makefile
-plugins/mail-to-task/Makefile
-plugins/new-mail-notify/Makefile
-plugins/subject-thread/Makefile
-plugins/save-attachments/Makefile
-plugins/save-calendar/Makefile
-plugins/select-one-source/Makefile
-plugins/mark-calendar-offline/Makefile
-plugins/prefer-plain/Makefile
-plugins/copy-tool/Makefile
-plugins/folder-unsubscribe/Makefile
-plugins/mailing-list-actions/Makefile
-plugins/itip-formatter/Makefile
-plugins/groupwise-account-setup/Makefile
-plugins/backup-restore/Makefile
-plugins/shared-folder/Makefile
-plugins/groupwise-send-options/Makefile
-plugins/exchange-account-setup/Makefile
-plugins/groupwise-status-tracking/Makefile
-plugins/default-source/Makefile
-plugins/addressbook-file/Makefile
-plugins/addressbook-groupwise/Makefile
smime/Makefile
smime/lib/Makefile
smime/gui/Makefile
tools/Makefile
evolution-shell.pc
-evolution-plugin.pc
+camel.pc
])
if test "x$with_sub_version" != "x"; then
@@ -1610,7 +1496,6 @@ echo "\
IPv6 support: $msg_ipv6
Dot Locking: $msg_dot
File Locking: $msg_file
- Plugins: $msg_plugins
Gtk-doc: $enable_gtk_doc"
if test x$enable_gtk_doc = xyes; then
diff --git a/doc/devel/executive-summary/evolution-services.hierarchy b/doc/devel/executive-summary/evolution-services.hierarchy
deleted file mode 100644
index 37559d819d..0000000000
--- a/doc/devel/executive-summary/evolution-services.hierarchy
+++ /dev/null
@@ -1,7 +0,0 @@
-GtkObject
- BonoboObject
- ExecutiveSummaryComponent
- ExecutiveSummaryComponentFactory
- Handle to remote Bonobo::Unknown
- ExecutiveSummaryComponentFactoryClient
- ExecutiveSummaryHtmlView
diff --git a/doc/devel/importer/evolution-shell-importer.hierarchy b/doc/devel/importer/evolution-shell-importer.hierarchy
deleted file mode 100644
index c46ebdf782..0000000000
--- a/doc/devel/importer/evolution-shell-importer.hierarchy
+++ /dev/null
@@ -1,7 +0,0 @@
-GtkObject
- BonoboObject
- BonoboXObject
- EvolutionImporter
- EvolutionImporterListener
- Handle to remote Bonobo::Unknown
- EvolutionImporterClient
diff --git a/e-util/ChangeLog b/e-util/ChangeLog
index f4a0eed16c..acc3064b10 100644
--- a/e-util/ChangeLog
+++ b/e-util/ChangeLog
@@ -1,197 +1,12 @@
-2005-02-14 Rodney Dawes <dobey@novell.com>
+2005-01-21 Not Zed <NotZed@Ximian.com>
- * e-menu.c (emph_construct): If the plug-in is not enabled, do nothing
-
-2005-02-07 Not Zed <NotZed@Ximian.com>
-
- * e-popup.c (emph_construct_menu):
- * e-menu.c (emph_construct_menu):
- * e-config.c (emph_construct_menu): Don't let the 'id' field,
- which identifies the target menu/whatever, to be NULL, otherwise
- it gets added to all.
-
-2005-02-04 Rodney Dawes <dobey@novell.com>
-
- * e-passwords.c (ep_ask_password): Set the border widths for the
- dialog containers to be HIG compliant
- Fix the padding/spacing on the internal vbox to be HIG compliant
-
-2005-01-27 Mengjie Yu <meng-jie.yu@sun.com>
-
- * e-request.c: (e_request_string):add a11y description for the
- entry.
-
-2005-01-26 Jeffrey Stedfast <fejj@novell.com>
-
- * e-config.c (ech_check): If the plugin isn't enabled, return TRUE
- so that the suer doesn't get locked in one of the account druid
- pages.
-
-2005-01-21 JP Rosevear <jpr@novell.com>
-
- Fixes #46404
-
- * Makefile.am: build new files
-
- * e-print.[hc]: print related config and dialog routines
-
-2005-01-17 Rodrigo Moya <rodrigo@novell.com>
-
- * e-url.[ch]:
- * Makefile.am: removed e-url.[ch], which are now in libedataserver.
+ * e-memory.c: 64 bit fixes.
2005-01-08 Not Zed <NotZed@Ximian.com>
* e-url.c (e_url_shroud): dont' use '%.*s' for truncating string
output.
-2005-01-09 JP Rosevear <jpr@novell.com>
-
- * e-url.c (e_uri_new): fix parsing of query string
-
-2005-01-07 Rodrigo Moya <rodrigo@novell.com>
-
- * e-categories-config.c (e_categories_config_open_dialog_for_entry):
- set the dialog's parent.
-
-2005-01-07 Rodrigo Moya <rodrigo@novell.com>
-
- * e-categories-config.c (e_categories_config_open_dialog_for_entry):
- use the new ECategoriesDialog in libedataserverui.
-
-2005-01-06 Rodney Dawes <dobey@novell.com>
-
- * e-config.c (e_config_create_window): Add the GTK_DIALOG_NOSEPARATOR
- flag, and set appropriate border widths around the main dialog vbox,
- and action area, to be more HIG compliant
-
-2005-01-06 JP Rosevear <jpr@novell.com>
-
- * e-error-tool.c (main): use the base name only, so if a full path
- is passed to us we still write out to the current directory, for
- when builddir != srcdir
-
-2005-01-04 Rodrigo Moya <rodrigo@novell.com>
-
- * e-categories-config.[ch]: removed most of the API. The rest will
- be removed as the GAL dependencies are sorted out.
-
-2004-12-22 Not Zed <NotZed@Ximian.com>
-
- * e-plugin.c: include config.h.
-
-2004-12-17 Not Zed <NotZed@Ximian.com>
-
- * e-popup.c (e_popup_add_items): add a translation domain to api.
- (e_popup_create_menu): translate the label using the supplied
- domain.
- (emph_popup_factory): pass domain to popup_add_items.
-
- * e-plugin.c (ep_construct): if we have a localedir set, then
- bindtextdomain so gettext can find it.
-
-2004-12-21 JP Rosevear <jpr@novell.com>
-
- Fixes #30992
-
- * e-config.c (e_config_create_window): use cancel rather than
- close button
-
-2004-12-21 JP Rosevear <jpr@novell.com>
-
- * e-account.c: convert to G_DEFINE_TYPE
-
- * e-account-list.c: ditto
-
-2004-12-08 Not Zed <NotZed@Ximian.com>
-
- * e-plugin.c (e_plugin_load_plugins): kill warning if we can't
- open the path.
-
-2004-12-06 Not Zed <NotZed@Ximian.com>
-
- * e-config.c (ec_rebuild): set the table spacings to 6 for
- generated tables.
-
-2004-11-22 Not Zed <NotZed@Ximian.com>
-
- * e-config.c (ec_rebuild): if the table existed before and we have
- no factory, destroy it always.
-
-2004-12-03 Not Zed <NotZed@Ximian.com>
-
- * e-config.c (ec_rebuild): revert the patch from chenthill, this
- wont work yet.
-
-2004-11-29 Mengjie Yu <meng-jie.yu@sun.com>
-
- * e-config.c: (ec_rebuild):add mnemonic for label.
- * e-passwords.c: (ep_ask_password):add description for password dialog.
-
-2004-11-26 JP Rosevear <jpr@novell.com>
-
- * e-gui-utils.c (e_create_image_widget): get the image directly
- from the icon factory
-
- * e-config.c: insert debug defines so we can
- turn spew on and off
-
- * e-event.c: insert debug defines so we can turn spew on and off
-
- * e-menu.c: insert debug defines so we can turn spew on and off
-
- * e-plugin.c: insert debug defines and set to off for now
-
- * e-popup.c: insert debug defines so we can turn spew on and off
- (e_popup_create_menu): get the image directly from the icon
- factory
-
-2004-11-26 JP Rosevear <jpr@novell.com>
-
- * e-icon-factory.h: add proto
-
- * e-icon-factory.c (e_icon_factory_init): cast to kill warning
- (e_icon_factory_get_image): new function to return a GtkImage
- widget give an icon name and size
-
-2004-11-25 Chenthill Palanisamy <pchenthill@novell.com>
-
- * e-config.c (ec_rebuild): Set the row and column spacings as
- tweleve while creating the table to make it HIG compliant.
-
-2004-11-19 Not Zed <NotZed@Ximian.com>
-
- * e-plugin.c (ep_load): if the plugin fails to load just disable
- it, don't unref it (it may be referenced elsewhere).
-
-2004-11-18 Not Zed <NotZed@Ximian.com>
-
- * e-plugin.c (epl_loadmodule): split out module loadng code.
- (epl_construct): if we're enabled, and load-on-startup is set,
- load the module right away. Not to be abused!
-
-2004-11-16 Not Zed <NotZed@Ximian.com>
-
- * e-host-utils.[ch]: removed, code moved into
- camel-net-utils.[ch].
-
-2004-11-15 Not Zed <NotZed@Ximian.com>
-
- * e-trie.[ch], e-memory.[ch], e-sexp.[ch], e-msgport.[ch]: Moved
- to eds/libedataserver.
-
- * e-path.[ch]: removed & deleted.
-
-2004-11-03 Not Zed <NotZed@Ximian.com>
-
- * e-plugin.c (e_plugin_list_plugins): added helper api to list all
- plugins.
- (ep_construct): load authors into new list for them.
- (e_plugin_register_type): setup disabled list.
- (ep_construct): dont load the hooks if we're not enabled.
- (e_plugin_enable): make this a virutal method.
- (e_plugin_invoke): if we're disabled, noop.
-
2004-11-01 Not Zed <NotZed@Ximian.com>
** See bug #68787
@@ -200,86 +15,12 @@
before dereferencing it.
* e-account.c (xml_set_prop): same here.
-2004-10-28 Not Zed <NotZed@Ximian.com>
-
- * e-config.c (ec_rebuild): revert the last change.
-
-2004-10-28 Not Zed <NotZed@Ximian.com>
-
- * e-config.c (ec_rebuild): set the default row/col spacings of the
- table.
-
-2004-10-20 Not Zed <NotZed@Ximian.com>
-
- * e-config.c (ec_rebuild): check for empty trailing sections/pages
- after we exit the main loop.
-
- * e-plugin.c (e_plugin_get_type): make ~/.eplugins the default
- eplugin location, not ~/.eplug.
-
-2004-10-18 Not Zed <NotZed@Ximian.com>
-
- * e-config.h: fix some forward decls.
-
-2004-10-19 JP Rosevear <jpr@novell.com>
-
- * e-config.c, e-event.c, e-menu.c, e-plugin.c, e-plugin.h,
- e-popup.c: convert to org.gnome hook names
-
2004-10-07 Jeffrey Stedfast <fejj@novell.com>
* e-passwords.c (ep_ask_password): Use "%s" as the formatter
argument and msg->prompt as a printf-style argument rather than
using it as the format string. Fixes bug #67622.
-2004-10-12 Not Zed <NotZed@Ximian.com>
-
- * e-config.c (ech_check, ech_config_factory, emph_construct_menu):
- setup a "check" handler, page-check/validation callback.
-
- * e-popup.c (e_popup_new): new method to create a targetless popup
- menu.
-
-2004-10-08 JP Rosevear <jpr@novell.com>
-
- * e-plugin.c (ep_load): fix typo
-
-2004-10-08 Not Zed <NotZed@Ximian.com>
-
- * e-plugin.c (ep_load): handle wrong root element properly. From
- David Trowbridge <David.Trowbridge@Colorado.edu>
-
-2004-10-07 Not Zed <NotZed@Ximian.com>
-
- * e-plugin.h: Fix the function pointer types!
-
- * e-plugin.c (epl_invoke): noop if we're disabled, and do some
- lifecycle stuff now, call e_plugin_lib_enable on the module if it
- exists.
-
-2004-10-07 Not Zed <NotZed@Ximian.com>
-
- * e-config.c (ec_rebuild): show the toplevel notebook if we
- had to create one, always.
-
- * e-menu.c (e_menu_add_items): initialise node->menu properly.
-
- * e-plugin.c (ep_load): read/initialise a unique id for all
- plugins and track them in a hashtable.
- (ep_construct): refactor so we have more control over what
- happens. if the hook handling class isn't registered yet, just
- note it and keep going.
- (e_plugin_hook_new): remove this, its handled internally by above.
-
-2004-10-06 Not Zed <NotZed@Ximian.com>
-
- * e-popup.c (e_popup_create_menu): only take one mask parameter,
- and implement EPopupItem->enable to do what the other mask did.
- (ep_activate): if this is a toggle or radiobutton, set the active
- state on the item->type.
- (e_popup_create_menu): if a menu image starts with gtk-, then
- assume it is a gtk stock image instead.
-
2004-08-27 Not Zed <NotZed@Ximian.com>
* e-passwords.c (e_passwords_ask_password): return cancelled if
@@ -298,7 +39,8 @@
2004-08-13 Rodrigo Moya <rodrigo@novell.com>
- * e-categories-config.c: include gtkdialog.h rather than gnome-dialog.h.
+ * e-categories-config.c: include gtkdialog.h rather than
+ gnome-dialog.h.
2004-08-12 Carlos Garnacho Parro <carlosg@gnome.org>
@@ -361,185 +103,6 @@
(d): turn off debugging
(expire_dir_rec): remove debug printfs
-2004-08-24 JP Rosevear <jpr@novell.com>
-
- * Makefile.am: define EVOLUTION_PLUGINDIR
-
- * e-plugin.c (e_plugin_get_type): add both a global and user
- specifc eplug path as defaults
- (e_plugin_load_plugins): just skip a directory if it can't be
- opened
-
-2004-09-10 Not Zed <NotZed@Ximian.com>
-
- * e-popup.c (emph_construct_menu): duh, setup the hook pointer.
-
- * e-menu.c (e_menu_add_items): pass pixmaps and ui files to this
- function now.
- (e_menu_add_pixmap): removed, covered by above.
- (e_menu_add_ui): removed, covered by above.
- (emph_construct_menu): setup the hook pointer properly.
-
- * e-menu.h: moved the pixmap and ui file structures to be public,
- removed hte hook equivalents.
-
-2004-09-09 Not Zed <NotZed@Ximian.com>
-
- * e-event.c (e_event_remove_items): implement a remove function.
- (e_event_add_items): return a handle to pass to above.
- (emph_event_handle): noop if we're disabled.
-
- * e-popup.c (emph_popup_factory): noop if the
- plugin is disabled.
-
- * e-plugin.c (ep_init): setup an enabled bit for the plugin.
- Preliminary work on being able to manage plugins.
- (e_plugin_hook_enable): set hook enable state.
- (e_plugin_enable): set plugin enable state.
-
-2004-09-07 Not Zed <NotZed@Ximian.com>
-
- * e-config.c (ec_rebuild): pass the right old widget to the page
- factory.
- (ec_widget_destroy): unref the config and the target when done.
- (e_config_create_widget): force the notebook to page 0, workaround
- some other bug i don't understand.
- (e_config_create_window): set dialog hint on druid.
-
-2004-09-06 Not Zed <NotZed@Ximian.com>
-
- * e-account.c (e_account_import): emit a changed event on the dest.
- (e_account_set_from_xml): emit a changed event if we were.
-
- * e-config.c (ec_rebuild): add a table item for some type-safety.
- remove/alter the asserts so the code attemps to fail gracefully
- rather than just fail.
-
-2004-09-01 Not Zed <NotZed@Ximian.com>
-
- * e-menu.[ch]:
- * e-popup.[ch]:
- * e-config.[ch]:
- * e-event.[ch]: API syncrhonisation. Item callbacks now get the
- root object, the item, and user-supplied data. Removed
- now-redundant data and structures. Documentation updates.
-
-2004-08-30 Not Zed <NotZed@Ximian.com>
-
- * e-popup.c (emph_construct_item): just build a popupitem
- directly, use user_data to pass the activate method name.
-
- * e-popup.h: removed epopuphookitem.
-
- * e-popup.c (emph_construct_item): dont set hook on hookitem
- anymore, dont need to set user_data either.
-
- * e-popup.h: no longer pass parent pointer in EPopupHookItem, its
- handled by add_items's data now.
-
- * e-popup.c (ep_finalise): re-arrange and call freefunc with the
- new args.
- (e_popup_create_menu): change the activate data so we can pass the
- new api arguments.
- (ep_activate): changes for api changes.
- (emph_popup_factory): no longer takes target arg, taken from the
- popup, pass the popuphook to the add_items call.
- (emph_popup_activate): changed for new argument types.
-
- * e-popup.h: removed popup from epopupitem.
-
- * e-popup.c (e_popup_add_static_items): make private/rename to
- ep_add_static_items.
- (ep_add_static_items): dont pass target, it is set on the epopup
- structure.
- (e_popup_add_items): change the freefunc to be an EPopupItemsFunc
- and add a user-data field, and track the parent epopup.
-
- * e-popup.h: change the activatefunc to pass the target and data
- supplied to add_items.
-
-2004-08-25 Not Zed <NotZed@Ximian.com>
-
- * e-config.c (e_config_new): removed, this shouldn't be here for
- an abstract class.
- (*): Added doco.
-
-2004-08-24 Not Zed <NotZed@Ximian.com>
-
- * e-config.c (emph_construct_item): translate the label text.
-
- * e-popup.c (emph_construct_item): translate the label text.
-
- * e-plugin.c (e_plugin_xml_prop_domain): helper to get a property
- translated.
- (ep_construct): translate the name and description based on the
- new domain tag. get the description as tag content not property.
- (e_plugin_xml_content_domain): similar for xml node content.
-
-2004-08-24 Not Zed <NotZed@Ximian.com>
-
- * e-account.c (init): setup some defaults for the account.
-
- * e-config.c (e_config_create_widget): remove target arg actually.
- (ec_rebuild): add druid page start/end pages. fixes.
- (ec_druid_finish, ec_druid_cancel): handle finishing the druid.
-
-2004-08-23 Not Zed <NotZed@Ximian.com>
-
- * e-config.c (ec_druid_prepare, ec_druid_prev, ec_druid_next):
- handle druid navigation.
-
-2004-08-20 Not Zed <NotZed@Ximian.com>
-
- * e-config.c (e_config_target_changed): add 'how' changed arg.
- (e_config_create_widget): dont take target anymore, set that
- separately.
- (e_config_set_target): new virtual method to set the target.
- (ec_set_target): implementation.
-
-2004-08-19 Not Zed <NotZed@Ximian.com>
-
- * e-account.c (e_account_set_bool): only emit changed if it did.
-
-2004-08-17 Not Zed <NotZed@Ximian.com>
-
- * e-config.c (e_config_page_check): fix a past-o.
- (e_config_target_changed): treat the returned page for a druid
- page factory as a gnomedruidpagestandard, so get_page works, etc.
-
-2004-08-16 Not Zed <NotZed@Ximian.com>
-
- * e-event.[ch]: Added event hook and dispatch router.
-
-2004-08-13 Not Zed <NotZed@Ximian.com>
-
- * e-plugin.c (e_plugin_load_plugins): don't take a path, load all
- paths set.
- (e_plugin_add_load_path): add a load path to the search path.
- (e_plugin_get_type): setup the initial load path from environment
- or defaults.
- (e_plugin_xml_int): helper to get a prop in int format.
-
-2004-08-11 Not Zed <NotZed@Ximian.com>
-
- * e-config.c (e_config_target_changed): handle DRUID root type.
-
-2004-08-05 Not Zed <NotZed@Ximian.com>
-
- * e-account.c (class_init): add a changed signal.
- (e_account_set_string, e_account_set_int, e_account_set_bool):
- emit changed signal if it did.
-
- * e-config.c (e_config_add_page_check): add a page verification
- function. It will be called for the given page, or all pages, to
- verify the page contains valid data.
-
-2004-07-29 Not Zed <NotZed@Ximian.com>
-
- * e-account.c (e_account_get_string, e_account_get_int)
- (e_account_get_bool, e_account_set_string, e_account_set_int)
- (e_account_set_bool): implement. completely table driven.
-
2004-07-02 Chris Toshok <toshok@ximian.com>
[ fixes #60691 ]
diff --git a/e-util/e-account.c b/e-util/e-account.c
index b919a56cc2..d8b21df446 100644
--- a/e-util/e-account.c
+++ b/e-util/e-account.c
@@ -18,7 +18,7 @@
*/
#ifdef HAVE_CONFIG_H
-#include <config.h>
+#include "config.h"
#endif
#include "e-account.h"
@@ -27,20 +27,15 @@
#include <string.h>
+#include <gal/util/e-util.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/xmlmemory.h>
#include <gconf/gconf-client.h>
-enum {
- CHANGED,
- LAST_SIGNAL
-};
-
-static guint signals[LAST_SIGNAL];
-
-G_DEFINE_TYPE (EAccount, e_account, G_TYPE_OBJECT)
+#define PARENT_TYPE G_TYPE_OBJECT
+static GObjectClass *parent_class = NULL;
/*
lock mail accounts Relatively difficult -- involves redesign of the XML blobs which describe accounts
@@ -77,37 +72,23 @@ set trash emptying frequency
** lock destination account/options
*/
-static void e_account_finalize (GObject *);
+static void finalize (GObject *);
static void
-e_account_class_init (EAccountClass *klass)
+class_init (GObjectClass *object_class)
{
- GObjectClass *object_class;
-
+ parent_class = g_type_class_ref (PARENT_TYPE);
+
/* virtual method override */
- object_class = G_OBJECT_CLASS (klass);
- object_class->finalize = e_account_finalize;
-
- signals[CHANGED] =
- g_signal_new("changed",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (EAccountClass, changed),
- NULL, NULL,
- g_cclosure_marshal_VOID__INT,
- G_TYPE_NONE, 1,
- G_TYPE_INT);
+ object_class->finalize = finalize;
}
static void
-e_account_init (EAccount *account)
+init (EAccount *account)
{
account->id = g_new0 (EAccountIdentity, 1);
account->source = g_new0 (EAccountService, 1);
account->transport = g_new0 (EAccountService, 1);
-
- account->source->auto_check = FALSE;
- account->source->auto_check_time = 10;
}
static void
@@ -137,7 +118,7 @@ service_destroy (EAccountService *service)
}
static void
-e_account_finalize (GObject *object)
+finalize (GObject *object)
{
EAccount *account = E_ACCOUNT (object);
@@ -158,9 +139,12 @@ e_account_finalize (GObject *object)
g_free (account->smime_sign_key);
g_free (account->smime_encrypt_key);
- G_OBJECT_CLASS (e_account_parent_class)->finalize (object);
+ G_OBJECT_CLASS (parent_class)->finalize (object);
}
+E_MAKE_TYPE (e_account, "EAccount", EAccount, class_init, init, PARENT_TYPE)
+
+
/**
* e_account_new:
*
@@ -437,11 +421,10 @@ e_account_set_from_xml (EAccount *account, const char *xml)
xmlFreeDoc (doc);
- g_signal_emit(account, signals[CHANGED], 0, -1);
-
return changed;
}
+
/**
* e_account_import:
* @dest: destination account object
@@ -507,10 +490,9 @@ e_account_import (EAccount *dest, EAccount *src)
dest->smime_encrypt_to_self = src->smime_encrypt_to_self;
g_free (dest->smime_encrypt_key);
dest->smime_encrypt_key = g_strdup (src->smime_encrypt_key);
-
- g_signal_emit(dest, signals[CHANGED], 0, -1);
}
+
/**
* e_account_to_xml:
* @account: an #EAccount
@@ -668,55 +650,44 @@ static struct _system_info {
{ "transport", 1<<EAP_LOCK_TRANSPORT },
};
-#define TYPE_STRING (1)
-#define TYPE_INT (2)
-#define TYPE_BOOL (3)
-#define TYPE_MASK (0xff)
-#define TYPE_STRUCT (1<<8)
-
-static struct _account_info {
+static struct {
guint32 perms;
- guint32 type;
- unsigned int offset;
- unsigned int struct_offset;
-} account_info[E_ACCOUNT_ITEM_LAST] = {
- { /* E_ACCOUNT_NAME */ 0, TYPE_STRING, G_STRUCT_OFFSET(EAccount, name) },
-
- { /* E_ACCOUNT_ID_NAME, */ 0, TYPE_STRING|TYPE_STRUCT, G_STRUCT_OFFSET(EAccount, id), G_STRUCT_OFFSET(EAccountIdentity, name) },
- { /* E_ACCOUNT_ID_ADDRESS, */ 0, TYPE_STRING|TYPE_STRUCT, G_STRUCT_OFFSET(EAccount, id), G_STRUCT_OFFSET(EAccountIdentity, address) },
- { /* E_ACCOUNT_ID_REPLY_TO, */ 0, TYPE_STRING|TYPE_STRUCT, G_STRUCT_OFFSET(EAccount, id), G_STRUCT_OFFSET(EAccountIdentity, reply_to) },
- { /* E_ACCOUNT_ID_ORGANIZATION */ 0, TYPE_STRING|TYPE_STRUCT, G_STRUCT_OFFSET(EAccount, id), G_STRUCT_OFFSET(EAccountIdentity, organization) },
- { /* E_ACCOUNT_ID_SIGNATURE */ 1<<EAP_LOCK_SIGNATURE, TYPE_STRING|TYPE_STRUCT, G_STRUCT_OFFSET(EAccount, id), G_STRUCT_OFFSET(EAccountIdentity, sig_uid) },
-
- { /* E_ACCOUNT_SOURCE_URL */ 1<<EAP_LOCK_SOURCE, TYPE_STRING|TYPE_STRUCT, G_STRUCT_OFFSET(EAccount, source), G_STRUCT_OFFSET(EAccountService, url) },
- { /* E_ACCOUNT_SOURCE_KEEP_ON_SERVER */ 0, TYPE_BOOL|TYPE_STRUCT, G_STRUCT_OFFSET(EAccount, source), G_STRUCT_OFFSET(EAccountService, keep_on_server) },
- { /* E_ACCOUNT_SOURCE_AUTO_CHECK */ 1<<EAP_LOCK_AUTOCHECK, TYPE_BOOL|TYPE_STRUCT, G_STRUCT_OFFSET(EAccount, source), G_STRUCT_OFFSET(EAccountService, auto_check) },
- { /* E_ACCOUNT_SOURCE_AUTO_CHECK_TIME */ 1<<EAP_LOCK_AUTOCHECK, TYPE_INT|TYPE_STRUCT, G_STRUCT_OFFSET(EAccount, source), G_STRUCT_OFFSET(EAccountService, auto_check_time) },
- { /* E_ACCOUNT_SOURCE_SAVE_PASSWD */ 1<<EAP_LOCK_SAVE_PASSWD, TYPE_BOOL|TYPE_STRUCT, G_STRUCT_OFFSET(EAccount, source), G_STRUCT_OFFSET(EAccountService, save_passwd) },
-
- { /* E_ACCOUNT_TRANSPORT_URL */ 1<<EAP_LOCK_TRANSPORT, TYPE_STRING|TYPE_STRUCT, G_STRUCT_OFFSET(EAccount, transport), G_STRUCT_OFFSET(EAccountService, url) },
- { /* E_ACCOUNT_TRANSPORT_SAVE_PASSWD */ 1<<EAP_LOCK_SAVE_PASSWD, TYPE_BOOL|TYPE_STRUCT, G_STRUCT_OFFSET(EAccount, transport), G_STRUCT_OFFSET(EAccountService, save_passwd) },
-
- { /* E_ACCOUNT_DRAFTS_FOLDER_URI */ 1<<EAP_LOCK_DEFAULT_FOLDERS, TYPE_STRING, G_STRUCT_OFFSET(EAccount, drafts_folder_uri) },
- { /* E_ACCOUNT_SENT_FOLDER_URI */ 1<<EAP_LOCK_DEFAULT_FOLDERS, TYPE_STRING, G_STRUCT_OFFSET(EAccount, sent_folder_uri) },
-
- { /* E_ACCOUNT_CC_ALWAYS */ 0, TYPE_BOOL, G_STRUCT_OFFSET(EAccount, always_cc) },
- { /* E_ACCOUNT_CC_ADDRS */ 0, TYPE_STRING, G_STRUCT_OFFSET(EAccount, cc_addrs) },
-
- { /* E_ACCOUNT_BCC_ALWAYS */ 0, TYPE_BOOL, G_STRUCT_OFFSET(EAccount, always_bcc) },
- { /* E_ACCOUNT_BCC_ADDRS */ 0, TYPE_STRING, G_STRUCT_OFFSET(EAccount, bcc_addrs) },
-
- { /* E_ACCOUNT_PGP_KEY */ 0, TYPE_STRING, G_STRUCT_OFFSET(EAccount, pgp_key) },
- { /* E_ACCOUNT_PGP_ENCRYPT_TO_SELF */ 0, TYPE_BOOL, G_STRUCT_OFFSET(EAccount, pgp_encrypt_to_self) },
- { /* E_ACCOUNT_PGP_ALWAYS_SIGN */ 0, TYPE_BOOL, G_STRUCT_OFFSET(EAccount, pgp_always_sign) },
- { /* E_ACCOUNT_PGP_NO_IMIP_SIGN */ 0, TYPE_BOOL, G_STRUCT_OFFSET(EAccount, pgp_no_imip_sign) },
- { /* E_ACCOUNT_PGP_ALWAYS_TRUST */ 0, TYPE_BOOL, G_STRUCT_OFFSET(EAccount, pgp_always_trust) },
-
- { /* E_ACCOUNT_SMIME_SIGN_KEY */ 0, TYPE_STRING, G_STRUCT_OFFSET(EAccount, smime_sign_key) },
- { /* E_ACCOUNT_SMIME_ENCRYPT_KEY */ 0, TYPE_STRING, G_STRUCT_OFFSET(EAccount, smime_encrypt_key) },
- { /* E_ACCOUNT_SMIME_SIGN_DEFAULT */ 0, TYPE_BOOL, G_STRUCT_OFFSET(EAccount, smime_sign_default) },
- { /* E_ACCOUNT_SMIME_ENCRYPT_TO_SELF */ 0, TYPE_BOOL, G_STRUCT_OFFSET(EAccount, smime_encrypt_to_self) },
- { /* E_ACCOUNT_SMIME_ENCRYPT_DEFAULT */ 0, TYPE_BOOL, G_STRUCT_OFFSET(EAccount, smime_encrypt_default) },
+} account_perms[E_ACCOUNT_ITEM_LAST] = {
+ { /* E_ACCOUNT_ID_NAME, */ },
+ { /* E_ACCOUNT_ID_ADDRESS, */ },
+ { /* E_ACCOUNT_ID_REPLY_TO, */ },
+ { /* E_ACCOUNT_ID_ORGANIZATION */ },
+ { /* E_ACCOUNT_ID_SIGNATURE */ 1<<EAP_LOCK_SIGNATURE },
+
+ { /* E_ACCOUNT_SOURCE_URL */ 1<<EAP_LOCK_SOURCE },
+ { /* E_ACCOUNT_SOURCE_KEEP_ON_SERVER */ },
+ { /* E_ACCOUNT_SOURCE_AUTO_CHECK */ 1<<EAP_LOCK_AUTOCHECK },
+ { /* E_ACCOUNT_SOURCE_AUTO_CHECK_TIME */ 1<<EAP_LOCK_AUTOCHECK },
+ { /* E_ACCOUNT_SOURCE_SAVE_PASSWD */ 1<<EAP_LOCK_SAVE_PASSWD },
+
+ { /* E_ACCOUNT_TRANSPORT_URL */ 1<<EAP_LOCK_TRANSPORT },
+ { /* E_ACCOUNT_TRANSPORT_SAVE_PASSWD */ 1<<EAP_LOCK_SAVE_PASSWD },
+
+ { /* E_ACCOUNT_DRAFTS_FOLDER_URI */ 1<<EAP_LOCK_DEFAULT_FOLDERS },
+ { /* E_ACCOUNT_SENT_FOLDER_URI */ 1<<EAP_LOCK_DEFAULT_FOLDERS },
+
+ { /* E_ACCOUNT_CC_ALWAYS */ },
+ { /* E_ACCOUNT_CC_ADDRS */ },
+
+ { /* E_ACCOUNT_BCC_ALWAYS */ },
+ { /* E_ACCOUNT_BCC_ADDRS */ },
+
+ { /* E_ACCOUNT_PGP_KEY */ },
+ { /* E_ACCOUNT_PGP_ENCRYPT_TO_SELF */ },
+ { /* E_ACCOUNT_PGP_ALWAYS_SIGN */ },
+ { /* E_ACCOUNT_PGP_NO_IMIP_SIGN */ },
+ { /* E_ACCOUNT_PGP_ALWAYS_TRUST */ },
+
+ { /* E_ACCOUNT_SMIME_SIGN_KEY */ },
+ { /* E_ACCOUNT_SMIME_ENCRYPT_KEY */ },
+ { /* E_ACCOUNT_SMIME_SIGN_DEFAULT */ },
+ { /* E_ACCOUNT_SMIME_ENCRYPT_TO_SELF */ },
+ { /* E_ACCOUNT_SMIME_ENCRYPE_DEFAULT */ },
};
static GHashTable *ea_option_table;
@@ -799,89 +770,6 @@ ea_setting_setup(void)
g_object_unref(gconf);
}
-/* look up the item in the structure or the substructure using our table of reflection data */
-#define addr(ea, type) \
- ((account_info[type].type & TYPE_STRUCT)? \
- (((char **)(((char *)ea)+account_info[type].offset))[0] + account_info[type].struct_offset): \
- (((char *)ea)+account_info[type].offset))
-
-const char *e_account_get_string(EAccount *ea, e_account_item_t type)
-{
- return *((const char **)addr(ea, type));
-}
-
-int e_account_get_int(EAccount *ea, e_account_item_t type)
-{
- return *((int *)addr(ea, type));
-}
-
-gboolean e_account_get_bool(EAccount *ea, e_account_item_t type)
-{
- return *((gboolean *)addr(ea, type));
-}
-
-static void
-dump_account(EAccount *ea)
-{
- char *xml;
-
- printf("Account changed\n");
- xml = e_account_to_xml(ea);
- printf(" ->\n%s\n", xml);
- g_free(xml);
-}
-
-/* TODO: should it return true if it changed? */
-void e_account_set_string(EAccount *ea, e_account_item_t type, const char *val)
-{
- char **p;
-
- if (!e_account_writable(ea, type)) {
- g_warning("Trying to set non-writable option account value");
- } else {
- p = (char **)addr(ea, type);
- printf("Setting string %d: old '%s' new '%s'\n", type, *p, val);
- if (*p != val
- && (*p == NULL || val == NULL || strcmp(*p, val) != 0)) {
- g_free(*p);
- *p = g_strdup(val);
-
- dump_account(ea);
- g_signal_emit(ea, signals[CHANGED], 0, type);
- }
- }
-}
-
-void e_account_set_int(EAccount *ea, e_account_item_t type, int val)
-{
- if (!e_account_writable(ea, type)) {
- g_warning("Trying to set non-writable option account value");
- } else {
- int *p = (int *)addr(ea, type);
-
- if (*p != val) {
- *p = val;
- dump_account(ea);
- g_signal_emit(ea, signals[CHANGED], 0, type);
- }
- }
-}
-
-void e_account_set_bool(EAccount *ea, e_account_item_t type, gboolean val)
-{
- if (!e_account_writable(ea, type)) {
- g_warning("Trying to set non-writable option account value");
- } else {
- gboolean *p = (gboolean *)addr(ea, type);
-
- if (*p != val) {
- *p = val;
- dump_account(ea);
- g_signal_emit(ea, signals[CHANGED], 0, type);
- }
- }
-}
-
gboolean
e_account_writable_option(EAccount *ea, const char *protocol, const char *option)
{
@@ -910,5 +798,5 @@ e_account_writable(EAccount *ea, e_account_item_t type)
{
ea_setting_setup();
- return (account_info[type].perms & ea_perms) == 0;
+ return (account_perms[type].perms & ea_perms) == 0;
}
diff --git a/e-util/e-bit-array.c b/e-util/e-bit-array.c
deleted file mode 100644
index bb98a3f465..0000000000
--- a/e-util/e-bit-array.c
+++ /dev/null
@@ -1,429 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-bit-array.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <gtk/gtksignal.h>
-#include "e-bit-array.h"
-#include "gal/util/e-util.h"
-
-#define PARENT_TYPE G_TYPE_OBJECT
-
-#define ONES ((guint32) 0xffffffff)
-
-#define BOX(n) ((n) / 32)
-#define OFFSET(n) (31 - ((n) % 32))
-#define BITMASK(n) ((guint32)(((guint32) 0x1) << OFFSET((n))))
-#define BITMASK_LEFT(n) ((((n) % 32) == 0) ? 0 : (ONES << (32 - ((n) % 32))))
-#define BITMASK_RIGHT(n) ((guint32)(((guint32) ONES) >> ((n) % 32)))
-
-static GObjectClass *parent_class;
-
-static void
-e_bit_array_insert_real(EBitArray *eba, int row)
-{
- int box;
- int i;
- if(eba->bit_count >= 0) {
- /* Add another word if needed. */
- if ((eba->bit_count & 0x1f) == 0) {
- eba->data = g_renew(guint32, eba->data, (eba->bit_count >> 5) + 1);
- eba->data[eba->bit_count >> 5] = 0;
- }
-
- /* The box is the word that our row is in. */
- box = BOX(row);
- /* Shift all words to the right of our box right one bit. */
- for (i = eba->bit_count >> 5; i > box; i--) {
- eba->data[i] = (eba->data[i] >> 1) | (eba->data[i - 1] << 31);
- }
-
- /* Shift right half of box one bit to the right. */
- eba->data[box] = (eba->data[box] & BITMASK_LEFT(row)) | ((eba->data[box] & BITMASK_RIGHT(row)) >> 1);
- eba->bit_count ++;
- }
-}
-
-static void
-e_bit_array_delete_real(EBitArray *eba, int row, gboolean move_selection_mode)
-{
- int box;
- int i;
- int last;
- int selected = FALSE;
- if(eba->bit_count >= 0) {
- guint32 bitmask;
- box = row >> 5;
- last = eba->bit_count >> 5;
-
- /* Build bitmasks for the left and right half of the box */
- bitmask = BITMASK_RIGHT(row) >> 1;
- if (move_selection_mode)
- selected = e_bit_array_value_at(eba, row);
- /* Shift right half of box one bit to the left. */
- eba->data[box] = (eba->data[box] & BITMASK_LEFT(row))| ((eba->data[box] & bitmask) << 1);
-
- /* Shift all words to the right of our box left one bit. */
- if (box < last) {
- eba->data[box] &= eba->data[box + 1] >> 31;
-
- for (i = box + 1; i < last; i++) {
- eba->data[i] = (eba->data[i] << 1) | (eba->data[i + 1] >> 31);
- }
- /* this over-runs our memory! */
- /*eba->data[i] = eba->data[i] << 1; */
- }
- eba->bit_count --;
- /* Remove the last word if not needed. */
- if ((eba->bit_count & 0x1f) == 0) {
- eba->data = g_renew(guint32, eba->data, eba->bit_count >> 5);
- }
- if (move_selection_mode && selected && eba->bit_count > 0) {
- e_bit_array_select_single_row (eba, row == eba->bit_count ? row - 1 : row);
- }
- }
-}
-
-/* FIXME : Improve efficiency here. */
-void
-e_bit_array_delete(EBitArray *eba, int row, int count)
-{
- int i;
- for (i = 0; i < count; i++)
- e_bit_array_delete_real(eba, row, FALSE);
-}
-
-/* FIXME : Improve efficiency here. */
-void
-e_bit_array_delete_single_mode(EBitArray *eba, int row, int count)
-{
- int i;
- for (i = 0; i < count; i++)
- e_bit_array_delete_real(eba, row, TRUE);
-}
-
-/* FIXME : Improve efficiency here. */
-void
-e_bit_array_insert(EBitArray *eba, int row, int count)
-{
- int i;
- for (i = 0; i < count; i++)
- e_bit_array_insert_real(eba, row);
-}
-
-/* FIXME: Implement this more efficiently. */
-void
-e_bit_array_move_row(EBitArray *eba, int old_row, int new_row)
-{
- e_bit_array_delete_real(eba, old_row, FALSE);
- e_bit_array_insert_real(eba, new_row);
-}
-
-static void
-eba_dispose (GObject *object)
-{
- EBitArray *eba;
-
- eba = E_BIT_ARRAY (object);
-
- if (eba->data)
- g_free(eba->data);
- eba->data = NULL;
-
- if (G_OBJECT_CLASS (parent_class)->dispose)
- (* G_OBJECT_CLASS (parent_class)->dispose) (object);
-}
-
-/**
- * e_selection_model_is_row_selected
- * @selection: #EBitArray to check
- * @n: The row to check
- *
- * This routine calculates whether the given row is selected.
- *
- * Returns: %TRUE if the given row is selected
- */
-gboolean
-e_bit_array_value_at (EBitArray *eba,
- gint n)
-{
- if (eba->bit_count < n || eba->bit_count == 0)
- return 0;
- else
- return (eba->data[BOX(n)] >> OFFSET(n)) & 0x1;
-}
-
-/**
- * e_selection_model_foreach
- * @selection: #EBitArray to traverse
- * @callback: The callback function to call back.
- * @closure: The closure
- *
- * This routine calls the given callback function once for each
- * selected row, passing closure as the closure.
- */
-void
-e_bit_array_foreach (EBitArray *eba,
- EForeachFunc callback,
- gpointer closure)
-{
- int i;
- int last = (eba->bit_count + 31) / 32;
- for (i = 0; i < last; i++) {
- if (eba->data[i]) {
- int j;
- guint32 value = eba->data[i];
- for (j = 0; j < 32; j++) {
- if (value & 0x80000000) {
- callback(i * 32 + j, closure);
- }
- value <<= 1;
- }
- }
- }
-}
-
-/**
- * e_selection_model_clear
- * @selection: #EBitArray to clear
- *
- * This routine clears the selection to no rows selected.
- */
-void
-e_bit_array_clear(EBitArray *eba)
-{
- g_free(eba->data);
- eba->data = NULL;
- eba->bit_count = 0;
-}
-
-#define PART(x,n) (((x) & (0x01010101 << n)) >> n)
-#define SECTION(x, n) (((x) >> (n * 8)) & 0xff)
-
-/**
- * e_selection_model_selected_count
- * @selection: #EBitArray to count
- *
- * This routine calculates the number of rows selected.
- *
- * Returns: The number of rows selected in the given model.
- */
-gint
-e_bit_array_selected_count (EBitArray *eba)
-{
- gint count;
- int i;
- int last;
-
- if (!eba->data)
- return 0;
-
- count = 0;
-
- last = BOX(eba->bit_count - 1);
-
- for (i = 0; i <= last; i++) {
- int j;
- guint32 thiscount = 0;
- for (j = 0; j < 8; j++)
- thiscount += PART(eba->data[i], j);
- for (j = 0; j < 4; j++)
- count += SECTION(thiscount, j);
- }
-
- return count;
-}
-
-/**
- * e_selection_model_select_all
- * @selection: #EBitArray to select all
- *
- * This routine selects all the rows in the given
- * #EBitArray.
- */
-void
-e_bit_array_select_all (EBitArray *eba)
-{
- int i;
-
- if (!eba->data)
- eba->data = g_new0 (guint32, (eba->bit_count + 31) / 32);
-
- for (i = 0; i < (eba->bit_count + 31) / 32; i ++) {
- eba->data[i] = ONES;
- }
-
- /* need to zero out the bits corresponding to the rows not
- selected in the last full 32 bit mask */
- if (eba->bit_count % 32) {
- int unselected_mask = 0;
- int num_unselected_in_last_byte = 32 - eba->bit_count % 32;
-
- for (i = 0; i < num_unselected_in_last_byte; i ++)
- unselected_mask |= 1 << i;
-
- eba->data[(eba->bit_count + 31) / 32 - 1] &= ~unselected_mask;
- }
-}
-
-/**
- * e_selection_model_invert_selection
- * @selection: #EBitArray to invert
- *
- * This routine inverts all the rows in the given
- * #EBitArray.
- */
-void
-e_bit_array_invert_selection (EBitArray *eba)
-{
- int i;
-
- if (!eba->data)
- eba->data = g_new0 (guint32, (eba->bit_count + 31) / 32);
-
- for (i = 0; i < (eba->bit_count + 31) / 32; i ++) {
- eba->data[i] = ~eba->data[i];
- }
-}
-
-int
-e_bit_array_bit_count (EBitArray *eba)
-{
- return eba->bit_count;
-}
-
-gboolean
-e_bit_array_cross_and (EBitArray *eba)
-{
- int i;
- for (i = 0; i < eba->bit_count / 32; i++) {
- if (eba->data[i] != ONES)
- return FALSE;
- }
- if ((eba->bit_count % 32) && ((eba->data[i] & BITMASK_LEFT(eba->bit_count)) != BITMASK_LEFT(eba->bit_count)))
- return FALSE;
- return TRUE;
-}
-
-gboolean
-e_bit_array_cross_or (EBitArray *eba)
-{
- int i;
- for (i = 0; i < eba->bit_count / 32; i++) {
- if (eba->data[i] != 0)
- return TRUE;
- }
- if ((eba->bit_count % 32) && ((eba->data[i] & BITMASK_LEFT(eba->bit_count)) != 0))
- return TRUE;
- return FALSE;
-}
-
-#define OPERATE(object, i,mask,grow) ((grow) ? (((object)->data[(i)]) |= ((guint32) ~(mask))) : (((object)->data[(i)]) &= (mask)))
-
-void
-e_bit_array_change_one_row(EBitArray *eba, int row, gboolean grow)
-{
- int i;
- i = BOX(row);
-
- OPERATE(eba, i, ~BITMASK(row), grow);
-}
-
-void
-e_bit_array_change_range(EBitArray *eba, int start, int end, gboolean grow)
-{
- int i, last;
- if (start != end) {
- i = BOX(start);
- last = BOX(end);
-
- if (i == last) {
- OPERATE(eba, i, BITMASK_LEFT(start) | BITMASK_RIGHT(end), grow);
- } else {
- OPERATE(eba, i, BITMASK_LEFT(start), grow);
- if (grow)
- for (i ++; i < last; i++)
- eba->data[i] = ONES;
- else
- for (i ++; i < last; i++)
- eba->data[i] = 0;
- OPERATE(eba, i, BITMASK_RIGHT(end), grow);
- }
- }
-}
-
-void
-e_bit_array_select_single_row (EBitArray *eba, int row)
-{
- int i;
- for (i = 0; i < ((eba->bit_count + 31) / 32); i++) {
- if (!((i == BOX(row) && eba->data[i] == BITMASK(row)) ||
- (i != BOX(row) && eba->data[i] == 0))) {
- g_free(eba->data);
- eba->data = g_new0(guint32, (eba->bit_count + 31) / 32);
- eba->data[BOX(row)] = BITMASK(row);
-
- break;
- }
- }
-}
-
-void
-e_bit_array_toggle_single_row (EBitArray *eba, int row)
-{
- if (eba->data[BOX(row)] & BITMASK(row))
- eba->data[BOX(row)] &= ~BITMASK(row);
- else
- eba->data[BOX(row)] |= BITMASK(row);
-}
-
-
-static void
-e_bit_array_init (EBitArray *eba)
-{
- eba->data = NULL;
- eba->bit_count = 0;
-}
-
-static void
-e_bit_array_class_init (EBitArrayClass *klass)
-{
- GObjectClass *object_class;
-
- parent_class = g_type_class_ref (PARENT_TYPE);
-
- object_class = G_OBJECT_CLASS(klass);
-
- object_class->dispose = eba_dispose;
-}
-
-E_MAKE_TYPE(e_bit_array, "EBitArray", EBitArray,
- e_bit_array_class_init, e_bit_array_init, PARENT_TYPE)
-
-EBitArray *
-e_bit_array_new (int count)
-{
- EBitArray *eba = g_object_new (E_BIT_ARRAY_TYPE, NULL);
- eba->bit_count = count;
- eba->data = g_new0(guint32, (eba->bit_count + 31) / 32);
- return eba;
-}
diff --git a/e-util/e-bit-array.h b/e-util/e-bit-array.h
deleted file mode 100644
index ebfe644da6..0000000000
--- a/e-util/e-bit-array.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-bit-array.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_BIT_ARRAY_H_
-#define _E_BIT_ARRAY_H_
-
-#include <glib-object.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-#define E_BIT_ARRAY_TYPE (e_bit_array_get_type ())
-#define E_BIT_ARRAY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_BIT_ARRAY_TYPE, EBitArray))
-#define E_BIT_ARRAY_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_BIT_ARRAY_TYPE, EBitArrayClass))
-#define E_IS_BIT_ARRAY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_BIT_ARRAY_TYPE))
-#define E_IS_BIT_ARRAY_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_BIT_ARRAY_TYPE))
-
-#ifndef _E_FOREACH_FUNC_H_
-#define _E_FOREACH_FUNC_H_
-typedef void (*EForeachFunc) (int model_row,
- gpointer closure);
-#endif
-
-typedef struct {
- GObject base;
-
- gint bit_count;
- guint32 *data;
-} EBitArray;
-
-typedef struct {
- GObjectClass parent_class;
-} EBitArrayClass;
-
-
-GType e_bit_array_get_type (void);
-EBitArray *e_bit_array_new (int count);
-
-gboolean e_bit_array_value_at (EBitArray *selection,
- gint n);
-void e_bit_array_foreach (EBitArray *selection,
- EForeachFunc callback,
- gpointer closure);
-void e_bit_array_clear (EBitArray *selection);
-gint e_bit_array_selected_count (EBitArray *selection);
-void e_bit_array_select_all (EBitArray *selection);
-void e_bit_array_invert_selection (EBitArray *selection);
-int e_bit_array_bit_count (EBitArray *selection);
-void e_bit_array_change_one_row (EBitArray *selection,
- int row,
- gboolean grow);
-void e_bit_array_change_range (EBitArray *selection,
- int start,
- int end,
- gboolean grow);
-void e_bit_array_select_single_row (EBitArray *eba,
- int row);
-void e_bit_array_toggle_single_row (EBitArray *eba,
- int row);
-
-void e_bit_array_insert (EBitArray *esm,
- int row,
- int count);
-void e_bit_array_delete (EBitArray *esm,
- int row,
- int count);
-void e_bit_array_delete_single_mode (EBitArray *esm,
- int row,
- int count);
-void e_bit_array_move_row (EBitArray *esm,
- int old_row,
- int new_row);
-gint e_bit_array_bit_count (EBitArray *esm);
-
-gboolean e_bit_array_cross_and (EBitArray *esm);
-gboolean e_bit_array_cross_or (EBitArray *esm);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-
-#endif /* _E_BIT_ARRAY_H_ */
diff --git a/e-util/e-i18n.h b/e-util/e-i18n.h
deleted file mode 100644
index 829b2480aa..0000000000
--- a/e-util/e-i18n.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-i18n.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * Copied from gnome-i18nP.h, because this header is typically not installed
- *
- * This file has to be included before any file from the GNOME libraries
- * to have this override the definitions that are pulled from the gnome-i18n.h
- *
- * the difference is that gnome-i18n.h is used for applications, and this is
- * used by libraries (because libraries have to use dcgettext instead of
- * gettext and they need to provide the translation domain, unlike apps).
- *
- * So you can just put this after you include config.h
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef __E_I18N_H__
-#define __E_I18N_H__
-
-#include <libgnome/gnome-i18n.h>
-
-G_BEGIN_DECLS
-
-#ifdef ENABLE_NLS
- /* this function is defined in e-util.c */
- extern char *e_gettext (const char *msgid);
-# undef _
-# ifdef GNOME_EXPLICIT_TRANSLATION_DOMAIN
-/* No parentheses allowed here since that breaks string concatenation. */
-# define E_I18N_DOMAIN GNOME_EXPLICIT_TRANSLATION_DOMAIN
-# else
-/* No parentheses allowed here since that breaks string concatenation. */
-# define E_I18N_DOMAIN PACKAGE
-# endif
-# define _(String) e_gettext (String)
-# ifdef gettext_noop
-# define N_(String) gettext_noop (String)
-# else
-# define N_(String) (String)
-# endif
-#else
-/* Stubs that do something close enough. */
-# define textdomain(String) (String)
-# define gettext(String) (String)
-# define dgettext(Domain,Message) (Message)
-# define dcgettext(Domain,Message,Type) (Message)
-# define bindtextdomain(Domain,Directory) (Domain)
-# define _(String) (String)
-# define N_(String) (String)
-/* No parentheses allowed here since that breaks string concatenation. */
-# define E_I18N_DOMAIN ""
-#endif
-
-G_END_DECLS
-
-#endif /* __E_I18N_H__ */
diff --git a/e-util/e-iconv.c b/e-util/e-iconv.c
deleted file mode 100644
index 3236521438..0000000000
--- a/e-util/e-iconv.c
+++ /dev/null
@@ -1,614 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-iconv.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Michael Zucchi <notzed@ximian.com>
- * Jeffery Stedfast <fejj@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-
-#include <glib.h>
-#include "e-iconv.h"
-
-#include <locale.h>
-
-#ifdef HAVE_CODESET
-#include <langinfo.h>
-#endif
-
-#include "iconv-detect.h"
-
-#define cd(x)
-
-#ifdef G_THREADS_ENABLED
-static GStaticMutex lock = G_STATIC_MUTEX_INIT;
-#define LOCK() g_static_mutex_lock(&lock)
-#define UNLOCK() g_static_mutex_unlock(&lock)
-#else
-#define LOCK()
-#define UNLOCK()
-#endif
-
-typedef struct _EDListNode {
- struct _EDListNode *next;
- struct _EDListNode *prev;
-} EDListNode;
-
-typedef struct _EDList {
- struct _EDListNode *head;
- struct _EDListNode *tail;
- struct _EDListNode *tailpred;
-} EDList;
-
-#define E_DLIST_INITIALISER(l) { (EDListNode *)&l.tail, 0, (EDListNode *)&l.head }
-
-struct _iconv_cache_node {
- struct _iconv_cache_node *next;
- struct _iconv_cache_node *prev;
-
- struct _iconv_cache *parent;
-
- int busy;
- iconv_t ip;
-};
-
-struct _iconv_cache {
- struct _iconv_cache *next;
- struct _iconv_cache *prev;
-
- char *conv;
-
- EDList open; /* stores iconv_cache_nodes, busy ones up front */
-};
-
-#define E_ICONV_CACHE_SIZE (16)
-
-static EDList iconv_cache_list;
-static GHashTable *iconv_cache;
-static GHashTable *iconv_cache_open;
-static unsigned int iconv_cache_size = 0;
-
-static GHashTable *iconv_charsets = NULL;
-static char *locale_charset = NULL;
-static char *locale_lang = NULL;
-
-struct {
- char *charset;
- char *iconv_name;
-} known_iconv_charsets[] = {
-#if 0
- /* charset name, iconv-friendly charset name */
- { "iso-8859-1", "iso-8859-1" },
- { "iso8859-1", "iso-8859-1" },
- /* the above mostly serves as an example for iso-style charsets,
- but we have code that will populate the iso-*'s if/when they
- show up in e_iconv_charset_name() so I'm
- not going to bother putting them all in here... */
- { "windows-cp1251", "cp1251" },
- { "windows-1251", "cp1251" },
- { "cp1251", "cp1251" },
- /* the above mostly serves as an example for windows-style
- charsets, but we have code that will parse and convert them
- to their cp#### equivalents if/when they show up in
- e_iconv_charset_name() so I'm not going to bother
- putting them all in here either... */
-#endif
- /* charset name (lowercase!), iconv-friendly name (sometimes case sensitive) */
- { "utf-8", "UTF-8" },
-
- /* 10646 is a special case, its usually UCS-2 big endian */
- /* This might need some checking but should be ok for solaris/linux */
- { "iso-10646-1", "UCS-2BE" },
- { "iso_10646-1", "UCS-2BE" },
- { "iso10646-1", "UCS-2BE" },
- { "iso-10646", "UCS-2BE" },
- { "iso_10646", "UCS-2BE" },
- { "iso10646", "UCS-2BE" },
-
- { "ks_c_5601-1987", "EUC-KR" },
-
- /* FIXME: Japanese/Korean/Chinese stuff needs checking */
- { "euckr-0", "EUC-KR" },
- { "5601", "EUC-KR" },
- { "zh_TW-euc", "EUC-TW" },
- { "zh_CN.euc", "gb2312" },
- { "zh_TW-big5", "BIG5" },
- { "euc-cn", "gb2312" },
- { "big5-0", "BIG5" },
- { "big5.eten-0", "BIG5" },
- { "big5hkscs-0", "BIG5HKSCS" },
- { "gb2312-0", "gb2312" },
- { "gb2312.1980-0", "gb2312" },
- { "gb-2312", "gb2312" },
- { "gb18030-0", "gb18030" },
- { "gbk-0", "GBK" },
-
- { "eucjp-0", "eucJP" },
- { "ujis-0", "ujis" },
- { "jisx0208.1983-0","SJIS" },
- { "jisx0212.1990-0","SJIS" },
- { "pck", "SJIS" },
- { NULL, NULL }
-};
-
-
-
-/* Another copy of this trivial list implementation
- Why? This stuff gets called a lot (potentially), should run fast,
- and g_list's are f@@#$ed up to make this a hassle */
-static void e_dlist_init(EDList *v)
-{
- v->head = (EDListNode *)&v->tail;
- v->tail = 0;
- v->tailpred = (EDListNode *)&v->head;
-}
-
-static EDListNode *e_dlist_addhead(EDList *l, EDListNode *n)
-{
- n->next = l->head;
- n->prev = (EDListNode *)&l->head;
- l->head->prev = n;
- l->head = n;
- return n;
-}
-
-static EDListNode *e_dlist_addtail(EDList *l, EDListNode *n)
-{
- n->next = (EDListNode *)&l->tail;
- n->prev = l->tailpred;
- l->tailpred->next = n;
- l->tailpred = n;
- return n;
-}
-
-static EDListNode *e_dlist_remove(EDListNode *n)
-{
- n->next->prev = n->prev;
- n->prev->next = n->next;
- return n;
-}
-
-
-/* fucking glib... */
-static const char *
-e_strdown (char *str)
-{
- register char *s = str;
-
- while (*s) {
- if (*s >= 'A' && *s <= 'Z')
- *s += 0x20;
- s++;
- }
-
- return str;
-}
-
-static const char *
-e_strup (char *str)
-{
- register char *s = str;
-
- while (*s) {
- if (*s >= 'a' && *s <= 'z')
- *s -= 0x20;
- s++;
- }
-
- return str;
-}
-
-
-static void
-locale_parse_lang (const char *locale)
-{
- char *codeset, *lang;
-
- if ((codeset = strchr (locale, '.')))
- lang = g_strndup (locale, codeset - locale);
- else
- lang = g_strdup (locale);
-
- /* validate the language */
- if (strlen (lang) >= 2) {
- if (lang[2] == '-' || lang[2] == '_') {
- /* canonicalise the lang */
- e_strdown (lang);
-
- /* validate the country code */
- if (strlen (lang + 3) > 2) {
- /* invalid country code */
- lang[2] = '\0';
- } else {
- lang[2] = '-';
- e_strup (lang + 3);
- }
- } else if (lang[2] != '\0') {
- /* invalid language */
- g_free (lang);
- lang = NULL;
- }
-
- locale_lang = lang;
- } else {
- /* invalid language */
- locale_lang = NULL;
- g_free (lang);
- }
-}
-
-/* NOTE: Owns the lock on return if keep is TRUE ! */
-static void
-e_iconv_init(int keep)
-{
- char *from, *to, *locale;
- int i;
-
- LOCK();
-
- if (iconv_charsets != NULL) {
- if (!keep)
- UNLOCK();
- return;
- }
-
- iconv_charsets = g_hash_table_new(g_str_hash, g_str_equal);
-
- for (i = 0; known_iconv_charsets[i].charset != NULL; i++) {
- from = g_strdup(known_iconv_charsets[i].charset);
- to = g_strdup(known_iconv_charsets[i].iconv_name);
- e_strdown (from);
- g_hash_table_insert(iconv_charsets, from, to);
- }
-
- e_dlist_init(&iconv_cache_list);
- iconv_cache = g_hash_table_new(g_str_hash, g_str_equal);
- iconv_cache_open = g_hash_table_new(NULL, NULL);
-
- locale = setlocale (LC_ALL, NULL);
-
- if (!locale || !strcmp (locale, "C") || !strcmp (locale, "POSIX")) {
- /* The locale "C" or "POSIX" is a portable locale; its
- * LC_CTYPE part corresponds to the 7-bit ASCII character
- * set.
- */
-
- locale_charset = NULL;
- locale_lang = NULL;
- } else {
-#ifdef HAVE_CODESET
- locale_charset = g_strdup (nl_langinfo (CODESET));
- e_strdown (locale_charset);
-#else
- /* A locale name is typically of the form language[_terri-
- * tory][.codeset][@modifier], where language is an ISO 639
- * language code, territory is an ISO 3166 country code, and
- * codeset is a character set or encoding identifier like
- * ISO-8859-1 or UTF-8.
- */
- char *codeset, *p;
-
- codeset = strchr (locale, '.');
- if (codeset) {
- codeset++;
-
- /* ; is a hack for debian systems and / is a hack for Solaris systems */
- for (p = codeset; *p && !strchr ("@;/", *p); p++);
- locale_charset = g_strndup (codeset, p - codeset);
- e_strdown (locale_charset);
- } else {
- /* charset unknown */
- locale_charset = NULL;
- }
-#endif
-
- /* parse the locale lang */
- locale_parse_lang (locale);
-
- }
-
- if (!keep)
- UNLOCK();
-}
-
-const char *e_iconv_charset_name(const char *charset)
-{
- char *name, *ret, *tmp;
-
- if (charset == NULL)
- return NULL;
-
- name = g_alloca (strlen (charset) + 1);
- strcpy (name, charset);
- e_strdown (name);
-
- e_iconv_init(TRUE);
- ret = g_hash_table_lookup(iconv_charsets, name);
- if (ret != NULL) {
- UNLOCK();
- return ret;
- }
-
- /* Unknown, try canonicalise some basic charset types to something that should work */
- if (strncmp(name, "iso", 3) == 0) {
- /* Convert iso-nnnn-n or isonnnn-n or iso_nnnn-n to iso-nnnn-n or isonnnn-n */
- int iso, codepage;
- char *p;
-
- tmp = name + 3;
- if (*tmp == '-' || *tmp == '_')
- tmp++;
-
- iso = strtoul (tmp, &p, 10);
-
- if (iso == 10646) {
- /* they all become ICONV_10646 */
- ret = g_strdup (ICONV_10646);
- } else {
- tmp = p;
- if (*tmp == '-' || *tmp == '_')
- tmp++;
-
- codepage = strtoul (tmp, &p, 10);
-
- if (p > tmp) {
- /* codepage is numeric */
-#ifdef __aix__
- if (codepage == 13)
- ret = g_strdup ("IBM-921");
- else
-#endif /* __aix__ */
- ret = g_strdup_printf (ICONV_ISO_D_FORMAT, iso, codepage);
- } else {
- /* codepage is a string - probably iso-2022-jp or something */
- ret = g_strdup_printf (ICONV_ISO_S_FORMAT, iso, p);
- }
- }
- } else if (strncmp(name, "windows-", 8) == 0) {
- /* Convert windows-nnnnn or windows-cpnnnnn to cpnnnn */
- tmp = name+8;
- if (!strncmp(tmp, "cp", 2))
- tmp+=2;
- ret = g_strdup_printf("CP%s", tmp);
- } else if (strncmp(name, "microsoft-", 10) == 0) {
- /* Convert microsoft-nnnnn or microsoft-cpnnnnn to cpnnnn */
- tmp = name+10;
- if (!strncmp(tmp, "cp", 2))
- tmp+=2;
- ret = g_strdup_printf("CP%s", tmp);
- } else {
- /* Just assume its ok enough as is, case and all */
- ret = g_strdup(charset);
- }
-
- g_hash_table_insert(iconv_charsets, g_strdup(name), ret);
- UNLOCK();
-
- return ret;
-}
-
-static void
-flush_entry(struct _iconv_cache *ic)
-{
- struct _iconv_cache_node *in, *nn;
-
- in = (struct _iconv_cache_node *)ic->open.head;
- nn = in->next;
- while (nn) {
- if (in->ip != (iconv_t)-1) {
- g_hash_table_remove(iconv_cache_open, in->ip);
- iconv_close(in->ip);
- }
- g_free(in);
- in = nn;
- nn = in->next;
- }
- g_free(ic->conv);
- g_free(ic);
-}
-
-/* This should run pretty quick, its called a lot */
-iconv_t e_iconv_open(const char *oto, const char *ofrom)
-{
- const char *to, *from;
- char *tofrom;
- struct _iconv_cache *ic;
- struct _iconv_cache_node *in;
- int errnosav;
- iconv_t ip;
-
- if (oto == NULL || ofrom == NULL) {
- errno = EINVAL;
- return (iconv_t) -1;
- }
-
- to = e_iconv_charset_name (oto);
- from = e_iconv_charset_name (ofrom);
- tofrom = g_alloca (strlen (to) + strlen (from) + 2);
- sprintf(tofrom, "%s%%%s", to, from);
-
- LOCK();
-
- ic = g_hash_table_lookup(iconv_cache, tofrom);
- if (ic) {
- e_dlist_remove((EDListNode *)ic);
- } else {
- struct _iconv_cache *last = (struct _iconv_cache *)iconv_cache_list.tailpred;
- struct _iconv_cache *prev;
-
- prev = last->prev;
- while (prev && iconv_cache_size > E_ICONV_CACHE_SIZE) {
- in = (struct _iconv_cache_node *)last->open.head;
- if (in->next && !in->busy) {
- cd(printf("Flushing iconv converter '%s'\n", last->conv));
- e_dlist_remove((EDListNode *)last);
- g_hash_table_remove(iconv_cache, last->conv);
- flush_entry(last);
- iconv_cache_size--;
- }
- last = prev;
- prev = last->prev;
- }
-
- iconv_cache_size++;
-
- ic = g_malloc(sizeof(*ic));
- e_dlist_init(&ic->open);
- ic->conv = g_strdup(tofrom);
- g_hash_table_insert(iconv_cache, ic->conv, ic);
-
- cd(printf("Creating iconv converter '%s'\n", ic->conv));
- }
- e_dlist_addhead(&iconv_cache_list, (EDListNode *)ic);
-
- /* If we have a free iconv, use it */
- in = (struct _iconv_cache_node *)ic->open.tailpred;
- if (in->prev && !in->busy) {
- cd(printf("using existing iconv converter '%s'\n", ic->conv));
- ip = in->ip;
- if (ip != (iconv_t)-1) {
- /* work around some broken iconv implementations
- * that die if the length arguments are NULL
- */
- size_t buggy_iconv_len = 0;
- char *buggy_iconv_buf = NULL;
-
- /* resets the converter */
- iconv(ip, &buggy_iconv_buf, &buggy_iconv_len, &buggy_iconv_buf, &buggy_iconv_len);
- in->busy = TRUE;
- e_dlist_remove((EDListNode *)in);
- e_dlist_addhead(&ic->open, (EDListNode *)in);
- }
- } else {
- cd(printf("creating new iconv converter '%s'\n", ic->conv));
- ip = iconv_open(to, from);
- in = g_malloc(sizeof(*in));
- in->ip = ip;
- in->parent = ic;
- e_dlist_addhead(&ic->open, (EDListNode *)in);
- if (ip != (iconv_t)-1) {
- g_hash_table_insert(iconv_cache_open, ip, in);
- in->busy = TRUE;
- } else {
- errnosav = errno;
- g_warning("Could not open converter for '%s' to '%s' charset", from, to);
- in->busy = FALSE;
- errno = errnosav;
- }
- }
-
- UNLOCK();
-
- return ip;
-}
-
-size_t e_iconv(iconv_t cd, const char **inbuf, size_t *inbytesleft, char ** outbuf, size_t *outbytesleft)
-{
- return iconv(cd, (char **) inbuf, inbytesleft, outbuf, outbytesleft);
-}
-
-void
-e_iconv_close(iconv_t ip)
-{
- struct _iconv_cache_node *in;
-
- if (ip == (iconv_t)-1)
- return;
-
- LOCK();
- in = g_hash_table_lookup(iconv_cache_open, ip);
- if (in) {
- cd(printf("closing iconv converter '%s'\n", in->parent->conv));
- e_dlist_remove((EDListNode *)in);
- in->busy = FALSE;
- e_dlist_addtail(&in->parent->open, (EDListNode *)in);
- } else {
- g_warning("trying to close iconv i dont know about: %p", ip);
- iconv_close(ip);
- }
- UNLOCK();
-
-}
-
-const char *e_iconv_locale_charset(void)
-{
- e_iconv_init(FALSE);
-
- return locale_charset;
-}
-
-
-const char *
-e_iconv_locale_language (void)
-{
- e_iconv_init (FALSE);
-
- return locale_lang;
-}
-
-/* map CJKR charsets to their language code */
-/* NOTE: only support charset names that will be returned by
- * e_iconv_charset_name() so that we don't have to keep track of all
- * the aliases too. */
-static struct {
- char *charset;
- char *lang;
-} cjkr_lang_map[] = {
- { "Big5", "zh" },
- { "BIG5HKSCS", "zh" },
- { "gb2312", "zh" },
- { "gb18030", "zh" },
- { "gbk", "zh" },
- { "euc-tw", "zh" },
- { "iso-2022-jp", "ja" },
- { "sjis", "ja" },
- { "ujis", "ja" },
- { "eucJP", "ja" },
- { "euc-jp", "ja" },
- { "euc-kr", "ko" },
- { "koi8-r", "ru" },
- { "koi8-u", "uk" }
-};
-
-#define NUM_CJKR_LANGS (sizeof (cjkr_lang_map) / sizeof (cjkr_lang_map[0]))
-
-const char *
-e_iconv_charset_language (const char *charset)
-{
- int i;
-
- if (!charset)
- return NULL;
-
- charset = e_iconv_charset_name (charset);
- for (i = 0; i < NUM_CJKR_LANGS; i++) {
- if (!strcasecmp (cjkr_lang_map[i].charset, charset))
- return cjkr_lang_map[i].lang;
- }
-
- return NULL;
-}
diff --git a/e-util/e-iconv.h b/e-util/e-iconv.h
deleted file mode 100644
index 14b93853d5..0000000000
--- a/e-util/e-iconv.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-iconv.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Michael Zucchi <notzed@ximian.com>
- * Jeffrey Stedfast <fejj@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_ICONV_H_
-#define _E_ICONV_H_
-
-#include <iconv.h>
-
-#ifdef __cplusplus
-extern "C" {
-#pragma }
-#endif /* __cplusplus */
-
-const char *e_iconv_charset_name(const char *charset);
-iconv_t e_iconv_open(const char *oto, const char *ofrom);
-size_t e_iconv(iconv_t cd, const char **inbuf, size_t *inbytesleft, char ** outbuf, size_t *outbytesleft);
-void e_iconv_close(iconv_t ip);
-const char *e_iconv_locale_charset(void);
-
-/* languages */
-const char *e_iconv_locale_language (void);
-const char *e_iconv_charset_language (const char *charset);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* !_E_ICONV_H_ */
diff --git a/e-util/e-marshal.list b/e-util/e-marshal.list
deleted file mode 100644
index b478efb1ce..0000000000
--- a/e-util/e-marshal.list
+++ /dev/null
@@ -1,52 +0,0 @@
-BOOLEAN:INT,INT,OBJECT,INT,INT,UINT
-BOOLEAN:INT,POINTER,INT,OBJECT,INT,INT,UINT
-BOOLEAN:NONE
-BOOLEAN:OBJECT
-BOOLEAN:OBJECT,DOUBLE,DOUBLE,BOOLEAN
-BOOLEAN:POINTER,POINTER,INT,INT,INT
-BOOLEAN:POINTER,POINTER,POINTER,INT,INT,INT
-BOOLEAN:STRING,INT
-DOUBLE:OBJECT,DOUBLE,DOUBLE,BOOLEAN
-INT:BOXED
-INT:INT
-INT:INT,INT,BOXED
-INT:INT,POINTER,INT,BOXED
-INT:OBJECT,BOXED
-INT:POINTER
-NONE:BOXED
-NONE:BOXED,INT
-NONE:BOXED,INT,INT
-NONE:DOUBLE
-NONE:INT
-NONE:INT,INT
-NONE:INT,INT,BOXED
-NONE:INT,INT,OBJECT
-NONE:INT,INT,OBJECT,BOXED,UINT,UINT
-NONE:INT,INT,OBJECT,INT,INT,BOXED,UINT,UINT
-NONE:INT,INT,OBJECT,POINTER,UINT,UINT
-NONE:INT,INT,OBJECT,UINT
-NONE:INT,INT,STRING,STRING
-NONE:INT,INT,STRING,STRING,POINTER
-NONE:INT,POINTER
-NONE:INT,POINTER,INT,BOXED
-NONE:INT,POINTER,INT,OBJECT
-NONE:INT,POINTER,INT,OBJECT,BOXED,UINT,UINT
-NONE:INT,POINTER,INT,OBJECT,INT,INT,BOXED,UINT,UINT
-NONE:INT,POINTER,INT,OBJECT,UINT
-NONE:INT,STRING
-NONE:NONE
-NONE:OBJECT
-NONE:OBJECT,OBJECT
-NONE:OBJECT,DOUBLE,DOUBLE,BOOLEAN
-NONE:POINTER
-NONE:POINTER,BOOLEAN
-NONE:POINTER,BOOLEAN,BOOLEAN,BOOLEAN
-NONE:POINTER,INT
-NONE:POINTER,INT,INT
-NONE:POINTER,INT,INT,INT
-NONE:POINTER,INT,INT,INT,INT
-NONE:POINTER,INT,OBJECT
-NONE:POINTER,POINTER
-NONE:POINTER,POINTER,INT
-OBJECT:OBJECT,DOUBLE,DOUBLE,BOOLEAN
-POINTER:NONE
diff --git a/e-util/e-memory.c b/e-util/e-memory.c
new file mode 100644
index 0000000000..747808c507
--- /dev/null
+++ b/e-util/e-memory.c
@@ -0,0 +1,1310 @@
+/*
+ * Copyright (c) 2000, 2001 Ximian Inc.
+ *
+ * Authors: Michael Zucchi <notzed@ximian.com>
+ * Jacob Berkman <jacob@ximian.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+
+*/
+
+#include "e-memory.h"
+
+#include <string.h> /* memset() */
+#include <stdlib.h> /* alloca() */
+#include <glib.h>
+
+#define s(x) /* strv debug */
+#define p(x) /* poolv debug */
+#define p2(x) /* poolv assertion checking */
+
+/*#define MALLOC_CHECK*/
+
+/*#define PROFILE_POOLV*/
+
+#ifdef PROFILE_POOLV
+#include <time.h>
+#define pp(x) x
+#else
+#define pp(x)
+#endif
+
+/*#define TIMEIT*/
+
+#ifdef TIMEIT
+#include <sys/time.h>
+#include <unistd.h>
+
+struct timeval timeit_start;
+
+static time_start(const char *desc)
+{
+ gettimeofday(&timeit_start, NULL);
+ printf("starting: %s\n", desc);
+}
+
+static time_end(const char *desc)
+{
+ unsigned long diff;
+ struct timeval end;
+
+ gettimeofday(&end, NULL);
+ diff = end.tv_sec * 1000 + end.tv_usec/1000;
+ diff -= timeit_start.tv_sec * 1000 + timeit_start.tv_usec/1000;
+ printf("%s took %ld.%03ld seconds\n",
+ desc, diff / 1000, diff % 1000);
+}
+#else
+#define time_start(x)
+#define time_end(x)
+#endif
+
+#ifdef MALLOC_CHECK
+#include <mcheck.h>
+#include <stdio.h>
+static void
+checkmem(void *p)
+{
+ if (p) {
+ int status = mprobe(p);
+
+ switch (status) {
+ case MCHECK_HEAD:
+ printf("Memory underrun at %p\n", p);
+ abort();
+ case MCHECK_TAIL:
+ printf("Memory overrun at %p\n", p);
+ abort();
+ case MCHECK_FREE:
+ printf("Double free %p\n", p);
+ abort();
+ }
+ }
+}
+#define MPROBE(x) checkmem((void *)(x))
+#else
+#define MPROBE(x)
+#endif
+
+/* mempool class */
+
+typedef struct _MemChunkFreeNode {
+ struct _MemChunkFreeNode *next;
+ unsigned int atoms;
+} MemChunkFreeNode;
+
+typedef struct _EMemChunk {
+ unsigned int blocksize; /* number of atoms in a block */
+ unsigned int atomsize; /* size of each atom */
+ GPtrArray *blocks; /* blocks of raw memory */
+ struct _MemChunkFreeNode *free;
+} MemChunk;
+
+/**
+ * e_memchunk_new:
+ * @atomcount: The number of atoms stored in a single malloc'd block of memory.
+ * @atomsize: The size of each allocation.
+ *
+ * Create a new memchunk header. Memchunks are an efficient way to allocate
+ * and deallocate identical sized blocks of memory quickly, and space efficiently.
+ *
+ * e_memchunks are effectively the same as gmemchunks, only faster (much), and
+ * they use less memory overhead for housekeeping.
+ *
+ * Return value: The new header.
+ **/
+MemChunk *e_memchunk_new(int atomcount, int atomsize)
+{
+ MemChunk *m = g_malloc(sizeof(*m));
+
+ m->blocksize = atomcount;
+ m->atomsize = MAX(atomsize, sizeof(MemChunkFreeNode));
+ m->blocks = g_ptr_array_new();
+ m->free = NULL;
+
+ return m;
+}
+
+/**
+ * memchunk_alloc:
+ * @m:
+ *
+ * Allocate a new atom size block of memory from a memchunk.
+ **/
+void *e_memchunk_alloc(MemChunk *m)
+{
+ char *b;
+ MemChunkFreeNode *f;
+ void *mem;
+
+ f = m->free;
+ if (f) {
+ f->atoms--;
+ if (f->atoms > 0) {
+ mem = ((char *)f) + (f->atoms*m->atomsize);
+ } else {
+ mem = f;
+ m->free = m->free->next;
+ }
+ return mem;
+ } else {
+ b = g_malloc(m->blocksize * m->atomsize);
+ g_ptr_array_add(m->blocks, b);
+ f = (MemChunkFreeNode *)&b[m->atomsize];
+ f->atoms = m->blocksize-1;
+ f->next = NULL;
+ m->free = f;
+ return b;
+ }
+}
+
+void *e_memchunk_alloc0(EMemChunk *m)
+{
+ void *mem;
+
+ mem = e_memchunk_alloc(m);
+ memset(mem, 0, m->atomsize);
+
+ return mem;
+}
+
+/**
+ * e_memchunk_free:
+ * @m:
+ * @mem: Address of atom to free.
+ *
+ * Free a single atom back to the free pool of atoms in the given
+ * memchunk.
+ **/
+void
+e_memchunk_free(MemChunk *m, void *mem)
+{
+ MemChunkFreeNode *f;
+
+ /* put the location back in the free list. If we knew if the preceeding or following
+ cells were free, we could merge the free nodes, but it doesn't really add much */
+ f = mem;
+ f->next = m->free;
+ m->free = f;
+ f->atoms = 1;
+
+ /* we could store the free list sorted - we could then do the above, and also
+ probably improve the locality of reference properties for the allocator */
+ /* and it would simplify some other algorithms at that, but slow this one down
+ significantly */
+}
+
+/**
+ * e_memchunk_empty:
+ * @m:
+ *
+ * Clean out the memchunk buffers. Marks all allocated memory as free blocks,
+ * but does not give it back to the system. Can be used if the memchunk
+ * is to be used repeatedly.
+ **/
+void
+e_memchunk_empty(MemChunk *m)
+{
+ int i;
+ MemChunkFreeNode *f, *h = NULL;
+
+ for (i=0;i<m->blocks->len;i++) {
+ f = (MemChunkFreeNode *)m->blocks->pdata[i];
+ f->atoms = m->blocksize;
+ f->next = h;
+ h = f;
+ }
+ m->free = h;
+}
+
+struct _cleaninfo {
+ struct _cleaninfo *next;
+ char *base;
+ int count;
+ int size; /* just so tree_search has it, sigh */
+};
+
+static int tree_compare(struct _cleaninfo *a, struct _cleaninfo *b)
+{
+ if (a->base < b->base)
+ return -1;
+ else if (a->base > b->base)
+ return 1;
+ return 0;
+}
+
+static int tree_search(struct _cleaninfo *a, char *mem)
+{
+ if (a->base <= mem) {
+ if (mem < &a->base[a->size])
+ return 0;
+ return 1;
+ }
+ return -1;
+}
+
+/**
+ * e_memchunk_clean:
+ * @m:
+ *
+ * Scan all empty blocks and check for blocks which can be free'd
+ * back to the system.
+ *
+ * This routine may take a while to run if there are many allocated
+ * memory blocks (if the total number of allocations is many times
+ * greater than atomcount).
+ **/
+void
+e_memchunk_clean(MemChunk *m)
+{
+ GTree *tree;
+ int i;
+ MemChunkFreeNode *f;
+ struct _cleaninfo *ci, *hi = NULL;
+
+ f = m->free;
+ if (m->blocks->len == 0 || f == NULL)
+ return;
+
+ /* first, setup the tree/list so we can map free block addresses to block addresses */
+ tree = g_tree_new((GCompareFunc)tree_compare);
+ for (i=0;i<m->blocks->len;i++) {
+ ci = alloca(sizeof(*ci));
+ ci->count = 0;
+ ci->base = m->blocks->pdata[i];
+ ci->size = m->blocksize * m->atomsize;
+ g_tree_insert(tree, ci, ci);
+ ci->next = hi;
+ hi = ci;
+ }
+
+ /* now, scan all free nodes, and count them in their tree node */
+ while (f) {
+ ci = g_tree_search(tree, (GCompareFunc) tree_search, f);
+ if (ci) {
+ ci->count += f->atoms;
+ } else {
+ g_warning("error, can't find free node in memory block\n");
+ }
+ f = f->next;
+ }
+
+ /* if any nodes are all free, free & unlink them */
+ ci = hi;
+ while (ci) {
+ if (ci->count == m->blocksize) {
+ MemChunkFreeNode *prev = NULL;
+
+ f = m->free;
+ while (f) {
+ if (tree_search (ci, (void *) f) == 0) {
+ /* prune this node from our free-node list */
+ if (prev)
+ prev->next = f->next;
+ else
+ m->free = f->next;
+ } else {
+ prev = f;
+ }
+
+ f = f->next;
+ }
+
+ g_ptr_array_remove_fast(m->blocks, ci->base);
+ g_free(ci->base);
+ }
+ ci = ci->next;
+ }
+
+ g_tree_destroy(tree);
+}
+
+/**
+ * e_memchunk_destroy:
+ * @m:
+ *
+ * Free the memchunk header, and all associated memory.
+ **/
+void
+e_memchunk_destroy(MemChunk *m)
+{
+ int i;
+
+ if (m == NULL)
+ return;
+
+ for (i=0;i<m->blocks->len;i++)
+ g_free(m->blocks->pdata[i]);
+ g_ptr_array_free(m->blocks, TRUE);
+ g_free(m);
+}
+
+typedef struct _MemPoolNode {
+ struct _MemPoolNode *next;
+
+ int free;
+} MemPoolNode;
+
+typedef struct _MemPoolThresholdNode {
+ struct _MemPoolThresholdNode *next;
+} MemPoolThresholdNode;
+
+#define ALIGNED_SIZEOF(t) ((sizeof (t) + G_MEM_ALIGN - 1) & -G_MEM_ALIGN)
+
+typedef struct _EMemPool {
+ int blocksize;
+ int threshold;
+ unsigned int align;
+ struct _MemPoolNode *blocks;
+ struct _MemPoolThresholdNode *threshold_blocks;
+} MemPool;
+
+/* a pool of mempool header blocks */
+static MemChunk *mempool_memchunk;
+#ifdef G_THREADS_ENABLED
+static GStaticMutex mempool_mutex = G_STATIC_MUTEX_INIT;
+#endif
+
+/**
+ * e_mempool_new:
+ * @blocksize: The base blocksize to use for all system alocations.
+ * @threshold: If the allocation exceeds the threshold, then it is
+ * allocated separately and stored in a separate list.
+ * @flags: Alignment options: E_MEMPOOL_ALIGN_STRUCT uses native
+ * struct alignment, E_MEMPOOL_ALIGN_WORD aligns to 16 bits (2 bytes),
+ * and E_MEMPOOL_ALIGN_BYTE aligns to the nearest byte. The default
+ * is to align to native structures.
+ *
+ * Create a new mempool header. Mempools can be used to efficiently
+ * allocate data which can then be freed as a whole.
+ *
+ * Mempools can also be used to efficiently allocate arbitrarily
+ * aligned data (such as strings) without incurring the space overhead
+ * of aligning each allocation (which is not required for strings).
+ *
+ * However, each allocation cannot be freed individually, only all
+ * or nothing.
+ *
+ * Return value:
+ **/
+MemPool *e_mempool_new(int blocksize, int threshold, EMemPoolFlags flags)
+{
+ MemPool *pool;
+
+#ifdef G_THREADS_ENABLED
+ g_static_mutex_lock(&mempool_mutex);
+#endif
+ if (mempool_memchunk == NULL) {
+ mempool_memchunk = e_memchunk_new(8, sizeof(MemPool));
+ }
+ pool = e_memchunk_alloc(mempool_memchunk);
+#ifdef G_THREADS_ENABLED
+ g_static_mutex_unlock(&mempool_mutex);
+#endif
+ if (threshold >= blocksize)
+ threshold = blocksize * 2 / 3;
+ pool->blocksize = blocksize;
+ pool->threshold = threshold;
+ pool->blocks = NULL;
+ pool->threshold_blocks = NULL;
+
+ switch (flags & E_MEMPOOL_ALIGN_MASK) {
+ case E_MEMPOOL_ALIGN_STRUCT:
+ default:
+ pool->align = G_MEM_ALIGN-1;
+ break;
+ case E_MEMPOOL_ALIGN_WORD:
+ pool->align = 2-1;
+ break;
+ case E_MEMPOOL_ALIGN_BYTE:
+ pool->align = 1-1;
+ }
+ return pool;
+}
+
+/**
+ * e_mempool_alloc:
+ * @pool:
+ * @size:
+ *
+ * Allocate a new data block in the mempool. Size will
+ * be rounded up to the mempool's alignment restrictions
+ * before being used.
+ **/
+void *e_mempool_alloc(MemPool *pool, register int size)
+{
+ size = (size + pool->align) & (~(pool->align));
+ if (size>=pool->threshold) {
+ MemPoolThresholdNode *n;
+
+ n = g_malloc(ALIGNED_SIZEOF(*n) + size);
+ n->next = pool->threshold_blocks;
+ pool->threshold_blocks = n;
+ return (char *) n + ALIGNED_SIZEOF(*n);
+ } else {
+ register MemPoolNode *n;
+
+ n = pool->blocks;
+ if (n && n->free >= size) {
+ n->free -= size;
+ return (char *) n + ALIGNED_SIZEOF(*n) + n->free;
+ }
+
+ /* maybe we could do some sort of the free blocks based on size, but
+ it doubt its worth it at all */
+
+ n = g_malloc(ALIGNED_SIZEOF(*n) + pool->blocksize);
+ n->next = pool->blocks;
+ pool->blocks = n;
+ n->free = pool->blocksize - size;
+ return (char *) n + ALIGNED_SIZEOF(*n) + n->free;
+ }
+}
+
+char *e_mempool_strdup(EMemPool *pool, const char *str)
+{
+ char *out;
+
+ out = e_mempool_alloc(pool, strlen(str)+1);
+ strcpy(out, str);
+
+ return out;
+}
+
+/**
+ * e_mempool_flush:
+ * @pool:
+ * @freeall: Free all system allocated blocks as well.
+ *
+ * Flush used memory and mark allocated blocks as free.
+ *
+ * If @freeall is #TRUE, then all allocated blocks are free'd
+ * as well. Otherwise only blocks above the threshold are
+ * actually freed, and the others are simply marked as empty.
+ **/
+void e_mempool_flush(MemPool *pool, int freeall)
+{
+ MemPoolThresholdNode *tn, *tw;
+ MemPoolNode *pw, *pn;
+
+ tw = pool->threshold_blocks;
+ while (tw) {
+ tn = tw->next;
+ g_free(tw);
+ tw = tn;
+ }
+ pool->threshold_blocks = NULL;
+
+ if (freeall) {
+ pw = pool->blocks;
+ while (pw) {
+ pn = pw->next;
+ g_free(pw);
+ pw = pn;
+ }
+ pool->blocks = NULL;
+ } else {
+ pw = pool->blocks;
+ while (pw) {
+ pw->free = pool->blocksize;
+ pw = pw->next;
+ }
+ }
+}
+
+/**
+ * e_mempool_destroy:
+ * @pool:
+ *
+ * Free all memory associated with a mempool.
+ **/
+void e_mempool_destroy(MemPool *pool)
+{
+ if (pool) {
+ e_mempool_flush(pool, 1);
+#ifdef G_THREADS_ENABLED
+ g_static_mutex_lock(&mempool_mutex);
+#endif
+ e_memchunk_free(mempool_memchunk, pool);
+#ifdef G_THREADS_ENABLED
+ g_static_mutex_unlock(&mempool_mutex);
+#endif
+ }
+}
+
+
+/*
+ string array classes
+*/
+
+#define STRV_UNPACKED ((unsigned char)(~0))
+
+struct _EStrv {
+ unsigned char length; /* how many entries we have (or the token STRV_UNPACKED) */
+ char data[1]; /* data follows */
+};
+
+struct _s_strv_string {
+ char *string; /* the string to output */
+ char *free; /* a string to free, if we referenced it */
+};
+
+struct _e_strvunpacked {
+ unsigned char type; /* we overload last to indicate this is unpacked */
+ MemPool *pool; /* pool of memory for strings */
+ struct _EStrv *source; /* if we were converted from a packed one, keep the source around for a while */
+ unsigned int length;
+ struct _s_strv_string strings[1]; /* the string array data follows */
+};
+
+/**
+ * e_strv_new:
+ * @size: The number of elements in the strv. Currently this is limited
+ * to 254 elements.
+ *
+ * Create a new strv (string array) header. strv's can be used to
+ * create and work with arrays of strings that can then be compressed
+ * into a space-efficient static structure. This is useful
+ * where a number of strings are to be stored for lookup, and not
+ * generally edited afterwards.
+ *
+ * The size limit is currently 254 elements. This will probably not
+ * change as arrays of this size suffer significant performance
+ * penalties when looking up strings with high indices.
+ *
+ * Return value:
+ **/
+struct _EStrv *
+e_strv_new(int size)
+{
+ struct _e_strvunpacked *s;
+
+ g_assert(size<255);
+
+ s = g_malloc(sizeof(*s) + (size-1)*sizeof(s->strings[0]));
+ s(printf("new strv=%p, size = %d bytes\n", s, sizeof(*s) + (size-1)*sizeof(char *)));
+ s->type = STRV_UNPACKED;
+ s->pool = NULL;
+ s->length = size;
+ s->source = NULL;
+ memset(s->strings, 0, size*sizeof(s->strings[0]));
+
+ return (struct _EStrv *)s;
+}
+
+static struct _e_strvunpacked *
+strv_unpack(struct _EStrv *strv)
+{
+ struct _e_strvunpacked *s;
+ register char *p;
+ int i;
+
+ s(printf("unpacking\n"));
+
+ s = (struct _e_strvunpacked *)e_strv_new(strv->length);
+ p = strv->data;
+ for (i=0;i<s->length;i++) {
+ if (i>0)
+ while (*p++)
+ ;
+ s->strings[i].string = p;
+ }
+ s->source = strv;
+ s->type = STRV_UNPACKED;
+
+ return s;
+}
+
+/**
+ * e_strv_set_ref:
+ * @strv:
+ * @index:
+ * @str:
+ *
+ * Set a string array element by reference. The string
+ * is not copied until the array is packed.
+ *
+ * If @strv has been packed, then it is unpacked ready
+ * for more inserts, and should be packed again once finished with.
+ * The memory used by the original @strv is not freed until
+ * the new strv is packed, or freed itself.
+ *
+ * Return value: A new EStrv if the strv has already
+ * been packed, otherwise @strv.
+ **/
+struct _EStrv *
+e_strv_set_ref(struct _EStrv *strv, int index, char *str)
+{
+ struct _e_strvunpacked *s;
+
+ s(printf("set ref %d '%s'\nawkmeharder: %s\n ", index, str, str));
+
+ if (strv->length != STRV_UNPACKED)
+ s = strv_unpack(strv);
+ else
+ s = (struct _e_strvunpacked *)strv;
+
+ g_assert(index>=0 && index < s->length);
+
+ s->strings[index].string = str;
+
+ return (struct _EStrv *)s;
+}
+
+/**
+ * e_strv_set_ref_free:
+ * @strv:
+ * @index:
+ * @str:
+ *
+ * Set a string by reference, similar to set_ref, but also
+ * free the string when finished with it. The string
+ * is not copied until the strv is packed, and not at
+ * all if the index is overwritten.
+ *
+ * Return value: @strv if already unpacked, otherwise an packed
+ * EStrv.
+ **/
+struct _EStrv *
+e_strv_set_ref_free(struct _EStrv *strv, int index, char *str)
+{
+ struct _e_strvunpacked *s;
+
+ s(printf("set ref %d '%s'\nawkmeevenharder: %s\n ", index, str, str));
+
+ if (strv->length != STRV_UNPACKED)
+ s = strv_unpack(strv);
+ else
+ s = (struct _e_strvunpacked *)strv;
+
+ g_assert(index>=0 && index < s->length);
+
+ s->strings[index].string = str;
+ if (s->strings[index].free)
+ g_free(s->strings[index].free);
+ s->strings[index].free = str;
+
+ return (struct _EStrv *)s;
+}
+
+/**
+ * e_strv_set:
+ * @strv:
+ * @index:
+ * @str:
+ *
+ * Set a string array reference. The string @str is copied
+ * into the string array at location @index.
+ *
+ * If @strv has been packed, then it is unpacked ready
+ * for more inserts, and should be packed again once finished with.
+ *
+ * Return value: A new EStrv if the strv has already
+ * been packed, otherwise @strv.
+ **/
+struct _EStrv *
+e_strv_set(struct _EStrv *strv, int index, const char *str)
+{
+ struct _e_strvunpacked *s;
+
+ s(printf("set %d '%s'\n", index, str));
+
+ if (strv->length != STRV_UNPACKED)
+ s = strv_unpack(strv);
+ else
+ s = (struct _e_strvunpacked *)strv;
+
+ g_assert(index>=0 && index < s->length);
+
+ if (s->pool == NULL)
+ s->pool = e_mempool_new(1024, 512, E_MEMPOOL_ALIGN_BYTE);
+
+ s->strings[index].string = e_mempool_alloc(s->pool, strlen(str)+1);
+ strcpy(s->strings[index].string, str);
+
+ return (struct _EStrv *)s;
+}
+
+/**
+ * e_strv_pack:
+ * @strv:
+ *
+ * Pack the @strv into a space efficient structure for later lookup.
+ *
+ * All strings are packed into a single allocated block, separated
+ * by single \0 characters, together with a count byte.
+ *
+ * Return value:
+ **/
+struct _EStrv *
+e_strv_pack(struct _EStrv *strv)
+{
+ struct _e_strvunpacked *s;
+ int len, i;
+ register char *src, *dst;
+
+ if (strv->length == STRV_UNPACKED) {
+ s = (struct _e_strvunpacked *)strv;
+
+ s(printf("packing string\n"));
+
+ len = 0;
+ for (i=0;i<s->length;i++)
+ len += s->strings[i].string?strlen(s->strings[i].string)+1:1;
+
+ strv = g_malloc(sizeof(*strv) + len);
+ s(printf("allocating strv=%p, size = %d\n", strv, sizeof(*strv)+len));
+ strv->length = s->length;
+ dst = strv->data;
+ for (i=0;i<s->length;i++) {
+ if ((src = s->strings[i].string)) {
+ while ((*dst++ = *src++))
+ ;
+ } else {
+ *dst++ = 0;
+ }
+ }
+ e_strv_destroy((struct _EStrv *)s);
+ }
+ return strv;
+}
+
+/**
+ * e_strv_get:
+ * @strv:
+ * @index:
+ *
+ * Retrieve a string by index. This function works
+ * identically on both packed and unpacked strv's, although
+ * may be much slower on a packed strv.
+ *
+ * Return value:
+ **/
+char *
+e_strv_get(struct _EStrv *strv, int index)
+{
+ struct _e_strvunpacked *s;
+ char *p;
+
+ if (strv->length != STRV_UNPACKED) {
+ g_assert(index>=0 && index < strv->length);
+ p = strv->data;
+ while (index > 0) {
+ while (*p++ != 0)
+ ;
+ index--;
+ }
+ return p;
+ } else {
+ s = (struct _e_strvunpacked *)strv;
+ g_assert(index>=0 && index < s->length);
+ return s->strings[index].string?s->strings[index].string:"";
+ }
+}
+
+/**
+ * e_strv_destroy:
+ * @strv:
+ *
+ * Free a strv and all associated memory. Works on packed
+ * or unpacked strv's.
+ **/
+void
+e_strv_destroy(struct _EStrv *strv)
+{
+ struct _e_strvunpacked *s;
+ int i;
+
+ s(printf("freeing strv\n"));
+
+ if (strv->length == STRV_UNPACKED) {
+ s = (struct _e_strvunpacked *)strv;
+ if (s->pool)
+ e_mempool_destroy(s->pool);
+ if (s->source)
+ e_strv_destroy(s->source);
+ for (i=0;i<s->length;i++) {
+ if (s->strings[i].free)
+ g_free(s->strings[i].free);
+ }
+ }
+
+ s(printf("freeing strv=%p\n", strv));
+
+ g_free(strv);
+}
+
+
+
+/* string pool stuff */
+
+/* TODO:
+ garbage collection, using the following technique:
+ Create a memchunk for each possible size of poolv, and allocate every poolv from those
+ To garbage collect, scan all memchunk internally, ignoring any free areas (or mark each
+ poolv when freeing it - set length 0?), and find out which strings are not anywhere,
+ then free them.
+
+ OR:
+ Just keep a refcount in the hashtable, instead of duplicating the key pointer.
+
+ either would also require a free for the mempool, so ignore it for now */
+
+/*#define POOLV_REFCNT*/ /* Define to enable refcounting code that does
+ automatic garbage collection of unused strings */
+
+static GHashTable *poolv_pool = NULL;
+static EMemPool *poolv_mempool = NULL;
+
+#ifdef MALLOC_CHECK
+static GPtrArray *poolv_table = NULL;
+#endif
+
+#ifdef PROFILE_POOLV
+static gulong poolv_hits = 0;
+static gulong poolv_misses = 0;
+static unsigned long poolv_mem, poolv_count;
+#endif
+
+#ifdef G_THREADS_ENABLED
+static GStaticMutex poolv_mutex = G_STATIC_MUTEX_INIT;
+#endif
+
+struct _EPoolv {
+ unsigned char length;
+ char *s[1];
+};
+
+/**
+ * e_poolv_new: @size: The number of elements in the poolv, maximum of 254 elements.
+ *
+ * create a new poolv (string vector which shares a global string
+ * pool). poolv's can be used to work with arrays of strings which
+ * save memory by eliminating duplicated allocations of the same
+ * string.
+ *
+ * this is useful when you have a log of read-only strings that do not
+ * go away and are duplicated a lot (such as email headers).
+ *
+ * we should probably in the future ref count the strings contained in
+ * the hash table, but for now let's not.
+ *
+ * Return value: new pooled string vector
+ **/
+EPoolv *
+e_poolv_new(unsigned int size)
+{
+ EPoolv *poolv;
+
+ g_assert(size < 255);
+
+ poolv = g_malloc0(sizeof (*poolv) + (size - 1) * sizeof (char *));
+ poolv->length = size;
+
+#ifdef G_THREADS_ENABLED
+ g_static_mutex_lock(&poolv_mutex);
+#endif
+ if (!poolv_pool)
+ poolv_pool = g_hash_table_new(g_str_hash, g_str_equal);
+
+ if (!poolv_mempool)
+ poolv_mempool = e_mempool_new(32 * 1024, 512, E_MEMPOOL_ALIGN_BYTE);
+
+#ifdef MALLOC_CHECK
+ {
+ int i;
+
+ if (poolv_table == NULL)
+ poolv_table = g_ptr_array_new();
+
+ for (i=0;i<poolv_table->len;i++)
+ MPROBE(poolv_table->pdata[i]);
+
+ g_ptr_array_add(poolv_table, poolv);
+ }
+#endif
+
+#ifdef G_THREADS_ENABLED
+ g_static_mutex_unlock(&poolv_mutex);
+#endif
+
+ p(printf("new poolv=%p\tsize=%d\n", poolv, sizeof(*poolv) + (size-1)*sizeof(char *)));
+
+#ifdef PROFILE_POOLV
+ poolv_count++;
+#endif
+ return poolv;
+}
+
+/**
+ * e_poolv_cpy:
+ * @dest: destination pooled string vector
+ * @src: source pooled string vector
+ *
+ * Copy the contents of a pooled string vector
+ *
+ * Return value: @dest, which may be re-allocated if the strings
+ * are different lengths.
+ **/
+EPoolv *
+e_poolv_cpy(EPoolv *dest, const EPoolv *src)
+{
+#ifdef POOLV_REFCNT
+ int i;
+ unsigned int ref;
+ char *key;
+#endif
+
+ p2(g_return_val_if_fail (dest != NULL, NULL));
+ p2(g_return_val_if_fail (src != NULL, NULL));
+
+ MPROBE(dest);
+ MPROBE(src);
+
+ if (dest->length != src->length) {
+ e_poolv_destroy(dest);
+ dest = e_poolv_new(src->length);
+ }
+
+#ifdef POOLV_REFCNT
+#ifdef G_THREADS_ENABLED
+ g_static_mutex_lock(&poolv_mutex);
+#endif
+ /* ref new copies */
+ for (i=0;i<src->length;i++) {
+ if (src->s[i]) {
+ if (g_hash_table_lookup_extended(poolv_pool, src->s[i], (void **)&key, (void **)&ref)) {
+ g_hash_table_insert(poolv_pool, key, (void *)(ref+1));
+ } else {
+ g_assert_not_reached();
+ }
+ }
+ }
+
+ /* unref the old ones */
+ for (i=0;i<dest->length;i++) {
+ if (dest->s[i]) {
+ if (g_hash_table_lookup_extended(poolv_pool, dest->s[i], (void **)&key, (void **)&ref)) {
+ /* if ref == 1 free it */
+ g_assert(ref > 0);
+ g_hash_table_insert(poolv_pool, key, (void *)(ref-1));
+ } else {
+ g_assert_not_reached();
+ }
+ }
+ }
+#ifdef G_THREADS_ENABLED
+ g_static_mutex_unlock(&poolv_mutex);
+#endif
+#endif
+
+ memcpy(dest->s, src->s, src->length * sizeof (char *));
+
+ return dest;
+}
+
+#ifdef PROFILE_POOLV
+static void
+poolv_profile_update (void)
+{
+ static time_t last_time = 0;
+ time_t new_time;
+
+ new_time = time (NULL);
+ if (new_time - last_time < 5)
+ return;
+
+ printf("poolv profile: %lu hits, %lu misses: %d%% hit rate, memory: %lu, instances: %lu\n",
+ poolv_hits, poolv_misses,
+ (int)(100.0 * ((double) poolv_hits / (double) (poolv_hits + poolv_misses))),
+ poolv_mem, poolv_count);
+
+ last_time = new_time;
+}
+#endif
+
+/**
+ * e_poolv_set:
+ * @poolv: pooled string vector
+ * @index: index in vector of string
+ * @str: string to set
+ * @freeit: whether the caller is releasing its reference to the
+ * string
+ *
+ * Set a string vector reference. If the caller will no longer be
+ * referencing the string, freeit should be TRUE. Otherwise, this
+ * will duplicate the string if it is not found in the pool.
+ *
+ * Return value: @poolv
+ **/
+EPoolv *
+e_poolv_set (EPoolv *poolv, int index, char *str, int freeit)
+{
+#ifdef POOLV_REFCNT
+ unsigned int ref;
+ char *key;
+#endif
+
+ p2(g_return_val_if_fail (poolv != NULL, NULL));
+
+ g_assert(index >=0 && index < poolv->length);
+
+ MPROBE(poolv);
+
+ p(printf("setting %d `%s'\n", index, str));
+
+ if (!str) {
+#ifdef POOLV_REFCNT
+ if (poolv->s[index]) {
+ if (g_hash_table_lookup_extended(poolv_pool, poolv->s[index], (void **)&key, (void **)&ref)) {
+ g_assert(ref > 0);
+ g_hash_table_insert(poolv_pool, key, (void *)(ref-1));
+ } else {
+ g_assert_not_reached();
+ }
+ }
+#endif
+ poolv->s[index] = NULL;
+ return poolv;
+ }
+
+#ifdef G_THREADS_ENABLED
+ g_static_mutex_lock(&poolv_mutex);
+#endif
+
+#ifdef POOLV_REFCNT
+ if (g_hash_table_lookup_extended(poolv_pool, str, (void **)&key, (void **)&ref)) {
+ g_hash_table_insert(poolv_pool, key, (void *)(ref+1));
+ poolv->s[index] = key;
+# ifdef PROFILE_POOLV
+ poolv_hits++;
+ poolv_profile_update ();
+# endif
+ } else {
+# ifdef PROFILE_POOLV
+ poolv_misses++;
+ poolv_mem += strlen(str);
+ poolv_profile_update ();
+# endif
+ poolv->s[index] = e_mempool_strdup(poolv_mempool, str);
+ g_hash_table_insert(poolv_pool, poolv->s[index], (void *)1);
+ }
+
+#else /* !POOLV_REFCNT */
+ if ((poolv->s[index] = g_hash_table_lookup(poolv_pool, str)) != NULL) {
+# ifdef PROFILE_POOLV
+ poolv_hits++;
+ poolv_profile_update ();
+# endif
+ } else {
+# ifdef PROFILE_POOLV
+ poolv_misses++;
+ poolv_mem += strlen(str);
+ poolv_profile_update ();
+# endif
+ poolv->s[index] = e_mempool_strdup(poolv_mempool, str);
+ g_hash_table_insert(poolv_pool, poolv->s[index], poolv->s[index]);
+ }
+#endif /* !POOLV_REFCNT */
+
+#ifdef G_THREADS_ENABLED
+ g_static_mutex_unlock(&poolv_mutex);
+#endif
+
+ if (freeit)
+ g_free(str);
+
+ return poolv;
+}
+
+/**
+ * e_poolv_get:
+ * @poolv: pooled string vector
+ * @index: index in vector of string
+ *
+ * Retrieve a string by index. This could possibly just be a macro.
+ *
+ * Since the pool is never freed, this string does not need to be
+ * duplicated, but should not be modified.
+ *
+ * Return value: string at that index.
+ **/
+const char *
+e_poolv_get(EPoolv *poolv, int index)
+{
+ g_assert(poolv != NULL);
+ g_assert(index>= 0 && index < poolv->length);
+
+ MPROBE(poolv);
+
+ p(printf("get %d = `%s'\n", index, poolv->s[index]));
+
+ return poolv->s[index]?poolv->s[index]:"";
+}
+
+/**
+ * e_poolv_destroy:
+ * @poolv: pooled string vector to free
+ *
+ * Free a pooled string vector. This doesn't free the strings from
+ * the vector, however.
+ **/
+void
+e_poolv_destroy(EPoolv *poolv)
+{
+#ifdef POOLV_REFCNT
+ int i;
+ unsigned int ref;
+ char *key;
+
+ MPROBE(poolv);
+
+#ifdef G_THREADS_ENABLED
+ g_static_mutex_lock(&poolv_mutex);
+#endif
+
+#ifdef MALLOC_CHECK
+ for (i=0;i<poolv_table->len;i++)
+ MPROBE(poolv_table->pdata[i]);
+
+ g_ptr_array_remove_fast(poolv_table, poolv);
+#endif
+
+ for (i=0;i<poolv->length;i++) {
+ if (poolv->s[i]) {
+ if (g_hash_table_lookup_extended(poolv_pool, poolv->s[i], (void **)&key, (void **)&ref)) {
+ /* if ref == 1 free it */
+ g_assert(ref > 0);
+ g_hash_table_insert(poolv_pool, key, (void *)(ref-1));
+ } else {
+ g_assert_not_reached();
+ }
+ }
+ }
+#ifdef G_THREADS_ENABLED
+ g_static_mutex_unlock(&poolv_mutex);
+#endif
+#endif
+
+#ifdef PROFILE_POOLV
+ poolv_count++;
+#endif
+ g_free(poolv);
+}
+
+#if 0
+
+#define CHUNK_SIZE (20)
+#define CHUNK_COUNT (32)
+
+#define s(x)
+
+main()
+{
+ int i;
+ MemChunk *mc;
+ void *mem, *last;
+ GMemChunk *gmc;
+ struct _EStrv *s;
+
+ s = strv_new(8);
+ s = strv_set(s, 1, "Testing 1");
+ s = strv_set(s, 2, "Testing 2");
+ s = strv_set(s, 3, "Testing 3");
+ s = strv_set(s, 4, "Testing 4");
+ s = strv_set(s, 5, "Testing 5");
+ s = strv_set(s, 6, "Testing 7");
+
+ for (i=0;i<8;i++) {
+ printf("s[%d] = %s\n", i, strv_get(s, i));
+ }
+
+ s(sleep(5));
+
+ printf("packing ...\n");
+ s = strv_pack(s);
+
+ for (i=0;i<8;i++) {
+ printf("s[%d] = %s\n", i, strv_get(s, i));
+ }
+
+ printf("setting ...\n");
+
+ s = strv_set_ref(s, 1, "Testing 1 x");
+
+ for (i=0;i<8;i++) {
+ printf("s[%d] = %s\n", i, strv_get(s, i));
+ }
+
+ printf("packing ...\n");
+ s = strv_pack(s);
+
+ for (i=0;i<8;i++) {
+ printf("s[%d] = %s\n", i, strv_get(s, i));
+ }
+
+ strv_free(s);
+
+#if 0
+ time_start("Using memchunks");
+ mc = memchunk_new(CHUNK_COUNT, CHUNK_SIZE);
+ for (i=0;i<1000000;i++) {
+ mem = memchunk_alloc(mc);
+ if ((i & 1) == 0)
+ memchunk_free(mc, mem);
+ }
+ s(sleep(10));
+ memchunk_destroy(mc);
+ time_end("allocating 1000000 memchunks, freeing 500k");
+
+ time_start("Using gmemchunks");
+ gmc = g_mem_chunk_new("memchunk", CHUNK_SIZE, CHUNK_SIZE*CHUNK_COUNT, G_ALLOC_AND_FREE);
+ for (i=0;i<1000000;i++) {
+ mem = g_mem_chunk_alloc(gmc);
+ if ((i & 1) == 0)
+ g_mem_chunk_free(gmc, mem);
+ }
+ s(sleep(10));
+ g_mem_chunk_destroy(gmc);
+ time_end("allocating 1000000 gmemchunks, freeing 500k");
+
+ time_start("Using memchunks");
+ mc = memchunk_new(CHUNK_COUNT, CHUNK_SIZE);
+ for (i=0;i<1000000;i++) {
+ mem = memchunk_alloc(mc);
+ }
+ s(sleep(10));
+ memchunk_destroy(mc);
+ time_end("allocating 1000000 memchunks");
+
+ time_start("Using gmemchunks");
+ gmc = g_mem_chunk_new("memchunk", CHUNK_SIZE, CHUNK_COUNT*CHUNK_SIZE, G_ALLOC_ONLY);
+ for (i=0;i<1000000;i++) {
+ mem = g_mem_chunk_alloc(gmc);
+ }
+ s(sleep(10));
+ g_mem_chunk_destroy(gmc);
+ time_end("allocating 1000000 gmemchunks");
+
+ time_start("Using malloc");
+ for (i=0;i<1000000;i++) {
+ malloc(CHUNK_SIZE);
+ }
+ time_end("allocating 1000000 malloc");
+#endif
+
+}
+
+#endif
diff --git a/e-util/e-passwords.c b/e-util/e-passwords.c
index a3719726d9..6fe405ee50 100644
--- a/e-util/e-passwords.c
+++ b/e-util/e-passwords.c
@@ -51,7 +51,7 @@
#include <gtk/gtkmessagedialog.h>
#include "e-passwords.h"
-#include "libedataserver/e-msgport.h"
+#include "e-msgport.h"
#include "widgets/misc/e-error.h"
#ifndef ENABLE_THREADS
@@ -420,7 +420,6 @@ ep_ask_password(EPassMsg *msg)
GtkWidget *vbox;
int type = msg->flags & E_PASSWORDS_REMEMBER_MASK;
int noreply = msg->noreply;
- AtkObject *a11y;
msg->noreply = 1;
@@ -432,24 +431,17 @@ ep_ask_password(EPassMsg *msg)
"%s", msg->prompt);
gtk_window_set_title(GTK_WINDOW(password_dialog), msg->title);
- gtk_widget_ensure_style (GTK_WIDGET (password_dialog));
- gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (password_dialog)->vbox), 0);
- gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (password_dialog)->action_area), 12);
-
#if !GTK_CHECK_VERSION (2,4,0)
gtk_dialog_set_has_separator(password_dialog, FALSE);
#endif
gtk_dialog_set_default_response(password_dialog, GTK_RESPONSE_OK);
- vbox = gtk_vbox_new (FALSE, 12);
+ vbox = gtk_vbox_new (FALSE, 6);
gtk_widget_show (vbox);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (password_dialog)->vbox), vbox, TRUE, FALSE, 0);
- gtk_container_set_border_width((GtkContainer *)vbox, 12);
+ gtk_container_set_border_width((GtkContainer *)vbox, 6);
msg->entry = gtk_entry_new ();
-
- a11y = gtk_widget_get_accessible (msg->entry);
- atk_object_set_description (a11y, msg->prompt);
gtk_entry_set_visibility ((GtkEntry *)msg->entry, !(msg->flags & E_PASSWORDS_SECRET));
gtk_entry_set_activates_default((GtkEntry *)msg->entry, TRUE);
gtk_box_pack_start (GTK_BOX (vbox), msg->entry, TRUE, FALSE, 3);
diff --git a/e-util/e-sorter-array.c b/e-util/e-sorter-array.c
deleted file mode 100644
index ab1e748d9a..0000000000
--- a/e-util/e-sorter-array.c
+++ /dev/null
@@ -1,259 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-sorter-array.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <stdlib.h>
-#include <string.h>
-#include "gal/util/e-util.h"
-#include "e-sorter-array.h"
-
-#define d(x)
-
-#define PARENT_TYPE E_SORTER_TYPE
-
-#define INCREMENT_AMOUNT 100
-
-static ESorterClass *parent_class;
-
-static void esa_sort (ESorterArray *esa);
-static void esa_backsort (ESorterArray *esa);
-
-static gint esa_model_to_sorted (ESorter *sorter, int row);
-static gint esa_sorted_to_model (ESorter *sorter, int row);
-static void esa_get_model_to_sorted_array (ESorter *sorter, int **array, int *count);
-static void esa_get_sorted_to_model_array (ESorter *sorter, int **array, int *count);
-static gboolean esa_needs_sorting (ESorter *esa);
-
-#define ESA_NEEDS_SORTING(esa) (((ESorterArray *) (esa))->compare != NULL)
-
-static int
-esort_callback(const void *data1, const void *data2, gpointer user_data)
-{
- ESorterArray *esa = user_data;
- int ret_val;
- int int1, int2;
-
- int1 = *(int *)data1;
- int2 = *(int *)data2;
-
- ret_val = esa->compare (int1, int2, esa->closure);
- if (ret_val != 0)
- return ret_val;
-
- if (int1 < int2)
- return -1;
- if (int1 > int2)
- return 1;
- return 0;
-}
-
-static void
-esa_sort(ESorterArray *esa)
-{
- int rows;
- int i;
-
- if (esa->sorted)
- return;
-
- rows = esa->rows;
-
- esa->sorted = g_new(int, rows);
- for (i = 0; i < rows; i++)
- esa->sorted[i] = i;
-
- if (esa->compare)
- e_sort (esa->sorted, rows, sizeof(int), esort_callback, esa);
-}
-
-static void
-esa_backsort(ESorterArray *esa)
-{
- int i, rows;
-
- if (esa->backsorted)
- return;
-
- esa_sort(esa);
-
- rows = esa->rows;
-
- esa->backsorted = g_new0(int, rows);
-
- for (i = 0; i < rows; i++) {
- esa->backsorted[esa->sorted[i]] = i;
- }
-}
-
-
-static gint
-esa_model_to_sorted (ESorter *es, int row)
-{
- ESorterArray *esa = E_SORTER_ARRAY(es);
-
- g_return_val_if_fail(row >= 0, -1);
- g_return_val_if_fail(row < esa->rows, -1);
-
- if (ESA_NEEDS_SORTING(es))
- esa_backsort(esa);
-
- if (esa->backsorted)
- return esa->backsorted[row];
- else
- return row;
-}
-
-static gint
-esa_sorted_to_model (ESorter *es, int row)
-{
- ESorterArray *esa = (ESorterArray *) es;
-
- g_return_val_if_fail(row >= 0, -1);
- g_return_val_if_fail(row < esa->rows, -1);
-
- if (ESA_NEEDS_SORTING(es))
- esa_sort(esa);
-
- if (esa->sorted)
- return esa->sorted[row];
- else
- return row;
-}
-
-static void
-esa_get_model_to_sorted_array (ESorter *es, int **array, int *count)
-{
- ESorterArray *esa = E_SORTER_ARRAY(es);
- if (array || count) {
- esa_backsort(esa);
-
- if (array)
- *array = esa->backsorted;
- if (count)
- *count = esa->rows;
- }
-}
-
-static void
-esa_get_sorted_to_model_array (ESorter *es, int **array, int *count)
-{
- ESorterArray *esa = E_SORTER_ARRAY(es);
- if (array || count) {
- esa_sort(esa);
-
- if (array)
- *array = esa->sorted;
- if (count)
- *count = esa->rows;
- }
-}
-
-static gboolean
-esa_needs_sorting(ESorter *es)
-{
- ESorterArray *esa = E_SORTER_ARRAY(es);
- return esa->compare != NULL;
-}
-
-void
-e_sorter_array_clean(ESorterArray *esa)
-{
- g_free(esa->sorted);
- esa->sorted = NULL;
-
- g_free(esa->backsorted);
- esa->backsorted = NULL;
-}
-
-void
-e_sorter_array_set_count (ESorterArray *esa, int count)
-{
- e_sorter_array_clean (esa);
- esa->rows = count;
-}
-
-void
-e_sorter_array_append (ESorterArray *esa, int count)
-{
- int i;
- g_free(esa->backsorted);
- esa->backsorted = NULL;
-
- if (esa->sorted) {
- esa->sorted = g_renew(int, esa->sorted, esa->rows + count);
- for (i = 0; i < count; i++) {
- int value = esa->rows;
- size_t pos;
- e_bsearch (&value, esa->sorted, esa->rows, sizeof (int), esort_callback, esa, &pos, NULL);
- memmove (esa->sorted + pos + 1, esa->sorted + pos, sizeof (int) * (esa->rows - pos));
- esa->sorted[pos] = value;
- esa->rows ++;
- }
- } else {
- esa->rows += count;
- }
-}
-
-ESorterArray *
-e_sorter_array_construct (ESorterArray *esa,
- ECompareRowsFunc compare,
- gpointer closure)
-{
- esa->compare = compare;
- esa->closure = closure;
- return esa;
-}
-
-ESorterArray *
-e_sorter_array_new (ECompareRowsFunc compare, gpointer closure)
-{
- ESorterArray *esa = g_object_new (E_SORTER_ARRAY_TYPE, NULL);
-
- return e_sorter_array_construct (esa, compare, closure);
-}
-
-static void
-esa_class_init (ESorterArrayClass *klass)
-{
- ESorterClass *sorter_class = E_SORTER_CLASS(klass);
-
- parent_class = g_type_class_ref (PARENT_TYPE);
-
- sorter_class->model_to_sorted = esa_model_to_sorted ;
- sorter_class->sorted_to_model = esa_sorted_to_model ;
- sorter_class->get_model_to_sorted_array = esa_get_model_to_sorted_array ;
- sorter_class->get_sorted_to_model_array = esa_get_sorted_to_model_array ;
- sorter_class->needs_sorting = esa_needs_sorting ;
-}
-
-static void
-esa_init (ESorterArray *esa)
-{
- esa->rows = 0;
- esa->compare = NULL;
- esa->closure = NULL;
- esa->sorted = NULL;
- esa->backsorted = NULL;
-}
-
-E_MAKE_TYPE(e_sorter_array, "ESorterArray", ESorterArray, esa_class_init, esa_init, PARENT_TYPE)
diff --git a/e-util/e-sorter-array.h b/e-util/e-sorter-array.h
deleted file mode 100644
index 227e437443..0000000000
--- a/e-util/e-sorter-array.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-sorter-array.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_SORTER_ARRAY_H_
-#define _E_SORTER_ARRAY_H_
-
-#include <glib.h>
-#include <glib-object.h>
-#include <gal/util/e-sorter.h>
-
-G_BEGIN_DECLS
-
-#define E_SORTER_ARRAY_TYPE (e_sorter_array_get_type ())
-#define E_SORTER_ARRAY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_SORTER_ARRAY_TYPE, ESorterArray))
-#define E_SORTER_ARRAY_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_SORTER_ARRAY_TYPE, ESorterArrayClass))
-#define E_IS_SORTER_ARRAY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_SORTER_ARRAY_TYPE))
-#define E_IS_SORTER_ARRAY_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_SORTER_ARRAY_TYPE))
-
-#ifndef _E_COMPARE_ROWS_FUNC_H_
-#define _E_COMPARE_ROWS_FUNC_H_
-typedef int (*ECompareRowsFunc) (int row1,
- int row2,
- gpointer closure);
-#endif
-
-typedef struct {
- ESorter base;
-
- ECompareRowsFunc compare;
- gpointer closure;
-
- /* If needs_sorting is 0, then model_to_sorted and sorted_to_model are no-ops. */
- int *sorted;
- int *backsorted;
-
- int rows;
-} ESorterArray;
-
-typedef struct {
- ESorterClass parent_class;
-} ESorterArrayClass;
-
-GType e_sorter_array_get_type (void);
-ESorterArray *e_sorter_array_construct (ESorterArray *sorter,
- ECompareRowsFunc compare,
- gpointer closure);
-ESorterArray *e_sorter_array_new (ECompareRowsFunc compare,
- gpointer closure);
-void e_sorter_array_clean (ESorterArray *esa);
-void e_sorter_array_set_count (ESorterArray *esa,
- int count);
-void e_sorter_array_append (ESorterArray *esa,
- int count);
-
-G_END_DECLS
-
-#endif /* _E_SORTER_ARRAY_H_ */
diff --git a/e-util/e-sorter.c b/e-util/e-sorter.c
deleted file mode 100644
index adee6d0d98..0000000000
--- a/e-util/e-sorter.c
+++ /dev/null
@@ -1,153 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-sorter.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <stdlib.h>
-#include <string.h>
-#include "gal/util/e-util.h"
-#include "e-sorter.h"
-
-#define d(x)
-
-#define PARENT_TYPE G_TYPE_OBJECT
-
-static GObjectClass *parent_class;
-
-static gint es_model_to_sorted (ESorter *es, int row);
-static gint es_sorted_to_model (ESorter *es, int row);
-static void es_get_model_to_sorted_array (ESorter *es, int **array, int *count);
-static void es_get_sorted_to_model_array (ESorter *es, int **array, int *count);
-static gboolean es_needs_sorting(ESorter *es);
-
-static void
-es_class_init (ESorterClass *klass)
-{
- parent_class = g_type_class_ref (PARENT_TYPE);
-
- klass->model_to_sorted = es_model_to_sorted;
- klass->sorted_to_model = es_sorted_to_model;
- klass->get_model_to_sorted_array = es_get_model_to_sorted_array;
- klass->get_sorted_to_model_array = es_get_sorted_to_model_array;
- klass->needs_sorting = es_needs_sorting;
-}
-
-static void
-es_init (ESorter *es)
-{
-}
-
-E_MAKE_TYPE(e_sorter, "ESorter", ESorter, es_class_init, es_init, PARENT_TYPE)
-
-ESorter *
-e_sorter_new (void)
-{
- ESorter *es = g_object_new (E_SORTER_TYPE, NULL);
-
- return es;
-}
-
-
-static gint
-es_model_to_sorted (ESorter *es, int row)
-{
- return row;
-}
-
-static gint
-es_sorted_to_model (ESorter *es, int row)
-{
- return row;
-}
-
-
-static void
-es_get_model_to_sorted_array (ESorter *es, int **array, int *count)
-{
-}
-
-static void
-es_get_sorted_to_model_array (ESorter *es, int **array, int *count)
-{
-}
-
-
-static gboolean
-es_needs_sorting(ESorter *es)
-{
- return FALSE;
-}
-
-gint
-e_sorter_model_to_sorted (ESorter *es, int row)
-{
- g_return_val_if_fail(es != NULL, -1);
- g_return_val_if_fail(row >= 0, -1);
-
- if (E_SORTER_GET_CLASS(es)->model_to_sorted)
- return E_SORTER_GET_CLASS(es)->model_to_sorted (es, row);
- else
- return -1;
-}
-
-gint
-e_sorter_sorted_to_model (ESorter *es, int row)
-{
- g_return_val_if_fail(es != NULL, -1);
- g_return_val_if_fail(row >= 0, -1);
-
- if (E_SORTER_GET_CLASS(es)->sorted_to_model)
- return E_SORTER_GET_CLASS(es)->sorted_to_model (es, row);
- else
- return -1;
-}
-
-
-void
-e_sorter_get_model_to_sorted_array (ESorter *es, int **array, int *count)
-{
- g_return_if_fail(es != NULL);
-
- if (E_SORTER_GET_CLASS(es)->get_model_to_sorted_array)
- E_SORTER_GET_CLASS(es)->get_model_to_sorted_array (es, array, count);
-}
-
-void
-e_sorter_get_sorted_to_model_array (ESorter *es, int **array, int *count)
-{
- g_return_if_fail(es != NULL);
-
- if (E_SORTER_GET_CLASS(es)->get_sorted_to_model_array)
- E_SORTER_GET_CLASS(es)->get_sorted_to_model_array (es, array, count);
-}
-
-
-gboolean
-e_sorter_needs_sorting(ESorter *es)
-{
- g_return_val_if_fail (es != NULL, FALSE);
-
- if (E_SORTER_GET_CLASS(es)->needs_sorting)
- return E_SORTER_GET_CLASS(es)->needs_sorting (es);
- else
- return FALSE;
-}
diff --git a/e-util/e-sorter.h b/e-util/e-sorter.h
deleted file mode 100644
index a70c2bd2d7..0000000000
--- a/e-util/e-sorter.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-sorter.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_SORTER_H_
-#define _E_SORTER_H_
-
-#include <glib-object.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-#define E_SORTER_TYPE (e_sorter_get_type ())
-#define E_SORTER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_SORTER_TYPE, ESorter))
-#define E_SORTER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_SORTER_TYPE, ESorterClass))
-#define E_IS_SORTER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_SORTER_TYPE))
-#define E_IS_SORTER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_SORTER_TYPE))
-#define E_SORTER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), E_SORTER_TYPE, ESorterClass))
-
-typedef struct {
- GObject base;
-} ESorter;
-
-typedef struct {
- GObjectClass parent_class;
- gint (*model_to_sorted) (ESorter *sorter,
- int row);
- gint (*sorted_to_model) (ESorter *sorter,
- int row);
-
- void (*get_model_to_sorted_array) (ESorter *sorter,
- int **array,
- int *count);
- void (*get_sorted_to_model_array) (ESorter *sorter,
- int **array,
- int *count);
-
- gboolean (*needs_sorting) (ESorter *sorter);
-} ESorterClass;
-
-GType e_sorter_get_type (void);
-ESorter *e_sorter_new (void);
-
-gint e_sorter_model_to_sorted (ESorter *sorter,
- int row);
-gint e_sorter_sorted_to_model (ESorter *sorter,
- int row);
-
-void e_sorter_get_model_to_sorted_array (ESorter *sorter,
- int **array,
- int *count);
-void e_sorter_get_sorted_to_model_array (ESorter *sorter,
- int **array,
- int *count);
-
-gboolean e_sorter_needs_sorting (ESorter *sorter);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* _E_SORTER_H_ */
diff --git a/e-util/e-text-event-processor-emacs-like.c b/e-util/e-text-event-processor-emacs-like.c
deleted file mode 100644
index 478dc2d68b..0000000000
--- a/e-util/e-text-event-processor-emacs-like.c
+++ /dev/null
@@ -1,495 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-text-event-processor-emacs-like.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <string.h>
-#include <gdk/gdkkeysyms.h>
-#include <gal/util/e-util.h>
-#include "e-text-event-processor-emacs-like.h"
-
-static void e_text_event_processor_emacs_like_init (ETextEventProcessorEmacsLike *card);
-static void e_text_event_processor_emacs_like_class_init (ETextEventProcessorEmacsLikeClass *klass);
-static gint e_text_event_processor_emacs_like_event (ETextEventProcessor *tep, ETextEventProcessorEvent *event);
-
-#define PARENT_TYPE E_TEXT_EVENT_PROCESSOR_TYPE
-static ETextEventProcessorClass *parent_class = NULL;
-
-/* The arguments we take */
-enum {
- ARG_0
-};
-
-static const ETextEventProcessorCommand control_keys[26] =
-{
- { E_TEP_START_OF_LINE, E_TEP_MOVE, 0, "" }, /* a */
- { E_TEP_BACKWARD_CHARACTER, E_TEP_MOVE, 0, "" }, /* b */
- { E_TEP_SELECTION, E_TEP_COPY, 0, "" }, /* c */
- { E_TEP_FORWARD_CHARACTER, E_TEP_DELETE, 0, "" }, /* d */
- { E_TEP_END_OF_LINE, E_TEP_MOVE, 0, "" }, /* e */
- { E_TEP_FORWARD_CHARACTER, E_TEP_MOVE, 0, "" }, /* f */
- { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* g */
- { E_TEP_BACKWARD_CHARACTER, E_TEP_DELETE, 0, "" }, /* h */
- { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* i */
- { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* j */
- { E_TEP_END_OF_LINE, E_TEP_DELETE, 0, "" }, /* k */
- { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* l */
- { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* m */
- { E_TEP_FORWARD_LINE, E_TEP_MOVE, 0, "" }, /* n */
- { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* o */
- { E_TEP_BACKWARD_LINE, E_TEP_MOVE, 0, "" }, /* p */
- { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* q */
- { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* r */
- { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* s */
- { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* t */
- { E_TEP_START_OF_LINE, E_TEP_DELETE, 0, "" }, /* u */
- { E_TEP_SELECTION, E_TEP_PASTE, 0, "" }, /* v */
- { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* w */
- { E_TEP_SELECTION, E_TEP_DELETE, 0, "" }, /* x */
- { E_TEP_SELECTION, E_TEP_PASTE, 0, "" }, /* y */
- { E_TEP_SELECTION, E_TEP_NOP, 0, "" } /* z */
-};
-
-static const ETextEventProcessorCommand alt_keys[26] =
-{
- { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* a */
- { E_TEP_BACKWARD_WORD, E_TEP_MOVE, 0, "" }, /* b */
- { E_TEP_SELECTION, E_TEP_CAPS, E_TEP_CAPS_TITLE, "" },/* c */
- { E_TEP_FORWARD_WORD, E_TEP_DELETE, 0, "" }, /* d */
- { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* e */
- { E_TEP_FORWARD_WORD, E_TEP_MOVE, 0, "" }, /* f */
- { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* g */
- { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* h */
- { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* i */
- { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* j */
- { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* k */
- { E_TEP_SELECTION, E_TEP_CAPS, E_TEP_CAPS_LOWER, "" }, /* l */
- { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* m */
- { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* n */
- { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* o */
- { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* p */
- { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* q */
- { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* r */
- { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* s */
- { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* t */
- { E_TEP_SELECTION, E_TEP_CAPS, E_TEP_CAPS_UPPER, "" }, /* u */
- { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* v */
- { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* w */
- { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* x */
- { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* y */
- { E_TEP_SELECTION, E_TEP_NOP, 0, "" } /* z */
-
-};
-
-E_MAKE_TYPE (e_text_event_processor_emacs_like,
- "ETextEventProcessorEmacsLike",
- ETextEventProcessorEmacsLike,
- e_text_event_processor_emacs_like_class_init,
- e_text_event_processor_emacs_like_init,
- PARENT_TYPE)
-
-static void
-e_text_event_processor_emacs_like_class_init (ETextEventProcessorEmacsLikeClass *klass)
-{
- ETextEventProcessorClass *processor_class;
-
- processor_class = (ETextEventProcessorClass*) klass;
-
- parent_class = g_type_class_ref (PARENT_TYPE);
-
- processor_class->event = e_text_event_processor_emacs_like_event;
-}
-
-static void
-e_text_event_processor_emacs_like_init (ETextEventProcessorEmacsLike *tep)
-{
-}
-
-static gint
-e_text_event_processor_emacs_like_event (ETextEventProcessor *tep, ETextEventProcessorEvent *event)
-{
- ETextEventProcessorCommand command;
- ETextEventProcessorEmacsLike *tep_el = E_TEXT_EVENT_PROCESSOR_EMACS_LIKE(tep);
- command.action = E_TEP_NOP;
- switch (event->type) {
- case GDK_BUTTON_PRESS:
- if (event->button.button == 1) {
- command.action = E_TEP_GRAB;
- command.time = event->button.time;
- g_signal_emit_by_name (tep, "command", &command);
- if (event->button.state & GDK_SHIFT_MASK)
- command.action = E_TEP_SELECT;
- else
- command.action = E_TEP_MOVE;
- command.position = E_TEP_VALUE;
- command.value = event->button.position;
- command.time = event->button.time;
- tep_el->mouse_down = TRUE;
- }
- break;
- case GDK_2BUTTON_PRESS:
- if (event->button.button == 1) {
- command.action = E_TEP_SELECT;
- command.position = E_TEP_SELECT_WORD;
- command.time = event->button.time;
- }
- break;
- case GDK_3BUTTON_PRESS:
- if (event->button.button == 1) {
- command.action = E_TEP_SELECT;
- command.position = E_TEP_SELECT_ALL;
- command.time = event->button.time;
- }
- break;
- case GDK_BUTTON_RELEASE:
- if (event->button.button == 1) {
- command.action = E_TEP_UNGRAB;
- command.time = event->button.time;
- tep_el->mouse_down = FALSE;
- } else if (event->button.button == 2) {
- command.action = E_TEP_MOVE;
- command.position = E_TEP_VALUE;
- command.value = event->button.position;
- command.time = event->button.time;
- g_signal_emit_by_name (tep, "command", &command);
-
- command.action = E_TEP_GET_SELECTION;
- command.position = E_TEP_SELECTION;
- command.value = 0;
- command.time = event->button.time;
- }
- break;
- case GDK_MOTION_NOTIFY:
- if (tep_el->mouse_down) {
- command.action = E_TEP_SELECT;
- command.position = E_TEP_VALUE;
- command.time = event->motion.time;
- command.value = event->motion.position;
- }
- break;
- case GDK_KEY_PRESS:
- {
- ETextEventProcessorEventKey key = event->key;
- command.time = event->key.time;
- if (key.state & GDK_SHIFT_MASK)
- command.action = E_TEP_SELECT;
- else if (key.state & GDK_MOD1_MASK)
- command.action = E_TEP_NOP;
- else
- command.action = E_TEP_MOVE;
- switch(key.keyval) {
- case GDK_Home:
- case GDK_KP_Home:
- if (key.state & GDK_CONTROL_MASK)
- command.position = E_TEP_START_OF_BUFFER;
- else
- command.position = E_TEP_START_OF_LINE;
- break;
- case GDK_End:
- case GDK_KP_End:
- if (key.state & GDK_CONTROL_MASK)
- command.position = E_TEP_END_OF_BUFFER;
- else
- command.position = E_TEP_END_OF_LINE;
- break;
- case GDK_Page_Up:
- case GDK_KP_Page_Up: command.position = E_TEP_BACKWARD_PAGE; break;
-
- case GDK_Page_Down:
- case GDK_KP_Page_Down: command.position = E_TEP_FORWARD_PAGE; break;
- /* CUA has Ctrl-Up/Ctrl-Down as paragraph up down */
- case GDK_Up:
- case GDK_KP_Up: command.position = E_TEP_BACKWARD_LINE; break;
-
- case GDK_Down:
- case GDK_KP_Down: command.position = E_TEP_FORWARD_LINE; break;
-
- case GDK_Left:
- case GDK_KP_Left:
- if (key.state & GDK_CONTROL_MASK)
- command.position = E_TEP_BACKWARD_WORD;
- else
- command.position = E_TEP_BACKWARD_CHARACTER;
- break;
- case GDK_Right:
- case GDK_KP_Right:
- if (key.state & GDK_CONTROL_MASK)
- command.position = E_TEP_FORWARD_WORD;
- else
- command.position = E_TEP_FORWARD_CHARACTER;
- break;
-
- case GDK_BackSpace:
- command.action = E_TEP_DELETE;
- if (key.state & GDK_CONTROL_MASK)
- command.position = E_TEP_BACKWARD_WORD;
- else
- command.position = E_TEP_BACKWARD_CHARACTER;
- break;
- case GDK_Clear:
- command.action = E_TEP_DELETE;
- command.position = E_TEP_END_OF_LINE;
- break;
- case GDK_Insert:
- case GDK_KP_Insert:
- if (key.state & GDK_SHIFT_MASK) {
- command.action = E_TEP_PASTE;
- command.position = E_TEP_SELECTION;
- } else if (key.state & GDK_CONTROL_MASK) {
- command.action = E_TEP_COPY;
- command.position = E_TEP_SELECTION;
- } else {
- /* gtk_toggle_insert(text) -- IMPLEMENT -- FIXME */
- }
- break;
- case GDK_Delete:
- case GDK_KP_Delete:
- if (key.state & GDK_CONTROL_MASK){
- command.action = E_TEP_DELETE;
- command.position = E_TEP_FORWARD_WORD;
- } else if (key.state & GDK_SHIFT_MASK) {
- command.action = E_TEP_COPY;
- command.position = E_TEP_SELECTION;
- g_signal_emit_by_name (tep, "command", &command);
-
- command.action = E_TEP_DELETE;
- command.position = E_TEP_SELECTION;
- } else {
- command.action = E_TEP_DELETE;
- command.position = E_TEP_FORWARD_CHARACTER;
- }
- break;
- case GDK_Tab:
- case GDK_KP_Tab:
- case GDK_ISO_Left_Tab:
- case GDK_3270_BackTab:
- /* Don't insert literally */
- command.action = E_TEP_NOP;
- command.position = E_TEP_SELECTION;
- break;
- case GDK_Return:
- case GDK_KP_Enter:
- if (tep->allow_newlines) {
- if (key.state & GDK_CONTROL_MASK) {
- command.action = E_TEP_ACTIVATE;
- command.position = E_TEP_SELECTION;
- } else {
- command.action = E_TEP_INSERT;
- command.position = E_TEP_SELECTION;
- command.value = 1;
- command.string = "\n";
- }
- } else {
- if (key.state & GDK_CONTROL_MASK) {
- command.action = E_TEP_NOP;
- command.position = E_TEP_SELECTION;
- } else {
- command.action = E_TEP_ACTIVATE;
- command.position = E_TEP_SELECTION;
- }
- }
- break;
- case GDK_Escape:
- /* Don't insert literally */
- command.action = E_TEP_NOP;
- command.position = E_TEP_SELECTION;
- break;
-
- case GDK_KP_Space:
- command.action = E_TEP_INSERT;
- command.position = E_TEP_SELECTION;
- command.value = 1;
- command.string = " ";
- break;
- case GDK_KP_Equal:
- command.action = E_TEP_INSERT;
- command.position = E_TEP_SELECTION;
- command.value = 1;
- command.string = "=";
- break;
- case GDK_KP_Multiply:
- command.action = E_TEP_INSERT;
- command.position = E_TEP_SELECTION;
- command.value = 1;
- command.string = "*";
- break;
- case GDK_KP_Add:
- command.action = E_TEP_INSERT;
- command.position = E_TEP_SELECTION;
- command.value = 1;
- command.string = "+";
- break;
- case GDK_KP_Subtract:
- command.action = E_TEP_INSERT;
- command.position = E_TEP_SELECTION;
- command.value = 1;
- command.string = "-";
- break;
- case GDK_KP_Decimal:
- command.action = E_TEP_INSERT;
- command.position = E_TEP_SELECTION;
- command.value = 1;
- command.string = ".";
- break;
- case GDK_KP_Divide:
- command.action = E_TEP_INSERT;
- command.position = E_TEP_SELECTION;
- command.value = 1;
- command.string = "/";
- break;
- case GDK_KP_0:
- command.action = E_TEP_INSERT;
- command.position = E_TEP_SELECTION;
- command.value = 1;
- command.string = "0";
- break;
- case GDK_KP_1:
- command.action = E_TEP_INSERT;
- command.position = E_TEP_SELECTION;
- command.value = 1;
- command.string = "1";
- break;
- case GDK_KP_2:
- command.action = E_TEP_INSERT;
- command.position = E_TEP_SELECTION;
- command.value = 1;
- command.string = "2";
- break;
- case GDK_KP_3:
- command.action = E_TEP_INSERT;
- command.position = E_TEP_SELECTION;
- command.value = 1;
- command.string = "3";
- break;
- case GDK_KP_4:
- command.action = E_TEP_INSERT;
- command.position = E_TEP_SELECTION;
- command.value = 1;
- command.string = "4";
- break;
- case GDK_KP_5:
- command.action = E_TEP_INSERT;
- command.position = E_TEP_SELECTION;
- command.value = 1;
- command.string = "5";
- break;
- case GDK_KP_6:
- command.action = E_TEP_INSERT;
- command.position = E_TEP_SELECTION;
- command.value = 1;
- command.string = "6";
- break;
- case GDK_KP_7:
- command.action = E_TEP_INSERT;
- command.position = E_TEP_SELECTION;
- command.value = 1;
- command.string = "7";
- break;
- case GDK_KP_8:
- command.action = E_TEP_INSERT;
- command.position = E_TEP_SELECTION;
- command.value = 1;
- command.string = "8";
- break;
- case GDK_KP_9:
- command.action = E_TEP_INSERT;
- command.position = E_TEP_SELECTION;
- command.value = 1;
- command.string = "9";
- break;
-
- default:
- if ((key.state & GDK_CONTROL_MASK) && !(key.state & GDK_MOD1_MASK)) {
- if ((key.keyval >= 'A') && (key.keyval <= 'Z'))
- key.keyval -= 'A' - 'a';
-
- if ((key.keyval >= 'a') && (key.keyval <= 'z')) {
- command.position = control_keys[(int) (key.keyval - 'a')].position;
- if (control_keys[(int) (key.keyval - 'a')].action != E_TEP_MOVE)
- command.action = control_keys[(int) (key.keyval - 'a')].action;
- command.value = control_keys[(int) (key.keyval - 'a')].value;
- command.string = control_keys[(int) (key.keyval - 'a')].string;
- }
-
- if (key.keyval == ' ') {
- command.action = E_TEP_NOP;
- }
-
- if (key.keyval == 'x') {
- command.action = E_TEP_COPY;
- command.position = E_TEP_SELECTION;
- g_signal_emit_by_name (tep, "command", &command);
-
- command.action = E_TEP_DELETE;
- command.position = E_TEP_SELECTION;
- }
-
- break;
- } else if ((key.state & GDK_MOD1_MASK) && !(key.state & GDK_CONTROL_MASK)) {
- if ((key.keyval >= 'A') && (key.keyval <= 'Z'))
- key.keyval -= 'A' - 'a';
-
- if ((key.keyval >= 'a') && (key.keyval <= 'z')) {
- command.position = alt_keys[(int) (key.keyval - 'a')].position;
- if (alt_keys[(int) (key.keyval - 'a')].action != E_TEP_MOVE)
- command.action = alt_keys[(int) (key.keyval - 'a')].action;
- command.value = alt_keys[(int) (key.keyval - 'a')].value;
- command.string = alt_keys[(int) (key.keyval - 'a')].string;
- }
- } else if (!(key.state & GDK_MOD1_MASK) && !(key.state & GDK_CONTROL_MASK) && key.length > 0) {
- if (key.keyval >= GDK_KP_0 && key.keyval <= GDK_KP_9) {
- key.keyval = '0';
- key.string = "0";
- }
- command.action = E_TEP_INSERT;
- command.position = E_TEP_SELECTION;
- command.value = strlen(key.string);
- command.string = key.string;
-
- } else {
- command.action = E_TEP_NOP;
- }
- }
- break;
- case GDK_KEY_RELEASE:
- command.time = event->key.time;
- command.action = E_TEP_NOP;
- break;
- default:
- command.action = E_TEP_NOP;
- break;
- }
- }
- if (command.action != E_TEP_NOP) {
- g_signal_emit_by_name (tep, "command", &command);
- return 1;
- }
- else
- return 0;
-}
-
-ETextEventProcessor *
-e_text_event_processor_emacs_like_new (void)
-{
- ETextEventProcessorEmacsLike *retval = g_object_new (E_TEXT_EVENT_PROCESSOR_EMACS_LIKE_TYPE, NULL);
- return E_TEXT_EVENT_PROCESSOR (retval);
-}
-
diff --git a/e-util/e-text-event-processor-emacs-like.h b/e-util/e-text-event-processor-emacs-like.h
deleted file mode 100644
index 1fd74dacfe..0000000000
--- a/e-util/e-text-event-processor-emacs-like.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-text-event-processor-emacs-like.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef __E_TEXT_EVENT_PROCESSOR_EMACS_LIKE_H__
-#define __E_TEXT_EVENT_PROCESSOR_EMACS_LIKE_H__
-
-#include <gal/util/e-text-event-processor.h>
-
-#ifdef __cplusplus
-extern "C" {
-#pragma }
-#endif /* __cplusplus */
-
-/* ETextEventProcessorEmacsLike - Turns events on a text widget into commands. Uses an emacs-ish interface.
- *
- */
-
-#define E_TEXT_EVENT_PROCESSOR_EMACS_LIKE_TYPE (e_text_event_processor_emacs_like_get_type ())
-#define E_TEXT_EVENT_PROCESSOR_EMACS_LIKE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TEXT_EVENT_PROCESSOR_EMACS_LIKE_TYPE, ETextEventProcessorEmacsLike))
-#define E_TEXT_EVENT_PROCESSOR_EMACS_LIKE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TEXT_EVENT_PROCESSOR_EMACS_LIKE_TYPE, ETextEventProcessorEmacsLikeClass))
-#define E_IS_TEXT_EVENT_PROCESSOR_EMACS_LIKE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TEXT_EVENT_PROCESSOR_EMACS_LIKE_TYPE))
-#define E_IS_TEXT_EVENT_PROCESSOR_EMACS_LIKE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), E_TEXT_EVENT_PROCESSOR_EMACS_LIKE_TYPE))
-
-
-typedef struct _ETextEventProcessorEmacsLike ETextEventProcessorEmacsLike;
-typedef struct _ETextEventProcessorEmacsLikeClass ETextEventProcessorEmacsLikeClass;
-
-struct _ETextEventProcessorEmacsLike
-{
- ETextEventProcessor parent;
-
- /* object specific fields */
- guint mouse_down : 1;
-};
-
-struct _ETextEventProcessorEmacsLikeClass
-{
- ETextEventProcessorClass parent_class;
-};
-
-
-GType e_text_event_processor_emacs_like_get_type (void);
-ETextEventProcessor *e_text_event_processor_emacs_like_new (void);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-
-#endif /* __E_TEXT_EVENT_PROCESSOR_EMACS_LIKE_H__ */
diff --git a/e-util/e-text-event-processor-types.h b/e-util/e-text-event-processor-types.h
deleted file mode 100644
index 5cb3f198d7..0000000000
--- a/e-util/e-text-event-processor-types.h
+++ /dev/null
@@ -1,132 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-text-event-processor-types.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef __E_TEXT_EVENT_PROCESSOR_TYPES_H__
-#define __E_TEXT_EVENT_PROCESSOR_TYPES_H__
-
-#include <glib/gmacros.h>
-
-G_BEGIN_DECLS
-
-#include <gdk/gdkevents.h>
-
-typedef union _ETextEventProcessorEvent ETextEventProcessorEvent;
-
-typedef enum {
- E_TEP_VALUE,
- E_TEP_SELECTION,
-
- E_TEP_START_OF_BUFFER,
- E_TEP_END_OF_BUFFER,
-
- E_TEP_START_OF_LINE,
- E_TEP_END_OF_LINE,
-
- E_TEP_FORWARD_CHARACTER,
- E_TEP_BACKWARD_CHARACTER,
-
- E_TEP_FORWARD_WORD,
- E_TEP_BACKWARD_WORD,
-
- E_TEP_FORWARD_LINE,
- E_TEP_BACKWARD_LINE,
-
- E_TEP_FORWARD_PARAGRAPH,
- E_TEP_BACKWARD_PARAGRAPH,
-
- E_TEP_FORWARD_PAGE,
- E_TEP_BACKWARD_PAGE,
-
- E_TEP_SELECT_WORD,
- E_TEP_SELECT_ALL
-
-} ETextEventProcessorCommandPosition;
-
-typedef enum {
- E_TEP_MOVE,
- E_TEP_SELECT,
- E_TEP_DELETE,
- E_TEP_INSERT,
-
- E_TEP_CAPS,
-
- E_TEP_COPY,
- E_TEP_PASTE,
- E_TEP_GET_SELECTION,
- E_TEP_SET_SELECT_BY_WORD,
- E_TEP_ACTIVATE,
-
- E_TEP_GRAB,
- E_TEP_UNGRAB,
-
- E_TEP_NOP
-} ETextEventProcessorCommandAction;
-
-typedef struct {
- ETextEventProcessorCommandPosition position;
- ETextEventProcessorCommandAction action;
- int value;
- char *string;
- guint32 time;
-} ETextEventProcessorCommand;
-
-typedef struct {
- GdkEventType type;
- guint32 time;
- guint state;
- guint button;
- gint position;
-} ETextEventProcessorEventButton;
-
-typedef struct {
- GdkEventType type;
- guint32 time;
- guint state;
- guint keyval;
- gint length;
- gchar *string;
-} ETextEventProcessorEventKey;
-
-typedef struct {
- GdkEventType type;
- guint32 time;
- guint state;
- gint position;
-} ETextEventProcessorEventMotion;
-
-union _ETextEventProcessorEvent {
- GdkEventType type;
- ETextEventProcessorEventButton button;
- ETextEventProcessorEventKey key;
- ETextEventProcessorEventMotion motion;
-};
-
-typedef enum _ETextEventProcessorCaps {
- E_TEP_CAPS_UPPER,
- E_TEP_CAPS_LOWER,
- E_TEP_CAPS_TITLE
-} ETextEventProcessorCaps;
-
-G_END_DECLS
-
-#endif /* __E_TEXT_EVENT_PROCESSOR_TYPES_H__ */
diff --git a/e-util/e-text-event-processor.c b/e-util/e-text-event-processor.c
deleted file mode 100644
index 6b974d894e..0000000000
--- a/e-util/e-text-event-processor.c
+++ /dev/null
@@ -1,148 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-text-event-processor.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include "e-text-event-processor.h"
-#include <gal/util/e-util.h>
-#include <gal/util/e-i18n.h>
-#include "gal/util/e-marshal.h"
-
-static void e_text_event_processor_init (ETextEventProcessor *card);
-static void e_text_event_processor_class_init (ETextEventProcessorClass *klass);
-
-static void e_text_event_processor_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec);
-static void e_text_event_processor_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec);
-
-#define PARENT_TYPE G_TYPE_OBJECT
-static GObjectClass *parent_class = NULL;
-
-/* The arguments we take */
-enum {
- PROP_0,
- PROP_ALLOW_NEWLINES
-};
-
-enum {
- E_TEP_EVENT,
- E_TEP_LAST_SIGNAL
-};
-
-static guint e_tep_signals[E_TEP_LAST_SIGNAL] = { 0 };
-
-E_MAKE_TYPE (e_text_event_processor,
- "ETextEventProcessor",
- ETextEventProcessor,
- e_text_event_processor_class_init,
- e_text_event_processor_init,
- PARENT_TYPE)
-
-static void
-e_text_event_processor_class_init (ETextEventProcessorClass *klass)
-{
- GObjectClass *object_class;
-
- object_class = (GObjectClass*) klass;
-
- parent_class = g_type_class_ref (PARENT_TYPE);
-
- object_class->set_property = e_text_event_processor_set_property;
- object_class->get_property = e_text_event_processor_get_property;
-
- e_tep_signals[E_TEP_EVENT] =
- g_signal_new ("command",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETextEventProcessorClass, command),
- NULL, NULL,
- e_marshal_NONE__POINTER,
- G_TYPE_NONE, 1,
- G_TYPE_POINTER);
-
- g_object_class_install_property (object_class, PROP_ALLOW_NEWLINES,
- g_param_spec_boolean ("allow_newlines",
- _( "Allow newlines" ),
- _( "Allow newlines" ),
- FALSE,
- G_PARAM_READWRITE));
-
- klass->event = NULL;
- klass->command = NULL;
-
-}
-
-static void
-e_text_event_processor_init (ETextEventProcessor *tep)
-{
- tep->allow_newlines = TRUE;
-}
-
-gint
-e_text_event_processor_handle_event (ETextEventProcessor *tep, ETextEventProcessorEvent *event)
-{
- if (E_TEXT_EVENT_PROCESSOR_GET_CLASS(tep)->event)
- return E_TEXT_EVENT_PROCESSOR_GET_CLASS(tep)->event(tep, event);
- else
- return 0;
-}
-
-/* Set_arg handler for the text item */
-static void
-e_text_event_processor_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- ETextEventProcessor *tep = E_TEXT_EVENT_PROCESSOR (object);
-
- switch (prop_id) {
- case PROP_ALLOW_NEWLINES:
- tep->allow_newlines = g_value_get_boolean (value);
- break;
- default:
- return;
- }
-}
-
-/* Get_arg handler for the text item */
-static void
-e_text_event_processor_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- ETextEventProcessor *tep = E_TEXT_EVENT_PROCESSOR (object);
-
- switch (prop_id) {
- case PROP_ALLOW_NEWLINES:
- g_value_set_boolean (value, tep->allow_newlines);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
diff --git a/e-util/e-text-event-processor.h b/e-util/e-text-event-processor.h
deleted file mode 100644
index 21f2550fde..0000000000
--- a/e-util/e-text-event-processor.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-text-event-processor.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef __E_TEXT_EVENT_PROCESSOR_H__
-#define __E_TEXT_EVENT_PROCESSOR_H__
-
-#include <glib.h>
-#include <gtk/gtkobject.h>
-#include <gal/util/e-text-event-processor-types.h>
-
-#ifdef __cplusplus
-extern "C" {
-#pragma }
-#endif /* __cplusplus */
-
-/* ETextEventProcessor - Turns events on a text widget into commands.
- *
- */
-
-#define E_TEXT_EVENT_PROCESSOR_TYPE (e_text_event_processor_get_type ())
-#define E_TEXT_EVENT_PROCESSOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TEXT_EVENT_PROCESSOR_TYPE, ETextEventProcessor))
-#define E_TEXT_EVENT_PROCESSOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TEXT_EVENT_PROCESSOR_TYPE, ETextEventProcessorClass))
-#define E_IS_TEXT_EVENT_PROCESSOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TEXT_EVENT_PROCESSOR_TYPE))
-#define E_IS_TEXT_EVENT_PROCESSOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), E_TEXT_EVENT_PROCESSOR_TYPE))
-#define E_TEXT_EVENT_PROCESSOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), E_TEXT_EVENT_PROCESSOR_TYPE, ETextEventProcessorClass))
-typedef struct _ETextEventProcessor ETextEventProcessor;
-typedef struct _ETextEventProcessorClass ETextEventProcessorClass;
-
-struct _ETextEventProcessor
-{
- GObject parent;
-
- /* object specific fields */
- guint allow_newlines : 1;
-};
-
-struct _ETextEventProcessorClass
-{
- GtkObjectClass parent_class;
-
- /* signals */
- void (* command) (ETextEventProcessor *tep, ETextEventProcessorCommand *command);
-
- /* virtual functions */
- gint (* event) (ETextEventProcessor *tep, ETextEventProcessorEvent *event);
-};
-
-
-GType e_text_event_processor_get_type (void);
-gint e_text_event_processor_handle_event (ETextEventProcessor *tep, ETextEventProcessorEvent *event);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-
-#endif /* __E_TEXT_EVENT_PROCESSOR_H__ */
diff --git a/e-util/e-url.c b/e-util/e-url.c
new file mode 100644
index 0000000000..6d43b11684
--- /dev/null
+++ b/e-util/e-url.c
@@ -0,0 +1,343 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * e-url.c
+ *
+ * Copyright (C) 2001 Ximian, Inc.
+ *
+ * Developed by Jon Trowbridge <trow@ximian.com>
+ * Rodrigo Moya <rodrigo@ximian.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA.
+ */
+
+#include <config.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include "e-url.h"
+
+char *
+e_url_shroud (const char *url)
+{
+ const char *first_colon = NULL;
+ const char *last_at = NULL;
+ const char *p;
+ char *shrouded;
+
+ if (url == NULL)
+ return NULL;
+
+ /* Skip past the moniker */
+ for (p = url; *p && *p != ':'; ++p);
+ if (*p)
+ ++p;
+
+ while (*p) {
+ if (first_colon == NULL && *p == ':')
+ first_colon = p;
+ if (*p == '@')
+ last_at = p;
+ ++p;
+ }
+
+ if (first_colon && last_at && first_colon < last_at) {
+ shrouded = g_malloc(first_colon - url + strlen(last_at)+1);
+ memcpy(shrouded, url, first_colon-url);
+ strcpy(shrouded + (first_colon-url), last_at);
+ } else {
+ shrouded = g_strdup (url);
+ }
+
+ return shrouded;
+}
+
+gboolean
+e_url_equal (const char *url1, const char *url2)
+{
+ char *shroud1 = e_url_shroud (url1);
+ char *shroud2 = e_url_shroud (url2);
+ gint len1, len2;
+ gboolean rv;
+
+ if (shroud1 == NULL || shroud2 == NULL) {
+ rv = (shroud1 == shroud2);
+ } else {
+ len1 = strlen (shroud1);
+ len2 = strlen (shroud2);
+
+ rv = !strncmp (shroud1, shroud2, MIN (len1, len2));
+ }
+
+ g_free (shroud1);
+ g_free (shroud2);
+
+ return rv;
+}
+
+#define HEXVAL(c) (isdigit (c) ? (c) - '0' : tolower (c) - 'a' + 10)
+
+static void
+uri_decode (char *part)
+{
+ guchar *s, *d;
+
+ s = d = (guchar *)part;
+ while (*s) {
+ if (*s == '%') {
+ if (isxdigit (s[1]) && isxdigit (s[2])) {
+ *d++ = HEXVAL (s[1]) * 16 + HEXVAL (s[2]);
+ s += 3;
+ } else
+ *d++ = *s++;
+ } else
+ *d++ = *s++;
+ }
+ *d = '\0';
+}
+
+EUri *
+e_uri_new (const char *uri_string)
+{
+ EUri *uri;
+ const char *end, *hash, *colon, *semi, *at, *slash, *question;
+ const char *p;
+
+ if (!uri_string)
+ return NULL;
+
+ uri = g_new0 (EUri, 1);
+
+ /* find fragment */
+ end = hash = strchr (uri_string, '#');
+ if (hash && hash[1]) {
+ uri->fragment = g_strdup (hash + 1);
+ uri_decode (uri->fragment);
+ }
+ else
+ end = uri_string + strlen (uri_string);
+
+ /* find protocol: initial [a-z+.-]* substring until ":" */
+ p = uri_string;
+ while (p < end && (isalnum ((unsigned char) *p) ||
+ *p == '.' || *p == '+' || *p == '-'))
+ p++;
+
+ if (p > uri_string && *p == ':') {
+ uri->protocol = g_ascii_strdown (uri_string, p - uri_string);
+ uri_string = p + 1;
+ }
+ else
+ uri->protocol = g_strdup ("file");
+
+ if (!*uri_string)
+ return uri;
+
+ /* check for authority */
+ if (strncmp (uri_string, "//", 2) == 0) {
+ uri_string += 2;
+
+ slash = uri_string + strcspn (uri_string, "/#");
+ at = strchr (uri_string, '@');
+ if (at && at < slash) {
+ colon = strchr (uri_string, ':');
+ if (colon && colon < at) {
+ uri->passwd = g_strndup (colon + 1, at - colon - 1);
+ uri_decode (uri->passwd);
+ }
+ else {
+ uri->passwd = NULL;
+ colon = at;
+ }
+
+ semi = strchr (uri_string, ';');
+ if (semi && semi < colon &&
+ !strncasecmp (semi, ";auth=", 6)) {
+ uri->authmech = g_strndup (semi + 6, colon - semi - 6);
+ uri_decode (uri->authmech);
+ }
+ else {
+ uri->authmech = NULL;
+ semi = colon;
+ }
+
+ uri->user = g_strndup (uri_string, semi - uri_string);
+ uri_decode (uri->user);
+ uri_string = at + 1;
+ }
+ else
+ uri->user = uri->passwd = uri->authmech = NULL;
+
+ /* find host and port */
+ colon = strchr (uri_string, ':');
+ if (colon && colon < slash) {
+ uri->host = g_strndup (uri_string, colon - uri_string);
+ uri->port = strtoul (colon + 1, NULL, 10);
+ }
+ else {
+ uri->host = g_strndup (uri_string, slash - uri_string);
+ uri_decode (uri->host);
+ uri->port = 0;
+ }
+
+ uri_string = slash;
+ }
+
+ /* find query */
+ question = memchr (uri_string, '?', end - uri_string);
+ if (question) {
+ if (question[1]) {
+ uri->query = g_strndup (question + 1, end - (question + 1));
+ uri_decode (uri->query);
+ }
+ end = question;
+ }
+
+ /* find parameters */
+ semi = memchr (uri_string, ';', end - uri_string);
+ if (semi) {
+ if (semi[1]) {
+ const char *cur, *p, *eq;
+ char *name, *value;
+
+ for (cur = semi + 1; cur < end; cur = p + 1) {
+ p = memchr (cur, ';', end - cur);
+ if (!p)
+ p = end;
+ eq = memchr (cur, '=', p - cur);
+ if (eq) {
+ name = g_strndup (cur, eq - cur);
+ value = g_strndup (eq + 1, p - (eq + 1));
+ uri_decode (value);
+ } else {
+ name = g_strndup (cur, p - cur);
+ value = g_strdup ("");
+ }
+ uri_decode (name);
+ g_datalist_set_data_full (&uri->params, name,
+ value, g_free);
+ g_free (name);
+ }
+ }
+ end = semi;
+ }
+
+ if (end != uri_string) {
+ uri->path = g_strndup (uri_string, end - uri_string);
+ uri_decode (uri->path);
+ }
+
+ return uri;
+}
+
+void
+e_uri_free (EUri *uri)
+{
+ if (uri) {
+ g_free (uri->protocol);
+ g_free (uri->user);
+ g_free (uri->authmech);
+ g_free (uri->passwd);
+ g_free (uri->host);
+ g_free (uri->path);
+ g_datalist_clear (&uri->params);
+ g_free (uri->query);
+ g_free (uri->fragment);
+
+ g_free (uri);
+ }
+}
+
+const char *
+e_uri_get_param (EUri *uri, const char *name)
+{
+ return g_datalist_get_data (&uri->params, name);
+}
+
+static void
+copy_param_cb (GQuark key_id, gpointer data, gpointer user_data)
+{
+ GData *params = (GData *) user_data;
+
+ g_datalist_id_set_data_full (&params, key_id, g_strdup (data), g_free);
+}
+
+EUri *
+e_uri_copy (EUri *uri)
+{
+ EUri *uri_copy;
+
+ g_return_val_if_fail (uri != NULL, NULL);
+
+ uri_copy = g_new0 (EUri, 1);
+ uri_copy->protocol = g_strdup (uri->protocol);
+ uri_copy->user = g_strdup (uri->user);
+ uri_copy->authmech = g_strdup (uri->authmech);
+ uri_copy->passwd = g_strdup (uri->passwd);
+ uri_copy->host = g_strdup (uri->host);
+ uri_copy->port = uri->port;
+ uri_copy->path = g_strdup (uri->path);
+ uri_copy->query = g_strdup (uri->query);
+ uri_copy->fragment = g_strdup (uri->fragment);
+
+ /* copy uri->params */
+ g_datalist_foreach (&uri->params,
+ (GDataForeachFunc) copy_param_cb,
+ &uri_copy->params);
+
+ return uri_copy;
+}
+
+char *
+e_uri_to_string (EUri *uri, gboolean show_password)
+{
+ char *str_uri = NULL;
+
+ g_return_val_if_fail (uri != NULL, NULL);
+
+ if (uri->port != 0)
+ str_uri = g_strdup_printf (
+ "%s://%s%s%s%s%s%s%s:%d%s%s%s",
+ uri->protocol,
+ uri->user ? uri->user : "",
+ uri->authmech ? ";auth=" : "",
+ uri->authmech ? uri->authmech : "",
+ uri->passwd && show_password ? ":" : "",
+ uri->passwd && show_password ? uri->passwd : "",
+ uri->user ? "@" : "",
+ uri->host ? uri->host : "",
+ uri->port,
+ uri->path ? uri->path : "",
+ uri->query ? "?" : "",
+ uri->query ? uri->query : "");
+ else
+ str_uri = g_strdup_printf(
+ "%s://%s%s%s%s%s%s%s%s%s%s",
+ uri->protocol,
+ uri->user ? uri->user : "",
+ uri->authmech ? ";auth=" : "",
+ uri->authmech ? uri->authmech : "",
+ uri->passwd && show_password ? ":" : "",
+ uri->passwd && show_password ? uri->passwd : "",
+ uri->user ? "@" : "",
+ uri->host ? uri->host : "",
+ uri->path ? uri->path : "",
+ uri->query ? "?" : "",
+ uri->query ? uri->query : "");
+
+ return str_uri;
+}
diff --git a/e-util/e-util.c b/e-util/e-util.c
deleted file mode 100644
index 2514cfc931..0000000000
--- a/e-util/e-util.c
+++ /dev/null
@@ -1,1230 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-util.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include "e-util.h"
-#include "e-i18n.h"
-
-#include <glib.h>
-#include <gtk/gtkobject.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <ctype.h>
-#include <sys/stat.h>
-#include <string.h>
-#include <locale.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <time.h>
-#include <libgnome/gnome-util.h>
-#include <math.h>
-
-#if 0
-#include <libgnomevfs/gnome-vfs.h>
-#endif
-
-int
-g_str_compare (const void *x, const void *y)
-{
- if (x == NULL || y == NULL) {
- if (x == y)
- return 0;
- else
- return x ? -1 : 1;
- }
-
- return strcmp (x, y);
-}
-
-int
-g_collate_compare (const void *x, const void *y)
-{
- if (x == NULL || y == NULL) {
- if (x == y)
- return 0;
- else
- return x ? -1 : 1;
- }
-
- return g_utf8_collate (x, y);
-}
-
-int
-g_int_compare (const void *x, const void *y)
-{
- if (GPOINTER_TO_INT (x) < GPOINTER_TO_INT (y))
- return -1;
- else if (GPOINTER_TO_INT (x) == GPOINTER_TO_INT (y))
- return 0;
- else
- return 1;
-}
-
-char *
-e_strdup_strip(const char *string)
-{
- int i;
- int length = 0;
- int initial = 0;
- for ( i = 0; string[i]; i++ ) {
- if (initial == i && isspace((unsigned char) string[i])) {
- initial ++;
- }
- if (!isspace((unsigned char) string[i])) {
- length = i - initial + 1;
- }
- }
- return g_strndup(string + initial, length);
-}
-
-void
-e_free_object_list (GList *list)
-{
- GList *p;
-
- for (p = list; p != NULL; p = p->next)
- g_object_unref (p->data);
-
- g_list_free (list);
-}
-
-void
-e_free_object_slist (GSList *list)
-{
- GSList *p;
-
- for (p = list; p != NULL; p = p->next)
- g_object_unref (p->data);
-
- g_slist_free (list);
-}
-
-void
-e_free_string_list (GList *list)
-{
- GList *p;
-
- for (p = list; p != NULL; p = p->next)
- g_free (p->data);
-
- g_list_free (list);
-}
-
-void
-e_free_string_slist (GSList *list)
-{
- GSList *p;
-
- for (p = list; p != NULL; p = p->next)
- g_free (p->data);
- g_slist_free (list);
-}
-
-#define BUFF_SIZE 1024
-
-char *
-e_read_file(const char *filename)
-{
- int fd;
- char buffer[BUFF_SIZE];
- GList *list = NULL, *list_iterator;
- GList *lengths = NULL, *lengths_iterator;
- int length = 0;
- int bytes;
- char *ret_val;
-
- fd = open(filename, O_RDONLY);
- if (fd == -1)
- return NULL;
- bytes = read(fd, buffer, BUFF_SIZE);
- while (bytes) {
- if (bytes > 0) {
- char *temp = g_malloc(bytes);
- memcpy (temp, buffer, bytes);
- list = g_list_prepend(list, temp);
- lengths = g_list_prepend(lengths, GINT_TO_POINTER(bytes));
- length += bytes;
- } else {
- if (errno != EINTR) {
- close(fd);
- g_list_foreach(list, (GFunc) g_free, NULL);
- g_list_free(list);
- g_list_free(lengths);
- return NULL;
- }
- }
- bytes = read(fd, buffer, BUFF_SIZE);
- }
- ret_val = g_new(char, length + 1);
- ret_val[length] = 0;
- lengths_iterator = lengths;
- list_iterator = list;
- for ( ; list_iterator; list_iterator = list_iterator->next, lengths_iterator = lengths_iterator->next) {
- int this_length = GPOINTER_TO_INT(lengths_iterator->data);
- length -= this_length;
- memcpy(ret_val + length, list_iterator->data, this_length);
- }
- close(fd);
- g_list_foreach(list, (GFunc) g_free, NULL);
- g_list_free(list);
- g_list_free(lengths);
- return ret_val;
-}
-
-gint
-e_write_file(const char *filename, const char *data, int flags)
-{
- int fd;
- int length = strlen(data);
- int bytes;
- fd = open(filename, flags | O_WRONLY, 0666);
- if (fd == -1)
- return errno;
- while (length > 0) {
- bytes = write(fd, data, length);
- if (bytes > 0) {
- length -= bytes;
- data += bytes;
- } else {
- if (errno != EINTR && errno != EAGAIN) {
- int save_errno = errno;
- close(fd);
- return save_errno;
- }
- }
- }
- if (close(fd) != 0) {
- return errno;
- }
- return 0;
-}
-
-gint
-e_write_file_mkstemp(char *filename, const char *data)
-{
- int fd;
- int length = strlen(data);
- int bytes;
- fd = mkstemp (filename);
- if (fd == -1)
- return errno;
- while (length > 0) {
- bytes = write(fd, data, length);
- if (bytes > 0) {
- length -= bytes;
- data += bytes;
- } else {
- if (errno != EINTR && errno != EAGAIN) {
- int save_errno = errno;
- close(fd);
- return save_errno;
- }
- }
- }
- if (close(fd) != 0) {
- return errno;
- }
- return 0;
-}
-
-/**
- * e_mkdir_hier:
- * @path: a directory path
- * @mode: a mode, as for mkdir(2)
- *
- * This creates the named directory with the given @mode, creating
- * any necessary intermediate directories (with the same @mode).
- *
- * Return value: 0 on success, -1 on error, in which case errno will
- * be set as for mkdir(2).
- **/
-int
-e_mkdir_hier(const char *path, mode_t mode)
-{
- char *copy, *p;
-
- if (path[0] == '/') {
- p = copy = g_strdup (path);
- } else {
- gchar *current_dir = g_get_current_dir();
- p = copy = g_concat_dir_and_file (current_dir, path);
- }
-
- do {
- p = strchr (p + 1, '/');
- if (p)
- *p = '\0';
- if (access (copy, F_OK) == -1) {
- if (mkdir (copy, mode) == -1) {
- g_free (copy);
- return -1;
- }
- }
- if (p)
- *p = '/';
- } while (p);
-
- g_free (copy);
- return 0;
-}
-
-#if 0
-char *
-e_read_uri(const char *uri)
-{
- GnomeVFSHandle *handle;
- GList *list = NULL, *list_iterator;
- GList *lengths = NULL, *lengths_iterator;
- gchar buffer[1025];
- gchar *ret_val;
- int length = 0;
- GnomeVFSFileSize bytes;
-
- gnome_vfs_open(&handle, uri, GNOME_VFS_OPEN_READ);
-
- gnome_vfs_read(handle, buffer, 1024, &bytes);
- while (bytes) {
- if (bytes) {
- char *temp = g_malloc(bytes);
- memcpy (temp, buffer, bytes);
- list = g_list_prepend(list, temp);
- lengths = g_list_prepend(lengths, GINT_TO_POINTER((gint) bytes));
- length += bytes;
- }
- gnome_vfs_read(handle, buffer, 1024, &bytes);
- }
-
- ret_val = g_new(char, length + 1);
- ret_val[length] = 0;
- lengths_iterator = lengths;
- list_iterator = list;
- for ( ; list_iterator; list_iterator = list_iterator->next, lengths_iterator = lengths_iterator->next) {
- int this_length = GPOINTER_TO_INT(lengths_iterator->data);
- length -= this_length;
- memcpy(ret_val + length, list_iterator->data, this_length);
- }
- gnome_vfs_close(handle);
- g_list_foreach(list, (GFunc) g_free, NULL);
- g_list_free(list);
- g_list_free(lengths);
- return ret_val;
-}
-#endif
-
-/* Include build marshalers */
-
-#include "e-marshal.h"
-#include "e-marshal.c"
-
-gchar**
-e_strsplit (const gchar *string,
- const gchar *delimiter,
- gint max_tokens)
-{
- GSList *string_list = NULL, *slist;
- gchar **str_array, *s;
- guint i, n = 1;
-
- g_return_val_if_fail (string != NULL, NULL);
- g_return_val_if_fail (delimiter != NULL, NULL);
-
- if (max_tokens < 1)
- max_tokens = G_MAXINT;
-
- s = strstr (string, delimiter);
- if (s)
- {
- guint delimiter_len = strlen (delimiter);
-
- do
- {
- guint len;
- gchar *new_string;
-
- len = s - string;
- new_string = g_new (gchar, len + 1);
- strncpy (new_string, string, len);
- new_string[len] = 0;
- string_list = g_slist_prepend (string_list, new_string);
- n++;
- string = s + delimiter_len;
- s = strstr (string, delimiter);
- }
- while (--max_tokens && s);
- }
-
- n++;
- string_list = g_slist_prepend (string_list, g_strdup (string));
-
- str_array = g_new (gchar*, n);
-
- i = n - 1;
-
- str_array[i--] = NULL;
- for (slist = string_list; slist; slist = slist->next)
- str_array[i--] = slist->data;
-
- g_slist_free (string_list);
-
- return str_array;
-}
-
-gchar *
-e_strstrcase (const gchar *haystack, const gchar *needle)
-{
- /* find the needle in the haystack neglecting case */
- const gchar *ptr;
- guint len;
-
- g_return_val_if_fail (haystack != NULL, NULL);
- g_return_val_if_fail (needle != NULL, NULL);
-
- len = strlen(needle);
- if (len > strlen(haystack))
- return NULL;
-
- if (len == 0)
- return (gchar *) haystack;
-
- for (ptr = haystack; *(ptr + len - 1) != '\0'; ptr++)
- if (!g_strncasecmp (ptr, needle, len))
- return (gchar *) ptr;
-
- return NULL;
-}
-
-/* This only makes a filename safe for usage as a filename. It still may have shell meta-characters in it. */
-void
-e_filename_make_safe (gchar *string)
-{
- gchar *p, *ts;
- gunichar c;
-
- g_return_if_fail (string != NULL);
- p = string;
-
- while(p && *p) {
- c = g_utf8_get_char (p);
- ts = p;
- p = g_utf8_next_char (p);
- if (!g_unichar_isprint(c) || ( c < 0xff && strchr (" /'\"`&();|<>$%{}!", c&0xff ))) {
- while (ts<p)
- *ts++ = '_';
- }
- }
-}
-
-static gint
-epow10 (gint number) {
- gint value;
-
- for (value = 1; number > 0; number --) {
- value *= 10;
- }
- return value;
-}
-
-gchar *
-e_format_number (gint number)
-{
- GList *iterator, *list = NULL;
- struct lconv *locality;
- gint char_length = 0;
- gint group_count = 0;
- guchar *grouping;
- int last_count = 3;
- int divider;
- char *value;
- char *value_iterator;
-
- locality = localeconv();
- grouping = locality->grouping;
- while (number) {
- char *group;
- switch (*grouping) {
- default:
- last_count = *grouping;
- grouping++;
- case 0:
- divider = epow10(last_count);
- if (number >= divider) {
- group = g_strdup_printf("%0*d", last_count, number % divider);
- } else {
- group = g_strdup_printf("%d", number % divider);
- }
- number /= divider;
- break;
- case CHAR_MAX:
- group = g_strdup_printf("%d", number);
- number = 0;
- break;
- }
- char_length += strlen(group);
- list = g_list_prepend(list, group);
- group_count ++;
- }
-
- if (list) {
- value = g_new(char, 1 + char_length + (group_count - 1) * strlen(locality->thousands_sep));
-
- iterator = list;
- value_iterator = value;
-
- strcpy(value_iterator, iterator->data);
- value_iterator += strlen(iterator->data);
- for (iterator = iterator->next; iterator; iterator = iterator->next) {
- strcpy(value_iterator, locality->thousands_sep);
- value_iterator += strlen(locality->thousands_sep);
-
- strcpy(value_iterator, iterator->data);
- value_iterator += strlen(iterator->data);
- }
- e_free_string_list (list);
- return value;
- } else {
- return g_strdup("0");
- }
-}
-
-static gchar *
-do_format_number_as_float (double number)
-{
- GList *iterator, *list = NULL;
- struct lconv *locality;
- gint char_length = 0;
- gint group_count = 0;
- guchar *grouping;
- int last_count = 3;
- int divider;
- char *value;
- char *value_iterator;
- double fractional;
-
- locality = localeconv();
- grouping = locality->grouping;
- while (number >= 1.0) {
- char *group;
- switch (*grouping) {
- default:
- last_count = *grouping;
- grouping++;
- /* Fall through */
- case 0:
- divider = epow10(last_count);
- number /= divider;
- fractional = modf (number, &number);
- fractional *= divider;
- fractional = floor (fractional);
-
- if (number >= 1.0) {
- group = g_strdup_printf("%0*d", last_count, (int) fractional);
- } else {
- group = g_strdup_printf("%d", (int) fractional);
- }
- break;
- case CHAR_MAX:
- divider = epow10(last_count);
- number /= divider;
- fractional = modf (number, &number);
- fractional *= divider;
- fractional = floor (fractional);
-
- while (number >= 1.0) {
- group = g_strdup_printf("%0*d", last_count, (int) fractional);
-
- char_length += strlen(group);
- list = g_list_prepend(list, group);
- group_count ++;
-
- divider = epow10(last_count);
- number /= divider;
- fractional = modf (number, &number);
- fractional *= divider;
- fractional = floor (fractional);
- }
-
- group = g_strdup_printf("%d", (int) fractional);
- break;
- }
- char_length += strlen(group);
- list = g_list_prepend(list, group);
- group_count ++;
- }
-
- if (list) {
- value = g_new(char, 1 + char_length + (group_count - 1) * strlen(locality->thousands_sep));
-
- iterator = list;
- value_iterator = value;
-
- strcpy(value_iterator, iterator->data);
- value_iterator += strlen(iterator->data);
- for (iterator = iterator->next; iterator; iterator = iterator->next) {
- strcpy(value_iterator, locality->thousands_sep);
- value_iterator += strlen(locality->thousands_sep);
-
- strcpy(value_iterator, iterator->data);
- value_iterator += strlen(iterator->data);
- }
- e_free_string_list (list);
- return value;
- } else {
- return g_strdup("0");
- }
-}
-
-gchar *
-e_format_number_float (gfloat number)
-{
- gfloat int_part;
- gint fraction;
- struct lconv *locality;
- gchar *str_intpart;
- gchar *decimal_point;
- gchar *str_fraction;
- gchar *value;
-
- locality = localeconv();
-
- int_part = floor (number);
- str_intpart = do_format_number_as_float ((double) int_part);
-
- if (!strcmp(locality->mon_decimal_point, "")) {
- decimal_point = ".";
- }
- else {
- decimal_point = locality->mon_decimal_point;
- }
-
- fraction = (int) ((number - int_part) * 100);
-
- if (fraction == 0) {
- str_fraction = g_strdup ("00");
- } else {
- str_fraction = g_strdup_printf ("%02d", fraction);
- }
-
- value = g_strconcat (str_intpart, decimal_point, str_fraction, NULL);
-
- g_free (str_intpart);
- g_free (str_fraction);
-
- return value;
-}
-
-gboolean
-e_create_directory (gchar *directory)
-{
- gint ret_val = e_mkdir_hier (directory, 0777);
- if (ret_val == -1)
- return FALSE;
- else
- return TRUE;
-}
-
-
-/* Perform a binary search for key in base which has nmemb elements
- of size bytes each. The comparisons are done by (*compare)(). */
-void e_bsearch (const void *key,
- const void *base,
- size_t nmemb,
- size_t size,
- ESortCompareFunc compare,
- gpointer closure,
- size_t *start,
- size_t *end)
-{
- size_t l, u, idx;
- const void *p;
- int comparison;
- if (!(start || end))
- return;
-
- l = 0;
- u = nmemb;
- while (l < u) {
- idx = (l + u) / 2;
- p = (void *) (((const char *) base) + (idx * size));
- comparison = (*compare) (key, p, closure);
- if (comparison < 0)
- u = idx;
- else if (comparison > 0)
- l = idx + 1;
- else {
- size_t lsave, usave;
- lsave = l;
- usave = u;
- if (start) {
- while (l < u) {
- idx = (l + u) / 2;
- p = (void *) (((const char *) base) + (idx * size));
- comparison = (*compare) (key, p, closure);
- if (comparison <= 0)
- u = idx;
- else
- l = idx + 1;
- }
- *start = l;
-
- l = lsave;
- u = usave;
- }
- if (end) {
- while (l < u) {
- idx = (l + u) / 2;
- p = (void *) (((const char *) base) + (idx * size));
- comparison = (*compare) (key, p, closure);
- if (comparison < 0)
- u = idx;
- else
- l = idx + 1;
- }
- *end = l;
- }
- return;
- }
- }
-
- if (start)
- *start = l;
- if (end)
- *end = l;
-}
-
-static gpointer closure_closure;
-static ESortCompareFunc compare_closure;
-
-static int
-qsort_callback(const void *data1, const void *data2)
-{
- return (*compare_closure) (data1, data2, closure_closure);
-}
-
-/* Forget it. We're just going to use qsort. I lost the need for a stable sort. */
-void
-e_sort (void *base,
- size_t nmemb,
- size_t size,
- ESortCompareFunc compare,
- gpointer closure)
-{
- closure_closure = closure;
- compare_closure = compare;
- qsort(base, nmemb, size, qsort_callback);
-#if 0
- void *base_copy;
- int i;
- base_copy = g_malloc(nmemb * size);
-
- for (i = 0; i < nmemb; i++) {
- int position;
- e_bsearch(base + (i * size), base_copy, i, size, compare, closure, NULL, &position);
- memmove(base_copy + (position + 1) * size, base_copy + position * size, (i - position) * size);
- memcpy(base_copy + position * size, base + i * size, size);
- }
- memcpy(base, base_copy, nmemb * size);
- g_free(base_copy);
-#endif
-}
-
-size_t e_strftime(char *s, size_t max, const char *fmt, const struct tm *tm)
-{
-#ifdef HAVE_LKSTRFTIME
- return strftime(s, max, fmt, tm);
-#else
- char *c, *ffmt, *ff;
- size_t ret;
-
- ffmt = g_strdup(fmt);
- ff = ffmt;
- while ((c = strstr(ff, "%l")) != NULL) {
- c[1] = 'I';
- ff = c;
- }
-
- ff = fmt;
- while ((c = strstr(ff, "%k")) != NULL) {
- c[1] = 'H';
- ff = c;
- }
-
- ret = strftime(s, max, ffmt, tm);
- g_free(ffmt);
- return ret;
-#endif
-}
-
-size_t
-e_utf8_strftime(char *s, size_t max, const char *fmt, const struct tm *tm)
-{
- size_t sz, ret;
- char *locale_fmt, *buf;
-
- locale_fmt = g_locale_from_utf8(fmt, -1, NULL, &sz, NULL);
- if (!locale_fmt)
- return 0;
-
- ret = e_strftime(s, max, locale_fmt, tm);
- if (!ret) {
- g_free (locale_fmt);
- return 0;
- }
-
- buf = g_locale_to_utf8(s, ret, NULL, &sz, NULL);
- if (!buf) {
- g_free (locale_fmt);
- return 0;
- }
-
- if (sz >= max) {
- char *tmp = buf + max - 1;
- tmp = g_utf8_find_prev_char(buf, tmp);
- if (tmp)
- sz = tmp - buf;
- else
- sz = 0;
- }
- memcpy(s, buf, sz);
- s[sz] = '\0';
- g_free(locale_fmt);
- g_free(buf);
- return sz;
-}
-
-/**
- * Function to do a last minute fixup of the AM/PM stuff if the locale
- * and gettext haven't done it right. Most English speaking countries
- * except the USA use the 24 hour clock (UK, Australia etc). However
- * since they are English nobody bothers to write a language
- * translation (gettext) file. So the locale turns off the AM/PM, but
- * gettext does not turn on the 24 hour clock. Leaving a mess.
- *
- * This routine checks if AM/PM are defined in the locale, if not it
- * forces the use of the 24 hour clock.
- *
- * The function itself is a front end on strftime and takes exactly
- * the same arguments.
- *
- * TODO: Actually remove the '%p' from the fixed up string so that
- * there isn't a stray space.
- **/
-
-size_t e_strftime_fix_am_pm(char *s, size_t max, const char *fmt, const struct tm *tm)
-{
- char buf[10];
- char *sp;
- char *ffmt;
- size_t ret;
-
- if (strstr(fmt, "%p")==NULL && strstr(fmt, "%P")==NULL) {
- /* No AM/PM involved - can use the fmt string directly */
- ret=e_strftime(s, max, fmt, tm);
- } else {
- /* Get the AM/PM symbol from the locale */
- e_strftime (buf, 10, "%p", tm);
-
- if (buf[0]) {
- /**
- * AM/PM have been defined in the locale
- * so we can use the fmt string directly
- **/
- ret=e_strftime(s, max, fmt, tm);
- } else {
- /**
- * No AM/PM defined by locale
- * must change to 24 hour clock
- **/
- ffmt=g_strdup(fmt);
- for (sp=ffmt; (sp=strstr(sp, "%l")); sp++) {
- /**
- * Maybe this should be 'k', but I have never
- * seen a 24 clock actually use that format
- **/
- sp[1]='H';
- }
- for (sp=ffmt; (sp=strstr(sp, "%I")); sp++) {
- sp[1]='H';
- }
- ret=e_strftime(s, max, ffmt, tm);
- g_free(ffmt);
- }
- }
- return(ret);
-}
-
-size_t
-e_utf8_strftime_fix_am_pm(char *s, size_t max, const char *fmt, const struct tm *tm)
-{
- size_t sz, ret;
- char *locale_fmt, *buf;
-
- locale_fmt = g_locale_from_utf8(fmt, -1, NULL, &sz, NULL);
- if (!locale_fmt)
- return 0;
-
- ret = e_strftime_fix_am_pm(s, max, locale_fmt, tm);
- if (!ret) {
- g_free (locale_fmt);
- return 0;
- }
-
- buf = g_locale_to_utf8(s, ret, NULL, &sz, NULL);
- if (!buf) {
- g_free (locale_fmt);
- return 0;
- }
-
- if (sz >= max) {
- char *tmp = buf + max - 1;
- tmp = g_utf8_find_prev_char(buf, tmp);
- if (tmp)
- sz = tmp - buf;
- else
- sz = 0;
- }
- memcpy(s, buf, sz);
- s[sz] = '\0';
- g_free(locale_fmt);
- g_free(buf);
- return sz;
-}
-
-/**
- * e_flexible_strtod:
- * @nptr: the string to convert to a numeric value.
- * @endptr: if non-NULL, it returns the character after
- * the last character used in the conversion.
- *
- * Converts a string to a gdouble value. This function detects
- * strings either in the standard C locale or in the current locale.
- *
- * This function is typically used when reading configuration files or
- * other non-user input that should not be locale dependent, but may
- * have been in the past. To handle input from the user you should
- * normally use the locale-sensitive system strtod function.
- *
- * To convert from a double to a string in a locale-insensitive way, use
- * @g_ascii_dtostr.
- *
- * Return value: the gdouble value.
- **/
-gdouble
-e_flexible_strtod (const gchar *nptr,
- gchar **endptr)
-{
- gchar *fail_pos;
- gdouble val;
- struct lconv *locale_data;
- const char *decimal_point;
- int decimal_point_len;
- const char *p, *decimal_point_pos;
- const char *end = NULL; /* Silence gcc */
- char *copy, *c;
-
- g_return_val_if_fail (nptr != NULL, 0);
-
- fail_pos = NULL;
-
- locale_data = localeconv ();
- decimal_point = locale_data->decimal_point;
- decimal_point_len = strlen (decimal_point);
-
- g_assert (decimal_point_len != 0);
-
- decimal_point_pos = NULL;
- if (!strcmp (decimal_point, "."))
- return strtod (nptr, endptr);
-
- p = nptr;
-
- /* Skip leading space */
- while (isspace ((guchar)*p))
- p++;
-
- /* Skip leading optional sign */
- if (*p == '+' || *p == '-')
- p++;
-
- if (p[0] == '0' &&
- (p[1] == 'x' || p[1] == 'X')) {
- p += 2;
- /* HEX - find the (optional) decimal point */
-
- while (isxdigit ((guchar)*p))
- p++;
-
- if (*p == '.') {
- decimal_point_pos = p++;
-
- while (isxdigit ((guchar)*p))
- p++;
-
- if (*p == 'p' || *p == 'P')
- p++;
- if (*p == '+' || *p == '-')
- p++;
- while (isdigit ((guchar)*p))
- p++;
- end = p;
- } else if (strncmp (p, decimal_point, decimal_point_len) == 0) {
- return strtod (nptr, endptr);
- }
- } else {
- while (isdigit ((guchar)*p))
- p++;
-
- if (*p == '.') {
- decimal_point_pos = p++;
-
- while (isdigit ((guchar)*p))
- p++;
-
- if (*p == 'e' || *p == 'E')
- p++;
- if (*p == '+' || *p == '-')
- p++;
- while (isdigit ((guchar)*p))
- p++;
- end = p;
- } else if (strncmp (p, decimal_point, decimal_point_len) == 0) {
- return strtod (nptr, endptr);
- }
- }
- /* For the other cases, we need not convert the decimal point */
-
- if (!decimal_point_pos)
- return strtod (nptr, endptr);
-
- /* We need to convert the '.' to the locale specific decimal point */
- copy = g_malloc (end - nptr + 1 + decimal_point_len);
-
- c = copy;
- memcpy (c, nptr, decimal_point_pos - nptr);
- c += decimal_point_pos - nptr;
- memcpy (c, decimal_point, decimal_point_len);
- c += decimal_point_len;
- memcpy (c, decimal_point_pos + 1, end - (decimal_point_pos + 1));
- c += end - (decimal_point_pos + 1);
- *c = 0;
-
- val = strtod (copy, &fail_pos);
-
- if (fail_pos) {
- if (fail_pos > decimal_point_pos)
- fail_pos = (char *)nptr + (fail_pos - copy) - (decimal_point_len - 1);
- else
- fail_pos = (char *)nptr + (fail_pos - copy);
- }
-
- g_free (copy);
-
- if (endptr)
- *endptr = fail_pos;
-
- return val;
-}
-
-/**
- * e_ascii_dtostr:
- * @buffer: A buffer to place the resulting string in
- * @buf_len: The length of the buffer.
- * @format: The printf-style format to use for the
- * code to use for converting.
- * @d: The double to convert
- *
- * Converts a double to a string, using the '.' as
- * decimal_point. To format the number you pass in
- * a printf-style formating string. Allowed conversion
- * specifiers are eEfFgG.
- *
- * If you want to generates enough precision that converting
- * the string back using @g_strtod gives the same machine-number
- * (on machines with IEEE compatible 64bit doubles) use the format
- * string "%.17g". If you do this it is guaranteed that the size
- * of the resulting string will never be larger than
- * @G_ASCII_DTOSTR_BUF_SIZE bytes.
- *
- * Return value: The pointer to the buffer with the converted string.
- **/
-gchar *
-e_ascii_dtostr (gchar *buffer,
- gint buf_len,
- const gchar *format,
- gdouble d)
-{
- struct lconv *locale_data;
- const char *decimal_point;
- int decimal_point_len;
- gchar *p;
- int rest_len;
- gchar format_char;
-
- g_return_val_if_fail (buffer != NULL, NULL);
- g_return_val_if_fail (format[0] == '%', NULL);
- g_return_val_if_fail (strpbrk (format + 1, "'l%") == NULL, NULL);
-
- format_char = format[strlen (format) - 1];
-
- g_return_val_if_fail (format_char == 'e' || format_char == 'E' ||
- format_char == 'f' || format_char == 'F' ||
- format_char == 'g' || format_char == 'G',
- NULL);
-
- if (format[0] != '%')
- return NULL;
-
- if (strpbrk (format + 1, "'l%"))
- return NULL;
-
- if (!(format_char == 'e' || format_char == 'E' ||
- format_char == 'f' || format_char == 'F' ||
- format_char == 'g' || format_char == 'G'))
- return NULL;
-
-
- g_snprintf (buffer, buf_len, format, d);
-
- locale_data = localeconv ();
- decimal_point = locale_data->decimal_point;
- decimal_point_len = strlen (decimal_point);
-
- g_assert (decimal_point_len != 0);
-
- if (strcmp (decimal_point, ".")) {
- p = buffer;
-
- if (*p == '+' || *p == '-')
- p++;
-
- while (isdigit ((guchar)*p))
- p++;
-
- if (strncmp (p, decimal_point, decimal_point_len) == 0) {
- *p = '.';
- p++;
- if (decimal_point_len > 1) {
- rest_len = strlen (p + (decimal_point_len-1));
- memmove (p, p + (decimal_point_len-1),
- rest_len);
- p[rest_len] = 0;
- }
- }
- }
-
- return buffer;
-}
-
-gchar *
-e_strdup_append_strings (gchar *first_string, ...)
-{
- gchar *buffer;
- gchar *current;
- gint length;
- va_list args1;
- va_list args2;
- char *v_string;
- int v_int;
-
- va_start (args1, first_string);
- G_VA_COPY (args2, args1);
-
- length = 0;
-
- v_string = first_string;
- while (v_string) {
- v_int = va_arg (args1, int);
- if (v_int >= 0)
- length += v_int;
- else
- length += strlen (v_string);
- v_string = va_arg (args1, char *);
- }
-
- buffer = g_new (char, length + 1);
- current = buffer;
-
- v_string = first_string;
- while (v_string) {
- v_int = va_arg (args2, int);
- if (v_int < 0) {
- int i;
- for (i = 0; v_string[i]; i++) {
- *(current++) = v_string[i];
- }
- } else {
- int i;
- for (i = 0; v_string[i] && i < v_int; i++) {
- *(current++) = v_string[i];
- }
- }
- v_string = va_arg (args2, char *);
- }
- *(current++) = 0;
-
- va_end (args1);
- va_end (args2);
-
- return buffer;
-}
-
-gchar **
-e_strdupv (const gchar **str_array)
-{
- if (str_array) {
- gint i;
- gchar **retval;
-
- i = 0;
- while (str_array[i])
- i++;
-
- retval = g_new (gchar*, i + 1);
-
- i = 0;
- while (str_array[i]) {
- retval[i] = g_strdup (str_array[i]);
- i++;
- }
- retval[i] = NULL;
-
- return retval;
- } else {
- return NULL;
- }
-}
-
-char *
-e_gettext (const char *msgid)
-{
- static gboolean initialized = FALSE;
-
- if (!initialized) {
- bindtextdomain (E_I18N_DOMAIN, GNOMELOCALEDIR);
- bind_textdomain_codeset (E_I18N_DOMAIN, "UTF-8");
- initialized = TRUE;
- }
-
- return dgettext (E_I18N_DOMAIN, msgid);
-}
-
diff --git a/e-util/e-util.h b/e-util/e-util.h
deleted file mode 100644
index d9d51967d1..0000000000
--- a/e-util/e-util.h
+++ /dev/null
@@ -1,231 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-util.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_UTIL_H_
-#define _E_UTIL_H_
-
-#include <sys/types.h>
-#include <glib-object.h>
-#include <limits.h>
-
-#ifdef __cplusplus
-extern "C" {
-#pragma }
-#endif /* __cplusplus */
-
-#include <gal/util/e-marshal.h>
-
-#define E_MAKE_TYPE(l,str,t,ci,i,parent) \
-GType l##_get_type(void)\
-{\
- static GType type = 0; \
- if (!type){ \
- static GTypeInfo const object_info = { \
- sizeof (t##Class), \
- \
- (GBaseInitFunc) NULL, \
- (GBaseFinalizeFunc) NULL, \
- \
- (GClassInitFunc) ci, \
- (GClassFinalizeFunc) NULL, \
- NULL, /* class_data */ \
- \
- sizeof (t), \
- 0, /* n_preallocs */ \
- (GInstanceInitFunc) i, \
- }; \
- type = g_type_register_static (parent, str, &object_info, 0); \
- } \
- return type; \
-}
-
-
-#define E_MAKE_X_TYPE(l,str,t,ci,i,parent,poa_init,offset) \
-GtkType l##_get_type(void) \
-{ \
- static GtkType type = 0; \
- if (!type){ \
- GTypeInfo info = { \
- sizeof (t##Class), \
- \
- (GBaseInitFunc) NULL, \
- (GBaseFinalizeFunc) NULL, \
- \
- (GClassInitFunc) ci, \
- (GClassFinalizeFunc) NULL, \
- \
- NULL, /* class_data */ \
- \
- sizeof (t), \
- 0, /* n_preallocs */ \
- (GInstanceInitFunc) i, \
- }; \
- type = bonobo_x_type_unique ( \
- parent, poa_init, NULL, \
- offset, &info, str); \
- } \
- return type; \
-}
-
-#define GET_STRING_ARRAY_FROM_ELLIPSIS(labels, first_string) \
- { \
- va_list args; \
- int i; \
- char *s; \
- \
- va_start (args, (first_string)); \
- \
- i = 0; \
- for (s = (first_string); s; s = va_arg (args, char *)) \
- i++; \
- va_end (args); \
- \
- (labels) = g_new (char *, i + 1); \
- \
- va_start (args, (first_string)); \
- i = 0; \
- for (s = (first_string); s; s = va_arg (args, char *)) \
- (labels)[i++] = s; \
- \
- va_end (args); \
- (labels)[i] = NULL; \
- }
-
-
-#define GET_DUPLICATED_STRING_ARRAY_FROM_ELLIPSIS(labels, first_string) \
- { \
- int i; \
- GET_STRING_ARRAY_FROM_ELLIPSIS ((labels), (first_string)); \
- for (i = 0; labels[i]; i++) \
- labels[i] = g_strdup (labels[i]); \
- }
-
-
-#if 0
-# define E_OBJECT_CLASS_ADD_SIGNALS(oc,sigs,last) \
- gtk_object_class_add_signals (oc, sigs, last)
-# define E_OBJECT_CLASS_TYPE(oc) (oc)->type
-#else
-# define E_OBJECT_CLASS_ADD_SIGNALS(oc,sigs,last)
-# define E_OBJECT_CLASS_TYPE(oc) G_TYPE_FROM_CLASS (oc)
-#endif
-
-
-typedef enum {
- E_FOCUS_NONE,
- E_FOCUS_CURRENT,
- E_FOCUS_START,
- E_FOCUS_END
-} EFocus;
-int g_str_compare (const void *x,
- const void *y);
-int g_collate_compare (const void *x,
- const void *y);
-int g_int_compare (const void *x,
- const void *y);
-char *e_strdup_strip (const char *string);
-void e_free_object_list (GList *list);
-void e_free_object_slist (GSList *list);
-void e_free_string_list (GList *list);
-void e_free_string_slist (GSList *list);
-char *e_read_file (const char *filename);
-int e_write_file (const char *filename,
- const char *data,
- int flags);
-int e_write_file_mkstemp (char *filename,
- const char *data);
-int e_mkdir_hier (const char *path,
- mode_t mode);
-
-gchar **e_strsplit (const gchar *string,
- const gchar *delimiter,
- gint max_tokens);
-gchar *e_strstrcase (const gchar *haystack,
- const gchar *needle);
-/* This only makes a filename safe for usage as a filename. It still may have shell meta-characters in it. */
-void e_filename_make_safe (gchar *string);
-gchar *e_format_number (gint number);
-gchar *e_format_number_float (gfloat number);
-gboolean e_create_directory (gchar *directory);
-gchar **e_strdupv (const gchar **str_array);
-
-
-typedef int (*ESortCompareFunc) (const void *first,
- const void *second,
- gpointer closure);
-void e_sort (void *base,
- size_t nmemb,
- size_t size,
- ESortCompareFunc compare,
- gpointer closure);
-void e_bsearch (const void *key,
- const void *base,
- size_t nmemb,
- size_t size,
- ESortCompareFunc compare,
- gpointer closure,
- size_t *start,
- size_t *end);
-size_t e_strftime_fix_am_pm (char *s,
- size_t max,
- const char *fmt,
- const struct tm *tm);
-
-size_t e_strftime (char *s,
- size_t max,
- const char *fmt,
- const struct tm *tm);
-
-size_t e_utf8_strftime_fix_am_pm (char *s,
- size_t max,
- const char *fmt,
- const struct tm *tm);
-
-size_t e_utf8_strftime (char *s,
- size_t max,
- const char *fmt,
- const struct tm *tm);
-
-/* String to/from double conversion functions */
-gdouble e_flexible_strtod (const gchar *nptr,
- gchar **endptr);
-
-/* 29 bytes should enough for all possible values that
- * g_ascii_dtostr can produce with the %.17g format.
- * Then add 10 for good measure */
-#define E_ASCII_DTOSTR_BUF_SIZE (DBL_DIG + 12 + 10)
-gchar *e_ascii_dtostr (gchar *buffer,
- gint buf_len,
- const gchar *format,
- gdouble d);
-
-/* Alternating char * and int arguments with a NULL char * to end.
- Less than 0 for the int means copy the whole string. */
-gchar *e_strdup_append_strings (gchar *first_string,
- ...);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* _E_UTIL_H_ */
diff --git a/e-util/e-xml-utils.c b/e-util/e-xml-utils.c
deleted file mode 100644
index 437934be65..0000000000
--- a/e-util/e-xml-utils.c
+++ /dev/null
@@ -1,502 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-xml-utils.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "e-xml-utils.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <locale.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <math.h>
-#include <string.h>
-#include <libxml/parser.h>
-#include <libxml/xmlmemory.h>
-
-#include "gal/util/e-i18n.h"
-#include "gal/util/e-util.h"
-
-xmlNode *
-e_xml_get_child_by_name (const xmlNode *parent, const xmlChar *child_name)
-{
- xmlNode *child;
-
- g_return_val_if_fail (parent != NULL, NULL);
- g_return_val_if_fail (child_name != NULL, NULL);
-
- for (child = parent->xmlChildrenNode; child != NULL; child = child->next) {
- if (xmlStrcmp (child->name, child_name) == 0) {
- return child;
- }
- }
- return NULL;
-}
-
-/* Returns the first child with the name child_name and the "lang"
- * attribute that matches the current LC_MESSAGES, or else, the first
- * child with the name child_name and no "lang" attribute.
- */
-xmlNode *
-e_xml_get_child_by_name_by_lang (const xmlNode *parent,
- const xmlChar *child_name,
- const gchar *lang)
-{
- xmlNode *child;
- /* This is the default version of the string. */
- xmlNode *C = NULL;
-
- g_return_val_if_fail (parent != NULL, NULL);
- g_return_val_if_fail (child_name != NULL, NULL);
-
- if (lang == NULL) {
-#ifdef HAVE_LC_MESSAGES
- lang = setlocale (LC_MESSAGES, NULL);
-#else
- lang = setlocale (LC_CTYPE, NULL);
-#endif
- }
- for (child = parent->xmlChildrenNode; child != NULL; child = child->next) {
- if (xmlStrcmp (child->name, child_name) == 0) {
- xmlChar *this_lang = xmlGetProp (child, "lang");
- if (this_lang == NULL) {
- C = child;
- } else if (xmlStrcmp(this_lang, "lang") == 0) {
- return child;
- }
- }
- }
- return C;
-}
-
-static xmlNode *
-e_xml_get_child_by_name_by_lang_list_with_score (const xmlNode *parent,
- const gchar *name,
- const GList *lang_list,
- gint *best_lang_score)
-{
- xmlNodePtr best_node = NULL, node;
-
- for (node = parent->xmlChildrenNode; node != NULL; node = node->next) {
- xmlChar *lang;
-
- if (node->name == NULL || strcmp (node->name, name) != 0) {
- continue;
- }
- lang = xmlGetProp (node, "xml:lang");
- if (lang != NULL) {
- const GList *l;
- gint i;
-
- for (l = lang_list, i = 0;
- l != NULL && i < *best_lang_score;
- l = l->next, i++) {
- if (strcmp ((gchar *) l->data, lang) == 0) {
- best_node = node;
- *best_lang_score = i;
- }
- }
- } else {
- if (best_node == NULL) {
- best_node = node;
- }
- }
- xmlFree (lang);
- if (*best_lang_score == 0) {
- return best_node;
- }
- }
-
- return best_node;
-}
-
-/*
- * e_xml_get_child_by_name_by_lang_list:
- *
- */
-xmlNode *
-e_xml_get_child_by_name_by_lang_list (const xmlNode *parent,
- const gchar *name,
- const GList *lang_list)
-{
- gint best_lang_score = INT_MAX;
-
- g_return_val_if_fail (parent != NULL, NULL);
- g_return_val_if_fail (name != NULL, NULL);
-
- if (lang_list == NULL) {
- lang_list = gnome_i18n_get_language_list ("LC_MESSAGES");
- }
- return e_xml_get_child_by_name_by_lang_list_with_score
- (parent,name,
- lang_list,
- &best_lang_score);
-}
-
-/*
- * e_xml_get_child_by_name_no_lang
- *
- */
-xmlNode *
-e_xml_get_child_by_name_no_lang (const xmlNode *parent, const gchar *name)
-{
- xmlNodePtr node;
-
- g_return_val_if_fail (parent != NULL, NULL);
- g_return_val_if_fail (name != NULL, NULL);
-
- for (node = parent->xmlChildrenNode; node != NULL; node = node->next) {
- xmlChar *lang;
-
- if (node->name == NULL || strcmp (node->name, name) != 0) {
- continue;
- }
- lang = xmlGetProp (node, "xml:lang");
- if (lang == NULL) {
- return node;
- }
- xmlFree (lang);
- }
-
- return NULL;
-}
-
-gint
-e_xml_get_integer_prop_by_name (const xmlNode *parent, const xmlChar *prop_name)
-{
- g_return_val_if_fail (parent != NULL, 0);
- g_return_val_if_fail (prop_name != NULL, 0);
-
- return e_xml_get_integer_prop_by_name_with_default (parent, prop_name, 0);
-}
-
-gint
-e_xml_get_integer_prop_by_name_with_default (const xmlNode *parent,
- const xmlChar *prop_name,
- gint def)
-{
- xmlChar *prop;
- gint ret_val = def;
-
- g_return_val_if_fail (parent != NULL, 0);
- g_return_val_if_fail (prop_name != NULL, 0);
-
- prop = xmlGetProp ((xmlNode *) parent, prop_name);
- if (prop != NULL) {
- (void) sscanf (prop, "%d", &ret_val);
- xmlFree (prop);
- }
- return ret_val;
-}
-
-void
-e_xml_set_integer_prop_by_name (xmlNode *parent,
- const xmlChar *prop_name,
- gint value)
-{
- gchar *valuestr;
-
- g_return_if_fail (parent != NULL);
- g_return_if_fail (prop_name != NULL);
-
- valuestr = g_strdup_printf ("%d", value);
- xmlSetProp (parent, prop_name, valuestr);
- g_free (valuestr);
-}
-
-guint
-e_xml_get_uint_prop_by_name (const xmlNode *parent, const xmlChar *prop_name)
-{
- g_return_val_if_fail (parent != NULL, 0);
- g_return_val_if_fail (prop_name != NULL, 0);
-
- return e_xml_get_uint_prop_by_name_with_default (parent, prop_name, 0);
-}
-
-guint
-e_xml_get_uint_prop_by_name_with_default (const xmlNode *parent,
- const xmlChar *prop_name,
- guint def)
-{
- xmlChar *prop;
- guint ret_val = def;
-
- g_return_val_if_fail (parent != NULL, 0);
- g_return_val_if_fail (prop_name != NULL, 0);
-
- prop = xmlGetProp ((xmlNode *) parent, prop_name);
- if (prop != NULL) {
- (void) sscanf (prop, "%u", &ret_val);
- xmlFree (prop);
- }
- return ret_val;
-}
-
-void
-e_xml_set_uint_prop_by_name (xmlNode *parent,
- const xmlChar *prop_name,
- guint value)
-{
- gchar *valuestr;
-
- g_return_if_fail (parent != NULL);
- g_return_if_fail (prop_name != NULL);
-
- valuestr = g_strdup_printf ("%u", value);
- xmlSetProp (parent, prop_name, valuestr);
- g_free (valuestr);
-}
-
-gboolean
-e_xml_get_bool_prop_by_name (const xmlNode *parent,
- const xmlChar *prop_name)
-{
- g_return_val_if_fail (parent != NULL, 0);
- g_return_val_if_fail (prop_name != NULL, 0);
-
- return e_xml_get_bool_prop_by_name_with_default (parent,
- prop_name,
- FALSE);
-}
-
-gboolean
-e_xml_get_bool_prop_by_name_with_default(const xmlNode *parent,
- const xmlChar *prop_name,
- gboolean def)
-{
- xmlChar *prop;
- gboolean ret_val = def;
-
- g_return_val_if_fail (parent != NULL, 0);
- g_return_val_if_fail (prop_name != NULL, 0);
-
- prop = xmlGetProp ((xmlNode *) parent, prop_name);
- if (prop != NULL) {
- if (g_strcasecmp (prop, "true") == 0) {
- ret_val = TRUE;
- } else if (g_strcasecmp (prop, "false") == 0) {
- ret_val = FALSE;
- }
- xmlFree(prop);
- }
- return ret_val;
-}
-
-void
-e_xml_set_bool_prop_by_name (xmlNode *parent, const xmlChar *prop_name, gboolean value)
-{
- g_return_if_fail (parent != NULL);
- g_return_if_fail (prop_name != NULL);
-
- if (value) {
- xmlSetProp (parent, prop_name, "true");
- } else {
- xmlSetProp (parent, prop_name, "false");
- }
-}
-
-gdouble
-e_xml_get_double_prop_by_name (const xmlNode *parent, const xmlChar *prop_name)
-{
- g_return_val_if_fail (parent != NULL, 0);
- g_return_val_if_fail (prop_name != NULL, 0);
-
- return e_xml_get_double_prop_by_name_with_default (parent, prop_name, 0.0);
-}
-
-gdouble
-e_xml_get_double_prop_by_name_with_default (const xmlNode *parent, const xmlChar *prop_name, gdouble def)
-{
- xmlChar *prop;
- gdouble ret_val = def;
-
- g_return_val_if_fail (parent != NULL, 0);
- g_return_val_if_fail (prop_name != NULL, 0);
-
- prop = xmlGetProp ((xmlNode *) parent, prop_name);
- if (prop != NULL) {
- ret_val = e_flexible_strtod (prop, NULL);
- xmlFree (prop);
- }
- return ret_val;
-}
-
-void
-e_xml_set_double_prop_by_name(xmlNode *parent, const xmlChar *prop_name, gdouble value)
-{
- char buffer[E_ASCII_DTOSTR_BUF_SIZE];
- char *format;
-
- g_return_if_fail (parent != NULL);
- g_return_if_fail (prop_name != NULL);
-
- if (fabs (value) < 1e9 && fabs (value) > 1e-5) {
- format = g_strdup_printf ("%%.%df", DBL_DIG);
- } else {
- format = g_strdup_printf ("%%.%dg", DBL_DIG);
- }
- e_ascii_dtostr (buffer, sizeof (buffer), format, value);
- g_free (format);
-
- xmlSetProp (parent, prop_name, buffer);
-}
-
-gchar *
-e_xml_get_string_prop_by_name (const xmlNode *parent, const xmlChar *prop_name)
-{
- g_return_val_if_fail (parent != NULL, 0);
- g_return_val_if_fail (prop_name != NULL, 0);
-
- return e_xml_get_string_prop_by_name_with_default (parent, prop_name, NULL);
-}
-
-gchar *
-e_xml_get_string_prop_by_name_with_default (const xmlNode *parent, const xmlChar *prop_name, const gchar *def)
-{
- xmlChar *prop;
- gchar *ret_val;
-
- g_return_val_if_fail (parent != NULL, 0);
- g_return_val_if_fail (prop_name != NULL, 0);
-
- prop = xmlGetProp ((xmlNode *) parent, prop_name);
- if (prop != NULL) {
- ret_val = g_strdup (prop);
- xmlFree (prop);
- } else {
- ret_val = g_strdup (def);
- }
- return ret_val;
-}
-
-void
-e_xml_set_string_prop_by_name (xmlNode *parent, const xmlChar *prop_name, const gchar *value)
-{
- g_return_if_fail (parent != NULL);
- g_return_if_fail (prop_name != NULL);
-
- if (value != NULL) {
- xmlSetProp (parent, prop_name, value);
- }
-}
-
-gchar *
-e_xml_get_translated_string_prop_by_name (const xmlNode *parent, const xmlChar *prop_name)
-{
- xmlChar *prop;
- gchar *ret_val = NULL;
- gchar *combined_name;
-
- g_return_val_if_fail (parent != NULL, 0);
- g_return_val_if_fail (prop_name != NULL, 0);
-
- prop = xmlGetProp ((xmlNode *) parent, prop_name);
- if (prop != NULL) {
- ret_val = g_strdup (prop);
- xmlFree (prop);
- return ret_val;
- }
-
- combined_name = g_strdup_printf("_%s", prop_name);
- prop = xmlGetProp ((xmlNode *) parent, combined_name);
- if (prop != NULL) {
- ret_val = g_strdup (gettext(prop));
- xmlFree (prop);
- }
- g_free(combined_name);
-
- return ret_val;
-}
-
-
-int
-e_xml_save_file (const char *filename, xmlDocPtr doc)
-{
- char *filesave, *slash, *xmlbuf;
- size_t n, written = 0;
- int ret, fd, size;
- int errnosave;
- ssize_t w;
-
- filesave = alloca (strlen (filename) + 5);
- slash = strrchr (filename, '/');
- if (slash)
- sprintf (filesave, "%.*s.#%s", slash - filename + 1, filename, slash + 1);
- else
- sprintf (filesave, ".#%s", filename);
-
- fd = open (filesave, O_WRONLY | O_CREAT | O_TRUNC, 0600);
- if (fd == -1)
- return -1;
-
- xmlDocDumpFormatMemory (doc, (xmlChar **) &xmlbuf, &size, TRUE);
- if (size <= 0) {
- close (fd);
- unlink (filesave);
- errno = ENOMEM;
- return -1;
- }
-
- n = (size_t) size;
- do {
- do {
- w = write (fd, xmlbuf + written, n - written);
- } while (w == -1 && errno == EINTR);
-
- if (w > 0)
- written += w;
- } while (w != -1 && written < n);
-
- xmlFree (xmlbuf);
-
- if (written < n || fsync (fd) == -1) {
- errnosave = errno;
- close (fd);
- unlink (filesave);
- errno = errnosave;
- return -1;
- }
-
- while ((ret = close (fd)) == -1 && errno == EINTR)
- ;
-
- if (ret == -1)
- return -1;
-
- if (rename (filesave, filename) == -1) {
- errnosave = errno;
- unlink (filesave);
- errno = errnosave;
- return -1;
- }
-
- return 0;
-}
diff --git a/e-util/e-xml-utils.h b/e-util/e-xml-utils.h
deleted file mode 100644
index 6c39ee6f79..0000000000
--- a/e-util/e-xml-utils.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-xml-utils.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef __E_XML_UTILS__
-#define __E_XML_UTILS__
-
-#include <glib.h>
-#include <libxml/tree.h>
-
-G_BEGIN_DECLS
-
-xmlNode *e_xml_get_child_by_name (const xmlNode *parent,
- const xmlChar *child_name);
-/* lang set to NULL means use the current locale. */
-xmlNode *e_xml_get_child_by_name_by_lang (const xmlNode *parent,
- const xmlChar *child_name,
- const gchar *lang);
-/* lang_list set to NULL means use the current locale. */
-xmlNode *e_xml_get_child_by_name_by_lang_list (const xmlNode *parent,
- const gchar *name,
- const GList *lang_list);
-xmlNode *e_xml_get_child_by_name_no_lang (const xmlNode *parent,
- const gchar *name);
-
-
-gint e_xml_get_integer_prop_by_name (const xmlNode *parent,
- const xmlChar *prop_name);
-gint e_xml_get_integer_prop_by_name_with_default (const xmlNode *parent,
- const xmlChar *prop_name,
- gint def);
-void e_xml_set_integer_prop_by_name (xmlNode *parent,
- const xmlChar *prop_name,
- gint value);
-
-
-guint e_xml_get_uint_prop_by_name (const xmlNode *parent,
- const xmlChar *prop_name);
-guint e_xml_get_uint_prop_by_name_with_default (const xmlNode *parent,
- const xmlChar *prop_name,
- guint def);
-void e_xml_set_uint_prop_by_name (xmlNode *parent,
- const xmlChar *prop_name,
- guint value);
-
-
-gboolean e_xml_get_bool_prop_by_name (const xmlNode *parent,
- const xmlChar *prop_name);
-gboolean e_xml_get_bool_prop_by_name_with_default (const xmlNode *parent,
- const xmlChar *prop_name,
- gboolean def);
-void e_xml_set_bool_prop_by_name (xmlNode *parent,
- const xmlChar *prop_name,
- gboolean value);
-
-gdouble e_xml_get_double_prop_by_name (const xmlNode *parent,
- const xmlChar *prop_name);
-gdouble e_xml_get_double_prop_by_name_with_default (const xmlNode *parent,
- const xmlChar *prop_name,
- gdouble def);
-void e_xml_set_double_prop_by_name ( xmlNode *parent,
- const xmlChar *prop_name,
- gdouble value);
-
-
-gchar *e_xml_get_string_prop_by_name (const xmlNode *parent,
- const xmlChar *prop_name);
-gchar *e_xml_get_string_prop_by_name_with_default (const xmlNode *parent,
- const xmlChar *prop_name,
- const gchar *def);
-void e_xml_set_string_prop_by_name (xmlNode *parent,
- const xmlChar *prop_name,
- const gchar *value);
-
-gchar *e_xml_get_translated_string_prop_by_name (const xmlNode *parent,
- const xmlChar *prop_name);
-
-int e_xml_save_file (const char *filename, xmlDocPtr doc);
-
-G_END_DECLS
-
-#endif /* __E_XML_UTILS__ */
diff --git a/filter/ChangeLog b/filter/ChangeLog
index c810b73ab3..8687527bf1 100644
--- a/filter/ChangeLog
+++ b/filter/ChangeLog
@@ -1,36 +1,8 @@
-2005-02-17 Harry Lu <harry.lu@sun.com>
+2005-01-21 Not Zed <NotZed@Ximian.com>
- Fix for 72676.
-
- * rule-editor.c: (double_click): call gtk_tree_selection_get_selected
- to see if there is a row selected.
-
-2005-02-09 Hans Petter Jansson <hpj@novell.com>
-
- * Makefile.am: Install shared libraries in privlibdir.
-
-2005-01-11 Not Zed <NotZed@Ximian.com>
-
- * filter-part.c (filter_part_expand_code): cast lenght specifiers
+ * filter-part.c (filter_part_expand_code): cast length specifiers
to int.
-2004-12-02 Diego Sevilla Ruiz <dsevilla@dsevilla>
-
- * filter.glade: Added label "Show filters for mail:".
-
- * filter-rule.c: Capitalize Ingoing and Outgoing labels.
- Fixes #46229.
-
-2004-11-29 Mengjie Yu <meng-jie.yu@sun.com>
-
- * filter-rule.c: (get_widget):add mnemonic widget in search box.
-
-2004-11-15 Not Zed <NotZed@Ximian.com>
-
- * *.c: Moved stuff from e-util to libedataserver.
-
- * filter-system-flag.c: removed gal header.
-
2004-07-29 Carlos Garnacho Parro <carlosg@gnome.org>
* filter-file.c: added the "use_filechooser" property to the
diff --git a/help/C/figures/evo_email_a.png b/help/C/figures/evo_email_a.png
index 5d1c6d609b..131ce9a4f1 100755
--- a/help/C/figures/evo_email_a.png
+++ b/help/C/figures/evo_email_a.png
Binary files differ
diff --git a/help/C/figures/evo_identity_a.png b/help/C/figures/evo_identity_a.png
index a2500b783a..3d58558566 100755
--- a/help/C/figures/evo_identity_a.png
+++ b/help/C/figures/evo_identity_a.png
Binary files differ
diff --git a/help/C/figures/evo_mail_callout_a.png b/help/C/figures/evo_mail_callout_a.png
index 2f9b438875..9c6f7c6d96 100755
--- a/help/C/figures/evo_mail_callout_a.png
+++ b/help/C/figures/evo_mail_callout_a.png
Binary files differ
diff --git a/help/C/figures/evo_receive_setup_a.png b/help/C/figures/evo_receive_setup_a.png
index 260d0d3e3b..b98a374ccb 100755
--- a/help/C/figures/evo_receive_setup_a.png
+++ b/help/C/figures/evo_receive_setup_a.png
Binary files differ
diff --git a/help/C/figures/evo_send_setup_a.png b/help/C/figures/evo_send_setup_a.png
index 08981edc8d..68d6646a69 100755
--- a/help/C/figures/evo_send_setup_a.png
+++ b/help/C/figures/evo_send_setup_a.png
Binary files differ
diff --git a/help/ChangeLog b/help/ChangeLog
index d49a4bc91f..c432adea05 100644
--- a/help/ChangeLog
+++ b/help/ChangeLog
@@ -1,3 +1,9 @@
+2004-11-05 JP Rosevear <jpr@novell.com>
+
+ Fixes #68742
+
+ * C/evolution.xml: fix section id
+
2004-10-11 Rodney Dawes <dobey@novell.com>
* C/Makefile.am: Add new images to figures
diff --git a/help/devel/executive-summary/evolution-services.hierarchy b/help/devel/executive-summary/evolution-services.hierarchy
deleted file mode 100644
index 37559d819d..0000000000
--- a/help/devel/executive-summary/evolution-services.hierarchy
+++ /dev/null
@@ -1,7 +0,0 @@
-GtkObject
- BonoboObject
- ExecutiveSummaryComponent
- ExecutiveSummaryComponentFactory
- Handle to remote Bonobo::Unknown
- ExecutiveSummaryComponentFactoryClient
- ExecutiveSummaryHtmlView
diff --git a/help/devel/importer/evolution-shell-importer.hierarchy b/help/devel/importer/evolution-shell-importer.hierarchy
deleted file mode 100644
index c46ebdf782..0000000000
--- a/help/devel/importer/evolution-shell-importer.hierarchy
+++ /dev/null
@@ -1,7 +0,0 @@
-GtkObject
- BonoboObject
- BonoboXObject
- EvolutionImporter
- EvolutionImporterListener
- Handle to remote Bonobo::Unknown
- EvolutionImporterClient
diff --git a/mail/ChangeLog b/mail/ChangeLog
index b4c9f43a27..e02b747a6a 100644
--- a/mail/ChangeLog
+++ b/mail/ChangeLog
@@ -1,306 +1,78 @@
-2005-02-15 Radek Doulik <rodo@novell.com>
+2005-02-09 Jeffrey Stedfast <fejj@novell.com>
- * em-junk-filter.c: use camel_debug
-
-2005-02-10 Not Zed <NotZed@Ximian.com>
-
- ** See bug #72266
-
- * em-folder-selection-button.c
- (em_folder_selection_button_clicked): if the selector is already
- up, just raise it.
- (em_folder_selection_button_destroy): destroy the selector if it
- is still up.
+ * message-list.c (message_list_set_folder): Reset the
+ normalised_hash. Fixes bug #33933.
2005-02-09 Not Zed <NotZed@Ximian.com>
- ** See bug #71429
-
- * em-folder-view.c (emfv_activate): setup the plugin menu's after
- the main ones.
-
-2005-02-08 Not Zed <NotZed@Ximian.com>
-
- ** See bug #72228
-
- * mail-ops.c (mail_send_message): fix this god-awful goto-loop
- crap, and delete the message if it worked.
- (mail_send_message): fix a major-leak with sent messages never
- being unreffed.
- (send_queue_send): don't get messages ourself.
- (mail_send_message): dont lose the exception if we
- can't even open the sent folder.
-
-2005-02-07 Not Zed <NotZed@Ximian.com>
-
- ** See bug #72209
-
- * em-folder-tree.c (emft_popup_copy_folder_exclude): implement one
- for copying/moving folders.
-
- * em-folder-selection.c (em_select_folder): add an excluded func
- argument, fix callers.
-
- * em-folder-tree.c
- (em_folder_tree_set_exclude_func): allow custom callback for
- exclusion.
- (emft_select_func): handle the custom excluded callback.
+ ** See bug #70795
-2005-02-07 Harry Lu <harry.lu@sun.com>
+ * em-folder-view.c (em_folder_view_open_selected): set the search
+ on the browser to match the current view.
- Fix for 72275.
- * em-folder-view.c: (emfv_popup_menu): try to bring up menu for
- preivew html object.
- (emfv_format_popup_event): handle event == NULL case.
- * em-format-html-display.c: (em_format_html_display_popup_menu):
- New function to popup context menu.
- * em-format-html-display.h: add new function declaration.
+ * message-list.c (mail_regen_list): save the search if no folder
+ set, incase the folder gets set later on.
2005-02-04 Not Zed <NotZed@Ximian.com>
- * em-subscribe-editor.c (sub_folderinfo_get): reverted jeff's
- patch for the subscribed hint.
-
** See bug #65329
* em-folder-properties.c (emfp_dialog_got_folder): translate
local-store special folders.
- * mail-session.c (alert_user, do_user_message): if we aren't
- waiting for cancel, then don't worry about waiting on the reply
- port, otherwise we could block when we don't need to, if there is
- another window already up.
-
-2005-02-03 Jeffrey Stedfast <fejj@novell.com>
-
- * message-list.c (message_list_set_folder): Use
- g_hash_table_foreach_remove() instead so the keys don't point to
- free'd values.
- (normalised_free): Return TRUE.
-
-2005-02-02 Rodney Dawes <dobey@novell.com>
-
- * em-subscribe-editor.c (em_subscribe_editor_new): Use the
- gtk_widget_ensure_style method instead of gtk_widget_realize when
- setting the border widths of the dialog containers for HIG compliance
-
- Fixes #68743
-
-2005-02-02 Jeffrey Stedfast <fejj@novell.com>
-
- Fixes bug #70454
-
- * em-subscribe-editor.c (sub_folderinfo_get): Request subscription
- info (new flag).
- (sub_fill_level): Fixed the FIXME here (imap4 now implements
- CAMEL_FOLDER_SUBSCRIBED flag properly).
-
-2005-02-01 Rodney Dawes <dobey@novell.com>
-
- * em-folder-browser.c: Replace "_Virtual Folder" with "_vFolder" for
- the search menu to create a vfolder from a search
-
- * em-folder-tree-model.c (sort_cb): s/VFolders/vFolders/ for sorting
- in the folder tree
- (em_folder_tree_model_load_state): s/VFolders/vFolders/ in a comment
-
- * em-folder-view.c: s/VFolder/vFolder/ for the popup menu
-
- * em-vfolder-editor.c (em_vfolder_editor_new): Replace the string
- "Virtual _Folders" with "v_Folders" for the label
-
- * em-vfolder-rule.c (em_vfolder_editor_sourcelist_new): Repalce the
- string "VFolder source" with "vFolder source"
-
- * mail-errors.xml:
- * mail-errors.xml.h: Replace "virtual folder" with "vFolder" in an
- error string
-
- * mail-vfolder.c (vfolder_setup_desc): s/vfolder/vFolder/
- (vfolder_setup_do): s/vfolder/vFolder/
- (vfolder_load_storage): s/VFolders/vFolders/
- (vfolder_edit_rule): s/VFolder/vFolder/
- (vfolder_gui_add_rule): s/VFolder/vFolder/
-
- Fixes #68137
-
2005-02-01 Not Zed <NotZed@Ximian.com>
- ** See bug #65329.
-
- * mail-component.c (view_changed_cb): translate special names on
- the local store.
-
- * em-folder-tree-model.c (sort_cb): use the type hint to sort for
- inbox, not the name.
- (emft_is_special_local_folder): removed.
- (em_folder_tree_model_set_folder_info): special-case the
- local-store case, handle translated names and the name hints.
-
- * em-folder-tree.c (render_pixbuf): use the camel folderinfo
- folder type to determine the icon, don't hardcode based on name.
-
- ** See bug #71310
-
- * em-composer-prefs.c (sig_add_script_response): force a save of
- the signatures as soon as they change. Also save the script name
- if we were just editing it, not just the signature name.
-
** See bug #71312.
* em-folder-view.c (em_folder_view_open_selected): if we're
looking at a vfolder, then look open the original folder if we need
to perform any edits.
-2005-01-31 Hans Petter Jansson <hpj@novell.com>
-
- * importers/mail-importer.h (mc): Remove unused global symbol.
-
-2005-01-28 Jeffrey Stedfast <fejj@novell.com>
+2005-02-01 Not Zed <NotZed@Ximian.com>
- * message-list.c (message_list_set_folder): Reset the normalised
- string sort table.
+ ** See bug #71310
-2005-01-31 JP Rosevear <jpr@novell.com>
+ * em-composer-prefs.c (sig_add_script_response): force a save of
+ the signatures as soon as they change. Also save the script name
+ if we were just editing it, not just the signature name.
- Fixes #71937
+2005-02-01 Not Zed <NotZed@Ximian.com>
- * evolution-mail.schemas.in.in: fix spelling error
+ ** See bug #65329.
- * mail-errors.xml: fix two spelling errors
+ * mail-component.c (view_changed_cb): translate special names on
+ the local store.
2005-01-31 Not Zed <NotZed@Ximian.com>
-
- ** See bug #67083
-
- * em-format-html.c (efh_format_text_header): no-wrap the header line.
-
+
** See bug #69850
* mail-autofilter.c (rule_from_message): dont crash if we're
missing the requested headers.
- ** See bug #71521.
-
- * em-account-editor.c (emae_url_set_hostport): dont ever set a
- NULL host.
-
-2005-01-28 Not Zed <NotZed@Ximian.com>
-
- * em-account-editor.c (emae_service_provider_changed): handle
- 'hide' bits, don't get/set values from the widgets at all.
-
- * em-account-editor.c: put some tables back into the
- druid and editor, since econfig supports tables now.
-
- * em-account-editor.c (emae_service_provider_changed): handle
- 'hide' bits, don't get/set values from the widgets at all.
-
- * em-account-editor.c: put some tables back into the
- druid and editor, since econfig supports tables now.
-
- * em-account-editor.c (emae_service_provider_changed): handle
- 'hide' bits, don't get/set values from the widgets at all.
-
- * em-account-editor.c: put some tables back into the
- druid and editor, since econfig supports tables now.
-
- ** See bug #71520.
-
- * em-account-prefs.c (account_edit_clicked): repeat the nasty hack
- from account_edit, to refresh the list after edit.
-
-2005-01-27 Not Zed <NotZed@Ximian.com>
-
- * See bug #69815.
-
- * mail-component.c (impl_quit): shutdown vfolders as first step.
-
- * mail-vfolder.c (vfolder_setup_do): if we're shutdown during
- processing, just noop.
- (vfolder_adduri_do): same.
- (mail_vfolder_shutdown): set the shutdown flag.
-
-2005-01-27 Rodney Dawes <dobey@novell.com>
-
- * mail-config.glade: Fix the labels in the account druid to be
- left aligned, and justified left
- Fix the border and spacing for all the vboxes in the account druid
- pages to be HIG compliant
- Fix the account naming info label to be more concise
-
- Fixes #68696
-
-2005-01-27 Rodney Dawes <dobey@novell.com>
-
- * mail-send-recv.c (build_dialog): Fix the dialog to have borders
- that are HIG-compliant and fix up the spacing and padding of the
- internal widgets to do the right thing to be HIG compliant
-
-2005-01-27 JP Rosevear <jpr@novell.com>
-
- * em-format-hook.c: add a d(x) debugging define and default to off
-
-2005-01-26 Mengjie Yu <meng-jie.yu@sun.com>
-
- Fixes #71774
-
- * em-folder-tree.c (emft_popup_rename_folder): we should check
- whether the 'new_name' is a NULL pointer to avoid Evolution
- crashes.
-
-2005-01-25 Mengjie Yu <meng-jie.yu@sun.com>
-
- * em-mailer-prefs.c: (restore_labels_clicked),
- (em_mailer_prefs_construct):
- add a11y names for color pickers.
-
-2005-01-24 Hans Petter Jansson <hpj@novell.com>
-
- * Makefile.am (libevolution_mail_la_LIBADD): Pull in the contact
- editors, so we can pass pointers to their creation functions to
- ENameSelectorEntry.
-
-2005-01-24 JP Rosevear <jpr@novell.com>
-
- * searchtypes.xml: add back body contains
-
-2005-01-21 JP Rosevear <jpr@novell.com>
-
- Fixes #46287
-
- * mail-config.glade: remove enable/disable button
-
- * em-composer-prefs.h: remove unused button
-
- * em-composer-prefs.c (spell_language_toggled): handle the cell
- being toggled
- (spell_setup): enable/disable button is gone
- (em_composer_prefs_construct): setup a listener for the toggle
- cell
-
-2005-01-24 Radek Doulik <rodo@ximian.com>
+2005-01-14 Not Zed <NotZed@Ximian.com>
- * em-popup.[ch]: removed EM_POPUP_SELECT_MARK_[NO]JUNK masks
+ ** Related to changes for #65178.
-2005-01-20 Radek Doulik <rodo@ximian.com>
+ * mail-vfolder.c (mv_find_folder): changed from my_list_find, take
+ store arg and use camel_Store_Folder_uri_equal() instead of wrong
+ uri_cmp function.
+ (mail_vfolder_delete_uri): same.
+ (mail_vfolder_rename_uri): same.
+ (uri_is_ignore): take store arg, and same as above. use the right
+ uri for checking sent folder.
+ (mail_vfolder_*): convert to storing uri's in camel form.
- * em-folder-view.c: patch from Chris Lahey, makes Mark as Junk/not
- Junk items active on all messages, removes calls to
- message_list_get_selected where not needed
+2005-01-19 Not Zed <NotZed@Ximian.com>
-2005-01-24 Not Zed <NotZed@Ximian.com>
+ ** See bug #70858.
- * searchtypes.xml: changed for 69122.
+ * em-folder-selector.c (folder_created_cb): removed.
+ (emfs_response): set the selected uri directly after creating it,
+ rather than doing it asynchronously.
-2005-01-21 JP Rosevear <jpr@novell.com>
-
- Fixes #46404
-
- * em-folder-view.c (emfv_print_response): use the config in the
- print data and free it
- (em_folder_view_print): load the config from e_print and use the
- dialog from e_print
+ * mail-account-gui.c (mail_account_gui_save): dont dereference
+ default folder pointers if they're NULL.
2005-01-21 Not Zed <NotZed@Ximian.com>
@@ -309,30 +81,34 @@
* em-format-html-display.c (efhd_init, efhd_gtkhtml_style_set): if
the style changes, re-calculate the page colours, and redraw.
-2005-01-20 Jeffrey Stedfast <fejj@novell.com>
+2005-01-18 Not Zed <NotZed@Ximian.com>
- * em-folder-tree.c (emft_copy_folders__desc): Added a description
- function for copying folders (so we don't get a "Working 0x..."
- status message).
+ ** See bug #70768.
- * mail-mt.c (do_op_status): Always g_free(what) since we always
- strdup it.
+ * em-folder-browser.c (emfb_mark_all_read): get the uid list from
+ the message-list (view) rather than folder (model).
-2005-01-20 Not Zed <NotZed@Ximian.com>
+ * message-list.c (message_list_foreach): removed, no longer used.
+ (message_list_get_uids): new function replacing ml_foreach, get
+ visible uids's of messages.
- ** See bug #55831.
+2005-01-18 Not Zed <NotZed@Ximian.com>
+
+ * em-format-html.c (emfh_gethttp): kill old 'load http 0 now=0' debug.
- * evolution-mail.schemas.in.in: added open_many prompt key.
+ ** See bug #70563.
- * mail-errors.xml: added ask-open-many
+ * em-utils.c (emu_set_proxy, emu_proxy_setup)
+ (em_utils_get_proxy_uri): make sure the init code is called from
+ main thread (gconf usage), and add locking for data consistency.
- * em-folder-view.c (em_folder_view_open_selected): put back the
- 'you're opening too many are you sure' thing.
+2005-01-08 Not Zed <NotZed@Ximian.com>
-2005-01-19 Jeffrey Stedfast <fejj@novell.com>
+ * mail-account-gui.c (save_service): dont skip the authtype
+ setting if we don't have a needsauth widget at all (i.e. the store
+ page).
- * em-folder-properties.c (emfp_get_folder_item): Increment i each
- time thru the loop or we lose widgets.
+ * em-folder-tree.c (emft_get_folder_info__desc): fix broken cast.
2005-01-19 Not Zed <NotZed@Ximian.com>
@@ -344,11 +120,6 @@
(em_utils_composer_save_draft_cb): grab resources before getting
the folder, so the composer doesn't go away.
-2005-01-18 Rodrigo Moya <rodrigo@novell.com>
-
- * em-filter-source-element.c:
- * mail-config.c: removed e-url.h include.
-
2005-01-18 Not Zed <NotZed@Ximian.com>
** See bug #70768.
@@ -361,174 +132,20 @@
visible uids's of messages.
2005-01-18 Not Zed <NotZed@Ximian.com>
-
+
** See bug #71105.
* em-folder-tree.c (emft_popup_rename_folder): dont let a user
rename a folder to one including '/'.
- * em-format-html.c (emfh_gethttp): kill old 'load http 0 now=0' debug.
-
- ** See bug #70563.
-
- * em-utils.c (emu_set_proxy, emu_proxy_setup)
- (em_utils_get_proxy_uri): make sure the init code is called from
- main thread (gconf usage), and add locking for data consistency.
-
-2005-01-14 Not Zed <NotZed@Ximian.com>
-
- ** Related to changes for #65178.
-
- * mail-vfolder.c (mv_find_folder): changed from my_list_find, take
- store arg and use camel_Store_Folder_uri_equal() instead of wrong
- uri_cmp function.
- (mail_vfolder_delete_uri): same.
- (mail_vfolder_rename_uri): same.
- (uri_is_ignore): take store arg, and same as above. use the right
- uri for checking sent folder.
- (mail_vfolder_*): convert to storing uri's in camel form.
-
-2005-01-13 Not Zed <NotZed@Ximian.com>
-
- ** See bug #71029.
-
- * em-account-editor.c (emae_option_toggle): revert menjie's patch
- and do it using object args.
-
-2005-01-12 Not Zed <NotZed@Ximian.com>
-
- ** See bug #70990.
-
- * em-account-editor.c (emae_service_url_changed): if the value is
- "" then don't set it
-
- ** See bug #70018.
-
- * mail-signature-editor.c (mail_signature_editor): use the right
- version for the gtkhtml editor control.
-
-2005-01-11 Vivek Jain <jvivek@novell.com>
-
- * em-folder-tree.c (render_pixbuf): Added conditions to check for
- shared folders to display different icon if it is a shard folder.
-
-2005-01-07 Not Zed <NotZed@Ximian.com>
-
- * em-account-prefs.c (account_add_clicked): remove old code, setup
- transient parent and weak ref for refresh.
+ * em-format-html.c (emfh_gethttp): kill old 'load http 0 now=0' debug.
+
+2004-12-01 Not Zed <NotZed@Ximian.com>
-2005-01-06 JP Rosevear <jpr@novell.com>
+ ** See bug #69851.
- * Makefile.am: install schemas properly
-
-2005-01-06 Jeffrey Stedfast <fejj@novell.com>
-
- * mail-folder-cache.c (mail_note_store): Handle the
- CamelOfflineStore case just like the CamelDiscoStore case.
-
- * mail-ops.c (prep_offline_do): Since we can't kill off
- CamelDisco* (groupwise is using it), we have to handle both
- CamelOfflineFolder and CamelDiscoFolder for now.
- (set_offline_do): Same.
-
-2005-01-05 Not Zed <NotZed@Ximian.com>
-
- * em-menu.c: (emph_targets[]): Add the widget target, missed this.
-
-2005-01-05 Not Zed <NotZed@Ximian.com>
-
- * em-menu.c (em_menu_target_new_widget): add a semi-dummy target
- for widget target.
-
- * mail-component.c (handleuri_got_folder): handle the "reply"
- parameter, if set.
-
- * em-composer-utils.c (em_utils_reply_to_message): only ref the
- source if supplied.
- (reply_to_message): only unref the source if supplied.
-
-2004-12-28 Mengjie Yu <meng-jie.yu@sun.com>
-
- * em-folder-tree.c: (em_folder_tree_new_with_model):
- add atk name for the treeview.
-
-2004-12-22 Not Zed <NotZed@Ximian.com>
-
- * em-account-editor.c (emae_needs_auth): moved to after
- emae_authtype_changed to fix warning.
-
-2004-12-17 Not Zed <NotZed@Ximian.com>
-
- * em-format-html-display.c (efhd_attachment_popup):
-
- * message-list.c (ml_tree_drag_data_received):
-
- * em-folder-view.c (emfv_popup, emfv_format_popup_event):
-
- * em-folder-tree.c (tree_drag_data_received): api changes.
- (emft_popup):
-
- * em-popup.c (emp_standard_menu_factory)
- (emp_standard_menu_factory): api changes.
-
-2004-12-21 Not Zed <NotZed@Ximian.com>
-
- * em-account-editor.c (emae_needs_auth): if we're turned on, then
- record the current authtype setting on the widgets, if we're
- turned off, clear the authmech setting.
- (emae_setup_service): setup the needs auth after the authtype, and
- get setting from url->authmech.
- (emae_service_provider_changed): only clear the url->authmech if
- we don't have the current one in our list.
-
-2004-12-20 Takeshi AIHANA <aihana@gnome.gr.jp>
-
- * default/Makefile.am: Added 'ja' and 'nl' to install.
-
-2004-12-14 Rodney Dawes <dobey@novell.com>
-
- * mail-account-gui.c: Remove this from CVS
-
- * mail-config.glade: Use em_account_editor_folder_selector_button_new
- instead of mail_account_gui_folder_selector_button_new
-
-2004-12-14 JP Rosevear <jpr@novell.com>
-
- Fixes #68759
-
- * mail-account-gui.c (service_check_supported): fix typo in
- routine name
-
-2004-12-08 Hans Petter Jansson <hpj@novell.com>
-
- * importers/pine-importer.c: Include <libebook/e-destination.h> from
- evolution-data-server.
-
-2004-12-08 Rodney Dawes <dobey@novell.com>
-
- * em-folder-tree.c:
- * mail-component.c (impl__get_userCreatableItems):
- Use stock_new-dir instead of stock_folder for "New Folder" creation
-
-2004-12-07 Mengjie Yu <meng-jie.yu@sun.com>
-
- * mail-config.glade: add mnemonic for buttons, labels, etc.
- * mail-dialogs.glade:add mnemonic for buttons, labels, etc.
- * message-tags.glade:add mnemonic for buttons, labels, etc.
-
-2004-12-08 Not Zed <NotZed@Ximian.com>
-
- * mail-component-factory.c (make_factory): and put them here
- instead so they're available even when the mailer isn't activated
- yet.
-
- * mail-component.c (mc_startup): remove plugin hook registrations.
-
-2004-11-22 Not Zed <NotZed@Ximian.com>
-
- * em-account-editor.c (emae_receive_options_extra_item): dont
- track containee widgets anymore, they are automagically destroyed
- by the container if required.
+ * mail-account-gui.c (save_service): dont skip the save_password
+ setting if we don't have a needs_auth widget.
2004-11-25 Radek Doulik <rodo@ximian.com>
@@ -540,22 +157,6 @@
Fixes #69623
-2004-12-01 Mengjie Yu <meng-jie.yu@sun.com>
-
- * em-account-editor.c:according to the HIG, remove accelerators in
- the notebook tab labels
-
-2004-12-01 Mengjie Yu <meng-jie.yu@sun.com>
-
- * em-account-editor.c: (emae_option_toggle),
- (emae_receive_options_item):add mnemonic for buttons.
- * em-format-html-display.c: (efhd_attachment_button):add atk name
- for the popup button.
- * mail-account-gui.c: (mail_account_gui_build_extra_conf):add
- access key for checkbox.
- * message-list.c: (message_list_construct):add a atk name for the
- message list.
-
2004-11-22 Not Zed <NotZed@Ximian.com>
** See bug #69339.
@@ -597,87 +198,20 @@
some strcasecmp() calls changed with g_ascii_strcasecmp() for Turkish
character conversiton problems [ http://www.i18nguy.com/unicode/turkish-i18n.html ]
-2004-11-26 JP Rosevear <jpr@novell.com>
-
- * em-format.c: wrap printf's in debug defines
-
-2004-11-26 JP Rosevear <jpr@novell.com>
-
- * em-format-html-display.c (efhd_xpkcs7mime_button): get image
- widget directly from icon factory
-
- * mail-send-recv.c (build_dialog): ditto
-
-2004-10-12 Radek Doulik <rodo@ximian.com>
-
- * em-junk-filter.c: when starting new spamd, call it with
- --socketpath parameter to use unix sockets instead of opening TCP
- port. kill such started daemon in finalize callback which is
- installed by atexit. also try to respawn spamd in case spamc
- returns error, if respawning is too fast (8 restarts in last 5
- minutes) fallback to spamassassin
-
- * mail-component.c (impl_quit): call mail_session_quit
-
- * mail-session.c (mail_session_init): call junk plugin init
- (mail_session_quit): new method, called on evo exit
-
-2004-11-22 Joan Sanfeliu <joan@fibranet.com>
-
- * mail-config.glade : Evolution word spelled with an uppercase E
-
- Fixes #61065
-
-2004-11-16 Not Zed <NotZed@Ximian.com>
-
- * Makefile.am:
- * importers/Makefile.am: Removed camel linking.
-
-2004-11-15 Not Zed <NotZed@Ximian.com>
-
- * *.c: Moved various things from e-util to libedataserver.
-
- * GNOME_Evolution_Mail.server.in.in: remove the startup wizard stuff.
+2004-11-10 Not Zed <NotZed@Ximian.com>
- * mail-config-druid.[ch]:
- * mail-account-editor.[ch]:
- * mail-account-gui.[ch]: removed & deleted.
+ ** See bug #68794.
- * mail-session.c (mail_session_init): and here too.
- * em-migrate.c (em_migrate_1_4): init camel-provider library too.
- (e_path_to_physical): copy from e-util/e-path.c.
+ * mail-account-gui.h: moved the needs_auth checkbox to the service
+ structure so it can be checked in save_service. removed the
+ transport_needs_auth field. the 'source' one is always NULL.
- * Makefile.am (libevolution_mail_la_LIBADD): link to new libcamel
- provider too.
-
-2004-11-12 Not Zed <NotZed@Ximian.com>
-
- * filtertypes.xml:
- * vfoldertypes.xml:
- * searchtypes.xml: Added 'match all' rules.
-
- ** Merge in notzed-messageinfo-branch.
-
-2004-11-11 Radek Doulik <rodo@ximian.com>
-
- * em-format-hook.c (emfh_enable): l = g_list_next (l); in inner
- loop instead of g = g_list_next (l).. probably typo after c'n'p
-
- * em-format.c (em_format_class_remove_handler): in case the old
- handler doesn't exist, remove 'info' handler from type_handler
- table
+ * mail-account-gui.c (save_service): check the needs-auth checkbox
+ rather than the round-a-bout and functionless sensitivity check on
+ the widget.
2004-11-03 Not Zed <NotZed@Ximian.com>
- * em-folder-view.c (emfv_popup): Fix the popup id.
-
-2004-11-03 Not Zed <NotZed@Ximian.com>
-
- * em-folder-view.c (emfv_list_done_message_selected): revert
- jeff's last change - we do actually want to know when we couldn't
- load a message. the crash he was fixing was fixed elsewhere.
- also fix the unref ordering stuff.
-
* em-format-html.c (efh_format_timeout): removed the fixme i
added.
@@ -694,131 +228,17 @@
(em_format_part_as): track content-base (& absolute
content-location) of all parts here.
-2004-11-02 Not Zed <NotZed@Ximian.com>
-
- * em-event.c (eme_target_free, em_event_target_new_message):
- handle NULL folder or message.
-
-2004-11-02 Jeffrey Stedfast <fejj@novell.com>
-
- * em-folder-view.c (emfv_list_done_message_selected): Check for
- NULL messages (happens if the message isn't available).
-
-2004-11-02 Radek Doulik <rodo@ximian.com>
-
- * em-format-html.c: replace 3 nested html tables used to create
- this gray border around parts content with div block with border
- style
- use shorthand border: property
-
-2004-11-01 Jeffrey Stedfast <fejj@novell.com>
-
- * em-account-editor.c: Change the labels back to the same as they
- were in 2.0
-
-2004-11-12 Not Zed <NotZed@Ximian.com>
-
- * mail-send-recv.c (auto_account_finalised): fix the callback
- signature.
-
-2004-11-11 Not Zed <NotZed@Ximian.com>
-
- * mail-component.c (mc_add_store):
- (mc_add_store_done): Let the counters know about the junk/trash
- folders that have already been opened.
-
- * em-vfs-stream.[ch]: Added stream class to read/write gnome-vfs
- data from camel. NFI if this will work, depends on how
- thread-safe gnome-vfs is.
-
-2004-11-08 Not Zed <NotZed@Ximian.com>
-
- * mail-vfolder.c (uri_is_spethal): fix the special check for local
- folders.
-
-2004-10-30 Not Zed <NotZed@Ximian.com>
-
- * */*.c, *.c: camel api changes.
-
-2004-10-28 Not Zed <NotZed@Ximian.com>
-
- * mail-folder-cache.c (real_flush_updates):
- * em-message-browser.c (em_message_browser_new):
- * em-mailer-prefs.c (em_mailer_prefs_construct):
- * em-format-html-display.c (efhd_attachment_popup):
- * em-folder-view.c (emfv_popup, emfv_list_done_message_selected)
- (emfv_format_popup_event):
- * em-folder-tree.c (emft_popup):
- * em-folder-properties.c (emfp_dialog_got_folder):
- * em-folder-browser.c (em_folder_browser_new):
- * em-composer-utils.c (em_utils_reply_to_message):
- * em-composer-prefs.c (em_composer_prefs_construct):
- * em-account-editor.c (em_account_editor_construct): added hook
- docs, and cleaned up some of the hook point names.
-
-2004-10-22 Jeffrey Stedfast <fejj@novell.com>
-
- * em-folder-tree.c: Give the Rename item a different path than the
- Delete item.
-
-2004-10-22 Not Zed <NotZed@Ximian.com>
-
- * em-event.c (eme_target_free): duh, they're camel not gobjects.
-
- * em-folder-view.c (emfv_list_done_message_selected): added a
- message.reading event.
-
-2004-10-22 Nat Friedman <nat@novell.com>
-
- * em-event.c: Add a REPLY_ALL flag to the Message target.
- * em-composer-utils.c (em_utils_reply_to_message): Set the
- REPLY_ALL flag when appropriate.
-
-2004-10-21 Not Zed <NotZed@Ximian.com>
-
- * em-composer-utils.c (em_utils_reply_to_message): emit a
- 'message.replying' event with a message target.
-
-2004-10-21 Nat Friedman <nat@novell.com>
-
- * em-event.c (em_event_target_new_message): new target type for
- message-related events.
-
-2004-10-21 Not Zed <NotZed@Ximian.com>
-
- * em-folder-view.c (emfv_format_popup_event): put 'evolution' back
- in the popup hook names.
-
-2004-10-19 JP Rosevear <jpr@novell.com>
-
- * em-account-editor.c, em-composer-prefs.c, em-config.c,
- em-event.c, em-folder-browser.c, em-folder-properties.c,
- em-folder-tree.c, em-folder-view.c, em-format-hook.c,
- em-format-html-display.c, em-mailer-prefs.c, em-menu.c,
- em-message-browser.c, em-popup.c, message-list.c: convert to
- org.gnome hook names
-
-2004-10-19 JP Rosevear <jpr@novell.com>
-
- * message-list.c: convert to G_DEFINE_TYPE
-
2004-10-11 Not Zed <NotZed@Ximian.com>
** See bug #67014.
- * mail-errors.xml: added "checking-service" error.
-
- * em-account-editor.c (em_account_editor_construct): keep track of
- the dialogue
- (emae_editor_destroyed): , and clean up when destroyed.
-
- * em-account-editor.c (emae_check_authtype)
- (emae_check_authtype_response, emae_check_authtype_done): handle
- checking authtype gui here.
-
* mail-config.c (check_service_describe, check_service_check)
(check_response, mail_config_check_service): removed.
+ * mail-account-gui.c (service_check_supported): call
+ mail_check_service to do the checking async. Make the popopup
+ window non-modal, but de-sensitize the dialog instead.
+
* mail-ops.c (mail_check_service): moved here from mail-config,
and modified to be a re-usable threaded function.
@@ -829,23 +249,6 @@
* em-folder-view.c (emfv_init): dont ref/sink the invisible.
(emfv_destroy): just destroy it here.
-2004-10-15 Not Zed <NotZed@Ximian.com>
-
- * em-composer-utils.c (create_new_composer):
- (em_utils_compose_new_message, forward_non_attached): do noting if
- the composer couldn't be created. We get a popup from elsewhere
- to let the user know.
-
-2004-10-14 Sivaiah Nallagatla <snallagatla@novell.com>
-
- * mail-errors.xml : Remove Pango markup from groupwise
- account setup error message
-
-2004-10-12 Not Zed <NotZed@Ximian.com>
-
- * em-format-html-display.c (efhd_find_handler): use builtin
- handlers (and plugins) always overriding bonobo ones.
-
2004-10-11 Not Zed <NotZed@Ximian.com>
** See bug #67408.
@@ -854,27 +257,10 @@
destroyed.
(emfv_destroy): set destroyed bit.
-2004-10-11 Not Zed <NotZed@Ximian.com>
+2004-10-07 JP Rosevear <jpr@novell.com>
- * mail-component.c (mc_startup): register the formatter types
- before registering the formatter hook.
-
-2004-10-08 JP Rosevear <jpr@novell.com>
-
- * mail-account-gui.c (browse_clicked): use "Select a file"
-
-2004-10-08 Harry Lu <harry.lu@sun.com>
-
- * em-folder-tree.c: (em_folder_tree_class_init), (real_popup_menu),
- (emft_popup_menu), (emft_tree_button_press): implement popup_menu
- so that popup menu can be shown with Shift+F10 on folder tree.
- * em-folder-view.c: (emfv_popup), (emfv_list_key_press):
- same as above.
-
-2004-10-07 Not Zed <NotZed@Ximian.com>
-
- * mail-component.c (mc_startup): dont init the base plugin system
- here anymore, only register the hook types for mail hooks.
+ * mail-account-gui.c (browse_clicked): use "Select a file" so as
+ not to break string freeze
2004-09-28 Not Zed <NotZed@Ximian.com>
@@ -884,12 +270,6 @@
2004-10-06 Not Zed <NotZed@Ximian.com>
- * em-folder-tree.c (emft_get_folder_info__desc): fix busted cast.
-
- * *.c: e-popup api changes.
-
-2004-10-06 Not Zed <NotZed@Ximian.com>
-
* em-folder-tree.c (emft_tree_button_press): remove some debug
that made it in accidentally.
@@ -909,10 +289,6 @@
* em-migrate.c (upgrade_passwords_1_2): fix uninitialised pointer.
-2004-09-27 Jeffrey Stedfast <fejj@novell.com>
-
- * em-account-editor.c: Changed the SSL option menu labels.
-
2004-09-21 Not Zed <NotZed@Ximian.com>
** See bug #63521.
@@ -980,6 +356,65 @@
emfv->mark_seen for deciding whether or not to mark the message as
seen. Fixes bug #65448.
+2004-09-08 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #60515.
+
+ * mail-account-gui.c (sig_fill_menu): connect to the activate
+ signal for the none item.
+
+2004-09-01 Jeffrey Stedfast <fejj@novell.com>
+
+ Fix for bug #63377 and prevention of similar cases.
+
+ * em-format.c (emf_finalise): Free the default_charset.
+ (emf_format_clone): Clone the default_charset - this prevents the
+ particular crash described in bug #63377.
+
+ * em-utils.c (em_utils_message_to_html): If source is NULL, set
+ our own default charset (from the user's gconf key) on the
+ formatter to make sure there's always a source charset for
+ conversion to UTF-8.
+
+2004-08-30 Jeffrey Stedfast <fejj@novell.com>
+
+ * em-folder-tree.c (emft_popup_delete_folder): Set the store and
+ full_name info on the dialog.
+ (emft_popup_delete_response): Use the requisite data stored on the
+ dialog object rather than examining the selection again. Fixes bug
+ #62665.
+
+2004-08-30 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #64377.
+
+ * em-folder-selector.c (emfs_response): only set the uri if we
+ have one to set.
+
+ * em-folder-tree.c (em_folder_tree_finalize): Removed
+ cose using selected_path and selected_uri strings.
+ (emft_popup_new_folder): "
+ (emft_popup_copy_folder_selected): "
+ (emft_tree_selection_changed):
+ (emft_tree_row_activated): ", free paths after use.
+
+ * em-folder-selector.c (emfs_create_name_changed): free
+ get_selected_uri return.
+ (emfs_create_name_activate): "
+ (em_folder_selector_get_selected_path): handle api change, store
+ the selected_path too.
+
+ * em-folder-tree.c (em_folder_tree_get_selected_uri):
+ de-constify,and get the selection directly from the tree.
+ (em_folder_tree_get_selected_path): same.
+
+2004-08-27 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #63456.
+
+ * message-list.c (main_folder_changed): noop if the async_event
+ pointer is NULL which can happen during destroy.
+
2004-09-09 Jeffrey Stedfast <fejj@novell.com>
* mail-account-gui.c (mail_account_gui_new): If built with
@@ -1387,216 +822,6 @@
* Makefile.am (SUBDIRS): Revert previous error change
-2004-09-10 Not Zed <NotZed@Ximian.com>
-
- * em-*: various doco updates.
-
- * em-format-quote.c (emfq_builtin_init): instead of removing the
- type, just add an override noop. Changed api's.
-
-2004-09-09 Not Zed <NotZed@Ximian.com>
-
- * em-format.c (em_format_class_remove_handler): Change this to use
- the original structure only, not by type.
-
- * em-format-hook.c (emfh_enable): implement hook enablation.
-
-2004-09-07 Not Zed <NotZed@Ximian.com>
-
- * em-account-editor.c (emae_setup_providers): set the provider
- shown selected on the store as well.
-
- * mail-config.glade: moved the druid 'help text' directly into the
- glade file.
-
- * em-account-editor.c (emae_check_complete): add pre-load for
- management page options.
-
- * em-utils.c (em_utils_configure_account): remove use of
- mail-config-druid.
-
- * em-account-editor.c (emae_remove_childen): removed.
- (*): removed service->url, always get it from/set it to the
- e-account so it doesn't have side-effects with plugins.
-
- * mail-dialogs.glade: fix up the names of the various license
- dialog fields.
-
-2004-09-06 Not Zed <NotZed@Ximian.com>
-
- * em-account-editor.c (emae_receive_options_extra_item): store the
- config widgets in the item entry itself.
- (emae_auto_detect): wasted a whole lot of time on this crap.
-
- * em-account-prefs.c (account_able_clicked): removed some redundant logic.
-
- * mail-send-recv.c (mail_autoreceive_setup): renamed to
- mail_autoreceive_init and rewrote all the callbacks. now it
- listens to events on the accountlist directly and doesn't need
- invoking manually. It also runs relative to the account always,
- rather than copying the uri. Removed all callers except the mail
- component one.
-
- * em-account-editor.c (em_account_editor_provider_selector_new):
- removed becaus eof below.
- (em_account_editor_construct): copy the account to a working
- object if supplied, else create a new one.
-
- * mail-config.glade: make the provider selectors just use
- em_account_editor_dropdown new for the dropdown menu.
-
- * em-account-editor.c (prepare_signatures): removed, merged into
- the identity page code.
- (sig_fill_menu): removed.
- (emae_setup_signatures): new function to setup signatures on a
- gtkcombobox.
- (clear_menu): removed.
- (signature_changed): removed.
- (emae_signature_changed): new function for changed.
- (signature_removed): removed.
- (emae_signature_removed): new function for removed.
- (emae_signature_get_iter): helper for finding the right row for
- this signature.
- (signature_added): removed.
- (emae_signature_added): new function for added.
- (sig_activate): removed.
- (emae_signaturetype_changed): new function to update the account
- info immediately.
- (sig_add_new_signature): renamed to emae_signature_new.
- (select_account_signature): no longer needed, this happens in the
- setup.
-
- * mail-config.glade: changed the signature thing to a custom
- widget (gtkcombobox).
-
- * em-account-editor.c (em_account_editor_construct): updates for
- api change, table sections require table items.
- (emae_setup_service): handle host:port hostname syntax.
- (emae_hostname_changed): and here too.
- (emae_commit): fill this out, and implement it.
-
-2004-09-04 Not Zed <NotZed@Ximian.com>
-
- * *.c: include gnome i18.h if needed since camel-object.h was
- fixed.
-
- * em-format.c (em_format_class_add_handler): if a handler is
- already set for type, link it in.
-
- * em-format.h: added a link pointer to EMFormatHanlder, so that
- overrides can also fallback. remove applications member - not
- used anymore.
-
-2004-09-01 Not Zed <NotZed@Ximian.com>
-
- * em-popup.h: added some docs.
-
- * em-popup.c (emp_standard_menu_factory):
- * em-folder-tree.c (tree_drag_data_received): popup api changes.
-
-2004-08-31 Not Zed <NotZed@Ximian.com>
-
- * em-format-html-display.c (efhd_attachment_button_show): use a
- wrapper for the button event since the popup event has changed
- signature.
-
-2004-08-30 Not Zed <NotZed@Ximian.com>
-
- * em-popup.c (emp_standard_menu_factory): changed args.
- (struct _open_in_item): removed, use user data instead.
- (*): fix callbacks for new apis.
- (emp_popup_open): Removed some dead popup callbacks never invoked.
- (em_popup_target_new_attachments): new target type for attachment
- bar in composer.
-
- * em-folder-tree.c (emft_popup*): convert to new e-popup apis.
-
- * em-folder-view.c: emfv_popup_*: convert to new e-poup callback
- signatures.
- (EMFV_MAP_CALLBACK): fix for e-popup callback change.
- (EMFV_POPUP_AUTO_TYPE): same.
- (emfv_popup): dont bother setting item callback data.
- (emfv_popup_labels_free): api changes.
- (emfv_popup_items_free): new free method.
- (EMFVPopupItem): No longer needed.
- (emfv_uri_popup_free): api changes.
- (emfv_format_popup_event): new api's == simpler code.
-
- * em-account-editor.c (emae_receive_options_extra_item): add a
- hack for the label item, which is only used by connector to
- override the hostname and username labels.
-
-2004-08-24 Not Zed <NotZed@Ximian.com>
-
- * em-account-editor.c (em_account_editor_construct): create the
- window rather than the widget here.
-
- * mail-config.glade: remove the extra_page from the druid, it is
- autogenerated now. renamed the "Receiving options" notebook page
- to "Receiving Email" since it isn't hte options page.
-
- * em-account-editor.c (emae_receive_options_page): no longer
- needed, autogenerated.
- (emae_receive_options_item): setup the auto-receive time values.
- (emae_receive_page): don't setup the auto check time values here.
-
- * mail-config.glade: Remove the Receiving Mail tab, it is now
- completely auto-generated.
-
-2004-08-17 Not Zed <NotZed@Ximian.com>
-
- * em-event.[ch]: mail event dispatcher.
-
- * mail-component.c (mc_startup): hook into events.
-
- * mail-folder-cache.c (update_1folder): always set the uri field.
- (real_flush_updates): emit a folder.changed:new event if we have new
- mail.
-
-2004-08-13 Not Zed <NotZed@Ximian.com>
-
- * mail-config.glade: replaced ssl selector with custom widget
- (gtkcombobox). Giv the preferences, composer toplevel unique
- names.
-
-2004-07-29 Not Zed <NotZed@Ximian.com>
-
- * mail-config.glade: replaced source and transport selector with
- custom widget (gtkcombobox).
-
- * em-account-editor.[ch]: copy over mail-account-gui.[ch] and
- rename stuff. Make a gobject. Move most internals, internal.
-
-2004-07-28 Not Zed <NotZed@Ximian.com>
-
- * em-composer-prefs.c (em_composer_prefs_construct): get the
- toplevel tab as the root.
- (em_composer_prefs_construct): setup plugin metadata for composer
- prefs.
-
- * em-mailer-prefs.c (em_mailer_prefs_construct): setup plugin
- metadata for mail preferences.
-
- * em-config.c (em_config_target_new_prefs): new target for 'prefs'
- mode, everything global via gconf.
-
- * em-mailer-prefs.c (em_mailer_prefs_construct): get the gui from
- the preferences_toplevel not the preferences_tab window which we
- don't need.
-
- * mail-config.glade: rename the preferences 'toplevel' to
- preferences_toplevel so we can get it unparented. And the
- composer toplevel to composer_toplevel.
-
- * em-folder-properties.c (em_folder_properties_show): remove test
- code.
-
- * em-format.h (struct _EMFormatPURI): add a free function
- callback.
-
- * em-format.c (emf_clear_puri_node): if the free function is set,
- call it.
-
2004-07-01 Rodney Dawes <dobey@novell.com>
* Makefile.am (BUILT_SOURCES): Remove $(error_i18n)
diff --git a/mail/em-composer-prefs.c b/mail/em-composer-prefs.c
index 7a3cd88beb..2867fa50e5 100644
--- a/mail/em-composer-prefs.c
+++ b/mail/em-composer-prefs.c
@@ -38,7 +38,7 @@
#include <bonobo/bonobo-generic-factory.h>
-#include <libedataserver/e-iconv.h>
+#include <gal/util/e-iconv.h>
#include <gal/widgets/e-gui-utils.h>
#include <gtk/gtktreemodel.h>
@@ -66,7 +66,6 @@
#include "mail-config.h"
#include "mail-signature-editor.h"
-#include "em-config.h"
#define d(x)
@@ -583,6 +582,28 @@ spell_color_set (GtkWidget *widget, guint r, guint g, guint b, guint a, EMCompos
gconf_client_set_int (prefs->gconf, GNOME_SPELL_GCONF_DIR "/spell_error_color_blue", b, NULL);
}
+static void
+spell_live_toggled (GtkWidget *widget, gpointer user_data)
+{
+ /* FIXME: what gconf key is this? */
+}
+
+static void
+spell_language_selection_changed (GtkTreeSelection *selection, EMComposerPrefs *prefs)
+{
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+ gboolean state = FALSE;
+
+ if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
+ gtk_tree_model_get ((GtkTreeModel *) model, &iter, 0, &state, -1);
+ gtk_button_set_label ((GtkButton *) prefs->spell_able_button, state ? _("Disable") : _("Enable"));
+ state = TRUE;
+ }
+
+ gtk_widget_set_sensitive (prefs->spell_able_button, state);
+}
+
static char *
spell_get_language_str (EMComposerPrefs *prefs)
{
@@ -619,25 +640,58 @@ spell_get_language_str (EMComposerPrefs *prefs)
return rv;
}
-static void
-spell_language_toggled (GtkCellRendererToggle *renderer, const char *path_string, EMComposerPrefs *prefs)
+static void
+spell_language_enable (GtkWidget *widget, EMComposerPrefs *prefs)
{
- GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+ GtkTreeSelection *selection;
+ gboolean state;
+ char *str;
+
+ selection = gtk_tree_view_get_selection (prefs->language);
+ if (!gtk_tree_selection_get_selected (selection, &model, &iter))
+ return;
+
+ gtk_tree_model_get (model, &iter, 0, &state, -1);
+ gtk_list_store_set ((GtkListStore *) model, &iter, 0, !state, -1);
+ gtk_button_set_label ((GtkButton *) prefs->spell_able_button, state ? _("Enable") : _("Disable"));
+
+ str = spell_get_language_str (prefs);
+ gconf_client_set_string (prefs->gconf, GNOME_SPELL_GCONF_DIR "/language", str ? str : "", NULL);
+ g_free (str);
+}
+
+static gboolean
+spell_language_button_press (GtkTreeView *treeview, GdkEventButton *event, EMComposerPrefs *prefs)
+{
+ GtkTreeViewColumn *column = NULL;
+ GtkTreePath *path = NULL;
GtkTreeModel *model;
GtkTreeIter iter;
gboolean enabled;
char *str;
- model = gtk_tree_view_get_model (prefs->language);
+ if (!(gtk_tree_view_get_path_at_pos (treeview, event->x, event->y, &path, &column, NULL, NULL)))
+ return FALSE;
+
+ /* FIXME: This routine should just be a "toggled" event handler on the checkbox cell renderer which
+ has "activatable" set. */
+
+ if (strcmp (gtk_tree_view_column_get_title (column), _("Enabled")) != 0)
+ return FALSE;
+
+ model = gtk_tree_view_get_model (treeview);
gtk_tree_model_get_iter (model, &iter, path);
gtk_tree_model_get (model, &iter, 0, &enabled, -1);
gtk_list_store_set ((GtkListStore *) model, &iter, 0, !enabled, -1);
+ gtk_button_set_label ((GtkButton *) prefs->spell_able_button, enabled ? _("Enable") : _("Disable"));
str = spell_get_language_str (prefs);
gconf_client_set_string (prefs->gconf, GNOME_SPELL_GCONF_DIR "/language", str ? str : "", NULL);
g_free (str);
-
- gtk_tree_path_free (path);
+
+ return FALSE;
}
static void
@@ -664,6 +718,14 @@ spell_setup (EMComposerPrefs *prefs)
widget = glade_xml_get_widget (prefs->gui, "colorpickerSpellCheckColor");
g_signal_connect (widget, "color_set", G_CALLBACK (spell_color_set), prefs);
+
+ widget = glade_xml_get_widget (prefs->gui, "buttonSpellCheckEnable");
+ g_signal_connect (widget, "clicked", G_CALLBACK (spell_language_enable), prefs);
+
+ widget = glade_xml_get_widget (prefs->gui, "chkEnableSpellChecking");
+ g_signal_connect (widget, "toggled", G_CALLBACK (spell_live_toggled), prefs);
+
+ g_signal_connect (prefs->language, "button_press_event", G_CALLBACK (spell_language_button_press), prefs);
}
static gboolean
@@ -782,36 +844,6 @@ toggle_button_init (EMComposerPrefs *prefs, GtkToggleButton *toggle, int not, co
gtk_widget_set_sensitive ((GtkWidget *) toggle, FALSE);
}
-static GtkWidget *
-emcp_widget_glade(EConfig *ec, EConfigItem *item, struct _GtkWidget *parent, struct _GtkWidget *old, void *data)
-{
- EMComposerPrefs *prefs = data;
-
- return glade_xml_get_widget(prefs->gui, item->label);
-}
-
-/* plugin meta-data */
-static EMConfigItem emcp_items[] = {
- { E_CONFIG_BOOK, "", "composer_toplevel", emcp_widget_glade },
- { E_CONFIG_PAGE, "00.general", "vboxGeneral", emcp_widget_glade },
- { E_CONFIG_SECTION, "00.general/00.behavior", "vboxBehavior", emcp_widget_glade },
- { E_CONFIG_SECTION, "00.general/10.alerts", "vboxAlerts", emcp_widget_glade },
- { E_CONFIG_PAGE, "10.signatures", "vboxSignatures", emcp_widget_glade },
- /* signature/signatures and signature/preview parts not usable */
-
- { E_CONFIG_PAGE, "20.spellcheck", "vboxSpellChecking", emcp_widget_glade },
- { E_CONFIG_SECTION, "20.spellcheck/00.languages", "vbox178", emcp_widget_glade },
- { E_CONFIG_SECTION, "20.spellcheck/00.options", "vboxOptions", emcp_widget_glade },
-};
-
-static void
-emcp_free(EConfig *ec, GSList *items, void *data)
-{
- /* the prefs data is freed automagically */
-
- g_slist_free(items);
-}
-
static void
em_composer_prefs_construct (EMComposerPrefs *prefs)
{
@@ -820,34 +852,24 @@ em_composer_prefs_construct (EMComposerPrefs *prefs)
GladeXML *gui;
GtkListStore *model;
GtkTreeSelection *selection;
- GtkCellRenderer *cell_renderer;
int style;
char *buf;
- EMConfig *ec;
- EMConfigTargetPrefs *target;
- GSList *l;
- int i;
prefs->gconf = mail_config_get_gconf_client ();
- gui = glade_xml_new (EVOLUTION_GLADEDIR "/mail-config.glade", "composer_toplevel", NULL);
+ gui = glade_xml_new (EVOLUTION_GLADEDIR "/mail-config.glade", "composer_tab", NULL);
prefs->gui = gui;
prefs->sig_script_gui = glade_xml_new (EVOLUTION_GLADEDIR "/mail-config.glade", "vbox_add_script_signature", NULL);
-
- /** @HookPoint-EMConfig: Mail Composer Preferences
- * @Id: org.gnome.evolution.mail.composerPrefs
- * @Type: E_CONFIG_BOOK
- * @Class: org.gnome.evolution.mail.config:1.0
- * @Target: EMConfigTargetPrefs
- *
- * The mail composer preferences settings page.
- */
- ec = em_config_new(E_CONFIG_BOOK, "org.gnome.evolution.mail.composerPrefs");
- l = NULL;
- for (i=0;i<sizeof(emcp_items)/sizeof(emcp_items[0]);i++)
- l = g_slist_prepend(l, &emcp_items[i]);
- e_config_add_items((EConfig *)ec, l, NULL, NULL, emcp_free, prefs);
-
+
+ /* get our toplevel widget */
+ toplevel = glade_xml_get_widget (gui, "toplevel");
+
+ /* reparent */
+ gtk_widget_ref (toplevel);
+ gtk_container_remove (GTK_CONTAINER (toplevel->parent), toplevel);
+ gtk_container_add (GTK_CONTAINER (prefs), toplevel);
+ gtk_widget_unref (toplevel);
+
/* General tab */
/* Default Behavior */
@@ -884,19 +906,19 @@ em_composer_prefs_construct (EMComposerPrefs *prefs)
prefs->language = GTK_TREE_VIEW (glade_xml_get_widget (gui, "listSpellCheckLanguage"));
model = gtk_list_store_new (3, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_POINTER);
gtk_tree_view_set_model (prefs->language, (GtkTreeModel *) model);
- cell_renderer = gtk_cell_renderer_toggle_new ();
gtk_tree_view_insert_column_with_attributes (prefs->language, -1, _("Enabled"),
- cell_renderer,
+ gtk_cell_renderer_toggle_new (),
"active", 0,
NULL);
- g_signal_connect (cell_renderer, "toggled", G_CALLBACK (spell_language_toggled), prefs);
-
gtk_tree_view_insert_column_with_attributes (prefs->language, -1, _("Language(s)"),
gtk_cell_renderer_text_new (),
"text", 1,
NULL);
selection = gtk_tree_view_get_selection (prefs->language);
- gtk_tree_selection_set_mode (selection, GTK_SELECTION_NONE);
+ gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
+ g_signal_connect (selection, "changed", G_CALLBACK (spell_language_selection_changed), prefs);
+
+ prefs->spell_able_button = glade_xml_get_widget (gui, "buttonSpellCheckEnable");
info_pixmap = glade_xml_get_widget (gui, "pixmapSpellInfo");
gtk_image_set_from_stock (GTK_IMAGE (info_pixmap), GTK_STOCK_DIALOG_INFO, GTK_ICON_SIZE_BUTTON);
if (!spell_setup_check_options (prefs)) {
@@ -970,14 +992,9 @@ em_composer_prefs_construct (EMComposerPrefs *prefs)
g_signal_connect (prefs->sig_preview, "url_requested", G_CALLBACK (url_requested), NULL);
gtk_widget_show (GTK_WIDGET (prefs->sig_preview));
gtk_container_add (GTK_CONTAINER (widget), GTK_WIDGET (prefs->sig_preview));
-
- /* get our toplevel widget */
- target = em_config_target_new_prefs(ec, prefs->gconf);
- e_config_set_target((EConfig *)ec, (EConfigTarget *)target);
- toplevel = e_config_create_widget((EConfig *)ec);
- gtk_container_add (GTK_CONTAINER (prefs), toplevel);
}
+
GtkWidget *
em_composer_prefs_new (void)
{
diff --git a/mail/em-composer-utils.c b/mail/em-composer-utils.c
index e7b0a7aa35..602f58b708 100644
--- a/mail/em-composer-utils.c
+++ b/mail/em-composer-utils.c
@@ -28,7 +28,6 @@
#include <gtk/gtkdialog.h>
#include <gal/util/e-util.h>
-#include <libgnome/gnome-i18n.h>
#include "mail-mt.h"
#include "mail-ops.h"
@@ -45,7 +44,6 @@
#include "composer/e-msg-composer.h"
#include "em-format-html.h"
#include "em-format-quote.h"
-#include "em-event.h"
#include "e-util/e-account-list.h"
@@ -415,8 +413,8 @@ em_utils_composer_send_cb (EMsgComposer *composer, gpointer user_data)
if (mail_folder) {
/* mail the message */
- info = camel_message_info_new(NULL);
- camel_message_info_set_flags(info, CAMEL_MESSAGE_SEEN, ~0);
+ info = camel_message_info_new ();
+ info->flags = CAMEL_MESSAGE_SEEN;
send = g_malloc (sizeof (*send));
send->emcs = user_data;
@@ -439,8 +437,8 @@ em_utils_composer_send_cb (EMsgComposer *composer, gpointer user_data)
mail_tool_destroy_xevolution (xev);
/* mail the message */
- info = camel_message_info_new(NULL);
- camel_message_info_set_flags(info, CAMEL_MESSAGE_SEEN, ~0);
+ info = camel_message_info_new ();
+ info->flags = CAMEL_MESSAGE_SEEN;
post_ptr = post_folders;
while (post_ptr) {
@@ -533,7 +531,7 @@ save_draft_done (CamelFolder *folder, CamelMimeMessage *msg, CamelMessageInfo *i
g_object_unref (sdi->composer);
if (sdi->emcs)
emcs_unref (sdi->emcs);
- camel_message_info_free(info);
+ g_free (info);
g_free (sdi);
}
@@ -599,8 +597,8 @@ em_utils_composer_save_draft_cb (EMsgComposer *composer, int quit, gpointer user
camel_object_ref (folder);
}
- info = camel_message_info_new(NULL);
- camel_message_info_set_flags(info, CAMEL_MESSAGE_DRAFT | CAMEL_MESSAGE_SEEN, ~0);
+ info = g_malloc0(sizeof(*info));
+ info->flags = CAMEL_MESSAGE_DRAFT | CAMEL_MESSAGE_SEEN;
mail_append_mail (folder, msg, info, save_draft_done, sdi);
camel_object_unref (folder);
@@ -644,9 +642,7 @@ create_new_composer (const char *subject, const char *fromuri)
EAccount *account = NULL;
composer = e_msg_composer_new ();
- if (composer == NULL)
- return NULL;
-
+
if (fromuri)
account = mail_config_get_account_by_source_url(fromuri);
@@ -669,8 +665,6 @@ em_utils_compose_new_message (const char *fromuri)
GtkWidget *composer;
composer = (GtkWidget *) create_new_composer ("", fromuri);
- if (composer == NULL)
- return;
e_msg_composer_unset_changed ((EMsgComposer *)composer);
e_msg_composer_drop_editor_undo ((EMsgComposer *)composer);
@@ -846,10 +840,8 @@ forward_attached (CamelFolder *folder, GPtrArray *messages, CamelMimePart *part,
EMsgComposer *composer;
composer = create_new_composer (subject, fromuri);
- if (composer == NULL)
- return;
-
e_msg_composer_attach (composer, part);
+
e_msg_composer_unset_changed (composer);
e_msg_composer_drop_editor_undo (composer);
@@ -912,16 +904,16 @@ forward_non_attached (GPtrArray *messages, int style, const char *fromuri)
if (text) {
composer = create_new_composer (subject, fromuri);
- if (composer) {
- if (CAMEL_IS_MULTIPART(camel_medium_get_content_object((CamelMedium *)message)))
- e_msg_composer_add_message_attachments(composer, message, FALSE);
+ if (CAMEL_IS_MULTIPART(camel_medium_get_content_object((CamelMedium *)message)))
+ e_msg_composer_add_message_attachments(composer, message, FALSE);
- e_msg_composer_set_body_text (composer, text, len);
- e_msg_composer_unset_changed (composer);
- e_msg_composer_drop_editor_undo (composer);
+ e_msg_composer_set_body_text (composer, text, len);
+
+ e_msg_composer_unset_changed (composer);
+ e_msg_composer_drop_editor_undo (composer);
+
+ gtk_widget_show (GTK_WIDGET (composer));
- gtk_widget_show (GTK_WIDGET (composer));
- }
g_free (text);
}
@@ -1730,8 +1722,7 @@ reply_to_message(CamelFolder *folder, const char *uid, CamelMimeMessage *message
if (message != NULL)
em_utils_reply_to_message(folder, uid, message, rd->mode, rd->source);
- if (rd->source)
- g_object_unref(rd->source);
+ g_object_unref(rd->source);
g_free(rd);
}
@@ -1760,34 +1751,19 @@ em_utils_reply_to_message(CamelFolder *folder, const char *uid, CamelMimeMessage
EAccount *account;
const char *postto = NULL;
guint32 flags;
- EMEvent *eme;
- EMEventTargetMessage *target;
if (folder && uid && message == NULL) {
struct _reply_data *rd = g_malloc0(sizeof(*rd));
rd->mode = mode;
rd->source = source;
- if (rd->source)
- g_object_ref(rd->source);
+ g_object_ref(rd->source);
mail_get_message(folder, uid, reply_to_message, rd, mail_thread_new);
return;
}
g_return_if_fail(message != NULL);
-
- /** @Event: message.replying
- * @Title: Message being replied to
- * @Target: EMEventTargetMessage
- *
- * message.replying is emitted when a user starts replying to a message.
- */
-
- eme = em_event_peek();
- target = em_event_target_new_message(eme, folder, message, uid,
- mode == REPLY_MODE_ALL ? EM_EVENT_MESSAGE_REPLY_ALL : 0);
- e_event_emit((EEvent *)eme, "message.replying", (EEventTarget *)target);
account = guess_account (message, folder);
flags = CAMEL_MESSAGE_ANSWERED | CAMEL_MESSAGE_SEEN;
diff --git a/mail/em-folder-browser.c b/mail/em-folder-browser.c
index c0b9d92529..ded2ace97f 100644
--- a/mail/em-folder-browser.c
+++ b/mail/em-folder-browser.c
@@ -60,7 +60,7 @@
#include <bonobo/bonobo-ui-util.h>
/* for efilterbar stuff */
-#include <libedataserver/e-sexp.h>
+#include <e-util/e-sexp.h>
#include "mail-vfolder.h"
#include "em-vfolder-rule.h"
#include <widgets/misc/e-filter-bar.h>
@@ -74,7 +74,6 @@
#include "em-folder-browser.h"
#include "em-folder-properties.h"
#include "em-subscribe-editor.h"
-#include "em-menu.h"
#include "message-list.h"
#include "mail-component.h"
@@ -102,8 +101,6 @@ struct _EMFolderBrowserPrivate {
char *select_uid;
guint folder_changed_id;
-
- EMMenu *menu; /* toplevel menu manager */
};
static void emfb_activate(EMFolderView *emfv, BonoboUIComponent *uic, int state);
@@ -130,7 +127,7 @@ static ESearchBarItem emfb_search_items[] = {
E_FILTERBAR_SAVE,
E_FILTERBAR_EDIT,
{ NULL, 0, NULL },
- { N_("Create _vFolder From Search..."), ESB_SAVE, NULL },
+ { N_("Create _Virtual Folder From Search..."), ESB_SAVE, NULL },
{ NULL, -1, NULL }
};
@@ -291,15 +288,6 @@ GtkWidget *em_folder_browser_new(void)
{
EMFolderBrowser *emfb = g_object_new(em_folder_browser_get_type(), 0);
- /** @HookPoint-EMMenu: Main Mail Menu
- * @Id: org.gnome.evolution.mail.browser
- * @Class: org.gnome.evolution.mail.bonobomenu:1.0
- * @Target: EMMenuTargetSelect
- *
- * The main menu of mail view of the main application window.
- */
- ((EMFolderView *)emfb)->menu = em_menu_new("org.gnome.evolution.mail.browser");
-
return (GtkWidget *)emfb;
}
diff --git a/mail/em-folder-properties.c b/mail/em-folder-properties.c
index e4e50b8aeb..c4baa983b8 100644
--- a/mail/em-folder-properties.c
+++ b/mail/em-folder-properties.c
@@ -40,10 +40,8 @@
#include <camel/camel-folder.h>
#include <camel/camel-vee-folder.h>
-#include <libgnome/gnome-i18n.h>
#include "em-folder-properties.h"
-#include "em-config.h"
#include "mail-component.h"
#include "mail-ops.h"
@@ -54,32 +52,19 @@ struct _prop_data {
void *object;
CamelArgV *argv;
GtkWidget **widgets;
-
- GSList *properties;
- char *name;
- int total;
- int unread;
- EMConfig *config;
};
static void
emfp_dialog_response (GtkWidget *dialog, int response, struct _prop_data *prop_data)
{
- if (response == GTK_RESPONSE_OK)
- e_config_commit((EConfig *)prop_data->config);
- else
- e_config_abort((EConfig *)prop_data->config);
-
- gtk_widget_destroy (dialog);
-}
-
-static void
-emfp_commit(EConfig *ec, GSList *items, void *data)
-{
- struct _prop_data *prop_data = data;
CamelArgV *argv = prop_data->argv;
int i;
+ if (response != GTK_RESPONSE_OK) {
+ gtk_widget_destroy (dialog);
+ return;
+ }
+
for (i = 0; i < argv->argc; i++) {
CamelArg *arg = &argv->argv[i];
@@ -98,75 +83,144 @@ emfp_commit(EConfig *ec, GSList *items, void *data)
}
camel_object_setv (prop_data->object, NULL, argv);
+ gtk_widget_destroy (dialog);
}
static void
-emfp_free(EConfig *ec, GSList *items, void *data)
+emfp_dialog_free (void *data)
{
struct _prop_data *prop_data = data;
int i;
- g_slist_free(items);
-
for (i = 0; i < prop_data->argv->argc; i++) {
if ((prop_data->argv->argv[i].tag & CAMEL_ARG_TYPE) == CAMEL_ARG_STR)
g_free (prop_data->argv->argv[i].ca_str);
}
-
- camel_object_free (prop_data->object, CAMEL_FOLDER_PROPERTIES, prop_data->properties);
- camel_object_free (prop_data->object, CAMEL_FOLDER_NAME, prop_data->name);
camel_object_unref (prop_data->object);
g_free (prop_data->argv);
-
g_free (prop_data);
}
-static GtkWidget *
-emfp_get_folder_item(EConfig *ec, EConfigItem *item, struct _GtkWidget *parent, struct _GtkWidget *old, void *data)
+static void
+emfp_dialog_got_folder (char *uri, CamelFolder *folder, void *data)
{
+ GtkWidget *dialog, *w, *table, *label, *vbox, *hbox;
+ struct _prop_data *prop_data;
+ CamelArgGetV *arggetv;
+ CamelArgV *argv;
+ GSList *list, *l;
+ gint32 count, i;
+ char *name, *title;
char countstr[16];
- GtkWidget *w, *table, *label;
- struct _prop_data *prop_data = data;
- int row = 0, i;
- GSList *l;
+ int row = 0, total=0, unread=0;
+
+ if (folder == NULL)
+ return;
+
+ camel_object_get (folder, NULL, CAMEL_FOLDER_PROPERTIES, &list, CAMEL_FOLDER_NAME, &name,
+ CAMEL_FOLDER_TOTAL, &total, CAMEL_FOLDER_UNREAD, &unread, NULL);
+
+ dialog = gtk_dialog_new_with_buttons (_("Folder Properties"), NULL,
+ GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_OK, GTK_RESPONSE_OK,
+ NULL);
+ gtk_window_set_default_size ((GtkWindow *) dialog, 192, 160);
+ gtk_widget_ensure_style (dialog);
+ gtk_container_set_border_width ((GtkContainer *) ((GtkDialog *) dialog)->vbox, 0);
+ gtk_container_set_border_width ((GtkContainer *) ((GtkDialog *) dialog)->vbox, 12);
+
+ vbox = gtk_vbox_new (FALSE, 12);
+ gtk_container_set_border_width ((GtkContainer *) vbox, 12);
+ gtk_box_pack_start ((GtkBox *) ((GtkDialog *) dialog)->vbox, vbox, TRUE, TRUE, 0);
+ gtk_widget_show (vbox);
+
+ if (folder->parent_store == mail_component_peek_local_store(NULL)
+ && (!strcmp(name, "Drafts")
+ || !strcmp(name, "Inbox")
+ || !strcmp(name, "Outbox")
+ || !strcmp(name, "Sent")))
+ title = g_strdup_printf("<b>%s</b>", _(name));
+ else
+ title = g_strdup_printf ("<b>%s</b>", name);
- if (old)
- return old;
+ label = gtk_label_new (title);
+ gtk_label_set_use_markup ((GtkLabel *) label, TRUE);
+ gtk_misc_set_alignment ((GtkMisc *) label, 0.0, 0.5);
+ gtk_box_pack_start ((GtkBox *) vbox, label, FALSE, FALSE, 0);
+ gtk_widget_show (label);
+ g_free (title);
+
+ hbox = gtk_hbox_new (FALSE, 12);
+ gtk_box_pack_start ((GtkBox *) vbox, hbox, FALSE, FALSE, 0);
+ gtk_widget_show (hbox);
+
+ label = gtk_label_new ("");
+ gtk_box_pack_start ((GtkBox *) hbox, label, FALSE, FALSE, 0);
+ gtk_widget_show (label);
- table = gtk_table_new (g_slist_length (prop_data->properties) + 2, 2, FALSE);
+ /* TODO: maybe we want some basic properties here, like message counts/approximate size/etc */
+ table = gtk_table_new (g_slist_length (list) + 2, 2, FALSE);
gtk_table_set_row_spacings ((GtkTable *) table, 6);
gtk_table_set_col_spacings ((GtkTable *) table, 12);
gtk_widget_show (table);
- gtk_box_pack_start ((GtkBox *) parent, table, TRUE, TRUE, 0);
+ gtk_box_pack_start ((GtkBox *) hbox, table, TRUE, TRUE, 0);
/* TODO: can this be done in a loop? */
- label = gtk_label_new (ngettext ("Total message:", "Total messages:", prop_data->total));
+ label = gtk_label_new (ngettext ("Total message:", "Total messages:", total));
gtk_widget_show (label);
gtk_misc_set_alignment ((GtkMisc *) label, 0.0, 0.5);
gtk_table_attach ((GtkTable *) table, label, 0, 1, row, row+1, GTK_FILL, 0, 0, 0);
- sprintf(countstr, "%d", prop_data->total);
+ sprintf(countstr, "%d", total);
label = gtk_label_new (countstr);
gtk_widget_show (label);
gtk_misc_set_alignment ((GtkMisc *) label, 1.0, 0.5);
gtk_table_attach ((GtkTable *) table, label, 1, 2, row, row+1, GTK_FILL | GTK_EXPAND, 0, 0, 0);
row++;
- label = gtk_label_new (ngettext ("Unread message:", "Unread messages:", prop_data->unread));
+ label = gtk_label_new (ngettext ("Unread message:", "Unread messages:", unread));
gtk_widget_show (label);
gtk_misc_set_alignment ((GtkMisc *) label, 0.0, 0.5);
gtk_table_attach ((GtkTable *) table, label, 0, 1, row, row+1, GTK_FILL, 0, 0, 0);
- sprintf(countstr, "%d", prop_data->unread);
+ sprintf(countstr, "%d", unread);
label = gtk_label_new (countstr);
gtk_widget_show (label);
gtk_misc_set_alignment ((GtkMisc *) label, 1.0, 0.5);
gtk_table_attach ((GtkTable *) table, label, 1, 2, row, row+1, GTK_FILL | GTK_EXPAND, 0, 0, 0);
row++;
+ /* build an arggetv/argv to retrieve/store the results */
+ count = g_slist_length (list);
+ arggetv = g_malloc0 (sizeof (*arggetv) + (count - CAMEL_ARGV_MAX) * sizeof (arggetv->argv[0]));
+ arggetv->argc = count;
+ argv = g_malloc0 (sizeof (*argv) + (count - CAMEL_ARGV_MAX) * sizeof (argv->argv[0]));
+ argv->argc = count;
+
+ i = 0;
+ l = list;
+ while (l) {
+ CamelProperty *prop = l->data;
+
+ argv->argv[i].tag = prop->tag;
+ arggetv->argv[i].tag = prop->tag;
+ arggetv->argv[i].ca_ptr = &argv->argv[i].ca_ptr;
+
+ l = l->next;
+ i++;
+ }
+
+ camel_object_getv (folder, NULL, arggetv);
+ g_free (arggetv);
+
+ prop_data = g_malloc0 (sizeof (*prop_data));
+ prop_data->widgets = g_malloc0 (sizeof (prop_data->widgets[0]) * count);
+ prop_data->argv = argv;
+
/* setup the ui with the values retrieved */
- l = prop_data->properties;
+ l = list;
i = 0;
while (l) {
CamelProperty *prop = l->data;
@@ -174,7 +228,7 @@ emfp_get_folder_item(EConfig *ec, EConfigItem *item, struct _GtkWidget *parent,
switch (prop->tag & CAMEL_ARG_TYPE) {
case CAMEL_ARG_BOO:
w = gtk_check_button_new_with_label (prop->description);
- gtk_toggle_button_set_active ((GtkToggleButton *) w, prop_data->argv->argv[i].ca_int != 0);
+ gtk_toggle_button_set_active ((GtkToggleButton *) w, argv->argv[i].ca_int != 0);
gtk_widget_show (w);
gtk_table_attach ((GtkTable *) table, w, 0, 2, row, row + 1, GTK_FILL | GTK_EXPAND, 0, 0, 0);
prop_data->widgets[i] = w;
@@ -187,10 +241,10 @@ emfp_get_folder_item(EConfig *ec, EConfigItem *item, struct _GtkWidget *parent,
w = gtk_entry_new ();
gtk_widget_show (w);
- if (prop_data->argv->argv[i].ca_str) {
- gtk_entry_set_text ((GtkEntry *) w, prop_data->argv->argv[i].ca_str);
- camel_object_free (prop_data->object, prop_data->argv->argv[i].tag, prop_data->argv->argv[i].ca_str);
- prop_data->argv->argv[i].ca_str = NULL;
+ if (argv->argv[i].ca_str) {
+ gtk_entry_set_text ((GtkEntry *) w, argv->argv[i].ca_str);
+ camel_object_free (folder, argv->argv[i].tag, argv->argv[i].ca_str);
+ argv->argv[i].ca_str = NULL;
}
gtk_table_attach ((GtkTable *) table, w, 1, 2, row, row + 1, GTK_FILL | GTK_EXPAND, 0, 0, 0);
prop_data->widgets[i] = w;
@@ -202,112 +256,18 @@ emfp_get_folder_item(EConfig *ec, EConfigItem *item, struct _GtkWidget *parent,
row++;
l = l->next;
- i++;
}
-
- return table;
-}
-
-#define EMFP_FOLDER_SECTION (2)
-
-static EMConfigItem emfp_items[] = {
- { E_CONFIG_BOOK, "", NULL },
- { E_CONFIG_PAGE, "00.general", N_("General") },
- { E_CONFIG_SECTION, "00.general/00.folder", NULL /* set by code */ },
- { E_CONFIG_ITEM, "00.general/00.folder/00.info", NULL, emfp_get_folder_item },
-};
-
-static void
-emfp_dialog_got_folder (char *uri, CamelFolder *folder, void *data)
-{
- GtkWidget *dialog, *w;
- struct _prop_data *prop_data;
- GSList *l;
- gint32 count, i;
- EMConfig *ec;
- EMConfigTargetFolder *target;
- CamelArgGetV *arggetv;
- CamelArgV *argv;
-
- if (folder == NULL)
- return;
-
- prop_data = g_malloc0 (sizeof (*prop_data));
+
prop_data->object = folder;
camel_object_ref (folder);
-
- camel_object_get (folder, NULL, CAMEL_FOLDER_PROPERTIES, &prop_data->properties, CAMEL_FOLDER_NAME, &prop_data->name,
- CAMEL_FOLDER_TOTAL, &prop_data->total, CAMEL_FOLDER_UNREAD, &prop_data->unread, NULL);
-
- if (folder->parent_store == mail_component_peek_local_store(NULL)
- && (!strcmp(prop_data->name, "Drafts")
- || !strcmp(prop_data->name, "Inbox")
- || !strcmp(prop_data->name, "Outbox")
- || !strcmp(prop_data->name, "Sent")))
- emfp_items[EMFP_FOLDER_SECTION].label = _(prop_data->name);
- else
- emfp_items[EMFP_FOLDER_SECTION].label = prop_data->name;
-
- count = g_slist_length (prop_data->properties);
-
- prop_data->widgets = g_malloc0 (sizeof (prop_data->widgets[0]) * count);
-
- /* build an arggetv/argv to retrieve/store the results */
- argv = g_malloc0 (sizeof (*argv) + (count - CAMEL_ARGV_MAX) * sizeof (argv->argv[0]));
- argv->argc = count;
- arggetv = g_malloc0 (sizeof (*arggetv) + (count - CAMEL_ARGV_MAX) * sizeof (arggetv->argv[0]));
- arggetv->argc = count;
- i = 0;
- l = prop_data->properties;
- while (l) {
- CamelProperty *prop = l->data;
-
- argv->argv[i].tag = prop->tag;
- arggetv->argv[i].tag = prop->tag;
- arggetv->argv[i].ca_ptr = &argv->argv[i].ca_ptr;
-
- l = l->next;
- i++;
- }
+ camel_object_free (folder, CAMEL_FOLDER_PROPERTIES, list);
+ camel_object_free (folder, CAMEL_FOLDER_NAME, name);
- camel_object_getv (prop_data->object, NULL, arggetv);
- g_free (arggetv);
- prop_data->argv = argv;
-
- dialog = gtk_dialog_new_with_buttons (_("Folder Properties"), NULL,
- GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
- GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
- GTK_STOCK_OK, GTK_RESPONSE_OK,
- NULL);
- gtk_window_set_default_size ((GtkWindow *) dialog, 192, 160);
- gtk_widget_ensure_style (dialog);
- gtk_container_set_border_width ((GtkContainer *) ((GtkDialog *) dialog)->vbox, 12);
-
- /** @HookPoint-EMConfig: Folder Properties Window
- * @Id: org.gnome.evolution.mail.folderConfig
- * @Type: E_CONFIG_BOOK
- * @Class: org.gnome.evolution.mail.config:1.0
- * @Target: EMConfigTargetFolder
- *
- * The folder properties window.
- */
- ec = em_config_new(E_CONFIG_BOOK, "org.gnome.evolution.mail.folderConfig");
- prop_data->config = ec;
- l = NULL;
- for (i=0;i<sizeof(emfp_items)/sizeof(emfp_items[0]);i++)
- l = g_slist_prepend(l, &emfp_items[i]);
- e_config_add_items((EConfig *)ec, l, emfp_commit, NULL, emfp_free, prop_data);
-
- target = em_config_target_new_folder(ec, folder, uri);
- e_config_set_target((EConfig *)ec, (EConfigTarget *)target);
- w = e_config_create_widget((EConfig *)ec);
-
- gtk_box_pack_start ((GtkBox *) ((GtkDialog *) dialog)->vbox, w, TRUE, TRUE, 0);
-
/* we do 'apply on ok' ... since instant apply may apply some very long running tasks */
g_signal_connect (dialog, "response", G_CALLBACK (emfp_dialog_response), prop_data);
+ g_object_set_data_full ((GObject *) dialog, "e-prop-data", prop_data, emfp_dialog_free);
gtk_widget_show (dialog);
}
diff --git a/mail/em-folder-selector.c b/mail/em-folder-selector.c
index 69f4662d79..1b3af98192 100644
--- a/mail/em-folder-selector.c
+++ b/mail/em-folder-selector.c
@@ -108,15 +108,7 @@ em_folder_selector_init (EMFolderSelector *emfs)
static void
em_folder_selector_destroy (GtkObject *obj)
{
- EMFolderSelector *emfs = (EMFolderSelector *) obj;
- EMFolderTreeModel *model;
-
- if (emfs->created_id != 0) {
- model = em_folder_tree_get_model (emfs->emft);
- g_signal_handler_disconnect (model, emfs->created_id);
- emfs->created_id = 0;
- }
-
+ /*EMFolderSelector *emfs = (EMFolderSelector *) obj;*/
GTK_OBJECT_CLASS (parent_class)->destroy (obj);
}
@@ -127,31 +119,11 @@ em_folder_selector_finalize (GObject *obj)
g_free (emfs->selected_path);
g_free (emfs->selected_uri);
- g_free (emfs->created_uri);
G_OBJECT_CLASS (parent_class)->finalize (obj);
}
static void
-folder_created_cb (EMFolderTreeModel *model, const char *path, const char *uri, EMFolderSelector *emfs)
-{
- CamelException ex;
- CamelStore *store;
-
- camel_exception_init (&ex);
- if (!(store = (CamelStore *) camel_session_get_service (session, uri, CAMEL_PROVIDER_STORE, &ex)))
- return;
-
- if (camel_store_folder_uri_equal (store, emfs->created_uri, uri)) {
- em_folder_tree_set_selected (emfs->emft, uri);
- g_signal_handler_disconnect (model, emfs->created_id);
- emfs->created_id = 0;
- }
-
- camel_object_unref (store);
-}
-
-static void
emfs_response (GtkWidget *dialog, int response, EMFolderSelector *emfs)
{
EMFolderTreeModel *model;
@@ -172,14 +144,8 @@ emfs_response (GtkWidget *dialog, int response, EMFolderSelector *emfs)
if (gtk_dialog_run ((GtkDialog *) dialog) == GTK_RESPONSE_OK) {
uri = em_folder_selector_get_selected_uri ((EMFolderSelector *) dialog);
path = em_folder_selector_get_selected_path ((EMFolderSelector *) dialog);
-
- g_free (emfs->created_uri);
- emfs->created_uri = g_strdup (uri);
-
- if (emfs->created_id == 0)
- emfs->created_id = g_signal_connect (model, "folder-added", G_CALLBACK (folder_created_cb), emfs);
-
em_folder_tree_create_folder (emfs->emft, path, uri);
+ em_folder_tree_set_selected(emfs->emft, uri);
}
gtk_widget_destroy (dialog);
diff --git a/mail/em-folder-selector.h b/mail/em-folder-selector.h
index 9d282dd77b..c33017ed20 100644
--- a/mail/em-folder-selector.h
+++ b/mail/em-folder-selector.h
@@ -49,9 +49,6 @@ struct _EMFolderSelector {
struct _GtkEntry *name_entry;
char *selected_path;
char *selected_uri;
-
- char *created_uri;
- guint created_id;
};
struct _EMFolderSelectorClass {
diff --git a/mail/em-folder-tree-model.c b/mail/em-folder-tree-model.c
index 40cf8de1e9..33c3c97843 100644
--- a/mail/em-folder-tree-model.c
+++ b/mail/em-folder-tree-model.c
@@ -20,6 +20,7 @@
*
*/
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
@@ -37,7 +38,6 @@
#include <e-util/e-mktemp.h>
#include <gal/util/e-xml-utils.h>
-#include <libgnome/gnome-i18n.h>
#include <camel/camel-file-utils.h>
@@ -184,23 +184,22 @@ sort_cb (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data
char *aname, *bname;
CamelStore *store;
gboolean is_store;
- guint32 aflags, bflags;
int rv = -2;
gtk_tree_model_get (model, a, COL_BOOL_IS_STORE, &is_store,
COL_POINTER_CAMEL_STORE, &store,
- COL_STRING_DISPLAY_NAME, &aname, COL_UINT_FLAGS, &aflags, -1);
- gtk_tree_model_get (model, b, COL_STRING_DISPLAY_NAME, &bname, COL_UINT_FLAGS, &bflags, -1);
+ COL_STRING_DISPLAY_NAME, &aname, -1);
+ gtk_tree_model_get (model, b, COL_STRING_DISPLAY_NAME, &bname, -1);
if (is_store) {
- /* On This Computer is always first and vFolders is always last */
+ /* On This Computer is always first and VFolders is always last */
if (!strcmp (aname, _("On This Computer")))
rv = -1;
else if (!strcmp (bname, _("On This Computer")))
rv = 1;
- else if (!strcmp (aname, _("vFolders")))
+ else if (!strcmp (aname, _("VFolders")))
rv = 1;
- else if (!strcmp (bname, _("vFolders")))
+ else if (!strcmp (bname, _("VFolders")))
rv = -1;
} else if (store == vfolder_store) {
/* UNMATCHED is always last */
@@ -210,9 +209,9 @@ sort_cb (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data
rv = -1;
} else {
/* Inbox is always first */
- if ((aflags & CAMEL_FOLDER_TYPE_MASK) == CAMEL_FOLDER_TYPE_INBOX)
+ if (aname && (!strcmp (aname, "INBOX") || !strcmp (aname, _("Inbox"))))
rv = -1;
- else if ((bflags & CAMEL_FOLDER_TYPE_MASK) == CAMEL_FOLDER_TYPE_INBOX)
+ else if (bname && (!strcmp (bname, "INBOX") || !strcmp (bname, _("Inbox"))))
rv = 1;
}
@@ -331,7 +330,7 @@ em_folder_tree_model_load_state (EMFolderTreeModel *model, const char *filename)
if (stat (filename, &st) == 0 && (model->state = xmlParseFile (filename)))
return;
- /* setup some defaults - expand "Local Folders" and "vFolders" */
+ /* setup some defaults - expand "Local Folders" and "VFolders" */
model->state = xmlNewDoc ("1.0");
root = xmlNewDocNode (model->state, NULL, "tree-state", NULL);
xmlDocSetRootElement (model->state, root);
@@ -415,6 +414,16 @@ account_removed (EAccountList *accounts, EAccount *account, gpointer user_data)
em_folder_tree_model_remove_store (model, si->store);
}
+/* NB: more-or-less copied from em-folder-tree.c */
+static gboolean
+emft_is_special_local_folder(CamelStore *store, const char *name)
+{
+ /* Bit of a hack to translate local mailbox names */
+ return store == mail_component_peek_local_store(NULL)
+ && (!strcmp (name, "Drafts") || !strcmp (name, "Inbox")
+ || !strcmp (name, "Outbox") || !strcmp (name, "Sent"));
+}
+
void
em_folder_tree_model_set_folder_info (EMFolderTreeModel *model, GtkTreeIter *iter,
struct _EMFolderTreeModelStoreInfo *si,
@@ -428,7 +437,6 @@ em_folder_tree_model_set_folder_info (EMFolderTreeModel *model, GtkTreeIter *ite
struct _CamelFolder *folder;
gboolean emitted = FALSE;
const char *name;
- guint32 flags;
if (!fully_loaded)
load = fi->child == NULL && !(fi->flags & (CAMEL_FOLDER_NOCHILDREN | CAMEL_FOLDER_NOINFERIORS));
@@ -460,22 +468,10 @@ em_folder_tree_model_set_folder_info (EMFolderTreeModel *model, GtkTreeIter *ite
camel_object_unref(folder);
}
- /* TODO: maybe this should be handled by mail_get_folderinfo (except em-folder-tree doesn't use it, duh) */
- flags = fi->flags;
- name = fi->name;
- if (si->store == mail_component_peek_local_store(NULL)) {
- if (!strcmp(fi->full_name, "Drafts")) {
- name = _("Drafts");
- } else if (!strcmp(fi->full_name, "Inbox")) {
- flags = (flags & ~CAMEL_FOLDER_TYPE_MASK) | CAMEL_FOLDER_TYPE_INBOX;
- name = _("Inbox");
- } else if (!strcmp(fi->full_name, "Outbox")) {
- flags = (flags & ~CAMEL_FOLDER_TYPE_MASK) | CAMEL_FOLDER_TYPE_OUTBOX;
- name = _("Outbox");
- } else if (!strcmp(fi->full_name, "Sent")) {
- name = _("Sent");
- }
- }
+ if (emft_is_special_local_folder(si->store, fi->full_name))
+ name = _(fi->name);
+ else
+ name = fi->name;
gtk_tree_store_set ((GtkTreeStore *) model, iter,
COL_STRING_DISPLAY_NAME, name,
@@ -483,7 +479,7 @@ em_folder_tree_model_set_folder_info (EMFolderTreeModel *model, GtkTreeIter *ite
COL_STRING_FULL_NAME, fi->full_name,
COL_STRING_URI, fi->uri,
COL_UINT_UNREAD, unread,
- COL_UINT_FLAGS, flags,
+ COL_UINT_FLAGS, fi->flags,
COL_BOOL_IS_STORE, FALSE,
COL_BOOL_LOAD_SUBDIRS, load,
-1);
diff --git a/mail/em-folder-tree.c b/mail/em-folder-tree.c
index 7bc32e5568..1c6d71d854 100644
--- a/mail/em-folder-tree.c
+++ b/mail/em-folder-tree.c
@@ -37,7 +37,6 @@
#include <gtk/gtk.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
-#include <libgnome/gnome-i18n.h>
#include <camel/camel-session.h>
#include <camel/camel-store.h>
@@ -88,8 +87,6 @@ struct _EMFolderTreePrivate {
GHashTable *select_uris_table; /*Removed as they're encountered, so use this to find uri's not presnet but selected */
guint32 excluded;
- gboolean (*excluded_func)(EMFolderTree *emft, GtkTreeModel *model, GtkTreeIter *iter, void *data);
- void *excluded_data;
int do_multiselect:1; /* multiple select mode */
int cursor_set:1; /* set to TRUE means we or something
@@ -165,7 +162,6 @@ static void emft_tree_row_expanded (GtkTreeView *treeview, GtkTreeIter *root, Gt
static gboolean emft_tree_button_press (GtkTreeView *treeview, GdkEventButton *event, EMFolderTree *emft);
static void emft_tree_selection_changed (GtkTreeSelection *selection, EMFolderTree *emft);
static gboolean emft_tree_user_event (GtkTreeView *treeview, GdkEvent *e, EMFolderTree *emft);
-static gboolean emft_popup_menu (GtkWidget *widget);
struct _emft_selection_data {
GtkTreeModel *model;
@@ -204,14 +200,11 @@ em_folder_tree_class_init (EMFolderTreeClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkObjectClass *gtk_object_class = GTK_OBJECT_CLASS (klass);
- GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
parent_class = g_type_class_ref (GTK_TYPE_VBOX);
object_class->finalize = em_folder_tree_finalize;
gtk_object_class->destroy = em_folder_tree_destroy;
-
- widget_class->popup_menu = emft_popup_menu;
signals[FOLDER_SELECTED] =
g_signal_new ("folder-selected",
@@ -266,8 +259,6 @@ enum {
FOLDER_ICON_OUTBOX,
FOLDER_ICON_TRASH,
FOLDER_ICON_JUNK,
- FOLDER_ICON_SHARED_TO_ME,
- FOLDER_ICON_SHARED_BY_ME,
FOLDER_ICON_LAST
};
@@ -280,7 +271,7 @@ render_pixbuf (GtkTreeViewColumn *column, GtkCellRenderer *renderer,
static gboolean initialised = FALSE;
GdkPixbuf *pixbuf = NULL;
gboolean is_store;
- guint32 flags;
+ char *full_name;
if (!initialised) {
folder_icons[FOLDER_ICON_NORMAL] = e_icon_factory_get_icon ("stock_folder", E_ICON_SIZE_MENU);
@@ -288,38 +279,27 @@ render_pixbuf (GtkTreeViewColumn *column, GtkCellRenderer *renderer,
folder_icons[FOLDER_ICON_OUTBOX] = e_icon_factory_get_icon ("stock_outbox", E_ICON_SIZE_MENU);
folder_icons[FOLDER_ICON_TRASH] = e_icon_factory_get_icon ("stock_delete", E_ICON_SIZE_MENU);
folder_icons[FOLDER_ICON_JUNK] = e_icon_factory_get_icon ("stock_spam", E_ICON_SIZE_MENU);
- folder_icons[FOLDER_ICON_SHARED_TO_ME] = e_icon_factory_get_icon ("stock_shared_to_me", E_ICON_SIZE_MENU);
- folder_icons[FOLDER_ICON_SHARED_BY_ME] = e_icon_factory_get_icon ("stock_shared_by_me", E_ICON_SIZE_MENU);
initialised = TRUE;
}
- gtk_tree_model_get (model, iter, COL_BOOL_IS_STORE, &is_store, COL_UINT_FLAGS, &flags, -1);
-
- if (!is_store) {
- switch((flags & CAMEL_FOLDER_TYPE_MASK)) {
- case CAMEL_FOLDER_TYPE_INBOX:
+ gtk_tree_model_get (model, iter, COL_STRING_FULL_NAME, &full_name,
+ COL_BOOL_IS_STORE, &is_store, -1);
+
+ if (!is_store && full_name != NULL) {
+ if (!g_ascii_strcasecmp (full_name, "Inbox"))
pixbuf = folder_icons[FOLDER_ICON_INBOX];
- break;
- case CAMEL_FOLDER_TYPE_OUTBOX:
+ else if (!g_ascii_strcasecmp (full_name, "Outbox"))
pixbuf = folder_icons[FOLDER_ICON_OUTBOX];
- break;
- case CAMEL_FOLDER_TYPE_TRASH:
+ else if (!strcmp (full_name, CAMEL_VTRASH_NAME))
pixbuf = folder_icons[FOLDER_ICON_TRASH];
- break;
- case CAMEL_FOLDER_TYPE_JUNK:
+ else if (!strcmp (full_name, CAMEL_VJUNK_NAME))
pixbuf = folder_icons[FOLDER_ICON_JUNK];
- break;
- default:
- if (flags & CAMEL_FOLDER_SHARED_TO_ME)
- pixbuf = folder_icons[FOLDER_ICON_SHARED_TO_ME];
- else if (flags & CAMEL_FOLDER_SHARED_BY_ME)
- pixbuf = folder_icons[FOLDER_ICON_SHARED_BY_ME];
- else
- pixbuf = folder_icons[FOLDER_ICON_NORMAL];
- }
+ else
+ pixbuf = folder_icons[FOLDER_ICON_NORMAL];
}
-
+
g_object_set (renderer, "pixbuf", pixbuf, "visible", !is_store, NULL);
+ g_free (full_name);
}
static void
@@ -362,15 +342,12 @@ emft_select_func(GtkTreeSelection *selection, GtkTreeModel *model, GtkTreePath *
GtkTreeIter iter;
/* NB: This will be called with selection==NULL from tree_row_activated */
- if (emft->priv->excluded == 0 && emft->priv->excluded_func == NULL)
+ if (emft->priv->excluded == 0)
return TRUE;
if (!gtk_tree_model_get_iter(model, &iter, path))
return TRUE;
- if (emft->priv->excluded_func != NULL)
- return emft->priv->excluded_func(emft, model, &iter, emft->priv->excluded_data);
-
gtk_tree_model_get(model, &iter, COL_UINT_FLAGS, &flags, COL_BOOL_IS_STORE, &is_store, -1);
if (is_store)
flags |= CAMEL_FOLDER_NOSELECT;
@@ -673,7 +650,6 @@ GtkWidget *
em_folder_tree_new_with_model (EMFolderTreeModel *model)
{
EMFolderTree *emft;
- AtkObject *a11y;
emft = g_object_new (EM_TYPE_FOLDER_TREE, NULL);
em_folder_tree_construct (emft, model);
@@ -683,9 +659,6 @@ em_folder_tree_new_with_model (EMFolderTreeModel *model)
emft->priv->loading_row_id = g_signal_connect (model, "loading-row", G_CALLBACK (emft_maybe_expand_row), emft);
emft->priv->loaded_row_id = g_signal_connect (model, "loaded-row", G_CALLBACK (emft_maybe_expand_row), emft);
-
- a11y = gtk_widget_get_accessible (GTK_WIDGET (emft->priv->treeview));
- atk_object_set_name (a11y, _("Mail Folder Tree"));
return (GtkWidget *) emft;
}
@@ -1014,48 +987,36 @@ tree_drag_data_action(struct _DragDataReceivedAsync *m)
}
static void
-emft_drop_popup_copy(EPopup *ep, EPopupItem *item, void *data)
+emft_drop_popup_copy(GtkWidget *item, struct _DragDataReceivedAsync *m)
{
- struct _DragDataReceivedAsync *m = data;
-
m->action = GDK_ACTION_COPY;
tree_drag_data_action(m);
}
static void
-emft_drop_popup_move(EPopup *ep, EPopupItem *item, void *data)
+emft_drop_popup_move(GtkWidget *item, struct _DragDataReceivedAsync *m)
{
- struct _DragDataReceivedAsync *m = data;
-
m->action = GDK_ACTION_MOVE;
tree_drag_data_action(m);
}
static void
-emft_drop_popup_cancel(EPopup *ep, EPopupItem *item, void *data)
+emft_drop_popup_cancel(GtkWidget *item, struct _DragDataReceivedAsync *m)
{
- struct _DragDataReceivedAsync *m = data;
-
m->aborted = TRUE;
mail_msg_free(&m->msg);
}
-static EPopupItem emft_drop_popup_menu[] = {
- { E_POPUP_ITEM, "00.emc.00", N_("_Copy to Folder"), emft_drop_popup_copy, NULL, NULL, 1 },
- { E_POPUP_ITEM, "00.emc.01", N_("_Move to Folder"), emft_drop_popup_move, NULL, NULL, 1 },
- { E_POPUP_ITEM, "00.emc.02", N_("_Copy"), emft_drop_popup_copy, NULL, "stock_folder-copy", 2 },
- { E_POPUP_ITEM, "00.emc.03", N_("_Move"), emft_drop_popup_move, NULL, "stock_folder-move", 2 },
- { E_POPUP_BAR, "10.emc" },
- { E_POPUP_ITEM, "99.emc.00", N_("Cancel _Drag"), emft_drop_popup_cancel, NULL, "stock_cancel", 0 },
+static EMPopupItem emft_drop_popup_menu[] = {
+ { EM_POPUP_ITEM, "00.emc.00", N_("_Copy to Folder"), G_CALLBACK (emft_drop_popup_copy), NULL, NULL, 1 },
+ { EM_POPUP_ITEM, "00.emc.01", N_("_Move to Folder"), G_CALLBACK (emft_drop_popup_move), NULL, NULL, 1 },
+ { EM_POPUP_ITEM, "00.emc.02", N_("_Copy"), G_CALLBACK (emft_drop_popup_copy), NULL, "stock_folder-copy", 2 },
+ { EM_POPUP_ITEM, "00.emc.03", N_("_Move"), G_CALLBACK (emft_drop_popup_move), NULL, "stock_folder-move", 2 },
+ { EM_POPUP_BAR, "10.emc" },
+ { EM_POPUP_ITEM, "99.emc.00", N_("Cancel _Drag"), G_CALLBACK (emft_drop_popup_cancel), NULL, "stock_cancel", 0 },
};
static void
-emft_drop_popup_free(EPopup *ep, GSList *items, void *data)
-{
- g_slist_free(items);
-}
-
-static void
tree_drag_data_received(GtkWidget *widget, GdkDragContext *context, int x, int y, GtkSelectionData *selection, guint info, guint time, EMFolderTree *emft)
{
struct _EMFolderTreePrivate *priv = emft->priv;
@@ -1114,20 +1075,22 @@ tree_drag_data_received(GtkWidget *widget, GdkDragContext *context, int x, int y
GSList *menus = NULL;
GtkMenu *menu;
- emp = em_popup_new("org.gnome.mail.storageset.popup.drop");
+ emp = em_popup_new("com.ximian.mail.storageset.popup.drop");
if (info != DND_DROP_TYPE_FOLDER)
mask = ~1;
else
mask = ~2;
for (i=0;i<sizeof(emft_drop_popup_menu)/sizeof(emft_drop_popup_menu[0]);i++) {
- EPopupItem *item = &emft_drop_popup_menu[i];
+ EMPopupItem *item = &emft_drop_popup_menu[i];
- if ((item->visible & mask) == 0)
+ if ((item->mask & mask) == 0) {
+ item->activate_data = m;
menus = g_slist_append(menus, item);
+ }
}
- e_popup_add_items((EPopup *)emp, menus, NULL, emft_drop_popup_free, m);
- menu = e_popup_create_menu_once((EPopup *)emp, NULL, mask);
+ em_popup_add_items(emp, menus, (GDestroyNotify)g_slist_free);
+ menu = em_popup_create_menu_once(emp, NULL, mask, mask);
gtk_menu_popup(menu, NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time());
} else {
tree_drag_data_action(m);
@@ -1571,12 +1534,6 @@ void em_folder_tree_set_excluded(EMFolderTree *emft, guint32 flags)
emft->priv->excluded = flags;
}
-void em_folder_tree_set_excluded_func(EMFolderTree *emft, EMFTExcludeFunc exclude, void *data)
-{
- emft->priv->excluded_func = exclude;
- emft->priv->excluded_data = data;
-}
-
GList *
em_folder_tree_get_selected_uris (EMFolderTree *emft)
{
@@ -2015,14 +1972,6 @@ struct _EMCopyFolders {
int delete;
};
-static char *
-emft_copy_folders__desc (struct _mail_msg *mm, int complete)
-{
- struct _EMCopyFolders *m = (struct _EMCopyFolders *) mm;
-
- return g_strdup_printf (_("Copying `%s' to `%s'"), m->frombase, m->tobase);
-}
-
static void
emft_copy_folders__copy (struct _mail_msg *mm)
{
@@ -2160,7 +2109,7 @@ emft_copy_folders__free (struct _mail_msg *mm)
}
static struct _mail_msg_op copy_folders_op = {
- emft_copy_folders__desc,
+ NULL,
emft_copy_folders__copy,
NULL,
emft_copy_folders__free,
@@ -2226,10 +2175,10 @@ emft_popup_copy_folder_selected (const char *uri, void *data)
if (!(tostore = camel_session_get_store (session, uri, &ex))) {
e_error_run((GtkWindow *)gtk_widget_get_toplevel((GtkWidget *) cfd->emft),
- cfd->delete?"mail:no-move-folder-to-notexist":"mail:no-copy-folder-to-notexist", frombase, uri, ex.desc, NULL);
+ cfd->delete?"mail:no-move-folder-to-notexist":"mail:no-move-folder-to-notexist", frombase, uri, ex.desc, NULL);
goto fail;
}
-
+
url = camel_url_new (uri, NULL);
if (((CamelService *)tostore)->provider->url_flags & CAMEL_URL_FRAGMENT_IS_PATH)
tobase = url->fragment;
@@ -2252,42 +2201,9 @@ fail:
g_free (cfd);
}
-/* tree here is the 'destination' selector, not 'self' */
-static gboolean
-emft_popup_copy_folder_exclude(EMFolderTree *tree, GtkTreeModel *model, GtkTreeIter *iter, void *data)
-{
- struct _copy_folder_data *cfd = data;
- int fromvfolder, tovfolder;
- char *fromuri, *touri;
- guint flags;
- gboolean is_store;
-
- /* handles moving to/from vfolders */
-
- fromuri = em_folder_tree_get_selected_uri(cfd->emft);
- fromvfolder = strncmp(fromuri, "vfolder:", 8) == 0;
- gtk_tree_model_get(model, iter, COL_STRING_URI, &touri, COL_UINT_FLAGS, &flags, COL_BOOL_IS_STORE, &is_store, -1);
- tovfolder = strncmp(touri, "vfolder:", 8) == 0;
- g_free(fromuri);
- g_free(touri);
-
- /* moving from vfolder to normal- not allowed */
- if (fromvfolder && !tovfolder && cfd->delete)
- return FALSE;
- /* copy/move from normal folder to vfolder - not allowed */
- if (!fromvfolder && tovfolder)
- return FALSE;
- /* copying to vfolder - not allowed */
- if (tovfolder && !cfd->delete)
- return FALSE;
-
- return (flags & EMFT_EXCLUDE_NOINFERIORS) == 0;
-}
-
static void
-emft_popup_copy(EPopup *ep, EPopupItem *item, void *data)
+emft_popup_copy (GtkWidget *item, EMFolderTree *emft)
{
- EMFolderTree *emft = data;
struct _copy_folder_data *cfd;
cfd = g_malloc (sizeof (*cfd));
@@ -2295,13 +2211,12 @@ emft_popup_copy(EPopup *ep, EPopupItem *item, void *data)
cfd->delete = FALSE;
em_select_folder (NULL, _("Select folder"), _("C_opy"),
- NULL, emft_popup_copy_folder_exclude, emft_popup_copy_folder_selected, cfd);
+ NULL, emft_popup_copy_folder_selected, cfd);
}
static void
-emft_popup_move(EPopup *ep, EPopupItem *item, void *data)
+emft_popup_move (GtkWidget *item, EMFolderTree *emft)
{
- EMFolderTree *emft = data;
struct _copy_folder_data *cfd;
cfd = g_malloc (sizeof (*cfd));
@@ -2309,7 +2224,7 @@ emft_popup_move(EPopup *ep, EPopupItem *item, void *data)
cfd->delete = TRUE;
em_select_folder (NULL, _("Select folder"), _("_Move"),
- NULL, emft_popup_copy_folder_exclude, emft_popup_copy_folder_selected, cfd);
+ NULL, emft_popup_copy_folder_selected, cfd);
}
@@ -2514,10 +2429,8 @@ emft_popup_new_folder_response (EMFolderSelector *emfs, int response, EMFolderTr
}
static void
-emft_popup_new_folder (EPopup *ep, EPopupItem *pitem, void *data)
+emft_popup_new_folder (GtkWidget *item, EMFolderTree *emft)
{
- EMFolderTree *emft = data;
-
EMFolderTree *folder_tree;
GtkWidget *dialog;
char *uri;
@@ -2642,9 +2555,8 @@ emft_popup_delete_response (GtkWidget *dialog, int response, EMFolderTree *emft)
}
static void
-emft_popup_delete_folder (EPopup *ep, EPopupItem *pitem, void *data)
+emft_popup_delete_folder (GtkWidget *item, EMFolderTree *emft)
{
- EMFolderTree *emft = data;
struct _EMFolderTreePrivate *priv = emft->priv;
GtkTreeSelection *selection;
CamelStore *local, *store;
@@ -2678,9 +2590,8 @@ emft_popup_delete_folder (EPopup *ep, EPopupItem *pitem, void *data)
}
static void
-emft_popup_rename_folder (EPopup *ep, EPopupItem *pitem, void *data)
+emft_popup_rename_folder (GtkWidget *item, EMFolderTree *emft)
{
- EMFolderTree *emft = data;
struct _EMFolderTreePrivate *priv = emft->priv;
char *prompt, *full_name, *name, *new_name, *uri;
GtkTreeSelection *selection;
@@ -2720,12 +2631,16 @@ emft_popup_rename_folder (EPopup *ep, EPopupItem *pitem, void *data)
prompt = g_strdup_printf (_("Rename the \"%s\" folder to:"), name);
while (!done) {
new_name = e_request_string (NULL, _("Rename Folder"), prompt, name);
- if (new_name == NULL || !strcmp (name, new_name)) {
- /* old name == new name */
- done = TRUE;
- } else if (strchr(new_name, '/') != NULL) {
+ if (strchr(new_name, '/') != NULL) {
+ char *tmp;
+
+ tmp = g_strdup_printf(_("The folder name \"%s\" is invalid because it contains the character \"%c\""), new_name, '/');
e_error_run((GtkWindow *)gtk_widget_get_toplevel((GtkWidget *)emft),
- "mail:no-rename-folder", name, new_name, _("Folder names cannot contain '/'"), NULL);
+ "mail:no-rename-folder", name, new_name, tmp, NULL);
+ g_free(tmp);
+ done = TRUE;
+ } else if (new_name == NULL || !strcmp (name, new_name)) {
+ /* old name == new name */
done = TRUE;
} else {
CamelFolderInfo *fi;
@@ -2779,9 +2694,8 @@ emft_popup_rename_folder (EPopup *ep, EPopupItem *pitem, void *data)
static void
-emft_popup_properties (EPopup *ep, EPopupItem *pitem, void *data)
+emft_popup_properties (GtkWidget *item, EMFolderTree *emft)
{
- EMFolderTree *emft = data;
struct _EMFolderTreePrivate *priv = emft->priv;
GtkTreeSelection *selection;
GtkTreeModel *model;
@@ -2797,40 +2711,34 @@ emft_popup_properties (EPopup *ep, EPopupItem *pitem, void *data)
g_free (uri);
}
-static EPopupItem emft_popup_items[] = {
+static EMPopupItem emft_popup_menu[] = {
#if 0
- { E_POPUP_ITEM, "00.emc.00", N_("_View"), emft_popup_view, NULL, NULL, EM_POPUP_FOLDER_SELECT },
- { E_POPUP_ITEM, "00.emc.01", N_("Open in _New Window"), emft_popup_open_new, NULL, NULL, EM_POPUP_FOLDER_SELECT },
+ { EM_POPUP_ITEM, "00.emc.00", N_("_View"), G_CALLBACK (emft_popup_view), NULL, NULL, EM_POPUP_FOLDER_SELECT },
+ { EM_POPUP_ITEM, "00.emc.01", N_("Open in _New Window"), G_CALLBACK (emft_popup_open_new), NULL, NULL, EM_POPUP_FOLDER_SELECT },
- { E_POPUP_BAR, "10.emc" },
+ { EM_POPUP_BAR, "10.emc" },
#endif
- { E_POPUP_ITEM, "10.emc.00", N_("_Copy..."), emft_popup_copy, NULL, "stock_folder-copy", 0, EM_POPUP_FOLDER_FOLDER|EM_POPUP_FOLDER_SELECT },
- { E_POPUP_ITEM, "10.emc.01", N_("_Move..."), emft_popup_move, NULL, "stock_folder-move", 0, EM_POPUP_FOLDER_FOLDER|EM_POPUP_FOLDER_DELETE },
+ { EM_POPUP_ITEM, "10.emc.00", N_("_Copy..."), G_CALLBACK (emft_popup_copy), NULL, "stock_folder-copy", EM_POPUP_FOLDER_FOLDER|EM_POPUP_FOLDER_SELECT },
+ { EM_POPUP_ITEM, "10.emc.01", N_("_Move..."), G_CALLBACK (emft_popup_move), NULL, "stock_folder-move", EM_POPUP_FOLDER_FOLDER|EM_POPUP_FOLDER_DELETE },
- { E_POPUP_BAR, "20.emc" },
+ { EM_POPUP_BAR, "20.emc" },
/* FIXME: need to disable for nochildren folders */
- { E_POPUP_ITEM, "20.emc.00", N_("_New Folder..."), emft_popup_new_folder, NULL, "stock_new-dir", 0, EM_POPUP_FOLDER_INFERIORS },
+ { EM_POPUP_ITEM, "20.emc.00", N_("_New Folder..."), G_CALLBACK (emft_popup_new_folder), NULL, "stock_folder", EM_POPUP_FOLDER_INFERIORS },
/* FIXME: need to disable for undeletable folders */
- { E_POPUP_ITEM, "20.emc.01", N_("_Delete"), emft_popup_delete_folder, NULL, "stock_delete", 0, EM_POPUP_FOLDER_FOLDER|EM_POPUP_FOLDER_DELETE },
- { E_POPUP_ITEM, "20.emc.02", N_("_Rename..."), emft_popup_rename_folder, NULL, NULL, 0, EM_POPUP_FOLDER_FOLDER|EM_POPUP_FOLDER_DELETE },
+ { EM_POPUP_ITEM, "20.emc.01", N_("_Delete"), G_CALLBACK (emft_popup_delete_folder), NULL, "stock_delete", EM_POPUP_FOLDER_FOLDER|EM_POPUP_FOLDER_DELETE },
+ { EM_POPUP_ITEM, "20.emc.01", N_("_Rename..."), G_CALLBACK (emft_popup_rename_folder), NULL, NULL, EM_POPUP_FOLDER_FOLDER|EM_POPUP_FOLDER_DELETE },
- { E_POPUP_BAR, "80.emc" },
- { E_POPUP_ITEM, "80.emc.00", N_("_Properties"), emft_popup_properties, NULL, "stock_folder-properties", 0, EM_POPUP_FOLDER_FOLDER|EM_POPUP_FOLDER_SELECT }
+ { EM_POPUP_BAR, "80.emc" },
+ { EM_POPUP_ITEM, "80.emc.00", N_("_Properties"), G_CALLBACK (emft_popup_properties), NULL, "stock_folder-properties", EM_POPUP_FOLDER_FOLDER|EM_POPUP_FOLDER_SELECT }
};
-static void
-emft_popup_free(EPopup *ep, GSList *items, void *data)
-{
- g_slist_free(items);
-}
-
static gboolean
-emft_popup (EMFolderTree *emft, GdkEvent *event)
+emft_tree_button_press (GtkTreeView *treeview, GdkEventButton *event, EMFolderTree *emft)
{
- GtkTreeView *treeview;
GtkTreeSelection *selection;
CamelStore *local, *store;
- EMPopupTargetFolder *target;
+ EMPopupTarget *target;
+ GtkTreePath *tree_path;
GtkTreeModel *model;
GtkTreeIter iter;
GSList *menus = NULL;
@@ -2842,13 +2750,29 @@ emft_popup (EMFolderTree *emft, GdkEvent *event)
EMPopup *emp;
int i;
- treeview = emft->priv->treeview;
-
/* this centralises working out when the user's done something */
emft_tree_user_event(treeview, (GdkEvent *)event, emft);
-
- /* FIXME: we really need the folderinfo to build a proper menu */
+
+ if (event->button != 3 && !(event->button == 1 && event->type == GDK_2BUTTON_PRESS))
+ return FALSE;
+
+ if (!gtk_tree_view_get_path_at_pos (treeview, (int) event->x, (int) event->y, &tree_path, NULL, NULL, NULL))
+ return FALSE;
+
+ /* select/focus the row that was right-clicked or double-clicked */
selection = gtk_tree_view_get_selection (treeview);
+ gtk_tree_selection_select_path(selection, tree_path);
+ gtk_tree_view_set_cursor (treeview, tree_path, NULL, FALSE);
+
+ if (event->button == 1 && event->type == GDK_2BUTTON_PRESS) {
+ emft_tree_row_activated (treeview, tree_path, NULL, emft);
+ gtk_tree_path_free (tree_path);
+ return TRUE;
+ }
+
+ gtk_tree_path_free (tree_path);
+
+ /* FIXME: we really need the folderinfo to build a proper menu */
if (!emft_selection_get_selected (selection, &model, &iter))
return FALSE;
@@ -2880,73 +2804,34 @@ emft_popup (EMFolderTree *emft, GdkEvent *event)
info_flags |= CAMEL_FOLDER_VIRTUAL | CAMEL_FOLDER_NOINFERIORS;
}
- /** @HookPoint-EMPopup: Folder Tree Context Menu
- * @Id: org.gnome.evolution.mail.foldertree.popup
- * @Class: org.gnome.evolution.mail.popup:1.0
- * @Target: EMPopupTargetFolder
- *
- * This is the context menu shown on the folder tree.
- */
- emp = em_popup_new ("org.gnome.evolution.mail.foldertree.popup");
+ /* handle right-click by opening a context menu */
+ emp = em_popup_new ("com.ximian.mail.storageset.popup.select");
/* FIXME: pass valid fi->flags here */
- target = em_popup_target_new_folder (emp, uri, info_flags, flags);
+ target = em_popup_target_new_folder (uri, info_flags, flags);
- for (i = 0; i < sizeof (emft_popup_items) / sizeof (emft_popup_items[0]); i++)
- menus = g_slist_prepend (menus, &emft_popup_items[i]);
+ for (i = 0; i < sizeof (emft_popup_menu) / sizeof (emft_popup_menu[0]); i++) {
+ EMPopupItem *item = &emft_popup_menu[i];
+
+ item->activate_data = emft;
+ menus = g_slist_prepend (menus, item);
+ }
- e_popup_add_items ((EPopup *)emp, menus, NULL, emft_popup_free, emft);
+ em_popup_add_items (emp, menus, (GDestroyNotify) g_slist_free);
- menu = e_popup_create_menu_once ((EPopup *)emp, (EPopupTarget *)target, 0);
+ menu = em_popup_create_menu_once (emp, target, 0, target->mask);
if (event == NULL || event->type == GDK_KEY_PRESS) {
/* FIXME: menu pos function */
- gtk_menu_popup (menu, NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time());
+ gtk_menu_popup (menu, NULL, NULL, NULL, NULL, 0, event->time);
} else {
- gtk_menu_popup (menu, NULL, NULL, NULL, NULL, event->button.button, event->button.time);
+ gtk_menu_popup (menu, NULL, NULL, NULL, NULL, event->button, event->time);
}
g_free (full_name);
g_free (uri);
-
- return TRUE;
-}
-
-static gboolean
-emft_popup_menu (GtkWidget *widget)
-{
- return emft_popup (EM_FOLDER_TREE (widget), NULL);
-}
-
-static gboolean
-emft_tree_button_press (GtkTreeView *treeview, GdkEventButton *event, EMFolderTree *emft)
-{
- GtkTreeSelection *selection;
- GtkTreePath *tree_path;
-
- /* this centralises working out when the user's done something */
- emft_tree_user_event(treeview, (GdkEvent *)event, emft);
- if (event->button != 3 && !(event->button == 1 && event->type == GDK_2BUTTON_PRESS))
- return FALSE;
-
- if (!gtk_tree_view_get_path_at_pos (treeview, (int) event->x, (int) event->y, &tree_path, NULL, NULL, NULL))
- return FALSE;
-
- /* select/focus the row that was right-clicked or double-clicked */
- selection = gtk_tree_view_get_selection (treeview);
- gtk_tree_selection_select_path(selection, tree_path);
- gtk_tree_view_set_cursor (treeview, tree_path, NULL, FALSE);
-
- if (event->button == 1 && event->type == GDK_2BUTTON_PRESS) {
- emft_tree_row_activated (treeview, tree_path, NULL, emft);
- gtk_tree_path_free (tree_path);
- return TRUE;
- }
-
- gtk_tree_path_free (tree_path);
-
- return emft_popup (emft, (GdkEvent *)event);
+ return TRUE;
}
/* This is called for keyboard and mouse events, it seems the only way
diff --git a/mail/em-folder-tree.h b/mail/em-folder-tree.h
index e7c465998b..8ce1ad5873 100644
--- a/mail/em-folder-tree.h
+++ b/mail/em-folder-tree.h
@@ -51,8 +51,6 @@ typedef struct _EMFolderTreeClass EMFolderTreeClass;
#define EMFT_EXCLUDE_SYSTEM CAMEL_FOLDER_SYSTEM
#define EMFT_EXCLUDE_VTRASH CAMEL_FOLDER_VTRASH
-typedef gboolean (*EMFTExcludeFunc)(EMFolderTree *emft, GtkTreeModel *model, GtkTreeIter *iter, void *data);
-
struct _EMFolderTree {
GtkVBox parent_object;
@@ -76,7 +74,6 @@ void em_folder_tree_enable_drag_and_drop (EMFolderTree *emft);
void em_folder_tree_set_multiselect (EMFolderTree *emft, gboolean mode);
void em_folder_tree_set_excluded(EMFolderTree *emft, guint32 flags);
-void em_folder_tree_set_excluded_func(EMFolderTree *emft, EMFTExcludeFunc exclude, void *data);
void em_folder_tree_set_selected_list (EMFolderTree *emft, GList *list);
GList *em_folder_tree_get_selected_uris (EMFolderTree *emft);
diff --git a/mail/em-folder-view.c b/mail/em-folder-view.c
index 8793aba3ea..0699849d04 100644
--- a/mail/em-folder-view.c
+++ b/mail/em-folder-view.c
@@ -67,7 +67,6 @@
#include <e-util/e-dialog-utils.h>
#include <e-util/e-icon-factory.h>
-#include <e-util/e-print.h>
#include "em-format-html-display.h"
#include "em-format-html-print.h"
@@ -79,8 +78,6 @@
#include "em-utils.h"
#include "em-composer-utils.h"
#include "em-marshal.h"
-#include "em-menu.h"
-#include "em-event.h"
#include <gtkhtml/gtkhtml.h>
#include <gtkhtml/htmlobject.h>
@@ -125,8 +122,6 @@ static void emfv_setting_setup(EMFolderView *emfv);
static void emfv_on_url_cb(GObject *emitter, const char *url, EMFolderView *emfv);
static void emfv_on_url(EMFolderView *emfv, const char *uri, const char *nice_uri);
-static gboolean emfv_popup_menu (GtkWidget *widget);
-
static const EMFolderViewEnable emfv_enable_map[];
struct _EMFolderViewPrivate {
@@ -254,7 +249,7 @@ emfv_destroy (GtkObject *o)
}
if (p->invisible) {
- gtk_object_destroy((GtkObject *)p->invisible);
+ gtk_object_destroy(p->invisible);
p->invisible = NULL;
}
@@ -273,8 +268,6 @@ emfv_class_init(GObjectClass *klass)
((GtkObjectClass *) klass)->destroy = emfv_destroy;
- ((GtkWidgetClass *) klass)->popup_menu = emfv_popup_menu;
-
((EMFolderViewClass *) klass)->update_message_style = TRUE;
((EMFolderViewClass *)klass)->set_folder = emfv_set_folder;
@@ -371,25 +364,12 @@ em_folder_view_open_selected(EMFolderView *emfv)
int i = 0;
uids = message_list_get_selected(emfv->list);
-
- if (uids->len >= 10) {
- char *num = g_strdup_printf("%d", uids->len);
- int doit;
-
- doit = em_utils_prompt_user((GtkWindow *)gtk_widget_get_toplevel((GtkWidget *)emfv),
- "/apps/evolution/mail/prompts/open_many",
- "mail:ask-open-many", num, NULL);
- g_free(num);
- if (!doit) {
- message_list_free_uids(emfv->list, uids);
- return 0;
- }
- }
-
- if (em_utils_folder_is_drafts(emfv->folder, emfv->folder_uri)
+
+ if (em_utils_folder_is_drafts(emfv->folder, emfv->folder_uri)
|| em_utils_folder_is_outbox(emfv->folder, emfv->folder_uri)) {
- em_utils_edit_messages(emfv->folder, uids, TRUE);
- return uids->len;
+ i = uids->len;
+ em_utils_edit_messages (emfv->folder, uids, TRUE);
+ return i;
}
/* for vfolders we need to edit the *original*, not the vfolder copy */
@@ -417,7 +397,7 @@ em_folder_view_open_selected(EMFolderView *emfv)
}
} else {
g_ptr_array_add(views, g_strdup(uids->pdata[i]));
- }
+ }
}
/* TODO: have an em_utils_open_messages call? */
@@ -426,6 +406,7 @@ em_folder_view_open_selected(EMFolderView *emfv)
emmb = (EMMessageBrowser *)em_message_browser_window_new();
message_list_set_threaded(((EMFolderView *)emmb)->list, emfv->list->threaded);
+ message_list_set_search(((EMFolderView *)emmb)->list, emfv->list->search);
em_folder_view_set_hide_deleted((EMFolderView *)emmb, emfv->hide_deleted);
/* FIXME: session needs to be passed easier than this */
em_format_set_session((EMFormat *)((EMFolderView *)emmb)->preview, ((EMFormat *)emfv->preview)->session);
@@ -435,7 +416,6 @@ em_folder_view_open_selected(EMFolderView *emfv)
g_free(views->pdata[i]);
}
g_ptr_array_free(views, TRUE);
-
message_list_free_uids(emfv->list, uids);
return i;
@@ -642,17 +622,22 @@ emfv_selection_clear_event(GtkWidget *widget, GdkEventSelection *event, EMFolder
/* Popup menu
In many cases these are the functions called by the bonobo callbacks too */
+struct _emfv_label_item {
+ EMPopupItem item;
+
+ EMFolderView *emfv;
+ const char *label;
+};
+
static void
-emfv_popup_open(EPopup *ep, EPopupItem *pitem, void *data)
+emfv_popup_open(GtkWidget *w, EMFolderView *emfv)
{
- EMFolderView *emfv = data;
em_folder_view_open_selected(emfv);
}
static void
-emfv_popup_edit (EPopup *ep, EPopupItem *pitem, void *data)
+emfv_popup_edit (GtkWidget *w, EMFolderView *emfv)
{
- EMFolderView *emfv = data;
GPtrArray *uids;
if (!em_utils_check_user_can_send_mail((GtkWidget *)emfv))
@@ -663,9 +648,8 @@ emfv_popup_edit (EPopup *ep, EPopupItem *pitem, void *data)
}
static void
-emfv_popup_saveas(EPopup *ep, EPopupItem *pitem, void *data)
+emfv_popup_saveas(GtkWidget *w, EMFolderView *emfv)
{
- EMFolderView *emfv = data;
GPtrArray *uids;
uids = message_list_get_selected(emfv->list);
@@ -673,37 +657,32 @@ emfv_popup_saveas(EPopup *ep, EPopupItem *pitem, void *data)
}
static void
-emfv_popup_print(EPopup *ep, EPopupItem *pitem, void *data)
+emfv_popup_print(GtkWidget *w, EMFolderView *emfv)
{
- EMFolderView *emfv = data;
em_folder_view_print(emfv, FALSE);
}
static void
-emfv_popup_reply_sender(EPopup *ep, EPopupItem *pitem, void *data)
+emfv_popup_reply_sender(GtkWidget *w, EMFolderView *emfv)
{
- EMFolderView *emfv = data;
emfv_message_reply(emfv, REPLY_MODE_SENDER);
}
static void
-emfv_popup_reply_list(EPopup *ep, EPopupItem *pitem, void *data)
+emfv_popup_reply_list(GtkWidget *w, EMFolderView *emfv)
{
- EMFolderView *emfv = data;
emfv_message_reply(emfv, REPLY_MODE_LIST);
}
static void
-emfv_popup_reply_all(EPopup *ep, EPopupItem *pitem, void *data)
+emfv_popup_reply_all(GtkWidget *w, EMFolderView *emfv)
{
- EMFolderView *emfv = data;
emfv_message_reply(emfv, REPLY_MODE_ALL);
}
static void
-emfv_popup_forward(EPopup *ep, EPopupItem *pitem, void *data)
+emfv_popup_forward(GtkWidget *w, EMFolderView *emfv)
{
- EMFolderView *emfv = data;
GPtrArray *uids;
if (!em_utils_check_user_can_send_mail((GtkWidget *)emfv))
@@ -714,18 +693,16 @@ emfv_popup_forward(EPopup *ep, EPopupItem *pitem, void *data)
}
static void
-emfv_popup_flag_followup(EPopup *ep, EPopupItem *pitem, void *data)
+emfv_popup_flag_followup(GtkWidget *w, EMFolderView *emfv)
{
- EMFolderView *emfv = data;
GPtrArray *uids = message_list_get_selected(emfv->list);
em_utils_flag_for_followup((GtkWidget *)emfv, emfv->folder, uids);
}
static void
-emfv_popup_flag_completed(EPopup *ep, EPopupItem *pitem, void *data)
+emfv_popup_flag_completed(GtkWidget *w, EMFolderView *emfv)
{
- EMFolderView *emfv = data;
GPtrArray *uids;
uids = message_list_get_selected(emfv->list);
@@ -733,25 +710,22 @@ emfv_popup_flag_completed(EPopup *ep, EPopupItem *pitem, void *data)
}
static void
-emfv_popup_flag_clear(EPopup *ep, EPopupItem *pitem, void *data)
+emfv_popup_flag_clear(GtkWidget *w, EMFolderView *emfv)
{
- EMFolderView *emfv = data;
GPtrArray *uids = message_list_get_selected(emfv->list);
em_utils_flag_for_followup_clear((GtkWidget *)emfv, emfv->folder, uids);
}
static void
-emfv_popup_mark_read(EPopup *ep, EPopupItem *pitem, void *data)
+emfv_popup_mark_read(GtkWidget *w, EMFolderView *emfv)
{
- EMFolderView *emfv = data;
em_folder_view_mark_selected(emfv, CAMEL_MESSAGE_SEEN, CAMEL_MESSAGE_SEEN);
}
static void
-emfv_popup_mark_unread(EPopup *ep, EPopupItem *pitem, void *data)
+emfv_popup_mark_unread(GtkWidget *w, EMFolderView *emfv)
{
- EMFolderView *emfv = data;
em_folder_view_mark_selected(emfv, CAMEL_MESSAGE_SEEN|CAMEL_MESSAGE_DELETED, 0);
if (emfv->priv->seen_id) {
@@ -761,63 +735,65 @@ emfv_popup_mark_unread(EPopup *ep, EPopupItem *pitem, void *data)
}
static void
-emfv_popup_mark_important(EPopup *ep, EPopupItem *pitem, void *data)
+emfv_popup_mark_important(GtkWidget *w, EMFolderView *emfv)
{
- EMFolderView *emfv = data;
em_folder_view_mark_selected(emfv, CAMEL_MESSAGE_FLAGGED|CAMEL_MESSAGE_DELETED, CAMEL_MESSAGE_FLAGGED);
}
static void
-emfv_popup_mark_unimportant(EPopup *ep, EPopupItem *pitem, void *data)
+emfv_popup_mark_unimportant(GtkWidget *w, EMFolderView *emfv)
{
- EMFolderView *emfv = data;
em_folder_view_mark_selected(emfv, CAMEL_MESSAGE_FLAGGED, 0);
}
static void
-emfv_popup_mark_junk (EPopup *ep, EPopupItem *pitem, void *data)
+emfv_popup_mark_junk (GtkWidget *w, EMFolderView *emfv)
{
- EMFolderView *emfv = data;
- int count;
+ GPtrArray *uids;
- count = em_folder_view_mark_selected(emfv,
- CAMEL_MESSAGE_SEEN|CAMEL_MESSAGE_JUNK|CAMEL_MESSAGE_JUNK_LEARN,
- CAMEL_MESSAGE_SEEN|CAMEL_MESSAGE_JUNK|CAMEL_MESSAGE_JUNK_LEARN);
- if (count == 1)
+ uids = message_list_get_selected(emfv->list);
+ em_folder_view_mark_selected(emfv,
+ CAMEL_MESSAGE_SEEN|CAMEL_MESSAGE_JUNK|CAMEL_MESSAGE_JUNK_LEARN,
+ CAMEL_MESSAGE_SEEN|CAMEL_MESSAGE_JUNK|CAMEL_MESSAGE_JUNK_LEARN);
+ if (uids->len == 1)
message_list_select(emfv->list, MESSAGE_LIST_SELECT_NEXT, 0, 0);
+
+ message_list_free_uids(emfv->list, uids);
}
static void
-emfv_popup_mark_nojunk (EPopup *ep, EPopupItem *pitem, void *data)
+emfv_popup_mark_nojunk (GtkWidget *w, EMFolderView *emfv)
{
- EMFolderView *emfv = data;
- int count;
+ GPtrArray *uids;
- count = em_folder_view_mark_selected(emfv,
- CAMEL_MESSAGE_JUNK|CAMEL_MESSAGE_JUNK_LEARN,
- CAMEL_MESSAGE_JUNK_LEARN);
- if (count == 1)
+ uids = message_list_get_selected(emfv->list);
+ em_folder_view_mark_selected(emfv,
+ CAMEL_MESSAGE_JUNK|CAMEL_MESSAGE_JUNK_LEARN,
+ CAMEL_MESSAGE_JUNK_LEARN);
+ if (uids->len == 1)
message_list_select(emfv->list, MESSAGE_LIST_SELECT_NEXT, 0, 0);
+
+ message_list_free_uids(emfv->list, uids);
}
static void
-emfv_popup_delete(EPopup *ep, EPopupItem *pitem, void *data)
+emfv_popup_delete(GtkWidget *w, EMFolderView *emfv)
{
- EMFolderView *emfv = data;
- int count;
+ GPtrArray *uids;
- count = em_folder_view_mark_selected(emfv, CAMEL_MESSAGE_SEEN|CAMEL_MESSAGE_DELETED, CAMEL_MESSAGE_SEEN|CAMEL_MESSAGE_DELETED);
+ uids = message_list_get_selected(emfv->list);
+ em_folder_view_mark_selected(emfv, CAMEL_MESSAGE_SEEN|CAMEL_MESSAGE_DELETED, CAMEL_MESSAGE_SEEN|CAMEL_MESSAGE_DELETED);
- if (count == 1) {
+ if (uids->len == 1) {
if (!message_list_select (emfv->list, MESSAGE_LIST_SELECT_NEXT, 0, 0) && emfv->hide_deleted)
message_list_select (emfv->list, MESSAGE_LIST_SELECT_PREVIOUS, 0, 0);
}
+ em_utils_uids_free(uids);
}
static void
-emfv_popup_undelete(EPopup *ep, EPopupItem *pitem, void *data)
+emfv_popup_undelete(GtkWidget *w, EMFolderView *emfv)
{
- EMFolderView *emfv = data;
em_folder_view_mark_selected(emfv, CAMEL_MESSAGE_DELETED, 0);
}
@@ -846,9 +822,8 @@ emfv_popup_move_cb(const char *uri, void *data)
}
static void
-emfv_popup_move(EPopup *ep, EPopupItem *pitem, void *data)
+emfv_popup_move(GtkWidget *w, EMFolderView *emfv)
{
- EMFolderView *emfv = data;
struct _move_data *d;
d = g_malloc(sizeof(*d));
@@ -857,13 +832,12 @@ emfv_popup_move(EPopup *ep, EPopupItem *pitem, void *data)
d->uids = message_list_get_selected(emfv->list);
d->delete = TRUE;
- em_select_folder ((GtkWindow *) emfv, _("Select folder"), _("_Move"), default_xfer_messages_uri, NULL, emfv_popup_move_cb, d);
+ em_select_folder ((GtkWindow *) emfv, _("Select folder"), _("_Move"), default_xfer_messages_uri, emfv_popup_move_cb, d);
}
static void
-emfv_popup_copy(EPopup *ep, EPopupItem *pitem, void *data)
+emfv_popup_copy(GtkWidget *w, EMFolderView *emfv)
{
- EMFolderView *emfv = data;
struct _move_data *d;
d = g_malloc(sizeof(*d));
@@ -872,7 +846,7 @@ emfv_popup_copy(EPopup *ep, EPopupItem *pitem, void *data)
d->uids = message_list_get_selected(emfv->list);
d->delete = FALSE;
- em_select_folder ((GtkWindow *) emfv, _("Select folder"), _("C_opy"), default_xfer_messages_uri, NULL, emfv_popup_move_cb, d);
+ em_select_folder ((GtkWindow *) emfv, _("Select folder"), _("C_opy"), default_xfer_messages_uri, emfv_popup_move_cb, d);
}
static void
@@ -888,24 +862,20 @@ emfv_set_label(EMFolderView *emfv, const char *label)
}
static void
-emfv_popup_label_clear(EPopup *ep, EPopupItem *pitem, void *data)
+emfv_popup_label_clear(GtkWidget *w, EMFolderView *emfv)
{
- EMFolderView *emfv = data;
emfv_set_label(emfv, NULL);
}
static void
-emfv_popup_label_set(EPopup *ep, EPopupItem *pitem, void *data)
+emfv_popup_label_set(GtkWidget *w, struct _emfv_label_item *item)
{
- EMFolderView *emfv = data;
-
- emfv_set_label(emfv, pitem->user_data);
+ emfv_set_label(item->emfv, item->label);
}
static void
-emfv_popup_add_sender(EPopup *ep, EPopupItem *pitem, void *data)
+emfv_popup_add_sender(GtkWidget *w, EMFolderView *emfv)
{
- EMFolderView *emfv = data;
GPtrArray *uids = message_list_get_selected(emfv->list);
CamelMessageInfo *info;
const char *addr;
@@ -920,18 +890,16 @@ emfv_popup_add_sender(EPopup *ep, EPopupItem *pitem, void *data)
}
static void
-emfv_popup_apply_filters(EPopup *ep, EPopupItem *pitem, void *data)
+emfv_popup_apply_filters(GtkWidget *w, EMFolderView *emfv)
{
- EMFolderView *emfv = data;
GPtrArray *uids = message_list_get_selected(emfv->list);
mail_filter_on_demand(emfv->folder, uids);
}
static void
-emfv_popup_filter_junk(EPopup *ep, EPopupItem *pitem, void *data)
+emfv_popup_filter_junk(GtkWidget *w, EMFolderView *emfv)
{
- EMFolderView *emfv = data;
GPtrArray *uids = message_list_get_selected(emfv->list);
mail_filter_junk(emfv->folder, uids);
@@ -942,9 +910,8 @@ emfv_popup_filter_junk(EPopup *ep, EPopupItem *pitem, void *data)
#define EMFV_POPUP_AUTO_TYPE(autotype, name, type) \
static void \
-name(EPopup *ep, EPopupItem *item, void *data) \
+name(GtkWidget *w, EMFolderView *emfv) \
{ \
- EMFolderView *emfv = data; \
autotype(emfv, type); \
}
@@ -960,87 +927,83 @@ EMFV_POPUP_AUTO_TYPE(filter_type_current, emfv_popup_filter_mlist, AUTO_MLIST)
/* TODO: Move some of these to be 'standard' menu's */
-static EPopupItem emfv_popup_items[] = {
- { E_POPUP_ITEM, "00.emfv.00", N_("_Open"), emfv_popup_open, NULL, NULL, 0 },
- { E_POPUP_ITEM, "00.emfv.01", N_("_Edit as New Message..."), emfv_popup_edit, NULL, NULL, EM_POPUP_SELECT_EDIT },
- { E_POPUP_ITEM, "00.emfv.02", N_("_Save As..."), emfv_popup_saveas, NULL, "stock_save-as", 0 },
- { E_POPUP_ITEM, "00.emfv.03", N_("_Print"), emfv_popup_print, NULL, "stock_print", 0 },
-
- { E_POPUP_BAR, "10.emfv" },
- { E_POPUP_ITEM, "10.emfv.00", N_("_Reply to Sender"), emfv_popup_reply_sender, NULL, "stock_mail-reply", EM_POPUP_SELECT_ONE },
- { E_POPUP_ITEM, "10.emfv.01", N_("Reply to _List"), emfv_popup_reply_list, NULL, NULL, EM_POPUP_SELECT_ONE|EM_POPUP_SELECT_MAILING_LIST },
- { E_POPUP_ITEM, "10.emfv.02", N_("Reply to _All"), emfv_popup_reply_all, NULL, "stock_mail-reply-to-all", EM_POPUP_SELECT_ONE },
- { E_POPUP_ITEM, "10.emfv.03", N_("_Forward"), emfv_popup_forward, NULL, "stock_mail-forward", EM_POPUP_SELECT_MANY },
-
- { E_POPUP_BAR, "20.emfv", NULL, NULL, NULL, NULL, EM_POPUP_SELECT_FLAG_FOLLOWUP|EM_POPUP_SELECT_FLAG_COMPLETED|EM_POPUP_SELECT_FLAG_CLEAR },
- { E_POPUP_ITEM, "20.emfv.00", N_("Follo_w Up..."), emfv_popup_flag_followup, NULL, "stock_mail-flag-for-followup", EM_POPUP_SELECT_FLAG_FOLLOWUP },
- { E_POPUP_ITEM, "20.emfv.01", N_("Fla_g Completed"), emfv_popup_flag_completed, NULL, NULL, EM_POPUP_SELECT_FLAG_COMPLETED },
- { E_POPUP_ITEM, "20.emfv.02", N_("Cl_ear Flag"), emfv_popup_flag_clear, NULL, NULL, EM_POPUP_SELECT_FLAG_CLEAR },
-
- { E_POPUP_BAR, "30.emfv" },
- { E_POPUP_ITEM, "30.emfv.00", N_("Mar_k as Read"), emfv_popup_mark_read, NULL, "stock_mail-open", EM_POPUP_SELECT_MARK_READ },
- { E_POPUP_ITEM, "30.emfv.01", N_("Mark as _Unread"), emfv_popup_mark_unread, NULL, "stock_mail-unread", EM_POPUP_SELECT_MARK_UNREAD },
- { E_POPUP_ITEM, "30.emfv.02", N_("Mark as _Important"), emfv_popup_mark_important, NULL, "stock_mail-priority-high", EM_POPUP_SELECT_MARK_IMPORTANT },
- { E_POPUP_ITEM, "30.emfv.03", N_("_Mark as Unimportant"), emfv_popup_mark_unimportant, NULL, NULL, EM_POPUP_SELECT_MARK_UNIMPORTANT },
- { E_POPUP_ITEM, "30.emfv.04", N_("Mark as _Junk"), emfv_popup_mark_junk, NULL, "stock_spam", EM_POPUP_SELECT_MANY },
- { E_POPUP_ITEM, "30.emfv.05", N_("Mark as _Not Junk"), emfv_popup_mark_nojunk, NULL, "stock_not-spam", EM_POPUP_SELECT_MANY },
-
- { E_POPUP_BAR, "40.emfv" },
- { E_POPUP_ITEM, "40.emfv.00", N_("_Delete"), emfv_popup_delete, NULL, "stock_delete", EM_POPUP_SELECT_DELETE },
- { E_POPUP_ITEM, "40.emfv.01", N_("U_ndelete"), emfv_popup_undelete, NULL, "stock_undelete", EM_POPUP_SELECT_UNDELETE },
-
- { E_POPUP_BAR, "50.emfv" },
- { E_POPUP_ITEM, "50.emfv.00", N_("Mo_ve to Folder..."), emfv_popup_move },
- { E_POPUP_ITEM, "50.emfv.01", N_("_Copy to Folder..."), emfv_popup_copy },
-
- { E_POPUP_BAR, "60.label" },
- { E_POPUP_SUBMENU, "60.label.00", N_("Label") },
- { E_POPUP_IMAGE, "60.label.00/00.label", N_("None"), emfv_popup_label_clear },
- { E_POPUP_BAR, "60.label.00/00.label.00" },
-
- { E_POPUP_BAR, "70.emfv", NULL, NULL, NULL, NULL, EM_POPUP_SELECT_ADD_SENDER },
- { E_POPUP_ITEM, "70.emfv.00", N_("Add Sender to Address_book"), emfv_popup_add_sender, NULL, NULL, EM_POPUP_SELECT_ADD_SENDER },
-
- { E_POPUP_BAR, "80.emfv" },
- { E_POPUP_ITEM, "80.emfv.00", N_("Appl_y Filters"), emfv_popup_apply_filters, NULL, "stock_mail-filters-apply" },
- { E_POPUP_ITEM, "80.emfv.01", N_("F_ilter Junk"), emfv_popup_filter_junk, NULL, "stock_spam" },
-
- { E_POPUP_BAR, "90.filter", NULL, NULL, NULL, NULL, EM_POPUP_SELECT_ONE },
- { E_POPUP_SUBMENU, "90.filter.00", N_("Crea_te Rule From Message"), NULL, NULL, NULL, EM_POPUP_SELECT_ONE },
- { E_POPUP_ITEM, "90.filter.00/00.00", N_("vFolder on _Subject"), emfv_popup_vfolder_subject, NULL, NULL, EM_POPUP_SELECT_ONE },
- { E_POPUP_ITEM, "90.filter.00/00.01", N_("vFolder on Se_nder"), emfv_popup_vfolder_sender, NULL, NULL, EM_POPUP_SELECT_ONE },
- { E_POPUP_ITEM, "90.filter.00/00.02", N_("vFolder on _Recipients"), emfv_popup_vfolder_recipients, NULL, NULL, EM_POPUP_SELECT_ONE },
- { E_POPUP_ITEM, "90.filter.00/00.03", N_("vFolder on Mailing _List"),
- emfv_popup_vfolder_mlist, NULL, NULL, EM_POPUP_SELECT_ONE|EM_POPUP_SELECT_MAILING_LIST },
-
- { E_POPUP_BAR, "90.filter.00/10", NULL, NULL, NULL, NULL, EM_POPUP_SELECT_ONE },
- { E_POPUP_ITEM, "90.filter.00/10.00", N_("Filter on Sub_ject"), emfv_popup_filter_subject, NULL, NULL, EM_POPUP_SELECT_ONE },
- { E_POPUP_ITEM, "90.filter.00/10.01", N_("Filter on Sen_der"), emfv_popup_filter_sender, NULL, NULL, EM_POPUP_SELECT_ONE },
- { E_POPUP_ITEM, "90.filter.00/10.02", N_("Filter on Re_cipients"), emfv_popup_filter_recipients, NULL, NULL, EM_POPUP_SELECT_ONE },
- { E_POPUP_ITEM, "90.filter.00/10.03", N_("Filter on _Mailing List"),
- emfv_popup_filter_mlist, NULL, NULL, EM_POPUP_SELECT_ONE|EM_POPUP_SELECT_MAILING_LIST },
+static EMPopupItem emfv_popup_menu[] = {
+ { EM_POPUP_ITEM, "00.emfv.00", N_("_Open"), G_CALLBACK(emfv_popup_open), NULL, NULL, 0 },
+ { EM_POPUP_ITEM, "00.emfv.01", N_("_Edit as New Message..."), G_CALLBACK(emfv_popup_edit), NULL, NULL, EM_POPUP_SELECT_EDIT },
+ { EM_POPUP_ITEM, "00.emfv.02", N_("_Save As..."), G_CALLBACK(emfv_popup_saveas), NULL, "stock_save-as", 0 },
+ { EM_POPUP_ITEM, "00.emfv.03", N_("_Print"), G_CALLBACK(emfv_popup_print), NULL, "stock_print", 0 },
+
+ { EM_POPUP_BAR, "10.emfv" },
+ { EM_POPUP_ITEM, "10.emfv.00", N_("_Reply to Sender"), G_CALLBACK(emfv_popup_reply_sender), NULL, "stock_mail-reply", EM_POPUP_SELECT_ONE },
+ { EM_POPUP_ITEM, "10.emfv.01", N_("Reply to _List"), G_CALLBACK(emfv_popup_reply_list), NULL, NULL, EM_POPUP_SELECT_ONE|EM_POPUP_SELECT_MAILING_LIST },
+ { EM_POPUP_ITEM, "10.emfv.02", N_("Reply to _All"), G_CALLBACK(emfv_popup_reply_all), NULL, "stock_mail-reply-to-all", EM_POPUP_SELECT_ONE },
+ { EM_POPUP_ITEM, "10.emfv.03", N_("_Forward"), G_CALLBACK(emfv_popup_forward), NULL, "stock_mail-forward", EM_POPUP_SELECT_MANY },
+
+ { EM_POPUP_BAR, "20.emfv", NULL, NULL, NULL, NULL, EM_POPUP_SELECT_FLAG_FOLLOWUP|EM_POPUP_SELECT_FLAG_COMPLETED|EM_POPUP_SELECT_FLAG_CLEAR },
+ { EM_POPUP_ITEM, "20.emfv.00", N_("Follo_w Up..."), G_CALLBACK(emfv_popup_flag_followup), NULL, "stock_mail-flag-for-followup", EM_POPUP_SELECT_FLAG_FOLLOWUP },
+ { EM_POPUP_ITEM, "20.emfv.01", N_("Fla_g Completed"), G_CALLBACK(emfv_popup_flag_completed), NULL, NULL, EM_POPUP_SELECT_FLAG_COMPLETED },
+ { EM_POPUP_ITEM, "20.emfv.02", N_("Cl_ear Flag"), G_CALLBACK(emfv_popup_flag_clear), NULL, NULL, EM_POPUP_SELECT_FLAG_CLEAR },
+
+ { EM_POPUP_BAR, "30.emfv" },
+ { EM_POPUP_ITEM, "30.emfv.00", N_("Mar_k as Read"), G_CALLBACK(emfv_popup_mark_read), NULL, "stock_mail-open", EM_POPUP_SELECT_MARK_READ },
+ { EM_POPUP_ITEM, "30.emfv.01", N_("Mark as _Unread"), G_CALLBACK(emfv_popup_mark_unread), NULL, "stock_mail-unread", EM_POPUP_SELECT_MARK_UNREAD },
+ { EM_POPUP_ITEM, "30.emfv.02", N_("Mark as _Important"), G_CALLBACK(emfv_popup_mark_important), NULL, "stock_mail-priority-high", EM_POPUP_SELECT_MARK_IMPORTANT },
+ { EM_POPUP_ITEM, "30.emfv.03", N_("_Mark as Unimportant"), G_CALLBACK(emfv_popup_mark_unimportant), NULL, NULL, EM_POPUP_SELECT_MARK_UNIMPORTANT },
+ { EM_POPUP_ITEM, "30.emfv.04", N_("Mark as _Junk"), G_CALLBACK(emfv_popup_mark_junk), NULL, "stock_spam", EM_POPUP_SELECT_MARK_JUNK },
+ { EM_POPUP_ITEM, "30.emfv.05", N_("Mark as _Not Junk"), G_CALLBACK(emfv_popup_mark_nojunk), NULL, "stock_not-spam", EM_POPUP_SELECT_MARK_NOJUNK },
+
+ { EM_POPUP_BAR, "40.emfv" },
+ { EM_POPUP_ITEM, "40.emfv.00", N_("_Delete"), G_CALLBACK(emfv_popup_delete), NULL, "stock_delete", EM_POPUP_SELECT_DELETE },
+ { EM_POPUP_ITEM, "40.emfv.01", N_("U_ndelete"), G_CALLBACK(emfv_popup_undelete), NULL, "stock_undelete", EM_POPUP_SELECT_UNDELETE },
+
+ { EM_POPUP_BAR, "50.emfv" },
+ { EM_POPUP_ITEM, "50.emfv.00", N_("Mo_ve to Folder..."), G_CALLBACK(emfv_popup_move) },
+ { EM_POPUP_ITEM, "50.emfv.01", N_("_Copy to Folder..."), G_CALLBACK(emfv_popup_copy) },
+
+ { EM_POPUP_BAR, "60.label" },
+ { EM_POPUP_SUBMENU, "60.label.00", N_("Label") },
+ { EM_POPUP_IMAGE, "60.label.00/00.label", N_("None"), G_CALLBACK(emfv_popup_label_clear) },
+ { EM_POPUP_BAR, "60.label.00/00.label.00" },
+
+ { EM_POPUP_BAR, "70.emfv", NULL, NULL, NULL, NULL, EM_POPUP_SELECT_ADD_SENDER },
+ { EM_POPUP_ITEM, "70.emfv.00", N_("Add Sender to Address_book"), G_CALLBACK(emfv_popup_add_sender), NULL, NULL, EM_POPUP_SELECT_ADD_SENDER },
+
+ { EM_POPUP_BAR, "80.emfv" },
+ { EM_POPUP_ITEM, "80.emfv.00", N_("Appl_y Filters"), G_CALLBACK(emfv_popup_apply_filters), NULL, "stock_mail-filters-apply" },
+ { EM_POPUP_ITEM, "80.emfv.01", N_("F_ilter Junk"), G_CALLBACK(emfv_popup_filter_junk), NULL, "stock_spam" },
+
+ { EM_POPUP_BAR, "90.filter", NULL, NULL, NULL, NULL, EM_POPUP_SELECT_ONE },
+ { EM_POPUP_SUBMENU, "90.filter.00", N_("Crea_te Rule From Message"), NULL, NULL, NULL, EM_POPUP_SELECT_ONE },
+ { EM_POPUP_ITEM, "90.filter.00/00.00", N_("VFolder on _Subject"), G_CALLBACK(emfv_popup_vfolder_subject), NULL, NULL, EM_POPUP_SELECT_ONE },
+ { EM_POPUP_ITEM, "90.filter.00/00.01", N_("VFolder on Se_nder"), G_CALLBACK(emfv_popup_vfolder_sender), NULL, NULL, EM_POPUP_SELECT_ONE },
+ { EM_POPUP_ITEM, "90.filter.00/00.02", N_("VFolder on _Recipients"), G_CALLBACK(emfv_popup_vfolder_recipients), NULL, NULL, EM_POPUP_SELECT_ONE },
+ { EM_POPUP_ITEM, "90.filter.00/00.03", N_("VFolder on Mailing _List"),
+ G_CALLBACK(emfv_popup_vfolder_mlist), NULL, NULL, EM_POPUP_SELECT_ONE|EM_POPUP_SELECT_MAILING_LIST },
+
+ { EM_POPUP_BAR, "90.filter.00/10", NULL, NULL, NULL, NULL, EM_POPUP_SELECT_ONE },
+ { EM_POPUP_ITEM, "90.filter.00/10.00", N_("Filter on Sub_ject"), G_CALLBACK(emfv_popup_filter_subject), NULL, NULL, EM_POPUP_SELECT_ONE },
+ { EM_POPUP_ITEM, "90.filter.00/10.01", N_("Filter on Sen_der"), G_CALLBACK(emfv_popup_filter_sender), NULL, NULL, EM_POPUP_SELECT_ONE },
+ { EM_POPUP_ITEM, "90.filter.00/10.02", N_("Filter on Re_cipients"), G_CALLBACK(emfv_popup_filter_recipients), NULL, NULL, EM_POPUP_SELECT_ONE },
+ { EM_POPUP_ITEM, "90.filter.00/10.03", N_("Filter on _Mailing List"),
+ G_CALLBACK(emfv_popup_filter_mlist), NULL, NULL, EM_POPUP_SELECT_ONE|EM_POPUP_SELECT_MAILING_LIST },
};
static void
-emfv_popup_labels_free(EPopup *ep, GSList *l, void *data)
+emfv_popup_labels_free(void *data)
{
+ GSList *l = data;
+
while (l) {
GSList *n = l->next;
- EPopupItem *item = l->data;
+ struct _emfv_label_item *item = l->data;
- g_free(item->path);
+ g_free(item->item.path);
g_free(item);
g_slist_free_1(l);
l = n;
}
}
-
-static void
-emfv_popup_items_free(EPopup *ep, GSList *items, void *data)
-{
- g_slist_free(items);
-}
static void
emfv_popup(EMFolderView *emfv, GdkEvent *event)
@@ -1048,38 +1011,37 @@ emfv_popup(EMFolderView *emfv, GdkEvent *event)
GSList *menus = NULL, *l, *label_list = NULL;
GtkMenu *menu;
EMPopup *emp;
- EMPopupTargetSelect *target;
+ EMPopupTarget *target;
int i;
- /** @HookPoint-EMPopup: Message List Context Menu
- * @Id: org.gnome.evolution.mail.folderview.popup.select
- * @Type: EMPopup
- * @Target: EMPopupTargetSelect
- *
- * This is the context menu shown on the message list or over a message.
- */
- emp = em_popup_new("org.gnome.evolution.mail.folderview.popup");
- target = em_folder_view_get_popup_target(emfv, emp);
+ emp = em_popup_new("com.ximian.mail.folderview.popup.select");
+ target = em_folder_view_get_popup_target(emfv);
+
+ for (i=0;i<sizeof(emfv_popup_menu)/sizeof(emfv_popup_menu[0]);i++) {
+ EMPopupItem *item = &emfv_popup_menu[i];
- for (i=0;i<sizeof(emfv_popup_items)/sizeof(emfv_popup_items[0]);i++)
- menus = g_slist_prepend(menus, &emfv_popup_items[i]);
+ item->activate_data = emfv;
+ menus = g_slist_prepend(menus, item);
+ }
- e_popup_add_items((EPopup *)emp, menus, NULL, emfv_popup_items_free, emfv);
+ em_popup_add_items(emp, menus, (GDestroyNotify)g_slist_free);
i = 1;
for (l = mail_config_get_labels(); l; l = l->next) {
- EPopupItem *item;
+ struct _emfv_label_item *item;
MailConfigLabel *label = l->data;
GdkPixmap *pixmap;
GdkColor colour;
GdkGC *gc;
item = g_malloc0(sizeof(*item));
- item->type = E_POPUP_IMAGE;
- item->path = g_strdup_printf("60.label.00/00.label.%02d", i++);
- item->label = label->name;
- item->activate = emfv_popup_label_set;
- item->user_data = label->tag;
+ item->item.type = EM_POPUP_IMAGE;
+ item->item.path = g_strdup_printf("60.label.00/00.label.%02d", i++);
+ item->item.label = label->name;
+ item->item.activate = G_CALLBACK(emfv_popup_label_set);
+ item->item.activate_data = item;
+ item->emfv = emfv;
+ item->label = label->tag;
gdk_color_parse(label->colour, &colour);
gdk_color_alloc(gdk_colormap_get_system(), &colour);
@@ -1090,19 +1052,19 @@ emfv_popup(EMFolderView *emfv, GdkEvent *event)
gdk_draw_rectangle(pixmap, gc, TRUE, 0, 0, 16, 16);
gdk_gc_unref(gc);
- item->image = gtk_image_new_from_pixmap(pixmap, NULL);
- gtk_widget_show(item->image);
+ item->item.image = gtk_image_new_from_pixmap(pixmap, NULL);
+ gtk_widget_show(item->item.image);
label_list = g_slist_prepend(label_list, item);
}
- e_popup_add_items((EPopup *)emp, label_list, NULL, emfv_popup_labels_free, emfv);
+ em_popup_add_items(emp, label_list, emfv_popup_labels_free);
- menu = e_popup_create_menu_once((EPopup *)emp, (EPopupTarget *)target, 0);
+ menu = em_popup_create_menu_once(emp, target, target->mask, target->mask);
if (event == NULL || event->type == GDK_KEY_PRESS) {
/* FIXME: menu pos function */
- gtk_menu_popup(menu, NULL, NULL, NULL, NULL, 0, event ? event->key.time : gtk_get_current_event_time());
+ gtk_menu_popup(menu, NULL, NULL, NULL, NULL, 0, event ? event->key.time : time (NULL));
} else {
gtk_menu_popup(menu, NULL, NULL, NULL, NULL, event->button.button, event->button.time);
}
@@ -1117,7 +1079,7 @@ emfv_popup(EMFolderView *emfv, GdkEvent *event)
static void \
from(BonoboUIComponent *uid, void *data, const char *path) \
{ \
- to(NULL, NULL, data); \
+ to(NULL, (EMFolderView *)data); \
}
EMFV_MAP_CALLBACK(emfv_add_sender_addressbook, emfv_popup_add_sender)
@@ -1642,8 +1604,8 @@ static const EMFolderViewEnable emfv_enable_map[] = {
{ "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 },
- { "MessageMarkAsNotJunk", EM_POPUP_SELECT_MANY },
+ { "MessageMarkAsJunk", EM_POPUP_SELECT_MANY|EM_POPUP_SELECT_MARK_JUNK },
+ { "MessageMarkAsNotJunk", EM_POPUP_SELECT_MANY|EM_POPUP_SELECT_MARK_NOJUNK },
{ "MessageFollowUpFlag", EM_POPUP_SELECT_MANY },
{ "MessageMove", EM_POPUP_SELECT_MANY },
{ "MessageOpen", EM_POPUP_SELECT_MANY },
@@ -1689,31 +1651,15 @@ emfv_enable_menus(EMFolderView *emfv)
guint32 disable_mask;
GString *name;
GSList *l;
+ EMPopupTarget *t;
if (emfv->uic == NULL)
return;
- {
- if (emfv->menu) {
- if (emfv->folder) {
- EMMenuTargetSelect *t;
-
- t = em_menu_target_new_select(emfv->menu, emfv->folder, emfv->folder_uri, message_list_get_selected(emfv->list));
- e_menu_update_target((EMenu *)emfv->menu, t);
- } else {
- e_menu_update_target((EMenu *)emfv->menu, NULL);
- }
- }
- }
-
if (emfv->folder) {
- EMPopup *emp = em_popup_new("dummy");
- EMPopupTargetSelect *t;
-
- t = em_folder_view_get_popup_target(emfv, emp);
- disable_mask = t->target.mask;
- e_popup_target_free((EPopup *)emp, t);
- g_object_unref(emp);
+ t = em_folder_view_get_popup_target(emfv);
+ disable_mask = t->mask;
+ em_popup_target_free(t);
} else {
disable_mask = ~0;
}
@@ -1819,10 +1765,6 @@ emfv_activate(EMFolderView *emfv, BonoboUIComponent *uic, int act)
bonobo_ui_component_add_verb_list_with_data(uic, emfv_message_verbs, emfv);
e_pixmaps_update(uic, emfv_message_pixmaps);
- /* must do plugin menu's after main ones because of bonobo bustedness */
- if (emfv->menu)
- e_menu_activate((EMenu *)emfv->menu, uic, act);
-
state = emfv->preview->caret_mode;
bonobo_ui_component_set_prop(uic, "/commands/CaretMode", "state", state?"1":"0", NULL);
bonobo_ui_component_add_listener(uic, "CaretMode", emfv_caret_mode, emfv);
@@ -1850,9 +1792,6 @@ emfv_activate(EMFolderView *emfv, BonoboUIComponent *uic, int act)
} else {
const BonoboUIVerb *v;
- if (emfv->menu)
- e_menu_activate((EMenu *)emfv->menu, uic, act);
-
/* TODO: Should this just rm /? */
for (v = &emfv_message_verbs[0]; v->cname; v++)
bonobo_ui_component_remove_verb(uic, v->cname);
@@ -1877,7 +1816,6 @@ emfv_activate(EMFolderView *emfv, BonoboUIComponent *uic, int act)
struct _print_data {
EMFolderView *emfv;
- GnomePrintConfig *config;
int preview;
CamelFolder *folder;
char *uid;
@@ -1887,15 +1825,20 @@ static void
emfv_print_response(GtkWidget *w, int resp, struct _print_data *data)
{
EMFormatHTMLPrint *print;
+ GnomePrintConfig *config = NULL;
switch (resp) {
case GNOME_PRINT_DIALOG_RESPONSE_PREVIEW:
data->preview = TRUE;
case GNOME_PRINT_DIALOG_RESPONSE_PRINT:
+ if (w)
+ config = gnome_print_dialog_get_config((GnomePrintDialog *)w);
print = em_format_html_print_new();
em_format_set_session((EMFormat *)print, ((EMFormat *)data->emfv->preview)->session);
- em_format_html_print_message(print, (EMFormatHTML *)data->emfv->preview, data->config, data->folder, data->uid, data->preview);
+ em_format_html_print_message(print, (EMFormatHTML *)data->emfv->preview, config, data->folder, data->uid, data->preview);
g_object_unref(print);
+ if (config)
+ g_object_unref(config);
break;
}
@@ -1903,8 +1846,6 @@ emfv_print_response(GtkWidget *w, int resp, struct _print_data *data)
gtk_widget_destroy(w);
g_object_unref(data->emfv);
- e_print_save_config (data->config);
- g_object_unref(data->config);
camel_object_unref(data->folder);
g_free(data->uid);
g_free(data);
@@ -1927,7 +1868,6 @@ int em_folder_view_print(EMFolderView *emfv, int preview)
data = g_malloc0(sizeof(*data));
data->emfv = emfv;
g_object_ref(emfv);
- data->config = e_print_load_config ();
data->preview = preview;
data->folder = emfv->folder;
camel_object_ref(data->folder);
@@ -1937,8 +1877,8 @@ int em_folder_view_print(EMFolderView *emfv, int preview)
if (preview) {
emfv_print_response(NULL, GNOME_PRINT_DIALOG_RESPONSE_PREVIEW, data);
} else {
- GtkDialog *dialog = (GtkDialog *)e_print_get_dialog_with_config (_("Print Message"), GNOME_PRINT_DIALOG_COPIES, data->config);
-
+ GtkDialog *dialog = (GtkDialog *)gnome_print_dialog_new(NULL, _("Print Message"), GNOME_PRINT_DIALOG_COPIES);
+
gtk_dialog_set_default_response(dialog, GNOME_PRINT_DIALOG_RESPONSE_PRINT);
e_dialog_set_transient_for ((GtkWindow *) dialog, (GtkWidget *) emfv);
g_signal_connect(dialog, "response", G_CALLBACK(emfv_print_response), data);
@@ -1948,29 +1888,29 @@ int em_folder_view_print(EMFolderView *emfv, int preview)
return 0;
}
-EMPopupTargetSelect *
-em_folder_view_get_popup_target(EMFolderView *emfv, EMPopup *emp)
+EMPopupTarget *
+em_folder_view_get_popup_target(EMFolderView *emfv)
{
- EMPopupTargetSelect *t;
+ EMPopupTarget *t;
- t = em_popup_target_new_select(emp, emfv->folder, emfv->folder_uri, message_list_get_selected(emfv->list));
- t->target.widget = (GtkWidget *)emfv;
+ t = em_popup_target_new_select(emfv->folder, emfv->folder_uri, message_list_get_selected(emfv->list));
+ t->widget = (GtkWidget *)emfv;
if (emfv->list->threaded)
- t->target.mask &= ~EM_FOLDER_VIEW_SELECT_THREADED;
+ t->mask &= ~EM_FOLDER_VIEW_SELECT_THREADED;
if (message_list_hidden(emfv->list) != 0)
- t->target.mask &= ~EM_FOLDER_VIEW_SELECT_HIDDEN;
+ t->mask &= ~EM_FOLDER_VIEW_SELECT_HIDDEN;
if (message_list_can_select(emfv->list, MESSAGE_LIST_SELECT_NEXT, 0, 0))
- t->target.mask &= ~EM_FOLDER_VIEW_SELECT_NEXT_MSG;
+ t->mask &= ~EM_FOLDER_VIEW_SELECT_NEXT_MSG;
if (message_list_can_select(emfv->list, MESSAGE_LIST_SELECT_PREVIOUS, 0, 0))
- t->target.mask &= ~EM_FOLDER_VIEW_SELECT_PREV_MSG;
+ t->mask &= ~EM_FOLDER_VIEW_SELECT_PREV_MSG;
/* See bug #54770 */
if (!emfv->hide_deleted)
- t->target.mask &= ~EM_POPUP_SELECT_DELETE;
+ t->mask &= ~EM_POPUP_SELECT_DELETE;
return t;
}
@@ -2034,27 +1974,14 @@ static void
emfv_list_done_message_selected(CamelFolder *folder, const char *uid, CamelMimeMessage *msg, void *data)
{
EMFolderView *emfv = data;
- EMEvent *eme;
- EMEventTargetMessage *target;
if (emfv->preview == NULL) {
emfv->priv->nomarkseen = FALSE;
- emfv_enable_menus(emfv);
g_object_unref (emfv);
+ emfv_enable_menus(emfv);
return;
}
-
- /** @Event: message.reading
- * @Title: Viewing a message
- * @Target: EMEventTargetMessage
- *
- * message.reading is emitted whenever a user views a message.
- */
- /* TODO: do we emit a message.reading with no message when we're looking at nothing or don't care? */
- eme = em_event_peek();
- target = em_event_target_new_message(eme, folder, msg, uid, 0);
- e_event_emit((EEvent *)eme, "message.reading", (EEventTarget *)target);
-
+
em_format_format((EMFormat *)emfv->preview, folder, uid, msg);
if (emfv->priv->seen_id)
@@ -2063,11 +1990,11 @@ emfv_list_done_message_selected(CamelFolder *folder, const char *uid, CamelMimeM
if (msg && emfv->mark_seen && !emfv->priv->nomarkseen) {
if (emfv->mark_seen_timeout > 0) {
struct mst_t *mst;
-
+
mst = g_new (struct mst_t, 1);
mst->emfv = emfv;
mst->uid = g_strdup (uid);
-
+
emfv->priv->seen_id = g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE, emfv->mark_seen_timeout,
(GSourceFunc)do_mark_seen, mst, (GDestroyNotify)mst_free);
} else {
@@ -2075,9 +2002,10 @@ emfv_list_done_message_selected(CamelFolder *folder, const char *uid, CamelMimeM
}
}
+ g_object_unref (emfv);
emfv->priv->nomarkseen = FALSE;
+
emfv_enable_menus(emfv);
- g_object_unref (emfv);
}
static void
@@ -2139,6 +2067,10 @@ emfv_list_key_press(ETree *tree, int row, ETreePath path, int col, GdkEvent *ev,
case GDK_ISO_Enter:
em_folder_view_open_selected(emfv);
break;
+ case GDK_Menu:
+ /* FIXME: location of popup */
+ emfv_popup(emfv, NULL);
+ break;
case '!':
uids = message_list_get_selected(emfv->list);
@@ -2161,26 +2093,6 @@ emfv_list_key_press(ETree *tree, int row, ETreePath path, int col, GdkEvent *ev,
return TRUE;
}
-static gboolean
-emfv_popup_menu (GtkWidget *widget)
-{
- gboolean ret = FALSE;
- EMFolderView *emfv = (EMFolderView *)widget;
-
- /* Try to bring up menu for preview html object.
- Currently we cannot directly connect to html's "popup_menu" signal
- since it doesn't work.
- */
-
- if (GTK_WIDGET_HAS_FOCUS (emfv->preview->formathtml.html))
- ret = em_format_html_display_popup_menu (emfv->preview);
-
- if (!ret)
- emfv_popup (emfv, NULL);
-
- return TRUE;
-}
-
static void
emfv_list_selection_change(ETree *tree, EMFolderView *emfv)
{
@@ -2212,32 +2124,38 @@ emfv_format_link_clicked(EMFormatHTMLDisplay *efhd, const char *uri, EMFolderVie
}
}
+struct _EMFVPopupItem {
+ EMPopupItem item;
+
+ EMFolderView *emfv;
+ char *uri;
+};
+
static void
-emp_uri_popup_link_copy(EPopup *ep, EPopupItem *pitem, void *data)
+emp_uri_popup_link_copy(GtkWidget *w, struct _EMFVPopupItem *item)
{
- EMFolderView *emfv = data;
- struct _EMFolderViewPrivate *p = emfv->priv;
+ struct _EMFolderViewPrivate *p = item->emfv->priv;
g_free(p->selection_uri);
- p->selection_uri = g_strdup(pitem->user_data);
+ p->selection_uri = g_strdup(item->uri);
gtk_selection_owner_set(p->invisible, GDK_SELECTION_PRIMARY, gtk_get_current_event_time());
gtk_selection_owner_set(p->invisible, GDK_SELECTION_CLIPBOARD, gtk_get_current_event_time());
}
-static EPopupItem emfv_uri_popups[] = {
- { E_POPUP_ITEM, "00.uri.01", N_("_Copy Link Location"), emp_uri_popup_link_copy, NULL, NULL, EM_POPUP_URI_NOT_MAILTO },
+static struct _EMFVPopupItem emfv_uri_popups[] = {
+ { { EM_POPUP_ITEM, "00.uri.01", N_("_Copy Link Location"), G_CALLBACK(emp_uri_popup_link_copy), NULL, NULL, EM_POPUP_URI_NOT_MAILTO }, },
};
static void
-emfv_uri_popup_free(EPopup *ep, GSList *list, void *data)
+emfv_uri_popup_free(GSList *list)
{
while (list) {
GSList *n = list->next;
- struct _EPopupItem *item = list->data;
+ struct _EMFVPopupItem *item = list->data;
- g_free(item->user_data);
- item->user_data = NULL;
+ g_free(item->uri);
+ g_object_unref(item->emfv);
g_slist_free_1(list);
list = n;
@@ -2248,7 +2166,7 @@ static int
emfv_format_popup_event(EMFormatHTMLDisplay *efhd, GdkEventButton *event, const char *uri, CamelMimePart *part, EMFolderView *emfv)
{
EMPopup *emp;
- EPopupTarget *target;
+ EMPopupTarget *target;
GtkMenu *menu;
if (uri == NULL && part == NULL) {
@@ -2265,47 +2183,27 @@ emfv_format_popup_event(EMFormatHTMLDisplay *efhd, GdkEventButton *event, const
/* FIXME: this maybe should just fit on em-html-display, it has access to the
snooped part type */
- /** @HookPoint-EMPopup: Inline URI Context Menu
- * @Id: org.gnome.evolution.mail.folderview.popup
- * @Class: org.gnome.evolution.mail.popup:1.0
- * @Target: EMPopupTargetURI
- *
- * This is the context menu shown when clicking on inline URIs,
- * including addresses or normal HTML links that are displayed inside
- * the message view.
- */
-
- /** @HookPoint-EMPopup: Inline Object Context Menu
- * @Id: org.gnome.evolution.mail.folderview.popup
- * @Class: org.gnome.evolution.mail.popup:1.0
- * @Target: EMPopupTargetPart
- *
- * This is the context menu shown when clicking on inline
- * content such as a picture.
- */
- emp = em_popup_new("org.gnome.evolution.mail.folderview.popup");
+ emp = em_popup_new("com.ximian.mail.folderview.popup.uri");
if (part)
- target = (EPopupTarget *)em_popup_target_new_part(emp, part, NULL);
+ target = em_popup_target_new_part(part, NULL);
else {
GSList *menus = NULL;
int i;
- EMPopupTargetURI *t;
- t = em_popup_target_new_uri(emp, uri);
- target = (EPopupTarget *)t;
+ target = em_popup_target_new_uri(uri);
for (i=0;i<sizeof(emfv_uri_popups)/sizeof(emfv_uri_popups[0]);i++) {
- emfv_uri_popups[i].user_data = g_strdup(t->uri);
+ emfv_uri_popups[i].item.activate_data = &emfv_uri_popups[i];
+ emfv_uri_popups[i].emfv = emfv;
+ g_object_ref(emfv);
+ emfv_uri_popups[i].uri = g_strdup(target->data.uri);
menus = g_slist_prepend(menus, &emfv_uri_popups[i]);
}
- e_popup_add_items((EPopup *)emp, menus, NULL, emfv_uri_popup_free, emfv);
+ em_popup_add_items(emp, menus, (GDestroyNotify)emfv_uri_popup_free);
}
- menu = e_popup_create_menu_once((EPopup *)emp, target, 0);
- if (event == NULL)
- gtk_menu_popup (menu, NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time());
- else
- gtk_menu_popup(menu, NULL, NULL, NULL, NULL, event->button, event->time);
+ menu = em_popup_create_menu_once(emp, target, target->mask, target->mask);
+ gtk_menu_popup(menu, NULL, NULL, NULL, NULL, event->button, event->time);
return TRUE;
}
diff --git a/mail/em-format-html-display.c b/mail/em-format-html-display.c
index 6f74fa0495..0f539fb3f1 100644
--- a/mail/em-format-html-display.c
+++ b/mail/em-format-html-display.c
@@ -52,7 +52,12 @@
#include <glade/glade.h>
#include <libgnomevfs/gnome-vfs-mime-handlers.h>
-#include <libgnome/gnome-i18n.h>
+
+#if 0
+#include <libgnomevfs/gnome-vfs-utils.h>
+#include <libgnomevfs/gnome-vfs-mime-utils.h>
+#include <libgnomevfs/gnome-vfs-mime.h>
+#endif
#include <bonobo/bonobo-control-frame.h>
#include <bonobo/bonobo-stream-memory.h>
@@ -72,7 +77,7 @@
/* should this be in e-util rather than gal? */
#include <gal/util/e-util.h>
-#include <libedataserver/e-msgport.h>
+#include <e-util/e-msgport.h>
#include <e-util/e-gui-utils.h>
#include <e-util/e-dialog-utils.h>
#include <e-util/e-icon-factory.h>
@@ -612,41 +617,6 @@ efhd_html_button_press_event (GtkWidget *widget, GdkEventButton *event, EMFormat
return res;
}
-gboolean
-em_format_html_display_popup_menu (EMFormatHTMLDisplay *efhd)
-{
- GtkHTML *html;
- HTMLEngine *e;
- HTMLObject *obj;
- const char *url;
- gboolean res = FALSE;
- gint offset;
- EMFormatPURI *puri = NULL;
- char *uri = NULL;
-
- html = efhd->formathtml.html;
- e = html->engine;
- if (!efhd->caret_mode)
- obj = html_engine_get_focus_object (e, &offset);
- else {
- obj = e->cursor->object;
- offset = e->cursor->offset;
- }
-
- if ( obj != NULL
- && ((url = html_object_get_src(obj)) != NULL
- || (url = html_object_get_url(obj, offset)) != NULL)) {
- uri = gtk_html_get_url_object_relative(html, obj, url);
- puri = em_format_find_puri((EMFormat *)efhd, uri);
- }
-
- g_signal_emit((GtkObject *)efhd, efhd_signals[EFHD_POPUP_EVENT], 0, NULL, uri, puri?puri->part:NULL, &res);
-
- g_free(uri);
-
- return res;
-}
-
static void
efhd_html_link_clicked (GtkHTML *html, const char *url, EMFormatHTMLDisplay *efhd)
{
@@ -875,6 +845,7 @@ static gboolean
efhd_xpkcs7mime_button(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *pobject)
{
GtkWidget *icon, *button;
+ GdkPixbuf *pixbuf;
struct _smime_pobject *po = (struct _smime_pobject *)pobject;
const char *name;
@@ -884,7 +855,10 @@ efhd_xpkcs7mime_button(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObje
else
name = smime_encrypt_table[po->valid->encrypt.status].icon;
- icon = e_icon_factory_get_image (name, E_ICON_SIZE_LARGE_TOOLBAR);
+ pixbuf = e_icon_factory_get_icon (name, E_ICON_SIZE_LARGE_TOOLBAR);
+
+ icon = gtk_image_new_from_pixbuf (pixbuf);
+ g_object_unref(pixbuf);
gtk_widget_show(icon);
button = gtk_button_new();
@@ -963,17 +937,19 @@ static const EMFormatHandler *efhd_find_handler(EMFormat *emf, const char *mime_
{
const EMFormatHandler *handle;
- if ( (handle = ((EMFormatClass *)efhd_parent)->find_handler(emf, mime_type)) == NULL
- && efhd_use_component(mime_type)
- && (handle = g_hash_table_lookup(efhd_bonobo_handlers, mime_type)) == NULL) {
- EMFormatHandler *h = g_malloc0(sizeof(*h));
+ if (efhd_use_component(mime_type)) {
+ if ((handle = g_hash_table_lookup(efhd_bonobo_handlers, mime_type)) == NULL) {
+ EMFormatHandler *h = g_malloc0(sizeof(*h));
- h->mime_type = g_strdup(mime_type);
- h->handler = efhd_bonobo_unknown;
- h->flags = EM_FORMAT_HANDLER_INLINE_DISPOSITION;
- g_hash_table_insert(efhd_bonobo_handlers, h->mime_type, h);
+ h->mime_type = g_strdup(mime_type);
+ h->handler = efhd_bonobo_unknown;
+ h->flags = EM_FORMAT_HANDLER_INLINE_DISPOSITION;
+ g_hash_table_insert(efhd_bonobo_handlers, h->mime_type, h);
- handle = h;
+ handle = h;
+ }
+ } else {
+ handle = ((EMFormatClass *)efhd_parent)->find_handler(emf, mime_type);
}
return handle;
@@ -1074,35 +1050,21 @@ static void efhd_format_source(EMFormat *emf, CamelStream *stream, CamelMimePart
/* if it hasn't been processed yet, format the attachment */
static void
-efhd_attachment_show(EPopup *ep, EPopupItem *item, void *data)
+efhd_attachment_show(GtkWidget *w, struct _attach_puri *info)
{
- struct _attach_puri *info = data;
-
d(printf("show attachment button called\n"));
info->shown = ~info->shown;
em_format_set_inline(info->puri.format, info->puri.part_id, info->shown);
}
-static void
-efhd_attachment_button_show(GtkWidget *w, void *data)
-{
- efhd_attachment_show(NULL, NULL, data);
-}
-
-static EPopupItem efhd_menu_items[] = {
- { E_POPUP_BAR, "05.display", },
- { E_POPUP_ITEM, "05.display.00", N_("_View Inline"), efhd_attachment_show },
- { E_POPUP_ITEM, "05.display.00", N_("_Hide"), efhd_attachment_show },
+static EMPopupItem efhd_menu_items[] = {
+ { EM_POPUP_BAR, "05.display", },
+ { EM_POPUP_ITEM, "05.display.00", N_("_View Inline"), G_CALLBACK(efhd_attachment_show) },
+ { EM_POPUP_ITEM, "05.display.00", N_("_Hide"), G_CALLBACK(efhd_attachment_show) },
};
static void
-efhd_menu_items_free(EPopup *ep, GSList *items, void *data)
-{
- g_slist_free(items);
-}
-
-static void
efhd_popup_place_widget(GtkMenu *menu, int *x, int *y, gboolean *push_in, gpointer user_data)
{
GtkWidget *w = user_data;
@@ -1118,8 +1080,8 @@ efhd_attachment_popup(GtkWidget *w, GdkEventButton *event, struct _attach_puri *
GtkMenu *menu;
GSList *menus = NULL;
EMPopup *emp;
- EMPopupTargetPart *target;
- EPopupItem *item;
+ EMPopupTarget *target;
+ EMPopupItem *item;
d(printf("attachment popup, button %d\n", event->button));
@@ -1128,29 +1090,23 @@ efhd_attachment_popup(GtkWidget *w, GdkEventButton *event, struct _attach_puri *
return FALSE;
}
- /** @HookPoint-EMPopup: Attachment Button Context Menu
- * @Id: org.gnome.evolution.mail.formathtmldisplay.popup
- * @Class: org.gnome.evolution.mail.popup:1.0
- * @Target: EMPopupTargetPart
- *
- * This is the drop-down menu shown when a user clicks on the down arrow
- * of the attachment button in inline mail content.
- */
- emp = em_popup_new("org.gnome.evolution.mail.formathtmldisplay.popup");
- target = em_popup_target_new_part(emp, info->puri.part, info->handle?info->handle->mime_type:NULL);
- target->target.widget = w;
+ emp = em_popup_new("com.ximian.mail.formathtmldisplay.popup.part");
+ target = em_popup_target_new_part(info->puri.part, info->handle?info->handle->mime_type:NULL);
+ target->widget = w;
/* add our local menus */
if (info->handle) {
/* show/hide menus, only if we have an inline handler */
+ efhd_menu_items[0].activate_data = info;
menus = g_slist_prepend(menus, &efhd_menu_items[0]);
item = &efhd_menu_items[info->shown?2:1];
+ item->activate_data = info;
menus = g_slist_prepend(menus, item);
}
- e_popup_add_items((EPopup *)emp, menus, NULL, efhd_menu_items_free, info);
+ em_popup_add_items(emp, menus, (GDestroyNotify)g_slist_free);
- menu = e_popup_create_menu_once((EPopup *)emp, (EPopupTarget *)target, 0);
+ menu = em_popup_create_menu_once(emp, target, target->mask, target->mask);
if (event)
gtk_menu_popup(menu, NULL, NULL, NULL, NULL, event->button, event->time);
else
@@ -1255,7 +1211,6 @@ efhd_attachment_button(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObje
{ NULL, 0, 0 },
{ "text/uri-list", 0, 1 },
};
- AtkObject *a11y;
/* FIXME: handle default shown case */
d(printf("adding attachment button/content\n"));
@@ -1269,7 +1224,7 @@ efhd_attachment_button(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObje
button = gtk_button_new();
if (info->handle)
- g_signal_connect(button, "clicked", G_CALLBACK(efhd_attachment_button_show), info);
+ g_signal_connect(button, "clicked", G_CALLBACK(efhd_attachment_show), info);
else {
gtk_widget_set_sensitive(button, FALSE);
GTK_WIDGET_UNSET_FLAGS(button, GTK_CAN_FOCUS);
@@ -1335,11 +1290,6 @@ efhd_attachment_button(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObje
button = gtk_button_new();
/*GTK_WIDGET_UNSET_FLAGS(button, GTK_CAN_FOCUS);*/
gtk_container_add((GtkContainer *)button, gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_NONE));
-
- a11y = gtk_widget_get_accessible (button);
- atk_object_set_name (a11y, _("Attachment Button"));
-
-
g_signal_connect(button, "button_press_event", G_CALLBACK(efhd_attachment_popup), info);
g_signal_connect(button, "popup_menu", G_CALLBACK(efhd_attachment_popup_menu), info);
g_signal_connect(button, "clicked", G_CALLBACK(efhd_attachment_popup_menu), info);
diff --git a/mail/em-format-html.c b/mail/em-format-html.c
index 6a473eb0df..b8699bbac1 100644
--- a/mail/em-format-html.c
+++ b/mail/em-format-html.c
@@ -31,9 +31,9 @@
#include <fcntl.h>
#include <ctype.h>
-#include <libedataserver/e-iconv.h>
-#include <libedataserver/e-util.h> /* for e_utf8_strftime, what about e_time_format_time? */
-#include <libedataserver/e-time-utils.h>
+#include <gal/util/e-iconv.h>
+#include <gal/util/e-util.h> /* for e_utf8_strftime, what about e_time_format_time? */
+#include "e-util/e-time-utils.h"
#include "e-util/e-icon-factory.h"
#include <gtkhtml/gtkhtml.h>
@@ -41,7 +41,9 @@
#include <gtkhtml/gtkhtml-stream.h>
#include <gtkhtml/htmlengine.h>
-#include <libgnome/gnome-i18n.h>
+#include <libgnomevfs/gnome-vfs-utils.h>
+#include <libgnomevfs/gnome-vfs-mime-utils.h>
+#include <libgnomevfs/gnome-vfs-mime-handlers.h>
#include <camel/camel-mime-message.h>
#include <camel/camel-stream.h>
@@ -59,7 +61,7 @@
#include <camel/camel-data-cache.h>
#include <camel/camel-file-utils.h>
-#include <libedataserver/e-msgport.h>
+#include <e-util/e-msgport.h>
#include "mail-component.h"
#include "mail-config.h"
@@ -658,7 +660,9 @@ efh_text_plain(EMFormatHTML *efh, CamelStream *stream, CamelMimePart *part, EMFo
struct _EMFormatHTMLCache *efhc;
camel_stream_printf (stream,
- "<div style=\"border: solid #%06x 1px; background-color: #%06x; padding: 10px;\">\n",
+ "<table bgcolor=\"#%06x\" cellspacing=0 cellpadding=1 width=100%%><tr><td>\n"
+ "<table bgcolor=\"#%06x\" cellspacing=0 cellpadding=0 width=100%%><tr><td>\n"
+ "<table cellspacing=0 cellpadding=10><td><tr>\n",
efh->frame_colour & 0xffffff, efh->content_colour & 0xffffff);
flags = efh->text_html_flags;
@@ -740,7 +744,10 @@ efh_text_plain(EMFormatHTML *efh, CamelStream *stream, CamelMimePart *part, EMFo
}
camel_object_unref(filtered_stream);
- camel_stream_write_string(stream, "</div>\n");
+ camel_stream_write_string(stream,
+ "</td></tr></table>\n"
+ "</td></tr></table>\n"
+ "</td></tr></table>\n");
}
static void
@@ -766,13 +773,18 @@ efh_text_enriched(EMFormatHTML *efh, CamelStream *stream, CamelMimePart *part, E
camel_object_unref(enriched);
camel_stream_printf (stream,
- "<div style=\"border: solid #%06x 1px; background-color: #%06x; padding: 10px;\">\n",
+ "<table bgcolor=\"#%06x\" cellspacing=0 cellpadding=1 width=100%%><tr><td>\n"
+ "<table bgcolor=\"#%06x\" cellspacing=0 cellpadding=0 width=100%%><tr><td>\n"
+ "<table cellspacing=0 cellpadding=10><td><tr>\n",
efh->frame_colour & 0xffffff, efh->content_colour & 0xffffff);
em_format_format_text((EMFormat *)efh, (CamelStream *)filtered_stream, dw);
camel_object_unref(filtered_stream);
- camel_stream_write_string(stream, "</div>");
+ camel_stream_write_string(stream,
+ "</td></tr></table>\n"
+ "</td></tr></table>\n"
+ "</td></tr></table>\n");
}
static void
@@ -789,7 +801,8 @@ efh_text_html(EMFormatHTML *efh, CamelStream *stream, CamelMimePart *part, EMFor
char *cid = NULL;
camel_stream_printf (stream,
- "<div style=\"border: solid #%06x 1px; background-color: #%06x;\">\n"
+ "<table bgcolor=\"#%06x\" cellspacing=0 cellpadding=1 width=100%%><tr><td>\n"
+ "<table bgcolor=\"#%06x\" cellspacing=0 cellpadding=0 width=100%%><tr><td>\n"
"<!-- text/html -->\n",
efh->frame_colour & 0xffffff, efh->content_colour & 0xffffff);
@@ -820,7 +833,8 @@ efh_text_html(EMFormatHTML *efh, CamelStream *stream, CamelMimePart *part, EMFor
d(printf("adding iframe, location %s\n", cid));
camel_stream_printf(stream,
"<iframe src=\"%s\" frameborder=0 scrolling=no>could not get %s</iframe>\n"
- "</div>\n",
+ "</td></tr></table>\n"
+ "</td></tr></table>\n",
cid, cid);
g_free(cid);
}
@@ -924,7 +938,9 @@ efh_message_deliverystatus(EMFormatHTML *efh, CamelStream *stream, CamelMimePart
/* Yuck, this is copied from efh_text_plain */
camel_stream_printf (stream,
- "<div style=\"border: solid #%06x 1px; background-color: #%06x; padding: 10px;\">\n",
+ "<table bgcolor=\"#%06x\" cellspacing=0 cellpadding=1 width=100%%><tr><td>\n"
+ "<table bgcolor=\"#%06x\" cellspacing=0 cellpadding=0 width=100%%><tr><td>\n"
+ "<table cellspacing=0 cellpadding=10><td><tr>\n",
efh->frame_colour & 0xffffff, efh->content_colour & 0xffffff);
filtered_stream = camel_stream_filter_new_with_stream(stream);
@@ -937,7 +953,10 @@ efh_message_deliverystatus(EMFormatHTML *efh, CamelStream *stream, CamelMimePart
camel_stream_flush((CamelStream *)filtered_stream);
camel_stream_write_string(stream, "</tt>\n");
- camel_stream_write_string(stream, "</div>");
+ camel_stream_write_string(stream,
+ "</td></tr></table>\n"
+ "</td></tr></table>\n"
+ "</td></tr></table>\n");
}
static void
@@ -1401,9 +1420,9 @@ efh_format_text_header (EMFormatHTML *emfh, CamelStream *stream, const char *lab
fmt = "<tr><td>%s: %s</td></tr>";
} else {
if (flags & EM_FORMAT_HEADER_BOLD)
- fmt = "<tr><th align=\"right\" valign=\"top\" nowrap>%s:<b>&nbsp;</b></th><td>%s</td></tr>";
+ fmt = "<tr><th align=\"right\" valign=\"top\">%s:<b>&nbsp;</b></th><td>%s</td></tr>";
else
- fmt = "<tr><td align=\"right\" valign=\"top\" nowrap>%s:<b>&nbsp;</b></td><td>%s</td></tr>";
+ fmt = "<tr><td align=\"right\" valign=\"top\">%s:<b>&nbsp;</b></td><td>%s</td></tr>";
}
}
diff --git a/mail/em-format.c b/mail/em-format.c
index e331a03493..0ad9057b81 100644
--- a/mail/em-format.c
+++ b/mail/em-format.c
@@ -31,9 +31,8 @@
#include <libgnomevfs/gnome-vfs-mime.h>
#include <libgnomevfs/gnome-vfs-mime-utils.h>
#include <libgnomevfs/gnome-vfs-mime-handlers.h>
-#include <libgnome/gnome-i18n.h>
-#include <libedataserver/e-msgport.h>
+#include <e-util/e-msgport.h>
#include <camel/camel-url.h>
#include <camel/camel-stream.h>
#include <camel/camel-stream-mem.h>
@@ -202,10 +201,8 @@ em_format_get_type(void)
* @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.
+ * Add a mime type handler to this class. This is only used by implementing
+ * classes.
*
* When a mime type described by @info is encountered, the callback will
* be invoked. Note that @info may be extended by sub-classes if
@@ -216,39 +213,26 @@ em_format_get_type(void)
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);
+ /* FIXME: do we care? This is really gui stuff */
+ /*
+ if (info->applications == NULL)
+ info->applications = gnome_vfs_mime_get_short_list_applications(info->mime_type);*/
}
+
/**
* em_format_class_remove_handler:
- * @emfc:
- * @info:
- *
- * Remove a handler. @info must be a value which was previously
- * added.
+ * @emfc: EMFormatClass
+ * @mime_type: mime-type of handler to remove
+ *
+ * Remove a mime type handler from this class. This is only used by
+ * implementing classes.
**/
void
-em_format_class_remove_handler(EMFormatClass *emfc, EMFormatHandler *info)
+em_format_class_remove_handler (EMFormatClass *emfc, const char *mime_type)
{
- 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);
- 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;
- }
+ g_hash_table_remove (emfc->type_handlers, mime_type);
}
/**
@@ -328,8 +312,6 @@ em_format_add_puri(EMFormat *emf, size_t size, const char *cid, CamelMimePart *p
EMFormatPURI *puri;
const char *tmp;
- d(printf("adding puri for part: %s\n", emf->part_id->str));
-
g_assert(size >= sizeof(*puri));
puri = g_malloc0(size);
@@ -485,8 +467,6 @@ emf_clear_puri_node(struct _EMFormatPURITree *node)
pw = (EMFormatPURI *)node->uri_list.head;
pn = pw->next;
while (pn) {
- if (pw->free)
- pw->free(pw);
g_free(pw->uri);
g_free(pw->cid);
g_free(pw->part_id);
@@ -1381,7 +1361,7 @@ emf_multipart_related(EMFormat *emf, CamelStream *stream, CamelMimePart *part, c
g_string_printf(emf->part_id, "%s", puri->part_id);
em_format_part(emf, stream, puri->part);
} else
- d(printf("unreferenced uri generated by format code: %s\n", puri->uri?puri->uri:puri->cid));
+ printf("unreferenced uri generated by format code: %s\n", puri->uri?puri->uri:puri->cid);
}
puri = purin;
purin = purin->next;
diff --git a/mail/em-format.h b/mail/em-format.h
index a822809bc1..4cdfbdd66a 100644
--- a/mail/em-format.h
+++ b/mail/em-format.h
@@ -28,7 +28,7 @@
#define _EM_FORMAT_H
#include <glib-object.h>
-#include "libedataserver/e-msgport.h"
+#include "e-util/e-msgport.h"
struct _CamelStream;
struct _CamelMimePart;
@@ -53,70 +53,25 @@ typedef enum _em_format_mode_t {
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.
- *
- **/
+/* can be subclassed/extended ... */
struct _EMFormatHandler {
char *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,
+ GList *applications; /* gnome vfs short-list of applications, do we care? */
};
+/* inline by default */
+#define EM_FORMAT_HANDLER_INLINE (1<<0)
+/* inline by default, and override content-disposition always */
+#define EM_FORMAT_HANDLER_INLINE_DISPOSITION (1<<1)
typedef struct _EMFormatPURI EMFormatPURI;
typedef void (*EMFormatPURIFunc)(EMFormat *md, struct _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;
+ struct _EMFormatPURI *next, *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 */
@@ -129,23 +84,9 @@ struct _EMFormatPURI {
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.
- **/
+/* used to stack pending uri's for visibility (multipart/related) */
struct _EMFormatPURITree {
- struct _EMFormatPURITree *next;
- struct _EMFormatPURITree *prev;
- struct _EMFormatPURITree *parent;
+ struct _EMFormatPURITree *next, *prev, *parent;
EDList uri_list;
EDList children;
@@ -161,34 +102,6 @@ struct _EMFormatHeader {
#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;
@@ -287,7 +200,7 @@ char *em_format_describe_part(struct _CamelMimePart *part, const char *mimetype)
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);
+void em_format_class_remove_handler (EMFormatClass *emfc, const char *mime_type);
#define em_format_find_handler(emf, type) ((EMFormatClass *)G_OBJECT_GET_CLASS(emf))->find_handler((emf), (type))
const EMFormatHandler *em_format_fallback_handler(EMFormat *emf, const char *mime_type);
diff --git a/mail/em-junk-filter.c b/mail/em-junk-filter.c
index 78fe042fdb..5885e5d0d6 100644
--- a/mail/em-junk-filter.c
+++ b/mail/em-junk-filter.c
@@ -33,37 +33,26 @@
#include <signal.h>
#include <string.h>
#include <pthread.h>
-#include <signal.h>
-#include <time.h>
-#include <camel/camel-debug.h>
#include <camel/camel-file-utils.h>
#include <camel/camel-data-wrapper.h>
#include <camel/camel-stream-fs.h>
-#include <camel/camel-stream-mem.h>
-#include <camel/camel-i18n.h>
-#include <e-util/e-mktemp.h>
#include "mail-session.h"
#include "em-junk-filter.h"
#include <gconf/gconf-client.h>
-#define d(x) (camel_debug("junk")?(x):0)
+#define d(x) x
static pthread_mutex_t em_junk_sa_init_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t em_junk_sa_report_lock = PTHREAD_MUTEX_INITIALIZER;
-static pthread_mutex_t em_junk_sa_preferred_socket_path_lock = PTHREAD_MUTEX_INITIALIZER;
-static pthread_mutex_t em_junk_sa_spamd_restart_lock = PTHREAD_MUTEX_INITIALIZER;
static const char *em_junk_sa_get_name (void);
static gboolean em_junk_sa_check_junk (CamelMimeMessage *msg);
static void em_junk_sa_report_junk (CamelMimeMessage *msg);
static void em_junk_sa_report_notjunk (CamelMimeMessage *msg);
static void em_junk_sa_commit_reports (void);
-static void em_junk_sa_init (void);
-static void em_junk_sa_finalize (void);
-static void em_junk_sa_kill_spamd (void);
static EMJunkPlugin spam_assassin_plugin = {
{
@@ -73,7 +62,6 @@ static EMJunkPlugin spam_assassin_plugin = {
em_junk_sa_report_junk,
em_junk_sa_report_notjunk,
em_junk_sa_commit_reports,
- em_junk_sa_init,
},
NULL,
NULL
@@ -83,24 +71,14 @@ static gboolean em_junk_sa_tested = FALSE;
static gboolean em_junk_sa_spamd_tested = FALSE;
static gboolean em_junk_sa_use_spamc = FALSE;
static gboolean em_junk_sa_available = FALSE;
-static gboolean em_junk_sa_system_spamd_available = FALSE;
-static gboolean em_junk_sa_new_daemon_started = FALSE;
-static char *em_junk_sa_socket_path = NULL;
-static char *em_junk_sa_spamd_pidfile = NULL;
+static int em_junk_sa_spamd_port = -1;
static char *em_junk_sa_spamc_binary = NULL;
static GConfClient *em_junk_sa_gconf = NULL;
/* volatile so not cached between threads */
static volatile gboolean em_junk_sa_local_only;
static volatile gboolean em_junk_sa_use_daemon;
-static char * em_junk_sa_preferred_socket_path;
-
-static char *em_junk_sa_spamc_binaries [3] = {"spamc", "/usr/sbin/spamc", NULL};
-static char *em_junk_sa_spamd_binaries [3] = {"spamd", "/usr/sbin/spamd", NULL};
-
-#define SPAMD_RESTARTS_SIZE 8
-static time_t em_junk_sa_spamd_restarts [SPAMD_RESTARTS_SIZE] = {0, 0, 0, 0, 0, 0, 0, 0};
-static int em_junk_sa_spamd_restarts_count = 0;
+static volatile int em_junk_sa_daemon_port;
char *em_junk_sa_spamc_gconf_binary = NULL;
char *em_junk_sa_spamd_gconf_binary = NULL;
@@ -112,23 +90,23 @@ em_junk_sa_get_name (void)
}
static int
-pipe_to_sa_full (CamelMimeMessage *msg, const char *in, char **argv, int rv_err, int wait_for_termination, GByteArray *output_buffer)
+pipe_to_sa_with_error (CamelMimeMessage *msg, const char *in, char **argv, int rv_err)
{
- int result, status, errnosav, fds[2], out_fds[2];
+ int result, status, errnosav, fds[2];
CamelStream *stream;
char *program;
pid_t pid;
-
- if (camel_debug_start ("junk")) {
+#if d(!)0
+ {
int i;
printf ("pipe_to_sa ");
for (i = 0; argv[i]; i++)
printf ("%s ", argv[i]);
printf ("\n");
- camel_debug_end ();
}
+#endif
program = g_find_program_in_path (argv [0]);
if (program == NULL) {
@@ -144,13 +122,6 @@ pipe_to_sa_full (CamelMimeMessage *msg, const char *in, char **argv, int rv_err,
return rv_err;
}
- if (output_buffer && pipe (out_fds) == -1) {
- errnosav = errno;
- d(printf ("failed to create a pipe (for use with spamassassin: %s\n", strerror (errno)));
- errno = errnosav;
- return rv_err;
- }
-
if (!(pid = fork ())) {
/* child process */
int maxfd, fd, nullfd;
@@ -158,14 +129,10 @@ pipe_to_sa_full (CamelMimeMessage *msg, const char *in, char **argv, int rv_err,
nullfd = open ("/dev/null", O_WRONLY);
if (dup2 (fds[0], STDIN_FILENO) == -1 ||
- dup2 (nullfd, STDERR_FILENO) == -1 ||
- (output_buffer == NULL && dup2 (nullfd, STDOUT_FILENO) == -1) ||
- (output_buffer != NULL && dup2 (out_fds[1], STDOUT_FILENO) == -1))
+ dup2 (nullfd, STDOUT_FILENO) == -1 ||
+ dup2 (nullfd, STDERR_FILENO) == -1)
_exit (rv_err & 0377);
- close (fds [0]);
- if (output_buffer)
- close (out_fds [1]);
-
+
setsid ();
maxfd = sysconf (_SC_OPEN_MAX);
@@ -184,8 +151,6 @@ pipe_to_sa_full (CamelMimeMessage *msg, const char *in, char **argv, int rv_err,
/* parent process */
close (fds[0]);
- if (output_buffer)
- close (out_fds [1]);
if (msg) {
stream = camel_stream_fs_new_with_fd (fds[1]);
@@ -198,92 +163,54 @@ pipe_to_sa_full (CamelMimeMessage *msg, const char *in, char **argv, int rv_err,
camel_write (fds[1], in, strlen (in));
close (fds[1]);
}
-
- if (output_buffer) {
- CamelStreamMem *memstream;
-
- stream = camel_stream_fs_new_with_fd (out_fds[0]);
-
- memstream = (CamelStreamMem *) camel_stream_mem_new ();
- camel_stream_mem_set_byte_array (memstream, output_buffer);
-
- camel_stream_write_to_stream (stream, (CamelStream *) memstream);
- camel_object_unref (stream);
- g_byte_array_append (output_buffer, "", 1);
-
- d(printf ("child process output: %s len: %d\n", output_buffer->data, output_buffer->len));
- }
- if (wait_for_termination) {
- d(printf ("wait for child %d termination\n", pid));
- result = waitpid (pid, &status, 0);
+ result = waitpid (pid, &status, 0);
- d(printf ("child %d terminated with result %d status %d exited %d exitstatus %d\n", pid, result, status, WIFEXITED (status), WEXITSTATUS (status)));
-
- if (result == -1 && errno == EINTR) {
- /* child process is hanging... */
- kill (pid, SIGTERM);
+ 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);
- if (result == 0) {
- /* ...still hanging, set phasers to KILL */
- kill (pid, SIGKILL);
- sleep (1);
- result = waitpid (pid, &status, WNOHANG);
- }
}
+ }
- if (result != -1 && WIFEXITED (status))
- return WEXITSTATUS (status);
- else
- return rv_err;
- } else
- return 0;
+ if (result != -1 && WIFEXITED (status))
+ return WEXITSTATUS (status);
+ else
+ return rv_err;
}
static int
pipe_to_sa (CamelMimeMessage *msg, const char *in, char **argv)
{
- return pipe_to_sa_full (msg, in, argv, -1, 1, NULL);
-}
-
-static char *
-em_junk_sa_get_socket_path ()
-{
- if (em_junk_sa_preferred_socket_path)
- return em_junk_sa_preferred_socket_path;
- else
- return em_junk_sa_socket_path;
+ return pipe_to_sa_with_error (msg, in, argv, -1);
}
static gboolean
-em_junk_sa_test_spamd_running (char *binary, gboolean system)
+em_junk_sa_test_spamd_running (char *binary, int port)
{
- char *argv[5];
+ char port_buf[12], *argv[5];
int i = 0;
- gboolean rv;
-
- pthread_mutex_lock (&em_junk_sa_preferred_socket_path_lock);
-
- d(fprintf (stderr, "test if spamd is running (system %d) or using socket path %s\n", system, em_junk_sa_get_socket_path ()));
+
+ d(fprintf (stderr, "test if spamd is running (port %d) using %s\n", port, binary));
argv[i++] = binary;
argv[i++] = "-x";
- if (!system) {
- argv[i++] = "-U";
- argv[i++] = em_junk_sa_get_socket_path ();
+ if (port > 0) {
+ sprintf (port_buf, "%d", port);
+ argv[i++] = "-p";
+ argv[i++] = port_buf;
}
argv[i] = NULL;
- rv = pipe_to_sa (NULL, "From test@127.0.0.1", argv) == 0;
-
- d(fprintf (stderr, "result: %d (%s)\n", rv, rv ? "success" : "failed"));
-
- pthread_mutex_unlock (&em_junk_sa_preferred_socket_path_lock);
-
- return rv;
+ return pipe_to_sa (NULL, "From test@127.0.0.1", argv) == 0;
}
static void
@@ -306,93 +233,37 @@ em_junk_sa_test_spamassassin (void)
#define MAX_SPAMD_PORTS 1
static gboolean
-em_junk_sa_run_spamd (char *binary)
+em_junk_sa_run_spamd (char *binary, int *port)
{
- char *argv[8];
- int i;
- gboolean rv = FALSE;
-
- pthread_mutex_lock (&em_junk_sa_preferred_socket_path_lock);
+ char *argv[6];
+ char port_buf[12];
+ int i, p = em_junk_sa_daemon_port;
d(fprintf (stderr, "looks like spamd is not running\n"));
i = 0;
argv[i++] = binary;
- argv[i++] = "--socketpath";
- argv[i++] = em_junk_sa_get_socket_path ();
+ argv[i++] = "--port";
+ argv[i++] = port_buf;
if (em_junk_sa_local_only)
argv[i++] = "--local";
- //argv[i++] = "--daemonize";
- argv[i++] = "--pidfile";
- argv[i++] = em_junk_sa_spamd_pidfile;
+ argv[i++] = "--daemonize";
argv[i] = NULL;
-
- d(fprintf (stderr, "trying to run %s with socket path %s\n", binary, em_junk_sa_get_socket_path ()));
+
+ for (i = 0; i < MAX_SPAMD_PORTS; i++, p++) {
+ d(fprintf (stderr, "trying to run %s at port %d\n", binary, p));
- if (!pipe_to_sa_full (NULL, NULL, argv, -1, 0, NULL)) {
- int i;
- struct timespec time_req;
- struct stat stat_buf;
-
- d(fprintf (stderr, "success\n"));
- d(fprintf (stderr, "waiting for spamd to come up\n"));
-
- time_req.tv_sec = 0;
- time_req.tv_nsec = 50000000;
-
- for (i = 0; i < 100; i ++) {
- if (stat (em_junk_sa_get_socket_path (), &stat_buf) == 0) {
- d(fprintf (stderr, "socket created\n"));
- break;
- }
- nanosleep (&time_req, NULL);
+ snprintf (port_buf, 11, "%d", p);
+ if (!pipe_to_sa (NULL, NULL, argv)) {
+ d(fprintf (stderr, "success at port %d\n", p));
+ *port = p;
+ return TRUE;
}
- d(fprintf (stderr, "waiting is over (after %dms)\n", 50*i));
-
- rv = TRUE;
}
- pthread_mutex_unlock (&em_junk_sa_preferred_socket_path_lock);
-
- return rv;
-}
-
-static void
-em_junk_sa_start_own_daemon ()
-{
- int b;
-
- em_junk_sa_new_daemon_started = FALSE;
-
- em_junk_sa_socket_path = e_mktemp ("spamd-socket-path-XXXXXX");
- em_junk_sa_spamd_pidfile = e_mktemp ("spamd-pid-file-XXXXXX");
-
- for (b = 0; em_junk_sa_spamd_binaries [b]; b ++) {
- em_junk_sa_use_spamc = em_junk_sa_run_spamd (em_junk_sa_spamd_binaries [b]);
- if (em_junk_sa_use_spamc) {
- em_junk_sa_new_daemon_started = TRUE;
- break;
- }
- }
-}
-
-static void
-em_junk_sa_find_spamc ()
-{
- if (em_junk_sa_use_spamc && em_junk_sa_new_daemon_started) {
- int b;
-
- em_junk_sa_use_spamc = FALSE;
- for (b = 0; em_junk_sa_spamc_binaries [b]; b ++) {
- em_junk_sa_spamc_binary = em_junk_sa_spamc_binaries [b];
- if (em_junk_sa_test_spamd_running (em_junk_sa_spamc_binary, FALSE)) {
- em_junk_sa_use_spamc = TRUE;
- break;
- }
- }
- }
+ return FALSE;
}
static void
@@ -401,17 +272,20 @@ em_junk_sa_test_spamd (void)
char *argv[4];
int i, b;
gboolean try_system_spamd = TRUE;
+ gboolean new_daemon_started = FALSE;
+ char *spamc_binaries [3] = {"spamc", "/usr/sbin/spamc", NULL};
+ char *spamd_binaries [3] = {"spamd", "/usr/sbin/spamd", NULL};
if (em_junk_sa_spamc_gconf_binary) {
- em_junk_sa_spamc_binaries [0] = em_junk_sa_spamc_gconf_binary;
- em_junk_sa_spamc_binaries [1] = NULL;
+ spamc_binaries [0] = em_junk_sa_spamc_gconf_binary;
+ spamc_binaries [1] = NULL;
}
-
+
if (em_junk_sa_spamd_gconf_binary) {
- em_junk_sa_spamd_binaries [0] = em_junk_sa_spamd_gconf_binary;
- em_junk_sa_spamd_binaries [1] = NULL;
+ spamd_binaries [0] = em_junk_sa_spamd_gconf_binary;
+ spamd_binaries [1] = NULL;
try_system_spamd = FALSE;
- }
+ }
em_junk_sa_use_spamc = FALSE;
@@ -430,36 +304,55 @@ em_junk_sa_test_spamd (void)
/* try to use sytem spamd first */
if (try_system_spamd) {
- for (b = 0; em_junk_sa_spamc_binaries [b]; b ++) {
- em_junk_sa_spamc_binary = em_junk_sa_spamc_binaries [b];
- if (em_junk_sa_test_spamd_running (em_junk_sa_spamc_binary, TRUE)) {
+ for (b = 0; spamc_binaries [b]; b ++) {
+ em_junk_sa_spamc_binary = spamc_binaries [b];
+ if (em_junk_sa_test_spamd_running (em_junk_sa_spamc_binary, -1)) {
em_junk_sa_use_spamc = TRUE;
- em_junk_sa_system_spamd_available = TRUE;
+ em_junk_sa_spamd_port = -1;
break;
}
}
}
- /* if there's no system spamd running, try to use user one with user specified socket */
- if (!em_junk_sa_use_spamc && em_junk_sa_preferred_socket_path) {
- for (b = 0; em_junk_sa_spamc_binaries [b]; b ++) {
- em_junk_sa_spamc_binary = em_junk_sa_spamc_binaries [b];
- if (em_junk_sa_test_spamd_running (em_junk_sa_spamc_binary, FALSE)) {
- em_junk_sa_use_spamc = TRUE;
- em_junk_sa_system_spamd_available = FALSE;
- break;
+ /* if there's no system spamd running, try to use user one on evo spamd port */
+ if (!em_junk_sa_use_spamc) {
+ int port = em_junk_sa_daemon_port;
+
+ for (i = 0; i < MAX_SPAMD_PORTS; i ++, port ++) {
+ for (b = 0; spamc_binaries [b]; b ++) {
+ em_junk_sa_spamc_binary = spamc_binaries [b];
+ if (em_junk_sa_test_spamd_running (em_junk_sa_spamc_binary, port)) {
+ em_junk_sa_use_spamc = TRUE;
+ em_junk_sa_spamd_port = port;
+ break;
+ }
}
}
}
/* unsuccessful? try to run one ourselfs */
if (!em_junk_sa_use_spamc)
- em_junk_sa_start_own_daemon ();
-
+ for (b = 0; spamd_binaries [b]; b ++) {
+ em_junk_sa_use_spamc = em_junk_sa_run_spamd (spamd_binaries [b], &em_junk_sa_spamd_port);
+ if (em_junk_sa_use_spamc) {
+ new_daemon_started = TRUE;
+ break;
+ }
+ }
+
/* new daemon started => let find spamc binary */
- em_junk_sa_find_spamc ();
+ if (em_junk_sa_use_spamc && new_daemon_started) {
+ em_junk_sa_use_spamc = FALSE;
+ for (b = 0; spamc_binaries [b]; b ++) {
+ em_junk_sa_spamc_binary = spamc_binaries [b];
+ if (em_junk_sa_test_spamd_running (em_junk_sa_spamc_binary, em_junk_sa_spamd_port)) {
+ em_junk_sa_use_spamc = TRUE;
+ break;
+ }
+ }
+ }
- d(fprintf (stderr, "use spamd: %s\n", em_junk_sa_use_spamc ? "yes" : "no"));
+ d(fprintf (stderr, "use spamd %d at port %d with %s\n", em_junk_sa_use_spamc, em_junk_sa_spamd_port, em_junk_sa_spamc_binary));
em_junk_sa_spamd_tested = TRUE;
}
@@ -481,84 +374,23 @@ em_junk_sa_is_available (void)
}
static gboolean
-em_junk_sa_check_respawn_too_fast ()
-{
- time_t time_now = time (NULL);
- gboolean rv;
-
- pthread_mutex_lock (&em_junk_sa_spamd_restart_lock);
-
- if (em_junk_sa_spamd_restarts_count >= SPAMD_RESTARTS_SIZE) {
- /* all restarts in last 5 minutes */
- rv = (time_now - em_junk_sa_spamd_restarts [em_junk_sa_spamd_restarts_count % SPAMD_RESTARTS_SIZE] < 5*60);
- } else
- rv = FALSE;
-
- em_junk_sa_spamd_restarts [em_junk_sa_spamd_restarts_count % SPAMD_RESTARTS_SIZE] = time_now;
- em_junk_sa_spamd_restarts_count ++;
-
- pthread_mutex_unlock (&em_junk_sa_spamd_restart_lock);
-
- d(printf ("em_junk_sa_check_respawn_too_fast: %d\n", rv));
-
- return rv;
-}
-
-static gboolean
-em_junk_sa_respawn_spamd ()
-{
- d(printf ("em_junk_sa_respawn_spamd\n"));
- if (em_junk_sa_test_spamd_running (em_junk_sa_spamc_binary, em_junk_sa_system_spamd_available)) {
- /* false alert */
- d(printf ("false alert, spamd still running\n"));
-
- return FALSE;
- }
-
- d(printf ("going to kill old spamd and start new one\n"));
- em_junk_sa_kill_spamd ();
-
- if (em_junk_sa_check_respawn_too_fast ()) {
- g_warning ("respawning of spamd too fast => fallback to use spamassassin directly");
-
- em_junk_sa_use_spamc = em_junk_sa_use_daemon = FALSE;
- return FALSE;
- }
-
- em_junk_sa_start_own_daemon ();
- em_junk_sa_find_spamc ();
-
- d(printf ("%s\n", em_junk_sa_use_spamc ? "success" : "failed"));
-
- return em_junk_sa_use_spamc;
-}
-
-static gboolean
em_junk_sa_check_junk (CamelMimeMessage *msg)
{
- GByteArray *out = NULL;
- char *argv[7], *to_free = NULL;
- int i = 0, socket_i;
- gboolean rv;
-
+ char *argv[5], buf[12];
+ int i = 0;
+
d(fprintf (stderr, "em_junk_sa_check_junk\n"));
if (!em_junk_sa_is_available ())
return FALSE;
-
+
if (em_junk_sa_use_spamc && em_junk_sa_use_daemon) {
- out = g_byte_array_new ();
argv[i++] = em_junk_sa_spamc_binary;
argv[i++] = "-c";
- argv[i++] = "-t";
- argv[i++] = "60";
- if (!em_junk_sa_system_spamd_available) {
- argv[i++] = "-U";
-
- pthread_mutex_lock (&em_junk_sa_preferred_socket_path_lock);
- socket_i = i;
- argv[i++] = to_free = g_strdup (em_junk_sa_get_socket_path ());
- pthread_mutex_unlock (&em_junk_sa_preferred_socket_path_lock);
+ if (em_junk_sa_spamd_port != -1) {
+ sprintf (buf, "%d", em_junk_sa_spamd_port);
+ argv[i++] = "-p";
+ argv[i++] = buf;
}
} else {
argv [i++] = "spamassassin";
@@ -569,32 +401,7 @@ em_junk_sa_check_junk (CamelMimeMessage *msg)
argv[i] = NULL;
- rv = pipe_to_sa_full (msg, NULL, argv, 0, 1, out) != 0;
-
- if (!rv && out && !strcmp (out->data, "0/0\n")) {
- /* an error occured */
- if (em_junk_sa_respawn_spamd ()) {
- g_byte_array_set_size (out, 0);
-
- pthread_mutex_lock (&em_junk_sa_preferred_socket_path_lock);
- g_free (to_free);
- argv [socket_i] = to_free = g_strdup (em_junk_sa_get_socket_path ());
- pthread_mutex_unlock (&em_junk_sa_preferred_socket_path_lock);
-
- rv = pipe_to_sa_full (msg, NULL, argv, 0, 1, out) != 0;
- } else if (!em_junk_sa_use_spamc)
- /* in case respawning were too fast we fallback to spamassassin */
- rv = em_junk_sa_check_junk (msg);
- }
-
- g_free (to_free);
-
- d(fprintf (stderr, "em_junk_sa_check_junk rv = %d\n", rv));
-
- if (out)
- g_byte_array_free (out, TRUE);
-
- return rv;
+ return pipe_to_sa_with_error (msg, NULL, argv, 0) != 0;
}
static void
@@ -685,23 +492,13 @@ em_junk_sa_setting_notify(GConfClient *gconf, guint cnxn_id, GConfEntry *entry,
em_junk_sa_local_only = gconf_value_get_bool(value);
else if (!strcmp(tkey, "use_daemon"))
em_junk_sa_use_daemon = gconf_value_get_bool(value);
- else if (!strcmp(tkey, "socket_path")) {
- pthread_mutex_lock (&em_junk_sa_preferred_socket_path_lock);
- g_free (em_junk_sa_preferred_socket_path);
- em_junk_sa_preferred_socket_path = g_strdup (gconf_value_get_string(value));
- pthread_mutex_unlock (&em_junk_sa_preferred_socket_path_lock);
- }
+ else if (!strcmp(tkey, "daemon_port"))
+ em_junk_sa_daemon_port = gconf_value_get_int(value);
}
const EMJunkPlugin *
em_junk_filter_get_plugin (void)
{
- return &spam_assassin_plugin;
-}
-
-static void
-em_junk_sa_init (void)
-{
pthread_mutex_lock (&em_junk_sa_init_lock);
if (!em_junk_sa_gconf) {
@@ -710,11 +507,7 @@ em_junk_sa_init (void)
em_junk_sa_local_only = gconf_client_get_bool (em_junk_sa_gconf, "/apps/evolution/mail/junk/sa/local_only", NULL);
em_junk_sa_use_daemon = gconf_client_get_bool (em_junk_sa_gconf, "/apps/evolution/mail/junk/sa/use_daemon", NULL);
-
- pthread_mutex_lock (&em_junk_sa_preferred_socket_path_lock);
- g_free (em_junk_sa_preferred_socket_path);
- em_junk_sa_preferred_socket_path = g_strdup (gconf_client_get_string (em_junk_sa_gconf, "/apps/evolution/mail/junk/sa/socket_path", NULL));
- pthread_mutex_unlock (&em_junk_sa_preferred_socket_path_lock);
+ em_junk_sa_daemon_port = gconf_client_get_int (em_junk_sa_gconf, "/apps/evolution/mail/junk/sa/daemon_port", NULL);
gconf_client_notify_add(em_junk_sa_gconf, "/apps/evolution/mail/junk/sa",
(GConfClientNotifyFunc)em_junk_sa_setting_notify,
@@ -726,47 +519,5 @@ em_junk_sa_init (void)
pthread_mutex_unlock (&em_junk_sa_init_lock);
- atexit (em_junk_sa_finalize);
-}
-
-static void
-em_junk_sa_kill_spamd (void)
-{
- pthread_mutex_lock (&em_junk_sa_preferred_socket_path_lock);
- g_free (em_junk_sa_preferred_socket_path);
- em_junk_sa_preferred_socket_path = NULL;
- pthread_mutex_unlock (&em_junk_sa_preferred_socket_path_lock);
-
- if (em_junk_sa_new_daemon_started) {
- int fd = open (em_junk_sa_spamd_pidfile, O_RDONLY);
-
- if (fd != -1) {
- char pid_str [16];
- int bytes;
-
- bytes = read (fd, pid_str, 15);
- if (bytes > 0) {
- int pid;
-
- pid_str [bytes] = 0;
- pid = atoi (pid_str);
-
- if (pid > 0) {
- kill (pid, SIGTERM);
- d(fprintf (stderr, "em_junk_sa_finalize send SIGTERM to daemon with pid %d\n", pid));
- waitpid (pid, NULL, 0);
- }
- }
-
- close (fd);
- }
- }
-}
-
-static void
-em_junk_sa_finalize (void)
-{
- d(fprintf (stderr, "em_junk_sa_finalize\n"));
-
- em_junk_sa_kill_spamd ();
+ return &spam_assassin_plugin;
}
diff --git a/mail/em-message-browser.c b/mail/em-message-browser.c
index caf93e7e41..4f3a2aaa2c 100644
--- a/mail/em-message-browser.c
+++ b/mail/em-message-browser.c
@@ -41,7 +41,6 @@
#include "em-format-html-display.h"
#include "em-message-browser.h"
-#include "em-menu.h"
#include "evolution-shell-component-utils.h" /* Pixmap stuff, sigh */
@@ -176,15 +175,6 @@ GtkWidget *em_message_browser_new(void)
{
EMMessageBrowser *emmb = g_object_new(em_message_browser_get_type(), 0);
- /** @HookPoint-EMMenu: Standalone Mssage View Menu
- * @Id: org.gnome.evolution.mail.messagebrowser
- * @Class: org.gnome.evolution.mail.bonobomenu:1.0
- * @Target: EMMenuTargetSelect
- *
- * The main menu of standalone message viewer.
- */
- ((EMFolderView *)emmb)->menu = em_menu_new("org.gnome.evolution.mail.messagebrowser");
-
return (GtkWidget *)emmb;
}
diff --git a/mail/em-migrate.c b/mail/em-migrate.c
index d2c9c1909c..87d200e2b8 100644
--- a/mail/em-migrate.c
+++ b/mail/em-migrate.c
@@ -42,7 +42,6 @@
#include <libgnome/gnome-config.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>
@@ -54,12 +53,13 @@
#include <libgnome/gnome-i18n.h>
#include <gal/util/e-util.h>
-#include <libedataserver/e-iconv.h>
+#include <gal/util/e-iconv.h>
#include <gal/util/e-xml-utils.h>
#include "e-util/e-bconf-map.h"
#include "e-util/e-account-list.h"
#include "e-util/e-signature-list.h"
+#include "e-util/e-path.h"
#include "widgets/misc/e-error.h"
#include "mail-config.h"
@@ -2315,84 +2315,6 @@ em_migrate_folder_view_settings_1_4 (const char *evolution_dir, CamelException *
return 0;
}
-#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 int
em_migrate_imap_cmeta_1_4(const char *evolution_dir, CamelException *ex)
{
@@ -2481,7 +2403,6 @@ em_migrate_1_4 (const char *evolution_dir, xmlDocPtr filters, xmlDocPtr vfolders
path = g_build_filename (evolution_dir, "mail", NULL);
camel_init (path, TRUE);
- camel_provider_init();
session = (EMMigrateSession *) em_migrate_session_new (path);
g_free (path);
diff --git a/mail/em-popup.c b/mail/em-popup.c
index bf3a017097..28e5121c51 100644
--- a/mail/em-popup.c
+++ b/mail/em-popup.c
@@ -40,10 +40,9 @@
#include <libgnome/gnome-url.h>
#include <libgnomevfs/gnome-vfs-mime.h>
-#include <libgnome/gnome-i18n.h>
#include "em-popup.h"
-#include "libedataserver/e-msgport.h"
+#include "e-util/e-msgport.h"
#include <e-util/e-icon-factory.h>
#include "em-utils.h"
#include "em-composer-utils.h"
@@ -64,69 +63,71 @@
#include <gal/util/e-util.h>
-static void emp_standard_menu_factory(EPopup *emp, void *data);
+static void emp_standard_menu_factory(EMPopup *emp, EMPopupTarget *target, void *data);
+
+struct _EMPopupFactory {
+ struct _EMPopupFactory *next, *prev;
+
+ char *menuid;
+ EMPopupFactoryFunc factory;
+ void *factory_data;
+};
+
+struct _menu_node {
+ struct _menu_node *next, *prev;
+
+ GSList *menu;
+ GDestroyNotify freefunc;
+};
+
+struct _EMPopupPrivate {
+ EDList menus;
+};
+
+static EDList emp_factories = E_DLIST_INITIALISER(emp_factories);
static GObjectClass *emp_parent;
static void
emp_init(GObject *o)
{
- /*EMPopup *emp = (EMPopup *)o; */
-}
+ EMPopup *emp = (EMPopup *)o;
+ struct _EMPopupPrivate *p;
-static void
-emp_finalise(GObject *o)
-{
- ((GObjectClass *)emp_parent)->finalize(o);
+ p = emp->priv = g_malloc0(sizeof(struct _EMPopupPrivate));
+
+ e_dlist_init(&p->menus);
}
static void
-emp_target_free(EPopup *ep, EPopupTarget *t)
+emp_finalise(GObject *o)
{
- switch (t->type) {
- case EM_POPUP_TARGET_SELECT: {
- EMPopupTargetSelect *s = (EMPopupTargetSelect *)t;
-
- if (s->folder)
- camel_object_unref(s->folder);
- g_free(s->uri);
- if (s->uids)
- em_utils_uids_free(s->uids);
- break; }
- case EM_POPUP_TARGET_URI: {
- EMPopupTargetURI *s = (EMPopupTargetURI *)t;
+ EMPopup *emp = (EMPopup *)o;
+ struct _EMPopupPrivate *p = emp->priv;
+ struct _menu_node *mnode, *nnode;
- g_free(s->uri);
- break; }
- case EM_POPUP_TARGET_PART: {
- EMPopupTargetPart *s = (EMPopupTargetPart *)t;
+ g_free(emp->menuid);
- camel_object_unref(s->part);
- g_free(s->mime_type);
- break; }
- case EM_POPUP_TARGET_FOLDER: {
- EMPopupTargetFolder *s = (EMPopupTargetFolder *)t;
-
- g_free(s->uri);
- break; }
- case EM_POPUP_TARGET_ATTACHMENTS: {
- EMPopupTargetAttachments *s = (EMPopupTargetAttachments *)t;
+ mnode = (struct _menu_node *)p->menus.head;
+ nnode = mnode->next;
+ while (nnode) {
+ if (mnode->freefunc)
+ mnode->freefunc(mnode->menu);
- g_slist_foreach(s->attachments, (GFunc)g_object_unref, NULL);
- g_slist_free(s->attachments);
- break; }
+ g_free(mnode);
+ mnode = nnode;
+ nnode = nnode->next;
}
- ((EPopupClass *)emp_parent)->target_free(ep, t);
+ g_free(p);
+
+ ((GObjectClass *)emp_parent)->finalize(o);
}
static void
emp_class_init(GObjectClass *klass)
{
klass->finalize = emp_finalise;
- ((EPopupClass *)klass)->target_free = emp_target_free;
-
- e_popup_class_add_factory((EPopupClass *)klass, NULL, emp_standard_menu_factory, NULL);
}
GType
@@ -143,8 +144,11 @@ em_popup_get_type(void)
sizeof(EMPopup), 0,
(GInstanceInitFunc)emp_init
};
- emp_parent = g_type_class_ref(e_popup_get_type());
- type = g_type_register_static(e_popup_get_type(), "EMPopup", &info, 0);
+ emp_parent = g_type_class_ref(G_TYPE_OBJECT);
+ type = g_type_register_static(G_TYPE_OBJECT, "EMPopup", &info, 0);
+
+ /* FIXME: this should probably sit somewhere in global setup */
+ em_popup_static_add_factory(NULL, (EMPopupFactoryFunc)emp_standard_menu_factory, NULL);
}
return type;
@@ -154,12 +158,291 @@ EMPopup *em_popup_new(const char *menuid)
{
EMPopup *emp = g_object_new(em_popup_get_type(), 0);
- e_popup_construct(&emp->popup, menuid);
+ emp->menuid = g_strdup(menuid);
return emp;
}
/**
+ * em_popup_add_items:
+ * @emp:
+ * @items:
+ * @freefunc:
+ *
+ * Add new EMPopupItems to the menu's. Any with the same path
+ * will override previously defined menu items, at menu building
+ * time.
+ **/
+void
+em_popup_add_items(EMPopup *emp, GSList *items, GDestroyNotify freefunc)
+{
+ struct _menu_node *node;
+
+ node = g_malloc(sizeof(*node));
+ node->menu = items;
+ node->freefunc = freefunc;
+ e_dlist_addtail(&emp->priv->menus, (EDListNode *)node);
+}
+
+/**
+ * em_popup_add_static_items:
+ * @emp:
+ * @target: Target of this menu.
+ *
+ * Will load up any matching menu items from an installed
+ * popup factory. If the menuid of @emp is NULL, then this
+ * has no effect.
+ *
+ **/
+void
+em_popup_add_static_items(EMPopup *emp, EMPopupTarget *target)
+{
+ struct _EMPopupFactory *f;
+
+ if (emp->menuid == NULL || target == NULL)
+ return;
+
+ /* setup the menu itself */
+ f = (struct _EMPopupFactory *)emp_factories.head;
+ while (f->next) {
+ if (f->menuid == NULL
+ || !strcmp(f->menuid, emp->menuid)) {
+ f->factory(emp, target, f->factory_data);
+ }
+ f = f->next;
+ }
+}
+
+static int
+emp_cmp(const void *ap, const void *bp)
+{
+ struct _EMPopupItem *a = *((void **)ap);
+ struct _EMPopupItem *b = *((void **)bp);
+
+ return strcmp(a->path, b->path);
+}
+
+/**
+ * em_popup_create:
+ * @menuitems:
+ * @hide_mask: used to hide menu items, not sure of it's utility,
+ * since you could just 'not add them' in the first place. Saves
+ * copying logic anyway.
+ * @disable_mask: used to disable menu items.
+ *
+ * TEMPORARY code to create a menu from a list of items.
+ *
+ * The menu items are merged based on their path element, and
+ * built into a menu tree.
+ *
+ * Return value:
+ **/
+GtkMenu *
+em_popup_create_menu(EMPopup *emp, guint32 hide_mask, guint32 disable_mask)
+{
+ struct _EMPopupPrivate *p = emp->priv;
+ struct _menu_node *mnode, *nnode;
+ GPtrArray *items = g_ptr_array_new();
+ GSList *l;
+ GString *ppath = g_string_new("");
+ GtkMenu *topmenu;
+ GHashTable *menu_hash = g_hash_table_new(g_str_hash, g_str_equal),
+ *group_hash = g_hash_table_new(g_str_hash, g_str_equal);
+ /*char *domain = NULL;*/
+ int i;
+
+ /* FIXME: need to override old ones with new names */
+ mnode = (struct _menu_node *)p->menus.head;
+ nnode = mnode->next;
+ while (nnode) {
+ for (l=mnode->menu; l; l = l->next)
+ g_ptr_array_add(items, l->data);
+ mnode = nnode;
+ nnode = nnode->next;
+ }
+
+ qsort(items->pdata, items->len, sizeof(items->pdata[0]), emp_cmp);
+
+ topmenu = (GtkMenu *)gtk_menu_new();
+ for (i=0;i<items->len;i++) {
+ GtkWidget *label;
+ struct _EMPopupItem *item = items->pdata[i];
+ GtkMenu *thismenu;
+ GtkMenuItem *menuitem;
+ char *tmp;
+
+ /* for bar's, the mask is exclusive or */
+ if (item->mask) {
+ if ((item->type & EM_POPUP_TYPE_MASK) == EM_POPUP_BAR) {
+ if ((item->mask & hide_mask) == item->mask)
+ continue;
+ } else if (item->mask & hide_mask)
+ continue;
+ }
+
+ g_string_truncate(ppath, 0);
+ tmp = strrchr(item->path, '/');
+ if (tmp) {
+ g_string_append_len(ppath, item->path, tmp-item->path);
+ thismenu = g_hash_table_lookup(menu_hash, ppath->str);
+ g_assert(thismenu != NULL);
+ } else {
+ thismenu = topmenu;
+ }
+
+ switch (item->type & EM_POPUP_TYPE_MASK) {
+ case EM_POPUP_ITEM:
+ if (item->image) {
+ GdkPixbuf *pixbuf;
+ GtkWidget *image;
+
+ pixbuf = e_icon_factory_get_icon ((char *)item->image, E_ICON_SIZE_MENU);
+ image = gtk_image_new_from_pixbuf (pixbuf);
+ g_object_unref (pixbuf);
+
+ gtk_widget_show(image);
+ menuitem = (GtkMenuItem *)gtk_image_menu_item_new();
+ gtk_image_menu_item_set_image((GtkImageMenuItem *)menuitem, image);
+ } else {
+ menuitem = (GtkMenuItem *)gtk_menu_item_new();
+ }
+ break;
+ case EM_POPUP_TOGGLE:
+ menuitem = (GtkMenuItem *)gtk_check_menu_item_new();
+ gtk_check_menu_item_set_active((GtkCheckMenuItem *)menuitem, item->type & EM_POPUP_ACTIVE);
+ break;
+ case EM_POPUP_RADIO:
+ menuitem = (GtkMenuItem *)gtk_radio_menu_item_new(g_hash_table_lookup(group_hash, ppath->str));
+ g_hash_table_insert(group_hash, ppath->str, gtk_radio_menu_item_get_group((GtkRadioMenuItem *)menuitem));
+ gtk_check_menu_item_set_active((GtkCheckMenuItem *)menuitem, item->type & EM_POPUP_ACTIVE);
+ break;
+ case EM_POPUP_IMAGE:
+ menuitem = (GtkMenuItem *)gtk_image_menu_item_new();
+ gtk_image_menu_item_set_image((GtkImageMenuItem *)menuitem, item->image);
+ break;
+ case EM_POPUP_SUBMENU: {
+ GtkMenu *submenu = (GtkMenu *)gtk_menu_new();
+
+ g_hash_table_insert(menu_hash, item->path, submenu);
+ menuitem = (GtkMenuItem *)gtk_menu_item_new();
+ gtk_menu_item_set_submenu(menuitem, (GtkWidget *)submenu);
+ break; }
+ case EM_POPUP_BAR:
+ /* TODO: double-bar, end-bar stuff? */
+ menuitem = (GtkMenuItem *)gtk_separator_menu_item_new();
+ break;
+ default:
+ continue;
+ }
+
+ if (item->label) {
+ label = gtk_label_new_with_mnemonic(_(item->label));
+ gtk_misc_set_alignment((GtkMisc *)label, 0.0, 0.5);
+ gtk_widget_show(label);
+ gtk_container_add((GtkContainer *)menuitem, label);
+ }
+
+ if (item->activate)
+ g_signal_connect(menuitem, "activate", item->activate, item->activate_data);
+
+ gtk_menu_shell_append((GtkMenuShell *)thismenu, (GtkWidget *)menuitem);
+
+ if (item->mask & disable_mask)
+ gtk_widget_set_sensitive((GtkWidget *)menuitem, FALSE);
+
+ gtk_widget_show((GtkWidget *)menuitem);
+ }
+
+ g_string_free(ppath, TRUE);
+ g_ptr_array_free(items, TRUE);
+ g_hash_table_destroy(menu_hash);
+ g_hash_table_destroy(group_hash);
+
+ return topmenu;
+}
+
+static void
+emp_popup_done(GtkWidget *w, EMPopup *emp)
+{
+ gtk_widget_destroy(w);
+ g_object_unref(emp);
+}
+
+/**
+ * em_popup_create_menu_once:
+ * @emp: EMPopup, once the menu is shown, this cannot be
+ * considered a valid pointer.
+ * @target: If set, the target of the selection. Static menu
+ * items will be added. The target will be freed once complete.
+ * @hide_mask:
+ * @disable_mask:
+ *
+ * Like popup_create_menu, but automatically sets up the menu
+ * so that it is destroyed once a selection takes place, and
+ * the EMPopup is unreffed.
+ *
+ * Return value: A menu, to popup.
+ **/
+GtkMenu *
+em_popup_create_menu_once(EMPopup *emp, EMPopupTarget *target, guint32 hide_mask, guint32 disable_mask)
+{
+ GtkMenu *menu;
+
+ if (target)
+ em_popup_add_static_items(emp, target);
+
+ menu = em_popup_create_menu(emp, hide_mask, disable_mask);
+
+ if (target)
+ g_signal_connect_swapped(menu, "selection_done", G_CALLBACK(em_popup_target_free), target);
+ g_signal_connect(menu, "selection_done", G_CALLBACK(emp_popup_done), emp);
+
+ return menu;
+}
+
+/* ********************************************************************** */
+
+/**
+ * em_popup_static_add_factory:
+ * @menuid:
+ * @func:
+ * @data:
+ *
+ * Add a popup factory which will be called to add_items() any
+ * extra menu's if wants to do the current PopupTarget.
+ *
+ * TODO: Make the menuid a pattern?
+ *
+ * Return value: A handle to the factory.
+ **/
+EMPopupFactory *
+em_popup_static_add_factory(const char *menuid, EMPopupFactoryFunc func, void *data)
+{
+ struct _EMPopupFactory *f = g_malloc0(sizeof(*f));
+
+ f->menuid = g_strdup(menuid);
+ f->factory = func;
+ f->factory_data = data;
+ e_dlist_addtail(&emp_factories, (EDListNode *)f);
+
+ return f;
+}
+
+/**
+ * em_popup_static_remove_factory:
+ * @f:
+ *
+ * Remove a popup factory.
+ **/
+void
+em_popup_static_remove_factory(EMPopupFactory *f)
+{
+ e_dlist_remove((EDListNode *)f);
+ g_free(f->menuid);
+ g_free(f);
+}
+
+/**
* em_popup_target_new_select:
* @folder: The selection will ref this for the life of it.
* @folder_uri:
@@ -169,20 +452,21 @@ EMPopup *em_popup_new(const char *menuid)
*
* Return value:
**/
-EMPopupTargetSelect *
-em_popup_target_new_select(EMPopup *emp, struct _CamelFolder *folder, const char *folder_uri, GPtrArray *uids)
+EMPopupTarget *
+em_popup_target_new_select(struct _CamelFolder *folder, const char *folder_uri, GPtrArray *uids)
{
- EMPopupTargetSelect *t = e_popup_target_new(&emp->popup, EM_POPUP_TARGET_SELECT, sizeof(*t));
+ EMPopupTarget *t = g_malloc0(sizeof(*t));
guint32 mask = ~0;
int i;
const char *tmp;
- t->uids = uids;
- t->folder = folder;
- t->uri = g_strdup(folder_uri);
+ t->type = EM_POPUP_TARGET_SELECT;
+ t->data.select.uids = uids;
+ t->data.select.folder = folder;
+ t->data.select.folder_uri = g_strdup(folder_uri);
if (folder == NULL) {
- t->target.mask = mask;
+ t->mask = mask;
return t;
}
@@ -206,31 +490,34 @@ em_popup_target_new_select(EMPopup *emp, struct _CamelFolder *folder, const char
for (i = 0; i < uids->len; i++) {
CamelMessageInfo *info = camel_folder_get_message_info(folder, uids->pdata[i]);
- guint32 flags;
if (info == NULL)
continue;
- flags = camel_message_info_flags(info);
- if (flags & CAMEL_MESSAGE_SEEN)
+ if (info->flags & CAMEL_MESSAGE_SEEN)
mask &= ~EM_POPUP_SELECT_MARK_UNREAD;
else
mask &= ~EM_POPUP_SELECT_MARK_READ;
- if (flags & CAMEL_MESSAGE_DELETED)
+ if (info->flags & CAMEL_MESSAGE_DELETED)
mask &= ~EM_POPUP_SELECT_UNDELETE;
else
mask &= ~EM_POPUP_SELECT_DELETE;
- if (flags & CAMEL_MESSAGE_FLAGGED)
+ if (info->flags & CAMEL_MESSAGE_FLAGGED)
mask &= ~EM_POPUP_SELECT_MARK_UNIMPORTANT;
else
mask &= ~EM_POPUP_SELECT_MARK_IMPORTANT;
- tmp = camel_message_info_user_tag(info, "follow-up");
+ if (info->flags & CAMEL_MESSAGE_JUNK)
+ mask &= ~EM_POPUP_SELECT_MARK_NOJUNK;
+ else
+ mask &= ~EM_POPUP_SELECT_MARK_JUNK;
+
+ tmp = camel_tag_get (&info->user_tags, "follow-up");
if (tmp && *tmp) {
mask &= ~EM_POPUP_SELECT_FLAG_CLEAR;
- tmp = camel_message_info_user_tag(info, "completed-on");
+ tmp = camel_tag_get(&info->user_tags, "completed-on");
if (tmp == NULL || *tmp == 0)
mask &= ~EM_POPUP_SELECT_FLAG_COMPLETED;
} else
@@ -244,18 +531,19 @@ em_popup_target_new_select(EMPopup *emp, struct _CamelFolder *folder, const char
camel_folder_free_message_info(folder, info);
}
- t->target.mask = mask;
+ t->mask = mask;
return t;
}
-EMPopupTargetURI *
-em_popup_target_new_uri(EMPopup *emp, const char *uri)
+EMPopupTarget *
+em_popup_target_new_uri(const char *uri)
{
- EMPopupTargetURI *t = e_popup_target_new(&emp->popup, EM_POPUP_TARGET_URI, sizeof(*t));
+ EMPopupTarget *t = g_malloc0(sizeof(*t));
guint32 mask = ~0;
- t->uri = g_strdup(uri);
+ t->type = EM_POPUP_TARGET_URI;
+ t->data.uri = g_strdup(uri);
if (g_ascii_strncasecmp(uri, "http:", 5) == 0
|| g_ascii_strncasecmp(uri, "https:", 6) == 0)
@@ -265,46 +553,48 @@ em_popup_target_new_uri(EMPopup *emp, const char *uri)
else
mask &= ~EM_POPUP_URI_NOT_MAILTO;
- t->target.mask = mask;
+ t->mask = mask;
return t;
}
-EMPopupTargetPart *
-em_popup_target_new_part(EMPopup *emp, struct _CamelMimePart *part, const char *mime_type)
+EMPopupTarget *
+em_popup_target_new_part(struct _CamelMimePart *part, const char *mime_type)
{
- EMPopupTargetPart *t = e_popup_target_new(&emp->popup, EM_POPUP_TARGET_PART, sizeof(*t));
+ EMPopupTarget *t = g_malloc0(sizeof(*t));
guint32 mask = ~0;
- t->part = part;
+ t->type = EM_POPUP_TARGET_PART;
+ t->data.part.part = part;
camel_object_ref(part);
if (mime_type)
- t->mime_type = g_strdup(mime_type);
+ t->data.part.mime_type = g_strdup(mime_type);
else
- t->mime_type = camel_data_wrapper_get_mime_type((CamelDataWrapper *)part);
+ t->data.part.mime_type = camel_data_wrapper_get_mime_type((CamelDataWrapper *)part);
- camel_strdown(t->mime_type);
+ camel_strdown(t->data.part.mime_type);
if (CAMEL_IS_MIME_MESSAGE(camel_medium_get_content_object((CamelMedium *)part)))
mask &= ~EM_POPUP_PART_MESSAGE;
- if (strncmp(t->mime_type, "image/", 6) == 0)
+ if (strncmp(t->data.part.mime_type, "image/", 6) == 0)
mask &= ~EM_POPUP_PART_IMAGE;
- t->target.mask = mask;
+ t->mask = mask;
return t;
}
/* TODO: This should be based on the CamelFolderInfo, but ... em-folder-tree doesn't keep it? */
-EMPopupTargetFolder *
-em_popup_target_new_folder (EMPopup *emp, const char *uri, guint32 info_flags, guint32 popup_flags)
+EMPopupTarget *
+em_popup_target_new_folder (const char *uri, guint32 info_flags, guint32 popup_flags)
{
- EMPopupTargetFolder *t = e_popup_target_new(&emp->popup, EM_POPUP_TARGET_FOLDER, sizeof(*t));
+ EMPopupTarget *t = g_malloc0(sizeof(*t));
guint32 mask = ~0;
CamelURL *url;
- t->uri = g_strdup(uri);
+ t->type = EM_POPUP_TARGET_FOLDER;
+ t->data.folder.folder_uri = g_strdup(uri);
if (popup_flags & EM_POPUP_FOLDER_STORE)
mask &= ~(EM_POPUP_FOLDER_STORE|EM_POPUP_FOLDER_INFERIORS);
@@ -339,63 +629,91 @@ em_popup_target_new_folder (EMPopup *emp, const char *uri, guint32 info_flags, g
camel_url_free(url);
done:
- t->target.mask = mask;
+ t->mask = mask;
return t;
}
-/**
- * em_popup_target_new_attachments:
- * @emp:
- * @attachments: A list of EMsgComposerAttachment objects, reffed for
- * the list. Will be unreff'd once finished with.
- *
- * Owns the list @attachments and their items after they're passed in.
- *
- * Return value:
- **/
-EMPopupTargetAttachments *
-em_popup_target_new_attachments(EMPopup *emp, GSList *attachments)
+void
+em_popup_target_free(EMPopupTarget *t)
{
- EMPopupTargetAttachments *t = e_popup_target_new(&emp->popup, EM_POPUP_TARGET_ATTACHMENTS, sizeof(*t));
- guint32 mask = ~0;
- int len = g_slist_length(attachments);
-
- t->attachments = attachments;
- if (len > 0)
- mask &= ~ EM_POPUP_ATTACHMENTS_MANY;
- if (len == 1)
- mask &= ~ EM_POPUP_ATTACHMENTS_ONE;
- t->target.mask = mask;
+ switch (t->type) {
+ case EM_POPUP_TARGET_SELECT:
+ if (t->data.select.folder)
+ camel_object_unref(t->data.select.folder);
+ g_free(t->data.select.folder_uri);
+ if (t->data.select.uids)
+ em_utils_uids_free(t->data.select.uids);
+ break;
+ case EM_POPUP_TARGET_URI:
+ g_free(t->data.uri);
+ break;
+ case EM_POPUP_TARGET_PART:
+ camel_object_unref(t->data.part.part);
+ g_free(t->data.part.mime_type);
+ break;
+ case EM_POPUP_TARGET_FOLDER:
+ g_free(t->data.folder.folder_uri);
+ break;
+ }
- return t;
+ g_free(t);
}
/* ********************************************************************** */
+#if 0
+/* TODO: flesh these out where possible */
+static void
+emp_popup_open(GtkWidget *w, EMFolderView *emfv)
+{
+ em_folder_view_open_selected(emfv);
+}
+
+static void
+emp_popup_edit (GtkWidget *w, EMPopupTarget *t)
+{
+ if (!em_utils_check_user_can_send_mail(t->widget))
+ return;
+
+ em_utils_edit_messages(t->widget, t->data.select.folder, em_utils_uids_copy(t->data.select.uids), FALSE);
+}
+
static void
-emp_part_popup_saveas(EPopup *ep, EPopupItem *item, void *data)
+emp_popup_saveas(GtkWidget *w, EMPopupTarget *t)
{
- EMPopupTargetPart *t = (EMPopupTargetPart *)ep->target;
+ em_utils_save_messages(t->widget, t->data.select.folder, em_utils_uids_copy(t->data.select.uids));
+}
- em_utils_save_part(ep->target->widget, _("Save As..."), t->part);
+static EMPopupItem emp_standard_select_popups[] = {
+ /*{ EM_POPUP_ITEM, "00.select.00", N_("_Open"), G_CALLBACK(emp_popup_open), NULL, NULL, 0 },*/
+ { EM_POPUP_ITEM, "00.select.01", N_("_Edit as New Message..."), G_CALLBACK(emp_popup_edit), NULL, NULL, EM_POPUP_SELECT_EDIT },
+ { EM_POPUP_ITEM, "00.select.02", N_("_Save As..."), G_CALLBACK(emp_popup_saveas), NULL, "stock_save-as", 0 },
+};
+#endif
+
+/* ********************************************************************** */
+
+static void
+emp_part_popup_saveas(GtkWidget *w, EMPopupTarget *t)
+{
+ em_utils_save_part(w, _("Save As..."), t->data.part.part);
}
static void
-emp_part_popup_set_background(EPopup *ep, EPopupItem *item, void *data)
+emp_part_popup_set_background(GtkWidget *w, EMPopupTarget *t)
{
- EMPopupTargetPart *t = (EMPopupTargetPart *)ep->target;
GConfClient *gconf;
char *str, *filename, *path, *extension;
unsigned int i=1;
- filename = g_strdup(camel_mime_part_get_filename(t->part));
+ filename = g_strdup(camel_mime_part_get_filename(t->data.part.part));
/* if filename is blank, create a default filename based on MIME type */
if (!filename || !filename[0]) {
CamelContentType *ct;
- ct = camel_mime_part_get_content_type(t->part);
+ ct = camel_mime_part_get_content_type(t->data.part.part);
g_free (filename);
filename = g_strdup_printf (_("untitled_image.%s"), ct->subtype);
}
@@ -419,7 +737,7 @@ emp_part_popup_set_background(EPopup *ep, EPopupItem *item, void *data)
g_free(filename);
- if (em_utils_save_part_to_file(ep->target->widget, path, t->part)) {
+ if (em_utils_save_part_to_file(w, path, t->data.part.part)) {
gconf = gconf_client_get_default();
/* if the filename hasn't changed, blank the filename before
@@ -449,68 +767,64 @@ emp_part_popup_set_background(EPopup *ep, EPopupItem *item, void *data)
}
static void
-emp_part_popup_reply_sender(EPopup *ep, EPopupItem *item, void *data)
+emp_part_popup_reply_sender (GtkWidget *w, EMPopupTarget *t)
{
- EMPopupTargetPart *t = (EMPopupTargetPart *)ep->target;
CamelMimeMessage *message;
- message = (CamelMimeMessage *)camel_medium_get_content_object((CamelMedium *)t->part);
- em_utils_reply_to_message(NULL, NULL, message, REPLY_MODE_SENDER, NULL);
+ message = (CamelMimeMessage *) camel_medium_get_content_object ((CamelMedium *) t->data.part.part);
+ em_utils_reply_to_message (NULL, NULL, message, REPLY_MODE_SENDER, NULL);
}
static void
-emp_part_popup_reply_list (EPopup *ep, EPopupItem *item, void *data)
+emp_part_popup_reply_list (GtkWidget *w, EMPopupTarget *t)
{
- EMPopupTargetPart *t = (EMPopupTargetPart *)ep->target;
CamelMimeMessage *message;
- message = (CamelMimeMessage *)camel_medium_get_content_object((CamelMedium *)t->part);
- em_utils_reply_to_message(NULL, NULL, message, REPLY_MODE_LIST, NULL);
+ message = (CamelMimeMessage *) camel_medium_get_content_object ((CamelMedium *) t->data.part.part);
+ em_utils_reply_to_message (NULL, NULL, message, REPLY_MODE_LIST, NULL);
}
static void
-emp_part_popup_reply_all (EPopup *ep, EPopupItem *item, void *data)
+emp_part_popup_reply_all (GtkWidget *w, EMPopupTarget *t)
{
- EMPopupTargetPart *t = (EMPopupTargetPart *)ep->target;
CamelMimeMessage *message;
- message = (CamelMimeMessage *)camel_medium_get_content_object((CamelMedium *)t->part);
- em_utils_reply_to_message(NULL, NULL, message, REPLY_MODE_ALL, NULL);
+ message = (CamelMimeMessage *) camel_medium_get_content_object ((CamelMedium *) t->data.part.part);
+ em_utils_reply_to_message (NULL, NULL, message, REPLY_MODE_ALL, NULL);
}
static void
-emp_part_popup_forward (EPopup *ep, EPopupItem *item, void *data)
+emp_part_popup_forward (GtkWidget *w, EMPopupTarget *t)
{
- EMPopupTargetPart *t = (EMPopupTargetPart *)ep->target;
CamelMimeMessage *message;
/* TODO: have a emfv specific override so we can get the parent folder uri */
- message = (CamelMimeMessage *)camel_medium_get_content_object((CamelMedium *) t->part);
- em_utils_forward_message(message, NULL);
+ message = (CamelMimeMessage *) camel_medium_get_content_object ((CamelMedium *) t->data.part.part);
+ em_utils_forward_message (message, NULL);
}
static EMPopupItem emp_standard_object_popups[] = {
- { E_POPUP_ITEM, "00.part.00", N_("_Save As..."), emp_part_popup_saveas, NULL, "stock_save-as", 0 },
- { E_POPUP_ITEM, "00.part.10", N_("Set as _Background"), emp_part_popup_set_background, NULL, NULL, EM_POPUP_PART_IMAGE },
- { E_POPUP_BAR, "10.part", NULL, NULL, NULL, NULL, EM_POPUP_PART_MESSAGE },
- { E_POPUP_ITEM, "10.part.00", N_("_Reply to sender"), emp_part_popup_reply_sender, NULL, "stock_mail-reply" , EM_POPUP_PART_MESSAGE },
- { E_POPUP_ITEM, "10.part.01", N_("Reply to _List"), emp_part_popup_reply_list, NULL, NULL, EM_POPUP_PART_MESSAGE},
- { E_POPUP_ITEM, "10.part.03", N_("Reply to _All"), emp_part_popup_reply_all, NULL, "stock_mail-reply-to-all", EM_POPUP_PART_MESSAGE},
- { E_POPUP_BAR, "20.part", NULL, NULL, NULL, NULL, EM_POPUP_PART_MESSAGE },
- { E_POPUP_ITEM, "20.part.00", N_("_Forward"), emp_part_popup_forward, NULL, "stock_mail-forward", EM_POPUP_PART_MESSAGE },
+ { EM_POPUP_ITEM, "00.part.00", N_("_Save As..."), G_CALLBACK(emp_part_popup_saveas), NULL, "stock_save-as", 0 },
+ { EM_POPUP_ITEM, "00.part.10", N_("Set as _Background"), G_CALLBACK(emp_part_popup_set_background), NULL, NULL, EM_POPUP_PART_IMAGE },
+ { EM_POPUP_BAR, "10.part", NULL, NULL, NULL, NULL, EM_POPUP_PART_MESSAGE },
+ { EM_POPUP_ITEM, "10.part.00", N_("_Reply to sender"), G_CALLBACK(emp_part_popup_reply_sender), NULL, "stock_mail-reply" , EM_POPUP_PART_MESSAGE },
+ { EM_POPUP_ITEM, "10.part.01", N_("Reply to _List"), G_CALLBACK(emp_part_popup_reply_list), NULL, NULL, EM_POPUP_PART_MESSAGE},
+ { EM_POPUP_ITEM, "10.part.03", N_("Reply to _All"), G_CALLBACK(emp_part_popup_reply_all), NULL, "stock_mail-reply-to-all", EM_POPUP_PART_MESSAGE},
+ { EM_POPUP_BAR, "20.part", NULL, NULL, NULL, NULL, EM_POPUP_PART_MESSAGE },
+ { EM_POPUP_ITEM, "20.part.00", N_("_Forward"), G_CALLBACK(emp_part_popup_forward), NULL, "stock_mail-forward", EM_POPUP_PART_MESSAGE },
+
};
-static const EPopupItem emp_standard_part_apps_bar = { E_POPUP_BAR, "99.object" };
+static const EMPopupItem emp_standard_part_apps_bar = { EM_POPUP_BAR, "99.object" };
/* ********************************************************************** */
static void
-emp_uri_popup_link_open(EPopup *ep, EPopupItem *item, void *data)
+emp_uri_popup_link_open(GtkWidget *w, EMPopupTarget *t)
{
- EMPopupTargetURI *t = (EMPopupTargetURI *)ep->target;
GError *err = NULL;
- gnome_url_show(t->uri, &err);
+ gnome_url_show(t->data.uri, &err);
if (err) {
g_warning("gnome_url_show: %s", err->message);
g_error_free(err);
@@ -518,36 +832,33 @@ emp_uri_popup_link_open(EPopup *ep, EPopupItem *item, void *data)
}
static void
-emp_uri_popup_address_send(EPopup *ep, EPopupItem *item, void *data)
+emp_uri_popup_address_send (GtkWidget *w, EMPopupTarget *t)
{
- EMPopupTargetURI *t = (EMPopupTargetURI *)ep->target;
-
/* TODO: have an emfv specific override to get the from uri */
- em_utils_compose_new_message_with_mailto(t->uri, NULL);
+ em_utils_compose_new_message_with_mailto (t->data.uri, NULL);
}
static void
-emp_uri_popup_address_add(EPopup *ep, EPopupItem *item, void *data)
+emp_uri_popup_address_add(GtkWidget *w, EMPopupTarget *t)
{
- EMPopupTargetURI *t = (EMPopupTargetURI *)ep->target;
CamelURL *url;
- url = camel_url_new(t->uri, NULL);
+ url = camel_url_new(t->data.uri, NULL);
if (url == NULL) {
- g_warning("cannot parse url '%s'", t->uri);
+ g_warning("cannot parse url '%s'", t->data.uri);
return;
}
if (url->path && url->path[0])
- em_utils_add_address(ep->target->widget, url->path);
+ em_utils_add_address(w, url->path);
camel_url_free(url);
}
-static EPopupItem emp_standard_uri_popups[] = {
- { E_POPUP_ITEM, "00.uri.00", N_("_Open Link in Browser"), emp_uri_popup_link_open, NULL, NULL, EM_POPUP_URI_NOT_MAILTO },
- { E_POPUP_ITEM, "00.uri.10", N_("Se_nd message to..."), emp_uri_popup_address_send, NULL, NULL, EM_POPUP_URI_MAILTO },
- { E_POPUP_ITEM, "00.uri.20", N_("_Add to Addressbook"), emp_uri_popup_address_add, NULL, NULL, EM_POPUP_URI_MAILTO },
+static EMPopupItem emp_standard_uri_popups[] = {
+ { EM_POPUP_ITEM, "00.uri.00", N_("_Open Link in Browser"), G_CALLBACK(emp_uri_popup_link_open), NULL, NULL, EM_POPUP_URI_NOT_MAILTO },
+ { EM_POPUP_ITEM, "00.uri.10", N_("Se_nd message to..."), G_CALLBACK(emp_uri_popup_address_send), NULL, NULL, EM_POPUP_URI_MAILTO },
+ { EM_POPUP_ITEM, "00.uri.20", N_("_Add to Addressbook"), G_CALLBACK(emp_uri_popup_address_add), NULL, NULL, EM_POPUP_URI_MAILTO },
};
/* ********************************************************************** */
@@ -556,21 +867,23 @@ static EPopupItem emp_standard_uri_popups[] = {
#include <libgnomevfs/gnome-vfs-mime-handlers.h>
- EMPopupTargetPart *target;
+struct _open_in_item {
+ EMPopupItem item;
+ EMPopupTarget *target;
+ GnomeVFSMimeApplication *app;
+};
static void
-emp_apps_open_in(EPopup *ep, EPopupItem *item, void *data)
+emp_apps_open_in(GtkWidget *w, struct _open_in_item *item)
{
char *path;
- EMPopupTargetPart *target = (EMPopupTargetPart *)ep->target;
- path = em_utils_temp_save_part(target->target.widget, target->part);
+ path = em_utils_temp_save_part(item->target->widget, item->target->data.part.part);
if (path) {
- GnomeVFSMimeApplication *app = item->user_data;
- int douri = (app->expects_uris == GNOME_VFS_MIME_APPLICATION_ARGUMENT_TYPE_URIS);
+ int douri = (item->app->expects_uris == GNOME_VFS_MIME_APPLICATION_ARGUMENT_TYPE_URIS);
char *command;
- if (app->requires_terminal) {
+ if (item->app->requires_terminal) {
char *term, *args = NULL;
GConfClient *gconf;
@@ -583,11 +896,11 @@ emp_apps_open_in(EPopup *ep, EPopupItem *item, void *data)
return;
command = g_strdup_printf ("%s%s%s %s %s%s &", term, args ? " " : "", args ? args : "",
- app->command, douri ? "file://" : "", path);
+ item->app->command, douri ? "file://" : "", path);
g_free (term);
g_free (args);
} else {
- command = g_strdup_printf ("%s %s%s &", app->command, douri ? "file://" : "", path);
+ command = g_strdup_printf ("%s %s%s &", item->app->command, douri ? "file://" : "", path);
}
/* FIXME: Do not use system here */
@@ -598,14 +911,14 @@ emp_apps_open_in(EPopup *ep, EPopupItem *item, void *data)
}
static void
-emp_apps_popup_free(EPopup *ep, GSList *free_list, void *data)
+emp_apps_popup_free(GSList *free_list)
{
while (free_list) {
GSList *n = free_list->next;
- EPopupItem *item = free_list->data;
+ struct _open_in_item *item = free_list->data;
- g_free(item->path);
- g_free(item->label);
+ g_free(item->item.path);
+ g_free(item->item.label);
g_free(item);
g_slist_free_1(free_list);
@@ -614,19 +927,13 @@ emp_apps_popup_free(EPopup *ep, GSList *free_list, void *data)
}
static void
-emp_standard_items_free(EPopup *ep, GSList *items, void *data)
-{
- g_slist_free(items);
-}
-
-static void
-emp_standard_menu_factory(EPopup *emp, void *data)
+emp_standard_menu_factory(EMPopup *emp, EMPopupTarget *target, void *data)
{
int i, len;
- EPopupItem *items;
+ EMPopupItem *items;
GSList *menus = NULL;
- switch (emp->target->type) {
+ switch (target->type) {
#if 0
case EM_POPUP_TARGET_SELECT:
return;
@@ -634,21 +941,18 @@ emp_standard_menu_factory(EPopup *emp, void *data)
len = LEN(emp_standard_select_popups);
break;
#endif
- case EM_POPUP_TARGET_URI: {
- /*EMPopupTargetURI *t = (EMPopupTargetURI *)target;*/
-
+ case EM_POPUP_TARGET_URI:
items = emp_standard_uri_popups;
len = LEN(emp_standard_uri_popups);
- break; }
+ break;
case EM_POPUP_TARGET_PART: {
- EMPopupTargetPart *t = (EMPopupTargetPart *)emp->target;
- GList *apps = gnome_vfs_mime_get_short_list_applications(t->mime_type);
+ GList *apps = gnome_vfs_mime_get_short_list_applications(target->data.part.mime_type);
/* FIXME: use the snoop_part stuff from em-format.c */
- if (apps == NULL && strcmp(t->mime_type, "application/octet-stream") == 0) {
+ if (apps == NULL && strcmp(target->data.part.mime_type, "application/octet-stream") == 0) {
const char *filename, *name_type;
- filename = camel_mime_part_get_filename(t->part);
+ filename = camel_mime_part_get_filename(target->data.part.part);
if (filename) {
/* GNOME-VFS will misidentify TNEF attachments as MPEG */
@@ -670,23 +974,25 @@ emp_standard_menu_factory(EPopup *emp, void *data)
for (l = apps, i = 0; l; l = l->next, i++) {
GnomeVFSMimeApplication *app = l->data;
- EPopupItem *item;
+ struct _open_in_item *item;
if (app->requires_terminal)
continue;
item = g_malloc0(sizeof(*item));
- item->type = E_POPUP_ITEM;
- item->path = g_strdup_printf("99.object.%02d", i);
- item->label = g_strdup_printf(_("Open in %s..."), app->name);
- item->activate = emp_apps_open_in;
- item->user_data = app;
+ item->item.type = EM_POPUP_ITEM;
+ item->item.path = g_strdup_printf("99.object.%02d", i);
+ item->item.label = g_strdup_printf(_("Open in %s..."), app->name);
+ item->item.activate = G_CALLBACK(emp_apps_open_in);
+ item->item.activate_data = item;
+ item->target = target;
+ item->app = app;
open_menus = g_slist_prepend(open_menus, item);
}
if (open_menus)
- e_popup_add_items(emp, open_menus, NULL, emp_apps_popup_free, NULL);
+ em_popup_add_items(emp, open_menus, (GDestroyNotify)emp_apps_popup_free);
g_string_free(label, TRUE);
g_list_free(apps);
@@ -701,137 +1007,12 @@ emp_standard_menu_factory(EPopup *emp, void *data)
}
for (i=0;i<len;i++) {
- if ((items[i].visible & emp->target->mask) == 0)
+ if ((items[i].mask & target->mask) == 0) {
+ items[i].activate_data = target;
menus = g_slist_prepend(menus, &items[i]);
+ }
}
if (menus)
- e_popup_add_items(emp, menus, NULL, emp_standard_items_free, NULL);
-}
-
-/* ********************************************************************** */
-
-/* Popup menu plugin handler */
-
-/*
-<e-plugin
- class="org.gnome.mail.plugin.popup:1.0"
- id="org.gnome.mail.plugin.popup.item:1.0"
- type="shlib"
- location="/opt/gnome2/lib/camel/1.0/libcamelimap.so"
- name="imap"
- description="IMAP4 and IMAP4v1 mail store">
- <hook class="org.gnome.mail.popupMenu:1.0"
- handler="HandlePopup">
- <menu id="any" target="select">
- <item
- type="item|toggle|radio|image|submenu|bar"
- active
- path="foo/bar"
- label="label"
- icon="foo"
- mask="select_one"
- activate="emp_view_emacs"/>
- </menu>
- </extension>
-
-*/
-
-static void *emph_parent_class;
-#define emph ((EMPopupHook *)eph)
-
-static const EPopupHookTargetMask emph_select_masks[] = {
- { "one", EM_POPUP_SELECT_ONE },
- { "many", EM_POPUP_SELECT_MANY },
- { "mark_read", EM_POPUP_SELECT_MARK_READ },
- { "mark_unread", EM_POPUP_SELECT_MARK_UNREAD },
- { "delete", EM_POPUP_SELECT_DELETE },
- { "undelete", EM_POPUP_SELECT_UNDELETE },
- { "mailing_list", EM_POPUP_SELECT_MAILING_LIST },
- { "resend", EM_POPUP_SELECT_EDIT },
- { "mark_important", EM_POPUP_SELECT_MARK_IMPORTANT },
- { "mark_unimportant", EM_POPUP_SELECT_MARK_UNIMPORTANT },
- { "flag_followup", EM_POPUP_SELECT_FLAG_FOLLOWUP },
- { "flag_completed", EM_POPUP_SELECT_FLAG_COMPLETED },
- { "flag_clear", EM_POPUP_SELECT_FLAG_CLEAR },
- { "add_sender", EM_POPUP_SELECT_ADD_SENDER },
- { "folder", EM_POPUP_SELECT_FOLDER },
- { 0 }
-};
-
-static const EPopupHookTargetMask emph_uri_masks[] = {
- { "http", EM_POPUP_URI_HTTP },
- { "mailto", EM_POPUP_URI_MAILTO },
- { "notmailto", EM_POPUP_URI_NOT_MAILTO },
- { 0 }
-};
-
-static const EPopupHookTargetMask emph_part_masks[] = {
- { "message", EM_POPUP_PART_MESSAGE },
- { "image", EM_POPUP_PART_IMAGE },
- { 0 }
-};
-
-static const EPopupHookTargetMask emph_folder_masks[] = {
- { "folder", EM_POPUP_FOLDER_FOLDER },
- { "store", EM_POPUP_FOLDER_STORE },
- { "inferiors", EM_POPUP_FOLDER_INFERIORS },
- { "delete", EM_POPUP_FOLDER_DELETE },
- { "select", EM_POPUP_FOLDER_SELECT },
- { 0 }
-};
-
-static const EPopupHookTargetMask emph_attachments_masks[] = {
- { "one", EM_POPUP_ATTACHMENTS_ONE },
- { "many", EM_POPUP_ATTACHMENTS_MANY },
- { 0 }
-};
-
-static const EPopupHookTargetMap emph_targets[] = {
- { "select", EM_POPUP_TARGET_SELECT, emph_select_masks },
- { "uri", EM_POPUP_TARGET_URI, emph_uri_masks },
- { "part", EM_POPUP_TARGET_PART, emph_part_masks },
- { "folder", EM_POPUP_TARGET_FOLDER, emph_folder_masks },
- { "attachments", EM_POPUP_TARGET_ATTACHMENTS, emph_attachments_masks },
- { 0 }
-};
-
-static void
-emph_finalise(GObject *o)
-{
- /*EPluginHook *eph = (EPluginHook *)o;*/
-
- ((GObjectClass *)emph_parent_class)->finalize(o);
-}
-
-static void
-emph_class_init(EPluginHookClass *klass)
-{
- int i;
-
- ((GObjectClass *)klass)->finalize = emph_finalise;
- ((EPluginHookClass *)klass)->id = "org.gnome.evolution.mail.popup:1.0";
-
- for (i=0;emph_targets[i].type;i++)
- e_popup_hook_class_add_target_map((EPopupHookClass *)klass, &emph_targets[i]);
-
- ((EPopupHookClass *)klass)->popup_class = g_type_class_ref(em_popup_get_type());
-}
-
-GType
-em_popup_hook_get_type(void)
-{
- static GType type = 0;
-
- if (!type) {
- static const GTypeInfo info = {
- sizeof(EMPopupHookClass), NULL, NULL, (GClassInitFunc) emph_class_init, NULL, NULL,
- sizeof(EMPopupHook), 0, (GInstanceInitFunc) NULL,
- };
-
- emph_parent_class = g_type_class_ref(e_popup_hook_get_type());
- type = g_type_register_static(e_popup_hook_get_type(), "EMPopupHook", &info, 0);
- }
-
- return type;
+ em_popup_add_items(emp, menus, (GDestroyNotify)g_slist_free);
}
diff --git a/mail/em-subscribe-editor.c b/mail/em-subscribe-editor.c
index 92588c76f9..ab0b098b36 100644
--- a/mail/em-subscribe-editor.c
+++ b/mail/em-subscribe-editor.c
@@ -43,7 +43,6 @@
#include "mail-config.h"
#include <glade/glade.h>
-#include <libgnome/gnome-i18n.h>
#include <gtk/gtkdialog.h>
#include <gtk/gtkscrolledwindow.h>
@@ -300,7 +299,9 @@ sub_fill_level(EMSubscribe *sub, CamelFolderInfo *info, GtkTreeIter *parent, in
gtk_tree_store_append(treestore, &iter, parent);
node = g_malloc0(sizeof(*node));
node->info = fi;
- state = (fi->flags & CAMEL_FOLDER_SUBSCRIBED) != 0;
+ /* FIXME: CAMEL_FOLDER_SUBSCRIBED not implemented properly in imap */
+ state = camel_store_folder_subscribed(sub->store, fi->full_name);
+ /* state = (fi->flags & CAMEL_FOLDER_SUBSCRIBED) != 0; */
gtk_tree_store_set(treestore, &iter, 0, state, 1, fi->name, 2, node, -1);
if ((fi->flags & CAMEL_FOLDER_NOINFERIORS) == 0) {
node->path = gtk_tree_model_get_path((GtkTreeModel *)treestore, &iter);
@@ -844,7 +845,7 @@ GtkDialog *em_subscribe_editor_new(void)
se->dialog = (GtkDialog *)glade_xml_get_widget (xml, "subscribe_dialog");
g_signal_connect(se->dialog, "destroy", G_CALLBACK(sub_editor_destroy), se);
- gtk_widget_ensure_style ((GtkWidget *)se->dialog);
+ gtk_widget_realize ((GtkWidget *)se->dialog);
gtk_container_set_border_width ((GtkContainer *) ((GtkDialog *)se->dialog)->action_area, 12);
gtk_container_set_border_width ((GtkContainer *) ((GtkDialog *)se->dialog)->vbox, 0);
diff --git a/mail/em-utils.c b/mail/em-utils.c
index 0236f2e329..b31ba4ad78 100644
--- a/mail/em-utils.c
+++ b/mail/em-utils.c
@@ -44,13 +44,13 @@
#include <libgnomevfs/gnome-vfs-mime.h>
#include <libgnomevfs/gnome-vfs-mime-utils.h>
#include <libgnomevfs/gnome-vfs-mime-handlers.h>
-#include <libgnome/gnome-i18n.h>
#include "mail-component.h"
#include "mail-mt.h"
#include "mail-ops.h"
#include "mail-tools.h"
#include "mail-config.h"
+#include "mail-config-druid.h"
#include "message-tag-followup.h"
#include <e-util/e-mktemp.h>
@@ -63,7 +63,6 @@
#include "em-utils.h"
#include "em-composer-utils.h"
#include "em-format-quote.h"
-#include "em-account-editor.h"
static void emu_save_part_done (CamelMimePart *part, char *name, int done, void *data);
@@ -179,18 +178,19 @@ druid_destroy_cb (gpointer user_data, GObject *deadbeef)
gboolean
em_utils_configure_account (GtkWidget *parent)
{
- EMAccountEditor *emae;
-
- emae = em_account_editor_new(NULL, EMAE_DRUID);
+ MailConfigDruid *druid;
+
+ druid = mail_config_druid_new ();
+
if (parent != NULL)
- e_dialog_set_transient_for((GtkWindow *)emae->editor, parent);
-
- g_object_weak_ref((GObject *)emae->editor, (GWeakNotify) druid_destroy_cb, NULL);
- gtk_widget_show(emae->editor);
- gtk_grab_add(emae->editor);
- gtk_main();
+ e_dialog_set_transient_for ((GtkWindow *) druid, parent);
+
+ g_object_weak_ref ((GObject *) druid, (GWeakNotify) druid_destroy_cb, NULL);
+ gtk_widget_show ((GtkWidget *) druid);
+ gtk_grab_add ((GtkWidget *) druid);
+ gtk_main ();
- return mail_config_is_configured();
+ return mail_config_is_configured ();
}
/**
@@ -696,10 +696,8 @@ em_utils_flag_for_followup (GtkWidget *parent, CamelFolder *folder, GPtrArray *u
info = camel_folder_get_message_info (folder, uids->pdata[0]);
if (info) {
- const CamelTag *tags = camel_message_info_user_tags(info);
-
- if (tags)
- message_tag_editor_set_tag_list (MESSAGE_TAG_EDITOR (editor), tags);
+ if (info->user_tags)
+ message_tag_editor_set_tag_list (MESSAGE_TAG_EDITOR (editor), info->user_tags);
camel_folder_free_message_info (folder, info);
}
}
diff --git a/mail/mail-account-gui.c b/mail/mail-account-gui.c
new file mode 100644
index 0000000000..a2ee0c0fb3
--- /dev/null
+++ b/mail/mail-account-gui.c
@@ -0,0 +1,2531 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors:
+ * Dan Winship <danw@ximian.com>
+ * Jeffrey Stedfast <fejj@ximian.com>
+ *
+ * Copyright 2001 Ximian, Inc. (www.ximian.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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+
+#include <string.h>
+#include <stdarg.h>
+#include <sys/stat.h>
+
+#include <gconf/gconf-client.h>
+
+#include <gtk/gtkentry.h>
+#include <gtk/gtktogglebutton.h>
+#include <gtk/gtktextbuffer.h>
+#include <gtk/gtktextview.h>
+#include <gtk/gtkcheckbutton.h>
+#include <gtk/gtkspinbutton.h>
+#include <gtk/gtkmenuitem.h>
+#include <gtk/gtkoptionmenu.h>
+#include <gtk/gtknotebook.h>
+#include <gtk/gtkhbox.h>
+#include <gtk/gtkdialog.h>
+#include <gtk/gtkstock.h>
+#ifdef USE_GTKFILECHOOSER
+#include <gtk/gtkfilechooser.h>
+#include <gtk/gtkradiobutton.h>
+#include <libgnomeui/gnome-file-entry.h>
+#endif
+
+#include <e-util/e-account-list.h>
+#include <e-util/e-signature-list.h>
+
+#include <widgets/misc/e-error.h>
+
+#include "em-account-prefs.h"
+#include "em-folder-selection-button.h"
+#include "mail-account-gui.h"
+#include "mail-session.h"
+#include "mail-send-recv.h"
+#include "mail-signature-editor.h"
+#include "mail-component.h"
+#include "em-utils.h"
+#include "em-composer-prefs.h"
+#include "mail-config.h"
+#include "mail-ops.h"
+#include "mail-mt.h"
+
+#if defined (HAVE_NSS)
+#include "smime/gui/e-cert-selector.h"
+#endif
+
+#define d(x)
+
+static void save_service (MailAccountGuiService *gsvc, GHashTable *extra_conf, EAccountService *service);
+static void service_changed (GtkEntry *entry, gpointer user_data);
+
+struct {
+ char *label;
+ char *value;
+} ssl_options[] = {
+ { N_("Always"), "always" },
+ { N_("Whenever Possible"), "when-possible" },
+ { N_("Never"), "never" }
+};
+
+static int num_ssl_options = sizeof (ssl_options) / sizeof (ssl_options[0]);
+
+static gboolean
+is_email (const char *address)
+{
+ /* This is supposed to check if the address's domain could be
+ an FQDN but alas, it's not worth the pain and suffering. */
+ const char *at;
+
+ at = strchr (address, '@');
+ /* make sure we have an '@' and that it's not the first or last char */
+ if (!at || at == address || *(at + 1) == '\0')
+ return FALSE;
+
+ return TRUE;
+}
+
+static GtkWidget *
+get_focused_widget (GtkWidget *def, ...)
+{
+ GtkWidget *widget, *ret = NULL;
+ va_list args;
+
+ va_start (args, def);
+ widget = va_arg (args, GtkWidget *);
+ while (widget) {
+ if (GTK_WIDGET_HAS_FOCUS (widget)) {
+ ret = widget;
+ break;
+ }
+
+ widget = va_arg (args, GtkWidget *);
+ }
+ va_end (args);
+
+ if (ret)
+ return ret;
+ else
+ return def;
+}
+
+gboolean
+mail_account_gui_identity_complete (MailAccountGui *gui, GtkWidget **incomplete)
+{
+ const char *text;
+
+ text = gtk_entry_get_text (gui->full_name);
+ if (!text || !*text) {
+ if (incomplete)
+ *incomplete = get_focused_widget (GTK_WIDGET (gui->full_name),
+ GTK_WIDGET (gui->email_address),
+ GTK_WIDGET (gui->reply_to),
+ NULL);
+ return FALSE;
+ }
+
+ text = gtk_entry_get_text (gui->email_address);
+ if (!text || !is_email (text)) {
+ if (incomplete)
+ *incomplete = get_focused_widget (GTK_WIDGET (gui->email_address),
+ GTK_WIDGET (gui->full_name),
+ GTK_WIDGET (gui->reply_to),
+ NULL);
+ return FALSE;
+ }
+
+ /* make sure that if the reply-to field is filled in, that it is valid */
+ text = gtk_entry_get_text (gui->reply_to);
+ if (text && *text && !is_email (text)) {
+ if (incomplete)
+ *incomplete = get_focused_widget (GTK_WIDGET (gui->reply_to),
+ GTK_WIDGET (gui->email_address),
+ GTK_WIDGET (gui->full_name),
+ NULL);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+auto_detected_foreach (gpointer key, gpointer value, gpointer user_data)
+{
+ g_free (key);
+ g_free (value);
+}
+
+static void
+check_button_state (GtkToggleButton *button, gpointer data)
+{
+ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (button)))
+ gtk_widget_set_sensitive (GTK_WIDGET (data), TRUE);
+ else
+ gtk_widget_set_sensitive (GTK_WIDGET (data), FALSE);
+}
+
+
+static gboolean
+populate_text_entry (GtkTextView *view, const char *filename)
+{
+ FILE *fd;
+ char *filebuf;
+ GtkTextIter iter;
+ GtkTextBuffer *buffer;
+ int count;
+
+ g_return_val_if_fail (filename != NULL , FALSE);
+
+ fd = fopen (filename, "r");
+
+ if (!fd) {
+ /* FIXME: Should never come here */
+ return FALSE;
+ }
+
+ filebuf = g_malloc (1024);
+
+ buffer = gtk_text_buffer_new (NULL);
+ gtk_text_buffer_get_start_iter (buffer, &iter);
+
+ while (!feof (fd) && !ferror (fd)) {
+ count = fread (filebuf, 1, sizeof (filebuf), fd);
+ gtk_text_buffer_insert (buffer, &iter, filebuf, count);
+ }
+ gtk_text_view_set_buffer (GTK_TEXT_VIEW (view),
+ GTK_TEXT_BUFFER (buffer));
+ fclose (fd);
+ g_free (filebuf);
+ return TRUE;
+}
+
+static gboolean
+display_license (CamelProvider *prov)
+{
+ GladeXML *xml;
+ GtkWidget *top_widget;
+ GtkTextView *text_entry;
+ GtkButton *button_yes, *button_no;
+ GtkCheckButton *check_button;
+ GtkResponseType response = GTK_RESPONSE_NONE;
+ GtkLabel *top_label;
+ char *label_text, *dialog_title;
+ gboolean status;
+
+ xml = glade_xml_new (EVOLUTION_GLADEDIR "/mail-dialogs.glade", "lic_dialog", NULL);
+
+ top_widget = glade_xml_get_widget (xml, "lic_dialog");
+ text_entry = GTK_TEXT_VIEW (glade_xml_get_widget (xml, "textview1"));
+ if (!(status = populate_text_entry (GTK_TEXT_VIEW (text_entry), prov->license_file)))
+ goto failed;
+
+ gtk_text_view_set_editable (GTK_TEXT_VIEW (text_entry), FALSE);
+
+ button_yes = GTK_BUTTON (glade_xml_get_widget (xml, "lic_yes_button"));
+ gtk_widget_set_sensitive (GTK_WIDGET (button_yes), FALSE);
+
+ button_no = GTK_BUTTON (glade_xml_get_widget (xml, "lic_no_button"));
+
+ check_button = GTK_CHECK_BUTTON (glade_xml_get_widget (xml, "lic_checkbutton"));
+
+ top_label = GTK_LABEL (glade_xml_get_widget (xml, "lic_top_label"));
+
+ label_text = g_strdup_printf (_("\nPlease read carefully the license agreement\n"
+ "for %s displayed below\n"
+ "and tick the check box for accepting it\n"), prov->license);
+
+ gtk_label_set_label (top_label, label_text);
+
+ dialog_title = g_strdup_printf (_("%s License Agreement"), prov->license);
+
+ gtk_window_set_title (GTK_WINDOW (top_widget), dialog_title);
+
+ g_signal_connect (check_button, "toggled", G_CALLBACK (check_button_state), button_yes);
+
+ response = gtk_dialog_run (GTK_DIALOG (top_widget));
+
+ g_free (label_text);
+ g_free (dialog_title);
+
+ failed:
+ gtk_widget_destroy (top_widget);
+ g_object_unref (xml);
+
+ return (response == GTK_RESPONSE_ACCEPT);
+}
+
+static gboolean
+service_complete (MailAccountGuiService *service, GHashTable *extra_config, GtkWidget **incomplete)
+{
+ const CamelProvider *prov = service->provider;
+ GtkWidget *path;
+ const char *text;
+
+ if (!prov)
+ return TRUE;
+
+ /* transports don't have a path */
+ if (service->path)
+ path = GTK_WIDGET (service->path);
+ else
+ path = NULL;
+
+ if (CAMEL_PROVIDER_NEEDS (prov, CAMEL_URL_PART_HOST)) {
+ text = gtk_entry_get_text (service->hostname);
+ if (!text || !*text) {
+ if (incomplete)
+ *incomplete = get_focused_widget (GTK_WIDGET (service->hostname),
+ GTK_WIDGET (service->username),
+ path,
+ NULL);
+ return FALSE;
+ }
+ }
+
+ if (CAMEL_PROVIDER_NEEDS (prov, CAMEL_URL_PART_USER)) {
+ text = gtk_entry_get_text (service->username);
+ if (!text || !*text) {
+ if (incomplete)
+ *incomplete = get_focused_widget (GTK_WIDGET (service->username),
+ GTK_WIDGET (service->hostname),
+ path,
+ NULL);
+ return FALSE;
+ }
+ }
+
+ if (CAMEL_PROVIDER_NEEDS (prov, CAMEL_URL_PART_PATH)) {
+ if (!path) {
+ d(printf ("aagh, transports aren't supposed to have paths.\n"));
+ return TRUE;
+ }
+
+ text = gtk_entry_get_text (service->path);
+ if (!text || !*text) {
+ if (incomplete)
+ *incomplete = get_focused_widget (GTK_WIDGET (service->path),
+ GTK_WIDGET (service->hostname),
+ GTK_WIDGET (service->username),
+ NULL);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static gboolean
+mail_account_gui_check_for_license (CamelProvider *prov)
+{
+ GConfClient *gconf;
+ gboolean accepted = TRUE, status;
+ GSList * providers_list, *l, *n;
+ char *provider;
+
+ if (prov->flags & CAMEL_PROVIDER_HAS_LICENSE) {
+ gconf = mail_config_get_gconf_client ();
+
+ providers_list = gconf_client_get_list (gconf, "/apps/evolution/mail/licenses", GCONF_VALUE_STRING, NULL);
+
+ for (l = providers_list, accepted = FALSE; l && !accepted; l = g_slist_next (l))
+ accepted = (strcmp ((char *)l->data, prov->protocol) == 0);
+ if (!accepted) {
+ /* Since the license is not yet accepted, pop-up a
+ * dialog to display the license agreement and check
+ * if the user accepts it
+ */
+
+ if ((accepted = display_license (prov)) == TRUE) {
+ provider = g_strdup (prov->protocol);
+ providers_list = g_slist_append (providers_list,
+ provider);
+ status = gconf_client_set_list (gconf,
+ "/apps/evolution/mail/licenses",
+ GCONF_VALUE_STRING,
+ providers_list, NULL);
+ }
+ }
+ l = providers_list;
+ while (l) {
+ n = g_slist_next (l);
+ g_free (l->data);
+ g_slist_free_1 (l);
+ l = n;
+ }
+ }
+ return accepted;
+}
+
+gboolean
+mail_account_gui_source_complete (MailAccountGui *gui, GtkWidget **incomplete)
+{
+ return service_complete (&gui->source, gui->extra_config, incomplete);
+}
+
+void
+mail_account_gui_auto_detect_extra_conf (MailAccountGui *gui)
+{
+ MailAccountGuiService *service = &gui->source;
+ CamelProvider *prov = service->provider;
+ GHashTable *auto_detected;
+ GtkWidget *path;
+ CamelURL *url;
+ char *text;
+ const char *tmp;
+
+ if (!prov)
+ return;
+
+ /* transports don't have a path */
+ if (service->path)
+ path = GTK_WIDGET (service->path);
+ else
+ path = NULL;
+
+ url = g_new0 (CamelURL, 1);
+ camel_url_set_protocol (url, prov->protocol);
+
+ if (CAMEL_PROVIDER_ALLOWS (prov, CAMEL_URL_PART_HOST)) {
+ text = g_strdup (gtk_entry_get_text (service->hostname));
+ if (*text) {
+ char *port;
+
+ port = strchr (text, ':');
+ if (port) {
+ *port++ = '\0';
+ camel_url_set_port (url, atoi (port));
+ }
+
+ camel_url_set_host (url, text);
+ }
+ g_free (text);
+ }
+
+ if (CAMEL_PROVIDER_ALLOWS (prov, CAMEL_URL_PART_USER)) {
+ text = g_strdup (gtk_entry_get_text (service->username));
+ g_strstrip (text);
+ camel_url_set_user (url, text);
+ g_free (text);
+ }
+
+ if (path && CAMEL_PROVIDER_ALLOWS (prov, CAMEL_URL_PART_PATH)) {
+ tmp = gtk_entry_get_text (service->path);
+ if (tmp && *tmp)
+ camel_url_set_path (url, tmp);
+ }
+
+ camel_provider_auto_detect (prov, url, &auto_detected, NULL);
+ camel_url_free (url);
+
+ if (auto_detected) {
+ CamelProviderConfEntry *entries;
+ GtkToggleButton *toggle;
+ GtkSpinButton *spin;
+ GtkEntry *entry;
+ char *value;
+ int i;
+
+ entries = service->provider->extra_conf;
+
+ for (i = 0; entries[i].type != CAMEL_PROVIDER_CONF_END; i++) {
+ GtkWidget *enable_widget = NULL;
+
+ if (!entries[i].name)
+ continue;
+
+ value = g_hash_table_lookup (auto_detected, entries[i].name);
+ if (!value)
+ continue;
+
+ switch (entries[i].type) {
+ case CAMEL_PROVIDER_CONF_CHECKBOX:
+ toggle = g_hash_table_lookup (gui->extra_config, entries[i].name);
+ gtk_toggle_button_set_active (toggle, atoi (value));
+ enable_widget = (GtkWidget *)toggle;
+ break;
+
+ case CAMEL_PROVIDER_CONF_ENTRY:
+ entry = g_hash_table_lookup (gui->extra_config, entries[i].name);
+ if (value)
+ gtk_entry_set_text (entry, value);
+ enable_widget = (GtkWidget *)entry;
+ break;
+
+ case CAMEL_PROVIDER_CONF_CHECKSPIN:
+ {
+ gboolean enable;
+ double val;
+ char *name;
+
+ toggle = g_hash_table_lookup (gui->extra_config, entries[i].name);
+ name = g_strdup_printf ("%s_value", entries[i].name);
+ spin = g_hash_table_lookup (gui->extra_config, name);
+ g_free (name);
+
+ enable = *value++ == 'y';
+ gtk_toggle_button_set_active (toggle, enable);
+ g_assert (*value == ':');
+ val = strtod (++value, NULL);
+ gtk_spin_button_set_value (spin, val);
+ enable_widget = (GtkWidget *)spin;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (enable_widget)
+ gtk_widget_set_sensitive(enable_widget, e_account_writable_option(gui->account, prov->protocol, entries[i].name));
+
+ }
+
+ g_hash_table_foreach (auto_detected, auto_detected_foreach, NULL);
+ g_hash_table_destroy (auto_detected);
+ }
+}
+
+gboolean
+mail_account_gui_transport_complete (MailAccountGui *gui, GtkWidget **incomplete)
+{
+ if (!gui->transport.provider) {
+ if (incomplete)
+ *incomplete = GTK_WIDGET (gui->transport.type);
+ return FALSE;
+ }
+
+ /* If it's both source and transport, there's nothing extra to
+ * configure on the transport page.
+ */
+ if (CAMEL_PROVIDER_IS_STORE_AND_TRANSPORT (gui->transport.provider)) {
+ if (gui->transport.provider == gui->source.provider)
+ return TRUE;
+ if (incomplete)
+ *incomplete = GTK_WIDGET (gui->transport.type);
+ return FALSE;
+ }
+
+ if (!service_complete (&gui->transport, NULL, incomplete))
+ return FALSE;
+
+ /* FIXME? */
+ if (gtk_toggle_button_get_active (gui->transport.needs_auth) &&
+ CAMEL_PROVIDER_ALLOWS (gui->transport.provider, CAMEL_URL_PART_USER)) {
+ const char *text = gtk_entry_get_text (gui->transport.username);
+
+ if (!text || !*text) {
+ if (incomplete)
+ *incomplete = get_focused_widget (GTK_WIDGET (gui->transport.username),
+ GTK_WIDGET (gui->transport.hostname),
+ NULL);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+gboolean
+mail_account_gui_management_complete (MailAccountGui *gui, GtkWidget **incomplete)
+{
+ const char *text;
+
+ text = gtk_entry_get_text (gui->account_name);
+ if (text && *text)
+ return TRUE;
+
+ if (incomplete)
+ *incomplete = GTK_WIDGET (gui->account_name);
+
+ return FALSE;
+}
+
+
+static void
+service_authtype_changed (GtkWidget *widget, gpointer user_data)
+{
+ MailAccountGuiService *service = user_data;
+ CamelServiceAuthType *authtype;
+
+ service->authitem = widget;
+ authtype = g_object_get_data ((GObject *) widget, "authtype");
+
+ gtk_widget_set_sensitive (GTK_WIDGET (service->remember), authtype->need_password);
+}
+
+static void
+build_auth_menu (MailAccountGuiService *service, GList *all_authtypes,
+ GList *supported_authtypes, gboolean check_supported)
+{
+ GtkWidget *menu, *item, *first = NULL;
+ CamelServiceAuthType *current, *authtype, *sauthtype;
+ int history = 0, i;
+ GList *l, *s;
+
+ if (service->authitem)
+ current = g_object_get_data ((GObject *) service->authitem, "authtype");
+ else
+ current = NULL;
+
+ service->authitem = NULL;
+
+ menu = gtk_menu_new ();
+
+ for (l = all_authtypes, i = 0; l; l = l->next, i++) {
+ authtype = l->data;
+
+ item = gtk_menu_item_new_with_label (authtype->name);
+ for (s = supported_authtypes; s; s = s->next) {
+ sauthtype = s->data;
+ if (!strcmp (authtype->name, sauthtype->name))
+ break;
+ }
+
+ if (check_supported && !s) {
+ gtk_widget_set_sensitive (item, FALSE);
+ } else if (current && !strcmp (authtype->name, current->name)) {
+ first = item;
+ history = i;
+ } else if (!first) {
+ first = item;
+ history = i;
+ }
+
+ g_object_set_data ((GObject *) item, "authtype", authtype);
+ g_signal_connect (item, "activate", G_CALLBACK (service_authtype_changed), service);
+
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+
+ gtk_widget_show (item);
+ }
+
+ gtk_option_menu_remove_menu (service->authtype);
+ gtk_option_menu_set_menu (service->authtype, menu);
+
+ if (first) {
+ gtk_option_menu_set_history (service->authtype, history);
+ g_signal_emit_by_name (first, "activate");
+ }
+}
+
+static void
+transport_provider_set_available (MailAccountGui *gui, CamelProvider *provider,
+ gboolean available)
+{
+ GtkWidget *menuitem;
+
+ menuitem = g_object_get_data ((GObject *) gui->transport.type, provider->protocol);
+ g_return_if_fail (menuitem != NULL);
+
+ gtk_widget_set_sensitive (menuitem, available);
+
+ if (available) {
+ gpointer number = g_object_get_data ((GObject *) menuitem, "number");
+
+ g_signal_emit_by_name (menuitem, "activate");
+ gtk_option_menu_set_history (gui->transport.type, GPOINTER_TO_UINT (number));
+ }
+}
+
+static void
+source_type_changed (GtkWidget *widget, gpointer user_data)
+{
+ MailAccountGui *gui = user_data;
+ GtkWidget *file_entry, *label, *frame, *dwidget = NULL;
+ CamelProvider *provider;
+ gboolean writeable;
+ gboolean license_accepted = TRUE;
+
+ provider = g_object_get_data ((GObject *) widget, "provider");
+
+ /* If the previously-selected provider has a linked transport,
+ * disable it.
+ */
+ if (gui->source.provider &&
+ CAMEL_PROVIDER_IS_STORE_AND_TRANSPORT (gui->source.provider))
+ transport_provider_set_available (gui, gui->source.provider, FALSE);
+
+ gui->source.provider = provider;
+
+ if (gui->source.provider) {
+ writeable = e_account_writable_option (gui->account, gui->source.provider->protocol, "auth");
+ gtk_widget_set_sensitive ((GtkWidget *) gui->source.authtype, writeable);
+ gtk_widget_set_sensitive ((GtkWidget *) gui->source.check_supported, writeable);
+
+ writeable = e_account_writable_option (gui->account, gui->source.provider->protocol, "use_ssl");
+ gtk_widget_set_sensitive ((GtkWidget *) gui->source.use_ssl, writeable);
+
+ writeable = e_account_writable (gui->account, E_ACCOUNT_SOURCE_SAVE_PASSWD);
+ gtk_widget_set_sensitive ((GtkWidget *) gui->source.remember, writeable);
+ }
+
+ if (provider)
+ gtk_label_set_text (gui->source.description, provider->description);
+ else
+ gtk_label_set_text (gui->source.description, "");
+
+ if (gui->source.provider)
+ license_accepted = mail_account_gui_check_for_license (gui->source.provider);
+
+ frame = glade_xml_get_widget (gui->xml, "source_frame");
+ if (provider && license_accepted) {
+ gtk_widget_show (frame);
+
+ /* hostname */
+ label = glade_xml_get_widget (gui->xml, "source_host_label");
+
+ if (CAMEL_PROVIDER_ALLOWS (provider, CAMEL_URL_PART_HOST)) {
+ dwidget = GTK_WIDGET (gui->source.hostname);
+ gtk_widget_show (GTK_WIDGET (gui->source.hostname));
+ gtk_widget_show (label);
+ } else {
+ gtk_widget_hide (GTK_WIDGET (gui->source.hostname));
+ gtk_widget_hide (label);
+ }
+
+ /* username */
+ label = glade_xml_get_widget (gui->xml, "source_user_label");
+
+ if (CAMEL_PROVIDER_ALLOWS (provider, CAMEL_URL_PART_USER)) {
+ if (!dwidget)
+ dwidget = GTK_WIDGET (gui->source.username);
+ gtk_widget_show (GTK_WIDGET (gui->source.username));
+ gtk_widget_show (label);
+ } else {
+ gtk_widget_hide (GTK_WIDGET (gui->source.username));
+ gtk_widget_hide (label);
+ }
+
+ /* path */
+ label = glade_xml_get_widget (gui->xml, "source_path_label");
+ file_entry = glade_xml_get_widget (gui->xml, "source_path_entry");
+
+ if (CAMEL_PROVIDER_ALLOWS (provider, CAMEL_URL_PART_PATH)) {
+ if (!dwidget)
+ dwidget = GTK_WIDGET (gui->source.path);
+
+ gtk_widget_show (GTK_WIDGET (file_entry));
+ gtk_widget_show (label);
+ } else {
+ gtk_entry_set_text (gui->source.path, "");
+ gtk_widget_hide (GTK_WIDGET (file_entry));
+ gtk_widget_hide (label);
+ }
+
+ /* ssl */
+#ifdef HAVE_SSL
+ gtk_widget_hide (gui->source.no_ssl);
+ if (provider && provider->flags & CAMEL_PROVIDER_SUPPORTS_SSL) {
+ gtk_widget_show (gui->source.ssl_frame);
+ gtk_widget_show (gui->source.ssl_hbox);
+ } else {
+ gtk_widget_hide (gui->source.ssl_frame);
+ gtk_widget_hide (gui->source.ssl_hbox);
+ }
+#else
+ gtk_widget_hide (gui->source.ssl_hbox);
+ gtk_widget_show (gui->source.no_ssl);
+#endif
+
+ /* auth */
+ frame = glade_xml_get_widget (gui->xml, "source_auth_frame");
+ if (provider && CAMEL_PROVIDER_ALLOWS (provider, CAMEL_URL_PART_AUTH)) {
+ build_auth_menu (&gui->source, provider->authtypes, NULL, FALSE);
+ gtk_widget_show (frame);
+ } else
+ gtk_widget_hide (frame);
+ } else {
+ gtk_widget_hide (frame);
+ frame = glade_xml_get_widget (gui->xml, "source_auth_frame");
+ gtk_widget_hide (frame);
+ }
+
+ g_signal_emit_by_name (gui->source.username, "changed");
+
+ if (dwidget)
+ gtk_widget_grab_focus (dwidget);
+
+ mail_account_gui_build_extra_conf (gui, gui && gui->account && gui->account->source ? gui->account->source->url : NULL);
+
+ if (provider && CAMEL_PROVIDER_IS_STORE_AND_TRANSPORT (provider))
+ transport_provider_set_available (gui, provider, TRUE);
+}
+
+
+static void
+transport_needs_auth_toggled (GtkToggleButton *toggle, gpointer data)
+{
+ MailAccountGui *gui = data;
+ gboolean need = gtk_toggle_button_get_active (toggle);
+ GtkWidget *widget;
+
+ widget = glade_xml_get_widget (gui->xml, "transport_auth_frame");
+ gtk_widget_set_sensitive (widget, need);
+ if (need)
+ service_changed (NULL, &gui->transport);
+}
+
+static void
+transport_type_changed (GtkWidget *widget, gpointer user_data)
+{
+ MailAccountGui *gui = user_data;
+ CamelProvider *provider;
+ GtkWidget *label, *frame;
+ gboolean writeable;
+
+ provider = g_object_get_data ((GObject *) widget, "provider");
+ gui->transport.provider = provider;
+
+ if (gui->transport.provider) {
+ writeable = e_account_writable_option (gui->account, gui->transport.provider->protocol, "auth");
+ gtk_widget_set_sensitive ((GtkWidget *) gui->transport.authtype, writeable);
+ gtk_widget_set_sensitive ((GtkWidget *) gui->transport.check_supported, writeable);
+
+ writeable = e_account_writable_option (gui->account, gui->transport.provider->protocol, "use_ssl");
+ gtk_widget_set_sensitive ((GtkWidget *) gui->transport.use_ssl, writeable);
+
+ writeable = e_account_writable (gui->account, E_ACCOUNT_TRANSPORT_SAVE_PASSWD);
+ gtk_widget_set_sensitive ((GtkWidget *) gui->transport.remember, writeable);
+ }
+
+ /* description */
+ gtk_label_set_text (gui->transport.description, provider->description);
+
+ frame = glade_xml_get_widget (gui->xml, "transport_frame");
+ if (!CAMEL_PROVIDER_IS_STORE_AND_TRANSPORT (provider) &&
+ (CAMEL_PROVIDER_ALLOWS (provider, CAMEL_URL_PART_HOST) ||
+ (CAMEL_PROVIDER_ALLOWS (provider, CAMEL_URL_PART_AUTH) &&
+ !CAMEL_PROVIDER_NEEDS (provider, CAMEL_URL_PART_AUTH)))) {
+ gtk_widget_show (frame);
+
+ label = glade_xml_get_widget (gui->xml, "transport_host_label");
+ if (CAMEL_PROVIDER_ALLOWS (provider, CAMEL_URL_PART_HOST)) {
+ gtk_widget_show (GTK_WIDGET (gui->transport.hostname));
+ gtk_widget_show (label);
+ } else {
+ gtk_widget_hide (GTK_WIDGET (gui->transport.hostname));
+ gtk_widget_hide (label);
+ }
+
+ /* ssl */
+#ifdef HAVE_SSL
+ gtk_widget_hide (gui->transport.no_ssl);
+ if (provider && provider->flags & CAMEL_PROVIDER_SUPPORTS_SSL) {
+ gtk_widget_show (gui->transport.ssl_frame);
+ gtk_widget_show (gui->transport.ssl_hbox);
+ } else {
+ gtk_widget_hide (gui->transport.ssl_frame);
+ gtk_widget_hide (gui->transport.ssl_hbox);
+ }
+#else
+ gtk_widget_hide (gui->transport.ssl_hbox);
+ gtk_widget_show (gui->transport.no_ssl);
+#endif
+
+ /* auth */
+ if (CAMEL_PROVIDER_ALLOWS (provider, CAMEL_URL_PART_AUTH) &&
+ !CAMEL_PROVIDER_NEEDS (provider, CAMEL_URL_PART_AUTH))
+ gtk_widget_show (GTK_WIDGET (gui->transport.needs_auth));
+ else
+ gtk_widget_hide (GTK_WIDGET (gui->transport.needs_auth));
+ } else
+ gtk_widget_hide (frame);
+
+ frame = glade_xml_get_widget (gui->xml, "transport_auth_frame");
+ if (!CAMEL_PROVIDER_IS_STORE_AND_TRANSPORT (provider) &&
+ CAMEL_PROVIDER_ALLOWS (provider, CAMEL_URL_PART_AUTH)) {
+ gtk_widget_show (frame);
+
+ label = glade_xml_get_widget (gui->xml, "transport_user_label");
+ if (CAMEL_PROVIDER_ALLOWS (provider, CAMEL_URL_PART_USER)) {
+ gtk_widget_show (GTK_WIDGET (gui->transport.username));
+ gtk_widget_show (label);
+ } else {
+ gtk_widget_hide (GTK_WIDGET (gui->transport.username));
+ gtk_widget_hide (label);
+ }
+
+ build_auth_menu (&gui->transport, provider->authtypes, NULL, FALSE);
+ transport_needs_auth_toggled (gui->transport.needs_auth, gui);
+ } else
+ gtk_widget_hide (frame);
+
+ g_signal_emit_by_name (gui->transport.hostname, "changed");
+}
+
+static void
+service_changed (GtkEntry *entry, gpointer user_data)
+{
+ MailAccountGuiService *service = user_data;
+
+ gtk_widget_set_sensitive (GTK_WIDGET (service->check_supported),
+ service_complete (service, NULL, NULL));
+}
+
+/* the fun of async ... */
+struct _service_check_data {
+ MailAccountGuiService *gsvc;
+ GtkWidget *dialog;
+ GtkWidget *window;
+
+ int id;
+ gulong destroy_id;
+ int destroyed:1;
+};
+
+static void
+service_check_done(const char *url, CamelProviderType type, GList *types, void *data)
+{
+ struct _service_check_data *sd = data;
+
+ if (!sd->destroyed) {
+ gtk_widget_set_sensitive(sd->window, TRUE);
+ build_auth_menu(sd->gsvc, sd->gsvc->provider->authtypes, types, TRUE);
+ }
+
+ if (sd->dialog) {
+ gtk_widget_destroy(sd->dialog);
+ sd->dialog = NULL;
+ }
+
+ if (sd->destroy_id)
+ g_signal_handler_disconnect(sd->window, sd->destroy_id);
+
+ g_free(sd);
+}
+
+static void
+service_check_response(GtkDialog *d, int button, struct _service_check_data *sd)
+{
+ mail_msg_cancel(sd->id);
+
+ gtk_widget_destroy(sd->dialog);
+ sd->dialog = NULL;
+}
+
+static void
+service_check_destroy(GtkWindow *w, struct _service_check_data *sd)
+{
+ sd->destroy_id = 0;
+ sd->destroyed = TRUE;
+ mail_msg_cancel(sd->id);
+}
+
+static void
+service_check_supported (GtkButton *button, gpointer user_data)
+{
+ MailAccountGuiService *gsvc = user_data;
+ EAccountService *service;
+ GtkWidget *dialog;
+ GtkWidget *authitem;
+ struct _service_check_data *sd;
+
+ sd = g_malloc0(sizeof(*sd));
+ sd->id = -1;
+ sd->gsvc = gsvc;
+
+ /* This is sort of a hack, when checking for supported AUTH
+ types we don't want to use whatever authtype is selected
+ because it may not be available. */
+ service = g_malloc0(sizeof(*service));
+ authitem = gsvc->authitem;
+ gsvc->authitem = NULL;
+ save_service (gsvc, NULL, service);
+ gsvc->authitem = authitem;
+
+ sd->window = gtk_widget_get_toplevel((GtkWidget *)button);
+ sd->destroy_id = g_signal_connect(sd->window, "destroy", G_CALLBACK(service_check_destroy), sd);
+
+ gtk_widget_set_sensitive(sd->window, FALSE);
+ dialog = gtk_dialog_new_with_buttons(_("Connecting to server..."),
+ (GtkWindow *)sd->window,
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ NULL);
+ gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
+ gtk_label_new(_("Connecting to server...")),
+ TRUE, TRUE, 10);
+ g_signal_connect(dialog, "response", G_CALLBACK(service_check_response), sd);
+ gtk_widget_show_all(dialog);
+
+ sd->dialog = dialog;
+ sd->id = mail_check_service(service->url, gsvc->provider_type, service_check_done, sd);
+
+ g_free (service->url);
+ g_free (service);
+}
+
+
+static void
+toggle_sensitivity (GtkToggleButton *toggle, GtkWidget *widget)
+{
+ gtk_widget_set_sensitive (widget, gtk_toggle_button_get_active (toggle));
+}
+
+/* Returns true if the widget is enabled */
+static gboolean
+setup_toggle (GtkWidget *widget, const char *depname, MailAccountGui *gui)
+{
+ GtkToggleButton *toggle;
+
+ if (!strcmp (depname, "UNIMPLEMENTED")) {
+ gtk_widget_set_sensitive (widget, FALSE);
+ return FALSE;
+ }
+
+ toggle = g_hash_table_lookup (gui->extra_config, depname);
+ g_signal_connect (toggle, "toggled", G_CALLBACK (toggle_sensitivity), widget);
+ toggle_sensitivity (toggle, widget);
+
+ return gtk_toggle_button_get_active(toggle);
+}
+
+void
+mail_account_gui_build_extra_conf (MailAccountGui *gui, const char *url_string)
+{
+ CamelURL *url;
+ GtkWidget *mailcheck_frame, *mailcheck_hbox;
+ GtkWidget *hostname_label, *username_label, *path_label;
+ GtkWidget *hostname, *username, *path;
+ GtkTable *main_table, *cur_table;
+ CamelProviderConfEntry *entries;
+ GList *child, *next;
+ char *name;
+ int i, rows;
+
+ if (url_string)
+ url = camel_url_new (url_string, NULL);
+ else
+ url = NULL;
+
+ hostname_label = glade_xml_get_widget (gui->xml, "source_host_label");
+ gtk_label_set_text_with_mnemonic (GTK_LABEL (hostname_label), _("_Host:"));
+ hostname = glade_xml_get_widget (gui->xml, "source_host");
+
+ username_label = glade_xml_get_widget (gui->xml, "source_user_label");
+ gtk_label_set_text_with_mnemonic (GTK_LABEL (username_label), _("User_name:"));
+ username = glade_xml_get_widget (gui->xml, "source_user");
+
+ path_label = glade_xml_get_widget (gui->xml, "source_path_label");
+ gtk_label_set_text_with_mnemonic (GTK_LABEL (path_label), _("_Path:"));
+ path = glade_xml_get_widget (gui->xml, "source_path");
+
+ /* Remove the contents of the extra_table except for the
+ * mailcheck_frame.
+ */
+ main_table = (GtkTable *) glade_xml_get_widget (gui->xml, "extra_table");
+ gtk_container_set_border_width ((GtkContainer *) main_table, 12);
+ gtk_table_set_row_spacings (main_table, 6);
+ gtk_table_set_col_spacings (main_table, 8);
+ mailcheck_frame = glade_xml_get_widget (gui->xml, "extra_mailcheck_frame");
+ child = gtk_container_get_children (GTK_CONTAINER (main_table));
+ while (child != NULL) {
+ next = child->next;
+ if (child->data != (gpointer) mailcheck_frame)
+ gtk_container_remove (GTK_CONTAINER (main_table), child->data);
+ g_list_free_1 (child);
+ child = next;
+ }
+
+ gtk_table_resize (main_table, 1, 2);
+
+ /* Remove any additional mailcheck items. */
+ cur_table = (GtkTable *) glade_xml_get_widget (gui->xml, "extra_mailcheck_table");
+ gtk_container_set_border_width ((GtkContainer *) cur_table, 12);
+ gtk_table_set_row_spacings (cur_table, 6);
+ gtk_table_set_col_spacings (cur_table, 8);
+ mailcheck_hbox = glade_xml_get_widget (gui->xml, "extra_mailcheck_hbox");
+ child = gtk_container_get_children (GTK_CONTAINER (cur_table));
+ while (child != NULL) {
+ next = child->next;
+ if (child->data != (gpointer) mailcheck_hbox)
+ gtk_container_remove (GTK_CONTAINER (cur_table), child->data);
+ g_list_free_1 (child);
+ child = next;
+ }
+
+ gtk_table_resize (cur_table, 1, 2);
+
+ if (!gui->source.provider) {
+ gtk_widget_set_sensitive (GTK_WIDGET (main_table), FALSE);
+ if (url)
+ camel_url_free (url);
+ return;
+ } else
+ gtk_widget_set_sensitive(GTK_WIDGET(main_table), e_account_writable(gui->account, E_ACCOUNT_SOURCE_URL));
+
+ /* Set up our hash table. */
+ if (gui->extra_config)
+ g_hash_table_destroy (gui->extra_config);
+ gui->extra_config = g_hash_table_new (g_str_hash, g_str_equal);
+
+ entries = gui->source.provider->extra_conf;
+ if (!entries)
+ goto done;
+
+ cur_table = main_table;
+ rows = main_table->nrows;
+ for (i = 0; ; i++) {
+ GtkWidget *enable_widget = NULL;
+ int enabled = TRUE;
+
+ switch (entries[i].type) {
+ case CAMEL_PROVIDER_CONF_SECTION_START:
+ {
+ GtkWidget *frame, *label;
+ char *markup;
+
+ if (entries[i].name && !strcmp (entries[i].name, "mailcheck")) {
+ cur_table = (GtkTable *) glade_xml_get_widget (gui->xml, "extra_mailcheck_table");
+ rows = cur_table->nrows;
+ break;
+ }
+
+ markup = g_strdup_printf ("<span weight=\"bold\">%s</span>", entries[i].text);
+ label = gtk_label_new (NULL);
+ gtk_label_set_markup ((GtkLabel *) label, markup);
+ gtk_label_set_justify ((GtkLabel *) label, GTK_JUSTIFY_LEFT);
+ gtk_label_set_use_markup ((GtkLabel *) label, TRUE);
+ gtk_misc_set_alignment ((GtkMisc *) label, 0.0, 0.5);
+ gtk_widget_show (label);
+ g_free (markup);
+
+ cur_table = (GtkTable *) gtk_table_new (0, 2, FALSE);
+ gtk_container_set_border_width ((GtkContainer *) cur_table, 12);
+ gtk_table_set_row_spacings (cur_table, 6);
+ gtk_table_set_col_spacings (cur_table, 8);
+ gtk_widget_show ((GtkWidget *) cur_table);
+
+ frame = gtk_vbox_new (FALSE, 0);
+ gtk_box_pack_start ((GtkBox *) frame, label, FALSE, FALSE, 0);
+ gtk_box_pack_start ((GtkBox *) frame, (GtkWidget *) cur_table, FALSE, FALSE, 0);
+ gtk_widget_show (frame);
+
+ gtk_table_attach (main_table, frame, 0, 2,
+ rows, rows + 1,
+ GTK_EXPAND | GTK_FILL, 0, 0, 0);
+
+ rows = 0;
+
+ break;
+ }
+ case CAMEL_PROVIDER_CONF_SECTION_END:
+ cur_table = main_table;
+ rows = main_table->nrows;
+ break;
+
+ case CAMEL_PROVIDER_CONF_LABEL:
+ if (entries[i].name && entries[i].text) {
+ GtkWidget *label;
+
+ if (!strcmp (entries[i].name, "username")) {
+ gtk_label_set_text_with_mnemonic (GTK_LABEL (username_label), entries[i].text);
+ enable_widget = username_label;
+ } else if (!strcmp (entries[i].name, "hostname")) {
+ gtk_label_set_text_with_mnemonic (GTK_LABEL (hostname_label), entries[i].text);
+ enable_widget = hostname_label;
+ } else if (!strcmp (entries[i].name, "path")) {
+ gtk_label_set_text_with_mnemonic (GTK_LABEL (path_label), entries[i].text);
+ enable_widget = path_label;
+ } else {
+ /* make a new label */
+ label = gtk_label_new (entries[i].text);
+ gtk_table_resize (cur_table, cur_table->nrows + 1, 2);
+ gtk_table_attach (cur_table, label, 0, 2, rows, rows + 1,
+ GTK_EXPAND | GTK_FILL, 0, 0, 0);
+ rows++;
+ enable_widget = label;
+ }
+ }
+ break;
+
+ case CAMEL_PROVIDER_CONF_CHECKBOX:
+ {
+ GtkWidget *checkbox;
+ gboolean active;
+
+ checkbox = gtk_check_button_new_with_label (entries[i].text);
+ if (url)
+ active = camel_url_get_param (url, entries[i].name) != NULL;
+ else
+ active = atoi (entries[i].value);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbox), active);
+
+ gtk_table_attach (cur_table, checkbox, 0, 2, rows, rows + 1,
+ GTK_EXPAND | GTK_FILL, 0, 0, 0);
+ rows++;
+ g_hash_table_insert (gui->extra_config, entries[i].name, checkbox);
+ if (entries[i].depname)
+ enabled = setup_toggle(checkbox, entries[i].depname, gui);
+
+ enable_widget = checkbox;
+ break;
+ }
+
+ case CAMEL_PROVIDER_CONF_ENTRY:
+ {
+ GtkWidget *label, *entry;
+ const char *text;
+
+ if (!strcmp (entries[i].name, "username")) {
+ gtk_label_set_text_with_mnemonic (GTK_LABEL (username_label), entries[i].text);
+ label = username_label;
+ entry = username;
+ } else if (!strcmp (entries[i].name, "hostname")) {
+ gtk_label_set_text_with_mnemonic (GTK_LABEL (hostname_label), entries[i].text);
+ label = hostname_label;
+ entry = hostname;
+ } else if (!strcmp (entries[i].name, "path")) {
+ gtk_label_set_text_with_mnemonic (GTK_LABEL (path_label), entries[i].text);
+ label = path_label;
+ entry = path;
+ } else {
+ /* make a new text entry with label */
+ label = gtk_label_new (entries[i].text);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0);
+ entry = gtk_entry_new ();
+
+ gtk_table_attach (cur_table, label, 0, 1, rows, rows + 1,
+ GTK_FILL, 0, 0, 0);
+ gtk_table_attach (cur_table, entry, 1, 2, rows, rows + 1,
+ GTK_EXPAND | GTK_FILL, 0, 0, 0);
+ rows++;
+ }
+
+ if (url)
+ text = camel_url_get_param (url, entries[i].name);
+ else
+ text = entries[i].value;
+
+ if (text)
+ gtk_entry_set_text (GTK_ENTRY (entry), text);
+
+ if (entries[i].depname) {
+ setup_toggle (entry, entries[i].depname, gui);
+ enabled = setup_toggle (label, entries[i].depname, gui);
+ }
+
+ g_hash_table_insert (gui->extra_config, entries[i].name, entry);
+
+ enable_widget = entry;
+ break;
+ }
+
+ case CAMEL_PROVIDER_CONF_CHECKSPIN:
+ {
+ GtkWidget *hbox, *checkbox, *spin, *label;
+ GtkObject *adj;
+ char *data, *pre, *post, *p;
+ double min, def, max;
+ gboolean enable;
+
+ /* FIXME: this is pretty fucked... */
+ data = entries[i].text;
+ p = strstr (data, "%s");
+ g_return_if_fail (p != NULL);
+
+ pre = g_strndup (data, p - data);
+ post = p + 2;
+
+ data = entries[i].value;
+ enable = *data++ == 'y';
+ g_return_if_fail (*data == ':');
+ min = strtod (data + 1, &data);
+ g_return_if_fail (*data == ':');
+ def = strtod (data + 1, &data);
+ g_return_if_fail (*data == ':');
+ max = strtod (data + 1, NULL);
+
+ if (url) {
+ const char *val;
+
+ val = camel_url_get_param (url, entries[i].name);
+ if (!val)
+ enable = FALSE;
+ else {
+ enable = TRUE;
+ def = atof (val);
+ }
+ }
+
+ hbox = gtk_hbox_new (FALSE, 0);
+ checkbox = gtk_check_button_new_with_label (pre);
+ g_free (pre);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbox), enable);
+ adj = gtk_adjustment_new (def, min, max, 1, 1, 1);
+ spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0);
+ label = gtk_label_new (post);
+
+ gtk_box_pack_start (GTK_BOX (hbox), checkbox, FALSE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (hbox), spin, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 4);
+
+ gtk_table_attach (cur_table, hbox, 0, 2, rows, rows + 1,
+ GTK_EXPAND | GTK_FILL, 0, 0, 0);
+ rows++;
+ g_hash_table_insert (gui->extra_config, entries[i].name, checkbox);
+ name = g_strdup_printf ("%s_value", entries[i].name);
+ g_hash_table_insert (gui->extra_config, name, spin);
+ if (entries[i].depname) {
+ setup_toggle (checkbox, entries[i].depname, gui);
+ setup_toggle (spin, entries[i].depname, gui);
+ enabled = setup_toggle (label, entries[i].depname, gui);
+ }
+
+ enable_widget = hbox;
+ break;
+ }
+
+ case CAMEL_PROVIDER_CONF_HIDDEN:
+ break;
+
+ case CAMEL_PROVIDER_CONF_END:
+ goto done;
+ }
+
+ if (enabled && enable_widget)
+ gtk_widget_set_sensitive(enable_widget, e_account_writable_option(gui->account, gui->source.provider->protocol, entries[i].name));
+ }
+
+ done:
+ gtk_widget_show_all (GTK_WIDGET (main_table));
+ if (url)
+ camel_url_free (url);
+}
+
+static void
+extract_values (MailAccountGuiService *source, GHashTable *extra_config, CamelURL *url)
+{
+ CamelProviderConfEntry *entries;
+ GtkToggleButton *toggle;
+ GtkEntry *entry;
+ GtkSpinButton *spin;
+ char *name;
+ int i;
+
+ if (!source->provider || !source->provider->extra_conf)
+ return;
+ entries = source->provider->extra_conf;
+
+ for (i = 0; ; i++) {
+ if (entries[i].depname) {
+ toggle = g_hash_table_lookup (extra_config, entries[i].depname);
+ if (!toggle || !gtk_toggle_button_get_active (toggle))
+ continue;
+ }
+
+ switch (entries[i].type) {
+ case CAMEL_PROVIDER_CONF_CHECKBOX:
+ toggle = g_hash_table_lookup (extra_config, entries[i].name);
+ if (gtk_toggle_button_get_active (toggle))
+ camel_url_set_param (url, entries[i].name, "");
+ break;
+
+ case CAMEL_PROVIDER_CONF_ENTRY:
+ if (strcmp (entries[i].name, "username") == 0
+ || strcmp (entries[i].name, "hostname") == 0
+ || strcmp (entries[i].name, "path") == 0) {
+ break;
+ }
+ entry = g_hash_table_lookup (extra_config, entries[i].name);
+ camel_url_set_param (url, entries[i].name, gtk_entry_get_text (entry));
+ break;
+
+ case CAMEL_PROVIDER_CONF_CHECKSPIN:
+ toggle = g_hash_table_lookup (extra_config, entries[i].name);
+ if (!gtk_toggle_button_get_active (toggle))
+ break;
+ name = g_strdup_printf ("%s_value", entries[i].name);
+ spin = g_hash_table_lookup (extra_config, name);
+ g_free (name);
+ name = g_strdup_printf ("%d", gtk_spin_button_get_value_as_int (spin));
+ camel_url_set_param (url, entries[i].name, name);
+ g_free (name);
+ break;
+
+ case CAMEL_PROVIDER_CONF_HIDDEN:
+ if (entries[i].value)
+ camel_url_set_param (url, entries[i].name, entries[i].value);
+ break;
+
+ case CAMEL_PROVIDER_CONF_END:
+ return;
+
+ default:
+ break;
+ }
+ }
+}
+
+static void
+folder_selected (EMFolderSelectionButton *button, gpointer user_data)
+{
+ char **folder_name = user_data;
+
+ g_free (*folder_name);
+ *folder_name = g_strdup(em_folder_selection_button_get_selection(button));
+}
+
+static void
+default_folders_clicked (GtkButton *button, gpointer user_data)
+{
+ MailAccountGui *gui = user_data;
+
+ /* Drafts folder */
+ g_free (gui->drafts_folder_uri);
+ gui->drafts_folder_uri = g_strdup(mail_component_get_folder_uri(NULL, MAIL_COMPONENT_FOLDER_DRAFTS));
+ em_folder_selection_button_set_selection((EMFolderSelectionButton *)gui->drafts_folder_button, gui->drafts_folder_uri);
+
+ /* Sent folder */
+ g_free (gui->sent_folder_uri);
+ gui->sent_folder_uri = g_strdup(mail_component_get_folder_uri(NULL, MAIL_COMPONENT_FOLDER_SENT));
+ em_folder_selection_button_set_selection((EMFolderSelectionButton *)gui->sent_folder_button, gui->sent_folder_uri);
+}
+
+GtkWidget *mail_account_gui_folder_selector_button_new (char *widget_name, char *string1, char *string2, int int1, int int2);
+
+GtkWidget *
+mail_account_gui_folder_selector_button_new (char *widget_name,
+ char *string1, char *string2,
+ int int1, int int2)
+{
+ return (GtkWidget *)em_folder_selection_button_new(_("Select Folder"), NULL);
+}
+
+static gboolean
+setup_service (MailAccountGui *gui, MailAccountGuiService *gsvc, EAccountService *service)
+{
+ CamelURL *url = camel_url_new (service->url, NULL);
+ gboolean has_auth = FALSE;
+
+ if (url == NULL || gsvc->provider == NULL)
+ return FALSE;
+
+ if (url->user && CAMEL_PROVIDER_ALLOWS (gsvc->provider, CAMEL_URL_PART_USER))
+ gtk_entry_set_text (gsvc->username, url->user);
+
+ if (url->host && CAMEL_PROVIDER_ALLOWS (gsvc->provider, CAMEL_URL_PART_HOST)) {
+ char *hostname;
+
+ if (url->port)
+ hostname = g_strdup_printf ("%s:%d", url->host, url->port);
+ else
+ hostname = g_strdup (url->host);
+
+ gtk_entry_set_text (gsvc->hostname, hostname);
+ g_free (hostname);
+ }
+
+ if (url->path && CAMEL_PROVIDER_ALLOWS (gsvc->provider, CAMEL_URL_PART_PATH))
+ gtk_entry_set_text (gsvc->path, url->path);
+
+ if (gsvc->provider->flags & CAMEL_PROVIDER_SUPPORTS_SSL) {
+ GList *children, *item;
+ const char *use_ssl;
+ int i;
+
+ use_ssl = camel_url_get_param (url, "use_ssl");
+ if (!use_ssl)
+ use_ssl = "never";
+ else if (!*use_ssl) /* old config code just used an empty string as the value */
+ use_ssl = "always";
+
+ children = gtk_container_get_children(GTK_CONTAINER (gtk_option_menu_get_menu (gsvc->use_ssl)));
+ for (item = children, i = 0; item; item = item->next, i++) {
+ if (!strcmp (use_ssl, ssl_options[i].value)) {
+ gtk_option_menu_set_history (gsvc->use_ssl, i);
+ g_signal_emit_by_name (item->data, "activate", gsvc);
+ break;
+ }
+ }
+ }
+
+ if (url->authmech && CAMEL_PROVIDER_ALLOWS (gsvc->provider, CAMEL_URL_PART_AUTH)) {
+ GList *children, *item;
+ CamelServiceAuthType *authtype;
+ int i;
+
+ children = gtk_container_get_children(GTK_CONTAINER (gtk_option_menu_get_menu (gsvc->authtype)));
+ for (item = children, i = 0; item; item = item->next, i++) {
+ authtype = g_object_get_data ((GObject *) item->data, "authtype");
+ if (!authtype)
+ continue;
+ if (!strcmp (authtype->authproto, url->authmech)) {
+ gtk_option_menu_set_history (gsvc->authtype, i);
+ g_signal_emit_by_name (item->data, "activate");
+ break;
+ }
+ }
+ g_list_free (children);
+
+ has_auth = TRUE;
+ }
+ camel_url_free (url);
+
+ gtk_toggle_button_set_active (gsvc->remember, service->save_passwd);
+
+ gtk_widget_set_sensitive((GtkWidget *)gsvc->authtype, e_account_writable_option(gui->account, gsvc->provider->protocol, "auth"));
+ gtk_widget_set_sensitive((GtkWidget *)gsvc->use_ssl, e_account_writable_option(gui->account, gsvc->provider->protocol, "use_ssl"));
+
+ return has_auth;
+}
+
+static gint
+provider_compare (const CamelProvider *p1, const CamelProvider *p2)
+{
+ /* sort providers based on "location" (ie. local or remote) */
+ if (p1->flags & CAMEL_PROVIDER_IS_REMOTE) {
+ if (p2->flags & CAMEL_PROVIDER_IS_REMOTE)
+ return 0;
+ return -1;
+ } else {
+ if (p2->flags & CAMEL_PROVIDER_IS_REMOTE)
+ return 1;
+ return 0;
+ }
+}
+
+static void
+ssl_option_activate (GtkWidget *widget, gpointer user_data)
+{
+ MailAccountGuiService *service = user_data;
+
+ service->ssl_selected = widget;
+}
+
+static void
+construct_ssl_menu (MailAccountGuiService *service)
+{
+ GtkWidget *menu, *item = NULL;
+ int i;
+
+ menu = gtk_menu_new ();
+
+ for (i = 0; i < num_ssl_options; i++) {
+ item = gtk_menu_item_new_with_label (_(ssl_options[i].label));
+ g_object_set_data ((GObject *) item, "use_ssl", ssl_options[i].value);
+ g_signal_connect (item, "activate", G_CALLBACK (ssl_option_activate), service);
+ gtk_widget_show (item);
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+ }
+
+ gtk_option_menu_remove_menu (service->use_ssl);
+ gtk_option_menu_set_menu (service->use_ssl, menu);
+
+ gtk_option_menu_set_history (service->use_ssl, i - 1);
+ g_signal_emit_by_name (item, "activate", service);
+}
+
+static void
+sig_activate (GtkWidget *item, MailAccountGui *gui)
+{
+ ESignature *sig;
+
+ sig = g_object_get_data ((GObject *) item, "sig");
+
+ gui->sig_uid = sig ? sig->uid : NULL;
+}
+
+static void
+signature_added (ESignatureList *signatures, ESignature *sig, MailAccountGui *gui)
+{
+ GtkWidget *menu, *item;
+
+ menu = gtk_option_menu_get_menu (gui->sig_menu);
+ if (sig->autogen)
+ item = gtk_menu_item_new_with_label (_("Autogenerated"));
+ else
+ item = gtk_menu_item_new_with_label (sig->name);
+ g_object_set_data ((GObject *) item, "sig", sig);
+ g_signal_connect (item, "activate", G_CALLBACK (sig_activate), gui);
+ gtk_widget_show (item);
+
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+
+ gtk_option_menu_set_history (gui->sig_menu, g_list_length (GTK_MENU_SHELL (menu)->children));
+}
+
+static void
+signature_removed (ESignatureList *signatures, ESignature *sig, MailAccountGui *gui)
+{
+ GtkWidget *menu;
+ ESignature *cur;
+ GList *items;
+
+ if (gui->sig_uid == sig->uid)
+ gui->sig_uid = NULL;
+
+ menu = gtk_option_menu_get_menu (gui->sig_menu);
+ items = GTK_MENU_SHELL (menu)->children;
+ while (items != NULL) {
+ cur = g_object_get_data (items->data, "sig");
+ if (cur == sig) {
+ gtk_widget_destroy (items->data);
+ break;
+ }
+ items = items->next;
+ }
+}
+
+static void
+menu_item_set_label (GtkMenuItem *item, const char *label)
+{
+ GtkWidget *widget;
+
+ widget = gtk_bin_get_child ((GtkBin *) item);
+ if (GTK_IS_LABEL (widget))
+ gtk_label_set_text ((GtkLabel *) widget, label);
+}
+
+static void
+signature_changed (ESignatureList *signatures, ESignature *sig, MailAccountGui *gui)
+{
+ GtkWidget *menu;
+ ESignature *cur;
+ GList *items;
+
+ menu = gtk_option_menu_get_menu (gui->sig_menu);
+ items = GTK_MENU_SHELL (menu)->children;
+ while (items != NULL) {
+ cur = g_object_get_data (items->data, "sig");
+ if (cur == sig) {
+ menu_item_set_label (items->data, sig->name);
+ break;
+ }
+ items = items->next;
+ }
+}
+
+static void
+clear_menu (GtkWidget *menu)
+{
+ while (GTK_MENU_SHELL (menu)->children)
+ gtk_container_remove (GTK_CONTAINER (menu), GTK_MENU_SHELL (menu)->children->data);
+}
+
+static void
+sig_fill_menu (MailAccountGui *gui)
+{
+ ESignatureList *signatures;
+ GtkWidget *menu, *item;
+ EIterator *it;
+
+ menu = gtk_option_menu_get_menu (gui->sig_menu);
+ clear_menu (menu);
+
+ item = gtk_menu_item_new_with_label (_("None"));
+ gtk_widget_show (item);
+ g_signal_connect (item, "activate", G_CALLBACK (sig_activate), gui);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+
+ signatures = mail_config_get_signatures ();
+ it = e_list_get_iterator ((EList *) signatures);
+
+ while (e_iterator_is_valid (it)) {
+ ESignature *sig;
+
+ sig = (ESignature *) e_iterator_get (it);
+ signature_added (signatures, sig, gui);
+ e_iterator_next (it);
+ }
+
+ g_object_unref (it);
+
+ gui->sig_added_id = g_signal_connect (signatures, "signature-added", G_CALLBACK (signature_added), gui);
+ gui->sig_removed_id = g_signal_connect (signatures, "signature-removed", G_CALLBACK (signature_removed), gui);
+ gui->sig_changed_id = g_signal_connect (signatures, "signature-changed", G_CALLBACK (signature_changed), gui);
+
+ gtk_option_menu_set_history (gui->sig_menu, 0);
+}
+
+static void
+sig_switch_to_list (GtkWidget *w, MailAccountGui *gui)
+{
+ gtk_window_set_transient_for (GTK_WINDOW (gtk_widget_get_toplevel (w)), NULL);
+ gdk_window_raise (GTK_WIDGET (gui->dialog)->window);
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (glade_xml_get_widget (gui->dialog->gui, "notebook")), 3);
+}
+
+static void
+sig_add_new_signature (GtkWidget *w, MailAccountGui *gui)
+{
+ GConfClient *gconf;
+ gboolean send_html;
+ GtkWidget *parent;
+
+ if (!gui->dialog)
+ return;
+
+ sig_switch_to_list (w, gui);
+
+ gconf = mail_config_get_gconf_client ();
+ send_html = gconf_client_get_bool (gconf, "/apps/evolution/mail/composer/send_html", NULL);
+
+ parent = gtk_widget_get_toplevel (w);
+ parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL;
+
+ em_composer_prefs_new_signature ((GtkWindow *) parent, send_html);
+}
+
+static void
+select_account_signature (MailAccountGui *gui)
+{
+ ESignature *sig, *cur;
+ GtkWidget *menu;
+ GList *items;
+ int i = 0;
+
+ if (!gui->account->id->sig_uid || !(sig = mail_config_get_signature_by_uid (gui->account->id->sig_uid)))
+ return;
+
+ menu = gtk_option_menu_get_menu (gui->sig_menu);
+ items = GTK_MENU_SHELL (menu)->children;
+ while (items != NULL) {
+ cur = g_object_get_data (items->data, "sig");
+ if (cur == sig) {
+ gtk_option_menu_set_history (gui->sig_menu, i);
+ gtk_menu_item_activate (items->data);
+ break;
+ }
+ items = items->next;
+ i++;
+ }
+}
+
+static void
+prepare_signatures (MailAccountGui *gui)
+{
+ GtkWidget *button;
+
+ gui->sig_menu = (GtkOptionMenu *) glade_xml_get_widget (gui->xml, "sigOption");
+ sig_fill_menu (gui);
+
+ button = glade_xml_get_widget (gui->xml, "sigAddNew");
+ g_signal_connect (button, "clicked", G_CALLBACK (sig_add_new_signature), gui);
+
+ if (!gui->dialog) {
+ gtk_widget_hide (glade_xml_get_widget (gui->xml, "sigLabel"));
+ gtk_widget_hide (glade_xml_get_widget (gui->xml, "sigOption"));
+ gtk_widget_hide (glade_xml_get_widget (gui->xml, "sigAddNew"));
+ }
+
+ select_account_signature (gui);
+}
+
+#if defined (HAVE_NSS)
+static void
+smime_changed(MailAccountGui *gui)
+{
+ int act;
+ const char *tmp;
+
+ tmp = gtk_entry_get_text(gui->smime_sign_key);
+ act = tmp && tmp[0];
+ gtk_widget_set_sensitive((GtkWidget *)gui->smime_sign_key_clear, act);
+ gtk_widget_set_sensitive((GtkWidget *)gui->smime_sign_default, act);
+ if (!act)
+ gtk_toggle_button_set_active(gui->smime_sign_default, FALSE);
+
+ tmp = gtk_entry_get_text(gui->smime_encrypt_key);
+ act = tmp && tmp[0];
+ gtk_widget_set_sensitive((GtkWidget *)gui->smime_encrypt_key_clear, act);
+ gtk_widget_set_sensitive((GtkWidget *)gui->smime_encrypt_default, act);
+ gtk_widget_set_sensitive((GtkWidget *)gui->smime_encrypt_to_self, act);
+ if (!act) {
+ gtk_toggle_button_set_active(gui->smime_encrypt_default, FALSE);
+ gtk_toggle_button_set_active(gui->smime_encrypt_to_self, FALSE);
+ }
+}
+
+static void
+smime_sign_key_selected(GtkWidget *dialog, const char *key, MailAccountGui *gui)
+{
+ if (key != NULL) {
+ gtk_entry_set_text(gui->smime_sign_key, key);
+ smime_changed(gui);
+ }
+
+ gtk_widget_destroy(dialog);
+}
+
+static void
+smime_sign_key_select(GtkWidget *button, MailAccountGui *gui)
+{
+ GtkWidget *w;
+
+ w = e_cert_selector_new(E_CERT_SELECTOR_SIGNER, gtk_entry_get_text(gui->smime_sign_key));
+ gtk_window_set_modal((GtkWindow *)w, TRUE);
+ gtk_window_set_transient_for((GtkWindow *)w, (GtkWindow *)gui->dialog);
+ g_signal_connect(w, "selected", G_CALLBACK(smime_sign_key_selected), gui);
+ gtk_widget_show(w);
+}
+
+static void
+smime_sign_key_clear(GtkWidget *w, MailAccountGui *gui)
+{
+ gtk_entry_set_text(gui->smime_sign_key, "");
+ smime_changed(gui);
+}
+
+static void
+smime_encrypt_key_selected(GtkWidget *dialog, const char *key, MailAccountGui *gui)
+{
+ if (key != NULL) {
+ gtk_entry_set_text(gui->smime_encrypt_key, key);
+ smime_changed(gui);
+ }
+
+ gtk_widget_destroy(dialog);
+}
+
+static void
+smime_encrypt_key_select(GtkWidget *button, MailAccountGui *gui)
+{
+ GtkWidget *w;
+
+ w = e_cert_selector_new(E_CERT_SELECTOR_SIGNER, gtk_entry_get_text(gui->smime_encrypt_key));
+ gtk_window_set_modal((GtkWindow *)w, TRUE);
+ gtk_window_set_transient_for((GtkWindow *)w, (GtkWindow *)gui->dialog);
+ g_signal_connect(w, "selected", G_CALLBACK(smime_encrypt_key_selected), gui);
+ gtk_widget_show(w);
+}
+
+static void
+smime_encrypt_key_clear(GtkWidget *w, MailAccountGui *gui)
+{
+ gtk_entry_set_text(gui->smime_encrypt_key, "");
+ smime_changed(gui);
+}
+#endif
+
+#ifdef USE_GTKFILECHOOSER
+static void
+select_file_toggled (GtkToggleButton *toggle, GtkFileChooser *chooser)
+{
+ GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
+
+ if (gtk_toggle_button_get_active (toggle))
+ action = GTK_FILE_CHOOSER_ACTION_OPEN;
+
+ gtk_file_chooser_set_action (chooser, action);
+}
+
+static void
+browse_clicked (GnomeFileEntry *fentry, MailAccountGui *gui)
+{
+ GtkWidget *check;
+ struct stat st;
+ char *path;
+
+ if (GTK_IS_FILE_CHOOSER (fentry->fsw)) {
+ check = gtk_check_button_new_with_label (_("Select a file"));
+ g_signal_connect (check, "toggled", G_CALLBACK (select_file_toggled), fentry->fsw);
+ gtk_widget_show (check);
+ gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (fentry->fsw), check);
+
+ path = gnome_file_entry_get_full_path (fentry, TRUE);
+ if (path && stat (path, &st) == 0 && S_ISREG (st.st_mode))
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), TRUE);
+ else
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), FALSE);
+ gtk_toggle_button_toggled (GTK_TOGGLE_BUTTON (check));
+ g_free (path);
+ }
+
+ g_signal_handlers_disconnect_by_func (fentry, G_CALLBACK (fentry), gui);
+}
+#endif /* USE_GTKFILECHOOSER */
+
+MailAccountGui *
+mail_account_gui_new (EAccount *account, EMAccountPrefs *dialog)
+{
+ MailAccountGui *gui;
+ GtkWidget *fileentry;
+
+ g_object_ref (account);
+
+ gui = g_new0 (MailAccountGui, 1);
+ gui->account = account;
+ gui->dialog = dialog;
+ gui->xml = glade_xml_new (EVOLUTION_GLADEDIR "/mail-config.glade", NULL, NULL);
+
+#ifdef USE_GTKFILECHOOSER
+ /* KLUDGE: If this Evolution was built with GtkFileChooser support, the user
+ * won't be able to create some types of local accounts because GtkFileChooser
+ * must be set to allow selection of one or the other of file vs folder.
+ * However, some providers allow the selection of files *or* folders. */
+ fileentry = glade_xml_get_widget (gui->xml, "source_path_entry");
+ g_signal_connect_after (fileentry, "browse-clicked", G_CALLBACK (browse_clicked), gui);
+#endif
+
+ /* Management */
+ gui->account_name = GTK_ENTRY (glade_xml_get_widget (gui->xml, "management_name"));
+ gui->default_account = GTK_TOGGLE_BUTTON (glade_xml_get_widget (gui->xml, "management_default"));
+ if (account->name)
+ gtk_entry_set_text (gui->account_name, account->name);
+ if (!mail_config_get_default_account ()
+ || (account == mail_config_get_default_account ()))
+ gtk_toggle_button_set_active (gui->default_account, TRUE);
+
+ /* Identity */
+ gui->full_name = GTK_ENTRY (glade_xml_get_widget (gui->xml, "identity_full_name"));
+ gui->email_address = GTK_ENTRY (glade_xml_get_widget (gui->xml, "identity_address"));
+ gui->reply_to = GTK_ENTRY (glade_xml_get_widget (gui->xml, "identity_reply_to"));
+ gui->organization = GTK_ENTRY (glade_xml_get_widget (gui->xml, "identity_organization"));
+
+ if (account->id->name)
+ gtk_entry_set_text (gui->full_name, account->id->name);
+ if (account->id->address)
+ gtk_entry_set_text (gui->email_address, account->id->address);
+ if (account->id->reply_to)
+ gtk_entry_set_text (gui->reply_to, account->id->reply_to);
+ if (account->id->organization)
+ gtk_entry_set_text (gui->organization, account->id->organization);
+
+ prepare_signatures (gui);
+
+ /* Source */
+ gui->source.provider_type = CAMEL_PROVIDER_STORE;
+ gui->source.container = glade_xml_get_widget(gui->xml, "source_vbox");
+ gui->source.type = GTK_OPTION_MENU (glade_xml_get_widget (gui->xml, "source_type_omenu"));
+ gui->source.description = GTK_LABEL (glade_xml_get_widget (gui->xml, "source_description"));
+ gui->source.hostname = GTK_ENTRY (glade_xml_get_widget (gui->xml, "source_host"));
+ g_signal_connect (gui->source.hostname, "changed",
+ G_CALLBACK (service_changed), &gui->source);
+ gui->source.username = GTK_ENTRY (glade_xml_get_widget (gui->xml, "source_user"));
+ g_signal_connect (gui->source.username, "changed",
+ G_CALLBACK (service_changed), &gui->source);
+ gui->source.path = GTK_ENTRY (glade_xml_get_widget (gui->xml, "source_path"));
+ g_signal_connect (gui->source.path, "changed",
+ G_CALLBACK (service_changed), &gui->source);
+ gui->source.ssl_frame = glade_xml_get_widget (gui->xml, "source_security_frame");
+ gtk_widget_hide (gui->source.ssl_frame);
+ gui->source.ssl_hbox = glade_xml_get_widget (gui->xml, "source_ssl_hbox");
+ gui->source.use_ssl = GTK_OPTION_MENU (glade_xml_get_widget (gui->xml, "source_use_ssl"));
+ construct_ssl_menu (&gui->source);
+ gui->source.no_ssl = glade_xml_get_widget (gui->xml, "source_ssl_disabled");
+ gui->source.authtype = GTK_OPTION_MENU (glade_xml_get_widget (gui->xml, "source_auth_omenu"));
+ gui->source.remember = GTK_TOGGLE_BUTTON (glade_xml_get_widget (gui->xml, "source_remember_password"));
+ gui->source.check_supported = GTK_BUTTON (glade_xml_get_widget (gui->xml, "source_check_supported"));
+ g_signal_connect (gui->source.check_supported, "clicked",
+ G_CALLBACK (service_check_supported), &gui->source);
+ gui->source_auto_check = GTK_TOGGLE_BUTTON (glade_xml_get_widget (gui->xml, "extra_auto_check"));
+ gui->source_auto_check_min = GTK_SPIN_BUTTON (glade_xml_get_widget (gui->xml, "extra_auto_check_min"));
+
+ /* Transport */
+ gui->transport.provider_type = CAMEL_PROVIDER_TRANSPORT;
+ gui->transport.container = glade_xml_get_widget(gui->xml, "transport_vbox");
+ gui->transport.type = GTK_OPTION_MENU (glade_xml_get_widget (gui->xml, "transport_type_omenu"));
+ gui->transport.description = GTK_LABEL (glade_xml_get_widget (gui->xml, "transport_description"));
+ gui->transport.hostname = GTK_ENTRY (glade_xml_get_widget (gui->xml, "transport_host"));
+ g_signal_connect (gui->transport.hostname, "changed",
+ G_CALLBACK (service_changed), &gui->transport);
+ gui->transport.username = GTK_ENTRY (glade_xml_get_widget (gui->xml, "transport_user"));
+ g_signal_connect (gui->transport.username, "changed",
+ G_CALLBACK (service_changed), &gui->transport);
+ gui->transport.ssl_frame = glade_xml_get_widget (gui->xml, "transport_security_frame");
+ gtk_widget_hide (gui->transport.ssl_frame);
+ gui->transport.ssl_hbox = glade_xml_get_widget (gui->xml, "transport_ssl_hbox");
+ gui->transport.use_ssl = GTK_OPTION_MENU (glade_xml_get_widget (gui->xml, "transport_use_ssl"));
+ construct_ssl_menu (&gui->transport);
+ gui->transport.no_ssl = glade_xml_get_widget (gui->xml, "transport_ssl_disabled");
+ gui->transport.needs_auth = GTK_TOGGLE_BUTTON (glade_xml_get_widget (gui->xml, "transport_needs_auth"));
+ g_signal_connect (gui->transport.needs_auth, "toggled",
+ G_CALLBACK (transport_needs_auth_toggled), gui);
+ gui->transport.authtype = GTK_OPTION_MENU (glade_xml_get_widget (gui->xml, "transport_auth_omenu"));
+ gui->transport.remember = GTK_TOGGLE_BUTTON (glade_xml_get_widget (gui->xml, "transport_remember_password"));
+ gui->transport.check_supported = GTK_BUTTON (glade_xml_get_widget (gui->xml, "transport_check_supported"));
+ g_signal_connect (gui->transport.check_supported, "clicked",
+ G_CALLBACK (service_check_supported), &gui->transport);
+
+ /* Drafts folder */
+ gui->drafts_folder_button = GTK_BUTTON (glade_xml_get_widget (gui->xml, "drafts_button"));
+ g_signal_connect (gui->drafts_folder_button, "selected", G_CALLBACK (folder_selected), &gui->drafts_folder_uri);
+ if (account->drafts_folder_uri)
+ gui->drafts_folder_uri = em_uri_to_camel (account->drafts_folder_uri);
+ else
+ gui->drafts_folder_uri = g_strdup(mail_component_get_folder_uri(NULL, MAIL_COMPONENT_FOLDER_DRAFTS));
+ em_folder_selection_button_set_selection((EMFolderSelectionButton *)gui->drafts_folder_button, gui->drafts_folder_uri);
+ gtk_widget_show ((GtkWidget *) gui->drafts_folder_button);
+
+ /* Sent folder */
+ gui->sent_folder_button = GTK_BUTTON (glade_xml_get_widget (gui->xml, "sent_button"));
+ g_signal_connect (gui->sent_folder_button, "selected", G_CALLBACK (folder_selected), &gui->sent_folder_uri);
+ if (account->sent_folder_uri)
+ gui->sent_folder_uri = em_uri_to_camel (account->sent_folder_uri);
+ else
+ gui->sent_folder_uri = g_strdup(mail_component_get_folder_uri(NULL, MAIL_COMPONENT_FOLDER_SENT));
+ em_folder_selection_button_set_selection((EMFolderSelectionButton *)gui->sent_folder_button, gui->sent_folder_uri);
+ gtk_widget_show ((GtkWidget *) gui->sent_folder_button);
+
+ /* Special Folders "Reset Defaults" button */
+ gui->restore_folders_button = (GtkButton *)glade_xml_get_widget (gui->xml, "default_folders_button");
+ g_signal_connect (gui->restore_folders_button, "clicked", G_CALLBACK (default_folders_clicked), gui);
+
+ /* Always Cc */
+ gui->always_cc = GTK_TOGGLE_BUTTON (glade_xml_get_widget (gui->xml, "always_cc"));
+ gtk_toggle_button_set_active (gui->always_cc, account->always_cc);
+ gui->cc_addrs = GTK_ENTRY (glade_xml_get_widget (gui->xml, "cc_addrs"));
+ if (account->cc_addrs)
+ gtk_entry_set_text (gui->cc_addrs, account->cc_addrs);
+
+ /* Always Bcc */
+ gui->always_bcc = GTK_TOGGLE_BUTTON (glade_xml_get_widget (gui->xml, "always_bcc"));
+ gtk_toggle_button_set_active (gui->always_bcc, account->always_bcc);
+ gui->bcc_addrs = GTK_ENTRY (glade_xml_get_widget (gui->xml, "bcc_addrs"));
+ if (account->bcc_addrs)
+ gtk_entry_set_text (gui->bcc_addrs, account->bcc_addrs);
+
+ /* Security */
+ gui->pgp_key = GTK_ENTRY (glade_xml_get_widget (gui->xml, "pgp_key"));
+ if (account->pgp_key)
+ gtk_entry_set_text (gui->pgp_key, account->pgp_key);
+ gui->pgp_encrypt_to_self = GTK_TOGGLE_BUTTON (glade_xml_get_widget (gui->xml, "pgp_encrypt_to_self"));
+ gtk_toggle_button_set_active (gui->pgp_encrypt_to_self, account->pgp_encrypt_to_self);
+ gui->pgp_always_sign = GTK_TOGGLE_BUTTON (glade_xml_get_widget (gui->xml, "pgp_always_sign"));
+ gtk_toggle_button_set_active (gui->pgp_always_sign, account->pgp_always_sign);
+ gui->pgp_no_imip_sign = GTK_TOGGLE_BUTTON (glade_xml_get_widget (gui->xml, "pgp_no_imip_sign"));
+ gtk_toggle_button_set_active (gui->pgp_no_imip_sign, account->pgp_no_imip_sign);
+ gui->pgp_always_trust = GTK_TOGGLE_BUTTON (glade_xml_get_widget (gui->xml, "pgp_always_trust"));
+ gtk_toggle_button_set_active (gui->pgp_always_trust, account->pgp_always_trust);
+
+#if defined (HAVE_NSS)
+ gui->smime_sign_key = (GtkEntry *)glade_xml_get_widget (gui->xml, "smime_sign_key");
+ if (account->smime_sign_key)
+ gtk_entry_set_text(gui->smime_sign_key, account->smime_sign_key);
+ gui->smime_sign_key_select = (GtkButton *)glade_xml_get_widget (gui->xml, "smime_sign_key_select");
+ gui->smime_sign_key_clear = (GtkButton *)glade_xml_get_widget (gui->xml, "smime_sign_key_clear");
+ g_signal_connect(gui->smime_sign_key_select, "clicked", G_CALLBACK(smime_sign_key_select), gui);
+ g_signal_connect(gui->smime_sign_key_clear, "clicked", G_CALLBACK(smime_sign_key_clear), gui);
+
+ gui->smime_sign_default = (GtkToggleButton *)glade_xml_get_widget (gui->xml, "smime_sign_default");
+ gtk_toggle_button_set_active(gui->smime_sign_default, account->smime_sign_default);
+
+ gui->smime_encrypt_key = (GtkEntry *)glade_xml_get_widget (gui->xml, "smime_encrypt_key");
+ if (account->smime_encrypt_key)
+ gtk_entry_set_text(gui->smime_encrypt_key, account->smime_encrypt_key);
+ gui->smime_encrypt_key_select = (GtkButton *)glade_xml_get_widget (gui->xml, "smime_encrypt_key_select");
+ gui->smime_encrypt_key_clear = (GtkButton *)glade_xml_get_widget (gui->xml, "smime_encrypt_key_clear");
+ g_signal_connect(gui->smime_encrypt_key_select, "clicked", G_CALLBACK(smime_encrypt_key_select), gui);
+ g_signal_connect(gui->smime_encrypt_key_clear, "clicked", G_CALLBACK(smime_encrypt_key_clear), gui);
+
+ gui->smime_encrypt_default = (GtkToggleButton *)glade_xml_get_widget (gui->xml, "smime_encrypt_default");
+ gtk_toggle_button_set_active(gui->smime_encrypt_default, account->smime_encrypt_default);
+ gui->smime_encrypt_to_self = (GtkToggleButton *)glade_xml_get_widget (gui->xml, "smime_encrypt_to_self");
+ gtk_toggle_button_set_active(gui->smime_encrypt_to_self, account->smime_encrypt_to_self);
+ smime_changed(gui);
+#else
+ {
+ /* Since we don't have NSS, hide the S/MIME config options */
+ GtkWidget *frame;
+
+ frame = glade_xml_get_widget (gui->xml, "smime_vbox");
+ gtk_widget_destroy (frame);
+ }
+#endif /* HAVE_NSS */
+
+ return gui;
+}
+
+void
+mail_account_gui_setup (MailAccountGui *gui, GtkWidget *top)
+{
+ GtkWidget *stores, *transports, *item, *none;
+ GtkWidget *fstore = NULL, *ftransport = NULL;
+ int si = 0, hstore = 0, ti = 0, htransport = 0;
+ int max_width = 0;
+ char *max_authname = NULL;
+ char *source_proto, *transport_proto;
+ GList *providers, *l;
+ gboolean writeable;
+
+ printf("account gui setup\n");
+
+ if (gui->account->source && gui->account->source->url) {
+ source_proto = gui->account->source->url;
+ source_proto = g_strndup (source_proto, strcspn (source_proto, ":"));
+ } else
+ source_proto = NULL;
+
+ if (gui->account->transport && gui->account->transport->url) {
+ transport_proto = gui->account->transport->url;
+ transport_proto = g_strndup (transport_proto, strcspn (transport_proto, ":"));
+ } else
+ transport_proto = NULL;
+
+ /* Construct source/transport option menus */
+ stores = gtk_menu_new ();
+ transports = gtk_menu_new ();
+
+ /* add a "None" option to the stores menu */
+ none = item = gtk_menu_item_new_with_label (_("None"));
+ g_object_set_data ((GObject *) item, "provider", NULL);
+ g_signal_connect (item, "activate", G_CALLBACK (source_type_changed), gui);
+ gtk_menu_shell_append(GTK_MENU_SHELL(stores), item);
+ gtk_widget_show (item);
+ si++;
+
+ providers = camel_provider_list(TRUE);
+
+ /* sort the providers, remote first */
+ providers = g_list_sort (providers, (GCompareFunc) provider_compare);
+
+ for (l = providers; l; l = l->next) {
+ CamelProvider *provider = l->data;
+
+ if (!(!strcmp (provider->domain, "mail") || !strcmp (provider->domain, "news")))
+ continue;
+
+ item = NULL;
+ if (provider->object_types[CAMEL_PROVIDER_STORE] && provider->flags & CAMEL_PROVIDER_IS_SOURCE) {
+ item = gtk_menu_item_new_with_label (provider->name);
+ g_object_set_data ((GObject *) gui->source.type, provider->protocol, item);
+ g_object_set_data ((GObject *) item, "provider", provider);
+ g_object_set_data ((GObject *) item, "number", GUINT_TO_POINTER (si));
+ g_signal_connect (item, "activate", G_CALLBACK (source_type_changed), gui);
+
+ gtk_menu_shell_append(GTK_MENU_SHELL(stores), item);
+
+ gtk_widget_show (item);
+
+ if (!fstore) {
+ fstore = item;
+ hstore = si;
+ }
+
+ if (source_proto && !g_ascii_strcasecmp (provider->protocol, source_proto)) {
+ fstore = item;
+ hstore = si;
+ }
+
+ si++;
+ }
+
+ if (provider->object_types[CAMEL_PROVIDER_TRANSPORT]) {
+ item = gtk_menu_item_new_with_label (provider->name);
+ g_object_set_data ((GObject *) gui->transport.type, provider->protocol, item);
+ g_object_set_data ((GObject *) item, "provider", provider);
+ g_object_set_data ((GObject *) item, "number", GUINT_TO_POINTER (ti));
+ g_signal_connect (item, "activate", G_CALLBACK (transport_type_changed), gui);
+
+ gtk_menu_shell_append(GTK_MENU_SHELL(transports), item);
+
+ gtk_widget_show (item);
+
+ if (CAMEL_PROVIDER_IS_STORE_AND_TRANSPORT (provider))
+ gtk_widget_set_sensitive (item, FALSE);
+
+ if (!ftransport
+ && !CAMEL_PROVIDER_IS_STORE_AND_TRANSPORT (provider)) {
+ ftransport = item;
+ htransport = ti;
+ }
+
+ if (transport_proto && !g_ascii_strcasecmp (provider->protocol, transport_proto)) {
+ ftransport = item;
+ htransport = ti;
+ }
+
+ ti++;
+ }
+
+ if (item && provider->authtypes) {
+ /*GdkFont *font = GTK_WIDGET (item)->style->font;*/
+ CamelServiceAuthType *at;
+ int width;
+ GList *a;
+
+ for (a = provider->authtypes; a; a = a->next) {
+ at = a->data;
+
+ /* Just using string length is probably good enough,
+ as we only use the width of the widget, not the string */
+ /*width = gdk_string_width (font, at->name);*/
+ width = strlen(at->name) * 14;
+ if (width > max_width) {
+ max_authname = at->name;
+ max_width = width;
+ }
+ }
+ }
+ }
+ g_list_free (providers);
+
+ if (!fstore || !source_proto) {
+ fstore = none;
+ hstore = 0;
+ }
+
+ /* set the menus on the optionmenus */
+ gtk_option_menu_remove_menu (gui->source.type);
+ gtk_option_menu_set_menu (gui->source.type, stores);
+
+ gtk_option_menu_remove_menu (gui->transport.type);
+ gtk_option_menu_set_menu (gui->transport.type, transports);
+
+ /* Force the authmenus to the width of the widest element */
+ if (max_authname) {
+ GtkWidget *menu;
+ GtkRequisition size_req;
+
+ menu = gtk_menu_new ();
+ item = gtk_menu_item_new_with_label (max_authname);
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+ gtk_widget_show_all (menu);
+ gtk_option_menu_set_menu (gui->source.authtype, menu);
+ gtk_widget_show (GTK_WIDGET (gui->source.authtype));
+ gtk_widget_size_request (GTK_WIDGET (gui->source.authtype),
+ &size_req);
+
+ gtk_widget_set_size_request (GTK_WIDGET (gui->source.authtype),
+ size_req.width, -1);
+ gtk_widget_set_size_request (GTK_WIDGET (gui->transport.authtype),
+ size_req.width, -1);
+ }
+
+ if (top != NULL) {
+ gtk_widget_show (top);
+ }
+
+ if (fstore) {
+ g_signal_emit_by_name (fstore, "activate");
+ gtk_option_menu_set_history (gui->source.type, hstore);
+ }
+
+ if (ftransport) {
+ g_signal_emit_by_name (ftransport, "activate");
+ gtk_option_menu_set_history (gui->transport.type, htransport);
+ }
+
+ if (source_proto) {
+ setup_service (gui, &gui->source, gui->account->source);
+ gui->source.provider_type = CAMEL_PROVIDER_STORE;
+ g_free (source_proto);
+ if (gui->account->source->auto_check) {
+ gtk_toggle_button_set_active (gui->source_auto_check, TRUE);
+ gtk_spin_button_set_value (gui->source_auto_check_min,
+ gui->account->source->auto_check_time);
+ }
+ }
+
+ if (transport_proto) {
+ if (setup_service (gui, &gui->transport, gui->account->transport))
+ gtk_toggle_button_set_active (gui->transport.needs_auth, TRUE);
+ gui->transport.provider_type = CAMEL_PROVIDER_TRANSPORT;
+ g_free (transport_proto);
+ }
+
+ /* FIXME: drive by table?? */
+ if (!e_account_writable (gui->account, E_ACCOUNT_SOURCE_URL)) {
+ gtk_widget_set_sensitive (gui->source.container, FALSE);
+ } else {
+ gtk_widget_set_sensitive (gui->source.container, TRUE);
+
+ if (gui->source.provider) {
+ writeable = e_account_writable_option (gui->account, gui->source.provider->protocol, "auth");
+ gtk_widget_set_sensitive ((GtkWidget *) gui->source.authtype, writeable);
+ gtk_widget_set_sensitive ((GtkWidget *) gui->source.check_supported, writeable);
+
+ writeable = e_account_writable_option (gui->account, gui->source.provider->protocol, "use_ssl");
+ gtk_widget_set_sensitive ((GtkWidget *) gui->source.use_ssl, writeable);
+
+ writeable = e_account_writable (gui->account, E_ACCOUNT_SOURCE_SAVE_PASSWD);
+ gtk_widget_set_sensitive ((GtkWidget *) gui->source.remember, writeable);
+ }
+ }
+
+ if (!e_account_writable (gui->account, E_ACCOUNT_TRANSPORT_URL)) {
+ gtk_widget_set_sensitive (gui->transport.container, FALSE);
+ } else {
+ gtk_widget_set_sensitive (gui->transport.container, TRUE);
+
+ if (gui->transport.provider) {
+ writeable = e_account_writable_option (gui->account, gui->transport.provider->protocol, "auth");
+ gtk_widget_set_sensitive ((GtkWidget *) gui->transport.authtype, writeable);
+ gtk_widget_set_sensitive ((GtkWidget *) gui->transport.check_supported, writeable);
+
+ writeable = e_account_writable_option (gui->account, gui->transport.provider->protocol, "use_ssl");
+ gtk_widget_set_sensitive ((GtkWidget *) gui->transport.use_ssl, writeable);
+
+ writeable = e_account_writable (gui->account, E_ACCOUNT_TRANSPORT_SAVE_PASSWD);
+ gtk_widget_set_sensitive ((GtkWidget *) gui->transport.remember, writeable);
+ }
+ }
+
+ gtk_widget_set_sensitive((GtkWidget *)gui->drafts_folder_button, e_account_writable(gui->account, E_ACCOUNT_DRAFTS_FOLDER_URI));
+ gtk_widget_set_sensitive((GtkWidget *)gui->sent_folder_button, e_account_writable(gui->account, E_ACCOUNT_SENT_FOLDER_URI));
+ gtk_widget_set_sensitive((GtkWidget *)gui->restore_folders_button,
+ e_account_writable(gui->account, E_ACCOUNT_SENT_FOLDER_URI)
+ || e_account_writable(gui->account, E_ACCOUNT_DRAFTS_FOLDER_URI));
+ gtk_widget_set_sensitive((GtkWidget *)gui->sig_menu, e_account_writable(gui->account, E_ACCOUNT_ID_SIGNATURE));
+ gtk_widget_set_sensitive(glade_xml_get_widget(gui->xml, "sigAddNew"),
+ gconf_client_key_is_writable(mail_config_get_gconf_client(),
+ "/apps/evolution/mail/signatures", NULL));
+ gtk_widget_set_sensitive((GtkWidget *)gui->source_auto_check, e_account_writable(gui->account, E_ACCOUNT_SOURCE_AUTO_CHECK));
+ gtk_widget_set_sensitive((GtkWidget *)gui->source_auto_check_min, e_account_writable(gui->account, E_ACCOUNT_SOURCE_AUTO_CHECK_TIME));
+}
+
+static void
+save_service (MailAccountGuiService *gsvc, GHashTable *extra_config, EAccountService *service)
+{
+ CamelURL *url;
+ const char *str;
+
+ if (!gsvc->provider) {
+ g_free (service->url);
+ service->url = NULL;
+ return;
+ }
+
+ url = g_new0 (CamelURL, 1);
+ url->protocol = g_strdup (gsvc->provider->protocol);
+
+ if (CAMEL_PROVIDER_ALLOWS (gsvc->provider, CAMEL_URL_PART_USER)) {
+ str = gtk_entry_get_text (gsvc->username);
+ if (str && *str)
+ url->user = g_strstrip (g_strdup (str));
+ }
+
+ if (CAMEL_PROVIDER_ALLOWS (gsvc->provider, CAMEL_URL_PART_AUTH) && url->user) {
+ if (gsvc->needs_auth == NULL || gtk_toggle_button_get_active(gsvc->needs_auth)) {
+ CamelServiceAuthType *authtype;
+
+ authtype = g_object_get_data(G_OBJECT(gsvc->authitem), "authtype");
+ if (authtype && authtype->authproto && *authtype->authproto)
+ url->authmech = g_strdup (authtype->authproto);
+ }
+
+ if (gsvc->remember)
+ service->save_passwd = gtk_toggle_button_get_active (gsvc->remember);
+ }
+
+ if (CAMEL_PROVIDER_ALLOWS (gsvc->provider, CAMEL_URL_PART_HOST)) {
+ char *pport;
+
+ str = gtk_entry_get_text (gsvc->hostname);
+ if (str && *str) {
+ pport = strchr (str, ':');
+ if (pport) {
+ url->host = g_strndup (str, pport - str);
+ url->port = atoi (pport + 1);
+ } else
+ url->host = g_strdup (str);
+ }
+ }
+
+ if (CAMEL_PROVIDER_ALLOWS (gsvc->provider, CAMEL_URL_PART_PATH)) {
+ str = gtk_entry_get_text (gsvc->path);
+ if (str && *str)
+ url->path = g_strdup (str);
+ }
+
+ if (gsvc->provider->flags & CAMEL_PROVIDER_SUPPORTS_SSL) {
+ const char *use_ssl;
+
+ use_ssl = g_object_get_data(G_OBJECT(gsvc->ssl_selected), "use_ssl");
+
+ /* set the value to either "always" or "when-possible"
+ but don't bother setting it for "never" */
+ if (strcmp (use_ssl, "never"))
+ camel_url_set_param (url, "use_ssl", use_ssl);
+ }
+
+ if (extra_config)
+ extract_values (gsvc, extra_config, url);
+
+ g_free (service->url);
+ service->url = camel_url_to_string (url, 0);
+
+ /* Temporary until keep_on_server moves into the POP provider */
+ if (camel_url_get_param (url, "keep_on_server"))
+ service->keep_on_server = TRUE;
+
+ camel_url_free (url);
+}
+
+static void
+add_new_store (char *uri, CamelStore *store, void *user_data)
+{
+ MailComponent *component = mail_component_peek ();
+ EAccount *account = user_data;
+
+ if (store == NULL)
+ return;
+
+ mail_component_add_store (component, store, account->name);
+}
+
+gboolean
+mail_account_gui_save (MailAccountGui *gui)
+{
+ EAccount *account, *new;
+ CamelProvider *provider = NULL;
+ gboolean is_new = FALSE;
+ const char *new_name;
+ gboolean is_storage;
+
+ if (!mail_account_gui_identity_complete (gui, NULL) ||
+ !mail_account_gui_source_complete (gui, NULL) ||
+ !mail_account_gui_transport_complete (gui, NULL) ||
+ !mail_account_gui_management_complete (gui, NULL))
+ return FALSE;
+
+ new = gui->account;
+
+ /* this would happen at an inconvenient time in the druid,
+ * but the druid performs its own check so this can't happen
+ * here. */
+
+ new_name = gtk_entry_get_text (gui->account_name);
+ account = mail_config_get_account_by_name (new_name);
+
+ if (account && account != new) {
+ e_error_run((GtkWindow *)gtk_widget_get_toplevel((GtkWidget *)gui->account_name),
+ "mail:account-notunique", NULL);
+ return FALSE;
+ }
+
+ account = new;
+
+ new = e_account_new ();
+ new->name = g_strdup (new_name);
+ new->enabled = account->enabled;
+
+ /* construct the identity */
+ new->id->name = g_strdup (gtk_entry_get_text (gui->full_name));
+ new->id->address = g_strdup (gtk_entry_get_text (gui->email_address));
+ new->id->reply_to = g_strdup (gtk_entry_get_text (gui->reply_to));
+ new->id->organization = g_strdup (gtk_entry_get_text (gui->organization));
+
+ /* signatures */
+ new->id->sig_uid = g_strdup (gui->sig_uid);
+
+ /* source */
+ save_service (&gui->source, gui->extra_config, new->source);
+ if (new->source->url)
+ provider = camel_provider_get(new->source->url, NULL);
+
+ new->source->auto_check = gtk_toggle_button_get_active (gui->source_auto_check);
+ if (new->source->auto_check)
+ new->source->auto_check_time = gtk_spin_button_get_value_as_int (gui->source_auto_check_min);
+
+ /* transport */
+ if (CAMEL_PROVIDER_IS_STORE_AND_TRANSPORT (gui->transport.provider)) {
+ /* The transport URI is the same as the source URI. */
+ save_service (&gui->source, gui->extra_config, new->transport);
+ } else
+ save_service (&gui->transport, NULL, new->transport);
+
+ /* Check to make sure that the Drafts folder uri is "valid" before assigning it */
+ if (gui->drafts_folder_uri != NULL
+ && (mail_config_get_account_by_source_url (gui->drafts_folder_uri) ||
+ !strncmp (gui->drafts_folder_uri, "mbox:", 5))) {
+ new->drafts_folder_uri = em_uri_from_camel (gui->drafts_folder_uri);
+ } else {
+ /* assign defaults - the uri is unknown to us (probably pointed to an old source url) */
+ new->drafts_folder_uri = em_uri_from_camel(mail_component_get_folder_uri(NULL, MAIL_COMPONENT_FOLDER_DRAFTS));
+ }
+
+ /* Check to make sure that the Sent folder uri is "valid" before assigning it */
+ if (gui->sent_folder_uri != NULL
+ && (mail_config_get_account_by_source_url (gui->sent_folder_uri) ||
+ !strncmp (gui->sent_folder_uri, "mbox:", 5))) {
+ new->sent_folder_uri = em_uri_from_camel (gui->sent_folder_uri);
+ } else {
+ /* assign defaults - the uri is unknown to us (probably pointed to an old source url) */
+ new->sent_folder_uri = em_uri_from_camel(mail_component_get_folder_uri(NULL, MAIL_COMPONENT_FOLDER_SENT));
+ }
+
+ new->always_cc = gtk_toggle_button_get_active (gui->always_cc);
+ new->cc_addrs = g_strdup (gtk_entry_get_text (gui->cc_addrs));
+ new->always_bcc = gtk_toggle_button_get_active (gui->always_bcc);
+ new->bcc_addrs = g_strdup (gtk_entry_get_text (gui->bcc_addrs));
+
+ new->pgp_key = g_strdup (gtk_entry_get_text (gui->pgp_key));
+ new->pgp_encrypt_to_self = gtk_toggle_button_get_active (gui->pgp_encrypt_to_self);
+ new->pgp_always_sign = gtk_toggle_button_get_active (gui->pgp_always_sign);
+ new->pgp_no_imip_sign = gtk_toggle_button_get_active (gui->pgp_no_imip_sign);
+ new->pgp_always_trust = gtk_toggle_button_get_active (gui->pgp_always_trust);
+
+#if defined (HAVE_NSS)
+ new->smime_sign_default = gtk_toggle_button_get_active (gui->smime_sign_default);
+ new->smime_sign_key = g_strdup (gtk_entry_get_text (gui->smime_sign_key));
+
+ new->smime_encrypt_default = gtk_toggle_button_get_active (gui->smime_encrypt_default);
+ new->smime_encrypt_key = g_strdup (gtk_entry_get_text (gui->smime_encrypt_key));
+ new->smime_encrypt_to_self = gtk_toggle_button_get_active (gui->smime_encrypt_to_self);
+#endif /* HAVE_NSS */
+
+ is_storage = provider && (provider->flags & CAMEL_PROVIDER_IS_STORAGE);
+
+ if (!mail_config_find_account (account)) {
+ /* this is a new account so add it to our account-list */
+ is_new = TRUE;
+ }
+
+ /* update the old account with the new settings */
+ e_account_import (account, new);
+ g_object_unref (new);
+
+ if (is_new) {
+ mail_config_add_account (account);
+
+ /* if the account provider is something we can stick
+ in the folder-tree and not added by some other
+ component, then get the CamelStore and add it to
+ the folder-tree */
+ if (is_storage && account->enabled)
+ mail_get_store (account->source->url, NULL, add_new_store, account);
+ } else {
+ e_account_list_change (mail_config_get_accounts (), account);
+ }
+
+ if (gtk_toggle_button_get_active (gui->default_account))
+ mail_config_set_default_account (account);
+
+ mail_config_save_accounts ();
+
+ mail_autoreceive_setup ();
+
+ return TRUE;
+}
+
+void
+mail_account_gui_destroy (MailAccountGui *gui)
+{
+ ESignatureList *signatures;
+
+ g_object_unref (gui->xml);
+ g_object_unref (gui->account);
+
+ signatures = mail_config_get_signatures ();
+ g_signal_handler_disconnect (signatures, gui->sig_added_id);
+ g_signal_handler_disconnect (signatures, gui->sig_removed_id);
+ g_signal_handler_disconnect (signatures, gui->sig_changed_id);
+
+ if (gui->extra_config)
+ g_hash_table_destroy (gui->extra_config);
+
+ g_free (gui->drafts_folder_uri);
+ g_free (gui->sent_folder_uri);
+ g_free (gui);
+}
diff --git a/mail/mail-account-gui.h b/mail/mail-account-gui.h
new file mode 100644
index 0000000000..8044041b5e
--- /dev/null
+++ b/mail/mail-account-gui.h
@@ -0,0 +1,146 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors:
+ * Jeffrey Stedfast <fejj@ximian.com>
+ * Dan Winship <danw@ximian.com>
+ *
+ * Copyright 2001-2003 Ximian, Inc. (www.ximian.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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef MAIL_ACCOUNT_GUI_H
+#define MAIL_ACCOUNT_GUI_H
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif /* __cplusplus */
+
+#include <camel/camel-provider.h>
+
+struct _EAccount;
+struct _EMAccountPrefs;
+
+typedef struct _MailAccountGuiService {
+ struct _GtkWidget *container;
+
+ struct _GtkOptionMenu *type;
+ struct _GtkLabel *description;
+ struct _GtkEntry *hostname;
+ struct _GtkEntry *username;
+ struct _GtkEntry *path;
+ struct _GtkWidget *ssl_frame;
+ struct _GtkOptionMenu *use_ssl;
+ struct _GtkWidget *ssl_selected;
+ struct _GtkWidget *ssl_hbox;
+ struct _GtkWidget *no_ssl;
+ struct _GtkOptionMenu *authtype;
+ struct _GtkWidget *authitem;
+ struct _GtkToggleButton *remember;
+ struct _GtkButton *check_supported;
+
+ struct _GtkToggleButton *needs_auth;
+
+ CamelProvider *provider;
+ CamelProviderType provider_type;
+} MailAccountGuiService;
+
+typedef struct _MailAccountGui {
+ struct _EAccount *account;
+ struct _EMAccountPrefs *dialog;
+ struct _GladeXML *xml;
+
+ /* identity */
+ struct _GtkEntry *full_name;
+ struct _GtkEntry *email_address;
+ struct _GtkEntry *reply_to;
+ struct _GtkEntry *organization;
+
+ /* signatures */
+ struct _GtkOptionMenu *sig_menu;
+ guint sig_added_id;
+ guint sig_removed_id;
+ guint sig_changed_id;
+ const char *sig_uid;
+
+ /* incoming mail */
+ MailAccountGuiService source;
+ struct _GtkToggleButton *source_auto_check;
+ struct _GtkSpinButton *source_auto_check_min;
+
+ /* extra incoming config */
+ GHashTable *extra_config;
+
+ /* outgoing mail */
+ MailAccountGuiService transport;
+
+ /* account management */
+ struct _GtkEntry *account_name;
+ struct _GtkToggleButton *default_account;
+
+ /* special folders */
+ struct _GtkButton *drafts_folder_button;
+ char *drafts_folder_uri;
+ struct _GtkButton *sent_folder_button;
+ char *sent_folder_uri;
+ struct _GtkButton *restore_folders_button;
+
+ /* always cc/bcc */
+ struct _GtkToggleButton *always_cc;
+ struct _GtkEntry *cc_addrs;
+ struct _GtkToggleButton *always_bcc;
+ struct _GtkEntry *bcc_addrs;
+
+ /* Security */
+ struct _GtkEntry *pgp_key;
+ struct _GtkToggleButton *pgp_encrypt_to_self;
+ struct _GtkToggleButton *pgp_always_sign;
+ struct _GtkToggleButton *pgp_no_imip_sign;
+ struct _GtkToggleButton *pgp_always_trust;
+
+ struct _GtkToggleButton *smime_sign_default;
+ struct _GtkEntry *smime_sign_key;
+ struct _GtkButton *smime_sign_key_select;
+ struct _GtkButton *smime_sign_key_clear;
+ struct _GtkButton *smime_sign_select;
+ struct _GtkToggleButton *smime_encrypt_default;
+ struct _GtkToggleButton *smime_encrypt_to_self;
+ struct _GtkEntry *smime_encrypt_key;
+ struct _GtkButton *smime_encrypt_key_select;
+ struct _GtkButton *smime_encrypt_key_clear;
+} MailAccountGui;
+
+
+MailAccountGui *mail_account_gui_new (struct _EAccount *account, struct _EMAccountPrefs *dialog);
+void mail_account_gui_setup (MailAccountGui *gui, struct _GtkWidget *top);
+gboolean mail_account_gui_save (MailAccountGui *gui);
+void mail_account_gui_destroy (MailAccountGui *gui);
+
+gboolean mail_account_gui_identity_complete (MailAccountGui *gui, struct _GtkWidget **incomplete);
+gboolean mail_account_gui_source_complete (MailAccountGui *gui, struct _GtkWidget **incomplete);
+gboolean mail_account_gui_transport_complete (MailAccountGui *gui, struct _GtkWidget **incomplete);
+gboolean mail_account_gui_management_complete (MailAccountGui *gui, struct _GtkWidget **incomplete);
+
+void mail_account_gui_build_extra_conf (MailAccountGui *gui, const char *url);
+
+void mail_account_gui_auto_detect_extra_conf (MailAccountGui *gui);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* MAIL_ACCOUNT_GUI_H */
diff --git a/mail/mail-component.c b/mail/mail-component.c
index e51a30268c..8b71bf47e7 100644
--- a/mail/mail-component.c
+++ b/mail/mail-component.c
@@ -35,6 +35,7 @@
#include <fcntl.h>
#include <errno.h>
+#include "em-popup.h"
#include "em-utils.h"
#include "em-composer-utils.h"
#include "em-format.h"
@@ -74,7 +75,6 @@
#include <gal/e-table/e-tree.h>
#include <gal/e-table/e-tree-memory.h>
-#include <libgnome/gnome-i18n.h>
#include <camel/camel-file-utils.h>
#include <camel/camel-vtrash-folder.h>
@@ -98,10 +98,6 @@ struct _store_info {
/* we keep a reference to these so they remain around for the session */
CamelFolder *vtrash;
CamelFolder *vjunk;
-
- /* for setup only */
- void (*done)(CamelStore *store, CamelFolderInfo *info, void *data);
- void *done_data;
};
struct _MailComponentPrivate {
@@ -176,21 +172,6 @@ store_info_free(struct _store_info *si)
g_free(si);
}
-static void
-mc_add_store_done(CamelStore *store, CamelFolderInfo *info, void *data)
-{
- struct _store_info *si = data;
-
- if (si->done)
- si->done(store, info, si);
-
- /* let the counters know about the already opened junk/trash folders */
- if (si->vtrash)
- mail_note_folder(si->vtrash);
- if (si->vjunk)
- mail_note_folder(si->vjunk);
-}
-
/* Utility functions. */
static void
mc_add_store(MailComponent *component, CamelStore *store, const char *name, void (*done)(CamelStore *store, CamelFolderInfo *info, void *data))
@@ -200,10 +181,9 @@ mc_add_store(MailComponent *component, CamelStore *store, const char *name, void
MAIL_COMPONENT_DEFAULT(component);
si = store_info_new(store, name);
- si->done = done;
g_hash_table_insert(component->priv->store_hash, store, si);
em_folder_tree_model_add_store(component->priv->model, store, si->name);
- mail_note_store(store, NULL, mc_add_store_done, si);
+ mail_note_store(store, NULL, done, component);
}
static void
@@ -654,8 +634,6 @@ impl_quit(PortableServer_Servant servant, CORBA_Environment *ev)
int now = time(NULL)/60/60/24, days;
GConfClient *gconf = mail_config_get_gconf_client();
- mail_vfolder_shutdown();
-
mc->priv->quit_expunge = gconf_client_get_bool(gconf, "/apps/evolution/mail/trash/empty_on_exit", NULL)
&& ((days = gconf_client_get_int(gconf, "/apps/evolution/mail/trash/empty_on_exit_days", NULL)) == 0
|| (days + gconf_client_get_int(gconf, "/apps/evolution/mail/trash/empty_date", NULL)) <= now);
@@ -700,7 +678,7 @@ impl__get_userCreatableItems (PortableServer_Servant servant, CORBA_Environment
list->_buffer[1].menuDescription = _("Mail _Folder");
list->_buffer[1].tooltip = _("Create a new mail folder");
list->_buffer[1].menuShortcut = 'f';
- list->_buffer[1].iconName = "stock_new-dir";
+ list->_buffer[1].iconName = "stock_folder";
list->_buffer[1].type = GNOME_Evolution_CREATABLE_FOLDER;
return list;
@@ -775,28 +753,13 @@ handleuri_got_folder(char *uri, CamelFolder *folder, void *data)
EMMessageBrowser *emmb;
if (folder != NULL) {
- const char *reply = camel_url_get_param(url, "reply");
-
- if (reply) {
- int mode;
-
- if (!strcmp(reply, "all"))
- mode = REPLY_MODE_ALL;
- else if (!strcmp(reply, "list"))
- mode = REPLY_MODE_LIST;
- else /* if "sender" or anything else */
- mode = REPLY_MODE_SENDER;
-
- em_utils_reply_to_message(folder, camel_url_get_param(url, "uid"), NULL, mode, NULL);
- } else {
- emmb = (EMMessageBrowser *)em_message_browser_window_new();
- /*message_list_set_threaded(((EMFolderView *)emmb)->list, emfv->list->threaded);*/
- /* FIXME: session needs to be passed easier than this */
- em_format_set_session((EMFormat *)((EMFolderView *)emmb)->preview, session);
- em_folder_view_set_folder((EMFolderView *)emmb, folder, uri);
- em_folder_view_set_message((EMFolderView *)emmb, camel_url_get_param(url, "uid"), FALSE);
- gtk_widget_show(emmb->window);
- }
+ emmb = (EMMessageBrowser *)em_message_browser_window_new();
+ /*message_list_set_threaded(((EMFolderView *)emmb)->list, emfv->list->threaded);*/
+ /* FIXME: session needs to be passed easier than this */
+ em_format_set_session((EMFormat *)((EMFolderView *)emmb)->preview, session);
+ em_folder_view_set_folder((EMFolderView *)emmb, folder, uri);
+ em_folder_view_set_message((EMFolderView *)emmb, camel_url_get_param(url, "uid"), FALSE);
+ gtk_widget_show(emmb->window);
} else {
g_warning("Couldn't open folder '%s'", uri);
}
@@ -900,7 +863,7 @@ mail_component_init (MailComponent *component)
priv->async_event = mail_async_event_new();
priv->store_hash = g_hash_table_new (NULL, NULL);
- mail_autoreceive_init();
+ mail_autoreceive_setup();
offline = mail_offline_handler_new();
bonobo_object_add_interface((BonoboObject *)component, (BonoboObject *)offline);
diff --git a/mail/mail-config-druid.c b/mail/mail-config-druid.c
new file mode 100644
index 0000000000..9cc3283042
--- /dev/null
+++ b/mail/mail-config-druid.c
@@ -0,0 +1,767 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors:
+ * Jeffrey Stedfast <fejj@ximian.com>
+ * Dan Winship <danw@ximian.com>
+ * Iain Holmes <iain@ximian.com>
+ *
+ * Copyright 2001 Ximian, Inc. (www.ximian.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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <gal/util/e-util.h>
+#include <glade/glade.h>
+#include <gtkhtml/gtkhtml.h>
+#include <libgnomeui/gnome-dialog.h>
+#include <libgnomeui/gnome-dialog-util.h>
+#include <libgnomeui/gnome-druid.h>
+#include <libgnomeui/gnome-druid-page-standard.h>
+#include <bonobo/bonobo-exception.h>
+
+#include "mail-config-druid.h"
+#include "mail-config.h"
+#include "mail-ops.h"
+#include "mail-session.h"
+#include "mail-account-gui.h"
+
+#include <evolution-wizard.h>
+#include <e-util/e-account.h>
+#include <e-util/e-icon-factory.h>
+
+typedef enum {
+ MAIL_CONFIG_WIZARD_PAGE_NONE = -1,
+ MAIL_CONFIG_WIZARD_PAGE_IDENTITY,
+ MAIL_CONFIG_WIZARD_PAGE_SOURCE,
+ MAIL_CONFIG_WIZARD_PAGE_EXTRA,
+ MAIL_CONFIG_WIZARD_PAGE_TRANSPORT,
+ MAIL_CONFIG_WIZARD_PAGE_MANAGEMENT,
+
+ MAIL_CONFIG_WIZARD_NUM_PAGES
+} MailConfigWizardPage;
+
+typedef struct {
+ /* Only one of these will be set */
+ GnomeDruid *druid;
+ EvolutionWizard *corba_wizard;
+
+ MailAccountGui *gui;
+
+ GPtrArray *interior_pages;
+ GnomeDruidPage *last_page;
+
+ gboolean identity_copied;
+ CamelProvider *last_source;
+ MailConfigWizardPage page;
+} MailConfigWizard;
+
+static void
+config_wizard_set_buttons_sensitive (MailConfigWizard *mcw,
+ gboolean prev_sensitive,
+ gboolean next_sensitive)
+{
+ if (mcw->corba_wizard) {
+ evolution_wizard_set_buttons_sensitive (mcw->corba_wizard,
+ prev_sensitive,
+ next_sensitive,
+ TRUE, NULL);
+ } else {
+ gnome_druid_set_buttons_sensitive (mcw->druid,
+ prev_sensitive,
+ next_sensitive,
+ TRUE, FALSE);
+ }
+}
+
+static void
+config_wizard_set_page (MailConfigWizard *mcw, MailConfigWizardPage page)
+{
+ if (mcw->corba_wizard)
+ evolution_wizard_set_page (mcw->corba_wizard, page, NULL);
+ else {
+ if (page < mcw->interior_pages->len)
+ gnome_druid_set_page (mcw->druid, mcw->interior_pages->pdata[page]);
+ else
+ gnome_druid_set_page (mcw->druid, mcw->last_page);
+ }
+}
+
+/* Identity Page */
+static void
+identity_changed (GtkWidget *widget, gpointer data)
+{
+ MailConfigWizard *mcw = data;
+ GtkWidget *incomplete;
+ gboolean next_sensitive;
+
+ if (mcw->page != MAIL_CONFIG_WIZARD_PAGE_IDENTITY)
+ return;
+
+ next_sensitive = mail_account_gui_identity_complete (mcw->gui, &incomplete);
+
+ config_wizard_set_buttons_sensitive (mcw, TRUE, next_sensitive);
+}
+
+static void
+identity_prepare (MailConfigWizard *mcw)
+{
+ mcw->page = MAIL_CONFIG_WIZARD_PAGE_IDENTITY;
+
+ if (!gtk_entry_get_text (mcw->gui->full_name)) {
+ char *uname;
+
+ uname = g_locale_to_utf8 (g_get_real_name (), -1, NULL, NULL, NULL);
+ gtk_entry_set_text (mcw->gui->full_name, uname ? uname : "");
+ g_free (uname);
+ }
+ identity_changed (NULL, mcw);
+}
+
+static gboolean
+identity_next (MailConfigWizard *mcw)
+{
+ if (!mcw->identity_copied) {
+ char *username;
+ const char *user;
+
+ /* Copy the username part of the email address into
+ * the Username field of the source and transport pages.
+ */
+ user = gtk_entry_get_text (mcw->gui->email_address);
+ username = g_strndup (user, strcspn (user, "@"));
+ gtk_entry_set_text (mcw->gui->source.username, username);
+ gtk_entry_set_text (mcw->gui->transport.username, username);
+ g_free (username);
+
+ mcw->identity_copied = TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+identity_activate_cb (GtkEntry *ent, gpointer user_data)
+{
+ MailConfigWizard *mcw = user_data;
+
+ if (mail_account_gui_identity_complete (mcw->gui, NULL) &&
+ !identity_next (mcw))
+ config_wizard_set_page (mcw, MAIL_CONFIG_WIZARD_PAGE_SOURCE);
+}
+
+/* Incoming mail Page */
+static void
+source_changed (GtkWidget *widget, gpointer data)
+{
+ MailConfigWizard *mcw = data;
+ GtkWidget *incomplete;
+ gboolean next_sensitive;
+
+ if (mcw->page != MAIL_CONFIG_WIZARD_PAGE_SOURCE)
+ return;
+
+ next_sensitive = mail_account_gui_source_complete (mcw->gui, &incomplete);
+
+ config_wizard_set_buttons_sensitive (mcw, TRUE, next_sensitive);
+}
+
+static void
+source_prepare (MailConfigWizard *mcw)
+{
+ mcw->page = MAIL_CONFIG_WIZARD_PAGE_SOURCE;
+ source_changed (NULL, mcw);
+}
+
+static gboolean
+source_next (MailConfigWizard *mcw)
+{
+ /* FIXME: if online, check that the data is good. */
+
+ if (mcw->gui->source.provider && mcw->gui->source.provider->extra_conf)
+ return FALSE;
+
+ /* Otherwise, skip to transport page. */
+ config_wizard_set_page (mcw, MAIL_CONFIG_WIZARD_PAGE_TRANSPORT);
+ return TRUE;
+}
+
+static void
+source_activate_cb (GtkEntry *ent, gpointer user_data)
+{
+ MailConfigWizard *mcw = user_data;
+
+ if (mail_account_gui_source_complete (mcw->gui, NULL) &&
+ !source_next (mcw))
+ config_wizard_set_page (mcw, MAIL_CONFIG_WIZARD_PAGE_EXTRA);
+}
+
+/* Extra Config Page */
+static void
+extra_prepare (MailConfigWizard *mcw)
+{
+ mcw->page = MAIL_CONFIG_WIZARD_PAGE_EXTRA;
+ if (mcw->gui->source.provider != mcw->last_source) {
+ mcw->last_source = mcw->gui->source.provider;
+ mail_account_gui_auto_detect_extra_conf (mcw->gui);
+ }
+}
+
+/* Transport Page */
+static gboolean
+transport_next (MailConfigWizard *mcw)
+{
+ /* FIXME: if online, check that the data is good. */
+ return FALSE;
+}
+
+static gboolean
+transport_back (MailConfigWizard *mcw)
+{
+ if (mcw->gui->source.provider && mcw->gui->source.provider->extra_conf)
+ return FALSE;
+ else {
+ config_wizard_set_page (mcw, MAIL_CONFIG_WIZARD_PAGE_SOURCE);
+ return TRUE;
+ }
+}
+
+static void
+transport_changed (GtkWidget *widget, gpointer data)
+{
+ MailConfigWizard *mcw = data;
+ GtkWidget *incomplete;
+ gboolean next_sensitive;
+
+ if (mcw->page != MAIL_CONFIG_WIZARD_PAGE_TRANSPORT)
+ return;
+
+ next_sensitive = mail_account_gui_transport_complete (mcw->gui, &incomplete);
+
+ config_wizard_set_buttons_sensitive (mcw, TRUE, next_sensitive);
+}
+
+static void
+transport_prepare (MailConfigWizard *mcw)
+{
+ mcw->page = MAIL_CONFIG_WIZARD_PAGE_TRANSPORT;
+ transport_changed (NULL, mcw);
+}
+
+static void
+transport_activate_cb (GtkEntry *ent, gpointer user_data)
+{
+ MailConfigWizard *mcw = user_data;
+
+ if (mail_account_gui_transport_complete (mcw->gui, NULL) &&
+ !transport_next (mcw))
+ config_wizard_set_page (mcw, MAIL_CONFIG_WIZARD_PAGE_MANAGEMENT);
+}
+
+/* Management page */
+static gboolean
+management_check (MailConfigWizard *mcw)
+{
+ gboolean next_sensitive;
+ const char *text;
+
+ text = gtk_entry_get_text (mcw->gui->account_name);
+ next_sensitive = text && *text;
+
+ /* no accounts with the same name */
+ if (next_sensitive && mail_config_get_account_by_name (text))
+ next_sensitive = FALSE;
+
+ config_wizard_set_buttons_sensitive (mcw, TRUE, next_sensitive);
+ return next_sensitive;
+}
+
+static void
+management_prepare (MailConfigWizard *mcw)
+{
+ const char *name, *text;
+
+ mcw->page = MAIL_CONFIG_WIZARD_PAGE_MANAGEMENT;
+
+ text = gtk_entry_get_text (mcw->gui->account_name);
+ if (!text || *text == '\0') {
+ name = gtk_entry_get_text(mcw->gui->email_address);
+ if (name && *name) {
+ if (mail_config_get_account_by_name (name)) {
+ char *template;
+ unsigned int i = 1, len;
+
+ /* length of name + 1 char for ' ' + 1 char
+ for '(' + 10 chars for %d + 1 char for ')'
+ + 1 char for nul */
+ len = strlen (name);
+ template = alloca (len + 14);
+ strcpy (template, name);
+ name = template;
+ do {
+ sprintf (template + len, " (%d)", i++);
+ } while (mail_config_get_account_by_name (name) && i != 0);
+ }
+
+ gtk_entry_set_text(mcw->gui->account_name, name);
+ }
+ }
+
+ management_check (mcw);
+}
+
+static void
+management_changed (GtkWidget *widget, gpointer data)
+{
+ MailConfigWizard *mcw = data;
+
+ if (mcw->page != MAIL_CONFIG_WIZARD_PAGE_MANAGEMENT)
+ return;
+
+ management_check (mcw);
+}
+
+static void
+management_activate_cb (GtkEntry *ent, gpointer user_data)
+{
+ MailConfigWizard *mcw = user_data;
+
+ if (management_check (mcw))
+ config_wizard_set_page (mcw, mcw->page + 1);
+}
+
+static struct {
+ const char *page_name, *title, *icon_name;
+ void (*prepare_func) (MailConfigWizard *mcw);
+ gboolean (*back_func) (MailConfigWizard *mcw);
+ gboolean (*next_func) (MailConfigWizard *mcw);
+ const char *help_text;
+} wizard_pages[] = {
+ { "identity_page", N_("Identity"), "stock_contact",
+ identity_prepare, NULL, identity_next,
+ N_("Please enter your name and email address below. "
+ "The \"optional\" fields below do not need to be "
+ "filled in, unless you wish to include this "
+ "information in email you send.")
+ },
+
+ { "source_page", N_("Receiving Mail"), "stock_mail-receive",
+ source_prepare, NULL, source_next,
+ N_("Please enter information about your incoming "
+ "mail server below. If you are not sure, ask your "
+ "system administrator or Internet Service Provider.")
+ },
+
+ { "extra_page", N_("Receiving Mail"), "stock_mail-receive",
+ extra_prepare, NULL, NULL,
+ N_("Please select among the following options")
+ },
+
+ { "transport_page", N_("Sending Mail"), "stock_mail-send",
+ transport_prepare, transport_back, transport_next,
+ N_("Please enter information about the way you will "
+ "send mail. If you are not sure, ask your system "
+ "administrator or Internet Service Provider.")
+ },
+
+ { "management_page", N_("Account Management"), "stock_person",
+ management_prepare, NULL, NULL,
+ N_("You are almost done with the mail configuration "
+ "process. The identity, incoming mail server and "
+ "outgoing mail transport method which you provided "
+ "will be grouped together to make an Evolution mail "
+ "account. Please enter a name for this account in "
+ "the space below. This name will be used for display "
+ "purposes only.")
+ }
+};
+static const int num_wizard_pages = sizeof (wizard_pages) / sizeof (wizard_pages[0]);
+
+static GtkWidget *
+get_page (GladeXML *xml, int page_num)
+{
+ GtkWidget *vbox, *widget;
+
+ vbox = gtk_vbox_new (FALSE, 4);
+
+ widget = gtk_label_new (_(wizard_pages[page_num].help_text));
+ gtk_label_set_line_wrap (GTK_LABEL (widget), TRUE);
+ gtk_label_set_justify (GTK_LABEL (widget), GTK_JUSTIFY_FILL);
+ gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0);
+ gtk_widget_show_all (vbox);
+
+ switch (page_num) {
+ case MAIL_CONFIG_WIZARD_PAGE_IDENTITY:
+ widget = glade_xml_get_widget (xml, "identity_required_frame");
+ gtk_container_set_border_width (GTK_CONTAINER (widget), 0);
+ gtk_widget_reparent (widget, vbox);
+ gtk_box_set_child_packing (GTK_BOX (vbox), widget, FALSE, FALSE, 0, GTK_PACK_START);
+ widget = glade_xml_get_widget (xml, "identity_optional_frame");
+ gtk_container_set_border_width (GTK_CONTAINER (widget), 0);
+ gtk_widget_reparent (widget, vbox);
+ gtk_box_set_child_packing (GTK_BOX (vbox), widget, FALSE, FALSE, 0, GTK_PACK_START);
+ break;
+
+ case MAIL_CONFIG_WIZARD_PAGE_SOURCE:
+ widget = glade_xml_get_widget (xml, "source_vbox");
+ gtk_container_set_border_width (GTK_CONTAINER (widget), 0);
+ gtk_widget_reparent (widget, vbox);
+ break;
+
+ case MAIL_CONFIG_WIZARD_PAGE_EXTRA:
+ widget = glade_xml_get_widget (xml, "extra_table");
+ gtk_container_set_border_width (GTK_CONTAINER (widget), 0);
+ gtk_widget_reparent (widget, vbox);
+ break;
+
+ case MAIL_CONFIG_WIZARD_PAGE_TRANSPORT:
+ widget = glade_xml_get_widget (xml, "transport_vbox");
+ gtk_container_set_border_width (GTK_CONTAINER (widget), 0);
+ gtk_widget_reparent (widget, vbox);
+ break;
+
+ case MAIL_CONFIG_WIZARD_PAGE_MANAGEMENT:
+ widget = glade_xml_get_widget (xml, "management_frame");
+ gtk_container_set_border_width (GTK_CONTAINER (widget), 0);
+ gtk_widget_reparent (widget, vbox);
+ break;
+
+ default:
+ g_return_val_if_reached (NULL);
+ }
+
+ return vbox;
+}
+
+
+static MailConfigWizard *
+config_wizard_new (void)
+{
+ MailConfigWizard *mcw;
+ const char *user;
+ EAccountService *xport;
+ struct utsname uts;
+ EAccount *account;
+
+ /* Create a new account object with some defaults */
+ account = e_account_new ();
+ account->enabled = TRUE;
+
+ account->id->name = g_locale_to_utf8 (g_get_real_name (), -1, NULL, NULL, NULL);
+ user = g_get_user_name ();
+ if (user && !uname (&uts) && strchr (uts.nodename, '.'))
+ account->id->address = g_strdup_printf ("%s@%s", user, uts.nodename);
+
+ if ((xport = mail_config_get_default_transport ())) {
+ account->transport->url = g_strdup (xport->url);
+ account->transport->save_passwd = xport->save_passwd;
+ }
+
+ /* Create the config wizard object */
+ mcw = g_new0 (MailConfigWizard, 1);
+ mcw->gui = mail_account_gui_new (account, NULL);
+ g_object_unref (account);
+
+ /* Set up gui */
+ g_signal_connect (mcw->gui->account_name, "changed",
+ G_CALLBACK (management_changed), mcw);
+ g_signal_connect (mcw->gui->full_name, "changed",
+ G_CALLBACK (identity_changed), mcw);
+ g_signal_connect (mcw->gui->email_address, "changed",
+ G_CALLBACK (identity_changed), mcw);
+ g_signal_connect (mcw->gui->reply_to,"changed",
+ G_CALLBACK (identity_changed), mcw);
+ g_signal_connect (mcw->gui->source.hostname, "changed",
+ G_CALLBACK (source_changed), mcw);
+ g_signal_connect (mcw->gui->source.username, "changed",
+ G_CALLBACK (source_changed), mcw);
+ g_signal_connect (mcw->gui->source.path, "changed",
+ G_CALLBACK (source_changed), mcw);
+ g_signal_connect (mcw->gui->transport.hostname, "changed",
+ G_CALLBACK (transport_changed), mcw);
+ g_signal_connect (mcw->gui->transport.username, "changed",
+ G_CALLBACK (transport_changed), mcw);
+ g_signal_connect (mcw->gui->transport.needs_auth, "toggled",
+ G_CALLBACK (transport_changed), mcw);
+
+ g_signal_connect (mcw->gui->account_name, "activate",
+ G_CALLBACK (management_activate_cb), mcw);
+
+ g_signal_connect (mcw->gui->full_name, "activate",
+ G_CALLBACK (identity_activate_cb), mcw);
+ g_signal_connect (mcw->gui->email_address, "activate",
+ G_CALLBACK (identity_activate_cb), mcw);
+ g_signal_connect (mcw->gui->reply_to,"activate",
+ G_CALLBACK (identity_activate_cb), mcw);
+ g_signal_connect (mcw->gui->organization, "activate",
+ G_CALLBACK (identity_activate_cb), mcw);
+
+ g_signal_connect (mcw->gui->source.hostname, "activate",
+ G_CALLBACK (source_activate_cb), mcw);
+ g_signal_connect (mcw->gui->source.username, "activate",
+ G_CALLBACK (source_activate_cb), mcw);
+ g_signal_connect (mcw->gui->source.path, "activate",
+ G_CALLBACK (source_activate_cb), mcw);
+
+ g_signal_connect (mcw->gui->transport.hostname, "activate",
+ G_CALLBACK (transport_activate_cb), mcw);
+ g_signal_connect (mcw->gui->transport.username, "activate",
+ G_CALLBACK (transport_activate_cb), mcw);
+
+ return mcw;
+}
+
+static void
+free_config_wizard (MailConfigWizard *mcw)
+{
+ mail_account_gui_destroy (mcw->gui);
+
+ if (mcw->interior_pages)
+ g_ptr_array_free (mcw->interior_pages, TRUE);
+
+ g_free (mcw);
+}
+
+/* In-proc config druid */
+
+static void
+druid_cancel (GnomeDruid *druid, gpointer user_data)
+{
+ MailConfigWizard *mcw = user_data;
+ GtkWidget *window;
+
+ window = glade_xml_get_widget (mcw->gui->xml, "account_druid");
+ gtk_widget_destroy (window);
+
+ free_config_wizard (mcw);
+}
+
+static void
+druid_finish (GnomeDruidPage *page, GnomeDruid *druid, gpointer user_data)
+{
+ MailConfigWizard *mcw = user_data;
+
+ mail_account_gui_save (mcw->gui);
+ druid_cancel (druid, user_data);
+}
+
+static void
+druid_prepare (GnomeDruidPage *page, GnomeDruid *druid, gpointer data)
+{
+ MailConfigWizard *mcw = g_object_get_data (G_OBJECT (druid), "MailConfigWizard");
+ int page_num = GPOINTER_TO_INT (data);
+
+ if (wizard_pages[page_num].prepare_func)
+ wizard_pages[page_num].prepare_func (mcw);
+}
+
+static gboolean
+druid_back (GnomeDruidPage *page, GnomeDruid *druid, gpointer data)
+{
+ MailConfigWizard *mcw = g_object_get_data (G_OBJECT (druid), "MailConfigWizard");
+ int page_num = GPOINTER_TO_INT (data);
+
+ if (wizard_pages[page_num].back_func)
+ return wizard_pages[page_num].back_func (mcw);
+ else
+ return FALSE;
+}
+
+static gboolean
+druid_next (GnomeDruidPage *page, GnomeDruid *druid, gpointer data)
+{
+ MailConfigWizard *mcw = g_object_get_data (G_OBJECT (druid), "MailConfigWizard");
+ int page_num = GPOINTER_TO_INT (data);
+
+ if (wizard_pages[page_num].next_func)
+ return wizard_pages[page_num].next_func (mcw);
+ else
+ return FALSE;
+}
+
+
+MailConfigDruid *
+mail_config_druid_new (void)
+{
+ MailConfigWizard *mcw;
+ GtkWidget *new, *page;
+ GdkPixbuf *icon;
+ int i;
+
+ mcw = config_wizard_new ();
+ mcw->druid = (GnomeDruid *)glade_xml_get_widget (mcw->gui->xml, "druid");
+ g_object_set_data (G_OBJECT (mcw->druid), "MailConfigWizard", mcw);
+ gtk_widget_show_all (GTK_WIDGET (mcw->druid));
+
+ mcw->interior_pages = g_ptr_array_new ();
+ for (i = 0; i < num_wizard_pages; i++) {
+ page = glade_xml_get_widget (mcw->gui->xml,
+ wizard_pages[i].page_name);
+ icon = e_icon_factory_get_icon (wizard_pages[i].icon_name, E_ICON_SIZE_DIALOG);
+ gnome_druid_page_standard_set_logo (GNOME_DRUID_PAGE_STANDARD (page), icon);
+ g_object_unref (icon);
+ g_ptr_array_add (mcw->interior_pages, page);
+ gtk_box_pack_start (GTK_BOX (GNOME_DRUID_PAGE_STANDARD (page)->vbox),
+ get_page (mcw->gui->xml, i),
+ FALSE, FALSE, 0);
+ g_signal_connect (page, "back", G_CALLBACK (druid_back),
+ GINT_TO_POINTER (i));
+ g_signal_connect (page, "next", G_CALLBACK (druid_next),
+ GINT_TO_POINTER (i));
+
+ /* At least in 2.0 (and probably 2.2 too),
+ * GnomeDruidPageStandard is broken and you need to
+ * connect_after to "prepare" or else its default
+ * method will run after your signal handler and
+ * undo its button sensitivity changes.
+ */
+ g_signal_connect_after (page, "prepare",
+ G_CALLBACK (druid_prepare),
+ GINT_TO_POINTER (i));
+ }
+ g_signal_connect (mcw->druid, "cancel", G_CALLBACK (druid_cancel), mcw);
+
+ mcw->last_page = (GnomeDruidPage *)glade_xml_get_widget (mcw->gui->xml, "finish_page");
+ g_signal_connect (mcw->last_page, "finish", G_CALLBACK (druid_finish), mcw);
+
+ gnome_druid_set_buttons_sensitive (mcw->druid, FALSE, TRUE, TRUE, FALSE);
+ /*gtk_widget_show_all (GTK_WIDGET (mcw->druid));*/
+ mail_account_gui_setup (mcw->gui, NULL);
+
+ new = glade_xml_get_widget (mcw->gui->xml, "account_druid");
+ gtk_window_set_type_hint ((GtkWindow *) new, GDK_WINDOW_TYPE_HINT_DIALOG);
+
+ return (MailConfigDruid *) new;
+}
+
+
+/* CORBA wizard */
+
+static void
+wizard_next_cb (EvolutionWizard *wizard,
+ int page_num,
+ MailConfigWizard *mcw)
+{
+ if (page_num >= MAIL_CONFIG_WIZARD_PAGE_MANAGEMENT)
+ return;
+
+ if (wizard_pages[page_num].next_func &&
+ wizard_pages[page_num].next_func (mcw))
+ return;
+
+ evolution_wizard_set_page (wizard, page_num + 1, NULL);
+}
+
+static void
+wizard_prepare_cb (EvolutionWizard *wizard,
+ int page_num,
+ MailConfigWizard *mcw)
+{
+ if (wizard_pages[page_num].prepare_func)
+ wizard_pages[page_num].prepare_func (mcw);
+}
+
+static void
+wizard_back_cb (EvolutionWizard *wizard,
+ int page_num,
+ MailConfigWizard *mcw)
+{
+ if (page_num >= MAIL_CONFIG_WIZARD_NUM_PAGES) {
+ evolution_wizard_set_page (wizard, MAIL_CONFIG_WIZARD_PAGE_MANAGEMENT, NULL);
+ return;
+ }
+
+ if (wizard_pages[page_num].back_func &&
+ wizard_pages[page_num].back_func (mcw))
+ return;
+
+ if (page_num > 0)
+ evolution_wizard_set_page (wizard, page_num - 1, NULL);
+}
+
+static void
+wizard_finish_cb (EvolutionWizard *wizard,
+ MailConfigWizard *w)
+{
+ MailAccountGui *gui = w->gui;
+
+ /* Save the settings for that account */
+ if (mail_account_gui_save (gui) == FALSE)
+ /* problem. Um, how to keep the druid alive? */
+ return;
+
+ /* Write out the config info */
+ mail_config_write ();
+ mail_account_gui_destroy (gui);
+ w->gui = NULL;
+}
+
+static void
+wizard_cancel_cb (EvolutionWizard *wizard,
+ MailConfigWizard *mcw)
+{
+ mail_account_gui_destroy (mcw->gui);
+ mcw->gui = NULL;
+}
+
+static void
+wizard_help_cb (EvolutionWizard *wizard,
+ int page_num,
+ MailConfigWizard *mcw)
+{
+}
+
+BonoboObject *
+evolution_mail_config_wizard_new (void)
+{
+ EvolutionWizard *wizard;
+ MailConfigWizard *mcw;
+ GdkPixbuf *icon;
+ int i;
+
+ mcw = config_wizard_new ();
+ mail_account_gui_setup (mcw->gui, NULL);
+
+ wizard = evolution_wizard_new ();
+ for (i = 0; i < MAIL_CONFIG_WIZARD_NUM_PAGES; i++) {
+ icon = e_icon_factory_get_icon (wizard_pages[i].icon_name, E_ICON_SIZE_DIALOG);
+ evolution_wizard_add_page (wizard, _(wizard_pages[i].title),
+ icon, get_page (mcw->gui->xml, i));
+ g_object_unref (icon);
+ }
+
+ g_object_set_data_full (G_OBJECT (wizard), "MailConfigWizard",
+ mcw, (GDestroyNotify)free_config_wizard);
+ mcw->corba_wizard = wizard;
+
+ g_signal_connect (wizard, "next", G_CALLBACK (wizard_next_cb), mcw);
+ g_signal_connect (wizard, "prepare", G_CALLBACK (wizard_prepare_cb), mcw);
+ g_signal_connect (wizard, "back", G_CALLBACK (wizard_back_cb), mcw);
+ g_signal_connect (wizard, "finish", G_CALLBACK (wizard_finish_cb), mcw);
+ g_signal_connect (wizard, "cancel", G_CALLBACK (wizard_cancel_cb), mcw);
+ g_signal_connect (wizard, "help", G_CALLBACK (wizard_help_cb), mcw);
+
+ return BONOBO_OBJECT (wizard);
+}
diff --git a/mail/mail-config.c b/mail/mail-config.c
index 0d0943b254..c1c8adf02d 100644
--- a/mail/mail-config.c
+++ b/mail/mail-config.c
@@ -54,6 +54,7 @@
#include <gal/util/e-util.h>
#include <gal/widgets/e-gui-utils.h>
+#include <e-util/e-url.h>
#include <e-util/e-passwords.h>
#include <e-util/e-account-list.h>
#include <e-util/e-signature-list.h>
diff --git a/mail/mail-config.glade b/mail/mail-config.glade
index 4df8207e26..2103e332e5 100644
--- a/mail/mail-config.glade
+++ b/mail/mail-config.glade
@@ -41,31 +41,10 @@ Click &quot;Forward&quot; to begin. </property>
<child internal-child="vbox">
<widget class="GtkVBox" id="druid_identity_vbox">
- <property name="border_width">12</property>
+ <property name="border_width">16</property>
<property name="visible">True</property>
<property name="homogeneous">False</property>
- <property name="spacing">12</property>
-
- <child>
- <widget class="GtkLabel" id="identity_help">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Please enter your name and email address below. The &quot;optional&quot; fields below do not need to be filled in, unless you wish to include this information in email you send.</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">True</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- </packing>
- </child>
+ <property name="spacing">0</property>
<child>
<placeholder/>
@@ -82,31 +61,30 @@ Click &quot;Forward&quot; to begin. </property>
<child internal-child="vbox">
<widget class="GtkVBox" id="druid_source_vbox">
- <property name="border_width">12</property>
+ <property name="border_width">16</property>
<property name="visible">True</property>
<property name="homogeneous">False</property>
- <property name="spacing">12</property>
+ <property name="spacing">0</property>
<child>
- <widget class="GtkLabel" id="extra_help">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Please select among the following options</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">True</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- </packing>
+ <placeholder/>
</child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GnomeDruidPageStandard" id="extra_page">
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">Receiving Email</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="druid_extra_vbox">
+ <property name="border_width">16</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
<child>
<placeholder/>
@@ -123,31 +101,10 @@ Click &quot;Forward&quot; to begin. </property>
<child internal-child="vbox">
<widget class="GtkVBox" id="druid_transport_vbox">
- <property name="border_width">12</property>
+ <property name="border_width">16</property>
<property name="visible">True</property>
<property name="homogeneous">False</property>
- <property name="spacing">12</property>
-
- <child>
- <widget class="GtkLabel" id="transport_help">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Please enter information about the way you will send mail. If you are not sure, ask your system administrator or Internet Service Provider.</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">True</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- </packing>
- </child>
+ <property name="spacing">0</property>
<child>
<placeholder/>
@@ -164,32 +121,10 @@ Click &quot;Forward&quot; to begin. </property>
<child internal-child="vbox">
<widget class="GtkVBox" id="druid_management_vbox">
- <property name="border_width">12</property>
+ <property name="border_width">16</property>
<property name="visible">True</property>
<property name="homogeneous">False</property>
- <property name="spacing">12</property>
-
- <child>
- <widget class="GtkLabel" id="management_help">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Please enter a descriptive name for this account in the space below.
-This name will be used for display purposes only.</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">True</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- </packing>
- </child>
+ <property name="spacing">0</property>
<child>
<placeholder/>
@@ -376,7 +311,7 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<property name="max_length">0</property>
<property name="text" translatable="yes"></property>
<property name="has_frame">True</property>
- <property name="invisible_char">*</property>
+ <property name="invisible_char" translatable="yes">*</property>
<property name="activates_default">False</property>
</widget>
<packing>
@@ -503,7 +438,7 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<property name="max_length">0</property>
<property name="text" translatable="yes"></property>
<property name="has_frame">True</property>
- <property name="invisible_char">*</property>
+ <property name="invisible_char" translatable="yes">*</property>
<property name="activates_default">False</property>
</widget>
<packing>
@@ -574,7 +509,7 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<property name="max_length">0</property>
<property name="text" translatable="yes"></property>
<property name="has_frame">True</property>
- <property name="invisible_char">*</property>
+ <property name="invisible_char" translatable="yes">*</property>
<property name="activates_default">False</property>
</widget>
<packing>
@@ -691,7 +626,7 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
- <property name="mnemonic_widget">signature_dropdown</property>
+ <property name="mnemonic_widget">sigOption</property>
</widget>
<packing>
<property name="left_attach">0</property>
@@ -710,12 +645,24 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<property name="spacing">6</property>
<child>
- <widget class="Custom" id="signature_dropdown">
+ <widget class="GtkOptionMenu" id="sigOption">
<property name="visible">True</property>
- <property name="creation_function">em_account_editor_dropdown_new</property>
- <property name="int1">0</property>
- <property name="int2">0</property>
- <property name="last_modification_time">Mon, 06 Sep 2004 01:00:22 GMT</property>
+ <property name="can_focus">True</property>
+ <property name="history">0</property>
+
+ <child internal-child="menu">
+ <widget class="GtkMenu" id="convertwidget1">
+ <property name="visible">True</property>
+
+ <child>
+ <widget class="GtkMenuItem" id="convertwidget2">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Default</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
</widget>
<packing>
<property name="padding">0</property>
@@ -761,7 +708,7 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<property name="max_length">0</property>
<property name="text" translatable="yes"></property>
<property name="has_frame">True</property>
- <property name="invisible_char">*</property>
+ <property name="invisible_char" translatable="yes">*</property>
<property name="activates_default">False</property>
</widget>
<packing>
@@ -807,7 +754,7 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<property name="max_length">0</property>
<property name="text" translatable="yes"></property>
<property name="has_frame">True</property>
- <property name="invisible_char">*</property>
+ <property name="invisible_char" translatable="yes">*</property>
<property name="activates_default">False</property>
</widget>
<packing>
@@ -947,7 +894,7 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
- <property name="mnemonic_widget">source_type_dropdown</property>
+ <property name="mnemonic_widget">source_type_omenu</property>
</widget>
<packing>
<property name="left_attach">0</property>
@@ -1008,12 +955,56 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
</child>
<child>
- <widget class="Custom" id="source_type_dropdown">
+ <widget class="GtkOptionMenu" id="source_type_omenu">
<property name="visible">True</property>
- <property name="creation_function">em_account_editor_dropdown_new</property>
- <property name="int1">0</property>
- <property name="int2">0</property>
- <property name="last_modification_time">Thu, 29 Jul 2004 05:31:24 GMT</property>
+ <property name="can_focus">True</property>
+ <property name="history">0</property>
+
+ <child internal-child="menu">
+ <widget class="GtkMenu" id="convertwidget3">
+ <property name="visible">True</property>
+
+ <child>
+ <widget class="GtkMenuItem" id="convertwidget4">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">POP</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="convertwidget5">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">IMAPv4 </property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="convertwidget6">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Standard Unix mbox</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="convertwidget7">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Qmail maildir </property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="convertwidget8">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">None</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
</widget>
<packing>
<property name="left_attach">1</property>
@@ -1174,7 +1165,7 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<property name="max_length">0</property>
<property name="text" translatable="yes"></property>
<property name="has_frame">True</property>
- <property name="invisible_char">*</property>
+ <property name="invisible_char" translatable="yes">*</property>
<property name="activates_default">False</property>
</widget>
<packing>
@@ -1195,7 +1186,7 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<property name="max_length">0</property>
<property name="text" translatable="yes"></property>
<property name="has_frame">True</property>
- <property name="invisible_char">*</property>
+ <property name="invisible_char" translatable="yes">*</property>
<property name="activates_default">False</property>
</widget>
<packing>
@@ -1240,7 +1231,6 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<property name="directory_entry">False</property>
<property name="modal">False</property>
<property name="use_filechooser">True</property>
- <property name="filechooser_action">GTK_FILE_CHOOSER_ACTION_OPEN</property>
<child internal-child="entry">
<widget class="GtkEntry" id="source_path">
@@ -1251,7 +1241,7 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<property name="max_length">0</property>
<property name="text" translatable="yes"></property>
<property name="has_frame">True</property>
- <property name="invisible_char">*</property>
+ <property name="invisible_char" translatable="yes">*</property>
<property name="activates_default">False</property>
</widget>
</child>
@@ -1363,7 +1353,7 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<child>
<widget class="GtkLabel" id="lblSourceUseSSL">
<property name="visible">True</property>
- <property name="label" translatable="yes">_Use Secure Connection:</property>
+ <property name="label" translatable="yes">_Use Secure Connection (SSL):</property>
<property name="use_underline">True</property>
<property name="use_markup">False</property>
<property name="justify">GTK_JUSTIFY_CENTER</property>
@@ -1383,12 +1373,40 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
</child>
<child>
- <widget class="Custom" id="source_use_ssl">
+ <widget class="GtkOptionMenu" id="source_use_ssl">
<property name="visible">True</property>
- <property name="creation_function">em_account_editor_ssl_selector_new</property>
- <property name="int1">0</property>
- <property name="int2">0</property>
- <property name="last_modification_time">Tue, 03 Aug 2004 07:22:52 GMT</property>
+ <property name="can_focus">True</property>
+ <property name="history">0</property>
+
+ <child internal-child="menu">
+ <widget class="GtkMenu" id="convertwidget9">
+ <property name="visible">True</property>
+
+ <child>
+ <widget class="GtkMenuItem" id="convertwidget10">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Always</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="convertwidget11">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Whenever Possible</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="convertwidget12">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Never</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
</widget>
<packing>
<property name="padding">0</property>
@@ -1430,7 +1448,7 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<child>
<widget class="GtkLabel" id="label514">
<property name="visible">True</property>
- <property name="label" translatable="yes">&lt;b&gt;SSL is not supported in this build of Evolution&lt;/b&gt;</property>
+ <property name="label" translatable="yes">&lt;b&gt;SSL is not supported in this build of evolution&lt;/b&gt;</property>
<property name="use_underline">False</property>
<property name="use_markup">True</property>
<property name="justify">GTK_JUSTIFY_CENTER</property>
@@ -1543,12 +1561,32 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<property name="spacing">6</property>
<child>
- <widget class="Custom" id="source_auth_dropdown">
+ <widget class="GtkOptionMenu" id="source_auth_omenu">
<property name="visible">True</property>
- <property name="creation_function">em_account_editor_dropdown_new</property>
- <property name="int1">0</property>
- <property name="int2">0</property>
- <property name="last_modification_time">Thu, 29 Jul 2004 08:38:30 GMT</property>
+ <property name="can_focus">True</property>
+ <property name="history">0</property>
+
+ <child internal-child="menu">
+ <widget class="GtkMenu" id="convertwidget13">
+ <property name="visible">True</property>
+
+ <child>
+ <widget class="GtkMenuItem" id="convertwidget14">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Password</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="convertwidget15">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Kerberos </property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
</widget>
<packing>
<property name="padding">0</property>
@@ -1635,9 +1673,229 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
</child>
<child>
+ <widget class="GtkLabel" id="label32">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Receiving Mail</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vboxExtraTableBorder">
+ <property name="border_width">12</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">12</property>
+
+ <child>
+ <widget class="GtkTable" id="extra_table">
+ <property name="visible">True</property>
+ <property name="n_rows">1</property>
+ <property name="n_columns">2</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">18</property>
+ <property name="column_spacing">6</property>
+
+ <child>
+ <widget class="GtkVBox" id="extra_mailcheck_frame">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkTable" id="extra_mailcheck_table">
+ <property name="visible">True</property>
+ <property name="n_rows">1</property>
+ <property name="n_columns">2</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">6</property>
+
+ <child>
+ <widget class="GtkTable" id="extra_table">
+ <property name="visible">True</property>
+ <property name="n_rows">1</property>
+ <property name="n_columns">2</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">0</property>
+
+ <child>
+ <widget class="GtkVBox" id="extra_mailcheck_frame">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="lblMailCheck">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;span weight=&quot;bold&quot;&gt;Checking for New Mail&lt;/span&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkTable" id="extra_mailcheck_table">
+ <property name="border_width">12</property>
+ <property name="visible">True</property>
+ <property name="n_rows">1</property>
+ <property name="n_columns">2</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">0</property>
+ <property name="column_spacing">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="extra_mailcheck_hbox">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">4</property>
+
+ <child>
+ <widget class="GtkCheckButton" id="extra_auto_check">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Automatically check for _new mail every</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkSpinButton" id="extra_auto_check_min">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="climb_rate">1</property>
+ <property name="digits">0</property>
+ <property name="numeric">True</property>
+ <property name="update_policy">GTK_UPDATE_ALWAYS</property>
+ <property name="snap_to_ticks">False</property>
+ <property name="wrap">False</property>
+ <property name="adjustment">10 1 1440 1 10 10</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="lblMinutes">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">minutes</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="tab_expand">False</property>
+ <property name="tab_fill">True</property>
+ </packing>
+ </child>
+
+ <child>
<widget class="GtkLabel" id="label33">
<property name="visible">True</property>
- <property name="label" translatable="yes">Receiving Email</property>
+ <property name="label" translatable="yes">Receiving Options</property>
<property name="use_underline">True</property>
<property name="use_markup">False</property>
<property name="justify">GTK_JUSTIFY_CENTER</property>
@@ -1688,7 +1946,7 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<property name="yalign">0</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
- <property name="mnemonic_widget">transport_type_dropdown</property>
+ <property name="mnemonic_widget">transport_type_omenu</property>
</widget>
<packing>
<property name="left_attach">0</property>
@@ -1724,12 +1982,32 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
</child>
<child>
- <widget class="Custom" id="transport_type_dropdown">
+ <widget class="GtkOptionMenu" id="transport_type_omenu">
<property name="visible">True</property>
- <property name="creation_function">em_account_editor_dropdown_new</property>
- <property name="int1">0</property>
- <property name="int2">0</property>
- <property name="last_modification_time">Thu, 29 Jul 2004 05:42:00 GMT</property>
+ <property name="can_focus">True</property>
+ <property name="history">0</property>
+
+ <child internal-child="menu">
+ <widget class="GtkMenu" id="convertwidget16">
+ <property name="visible">True</property>
+
+ <child>
+ <widget class="GtkMenuItem" id="convertwidget17">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">SMTP</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="convertwidget18">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Sendmail</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
</widget>
<packing>
<property name="left_attach">1</property>
@@ -1901,7 +2179,7 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<property name="max_length">0</property>
<property name="text" translatable="yes"></property>
<property name="has_frame">True</property>
- <property name="invisible_char">*</property>
+ <property name="invisible_char" translatable="yes">*</property>
<property name="activates_default">False</property>
</widget>
<packing>
@@ -2037,7 +2315,7 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<child>
<widget class="GtkLabel" id="lblTransportUseSSL">
<property name="visible">True</property>
- <property name="label" translatable="yes">_Use Secure Connection:</property>
+ <property name="label" translatable="yes">_Use Secure Connection (SSL):</property>
<property name="use_underline">True</property>
<property name="use_markup">False</property>
<property name="justify">GTK_JUSTIFY_CENTER</property>
@@ -2057,12 +2335,40 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
</child>
<child>
- <widget class="Custom" id="transport_use_ssl">
+ <widget class="GtkOptionMenu" id="transport_use_ssl">
<property name="visible">True</property>
- <property name="creation_function">em_account_editor_ssl_selector_new</property>
- <property name="int1">0</property>
- <property name="int2">0</property>
- <property name="last_modification_time">Tue, 03 Aug 2004 07:23:50 GMT</property>
+ <property name="can_focus">True</property>
+ <property name="history">0</property>
+
+ <child internal-child="menu">
+ <widget class="GtkMenu" id="convertwidget19">
+ <property name="visible">True</property>
+
+ <child>
+ <widget class="GtkMenuItem" id="convertwidget20">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Always</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="convertwidget21">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Whenever Possible</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="convertwidget22">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Never</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
</widget>
<packing>
<property name="padding">0</property>
@@ -2104,7 +2410,7 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<child>
<widget class="GtkLabel" id="transport_ssl_disabled_label">
<property name="visible">True</property>
- <property name="label" translatable="yes">&lt;b&gt;SSL is not supported in this build of Evolution&lt;/b&gt;</property>
+ <property name="label" translatable="yes">&lt;b&gt;SSL is not supported in this build of evolution&lt;/b&gt;</property>
<property name="use_underline">False</property>
<property name="use_markup">True</property>
<property name="justify">GTK_JUSTIFY_CENTER</property>
@@ -2241,7 +2547,7 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
- <property name="mnemonic_widget">transport_auth_dropdown</property>
+ <property name="mnemonic_widget">transport_auth_omenu</property>
</widget>
<packing>
<property name="left_attach">0</property>
@@ -2287,7 +2593,7 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<property name="max_length">0</property>
<property name="text" translatable="yes"></property>
<property name="has_frame">True</property>
- <property name="invisible_char">*</property>
+ <property name="invisible_char" translatable="yes">*</property>
<property name="activates_default">False</property>
</widget>
<packing>
@@ -2306,12 +2612,32 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<property name="spacing">6</property>
<child>
- <widget class="Custom" id="transport_auth_dropdown">
+ <widget class="GtkOptionMenu" id="transport_auth_omenu">
<property name="visible">True</property>
- <property name="creation_function">em_account_editor_dropdown_new</property>
- <property name="int1">0</property>
- <property name="int2">0</property>
- <property name="last_modification_time">Thu, 29 Jul 2004 08:37:13 GMT</property>
+ <property name="can_focus">True</property>
+ <property name="history">0</property>
+
+ <child internal-child="menu">
+ <widget class="GtkMenu" id="convertwidget23">
+ <property name="visible">True</property>
+
+ <child>
+ <widget class="GtkMenuItem" id="convertwidget24">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Password</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="convertwidget25">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Kerberos </property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
</widget>
<packing>
<property name="padding">0</property>
@@ -2588,10 +2914,10 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<child>
<widget class="Custom" id="sent_button">
<property name="visible">True</property>
- <property name="creation_function">em_account_editor_folder_selector_button_new</property>
+ <property name="creation_function">mail_account_gui_folder_selector_button_new</property>
<property name="int1">0</property>
<property name="int2">0</property>
- <property name="last_modification_time">Tue, 14 Dec 2004 17:07:09 GMT</property>
+ <property name="last_modification_time">Wed, 03 Apr 2002 23:03:59 GMT</property>
</widget>
<packing>
<property name="left_attach">1</property>
@@ -2606,10 +2932,10 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<child>
<widget class="Custom" id="drafts_button">
<property name="visible">True</property>
- <property name="creation_function">em_account_editor_folder_selector_button_new</property>
+ <property name="creation_function">mail_account_gui_folder_selector_button_new</property>
<property name="int1">0</property>
<property name="int2">0</property>
- <property name="last_modification_time">Tue, 14 Dec 2004 17:07:02 GMT</property>
+ <property name="last_modification_time">Wed, 03 Apr 2002 23:03:41 GMT</property>
</widget>
<packing>
<property name="left_attach">1</property>
@@ -2872,7 +3198,7 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<property name="max_length">0</property>
<property name="text" translatable="yes"></property>
<property name="has_frame">True</property>
- <property name="invisible_char">*</property>
+ <property name="invisible_char" translatable="yes">*</property>
<property name="activates_default">False</property>
</widget>
<packing>
@@ -2988,7 +3314,7 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<property name="max_length">0</property>
<property name="text" translatable="yes"></property>
<property name="has_frame">True</property>
- <property name="invisible_char">*</property>
+ <property name="invisible_char" translatable="yes">*</property>
<property name="activates_default">False</property>
</widget>
<packing>
@@ -3195,7 +3521,7 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<property name="max_length">0</property>
<property name="text" translatable="yes"></property>
<property name="has_frame">True</property>
- <property name="invisible_char">*</property>
+ <property name="invisible_char" translatable="yes">*</property>
<property name="activates_default">False</property>
</widget>
<packing>
@@ -3216,7 +3542,7 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<widget class="GtkCheckButton" id="pgp_always_sign">
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="label" translatable="yes">Al_ways sign outgoing messages when using this account</property>
+ <property name="label" translatable="yes">Always _sign outgoing messages when using this account</property>
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
@@ -3235,7 +3561,7 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<widget class="GtkCheckButton" id="pgp_no_imip_sign">
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="label" translatable="yes">_Don't sign meeting requests (for Outlook compatibility)</property>
+ <property name="label" translatable="yes">Don't sign _meeting requests (for Outlook compatibility)</property>
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
@@ -3254,7 +3580,7 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<widget class="GtkCheckButton" id="pgp_encrypt_to_self">
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="label" translatable="yes">Always encrypt to _myself when sending encrypted mail</property>
+ <property name="label" translatable="yes">Al_ways encrypt to myself when sending encrypted mail</property>
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
@@ -3389,7 +3715,7 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<property name="max_length">0</property>
<property name="text" translatable="yes"></property>
<property name="has_frame">True</property>
- <property name="invisible_char">*</property>
+ <property name="invisible_char" translatable="yes">*</property>
<property name="activates_default">False</property>
</widget>
<packing>
@@ -3410,7 +3736,7 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<property name="max_length">0</property>
<property name="text" translatable="yes"></property>
<property name="has_frame">True</property>
- <property name="invisible_char">*</property>
+ <property name="invisible_char" translatable="yes">*</property>
<property name="activates_default">False</property>
</widget>
<packing>
@@ -3426,7 +3752,7 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<widget class="GtkCheckButton" id="smime_encrypt_to_self">
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="label" translatable="yes">Also encrypt to sel_f when sending encrypted mail</property>
+ <property name="label" translatable="yes">A_lso encrypt to self when sending encrypted mail</property>
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
@@ -3448,7 +3774,7 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<widget class="GtkCheckButton" id="smime_encrypt_default">
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="label" translatable="yes">Encrypt out_going messages (by default)</property>
+ <property name="label" translatable="yes">_Encrypt outgoing messages (by default)</property>
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
@@ -3470,7 +3796,7 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<widget class="GtkCheckButton" id="smime_sign_default">
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="label" translatable="yes">Digitally _sign outgoing messages (by default)</property>
+ <property name="label" translatable="yes">_Digitally sign outgoing messages (by default)</property>
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
@@ -3531,7 +3857,7 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<child>
<widget class="GtkLabel" id="label469">
<property name="visible">True</property>
- <property name="label" translatable="yes">Sig_ning certificate:</property>
+ <property name="label" translatable="yes">Si_gning certificate:</property>
<property name="use_underline">True</property>
<property name="use_markup">False</property>
<property name="justify">GTK_JUSTIFY_LEFT</property>
@@ -3604,7 +3930,7 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<child>
<widget class="GtkLabel" id="button98">
<property name="visible">True</property>
- <property name="label" translatable="yes">Se_lect...</property>
+ <property name="label" translatable="yes">Select...</property>
<property name="use_underline">True</property>
<property name="use_markup">False</property>
<property name="justify">GTK_JUSTIFY_LEFT</property>
@@ -3637,68 +3963,10 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<widget class="GtkButton" id="smime_encrypt_key_clear">
<property name="visible">True</property>
<property name="can_focus">True</property>
+ <property name="label">gtk-clear</property>
+ <property name="use_stock">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
-
- <child>
- <widget class="GtkAlignment" id="alignment35">
- <property name="visible">True</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xscale">0</property>
- <property name="yscale">0</property>
- <property name="top_padding">0</property>
- <property name="bottom_padding">0</property>
- <property name="left_padding">0</property>
- <property name="right_padding">0</property>
-
- <child>
- <widget class="GtkHBox" id="hbox230">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">2</property>
-
- <child>
- <widget class="GtkImage" id="image10">
- <property name="visible">True</property>
- <property name="stock">gtk-clear</property>
- <property name="icon_size">4</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label577">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Clea_r</property>
- <property name="use_underline">True</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- </child>
- </widget>
- </child>
</widget>
<packing>
<property name="padding">0</property>
@@ -3768,7 +4036,7 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<child>
<widget class="GtkLabel" id="label472">
<property name="visible">True</property>
- <property name="label" translatable="yes">S_elect...</property>
+ <property name="label" translatable="yes">Select...</property>
<property name="use_underline">True</property>
<property name="use_markup">False</property>
<property name="justify">GTK_JUSTIFY_LEFT</property>
@@ -3801,68 +4069,10 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<widget class="GtkButton" id="smime_sign_key_clear">
<property name="visible">True</property>
<property name="can_focus">True</property>
+ <property name="label">gtk-clear</property>
+ <property name="use_stock">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
-
- <child>
- <widget class="GtkAlignment" id="alignment34">
- <property name="visible">True</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xscale">0</property>
- <property name="yscale">0</property>
- <property name="top_padding">0</property>
- <property name="bottom_padding">0</property>
- <property name="left_padding">0</property>
- <property name="right_padding">0</property>
-
- <child>
- <widget class="GtkHBox" id="hbox229">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">2</property>
-
- <child>
- <widget class="GtkImage" id="image9">
- <property name="visible">True</property>
- <property name="stock">gtk-clear</property>
- <property name="icon_size">4</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label576">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Cle_ar</property>
- <property name="use_underline">True</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- </child>
- </widget>
- </child>
</widget>
<packing>
<property name="padding">0</property>
@@ -4142,7 +4352,7 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
<child>
- <widget class="GtkNotebook" id="preferences_toplevel">
+ <widget class="GtkNotebook" id="toplevel">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="show_tabs">True</property>
@@ -5020,7 +5230,6 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<property name="directory_entry">False</property>
<property name="modal">False</property>
<property name="use_filechooser">True</property>
- <property name="filechooser_action">GTK_FILE_CHOOSER_ACTION_OPEN</property>
<child internal-child="entry">
<widget class="GtkEntry" id="txtNotifyPlaySound">
@@ -5031,7 +5240,7 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<property name="max_length">0</property>
<property name="text" translatable="yes"></property>
<property name="has_frame">True</property>
- <property name="invisible_char">*</property>
+ <property name="invisible_char" translatable="yes">*</property>
<property name="activates_default">False</property>
</widget>
</child>
@@ -5550,7 +5759,7 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<property name="max_length">0</property>
<property name="text" translatable="yes">Important</property>
<property name="has_frame">True</property>
- <property name="invisible_char">*</property>
+ <property name="invisible_char" translatable="yes">*</property>
<property name="activates_default">False</property>
</widget>
<packing>
@@ -5572,7 +5781,7 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<property name="max_length">0</property>
<property name="text" translatable="yes">Work</property>
<property name="has_frame">True</property>
- <property name="invisible_char">*</property>
+ <property name="invisible_char" translatable="yes">*</property>
<property name="activates_default">False</property>
</widget>
<packing>
@@ -5594,7 +5803,7 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<property name="max_length">0</property>
<property name="text" translatable="yes">Personal</property>
<property name="has_frame">True</property>
- <property name="invisible_char">*</property>
+ <property name="invisible_char" translatable="yes">*</property>
<property name="activates_default">False</property>
</widget>
<packing>
@@ -5616,7 +5825,7 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<property name="max_length">0</property>
<property name="text" translatable="yes">To Do</property>
<property name="has_frame">True</property>
- <property name="invisible_char">*</property>
+ <property name="invisible_char" translatable="yes">*</property>
<property name="activates_default">False</property>
</widget>
<packing>
@@ -5638,7 +5847,7 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<property name="max_length">0</property>
<property name="text" translatable="yes">Later</property>
<property name="has_frame">True</property>
- <property name="invisible_char">*</property>
+ <property name="invisible_char" translatable="yes">*</property>
<property name="activates_default">False</property>
</widget>
<packing>
@@ -5793,7 +6002,7 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<property name="max_length">0</property>
<property name="text" translatable="yes"></property>
<property name="has_frame">True</property>
- <property name="invisible_char">*</property>
+ <property name="invisible_char" translatable="yes">*</property>
<property name="activates_default">False</property>
</widget>
<packing>
@@ -6241,7 +6450,7 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
<child>
- <widget class="GtkNotebook" id="composer_toplevel">
+ <widget class="GtkNotebook" id="toplevel">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="show_tabs">True</property>
@@ -6400,7 +6609,7 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<child>
<widget class="GtkAlignment" id="alignment25">
<property name="visible">True</property>
- <property name="xalign">7.45058015283e-09</property>
+ <property name="xalign">7.45058e-09</property>
<property name="yalign">0.5</property>
<property name="xscale">0</property>
<property name="yscale">1</property>
@@ -7235,6 +7444,57 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<property name="spacing">12</property>
<child>
+ <widget class="GtkHBox" id="hboxImageAndHelp">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkImage" id="pixmapSpellInfo">
+ <property name="visible">True</property>
+ <property name="stock">gtk-dialog-info</property>
+ <property name="icon_size">6</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="lblSpellChecking">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">This page allows you to configure spell checking behavior and language. The list of languages here reflects only the languages for which you have a dictionary installed.</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">True</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
<widget class="GtkVBox" id="vbox196">
<property name="visible">True</property>
<property name="homogeneous">False</property>
@@ -7354,53 +7614,33 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
</child>
<child>
- <widget class="GtkHBox" id="hboxImageAndHelp">
+ <widget class="GtkHBox" id="hbox219">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">6</property>
<child>
- <widget class="GtkImage" id="pixmapSpellInfo">
+ <widget class="GtkButton" id="buttonSpellCheckEnable">
<property name="visible">True</property>
- <property name="stock">gtk-dialog-info</property>
- <property name="icon_size">4</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
+ <property name="sensitive">False</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_Enable</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="lblSpellChecking">
- <property name="visible">True</property>
- <property name="label" translatable="yes">The list of languages here reflects only the languages for which you have a dictionary installed.</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">True</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
+ <property name="fill">False</property>
</packing>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
- <property name="fill">True</property>
+ <property name="fill">False</property>
</packing>
</child>
</widget>
@@ -7579,7 +7819,7 @@ For example: &quot;Work&quot; or &quot;Personal&quot;</property>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
- <property name="fill">True</property>
+ <property name="fill">False</property>
</packing>
</child>
</widget>
@@ -8066,7 +8306,7 @@ for display purposes only. </property>
<property name="max_length">0</property>
<property name="text" translatable="yes"></property>
<property name="has_frame">True</property>
- <property name="invisible_char">*</property>
+ <property name="invisible_char" translatable="yes">*</property>
<property name="activates_default">False</property>
</widget>
<packing>
@@ -8086,7 +8326,6 @@ for display purposes only. </property>
<property name="directory_entry">False</property>
<property name="modal">False</property>
<property name="use_filechooser">True</property>
- <property name="filechooser_action">GTK_FILE_CHOOSER_ACTION_OPEN</property>
<child internal-child="entry">
<widget class="GtkEntry" id="combo-entry2">
@@ -8097,7 +8336,7 @@ for display purposes only. </property>
<property name="max_length">0</property>
<property name="text" translatable="yes"></property>
<property name="has_frame">True</property>
- <property name="invisible_char">*</property>
+ <property name="invisible_char" translatable="yes">*</property>
<property name="activates_default">False</property>
</widget>
</child>
diff --git a/mail/mail-errors.xml b/mail/mail-errors.xml
index 045cf9326a..9e32d5aba2 100644
--- a/mail/mail-errors.xml
+++ b/mail/mail-errors.xml
@@ -69,13 +69,6 @@ Many email systems add an Apparently-To header to messages that only have BCC re
<button label="_Empty Trash" response="GTK_RESPONSE_YES"/>
</error>
- <error id="ask-open-many" type="warning" default="GTK_RESPONSE_CANCEL">
- <primary>Are you sure you want to open {0} messages at once?</primary>
- <secondary>Opening too many messages at once may take a long time.</secondary>
- <button stock="gtk-cancel" response="GTK_RESPONSE_CANCEL"/>
- <button label="_Open Messages" response="GTK_RESPONSE_YES"/>
- </error>
-
<error id="exit-unsaved" type="warning" default="GTK_RESPONSE_NO">
<primary>You have unsent messages, do you wish to quit anyway?</primary>
<secondary>If you quit, these messages will not be sent until Evolution is started again.</secondary>
@@ -263,7 +256,7 @@ The message is stored in the Outbox folder. Check the message for errors and re
<error id="vfolder-notexist" type="error">
<primary>Cannot edit vFolder &quot;{0}&quot; as it does not exist.</primary>
- <secondary>This folder may have been added implicitly, go to the vFolder editor to add it explicitly, if required.</secondary>
+ <secondary>This folder may have been added implictly, go to the virtual folder editor to add it explictly, if required.</secondary>
</error>
<error id="vfolder-notunique" type="error">
@@ -318,23 +311,9 @@ You can choose to ignore this folder, overwrite or append its contents, or quit.
<button label="_Append" response="GTK_RESPONSE_OK"/>
</error>
- <error id="no-load-license" type="error">
- <primary>Unable to read license file.</primary>
- <secondary>Cannot read the license file &quot;{0}&quot;, due to an
- installation problem. You will not be able to use this provider until
- you can accept its license.</secondary>
- </error>
-
- <error id="checking-service" type="info">
- <title>Querying server</title>
- <primary>Please wait.</primary>
- <secondary>Querying server for a list of supported authentication mechanisms.</secondary>
- <button stock="gtk-cancel" response="GTK_RESPONSE_CANCEL"/>
- </error>
-
<error id="gw-accountsetup-error" type="error">
- <primary>Unable to connect to the GroupWise
-server.</primary>
+ <primary><span weight="bold" size="larger">Unable to connect to the GroupWise
+server.</span></primary>
<secondary>
Please check your account settings and try again.
</secondary>
diff --git a/mail/mail-errors.xml.h b/mail/mail-errors.xml.h
index ba728c520d..74cdecfc92 100644
--- a/mail/mail-errors.xml.h
+++ b/mail/mail-errors.xml.h
@@ -49,11 +49,6 @@ char *s = N_("Are you sure you want to permanently remove all the deleted messag
/* mail:ask-empty-trash secondary */
char *s = N_("If you continue, you will not be able to recover these messages.");
char *s = N_("_Empty Trash");
-/* mail:ask-open-many primary */
-char *s = N_("Are you sure you want to open {0} messages at once?");
-/* mail:ask-open-many secondary */
-char *s = N_("Opening too many messages at once may take a long time.");
-char *s = N_("_Open Messages");
/* mail:exit-unsaved primary */
char *s = N_("You have unsent messages, do you wish to quit anyway?");
/* mail:exit-unsaved secondary */
@@ -190,7 +185,7 @@ char *s = N_("_Discard changes");
/* mail:vfolder-notexist primary */
char *s = N_("Cannot edit vFolder \"{0}\" as it does not exist.");
/* mail:vfolder-notexist secondary */
-char *s = N_("This folder may have been added implicitly, go to the vFolder editor to add it explicitly, if required.");
+char *s = N_("This folder may have been added implictly, go to the virtual folder editor to add it explictly, if required.");
/* mail:vfolder-notunique primary */
char *s = N_("Cannot add vFolder \"{0}\".");
/* mail:vfolder-notunique secondary */
@@ -235,18 +230,6 @@ char *s = N_("A non-empty folder at \"{1}\" already exists.\n"
char *s = N_("Ignore");
char *s = N_("_Overwrite");
char *s = N_("_Append");
-/* mail:no-load-license primary */
-char *s = N_("Unable to read license file.");
-/* mail:no-load-license secondary */
-char *s = N_("Cannot read the license file \"{0}\", due to an\n"
- " installation problem. You will not be able to use this provider until\n"
- " you can accept its license.");
-/* mail:checking-service title */
-char *s = N_("Querying server");
-/* mail:checking-service primary */
-char *s = N_("Please wait.");
-/* mail:checking-service secondary */
-char *s = N_("Querying server for a list of supported authentication mechanisms.");
/* mail:gw-accountsetup-error primary */
char *s = N_("Unable to connect to the GroupWise\n"
"server.");
diff --git a/mail/mail-ops.c b/mail/mail-ops.c
index 3c80c7c535..d0c5e272a1 100644
--- a/mail/mail-ops.c
+++ b/mail/mail-ops.c
@@ -36,14 +36,11 @@
#include <errno.h>
#include <libgnome/gnome-exec.h>
#include <gal/util/e-util.h>
-#include <libgnome/gnome-i18n.h>
#include <camel/camel-mime-filter-from.h>
#include <camel/camel-stream-filter.h>
#include <camel/camel-stream-fs.h>
#include <camel/camel-mime-filter-charset.h>
-#include <camel/camel-offline-folder.h>
-#include <camel/camel-offline-store.h>
#include <camel/camel-disco-folder.h>
#include <camel/camel-disco-store.h>
#include <camel/camel-operation.h>
@@ -443,7 +440,8 @@ static char *resent_recipients[] = {
/* send 1 message to a specific transport */
static void
-mail_send_message(CamelFolder *queue, const char *uid, const char *destination, CamelFilterDriver *driver, CamelException *ex)
+mail_send_message (CamelMimeMessage *message, const char *destination,
+ CamelFilterDriver *driver, CamelException *ex)
{
EAccount *account = NULL;
const CamelInternetAddress *iaddr;
@@ -456,14 +454,10 @@ mail_send_message(CamelFolder *queue, const char *uid, const char *destination,
CamelFolder *folder = NULL;
GString *err = NULL;
XEvolution *xev;
- CamelMimeMessage *message;
int i;
-
- message = camel_folder_get_message(queue, uid, ex);
- if (!message)
- return;
- camel_medium_set_header (CAMEL_MEDIUM (message), "X-Mailer", "Evolution " VERSION SUB_VERSION " " VERSION_COMMENT);
+ camel_medium_set_header (CAMEL_MEDIUM (message), "X-Mailer",
+ "Evolution " VERSION SUB_VERSION " " VERSION_COMMENT);
xev = mail_tool_remove_xevolution_headers (message);
@@ -532,18 +526,12 @@ mail_send_message(CamelFolder *queue, const char *uid, const char *destination,
}
/* post-process */
- err = g_string_new("");
- info = camel_message_info_new(NULL);
- camel_message_info_set_flags(info, CAMEL_MESSAGE_SEEN, ~0);
+ info = camel_message_info_new ();
+ info->flags = CAMEL_MESSAGE_SEEN;
if (sent_folder_uri) {
folder = mail_tool_uri_to_folder (sent_folder_uri, 0, ex);
- if (camel_exception_is_set(ex)) {
- g_string_append_printf (err, _("Failed to append to %s: %s\n"
- "Appending to local `Sent' folder instead."),
- sent_folder_uri, camel_exception_get_description (ex));
- camel_exception_clear (ex);
- }
+ camel_exception_clear (ex);
g_free (sent_folder_uri);
}
@@ -560,12 +548,14 @@ mail_send_message(CamelFolder *queue, const char *uid, const char *destination,
if (camel_exception_get_id (ex) == CAMEL_EXCEPTION_USER_CANCEL)
goto exit;
- /* sending mail, filtering failed */
+ /* save this error */
+ err = g_string_new ("");
g_string_append_printf (err, _("Failed to apply outgoing filters: %s"),
camel_exception_get_description (ex));
}
}
+ retry_append:
camel_exception_clear (ex);
camel_folder_append_message (folder, message, info, NULL, ex);
if (camel_exception_is_set (ex)) {
@@ -576,48 +566,42 @@ mail_send_message(CamelFolder *queue, const char *uid, const char *destination,
sent_folder = mail_component_get_folder(NULL, MAIL_COMPONENT_FOLDER_SENT);
+ if (err == NULL)
+ err = g_string_new ("");
+ else
+ g_string_append (err, "\n\n");
+
if (folder != sent_folder) {
const char *name;
camel_object_get (folder, NULL, CAMEL_OBJECT_DESCRIPTION, (char **) &name, 0);
- if (err->len)
- g_string_append(err, "\n\n");
g_string_append_printf (err, _("Failed to append to %s: %s\n"
"Appending to local `Sent' folder instead."),
name, camel_exception_get_description (ex));
camel_object_ref (sent_folder);
camel_object_unref (folder);
folder = sent_folder;
-
- camel_exception_clear (ex);
- camel_folder_append_message (folder, message, info, NULL, ex);
- }
-
- if (camel_exception_is_set (ex)) {
- if (camel_exception_get_id (ex) == CAMEL_EXCEPTION_USER_CANCEL)
- goto exit;
-
- if (err->len)
- g_string_append(err, "\n\n");
+
+ goto retry_append;
+ } else {
g_string_append_printf (err, _("Failed to append to local `Sent' folder: %s"),
camel_exception_get_description (ex));
}
}
-
- if (!camel_exception_is_set(ex))
- camel_folder_set_message_flags (queue, uid, CAMEL_MESSAGE_DELETED|CAMEL_MESSAGE_SEEN, ~0);
- if (err->len) {
+ if (err != NULL) {
/* set the culmulative exception report */
camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, err->str);
}
- exit:
- g_string_free (err, TRUE);
+ exit:
+
camel_folder_sync (folder, FALSE, NULL);
camel_message_info_free (info);
camel_object_unref (folder);
- camel_object_unref(message);
+
+ if (err != NULL)
+ g_string_free (err, TRUE);
}
/* ** SEND MAIL QUEUE ***************************************************** */
@@ -673,11 +657,10 @@ send_queue_send(struct _mail_msg *mm)
CamelMessageInfo *info;
info = camel_folder_get_message_info (m->queue, uids->pdata[i]);
- if (info) {
- if ((camel_message_info_flags(info) & CAMEL_MESSAGE_DELETED) == 0)
- send_uids->pdata[j++] = uids->pdata[i];
- camel_folder_free_message_info(m->queue, info);
- }
+ if (info && info->flags & CAMEL_MESSAGE_DELETED)
+ continue;
+
+ send_uids->pdata[j++] = uids->pdata[i];
}
send_uids->len = j;
@@ -692,32 +675,36 @@ send_queue_send(struct _mail_msg *mm)
camel_operation_register (m->cancel);
camel_exception_init (&ex);
-
- /* NB: This code somewhat abuses the 'exception' stuff. Apart from fatal problems, it is also
- used as a mechanism to accumualte warning messages and present them back to the user. */
-
+
for (i = 0, j = 0; i < send_uids->len; i++) {
int pc = (100 * i) / send_uids->len;
+ CamelMimeMessage *message;
report_status (m, CAMEL_FILTER_STATUS_START, pc, _("Sending message %d of %d"), i+1, send_uids->len);
- mail_send_message (m->queue, send_uids->pdata[i], m->destination, m->driver, &ex);
- if (camel_exception_is_set (&ex)) {
- if (ex.id != CAMEL_EXCEPTION_USER_CANCEL) {
- /* merge exceptions into one */
- if (camel_exception_is_set (&mm->ex))
- camel_exception_setv (&mm->ex, CAMEL_EXCEPTION_SYSTEM, "%s\n\n%s", mm->ex.desc, ex.desc);
- else
- camel_exception_xfer (&mm->ex, &ex);
- camel_exception_clear (&ex);
-
- /* keep track of the number of failures */
- j++;
- } else {
- /* transfer the USER_CANCEL exeption to the async op exception and then break */
+ if (!(message = camel_folder_get_message (m->queue, send_uids->pdata[i], &ex))) {
+ /* I guess ignore errors where we can't get the message (should never happen anyway)? */
+ camel_exception_clear (&ex);
+ continue;
+ }
+
+ mail_send_message (message, m->destination, m->driver, &ex);
+ if (!camel_exception_is_set (&ex)) {
+ camel_folder_set_message_flags (m->queue, send_uids->pdata[i], CAMEL_MESSAGE_DELETED|CAMEL_MESSAGE_SEEN, ~0);
+ } else if (ex.id != CAMEL_EXCEPTION_USER_CANCEL) {
+ /* merge exceptions into one */
+ if (camel_exception_is_set (&mm->ex))
+ camel_exception_setv (&mm->ex, CAMEL_EXCEPTION_SYSTEM, "%s\n\n%s", mm->ex.desc, ex.desc);
+ else
camel_exception_xfer (&mm->ex, &ex);
- break;
- }
+ camel_exception_clear (&ex);
+
+ /* keep track of the number of failures */
+ j++;
+ } else {
+ /* transfer the USER_CANCEL exeption to the async op exception and then break */
+ camel_exception_xfer (&mm->ex, &ex);
+ break;
}
}
@@ -2118,8 +2105,6 @@ static void prep_offline_do(struct _mail_msg *mm)
camel_disco_folder_prepare_for_offline((CamelDiscoFolder *)folder,
"(match-all)",
&mm->ex);
- } else if (CAMEL_IS_OFFLINE_FOLDER (folder)) {
- camel_offline_folder_downsync ((CamelOfflineFolder *) folder, "(match-all)", &mm->ex);
}
/* prepare_for_offline should do this? */
/* of course it should all be atomic, but ... */
@@ -2213,18 +2198,6 @@ static void set_offline_do(struct _mail_msg *mm)
&mm->ex);
return;
}
- } else if (CAMEL_IS_OFFLINE_STORE (m->store)) {
- if (!m->offline) {
- camel_offline_store_set_network_state (CAMEL_OFFLINE_STORE (m->store),
- CAMEL_OFFLINE_STORE_NETWORK_AVAIL,
- &mm->ex);
- return;
- } else {
- camel_offline_store_set_network_state (CAMEL_OFFLINE_STORE (m->store),
- CAMEL_OFFLINE_STORE_NETWORK_UNAVAIL,
- &mm->ex);
- return;
- }
}
if (m->offline)
diff --git a/mail/mail-ops.h b/mail/mail-ops.h
index 21c0685165..8527994eaa 100644
--- a/mail/mail-ops.h
+++ b/mail/mail-ops.h
@@ -36,7 +36,7 @@ extern "C" {
#include "camel/camel-mime-message.h"
#include "camel/camel-operation.h"
-#include "libedataserver/e-msgport.h"
+#include "e-util/e-msgport.h"
#include "e-util/e-account.h"
void mail_append_mail (CamelFolder *folder, CamelMimeMessage *message, CamelMessageInfo *info,
diff --git a/mail/mail-tools.c b/mail/mail-tools.c
index b49fb38a43..20f6ae0fe9 100644
--- a/mail/mail-tools.c
+++ b/mail/mail-tools.c
@@ -36,7 +36,6 @@
#include <gconf/gconf.h>
#include <gconf/gconf-client.h>
-#include <libgnome/gnome-i18n.h>
#include <camel/camel-vee-folder.h>
#include <camel/camel-file-utils.h>
diff --git a/mail/mail-vfolder.c b/mail/mail-vfolder.c
index 8798ccba33..01cdd1ace2 100644
--- a/mail/mail-vfolder.c
+++ b/mail/mail-vfolder.c
@@ -59,9 +59,6 @@ static pthread_mutex_t vfolder_lock = PTHREAD_MUTEX_INITIALIZER;
static GList *source_folders_remote; /* list of source folder uri's - remote ones */
static GList *source_folders_local; /* list of source folder uri's - local ones */
static GHashTable *vfolder_hash;
-/* This is a slightly hacky solution to shutting down, we poll this variable in various
- loops, and just quit processing if it is set. */
-static volatile int shutdown; /* are we shutting down? */
/* more globals ... */
extern CamelSession *session;
@@ -87,7 +84,7 @@ vfolder_setup_desc(struct _mail_msg *mm, int done)
{
struct _setup_msg *m = (struct _setup_msg *)mm;
- return g_strdup_printf(_("Setting up vFolder: %s"), m->folder->full_name);
+ return g_strdup_printf(_("Setting up vfolder: %s"), m->folder->full_name);
}
static void
@@ -97,12 +94,12 @@ vfolder_setup_do(struct _mail_msg *mm)
GList *l, *list = NULL;
CamelFolder *folder;
- d(printf("Setting up vFolder: %s\n", m->folder->full_name));
+ d(printf("Setting up vfolder: %s\n", m->folder->full_name));
camel_vee_folder_set_expression((CamelVeeFolder *)m->folder, m->query);
l = m->sources_uri;
- while (l && !shutdown) {
+ while (l) {
d(printf(" Adding uri: %s\n", (char *)l->data));
folder = mail_tool_uri_to_folder (l->data, 0, &mm->ex);
if (folder) {
@@ -115,15 +112,14 @@ vfolder_setup_do(struct _mail_msg *mm)
}
l = m->sources_folder;
- while (l && !shutdown) {
+ while (l) {
d(printf(" Adding folder: %s\n", ((CamelFolder *)l->data)->full_name));
camel_object_ref(l->data);
list = g_list_append(list, l->data);
l = l->next;
}
- if (!shutdown)
- camel_vee_folder_set_folders((CamelVeeFolder *)m->folder, list);
+ camel_vee_folder_set_folders((CamelVeeFolder *)m->folder, list);
l = list;
while (l) {
@@ -255,13 +251,9 @@ vfolder_adduri_do(struct _mail_msg *mm)
GList *l;
CamelFolder *folder = NULL;
- if (shutdown)
- return;
-
d(printf("%s uri to vfolder: %s\n", m->remove?"Removing":"Adding", m->uri));
/* we dont try lookup the cache if we are removing it, its no longer there */
-
if (!m->remove && !mail_note_get_folder_from_uri(m->uri, &folder)) {
g_warning("Folder '%s' disappeared while I was adding/remove it to/from my vfolder", m->uri);
return;
@@ -272,7 +264,7 @@ vfolder_adduri_do(struct _mail_msg *mm)
if (folder != NULL) {
l = m->folders;
- while (l && !shutdown) {
+ while (l) {
if (m->remove)
camel_vee_folder_remove_folder((CamelVeeFolder *)l->data, folder);
else
@@ -410,19 +402,11 @@ uri_is_spethal(CamelStore *store, const char *uri)
return TRUE;
/* don't use strcasecmp here */
- if (url->fragment) {
- res = (((store->flags & CAMEL_STORE_VTRASH)
- && strcmp(url->fragment, CAMEL_VTRASH_NAME) == 0)
- || ((store->flags & CAMEL_STORE_VJUNK)
- && strcmp(url->fragment, CAMEL_VJUNK_NAME) == 0));
- } else {
- res = url->path
- && (((store->flags & CAMEL_STORE_VTRASH)
- && strcmp(url->path, "/" CAMEL_VTRASH_NAME) == 0)
- || ((store->flags & CAMEL_STORE_VJUNK)
- && strcmp(url->path, "/" CAMEL_VJUNK_NAME) == 0));
- }
-
+ res = url->path
+ && (((store->flags & CAMEL_STORE_VTRASH)
+ && strcmp(url->path, "/" CAMEL_VTRASH_NAME) == 0)
+ || ((store->flags & CAMEL_STORE_VJUNK)
+ && strcmp(url->path, "/" CAMEL_VJUNK_NAME) == 0));
camel_url_free(url);
return res;
@@ -896,7 +880,7 @@ vfolder_load_storage(void)
(CamelObjectEventHookFunc)store_folder_renamed, NULL);
d(printf("got store '%s' = %p\n", storeuri, vfolder_store));
- mail_component_load_store_by_uri (mail_component_peek (), storeuri, _("vFolders"));
+ mail_component_load_store_by_uri (mail_component_peek (), storeuri, _("VFolders"));
/* load our rules */
user = g_strdup_printf ("%s/mail/vfolders.xml", mail_component_peek_base_directory (mail_component_peek ()));
@@ -1005,7 +989,7 @@ vfolder_edit_rule(const char *uri)
w = filter_rule_get_widget((FilterRule *)newrule, (RuleContext *)context);
- gd = (GtkDialog *)gtk_dialog_new_with_buttons(_("Edit vFolder"), NULL,
+ gd = (GtkDialog *)gtk_dialog_new_with_buttons(_("Edit VFolder"), NULL,
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_STOCK_CANCEL,
GTK_RESPONSE_CANCEL,
@@ -1089,7 +1073,7 @@ vfolder_gui_add_rule(EMVFolderRule *rule)
w = filter_rule_get_widget((FilterRule *)rule, (RuleContext *)context);
- gd = (GtkDialog *)gtk_dialog_new_with_buttons(_("New vFolder"),
+ gd = (GtkDialog *)gtk_dialog_new_with_buttons(_("New VFolder"),
NULL,
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_STOCK_CANCEL,
@@ -1134,8 +1118,6 @@ vfolder_foreach_cb (gpointer key, gpointer data, gpointer user_data)
void
mail_vfolder_shutdown (void)
{
- shutdown = 1;
-
g_hash_table_foreach (vfolder_hash, vfolder_foreach_cb, NULL);
g_hash_table_destroy (vfolder_hash);
vfolder_hash = NULL;
diff --git a/mail/message-list.c b/mail/message-list.c
index 59c08cc3ce..c8b39ba462 100644
--- a/mail/message-list.c
+++ b/mail/message-list.c
@@ -39,7 +39,6 @@
#include <gtk/gtkmain.h>
#include <gtk/gtkinvisible.h>
-#include <libgnome/gnome-i18n.h>
#include <gal/util/e-util.h>
#include <gal/widgets/e-gui-utils.h>
@@ -57,7 +56,7 @@
#include <camel/camel-folder.h>
#include <camel/camel-folder-thread.h>
#include <camel/camel-vee-folder.h>
-#include <libedataserver/e-memory.h>
+#include <e-util/e-memory.h>
#include "filter/filter-label.h"
@@ -153,6 +152,8 @@ enum {
NORMALISED_LAST,
};
+#define PARENT_TYPE (e_tree_scrolled_get_type ())
+
/* #define SMART_ADDRESS_COMPARE */
#ifdef SMART_ADDRESS_COMPARE
@@ -164,7 +165,7 @@ struct _EMailAddress {
typedef struct _EMailAddress EMailAddress;
#endif /* SMART_ADDRESS_COMPARE */
-G_DEFINE_TYPE (MessageList, message_list, E_TREE_SCROLLED_TYPE);
+static ETreeScrolledClass *message_list_parent_class;
static void on_cursor_activated_cmd (ETree *tree, int row, ETreePath path, gpointer user_data);
static void on_selection_changed_cmd(ETree *tree, MessageList *ml);
@@ -487,7 +488,7 @@ ml_search_forward(MessageList *ml, int start, int end, guint32 flags, guint32 ma
path = e_tree_table_adapter_node_at_row(etta, row);
if (path
&& (info = get_message_info(ml, path))
- && (camel_message_info_flags(info) & mask) == flags)
+ && (info->flags & mask) == flags)
return path;
}
@@ -506,7 +507,7 @@ ml_search_backward(MessageList *ml, int start, int end, guint32 flags, guint32 m
path = e_tree_table_adapter_node_at_row(etta, row);
if (path
&& (info = get_message_info(ml, path))
- && (camel_message_info_flags(info) & mask) == flags)
+ && (info->flags & mask) == flags)
return path;
}
@@ -1077,7 +1078,7 @@ subtree_unread(MessageList *ml, ETreePath node)
info = e_tree_memory_node_get_data((ETreeMemory *)ml->model, node);
g_assert(info);
- if (!(camel_message_info_flags(info) & CAMEL_MESSAGE_SEEN))
+ if (!(info->flags & CAMEL_MESSAGE_SEEN))
return TRUE;
if ((child = e_tree_model_node_get_first_child (E_TREE_MODEL (ml->model), node)))
@@ -1099,7 +1100,7 @@ subtree_size(MessageList *ml, ETreePath node)
info = e_tree_memory_node_get_data((ETreeMemory *)ml->model, node);
g_assert(info);
- size += camel_message_info_size(info);
+ size += info->size;
if ((child = e_tree_model_node_get_first_child (E_TREE_MODEL (ml->model), node)))
size += subtree_size(ml, child);
@@ -1120,9 +1121,9 @@ subtree_earliest(MessageList *ml, ETreePath node, int sent)
g_assert(info);
if (sent)
- date = camel_message_info_date_sent(info);
+ date = info->date_sent;
else
- date = camel_message_info_date_received(info);
+ date = info->date_received;
if (earliest == 0 || date < earliest)
earliest = date;
@@ -1145,7 +1146,6 @@ ml_tree_value_at (ETreeModel *etm, ETreePath path, int col, void *model_data)
MessageList *message_list = model_data;
CamelMessageInfo *msg_info;
const char *str;
- guint32 flags;
if (e_tree_model_node_is_root (etm, path))
return NULL;
@@ -1156,21 +1156,20 @@ ml_tree_value_at (ETreeModel *etm, ETreePath path, int col, void *model_data)
switch (col){
case COL_MESSAGE_STATUS:
- flags = camel_message_info_flags(msg_info);
- if (flags & CAMEL_MESSAGE_ANSWERED)
+ if (msg_info->flags & CAMEL_MESSAGE_ANSWERED)
return GINT_TO_POINTER (2);
- else if (flags & CAMEL_MESSAGE_SEEN)
+ else if (msg_info->flags & CAMEL_MESSAGE_SEEN)
return GINT_TO_POINTER (1);
else
return GINT_TO_POINTER (0);
break;
case COL_FLAGGED:
- return GINT_TO_POINTER ((camel_message_info_flags(msg_info) & CAMEL_MESSAGE_FLAGGED) != 0);
+ return GINT_TO_POINTER ((msg_info->flags & CAMEL_MESSAGE_FLAGGED) != 0);
case COL_SCORE: {
const char *tag;
int score = 0;
- tag = camel_message_info_user_tag(msg_info, "score");
+ tag = camel_tag_get ((CamelTag **) &msg_info->user_tags, "score");
if (tag)
score = atoi (tag);
@@ -1181,8 +1180,8 @@ ml_tree_value_at (ETreeModel *etm, ETreePath path, int col, void *model_data)
/* FIXME: this all should be methods off of message-tag-followup class,
FIXME: the tag names should be namespaced :( */
- tag = camel_message_info_user_tag(msg_info, "follow-up");
- cmp = camel_message_info_user_tag(msg_info, "completed-on");
+ tag = camel_tag_get ((CamelTag **) &msg_info->user_tags, "follow-up");
+ cmp = camel_tag_get ((CamelTag **) &msg_info->user_tags, "completed-on");
if (tag && tag[0]) {
if (cmp && cmp[0])
return GINT_TO_POINTER(2);
@@ -1195,7 +1194,7 @@ ml_tree_value_at (ETreeModel *etm, ETreePath path, int col, void *model_data)
const char *tag;
time_t due_by;
- tag = camel_message_info_user_tag(msg_info, "due-by");
+ tag = camel_tag_get ((CamelTag **) &msg_info->user_tags, "due-by");
if (tag && *tag) {
due_by = camel_header_decode_date (tag, NULL);
return GINT_TO_POINTER (due_by);
@@ -1204,10 +1203,10 @@ ml_tree_value_at (ETreeModel *etm, ETreePath path, int col, void *model_data)
}
}
case COL_FOLLOWUP_FLAG:
- str = camel_message_info_user_tag(msg_info, "follow-up");
+ str = camel_tag_get ((CamelTag **) &msg_info->user_tags, "follow-up");
return (void *)(str ? str : "");
case COL_ATTACHMENT:
- return GINT_TO_POINTER ((camel_message_info_flags(msg_info) & CAMEL_MESSAGE_ATTACHMENTS) != 0);
+ return GINT_TO_POINTER ((msg_info->flags & CAMEL_MESSAGE_ATTACHMENTS) != 0);
case COL_FROM:
str = camel_message_info_from (msg_info);
return (void *)(str ? str : "");
@@ -1219,41 +1218,38 @@ ml_tree_value_at (ETreeModel *etm, ETreePath path, int col, void *model_data)
case COL_SUBJECT_NORM:
return (void *) get_normalised_string (message_list, msg_info, col);
case COL_SENT:
- return GINT_TO_POINTER (camel_message_info_date_sent(msg_info));
+ return GINT_TO_POINTER (msg_info->date_sent);
case COL_RECEIVED:
- return GINT_TO_POINTER (camel_message_info_date_received(msg_info));
+ return GINT_TO_POINTER (msg_info->date_received);
case COL_TO:
str = camel_message_info_to (msg_info);
return (void *)(str ? str : "");
case COL_TO_NORM:
return (void *) get_normalised_string (message_list, msg_info, col);
case COL_SIZE:
- return GINT_TO_POINTER (camel_message_info_size(msg_info));
+ return GINT_TO_POINTER (msg_info->size);
case COL_DELETED:
- return GINT_TO_POINTER ((camel_message_info_flags(msg_info) & CAMEL_MESSAGE_DELETED) != 0);
+ return GINT_TO_POINTER ((msg_info->flags & CAMEL_MESSAGE_DELETED) != 0);
case COL_UNREAD: {
ETreePath child;
- flags = camel_message_info_flags(msg_info);
-
+
child = e_tree_model_node_get_first_child(etm, path);
if (child && !e_tree_node_is_expanded(message_list->tree, path)
- && (flags & CAMEL_MESSAGE_SEEN)) {
+ && (msg_info->flags & CAMEL_MESSAGE_SEEN)) {
return GINT_TO_POINTER (subtree_unread (message_list, child));
}
- return GINT_TO_POINTER (!(flags & CAMEL_MESSAGE_SEEN));
+ return GINT_TO_POINTER (!(msg_info->flags & CAMEL_MESSAGE_SEEN));
}
case COL_COLOUR: {
const char *colour, *due_by, *completed, *label;
/* Priority: colour tag; label tag; important flag; due-by tag */
-
- /* This is astonisngly poorly written code */
-
- colour = camel_message_info_user_tag(msg_info, "colour");
- due_by = camel_message_info_user_tag(msg_info, "due-by");
- completed = camel_message_info_user_tag(msg_info, "completed-on");
- label = camel_message_info_user_tag(msg_info, "label");
+
+ colour = camel_tag_get ((CamelTag **) &msg_info->user_tags, "colour");
+ due_by = camel_tag_get ((CamelTag **) &msg_info->user_tags, "due-by");
+ completed = camel_tag_get ((CamelTag **) &msg_info->user_tags, "completed-on");
+ label = camel_tag_get ((CamelTag **) &msg_info->user_tags, "label");
if (colour == NULL) {
find_colour:
if (label != NULL) {
@@ -1263,7 +1259,7 @@ ml_tree_value_at (ETreeModel *etm, ETreePath path, int col, void *model_data)
label = NULL;
goto find_colour;
}
- } else if (camel_message_info_flags(msg_info) & CAMEL_MESSAGE_FLAGGED) {
+ } else if (msg_info->flags & CAMEL_MESSAGE_FLAGGED) {
/* FIXME: extract from the important.xpm somehow. */
colour = "#A7453E";
} else if ((due_by && *due_by) && !(completed && *completed)) {
@@ -1682,48 +1678,34 @@ ml_drop_action(struct _drop_msg *m)
}
static void
-ml_drop_popup_copy(EPopup *ep, EPopupItem *item, void *data)
+ml_drop_popup_copy(GtkWidget *item, struct _drop_msg *m)
{
- struct _drop_msg *m = data;
-
m->action = GDK_ACTION_COPY;
ml_drop_action(m);
}
static void
-ml_drop_popup_move(EPopup *ep, EPopupItem *item, void *data)
+ml_drop_popup_move(GtkWidget *item, struct _drop_msg *m)
{
- struct _drop_msg *m = data;
-
m->action = GDK_ACTION_MOVE;
ml_drop_action(m);
}
static void
-ml_drop_popup_cancel(EPopup *ep, EPopupItem *item, void *data)
+ml_drop_popup_cancel(GtkWidget *item, struct _drop_msg *m)
{
- struct _drop_msg *m = data;
-
m->aborted = TRUE;
mail_msg_free(&m->msg);
}
-static EPopupItem ml_drop_popup_menu[] = {
- { E_POPUP_ITEM, "00.emc.02", N_("_Copy"), ml_drop_popup_copy, NULL, "stock_folder-copy", 0 },
- { E_POPUP_ITEM, "00.emc.03", N_("_Move"), ml_drop_popup_move, NULL, "stock_folder-move", 0 },
- { E_POPUP_BAR, "10.emc" },
- { E_POPUP_ITEM, "99.emc.00", N_("Cancel _Drag"), ml_drop_popup_cancel, NULL, NULL, 0 },
+static EMPopupItem ml_drop_popup_menu[] = {
+ { EM_POPUP_ITEM, "00.emc.02", N_("_Copy"), G_CALLBACK(ml_drop_popup_copy), NULL, "stock_folder-copy", 0 },
+ { EM_POPUP_ITEM, "00.emc.03", N_("_Move"), G_CALLBACK(ml_drop_popup_move), NULL, "stock_folder-move", 0 },
+ { EM_POPUP_BAR, "10.emc" },
+ { EM_POPUP_ITEM, "99.emc.00", N_("Cancel _Drag"), G_CALLBACK(ml_drop_popup_cancel), NULL, NULL, 0 },
};
static void
-ml_drop_popup_free(EPopup *ep, GSList *items, void *data)
-{
- g_slist_free(items);
-
- /* FIXME: free data if no item was selected? */
-}
-
-static void
ml_tree_drag_data_received (ETree *tree, int row, ETreePath path, int col,
GdkDragContext *context, gint x, gint y,
GtkSelectionData *data, guint info,
@@ -1755,12 +1737,15 @@ ml_tree_drag_data_received (ETree *tree, int row, ETreePath path, int col,
GtkMenu *menu;
int i;
- emp = em_popup_new("org.gnome.mail.messagelist.popup.drop");
- for (i=0;i<sizeof(ml_drop_popup_menu)/sizeof(ml_drop_popup_menu[0]);i++)
- menus = g_slist_append(menus, &ml_drop_popup_menu[i]);
+ emp = em_popup_new("com.ximian.mail.messagelist.popup.drop");
+ for (i=0;i<sizeof(ml_drop_popup_menu)/sizeof(ml_drop_popup_menu[0]);i++) {
+ EMPopupItem *item = &ml_drop_popup_menu[i];
- e_popup_add_items((EPopup *)emp, menus, NULL, ml_drop_popup_free, m);
- menu = e_popup_create_menu_once((EPopup *)emp, NULL, 0);
+ item->activate_data = m;
+ menus = g_slist_append(menus, item);
+ }
+ em_popup_add_items(emp, menus, (GDestroyNotify)g_slist_free);
+ menu = em_popup_create_menu_once(emp, NULL, 0, 0);
gtk_menu_popup(menu, NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time());
} else {
ml_drop_action(m);
@@ -1802,11 +1787,12 @@ ml_scrolled (GtkAdjustment *adj, MessageList *ml)
}
/*
- * GObject::init
+ * GtkObject::init
*/
static void
-message_list_init (MessageList *message_list)
+message_list_init (GtkObject *object)
{
+ MessageList *message_list = MESSAGE_LIST (object);
struct _MessageListPrivate *p;
GtkAdjustment *adjustment;
GdkAtom matom;
@@ -1864,7 +1850,7 @@ message_list_destroy(GtkObject *object)
mail_async_event_destroy(message_list->async_event);
message_list->async_event = NULL;
}
-
+
if (message_list->folder) {
/* need to do this before removing folder, folderinfo's might not exist after */
save_tree_state(message_list);
@@ -1948,20 +1934,20 @@ message_list_finalise (GObject *object)
}
/*
- * GObjectClass::init
+ * GtkObjectClass::init
*/
static void
-message_list_class_init (MessageListClass *message_list_class)
+message_list_class_init (GObjectClass *object_class)
{
- GObjectClass *object_class = (GObjectClass *) message_list_class;
- GtkObjectClass *gtkobject_class = (GtkObjectClass *) message_list_class;
int i;
+ message_list_parent_class = g_type_class_ref(PARENT_TYPE);
+
for (i=0;i<sizeof(ml_drag_info)/sizeof(ml_drag_info[0]);i++)
ml_drag_info[i].atom = gdk_atom_intern(ml_drag_info[i].target, FALSE);
object_class->finalize = message_list_finalise;
- gtkobject_class->destroy = message_list_destroy;
+ ((GtkObjectClass *)object_class)->destroy = message_list_destroy;
message_list_signals[MESSAGE_SELECTED] =
g_signal_new ("message_selected",
@@ -1999,7 +1985,6 @@ message_list_class_init (MessageListClass *message_list_class)
static void
message_list_construct (MessageList *message_list)
{
- AtkObject *a11y;
gboolean construct_failed;
message_list->model =
e_tree_memory_callbacks_new (ml_tree_icon_at,
@@ -2041,11 +2026,6 @@ message_list_construct (MessageList *message_list)
if (!construct_failed)
e_tree_root_node_set_visible (message_list->tree, FALSE);
- if (atk_get_root () != NULL) {
- a11y = gtk_widget_get_accessible (message_list->tree);
- atk_object_set_name (a11y, _("Message List"));
- }
-
g_signal_connect((message_list->tree), "cursor_activated",
G_CALLBACK (on_cursor_activated_cmd),
message_list);
@@ -2161,7 +2141,7 @@ find_next_undeleted (MessageList *ml)
check |= CAMEL_MESSAGE_DELETED;
info = get_message_info (ml, node);
- if (info && (camel_message_info_flags(info) & check) == 0) {
+ if (info && (info->flags & check) == 0) {
return NULL;
}
@@ -2178,7 +2158,7 @@ find_next_undeleted (MessageList *ml)
node = e_tree_node_at_row (et, vrow);
info = get_message_info (ml, node);
- if (info && (camel_message_info_flags(info) & check) == 0) {
+ if (info && (info->flags & check) == 0) {
return g_strdup (camel_message_info_uid (info));
}
vrow ++;
@@ -2681,21 +2661,17 @@ mail_folder_hide_by_flag (CamelFolder *folder, MessageList *ml, CamelFolderChang
for (i = 0; i < oldchanges->uid_changed->len; i++) {
ETreePath node = g_hash_table_lookup (ml->uid_nodemap, oldchanges->uid_changed->pdata[i]);
- guint32 flags;
-
+
info = camel_folder_get_message_info (folder, oldchanges->uid_changed->pdata[i]);
- if (info)
- flags = camel_message_info_flags(info);
-
- if (node != NULL && info != NULL && (flags & flag) != 0)
+ if (node != NULL && info != NULL && (info->flags & flag) != 0)
camel_folder_change_info_remove_uid (newchanges, oldchanges->uid_changed->pdata[i]);
- else if (node == NULL && info != NULL && (flags & flag) == 0)
+ else if (node == NULL && info != NULL && (info->flags & flag) == 0)
camel_folder_change_info_add_uid (newchanges, oldchanges->uid_changed->pdata[i]);
else
camel_folder_change_info_change_uid (newchanges, oldchanges->uid_changed->pdata[i]);
camel_folder_free_message_info (folder, info);
}
-
+
if (newchanges->uid_added->len > 0 || newchanges->uid_removed->len > 0) {
for (i = 0; i < oldchanges->uid_added->len; i++)
camel_folder_change_info_add_uid (newchanges, oldchanges->uid_added->pdata[i]);
@@ -2764,7 +2740,7 @@ folder_changed (CamelObject *o, gpointer event_data, gpointer user_data)
{
CamelFolderChangeInfo *changes;
MessageList *ml = MESSAGE_LIST (user_data);
-
+
if (event_data) {
changes = camel_folder_change_info_new();
camel_folder_change_info_cat(changes, (CamelFolderChangeInfo *)event_data);
@@ -2806,7 +2782,6 @@ message_list_set_folder (MessageList *message_list, CamelFolder *folder, const c
message_list->idle_id = 0;
}
- /* reset the normalised sort performance hack */
g_hash_table_foreach_remove (message_list->normalised_hash, normalised_free, NULL);
mail_regen_cancel(message_list);
@@ -2878,6 +2853,8 @@ message_list_set_folder (MessageList *message_list, CamelFolder *folder, const c
}
}
+E_MAKE_TYPE (message_list, "MessageList", MessageList, message_list_class_init, message_list_init, PARENT_TYPE);
+
static gboolean
on_cursor_activated_idle (gpointer data)
{
@@ -2957,8 +2934,7 @@ on_click (ETree *tree, gint row, ETreePath path, gint col, GdkEvent *event, Mess
{
CamelMessageInfo *info;
int flag;
- guint32 flags;
-
+
if (col == COL_MESSAGE_STATUS)
flag = CAMEL_MESSAGE_SEEN;
else if (col == COL_FLAGGED)
@@ -2968,21 +2944,19 @@ on_click (ETree *tree, gint row, ETreePath path, gint col, GdkEvent *event, Mess
if (!(info = get_message_info (list, path)))
return FALSE;
-
- flags = camel_message_info_flags(info);
-
+
/* If a message was marked as deleted and the user flags it as
important, marks it as needing a reply, marks it as unread,
then undelete the message. */
- if (flags & CAMEL_MESSAGE_DELETED) {
- if (col == COL_FLAGGED && !(flags & CAMEL_MESSAGE_FLAGGED))
+ if (info->flags & CAMEL_MESSAGE_DELETED) {
+ if (col == COL_FLAGGED && !(info->flags & CAMEL_MESSAGE_FLAGGED))
flag |= CAMEL_MESSAGE_DELETED;
- if (col == COL_MESSAGE_STATUS && (flags & CAMEL_MESSAGE_SEEN))
+ if (col == COL_MESSAGE_STATUS && (info->flags & CAMEL_MESSAGE_SEEN))
flag |= CAMEL_MESSAGE_DELETED;
}
- camel_folder_set_message_flags (list->folder, camel_message_info_uid (info), flag, ~flags);
+ camel_folder_set_message_flags (list->folder, camel_message_info_uid (info), flag, ~info->flags);
if (flag == CAMEL_MESSAGE_SEEN && list->seen_id) {
g_source_remove (list->seen_id);
@@ -3673,8 +3647,13 @@ mail_regen_list (MessageList *ml, const char *search, const char *hideexpr, Came
struct _regen_list_msg *m;
GConfClient *gconf;
- if (ml->folder == NULL)
+ if (ml->folder == NULL) {
+ if (ml->search != search) {
+ g_free(ml->search);
+ ml->search = g_strdup(search);
+ }
return;
+ }
mail_regen_cancel(ml);
diff --git a/plugins/.cvsignore b/plugins/.cvsignore
deleted file mode 100644
index cffa601193..0000000000
--- a/plugins/.cvsignore
+++ /dev/null
@@ -1,4 +0,0 @@
-.deps
-.libs
-Makefile
-Makefile.in
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
deleted file mode 100644
index e8cba7c235..0000000000
--- a/plugins/Makefile.am
+++ /dev/null
@@ -1,2 +0,0 @@
-SUBDIRS = $(plugins_enabled)
-DIST_SUBDIRS = $(plugins_base) $(plugins_all)
diff --git a/plugins/addressbook-file/ChangeLog b/plugins/addressbook-file/ChangeLog
deleted file mode 100644
index ac66da93e1..0000000000
--- a/plugins/addressbook-file/ChangeLog
+++ /dev/null
@@ -1,3 +0,0 @@
-2005-01-21 Sivaiah Nallagatla <snallagatla@novell.com>
-
- * initial commit
diff --git a/plugins/addressbook-file/Makefile.am b/plugins/addressbook-file/Makefile.am
deleted file mode 100644
index 76ae687dfd..0000000000
--- a/plugins/addressbook-file/Makefile.am
+++ /dev/null
@@ -1,16 +0,0 @@
-INCLUDES = \
- -I$(top_srcdir) \
- $(EVOLUTION_CFLAGS) \
- $(EVOLUTION_ADDRESSBOOK_CFLAGS)
-
-
-@EVO_PLUGIN_RULE@
-
-plugin_DATA = org-gnome-addressbook-file.eplug
-plugin_LTLIBRARIES = liborg-gnome-addressbook-file.la
-
-
-liborg_gnome_addressbook_file_la_SOURCES = addressbook-file.c
-liborg_gnome_addressbook_file_la_LDFLAGS = -module -avoid-version
-
-EXTRA_DIST = org-gnome-addressbook-file.eplug.in
diff --git a/plugins/addressbook-file/addressbook-file.c b/plugins/addressbook-file/addressbook-file.c
deleted file mode 100644
index 04b1e59b68..0000000000
--- a/plugins/addressbook-file/addressbook-file.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- *
- *
- * Copyright (C) 2004 Sivaiah Nallagatla
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- */
-
-#include <gtk/gtklabel.h>
-#include <gtk/gtkentry.h>
-#include <gtk/gtktable.h>
-#include <gtk/gtkspinbutton.h>
-#include <gtk/gtkoptionmenu.h>
-#include <gtk/gtkmenu.h>
-#include <gtk/gtkmenuitem.h>
-#include <gtk/gtkhbox.h>
-#include <e-util/e-config.h>
-#include <addressbook/gui/widgets/eab-config.h>
-#include <libedataserver/e-source.h>
-#include <libgnome/gnome-i18n.h>
-#include <string.h>
-
-GtkWidget *e_calendar_file_dummy (EPlugin *epl, EConfigHookItemFactoryData *data);
-
-GtkWidget *
-e_book_file_dummy (EPlugin *epl, EConfigHookItemFactoryData *data)
-{
- EABConfigTargetSource *t = (EABConfigTargetSource *) data->target;
- ESource *source = t->source;
- char *uri_text;
-
- uri_text = e_source_get_uri (source);
- if (strncmp (uri_text, "file", 4)) {
- g_free (uri_text);
-
- return NULL;
- }
-
- e_source_set_relative_uri (source, e_source_peek_uid (source));
- uri_text = e_source_get_uri (source);
-
- return NULL;
-}
diff --git a/plugins/addressbook-file/org-gnome-addressbook-file.eplug.in b/plugins/addressbook-file/org-gnome-addressbook-file.eplug.in
deleted file mode 100644
index 7d1f8ad655..0000000000
--- a/plugins/addressbook-file/org-gnome-addressbook-file.eplug.in
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0"?>
-<e-plugin-list>
- <e-plugin
- type="shlib"
- location="@PLUGINDIR@/liborg-gnome-addressbook-file.so"
- id="org.gnome.evolution.addressbook.file"
- name="Local Address Books">
- <hook class="org.gnome.evolution.addressbook.config:1.0">
- <group
- target="source"
- id="com.novell.evolution.addressbook.config.accountEditor">
- <item
- type="item"
- path="00.general/10.display/00.file_dummy"
- factory="e_book_file_dummy"/>
- </group>
- </hook>
- </e-plugin>
-</e-plugin-list>
diff --git a/plugins/addressbook-groupwise/ChangeLog b/plugins/addressbook-groupwise/ChangeLog
deleted file mode 100644
index b51b27aa12..0000000000
--- a/plugins/addressbook-groupwise/ChangeLog
+++ /dev/null
@@ -1,3 +0,0 @@
-2005-01-29 Sivaiah Nallagatla <snallagatla@novell.com>
-
- * initial commit
diff --git a/plugins/addressbook-groupwise/Makefile.am b/plugins/addressbook-groupwise/Makefile.am
deleted file mode 100644
index 8a79c5b39c..0000000000
--- a/plugins/addressbook-groupwise/Makefile.am
+++ /dev/null
@@ -1,16 +0,0 @@
-INCLUDES = \
- -I$(top_srcdir) \
- $(EVOLUTION_CFLAGS) \
- $(EVOLUTION_ADDRESSBOOK_CFLAGS)
-
-
-@EVO_PLUGIN_RULE@
-
-plugin_DATA = org-gnome-addressbook-groupwise.eplug
-plugin_LTLIBRARIES = liborg-gnome-addressbook-groupwise.la
-
-
-liborg_gnome_addressbook_groupwise_la_SOURCES = addressbook-groupwise.c
-liborg_gnome_addressbook_groupwise_la_LDFLAGS = -module -avoid-version
-
-EXTRA_DIST = org-gnome-addressbook-groupwise.eplug.in
diff --git a/plugins/addressbook-groupwise/addressbook-groupwise.c b/plugins/addressbook-groupwise/addressbook-groupwise.c
deleted file mode 100644
index 1cd1691afb..0000000000
--- a/plugins/addressbook-groupwise/addressbook-groupwise.c
+++ /dev/null
@@ -1,75 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/* *
- * Copyright (C) 2004 Sivaiah Nallagatla <snallagtla@novell.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- */
-
-#include <gtk/gtklabel.h>
-#include <gtk/gtkentry.h>
-#include <gtk/gtktable.h>
-#include <gtk/gtkspinbutton.h>
-#include <gtk/gtkoptionmenu.h>
-#include <gtk/gtkmenu.h>
-#include <gtk/gtkmenuitem.h>
-#include <gtk/gtkhbox.h>
-#include <e-util/e-config.h>
-#include <addressbook/gui/widgets/eab-config.h>
-#include <libedataserver/e-source.h>
-#include <libgnome/gnome-i18n.h>
-#include <string.h>
-
-void commit_groupwise_addressbook (EPlugin *epl, EConfigTarget *target);
-GtkWidget *e_book_groupwise_dummy (EPlugin *epl, EConfigHookItemFactoryData *data);
-
-void
-commit_groupwise_addressbook (EPlugin *epl, EConfigTarget *target)
-{
- EABConfigTargetSource *t = (EABConfigTargetSource *) target;
- ESource *source = t->source;
- char *uri_text;
- ESourceGroup *source_group;
- char *relative_uri;
- GSList *l;
-
- uri_text = e_source_get_uri (source);
- if (strncmp (uri_text, "groupwise", 9)) {
- g_free (uri_text);
-
- return ;
- }
- e_source_set_property (source, "auth-domain", "Groupwise");
- relative_uri = g_strconcat (";", e_source_peek_name (source), NULL);
- e_source_set_relative_uri (source, relative_uri);
- g_free (relative_uri);
-
- source_group = e_source_peek_group (source);
- l = e_source_group_peek_sources(source_group);
- if (l && l->data ) {
- e_source_set_property(source, "auth", e_source_get_property(l->data, "auth"));
- e_source_set_property(source, "user", e_source_get_property(l->data, "user"));
- e_source_set_property(source, "use_ssl", e_source_get_property(l->data, "use_ssl"));
- e_source_set_property(source, "port", e_source_get_property(l->data, "port"));
- }
-}
-
-GtkWidget *
-e_book_groupwise_dummy (EPlugin *epl, EConfigHookItemFactoryData *data)
-{
-
-
- return NULL;
-}
diff --git a/plugins/addressbook-groupwise/org-gnome-addressbook-groupwise.eplug.in b/plugins/addressbook-groupwise/org-gnome-addressbook-groupwise.eplug.in
deleted file mode 100644
index 6c4a76db71..0000000000
--- a/plugins/addressbook-groupwise/org-gnome-addressbook-groupwise.eplug.in
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0"?>
-<e-plugin-list>
- <e-plugin
- type="shlib"
- location="@PLUGINDIR@/liborg-gnome-addressbook-groupwise.so"
- id="org.gnome.evolution.addressbook.groupwise"
- name="Groupwise Address Books">
- <hook class="org.gnome.evolution.addressbook.config:1.0">
- <group
- target="source"
- id="com.novell.evolution.addressbook.config.accountEditor"
- commit="commit_groupwise_addressbook">
- <item
- type="item"
- path="00.general/10.display/00.gw_dummy"
- factory="e_book_groupwise_dummy"
- />
- </group>
- </hook>
- </e-plugin>
-</e-plugin-list>
diff --git a/plugins/audio-inline/.cvsignore b/plugins/audio-inline/.cvsignore
deleted file mode 100644
index 683d5ddbe2..0000000000
--- a/plugins/audio-inline/.cvsignore
+++ /dev/null
@@ -1,5 +0,0 @@
-.deps
-.libs
-Makefile
-Makefile.in
-*.eplug \ No newline at end of file
diff --git a/plugins/audio-inline/ChangeLog b/plugins/audio-inline/ChangeLog
deleted file mode 100644
index 6dbf786aa7..0000000000
--- a/plugins/audio-inline/ChangeLog
+++ /dev/null
@@ -1,34 +0,0 @@
-2004-11-26 JP Rosevear <jpr@novell.com>
-
- * audio-inline.c (org_gnome_audio_inline_add_button): get image
- from icon factory directly
-
-2004-11-11 Radek Doulik <rodo@ximian.com>
-
- * org-gnome-audio-inline.eplug.in: fixed author and description
-
-2004-11-01 JP Rosevear <jpr@novell.com>
-
- * Makefile.am: dist .eplug.in file
-
-2004-10-25 Radek Doulik <rodo@ximian.com>
-
- * audio-inline.c: removed unused enum declaration
- (org_gnome_audio_inline_play_clicked): added cast to &argv to
- quiet compiler
- handle more mime types
-
- * org-gnome-audio-inline.eplug.in: handle application/x-ogg mime
- type
- handle more mime types
-
- * audio-inline.c: handle application/x-ogg mime type
-
- * org-gnome-audio-inline.eplug.in: handle audio/x-mp3 mime type
-
- * audio-inline.c: (org_gnome_audio_inline_play_clicked): handle
- audio/x-mp3 mime type
-
-2004-10-25 Radek Doulik <rodo@ximian.com>
-
- * audio-inline.c: imported audio inline plugin \ No newline at end of file
diff --git a/plugins/audio-inline/Makefile.am b/plugins/audio-inline/Makefile.am
deleted file mode 100644
index e969972b6b..0000000000
--- a/plugins/audio-inline/Makefile.am
+++ /dev/null
@@ -1,15 +0,0 @@
-INCLUDES = \
- -I$(top_srcdir) \
- $(EVOLUTION_MAIL_CFLAGS) \
- $(GSTREAMER_CFLAGS)
-
-@EVO_PLUGIN_RULE@
-
-plugin_DATA = org-gnome-audio-inline.eplug
-plugin_LTLIBRARIES = liborg-gnome-audio-inline.la
-
-liborg_gnome_audio_inline_la_SOURCES = audio-inline.c
-liborg_gnome_audio_inline_la_LDFLAGS = -module -avoid-version
-liborg_gnome_audio_inline_la_LIBADD = $(GSTREAMER_LIBS)
-
-EXTRA_DIST = org-gnome-audio-inline.eplug.in \ No newline at end of file
diff --git a/plugins/audio-inline/audio-inline.c b/plugins/audio-inline/audio-inline.c
deleted file mode 100644
index 36c6cfed44..0000000000
--- a/plugins/audio-inline/audio-inline.c
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- Copyright (C) 2004 Novell, Inc.
- Author: Radek Doulik
-
- */
-
-/* This file is licensed under the GNU GPL v2 or later */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <unistd.h> /* for unlink */
-#include <string.h>
-#include "e-util/e-icon-factory.h"
-#include "e-util/e-mktemp.h"
-#include "camel/camel-medium.h"
-#include "camel/camel-mime-part.h"
-#include "camel/camel-stream.h"
-#include "camel/camel-stream-fs.h"
-#include "mail/em-format-hook.h"
-#include "mail/em-format-html.h"
-#include "gtk/gtkbutton.h"
-#include "gtk/gtkbox.h"
-#include "gtk/gtkimage.h"
-#include "gtk/gtkhbbox.h"
-#include "gtkhtml/gtkhtml-embedded.h"
-#include "gst/gst.h"
-
-#define d(x) x
-
-void org_gnome_audio_inline_format (void *ep, EMFormatHookTarget *t);
-
-volatile static int org_gnome_audio_class_id_counter = 0;
-
-struct _org_gnome_audio_inline_pobject {
- EMFormatHTMLPObject object;
-
- CamelMimePart *part;
- char *filename;
- GstElement *thread;
-};
-
-static void
-org_gnome_audio_inline_pobject_free (EMFormatHTMLPObject *o)
-{
- struct _org_gnome_audio_inline_pobject *po = (struct _org_gnome_audio_inline_pobject *) o;
-
- d(printf ("audio inline formatter: pobject free\n"));
-
- if (po->part) {
- camel_object_unref (po->part);
- po->part = NULL;
- }
- if (po->filename) {
- unlink (po->filename);
- g_free (po->filename);
- po->filename = NULL;
- }
- if (po->thread) {
- gst_element_set_state (po->thread, GST_STATE_NULL);
- gst_object_unref (GST_OBJECT (po->thread));
- po->thread = NULL;
- }
-}
-
-static void
-org_gnome_audio_inline_pause_clicked (GtkWidget *button, EMFormatHTMLPObject *pobject)
-{
- struct _org_gnome_audio_inline_pobject *po = (struct _org_gnome_audio_inline_pobject *) pobject;
-
- if (po->thread) {
- /* start playing */
- gst_element_set_state (po->thread, GST_STATE_PAUSED);
- }
-}
-
-static void
-org_gnome_audio_inline_stop_clicked (GtkWidget *button, EMFormatHTMLPObject *pobject)
-{
- struct _org_gnome_audio_inline_pobject *po = (struct _org_gnome_audio_inline_pobject *) pobject;
-
- if (po->thread) {
- /* start playing */
- gst_element_set_state (po->thread, GST_STATE_READY);
- }
-}
-
-static GstElement *
-org_gnome_audio_inline_gst_mpeg_thread (GstElement *filesrc)
-{
- GstElement *thread, *decoder, *audiosink;
-
- /* create a new thread to hold the elements */
- thread = gst_thread_new ("org-gnome-audio-inline-mpeg-thread");
-
- /* now it's time to get the decoder */
- decoder = gst_element_factory_make ("mad", "decoder");
-
- /* and an audio sink */
- audiosink = gst_element_factory_make ("osssink", "play_audio");
-
- /* add objects to the main pipeline */
- gst_bin_add_many (GST_BIN (thread), filesrc, decoder, audiosink, NULL);
-
- /* link src to sink */
- gst_element_link_many (filesrc, decoder, audiosink, NULL);
-
- return thread;
-}
-
-static GstElement *
-org_gnome_audio_inline_gst_ogg_thread (GstElement *filesrc)
-{
- GstElement *thread, *demuxer, *decoder, *converter, *audiosink;
-
- /* create a new thread to hold the elements */
- thread = gst_thread_new ("org-gnome-audio-inline-mpeg-thread");
-
- /* create an ogg demuxer */
- demuxer = gst_element_factory_make ("oggdemux", "demuxer");
- g_assert (demuxer != NULL);
-
- /* create a vorbis decoder */
- decoder = gst_element_factory_make ("vorbisdec", "decoder");
- g_assert (decoder != NULL);
-
- /* create an audio converter */
- converter = gst_element_factory_make ("audioconvert", "converter");
- g_assert (decoder != NULL);
-
- /* and an audio sink */
- audiosink = gst_element_factory_make ("osssink", "play_audio");
- g_assert (audiosink != NULL);
-
- /* add objects to the thread */
- gst_bin_add_many (GST_BIN (thread), filesrc, demuxer, decoder, converter, audiosink, NULL);
-
- /* link them in the logical order */
- gst_element_link_many (filesrc, demuxer, decoder, converter, audiosink, NULL);
-
- return thread;
-}
-
-static GstElement *
-org_gnome_audio_inline_gst_flac_thread (GstElement *filesrc)
-{
- GstElement *thread, *decoder, *audiosink;
-
- /* create a new thread to hold the elements */
- thread = gst_thread_new ("org-gnome-audio-inline-flac-thread");
-
- /* now it's time to get the decoder */
- decoder = gst_element_factory_make ("flacdec", "decoder");
-
- /* and an audio sink */
- audiosink = gst_element_factory_make ("osssink", "play_audio");
-
- /* add objects to the main pipeline */
- gst_bin_add_many (GST_BIN (thread), filesrc, decoder, audiosink, NULL);
-
- /* link src to sink */
- gst_element_link_many (filesrc, decoder, audiosink, NULL);
-
- return thread;
-}
-
-static GstElement *
-org_gnome_audio_inline_gst_mod_thread (GstElement *filesrc)
-{
- GstElement *thread, *decoder, *audiosink;
-
- /* create a new thread to hold the elements */
- thread = gst_thread_new ("org-gnome-audio-inline-flac-thread");
-
- /* now it's time to get the decoder */
- decoder = gst_element_factory_make ("mikmod", "decoder");
-
- /* and an audio sink */
- audiosink = gst_element_factory_make ("osssink", "play_audio");
-
- /* add objects to the main pipeline */
- gst_bin_add_many (GST_BIN (thread), filesrc, decoder, audiosink, NULL);
-
- /* link src to sink */
- gst_element_link_many (filesrc, decoder, audiosink, NULL);
-
- return thread;
-}
-
-static void
-org_gnome_audio_inline_play_clicked (GtkWidget *button, EMFormatHTMLPObject *pobject)
-{
- struct _org_gnome_audio_inline_pobject *po = (struct _org_gnome_audio_inline_pobject *) pobject;
-
- d(printf ("audio inline formatter: play\n"));
-
- if (!po->filename) {
- CamelStream *stream;
- CamelDataWrapper *data;
- int argc = 1;
- char *argv [] = { "org_gnome_audio_inline", NULL };
-
- po->filename = e_mktemp ("org-gnome-audio-inline-file-XXXXXX");
-
- d(printf ("audio inline formatter: write to temp file %s\n", po->filename));
-
- stream = camel_stream_fs_new_with_name (po->filename, O_RDWR | O_CREAT | O_TRUNC, 0600);
- data = camel_medium_get_content_object (CAMEL_MEDIUM (po->part));
- camel_data_wrapper_decode_to_stream (data, stream);
- camel_stream_flush (stream);
- camel_object_unref (stream);
-
- d(printf ("audio inline formatter: init gst thread\n"));
-
- if (gst_init_check (&argc, (char ***) &argv)) {
- CamelContentType *type;
- GstElement *filesrc;
-
- /* create a disk reader */
- filesrc = gst_element_factory_make ("filesrc", "disk_source");
- g_object_set (G_OBJECT (filesrc), "location", po->filename, NULL);
-
- type = camel_mime_part_get_content_type (po->part);
- if (type) {
- if (!strcasecmp (type->type, "audio")) {
- if (!strcasecmp (type->subtype, "mpeg") || !strcasecmp (type->subtype, "x-mpeg")
- || !strcasecmp (type->subtype, "mpeg3") || !strcasecmp (type->subtype, "x-mpeg3")
- || !strcasecmp (type->subtype, "mp3") || !strcasecmp (type->subtype, "x-mp3")) {
- po->thread = org_gnome_audio_inline_gst_mpeg_thread (filesrc);
- } else if (!strcasecmp (type->subtype, "flac") || !strcasecmp (type->subtype, "x-flac")) {
- po->thread = org_gnome_audio_inline_gst_flac_thread (filesrc);
- } else if (!strcasecmp (type->subtype, "mod") || !strcasecmp (type->subtype, "x-mod")) {
- po->thread = org_gnome_audio_inline_gst_mod_thread (filesrc);
- }
- } else if (!strcasecmp (type->type, "application")) {
- if (!strcasecmp (type->subtype, "ogg") || !strcasecmp (type->subtype, "x-ogg")) {
- po->thread = org_gnome_audio_inline_gst_ogg_thread (filesrc);
- }
- }
- }
- }
- }
-
- if (po->thread) {
- /* start playing */
- gst_element_set_state (po->thread, GST_STATE_PLAYING);
- }
-}
-
-static void
-org_gnome_audio_inline_add_button (GtkWidget *box, char *icon_name, GCallback cb, gpointer data)
-{
- GtkWidget *icon, *button;
- GdkPixbuf *pixbuf;
-
- icon = e_icon_factory_get_image (icon_name, E_ICON_SIZE_LARGE_TOOLBAR);
- gtk_widget_show (icon);
-
- button = gtk_button_new ();
- g_signal_connect (button, "clicked", cb, data);
-
- gtk_container_add ((GtkContainer *) button, icon);
- gtk_widget_show (button);
- gtk_box_pack_end_defaults (GTK_BOX (box), button);
-}
-
-static gboolean
-org_gnome_audio_inline_button_panel (EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *pobject)
-{
- GtkWidget *box;
- struct _org_gnome_audio_inline_pobject *po = (struct _org_gnome_audio_inline_pobject *) pobject;
-
- /* it is OK to call UI functions here, since we are called from UI thread */
-
- box = gtk_hbutton_box_new ();
- org_gnome_audio_inline_add_button (box, "stock_media-play", G_CALLBACK (org_gnome_audio_inline_play_clicked), po);
- org_gnome_audio_inline_add_button (box, "stock_media-pause", G_CALLBACK (org_gnome_audio_inline_pause_clicked), po);
- org_gnome_audio_inline_add_button (box, "stock_media-stop", G_CALLBACK (org_gnome_audio_inline_stop_clicked), po);
-
- gtk_widget_show (box);
- gtk_container_add ((GtkContainer *) eb, box);
-
- return TRUE;
-}
-
-void
-org_gnome_audio_inline_format (void *ep, EMFormatHookTarget *t)
-{
- struct _org_gnome_audio_inline_pobject *pobj;
- char *classid = g_strdup_printf ("org-gnome-audio-inline-button-panel-%d", org_gnome_audio_class_id_counter);
-
- org_gnome_audio_class_id_counter ++;
-
- d(printf ("audio inline formatter: format classid %s\n", classid));
-
- pobj = (struct _org_gnome_audio_inline_pobject *) em_format_html_add_pobject ((EMFormatHTML *) t->format, sizeof(*pobj), classid,
- t->part, org_gnome_audio_inline_button_panel);
- camel_object_ref (t->part);
- pobj->part = t->part;
- pobj->filename = NULL;
- pobj->thread = NULL;
- pobj->object.free = org_gnome_audio_inline_pobject_free;
-
- camel_stream_printf (t->stream, "<object classid=%s></object>\n", classid);
-}
diff --git a/plugins/audio-inline/org-gnome-audio-inline.eplug.in b/plugins/audio-inline/org-gnome-audio-inline.eplug.in
deleted file mode 100644
index 0d87a36cc2..0000000000
--- a/plugins/audio-inline/org-gnome-audio-inline.eplug.in
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0"?>
-<e-plugin-list>
- <e-plugin
- type="shlib"
- id="org.gnome.evolution.plugin.audioInline"
- location="@PLUGINDIR@/liborg-gnome-audio-inline.la"
- name="Audio inline plugin">
-
- <description>A formatter plugin which displays audio attachments inline and allows you to play them directly from evolution</description>
- <author name="Radek Doulík" email="rodo@novell.com"/>
-
- <hook class="org.gnome.evolution.mail.format:1.0">
- <group id="EMFormatHTMLDisplay">
- <item mime_type="audio/mpeg" format="org_gnome_audio_inline_format" flags="inline_disposition"/>
- <item mime_type="audio/x-mpeg" format="org_gnome_audio_inline_format" flags="inline_disposition"/>
- <item mime_type="audio/mpeg3" format="org_gnome_audio_inline_format" flags="inline_disposition"/>
- <item mime_type="audio/x-mpeg3" format="org_gnome_audio_inline_format" flags="inline_disposition"/>
- <item mime_type="audio/mp3" format="org_gnome_audio_inline_format" flags="inline_disposition"/>
- <item mime_type="audio/x-mp3" format="org_gnome_audio_inline_format" flags="inline_disposition"/>
- <item mime_type="audio/flac" format="org_gnome_audio_inline_format" flags="inline_disposition"/>
- <item mime_type="audio/x-flac" format="org_gnome_audio_inline_format" flags="inline_disposition"/>
- <item mime_type="audio/mod" format="org_gnome_audio_inline_format" flags="inline_disposition"/>
- <item mime_type="audio/x-mod" format="org_gnome_audio_inline_format" flags="inline_disposition"/>
- <item mime_type="application/ogg" format="org_gnome_audio_inline_format" flags="inline_disposition"/>
- <item mime_type="application/x-ogg" format="org_gnome_audio_inline_format" flags="inline_disposition"/>
- </group>
- </hook>
-
- </e-plugin>
-</e-plugin-list>
diff --git a/plugins/backup-restore/.cvsignore b/plugins/backup-restore/.cvsignore
deleted file mode 100644
index 76bd16c42d..0000000000
--- a/plugins/backup-restore/.cvsignore
+++ /dev/null
@@ -1,6 +0,0 @@
-.deps
-.libs
-Makefile
-Makefile.in
-*.eplug
-backup \ No newline at end of file
diff --git a/plugins/backup-restore/ChangeLog b/plugins/backup-restore/ChangeLog
deleted file mode 100644
index df66bd61fc..0000000000
--- a/plugins/backup-restore/ChangeLog
+++ /dev/null
@@ -1,4 +0,0 @@
-2004-12-16 JP Rosevear <jpr@novell.com>
-
- * Imported backup/restore plugin
-
diff --git a/plugins/backup-restore/Makefile.am b/plugins/backup-restore/Makefile.am
deleted file mode 100644
index 3627d1c69a..0000000000
--- a/plugins/backup-restore/Makefile.am
+++ /dev/null
@@ -1,26 +0,0 @@
-INCLUDES = \
- -DEVOLUTION_LOCALEDIR=\""$(localedir)"\" \
- -DEVOLUTION_TOOLSDIR=\""$(privlibexecdir)"\" \
- -DPREFIX=\""$(prefix)"\" \
- -DSYSCONFDIR=\""$(sysconfdir)"\" \
- -DDATADIR=\""$(datadir)"\" \
- -DLIBDIR=\""$(libdir)"\" \
- -I$(top_srcdir) \
- $(SHELL_CFLAGS) \
- $(E_UTIL_CFLAGS)
-
-@EVO_PLUGIN_RULE@
-
-plugin_DATA = org-gnome-backup-restore.eplug org-gnome-backup-restore.xml
-plugin_LTLIBRARIES = liborg-gnome-backup-restore.la
-
-liborg_gnome_backup_restore_la_SOURCES = backup-restore.c
-liborg_gnome_backup_restore_la_LDFLAGS = -module -avoid-version
-
-privlibexec_PROGRAMS = backup
-backup_SOURCES = backup.c
-backup_LDADD = $(SHELL_LIBS)
-
-EXTRA_DIST = \
- org-gnome-backup-restore.eplug.in \
- org-gnome-backup-restore.xml \ No newline at end of file
diff --git a/plugins/backup-restore/backup-restore.c b/plugins/backup-restore/backup-restore.c
deleted file mode 100644
index 7344806e83..0000000000
--- a/plugins/backup-restore/backup-restore.c
+++ /dev/null
@@ -1,122 +0,0 @@
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <gtk/gtk.h>
-#include <libgnome/gnome-i18n.h>
-#include "shell/es-menu.h"
-
-void org_gnome_backup_restore_backup (EPlugin *ep, ESMenuTargetShell *target);
-void org_gnome_backup_restore_restore (EPlugin *ep, ESMenuTargetShell *target);
-
-static void
-backup (const char *filename, gboolean restart)
-{
- if (restart)
- execl (EVOLUTION_TOOLSDIR "/backup", "backup", "--backup", "--restart", filename, NULL);
- else
- execl (EVOLUTION_TOOLSDIR "/backup", "backup", "--backup", filename, NULL);
-}
-
-static void
-restore (const char *filename, gboolean restart)
-{
- if (restart)
- execl (EVOLUTION_TOOLSDIR "/backup", "backup", "--restore", "--restart", filename, NULL);
- else
- execl (EVOLUTION_TOOLSDIR "/backup", "backup", "--restore", filename, NULL);
-}
-
-static gboolean
-sanity_check (const char *filename)
-{
- char *command;
- int result;
-
- command = g_strdup_printf ("%s/backup --check %s", EVOLUTION_TOOLSDIR, filename);
- result = system (command);
- g_free (command);
-
- g_message ("Sanity check result %d:%d", WIFEXITED (result), WEXITSTATUS (result));
-
- return WIFEXITED (result) && (WEXITSTATUS (result) == 0);
-}
-
-void
-org_gnome_backup_restore_backup (EPlugin *ep, ESMenuTargetShell *target)
-{
- GtkWidget *dlg;
- GtkWidget *vbox, *check;
- int response;
-
- dlg = gtk_file_chooser_dialog_new (_("Select name of Evolution archive"), GTK_WINDOW (target->target.widget),
- GTK_FILE_CHOOSER_ACTION_SAVE,
- GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
- GTK_STOCK_SAVE, GTK_RESPONSE_OK, NULL);
-
- gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dlg), "evolution-backup.tar.gz");
-
- vbox = gtk_vbox_new (FALSE, 6);
- gtk_widget_show (vbox);
-
- check = gtk_check_button_new_with_mnemonic (_("_Restart Evolution after backup"));
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), TRUE);
- gtk_widget_show (check);
-
- gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, TRUE, 0);
- gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (dlg), vbox);
-
- response = gtk_dialog_run (GTK_DIALOG (dlg));
- if (response == GTK_RESPONSE_OK) {
- char *filename;
-
- filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dlg));
-
- backup (filename, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check)));
-
- g_free (filename);
- }
-
- gtk_widget_destroy (dlg);
-}
-
-void
-org_gnome_backup_restore_restore (EPlugin *ep, ESMenuTargetShell *target)
-{
- GtkWidget *dlg;
- GtkWidget *vbox, *check;
- int response;
-
- dlg = gtk_file_chooser_dialog_new (_("Select Evolution archive to restore"), GTK_WINDOW (target->target.widget),
- GTK_FILE_CHOOSER_ACTION_OPEN,
- GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
- GTK_STOCK_OPEN, GTK_RESPONSE_OK, NULL);
-
- vbox = gtk_vbox_new (FALSE, 6);
- gtk_widget_show (vbox);
-
- check = gtk_check_button_new_with_mnemonic (_("_Restart Evolution after restore"));
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), TRUE);
- gtk_widget_show (check);
-
- gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, TRUE, 0);
- gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (dlg), vbox);
-
- response = gtk_dialog_run (GTK_DIALOG (dlg));
- if (response == GTK_RESPONSE_OK) {
- char *filename;
-
- filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dlg));
-
- if (sanity_check (filename)) {
- restore (filename, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check)));
- } else {
- g_message ("Invalid archive");
- }
-
- g_free (filename);
- }
-
- gtk_widget_destroy (dlg);
-}
-
-
diff --git a/plugins/backup-restore/backup.c b/plugins/backup-restore/backup.c
deleted file mode 100644
index 9048ee2928..0000000000
--- a/plugins/backup-restore/backup.c
+++ /dev/null
@@ -1,153 +0,0 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/wait.h>
-
-#include <libgnome/gnome-i18n.h>
-#include <libgnome/gnome-util.h>
-
-#define EVOLUTION "evolution-" BASE_VERSION
-#define EVOLUTION_DIR "~/.evolution/"
-#define EVOLUTION_DIR_BACKUP "~/.evolution-old/"
-#define GCONF_DUMP_FILE "backup-restore-gconf.xml"
-#define GCONF_DUMP_PATH EVOLUTION_DIR GCONF_DUMP_FILE
-#define GCONF_DIR "/apps/evolution"
-#define ARCHIVE_NAME "evolution-backup.tar.gz"
-
-static gboolean backup_op = FALSE;
-static gboolean restore_op = FALSE;
-static gboolean check_op = FALSE;
-static gboolean restart_arg = FALSE;
-
-#define d(x) x
-
-/* #define s(x) system (x) */
-#define s(x) G_STMT_START { g_message (x); system (x); } G_STMT_END
-
-static void
-backup (const char *filename)
-{
- char *command;
-
- /* FIXME Will the versioned setting always work? */
- s (EVOLUTION " --force-shutdown");
-
- s ("gconftool-2 --dump " GCONF_DIR " > " GCONF_DUMP_PATH);
-
- /* FIXME stay on this file system ,other options?" */
- /* FIXME compression type?" */
- /* FIXME date/time stamp?" */
- /* FIXME archive location?" */
- command = g_strdup_printf ("cd ~ && tar zpcf %s .evolution", filename);
- s (command);
- g_free (command);
-
- if (restart_arg)
- s (EVOLUTION);
-}
-
-static void
-restore (const char *filename)
-{
- char *command;
-
- /* FIXME Will the versioned setting always work? */
- s (EVOLUTION " --force-shutdown");
-
- s ("mv " EVOLUTION_DIR " " EVOLUTION_DIR_BACKUP);
-
- command = g_strdup_printf ("cd ~ && tar zxf %s", filename);
- s (command);
- g_free (command);
-
- s ("gconftool-2 --load " GCONF_DUMP_PATH);
- s ("rm -rf " GCONF_DUMP_PATH);
- s ("rm -rf " EVOLUTION_DIR_BACKUP);
-
- if (restart_arg)
- s (EVOLUTION);
-}
-
-static void
-check (const char *filename)
-{
- char *command;
- int result;
-
- command = g_strdup_printf ("tar ztf %s | grep -e \"^\\.evolution/$\"", filename);
- result = system (command);
- g_free (command);
-
- g_message ("First result %d", result);
- if (result)
- exit (result);
-
- command = g_strdup_printf ("tar ztf %s | grep -e \"^\\.evolution/%s$\"", filename, GCONF_DUMP_FILE);
- result = system (command);
- g_free (command);
-
- g_message ("Second result %d", result);
-
- exit (result);
-}
-
-int
-main (int argc, char **argv)
-{
- GValue popt_context_value = { 0, };
- GnomeProgram *program;
- poptContext popt_context;
- const char **args;
-
- struct poptOption options[] = {
- { "backup", '\0', POPT_ARG_NONE, &backup_op, 0,
- N_("Backup Evolution directory"), NULL },
- { "restore", '\0', POPT_ARG_NONE, &restore_op, 0,
- N_("Restore Evolution directory"), NULL },
- { "check", '\0', POPT_ARG_NONE, &check_op, 0,
- N_("Check Evolution archive"), NULL },
- { "restart", '\0', POPT_ARG_NONE, &restart_arg, 0,
- N_("Restart Evolution"), NULL },
- { NULL, '\0', 0, NULL, 0, NULL, NULL }
- };
-
- bindtextdomain (GETTEXT_PACKAGE, EVOLUTION_LOCALEDIR);
- bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
- textdomain (GETTEXT_PACKAGE);
-
- program = gnome_program_init (PACKAGE, VERSION, LIBGNOME_MODULE, argc, argv,
- GNOME_PROGRAM_STANDARD_PROPERTIES,
- GNOME_PARAM_POPT_TABLE, options,
- NULL);
-
- g_value_init (&popt_context_value, G_TYPE_POINTER);
- g_object_get_property (G_OBJECT (program), GNOME_PARAM_POPT_CONTEXT, &popt_context_value);
- popt_context = g_value_get_pointer (&popt_context_value);
- args = poptGetArgs (popt_context);
-
- if (args != NULL) {
- const char **p;
-
- for (p = args; *p != NULL; p++) {
- if (backup_op) {
- d(g_message ("Backing up to %s", (char *) *p));
- backup ((char *) *p);
- } else if (restore_op) {
- d(g_message ("Restoring from %s", (char *) *p));
- restore ((char *) *p);
- } else if (check_op) {
- d(g_message ("Checking %s", (char *) *p));
- check ((char *) *p);
- }
- }
- }
-
- g_value_unset (&popt_context_value);
-
- return 0;
-}
diff --git a/plugins/backup-restore/org-gnome-backup-restore.eplug.in b/plugins/backup-restore/org-gnome-backup-restore.eplug.in
deleted file mode 100644
index 09a080bf91..0000000000
--- a/plugins/backup-restore/org-gnome-backup-restore.eplug.in
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0"?>
-<e-plugin-list>
- <!-- the path to the shared library -->
- <e-plugin
- id="org.gnome.plugin.backup.restore"
- type="shlib"
- location="@PLUGINDIR@/liborg-gnome-backup-restore.so"
- name="Backup and restore plugin"
- description="A plugin for backing up and restore Evolution data and settings.">
-
- <hook class="org.gnome.evolution.shell.bonobomenu:1.0">
-
- <menu id="org.gnome.evolution.shell" target="shell">
- <!-- the path to the bonobo menu description -->
- <ui file="@PLUGINDIR@/org-gnome-backup-restore.xml"/>
- <item
- type="item"
- verb="EPBRBackup"
- path="/commands/EPBRBackup"
- enable="one"
- activate="org_gnome_backup_restore_backup"/>
- <item
- type="item"
- verb="EPBRRestore"
- path="/commands/EPBRRestore"
- enable="one"
- activate="org_gnome_backup_restore_restore"/>
- </menu>
-
- </hook>
-
- </e-plugin>
-</e-plugin-list>
diff --git a/plugins/backup-restore/org-gnome-backup-restore.xml b/plugins/backup-restore/org-gnome-backup-restore.xml
deleted file mode 100644
index 9af58343d1..0000000000
--- a/plugins/backup-restore/org-gnome-backup-restore.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<Root>
- <commands>
- <cmd name="EPBRBackup" _label="Backup Settings..."
- _tip="Backup and restore Evolution data and settings"
- pixtype="pixmap"/>
-
- <cmd name="EPBRRestore" _label="Restore Settings..."
- _tip="Backup and restore Evolution data and settings"
- pixtype="pixmap"/>
-
- </commands>
-
- <menu>
- <submenu name="File">
- <placeholder name="FileOps">
- <menuitem name="EPBRBackup" verb=""/>
- <menuitem name="EPBRRestore" verb=""/>
- </placeholder>
- </submenu>
- </menu>
-</Root>
diff --git a/plugins/bbdb/.cvsignore b/plugins/bbdb/.cvsignore
deleted file mode 100644
index 05cc709f87..0000000000
--- a/plugins/bbdb/.cvsignore
+++ /dev/null
@@ -1,4 +0,0 @@
-Makefile.in
-Makefile
-org-gnome-evolution-bbdb.eplug
-test-evobuddy
diff --git a/plugins/bbdb/ChangeLog b/plugins/bbdb/ChangeLog
deleted file mode 100644
index 017a2da387..0000000000
--- a/plugins/bbdb/ChangeLog
+++ /dev/null
@@ -1,81 +0,0 @@
-2005-02-07 JP Rosevear <jpr@novell.com>
-
- * org-gnome-evolution-bbdb.eplug.in: specify id
-
-2005-01-31 Sivaiah Nallagatla <snallagatla@novell.com>
-
- * gaimbuddies.c (bbdb_sync_buddy_list) : initialize
- GError* to NULL
- Fixes #71512
-
- * bbdb.c (bbdb_open_addressbook) : ditto
-
-2005-01-22 Nat Friedman <nat@novell.com>
-
- * gaimbuddies.c (im_list_contains_buddy): Check the buddy account
- name, not alias. Duh.
- (free_contact_list): Removed.
-
-2005-01-13 Nat Friedman <nat@novell.com>
-
- * gaimbuddies.c (bbdb_sync_buddy_list_check): Remove some debug
- printfs.
- (bbdb_sync_buddy_list): Do not query for the IM name, which is
- slow. Instead, query by alias and only commit the contact if we
- have changes for it.
- (bbdb_merge_buddy_to_contact): Return a boolean indicating whether
- we dirtied the contact or not.
-
-2005-01-08 Nat Friedman <nat@novell.com>
-
- * org-gnome-evolution-bbdb.eplug.in: Reformatted the description.
-
-2004-11-03 Nat Friedman <nat@novell.com>
-
- * org-gnome-evolution-bbdb.eplug.in: Add description and author
- fields. Change name.
-
-2004-11-01 JP Rosevear <jpr@novell.com>
-
- * Makefile.am: dist .eplug.in file
-
-2004-11-01 JP Rosevear <jpr@novell.com>
-
- * Makefile.am: list bbdb.h as a source so it gets disted
-
-2004-10-27 Nat Friedman <nat@novell.com>
-
- * bbdb.c (bbdb_page_factory): Use _with_mnemonic for the button.
-
- * Makefile.am: Don't build the test program by default.
-
-2004-10-25 Nat Friedman <nat@novell.com>
-
- * bbdb.c (e_plugin_lib_enable): Sync the Gaim buddy list. Set a
- timer to check for Gaim buddy list chnages to sync.
- (bbdb_do_it): Free some memory we were leaking before.
- (bbdb_open_addressbook): New function for Gaim buddy list support.
- (bbdb_check_gaim_enabled): Likewise.
- (enable_gaim_toggled_cb): Likewise.
- (synchronize_button_clicked_cb): Likewise.
- (bbdb_page_factory): Added UI for Gaim buddy list sync support.
-
- * gaimbuddies.c: New file, contains routines to synchronize IM
- information and buddy icons from a Gaim buddy list.
-
- * bbdb.h: New file, contains shared macros and prototypes.
-
- * test-evobuddy.c (main): New function, tests a gaim buddy list
- sync.
-
-2004-10-23 Nat Friedman <nat@novell.com>
-
- * bbdb.c (bbdb_do_it): Change assertions to if statements, so as
- not to issue warnings in the case of routine failures (name
- is NULL). Don't add an email to a contact if the appropriate
- contact is ambiguous.
-
-2004-10-22 Nat Friedman <nat@novell.com>
-
- * Initial checkin.
-
diff --git a/plugins/bbdb/Makefile.am b/plugins/bbdb/Makefile.am
deleted file mode 100644
index d57c276b6f..0000000000
--- a/plugins/bbdb/Makefile.am
+++ /dev/null
@@ -1,14 +0,0 @@
-INCLUDES = \
- -I$(top_srcdir) \
- $(EVOLUTION_MAIL_CFLAGS) \
- $(EVOLUTION_ADDRESSBOOK_CFLAGS)
-
-@EVO_PLUGIN_RULE@
-
-plugin_DATA = org-gnome-evolution-bbdb.eplug
-plugin_LTLIBRARIES = liborg-gnome-evolution-bbdb.la
-
-liborg_gnome_evolution_bbdb_la_SOURCES = bbdb.c bbdb.h gaimbuddies.c
-liborg_gnome_evolution_bbdb_la_LDFLAGS = -module -avoid-version
-
-EXTRA_DIST = org-gnome-evolution-bbdb.eplug.in \ No newline at end of file
diff --git a/plugins/bbdb/bbdb.c b/plugins/bbdb/bbdb.c
deleted file mode 100644
index d1a9619277..0000000000
--- a/plugins/bbdb/bbdb.c
+++ /dev/null
@@ -1,467 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
- *
- * An Evolution EPlugin that automatically populates your addressbook
- * as you reply to messages. Inspired by an Emacs contact management
- * tool called The Insidious Big Brother Database, a jwz joint.
- *
- * Nat Friedman
- * 22 October 2004
- * Boston
- *
- * Copyright (C) 2004 Novell, Inc.
- *
- * Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation
- * files (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use, copy,
- * modify, merge, publish, distribute, sublicense, and/or sell copies
- * of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <gtk/gtk.h>
-#include <libgnome/gnome-i18n.h>
-#include <string.h>
-
-#include <libebook/e-book.h>
-#include <libedataserverui/e-source-option-menu.h>
-
-#include <e-util/e-config.h>
-#include <mail/em-config.h>
-#include <mail/em-event.h>
-#include <camel/camel-mime-message.h>
-
-#include "bbdb.h"
-
-/* Plugin hooks */
-int e_plugin_lib_enable (EPluginLib *ep, int enable);
-void bbdb_handle_reply (EPlugin *ep, EMEventTargetMessage *target);
-GtkWidget *bbdb_page_factory (EPlugin *ep, EConfigHookItemFactoryData *hook_data);
-GtkWidget *bbdb_page_factory (EPlugin *ep, EConfigHookItemFactoryData *hook_data);
-
-/* For internal use */
-struct bbdb_stuff {
- EMConfigTargetPrefs *target;
- ESourceList *source_list;
-
- GtkWidget *option_menu;
- GtkWidget *check;
- GtkWidget *check_gaim;
-};
-
-/* Static forward declarations */
-static gboolean bbdb_timeout (gpointer data);
-static void bbdb_do_it (EBook *book, const char *name, const char *email);
-static void add_email_to_contact (EContact *contact, const char *email);
-static void enable_toggled_cb (GtkWidget *widget, gpointer data);
-static void source_changed_cb (GtkWidget *widget, ESource *source, gpointer data);
-static GtkWidget *create_addressbook_option_menu (struct bbdb_stuff *stuff);
-static void cleanup_cb (GObject *o, gpointer data);
-
-int
-e_plugin_lib_enable (EPluginLib *ep, int enable)
-{
- /* Start up the plugin. */
- if (enable) {
- fprintf (stderr, "BBDB spinning up...\n");
-
- if (bbdb_check_gaim_enabled ())
- bbdb_sync_buddy_list_check ();
-
- g_timeout_add (BBDB_BLIST_CHECK_INTERVAL,
- (GSourceFunc) bbdb_timeout,
- NULL);
- }
-
- return 0;
-}
-
-static gboolean
-bbdb_timeout (gpointer data)
-{
- bbdb_sync_buddy_list_check ();
-
- return TRUE;
-}
-
-/* Code to populate addressbook when you reply to a mail follows */
-
-void
-bbdb_handle_reply (EPlugin *ep, EMEventTargetMessage *target)
-{
- const CamelInternetAddress *cia;
- const char *name;
- const char *email;
- EBook *book = NULL;
- int i;
-
- /* Open the addressbook */
- book = bbdb_open_addressbook ();
-
- cia = camel_mime_message_get_from (target->message);
- for (i = 0; i < camel_address_length CAMEL_ADDRESS (cia); i ++) {
- camel_internet_address_get (cia, i, &name, &email);
- bbdb_do_it (book, name, email);
- }
-
- /* If this is a reply-all event, process To: and Cc: also. */
- if (((EEventTarget *) target)->mask & EM_EVENT_MESSAGE_REPLY_ALL) {
- g_object_unref (G_OBJECT (book));
- return;
- }
-
- cia = camel_mime_message_get_recipients (target->message, CAMEL_RECIPIENT_TYPE_TO);
- for (i = 0; i < camel_address_length CAMEL_ADDRESS (cia); i ++) {
- camel_internet_address_get (cia, i, &name, &email);
- bbdb_do_it (book, name, email);
- }
-
- cia = camel_mime_message_get_recipients (target->message, CAMEL_RECIPIENT_TYPE_CC);
- for (i = 0; i < camel_address_length CAMEL_ADDRESS (cia); i ++) {
- camel_internet_address_get (cia, i, &name, &email);
- bbdb_do_it (book, name, email);
- }
-
- g_object_unref (G_OBJECT (book));
-}
-
-static void
-bbdb_do_it (EBook *book, const char *name, const char *email)
-{
- char *query_string;
- EBookQuery *query;
- GList *contacts, *l;
- EContact *contact;
-
- gboolean status;
- GError *error = NULL;
-
- g_return_if_fail (book != NULL);
-
- if (name == NULL || email == NULL)
- return;
-
- if (! strcmp (name, "") || ! strcmp (email, ""))
- return;
-
- if (strchr (email, '@') == NULL)
- return;
-
- /* If any contacts exists with this email address, don't do anything */
- query_string = g_strdup_printf ("(contains \"email\" \"%s\")", email);
- query = e_book_query_from_string (query_string);
- g_free (query_string);
-
- status = e_book_get_contacts (book, query, &contacts, NULL);
- e_book_query_unref (query);
- if (contacts != NULL) {
- GList *l;
- for (l = contacts; l != NULL; l = l->next)
- g_object_unref ((GObject *)l->data);
- g_list_free (contacts);
-
- return;
- }
-
- /* If a contact exists with this name, add the email address to it. */
- query_string = g_strdup_printf ("(is \"full_name\" \"%s\")", name);
- query = e_book_query_from_string (query_string);
- g_free (query_string);
-
- status = e_book_get_contacts (book, query, &contacts, NULL);
- e_book_query_unref (query);
- if (contacts != NULL) {
-
- /* FIXME: If there's more than one contact with this
- name, just give up; we're not smart enough for
- this. */
- if (contacts->next != NULL) {
- return;
- }
-
- contact = (EContact *) contacts->data;
- add_email_to_contact (contact, email);
- if (! e_book_commit_contact (book, contact, &error)) {
- g_warning ("bbdb: Could not modify contact: %s\n", error->message);
- g_error_free (error);
- }
-
- for (l = contacts; l != NULL; l = l->next)
- g_object_unref ((GObject *)l->data);
- g_list_free (contacts);
-
- return;
- }
-
- /* Otherwise, create a new contact. */
- contact = e_contact_new ();
- e_contact_set (contact, E_CONTACT_FULL_NAME, (gpointer) name);
- add_email_to_contact (contact, email);
-
- if (! e_book_add_contact (book, contact, &error)) {
- g_warning ("bbdb: Failed to add new contact: %s\n", error->message);
- g_error_free (error);
- return;
- }
-
- g_object_unref (G_OBJECT (contact));
-}
-
-EBook *
-bbdb_open_addressbook (void)
-{
- GConfClient *gconf;
- char *uri;
- EBook *book = NULL;
-
- gboolean enable;
-
- gboolean status;
- GError *error = NULL;
-
- gconf = gconf_client_get_default ();
-
- /* Check to see if we're supposed to be running */
- enable = gconf_client_get_bool (gconf, GCONF_KEY_ENABLE, NULL);
- if (! enable) {
- g_object_unref (G_OBJECT (gconf));
- return NULL;
- }
-
- /* Open the appropriate addresbook. */
- uri = gconf_client_get_string (gconf, GCONF_KEY_WHICH_ADDRESSBOOK, NULL);
- g_object_unref (G_OBJECT (gconf));
- if (uri == NULL)
- book = e_book_new_system_addressbook (&error);
- else
- book = e_book_new_from_uri (uri, &error);
- if (book == NULL) {
- g_warning ("bbdb: failed to get addressbook: %s\n", error->message);
- g_error_free (error);
- return NULL;
- }
-
- status = e_book_open (book, FALSE, &error);
- if (! status) {
- g_warning ("bbdb: failed to open addressbook: %s\n", error->message);
- g_error_free (error);
- return NULL;
- }
-
- return book;
-}
-
-gboolean
-bbdb_check_gaim_enabled ()
-{
- GConfClient *gconf;
- gboolean gaim_enabled;
-
- gconf = gconf_client_get_default ();
- gaim_enabled = gconf_client_get_bool (gconf, GCONF_KEY_ENABLE_GAIM, NULL);
-
- g_object_unref (G_OBJECT (gconf));
-
- return gaim_enabled;
-}
-
-static void
-add_email_to_contact (EContact *contact, const char *email)
-{
- GList *emails;
-
- emails = e_contact_get (contact, E_CONTACT_EMAIL);
- emails = g_list_append (emails, (gpointer) email);
- e_contact_set (contact, E_CONTACT_EMAIL, (gpointer) emails);
-}
-
-
-
-/* Code to implement the configuration user interface follows */
-
-static void
-enable_toggled_cb (GtkWidget *widget, gpointer data)
-{
- struct bbdb_stuff *stuff = (struct bbdb_stuff *) data;
- gboolean active;
-
- active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
-
- /* Save the new setting to gconf */
- gconf_client_set_bool (stuff->target->gconf, GCONF_KEY_ENABLE, active, NULL);
-
- gtk_widget_set_sensitive (stuff->option_menu, active);
-}
-
-static void
-enable_gaim_toggled_cb (GtkWidget *widget, gpointer data)
-{
- struct bbdb_stuff *stuff = (struct bbdb_stuff *) data;
- gboolean active;
-
- active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
-
- /* Save the new setting to gconf */
- gconf_client_set_bool (stuff->target->gconf, GCONF_KEY_ENABLE_GAIM, active, NULL);
-}
-
-static void
-synchronize_button_clicked_cb (GtkWidget *button)
-{
- bbdb_sync_buddy_list ();
-}
-
-static void
-source_changed_cb (GtkWidget *widget, ESource *source, gpointer data)
-{
- struct bbdb_stuff *stuff = (struct bbdb_stuff *) data;
-
- gconf_client_set_string (stuff->target->gconf, GCONF_KEY_WHICH_ADDRESSBOOK, e_source_get_uri (source), NULL);
-}
-
-static GtkWidget *
-create_addressbook_option_menu (struct bbdb_stuff *stuff)
-{
- GtkWidget *menu;
- ESourceList *source_list;
- char *selected_source_uri;
- ESource *selected_source;
-
- GConfClient *gconf = stuff->target->gconf;
-
- source_list = e_source_list_new_for_gconf (gconf, "/apps/evolution/addressbook/sources");
- menu = e_source_option_menu_new (source_list);
-
- selected_source_uri = gconf_client_get_string (gconf, GCONF_KEY_WHICH_ADDRESSBOOK, NULL);
- if (selected_source_uri != NULL) {
- selected_source = e_source_new_with_absolute_uri ("", selected_source_uri);
- e_source_option_menu_select (E_SOURCE_OPTION_MENU (menu), selected_source);
- }
-
- gtk_widget_show (menu);
-
- stuff->source_list = source_list;
-
- return menu;
-}
-
-GtkWidget *
-bbdb_page_factory (EPlugin *ep, EConfigHookItemFactoryData *hook_data)
-{
- struct bbdb_stuff *stuff;
- EMConfigTargetPrefs *target = (EMConfigTargetPrefs *) hook_data->config->target;
- GtkWidget *page;
- GtkWidget *tab_label;
- GtkWidget *frame;
- GtkWidget *frame_label;
- GtkWidget *padding_label;
- GtkWidget *hbox;
- GtkWidget *inner_vbox;
- GtkWidget *check;
- GtkWidget *option;
- GtkWidget *check_gaim;
- GtkWidget *button;
-
- /* A structure to pass some stuff around */
- stuff = g_new0 (struct bbdb_stuff, 1);
- stuff->target = target;
-
- /* Create a new notebook page */
- page = gtk_vbox_new (FALSE, 0);
- GTK_CONTAINER (page)->border_width = 12;
- tab_label = gtk_label_new (_("Automatic Contacts"));
- gtk_notebook_append_page (GTK_NOTEBOOK (hook_data->parent), page, tab_label);
-
- /* Frame */
- frame = gtk_vbox_new (FALSE, 6);
- gtk_box_pack_start (GTK_BOX (page), frame, FALSE, FALSE, 0);
-
- /* "Automatic Contacts" */
- frame_label = gtk_label_new ("");
- gtk_label_set_markup (GTK_LABEL (frame_label), _("<span weight=\"bold\">Automatic Contacts</span>"));
- GTK_MISC (frame_label)->xalign = 0.0;
- gtk_box_pack_start (GTK_BOX (frame), frame_label, FALSE, FALSE, 0);
-
- /* Indent/padding */
- hbox = gtk_hbox_new (FALSE, 12);
- gtk_box_pack_start (GTK_BOX (frame), hbox, FALSE, TRUE, 0);
- padding_label = gtk_label_new ("");
- gtk_box_pack_start (GTK_BOX (hbox), padding_label, FALSE, FALSE, 0);
- inner_vbox = gtk_vbox_new (FALSE, 6);
- gtk_box_pack_start (GTK_BOX (hbox), inner_vbox, FALSE, FALSE, 0);
-
- /* Enable BBDB checkbox */
- check = gtk_check_button_new_with_mnemonic (_("_Automatically create entries in the addressbook when responding to mail"));
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), gconf_client_get_bool (target->gconf, GCONF_KEY_ENABLE, NULL));
- g_signal_connect (GTK_TOGGLE_BUTTON (check), "toggled", G_CALLBACK (enable_toggled_cb), stuff);
- gtk_box_pack_start (GTK_BOX (inner_vbox), check, FALSE, FALSE, 0);
- stuff->check = check;
-
- /* Source selection open menu */
- option = create_addressbook_option_menu (stuff);
- g_signal_connect (option, "source_selected", G_CALLBACK (source_changed_cb), stuff);
- gtk_widget_set_sensitive (option, gconf_client_get_bool (target->gconf, GCONF_KEY_ENABLE, NULL));
- gtk_box_pack_start (GTK_BOX (inner_vbox), option, FALSE, FALSE, 0);
- stuff->option_menu = option;
-
- /* "Instant Messaging Contacts" */
- frame = gtk_vbox_new (FALSE, 6);
- gtk_box_pack_start (GTK_BOX (page), frame, TRUE, TRUE, 24);
-
- frame_label = gtk_label_new ("");
- gtk_label_set_markup (GTK_LABEL (frame_label), _("<span weight=\"bold\">Instant Messaging Contacts</span>"));
- GTK_MISC (frame_label)->xalign = 0.0;
- gtk_box_pack_start (GTK_BOX (frame), frame_label, FALSE, FALSE, 0);
-
- /* Indent/padding */
- hbox = gtk_hbox_new (FALSE, 12);
- gtk_box_pack_start (GTK_BOX (frame), hbox, FALSE, TRUE, 0);
- padding_label = gtk_label_new ("");
- gtk_box_pack_start (GTK_BOX (hbox), padding_label, FALSE, FALSE, 0);
- inner_vbox = gtk_vbox_new (FALSE, 6);
- gtk_box_pack_start (GTK_BOX (hbox), inner_vbox, FALSE, FALSE, 0);
-
- /* Enable Gaim Checkbox */
- check_gaim = gtk_check_button_new_with_mnemonic (_("Periodically synchronize contact information and images from my _instant messenger"));
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_gaim), gconf_client_get_bool (target->gconf, GCONF_KEY_ENABLE_GAIM, NULL));
- g_signal_connect (GTK_TOGGLE_BUTTON (check_gaim), "toggled", G_CALLBACK (enable_gaim_toggled_cb), stuff);
- gtk_box_pack_start (GTK_BOX (inner_vbox), check_gaim, FALSE, FALSE, 0);
- stuff->check_gaim = check_gaim;
-
- /* Synchronize now button. */
- button = gtk_button_new_with_mnemonic (_("Synchronize with _buddy list now"));
- g_signal_connect (GTK_BUTTON (button), "clicked", G_CALLBACK (synchronize_button_clicked_cb), stuff);
- gtk_box_pack_start (GTK_BOX (inner_vbox), button, FALSE, FALSE, 0);
-
- /* Clean up */
- g_signal_connect (page, "destroy", G_CALLBACK (cleanup_cb), stuff);
-
- gtk_widget_show_all (page);
-
- return page;
-}
-
-static void
-cleanup_cb (GObject *o, gpointer data)
-{
- struct bbdb_stuff *stuff = data;
-
- g_object_unref (stuff->source_list);
- g_free (stuff);
-}
diff --git a/plugins/bbdb/bbdb.h b/plugins/bbdb/bbdb.h
deleted file mode 100644
index 5fe9e39bdd..0000000000
--- a/plugins/bbdb/bbdb.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef __BBDB_H__
-#define __BBDB_H__
-
-/* Where to store the config values */
-#define GCONF_KEY_ENABLE "/apps/evolution/autocontacts/enable_autocontacts"
-#define GCONF_KEY_ENABLE_GAIM "/apps/evolution/autocontacts/auto_sync_gaim"
-#define GCONF_KEY_WHICH_ADDRESSBOOK "/apps/evolution/autocontacts/addressbook_source"
-#define GCONF_KEY_GAIM_LAST_SYNC "/apps/evolution/autocontacts/gaim_last_sync_time"
-
-/* How often to poll the buddy list for changes (every two minutes) */
-#define BBDB_BLIST_CHECK_INTERVAL (2 * 60 * 1000)
-
-/* bbdb.c */
-EBook *bbdb_open_addressbook (void);
-gboolean bbdb_check_gaim_enabled (void);
-
-/* gaimbuddies.c */
-void bbdb_sync_buddy_list (void);
-void bbdb_sync_buddy_list_check (void);
-
-
-#endif /* __BBDB_H__ */
diff --git a/plugins/bbdb/gaimbuddies.c b/plugins/bbdb/gaimbuddies.c
deleted file mode 100644
index fd86bf537d..0000000000
--- a/plugins/bbdb/gaimbuddies.c
+++ /dev/null
@@ -1,439 +0,0 @@
-/*
- * Routines to copy information from a Gaim buddy list into an
- * Evolution addressbook.
- *
- * I currently copy IM account names and buddy icons, provided you
- * don't already have a buddy icon defined for a person.
- *
- * This works today (25 October 2004), but is pretty sure to break
- * later on as the Gaim buddylist file format shifts.
- *
- * Nat Friedman <nat@novell.com>
- *
- * Copyright 2004 Novell, Inc.
- *
- * Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation
- * files (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use, copy,
- * modify, merge, publish, distribute, sublicense, and/or sell copies
- * of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-#include <glib.h>
-#include <libxml/tree.h>
-#include <libxml/parser.h>
-#include <libxml/xmlmemory.h>
-#include <gal/util/e-xml-utils.h>
-
-#include <gtk/gtk.h>
-#include <libgnome/gnome-i18n.h>
-#include <string.h>
-
-#include <libebook/e-book.h>
-#include <libedataserverui/e-source-option-menu.h>
-
-#include <sys/time.h>
-#include <sys/stat.h>
-
-#include <e-util/e-config.h>
-
-#include "bbdb.h"
-
-typedef struct {
- char *account_name;
- char *proto;
- char *alias;
- char *icon;
-} GaimBuddy;
-
-/* Defined in bbdb.c */
-EBook *bbdb_open_addressbook (void);
-
-/* Forward declarations for this file. */
-void bbdb_sync_buddy_list (void);
-static gboolean bbdb_merge_buddy_to_contact (EBook *book, GaimBuddy *b, EContact *c);
-static GList *bbdb_get_gaim_buddy_list (void);
-static char *get_node_text (xmlNodePtr node);
-static char *get_buddy_icon_from_setting (xmlNodePtr setting);
-static char *get_node_text (xmlNodePtr node);
-static void free_buddy_list (GList *blist);
-static void parse_buddy_group (xmlNodePtr group, GList **buddies);
-static EContactField proto_to_contact_field (const char *proto);
-
-void
-bbdb_sync_buddy_list_check (void)
-{
- GConfClient *gconf;
- struct stat statbuf;
- time_t last_sync;
- char *blist_path;
- char *last_sync_str;
-
- gconf = gconf_client_get_default ();
-
- if (! gconf_client_get_bool (gconf, GCONF_KEY_ENABLE_GAIM, NULL)) {
- g_object_unref (G_OBJECT (gconf));
- return;
- }
-
- blist_path = g_build_path ("/", getenv ("HOME"), ".gaim/blist.xml", NULL);
- if (stat (blist_path, &statbuf) < 0) {
- g_object_unref (G_OBJECT (gconf));
- return;
- }
-
- /* Reprocess the buddy list if it's been updated. */
- last_sync_str = gconf_client_get_string (gconf, GCONF_KEY_GAIM_LAST_SYNC, NULL);
- if (last_sync_str == NULL || ! strcmp (last_sync_str, ""))
- last_sync = (time_t) 0;
- else
- last_sync = (time_t) g_ascii_strtoull (last_sync_str, NULL, 10);
-
- g_free (last_sync_str);
- g_object_unref (G_OBJECT (gconf));
-
- if (statbuf.st_mtime > last_sync) {
- fprintf (stderr, "bbdb: Buddy list has changed since last sync.\n");
-
- bbdb_sync_buddy_list ();
- }
-}
-
-void
-bbdb_sync_buddy_list (void)
-{
- GList *blist, *l;
- EBook *book = NULL;
-
- /* Get the Gaim buddy list */
- blist = bbdb_get_gaim_buddy_list ();
- if (blist == NULL)
- return;
-
- /* Open the addressbook */
- book = bbdb_open_addressbook ();
- if (book == NULL) {
- free_buddy_list (blist);
- return;
- }
-
- printf ("bbdb: Synchronizing buddy list to contacts...\n");
- /* Walk the buddy list */
- for (l = blist; l != NULL; l = l->next) {
- GaimBuddy *b = l->data;
- EBookQuery *query;
- GList *contacts;
- GError *error = NULL;
- EContact *c;
-
- if (b->alias == NULL || strlen (b->alias) == 0)
- continue;
-
- /* Look for an exact match full name == buddy alias */
- query = e_book_query_field_test (E_CONTACT_FULL_NAME, E_BOOK_QUERY_IS, b->alias);
- e_book_get_contacts (book, query, &contacts, NULL);
- e_book_query_unref (query);
- if (contacts != NULL) {
-
- /* FIXME: If there's more than one contact with this
- name, just give up; we're not smart enough for
- this. */
- if (contacts->next != NULL)
- continue;
-
- c = E_CONTACT (contacts->data);
-
- if (! bbdb_merge_buddy_to_contact (book, b, c))
- continue;
-
- /* Write it out to the addressbook */
- if (! e_book_commit_contact (book, c, &error)) {
- g_warning ("bbdb: Could not modify contact: %s\n", error->message);
- g_error_free (error);
- }
- continue;
- }
-
- /* Otherwise, create a new contact. */
- c = e_contact_new ();
- e_contact_set (c, E_CONTACT_FULL_NAME, (gpointer) b->alias);
- if (! bbdb_merge_buddy_to_contact (book, b, c)) {
- g_object_unref (G_OBJECT (c));
- continue;
- }
-
- if (! e_book_add_contact (book, c, &error)) {
- g_warning ("bbdb: Failed to add new contact: %s\n", error->message);
- g_error_free (error);
- return;
- }
- g_object_unref (G_OBJECT (c));
-
- }
-
-
- /* Update the last-sync'd time */
- {
- GConfClient *gconf;
- time_t last_sync;
- char *last_sync_str;
-
- gconf = gconf_client_get_default ();
-
- time (&last_sync);
- last_sync_str = g_strdup_printf ("%ld", (glong) last_sync);
- gconf_client_set_string (gconf, GCONF_KEY_GAIM_LAST_SYNC, last_sync_str, NULL);
- g_free (last_sync_str);
-
- g_object_unref (G_OBJECT (gconf));
- }
- printf ("bbdb: Done syncing buddy list to contacts.\n");
-}
-
-static gboolean
-im_list_contains_buddy (GList *ims, GaimBuddy *b)
-{
- GList *l;
-
- for (l = ims; l != NULL; l = l->next) {
- char *im = (char *) l->data;
-
- if (! strcmp (im, b->account_name))
- return TRUE;
- }
-
- return FALSE;
-}
-
-static gboolean
-bbdb_merge_buddy_to_contact (EBook *book, GaimBuddy *b, EContact *c)
-{
- EContactField field;
- GList *ims, *l;
- gboolean dirty = FALSE;
-
- EContactPhoto *photo = NULL;
-
- GError *error = NULL;
-
- /* Set the IM account */
- field = proto_to_contact_field (b->proto);
- ims = e_contact_get (c, field);
- if (! im_list_contains_buddy (ims, b)) {
- ims = g_list_append (ims, (gpointer) b->account_name);
- e_contact_set (c, field, (gpointer) ims);
- dirty = TRUE;
- }
-
- /* Set the photo if it's not set */
- if (b->icon != NULL) {
- photo = e_contact_get (c, E_CONTACT_PHOTO);
- if (photo == NULL) {
-
- photo = g_new0 (EContactPhoto, 1);
-
- if (! g_file_get_contents (b->icon, &photo->data, &photo->length, &error)) {
- g_warning ("bbdb: Could not read buddy icon: %s\n", error->message);
- g_error_free (error);
- for (l = ims; l != NULL; l = l->next)
- g_free ((char *) l->data);
- g_list_free (ims);
- return dirty;
- }
-
- e_contact_set (c, E_CONTACT_PHOTO, (gpointer) photo);
- dirty = TRUE;
- }
- }
-
- /* Clean up */
- if (photo != NULL)
- e_contact_photo_free (photo);
-
- for (l = ims; l != NULL; l = l->next)
- g_free ((char *) l->data);
- g_list_free (ims);
-
- return dirty;
-}
-
-static EContactField
-proto_to_contact_field (const char *proto)
-{
- if (! strcmp (proto, "prpl-oscar"))
- return E_CONTACT_IM_AIM;
- if (! strcmp (proto, "prpl-novell"))
- return E_CONTACT_IM_GROUPWISE;
- if (! strcmp (proto, "prpl-msn"))
- return E_CONTACT_IM_MSN;
- if (! strcmp (proto, "prpl-icq"))
- return E_CONTACT_IM_ICQ;
- if (! strcmp (proto, "prpl-yahoo"))
- return E_CONTACT_IM_YAHOO;
- if (! strcmp (proto, "prpl-jabber"))
- return E_CONTACT_IM_JABBER;
-
- return E_CONTACT_IM_AIM;
-}
-
-static GList *
-bbdb_get_gaim_buddy_list (void)
-{
- char *blist_path;
- xmlDocPtr buddy_xml;
- xmlNodePtr root, child, blist;
- GList *buddies = NULL;
-
- blist_path = g_build_path ("/", getenv ("HOME"), ".gaim/blist.xml", NULL);
-
- buddy_xml = xmlParseFile (blist_path);
- g_free (blist_path);
- if (! buddy_xml) {
- fprintf (stderr, "bbdb: Could not open Gaim buddy list.\n");
- return NULL;
- }
-
- root = xmlDocGetRootElement (buddy_xml);
- if (strcmp (root->name, "gaim")) {
- fprintf (stderr, "bbdb: Could not parse Gaim buddy list.\n");
- xmlFreeDoc (buddy_xml);
- return NULL;
- }
-
- blist = NULL;
- for (child = root->children; child != NULL; child = child->next) {
- if (! strcmp (child->name, "blist")) {
- blist = child;
- break;
- }
- }
- if (blist == NULL) {
- fprintf (stderr, "bbdb: Could not find 'blist' element in Gaim buddy list.\n");
- xmlFreeDoc (buddy_xml);
- return NULL;
- }
-
- for (child = blist->children; child != NULL; child = child->next) {
- if (! strcmp (child->name, "group"))
- parse_buddy_group (child, &buddies);
- }
-
- xmlFreeDoc (buddy_xml);
-
- return buddies;
-}
-
-static void
-free_buddy_list (GList *blist)
-{
- GList *l;
-
- for (l = blist; l != NULL; l = l->next) {
- GaimBuddy *gb = l->data;
-
- g_free (gb->icon);
- g_free (gb->alias);
- g_free (gb->account_name);
- g_free (gb->proto);
- g_free (gb);
- }
-
- g_list_free (l);
-}
-
-static char *
-get_node_text (xmlNodePtr node)
-{
- if (node->children == NULL || node->children->content == NULL ||
- strcmp (node->children->name, "text"))
- return NULL;
-
- return g_strdup (node->children->content);
-}
-
-static char *
-get_buddy_icon_from_setting (xmlNodePtr setting)
-{
- char *icon = NULL;
-
- icon = get_node_text (setting);
- if (icon [0] != '/') {
- char *path;
-
- path = g_build_path ("/", getenv ("HOME"), ".gaim/icons", icon, NULL);
- g_free (icon);
- icon = path;
- }
-
-
- return icon;
-}
-
-static void
-parse_contact (xmlNodePtr contact, GList **buddies)
-{
- xmlNodePtr child;
- xmlNodePtr buddy = NULL;
- GaimBuddy *gb;
-
- for (child = contact->children; child != NULL; child = child->next) {
- if (! strcmp (child->name, "buddy")) {
- buddy = child;
- break;
- }
- }
-
- if (buddy == NULL) {
- fprintf (stderr, "bbdb: Could not find buddy in contact. Malformed Gaim buddy list file.\n");
- return;
- }
-
- gb = g_new0 (GaimBuddy, 1);
-
- gb->proto = e_xml_get_string_prop_by_name (buddy, "proto");
-
- for (child = buddy->children; child != NULL; child = child->next) {
- if (! strcmp (child->name, "setting")) {
- char *setting_type;
- setting_type = e_xml_get_string_prop_by_name (child, "name");
-
- if (! strcmp (setting_type, "buddy_icon"))
- gb->icon = get_buddy_icon_from_setting (child);
-
- g_free (setting_type);
- } else if (! strcmp (child->name, "name"))
- gb->account_name = get_node_text (child);
- else if (! strcmp (child->name, "alias"))
- gb->alias = get_node_text (child);
-
- }
-
- *buddies = g_list_prepend (*buddies, gb);
-}
-
-static void
-parse_buddy_group (xmlNodePtr group, GList **buddies)
-{
- xmlNodePtr child;
-
- for (child = group->children; child != NULL; child = child->next) {
- if (strcmp (child->name, "contact"))
- continue;
-
- parse_contact (child, buddies);
- }
-}
diff --git a/plugins/bbdb/org-gnome-evolution-bbdb.eplug.in b/plugins/bbdb/org-gnome-evolution-bbdb.eplug.in
deleted file mode 100644
index 2c435c9af4..0000000000
--- a/plugins/bbdb/org-gnome-evolution-bbdb.eplug.in
+++ /dev/null
@@ -1,27 +0,0 @@
-<e-plugin-list>
- <e-plugin
- type="shlib"
- id="org.gnome.evolution.bbdb"
- name="Automatic contacts"
- location="@PLUGINDIR@/liborg-gnome-evolution-bbdb.so">
-
- <description>Automatically fills your addressbook with names and email addresses as you reply to mails. Also fills in IM contact information from your buddy lists.</description>
-
- <author name="Nat Friedman" email="nat@novell.com"/>
-
- <hook class="org.gnome.evolution.mail.events:1.0">
- <event
- id="message.replying"
- handle="bbdb_handle_reply"
- target="message"
- />
- </hook>
-
- <hook class="org.gnome.evolution.mail.config:1.0">
- <group id="org.gnome.evolution.mail.prefs" target="prefs">
- <item type="page" path="80.bbdb" label="BBDB" factory="bbdb_page_factory"/>
- </group>
- </hook>
-
- </e-plugin>
-</e-plugin-list>
diff --git a/plugins/bbdb/test-evobuddy.c b/plugins/bbdb/test-evobuddy.c
deleted file mode 100644
index 269999beb1..0000000000
--- a/plugins/bbdb/test-evobuddy.c
+++ /dev/null
@@ -1,15 +0,0 @@
-#include <stdio.h>
-
-void bbdb_sync_buddy_list (void);
-
-int
-main (void)
-{
- printf ("Syncing...\n");
-
- bbdb_sync_buddy_list ();
-
- printf ("Done!\n");
-
- return 0;
-}
diff --git a/plugins/calendar-file/.cvsignore b/plugins/calendar-file/.cvsignore
deleted file mode 100644
index 683d5ddbe2..0000000000
--- a/plugins/calendar-file/.cvsignore
+++ /dev/null
@@ -1,5 +0,0 @@
-.deps
-.libs
-Makefile
-Makefile.in
-*.eplug \ No newline at end of file
diff --git a/plugins/calendar-file/ChangeLog b/plugins/calendar-file/ChangeLog
deleted file mode 100644
index 204a726002..0000000000
--- a/plugins/calendar-file/ChangeLog
+++ /dev/null
@@ -1,3 +0,0 @@
-2005-01-06 JP Rosevear <jpr@novell.com>
-
- * Initial import of file properties plugin.
diff --git a/plugins/calendar-file/Makefile.am b/plugins/calendar-file/Makefile.am
deleted file mode 100644
index a064042290..0000000000
--- a/plugins/calendar-file/Makefile.am
+++ /dev/null
@@ -1,16 +0,0 @@
-INCLUDES = \
- -I$(top_srcdir) \
- $(EVOLUTION_CFLAGS) \
- $(EVOLUTION_CALENDAR_CFLAGS) \
- $(SOURCE_SEL_CFLAGS)
-
-@EVO_PLUGIN_RULE@
-
-plugin_DATA = org-gnome-calendar-file.eplug
-plugin_LTLIBRARIES = liborg-gnome-calendar-file.la
-
-
-liborg_gnome_calendar_file_la_SOURCES = calendar-file.c
-liborg_gnome_calendar_file_la_LDFLAGS = -module -avoid-version
-
-EXTRA_DIST = org-gnome-calendar-file.eplug.in
diff --git a/plugins/calendar-file/calendar-file.c b/plugins/calendar-file/calendar-file.c
deleted file mode 100644
index f47ce2c8ac..0000000000
--- a/plugins/calendar-file/calendar-file.c
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- *
- *
- * Copyright (C) 2004 David Trowbridge
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- */
-
-#include <gtk/gtklabel.h>
-#include <gtk/gtkentry.h>
-#include <gtk/gtktable.h>
-#include <gtk/gtkspinbutton.h>
-#include <gtk/gtkoptionmenu.h>
-#include <gtk/gtkmenu.h>
-#include <gtk/gtkmenuitem.h>
-#include <gtk/gtkhbox.h>
-#include <e-util/e-config.h>
-#include <calendar/gui/e-cal-config.h>
-#include <libedataserver/e-source.h>
-#include <libedataserver/e-url.h>
-#include <libgnome/gnome-i18n.h>
-#include <string.h>
-
-GtkWidget *e_calendar_file_dummy (EPlugin *epl, EConfigHookItemFactoryData *data);
-
-GtkWidget *
-e_calendar_file_dummy (EPlugin *epl, EConfigHookItemFactoryData *data)
-{
- ECalConfigTargetSource *t = (ECalConfigTargetSource *) data->target;
- ESource *source = t->source;
- char *uri_text;
-
- uri_text = e_source_get_uri (source);
- if (strncmp (uri_text, "file", 4)) {
- g_free (uri_text);
-
- return NULL;
- }
-
- e_source_set_relative_uri (source, e_source_peek_uid (source));
- uri_text = e_source_get_uri (source);
-
- return NULL;
-}
diff --git a/plugins/calendar-file/org-gnome-calendar-file.eplug.in b/plugins/calendar-file/org-gnome-calendar-file.eplug.in
deleted file mode 100644
index edb70947fc..0000000000
--- a/plugins/calendar-file/org-gnome-calendar-file.eplug.in
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0"?>
-<e-plugin-list>
- <e-plugin
- type="shlib"
- location="@PLUGINDIR@/liborg-gnome-calendar-file.so"
- id="org.gnome.evolution.calendar.file"
- name="Local Calendars">
- <hook class="org.gnome.evolution.calendar.config:1.0">
- <group
- target="source"
- id="org.gnome.evolution.calendar.calendarProperties">
- <item
- type="item_table"
- path="00.general/00.source/00.file_dummy"
- factory="e_calendar_file_dummy"/>
- </group>
- </hook>
- </e-plugin>
-</e-plugin-list>
diff --git a/plugins/calendar-http/.cvsignore b/plugins/calendar-http/.cvsignore
deleted file mode 100644
index 683d5ddbe2..0000000000
--- a/plugins/calendar-http/.cvsignore
+++ /dev/null
@@ -1,5 +0,0 @@
-.deps
-.libs
-Makefile
-Makefile.in
-*.eplug \ No newline at end of file
diff --git a/plugins/calendar-http/ChangeLog b/plugins/calendar-http/ChangeLog
deleted file mode 100644
index 7140b2c21f..0000000000
--- a/plugins/calendar-http/ChangeLog
+++ /dev/null
@@ -1,29 +0,0 @@
-2005-01-06 JP Rosevear <jpr@novell.com>
-
- * Makefile.am: include top_srcdir
-
-2004-12-28 David Trowbridge <David.Trowbridge@Colorado.edu>
-
- * calendar-http.c (e_calendar_http_check): s/strcmp/strncmp.
-
- * org-gnome-calendar-http.eplug.in: fixed order of menus.
-
-2004-11-12 Diego Sevilla Ruiz <dsevilla@ditec.um.es>
-
- * calendar-http.c (e_calendar_http_check): Accept protocol-less
- URIs. Fixes #68264.
- (e_calendar_http_check): Fixed a memory leak.
- (e_calendar_http_refresh): Another mem. leak fix.
- (e_calendar_http_url): Fixed another more memory leak.
-
-2004-11-09 Rodney Dawes <dobey@novell.com>
-
- * Makefile.am: Add EXTRA_DIST variable for the eplug.in file
-
-2004-11-04 Not Zed <NotZed@Ximian.com>
-
- * Makefile.am: duh, add this to cvs, remove Makefile.
-
-2004-11-04 David Trowbridge <David.Trowbridge@Colorado.edu>
-
- * Initial import of webcal properties plugin.
diff --git a/plugins/calendar-http/Makefile.am b/plugins/calendar-http/Makefile.am
deleted file mode 100644
index efe8c01679..0000000000
--- a/plugins/calendar-http/Makefile.am
+++ /dev/null
@@ -1,16 +0,0 @@
-INCLUDES = \
- -I$(top_srcdir) \
- $(EVOLUTION_CFLAGS) \
- $(EVOLUTION_CALENDAR_CFLAGS) \
- $(SOURCE_SEL_CFLAGS)
-
-@EVO_PLUGIN_RULE@
-
-plugin_DATA = org-gnome-calendar-http.eplug
-plugin_LTLIBRARIES = liborg-gnome-calendar-http.la
-
-
-liborg_gnome_calendar_http_la_SOURCES = calendar-http.c
-liborg_gnome_calendar_http_la_LDFLAGS = -module -avoid-version
-
-EXTRA_DIST = org-gnome-calendar-http.eplug.in
diff --git a/plugins/calendar-http/calendar-http.c b/plugins/calendar-http/calendar-http.c
deleted file mode 100644
index 988fd18929..0000000000
--- a/plugins/calendar-http/calendar-http.c
+++ /dev/null
@@ -1,314 +0,0 @@
-/*
- *
- *
- * Copyright (C) 2004 David Trowbridge
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- */
-
-#include <gtk/gtklabel.h>
-#include <gtk/gtkentry.h>
-#include <gtk/gtktable.h>
-#include <gtk/gtkspinbutton.h>
-#include <gtk/gtkoptionmenu.h>
-#include <gtk/gtkmenu.h>
-#include <gtk/gtkmenuitem.h>
-#include <gtk/gtkhbox.h>
-#include <e-util/e-config.h>
-#include <calendar/gui/e-cal-config.h>
-#include <libedataserver/e-source.h>
-#include <libedataserver/e-url.h>
-#include <libgnome/gnome-i18n.h>
-#include <string.h>
-
-GtkWidget *e_calendar_http_url (EPlugin *epl, EConfigHookItemFactoryData *data);
-GtkWidget *e_calendar_http_refresh (EPlugin *epl, EConfigHookItemFactoryData *data);
-gboolean e_calendar_http_check (EPlugin *epl, EConfigHookPageCheckData *data);
-
-static gchar *
-print_uri_noproto (EUri *uri)
-{
- gchar *uri_noproto;
-
- if (uri->port != 0)
- uri_noproto = g_strdup_printf (
- "%s%s%s%s%s%s%s:%d%s%s%s",
- uri->user ? uri->user : "",
- uri->authmech ? ";auth=" : "",
- uri->authmech ? uri->authmech : "",
- uri->passwd ? ":" : "",
- uri->passwd ? uri->passwd : "",
- uri->user ? "@" : "",
- uri->host ? uri->host : "",
- uri->port,
- uri->path ? uri->path : "",
- uri->query ? "?" : "",
- uri->query ? uri->query : "");
- else
- uri_noproto = g_strdup_printf (
- "%s%s%s%s%s%s%s%s%s%s",
- uri->user ? uri->user : "",
- uri->authmech ? ";auth=" : "",
- uri->authmech ? uri->authmech : "",
- uri->passwd ? ":" : "",
- uri->passwd ? uri->passwd : "",
- uri->user ? "@" : "",
- uri->host ? uri->host : "",
- uri->path ? uri->path : "",
- uri->query ? "?" : "",
- uri->query ? uri->query : "");
- return uri_noproto;
-}
-
-static void
-url_changed (GtkEntry *entry, ESource *source)
-{
- EUri *uri;
- char *relative_uri;
-
- uri = e_uri_new (gtk_entry_get_text (GTK_ENTRY (entry)));
- relative_uri = print_uri_noproto (uri);
- e_source_set_relative_uri (source, relative_uri);
- g_free (relative_uri);
- e_uri_free (uri);
-}
-
-GtkWidget *
-e_calendar_http_url (EPlugin *epl, EConfigHookItemFactoryData *data)
-{
- static GtkWidget *label;
- GtkWidget *entry, *parent;
- int row;
- ECalConfigTargetSource *t = (ECalConfigTargetSource *) data->target;
- EUri *uri;
- char *uri_text;
- static GtkWidget *hidden = NULL;
-
- if (!hidden)
- hidden = gtk_label_new ("");
-
- if (data->old)
- gtk_widget_destroy (label);
-
- uri_text = e_source_get_uri (t->source);
- uri = e_uri_new (uri_text);
- if ((strcmp (uri->protocol, "http") &&
- strcmp (uri->protocol, "webcal"))) {
- e_uri_free (uri);
- g_free (uri_text);
- return hidden;
- }
- e_uri_free (uri);
-
- parent = data->parent;
-
- row = ((GtkTable*)parent)->nrows;
-
- label = gtk_label_new_with_mnemonic (_("_URL:"));
- gtk_widget_show (label);
- gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
- gtk_table_attach (GTK_TABLE (parent), label, 0, 1, row, row+1, GTK_FILL, 0, 0, 0);
-
- entry = gtk_entry_new ();
- gtk_widget_show (entry);
- gtk_entry_set_text (GTK_ENTRY (entry), uri_text);
- gtk_table_attach (GTK_TABLE (parent), entry, 1, 2, row, row+1, GTK_EXPAND | GTK_FILL, 0, 0, 0);
- gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
- g_signal_connect (G_OBJECT (entry), "changed", G_CALLBACK (url_changed), t->source);
-
- g_free (uri_text);
- return entry;
-}
-
-static void
-set_refresh_time (ESource *source, GtkWidget *spin, GtkWidget *option)
-{
- int time;
- int item_num = 0;
- const char *refresh_str = e_source_get_property (source, "refresh");
- time = refresh_str ? atoi (refresh_str) : 30;
-
- if (time && !(time % 10080)) {
- /* weeks */
- item_num = 3;
- time /= 10080;
- } else if (time && !(time % 1440)) {
- /* days */
- item_num = 2;
- time /= 1440;
- } else if (time && !(time % 60)) {
- /* hours */
- item_num = 1;
- time /= 60;
- }
- gtk_option_menu_set_history (GTK_OPTION_MENU (option), item_num);
- gtk_spin_button_set_value (GTK_SPIN_BUTTON (spin), time);
-}
-
-static char *
-get_refresh_minutes (GtkWidget *spin, GtkWidget *option)
-{
- int setting = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (spin));
- switch (gtk_option_menu_get_history (GTK_OPTION_MENU (option))) {
- case 0:
- /* minutes */
- break;
- case 1:
- /* hours */
- setting *= 60;
- break;
- case 2:
- /* days */
- setting *= 1440;
- break;
- case 3:
- /* weeks - is this *really* necessary? */
- setting *= 10080;
- break;
- default:
- g_warning ("Time unit out of range");
- break;
- }
-
- return g_strdup_printf ("%d", setting);
-}
-
-static void
-spin_changed (GtkSpinButton *spin, ECalConfigTargetSource *t)
-{
- char *refresh_str;
- GtkWidget *option;
-
- option = g_object_get_data (G_OBJECT (spin), "option");
-
- refresh_str = get_refresh_minutes ((GtkWidget *) spin, option);
- e_source_set_property (t->source, "refresh", refresh_str);
- g_free (refresh_str);
-}
-
-static void
-option_changed (GtkOptionMenu *option, ECalConfigTargetSource *t)
-{
- char *refresh_str;
- GtkWidget *spin;
-
- spin = g_object_get_data (G_OBJECT (option), "spin");
-
- refresh_str = get_refresh_minutes (spin, (GtkWidget *) option);
- e_source_set_property (t->source, "refresh", refresh_str);
- g_free (refresh_str);
-}
-
-GtkWidget *
-e_calendar_http_refresh (EPlugin *epl, EConfigHookItemFactoryData *data)
-{
- static GtkWidget *label;
- GtkWidget *option, *spin, *menu, *hbox, *parent;
- GtkWidget *times[4];
- int row, i;
- ECalConfigTargetSource *t = (ECalConfigTargetSource *) data->target;
- ESource *source = t->source;
- EUri *uri;
- char* uri_text;
- static GtkWidget *hidden = NULL;
-
- if (!hidden)
- hidden = gtk_label_new ("");
-
- if (data->old)
- gtk_widget_destroy (label);
-
- uri_text = e_source_get_uri (t->source);
- uri = e_uri_new (uri_text);
- g_free (uri_text);
- if ((strcmp (uri->protocol, "http") &&
- strcmp (uri->protocol, "webcal"))) {
- e_uri_free (uri);
- return hidden;
- }
- e_uri_free (uri);
-
- parent = data->parent;
-
- row = ((GtkTable*)parent)->nrows;
-
- label = gtk_label_new_with_mnemonic (_("_Refresh:"));
- gtk_widget_show (label);
- gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
- gtk_table_attach (GTK_TABLE (parent), label, 0, 1, row, row+1, GTK_FILL, 0, 0, 0);
-
- hbox = gtk_hbox_new (FALSE, 6);
- gtk_widget_show (hbox);
-
- spin = gtk_spin_button_new_with_range (0, 100, 1);
- gtk_label_set_mnemonic_widget (GTK_LABEL (label), spin);
- gtk_widget_show (spin);
- gtk_box_pack_start (GTK_BOX (hbox), spin, FALSE, TRUE, 0);
-
- option = gtk_option_menu_new ();
- gtk_widget_show (option);
- times[0] = gtk_menu_item_new_with_label (_("minutes"));
- times[1] = gtk_menu_item_new_with_label (_("hours"));
- times[2] = gtk_menu_item_new_with_label (_("days"));
- times[3] = gtk_menu_item_new_with_label (_("weeks"));
- menu = gtk_menu_new ();
- gtk_widget_show (menu);
- for (i = 0; i < 4; i++) {
- gtk_widget_show (times[i]);
- gtk_menu_shell_append (GTK_MENU_SHELL (menu), times[i]);
- }
- gtk_option_menu_set_menu (GTK_OPTION_MENU (option), menu);
- set_refresh_time (source, spin, option);
- gtk_box_pack_start (GTK_BOX (hbox), option, FALSE, TRUE, 0);
-
- g_object_set_data (G_OBJECT (option), "spin", spin);
- g_signal_connect (G_OBJECT (option), "changed", G_CALLBACK (option_changed), t);
- g_object_set_data (G_OBJECT (spin), "option", option);
- g_signal_connect (G_OBJECT (spin), "value-changed", G_CALLBACK (spin_changed), t);
-
- gtk_table_attach (GTK_TABLE (parent), hbox, 1, 2, row, row+1, GTK_EXPAND | GTK_FILL, 0, 0, 0);
-
- return hbox;
-}
-
-gboolean
-e_calendar_http_check (EPlugin *epl, EConfigHookPageCheckData *data)
-{
- /* FIXME - check pageid */
- ECalConfigTargetSource *t = (ECalConfigTargetSource *) data->target;
- EUri *uri;
- gboolean ok = FALSE;
- ESourceGroup *group = e_source_peek_group (t->source);
- char *uri_text;
-
- if (strncmp (e_source_group_peek_base_uri (group), "webcal", 6))
- return TRUE;
-
- uri_text = e_source_get_uri (t->source);
- if (!strncmp (uri_text, "file:", 5)) {
- g_free (uri_text);
- return FALSE;
- }
-
- uri = e_uri_new (uri_text);
- ok = ((!strcmp (uri->protocol, "webcal")) ||
- (!strcmp (uri->protocol, "http")) ||
- (!strcmp (uri->protocol, "file")) );
- e_uri_free (uri);
- g_free (uri_text);
-
- return ok;
-}
diff --git a/plugins/calendar-http/org-gnome-calendar-http.eplug.in b/plugins/calendar-http/org-gnome-calendar-http.eplug.in
deleted file mode 100644
index 3ffe2783c4..0000000000
--- a/plugins/calendar-http/org-gnome-calendar-http.eplug.in
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0"?>
-<e-plugin-list>
- <e-plugin
- type="shlib"
- location="@PLUGINDIR@/liborg-gnome-calendar-http.so"
- id="org.gnome.evolution.calendar.http"
- name="HTTP Calendars">
- <hook class="org.gnome.evolution.calendar.config:1.0">
- <group
- target="source"
- id="org.gnome.evolution.calendar.calendarProperties"
- check="e_calendar_http_check">
- <item
- type="item_table"
- path="00.general/00.source/40.url"
- factory="e_calendar_http_url"/>
- <item
- type="item_table"
- path="00.general/00.source/50.refresh"
- factory="e_calendar_http_refresh"/>
- </group>
- </hook>
- </e-plugin>
-</e-plugin-list>
diff --git a/plugins/calendar-weather/.cvsignore b/plugins/calendar-weather/.cvsignore
deleted file mode 100644
index 683d5ddbe2..0000000000
--- a/plugins/calendar-weather/.cvsignore
+++ /dev/null
@@ -1,5 +0,0 @@
-.deps
-.libs
-Makefile
-Makefile.in
-*.eplug \ No newline at end of file
diff --git a/plugins/calendar-weather/ChangeLog b/plugins/calendar-weather/ChangeLog
deleted file mode 100644
index f7a0045ea5..0000000000
--- a/plugins/calendar-weather/ChangeLog
+++ /dev/null
@@ -1,46 +0,0 @@
-2005-02-02 Rodney Dawes <dobey@novell.com>
-
- * Makefile.am (INCLUDES): Use $(weatherdir) instead of duplicating the
- define for it below
- (weatherdir): Fix to use the correct versioned directory
-
-2005-01-26 David Trowbridge <trowbrds@cs.colorado.edu>
-
- * org-gnome-calendar-weather.eplug.in: fix typo
-
-2005-01-25 Rodrigo Moya <rodrigo@novell.com>
-
- * calendar-weather.c (e_plugin_lib_enable): set all new categories to
- not searchable.
-
-2005-01-12 David Trowbridge <trowbrds@cs.colorado.edu>
-
- * calendar-weather.c (e_calendar_weather_units): fix spelling
-
-2005-01-12 David Trowbridge <trowbrds@cs.colorado.edu>
-
- * calendar-weather.c, org-gnome-calendar-weather.eplug.in: use
- a single setting for metric/imperial rather than separate
- temperature and snowfall settings
-
-2005-01-10 Rodrigo Moya <rodrigo@novell.com>
-
- * calendar-weather.c (create_source_selected): use HIG-compliant
- button order.
-
-2005-01-07 Rodrigo Moya <rodrigo@novell.com>
-
- * Makefile.am: define EDS's datadir, needed to get to the
- Locations.xml file.
-
- * calendar-weather.c (load_locations): use EDS's datadir for the
- Locations.xml file full path.
-
-2005-01-07 Rodrigo Moya <rodrigo@novell.com>
-
- * Makefile.am: define weatherdatadir here, no need to use e-d-s's one,
- use evolution's instead.
-
-2005-01-06 David Trowbridge <trowbrds@cs.colorado.edu>
-
- * Initial import of weather properties plugin
diff --git a/plugins/calendar-weather/Makefile.am b/plugins/calendar-weather/Makefile.am
deleted file mode 100644
index 67fe1bfb6a..0000000000
--- a/plugins/calendar-weather/Makefile.am
+++ /dev/null
@@ -1,33 +0,0 @@
-eds_datadir = `pkg-config --variable=privdatadir evolution-data-server-1.2`
-
-INCLUDES = \
- -I$(top_srcdir)/shell \
- $(EVOLUTION_CFLAGS) \
- $(EVOLUTION_CALENDAR_CFLAGS) \
- $(SOURCE_SEL_CFLAGS) \
- -DWEATHER_DATADIR=\""$(weatherdir)"\" \
- -DWEATHER_EDS_DATADIR=\""$(eds_datadir)/weather"\"
-
-@EVO_PLUGIN_RULE@
-
-# These will actually install into the e-d-s share directory, but
-# if the plugin is disabled, we aren't going to be needing them.
-weatherdatadir = $(datadir)/evolution/$(BASE_VERSION)/weather
-weatherdata_DATA = \
- category_weather_cloudy_16.png \
- category_weather_fog_16.png \
- category_weather_partly_cloudy_16.png \
- category_weather_rain_16.png \
- category_weather_snow_16.png \
- category_weather_sun_16.png \
- category_weather_tstorm_16.png
-
-plugin_DATA = org-gnome-calendar-weather.eplug
-plugin_LTLIBRARIES = liborg-gnome-calendar-weather.la
-
-liborg_gnome_calendar_weather_la_SOURCES = calendar-weather.c
-liborg_gnome_calendar_weather_la_LDFLAGS = -module -avoid-version
-
-EXTRA_DIST = \
- org-gnome-calendar-weather.eplug.in \
- $(weatherdata_DATA)
diff --git a/plugins/calendar-weather/calendar-weather.c b/plugins/calendar-weather/calendar-weather.c
deleted file mode 100644
index 976c204d01..0000000000
--- a/plugins/calendar-weather/calendar-weather.c
+++ /dev/null
@@ -1,698 +0,0 @@
-/*
- * Authors: David Trowbridge <trowbrds@cs.colorado.edu>
- *
- * Copyright (C) 2005 Novell, Inc. (www.novell.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- */
-
-#include <gtk/gtk.h>
-#include <e-util/e-config.h>
-#include <calendar/gui/e-cal-config.h>
-#include <calendar/gui/e-cal-event.h>
-#include <calendar/gui/calendar-component.h>
-#include <libedataserver/e-source.h>
-#include <libedataserver/e-url.h>
-#include <libedataserver/e-categories.h>
-#include <libgnome/gnome-i18n.h>
-#include <libxml/parser.h>
-#include <libxml/tree.h>
-#include <string.h>
-
-GtkWidget *e_calendar_weather_location (EPlugin *epl, EConfigHookItemFactoryData *data);
-GtkWidget *e_calendar_weather_refresh (EPlugin *epl, EConfigHookItemFactoryData *data);
-GtkWidget *e_calendar_weather_units (EPlugin *epl, EConfigHookItemFactoryData *data);
-gboolean e_calendar_weather_check (EPlugin *epl, EConfigHookPageCheckData *data);
-void e_calendar_weather_migrate (EPlugin *epl, ECalEventTargetComponent *data);
-int e_plugin_lib_enable (EPluginLib *epl, int enable);
-
-static GtkTreeStore *store = NULL;
-
-#define WEATHER_BASE_URI "weather://"
-
-int
-e_plugin_lib_enable (EPluginLib *epl, int enable)
-{
- GList *l;
- gboolean found = FALSE;
-
- /* Add the categories icons if we don't have them. */
- for (l = e_categories_get_list (); l; l = g_list_next (l)) {
- if (!strcmp (l->data, _("Weather: Cloudy"))) {
- found = TRUE;
- break;
- }
- }
- if (!found) {
- e_categories_add (_("Weather: Cloudy"), NULL, WEATHER_DATADIR "/category_weather_cloudy_16.png", FALSE);
- e_categories_add (_("Weather: Fog"), NULL, WEATHER_DATADIR "/category_weather_fog_16.png", FALSE);
- e_categories_add (_("Weather: Partly Cloudy"), NULL, WEATHER_DATADIR "/category_weather_partly_cloudy_16.png", FALSE);
- e_categories_add (_("Weather: Rain"), NULL, WEATHER_DATADIR "/category_weather_rain_16.png", FALSE);
- e_categories_add (_("Weather: Snow"), NULL, WEATHER_DATADIR "/category_weather_snow_16.png", FALSE);
- e_categories_add (_("Weather: Sunny"), NULL, WEATHER_DATADIR "/category_weather_sun_16.png", FALSE);
- e_categories_add (_("Weather: Thunderstorms"), NULL, WEATHER_DATADIR "/category_weather_tstorm_16.png", FALSE);
- }
-
- return 0;
-}
-
-void
-e_calendar_weather_migrate (EPlugin *epl, ECalEventTargetComponent *data)
-{
- /* Perform a migration step here. This allows us to keep the weather calendar completely
- * separate from evolution. If the plugin isn't built, the weather source group won't
- * show up in the user's evolution. If it is, this will create it if it doesn't exist */
- CalendarComponent *component;
- ESourceList *source_list;
- ESourceGroup *group;
- GSList *groups;
- ESourceGroup *weather = NULL;
-
- component = data->component;
- source_list = calendar_component_peek_source_list (component);
-
- groups = e_source_list_peek_groups (source_list);
- if (groups) {
- /* groups are already there, we need to search */
- GSList *g;
-
- for (g = groups; g; g = g_slist_next (g)) {
- group = E_SOURCE_GROUP (g->data);
- if (!weather && !strcmp (WEATHER_BASE_URI, e_source_group_peek_base_uri (group)))
- weather = g_object_ref (group);
- }
- }
-
- if (!weather) {
- group = e_source_group_new (_("Weather"), WEATHER_BASE_URI);
- e_source_list_add_group (source_list, group, -1);
-
- weather = group;
- }
-
- if (weather)
- g_object_unref (weather);
-
- e_source_list_sync (source_list, NULL);
- return 0;
-}
-
-static void
-parse_subtree (GtkTreeIter *parent, xmlNode *node)
-{
- GtkTreeIter iter;
- xmlNode *child;
-
- if (node->type == XML_ELEMENT_NODE) {
- gtk_tree_store_append (store, &iter, parent);
- if (strcmp (node->name, "location") == 0) {
- xmlAttr *attr;
-
- child = node->children;
- g_assert (child->type == XML_TEXT_NODE);
- gtk_tree_store_set (store, &iter, 0, child->content, -1);
-
- for (attr = node->properties; attr; attr = attr->next) {
- if (strcmp (attr->name, "code") == 0)
- gtk_tree_store_set (store, &iter, 1, attr->children->content, -1);
- else if (strcmp (attr->name, "url") == 0)
- gtk_tree_store_set (store, &iter, 2, attr->children->content, -1);
- else if (strcmp (attr->name, "type") == 0)
- gtk_tree_store_set (store, &iter, 3, attr->children->content, -1);
- }
- } else {
- xmlAttr *attr;
-
- for (child = node->children; child; child = child->next)
- parse_subtree (&iter, child);
-
- for (attr = node->properties; attr; attr = attr->next)
- if (strcmp (attr->name, "name") == 0)
- gtk_tree_store_set (store, &iter, 0, attr->children->content, -1);
- }
- }
-}
-
-static void
-load_locations ()
-{
- xmlDoc *doc;
- xmlNode *root, *child;
-
- LIBXML_TEST_VERSION
-
- doc = xmlParseFile (WEATHER_EDS_DATADIR "/Locations.xml");
- if (doc == NULL) {
- g_warning ("failed to read locations file");
- return;
- }
-
- if (store == NULL)
- store = gtk_tree_store_new (4,
- G_TYPE_STRING, /* name */
- G_TYPE_STRING, /* code */
- G_TYPE_STRING, /* URL */
- G_TYPE_STRING); /* type */
-
- root = xmlDocGetRootElement (doc);
- for (child = root->children; child; child = child->next)
- parse_subtree (NULL, child);
- xmlFreeDoc (doc);
-}
-
-static void
-selection_changed (GtkTreeSelection *selection, GtkDialog *dialog)
-{
- GtkTreeModel *model;
- GtkTreeIter iter;
-
- if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
- gchar *code = NULL;
- gtk_tree_model_get (model, &iter, 1, &code, -1);
- if (code != NULL) {
- gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, TRUE);
- } else {
- GtkTreeView *view = gtk_tree_selection_get_tree_view (selection);
- GtkTreePath *path;
- path = gtk_tree_model_get_path (model, &iter);
- gtk_tree_view_expand_row (view, path, FALSE);
- gtk_tree_path_free (path);
- gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE);
- }
- } else {
- gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE);
- }
-}
-
-static struct
-{
- gchar **ids;
- GtkTreeIter *result;
-} find_data;
-
-static gboolean
-find_location_func (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *node, gpointer data)
-{
- gchar *type, *code, *name;
- gtk_tree_model_get (model, node, 0, &name, 1, &code, 3, &type, -1);
- if (name == NULL || code == NULL || type == NULL)
- return FALSE;
- if ((!strcmp (type, find_data.ids[0])) &&
- (!strcmp (code, find_data.ids[1])) &&
- (!strcmp (name, find_data.ids[2]))) {
- find_data.result = gtk_tree_iter_copy (node);
- return TRUE;
- }
- return FALSE;
-}
-
-static GtkTreeIter *
-find_location (gchar *relative_url)
-{
- /* type/code/name */
- find_data.ids = g_strsplit (relative_url, "/", -1);
- find_data.result = NULL;
- gtk_tree_model_foreach (GTK_TREE_MODEL (store), (GtkTreeModelForeachFunc) find_location_func, NULL);
-
- g_strfreev (find_data.ids);
- return find_data.result;
-}
-
-static gboolean
-treeview_clicked (GtkTreeView *treeview, GdkEventButton *event, GtkDialog *dialog)
-{
- if (event->type == GDK_2BUTTON_PRESS) {
- GtkTreeSelection *selection = gtk_tree_view_get_selection (treeview);
- GtkTreeModel *model;
- GtkTreeIter iter;
-
- if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
- gchar *code = NULL;
- gtk_tree_model_get (model, &iter, 1, &code, -1);
- if (code != NULL) {
- gtk_dialog_response (dialog, GTK_RESPONSE_OK);
- return TRUE;
- }
- }
- }
- return FALSE;
-}
-
-static GtkDialog *
-create_source_selector (ESource *source)
-{
- GtkWidget *dialog, *treeview, *scrolledwindow;
- GtkCellRenderer *text;
- GtkTreeSelection *selection;
- gchar *uri_text;
- EUri *uri;
-
- /* FIXME - should show an error here if it fails*/
- if (store == NULL)
- return NULL;
-
- dialog = gtk_dialog_new_with_buttons (
- _("Select a location"),
- NULL, GTK_DIALOG_MODAL,
- GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
- GTK_STOCK_OK, GTK_RESPONSE_OK,
- NULL);
- gtk_container_set_border_width (GTK_CONTAINER (dialog), 6);
-
- scrolledwindow = gtk_scrolled_window_new (NULL, NULL);
- gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
- gtk_widget_show (scrolledwindow);
- treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
- gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
- gtk_widget_show (treeview);
- gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolledwindow), treeview);
- gtk_widget_add_events (treeview, GDK_BUTTON_PRESS);
- g_signal_connect (G_OBJECT (treeview), "button-press-event", G_CALLBACK (treeview_clicked), dialog);
- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
- gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
-
- uri_text = e_source_get_uri (source);
- uri = e_uri_new (uri_text);
- if (uri->path && strlen (uri->path)) {
- GtkTreeIter *iter = find_location (uri_text + 10);
- GtkTreePath *path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), iter);
- gtk_tree_view_expand_to_path (GTK_TREE_VIEW (treeview), path);
- gtk_tree_selection_select_path (selection, path);
- gtk_tree_path_free (path);
- }
- g_free (uri_text);
- e_uri_free (uri);
-
- g_signal_connect (G_OBJECT (selection), "changed", G_CALLBACK (selection_changed), dialog);
- g_object_set_data (G_OBJECT (dialog), "treeview", treeview);
-
- text = gtk_cell_renderer_text_new ();
- gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview), -1, "location", text, "text", 0, NULL);
-
- gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), scrolledwindow);
- gtk_container_set_border_width (GTK_CONTAINER (scrolledwindow), 6);
- gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 6);
-
- gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE);
- gtk_window_set_default_size (GTK_WINDOW (dialog), 420, 340);
-
- return GTK_DIALOG (dialog);
-}
-
-static gchar *
-build_location_path (GtkTreeIter *iter)
-{
- GtkTreeIter parent;
- gchar *path, *temp1, *temp2;
-
- gtk_tree_model_get (GTK_TREE_MODEL (store), iter, 0, &temp1, -1);
- path = g_strdup (temp1);
-
- while (gtk_tree_model_iter_parent (GTK_TREE_MODEL (store), &parent, iter)) {
- gtk_tree_model_get (GTK_TREE_MODEL (store), &parent, 0, &temp1, -1);
- temp2 = g_strdup_printf ("%s : %s", temp1, path);
- g_free (path);
- path = temp2;
- iter = gtk_tree_iter_copy (&parent);
- }
- return path;
-}
-
-static void
-location_clicked (GtkButton *button, ESource *source)
-{
- GtkDialog *dialog = create_source_selector (source);
- gint response;
-
- if (dialog == NULL)
- return;
-
- response = gtk_dialog_run (dialog);
-
- if (response == GTK_RESPONSE_OK) {
- GtkTreeView *view = GTK_TREE_VIEW (g_object_get_data (G_OBJECT (dialog), "treeview"));
- GtkTreeSelection *selection = gtk_tree_view_get_selection (view);
- GtkTreeModel *model;
- GtkTreeIter iter;
- GtkWidget *label;
- gchar *type, *code, *name;
- gchar *path, *uri;
-
- gtk_tree_selection_get_selected (selection, &model, &iter);
- gtk_tree_model_get (model, &iter, 0, &name, 1, &code, 3, &type, -1);
- path = build_location_path (&iter);
-
- label = gtk_bin_get_child (GTK_BIN (button));
- gtk_label_set_text (GTK_LABEL (label), path);
-
- uri = g_strdup_printf ("%s/%s/%s", type, code, name);
- /* FIXME - url_encode (&uri); */
- e_source_set_relative_uri (source, uri);
- g_free (uri);
- } else {
- GtkWidget *label;
- const gchar *text;
-
- label = GTK_WIDGET (gtk_bin_get_child (GTK_BIN (button)));
- text = gtk_label_get_text (GTK_LABEL (label));
- if (strcmp (text, _("None")) == 0)
- e_source_set_relative_uri (source, "");
- }
-
- gtk_widget_destroy (GTK_WIDGET (dialog));
-}
-
-GtkWidget *
-e_calendar_weather_location (EPlugin *epl, EConfigHookItemFactoryData *data)
-{
- static GtkWidget *label;
- GtkWidget *button, *parent, *text;
- int row;
- ECalConfigTargetSource *t = (ECalConfigTargetSource *) data->target;
- ESource *source = t->source;
- EUri *uri;
- char *uri_text;
- static GtkWidget *hidden;
-
- if (store == NULL)
- load_locations ();
-
- if (!hidden)
- hidden = gtk_label_new ("");
-
- if (data->old)
- gtk_widget_destroy (label);
-
- uri_text = e_source_get_uri (t->source);
- uri = e_uri_new (uri_text);
- if (strcmp (uri->protocol, "weather")) {
- e_uri_free (uri);
- return hidden;
- }
-
- parent = data->parent;
-
- row = ((GtkTable*)parent)->nrows;
-
- label = gtk_label_new_with_mnemonic (_("_Location:"));
- gtk_widget_show (label);
- gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
- gtk_table_attach (GTK_TABLE (parent), label, 0, 1, row, row+1, GTK_FILL, 0, 0, 0);
-
- button = gtk_button_new ();
- g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (location_clicked), source);
- gtk_widget_show (button);
-
- if (uri->path && strlen (uri->path)) {
- GtkTreeIter *iter = find_location (uri_text + 10);
- gchar *location = build_location_path (iter);
- text = gtk_label_new (location);
- g_free (location);
- } else
- text = gtk_label_new (_("None"));
- gtk_widget_show (text);
-#if (GTK_CHECK_VERSION(2, 6, 0))
- gtk_label_set_ellipsize (GTK_LABEL (text), PANGO_ELLIPSIZE_START);
-#endif
- gtk_container_add (GTK_CONTAINER (button), text);
- e_uri_free (uri);
- g_free (uri_text);
-
- gtk_table_attach (GTK_TABLE (parent), button, 1, 2, row, row+1, GTK_EXPAND | GTK_FILL, 0, 0, 0);
-
- return button;
-}
-
-static void
-set_refresh_time (ESource *source, GtkWidget *spin, GtkWidget *option)
-{
- int time;
- int item_num = 0;
- const char *refresh_str = e_source_get_property (source, "refresh");
- time = refresh_str ? atoi (refresh_str) : 30;
-
- if (time && !(time % 10080)) {
- /* weeks */
- item_num = 3;
- time /= 10080;
- } else if (time && !(time % 1440)) {
- /* days */
- item_num = 2;
- time /= 1440;
- } else if (time && !(time % 60)) {
- /* hours */
- item_num = 1;
- time /= 60;
- }
- gtk_option_menu_set_history (GTK_OPTION_MENU (option), item_num);
- gtk_spin_button_set_value (GTK_SPIN_BUTTON (spin), time);
-}
-
-static char *
-get_refresh_minutes (GtkWidget *spin, GtkWidget *option)
-{
- int setting = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (spin));
- switch (gtk_option_menu_get_history (GTK_OPTION_MENU (option))) {
- case 0:
- /* minutes */
- break;
- case 1:
- /* hours */
- setting *= 60;
- break;
- case 2:
- /* days */
- setting *= 1440;
- break;
- case 3:
- /* weeks - is this *really* necessary? */
- setting *= 10080;
- break;
- default:
- g_warning ("Time unit out of range");
- break;
- }
- return g_strdup_printf ("%d", setting);
-}
-
-static void
-spin_changed (GtkSpinButton *spin, ECalConfigTargetSource *t)
-{
- char *refresh_str;
- GtkWidget *option;
-
- option = g_object_get_data (G_OBJECT (spin), "option");
-
- refresh_str = get_refresh_minutes ((GtkWidget *) spin, option);
- e_source_set_property (t->source, "refresh", refresh_str);
- g_free (refresh_str);
-}
-
-static void
-option_changed (GtkOptionMenu *option, ECalConfigTargetSource *t)
-{
- char *refresh_str;
- GtkWidget *spin;
-
- spin = g_object_get_data (G_OBJECT (option), "spin");
-
- refresh_str = get_refresh_minutes (spin, (GtkWidget *) option);
- e_source_set_property (t->source, "refresh", refresh_str);
- g_free (refresh_str);
-}
-
-GtkWidget *
-e_calendar_weather_refresh (EPlugin *epl, EConfigHookItemFactoryData *data)
-{
- static GtkWidget *label;
- GtkWidget *option, *spin, *menu, *hbox, *parent;
- GtkWidget *times[4];
- int row, i;
- ECalConfigTargetSource *t = (ECalConfigTargetSource *) data->target;
- ESource *source = t->source;
- EUri *uri;
- char *uri_text;
- static GtkWidget *hidden = NULL;
-
- if (!hidden)
- hidden = gtk_label_new ("");
-
- if (data->old)
- gtk_widget_destroy (label);
-
- uri_text = e_source_get_uri (t->source);
- uri = e_uri_new (uri_text);
- g_free (uri_text);
- if (strcmp (uri->protocol, "weather")) {
- e_uri_free (uri);
- return hidden;
- }
- e_uri_free (uri);
-
- parent = data->parent;
-
- row = ((GtkTable*)parent)->nrows;
-
- label = gtk_label_new_with_mnemonic (_("_Refresh:"));
- gtk_widget_show (label);
- gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
- gtk_table_attach (GTK_TABLE (parent), label, 0, 1, row, row+1, GTK_FILL, 0, 0, 0);
-
- hbox = gtk_hbox_new (FALSE, 6);
- gtk_widget_show (hbox);
-
- spin = gtk_spin_button_new_with_range (0, 100, 1);
- gtk_label_set_mnemonic_widget (GTK_LABEL (label), spin);
- gtk_widget_show (spin);
- gtk_box_pack_start (GTK_BOX (hbox), spin, FALSE, TRUE, 0);
-
- option = gtk_option_menu_new ();
- gtk_widget_show (option);
- times[0] = gtk_menu_item_new_with_label (_("minutes"));
- times[1] = gtk_menu_item_new_with_label (_("hours"));
- times[2] = gtk_menu_item_new_with_label (_("days"));
- times[3] = gtk_menu_item_new_with_label (_("weeks"));
- menu = gtk_menu_new ();
- gtk_widget_show (menu);
- for (i = 0; i < 4; i++) {
- gtk_widget_show (times[i]);
- gtk_menu_shell_append (GTK_MENU_SHELL (menu), times[i]);
- }
- gtk_option_menu_set_menu (GTK_OPTION_MENU (option), menu);
- set_refresh_time (source, spin, option);
- gtk_box_pack_start (GTK_BOX (hbox), option, FALSE, TRUE, 0);
-
- g_object_set_data (G_OBJECT (option), "spin", spin);
- g_signal_connect (G_OBJECT (option), "changed", G_CALLBACK (option_changed), t);
- g_object_set_data (G_OBJECT (spin), "option", option);
- g_signal_connect (G_OBJECT (spin), "value-changed", G_CALLBACK (spin_changed), t);
-
- gtk_table_attach (GTK_TABLE (parent), hbox, 1, 2, row, row+1, GTK_EXPAND | GTK_FILL, 0, 0, 0);
-
- return hbox;
-}
-
-static void
-set_units (ESource *source, GtkWidget *option)
-{
- const char *format = e_source_get_property (source, "units");
- if (format == NULL) {
- format = e_source_get_property (source, "temperature");
- if (format == NULL) {
- e_source_set_property (source, "units", "metric");
- gtk_option_menu_set_history (GTK_OPTION_MENU (option), 0);
- } else if (strcmp (format, "fahrenheit") == 0) {
- /* old format, convert */
- e_source_set_property (source, "units", "imperial");
- gtk_option_menu_set_history (GTK_OPTION_MENU (option), 1);
- } else {
- e_source_set_property (source, "units", "metric");
- gtk_option_menu_set_history (GTK_OPTION_MENU (option), 0);
- }
- } else {
- if (strcmp (format, "metric") == 0)
- gtk_option_menu_set_history (GTK_OPTION_MENU (option), 0);
- else
- gtk_option_menu_set_history (GTK_OPTION_MENU (option), 1);
- }
-}
-
-static void
-units_changed (GtkOptionMenu *option, ECalConfigTargetSource *t)
-{
- int choice = gtk_option_menu_get_history (GTK_OPTION_MENU (option));
- if (choice == 0)
- e_source_set_property (t->source, "units", "metric");
- else
- e_source_set_property (t->source, "units", "imperial");
-}
-
-GtkWidget *
-e_calendar_weather_units (EPlugin *epl, EConfigHookItemFactoryData *data)
-{
- static GtkWidget *label;
- GtkWidget *option, *menu, *parent;
- GtkWidget *formats[2];
- int row, i;
- ECalConfigTargetSource *t = (ECalConfigTargetSource *) data->target;
- ESource *source = t->source;
- EUri *uri;
- char *uri_text;
- static GtkWidget *hidden = NULL;
-
- if (!hidden)
- hidden = gtk_label_new ("");
-
- if (data->old)
- gtk_widget_destroy (label);
-
- uri_text = e_source_get_uri (t->source);
- uri = e_uri_new (uri_text);
- g_free (uri_text);
- if (strcmp (uri->protocol, "weather")) {
- e_uri_free (uri);
- return hidden;
- }
- e_uri_free (uri);
-
- parent = data->parent;
-
- row = ((GtkTable*)parent)->nrows;
-
- label = gtk_label_new_with_mnemonic (_("_Units:"));
- gtk_widget_show (label);
- gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
- gtk_table_attach (GTK_TABLE (parent), label, 0, 1, row, row+1, GTK_FILL, 0, 0, 0);
-
- option = gtk_option_menu_new ();
- gtk_widget_show (option);
- formats[0] = gtk_menu_item_new_with_label (_("Metric (Celsius, cm, etc)"));
- formats[1] = gtk_menu_item_new_with_label (_("Imperial (Fahrenheit, inches, etc)"));
- menu = gtk_menu_new ();
- gtk_widget_show (menu);
- for (i = 0; i < 2; i++) {
- gtk_widget_show (formats[i]);
- gtk_menu_shell_append (GTK_MENU_SHELL (menu), formats[i]);
- }
- gtk_option_menu_set_menu (GTK_OPTION_MENU (option), menu);
- set_units (source, option);
- gtk_label_set_mnemonic_widget (GTK_LABEL (label), option);
- g_signal_connect (G_OBJECT (option), "changed", G_CALLBACK (units_changed), t);
- gtk_table_attach (GTK_TABLE (parent), option, 1, 2, row, row+1, GTK_FILL, 0, 0, 0);
-
- return option;
-}
-
-gboolean
-e_calendar_weather_check (EPlugin *epl, EConfigHookPageCheckData *data)
-{
- /* FIXME - check pageid */
- ECalConfigTargetSource *t = (ECalConfigTargetSource *) data->target;
- EUri *uri;
- gboolean ok = FALSE;
- ESourceGroup *group = e_source_peek_group (t->source);
-
- /* always return TRUE if this isn't a weather source */
- if (strncmp (e_source_group_peek_base_uri (group), "weather", 7))
- return TRUE;
-
- uri = e_uri_new (e_source_get_uri (t->source));
- /* make sure that the protocol is weather:// and that the path isn't empty */
- ok = (uri->path && strlen (uri->path));
- e_uri_free (uri);
-
- return ok;
-}
diff --git a/plugins/calendar-weather/category_weather_cloudy_16.png b/plugins/calendar-weather/category_weather_cloudy_16.png
deleted file mode 100644
index ddb3ba7c59..0000000000
--- a/plugins/calendar-weather/category_weather_cloudy_16.png
+++ /dev/null
Binary files differ
diff --git a/plugins/calendar-weather/category_weather_fog_16.png b/plugins/calendar-weather/category_weather_fog_16.png
deleted file mode 100644
index 23e4e2f1d4..0000000000
--- a/plugins/calendar-weather/category_weather_fog_16.png
+++ /dev/null
Binary files differ
diff --git a/plugins/calendar-weather/category_weather_partly_cloudy_16.png b/plugins/calendar-weather/category_weather_partly_cloudy_16.png
deleted file mode 100644
index 472feaa654..0000000000
--- a/plugins/calendar-weather/category_weather_partly_cloudy_16.png
+++ /dev/null
Binary files differ
diff --git a/plugins/calendar-weather/category_weather_rain_16.png b/plugins/calendar-weather/category_weather_rain_16.png
deleted file mode 100644
index e00d5e1c82..0000000000
--- a/plugins/calendar-weather/category_weather_rain_16.png
+++ /dev/null
Binary files differ
diff --git a/plugins/calendar-weather/category_weather_snow_16.png b/plugins/calendar-weather/category_weather_snow_16.png
deleted file mode 100644
index 5e95985f5f..0000000000
--- a/plugins/calendar-weather/category_weather_snow_16.png
+++ /dev/null
Binary files differ
diff --git a/plugins/calendar-weather/category_weather_sun_16.png b/plugins/calendar-weather/category_weather_sun_16.png
deleted file mode 100644
index 780c61c23c..0000000000
--- a/plugins/calendar-weather/category_weather_sun_16.png
+++ /dev/null
Binary files differ
diff --git a/plugins/calendar-weather/category_weather_tstorm_16.png b/plugins/calendar-weather/category_weather_tstorm_16.png
deleted file mode 100644
index b2af092b53..0000000000
--- a/plugins/calendar-weather/category_weather_tstorm_16.png
+++ /dev/null
Binary files differ
diff --git a/plugins/calendar-weather/org-gnome-calendar-weather.eplug.in b/plugins/calendar-weather/org-gnome-calendar-weather.eplug.in
deleted file mode 100644
index 2ce03a29bd..0000000000
--- a/plugins/calendar-weather/org-gnome-calendar-weather.eplug.in
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0"?>
-<e-plugin-list>
- <e-plugin
- type="shlib"
- location="@PLUGINDIR@/liborg-gnome-calendar-weather.so"
- id="org.gnome.evolution.calendar.weather"
- name="Weather Calendars">
- <description>Provides core functionality for weather calendars</description>
- <author name="David Trowbridge" email="trowbrds@cs.colorado.edu"/>
- <hook class="org.gnome.evolution.calendar.config:1.0">
- <group
- target="source"
- id="org.gnome.evolution.calendar.calendarProperties"
- check="e_calendar_weather_check">
- <item
- type="item_table"
- path="00.general/00.source/40.location"
- factory="e_calendar_weather_location"/>
- <item
- type="item_table"
- path="00.general/00.source/50.units"
- factory="e_calendar_weather_units"/>
- <item
- type="item_table"
- path="00.general/00.source/60.refresh"
- factory="e_calendar_weather_refresh"/>
- </group>
- </hook>
- <hook class="org.gnome.evolution.calendar.events:1.0">
- <event target="component" id="component.migration" handle="e_calendar_weather_migrate"/>
- </hook>
- </e-plugin>
-</e-plugin-list>
diff --git a/plugins/copy-tool/.cvsignore b/plugins/copy-tool/.cvsignore
deleted file mode 100644
index 683d5ddbe2..0000000000
--- a/plugins/copy-tool/.cvsignore
+++ /dev/null
@@ -1,5 +0,0 @@
-.deps
-.libs
-Makefile
-Makefile.in
-*.eplug \ No newline at end of file
diff --git a/plugins/copy-tool/ChangeLog b/plugins/copy-tool/ChangeLog
deleted file mode 100644
index 761df6d9fe..0000000000
--- a/plugins/copy-tool/ChangeLog
+++ /dev/null
@@ -1,21 +0,0 @@
-2004-11-03 Not Zed <NotZed@Ximian.com>
-
- * org-gnome-copy-tool.eplug.in: gave it a better name and fixed
- the description and author tags.
-
-2004-11-01 JP Rosevear <jpr@novell.com>
-
- * Makefile.am: dist .eplug.in file
-
-2004-10-28 Not Zed <NotZed@Ximian.com>
-
- * org-gnome-copy-tool.eplug.in: fix folderview popup hook id.
-
-2004-10-21 JP Rosevear <jpr@novell.com>
-
- * org-gnome-copy-tool.eplug.in: s/image/icon/
-
-2004-10-20 Not Zed <NotZed@Ximian.com>
-
- * implemented a copy-utils plugin.
-
diff --git a/plugins/copy-tool/Makefile.am b/plugins/copy-tool/Makefile.am
deleted file mode 100644
index 73092c3d20..0000000000
--- a/plugins/copy-tool/Makefile.am
+++ /dev/null
@@ -1,13 +0,0 @@
-INCLUDES = \
- -I$(top_srcdir) \
- $(EVOLUTION_MAIL_CFLAGS)
-
-@EVO_PLUGIN_RULE@
-
-plugin_DATA = org-gnome-copy-tool.eplug
-plugin_LTLIBRARIES = liborg-gnome-copy-tool.la
-
-liborg_gnome_copy_tool_la_SOURCES = copy-tool.c
-liborg_gnome_copy_tool_la_LDFLAGS = -module -avoid-version
-
-EXTRA_DIST = org-gnome-copy-tool.eplug.in \ No newline at end of file
diff --git a/plugins/copy-tool/copy-tool.c b/plugins/copy-tool/copy-tool.c
deleted file mode 100644
index 5571ba25c1..0000000000
--- a/plugins/copy-tool/copy-tool.c
+++ /dev/null
@@ -1,100 +0,0 @@
-
-/* Copyright (C) 2004 Michael Zucchi */
-
-/* This file is licensed under the GNU GPL v2 or later */
-
-/* Add 'copy to clipboard' things to various menu's.
-
- Uh, so far only to copy mail addresses from mail content */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <glib/gi18n-lib.h>
-#include <string.h>
-#include <stdio.h>
-
-#include "mail/em-popup.h"
-
-#include <gtk/gtkmain.h>
-#include <gtk/gtkinvisible.h>
-#include <gtk/gtkselection.h>
-
-#include "camel/camel-internet-address.h"
-#include "camel/camel-url.h"
-
-static GtkWidget *invisible;
-static char *address_uri;
-
-void org_gnome_copy_tool_copy_address(void *ep, EMPopupTargetURI *t);
-
-void
-org_gnome_copy_tool_copy_address(void *ep, EMPopupTargetURI *t)
-{
- g_free(address_uri);
- address_uri = g_strdup(t->uri);
-
- printf("copying address '%s'\n", address_uri);
-
- gtk_selection_owner_set(invisible, GDK_SELECTION_PRIMARY, gtk_get_current_event_time());
- gtk_selection_owner_set(invisible, GDK_SELECTION_CLIPBOARD, gtk_get_current_event_time());
-}
-
-static void
-ct_selection_get(GtkWidget *widget, GtkSelectionData *data, guint info, guint time_stamp, void *dummy)
-{
- printf("get selection, address is '%s'\n", address_uri);
-
- if (address_uri == NULL)
- return;
-
- if (strncmp (address_uri, "mailto:", 7) == 0) {
- CamelInternetAddress *cia = camel_internet_address_new();
- CamelURL *curl;
- char *addr;
- const char *tmp;
-
- curl = camel_url_new(address_uri, NULL);
- camel_address_decode((CamelAddress *)cia, curl->path);
- /* should it perhaps use address format? */
- addr = camel_address_encode((CamelAddress *)cia);
- tmp = addr && addr[0] ? addr : address_uri + 7;
- printf("get selection, setting to' %s'\n", tmp);
-
- gtk_selection_data_set(data, data->target, 8, tmp, strlen(tmp));
- g_free(addr);
- camel_url_free(curl);
- camel_object_unref(cia);
- }
-}
-
-static void
-ct_selection_clear_event(GtkWidget *widget, GdkEventSelection *event, void *dummy)
-{
- printf("selection clear event\n");
-
- g_free(address_uri);
- address_uri = NULL;
-}
-
-int e_plugin_lib_enable(EPluginLib *ep, int enable);
-
-int
-e_plugin_lib_enable(EPluginLib *ep, int enable)
-{
- if (enable) {
- invisible = gtk_invisible_new();
- g_signal_connect(invisible, "selection_get", G_CALLBACK(ct_selection_get), NULL);
- g_signal_connect(invisible, "selection_clear_event", G_CALLBACK(ct_selection_clear_event), NULL);
- gtk_selection_add_target(invisible, GDK_SELECTION_PRIMARY, GDK_SELECTION_TYPE_STRING, 0);
- gtk_selection_add_target(invisible, GDK_SELECTION_CLIPBOARD, GDK_SELECTION_TYPE_STRING, 1);
- } else {
- g_free(address_uri);
- address_uri = NULL;
- gtk_widget_destroy(invisible);
- invisible = NULL;
- }
-
- return 0;
-}
diff --git a/plugins/copy-tool/org-gnome-copy-tool.eplug.in b/plugins/copy-tool/org-gnome-copy-tool.eplug.in
deleted file mode 100644
index 10c2a5d6be..0000000000
--- a/plugins/copy-tool/org-gnome-copy-tool.eplug.in
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0"?>
-<e-plugin-list>
- <e-plugin
- type="shlib"
- id="org.gnome.evolution.plugin.copyTool"
- location="@PLUGINDIR@/liborg-gnome-copy-tool.so"
- name="Copy tool">
- <description>A test plugin which demonstrates a popup menu plugin which lets you copy things to the clipboard</description>
- <author name="Michael Zucchi" email="notzed@ximian.com"/>
-
- <!-- hook into the uri popup menu -->
- <hook class="org.gnome.evolution.mail.popup:1.0">
- <menu id="org.gnome.evolution.mail.folderview.popup" target="uri">
- <item
- type="item"
- path="80.test"
- icon="gtk-copy"
- label="Copy _Email Address"
- visible="mailto"
- activate="org_gnome_copy_tool_copy_address"/>
- </menu>
- </hook>
- </e-plugin>
-</e-plugin-list>
diff --git a/plugins/default-source/ChangeLog b/plugins/default-source/ChangeLog
deleted file mode 100644
index d8a42cd5e2..0000000000
--- a/plugins/default-source/ChangeLog
+++ /dev/null
@@ -1,3 +0,0 @@
-2005-01-21 Sivaiah Nallagatla <snallagatla@novell.com>
-
- * initil commit
diff --git a/plugins/default-source/Makefile.am b/plugins/default-source/Makefile.am
deleted file mode 100644
index 077164c578..0000000000
--- a/plugins/default-source/Makefile.am
+++ /dev/null
@@ -1,17 +0,0 @@
-INCLUDES = \
- -I$(top_srcdir) \
- $(EVOLUTION_CFLAGS) \
- $(EVOLUTION_CALENDAR_CFLAGS) \
- $(EVOLUTION_ADDRESSBOOK_CFLAGS) \
- $(SOURCE_SEL_CFLAGS)
-
-@EVO_PLUGIN_RULE@
-
-plugin_DATA = org-gnome-default-source.eplug
-plugin_LTLIBRARIES = liborg-gnome-default-source.la
-
-
-liborg_gnome_default_source_la_SOURCES = default-source.c
-liborg_gnome_default_source_la_LDFLAGS = -module -avoid-version
-
-EXTRA_DIST = org-gnome-default-source.eplug.in
diff --git a/plugins/default-source/default-source.c b/plugins/default-source/default-source.c
deleted file mode 100644
index ff506b13ff..0000000000
--- a/plugins/default-source/default-source.c
+++ /dev/null
@@ -1,123 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * Copyright (C) 2004 D
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- */
-
-#include <gtk/gtk.h>
-
-#include <e-util/e-config.h>
-#include <calendar/gui/e-cal-config.h>
-#include <libedataserver/e-source.h>
-#include <addressbook/gui/widgets/eab-config.h>
-#include <libebook/e-book.h>
-#include <libecal/e-cal.h>
-#include <libedataserver/e-source.h>
-#include <libgnome/gnome-i18n.h>
-#include <string.h>
-GtkWidget* org_gnome_default_book (EPlugin *epl, EConfigHookItemFactoryData *data);
-void commit_default_calendar (EPlugin *epl, EConfigTarget *target);
-void commit_default_book (EPlugin *epl, EConfigTarget *target);
-void
-commit_default_calendar (EPlugin *epl, EConfigTarget *target)
-{
- ECalConfigTargetSource *cal_target;
- ESource *source;
-
- cal_target = (ECalConfigTargetSource *) target;
- source = cal_target->source;
- if (e_source_get_property (source, "default"))
- if (!e_cal_set_default_source (source, E_CAL_SOURCE_TYPE_EVENT, NULL))
- e_cal_set_default_source (source, E_CAL_SOURCE_TYPE_TODO, NULL);
-}
-
-void
-commit_default_book (EPlugin *epl, EConfigTarget *target)
-{
- EABConfigTargetSource *book_target;
- ESource *source;
-
- book_target = (EABConfigTargetSource *) target;
- source = book_target->source;
- if (e_source_get_property (source, "default"))
- e_book_set_default_source (source, NULL);
-
-
-}
-
-static void
-default_source_changed (GtkWidget *check_box, ESource *source)
-{
-
- if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check_box)))
- e_source_set_property (source, "default", "true");
- else
- e_source_set_property (source, "default", NULL);
-}
-
-
-GtkWidget *
-org_gnome_default_book (EPlugin *epl, EConfigHookItemFactoryData *data)
-{
- GtkWidget *widget;
- ESource *source;
- EABConfigTargetSource *book_target;
-
- if (data->old)
- return data->old;
- widget = gtk_check_button_new_with_label (_("Mark as default folder"));
- book_target = (EABConfigTargetSource *) data->target;
- source = book_target->source;
-
- if (e_source_get_property (source, "default"))
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
- else
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), FALSE);
- gtk_container_add (GTK_CONTAINER (data->parent), widget);
-
- g_signal_connect (GTK_TOGGLE_BUTTON (widget), "toggled", G_CALLBACK (default_source_changed), source);
- gtk_widget_show (widget);
- return widget;
-}
-
-
-GtkWidget *
-org_gnome_default_cal (EPlugin *epl, EConfigHookItemFactoryData *data)
-{
- GtkWidget *widget;
- ESource *source;
- ECalConfigTargetSource *cal_target;
- int i;
-
- if (data->old)
- return data->old;
- widget = gtk_check_button_new_with_label (_("Mark as default folder"));
- cal_target = (ECalConfigTargetSource *) data->target;
- source = cal_target->source;
-
- if (e_source_get_property (source, "default"))
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
- else
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), FALSE);
-
- i = ((GtkTable *)data->parent)->nrows;
- gtk_table_attach((GtkTable *)data->parent, widget, 1, 2, i, i+1, GTK_EXPAND | GTK_FILL, 0, 0, 0);
-
- g_signal_connect (GTK_TOGGLE_BUTTON (widget), "toggled", G_CALLBACK (default_source_changed), source);
- gtk_widget_show (widget);
- return widget;
-}
diff --git a/plugins/default-source/org-gnome-default-source.eplug.in b/plugins/default-source/org-gnome-default-source.eplug.in
deleted file mode 100644
index 127f16c78e..0000000000
--- a/plugins/default-source/org-gnome-default-source.eplug.in
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0"?>
-<e-plugin-list>
- <e-plugin
- type="shlib"
- location="@PLUGINDIR@/liborg-gnome-default-source.so"
- id="org.gnome.evolution.plugin.default-source"
- name="Default Sources">
- <hook class="org.gnome.evolution.calendar.config:1.0">
- <group
- target="source"
- id="org.gnome.evolution.calendar.calendarProperties"
- commit="commit_default_calendar"
- >
- <item
- type="item_table"
- path="00.general/00.source/40.default"
- factory="org_gnome_default_cal"/>
- </group>
- </hook>
- <hook class="org.gnome.evolution.addressbook.config:1.0">
- <group
- target="source"
- id="com.novell.evolution.addressbook.config.accountEditor"
- commit="commit_default_book"
- >
- <item
- type="item"
- path="00.general/10.display/30.default"
- factory="org_gnome_default_book"/>
- </group>
- </hook>
-
- </e-plugin>
-</e-plugin-list>
diff --git a/plugins/exchange-account-setup/ChangeLog b/plugins/exchange-account-setup/ChangeLog
deleted file mode 100644
index 738b51dbd4..0000000000
--- a/plugins/exchange-account-setup/ChangeLog
+++ /dev/null
@@ -1,158 +0,0 @@
-2005-02-07 Sushma Rai <rsushma@novell.com>
-
- * org-gnome-exchange-account-setup.eplug.in: Added plugin for adding
- auth type section to editor.
-
- * exchange-account-setup.c (org_gnome_exchange_auth_section): Adding
- and handling authentication type for exchange account.
-
-2005-01-28 Not Zed <NotZed@Ximian.com>
-
- ** related to bug #71520.
-
- * exchange-account-setup.c: All but re-written.
- Fixed the license of the file.
- Fixed a translation string.
- Modified return condition check.
- Fixed problem over writing current account with the old data.
- Removed duplicated code.
- Removed the hack for handling NULL hostname, now using
- CAMEL_URL_HIDDEN_HOST url flag in the provider.
- Using E_ACCOUNT_SOURCE_SAVE_PASSWD for remember password.
- Removed the way owa url entry was added to table in config section,
- Now econfig supports tables.
-
- * exchange-ask-password.c: removed, functionality moved to
- exchange-account-setup.c.
-
-2005-01-25 Sushma Rai <rsushma@novell.com>
-
- * exchange-account-setup.c (create_page): Fixed empty
- string being marked for translation problem. #71644
-
-2005-01-23 Sushma Rai <rsushma@novell.com>
-
- * org-gnome-exchange-account-setup.eplug.in: Added plugins
- for handling hiding auth type section in druid.
-
- * exchange-account-setup.c (add_owa_entry_to_editor): Changed the
- button label to "Authenticate" from OK
-
- * exchange-ask-password.c (add_owa_entry): Changed the button label
- to Authenticate.
- (org_gnome_exchange_handle_auth): Hiding Auth section in receive page.
- (org_gnome_exchange_handle_send_auth_option): Hiding the Auth section
- in send page
-
-2005-01-22 Sushma Rai <rsushma@novell.com>
-
- * org-gnome-exchange-account-setup.eplug.in: Added
- org_gnome_exchange_check_options plugin.
-
- * exchange-ask-password.c (org_gnome_exchange_check_options):
- Reads OWA URL value and sets use_ssl and owa_url values for source
- account url.
-
- * exchange-account-setup.c (org_gnome_exchange_set_url)
- (add_owa_entry_to_editor): Reading owa url value from gconf and setting
- owa url value in the account editor. Fixes #71378
-
-2005-01-19 Sushma Rai <rsushma@novell.com>
-
- * exchange-ask-password.c (validate_exchange_user): Fix for remembering
- password if user has selected that option, while creating the account.
-
-2005-01-18 Sushma Rai <rsushma@novell.com>
-
- * exchange-ask-password.c (validate_exchange_user): Reading the return
- value of user validation function. Fixes #71385
-
-2005-01-18 Sushma Rai <rsushma@novell.com>
-
- * exchange-ask-password.c (validate_exchange_user): Filling up
- user name so that page check doesn't fail. Fixes #71384
-
-2005-01-18 Sushma Rai <rsushma@novell.com>
-
- * exchange-ask-password.c (org_gnome_exchange_read_url):
- Setting dummy host name, which will be reset to proper
- hostname once the user is authenticated.
-
-2005-01-18 Sushma Rai <rsushma@novell.com>
-
- * org-gnome-exchange-account-setup.eplug.in: Moved two account
- editor plugins unser same hook class.
-
- * exchange-ask-password.c: Reorganized the code.
- Used accessor functions to read and set EAccount values.
- Removed editor specific factory function add_owa_entry_to_editor()
- from here.
-
- * exchange-account-setup.c: Reorganized the code.
- Moved add_owa_entry_to_editor() and it's sub functions into this file.
- (org_gnome_exchange_account_setup): Reading source url and transport
- url values stored in gconf and filling up the EAccount structure.
- This fixes the problem of page check failure, as improper source url
- and transport url values, as we don't read host name in the editor.
- (org_gnome_exchange_set_url): Similar.
-
-2005-01-17 Sushma Rai <rsushma@novell.com>
-
- * Makefile.am: Linking to camel libs. Fixes plugin loading problem
- due to undefined camel symbol, during evolution startup.
-
-2005-01-13 Sushma Rai <rsushma@novell.com>
-
- * org-gnome-exchange-account-setup.eplug.in: Combined
- all the plugins into one.
-
-2005-01-12 Sushma Rai <rsushma@novell.com>
-
- * exchange-ask-password.c: (validate_exchange_user):
- Added one more error condition check.
-
-2005-01-12 Sushma Rai <rsushma@novell.com>
-
- * org-gnome-exchange-account-setup.eplug.in: Factory
- method to add owa url entry to account editor.
-
- * exchange-ask-password.c: (org_gnome_exchange_set_url)
- (add_owa_entry_to_editor): Adds owa url entry to the
- account editor for Exchange account.
- (validate_exchange_user): Using the CamelProvider private
- function defined by Exchange camel provider.
-
-2005-01-11 Sushma Rai <rsushma@novell.com>
-
- * org-gnome-exchange-account-setup.eplug.in: Removed page check plugin
-
- * exchange-ask-password.c: Added a button to prompt for password
- instead of listening on page next signal
-
-2005-01-11 Not Zed <NotZed@Ximian.com>
-
- * Makefile.am: fix LDFLAGS variable name.
-
-2005-01-10 Sushma Rai <rsushma@novell.com>
-
- * exchange-ask-password.c: (validate_exchange_user):
- Corrected argument order.
-
-2005-01-10 Sushma Rai <rsushma@novell.com>
-
- * org-gnome-exchange-account-setup.eplug.in: Added plugin to read
- OWA url entry to the account set up druid.
-
- * exchange-ask-password.c: Create a entry for OWA URL and reads the
- URL value.
-
-2005-01-09 Sushma Rai <rsushma@novell.com>
-
- * exchange-ask-password.c: Pops up password dialog and validates
- user credentials once owa url and user name are entered.
-
- * org-gnome-exchange-account-setup.eplug.in: Added page check plugin.
-
-2005-01-09 Sushma Rai <rsushma@novell.com>
-
- * Intial ckeckin, Plugin for Exchange account specific settings
diff --git a/plugins/exchange-account-setup/Makefile.am b/plugins/exchange-account-setup/Makefile.am
deleted file mode 100644
index c0ecbca72b..0000000000
--- a/plugins/exchange-account-setup/Makefile.am
+++ /dev/null
@@ -1,22 +0,0 @@
-INCLUDES = -I . \
- -I$(top_srcdir) \
- $(EVOLUTION_MAIL_CFLAGS) \
- $(CAMEL_CFLAGS) \
- -DEVOLUTION_GLADEDIR=\""$(gladedir)"\"
-
-@EVO_PLUGIN_RULE@
-
-plugin_DATA = org-gnome-exchange-account-setup.eplug
-plugin_LTLIBRARIES = liborg-gnome-exchange-account-settings.la
-
-liborg_gnome_exchange_account_settings_la_SOURCES = \
- exchange-account-setup.c
-
-liborg_gnome_exchange_account_settings_la_LIBADD = \
- $(top_builddir)/e-util/libeutil.la \
- $(top_builddir)/widgets/misc/libemiscwidgets.la \
- $(CAMEL_LIBS)
-
-liborg_gnome_exchange_account_settings_la_LDFLAGS = -module -avoid-version
-
-EXTRA_DIST = org-gnome-exchange-account-setup.eplug.in
diff --git a/plugins/exchange-account-setup/exchange-account-setup.c b/plugins/exchange-account-setup/exchange-account-setup.c
deleted file mode 100644
index 3d1493d5f5..0000000000
--- a/plugins/exchange-account-setup/exchange-account-setup.c
+++ /dev/null
@@ -1,533 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
- *
- * Sushma Rai <rsushma@novell.com>
- * Copyright (C) 2004 Novell, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <string.h>
-#include <glib/gi18n.h>
-#include <glade/glade.h>
-#include <gtk/gtk.h>
-#include <gtk/gtkdialog.h>
-#include <gconf/gconf-client.h>
-#include <camel/camel-provider.h>
-#include <camel/camel-url.h>
-#include <camel/camel-service.h>
-#include "mail/em-account-editor.h"
-#include "mail/em-config.h"
-#include "e-util/e-account.h"
-#include "widgets/misc/e-error.h"
-
-GtkWidget* org_gnome_exchange_settings(EPlugin *epl, EConfigHookItemFactoryData *data);
-GtkWidget *org_gnome_exchange_owa_url(EPlugin *epl, EConfigHookItemFactoryData *data);
-gboolean org_gnome_exchange_check_options(EPlugin *epl, EConfigHookPageCheckData *data);
-GtkWidget *org_gnome_exchange_auth_section (EPlugin *epl, EConfigHookItemFactoryData *data);
-
-/* NB: This should be given a better name, it is NOT a camel service, it is only a camel-exchange one */
-typedef gboolean (CamelProviderValidateUserFunc) (CamelURL *camel_url, const char *url, gboolean *remember_password, CamelException *ex);
-
-typedef struct {
- CamelProviderValidateUserFunc *validate_user;
-}CamelProviderValidate;
-
-CamelServiceAuthType camel_exchange_ntlm_authtype = {
- /* i18n: "Secure Password Authentication" is an Outlookism */
- N_("Secure Password"),
-
- /* i18n: "NTLM" probably doesn't translate */
- N_("This option will connect to the Exchange server using "
- "secure password (NTLM) authentication."),
-
- "",
- TRUE
-};
-
-CamelServiceAuthType camel_exchange_password_authtype = {
- N_("Plaintext Password"),
-
- N_("This option will connect to the Exchange server using "
- "standard plaintext password authentication."),
-
- "Basic",
- TRUE
-};
-
-
-/* only used in editor */
-GtkWidget *
-org_gnome_exchange_settings(EPlugin *epl, EConfigHookItemFactoryData *data)
-{
- EMConfigTargetAccount *target_account;
- const char *source_url;
- CamelURL *url;
- GtkWidget *oof_page;
- GtkWidget *oof_table;
- GtkWidget *oof_description, *label_status, *label_empty;
- GtkWidget *radiobutton_inoff, *radiobutton_oof;
- GtkWidget *vbox_oof, *vbox_oof_message;
- GtkWidget *oof_frame;
- GtkWidget *scrolledwindow_oof;
- GtkWidget *textview_oof;
- char *txt;
-
- target_account = (EMConfigTargetAccount *)data->config->target;
- source_url = e_account_get_string (target_account->account, E_ACCOUNT_SOURCE_URL);
- url = camel_url_new(source_url, NULL);
- if (url == NULL
- || strcmp(url->protocol, "exchange") != 0) {
- if (url)
- camel_url_free(url);
- return NULL;
- }
-
- if (data->old) {
- camel_url_free(url);
- return data->old;
- }
-
- /* FIXME: This out of office data never goes anywhere */
-
- oof_page = gtk_vbox_new (FALSE, 6);
- gtk_container_set_border_width (GTK_CONTAINER (oof_page), 12);
-
- /* Description section */
-
- oof_description = gtk_label_new (_("The message specified below will be automatically sent to \neach person who sends mail to you while you are out of the office."));
- gtk_label_set_justify (GTK_LABEL (oof_description), GTK_JUSTIFY_LEFT);
- gtk_label_set_line_wrap (GTK_LABEL (oof_description), TRUE);
- gtk_misc_set_alignment (GTK_MISC (oof_description), 0.5, 0.5);
- gtk_misc_set_padding (GTK_MISC (oof_description), 0, 18);
-
- gtk_box_pack_start (GTK_BOX (oof_page), oof_description, FALSE, TRUE, 0);
-
- /* Table with out of office radio buttons */
-
- oof_table = gtk_table_new (2, 2, FALSE);
- gtk_table_set_col_spacings (GTK_TABLE (oof_table), 6);
- gtk_table_set_row_spacings (GTK_TABLE (oof_table), 6);
- gtk_box_pack_start (GTK_BOX (oof_page), oof_table, FALSE, FALSE, 0);
-
- /* translators: exchange out of office status header */
- txt = g_strdup_printf("<b>%s</b>", _("Status:"));
- label_status = gtk_label_new (txt);
- g_free(txt);
- gtk_label_set_justify (GTK_LABEL (label_status), GTK_JUSTIFY_CENTER);
- gtk_misc_set_alignment (GTK_MISC (label_status), 0, 0.5);
- gtk_misc_set_padding (GTK_MISC (label_status), 0, 0);
- gtk_label_set_use_markup (GTK_LABEL (label_status), TRUE);
- gtk_table_attach (GTK_TABLE (oof_table), label_status, 0, 1, 0, 1,
- GTK_FILL, GTK_FILL, 0, 0);
-
- radiobutton_inoff = gtk_radio_button_new_with_label (NULL,
- _("I am in the office"));
- gtk_table_attach (GTK_TABLE (oof_table), radiobutton_inoff, 1, 2, 0, 1,
- GTK_FILL, GTK_FILL, 0, 0);
-
- label_empty = gtk_label_new ("");
- gtk_label_set_justify (GTK_LABEL (label_empty), GTK_JUSTIFY_LEFT);
- gtk_misc_set_alignment (GTK_MISC (label_empty), 0, 0.5);
- gtk_misc_set_padding (GTK_MISC (label_empty), 0, 0);
- gtk_label_set_use_markup (GTK_LABEL (label_empty), FALSE);
- gtk_table_attach (GTK_TABLE (oof_table), label_empty, 0, 1, 1, 2,
- GTK_FILL, GTK_FILL, 0, 0);
-
- radiobutton_oof = gtk_radio_button_new_with_label_from_widget (
- GTK_RADIO_BUTTON (radiobutton_inoff),
- _("I am out of the office"));
-
-
- gtk_table_attach (GTK_TABLE (oof_table), radiobutton_oof, 1, 2, 1, 2,
- GTK_FILL, GTK_FILL, 0, 0);
-
- /* frame containg oof message text box */
-
- vbox_oof = gtk_vbox_new (FALSE, 6);
- gtk_box_pack_start (GTK_BOX (oof_page), vbox_oof, FALSE, FALSE, 0);
-
- oof_frame = gtk_frame_new ("");
- gtk_container_set_border_width (GTK_CONTAINER (oof_frame), 1);
- gtk_frame_set_shadow_type (GTK_FRAME (oof_frame), GTK_SHADOW_ETCHED_IN);
- gtk_frame_set_label (GTK_FRAME (oof_frame), _("Out of office Message:"));
- gtk_box_pack_start (GTK_BOX (vbox_oof), oof_frame, FALSE, FALSE, 0);
-
- vbox_oof_message = gtk_vbox_new (FALSE, 6);
- gtk_container_add (GTK_CONTAINER (oof_frame), vbox_oof_message);
-
- scrolledwindow_oof = gtk_scrolled_window_new(NULL, NULL);
- gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow_oof),
- GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
- gtk_scrolled_window_set_shadow_type (
- GTK_SCROLLED_WINDOW (scrolledwindow_oof),
- GTK_SHADOW_IN);
- gtk_box_pack_start (GTK_BOX (vbox_oof_message),
- scrolledwindow_oof, TRUE, TRUE, 0);
-
- textview_oof = gtk_text_view_new();
- gtk_text_view_set_justification (GTK_TEXT_VIEW (textview_oof),
- GTK_JUSTIFY_LEFT);
- gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (textview_oof),
- GTK_WRAP_WORD);
- gtk_text_view_set_editable (GTK_TEXT_VIEW (textview_oof), TRUE);
- gtk_container_add (GTK_CONTAINER (scrolledwindow_oof), textview_oof);
- gtk_widget_show_all (scrolledwindow_oof);
-
- gtk_widget_show_all (oof_page);
-
- gtk_notebook_insert_page (GTK_NOTEBOOK (data->parent), oof_page, gtk_label_new(_("Exchange Settings")), 4);
-
- return oof_page;
-}
-
-static void
-owa_authenticate_user(GtkWidget *button, EConfig *config)
-{
- EMConfigTargetAccount *target_account = (EMConfigTargetAccount *)config->target;
- CamelProviderValidate *validate;
- CamelURL *url=NULL;
- CamelProvider *provider = NULL;
- gboolean remember_password;
- char *url_string;
- const char *source_url, *id_name;
- char *at, *user;
-
- source_url = e_account_get_string (target_account->account, E_ACCOUNT_SOURCE_URL);
- provider = camel_provider_get (source_url, NULL);
- if (!provider || provider->priv == NULL) {
- /* can't happen? */
- return;
- }
-
- url = camel_url_new(source_url, NULL);
- validate = provider->priv;
- if (url->user == NULL) {
- id_name = e_account_get_string (target_account->account, E_ACCOUNT_ID_ADDRESS);
- if (id_name) {
- at = strchr(id_name, '@');
- user = g_alloca(at-id_name+1);
- memcpy(user, id_name, at-id_name);
- user[at-id_name] = 0;
- camel_url_set_user (url, user);
- }
- }
-
- /* validate_user() CALLS GTK!!!
-
- THIS IS TOTALLY UNNACCEPTABLE!!!!!!!!
-
- It must use camel_session_ask_password, and it should return an exception for any problem,
- which should then be shown using e-error */
-
- if (validate->validate_user(url, camel_url_get_param(url, "owa_url"), &remember_password, NULL)) {
- url_string = camel_url_to_string (url, 0);
- e_account_set_string(target_account->account, E_ACCOUNT_SOURCE_URL, url_string);
- e_account_set_string(target_account->account, E_ACCOUNT_TRANSPORT_URL, url_string);
- e_account_set_bool(target_account->account, E_ACCOUNT_SOURCE_SAVE_PASSWD, remember_password);
- g_free(url_string);
- }
-
- camel_url_free (url);
-}
-
-static void
-owa_editor_entry_changed(GtkWidget *entry, EConfig *config)
-{
- const char *uri, *ssl = NULL;
- CamelURL *url, *owaurl = NULL;
- char *url_string;
- EMConfigTargetAccount *target = (EMConfigTargetAccount *)config->target;
- GtkWidget *button = g_object_get_data((GObject *)entry, "authenticate-button");
- int active = FALSE;
-
- /* NB: we set the button active only if we have a parsable uri entered */
-
- url = camel_url_new(e_account_get_string(target->account, E_ACCOUNT_SOURCE_URL), NULL);
- uri = gtk_entry_get_text((GtkEntry *)entry);
- if (uri && uri[0]) {
- camel_url_set_param(url, "owa_url", uri);
- owaurl = camel_url_new(uri, NULL);
- if (owaurl) {
- active = TRUE;
-
- /* i'm not sure why we need this, "ssl connection mode" is redundant
- since we have it in the owa-url protocol */
- if (!strcmp(owaurl->protocol, "https"))
- ssl = "always";
- camel_url_free(owaurl);
- }
- } else {
- camel_url_set_param(url, "owa_url", NULL);
- }
-
- camel_url_set_param(url, "use_ssl", ssl);
- gtk_widget_set_sensitive(button, active);
-
- url_string = camel_url_to_string(url, 0);
- e_account_set_string(target->account, E_ACCOUNT_SOURCE_URL, url_string);
- g_free(url_string);
-}
-
-static void
-destroy_label(GtkWidget *old, GtkWidget *label)
-{
- gtk_widget_destroy(label);
-}
-
-/* used by editor and druid - same code */
-GtkWidget *
-org_gnome_exchange_owa_url(EPlugin *epl, EConfigHookItemFactoryData *data)
-{
- EMConfigTargetAccount *target_account;
- const char *source_url, *owa_url;
- GtkWidget *owa_entry;
- CamelURL *url;
- int row;
- GtkWidget *hbox, *label, *button;
-
- target_account = (EMConfigTargetAccount *)data->config->target;
- source_url = e_account_get_string (target_account->account, E_ACCOUNT_SOURCE_URL);
- url = camel_url_new(source_url, NULL);
- if (url == NULL
- || strcmp(url->protocol, "exchange") != 0) {
- if (url)
- camel_url_free(url);
-
- if (data->old
- && (label = g_object_get_data((GObject *)data->old, "authenticate-label")))
- gtk_widget_destroy(label);
-
- /* TODO: we could remove 'owa-url' from the url,
- but that will lose it if we come back. Maybe a commit callback could do it */
-
- return NULL;
- }
-
- if (data->old) {
- camel_url_free(url);
- return data->old;
- }
-
- owa_url = camel_url_get_param(url, "owa_url");
-
- row = ((GtkTable *)data->parent)->nrows;
-
- hbox = gtk_hbox_new (FALSE, 6);
- label = gtk_label_new_with_mnemonic(_("_OWA Url:"));
- gtk_widget_show(label);
-
- owa_entry = gtk_entry_new();
- if (owa_url)
- gtk_entry_set_text(GTK_ENTRY (owa_entry), owa_url);
- gtk_label_set_mnemonic_widget((GtkLabel *)label, owa_entry);
-
- button = gtk_button_new_with_mnemonic (_("A_uthenticate"));
- gtk_widget_set_sensitive (button, owa_url && owa_url[0]);
-
- gtk_box_pack_start (GTK_BOX (hbox), owa_entry, TRUE, TRUE, 0);
- gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
- gtk_widget_show_all(hbox);
-
- gtk_table_attach (GTK_TABLE (data->parent), label, 0, 1, row, row+1, 0, 0, 0, 0);
- gtk_table_attach (GTK_TABLE (data->parent), hbox, 1, 2, row, row+1, GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);
-
- g_signal_connect (owa_entry, "changed", G_CALLBACK(owa_editor_entry_changed), data->config);
- g_object_set_data((GObject *)owa_entry, "authenticate-button", button);
- g_signal_connect (button, "clicked", G_CALLBACK(owa_authenticate_user), data->config);
-
- /* Track the authenticate label, so we can destroy it if e-config is to destroy the hbox */
- g_object_set_data((GObject *)hbox, "authenticate-label", label);
-
- return hbox;
-}
-
-gboolean
-org_gnome_exchange_check_options(EPlugin *epl, EConfigHookPageCheckData *data)
-{
- EMConfigTargetAccount *target = (EMConfigTargetAccount *)data->config->target;
- int status = TRUE;
-
- /* We assume that if the host is set, then the setting is valid.
- The host gets set when the provider validate() call is made */
- if (data->pageid == NULL || strcmp(data->pageid, "20.receive_options") == 0) {
- CamelURL *url;
-
- url = camel_url_new(e_account_get_string(target->account, E_ACCOUNT_SOURCE_URL), NULL);
- /* Note: we only care about exchange url's, we WILL get called on all other url's too. */
- if (url != NULL
- && strcmp(url->protocol, "exchange") == 0
- && (url->host == NULL || url->host[0] == 0))
- status = FALSE;
-
- if (url)
- camel_url_free(url);
- }
-
- return status;
-}
-
-static void
-exchange_check_authtype (GtkWidget *w, EConfig *config)
-{
- return;
-}
-
-static void
-exchange_authtype_changed (GtkComboBox *dropdown, EConfig *config)
-{
- EMConfigTargetAccount *target = (EMConfigTargetAccount *)config->target;
- int id = gtk_combo_box_get_active(dropdown);
- GtkTreeModel *model;
- GtkTreeIter iter;
- CamelServiceAuthType *authtype;
- CamelURL *url;
- const char *source_url;
- char *url_string;
-
- source_url = e_account_get_string (target->account,
- E_ACCOUNT_SOURCE_URL);
- if (id == -1)
- return;
-
- url = camel_url_new (source_url, NULL);
- model = gtk_combo_box_get_model(dropdown);
- if (gtk_tree_model_iter_nth_child(model, &iter, NULL, id)) {
- gtk_tree_model_get(model, &iter, 1, &authtype, -1);
- if (authtype)
- camel_url_set_authmech(url, authtype->authproto);
- else
- camel_url_set_authmech(url, NULL);
-
- url_string = camel_url_to_string(url, 0);
- e_account_set_string(target->account, E_ACCOUNT_SOURCE_URL, url_string);
- g_free(url_string);
- }
- camel_url_free(url);
-}
-
-GtkWidget *
-org_gnome_exchange_auth_section (EPlugin *epl, EConfigHookItemFactoryData *data)
-{
- EMConfigTargetAccount *target_account;
- const char *source_url;
- char *label_text;
- CamelURL *url;
- GtkWidget *hbox, *button, *auth_label, *vbox, *label_hide;
- GtkComboBox *dropdown;
- GtkTreeIter iter;
- GtkListStore *store;
- int i, active=0, auth_changed_id = 0;
- GList *authtypes, *l, *ll;
-
- target_account = (EMConfigTargetAccount *)data->config->target;
- source_url = e_account_get_string (target_account->account,
- E_ACCOUNT_SOURCE_URL);
- url = camel_url_new (source_url, NULL);
- if (url == NULL
- || strcmp (url->protocol, "exchange") != 0) {
- if (url)
- camel_url_free (url);
-
- return NULL;
- }
-
- if (data->old) {
- camel_url_free(url);
- return data->old;
- }
-
- vbox = gtk_vbox_new (FALSE, 6);
-
- label_text = g_strdup_printf("<b>%s</b>", _("Authentication Type"));
- auth_label = gtk_label_new (label_text);
- g_free (label_text);
- gtk_label_set_justify (GTK_LABEL (auth_label), GTK_JUSTIFY_LEFT);
- gtk_misc_set_alignment (GTK_MISC (auth_label), 0, 0.5);
- gtk_misc_set_padding (GTK_MISC (auth_label), 0, 0);
- gtk_label_set_use_markup (GTK_LABEL (auth_label), TRUE);
-
- label_hide = gtk_label_new("\n");
-
- hbox = gtk_hbox_new (FALSE, 6);
-
- dropdown = (GtkComboBox * )gtk_combo_box_new ();
-
- button = gtk_button_new_with_mnemonic (_("Ch_eck for Supported Types"));
-
- authtypes = g_list_prepend (g_list_prepend (NULL, &camel_exchange_password_authtype),
- &camel_exchange_ntlm_authtype);
- store = gtk_list_store_new(3, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_BOOLEAN);
-
- for (i=0, l=authtypes; l; l=l->next, i++) {
- CamelServiceAuthType *authtype = l->data;
- int avail = TRUE;
-
- if (authtypes) {
- for (ll = authtypes; ll; ll = g_list_next(ll))
- if (!strcmp(authtype->authproto,
- ((CamelServiceAuthType *)ll->data)->authproto))
- break;
- avail = ll != NULL;
- }
- gtk_list_store_append (store, &iter);
- gtk_list_store_set (store, &iter, 0, authtype->name, 1,
- authtype, 2, !avail, -1);
-
- if (url && url->authmech && !strcmp(url->authmech, authtype->authproto))
- active = i;
- }
-
- gtk_combo_box_set_model (dropdown, (GtkTreeModel *)store);
- gtk_combo_box_set_active (dropdown, -1);
-
- if (auth_changed_id == 0) {
- GtkCellRenderer *cell = gtk_cell_renderer_text_new();
-
- gtk_cell_layout_pack_start ((GtkCellLayout *)dropdown, cell, TRUE);
- gtk_cell_layout_set_attributes ((GtkCellLayout *)dropdown, cell,
- "text", 0, "strikethrough", 2, NULL);
-
- auth_changed_id = g_signal_connect (dropdown,
- "changed",
- G_CALLBACK (exchange_authtype_changed),
- data->config);
- g_signal_connect (button,
- "clicked",
- G_CALLBACK(exchange_check_authtype),
- data->config);
- }
-
- gtk_combo_box_set_active(dropdown, active);
-
- gtk_box_pack_start (GTK_BOX (hbox), GTK_WIDGET (dropdown), FALSE, FALSE, 0);
- gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
-
- gtk_box_pack_start (GTK_BOX (vbox), auth_label, TRUE, TRUE, 0);
- gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
- gtk_box_pack_start (GTK_BOX (vbox), label_hide, TRUE, TRUE, 0);
- gtk_widget_show_all (vbox);
-
- gtk_box_pack_start (GTK_BOX (data->parent), vbox, TRUE, TRUE, 0);
-
- if (url)
- camel_url_free(url);
- g_list_free (authtypes);
-
- return vbox;
-}
diff --git a/plugins/exchange-account-setup/exchange-ask-password.c b/plugins/exchange-account-setup/exchange-ask-password.c
deleted file mode 100644
index c21bd67c07..0000000000
--- a/plugins/exchange-account-setup/exchange-ask-password.c
+++ /dev/null
@@ -1,357 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
- *
- * Sushma Rai <rsushma@novell.com>
- * Copyright (C) 2004 Novell, Inc.
- *
- * Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation
- * files (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use, copy,
- * modify, merge, publish, distribute, sublicense, and/or sell copies
- * of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-#include <string.h>
-#include <libgnome/gnome-i18n.h>
-#include <glade/glade.h>
-#include <gtk/gtk.h>
-#include <gtk/gtkdialog.h>
-#include <camel/camel-provider.h>
-#include <camel/camel-url.h>
-#include "mail/em-account-editor.h"
-#include "mail/em-config.h"
-#include "e-util/e-account.h"
-#include "e-util/e-passwords.h"
-#include "e-util/e-config.h"
-
-int e_plugin_lib_enable (EPluginLib *ep, int enable);
-void exchange_options_commit (EPlugin *epl, EConfigHookItemFactoryData *data);
-GtkWidget *org_gnome_exchange_read_url (EPlugin *epl, EConfigHookItemFactoryData *data);
-gboolean org_gnome_exchange_check_options (EPlugin *epl, EConfigHookPageCheckData *data);
-
-const char *owa_entry_text = NULL;
-
-typedef gboolean (CamelProviderValidateUserFunc) (CamelURL *camel_url, const char *url, gboolean *remember_password, CamelException *ex);
-
-typedef struct {
- CamelProviderValidateUserFunc *validate_user;
-}CamelProviderValidate;
-
-int
-e_plugin_lib_enable (EPluginLib *ep, int enable)
-{
- if (enable) {
- }
- return 0;
-}
-
-void
-exchange_options_commit (EPlugin *epl, EConfigHookItemFactoryData *data)
-{
- return;
-}
-
-static gboolean
-validate_exchange_user (void *data)
-{
- EMConfigTargetAccount *target_account = data;
- CamelProviderValidate *validate;
- CamelURL *url=NULL;
- CamelProvider *provider = NULL;
- gboolean valid = FALSE, *remember_password;
- char *account_url, *url_string;
- const char *source_url, *id_name;
- static int count = 0;
- char *at, *user;
-
- if (count)
- return valid;
-
- source_url = e_account_get_string (target_account->account,
- E_ACCOUNT_SOURCE_URL);
- account_url = g_strdup (source_url);
- provider = camel_provider_get (account_url, NULL);
- if (!provider) {
- return FALSE; /* This should never happen */
- }
- url = camel_url_new_with_base (NULL, account_url);
- validate = provider->priv;
- if (validate) {
-
- if (url->user == NULL) {
- id_name = e_account_get_string (target_account->account,
- E_ACCOUNT_ID_ADDRESS);
- if (id_name) {
- at = strchr(id_name, '@');
- user = g_alloca(at-id_name+1);
- memcpy(user, id_name, at-id_name);
- user[at-id_name] = 0;
-
- camel_url_set_user (url, user);
- }
- }
- valid = validate->validate_user (url, owa_entry_text,
- remember_password, NULL);
- }
-
- /* FIXME: need to check for return value */
- if (valid) {
- count ++;
- url_string = camel_url_to_string (url, 0);
- e_account_set_string (target_account->account,
- E_ACCOUNT_SOURCE_URL, url_string);
- e_account_set_string (target_account->account,
- E_ACCOUNT_TRANSPORT_URL, url_string);
- target_account->account->source->save_passwd = *remember_password;
- }
-
- camel_url_free (url);
- g_free (account_url);
- return valid;
-}
-
-static void
-ok_button_clicked (GtkWidget *button, void *data)
-{
- gboolean valid = FALSE;
-
- valid = validate_exchange_user (data); // FIXME: return value
-}
-
-static void
-owa_entry_changed (GtkWidget *entry, void *data)
-{
- GtkWidget *button = data;
-
- /* FIXME: return owa_entry_text instead of making it global */
- owa_entry_text = gtk_entry_get_text (GTK_ENTRY (entry));
- if (owa_entry_text)
- gtk_widget_set_sensitive (button, TRUE);
-}
-
-static GtkWidget *
-add_owa_entry (GtkWidget *parent,
- EConfig *config,
- EMConfigTargetAccount *target_account)
-{
- GtkWidget *section, *owa_entry;
- GtkWidget *hbox, *hbox_inner, *label, *button;
- GList *container_list, *l;
- GValue rows = { 0, };
- GValue cols = { 0, };
- gint n_rows, n_cols;
-
- /* Since configure section in the receive page is not plugin enabled
- * traversing through the container hierarchy to get the reference
- * to the table, to which owa_url entry has to be added.
- * This needs to be changed once we can access configure section from
- * the plugin.
- */
-
- container_list = gtk_container_get_children (GTK_CONTAINER (parent));
- l = g_list_nth (container_list, 1); /* vboxsourceborder */
- container_list = gtk_container_get_children (GTK_CONTAINER (l->data));
- l = g_list_nth (container_list, 0); /* sourcevbox */
- container_list = gtk_container_get_children (GTK_CONTAINER (l->data));
- l = g_list_nth (container_list, 2); /* source frame */
- container_list = gtk_container_get_children (GTK_CONTAINER (l->data));
- l = g_list_nth (container_list, 1); /* hbox173 */
- container_list = gtk_container_get_children (GTK_CONTAINER (l->data));
- l = g_list_nth (container_list, 1); /* table 13 */
- container_list = gtk_container_get_children (GTK_CONTAINER (l->data));
- l = g_list_nth (container_list, 0); /* table 4*/
-
- g_value_init (&rows, G_TYPE_INT);
- g_value_init (&cols, G_TYPE_INT);
- g_object_get_property (G_OBJECT (l->data), "n-rows", &rows);
- g_object_get_property (G_OBJECT (l->data), "n-columns", &cols);
- n_rows = g_value_get_int (&rows);
- n_cols = g_value_get_int (&cols);
-
- hbox = gtk_hbox_new (FALSE, 6);
- gtk_widget_show (hbox);
-
- hbox_inner = gtk_hbox_new (FALSE, 6);
- gtk_widget_show (hbox_inner);
-
- owa_entry = gtk_entry_new ();
- gtk_widget_show (owa_entry);
-
- button = gtk_button_new_with_mnemonic (_("A_uthenticate"));
- gtk_widget_set_sensitive (button, FALSE);
- gtk_widget_show (button);
-
- gtk_box_pack_start (GTK_BOX (hbox_inner), owa_entry, TRUE, TRUE, 0);
- gtk_box_pack_start (GTK_BOX (hbox_inner), button, TRUE, TRUE, 0);
-
- label = gtk_label_new_with_mnemonic(_("_OWA Url:"));
- gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
- gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
- gtk_widget_show (label);
-
- gtk_box_pack_start (GTK_BOX (hbox), hbox_inner, TRUE, TRUE, 0);
-
- gtk_table_attach (GTK_TABLE (l->data), label, 0, n_cols-1, n_rows, n_rows+1, GTK_FILL, GTK_FILL, 0, 0);
- gtk_table_attach (GTK_TABLE (l->data), hbox, n_cols-1, n_cols, n_rows, n_rows+1, GTK_FILL, GTK_FILL, 0, 0);
-
- gtk_widget_show (GTK_WIDGET (l->data));
-
- g_signal_connect (owa_entry, "changed",
- G_CALLBACK (owa_entry_changed), button);
- g_signal_connect (button, "clicked",
- G_CALLBACK (ok_button_clicked), target_account);
-
- section = gtk_vbox_new (FALSE, 0);
- gtk_widget_hide (section);
- return section; /* FIXME: return entry */
-}
-
-GtkWidget *
-org_gnome_exchange_read_url (EPlugin *epl, EConfigHookItemFactoryData *data)
-{
- EMConfigTargetAccount *target_account;
- EConfig *config;
- char *account_url = NULL, *exchange_url = NULL;
- const char *source_url;
- GtkWidget *owa_entry = NULL, *parent;
-
- config = data->config;
- target_account = (EMConfigTargetAccount *)data->config->target;
-
- source_url = e_account_get_string (target_account->account,
- E_ACCOUNT_SOURCE_URL);
- account_url = g_strdup (source_url);
- exchange_url = g_strrstr (account_url, "exchange");
-
- if (exchange_url) {
- if (data->old)
- return data->old;
-
- parent = data->parent;
- owa_entry = add_owa_entry (parent, config, target_account);
- }
- g_free (account_url);
- return owa_entry;
-}
-
-
-GtkWidget *
-org_gnome_exchange_handle_auth (EPlugin *epl, EConfigHookItemFactoryData *data)
-{
- EMConfigTargetAccount *target_account;
- EConfig *config;
- char *account_url = NULL, *exchange_url = NULL, *url_string;
- const char *source_url;
- char *auth_type;
- GtkWidget *auth_section=NULL, *parent, *section;
-
- config = data->config;
- target_account = (EMConfigTargetAccount *)data->config->target;
-
- source_url = e_account_get_string (target_account->account,
- E_ACCOUNT_SOURCE_URL);
- account_url = g_strdup (source_url);
- exchange_url = g_strrstr (account_url, "exchange");
-
- if (exchange_url) {
- parent = data->parent;
-
- /* We don't need auth section while creating the account. But
- * we need that in the Editor. And since we get the child vbox
- * from the plugin, we are finding the parent section and
- * hiding it. This is a temporary fix and this needs to be handled
- * in the proper way. */
- section = gtk_widget_get_parent (gtk_widget_get_parent (parent));
- gtk_widget_hide (section);
- }
- auth_section = gtk_entry_new ();
- gtk_widget_hide (auth_section);
- return auth_section;
-}
-
-GtkWidget *
-org_gnome_exchange_handle_send_auth_option (EPlugin *epl, EConfigHookItemFactoryData *data)
-{
- EMConfigTargetAccount *target_account;
- EConfig *config;
- char *account_url = NULL, *exchange_url = NULL, *url_string;
- const char *source_url;
- char *auth_type;
- GtkWidget *auth_section=NULL, *parent, *section;
-
- config = data->config;
- target_account = (EMConfigTargetAccount *)data->config->target;
-
- source_url = e_account_get_string (target_account->account,
- E_ACCOUNT_SOURCE_URL);
- account_url = g_strdup (source_url);
- exchange_url = g_strrstr (account_url, "exchange");
-
- if (exchange_url) {
- parent = data->parent;
- /* We don't need auth section while creating the account. But
- * we need that in the Editor. And since we get the child vbox
- * from the plugin, we are finding the parent section and
- * hiding it. This is a temporary fix and this needs to be handled
- * in the proper way. */
- section = gtk_widget_get_parent (
- gtk_widget_get_parent (gtk_widget_get_parent(parent)));
- gtk_widget_hide (section);
- }
- auth_section = gtk_entry_new ();
- gtk_widget_hide (auth_section);
- return auth_section;
-}
-
-gboolean
-org_gnome_exchange_check_options (EPlugin *epl, EConfigHookPageCheckData *data)
-{
- EMConfigTargetAccount *target_account;
- EConfig *config;
- char *account_url = NULL, *exchange_url = NULL, *url_string;
- char *use_ssl = NULL;
- static int page_check_count = 0;
- CamelURL *url;
-
- if ((strcmp (data->pageid, "20.receive_options")) || page_check_count)
- return TRUE;
-
- config = data->config;
- target_account = (EMConfigTargetAccount *)data->config->target;
- account_url = g_strdup (target_account->account->source->url);
- exchange_url = g_strrstr (account_url, "exchange");
-
- if (exchange_url) {
- page_check_count ++;
-
- if (owa_entry_text){
- if (!strncmp (owa_entry_text, "https:", 6))
- use_ssl = "always";
-
- url = camel_url_new_with_base (NULL, account_url);
-
- if (use_ssl)
- camel_url_set_param (url, "use_ssl", use_ssl);
- camel_url_set_param (url, "owa_url", owa_entry_text);
-
- url_string = camel_url_to_string (url, 0);
- e_account_set_string (target_account->account,
- E_ACCOUNT_SOURCE_URL, url_string);
- camel_url_free (url);
- }
- }
- return TRUE;
-}
diff --git a/plugins/exchange-account-setup/org-gnome-exchange-account-setup.eplug.in b/plugins/exchange-account-setup/org-gnome-exchange-account-setup.eplug.in
deleted file mode 100644
index df66266934..0000000000
--- a/plugins/exchange-account-setup/org-gnome-exchange-account-setup.eplug.in
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0"?>
-<e-plugin-list>
- <e-plugin
- type="shlib"
- id="org.gnome.evolution.plugin.exchange-account-settings"
- location="@PLUGINDIR@/liborg-gnome-exchange-account-settings.so"
- load-on-startup="true"
- name="Exchange Account Setup"
- description="A pluign for Exchange account specific settings">
-
- <hook class="org.gnome.evolution.mail.config:1.0">
- <group
- target="account"
- id="org.gnome.evolution.mail.config.accountEditor"
- check="org_gnome_exchange_check_options">
- <item type="page"
- path="40.oof"
- label="Exchange Settings"
- factory="org_gnome_exchange_settings"/>
- <item type="item_table"
- path="10.receive/10.config/20.owa"
- factory="org_gnome_exchange_owa_url"/>
- <item type="section"
- path="10.receive/30.auth/00.exchange_auth"
- factory="org_gnome_exchange_auth_section"/>
- </group>
-
- <group
- target="account"
- id="org.gnome.evolution.mail.config.accountDruid"
- check="org_gnome_exchange_check_options">
- <item type="item_table"
- path="10.receive/10.config/20.owa"
- factory="org_gnome_exchange_owa_url"/>
- </group>
- </hook>
-
- </e-plugin>
-</e-plugin-list>
diff --git a/plugins/folder-unsubscribe/.cvsignore b/plugins/folder-unsubscribe/.cvsignore
deleted file mode 100644
index 0ead335993..0000000000
--- a/plugins/folder-unsubscribe/.cvsignore
+++ /dev/null
@@ -1,3 +0,0 @@
-Makefile.in
-Makefile
-org-gnome-mail-folder-unsubscribe.eplug
diff --git a/plugins/folder-unsubscribe/ChangeLog b/plugins/folder-unsubscribe/ChangeLog
deleted file mode 100644
index a0434fc52a..0000000000
--- a/plugins/folder-unsubscribe/ChangeLog
+++ /dev/null
@@ -1,8 +0,0 @@
-2004-11-01 JP Rosevear <jpr@novell.com>
-
- * Makefile.am: dist .eplug.in file
-
-2004-10-28 Not Zed <NotZed@Ximian.com>
-
- * org-gnome-mail-folder-unsubscribe.eplug.in: fix hook id
-
diff --git a/plugins/folder-unsubscribe/Makefile.am b/plugins/folder-unsubscribe/Makefile.am
deleted file mode 100644
index ca805d45d9..0000000000
--- a/plugins/folder-unsubscribe/Makefile.am
+++ /dev/null
@@ -1,13 +0,0 @@
-INCLUDES = \
- -I$(top_srcdir) \
- $(EVOLUTION_MAIL_CFLAGS)
-
-@EVO_PLUGIN_RULE@
-
-plugin_DATA = org-gnome-mail-folder-unsubscribe.eplug
-plugin_LTLIBRARIES = liborg-gnome-mail-folder-unsubscribe.la
-
-liborg_gnome_mail_folder_unsubscribe_la_SOURCES = folder-unsubscribe.c
-liborg_gnome_mail_folder_unsubscribe_la_LDFLAGS = -module -avoid-version
-
-EXTRA_DIST = org-gnome-mail-folder-unsubscribe.eplug.in \ No newline at end of file
diff --git a/plugins/folder-unsubscribe/folder-unsubscribe.c b/plugins/folder-unsubscribe/folder-unsubscribe.c
deleted file mode 100644
index b1900142f9..0000000000
--- a/plugins/folder-unsubscribe/folder-unsubscribe.c
+++ /dev/null
@@ -1,112 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * Authors: Jeffrey Stedfast <fejj@novell.com>
- *
- * Copyright 2004 Novell, Inc. (www.novell.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
- *
- */
-
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <glib.h>
-#include <glib/gi18n.h>
-
-#include <string.h>
-
-#include <camel/camel-session.h>
-#include <camel/camel-store.h>
-#include <camel/camel-url.h>
-
-#include "mail/em-popup.h"
-#include "mail/mail-mt.h"
-#include "mail/mail-ops.h"
-
-
-void org_gnome_mail_folder_unsubscribe (EPlugin *plug, EMPopupTargetFolder *target);
-
-
-
-struct _folder_unsub_t {
- struct _mail_msg msg;
-
- char *uri;
-};
-
-static char *
-folder_unsubscribe__desc (struct _mail_msg *mm, int done)
-{
- struct _folder_unsub_t *unsub = (struct _folder_unsub_t *) mm;
-
- return g_strdup_printf (_("Unsubscribing from folder \"%s\""), unsub->uri);
-}
-
-static void
-folder_unsubscribe__unsub (struct _mail_msg *mm)
-{
- struct _folder_unsub_t *unsub = (struct _folder_unsub_t *) mm;
- extern CamelSession *session;
- const char *path = NULL;
- CamelStore *store;
- CamelURL *url;
-
- if (!(store = camel_session_get_store (session, unsub->uri, &mm->ex)))
- return;
-
- url = camel_url_new (unsub->uri, NULL);
- if (((CamelService *) store)->provider->url_flags & CAMEL_URL_FRAGMENT_IS_PATH)
- path = url->fragment;
- else if (url->path && url->path[0])
- path = url->path + 1;
-
- if (path != NULL)
- camel_store_unsubscribe_folder (store, path, &mm->ex);
-
- camel_url_free (url);
-}
-
-static void
-folder_unsubscribe__free (struct _mail_msg *mm)
-{
- struct _folder_unsub_t *unsub = (struct _folder_unsub_t *) mm;
-
- g_free (unsub->uri);
-}
-
-static struct _mail_msg_op unsubscribe_op = {
- folder_unsubscribe__desc,
- folder_unsubscribe__unsub,
- NULL,
- folder_unsubscribe__free,
-};
-
-
-void
-org_gnome_mail_folder_unsubscribe (EPlugin *plug, EMPopupTargetFolder *target)
-{
- struct _folder_unsub_t *unsub;
-
- if (target->uri == NULL)
- return;
-
- unsub = mail_msg_new (&unsubscribe_op, NULL, sizeof (struct _folder_unsub_t));
- unsub->uri = g_strdup (target->uri);
-
- e_thread_put (mail_thread_new, (EMsg *) unsub);
-}
diff --git a/plugins/folder-unsubscribe/org-gnome-mail-folder-unsubscribe.eplug.in b/plugins/folder-unsubscribe/org-gnome-mail-folder-unsubscribe.eplug.in
deleted file mode 100644
index 5fd793a8a3..0000000000
--- a/plugins/folder-unsubscribe/org-gnome-mail-folder-unsubscribe.eplug.in
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0"?>
-<e-plugin-list>
- <e-plugin id="org.gnome.mail.folder.unsubscribe"
- type="shlib" domain="evolution" name="Unsubscribe Folders"
- location="@PLUGINDIR@/liborg-gnome-mail-folder-unsubscribe.so">
- <description>Allows unsubscribing folders in the folder tree context menu</description>
- <author name="Jeffrey Stedfast" email="fejj@novell.com"/>
- <hook class="org.gnome.evolution.mail.popup:1.0">
- <menu id="org.gnome.evolution.mail.foldertree.popup" target="folder">
- <item type="item" path="20.emc.03" label="_Unsubscribe"
- activate="org_gnome_mail_folder_unsubscribe"
- enable="delete" visible="delete"/>
- </menu>
- </hook>
- </e-plugin>
-</e-plugin-list>
diff --git a/plugins/groupwise-account-setup/ChangeLog b/plugins/groupwise-account-setup/ChangeLog
deleted file mode 100644
index 117d263206..0000000000
--- a/plugins/groupwise-account-setup/ChangeLog
+++ /dev/null
@@ -1,44 +0,0 @@
-2005-01-28 Sivaiah Nallagatla <snallagatla@novell.com>
-
- * camel-gw-listner.c (get_address_book_names_from_server)
- : Remove leading "%s" in the message. Similar to
- #36137
-
-2005-01-23 Sivaiah Nallagatla <snalagatla@novell.com>
-
- * camel-gw-listener.c (add_esource)
- (modify_esource) (add_addressbook_sources) :
- Don't set offline_sync value taken from camel url
- instead set "1" or "0" depending upon offline is enabled
- or not
-
-2005-01-21 Sivaiah Nallagatla <snallagtla@novell.com>
-
- * org-gnome-gw-account-setup.eplug.in : changed
- the item type from "item" to "item_table". avoids
- some debug spew on the console
-
-2005-01-20 Sivaiah Nallagatla <snallagatla@novell.com>
-
- * camel-gw-listener.c: (add_calendar_tasks_sources):
- Assiged value to URL.
-
-2005-01-15 Sivaiah Nallagatla <snallagatla@novell.com>
-
- * camel-gw-listner.c : use url->host instead of reading "poa"
- parameter everywhere. use "use_ssl" param instead of soap_ssl
- We not longer have separate settings for soap as we use soap for mail
- now
-
-2004-12-17 Sivaiah Nallagatla <snallagatla@novell.com>
-
- * camel-gw-listner.c (add_esource) : read "soap_ssl" from
- the camel url instead of "use_ssl"
-
-2004-12-15 Rodney Dawes <dobey@novell.com>
-
- * Makefile.am: Add camel-gw-listener.h to SOURCES
-
-2004-12-03 Sivaiah Nallagatla <snallagatla@novell.com>
-
- * initial check in
diff --git a/plugins/groupwise-account-setup/Makefile.am b/plugins/groupwise-account-setup/Makefile.am
deleted file mode 100644
index 62a52db90b..0000000000
--- a/plugins/groupwise-account-setup/Makefile.am
+++ /dev/null
@@ -1,23 +0,0 @@
-INCLUDES = -I . \
- -I$(top_srcdir) \
- $(EVOLUTION_MAIL_CFLAGS) \
- $(CAMEL_GROUPWISE_CFLAGS)
-
-@EVO_PLUGIN_RULE@
-
-plugin_DATA = org-gnome-gw-account-setup.eplug
-plugin_LTLIBRARIES = liborg-gnome-gw-account-setup.la
-
-liborg_gnome_gw_account_setup_la_SOURCES = \
- groupwise-account-setup.c \
- camel-gw-listener.c \
- camel-gw-listener.h
-
-liborg_gnome_gw_account_setup_la_LIBADD = \
- $(CAMEL_GROUPWISE_LIBS) \
- $(top_builddir)/e-util/libeutil.la \
- $(top_builddir)/widgets/misc/libemiscwidgets.la
-
-liborg_gnome_gw_account_setup_la_LDFLAGS = -module -avoid-version
-
-EXTRA_DIST = org-gnome-gw-account-setup.eplug.in
diff --git a/plugins/groupwise-account-setup/camel-gw-listener.h b/plugins/groupwise-account-setup/camel-gw-listener.h
deleted file mode 100644
index bf1df856a6..0000000000
--- a/plugins/groupwise-account-setup/camel-gw-listener.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * Authors :
- *
- * Sivaiah Nallagatla <snallagatla@novell.com>
- *
- * Copyright 2003, Novell, Inc.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
- */
-
-
-#ifndef CAMEL_GW_LISTENER_H
-#define CAMEL_GW_LISTENER_H
-
-
-#include <libedataserver/e-account-list.h>
-#include<libedataserver/e-source.h>
-#include<libedataserver/e-source-list.h>
-#include <camel/camel-url.h>
-
-G_BEGIN_DECLS
-
-#define CAMEL_TYPE_GW_LISTENER (camel_gw_listener_get_type ())
-#define CAMEL_GW_LISTENER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CAMEL_TYPE_GW_LISTENER, CamelGwListener))
-#define CAMEL_GW_LISTENER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CAMEL_TYPE_GW_LISTENER, CamelGWListenerClass))
-#define CAMEL_IS_GWLISTENER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CAMEL_TYPE_GW_LISTENER))
-#define CAMEL_IS_GW_LISTENER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), CAMEL_TYPE_GW_LISTENER))
-
-typedef struct _CamelGwListener CamelGwListener;
-typedef struct _CamelGwListenerClass CamelGwListenerClass;
-typedef struct _CamelGwListenerPrivate CamelGwListenerPrivate;
-struct _CamelGwListener {
- GObject parent;
-
- CamelGwListenerPrivate *priv;
-};
-
-struct _CamelGwListenerClass {
- GObjectClass parent_class;
-
-
-};
-
-GType camel_gw_listener_get_type (void);
-CamelGwListener *camel_gw_listener_new (void);
-
-G_END_DECLS
-
-#endif
-
diff --git a/plugins/groupwise-account-setup/groupwise-account-setup.c b/plugins/groupwise-account-setup/groupwise-account-setup.c
deleted file mode 100644
index 930585e74d..0000000000
--- a/plugins/groupwise-account-setup/groupwise-account-setup.c
+++ /dev/null
@@ -1,67 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
- *
- * Sivaiah Nallagatla <snallagatla@novell.com>
- * Copyright (C) 2004 Novell, Inc.
- *
- * Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation
- * files (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use, copy,
- * modify, merge, publish, distribute, sublicense, and/or sell copies
- * of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-
-#include "camel-gw-listener.h"
-#include <gtk/gtk.h>
-#include "mail/em-config.h"
-
-static CamelGwListener *config_listener = NULL;
-
-int e_plugin_lib_enable (EPluginLib *ep, int enable);
-GtkWidget* org_gnome_gw_account_setup(struct _EPlugin *epl, struct _EConfigHookItemFactoryData *data);
-
-static void
-free_groupwise_listener ( void )
-{
- g_object_unref (config_listener);
-}
-
-int
-e_plugin_lib_enable (EPluginLib *ep, int enable)
-{
- if (!config_listener) {
- config_listener = camel_gw_listener_new ();
- g_atexit ( free_groupwise_listener );
- }
-
- return 0;
-}
-
-
-GtkWidget *
-org_gnome_gw_account_setup(struct _EPlugin *epl, struct _EConfigHookItemFactoryData *data)
-{
- GtkWidget *w;
-
- if (data->old)
- return data->old;
- /* FIXME, with new soap camel provider we don't need extra settings in receiving options page, Remove them
- from camel-groupwise-provider.c once soap provider is ready and add any groupwise sepcific settings like "add contacts automatically to Frequent contacts folder" here*/
-
- w = gtk_invisible_new ();
- return w;
-}
diff --git a/plugins/groupwise-account-setup/org-gnome-gw-account-setup.eplug.in b/plugins/groupwise-account-setup/org-gnome-gw-account-setup.eplug.in
deleted file mode 100644
index 33994fc620..0000000000
--- a/plugins/groupwise-account-setup/org-gnome-gw-account-setup.eplug.in
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0"?>
-<e-plugin-list>
- <e-plugin
- type="shlib"
- id="org.gnome.evolution.plugin.gw-account-setup"
- location="@PLUGINDIR@/liborg-gnome-gw-account-setup.so"
- load-on-startup="true"
- name="Groupwise Account Setup"
- description="A pluign to setup groupwise calendar and contacts sources">
-
-
- <hook class="org.gnome.evolution.mail.config:1.0">
- <group target="account" id="org.gnome.evolution.mail.config.accountDruid">
- <item type="item_table" path="20.receive_options/30.soapport/50.dummy" factory="org_gnome_gw_account_setup"/>
- </group>
- </hook>
-
- <hook class="org.gnome.evolution.mail.config:1.0">
- <group target="account" id="org.gnome.evolution.mail.config.accountEditor">
- <item type="item_table" path="20.receive_options/30.soapport/50.dummy" factory="org_gnome_gw_account_setup"/>
- </group>
- </hook>
-
-
- </e-plugin>
-</e-plugin-list>
diff --git a/plugins/groupwise-send-options/ChangeLog b/plugins/groupwise-send-options/ChangeLog
deleted file mode 100755
index f005c16cd6..0000000000
--- a/plugins/groupwise-send-options/ChangeLog
+++ /dev/null
@@ -1,13 +0,0 @@
-2005-02-03 Chenthill Palanisamy <pchenthill@novell.com>
-
- * send-options.c: (add_day_to_time), (send_options_commit),
- (org_gnome_compose_send_options):Added functions to destroy
- the dialog when the composer is destroyed to solve the crash.
- Removed the return statement so that the send options gets
- added to the composer headers. Made modification in setting
- the values for some headers.
- Changing the file name from Changelog to ChangeLog.
-
-2005-01-10 Parthasarathi@novell.com <sparthasarathi@novell.com>
-
- * initial check in for groupwise send options
diff --git a/plugins/groupwise-send-options/Makefile.am b/plugins/groupwise-send-options/Makefile.am
deleted file mode 100644
index b30ce1f03e..0000000000
--- a/plugins/groupwise-send-options/Makefile.am
+++ /dev/null
@@ -1,15 +0,0 @@
-INCLUDES = \
- -I$(top_srcdir) \
- $(EVOLUTION_MAIL_CFLAGS)
-
-@EVO_PLUGIN_RULE@
-
-plugin_DATA = org-gnome-compose-send-options.eplug org-gnome-compose-send-options.xml
-plugin_LTLIBRARIES = liborg-gnome-compose-send-options.la
-
-liborg_gnome_compose_send_options_la_SOURCES = send-options.c send-options.h
-liborg_gnome_compose_send_options_la_LDFLAGS = -module -avoid-version
-
-EXTRA_DIST = \
- org-gnome-compose-send-options.eplug.in \
- org-gnome-compose-send-options.xml
diff --git a/plugins/groupwise-send-options/org-gnome-compose-send-options.eplug.in b/plugins/groupwise-send-options/org-gnome-compose-send-options.eplug.in
deleted file mode 100644
index 2fc06d389e..0000000000
--- a/plugins/groupwise-send-options/org-gnome-compose-send-options.eplug.in
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0"?>
-<e-plugin-list>
- <e-plugin
- type="shlib"
- id="org.gnome.evolution.plugin.compose.sendoptions"
- location="@PLUGINDIR@/liborg-gnome-compose-send-options.so"
- name="Send options in compose for GW">
- <description>Lets you have the send options menu item in the composer window for groupwise mails</description>
- <author name="Parthasarathi Susarla" email="sparthasarathi@novell.com"/>
-
- <!-- hook into the popup menu -->
- <hook class="org.gnome.evolution.mail.bonobomenu:1.0">
- <menu id="org.gnome.evolution.mail.composer" target="select">
- <ui file="@PLUGINDIR@/org-gnome-compose-send-options.xml"/>
- <item
- type="item"
- verb="EPSOSendOptions"
- path="/commands/EPSOSendOptions"
- enable="one"
- activate="org_gnome_compose_send_options"/>
- </menu>
- </hook>
-
- </e-plugin>
-</e-plugin-list>
diff --git a/plugins/groupwise-send-options/org-gnome-compose-send-options.xml b/plugins/groupwise-send-options/org-gnome-compose-send-options.xml
deleted file mode 100644
index c5947c6a33..0000000000
--- a/plugins/groupwise-send-options/org-gnome-compose-send-options.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<Root>
- <commands>
- <cmd name="EPSOSendOptions" _label="Send Options"
- _tip="Add Send Options to groupwise messages"/>
- </commands>
-
- <menu>
- <submenu name="Insert">
- <placeholder name="Component">
- <separator f="" name="sendoptions1"/>
- <menuitem name="EPSOSendOptions" verb=""/>
- <separator f="" name="sendoptions2"/>
- </placeholder>
- </submenu>
-
- </menu>
-</Root>
diff --git a/plugins/groupwise-send-options/send-options.c b/plugins/groupwise-send-options/send-options.c
deleted file mode 100644
index 7e8d71d610..0000000000
--- a/plugins/groupwise-send-options/send-options.c
+++ /dev/null
@@ -1,144 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
- *
- * Authors: Parthasarathi Susarla <sparthasarathi@novell.com>
- *
- * Copyright 2004 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., 59 Temple Street #330, Boston, MA 02111-1307, USA.
- *
- */
-
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdio.h>
-
-#include <glib.h>
-#include <glib/gi18n.h>
-
-#include "send-options.h"
-
-#include "mail/em-menu.h"
-#include "mail/em-utils.h"
-
-#include "composer/e-msg-composer.h"
-#include "e-util/e-account.h"
-
-#include "widgets/misc/e-send-options.h"
-
-static ESendOptionsDialog * dialog = NULL ;
-
-void org_gnome_compose_send_options (EPlugin *ep, EMMenuTargetWidget *t);
-
-static time_t
-add_day_to_time (time_t time, int days)
-{
- struct tm *tm;
-
- tm = localtime (&time);
- tm->tm_mday += days;
- tm->tm_isdst = -1;
-
- return mktime (tm);
-}
-
-static void
-send_options_commit (EMsgComposer *comp, gpointer user_data)
-{
- if (!user_data && !E_IS_SENDOPTIONS_DIALOG (user_data))
- return;
-
- if (dialog) {
- g_object_unref (dialog);
- dialog = NULL;
- }
-}
-
-void
-org_gnome_compose_send_options (EPlugin *ep, EMMenuTargetWidget *t)
-{
- struct _EMenuTarget menu = t->target ;
- EMsgComposer *comp = (struct _EMsgComposer *)menu.widget ;
- EAccount *account = NULL;
- char *temp = NULL;
- char *url;
- char value [100];
-
- account = e_msg_composer_get_preferred_account (comp) ;
- url = g_strdup (account->transport->url) ;
- temp = strstr (url, "groupwise") ;
- if (!temp) {
- g_print ("Sorry send options only available for a groupwise account\n") ;
- }
- g_free (temp) ;
- /*disply the send options dialog*/
- if (!dialog) {
- g_print ("New dialog\n\n") ;
- dialog = e_sendoptions_dialog_new () ;
- }
-
- e_sendoptions_dialog_run (dialog, menu.widget, E_ITEM_MAIL) ;
-
- if (dialog->data->gopts->reply_enabled) {
- if (dialog->data->gopts->reply_convenient)
- e_msg_composer_add_header (comp, X_REPLY_CONVENIENT ,"1" ) ;
- else if (dialog->data->gopts->reply_within) {
- time_t t;
- t = add_day_to_time (time (NULL), dialog->data->gopts->reply_convenient);
- strftime (value, 17, "%Y%m%dT%H%M%SZ", gmtime (&t));
- e_msg_composer_add_header (comp, X_REPLY_WITHIN , value) ;
- }
- }
-
- if (dialog->data->gopts->expiration_enabled) {
- if (dialog->data->gopts->expire_after != 0) {
- time_t t;
- t = add_day_to_time (time (NULL), dialog->data->gopts->expire_after);
- strftime (value, 17, "%Y%m%dT%H%M%SZ", gmtime (&t));
- e_msg_composer_add_header (comp, X_EXPIRE_AFTER, value) ;
- }
- }
- if (dialog->data->gopts->delay_enabled) {
- strftime (value, 17, "%Y%m%dT%H%M%SZ", gmtime (&dialog->data->gopts->delay_until));
- e_msg_composer_add_header (comp, X_DELAY_UNTIL, value) ;
- }
-
- /*Status Tracking Options*/
- if (dialog->data->sopts->tracking_enabled) {
- temp = g_strdup_printf ("%d",dialog->data->sopts->track_when) ;
- e_msg_composer_add_header (comp, X_TRACK_WHEN, temp) ;
- g_free (temp) ;
- }
-
- if (dialog->data->sopts->autodelete) {
- e_msg_composer_add_header (comp, X_AUTODELETE, "1") ;
- }
- if (dialog->data->sopts->opened) {
- temp = g_strdup_printf ("%d",dialog->data->sopts->opened) ;
- e_msg_composer_add_header (comp, X_RETURN_NOTIFY_OPEN, temp) ;
- g_free (temp) ;
- }
- if (dialog->data->sopts->declined) {
- temp = g_strdup_printf ("%d",dialog->data->sopts->declined) ;
- e_msg_composer_add_header (comp, X_RETURN_NOTIFY_DECLINE, temp) ;
- g_free (temp) ;
- }
-
- g_signal_connect (GTK_WIDGET (comp), "destroy",
- G_CALLBACK (send_options_commit), dialog);
-}
-
-
diff --git a/plugins/groupwise-send-options/send-options.h b/plugins/groupwise-send-options/send-options.h
deleted file mode 100644
index 76c79a2a00..0000000000
--- a/plugins/groupwise-send-options/send-options.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
- *
- * Authors: Parthasarathi Susarla <sparthasarathi@novell.com>
- *
- * Copyright 2004 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., 59 Temple Street #330, Boston, MA 02111-1307, USA.
- *
- */
-
-#ifndef __GW_SEND_OPTIONS__
-#define __GW_SEND_OPTIONS__
-
-/*Headers for send options*/
-#define X_SEND_OPTIONS "X-gw-send-options"
-/*General Options*/
-#define X_SEND_OPT_PRIORITY "X-gw-send-opt-priority"
-#define X_REPLY_CONVENIENT "X-reply-convenient"
-#define X_REPLY_WITHIN "X-reply-within"
-#define X_EXPIRE_AFTER "X-expire-after"
-#define X_DELAY_UNTIL "X-delay-until"
-
-/*Status Tracking Options*/
-#define X_TRACK_WHEN "X-track-when"
-#define X_AUTODELETE "X-auto-delete"
-#define X_RETURN_NOTIFY_OPEN "X-return-notify-open"
-#define X_RETURN_NOTIFY_DECLINE "X-return-notify-decline"
-
-#endif /*__GW_SEND_OPTIONS__*/
diff --git a/plugins/groupwise-status-tracking/Changelog b/plugins/groupwise-status-tracking/Changelog
deleted file mode 100644
index 48d92a1184..0000000000
--- a/plugins/groupwise-status-tracking/Changelog
+++ /dev/null
@@ -1,3 +0,0 @@
-2005-01-20 Parthasarathi Susarla <sparthasarathi@novell.com> Chenthill Palanisamy <pchenthill@novell.com>
-
- * first commit of the status tracking plugin
diff --git a/plugins/groupwise-status-tracking/Makefile.am b/plugins/groupwise-status-tracking/Makefile.am
deleted file mode 100644
index cc1aeac51c..0000000000
--- a/plugins/groupwise-status-tracking/Makefile.am
+++ /dev/null
@@ -1,15 +0,0 @@
-INCLUDES = \
- -I$(top_srcdir) \
- $(CAMEL_GROUPWISE_CFLAGS) \
- $(EVOLUTION_MAIL_CFLAGS)
-
-@EVO_PLUGIN_RULE@
-
-plugin_DATA = org-gnome-status-track.eplug
-plugin_LTLIBRARIES = liborg-gnome-status-track.la
-
-liborg_gnome_status_track_la_SOURCES = status-track.c
-liborg_gnome_status_track_la_LIBADD = $(CAMEL_GROUPWISE_LIBS)
-liborg_gnome_status_track_la_LDFLAGS = -module -avoid-version
-
-EXTRA_DIST = org-gnome-status-track.eplug.in
diff --git a/plugins/groupwise-status-tracking/org-gnome-status-track.eplug.in b/plugins/groupwise-status-tracking/org-gnome-status-track.eplug.in
deleted file mode 100644
index a2d3d4bee4..0000000000
--- a/plugins/groupwise-status-tracking/org-gnome-status-track.eplug.in
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0"?>
-<e-plugin-list>
- <e-plugin
- type="shlib"
- id="org.gnome.evolution.plugin.status.track"
- location="@PLUGINDIR@/liborg-gnome-status-track.so"
- name="Track status of a sent mail in a groupwise account">
- <description>A plugin which allows status tracking. This is applicable for groupwise mailboxes only</description>
- <author name="Parthasarathi Susarla" email="sparthasarathi@novell.com"/>
-
- <!-- hook into the uri popup menu -->
- <hook class="org.gnome.evolution.mail.popup:1.0">
- <menu id="org.gnome.evolution.mail.folderview.popup" target="select">
- <item
- type="item"
- path="21.gw_status_tracking"
- label="Track Message Status"
- enable="one"
- visible="one"
- activate="org_gnome_track_status"/>
- </menu>
- </hook>
- </e-plugin>
-</e-plugin-list>
-
diff --git a/plugins/groupwise-status-tracking/status-track.c b/plugins/groupwise-status-tracking/status-track.c
deleted file mode 100644
index e4b208a812..0000000000
--- a/plugins/groupwise-status-tracking/status-track.c
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * Copyright (C) 2004 Novell, Inc.
- *
- * Author(s): Chenthill Palanisamy <pchenthill@novell.com>
- * Parthasarathi Susarla <sparthasarathi@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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
- */
-
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <glib/gi18n-lib.h>
-#include <string.h>
-#include <stdio.h>
-#include <time.h>
-#include <gtk/gtk.h>
-
-#include "camel/camel-folder.h"
-#include "camel/camel-medium.h"
-#include "camel/camel-mime-message.h"
-#include "mail/em-popup.h"
-
-#include <e-gw-connection.h>
-
-
-void org_gnome_track_status (void *ep, EMPopupTargetSelect *t) ;
-void add_recipient (GtkTable *table, char *recp, int row) ;
-int add_detail (GtkTable *table, char *label, char *value, int row) ;
-
-void
-add_recipient (GtkTable *table, char *recp, int row)
-{
- GtkWidget *widget ;
-
- widget = gtk_label_new (recp) ;
- gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
- gtk_table_attach (table, widget , 0, 1, row, row + 1, GTK_FILL, 0, 0, 0);
-}
-
-int
-add_detail (GtkTable *table, char *label, char *value, int row)
-{
- GtkWidget *widget ;
- time_t time = e_gw_connection_get_date_from_string (value) ;
- char *str = ctime (&time) ;
-
- str [strlen(str)-1] = '\0' ;
-
- widget = gtk_label_new (label);
- gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
- gtk_table_attach (table, widget , 1, 2, row, row + 1, GTK_FILL, 0, 0, 0);
- widget = gtk_label_new (str);
- gtk_table_attach (table, widget , 2, 3, row, row + 1, GTK_FILL, 0, 0, 0);
- row++;
- return row ;
-}
-/*
- * The format for the options is:
- * 0 1 2 3 4 5 6 7 8 9
- * X-gw-status-opt: /TO/CC/BCC;name;email;delivered;opened;accepted;deleted;declined;completed;undelivered::
- */
-void org_gnome_track_status (void *ep, EMPopupTargetSelect *t)
-{
- CamelMimeMessage *msg = NULL ;
- const CamelInternetAddress *from ;
- const char *namep, *addp ;
-
- GtkDialog *d ;
- GtkTable *table ;
- GtkWidget *widget;
- GtkScrolledWindow *win;
- GtkVBox *vbox;
-
- time_t time ;
- char *time_str ;
-
- const char *status = NULL ;
- char **temp1 = NULL, **temp2 = NULL , **ptr = NULL, *str = NULL ;
-
- int row = 0;
-
- /*check if it is a groupwise account*/
- str = strstr (t->uri, "groupwise") ;
- if (!str) {
- g_warning ("Status tracking available for groupwise account only") ;
- return ;
- }
- str = strstr (t->uri, "Sent Items") ;
- if (!str) {
- g_warning ("Status tracking available for a sent folder only") ;
- return ;
- }
-
- /*Get message*/
- msg = camel_folder_get_message (t->folder, g_ptr_array_index (t->uids, 0), NULL);
- if (!msg) {
- g_print ("Error!! No message\n") ;
- return ;
- }
- status = camel_medium_get_header ( CAMEL_MEDIUM(msg), "X-gw-status-opt") ;
- if (!status) {
- g_print ("Error!! No header\n") ;
- return ;
- }
-
- /*Create the dialog*/
- d = (GtkDialog *) gtk_dialog_new ();
- gtk_dialog_add_button (d, GTK_STOCK_OK, GTK_RESPONSE_OK);
- gtk_window_set_title (GTK_WINDOW (d), "Message Status");
-
- table = (GtkTable *) gtk_table_new (1, 2, FALSE);
- win = (GtkScrolledWindow *) gtk_scrolled_window_new (NULL, NULL);
- gtk_container_add (GTK_CONTAINER (GTK_DIALOG(d)->vbox), GTK_WIDGET (win));
- vbox = (GtkVBox *) gtk_vbox_new (FALSE, 12);
- gtk_scrolled_window_add_with_viewport (win, GTK_WIDGET(vbox));
- gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET (table), FALSE, TRUE, 0);
- gtk_scrolled_window_set_policy (win, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
-
- gtk_table_set_col_spacings (table ,12);
- gtk_table_set_row_spacings (table, 6);
-
- /*Subject*/
- widget = gtk_label_new ("<b>Subject</b> :");
- gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
- gtk_label_set_use_markup (GTK_LABEL (widget), TRUE);
- gtk_table_attach (table, widget , 0, 1, row, row + 1, GTK_FILL, 0, 0, 0);
- widget = gtk_label_new (camel_mime_message_get_subject(msg));
- gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
- gtk_table_attach (table, widget , 1, 2, row, row + 1, GTK_FILL, 0, 0, 0);
- row++;
-
- /*From*/
- from = camel_mime_message_get_from (msg) ;
- camel_internet_address_get (from, 0, &namep, &addp) ;
- widget = gtk_label_new ("<b>From</b> :");
- gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
- gtk_label_set_use_markup (GTK_LABEL (widget), TRUE);
- gtk_table_attach (table, widget , 0, 1, row, row + 1, GTK_FILL, 0, 0, 0);
- widget = gtk_label_new (namep);
- gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
- gtk_table_attach (table, widget , 1, 2, row, row + 1, GTK_FILL, 0, 0, 0);
- row++;
-
- /*creation date*/
- time = camel_mime_message_get_date (msg, NULL) ;
- time_str = ctime (&time) ;
- time_str[strlen(time_str)-1] = '\0' ;
- widget = gtk_label_new ("<b>Creation date</b> :");
- gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
- gtk_label_set_use_markup (GTK_LABEL (widget), TRUE);
- gtk_table_attach (table, widget , 0, 1, row, row + 1, GTK_FILL, 0, 0, 0);
- widget = gtk_label_new (time_str);
- gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
- gtk_table_attach (table, widget , 1, 2, row, row + 1, GTK_FILL, 0, 0, 0);
- row++;
-
- /*spacing*/
- widget = gtk_label_new ("");
- gtk_table_attach (table, widget, 0, 1, row, row + 1, GTK_FILL, 0, 0, 0);
- row++;
-
- /*Table headers*/
- row = 0;
- table = (GtkTable *) gtk_table_new (1, 3, FALSE);
- gtk_table_set_col_spacings (table ,12);
- gtk_table_set_row_spacings (table, 6);
- gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET (table), FALSE, TRUE, 0);
- widget = gtk_label_new ("<b>Recipients </b>");
- gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
- gtk_label_set_use_markup (GTK_LABEL (widget), TRUE);
- gtk_table_attach (table, widget , 0, 1, row, row + 1, GTK_FILL, 0, 0, 0);
- widget = gtk_label_new ("<b>Action</b>");
- gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
- gtk_label_set_use_markup (GTK_LABEL (widget), TRUE);
- gtk_table_attach (table, widget , 1, 2, row, row + 1, GTK_FILL, 0, 0, 0);
- widget = gtk_label_new ("<b>Date and Time</b>");
- gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
- gtk_label_set_use_markup (GTK_LABEL (widget), TRUE);
- gtk_table_attach (table, widget , 2, 3, row, row + 1, GTK_FILL, 0, 0, 0);
- row++;
-
-
- temp1 = g_strsplit (status, "::", -1) ;
- ptr = temp1 ;
- str = *ptr ;
- while (str) {
- temp2 = g_strsplit (str, ";", -1) ;
- if (*temp2) {
- if (strlen(temp2[0]));
- if (strlen(temp2[1]))
- add_recipient (table, temp2[1], row) ;
- if (strlen(temp2[2]));
- if (strlen(temp2[3]))
- row = add_detail (table,"delivered" , temp2[3], row) ;
- if (strlen(temp2[4]))
- row = add_detail (table,"opened" , temp2[3], row) ;
- if (strlen(temp2[5]))
- row = add_detail (table,"accepted" , temp2[3], row) ;
- if (strlen(temp2[6]))
- row = add_detail (table,"deleted" , temp2[3], row) ;
- if (strlen(temp2[7]))
- row = add_detail (table,"declined" , temp2[3], row) ;
- if (strlen(temp2[8]))
- row = add_detail (table,"completed" , temp2[3], row) ;
- if (strlen(temp2[9]))
- row = add_detail (table,"undelivered" , temp2[3], row) ;
- }
- str = *(++ptr) ;
- g_strfreev (temp2) ;
- }
-
- /*set size and display the dialog*/
- gtk_widget_set_usize (GTK_WIDGET (win), 400, 300);
- gtk_widget_show_all (GTK_WIDGET (d));
- if (gtk_dialog_run (d) == GTK_RESPONSE_OK)
- gtk_widget_destroy (GTK_WIDGET (d));
- else
- gtk_widget_destroy (GTK_WIDGET (d));
-
-
- g_strfreev (temp1) ;
-
-}
diff --git a/plugins/itip-formatter/.cvsignore b/plugins/itip-formatter/.cvsignore
deleted file mode 100644
index 12b8e0db22..0000000000
--- a/plugins/itip-formatter/.cvsignore
+++ /dev/null
@@ -1,6 +0,0 @@
-.deps
-.libs
-Makefile
-Makefile.in
-*.eplug
-org-gnome-itip-formatter-errors.xml.h
diff --git a/plugins/itip-formatter/ChangeLog b/plugins/itip-formatter/ChangeLog
deleted file mode 100644
index 7e3fe55799..0000000000
--- a/plugins/itip-formatter/ChangeLog
+++ /dev/null
@@ -1,343 +0,0 @@
-2005-02-07 JP Rosevear <jpr@novell.com>
-
- * org-gnome-itip-formatter.eplug.in: specify id for config page
-
-2005-03-03 Rodney Dawes <dobey@novell.com>
-
- * itip-view.c (itip_view_init): Set the spacing for ourself to 12
- to be HIG compliant as we are a GtkHBox derivative
- Align the icon at 0.5 in the X direction to be HIG compliant
- Set the spacing between table rows/columns to be HIG compliant
- Fix the spacing/padding for all the boxes and packing calls to be
- HIG compliant
-
- Fixes #41235
-
-2005-02-02 Chenthill Palanisamy <pchenthill@novell.com>
-
- reviewed by Harish Krishnaswamy <kharish@novell.com>
-
- Fixes #71460
- * itip-formatter.c: (view_response_cb): If the my_address
- is not set. Set it from the backend.
-
-2005-01-27 JP Rosevear <jpr@novell.com>
-
- * itip-view.c (format_date_and_time_x): make tomorrow and this
- week strings work properly
-
-2005-01-27 JP Rosevear <jpr@novell.com>
-
- * itip-formatter.c (find_cal_opened_cb): remove debug test
-
-442005-01-27 JP Rosevear <jpr@novell.com>
-
- * itip-formatter.c: add some debugging spew
-
-2005-01-27 Rodrigo Moya <rodrigo@novell.com>
-
- * itip-formatter.c (update_attendee_status): deal with the itip
- message having an individual instance.
-
-2005-01-26 JP Rosevear <jpr@novell.com>
-
- Fixes #71485
-
- * itip-formatter.c (update_attendee_status): fix message paste-o
-
- * itip-view.c (format_date_and_time_x): improve translator
- comments
-
-2005-01-25 JP Rosevear <jpr@novell.com>
-
- * itip-formatter.c (pitip_free): actually destroy the client
- hashes so the signals get cleaned up
- (format_itip): create a proper unique classid for the pobject
-
-2005-01-14 JP Rosevear <jpr@novell.com>
-
- * itip-formatter.c (extract_itip_data): use
- camel_data_wrapper_decode_to_stream instead of
- camel_data_wrapper_write_to_stream
-
-2005-01-14 JP Rosevear <jpr@novell.com>
-
- * itip-formatter.c (format_itip_object): handle UTC dtstart/dtend
- properly
-
-2005-01-11 JP Rosevear <jpr@novell.com>
-
- Fixes #29985
-
- * itip-formatter.c (view_response_cb): set the message flags to
- answered if we send successfully
-
-2005-01-11 Harish Krishnaswamy <kharish@novell.com>
-
- * itip-formatter.c (update_item): Fixed a compiler warning.
-
-2005-01-10 JP Rosevear <jpr@novell.com>
-
- * itip-formatter.c (update_item): set to the new items, duh
-
-2005-01-10 JP Rosevear <jpr@novell.com>
-
- * itip-formatter.c (update_item): compare pointers instead of
- content id
-
-2005-01-10 JP Rosevear <jpr@novell.com>
-
- * itip-formatter.c (update_item): first crack at saving
- attachments for the backend
- (extract_itip_data): tell the user what to do for more than one
- attachment
-
-2005-01-09 JP Rosevear <jpr@novell.com>
-
- * itip-view.h: remove error mode
-
- * itip-formatter.c (set_itip_error): show error information to the
- user
- (extract_itip_data): use above
- (format_itip_object): no more "error" mode
-
-2005-01-09 JP Rosevear <jpr@novell.com>
-
- * itip-view.c (itip_view_set_delegator): accessor
- (itip_view_get_delegator): ditto
-
- * itip-view.h: new protos
-
- * itip-formatter.c (extract_itip_data): put delegate sections back
- in and handle default reminder
- (format_itip_object): set the delegator for requests, find the
- delegator calendar if necessary
-
-2005-01-09 JP Rosevear <jpr@novell.com>
-
- * itip-formatter.c (idle_open_cb): launch an evolution window
- pointing at the calendar date of the appointment
- (view_response_cb): use it
-
-2005-01-09 JP Rosevear <jpr@novell.com>
-
- * itip-formatter.c (find_cal_opened_cb): only check for conflicts
- if the source has the conflict property
- (initialize_selection): select the "conflict" sources in the
- selector
- (source_selection_changed): update the source properties
- (itip_formatter_page_factory): include the source selector for
- selecting conflict checking calendars
-
-2005-01-08 Harish Krishnaswamy <kharish@novell.com>
-
- * itip-formatter.c: (send_item), (view_response_cb):
- update itip_send_comp calls with the new prototype.
-
-2005-01-07 JP Rosevear <jpr@novell.com>
-
- * itip-view.h: new protos
-
- * itip-view.c (set_tasklist_sender_text): task sender messages
- (set_calendar_sender_text): calendar sender messages
- (set_sender_text): select above as appropriate
- (itip_view_set_item_type): accessor
- (itip_view_get_item_type): ditto
-
- * itip-formatter.c (find_cal_opened_cb): messages for
- meetings/tasks/journals
- (send_item): ditto
- (format_itip_object): ditto
- (itip_formatter_page_factory): change page title
-
-2005-01-07 JP Rosevear <jpr@novell.com>
-
- * itip-formatter.c (view_response_cb): ensure there is only one
- attendee in the RSVP even if the user is duplicated
-
-2005-01-07 JP Rosevear <jpr@novell.com>
-
- * itip-view.h: protos
-
- * itip-view.c (rsvp_toggled_cb): set comment sensitivity
- (itip_view_init): add comment entry
- (itip_view_set_rsvp): make comment entry sensitive when rsvp is
- (itip_view_set_rsvp_comment): accessor
- (itip_view_get_rsvp_comment): ditto
-
- * itip-formatter.c (find_cal_opened_cb): set error message if we
- can't find the item
- (view_response_cb): add comment if the user sets one
-
-2005-01-07 JP Rosevear <jpr@novell.com>
-
- * itip-view.h: add protos
-
- * itip-view.c (set_sender_text): update descriptions better
- (set_status_text): show/hide status
- (set_comment_text): show/hide comment
- (set_buttons): update buttons for add an refresh
- (itip_view_destroy): free comment/status
- (itip_view_init): add status/comment widgets
- (itip_view_set_status): accessor
- (itip_view_get_status): ditto
- (itip_view_set_comment): ditto
- (itip_view_get_comment): ditto
-
- * itip-formatter.c (find_cal_opened_cb): make sure rsvp is off for
- publish
- (format_itip_object): decline counter is sent by an organizer; set
- status and comment when appropriate
-
-2005-01-05 Rodney Dawes <dobey@novell.com>
-
- * Makefile.am: Dist the errors data properly, and add the .eplug
- output file to BUILT_SOURCES
-
-2005-01-03 Rodney Dawes <dobey@novell.com>
-
- * itip-formatter.c (format_itip_object): Don't do set_usize ()
- on the container
-
-2005-01-03 JP Rosevear <jpr@novell.com>
-
- * itip-formatter.c (format_itip_object): load accounts
-
-2005-01-03 JP Rosevear <jpr@novell.com>
-
- * org-gnome-itip-formatter-errors.xml: remove unused message
-
- * itip-formatter.c (update_item): use info item, not e-error
-
-2005-01-03 JP Rosevear <jpr@novell.com>
-
- * itip-formatter.c (view_response_cb): implement cancel
- (update_item): add cancel info item
-
-2005-01-03 JP Rosevear <jpr@novell.com>
-
- * itip-view.c (itip_view_add_upper_info_item_printf): utility
- routine to make it easier to add info items
- (itip_view_add_lower_info_item_printf): ditto
-
- * itip-view.h: new protos
-
- * itip-formatter.c: use new printf routines everyhwere it makes
- sense
-
-2005-01-03 JP Rosevear <jpr@novell.com>
-
- * itip-formatter.c (find_cal_opened_cb): move the adjust item work
- here when we actually have the calendar
- (pitip_free): implement a free function
- (find_cal_opened_cb): check the methods instead of the show
- selector member
- (find_cal_opened_cb): default to true for the rsvp setting
-
-2005-01-03 JP Rosevear <jpr@novell.com>
-
- * itip-view.h: add response enums
-
- * itip-view.c (set_buttons): fiddle with button names and response enums
-
- * itip-formatter.c (find_server): don't include our uid in the
- conflicts search
- (update_attendee_status): update the status of the attendee and
- save it out
- (adjust_item): get relevant properties for items that might
- contain them if sent from an attendee
- (get_real_item): get the actual, current item
- (send_item): send the item
- (view_response_cb): handle REPLY and REFRESH requests
- (format_itip_object): adjust the item if necessary and set the
- attendee for reply/refresh; prevent crash if no description
- (pitip_free): skeleton free function
- (format_itip): load delete message setting
- (delete_toggled_cb): set delete message setting based on toggle
- (itip_formatter_page_factory): make the delete message check box
- work
-
- * Makefile.am: install e-error messages
-
-2005-01-03 JP Rosevear <jpr@novell.com>
-
- * itip-view.h: new protos, signal
-
- * itip-view.c (set_info_items): be more generic so both upper and
- lower setting can use it
- (set_upper_info_items): set the upper info items
- (set_lower_info_items): ditto for lower items
- (itip_view_destroy): clear both sets of info items
- (itip_view_class_init): add source selected signalo
- (itip_view_init): add separate upper and lower info item areas and
- a detail area
- (itip_view_add_upper_info_item): add upper info item
- (itip_view_remove_upper_info_item): remove a singal upper area
- info item
- (itip_view_clear_upper_info_items): clear them all
- (itip_view_add_lower_info_item): as above
- (itip_view_remove_lower_info_item): ditto
- (itip_view_clear_lower_info_items): ditto
- (source_selected_cb): emit the source selected signal when the
- source in the option menu changes
- (itip_view_set_source_list): take a source list and create an
- e-source-option-menu if its non-null
- (itip_view_get_source_list): get source list
- (itip_view_set_source): set a specific source in the source option
- menu
- (itip_view_get_source): obtain that source
- (itip_view_set_rsvp): get the rsvp status
- (itip_view_get_rsvp): set it
- (itip_view_set_show_rsvp): set visibility of rsvp check box
- (itip_view_get_show_rsvp): get the visibility of rsvp check box
- (itip_view_set_buttons_sensitive): set button sensitivity
- (itip_view_get_buttons_sensitive): get button sensitivity
-
- * itip-formatter.c (find_my_address): find the user's address in
- the list of attendees
- (set_buttons_sensitive): set the action buttons sensitivity
- appropriately
- (cal_opened_cb): use above
- (start_calendar_server): ditto
- (start_calendar_server_by_uid): de-sensitize buttons to start
- (source_selected_cb): ditto
- (find_cal_opened_cb): check for conflicting appointments; set
- informative info area items
- (find_server): create the sexp for determining conflicts
- (update_item): oset informative info area items
- (view_response_cb): implement some of the responses, start on
- implementing rsvp
- (format_itip_object): load the source lists properly
-
-2004-12-29 JP Rosevear <jpr@novell.com>
-
- * itip-view.h: new protos
-
- * itip-view.c (format_date_and_time_x): don't draw the leading
- zero in 12hr clock mode for the hour
- (set_sender_text): make intro statements closer to the UI design
- (set_description_text): display description
- (set_info_items): show info items, messages with icons
- (set_progress_text): show progress text item (for
- loading/searching calendars)
- (set_one_button): add a response button
- (set_buttons): set response buttons based on mode
- (itip_view_destroy): clear info items
- (itip_view_class_init): add response signal
- (itip_view_init): new areas for description, info items, buttons
- (itip_view_set_description): accessor
- (itip_view_get_description): ditto
- (itip_view_add_info_item): add an info item to the display
- (itip_view_clear_info_items): clear all items
- (itip_view_set_progress): set the progress message
-
- * itip-formatter.c: move over calendar loading, searching code,
- set more itip view properties
-
- * org-gnome-itip-formatter.eplug.in: add a config page item,
- doesn't do much right now
-
-2004-12-22 JP Rosevear <jpr@novell.com>
-
- * Initial checkin of new itip formatter
-
diff --git a/plugins/itip-formatter/Makefile.am b/plugins/itip-formatter/Makefile.am
deleted file mode 100644
index def2a59f4a..0000000000
--- a/plugins/itip-formatter/Makefile.am
+++ /dev/null
@@ -1,23 +0,0 @@
-INCLUDES = \
- -I$(top_srcdir) \
- $(EVOLUTION_MAIL_CFLAGS) \
- $(EVOLUTION_CALENDAR_CFLAGS)
-
-@EVO_PLUGIN_RULE@
-
-plugin_DATA = org-gnome-itip-formatter.eplug
-plugin_LTLIBRARIES = liborg-gnome-itip-formatter.la
-
-liborg_gnome_itip_formatter_la_SOURCES = itip-formatter.c itip-view.c itip-view.h
-liborg_gnome_itip_formatter_la_LDFLAGS = -module -avoid-version
-
-error_DATA = org-gnome-itip-formatter-errors.xml
-error_i18n = $(error_DATA:.xml=.xml.h)
-errordir = $(privdatadir)/errors
-%.xml.h: %.xml
- $(top_builddir)/e-util/e-error-tool $^
-
-BUILT_SOURCES = $(plugin_DATA) $(error_i18n)
-
-EXTRA_DIST = $(error_DATA) $(error_i18n) org-gnome-itip-formatter.eplug.in
-
diff --git a/plugins/itip-formatter/itip-formatter.c b/plugins/itip-formatter/itip-formatter.c
deleted file mode 100644
index d1954a8cb9..0000000000
--- a/plugins/itip-formatter/itip-formatter.c
+++ /dev/null
@@ -1,1732 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * Authors: JP Rosevear <jpr@novell.com>
- *
- * Copyright 2004 Novell, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <string.h>
-#include <glib.h>
-#include <gtk/gtk.h>
-#include <libgnome/gnome-i18n.h>
-#include <gconf/gconf-client.h>
-#include <camel/camel-stream.h>
-#include <camel/camel-stream-mem.h>
-#include <camel/camel-medium.h>
-#include <camel/camel-mime-message.h>
-#include <camel/camel-folder.h>
-#include <camel/camel-multipart.h>
-#include <libecal/e-cal.h>
-#include <libecal/e-cal-time-util.h>
-#include <libedataserverui/e-source-option-menu.h>
-#include <libedataserverui/e-source-selector.h>
-#include <gtkhtml/gtkhtml-embedded.h>
-#include <mail/em-format-hook.h>
-#include <mail/em-config.h>
-#include <mail/em-format-html.h>
-#include <mail/em-utils.h>
-#include <e-util/e-account-list.h>
-#include <e-util/e-icon-factory.h>
-#include <widgets/misc/e-error.h>
-#include <calendar/gui/calendar-config.h>
-#include <calendar/gui/itip-utils.h>
-#include <calendar/common/authentication.h>
-#include "itip-view.h"
-
-#define CLASSID "itip://"
-#define GCONF_KEY_DELETE "/apps/evolution/itip/delete_processed"
-
-#define d(x) x
-
-void format_itip (EPlugin *ep, EMFormatHookTarget *target);
-GtkWidget *itip_formatter_page_factory (EPlugin *ep, EConfigHookItemFactoryData *hook_data);
-
-typedef struct {
- EMFormatHTMLPObject pobject;
-
- GtkWidget *view;
-
- ESourceList *source_lists[E_CAL_SOURCE_TYPE_LAST];
- GHashTable *ecals[E_CAL_SOURCE_TYPE_LAST];
-
- ECal *current_ecal;
- ECalSourceType type;
-
- char *vcalendar;
- ECalComponent *comp;
- icalcomponent *main_comp;
- icalcomponent *ical_comp;
- icalcomponent *top_level;
- icalcompiter iter;
- icalproperty_method method;
- time_t start_time;
- time_t end_time;
-
- int current;
- int total;
-
- gchar *calendar_uid;
-
- EAccountList *accounts;
-
- gchar *from_address;
- gchar *delegator_address;
- gchar *delegator_name;
- gchar *my_address;
- gint view_only;
-
- guint progress_info_id;
-
- gboolean delete_message;
-} FormatItipPObject;
-
-typedef struct {
- FormatItipPObject *pitip;
- char *uid;
-
- char *sexp;
-
- int count;
-} FormatItipFindData;
-
-typedef void (* FormatItipOpenFunc) (ECal *ecal, ECalendarStatus status, gpointer data);
-
-static void
-find_my_address (FormatItipPObject *pitip, icalcomponent *ical_comp, icalparameter_partstat *status)
-{
- icalproperty *prop;
- char *my_alt_address = NULL;
-
- for (prop = icalcomponent_get_first_property (ical_comp, ICAL_ATTENDEE_PROPERTY);
- prop != NULL;
- prop = icalcomponent_get_next_property (ical_comp, ICAL_ATTENDEE_PROPERTY)) {
- icalvalue *value;
- icalparameter *param;
- const char *attendee, *name;
- char *attendee_clean, *name_clean;
- EIterator *it;
-
- value = icalproperty_get_value (prop);
- if (value != NULL) {
- attendee = icalvalue_get_string (value);
- attendee_clean = g_strdup (itip_strip_mailto (attendee));
- attendee_clean = g_strstrip (attendee_clean);
- } else {
- attendee = NULL;
- attendee_clean = NULL;
- }
-
- param = icalproperty_get_first_parameter (prop, ICAL_CN_PARAMETER);
- if (param != NULL) {
- name = icalparameter_get_cn (param);
- name_clean = g_strdup (name);
- name_clean = g_strstrip (name_clean);
- } else {
- name = NULL;
- name_clean = NULL;
- }
-
- if (pitip->delegator_address) {
- char *delegator_clean;
-
- delegator_clean = g_strdup (itip_strip_mailto (attendee));
- delegator_clean = g_strstrip (delegator_clean);
-
- /* If the mailer told us the address to use, use that */
- if (delegator_clean != NULL
- && !g_ascii_strcasecmp (attendee_clean, delegator_clean)) {
- pitip->my_address = g_strdup (itip_strip_mailto (pitip->delegator_address));
- pitip->my_address = g_strstrip (pitip->my_address);
-
- if (status) {
- param = icalproperty_get_first_parameter (prop, ICAL_PARTSTAT_PARAMETER);
- *status = param ? icalparameter_get_partstat (param) : ICAL_PARTSTAT_NEEDSACTION;
- }
- }
-
- g_free (delegator_clean);
- } else {
- it = e_list_get_iterator((EList *)pitip->accounts);
- while (e_iterator_is_valid(it)) {
- const EAccount *account = e_iterator_get(it);
-
- /* Check for a matching address */
- if (attendee_clean != NULL
- && !g_ascii_strcasecmp (account->id->address, attendee_clean)) {
- pitip->my_address = g_strdup (account->id->address);
- if (status) {
- param = icalproperty_get_first_parameter (prop, ICAL_PARTSTAT_PARAMETER);
- *status = param ? icalparameter_get_partstat (param) : ICAL_PARTSTAT_NEEDSACTION;
- }
- g_free (attendee_clean);
- g_free (name_clean);
- g_free (my_alt_address);
- g_object_unref(it);
- return;
- }
-
- /* Check for a matching cname to fall back on */
- if (name_clean != NULL
- && !g_ascii_strcasecmp (account->id->name, name_clean))
- my_alt_address = g_strdup (attendee_clean);
-
- e_iterator_next(it);
- }
- g_object_unref(it);
- }
-
- g_free (attendee_clean);
- g_free (name_clean);
- }
-
- pitip->my_address = my_alt_address;
- if (status)
- *status = ICAL_PARTSTAT_NEEDSACTION;
-}
-
-static ECalComponent *
-get_real_item (FormatItipPObject *pitip)
-{
- ECalComponent *comp;
- icalcomponent *icalcomp;
- gboolean found = FALSE;
- const char *uid;
-
- e_cal_component_get_uid (pitip->comp, &uid);
-
- found = e_cal_get_object (pitip->current_ecal, uid, NULL, &icalcomp, NULL);
- if (!found)
- return NULL;
-
- comp = e_cal_component_new ();
- if (!e_cal_component_set_icalcomponent (comp, icalcomp)) {
- g_object_unref (comp);
- icalcomponent_free (icalcomp);
- return NULL;
- }
-
- return comp;
-}
-
-static void
-adjust_item (FormatItipPObject *pitip, ECalComponent *comp)
-{
- ECalComponent *real_comp;
-
- real_comp = get_real_item (pitip);
- if (real_comp != NULL) {
- ECalComponentText text;
- const char *string;
- GSList *l;
-
- e_cal_component_get_summary (real_comp, &text);
- e_cal_component_set_summary (comp, &text);
- e_cal_component_get_location (real_comp, &string);
- e_cal_component_set_location (comp, string);
- e_cal_component_get_description_list (real_comp, &l);
- e_cal_component_set_description_list (comp, l);
- e_cal_component_free_text_list (l);
-
- g_object_unref (real_comp);
- } else {
- ECalComponentText text = {_("Unknown"), NULL};
-
- e_cal_component_set_summary (comp, &text);
- }
-}
-
-static void
-set_buttons_sensitive (FormatItipPObject *pitip)
-{
- gboolean read_only = TRUE;
-
- if (pitip->current_ecal)
- e_cal_is_read_only (pitip->current_ecal, &read_only, NULL);
-
- itip_view_set_buttons_sensitive (ITIP_VIEW (pitip->view), pitip->current_ecal != NULL && !read_only);
-}
-
-
-static void
-cal_opened_cb (ECal *ecal, ECalendarStatus status, gpointer data)
-{
- FormatItipPObject *pitip = data;
- ESource *source;
- ECalSourceType source_type;
- icaltimezone *zone;
-
- source_type = e_cal_get_source_type (ecal);
- source = e_cal_get_source (ecal);
-
- g_signal_handlers_disconnect_matched (ecal, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, cal_opened_cb, NULL);
-
- if (status != E_CALENDAR_STATUS_OK) {
- d(printf ("Failed opening itip formatter calendar '%s' during non-search opening\n", e_source_peek_name (source)));
- itip_view_add_lower_info_item_printf (ITIP_VIEW (pitip->view), ITIP_VIEW_INFO_ITEM_TYPE_WARNING,
- "Failed to load the calendar '%s'", e_source_peek_name (source));
-
- g_hash_table_remove (pitip->ecals[source_type], e_source_peek_uid (source));
-
- return;
- }
-
- zone = calendar_config_get_icaltimezone ();
- e_cal_set_default_timezone (ecal, zone, NULL);
-
- pitip->current_ecal = ecal;
-
- set_buttons_sensitive (pitip);
-}
-
-static ECal *
-start_calendar_server (FormatItipPObject *pitip, ESource *source, ECalSourceType type, FormatItipOpenFunc func, gpointer data)
-{
- ECal *ecal;
-
- ecal = g_hash_table_lookup (pitip->ecals[type], e_source_peek_uid (source));
- if (ecal) {
- pitip->current_ecal = ecal;
-
- itip_view_remove_lower_info_item (ITIP_VIEW (pitip->view), pitip->progress_info_id);
- pitip->progress_info_id = 0;
-
- set_buttons_sensitive (pitip);
-
- return ecal;
- }
-
- ecal = auth_new_cal_from_source (source, type);
- g_signal_connect (G_OBJECT (ecal), "cal_opened", G_CALLBACK (func), data);
-
- g_hash_table_insert (pitip->ecals[type], g_strdup (e_source_peek_uid (source)), ecal);
-
- e_cal_open_async (ecal, TRUE);
-
- return ecal;
-}
-
-static ECal *
-start_calendar_server_by_uid (FormatItipPObject *pitip, const char *uid, ECalSourceType type)
-{
- int i;
-
- itip_view_set_buttons_sensitive (ITIP_VIEW (pitip->view), FALSE);
-
- for (i = 0; i < E_CAL_SOURCE_TYPE_LAST; i++) {
- ESource *source;
-
- source = e_source_list_peek_source_by_uid (pitip->source_lists[i], uid);
- if (source)
- return start_calendar_server (pitip, source, type, cal_opened_cb, pitip);
- }
-
- return NULL;
-}
-
-static void
-source_selected_cb (ItipView *view, ESource *source, gpointer data)
-{
- FormatItipPObject *pitip = data;
-
- itip_view_set_buttons_sensitive (ITIP_VIEW (pitip->view), FALSE);
-
- start_calendar_server (pitip, source, pitip->type, cal_opened_cb, pitip);
-}
-
-static void
-find_cal_opened_cb (ECal *ecal, ECalendarStatus status, gpointer data)
-{
- FormatItipFindData *fd = data;
- FormatItipPObject *pitip = fd->pitip;
- ESource *source;
- ECalSourceType source_type;
- icalcomponent *icalcomp;
- icaltimezone *zone;
- GList *objects = NULL;
-
- source_type = e_cal_get_source_type (ecal);
- source = e_cal_get_source (ecal);
-
- fd->count--;
-
- g_signal_handlers_disconnect_matched (ecal, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, find_cal_opened_cb, NULL);
-
- if (status != E_CALENDAR_STATUS_OK) {
- /* FIXME Do we really want to warn here? If we fail
- * to find the item, this won't be cleared but the
- * selector might be shown */
- d(printf ("Failed opening itip formatter calendar '%s' during search opening... ", e_source_peek_name (source)));
- itip_view_add_lower_info_item_printf (ITIP_VIEW (pitip->view), ITIP_VIEW_INFO_ITEM_TYPE_WARNING,
- "Failed to load the calendar '%s'", e_source_peek_name (source));
-
- g_hash_table_remove (pitip->ecals[source_type], e_source_peek_uid (source));
-
- goto cleanup;
- }
-
- /* Check for conflicts */
- /* If the query fails, we'll just ignore it */
- /* FIXME What happens for recurring conflicts? */
- if (pitip->type == E_CAL_SOURCE_TYPE_EVENT
- && e_source_get_property (E_SOURCE (source), "conflict")
- && !g_ascii_strcasecmp (e_source_get_property (E_SOURCE (source), "conflict"), "true")
- && e_cal_get_object_list (ecal, fd->sexp, &objects, NULL)
- && g_list_length (objects) > 0) {
- itip_view_add_upper_info_item_printf (ITIP_VIEW (pitip->view), ITIP_VIEW_INFO_ITEM_TYPE_WARNING,
- "An appointment in the calendar '%s' conflicts with this meeting", e_source_peek_name (source));
-
- e_cal_free_object_list (objects);
- }
-
- if (e_cal_get_object (ecal, fd->uid, NULL, &icalcomp, NULL)) {
- icalcomponent_free (icalcomp);
-
- pitip->current_ecal = ecal;
-
- /* Provide extra info, since its not in the component */
- /* FIXME Check sequence number of meeting? */
- /* FIXME Do we need to adjust elsewhere for the delegated calendar item? */
- /* FIXME Need to update the fields in the view now */
- if (pitip->method == ICAL_METHOD_REPLY || pitip->method == ICAL_METHOD_REFRESH)
- adjust_item (pitip, pitip->comp);
-
- /* We clear everything because we don't really care
- * about any other info/warnings now we found an
- * existing versions */
- itip_view_clear_lower_info_items (ITIP_VIEW (pitip->view));
- pitip->progress_info_id = 0;
-
- /* FIXME Check read only state of calendar? */
- itip_view_add_lower_info_item_printf (ITIP_VIEW (pitip->view), ITIP_VIEW_INFO_ITEM_TYPE_INFO,
- "Found the appointment in the calendar '%s'", e_source_peek_name (source));
-
- set_buttons_sensitive (pitip);
- }
-
- zone = calendar_config_get_icaltimezone ();
- e_cal_set_default_timezone (ecal, zone, NULL);
-
- cleanup:
- d(printf ("Decreasing itip formatter search count to %d\n", fd->count));
-
- if (fd->count == 0) {
- itip_view_remove_lower_info_item (ITIP_VIEW (pitip->view), pitip->progress_info_id);
- pitip->progress_info_id = 0;
-
- if ((pitip->method == ICAL_METHOD_PUBLISH || pitip->method == ICAL_METHOD_REQUEST)
- && !pitip->current_ecal) {
- ESource *source = NULL;
- char *uid;
-
- switch (pitip->type) {
- case E_CAL_SOURCE_TYPE_EVENT:
- uid = calendar_config_get_primary_calendar ();
- break;
- case E_CAL_SOURCE_TYPE_TODO:
- uid = calendar_config_get_primary_tasks ();
- break;
- default:
- uid = NULL;
- g_assert_not_reached ();
- }
-
- if (uid) {
- source = e_source_list_peek_source_by_uid (pitip->source_lists[pitip->type], uid);
- g_free (uid);
- }
-
- /* Try to create a default if there isn't one */
- if (!source)
- source = e_source_list_peek_source_any (pitip->source_lists[pitip->type]);
-
- itip_view_set_source_list (ITIP_VIEW (pitip->view), pitip->source_lists[pitip->type]);
- g_signal_connect (pitip->view, "source_selected", G_CALLBACK (source_selected_cb), pitip);
-
- /* The only method that RSVP makes sense for is REQUEST */
- /* FIXME Default to the suggestion for RSVP for my attendee */
- itip_view_set_rsvp (ITIP_VIEW (pitip->view), pitip->method == ICAL_METHOD_REQUEST ? TRUE : FALSE);
- itip_view_set_show_rsvp (ITIP_VIEW (pitip->view), pitip->method == ICAL_METHOD_REQUEST ? TRUE : FALSE);
-
- if (source) {
- itip_view_set_source (ITIP_VIEW (pitip->view), source);
-
- /* FIXME Shouldn't the buttons be sensitized here? */
- } else {
- itip_view_add_lower_info_item (ITIP_VIEW (pitip->view), ITIP_VIEW_INFO_ITEM_TYPE_ERROR, "Unable to find any calendars");
- itip_view_set_buttons_sensitive (ITIP_VIEW (pitip->view), FALSE);
- }
- } else if (!pitip->current_ecal) {
- switch (pitip->type) {
- case E_CAL_SOURCE_TYPE_EVENT:
- itip_view_add_lower_info_item_printf (ITIP_VIEW (pitip->view), ITIP_VIEW_INFO_ITEM_TYPE_WARNING,
- "Unable to find this meeting in any calendar");
- break;
- case E_CAL_SOURCE_TYPE_TODO:
- itip_view_add_lower_info_item_printf (ITIP_VIEW (pitip->view), ITIP_VIEW_INFO_ITEM_TYPE_WARNING,
- "Unable to find this task in any task list");
- break;
- case E_CAL_SOURCE_TYPE_JOURNAL:
- itip_view_add_lower_info_item_printf (ITIP_VIEW (pitip->view), ITIP_VIEW_INFO_ITEM_TYPE_WARNING,
- "Unable to find this journal entry in any journal");
- break;
- default:
- g_assert_not_reached ();
- break;
- }
- }
-
- g_free (fd->uid);
- g_free (fd);
- }
-}
-
-static void
-find_server (FormatItipPObject *pitip, ECalComponent *comp)
-{
- FormatItipFindData *fd = NULL;
- GSList *groups, *l;
- const char *uid;
-
- e_cal_component_get_uid (comp, &uid);
-
- pitip->progress_info_id = itip_view_add_lower_info_item (ITIP_VIEW (pitip->view), ITIP_VIEW_INFO_ITEM_TYPE_PROGRESS,
- "Searching for an existing version of this appointment");
-
- itip_view_set_buttons_sensitive (ITIP_VIEW (pitip->view), FALSE);
-
- groups = e_source_list_peek_groups (pitip->source_lists[pitip->type]);
- for (l = groups; l; l = l->next) {
- ESourceGroup *group;
- GSList *sources, *m;
-
- group = l->data;
-
- sources = e_source_group_peek_sources (group);
- for (m = sources; m; m = m->next) {
- ESource *source;
- ECal *ecal;
-
- source = m->data;
-
- if (!fd) {
- char *start = NULL, *end = NULL;
-
- fd = g_new0 (FormatItipFindData, 1);
- fd->pitip = pitip;
- fd->uid = g_strdup (uid);
-
- if (pitip->start_time && pitip->end_time) {
- start = isodate_from_time_t (pitip->start_time);
- end = isodate_from_time_t (pitip->end_time);
-
- fd->sexp = g_strdup_printf ("(and (occur-in-time-range? (make-time \"%s\") (make-time \"%s\")) (not (uid? \"%s\")))",
- start, end, icalcomponent_get_uid (pitip->ical_comp));
- }
-
- g_free (start);
- g_free (end);
- }
- fd->count++;
- d(printf ("Increasing itip formatter search count to %d\n", fd->count));
-
- ecal = start_calendar_server (pitip, source, pitip->type, find_cal_opened_cb, fd);
- }
- }
-}
-
-static void
-cleanup_ecal (gpointer data)
-{
- ECal *ecal = data;
-
- /* Clean up any signals */
- g_signal_handlers_disconnect_matched (ecal, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, cal_opened_cb, NULL);
- g_signal_handlers_disconnect_matched (ecal, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, find_cal_opened_cb, NULL);
-
- g_object_unref (ecal);
-}
-
-static icalproperty *
-find_attendee (icalcomponent *ical_comp, const char *address)
-{
- icalproperty *prop;
-
- if (address == NULL)
- return NULL;
-
- for (prop = icalcomponent_get_first_property (ical_comp, ICAL_ATTENDEE_PROPERTY);
- prop != NULL;
- prop = icalcomponent_get_next_property (ical_comp, ICAL_ATTENDEE_PROPERTY)) {
- icalvalue *value;
- const char *attendee;
- char *text;
-
- value = icalproperty_get_value (prop);
- if (!value)
- continue;
-
- attendee = icalvalue_get_string (value);
-
- text = g_strdup (itip_strip_mailto (attendee));
- text = g_strstrip (text);
- if (!g_strcasecmp (address, text)) {
- g_free (text);
- break;
- }
- g_free (text);
- }
-
- return prop;
-}
-
-static gboolean
-change_status (icalcomponent *ical_comp, const char *address, icalparameter_partstat status)
-{
- icalproperty *prop;
-
- prop = find_attendee (ical_comp, address);
- if (prop) {
- icalparameter *param;
-
- icalproperty_remove_parameter (prop, ICAL_PARTSTAT_PARAMETER);
- param = icalparameter_new_partstat (status);
- icalproperty_add_parameter (prop, param);
- } else {
- icalparameter *param;
-
- if (address != NULL) {
- prop = icalproperty_new_attendee (address);
- icalcomponent_add_property (ical_comp, prop);
-
- param = icalparameter_new_role (ICAL_ROLE_OPTPARTICIPANT);
- icalproperty_add_parameter (prop, param);
-
- param = icalparameter_new_partstat (status);
- icalproperty_add_parameter (prop, param);
- } else {
- EAccount *a;
-
- a = itip_addresses_get_default ();
-
- prop = icalproperty_new_attendee (a->id->address);
- icalcomponent_add_property (ical_comp, prop);
-
- param = icalparameter_new_cn (a->id->name);
- icalproperty_add_parameter (prop, param);
-
- param = icalparameter_new_role (ICAL_ROLE_REQPARTICIPANT);
- icalproperty_add_parameter (prop, param);
-
- param = icalparameter_new_partstat (status);
- icalproperty_add_parameter (prop, param);
- }
- }
-
- return TRUE;
-}
-
-static void
-message_foreach_part (CamelMimePart *part, GSList **part_list)
-{
- CamelDataWrapper *containee;
- int parts, i;
- int go = TRUE;
-
- *part_list = g_slist_append (*part_list, part);
-
- containee = camel_medium_get_content_object (CAMEL_MEDIUM (part));
-
- if (containee == NULL)
- return;
-
- /* using the object types is more accurate than using the mime/types */
- if (CAMEL_IS_MULTIPART (containee)) {
- parts = camel_multipart_get_number (CAMEL_MULTIPART (containee));
- for (i = 0; go && i < parts; i++) {
- CamelMimePart *part = camel_multipart_get_part (CAMEL_MULTIPART (containee), i);
-
- message_foreach_part (part, part_list);
- }
- } else if (CAMEL_IS_MIME_MESSAGE (containee)) {
- message_foreach_part ((CamelMimePart *)containee, part_list);
- }
-}
-
-static void
-update_item (FormatItipPObject *pitip, ItipViewResponse response)
-{
- struct icaltimetype stamp;
- icalproperty *prop;
- icalcomponent *clone;
- ECalComponent *clone_comp;
- ESource *source;
- GError *error = NULL;
-
- /* Set X-MICROSOFT-CDO-REPLYTIME to record the time at which
- * the user accepted/declined the request. (Outlook ignores
- * SEQUENCE in REPLY reponses and instead requires that each
- * updated response have a later REPLYTIME than the previous
- * one.) This also ends up getting saved in our own copy of
- * the meeting, though there's currently no way to see that
- * information (unless it's being saved to an Exchange folder
- * and you then look at it in Outlook).
- */
- stamp = icaltime_current_time_with_zone (icaltimezone_get_utc_timezone ());
- prop = icalproperty_new_x (icaltime_as_ical_string (stamp));
- icalproperty_set_x_name (prop, "X-MICROSOFT-CDO-REPLYTIME");
- icalcomponent_add_property (pitip->ical_comp, prop);
-
- clone = icalcomponent_new_clone (pitip->ical_comp);
- icalcomponent_add_component (pitip->top_level, clone);
- icalcomponent_set_method (pitip->top_level, pitip->method);
-
- clone_comp = e_cal_component_new ();
- if (!e_cal_component_set_icalcomponent (clone_comp, clone)) {
- itip_view_add_lower_info_item (ITIP_VIEW (pitip->view), ITIP_VIEW_INFO_ITEM_TYPE_ERROR, _("Unable to parse item"));
- goto cleanup;
- }
- source = e_cal_get_source (pitip->current_ecal);
-
- if ((response != ITIP_VIEW_RESPONSE_CANCEL)
- && (response != ITIP_VIEW_RESPONSE_DECLINE)){
- GSList *attachments = NULL, *new_attachments = NULL, *l;
- CamelMimeMessage *msg = ((EMFormat *) pitip->pobject.format)->message;
-
- e_cal_component_get_attachment_list (clone_comp, &attachments);
- g_message ("Number of attachments is %d", g_slist_length (attachments));
-
- for (l = attachments; l; l = l->next) {
- GSList *parts = NULL, *m;
- char *uri, *new_uri;
- CamelMimePart *part;
-
- uri = l->data;
-
- if (!g_ascii_strncasecmp (uri, "cid:...", 7)) {
- message_foreach_part ((CamelMimePart *) msg, &parts);
-
- for (m = parts; m; m = m->next) {
- part = m->data;
-
- /* Skip the actual message and the text/calendar part */
- /* FIXME Do we need to skip anything else? */
- if (part == (CamelMimePart *) msg || part == pitip->pobject.part)
- continue;
-
- new_uri = em_utils_temp_save_part (NULL, part);
- g_message ("DEBUG: the uri obtained was %s\n", new_uri);
- new_attachments = g_slist_append (new_attachments, new_uri);
- }
-
- g_slist_free (parts);
-
- } else if (!g_ascii_strncasecmp (uri, "cid:", 4)) {
- part = camel_mime_message_get_part_by_content_id (msg, uri);
- new_uri = em_utils_temp_save_part (NULL, part);
- new_attachments = g_slist_append (new_attachments, new_uri);
- } else {
- /* Preserve existing non-cid ones */
- new_attachments = g_slist_append (new_attachments, g_strdup (uri));
- }
- }
-
- e_cal_component_set_attachment_list (clone_comp, new_attachments);
- }
-
- if (!e_cal_receive_objects (pitip->current_ecal, pitip->top_level, &error)) {
- itip_view_add_lower_info_item_printf (ITIP_VIEW (pitip->view), ITIP_VIEW_INFO_ITEM_TYPE_INFO,
- _("Unable to send item to calendar '%s'. %s"),
- e_source_peek_name (source), error->message);
- g_error_free (error);
- } else {
- itip_view_set_source_list (ITIP_VIEW (pitip->view), NULL);
-
- itip_view_clear_lower_info_items (ITIP_VIEW (pitip->view));
-
- switch (response) {
- case ITIP_VIEW_RESPONSE_ACCEPT:
- itip_view_add_lower_info_item_printf (ITIP_VIEW (pitip->view), ITIP_VIEW_INFO_ITEM_TYPE_INFO,
- _("Sent to calendar '%s' as accepted"), e_source_peek_name (source));
- break;
- case ITIP_VIEW_RESPONSE_TENTATIVE:
- itip_view_add_lower_info_item_printf (ITIP_VIEW (pitip->view), ITIP_VIEW_INFO_ITEM_TYPE_INFO,
- _("Sent to calendar '%s' as tentative"), e_source_peek_name (source));
- break;
- case ITIP_VIEW_RESPONSE_DECLINE:
- /* FIXME some calendars just might not save it at all, is this accurate? */
- itip_view_add_lower_info_item_printf (ITIP_VIEW (pitip->view), ITIP_VIEW_INFO_ITEM_TYPE_INFO,
- _("Sent to calendar '%s' as declined"), e_source_peek_name (source));
- break;
- case ITIP_VIEW_RESPONSE_CANCEL:
- /* FIXME some calendars just might not save it at all, is this accurate? */
- itip_view_add_lower_info_item_printf (ITIP_VIEW (pitip->view), ITIP_VIEW_INFO_ITEM_TYPE_INFO,
- _("Sent to calendar '%s' as cancelled"), e_source_peek_name (source));
- break;
- default:
- g_assert_not_reached ();
- break;
- }
-
- /* FIXME Should we hide or desensitize the buttons now? */
- }
-
- cleanup:
- icalcomponent_remove_component (pitip->top_level, clone);
- g_object_unref (clone_comp);
-}
-
-static void
-update_attendee_status (FormatItipPObject *pitip)
-{
- ECalComponent *comp = NULL;
- icalcomponent *icalcomp = NULL;
- const char *uid, *rid;
- GError *error;
-
- /* Obtain our version */
- e_cal_component_get_uid (pitip->comp, &uid);
- rid = e_cal_component_get_recurid_as_string (pitip->comp);
- if (e_cal_get_object (pitip->current_ecal, uid, rid, &icalcomp, NULL)) {
- GSList *attendees;
-
- comp = e_cal_component_new ();
- if (!e_cal_component_set_icalcomponent (comp, icalcomp)) {
- icalcomponent_free (icalcomp);
-
- itip_view_add_lower_info_item (ITIP_VIEW (pitip->view), ITIP_VIEW_INFO_ITEM_TYPE_ERROR, "The meeting is invalid and cannot be updated");
- } else {
- e_cal_component_get_attendee_list (pitip->comp, &attendees);
- if (attendees != NULL) {
- ECalComponentAttendee *a = attendees->data;
- icalproperty *prop;
-
- prop = find_attendee (icalcomp, itip_strip_mailto (a->value));
-
- if (prop == NULL) {
- if (e_error_run (NULL, "org.gnome.itip-formatter:add-unknown-attendee", NULL) == GTK_RESPONSE_YES) {
- change_status (icalcomp, itip_strip_mailto (a->value), a->status);
- e_cal_component_rescan (comp);
- } else {
- goto cleanup;
- }
- } else if (a->status == ICAL_PARTSTAT_NONE || a->status == ICAL_PARTSTAT_X) {
- itip_view_add_lower_info_item (ITIP_VIEW (pitip->view), ITIP_VIEW_INFO_ITEM_TYPE_ERROR,
- _("Attendee status could not be updated because the status is invalid"));
- goto cleanup;
- } else {
- change_status (icalcomp, itip_strip_mailto (a->value), a->status);
- e_cal_component_rescan (comp);
- }
- }
- }
-
- if (!e_cal_modify_object (pitip->current_ecal, icalcomp, rid ? CALOBJ_MOD_THIS : CALOBJ_MOD_ALL, &error)) {
- itip_view_add_lower_info_item_printf (ITIP_VIEW (pitip->view), ITIP_VIEW_INFO_ITEM_TYPE_ERROR,
- _("Unable to update attendee. %s"), error->message);
-
- g_error_free (error);
- } else {
- itip_view_add_lower_info_item (ITIP_VIEW (pitip->view), ITIP_VIEW_INFO_ITEM_TYPE_INFO, _("Attendee status updated"));
- }
- } else {
- itip_view_add_lower_info_item (ITIP_VIEW (pitip->view), ITIP_VIEW_INFO_ITEM_TYPE_WARNING,
- _("Attendee status can not be updated because the item no longer exists"));
- }
-
- cleanup:
- if (comp != NULL)
- g_object_unref (comp);
-}
-
-static void
-send_item (FormatItipPObject *pitip)
-{
- ECalComponent *comp;
-
- comp = get_real_item (pitip);
-
- if (comp != NULL) {
- itip_send_comp (E_CAL_COMPONENT_METHOD_REQUEST, comp, pitip->current_ecal, NULL, NULL);
- g_object_unref (comp);
-
- switch (pitip->type) {
- case E_CAL_SOURCE_TYPE_EVENT:
- itip_view_add_lower_info_item (ITIP_VIEW (pitip->view), ITIP_VIEW_INFO_ITEM_TYPE_INFO, "Meeting information sent");
- break;
- case E_CAL_SOURCE_TYPE_TODO:
- itip_view_add_lower_info_item (ITIP_VIEW (pitip->view), ITIP_VIEW_INFO_ITEM_TYPE_INFO, "Task information sent");
- break;
- case E_CAL_SOURCE_TYPE_JOURNAL:
- itip_view_add_lower_info_item (ITIP_VIEW (pitip->view), ITIP_VIEW_INFO_ITEM_TYPE_INFO, "Journal entry information sent");
- break;
- default:
- g_assert_not_reached ();
- break;
- }
- } else {
- switch (pitip->type) {
- case E_CAL_SOURCE_TYPE_EVENT:
- itip_view_add_lower_info_item (ITIP_VIEW (pitip->view), ITIP_VIEW_INFO_ITEM_TYPE_ERROR, "Unable to send meeting information, the meeting does not exist");
- break;
- case E_CAL_SOURCE_TYPE_TODO:
- itip_view_add_lower_info_item (ITIP_VIEW (pitip->view), ITIP_VIEW_INFO_ITEM_TYPE_ERROR, "Unable to send task information, the task does not exist");
- break;
- case E_CAL_SOURCE_TYPE_JOURNAL:
- itip_view_add_lower_info_item (ITIP_VIEW (pitip->view), ITIP_VIEW_INFO_ITEM_TYPE_ERROR, "Unable to send journal entry information, the journal entry does not exist");
- break;
- default:
- g_assert_not_reached ();
- break;
- }
- }
-}
-
-static icalcomponent *
-get_next (icalcompiter *iter)
-{
- icalcomponent *ret = NULL;
- icalcomponent_kind kind;
-
- do {
- icalcompiter_next (iter);
- ret = icalcompiter_deref (iter);
- if (ret == NULL)
- break;
- kind = icalcomponent_isa (ret);
- } while (ret != NULL
- && kind != ICAL_VEVENT_COMPONENT
- && kind != ICAL_VTODO_COMPONENT
- && kind != ICAL_VFREEBUSY_COMPONENT);
-
- return ret;
-}
-
-static void
-set_itip_error (FormatItipPObject *pitip, GtkContainer *container, const char *primary, const char *secondary)
-{
- GtkWidget *vbox, *label;
- char *message;
-
- vbox = gtk_vbox_new (FALSE, 12);
- gtk_widget_show (vbox);
-
- message = g_strdup_printf ("<b>%s</b>", primary);
- label = gtk_label_new (NULL);
- gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
- gtk_label_set_markup (GTK_LABEL (label), message);
- g_free (message);
- gtk_widget_show (label);
- gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
-
- label = gtk_label_new (secondary);
- gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
- gtk_widget_show (label);
- gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
-
- gtk_container_add (container, vbox);
-}
-
-static gboolean
-extract_itip_data (FormatItipPObject *pitip, GtkContainer *container)
-{
- CamelDataWrapper *content;
- CamelStream *mem;
- icalproperty *prop;
- icalcomponent_kind kind = ICAL_NO_COMPONENT;
- icalcomponent *tz_comp;
- icalcompiter tz_iter;
- icalcomponent *alarm_comp;
- icalcompiter alarm_iter;
-
- content = camel_medium_get_content_object ((CamelMedium *) pitip->pobject.part);
- mem = camel_stream_mem_new ();
- camel_data_wrapper_decode_to_stream (content, mem);
-
- pitip->vcalendar = g_strndup (((CamelStreamMem *) mem)->buffer->data, ((CamelStreamMem *) mem)->buffer->len);
-
- camel_object_unref (mem);
-
- pitip->top_level = e_cal_util_new_top_level ();
-
- pitip->main_comp = icalparser_parse_string (pitip->vcalendar);
- if (pitip->main_comp == NULL) {
- set_itip_error (pitip, container,
- _("The calendar attached is not valid"),
- _("The message claims to contain a calendar, but the calendar is not valid iCalendar."));
-
- return FALSE;
- }
-
- prop = icalcomponent_get_first_property (pitip->main_comp, ICAL_METHOD_PROPERTY);
- if (prop == NULL) {
- pitip->method = ICAL_METHOD_PUBLISH;
- } else {
- pitip->method = icalproperty_get_method (prop);
- }
-
- tz_iter = icalcomponent_begin_component (pitip->main_comp, ICAL_VTIMEZONE_COMPONENT);
- while ((tz_comp = icalcompiter_deref (&tz_iter)) != NULL) {
- icalcomponent *clone;
-
- clone = icalcomponent_new_clone (tz_comp);
- icalcomponent_add_component (pitip->top_level, clone);
-
- icalcompiter_next (&tz_iter);
- }
-
- pitip->iter = icalcomponent_begin_component (pitip->main_comp, ICAL_ANY_COMPONENT);
- pitip->ical_comp = icalcompiter_deref (&pitip->iter);
- if (pitip->ical_comp != NULL) {
- kind = icalcomponent_isa (pitip->ical_comp);
- if (kind != ICAL_VEVENT_COMPONENT
- && kind != ICAL_VTODO_COMPONENT
- && kind != ICAL_VFREEBUSY_COMPONENT)
- pitip->ical_comp = get_next (&pitip->iter);
- }
-
- if (pitip->ical_comp == NULL) {
- set_itip_error (pitip, container,
- _("The item in the calendar is not valid"),
- _("The message does contain a calendar, but the calendar contains no events, tasks or free/busy information"));
-
- return FALSE;
- }
-
- pitip->total = icalcomponent_count_components (pitip->main_comp, ICAL_VEVENT_COMPONENT);
- pitip->total += icalcomponent_count_components (pitip->main_comp, ICAL_VTODO_COMPONENT);
- pitip->total += icalcomponent_count_components (pitip->main_comp, ICAL_VFREEBUSY_COMPONENT);
-
- if (pitip->total > 1) {
- set_itip_error (pitip, container,
- _("The calendar attached contains multiple items"),
- _("To process all of these items, the file should be saved and the calendar imported"));
-
- return FALSE;
- } if (pitip->total > 0) {
- pitip->current = 1;
- } else {
- pitip->current = 0;
- }
-
- /* Determine any delegate sections */
- prop = icalcomponent_get_first_property (pitip->ical_comp, ICAL_X_PROPERTY);
- while (prop) {
- const char *x_name, *x_val;
-
- x_name = icalproperty_get_x_name (prop);
- x_val = icalproperty_get_x (prop);
-
- if (!strcmp (x_name, "X-EVOLUTION-DELEGATOR-CALENDAR-UID"))
- pitip->calendar_uid = g_strdup (x_val);
- else if (!strcmp (x_name, "X-EVOLUTION-DELEGATOR-CALENDAR-URI"))
- g_warning (G_STRLOC ": X-EVOLUTION-DELEGATOR-CALENDAR-URI used");
- else if (!strcmp (x_name, "X-EVOLUTION-DELEGATOR-ADDRESS"))
- pitip->delegator_address = g_strdup (x_val);
- else if (!strcmp (x_name, "X-EVOLUTION-DELEGATOR-NAME"))
- pitip->delegator_name = g_strdup (x_val);
-
- prop = icalcomponent_get_next_property (pitip->ical_comp, ICAL_X_PROPERTY);
- }
-
- /* Strip out alarms for security purposes */
- alarm_iter = icalcomponent_begin_component (pitip->ical_comp, ICAL_VALARM_COMPONENT);
- while ((alarm_comp = icalcompiter_deref (&alarm_iter)) != NULL) {
- icalcomponent_remove_component (pitip->ical_comp, alarm_comp);
-
- icalcompiter_next (&alarm_iter);
- }
-
- pitip->comp = e_cal_component_new ();
- if (!e_cal_component_set_icalcomponent (pitip->comp, pitip->ical_comp)) {
- g_object_unref (pitip->comp);
- pitip->comp = NULL;
-
- set_itip_error (pitip, container,
- _("The item in the calendar is not valid"),
- _("The message does contain a calendar, but the calendar contains no events, tasks or free/busy information"));
-
- return FALSE;
- };
-
- /* Add default reminder if the config says so */
- if (calendar_config_get_use_default_reminder ()) {
- ECalComponentAlarm *acomp;
- int interval;
- CalUnits units;
- ECalComponentAlarmTrigger trigger;
-
- interval = calendar_config_get_default_reminder_interval ();
- units = calendar_config_get_default_reminder_units ();
-
- acomp = e_cal_component_alarm_new ();
-
- e_cal_component_alarm_set_action (acomp, E_CAL_COMPONENT_ALARM_DISPLAY);
-
- trigger.type = E_CAL_COMPONENT_ALARM_TRIGGER_RELATIVE_START;
- memset (&trigger.u.rel_duration, 0, sizeof (trigger.u.rel_duration));
-
- trigger.u.rel_duration.is_neg = TRUE;
-
- switch (units) {
- case CAL_MINUTES:
- trigger.u.rel_duration.minutes = interval;
- break;
- case CAL_HOURS:
- trigger.u.rel_duration.hours = interval;
- break;
- case CAL_DAYS:
- trigger.u.rel_duration.days = interval;
- break;
- default:
- g_assert_not_reached ();
- }
-
- e_cal_component_alarm_set_trigger (acomp, trigger);
- e_cal_component_add_alarm (pitip->comp, acomp);
-
- e_cal_component_alarm_free (acomp);
- }
-
- find_my_address (pitip, pitip->ical_comp, NULL);
-
- return TRUE;
-}
-
-static gboolean
-idle_open_cb (gpointer data)
-{
- FormatItipPObject *pitip = data;
- char *command;
-
- command = g_strdup_printf ("evolution-%s \"calendar://?startdate=%s&enddate=%s\"", BASE_VERSION,
- isodate_from_time_t (pitip->start_time), isodate_from_time_t (pitip->end_time));
- if (!g_spawn_command_line_async (command, NULL)) {
- g_warning ("Could not launch %s", command);
- }
- g_free (command);
-
- return FALSE;
-}
-
-static void
-view_response_cb (GtkWidget *widget, ItipViewResponse response, gpointer data)
-{
- FormatItipPObject *pitip = data;
- gboolean status = FALSE;
-
- if (!pitip->my_address && pitip->current_ecal != NULL)
- e_cal_get_cal_address (pitip->current_ecal, &pitip->my_address, NULL);
-
- switch (response) {
- case ITIP_VIEW_RESPONSE_ACCEPT:
- status = change_status (pitip->ical_comp, pitip->my_address,
- ICAL_PARTSTAT_ACCEPTED);
- if (status) {
- e_cal_component_rescan (pitip->comp);
- update_item (pitip, response);
- }
- break;
- case ITIP_VIEW_RESPONSE_TENTATIVE:
- status = change_status (pitip->ical_comp, pitip->my_address,
- ICAL_PARTSTAT_TENTATIVE);
- if (status) {
- e_cal_component_rescan (pitip->comp);
- update_item (pitip, response);
- }
- break;
- case ITIP_VIEW_RESPONSE_DECLINE:
- status = change_status (pitip->ical_comp, pitip->my_address,
- ICAL_PARTSTAT_DECLINED);
- if (status) {
- e_cal_component_rescan (pitip->comp);
- update_item (pitip, response);
- }
- break;
- case ITIP_VIEW_RESPONSE_UPDATE:
- update_attendee_status (pitip);
- break;
- case ITIP_VIEW_RESPONSE_CANCEL:
- update_item (pitip, response);
- break;
- case ITIP_VIEW_RESPONSE_REFRESH:
- send_item (pitip);
- break;
- case ITIP_VIEW_RESPONSE_OPEN:
- g_idle_add (idle_open_cb, pitip);
- return;
- default:
- break;
- }
-
- if (pitip->delete_message) {
- g_message ("Deleting!");
- camel_folder_delete_message (((EMFormat *) pitip->pobject.format)->folder, ((EMFormat *) pitip->pobject.format)->uid);
- }
-
- if (e_cal_get_save_schedules (pitip->current_ecal))
- return;
-
- if (itip_view_get_rsvp (ITIP_VIEW (pitip->view)) && status) {
- ECalComponent *comp = NULL;
- ECalComponentVType vtype;
- icalcomponent *ical_comp;
- icalproperty *prop;
- icalvalue *value;
- const char *attendee, *comment;
- GSList *l, *list = NULL;
- gboolean found;
-
- comp = e_cal_component_clone (pitip->comp);
- if (comp == NULL)
- return;
-
- vtype = e_cal_component_get_vtype (comp);
-
- if (pitip->my_address == NULL)
- find_my_address (pitip, pitip->ical_comp, NULL);
- g_assert (pitip->my_address != NULL);
-
- ical_comp = e_cal_component_get_icalcomponent (comp);
-
- /* Remove all attendees except the one we are responding as */
- found = FALSE;
- for (prop = icalcomponent_get_first_property (ical_comp, ICAL_ATTENDEE_PROPERTY);
- prop != NULL;
- prop = icalcomponent_get_next_property (ical_comp, ICAL_ATTENDEE_PROPERTY))
- {
- char *text;
-
- value = icalproperty_get_value (prop);
- if (!value)
- continue;
-
- attendee = icalvalue_get_string (value);
-
- text = g_strdup (itip_strip_mailto (attendee));
- text = g_strstrip (text);
-
- /* We do this to ensure there is at most one
- * attendee in the response */
- if (found || g_strcasecmp (pitip->my_address, text))
- list = g_slist_prepend (list, prop);
- else if (!g_strcasecmp (pitip->my_address, text))
- found = TRUE;
- g_free (text);
- }
-
- for (l = list; l; l = l->next) {
- prop = l->data;
- icalcomponent_remove_property (ical_comp, prop);
- icalproperty_free (prop);
- }
- g_slist_free (list);
-
- /* Add a comment if there user set one */
- comment = itip_view_get_rsvp_comment (ITIP_VIEW (pitip->view));
- if (comment) {
- GSList comments;
- ECalComponentText text;
-
- text.value = comment;
- text.altrep = NULL;
-
- comments.data = &text;
- comments.next = NULL;
-
- e_cal_component_set_comment_list (comp, &comments);
- }
-
- e_cal_component_rescan (comp);
- if (itip_send_comp (E_CAL_COMPONENT_METHOD_REPLY, comp, pitip->current_ecal, pitip->top_level, NULL)) {
- camel_folder_set_message_flags (((EMFormat *) pitip->pobject.format)->folder, ((EMFormat *) pitip->pobject.format)->uid,
- CAMEL_MESSAGE_ANSWERED, CAMEL_MESSAGE_ANSWERED);
- }
-
- g_object_unref (comp);
-
- }
-}
-
-static gboolean
-format_itip_object (EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *pobject)
-{
- FormatItipPObject *pitip = (FormatItipPObject *) pobject;
- ECalComponentText text;
- ECalComponentOrganizer organizer;
- ECalComponentDateTime datetime;
- icaltimezone *from_zone, *to_zone;
- GString *gstring = NULL;
- GSList *list, *l;
- const char *string;
- int i;
-
- /* Accounts */
- pitip->accounts = itip_addresses_get ();
-
- /* Source Lists and open ecal clients */
- for (i = 0; i < E_CAL_SOURCE_TYPE_LAST; i++) {
- if (!e_cal_get_sources (&pitip->source_lists[i], i, NULL))
- /* FIXME More error handling? */
- pitip->source_lists[i] = NULL;
-
- /* Initialize the ecal hashes */
- pitip->ecals[i] = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, cleanup_ecal);
- }
-
- /* FIXME Handle multiple VEVENTS with the same UID, ie detached instances */
- if (!extract_itip_data (pitip, GTK_CONTAINER (eb)))
- return TRUE;
-
- pitip->view = itip_view_new ();
- gtk_container_add (GTK_CONTAINER (eb), pitip->view);
- gtk_widget_show (pitip->view);
-
- switch (pitip->method) {
- case ICAL_METHOD_PUBLISH:
- itip_view_set_mode (ITIP_VIEW (pitip->view), ITIP_VIEW_MODE_PUBLISH);
- break;
- case ICAL_METHOD_REQUEST:
- itip_view_set_mode (ITIP_VIEW (pitip->view), ITIP_VIEW_MODE_REQUEST);
- break;
- case ICAL_METHOD_REPLY:
- itip_view_set_mode (ITIP_VIEW (pitip->view), ITIP_VIEW_MODE_REPLY);
- break;
- case ICAL_METHOD_ADD:
- itip_view_set_mode (ITIP_VIEW (pitip->view), ITIP_VIEW_MODE_ADD);
- break;
- case ICAL_METHOD_CANCEL:
- itip_view_set_mode (ITIP_VIEW (pitip->view), ITIP_VIEW_MODE_CANCEL);
- break;
- case ICAL_METHOD_REFRESH:
- itip_view_set_mode (ITIP_VIEW (pitip->view), ITIP_VIEW_MODE_REFRESH);
- break;
- case ICAL_METHOD_COUNTER:
- itip_view_set_mode (ITIP_VIEW (pitip->view), ITIP_VIEW_MODE_COUNTER);
- break;
- case ICAL_METHOD_DECLINECOUNTER:
- itip_view_set_mode (ITIP_VIEW (pitip->view), ITIP_VIEW_MODE_DECLINECOUNTER);
- break;
- default:
- g_assert_not_reached ();
- break;
- }
-
- itip_view_set_item_type (ITIP_VIEW (pitip->view), pitip->type);
-
- switch (pitip->method) {
- case ICAL_METHOD_REQUEST:
- /* FIXME What about the name? */
- itip_view_set_delegator (ITIP_VIEW (pitip->view), pitip->delegator_address);
- case ICAL_METHOD_PUBLISH:
- case ICAL_METHOD_ADD:
- case ICAL_METHOD_CANCEL:
- case ICAL_METHOD_DECLINECOUNTER:
- /* An organizer sent this */
- e_cal_component_get_organizer (pitip->comp, &organizer);
- itip_view_set_organizer (ITIP_VIEW (pitip->view), organizer.cn ? organizer.cn : itip_strip_mailto (organizer.value));
- /* FIXME, do i need to strip the sentby somehow? Maybe with camel? */
- itip_view_set_sentby (ITIP_VIEW (pitip->view), organizer.sentby);
-
- /* FIXME try and match sender with organizer/attendee/sentby?
- pd->from_address = camel_address_encode
- ((CamelAddress *)from); g_message ("Detected from address %s",
- pd->from_address);
- */
- break;
- case ICAL_METHOD_REPLY:
- case ICAL_METHOD_REFRESH:
- case ICAL_METHOD_COUNTER:
- /* An attendee sent this */
- e_cal_component_get_attendee_list (pitip->comp, &list);
- if (list != NULL) {
- ECalComponentAttendee *attendee;
-
- attendee = list->data;
-
- itip_view_set_attendee (ITIP_VIEW (pitip->view), attendee->cn ? attendee->cn : itip_strip_mailto (attendee->value));
-
- e_cal_component_free_attendee_list (list);
- }
- break;
- default:
- g_assert_not_reached ();
- break;
- }
-
- e_cal_component_get_summary (pitip->comp, &text);
- itip_view_set_summary (ITIP_VIEW (pitip->view), text.value ? text.value : _("None"));
-
- e_cal_component_get_location (pitip->comp, &string);
- itip_view_set_location (ITIP_VIEW (pitip->view), string);
-
- /* Status really only applies for REPLY */
- if (pitip->method == ICAL_METHOD_REPLY) {
- e_cal_component_get_attendee_list (pitip->comp, &list);
- if (list != NULL) {
- ECalComponentAttendee *a = list->data;
-
- switch (a->status) {
- case ICAL_PARTSTAT_ACCEPTED:
- itip_view_set_status (ITIP_VIEW (pitip->view), _("Accepted"));
- break;
- case ICAL_PARTSTAT_TENTATIVE:
- itip_view_set_status (ITIP_VIEW (pitip->view), _("Tentatively Accepted"));
- break;
- case ICAL_PARTSTAT_DECLINED:
- itip_view_set_status (ITIP_VIEW (pitip->view), _("Declined"));
- break;
- default:
- itip_view_set_status (ITIP_VIEW (pitip->view), _("Unknown"));
- }
- }
- e_cal_component_free_attendee_list (list);
- }
-
- if (pitip->method == ICAL_METHOD_REPLY
- || pitip->method == ICAL_METHOD_COUNTER
- || pitip->method == ICAL_METHOD_DECLINECOUNTER) {
- /* FIXME Check spec to see if multiple comments are actually valid */
- /* Comments for ITIP are limited to one per object */
- e_cal_component_get_comment_list (pitip->comp, &list);
- if (list) {
- ECalComponentText *text = list->data;
-
- if (text->value)
- itip_view_set_comment (ITIP_VIEW (pitip->view), text->value);
- }
- e_cal_component_free_text_list (list);
- }
-
- e_cal_component_get_description_list (pitip->comp, &list);
- for (l = list; l; l = l->next) {
- ECalComponentText *text = l->data;
-
- if (!gstring && text->value)
- gstring = g_string_new (text->value);
- else if (text->value)
- g_string_append_printf (gstring, "\n\n%s", text->value);
- }
- e_cal_component_free_text_list (list);
-
- if (gstring) {
- itip_view_set_description (ITIP_VIEW (pitip->view), gstring->str);
- g_string_free (gstring, TRUE);
- }
-
- to_zone = calendar_config_get_icaltimezone ();
-
- e_cal_component_get_dtstart (pitip->comp, &datetime);
- pitip->start_time = 0;
- if (datetime.value) {
- struct tm start_tm;
-
- /* If the timezone is not in the component, guess the local time */
- /* Should we guess if the timezone is an olsen name somehow? */
- if (datetime.value->is_utc)
- from_zone = icaltimezone_get_utc_timezone ();
- else if (!datetime.value->is_utc && datetime.tzid)
- from_zone = icalcomponent_get_timezone (pitip->top_level, datetime.tzid);
- else
- from_zone = NULL;
-
- start_tm = icaltimetype_to_tm_with_zone (datetime.value, from_zone, to_zone);
-
- itip_view_set_start (ITIP_VIEW (pitip->view), &start_tm);
- pitip->start_time = icaltime_as_timet_with_zone (*datetime.value, from_zone);
- }
- e_cal_component_free_datetime (&datetime);
-
- e_cal_component_get_dtend (pitip->comp, &datetime);
- pitip->end_time = 0;
- if (datetime.value) {
- struct tm end_tm;
-
- /* If the timezone is not in the component, guess the local time */
- /* Should we guess if the timezone is an olsen name somehow? */
- if (datetime.value->is_utc)
- from_zone = icaltimezone_get_utc_timezone ();
- else if (!datetime.value->is_utc && datetime.tzid)
- from_zone = icalcomponent_get_timezone (pitip->top_level, datetime.tzid);
- else
- from_zone = NULL;
-
- end_tm = icaltimetype_to_tm_with_zone (datetime.value, from_zone, to_zone);
-
- itip_view_set_end (ITIP_VIEW (pitip->view), &end_tm);
- pitip->end_time = icaltime_as_timet_with_zone (*datetime.value, from_zone);
- }
- e_cal_component_free_datetime (&datetime);
-
- /* Recurrence info */
- /* FIXME Better recurring description */
- if (e_cal_component_has_recurrences (pitip->comp)) {
- /* FIXME Tell the user we don't support recurring tasks */
- switch (pitip->type) {
- case E_CAL_SOURCE_TYPE_EVENT:
- itip_view_add_upper_info_item (ITIP_VIEW (pitip->view), ITIP_VIEW_INFO_ITEM_TYPE_INFO, "This meeting recurs");
- break;
- case E_CAL_SOURCE_TYPE_TODO:
- itip_view_add_upper_info_item (ITIP_VIEW (pitip->view), ITIP_VIEW_INFO_ITEM_TYPE_INFO, "This task recurs");
- break;
- case E_CAL_SOURCE_TYPE_JOURNAL:
- itip_view_add_upper_info_item (ITIP_VIEW (pitip->view), ITIP_VIEW_INFO_ITEM_TYPE_INFO, "This journal recurs");
- break;
- default:
- g_assert_not_reached ();
- break;
- }
- }
-
- g_signal_connect (pitip->view, "response", G_CALLBACK (view_response_cb), pitip);
-
- if (pitip->calendar_uid)
- pitip->current_ecal = start_calendar_server_by_uid (pitip, pitip->calendar_uid, pitip->type);
- else
- find_server (pitip, pitip->comp);
-
- return TRUE;
-}
-
-static void
-pitip_free (EMFormatHTMLPObject *pobject)
-{
- FormatItipPObject *pitip = (FormatItipPObject *) pobject;
- int i;
-
- for (i = 0; i < E_CAL_SOURCE_TYPE_LAST; i++) {
- if (pitip->source_lists[i])
- g_object_unref (pitip->source_lists[i]);
- pitip->source_lists[i] = NULL;
-
- g_hash_table_destroy (pitip->ecals[i]);
- pitip->ecals[i] = NULL;
- }
-
- g_free (pitip->vcalendar);
- pitip->vcalendar = NULL;
-
- if (pitip->comp) {
- g_object_unref (pitip->comp);
- pitip->comp = NULL;
- }
-
- if (pitip->top_level) {
- icalcomponent_free (pitip->top_level);
- pitip->top_level = NULL;
- }
-
- if (pitip->main_comp) {
- icalcomponent_free (pitip->main_comp);
- pitip->main_comp = NULL;
- }
- pitip->ical_comp = NULL;
-
- g_free (pitip->calendar_uid);
- pitip->calendar_uid = NULL;
-
- g_free (pitip->from_address);
- pitip->from_address = NULL;
- g_free (pitip->delegator_address);
- pitip->delegator_address = NULL;
- g_free (pitip->delegator_name);
- pitip->delegator_name = NULL;
- g_free (pitip->my_address);
- pitip->my_address = NULL;
-}
-
-void
-format_itip (EPlugin *ep, EMFormatHookTarget *target)
-{
- FormatItipPObject *pitip;
- GConfClient *gconf;
- char *classid;
-
- classid = g_strdup_printf("itip:///%s", ((EMFormat *) target->format)->part_id->str);
-
- pitip = (FormatItipPObject *) em_format_html_add_pobject ((EMFormatHTML *) target->format, sizeof (FormatItipPObject), classid, target->part, format_itip_object);
- pitip->pobject.free = pitip_free;
-
- gconf = gconf_client_get_default ();
- pitip->delete_message = gconf_client_get_bool (gconf, GCONF_KEY_DELETE, NULL);
- g_object_unref (gconf);
-
- camel_stream_printf (target->stream, "<table border=0 width=\"100%%\" cellpadding=3><tr>");
- camel_stream_printf (target->stream, "<td valign=top><object classid=\"%s\"></object></td><td width=100%% valign=top>", classid);
- camel_stream_printf (target->stream, "</td></tr></table>");
-
- g_free (classid);
-}
-
-static void
-delete_toggled_cb (GtkWidget *widget, gpointer data)
-{
- EMConfigTargetPrefs *target = data;
-
- gconf_client_set_bool (target->gconf, GCONF_KEY_DELETE, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)), NULL);
-}
-
-static void
-initialize_selection (ESourceSelector *selector, ESourceList *source_list)
-{
- GSList *groups;
-
- for (groups = e_source_list_peek_groups (source_list); groups; groups = groups->next) {
- ESourceGroup *group = E_SOURCE_GROUP (groups->data);
- GSList *sources;
- for (sources = e_source_group_peek_sources (group); sources; sources = sources->next) {
- ESource *source = E_SOURCE (sources->data);
- const char *completion = e_source_get_property (source, "conflict");
- if (completion && !g_ascii_strcasecmp (completion, "true"))
- e_source_selector_select_source (selector, source);
- }
- }
-}
-
-static void
-source_selection_changed (ESourceSelector *selector, gpointer data)
-{
- ESourceList *source_list = data;
- GSList *selection;
- GSList *l;
- GSList *groups;
-
- /* first we clear all the completion flags from all sources */
- g_message ("Clearing selection");
- for (groups = e_source_list_peek_groups (source_list); groups; groups = groups->next) {
- ESourceGroup *group = E_SOURCE_GROUP (groups->data);
- GSList *sources;
- for (sources = e_source_group_peek_sources (group); sources; sources = sources->next) {
- ESource *source = E_SOURCE (sources->data);
-
- g_message ("Unsetting for %s", e_source_peek_name (source));
- e_source_set_property (source, "conflict", NULL);
- }
- }
-
- /* then we loop over the selector's selection, setting the
- property on those sources */
- selection = e_source_selector_get_selection (selector);
- for (l = selection; l; l = l->next) {
- g_message ("Setting for %s", e_source_peek_name (E_SOURCE (l->data)));
- e_source_set_property (E_SOURCE (l->data), "conflict", "true");
- }
- e_source_selector_free_selection (selection);
-
- /* FIXME show an error if this fails? */
- e_source_list_sync (source_list, NULL);
-}
-
-GtkWidget *
-itip_formatter_page_factory (EPlugin *ep, EConfigHookItemFactoryData *hook_data)
-{
- EMConfigTargetPrefs *target = (EMConfigTargetPrefs *) hook_data->config->target;
- GtkWidget *page;
- GtkWidget *tab_label;
- GtkWidget *frame;
- GtkWidget *frame_label;
- GtkWidget *padding_label;
- GtkWidget *hbox;
- GtkWidget *inner_vbox;
- GtkWidget *check;
- GtkWidget *label;
- GtkWidget *ess;
- GtkWidget *scrolledwin;
- ESourceList *source_list;
-
- /* Create a new notebook page */
- page = gtk_vbox_new (FALSE, 0);
- GTK_CONTAINER (page)->border_width = 12;
- tab_label = gtk_label_new (_("Meetings and Tasks"));
- gtk_notebook_append_page (GTK_NOTEBOOK (hook_data->parent), page, tab_label);
-
- /* Frame */
- frame = gtk_vbox_new (FALSE, 6);
- gtk_box_pack_start (GTK_BOX (page), frame, FALSE, FALSE, 0);
-
- /* "General" */
- frame_label = gtk_label_new ("");
- gtk_label_set_markup (GTK_LABEL (frame_label), _("<span weight=\"bold\">General</span>"));
- GTK_MISC (frame_label)->xalign = 0.0;
- gtk_box_pack_start (GTK_BOX (frame), frame_label, FALSE, FALSE, 0);
-
- /* Indent/padding */
- hbox = gtk_hbox_new (FALSE, 12);
- gtk_box_pack_start (GTK_BOX (frame), hbox, FALSE, TRUE, 0);
- padding_label = gtk_label_new ("");
- gtk_box_pack_start (GTK_BOX (hbox), padding_label, FALSE, FALSE, 0);
- inner_vbox = gtk_vbox_new (FALSE, 6);
- gtk_box_pack_start (GTK_BOX (hbox), inner_vbox, FALSE, FALSE, 0);
-
- /* Delete message after acting */
- /* FIXME Need a schema for this */
- check = gtk_check_button_new_with_mnemonic (_("_Delete message after acting"));
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), gconf_client_get_bool (target->gconf, GCONF_KEY_DELETE, NULL));
- g_signal_connect (GTK_TOGGLE_BUTTON (check), "toggled", G_CALLBACK (delete_toggled_cb), target);
- gtk_box_pack_start (GTK_BOX (inner_vbox), check, FALSE, FALSE, 0);
-
- /* "Conflict searching" */
- frame = gtk_vbox_new (FALSE, 6);
- gtk_box_pack_start (GTK_BOX (page), frame, TRUE, TRUE, 24);
-
- frame_label = gtk_label_new ("");
- gtk_label_set_markup (GTK_LABEL (frame_label), _("<span weight=\"bold\">Conflict Search</span>"));
- GTK_MISC (frame_label)->xalign = 0.0;
- gtk_box_pack_start (GTK_BOX (frame), frame_label, FALSE, FALSE, 0);
-
- /* Indent/padding */
- hbox = gtk_hbox_new (FALSE, 12);
- gtk_box_pack_start (GTK_BOX (frame), hbox, TRUE, TRUE, 0);
- padding_label = gtk_label_new ("");
- gtk_box_pack_start (GTK_BOX (hbox), padding_label, FALSE, FALSE, 0);
- inner_vbox = gtk_vbox_new (FALSE, 6);
- gtk_box_pack_start (GTK_BOX (hbox), inner_vbox, TRUE, TRUE, 0);
-
- /* Source selector */
- label = gtk_label_new (_("Select the calendars to search for meeting conflicts"));
- gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
- gtk_box_pack_start (GTK_BOX (inner_vbox), label, FALSE, FALSE, 0);
-
- if (!e_cal_get_sources (&source_list, E_CAL_SOURCE_TYPE_EVENT, NULL))
- /* FIXME Error handling */;
-
- scrolledwin = gtk_scrolled_window_new (NULL, NULL);
-
- gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwin),
- GTK_POLICY_AUTOMATIC,
- GTK_POLICY_AUTOMATIC);
- gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwin),
- GTK_SHADOW_IN);
- gtk_box_pack_start (GTK_BOX (inner_vbox), scrolledwin, TRUE, TRUE, 0);
-
- ess = e_source_selector_new (source_list);
- gtk_container_add (GTK_CONTAINER (scrolledwin), ess);
-
- initialize_selection (E_SOURCE_SELECTOR (ess), source_list);
-
- g_signal_connect (ess, "selection_changed", G_CALLBACK (source_selection_changed), source_list);
- g_object_weak_ref (G_OBJECT (page), (GWeakNotify) g_object_unref, source_list);
-
- gtk_widget_show_all (page);
-
- return page;
-}
-
diff --git a/plugins/itip-formatter/itip-view.c b/plugins/itip-formatter/itip-view.c
deleted file mode 100644
index 9403e7c4e2..0000000000
--- a/plugins/itip-formatter/itip-view.c
+++ /dev/null
@@ -1,1784 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * Authors: JP Rosevear <jpr@novell.com>
- *
- * Copyright 2004 Novell, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <string.h>
-#include <glib.h>
-#include <gtk/gtk.h>
-#include <libgnome/gnome-i18n.h>
-#include <gconf/gconf-client.h>
-#include <camel/camel-stream.h>
-#include <camel/camel-stream-mem.h>
-#include <camel/camel-medium.h>
-#include <camel/camel-mime-message.h>
-#include <libedataserver/e-time-utils.h>
-#include <libedataserverui/e-source-option-menu.h>
-#include <libecal/e-cal.h>
-#include <gtkhtml/gtkhtml-embedded.h>
-#include <mail/em-format-hook.h>
-#include <mail/em-format-html.h>
-#include <e-util/e-account-list.h>
-#include <e-util/e-icon-factory.h>
-#include <e-util/e-time-utils.h>
-#include <e-util/e-gtk-utils.h>
-#include <calendar/gui/itip-utils.h>
-#include "itip-view.h"
-
-#define MEETING_ICON "stock_new-meeting"
-
-G_DEFINE_TYPE (ItipView, itip_view, GTK_TYPE_HBOX);
-
-typedef struct {
- ItipViewInfoItemType type;
- char *message;
-
- guint id;
-} ItipViewInfoItem;
-
-struct _ItipViewPrivate {
- ItipViewMode mode;
- ECalSourceType type;
-
- GtkWidget *sender_label;
- char *organizer;
- char *sentby;
- char *delegator;
- char *attendee;
-
- GtkWidget *summary_label;
- char *summary;
-
- GtkWidget *location_header;
- GtkWidget *location_label;
- char *location;
-
- GtkWidget *status_header;
- GtkWidget *status_label;
- char *status;
-
- GtkWidget *comment_header;
- GtkWidget *comment_label;
- char *comment;
-
- GtkWidget *start_header;
- GtkWidget *start_label;
- struct tm *start_tm;
-
- GtkWidget *end_header;
- GtkWidget *end_label;
- struct tm *end_tm;
-
- GtkWidget *upper_info_box;
- GSList *upper_info_items;
-
- GtkWidget *lower_info_box;
- GSList *lower_info_items;
-
- guint next_info_item_id;
-
- GtkWidget *description_label;
- char *description;
-
- GtkWidget *selector_box;
- GtkWidget *esom;
- GtkWidget *esom_header;
- ESourceList *source_list;
-
- GtkWidget *rsvp_box;
- GtkWidget *rsvp_check;
- GtkWidget *rsvp_comment_header;
- GtkWidget *rsvp_comment_entry;
- gboolean rsvp_show;
-
- GtkWidget *button_box;
- gboolean buttons_sensitive;
-};
-
-/* Signal IDs */
-enum {
- SOURCE_SELECTED,
- RESPONSE,
- LAST_SIGNAL
-};
-
-static guint signals[LAST_SIGNAL] = { 0 };
-
-static void
-format_date_and_time_x (struct tm *date_tm,
- struct tm *current_tm,
- gboolean use_24_hour_format,
- gboolean show_midnight,
- gboolean show_zero_seconds,
- char *buffer,
- int buffer_size)
-{
- char *format;
- struct tm tomorrow_tm, week_tm;
-
- /* Calculate a normalized "tomorrow" */
- tomorrow_tm = *current_tm;
- if (tomorrow_tm.tm_mday == time_days_in_month (date_tm->tm_year + 1900, date_tm->tm_mon)) {
- tomorrow_tm.tm_mday = 1;
- if (tomorrow_tm.tm_mon == 11) {
- tomorrow_tm.tm_mon = 1;
- tomorrow_tm.tm_year++;
- } else {
- tomorrow_tm.tm_mon++;
- }
- } else {
- tomorrow_tm.tm_mday++;
- }
-
- /* Calculate a normalized "next seven days" */
- week_tm = *current_tm;
- if (week_tm.tm_mday + 6 > time_days_in_month (date_tm->tm_year + 1900, date_tm->tm_mon)) {
- week_tm.tm_mday = (week_tm.tm_mday + 6) % time_days_in_month (date_tm->tm_year + 1900, date_tm->tm_mon);
- if (week_tm.tm_mon == 11) {
- week_tm.tm_mon = 1;
- week_tm.tm_year++;
- } else {
- week_tm.tm_mon++;
- }
- } else {
- week_tm.tm_mday += 6;
- }
-
- /* Today */
- if (date_tm->tm_mday == current_tm->tm_mday &&
- date_tm->tm_mon == current_tm->tm_mon &&
- date_tm->tm_year == current_tm->tm_year) {
- if (!show_midnight && date_tm->tm_hour == 0
- && date_tm->tm_min == 0 && date_tm->tm_sec == 0) {
- /* strftime format of a weekday and a date. */
- format = _("Today");
- } else if (use_24_hour_format) {
- if (!show_zero_seconds && date_tm->tm_sec == 0)
- /* strftime format of a time,
- in 24-hour format, without seconds. */
- format = _("Today %H:%M");
- else
- /* strftime format of a time,
- in 24-hour format. */
- format = _("Today %H:%M:%S");
- } else {
- if (!show_zero_seconds && date_tm->tm_sec == 0)
- /* strftime format of a time,
- in 12-hour format, without seconds. */
- format = _("Today %l:%M %p");
- else
- /* strftime format of a time,
- in 12-hour format. */
- format = _("Today %l:%M:%S %p");
- }
-
- /* Tomorrow */
- } else if (date_tm->tm_mday == tomorrow_tm.tm_mday &&
- date_tm->tm_mon == tomorrow_tm.tm_mon &&
- date_tm->tm_year == tomorrow_tm.tm_year) {
- if (!show_midnight && date_tm->tm_hour == 0
- && date_tm->tm_min == 0 && date_tm->tm_sec == 0) {
- /* strftime format of a weekday and a date. */
- format = _("Tomorrow");
- } else if (use_24_hour_format) {
- if (!show_zero_seconds && date_tm->tm_sec == 0)
- /* strftime format of a time,
- in 24-hour format, without seconds. */
- format = _("Tomorrow %H:%M");
- else
- /* strftime format of a time,
- in 24-hour format. */
- format = _("Tomorrow %H:%M:%S");
- } else {
- if (!show_zero_seconds && date_tm->tm_sec == 0)
- /* strftime format of a time,
- in 12-hour format, without seconds. */
- format = _("Tomorrow %l:%M %p");
- else
- /* strftime format of a time,
- in 12-hour format. */
- format = _("Tomorrow %l:%M:%S %p");
- }
-
- /* Within 6 days */
- } else if ((date_tm->tm_year >= current_tm->tm_year &&
- date_tm->tm_mon >= current_tm->tm_mon &&
- date_tm->tm_mday >= current_tm->tm_mday) &&
-
- (date_tm->tm_year < week_tm.tm_year ||
-
- (date_tm->tm_year == week_tm.tm_year &&
- date_tm->tm_mon < week_tm.tm_mon) ||
-
- (date_tm->tm_year == week_tm.tm_year &&
- date_tm->tm_mon == week_tm.tm_mon &&
- date_tm->tm_mday < week_tm.tm_mday))) {
- if (!show_midnight && date_tm->tm_hour == 0
- && date_tm->tm_min == 0 && date_tm->tm_sec == 0) {
- /* strftime format of a weekday. */
- format = _("%A");
- } else if (use_24_hour_format) {
- if (!show_zero_seconds && date_tm->tm_sec == 0)
- /* strftime format of a weekday and a
- time, in 24-hour format, without seconds. */
- format = _("%A %H:%M");
- else
- /* strftime format of a weekday and a
- time, in 24-hour format. */
- format = _("%A %H:%M:%S");
- } else {
- if (!show_zero_seconds && date_tm->tm_sec == 0)
- /* strftime format of a weekday and a
- time, in 12-hour format, without seconds. */
- format = _("%A %l:%M %p");
- else
- /* strftime format of a weekday and a
- time, in 12-hour format. */
- format = _("%A %l:%M:%S %p");
- }
-
- /* This Year */
- } else if (date_tm->tm_year == current_tm->tm_year) {
- if (!show_midnight && date_tm->tm_hour == 0
- && date_tm->tm_min == 0 && date_tm->tm_sec == 0) {
- /* strftime format of a weekday and a date
- without a year. */
- format = _("%A, %B %e");
- } else if (use_24_hour_format) {
- if (!show_zero_seconds && date_tm->tm_sec == 0)
- /* strftime format of a weekday, a date
- without a year and a time,
- in 24-hour format, without seconds. */
- format = _("%A, %B %e %H:%M");
- else
- /* strftime format of a weekday, a date without a year
- and a time, in 24-hour format. */
- format = _("%A, %B %e %H:%M:%S");
- } else {
- if (!show_zero_seconds && date_tm->tm_sec == 0)
- /* strftime format of a weekday, a date without a year
- and a time, in 12-hour format, without seconds. */
- format = _("%A, %B %e %l:%M %p");
- else
- /* strftime format of a weekday, a date without a year
- and a time, in 12-hour format. */
- format = _("%A, %B %e %l:%M:%S %p");
- }
- } else {
- if (!show_midnight && date_tm->tm_hour == 0
- && date_tm->tm_min == 0 && date_tm->tm_sec == 0) {
- /* strftime format of a weekday and a date. */
- format = _("%A, %B %e, %Y");
- } else if (use_24_hour_format) {
- if (!show_zero_seconds && date_tm->tm_sec == 0)
- /* strftime format of a weekday, a date and a
- time, in 24-hour format, without seconds. */
- format = _("%A, %B %e, %Y %H:%M");
- else
- /* strftime format of a weekday, a date and a
- time, in 24-hour format. */
- format = _("%A, %B %e, %Y %H:%M:%S");
- } else {
- if (!show_zero_seconds && date_tm->tm_sec == 0)
- /* strftime format of a weekday, a date and a
- time, in 12-hour format, without seconds. */
- format = _("%A, %B %e, %Y %l:%M %p");
- else
- /* strftime format of a weekday, a date and a
- time, in 12-hour format. */
- format = _("%A, %B %e, %Y %l:%M:%S %p");
- }
- }
-
- /* strftime returns 0 if the string doesn't fit, and leaves the buffer
- undefined, so we set it to the empty string in that case. */
- if (e_utf8_strftime (buffer, buffer_size, format, date_tm) == 0)
- buffer[0] = '\0';
-}
-
-static void
-set_calendar_sender_text (ItipView *view)
-{
- ItipViewPrivate *priv;
- const char *organizer, *attendee;
- char *sender = NULL;
-
- priv = view->priv;
-
- organizer = priv->organizer ? priv->organizer : _("An unknown person");
- attendee = priv->attendee ? priv->attendee : _("An unknown person");
-
- switch (priv->mode) {
- case ITIP_VIEW_MODE_PUBLISH:
- if (priv->sentby)
- sender = g_strdup_printf (_("<b>%s</b> through %s has published the following meeting information:"), organizer, priv->sentby);
- else
- sender = g_strdup_printf (_("<b>%s</b> has published the following meeting information:"), organizer);
- break;
- case ITIP_VIEW_MODE_REQUEST:
- /* FIXME is the delegator stuff handled correctly here? */
- if (priv->delegator) {
- sender = g_strdup_printf (_("<b>%s</b> requests the presence of %s at the following meeting:"), organizer, priv->delegator);
- } else {
- if (priv->sentby)
- sender = g_strdup_printf (_("<b>%s</b> through %s requests your presence at the following meeting:"), organizer, priv->sentby);
- else
- sender = g_strdup_printf (_("<b>%s</b> requests your presence at the following meeting:"), organizer);
- }
- break;
- case ITIP_VIEW_MODE_ADD:
- /* FIXME What text for this? */
- if (priv->sentby)
- sender = g_strdup_printf (_("<b>%s</b> through %s wishes to add to an existing meeting:"), organizer, priv->sentby);
- else
- sender = g_strdup_printf (_("<b>%s</b> wishes to add to an existing meeting:"), organizer);
- break;
- case ITIP_VIEW_MODE_REFRESH:
- sender = g_strdup_printf (_("<b>%s</b> wishes to receive the latest information for the following meeting:"), attendee);
- break;
- case ITIP_VIEW_MODE_REPLY:
- sender = g_strdup_printf (_("<b>%s</b> has sent back the following meeting response:"), attendee);
- break;
- case ITIP_VIEW_MODE_CANCEL:
- if (priv->sentby)
- sender = g_strdup_printf (_("<b>%s</b> through %s has cancelled the following meeting:"), organizer, priv->sentby);
- else
- sender = g_strdup_printf (_("<b>%s</b> has cancelled the following meeting."), organizer);
- break;
- case ITIP_VIEW_MODE_COUNTER:
- sender = g_strdup_printf (_("<b>%s</b> has proposed the following meeting changes."), attendee);
- break;
- case ITIP_VIEW_MODE_DECLINECOUNTER:
- if (priv->sentby)
- sender = g_strdup_printf (_("<b>%s</b> through %s has declined the following meeting changes:"), organizer, priv->sentby);
- else
- sender = g_strdup_printf (_("<b>%s</b> has declined the following meeting changes."), organizer);
- break;
- default:
- break;
- }
-
- gtk_label_set_text (GTK_LABEL (priv->sender_label), sender);
- gtk_label_set_use_markup (GTK_LABEL (priv->sender_label), TRUE);
-
- g_free (sender);
-}
-
-static void
-set_tasklist_sender_text (ItipView *view)
-{
- ItipViewPrivate *priv;
- const char *organizer, *attendee;
- char *sender = NULL;
-
- priv = view->priv;
-
- organizer = priv->organizer ? priv->organizer : _("An unknown person");
- attendee = priv->attendee ? priv->attendee : _("An unknown person");
-
- switch (priv->mode) {
- case ITIP_VIEW_MODE_PUBLISH:
- if (priv->sentby)
- sender = g_strdup_printf (_("<b>%s</b> through %s has published the following task:"), organizer, priv->sentby);
- else
- sender = g_strdup_printf (_("<b>%s</b> has published the following task:"), organizer);
- break;
- case ITIP_VIEW_MODE_REQUEST:
- /* FIXME is the delegator stuff handled correctly here? */
- if (priv->delegator) {
- sender = g_strdup_printf (_("<b>%s</b> requests the assignment of %s to the following task:"), organizer, priv->delegator);
- } else {
- if (priv->sentby)
- sender = g_strdup_printf (_("<b>%s</b> through %s has assigned you a task:"), organizer, priv->sentby);
- else
- sender = g_strdup_printf (_("<b>%s</b> has assigned you a task:"), organizer);
- }
- break;
- case ITIP_VIEW_MODE_ADD:
- /* FIXME What text for this? */
- if (priv->sentby)
- sender = g_strdup_printf (_("<b>%s</b> through %s wishes to add to an existing task:"), organizer, priv->sentby);
- else
- sender = g_strdup_printf (_("<b>%s</b> wishes to add to an existing task:"), organizer);
- break;
- case ITIP_VIEW_MODE_REFRESH:
- sender = g_strdup_printf (_("<b>%s</b> wishes to receive the latest information for the following assigned task:"), attendee);
- break;
- case ITIP_VIEW_MODE_REPLY:
- sender = g_strdup_printf (_("<b>%s</b> has sent back the following assigned task response:"), attendee);
- break;
- case ITIP_VIEW_MODE_CANCEL:
- if (priv->sentby)
- sender = g_strdup_printf (_("<b>%s</b> through %s has cancelled the following assigned task:"), organizer, priv->sentby);
- else
- sender = g_strdup_printf (_("<b>%s</b> has cancelled the following assigned task:"), organizer);
- break;
- case ITIP_VIEW_MODE_COUNTER:
- sender = g_strdup_printf (_("<b>%s</b> has proposed the following task assignment changes:"), attendee);
- break;
- case ITIP_VIEW_MODE_DECLINECOUNTER:
- if (priv->sentby)
- sender = g_strdup_printf (_("<b>%s</b> through %s has declined the following assigned task:"), organizer, priv->sentby);
- else
- sender = g_strdup_printf (_("<b>%s</b> has declined the following assigned task:"), organizer);
- break;
- default:
- break;
- }
-
- gtk_label_set_text (GTK_LABEL (priv->sender_label), sender);
- gtk_label_set_use_markup (GTK_LABEL (priv->sender_label), TRUE);
-
- g_free (sender);
-}
-
-static void
-set_sender_text (ItipView *view)
-{
- ItipViewPrivate *priv;
-
- priv = view->priv;
-
- switch (priv->type) {
- case E_CAL_SOURCE_TYPE_EVENT:
- set_calendar_sender_text (view);
- break;
- case E_CAL_SOURCE_TYPE_TODO:
- set_tasklist_sender_text (view);
- break;
- default:
- break;
- }
-}
-
-static void
-set_summary_text (ItipView *view)
-{
- ItipViewPrivate *priv;
- char *summary = NULL;
-
- priv = view->priv;
-
- summary = g_strdup_printf ("<b>%s</b>", priv->summary);
-
- gtk_label_set_text (GTK_LABEL (priv->summary_label), summary);
- gtk_label_set_use_markup (GTK_LABEL (priv->summary_label), TRUE);
-
- g_free (summary);
-}
-
-static void
-set_location_text (ItipView *view)
-{
- ItipViewPrivate *priv;
-
- priv = view->priv;
-
- gtk_label_set_text (GTK_LABEL (priv->location_label), priv->location);
-
- priv->location ? gtk_widget_show (priv->location_header) : gtk_widget_hide (priv->location_header);
- priv->location ? gtk_widget_show (priv->location_label) : gtk_widget_hide (priv->location_label);
-}
-
-static void
-set_status_text (ItipView *view)
-{
- ItipViewPrivate *priv;
-
- priv = view->priv;
-
- gtk_label_set_text (GTK_LABEL (priv->status_label), priv->status);
-
- priv->status ? gtk_widget_show (priv->status_header) : gtk_widget_hide (priv->status_header);
- priv->status ? gtk_widget_show (priv->status_label) : gtk_widget_hide (priv->status_label);
-}
-
-static void
-set_comment_text (ItipView *view)
-{
- ItipViewPrivate *priv;
-
- priv = view->priv;
-
- gtk_label_set_text (GTK_LABEL (priv->comment_label), priv->comment);
-
- priv->comment ? gtk_widget_show (priv->comment_header) : gtk_widget_hide (priv->comment_header);
- priv->comment ? gtk_widget_show (priv->comment_label) : gtk_widget_hide (priv->comment_label);
-}
-
-static void
-set_description_text (ItipView *view)
-{
- ItipViewPrivate *priv;
-
- priv = view->priv;
-
- gtk_label_set_text (GTK_LABEL (priv->description_label), priv->description);
-
- priv->description ? gtk_widget_show (priv->description_label) : gtk_widget_hide (priv->description_label);
-}
-
-static void
-set_start_text (ItipView *view)
-{
- ItipViewPrivate *priv;
- char buffer[256];
- time_t now;
- struct tm *now_tm;
-
- priv = view->priv;
-
- now = time (NULL);
- now_tm = localtime (&now);
-
- if (priv->start_tm) {
- format_date_and_time_x (priv->start_tm, now_tm, FALSE, TRUE, FALSE, buffer, 256);
- gtk_label_set_text (GTK_LABEL (priv->start_label), buffer);
- } else {
- gtk_label_set_text (GTK_LABEL (priv->start_label), NULL);
- }
-
- priv->start_tm ? gtk_widget_show (priv->start_header) : gtk_widget_hide (priv->start_header);
- priv->start_tm ? gtk_widget_show (priv->start_label) : gtk_widget_hide (priv->start_label);
-}
-
-static void
-set_end_text (ItipView *view)
-{
- ItipViewPrivate *priv;
- char buffer[256];
- time_t now;
- struct tm *now_tm;
-
- priv = view->priv;
-
- now = time (NULL);
- now_tm = localtime (&now);
-
- if (priv->end_tm) {
- format_date_and_time_x (priv->end_tm, now_tm, FALSE, TRUE, FALSE, buffer, 256);
- gtk_label_set_text (GTK_LABEL (priv->end_label), buffer);
- } else {
- gtk_label_set_text (GTK_LABEL (priv->end_label), NULL);
- }
-
- priv->end_tm ? gtk_widget_show (priv->end_header) : gtk_widget_hide (priv->end_header);
- priv->end_tm ? gtk_widget_show (priv->end_label) : gtk_widget_hide (priv->end_label);
-}
-
-static void
-set_info_items (GtkWidget *info_box, GSList *info_items)
-{
- GSList *l;
-
- gtk_container_foreach (GTK_CONTAINER (info_box), (GtkCallback) gtk_widget_destroy, NULL);
-
- for (l = info_items; l; l = l->next) {
- ItipViewInfoItem *item = l->data;
- GtkWidget *hbox, *image, *label;
-
- hbox = gtk_hbox_new (FALSE, 0);
-
- switch (item->type) {
- case ITIP_VIEW_INFO_ITEM_TYPE_INFO:
- image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_INFO, GTK_ICON_SIZE_SMALL_TOOLBAR);
- break;
- case ITIP_VIEW_INFO_ITEM_TYPE_WARNING:
- image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_SMALL_TOOLBAR);
- break;
- case ITIP_VIEW_INFO_ITEM_TYPE_ERROR:
- image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_ERROR, GTK_ICON_SIZE_SMALL_TOOLBAR);
- break;
- case ITIP_VIEW_INFO_ITEM_TYPE_PROGRESS:
- image = e_icon_factory_get_image ("stock_animation", E_ICON_SIZE_BUTTON);
- break;
- case ITIP_VIEW_INFO_ITEM_TYPE_NONE:
- default:
- image = NULL;
- }
-
- if (image) {
- gtk_widget_show (image);
- gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 6);
- }
-
- label = gtk_label_new (item->message);
- gtk_widget_show (label);
- gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 6);
-
- gtk_widget_show (hbox);
- gtk_box_pack_start (GTK_BOX (info_box), hbox, FALSE, FALSE, 6);
- }
-}
-
-static void
-set_upper_info_items (ItipView *view)
-{
- ItipViewPrivate *priv;
-
- priv = view->priv;
-
- set_info_items (priv->upper_info_box, priv->upper_info_items);
-}
-
-static void
-set_lower_info_items (ItipView *view)
-{
- ItipViewPrivate *priv;
-
- priv = view->priv;
-
- set_info_items (priv->lower_info_box, priv->lower_info_items);
-}
-
-#define DATA_RESPONSE_KEY "ItipView::button_response"
-
-static void
-button_clicked_cb (GtkWidget *widget, gpointer data)
-{
- ItipViewResponse response;
-
- response = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), DATA_RESPONSE_KEY));
-
- g_message ("Response %d", response);
- g_signal_emit (G_OBJECT (data), signals[RESPONSE], 0, response);
-}
-
-static void
-set_one_button (ItipView *view, char *label, char *stock_id, ItipViewResponse response)
-{
- ItipViewPrivate *priv;
- GtkWidget *button;
-
- priv = view->priv;
-
- button = e_gtk_button_new_with_icon (label, stock_id);
- g_object_set_data (G_OBJECT (button), DATA_RESPONSE_KEY, GINT_TO_POINTER (response));
- gtk_widget_show (button);
- gtk_container_add (GTK_CONTAINER (priv->button_box), button);
-
- g_signal_connect (button, "clicked", G_CALLBACK (button_clicked_cb), view);
-}
-
-static void
-set_buttons (ItipView *view)
-{
- ItipViewPrivate *priv;
-
- priv = view->priv;
-
- gtk_container_foreach (GTK_CONTAINER (priv->button_box), (GtkCallback) gtk_widget_destroy, NULL);
-
- /* Everything gets the open button */
- set_one_button (view, "_Open Calendar", GTK_STOCK_JUMP_TO, ITIP_VIEW_RESPONSE_OPEN);
-
- switch (priv->mode) {
- case ITIP_VIEW_MODE_PUBLISH:
- /* FIXME Is this really the right button? */
- set_one_button (view, "_Accept", GTK_STOCK_APPLY, ITIP_VIEW_RESPONSE_ACCEPT);
- break;
- case ITIP_VIEW_MODE_REQUEST:
- set_one_button (view, "_Decline", GTK_STOCK_CANCEL, ITIP_VIEW_RESPONSE_DECLINE);
- set_one_button (view, "_Tentative", GTK_STOCK_DIALOG_QUESTION, ITIP_VIEW_RESPONSE_TENTATIVE);
- set_one_button (view, "_Accept", GTK_STOCK_APPLY, ITIP_VIEW_RESPONSE_ACCEPT);
- break;
- case ITIP_VIEW_MODE_ADD:
- set_one_button (view, "_Decline", GTK_STOCK_CANCEL, ITIP_VIEW_RESPONSE_DECLINE);
- set_one_button (view, "_Tentative", GTK_STOCK_DIALOG_QUESTION, ITIP_VIEW_RESPONSE_TENTATIVE);
- set_one_button (view, "_Accept", GTK_STOCK_APPLY, ITIP_VIEW_RESPONSE_ACCEPT);
- break;
- case ITIP_VIEW_MODE_REFRESH:
- /* FIXME Is this really the right button? */
- set_one_button (view, "_Send Information", GTK_STOCK_REFRESH, ITIP_VIEW_RESPONSE_REFRESH);
- break;
- case ITIP_VIEW_MODE_REPLY:
- /* FIXME Is this really the right button? */
- set_one_button (view, "_Update Attendee Status", GTK_STOCK_REFRESH, ITIP_VIEW_RESPONSE_UPDATE);
- break;
- case ITIP_VIEW_MODE_CANCEL:
- set_one_button (view, "_Update", GTK_STOCK_REFRESH, ITIP_VIEW_RESPONSE_CANCEL);
- break;
- case ITIP_VIEW_MODE_COUNTER:
- set_one_button (view, "_Decline", GTK_STOCK_CANCEL, ITIP_VIEW_RESPONSE_DECLINE);
- set_one_button (view, "_Tentative", GTK_STOCK_DIALOG_QUESTION, ITIP_VIEW_RESPONSE_TENTATIVE);
- set_one_button (view, "_Accept", GTK_STOCK_APPLY, ITIP_VIEW_RESPONSE_ACCEPT);
- break;
- case ITIP_VIEW_MODE_DECLINECOUNTER:
- set_one_button (view, "_Decline", GTK_STOCK_CANCEL, ITIP_VIEW_RESPONSE_DECLINE);
- set_one_button (view, "_Tentative", GTK_STOCK_DIALOG_QUESTION, ITIP_VIEW_RESPONSE_TENTATIVE);
- set_one_button (view, "_Accept", GTK_STOCK_APPLY, ITIP_VIEW_RESPONSE_ACCEPT);
- break;
- default:
- break;
- }
-}
-
-static void
-itip_view_destroy (GtkObject *object)
-{
- ItipView *view = ITIP_VIEW (object);
- ItipViewPrivate *priv = view->priv;
-
- if (priv) {
- g_free (priv->organizer);
- g_free (priv->sentby);
- g_free (priv->delegator);
- g_free (priv->attendee);
- g_free (priv->location);
- g_free (priv->status);
- g_free (priv->comment);
- g_free (priv->start_tm);
- g_free (priv->end_tm);
-
- itip_view_clear_upper_info_items (view);
- itip_view_clear_lower_info_items (view);
-
- g_free (priv);
- view->priv = NULL;
- }
-
- GTK_OBJECT_CLASS (itip_view_parent_class)->destroy (object);
-}
-
-static void
-itip_view_class_init (ItipViewClass *klass)
-{
- GObjectClass *object_class;
- GtkObjectClass *gtkobject_class;
-
- object_class = G_OBJECT_CLASS (klass);
- gtkobject_class = GTK_OBJECT_CLASS (klass);
-
- gtkobject_class->destroy = itip_view_destroy;
-
- signals[SOURCE_SELECTED] =
- g_signal_new ("source_selected",
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ItipViewClass, source_selected),
- NULL, NULL,
- gtk_marshal_NONE__POINTER,
- G_TYPE_NONE, 1, G_TYPE_POINTER);
-
- signals[RESPONSE] =
- g_signal_new ("response",
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ItipViewClass, response),
- NULL, NULL,
- gtk_marshal_NONE__INT,
- G_TYPE_NONE, 1, G_TYPE_INT);
-}
-
-static void
-rsvp_toggled_cb (GtkWidget *widget, gpointer data)
-{
- ItipView *view = data;
- ItipViewPrivate *priv;
- gboolean rsvp;
-
- priv = view->priv;
-
- rsvp = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->rsvp_check));
-
- gtk_widget_set_sensitive (priv->rsvp_comment_header, rsvp);
- gtk_widget_set_sensitive (priv->rsvp_comment_entry, rsvp);
-}
-
-static void
-itip_view_init (ItipView *view)
-{
- ItipViewPrivate *priv;
- GtkWidget *icon, *vbox, *hbox, *separator, *table, *label;
-
- priv = g_new0 (ItipViewPrivate, 1);
- view->priv = priv;
-
- priv->mode = ITIP_VIEW_MODE_NONE;
-
- gtk_box_set_spacing (GTK_BOX (view), 12);
-
- /* The meeting icon */
- icon = e_icon_factory_get_image (MEETING_ICON, E_ICON_SIZE_LARGE_TOOLBAR);
- gtk_misc_set_alignment (GTK_MISC (icon), 0.5, 0);
- gtk_widget_show (icon);
-
- gtk_box_pack_start (GTK_BOX (view), icon, FALSE, FALSE, 0);
-
- /* The RHS */
- vbox = gtk_vbox_new (FALSE, 12);
- gtk_widget_show (vbox);
- gtk_box_pack_start (GTK_BOX (view), vbox, FALSE, FALSE, 0);
-
- /* The first section listing the sender */
- /* FIXME What to do if the send and organizer do not match */
- priv->sender_label = gtk_label_new (NULL);
- gtk_misc_set_alignment (GTK_MISC (priv->sender_label), 0, 0.5);
- gtk_widget_show (priv->sender_label);
- gtk_box_pack_start (GTK_BOX (vbox), priv->sender_label, FALSE, FALSE, 0);
-
- separator = gtk_hseparator_new ();
- gtk_widget_show (separator);
- gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, 0);
-
- /* A table with information on the meeting and any extra info/warnings */
- table = gtk_table_new (4, 2, FALSE);
- gtk_table_set_row_spacings (GTK_TABLE (table), 6);
- gtk_table_set_col_spacings (GTK_TABLE (table), 6);
- gtk_widget_show (table);
- gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
-
- /* Summary */
- priv->summary_label = gtk_label_new (NULL);
- gtk_misc_set_alignment (GTK_MISC (priv->summary_label), 0, 0.5);
- gtk_widget_show (priv->summary_label);
- gtk_table_attach (GTK_TABLE (table), priv->summary_label, 0, 2, 0, 1, GTK_FILL, 0, 0, 0);
-
- /* Location */
- priv->location_header = gtk_label_new (_("Location:"));
- priv->location_label = gtk_label_new (NULL);
- gtk_misc_set_alignment (GTK_MISC (priv->location_header), 0, 0.5);
- gtk_misc_set_alignment (GTK_MISC (priv->location_label), 0, 0.5);
- gtk_table_attach (GTK_TABLE (table), priv->location_header, 0, 1, 1, 2, GTK_FILL, 0, 0, 0);
- gtk_table_attach (GTK_TABLE (table), priv->location_label, 1, 2, 1, 2, GTK_FILL, 0, 0, 0);
-
- /* Start time */
- priv->start_header = gtk_label_new (_("Start time:"));
- priv->start_label = gtk_label_new (NULL);
- gtk_misc_set_alignment (GTK_MISC (priv->start_header), 0, 0.5);
- gtk_misc_set_alignment (GTK_MISC (priv->start_label), 0, 0.5);
- gtk_widget_show (priv->start_header);
- gtk_table_attach (GTK_TABLE (table), priv->start_header, 0, 1, 2, 3, GTK_FILL, 0, 0, 0);
- gtk_table_attach (GTK_TABLE (table), priv->start_label, 1, 2, 2, 3, GTK_FILL, 0, 0, 0);
-
- /* End time */
- priv->end_header = gtk_label_new (_("End time:"));
- priv->end_label = gtk_label_new (NULL);
- gtk_misc_set_alignment (GTK_MISC (priv->end_header), 0, 0.5);
- gtk_misc_set_alignment (GTK_MISC (priv->end_label), 0, 0.5);
- gtk_table_attach (GTK_TABLE (table), priv->end_header, 0, 1, 3, 4, GTK_FILL, 0, 0, 0);
- gtk_table_attach (GTK_TABLE (table), priv->end_label, 1, 2, 3, 4, GTK_FILL, 0, 0, 0);
-
- /* Status */
- priv->status_header = gtk_label_new (_("Status:"));
- priv->status_label = gtk_label_new (NULL);
- gtk_misc_set_alignment (GTK_MISC (priv->status_header), 0, 0.5);
- gtk_misc_set_alignment (GTK_MISC (priv->status_label), 0, 0.5);
- gtk_table_attach (GTK_TABLE (table), priv->status_header, 0, 1, 4, 5, GTK_FILL, 0, 0, 0);
- gtk_table_attach (GTK_TABLE (table), priv->status_label, 1, 2, 4, 5, GTK_FILL, 0, 0, 0);
-
- /* Comment */
- priv->comment_header = gtk_label_new (_("Comment:"));
- priv->comment_label = gtk_label_new (NULL);
- gtk_misc_set_alignment (GTK_MISC (priv->comment_header), 0, 0.5);
- gtk_misc_set_alignment (GTK_MISC (priv->comment_label), 0, 0.5);
- gtk_table_attach (GTK_TABLE (table), priv->comment_header, 0, 1, 5, 6, GTK_FILL, 0, 0, 0);
- gtk_table_attach (GTK_TABLE (table), priv->comment_label, 1, 2, 5, 6, GTK_FILL, 0, 0, 0);
-
- /* Upper Info items */
- priv->upper_info_box = gtk_vbox_new (FALSE, 12);
- gtk_widget_show (priv->upper_info_box);
- gtk_box_pack_start (GTK_BOX (vbox), priv->upper_info_box, FALSE, FALSE, 0);
-
- /* Description */
- priv->description_label = gtk_label_new (NULL);
- gtk_label_set_line_wrap (GTK_LABEL (priv->description_label), TRUE);
- gtk_misc_set_alignment (GTK_MISC (priv->description_label), 0, 0.5);
-// gtk_box_pack_start (GTK_BOX (vbox), priv->description_label, FALSE, FALSE, 0);
-
- separator = gtk_hseparator_new ();
- gtk_widget_show (separator);
- gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, 0);
-
- /* Lower Info items */
- priv->lower_info_box = gtk_vbox_new (FALSE, 12);
- gtk_widget_show (priv->lower_info_box);
- gtk_box_pack_start (GTK_BOX (vbox), priv->lower_info_box, FALSE, FALSE, 0);
-
- /* Selector area */
- priv->selector_box = gtk_hbox_new (FALSE, 12);
- gtk_widget_show (priv->selector_box);
- gtk_box_pack_start (GTK_BOX (vbox), priv->selector_box, FALSE, FALSE, 0);
-
- /* RSVP area */
- priv->rsvp_box = gtk_vbox_new (FALSE, 12);
- gtk_box_pack_start (GTK_BOX (vbox), priv->rsvp_box, FALSE, FALSE, 0);
-
- priv->rsvp_check = gtk_check_button_new_with_mnemonic ("Send _reply to sender");
- gtk_widget_show (priv->rsvp_check);
- gtk_box_pack_start (GTK_BOX (priv->rsvp_box), priv->rsvp_check, FALSE, FALSE, 0);
-
- g_signal_connect (priv->rsvp_check, "toggled", G_CALLBACK (rsvp_toggled_cb), view);
-
- hbox = gtk_hbox_new (FALSE, 12);
- gtk_widget_show (hbox);
- gtk_box_pack_start (GTK_BOX (priv->rsvp_box), hbox, FALSE, FALSE, 0);
-
- label = gtk_label_new (NULL);
- gtk_widget_show (label);
- gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
-
- priv->rsvp_comment_header = gtk_label_new (_("Comment:"));
- gtk_widget_set_sensitive (priv->rsvp_comment_header, FALSE);
- gtk_widget_show (priv->rsvp_comment_header);
- gtk_box_pack_start (GTK_BOX (hbox), priv->rsvp_comment_header, FALSE, FALSE, 0);
-
- priv->rsvp_comment_entry = gtk_entry_new ();
- gtk_widget_set_sensitive (priv->rsvp_comment_entry, FALSE);
- gtk_widget_show (priv->rsvp_comment_entry);
- gtk_box_pack_start (GTK_BOX (hbox), priv->rsvp_comment_entry, FALSE, TRUE, 0);
-
- /* The buttons for actions */
- priv->button_box = gtk_hbutton_box_new ();
- gtk_button_box_set_layout (GTK_BUTTON_BOX (priv->button_box), GTK_BUTTONBOX_END);
- gtk_box_set_spacing (GTK_BOX (priv->button_box), 12);
- gtk_widget_show (priv->button_box);
- gtk_box_pack_start (GTK_BOX (vbox), priv->button_box, FALSE, FALSE, 0);
-
- priv->buttons_sensitive = TRUE;
-}
-
-GtkWidget *
-itip_view_new (void)
-{
- ItipView *itip_view = g_object_new (ITIP_TYPE_VIEW, "homogeneous", FALSE, "spacing", 6, NULL);
-
- return GTK_WIDGET (itip_view);
-}
-
-void
-itip_view_set_mode (ItipView *view, ItipViewMode mode)
-{
- ItipViewPrivate *priv;
-
- g_return_if_fail (view != NULL);
- g_return_if_fail (ITIP_IS_VIEW (view));
-
- priv = view->priv;
-
- priv->mode = mode;
-
- set_sender_text (view);
- set_buttons (view);
-}
-
-ItipViewMode
-itip_view_get_mode (ItipView *view)
-{
- ItipViewPrivate *priv;
-
- g_return_val_if_fail (view != NULL, ITIP_VIEW_MODE_NONE);
- g_return_val_if_fail (ITIP_IS_VIEW (view), ITIP_VIEW_MODE_NONE);
-
- priv = view->priv;
-
- return priv->mode;
-}
-
-void
-itip_view_set_item_type (ItipView *view, ECalSourceType type)
-{
- ItipViewPrivate *priv;
-
- g_return_if_fail (view != NULL);
- g_return_if_fail (ITIP_IS_VIEW (view));
-
- priv = view->priv;
-
- priv->type = type;
-
- set_sender_text (view);
-}
-
-ECalSourceType
-itip_view_get_item_type (ItipView *view)
-{
- ItipViewPrivate *priv;
-
- g_return_val_if_fail (view != NULL, ITIP_VIEW_MODE_NONE);
- g_return_val_if_fail (ITIP_IS_VIEW (view), ITIP_VIEW_MODE_NONE);
-
- priv = view->priv;
-
- return priv->type;
-}
-
-
-void
-itip_view_set_organizer (ItipView *view, const char *organizer)
-{
- ItipViewPrivate *priv;
-
- g_return_if_fail (view != NULL);
- g_return_if_fail (ITIP_IS_VIEW (view));
-
- priv = view->priv;
-
- if (priv->organizer)
- g_free (priv->organizer);
-
- priv->organizer = g_strdup (organizer);
-
- set_sender_text (view);
-}
-
-const char *
-itip_view_get_organizer (ItipView *view)
-{
- ItipViewPrivate *priv;
-
- g_return_val_if_fail (view != NULL, NULL);
- g_return_val_if_fail (ITIP_IS_VIEW (view), NULL);
-
- priv = view->priv;
-
- return priv->organizer;
-}
-
-void
-itip_view_set_sentby (ItipView *view, const char *sentby)
-{
- ItipViewPrivate *priv;
-
- g_return_if_fail (view != NULL);
- g_return_if_fail (ITIP_IS_VIEW (view));
-
- priv = view->priv;
-
- if (priv->sentby)
- g_free (priv->sentby);
-
- priv->sentby = g_strdup (sentby);
-
- set_sender_text (view);
-}
-
-const char *
-itip_view_get_sentby (ItipView *view)
-{
- ItipViewPrivate *priv;
-
- g_return_val_if_fail (view != NULL, NULL);
- g_return_val_if_fail (ITIP_IS_VIEW (view), NULL);
-
- priv = view->priv;
-
- return priv->sentby;
-}
-
-void
-itip_view_set_attendee (ItipView *view, const char *attendee)
-{
- ItipViewPrivate *priv;
-
- g_return_if_fail (view != NULL);
- g_return_if_fail (ITIP_IS_VIEW (view));
-
- priv = view->priv;
-
- if (priv->attendee)
- g_free (priv->attendee);
-
- priv->attendee = g_strdup (attendee);
-
- set_sender_text (view);
-}
-
-const char *
-itip_view_get_attendee (ItipView *view)
-{
- ItipViewPrivate *priv;
-
- g_return_val_if_fail (view != NULL, NULL);
- g_return_val_if_fail (ITIP_IS_VIEW (view), NULL);
-
- priv = view->priv;
-
- return priv->attendee;
-}
-
-void
-itip_view_set_delegator (ItipView *view, const char *delegator)
-{
- ItipViewPrivate *priv;
-
- g_return_if_fail (view != NULL);
- g_return_if_fail (ITIP_IS_VIEW (view));
-
- priv = view->priv;
-
- if (priv->delegator)
- g_free (priv->delegator);
-
- priv->delegator = g_strdup (delegator);
-
- set_sender_text (view);
-}
-
-const char *
-itip_view_get_delegator (ItipView *view)
-{
- ItipViewPrivate *priv;
-
- g_return_val_if_fail (view != NULL, NULL);
- g_return_val_if_fail (ITIP_IS_VIEW (view), NULL);
-
- priv = view->priv;
-
- return priv->delegator;
-}
-
-void
-itip_view_set_summary (ItipView *view, const char *summary)
-{
- ItipViewPrivate *priv;
-
- g_return_if_fail (view != NULL);
- g_return_if_fail (ITIP_IS_VIEW (view));
-
- priv = view->priv;
-
- if (priv->summary)
- g_free (priv->summary);
-
- priv->summary = summary ? g_strstrip (g_strdup (summary)) : NULL;
-
- set_summary_text (view);
-}
-
-const char *
-itip_view_get_summary (ItipView *view)
-{
- ItipViewPrivate *priv;
-
- g_return_val_if_fail (view != NULL, NULL);
- g_return_val_if_fail (ITIP_IS_VIEW (view), NULL);
-
- priv = view->priv;
-
- return priv->summary;
-}
-
-void
-itip_view_set_location (ItipView *view, const char *location)
-{
- ItipViewPrivate *priv;
-
- g_return_if_fail (view != NULL);
- g_return_if_fail (ITIP_IS_VIEW (view));
-
- priv = view->priv;
-
- if (priv->location)
- g_free (priv->location);
-
- priv->location = location ? g_strstrip (g_strdup (location)) : NULL;
-
- set_location_text (view);
-}
-
-const char *
-itip_view_get_location (ItipView *view)
-{
- ItipViewPrivate *priv;
-
- g_return_val_if_fail (view != NULL, NULL);
- g_return_val_if_fail (ITIP_IS_VIEW (view), NULL);
-
- priv = view->priv;
-
- return priv->location;
-}
-
-void
-itip_view_set_status (ItipView *view, const char *status)
-{
- ItipViewPrivate *priv;
-
- g_return_if_fail (view != NULL);
- g_return_if_fail (ITIP_IS_VIEW (view));
-
- priv = view->priv;
-
- if (priv->status)
- g_free (priv->status);
-
- priv->status = status ? g_strstrip (g_strdup (status)) : NULL;
-
- set_status_text (view);
-}
-
-const char *
-itip_view_get_status (ItipView *view)
-{
- ItipViewPrivate *priv;
-
- g_return_val_if_fail (view != NULL, NULL);
- g_return_val_if_fail (ITIP_IS_VIEW (view), NULL);
-
- priv = view->priv;
-
- return priv->status;
-}
-
-void
-itip_view_set_comment (ItipView *view, const char *comment)
-{
- ItipViewPrivate *priv;
-
- g_return_if_fail (view != NULL);
- g_return_if_fail (ITIP_IS_VIEW (view));
-
- priv = view->priv;
-
- if (priv->comment)
- g_free (priv->comment);
-
- priv->comment = comment ? g_strstrip (g_strdup (comment)) : NULL;
-
- set_comment_text (view);
-}
-
-const char *
-itip_view_get_comment (ItipView *view)
-{
- ItipViewPrivate *priv;
-
- g_return_val_if_fail (view != NULL, NULL);
- g_return_val_if_fail (ITIP_IS_VIEW (view), NULL);
-
- priv = view->priv;
-
- return priv->comment;
-}
-
-
-void
-itip_view_set_description (ItipView *view, const char *description)
-{
- ItipViewPrivate *priv;
-
- g_return_if_fail (view != NULL);
- g_return_if_fail (ITIP_IS_VIEW (view));
-
- priv = view->priv;
-
- if (priv->description)
- g_free (priv->description);
-
- priv->description = description ? g_strstrip (g_strdup (description)) : NULL;
-
- set_description_text (view);
-}
-
-const char *
-itip_view_get_description (ItipView *view)
-{
- ItipViewPrivate *priv;
-
- g_return_val_if_fail (view != NULL, NULL);
- g_return_val_if_fail (ITIP_IS_VIEW (view), NULL);
-
- priv = view->priv;
-
- return priv->description;
-}
-
-
-void
-itip_view_set_start (ItipView *view, struct tm *start)
-{
- ItipViewPrivate *priv;
-
- g_return_if_fail (view != NULL);
- g_return_if_fail (ITIP_IS_VIEW (view));
-
- priv = view->priv;
-
- if (priv->start_tm && !start) {
- g_free (priv->start_tm);
- priv->start_tm = NULL;
- } else if (start) {
- if (!priv->start_tm)
- priv->start_tm = g_new0 (struct tm, 1);
-
- *priv->start_tm = *start;
- }
-
- set_start_text (view);
-}
-
-const struct tm *
-itip_view_get_start (ItipView *view)
-{
- ItipViewPrivate *priv;
-
- g_return_val_if_fail (view != NULL, NULL);
- g_return_val_if_fail (ITIP_IS_VIEW (view), NULL);
-
- priv = view->priv;
-
- return priv->start_tm;
-}
-
-void
-itip_view_set_end (ItipView *view, struct tm *end)
-{
- ItipViewPrivate *priv;
-
- g_return_if_fail (view != NULL);
- g_return_if_fail (ITIP_IS_VIEW (view));
-
- priv = view->priv;
-
- if (priv->end_tm && !end) {
- g_free (priv->end_tm);
- priv->end_tm = NULL;
- } else if (end) {
- if (!priv->end_tm)
- priv->end_tm = g_new0 (struct tm, 1);
-
- *priv->end_tm = *end;
- }
-
- set_end_text (view);
-}
-
-const struct tm *
-itip_view_get_end (ItipView *view)
-{
- ItipViewPrivate *priv;
-
- g_return_val_if_fail (view != NULL, NULL);
- g_return_val_if_fail (ITIP_IS_VIEW (view), NULL);
-
- priv = view->priv;
-
- return priv->end_tm;
-}
-
-guint
-itip_view_add_upper_info_item (ItipView *view, ItipViewInfoItemType type, const char *message)
-{
- ItipViewPrivate *priv;
- ItipViewInfoItem *item;
-
- g_return_val_if_fail (view != NULL, 0);
- g_return_val_if_fail (ITIP_IS_VIEW (view), 0);
-
- priv = view->priv;
-
- item = g_new0 (ItipViewInfoItem, 1);
-
- item->type = type;
- item->message = g_strdup (message);
- item->id = priv->next_info_item_id++;
-
- priv->upper_info_items = g_slist_append (priv->upper_info_items, item);
-
- set_upper_info_items (view);
-
- return item->id;
-}
-
-guint
-itip_view_add_upper_info_item_printf (ItipView *view, ItipViewInfoItemType type, const char *format, ...)
-{
- ItipViewPrivate *priv;
- va_list args;
- char *message;
- guint id;
-
- g_return_val_if_fail (view != NULL, 0);
- g_return_val_if_fail (ITIP_IS_VIEW (view), 0);
-
- priv = view->priv;
-
- va_start (args, format);
- message = g_strdup_vprintf (format, args);
- va_end (args);
-
- id = itip_view_add_upper_info_item (view, type, message);
- g_free (message);
-
- return id;
-}
-
-void
-itip_view_remove_upper_info_item (ItipView *view, guint id)
-{
- ItipViewPrivate *priv;
- GSList *l;
-
- g_return_if_fail (view != NULL);
- g_return_if_fail (ITIP_IS_VIEW (view));
-
- priv = view->priv;
-
- for (l = priv->upper_info_items; l; l = l->next) {
- ItipViewInfoItem *item = l->data;
-
- if (item->id == id) {
- priv->upper_info_items = g_slist_remove (priv->upper_info_items, item);
-
- g_free (item->message);
- g_free (item);
-
- set_upper_info_items (view);
-
- return;
- }
- }
-}
-
-void
-itip_view_clear_upper_info_items (ItipView *view)
-{
- ItipViewPrivate *priv;
- GSList *l;
-
- g_return_if_fail (view != NULL);
- g_return_if_fail (ITIP_IS_VIEW (view));
-
- priv = view->priv;
-
- gtk_container_foreach (GTK_CONTAINER (priv->upper_info_box), (GtkCallback) gtk_widget_destroy, NULL);
-
- for (l = priv->upper_info_items; l; l = l->next) {
- ItipViewInfoItem *item = l->data;
-
- g_free (item->message);
- g_free (item);
- }
-
- g_slist_free (priv->upper_info_items);
- priv->upper_info_items = NULL;
-}
-
-guint
-itip_view_add_lower_info_item (ItipView *view, ItipViewInfoItemType type, const char *message)
-{
- ItipViewPrivate *priv;
- ItipViewInfoItem *item;
-
- g_return_val_if_fail (view != NULL, 0);
- g_return_val_if_fail (ITIP_IS_VIEW (view), 0);
-
- priv = view->priv;
-
- item = g_new0 (ItipViewInfoItem, 1);
-
- item->type = type;
- item->message = g_strdup (message);
- item->id = priv->next_info_item_id++;
-
- priv->lower_info_items = g_slist_append (priv->lower_info_items, item);
-
- set_lower_info_items (view);
-
- return item->id;
-}
-
-guint
-itip_view_add_lower_info_item_printf (ItipView *view, ItipViewInfoItemType type, const char *format, ...)
-{
- ItipViewPrivate *priv;
- va_list args;
- char *message;
- guint id;
-
- g_return_val_if_fail (view != NULL, 0);
- g_return_val_if_fail (ITIP_IS_VIEW (view), 0);
-
- priv = view->priv;
-
- va_start (args, format);
- message = g_strdup_vprintf (format, args);
- va_end (args);
-
- id = itip_view_add_lower_info_item (view, type, message);
- g_free (message);
-
- return id;
-}
-
-void
-itip_view_remove_lower_info_item (ItipView *view, guint id)
-{
- ItipViewPrivate *priv;
- GSList *l;
-
- g_return_if_fail (view != NULL);
- g_return_if_fail (ITIP_IS_VIEW (view));
-
- priv = view->priv;
-
- for (l = priv->lower_info_items; l; l = l->next) {
- ItipViewInfoItem *item = l->data;
-
- if (item->id == id) {
- priv->lower_info_items = g_slist_remove (priv->lower_info_items, item);
-
- g_free (item->message);
- g_free (item);
-
- set_lower_info_items (view);
-
- return;
- }
- }
-}
-
-void
-itip_view_clear_lower_info_items (ItipView *view)
-{
- ItipViewPrivate *priv;
- GSList *l;
-
- g_return_if_fail (view != NULL);
- g_return_if_fail (ITIP_IS_VIEW (view));
-
- priv = view->priv;
-
- gtk_container_foreach (GTK_CONTAINER (priv->lower_info_box), (GtkCallback) gtk_widget_destroy, NULL);
-
- for (l = priv->lower_info_items; l; l = l->next) {
- ItipViewInfoItem *item = l->data;
-
- g_free (item->message);
- g_free (item);
- }
-
- g_slist_free (priv->lower_info_items);
- priv->lower_info_items = NULL;
-}
-
-static void
-source_selected_cb (ESourceOptionMenu *esom, ESource *source, gpointer data)
-{
- ItipView *view = data;
-
- g_signal_emit (view, signals[SOURCE_SELECTED], 0, source);
-}
-
-void
-itip_view_set_source_list (ItipView *view, ESourceList *source_list)
-{
- ItipViewPrivate *priv;
-
- g_return_if_fail (view != NULL);
- g_return_if_fail (ITIP_IS_VIEW (view));
-
- priv = view->priv;
-
- if (priv->source_list)
- g_object_unref (priv->source_list);
-
- if (priv->esom)
- gtk_widget_destroy (priv->esom);
-
- if (!source_list) {
- if (priv->esom_header)
- gtk_widget_destroy (priv->esom_header);
-
- priv->source_list = NULL;
- priv->esom = NULL;
- priv->esom_header = NULL;
-
- return;
- }
-
- priv->source_list = g_object_ref (source_list);
-
- priv->esom = e_source_option_menu_new (source_list);
- gtk_widget_show (priv->esom);
- g_signal_connect (priv->esom, "source_selected", G_CALLBACK (source_selected_cb), view);
-
- if (!priv->esom_header) {
- priv->esom_header = gtk_label_new_with_mnemonic (_("_Calendar:"));
- gtk_label_set_mnemonic_widget (GTK_LABEL (priv->esom_header), priv->esom);
- gtk_widget_show (priv->esom_header);
- }
-
- gtk_box_pack_start (GTK_BOX (priv->selector_box), priv->esom_header, FALSE, TRUE, 6);
- gtk_box_pack_start (GTK_BOX (priv->selector_box), priv->esom, FALSE, TRUE, 0);
-}
-
-ESourceList *
-itip_view_get_source_list (ItipView *view)
-{
- ItipViewPrivate *priv;
-
- g_return_val_if_fail (view != NULL, FALSE);
- g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE);
-
- priv = view->priv;
-
- return priv->source_list;
-}
-
-void
-itip_view_set_source (ItipView *view, ESource *source)
-{
- ItipViewPrivate *priv;
-
- g_return_if_fail (view != NULL);
- g_return_if_fail (ITIP_IS_VIEW (view));
-
- priv = view->priv;
-
- if (!priv->esom)
- return;
-
- e_source_option_menu_select (E_SOURCE_OPTION_MENU (priv->esom), source);
-}
-
-ESource *
-itip_view_get_source (ItipView *view)
-{
- ItipViewPrivate *priv;
-
- g_return_val_if_fail (view != NULL, FALSE);
- g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE);
-
- priv = view->priv;
-
- if (!priv->esom)
- return NULL;
-
- return e_source_option_menu_peek_selected (E_SOURCE_OPTION_MENU (priv->esom));
-}
-
-void
-itip_view_set_rsvp (ItipView *view, gboolean rsvp)
-{
- ItipViewPrivate *priv;
-
- g_return_if_fail (view != NULL);
- g_return_if_fail (ITIP_IS_VIEW (view));
-
- priv = view->priv;
-
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->rsvp_check), rsvp);
-
- gtk_widget_set_sensitive (priv->rsvp_comment_header, rsvp);
- gtk_widget_set_sensitive (priv->rsvp_comment_entry, rsvp);
-}
-
-gboolean
-itip_view_get_rsvp (ItipView *view)
-{
- ItipViewPrivate *priv;
-
- g_return_val_if_fail (view != NULL, FALSE);
- g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE);
-
- priv = view->priv;
-
- return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->rsvp_check));
-}
-
-void
-itip_view_set_show_rsvp (ItipView *view, gboolean rsvp)
-{
- ItipViewPrivate *priv;
-
- g_return_if_fail (view != NULL);
- g_return_if_fail (ITIP_IS_VIEW (view));
-
- priv = view->priv;
-
- priv->rsvp_show = rsvp;
-
- priv->rsvp_show ? gtk_widget_show (priv->rsvp_box) : gtk_widget_hide (priv->rsvp_box);
-}
-
-gboolean
-itip_view_get_show_rsvp (ItipView *view)
-{
- ItipViewPrivate *priv;
-
- g_return_val_if_fail (view != NULL, FALSE);
- g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE);
-
- priv = view->priv;
-
- return priv->rsvp_show;
-}
-
-void
-itip_view_set_rsvp_comment (ItipView *view, const char *comment)
-{
- ItipViewPrivate *priv;
-
- g_return_if_fail (view != NULL);
- g_return_if_fail (ITIP_IS_VIEW (view));
-
- priv = view->priv;
-
- gtk_entry_set_text (GTK_ENTRY (priv->rsvp_comment_entry), comment);
-}
-
-const char *
-itip_view_get_rsvp_comment (ItipView *view)
-{
- ItipViewPrivate *priv;
-
- g_return_val_if_fail (view != NULL, FALSE);
- g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE);
-
- priv = view->priv;
-
- return gtk_entry_get_text (GTK_ENTRY (priv->rsvp_comment_entry));
-}
-
-void
-itip_view_set_buttons_sensitive (ItipView *view, gboolean sensitive)
-{
- ItipViewPrivate *priv;
-
- g_return_if_fail (view != NULL);
- g_return_if_fail (ITIP_IS_VIEW (view));
-
- priv = view->priv;
-
- priv->buttons_sensitive = sensitive;
-
- gtk_widget_set_sensitive (priv->button_box, priv->buttons_sensitive);
-}
-
-gboolean
-itip_view_get_buttons_sensitive (ItipView *view)
-{
- ItipViewPrivate *priv;
-
- g_return_val_if_fail (view != NULL, FALSE);
- g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE);
-
- priv = view->priv;
-
- return priv->buttons_sensitive;
-}
-
-
diff --git a/plugins/itip-formatter/itip-view.h b/plugins/itip-formatter/itip-view.h
deleted file mode 100644
index a8605a9564..0000000000
--- a/plugins/itip-formatter/itip-view.h
+++ /dev/null
@@ -1,164 +0,0 @@
-/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
-/* itip-view.h
- *
- * Copyright (C) 2004 Novell, Inc.
- *
- * 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., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- *
- * Author: JP Rosevear
- */
-
-#ifndef _ITIP_VIEW_H_
-#define _ITIP_VIEW_H_
-
-#include <stdarg.h>
-#include <unistd.h>
-#include <glib-object.h>
-#include <gtk/gtkhbox.h>
-#include <libedataserver/e-source-list.h>
-#include <libecal/e-cal.h>
-
-G_BEGIN_DECLS
-
-#define ITIP_TYPE_VIEW (itip_view_get_type ())
-#define ITIP_VIEW(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), ITIP_TYPE_VIEW, ItipView))
-#define ITIP_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ITIP_TYPE_VIEW, ItipViewClass))
-#define ITIP_IS_VIEW(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), ITIP_TYPE_VIEW))
-#define ITIP_IS_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), ITIP_TYPE_VIEW))
-#define ITIP_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ITIP_TYPE_VIEW, ItipViewClass))
-
-typedef struct _ItipView ItipView;
-typedef struct _ItipViewPrivate ItipViewPrivate;
-typedef struct _ItipViewClass ItipViewClass;
-
-typedef enum {
- ITIP_VIEW_MODE_NONE,
- ITIP_VIEW_MODE_PUBLISH,
- ITIP_VIEW_MODE_REQUEST,
- ITIP_VIEW_MODE_COUNTER,
- ITIP_VIEW_MODE_DECLINECOUNTER,
- ITIP_VIEW_MODE_ADD,
- ITIP_VIEW_MODE_REPLY,
- ITIP_VIEW_MODE_REFRESH,
- ITIP_VIEW_MODE_CANCEL
-} ItipViewMode;
-
-typedef enum {
- ITIP_VIEW_RESPONSE_NONE,
- ITIP_VIEW_RESPONSE_ACCEPT,
- ITIP_VIEW_RESPONSE_TENTATIVE,
- ITIP_VIEW_RESPONSE_DECLINE,
- ITIP_VIEW_RESPONSE_UPDATE,
- ITIP_VIEW_RESPONSE_CANCEL,
- ITIP_VIEW_RESPONSE_REFRESH,
- ITIP_VIEW_RESPONSE_OPEN
-} ItipViewResponse;
-
-typedef enum {
- ITIP_VIEW_INFO_ITEM_TYPE_NONE,
- ITIP_VIEW_INFO_ITEM_TYPE_INFO,
- ITIP_VIEW_INFO_ITEM_TYPE_WARNING,
- ITIP_VIEW_INFO_ITEM_TYPE_ERROR,
- ITIP_VIEW_INFO_ITEM_TYPE_PROGRESS
-} ItipViewInfoItemType;
-
-struct _ItipView {
- GtkHBox parent_instance;
-
- ItipViewPrivate *priv;
-
- GtkWidget *action_vbox;
-};
-
-struct _ItipViewClass {
- GtkHBoxClass parent_class;
-
- void (* source_selected) (ItipView *view, ESource *selected_source);
- void (* response) (ItipView *view, int response);
-};
-
-GType itip_view_get_type (void);
-GtkWidget *itip_view_new (void);
-
-void itip_view_set_mode (ItipView *view, ItipViewMode mode);
-ItipViewMode itip_view_get_mode (ItipView *view);
-
-void itip_view_set_item_type (ItipView *view, ECalSourceType type);
-ECalSourceType itip_view_get_item_type (ItipView *view);
-
-void itip_view_set_organizer (ItipView *view, const char *organizer);
-const char *itip_view_get_organizer (ItipView *view);
-
-void itip_view_set_sentby (ItipView *view, const char *sentby);
-const char *itip_view_get_sentby (ItipView *view);
-
-void itip_view_set_attendee (ItipView *view, const char *attendee);
-const char *itip_view_get_attendee (ItipView *view);
-
-void itip_view_set_delegator (ItipView *view, const char *delegator);
-const char *itip_view_get_delegator (ItipView *view);
-
-void itip_view_set_summary (ItipView *view, const char *summary);
-const char *itip_view_get_summary (ItipView *view);
-
-void itip_view_set_location (ItipView *view, const char *location);
-const char *itip_view_get_location (ItipView *view);
-
-void itip_view_set_status (ItipView *view, const char *status);
-const char *itip_view_get_status (ItipView *view);
-
-void itip_view_set_comment (ItipView *view, const char *comment);
-const char *itip_view_get_comment (ItipView *view);
-
-void itip_view_set_description (ItipView *view, const char *description);
-const char *itip_view_get_description (ItipView *view);
-
-void itip_view_set_start (ItipView *view, struct tm *start);
-const struct tm *itip_view_get_start (ItipView *view);
-
-void itip_view_set_end (ItipView *view, struct tm *end);
-const struct tm *itip_view_get_end (ItipView *view);
-
-guint itip_view_add_upper_info_item (ItipView *view, ItipViewInfoItemType type, const char *message);
-guint itip_view_add_upper_info_item_printf (ItipView *view, ItipViewInfoItemType, const char *format, ...) G_GNUC_PRINTF (3, 4);
-void itip_view_remove_upper_info_item (ItipView *view, guint id);
-void itip_view_clear_upper_info_items (ItipView *view);
-
-guint itip_view_add_lower_info_item (ItipView *view, ItipViewInfoItemType type, const char *message);
-guint itip_view_add_lower_info_item_printf (ItipView *view, ItipViewInfoItemType type, const char *format, ...) G_GNUC_PRINTF (3, 4);
-void itip_view_remove_lower_info_item (ItipView *view, guint id);
-void itip_view_clear_lower_info_items (ItipView *view);
-
-void itip_view_set_source_list (ItipView *view, ESourceList *source_list);
-ESourceList *itip_view_get_source_list (ItipView *view);
-
-void itip_view_set_source (ItipView *view, ESource *source);
-ESource *itip_view_get_source (ItipView *view);
-
-void itip_view_set_rsvp (ItipView *view, gboolean rsvp);
-gboolean itip_view_get_rsvp (ItipView *view);
-
-void itip_view_set_show_rsvp (ItipView *view, gboolean rsvp);
-gboolean itip_view_get_show_rsvp (ItipView *view);
-
-void itip_view_set_rsvp_comment (ItipView *view, const char *comment);
-const char *itip_view_get_rsvp_comment (ItipView *view);
-
-void itip_view_set_buttons_sensitive (ItipView *view, gboolean sensitive);
-gboolean itip_view_get_buttons_sensitive (ItipView *view);
-
-G_END_DECLS
-
-#endif
diff --git a/plugins/itip-formatter/org-gnome-itip-formatter-errors.xml b/plugins/itip-formatter/org-gnome-itip-formatter-errors.xml
deleted file mode 100644
index f8f462a1e8..0000000000
--- a/plugins/itip-formatter/org-gnome-itip-formatter-errors.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<error-list domain="org.gnome.itip-formatter">
-
- <error id="add-unknown-attendee" type="question">
- <primary>This response is not from a current attendee. Add the sender as an attendee?</primary>
- </error>
-
-</error-list>
diff --git a/plugins/itip-formatter/org-gnome-itip-formatter.eplug.in b/plugins/itip-formatter/org-gnome-itip-formatter.eplug.in
deleted file mode 100644
index 87e55cce54..0000000000
--- a/plugins/itip-formatter/org-gnome-itip-formatter.eplug.in
+++ /dev/null
@@ -1,20 +0,0 @@
-<e-plugin-list>
- <e-plugin id="org.gnome.evolution.itip_formatter" type="shlib" name="Itip Formatter" description="Displays text/calendar parts in messages"
- location="@PLUGINDIR@/liborg-gnome-itip-formatter.so">
-
- <hook class="org.gnome.evolution.mail.format:1.0">
- <group id="EMFormatHTMLDisplay">
- <item mime_type="text/calendar" flags="inline_disposition" format="format_itip"/>
- </group>
- <group id="EMFormat">
- <item mime_type="text/calendar" flags="inline_disposition" format="format_itip"/>
- </group>
- </hook>
-
- <hook class="org.gnome.evolution.mail.config:1.0">
- <group id="org.gnome.evolution.mail.prefs" target="prefs">
- <item type="page" path="90.bbdb" label="BBDB" factory="itip_formatter_page_factory"/>
- </group>
- </hook>
- </e-plugin>
-</e-plugin-list> \ No newline at end of file
diff --git a/plugins/mail-to-meeting/.cvsignore b/plugins/mail-to-meeting/.cvsignore
deleted file mode 100644
index 683d5ddbe2..0000000000
--- a/plugins/mail-to-meeting/.cvsignore
+++ /dev/null
@@ -1,5 +0,0 @@
-.deps
-.libs
-Makefile
-Makefile.in
-*.eplug \ No newline at end of file
diff --git a/plugins/mail-to-meeting/ChangeLog b/plugins/mail-to-meeting/ChangeLog
deleted file mode 100644
index 5b88823004..0000000000
--- a/plugins/mail-to-meeting/ChangeLog
+++ /dev/null
@@ -1,21 +0,0 @@
-2004-11-04 Rodrigo Moya <rodrigo@novell.com>
-
- * org-gnome-mail-to-meeting.eplug.in: fixed description and added
- author's info, to display correctly on the plugin manager.
-
-2004-11-03 Not Zed <NotZed@Ximian.com>
-
- * org-gnome-mail-to-meeting.eplug.in: fix the popup id.
-
-2004-11-01 JP Rosevear <jpr@novell.com>
-
- * Makefile.am: dist .eplug.in file
-
-2004-10-29 Rodrigo Moya <rodrigo@novell.com>
-
- * org-gnome-mail-to-meeting.eplug.in: fix folder view popup id and
- use stock icon for meetings.
-
-2004-10-29 Rodrigo Moya <rodrigo@novell.com>
-
- * added mail-to-meeting plugin, to convert mails to meetings.
diff --git a/plugins/mail-to-meeting/Makefile.am b/plugins/mail-to-meeting/Makefile.am
deleted file mode 100644
index 2646d59670..0000000000
--- a/plugins/mail-to-meeting/Makefile.am
+++ /dev/null
@@ -1,13 +0,0 @@
-INCLUDES = \
- -I$(top_srcdir) \
- $(EVOLUTION_MAIL_CFLAGS)
-
-@EVO_PLUGIN_RULE@
-
-plugin_DATA = org-gnome-mail-to-meeting.eplug
-plugin_LTLIBRARIES = liborg-gnome-mail-to-meeting.la
-
-liborg_gnome_mail_to_meeting_la_SOURCES = mail-to-meeting.c
-liborg_gnome_mail_to_meeting_la_LDFLAGS = -module -avoid-version
-
-EXTRA_DIST = org-gnome-mail-to-meeting.eplug.in \ No newline at end of file
diff --git a/plugins/mail-to-meeting/mail-to-meeting.c b/plugins/mail-to-meeting/mail-to-meeting.c
deleted file mode 100644
index 4c358fe61a..0000000000
--- a/plugins/mail-to-meeting/mail-to-meeting.c
+++ /dev/null
@@ -1,179 +0,0 @@
-/* Evolution - Mail To Meeting plugin
- *
- * Copyright (C) 2004 Ximian, Inc.
- *
- * Authors: Rodrigo Moya <rodrigo@ximian.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <glib/gi18n-lib.h>
-#include <string.h>
-#include <stdio.h>
-
-#include <gconf/gconf-client.h>
-#include <libecal/e-cal.h>
-#include <libedataserverui/e-source-selector-dialog.h>
-#include "camel/camel-folder.h"
-#include "camel/camel-mime-message.h"
-#include "mail/em-popup.h"
-
-static void
-add_attendee_cb (gpointer key, gpointer value, gpointer user_data)
-{
- ECalComponentAttendee *ca;
- const char *str, *name;
- GList **attendees = user_data;
-
- if (!camel_internet_address_get (value, 0, &name, &str))
- return;
-
- ca = g_new0 (ECalComponentAttendee, 1);
- ca->value = str;
- ca->cn = name;
- /* FIXME: missing many fields */
-
- *attendees = g_slist_append (*attendees, ca);
-}
-
-static void
-set_attendees (ECalComponent *comp, CamelMimeMessage *message)
-{
- GSList *attendees = NULL, *l;
-
- g_hash_table_foreach (message->recipients, (GHFunc) add_attendee_cb, &attendees);
- e_cal_component_set_attendee_list (comp, attendees);
-
- for (l = attendees; l != NULL; l = l->next)
- g_free (l->data);
- g_slist_free (attendees);
-}
-
-static void
-set_organizer (ECalComponent *comp, CamelMimeMessage *message)
-{
- const CamelInternetAddress *address;
- const char *str, *name;
- ECalComponentOrganizer organizer = {NULL, NULL, NULL, NULL};
-
- if (message->reply_to)
- address = message->reply_to;
- else if (message->from)
- address = message->from;
- else
- return;
-
- if (!camel_internet_address_get (address, 0, &name, &str))
- return;
-
- organizer.value = str;
- organizer.cn = name;
- e_cal_component_set_organizer (comp, &organizer);
-}
-
-static void
-do_mail_to_meeting (EMPopupTargetSelect *t, ESource *meeting_source)
-{
- ECal *client;
-
- /* open the meeting client */
- client = e_cal_new (meeting_source, E_CAL_SOURCE_TYPE_EVENT);
- if (e_cal_open (client, FALSE, NULL)) {
- int i;
-
- for (i = 0; i < (t->uids ? t->uids->len : 0); i++) {
- CamelMimeMessage *message;
- ECalComponent *comp;
- ECalComponentText text;
- GSList sl;
- char *str;
-
- /* retrieve the message from the CamelFolder */
- message = camel_folder_get_message (t->folder, g_ptr_array_index (t->uids, i), NULL);
- if (!message)
- continue;
-
- comp = e_cal_component_new ();
- e_cal_component_set_new_vtype (comp, E_CAL_COMPONENT_EVENT);
- e_cal_component_set_uid (comp, camel_mime_message_get_message_id (message));
-
- /* set the meeting's summary */
- text.value = camel_mime_message_get_subject (message);
- text.altrep = NULL;
- e_cal_component_set_summary (comp, &text);
-
- /* FIXME: a better way to get the full body */
- str = camel_mime_message_build_mbox_from (message);
- text.value = str;
- sl.next = NULL;
- sl.data = &text;
- e_cal_component_set_description_list (comp, &sl);
-
- g_free (str);
-
- /* set the organizer, and the attendees */
- set_organizer (comp, message);
- set_attendees (comp, message);
-
- /* save the meeting to the selected source */
- e_cal_create_object (client, e_cal_component_get_icalcomponent (comp), NULL, NULL);
-
- g_object_unref (comp);
- }
- }
-
- /* free memory */
- g_object_unref (client);
-}
-
-void org_gnome_mail_to_meeting (void *ep, EMPopupTargetSelect *t);
-
-void
-org_gnome_mail_to_meeting (void *ep, EMPopupTargetSelect *t)
-{
- GtkWidget *dialog;
- GConfClient *conf_client;
- ESourceList *source_list;
-
- /* ask the user which meeting list to save to */
- conf_client = gconf_client_get_default ();
- source_list = e_source_list_new_for_gconf (conf_client, "/apps/evolution/calendar/sources");
-
- dialog = e_source_selector_dialog_new (NULL, source_list);
-
- if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
- ESource *source;
-
- /* if a source has been selected, perform the mail2meeting operation */
- source = e_source_selector_dialog_peek_primary_selection (E_SOURCE_SELECTOR_DIALOG (dialog));
- if (source)
- do_mail_to_meeting (t, source);
- }
-
- g_object_unref (conf_client);
- g_object_unref (source_list);
- gtk_widget_destroy (dialog);
-}
-
-int e_plugin_lib_enable(EPluginLib *ep, int enable);
-
-int
-e_plugin_lib_enable(EPluginLib *ep, int enable)
-{
- return 0;
-}
diff --git a/plugins/mail-to-meeting/org-gnome-mail-to-meeting.eplug.in b/plugins/mail-to-meeting/org-gnome-mail-to-meeting.eplug.in
deleted file mode 100644
index 5248409158..0000000000
--- a/plugins/mail-to-meeting/org-gnome-mail-to-meeting.eplug.in
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0"?>
-<e-plugin-list>
- <e-plugin
- type="shlib"
- id="org.gnome.evolution.plugin.mailToMeeting"
- location="@PLUGINDIR@/liborg-gnome-mail-to-meeting.so"
- name="Convert a mail message into a meeting">
- <description>A plugin which allows the creation of meetings from the contents of a mail message</description>
- <author name="Rodrigo Moya" email="rodrigo@novell.com"/>
-
- <!-- hook into the uri popup menu -->
- <hook class="org.gnome.evolution.mail.popup:1.0">
- <menu id="org.gnome.evolution.mail.folderview.popup" target="select">
- <item
- type="item"
- path="72.mail_to_meeting"
- icon="stock_new-meeting"
- label="Con_vert to Meeting"
- enable="one"
- visible="one"
- activate="org_gnome_mail_to_meeting"/>
- </menu>
- </hook>
- </e-plugin>
-</e-plugin-list>
diff --git a/plugins/mail-to-task/.cvsignore b/plugins/mail-to-task/.cvsignore
deleted file mode 100644
index 683d5ddbe2..0000000000
--- a/plugins/mail-to-task/.cvsignore
+++ /dev/null
@@ -1,5 +0,0 @@
-.deps
-.libs
-Makefile
-Makefile.in
-*.eplug \ No newline at end of file
diff --git a/plugins/mail-to-task/ChangeLog b/plugins/mail-to-task/ChangeLog
deleted file mode 100644
index ffe03944a7..0000000000
--- a/plugins/mail-to-task/ChangeLog
+++ /dev/null
@@ -1,45 +0,0 @@
-2005-01-14 Rodrigo Moya <rodrigo@novell.com>
-
- * mail-to-task.c (set_description): new function to correctly
- retrieve the body of the message.
- (do_mail_to_task): call set_description.
-
-2004-11-04 Rodrigo Moya <rodrigo@novell.com>
-
- * org-gnome-mail-to-task.eplug.in: fixed description and added
- author's info, to display correctly on the plugin manager.
-
-2004-11-03 Not Zed <NotZed@Ximian.com>
-
- * org-gnome-mail-to-task.eplug.in: revert rodrigo's last fix, it should
- actually work now, i hope.
-
-2004-11-01 JP Rosevear <jpr@novell.com>
-
- * Makefile.am: dist .eplugin.in file
-
-2004-10-29 Rodrigo Moya <rodrigo@novell.com>
-
- * org-gnome-mail-to-task.eplug.in: fix folder view popup id again.
-
-2004-10-28 Not Zed <NotZed@Ximian.com>
-
- * org-gnome-mail-to-task.eplug.in: fix folder view popup id.
-
-2004-10-21 Rodrigo Moya <rodrigo@novell.com>
-
- * mail-to-task.c (set_attendees, set_organizer): new functions.
- (do_mail_to_task): set attendees and organizer on the task from the
- recipients in the mail message.
-
- * org-gnome-mail-to-task.eplug.in: use correct icon.
-
-2004-10-21 Rodrigo Moya <rodrigo@novell.com>
-
- * org-gnome-mail-to-task.eplug.in: fixed to make the plugin show
- up in the correct place.
-
-2004-10-21 Rodrigo Moya <rodrigo@novell.com>
-
- * mail-to-task.c: implemented plugin for converting selected
- mails to tasks.
diff --git a/plugins/mail-to-task/Makefile.am b/plugins/mail-to-task/Makefile.am
deleted file mode 100644
index 182dcdf59f..0000000000
--- a/plugins/mail-to-task/Makefile.am
+++ /dev/null
@@ -1,13 +0,0 @@
-INCLUDES = \
- -I$(top_srcdir) \
- $(EVOLUTION_MAIL_CFLAGS)
-
-@EVO_PLUGIN_RULE@
-
-plugin_DATA = org-gnome-mail-to-task.eplug
-plugin_LTLIBRARIES = liborg-gnome-mail-to-task.la
-
-liborg_gnome_mail_to_task_la_SOURCES = mail-to-task.c
-liborg_gnome_mail_to_task_la_LDFLAGS = -module -avoid-version
-
-EXTRA_DIST = org-gnome-mail-to-task.eplug.in \ No newline at end of file
diff --git a/plugins/mail-to-task/mail-to-task.c b/plugins/mail-to-task/mail-to-task.c
deleted file mode 100644
index d2c5f9eb71..0000000000
--- a/plugins/mail-to-task/mail-to-task.c
+++ /dev/null
@@ -1,190 +0,0 @@
-
-/* Copyright (C) 2004 Novell, Inc */
-/* Authors: Michael Zucchi
- Rodrigo Moya */
-
-/* This file is licensed under the GNU GPL v2 or later */
-
-/* Convert a mail message into a task */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <glib/gi18n-lib.h>
-#include <string.h>
-#include <stdio.h>
-
-#include <gconf/gconf-client.h>
-#include <libecal/e-cal.h>
-#include <libedataserverui/e-source-selector-dialog.h>
-#include <camel/camel-folder.h>
-#include <camel/camel-medium.h>
-#include <camel/camel-mime-message.h>
-#include <camel/camel-stream.h>
-#include <camel/camel-stream-mem.h>
-#include "mail/em-popup.h"
-
-static void
-add_attendee_cb (gpointer key, gpointer value, gpointer user_data)
-{
- ECalComponentAttendee *ca;
- const char *str, *name;
- GList **attendees = user_data;
-
- if (!camel_internet_address_get (value, 0, &name, &str))
- return;
-
- ca = g_new0 (ECalComponentAttendee, 1);
- ca->value = str;
- ca->cn = name;
- /* FIXME: missing many fields */
-
- *attendees = g_slist_append (*attendees, ca);
-}
-
-static void
-set_attendees (ECalComponent *comp, CamelMimeMessage *message)
-{
- GSList *attendees = NULL, *l;
-
- g_hash_table_foreach (message->recipients, (GHFunc) add_attendee_cb, &attendees);
- e_cal_component_set_attendee_list (comp, attendees);
-
- for (l = attendees; l != NULL; l = l->next)
- g_free (l->data);
- g_slist_free (attendees);
-}
-
-static void
-set_description (ECalComponent *comp, CamelMimeMessage *message)
-{
- CamelDataWrapper *content;
- CamelStream *mem;
- ECalComponentText text;
- GSList sl;
- char *str;
-
- content = camel_medium_get_content_object ((CamelMedium *) message);
- if (!content)
- return;
-
- mem = camel_stream_mem_new ();
- camel_data_wrapper_decode_to_stream (content, mem);
-
- str = g_strndup (((CamelStreamMem *) mem)->buffer->data, ((CamelStreamMem *) mem)->buffer->len);
- camel_object_unref (mem);
-
- text.value = str;
- text.altrep = NULL;
- sl.next = NULL;
- sl.data = &text;
-
- e_cal_component_set_description_list (comp, &sl);
-
- g_free (str);
-}
-
-static void
-set_organizer (ECalComponent *comp, CamelMimeMessage *message)
-{
- const CamelInternetAddress *address;
- const char *str, *name;
- ECalComponentOrganizer organizer = {NULL, NULL, NULL, NULL};
-
- if (message->reply_to)
- address = message->reply_to;
- else if (message->from)
- address = message->from;
- else
- return;
-
- if (!camel_internet_address_get (address, 0, &name, &str))
- return;
-
- organizer.value = str;
- organizer.cn = name;
- e_cal_component_set_organizer (comp, &organizer);
-}
-
-static void
-do_mail_to_task (EMPopupTargetSelect *t, ESource *tasks_source)
-{
- ECal *client;
-
- /* open the task client */
- client = e_cal_new (tasks_source, E_CAL_SOURCE_TYPE_TODO);
- if (e_cal_open (client, FALSE, NULL)) {
- int i;
-
- for (i = 0; i < (t->uids ? t->uids->len : 0); i++) {
- CamelMimeMessage *message;
- ECalComponent *comp;
- ECalComponentText text;
-
- /* retrieve the message from the CamelFolder */
- message = camel_folder_get_message (t->folder, g_ptr_array_index (t->uids, i), NULL);
- if (!message)
- continue;
-
- comp = e_cal_component_new ();
- e_cal_component_set_new_vtype (comp, E_CAL_COMPONENT_TODO);
- e_cal_component_set_uid (comp, camel_mime_message_get_message_id (message));
-
- /* set the task's summary */
- text.value = camel_mime_message_get_subject (message);
- text.altrep = NULL;
- e_cal_component_set_summary (comp, &text);
-
- /* set all fields */
- set_description (comp, message);
- set_organizer (comp, message);
- set_attendees (comp, message);
-
- /* save the task to the selected source */
- e_cal_create_object (client, e_cal_component_get_icalcomponent (comp), NULL, NULL);
-
- g_object_unref (comp);
- }
- }
-
- /* free memory */
- g_object_unref (client);
-}
-
-void org_gnome_mail_to_task (void *ep, EMPopupTargetSelect *t);
-
-void
-org_gnome_mail_to_task (void *ep, EMPopupTargetSelect *t)
-{
- GtkWidget *dialog;
- GConfClient *conf_client;
- ESourceList *source_list;
-
- /* ask the user which tasks list to save to */
- conf_client = gconf_client_get_default ();
- source_list = e_source_list_new_for_gconf (conf_client, "/apps/evolution/tasks/sources");
-
- dialog = e_source_selector_dialog_new (NULL, source_list);
-
- if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
- ESource *source;
-
- /* if a source has been selected, perform the mail2task operation */
- source = e_source_selector_dialog_peek_primary_selection (E_SOURCE_SELECTOR_DIALOG (dialog));
- if (source)
- do_mail_to_task (t, source);
- }
-
- g_object_unref (conf_client);
- g_object_unref (source_list);
- gtk_widget_destroy (dialog);
-}
-
-int e_plugin_lib_enable(EPluginLib *ep, int enable);
-
-int
-e_plugin_lib_enable(EPluginLib *ep, int enable)
-{
- return 0;
-}
diff --git a/plugins/mail-to-task/org-gnome-mail-to-task.eplug.in b/plugins/mail-to-task/org-gnome-mail-to-task.eplug.in
deleted file mode 100644
index e1fe4dc6b3..0000000000
--- a/plugins/mail-to-task/org-gnome-mail-to-task.eplug.in
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0"?>
-<e-plugin-list>
- <e-plugin
- type="shlib"
- id="org.gnome.evolution.plugin.mailToTask"
- location="@PLUGINDIR@/liborg-gnome-mail-to-task.so"
- name="Convert a mail message into a task">
- <description>A plugin which allows the creation of tasks from the contents of a mail message</description>
- <author name="Rodrigo Moya" email="rodrigo@novell.com"/>
-
- <!-- hook into the uri popup menu -->
- <hook class="org.gnome.evolution.mail.popup:1.0">
- <menu id="org.gnome.evolution.mail.folderview.popup" target="select">
- <item
- type="item"
- path="71.mail_to_task"
- icon="stock_todo"
- label="Con_vert to Task"
- enable="one"
- visible="one"
- activate="org_gnome_mail_to_task"/>
- </menu>
- </hook>
- </e-plugin>
-</e-plugin-list>
diff --git a/plugins/mailing-list-actions/.cvsignore b/plugins/mailing-list-actions/.cvsignore
deleted file mode 100644
index 683d5ddbe2..0000000000
--- a/plugins/mailing-list-actions/.cvsignore
+++ /dev/null
@@ -1,5 +0,0 @@
-.deps
-.libs
-Makefile
-Makefile.in
-*.eplug \ No newline at end of file
diff --git a/plugins/mailing-list-actions/ChangeLog b/plugins/mailing-list-actions/ChangeLog
deleted file mode 100644
index 6af314e08d..0000000000
--- a/plugins/mailing-list-actions/ChangeLog
+++ /dev/null
@@ -1,34 +0,0 @@
-2004-11-24 JP Rosevear <jpr@novell.com>
-
- * mailing-list-actions.c: make sure GETTEXT_PACKAGE is defined
-
-2004-11-04 Meilof Veeningen <meilof@wanadoo.nl>
-
- * org-gnome-mailing-list-actions.eplug.in: Added author tag, fixed
- description, removed "plugin" from name, changed position of item
- in popup menu, using "enable" rather than "visible" for bonobo menus
-
- * org-gnome-mailing-list-actions.xml: Now place menus in
- MailMessageActions placeholder; moved label to <commands> section
-
- * org-gnome-mailing-list-actions-errors.xml: fixed button order:
- "Cancel" now leftmost button; added e-mail address to send confirm
- dialog
-
- * mailing-list-actions.c: account guessing now first based on message;
- added e-mail address to send confirm dialog
-
-2004-11-09 Rodney Dawes <dobey@novell.com>
-
- * Makefile.am: Add org-gnome-mailing-list-actions.xml to EXTRA_DIST
-
-2004-11-09 Rodney Dawes <dobey@novell.com>
-
- * Makefile.am: Add the eplug.in file to EXTRA_DIST
-
-2004-11-05 JP Rosevear <jpr@novell.com>
-
- * mailing-list-actions.c: include <config.h> for GETTEXT_PACKAGE
-
- Added mailing list actions plugin from Meilof Veeningen <meilof@wanadoo.nl>
-
diff --git a/plugins/mailing-list-actions/Makefile.am b/plugins/mailing-list-actions/Makefile.am
deleted file mode 100644
index 27704c46a5..0000000000
--- a/plugins/mailing-list-actions/Makefile.am
+++ /dev/null
@@ -1,24 +0,0 @@
-INCLUDES = \
- -I$(top_srcdir) \
- $(EVOLUTION_MAIL_CFLAGS)
-
-@EVO_PLUGIN_RULE@
-
-plugin_DATA = org-gnome-mailing-list-actions.eplug org-gnome-mailing-list-actions.xml
-plugin_LTLIBRARIES = liborg-gnome-mailing-list-actions.la
-
-liborg_gnome_mailing_list_actions_la_SOURCES = mailing-list-actions.c
-liborg_gnome_mailing_list_actions_la_LDFLAGS = -module -avoid-version
-
-error_DATA = org-gnome-mailing-list-actions-errors.xml
-error_i18n = $(error_DATA:.xml=.xml.h)
-errordir = $(privdatadir)/errors
-%.xml.h: %.xml
- $(top_builddir)/e-util/e-error-tool $^
-
-BUILT_SOURCES = $(error_i18n)
-EXTRA_DIST = \
- $(error_DATA) \
- $(error_i18n) \
- org-gnome-mailing-list-actions.eplug.in \
- org-gnome-mailing-list-actions.xml
diff --git a/plugins/mailing-list-actions/mailing-list-actions.c b/plugins/mailing-list-actions/mailing-list-actions.c
deleted file mode 100644
index e79db1fc55..0000000000
--- a/plugins/mailing-list-actions/mailing-list-actions.c
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * Copyright (C) 2004 Meilof Veeningen <meilof@wanadoo.nl>
- *
- * This file is licensed under the GNU GPL v2 or later
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <glib/gi18n-lib.h>
-#include <stdio.h>
-#include <string.h>
-#include <gconf/gconf-client.h>
-#include <gtk/gtkcombobox.h>
-#include <gtk/gtkliststore.h>
-#include <gtk/gtkcellrenderertext.h>
-#include <gtk/gtkcelllayout.h>
-#include <gtk/gtktable.h>
-#include <gtk/gtklabel.h>
-#include <gtk/gtkmenuitem.h>
-#include <gtk/gtkdialog.h>
-#include <libgnome/gnome-url.h>
-
-#include "camel/camel-multipart.h"
-#include "camel/camel-mime-part.h"
-#include "camel/camel-exception.h"
-#include "camel/camel-folder.h"
-#include "composer/e-msg-composer.h"
-#include "mail/em-composer-utils.h"
-#include "mail/em-format-hook.h"
-#include "mail/em-format.h"
-#include "mail/em-menu.h"
-#include "mail/em-config.h"
-#include "mail/mail-ops.h"
-#include "mail/mail-mt.h"
-#include "mail/mail-config.h"
-#include "widgets/misc/e-error.h"
-
-typedef enum {
- EMLA_ACTION_HELP,
- EMLA_ACTION_UNSUBSCRIBE,
- EMLA_ACTION_SUBSCRIBE,
- EMLA_ACTION_POST,
- EMLA_ACTION_OWNER,
- EMLA_ACTION_ARCHIVE
-} EmlaAction;
-
-typedef struct {
- EmlaAction action; /* action enumeration */
- gboolean interactive; /* whether the user needs to edit a mailto: message (e.g. for post action) */
- const char* header; /* header representing the action */
-} EmlaActionHeader;
-
-const EmlaActionHeader emla_action_headers[] = {
- { EMLA_ACTION_HELP, FALSE, "List-Help" },
- { EMLA_ACTION_UNSUBSCRIBE, TRUE, "List-Unsubscribe" },
- { EMLA_ACTION_SUBSCRIBE, FALSE, "List-Subscribe" },
- { EMLA_ACTION_POST, TRUE, "List-Post" },
- { EMLA_ACTION_OWNER, TRUE, "List-Owner" },
- { EMLA_ACTION_ARCHIVE, FALSE, "List-Archive" },
-};
-
-const int emla_n_action_headers = sizeof(emla_action_headers) / sizeof(EmlaActionHeader);
-
-void emla_list_action (EPlugin *item, EMMenuTargetSelect* sel, EmlaAction action);
-void emla_list_help (EPlugin *item, EMMenuTargetSelect* sel);
-void emla_list_unsubscribe (EPlugin *item, EMMenuTargetSelect* sel);
-void emla_list_subscribe (EPlugin *item, EMMenuTargetSelect* sel);
-void emla_list_post (EPlugin *item, EMMenuTargetSelect* sel);
-void emla_list_owner (EPlugin *item, EMMenuTargetSelect* sel);
-void emla_list_archive (EPlugin *item, EMMenuTargetSelect* sel);
-
-void emla_list_action_do (CamelFolder *folder, const char *uid, CamelMimeMessage *msg, void *data);
-
-typedef struct {
- EmlaAction action;
- char* uri;
-} emla_action_data;
-
-void emla_list_action (EPlugin *item, EMMenuTargetSelect* sel, EmlaAction action)
-{
- emla_action_data *data;
-
- g_return_if_fail (sel->uids->len == 1);
-
- data = (emla_action_data *) malloc (sizeof (emla_action_data));
- data->action = action;
- data->uri = strdup (sel->uri);
-
- mail_get_message (sel->folder, (const char*) g_ptr_array_index (sel->uids, 0),
- emla_list_action_do, data, mail_thread_new);
-}
-
-void emla_list_action_do (CamelFolder *folder, const char *uid, CamelMimeMessage *msg, void *data)
-{
- emla_action_data *action_data = (emla_action_data *) data;
- EmlaAction action = action_data->action;
- const char* header = NULL, *headerpos;
- char *end, *url = NULL;
- int t;
- GError *err;
- EMsgComposer *composer;
- int send_message_response;
- EAccount *account;
-
- for (t = 0; t < emla_n_action_headers; t++) {
- if (emla_action_headers[t].action == action &&
- (header = camel_medium_get_header (CAMEL_MEDIUM (msg), emla_action_headers[t].header)) != NULL)
- break;
- }
-
- if (!header) {
- /* there was no header matching the action */
- e_error_run (NULL, "org.gnome.mailing-list-actions:no-header", NULL);
- goto exit;
- }
-
- headerpos = header;
-
- if (action == EMLA_ACTION_POST) {
- while (*headerpos == ' ') headerpos++;
- if (g_ascii_strcasecmp (headerpos, "NO") == 0) {
- e_error_run (NULL, "org.gnome.mailing-list-actions:posting-not-allowed", NULL);
- goto exit;
- }
- }
-
- /* parse the action value */
- while (*headerpos) {
- /* skip whitespace */
- while (*headerpos == ' ') headerpos++;
- if (*headerpos != '<' || (end = strchr (headerpos++, '>')) == NULL) {
- e_error_run (NULL, "org.gnome.mailing-list-actions:malformed-header", emla_action_headers[t].header, header, NULL);
- goto exit;
- }
-
- /* get URL portion */
- url = (char *) malloc (end - headerpos);
- strncpy (url, headerpos, end - headerpos);
- url[end-headerpos] = '\0';
-
- if (strncmp (url, "mailto:", 6) == 0) {
- if (emla_action_headers[t].interactive)
- send_message_response = GTK_RESPONSE_NO;
- else
- send_message_response = e_error_run (NULL, "org.gnome.mailing-list-actions:ask-send-message", url, NULL);
-
- if (send_message_response == GTK_RESPONSE_YES) {
- /* directly send message */
- composer = e_msg_composer_new_from_url (url);
- if ((account = mail_config_get_account_by_source_url (action_data->uri)))
- e_msg_composer_hdrs_set_from_account ((EMsgComposerHdrs *) composer->hdrs, account->name);
- em_utils_composer_send_cb (composer, NULL);
- } else if (send_message_response == GTK_RESPONSE_NO) {
- /* show composer */
- em_utils_compose_new_message_with_mailto (url, action_data->uri);
- }
-
- goto exit;
- } else {
- err = NULL;
- gnome_url_show (url, &err);
- if (!err)
- goto exit;
- g_error_free (err);
- }
- free (url);
- url = NULL;
- headerpos = end++;
-
- /* ignore everything 'till next comma */
- headerpos = strchr (headerpos, ',');
- if (!headerpos)
- break;
- headerpos++;
- }
-
- /* if we got here, there's no valid action */
- e_error_run (NULL, "org.gnome.mailing-list-actions:no-action", header, NULL);
-
-exit:
- free (action_data->uri);
- free (action_data);
- if (url)
- free(url);
-}
-
-void emla_list_help (EPlugin *item, EMMenuTargetSelect* sel)
-{
- emla_list_action (item, sel, EMLA_ACTION_HELP);
-}
-
-void emla_list_unsubscribe (EPlugin *item, EMMenuTargetSelect* sel)
-{
- emla_list_action (item, sel, EMLA_ACTION_UNSUBSCRIBE);
-}
-
-void emla_list_subscribe (EPlugin *item, EMMenuTargetSelect* sel)
-{
- emla_list_action (item, sel, EMLA_ACTION_SUBSCRIBE);
-}
-
-void emla_list_post (EPlugin *item, EMMenuTargetSelect* sel)
-{
- emla_list_action (item, sel, EMLA_ACTION_POST);
-}
-
-void emla_list_owner (EPlugin *item, EMMenuTargetSelect* sel)
-{
- emla_list_action (item, sel, EMLA_ACTION_OWNER);
-}
-
-void emla_list_archive (EPlugin *item, EMMenuTargetSelect* sel)
-{
- emla_list_action (item, sel, EMLA_ACTION_ARCHIVE);
-}
diff --git a/plugins/mailing-list-actions/org-gnome-mailing-list-actions-errors.xml b/plugins/mailing-list-actions/org-gnome-mailing-list-actions-errors.xml
deleted file mode 100644
index 69b20fa834..0000000000
--- a/plugins/mailing-list-actions/org-gnome-mailing-list-actions-errors.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<error-list domain="org.gnome.mailing-list-actions">
-
- <error id="no-header" type="error">
- <primary>Action not available</primary>
- <secondary>This message does not contain the header information required for this action.</secondary>
- </error>
-
- <error id="posting-not-allowed" type="error">
- <primary>Posting not allowed</primary>
- <secondary>Posting to this mailing list is not allowed. Possibly, this is a read-only mailing list. Contact the list owner for details.</secondary>
- </error>
-
- <error id="ask-send-message" type="question" default="GTK_RESPONSE_YES">
- <primary>Send e-mail message to mailing list?</primary>
- <secondary>An e-mail message will be sent to the URL "{0}". You can either send the message automatically, or see and change it first.
-
-You should receive an answer from the mailing list shortly after the message has been sent.</secondary>
- <button label="_Send message" response="GTK_RESPONSE_YES"/>
- <button label="_Edit message" response="GTK_RESPONSE_NO"/>
- <button stock="gtk-cancel" response="GTK_RESPONSE_CANCEL"/>
- </error>
-
- <error id="malformed-header" type="error">
- <primary>Malformed header</primary>
- <secondary>The {0} header of this message is malformed and could not be processed.
-
-Header: {1}</secondary>
- </error>
-
- <error id="no-action" type="error">
- <primary>No e-mail action</primary>
- <secondary>The action could not be performed. This means the header for this action did not contain any action we could handle.
-
-Header: {0}</secondary>
- </error>
-
-</error-list>
diff --git a/plugins/mailing-list-actions/org-gnome-mailing-list-actions-errors.xml.h b/plugins/mailing-list-actions/org-gnome-mailing-list-actions-errors.xml.h
deleted file mode 100644
index a5bbbbcc20..0000000000
--- a/plugins/mailing-list-actions/org-gnome-mailing-list-actions-errors.xml.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/* org.gnome.mailing-list-actions:no-header primary */
-char *s = N_("Action not available");
-/* org.gnome.mailing-list-actions:no-header secondary */
-char *s = N_("This message does not contain the header information required for this action.");
-/* org.gnome.mailing-list-actions:posting-not-allowed primary */
-char *s = N_("Posting not allowed");
-/* org.gnome.mailing-list-actions:posting-not-allowed secondary */
-char *s = N_("Posting to this mailing list is not allowed. Possibly, this is a read-only mailing list. Contact the list owner for details.");
-/* org.gnome.mailing-list-actions:ask-send-message primary */
-char *s = N_("Send e-mail message to mailing list?");
-/* org.gnome.mailing-list-actions:ask-send-message secondary */
-char *s = N_("An e-mail message will be sent to the URL \"{0}\". You can either send the message automatically, or see and change it first.\n"
- "\n"
- "You should receive an answer from the mailing list shortly after the message has been sent.");
-char *s = N_("_Send message");
-char *s = N_("_Edit message");
-/* org.gnome.mailing-list-actions:malformed-header primary */
-char *s = N_("Malformed header");
-/* org.gnome.mailing-list-actions:malformed-header secondary */
-char *s = N_("The {0} header of this message is malformed and could not be processed.\n"
- "\n"
- "Header: {1}");
-/* org.gnome.mailing-list-actions:no-action primary */
-char *s = N_("No e-mail action");
-/* org.gnome.mailing-list-actions:no-action secondary */
-char *s = N_("The action could not be performed. This means the header for this action did not contain any action we could handle.\n"
- "\n"
- "Header: {0}");
diff --git a/plugins/mailing-list-actions/org-gnome-mailing-list-actions.eplug.in b/plugins/mailing-list-actions/org-gnome-mailing-list-actions.eplug.in
deleted file mode 100644
index 749bc9fdc3..0000000000
--- a/plugins/mailing-list-actions/org-gnome-mailing-list-actions.eplug.in
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0"?>
-<e-plugin-list>
- <e-plugin
- type="shlib"
- id="org.gnome.plugin.mailing-list.actions"
- domain="eplug-mailing-list-actions"
- location="@PLUGINDIR@/liborg-gnome-mailing-list-actions.so"
- name="Mailing List Actions plugin"
- description="Provide actions for common mailing list commands (subscribe, unsubscribe, ...)">
- <hook class="org.gnome.evolution.mail.bonobomenu:1.0">
- <menu id="org.gnome.evolution.mail.browser" target="select">
- <ui file="@PLUGINDIR@/org-gnome-mailing-list-actions.xml"/>
- <item type="item" verb="ListHelp" path="/commands/ListHelp" visible="mailing_list" activate="emla_list_help"/>
- <item type="item" verb="ListSubscribe" path="/commands/ListSubscribe" visible="mailing_list" activate="emla_list_subscribe"/>
- <item type="item" verb="ListUnsubscribe" path="/commands/ListUnsubscribe" visible="mailing_list" activate="emla_list_unsubscribe"/>
- <item type="item" verb="ListPost" path="/commands/ListPost" visible="mailing_list" activate="emla_list_post"/>
- <item type="item" verb="ListOwner" path="/commands/ListOwner" visible="mailing_list" activate="emla_list_owner"/>
- <item type="item" verb="ListArchive" path="/commands/ListArchive" visible="mailing_list" activate="emla_list_archive"/>
- </menu>
- <menu id="org.gnome.evolution.mail.messagebrowser" target="select">
- <ui file="@PLUGINDIR@/org-gnome-mailing-list-actions.xml"/>
- <item type="item" verb="ListHelp" path="/commands/ListHelp" visible="mailing_list" activate="emla_list_help"/>
- <item type="item" verb="ListSubscribe" path="/commands/ListSubscribe" visible="mailing_list" activate="emla_list_subscribe"/>
- <item type="item" verb="ListUnsubscribe" path="/commands/ListUnsubscribe" visible="mailing_list" activate="emla_list_unsubscribe"/>
- <item type="item" verb="ListPost" path="/commands/ListPost" visible="mailing_list" activate="emla_list_post"/>
- <item type="item" verb="ListOwner" path="/commands/ListOwner" visible="mailing_list" activate="emla_list_owner"/>
- <item type="item" verb="ListArchive" path="/commands/ListArchive" visible="mailing_list" activate="emla_list_archive"/>
- </menu>
- </hook>
- <hook class="org.gnome.evolution.mail.popup:1.0">
- <menu id="org.gnome.mail.folderview.popup.select" target="select">
- <item type="bar" path="96.list" visible="mailing_list" activate=""/>
- <item type="submenu" path="96.list.00" visible="mailing_list" activate="" label="Mailing _List"/>
- <item type="item" verb="ListHelp" path="96.list.00/00.help" label="Get list _usage information" visible="mailing_list" activate="emla_list_help"/>
- <item type="item" verb="ListSubscribe" path="96.list.00/10.subscribe" label="_Subscribe to list" visible="mailing_list" activate="emla_list_subscribe"/>
- <item type="item" verb="ListUnsubscribe" path="96.list.00/20.unsubscribe" label="_Un-subscribe to list" visible="mailing_list" activate="emla_list_unsubscribe"/>
- <item type="item" verb="ListPost" path="96.list.00/30.post" label="_Post message to list" visible="mailing_list" activate="emla_list_post"/>
- <item type="item" verb="ListOwner" path="96.list.00/40.owner" label="Contact list _owner" visible="mailing_list" activate="emla_list_owner"/>
- <item type="item" verb="ListArchive" path="96.list.00/50.archive" label="Get list _archive" visible="mailing_list" activate="emla_list_archive"/>
- </menu>
- </hook>
- </e-plugin>
-</e-plugin-list>
diff --git a/plugins/mailing-list-actions/org-gnome-mailing-list-actions.xml b/plugins/mailing-list-actions/org-gnome-mailing-list-actions.xml
deleted file mode 100644
index 726a9dbaa8..0000000000
--- a/plugins/mailing-list-actions/org-gnome-mailing-list-actions.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<Root>
- <commands>
- <cmd name="ListHelp" _tip="Get information about the usage of the list this message belongs to"/>
- <cmd name="ListSubscribe" _tip="Subscribe to the mailing list this message belongs to"/>
- <cmd name="ListUnsubscribe" _tip="Unsubscribe to the mailing list this message belongs to"/>
- <cmd name="ListPost" _tip="Post a message to the mailing list this message belongs to"/>
- <cmd name="ListOwner" _tip="Contact the owner of the mailing list this message belongs to"/>
- <cmd name="ListArchive" _tip="Get an archive of the list this message belongs to"/>
- </commands>
-
- <menu>
- <submenu name="Actions">
- <submenu name="List" _label="Mailing _List">
- <menuitem verb="ListHelp" _label="Get list _usage information"/>
- <menuitem verb="ListSubscribe" _label="_Subscribe to list"/>
- <menuitem verb="ListUnsubscribe" _label="_Un-subscribe to list"/>
- <menuitem verb="ListPost" _label="_Post message to list"/>
- <menuitem verb="ListOwner" _label="Contact list _owner"/>
- <menuitem verb="ListArchive" _label="Get list _archive"/>
- </submenu>
- </submenu>
- </menu>
-</Root>
diff --git a/plugins/mark-calendar-offline/.cvsignore b/plugins/mark-calendar-offline/.cvsignore
deleted file mode 100644
index 9d1a6b6468..0000000000
--- a/plugins/mark-calendar-offline/.cvsignore
+++ /dev/null
@@ -1,3 +0,0 @@
-Makefile
-Makefile.in
-org-gnome-mark-calendar-offline.eplug
diff --git a/plugins/mark-calendar-offline/ChangeLog b/plugins/mark-calendar-offline/ChangeLog
deleted file mode 100644
index e6b33adc38..0000000000
--- a/plugins/mark-calendar-offline/ChangeLog
+++ /dev/null
@@ -1,10 +0,0 @@
-2004-11-01 JP Rosevear <jpr@novell.com>
-
- * Makefile.am: dist .eplug.in file
-
-2004-10-22 Harish Krishnaswamy <kharish@novell.com>
-
- * mark-calendar-offline.c: implement a plugin that lets the user mark a
- calendar to be available for off-line use, if it is not already set to be so
- and vice versa
-
diff --git a/plugins/mark-calendar-offline/Makefile.am b/plugins/mark-calendar-offline/Makefile.am
deleted file mode 100644
index bdd9fc46f3..0000000000
--- a/plugins/mark-calendar-offline/Makefile.am
+++ /dev/null
@@ -1,13 +0,0 @@
-INCLUDES = \
- -I$(top_srcdir) \
- $(EVOLUTION_CALENDAR_CFLAGS)
-
-@EVO_PLUGIN_RULE@
-
-plugin_DATA = org-gnome-mark-calendar-offline.eplug
-plugin_LTLIBRARIES = liborg-gnome-mark-calendar-offline.la
-
-liborg_gnome_mark_calendar_offline_la_SOURCES = mark-calendar-offline.c
-liborg_gnome_mark_calendar_offline_la_LDFLAGS = -module -avoid-version
-
-EXTRA_DIST = org-gnome-mark-calendar-offline.eplug.in \ No newline at end of file
diff --git a/plugins/mark-calendar-offline/mark-calendar-offline.c b/plugins/mark-calendar-offline/mark-calendar-offline.c
deleted file mode 100644
index 95083c7ff2..0000000000
--- a/plugins/mark-calendar-offline/mark-calendar-offline.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
- *
- * Authors: Harish Krishnaswamy (kharish@novell.com)
- *
- * Copyright 2004 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., 59 Temple Street #330, Boston, MA 02111-1307, USA.
- *
- */
-
-/* This is prototype code only, this may, or may not, use undocumented
- * unstable or private internal function calls.
- * This code has been derived from the source of the sample eplugin
- * select_one_source.
- */
-
-#include <glib.h>
-#include <glib/gi18n.h>
-#include <libedataserver/e-source.h>
-#include <libedataserverui/e-source-selector.h>
-#include <calendar/gui/e-cal-popup.h>
-
-void org_gnome_mark_calendar_offline (EPlugin *ep, ECalPopupTargetSource *target);
-void org_gnome_mark_calendar_no_offline (EPlugin *ep, ECalPopupTargetSource *target);
-
-void
-org_gnome_mark_calendar_no_offline (EPlugin *ep, ECalPopupTargetSource *target)
-{
- ESource *source;
-
- source = e_source_selector_peek_primary_selection (target->selector);
- e_source_set_property (source, "offline", "0");
-}
-
-void
-org_gnome_mark_calendar_offline (EPlugin *ep, ECalPopupTargetSource *target)
-{
- ESource *source;
-
- source = e_source_selector_peek_primary_selection (target->selector);
- e_source_set_property (source, "offline", "1");
-}
-
diff --git a/plugins/mark-calendar-offline/org-gnome-mark-calendar-offline.eplug.in b/plugins/mark-calendar-offline/org-gnome-mark-calendar-offline.eplug.in
deleted file mode 100644
index 75b8b9c866..0000000000
--- a/plugins/mark-calendar-offline/org-gnome-mark-calendar-offline.eplug.in
+++ /dev/null
@@ -1,16 +0,0 @@
-<e-plugin-list>
- <e-plugin id="org.gnome.evolution.mark_calendar_offline" type="shlib" name="Mark calendar offline" description="Marks the selected calendar for offline viewing"
- location="@PLUGINDIR@/liborg-gnome-mark-calendar-offline.so">
-
- <hook class="org.gnome.evolution.calendar.popup:1.0">
- <menu id="org.gnome.evolution.calendar.source.popup" target="source">
- <item type="item" path="28.mark_calendar_offline" label="_Mark Calendar for offline use" icon="stock_disconnect" visible="offline" activate="org_gnome_mark_calendar_offline"/>
- </menu>
- </hook>
- <hook class="org.gnome.evolution.calendar.popup:1.0">
- <menu id="org.gnome.evolution.calendar.source.popup" target="source">
- <item type="item" path="28.mark_calendar_no_offline" label="_Do not make this available offline" icon="stock_connect" visible="no-offline" activate="org_gnome_mark_calendar_no_offline"/>
- </menu>
- </hook>
- </e-plugin>
-</e-plugin-list>
diff --git a/plugins/new-mail-notify/ChangeLog b/plugins/new-mail-notify/ChangeLog
deleted file mode 100644
index afe8bd29cb..0000000000
--- a/plugins/new-mail-notify/ChangeLog
+++ /dev/null
@@ -1,42 +0,0 @@
-2005-01-13 Not Zed <NotZed@Ximian.com>
-
- * new-mail-notify.c: added prototypes for exported functions,
- re-arranged slightly to staticise internal functions.
-
- * new-mail-notify.h: removed.
-
-2005-01-12 Miguel Angel Lopez Hernandez <miguel@gulev.org.mx>
-
- * new-mail-notify.[ch]: Fix author's name, changes in code
- to maintain coding style
- (org_gnome_new_mail_notify): Now sends the dbus message using
- the send_dbus_message function
- (org_gnome_message_reading_notify): Added function, called when
- a message.reading event is fired
- (send_dbus_message): Added function, generic function to send
- dbus messages
-
- * org-gnome-new-mail-notify.eplug.in: define the message reading
- event
-
-2005-01-11 JP Rosevear <jpr@novell.com>
-
- * Makefile.am: add new-mail-notify.h so it gets disted
-
-2005-01-11 Not Zed <NotZed@Ximian.com>
-
- * new-mail-notify.c (org_gnome_new_mail_config)
- (org_gnome_new_mail_notify): renamed slightly for
- namespace/consistency.
- (org_gnome_new_mail_notify): fixed signature.
- (org_gnome_new_mail_notify): fixed some warnings & formatting.
-
-2004-12-30 Miguel Angel Lopez Hernandez <miguel@gulev.org.mx>
-
- * new-mail-notify.[ch]: Plugin implementation
-
- * org-gnome-new-mail-notify.eplug.in: define the
- new mail notify plugin
-
- * Makefile.am: build the new mail notify plugin
-
diff --git a/plugins/new-mail-notify/Makefile.am b/plugins/new-mail-notify/Makefile.am
deleted file mode 100644
index bef0fd41d1..0000000000
--- a/plugins/new-mail-notify/Makefile.am
+++ /dev/null
@@ -1,18 +0,0 @@
-INCLUDES = \
- -I$(top_srcdir) \
- -DDBUS_API_SUBJECT_TO_CHANGE=1 \
- $(EVOLUTION_MAIL_CFLAGS) \
- $(NMN_CFLAGS)
-
-LIBS = \
- $(NMN_LIBS)
-
-@EVO_PLUGIN_RULE@
-
-plugin_DATA = org-gnome-new-mail-notify.eplug
-plugin_LTLIBRARIES = liborg-gnome-new-mail-notify.la
-
-liborg_gnome_new_mail_notify_la_SOURCES = new-mail-notify.c
-liborg_gnome_new_mail_notify_la_LDFLAGS = -module -avoid-version
-
-EXTRA_DIST = org-gnome-new-mail-notify.eplug.in
diff --git a/plugins/new-mail-notify/new-mail-notify.c b/plugins/new-mail-notify/new-mail-notify.c
deleted file mode 100644
index e6147a1564..0000000000
--- a/plugins/new-mail-notify/new-mail-notify.c
+++ /dev/null
@@ -1,143 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * Author: Miguel Angel Lopez Hernandez <miguel@gulev.org.mx>
- *
- * Copyright 2004 Novell, Inc.
- *
- * 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., 59 Temple Street #330, Boston, MA 02111-1307, USA.
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <string.h>
-#include <glib.h>
-#include <gtk/gtk.h>
-#include <libgnome/gnome-i18n.h>
-#include <gconf/gconf-client.h>
-#include <e-util/e-config.h>
-#include <mail/em-config.h>
-#include <mail/em-event.h>
-#include <dbus/dbus-glib.h>
-#include <dbus/dbus-glib-lowlevel.h>
-#include <camel/camel-folder.h>
-
-#define GCONF_KEY "/apps/evolution/mail/notify/gen_dbus_msg"
-#define DBUS_PATH "/org/gnome/evolution/mail/newmail"
-#define DBUS_INTERFACE "org.gnome.evolution.mail.dbus.Signal"
-
-GtkWidget *org_gnome_new_mail_config (EPlugin *ep, EConfigHookItemFactoryData *hook_data);
-void org_gnome_new_mail_notify (EPlugin *ep, EMEventTargetFolder *t);
-void org_gnome_message_reading_notify (EPlugin *ep, EMEventTargetMessage *t);
-
-static void
-toggled_cb (GtkWidget *widget, EConfig *config)
-{
- EMConfigTargetPrefs *target = (EMConfigTargetPrefs *) config->target;
-
- /* Save the new setting to gconf */
- gconf_client_set_bool (target->gconf,
- GCONF_KEY,
- gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)),
- NULL);
-}
-
-GtkWidget *
-org_gnome_new_mail_config (EPlugin *ep, EConfigHookItemFactoryData *hook_data)
-{
- GtkWidget *notify;
-
- EMConfigTargetPrefs *target = (EMConfigTargetPrefs *) hook_data->config->target;
-
- /* Create the checkbox we will display, complete with mnemonic that is unique in the dialog */
- notify = gtk_check_button_new_with_mnemonic (_("_Generates a D-BUS message when new mail arrives"));
-
- /* Set the toggle button to the current gconf setting */
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (notify),
- gconf_client_get_bool (target->gconf,
- GCONF_KEY, NULL));
-
- /* Listen for the item being toggled on and off */
- g_signal_connect (GTK_TOGGLE_BUTTON (notify),
- "toggled",
- G_CALLBACK (toggled_cb),
- hook_data->config);
-
- /* Pack the checkbox in the parent widget and show it */
- gtk_box_pack_start (GTK_BOX (hook_data->parent), notify, FALSE, FALSE, 0);
- gtk_widget_show (notify);
-
- return notify;
-}
-
-static void
-send_dbus_message (const char *message_name, const char *data)
-{
- GConfClient *client = gconf_client_get_default ();
-
- if (gconf_client_get_bool(client, GCONF_KEY, NULL)) {
- DBusConnection *bus;
- DBusError error;
- DBusMessage *message;
-
- /* Get a connection to the session bus */
- dbus_error_init (&error);
- bus = dbus_bus_get (DBUS_BUS_SESSION,
- &error);
-
- if (!bus) {
- printf ("Failed to connect to the D-BUS daemon: %s\n", error.message);
- dbus_error_free (&error);
- }
-
- /* Set up this connection to work in a GLib event loop */
- dbus_connection_setup_with_g_main (bus, NULL);
-
- /* Create a new message on the DBUS_INTERFACE */
- message = dbus_message_new_signal (DBUS_PATH,
- DBUS_INTERFACE,
- message_name);
-
- /* Appends the data as an argument to the message */
- dbus_message_append_args (message,
- DBUS_TYPE_STRING, data,
- DBUS_TYPE_INVALID);
-
- /* Sends the message */
- dbus_connection_send (bus,
- message,
- NULL);
-
- /* Frees the message */
- dbus_message_unref (message);
-
- /* printf("New message [%s] with arg [%s]!\n", message_name, data); */
- }
-
- g_object_unref (client);
-}
-
-void
-org_gnome_message_reading_notify (EPlugin *ep, EMEventTargetMessage *t)
-{
- send_dbus_message ("MessageReading", t->folder->name);
-}
-
-void
-org_gnome_new_mail_notify (EPlugin *ep, EMEventTargetFolder *t)
-{
- send_dbus_message ("Newmail", t->uri);
-}
diff --git a/plugins/new-mail-notify/org-gnome-new-mail-notify.eplug.in b/plugins/new-mail-notify/org-gnome-new-mail-notify.eplug.in
deleted file mode 100644
index 89531415b8..0000000000
--- a/plugins/new-mail-notify/org-gnome-new-mail-notify.eplug.in
+++ /dev/null
@@ -1,33 +0,0 @@
-<e-plugin-list>
- <e-plugin
- id="org.gnome.evolution.new_mail_notify"
- type="shlib"
- name="New Mail Notification"
- location="@PLUGINDIR@/liborg-gnome-new-mail-notify.so">
-
- <description>Generates a D-BUS message when new mail arrives.</description>
- <author name="Miguel Angel López Hernández" email="miguel@gulev.org.mx"/>
-
- <hook class="org.gnome.evolution.mail.events:1.0">
- <event id="folder.changed"
- enable="newmail"
- handle="org_gnome_new_mail_notify"
- target="folder"/>
- </hook>
-
- <hook class="org.gnome.evolution.mail.events:1.0">
- <event id="message.reading"
- handle="org_gnome_message_reading_notify"
- target="message"/>
- </hook>
-
- <hook class="org.gnome.evolution.mail.config:1.0">
- <group target="prefs">
- <item type="item"
- path="00.general/30.notify/00.new_mail_notify"
- label="New mail notify"
- factory="org_gnome_new_mail_config"/>
- </group>
- </hook>
- </e-plugin>
-</e-plugin-list>
diff --git a/plugins/plugin-manager/.cvsignore b/plugins/plugin-manager/.cvsignore
deleted file mode 100644
index 683d5ddbe2..0000000000
--- a/plugins/plugin-manager/.cvsignore
+++ /dev/null
@@ -1,5 +0,0 @@
-.deps
-.libs
-Makefile
-Makefile.in
-*.eplug \ No newline at end of file
diff --git a/plugins/plugin-manager/ChangeLog b/plugins/plugin-manager/ChangeLog
deleted file mode 100644
index 982ce98ed1..0000000000
--- a/plugins/plugin-manager/ChangeLog
+++ /dev/null
@@ -1,12 +0,0 @@
-2004-11-09 Rodney Dawes <dobey@novell.com>
-
- * Makefile.am: Add the xml file to EXTRA_DIST
-
-2004-11-03 Not Zed <NotZed@Ximian.com>
-
- * Makefile.am: extra_dist the .eplug.in file.
-
-2004-10-20 Not Zed <NotZed@Ximian.com>
-
- * implemented a plugin manager plugin.
-
diff --git a/plugins/plugin-manager/Makefile.am b/plugins/plugin-manager/Makefile.am
deleted file mode 100644
index 3056e036c9..0000000000
--- a/plugins/plugin-manager/Makefile.am
+++ /dev/null
@@ -1,15 +0,0 @@
-INCLUDES = \
- -I$(top_srcdir) \
- $(EVOLUTION_MAIL_CFLAGS)
-
-@EVO_PLUGIN_RULE@
-
-plugin_DATA = org-gnome-plugin-manager.eplug org-gnome-plugin-manager.xml
-plugin_LTLIBRARIES = liborg-gnome-plugin-manager.la
-
-liborg_gnome_plugin_manager_la_SOURCES = plugin-manager.c
-liborg_gnome_plugin_manager_la_LDFLAGS = -module -avoid-version
-
-EXTRA_DIST = \
- org-gnome-plugin-manager.eplug.in \
- org-gnome-plugin-manager.xml
diff --git a/plugins/plugin-manager/org-gnome-plugin-manager.eplug.in b/plugins/plugin-manager/org-gnome-plugin-manager.eplug.in
deleted file mode 100644
index 6bdbcd74e5..0000000000
--- a/plugins/plugin-manager/org-gnome-plugin-manager.eplug.in
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0"?>
-<e-plugin-list>
- <e-plugin
- type="shlib"
- id="org.gnome.evolution.plugin.manager"
- location="@PLUGINDIR@/liborg-gnome-plugin-manager.so"
- name="Plugin manager">
- <description>A plugin for managing which plugins are enabled or disabled.</description>
- <author name="Michael Zucchi" email="notzed@ximian.com"/>
- <hook class="org.gnome.evolution.shell.bonobomenu:1.0">
- <menu id="org.gnome.evolution.shell" target="shell">
- <!-- the path to the bonobo menu description -->
- <ui file="@PLUGINDIR@/org-gnome-plugin-manager.xml"/>
- <item
- type="item"
- verb="EPluginManagerManage"
- path="/commands/EPluginManagerManage"
- activate="org_gnome_plugin_manager_manage"/>
- </menu>
- </hook>
- </e-plugin>
-</e-plugin-list>
diff --git a/plugins/plugin-manager/org-gnome-plugin-manager.xml b/plugins/plugin-manager/org-gnome-plugin-manager.xml
deleted file mode 100644
index 53c465adef..0000000000
--- a/plugins/plugin-manager/org-gnome-plugin-manager.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<Root>
- <commands>
- <cmd name="EPluginManagerManage" _label="Manage Plugins..."
- _tip="Enable and disable plugins"/>
- </commands>
-
- <menu>
- <submenu name="Tools">
- <placeholder name="ComponentPlaceholder"/>
- <menuitem name="EPluginManagerManage" verb=""/>
- </submenu>
- </menu>
-</Root>
diff --git a/plugins/plugin-manager/plugin-manager.c b/plugins/plugin-manager/plugin-manager.c
deleted file mode 100644
index 160783e856..0000000000
--- a/plugins/plugin-manager/plugin-manager.c
+++ /dev/null
@@ -1,289 +0,0 @@
-
-/* Copyright (C) 2004 Novell Inc.
- by Michael Zucchi <notzed@ximian.com> */
-
-/* This file is licensed under the GNU GPL v2 or later */
-
-/* A plugin manager ui */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <glib/gi18n-lib.h>
-#include <string.h>
-#include <stdio.h>
-
-#include <gtk/gtklabel.h>
-#include <gtk/gtktreeview.h>
-#include <gtk/gtktreeselection.h>
-#include <gtk/gtkliststore.h>
-#include <gtk/gtkdialog.h>
-#include <gtk/gtkscrolledwindow.h>
-#include <gtk/gtktable.h>
-#include <gtk/gtkcellrenderertoggle.h>
-#include <gtk/gtkcellrenderertext.h>
-#include <gtk/gtkstock.h>
-#include <gtk/gtkhbox.h>
-
-#include "e-util/e-plugin.h"
-#include "shell/es-menu.h"
-
-enum {
- LABEL_NAME,
- LABEL_AUTHOR,
- LABEL_ID,
- LABEL_PATH,
- LABEL_DESCRIPTION,
- LABEL_LAST
-};
-
-static struct {
- const char *label;
-} label_info[LABEL_LAST] = {
- { N_("Name"), },
- { N_("Author(s)"), },
- { N_("Id"), },
- { N_("Path"), },
- { N_("Description"), },
-};
-
-typedef struct _Manager Manager;
-struct _Manager {
- GtkDialog *dialog;
- GtkTreeView *tree;
- GtkListStore *model;
-
- GtkTable *table;
- GtkLabel *labels[LABEL_LAST];
- GtkLabel *items[LABEL_LAST];
-
- GSList *plugins;
-};
-
-/* for tracking if we're shown */
-static GtkDialog *dialog;
-
-void org_gnome_plugin_manager_manage(void *ep, ESMenuTargetShell *t);
-
-static void
-eppm_set_label(GtkLabel *l, const char *v)
-{
- gtk_label_set_label(l, v?v:_("Unknown"));
-}
-
-static void
-eppm_show_plugin(Manager *m, EPlugin *ep)
-{
- if (ep) {
- eppm_set_label(m->items[LABEL_NAME], ep->name);
- if (ep->authors) {
- GSList *l = ep->authors;
- GString *out = g_string_new("");
-
- for (;l;l = g_slist_next(l)) {
- EPluginAuthor *epa = l->data;
-
- if (l != ep->authors)
- g_string_append(out, ",\n");
- if (epa->name)
- g_string_append(out, epa->name);
- if (epa->email) {
- g_string_append(out, " <");
- g_string_append(out, epa->email);
- g_string_append(out, ">");
- }
- }
- gtk_label_set_label(m->items[LABEL_AUTHOR], out->str);
- g_string_free(out, TRUE);
- } else {
- eppm_set_label(m->items[LABEL_AUTHOR], NULL);
- }
-
- eppm_set_label(m->items[LABEL_ID], ep->id);
- eppm_set_label(m->items[LABEL_PATH], ep->path);
- eppm_set_label(m->items[LABEL_DESCRIPTION], ep->description);
- gtk_widget_set_sensitive((GtkWidget *)m->table, TRUE);
- } else {
- int i;
-
- for (i=0;i<LABEL_LAST;i++)
- gtk_label_set_label(m->items[i], "");
- gtk_widget_set_sensitive((GtkWidget *)m->table, FALSE);
- }
-}
-
-static void
-eppm_selection_changed(GtkTreeSelection *selection, Manager *m)
-{
- GtkTreeModel *model;
- GtkTreeIter iter;
-
- if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
- EPlugin *ep;
-
- gtk_tree_model_get(model, &iter, 2, &ep, -1);
- eppm_show_plugin(m, ep);
- } else {
- eppm_show_plugin(m, NULL);
- }
-}
-
-static void
-eppm_enable_toggled(GtkCellRendererToggle *renderer, char *arg1, Manager *m)
-{
- GtkTreeSelection *selection;
- GtkTreePath *path;
- GtkTreeIter iter;
- EPlugin *plugin;
-
- path = gtk_tree_path_new_from_string(arg1);
- selection = gtk_tree_view_get_selection(m->tree);
- if (gtk_tree_model_get_iter((GtkTreeModel *)m->model, &iter, path)) {
- gtk_tree_model_get((GtkTreeModel *)m->model, &iter, 2, &plugin, -1);
- e_plugin_enable(plugin, !plugin->enabled);
- gtk_list_store_set(m->model, &iter, 1, plugin->enabled, -1);
- }
- gtk_tree_path_free(path);
-}
-
-static void
-eppm_free(void *data)
-{
- Manager *m = data;
- GSList *l;
-
- for (l = m->plugins;l;l=g_slist_next(l))
- g_object_unref(l->data);
- g_slist_free(m->plugins);
-
- g_free(m);
-}
-
-static void
-eppm_response(GtkDialog *w, int button, Manager *m)
-{
- gtk_widget_destroy((GtkWidget*)w);
- dialog = NULL;
-}
-
-void
-org_gnome_plugin_manager_manage(void *ep, ESMenuTargetShell *t)
-{
- Manager *m;
- int i;
- GtkWidget *hbox, *w;
- GtkTreeSelection *selection;
- GtkCellRenderer *renderer;
- GSList *l;
-
- if (dialog) {
- gdk_window_raise(((GtkWidget *)dialog)->window);
- return;
- }
-
- m = g_malloc0(sizeof(*m));
-
- /* Setup the ui */
- m->dialog = (GtkDialog *)gtk_dialog_new_with_buttons(_("Plugin Manager"),
- (GtkWindow *)gtk_widget_get_toplevel(t->target.widget),
- GTK_DIALOG_DESTROY_WITH_PARENT,
- GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
- /* this isn't actually big enough, but oh well, i'll work out resizing later */
- gtk_window_set_default_size((GtkWindow *)m->dialog, 640, 400);
- g_object_set((GObject *)m->dialog, "has_separator", FALSE, NULL);
-
- hbox = gtk_hbox_new(FALSE, 0);
- gtk_container_set_border_width((GtkContainer *)hbox, 12);
- gtk_box_pack_start((GtkBox *)m->dialog->vbox, hbox, TRUE, TRUE, 0);
-
- w = g_object_new(gtk_label_get_type(),
- "label", _("Note: Some changes will not take effect until restart"),
- "wrap", TRUE,
- NULL);
- gtk_widget_show(w);
- gtk_box_pack_start((GtkBox *)m->dialog->vbox, w, FALSE, TRUE, 6);
-
- m->tree = (GtkTreeView *)gtk_tree_view_new();
-
- renderer = gtk_cell_renderer_text_new ();
- gtk_tree_view_insert_column_with_attributes(m->tree, -1, _("Plugin"), renderer, "text", 0, NULL);
- renderer = gtk_cell_renderer_toggle_new();
- /*g_object_set((GObject *)renderer, "activatable", TRUE, NULL);*/
- gtk_tree_view_insert_column_with_attributes(m->tree, -1, _("Enabled"), renderer, "active", 1, NULL);
- g_signal_connect(renderer, "toggled", G_CALLBACK(eppm_enable_toggled), m);
-
- w = gtk_scrolled_window_new(NULL, NULL);
- gtk_scrolled_window_set_policy((GtkScrolledWindow *)w, GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
- gtk_scrolled_window_set_shadow_type((GtkScrolledWindow *)w, GTK_SHADOW_IN);
- gtk_container_add((GtkContainer *)w, (GtkWidget *)m->tree);
- gtk_box_pack_start((GtkBox *)hbox, (GtkWidget *)w, FALSE, TRUE, 6);
-
- m->table = (GtkTable *)gtk_table_new(LABEL_LAST, 2, FALSE);
- gtk_table_set_col_spacings(m->table, 6);
- gtk_table_set_row_spacings(m->table, 6);
- for (i=0;i<LABEL_LAST;i++) {
- char *markup;
-
- markup = g_strdup_printf("<span weight=\"bold\">%s</span>", _(label_info[i].label));
- m->labels[i] = g_object_new(gtk_label_get_type(),
- "label", markup,
- "use_markup", TRUE,
- "xalign", 1.0,
- "yalign", 0.0, NULL);
- g_free(markup);
- gtk_table_attach(m->table, (GtkWidget *)m->labels[i], 0, 1, i, i+1, GTK_FILL, GTK_FILL, 0, 0);
- m->items[i] = g_object_new(gtk_label_get_type(),
- "wrap", TRUE,
- "selectable", TRUE,
- "xalign", 0.0,
- "yalign", 0.0, NULL);
- gtk_table_attach(m->table, (GtkWidget *)m->items[i], 1, 2, i, i+1, GTK_EXPAND|GTK_FILL, GTK_FILL, 0, 0);
- }
-
- gtk_box_pack_start((GtkBox *)hbox, (GtkWidget *)m->table, TRUE, TRUE, 6);
- gtk_widget_show_all(hbox);
-
- selection = gtk_tree_view_get_selection(m->tree);
- gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
- g_signal_connect(selection, "changed", G_CALLBACK(eppm_selection_changed), m);
-
- m->plugins = e_plugin_list_plugins();
- m->model = gtk_list_store_new(3, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_POINTER);
-
- for (l=m->plugins;l;l=g_slist_next(l)) {
- EPlugin *ep = l->data;
- GtkTreeIter iter;
-
- /* hide ourselves always */
- if (!strcmp(ep->id, "org.gnome.evolution.plugin.manager"))
- continue;
-
- gtk_list_store_append(m->model, &iter);
- gtk_list_store_set(m->model, &iter,
- 0, ep->name?ep->name:ep->id,
- 1, ep->enabled,
- 2, ep,
- -1);
- }
- gtk_tree_view_set_model(m->tree, (GtkTreeModel *)m->model);
-
- g_object_set_data_full((GObject *)m->dialog, "plugin-manager", m, eppm_free);
- g_signal_connect(m->dialog, "response", G_CALLBACK(eppm_response), m);
-
- gtk_widget_show((GtkWidget *)m->dialog);
-}
-
-int e_plugin_lib_enable(EPluginLib *ep, int enable);
-
-int
-e_plugin_lib_enable(EPluginLib *ep, int enable)
-{
- if (enable) {
- } else {
- /* This plugin can't be disabled ... */
- return -1;
- }
-
- return 0;
-}
diff --git a/plugins/prefer-plain/.cvsignore b/plugins/prefer-plain/.cvsignore
deleted file mode 100644
index 683d5ddbe2..0000000000
--- a/plugins/prefer-plain/.cvsignore
+++ /dev/null
@@ -1,5 +0,0 @@
-.deps
-.libs
-Makefile
-Makefile.in
-*.eplug \ No newline at end of file
diff --git a/plugins/prefer-plain/ChangeLog b/plugins/prefer-plain/ChangeLog
deleted file mode 100644
index 3ee452f207..0000000000
--- a/plugins/prefer-plain/ChangeLog
+++ /dev/null
@@ -1,13 +0,0 @@
-2004-11-01 JP Rosevear <jpr@novell.com>
-
- * Makefile.am: dist .eplug.in file
-
-2004-10-21 Not Zed <NotZed@Ximian.com>
-
- * prefer-plain.c (e_plugin_lib_enable): setup the right plugin
- init function.
-
-2004-10-20 Not Zed <NotZed@Ximian.com>
-
- * Imported prefer-plain plugin.
-
diff --git a/plugins/prefer-plain/Makefile.am b/plugins/prefer-plain/Makefile.am
deleted file mode 100644
index 2ff15c7f7a..0000000000
--- a/plugins/prefer-plain/Makefile.am
+++ /dev/null
@@ -1,13 +0,0 @@
-INCLUDES = \
- -I$(top_srcdir) \
- $(EVOLUTION_MAIL_CFLAGS)
-
-@EVO_PLUGIN_RULE@
-
-plugin_DATA = org-gnome-prefer-plain.eplug
-plugin_LTLIBRARIES = liborg-gnome-prefer-plain.la
-
-liborg_gnome_prefer_plain_la_SOURCES = prefer-plain.c
-liborg_gnome_prefer_plain_la_LDFLAGS = -module -avoid-version
-
-EXTRA_DIST = org-gnome-prefer-plain.eplug.in \ No newline at end of file
diff --git a/plugins/prefer-plain/org-gnome-prefer-plain.eplug.in b/plugins/prefer-plain/org-gnome-prefer-plain.eplug.in
deleted file mode 100644
index 06218f7972..0000000000
--- a/plugins/prefer-plain/org-gnome-prefer-plain.eplug.in
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0"?>
-<e-plugin-list>
- <e-plugin
- type="shlib"
- id="org.gnome.evolution.plugin.preferPlain"
- location="@PLUGINDIR@/liborg-gnome-prefer-plain.so"
- name="Prefer plain-text plugin"
- description="A test plugin which demonstrates a formatter plugin which lets you choose to disable HTML mails">
-
- <!-- hook into the 'html mail' preferences page -->
- <hook class="org.gnome.evolution.mail.config:1.0">
- <group target="prefs" id="org.gnome.evolution.mail.prefs">
- <!-- we could also just insert our own items from a section factory, -->
- <!-- but then we also need to create our own section frame -->
- <item type="section_table" path="10.html/80.mode" label="Plain Text Mode"/>
- <item type="item_table" path="10.html/80.mode/00.mode" factory="org_gnome_prefer_plain_config_mode"/>
- </group>
- </hook>
-
- <hook class="org.gnome.evolution.mail.format:1.0">
- <!-- need to override all formatters that override this type -->
- <group id="EMFormatHTMLDisplay">
- <item mime_type="multipart/alternative" format="org_gnome_prefer_plain_multipart_alternative"/>
- <item mime_type="text/html" format="org_gnome_prefer_plain_text_html"/>
- </group>
- <group id="EMFormat">
- <item mime_type="multipart/alternative" format="org_gnome_prefer_plain_multipart_alternative"/>
- <item mime_type="text/html" format="org_gnome_prefer_plain_text_html"/>
- </group>
- </hook>
-
- </e-plugin>
-</e-plugin-list>
diff --git a/plugins/prefer-plain/prefer-plain.c b/plugins/prefer-plain/prefer-plain.c
deleted file mode 100644
index bad2990e56..0000000000
--- a/plugins/prefer-plain/prefer-plain.c
+++ /dev/null
@@ -1,191 +0,0 @@
-
-/* Copyright (C) 2004 Michael Zucchi */
-
-/* This file is licensed under the GNU GPL v2 or later */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <glib/gi18n-lib.h>
-#include <string.h>
-#include <stdio.h>
-
-#include "camel/camel-multipart.h"
-#include "camel/camel-mime-part.h"
-#include "mail/em-format-hook.h"
-#include "mail/em-format.h"
-
-#include <gconf/gconf-client.h>
-#include <gtk/gtkcombobox.h>
-#include <gtk/gtkliststore.h>
-#include <gtk/gtkcellrenderertext.h>
-#include <gtk/gtkcelllayout.h>
-#include <gtk/gtktable.h>
-#include <gtk/gtklabel.h>
-#include "mail/em-config.h"
-
-void org_gnome_prefer_plain_multipart_alternative(void *ep, EMFormatHookTarget *t);
-void org_gnome_prefer_plain_text_html(void *ep, EMFormatHookTarget *t);
-GtkWidget *org_gnome_prefer_plain_config_mode(struct _EPlugin *epl, struct _EConfigHookItemFactoryData *data);
-
-enum {
- EPP_NORMAL,
- EPP_PREFER,
- EPP_TEXT
-};
-
-static GConfClient *epp_gconf;
-static int epp_mode;
-
-void
-org_gnome_prefer_plain_text_html(void *ep, EMFormatHookTarget *t)
-{
- /* In text-only mode, all html output is suppressed */
- if (epp_mode != EPP_TEXT)
- t->item->handler.old->handler(t->format, t->stream, t->part, t->item->handler.old);
- else
- em_format_part_as(t->format, t->stream, t->part, NULL);
-}
-
-void
-org_gnome_prefer_plain_multipart_alternative(void *ep, EMFormatHookTarget *t)
-{
- CamelMultipart *mp = (CamelMultipart *)camel_medium_get_content_object((CamelMedium *)t->part);
- CamelMimePart *part, *display_part = NULL;
- int i, nparts, partidlen, displayid = 0;
-
- if (epp_mode == EPP_NORMAL) {
- t->item->handler.old->handler(t->format, t->stream, t->part, t->item->handler.old);
- return;
- } else if (!CAMEL_IS_MULTIPART(mp)) {
- em_format_format_source(t->format, t->stream, t->part);
- return;
- }
-
- nparts = camel_multipart_get_number(mp);
- for (i=0; i<nparts; i++) {
- part = camel_multipart_get_part(mp, i);
- if (camel_content_type_is(camel_mime_part_get_content_type(part), "text", "plain")) {
- displayid = i;
- display_part = part;
- break;
- }
- }
-
- /* this part-id stuff is poking private data, needs api */
- partidlen = t->format->part_id->len;
-
- /* if we found a text part, show it */
- if (display_part) {
- g_string_append_printf(t->format->part_id, ".alternative.%d", displayid);
- em_format_part_as(t->format, t->stream, display_part, "text/plain");
- g_string_truncate(t->format->part_id, partidlen);
- }
-
- /* all other parts are attachments */
- for (i=0;i<nparts; i++) {
- part = camel_multipart_get_part(mp, i);
- if (part != display_part) {
- g_string_append_printf(t->format->part_id, ".alternative.%d", i);
-
- em_format_part_as(t->format, t->stream, t->part, NULL);
-
- g_string_truncate(t->format->part_id, partidlen);
- }
- }
-
- g_string_truncate(t->format->part_id, partidlen);
-}
-
-static struct {
- const char *label;
- const char *key;
-} epp_options[] = {
- { N_("Show HTML if present"), "normal" },
- { N_("Prefer PLAIN"), "prefer_plain" },
- { N_("Only ever show PLAIN"), "only_plain" },
-};
-
-static void
-epp_mode_changed(GtkComboBox *dropdown, void *dummy)
-{
- epp_mode = gtk_combo_box_get_active(dropdown);
- if (epp_mode > 2)
- epp_mode = 0;
-
- gconf_client_set_string(epp_gconf, "/apps/evolution/eplugin/prefer_plain/mode", epp_options[epp_mode].key, NULL);
-}
-
-GtkWidget *
-org_gnome_prefer_plain_config_mode(struct _EPlugin *epl, struct _EConfigHookItemFactoryData *data)
-{
- /*EMConfigTargetPrefs *ep = (EMConfigTargetPrefs *)data->target;*/
- GtkComboBox *dropdown;
- GtkCellRenderer *cell;
- GtkListStore *store;
- GtkWidget *w;
- int i;
- GtkTreeIter iter;
-
- if (data->old)
- return data->old;
-
- dropdown = (GtkComboBox *)gtk_combo_box_new();
- cell = gtk_cell_renderer_text_new();
- store = gtk_list_store_new(1, G_TYPE_STRING);
- for (i=0;i<sizeof(epp_options)/sizeof(epp_options[0]);i++) {
- gtk_list_store_append(store, &iter);
- gtk_list_store_set(store, &iter, 0, _(epp_options[i].label), -1);
- }
-
- gtk_cell_layout_pack_start((GtkCellLayout *)dropdown, cell, TRUE);
- gtk_cell_layout_set_attributes((GtkCellLayout *)dropdown, cell, "text", 0, NULL);
- gtk_combo_box_set_model(dropdown, (GtkTreeModel *)store);
- /*gtk_combo_box_set_active(dropdown, -1);*/
- gtk_combo_box_set_active(dropdown, epp_mode);
- g_signal_connect(dropdown, "changed", G_CALLBACK(epp_mode_changed), NULL);
- gtk_widget_show((GtkWidget *)dropdown);
-
- w = gtk_label_new(_("HTML Mode"));
- gtk_widget_show(w);
-
- i = ((GtkTable *)data->parent)->nrows;
- gtk_table_attach((GtkTable *)data->parent, w, 0, 1, i, i+1, 0, 0, 0, 0);
- gtk_table_attach((GtkTable *)data->parent, (GtkWidget *)dropdown, 1, 2, i, i+1, GTK_FILL|GTK_EXPAND, 0, 0, 0);
-
- /* since this isnt dynamic, we don't need to track each item */
-
- return (GtkWidget *)dropdown;
-}
-
-int e_plugin_lib_enable(EPluginLib *ep, int enable);
-
-int
-e_plugin_lib_enable(EPluginLib *ep, int enable)
-{
- char *key;
- int i;
-
- if (enable) {
- epp_gconf = gconf_client_get_default();
- key = gconf_client_get_string(epp_gconf, "/apps/evolution/eplugin/prefer_plain/mode", NULL);
- if (key) {
- for (i=0;i<sizeof(epp_options)/sizeof(epp_options[0]);i++) {
- if (!strcmp(epp_options[i].key, key)) {
- epp_mode = i;
- break;
- }
- }
- } else {
- epp_mode = 0;
- }
- } else {
- if (epp_gconf) {
- g_object_unref(epp_gconf);
- epp_gconf = 0;
- }
- }
-
- return 0;
-}
diff --git a/plugins/save-attachments/.cvsignore b/plugins/save-attachments/.cvsignore
deleted file mode 100644
index 683d5ddbe2..0000000000
--- a/plugins/save-attachments/.cvsignore
+++ /dev/null
@@ -1,5 +0,0 @@
-.deps
-.libs
-Makefile
-Makefile.in
-*.eplug \ No newline at end of file
diff --git a/plugins/save-attachments/ChangeLog b/plugins/save-attachments/ChangeLog
deleted file mode 100644
index d1182867a9..0000000000
--- a/plugins/save-attachments/ChangeLog
+++ /dev/null
@@ -1,24 +0,0 @@
-2005-02-07 Not Zed <NotZed@Ximian.com>
-
- * save-attachments.c (save_part): fix the access() call test.
-
-2005-01-04 Philip Van Hoof <pvanhoof@gnome.org>
-
- * save-attachments.c: Use standard error messages
-
-2004-12-27 Philip Van Hoof <pvanhoof@gnome.org>
-
- * save-attachments.c: Warning when overwriting file
-
-2004-11-01 JP Rosevear <jpr@novell.com>
-
- * Makefile.am: dist xml menu file
-
-2004-11-01 JP Rosevear <jpr@novell.com>
-
- * Makefile.am: dist .eplug.in file
-
-2004-10-20 Not Zed <NotZed@Ximian.com>
-
- * Imported save-attachments example plugin.
-
diff --git a/plugins/save-attachments/Makefile.am b/plugins/save-attachments/Makefile.am
deleted file mode 100644
index ec09b11e2c..0000000000
--- a/plugins/save-attachments/Makefile.am
+++ /dev/null
@@ -1,15 +0,0 @@
-INCLUDES = \
- -I$(top_srcdir) \
- $(EVOLUTION_MAIL_CFLAGS)
-
-@EVO_PLUGIN_RULE@
-
-plugin_DATA = org-gnome-save-attachments.eplug org-gnome-save-attachments.xml
-plugin_LTLIBRARIES = liborg-gnome-save-attachments.la
-
-liborg_gnome_save_attachments_la_SOURCES = save-attachments.c
-liborg_gnome_save_attachments_la_LDFLAGS = -module -avoid-version
-
-EXTRA_DIST = \
- org-gnome-save-attachments.eplug.in \
- org-gnome-save-attachments.xml \ No newline at end of file
diff --git a/plugins/save-attachments/org-gnome-save-attachments.eplug.in b/plugins/save-attachments/org-gnome-save-attachments.eplug.in
deleted file mode 100644
index 0e162665bd..0000000000
--- a/plugins/save-attachments/org-gnome-save-attachments.eplug.in
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0"?>
-<e-plugin-list>
- <!-- the path to the shared library -->
- <e-plugin
- id="org.gnome.plugin.attachments.save"
- type="shlib"
- location="@PLUGINDIR@/liborg-gnome-save-attachments.so"
- name="Save attachments plugin"
- description="A plugin for saving all attachments or parts of a message at once.">
- <hook class="org.gnome.evolution.mail.bonobomenu:1.0">
- <menu id="org.gnome.evolution.mail.browser" target="select">
- <!-- the path to the bonobo menu description -->
- <ui file="@PLUGINDIR@/org-gnome-save-attachments.xml"/>
- <item
- type="item"
- verb="EPSASaveAttachments"
- path="/commands/EPSASaveAttachments"
- enable="one"
- activate="org_gnome_save_attachments_save"/>
- </menu>
- </hook>
- </e-plugin>
-</e-plugin-list>
diff --git a/plugins/save-attachments/org-gnome-save-attachments.xml b/plugins/save-attachments/org-gnome-save-attachments.xml
deleted file mode 100644
index 449bd229c8..0000000000
--- a/plugins/save-attachments/org-gnome-save-attachments.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<Root>
- <commands>
- <cmd name="EPSASaveAttachments" _label="Save Attachments ..."
- _tip="Save all attachments"
- pixtype="stock" pixname="Save"/>
- </commands>
-
- <menu>
- <submenu name="Actions">
- <placeholder name="ComponentActionsPlaceholder">
- <placeholder name="MailMessageActions">
- <separator f="" name="emaillist5"/>
- <menuitem name="EPSASaveAttachments" verb=""/>
- </placeholder>
- </placeholder>
- </submenu>
-
- </menu>
-</Root>
diff --git a/plugins/save-attachments/save-attachments.c b/plugins/save-attachments/save-attachments.c
deleted file mode 100644
index 0cf8436273..0000000000
--- a/plugins/save-attachments/save-attachments.c
+++ /dev/null
@@ -1,403 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
- *
- * Authors: Michael Zucchi <notzed@ximian.com>
- *
- * Copyright 2004 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., 59 Temple Street #330, Boston, MA 02111-1307, USA.
- *
- */
-
-/* This is prototype code only, this may, or may not, use undocumented
- * unstable or private internal function calls. */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdio.h>
-
-#include <glib.h>
-#include <glib/gi18n.h>
-
-#include <gtk/gtkcheckbutton.h>
-#include <gtk/gtkdialog.h>
-#include <gtk/gtkmessagedialog.h>
-#include <gtk/gtktreestore.h>
-#include <gtk/gtkcellrenderertext.h>
-#include <gtk/gtkcellrenderertoggle.h>
-#include <gtk/gtkbox.h>
-#include <gtk/gtkstock.h>
-#include <gtk/gtktreeview.h>
-#include <gtk/gtkfilechooser.h>
-#include <gtk/gtkframe.h>
-#include <gtk/gtklabel.h>
-#include <gtk/gtkalignment.h>
-#include <gtk/gtkscrolledwindow.h>
-#include <libgnomeui/gnome-file-entry.h>
-
-#include <camel/camel-folder.h>
-#include <camel/camel-exception.h>
-#include <camel/camel-mime-message.h>
-#include <camel/camel-multipart.h>
-#include <camel/camel-utf8.h>
-
-#include "widgets/misc/e-error.h"
-
-#include "mail/em-menu.h"
-#include "mail/em-utils.h"
-
-/* these are sort of mail-internal */
-#include "mail/mail-mt.h"
-#include "mail/mail-ops.h"
-
-void org_gnome_save_attachments_save(EPlugin *ep, EMMenuTargetSelect *target);
-
-struct _save_data {
- CamelFolder *folder;
- char *uid;
- CamelMimeMessage *msg;
-
- char *path;
- char *base;
-
- GtkWidget *entry;
- GtkWidget *tree;
- GtkTreeStore *model;
-};
-
-static void
-free_data(struct _save_data *data)
-{
- if (data->msg)
- camel_object_unref(data->msg);
- g_free(data->base);
- g_free(data->path);
- g_free(data->uid);
- camel_object_unref(data->folder);
- g_free(data);
-}
-
-static char *
-clean_name(const char *s)
-{
- GString *out = g_string_new("");
- int c;
- char *r;
-
- while ( (c = camel_utf8_getc((const unsigned char **)&s)) ) {
- if (!g_unichar_isprint(c) || ( c < 0x7f && strchr(" /'\"`&();|<>$%{}!", c )))
- c = '_';
- g_string_append_u(out, c);
- }
-
- r = g_strdup(out->str);
- g_string_free(out, TRUE);
-
- return r;
-}
-
-static void
-fill_model_rec(CamelMimeMessage *msg, CamelMimePart *part, GtkTreeStore *model, GtkTreeIter *parent, GString *name)
-{
- CamelDataWrapper *containee;
- int parts, i;
- char *type;
- GtkTreeIter iter;
- int len = name->len;
- CamelContentType *mime;
-
- containee = camel_medium_get_content_object((CamelMedium *)part);
- if (containee == NULL)
- return;
-
- mime = ((CamelDataWrapper *)containee)->mime_type;
- type = camel_content_type_simple(mime);
-
- if (CAMEL_IS_MULTIPART(containee)) {
- gtk_tree_store_append(model, &iter, parent);
- g_string_append_printf(name, ".multipart");
- gtk_tree_store_set(model, &iter, 0, FALSE, 1, type, 2, name->str, 3, name->str, 4, part, -1);
-
- parts = camel_multipart_get_number((CamelMultipart *)containee);
- for (i = 0; i < parts; i++) {
- CamelMimePart *mpart = camel_multipart_get_part((CamelMultipart *)containee, i);
-
- g_string_truncate(name, len);
- g_string_append_printf(name, ".%d", i);
- fill_model_rec(msg, mpart, model, &iter, name);
- }
- } else if (CAMEL_IS_MIME_MESSAGE(containee)) {
- gtk_tree_store_append(model, &iter, parent);
- g_string_append_printf(name, ".msg");
- gtk_tree_store_set(model, &iter, 0, FALSE, 1, type, 2, name->str, 3, name->str, 4, part, -1);
- fill_model_rec(msg, (CamelMimePart *)containee, model, &iter, name);
- } else {
- char *filename = NULL;
- const char *ext = NULL, *tmp;
- int save = FALSE;
-
- gtk_tree_store_append(model, &iter, parent);
- tmp = camel_mime_part_get_filename(part);
- if (tmp) {
- filename = clean_name(tmp);
- ext = strrchr(filename, '.');
- }
- tmp = camel_mime_part_get_disposition(part);
- if (tmp && !strcmp(tmp, "attachment"))
- save = TRUE;
-
- if (camel_content_type_is(mime, "text", "*")) {
- if (ext == NULL) {
- if ((ext = mime->subtype) == NULL || !strcmp(ext, "plain"))
- ext = "text";
- }
- } else if (camel_content_type_is(mime, "image", "*")) {
- if (ext == NULL) {
- if ((ext = mime->subtype) == NULL)
- ext = "image";
- }
- save = TRUE;
- }
-
- g_string_append_printf(name, ".%s", ext);
- gtk_tree_store_set(model, &iter, 0, save, 1, type, 2, filename?filename:name->str, 3, filename?NULL:name->str, 4, part, -1);
- g_free(filename);
- }
- g_free(type);
-
- g_string_truncate(name, len);
-}
-
-static void
-fill_model(CamelMimeMessage *msg, GtkTreeStore *model)
-{
- GString *name = g_string_new("");
- GtkTreeIter iter;
-
- gtk_tree_store_append(model, &iter, NULL);
- gtk_tree_store_set(model, &iter, 0, FALSE, 1, "message/rfc822", 2, ".msg", 3, ".msg", 4, msg, -1);
- fill_model_rec(msg, (CamelMimePart *)msg, model, &iter, name);
- g_string_free(name, TRUE);
-}
-
-static gboolean
-save_part(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, void *d)
-{
- struct _save_data *data = d;
- char *filename, *ext, *save;
- CamelMimePart *part;
- gboolean doit;
-
- /* TODO: check for existing file */
-
- gtk_tree_model_get(model, iter, 0, &doit, -1);
- if (!doit)
- return FALSE;
-
- gtk_tree_model_get(model, iter, 2, &filename, 3, &ext, 4, &part, -1);
- if (ext == NULL)
- save = g_build_filename(data->path, filename, NULL);
- else
- save = g_strdup_printf("%s%s", data->base, ext);
-
- /* FIXME: if part == data->msg then we need to save this
- * differently, not using the envelope MimePart */
-
- /*
- * The underlying em_utils_save_part_to_file ain't using gnome-vfs. Therefor
- * the POSIX access-call should suffice for checking the file existence.
- */
-
- if (access(save, F_OK) == 0)
- doit = e_error_run(NULL, E_ERROR_ASK_FILE_EXISTS_OVERWRITE, save, NULL) == GTK_RESPONSE_OK;
-
- if (doit)
- em_utils_save_part_to_file(NULL, save, part);
-
- g_free(ext);
- g_free(filename);
-
- return FALSE;
-}
-
-static void
-save_response(GtkWidget *d, int id, struct _save_data *data)
-{
- if (id == GTK_RESPONSE_OK) {
- char *tmp;
-
- data->base = gnome_file_entry_get_full_path((GnomeFileEntry *)data->entry, FALSE);
- data->path = g_strdup(data->base);
- tmp = strrchr(data->path, '/');
- if (tmp)
- *tmp = 0;
- gtk_tree_model_foreach((GtkTreeModel *)data->model, save_part, data);
- }
-
- gtk_widget_destroy(d);
- free_data(data);
-}
-
-static gboolean
-entry_changed_update(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, void *d)
-{
- const char *name = d;
- char *filename, *ext;
-
- gtk_tree_model_get(model, iter, 3, &ext, -1);
- if (ext) {
- filename = g_strdup_printf("%s%s", name, ext);
- gtk_tree_store_set((GtkTreeStore *)model, iter, 2, filename, -1);
- g_free(filename);
- g_free(ext);
- }
-
- return FALSE;
-}
-
-static void
-entry_changed(GtkWidget *entry, struct _save_data *data)
-{
- char *path;
- const char *file;
- struct stat st;
-
- path = gnome_file_entry_get_full_path((GnomeFileEntry *)data->entry, FALSE);
- if (path == NULL
- || (file = strrchr(path, '/')) == NULL
- || file[1] == 0
- || (stat(path, &st) == 0 && S_ISDIR(st.st_mode)))
- file = "attachment";
- else
- file++;
-
- gtk_tree_model_foreach((GtkTreeModel *)data->model, entry_changed_update, (void *)file);
- g_free(path);
-}
-
-static void
-toggle_changed(GtkWidget *entry, const char *spath, struct _save_data *data)
-{
- GtkTreePath *path;
- GtkTreeIter iter;
-
- path = gtk_tree_path_new_from_string(spath);
- if (gtk_tree_model_get_iter((GtkTreeModel *)data->model, &iter, path)) {
- gboolean on;
-
- gtk_tree_model_get((GtkTreeModel *)data->model, &iter, 0, &on, -1);
- gtk_tree_store_set(data->model, &iter, 0, !on, -1);
- }
-
- gtk_tree_path_free (path);
-}
-
-static void
-save_got_message(CamelFolder *folder, const char *uid, CamelMimeMessage *msg, void *d)
-{
- struct _save_data *data = d;
- GtkDialog *dialog;
- GtkWidget *w, *tree;
- GtkTreeStore *model;
- GtkCellRenderer *renderer;
-
- /* not found, the mailer will show an error box for this */
- if (msg == NULL) {
- free_data(data);
- return;
- }
-
- data->msg = msg;
- camel_object_ref(msg);
-
- dialog = (GtkDialog *)gtk_dialog_new_with_buttons("Save attachments",
- NULL, /* target->parent? */
- 0,
- GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
- GTK_STOCK_SAVE, GTK_RESPONSE_OK,
- NULL);
- w = gnome_file_entry_new("save-attachments", _("Select save base name"));
- data->entry = w;
- g_object_set(w, "filechooser_action", GTK_FILE_CHOOSER_ACTION_SAVE, NULL);
- gtk_widget_show(w);
- gtk_box_pack_start((GtkBox *)dialog->vbox, w, FALSE, TRUE, 6);
-
- w = gnome_file_entry_gtk_entry((GnomeFileEntry *)data->entry);
- g_signal_connect(w, "changed", G_CALLBACK(entry_changed), data);
-
- model = gtk_tree_store_new(5, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER);
- data->model = model;
- fill_model(msg, model);
-
- tree = gtk_tree_view_new_with_model((GtkTreeModel *)model);
- data->tree = tree;
- gtk_widget_show(tree);
- gtk_tree_view_expand_all((GtkTreeView *)tree);
-
- renderer = gtk_cell_renderer_text_new();
- gtk_tree_view_insert_column_with_attributes((GtkTreeView *)tree, -1,
- _("MIME Type"), renderer, "text", 1, NULL);
- gtk_tree_view_set_expander_column((GtkTreeView *)tree, gtk_tree_view_get_column((GtkTreeView *)tree, 0));
-
- renderer = gtk_cell_renderer_toggle_new();
- g_object_set(renderer, "activatable", TRUE, NULL);
- g_signal_connect(renderer, "toggled", G_CALLBACK(toggle_changed), data);
-
- gtk_tree_view_insert_column_with_attributes((GtkTreeView *)tree, -1,
- _("Save"), renderer, "active", 0, NULL);
- renderer = gtk_cell_renderer_text_new();
- gtk_tree_view_insert_column_with_attributes((GtkTreeView *)tree, -1,
- _("Name"), renderer, "text", 2, NULL);
-
- w = g_object_new(gtk_frame_get_type(),
- "shadow_type", GTK_SHADOW_NONE,
- "label_widget", g_object_new(gtk_label_get_type(),
- "label", "<span weight=\"bold\">Attachments</span>",
- "use_markup", TRUE,
- "xalign", 0.0, NULL),
- "child", g_object_new(gtk_alignment_get_type(),
- "left_padding", 12,
- "top_padding", 6,
- "child", g_object_new(gtk_scrolled_window_get_type(),
- "hscrollbar_policy", GTK_POLICY_AUTOMATIC,
- "vscrollbar_policy", GTK_POLICY_AUTOMATIC,
- "shadow_type", GTK_SHADOW_IN,
- "child", tree,
- NULL),
- NULL),
- NULL);
- gtk_widget_show_all(w);
-
- gtk_box_pack_start((GtkBox *)dialog->vbox, w, TRUE, TRUE, 0);
- g_signal_connect(dialog, "response", G_CALLBACK(save_response), data);
- gtk_window_set_default_size((GtkWindow *)dialog, 500, 500);
- gtk_widget_show((GtkWidget *)dialog);
-}
-
-void
-org_gnome_save_attachments_save(EPlugin *ep, EMMenuTargetSelect *target)
-{
- struct _save_data *data;
-
- if (target->uids->len != 1)
- return;
-
- data = g_malloc0(sizeof(*data));
- data->folder = target->folder;
- camel_object_ref(data->folder);
- data->uid = g_strdup(target->uids->pdata[0]);
-
- mail_get_message(data->folder, data->uid, save_got_message, data, mail_thread_new);
-}
diff --git a/plugins/save-calendar/.cvsignore b/plugins/save-calendar/.cvsignore
deleted file mode 100644
index 683d5ddbe2..0000000000
--- a/plugins/save-calendar/.cvsignore
+++ /dev/null
@@ -1,5 +0,0 @@
-.deps
-.libs
-Makefile
-Makefile.in
-*.eplug \ No newline at end of file
diff --git a/plugins/save-calendar/ChangeLog b/plugins/save-calendar/ChangeLog
deleted file mode 100644
index acfee8b0ca..0000000000
--- a/plugins/save-calendar/ChangeLog
+++ /dev/null
@@ -1,51 +0,0 @@
-2005-01-05 JP Rosevear <jpr@novell.com>
-
- * save-calendar.c (ask_destination_and_save): fix build for non
- gtk file chooser case
-
-2005-01-04 Philip Van Hoof <pvanhoof@gnome.org>
-
- * csv-format.c, rdf-format.c: Use standard error messages
-
-2004-12-27 Philip Van Hoof <pvanhoof@gnome.org>
-
- * csv-format.c, rdf-format.c: Warning when overwriting file
-
-2004-12-22 JP Rosevear <jpr@novell.com>
-
- * Makefile.am: list format-handler.h as a source so it dists
-
-2004-12-20 Philip Van Hoof <pvanhoof@gnome.org>
-
- * Makefile.am: Code splitup, each format has it's own c-file
- * csv-format.c: Added. Code splitup
- * format-handler.h: Added. Code splitup
- * ical-format.c: Added. Code splitup
- * rdf-format.c: Added. Support for RDF files. Code splitup
- * save-calendar.c: Support for RDF files. Code splitup
-
-2004-11-30 Philip Van Hoof <pvanhoof@gnome.org>
-
- * save-calendar.c: Support for CSV files
-
-2004-11-01 JP Rosevear <jpr@novell.com>
-
- * Makefile.am: dist .eplug.in file
-
-2004-10-21 Rodrigo Moya <rodrigo@novell.com>
-
- * save-calendar.c (do_save_calendar): get error information in
- e_cal_* calls, and display errors to the user.
-
-2004-10-21 JP Rosevear <jpr@novell.com>
-
- * save-calendar.c (do_save_calendar): compile if not using file
- chooser
-
-2004-10-21 Rodrigo Moya <rodrigo@novell.com>
-
- * org-gnome-save-calendar.eplug.in: better menu items.
-
-2004-10-21 Rodrigo Moya <rodrigo@novell.com>
-
- * save-calendar.c: new plugin for saving a calendar to disk.
diff --git a/plugins/save-calendar/Makefile.am b/plugins/save-calendar/Makefile.am
deleted file mode 100644
index 5470974673..0000000000
--- a/plugins/save-calendar/Makefile.am
+++ /dev/null
@@ -1,19 +0,0 @@
-INCLUDES = \
- -I$(top_srcdir) \
- $(EVOLUTION_CALENDAR_CFLAGS)
-
-@EVO_PLUGIN_RULE@
-
-plugin_DATA = org-gnome-save-calendar.eplug
-plugin_LTLIBRARIES = liborg-gnome-save-calendar.la
-
-liborg_gnome_save_calendar_la_SOURCES = \
- save-calendar.c \
- ical-format.c \
- csv-format.c \
- rdf-format.c \
- format-handler.h
-
-liborg_gnome_save_calendar_la_LDFLAGS = -module -avoid-version
-
-EXTRA_DIST = org-gnome-save-calendar.eplug.in
diff --git a/plugins/save-calendar/csv-format.c b/plugins/save-calendar/csv-format.c
deleted file mode 100644
index 80a32d2386..0000000000
--- a/plugins/save-calendar/csv-format.c
+++ /dev/null
@@ -1,576 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
- *
- * Authors: Philip Van Hoof <pvanhoof@gnome.org>
- *
- * Copyright 2004 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., 59 Temple Street #330, Boston, MA 02111-1307, USA.
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <glib.h>
-#include <glib/gi18n.h>
-#ifdef USE_GTKFILECHOOSER
-# include <gtk/gtkfilechooser.h>
-# include <gtk/gtkfilechooserdialog.h>
-#else
-# include <gtk/gtkfilesel.h>
-#endif
-#include <gtk/gtkmessagedialog.h>
-#include <gtk/gtkstock.h>
-#include <gtk/gtk.h>
-#include <libedataserver/e-source.h>
-#include <libedataserverui/e-source-selector.h>
-#include <libecal/e-cal.h>
-#include <calendar/gui/e-cal-popup.h>
-#include <libgnomevfs/gnome-vfs.h>
-#include <string.h>
-
-#include "widgets/misc/e-error.h"
-
-#include "format-handler.h"
-
-typedef struct _CsvConfig CsvConfig;
-struct _CsvConfig {
- gchar *newline;
- gchar *quote;
- gchar *delimiter;
- gboolean header;
-};
-
-static gboolean string_needsquotes (const char *value, CsvConfig *config);
-
-typedef struct _CsvPluginData CsvPluginData;
-struct _CsvPluginData
-{
- GtkWidget *delimiter_entry, *newline_entry, *quote_entry, *header_check;
-};
-
-static void
-display_error_message (GtkWidget *parent, GError *error)
-{
- GtkWidget *dialog;
-
- dialog = gtk_message_dialog_new (GTK_WINDOW (parent), 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
- error->message);
- gtk_dialog_run (GTK_DIALOG (dialog));
- gtk_widget_destroy (dialog);
-}
-
-
-enum { /* CSV helper enum */
- ECALCOMPONENTTEXT,
- ECALCOMPONENTATTENDEE,
- CONSTCHAR
-};
-
-
-
-/* Some helpers for the csv stuff */
-static GString *
-add_list_to_csv (GString *line, GSList *list_in, CsvConfig *config, gint type)
-{
-
- /*
- * This one will write 'ECalComponentText' and 'const char' GSLists. It will
- * put quotes around the complete written value if there's was only one value
- * but it required having quotes and if there was more than one value (in which
- * case delimiters are used to separate them, hence the need for the quotes).
- */
-
- if (list_in) {
- gboolean needquotes = FALSE;
- GSList *list = list_in;
- GString *tmp = NULL;
- gint cnt=0;
- while (list) {
- const char *str = NULL;
- if (cnt == 0)
- tmp = g_string_new ("");
- if (cnt > 0)
- needquotes = TRUE;
- switch (type) {
- case ECALCOMPONENTATTENDEE:
- str = ((ECalComponentAttendee*)list->data)->value;
- break;
- case ECALCOMPONENTTEXT:
- str = ((ECalComponentText*)list->data)->value;
- break;
- case CONSTCHAR:
- default:
- str = list->data;
- break;
- }
- if (!needquotes)
- needquotes = string_needsquotes (str, config);
- if (str)
- tmp = g_string_append (tmp, (const gchar*)str);
- list = g_slist_next (list); cnt++;
- if (list)
- tmp = g_string_append (tmp, config->delimiter);
- }
-
- if (needquotes)
- line = g_string_append (line, config->quote);
- line = g_string_append_len (line, tmp->str, tmp->len);
- g_string_free (tmp, TRUE);
- if (needquotes)
- line = g_string_append (line, config->quote);
- }
-
- line = g_string_append (line, config->delimiter);
- return line;
-}
-
-static GString *
-add_nummeric_to_csv (GString *line, gint *nummeric, CsvConfig *config)
-{
-
- /*
- * This one will write {-1}..{00}..{01}..{99}
- * it prepends a 0 if it's < 10 and > -1
- */
-
- if (nummeric)
- g_string_append_printf (line, "%s%d", (*nummeric<10 && *nummeric>-1)?"0":"", *nummeric);
-
- line = g_string_append (line, config->delimiter);
- return line;
-}
-
-static GString *
-add_time_to_csv (GString *line, icaltimetype *time, CsvConfig *config)
-{
- /*
- * Perhaps we should check for quotes, delimiter and newlines in the
- * resulting string: The translators can put it there!
- *
- * Or perhaps we shouldn't make this translatable?
- * Or perhaps there is a library-function to do this?
- */
-
- if (time) {
- g_string_append_printf (line, _("%s%d/%s%d/%s%d %s%d:%s%d:%s%d"),
- (time->month < 10)?"0":"", time->month,
- (time->day < 10)?"0":"", time->day,
- (time->year < 10)?"0":"", time->year,
- (time->hour < 10)?"0":"", time->hour,
- (time->minute < 10)?"0":"", time->minute,
- (time->second < 10)?"0":"", time->second);
- }
-
- line = g_string_append (line, config->delimiter);
- return line;
-}
-
-static gboolean
-string_needsquotes (const char *value, CsvConfig *config)
-{
-
- /* This is the actual need for quotes-checker */
-
- /*
- * These are the simple substring-checks
- *
- * Example: {Mom, can you please do that for me?}
- * Will be written as {"Mom, can you please do that for me?"}
- */
-
- gboolean needquotes = strstr (value, config->delimiter) ? TRUE:FALSE;
-
- if (!needquotes) {
- needquotes = strstr (value, config->newline) ? TRUE:FALSE;
- if (!needquotes)
- needquotes = strstr (value, config->quote) ? TRUE:FALSE;
- }
-
-
- /*
- * If the special-char is char+onespace (so like {, } {" }, {\n }) and it occurs
- * the value that is going to be written
- *
- * In this case we don't trust the user . . . and are going to quote the string
- * just to play save -- Quoting is always allowed in the CSV format. If you can
- * avoid it, it's better to do so since a lot applications don't support CSV
- * correctly! --.
- *
- * Example: {Mom,can you please do that for me?}
- * This example will be written as {"Mom,can you please do that for me?"} because
- * there's a {,} behind {Mom} and the delimiter is {, } (so we searched only the
- * first character of {, } and didn't trust the user).
- */
-
-
- if (!needquotes) {
- gint len = strlen (config->delimiter);
- if ((len == 2) && (config->delimiter[1] = ' ')) {
- needquotes = strchr (value, config->delimiter[0])?TRUE:FALSE;
- if (!needquotes) {
- gint len = strlen (config->newline);
- if ((len == 2) && (config->newline[1] = ' ')) {
- needquotes = strchr (value, config->newline[0])?TRUE:FALSE;
- if (!needquotes) {
- gint len = strlen (config->quote);
- if ((len == 2) && (config->quote[1] = ' ')) {
- needquotes = strchr
- (value, config->quote[0])?TRUE:FALSE;
- }
- }
- }
- }
- }
- }
-
- return needquotes;
-}
-
-static GString *
-add_string_to_csv (GString *line, const char *value, CsvConfig *config)
-{
- /* Will add a string to the record and will check for the need for quotes */
-
- if ((value) && (strlen(value)>0)) {
- gboolean needquotes = string_needsquotes (value, config);
-
- if (needquotes)
- line = g_string_append (line, config->quote);
- line = g_string_append (line, (const gchar*)value);
- if (needquotes)
- line = g_string_append (line, config->quote);
- }
- line = g_string_append (line, config->delimiter);
- return line;
-}
-
-/* Convert what the user types to what he probably means */
-static gchar *
-userstring_to_systemstring (const gchar *userstring)
-{
- const gchar *text = userstring;
- gint i=0, len = strlen(text);
- GString *str = g_string_new ("");
- gchar *retval = NULL;
-
- while (i < len) {
- if (text[i] == '\\') {
- switch (text[i+1]) {
- case 'n':
- str = g_string_append_c (str, '\n');
- i++;
- break;
- case '\\':
- str = g_string_append_c (str, '\\');
- i++;
- break;
- case 'r':
- str = g_string_append_c (str, '\r');
- i++;
- break;
- case 't':
- str = g_string_append_c (str, '\t');
- i++;
- break;
- }
- } else {
- str = g_string_append_c (str, text[i]);
- }
-
- i++;
- }
-
- retval = str->str;
- g_string_free (str, FALSE);
-
- return retval;
-}
-
-static void
-do_save_calendar_csv (FormatHandler *handler, EPlugin *ep, ECalPopupTargetSource *target, ECalSourceType type, char *dest_uri)
-{
-
- /*
- * According to some documentation about CSV, newlines 'are' allowed
- * in CSV-files. But you 'do' have to put the value between quotes.
- * The helper 'string_needsquotes' will check for that
- *
- * http://www.creativyst.com/Doc/Articles/CSV/CSV01.htm
- * http://www.creativyst.com/cgi-bin/Prod/15/eg/csv2xml.pl
- */
-
- ESource *primary_source;
- ECal *source_client;
- GError *error = NULL;
- GList *objects=NULL;
- GnomeVFSResult result;
- GnomeVFSHandle *handle;
- GnomeVFSURI *uri;
- GString *line = NULL;
- CsvConfig *config = NULL;
- CsvPluginData *d = handler->data;
- const gchar *tmp = NULL;
- gboolean doit = TRUE;
-
- if (!dest_uri)
- return;
-
- primary_source = e_source_selector_peek_primary_selection (target->selector);
-
- /* open source client */
- source_client = e_cal_new (primary_source, type);
- if (!e_cal_open (source_client, TRUE, &error)) {
- display_error_message (gtk_widget_get_toplevel (GTK_WIDGET (target->selector)), error);
- g_object_unref (source_client);
- g_error_free (error);
- return;
- }
-
- config = g_new (CsvConfig, 1);
-
- tmp = gtk_entry_get_text (GTK_ENTRY(d->delimiter_entry));
- config->delimiter = userstring_to_systemstring (tmp?tmp:", ");
- tmp = gtk_entry_get_text (GTK_ENTRY(d->newline_entry));
- config->newline = userstring_to_systemstring (tmp?tmp:"\\n");
- tmp = gtk_entry_get_text (GTK_ENTRY(d->quote_entry));
- config->quote = userstring_to_systemstring (tmp?tmp:"\"");
- config->header = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (d->header_check));
-
- uri = gnome_vfs_uri_new (dest_uri);
-
- result = gnome_vfs_open_uri (&handle, uri, GNOME_VFS_OPEN_READ);
- if (result == GNOME_VFS_OK)
- doit = e_error_run(gtk_widget_get_toplevel (GTK_WIDGET (target->selector)),
- E_ERROR_ASK_FILE_EXISTS_OVERWRITE, dest_uri, NULL) == GTK_RESPONSE_OK;
-
- if (doit) {
- result = gnome_vfs_open_uri (&handle, uri, GNOME_VFS_OPEN_WRITE);
- if (result != GNOME_VFS_OK) {
- gnome_vfs_create (&handle, dest_uri, GNOME_VFS_OPEN_WRITE, TRUE, GNOME_VFS_PERM_USER_ALL);
- result = gnome_vfs_open_uri (&handle, uri, GNOME_VFS_OPEN_WRITE);
- }
- }
-
- if (result == GNOME_VFS_OK && doit && e_cal_get_object_list_as_comp (source_client, "#t", &objects, NULL)) {
-
- if (config->header) {
- line = g_string_new ("");
- g_string_append_printf (line, _("Uid%sSummary%sDescription List%sCategories List%s"
- "Comment List%sCompleted%sCreated%sContact List%s"
- "Start%sEnd%sDue%sPercent Done%sPriority%sUrl%s"
- "Attendees List%sLocation%sModified%s"),
- config->delimiter, config->delimiter, config->delimiter, config->delimiter,
- config->delimiter, config->delimiter, config->delimiter, config->delimiter,
- config->delimiter, config->delimiter, config->delimiter, config->delimiter,
- config->delimiter, config->delimiter, config->delimiter, config->delimiter,
- config->newline);
-
- gnome_vfs_write (handle, line->str, line->len, NULL);
- g_string_free (line, TRUE);
- }
-
-
- while (objects != NULL) {
- ECalComponent *comp = objects->data;
- gchar *delimiter_temp = NULL;
- const char *temp_constchar;
- GSList *temp_list;
- ECalComponentDateTime temp_dt;
- struct icaltimetype *temp_time;
- int *temp_int;
- ECalComponentText temp_comptext;
-
- line = g_string_new ("");
-
- /* Getting the stuff */
- e_cal_component_get_uid (comp, &temp_constchar);
- line = add_string_to_csv (line, temp_constchar, config);
-
- e_cal_component_get_summary (comp, &temp_comptext);
- line = add_string_to_csv (line, &temp_comptext?temp_comptext.value:NULL, config);
-
- e_cal_component_get_description_list (comp, &temp_list);
- line = add_list_to_csv (line, temp_list, config, ECALCOMPONENTTEXT);
- if (temp_list)
- e_cal_component_free_text_list (temp_list);
-
- e_cal_component_get_categories_list (comp, &temp_list);
- line = add_list_to_csv (line, temp_list, config, CONSTCHAR);
- if (temp_list)
- e_cal_component_free_categories_list (temp_list);
-
- e_cal_component_get_comment_list (comp, &temp_list);
- line = add_list_to_csv (line, temp_list, config, ECALCOMPONENTTEXT);
- if (temp_list)
- e_cal_component_free_text_list (temp_list);
-
- e_cal_component_get_completed (comp, &temp_time);
- line = add_time_to_csv (line, temp_time, config);
- if (temp_time)
- e_cal_component_free_icaltimetype (temp_time);
-
- e_cal_component_get_created (comp, &temp_time);
- line = add_time_to_csv (line, temp_time, config);
- if (temp_time)
- e_cal_component_free_icaltimetype (temp_time);
-
- e_cal_component_get_contact_list (comp, &temp_list);
- line = add_list_to_csv (line, temp_list, config, ECALCOMPONENTTEXT);
- if (temp_list)
- e_cal_component_free_text_list (temp_list);
-
- e_cal_component_get_dtstart (comp, &temp_dt);
- line = add_time_to_csv (line, temp_dt.value ? temp_dt.value : NULL, config);
- if (temp_dt.value)
- e_cal_component_free_datetime (&temp_dt);
-
- e_cal_component_get_dtend (comp, &temp_dt);
- line = add_time_to_csv (line, temp_dt.value ? temp_dt.value : NULL, config);
- if (temp_dt.value)
- e_cal_component_free_datetime (&temp_dt);
-
- e_cal_component_get_due (comp, &temp_dt);
- line = add_time_to_csv (line, temp_dt.value ? temp_dt.value : NULL, config);
- if (temp_dt.value)
- e_cal_component_free_datetime (&temp_dt);
-
- e_cal_component_get_percent (comp, &temp_int);
- line = add_nummeric_to_csv (line, temp_int, config);
-
- e_cal_component_get_priority (comp, &temp_int);
- line = add_nummeric_to_csv (line, temp_int, config);
-
- e_cal_component_get_url (comp, &temp_constchar);
- line = add_string_to_csv (line, temp_constchar, config);
-
- if (e_cal_component_has_attendees (comp)) {
- e_cal_component_get_attendee_list (comp, &temp_list);
- line = add_list_to_csv (line, temp_list, config, ECALCOMPONENTATTENDEE);
- if (temp_list)
- e_cal_component_free_attendee_list (temp_list);
- } else {
- line = add_list_to_csv (line, NULL, config, ECALCOMPONENTATTENDEE);
- }
-
- e_cal_component_get_location (comp, &temp_constchar);
- line = add_string_to_csv (line, temp_constchar, config);
-
- e_cal_component_get_last_modified (comp, &temp_time);
-
- /* Append a newline (record delimiter) */
- delimiter_temp = config->delimiter;
- config->delimiter = config->newline;
-
- line = add_time_to_csv (line, temp_time, config);
-
- /* And restore for the next record */
- config->delimiter = delimiter_temp;
-
- /* Important note!
- * The documentation is not requiring this!
- *
- * if (temp_time) e_cal_component_free_icaltimetype (temp_time);
- *
- * Please uncomment and fix documentation if untrue
- * http://www.gnome.org/projects/evolution/developer-doc/libecal/ECalComponent.html
- * #e-cal-component-get-last-modified
- */
- gnome_vfs_write (handle, line->str, line->len, NULL);
-
- /* It's written, so we can free it */
- g_string_free (line, TRUE);
-
- objects = g_list_next (objects);
- }
-
- gnome_vfs_close (handle);
- }
-
- g_object_unref (source_client);
-
- g_free (config->delimiter);
- g_free (config->quote);
- g_free (config->newline);
- g_free (config);
-
- return;
-}
-
-
-
-
-
-static GtkWidget *
-create_options_widget (FormatHandler *handler)
-{
- GtkWidget *table = gtk_table_new (4, 2, FALSE), *label = NULL,
- *csv_options = gtk_expander_new (_("Advanced options for the CSV format")),
- *vbox = gtk_vbox_new (FALSE, 0);
- CsvPluginData *d = handler->data;
-
- d->delimiter_entry = gtk_entry_new ();
- d->newline_entry = gtk_entry_new ();
- d->quote_entry = gtk_entry_new ();
- d->header_check = gtk_check_button_new_with_label (_("Prepend a header"));
-
- /* Advanced CSV options */
- gtk_entry_set_text (GTK_ENTRY(d->delimiter_entry), ", ");
- gtk_entry_set_text (GTK_ENTRY(d->quote_entry), "\"");
- gtk_entry_set_text (GTK_ENTRY(d->newline_entry), "\\n");
-
- gtk_table_set_row_spacings (GTK_TABLE (table), 5);
- gtk_table_set_col_spacings (GTK_TABLE (table), 5);
- label = gtk_label_new (_("Value delimiter:"));
- gtk_misc_set_alignment (GTK_MISC (label), 0, 0.0);
- gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
- (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0);
- gtk_table_attach (GTK_TABLE (table), d->delimiter_entry, 1, 2, 0, 1,
- (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), (GtkAttachOptions) (0), 0, 0);
- label = gtk_label_new (_("Record delimiter:"));
- gtk_misc_set_alignment (GTK_MISC (label), 0, 0.0);
- gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2,
- (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0);
- gtk_table_attach (GTK_TABLE (table), d->newline_entry, 1, 2, 1, 2,
- (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), (GtkAttachOptions) (0), 0, 0);
- label = gtk_label_new (_("Encapsulate values with:"));
- gtk_misc_set_alignment (GTK_MISC (label), 0, 0.0);
- gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3,
- (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0);
- gtk_table_attach (GTK_TABLE (table), d->quote_entry, 1, 2, 2, 3,
- (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), (GtkAttachOptions) (0), 0, 0);
-
- gtk_box_pack_start (GTK_BOX (vbox), d->header_check, TRUE, TRUE, 0);
- gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0);
- gtk_widget_show_all (vbox);
-
- gtk_container_add (GTK_CONTAINER (csv_options), vbox);
-
-
- return csv_options;
-}
-
-FormatHandler *csv_format_handler_new (void)
-{
- FormatHandler *handler = g_new (FormatHandler, 1);
-
- handler->isdefault = FALSE;
- handler->combo_label = _("Comma separated value format (.csv)");
- handler->filename_ext = ".csv";
- handler->data = g_new (CsvPluginData, 1);
- handler->options_widget = create_options_widget (handler);
- handler->save = do_save_calendar_csv;
-
- return handler;
-}
diff --git a/plugins/save-calendar/format-handler.h b/plugins/save-calendar/format-handler.h
deleted file mode 100644
index 9ff29a118d..0000000000
--- a/plugins/save-calendar/format-handler.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
- *
- * Authors: Philip Van Hoof <pvanhoof@gnome.org>
- *
- * Copyright 2004 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., 59 Temple Street #330, Boston, MA 02111-1307, USA.
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <glib.h>
-#include <gtk/gtk.h>
-#include <libedataserver/e-source.h>
-#include <libedataserverui/e-source-selector.h>
-#include <libecal/e-cal.h>
-#include <calendar/gui/e-cal-popup.h>
-
-typedef struct _FormatHandler FormatHandler;
-
-struct _FormatHandler
-{
- gboolean isdefault;
- const gchar *combo_label;
- const gchar *filename_ext;
- GtkWidget *options_widget;
-
- gpointer data;
-
- void (*save) (FormatHandler *handler, EPlugin *ep, ECalPopupTargetSource *target, ECalSourceType type, char *dest_uri);
-};
-
-FormatHandler *csv_format_handler_new (void);
-FormatHandler *ical_format_handler_new (void);
-FormatHandler *rdf_format_handler_new (void);
diff --git a/plugins/save-calendar/ical-format.c b/plugins/save-calendar/ical-format.c
deleted file mode 100644
index 680885161c..0000000000
--- a/plugins/save-calendar/ical-format.c
+++ /dev/null
@@ -1,127 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
- *
- * Authors: Rodrigo Moya <rodrigo@novell.com>
- * Philip Van Hoof <pvanhoof@gnome.org>
- *
- * Copyright 2004 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., 59 Temple Street #330, Boston, MA 02111-1307, USA.
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <glib.h>
-#include <glib/gi18n.h>
-#ifdef USE_GTKFILECHOOSER
-# include <gtk/gtkfilechooser.h>
-# include <gtk/gtkfilechooserdialog.h>
-#else
-# include <gtk/gtkfilesel.h>
-#endif
-#include <gtk/gtkmessagedialog.h>
-#include <gtk/gtkstock.h>
-#include <gtk/gtk.h>
-#include <libedataserver/e-source.h>
-#include <libedataserverui/e-source-selector.h>
-#include <libecal/e-cal.h>
-#include <calendar/gui/e-cal-popup.h>
-#include <libgnomevfs/gnome-vfs.h>
-#include <string.h>
-
-#include "format-handler.h"
-
-static void
-display_error_message (GtkWidget *parent, GError *error)
-{
- GtkWidget *dialog;
-
- dialog = gtk_message_dialog_new (GTK_WINDOW (parent), 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
- error->message);
- gtk_dialog_run (GTK_DIALOG (dialog));
- gtk_widget_destroy (dialog);
-}
-
-static void
-do_save_calendar_ical (FormatHandler *handler, EPlugin *ep, ECalPopupTargetSource *target, ECalSourceType type, char *dest_uri)
-{
- ESource *primary_source;
- ECal *source_client, *dest_client;
- GError *error = NULL;
-
- primary_source = e_source_selector_peek_primary_selection (target->selector);
-
- if (!dest_uri)
- return;
-
- /* open source client */
- source_client = e_cal_new (primary_source, type);
- if (!e_cal_open (source_client, TRUE, &error)) {
- display_error_message (gtk_widget_get_toplevel (GTK_WIDGET (target->selector)), error);
- g_object_unref (source_client);
- g_error_free (error);
- return;
- }
-
- /* open destination client */
- error = NULL;
- dest_client = e_cal_new_from_uri (dest_uri, type);
- if (e_cal_open (dest_client, FALSE, &error)) {
- GList *objects;
-
- if (e_cal_get_object_list (source_client, "#t", &objects, NULL)) {
- while (objects != NULL) {
- icalcomponent *icalcomp = objects->data;
-
- /* FIXME: deal with additions/modifications */
-
- /* FIXME: This stores a directory with one file in it, the user expects only a file */
-
- /* FIXME: It would be nice if this ical-handler would use gnome-vfs rather than e_cal_* */
-
- error = NULL;
- if (!e_cal_create_object (dest_client, icalcomp, NULL, &error)) {
- display_error_message (gtk_widget_get_toplevel (GTK_WIDGET (target->selector)), error);
- g_error_free (error);
- }
-
- /* remove item from the list */
- objects = g_list_remove (objects, icalcomp);
- icalcomponent_free (icalcomp);
- }
- }
- } else {
- display_error_message (gtk_widget_get_toplevel (GTK_WIDGET (target->selector)), error);
- g_error_free (error);
- }
-
- /* terminate */
- g_object_unref (source_client);
- g_object_unref (dest_client);
-}
-
-FormatHandler *ical_format_handler_new (void)
-{
- FormatHandler *handler = g_new (FormatHandler, 1);
-
- handler->isdefault = TRUE;
- handler->combo_label = _("iCalendar format (.ics)");
- handler->filename_ext = ".ics";
- handler->options_widget = NULL;
- handler->save = do_save_calendar_ical;
- handler->data = NULL;
-
- return handler;
-}
diff --git a/plugins/save-calendar/org-gnome-save-calendar.eplug.in b/plugins/save-calendar/org-gnome-save-calendar.eplug.in
deleted file mode 100644
index 39d1f3f382..0000000000
--- a/plugins/save-calendar/org-gnome-save-calendar.eplug.in
+++ /dev/null
@@ -1,14 +0,0 @@
-<e-plugin-list>
- <e-plugin id="org.gnome.evolution.save_calendar" type="shlib" name="Save Selected Calendar or Tasks List" description="Saves selected calendar or tasks list to disk"
- location="@PLUGINDIR@/liborg-gnome-save-calendar.so">
-
- <hook class="org.gnome.evolution.calendar.popup:1.0">
- <menu id="org.gnome.evolution.tasks.source.popup" target="source">
- <item type="item" path="19.save_tasks" label="Save to _Disk" icon="stock_save" activate="org_gnome_save_tasks"/>
- </menu>
- <menu id="org.gnome.evolution.calendar.source.popup" target="source">
- <item type="item" path="19.save_calendar" label="Save to _Disk" icon="stock_save" activate="org_gnome_save_calendar"/>
- </menu>
- </hook>
- </e-plugin>
-</e-plugin-list> \ No newline at end of file
diff --git a/plugins/save-calendar/rdf-format.c b/plugins/save-calendar/rdf-format.c
deleted file mode 100644
index eb8154f782..0000000000
--- a/plugins/save-calendar/rdf-format.c
+++ /dev/null
@@ -1,396 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
- *
- * Authors: Philip Van Hoof <pvanhoof@gnome.org>
- *
- * Copyright 2004 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., 59 Temple Street #330, Boston, MA 02111-1307, USA.
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <glib.h>
-#include <glib/gi18n.h>
-#ifdef USE_GTKFILECHOOSER
-# include <gtk/gtkfilechooser.h>
-# include <gtk/gtkfilechooserdialog.h>
-#else
-# include <gtk/gtkfilesel.h>
-#endif
-#include <gtk/gtkmessagedialog.h>
-#include <gtk/gtkstock.h>
-#include <gtk/gtk.h>
-#include <libedataserver/e-source.h>
-#include <libedataserverui/e-source-selector.h>
-#include <libecal/e-cal.h>
-#include <calendar/gui/e-cal-popup.h>
-#include <libgnomevfs/gnome-vfs.h>
-#include <libxml/xmlmemory.h>
-#include <libxml/parser.h>
-#include <libxml/tree.h>
-#include <libxml/xmlIO.h>
-#include <libxml/xpath.h>
-#include <string.h>
-
-#include "widgets/misc/e-error.h"
-
-#include "format-handler.h"
-
-static void
-add_string_to_rdf (xmlNodePtr node, const gchar *tag, const char *value);
-
-/* Use { */
-
-/* #include <calendar/gui/calendar-config-keys.h> */
-/* #include <calendar/gui/calendar-config.h> */
-
-/* } or { */
-#define CALENDAR_CONFIG_PREFIX "/apps/evolution/calendar"
-#define CALENDAR_CONFIG_TIMEZONE CALENDAR_CONFIG_PREFIX "/display/timezone"
-
-GConfClient *config = NULL;
-
-static gchar *
-calendar_config_get_timezone (void)
-{
- gchar *retval = NULL;
-
- if (!config)
- config = gconf_client_get_default ();
-
- retval = gconf_client_get_string (config, CALENDAR_CONFIG_TIMEZONE, NULL);
-
- if (!retval)
- retval = g_strdup ("UTC");
-
- return retval;
-}
-/* } */
-
-enum { /* XML helper enum */
- ECALCOMPONENTTEXT,
- ECALCOMPONENTATTENDEE,
- CONSTCHAR
-};
-
-static void
-display_error_message (GtkWidget *parent, GError *error)
-{
- GtkWidget *dialog;
-
- dialog = gtk_message_dialog_new (GTK_WINDOW (parent), 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
- error->message);
- gtk_dialog_run (GTK_DIALOG (dialog));
- gtk_widget_destroy (dialog);
-}
-
-/* Some helpers for the xml stuff */
-static void
-add_list_to_rdf (xmlNodePtr node, const gchar *tag, GSList *list_in, gint type)
-{
- if (list_in) {
- GSList *list = list_in;
-
- while (list) {
- const char *str = NULL;
-
- switch (type) {
- case ECALCOMPONENTATTENDEE:
- str = ((ECalComponentAttendee*)list->data)->value;
- break;
- case ECALCOMPONENTTEXT:
- str = ((ECalComponentText*)list->data)->value;
- break;
- case CONSTCHAR:
- default:
- str = list->data;
- break;
- }
-
- add_string_to_rdf (node, tag, str);
-
- list = g_slist_next (list);
- }
- }
-}
-
-static void
-add_nummeric_to_rdf (xmlNodePtr node, const gchar *tag, gint *nummeric)
-{
- if (nummeric) {
- gchar *value = g_strdup_printf ("%d", *nummeric);
- xmlNodePtr cur_node = xmlNewChild (node, NULL, tag, value);
- xmlSetProp (cur_node, "rdf:datatype", "http://www.w3.org/2001/XMLSchema#integer");
- g_free (value);
- }
-}
-
-static void
-add_time_to_rdf (xmlNodePtr node, const gchar *tag, icaltimetype *time)
-{
- if (time) {
- xmlNodePtr cur_node = NULL;
- gchar *tmp = NULL;
- gchar *str = g_strdup_printf ("%s%d-%s%d-%s%dT%s%d:%s%d:%s%d",
- (time->year < 10)?"0":"", time->year,
- (time->month < 10)?"0":"", time->month,
- (time->day < 10)?"0":"", time->day,
- (time->hour < 10)?"0":"", time->hour,
- (time->minute < 10)?"0":"", time->minute,
- (time->second < 10)?"0":"", time->second);
- cur_node = xmlNewChild (node, NULL, tag, str);
-
- /* Not sure about this property */
- tmp = g_strdup_printf ("http://www.w3.org/2002/12/cal/tzd/%s#tz", calendar_config_get_timezone ());
- xmlSetProp (cur_node, "rdf:datatype", tmp);
- g_free (tmp);
-
- g_free (str);
- }
-}
-
-
-static void
-add_string_to_rdf (xmlNodePtr node, const gchar *tag, const char *value)
-{
- if (value) {
- xmlNodePtr cur_node = NULL;
- cur_node = xmlNewChild (node, NULL, tag, value);
- xmlSetProp (cur_node, "rdf:datatype", "http://www.w3.org/2001/XMLSchema#string");
- }
-}
-
-
-
-
-static void
-do_save_calendar_rdf (FormatHandler *handler, EPlugin *ep, ECalPopupTargetSource *target, ECalSourceType type, char *dest_uri)
-{
-
- /*
- * According to some documentation about CSV, newlines 'are' allowed
- * in CSV-files. But you 'do' have to put the value between quotes.
- * The helper 'string_needsquotes' will check for that
- *
- * http://www.creativyst.com/Doc/Articles/CSV/CSV01.htm
- * http://www.creativyst.com/cgi-bin/Prod/15/eg/csv2xml.pl
- */
-
- ESource *primary_source;
- ECal *source_client;
- GError *error = NULL;
- GList *objects=NULL;
- GnomeVFSResult result;
- GnomeVFSHandle *handle;
- GnomeVFSURI *uri;
- gchar *temp = NULL;
- gboolean doit = TRUE;
-
- if (!dest_uri)
- return;
-
- primary_source = e_source_selector_peek_primary_selection (target->selector);
-
- /* open source client */
- source_client = e_cal_new (primary_source, type);
- if (!e_cal_open (source_client, TRUE, &error)) {
- display_error_message (gtk_widget_get_toplevel (GTK_WIDGET (target->selector)), error);
- g_object_unref (source_client);
- g_error_free (error);
- return;
- }
-
- uri = gnome_vfs_uri_new (dest_uri);
-
- result = gnome_vfs_open_uri (&handle, uri, GNOME_VFS_OPEN_READ);
- if (result == GNOME_VFS_OK)
- doit = e_error_run(gtk_widget_get_toplevel (GTK_WIDGET (target->selector)),
- E_ERROR_ASK_FILE_EXISTS_OVERWRITE, dest_uri, NULL) == GTK_RESPONSE_OK;
-
- if (doit) {
- result = gnome_vfs_open_uri (&handle, uri, GNOME_VFS_OPEN_WRITE);
- if (result != GNOME_VFS_OK) {
- gnome_vfs_create (&handle, dest_uri, GNOME_VFS_OPEN_WRITE, TRUE, GNOME_VFS_PERM_USER_ALL);
- result = gnome_vfs_open_uri (&handle, uri, GNOME_VFS_OPEN_WRITE);
- }
- }
-
-
- if (result == GNOME_VFS_OK && doit && e_cal_get_object_list_as_comp (source_client, "#t", &objects, NULL)) {
- xmlBufferPtr buffer=xmlBufferCreate();
- xmlDocPtr doc = xmlNewDoc((xmlChar *) "1.0");
- xmlNodePtr fnode = doc->children;
-
- doc->children = xmlNewDocNode (doc, NULL, "rdf:RDF", NULL);
- xmlSetProp (doc->children, "xmlns:rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#");
- xmlSetProp (doc->children, "xmlns", "http://www.w3.org/2002/12/cal/ical#");
-
- fnode = xmlNewChild (doc->children, NULL, "Vcalendar", NULL);
-
- /* Should Evolution publicise these? */
- xmlSetProp (fnode, "xmlns:x-wr", "http://www.w3.org/2002/12/cal/prod/Apple_Comp_628d9d8459c556fa#");
- xmlSetProp (fnode, "xmlns:x-lic", "http://www.w3.org/2002/12/cal/prod/Apple_Comp_628d9d8459c556fa#");
-
- /* Not sure if it's correct like this */
- xmlNewChild (fnode, NULL, "prodid", "-//" PACKAGE_STRING "//iCal 1.0//EN");
-
- /* Assuming GREGORIAN is the only supported calendar scale */
- xmlNewChild (fnode, NULL, "calscale", "GREGORIAN");
-
- temp = calendar_config_get_timezone ();
- xmlNewChild (fnode, NULL, "x-wr:timezone", temp);
- g_free (temp);
-
- xmlNewChild (fnode, NULL, "method", "PUBLISH");
-
- xmlNewChild (fnode, NULL, "x-wr:relcalid", e_source_peek_uid (primary_source));
-
- xmlNewChild (fnode, NULL, "x-wr:calname", e_source_peek_name (primary_source));
-
- /* Version of this RDF-format */
- xmlNewChild (fnode, NULL, "version", "2.0");
-
- while (objects != NULL) {
- ECalComponent *comp = objects->data;
- const char *temp_constchar;
- gchar *tmp_str = NULL;
- GSList *temp_list;
- ECalComponentDateTime temp_dt;
- struct icaltimetype *temp_time;
- int *temp_int;
- ECalComponentText temp_comptext;
- xmlNodePtr c_node = xmlNewChild (fnode, NULL, "component", NULL);
- xmlNodePtr node = xmlNewChild (c_node, NULL, "Vevent", NULL);
-
- /* Getting the stuff */
- e_cal_component_get_uid (comp, &temp_constchar);
- tmp_str = g_strdup_printf ("#%s", temp_constchar);
- xmlSetProp (node, "about", tmp_str);
- g_free (tmp_str);
- add_string_to_rdf (node, "uid",temp_constchar);
-
- e_cal_component_get_summary (comp, &temp_comptext);
- add_string_to_rdf (node, "summary",&temp_comptext?temp_comptext.value:NULL);
-
- e_cal_component_get_description_list (comp, &temp_list);
- add_list_to_rdf (node, "description", temp_list, ECALCOMPONENTTEXT);
- if (temp_list)
- e_cal_component_free_text_list (temp_list);
-
- e_cal_component_get_categories_list (comp, &temp_list);
- add_list_to_rdf (node, "categories", temp_list, CONSTCHAR);
- if (temp_list)
- e_cal_component_free_categories_list (temp_list);
-
- e_cal_component_get_comment_list (comp, &temp_list);
- add_list_to_rdf (node, "comment", temp_list, ECALCOMPONENTTEXT);
-
- if (temp_list)
- e_cal_component_free_text_list (temp_list);
-
- e_cal_component_get_completed (comp, &temp_time);
- add_time_to_rdf (node, "completed", temp_time);
- if (temp_time)
- e_cal_component_free_icaltimetype (temp_time);
-
- e_cal_component_get_created (comp, &temp_time);
- add_time_to_rdf (node, "created", temp_time);
- if (temp_time)
- e_cal_component_free_icaltimetype (temp_time);
-
- e_cal_component_get_contact_list (comp, &temp_list);
- add_list_to_rdf (node, "contact", temp_list, ECALCOMPONENTTEXT);
- if (temp_list)
- e_cal_component_free_text_list (temp_list);
-
- e_cal_component_get_dtstart (comp, &temp_dt);
- add_time_to_rdf (node, "dtstart", temp_dt.value ? temp_dt.value : NULL);
- if (temp_dt.value)
- e_cal_component_free_datetime (&temp_dt);
-
- e_cal_component_get_dtend (comp, &temp_dt);
- add_time_to_rdf (node, "dtend", temp_dt.value ? temp_dt.value : NULL);
- if (temp_dt.value)
- e_cal_component_free_datetime (&temp_dt);
-
- e_cal_component_get_due (comp, &temp_dt);
- add_time_to_rdf (node, "due", temp_dt.value ? temp_dt.value : NULL);
- if (temp_dt.value)
- e_cal_component_free_datetime (&temp_dt);
-
- e_cal_component_get_percent (comp, &temp_int);
- add_nummeric_to_rdf (node, "percentComplete", temp_int);
-
- e_cal_component_get_priority (comp, &temp_int);
- add_nummeric_to_rdf (node, "priority", temp_int);
-
- e_cal_component_get_url (comp, &temp_constchar);
- add_string_to_rdf (node, "URL", temp_constchar);
-
- if (e_cal_component_has_attendees (comp)) {
- e_cal_component_get_attendee_list (comp, &temp_list);
- add_list_to_rdf (node, "attendee", temp_list, ECALCOMPONENTATTENDEE);
- if (temp_list)
- e_cal_component_free_attendee_list (temp_list);
- }
-
- e_cal_component_get_location (comp, &temp_constchar);
- add_string_to_rdf (node, "location", temp_constchar);
-
- e_cal_component_get_last_modified (comp, &temp_time);
- add_time_to_rdf (node, "lastModified",temp_time);
-
-
- /* Important note!
- * The documentation is not requiring this!
- *
- * if (temp_time) e_cal_component_free_icaltimetype (temp_time);
- *
- * Please uncomment and fix documentation if untrue
- * http://www.gnome.org/projects/evolution/developer-doc/libecal/ECalComponent.html
- * #e-cal-component-get-last-modified
- */
-
- objects = g_list_next (objects);
- }
-
- /* I used a buffer rather than xmlDocDump: I want gnome-vfs support */
- xmlNodeDump (buffer, doc, doc->children, 2, 1);
-
- gnome_vfs_write (handle, xmlBufferContent (buffer), xmlBufferLength (buffer), NULL);
-
- xmlBufferFree (buffer);
- xmlFreeDoc (doc);
- gnome_vfs_close (handle);
- }
-
- g_object_unref (source_client);
-
- return;
-}
-
-FormatHandler *rdf_format_handler_new (void)
-{
- FormatHandler *handler = g_new (FormatHandler, 1);
-
- handler->isdefault = FALSE;
- handler->combo_label = _("RDF format (.rdf)");
- handler->filename_ext = ".rdf";
- handler->options_widget = NULL;
- handler->save = do_save_calendar_rdf;
-
- return handler;
-}
diff --git a/plugins/save-calendar/save-calendar.c b/plugins/save-calendar/save-calendar.c
deleted file mode 100644
index 48a0614704..0000000000
--- a/plugins/save-calendar/save-calendar.c
+++ /dev/null
@@ -1,260 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
- *
- * Authors: Rodrigo Moya <rodrigo@novell.com>
- *
- * Copyright 2004 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., 59 Temple Street #330, Boston, MA 02111-1307, USA.
- *
- */
-
-/* This is prototype code only, this may, or may not, use undocumented
- * unstable or private internal function calls. */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <glib.h>
-#include <glib/gi18n.h>
-#ifdef USE_GTKFILECHOOSER
-# include <gtk/gtkfilechooser.h>
-# include <gtk/gtkfilechooserdialog.h>
-#else
-# include <gtk/gtkfilesel.h>
-#endif
-#include <gtk/gtkmessagedialog.h>
-#include <gtk/gtkstock.h>
-#include <gtk/gtk.h>
-#include <libedataserver/e-source.h>
-#include <libedataserverui/e-source-selector.h>
-#include <libecal/e-cal.h>
-#include <calendar/gui/e-cal-popup.h>
-#include <libgnomevfs/gnome-vfs.h>
-#include <string.h>
-
-#include "format-handler.h"
-
-enum { /* GtkComboBox enum */
- DEST_NAME_COLUMN,
- DEST_HANDLER,
- N_DEST_COLUMNS
-
-};
-
-void org_gnome_save_calendar (EPlugin *ep, ECalPopupTargetSource *target);
-void org_gnome_save_tasks (EPlugin *ep, ECalPopupTargetSource *target);
-
-
-static void
-extra_widget_foreach_hide (GtkWidget *widget, gpointer data)
-{
- if (widget != data)
- gtk_widget_hide (widget);
-}
-
-static void
-on_type_combobox_changed (GtkComboBox *combobox, gpointer data)
-{
- FormatHandler *handler = NULL;
- GtkWidget *extra_widget = data;
- GtkTreeIter iter;
- GtkTreeModel *model = gtk_combo_box_get_model (combobox);
-
- gtk_container_foreach (GTK_CONTAINER (extra_widget),
- extra_widget_foreach_hide, combobox);
-
- gtk_combo_box_get_active_iter (combobox, &iter);
-
- gtk_tree_model_get (model, &iter,
- DEST_HANDLER, &handler, -1);
-
-
- if (handler->options_widget)
- {
- gtk_widget_show (handler->options_widget);
- }
-
-}
-
-static void
-format_handlers_foreach_free (gpointer data, gpointer user_data)
-{
- FormatHandler *handler = data;
-
- if (handler->options_widget)
- gtk_widget_destroy (handler->options_widget);
-
- if (handler->data)
- g_free (handler->data);
-
- g_free (data);
-}
-
-static void
-ask_destination_and_save (EPlugin *ep, ECalPopupTargetSource *target, ECalSourceType type)
-{
- FormatHandler *handler = NULL;
-
- GtkWidget *extra_widget = gtk_vbox_new (FALSE, 0);
- GtkComboBox *combo = GTK_COMBO_BOX(gtk_combo_box_new ());
- GtkTreeModel *model = GTK_TREE_MODEL (gtk_list_store_new
- (N_DEST_COLUMNS, G_TYPE_STRING, G_TYPE_POINTER));
- GtkCellRenderer *renderer=NULL;
- GtkListStore *store = GTK_LIST_STORE (model);
- GtkTreeIter iter;
- GtkWidget *dialog = NULL;
- char *dest_uri = NULL;
- gboolean proceed = FALSE;
-
- GList *format_handlers = NULL;
-
- /* The available formathandlers */
- format_handlers = g_list_append (format_handlers,
- ical_format_handler_new ());
- format_handlers = g_list_append (format_handlers,
- csv_format_handler_new ());
- format_handlers = g_list_append (format_handlers,
- rdf_format_handler_new ());
-
-
- /* The Type GtkComboBox */
- gtk_box_pack_start (GTK_BOX (extra_widget), GTK_WIDGET (combo),
- TRUE, TRUE, 0);
- gtk_combo_box_set_model (combo, model);
-
- gtk_list_store_clear (store);
- renderer = gtk_cell_renderer_text_new ();
- gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, TRUE);
- gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo),
- renderer, "text", DEST_NAME_COLUMN, NULL);
-
- while (format_handlers) {
- FormatHandler *handler = format_handlers->data;
-
- gtk_list_store_append (store, &iter);
- gtk_list_store_set (store, &iter, DEST_NAME_COLUMN,
- handler->combo_label, -1);
- gtk_list_store_set (store, &iter, DEST_HANDLER, handler, -1);
-
- if (handler->options_widget) {
- gtk_box_pack_start (GTK_BOX (extra_widget),
- GTK_WIDGET (handler->options_widget), TRUE, TRUE, 0);
- gtk_widget_hide (handler->options_widget);
- }
-
- if (handler->isdefault) {
- gtk_combo_box_set_active_iter (combo, &iter);
- if (handler->options_widget)
- gtk_widget_show (handler->options_widget);
- }
-
- format_handlers = g_list_next (format_handlers);
- }
-
-
- g_signal_connect (G_OBJECT(combo), "changed",
- G_CALLBACK (on_type_combobox_changed), extra_widget);
-
-#ifdef USE_GTKFILECHOOSER
-
- dialog = gtk_file_chooser_dialog_new (_("Select destination file"),
- NULL,
- GTK_FILE_CHOOSER_ACTION_SAVE,
- GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
- GTK_STOCK_SAVE_AS, GTK_RESPONSE_OK,
- NULL);
-
- gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
- gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (dialog), extra_widget);
-#else
- dialog = gtk_file_selection_new (_("Select destination file"));
- gtk_box_pack_start (GTK_BOX (GTK_FILE_SELECTION (dialog)->main_vbox), extra_widget, FALSE, TRUE, 0);
-#endif
- gtk_widget_show (GTK_WIDGET(combo));
- gtk_widget_show (extra_widget);
-
-
- if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
- char *tmp = NULL;
-
- gtk_combo_box_get_active_iter (combo, &iter);
- gtk_tree_model_get (model, &iter,
- DEST_HANDLER, &handler, -1);
-
-#ifdef USE_GTKFILECHOOSER
- dest_uri = gtk_file_chooser_get_uri
- (GTK_FILE_CHOOSER (dialog));
-#else
- dest_uri = g_strdup (gtk_file_selection_get_filename
- (GTK_FILE_SELECTION (dialog)));
-#endif
-
- tmp = strstr (dest_uri, handler->filename_ext);
-
- if (tmp && *(tmp + strlen (handler->filename_ext)) == '\0') {
-
- proceed = TRUE;
-
- } else {
-
- GtkWidget *warning =
- gtk_message_dialog_new (NULL,
- GTK_DIALOG_DESTROY_WITH_PARENT,
- GTK_MESSAGE_QUESTION,
- GTK_BUTTONS_YES_NO,
- _("The suggested filename extension of this filetype (%s)"
- " is unused in the chosen filename. Do you want to "
- "continue?"), handler->filename_ext);
-
- if (gtk_dialog_run (GTK_DIALOG (warning)) == GTK_RESPONSE_YES)
- proceed = TRUE;
-
- gtk_widget_destroy (warning);
-
- }
-
- if (proceed) {
- handler->save (handler, ep, target, type, dest_uri);
- /* Free the handlers */
- g_list_foreach (format_handlers, format_handlers_foreach_free, NULL);
- g_list_free (format_handlers);
-
- /* Now we can destroy it */
- gtk_widget_destroy (dialog);
- g_free (dest_uri);
- }
-
- } else {
- /* Free the handlers */
- g_list_foreach (format_handlers, format_handlers_foreach_free, NULL);
- g_list_free (format_handlers);
-
- /* Now we can destroy it */
- gtk_widget_destroy (dialog);
- g_free (dest_uri);
- }
-}
-
-void
-org_gnome_save_calendar (EPlugin *ep, ECalPopupTargetSource *target)
-{
- ask_destination_and_save (ep, target, E_CAL_SOURCE_TYPE_EVENT);
-}
-
-void
-org_gnome_save_tasks (EPlugin *ep, ECalPopupTargetSource *target)
-{
- ask_destination_and_save (ep, target, E_CAL_SOURCE_TYPE_TODO);
-}
diff --git a/plugins/select-one-source/.cvsignore b/plugins/select-one-source/.cvsignore
deleted file mode 100644
index 683d5ddbe2..0000000000
--- a/plugins/select-one-source/.cvsignore
+++ /dev/null
@@ -1,5 +0,0 @@
-.deps
-.libs
-Makefile
-Makefile.in
-*.eplug \ No newline at end of file
diff --git a/plugins/select-one-source/ChangeLog b/plugins/select-one-source/ChangeLog
deleted file mode 100644
index f5204d7710..0000000000
--- a/plugins/select-one-source/ChangeLog
+++ /dev/null
@@ -1,10 +0,0 @@
-2004-11-01 JP Rosevear <jpr@novell.com>
-
- * Makefile.am: dist .eplug.in file
-
-2004-10-20 JP Rosevear <jpr@novell.com>
-
- * select-one-source.c: implement a plugin that allows the user to
- limit the displayed task lists or calendars to the current
- calendar or task list
-
diff --git a/plugins/select-one-source/Makefile.am b/plugins/select-one-source/Makefile.am
deleted file mode 100644
index 6b5b178e8d..0000000000
--- a/plugins/select-one-source/Makefile.am
+++ /dev/null
@@ -1,13 +0,0 @@
-INCLUDES = \
- -I$(top_srcdir) \
- $(EVOLUTION_CALENDAR_CFLAGS)
-
-@EVO_PLUGIN_RULE@
-
-plugin_DATA = org-gnome-select-one-source.eplug
-plugin_LTLIBRARIES = liborg-gnome-select-one-source.la
-
-liborg_gnome_select_one_source_la_SOURCES = select-one-source.c
-liborg_gnome_select_one_source_la_LDFLAGS = -module -avoid-version
-
-EXTRA_DIST = org-gnome-select-one-source.eplug.in \ No newline at end of file
diff --git a/plugins/select-one-source/mark-calendar-offline.c b/plugins/select-one-source/mark-calendar-offline.c
deleted file mode 100644
index 95083c7ff2..0000000000
--- a/plugins/select-one-source/mark-calendar-offline.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
- *
- * Authors: Harish Krishnaswamy (kharish@novell.com)
- *
- * Copyright 2004 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., 59 Temple Street #330, Boston, MA 02111-1307, USA.
- *
- */
-
-/* This is prototype code only, this may, or may not, use undocumented
- * unstable or private internal function calls.
- * This code has been derived from the source of the sample eplugin
- * select_one_source.
- */
-
-#include <glib.h>
-#include <glib/gi18n.h>
-#include <libedataserver/e-source.h>
-#include <libedataserverui/e-source-selector.h>
-#include <calendar/gui/e-cal-popup.h>
-
-void org_gnome_mark_calendar_offline (EPlugin *ep, ECalPopupTargetSource *target);
-void org_gnome_mark_calendar_no_offline (EPlugin *ep, ECalPopupTargetSource *target);
-
-void
-org_gnome_mark_calendar_no_offline (EPlugin *ep, ECalPopupTargetSource *target)
-{
- ESource *source;
-
- source = e_source_selector_peek_primary_selection (target->selector);
- e_source_set_property (source, "offline", "0");
-}
-
-void
-org_gnome_mark_calendar_offline (EPlugin *ep, ECalPopupTargetSource *target)
-{
- ESource *source;
-
- source = e_source_selector_peek_primary_selection (target->selector);
- e_source_set_property (source, "offline", "1");
-}
-
diff --git a/plugins/select-one-source/org-gnome-select-one-source.eplug.in b/plugins/select-one-source/org-gnome-select-one-source.eplug.in
deleted file mode 100644
index c39a46964b..0000000000
--- a/plugins/select-one-source/org-gnome-select-one-source.eplug.in
+++ /dev/null
@@ -1,14 +0,0 @@
-<e-plugin-list>
- <e-plugin id="org.gnome.evolution.select_one_source" type="shlib" name="Select one source" description="Selects a single calendar or task source for viewing"
- location="@PLUGINDIR@/liborg-gnome-select-one-source.so">
-
- <hook class="org.gnome.evolution.calendar.popup:1.0">
- <menu id="org.gnome.evolution.tasks.source.popup" target="source">
- <item type="item" path="25.select_one_source" label="_Show only this Task List" icon="stock_check-filled" activate="org_gnome_select_one_source"/>
- </menu>
- <menu id="org.gnome.evolution.calendar.source.popup" target="source">
- <item type="item" path="25.select_one_source" label="_Show only this Calendar" icon="stock_check-filled" activate="org_gnome_select_one_source"/>
- </menu>
- </hook>
- </e-plugin>
-</e-plugin-list> \ No newline at end of file
diff --git a/plugins/select-one-source/select-one-source.c b/plugins/select-one-source/select-one-source.c
deleted file mode 100644
index 7325e47dd8..0000000000
--- a/plugins/select-one-source/select-one-source.c
+++ /dev/null
@@ -1,52 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
- *
- * Authors: JP Rosevear <jpr@novell.com>
- *
- * Copyright 2004 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., 59 Temple Street #330, Boston, MA 02111-1307, USA.
- *
- */
-
-/* This is prototype code only, this may, or may not, use undocumented
- * unstable or private internal function calls. */
-
-#include <glib.h>
-#include <glib/gi18n.h>
-#include <libedataserver/e-source.h>
-#include <libedataserverui/e-source-selector.h>
-#include <calendar/gui/e-cal-popup.h>
-
-void org_gnome_select_one_source (EPlugin *ep, ECalPopupTargetSource *target);
-
-void
-org_gnome_select_one_source (EPlugin *ep, ECalPopupTargetSource *target)
-{
- GSList *selection, *l;
- ESource *primary_source;
-
- selection = e_source_selector_get_selection (target->selector);
- primary_source = e_source_selector_peek_primary_selection (target->selector);
-
- for (l = selection; l; l = l->next) {
- ESource *source = l->data;
-
- if (source != primary_source)
- e_source_selector_unselect_source (target->selector, source);
- }
-
- e_source_selector_select_source (target->selector, primary_source);
-
- e_source_selector_free_selection (selection);
-}
diff --git a/plugins/send-options/ChangeLog b/plugins/send-options/ChangeLog
deleted file mode 100644
index 16c3882863..0000000000
--- a/plugins/send-options/ChangeLog
+++ /dev/null
@@ -1,49 +0,0 @@
-2005-02-10 Chenthill Palanisamy <pchenthill@novell.com>
-
- * send-options.c: (e_sendoptions_clicked_cb): IF
- we get a invalid session string back from the server
- do the operation again.
-
-2005-01-24 Chenthill Palanisamy <pchenthill@novell.com>
-
-
- * org-gnome-send-options.eplug.in: Changed the item_type to
- section instead of item.
- * send-options.c (get_cnc): Made the necessary changes to get cnc
- since some part of dependant code was changed in groupwise account
- set up plugin.
- (org_gnome_send_options): Changed the prototype of the function
- to return the widget.
- (send_options_commit): Added a warning message if the Modification
- was not sent to the server.
-
-2005-01-12 Chenthill Palanisamy <pchenthill@novell.com>
-
- * Makefile.am:
- * send-options.c: (get_cnc), (e_send_options_load_general_opts),
- (e_sendoptions_clicked_cb), (org_gnome_send_options),
- (e_send_options_copy_general_opts),
- (e_send_options_copy_status_options),
- (check_status_options_changed), (check_general_changed),
- (send_options_copy_check_changed), (get_source),
- (add_return_value), (put_options_in_source),
- (add_send_options_to_source), (send_options_commit): Added some
- functons to change the global send options.
-
-2005-01-10 Rodney Dawes <dobey@novell.com>
-
- * Makefile.am (INCLUDES): Clean up spacing
- (liborg_gnome_send_options_la_LIBADD): Don't specify the path to
- the la file directly, use the _LIBS variables that correspond with
- those in INCLUDES to link to the correct libraries
-
-2005-01-10 Chenthill Palanisamy <pchenthill@novell.com>
-
- * MakeFile.am:
- * org-gnome-send-options.eplug.in: Plugin file to add
- the send options button in the account editor.
- * send-options.c: Adds the send options button inside a frame
- in the defaults page of the account editor for groupwise
- accounts. Clicking on the button gets the settings from the
- server and shows it in the send options dialog box.
-
diff --git a/plugins/send-options/Makefile.am b/plugins/send-options/Makefile.am
deleted file mode 100644
index 41d478cad1..0000000000
--- a/plugins/send-options/Makefile.am
+++ /dev/null
@@ -1,19 +0,0 @@
-INCLUDES = \
- -I$(top_srcdir) \
- -I$(top_srcdir)/camel \
- $(EVOLUTION_MAIL_CFLAGS) \
- $(EVOLUTION_CALENDAR_CFLAGS) \
- $(CAMEL_GROUPWISE_CFLAGS)
-
-@EVO_PLUGIN_RULE@
-
-plugin_DATA = org-gnome-send-options.eplug
-plugin_LTLIBRARIES = liborg-gnome-send-options.la
-
-liborg_gnome_send_options_la_SOURCES = send-options.c
-liborg_gnome_send_options_la_LDFLAGS = -module -avoid-version
-liborg_gnome_send_options_la_LIBADD = \
- $(EVOLUTION_MAIL_LIBS) \
- $(CAMEL_GROUPWISE_LIBS)
-
-EXTRA_DIST = org-gnome-send-options.eplug.in
diff --git a/plugins/send-options/org-gnome-send-options.eplug.in b/plugins/send-options/org-gnome-send-options.eplug.in
deleted file mode 100644
index 6e3b479f9b..0000000000
--- a/plugins/send-options/org-gnome-send-options.eplug.in
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0"?>
-<e-plugin-list>
- <e-plugin id="org.gnome.evolution.send_options" type="shlib" name="send options" description="Creates an global send options page"
- location="@PLUGINDIR@/liborg-gnome-send-options.so">
-
- <hook class="org.gnome.evolution.mail.config:1.0">
- <group id="org.gnome.evolution.mail.config.accountEditor"
- target="account" check = "send_options_changed" commit = "send_options_commit"
- abort = "send_options_abort">
- <item type="section" path="40.defaults/50.send_options" label="Send Options" factory="org_gnome_send_options" />
- </group>
- </hook>
- </e-plugin>
-</e-plugin-list>
diff --git a/plugins/send-options/send-options.c b/plugins/send-options/send-options.c
deleted file mode 100644
index 823865e617..0000000000
--- a/plugins/send-options/send-options.c
+++ /dev/null
@@ -1,553 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
- *
- * Authors: Chenthill Palanisamy (pchenthill@novell.com)
- *
- * Copyright 2004 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., 59 Temple Street #330, Boston, MA 02111-1307, USA.
- *
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <libgnome/gnome-i18n.h>
-#include <glade/glade.h>
-#include <gtk/gtk.h>
-#include "mail/em-account-editor.h"
-#include "mail/em-config.h"
-#include "e-util/e-account.h"
-#include <widgets/misc/e-send-options.h>
-#include <mail/em-config.h>
-#include <e-gw-connection.h>
-#include <camel/camel-url.h>
-#include "e-util/e-passwords.h"
-#include <libecal/e-cal-time-util.h>
-#include <libedataserver/e-source-list.h>
-
-ESendOptionsDialog *sod = NULL;
-GtkWidget *parent;
-EGwConnection *n_cnc;
-EGwSendOptions *opts = NULL;
-gboolean changed = FALSE;
-EAccount *account;
-
-GtkWidget* org_gnome_send_options (EPlugin *epl, EConfigHookItemFactoryData *data);
-void send_options_commit (EPlugin *epl, EConfigHookItemFactoryData *data);
-void send_options_changed (EPlugin *epl, EConfigHookItemFactoryData *data);
-void send_options_abort (EPlugin *epl, EConfigHookItemFactoryData *data);
-
-static EGwConnection *
-get_cnc ()
-{
- EGwConnection *cnc;
- char *uri, *failed_auth, *key, *prompt, *password = NULL;
- CamelURL *url;
- const char *poa_address, *use_ssl, *soap_port;
- gboolean remember;
-
- url = camel_url_new (account->source->url, NULL);
- if (url == NULL)
- return NULL;
- poa_address = url->host;
- if (!poa_address || strlen (poa_address) ==0)
- return NULL;
-
- 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");
-
- key = g_strdup_printf ("groupwise://%s@%s/", url->user, poa_address);
-
- if (!g_str_equal (use_ssl, "never"))
- uri = g_strdup_printf ("https://%s:%s/soap", poa_address, soap_port);
- else
- uri = g_strdup_printf ("http://%s:%s/soap", poa_address, soap_port);
-
- failed_auth = "";
- cnc = NULL;
-
- prompt = g_strdup_printf (_("%sEnter password for %s (user %s)"),
- failed_auth, poa_address, url->user);
-
- password = e_passwords_get_password ("Groupwise", key);
- if (!password)
- password = e_passwords_ask_password (prompt, "Groupwise", key, prompt,
- E_PASSWORDS_REMEMBER_FOREVER|E_PASSWORDS_SECRET, &remember, NULL);
- g_free (prompt);
-
- cnc = e_gw_connection_new (uri, url->user, password);
- if (!E_IS_GW_CONNECTION(cnc) && use_ssl && g_str_equal (use_ssl, "when-possible")) {
- char *http_uri = g_strconcat ("http://", uri + 8, NULL);
- cnc = e_gw_connection_new (http_uri, url->user, password);
- g_free (http_uri);
- }
-
- camel_url_free (url);
- return cnc;
-}
-
-
-static void
-e_send_options_load_general_opts (ESendOptionsGeneral *gopts, EGwSendOptionsGeneral *ggopts)
-{
- time_t temp;
-
- temp = time (NULL);
-
- gopts->priority = ggopts->priority;
-
- gopts->reply_enabled = ggopts->reply_enabled;
- gopts->reply_convenient = ggopts->reply_convenient;
- gopts->reply_within = ggopts->reply_within;
-
- gopts->expiration_enabled = ggopts->expiration_enabled;
- gopts->expire_after = ggopts->expire_after;
-
- gopts->delay_enabled = ggopts->delay_enabled;
-
- /* TODO convert int to timet comparing the current day */
- if (ggopts->delay_until) {
- gopts->delay_until = time_add_day_with_zone (temp, ggopts->delay_until, NULL);
- } else
- gopts->delay_until = 0;
-}
-
-static void
-e_send_options_load_status_options (ESendOptionsStatusTracking *sopts, EGwSendOptionsStatusTracking *gsopts)
-{
- sopts->tracking_enabled = gsopts->tracking_enabled;
- sopts->track_when = gsopts->track_when;
-
- sopts->autodelete = gsopts->autodelete;
-
- sopts->opened = gsopts->opened;
- sopts->accepted = gsopts->accepted;
- sopts->declined = gsopts->declined;
- sopts->completed = gsopts->completed;
-}
-
-static void
-e_send_options_load_default_data (EGwSendOptions *opts, ESendOptionsDialog *sod)
-{
- EGwSendOptionsGeneral *ggopts;
- EGwSendOptionsStatusTracking *gmopts;
- EGwSendOptionsStatusTracking *gcopts;
- EGwSendOptionsStatusTracking *gtopts;
-
- ggopts = e_gw_sendoptions_get_general_options (opts);
- gmopts = e_gw_sendoptions_get_status_tracking_options (opts, "mail");
- gcopts = e_gw_sendoptions_get_status_tracking_options (opts, "calendar");
- gtopts = e_gw_sendoptions_get_status_tracking_options (opts, "task");
-
- e_send_options_load_general_opts (sod->data->gopts, ggopts);
- e_send_options_load_status_options (sod->data->mopts, gmopts);
- e_send_options_load_status_options (sod->data->copts, gcopts);
- e_send_options_load_status_options (sod->data->topts, gtopts);
-}
-
-static void
-e_sendoptions_clicked_cb (GtkWidget *button, gpointer data)
-{
- EGwConnectionStatus status;
- account = (EAccount *) data;
- if (!sod) {
- sod = e_sendoptions_dialog_new ();
- e_sendoptions_set_global (sod, TRUE);
- if (!n_cnc)
- n_cnc = get_cnc ();
-
- if (!n_cnc) {
- g_warning ("Send Options: Could not get the connection to the server \n");
- return;
- }
-
- status = e_gw_connection_get_settings (n_cnc, &opts);
- if (status == E_GW_CONNECTION_STATUS_INVALID_CONNECTION)
- status = e_gw_connection_get_settings (n_cnc, &opts);
- if (status != E_GW_CONNECTION_STATUS_OK) {
- g_warning ("Send Options: Could not get the settings from the server");
- return;
- }
- e_send_options_load_default_data (opts, sod);
- }
-
- if (n_cnc)
- e_sendoptions_dialog_run (sod, parent ? parent : NULL, E_ITEM_NONE);
- else
- return;
-}
-
-GtkWidget *
-org_gnome_send_options (EPlugin *epl, EConfigHookItemFactoryData *data)
-{
- EMConfigTargetAccount *target_account;
- GtkWidget *frame, *button, *label, *vbox;
-
- target_account = (EMConfigTargetAccount *)data->config->target;
- account = target_account->account;
-
- if(!g_strrstr (account->source->url, "groupwise://"))
- return NULL;
-
- vbox = gtk_vbox_new (FALSE, 0);
- frame = gtk_frame_new ("");
- label = gtk_frame_get_label_widget (GTK_FRAME (frame));
- gtk_label_set_markup (GTK_LABEL (label), "<b>Send Options</b>");
- button = gtk_button_new_with_label ("Advanced send options");
- gtk_widget_show (button);
-
- g_signal_connect(button, "clicked",
- G_CALLBACK (e_sendoptions_clicked_cb), account);
-
- parent = gtk_widget_get_toplevel (GTK_WIDGET (data->parent));
- if (!GTK_WIDGET_TOPLEVEL (parent))
- parent = NULL;
-
- gtk_widget_set_size_request (button, 10, -1);
- gtk_box_pack_start (GTK_BOX (vbox), frame, 0, 0, 0);
- gtk_container_add (GTK_CONTAINER (frame), button);
- gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE);
- gtk_widget_show (frame);
- gtk_box_set_spacing (GTK_BOX (data->parent), 12);
- gtk_box_pack_start (GTK_BOX (data->parent), vbox, FALSE, FALSE, 0);
-
- return vbox;
-}
-
-static void
-send_options_finalize ()
-{
- if (n_cnc) {
- g_object_unref (n_cnc);
- n_cnc = NULL;
- }
-
- if (sod) {
- g_object_unref (sod);
- sod = NULL;
- }
-
- if (opts) {
- g_object_unref (opts);
- opts = NULL;
- }
-}
-
-static void
-e_send_options_copy_general_opts (ESendOptionsGeneral *gopts, EGwSendOptionsGeneral *ggopts)
-{
- time_t temp;
-
- temp = time (NULL);
-
- ggopts->priority = gopts->priority;
-
- ggopts->reply_enabled = gopts->reply_enabled;
- ggopts->reply_convenient = gopts->reply_convenient;
- ggopts->reply_within = gopts->reply_within;
-
- ggopts->expire_after = gopts->expire_after;
-
- if (gopts->expire_after == 0) {
- ggopts->expiration_enabled = FALSE;
- gopts->expiration_enabled = FALSE;
- } else
- ggopts->expiration_enabled = gopts->expiration_enabled;
-
- ggopts->delay_enabled = gopts->delay_enabled;
-
- if (gopts->delay_until) {
- int diff;
- icaltimetype temp, current;
-
- temp = icaltime_from_timet (gopts->delay_until, 0);
- current = icaltime_today ();
- diff = temp.day - current.day;
- ggopts->delay_until = diff;
- } else
- ggopts->delay_until = 0;
-}
-
-static void
-e_send_options_copy_status_options (ESendOptionsStatusTracking *sopts, EGwSendOptionsStatusTracking *gsopts)
-{
- gsopts->tracking_enabled = sopts->tracking_enabled;
- gsopts->track_when = sopts->track_when;
-
- gsopts->autodelete = sopts->autodelete;
-
- gsopts->opened = sopts->opened;
- gsopts->accepted = sopts->accepted;
- gsopts->declined = sopts->declined;
- gsopts->completed = sopts->completed;
-}
-
-static gboolean
-check_status_options_changed (EGwSendOptionsStatusTracking *n_sopts, EGwSendOptionsStatusTracking *o_sopts)
-{
- return (!(n_sopts->tracking_enabled == o_sopts->tracking_enabled
- && n_sopts->track_when == o_sopts->track_when
- && n_sopts->autodelete == o_sopts->autodelete
- && n_sopts->opened == o_sopts->opened
- && n_sopts->declined == o_sopts->declined
- && n_sopts->accepted == o_sopts->accepted
- && n_sopts->completed == o_sopts->completed));
-
-}
-
-static gboolean
-check_general_changed (EGwSendOptionsGeneral *n_gopts, EGwSendOptionsGeneral *o_gopts)
-{
- return (!(n_gopts->priority == o_gopts->priority
- && n_gopts->delay_enabled == o_gopts->delay_enabled
- && n_gopts->delay_until == o_gopts->delay_until
- && n_gopts->reply_enabled == o_gopts->reply_enabled
- && n_gopts->reply_convenient == o_gopts->reply_convenient
- && n_gopts->reply_within == o_gopts->reply_within
- && n_gopts->expiration_enabled == o_gopts->expiration_enabled
- && n_gopts->expire_after == o_gopts->expire_after));
-}
-
-static void
-send_options_copy_check_changed (EGwSendOptions *n_opts)
-{
- EGwSendOptionsGeneral *ggopts, *o_gopts;
- EGwSendOptionsStatusTracking *gmopts, *o_gmopts ;
- EGwSendOptionsStatusTracking *gcopts, *o_gcopts;
- EGwSendOptionsStatusTracking *gtopts, *o_gtopts;
-
- ggopts = e_gw_sendoptions_get_general_options (n_opts);
- gmopts = e_gw_sendoptions_get_status_tracking_options (n_opts, "mail");
- gcopts = e_gw_sendoptions_get_status_tracking_options (n_opts, "calendar");
- gtopts = e_gw_sendoptions_get_status_tracking_options (n_opts, "task");
-
- o_gopts = e_gw_sendoptions_get_general_options (opts);
- o_gmopts = e_gw_sendoptions_get_status_tracking_options (opts, "mail");
- o_gcopts = e_gw_sendoptions_get_status_tracking_options (opts, "calendar");
- o_gtopts = e_gw_sendoptions_get_status_tracking_options (opts, "task");
-
- e_send_options_copy_general_opts (sod->data->gopts, ggopts);
- e_send_options_copy_status_options (sod->data->mopts, gmopts);
- e_send_options_copy_status_options (sod->data->copts, gcopts);
- e_send_options_copy_status_options (sod->data->topts, gtopts);
-
- if (check_general_changed (ggopts, o_gopts))
- changed = TRUE;
- if (check_status_options_changed (gmopts, o_gmopts))
- changed = TRUE;
- if (check_status_options_changed (gcopts, o_gcopts))
- changed = TRUE;
- if (check_status_options_changed (gtopts, o_gtopts))
- changed = TRUE;
-}
-
-static ESource *
-get_source (ESourceList *list)
-{
- GSList *p, *l;
- char **temp = g_strsplit (account->source->url, ";", -1);
- char *uri = temp [0];
-
-
- l = e_source_list_peek_groups (list);
-
- for (p = l; p != NULL; p = p->next) {
- char *so_uri;
- GSList *r, *s;
- ESourceGroup *group = E_SOURCE_GROUP (p->data);
-
- s = e_source_group_peek_sources (group);
- for (r = s; r != NULL; r = r->next) {
- ESource *so = E_SOURCE (r->data);
- so_uri = e_source_get_uri (so);
-
- if (so_uri) {
- if (!strcmp (so_uri, uri)) {
- g_free (so_uri), so_uri = NULL;
- return E_SOURCE (r->data);
- }
- g_free (so_uri), so_uri = NULL;
- }
- }
- }
-
- g_strfreev (temp);
-
- return NULL;
-}
-
-static void
-add_return_value (EGwSendOptionsReturnNotify track, ESource *source, char *notify)
-{
- char *value;
-
- switch (track) {
- case E_GW_RETURN_NOTIFY_MAIL:
- value = g_strdup ("mail");
- break;
- default:
- value = g_strdup ("none");
- }
-
- e_source_set_property (source, notify, value);
- g_free (value), value = NULL;
-}
-
-static void
-put_options_in_source (ESource *source, EGwSendOptionsGeneral *gopts, EGwSendOptionsStatusTracking *sopts)
-{
- char *value;
- const char *val;
- icaltimetype tt;
-
- if (gopts) {
- /* priority */
- switch (gopts->priority) {
- case E_GW_PRIORITY_HIGH:
- value = g_strdup ("high");
- break;
- case E_GW_PRIORITY_STANDARD:
- value = g_strdup ("standard");
- break;
- case E_GW_PRIORITY_LOW:
- value = g_strdup ("low");
- break;
- default:
- value = g_strdup ("undefined");
- }
- e_source_set_property (source, "priority", value);
- g_free (value), value = NULL;
-
- /* Reply Requested */
- /*TODO Fill the value if it is not "convinient" */
- if (gopts->reply_enabled) {
- if (gopts->reply_convenient)
- value = g_strdup ("convinient");
- else
- value = g_strdup_printf ("%d",gopts->reply_within);
- } else
- value = g_strdup ("none");
- e_source_set_property (source, "reply-requested", value);
- g_free (value), value = NULL;
-
- /* Delay delivery */
- if (gopts->delay_enabled) {
- tt = icaltime_today ();
- icaltime_adjust (&tt, gopts->delay_until, 0, 0, 0);
- val = icaltime_as_ical_string (tt);
- } else
- val = "none";
- e_source_set_property (source, "delay-delivery", val);
-
- /* Expiration date */
- if (gopts->expiration_enabled)
- value = g_strdup_printf ("%d", gopts->expire_after);
- else
- value = g_strdup ("none");
- e_source_set_property (source, "expiration", value);
- g_free (value), value = NULL;
- }
-
- if (sopts) {
- /* status tracking */
- if (sopts->tracking_enabled) {
- switch (sopts->track_when) {
- case E_GW_DELIVERED :
- value = g_strdup ("delivered");
- break;
- case E_GW_DELIVERED_OPENED:
- value = g_strdup ("delivered-opened");
- break;
- default:
- value = g_strdup ("all");
- }
- } else
- value = g_strdup ("none");
- e_source_set_property (source, "status-tracking", value);
- g_free (value), value = NULL;
-
- add_return_value (sopts->opened, source, "return-open");
- add_return_value (sopts->accepted, source, "return-accept");
- add_return_value (sopts->declined, source, "return-decline");
- add_return_value (sopts->completed, source, "return-complete");
- }
-}
-
-static void
-add_send_options_to_source (EGwSendOptions *n_opts)
-{
- GConfClient *gconf = gconf_client_get_default ();
- ESource *csource, *tsource;
- ESourceList *list;
- EGwSendOptionsGeneral *gopts;
- EGwSendOptionsStatusTracking *topts, *mopts, *copts;
-
- list = e_source_list_new_for_gconf (gconf, "/apps/evolution/calendar/sources");
- csource = get_source (list);
-
- list = e_source_list_new_for_gconf (gconf, "/apps/evolution/tasks/sources");
- tsource = get_source (list);
-
- gopts = e_gw_sendoptions_get_general_options (n_opts);
- mopts = e_gw_sendoptions_get_status_tracking_options (n_opts, "mail");
- copts = e_gw_sendoptions_get_status_tracking_options (n_opts, "calendar");
- topts = e_gw_sendoptions_get_status_tracking_options (n_opts, "task");
-
- if (csource)
- put_options_in_source (csource, gopts, copts);
-
- if (tsource)
- put_options_in_source (tsource, gopts, topts);
-
- g_object_unref (gconf);
-}
-
-void
-send_options_commit (EPlugin *epl, EConfigHookItemFactoryData *data)
-{
- EGwSendOptions *n_opts;
- EGwConnectionStatus status = E_GW_CONNECTION_STATUS_OK;
-
- if (sod) {
- n_opts = e_gw_sendoptions_new ();
- send_options_copy_check_changed (n_opts);
-
- if (changed)
- status = e_gw_connection_modify_settings (n_cnc, n_opts);
-
- if (!changed || status != E_GW_CONNECTION_STATUS_OK) {
- g_warning (G_STRLOC "Cannot modify Send Options: %s", e_gw_connection_get_error_message (status));
- g_object_unref (n_opts);
- n_opts = NULL;
- } else
- add_send_options_to_source (n_opts);
- }
-
- send_options_finalize ();
-}
-
-void
-send_options_changed (EPlugin *epl, EConfigHookItemFactoryData *data)
-{
-}
-
-void
-send_options_abort (EPlugin *epl, EConfigHookItemFactoryData *data)
-{
- send_options_finalize ();
-}
-
-
diff --git a/plugins/shared-folder/ChangeLog b/plugins/shared-folder/ChangeLog
deleted file mode 100644
index 833f871ba2..0000000000
--- a/plugins/shared-folder/ChangeLog
+++ /dev/null
@@ -1,101 +0,0 @@
-2005-02-17 Vivek Jain <jvivek@novell.com>
-
- * share-folder-common.c : (get_cnc):
-
- use ssl when "always" and "whenever possible" is enabled
- changed "soap_ssl" to "use_ssl"
- use the default port "7191" instead of "7181"
-
-2005-01-24 Vivek Jain <jvivek@novell.com>
- *properties.glade : changed the layout of the widgets
- *share-folder.[ch]: removed the checkbuttons for display of rights
- : removed new_list, update_list and remove_list
- added users_list
- *share-folder.c : removed function (update_list_update)
- (share_folder_construct) : added gtk_cell_renderer_toggle for
- displaying rights
- added one structure SharedUsers to have a single list instead of three
- different lists. Made corresponding changes in all functions.
- *share-folder-common.c : (new_folder_response): use
- gtk_widget_reparent to pack the widget
- added two files
- *org-gnome-shared-folder-errors.xml
- *org-gnome-shared-folder-errors.xml.h : to display error message
- *Makefile.am : included error data
-
-
-
-2005-01-19 Vivek Jain <jvivek@novell.com>
- *install-shared.c
- (org_gnome_popup_wizard): fixed a crash, caused by g_free
- (install_folder_response): free the memory
-
-2005-01-18 Vivek Jain <jvivek@novell.com>
- *install-shared.c
- (org_gnome_popup_wizard): removed unnecessary stuff for the display of
- wizard
-
-2005-01-18 Parthasarathi Susarla <sparthasarathi@novell.com>
-
- *install-shared.c
- (org_gnome_popup_wizard): displays the message without the
- mime headers
-
-2005-01-17 Vivek Jain <jvivek@novell.com>
- *install-shared.c : (org_gnome_popup_wizard): included a condition
- (null check) to fix a crash
- * shared-folder-common.c :(org_gnome_shared_folder_factory): some
- condition checks to avoid the possible crashes
- (get_container_id): included code to return top level container id if
- folder name is passed as null
-
-2005-01-13 Vivek Jain <jvivek@novell.com>
- * share-folder.c :changed the function find_node to return user node
- corresponding to the mail address given.
- (add_clicked): added a condition so that user can't share folder to itself.
- (user_selected): modified to display proper rights when owner is selected.
- * share-folder-common.c : calling share_folder with a cnc in it.
-
-2005-01-11 Vivek Jain <jvivek@novell.com>
- killed compile time warnings by including suitable definitions
- and type casting widgets
-
-2005-01-10 Vivek Jain <jvivek@novell.com> Included
-
- * install-shared.c : opens up a wizard on reading a shared folder
- notification and installs shared folder at the recepient end.
- * share-folder-common.c : added
- (refresh_folder_tree) : to refresh the folder tree when a folder is shared or
- a shared folder is created so that different icons are displayed
- (get_cnc): to get a connection
- (get_container_id):to get the container id of the folder user selects
- * share-folder.c : minor changes to fix the crash
- * Makefile.am : including install-shared.c in sources
- * org-gnome-shared-folder.eplug.in : added a plugin to the e-plugin list for
- the message-read event
-
-2004-12-15 Vivek Jain <jvivek@novell.com>
-
- Added (Create a shared folder) functionality in the plugin
- * org-gnome-shared-folder.eplug.in : added a plugin in the plugin list
- * share-folder-common.c : included functions to create a shared folder
-
-2004-12-15 Vivek Jain <jvivek@novell.com>
-
- * shared-folder-common.c : (org_gnome_shared_folder_factory)
- * shared-folder.c : some whitespace changes, typecasting widgets,
- in (on_add_clicked) removed assigning the rights portion
-
- 2004-12-08 Vivek Jain <jvivek@novell.com>
-
- The following files are added as an initial check in for the plugin that
- implements shared-folder functionality in the groupwise folders
- * share-folder.c
- * share-folder.h
- * share-folder-common.c
- * properties.glade
- * Makefile.am
- * org-gnome-shared-folder.eplug.in
-
-
-
diff --git a/plugins/shared-folder/Makefile.am b/plugins/shared-folder/Makefile.am
deleted file mode 100644
index 08d1f0b29a..0000000000
--- a/plugins/shared-folder/Makefile.am
+++ /dev/null
@@ -1,32 +0,0 @@
-INCLUDES = \
- -I$(top_srcdir)\
- -I$(top_srcdir)/camel \
- $(EVOLUTION_MAIL_CFLAGS)\
- $(CAMEL_GROUPWISE_CFLAGS)\
- -DEVOLUTION_GLADEDIR=\""$(gladedir)"\"
-
-@EVO_PLUGIN_RULE@
-
-plugin_DATA = org-gnome-shared-folder.eplug
-plugin_LTLIBRARIES = liborg-gnome-shared-folder.la
-
-liborg_gnome_shared_folder_la_SOURCES = share-folder-common.c share-folder.c install-shared.c share-folder.h
-liborg_gnome_shared_folder_la_LIBADD= $(CAMEL_GROUPWISE_LIBS)
-
-
-liborg_gnome_shared_folder_la_LDFLAGS = -module -avoid-version
-
-glade_DATA =properties.glade
-
-error_DATA = org-gnome-shared-folder-errors.xml
-error_i18n = $(error_DATA:.xml=.xml.h)
-errordir = $(privdatadir)/errors
-%.xml.h: %.xml
- $(top_builddir)/e-util/e-error-tool $^
-
-BUILT_SOURCES = $(error_i18n)
-EXTRA_DIST = \
- $(error_DATA) \
- $(error_i18n) \
- $(glade_DATA) \
- org-gnome-shared-folder.eplug.in
diff --git a/plugins/shared-folder/install-shared.c b/plugins/shared-folder/install-shared.c
deleted file mode 100644
index d92e926764..0000000000
--- a/plugins/shared-folder/install-shared.c
+++ /dev/null
@@ -1,221 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * Authors: Vivek Jain <jvivek@novell.com>
- *
- * Copyright 2004 Novell, Inc.
- *
- * 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., 59 Temple Street #330, Boston, MA 02111-1307, USA.
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <string.h>
-#include <glib.h>
-#include <gnome.h>
-#include <gtk/gtk.h>
-#include <libgnomeui/libgnomeui.h>
-#include <libgnome/gnome-i18n.h>
-#include <gconf/gconf-client.h>
-#include <e-util/e-config.h>
-#include <mail/em-config.h>
-#include <mail/em-event.h>
-#include <mail/mail-component.h>
-#include <camel/camel-mime-message.h>
-#include <camel/camel-stream.h>
-#include <camel/camel-session.h>
-#include <camel/camel-stream-mem.h>
-#include <camel/camel-data-wrapper.h>
-#include <camel/camel-multipart.h>
-#include <mail/em-folder-tree.h>
-#include <mail/mail-config.h>
-#include <mail/em-folder-selector.h>
-#include <camel/camel-medium.h>
-#include <e-gw-connection.h>
-#include <share-folder.h>
-
-extern CamelSession *session;
-struct AcceptData {
- const char *item_id;
- EMFolderTreeModel *model;
-};
-
-
-void org_gnome_popup_wizard (EPlugin *ep, EMEventTargetMessage *target);
-
-static void
-install_folder_response (EMFolderSelector *emfs, int response, gpointer *data)
-{
- struct AcceptData *accept_data = (struct AcceptData *)data;
- EMFolderTreeModel *model;
- const char *uri, *path;
- int parts = 0;
- gchar **names;
- gchar *folder_name;
- gchar *parent_name;
- gchar *container_id,*item_id;
- CamelException ex;
- CamelStore *store;
- EAccount *account;
- CamelProvider *provider;
- EGwConnection *cnc;
-
- if (response == GTK_RESPONSE_CANCEL){
- gtk_widget_destroy (GTK_WIDGET (emfs));
- } else {
- model = accept_data->model;
- item_id = accept_data->item_id;
- uri = em_folder_selector_get_selected_uri (emfs);
- path = em_folder_selector_get_selected_path (emfs);
- names = g_strsplit (path, "/", -1);
- if(names == NULL){
- folder_name = (gchar *)path;
- parent_name = NULL;
- } else {
- while (names [parts])
- parts++;
- folder_name = names[parts -1];
- if (parts >= 2)
- parent_name = names[parts -2];
- else
- parent_name = NULL;
- }
- camel_exception_init (&ex);
- if (!(store = (CamelStore *) camel_session_get_service (session, uri, CAMEL_PROVIDER_STORE, &ex))) {
- camel_exception_clear (&ex);
- return;
- }
-
- cnc = get_cnc (store);
- if(E_IS_GW_CONNECTION (cnc)) {
- container_id = get_container_id (cnc, parent_name);
-
- if(e_gw_connection_accept_shared_folder (cnc, folder_name, container_id, item_id, NULL) == E_GW_CONNECTION_STATUS_OK) {
-
- uri = camel_url_to_string (((CamelService *) store)->url, CAMEL_URL_HIDE_ALL);
- account = mail_config_get_account_by_source_url (uri);
- uri = account->source->url;
- em_folder_tree_model_remove_store (model, store);
- camel_exception_init (&ex);
- if (!(provider = camel_provider_get(uri, &ex))) {
- camel_exception_clear (&ex);
- return;
- }
-
- /* make sure the new store belongs in the tree */
- if (!(provider->flags & CAMEL_PROVIDER_IS_STORAGE))
- return;
-
- em_folder_tree_model_add_store (model, store, account->name);
- camel_object_unref (store);
- }
- }
-
- g_strfreev(names);
- gtk_widget_destroy ((GtkWidget *)emfs);
- }
-
-}
-
-static void
-accept_clicked(GnomeDruidPage *page, GtkWidget *druid, const char *id)
-{
- EMFolderTreeModel *model;
- EMFolderTree *folder_tree;
- GtkWidget *dialog ;
- struct AcceptData *accept_data;
- char *uri;
- accept_data = g_new0(struct AcceptData, 1);
- model = mail_component_peek_tree_model (mail_component_peek ());
- folder_tree = (EMFolderTree *) em_folder_tree_new_with_model (model);
- dialog = em_folder_selector_create_new (folder_tree, 0, _("Create folder"), _("Specify where to create the folder:"));
- uri = em_folder_tree_get_selected_uri(folder_tree);
- em_folder_selector_set_selected ((EMFolderSelector *) dialog, uri);
- g_free(uri);
- accept_data->item_id = id;
- accept_data->model = model;
- g_signal_connect (dialog, "response", G_CALLBACK (install_folder_response), accept_data);
- gtk_window_set_title (GTK_WINDOW (dialog), "Install Shared Folder");
- gtk_widget_destroy (druid);
- gtk_widget_show (dialog);
-
-}
-
-void
-org_gnome_popup_wizard (EPlugin *ep, EMEventTargetMessage *target)
-{
- const CamelInternetAddress *from_addr = NULL;
- const char *name, *item_id;
- const char *email;
- GtkWidget *window;
- GnomeDruid *wizard;
- GnomeDruidPageEdge *title_page;
- CamelMimeMessage *msg = (CamelMimeMessage *) target->message ;
- CamelStreamMem *content ;
- CamelDataWrapper *dw ;
- CamelMimePart *mime_part ;
- CamelMultipart *mp ;
- char *notification;
- char *start_message;
- char *buffer = NULL;
-
- if (!msg)
- return ;
-
- mime_part = CAMEL_MIME_PART(msg) ;
- notification = (char *)camel_medium_get_header (CAMEL_MEDIUM(msg),"X-notification") ;
- if (!notification) {
- return ;
-
- } else {
- mp = (CamelMultipart *) camel_medium_get_content_object (CAMEL_MEDIUM (msg)) ;
- dw = camel_data_wrapper_new () ;
- content = (CamelStreamMem *)camel_stream_mem_new();
- if (!mp)
- return ;
-
- if (CAMEL_IS_MULTIPART (mp)) {
- mime_part = camel_multipart_get_part (mp, 0) ;
- dw = camel_medium_get_content_object (CAMEL_MEDIUM (mime_part)) ;
- camel_data_wrapper_write_to_stream(dw, (CamelStream *)content) ;
- buffer = g_malloc0 (content->buffer->len+1) ;
- buffer = memcpy (buffer, content->buffer->data, content->buffer->len) ;
-
- } else {
- dw = camel_medium_get_content_object (CAMEL_MEDIUM (msg)) ;
- camel_data_wrapper_write_to_stream(dw, (CamelStream *)content) ;
- buffer = g_malloc0 (content->buffer->len+1) ;
- buffer = memcpy (buffer, content->buffer->data, content->buffer->len) ;
- }
-
- from_addr = camel_mime_message_get_from ((CamelMimeMessage *)target->message);
- if (camel_internet_address_get (from_addr,0, &name, &email)) {
- start_message = g_strconcat (" The User ", "'", name, "'" ," has shared a folder with you\n\n", " Message from ", "'" , name, "'\n\n\n", buffer, "\n\n\n", "Click 'Forward' to install the shared folder\n\n",NULL);
- title_page = GNOME_DRUID_PAGE_EDGE (gnome_druid_page_edge_new_with_vals(GNOME_EDGE_START, TRUE, "Install the shared folder", start_message, NULL, NULL, NULL));
- wizard = GNOME_DRUID (gnome_druid_new_with_window ("Shared Folder Installation", NULL, TRUE, (GtkWidget**)(&window)));
- gtk_window_set_position (GTK_WINDOW (window) , GTK_WIN_POS_CENTER_ALWAYS);
- gnome_druid_append_page(wizard, GNOME_DRUID_PAGE(title_page));
- gtk_widget_show_all (GTK_WIDGET (title_page));
- item_id = camel_mime_message_get_message_id (msg);
- g_signal_connect (title_page, "next", G_CALLBACK(accept_clicked), item_id);
- } else
- g_warning ("Could not get the sender name");
-
- g_free (buffer) ;
- g_free (start_message) ;
- }
-}
-
diff --git a/plugins/shared-folder/org-gnome-shared-folder-errors.xml b/plugins/shared-folder/org-gnome-shared-folder-errors.xml
deleted file mode 100644
index 6a1339210f..0000000000
--- a/plugins/shared-folder/org-gnome-shared-folder-errors.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<error-list domain="org.gnome.evolution.mail_shared_folder">
-<error id="invalid-user" type="error">
-<primary>Invalid user</primary>
-<secondary>
-You cannot share folder with specified user &quot;{0}&quot;
-</secondary>
-</error>
-
-<error id="no-user" type="error">
-<primary>Specify User</primary>
-<secondary>
- You have to specify a user name whom you want to add to the list
-</secondary>
-</error>
-
-
-</error-list>
-
diff --git a/plugins/shared-folder/org-gnome-shared-folder-errors.xml.h b/plugins/shared-folder/org-gnome-shared-folder-errors.xml.h
deleted file mode 100644
index 7069f413b3..0000000000
--- a/plugins/shared-folder/org-gnome-shared-folder-errors.xml.h
+++ /dev/null
@@ -1,11 +0,0 @@
-/* org.gnome.evolution.mail_shared_folder:invalid-user primary */
-char *s = N_("Invalid user");
-/* org.gnome.evolution.mail_shared_folder:invalid-user secondary */
-char *s = N_("\n"
- "You cannot share folder with specified user \"{0}\" \n"
- "");
-/* org.gnome.evolution.mail_shared_folder:no-user primary */
-char *s = N_("Specify User");
-/* org.gnome.evolution.mail_shared_folder:no-user secondary */
-char *s = N_("\n"
- "\tYou have to specify a user name whom you want to add to the list \n");
diff --git a/plugins/shared-folder/org-gnome-shared-folder.eplug.in b/plugins/shared-folder/org-gnome-shared-folder.eplug.in
deleted file mode 100644
index b91ccf7b5a..0000000000
--- a/plugins/shared-folder/org-gnome-shared-folder.eplug.in
+++ /dev/null
@@ -1,41 +0,0 @@
-<e-plugin-list>
- <e-plugin id="org.gnome.evolution.mail_shared_folder" type="shlib" name="Shared folder" description="shared folder properties "
- location="@PLUGINDIR@/liborg-gnome-shared-folder.so">
- <hook class="org.gnome.evolution.mail.config:1.0">
- <group
- id="org.gnome.evolution.mail.folderConfig"
- target="folder"
- check="shared_folder_check"
- commit="shared_folder_commit"
- abort="shared_folder_abort">
- <item type="page" path="10.shared" label="Shared" factory="org_gnome_shared_folder_factory"/>
- </group>
- </hook>
- </e-plugin>
- <e-plugin id="org.gnome.evolution.mail_view" type="shlib" name="mail view" description="viewing the mail"
- location="@PLUGINDIR@/liborg-gnome-shared-folder.so">
-
-<hook class="org.gnome.evolution.mail.events:1.0">
-<event
- target="message"
- id="message.reading"
- type="pass"
- handle="org_gnome_popup_wizard"/>
-</hook>
-</e-plugin>
-
- <e-plugin id="org.gnome.mail.folder.create_option"
- type="shlib" domain="evolution" name="CREATE Folders"
- location="@PLUGINDIR@/liborg-gnome-shared-folder.so">
- <description>Allows creating shared folders in the folder tree context menu</description>
- <author name="Vivek Jain" email="jvivek@novell.com"/>
- <hook class="org.gnome.evolution.mail.popup:1.0">
- <menu id="org.gnome.evolution.mail.foldertree.popup" target="folder">
- <item type="item" path="20.emc.00" label="_New Shared Folder"
- activate="org_gnome_create_option"
- enable="delete" visible="delete"/>
- </menu>
- </hook>
- </e-plugin>
-
-</e-plugin-list>
diff --git a/plugins/shared-folder/properties.glade b/plugins/shared-folder/properties.glade
deleted file mode 100644
index e2fce0be65..0000000000
--- a/plugins/shared-folder/properties.glade
+++ /dev/null
@@ -1,860 +0,0 @@
-<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
-<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
-
-<glade-interface>
-<requires lib="gnome"/>
-
-<widget class="GtkWindow" id="main_page">
- <property name="title" translatable="yes">Folder Properties</property>
- <property name="type">GTK_WINDOW_TOPLEVEL</property>
- <property name="window_position">GTK_WIN_POS_NONE</property>
- <property name="modal">False</property>
- <property name="resizable">True</property>
- <property name="destroy_with_parent">False</property>
- <property name="decorated">True</property>
- <property name="skip_taskbar_hint">False</property>
- <property name="skip_pager_hint">False</property>
- <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
- <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
-
- <child>
- <widget class="GtkNotebook" id="sharing_props">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="show_tabs">True</property>
- <property name="show_border">True</property>
- <property name="tab_pos">GTK_POS_TOP</property>
- <property name="scrollable">False</property>
- <property name="enable_popup">False</property>
-
- <child>
- <widget class="GtkVBox" id="vboxSharing">
- <property name="border_width">12</property>
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">12</property>
-
- <child>
- <widget class="GtkVBox" id="vboxSharingOptions">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="GtkHBox" id="hbox186">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">12</property>
-
- <child>
- <widget class="GtkLabel" id="label539">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkVBox" id="vbox190">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="GtkRadioButton" id="radNotShared">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">_Not Shared</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkRadioButton" id="radShared">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">_Shared With ...</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- <property name="group">radNotShared</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkVBox" id="vbox194">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">0</property>
-
- <child>
- <widget class="GtkHBox" id="hbox226">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="GtkVBox" id="vbox195">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">0</property>
-
- <child>
- <widget class="GtkHBox" id="hbox227">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">0</property>
-
- <child>
- <widget class="GtkLabel" id="label557">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Name:</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkEntry" id="entry4">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="editable">True</property>
- <property name="visibility">True</property>
- <property name="max_length">0</property>
- <property name="text" translatable="yes"></property>
- <property name="has_frame">True</property>
- <property name="invisible_char" translatable="yes">*</property>
- <property name="activates_default">False</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="users">
- <property name="visible">True</property>
- <property name="label" translatable="yes">&lt;b&gt;Users :&lt;/b&gt;</property>
- <property name="use_underline">False</property>
- <property name="use_markup">True</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">6</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkScrolledWindow" id="scrolledwindow4">
- <property name="width_request">282</property>
- <property name="height_request">150</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="hscrollbar_policy">GTK_POLICY_ALWAYS</property>
- <property name="vscrollbar_policy">GTK_POLICY_ALWAYS</property>
- <property name="shadow_type">GTK_SHADOW_NONE</property>
- <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
-
- <child>
- <placeholder/>
- </child>
- </widget>
- <packing>
- <property name="padding">6</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkVBox" id="vbox196">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="GtkButton" id="Address">
- <property name="width_request">96</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
-
- <child>
- <widget class="GtkAlignment" id="alignment6">
- <property name="visible">True</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xscale">0</property>
- <property name="yscale">0</property>
- <property name="top_padding">0</property>
- <property name="bottom_padding">0</property>
- <property name="left_padding">0</property>
- <property name="right_padding">0</property>
-
- <child>
- <widget class="GtkHBox" id="hbox232">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">2</property>
-
- <child>
- <widget class="GtkImage" id="image5">
- <property name="visible">True</property>
- <property name="stock">gtk-jump-to</property>
- <property name="icon_size">4</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label563">
- <property name="visible">True</property>
- <property name="label" translatable="yes">_Contacts...</property>
- <property name="use_underline">True</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- </child>
- </widget>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkButton" id="Add">
- <property name="width_request">61</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
-
- <child>
- <widget class="GtkAlignment" id="alignment4">
- <property name="visible">True</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xscale">0</property>
- <property name="yscale">0</property>
- <property name="top_padding">0</property>
- <property name="bottom_padding">0</property>
- <property name="left_padding">0</property>
- <property name="right_padding">0</property>
-
- <child>
- <widget class="GtkHBox" id="hbox229">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">2</property>
-
- <child>
- <widget class="GtkImage" id="image3">
- <property name="visible">True</property>
- <property name="stock">gtk-add</property>
- <property name="icon_size">4</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label561">
- <property name="width_request">29</property>
- <property name="visible">True</property>
- <property name="label" translatable="yes">_Add</property>
- <property name="use_underline">True</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- </child>
- </widget>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkButton" id="Remove">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
-
- <child>
- <widget class="GtkAlignment" id="alignment5">
- <property name="visible">True</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xscale">0</property>
- <property name="yscale">0</property>
- <property name="top_padding">0</property>
- <property name="bottom_padding">0</property>
- <property name="left_padding">0</property>
- <property name="right_padding">0</property>
-
- <child>
- <widget class="GtkHBox" id="hbox230">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">2</property>
-
- <child>
- <widget class="GtkImage" id="image4">
- <property name="visible">True</property>
- <property name="stock">gtk-remove</property>
- <property name="icon_size">4</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label562">
- <property name="visible">True</property>
- <property name="label" translatable="yes">_Remove</property>
- <property name="use_underline">True</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- </child>
- </widget>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <placeholder/>
- </child>
-
- <child>
- <widget class="GtkButton" id="Notification">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
-
- <child>
- <widget class="GtkAlignment" id="alignment7">
- <property name="visible">True</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xscale">0</property>
- <property name="yscale">0</property>
- <property name="top_padding">0</property>
- <property name="bottom_padding">0</property>
- <property name="left_padding">0</property>
- <property name="right_padding">0</property>
-
- <child>
- <widget class="GtkHBox" id="hbox233">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">2</property>
-
- <child>
- <widget class="GtkImage" id="image6">
- <property name="visible">True</property>
- <property name="stock">gnome-stock-mail-new</property>
- <property name="icon_size">4</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label564">
- <property name="visible">True</property>
- <property name="label" translatable="yes">_Cutomize notification message</property>
- <property name="use_underline">True</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- </child>
- </widget>
- </child>
- </widget>
- <packing>
- <property name="padding">11</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="tab_expand">False</property>
- <property name="tab_fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="lblSharing">
- <property name="visible">True</property>
- <property name="label" translatable="yes">_Sharing</property>
- <property name="use_underline">True</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_CENTER</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="type">tab</property>
- </packing>
- </child>
- </widget>
- </child>
-</widget>
-
-<widget class="GtkWindow" id="window1">
- <property name="visible">True</property>
- <property name="title" translatable="yes">Shared Folder Notification</property>
- <property name="type">GTK_WINDOW_TOPLEVEL</property>
- <property name="window_position">GTK_WIN_POS_CENTER</property>
- <property name="modal">False</property>
- <property name="resizable">True</property>
- <property name="destroy_with_parent">False</property>
- <property name="decorated">True</property>
- <property name="skip_taskbar_hint">False</property>
- <property name="skip_pager_hint">False</property>
- <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
- <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
-
- <child>
- <widget class="GtkVBox" id="vbox191">
- <property name="border_width">12</property>
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">12</property>
-
- <child>
- <widget class="GtkLabel" id="label551">
- <property name="visible">True</property>
- <property name="label" translatable="yes">The participants will receive the following notification.
-</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_CENTER</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.66</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">1</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkHBox" id="hbox223">
- <property name="height_request">309</property>
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">12</property>
-
- <child>
- <widget class="GtkVBox" id="vbox193">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">5</property>
-
- <child>
- <widget class="GtkLabel" id="label553">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Subject</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_CENTER</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkEntry" id="entry3">
- <property name="width_request">158</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="editable">True</property>
- <property name="visibility">True</property>
- <property name="max_length">0</property>
- <property name="text" translatable="yes"></property>
- <property name="has_frame">True</property>
- <property name="invisible_char" translatable="yes">*</property>
- <property name="activates_default">False</property>
- </widget>
- <packing>
- <property name="padding">6</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label554">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Message</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_CENTER</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkScrolledWindow" id="scrolledwindow3">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="hscrollbar_policy">GTK_POLICY_ALWAYS</property>
- <property name="vscrollbar_policy">GTK_POLICY_ALWAYS</property>
- <property name="shadow_type">GTK_SHADOW_NONE</property>
- <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
-
- <child>
- <widget class="GtkTextView" id="textview1">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="editable">True</property>
- <property name="overwrite">False</property>
- <property name="accepts_tab">True</property>
- <property name="justification">GTK_JUSTIFY_LEFT</property>
- <property name="wrap_mode">GTK_WRAP_NONE</property>
- <property name="cursor_visible">True</property>
- <property name="pixels_above_lines">0</property>
- <property name="pixels_below_lines">0</property>
- <property name="pixels_inside_wrap">0</property>
- <property name="left_margin">0</property>
- <property name="right_margin">0</property>
- <property name="indent">0</property>
- <property name="text" translatable="yes"></property>
- </widget>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkHBox" id="hbox224">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">0</property>
-
- <child>
- <widget class="GtkLabel" id="label555">
- <property name="width_request">248</property>
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.52</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkHButtonBox" id="hbuttonbox2">
- <property name="visible">True</property>
- <property name="layout_style">GTK_BUTTONBOX_END</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="GtkButton" id="nCancel">
- <property name="visible">True</property>
- <property name="can_default">True</property>
- <property name="can_focus">True</property>
- <property name="label">gtk-cancel</property>
- <property name="use_stock">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <signal name="clicked" handler="on_nCancel_clicked" last_modification_time="Tue, 23 Nov 2004 10:56:42 GMT"/>
- </widget>
- </child>
-
- <child>
- <widget class="GtkButton" id="nOK">
- <property name="visible">True</property>
- <property name="can_default">True</property>
- <property name="can_focus">True</property>
- <property name="label">gtk-ok</property>
- <property name="use_stock">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <signal name="clicked" handler="on_nOK_clicked" last_modification_time="Tue, 23 Nov 2004 10:57:50 GMT"/>
- </widget>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">42</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- </child>
-</widget>
-
-</glade-interface>
diff --git a/plugins/shared-folder/share-folder-common.c b/plugins/shared-folder/share-folder-common.c
deleted file mode 100644
index 45996caae6..0000000000
--- a/plugins/shared-folder/share-folder-common.c
+++ /dev/null
@@ -1,476 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * Authors: Vivek Jain <jvivek@novell.com>
- *
- * Copyright 2004 Novell, Inc.
- *
- * 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., 59 Temple Street #330, Boston, MA 02111-1307, USA.
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <string.h>
-#include <glib.h>
-#include <gtk/gtk.h>
-#include <libgnome/gnome-i18n.h>
-#include <e-util/e-config.h>
-#include <mail/em-config.h>
-#include <mail/em-popup.h>
-#include <mail/em-folder-properties.h>
-#include <mail/em-folder-tree.h>
-#include <mail/em-folder-selector.h>
-#include <mail/mail-mt.h>
-#include <mail/mail-component.h>
-#include <mail/mail-config.h>
-#include <mail/em-vfolder-rule.h>
-#include <filter/filter-rule.h>
-#include <camel/camel-store.h>
-#include <camel/camel-session.h>
-#include <camel/camel-store.h>
-#include <camel/camel-vee-store.h>
-#include <camel/camel-folder.h>
-#include <e-gw-container.h>
-#include <e-gw-connection.h>
-#include <glade/glade.h>
-#include <libgnomeui/libgnomeui.h>
-#include "share-folder.h"
-#define d(x)
-
-ShareFolder *common = NULL;
-extern CamelSession *session;
-struct ShareInfo {
- GtkWidget *d;
- ShareFolder *sf;
- EMFolderTreeModel *model;
- EMFolderSelector *emfs;
-};
-
-GtkWidget * org_gnome_shared_folder_factory (EPlugin *ep, EConfigHookItemFactoryData *hook_data);
-void org_gnome_create_option(EPlugin *ep, EMPopupTargetFolder *target);
-void shared_folder_commit (EPlugin *ep, EConfigTarget *tget);
-void shared_folder_abort (EPlugin *ep, EConfigTarget *target);
-
-static void refresh_folder_tree (EMFolderTreeModel *model, CamelStore *store);
-
-static void
-refresh_folder_tree (EMFolderTreeModel *model, CamelStore *store)
-{
- gchar *uri;
- EAccount *account;
- CamelException ex;
- CamelProvider *provider;
-
- uri = camel_url_to_string (((CamelService *) store)->url, CAMEL_URL_HIDE_ALL);
- account = mail_config_get_account_by_source_url (uri);
- uri = account->source->url;
- em_folder_tree_model_remove_store (model, store);
-
- camel_exception_init (&ex);
- if (!(provider = camel_provider_get(uri, &ex))) {
- camel_exception_clear (&ex);
- return;
- }
- if (!(provider->flags & CAMEL_PROVIDER_IS_STORAGE))
- return;
- em_folder_tree_model_add_store (model, store, account->name);
- //camel_object_unref (store);
-}
-
-void
-shared_folder_commit (EPlugin *ep, EConfigTarget *tget)
-{
- EMConfigTargetFolder *target = (EMConfigTargetFolder *)tget->config->target;
- CamelFolder *folder = target->folder;
- CamelStore *store = folder->parent_store;
- EMFolderTreeModel *model = mail_component_peek_tree_model (mail_component_peek ());
- if (common) {
- share_folder (common);
- refresh_folder_tree (model, store);
- g_object_run_dispose ((GObject *)common);
- common = NULL;
- }
-}
-
-void
-shared_folder_abort (EPlugin *ep, EConfigTarget *target)
-{
- if (common) {
- g_object_run_dispose ((GObject *)common);
- common = NULL;
- }
-}
-
-struct _EMCreateFolder {
- struct _mail_msg msg;
-
- /* input data */
- CamelStore *store;
- char *full_name;
- char *parent;
- char *name;
-
- /* output data */
- CamelFolderInfo *fi;
-
- /* callback data */
- void (* done) (struct _EMCreateFolder *m, void *user_data);
- void *user_data;
-};
-
-static char *
-create_folder__desc (struct _mail_msg *mm, int done)
-{
- struct _EMCreateFolder *m = (struct _EMCreateFolder *) mm;
-
- return g_strdup_printf (_("Creating folder `%s'"), m->full_name);
-}
-
-static void
-create_folder__create (struct _mail_msg *mm)
-{
- struct _EMCreateFolder *m = (struct _EMCreateFolder *) mm;
-
- d(printf ("creating folder parent='%s' name='%s' full_name='%s'\n", m->parent, m->name, m->full_name));
-
- if ((m->fi = camel_store_create_folder (m->store, m->parent, m->name, &mm->ex))) {
- if (camel_store_supports_subscriptions (m->store))
- camel_store_subscribe_folder (m->store, m->full_name, &mm->ex);
- }
-}
-
-static void
-create_folder__created (struct _mail_msg *mm)
-{
- struct _EMCreateFolder *m = (struct _EMCreateFolder *) mm;
- struct ShareInfo *ssi = (struct ShareInfo *) m->user_data;
- CamelStore *store = CAMEL_STORE (m->store) ;
- EGwConnection *ccnc;
-
- if (m->done) {
- ccnc = get_cnc (store);
- if(E_IS_GW_CONNECTION (ccnc)) {
- (ssi->sf)->cnc = ccnc;
-
- (ssi->sf)->container_id = g_strdup (get_container_id ((ssi->sf)->cnc, m->name));
- share_folder(ssi->sf);
- }
-
- m->done (m, m->user_data);
- }
-}
-
-static void
-create_folder__free (struct _mail_msg *mm)
-{
- struct _EMCreateFolder *m = (struct _EMCreateFolder *) mm;
-
- camel_store_free_folder_info (m->store, m->fi);
- camel_object_unref (m->store);
- g_free (m->full_name);
- g_free (m->parent);
- g_free (m->name);
-}
-
-static struct _mail_msg_op create_folder_op = {
- create_folder__desc,
- create_folder__create,
- create_folder__created,
- create_folder__free,
-};
-
-static void
-new_folder_created_cb (struct _EMCreateFolder *m, void *user_data)
-{
- struct ShareInfo *ssi = (struct ShareInfo *) user_data;
- EMFolderSelector *emfs = ssi->emfs;
- if (m->fi){
- refresh_folder_tree (ssi->model, m->store);
- gtk_widget_destroy ((GtkWidget *) emfs);
- gtk_widget_destroy ((GtkWidget *) ssi->d);
- }
-
- g_object_unref (emfs);
-}
-
-static int
-create_folder (CamelStore *store, const char *full_name, void (* done) (struct _EMCreateFolder *m, void *user_data), void *user_data)
-{
- char *name, *namebuf = NULL;
- struct _EMCreateFolder *m;
- const char *parent;
- int id;
-
- namebuf = g_strdup (full_name);
- if (!(name = strrchr (namebuf, '/'))) {
- name = namebuf;
- parent = "";
- } else {
- *name++ = '\0';
- parent = namebuf;
- }
-
- m = mail_msg_new (&create_folder_op, NULL, sizeof (struct _EMCreateFolder));
- camel_object_ref (store);
- m->store = store;
- m->full_name = g_strdup (full_name);
- m->parent = g_strdup (parent);
- m->name = g_strdup (name);
- m->user_data = (struct ShareInfo *) user_data;
- m->done = done;
- g_free (namebuf);
- id = m->msg.seq;
- e_thread_put (mail_thread_new, (EMsg *) m);
-
- return id;
-}
-
-static void
-users_dialog_response(GtkWidget *dialog, int response, struct ShareInfo *ssi)
-{
- struct _EMFolderTreeModelStoreInfo *si;
- EMFolderSelector *emfs = ssi->emfs;
- const char *uri, *path;
- CamelException ex;
- CamelStore *store;
-
- if (response != GTK_RESPONSE_OK) {
- gtk_widget_destroy ((GtkWidget *) emfs);
- gtk_widget_destroy(dialog);
- return;
- }
-
- uri = em_folder_selector_get_selected_uri (emfs);
- path = em_folder_selector_get_selected_path (emfs);
-
- d(printf ("Creating new folder: %s (%s)\n", path, uri));
-
- camel_exception_init (&ex);
- if (!(store = (CamelStore *) camel_session_get_service (session, uri, CAMEL_PROVIDER_STORE, &ex))) {
- camel_exception_clear (&ex);
- return;
- }
-
- if (!(si = g_hash_table_lookup ((ssi->model)->store_hash, store))) {
- g_assert_not_reached ();
- camel_object_unref (store);
- return;
- }
-
- if (CAMEL_IS_VEE_STORE(store)) {
- EMVFolderRule *rule;
-
- rule = em_vfolder_rule_new();
- filter_rule_set_name((FilterRule *)rule, path);
- vfolder_gui_add_rule(rule);
- gtk_widget_destroy((GtkWidget *)emfs);
- } else {
- g_object_ref (emfs);
- ssi->d = dialog;
- create_folder (si->store, path, new_folder_created_cb, ssi);
-
- }
- camel_object_unref (store);
-}
-
-static void
-new_folder_response (EMFolderSelector *emfs, int response, EMFolderTreeModel *model)
-{
- GtkWidget *users_dialog;
- GtkWidget *w;
- struct ShareInfo *ssi;
- const char *uri;
- EGwConnection *cnc;
- CamelException ex;
- CamelStore *store;
-
- ssi = g_new0(struct ShareInfo, 1);
- if (response != GTK_RESPONSE_OK) {
- gtk_widget_destroy ((GtkWidget *) emfs);
- return;
- }
-
- /* i want store at this point to get cnc not sure proper or not*/
- uri = em_folder_selector_get_selected_uri (emfs);
- camel_exception_init (&ex);
- if (!(store = (CamelStore *) camel_session_get_service (session, uri, CAMEL_PROVIDER_STORE, &ex))) {
- camel_exception_clear (&ex);
- return;
- }
-
- cnc = get_cnc (store);
- users_dialog = gtk_dialog_new_with_buttons (
- _("Users"), NULL, GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
- w = gtk_label_new_with_mnemonic (_("Enter the users and set permissions"));
- gtk_widget_show(w);
- gtk_box_pack_start(GTK_BOX (GTK_DIALOG (users_dialog)->vbox), (GtkWidget *) w, TRUE, TRUE, 6);
- ssi->sf = share_folder_new (cnc, NULL);
- gtk_widget_set_sensitive (GTK_WIDGET ((ssi->sf)->table), TRUE);
- ssi->model = model;
- ssi->emfs = emfs;
- gtk_widget_reparent (GTK_WIDGET ((ssi->sf)->table), GTK_DIALOG (users_dialog)->vbox);
- gtk_widget_hide((GtkWidget*) emfs);
- gtk_window_resize (GTK_WINDOW (users_dialog), 350, 300);
- gtk_widget_show(users_dialog);
- g_signal_connect (users_dialog, "response", G_CALLBACK (users_dialog_response), ssi);
-
- camel_object_unref (store);
- return ;
-
-}
-
-void
-org_gnome_create_option(EPlugin *ep, EMPopupTargetFolder *target)
-{
-
- EMFolderTreeModel *model;
- EMFolderTree *folder_tree;
- GtkWidget *dialog ;
- char *uri;
-
- model = mail_component_peek_tree_model (mail_component_peek ());
- folder_tree = (EMFolderTree *) em_folder_tree_new_with_model (model);
- dialog = em_folder_selector_create_new (folder_tree, 0, _("Create folder"), _("Specify where to create the folder:"));
- uri = em_folder_tree_get_selected_uri(folder_tree);
- em_folder_selector_set_selected ((EMFolderSelector *) dialog, uri);
- g_free(uri);
- g_signal_connect (dialog, "response", G_CALLBACK (new_folder_response), model);
- gtk_window_set_title (GTK_WINDOW (dialog), "New Shared Folder" );
- gtk_widget_show(dialog);
-
-}
-
-GtkWidget *
-org_gnome_shared_folder_factory (EPlugin *ep, EConfigHookItemFactoryData *hook_data)
-{
-
- gchar *folderuri = NULL;
- gchar *account = NULL;
- gchar *id = NULL;
- gchar *sub = NULL;
- EGwConnection *cnc;
- ShareFolder *sharing_tab;
- EMConfigTargetFolder *target= (EMConfigTargetFolder *)hook_data->config->target;
-
- folderuri = g_strdup(target->uri);
- if (folderuri) {
- account = g_strrstr(folderuri, "groupwise");
- sub = g_strrstr(folderuri, "#");
- } else
- return NULL;
-
- if(sub == NULL)
- sub = g_strrstr(folderuri, "/");
- if (sub)
- sub++;
- else
- return NULL;
-
- if ( !( strcmp (sub, "Mailbox") && strcmp (sub, "Calendar") && strcmp (sub, "Contacts") && strcmp (sub, "Documents") && strcmp (sub, "Authored") && strcmp (sub, "Default Library") && strcmp (sub, "Work In Progress") && strcmp (sub, "Cabinet") && strcmp (sub, "Sent Items") && strcmp (sub, "Trash") && strcmp (sub, "Checklist"))) {
- g_free (folderuri);
- return NULL;
- }
-
- if (account) {
- CamelFolder *folder = target->folder;
- CamelStore *store = folder->parent_store;
- cnc = get_cnc (store);
- if (E_IS_GW_CONNECTION (cnc))
- id = get_container_id (cnc, sub);
- else
- g_warning("Could not Connnect\n");
-
- g_free (folderuri);
- if (cnc && id)
- sharing_tab = share_folder_new (cnc, id);
- else
- return NULL;
-
- gtk_notebook_append_page((GtkNotebook *) hook_data->parent, (GtkWidget *) sharing_tab->vbox, gtk_label_new_with_mnemonic N_("Sharing"));
- common = sharing_tab;
-
- return GTK_WIDGET (sharing_tab);
- } else
- return NULL;
-}
-
-EGwConnection *
-get_cnc (CamelStore *store)
-{
- EGwConnection *cnc;
- const char *uri, *property_value, *server_name, *user, *port;
- char *use_ssl;
- CamelService *service;
- CamelURL *url;
-
- if (!store)
- return NULL;
-
- service = CAMEL_SERVICE(store);
- url = service->url;
- server_name = g_strdup (url->host);
- user = g_strdup (url->user);
- property_value = camel_url_get_param (url, "soap_port");
- use_ssl = g_strdup (camel_url_get_param (url, "use_ssl"));
- if(property_value == NULL)
- port = g_strdup ("7191");
- else if (strlen(property_value) == 0)
- port = g_strdup ("7191");
- else
- port = g_strdup (property_value);
-
- if (use_ssl && !g_str_equal (use_ssl, "never"))
- uri = g_strconcat ("https://", server_name, ":", port, "/soap", NULL);
- else
- uri = g_strconcat ("http://", server_name, ":", port, "/soap", NULL);
-
- cnc = e_gw_connection_new (uri, user, service->url->passwd);
- if (!E_IS_GW_CONNECTION(cnc) && use_ssl && g_str_equal (use_ssl, "when-possible")) {
- char *http_uri = g_strconcat ("http://", uri + 8, NULL);
- cnc = e_gw_connection_new (http_uri, user, service->url->passwd);
- g_free (http_uri);
- }
- g_free (use_ssl);
- use_ssl = NULL;
-
- return cnc;
-
-}
-
-gchar *
-get_container_id(EGwConnection *cnc, gchar *fname)
-{
- GList *container_list = NULL;
- gchar *id = NULL;
- const char *name;
- /* get list of containers */
- if (e_gw_connection_get_container_list (cnc, "folders", &(container_list)) == E_GW_CONNECTION_STATUS_OK) {
- GList *container = NULL;
-
- for (container = container_list; container != NULL; container = container->next) {
- name = e_gw_container_get_name (container->data);
- /* if Null is passed as name then we return top lavel id*/
- if (fname == NULL) {
- id = g_strdup (e_gw_container_get_id (container->data));
- break;
- } else if (!strcmp (name, fname)) {
- id = g_strdup (e_gw_container_get_id (container->data));
- break;
- }
- }
- e_gw_connection_free_container_list (container_list);
- }
- return id;
-}
diff --git a/plugins/shared-folder/share-folder.c b/plugins/shared-folder/share-folder.c
deleted file mode 100644
index 84bc93b2f3..0000000000
--- a/plugins/shared-folder/share-folder.c
+++ /dev/null
@@ -1,742 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * Author: Vivek Jain <jvivek@novell.com>
- *
- * Copyright 2004 Novell, Inc.
- *
- * 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., 59 Temple Street #330, Boston, MA 02111-1307, USA.
- *
- */
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-#include <glade/glade.h>
-#include "share-folder.h"
-#include <glib/gmain.h>
-#include <gtk/gtktreemodel.h>
-#include <gtk/gtkliststore.h>
-#include <gtk/gtktreeselection.h>
-#include <gtk/gtktreeview.h>
-#include <gtk/gtkdialog.h>
-#include <gtk/gtkbutton.h>
-#include <gtk/gtk.h>
-#include <gtk/gtktogglebutton.h>
-#include <gtk/gtkcellrenderertoggle.h>
-#include <gtk/gtkcellrenderertext.h>
-#include <libedataserverui/e-contact-store.h>
-#include <libgnomeui/gnome-ui-init.h>
-#include <libgnome/gnome-init.h>
-#include <widgets/misc/e-error.h>
-#include <e-gw-container.h>
-#include <e-gw-connection.h>
-#define ROOTNODE "vboxSharing"
-#define NROOTNODE "vbox191"
-#define d(x)
-
-struct _SharedUser {
- EShUsers *user_node;
- int flag;
-};
-typedef struct _SharedUser SharedUser;
-
-static void share_folder_class_init (ShareFolderClass *class);
-static void share_folder_init (ShareFolder *sf);
-static void share_folder_destroy (GtkObject *obj);
-static void share_folder_finalise (GObject *obj);
-static void free_user_node(EShUsers *user);
-static void free_node(SharedUser *user);
-static void free_all(ShareFolder *sf);
-static SharedUser * find_node(GList *list, gchar *email);
-static void free_all(ShareFolder *sf);
-static void get_container_list (ShareFolder *sf);
-static void user_selected(GtkTreeSelection *selection, ShareFolder *sf);
-static void not_shared_clicked (GtkRadioButton *button, ShareFolder *sf);
-static void shared_clicked (GtkRadioButton *button, ShareFolder *sf);
-static void add_clicked(GtkButton *button, ShareFolder *sf);
-static void remove_clicked(GtkButton *button, ShareFolder *sf);
-static void not_ok_clicked(GtkButton *button, ShareFolder *sf);
-static void not_cancel_clicked(GtkButton *button, GtkWidget *window);
-static void not_cancel_clicked(GtkButton *button, GtkWidget *window);
-static void share_folder_construct (ShareFolder *sf);
-GType share_folder_get_type (void);
-
-static GtkVBoxClass *parent_class = NULL;
-
-GType
-share_folder_get_type (void)
-{
- static GType type = 0;
-
- if (!type) {
- static const GTypeInfo info = {
- sizeof (ShareFolderClass),
- NULL, NULL,
- (GClassInitFunc) share_folder_class_init,
- NULL, NULL,
- sizeof (ShareFolder),
- 0,
- (GInstanceInitFunc) share_folder_init
- };
-
- type = g_type_register_static (gtk_vbox_get_type (), "ShareFolder", &info, 0);
- }
-
- return type;
-}
-
-static void
-share_folder_class_init (ShareFolderClass *klass)
-{
- GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
- GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass);
-
- parent_class = g_type_class_ref (gtk_vbox_get_type ());
- object_class->destroy = share_folder_destroy;
- gobject_class->finalize = share_folder_finalise;
-}
-
-static void
-share_folder_finalise (GObject *obj)
-{
- ShareFolder *sf = (ShareFolder *) obj;
- g_object_unref (sf->xml);
- free_all(sf);
- G_OBJECT_CLASS (parent_class)->finalize (obj);
-}
-
-static void
-share_folder_destroy (GtkObject *obj)
-{
-
- ShareFolder *sf = (ShareFolder *) obj;
- free_all (sf);
- GTK_OBJECT_CLASS (parent_class)->destroy (obj);
-}
-
-static void
-share_folder_init (ShareFolder *sf)
-{
- sf->gcontainer = NULL;
- sf->users = 0;
- sf->flag_for_ok = 0;
- sf->shared = FALSE;
- sf->container_list = NULL;
- sf->users_list = NULL;
- sf->sub = "Shared Folder notification";
- sf->message = NULL;
-}
-
-static void
-free_user_node(EShUsers *user)
-{
- if(user){
- g_free(user->email);
- user->email = NULL;
- }
- return ;
-}
-
-static void
-free_node(SharedUser *usr)
-{
- EShUsers *user = usr->user_node;
- if(user){
- g_free(user->email);
- user->email = NULL;
- }
- return ;
-}
-
-static SharedUser *
-find_node(GList *list, gchar *email)
-{
- SharedUser *user = NULL;
- EShUsers *usr = NULL;
- GList *tmp;
- gint i ;
-
- if(list){
- tmp = g_list_first(list);
- for(i=0; tmp ; i++)
- {
- user = tmp->data;
- usr = user->user_node;
- if(!g_ascii_strcasecmp(usr->email, email)){
- return user; /*if found, it returns that user*/
- }
- tmp= g_list_next(tmp);
- }
- }
- return NULL;
-}
-
-static void
-free_all (ShareFolder *sf)
-{
- if (sf->users_list){
- g_list_foreach (sf->users_list,(GFunc) free_node, NULL);
- g_list_free (sf->users_list);
- sf->users_list = NULL;
- }
-
- e_gw_connection_free_container_list (sf->container_list);
-}
-
-
-static void
-display_container (EGwContainer *container , ShareFolder *sf)
-{
- gchar **tail;
- gchar *id_shared;
- gchar *id_unshared;
- gboolean byme = FALSE;
- gboolean tome = FALSE;
- gchar *email = NULL;
- gchar *msg;
- GList *user_list = NULL;
- EShUsers *user = NULL;
-
- id_shared = g_strdup(e_gw_container_get_id(container));
- /* this has to be done since id changes after the folder is shared*/
- if( g_str_has_suffix (id_shared, "35")){
- tail = g_strsplit(id_shared, "@", 2);
- id_unshared = g_strconcat(tail[0], "@", "13", NULL);
- g_strfreev(tail);
- }
-
- if((!g_ascii_strcasecmp(id_unshared, sf->container_id)) || (!g_ascii_strcasecmp(id_shared, sf->container_id)) ){
- sf->gcontainer = container;
- byme = e_gw_container_get_is_shared_by_me(container);
- tome = e_gw_container_get_is_shared_to_me(container);
- if(byme || tome) {
- e_gw_container_get_user_list (sf->gcontainer, &user_list);
- sf->users = g_list_length (user_list);
- if(sf->users != 0) {
- sf->is_shared = TRUE;
- gtk_toggle_button_set_active((GtkToggleButton *) sf->shared, TRUE);
- shared_clicked(sf->shared , sf);
- if (tome) {
- gtk_widget_set_sensitive (GTK_WIDGET (sf->not_shared), FALSE);
- gtk_widget_set_sensitive (GTK_WIDGET (sf->add_button), FALSE);
- gtk_widget_set_sensitive (GTK_WIDGET (sf->remove), FALSE);
- gtk_widget_set_sensitive (GTK_WIDGET (sf->add_book), FALSE);
- gtk_widget_set_sensitive (GTK_WIDGET (sf->notification), FALSE);
- gtk_widget_set_sensitive (GTK_WIDGET (sf->user_list), FALSE);
- email = g_strdup (e_gw_container_get_owner (sf->gcontainer));
- msg = g_strconcat (email, " (Owner)", NULL);
- gtk_list_store_append (GTK_LIST_STORE (sf->model), &(sf->iter));
- gtk_list_store_set (GTK_LIST_STORE (sf->model), &(sf->iter), 0, msg, -1);
- g_free (msg);
- g_free (email);
-
- } else
- gtk_widget_set_sensitive (GTK_WIDGET (sf->table), TRUE);
-/* I populate the list and set flags to 0 for the existing users*/
- while (user_list) {
- SharedUser *shared_user = g_new0 (SharedUser , 1);
- gboolean add, edit, delete;
- add = edit = delete = FALSE;
- user = user_list->data;
- shared_user->user_node = user;
- shared_user->flag = 0;
- email = g_strdup (user->email);
- if (user->rights & 0x1)
- add = TRUE;
- if (user->rights & 0x2)
- edit = TRUE;
- if (user->rights & 0x4)
- delete = TRUE;
-
- msg = g_strdup_printf ("%s", email);
- gtk_list_store_append (GTK_LIST_STORE (sf->model), &(sf->iter));
- gtk_list_store_set (GTK_LIST_STORE (sf->model), &(sf->iter), 0, msg, 1, add, 2, edit, 3, delete, -1);
- sf->users_list = g_list_append (sf->users_list, shared_user);
- g_free (msg);
- g_free (email);
- msg = NULL;
- email = NULL;
- user_list = user_list->next;
- }
- /* i also need to display status*/
- } else {
-
- gtk_toggle_button_set_active ((GtkToggleButton *) sf->not_shared, TRUE);
- not_shared_clicked (sf->not_shared , sf);
- }
- }
- }
-}
-
-static void
-get_container_list (ShareFolder *sf)
-{
- sf->container_list = NULL;
- if (E_IS_GW_CONNECTION (sf->cnc)) {
- /* get list of containers */
- if (e_gw_connection_get_container_list (sf->cnc, "folders", &(sf->container_list)) == E_GW_CONNECTION_STATUS_OK) {
- GList *container = NULL;
-
- for (container = sf->container_list; container != NULL; container = container->next)
- display_container (E_GW_CONTAINER (container->data), sf);
-
- }
- else
- g_warning("Could not get the Container List");
- }
-}
-
-
-static void
-shared_clicked (GtkRadioButton *button, ShareFolder *sf)
-{
-
- gtk_widget_set_sensitive (GTK_WIDGET (sf->table) ,TRUE);
- sf->flag_for_ok = 0;
-}
-
-static void
-not_shared_clicked (GtkRadioButton *button, ShareFolder *sf)
-{
- if (!sf->is_shared) {
- sf->flag_for_ok = 0;
- } else {
- sf->flag_for_ok = 2;
- }
- gtk_widget_set_sensitive (GTK_WIDGET (sf->table), FALSE);
-
-}
-
-static void
-add_clicked(GtkButton *button, ShareFolder *sf)
-{
- const char *email = NULL;
- const char *self_email = NULL;
- SharedUser *new_user = NULL;
- EShUsers *usr = NULL;
- gint rights = 0;
- gchar *msg = NULL;
- EDestinationStore *destination_store;
- GList *destinations, *tmp;
- ENameSelectorEntry *name_selector_entry;
-
- name_selector_entry = e_name_selector_peek_section_entry (sf->name_selector, "Add User");
- destination_store = e_name_selector_entry_peek_destination_store (E_NAME_SELECTOR_ENTRY (
- name_selector_entry));
- destinations = e_destination_store_list_destinations (destination_store);
- tmp = destinations;
- self_email = g_strdup (e_gw_connection_get_user_email (sf->cnc));
- for (; tmp != NULL; tmp = g_list_next (tmp)) {
- email = e_destination_get_email (tmp->data);
- /* You can't share a folder with yourself*/
- if (g_strrstr (email, "@") == NULL || (!g_ascii_strcasecmp (email , self_email)))
- e_error_run (NULL, "org.gnome.evolution.mail_shared_folder:invalid-user",email ,NULL);
- else {
- if (!g_ascii_strcasecmp (email, "" )) {
- e_error_run (NULL, "org.gnome.evolution.mail_shared_folder:no-user",NULL);
-
- return ;
- }
-
-
- /*check whether already exists*/
- if (sf->users_list && email){
- new_user = find_node (sf->users_list, (gchar *)email);
- if (new_user)
- return ;
-
- }
- usr = g_new0 (EShUsers, 1);
- new_user = g_new0 (SharedUser, 1);
- usr->email = g_strdup(email);
- usr->rights = rights;
- new_user->user_node = usr;
- new_user->flag = 1;
- msg = g_strdup (email);
- gtk_list_store_append (GTK_LIST_STORE (sf->model), &(sf->iter));
-
- /* have to add code for rights*/
- gtk_list_store_set (GTK_LIST_STORE (sf->model), &(sf->iter), 0, msg, -1);
- g_free(msg);
- sf->users_list = g_list_append (sf->users_list, new_user);
- sf->flag_for_ok = 0;
- }
- }
- gtk_entry_set_text (GTK_ENTRY(name_selector_entry), "");
-
-}
-
-static void
-remove_clicked(GtkButton *button, ShareFolder *sf)
-{
-
- SharedUser *usr = NULL;
- gchar *email;
-
- gtk_tree_model_get ((GtkTreeModel *) sf->model, &(sf->iter), 0, &email, -1);
- usr = find_node (sf->users_list, email);
- if (usr->flag & 0x1) {
- sf->users_list = g_list_remove (sf->users_list, usr);
- free_node(usr);
- } else {
- usr->flag = 0;
- usr->flag |= 0x4;
- }
- g_free (email);
- gtk_list_store_remove (GTK_LIST_STORE (sf->model), &(sf->iter));
- sf->flag_for_ok = 1;
-}
-
-void
-share_folder (ShareFolder *sf)
-{
-
- GList *new_list = NULL;
- GList *update_list = NULL;
- GList *remove_list = NULL;
- GList *node = NULL;
- SharedUser *user = NULL;
-
- for (node = sf->users_list; node; node = node->next)
- {
- user = node->data;
- if (user->flag & 0x1)
- new_list = g_list_append (new_list, user->user_node);
- else if (user->flag & 0x2)
- update_list = g_list_append (update_list, user->user_node);
- else if (user->flag & 0x4) {
- remove_list = g_list_append (remove_list, user->user_node);
- }
- }
-
- if (E_IS_GW_CONNECTION (sf->cnc)) {
- if(sf->flag_for_ok == 2){ /* you have to remove all the users*/
- GList *list = NULL;
-
- if(new_list){
- g_list_foreach (new_list, (GFunc) free_user_node, NULL);
- g_list_free (new_list);
- }
- if(update_list){
- g_list_foreach (update_list, (GFunc) free_user_node, NULL);
- g_list_free (update_list);
- }
-
- new_list = NULL;
- if(remove_list){
- g_list_foreach (remove_list,(GFunc) free_user_node, NULL);
- g_list_free (remove_list);
- }
- remove_list = NULL;
- if (sf->gcontainer) {
- e_gw_container_get_user_list (sf->gcontainer, &list);
- remove_list = g_list_copy (list);
-
- } else {
- g_warning("Container is Null");
- }
-
-
- } else {
- if (new_list) {
- if (e_gw_connection_share_folder (sf->cnc, sf->container_id, new_list, sf->sub, sf->mesg, 0) == E_GW_CONNECTION_STATUS_OK);
- }
-
- if (update_list) {
- sf->sub = "Shared Folder rights updated";
-
- if (e_gw_connection_share_folder (sf->cnc, sf->container_id, update_list, sf->sub, sf->mesg, 2) == E_GW_CONNECTION_STATUS_OK);
- }
- }
- if (remove_list) {
- sf->sub = "Shared Folder removed";
- if (e_gw_connection_share_folder (sf->cnc, sf->container_id, remove_list, sf->sub, sf->mesg, 1) == E_GW_CONNECTION_STATUS_OK);
- }
-
- }
-}
-
-static void
-not_ok_clicked(GtkButton *button, ShareFolder *sf)
-{
-
- gchar *subj = NULL;
- gchar *msg = NULL;
- GtkTextIter *start, *end;
- GtkTextBuffer *buffer;
-
- buffer = gtk_text_buffer_new (NULL);
- start = g_new0 (GtkTextIter, 1);
- end = g_new0 (GtkTextIter, 1);
- subj = g_strdup (gtk_entry_get_text (sf->subject));
- if (subj)
- sf->sub = subj;
- buffer = gtk_text_view_get_buffer (sf->message);
- gtk_text_buffer_get_start_iter (buffer, start);
- gtk_text_buffer_get_end_iter (buffer, end);
- msg = gtk_text_buffer_get_text (buffer, start, end, FALSE);
- if (msg)
- sf->mesg = msg;
- gtk_widget_destroy (GTK_WIDGET (sf->window));
-
-}
-
-static void
-not_cancel_clicked(GtkButton *button, GtkWidget *window)
-{
- gtk_widget_destroy(window);
-}
-
-
-static void
-notification_clicked(GtkButton *button, ShareFolder *sf)
-{
- static GladeXML *xmln;
- GtkButton *not_ok;
- GtkButton *not_cancel;
- GtkWidget *vbox;
-
- sf->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
- xmln = glade_xml_new (EVOLUTION_GLADEDIR "/properties.glade", NROOTNODE , NULL);
- vbox = GTK_WIDGET (glade_xml_get_widget (xmln, "vbox191"));
- gtk_container_add (GTK_CONTAINER (sf->window), vbox);
- sf->subject = GTK_ENTRY (glade_xml_get_widget (xmln, "entry3"));
- gtk_entry_set_text(GTK_ENTRY (sf->subject) , sf->sub);
- sf->message = GTK_TEXT_VIEW (glade_xml_get_widget (xmln, "textview1"));
- not_ok = GTK_BUTTON (glade_xml_get_widget (xmln, "nOK"));
- g_signal_connect ((gpointer) not_ok, "clicked", G_CALLBACK (not_ok_clicked), sf);
- not_cancel = GTK_BUTTON (glade_xml_get_widget (xmln, "nCancel"));
- g_signal_connect ((gpointer) not_cancel, "clicked", G_CALLBACK (not_cancel_clicked), sf->window);
- gtk_window_set_title (GTK_WINDOW (sf->window), "Custom Notification");
- gtk_window_set_position (GTK_WINDOW (sf->window) , GTK_WIN_POS_CENTER_ALWAYS);
- gtk_window_set_default_size (GTK_WINDOW (sf->window), 100, 200);
- gtk_widget_show_all (sf->window);
-}
-
-static void
-addressbook_dialog_response (ENameSelectorDialog *name_selector_dialog, gint response, gpointer user_data)
-{
- gtk_widget_hide (GTK_WIDGET (name_selector_dialog));
-}
-
-static void
-addressbook_entry_changed (GtkWidget *entry, gpointer user_data)
-{
-
-}
-
-static void
-address_button_clicked_cb (GtkButton *button, gpointer data)
-{
- ShareFolder *sf = data;
- ENameSelectorDialog *name_selector_dialog;
-
- name_selector_dialog = e_name_selector_peek_dialog (sf->name_selector);
- gtk_widget_show (GTK_WIDGET (name_selector_dialog));
-}
-
- static void
-user_selected(GtkTreeSelection *selection, ShareFolder *sf)
-{
-
- gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
- if (gtk_tree_selection_get_selected (selection, &(sf->model), &(sf->iter))){
- gtk_widget_set_sensitive (GTK_WIDGET (sf->remove), TRUE);
-
- }
-}
-
-
-static void
-add_right_clicked (GtkCellRenderer *renderer, gchar *arg1, ShareFolder *sf )
-{
- gboolean right = FALSE;
- SharedUser *usr = NULL;
- EShUsers *user = NULL;
- char *email = NULL;
- GtkTreeSelection *selection = NULL;
- selection = gtk_tree_view_get_selection(GTK_TREE_VIEW (sf->user_list));
- gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
- if (! gtk_tree_selection_get_selected (selection, &(sf->model), &(sf->iter)));
- gtk_tree_model_get ((GtkTreeModel *) sf->model, &(sf->iter), 0, &email, 1, &right , -1);
- usr = find_node(sf->users_list, email);
- if (!usr)
- return ;
- if(! usr->flag) /* if user was already existing one change the flag to update*/
- usr->flag = usr->flag | 0x2;
- user = usr->user_node;
- if (!right) {
- user->rights |= 0x1;
- gtk_list_store_set (GTK_LIST_STORE (sf->model), &(sf->iter), 1, TRUE, -1);
- } else {
- user->rights &= 0x6;
- gtk_list_store_set (GTK_LIST_STORE (sf->model), &(sf->iter), 1, FALSE, -1);
- }
-
-}
-
- static void
-edit_right_clicked(GtkCellRenderer *renderer, gchar *arg1, ShareFolder *sf )
-{
- gboolean right = FALSE;
- SharedUser *usr = NULL;
- EShUsers *user = NULL;
- char *email = NULL;
- gtk_tree_model_get ((GtkTreeModel *) sf->model, &(sf->iter), 0, &email, 2, &right , -1);
- usr = find_node(sf->users_list, email);
- if(! usr->flag) /* if user was already existing one change the flag to update*/
- usr->flag = usr->flag | 0x2;
- user = usr->user_node;
-
- if (!right) {
- user->rights |= 0x2;
- gtk_list_store_set (GTK_LIST_STORE (sf->model), &(sf->iter), 2, TRUE, -1);
- } else {
- user->rights &= 0x5;
- gtk_list_store_set (GTK_LIST_STORE (sf->model), &(sf->iter), 2, FALSE, -1);
- }
-
-}
-
- static void
-delete_right_clicked(GtkCellRenderer *renderer, gchar *arg1, ShareFolder *sf )
-{
- gboolean right = FALSE;
- SharedUser *usr = NULL;
- EShUsers *user = NULL;
- char *email = NULL;
- gtk_tree_model_get ((GtkTreeModel *) sf->model, &(sf->iter), 0, &email, 3, &right , -1);
- usr = find_node(sf->users_list, email);
- if(! usr->flag) /* if user was already existing one change the flag to update*/
- usr->flag = usr->flag | 0x2;
- user = usr->user_node;
- if (!right) {
- user->rights |= 0x4;
- gtk_list_store_set (GTK_LIST_STORE (sf->model), &(sf->iter), 3, TRUE, -1);
- } else {
- user->rights &= 0x3;
- gtk_list_store_set (GTK_LIST_STORE (sf->model), &(sf->iter), 3, FALSE, -1);
- }
-
-}
-
-static void
-share_folder_construct (ShareFolder *sf)
-{
- GladeXML *xml;
- ENameSelectorDialog *name_selector_dialog;
- ENameSelectorModel *name_selector_model;
- ENameSelectorEntry *name_selector_entry;
- GtkWidget *box;
-
- xml = glade_xml_new (EVOLUTION_GLADEDIR "/properties.glade", ROOTNODE, NULL);
- sf->xml =xml;
-
- if (!sf->xml) {
- g_warning ("could not get xml");
- }
- sf->vbox = GTK_VBOX (glade_xml_get_widget(sf->xml, "vboxSharing"));
- sf->table = GTK_WIDGET (glade_xml_get_widget (sf->xml, "vbox194"));
- gtk_widget_set_sensitive (GTK_WIDGET (sf->table), FALSE);
-
- sf->shared = GTK_RADIO_BUTTON (glade_xml_get_widget (sf->xml, "radShared"));
- g_signal_connect ((gpointer) sf->shared, "clicked", G_CALLBACK (shared_clicked), sf);
-
- sf->not_shared = GTK_RADIO_BUTTON (glade_xml_get_widget (sf->xml, "radNotShared"));
- g_signal_connect ((gpointer) sf->not_shared, "clicked", G_CALLBACK (not_shared_clicked), sf);
-
- sf->add_book = GTK_BUTTON (glade_xml_get_widget (sf->xml, "Address"));
- gtk_widget_set_sensitive (GTK_WIDGET (sf->add_book), TRUE);
- g_signal_connect((GtkWidget *) sf->add_book, "clicked", G_CALLBACK (address_button_clicked_cb), sf);
-
- sf->name_selector = e_name_selector_new ();
- name_selector_dialog = e_name_selector_peek_dialog (sf->name_selector);
- g_signal_connect (name_selector_dialog, "response",
- G_CALLBACK (addressbook_dialog_response), sf);
-
- name_selector_model = e_name_selector_peek_model (sf->name_selector);
- e_name_selector_model_add_section (name_selector_model, "Add User", "Add User", NULL);
-
- name_selector_entry = e_name_selector_peek_section_entry (sf->name_selector, "Add User");
- g_signal_connect (name_selector_entry, "changed",
- G_CALLBACK (addressbook_entry_changed), sf);
-
- sf->add_button = GTK_BUTTON (glade_xml_get_widget(sf->xml, "Add"));
- g_signal_connect((GtkWidget *) sf->add_button, "clicked", G_CALLBACK (add_clicked), sf);
-
- sf->remove = GTK_BUTTON(glade_xml_get_widget(sf->xml, "Remove"));
- g_signal_connect ((GtkWidget *) sf->remove, "clicked", G_CALLBACK (remove_clicked), sf);
- gtk_widget_set_sensitive(GTK_WIDGET (sf->remove), FALSE);
-
- sf->notification = GTK_BUTTON (glade_xml_get_widget (sf->xml, "Notification"));
- g_signal_connect((GtkWidget *) sf->notification, "clicked", G_CALLBACK (notification_clicked), sf);
-
- sf->name = GTK_ENTRY (glade_xml_get_widget (sf->xml, "entry4"));
- /*TODO:connect name and label*/
- gtk_widget_hide (GTK_WIDGET(sf->name));
- box = GTK_WIDGET (glade_xml_get_widget (sf->xml, "hbox227"));
- gtk_box_pack_start (GTK_BOX (box), (GtkWidget *) name_selector_entry, TRUE, TRUE, 0);
- gtk_widget_show ((GtkWidget *) name_selector_entry);
-
- sf->scrolled_window = GTK_WIDGET (glade_xml_get_widget (sf->xml,"scrolledwindow4"));
-
- gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sf->scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
-
- sf->model = gtk_list_store_new (4, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN);
- sf->user_list = gtk_tree_view_new ();
- gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (sf->scrolled_window), (GtkWidget *)sf->user_list);
- gtk_tree_view_set_model (GTK_TREE_VIEW (sf->user_list), GTK_TREE_MODEL (sf->model));
- gtk_widget_show (GTK_WIDGET (sf->user_list));
-
- sf->cell = gtk_cell_renderer_text_new ();
- sf->column = gtk_tree_view_column_new_with_attributes ("Users", sf->cell, "text", 0, NULL);
- gtk_tree_view_append_column (GTK_TREE_VIEW (sf->user_list),
- GTK_TREE_VIEW_COLUMN (sf->column));
-
- sf->cell = gtk_cell_renderer_toggle_new ();
- sf->column = gtk_tree_view_column_new_with_attributes ("Add ", sf->cell, "active" , 1, NULL);
- gtk_tree_view_append_column (GTK_TREE_VIEW (sf->user_list),
- GTK_TREE_VIEW_COLUMN (sf->column));
- g_signal_connect (sf->cell, "toggled", G_CALLBACK (add_right_clicked), sf);
-
- sf->cell = gtk_cell_renderer_toggle_new ();
- sf->column = gtk_tree_view_column_new_with_attributes ("Modify", sf->cell, "active", 2, NULL);
- gtk_tree_view_append_column (GTK_TREE_VIEW (sf->user_list),
- GTK_TREE_VIEW_COLUMN (sf->column));
- g_signal_connect (sf->cell, "toggled", G_CALLBACK (edit_right_clicked), sf);
-
- sf->cell = gtk_cell_renderer_toggle_new ();
- sf->column = gtk_tree_view_column_new_with_attributes ("Delete", sf->cell, "active", 3, NULL);
- gtk_tree_view_append_column (GTK_TREE_VIEW (sf->user_list),
- GTK_TREE_VIEW_COLUMN (sf->column));
- g_signal_connect (sf->cell, "toggled", G_CALLBACK (delete_right_clicked), sf);
-
- g_signal_connect(gtk_tree_view_get_selection(GTK_TREE_VIEW (sf->user_list)), "changed", G_CALLBACK (user_selected), sf);
-}
-
-ShareFolder *
-share_folder_new (EGwConnection *ccnc, gchar *id)
-{
- ShareFolder *new;
- new = (ShareFolder *) g_object_new (share_folder_get_type (), NULL);
- share_folder_construct (new);
- new->cnc = ccnc;
- new->container_id = id;
- if (ccnc && id)
- get_container_list(new);
-
- return (ShareFolder *) new;
-}
-
-
diff --git a/plugins/shared-folder/share-folder.h b/plugins/shared-folder/share-folder.h
deleted file mode 100644
index ac34ada29c..0000000000
--- a/plugins/shared-folder/share-folder.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * Authors: Vivek Jain <jvivek@novell.com>
- *
- * Copyright 2002-2003 Ximian, Inc. (www.ximian.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
- *
- */
-
-#ifndef __SHARE_FOLDER_H__
-#define __SHARE_FOLDER_H__
-
-#ifdef __cplusplus
-extern "C" {
-#pragma }
-#endif /* __cplusplus */
-
-#include <glib.h>
-#include <gtk/gtkvbox.h>
-#include <gtk/gtk.h>
-#include <camel/camel-store.h>
-#include <e-gw-connection.h>
-#include <libedataserverui/e-name-selector.h>
-
-#define _SHARE_FOLDER_TYPE (share_folder_get_type ())
-#define SHARE_FOLDER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SHARE_FOLDER, ShareFolder))
-#define SHARE_FOLDER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), SHARE_FOLDER_TYPE, ShareFolder))
-#define IS_SHARE_FOLDER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SHARE_FOLDER_TYPE))
-#define IS_SHARE_FOLDER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), SHARE_FOLDER_TYPE))
-
-typedef struct _ShareFolder ShareFolder;
-typedef struct _ShareFolderClass ShareFolderClass;
-
-struct _GtkWidget;
-struct _GladeXML;
-struct _GtkButton;
-struct _GtkTreeView;
-struct _GtkLabel;
-struct _GtkEntry;
-struct _GtkWindow;
-struct _GtkRadioButton;
-struct _GtkListStore;
-struct _GtkCellRenderer;
-struct _GtkTreeViewColumn;
-struct _GtkFrame;
-struct _GtkVBox;
-
-struct _ShareFolder {
- GtkVBox parent_object;
-
- struct _GladeXML *xml;
-
- /* General tab */
-
- /* Default Behavior */
- struct _GtkTreeView *user_list;
- struct _GtkTextView *message;
- struct _GtkButton *add_button;
- struct _GtkButton *remove;
- struct _GtkButton *add_book;
- struct _GtkButton *notification;
- struct _GtkEntry *name;
- struct _GtkEntry *subject;
- struct _GtkRadioButton *shared;
- struct _GtkRadioButton *not_shared;
- struct _GtkWidget *scrolled_window;
- struct _GtkListStore *model;
- struct _GtkCellRenderer *cell;
- struct _GtkTreeViewColumn *column;
- struct _GtkVBox *vbox;
- struct _GtkVBox *table;
- struct _GtkWidget *window;
-
- GList *users_list;
- EGwContainer *gcontainer;
- gint users;
- gboolean byme;
- gboolean tome;
- gint flag_for_ok;
- gchar *email;
- gboolean is_shared;
- EGwConnection *cnc;
- gchar *container_id;
- gchar *sub;
- gchar *mesg;
- GList *container_list;
- GtkTreeIter iter;
- ENameSelector *name_selector;
-
-};
-
-struct _ShareFolderClass {
- GtkVBoxClass parent_class;
-
-};
-
-GType share_folderget_type (void);
-struct _ShareFolder * share_folder_new (EGwConnection *ccnc, gchar *id);
-void share_folder(struct _ShareFolder *sf);
-gchar * get_container_id (EGwConnection *cnc, gchar *fname);
-EGwConnection * get_cnc (CamelStore *store);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* __EM_COMPOSER_PREFS_H__ */
diff --git a/plugins/subject-thread/.cvsignore b/plugins/subject-thread/.cvsignore
deleted file mode 100644
index 683d5ddbe2..0000000000
--- a/plugins/subject-thread/.cvsignore
+++ /dev/null
@@ -1,5 +0,0 @@
-.deps
-.libs
-Makefile
-Makefile.in
-*.eplug \ No newline at end of file
diff --git a/plugins/subject-thread/ChangeLog b/plugins/subject-thread/ChangeLog
deleted file mode 100644
index 312559fc23..0000000000
--- a/plugins/subject-thread/ChangeLog
+++ /dev/null
@@ -1,22 +0,0 @@
-2005-02-07 JP Rosevear <jpr@novell.com>
-
- * org-gnome-subject-thread.eplug.in: specify id
-
-2004-11-01 JP Rosevear <jpr@novell.com>
-
- * Makefile.am: dist .eplug.in file
-
-2004-10-20 Not Zed <NotZed@Ximian.com>
-
- * Makefile.am (INCLUDES): removed camel from include path,
- everything should include camel/foo.
-
-2004-10-20 JP Rosevear <jpr@novell.com>
-
- * subject-thread.c: implement
-
- * org-gnome-subject-thread.eplug.in: define the
- subject-thread plugin
-
- * Makefile.am: build the subject thread plugin
-
diff --git a/plugins/subject-thread/Makefile.am b/plugins/subject-thread/Makefile.am
deleted file mode 100644
index 2e692b41dc..0000000000
--- a/plugins/subject-thread/Makefile.am
+++ /dev/null
@@ -1,13 +0,0 @@
-INCLUDES = \
- -I$(top_srcdir) \
- $(EVOLUTION_MAIL_CFLAGS)
-
-@EVO_PLUGIN_RULE@
-
-plugin_DATA = org-gnome-subject-thread.eplug
-plugin_LTLIBRARIES = liborg-gnome-subject-thread.la
-
-liborg_gnome_subject_thread_la_SOURCES = subject-thread.c
-liborg_gnome_subject_thread_la_LDFLAGS = -module -avoid-version
-
-EXTRA_DIST = org-gnome-subject-thread.eplug.in \ No newline at end of file
diff --git a/plugins/subject-thread/org-gnome-subject-thread.eplug.in b/plugins/subject-thread/org-gnome-subject-thread.eplug.in
deleted file mode 100644
index 984d154a0f..0000000000
--- a/plugins/subject-thread/org-gnome-subject-thread.eplug.in
+++ /dev/null
@@ -1,11 +0,0 @@
-<e-plugin-list>
- <e-plugin id="org.gnome.evolution.mail_subject_thread" type="shlib" name="Subject Threading" description="Indicates if threading of messages should fall back to subject"
- location="@PLUGINDIR@/liborg-gnome-subject-thread.so">
-
- <hook class="org.gnome.evolution.mail.config:1.0">
- <group id="org.gnome.evolution.mail.prefs" target="prefs">
- <item type="item" path="00.general/10.display/80.subject_thread" label="Thread messages by subject" factory="org_gnome_subject_thread_factory"/>
- </group>
- </hook>
- </e-plugin>
-</e-plugin-list> \ No newline at end of file
diff --git a/plugins/subject-thread/subject-thread.c b/plugins/subject-thread/subject-thread.c
deleted file mode 100644
index 870ba02f5b..0000000000
--- a/plugins/subject-thread/subject-thread.c
+++ /dev/null
@@ -1,67 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * Authors: JP Rosevear <jpr@novell.com>
- *
- * Copyright 2004 Novell, Inc.
- *
- * 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., 59 Temple Street #330, Boston, MA 02111-1307, USA.
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <string.h>
-#include <glib.h>
-#include <gtk/gtk.h>
-#include <libgnome/gnome-i18n.h>
-#include <gconf/gconf-client.h>
-#include <e-util/e-config.h>
-#include <mail/em-config.h>
-
-#define GCONF_KEY "/apps/evolution/mail/display/thread_subject"
-
-GtkWidget *org_gnome_subject_thread_factory (EPlugin *ep, EConfigHookItemFactoryData *hook_data);
-
-static void
-toggled_cb (GtkWidget *widget, EConfig *config)
-{
- EMConfigTargetPrefs *target = (EMConfigTargetPrefs *) config->target;
-
- /* Save the new setting to gconf */
- gconf_client_set_bool (target->gconf, GCONF_KEY, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)), NULL);
-}
-
-GtkWidget *
-org_gnome_subject_thread_factory (EPlugin *ep, EConfigHookItemFactoryData *hook_data)
-{
- GtkWidget *check;
- EMConfigTargetPrefs *target = (EMConfigTargetPrefs *) hook_data->config->target;
-
- /* Create the checkbox we will display, complete with mnemonic that is unique in the dialog */
- check = gtk_check_button_new_with_mnemonic (_("Fall back to threading messages by sub_ject"));
-
- /* Set the toggle button to the current gconf setting */
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), gconf_client_get_bool (target->gconf, GCONF_KEY, NULL));
-
- /* Listen for the item being toggled on and off */
- g_signal_connect (GTK_TOGGLE_BUTTON (check), "toggled", G_CALLBACK (toggled_cb), hook_data->config);
-
- /* Pack the checkbox in the parent widget and show it */
- gtk_box_pack_start (GTK_BOX (hook_data->parent), check, FALSE, FALSE, 0);
- gtk_widget_show (check);
-
- return check;
-}
diff --git a/shell/ChangeLog b/shell/ChangeLog
index ba2880aeca..6130f811bc 100644
--- a/shell/ChangeLog
+++ b/shell/ChangeLog
@@ -1,166 +1,3 @@
-2005-02-10 JP Rosevear <jpr@novell.com>
-
- * e-component-registry.c (query_components): unref the menu icon
- if it exists to fix a leak
-
-2005-02-07 JP Rosevear <jpr@novell.com>
-
- * apps_evolution_shell.schemas.in.in: clean up descriptions
-
-2005-02-01 JP Rosevear <jpr@novell.com>
-
- * e-shell-window-commands.c: add to about box
-
-2005-01-28 JP Rosevear <jpr@novell.com>
-
- * e-component-registry.c: Remove e-shell-utils.c include
-
-2005-01-21 JP Rosevear <jpr@novell.com>
-
- * apps_evolution_shell.schemas.in.in: close long tag
-
-2005-01-21 JP Rosevear <jpr@novell.com>
-
- * apps_evolution_shell.schemas.in.in: add print_config schema item
-
-2005-01-21 JP Rosevear <jpr@novell.com>
-
- * e-shell-offline-handler.c
- (impl_OfflineProgressListener_updateProgress): mark priv->finished
- as true first so we don't access freed memory if we get finalized
- during the signal emmission
- (cancel_offline): ditto
- (finalize_offline): ditto
- (e_shell_offline_handler_put_components_offline): ditto
-
-2005-01-20 Mengjie Yu <meng-jie.yu@sun.com>
-
- * e-shell-importer.c: (import_druid_esc),
- (e_shell_importer_start_import):
- Close import wizard on 'ESC'
-
-2005-01-09 JP Rosevear <jpr@novell.com>
-
- * e-shell.c (impl_Shell_handleURI): open a new window if we get a
- component id type url
-
- * Evolution-Shell.idl: add ComponentNotFound exception
-
-2005-01-06 JP Rosevear <jpr@novell.com>
-
- * Makefile.am: install schemas properly and add some uninstall
- rules for local install rules
-
-2005-01-04 JP Rosevear <jpr@novell.com>
-
- * e-sidebar.h: new protos, modes
-
- * e-sidebar.c: handle 2 more modes, text only and toolbar style;
- allow visibility to be set for the buttons
-
- * e-shell-window.h: new proto
-
- * e-shell-window.c (setup_widgets): set the sidebar setting and
- visibility based on stored gconf settings
- (e_shell_window_save_defaults): save the current sidebar setting
- visibility
- (e_shell_window_peek_sidebar): return the sidebar
-
- * e-shell-window-commands.c (e_shell_window_commands_setup): add
- listeners for each of the component button radio items and for the
- hide toggle
- (view_buttons_icontext_item_toggled_handler): listener callback,
- set mode
- (view_buttons_icon_item_toggled_handler): ditto
- (view_buttons_text_item_toggled_handler): ditto
- (view_buttons_toolbar_item_toggled_handler): ditto
- (view_buttons_hide_item_toggled_handler): listener callback, set
- visibility
-
- * apps_evolution_shell.schemas.in.in: add component button style
- and visibility defaults
-
-2004-12-29 Rodrigo Moya <rodrigo@novell.com>
-
- * main.c (show_development_warning): 2.0 is the current stable
- version.
-
-2004-12-23 Sivaiah Nallaagatla <snallagatla@novell.com>
-
- * e-shell.c (e_shell_go_offline)
- (e_shell_go_online) : set start_offline gconf key
- when ever offline state is changed.
-
-2004-12-21 JP Rosevear <jpr@novell.com>
-
- * e-corba-config-page.c: Convert to G_DEFINE_TYPE
-
- * e-history.c: ditto
-
- * e-shell-folder-title-bar.c: ditto
-
- * e-shell-offline-handler.c: ditto
-
- * e-shell-settings-dialog.c: ditto
-
- * e-shell-window.c: ditto
-
- * e-sidebar.c: ditto
-
- * e-user-creatable-items-handler.c: ditto
-
- * e-component-registry.c: ditto
-
- * importer/evolution-importer-client.c: ditto
-
-2004-12-09 Rodney Dawes <dobey@novell.com>
-
- * e-shell-window-commands.c: Use stock_new-window for the New Window
- menu item in the File menu
-
-2004-12-08 David Mosberger <davidm@napali.hpl.hp.com>
-
- * main.c: include es-event.h to fix 64 bit platform problems.
-
-2004-11-22 Joan Sanfeliu <joan@fibranet.com>
-
- * main.c: Evolution product name spelled with an uppercase E
-
- Fixes #61605
-
-2004-11-02 mengjie yu <meng-jie.yu@sun.com>
-
- * evolution-startup-wizard.glade:remove the hard line breaks.
-
-2004-10-25 Not Zed <NotZed@Ximian.com>
-
- * main.c (main): register event hook.
-
- * e-shell.c (offline_procedure_finished_cb, e_shell_go_online):
- emit new state changed event.
-
- * main.c (main): register the menu hook.
- (): only define DEVELOPMENT if not already.
-
- * e-shell-window.c (init): setup menu manager.
- (e_shell_window_new): activate menu manager.
- (update_offline_toggle_status): update the menu manager when the
- offline state changes (currently only state which requires it)
-
- * es-menu.[ch]: Shell plugin menu manager.
-
-2004-10-07 Not Zed <NotZed@Ximian.com>
-
- * main.c (main): initialise plugin system.
- (main): add --disable-eplugin and --disable-mono arguments.
-
-2004-09-30 Kjartan Maraas <kmaraas@gnome.org>
-
- * e-shell-importer.c: (import_cb): use g_timeout_add().
- * importer/intelligent.c: (select_row_cb), (unselect_row_cb),
- (create_gui): use gtk_notebook_set_current_page() instead of
- deprecated gtk_notebook_set_page()
-
2004-09-24 Not Zed <NotZed@Ximian.com>
* e-shell-window-commands.c: Added ed catmur to the credits.
@@ -177,6 +14,10 @@
* e-shell-window-commands.c (about_box_new): don't show
"translator-credits" if not translated
+2004-09-13 JP Rosevear <jpr@novell.com>
+
+ * main.c: turn off development mode
+
2004-09-07 JP Rosevear <jpr@novell.com>
Fixes #17338
@@ -185,6 +26,14 @@
translator credits, update authors lists (not strictly authors,
but we have a lot of helpful people)
+2004-09-03 Not Zed <NotZed@Ximian.com>
+
+ ** See bug #61285.
+
+ * e-shell-settings-dialog.c (load_pages): use a better query to
+ get the configuration pages, the old one didn't include version
+ information properly.
+
2004-09-13 Sivaiah Nallagatla <snallagatla@novell.com>
* e-shell.c (offline_procedure_finished_cb)
@@ -281,10 +130,6 @@
* e-shell-errors.xml.h: Add this back to CVS for translators
* .cvsignore: Don't ignore e-shell-errors.xml.h
-2004-09-07 Not Zed <NotZed@Ximian.com>
-
- * e-shell.c (e_shell_construct): disable the startup wizard.
-
2004-06-24 Not Zed <NotZed@Ximian.com>
** See bug #57367.
diff --git a/shell/e-shell-settings-dialog.c b/shell/e-shell-settings-dialog.c
index 0b96b2cf63..42063ccea4 100644
--- a/shell/e-shell-settings-dialog.c
+++ b/shell/e-shell-settings-dialog.c
@@ -30,6 +30,8 @@
#include "e-corba-config-page.h"
#include <e-util/e-icon-factory.h>
+#include <gal/util/e-util.h>
+
#include <bonobo/bonobo-widget.h>
#include <bonobo/bonobo-exception.h>
@@ -37,12 +39,16 @@
#include <string.h>
+
+#define PARENT_TYPE e_multi_config_dialog_get_type ()
+static EMultiConfigDialogClass *parent_class = NULL;
+
+
+
struct _EShellSettingsDialogPrivate {
GHashTable *types;
};
-G_DEFINE_TYPE (EShellSettingsDialog, e_shell_settings_dialog, E_TYPE_MULTI_CONFIG_DIALOG)
-
/* FIXME ugly hack to work around that sizing of invisible widgets is broken
with Bonobo. */
@@ -289,21 +295,23 @@ impl_finalize (GObject *object)
g_free (priv);
- (* G_OBJECT_CLASS (e_shell_settings_dialog_parent_class)->finalize) (object);
+ (* G_OBJECT_CLASS (parent_class)->finalize) (object);
}
static void
-e_shell_settings_dialog_class_init (EShellSettingsDialogClass *klass)
+class_init (EShellSettingsDialog *class)
{
GObjectClass *object_class;
- object_class = G_OBJECT_CLASS (klass);
+ object_class = G_OBJECT_CLASS (class);
object_class->finalize = impl_finalize;
+
+ parent_class = g_type_class_ref(PARENT_TYPE);
}
static void
-e_shell_settings_dialog_init (EShellSettingsDialog *dialog)
+init (EShellSettingsDialog *dialog)
{
EShellSettingsDialogPrivate *priv;
@@ -359,4 +367,7 @@ e_shell_settings_dialog_show_type (EShellSettingsDialog *dialog, const char *typ
e_multi_config_dialog_show_page (E_MULTI_CONFIG_DIALOG (dialog), page);
}
+
+E_MAKE_TYPE (e_shell_settings_dialog, "EShellSettingsDialog", EShellSettingsDialog,
+ class_init, init, PARENT_TYPE)
diff --git a/shell/e-shell-window-commands.c b/shell/e-shell-window-commands.c
index c6a7ded294..05f95a63d4 100644
--- a/shell/e-shell-window-commands.c
+++ b/shell/e-shell-window-commands.c
@@ -293,7 +293,6 @@ static const char *authors[] = {
"Marius Vollmer",
"Mark Crichton",
"Mark Gordon",
- "Mark Moulder",
"Martha Burke",
"Martin Baulig",
"Martin Hicks",
@@ -645,7 +644,6 @@ static BonoboUIVerb help_verbs [] = {
static EPixmap pixmaps [] = {
E_PIXMAP ("/commands/SendReceive", "stock_mail-send-receive", E_ICON_SIZE_MENU),
E_PIXMAP ("/Toolbar/SendReceive", "stock_mail-send-receive", E_ICON_SIZE_LARGE_TOOLBAR),
- E_PIXMAP ("/menu/File/OpenNewWindow", "stock_new-window", E_ICON_SIZE_MENU),
E_PIXMAP ("/menu/File/FileImporter", "stock_mail-import", E_ICON_SIZE_MENU),
E_PIXMAP ("/menu/File/ToggleOffline", "stock_disconnect", E_ICON_SIZE_MENU),
E_PIXMAP ("/menu/Tools/Settings", "gnome-settings", E_ICON_SIZE_MENU),
@@ -728,75 +726,6 @@ shell_line_status_changed_cb (EShell *shell,
}
static void
-view_buttons_icontext_item_toggled_handler (BonoboUIComponent *ui_component,
- const char *path,
- Bonobo_UIComponent_EventType type,
- const char *state,
- EShellWindow *shell_window)
-{
- ESidebar *sidebar;
-
- sidebar = e_shell_window_peek_sidebar (shell_window);
- e_sidebar_set_mode (sidebar, E_SIDEBAR_MODE_BOTH);
-}
-
-static void
-view_buttons_icon_item_toggled_handler (BonoboUIComponent *ui_component,
- const char *path,
- Bonobo_UIComponent_EventType type,
- const char *state,
- EShellWindow *shell_window)
-{
- ESidebar *sidebar;
-
- sidebar = e_shell_window_peek_sidebar (shell_window);
- e_sidebar_set_mode (sidebar, E_SIDEBAR_MODE_ICON);
-}
-
-static void
-view_buttons_text_item_toggled_handler (BonoboUIComponent *ui_component,
- const char *path,
- Bonobo_UIComponent_EventType type,
- const char *state,
- EShellWindow *shell_window)
-{
- ESidebar *sidebar;
-
- sidebar = e_shell_window_peek_sidebar (shell_window);
- e_sidebar_set_mode (sidebar, E_SIDEBAR_MODE_TEXT);
-}
-
-static void
-view_buttons_toolbar_item_toggled_handler (BonoboUIComponent *ui_component,
- const char *path,
- Bonobo_UIComponent_EventType type,
- const char *state,
- EShellWindow *shell_window)
-{
- ESidebar *sidebar;
-
- sidebar = e_shell_window_peek_sidebar (shell_window);
- e_sidebar_set_mode (sidebar, E_SIDEBAR_MODE_TOOLBAR);
-}
-
-static void
-view_buttons_hide_item_toggled_handler (BonoboUIComponent *ui_component,
- const char *path,
- Bonobo_UIComponent_EventType type,
- const char *state,
- EShellWindow *shell_window)
-{
- ESidebar *sidebar;
- gboolean is_visible;
-
- sidebar = e_shell_window_peek_sidebar (shell_window);
-
- is_visible = state[0] == '0';
-
- e_sidebar_set_show_buttons (sidebar, is_visible);
-}
-
-static void
view_toolbar_item_toggled_handler (BonoboUIComponent *ui_component,
const char *path,
Bonobo_UIComponent_EventType type,
@@ -831,21 +760,6 @@ e_shell_window_commands_setup (EShellWindow *shell_window)
bonobo_ui_component_add_verb_list_with_data (uic, actions_verbs, shell_window);
bonobo_ui_component_add_verb_list_with_data (uic, tools_verbs, shell_window);
bonobo_ui_component_add_verb_list_with_data (uic, help_verbs, shell_window);
- bonobo_ui_component_add_listener (uic, "ViewButtonsIconText",
- (BonoboUIListenerFn)view_buttons_icontext_item_toggled_handler,
- (gpointer)shell_window);
- bonobo_ui_component_add_listener (uic, "ViewButtonsIcon",
- (BonoboUIListenerFn)view_buttons_icon_item_toggled_handler,
- (gpointer)shell_window);
- bonobo_ui_component_add_listener (uic, "ViewButtonsText",
- (BonoboUIListenerFn)view_buttons_text_item_toggled_handler,
- (gpointer)shell_window);
- bonobo_ui_component_add_listener (uic, "ViewButtonsToolbar",
- (BonoboUIListenerFn)view_buttons_toolbar_item_toggled_handler,
- (gpointer)shell_window);
- bonobo_ui_component_add_listener (uic, "ViewButtonsHide",
- (BonoboUIListenerFn)view_buttons_hide_item_toggled_handler,
- (gpointer)shell_window);
bonobo_ui_component_add_listener (uic, "ViewToolbar",
(BonoboUIListenerFn)view_toolbar_item_toggled_handler,
(gpointer)shell_window);
diff --git a/shell/e-shell.c b/shell/e-shell.c
index 0b77ebcf9f..0e43ee3fd7 100644
--- a/shell/e-shell.c
+++ b/shell/e-shell.c
@@ -41,7 +41,6 @@
#include "e-shell-startup-wizard.h"
#include "e-shell-marshal.h"
-#include "es-event.h"
#include "evolution-shell-component-utils.h"
@@ -255,7 +254,7 @@ impl_Shell_handleURI (PortableServer_Servant servant,
if (p)
*p = 0;
- component_info = e_component_registry_peek_info(shell->priv->component_registry, ECR_FIELD_SCHEMA, schema);
+ component_info = e_component_registry_peek_info(shell->priv->component_registry, ECR_FIELD_SCHEMA, schema);
if (component_info == NULL) {
show = TRUE;
component_info = e_component_registry_peek_info(shell->priv->component_registry, ECR_FIELD_ALIAS, schema);
@@ -266,16 +265,9 @@ impl_Shell_handleURI (PortableServer_Servant servant,
return;
}
- if (show) {
- GtkWidget *shell_window;
-
- shell_window = e_shell_create_window (shell, component_info->id, NULL);
- if (shell_window == NULL) {
- CORBA_exception_set (ev, CORBA_USER_EXCEPTION, ex_GNOME_Evolution_Shell_ComponentNotFound, NULL);
- return;
- }
- }
-
+ if (show && shell->priv->windows)
+ e_shell_window_switch_to_component((EShellWindow *)shell->priv->windows->data, component_info->id);
+
GNOME_Evolution_Component_handleURI (component_info->iface, uri, ev);
/* not an error not to implement it */
if (ev->_id != NULL && strcmp(ev->_id, ex_CORBA_NO_IMPLEMENT) == 0)
@@ -651,12 +643,10 @@ e_shell_construct (EShell *shell,
e_shell_attempt_upgrade(shell);
-#if 0
if (e_shell_startup_wizard_create () == FALSE) {
bonobo_object_unref (BONOBO_OBJECT (shell));
exit (0);
}
-#endif
priv->is_initialized = TRUE;
@@ -1065,7 +1055,6 @@ offline_procedure_finished_cb (EShellOfflineHandler *offline_handler,
{
EShell *shell;
EShellPrivate *priv;
- ESEvent *ese;
shell = E_SHELL (data);
priv = shell->priv;
@@ -1080,17 +1069,6 @@ offline_procedure_finished_cb (EShellOfflineHandler *offline_handler,
priv->offline_handler = NULL;
g_signal_emit (shell, signals[LINE_STATUS_CHANGED], 0, priv->line_status);
-
- /** @Event: Shell online state changed
- * @Id: state.changed
- * @Target: ESMenuTargetState
- *
- * This event is emitted whenever the shell online state changes.
- *
- * Only the online and offline states are emitted.
- */
- ese = es_event_peek();
- e_event_emit((EEvent *)ese, "state.changed", (EEventTarget *)es_event_target_new_state(ese, TRUE));
}
/**
@@ -1105,8 +1083,7 @@ e_shell_go_offline (EShell *shell,
EShellWindow *action_window)
{
EShellPrivate *priv;
- GConfClient *client;
-
+
g_return_if_fail (shell != NULL);
g_return_if_fail (E_IS_SHELL (shell));
g_return_if_fail (action_window != NULL);
@@ -1116,9 +1093,7 @@ e_shell_go_offline (EShell *shell,
if (priv->line_status != E_SHELL_LINE_STATUS_ONLINE)
return;
- client = gconf_client_get_default ();
- gconf_client_set_bool (client, "/apps/evolution/shell/start_offline", TRUE, NULL);
- g_object_unref (client);
+
priv->offline_handler = e_shell_offline_handler_new (shell);
g_signal_connect (priv->offline_handler, "offline_procedure_started",
@@ -1143,8 +1118,7 @@ e_shell_go_online (EShell *shell,
EShellPrivate *priv;
GSList *component_infos;
GSList *p;
- ESEvent *ese;
- GConfClient *client;
+
g_return_if_fail (shell != NULL);
g_return_if_fail (E_IS_SHELL (shell));
g_return_if_fail (action_window == NULL || E_IS_SHELL_WINDOW (action_window));
@@ -1177,11 +1151,6 @@ e_shell_go_online (EShell *shell,
priv->line_status = E_SHELL_LINE_STATUS_ONLINE;
e_passwords_set_online (TRUE);
g_signal_emit (shell, signals[LINE_STATUS_CHANGED], 0, priv->line_status);
- client = gconf_client_get_default ();
- gconf_client_set_bool (client, "/apps/evolution/shell/start_offline", FALSE, NULL);
- g_object_unref (client);
- ese = es_event_peek();
- e_event_emit((EEvent *)ese, "state.changed", (EEventTarget *)es_event_target_new_state(ese, TRUE));
}
diff --git a/shell/main.c b/shell/main.c
index 43ccb41d6c..e31afd75a2 100644
--- a/shell/main.c
+++ b/shell/main.c
@@ -33,8 +33,6 @@
#include "e-shell-constants.h"
#include "e-shell.h"
-#include "es-menu.h"
-#include "es-event.h"
#include <libxml/xmlmemory.h>
#include <libxml/parser.h>
@@ -83,14 +81,9 @@
#include <pthread.h>
-#include "e-util/e-plugin.h"
-#ifdef ENABLE_MONO
-#include "e-util/e-plugin-mono.h"
-#endif
-#ifndef DEVELOPMENT
-#define DEVELOPMENT (1)
-#endif
+/* #define DEVELOPMENT */
+
static EShell *shell = NULL;
@@ -102,10 +95,6 @@ static gboolean killev = FALSE;
#ifdef DEVELOPMENT
static gboolean force_migrate = FALSE;
#endif
-#ifdef ENABLE_MONO
-static gboolean disable_mono = FALSE;
-#endif
-static gboolean disable_eplugin = FALSE;
static gint idle_cb (void *data);
@@ -249,7 +238,7 @@ show_development_warning(void)
"\n"
"We hope that you enjoy the results of our hard work, and we\n"
"eagerly await your contributions!\n"),
- "2.0");
+ "1.4");
label = gtk_label_new (text);
g_free(text);
@@ -477,7 +466,7 @@ main (int argc, char **argv)
N_("Start in online mode"), NULL },
#ifdef KILL_PROCESS_CMD
{ "force-shutdown", '\0', POPT_ARG_NONE, &killev, 0,
- N_("Forcibly shut down all Evolution components"), NULL },
+ N_("Forcibly shut down all evolution components"), NULL },
#endif
#ifdef DEVELOPMENT
{ "force-migrate", '\0', POPT_ARG_NONE, &force_migrate, 0,
@@ -485,12 +474,6 @@ main (int argc, char **argv)
#endif
{ "debug", '\0', POPT_ARG_STRING, &evolution_debug_log, 0,
N_("Send the debugging output of all components to a file."), NULL },
-#ifdef ENABLE_MONO
- { "disable-mono", '\0', POPT_ARG_NONE, &disable_mono, 0,
- N_("Disable the mono plugin environment."), NULL },
-#endif
- { "disable-eplugin", '\0', POPT_ARG_NONE, &disable_eplugin, 0,
- N_("Disable loading of any plugins."), NULL },
{ "setup-only", '\0', POPT_ARG_NONE | POPT_ARGFLAG_DOC_HIDDEN,
&setup_only, 0, NULL, NULL },
{ NULL, '\0', 0, NULL, 0, NULL, NULL }
@@ -588,17 +571,6 @@ main (int argc, char **argv)
gnome_sound_init ("localhost");
- if (!disable_eplugin) {
-#ifdef ENABLE_MONO
- if (!disable_mono && getenv("EVOLUTION_DISABLE_MONO") == NULL)
- e_plugin_register_type(e_plugin_mono_get_type());
-#endif
- e_plugin_register_type(e_plugin_lib_get_type());
- e_plugin_hook_register_type(es_menu_hook_get_type());
- e_plugin_hook_register_type(es_event_hook_get_type());
- e_plugin_load_plugins();
- }
-
#ifdef DEVELOPMENT
client = gconf_client_get_default ();
skip_warning_dialog = gconf_client_get_bool (client, "/apps/evolution/shell/skip_warning_dialog", NULL);
diff --git a/smime/ChangeLog b/smime/ChangeLog
index 81d89d061f..5f4da8afdf 100644
--- a/smime/ChangeLog
+++ b/smime/ChangeLog
@@ -1,15 +1,3 @@
-2005-02-09 Hans Petter Jansson <hpj@novell.com>
-
- * lib/Makefile.am:
- * gui/Makefile.am: Install shared libraries to privlibdir.
-
-2005-02-04 Rodney Dawes <dobey@novell.com>
-
- * gui/ca-trust-dialog.c (ca_trust_dialog_new): Set the border widths
- for the dialog internal container widgets to be HIG compliant
-
- * gui/smime-ui.glade: Set the vbox spacing to 12 for HIG compliance
-
2004-11-23 Not Zed <NotZed@Ximian.com>
* gui/certificate-manager.c (delete_ca): don't remove the tree
@@ -17,10 +5,6 @@
(delete_your): same.
(delete_contact): same. Hoorah for code-reuse.
-2004-10-13 JP Rosevear <jpr@novell.com>
-
- * gui/e-cert-selector.c: update to use G_DEFINE_TYPE
-
2004-10-11 Not Zed <NotZed@Ximian.com>
* gui/e-cert-selector.c (e_cert_selector_new): dont try to
diff --git a/smime/gui/e-cert-selector.c b/smime/gui/e-cert-selector.c
index ac4c6e8785..881c4da76a 100644
--- a/smime/gui/e-cert-selector.c
+++ b/smime/gui/e-cert-selector.c
@@ -25,6 +25,8 @@
#include <libgnome/gnome-i18n.h>
+#include <gal/util/e-util.h>
+
#include <gtk/gtktextview.h>
#include <gtk/gtkoptionmenu.h>
#include <gtk/gtkmenuitem.h>
@@ -53,7 +55,7 @@ enum {
static guint ecs_signals[ECS_LAST_SIGNAL];
-G_DEFINE_TYPE (ECertSelector, e_cert_selector, GTK_TYPE_DIALOG)
+static GtkDialog *ecs_parent_class;
/* (this is what mozilla shows)
Issued to:
@@ -88,7 +90,7 @@ ecs_find_current(ECertSelector *ecs)
}
static void
-e_cert_selector_response(GtkDialog *dialog, gint button)
+ecs_response(GtkDialog *dialog, gint button)
{
CERTCertListNode *node;
@@ -213,7 +215,7 @@ e_cert_selector_new(int type, const char *currentid)
}
static void
-e_cert_selector_init(ECertSelector *ecs)
+ecs_init(ECertSelector *ecs)
{
gtk_dialog_add_buttons((GtkDialog *)ecs,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
@@ -223,7 +225,7 @@ e_cert_selector_init(ECertSelector *ecs)
}
static void
-e_cert_selector_finalise(GObject *o)
+ecs_finalise(GObject *o)
{
ECertSelector *ecs = (ECertSelector *)o;
@@ -232,14 +234,16 @@ e_cert_selector_finalise(GObject *o)
g_free(ecs->priv);
- ((GObjectClass *)e_cert_selector_parent_class)->finalize(o);
+ ((GObjectClass *)ecs_parent_class)->finalize(o);
}
static void
-e_cert_selector_class_init(ECertSelectorClass *klass)
+ecs_class_init(ECertSelectorClass *klass)
{
- ((GObjectClass *)klass)->finalize = e_cert_selector_finalise;
- ((GtkDialogClass *)klass)->response = e_cert_selector_response;
+ ecs_parent_class = g_type_class_ref(gtk_dialog_get_type());
+
+ ((GObjectClass *)klass)->finalize = ecs_finalise;
+ ((GtkDialogClass *)klass)->response = ecs_response;
ecs_signals[ECS_SELECTED] =
g_signal_new("selected",
@@ -250,3 +254,5 @@ e_cert_selector_class_init(ECertSelectorClass *klass)
g_cclosure_marshal_VOID__POINTER,
G_TYPE_NONE, 1, G_TYPE_POINTER);
}
+
+E_MAKE_TYPE(e_cert_selector, "ECertSelector", ECertSelector, ecs_class_init, ecs_init, gtk_dialog_get_type())
diff --git a/ui/evolution-addressbook.h b/ui/evolution-addressbook.h
new file mode 100644
index 0000000000..3128ccfb83
--- /dev/null
+++ b/ui/evolution-addressbook.h
@@ -0,0 +1,25 @@
+/*
+ * This file is autogenerated from evolution-addressbook.xml, do not edit
+ *
+ * This file contains translatable strings generated by
+ * bonobo-ui-extract. Add this file to your project's
+ * POTFILES.in. DO NOT compile it as part of your application.
+ */
+
+gchar *s = N_("_Print Contacts...");
+gchar *s = N_("As _Table");
+gchar *s = N_("_New Contact");
+gchar *s = N_("_Tools");
+gchar *s = N_("_Search for contacts");
+gchar *s = N_("New");
+gchar *s = N_("Create a new contact");
+gchar *s = N_("Find");
+gchar *s = N_("Find a contact");
+gchar *s = N_("Print");
+gchar *s = N_("Print contacts");
+gchar *s = N_("Delete");
+gchar *s = N_("Delete a contact");
+gchar *s = N_("View All");
+gchar *s = N_("View all contacts");
+gchar *s = N_("Stop");
+gchar *s = N_("Stop Loading");
diff --git a/ui/evolution-message-composer.h b/ui/evolution-message-composer.h
new file mode 100644
index 0000000000..bcc259c4d5
--- /dev/null
+++ b/ui/evolution-message-composer.h
@@ -0,0 +1,53 @@
+/*
+ * This file is autogenerated from evolution-message-composer.xml, do not edit
+ *
+ * This file contains translatable strings generated by
+ * bonobo-ui-extract. Add this file to your project's
+ * POTFILES.in. DO NOT compile it as part of your application.
+ */
+
+gchar *s = N_("Open");
+gchar *s = N_("Open a file");
+gchar *s = N_("Save");
+gchar *s = N_("Save the current file");
+gchar *s = N_("Save As");
+gchar *s = N_("Save the current file with a different name");
+gchar *s = N_("Close");
+gchar *s = N_("Close the current file");
+gchar *s = N_("Save in folder...");
+gchar *s = N_("Save the message in a specified folder");
+gchar *s = N_("Insert text file...");
+gchar *s = N_("Insert a file as text into the message");
+gchar *s = N_("Send");
+gchar *s = N_("Send the message now");
+gchar *s = N_("Send _later");
+gchar *s = N_("Send the message later");
+gchar *s = N_("Attach");
+gchar *s = N_("Attach a file");
+gchar *s = N_("HTML");
+gchar *s = N_("Send the mail in HTML format");
+gchar *s = N_("Show attachments");
+gchar *s = N_("Show / hide attachments");
+gchar *s = N_("_File");
+gchar *s = N_("_Open...");
+gchar *s = N_("_Save");
+gchar *s = N_("Save _As...");
+gchar *s = N_("Save in _folder... (FIXME)");
+gchar *s = N_("_Insert text file... (FIXME)");
+gchar *s = N_("Send");
+gchar *s = N_("Send _Later");
+gchar *s = N_("_Close");
+gchar *s = N_("_Edit");
+gchar *s = N_("F_ormat");
+gchar *s = N_("_View");
+gchar *s = N_("Show _attachments");
+gchar *s = N_("_Help");
+gchar *s = N_("_About...");
+gchar *s = N_("_Debug");
+gchar *s = N_("Send this message now");
+gchar *s = N_("Bold");
+gchar *s = N_("Sets something as bold");
+
+
+
+
diff --git a/widgets/ChangeLog b/widgets/ChangeLog
index e7cdc43f73..3154caedba 100644
--- a/widgets/ChangeLog
+++ b/widgets/ChangeLog
@@ -1,27 +1,3 @@
-2005-02-09 Hans Petter Jansson <hpj@novell.com>
-
- * e-timezone-dialog/Makefile.am:
- * menus/Makefile.am:
- * misc/Makefile.am: Install shared libraries to privlibdir.
-
-2005-01-18 Hao Sheng <hao.sheng@sun.com>
-
- * misc/e-dateedit.[ch]:
- (e_date_edit_get_entry): return the entry of the date edit.
-
-2004-11-12 JP Rosevear <jpr@novell.com>
-
- * menus/gal-view-menus.c: Convert to G_DEFINE_TYPE
-
-2004-11-12 JP Rosevear <jpr@novell.com>
-
- * e-timezone-dialog/e-timezone-dialog.c: convert to G_DEFINE_TYPE
-
-2004-10-28 Li Yuan <li.yuan@sun.com>
-
- * e-timezone-dialog/e-timezone-dialog.glade: Add a name for
- timezone combox.
-
2004-09-13 Rodney Dawes <dobey@novell.com>
* e-timezone-dialog/e-timezone-dialog.c (get_widgets):
@@ -39,6 +15,20 @@
Fixes #62970
+2004-06-22 Hans Petter Jansson <hpj@ximian.com>
+
+ * misc/e-source-selector.c (e_source_selector_peek_primary_selection):
+ Add preconditions. Make sure garbage or NULL data doesn't get used.
+
+2004-06-11 Larry Ewing <lewing@ximian.com>
+
+ * misc/e-source-selector.c: make the source selector use a colock
+ block instead of setting the foreground to indicate the source
+ color.
+ (pixbuf_cell_data_func): actually initialize the pixbuf (bad larry).
+ (pixbuf_cell_data_func): clean up warnings. (double bad larry).
+ (pixbuf_cell_data_func): fix the appearance a little.
+
2004-05-20 Rodney Dawes <dobey@ximian.com>
* e-timezone-dialog/e-timezone-dialog.c (e_timezone_dialog_construct):
@@ -69,6 +59,16 @@
* e-timezone-dialog/e-timezone-dialog.c
(e_timezone_dialog_dispose): don't reference uninitialized memory
+2003-12-16 Hans Petter Jansson <hpj@ximian.com>
+
+ * misc/e-source-option-menu.c (select_source_foreach_menu_item):
+ Use e_source_equal() instead of comparing pointers. This allows user
+ to pass in a source that was obtained from somewhere else. Set the
+ matching internal source as "selected" instead of the one passed in.
+ (select_source): Emit signal only if we found a match. Don't ref/unref
+ anything, since the selected source will always be from our internal
+ list.
+
2003-12-10 Not Zed <NotZed@Ximian.com>
* menus/gal-view-menus.c (remove_instance): NULL out
@@ -92,3 +92,43 @@
made to libical build.
* e-timezone-dialog.h: #include <libical/ical.h>
+
+2003-09-19 Bolian Yin <bolian.yin@sun.com>
+
+ Fixes #1245. ECalendar should be usable with the keyboard
+
+ *misc/e-calendar-item.c (e_calendar_item_focus): new func, focus
+ handler.
+ (e_calendar_item_key_press_event): new func, key press event
+ handler
+ (e_calendar_item_selection_add_days,
+ e_calendar_item_stop_selecting): helpers.
+ (e_calendar_item_ensure_days_visible,
+ e_calendar_item_set_selection_if_emission): add the flag to
+ control if we should emit e-calendar signals.
+ (e_calendar_item_class_init): register focus handler.
+ (e_calendar_item_event): add code for GDK_FOCUS_CHANGE and
+ GDK_KEY_PRESS.
+
+ *misc/e-calendar.c (e_calendar_focus): new func, focus handler
+ (e_calendar_button_has_focus): new func, if prev/next button has
+ focus.
+ (e_calendar_on_next_clicked, e_calendar_on_prev_clicked): click
+ signal handler for prev/next buttons.
+ (e_calendar_set_focusable): set if the e-calendar is focusable
+
+ *misc/e-dateedit.c (e_date_edit_show_date_popup, hide_date_popup):
+ grab/ungrab gdk keyboard.
+
+2003-08-27 Hans Petter Jansson <hpj@ximian.com>
+
+ Fixes #15638.
+
+ * misc/e-dateedit.c (rebuild_time_popup): Make 12-hour time format
+ not be zero-padded. Right-align time labels so digits line up.
+
+2003-08-27 Bolian Yin <bolian.yin@sun.com>
+
+ * misc/Makefile.am: add dependency on a11y/widgets.
+ * misc/e-calendar-item.c (e_calendar_item_class_init): a11y init.
+ (e_calendar_item_bounds): new func, impl the bounds virtual func.
diff --git a/widgets/e-timezone-dialog/e-timezone-dialog.c b/widgets/e-timezone-dialog/e-timezone-dialog.c
index 10b1930b8d..19a5685b38 100644
--- a/widgets/e-timezone-dialog/e-timezone-dialog.c
+++ b/widgets/e-timezone-dialog/e-timezone-dialog.c
@@ -20,10 +20,7 @@
* Boston, MA 02111-1307, USA.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-#endif
-
#include <gtk/gtksignal.h>
#include <gtk/gtkcombo.h>
#include <gtk/gtkentry.h>
@@ -34,6 +31,8 @@
#include "e-timezone-dialog.h"
+#include <gal/util/e-util.h>
+
#define E_TIMEZONE_DIALOG_MAP_POINT_NORMAL_RGBA 0xc070a0ff
#define E_TIMEZONE_DIALOG_MAP_POINT_HOVER_RGBA 0xffff60ff
#define E_TIMEZONE_DIALOG_MAP_POINT_SELECTED_1_RGBA 0xff60e0ff
@@ -91,7 +90,9 @@ static void set_map_timezone (ETimezoneDialog *etd,
static void on_combo_changed (GtkEditable *entry,
ETimezoneDialog *etd);
-G_DEFINE_TYPE (ETimezoneDialog, e_timezone_dialog, G_TYPE_OBJECT)
+
+static GObjectClass *parent_class;
+
/* Class initialization function for the event editor */
static void
@@ -102,6 +103,8 @@ e_timezone_dialog_class_init (ETimezoneDialogClass *class)
object_class = G_OBJECT_CLASS (class);
object_class->dispose = e_timezone_dialog_dispose;
object_class->finalize = e_timezone_dialog_finalize;
+
+ parent_class = gtk_type_class (G_TYPE_OBJECT);
}
/* Object initialization function for the event editor */
@@ -147,7 +150,7 @@ e_timezone_dialog_dispose (GObject *object)
priv->xml = NULL;
}
- (* G_OBJECT_CLASS (e_timezone_dialog_parent_class)->dispose) (object);
+ (* G_OBJECT_CLASS (parent_class)->dispose) (object);
}
/* Finalize handler for the event editor */
@@ -165,7 +168,7 @@ e_timezone_dialog_finalize (GObject *object)
g_free (priv);
- (* G_OBJECT_CLASS (e_timezone_dialog_parent_class)->finalize) (object);
+ (* G_OBJECT_CLASS (parent_class)->finalize) (object);
}
@@ -670,3 +673,6 @@ e_timezone_dialog_reparent (ETimezoneDialog *etd,
gtk_widget_reparent (priv->table, new_parent);
}
+
+E_MAKE_TYPE (e_timezone_dialog, "ETimezoneDialog", ETimezoneDialog,
+ e_timezone_dialog_class_init, e_timezone_dialog_init, G_TYPE_OBJECT)
diff --git a/widgets/e-timezone-dialog/e-timezone-dialog.glade b/widgets/e-timezone-dialog/e-timezone-dialog.glade
index 9a242ff59f..2f7bb95a0b 100644
--- a/widgets/e-timezone-dialog/e-timezone-dialog.glade
+++ b/widgets/e-timezone-dialog/e-timezone-dialog.glade
@@ -291,9 +291,6 @@ Use the right mouse button to zoom out.</property>
<property name="case_sensitive">False</property>
<property name="enable_arrow_keys">True</property>
<property name="enable_arrows_always">False</property>
- <accessibility>
- <atkproperty name="AtkObject::accessible_name" translatable="yes">TimeZone Combobox</atkproperty>
- </accessibility>
<child internal-child="entry">
<widget class="GtkEntry" id="combo-entry1">
diff --git a/widgets/menus/gal-define-views-dialog.c b/widgets/menus/gal-define-views-dialog.c
deleted file mode 100644
index 4d2854a0e1..0000000000
--- a/widgets/menus/gal-define-views-dialog.c
+++ /dev/null
@@ -1,379 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * gal-define-views-dialog.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-
-#include "gal-define-views-dialog.h"
-
-#include <gtk/gtk.h>
-#include "gal-define-views-model.h"
-#include "gal-view-new-dialog.h"
-#include <gal/e-table/e-table-scrolled.h>
-#include <gal/util/e-i18n.h>
-#include <gal/util/e-util.h>
-
-static void gal_define_views_dialog_init (GalDefineViewsDialog *card);
-static void gal_define_views_dialog_class_init (GalDefineViewsDialogClass *klass);
-static void gal_define_views_dialog_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
-static void gal_define_views_dialog_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
-static void gal_define_views_dialog_dispose (GObject *object);
-
-static GtkDialogClass *parent_class = NULL;
-#define PARENT_TYPE GTK_TYPE_DIALOG
-
-/* The properties we support */
-enum {
- PROP_0,
- PROP_COLLECTION
-};
-
-typedef struct {
- char *title;
- ETableModel *model;
- GalDefineViewsDialog *names;
-} GalDefineViewsDialogChild;
-
-
-E_MAKE_TYPE(gal_define_views_dialog, "GalDefineViewsDialog", GalDefineViewsDialog, gal_define_views_dialog_class_init, gal_define_views_dialog_init, PARENT_TYPE)
-
-static void
-gal_define_views_dialog_class_init (GalDefineViewsDialogClass *klass)
-{
- GObjectClass *object_class;
-
- object_class = (GObjectClass*) klass;
-
- parent_class = g_type_class_ref (PARENT_TYPE);
-
- object_class->set_property = gal_define_views_dialog_set_property;
- object_class->get_property = gal_define_views_dialog_get_property;
- object_class->dispose = gal_define_views_dialog_dispose;
-
- g_object_class_install_property (object_class, PROP_COLLECTION,
- g_param_spec_object ("collection",
- _("Collection"),
- /*_( */"XXX blurb" /*)*/,
- GAL_VIEW_COLLECTION_TYPE,
- G_PARAM_READWRITE));
-}
-
-/* ETable creation */
-#define SPEC "<ETableSpecification cursor-mode=\"line\" draw-grid=\"true\" selection-mode=\"single\" gettext-domain=\"" E_I18N_DOMAIN "\">" \
- "<ETableColumn model_col= \"0\" _title=\"Name\" expansion=\"1.0\" minimum_width=\"18\" resizable=\"true\" cell=\"string\" compare=\"string\"/>" \
- "<ETableState> <column source=\"0\"/> <grouping> </grouping> </ETableState>" \
- "</ETableSpecification>"
-
-/* For use from libglade. */
-GtkWidget *gal_define_views_dialog_create_etable(char *name, char *string1, char *string2, int int1, int int2);
-
-GtkWidget *
-gal_define_views_dialog_create_etable(char *name, char *string1, char *string2, int int1, int int2)
-{
- GtkWidget *table;
- ETableModel *model;
- model = gal_define_views_model_new();
- table = e_table_scrolled_new(model, NULL, SPEC, NULL);
- g_object_set_data(G_OBJECT (table), "GalDefineViewsDialog::model", model);
- return table;
-}
-
-/* Button callbacks */
-
-static void
-gdvd_button_new_dialog_callback(GtkWidget *widget, int id, GalDefineViewsDialog *dialog)
-{
- gchar *name;
- GalView *view;
- GalViewFactory *factory;
- switch (id) {
- case GTK_RESPONSE_OK:
- g_object_get(widget,
- "name", &name,
- "factory", &factory,
- NULL);
- if (name && factory) {
- g_strchomp(name);
- if (*name != '\0') {
- view = gal_view_factory_new_view(factory, name);
- gal_define_views_model_append(GAL_DEFINE_VIEWS_MODEL(dialog->model), view);
- gal_view_edit(view, GTK_WINDOW (dialog));
- g_object_unref(view);
- }
- }
- g_object_unref(factory);
- g_free(name);
- break;
- }
- gtk_widget_destroy (widget);
-}
-
-static void
-gdvd_button_new_callback(GtkWidget *widget, GalDefineViewsDialog *dialog)
-{
- GtkWidget *view_new_dialog = gal_view_new_dialog_new(dialog->collection);
- gtk_window_set_transient_for (GTK_WINDOW (view_new_dialog), GTK_WINDOW (dialog));
- g_signal_connect(view_new_dialog, "response",
- G_CALLBACK(gdvd_button_new_dialog_callback), dialog);
- gtk_widget_show(view_new_dialog);
-}
-
-static void
-gdvd_button_modify_callback(GtkWidget *widget, GalDefineViewsDialog *dialog)
-{
- int row;
- GtkWidget *scrolled;
- ETable *etable;
-
- scrolled = glade_xml_get_widget(dialog->gui, "custom-table");
- etable = e_table_scrolled_get_table(E_TABLE_SCROLLED(scrolled));
- row = e_table_get_cursor_row (E_TABLE(etable));
-
- if (row != -1) {
- GalView *view;
- view = gal_define_views_model_get_view(GAL_DEFINE_VIEWS_MODEL(dialog->model),
- row);
- gal_view_edit(view, GTK_WINDOW (dialog));
- }
-}
-
-static void
-gdvd_button_delete_callback(GtkWidget *widget, GalDefineViewsDialog *dialog)
-{
- int row;
- GtkWidget *scrolled;
- ETable *etable;
-
- scrolled = glade_xml_get_widget(dialog->gui, "custom-table");
- etable = e_table_scrolled_get_table(E_TABLE_SCROLLED(scrolled));
- row = e_table_get_cursor_row (E_TABLE(etable));
-
- if (row != -1) {
- gal_define_views_model_delete_view(GAL_DEFINE_VIEWS_MODEL(dialog->model),
- row);
- }
-
-}
-
-#if 0
-static void
-gdvd_button_copy_callback(GtkWidget *widget, GalDefineViewsDialog *dialog)
-{
- int row;
- GtkWidget *scrolled;
- ETable *etable;
-
- scrolled = glade_xml_get_widget(dialog->gui, "custom-table");
- etable = e_table_scrolled_get_table(E_TABLE_SCROLLED(scrolled));
- row = e_table_get_cursor_row (E_TABLE(etable));
-
- if (row != -1) {
- gal_define_views_model_copy_view(GAL_DEFINE_VIEWS_MODEL(dialog->model),
- row);
- }
-
-}
-#endif
-
-static void
-gdvd_connect_signal(GalDefineViewsDialog *dialog, char *widget_name, char *signal, GCallback handler)
-{
- GtkWidget *widget;
-
- widget = glade_xml_get_widget(dialog->gui, widget_name);
-
- if (widget)
- g_signal_connect(widget, signal, handler, dialog);
-}
-
-static void
-etable_selection_change_forall_cb (int row, GalDefineViewsDialog *dialog)
-{
- if (row != -1) {
- GalViewCollectionItem *item = gal_view_collection_get_view_item (dialog->collection, row);
-
- if (item)
- gtk_widget_set_sensitive (glade_xml_get_widget (dialog->gui, "button-delete"),
- !item->built_in);
- }
-}
-
-static void
-etable_selection_change (ETable *etable, GalDefineViewsDialog *dialog)
-{
- e_table_selected_row_foreach (etable, (EForeachFunc) etable_selection_change_forall_cb, dialog);
-}
-
-static void
-dialog_response (GalDefineViewsDialog *dialog, int response_id, gpointer data)
-{
- gal_view_collection_save (dialog->collection);
-}
-
-static void
-gal_define_views_dialog_init (GalDefineViewsDialog *dialog)
-{
- GladeXML *gui;
- GtkWidget *widget;
- GtkWidget *etable;
-
- dialog->collection = NULL;
-
- gui = glade_xml_new (GAL_GLADEDIR "/gal-define-views.glade", NULL, E_I18N_DOMAIN);
- dialog->gui = gui;
-
- widget = glade_xml_get_widget(gui, "table-top");
- if (!widget) {
- return;
- }
- gtk_widget_ref(widget);
- gtk_container_remove (GTK_CONTAINER (widget->parent), widget);
- gtk_window_set_default_size(GTK_WINDOW(dialog), 360, 270);
- gtk_container_set_border_width(GTK_CONTAINER(dialog), 6);
- gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), widget, TRUE, TRUE, 0);
- gtk_widget_unref(widget);
-
- gtk_dialog_add_buttons (GTK_DIALOG (dialog),
- GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
- NULL);
-
- gdvd_connect_signal(dialog, "button-new", "clicked", G_CALLBACK(gdvd_button_new_callback));
- gdvd_connect_signal(dialog, "button-modify", "clicked", G_CALLBACK(gdvd_button_modify_callback));
- gdvd_connect_signal(dialog, "button-delete", "clicked", G_CALLBACK(gdvd_button_delete_callback));
-#if 0
- gdvd_connect_signal(dialog, "button-copy", "clicked", G_CALLBACK(gdvd_button_copy_callback));
-#endif
-
- dialog->model = NULL;
- etable = glade_xml_get_widget(dialog->gui, "custom-table");
- if (etable) {
- dialog->model = g_object_get_data(G_OBJECT (etable), "GalDefineViewsDialog::model");
- g_object_set(dialog->model,
- "collection", dialog->collection,
- NULL);
- g_signal_connect (e_table_scrolled_get_table (E_TABLE_SCROLLED (etable)),
- "selection_change",
- G_CALLBACK (etable_selection_change), dialog);
- gtk_widget_show_all (etable);
- }
-
- gtk_window_set_policy(GTK_WINDOW(dialog), FALSE, TRUE, FALSE);
-
- g_signal_connect (dialog, "response", G_CALLBACK (dialog_response), NULL);
-
-}
-
-static void
-gal_define_views_dialog_dispose (GObject *object)
-{
- GalDefineViewsDialog *gal_define_views_dialog = GAL_DEFINE_VIEWS_DIALOG(object);
-
- if (gal_define_views_dialog->gui)
- g_object_unref(gal_define_views_dialog->gui);
- gal_define_views_dialog->gui = NULL;
-
- if (G_OBJECT_CLASS (parent_class)->dispose)
- (* G_OBJECT_CLASS (parent_class)->dispose) (object);
-}
-
-static void
-gal_define_views_dialog_set_collection(GalDefineViewsDialog *dialog,
- GalViewCollection *collection)
-{
- dialog->collection = collection;
- if (dialog->model) {
- g_object_set(dialog->model,
- "collection", collection,
- NULL);
- }
- if (dialog->gui) {
- GtkWidget *widget = glade_xml_get_widget(dialog->gui, "label-views");
- if (widget && GTK_IS_LABEL (widget)) {
- if (collection->title) {
- char *text = g_strdup_printf (_("Define Views for %s"),
- collection->title);
- gtk_label_set_text (GTK_LABEL (widget),
- text);
- gtk_window_set_title (GTK_WINDOW (dialog), text);
- g_free (text);
- } else {
- gtk_label_set_text (GTK_LABEL (widget),
- _("Define Views"));
- gtk_window_set_title (GTK_WINDOW (dialog),
- _("Define Views"));
- }
- }
- }
-}
-
-/**
- * gal_define_views_dialog_new
- *
- * Returns a new dialog for defining views.
- *
- * Returns: The GalDefineViewsDialog.
- */
-GtkWidget*
-gal_define_views_dialog_new (GalViewCollection *collection)
-{
- GtkWidget *widget = g_object_new (GAL_DEFINE_VIEWS_DIALOG_TYPE, NULL);
- gal_define_views_dialog_set_collection(GAL_DEFINE_VIEWS_DIALOG (widget), collection);
- return widget;
-}
-
-static void
-gal_define_views_dialog_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
-{
- GalDefineViewsDialog *dialog;
-
- dialog = GAL_DEFINE_VIEWS_DIALOG (object);
-
- switch (prop_id){
- case PROP_COLLECTION:
- if (g_value_get_object (value))
- gal_define_views_dialog_set_collection(dialog, GAL_VIEW_COLLECTION(g_value_get_object (value)));
- else
- gal_define_views_dialog_set_collection(dialog, NULL);
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- return;
- }
-}
-
-static void
-gal_define_views_dialog_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
-{
- GalDefineViewsDialog *dialog;
-
- dialog = GAL_DEFINE_VIEWS_DIALOG (object);
-
- switch (prop_id) {
- case PROP_COLLECTION:
- g_value_set_object (value, dialog->collection);
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
diff --git a/widgets/menus/gal-define-views-dialog.h b/widgets/menus/gal-define-views-dialog.h
deleted file mode 100644
index 03a047b9fe..0000000000
--- a/widgets/menus/gal-define-views-dialog.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * gal-define-views-dialog.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef __GAL_DEFINE_VIEWS_DIALOG_H__
-#define __GAL_DEFINE_VIEWS_DIALOG_H__
-
-#include <gtk/gtkdialog.h>
-#include <glade/glade.h>
-#include <gal/e-table/e-table-model.h>
-#include <gal/menus/gal-view-collection.h>
-
-#ifdef __cplusplus
-extern "C" {
-#pragma }
-#endif /* __cplusplus */
-
-/* GalDefineViewsDialog - A dialog displaying information about a contact.
- *
- * The following arguments are available:
- *
- * name type read/write description
- * --------------------------------------------------------------------------------
- */
-
-#define GAL_DEFINE_VIEWS_DIALOG_TYPE (gal_define_views_dialog_get_type ())
-#define GAL_DEFINE_VIEWS_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_DEFINE_VIEWS_DIALOG_TYPE, GalDefineViewsDialog))
-#define GAL_DEFINE_VIEWS_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_DEFINE_VIEWS_DIALOG_TYPE, GalDefineViewsDialogClass))
-#define GAL_IS_DEFINE_VIEWS_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_DEFINE_VIEWS_DIALOG_TYPE))
-#define GAL_IS_DEFINE_VIEWS_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), GAL_DEFINE_VIEWS_DIALOG_TYPE))
-
-typedef struct _GalDefineViewsDialog GalDefineViewsDialog;
-typedef struct _GalDefineViewsDialogClass GalDefineViewsDialogClass;
-
-struct _GalDefineViewsDialog
-{
- GtkDialog parent;
-
- /* item specific fields */
- GladeXML *gui;
- ETableModel *model;
-
- GalViewCollection *collection;
-};
-
-struct _GalDefineViewsDialogClass
-{
- GtkDialogClass parent_class;
-};
-
-GtkWidget *gal_define_views_dialog_new (GalViewCollection *collection);
-GType gal_define_views_dialog_get_type (void);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-
-#endif /* __GAL_DEFINE_VIEWS_DIALOG_H__ */
diff --git a/widgets/menus/gal-define-views-model.c b/widgets/menus/gal-define-views-model.c
deleted file mode 100644
index 40e54a53b6..0000000000
--- a/widgets/menus/gal-define-views-model.c
+++ /dev/null
@@ -1,322 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * gal-define-views-model.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <libxml/tree.h>
-#include <libxml/parser.h>
-#include <libxml/xmlmemory.h>
-#include "gal-define-views-model.h"
-#include <gal/util/e-i18n.h>
-#include <gal/util/e-util.h>
-
-#define PARENT_TYPE E_TABLE_MODEL_TYPE
-static ETableModelClass *parent_class;
-
-/*
- * GalDefineViewsModel callbacks
- * These are the callbacks that define the behavior of our custom model.
- */
-static void gal_define_views_model_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
-static void gal_define_views_model_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
-
-enum {
- PROP_0,
- PROP_EDITABLE,
- PROP_COLLECTION
-};
-
-static void
-gdvm_dispose(GObject *object)
-{
- GalDefineViewsModel *model = GAL_DEFINE_VIEWS_MODEL(object);
-
- if (model->collection)
- g_object_unref(model->collection);
- model->collection = NULL;
-
- if (G_OBJECT_CLASS (parent_class)->dispose)
- (* G_OBJECT_CLASS (parent_class)->dispose) (object);
-}
-
-/* This function returns the number of columns in our ETableModel. */
-static int
-gdvm_col_count (ETableModel *etc)
-{
- return 1;
-}
-
-/* This function returns the number of rows in our ETableModel. */
-static int
-gdvm_row_count (ETableModel *etc)
-{
- GalDefineViewsModel *views = GAL_DEFINE_VIEWS_MODEL(etc);
- if (views->collection)
- return gal_view_collection_get_count(views->collection);
- else
- return 0;
-}
-
-/* This function returns the value at a particular point in our ETableModel. */
-static void *
-gdvm_value_at (ETableModel *etc, int col, int row)
-{
- GalDefineViewsModel *views = GAL_DEFINE_VIEWS_MODEL(etc);
- const char *value;
-
- value = gal_view_get_title (gal_view_collection_get_view(views->collection, row));
-
- return (void *)(value ? value : "");
-}
-
-/* This function sets the value at a particular point in our ETableModel. */
-static void
-gdvm_set_value_at (ETableModel *etc, int col, int row, const void *val)
-{
- GalDefineViewsModel *views = GAL_DEFINE_VIEWS_MODEL(etc);
- if (views->editable) {
- e_table_model_pre_change(etc);
- gal_view_set_title(gal_view_collection_get_view(views->collection, row), val);
- e_table_model_cell_changed(etc, col, row);
- }
-}
-
-/* This function returns whether a particular cell is editable. */
-static gboolean
-gdvm_is_cell_editable (ETableModel *etc, int col, int row)
-{
- return GAL_DEFINE_VIEWS_MODEL(etc)->editable;
-}
-
-static void
-gdvm_append_row (ETableModel *etm, ETableModel *source, gint row)
-{
-}
-
-/* This function duplicates the value passed to it. */
-static void *
-gdvm_duplicate_value (ETableModel *etc, int col, const void *value)
-{
- return g_strdup(value);
-}
-
-/* This function frees the value passed to it. */
-static void
-gdvm_free_value (ETableModel *etc, int col, void *value)
-{
- g_free(value);
-}
-
-static void *
-gdvm_initialize_value (ETableModel *etc, int col)
-{
- return g_strdup("");
-}
-
-static gboolean
-gdvm_value_is_empty (ETableModel *etc, int col, const void *value)
-{
- return !(value && *(char *)value);
-}
-
-static char *
-gdvm_value_to_string (ETableModel *etc, int col, const void *value)
-{
- return g_strdup(value);
-}
-
-/**
- * gal_define_views_model_append
- * @model: The model to add to.
- * @view: The view to add.
- *
- * Adds the given view to the gal define views model.
- */
-void
-gal_define_views_model_append (GalDefineViewsModel *model,
- GalView *view)
-{
- ETableModel *etm = E_TABLE_MODEL(model);
-
- e_table_model_pre_change(etm);
- gal_view_collection_append(model->collection, view);
- e_table_model_row_inserted(etm, gal_view_collection_get_count(model->collection) - 1);
-}
-
-static void
-gal_define_views_model_class_init (GObjectClass *object_class)
-{
- ETableModelClass *model_class = (ETableModelClass *) object_class;
-
- parent_class = g_type_class_ref (PARENT_TYPE);
-
- object_class->dispose = gdvm_dispose;
- object_class->set_property = gal_define_views_model_set_property;
- object_class->get_property = gal_define_views_model_get_property;
-
- g_object_class_install_property (object_class, PROP_EDITABLE,
- g_param_spec_boolean ("editable",
- _("Editable"),
- /*_( */"XXX blurb" /*)*/,
- FALSE,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class, PROP_COLLECTION,
- g_param_spec_object ("collection",
- _("Collection"),
- /*_( */"XXX blurb" /*)*/,
- GAL_VIEW_COLLECTION_TYPE,
- G_PARAM_READWRITE));
-
- model_class->column_count = gdvm_col_count;
- model_class->row_count = gdvm_row_count;
- model_class->value_at = gdvm_value_at;
- model_class->set_value_at = gdvm_set_value_at;
- model_class->is_cell_editable = gdvm_is_cell_editable;
- model_class->append_row = gdvm_append_row;
- model_class->duplicate_value = gdvm_duplicate_value;
- model_class->free_value = gdvm_free_value;
- model_class->initialize_value = gdvm_initialize_value;
- model_class->value_is_empty = gdvm_value_is_empty;
- model_class->value_to_string = gdvm_value_to_string;
-}
-
-static void
-gal_define_views_model_init (GObject *object)
-{
- GalDefineViewsModel *model = GAL_DEFINE_VIEWS_MODEL(object);
-
- model->collection = NULL;
-}
-
-static void
-gal_define_views_model_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
-{
- GalDefineViewsModel *model;
-
- model = GAL_DEFINE_VIEWS_MODEL (object);
-
- switch (prop_id){
- case PROP_EDITABLE:
- model->editable = g_value_get_boolean (value);
- break;
-
- case PROP_COLLECTION:
- e_table_model_pre_change(E_TABLE_MODEL(object));
- if (g_value_get_object (value))
- model->collection = GAL_VIEW_COLLECTION(g_value_get_object (value));
- else
- model->collection = NULL;
- e_table_model_changed(E_TABLE_MODEL(object));
- break;
- }
-}
-
-static void
-gal_define_views_model_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
-{
- GalDefineViewsModel *model;
-
- model = GAL_DEFINE_VIEWS_MODEL (object);
-
- switch (prop_id) {
- case PROP_EDITABLE:
- g_value_set_boolean (value, model->editable);
- break;
-
- case PROP_COLLECTION:
- g_value_set_object (value, model->collection);
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-E_MAKE_TYPE(gal_define_views_model, "GalDefineViewsModel", GalDefineViewsModel, gal_define_views_model_class_init, gal_define_views_model_init, PARENT_TYPE)
-
-/**
- * gal_define_views_model_new
- *
- * Returns a new define views model. This is a list of views as an
- * ETable for use in the GalDefineViewsDialog.
- *
- * Returns: The new GalDefineViewsModel.
- */
-ETableModel *
-gal_define_views_model_new (void)
-{
- GalDefineViewsModel *et;
-
- et = g_object_new (GAL_DEFINE_VIEWS_MODEL_TYPE, NULL);
-
- return E_TABLE_MODEL(et);
-}
-
-/**
- * gal_define_views_model_get_view:
- * @model: The GalDefineViewsModel.
- * @n: Which view to get.
- *
- * Gets the nth view.
- *
- * Returns: The view.
- */
-GalView *
-gal_define_views_model_get_view (GalDefineViewsModel *model,
- int n)
-{
- return gal_view_collection_get_view(model->collection, n);
-}
-
-/**
- * gal_define_views_model_delete_view:
- * @model: The GalDefineViewsModel.
- * @n: Which view to delete.
- *
- * Deletes the nth view.
- */
-void
-gal_define_views_model_delete_view (GalDefineViewsModel *model,
- int n)
-{
- e_table_model_pre_change(E_TABLE_MODEL(model));
- gal_view_collection_delete_view(model->collection, n);
- e_table_model_row_deleted(E_TABLE_MODEL(model), n);
-}
-
-/**
- * gal_define_views_model_copy_view:
- * @model: The GalDefineViewsModel.
- * @n: Which view to copy.
- *
- * Copys the nth view.
- */
-void
-gal_define_views_model_copy_view (GalDefineViewsModel *model,
- int n)
-{
- ETableModel *etm = E_TABLE_MODEL(model);
- e_table_model_pre_change(etm);
- gal_view_collection_copy_view(model->collection, n);
- e_table_model_row_inserted(etm, gal_view_collection_get_count(model->collection) - 1);
-}
diff --git a/widgets/menus/gal-define-views-model.h b/widgets/menus/gal-define-views-model.h
deleted file mode 100644
index 6ea2b28cbc..0000000000
--- a/widgets/menus/gal-define-views-model.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * gal-define-views-model.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _GAL_DEFINE_VIEWS_MODEL_H_
-#define _GAL_DEFINE_VIEWS_MODEL_H_
-
-#include <gal/e-table/e-table-model.h>
-#include <gal/menus/gal-view.h>
-#include <gal/menus/gal-view-collection.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-#define GAL_DEFINE_VIEWS_MODEL_TYPE (gal_define_views_model_get_type ())
-#define GAL_DEFINE_VIEWS_MODEL(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GAL_DEFINE_VIEWS_MODEL_TYPE, GalDefineViewsModel))
-#define GAL_DEFINE_VIEWS_MODEL_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GAL_DEFINE_VIEWS_MODEL_TYPE, GalDefineViewsModelClass))
-#define GAL_IS_DEFINE_VIEWS_MODEL(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GAL_DEFINE_VIEWS_MODEL_TYPE))
-#define GAL_IS_DEFINE_VIEWS_MODEL_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GAL_DEFINE_VIEWS_MODEL_TYPE))
-
-typedef struct {
- ETableModel parent;
-
- /* item specific fields */
- GalViewCollection *collection;
-
- guint editable : 1;
-} GalDefineViewsModel;
-
-
-typedef struct {
- ETableModelClass parent_class;
-} GalDefineViewsModelClass;
-
-
-GType gal_define_views_model_get_type (void);
-ETableModel *gal_define_views_model_new (void);
-
-void gal_define_views_model_append (GalDefineViewsModel *model,
- GalView *view);
-GalView *gal_define_views_model_get_view (GalDefineViewsModel *model,
- int i);
-void gal_define_views_model_delete_view (GalDefineViewsModel *model,
- int i);
-void gal_define_views_model_copy_view (GalDefineViewsModel *model,
- int i);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* _GAL_DEFINE_VIEWS_MODEL_H_ */
diff --git a/widgets/menus/gal-define-views.glade b/widgets/menus/gal-define-views.glade
deleted file mode 100644
index 11395ad8b7..0000000000
--- a/widgets/menus/gal-define-views.glade
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
-<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
-
-<glade-interface>
-
-<widget class="GtkDialog" id="dialog1">
- <property name="title" translatable="yes">Define Views for &quot;%s&quot;</property>
- <property name="type">GTK_WINDOW_TOPLEVEL</property>
- <property name="window_position">GTK_WIN_POS_NONE</property>
- <property name="modal">False</property>
- <property name="resizable">True</property>
- <property name="destroy_with_parent">False</property>
- <property name="has_separator">True</property>
-
- <child internal-child="vbox">
- <widget class="GtkVBox" id="dialog-vbox1">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
-
- <child internal-child="action_area">
- <widget class="GtkHButtonBox" id="dialog-action_area1">
- <property name="visible">True</property>
- <property name="layout_style">GTK_BUTTONBOX_END</property>
-
- <child>
- <widget class="GtkButton" id="button7">
- <property name="visible">True</property>
- <property name="can_default">True</property>
- <property name="can_focus">True</property>
- <property name="label">gtk-close</property>
- <property name="use_stock">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="response_id">-5</property>
- </widget>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="pack_type">GTK_PACK_END</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkTable" id="table-top">
- <property name="visible">True</property>
- <property name="n_rows">4</property>
- <property name="n_columns">1</property>
- <property name="homogeneous">False</property>
- <property name="row_spacing">6</property>
- <property name="column_spacing">6</property>
-
- <child>
- <widget class="GtkHBox" id="hbox1">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="Custom" id="custom-table">
- <property name="visible">True</property>
- <property name="creation_function">gal_define_views_dialog_create_etable</property>
- <property name="int1">0</property>
- <property name="int2">0</property>
- <property name="last_modification_time">Fri, 10 Nov 2000 16:37:39 GMT</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkVBox" id="vbox1">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="GtkButton" id="button-new">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label">gtk-new</property>
- <property name="use_stock">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkButton" id="button-modify">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">_Edit...</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkButton" id="button-delete">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label">gtk-delete</property>
- <property name="use_stock">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="left_attach">0</property>
- <property name="right_attach">1</property>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkHButtonBox" id="hbuttonbox1">
- <property name="visible">True</property>
- <property name="layout_style">GTK_BUTTONBOX_END</property>
- <property name="spacing">6</property>
- </widget>
- <packing>
- <property name="left_attach">0</property>
- <property name="right_attach">1</property>
- <property name="top_attach">3</property>
- <property name="bottom_attach">4</property>
- <property name="x_options">fill</property>
- <property name="y_options">fill</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label-views">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Define Views for %s</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="left_attach">0</property>
- <property name="right_attach">1</property>
- <property name="top_attach">0</property>
- <property name="bottom_attach">1</property>
- <property name="x_options">fill</property>
- <property name="y_options"></property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">12</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- </child>
-</widget>
-
-</glade-interface>
diff --git a/widgets/menus/gal-view-collection.c b/widgets/menus/gal-view-collection.c
deleted file mode 100644
index 5e97419270..0000000000
--- a/widgets/menus/gal-view-collection.c
+++ /dev/null
@@ -1,823 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * gal-view-collection.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-
-#include <util/e-i18n.h>
-#include <sys/stat.h>
-#include <ctype.h>
-#include <string.h>
-#include <errno.h>
-#include <libxml/parser.h>
-#include <libgnome/gnome-util.h>
-#include <gal/util/e-util.h>
-#include <gal/util/e-xml-utils.h>
-#include <gal/widgets/e-unicode.h>
-#include "gal-view-collection.h"
-
-#define PARENT_TYPE G_TYPE_OBJECT
-
-static GObjectClass *gal_view_collection_parent_class;
-
-#define d(x)
-
-enum {
- DISPLAY_VIEW,
- CHANGED,
- LAST_SIGNAL
-};
-
-static guint gal_view_collection_signals [LAST_SIGNAL] = { 0, };
-
-/**
- * gal_view_collection_display_view:
- * @collection: The GalViewCollection to send the signal on.
- * @view: The view to display.
- *
- */
-void
-gal_view_collection_display_view (GalViewCollection *collection,
- GalView *view)
-{
- g_return_if_fail (collection != NULL);
- g_return_if_fail (GAL_IS_VIEW_COLLECTION (collection));
- g_return_if_fail (view != NULL);
- g_return_if_fail (GAL_IS_VIEW (view));
-
- g_signal_emit (collection,
- gal_view_collection_signals [DISPLAY_VIEW], 0,
- view);
-}
-
-static void
-gal_view_collection_changed (GalViewCollection *collection)
-{
- g_return_if_fail (collection != NULL);
- g_return_if_fail (GAL_IS_VIEW_COLLECTION (collection));
-
- g_signal_emit (collection,
- gal_view_collection_signals [CHANGED], 0);
-}
-
-static void
-gal_view_collection_item_free (GalViewCollectionItem *item)
-{
- g_free(item->id);
- if (item->view) {
- if (item->view_changed_id)
- g_signal_handler_disconnect (item->view,
- item->view_changed_id);
- g_object_unref(item->view);
- }
- g_free(item);
-}
-
-static char *
-gal_view_generate_string (GalViewCollection *collection,
- GalView *view,
- int which)
-{
- char *ret_val;
- char *pointer;
-
- if (which == 1)
- ret_val = g_strdup(gal_view_get_title(view));
- else
- ret_val = g_strdup_printf("%s_%d", gal_view_get_title(view), which);
- for (pointer = ret_val; *pointer; pointer++) {
- if (!isalnum((guint) *pointer)) {
- *pointer = '_';
- }
- }
- return ret_val;
-}
-
-static gint
-gal_view_check_string (GalViewCollection *collection,
- char *string)
-{
- int i;
-
- if (!strcmp (string, "current_view"))
- return FALSE;
-
- for (i = 0; i < collection->view_count; i++) {
- if (!strcmp(string, collection->view_data[i]->id))
- return FALSE;
- }
- for (i = 0; i < collection->removed_view_count; i++) {
- if (!strcmp(string, collection->removed_view_data[i]->id))
- return FALSE;
- }
- return TRUE;
-}
-
-static char *
-gal_view_generate_id (GalViewCollection *collection,
- GalView *view)
-{
- int i;
- for (i = 1; TRUE; i++) {
- char *try;
-
- try = gal_view_generate_string(collection, view, i);
- if (gal_view_check_string(collection, try))
- return try;
- g_free(try);
- }
-}
-
-static void
-gal_view_collection_dispose (GObject *object)
-{
- GalViewCollection *collection = GAL_VIEW_COLLECTION(object);
- int i;
-
- for (i = 0; i < collection->view_count; i++) {
- gal_view_collection_item_free (collection->view_data[i]);
- }
- g_free (collection->view_data);
- collection->view_data = NULL;
- collection->view_count = 0;
-
- e_free_object_list (collection->factory_list);
- collection->factory_list = NULL;
-
- for (i = 0; i < collection->removed_view_count; i++) {
- gal_view_collection_item_free (collection->removed_view_data[i]);
- }
- g_free(collection->removed_view_data);
- collection->removed_view_data = NULL;
- collection->removed_view_count = 0;
-
- g_free(collection->system_dir);
- collection->system_dir = NULL;
-
- g_free(collection->local_dir);
- collection->system_dir = NULL;
- collection->local_dir = NULL;
-
- g_free (collection->default_view);
- collection->default_view = NULL;
-
- g_free (collection->title);
- collection->title = NULL;
-
- if (gal_view_collection_parent_class->dispose)
- (*gal_view_collection_parent_class->dispose)(object);
-}
-
-static void
-gal_view_collection_class_init (GObjectClass *object_class)
-{
- GalViewCollectionClass *klass = GAL_VIEW_COLLECTION_CLASS(object_class);
- gal_view_collection_parent_class = g_type_class_ref (PARENT_TYPE);
-
- object_class->dispose = gal_view_collection_dispose;
-
- gal_view_collection_signals [DISPLAY_VIEW] =
- g_signal_new ("display_view",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GalViewCollectionClass, display_view),
- NULL, NULL,
- g_cclosure_marshal_VOID__OBJECT,
- G_TYPE_NONE, 1, GAL_VIEW_TYPE);
-
- gal_view_collection_signals [CHANGED] =
- g_signal_new ("changed",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GalViewCollectionClass, changed),
- NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
-
- klass->display_view = NULL;
- klass->changed = NULL;
-}
-
-static void
-gal_view_collection_init (GalViewCollection *collection)
-{
- collection->view_data = NULL;
- collection->view_count = 0;
- collection->factory_list = NULL;
-
- collection->removed_view_data = NULL;
- collection->removed_view_count = 0;
-
- collection->system_dir = NULL;
- collection->local_dir = NULL;
-
- collection->loaded = FALSE;
- collection->default_view = NULL;
- collection->default_view_built_in = TRUE;
-
- collection->title = NULL;
-}
-
-E_MAKE_TYPE(gal_view_collection, "GalViewCollection", GalViewCollection, gal_view_collection_class_init, gal_view_collection_init, PARENT_TYPE)
-
-/**
- * gal_view_collection_new:
- *
- * A collection of views and view factories.
- */
-GalViewCollection *
-gal_view_collection_new (void)
-{
- return g_object_new (GAL_VIEW_COLLECTION_TYPE, NULL);
-}
-
-void
-gal_view_collection_set_title (GalViewCollection *collection,
- const char *title)
-{
- g_free (collection->title);
- collection->title = g_strdup (title);
-}
-
-/**
- * gal_view_collection_set_storage_directories
- * @collection: The view collection to initialize
- * @system_dir: The location of the system built in views
- * @local_dir: The location to store the users set up views
- *
- * Sets up the GalViewCollection.
- */
-void
-gal_view_collection_set_storage_directories (GalViewCollection *collection,
- const char *system_dir,
- const char *local_dir)
-{
- g_return_if_fail (collection != NULL);
- g_return_if_fail (GAL_IS_VIEW_COLLECTION (collection));
- g_return_if_fail (system_dir != NULL);
- g_return_if_fail (local_dir != NULL);
-
- g_free(collection->system_dir);
- g_free(collection->local_dir);
-
- collection->system_dir = g_strdup(system_dir);
- collection->local_dir = g_strdup(local_dir);
-}
-
-/**
- * gal_view_collection_add_factory
- * @collection: The view collection to add a factory to
- * @factory: The factory to add. The @collection will add a reference
- * to the factory object, so you should unref it after calling this
- * function if you no longer need it.
- *
- * Adds the given factory to this collection. This list is used both
- * when loading views from their xml description as well as when the
- * user tries to create a new view.
- */
-void
-gal_view_collection_add_factory (GalViewCollection *collection,
- GalViewFactory *factory)
-{
- g_return_if_fail (collection != NULL);
- g_return_if_fail (GAL_IS_VIEW_COLLECTION (collection));
- g_return_if_fail (factory != NULL);
- g_return_if_fail (GAL_IS_VIEW_FACTORY (factory));
-
- g_object_ref (factory);
- collection->factory_list = g_list_prepend (collection->factory_list, factory);
-}
-
-static void
-view_changed (GalView *view,
- GalViewCollectionItem *item)
-{
- item->changed = TRUE;
- item->ever_changed = TRUE;
-
- g_signal_handler_block(G_OBJECT(item->view), item->view_changed_id);
- gal_view_collection_changed(item->collection);
- g_signal_handler_unblock(G_OBJECT(item->view), item->view_changed_id);
-}
-
-/* Use factory list to load a GalView file. */
-static GalView *
-gal_view_collection_real_load_view_from_file (GalViewCollection *collection, const char *type, const char *title, const char *dir, const char *filename)
-{
- GalViewFactory *factory;
- GList *factories;
-
- factory = NULL;
- for (factories = collection->factory_list; factories; factories = factories->next) {
- if (type && !strcmp(gal_view_factory_get_type_code(factories->data), type)) {
- factory = factories->data;
- break;
- }
- }
- if (factory) {
- GalView *view;
-
- view = gal_view_factory_new_view (factory, title);
- gal_view_set_title (view, title);
- gal_view_load(view, filename);
- return view;
- }
- return NULL;
-}
-
-GalView *
-gal_view_collection_load_view_from_file (GalViewCollection *collection, const char *type, const char *filename)
-{
- return gal_view_collection_real_load_view_from_file (collection, type, "", collection->local_dir, filename);
-}
-
-static GalViewCollectionItem *
-load_single_file (GalViewCollection *collection,
- gchar *dir,
- gboolean local,
- xmlNode *node)
-{
- GalViewCollectionItem *item;
- item = g_new(GalViewCollectionItem, 1);
- item->ever_changed = local;
- item->changed = FALSE;
- item->built_in = !local;
- item->id = e_xml_get_string_prop_by_name(node, "id");
- item->filename = e_xml_get_string_prop_by_name(node, "filename");
- item->title = e_xml_get_translated_utf8_string_prop_by_name(node, "title");
- item->type = e_xml_get_string_prop_by_name(node, "type");
- item->collection = collection;
- item->view_changed_id = 0;
-
- if (item->filename) {
- char *fullpath;
- fullpath = g_concat_dir_and_file(dir, item->filename);
- item->view = gal_view_collection_real_load_view_from_file (collection, item->type, item->title, dir, fullpath);
- g_free(fullpath);
- if (item->view) {
- item->view_changed_id =
- g_signal_connect(item->view, "changed",
- G_CALLBACK(view_changed), item);
- }
- }
- return item;
-}
-
-static void
-load_single_dir (GalViewCollection *collection,
- char *dir,
- gboolean local)
-{
- xmlDoc *doc = NULL;
- xmlNode *root;
- xmlNode *child;
- char *filename = g_concat_dir_and_file(dir, "galview.xml");
- char *default_view;
- struct stat st;
-
- if (stat (filename, &st) != -1 && S_ISREG (st.st_mode))
- doc = xmlParseFile (filename);
-
- if (!doc) {
- g_free (filename);
- return;
- }
- root = xmlDocGetRootElement(doc);
- for (child = root->xmlChildrenNode; child; child = child->next) {
- gchar *id;
- gboolean found = FALSE;
- int i;
-
- if (!strcmp (child->name, "text"))
- continue;
-
- id = e_xml_get_string_prop_by_name(child, "id");
- for (i = 0; i < collection->view_count; i++) {
- if (!strcmp(id, collection->view_data[i]->id)) {
- if (!local)
- collection->view_data[i]->built_in = TRUE;
- found = TRUE;
- break;
- }
- }
- if (!found) {
- for (i = 0; i < collection->removed_view_count; i++) {
- if (!strcmp(id, collection->removed_view_data[i]->id)) {
- if (!local)
- collection->removed_view_data[i]->built_in = TRUE;
- found = TRUE;
- break;
- }
- }
- }
-
- if (!found) {
- GalViewCollectionItem *item = load_single_file (collection, dir, local, child);
- if (item->filename && *item->filename) {
- collection->view_data = g_renew(GalViewCollectionItem *, collection->view_data, collection->view_count + 1);
- collection->view_data[collection->view_count] = item;
- collection->view_count ++;
- } else {
- collection->removed_view_data = g_renew(GalViewCollectionItem *, collection->removed_view_data, collection->removed_view_count + 1);
- collection->removed_view_data[collection->removed_view_count] = item;
- collection->removed_view_count ++;
- }
- }
- g_free(id);
- }
-
- default_view = e_xml_get_string_prop_by_name (root, "default-view");
- if (default_view) {
- if (local)
- collection->default_view_built_in = FALSE;
- else
- collection->default_view_built_in = TRUE;
- g_free (collection->default_view);
- collection->default_view = default_view;
- }
-
- g_free(filename);
- xmlFreeDoc(doc);
-}
-
-/**
- * gal_view_collection_load
- * @collection: The view collection to load information for
- *
- * Loads the data from the system and user directories specified in
- * set storage directories. This is primarily for internal use by
- * other parts of gal_view.
- */
-void
-gal_view_collection_load (GalViewCollection *collection)
-{
- g_return_if_fail (collection != NULL);
- g_return_if_fail (GAL_IS_VIEW_COLLECTION (collection));
- g_return_if_fail (collection->local_dir != NULL);
- g_return_if_fail (collection->system_dir != NULL);
- g_return_if_fail (!collection->loaded);
-
- if ((e_create_directory(collection->local_dir) == -1) && (errno != EEXIST))
- g_warning ("Unable to create dir %s: %s", collection->local_dir, g_strerror(errno));
-
- load_single_dir(collection, collection->local_dir, TRUE);
- load_single_dir(collection, collection->system_dir, FALSE);
- gal_view_collection_changed(collection);
-
- collection->loaded = TRUE;
-}
-
-/**
- * gal_view_collection_save
- * @collection: The view collection to save information for
- *
- * Saves the data to the user directory specified in set storage
- * directories. This is primarily for internal use by other parts of
- * gal_view.
- */
-void
-gal_view_collection_save (GalViewCollection *collection)
-{
- int i;
- xmlDoc *doc;
- xmlNode *root;
- char *filename;
-
- g_return_if_fail (collection != NULL);
- g_return_if_fail (GAL_IS_VIEW_COLLECTION (collection));
- g_return_if_fail (collection->local_dir != NULL);
-
- doc = xmlNewDoc("1.0");
- root = xmlNewNode(NULL, "GalViewCollection");
- xmlDocSetRootElement(doc, root);
-
- if (collection->default_view && !collection->default_view_built_in) {
- e_xml_set_string_prop_by_name(root, "default-view", collection->default_view);
- }
-
- for (i = 0; i < collection->view_count; i++) {
- xmlNode *child;
- GalViewCollectionItem *item;
-
- item = collection->view_data[i];
- if (item->ever_changed) {
- child = xmlNewChild(root, NULL, "GalView", NULL);
- e_xml_set_string_prop_by_name(child, "id", item->id);
- e_xml_set_string_prop_by_name(child, "title", item->title);
- e_xml_set_string_prop_by_name(child, "filename", item->filename);
- e_xml_set_string_prop_by_name(child, "type", item->type);
-
- if (item->changed) {
- filename = g_concat_dir_and_file(collection->local_dir, item->filename);
- gal_view_save(item->view, filename);
- g_free(filename);
- }
- }
- }
- for (i = 0; i < collection->removed_view_count; i++) {
- xmlNode *child;
- GalViewCollectionItem *item;
-
- item = collection->removed_view_data[i];
-
- child = xmlNewChild(root, NULL, "GalView", NULL);
- e_xml_set_string_prop_by_name(child, "id", item->id);
- e_xml_set_string_prop_by_name(child, "title", item->title);
- e_xml_set_string_prop_by_name(child, "type", item->type);
- }
- filename = g_concat_dir_and_file(collection->local_dir, "galview.xml");
- if (e_xml_save_file (filename, doc) == -1)
- g_warning ("Unable to save view to %s - %s", filename, g_strerror(errno));
- xmlFreeDoc(doc);
- g_free(filename);
-}
-
-/**
- * gal_view_collection_get_count
- * @collection: The view collection to count
- *
- * Calculates the number of views in the given collection.
- *
- * Returns: The number of views in the collection.
- */
-gint
-gal_view_collection_get_count (GalViewCollection *collection)
-{
- g_return_val_if_fail (collection != NULL, -1);
- g_return_val_if_fail (GAL_IS_VIEW_COLLECTION (collection), -1);
-
- return collection->view_count;
-}
-
-/**
- * gal_view_collection_get_view
- * @collection: The view collection to query
- * @n: The view to get.
- *
- * Returns: The nth view in the collection
- */
-GalView *
-gal_view_collection_get_view (GalViewCollection *collection,
- int n)
-{
- g_return_val_if_fail (collection != NULL, NULL);
- g_return_val_if_fail (GAL_IS_VIEW_COLLECTION (collection), NULL);
- g_return_val_if_fail (n < collection->view_count, NULL);
- g_return_val_if_fail (n >= 0, NULL);
-
- return collection->view_data[n]->view;
-}
-
-/**
- * gal_view_collection_get_view_item
- * @collection: The view collection to query
- * @n: The view item to get.
- *
- * Returns: The nth view item in the collection
- */
-GalViewCollectionItem *
-gal_view_collection_get_view_item (GalViewCollection *collection,
- int n)
-{
- g_return_val_if_fail (collection != NULL, NULL);
- g_return_val_if_fail (GAL_IS_VIEW_COLLECTION (collection), NULL);
- g_return_val_if_fail(n < collection->view_count, NULL);
- g_return_val_if_fail(n >= 0, NULL);
-
- return collection->view_data[n];
-}
-
-int
-gal_view_collection_get_view_index_by_id (GalViewCollection *collection, const char *view_id)
-{
- int i;
- for (i = 0; i < collection->view_count; i++) {
- if (!strcmp (collection->view_data[i]->id, view_id))
- return i;
- }
- return -1;
-}
-
-char *
-gal_view_collection_get_view_id_by_index (GalViewCollection *collection, int n)
-{
- g_return_val_if_fail (collection != NULL, NULL);
- g_return_val_if_fail (GAL_IS_VIEW_COLLECTION (collection), NULL);
- g_return_val_if_fail(n < collection->view_count, NULL);
- g_return_val_if_fail(n >= 0, NULL);
-
- return g_strdup (collection->view_data[n]->id);
-}
-
-
-void
-gal_view_collection_append (GalViewCollection *collection,
- GalView *view)
-{
- GalViewCollectionItem *item;
-
- g_return_if_fail (collection != NULL);
- g_return_if_fail (GAL_IS_VIEW_COLLECTION (collection));
- g_return_if_fail (view != NULL);
- g_return_if_fail (GAL_IS_VIEW (view));
-
- item = g_new(GalViewCollectionItem, 1);
- item->ever_changed = TRUE;
- item->changed = TRUE;
- item->built_in = FALSE;
- item->title = g_strdup(gal_view_get_title(view));
- item->type = g_strdup(gal_view_get_type_code(view));
- item->id = gal_view_generate_id(collection, view);
- item->filename = g_strdup_printf("%s.galview", item->id);
- item->view = view;
- item->collection = collection;
- g_object_ref(view);
-
- item->view_changed_id =
- g_signal_connect(item->view, "changed",
- G_CALLBACK (view_changed), item);
-
- collection->view_data = g_renew(GalViewCollectionItem *, collection->view_data, collection->view_count + 1);
- collection->view_data[collection->view_count] = item;
- collection->view_count ++;
-
- gal_view_collection_changed(collection);
-}
-
-void
-gal_view_collection_delete_view (GalViewCollection *collection,
- int i)
-{
- GalViewCollectionItem *item;
-
- g_return_if_fail (collection != NULL);
- g_return_if_fail (GAL_IS_VIEW_COLLECTION (collection));
- g_return_if_fail (i >= 0 && i < collection->view_count);
-
- item = collection->view_data[i];
- memmove(collection->view_data + i, collection->view_data + i + 1, (collection->view_count - i - 1) * sizeof(GalViewCollectionItem *));
- collection->view_count --;
- if (item->built_in) {
- g_free(item->filename);
- item->filename = NULL;
-
- collection->removed_view_data = g_renew(GalViewCollectionItem *, collection->removed_view_data, collection->removed_view_count + 1);
- collection->removed_view_data[collection->removed_view_count] = item;
- collection->removed_view_count ++;
- } else {
- gal_view_collection_item_free (item);
- }
-
- gal_view_collection_changed(collection);
-}
-
-void
-gal_view_collection_copy_view (GalViewCollection *collection,
- int i)
-{
- GalViewCollectionItem *item;
- GalView *view;
-
- g_return_if_fail (collection != NULL);
- g_return_if_fail (GAL_IS_VIEW_COLLECTION (collection));
- g_return_if_fail (i >= 0 && i < collection->view_count);
-
- view = collection->view_data[i]->view;
-
- item = g_new(GalViewCollectionItem, 1);
- item->ever_changed = TRUE;
- item->changed = FALSE;
- item->built_in = FALSE;
- item->title = g_strdup(gal_view_get_title(view));
- item->type = g_strdup(gal_view_get_type_code(view));
- item->id = gal_view_generate_id(collection, view);
- item->filename = g_strdup_printf("%s.galview", item->id);
- item->view = gal_view_clone(view);
- item->collection = collection;
-
- item->view_changed_id =
- g_signal_connect(item->view, "changed",
- G_CALLBACK (view_changed), item);
-
- collection->view_data = g_renew(GalViewCollectionItem *, collection->view_data, collection->view_count + 1);
- collection->view_data[collection->view_count] = item;
- collection->view_count ++;
-
- gal_view_collection_changed(collection);
-}
-
-gboolean
-gal_view_collection_loaded (GalViewCollection *collection)
-{
- return collection->loaded;
-}
-
-const char *
-gal_view_collection_append_with_title (GalViewCollection *collection, const char *title, GalView *view)
-{
- GalViewCollectionItem *item;
-
- g_return_val_if_fail (collection != NULL, NULL);
- g_return_val_if_fail (GAL_IS_VIEW_COLLECTION (collection), NULL);
- g_return_val_if_fail (view != NULL, NULL);
- g_return_val_if_fail (GAL_IS_VIEW (view), NULL);
-
- gal_view_set_title (view, title);
-
- d(g_print("%s: %p\n", G_GNUC_FUNCTION, view));
-
- item = g_new(GalViewCollectionItem, 1);
- item->ever_changed = TRUE;
- item->changed = TRUE;
- item->built_in = FALSE;
- item->title = g_strdup(gal_view_get_title(view));
- item->type = g_strdup(gal_view_get_type_code(view));
- item->id = gal_view_generate_id(collection, view);
- item->filename = g_strdup_printf("%s.galview", item->id);
- item->view = view;
- item->collection = collection;
- g_object_ref(view);
-
- item->view_changed_id =
- g_signal_connect(item->view, "changed",
- G_CALLBACK (view_changed), item);
-
- collection->view_data = g_renew(GalViewCollectionItem *, collection->view_data, collection->view_count + 1);
- collection->view_data[collection->view_count] = item;
- collection->view_count ++;
-
- gal_view_collection_changed(collection);
- return item->id;
-}
-
-const char *
-gal_view_collection_set_nth_view (GalViewCollection *collection, int i, GalView *view)
-{
- GalViewCollectionItem *item;
-
- g_return_val_if_fail (collection != NULL, NULL);
- g_return_val_if_fail (GAL_IS_VIEW_COLLECTION (collection), NULL);
- g_return_val_if_fail (view != NULL, NULL);
- g_return_val_if_fail (GAL_IS_VIEW (view), NULL);
- g_return_val_if_fail (i >= 0, NULL);
- g_return_val_if_fail (i < collection->view_count, NULL);
-
- d(g_print("%s: %p\n", G_GNUC_FUNCTION, view));
-
- item = collection->view_data[i];
-
- gal_view_set_title (view, item->title);
- g_object_ref (view);
- if (item->view) {
- g_signal_handler_disconnect (item->view,
- item->view_changed_id);
- g_object_unref (item->view);
- }
- item->view = view;
-
- item->ever_changed = TRUE;
- item->changed = TRUE;
- item->type = g_strdup(gal_view_get_type_code(view));
-
- item->view_changed_id =
- g_signal_connect(item->view, "changed",
- G_CALLBACK (view_changed), item);
-
- gal_view_collection_changed (collection);
- return item->id;
-}
-
-const char *
-gal_view_collection_get_default_view (GalViewCollection *collection)
-{
- return collection->default_view;
-}
-
-void
-gal_view_collection_set_default_view (GalViewCollection *collection, const char *id)
-{
- g_free (collection->default_view);
- collection->default_view = g_strdup (id);
- gal_view_collection_changed (collection);
- collection->default_view_built_in = FALSE;
-}
-
diff --git a/widgets/menus/gal-view-collection.h b/widgets/menus/gal-view-collection.h
deleted file mode 100644
index 9ba5eab71f..0000000000
--- a/widgets/menus/gal-view-collection.h
+++ /dev/null
@@ -1,151 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * gal-view-collection.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _GAL_VIEW_SET_H_
-#define _GAL_VIEW_SET_H_
-
-#include <gtk/gtkobject.h>
-#include <gal/menus/gal-view-factory.h>
-
-G_BEGIN_DECLS
-
-#define GAL_VIEW_COLLECTION_TYPE (gal_view_collection_get_type ())
-#define GAL_VIEW_COLLECTION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GAL_VIEW_COLLECTION_TYPE, GalViewCollection))
-#define GAL_VIEW_COLLECTION_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GAL_VIEW_COLLECTION_TYPE, GalViewCollectionClass))
-#define GAL_IS_VIEW_COLLECTION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GAL_VIEW_COLLECTION_TYPE))
-#define GAL_IS_VIEW_COLLECTION_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GAL_VIEW_COLLECTION_TYPE))
-#define GAL_VIEW_COLLECTION_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GAL_VIEW_COLLECTION_TYPE, GalViewCollectionClass))
-
-typedef struct GalViewCollectionItem GalViewCollectionItem;
-
-typedef struct {
- GObject base;
-
- GalViewCollectionItem **view_data;
- int view_count;
-
- GList *factory_list;
-
- GalViewCollectionItem **removed_view_data;
- int removed_view_count;
-
- guint loaded : 1;
- guint default_view_built_in : 1;
-
- char *system_dir;
- char *local_dir;
-
- char *default_view;
-
- char *title;
-} GalViewCollection;
-
-typedef struct {
- GObjectClass parent_class;
-
- /*
- * Signals
- */
- void (*display_view) (GalViewCollection *collection,
- GalView *view);
- void (*changed) (GalViewCollection *collection);
-} GalViewCollectionClass;
-
-struct GalViewCollectionItem {
- GalView *view;
- char *id;
- guint changed : 1;
- guint ever_changed : 1;
- guint built_in : 1;
- char *filename;
- char *title;
- char *type;
- GalViewCollection *collection;
- guint view_changed_id;
-};
-
-/* Standard functions */
-GType gal_view_collection_get_type (void);
-GalViewCollection *gal_view_collection_new (void);
-
-void gal_view_collection_set_title (GalViewCollection *collection,
- const char *title);
-/* Set up the view collection. Call these two functions before ever doing load or save and never call them again. */
-void gal_view_collection_set_storage_directories (GalViewCollection *collection,
- const char *system_dir,
- const char *local_dir);
-void gal_view_collection_add_factory (GalViewCollection *collection,
- GalViewFactory *factory);
-
-/* Send the display view signal. This function is deprecated. */
-void gal_view_collection_display_view (GalViewCollection *collection,
- GalView *view);
-
-
-/* Query the view collection. */
-gint gal_view_collection_get_count (GalViewCollection *collection);
-GalView *gal_view_collection_get_view (GalViewCollection *collection,
- int n);
-GalViewCollectionItem *gal_view_collection_get_view_item (GalViewCollection *collection,
- int n);
-int gal_view_collection_get_view_index_by_id (GalViewCollection *collection,
- const char *view_id);
-char *gal_view_collection_get_view_id_by_index (GalViewCollection *collection,
- int n);
-
-/* Manipulate the view collection */
-void gal_view_collection_append (GalViewCollection *collection,
- GalView *view);
-void gal_view_collection_delete_view (GalViewCollection *collection,
- int i);
-void gal_view_collection_copy_view (GalViewCollection *collection,
- int i);
-/* Call set_storage_directories and add factories for anything that
- * might be found there before doing either of these. */
-void gal_view_collection_load (GalViewCollection *collection);
-void gal_view_collection_save (GalViewCollection *collection);
-gboolean gal_view_collection_loaded (GalViewCollection *collection);
-
-/* Use factory list to load a GalView file. */
-GalView *gal_view_collection_load_view_from_file (GalViewCollection *collection,
- const char *type,
- const char *filename);
-
-/* Returns id of the new view. These functions are used for
- GalViewInstanceSaveAsDialog. */
-const char *gal_view_collection_append_with_title (GalViewCollection *collection,
- const char *title,
- GalView *view);
-const char *gal_view_collection_set_nth_view (GalViewCollection *collection,
- int i,
- GalView *view);
-
-const char *gal_view_collection_get_default_view (GalViewCollection *collection);
-void gal_view_collection_set_default_view (GalViewCollection *collection,
- const char *id);
-
-
-G_END_DECLS
-
-
-#endif /* _GAL_VIEW_COLLECTION_H_ */
diff --git a/widgets/menus/gal-view-etable.c b/widgets/menus/gal-view-etable.c
deleted file mode 100644
index a46368559e..0000000000
--- a/widgets/menus/gal-view-etable.c
+++ /dev/null
@@ -1,305 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * gal-view-etable.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include "gal-view-etable.h"
-#include <gal/e-table/e-table-config.h>
-
-#define PARENT_TYPE GAL_VIEW_TYPE
-
-static GalViewClass *gal_view_etable_parent_class;
-
-static void
-detach_table (GalViewEtable *view)
-{
- if (view->table == NULL)
- return;
- if (view->table_state_changed_id) {
- g_signal_handler_disconnect (view->table,
- view->table_state_changed_id);
- view->table_state_changed_id = 0;
- }
- g_object_unref (view->table);
- view->table = NULL;
-}
-
-static void
-detach_tree (GalViewEtable *view)
-{
- if (view->tree == NULL)
- return;
- if (view->tree_state_changed_id) {
- g_signal_handler_disconnect (view->tree,
- view->tree_state_changed_id);
- view->tree_state_changed_id = 0;
- }
- g_object_unref (view->tree);
- view->tree = NULL;
-}
-
-static void
-config_changed (ETableConfig *config, GalViewEtable *view)
-{
- ETableState *state;
- if (view->state)
- g_object_unref(view->state);
- g_object_get (config,
- "state", &state,
- NULL);
- view->state = e_table_state_duplicate(state);
- g_object_unref (state);
-
- gal_view_changed(GAL_VIEW(view));
-}
-
-static void
-gal_view_etable_edit (GalView *view, GtkWindow *parent)
-{
- GalViewEtable *etable_view = GAL_VIEW_ETABLE(view);
- ETableConfig *config;
-
- config = e_table_config_new(etable_view->title,
- etable_view->spec,
- etable_view->state,
- parent);
-
- g_signal_connect(config, "changed",
- G_CALLBACK(config_changed), view);
-}
-
-static void
-gal_view_etable_load (GalView *view,
- const char *filename)
-{
- e_table_state_load_from_file(GAL_VIEW_ETABLE(view)->state, filename);
-}
-
-static void
-gal_view_etable_save (GalView *view,
- const char *filename)
-{
- e_table_state_save_to_file(GAL_VIEW_ETABLE(view)->state, filename);
-}
-
-static const char *
-gal_view_etable_get_title (GalView *view)
-{
- return GAL_VIEW_ETABLE(view)->title;
-}
-
-static void
-gal_view_etable_set_title (GalView *view,
- const char *title)
-{
- g_free(GAL_VIEW_ETABLE(view)->title);
- GAL_VIEW_ETABLE(view)->title = g_strdup(title);
-}
-
-static const char *
-gal_view_etable_get_type_code (GalView *view)
-{
- return "etable";
-}
-
-static GalView *
-gal_view_etable_clone (GalView *view)
-{
- GalViewEtable *gve, *new;
-
- gve = GAL_VIEW_ETABLE(view);
-
- new = g_object_new (GAL_VIEW_ETABLE_TYPE, NULL);
- new->spec = gve->spec;
- new->title = g_strdup (gve->title);
- new->state = e_table_state_duplicate(gve->state);
-
- g_object_ref(new->spec);
-
- return GAL_VIEW(new);
-}
-
-static void
-gal_view_etable_dispose (GObject *object)
-{
- GalViewEtable *view = GAL_VIEW_ETABLE(object);
-
- gal_view_etable_detach (view);
-
- g_free(view->title);
- view->title = NULL;
-
- if (view->spec)
- g_object_unref(view->spec);
- view->spec = NULL;
-
- if (view->state)
- g_object_unref(view->state);
- view->state = NULL;
-
- if (G_OBJECT_CLASS (gal_view_etable_parent_class)->dispose)
- (* G_OBJECT_CLASS (gal_view_etable_parent_class)->dispose) (object);
-}
-
-static void
-gal_view_etable_class_init (GObjectClass *object_class)
-{
- GalViewClass *gal_view_class = GAL_VIEW_CLASS(object_class);
- gal_view_etable_parent_class = g_type_class_ref (PARENT_TYPE);
-
- gal_view_class->edit = gal_view_etable_edit ;
- gal_view_class->load = gal_view_etable_load ;
- gal_view_class->save = gal_view_etable_save ;
- gal_view_class->get_title = gal_view_etable_get_title ;
- gal_view_class->set_title = gal_view_etable_set_title ;
- gal_view_class->get_type_code = gal_view_etable_get_type_code;
- gal_view_class->clone = gal_view_etable_clone ;
-
- object_class->dispose = gal_view_etable_dispose ;
-}
-
-static void
-gal_view_etable_init (GalViewEtable *gve)
-{
- gve->spec = NULL;
- gve->state = e_table_state_new();
- gve->title = NULL;
-}
-
-E_MAKE_TYPE(gal_view_etable, "GalViewEtable", GalViewEtable, gal_view_etable_class_init, gal_view_etable_init, PARENT_TYPE)
-
-/**
- * gal_view_etable_new
- * @spec: The ETableSpecification that this view will be based upon.
- * @title: The name of the new view.
- *
- * Returns a new GalViewEtable. This is primarily for use by
- * GalViewFactoryEtable.
- *
- * Returns: The new GalViewEtable.
- */
-GalView *
-gal_view_etable_new (ETableSpecification *spec,
- const gchar *title)
-{
- return gal_view_etable_construct (g_object_new (GAL_VIEW_ETABLE_TYPE, NULL), spec, title);
-}
-
-/**
- * gal_view_etable_construct
- * @view: The view to construct.
- * @spec: The ETableSpecification that this view will be based upon.
- * @title: The name of the new view.
- *
- * constructs the GalViewEtable. To be used by subclasses and
- * language bindings.
- *
- * Returns: The GalViewEtable.
- */
-GalView *
-gal_view_etable_construct (GalViewEtable *view,
- ETableSpecification *spec,
- const gchar *title)
-{
- if (spec)
- g_object_ref(spec);
- view->spec = spec;
-
- if (view->state)
- g_object_unref(view->state);
- view->state = e_table_state_duplicate(spec->state);
-
- view->title = g_strdup(title);
-
- return GAL_VIEW(view);
-}
-
-void
-gal_view_etable_set_state (GalViewEtable *view, ETableState *state)
-{
- if (view->state)
- g_object_unref(view->state);
- view->state = e_table_state_duplicate(state);
-
- gal_view_changed(GAL_VIEW(view));
-}
-
-static void
-table_state_changed (ETable *table, GalViewEtable *view)
-{
- ETableState *state;
-
- state = e_table_get_state_object (table);
- g_object_unref (view->state);
- view->state = state;
-
- gal_view_changed(GAL_VIEW(view));
-}
-
-static void
-tree_state_changed (ETree *tree, GalViewEtable *view)
-{
- ETableState *state;
-
- state = e_tree_get_state_object (tree);
- g_object_unref (view->state);
- view->state = state;
-
- gal_view_changed(GAL_VIEW(view));
-}
-
-void
-gal_view_etable_attach_table (GalViewEtable *view, ETable *table)
-{
- gal_view_etable_detach (view);
-
- view->table = table;
-
- e_table_set_state_object(view->table, view->state);
- g_object_ref (view->table);
- view->table_state_changed_id =
- g_signal_connect(view->table, "state_change",
- G_CALLBACK (table_state_changed), view);
-}
-
-void
-gal_view_etable_attach_tree (GalViewEtable *view, ETree *tree)
-{
- gal_view_etable_detach (view);
-
- view->tree = tree;
-
- e_tree_set_state_object(view->tree, view->state);
- g_object_ref (view->tree);
- view->tree_state_changed_id =
- g_signal_connect(view->tree, "state_change",
- G_CALLBACK (tree_state_changed), view);
-}
-
-void
-gal_view_etable_detach (GalViewEtable *view)
-{
- if (view->table != NULL)
- detach_table (view);
- if (view->tree != NULL)
- detach_tree (view);
-}
diff --git a/widgets/menus/gal-view-etable.h b/widgets/menus/gal-view-etable.h
deleted file mode 100644
index 65879663fa..0000000000
--- a/widgets/menus/gal-view-etable.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * gal-view-etable.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _GAL_VIEW_ETABLE_H_
-#define _GAL_VIEW_ETABLE_H_
-
-#include <gtk/gtkobject.h>
-#include <gal/menus/gal-view.h>
-#include <gal/e-table/e-table-state.h>
-#include <gal/e-table/e-table-specification.h>
-#include <gal/e-table/e-table.h>
-#include <gal/e-table/e-tree.h>
-
-G_BEGIN_DECLS
-
-#define GAL_VIEW_ETABLE_TYPE (gal_view_etable_get_type ())
-#define GAL_VIEW_ETABLE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GAL_VIEW_ETABLE_TYPE, GalViewEtable))
-#define GAL_VIEW_ETABLE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GAL_VIEW_ETABLE_TYPE, GalViewEtableClass))
-#define GAL_IS_VIEW_ETABLE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GAL_VIEW_ETABLE_TYPE))
-#define GAL_IS_VIEW_ETABLE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GAL_VIEW_ETABLE_TYPE))
-
-typedef struct {
- GalView base;
-
- ETableSpecification *spec;
- ETableState *state;
- char *title;
-
- ETable *table;
- guint table_state_changed_id;
-
- ETree *tree;
- guint tree_state_changed_id;
-} GalViewEtable;
-
-typedef struct {
- GalViewClass parent_class;
-} GalViewEtableClass;
-
-/* Standard functions */
-GType gal_view_etable_get_type (void);
-GalView *gal_view_etable_new (ETableSpecification *spec,
- const gchar *title);
-GalView *gal_view_etable_construct (GalViewEtable *view,
- ETableSpecification *spec,
- const gchar *title);
-void gal_view_etable_set_state (GalViewEtable *view,
- ETableState *state);
-void gal_view_etable_attach_table (GalViewEtable *view,
- ETable *table);
-void gal_view_etable_attach_tree (GalViewEtable *view,
- ETree *tree);
-void gal_view_etable_detach (GalViewEtable *view);
-
-
-G_END_DECLS
-
-#endif /* _GAL_VIEW_ETABLE_H_ */
diff --git a/widgets/menus/gal-view-factory-etable.c b/widgets/menus/gal-view-factory-etable.c
deleted file mode 100644
index c0d68fe006..0000000000
--- a/widgets/menus/gal-view-factory-etable.c
+++ /dev/null
@@ -1,120 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * gal-view-factory-etable.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include "gal/util/e-i18n.h"
-#include "gal/util/e-util.h"
-#include "gal-view-factory-etable.h"
-#include "gal-view-etable.h"
-
-#define PARENT_TYPE GAL_VIEW_FACTORY_TYPE
-
-static GalViewFactoryClass *gal_view_factory_etable_parent_class;
-
-static const char *
-gal_view_factory_etable_get_title (GalViewFactory *factory)
-{
- return _("Table");
-}
-
-static GalView *
-gal_view_factory_etable_new_view (GalViewFactory *factory,
- const char *name)
-{
- return gal_view_etable_new(GAL_VIEW_FACTORY_ETABLE(factory)->spec, name);
-}
-
-static const char *
-gal_view_factory_etable_get_type_code (GalViewFactory *factory)
-{
- return "etable";
-}
-
-static void
-gal_view_factory_etable_dispose (GObject *object)
-{
- GalViewFactoryEtable *factory = GAL_VIEW_FACTORY_ETABLE(object);
-
- if (factory->spec)
- g_object_unref(factory->spec);
- factory->spec = NULL;
-
- if (G_OBJECT_CLASS (gal_view_factory_etable_parent_class)->dispose)
- (* G_OBJECT_CLASS (gal_view_factory_etable_parent_class)->dispose) (object);
-}
-
-static void
-gal_view_factory_etable_class_init (GObjectClass *object_class)
-{
- GalViewFactoryClass *view_factory_class = GAL_VIEW_FACTORY_CLASS(object_class);
- gal_view_factory_etable_parent_class = g_type_class_ref (PARENT_TYPE);
-
- view_factory_class->get_title = gal_view_factory_etable_get_title;
- view_factory_class->new_view = gal_view_factory_etable_new_view;
- view_factory_class->get_type_code = gal_view_factory_etable_get_type_code;
-
- object_class->dispose = gal_view_factory_etable_dispose;
-}
-
-static void
-gal_view_factory_etable_init (GalViewFactoryEtable *factory)
-{
- factory->spec = NULL;
-}
-
-/**
- * gal_view_etable_new
- * @spec: The spec to create GalViewEtables based upon.
- *
- * A new GalViewFactory for creating ETable views. Create one of
- * these and pass it to GalViewCollection for use.
- *
- * Returns: The new GalViewFactoryEtable.
- */
-GalViewFactory *
-gal_view_factory_etable_new (ETableSpecification *spec)
-{
- return gal_view_factory_etable_construct (g_object_new (GAL_VIEW_FACTORY_ETABLE_TYPE, NULL), spec);
-}
-
-/**
- * gal_view_etable_construct
- * @factory: The factory to construct
- * @spec: The spec to create GalViewEtables based upon.
- *
- * constructs the GalViewFactoryEtable. To be used by subclasses and
- * language bindings.
- *
- * Returns: The GalViewFactoryEtable.
- */
-GalViewFactory *
-gal_view_factory_etable_construct (GalViewFactoryEtable *factory,
- ETableSpecification *spec)
-{
- if (spec)
- g_object_ref(spec);
- factory->spec = spec;
- return GAL_VIEW_FACTORY(factory);
-}
-
-E_MAKE_TYPE(gal_view_factory_etable, "GalViewFactoryEtable", GalViewFactoryEtable, gal_view_factory_etable_class_init, gal_view_factory_etable_init, PARENT_TYPE)
diff --git a/widgets/menus/gal-view-factory-etable.h b/widgets/menus/gal-view-factory-etable.h
deleted file mode 100644
index 542aa255fc..0000000000
--- a/widgets/menus/gal-view-factory-etable.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * gal-view-factory-etable.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _GAL_VIEW_FACTORY_ETABLE_H_
-#define _GAL_VIEW_FACTORY_ETABLE_H_
-
-#include <gtk/gtkobject.h>
-#include <gal/menus/gal-view-factory.h>
-#include <gal/e-table/e-table-specification.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-#define GAL_VIEW_FACTORY_ETABLE_TYPE (gal_view_factory_etable_get_type ())
-#define GAL_VIEW_FACTORY_ETABLE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GAL_VIEW_FACTORY_ETABLE_TYPE, GalViewFactoryEtable))
-#define GAL_VIEW_FACTORY_ETABLE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GAL_VIEW_FACTORY_ETABLE_TYPE, GalViewFactoryEtableClass))
-#define GAL_IS_VIEW_FACTORY_ETABLE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GAL_VIEW_FACTORY_ETABLE_TYPE))
-#define GAL_IS_VIEW_FACTORY_ETABLE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GAL_VIEW_FACTORY_ETABLE_TYPE))
-#define GAL_VIEW_FACTORY_ETABLE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GAL_VIEW_FACTORY_ETABLE_TYPE, GalViewFactoryEtableClass))
-
-typedef struct {
- GalViewFactory base;
-
- ETableSpecification *spec;
-} GalViewFactoryEtable;
-
-typedef struct {
- GalViewFactoryClass parent_class;
-} GalViewFactoryEtableClass;
-
-/* Standard functions */
-GType gal_view_factory_etable_get_type (void);
-GalViewFactory *gal_view_factory_etable_new (ETableSpecification *spec);
-GalViewFactory *gal_view_factory_etable_construct (GalViewFactoryEtable *factory,
- ETableSpecification *spec);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* _GAL_VIEW_FACTORY_ETABLE_H_ */
diff --git a/widgets/menus/gal-view-factory.c b/widgets/menus/gal-view-factory.c
deleted file mode 100644
index 5bc2c9f11d..0000000000
--- a/widgets/menus/gal-view-factory.c
+++ /dev/null
@@ -1,107 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * gal-view-factory.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include "gal-view-factory.h"
-#include "gal/util/e-util.h"
-
-#define PARENT_TYPE G_TYPE_OBJECT
-
-#define d(x)
-
-d(static gint depth = 0;)
-
-static GObjectClass *gal_view_factory_parent_class;
-
-/**
- * gal_view_factory_get_title:
- * @factory: The factory to query.
- *
- * Returns: The title of the factory.
- */
-const char *
-gal_view_factory_get_title (GalViewFactory *factory)
-{
- g_return_val_if_fail (factory != NULL, 0);
- g_return_val_if_fail (GAL_IS_VIEW_FACTORY (factory), 0);
-
- if (GAL_VIEW_FACTORY_GET_CLASS (factory)->get_title)
- return GAL_VIEW_FACTORY_GET_CLASS (factory)->get_title (factory);
- else
- return NULL;
-}
-
-/**
- * gal_view_factory_new_view:
- * @factory: The factory to use
- * @name: the name for the view.
- *
- * Returns: The new view
- */
-GalView *
-gal_view_factory_new_view (GalViewFactory *factory,
- const char *name)
-{
- g_return_val_if_fail (factory != NULL, NULL);
- g_return_val_if_fail (GAL_IS_VIEW_FACTORY (factory), NULL);
-
- if (GAL_VIEW_FACTORY_GET_CLASS (factory)->new_view)
- return GAL_VIEW_FACTORY_GET_CLASS (factory)->new_view (factory, name);
- else
- return NULL;
-}
-
-/**
- * gal_view_factory_get_type_code:
- * @factory: The factory to use
- *
- * Returns: The type code
- */
-const char *
-gal_view_factory_get_type_code (GalViewFactory *factory)
-{
- g_return_val_if_fail (factory != NULL, NULL);
- g_return_val_if_fail (GAL_IS_VIEW_FACTORY (factory), NULL);
-
- if (GAL_VIEW_FACTORY_GET_CLASS (factory)->get_type_code)
- return GAL_VIEW_FACTORY_GET_CLASS (factory)->get_type_code (factory);
- else
- return NULL;
-}
-
-static void
-gal_view_factory_class_init (GObjectClass *object_class)
-{
- GalViewFactoryClass *klass = GAL_VIEW_FACTORY_CLASS(object_class);
- gal_view_factory_parent_class = g_type_class_ref (PARENT_TYPE);
-
- klass->get_title = NULL;
- klass->new_view = NULL;
-}
-
-static void
-gal_view_factory_init (GalViewFactory *factory)
-{
-}
-
-E_MAKE_TYPE(gal_view_factory, "GalViewFactory", GalViewFactory, gal_view_factory_class_init, gal_view_factory_init, PARENT_TYPE)
diff --git a/widgets/menus/gal-view-factory.h b/widgets/menus/gal-view-factory.h
deleted file mode 100644
index 5fff83e048..0000000000
--- a/widgets/menus/gal-view-factory.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * gal-view-factory.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _GAL_VIEW_FACTORY_H_
-#define _GAL_VIEW_FACTORY_H_
-
-#include <gtk/gtkobject.h>
-#include <gal/menus/gal-view.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-#define GAL_VIEW_FACTORY_TYPE (gal_view_factory_get_type ())
-#define GAL_VIEW_FACTORY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GAL_VIEW_FACTORY_TYPE, GalViewFactory))
-#define GAL_VIEW_FACTORY_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GAL_VIEW_FACTORY_TYPE, GalViewFactoryClass))
-#define GAL_IS_VIEW_FACTORY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GAL_VIEW_FACTORY_TYPE))
-#define GAL_IS_VIEW_FACTORY_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GAL_VIEW_FACTORY_TYPE))
-#define GAL_VIEW_FACTORY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GAL_VIEW_FACTORY_TYPE, GalViewFactoryClass))
-
-typedef struct {
- GObject base;
-} GalViewFactory;
-
-typedef struct {
- GObjectClass parent_class;
-
- /*
- * Virtual methods
- */
- const char *(*get_title) (GalViewFactory *factory);
- const char *(*get_type_code) (GalViewFactory *factory);
- GalView *(*new_view) (GalViewFactory *factory,
- const char *name);
-} GalViewFactoryClass;
-
-/* Standard functions */
-GType gal_view_factory_get_type (void);
-
-/* Query functions */
-/* Returns already translated title. */
-const char *gal_view_factory_get_title (GalViewFactory *factory);
-
-/* Returns the code for use in identifying this type of object in the
- * view list. This identifier should identify this as being the
- * unique factory for xml files which were written out with this
- * identifier. Thus each factory should have a unique type code. */
-const char *gal_view_factory_get_type_code (GalViewFactory *factory);
-
-/* Create a new view */
-GalView *gal_view_factory_new_view (GalViewFactory *factory,
- const char *name);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-
-#endif /* _GAL_VIEW_FACTORY_H_ */
diff --git a/widgets/menus/gal-view-instance-save-as-dialog.c b/widgets/menus/gal-view-instance-save-as-dialog.c
deleted file mode 100644
index b65d4acba2..0000000000
--- a/widgets/menus/gal-view-instance-save-as-dialog.c
+++ /dev/null
@@ -1,307 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * gal-define-views-dialog.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-
-#include "gal-view-instance-save-as-dialog.h"
-
-#include "gal-define-views-model.h"
-#include "gal-view-new-dialog.h"
-#include <gal/e-table/e-table-scrolled.h>
-#include <gal/util/e-i18n.h>
-#include <gtk/gtkentry.h>
-#include <gtk/gtktogglebutton.h>
-#include <gtk/gtkbox.h>
-#include <gtk/gtkstock.h>
-
-static GtkDialogClass *parent_class = NULL;
-#define PARENT_TYPE GTK_TYPE_DIALOG
-
-/* The arguments we take */
-enum {
- PROP_0,
- PROP_INSTANCE,
-};
-
-typedef struct {
- char *title;
- ETableModel *model;
- GalViewInstanceSaveAsDialog *names;
-} GalViewInstanceSaveAsDialogChild;
-
-
-/* Static functions */
-static void
-gal_view_instance_save_as_dialog_set_instance(GalViewInstanceSaveAsDialog *dialog,
- GalViewInstance *instance)
-{
- dialog->instance = instance;
- if (dialog->model) {
- GtkWidget *table;
- g_object_set(dialog->model,
- "collection", instance ? instance->collection : NULL,
- NULL);
- table = glade_xml_get_widget(dialog->gui, "custom-replace");
- if (table) {
- ETable *etable;
- etable = e_table_scrolled_get_table (E_TABLE_SCROLLED (table));
- e_selection_model_select_single_row (e_table_get_selection_model (etable), 0);
- e_selection_model_change_cursor (e_table_get_selection_model (etable), 0, 0);
- }
- }
-}
-
-static void
-gvisad_setup_radio_buttons (GalViewInstanceSaveAsDialog *dialog)
-{
- GtkWidget *radio_replace = glade_xml_get_widget (dialog->gui, "radiobutton-replace");
- GtkWidget *radio_create = glade_xml_get_widget (dialog->gui, "radiobutton-create" );
- GtkWidget *widget;
-
- widget = glade_xml_get_widget (dialog->gui, "custom-replace");
- if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (radio_replace))) {
- gtk_widget_set_sensitive (widget, TRUE);
- dialog->toggle = GAL_VIEW_INSTANCE_SAVE_AS_DIALOG_TOGGLE_REPLACE;
- } else {
- gtk_widget_set_sensitive (widget, FALSE);
- }
-
- widget = glade_xml_get_widget (dialog->gui, "entry-create");
- if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (radio_create))) {
- gtk_widget_set_sensitive (widget, TRUE);
- dialog->toggle = GAL_VIEW_INSTANCE_SAVE_AS_DIALOG_TOGGLE_CREATE;
- } else {
- gtk_widget_set_sensitive (widget, FALSE);
- }
-}
-
-static void
-gvisad_radio_toggled (GtkWidget *widget, GalViewInstanceSaveAsDialog *dialog)
-{
- gvisad_setup_radio_buttons (dialog);
-}
-
-static void
-gvisad_connect_signal(GalViewInstanceSaveAsDialog *dialog, char *widget_name, char *signal, GCallback handler)
-{
- GtkWidget *widget;
-
- widget = glade_xml_get_widget(dialog->gui, widget_name);
-
- if (widget)
- g_signal_connect (G_OBJECT (widget), signal, handler, dialog);
-}
-
-/* Method override implementations */
-static void
-gal_view_instance_save_as_dialog_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
-{
- GalViewInstanceSaveAsDialog *dialog;
-
- dialog = GAL_VIEW_INSTANCE_SAVE_AS_DIALOG (object);
-
- switch (prop_id){
- case PROP_INSTANCE:
- if (g_value_get_object (value))
- gal_view_instance_save_as_dialog_set_instance(dialog, GAL_VIEW_INSTANCE(g_value_get_object (value)));
- else
- gal_view_instance_save_as_dialog_set_instance(dialog, NULL);
- break;
-
- default:
- return;
- }
-}
-
-static void
-gal_view_instance_save_as_dialog_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
-{
- GalViewInstanceSaveAsDialog *dialog;
-
- dialog = GAL_VIEW_INSTANCE_SAVE_AS_DIALOG (object);
-
- switch (prop_id) {
- case PROP_INSTANCE:
- g_value_set_object (value, dialog->instance);
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-gal_view_instance_save_as_dialog_dispose (GObject *object)
-{
- GalViewInstanceSaveAsDialog *gal_view_instance_save_as_dialog = GAL_VIEW_INSTANCE_SAVE_AS_DIALOG(object);
-
- if (gal_view_instance_save_as_dialog->gui)
- g_object_unref(gal_view_instance_save_as_dialog->gui);
- gal_view_instance_save_as_dialog->gui = NULL;
-
- if (G_OBJECT_CLASS (parent_class)->dispose)
- (* G_OBJECT_CLASS (parent_class)->dispose) (object);
-}
-
-/* Init functions */
-static void
-gal_view_instance_save_as_dialog_class_init (GalViewInstanceSaveAsDialogClass *klass)
-{
- GObjectClass *object_class;
-
- object_class = (GObjectClass*) klass;
-
- parent_class = g_type_class_ref (PARENT_TYPE);
-
- object_class->set_property = gal_view_instance_save_as_dialog_set_property;
- object_class->get_property = gal_view_instance_save_as_dialog_get_property;
- object_class->dispose = gal_view_instance_save_as_dialog_dispose;
-
- g_object_class_install_property (object_class, PROP_INSTANCE,
- g_param_spec_object ("instance",
- _("Instance"),
- /*_( */"XXX blurb" /*)*/,
- GAL_VIEW_INSTANCE_TYPE,
- G_PARAM_READWRITE));
-}
-
-static void
-gal_view_instance_save_as_dialog_init (GalViewInstanceSaveAsDialog *dialog)
-{
- GladeXML *gui;
- GtkWidget *widget;
- GtkWidget *table;
-
- dialog->instance = NULL;
-
- gui = glade_xml_new_with_domain (GAL_GLADEDIR "/gal-view-instance-save-as-dialog.glade", NULL, E_I18N_DOMAIN);
- dialog->gui = gui;
-
- widget = glade_xml_get_widget(gui, "vbox-top");
- if (!widget) {
- return;
- }
- gtk_widget_ref(widget);
- gtk_container_remove (GTK_CONTAINER (widget->parent), widget);
- gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), widget, TRUE, TRUE, 0);
- gtk_widget_unref(widget);
-
- gtk_dialog_add_buttons (GTK_DIALOG (dialog),
- GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
- GTK_STOCK_OK, GTK_RESPONSE_OK,
- NULL);
-
- gvisad_connect_signal(dialog, "radiobutton-replace", "toggled", G_CALLBACK(gvisad_radio_toggled));
- gvisad_connect_signal(dialog, "radiobutton-create", "toggled", G_CALLBACK(gvisad_radio_toggled));
-
- dialog->model = NULL;
- table = glade_xml_get_widget(dialog->gui, "custom-replace");
- if (table) {
- dialog->model = g_object_get_data(G_OBJECT (table), "GalViewInstanceSaveAsDialog::model");
-
- gal_view_instance_save_as_dialog_set_instance (dialog, dialog->instance);
- gtk_widget_show_all (table);
- }
-
- gvisad_setup_radio_buttons (dialog);
- gtk_window_set_policy(GTK_WINDOW(dialog), FALSE, TRUE, FALSE);
- gtk_window_set_title (GTK_WINDOW (dialog), _("Save Current View"));
-}
-
-
-/* For use from libglade. */
-/* ETable creation */
-#define SPEC "<ETableSpecification no-headers=\"true\" cursor-mode=\"line\" draw-grid=\"false\" selection-mode=\"single\" gettext-domain=\"" E_I18N_DOMAIN "\">" \
- "<ETableColumn model_col= \"0\" _title=\"Name\" expansion=\"1.0\" minimum_width=\"18\" resizable=\"true\" cell=\"string\" compare=\"string\"/>" \
- "<ETableState> <column source=\"0\"/> <grouping> </grouping> </ETableState>" \
- "</ETableSpecification>"
-
-GtkWidget *gal_view_instance_save_as_dialog_create_etable(char *name, char *string1, char *string2, int int1, int int2);
-
-GtkWidget *
-gal_view_instance_save_as_dialog_create_etable(char *name, char *string1, char *string2, int int1, int int2)
-{
- GtkWidget *table;
- ETableModel *model;
- model = gal_define_views_model_new ();
- table = e_table_scrolled_new(model, NULL, SPEC, NULL);
- g_object_set_data(G_OBJECT (table), "GalViewInstanceSaveAsDialog::model", model);
-
- return table;
-}
-
-/* External methods */
-/**
- * gal_view_instance_save_as_dialog_new
- *
- * Returns a new dialog for defining views.
- *
- * Returns: The GalViewInstanceSaveAsDialog.
- */
-GtkWidget*
-gal_view_instance_save_as_dialog_new (GalViewInstance *instance)
-{
- GtkWidget *widget = g_object_new (GAL_VIEW_INSTANCE_SAVE_AS_DIALOG_TYPE, NULL);
- gal_view_instance_save_as_dialog_set_instance(GAL_VIEW_INSTANCE_SAVE_AS_DIALOG (widget), instance);
- return widget;
-}
-
-E_MAKE_TYPE(gal_view_instance_save_as_dialog, "GalViewInstanceSaveAsDialog",
- GalViewInstanceSaveAsDialog,
- gal_view_instance_save_as_dialog_class_init,
- gal_view_instance_save_as_dialog_init, PARENT_TYPE)
-
-void
-gal_view_instance_save_as_dialog_save (GalViewInstanceSaveAsDialog *dialog)
-{
- GalView *view = gal_view_instance_get_current_view (dialog->instance);
- GtkWidget *widget;
- const char *title;
- int n;
- const char *id = NULL;
-
- view = gal_view_clone (view);
- switch (dialog->toggle) {
- case GAL_VIEW_INSTANCE_SAVE_AS_DIALOG_TOGGLE_REPLACE:
- widget = glade_xml_get_widget(dialog->gui, "custom-replace");
- if (widget && E_IS_TABLE_SCROLLED (widget)) {
- n = e_table_get_cursor_row (e_table_scrolled_get_table (E_TABLE_SCROLLED (widget)));
- id = gal_view_collection_set_nth_view (dialog->instance->collection, n, view);
- gal_view_collection_save (dialog->instance->collection);
- }
- break;
- case GAL_VIEW_INSTANCE_SAVE_AS_DIALOG_TOGGLE_CREATE:
- widget = glade_xml_get_widget(dialog->gui, "entry-create");
- if (widget && GTK_IS_ENTRY (widget)) {
- title = gtk_entry_get_text (GTK_ENTRY (widget));
- id = gal_view_collection_append_with_title (dialog->instance->collection, title, view);
- gal_view_collection_save (dialog->instance->collection);
- }
- break;
- }
-
- if (id) {
- gal_view_instance_set_current_view_id (dialog->instance, id);
- }
-}
diff --git a/widgets/menus/gal-view-instance-save-as-dialog.glade b/widgets/menus/gal-view-instance-save-as-dialog.glade
deleted file mode 100644
index 54776827a0..0000000000
--- a/widgets/menus/gal-view-instance-save-as-dialog.glade
+++ /dev/null
@@ -1,260 +0,0 @@
-<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
-<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
-
-<glade-interface>
-<requires lib="gnome"/>
-
-<widget class="GtkDialog" id="dialog1">
- <property name="title" translatable="yes"></property>
- <property name="type">GTK_WINDOW_TOPLEVEL</property>
- <property name="window_position">GTK_WIN_POS_NONE</property>
- <property name="modal">False</property>
- <property name="resizable">True</property>
- <property name="destroy_with_parent">False</property>
- <property name="decorated">True</property>
- <property name="skip_taskbar_hint">False</property>
- <property name="skip_pager_hint">False</property>
- <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
- <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
- <property name="has_separator">True</property>
-
- <child internal-child="vbox">
- <widget class="GtkVBox" id="dialog-vbox1">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">8</property>
-
- <child internal-child="action_area">
- <widget class="GtkHButtonBox" id="dialog-action_area1">
- <property name="visible">True</property>
- <property name="layout_style">GTK_BUTTONBOX_END</property>
-
- <child>
- <widget class="GtkButton" id="button1">
- <property name="visible">True</property>
- <property name="can_default">True</property>
- <property name="can_focus">True</property>
- <property name="label">gtk-ok</property>
- <property name="use_stock">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="response_id">0</property>
- </widget>
- </child>
-
- <child>
- <widget class="GtkButton" id="button3">
- <property name="visible">True</property>
- <property name="can_default">True</property>
- <property name="can_focus">True</property>
- <property name="label">gtk-cancel</property>
- <property name="use_stock">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="response_id">0</property>
- </widget>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="pack_type">GTK_PACK_END</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkVBox" id="vbox-top">
- <property name="border_width">18</property>
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">12</property>
-
- <child>
- <widget class="GtkVBox" id="vbox2">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="GtkRadioButton" id="radiobutton-create">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">_Create new view</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">True</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkHBox" id="hbox1">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="GtkLabel" id="label9">
- <property name="visible">True</property>
- <property name="label" translatable="yes"> </property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label8">
- <property name="visible">True</property>
- <property name="label" translatable="yes">_Name:</property>
- <property name="use_underline">True</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- <property name="mnemonic_widget">entry-create</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkEntry" id="entry-create">
- <property name="visible">True</property>
- <property name="sensitive">False</property>
- <property name="can_focus">True</property>
- <property name="editable">True</property>
- <property name="visibility">True</property>
- <property name="max_length">0</property>
- <property name="text" translatable="yes"></property>
- <property name="has_frame">True</property>
- <property name="invisible_char" translatable="yes">*</property>
- <property name="activates_default">False</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkRadioButton" id="radiobutton-replace">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">_Replace existing view</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- <property name="group">radiobutton-create</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkHBox" id="hbox2">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="GtkLabel" id="label10">
- <property name="visible">True</property>
- <property name="label" translatable="yes"> </property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="Custom" id="custom-replace">
- <property name="visible">True</property>
- <property name="creation_function">gal_view_instance_save_as_dialog_create_etable</property>
- <property name="int1">0</property>
- <property name="int2">0</property>
- <property name="last_modification_time">Fri, 01 Feb 2002 20:18:32 GMT</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- </child>
-</widget>
-
-</glade-interface>
diff --git a/widgets/menus/gal-view-instance-save-as-dialog.h b/widgets/menus/gal-view-instance-save-as-dialog.h
deleted file mode 100644
index 53d99d0789..0000000000
--- a/widgets/menus/gal-view-instance-save-as-dialog.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * gal-define-views-dialog.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef __GAL_VIEW_INSTANCE_SAVE_AS_DIALOG_H__
-#define __GAL_VIEW_INSTANCE_SAVE_AS_DIALOG_H__
-
-#include <gtk/gtkdialog.h>
-#include <glade/glade.h>
-#include <gal/e-table/e-table-model.h>
-#include <gal/menus/gal-view-collection.h>
-#include <gal/menus/gal-view-instance.h>
-
-#ifdef __cplusplus
-extern "C" {
-#pragma }
-#endif /* __cplusplus */
-
-/* GalViewInstanceSaveAsDialog - A dialog displaying information about a contact.
- *
- * The following arguments are available:
- *
- * name type read/write description
- * --------------------------------------------------------------------------------
- */
-
-#define GAL_VIEW_INSTANCE_SAVE_AS_DIALOG_TYPE (gal_view_instance_save_as_dialog_get_type ())
-#define GAL_VIEW_INSTANCE_SAVE_AS_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_VIEW_INSTANCE_SAVE_AS_DIALOG_TYPE, GalViewInstanceSaveAsDialog))
-#define GAL_VIEW_INSTANCE_SAVE_AS_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_VIEW_INSTANCE_SAVE_AS_DIALOG_TYPE, GalViewInstanceSaveAsDialogClass))
-#define GAL_IS_VIEW_INSTANCE_SAVE_AS_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_VIEW_INSTANCE_SAVE_AS_DIALOG_TYPE))
-#define GAL_IS_VIEW_INSTANCE_SAVE_AS_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), GAL_VIEW_INSTANCE_SAVE_AS_DIALOG_TYPE))
-
-typedef struct _GalViewInstanceSaveAsDialog GalViewInstanceSaveAsDialog;
-typedef struct _GalViewInstanceSaveAsDialogClass GalViewInstanceSaveAsDialogClass;
-
-typedef enum {
- GAL_VIEW_INSTANCE_SAVE_AS_DIALOG_TOGGLE_REPLACE,
- GAL_VIEW_INSTANCE_SAVE_AS_DIALOG_TOGGLE_CREATE
-} GalViewInstanceSaveAsDialogToggle;
-
-struct _GalViewInstanceSaveAsDialog
-{
- GtkDialog parent;
-
- /* item specific fields */
- GladeXML *gui;
- ETableModel *model;
-
- GalViewInstance *instance;
- GalViewCollection *collection;
-
- GalViewInstanceSaveAsDialogToggle toggle;
-};
-
-struct _GalViewInstanceSaveAsDialogClass
-{
- GtkDialogClass parent_class;
-};
-
-GtkWidget *gal_view_instance_save_as_dialog_new (GalViewInstance *instance);
-GType gal_view_instance_save_as_dialog_get_type (void);
-
-void gal_view_instance_save_as_dialog_save (GalViewInstanceSaveAsDialog *dialog);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-
-#endif /* __GAL_VIEW_INSTANCE_SAVE_AS_DIALOG_H__ */
diff --git a/widgets/menus/gal-view-instance.c b/widgets/menus/gal-view-instance.c
deleted file mode 100644
index 6ce8a2ab86..0000000000
--- a/widgets/menus/gal-view-instance.c
+++ /dev/null
@@ -1,599 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * gal-view-instance.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-
-#include <util/e-i18n.h>
-#include <ctype.h>
-#include <string.h>
-#include <errno.h>
-#include <libxml/parser.h>
-#include <libgnome/gnome-util.h>
-#include <gal/util/e-util.h>
-#include <gal/util/e-xml-utils.h>
-#include <gal/widgets/e-unicode.h>
-#include "gal-view-instance.h"
-#include "gal-view-instance-save-as-dialog.h"
-#include "gal-define-views-dialog.h"
-#include <sys/stat.h>
-#include <unistd.h>
-#include <gtk/gtkcheckmenuitem.h>
-
-#define PARENT_TYPE G_TYPE_OBJECT
-
-static GObjectClass *gal_view_instance_parent_class;
-
-static const EPopupMenu separator = E_POPUP_SEPARATOR;
-static const EPopupMenu terminator = E_POPUP_TERMINATOR;
-
-
-#define d(x)
-
-enum {
- DISPLAY_VIEW,
- CHANGED,
- LAST_SIGNAL
-};
-
-static guint gal_view_instance_signals [LAST_SIGNAL] = { 0, };
-
-static void
-gal_view_instance_changed (GalViewInstance *instance)
-{
- g_return_if_fail (instance != NULL);
- g_return_if_fail (GAL_IS_VIEW_INSTANCE (instance));
-
- g_signal_emit (instance,
- gal_view_instance_signals [CHANGED], 0);
-}
-
-static void
-gal_view_instance_display_view (GalViewInstance *instance, GalView *view)
-{
- g_return_if_fail (instance != NULL);
- g_return_if_fail (GAL_IS_VIEW_INSTANCE (instance));
-
- g_signal_emit (instance,
- gal_view_instance_signals [DISPLAY_VIEW], 0,
- view);
-}
-
-static void
-save_current_view (GalViewInstance *instance)
-{
- xmlDoc *doc;
- xmlNode *root;
-
- doc = xmlNewDoc("1.0");
- root = xmlNewNode (NULL, "GalViewCurrentView");
- xmlDocSetRootElement(doc, root);
-
- if (instance->current_id)
- e_xml_set_string_prop_by_name (root, "current_view", instance->current_id);
- if (instance->current_type)
- e_xml_set_string_prop_by_name (root, "current_view_type", instance->current_type);
-
- if (e_xml_save_file (instance->current_view_filename, doc) == -1)
- g_warning ("Unable to save view to %s - %s", instance->current_view_filename, g_strerror(errno));
- xmlFreeDoc(doc);
-}
-
-static void
-view_changed (GalView *view, GalViewInstance *instance)
-{
- if (instance->current_id != NULL) {
- g_free (instance->current_id);
- instance->current_id = NULL;
- save_current_view (instance);
- gal_view_instance_changed(instance);
- }
-
- gal_view_save (view, instance->custom_filename);
-}
-
-static void
-disconnect_view (GalViewInstance *instance)
-{
- if (instance->current_view) {
- if (instance->view_changed_id) {
- g_signal_handler_disconnect (instance->current_view,
- instance->view_changed_id);
- }
-
- g_object_unref (instance->current_view);
- }
- g_free (instance->current_type);
- g_free (instance->current_title);
- instance->current_title = NULL;
- instance->current_type = NULL;
- instance->view_changed_id = 0;
- instance->current_view = NULL;
-}
-
-static void
-connect_view (GalViewInstance *instance, GalView *view)
-{
- if (instance->current_view)
- disconnect_view (instance);
- instance->current_view = view;
-
- instance->current_title = g_strdup (gal_view_get_title(view));
- instance->current_type = g_strdup (gal_view_get_type_code(view));
- instance->view_changed_id =
- g_signal_connect(instance->current_view, "changed",
- G_CALLBACK (view_changed), instance);
-
- gal_view_instance_display_view (instance, instance->current_view);
-}
-
-static void
-gal_view_instance_dispose (GObject *object)
-{
- GalViewInstance *instance = GAL_VIEW_INSTANCE(object);
-
- if (instance->collection) {
- if (instance->collection_changed_id) {
- g_signal_handler_disconnect (instance->collection,
- instance->collection_changed_id);
- }
- g_object_unref (instance->collection);
- }
-
- g_free (instance->instance_id);
- g_free (instance->custom_filename);
- g_free (instance->current_view_filename);
-
- g_free (instance->current_id);
- disconnect_view (instance);
-
- g_free (instance->default_view);
-
- if (gal_view_instance_parent_class->dispose)
- (*gal_view_instance_parent_class->dispose)(object);
-}
-
-static void
-gal_view_instance_class_init (GObjectClass *object_class)
-{
- GalViewInstanceClass *klass = GAL_VIEW_INSTANCE_CLASS(object_class);
- gal_view_instance_parent_class = g_type_class_ref (PARENT_TYPE);
-
- object_class->dispose = gal_view_instance_dispose;
-
- gal_view_instance_signals [DISPLAY_VIEW] =
- g_signal_new ("display_view",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GalViewInstanceClass, display_view),
- NULL, NULL,
- g_cclosure_marshal_VOID__OBJECT,
- G_TYPE_NONE, 1, GAL_VIEW_TYPE);
-
- gal_view_instance_signals [CHANGED] =
- g_signal_new ("changed",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GalViewInstanceClass, changed),
- NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
-
- klass->display_view = NULL;
- klass->changed = NULL;
-}
-
-static void
-gal_view_instance_init (GalViewInstance *instance)
-{
- instance->collection = NULL;
-
- instance->instance_id = NULL;
- instance->custom_filename = NULL;
- instance->current_view_filename = NULL;
-
- instance->current_title = NULL;
- instance->current_type = NULL;
- instance->current_id = NULL;
- instance->current_view = NULL;
-
- instance->view_changed_id = 0;
- instance->collection_changed_id = 0;
-
- instance->loaded = FALSE;
- instance->default_view = NULL;
-}
-
-E_MAKE_TYPE(gal_view_instance, "GalViewInstance", GalViewInstance, gal_view_instance_class_init, gal_view_instance_init, PARENT_TYPE)
-
-static void
-collection_changed (GalView *view, GalViewInstance *instance)
-{
- if (instance->current_id) {
- char *view_id = instance->current_id;
- instance->current_id = NULL;
- gal_view_instance_set_current_view_id (instance, view_id);
- g_free (view_id);
- }
-}
-
-static void
-load_current_view (GalViewInstance *instance)
-{
- xmlDoc *doc = NULL;
- xmlNode *root;
- GalView *view = NULL;
- struct stat st;
-
- if (stat (instance->current_view_filename, &st) != -1 && S_ISREG (st.st_mode))
- doc = xmlParseFile(instance->current_view_filename);
-
- if (doc == NULL) {
- instance->current_id = g_strdup (gal_view_instance_get_default_view (instance));
-
- if (instance->current_id) {
- int index = gal_view_collection_get_view_index_by_id (instance->collection,
- instance->current_id);
-
- if (index != -1) {
- view = gal_view_collection_get_view (instance->collection,
- index);
- view = gal_view_clone(view);
- connect_view (instance, view);
- }
- }
- return;
- }
-
- root = xmlDocGetRootElement(doc);
- instance->current_id = e_xml_get_string_prop_by_name_with_default (root, "current_view", NULL);
-
- if (instance->current_id != NULL) {
- int index = gal_view_collection_get_view_index_by_id (instance->collection,
- instance->current_id);
-
- if (index != -1) {
- view = gal_view_collection_get_view (instance->collection,
- index);
- view = gal_view_clone(view);
- }
- }
- if (view == NULL) {
- char *type;
- type = e_xml_get_string_prop_by_name_with_default (root, "current_view_type", NULL);
- view = gal_view_collection_load_view_from_file (instance->collection,
- type,
- instance->custom_filename);
- g_free (type);
- }
-
- connect_view (instance, view);
-
- xmlFreeDoc(doc);
-}
-
-/**
- * gal_view_instance_new:
- * @collection: This %GalViewCollection should be loaded before being passed to this function.
- * @instance_id: Which instance of this type of object is this (for most of evo, this is the folder id.)
- *
- * Create a new %GalViewInstance.
- *
- * Return value: The new %GalViewInstance.
- **/
-GalViewInstance *
-gal_view_instance_new (GalViewCollection *collection, const char *instance_id)
-{
- GalViewInstance *instance = g_object_new (GAL_VIEW_INSTANCE_TYPE, NULL);
- if (gal_view_instance_construct (instance, collection, instance_id))
- return instance;
- else {
- g_object_unref (instance);
- return NULL;
- }
-}
-
-GalViewInstance *
-gal_view_instance_construct (GalViewInstance *instance, GalViewCollection *collection, const char *instance_id)
-{
- char *filename;
- char *safe_id;
-
- g_return_val_if_fail (gal_view_collection_loaded (collection), NULL);
-
- instance->collection = collection;
- if (collection)
- g_object_ref (collection);
- instance->collection_changed_id =
- g_signal_connect (collection, "changed",
- G_CALLBACK (collection_changed), instance);
-
- if (instance_id)
- instance->instance_id = g_strdup (instance_id);
- else
- instance->instance_id = g_strdup ("");
-
- safe_id = g_strdup (instance->instance_id);
- e_filename_make_safe (safe_id);
-
- filename = g_strdup_printf ("custom_view-%s.xml", safe_id);
- instance->custom_filename = g_concat_dir_and_file (instance->collection->local_dir, filename);
- g_free (filename);
-
- filename = g_strdup_printf ("current_view-%s.xml", safe_id);
- instance->current_view_filename = g_concat_dir_and_file (instance->collection->local_dir, filename);
- g_free (filename);
-
- g_free (safe_id);
-
- return instance;
-}
-
-/* Manipulate the current view. */
-char *
-gal_view_instance_get_current_view_id (GalViewInstance *instance)
-{
- if (instance->current_id && gal_view_collection_get_view_index_by_id (instance->collection, instance->current_id) != -1)
- return g_strdup (instance->current_id);
- else
- return NULL;
-}
-
-void
-gal_view_instance_set_current_view_id (GalViewInstance *instance, const char *view_id)
-{
- GalView *view;
- int index;
-
- g_return_if_fail (instance != NULL);
- g_return_if_fail (GAL_IS_VIEW_INSTANCE (instance));
-
- d(g_print("%s: view_id set to %s\n", G_GNUC_FUNCTION, view_id));
-
- if (instance->current_id && !strcmp (instance->current_id, view_id))
- return;
-
- g_free (instance->current_id);
- instance->current_id = g_strdup (view_id);
-
- index = gal_view_collection_get_view_index_by_id (instance->collection, view_id);
- if (index != -1) {
- view = gal_view_collection_get_view (instance->collection, index);
- connect_view (instance, gal_view_clone (view));
- }
-
- save_current_view (instance);
- gal_view_instance_changed(instance);
-}
-
-GalView *
-gal_view_instance_get_current_view (GalViewInstance *instance)
-{
- return instance->current_view;
-}
-
-void
-gal_view_instance_set_custom_view (GalViewInstance *instance, GalView *view)
-{
- g_free (instance->current_id);
- instance->current_id = NULL;
-
- view = gal_view_clone (view);
- connect_view (instance, view);
- gal_view_save (view, instance->custom_filename);
- save_current_view (instance);
- gal_view_instance_changed(instance);
-}
-
-static void
-dialog_response(GtkWidget *dialog, int id, GalViewInstance *instance)
-{
- if (id == GTK_RESPONSE_OK) {
- gal_view_instance_save_as_dialog_save (GAL_VIEW_INSTANCE_SAVE_AS_DIALOG (dialog));
- }
- gtk_widget_destroy (dialog);
-}
-
-void
-gal_view_instance_save_as (GalViewInstance *instance)
-{
- GtkWidget *dialog = gal_view_instance_save_as_dialog_new(instance);
- g_signal_connect(dialog, "response",
- G_CALLBACK(dialog_response), instance);
- gtk_widget_show(dialog);
-}
-
-/* This is idempotent. Once it's been called once, the rest of the calls are ignored. */
-void
-gal_view_instance_load (GalViewInstance *instance)
-{
- if (!instance->loaded) {
- load_current_view (instance);
- instance->loaded = TRUE;
- }
-}
-
-/* These only mean anything before gal_view_instance_load is called the first time. */
-const char *
-gal_view_instance_get_default_view (GalViewInstance *instance)
-{
- if (instance->default_view)
- return instance->default_view;
- else
- return gal_view_collection_get_default_view (instance->collection);
-}
-
-void
-gal_view_instance_set_default_view (GalViewInstance *instance, const char *id)
-{
- g_free (instance->default_view);
- instance->default_view = g_strdup (id);
-}
-
-gboolean
-gal_view_instance_exists (GalViewInstance *instance)
-{
- struct stat st;
-
- if (instance->current_view_filename && stat (instance->current_view_filename, &st) == 0 && st.st_size > 0 && S_ISREG (st.st_mode))
- return TRUE;
- else
- return FALSE;
-
-}
-
-typedef struct {
- GalViewInstance *instance;
- char *id;
-} ListenerClosure;
-
-static void
-view_item_cb (GtkWidget *widget,
- gpointer user_data)
-{
- ListenerClosure *closure = user_data;
-
- if (GTK_CHECK_MENU_ITEM (widget)->active) {
- gal_view_instance_set_current_view_id (closure->instance, closure->id);
- }
-}
-
-static void
-add_popup_radio_item (EPopupMenu *menu_item,
- gchar *title,
- GtkSignalFunc fn,
- gpointer closure,
- gboolean value)
-{
- EPopupMenu menu_item_struct =
- E_POPUP_RADIO_ITEM_CC (title,
- fn,
- closure,
- 0,
- 0);
- menu_item_struct.is_active = value;
-
- e_popup_menu_copy_1 (menu_item, &menu_item_struct);
-}
-
-static void
-add_popup_menu_item (EPopupMenu *menu_item,
- gchar *title,
- GCallback fn,
- gpointer closure)
-{
- EPopupMenu menu_item_struct =
- E_POPUP_ITEM_CC (title,
- fn,
- closure,
- 0);
-
- e_popup_menu_copy_1 (menu_item, &menu_item_struct);
-}
-
-static void
-define_views_dialog_response(GtkWidget *dialog, int id, GalViewInstance *instance)
-{
- if (id == GTK_RESPONSE_OK) {
- gal_view_collection_save(instance->collection);
- }
- gtk_widget_destroy (dialog);
-}
-
-static void
-define_views_cb(GtkWidget *widget,
- GalViewInstance *instance)
-{
- GtkWidget *dialog = gal_define_views_dialog_new(instance->collection);
- g_signal_connect(dialog, "response",
- G_CALLBACK(define_views_dialog_response), instance);
- gtk_widget_show(dialog);
-}
-
-static void
-save_current_view_cb(GtkWidget *widget,
- GalViewInstance *instance)
-{
- gal_view_instance_save_as (instance);
-}
-
-EPopupMenu *
-gal_view_instance_get_popup_menu (GalViewInstance *instance)
-{
- EPopupMenu *ret_val;
- int length;
- int i;
- gboolean found = FALSE;
- char *id;
-
- length = gal_view_collection_get_count(instance->collection);
- id = gal_view_instance_get_current_view_id (instance);
-
- ret_val = g_new (EPopupMenu, length + 6);
-
- for (i = 0; i < length; i++) {
- gboolean value = FALSE;
- GalViewCollectionItem *item = gal_view_collection_get_view_item(instance->collection, i);
- ListenerClosure *closure;
-
- closure = g_new (ListenerClosure, 1);
- closure->instance = instance;
- closure->id = item->id;
- g_object_ref (closure->instance);
-
- if (!found && id && !strcmp (id, item->id)) {
- found = TRUE;
- value = TRUE;
- }
-
- add_popup_radio_item (ret_val + i, item->title, G_CALLBACK (view_item_cb), closure, value);
- }
-
- if (!found) {
- e_popup_menu_copy_1 (ret_val + i++, &separator);
-
- add_popup_radio_item (ret_val + i++, N_("Custom View"), NULL, NULL, TRUE);
- add_popup_menu_item (ret_val + i++, N_("Save Custom View"), G_CALLBACK (save_current_view_cb), instance);
- }
-
- e_popup_menu_copy_1 (ret_val + i++, &separator);
- add_popup_menu_item (ret_val + i++, N_("Define Views..."), G_CALLBACK (define_views_cb), instance);
- e_popup_menu_copy_1 (ret_val + i++, &terminator);
-
- if (id)
- g_free (id);
-
- return ret_val;
-}
-
-void
-gal_view_instance_free_popup_menu (GalViewInstance *instance, EPopupMenu *menu)
-{
- int i;
- /* This depends on the first non-custom closure to be a separator or a terminator. */
- for (i = 0; menu[i].name && *(menu[i].name); i++) {
- g_object_unref (((ListenerClosure *)(menu[i].closure))->instance);
- g_free (menu[i].closure);
- }
-
- e_popup_menu_free (menu);
-}
diff --git a/widgets/menus/gal-view-instance.h b/widgets/menus/gal-view-instance.h
deleted file mode 100644
index 05723a2ea6..0000000000
--- a/widgets/menus/gal-view-instance.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * gal-view-instance.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _GAL_VIEW_INSTANCE_H_
-#define _GAL_VIEW_INSTANCE_H_
-
-#include <gtk/gtkobject.h>
-#include <gal/menus/gal-view-collection.h>
-#include <gal/widgets/e-popup-menu.h>
-
-G_BEGIN_DECLS
-
-#define GAL_VIEW_INSTANCE_TYPE (gal_view_instance_get_type ())
-#define GAL_VIEW_INSTANCE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GAL_VIEW_INSTANCE_TYPE, GalViewInstance))
-#define GAL_VIEW_INSTANCE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GAL_VIEW_INSTANCE_TYPE, GalViewInstanceClass))
-#define GAL_IS_VIEW_INSTANCE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GAL_VIEW_INSTANCE_TYPE))
-#define GAL_IS_VIEW_INSTANCE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GAL_VIEW_INSTANCE_TYPE))
-
-typedef struct {
- GObject base;
-
- GalViewCollection *collection;
-
- char *instance_id;
- char *current_view_filename;
- char *custom_filename;
-
- char *current_title;
- char *current_type;
- char *current_id;
-
- GalView *current_view;
-
- guint view_changed_id;
- guint collection_changed_id;
-
- guint loaded : 1;
- char *default_view;
-} GalViewInstance;
-
-typedef struct {
- GObjectClass parent_class;
-
- /*
- * Signals
- */
- void (*display_view) (GalViewInstance *instance,
- GalView *view);
- void (*changed) (GalViewInstance *instance);
-} GalViewInstanceClass;
-
-/* Standard functions */
-GType gal_view_instance_get_type (void);
-
-/* */
-/*collection should be loaded when you call this.
- instance_id: Which instance of this type of object is this (for most of evo, this is the folder id.) */
-GalViewInstance *gal_view_instance_new (GalViewCollection *collection,
- const char *instance_id);
-GalViewInstance *gal_view_instance_construct (GalViewInstance *instance,
- GalViewCollection *collection,
- const char *instance_id);
-
-/* Manipulate the current view. */
-char *gal_view_instance_get_current_view_id (GalViewInstance *instance);
-void gal_view_instance_set_current_view_id (GalViewInstance *instance,
- const char *view_id);
-GalView *gal_view_instance_get_current_view (GalViewInstance *instance);
-
-/* Sets the current view to the given custom view. */
-void gal_view_instance_set_custom_view (GalViewInstance *instance,
- GalView *view);
-
-
-/* Returns true if this instance has ever been used before. */
-gboolean gal_view_instance_exists (GalViewInstance *instance);
-
-/* Manipulate the view collection */
-/* void gal_view_instance_set_as_default (GalViewInstance *instance); */
-void gal_view_instance_save_as (GalViewInstance *instance);
-
-/* This is idempotent. Once it's been called once, the rest of the calls are ignored. */
-void gal_view_instance_load (GalViewInstance *instance);
-
-/* These only mean anything before gal_view_instance_load is called the first time. */
-const char *gal_view_instance_get_default_view (GalViewInstance *instance);
-void gal_view_instance_set_default_view (GalViewInstance *instance,
- const char *id);
-
-EPopupMenu *gal_view_instance_get_popup_menu (GalViewInstance *instance);
-void gal_view_instance_free_popup_menu (GalViewInstance *instance,
- EPopupMenu *menu);
-
-G_END_DECLS
-
-#endif /* _GAL_VIEW_INSTANCE_H_ */
diff --git a/widgets/menus/gal-view-new-dialog.c b/widgets/menus/gal-view-new-dialog.c
deleted file mode 100644
index 00ef874e40..0000000000
--- a/widgets/menus/gal-view-new-dialog.c
+++ /dev/null
@@ -1,285 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * gal-view-new-dialog.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <gtk/gtk.h>
-#include <gtk/gtktreeselection.h>
-#include "gal-view-new-dialog.h"
-#include "gal-define-views-model.h"
-#include <gal/widgets/e-unicode.h>
-#include <gal/e-table/e-table-scrolled.h>
-#include <gal/util/e-i18n.h>
-#include <gal/util/e-util.h>
-
-static void gal_view_new_dialog_init (GalViewNewDialog *card);
-static void gal_view_new_dialog_class_init (GalViewNewDialogClass *klass);
-static void gal_view_new_dialog_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
-static void gal_view_new_dialog_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
-static void gal_view_new_dialog_dispose (GObject *object);
-
-static GtkDialogClass *parent_class = NULL;
-#define PARENT_TYPE GTK_TYPE_DIALOG
-
-/* The arguments we take */
-enum {
- PROP_0,
- PROP_NAME,
- PROP_FACTORY
-};
-
-E_MAKE_TYPE(gal_view_new_dialog, "GalViewNewDialog",
- GalViewNewDialog,
- gal_view_new_dialog_class_init,
- gal_view_new_dialog_init, PARENT_TYPE)
-
-static void
-gal_view_new_dialog_class_init (GalViewNewDialogClass *klass)
-{
- GObjectClass *object_class;
-
- object_class = (GObjectClass*) klass;
-
- parent_class = g_type_class_ref (PARENT_TYPE);
-
- object_class->set_property = gal_view_new_dialog_set_property;
- object_class->get_property = gal_view_new_dialog_get_property;
- object_class->dispose = gal_view_new_dialog_dispose;
-
- g_object_class_install_property (object_class, PROP_NAME,
- g_param_spec_string ("name",
- _("Name"),
- /*_( */"XXX blurb" /*)*/,
- NULL,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class, PROP_FACTORY,
- g_param_spec_object ("factory",
- _("Factory"),
- /*_( */"XXX blurb" /*)*/,
- GAL_VIEW_FACTORY_TYPE,
- G_PARAM_READWRITE));
-}
-
-static void
-gal_view_new_dialog_init (GalViewNewDialog *dialog)
-{
- GladeXML *gui;
- GtkWidget *widget;
-
- gui = glade_xml_new (GAL_GLADEDIR "/gal-view-new-dialog.glade", NULL, E_I18N_DOMAIN);
- dialog->gui = gui;
-
- widget = glade_xml_get_widget(gui, "table-top");
- if (!widget) {
- return;
- }
- gtk_widget_ref(widget);
- gtk_container_remove (GTK_CONTAINER (widget->parent), widget);
- gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), widget, TRUE, TRUE, 0);
- gtk_widget_unref(widget);
-
- gtk_dialog_add_buttons (GTK_DIALOG (dialog),
- GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
- GTK_STOCK_OK, GTK_RESPONSE_OK,
- NULL);
-
- gtk_window_set_policy(GTK_WINDOW(dialog), FALSE, TRUE, FALSE);
- gtk_window_set_modal (GTK_WINDOW(dialog), TRUE);
- gtk_window_set_title (GTK_WINDOW(dialog), _("Define New View"));
-
- dialog->collection = NULL;
- dialog->selected_factory = NULL;
-}
-
-static void
-gal_view_new_dialog_dispose (GObject *object)
-{
- GalViewNewDialog *gal_view_new_dialog = GAL_VIEW_NEW_DIALOG(object);
-
- if (gal_view_new_dialog->gui)
- g_object_unref(gal_view_new_dialog->gui);
- gal_view_new_dialog->gui = NULL;
-
- if (G_OBJECT_CLASS (parent_class)->dispose)
- (* G_OBJECT_CLASS (parent_class)->dispose) (object);
-}
-
-GtkWidget*
-gal_view_new_dialog_new (GalViewCollection *collection)
-{
- GtkWidget *widget =
- gal_view_new_dialog_construct(g_object_new (GAL_VIEW_NEW_DIALOG_TYPE, NULL),
- collection);
- return widget;
-}
-
-static void
-sensitize_ok_response (GalViewNewDialog *dialog)
-{
- gboolean ok = TRUE;
- const char *text;
-
- text = gtk_entry_get_text (GTK_ENTRY (dialog->entry));
- if (!text || !text[0])
- ok = FALSE;
-
- if (!dialog->selected_factory)
- ok = FALSE;
-
- gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, ok);
-}
-
-static gboolean
-selection_func (GtkTreeSelection *selection,
- GtkTreeModel *model,
- GtkTreePath *path,
- gboolean path_currently_selected,
- gpointer data)
-{
- GtkTreeIter iter;
- GalViewNewDialog *dialog = data;
-
- if (path_currently_selected)
- return TRUE;
-
- gtk_tree_model_get_iter (GTK_TREE_MODEL (dialog->list_store),
- &iter,
- (GtkTreePath*)path);
-
- gtk_tree_model_get (GTK_TREE_MODEL (dialog->list_store),
- &iter,
- 1, &dialog->selected_factory,
- -1);
-
- printf ("%s factory selected\n", gal_view_factory_get_title(dialog->selected_factory));
-
- sensitize_ok_response (dialog);
-
- return TRUE;
-}
-
-static void
-entry_changed (GtkWidget *entry, gpointer data)
-{
- GalViewNewDialog *dialog = data;
-
- sensitize_ok_response (dialog);
-}
-
-GtkWidget*
-gal_view_new_dialog_construct (GalViewNewDialog *dialog,
- GalViewCollection *collection)
-{
- GList *iterator;
- GtkTreeSelection *selection;
- GtkTreeViewColumn *column;
- GtkCellRenderer *rend;
-
- dialog->collection = collection;
- dialog->list = glade_xml_get_widget(dialog->gui,"list-type-list");
- dialog->entry = glade_xml_get_widget(dialog->gui, "entry-name");
- dialog->list_store = gtk_list_store_new (2,
- G_TYPE_STRING,
- G_TYPE_POINTER);
-
- rend = gtk_cell_renderer_text_new ();
- column = gtk_tree_view_column_new_with_attributes ("factory title",
- rend,
- "text", 0,
- NULL);
-
- gtk_tree_view_append_column (GTK_TREE_VIEW (dialog->list), column);
-
- iterator = dialog->collection->factory_list;
- for ( ; iterator; iterator = g_list_next(iterator) ) {
- GalViewFactory *factory = iterator->data;
- GtkTreeIter iter;
-
- g_object_ref(factory);
- gtk_list_store_append (dialog->list_store,
- &iter);
- gtk_list_store_set (dialog->list_store,
- &iter,
- 0, gal_view_factory_get_title(factory),
- 1, factory,
- -1);
- }
-
- gtk_tree_view_set_model (GTK_TREE_VIEW (dialog->list), GTK_TREE_MODEL (dialog->list_store));
-
- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->list));
- gtk_tree_selection_set_select_function (selection, selection_func, dialog, NULL);
-
- g_signal_connect (dialog->entry, "changed",
- G_CALLBACK (entry_changed), dialog);
-
- sensitize_ok_response (dialog);
-
- return GTK_WIDGET(dialog);
-}
-
-static void
-gal_view_new_dialog_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
-{
- GalViewNewDialog *dialog;
- GtkWidget *entry;
-
- dialog = GAL_VIEW_NEW_DIALOG (object);
-
- switch (prop_id){
- case PROP_NAME:
-
- if (entry && GTK_IS_ENTRY(entry)) {
- gtk_entry_set_text(GTK_ENTRY(entry), g_value_get_string (value));
- }
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- return;
- }
-}
-
-
-static void
-gal_view_new_dialog_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
-{
- GalViewNewDialog *dialog;
- GtkWidget *entry;
-
- dialog = GAL_VIEW_NEW_DIALOG (object);
-
- switch (prop_id) {
- case PROP_NAME:
- entry = glade_xml_get_widget(dialog->gui, "entry-name");
- if (entry && GTK_IS_ENTRY(entry)) {
- g_value_set_string (value, gtk_entry_get_text (GTK_ENTRY (entry)));
- }
- break;
- case PROP_FACTORY:
- g_value_set_object (value, dialog->selected_factory);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
diff --git a/widgets/menus/gal-view-new-dialog.glade b/widgets/menus/gal-view-new-dialog.glade
deleted file mode 100644
index 70922f5dc5..0000000000
--- a/widgets/menus/gal-view-new-dialog.glade
+++ /dev/null
@@ -1,175 +0,0 @@
-<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
-<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
-
-<glade-interface>
-
-<widget class="GtkDialog" id="dialog1">
- <property name="title" translatable="yes"></property>
- <property name="type">GTK_WINDOW_TOPLEVEL</property>
- <property name="window_position">GTK_WIN_POS_NONE</property>
- <property name="modal">False</property>
- <property name="resizable">True</property>
- <property name="destroy_with_parent">False</property>
- <property name="has_separator">True</property>
-
- <child internal-child="vbox">
- <widget class="GtkVBox" id="dialog-vbox1">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">8</property>
-
- <child internal-child="action_area">
- <widget class="GtkHButtonBox" id="dialog-action_area1">
- <property name="visible">True</property>
- <property name="layout_style">GTK_BUTTONBOX_END</property>
-
- <child>
- <widget class="GtkButton" id="button1">
- <property name="visible">True</property>
- <property name="can_default">True</property>
- <property name="can_focus">True</property>
- <property name="label">gtk-ok</property>
- <property name="use_stock">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="response_id">0</property>
- </widget>
- </child>
-
- <child>
- <widget class="GtkButton" id="button3">
- <property name="visible">True</property>
- <property name="can_default">True</property>
- <property name="can_focus">True</property>
- <property name="label">gtk-cancel</property>
- <property name="use_stock">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="response_id">0</property>
- </widget>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="pack_type">GTK_PACK_END</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkTable" id="table-top">
- <property name="visible">True</property>
- <property name="n_rows">4</property>
- <property name="n_columns">1</property>
- <property name="homogeneous">False</property>
- <property name="row_spacing">6</property>
- <property name="column_spacing">6</property>
-
- <child>
- <widget class="GtkLabel" id="label1">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Name of new view:</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_CENTER</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- <property name="mnemonic_widget">entry-name</property>
- </widget>
- <packing>
- <property name="left_attach">0</property>
- <property name="right_attach">1</property>
- <property name="top_attach">0</property>
- <property name="bottom_attach">1</property>
- <property name="x_options">fill</property>
- <property name="y_options"></property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkEntry" id="entry-name">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="editable">True</property>
- <property name="visibility">True</property>
- <property name="max_length">0</property>
- <property name="text" translatable="yes"></property>
- <property name="has_frame">True</property>
- <property name="invisible_char" translatable="yes">*</property>
- <property name="activates_default">False</property>
- </widget>
- <packing>
- <property name="left_attach">0</property>
- <property name="right_attach">1</property>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
- <property name="y_options">fill</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label2">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Type of view:</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_CENTER</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="left_attach">0</property>
- <property name="right_attach">1</property>
- <property name="top_attach">2</property>
- <property name="bottom_attach">3</property>
- <property name="x_options">fill</property>
- <property name="y_options"></property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkScrolledWindow" id="scrolledwindow1">
- <property name="visible">True</property>
- <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
- <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
- <property name="shadow_type">GTK_SHADOW_IN</property>
- <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
-
- <child>
- <widget class="GtkTreeView" id="list-type-list">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="headers_visible">False</property>
- <property name="rules_hint">False</property>
- <property name="reorderable">False</property>
- <property name="enable_search">True</property>
- </widget>
- </child>
- </widget>
- <packing>
- <property name="left_attach">0</property>
- <property name="right_attach">1</property>
- <property name="top_attach">3</property>
- <property name="bottom_attach">4</property>
- <property name="x_options">fill</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- </child>
-</widget>
-
-</glade-interface>
diff --git a/widgets/menus/gal-view-new-dialog.h b/widgets/menus/gal-view-new-dialog.h
deleted file mode 100644
index cd523a2476..0000000000
--- a/widgets/menus/gal-view-new-dialog.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * gal-view-new-dialog.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef __GAL_VIEW_NEW_DIALOG_H__
-#define __GAL_VIEW_NEW_DIALOG_H__
-
-#include <gtk/gtkdialog.h>
-#include <gtk/gtkliststore.h>
-#include <glade/glade.h>
-#include <gal-view-collection.h>
-
-#ifdef __cplusplus
-extern "C" {
-#pragma }
-#endif /* __cplusplus */
-
-/* GalViewNewDialog - A dialog displaying information about a contact.
- *
- * The following arguments are available:
- *
- * name type read/write description
- * --------------------------------------------------------------------------------
- */
-
-#define GAL_VIEW_NEW_DIALOG_TYPE (gal_view_new_dialog_get_type ())
-#define GAL_VIEW_NEW_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_VIEW_NEW_DIALOG_TYPE, GalViewNewDialog))
-#define GAL_VIEW_NEW_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_VIEW_NEW_DIALOG_TYPE, GalViewNewDialogClass))
-#define GAL_IS_VIEW_NEW_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_VIEW_NEW_DIALOG_TYPE))
-#define GAL_IS_VIEW_NEW_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), GAL_VIEW_NEW_DIALOG_TYPE))
-
-typedef struct _GalViewNewDialog GalViewNewDialog;
-typedef struct _GalViewNewDialogClass GalViewNewDialogClass;
-
-struct _GalViewNewDialog
-{
- GtkDialog parent;
-
- /* item specific fields */
- GladeXML *gui;
-
- GalViewCollection *collection;
- GalViewFactory *selected_factory;
-
- GtkListStore *list_store;
-
- GtkWidget *entry;
- GtkWidget *list;
-};
-
-struct _GalViewNewDialogClass
-{
- GtkDialogClass parent_class;
-};
-
-GtkWidget *gal_view_new_dialog_new (GalViewCollection *collection);
-GType gal_view_new_dialog_get_type (void);
-
-GtkWidget *gal_view_new_dialog_construct (GalViewNewDialog *dialog,
- GalViewCollection *collection);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-
-#endif /* __GAL_VIEW_NEW_DIALOG_H__ */
diff --git a/widgets/menus/gal-view.c b/widgets/menus/gal-view.c
deleted file mode 100644
index fa1402fae4..0000000000
--- a/widgets/menus/gal-view.c
+++ /dev/null
@@ -1,206 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * gal-view.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include "gal-view.h"
-#include "gal/util/e-util.h"
-
-#define PARENT_TYPE G_TYPE_OBJECT
-
-#define d(x)
-
-d(static gint depth = 0;)
-
-
-static GObjectClass *gal_view_parent_class;
-
-enum {
- CHANGED,
- LAST_SIGNAL
-};
-
-static guint gal_view_signals [LAST_SIGNAL] = { 0, };
-
-/**
- * gal_view_edit
- * @view: The view to edit
- * @parent: the parent window.
- */
-void
-gal_view_edit (GalView *view,
- GtkWindow *parent)
-{
- g_return_if_fail (view != NULL);
- g_return_if_fail (GAL_IS_VIEW (view));
- g_return_if_fail (GTK_IS_WINDOW (parent));
-
- if (GAL_VIEW_GET_CLASS (view)->edit)
- GAL_VIEW_GET_CLASS (view)->edit (view, parent);
-}
-
-/**
- * gal_view_load
- * @view: The view to load to
- * @filename: The file to load from
- */
-void
-gal_view_load (GalView *view,
- const char *filename)
-{
- g_return_if_fail (view != NULL);
- g_return_if_fail (GAL_IS_VIEW (view));
-
- if (GAL_VIEW_GET_CLASS (view)->load)
- GAL_VIEW_GET_CLASS (view)->load (view, filename);
-}
-
-/**
- * gal_view_save
- * @view: The view to save
- * @filename: The file to save to
- */
-void
-gal_view_save (GalView *view,
- const char *filename)
-{
- g_return_if_fail (view != NULL);
- g_return_if_fail (GAL_IS_VIEW (view));
-
- if (GAL_VIEW_GET_CLASS (view)->save)
- GAL_VIEW_GET_CLASS (view)->save (view, filename);
-}
-
-/**
- * gal_view_get_title
- * @view: The view to query.
- *
- * Returns: The title of the view.
- */
-const char *
-gal_view_get_title (GalView *view)
-{
- g_return_val_if_fail (view != NULL, NULL);
- g_return_val_if_fail (GAL_IS_VIEW (view), NULL);
-
- if (GAL_VIEW_GET_CLASS (view)->get_title)
- return GAL_VIEW_GET_CLASS (view)->get_title (view);
- else
- return NULL;
-}
-
-/**
- * gal_view_set_title
- * @view: The view to set.
- * @title: The new title value.
- */
-void
-gal_view_set_title (GalView *view,
- const char *title)
-{
- g_return_if_fail (view != NULL);
- g_return_if_fail (GAL_IS_VIEW (view));
-
- if (GAL_VIEW_GET_CLASS (view)->set_title)
- GAL_VIEW_GET_CLASS (view)->set_title (view, title);
-}
-
-/**
- * gal_view_get_type_code
- * @view: The view to get.
- *
- * Returns: The type of the view.
- */
-const char *
-gal_view_get_type_code (GalView *view)
-{
- g_return_val_if_fail (view != NULL, NULL);
- g_return_val_if_fail (GAL_IS_VIEW (view), NULL);
-
- if (GAL_VIEW_GET_CLASS (view)->get_type_code)
- return GAL_VIEW_GET_CLASS (view)->get_type_code (view);
- else
- return NULL;
-}
-
-/**
- * gal_view_clone
- * @view: The view to clone.
- *
- * Returns: The clone.
- */
-GalView *
-gal_view_clone (GalView *view)
-{
- g_return_val_if_fail (view != NULL, NULL);
- g_return_val_if_fail (GAL_IS_VIEW (view), NULL);
-
- if (GAL_VIEW_GET_CLASS (view)->clone)
- return GAL_VIEW_GET_CLASS (view)->clone (view);
- else
- return NULL;
-}
-
-/**
- * gal_view_changed
- * @view: The view that changed.
- */
-void
-gal_view_changed (GalView *view)
-{
- g_return_if_fail (view != NULL);
- g_return_if_fail (GAL_IS_VIEW (view));
-
- g_signal_emit(view,
- gal_view_signals [CHANGED], 0);
-}
-
-static void
-gal_view_class_init (GObjectClass *object_class)
-{
- GalViewClass *klass = GAL_VIEW_CLASS(object_class);
- gal_view_parent_class = g_type_class_ref (PARENT_TYPE);
-
- klass->edit = NULL;
- klass->load = NULL;
- klass->save = NULL;
- klass->get_title = NULL;
- klass->clone = NULL;
-
- klass->changed = NULL;
-
- gal_view_signals [CHANGED] =
- g_signal_new ("changed",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GalViewClass, changed),
- NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
-}
-
-static void
-gal_view_init (GalView *view)
-{
-}
-
-E_MAKE_TYPE(gal_view, "GalView", GalView, gal_view_class_init, gal_view_init, PARENT_TYPE)
diff --git a/widgets/menus/gal-view.h b/widgets/menus/gal-view.h
deleted file mode 100644
index 77056243c5..0000000000
--- a/widgets/menus/gal-view.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * gal-view.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _GAL_VIEW_H_
-#define _GAL_VIEW_H_
-
-#include <gtk/gtkwindow.h>
-#include <libxml/tree.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-#define GAL_VIEW_TYPE (gal_view_get_type ())
-#define GAL_VIEW(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GAL_VIEW_TYPE, GalView))
-#define GAL_VIEW_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GAL_VIEW_TYPE, GalViewClass))
-#define GAL_IS_VIEW(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GAL_VIEW_TYPE))
-#define GAL_IS_VIEW_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GAL_VIEW_TYPE))
-#define GAL_VIEW_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GAL_VIEW_TYPE, GalViewClass))
-
-typedef struct {
- GObject base;
-} GalView;
-
-typedef struct {
- GObjectClass parent_class;
-
- /*
- * Virtual methods
- */
- void (*edit) (GalView *view, GtkWindow *parent_window);
- void (*load) (GalView *view,
- const char *filename);
- void (*save) (GalView *view,
- const char *filename);
- const char *(*get_title) (GalView *view);
- void (*set_title) (GalView *view,
- const char *title);
- const char *(*get_type_code) (GalView *view);
- GalView *(*clone) (GalView *view);
-
- /* Signals */
- void (*changed) (GalView *view);
-} GalViewClass;
-
-/* Standard functions */
-GType gal_view_get_type (void);
-
-/* Open an editor dialog for this view, modal/transient for the GtkWindow arg. */
-void gal_view_edit (GalView *view,
- GtkWindow *parent);
-
-/* xml load and save functions */
-void gal_view_load (GalView *view,
- const char *filename);
-void gal_view_save (GalView *view,
- const char *filename);
-
-/* Title functions */
-const char *gal_view_get_title (GalView *view);
-void gal_view_set_title (GalView *view,
- const char *title);
-
-/* View type. */
-const char *gal_view_get_type_code (GalView *view);
-
-/* Cloning the view */
-GalView *gal_view_clone (GalView *view);
-
-/* Changed signal */
-void gal_view_changed (GalView *view);
-
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* _GAL_VIEW_H_ */
diff --git a/widgets/misc/ChangeLog b/widgets/misc/ChangeLog
index 29a90b9663..05525bc926 100644
--- a/widgets/misc/ChangeLog
+++ b/widgets/misc/ChangeLog
@@ -1,204 +1,9 @@
-2005-02-02 Li Yuan <li.yuan@sun.com>
+2004-09-28 JP Rosevear <jpr@novell.com>
- * e-url-entry.c: (init):
- add a11y name to url link button.
-
-2005-01-26 Rodney Dawes <dobey@novell.com>
-
- * e-error.c (e_error_newv): Fix up spacing to be HIG compliant for
- the borders around the dialogs
-
-2005-01-25 Not Zed <NotZed@Ximian.com>
-
- * e-error.c: turn off debug output, people think its a significant
- error.
-
-2005-01-24 Mengjie Yu <meng-jie.yu@sun.com>
-
- * e-search-bar.c: (set_option):
- add a11y name for the option menu.
-
-2005-01-20 Not Zed <NotZed@Ximian.com>
-
- ** See bug #64964.
-
- * e-error.c (e_error_newv): just use add_button, not
- add_action_widget, for stock+label widgets, since they both show
- the same, and for some reason set_default_response doesn't work
- otherwise.
-
-2005-01-20 Harry Lu <harry.lu@sun.com>
-
- * e-search-bar.c: (activate_by_subitems): add a translater note.
-
-2005-01-19 Harry Lu <harry.lu@sun.com>
-
- Fix for 46359, enable "Alt+Down Arrow" to show the popup for
- e-combo-cell-editable.c.
-
- * e-combo-cell-editable.c: (show_popup): rewrite it to a more
- generic function.
- (button_clicked_cb): call the new show_popup function.
- (entry_key_press_event_cb): show popup if "Alt+Down Arrow".
- (ecce_grab_focus): new function.
- (ecce_class_init): add grab_focus handler so that the entry
- can get focus.
-
-2005-01-17 Harry Lu <harry.lu@sun.com>
-
- Fix for 62831.
-
- * e-search-bar.c: (activate_by_subitems): add an a11y name for
- the search entry.
-
-2005-01-12 Chenthill Palanisamy <pchenthill@novell.com>
-
- * e-send-options.c: (e_send_options_get_widgets_data),
- (e_send_options_fill_widgets_with_data): Get the value
- for the autodelete toggle button
- (page_changed_cb): Do not hide the classification label
- and its combo box here.
-
-2005-01-10 Chenthill Palanisamy <pchenthill@novell.com>
-
- * e-send-options.c: (e_send_options_get_widgets_data),
- (e_send_options_fill_widgets_with_data), (page_changed_cb),
- (init_widgets), (get_widgets), (setup_widgets),
- (e_sendoptions_set_global), (e_sendoptions_dialog_run),
- (e_sendoptions_dialog_finalize), (e_sendoptions_dialog_dispose),
- (e_sendoptions_dialog_init), (e_sendoptions_dialog_class_init),
- (e_sendoptions_dialog_get_type): Added code to support global options.
- Filled the finalize and dispose functions.
- * e-send-options.glade: Changed a label id.
- * e-send-options.h: Added the set_global function.
-
-2005-01-06 JP Rosevear <jpr@novell.com>
-
- * Makefile.am: dist the glade file
-
-2005-01-06 Chenthill Palanisamy <pchenthill@novell.com>
+ Fixes #66164
- Commiting the files mentioned below again to HEAD since it
- was not added in head.
-
-2005-01-06 Chenthill Palanisamy <pchenthill@novell.com>
-
- merging send options
- * Makefile.am:
- * e-send-options.[ch]: Widgets for the send options dialog
- * e-send-options.glade: Contains interface for the dialog
-
-2005-01-04 Harry Lu <harry.lu@sun.com>
-
- * misc/e-combo-button.c: (e_combo_button_popup): new internal function
- to popup the menu.
- (impl_button_press_event): call the new function.
- (e_combo_button_class_init): init a11y.
- (e_combo_button_get_label): new function to return label.
- (e_combo_button_popup_menu): new function to popup menu.
- * misc/e-combo-button.h: add function declarations.
-
-2004-12-17 Not Zed <NotZed@Ximian.com>
-
- * e-error.c (ee_load, e_error_newv): translate strings based on
- translation-domain, if supplied.
-
-2004-12-14 Rodney Dawes <dobey@novell.com>
-
- * e-calendar-item.c (e_calendar_item_draw): Use gtk_paint_foo instead
- of the deprecated gtk_draw_foo functions
- (e_calendar_item_get_day_style): Use colors from the theme for the
- background and foreground of various items
-
- * test-calendar.c (main): Don't set a callback for getting the day
- style, we want the test app to use the widget defaults
- (get_day_style): Remove all this duplicated code as we want to use
- the widget default colors for day fg/bg
-
-2004-11-26 JP Rosevear <jpr@novell.com>
-
- * test-info-label.c: test prog
-
- * e-url-entry.c: get image directly from icon factory
-
- * e-combo-button.c: ditto; convert to G_DEFINE_TYPE
-
- * e-activity-handler.c: convert to G_DEFINE_TYPE
-
- * e-task-widget.c: ditto
-
- * e-task-bar.c: ditto
-
- * e-multi-config-dialog.c: ditto
-
- * e-dropdown-button.c: ditto
-
- * e-cell-renderer-combo.c: ditto
-
- * e-cell-date-edit.c: ditto
-
- * e-calendar.c: ditto
-
- * e-calendar-item.c: ditto
-
- * Makefile.am: don't build the title bar, build an info label test
- program
-
-2004-10-28 Li Yuan <li.yuan@sun.com>
-
- * e-calendar.c: (e_calendar_init), (e_calendar_new): Make
- accessibility name and description translatable. Add a atk name
- for the two buttons so that they can be UI grabbed by GOK.
-
- * e-dateedit.c: (e_date_edit_new), (create_children): Add a name
- for atk object. Make accessibility name and description
- translatable. Add name and description for the date_entry,
- date_button and time_combo.
- (e_date_edit_show_date_popup), (hide_date_popup): Grab and ungrab
- keyboard. add_relation(): New function to add labelled_by
- relation for entry and combobox.
-
- * e-map.c: (e_map_new): Add a name for world map widget. Make
- accessibility name and description translatable. Set the atk role
- to image.
-
- * e-multi-config-dialog.c: (e_multi_config_dialog_add_page): Add
- an atk name for the page.
-
-2004-10-27 JP Rosevear <jpr@novell.com>
-
- * Makefile.am: use E_WIDGET instead of GNOME_FULL
-
-2004-10-14 JP Rosevear <jpr@novell.com>
-
- * e-pilot-settings.c: fix e-source-option-menu include
-
-2004-10-13 JP Rosevear <jpr@novell.com>
-
- * Makefile.am: don't build source selector or source option menu
- or test programs any more
-
-2004-10-08 Harry Lu <harry.lu@sun.com>
-
- * e-source-selector.c: (e_source_selector_popup_menu),
- (class_init): implement popup_menu so that popup menu can
- be shown with Shift+F10.
-
-2004-10-06 JP Rosevear <jpr@novell.com>
-
- Fixes #66164
-
- * e-cell-date-edit.c (e_cell_date_edit_get_popup_pos): replicate
- fix to e-cell-combo.c by NotZed
-
-2004-10-01 Not Zed <NotZed@Ximian.com>
-
- * e-util-marshal.list: added boolean object boxed.
-
- * e-source-selector.c (class_init): add new 'popup event' signal,
- to replace fill_popup_menu.
- (selector_button_press_event): emit a POPUP_EVENT rather than a
- FILL_POPUP_MENU.
+ * e-cell-date-edit.c (e_cell_date_edit_get_popup_pos): replicate
+ fix to e-cell-combo.c by NotZed
2004-09-13 Rodney Dawes <dobey@novell.com>
@@ -273,12 +78,6 @@
(e_source_selector_set_select_new): Add function to set whether or not
we want to select new sources when we add them
-2004-06-22 Hans Petter Jansson <hpj@ximian.com>
-
- * e-source-selector.c (e_source_selector_peek_primary_selection):
- Add preconditions. Make sure garbage or NULL data doesn't get
- used.
-
2004-06-16 Not Zed <NotZed@Ximian.com>
* e-source-selector.c (cell_toggled_callback): fix a path leak and
@@ -287,15 +86,6 @@
you can toggle the currnet selection or not.
(cell_toggled_callback): implement set_toggle_selection behaviour.
-2004-06-11 Larry Ewing <lewing@ximian.com>
-
- * e-source-selector.c: make the source selector use a colock block
- instead of setting the foreground to indicate the source color.
- (pixbuf_cell_data_func): actually initialize the pixbuf (bad
- larry).
- (pixbuf_cell_data_func): clean up warnings. (double bad larry).
- (pixbuf_cell_data_func): fix the appearance a little.
-
2004-06-03 William Jon McCann <mccann@jhu.edu>
* e-error.c (e_error_newv): Add HIG border width for dialog window.
@@ -731,17 +521,6 @@
* e-cell-date-edit.c: (e_cell_date_edit_do_popup): call
gdk_window_focus() so that keyboard works correctly.
-2003-12-16 Hans Petter Jansson <hpj@ximian.com>
-
- * e-source-option-menu.c (select_source_foreach_menu_item): Use
- e_source_equal() instead of comparing pointers. This allows user
- to pass in a source that was obtained from somewhere else. Set the
- matching internal source as "selected" instead of the one passed
- in.
- (select_source): Emit signal only if we found a match. Don't
- ref/unref anything, since the selected source will always be from
- our internal list.
-
2003-12-04 Harry Lu <harry.lu@sun.com>
Fix for bugzilla bug #51624 and #51627.
@@ -874,48 +653,6 @@
* e-cell-renderer-combo.* : new, treeview renderer for combo cells
* e-combo-cell-editable.* : new, GtkCellEditable for combo cells
* Makefile.am : build the new files
-
-2003-09-19 Bolian Yin <bolian.yin@sun.com>
-
- Fixes #1245. ECalendar should be usable with the keyboard
-
- * e-calendar-item.c (e_calendar_item_focus): new func, focus
- handler.
- (e_calendar_item_key_press_event): new func, key press event
- handler
- (e_calendar_item_selection_add_days,
- e_calendar_item_stop_selecting): helpers.
- (e_calendar_item_ensure_days_visible,
- e_calendar_item_set_selection_if_emission): add the flag to
- control if we should emit e-calendar signals.
- (e_calendar_item_class_init): register focus handler.
- (e_calendar_item_event): add code for GDK_FOCUS_CHANGE and
- GDK_KEY_PRESS.
-
- * e-calendar.c (e_calendar_focus): new func, focus handler
- (e_calendar_button_has_focus): new func, if prev/next button has
- focus.
- (e_calendar_on_next_clicked, e_calendar_on_prev_clicked): click
- signal handler for prev/next buttons.
- (e_calendar_set_focusable): set if the e-calendar is focusable
-
- * e-dateedit.c (e_date_edit_show_date_popup, hide_date_popup):
- grab/ungrab gdk keyboard.
-
-2003-08-27 Hans Petter Jansson <hpj@ximian.com>
-
- Fixes #15638.
-
- * e-dateedit.c (rebuild_time_popup): Make 12-hour time format not
- be zero-padded. Right-align time labels so digits line up.
-
-2003-08-27 Bolian Yin <bolian.yin@sun.com>
-
- * Makefile.am: add dependency on a11y/widgets.
-
- * e-calendar-item.c (e_calendar_item_class_init): a11y init.
- (e_calendar_item_bounds): new func, impl the bounds virtual
- func.
2003-08-18 Ettore Perazzoli <ettore@ximian.com>
diff --git a/widgets/misc/e-canvas-background.c b/widgets/misc/e-canvas-background.c
deleted file mode 100644
index 0e57feff4e..0000000000
--- a/widgets/misc/e-canvas-background.c
+++ /dev/null
@@ -1,496 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-canvas-background.c - background color for canvas.
- * Copyright 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-
-#include "e-canvas-background.h"
-
-#include <math.h>
-#include <stdio.h>
-#include <gtk/gtksignal.h>
-#include <gdk/gdkkeysyms.h>
-#include "gal/widgets/e-hsv-utils.h"
-#include "gal/widgets/e-canvas.h"
-#include "gal/widgets/e-canvas-utils.h"
-#include "gal/util/e-util.h"
-#include "gal/util/e-i18n.h"
-#include <string.h>
-
-#define PARENT_OBJECT_TYPE gnome_canvas_item_get_type ()
-
-#define d(x)
-
-struct _ECanvasBackgroundPrivate {
- guint rgba; /* Fill color, RGBA */
- GdkColor color; /* Fill color */
- GdkBitmap *stipple; /* Stipple for fill */
- GdkGC *gc; /* GC for filling */
- double x1;
- double x2;
- double y1;
- double y2;
-
- guint needs_redraw : 1;
-};
-
-static GnomeCanvasItemClass *parent_class;
-
-enum {
- PROP_0,
- PROP_FILL_COLOR,
- PROP_FILL_COLOR_GDK,
- PROP_FILL_COLOR_RGBA,
- PROP_FILL_STIPPLE,
- PROP_X1,
- PROP_X2,
- PROP_Y1,
- PROP_Y2,
-};
-
-static void
-get_color(ECanvasBackground *ecb)
-{
- GnomeCanvasItem *item = GNOME_CANVAS_ITEM (ecb);
- ecb->priv->color.pixel = gnome_canvas_get_color_pixel (item->canvas,
- GNOME_CANVAS_COLOR (ecb->priv->color.red >> 8,
- ecb->priv->color.green>> 8,
- ecb->priv->color.blue>> 8));
-}
-
-static void
-ecb_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
-{
- double i2c [6];
- ArtPoint c1, c2, i1, i2;
- ECanvasBackground *ecb = E_CANVAS_BACKGROUND (item);
-
- /* Wrong BBox's are the source of redraw nightmares */
-
- gnome_canvas_item_i2c_affine (GNOME_CANVAS_ITEM (ecb), i2c);
-
- i1.x = ecb->priv->x1;
- i1.y = ecb->priv->y1;
- i2.x = ecb->priv->x2;
- i2.y = ecb->priv->y2;
- art_affine_point (&c1, &i1, i2c);
- art_affine_point (&c2, &i2, i2c);
-
- if (ecb->priv->x1 < 0)
- c1.x = -(double)UINT_MAX;
-
- if (ecb->priv->y1 < 0)
- c1.y = -(double)UINT_MAX;
-
- if (ecb->priv->x2 < 0)
- c2.x = (double)UINT_MAX;
-
- if (ecb->priv->y2 < 0)
- c2.y = (double)UINT_MAX;
-
- *x1 = c1.x;
- *y1 = c1.y;
- *x2 = c2.x + 1;
- *y2 = c2.y + 1;
-}
-
-/*
- * GnomeCanvasItem::update method
- */
-static void
-ecb_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
-{
- ArtPoint o1, o2;
- ECanvasBackground *ecb = E_CANVAS_BACKGROUND (item);
-
- if (GNOME_CANVAS_ITEM_CLASS (parent_class)->update)
- GNOME_CANVAS_ITEM_CLASS (parent_class)->update (item, affine, clip_path, flags);
-
- o1.x = item->x1;
- o1.y = item->y1;
- o2.x = item->x2;
- o2.y = item->y2;
-
- ecb_bounds (item, &item->x1, &item->y1, &item->x2, &item->y2);
- if (item->x1 != o1.x ||
- item->y1 != o1.y ||
- item->x2 != o2.x ||
- item->y2 != o2.y) {
- gnome_canvas_request_redraw (item->canvas, o1.x, o1.y, o2.x, o2.y);
- ecb->priv->needs_redraw = 1;
- }
-
- if (ecb->priv->needs_redraw) {
- gnome_canvas_request_redraw (item->canvas, item->x1, item->y1,
- item->x2, item->y2);
- ecb->priv->needs_redraw = 0;
- }
-}
-
-/* Sets the stipple pattern for the text */
-static void
-set_stipple (ECanvasBackground *ecb, GdkBitmap *stipple, int use_value)
-{
- if (use_value) {
- if (ecb->priv->stipple)
- gdk_bitmap_unref (ecb->priv->stipple);
-
- ecb->priv->stipple = stipple;
- if (stipple)
- gdk_bitmap_ref (stipple);
- }
-
- if (ecb->priv->gc) {
- if (stipple) {
- gdk_gc_set_stipple (ecb->priv->gc, stipple);
- gdk_gc_set_fill (ecb->priv->gc, GDK_STIPPLED);
- } else
- gdk_gc_set_fill (ecb->priv->gc, GDK_SOLID);
- }
-}
-
-static void
-ecb_dispose (GObject *object)
-{
- ECanvasBackground *ecb = E_CANVAS_BACKGROUND (object);
-
- if (ecb->priv) {
- if (ecb->priv->stipple)
- gdk_bitmap_unref (ecb->priv->stipple);
- ecb->priv->stipple = NULL;
-
- g_free (ecb->priv);
- ecb->priv = NULL;
- }
-
- if (G_OBJECT_CLASS (parent_class)->dispose)
- G_OBJECT_CLASS (parent_class)->dispose (object);
-}
-
-static void
-ecb_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- GnomeCanvasItem *item;
- ECanvasBackground *ecb;
-
- GdkColor color = { 0, 0, 0, 0, };
- GdkColor *pcolor;
- gboolean color_changed = FALSE;
-
- item = GNOME_CANVAS_ITEM (object);
- ecb = E_CANVAS_BACKGROUND (object);
-
- switch (prop_id){
- case PROP_FILL_COLOR:
- if (g_value_get_string (value))
- gdk_color_parse (g_value_get_string (value), &color);
-
- ecb->priv->rgba = ((color.red & 0xff00) << 16 |
- (color.green & 0xff00) << 8 |
- (color.blue & 0xff00) |
- 0xff);
- color_changed = TRUE;
- break;
-
- case PROP_FILL_COLOR_GDK:
- pcolor = g_value_get_boxed (value);
- if (pcolor) {
- color = *pcolor;
- }
-
- ecb->priv->rgba = ((color.red & 0xff00) << 16 |
- (color.green & 0xff00) << 8 |
- (color.blue & 0xff00) |
- 0xff);
- color_changed = TRUE;
- break;
-
- case PROP_FILL_COLOR_RGBA:
- ecb->priv->rgba = g_value_get_uint (value);
- color.red = ((ecb->priv->rgba >> 24) & 0xff) * 0x101;
- color.green = ((ecb->priv->rgba >> 16) & 0xff) * 0x101;
- color.blue = ((ecb->priv->rgba >> 8) & 0xff) * 0x101;
- color_changed = TRUE;
- break;
-
- case PROP_FILL_STIPPLE:
- set_stipple (ecb, g_value_get_object (value), TRUE);
- break;
-
- case PROP_X1:
- ecb->priv->x1 = g_value_get_double (value);
- break;
- case PROP_X2:
- ecb->priv->x2 = g_value_get_double (value);
- break;
- case PROP_Y1:
- ecb->priv->y1 = g_value_get_double (value);
- break;
- case PROP_Y2:
- ecb->priv->y2 = g_value_get_double (value);
- break;
- }
-
- if (color_changed) {
- ecb->priv->color = color;
-
- if (GNOME_CANVAS_ITEM_REALIZED & GTK_OBJECT_FLAGS(item)) {
- get_color (ecb);
- if (!item->canvas->aa) {
- gdk_gc_set_foreground (ecb->priv->gc, &ecb->priv->color);
- }
- }
- }
-
- ecb->priv->needs_redraw = 1;
- gnome_canvas_item_request_update (GNOME_CANVAS_ITEM(ecb));
-}
-
-static void
-ecb_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- GnomeCanvasItem *item;
- ECanvasBackground *ecb;
-
- item = GNOME_CANVAS_ITEM (object);
- ecb = E_CANVAS_BACKGROUND (object);
-
- switch (prop_id){
- case PROP_FILL_COLOR_GDK:
- g_value_set_boxed (value, gdk_color_copy (&ecb->priv->color));
- break;
- case PROP_FILL_COLOR_RGBA:
- g_value_set_uint (value, ecb->priv->rgba);
- break;
- case PROP_FILL_STIPPLE:
- g_value_set_object (value, ecb->priv->stipple);
- break;
- case PROP_X1:
- g_value_set_double (value, ecb->priv->x1);
- break;
- case PROP_X2:
- g_value_set_double (value, ecb->priv->x2);
- break;
- case PROP_Y1:
- g_value_set_double (value, ecb->priv->y1);
- break;
- case PROP_Y2:
- g_value_set_double (value, ecb->priv->y2);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-ecb_init (GnomeCanvasItem *item)
-{
- ECanvasBackground *ecb = E_CANVAS_BACKGROUND (item);
-
- ecb->priv = g_new (ECanvasBackgroundPrivate, 1);
-
- ecb->priv->color.pixel = 0;
- ecb->priv->color.red = 0;
- ecb->priv->color.green = 0;
- ecb->priv->color.blue = 0;
- ecb->priv->stipple = NULL;
- ecb->priv->gc = NULL;
- ecb->priv->x1 = -1.0;
- ecb->priv->x2 = -1.0;
- ecb->priv->y1 = -1.0;
- ecb->priv->y2 = -1.0;
-}
-
-static void
-ecb_realize (GnomeCanvasItem *item)
-{
- ECanvasBackground *ecb = E_CANVAS_BACKGROUND (item);
-
- if (GNOME_CANVAS_ITEM_CLASS (parent_class)->realize)
- GNOME_CANVAS_ITEM_CLASS (parent_class)->realize (item);
-
- ecb->priv->gc = gdk_gc_new (item->canvas->layout.bin_window);
- get_color (ecb);
- if (!item->canvas->aa)
- gdk_gc_set_foreground (ecb->priv->gc, &ecb->priv->color);
-
- set_stipple (ecb, NULL, FALSE);
-
- ecb->priv->needs_redraw = 1;
- gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (ecb));
-}
-
-static void
-ecb_unrealize (GnomeCanvasItem *item)
-{
- ECanvasBackground *ecb = E_CANVAS_BACKGROUND (item);
-
- gdk_gc_unref (ecb->priv->gc);
- ecb->priv->gc = NULL;
-
- if (GNOME_CANVAS_ITEM_CLASS (parent_class)->unrealize)
- GNOME_CANVAS_ITEM_CLASS (parent_class)->unrealize (item);
-}
-
-static void
-ecb_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, int height)
-{
- ECanvasBackground *ecb = E_CANVAS_BACKGROUND (item);
- int x1, x2, y1, y2;
- double i2c [6];
- ArtPoint upper_left, lower_right, ecb_base_point;
-
- /*
- * Find out our real position after grouping
- */
- gnome_canvas_item_i2c_affine (item, i2c);
- ecb_base_point.x = ecb->priv->x1;
- ecb_base_point.y = ecb->priv->y1;
- art_affine_point (&upper_left, &ecb_base_point, i2c);
-
- ecb_base_point.x = ecb->priv->x2;
- ecb_base_point.y = ecb->priv->y2;
- art_affine_point (&lower_right, &ecb_base_point, i2c);
-
- x1 = 0;
- y1 = 0;
- x2 = width;
- y2 = height;
- if (ecb->priv->x1 >= 0 && upper_left.x > x1)
- x1 = upper_left.x;
- if (ecb->priv->y1 >= 0 && upper_left.y > y1)
- y1 = upper_left.y;
- if (ecb->priv->x2 >= 0 && lower_right.x < x2)
- x2 = lower_right.x;
- if (ecb->priv->y2 >= 0 && lower_right.y < y2)
- y2 = lower_right.y;
-
- gdk_draw_rectangle (drawable, ecb->priv->gc, TRUE,
- x1, y1, x2 - x1, y2 - y1);
-}
-
-static double
-ecb_point (GnomeCanvasItem *item, double x, double y, int cx, int cy,
- GnomeCanvasItem **actual_item)
-{
- ECanvasBackground *ecb = E_CANVAS_BACKGROUND (item);
-
- if (ecb->priv->x1 >= 0 && ecb->priv->x1 > x)
- return 1.0;
- if (ecb->priv->x2 >= 0 && ecb->priv->x2 < x)
- return 1.0;
- if (ecb->priv->y1 >= 0 && ecb->priv->y1 > y)
- return 1.0;
- if (ecb->priv->y2 >= 0 && ecb->priv->y2 < y)
- return 1.0;
- *actual_item = item;
-
- return 0.0;
-}
-
-static void
-ecb_class_init (GObjectClass *object_class)
-{
- GnomeCanvasItemClass *item_class = (GnomeCanvasItemClass *) object_class;
-
- parent_class = g_type_class_ref (PARENT_OBJECT_TYPE);
-
- object_class->dispose = ecb_dispose;
- object_class->set_property = ecb_set_property;
- object_class->get_property = ecb_get_property;
-
- item_class->update = ecb_update;
- item_class->realize = ecb_realize;
- item_class->unrealize = ecb_unrealize;
- item_class->draw = ecb_draw;
- item_class->point = ecb_point;
-
- g_object_class_install_property (object_class, PROP_FILL_COLOR,
- g_param_spec_string ("fill_color",
- _( "Fill color" ),
- _( "Fill color" ),
- NULL,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class, PROP_FILL_COLOR_GDK,
- g_param_spec_boxed ("fill_color_gdk",
- _( "GDK fill color" ),
- _( "GDK fill color" ),
- GDK_TYPE_COLOR,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class, PROP_FILL_COLOR_RGBA,
- g_param_spec_uint ("fill_color_rgba",
- _( "GDK fill color" ),
- _( "GDK fill color" ),
- 0, G_MAXUINT, 0,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class, PROP_FILL_STIPPLE,
- g_param_spec_object ("fill_stipple",
- _( "Fill stipple" ),
- _( "FIll stipple" ),
- GDK_TYPE_WINDOW,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class, PROP_X1,
- g_param_spec_double ("x1",
- _( "X1" ),
- _( "X1" ),
- 0.0, G_MAXDOUBLE, 0.0,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class, PROP_X2,
- g_param_spec_double ("x2",
- _( "X2" ),
- _( "X2" ),
- 0.0, G_MAXDOUBLE, 0.0,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class, PROP_Y1,
- g_param_spec_double ("y1",
- _( "Y1" ),
- _( "Y1" ),
- 0.0, G_MAXDOUBLE, 0.0,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class, PROP_Y2,
- g_param_spec_double ("y2",
- _( "Y2" ),
- _( "Y2" ),
- 0.0, G_MAXDOUBLE, 0.0,
- G_PARAM_READWRITE));
-}
-
-E_MAKE_TYPE (e_canvas_background,
- "ECanvasBackground",
- ECanvasBackground,
- ecb_class_init,
- ecb_init,
- PARENT_OBJECT_TYPE)
diff --git a/widgets/misc/e-canvas-background.h b/widgets/misc/e-canvas-background.h
deleted file mode 100644
index 4a8e3294fb..0000000000
--- a/widgets/misc/e-canvas-background.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-canvas-background.h - background color for canvas.
- * Copyright 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef E_CANVAS_BACKGROUND_H
-#define E_CANVAS_BACKGROUND_H
-
-#include <libgnomecanvas/gnome-canvas.h>
-
-G_BEGIN_DECLS
-
-/*
- * name type read/write description
- * ------------------------------------------------------------------------------------------
- * fill_color string W X color specification for fill color,
- * or NULL pointer for no color (transparent)
- * fill_color_gdk GdkColor* RW Allocated GdkColor for fill
- * fill_stipple GdkBitmap* RW Stipple pattern for fill
- * x1 double RW Coordinates for edges of background rectangle
- * x2 double RW Default is all of them = -1.
- * y1 double RW Which means that the entire space is shown.
- * y2 double RW If you need the rectangle to have negative coordinates, use an affine.
- */
-
-
-#define E_CANVAS_BACKGROUND_TYPE (e_canvas_background_get_type ())
-#define E_CANVAS_BACKGROUND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_CANVAS_BACKGROUND_TYPE, ECanvasBackground))
-#define E_CANVAS_BACKGROUND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_CANVAS_BACKGROUND_TYPE, ECanvasBackgroundClass))
-#define E_IS_CANVAS_BACKGROUND(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_CANVAS_BACKGROUND_TYPE))
-#define E_IS_CANVAS_BACKGROUND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), E_CANVAS_BACKGROUND_TYPE))
-
-typedef struct _ECanvasBackground ECanvasBackground;
-typedef struct _ECanvasBackgroundClass ECanvasBackgroundClass;
-typedef struct _ECanvasBackgroundPrivate ECanvasBackgroundPrivate;
-
-struct _ECanvasBackground {
- GnomeCanvasItem item;
-
- ECanvasBackgroundPrivate *priv;
-};
-
-struct _ECanvasBackgroundClass {
- GnomeCanvasItemClass parent_class;
-};
-
-
-/* Standard Gtk function */
-GtkType e_canvas_background_get_type (void);
-
-G_END_DECLS
-
-#endif
diff --git a/widgets/misc/e-canvas-utils.c b/widgets/misc/e-canvas-utils.c
deleted file mode 100644
index 629804a2d7..0000000000
--- a/widgets/misc/e-canvas-utils.c
+++ /dev/null
@@ -1,171 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-canvas-utils.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include "e-canvas-utils.h"
-
-void
-e_canvas_item_move_absolute (GnomeCanvasItem *item, double dx, double dy)
-{
- double translate[6];
-
- g_return_if_fail (item != NULL);
- g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
-
- art_affine_translate (translate, dx, dy);
-
- gnome_canvas_item_affine_absolute (item, translate);
-}
-
-static double
-compute_offset(int top, int bottom, int page_top, int page_bottom)
-{
- int size = bottom - top;
- int offset = 0;
-
- if (top <= page_top && bottom >= page_bottom)
- return 0;
-
- if (bottom > page_bottom)
- offset = (bottom - page_bottom);
- if (top < page_top + offset)
- offset = (top - page_top);
-
- if (top <= page_top + offset && bottom >= page_bottom + offset)
- return offset;
-
- if (top < page_top + size * 3 / 2 + offset)
- offset = top - (page_top + size * 3 / 2);
- if (bottom > page_bottom - size * 3 / 2 + offset)
- offset = bottom - (page_bottom - size * 3 / 2);
- if (top < page_top + size * 3 / 2 + offset)
- offset = top - ((page_top + page_bottom - (bottom - top)) / 2);
-
- return offset;
-}
-
-
-static void
-e_canvas_show_area (GnomeCanvas *canvas, double x1, double y1, double x2, double y2)
-{
- GtkAdjustment *h, *v;
- int dx = 0, dy = 0;
-
- g_return_if_fail (canvas != NULL);
- g_return_if_fail (GNOME_IS_CANVAS (canvas));
-
- h = gtk_layout_get_hadjustment(GTK_LAYOUT(canvas));
- dx = compute_offset(x1, x2, h->value, h->value + h->page_size);
- if (dx)
- gtk_adjustment_set_value(h, CLAMP(h->value + dx, h->lower, h->upper - h->page_size));
-
- v = gtk_layout_get_vadjustment(GTK_LAYOUT(canvas));
- dy = compute_offset(y1, y2, v->value, v->value + v->page_size);
- if (dy)
- gtk_adjustment_set_value(v, CLAMP(v->value + dy, v->lower, v->upper - v->page_size));
-}
-
-void
-e_canvas_item_show_area (GnomeCanvasItem *item, double x1, double y1, double x2, double y2)
-{
- g_return_if_fail (item != NULL);
- g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
-
- gnome_canvas_item_i2w(item, &x1, &y1);
- gnome_canvas_item_i2w(item, &x2, &y2);
-
- e_canvas_show_area(item->canvas, x1, y1, x2, y2);
-}
-
-
-static gboolean
-e_canvas_area_shown (GnomeCanvas *canvas, double x1, double y1, double x2, double y2)
-{
- GtkAdjustment *h, *v;
- int dx = 0, dy = 0;
-
- g_return_val_if_fail (canvas != NULL, FALSE);
- g_return_val_if_fail (GNOME_IS_CANVAS (canvas), FALSE);
-
- h = gtk_layout_get_hadjustment(GTK_LAYOUT(canvas));
- dx = compute_offset(x1, x2, h->value, h->value + h->page_size);
- if (CLAMP(h->value + dx, h->lower, h->upper - h->page_size) - h->value != 0)
- return FALSE;
-
- v = gtk_layout_get_vadjustment(GTK_LAYOUT(canvas));
- dy = compute_offset(y1, y2, v->value, v->value + v->page_size);
- if (CLAMP(v->value + dy, v->lower, v->upper - v->page_size) - v->value != 0)
- return FALSE;
- return TRUE;
-}
-
-gboolean
-e_canvas_item_area_shown (GnomeCanvasItem *item, double x1, double y1, double x2, double y2)
-{
- g_return_val_if_fail (item != NULL, FALSE);
- g_return_val_if_fail (GNOME_IS_CANVAS_ITEM (item), FALSE);
-
- gnome_canvas_item_i2w(item, &x1, &y1);
- gnome_canvas_item_i2w(item, &x2, &y2);
-
- return e_canvas_area_shown(item->canvas, x1, y1, x2, y2);
-}
-
-typedef struct {
- double x1;
- double y1;
- double x2;
- double y2;
- GnomeCanvas *canvas;
-} DoubsAndCanvas;
-
-static gboolean
-show_area_timeout (gpointer data)
-{
- DoubsAndCanvas *dac = data;
-
- e_canvas_show_area(dac->canvas, dac->x1, dac->y1, dac->x2, dac->y2);
- g_object_unref (dac->canvas);
- g_free(dac);
- return FALSE;
-}
-
-void
-e_canvas_item_show_area_delayed (GnomeCanvasItem *item, double x1, double y1, double x2, double y2, gint delay)
-{
- DoubsAndCanvas *dac;
-
- g_return_if_fail (item != NULL);
- g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
-
- gnome_canvas_item_i2w(item, &x1, &y1);
- gnome_canvas_item_i2w(item, &x2, &y2);
-
- dac = g_new(DoubsAndCanvas, 1);
- dac->x1 = x1;
- dac->y1 = y1;
- dac->x2 = x2;
- dac->y2 = y2;
- dac->canvas = item->canvas;
- g_object_ref (item->canvas);
- g_timeout_add(delay, show_area_timeout, dac);
-}
diff --git a/widgets/misc/e-canvas-utils.h b/widgets/misc/e-canvas-utils.h
deleted file mode 100644
index 5b1a329140..0000000000
--- a/widgets/misc/e-canvas-utils.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef __E_CANVAS_UTILS__
-#define __E_CANVAS_UTILS__
-
-#include <libgnomecanvas/gnome-canvas.h>
-
-G_BEGIN_DECLS
-
-void e_canvas_item_move_absolute (GnomeCanvasItem *item,
- double dx,
- double dy);
-void e_canvas_item_show_area (GnomeCanvasItem *item,
- double x1,
- double y1,
- double x2,
- double y2);
-void e_canvas_item_show_area_delayed (GnomeCanvasItem *item,
- double x1,
- double y1,
- double x2,
- double y2,
- gint delay);
-/* Returns TRUE if the area is already shown on the screen (including
- spacing.) This is equivelent to returning FALSE iff show_area
- would do anything. */
-gboolean e_canvas_item_area_shown (GnomeCanvasItem *item,
- double x1,
- double y1,
- double x2,
- double y2);
-
-G_END_DECLS
-
-#endif /* __E_CANVAS_UTILS__ */
diff --git a/widgets/misc/e-canvas-vbox.c b/widgets/misc/e-canvas-vbox.c
deleted file mode 100644
index 354da5d872..0000000000
--- a/widgets/misc/e-canvas-vbox.c
+++ /dev/null
@@ -1,381 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-canvas-vbox.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <math.h>
-#include <gdk/gdkkeysyms.h>
-#include <gtk/gtksignal.h>
-#include "e-canvas-vbox.h"
-#include "e-canvas-utils.h"
-#include "e-canvas.h"
-#include "gal/util/e-util.h"
-#include "gal/util/e-i18n.h"
-
-static void e_canvas_vbox_init (ECanvasVbox *CanvasVbox);
-static void e_canvas_vbox_class_init (ECanvasVboxClass *klass);
-static void e_canvas_vbox_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
-static void e_canvas_vbox_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
-static void e_canvas_vbox_dispose (GObject *object);
-
-static gint e_canvas_vbox_event (GnomeCanvasItem *item, GdkEvent *event);
-static void e_canvas_vbox_realize (GnomeCanvasItem *item);
-
-static void e_canvas_vbox_reflow (GnomeCanvasItem *item, int flags);
-
-static void e_canvas_vbox_real_add_item(ECanvasVbox *e_canvas_vbox, GnomeCanvasItem *item);
-static void e_canvas_vbox_real_add_item_start(ECanvasVbox *e_canvas_vbox, GnomeCanvasItem *item);
-static void e_canvas_vbox_resize_children (GnomeCanvasItem *item);
-
-#define PARENT_TYPE GNOME_TYPE_CANVAS_GROUP
-static GnomeCanvasGroupClass *parent_class = NULL;
-
-/* The arguments we take */
-enum {
- PROP_0,
- PROP_WIDTH,
- PROP_MINIMUM_WIDTH,
- PROP_HEIGHT,
- PROP_SPACING
-};
-
-E_MAKE_TYPE (e_canvas_vbox,
- "ECanvasVbox",
- ECanvasVbox,
- e_canvas_vbox_class_init,
- e_canvas_vbox_init,
- PARENT_TYPE)
-
-static void
-e_canvas_vbox_class_init (ECanvasVboxClass *klass)
-{
- GObjectClass *object_class;
- GnomeCanvasItemClass *item_class;
-
- object_class = (GObjectClass*) klass;
- item_class = (GnomeCanvasItemClass *) klass;
-
- parent_class = g_type_class_ref (PARENT_TYPE);
-
- klass->add_item = e_canvas_vbox_real_add_item;
- klass->add_item_start = e_canvas_vbox_real_add_item_start;
-
- object_class->set_property = e_canvas_vbox_set_property;
- object_class->get_property = e_canvas_vbox_get_property;
- object_class->dispose = e_canvas_vbox_dispose;
-
- /* GnomeCanvasItem method overrides */
- item_class->event = e_canvas_vbox_event;
- item_class->realize = e_canvas_vbox_realize;
-
- g_object_class_install_property (object_class, PROP_WIDTH,
- g_param_spec_double ("width",
- _( "Width" ),
- _( "Width" ),
- 0.0, G_MAXDOUBLE, 0.0,
- G_PARAM_READWRITE));
- 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_HEIGHT,
- g_param_spec_double ("height",
- _( "Height" ),
- _( "Height" ),
- 0.0, G_MAXDOUBLE, 0.0,
- G_PARAM_READABLE));
- g_object_class_install_property (object_class, PROP_SPACING,
- g_param_spec_double ("spacing",
- _( "Spacing" ),
- _( "Spacing" ),
- 0.0, G_MAXDOUBLE, 0.0,
- G_PARAM_READWRITE));
-}
-
-static void
-e_canvas_vbox_init (ECanvasVbox *vbox)
-{
- vbox->items = NULL;
-
- vbox->width = 10;
- vbox->minimum_width = 10;
- vbox->height = 10;
- vbox->spacing = 0;
-
- e_canvas_item_set_reflow_callback(GNOME_CANVAS_ITEM(vbox), e_canvas_vbox_reflow);
-}
-
-static void
-e_canvas_vbox_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
-{
- GnomeCanvasItem *item;
- ECanvasVbox *e_canvas_vbox;
-
- item = GNOME_CANVAS_ITEM (object);
- e_canvas_vbox = E_CANVAS_VBOX (object);
-
- switch (prop_id){
- case PROP_WIDTH:
- case PROP_MINIMUM_WIDTH:
- e_canvas_vbox->minimum_width = g_value_get_double (value);
- e_canvas_vbox_resize_children(item);
- e_canvas_item_request_reflow(item);
- break;
- case PROP_SPACING:
- e_canvas_vbox->spacing = g_value_get_double (value);
- e_canvas_item_request_reflow(item);
- break;
- }
-}
-
-static void
-e_canvas_vbox_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
-{
- ECanvasVbox *e_canvas_vbox;
-
- e_canvas_vbox = E_CANVAS_VBOX (object);
-
- switch (prop_id) {
- case PROP_WIDTH:
- g_value_set_double (value, e_canvas_vbox->width);
- break;
- case PROP_MINIMUM_WIDTH:
- g_value_set_double (value, e_canvas_vbox->minimum_width);
- break;
- case PROP_HEIGHT:
- g_value_set_double (value, e_canvas_vbox->height);
- break;
- case PROP_SPACING:
- g_value_set_double (value, e_canvas_vbox->spacing);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-/* Used from g_list_foreach(); disconnects from an item's signals */
-static void
-disconnect_item_cb (gpointer data, gpointer user_data)
-{
- ECanvasVbox *vbox;
- GnomeCanvasItem *item;
-
- vbox = E_CANVAS_VBOX (user_data);
-
- item = GNOME_CANVAS_ITEM (data);
- g_signal_handlers_disconnect_matched (item,
- G_SIGNAL_MATCH_DATA,
- 0, 0, NULL, NULL,
- vbox);
-}
-
-static void
-e_canvas_vbox_dispose (GObject *object)
-{
- ECanvasVbox *vbox = E_CANVAS_VBOX(object);
-
- if (vbox->items) {
- g_list_foreach(vbox->items, disconnect_item_cb, vbox);
- g_list_free(vbox->items);
- vbox->items = NULL;
- }
-
- G_OBJECT_CLASS(parent_class)->dispose (object);
-}
-
-static gint
-e_canvas_vbox_event (GnomeCanvasItem *item, GdkEvent *event)
-{
- gint return_val = TRUE;
-
- switch (event->type) {
- case GDK_KEY_PRESS:
- switch (event->key.keyval) {
- case GDK_Left:
- case GDK_KP_Left:
- case GDK_Right:
- case GDK_KP_Right:
- case GDK_Down:
- case GDK_KP_Down:
- case GDK_Up:
- case GDK_KP_Up:
- case GDK_Return:
- case GDK_KP_Enter:
- return_val = TRUE;
- break;
- default:
- return_val = FALSE;
- break;
- }
- break;
- default:
- return_val = FALSE;
- break;
- }
- if (!return_val) {
- if (GNOME_CANVAS_ITEM_CLASS(parent_class)->event)
- return GNOME_CANVAS_ITEM_CLASS (parent_class)->event (item, event);
- }
- return return_val;
-
-}
-
-static void
-e_canvas_vbox_realize (GnomeCanvasItem *item)
-{
- if (GNOME_CANVAS_ITEM_CLASS(parent_class)->realize)
- (* GNOME_CANVAS_ITEM_CLASS(parent_class)->realize) (item);
-
- e_canvas_vbox_resize_children(item);
- e_canvas_item_request_reflow(item);
-}
-
-static void
-e_canvas_vbox_remove_item (gpointer data, GObject *where_object_was)
-{
- ECanvasVbox *vbox = data;
- vbox->items = g_list_remove(vbox->items, where_object_was);
-}
-
-static void
-e_canvas_vbox_real_add_item(ECanvasVbox *e_canvas_vbox, GnomeCanvasItem *item)
-{
- e_canvas_vbox->items = g_list_append(e_canvas_vbox->items, item);
- g_object_weak_ref (G_OBJECT (item),
- e_canvas_vbox_remove_item, e_canvas_vbox);
- if ( GTK_OBJECT_FLAGS( e_canvas_vbox ) & GNOME_CANVAS_ITEM_REALIZED ) {
- gnome_canvas_item_set(item,
- "width", (double) e_canvas_vbox->minimum_width,
- NULL);
- e_canvas_item_request_reflow(item);
- }
-}
-
-
-static void
-e_canvas_vbox_real_add_item_start(ECanvasVbox *e_canvas_vbox, GnomeCanvasItem *item)
-{
- e_canvas_vbox->items = g_list_prepend(e_canvas_vbox->items, item);
- g_object_weak_ref (G_OBJECT (item),
- e_canvas_vbox_remove_item, e_canvas_vbox);
- if ( GTK_OBJECT_FLAGS( e_canvas_vbox ) & GNOME_CANVAS_ITEM_REALIZED ) {
- gnome_canvas_item_set(item,
- "width", (double) e_canvas_vbox->minimum_width,
- NULL);
- e_canvas_item_request_reflow(item);
- }
-}
-
-static void
-e_canvas_vbox_resize_children (GnomeCanvasItem *item)
-{
- GList *list;
- ECanvasVbox *e_canvas_vbox;
-
- e_canvas_vbox = E_CANVAS_VBOX (item);
- for ( list = e_canvas_vbox->items; list; list = list->next ) {
- GnomeCanvasItem *child = GNOME_CANVAS_ITEM(list->data);
- gnome_canvas_item_set(child,
- "width", (double) e_canvas_vbox->minimum_width,
- NULL);
- }
-}
-
-static void
-e_canvas_vbox_reflow( GnomeCanvasItem *item, int flags )
-{
- ECanvasVbox *e_canvas_vbox = E_CANVAS_VBOX(item);
- if ( GTK_OBJECT_FLAGS( e_canvas_vbox ) & GNOME_CANVAS_ITEM_REALIZED ) {
-
- gdouble old_height;
- gdouble running_height;
- gdouble old_width;
- gdouble max_width;
-
- old_width = e_canvas_vbox->width;
- max_width = e_canvas_vbox->minimum_width;
-
- old_height = e_canvas_vbox->height;
- running_height = 0;
-
- if (e_canvas_vbox->items == NULL) {
- } else {
- GList *list;
- gdouble item_height;
- gdouble item_width;
-
- list = e_canvas_vbox->items;
- g_object_get (list->data,
- "height", &item_height,
- "width", &item_width,
- NULL);
- e_canvas_item_move_absolute(GNOME_CANVAS_ITEM(list->data),
- (double) 0,
- (double) running_height);
- running_height += item_height;
- if (max_width < item_width)
- max_width = item_width;
- list = g_list_next(list);
-
- for( ; list; list = g_list_next(list)) {
- running_height += e_canvas_vbox->spacing;
-
- g_object_get (list->data,
- "height", &item_height,
- "width", &item_width,
- NULL);
-
- e_canvas_item_move_absolute(GNOME_CANVAS_ITEM(list->data),
- (double) 0,
- (double) running_height);
-
- running_height += item_height;
- if (max_width < item_width)
- max_width = item_width;
- }
-
- }
- e_canvas_vbox->height = running_height;
- e_canvas_vbox->width = max_width;
- if (old_height != e_canvas_vbox->height ||
- old_width != e_canvas_vbox->width)
- e_canvas_item_request_parent_reflow(item);
- }
-}
-
-void
-e_canvas_vbox_add_item(ECanvasVbox *e_canvas_vbox, GnomeCanvasItem *item)
-{
- if (E_CANVAS_VBOX_CLASS(GTK_OBJECT_GET_CLASS(e_canvas_vbox))->add_item)
- (E_CANVAS_VBOX_CLASS(GTK_OBJECT_GET_CLASS(e_canvas_vbox))->add_item) (e_canvas_vbox, item);
-}
-
-void
-e_canvas_vbox_add_item_start(ECanvasVbox *e_canvas_vbox, GnomeCanvasItem *item)
-{
- if (E_CANVAS_VBOX_CLASS(GTK_OBJECT_GET_CLASS(e_canvas_vbox))->add_item_start)
- (E_CANVAS_VBOX_CLASS(GTK_OBJECT_GET_CLASS(e_canvas_vbox))->add_item_start) (e_canvas_vbox, item);
-}
-
diff --git a/widgets/misc/e-canvas-vbox.h b/widgets/misc/e-canvas-vbox.h
deleted file mode 100644
index 7d80e7c056..0000000000
--- a/widgets/misc/e-canvas-vbox.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-canvas-vbox.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef __E_CANVAS_VBOX_H__
-#define __E_CANVAS_VBOX_H__
-
-#include <gtk/gtktypeutils.h>
-#include <libgnomecanvas/gnome-canvas.h>
-
-#ifdef __cplusplus
-extern "C" {
-#pragma }
-#endif /* __cplusplus */
-
-/* ECanvasVbox - A canvas item container.
- *
- * The following arguments are available:
- *
- * name type read/write description
- * --------------------------------------------------------------------------------
- * width double RW width of the CanvasVbox
- * height double R height of the CanvasVbox
- * spacing double RW Spacing between items.
- */
-
-#define E_CANVAS_VBOX_TYPE (e_canvas_vbox_get_type ())
-#define E_CANVAS_VBOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_CANVAS_VBOX_TYPE, ECanvasVbox))
-#define E_CANVAS_VBOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_CANVAS_VBOX_TYPE, ECanvasVboxClass))
-#define E_IS_CANVAS_VBOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_CANVAS_VBOX_TYPE))
-#define E_IS_CANVAS_VBOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), E_CANVAS_VBOX_TYPE))
-
-
-typedef struct _ECanvasVbox ECanvasVbox;
-typedef struct _ECanvasVboxClass ECanvasVboxClass;
-
-struct _ECanvasVbox
-{
- GnomeCanvasGroup parent;
-
- /* item specific fields */
- GList *items; /* Of type GnomeCanvasItem */
-
- double width;
- double minimum_width;
- double height;
- double spacing;
-};
-
-struct _ECanvasVboxClass
-{
- GnomeCanvasGroupClass parent_class;
-
- /* Virtual methods. */
- void (* add_item) (ECanvasVbox *CanvasVbox, GnomeCanvasItem *item);
- void (* add_item_start) (ECanvasVbox *CanvasVbox, GnomeCanvasItem *item);
-};
-
-/*
- * To be added to a CanvasVbox, 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 CanvasVbox request if its size
- * changes.
- */
-void e_canvas_vbox_add_item(ECanvasVbox *e_canvas_vbox, GnomeCanvasItem *item);
-void e_canvas_vbox_add_item_start(ECanvasVbox *e_canvas_vbox, GnomeCanvasItem *item);
-GtkType e_canvas_vbox_get_type (void);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-
-#endif /* __E_CANVAS_VBOX_H__ */
diff --git a/widgets/misc/e-canvas.c b/widgets/misc/e-canvas.c
deleted file mode 100644
index 8be100fb4a..0000000000
--- a/widgets/misc/e-canvas.c
+++ /dev/null
@@ -1,1096 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-canvas.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <gtk/gtksignal.h>
-#include "e-canvas.h"
-#include "gal/util/e-util.h"
-#include <X11/Xlib.h>
-#include <gtk/gtkmain.h>
-#include <gtk/gtkimmulticontext.h>
-
-static void e_canvas_init (ECanvas *card);
-static void e_canvas_dispose (GObject *object);
-static void e_canvas_class_init (ECanvasClass *klass);
-static void e_canvas_realize (GtkWidget *widget);
-static void e_canvas_unrealize (GtkWidget *widget);
-static gint e_canvas_key (GtkWidget *widget,
- GdkEventKey *event);
-static gint e_canvas_button (GtkWidget *widget,
- GdkEventButton *event);
-
-static gint e_canvas_visibility (GtkWidget *widget,
- GdkEventVisibility *event,
- ECanvas *canvas);
-
-static gint e_canvas_focus_in (GtkWidget *widget,
- GdkEventFocus *event);
-static gint e_canvas_focus_out (GtkWidget *widget,
- GdkEventFocus *event);
-
-static void e_canvas_style_set (GtkWidget *widget,
- GtkStyle *previous_style);
-
-static int emit_event (GnomeCanvas *canvas, GdkEvent *event);
-
-#define PARENT_TYPE GNOME_TYPE_CANVAS
-static GnomeCanvasClass *parent_class = NULL;
-
-#define d(x)
-
-enum {
- REFLOW,
- LAST_SIGNAL
-};
-
-static guint e_canvas_signals [LAST_SIGNAL] = { 0, };
-
-E_MAKE_TYPE (e_canvas,
- "ECanvas",
- ECanvas,
- e_canvas_class_init,
- e_canvas_init,
- PARENT_TYPE)
-
-static void
-e_canvas_class_init (ECanvasClass *klass)
-{
- GObjectClass *object_class;
- GnomeCanvasClass *canvas_class;
- GtkWidgetClass *widget_class;
-
- object_class = (GObjectClass*) klass;
- canvas_class = (GnomeCanvasClass *) klass;
- widget_class = (GtkWidgetClass *) klass;
-
- parent_class = g_type_class_ref (PARENT_TYPE);
-
- object_class->dispose = e_canvas_dispose;
-
- widget_class->key_press_event = e_canvas_key;
- widget_class->key_release_event = e_canvas_key;
- widget_class->button_press_event = e_canvas_button;
- widget_class->button_release_event = e_canvas_button;
- widget_class->focus_in_event = e_canvas_focus_in;
- widget_class->focus_out_event = e_canvas_focus_out;
- widget_class->style_set = e_canvas_style_set;
- widget_class->realize = e_canvas_realize;
- widget_class->unrealize = e_canvas_unrealize;
-
- klass->reflow = NULL;
-
- e_canvas_signals [REFLOW] =
- g_signal_new ("reflow",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ECanvasClass, reflow),
- NULL, NULL,
- e_marshal_NONE__NONE,
- G_TYPE_NONE, 0);
-}
-
-static void
-e_canvas_init (ECanvas *canvas)
-{
- canvas->selection = NULL;
- canvas->cursor = NULL;
- canvas->im_context = gtk_im_multicontext_new ();
- canvas->tooltip_window = NULL;
-}
-
-static void
-e_canvas_dispose (GObject *object)
-{
- ECanvas *canvas = E_CANVAS(object);
-
- if (canvas->idle_id)
- g_source_remove(canvas->idle_id);
- canvas->idle_id = 0;
-
- if (canvas->grab_cancelled_check_id)
- g_source_remove (canvas->grab_cancelled_check_id);
- canvas->grab_cancelled_check_id = 0;
-
- if (canvas->toplevel) {
- if (canvas->visibility_notify_id)
- g_signal_handler_disconnect (canvas->toplevel,
- canvas->visibility_notify_id);
- canvas->visibility_notify_id = 0;
-
- g_object_unref (canvas->toplevel);
- canvas->toplevel = NULL;
- }
-
- if (canvas->im_context) {
- g_object_unref (canvas->im_context);
- canvas->im_context = NULL;
- }
-
- e_canvas_hide_tooltip(canvas);
-
- if ((G_OBJECT_CLASS (parent_class))->dispose)
- (*(G_OBJECT_CLASS (parent_class))->dispose) (object);
-}
-
-GtkWidget *
-e_canvas_new ()
-{
- return GTK_WIDGET (g_object_new (E_CANVAS_TYPE, NULL));
-}
-
-
-/* Emits an event for an item in the canvas, be it the current item, grabbed
- * item, or focused item, as appropriate.
- */
-static int
-emit_event (GnomeCanvas *canvas, GdkEvent *event)
-{
- GdkEvent *ev;
- gint finished;
- GnomeCanvasItem *item;
- GnomeCanvasItem *parent;
- guint mask;
-
- /* Choose where we send the event */
-
- item = canvas->current_item;
-
- if (canvas->focused_item
- && ((event->type == GDK_KEY_PRESS) || (event->type == GDK_KEY_RELEASE) || (event->type == GDK_FOCUS_CHANGE)))
- item = canvas->focused_item;
-
- if (canvas->grabbed_item)
- item = canvas->grabbed_item;
-
- /* Perform checks for grabbed items */
-
- if (canvas->grabbed_item) {
- switch (event->type) {
- case GDK_ENTER_NOTIFY:
- mask = GDK_ENTER_NOTIFY_MASK;
- break;
-
- case GDK_LEAVE_NOTIFY:
- mask = GDK_LEAVE_NOTIFY_MASK;
- break;
-
- case GDK_MOTION_NOTIFY:
- mask = GDK_POINTER_MOTION_MASK;
- break;
-
- case GDK_BUTTON_PRESS:
- case GDK_2BUTTON_PRESS:
- case GDK_3BUTTON_PRESS:
- mask = GDK_BUTTON_PRESS_MASK;
- break;
-
- case GDK_BUTTON_RELEASE:
- mask = GDK_BUTTON_RELEASE_MASK;
- break;
-
- case GDK_KEY_PRESS:
- mask = GDK_KEY_PRESS_MASK;
- break;
-
- case GDK_KEY_RELEASE:
- mask = GDK_KEY_RELEASE_MASK;
- break;
-
- default:
- mask = 0;
- break;
- }
-
- if (!(mask & canvas->grabbed_event_mask))
- return FALSE;
- }
-
- /* Convert to world coordinates -- we have two cases because of diferent
- * offsets of the fields in the event structures.
- */
-
- ev = gdk_event_copy (event);
-
- switch (ev->type) {
- case GDK_ENTER_NOTIFY:
- case GDK_LEAVE_NOTIFY:
- gnome_canvas_window_to_world (canvas,
- ev->crossing.x, ev->crossing.y,
- &ev->crossing.x, &ev->crossing.y);
- break;
-
- case GDK_MOTION_NOTIFY:
- case GDK_BUTTON_PRESS:
- case GDK_2BUTTON_PRESS:
- case GDK_3BUTTON_PRESS:
- case GDK_BUTTON_RELEASE:
- gnome_canvas_window_to_world (canvas,
- ev->motion.x, ev->motion.y,
- &ev->motion.x, &ev->motion.y);
- break;
-
- default:
- break;
- }
-
- /* The event is propagated up the hierarchy (for if someone connected to
- * a group instead of a leaf event), and emission is stopped if a
- * handler returns TRUE, just like for GtkWidget events.
- */
-
- finished = FALSE;
-
- while (item && !finished) {
- g_object_ref (item);
-
- g_signal_emit_by_name (item, "event", ev, &finished);
-
- parent = item->parent;
- g_object_unref (item);
-
- item = parent;
- }
-
- gdk_event_free (ev);
-
- return finished;
-}
-
-/* Key event handler for the canvas */
-static gint
-e_canvas_key (GtkWidget *widget, GdkEventKey *event)
-{
- GnomeCanvas *canvas;
- GdkEvent full_event;
-
- g_return_val_if_fail (widget != NULL, FALSE);
- g_return_val_if_fail (GNOME_IS_CANVAS (widget), FALSE);
- g_return_val_if_fail (event != NULL, FALSE);
-
- canvas = GNOME_CANVAS (widget);
-
- full_event.key = *event;
-
- return emit_event (canvas, &full_event);
-}
-
-
-/* This routine invokes the point method of the item. The argument x, y should
- * be in the parent's item-relative coordinate system. This routine applies the
- * inverse of the item's transform, maintaining the affine invariant.
- */
-#define HACKISH_AFFINE
-
-static double
-gnome_canvas_item_invoke_point (GnomeCanvasItem *item, double x, double y, int cx, int cy,
- GnomeCanvasItem **actual_item)
-{
-#ifdef HACKISH_AFFINE
- double i2w[6], w2c[6], i2c[6], c2i[6];
- ArtPoint c, i;
-#endif
-
-#ifdef HACKISH_AFFINE
- gnome_canvas_item_i2w_affine (item, i2w);
- gnome_canvas_w2c_affine (item->canvas, w2c);
- art_affine_multiply (i2c, i2w, w2c);
- art_affine_invert (c2i, i2c);
- c.x = cx;
- c.y = cy;
- art_affine_point (&i, &c, c2i);
- x = i.x;
- y = i.y;
-#endif
-
- return (* GNOME_CANVAS_ITEM_CLASS (GTK_OBJECT_GET_CLASS (item))->point) (
- item, x, y, cx, cy, actual_item);
-}
-
-/* Re-picks the current item in the canvas, based on the event's coordinates.
- * Also emits enter/leave events for items as appropriate.
- */
-#define DISPLAY_X1(canvas) (GNOME_CANVAS (canvas)->layout.xoffset)
-#define DISPLAY_Y1(canvas) (GNOME_CANVAS (canvas)->layout.yoffset)
-static int
-pick_current_item (GnomeCanvas *canvas, GdkEvent *event)
-{
- int button_down;
- double x, y;
- int cx, cy;
- int retval;
-
- retval = FALSE;
-
- /* If a button is down, we'll perform enter and leave events on the
- * current item, but not enter on any other item. This is more or less
- * like X pointer grabbing for canvas items.
- */
- button_down = canvas->state & (GDK_BUTTON1_MASK
- | GDK_BUTTON2_MASK
- | GDK_BUTTON3_MASK
- | GDK_BUTTON4_MASK
- | GDK_BUTTON5_MASK);
- d(g_print ("%s:%d: button_down = %s\n", __FUNCTION__, __LINE__, button_down ? "TRUE" : "FALSE"));
- if (!button_down)
- canvas->left_grabbed_item = FALSE;
-
- /* Save the event in the canvas. This is used to synthesize enter and
- * leave events in case the current item changes. It is also used to
- * re-pick the current item if the current one gets deleted. Also,
- * synthesize an enter event.
- */
- if (event != &canvas->pick_event) {
- if ((event->type == GDK_MOTION_NOTIFY) || (event->type == GDK_BUTTON_RELEASE)) {
- /* these fields have the same offsets in both types of events */
-
- canvas->pick_event.crossing.type = GDK_ENTER_NOTIFY;
- canvas->pick_event.crossing.window = event->motion.window;
- canvas->pick_event.crossing.send_event = event->motion.send_event;
- canvas->pick_event.crossing.subwindow = NULL;
- canvas->pick_event.crossing.x = event->motion.x;
- canvas->pick_event.crossing.y = event->motion.y;
- canvas->pick_event.crossing.mode = GDK_CROSSING_NORMAL;
- canvas->pick_event.crossing.detail = GDK_NOTIFY_NONLINEAR;
- canvas->pick_event.crossing.focus = FALSE;
- canvas->pick_event.crossing.state = event->motion.state;
-
- /* these fields don't have the same offsets in both types of events */
-
- if (event->type == GDK_MOTION_NOTIFY) {
- canvas->pick_event.crossing.x_root = event->motion.x_root;
- canvas->pick_event.crossing.y_root = event->motion.y_root;
- } else {
- canvas->pick_event.crossing.x_root = event->button.x_root;
- canvas->pick_event.crossing.y_root = event->button.y_root;
- }
- } else
- canvas->pick_event = *event;
- }
-
- /* Don't do anything else if this is a recursive call */
-
- if (canvas->in_repick)
- return retval;
-
- /* LeaveNotify means that there is no current item, so we don't look for one */
-
- if (canvas->pick_event.type != GDK_LEAVE_NOTIFY) {
- /* these fields don't have the same offsets in both types of events */
-
- if (canvas->pick_event.type == GDK_ENTER_NOTIFY) {
- x = canvas->pick_event.crossing.x + canvas->scroll_x1 - canvas->zoom_xofs;
- y = canvas->pick_event.crossing.y + canvas->scroll_y1 - canvas->zoom_yofs;
- } else {
- x = canvas->pick_event.motion.x + canvas->scroll_x1 - canvas->zoom_xofs;
- y = canvas->pick_event.motion.y + canvas->scroll_y1 - canvas->zoom_yofs;
- }
-
- /* canvas pixel coords */
-
- cx = (int) (x + 0.5);
- cy = (int) (y + 0.5);
-
- /* world coords */
-
- x = canvas->scroll_x1 + x / canvas->pixels_per_unit;
- y = canvas->scroll_y1 + y / canvas->pixels_per_unit;
-
- /* find the closest item */
-
- if (canvas->root->object.flags & GNOME_CANVAS_ITEM_VISIBLE)
- gnome_canvas_item_invoke_point (canvas->root, x, y, cx, cy,
- &canvas->new_current_item);
- else
- canvas->new_current_item = NULL;
- } else
- canvas->new_current_item = NULL;
-
- if ((canvas->new_current_item == canvas->current_item) && !canvas->left_grabbed_item)
- return retval; /* current item did not change */
-
- /* Synthesize events for old and new current items */
-
- if ((canvas->new_current_item != canvas->current_item)
- && (canvas->current_item != NULL)
- && !canvas->left_grabbed_item) {
- GdkEvent new_event;
- GnomeCanvasItem *item;
-
- item = canvas->current_item;
-
- new_event = canvas->pick_event;
- new_event.type = GDK_LEAVE_NOTIFY;
-
- new_event.crossing.detail = GDK_NOTIFY_ANCESTOR;
- new_event.crossing.subwindow = NULL;
- canvas->in_repick = TRUE;
- retval = emit_event (canvas, &new_event);
- canvas->in_repick = FALSE;
- }
-
- /* new_current_item may have been set to NULL during the call to emit_event() above */
-
- if ((canvas->new_current_item != canvas->current_item) && button_down) {
- canvas->left_grabbed_item = TRUE;
- return retval;
- }
-
- /* Handle the rest of cases */
-
- canvas->left_grabbed_item = FALSE;
- canvas->current_item = canvas->new_current_item;
-
- if (canvas->current_item != NULL) {
- GdkEvent new_event;
-
- new_event = canvas->pick_event;
- new_event.type = GDK_ENTER_NOTIFY;
- new_event.crossing.detail = GDK_NOTIFY_ANCESTOR;
- new_event.crossing.subwindow = NULL;
- retval = emit_event (canvas, &new_event);
- }
-
- return retval;
-}
-
-/* Button event handler for the canvas */
-static gint
-e_canvas_button (GtkWidget *widget, GdkEventButton *event)
-{
- GnomeCanvas *canvas;
- int mask;
- int retval;
-
- g_return_val_if_fail (widget != NULL, FALSE);
- g_return_val_if_fail (GNOME_IS_CANVAS (widget), FALSE);
- g_return_val_if_fail (event != NULL, FALSE);
-
- retval = FALSE;
-
- canvas = GNOME_CANVAS (widget);
-
- d(g_print ("button %d, event type %d, grabbed=%p, current=%p\n",
- event->button,
- event->type,
- canvas->grabbed_item,
- canvas->current_item));
-
- /* dispatch normally regardless of the event's window if an item has
- has a pointer grab in effect */
- if (!canvas->grabbed_item && event->window != canvas->layout.bin_window)
- return retval;
-
- switch (event->button) {
- case 1:
- mask = GDK_BUTTON1_MASK;
- break;
- case 2:
- mask = GDK_BUTTON2_MASK;
- break;
- case 3:
- mask = GDK_BUTTON3_MASK;
- break;
- case 4:
- mask = GDK_BUTTON4_MASK;
- break;
- case 5:
- mask = GDK_BUTTON5_MASK;
- break;
- default:
- mask = 0;
- }
-
- switch (event->type) {
- case GDK_BUTTON_PRESS:
- case GDK_2BUTTON_PRESS:
- case GDK_3BUTTON_PRESS:
- /* Pick the current item as if the button were not pressed, and
- * then process the event.
- */
- canvas->state = event->state;
- pick_current_item (canvas, (GdkEvent *) event);
- canvas->state ^= mask;
- retval = emit_event (canvas, (GdkEvent *) event);
- break;
-
- case GDK_BUTTON_RELEASE:
- /* Process the event as if the button were pressed, then repick
- * after the button has been released
- */
- canvas->state = event->state;
- retval = emit_event (canvas, (GdkEvent *) event);
- event->state ^= mask;
- canvas->state = event->state;
- pick_current_item (canvas, (GdkEvent *) event);
- event->state ^= mask;
- break;
-
- default:
- g_assert_not_reached ();
- }
-
- return retval;
-}
-
-/* Key event handler for the canvas */
-static gint
-e_canvas_visibility (GtkWidget *widget, GdkEventVisibility *event, ECanvas *canvas)
-{
- if (! canvas->visibility_first) {
- e_canvas_hide_tooltip(canvas);
- }
- canvas->visibility_first = FALSE;
-
- return FALSE;
-}
-
-
-/**
- * e_canvas_item_grab_focus:
- * @item: A canvas item.
- * @widget_too: Whether or not to grab the widget-level focus too
- *
- * Makes the specified item take the keyboard focus, so all keyboard
- * events will be sent to it. If the canvas widget itself did not have
- * the focus and @widget_too is %TRUE, it grabs that focus as well.
- **/
-void
-e_canvas_item_grab_focus (GnomeCanvasItem *item, gboolean widget_too)
-{
- GnomeCanvasItem *focused_item;
- GdkEvent ev;
-
- g_return_if_fail (item != NULL);
- g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
- g_return_if_fail (GTK_WIDGET_CAN_FOCUS (GTK_WIDGET (item->canvas)));
-
- focused_item = item->canvas->focused_item;
-
- if (focused_item) {
- ev.focus_change.type = GDK_FOCUS_CHANGE;
- ev.focus_change.window = GTK_LAYOUT (item->canvas)->bin_window;
- ev.focus_change.send_event = FALSE;
- ev.focus_change.in = FALSE;
-
- emit_event (item->canvas, &ev);
- }
-
- item->canvas->focused_item = item;
-
- if (widget_too && !GTK_WIDGET_HAS_FOCUS (GTK_WIDGET(item->canvas))) {
- gtk_widget_grab_focus (GTK_WIDGET (item->canvas));
- }
-
- if (item) {
- ev.focus_change.type = GDK_FOCUS_CHANGE;
- ev.focus_change.window = GTK_LAYOUT (item->canvas)->bin_window;
- ev.focus_change.send_event = FALSE;
- ev.focus_change.in = TRUE;
-
- emit_event (item->canvas, &ev);
- }
-}
-
-/* Focus in handler for the canvas */
-static gint
-e_canvas_focus_in (GtkWidget *widget, GdkEventFocus *event)
-{
- GnomeCanvas *canvas;
- ECanvas *ecanvas;
- GdkEvent full_event;
-
- canvas = GNOME_CANVAS (widget);
- ecanvas = E_CANVAS (widget);
-
- GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
-
- gtk_im_context_focus_in (ecanvas->im_context);
-
- if (canvas->focused_item) {
- full_event.focus_change = *event;
- return emit_event (canvas, &full_event);
- } else {
- return FALSE;
- }
-}
-
-/* Focus out handler for the canvas */
-static gint
-e_canvas_focus_out (GtkWidget *widget, GdkEventFocus *event)
-{
- GnomeCanvas *canvas;
- ECanvas *ecanvas;
- GdkEvent full_event;
-
- canvas = GNOME_CANVAS (widget);
- ecanvas = E_CANVAS (widget);
-
- GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
-
- gtk_im_context_focus_out (ecanvas->im_context);
-
- if (canvas->focused_item) {
- full_event.focus_change = *event;
- return emit_event (canvas, &full_event);
- } else {
- return FALSE;
- }
-}
-
-static void
-ec_style_set_recursive (GnomeCanvasItem *item, GtkStyle *previous_style)
-{
- guint signal_id = g_signal_lookup ("style_set", G_OBJECT_TYPE (item));
- if (signal_id >= 1) {
- GSignalQuery query;
- g_signal_query (signal_id, &query);
- if (query.return_type == GTK_TYPE_NONE && query.n_params == 1 && query.param_types[0] == GTK_TYPE_STYLE) {
- g_signal_emit (item, signal_id, 0, previous_style);
- }
- }
-
- if (GNOME_IS_CANVAS_GROUP (item) ) {
- GList *items = GNOME_CANVAS_GROUP (item)->item_list;
- for (; items; items = items->next)
- ec_style_set_recursive (items->data, previous_style);
- }
-}
-
-static void
-e_canvas_style_set (GtkWidget *widget, GtkStyle *previous_style)
-{
- ec_style_set_recursive (GNOME_CANVAS_ITEM (gnome_canvas_root (GNOME_CANVAS (widget))), previous_style);
-}
-
-
-static void
-e_canvas_realize (GtkWidget *widget)
-{
- ECanvas *ecanvas = E_CANVAS (widget);
-
- if (GTK_WIDGET_CLASS (parent_class)->realize)
- (* GTK_WIDGET_CLASS (parent_class)->realize) (widget);
-
- gdk_window_set_back_pixmap (GTK_LAYOUT (widget)->bin_window, NULL, FALSE);
-
- gtk_im_context_set_client_window (ecanvas->im_context, widget->window);
-}
-
-static void
-e_canvas_unrealize (GtkWidget *widget)
-{
- ECanvas * ecanvas = E_CANVAS (widget);
-
- if (ecanvas->idle_id) {
- g_source_remove(ecanvas->idle_id);
- ecanvas->idle_id = 0;
- }
-
- gtk_im_context_set_client_window (ecanvas->im_context, widget->window);
-
- if (GTK_WIDGET_CLASS (parent_class)->unrealize)
- (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
-}
-
-static void
-e_canvas_item_invoke_reflow (GnomeCanvasItem *item, int flags)
-{
- GnomeCanvasGroup *group;
- GList *list;
- GnomeCanvasItem *child;
-
- if (GNOME_IS_CANVAS_GROUP (item)) {
- group = GNOME_CANVAS_GROUP (item);
- for (list = group->item_list; list; list = list->next) {
- child = GNOME_CANVAS_ITEM (list->data);
- if (child->object.flags & E_CANVAS_ITEM_DESCENDENT_NEEDS_REFLOW)
- e_canvas_item_invoke_reflow (child, flags);
- }
- }
-
- if (item->object.flags & E_CANVAS_ITEM_NEEDS_REFLOW) {
- ECanvasItemReflowFunc func;
- func = (ECanvasItemReflowFunc)
- g_object_get_data (G_OBJECT (item),
- "ECanvasItem::reflow_callback");
- if (func)
- func (item, flags);
- }
-
- item->object.flags &= ~E_CANVAS_ITEM_NEEDS_REFLOW;
- item->object.flags &= ~E_CANVAS_ITEM_DESCENDENT_NEEDS_REFLOW;
-}
-
-static void
-do_reflow (ECanvas *canvas)
-{
- if (GNOME_CANVAS(canvas)->root->object.flags & E_CANVAS_ITEM_DESCENDENT_NEEDS_REFLOW)
- e_canvas_item_invoke_reflow (GNOME_CANVAS(canvas)->root, 0);
-}
-
-/* Idle handler for the e-canvas. It deals with pending reflows. */
-static gint
-idle_handler (gpointer data)
-{
- ECanvas *canvas;
-
- GDK_THREADS_ENTER();
-
- canvas = E_CANVAS (data);
- do_reflow (canvas);
-
- /* Reset idle id */
- canvas->idle_id = 0;
-
- g_signal_emit (canvas,
- e_canvas_signals [REFLOW], 0);
-
- GDK_THREADS_LEAVE();
-
- return FALSE;
-}
-
-/* Convenience function to add an idle handler to a canvas */
-static void
-add_idle (ECanvas *canvas)
-{
- if (canvas->idle_id != 0)
- return;
-
- canvas->idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_handler, (gpointer) canvas, NULL);
-}
-
-static void
-e_canvas_item_descendent_needs_reflow (GnomeCanvasItem *item)
-{
- if (item->object.flags & E_CANVAS_ITEM_DESCENDENT_NEEDS_REFLOW)
- return;
-
- item->object.flags |= E_CANVAS_ITEM_DESCENDENT_NEEDS_REFLOW;
- if (item->parent)
- e_canvas_item_descendent_needs_reflow(item->parent);
-}
-
-void
-e_canvas_item_request_reflow (GnomeCanvasItem *item)
-{
- if (item->object.flags & GNOME_CANVAS_ITEM_REALIZED) {
- item->object.flags |= E_CANVAS_ITEM_NEEDS_REFLOW;
- e_canvas_item_descendent_needs_reflow(item);
- add_idle(E_CANVAS(item->canvas));
- }
-}
-
-void
-e_canvas_item_request_parent_reflow (GnomeCanvasItem *item)
-{
- g_return_if_fail(item != NULL);
- g_return_if_fail(GNOME_IS_CANVAS_ITEM(item));
- e_canvas_item_request_reflow(item->parent);
-}
-
-void
-e_canvas_item_set_reflow_callback (GnomeCanvasItem *item, ECanvasItemReflowFunc func)
-{
- g_object_set_data(G_OBJECT(item), "ECanvasItem::reflow_callback", (gpointer) func);
-}
-
-
-void
-e_canvas_item_set_selection_callback (GnomeCanvasItem *item, ECanvasItemSelectionFunc func)
-{
- g_object_set_data(G_OBJECT(item), "ECanvasItem::selection_callback", (gpointer) func);
-}
-
-void
-e_canvas_item_set_selection_compare_callback (GnomeCanvasItem *item, ECanvasItemSelectionCompareFunc func)
-{
- g_object_set_data(G_OBJECT(item), "ECanvasItem::selection_compare_callback", (gpointer) func);
-}
-
-void
-e_canvas_item_set_cursor (GnomeCanvasItem *item, gpointer id)
-{
- GList *list;
- int flags;
- ECanvas *canvas;
- ECanvasSelectionInfo *info;
- ECanvasItemSelectionFunc func;
-
- g_return_if_fail(item != NULL);
- g_return_if_fail(GNOME_IS_CANVAS_ITEM(item));
- g_return_if_fail(item->canvas != NULL);
- g_return_if_fail(E_IS_CANVAS(item->canvas));
-
- canvas = E_CANVAS(item->canvas);
- flags = E_CANVAS_ITEM_SELECTION_DELETE_DATA;
-
- for (list = canvas->selection; list; list = g_list_next(list)) {
- info = list->data;
-
- func = (ECanvasItemSelectionFunc)g_object_get_data(G_OBJECT(info->item),
- "ECanvasItem::selection_callback");
- if (func)
- func(info->item, flags, info->id);
- g_message ("ECANVAS: free info (2): item %p, id %p",
- info->item, info->id);
- g_object_unref (info->item);
- g_free(info);
- }
- g_list_free(canvas->selection);
-
- canvas->selection = NULL;
-
- gnome_canvas_item_grab_focus(item);
-
- info = g_new(ECanvasSelectionInfo, 1);
- info->item = item;
- g_object_ref (info->item);
- info->id = id;
- g_message ("ECANVAS: new info item %p, id %p", item, id);
-
- flags = E_CANVAS_ITEM_SELECTION_SELECT | E_CANVAS_ITEM_SELECTION_CURSOR;
- func = (ECanvasItemSelectionFunc)g_object_get_data(G_OBJECT(item),
- "ECanvasItem::selection_callback");
- if (func)
- func(item, flags, id);
-
- canvas->selection = g_list_prepend(canvas->selection, info);
- canvas->cursor = info;
-}
-
-void
-e_canvas_item_set_cursor_end (GnomeCanvasItem *item, gpointer id)
-{
-}
-
-void
-e_canvas_item_add_selection (GnomeCanvasItem *item, gpointer id)
-{
- int flags;
- ECanvas *canvas;
- ECanvasSelectionInfo *info;
- ECanvasItemSelectionFunc func;
- GList *list;
-
- g_return_if_fail(item != NULL);
- g_return_if_fail(GNOME_IS_CANVAS_ITEM(item));
- g_return_if_fail(item->canvas != NULL);
- g_return_if_fail(E_IS_CANVAS(item->canvas));
-
- flags = E_CANVAS_ITEM_SELECTION_SELECT;
- canvas = E_CANVAS(item->canvas);
-
- if (canvas->cursor) {
- func = (ECanvasItemSelectionFunc)g_object_get_data(G_OBJECT(canvas->cursor->item),
- "ECanvasItem::selection_callback");
- if (func)
- func(canvas->cursor->item, flags, canvas->cursor->id);
- }
-
- gnome_canvas_item_grab_focus(item);
-
- flags = E_CANVAS_ITEM_SELECTION_SELECT | E_CANVAS_ITEM_SELECTION_CURSOR;
-
- for (list = canvas->selection; list; list = g_list_next(list)) {
- ECanvasSelectionInfo *search;
- search = list->data;
-
- if (search->item == item) {
- ECanvasItemSelectionCompareFunc compare_func;
- compare_func = (ECanvasItemSelectionCompareFunc)g_object_get_data(G_OBJECT(search->item),
- "ECanvasItem::selection_compare_callback");
-
- if (compare_func(search->item, search->id, id, 0) == 0) {
- canvas->cursor = search;
- func = (ECanvasItemSelectionFunc)g_object_get_data(G_OBJECT(item),
- "ECanvasItem::selection_callback");
- if (func)
- func(item, flags, search->id);
- return;
- }
- }
- }
-
- info = g_new(ECanvasSelectionInfo, 1);
- info->item = item;
- g_object_ref (info->item);
- info->id = id;
- g_message ("ECANVAS: new info (2): item %p, id %p", item, id);
-
- func = (ECanvasItemSelectionFunc)g_object_get_data(G_OBJECT(item),
- "ECanvasItem::selection_callback");
- if (func)
- func(item, flags, id);
-
- canvas->selection = g_list_prepend(canvas->selection, info);
- canvas->cursor = info;
-}
-
-void
-e_canvas_item_remove_selection (GnomeCanvasItem *item, gpointer id)
-{
- int flags;
- ECanvas *canvas;
- ECanvasSelectionInfo *info;
- GList *list;
-
- g_return_if_fail(item != NULL);
- g_return_if_fail(GNOME_IS_CANVAS_ITEM(item));
- g_return_if_fail(item->canvas != NULL);
- g_return_if_fail(E_IS_CANVAS(item->canvas));
-
- flags = E_CANVAS_ITEM_SELECTION_DELETE_DATA;
- canvas = E_CANVAS(item->canvas);
-
- for (list = canvas->selection; list; list = g_list_next(list)) {
- info = list->data;
-
- if (info->item == item) {
- ECanvasItemSelectionCompareFunc compare_func;
- compare_func = (ECanvasItemSelectionCompareFunc)g_object_get_data(G_OBJECT(info->item),
- "ECanvasItem::selection_compare_callback");
-
- if (compare_func(info->item, info->id, id, 0) == 0) {
- ECanvasItemSelectionFunc func;
- func = (ECanvasItemSelectionFunc) g_object_get_data(G_OBJECT(info->item),
- "ECanvasItem::selection_callback");
- if (func)
- func(info->item, flags, info->id);
- canvas->selection = g_list_remove_link(canvas->selection, list);
-
- if (canvas->cursor == info)
- canvas->cursor = NULL;
-
- g_message ("ECANVAS: removing info: item %p, info %p",
- info->item, info->id);
- g_object_unref (info->item);
- g_free(info);
- g_list_free_1(list);
- break;
- }
- }
- }
-}
-
-void e_canvas_popup_tooltip (ECanvas *canvas, GtkWidget *widget, int x, int y)
-{
- if (canvas->tooltip_window && canvas->tooltip_window != widget) {
- e_canvas_hide_tooltip(canvas);
- }
- canvas->tooltip_window = widget;
- canvas->visibility_first = TRUE;
- if (canvas->toplevel == NULL) {
- canvas->toplevel = gtk_widget_get_toplevel (GTK_WIDGET(canvas));
- if (canvas->toplevel) {
- gtk_widget_add_events(canvas->toplevel, GDK_VISIBILITY_NOTIFY_MASK);
- g_object_ref (canvas->toplevel);
- canvas->visibility_notify_id =
- g_signal_connect (canvas->toplevel, "visibility_notify_event",
- G_CALLBACK (e_canvas_visibility), canvas);
- }
- }
- gtk_widget_set_uposition (widget, x, y);
- gtk_widget_show (widget);
-}
-
-void e_canvas_hide_tooltip (ECanvas *canvas)
-{
- if (canvas->tooltip_window) {
- gtk_widget_destroy (canvas->tooltip_window);
- canvas->tooltip_window = NULL;
- }
-}
-
-
-static gboolean
-grab_cancelled_check (gpointer data)
-{
- ECanvas *canvas = data;
-
- if (GNOME_CANVAS (canvas)->grabbed_item == NULL) {
- canvas->grab_cancelled_cb = NULL;
- canvas->grab_cancelled_check_id = 0;
- canvas->grab_cancelled_time = 0;
- canvas->grab_cancelled_data = NULL;
- return FALSE;
- }
-
- if (gtk_grab_get_current ()) {
- gnome_canvas_item_ungrab(GNOME_CANVAS (canvas)->grabbed_item, canvas->grab_cancelled_time);
- if (canvas->grab_cancelled_cb) {
- canvas->grab_cancelled_cb (canvas,
- GNOME_CANVAS (canvas)->grabbed_item,
- canvas->grab_cancelled_data);
- }
- canvas->grab_cancelled_cb = NULL;
- canvas->grab_cancelled_check_id = 0;
- canvas->grab_cancelled_time = 0;
- canvas->grab_cancelled_data = NULL;
- return FALSE;
- }
- return TRUE;
-}
-
-int
-e_canvas_item_grab (ECanvas *canvas,
- GnomeCanvasItem *item,
- guint event_mask,
- GdkCursor *cursor,
- guint32 etime,
- ECanvasItemGrabCancelled cancelled_cb,
- gpointer cancelled_data)
-{
- if (gtk_grab_get_current ()) {
- return AlreadyGrabbed;
- } else {
- int ret_val = gnome_canvas_item_grab (item, event_mask, cursor, etime);
- if (ret_val == GrabSuccess) {
- canvas->grab_cancelled_cb = cancelled_cb;
- canvas->grab_cancelled_check_id =
- g_timeout_add_full (G_PRIORITY_LOW,
- 100,
- grab_cancelled_check,
- canvas,
- NULL);
- canvas->grab_cancelled_time = etime;
- canvas->grab_cancelled_data = cancelled_data;
- }
-
- return ret_val;
- }
-}
-
-void
-e_canvas_item_ungrab (ECanvas *canvas,
- GnomeCanvasItem *item,
- guint32 etime)
-{
- if (canvas->grab_cancelled_check_id) {
- g_source_remove (canvas->grab_cancelled_check_id);
- canvas->grab_cancelled_cb = NULL;
- canvas->grab_cancelled_check_id = 0;
- canvas->grab_cancelled_time = 0;
- canvas->grab_cancelled_data = NULL;
- gnome_canvas_item_ungrab (item, etime);
- }
-}
diff --git a/widgets/misc/e-canvas.h b/widgets/misc/e-canvas.h
deleted file mode 100644
index 092833430b..0000000000
--- a/widgets/misc/e-canvas.h
+++ /dev/null
@@ -1,157 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-canvas.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef __E_CANVAS_H__
-#define __E_CANVAS_H__
-
-#include <gtk/gtkimcontext.h>
-#include <libgnomecanvas/gnome-canvas.h>
-
-#ifdef __cplusplus
-extern "C" {
-#pragma }
-#endif /* __cplusplus */
-
-/* ECanvas - A class derived from canvas for the purpose of adding
- * evolution specific canvas hacks.
- */
-
-#define E_CANVAS_TYPE (e_canvas_get_type ())
-#define E_CANVAS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_CANVAS_TYPE, ECanvas))
-#define E_CANVAS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_CANVAS_TYPE, ECanvasClass))
-#define E_IS_CANVAS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_CANVAS_TYPE))
-#define E_IS_CANVAS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), E_CANVAS_TYPE))
-
-typedef void (*ECanvasItemReflowFunc) (GnomeCanvasItem *item,
- gint flags);
-
-typedef void (*ECanvasItemSelectionFunc) (GnomeCanvasItem *item,
- gint flags,
- gpointer user_data);
-/* Returns the same as strcmp does. */
-typedef gint (*ECanvasItemSelectionCompareFunc) (GnomeCanvasItem *item,
- gpointer data1,
- gpointer data2,
- gint flags);
-
-
-typedef struct _ECanvas ECanvas;
-typedef struct _ECanvasClass ECanvasClass;
-
-/* Object flags for items */
-enum {
- E_CANVAS_ITEM_NEEDS_REFLOW = 1 << 13,
- E_CANVAS_ITEM_DESCENDENT_NEEDS_REFLOW = 1 << 14
-};
-
-enum {
- E_CANVAS_ITEM_SELECTION_SELECT = 1 << 0, /* TRUE = select. FALSE = unselect. */
- E_CANVAS_ITEM_SELECTION_CURSOR = 1 << 1, /* TRUE = has become cursor. FALSE = not cursor. */
- E_CANVAS_ITEM_SELECTION_DELETE_DATA = 1 << 2
-};
-
-typedef struct {
- GnomeCanvasItem *item;
- gpointer id;
-} ECanvasSelectionInfo;
-
-typedef void (*ECanvasItemGrabCancelled) (ECanvas *canvas, GnomeCanvasItem *item, gpointer data);
-
-struct _ECanvas
-{
- GnomeCanvas parent;
- int idle_id;
- GList *selection;
- ECanvasSelectionInfo *cursor;
-
- GtkWidget *tooltip_window;
- int visibility_notify_id;
- GtkWidget *toplevel;
-
- guint visibility_first : 1;
-
- /* Input context for dead key support */
- GtkIMContext *im_context;
-
- ECanvasItemGrabCancelled grab_cancelled_cb;
- guint grab_cancelled_check_id;
- guint32 grab_cancelled_time;
- gpointer grab_cancelled_data;
-};
-
-struct _ECanvasClass
-{
- GnomeCanvasClass parent_class;
- void (* reflow) (ECanvas *canvas);
-};
-
-
-GtkType e_canvas_get_type (void);
-GtkWidget *e_canvas_new (void);
-
-/* Used to send all of the keystroke events to a specific item as well as
- * GDK_FOCUS_CHANGE events.
- */
-void e_canvas_item_grab_focus (GnomeCanvasItem *item,
- gboolean widget_too);
-void e_canvas_item_request_reflow (GnomeCanvasItem *item);
-void e_canvas_item_request_parent_reflow (GnomeCanvasItem *item);
-void e_canvas_item_set_reflow_callback (GnomeCanvasItem *item,
- ECanvasItemReflowFunc func);
-void e_canvas_item_set_selection_callback (GnomeCanvasItem *item,
- ECanvasItemSelectionFunc func);
-void e_canvas_item_set_selection_compare_callback (GnomeCanvasItem *item,
- ECanvasItemSelectionCompareFunc func);
-void e_canvas_item_set_cursor (GnomeCanvasItem *item,
- gpointer id);
-void e_canvas_item_add_selection (GnomeCanvasItem *item,
- gpointer id);
-void e_canvas_item_remove_selection (GnomeCanvasItem *item,
- gpointer id);
-
-int e_canvas_item_grab (ECanvas *canvas,
- GnomeCanvasItem *item,
- guint event_mask,
- GdkCursor *cursor,
- guint32 etime,
- ECanvasItemGrabCancelled cancelled,
- gpointer cancelled_data);
-void e_canvas_item_ungrab (ECanvas *canvas,
- GnomeCanvasItem *item,
- guint32 etime);
-
-/* Not implemented yet. */
-void e_canvas_item_set_cursor_end (GnomeCanvasItem *item,
- gpointer id);
-void e_canvas_popup_tooltip (ECanvas *canvas,
- GtkWidget *widget,
- int x,
- int y);
-void e_canvas_hide_tooltip (ECanvas *canvas);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-
-#endif /* __E_CANVAS_H__ */
diff --git a/widgets/misc/e-cell-date-edit.c b/widgets/misc/e-cell-date-edit.c
index 12167e3185..5564f20ea6 100644
--- a/widgets/misc/e-cell-date-edit.c
+++ b/widgets/misc/e-cell-date-edit.c
@@ -40,6 +40,7 @@
#include <gdk/gdkkeysyms.h>
#include <gtk/gtk.h>
+#include <gal/util/e-util.h>
#include <gal/e-table/e-table-item.h>
#include <gal/e-table/e-cell-text.h>
@@ -50,6 +51,8 @@
/* This depends on ECalendar which is why I didn't put it in gal. */
#include "e-calendar.h"
+static void e_cell_date_edit_class_init (GtkObjectClass *object_class);
+static void e_cell_date_edit_init (ECellDateEdit *ecde);
static void e_cell_date_edit_destroy (GtkObject *object);
static void e_cell_date_edit_get_arg (GtkObject *o,
GtkArg *arg,
@@ -112,14 +115,18 @@ enum {
ARG_UPPER_HOUR
};
-G_DEFINE_TYPE (ECellDateEdit, e_cell_date_edit, E_CELL_POPUP_TYPE);
+static ECellPopupClass *parent_class;
+
+
+E_MAKE_TYPE (e_cell_date_edit, "ECellDateEdit", ECellDateEdit,
+ e_cell_date_edit_class_init, e_cell_date_edit_init,
+ e_cell_popup_get_type());
static void
-e_cell_date_edit_class_init (ECellDateEditClass *ecdec)
+e_cell_date_edit_class_init (GtkObjectClass *object_class)
{
- GtkObjectClass *object_class = (GtkObjectClass *) ecdec;
- ECellPopupClass *ecpc = (ECellPopupClass *) ecdec;
+ ECellPopupClass *ecpc = (ECellPopupClass *) object_class;
gtk_object_add_arg_type ("ECellDateEdit::show_time",
GTK_TYPE_BOOL, GTK_ARG_READWRITE,
@@ -148,6 +155,8 @@ e_cell_date_edit_class_init (ECellDateEditClass *ecdec)
object_class->set_arg = e_cell_date_edit_set_arg;
ecpc->popup = e_cell_date_edit_do_popup;
+
+ parent_class = g_type_class_ref(e_cell_popup_get_type ());
}
@@ -301,7 +310,7 @@ e_cell_date_edit_destroy (GtkObject *object)
gtk_widget_destroy (ecde->popup_window);
ecde->popup_window = NULL;
- GTK_OBJECT_CLASS (e_cell_date_edit_parent_class)->destroy (object);
+ GTK_OBJECT_CLASS (parent_class)->destroy (object);
}
diff --git a/widgets/misc/e-colors.c b/widgets/misc/e-colors.c
deleted file mode 100644
index 3f16437bee..0000000000
--- a/widgets/misc/e-colors.c
+++ /dev/null
@@ -1,103 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-colors.c - General color allocation utilities
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Miguel de Icaza (miguel@kernel.org)
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-/* We keep our own color context, as the color allocation might take
- * place before things are realized.
- */
-
-#include <config.h>
-#include <gtk/gtkwidget.h>
-#include "e-colors.h"
-
-GdkColor e_white, e_dark_gray, e_black;
-
-gulong
-e_color_alloc (gushort red, gushort green, gushort blue)
-{
- e_color_init ();
-
- red >>= 8;
- green >>= 8;
- blue >>= 8;
- return gdk_rgb_xpixel_from_rgb (
- ((red & 0xff) << 16) | ((green & 0xff) << 8) |
- (blue & 0xff));
-}
-
-void
-e_color_alloc_gdk (GtkWidget *widget, GdkColor *c)
-{
- GdkColormap *map;
-
- e_color_init ();
-
- if (widget)
- map = gtk_widget_get_colormap (widget);
- else /* FIXME: multi depth broken ? */
- map = gtk_widget_get_default_colormap ();
-
- gdk_rgb_find_color (map, c);
-}
-
-void
-e_color_alloc_name (GtkWidget *widget, const char *name, GdkColor *c)
-{
- GdkColormap *map;
-
- e_color_init ();
-
- gdk_color_parse (name, c);
-
- if (widget)
- map = gtk_widget_get_colormap (widget);
- else /* FIXME: multi depth broken ? */
- map = gtk_widget_get_default_colormap ();
-
- gdk_rgb_find_color (map, c);
-}
-
-void
-e_color_init (void)
-{
- static gboolean e_color_inited = FALSE;
-
- /* It's surprisingly easy to end up calling this twice. Survive. */
- if (e_color_inited)
- return;
-
- e_color_inited = TRUE;
-
- /* Allocate the default colors */
- e_white.red = 65535;
- e_white.green = 65535;
- e_white.blue = 65535;
- e_color_alloc_gdk (NULL, &e_white);
-
- e_black.red = 0;
- e_black.green = 0;
- e_black.blue = 0;
- e_color_alloc_gdk (NULL, &e_black);
-
- e_color_alloc_name (NULL, "gray20", &e_dark_gray);
-}
-
diff --git a/widgets/misc/e-colors.h b/widgets/misc/e-colors.h
deleted file mode 100644
index 596fd2b0a5..0000000000
--- a/widgets/misc/e-colors.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-colors.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Miguel de Icaza (miguel@kernel.org)
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef GNOME_APP_LIBS_COLOR_H
-#define GNOME_APP_LIBS_COLOR_H
-
-#include <glib.h>
-#include <gdk/gdk.h>
-#include <gtk/gtkwidget.h>
-
-G_BEGIN_DECLS
-
-void e_color_init (void);
-
-/* Return the pixel value for the given red, green and blue */
-gulong e_color_alloc (gushort red, gushort green, gushort blue);
-void e_color_alloc_name (GtkWidget *widget, const char *name, GdkColor *color);
-void e_color_alloc_gdk (GtkWidget *widget, GdkColor *color);
-
-extern GdkColor e_white, e_dark_gray, e_black;
-
-G_END_DECLS
-
-#endif /* GNOME_APP_LIBS_COLOR_H */
diff --git a/widgets/misc/e-cursors.c b/widgets/misc/e-cursors.c
deleted file mode 100644
index 3b44ab809e..0000000000
--- a/widgets/misc/e-cursors.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-cursors.c - cursor handling for gnumeric
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Miguel de Icaza (miguel@gnu.org)
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-
-#include "e-cursors.h"
-
-#include "e-colors.h"
-#include "pixmaps/cursor_cross.xpm"
-#include "pixmaps/cursor_zoom_in.xpm"
-#include "pixmaps/cursor_zoom_out.xpm"
-#include "pixmaps/cursor_hand_open.xpm"
-#include "pixmaps/cursor_hand_closed.xpm"
-#include <stdio.h>
-
-#define GDK_INTERNAL_CURSOR -1
-
-typedef struct {
- GdkCursor *cursor;
- int hot_x, hot_y;
- char **xpm;
-} CursorDef;
-
-static CursorDef cursors [] = {
- { NULL, 17, 17, cursor_cross_xpm },
- { NULL, GDK_INTERNAL_CURSOR, GDK_CROSSHAIR, NULL },
- { NULL, GDK_INTERNAL_CURSOR, GDK_ARROW, NULL },
- { NULL, GDK_INTERNAL_CURSOR, GDK_FLEUR, NULL },
- { NULL, 24, 24, cursor_zoom_in_xpm },
- { NULL, 24, 24, cursor_zoom_out_xpm },
- { NULL, GDK_INTERNAL_CURSOR, GDK_SB_H_DOUBLE_ARROW, NULL },
- { NULL, GDK_INTERNAL_CURSOR, GDK_SB_V_DOUBLE_ARROW, NULL },
- { NULL, GDK_INTERNAL_CURSOR, GDK_SIZING, NULL },
- { NULL, GDK_INTERNAL_CURSOR, GDK_SIZING, NULL },
- { NULL, GDK_INTERNAL_CURSOR, GDK_HAND2, NULL },
- { NULL, 10, 10, cursor_hand_open_xpm },
- { NULL, 10, 10, cursor_hand_closed_xpm },
- { NULL, GDK_INTERNAL_CURSOR, GDK_XTERM, NULL },
- { NULL, 0, 0, NULL }
-};
-
-
-static void
-create_bitmap_and_mask_from_xpm (GdkBitmap **bitmap, GdkBitmap **mask, gchar **xpm)
-{
- int height, width, colors;
- char pixmap_buffer [(32 * 32)/8];
- char mask_buffer [(32 * 32)/8];
- int x, y, pix, yofs;
- int transparent_color, black_color;
-
- sscanf (xpm [0], "%d %d %d %d", &height, &width, &colors, &pix);
-
- g_assert (height == 32);
- g_assert (width == 32);
- g_assert (colors <= 3);
-
- transparent_color = ' ';
- black_color = '.';
-
- yofs = colors + 1;
- for (y = 0; y < 32; y++){
- for (x = 0; x < 32;){
- char value = 0, maskv = 0;
-
- for (pix = 0; pix < 8; pix++, x++){
- if (xpm [y + yofs][x] != transparent_color){
- maskv |= 1 << pix;
-
- /*
- * Invert the colours here because it seems
- * to workaround a bug the Matrox G100 Xserver?
- * We reverse the foreground & background in the next
- * routine to compensate.
- */
- if (xpm [y + yofs][x] == black_color){
- value |= 1 << pix;
- }
- }
- }
- pixmap_buffer [(y * 4 + x/8)-1] = value;
- mask_buffer [(y * 4 + x/8)-1] = maskv;
- }
- }
- *bitmap = gdk_bitmap_create_from_data (NULL, pixmap_buffer, 32, 32);
- *mask = gdk_bitmap_create_from_data (NULL, mask_buffer, 32, 32);
-}
-
-void
-e_cursors_init (void)
-{
- int i;
-
- e_color_init ();
-
- for (i = 0; cursors [i].hot_x; i++){
- GdkBitmap *bitmap, *mask;
-
- if (cursors [i].hot_x < 0)
- cursors [i].cursor = gdk_cursor_new (cursors [i].hot_y);
- else {
- create_bitmap_and_mask_from_xpm (&bitmap, &mask, cursors [i].xpm);
-
- /* The foreground and background colours are reversed.
- * See comment above for explanation.
- */
- cursors [i].cursor =
- gdk_cursor_new_from_pixmap (
- bitmap, mask,
- &e_black, &e_white,
- cursors [i].hot_x,
- cursors [i].hot_y);
- }
- }
-
- g_assert (i == E_CURSOR_NUM_CURSORS);
-}
-
-void
-e_cursors_shutdown (void)
-{
- int i;
-
- for (i = 0; cursors [i].hot_x; i++)
- gdk_cursor_destroy (cursors [i].cursor);
-}
-
-
-/* Returns a cursor given its type */
-GdkCursor *
-e_cursor_get (ECursorType type)
-{
- g_return_val_if_fail (type >= 0 && type < E_CURSOR_NUM_CURSORS, NULL);
-
- return cursors [type].cursor;
-}
diff --git a/widgets/misc/e-cursors.h b/widgets/misc/e-cursors.h
deleted file mode 100644
index 8e751b659d..0000000000
--- a/widgets/misc/e-cursors.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-cursors.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Miguel de Icaza (miguel@gnu.org)
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef GNOME_APP_LIB_CURSORS_H
-#define GNOME_APP_LIB_CURSORS_H
-
-#include <gdk/gdk.h>
-
-G_BEGIN_DECLS
-
-typedef enum {
- E_CURSOR_FAT_CROSS,
- E_CURSOR_THIN_CROSS,
- E_CURSOR_ARROW,
- E_CURSOR_MOVE,
- E_CURSOR_ZOOM_IN,
- E_CURSOR_ZOOM_OUT,
- E_CURSOR_SIZE_X,
- E_CURSOR_SIZE_Y,
- E_CURSOR_SIZE_TL,
- E_CURSOR_SIZE_TR,
- E_CURSOR_PRESS,
- E_CURSOR_HAND_OPEN,
- E_CURSOR_HAND_CLOSED,
- E_CURSOR_XTERM,
- E_CURSOR_NUM_CURSORS
-} ECursorType;
-
-void e_cursors_init (void);
-void e_cursors_shutdown (void);
-
-#define e_cursor_set(win, c) \
-G_STMT_START { \
- if (win) \
- gdk_window_set_cursor (win, e_cursor_get (c)); \
-} G_STMT_END
-
-#define e_cursor_set_widget(w, c) \
-G_STMT_START { \
- if (GTK_WIDGET (w)->window) \
- gdk_window_set_cursor (GTK_WIDGET (w)->window, e_cursor_get (c)); \
-} G_STMT_END
-
-GdkCursor *e_cursor_get (ECursorType type);
-
-G_END_DECLS
-
-#endif /* GNOME_APP_LIB_CURSORS_H */
diff --git a/widgets/misc/e-gui-utils.c b/widgets/misc/e-gui-utils.c
deleted file mode 100644
index 886fb3d7ca..0000000000
--- a/widgets/misc/e-gui-utils.c
+++ /dev/null
@@ -1,238 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-gui-utils.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Miguel de Icaza <miguel@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "e-gui-utils.h"
-
-#include <gtk/gtkentry.h>
-#include <gtk/gtksignal.h>
-#include <gdk-pixbuf/gdk-pixbuf.h>
-#include <libgnomecanvas/gnome-canvas-pixbuf.h>
-
-void
-e_auto_kill_popup_menu_on_selection_done (GtkMenu *menu)
-{
- g_return_if_fail (GTK_IS_MENU (menu));
-
- g_signal_connect (menu, "selection_done", G_CALLBACK (gtk_widget_destroy), menu);
-}
-
-void
-e_popup_menu (GtkMenu *menu, GdkEvent *event)
-{
- g_return_if_fail (GTK_IS_MENU (menu));
-
- e_auto_kill_popup_menu_on_selection_done (menu);
-
- if (event) {
- if (event->type == GDK_KEY_PRESS)
- gtk_menu_popup (menu, NULL, NULL, 0, NULL, 0,
- event->key.time);
- else if ((event->type == GDK_BUTTON_PRESS) ||
- (event->type == GDK_BUTTON_RELEASE) ||
- (event->type == GDK_2BUTTON_PRESS) ||
- (event->type == GDK_3BUTTON_PRESS)){
- gtk_menu_popup (menu, NULL, NULL, 0, NULL,
- event->button.button,
- event->button.time);
- }
- } else
- gtk_menu_popup (menu, NULL, NULL, 0, NULL, 0,
- GDK_CURRENT_TIME);
-}
-
-typedef struct {
- GtkCallback callback;
- gpointer closure;
-} CallbackClosure;
-
-static void
-e_container_foreach_leaf_callback(GtkWidget *widget, CallbackClosure *callback_closure)
-{
- if (GTK_IS_CONTAINER(widget)) {
- e_container_foreach_leaf(GTK_CONTAINER(widget), callback_closure->callback, callback_closure->closure);
- } else {
- (*callback_closure->callback) (widget, callback_closure->closure);
- }
-}
-
-void
-e_container_foreach_leaf(GtkContainer *container,
- GtkCallback callback,
- gpointer closure)
-{
- CallbackClosure callback_closure;
- callback_closure.callback = callback;
- callback_closure.closure = closure;
- gtk_container_foreach(container, (GtkCallback) e_container_foreach_leaf_callback, &callback_closure);
-}
-
-static void
-e_container_change_tab_order_destroy_notify(gpointer data)
-{
- GList *list = data;
- g_list_foreach(list, (GFunc) g_object_unref, NULL);
- g_list_free(list);
-}
-
-
-static gint
-e_container_change_tab_order_callback(GtkContainer *container,
- GtkDirectionType direction,
- GList *children)
-{
- GtkWidget *focus_child;
- GtkWidget *child;
-
- if (direction != GTK_DIR_TAB_FORWARD &&
- direction != GTK_DIR_TAB_BACKWARD)
- return FALSE;
-
- focus_child = container->focus_child;
-
- if (focus_child == NULL)
- return FALSE;
-
- if (direction == GTK_DIR_TAB_BACKWARD) {
- children = g_list_last(children);
- }
-
- while (children) {
- child = children->data;
- if (direction == GTK_DIR_TAB_FORWARD)
- children = children->next;
- else
- children = children->prev;
-
- if (!child)
- continue;
-
- if (focus_child) {
- if (focus_child == child) {
- focus_child = NULL;
-
- if (GTK_WIDGET_DRAWABLE (child) &&
- GTK_IS_CONTAINER (child) &&
- !GTK_WIDGET_HAS_FOCUS (child))
- if (gtk_widget_child_focus (GTK_WIDGET (child), direction)) {
- g_signal_stop_emission_by_name (container, "focus");
- return TRUE;
- }
- }
- }
- else if (GTK_WIDGET_DRAWABLE (child)) {
- if (GTK_IS_CONTAINER (child)) {
- if (gtk_widget_child_focus (GTK_WIDGET (child), direction)) {
- g_signal_stop_emission_by_name (container, "focus");
- return TRUE;
- }
- }
- else if (GTK_WIDGET_CAN_FOCUS (child)) {
- gtk_widget_grab_focus (child);
- g_signal_stop_emission_by_name (container, "focus");
- return TRUE;
- }
- }
- }
-
- return FALSE;
-}
-
-gint
-e_container_change_tab_order(GtkContainer *container, GList *widgets)
-{
- GList *list;
- list = g_list_copy(widgets);
- g_list_foreach(list, (GFunc) g_object_ref, NULL);
- return gtk_signal_connect_full(GTK_OBJECT(container), "focus",
- GTK_SIGNAL_FUNC(e_container_change_tab_order_callback),
- NULL, list,
- e_container_change_tab_order_destroy_notify,
- FALSE, FALSE);
-}
-
-struct widgetandint {
- GtkWidget *widget;
- int count;
-};
-
-static void
-nth_entry_callback(GtkWidget *widget, struct widgetandint *data)
-{
- if (GTK_IS_ENTRY(widget)) {
- if (data->count > 1) {
- data->count --;
- data->widget = widget;
- } else if (data->count == 1) {
- data->count --;
- data->widget = NULL;
- gtk_widget_grab_focus(widget);
- }
- }
-}
-
-void
-e_container_focus_nth_entry(GtkContainer *container, int n)
-{
- struct widgetandint data;
- data.widget = NULL;
- data.count = n;
- e_container_foreach_leaf(container, (GtkCallback) nth_entry_callback, &data);
- if (data.widget)
- gtk_widget_grab_focus(data.widget);
-}
-
-gboolean
-e_glade_xml_connect_widget (GladeXML *gui, char *name, char *signal, GCallback cb, gpointer closure)
-{
- GtkWidget *widget;
-
- widget = glade_xml_get_widget (gui, name);
-
- if (widget) {
- g_signal_connect (widget, signal,
- cb, closure);
- return TRUE;
- }
-
- return FALSE;
-}
-
-gboolean
-e_glade_xml_set_sensitive (GladeXML *gui, char *name, gboolean sensitive)
-{
- GtkWidget *widget;
-
- widget = glade_xml_get_widget (gui, name);
-
- if (widget) {
- gtk_widget_set_sensitive (widget, sensitive);
- return TRUE;
- }
-
- return FALSE;
-}
diff --git a/widgets/misc/e-gui-utils.h b/widgets/misc/e-gui-utils.h
deleted file mode 100644
index c52e233714..0000000000
--- a/widgets/misc/e-gui-utils.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-gui-utils.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Miguel de Icaza <miguel@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef GAL_GUI_UTILS_H
-#define GAL_GUI_UTILS_H
-
-#include <gtk/gtkmenu.h>
-#include <gtk/gtkwindow.h>
-
-#include <glade/glade-xml.h>
-
-G_BEGIN_DECLS
-
-void e_popup_menu (GtkMenu *menu,
- GdkEvent *event);
-void e_auto_kill_popup_menu_on_selection_done (GtkMenu *menu);
-
-void e_container_foreach_leaf (GtkContainer *container,
- GtkCallback callback,
- gpointer closure);
-void e_container_focus_nth_entry (GtkContainer *container,
- int n);
-gint e_container_change_tab_order (GtkContainer *container,
- GList *widgets);
-
-/* Returns TRUE on success. */
-gboolean e_glade_xml_connect_widget (GladeXML *gui,
- char *name,
- char *signal,
- GtkSignalFunc cb,
- gpointer closure);
-gboolean e_glade_xml_set_sensitive (GladeXML *gui,
- char *name,
- gboolean sensitive);
-
-G_END_DECLS
-
-#endif /* GAL_GUI_UTILS_H */
diff --git a/widgets/misc/e-hsv-utils.c b/widgets/misc/e-hsv-utils.c
deleted file mode 100644
index a5007b9b83..0000000000
--- a/widgets/misc/e-hsv-utils.c
+++ /dev/null
@@ -1,178 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-hsv-utils.c - utilites for manipulating colours in HSV space
- * Copyright (C) 1995-2001 Seth Nickell, Peter Mattis, Spencer Kimball and Josh MacDonald
- *
- * Authors:
- * Seth Nickell <seth@eazel.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-
-#include "e-hsv-utils.h"
-
-/* tweak_hsv is a really tweaky function. it modifies its first argument, which
- should be the colour you want tweaked. delta_h, delta_s and delta_v specify
- how much you want their respective channels modified (and in what direction).
- if it can't do the specified modification, it does it in the oppositon direction */
-void
-e_hsv_tweak (GdkColor *colour, gdouble delta_h, gdouble delta_s, gdouble delta_v)
-{
- gdouble h, s, v, r, g, b;
-
- r = colour->red / 65535.0f;
- g = colour->green / 65535.0f;
- b = colour->blue / 65535.0f;
-
- e_rgb_to_hsv (r, g, b, &h, &s, &v);
-
- if (h + delta_h < 0) {
- h -= delta_h;
- } else {
- h += delta_h;
- }
-
- if (s + delta_s < 0) {
- s -= delta_s;
- } else {
- s += delta_s;
- }
-
- if (v + delta_v < 0) {
- v -= delta_v;
- } else {
- v += delta_v;
- }
-
- e_hsv_to_rgb (h, s, v, &r, &g, &b);
-
- colour->red = r * 65535.0f;
- colour->green = g * 65535.0f;
- colour->blue = b * 65535.0f;
-}
-
-/* Copy n' Paste code from the GTK+ colour selector (gtkcolorsel.c) */
-/* Originally lifted, I suspect, from "Foley, van Dam" */
-void
-e_hsv_to_rgb (gdouble h, gdouble s, gdouble v,
- gdouble *r, gdouble *g, gdouble *b)
-{
- gint i;
- gdouble f, w, q, t;
-
- if (s == 0.0)
- s = 0.000001;
-
- if (h == -1.0)
- {
- *r = v;
- *g = v;
- *b = v;
- }
- else
- {
- if (h == 360.0)
- h = 0.0;
- h = h / 60.0;
- i = (gint) h;
- f = h - i;
- w = v * (1.0 - s);
- q = v * (1.0 - (s * f));
- t = v * (1.0 - (s * (1.0 - f)));
-
- switch (i)
- {
- case 0:
- *r = v;
- *g = t;
- *b = w;
- break;
- case 1:
- *r = q;
- *g = v;
- *b = w;
- break;
- case 2:
- *r = w;
- *g = v;
- *b = t;
- break;
- case 3:
- *r = w;
- *g = q;
- *b = v;
- break;
- case 4:
- *r = t;
- *g = w;
- *b = v;
- break;
- case 5:
- *r = v;
- *g = w;
- *b = q;
- break;
- }
- }
-}
-
-void
-e_rgb_to_hsv (gdouble r, gdouble g, gdouble b,
- gdouble *h, gdouble *s, gdouble *v)
-{
- double max, min, delta;
-
- max = r;
- if (g > max)
- max = g;
- if (b > max)
- max = b;
-
- min = r;
- if (g < min)
- min = g;
- if (b < min)
- min = b;
-
- *v = max;
-
- if (max != 0.0)
- *s = (max - min) / max;
- else
- *s = 0.0;
-
- if (*s == 0.0)
- *h = -1.0;
- else
- {
- delta = max - min;
-
- if (r == max)
- *h = (g - b) / delta;
- else if (g == max)
- *h = 2.0 + (b - r) / delta;
- else if (b == max)
- *h = 4.0 + (r - g) / delta;
-
- *h = *h * 60.0;
-
- if (*h < 0.0)
- *h = *h + 360;
- }
-}
-
-
diff --git a/widgets/misc/e-hsv-utils.h b/widgets/misc/e-hsv-utils.h
deleted file mode 100644
index bbde282697..0000000000
--- a/widgets/misc/e-hsv-utils.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-hsv-utils.h - utilites for manipulating colours in HSV space
- * Copyright (C) 1995-2001 Seth Nickell, Peter Mattis, Spencer Kimball and Josh MacDonald
- *
- * Authors:
- * Seth Nickell <seth@eazel.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_HSV_UTILS_H_
-#define _E_HSV_UTILS_H_
-
-#include <gdk/gdk.h>
-
-G_BEGIN_DECLS
-
-void e_hsv_to_rgb (gdouble h,
- gdouble s,
- gdouble v,
- gdouble *r,
- gdouble *g,
- gdouble *b);
-
-void e_rgb_to_hsv (gdouble r,
- gdouble g,
- gdouble b,
- gdouble *h,
- gdouble *s,
- gdouble *v);
-
-void e_hsv_tweak (GdkColor *colour,
- gdouble delta_h,
- gdouble delta_s,
- gdouble delta_v);
-
-G_END_DECLS
-
-#endif /* _E_HSV_UTILS_H_ */
diff --git a/widgets/misc/e-multi-config-dialog.c b/widgets/misc/e-multi-config-dialog.c
index 499ef97554..aa38ad1e34 100644
--- a/widgets/misc/e-multi-config-dialog.c
+++ b/widgets/misc/e-multi-config-dialog.c
@@ -37,8 +37,12 @@
#include <gdk-pixbuf/gdk-pixbuf.h>
+#define PARENT_TYPE gtk_dialog_get_type ()
+static GtkDialogClass *parent_class = NULL;
+
#define SWITCH_PAGE_INTERVAL 250
+
struct _EMultiConfigDialogPrivate {
GSList *pages;
@@ -51,8 +55,6 @@ struct _EMultiConfigDialogPrivate {
int set_page_timeout_page;
};
-G_DEFINE_TYPE (EMultiConfigDialog, e_multi_config_dialog, GTK_TYPE_DIALOG)
-
/* ETable stuff. */
@@ -175,7 +177,7 @@ impl_finalize (GObject *object)
g_free (priv);
- (* G_OBJECT_CLASS (e_multi_config_dialog_parent_class)->finalize) (object);
+ (* G_OBJECT_CLASS (parent_class)->finalize) (object);
}
@@ -214,7 +216,7 @@ impl_response (GtkDialog *dialog, int response_id)
/* GObject ctors. */
static void
-e_multi_config_dialog_class_init (EMultiConfigDialogClass *class)
+class_init (EMultiConfigDialogClass *class)
{
GObjectClass *object_class;
GtkDialogClass *dialog_class;
@@ -224,6 +226,8 @@ e_multi_config_dialog_class_init (EMultiConfigDialogClass *class)
dialog_class = GTK_DIALOG_CLASS (class);
dialog_class->response = impl_response;
+
+ parent_class = g_type_class_ref (PARENT_TYPE);
}
#define RGB_COLOR(color) (((color).red & 0xff00) << 8 | \
@@ -283,7 +287,7 @@ static ETableMemoryStoreColumnInfo columns[] = {
};
static void
-e_multi_config_dialog_init (EMultiConfigDialog *multi_config_dialog)
+init (EMultiConfigDialog *multi_config_dialog)
{
EMultiConfigDialogPrivate *priv;
ETableModel *list_e_table_model;
@@ -391,8 +395,6 @@ e_multi_config_dialog_add_page (EMultiConfigDialog *dialog,
EConfigPage *page_widget)
{
EMultiConfigDialogPrivate *priv;
- AtkObject *a11y;
- gint page_no;
g_return_if_fail (E_IS_MULTI_CONFIG_DIALOG (dialog));
g_return_if_fail (title != NULL);
@@ -409,17 +411,10 @@ e_multi_config_dialog_add_page (EMultiConfigDialog *dialog,
fill_in_pixbufs (dialog, e_table_model_row_count (priv->list_e_table_model) - 1);
}
- page_no = gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook),
+ gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook),
create_page_container (description, GTK_WIDGET (page_widget)),
NULL);
- a11y = gtk_widget_get_accessible (GTK_WIDGET(priv->notebook));
- AtkObject *a11yPage = atk_object_ref_accessible_child (a11y, page_no);
- if (a11yPage != NULL) {
- if (atk_object_get_role (a11yPage) == ATK_ROLE_PAGE_TAB)
- atk_object_set_name (a11yPage, title);
- g_object_unref (a11yPage);
- }
if (priv->pages->next == NULL) {
ETable *table;
@@ -445,3 +440,5 @@ e_multi_config_dialog_show_page (EMultiConfigDialog *dialog, int page)
gtk_notebook_set_page (GTK_NOTEBOOK (priv->notebook), page);
}
+
+E_MAKE_TYPE (e_multi_config_dialog, "EMultiConfigDialog", EMultiConfigDialog, class_init, init, PARENT_TYPE)
diff --git a/widgets/misc/e-popup-menu.c b/widgets/misc/e-popup-menu.c
deleted file mode 100644
index 8607cd1b01..0000000000
--- a/widgets/misc/e-popup-menu.c
+++ /dev/null
@@ -1,240 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-popup-menu.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Miguel de Icaza <miguel@ximian.com>
- * Jody Goldberg (jgoldberg@home.com)
- * Jeffrey Stedfast <fejj@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <string.h>
-#include <gtk/gtkimage.h>
-#include <gdk/gdkkeysyms.h>
-#include <gtk/gtkaccellabel.h>
-#include <gtk/gtklabel.h>
-#include <gtk/gtkmenuitem.h>
-#include <gtk/gtkcheckmenuitem.h>
-#include <gtk/gtkradiomenuitem.h>
-#include <gtk/gtksignal.h>
-#include <gtk/gtkimagemenuitem.h>
-
-#include "e-popup-menu.h"
-#include "e-gui-utils.h"
-
-#include <gal/util/e-i18n.h>
-
-/*
- * Creates an item with an optional icon
- */
-static void
-make_item (GtkMenu *menu, GtkMenuItem *item, const char *name, GtkWidget *pixmap)
-{
- GtkWidget *label;
-
- if (*name == '\0')
- return;
-
- /*
- * Ugh. This needs to go into Gtk+
- */
- label = gtk_label_new_with_mnemonic (name);
- gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
- gtk_widget_show (label);
-
- gtk_container_add (GTK_CONTAINER (item), label);
-
- if (pixmap && GTK_IS_IMAGE_MENU_ITEM (item)){
- gtk_widget_show (pixmap);
- gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), pixmap);
- }
-}
-
-GtkMenu *
-e_popup_menu_create (EPopupMenu *menu_list,
- guint32 disable_mask,
- guint32 hide_mask,
- void *default_closure)
-{
- return e_popup_menu_create_with_domain (menu_list,
- disable_mask,
- hide_mask,
- default_closure,
- NULL);
-}
-
-
-GtkMenu *
-e_popup_menu_create_with_domain (EPopupMenu *menu_list,
- guint32 disable_mask,
- guint32 hide_mask,
- void *default_closure,
- const char *domain)
-{
- GtkMenu *menu = GTK_MENU (gtk_menu_new ());
- GSList *group = NULL;
- gboolean last_item_separator = TRUE;
- int last_non_separator = -1;
- int i;
-
- for (i = 0; menu_list[i].name; i++) {
- if (strcmp ("", menu_list[i].name) && !(menu_list [i].disable_mask & hide_mask)) {
- last_non_separator = i;
- }
- }
-
- for (i = 0; i <= last_non_separator; i++) {
- gboolean separator;
-
- separator = !strcmp ("", menu_list[i].name);
-
- if ((!(separator && last_item_separator)) && !(menu_list [i].disable_mask & hide_mask)) {
- GtkWidget *item = NULL;
-
- if (!separator) {
- if (menu_list[i].is_toggle)
- item = gtk_check_menu_item_new ();
- else if (menu_list[i].is_radio)
- item = gtk_radio_menu_item_new (group);
- else
- item = menu_list[i].pixmap_widget ? gtk_image_menu_item_new () : gtk_menu_item_new ();
- if (menu_list[i].is_toggle || menu_list[i].is_radio)
- gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), menu_list[i].is_active);
- if (menu_list[i].is_radio)
- group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (item));
-
- make_item (menu, GTK_MENU_ITEM (item), dgettext(domain, menu_list[i].name), menu_list[i].pixmap_widget);
- } else {
- item = gtk_menu_item_new ();
- }
-
- gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
-
- if (!menu_list[i].submenu) {
- if (menu_list[i].fn)
- g_signal_connect (item, "activate",
- G_CALLBACK (menu_list[i].fn),
- menu_list[i].use_custom_closure ? menu_list[i].closure : default_closure);
- } else {
- /* submenu */
- GtkMenu *submenu;
-
- submenu = e_popup_menu_create (menu_list[i].submenu, disable_mask, hide_mask,
- default_closure);
-
- gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), GTK_WIDGET (submenu));
- }
-
- if (menu_list[i].disable_mask & disable_mask)
- gtk_widget_set_sensitive (item, FALSE);
-
- gtk_widget_show (item);
-
- last_item_separator = separator;
- }
- }
-
- return menu;
-}
-
-void
-e_popup_menu_run (EPopupMenu *menu_list, GdkEvent *event, guint32 disable_mask, guint32 hide_mask, void *default_closure)
-{
- GtkMenu *menu;
-
- g_return_if_fail (menu_list != NULL);
- g_return_if_fail (event != NULL);
-
- menu = e_popup_menu_create (menu_list, disable_mask, hide_mask, default_closure);
-
- e_popup_menu (menu, event);
-}
-
-void
-e_popup_menu_copy_1 (EPopupMenu *destination,
- const EPopupMenu *source)
-{
- destination->name = g_strdup (source->name);
- destination->pixname = g_strdup (source->pixname);
- destination->fn = source->fn;
- destination->submenu = e_popup_menu_copy (source->submenu);
- destination->disable_mask = source->disable_mask;
-
- destination->pixmap_widget = source->pixmap_widget;
- if (destination->pixmap_widget)
- g_object_ref (destination->pixmap_widget);
- destination->closure = source->closure;
-
- destination->is_toggle = source->is_toggle;
- destination->is_radio = source->is_radio;
- destination->is_active = source->is_active;
-
- destination->use_custom_closure = source->use_custom_closure;
-}
-
-void
-e_popup_menu_free_1 (EPopupMenu *menu_item)
-{
- g_free (menu_item->name);
- g_free (menu_item->pixname);
- e_popup_menu_free (menu_item->submenu);
-
- if (menu_item->pixmap_widget)
- g_object_unref (menu_item->pixmap_widget);
-}
-
-EPopupMenu *
-e_popup_menu_copy (const EPopupMenu *menu_list)
-{
- int i;
- EPopupMenu *ret_val;
-
- if (menu_list == NULL)
- return NULL;
-
- for (i = 0; menu_list[i].name; i++) {
- /* Intentionally empty */
- }
-
- ret_val = g_new (EPopupMenu, i + 1);
-
- for (i = 0; menu_list[i].name; i++) {
- e_popup_menu_copy_1 (ret_val + i, menu_list + i);
- }
-
- /* Copy the terminator */
- e_popup_menu_copy_1 (ret_val + i, menu_list + i);
-
- return ret_val;
-}
-
-void
-e_popup_menu_free (EPopupMenu *menu_list)
-{
- int i;
-
- if (menu_list == NULL)
- return;
-
- for (i = 0; menu_list[i].name; i++) {
- e_popup_menu_free_1 (menu_list + i);
- }
- g_free (menu_list);
-}
-
diff --git a/widgets/misc/e-popup-menu.h b/widgets/misc/e-popup-menu.h
deleted file mode 100644
index 7289ab5c86..0000000000
--- a/widgets/misc/e-popup-menu.h
+++ /dev/null
@@ -1,142 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-popup-menu.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Miguel de Icaza <miguel@ximian.com>
- * Jody Goldberg (jgoldberg@home.com)
- * Jeffrey Stedfast <fejj@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef E_POPUP_MENU_H
-#define E_POPUP_MENU_H
-
-#include <gtk/gtkmenu.h>
-#include <gtk/gtkwidget.h>
-
-G_BEGIN_DECLS
-
-#define E_POPUP_SEPARATOR { "", NULL, (NULL), NULL, 0 }
-#define E_POPUP_TERMINATOR { NULL, NULL, (NULL), NULL, 0 }
-
-
-/* In the following, CC = custom closure */
-
-#define E_POPUP_ITEM(name,fn,disable_mask) { (name), NULL, (fn), NULL, (disable_mask), NULL, NULL, 0, 0, 0, 0 }
-#define E_POPUP_ITEM_CC(name,fn,closure,disable_mask) { (name), NULL, (fn), NULL, (disable_mask), NULL, (closure), 0, 0, 0, 1 }
-#define E_POPUP_SUBMENU(name,submenu,disable_mask) { (name), NULL, NULL, (submenu), (disable_mask), NULL, NULL, 0, 0, 0, 0 }
-
-#define E_POPUP_PIXMAP_ITEM(name,pixmap,fn,disable_mask) { (name), (pixmap), (fn), NULL, (disable_mask), NULL, NULL, 0, 0, 0, 0 }
-#define E_POPUP_PIXMAP_ITEM_CC(name,pixmap,fn,closure,disable_mask) { (name), (pixmap), (fn), NULL, (disable_mask), NULL, (closure), 0, 0, 0, 1 }
-#define E_POPUP_PIXMAP_SUBMENU(name,pixmap,submenu,disable_mask) { (name), (pixmap), NULL, (submenu), (disable_mask), NULL, NULL, 0, 0, 0, 0 }
-
-#define E_POPUP_PIXMAP_WIDGET_ITEM(name,pixmap_widget,fn,disable_mask) { (name), NULL, (fn), NULL, (disable_mask), (pixmap_widget), NULL, 0, 0, 0, 0 }
-#define E_POPUP_PIXMAP_WIDGET_ITEM_CC(name,pixmap_widget,fn,closure,disable_mask) { (name), NULL, (fn), NULL, (disable_mask), (pixmap_widget), (closure), 0, 0, 0, 1 }
-#define E_POPUP_PIXMAP_WIDGET_SUBMENU(name,pixmap_widget,submenu,disable_mask) { (name), NULL, NULL, (submenu), (disable_mask), (pixmap_widget), NULL, 0, 0, 0, 0 }
-
-
-#define E_POPUP_TOGGLE_ITEM(name,fn,disable_mask,value) { (name), NULL, (fn), NULL, (disable_mask), NULL, NULL, 1, 0, value, 0 }
-#define E_POPUP_TOGGLE_ITEM_CC(name,fn,closure,disable_mask,value) { (name), NULL, (fn), NULL, (disable_mask), NULL, (closure), 1, 0, value, 1 }
-
-#define E_POPUP_SEPARATOR { "", NULL, (NULL), NULL, 0 }
-#define E_POPUP_TERMINATOR { NULL, NULL, (NULL), NULL, 0 }
-
-
-/* In the following, CC = custom closure */
-
-#define E_POPUP_ITEM(name,fn,disable_mask) { (name), NULL, (fn), NULL, (disable_mask), NULL, NULL, 0, 0, 0, 0 }
-#define E_POPUP_ITEM_CC(name,fn,closure,disable_mask) { (name), NULL, (fn), NULL, (disable_mask), NULL, (closure), 0, 0, 0, 1 }
-#define E_POPUP_SUBMENU(name,submenu,disable_mask) { (name), NULL, NULL, (submenu), (disable_mask), NULL, NULL, 0, 0, 0, 0 }
-
-#define E_POPUP_PIXMAP_ITEM(name,pixmap,fn,disable_mask) { (name), (pixmap), (fn), NULL, (disable_mask), NULL, NULL, 0, 0, 0, 0 }
-#define E_POPUP_PIXMAP_ITEM_CC(name,pixmap,fn,closure,disable_mask) { (name), (pixmap), (fn), NULL, (disable_mask), NULL, (closure), 0, 0, 0, 1 }
-#define E_POPUP_PIXMAP_SUBMENU(name,pixmap,submenu,disable_mask) { (name), (pixmap), NULL, (submenu), (disable_mask), NULL, NULL, 0, 0, 0, 0 }
-
-#define E_POPUP_PIXMAP_WIDGET_ITEM(name,pixmap_widget,fn,disable_mask) { (name), NULL, (fn), NULL, (disable_mask), (pixmap_widget), NULL, 0, 0, 0, 0 }
-#define E_POPUP_PIXMAP_WIDGET_ITEM_CC(name,pixmap_widget,fn,closure,disable_mask) { (name), NULL, (fn), NULL, (disable_mask), (pixmap_widget), (closure), 0, 0, 0, 1 }
-#define E_POPUP_PIXMAP_WIDGET_SUBMENU(name,pixmap_widget,submenu,disable_mask) { (name), NULL, NULL, (submenu), (disable_mask), (pixmap_widget), NULL, 0, 0, 0, 0 }
-
-
-#define E_POPUP_TOGGLE_ITEM(name,fn,disable_mask,value) { (name), NULL, (fn), NULL, (disable_mask), NULL, NULL, 1, 0, value, 0 }
-#define E_POPUP_TOGGLE_ITEM_CC(name,fn,closure,disable_mask,value) { (name), NULL, (fn), NULL, (disable_mask), NULL, (closure), 1, 0, value, 1 }
-
-#define E_POPUP_TOGGLE_PIXMAP_ITEM(name,pixmap,fn,disable_mask) { (name), (pixmap), (fn), NULL, (disable_mask), NULL, NULL, 1, 0, value, 0 }
-#define E_POPUP_TOGGLE_PIXMAP_ITEM_CC(name,pixmap,fn,closure,disable_mask) { (name), (pixmap), (fn), NULL, (disable_mask), NULL, (closure), 1, 0, value, 1 }
-
-#define E_POPUP_TOGGLE_PIXMAP_WIDGET_ITEM(name,pixmap_widget,fn,disable_mask) { (name), NULL, (fn), NULL, (disable_mask), (pixmap_widget), NULL, 1, 0, value, 0 }
-#define E_POPUP_TOGGLE_PIXMAP_WIDGET_ITEM_CC(name,pixmap_widget,fn,closure,disable_mask) { (name), NULL, (fn), NULL, (disable_mask), (pixmap_widget), (closure), 1, 0, value, 1 }
-
-
-#define E_POPUP_RADIO_ITEM(name,fn,disable_mask,value) { (name), NULL, (fn), NULL, (disable_mask), NULL, NULL, 0, 1, value, 0 }
-#define E_POPUP_RADIO_ITEM_CC(name,fn,closure,disable_mask,value) { (name), NULL, (fn), NULL, (disable_mask), NULL, (closure), 0, 1, value, 1 }
-
-#define E_POPUP_RADIO_PIXMAP_ITEM(name,pixmap,fn,disable_mask) { (name), (pixmap), (fn), NULL, (disable_mask), NULL, NULL, 0, 1, value, 0 }
-#define E_POPUP_RADIO_PIXMAP_ITEM_CC(name,pixmap,fn,closure,disable_mask) { (name), (pixmap), (fn), NULL, (disable_mask), NULL, (closure), 0, 1, value, 1 }
-
-#define E_POPUP_RADIO_PIXMAP_WIDGET_ITEM(name,pixmap_widget,fn,disable_mask) { (name), NULL, (fn), NULL, (disable_mask), (pixmap_widget), NULL, 0, 1, value, 0 }
-#define E_POPUP_RADIO_PIXMAP_WIDGET_ITEM_CC(name,pixmap_widget,fn,closure,disable_mask) { (name), NULL, (fn), NULL, (disable_mask), (pixmap_widget), (closure), 0, 1, value, 1 }
-
-
-typedef struct _EPopupMenu EPopupMenu;
-
-struct _EPopupMenu {
- char *name;
- char *pixname;
- GtkSignalFunc fn;
-
- EPopupMenu *submenu;
- guint32 disable_mask;
-
- /* Added post 0.19 */
- GtkWidget *pixmap_widget;
- void *closure;
-
- guint is_toggle : 1;
- guint is_radio : 1;
- guint is_active : 1;
-
- guint use_custom_closure : 1;
-};
-
-GtkMenu *e_popup_menu_create (EPopupMenu *menu_list,
- guint32 disable_mask,
- guint32 hide_mask,
- void *default_closure);
-GtkMenu *e_popup_menu_create_with_domain (EPopupMenu *menu_list,
- guint32 disable_mask,
- guint32 hide_mask,
- void *default_closure,
- const char *domain);
-void e_popup_menu_run (EPopupMenu *menu_list,
- GdkEvent *event,
- guint32 disable_mask,
- guint32 hide_mask,
- void *default_closure);
-
-/* Doesn't copy or free the memory. Just the contents. */
-void e_popup_menu_copy_1 (EPopupMenu *destination,
- const EPopupMenu *menu_item);
-void e_popup_menu_free_1 (EPopupMenu *menu_item);
-
-/* Copies or frees the entire structure. */
-EPopupMenu *e_popup_menu_copy (const EPopupMenu *menu_item);
-void e_popup_menu_free (EPopupMenu *menu_item);
-
-G_END_DECLS
-
-#endif /* E_POPUP_MENU_H */
diff --git a/widgets/misc/e-printable.c b/widgets/misc/e-printable.c
deleted file mode 100644
index 534f153823..0000000000
--- a/widgets/misc/e-printable.c
+++ /dev/null
@@ -1,209 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-printable.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <gtk/gtksignal.h>
-#include "gal/util/e-util.h"
-#include "e-printable.h"
-
-#define EP_CLASS(e) ((EPrintableClass *)((GtkObject *)e)->klass)
-
-#define PARENT_TYPE GTK_TYPE_OBJECT
-
-
-static GtkObjectClass *e_printable_parent_class;
-
-enum {
- PRINT_PAGE,
- DATA_LEFT,
- RESET,
- HEIGHT,
- WILL_FIT,
- LAST_SIGNAL
-};
-
-static guint e_printable_signals [LAST_SIGNAL] = { 0, };
-
-static void
-e_printable_class_init (GtkObjectClass *object_class)
-{
- EPrintableClass *klass = E_PRINTABLE_CLASS(object_class);
- e_printable_parent_class = g_type_class_ref (PARENT_TYPE);
-
- e_printable_signals [PRINT_PAGE] =
- g_signal_new ("print_page",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (EPrintableClass, print_page),
- NULL, NULL,
- e_marshal_NONE__OBJECT_DOUBLE_DOUBLE_BOOLEAN,
- G_TYPE_NONE, 4, G_TYPE_OBJECT, G_TYPE_DOUBLE,
- G_TYPE_DOUBLE, G_TYPE_BOOLEAN);
-
- e_printable_signals [DATA_LEFT] =
- g_signal_new ("data_left",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (EPrintableClass, data_left),
- NULL, NULL,
- e_marshal_BOOLEAN__NONE,
- G_TYPE_BOOLEAN, 0, G_TYPE_NONE);
-
- e_printable_signals [RESET] =
- g_signal_new ("reset",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (EPrintableClass, reset),
- NULL, NULL,
- e_marshal_NONE__NONE,
- G_TYPE_NONE, 0, G_TYPE_NONE);
-
- e_printable_signals [HEIGHT] =
- g_signal_new ("height",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (EPrintableClass, height),
- NULL, NULL,
- e_marshal_DOUBLE__OBJECT_DOUBLE_DOUBLE_BOOLEAN,
- G_TYPE_DOUBLE, 4, G_TYPE_OBJECT, G_TYPE_DOUBLE,
- G_TYPE_DOUBLE, G_TYPE_BOOLEAN);
-
- e_printable_signals [WILL_FIT] =
- g_signal_new ("will_fit",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (EPrintableClass, will_fit),
- NULL, NULL,
- e_marshal_BOOLEAN__OBJECT_DOUBLE_DOUBLE_BOOLEAN,
- G_TYPE_BOOLEAN, 4, G_TYPE_OBJECT, G_TYPE_DOUBLE,
- G_TYPE_DOUBLE, G_TYPE_BOOLEAN);
-
- klass->print_page = NULL;
- klass->data_left = NULL;
- klass->reset = NULL;
- klass->height = NULL;
- klass->will_fit = NULL;
-}
-
-
-E_MAKE_TYPE (e_printable,
- "EPrintable",
- EPrintable,
- e_printable_class_init,
- NULL,
- PARENT_TYPE)
-
-EPrintable *
-e_printable_new(void)
-{
- return E_PRINTABLE(g_object_new(E_PRINTABLE_TYPE, NULL));
-}
-
-void
-e_printable_print_page (EPrintable *e_printable,
- GnomePrintContext *context,
- gdouble width,
- gdouble height,
- gboolean quantized)
-{
- g_return_if_fail (e_printable != NULL);
- g_return_if_fail (E_IS_PRINTABLE (e_printable));
-
- g_signal_emit (e_printable,
- e_printable_signals [PRINT_PAGE], 0,
- context,
- width,
- height,
- quantized);
-}
-
-gboolean
-e_printable_data_left (EPrintable *e_printable)
-{
- gboolean ret_val;
-
- g_return_val_if_fail (e_printable != NULL, FALSE);
- g_return_val_if_fail (E_IS_PRINTABLE (e_printable), FALSE);
-
- g_signal_emit (e_printable,
- e_printable_signals [DATA_LEFT], 0,
- &ret_val);
-
- return ret_val;
-}
-
-void
-e_printable_reset (EPrintable *e_printable)
-{
- g_return_if_fail (e_printable != NULL);
- g_return_if_fail (E_IS_PRINTABLE (e_printable));
-
- g_signal_emit (e_printable,
- e_printable_signals [RESET], 0);
-}
-
-gdouble
-e_printable_height (EPrintable *e_printable,
- GnomePrintContext *context,
- gdouble width,
- gdouble max_height,
- gboolean quantized)
-{
- gdouble ret_val;
-
- g_return_val_if_fail (e_printable != NULL, -1);
- g_return_val_if_fail (E_IS_PRINTABLE (e_printable), -1);
-
- g_signal_emit (e_printable,
- e_printable_signals [HEIGHT], 0,
- context,
- width,
- max_height,
- quantized,
- &ret_val);
-
- return ret_val;
-}
-
-gboolean
-e_printable_will_fit (EPrintable *e_printable,
- GnomePrintContext *context,
- gdouble width,
- gdouble max_height,
- gboolean quantized)
-{
- gboolean ret_val;
-
- g_return_val_if_fail (e_printable != NULL, -1);
- g_return_val_if_fail (E_IS_PRINTABLE (e_printable), -1);
-
- g_signal_emit (e_printable,
- e_printable_signals [WILL_FIT], 0,
- context,
- width,
- max_height,
- quantized,
- &ret_val);
-
- return ret_val;
-}
diff --git a/widgets/misc/e-printable.h b/widgets/misc/e-printable.h
deleted file mode 100644
index 0c665f89c2..0000000000
--- a/widgets/misc/e-printable.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-printable.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_PRINTABLE_H_
-#define _E_PRINTABLE_H_
-
-#include <gtk/gtkobject.h>
-#include <libgnomeprint/gnome-print.h>
-
-G_BEGIN_DECLS
-
-#define E_PRINTABLE_TYPE (e_printable_get_type ())
-#define E_PRINTABLE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_PRINTABLE_TYPE, EPrintable))
-#define E_PRINTABLE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_PRINTABLE_TYPE, EPrintableClass))
-#define E_IS_PRINTABLE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_PRINTABLE_TYPE))
-#define E_IS_PRINTABLE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_PRINTABLE_TYPE))
-
-typedef struct {
- GtkObject base;
-} EPrintable;
-
-typedef struct {
- GtkObjectClass parent_class;
-
- /*
- * Signals
- */
-
- void (*print_page) (EPrintable *etm, GnomePrintContext *context, gdouble width, gdouble height, gboolean quantized);
- gboolean (*data_left) (EPrintable *etm);
- void (*reset) (EPrintable *etm);
- gdouble (*height) (EPrintable *etm, GnomePrintContext *context, gdouble width, gdouble max_height, gboolean quantized);
-
- /* e_printable_will_fit (ep, ...) should be equal in value to
- * (e_printable_print_page (ep, ...),
- * !e_printable_data_left(ep)) except that the latter has the
- * side effect of doing the printing and advancing the
- * position of the printable.
- */
-
- gboolean (*will_fit) (EPrintable *etm, GnomePrintContext *context, gdouble width, gdouble max_height, gboolean quantized);
-} EPrintableClass;
-
-GtkType e_printable_get_type (void);
-
-EPrintable *e_printable_new (void);
-
-/*
- * Routines for emitting signals on the e_table */
-void e_printable_print_page (EPrintable *e_printable,
- GnomePrintContext *context,
- gdouble width,
- gdouble height,
- gboolean quantized);
-gboolean e_printable_data_left (EPrintable *e_printable);
-void e_printable_reset (EPrintable *e_printable);
-gdouble e_printable_height (EPrintable *e_printable,
- GnomePrintContext *context,
- gdouble width,
- gdouble max_height,
- gboolean quantized);
-gboolean e_printable_will_fit (EPrintable *e_printable,
- GnomePrintContext *context,
- gdouble width,
- gdouble max_height,
- gboolean quantized);
-
-G_END_DECLS
-
-#endif /* _E_PRINTABLE_H_ */
diff --git a/widgets/misc/e-reflow-model.c b/widgets/misc/e-reflow-model.c
deleted file mode 100644
index 33a5498df5..0000000000
--- a/widgets/misc/e-reflow-model.c
+++ /dev/null
@@ -1,355 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-reflow-model.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include "e-reflow-model.h"
-#include "gal/util/e-util.h"
-
-#define PARENT_TYPE G_TYPE_OBJECT
-
-#define d(x)
-
-d(static gint depth = 0;)
-
-
-static GObjectClass *e_reflow_model_parent_class;
-
-enum {
- MODEL_CHANGED,
- COMPARISON_CHANGED,
- MODEL_ITEMS_INSERTED,
- MODEL_ITEM_CHANGED,
- MODEL_ITEM_REMOVED,
- LAST_SIGNAL
-};
-
-static guint e_reflow_model_signals [LAST_SIGNAL] = { 0, };
-
-/**
- * e_reflow_model_set_width:
- * @e_reflow_model: The e-reflow-model to operate on
- * @width: The new value for the width of each item.
- */
-void
-e_reflow_model_set_width (EReflowModel *e_reflow_model, int width)
-{
- g_return_if_fail (e_reflow_model != NULL);
- g_return_if_fail (E_IS_REFLOW_MODEL (e_reflow_model));
-
- E_REFLOW_MODEL_GET_CLASS (e_reflow_model)->set_width (e_reflow_model, width);
-}
-
-/**
- * e_reflow_model_count:
- * @e_reflow_model: The e-reflow-model to operate on
- *
- * Returns: the number of items in the reflow model.
- */
-int
-e_reflow_model_count (EReflowModel *e_reflow_model)
-{
- g_return_val_if_fail (e_reflow_model != NULL, 0);
- g_return_val_if_fail (E_IS_REFLOW_MODEL (e_reflow_model), 0);
-
- return E_REFLOW_MODEL_GET_CLASS (e_reflow_model)->count (e_reflow_model);
-}
-
-/**
- * e_reflow_model_height:
- * @e_reflow_model: The e-reflow-model to operate on
- * @n: The item number to get the height of.
- * @parent: The parent GnomeCanvasItem.
- *
- * Returns: the height of the nth item.
- */
-int
-e_reflow_model_height (EReflowModel *e_reflow_model, int n, GnomeCanvasGroup *parent)
-{
- g_return_val_if_fail (e_reflow_model != NULL, 0);
- g_return_val_if_fail (E_IS_REFLOW_MODEL (e_reflow_model), 0);
-
- return E_REFLOW_MODEL_GET_CLASS (e_reflow_model)->height (e_reflow_model, n, parent);
-}
-
-/**
- * e_reflow_model_incarnate:
- * @e_reflow_model: The e-reflow-model to operate on
- * @n: The item to create.
- * @parent: The parent GnomeCanvasItem to create a child of.
- *
- * Create a GnomeCanvasItem to represent the nth piece of data.
- *
- * Returns: the new GnomeCanvasItem.
- */
-GnomeCanvasItem *
-e_reflow_model_incarnate (EReflowModel *e_reflow_model, int n, GnomeCanvasGroup *parent)
-{
- g_return_val_if_fail (e_reflow_model != NULL, NULL);
- g_return_val_if_fail (E_IS_REFLOW_MODEL (e_reflow_model), NULL);
-
- return E_REFLOW_MODEL_GET_CLASS (e_reflow_model)->incarnate (e_reflow_model, n, parent);
-}
-
-/**
- * e_reflow_model_compare:
- * @e_reflow_model: The e-reflow-model to operate on
- * @n1: The first item to compare
- * @n2: The second item to compare
- *
- * Compares item n1 and item n2 to see which should come first.
- *
- * Returns: strcmp like semantics for the comparison value.
- */
-int
-e_reflow_model_compare (EReflowModel *e_reflow_model, int n1, int n2)
-{
-#if 0
- g_return_val_if_fail (e_reflow_model != NULL, 0);
- g_return_val_if_fail (E_IS_REFLOW_MODEL (e_reflow_model), 0);
-#endif
-
- return E_REFLOW_MODEL_GET_CLASS (e_reflow_model)->compare (e_reflow_model, n1, n2);
-}
-
-/**
- * e_reflow_model_reincarnate:
- * @e_reflow_model: The e-reflow-model to operate on
- * @n: The item to create.
- * @item: The item to reuse.
- *
- * Update item to represent the nth piece of data.
- */
-void
-e_reflow_model_reincarnate (EReflowModel *e_reflow_model, int n, GnomeCanvasItem *item)
-{
- g_return_if_fail (e_reflow_model != NULL);
- g_return_if_fail (E_IS_REFLOW_MODEL (e_reflow_model));
-
- E_REFLOW_MODEL_GET_CLASS (e_reflow_model)->reincarnate (e_reflow_model, n, item);
-}
-
-static void
-e_reflow_model_class_init (GObjectClass *object_class)
-{
- EReflowModelClass *klass = E_REFLOW_MODEL_CLASS(object_class);
- e_reflow_model_parent_class = g_type_class_ref (PARENT_TYPE);
-
- e_reflow_model_signals [MODEL_CHANGED] =
- g_signal_new ("model_changed",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (EReflowModelClass, model_changed),
- NULL, NULL,
- e_marshal_NONE__NONE,
- G_TYPE_NONE, 0);
-
- e_reflow_model_signals [COMPARISON_CHANGED] =
- g_signal_new ("comparison_changed",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (EReflowModelClass, comparison_changed),
- NULL, NULL,
- e_marshal_NONE__NONE,
- G_TYPE_NONE, 0);
-
- e_reflow_model_signals [MODEL_ITEMS_INSERTED] =
- g_signal_new ("model_items_inserted",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (EReflowModelClass, model_items_inserted),
- NULL, NULL,
- e_marshal_NONE__INT_INT,
- G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
-
- e_reflow_model_signals [MODEL_ITEM_CHANGED] =
- g_signal_new ("model_item_changed",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (EReflowModelClass, model_item_changed),
- NULL, NULL,
- e_marshal_NONE__INT,
- G_TYPE_NONE, 1, G_TYPE_INT);
-
- e_reflow_model_signals [MODEL_ITEM_REMOVED] =
- g_signal_new ("model_item_removed",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (EReflowModelClass, model_item_removed),
- NULL, NULL,
- e_marshal_NONE__INT,
- G_TYPE_NONE, 1, G_TYPE_INT);
-
- klass->set_width = NULL;
- klass->count = NULL;
- klass->height = NULL;
- klass->incarnate = NULL;
- klass->reincarnate = NULL;
-
- klass->model_changed = NULL;
- klass->comparison_changed = NULL;
- klass->model_items_inserted = NULL;
- klass->model_item_removed = NULL;
- klass->model_item_changed = NULL;
-}
-
-static void
-e_reflow_model_init (GObject *object)
-{
-}
-
-E_MAKE_TYPE(e_reflow_model, "EReflowModel", EReflowModel,
- e_reflow_model_class_init, e_reflow_model_init, PARENT_TYPE)
-
-#if d(!)0
-static void
-print_tabs (void)
-{
- int i;
- for (i = 0; i < depth; i++)
- g_print("\t");
-}
-#endif
-
-/**
- * e_reflow_model_changed:
- * @e_reflow_model: the reflow model to notify of the change
- *
- * Use this function to notify any views of this reflow model that
- * the contents of the reflow model have changed. This will emit
- * the signal "model_changed" on the @e_reflow_model object.
- *
- * It is preferable to use the e_reflow_model_item_changed() signal to
- * notify of smaller changes than to invalidate the entire model, as
- * the views might have ways of caching the information they render
- * from the model.
- */
-void
-e_reflow_model_changed (EReflowModel *e_reflow_model)
-{
- g_return_if_fail (e_reflow_model != NULL);
- g_return_if_fail (E_IS_REFLOW_MODEL (e_reflow_model));
-
- d(print_tabs());
- d(g_print("Emitting model_changed on model 0x%p.\n", e_reflow_model));
- d(depth++);
- g_signal_emit (e_reflow_model,
- e_reflow_model_signals [MODEL_CHANGED], 0);
- d(depth--);
-}
-
-/**
- * e_reflow_model_comparison_changed:
- * @e_reflow_model: the reflow model to notify of the change
- *
- * Use this function to notify any views of this reflow model that the
- * sorting has changed. The actual contents of the items hasn't, so
- * there's no need to re-query the model for the heights of the
- * individual items.
- */
-void
-e_reflow_model_comparison_changed (EReflowModel *e_reflow_model)
-{
- g_return_if_fail (e_reflow_model != NULL);
- g_return_if_fail (E_IS_REFLOW_MODEL (e_reflow_model));
-
- d(print_tabs());
- d(g_print("Emitting comparison_changed on model 0x%p.\n", e_reflow_model));
- d(depth++);
- g_signal_emit (e_reflow_model,
- e_reflow_model_signals [COMPARISON_CHANGED], 0);
- d(depth--);
-}
-
-/**
- * e_reflow_model_items_inserted:
- * @e_reflow_model: The model changed.
- * @position: The position the items were insert in.
- * @count: The number of items inserted.
- *
- * Use this function to notify any views of the reflow model that a number of items have been inserted.
- **/
-void
-e_reflow_model_items_inserted (EReflowModel *e_reflow_model, int position, int count)
-{
- g_return_if_fail (e_reflow_model != NULL);
- g_return_if_fail (E_IS_REFLOW_MODEL (e_reflow_model));
-
- d(print_tabs());
- d(g_print("Emitting items_inserted on model 0x%p, position=%d, count=%d.\n", e_reflow_model, position, count));
- d(depth++);
- g_signal_emit (e_reflow_model,
- e_reflow_model_signals [MODEL_ITEMS_INSERTED], 0,
- position, count);
- d(depth--);
-}
-
-/**
- * e_reflow_model_item_removed:
- * @e_reflow_model: The model changed.
- * @n: The position from which the items were removed.
- *
- * Use this function to notify any views of the reflow model that an
- * item has been removed.
- **/
-void
-e_reflow_model_item_removed (EReflowModel *e_reflow_model,
- int n)
-{
- g_return_if_fail (e_reflow_model != NULL);
- g_return_if_fail (E_IS_REFLOW_MODEL (e_reflow_model));
-
- d(print_tabs());
- d(g_print("Emitting item_removed on model 0x%p, n=%d.\n", e_reflow_model, n));
- d(depth++);
- g_signal_emit (e_reflow_model,
- e_reflow_model_signals [MODEL_ITEM_REMOVED], 0,
- n);
- d(depth--);
-}
-
-
-/**
- * e_reflow_model_item_changed:
- * @e_reflow_model: the reflow model to notify of the change
- * @item: the item that was changed in the model.
- *
- * Use this function to notify any views of the reflow model that the
- * contents of item @item have changed in model such that the height
- * has changed or the item needs to be reincarnated. This function
- * will emit the "model_item_changed" signal on the @e_reflow_model
- * object
- */
-void
-e_reflow_model_item_changed (EReflowModel *e_reflow_model, int n)
-{
- g_return_if_fail (e_reflow_model != NULL);
- g_return_if_fail (E_IS_REFLOW_MODEL (e_reflow_model));
-
- d(print_tabs());
- d(g_print("Emitting item_changed on model 0x%p, n=%d.\n", e_reflow_model, n));
- d(depth++);
- g_signal_emit (e_reflow_model,
- e_reflow_model_signals [MODEL_ITEM_CHANGED], 0,
- n);
- d(depth--);
-}
diff --git a/widgets/misc/e-reflow-model.h b/widgets/misc/e-reflow-model.h
deleted file mode 100644
index 25731b2af5..0000000000
--- a/widgets/misc/e-reflow-model.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-reflow-model.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_REFLOW_MODEL_H_
-#define _E_REFLOW_MODEL_H_
-
-#include <glib-object.h>
-#include <libgnomecanvas/gnome-canvas.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-#define E_REFLOW_MODEL_TYPE (e_reflow_model_get_type ())
-#define E_REFLOW_MODEL(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_REFLOW_MODEL_TYPE, EReflowModel))
-#define E_REFLOW_MODEL_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_REFLOW_MODEL_TYPE, EReflowModelClass))
-#define E_IS_REFLOW_MODEL(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_REFLOW_MODEL_TYPE))
-#define E_IS_REFLOW_MODEL_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_REFLOW_MODEL_TYPE))
-#define E_REFLOW_MODEL_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), E_REFLOW_MODEL_TYPE, EReflowModelClass))
-
-typedef struct {
- GObject base;
-} EReflowModel;
-
-typedef struct {
- GObjectClass parent_class;
-
- /*
- * Virtual methods
- */
- void (*set_width) (EReflowModel *etm, int width);
-
- int (*count) (EReflowModel *etm);
- int (*height) (EReflowModel *etm, int n, GnomeCanvasGroup *parent);
- GnomeCanvasItem *(*incarnate) (EReflowModel *etm, int n, GnomeCanvasGroup *parent);
- int (*compare) (EReflowModel *etm, int n1, int n2);
- void (*reincarnate) (EReflowModel *etm, int n, GnomeCanvasItem *item);
-
- /*
- * Signals
- */
-
- /*
- * These all come after the change has been made.
- * Major structural changes: model_changed
- * Changes to the sorting of elements: comparison_changed
- * Changes only in an item: item_changed
- */
- void (*model_changed) (EReflowModel *etm);
- void (*comparison_changed) (EReflowModel *etm);
- void (*model_items_inserted) (EReflowModel *etm, int position, int count);
- void (*model_item_removed) (EReflowModel *etm, int position);
- void (*model_item_changed) (EReflowModel *etm, int n);
-} EReflowModelClass;
-
-GType e_reflow_model_get_type (void);
-
-/**/
-void e_reflow_model_set_width (EReflowModel *e_reflow_model,
- int width);
-int e_reflow_model_count (EReflowModel *e_reflow_model);
-int e_reflow_model_height (EReflowModel *e_reflow_model,
- int n,
- GnomeCanvasGroup *parent);
-GnomeCanvasItem *e_reflow_model_incarnate (EReflowModel *e_reflow_model,
- int n,
- GnomeCanvasGroup *parent);
-int e_reflow_model_compare (EReflowModel *e_reflow_model,
- int n1,
- int n2);
-void e_reflow_model_reincarnate (EReflowModel *e_reflow_model,
- int n,
- GnomeCanvasItem *item);
-
-/*
- * Routines for emitting signals on the e_reflow
- */
-void e_reflow_model_changed (EReflowModel *e_reflow_model);
-void e_reflow_model_comparison_changed (EReflowModel *e_reflow_model);
-void e_reflow_model_items_inserted (EReflowModel *e_reflow_model,
- int position,
- int count);
-void e_reflow_model_item_removed (EReflowModel *e_reflow_model,
- int n);
-void e_reflow_model_item_changed (EReflowModel *e_reflow_model,
- int n);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* _E_REFLOW_MODEL_H_ */
diff --git a/widgets/misc/e-reflow.c b/widgets/misc/e-reflow.c
deleted file mode 100644
index a6888a11a6..0000000000
--- a/widgets/misc/e-reflow.c
+++ /dev/null
@@ -1,1506 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-reflow.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-
-#include "e-reflow.h"
-
-#include <math.h>
-#include <gdk/gdkkeysyms.h>
-#include "e-canvas-utils.h"
-#include "e-canvas.h"
-#include "gal/e-text/e-text.h"
-#include "gal/util/e-util.h"
-#include "gal/util/e-i18n.h"
-#include "gal/widgets/e-unicode.h"
-#include <gtk/gtksignal.h>
-#include "e-selection-model-simple.h"
-
-#include <string.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)
-
-#define PARENT_TYPE GNOME_TYPE_CANVAS_GROUP
-static GnomeCanvasGroupClass *parent_class = NULL;
-
-/* 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 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);
- }
- }
-}
-
-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] = 0;
- 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] = 0;
- 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, g_strdup(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;
-
- 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(parent_class)->dispose (object);
-}
-
-static void
-e_reflow_realize (GnomeCanvasItem *item)
-{
- EReflow *reflow;
- GnomeCanvasGroup *group;
- GtkAdjustment *adjustment;
- int count;
- int i;
-
- reflow = E_REFLOW (item);
- group = GNOME_CANVAS_GROUP (item);
-
- if (GNOME_CANVAS_ITEM_CLASS(parent_class)->realize)
- (* GNOME_CANVAS_ITEM_CLASS(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_destroy (reflow->arrow_cursor);
- gdk_cursor_destroy (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(parent_class)->unrealize)
- (* GNOME_CANVAS_ITEM_CLASS(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 0;
- i--;
- } else {
- if (i == count - 1)
- return 0;
- 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 1;
- }
- }
- }
- }
-#endif
- break;
- case GDK_BUTTON_PRESS:
- switch(event->button.button)
- {
- case 1:
- {
- GdkEventButton *button = (GdkEventButton *) event;
- double n_x, max_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));
-
- max_x = E_REFLOW_BORDER_WIDTH;
- max_x += (reflow->column_width + E_REFLOW_FULL_GUTTER) * reflow->column_count;
- if ( button->y >= E_REFLOW_BORDER_WIDTH && button->y <= reflow->height - E_REFLOW_BORDER_WIDTH && n_x < E_REFLOW_FULL_GUTTER && max_x > button->x ) {
- 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, max_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));
-
- max_x = E_REFLOW_BORDER_WIDTH;
- max_x += (reflow->column_width + E_REFLOW_FULL_GUTTER) * reflow->column_count;
-
- if ( motion->y >= E_REFLOW_BORDER_WIDTH && motion->y <= reflow->height - E_REFLOW_BORDER_WIDTH && n_x < E_REFLOW_FULL_GUTTER && max_x > motion->x) {
- 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, max_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));
-
- max_x = E_REFLOW_BORDER_WIDTH;
- max_x += (reflow->column_width + E_REFLOW_FULL_GUTTER) * reflow->column_count;
- if ( crossing->y >= E_REFLOW_BORDER_WIDTH && crossing->y <= reflow->height - E_REFLOW_BORDER_WIDTH && n_x < E_REFLOW_FULL_GUTTER && max_x > crossing->x) {
- 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( parent_class )->event)
- return (* GNOME_CANVAS_ITEM_CLASS( 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(parent_class)->draw)
- GNOME_CANVAS_ITEM_CLASS(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(parent_class)->update)
- GNOME_CANVAS_ITEM_CLASS(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(parent_class)->point)
- distance = GNOME_CANVAS_ITEM_CLASS(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;
-
- parent_class = g_type_class_ref (PARENT_TYPE);
-
- 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,
- e_marshal_NONE__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->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);
-}
-
-E_MAKE_TYPE (e_reflow,
- "EReflow",
- EReflow,
- e_reflow_class_init,
- e_reflow_init,
- PARENT_TYPE)
diff --git a/widgets/misc/e-reflow.h b/widgets/misc/e-reflow.h
deleted file mode 100644
index b92643a935..0000000000
--- a/widgets/misc/e-reflow.h
+++ /dev/null
@@ -1,146 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-reflow.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef __E_REFLOW_H__
-#define __E_REFLOW_H__
-
-#include <libgnomecanvas/gnome-canvas.h>
-#include <gal/widgets/e-reflow-model.h>
-#include <gal/widgets/e-selection-model.h>
-#include <gal/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;
-
- /* 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.
- */
-GtkType e_reflow_get_type (void);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* __E_REFLOW_H__ */
diff --git a/widgets/misc/e-selection-model-array.c b/widgets/misc/e-selection-model-array.c
deleted file mode 100644
index e6e96702a3..0000000000
--- a/widgets/misc/e-selection-model-array.c
+++ /dev/null
@@ -1,557 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-selection-model-array.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <gtk/gtksignal.h>
-#include "e-selection-model-array.h"
-#include "gal/util/e-i18n.h"
-#include "gal/util/e-util.h"
-
-#define PARENT_TYPE e_selection_model_get_type ()
-
-static ESelectionModelClass *parent_class;
-
-enum {
- PROP_0,
- PROP_CURSOR_ROW,
- PROP_CURSOR_COL
-};
-
-void
-e_selection_model_array_confirm_row_count(ESelectionModelArray *esma)
-{
- if (esma->eba == NULL) {
- int row_count = e_selection_model_array_get_row_count(esma);
- esma->eba = e_bit_array_new(row_count);
- esma->selected_row = -1;
- esma->selected_range_end = -1;
- }
-}
-
-/* FIXME: Should this deal with moving the selection if it's in single mode? */
-void
-e_selection_model_array_delete_rows(ESelectionModelArray *esma, int row, int count)
-{
- if (esma->eba) {
- if (E_SELECTION_MODEL(esma)->mode == GTK_SELECTION_SINGLE)
- e_bit_array_delete_single_mode(esma->eba, row, count);
- else
- e_bit_array_delete(esma->eba, row, count);
-
- if (esma->cursor_row > row + count)
- esma->cursor_row -= count;
- else if (esma->cursor_row > row)
- esma->cursor_row = row;
-
- if (esma->cursor_row >= e_bit_array_bit_count (esma->eba)) {
- esma->cursor_row = e_bit_array_bit_count (esma->eba) - 1;
- } else if (esma->cursor_row < 0) {
- esma->cursor_row = -1;
- }
- if (esma->cursor_row >= 0)
- e_bit_array_change_one_row(esma->eba, esma->cursor_row, TRUE);
-
- esma->selected_row = -1;
- esma->selected_range_end = -1;
- e_selection_model_selection_changed(E_SELECTION_MODEL(esma));
- e_selection_model_cursor_changed(E_SELECTION_MODEL(esma), esma->cursor_row, esma->cursor_col);
- }
-}
-
-void
-e_selection_model_array_insert_rows(ESelectionModelArray *esma, int row, int count)
-{
- if (esma->eba) {
- e_bit_array_insert(esma->eba, row, count);
-
- if (esma->cursor_row >= row)
- esma->cursor_row += count;
-
- esma->selected_row = -1;
- esma->selected_range_end = -1;
- e_selection_model_selection_changed(E_SELECTION_MODEL(esma));
- e_selection_model_cursor_changed(E_SELECTION_MODEL(esma), esma->cursor_row, esma->cursor_col);
- }
-}
-
-void
-e_selection_model_array_move_row(ESelectionModelArray *esma, int old_row, int new_row)
-{
- ESelectionModel *esm = E_SELECTION_MODEL(esma);
-
- if (esma->eba) {
- gboolean selected = e_bit_array_value_at(esma->eba, old_row);
- gboolean cursor = (esma->cursor_row == old_row);
-
- if (old_row < esma->cursor_row && esma->cursor_row < new_row)
- esma->cursor_row --;
- else if (new_row < esma->cursor_row && esma->cursor_row < old_row)
- esma->cursor_row ++;
-
- e_bit_array_move_row(esma->eba, old_row, new_row);
-
- if (selected) {
- if (esm->mode == GTK_SELECTION_SINGLE)
- e_bit_array_select_single_row (esma->eba, new_row);
- else
- e_bit_array_change_one_row(esma->eba, new_row, TRUE);
- }
- if (cursor) {
- esma->cursor_row = new_row;
- }
- esma->selected_row = -1;
- esma->selected_range_end = -1;
- e_selection_model_selection_changed(esm);
- e_selection_model_cursor_changed(esm, esma->cursor_row, esma->cursor_col);
- }
-}
-
-static void
-esma_dispose (GObject *object)
-{
- ESelectionModelArray *esma;
-
- esma = E_SELECTION_MODEL_ARRAY (object);
-
- if (esma->eba) {
- g_object_unref (esma->eba);
- esma->eba = NULL;
- }
-
- if (G_OBJECT_CLASS (parent_class)->dispose)
- (* G_OBJECT_CLASS (parent_class)->dispose) (object);
-}
-
-static void
-esma_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
-{
- ESelectionModelArray *esma = E_SELECTION_MODEL_ARRAY (object);
-
- switch (prop_id){
- case PROP_CURSOR_ROW:
- g_value_set_int (value, esma->cursor_row);
- break;
-
- case PROP_CURSOR_COL:
- g_value_set_int (value, esma->cursor_col);
- break;
- }
-}
-
-static void
-esma_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
-{
- ESelectionModel *esm = E_SELECTION_MODEL (object);
- ESelectionModelArray *esma = E_SELECTION_MODEL_ARRAY (object);
-
- switch (prop_id){
- case PROP_CURSOR_ROW:
- e_selection_model_do_something(esm, g_value_get_int (value), esma->cursor_col, 0);
- break;
-
- case PROP_CURSOR_COL:
- e_selection_model_do_something(esm, esma->cursor_row, g_value_get_int(value), 0);
- break;
- }
-}
-
-/**
- * e_selection_model_is_row_selected
- * @selection: #ESelectionModel to check
- * @n: The row to check
- *
- * This routine calculates whether the given row is selected.
- *
- * Returns: %TRUE if the given row is selected
- */
-static gboolean
-esma_is_row_selected (ESelectionModel *selection,
- gint n)
-{
- ESelectionModelArray *esma = E_SELECTION_MODEL_ARRAY(selection);
- if (esma->eba)
- return e_bit_array_value_at(esma->eba, n);
- else
- return FALSE;
-}
-
-/**
- * e_selection_model_foreach
- * @selection: #ESelectionModel to traverse
- * @callback: The callback function to call back.
- * @closure: The closure
- *
- * This routine calls the given callback function once for each
- * selected row, passing closure as the closure.
- */
-static void
-esma_foreach (ESelectionModel *selection,
- EForeachFunc callback,
- gpointer closure)
-{
- ESelectionModelArray *esma = E_SELECTION_MODEL_ARRAY(selection);
- if (esma->eba)
- e_bit_array_foreach(esma->eba, callback, closure);
-}
-
-/**
- * e_selection_model_clear
- * @selection: #ESelectionModel to clear
- *
- * This routine clears the selection to no rows selected.
- */
-static void
-esma_clear(ESelectionModel *selection)
-{
- ESelectionModelArray *esma = E_SELECTION_MODEL_ARRAY(selection);
- if (esma->eba) {
- g_object_unref(esma->eba);
- esma->eba = NULL;
- }
- esma->cursor_row = -1;
- esma->cursor_col = -1;
- esma->selected_row = -1;
- esma->selected_range_end = -1;
- e_selection_model_selection_changed(E_SELECTION_MODEL(esma));
- e_selection_model_cursor_changed(E_SELECTION_MODEL(esma), -1, -1);
-}
-
-#define PART(x,n) (((x) & (0x01010101 << n)) >> n)
-#define SECTION(x, n) (((x) >> (n * 8)) & 0xff)
-
-/**
- * e_selection_model_selected_count
- * @selection: #ESelectionModel to count
- *
- * This routine calculates the number of rows selected.
- *
- * Returns: The number of rows selected in the given model.
- */
-static gint
-esma_selected_count (ESelectionModel *selection)
-{
- ESelectionModelArray *esma = E_SELECTION_MODEL_ARRAY(selection);
- if (esma->eba)
- return e_bit_array_selected_count(esma->eba);
- else
- return 0;
-}
-
-/**
- * e_selection_model_select_all
- * @selection: #ESelectionModel to select all
- *
- * This routine selects all the rows in the given
- * #ESelectionModel.
- */
-static void
-esma_select_all (ESelectionModel *selection)
-{
- ESelectionModelArray *esma = E_SELECTION_MODEL_ARRAY(selection);
-
- e_selection_model_array_confirm_row_count(esma);
-
- e_bit_array_select_all(esma->eba);
-
- esma->cursor_col = 0;
- esma->cursor_row = 0;
- esma->selection_start_row = 0;
- esma->selected_row = -1;
- esma->selected_range_end = -1;
- e_selection_model_selection_changed(E_SELECTION_MODEL(esma));
- e_selection_model_cursor_changed(E_SELECTION_MODEL(esma), 0, 0);
-}
-
-/**
- * e_selection_model_invert_selection
- * @selection: #ESelectionModel to invert
- *
- * This routine inverts all the rows in the given
- * #ESelectionModel.
- */
-static void
-esma_invert_selection (ESelectionModel *selection)
-{
- ESelectionModelArray *esma = E_SELECTION_MODEL_ARRAY(selection);
-
- e_selection_model_array_confirm_row_count(esma);
-
- e_bit_array_invert_selection(esma->eba);
-
- esma->cursor_col = -1;
- esma->cursor_row = -1;
- esma->selection_start_row = 0;
- esma->selected_row = -1;
- esma->selected_range_end = -1;
- e_selection_model_selection_changed(E_SELECTION_MODEL(esma));
- e_selection_model_cursor_changed(E_SELECTION_MODEL(esma), -1, -1);
-}
-
-static int
-esma_row_count (ESelectionModel *selection)
-{
- ESelectionModelArray *esma = E_SELECTION_MODEL_ARRAY(selection);
- e_selection_model_array_confirm_row_count(esma);
- return e_bit_array_bit_count(esma->eba);
-}
-
-static void
-esma_change_one_row(ESelectionModel *selection, int row, gboolean grow)
-{
- ESelectionModelArray *esma = E_SELECTION_MODEL_ARRAY(selection);
- e_selection_model_array_confirm_row_count(esma);
- e_bit_array_change_one_row(esma->eba, row, grow);
-}
-
-static void
-esma_change_cursor (ESelectionModel *selection, int row, int col)
-{
- ESelectionModelArray *esma;
-
- g_return_if_fail(selection != NULL);
- g_return_if_fail(E_IS_SELECTION_MODEL(selection));
-
- esma = E_SELECTION_MODEL_ARRAY(selection);
-
- esma->cursor_row = row;
- esma->cursor_col = col;
-}
-
-static void
-esma_change_range(ESelectionModel *selection, int start, int end, gboolean grow)
-{
- int i;
- ESelectionModelArray *esma = E_SELECTION_MODEL_ARRAY(selection);
- if (start != end) {
- if (selection->sorter && e_sorter_needs_sorting(selection->sorter)) {
- for ( i = start; i < end; i++) {
- e_bit_array_change_one_row(esma->eba, e_sorter_sorted_to_model(selection->sorter, i), grow);
- }
- } else {
- e_selection_model_array_confirm_row_count(esma);
- e_bit_array_change_range(esma->eba, start, end, grow);
- }
- }
-}
-
-static int
-esma_cursor_row (ESelectionModel *selection)
-{
- ESelectionModelArray *esma = E_SELECTION_MODEL_ARRAY(selection);
- return esma->cursor_row;
-}
-
-static int
-esma_cursor_col (ESelectionModel *selection)
-{
- ESelectionModelArray *esma = E_SELECTION_MODEL_ARRAY(selection);
- return esma->cursor_col;
-}
-
-static void
-esma_real_select_single_row (ESelectionModel *selection, int row)
-{
- ESelectionModelArray *esma = E_SELECTION_MODEL_ARRAY(selection);
-
- e_selection_model_array_confirm_row_count(esma);
-
- e_bit_array_select_single_row(esma->eba, row);
-
- esma->selection_start_row = row;
- esma->selected_row = row;
- esma->selected_range_end = row;
-}
-
-static void
-esma_select_single_row (ESelectionModel *selection, int row)
-{
- ESelectionModelArray *esma = E_SELECTION_MODEL_ARRAY(selection);
- int selected_row = esma->selected_row;
- esma_real_select_single_row (selection, row);
-
- if (selected_row != -1 && esma->eba && selected_row < e_bit_array_bit_count (esma->eba)) {
- if (selected_row != row) {
- e_selection_model_selection_row_changed(selection, selected_row);
- e_selection_model_selection_row_changed(selection, row);
- }
- } else {
- e_selection_model_selection_changed(selection);
- }
-}
-
-static void
-esma_toggle_single_row (ESelectionModel *selection, int row)
-{
- ESelectionModelArray *esma = E_SELECTION_MODEL_ARRAY(selection);
-
- e_selection_model_array_confirm_row_count(esma);
- e_bit_array_toggle_single_row(esma->eba, row);
-
- esma->selection_start_row = row;
- esma->selected_row = -1;
- esma->selected_range_end = -1;
- e_selection_model_selection_row_changed(E_SELECTION_MODEL(esma), row);
-}
-
-static void
-esma_real_move_selection_end (ESelectionModel *selection, int row)
-{
- ESelectionModelArray *esma = E_SELECTION_MODEL_ARRAY(selection);
- int old_start;
- int old_end;
- int new_start;
- int new_end;
- if (selection->sorter && e_sorter_needs_sorting(selection->sorter)) {
- old_start = MIN (e_sorter_model_to_sorted(selection->sorter, esma->selection_start_row),
- e_sorter_model_to_sorted(selection->sorter, esma->cursor_row));
- old_end = MAX (e_sorter_model_to_sorted(selection->sorter, esma->selection_start_row),
- e_sorter_model_to_sorted(selection->sorter, esma->cursor_row)) + 1;
- new_start = MIN (e_sorter_model_to_sorted(selection->sorter, esma->selection_start_row),
- e_sorter_model_to_sorted(selection->sorter, row));
- new_end = MAX (e_sorter_model_to_sorted(selection->sorter, esma->selection_start_row),
- e_sorter_model_to_sorted(selection->sorter, row)) + 1;
- } else {
- old_start = MIN (esma->selection_start_row, esma->cursor_row);
- old_end = MAX (esma->selection_start_row, esma->cursor_row) + 1;
- new_start = MIN (esma->selection_start_row, row);
- new_end = MAX (esma->selection_start_row, row) + 1;
- }
- /* This wouldn't work nearly so smoothly if one end of the selection weren't held in place. */
- if (old_start < new_start)
- esma_change_range(selection, old_start, new_start, FALSE);
- if (new_start < old_start)
- esma_change_range(selection, new_start, old_start, TRUE);
- if (old_end < new_end)
- esma_change_range(selection, old_end, new_end, TRUE);
- if (new_end < old_end)
- esma_change_range(selection, new_end, old_end, FALSE);
- esma->selected_row = -1;
- esma->selected_range_end = -1;
-}
-
-static void
-esma_move_selection_end (ESelectionModel *selection, int row)
-{
- esma_real_move_selection_end (selection, row);
- e_selection_model_selection_changed(selection);
-}
-
-static void
-esma_set_selection_end (ESelectionModel *selection, int row)
-{
- ESelectionModelArray *esma = E_SELECTION_MODEL_ARRAY(selection);
- int selected_range_end = esma->selected_range_end;
- int view_row = e_sorter_model_to_sorted(selection->sorter, row);
-
- esma_real_select_single_row(selection, esma->selection_start_row);
- esma->cursor_row = esma->selection_start_row;
- esma_real_move_selection_end(selection, row);
-
- esma->selected_range_end = view_row;
- if (selected_range_end != -1 && view_row != -1) {
- if (selected_range_end == view_row - 1 ||
- selected_range_end == view_row + 1) {
- e_selection_model_selection_row_changed(selection, selected_range_end);
- e_selection_model_selection_row_changed(selection, view_row);
- }
- }
- e_selection_model_selection_changed(selection);
-}
-
-int
-e_selection_model_array_get_row_count (ESelectionModelArray *esma)
-{
- g_return_val_if_fail(esma != NULL, 0);
- g_return_val_if_fail(E_IS_SELECTION_MODEL_ARRAY(esma), 0);
-
- if (E_SELECTION_MODEL_ARRAY_GET_CLASS(esma)->get_row_count)
- return E_SELECTION_MODEL_ARRAY_GET_CLASS(esma)->get_row_count (esma);
- else
- return 0;
-}
-
-
-static void
-e_selection_model_array_init (ESelectionModelArray *esma)
-{
- esma->eba = NULL;
- esma->selection_start_row = 0;
- esma->cursor_row = -1;
- esma->cursor_col = -1;
-
- esma->selected_row = -1;
- esma->selected_range_end = -1;
-}
-
-static void
-e_selection_model_array_class_init (ESelectionModelArrayClass *klass)
-{
- GObjectClass *object_class;
- ESelectionModelClass *esm_class;
-
- parent_class = g_type_class_ref (PARENT_TYPE);
-
- object_class = G_OBJECT_CLASS(klass);
- esm_class = E_SELECTION_MODEL_CLASS(klass);
-
- object_class->dispose = esma_dispose;
- object_class->get_property = esma_get_property;
- object_class->set_property = esma_set_property;
-
- esm_class->is_row_selected = esma_is_row_selected ;
- esm_class->foreach = esma_foreach ;
- esm_class->clear = esma_clear ;
- esm_class->selected_count = esma_selected_count ;
- esm_class->select_all = esma_select_all ;
- esm_class->invert_selection = esma_invert_selection ;
- esm_class->row_count = esma_row_count ;
-
- esm_class->change_one_row = esma_change_one_row ;
- esm_class->change_cursor = esma_change_cursor ;
- esm_class->cursor_row = esma_cursor_row ;
- esm_class->cursor_col = esma_cursor_col ;
-
- esm_class->select_single_row = esma_select_single_row ;
- esm_class->toggle_single_row = esma_toggle_single_row ;
- esm_class->move_selection_end = esma_move_selection_end ;
- esm_class->set_selection_end = esma_set_selection_end ;
-
- klass->get_row_count = NULL ;
-
- g_object_class_install_property (object_class, PROP_CURSOR_ROW,
- g_param_spec_int ("cursor_row",
- _("Cursor Row"),
- /*_( */"XXX blurb" /*)*/,
- 0, G_MAXINT, 0,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class, PROP_CURSOR_COL,
- g_param_spec_int ("cursor_col",
- _("Cursor Column"),
- /*_( */"XXX blurb" /*)*/,
- 0, G_MAXINT, 0,
- G_PARAM_READWRITE));
-}
-
-E_MAKE_TYPE(e_selection_model_array, "ESelectionModelArray", ESelectionModelArray,
- e_selection_model_array_class_init, e_selection_model_array_init, PARENT_TYPE)
diff --git a/widgets/misc/e-selection-model-array.h b/widgets/misc/e-selection-model-array.h
deleted file mode 100644
index a533030f92..0000000000
--- a/widgets/misc/e-selection-model-array.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-selection-model-array.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_SELECTION_MODEL_ARRAY_H_
-#define _E_SELECTION_MODEL_ARRAY_H_
-
-#include <gtk/gtkobject.h>
-#include <gal/widgets/e-selection-model.h>
-#include <gal/util/e-bit-array.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-#define E_SELECTION_MODEL_ARRAY_TYPE (e_selection_model_array_get_type ())
-#define E_SELECTION_MODEL_ARRAY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_SELECTION_MODEL_ARRAY_TYPE, ESelectionModelArray))
-#define E_SELECTION_MODEL_ARRAY_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_SELECTION_MODEL_ARRAY_TYPE, ESelectionModelArrayClass))
-#define E_IS_SELECTION_MODEL_ARRAY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_SELECTION_MODEL_ARRAY_TYPE))
-#define E_IS_SELECTION_MODEL_ARRAY_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_SELECTION_MODEL_ARRAY_TYPE))
-#define E_SELECTION_MODEL_ARRAY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), E_SELECTION_MODEL_ARRAY_TYPE, ESelectionModelArrayClass))
-
-typedef struct {
- ESelectionModel base;
-
- EBitArray *eba;
-
- gint cursor_row;
- gint cursor_col;
- gint selection_start_row;
-
- guint model_changed_id;
- guint model_row_inserted_id, model_row_deleted_id;
-
- /* Anything other than -1 means that the selection is a single
- * row. This being -1 does not impart any information. */
- gint selected_row;
- /* Anything other than -1 means that the selection is a all
- * rows between selection_start_path and cursor_path where
- * selected_range_end is the rwo number of cursor_path. This
- * being -1 does not impart any information. */
- gint selected_range_end;
-
- guint frozen : 1;
- guint selection_model_changed : 1;
- guint group_info_changed : 1;
-} ESelectionModelArray;
-
-typedef struct {
- ESelectionModelClass parent_class;
-
- gint (*get_row_count) (ESelectionModelArray *selection);
-} ESelectionModelArrayClass;
-
-GType e_selection_model_array_get_type (void);
-
-/* Protected Functions */
-void e_selection_model_array_insert_rows (ESelectionModelArray *esm,
- int row,
- int count);
-void e_selection_model_array_delete_rows (ESelectionModelArray *esm,
- int row,
- int count);
-void e_selection_model_array_move_row (ESelectionModelArray *esm,
- int old_row,
- int new_row);
-void e_selection_model_array_confirm_row_count (ESelectionModelArray *esm);
-
-/* Protected Virtual Function */
-gint e_selection_model_array_get_row_count (ESelectionModelArray *esm);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-
-#endif /* _E_SELECTION_MODEL_ARRAY_H_ */
diff --git a/widgets/misc/e-selection-model-simple.c b/widgets/misc/e-selection-model-simple.c
deleted file mode 100644
index 51a0d86623..0000000000
--- a/widgets/misc/e-selection-model-simple.c
+++ /dev/null
@@ -1,115 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-selection-model-simple.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <gal/util/e-util.h>
-#include "e-selection-model-array.h"
-#include "e-selection-model-simple.h"
-
-#define PARENT_TYPE e_selection_model_array_get_type ()
-
-static ESelectionModelArray *parent_class;
-
-static gint esms_get_row_count (ESelectionModelArray *esma);
-
-static void
-e_selection_model_simple_init (ESelectionModelSimple *selection)
-{
- selection->row_count = 0;
-}
-
-static void
-e_selection_model_simple_class_init (ESelectionModelSimpleClass *klass)
-{
- ESelectionModelArrayClass *esma_class;
-
- parent_class = g_type_class_ref (PARENT_TYPE);
-
- esma_class = E_SELECTION_MODEL_ARRAY_CLASS(klass);
-
- esma_class->get_row_count = esms_get_row_count;
-}
-
-E_MAKE_TYPE(e_selection_model_simple, "ESelectionModelSimple", ESelectionModelSimple,
- e_selection_model_simple_class_init, e_selection_model_simple_init, PARENT_TYPE)
-
-/**
- * e_selection_model_simple_new
- *
- * This routine creates a new #ESelectionModelSimple.
- *
- * Returns: The new #ESelectionModelSimple.
- */
-ESelectionModelSimple *
-e_selection_model_simple_new (void)
-{
- return g_object_new (E_SELECTION_MODEL_SIMPLE_TYPE, NULL);
-}
-
-void
-e_selection_model_simple_set_row_count (ESelectionModelSimple *esms,
- int row_count)
-{
- if (esms->row_count != row_count) {
- ESelectionModelArray *esma = E_SELECTION_MODEL_ARRAY(esms);
- if (esma->eba)
- g_object_unref(esma->eba);
- esma->eba = NULL;
- esma->selected_row = -1;
- esma->selected_range_end = -1;
- }
- esms->row_count = row_count;
-}
-
-static gint
-esms_get_row_count (ESelectionModelArray *esma)
-{
- ESelectionModelSimple *esms = E_SELECTION_MODEL_SIMPLE(esma);
-
- return esms->row_count;
-}
-
-void e_selection_model_simple_insert_rows (ESelectionModelSimple *esms,
- int row,
- int count)
-{
- esms->row_count += count;
- e_selection_model_array_insert_rows (E_SELECTION_MODEL_ARRAY(esms), row, count);
-}
-
-void
-e_selection_model_simple_delete_rows (ESelectionModelSimple *esms,
- int row,
- int count)
-{
- esms->row_count -= count;
- e_selection_model_array_delete_rows (E_SELECTION_MODEL_ARRAY(esms), row, count);
-}
-
-void
-e_selection_model_simple_move_row (ESelectionModelSimple *esms,
- int old_row,
- int new_row)
-{
- e_selection_model_array_move_row (E_SELECTION_MODEL_ARRAY(esms), old_row, new_row);
-}
diff --git a/widgets/misc/e-selection-model-simple.h b/widgets/misc/e-selection-model-simple.h
deleted file mode 100644
index 6b4f84b4f9..0000000000
--- a/widgets/misc/e-selection-model-simple.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-selection-model-simple.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_SELECTION_MODEL_SIMPLE_H_
-#define _E_SELECTION_MODEL_SIMPLE_H_
-
-#include <gal/widgets/e-selection-model-array.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-#define E_SELECTION_MODEL_SIMPLE_TYPE (e_selection_model_simple_get_type ())
-#define E_SELECTION_MODEL_SIMPLE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_SELECTION_MODEL_SIMPLE_TYPE, ESelectionModelSimple))
-#define E_SELECTION_MODEL_SIMPLE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_SELECTION_MODEL_SIMPLE_TYPE, ESelectionModelSimpleClass))
-#define E_IS_SELECTION_MODEL_SIMPLE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_SELECTION_MODEL_SIMPLE_TYPE))
-#define E_IS_SELECTION_MODEL_SIMPLE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_SELECTION_MODEL_SIMPLE_TYPE))
-
-typedef struct {
- ESelectionModelArray parent;
-
- int row_count;
-} ESelectionModelSimple;
-
-typedef struct {
- ESelectionModelArrayClass parent_class;
-} ESelectionModelSimpleClass;
-
-GType e_selection_model_simple_get_type (void);
-ESelectionModelSimple *e_selection_model_simple_new (void);
-
-void e_selection_model_simple_insert_rows (ESelectionModelSimple *esms,
- int row,
- int count);
-void e_selection_model_simple_delete_rows (ESelectionModelSimple *esms,
- int row,
- int count);
-void e_selection_model_simple_move_row (ESelectionModelSimple *esms,
- int old_row,
- int new_row);
-
-void e_selection_model_simple_set_row_count (ESelectionModelSimple *selection,
- int row_count);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* _E_SELECTION_MODEL_SIMPLE_H_ */
-
diff --git a/widgets/misc/e-selection-model.c b/widgets/misc/e-selection-model.c
deleted file mode 100644
index 991fc78490..0000000000
--- a/widgets/misc/e-selection-model.c
+++ /dev/null
@@ -1,689 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-selection-model.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <gdk/gdkkeysyms.h>
-#include "e-selection-model.h"
-#include "gal/util/e-i18n.h"
-#include "gal/util/e-util.h"
-
-#define PARENT_TYPE G_TYPE_OBJECT
-
-static GObjectClass *e_selection_model_parent_class;
-
-enum {
- CURSOR_CHANGED,
- CURSOR_ACTIVATED,
- SELECTION_CHANGED,
- SELECTION_ROW_CHANGED,
- LAST_SIGNAL
-};
-
-static guint e_selection_model_signals [LAST_SIGNAL] = { 0, };
-
-enum {
- PROP_0,
- PROP_SORTER,
- PROP_SELECTION_MODE,
- PROP_CURSOR_MODE
-};
-
-inline static void
-add_sorter(ESelectionModel *esm, ESorter *sorter)
-{
- esm->sorter = sorter;
- if (sorter) {
- g_object_ref (sorter);
- }
-}
-
-inline static void
-drop_sorter(ESelectionModel *esm)
-{
- if (esm->sorter) {
- g_object_unref (esm->sorter);
- }
- esm->sorter = NULL;
-}
-
-static void
-esm_dispose (GObject *object)
-{
- ESelectionModel *esm;
-
- esm = E_SELECTION_MODEL (object);
-
- drop_sorter(esm);
-
- if (e_selection_model_parent_class->dispose)
- (* e_selection_model_parent_class->dispose) (object);
-}
-
-static void
-esm_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
-{
- ESelectionModel *esm = E_SELECTION_MODEL (object);
-
- switch (prop_id){
- case PROP_SORTER:
- g_value_set_object (value, esm->sorter);
- break;
-
- case PROP_SELECTION_MODE:
- g_value_set_int (value, esm->mode);
- break;
-
- case PROP_CURSOR_MODE:
- g_value_set_int (value, esm->cursor_mode);
- break;
- }
-}
-
-static void
-esm_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
-{
- ESelectionModel *esm = E_SELECTION_MODEL (object);
-
- switch (prop_id){
- case PROP_SORTER:
- drop_sorter(esm);
- add_sorter(esm, g_value_get_object (value) ? E_SORTER(g_value_get_object(value)) : NULL);
- break;
-
- case PROP_SELECTION_MODE:
- esm->mode = g_value_get_int (value);
- if (esm->mode == GTK_SELECTION_SINGLE) {
- int cursor_row = e_selection_model_cursor_row(esm);
- int cursor_col = e_selection_model_cursor_col(esm);
- e_selection_model_do_something(esm, cursor_row, cursor_col, 0);
- }
- break;
-
- case PROP_CURSOR_MODE:
- esm->cursor_mode = g_value_get_int (value);
- break;
- }
-}
-
-static void
-e_selection_model_init (ESelectionModel *selection)
-{
- selection->mode = GTK_SELECTION_MULTIPLE;
- selection->cursor_mode = E_CURSOR_SIMPLE;
- selection->old_selection = -1;
-}
-
-static void
-e_selection_model_class_init (ESelectionModelClass *klass)
-{
- GObjectClass *object_class;
-
- e_selection_model_parent_class = g_type_class_ref (PARENT_TYPE);
-
- object_class = G_OBJECT_CLASS(klass);
-
- object_class->dispose = esm_dispose;
- object_class->get_property = esm_get_property;
- object_class->set_property = esm_set_property;
-
- e_selection_model_signals [CURSOR_CHANGED] =
- g_signal_new ("cursor_changed",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ESelectionModelClass, cursor_changed),
- NULL, NULL,
- e_marshal_NONE__INT_INT,
- G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
-
- e_selection_model_signals [CURSOR_ACTIVATED] =
- g_signal_new ("cursor_activated",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ESelectionModelClass, cursor_activated),
- NULL, NULL,
- e_marshal_NONE__INT_INT,
- G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
-
- e_selection_model_signals [SELECTION_CHANGED] =
- g_signal_new ("selection_changed",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ESelectionModelClass, selection_changed),
- NULL, NULL,
- e_marshal_NONE__NONE,
- G_TYPE_NONE, 0);
-
- e_selection_model_signals [SELECTION_ROW_CHANGED] =
- g_signal_new ("selection_row_changed",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ESelectionModelClass, selection_row_changed),
- NULL, NULL,
- e_marshal_NONE__INT,
- G_TYPE_NONE, 1, G_TYPE_INT);
-
- klass->cursor_changed = NULL;
- klass->cursor_activated = NULL;
- klass->selection_changed = NULL;
- klass->selection_row_changed = NULL;
-
- klass->is_row_selected = NULL;
- klass->foreach = NULL;
- klass->clear = NULL;
- klass->selected_count = NULL;
- klass->select_all = NULL;
- klass->invert_selection = NULL;
- klass->row_count = NULL;
-
- klass->change_one_row = NULL;
- klass->change_cursor = NULL;
- klass->cursor_row = NULL;
- klass->cursor_col = NULL;
-
- klass->select_single_row = NULL;
- klass->toggle_single_row = NULL;
- klass->move_selection_end = NULL;
- klass->set_selection_end = NULL;
-
- g_object_class_install_property (object_class, PROP_SORTER,
- g_param_spec_object ("sorter",
- _("Sorter"),
- /*_( */"XXX blurb" /*)*/,
- E_SORTER_TYPE,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class, PROP_SELECTION_MODE,
- g_param_spec_int ("selection_mode",
- _("Selection Mode"),
- /*_( */"XXX blurb" /*)*/,
- GTK_SELECTION_NONE, GTK_SELECTION_MULTIPLE,
- GTK_SELECTION_SINGLE,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class, PROP_CURSOR_MODE,
- g_param_spec_int ("cursor_mode",
- _("Cursor Mode"),
- /*_( */"XXX blurb" /*)*/,
- E_CURSOR_LINE, E_CURSOR_SPREADSHEET,
- E_CURSOR_LINE,
- G_PARAM_READWRITE));
-}
-
-E_MAKE_TYPE(e_selection_model, "ESelectionModel", ESelectionModel,
- e_selection_model_class_init, e_selection_model_init, PARENT_TYPE)
-
-/**
- * e_selection_model_is_row_selected
- * @selection: #ESelectionModel to check
- * @n: The row to check
- *
- * This routine calculates whether the given row is selected.
- *
- * Returns: %TRUE if the given row is selected
- */
-gboolean
-e_selection_model_is_row_selected (ESelectionModel *selection,
- gint n)
-{
- if (E_SELECTION_MODEL_GET_CLASS(selection)->is_row_selected)
- return E_SELECTION_MODEL_GET_CLASS(selection)->is_row_selected (selection, n);
- else
- return FALSE;
-}
-
-/**
- * e_selection_model_foreach
- * @selection: #ESelectionModel to traverse
- * @callback: The callback function to call back.
- * @closure: The closure
- *
- * This routine calls the given callback function once for each
- * selected row, passing closure as the closure.
- */
-void
-e_selection_model_foreach (ESelectionModel *selection,
- EForeachFunc callback,
- gpointer closure)
-{
- if (E_SELECTION_MODEL_GET_CLASS(selection)->foreach)
- E_SELECTION_MODEL_GET_CLASS(selection)->foreach (selection, callback, closure);
-}
-
-/**
- * e_selection_model_clear
- * @selection: #ESelectionModel to clear
- *
- * This routine clears the selection to no rows selected.
- */
-void
-e_selection_model_clear(ESelectionModel *selection)
-{
- if (E_SELECTION_MODEL_GET_CLASS(selection)->clear)
- E_SELECTION_MODEL_GET_CLASS(selection)->clear (selection);
-}
-
-/**
- * e_selection_model_selected_count
- * @selection: #ESelectionModel to count
- *
- * This routine calculates the number of rows selected.
- *
- * Returns: The number of rows selected in the given model.
- */
-gint
-e_selection_model_selected_count (ESelectionModel *selection)
-{
- if (E_SELECTION_MODEL_GET_CLASS(selection)->selected_count)
- return E_SELECTION_MODEL_GET_CLASS(selection)->selected_count (selection);
- else
- return 0;
-}
-
-/**
- * e_selection_model_select_all
- * @selection: #ESelectionModel to select all
- *
- * This routine selects all the rows in the given
- * #ESelectionModel.
- */
-void
-e_selection_model_select_all (ESelectionModel *selection)
-{
- if (E_SELECTION_MODEL_GET_CLASS(selection)->select_all)
- E_SELECTION_MODEL_GET_CLASS(selection)->select_all (selection);
-}
-
-/**
- * e_selection_model_invert_selection
- * @selection: #ESelectionModel to invert
- *
- * This routine inverts all the rows in the given
- * #ESelectionModel.
- */
-void
-e_selection_model_invert_selection (ESelectionModel *selection)
-{
- if (E_SELECTION_MODEL_GET_CLASS(selection)->invert_selection)
- E_SELECTION_MODEL_GET_CLASS(selection)->invert_selection (selection);
-}
-
-int
-e_selection_model_row_count (ESelectionModel *selection)
-{
- if (E_SELECTION_MODEL_GET_CLASS(selection)->row_count)
- return E_SELECTION_MODEL_GET_CLASS(selection)->row_count (selection);
- else
- return 0;
-}
-
-void
-e_selection_model_change_one_row(ESelectionModel *selection, int row, gboolean grow)
-{
- if (E_SELECTION_MODEL_GET_CLASS(selection)->change_one_row)
- E_SELECTION_MODEL_GET_CLASS(selection)->change_one_row (selection, row, grow);
-}
-
-void
-e_selection_model_change_cursor (ESelectionModel *selection, int row, int col)
-{
- if (E_SELECTION_MODEL_GET_CLASS(selection)->change_cursor)
- E_SELECTION_MODEL_GET_CLASS(selection)->change_cursor (selection, row, col);
-}
-
-int
-e_selection_model_cursor_row (ESelectionModel *selection)
-{
- if (E_SELECTION_MODEL_GET_CLASS(selection)->cursor_row)
- return E_SELECTION_MODEL_GET_CLASS(selection)->cursor_row (selection);
- else
- return -1;
-}
-
-int
-e_selection_model_cursor_col (ESelectionModel *selection)
-{
- if (E_SELECTION_MODEL_GET_CLASS(selection)->cursor_col)
- return E_SELECTION_MODEL_GET_CLASS(selection)->cursor_col (selection);
- else
- return -1;
-}
-
-void
-e_selection_model_select_single_row (ESelectionModel *selection, int row)
-{
- if (E_SELECTION_MODEL_GET_CLASS(selection)->select_single_row)
- E_SELECTION_MODEL_GET_CLASS(selection)->select_single_row (selection, row);
-}
-
-void
-e_selection_model_toggle_single_row (ESelectionModel *selection, int row)
-{
- if (E_SELECTION_MODEL_GET_CLASS(selection)->toggle_single_row)
- E_SELECTION_MODEL_GET_CLASS(selection)->toggle_single_row (selection, row);
-}
-
-void
-e_selection_model_move_selection_end (ESelectionModel *selection, int row)
-{
- if (E_SELECTION_MODEL_GET_CLASS(selection)->move_selection_end)
- E_SELECTION_MODEL_GET_CLASS(selection)->move_selection_end (selection, row);
-}
-
-void
-e_selection_model_set_selection_end (ESelectionModel *selection, int row)
-{
- if (E_SELECTION_MODEL_GET_CLASS(selection)->set_selection_end)
- E_SELECTION_MODEL_GET_CLASS(selection)->set_selection_end (selection, row);
-}
-
-/**
- * e_selection_model_do_something
- * @selection: #ESelectionModel to do something to.
- * @row: The row to do something in.
- * @col: The col to do something in.
- * @state: The state in which to do something.
- *
- * This routine does whatever is appropriate as if the user clicked
- * the mouse in the given row and column.
- */
-void
-e_selection_model_do_something (ESelectionModel *selection,
- guint row,
- guint col,
- GdkModifierType state)
-{
- gint shift_p = state & GDK_SHIFT_MASK;
- gint ctrl_p = state & GDK_CONTROL_MASK;
- int row_count;
-
- selection->old_selection = -1;
-
- if (row == -1 && col != -1)
- row = 0;
- if (col == -1 && row != -1)
- col = 0;
-
- row_count = e_selection_model_row_count(selection);
- if (row_count >= 0 && row < row_count) {
- switch (selection->mode) {
- case GTK_SELECTION_SINGLE:
- e_selection_model_select_single_row (selection, row);
- break;
- case GTK_SELECTION_BROWSE:
- case GTK_SELECTION_MULTIPLE:
- if (shift_p) {
- e_selection_model_set_selection_end (selection, row);
- } else {
- if (ctrl_p) {
- e_selection_model_toggle_single_row (selection, row);
- } else {
- e_selection_model_select_single_row (selection, row);
- }
- }
- break;
- default:
- g_assert_not_reached ();
- break;
- }
- e_selection_model_change_cursor(selection, row, col);
- g_signal_emit(selection,
- e_selection_model_signals[CURSOR_CHANGED], 0,
- row, col);
- g_signal_emit(selection,
- e_selection_model_signals[CURSOR_ACTIVATED], 0,
- row, col);
- }
-}
-
-/**
- * e_selection_model_maybe_do_something
- * @selection: #ESelectionModel to do something to.
- * @row: The row to do something in.
- * @col: The col to do something in.
- * @state: The state in which to do something.
- *
- * If this row is selected, this routine just moves the cursor row and
- * column. Otherwise, it does the same thing as
- * e_selection_model_do_something(). This is for being used on
- * right clicks and other events where if the user hit the selection,
- * they don't want it to change.
- */
-gboolean
-e_selection_model_maybe_do_something (ESelectionModel *selection,
- guint row,
- guint col,
- GdkModifierType state)
-{
- selection->old_selection = -1;
-
- if (e_selection_model_is_row_selected(selection, row)) {
- e_selection_model_change_cursor(selection, row, col);
- g_signal_emit(selection,
- e_selection_model_signals[CURSOR_CHANGED], 0,
- row, col);
- return FALSE;
- } else {
- e_selection_model_do_something(selection, row, col, state);
- return TRUE;
- }
-}
-
-void
-e_selection_model_right_click_down (ESelectionModel *selection,
- guint row,
- guint col,
- GdkModifierType state)
-{
- if (selection->mode == GTK_SELECTION_SINGLE) {
- selection->old_selection = e_selection_model_cursor_row (selection);
- e_selection_model_select_single_row (selection, row);
- } else {
- e_selection_model_maybe_do_something (selection, row, col, state);
- }
-}
-
-void
-e_selection_model_right_click_up (ESelectionModel *selection)
-{
- if (selection->mode == GTK_SELECTION_SINGLE && selection->old_selection != -1) {
- e_selection_model_select_single_row (selection, selection->old_selection);
- }
-}
-
-void
-e_selection_model_select_as_key_press (ESelectionModel *selection,
- guint row,
- guint col,
- GdkModifierType state)
-{
- int cursor_activated = TRUE;
-
- gint shift_p = state & GDK_SHIFT_MASK;
- gint ctrl_p = state & GDK_CONTROL_MASK;
-
- selection->old_selection = -1;
-
- switch (selection->mode) {
- case GTK_SELECTION_BROWSE:
- case GTK_SELECTION_MULTIPLE:
- if (shift_p) {
- e_selection_model_set_selection_end (selection, row);
- } else if (!ctrl_p) {
- e_selection_model_select_single_row (selection, row);
- } else
- cursor_activated = FALSE;
- break;
- case GTK_SELECTION_SINGLE:
- e_selection_model_select_single_row (selection, row);
- break;
- default:
- g_assert_not_reached ();
- break;
- }
- if (row != -1) {
- e_selection_model_change_cursor(selection, row, col);
- g_signal_emit(selection,
- e_selection_model_signals[CURSOR_CHANGED], 0,
- row, col);
- if (cursor_activated)
- g_signal_emit(selection,
- e_selection_model_signals[CURSOR_ACTIVATED], 0,
- row, col);
- }
-}
-
-static gint
-move_selection (ESelectionModel *selection,
- gboolean up,
- GdkModifierType state)
-{
- int row = e_selection_model_cursor_row(selection);
- int col = e_selection_model_cursor_col(selection);
- int row_count;
-
- row = e_sorter_model_to_sorted(selection->sorter, row);
- if (up)
- row--;
- else
- row++;
- if (row < 0)
- row = 0;
- row_count = e_selection_model_row_count(selection);
- if (row >= row_count)
- row = row_count - 1;
- row = e_sorter_sorted_to_model(selection->sorter, row);
-
- e_selection_model_select_as_key_press (selection, row, col, state);
- return TRUE;
-}
-
-/**
- * e_selection_model_key_press
- * @selection: #ESelectionModel to affect.
- * @key: The event.
- *
- * This routine does whatever is appropriate as if the user pressed
- * the given key.
- *
- * Returns: %TRUE if the #ESelectionModel used the key.
- */
-gint
-e_selection_model_key_press (ESelectionModel *selection,
- GdkEventKey *key)
-{
- selection->old_selection = -1;
-
- switch (key->keyval) {
- case GDK_Up:
- case GDK_KP_Up:
- return move_selection(selection, TRUE, key->state);
- break;
- case GDK_Down:
- case GDK_KP_Down:
- return move_selection(selection, FALSE, key->state);
- break;
- case GDK_space:
- case GDK_KP_Space:
- if (selection->mode != GTK_SELECTION_SINGLE) {
- int row = e_selection_model_cursor_row(selection);
- int col = e_selection_model_cursor_col(selection);
- e_selection_model_toggle_single_row (selection, row);
- g_signal_emit(selection,
- e_selection_model_signals[CURSOR_ACTIVATED], 0,
- row, col);
- return TRUE;
- }
- break;
- case GDK_Return:
- case GDK_KP_Enter:
- if (selection->mode != GTK_SELECTION_SINGLE) {
- int row = e_selection_model_cursor_row(selection);
- int col = e_selection_model_cursor_col(selection);
- e_selection_model_select_single_row (selection, row);
- g_signal_emit(selection,
- e_selection_model_signals[CURSOR_ACTIVATED], 0,
- row, col);
- return TRUE;
- }
- break;
- case GDK_Home:
- case GDK_KP_Home:
- if (selection->cursor_mode == E_CURSOR_LINE) {
- int row = 0;
- int cursor_col = e_selection_model_cursor_col(selection);
-
- row = e_sorter_sorted_to_model(selection->sorter, row);
- e_selection_model_select_as_key_press (selection, row, cursor_col, key->state);
- return TRUE;
- }
- break;
- case GDK_End:
- case GDK_KP_End:
- if (selection->cursor_mode == E_CURSOR_LINE) {
- int row = e_selection_model_row_count(selection) - 1;
- int cursor_col = e_selection_model_cursor_col(selection);
-
- row = e_sorter_sorted_to_model(selection->sorter, row);
- e_selection_model_select_as_key_press (selection, row, cursor_col, key->state);
- return TRUE;
- }
- break;
- }
- return FALSE;
-}
-
-void
-e_selection_model_cursor_changed (ESelectionModel *selection,
- int row,
- int col)
-{
- g_signal_emit(selection,
- e_selection_model_signals[CURSOR_CHANGED], 0,
- row, col);
-}
-
-void
-e_selection_model_cursor_activated (ESelectionModel *selection,
- int row,
- int col)
-{
- g_signal_emit(selection,
- e_selection_model_signals[CURSOR_ACTIVATED], 0,
- row, col);
-}
-
-void
-e_selection_model_selection_changed (ESelectionModel *selection)
-{
- g_signal_emit(selection,
- e_selection_model_signals[SELECTION_CHANGED], 0);
-}
-
-void
-e_selection_model_selection_row_changed (ESelectionModel *selection,
- int row)
-{
- g_signal_emit(selection,
- e_selection_model_signals[SELECTION_ROW_CHANGED], 0,
- row);
-}
diff --git a/widgets/misc/e-selection-model.h b/widgets/misc/e-selection-model.h
deleted file mode 100644
index a78bdfd9c3..0000000000
--- a/widgets/misc/e-selection-model.h
+++ /dev/null
@@ -1,170 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-selection-model.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_SELECTION_MODEL_H_
-#define _E_SELECTION_MODEL_H_
-
-#include <gtk/gtkobject.h>
-#include <gal/util/e-sorter.h>
-#include <gdk/gdkevents.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-#define E_SELECTION_MODEL_TYPE (e_selection_model_get_type ())
-#define E_SELECTION_MODEL(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_SELECTION_MODEL_TYPE, ESelectionModel))
-#define E_SELECTION_MODEL_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_SELECTION_MODEL_TYPE, ESelectionModelClass))
-#define E_IS_SELECTION_MODEL(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_SELECTION_MODEL_TYPE))
-#define E_IS_SELECTION_MODEL_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_SELECTION_MODEL_TYPE))
-#define E_SELECTION_MODEL_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), E_SELECTION_MODEL_TYPE, ESelectionModelClass))
-
-#ifndef _E_FOREACH_FUNC_H_
-#define _E_FOREACH_FUNC_H_
-typedef void (*EForeachFunc) (int model_row,
- gpointer closure);
-#endif
-
-/* list selection modes */
-typedef enum {
- E_CURSOR_LINE,
- E_CURSOR_SIMPLE,
- E_CURSOR_SPREADSHEET
-} ECursorMode;
-
-typedef struct {
- GObject base;
-
- ESorter *sorter;
-
- GtkSelectionMode mode;
- ECursorMode cursor_mode;
-
- int old_selection;
-} ESelectionModel;
-
-typedef struct {
- GObjectClass parent_class;
-
- /* Virtual methods */
- gboolean (*is_row_selected) (ESelectionModel *esm, int row);
- void (*foreach) (ESelectionModel *esm, EForeachFunc callback, gpointer closure);
- void (*clear) (ESelectionModel *esm);
- gint (*selected_count) (ESelectionModel *esm);
- void (*select_all) (ESelectionModel *esm);
- void (*invert_selection) (ESelectionModel *esm);
- int (*row_count) (ESelectionModel *esm);
-
- /* Protected virtual methods. */
- void (*change_one_row) (ESelectionModel *esm, int row, gboolean on);
- void (*change_cursor) (ESelectionModel *esm, int row, int col);
- int (*cursor_row) (ESelectionModel *esm);
- int (*cursor_col) (ESelectionModel *esm);
-
- void (*select_single_row) (ESelectionModel *selection, int row);
- void (*toggle_single_row) (ESelectionModel *selection, int row);
- void (*move_selection_end) (ESelectionModel *selection, int row);
- void (*set_selection_end) (ESelectionModel *selection, int row);
-
- /*
- * Signals
- */
-
- void (*cursor_changed) (ESelectionModel *esm, int row, int col);
- void (*cursor_activated) (ESelectionModel *esm, int row, int col);
- void (*selection_row_changed) (ESelectionModel *esm, int row);
- void (*selection_changed) (ESelectionModel *esm);
-
-} ESelectionModelClass;
-
-
-GType e_selection_model_get_type (void);
-void e_selection_model_do_something (ESelectionModel *esm,
- guint row,
- guint col,
- GdkModifierType state);
-gboolean e_selection_model_maybe_do_something (ESelectionModel *esm,
- guint row,
- guint col,
- GdkModifierType state);
-void e_selection_model_right_click_down (ESelectionModel *selection,
- guint row,
- guint col,
- GdkModifierType state);
-void e_selection_model_right_click_up (ESelectionModel *selection);
-gint e_selection_model_key_press (ESelectionModel *esm,
- GdkEventKey *key);
-void e_selection_model_select_as_key_press (ESelectionModel *esm,
- guint row,
- guint col,
- GdkModifierType state);
-
-/* Virtual functions */
-gboolean e_selection_model_is_row_selected (ESelectionModel *esm,
- gint n);
-void e_selection_model_foreach (ESelectionModel *esm,
- EForeachFunc callback,
- gpointer closure);
-void e_selection_model_clear (ESelectionModel *esm);
-gint e_selection_model_selected_count (ESelectionModel *esm);
-void e_selection_model_select_all (ESelectionModel *esm);
-void e_selection_model_invert_selection (ESelectionModel *esm);
-int e_selection_model_row_count (ESelectionModel *esm);
-
-
-/* Private virtual Functions */
-void e_selection_model_change_one_row (ESelectionModel *esm,
- int row,
- gboolean on);
-void e_selection_model_change_cursor (ESelectionModel *esm,
- int row,
- int col);
-int e_selection_model_cursor_row (ESelectionModel *esm);
-int e_selection_model_cursor_col (ESelectionModel *esm);
-void e_selection_model_select_single_row (ESelectionModel *selection,
- int row);
-void e_selection_model_toggle_single_row (ESelectionModel *selection,
- int row);
-void e_selection_model_move_selection_end (ESelectionModel *selection,
- int row);
-void e_selection_model_set_selection_end (ESelectionModel *selection,
- int row);
-
-/* Signals */
-void e_selection_model_cursor_changed (ESelectionModel *selection,
- int row,
- int col);
-void e_selection_model_cursor_activated (ESelectionModel *selection,
- int row,
- int col);
-void e_selection_model_selection_row_changed (ESelectionModel *selection,
- int row);
-void e_selection_model_selection_changed (ESelectionModel *selection);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-
-#endif /* _E_SELECTION_MODEL_H_ */
-
diff --git a/widgets/misc/e-unicode.c b/widgets/misc/e-unicode.c
deleted file mode 100644
index d7bd33caa7..0000000000
--- a/widgets/misc/e-unicode.c
+++ /dev/null
@@ -1,2055 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-unicode.c - utf-8 support functions for gal
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Lauris Kaplinski <lauris@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-/*
- * TODO: Break simple ligatures in e_utf8_strstrcasedecomp
- */
-
-#include <config.h>
-
-#include "e-unicode.h"
-
-#include "gal/util/e-i18n.h"
-#include <ctype.h>
-#include <string.h>
-#include <stdio.h>
-#include <iconv.h>
-#include <gdk/gdk.h>
-#include <gdk/gdkx.h>
-#include <gdk/gdkkeysyms.h>
-#include <gtk/gtkmenuitem.h>
-#include <libxml/xmlmemory.h>
-#include <stdlib.h>
-#include "gal/util/e-iconv.h"
-
-#ifdef HAVE_ALLOCA_H
-#include <alloca.h>
-#endif
-
-#define d(x) x
-
-#define FONT_TESTING
-#define MAX_DECOMP 8
-
-static gint e_canonical_decomposition (gunichar ch, gunichar * buf);
-static gunichar e_stripped_char (gunichar ch);
-
-#ifndef NO_WARNINGS
-#warning FIXME: this has not been ported fully yet - non ASCII people beware.
-#endif
-
-/*
- * This my favourite
- *
- * strstr doing case insensitive, decomposing search
- *
- * Lauris
- */
-
-const gchar *
-e_utf8_strstrcasedecomp (const gchar *haystack, const gchar *needle)
-{
- gunichar *nuni;
- gunichar unival;
- gint nlen;
- const guchar *o, *p;
-
- if (haystack == NULL) return NULL;
- if (needle == NULL) return NULL;
- if (strlen (needle) == 0) return haystack;
- if (strlen (haystack) == 0) return NULL;
-
- nuni = alloca (sizeof (gunichar) * strlen (needle));
-
- nlen = 0;
- for (p = e_unicode_get_utf8 (needle, &unival); p && unival; p = e_unicode_get_utf8 (p, &unival)) {
- gint sc;
- sc = e_stripped_char (unival);
- if (sc) {
- nuni[nlen++] = sc;
- }
- }
- /* NULL means there was illegal utf-8 sequence */
- if (!p) return NULL;
- /* If everything is correct, we have decomposed, lowercase, stripped needle */
- if (nlen < 1) return haystack;
-
- o = haystack;
- for (p = e_unicode_get_utf8 (o, &unival); p && unival; p = e_unicode_get_utf8 (p, &unival)) {
- gint sc;
- sc = e_stripped_char (unival);
- if (sc) {
- /* We have valid stripped char */
- if (sc == nuni[0]) {
- const gchar *q = p;
- gint npos = 1;
- while (npos < nlen) {
- q = e_unicode_get_utf8 (q, &unival);
- if (!q || !unival) return NULL;
- sc = e_stripped_char (unival);
- if ((!sc) || (sc != nuni[npos])) break;
- npos++;
- }
- if (npos == nlen) {
- return o;
- }
- }
- }
- o = p;
- }
-
- return NULL;
-}
-
-const gchar *
-e_utf8_strstrcase (const gchar *haystack, const gchar *needle)
-{
- gunichar *nuni;
- gunichar unival;
- gint nlen;
- const guchar *o, *p;
-
- if (haystack == NULL) return NULL;
- if (needle == NULL) return NULL;
- if (strlen (needle) == 0) return haystack;
- if (strlen (haystack) == 0) return NULL;
-
- nuni = alloca (sizeof (gunichar) * strlen (needle));
-
- nlen = 0;
- for (p = e_unicode_get_utf8 (needle, &unival); p && unival; p = e_unicode_get_utf8 (p, &unival)) {
- nuni[nlen++] = g_unichar_tolower (unival);
- }
- /* NULL means there was illegal utf-8 sequence */
- if (!p) return NULL;
-
- o = haystack;
- for (p = e_unicode_get_utf8 (o, &unival); p && unival; p = e_unicode_get_utf8 (p, &unival)) {
- gint sc;
- sc = g_unichar_tolower (unival);
- /* We have valid stripped char */
- if (sc == nuni[0]) {
- const gchar *q = p;
- gint npos = 1;
- while (npos < nlen) {
- q = e_unicode_get_utf8 (q, &unival);
- if (!q || !unival) return NULL;
- sc = g_unichar_tolower (unival);
- if (sc != nuni[npos]) break;
- npos++;
- }
- if (npos == nlen) {
- return o;
- }
- }
- o = p;
- }
-
- return NULL;
-}
-
-#if 0
-const gchar *
-e_utf8_strstrcase (const gchar *haystack, const gchar *needle)
-{
- gchar *p;
- gunichar *huni, *nuni;
- gunichar unival;
- gint hlen, nlen, hp, np;
-
- if (haystack == NULL) return NULL;
- if (needle == NULL) return NULL;
- if (strlen (needle) == 0) return haystack;
-
- huni = alloca (sizeof (gunichar) * strlen (haystack));
-
- for (hlen = 0, p = e_unicode_get_utf8 (haystack, &unival); p && unival; hlen++, p = e_unicode_get_utf8 (p, &unival)) {
- huni[hlen] = g_unichar_tolower (unival);
- }
-
- if (!p) return NULL;
- if (hlen == 0) return NULL;
-
- nuni = alloca (sizeof (gunichar) * strlen (needle));
-
- for (nlen = 0, p = e_unicode_get_utf8 (needle, &unival); p && unival; nlen++, p = e_unicode_get_utf8 (p, &unival)) {
- nuni[nlen] = g_unichar_tolower (unival);
- }
-
- if (!p) return NULL;
- if (nlen == 0) return NULL;
-
- if (hlen < nlen) return NULL;
-
- for (hp = 0; hp <= hlen - nlen; hp++) {
- for (np = 0; np < nlen; np++) {
- if (huni[hp + np] != nuni[np]) break;
- }
- if (np == nlen) return haystack + unicode_offset_to_index (haystack, hp);
- }
-
- return NULL;
-}
-#endif
-
-gchar *
-e_utf8_from_gtk_event_key (GtkWidget *widget, guint keyval, const gchar *string)
-{
- gint unival;
- gchar *utf;
- gint unilen;
-
- if (keyval == GDK_VoidSymbol) {
- utf = e_utf8_from_locale_string (string);
- } else {
- unival = gdk_keyval_to_unicode (keyval);
-
- if (unival < ' ') return NULL;
-
- utf = g_new (gchar, 7);
-
- unilen = e_unichar_to_utf8 (unival, utf);
-
- utf[unilen] = '\0';
- }
-
- return utf;
-}
-
-gchar *
-e_utf8_from_iconv_string_sized (iconv_t ic, const gchar *string, gint bytes)
-{
- char *new, *ob;
- const char *ib;
- size_t ibl, obl;
-
- if (!string) return NULL;
-
- if (ic == (iconv_t) -1) {
- gint i;
- /* iso-8859-1 */
- ib = (char *) string;
- new = ob = g_new (unsigned char, bytes * 2 + 1);
- for (i = 0; i < (bytes); i ++) {
- ob += e_unichar_to_utf8 (ib[i], ob);
- }
- *ob = '\0';
- return new;
- }
-
- ib = string;
- ibl = bytes;
- new = ob = g_new (gchar, ibl * 6 + 1);
- obl = ibl * 6;
-
- while (ibl > 0) {
- e_iconv (ic, &ib, &ibl, &ob, &obl);
- if (ibl > 0) {
- gint len;
- if ((*ib & 0x80) == 0x00) len = 1;
- else if ((*ib &0xe0) == 0xc0) len = 2;
- else if ((*ib &0xf0) == 0xe0) len = 3;
- else if ((*ib &0xf8) == 0xf0) len = 4;
- else {
- g_warning ("Invalid UTF-8 sequence");
- break;
- }
- ib += len;
- ibl = bytes - (ib - string);
- if (ibl > bytes) ibl = 0;
- *ob++ = '_';
- obl--;
- }
- }
-
- *ob = '\0';
-
- return new;
-}
-
-gchar *
-e_utf8_from_iconv_string (iconv_t ic, const gchar *string)
-{
- if (!string) return NULL;
- return e_utf8_from_iconv_string_sized (ic, string, strlen (string));
-}
-
-gchar *
-e_utf8_to_iconv_string_sized (iconv_t ic, const gchar *string, gint bytes)
-{
- char *new, *ob;
- const char *ib;
- size_t ibl, obl;
-
- if (!string) return NULL;
-
- if (ic == (iconv_t) -1) {
- gint len;
- const gchar *u;
- gunichar uc;
-
- new = g_new (unsigned char, bytes * 4 + 1);
- u = string;
- len = 0;
-
- while ((u) && (u - string < bytes)) {
- u = e_unicode_get_utf8 (u, &uc);
- new[len++] = uc & 0xff;
- }
- new[len] = '\0';
- return new;
- }
-
- ib = string;
- ibl = bytes;
- new = ob = g_new (char, ibl * 4 + 4);
- obl = ibl * 4;
-
- while (ibl > 0) {
- e_iconv (ic, &ib, &ibl, &ob, &obl);
- if (ibl > 0) {
- gint len;
- if ((*ib & 0x80) == 0x00) len = 1;
- else if ((*ib &0xe0) == 0xc0) len = 2;
- else if ((*ib &0xf0) == 0xe0) len = 3;
- else if ((*ib &0xf8) == 0xf0) len = 4;
- else {
- g_warning ("Invalid UTF-8 sequence");
- break;
- }
- ib += len;
- ibl = bytes - (ib - string);
- if (ibl > bytes) ibl = 0;
-
- /* FIXME: this is wrong... what if the destination charset is 16 or 32 bit? */
- *ob++ = '_';
- obl--;
- }
- }
-
- /* Make sure to terminate with plenty of padding */
- memset (ob, 0, 4);
-
- return new;
-}
-
-gchar *
-e_utf8_to_iconv_string (iconv_t ic, const gchar *string)
-{
- if (!string) return NULL;
- return e_utf8_to_iconv_string_sized (ic, string, strlen (string));
-}
-
-gchar *
-e_utf8_from_charset_string_sized (const gchar *charset, const gchar *string, gint bytes)
-{
- iconv_t ic;
- char *ret;
-
- if (!string) return NULL;
-
- ic = e_iconv_open("utf-8", charset);
- ret = e_utf8_from_iconv_string_sized (ic, string, bytes);
- e_iconv_close(ic);
-
- return ret;
-}
-
-gchar *
-e_utf8_from_charset_string (const gchar *charset, const gchar *string)
-{
- if (!string) return NULL;
- return e_utf8_from_charset_string_sized (charset, string, strlen (string));
-}
-
-gchar *
-e_utf8_to_charset_string_sized (const gchar *charset, const gchar *string, gint bytes)
-{
- iconv_t ic;
- char *ret;
-
- if (!string) return NULL;
-
- ic = e_iconv_open(charset, "utf-8");
- ret = e_utf8_to_iconv_string_sized (ic, string, bytes);
- e_iconv_close(ic);
-
- return ret;
-}
-
-gchar *
-e_utf8_to_charset_string (const gchar *charset, const gchar *string)
-{
- if (!string) return NULL;
- return e_utf8_to_charset_string_sized (charset, string, strlen (string));
-}
-
-gchar *
-e_utf8_from_locale_string_sized (const gchar *string, gint bytes)
-{
- iconv_t ic;
- char *ret;
-
- if (!string) return NULL;
-
- ic = e_iconv_open("utf-8", e_iconv_locale_charset());
- ret = e_utf8_from_iconv_string_sized (ic, string, bytes);
- e_iconv_close(ic);
-
- return ret;
-}
-
-gchar *
-e_utf8_from_locale_string (const gchar *string)
-{
- if (!string) return NULL;
- return e_utf8_from_locale_string_sized (string, strlen (string));
-}
-
-gchar *
-e_utf8_to_locale_string_sized (const gchar *string, gint bytes)
-{
- iconv_t ic;
- char *ret;
-
- if (!string) return NULL;
-
- ic = e_iconv_open(e_iconv_locale_charset(), "utf-8");
- ret = e_utf8_to_iconv_string_sized (ic, string, bytes);
- e_iconv_close(ic);
-
- return ret;
-}
-
-gchar *
-e_utf8_to_locale_string (const gchar *string)
-{
- if (!string) return NULL;
- return e_utf8_to_locale_string_sized (string, strlen (string));
-}
-
-gboolean
-e_utf8_is_ascii (const gchar *string)
-{
- char c;
-
- g_return_val_if_fail (string != NULL, FALSE);
-
- for (; (c = *string); string++) {
- if (c & 0x80)
- return FALSE;
- }
-
- return TRUE;
-}
-
-gchar *
-e_utf8_gtk_entry_get_text (GtkEntry *entry)
-{
- return g_strdup (gtk_entry_get_text (entry));
-}
-
-gchar *
-e_utf8_gtk_editable_get_text (GtkEditable *editable)
-{
- return gtk_editable_get_chars (editable, 0, -1);
-}
-
-gchar *
-e_utf8_gtk_editable_get_chars (GtkEditable *editable, gint start, gint end)
-{
- return gtk_editable_get_chars (editable, start, end);
-}
-
-void
-e_utf8_gtk_editable_insert_text (GtkEditable *editable, const gchar *text, gint length, gint *position)
-{
- gtk_editable_insert_text (editable, text, length, position);
-}
-
-void
-e_utf8_gtk_editable_set_text (GtkEditable *editable, const gchar *text)
-{
- int position;
-
- gtk_editable_delete_text(editable, 0, -1);
- gtk_editable_insert_text (editable, text, strlen (text), &position);
-}
-
-void
-e_utf8_gtk_entry_set_text (GtkEntry *entry, const gchar *text)
-{
- if (!text)
- gtk_entry_set_text(entry, "");
- else
- gtk_entry_set_text (entry, text);
-}
-
-/*
- * Translate \U+XXXX\ sequences to utf8 chars
- */
-
-gchar *
-e_utf8_xml1_decode (const gchar *text)
-{
- const guchar *c;
- guchar *u, *d;
- int len, s;
-
- g_return_val_if_fail (text != NULL, NULL);
-
- len = strlen (text)+1;
- /* len * 2 is absolute maximum */
- u = d = g_malloc (len * 2);
-
- c = text;
- s = 0;
- while (s < len) {
- if ((s <= (len - 8)) &&
- (c[s ] == '\\') &&
- (c[s + 1] == 'U' ) &&
- (c[s + 2] == '+' ) &&
- isxdigit (c[s + 3]) &&
- isxdigit (c[s + 4]) &&
- isxdigit (c[s + 5]) &&
- isxdigit (c[s + 6]) &&
- (c[s + 7] == '\\')) {
- /* Valid \U+XXXX\ sequence */
- unsigned int unival;
- unival = strtol (c + s + 3, NULL, 16);
- d += e_unichar_to_utf8 (unival, d);
- s += 8;
- } else if (c[s] > 127) {
- /* fixme: We assume iso-8859-1 currently */
- d += e_unichar_to_utf8 (c[s], d);
- s += 1;
- } else {
- *d++ = c[s++];
- }
- }
- *d++ = '\0';
- u = g_realloc (u, (d - u));
-
- return u;
-}
-
-gchar *
-e_utf8_xml1_encode (const gchar *text)
-{
- guchar *u, *d, *c;
- int unival;
- int len;
-
- g_return_val_if_fail (text != NULL, NULL);
-
- len = 0;
- for (u = e_unicode_get_utf8 (text, &unival); u && unival; u = e_unicode_get_utf8 (u, &unival)) {
- if ((unival >= 0x80) || (unival == '\\')) {
- len += 8;
- } else {
- len += 1;
- }
- }
- d = c = g_new (guchar, len + 1);
-
- for (u = e_unicode_get_utf8 (text, &unival); u && unival; u = e_unicode_get_utf8 (u, &unival)) {
- if ((unival >= 0x80) || (unival == '\\')) {
- *c++ = '\\';
- *c++ = 'U';
- *c++ = '+';
- c += sprintf (c, "%04x", unival);
- *c++ = '\\';
- } else {
- *c++ = unival;
- }
- }
- *c = '\0';
-
- return d;
-}
-
-/**
- * e_unichar_to_utf8:
- * @c: a ISO10646 character code
- * @outbuf: output buffer, must have at least 6 bytes of space.
- * If %NULL, the length will be computed and returned
- * and nothing will be written to @out.
- *
- * Convert a single character to utf8
- *
- * Return value: number of bytes written
- **/
-
-gint
-e_unichar_to_utf8 (gint c, gchar *outbuf)
-{
- size_t len = 0;
- int first;
- int i;
-
- if (c < 0x80)
- {
- first = 0;
- len = 1;
- }
- else if (c < 0x800)
- {
- first = 0xc0;
- len = 2;
- }
- else if (c < 0x10000)
- {
- first = 0xe0;
- len = 3;
- }
- else if (c < 0x200000)
- {
- first = 0xf0;
- len = 4;
- }
- else if (c < 0x4000000)
- {
- first = 0xf8;
- len = 5;
- }
- else
- {
- first = 0xfc;
- len = 6;
- }
-
- if (outbuf)
- {
- for (i = len - 1; i > 0; --i)
- {
- outbuf[i] = (c & 0x3f) | 0x80;
- c >>= 6;
- }
- outbuf[0] = c | first;
- }
-
- return len;
-}
-
-gchar *
-e_unicode_get_utf8 (const gchar *text, gunichar *out)
-{
- *out = g_utf8_get_char (text);
- return (*out == (gunichar)-1) ? NULL : g_utf8_next_char (text);
-}
-
-/*
- * Canonical decomposition
- *
- * It is copied here from libunicode, because we do not want malloc
- *
- */
-
-typedef struct
-{
- unsigned short ch;
- unsigned char *expansion;
-} e_decomposition;
-
-static e_decomposition e_decomp_table[] =
-{
- { 0x00c0, "\x00\x41\x03\x00\0" },
- { 0x00c1, "\x00\x41\x03\x01\0" },
- { 0x00c2, "\x00\x41\x03\x02\0" },
- { 0x00c3, "\x00\x41\x03\x03\0" },
- { 0x00c4, "\x00\x41\x03\x08\0" },
- { 0x00c5, "\x00\x41\x03\x0a\0" },
- { 0x00c7, "\x00\x43\x03\x27\0" },
- { 0x00c8, "\x00\x45\x03\x00\0" },
- { 0x00c9, "\x00\x45\x03\x01\0" },
- { 0x00ca, "\x00\x45\x03\x02\0" },
- { 0x00cb, "\x00\x45\x03\x08\0" },
- { 0x00cc, "\x00\x49\x03\x00\0" },
- { 0x00cd, "\x00\x49\x03\x01\0" },
- { 0x00ce, "\x00\x49\x03\x02\0" },
- { 0x00cf, "\x00\x49\x03\x08\0" },
- { 0x00d1, "\x00\x4e\x03\x03\0" },
- { 0x00d2, "\x00\x4f\x03\x00\0" },
- { 0x00d3, "\x00\x4f\x03\x01\0" },
- { 0x00d4, "\x00\x4f\x03\x02\0" },
- { 0x00d5, "\x00\x4f\x03\x03\0" },
- { 0x00d6, "\x00\x4f\x03\x08\0" },
- { 0x00d9, "\x00\x55\x03\x00\0" },
- { 0x00da, "\x00\x55\x03\x01\0" },
- { 0x00db, "\x00\x55\x03\x02\0" },
- { 0x00dc, "\x00\x55\x03\x08\0" },
- { 0x00dd, "\x00\x59\x03\x01\0" },
- { 0x00e0, "\x00\x61\x03\x00\0" },
- { 0x00e1, "\x00\x61\x03\x01\0" },
- { 0x00e2, "\x00\x61\x03\x02\0" },
- { 0x00e3, "\x00\x61\x03\x03\0" },
- { 0x00e4, "\x00\x61\x03\x08\0" },
- { 0x00e5, "\x00\x61\x03\x0a\0" },
- { 0x00e7, "\x00\x63\x03\x27\0" },
- { 0x00e8, "\x00\x65\x03\x00\0" },
- { 0x00e9, "\x00\x65\x03\x01\0" },
- { 0x00ea, "\x00\x65\x03\x02\0" },
- { 0x00eb, "\x00\x65\x03\x08\0" },
- { 0x00ec, "\x00\x69\x03\x00\0" },
- { 0x00ed, "\x00\x69\x03\x01\0" },
- { 0x00ee, "\x00\x69\x03\x02\0" },
- { 0x00ef, "\x00\x69\x03\x08\0" },
- { 0x00f1, "\x00\x6e\x03\x03\0" },
- { 0x00f2, "\x00\x6f\x03\x00\0" },
- { 0x00f3, "\x00\x6f\x03\x01\0" },
- { 0x00f4, "\x00\x6f\x03\x02\0" },
- { 0x00f5, "\x00\x6f\x03\x03\0" },
- { 0x00f6, "\x00\x6f\x03\x08\0" },
- { 0x00f9, "\x00\x75\x03\x00\0" },
- { 0x00fa, "\x00\x75\x03\x01\0" },
- { 0x00fb, "\x00\x75\x03\x02\0" },
- { 0x00fc, "\x00\x75\x03\x08\0" },
- { 0x00fd, "\x00\x79\x03\x01\0" },
- { 0x00ff, "\x00\x79\x03\x08\0" },
- { 0x0100, "\x00\x41\x03\x04\0" },
- { 0x0101, "\x00\x61\x03\x04\0" },
- { 0x0102, "\x00\x41\x03\x06\0" },
- { 0x0103, "\x00\x61\x03\x06\0" },
- { 0x0104, "\x00\x41\x03\x28\0" },
- { 0x0105, "\x00\x61\x03\x28\0" },
- { 0x0106, "\x00\x43\x03\x01\0" },
- { 0x0107, "\x00\x63\x03\x01\0" },
- { 0x0108, "\x00\x43\x03\x02\0" },
- { 0x0109, "\x00\x63\x03\x02\0" },
- { 0x010a, "\x00\x43\x03\x07\0" },
- { 0x010b, "\x00\x63\x03\x07\0" },
- { 0x010c, "\x00\x43\x03\x0c\0" },
- { 0x010d, "\x00\x63\x03\x0c\0" },
- { 0x010e, "\x00\x44\x03\x0c\0" },
- { 0x010f, "\x00\x64\x03\x0c\0" },
- { 0x0112, "\x00\x45\x03\x04\0" },
- { 0x0113, "\x00\x65\x03\x04\0" },
- { 0x0114, "\x00\x45\x03\x06\0" },
- { 0x0115, "\x00\x65\x03\x06\0" },
- { 0x0116, "\x00\x45\x03\x07\0" },
- { 0x0117, "\x00\x65\x03\x07\0" },
- { 0x0118, "\x00\x45\x03\x28\0" },
- { 0x0119, "\x00\x65\x03\x28\0" },
- { 0x011a, "\x00\x45\x03\x0c\0" },
- { 0x011b, "\x00\x65\x03\x0c\0" },
- { 0x011c, "\x00\x47\x03\x02\0" },
- { 0x011d, "\x00\x67\x03\x02\0" },
- { 0x011e, "\x00\x47\x03\x06\0" },
- { 0x011f, "\x00\x67\x03\x06\0" },
- { 0x0120, "\x00\x47\x03\x07\0" },
- { 0x0121, "\x00\x67\x03\x07\0" },
- { 0x0122, "\x00\x47\x03\x27\0" },
- { 0x0123, "\x00\x67\x03\x27\0" },
- { 0x0124, "\x00\x48\x03\x02\0" },
- { 0x0125, "\x00\x68\x03\x02\0" },
- { 0x0128, "\x00\x49\x03\x03\0" },
- { 0x0129, "\x00\x69\x03\x03\0" },
- { 0x012a, "\x00\x49\x03\x04\0" },
- { 0x012b, "\x00\x69\x03\x04\0" },
- { 0x012c, "\x00\x49\x03\x06\0" },
- { 0x012d, "\x00\x69\x03\x06\0" },
- { 0x012e, "\x00\x49\x03\x28\0" },
- { 0x012f, "\x00\x69\x03\x28\0" },
- { 0x0130, "\x00\x49\x03\x07\0" },
- { 0x0134, "\x00\x4a\x03\x02\0" },
- { 0x0135, "\x00\x6a\x03\x02\0" },
- { 0x0136, "\x00\x4b\x03\x27\0" },
- { 0x0137, "\x00\x6b\x03\x27\0" },
- { 0x0139, "\x00\x4c\x03\x01\0" },
- { 0x013a, "\x00\x6c\x03\x01\0" },
- { 0x013b, "\x00\x4c\x03\x27\0" },
- { 0x013c, "\x00\x6c\x03\x27\0" },
- { 0x013d, "\x00\x4c\x03\x0c\0" },
- { 0x013e, "\x00\x6c\x03\x0c\0" },
- { 0x0143, "\x00\x4e\x03\x01\0" },
- { 0x0144, "\x00\x6e\x03\x01\0" },
- { 0x0145, "\x00\x4e\x03\x27\0" },
- { 0x0146, "\x00\x6e\x03\x27\0" },
- { 0x0147, "\x00\x4e\x03\x0c\0" },
- { 0x0148, "\x00\x6e\x03\x0c\0" },
- { 0x014c, "\x00\x4f\x03\x04\0" },
- { 0x014d, "\x00\x6f\x03\x04\0" },
- { 0x014e, "\x00\x4f\x03\x06\0" },
- { 0x014f, "\x00\x6f\x03\x06\0" },
- { 0x0150, "\x00\x4f\x03\x0b\0" },
- { 0x0151, "\x00\x6f\x03\x0b\0" },
- { 0x0154, "\x00\x52\x03\x01\0" },
- { 0x0155, "\x00\x72\x03\x01\0" },
- { 0x0156, "\x00\x52\x03\x27\0" },
- { 0x0157, "\x00\x72\x03\x27\0" },
- { 0x0158, "\x00\x52\x03\x0c\0" },
- { 0x0159, "\x00\x72\x03\x0c\0" },
- { 0x015a, "\x00\x53\x03\x01\0" },
- { 0x015b, "\x00\x73\x03\x01\0" },
- { 0x015c, "\x00\x53\x03\x02\0" },
- { 0x015d, "\x00\x73\x03\x02\0" },
- { 0x015e, "\x00\x53\x03\x27\0" },
- { 0x015f, "\x00\x73\x03\x27\0" },
- { 0x0160, "\x00\x53\x03\x0c\0" },
- { 0x0161, "\x00\x73\x03\x0c\0" },
- { 0x0162, "\x00\x54\x03\x27\0" },
- { 0x0163, "\x00\x74\x03\x27\0" },
- { 0x0164, "\x00\x54\x03\x0c\0" },
- { 0x0165, "\x00\x74\x03\x0c\0" },
- { 0x0168, "\x00\x55\x03\x03\0" },
- { 0x0169, "\x00\x75\x03\x03\0" },
- { 0x016a, "\x00\x55\x03\x04\0" },
- { 0x016b, "\x00\x75\x03\x04\0" },
- { 0x016c, "\x00\x55\x03\x06\0" },
- { 0x016d, "\x00\x75\x03\x06\0" },
- { 0x016e, "\x00\x55\x03\x0a\0" },
- { 0x016f, "\x00\x75\x03\x0a\0" },
- { 0x0170, "\x00\x55\x03\x0b\0" },
- { 0x0171, "\x00\x75\x03\x0b\0" },
- { 0x0172, "\x00\x55\x03\x28\0" },
- { 0x0173, "\x00\x75\x03\x28\0" },
- { 0x0174, "\x00\x57\x03\x02\0" },
- { 0x0175, "\x00\x77\x03\x02\0" },
- { 0x0176, "\x00\x59\x03\x02\0" },
- { 0x0177, "\x00\x79\x03\x02\0" },
- { 0x0178, "\x00\x59\x03\x08\0" },
- { 0x0179, "\x00\x5a\x03\x01\0" },
- { 0x017a, "\x00\x7a\x03\x01\0" },
- { 0x017b, "\x00\x5a\x03\x07\0" },
- { 0x017c, "\x00\x7a\x03\x07\0" },
- { 0x017d, "\x00\x5a\x03\x0c\0" },
- { 0x017e, "\x00\x7a\x03\x0c\0" },
- { 0x01a0, "\x00\x4f\x03\x1b\0" },
- { 0x01a1, "\x00\x6f\x03\x1b\0" },
- { 0x01af, "\x00\x55\x03\x1b\0" },
- { 0x01b0, "\x00\x75\x03\x1b\0" },
- { 0x01cd, "\x00\x41\x03\x0c\0" },
- { 0x01ce, "\x00\x61\x03\x0c\0" },
- { 0x01cf, "\x00\x49\x03\x0c\0" },
- { 0x01d0, "\x00\x69\x03\x0c\0" },
- { 0x01d1, "\x00\x4f\x03\x0c\0" },
- { 0x01d2, "\x00\x6f\x03\x0c\0" },
- { 0x01d3, "\x00\x55\x03\x0c\0" },
- { 0x01d4, "\x00\x75\x03\x0c\0" },
- { 0x01d5, "\x00\x55\x03\x08\x03\x04\0" },
- { 0x01d6, "\x00\x75\x03\x08\x03\x04\0" },
- { 0x01d7, "\x00\x55\x03\x08\x03\x01\0" },
- { 0x01d8, "\x00\x75\x03\x08\x03\x01\0" },
- { 0x01d9, "\x00\x55\x03\x08\x03\x0c\0" },
- { 0x01da, "\x00\x75\x03\x08\x03\x0c\0" },
- { 0x01db, "\x00\x55\x03\x08\x03\x00\0" },
- { 0x01dc, "\x00\x75\x03\x08\x03\x00\0" },
- { 0x01de, "\x00\x41\x03\x08\x03\x04\0" },
- { 0x01df, "\x00\x61\x03\x08\x03\x04\0" },
- { 0x01e0, "\x00\x41\x03\x07\x03\x04\0" },
- { 0x01e1, "\x00\x61\x03\x07\x03\x04\0" },
- { 0x01e2, "\x00\xc6\x03\x04\0" },
- { 0x01e3, "\x00\xe6\x03\x04\0" },
- { 0x01e6, "\x00\x47\x03\x0c\0" },
- { 0x01e7, "\x00\x67\x03\x0c\0" },
- { 0x01e8, "\x00\x4b\x03\x0c\0" },
- { 0x01e9, "\x00\x6b\x03\x0c\0" },
- { 0x01ea, "\x00\x4f\x03\x28\0" },
- { 0x01eb, "\x00\x6f\x03\x28\0" },
- { 0x01ec, "\x00\x4f\x03\x28\x03\x04\0" },
- { 0x01ed, "\x00\x6f\x03\x28\x03\x04\0" },
- { 0x01ee, "\x01\xb7\x03\x0c\0" },
- { 0x01ef, "\x02\x92\x03\x0c\0" },
- { 0x01f0, "\x00\x6a\x03\x0c\0" },
- { 0x01f4, "\x00\x47\x03\x01\0" },
- { 0x01f5, "\x00\x67\x03\x01\0" },
- { 0x01fa, "\x00\x41\x03\x0a\x03\x01\0" },
- { 0x01fb, "\x00\x61\x03\x0a\x03\x01\0" },
- { 0x01fc, "\x00\xc6\x03\x01\0" },
- { 0x01fd, "\x00\xe6\x03\x01\0" },
- { 0x01fe, "\x00\xd8\x03\x01\0" },
- { 0x01ff, "\x00\xf8\x03\x01\0" },
- { 0x0200, "\x00\x41\x03\x0f\0" },
- { 0x0201, "\x00\x61\x03\x0f\0" },
- { 0x0202, "\x00\x41\x03\x11\0" },
- { 0x0203, "\x00\x61\x03\x11\0" },
- { 0x0204, "\x00\x45\x03\x0f\0" },
- { 0x0205, "\x00\x65\x03\x0f\0" },
- { 0x0206, "\x00\x45\x03\x11\0" },
- { 0x0207, "\x00\x65\x03\x11\0" },
- { 0x0208, "\x00\x49\x03\x0f\0" },
- { 0x0209, "\x00\x69\x03\x0f\0" },
- { 0x020a, "\x00\x49\x03\x11\0" },
- { 0x020b, "\x00\x69\x03\x11\0" },
- { 0x020c, "\x00\x4f\x03\x0f\0" },
- { 0x020d, "\x00\x6f\x03\x0f\0" },
- { 0x020e, "\x00\x4f\x03\x11\0" },
- { 0x020f, "\x00\x6f\x03\x11\0" },
- { 0x0210, "\x00\x52\x03\x0f\0" },
- { 0x0211, "\x00\x72\x03\x0f\0" },
- { 0x0212, "\x00\x52\x03\x11\0" },
- { 0x0213, "\x00\x72\x03\x11\0" },
- { 0x0214, "\x00\x55\x03\x0f\0" },
- { 0x0215, "\x00\x75\x03\x0f\0" },
- { 0x0216, "\x00\x55\x03\x11\0" },
- { 0x0217, "\x00\x75\x03\x11\0" },
- { 0x0340, "\x03\x00\0" },
- { 0x0341, "\x03\x01\0" },
- { 0x0343, "\x03\x13\0" },
- { 0x0344, "\x03\x08\x03\x01\0" },
- { 0x0374, "\x02\xb9\0" },
- { 0x037e, "\x00\x3b\0" },
- { 0x0385, "\x00\xa8\x03\x01\0" },
- { 0x0386, "\x03\x91\x03\x01\0" },
- { 0x0387, "\x00\xb7\0" },
- { 0x0388, "\x03\x95\x03\x01\0" },
- { 0x0389, "\x03\x97\x03\x01\0" },
- { 0x038a, "\x03\x99\x03\x01\0" },
- { 0x038c, "\x03\x9f\x03\x01\0" },
- { 0x038e, "\x03\xa5\x03\x01\0" },
- { 0x038f, "\x03\xa9\x03\x01\0" },
- { 0x0390, "\x03\xb9\x03\x08\x03\x01\0" },
- { 0x03aa, "\x03\x99\x03\x08\0" },
- { 0x03ab, "\x03\xa5\x03\x08\0" },
- { 0x03ac, "\x03\xb1\x03\x01\0" },
- { 0x03ad, "\x03\xb5\x03\x01\0" },
- { 0x03ae, "\x03\xb7\x03\x01\0" },
- { 0x03af, "\x03\xb9\x03\x01\0" },
- { 0x03b0, "\x03\xc5\x03\x08\x03\x01\0" },
- { 0x03ca, "\x03\xb9\x03\x08\0" },
- { 0x03cb, "\x03\xc5\x03\x08\0" },
- { 0x03cc, "\x03\xbf\x03\x01\0" },
- { 0x03cd, "\x03\xc5\x03\x01\0" },
- { 0x03ce, "\x03\xc9\x03\x01\0" },
- { 0x03d3, "\x03\xd2\x03\x01\0" },
- { 0x03d4, "\x03\xd2\x03\x08\0" },
- { 0x0401, "\x04\x15\x03\x08\0" },
- { 0x0403, "\x04\x13\x03\x01\0" },
- { 0x0407, "\x04\x06\x03\x08\0" },
- { 0x040c, "\x04\x1a\x03\x01\0" },
- { 0x040e, "\x04\x23\x03\x06\0" },
- { 0x0419, "\x04\x18\x03\x06\0" },
- { 0x0439, "\x04\x38\x03\x06\0" },
- { 0x0451, "\x04\x35\x03\x08\0" },
- { 0x0453, "\x04\x33\x03\x01\0" },
- { 0x0457, "\x04\x56\x03\x08\0" },
- { 0x045c, "\x04\x3a\x03\x01\0" },
- { 0x045e, "\x04\x43\x03\x06\0" },
- { 0x0476, "\x04\x74\x03\x0f\0" },
- { 0x0477, "\x04\x75\x03\x0f\0" },
- { 0x04c1, "\x04\x16\x03\x06\0" },
- { 0x04c2, "\x04\x36\x03\x06\0" },
- { 0x04d0, "\x04\x10\x03\x06\0" },
- { 0x04d1, "\x04\x30\x03\x06\0" },
- { 0x04d2, "\x04\x10\x03\x08\0" },
- { 0x04d3, "\x04\x30\x03\x08\0" },
- { 0x04d6, "\x04\x15\x03\x06\0" },
- { 0x04d7, "\x04\x35\x03\x06\0" },
- { 0x04da, "\x04\xd8\x03\x08\0" },
- { 0x04db, "\x04\xd9\x03\x08\0" },
- { 0x04dc, "\x04\x16\x03\x08\0" },
- { 0x04dd, "\x04\x36\x03\x08\0" },
- { 0x04de, "\x04\x17\x03\x08\0" },
- { 0x04df, "\x04\x37\x03\x08\0" },
- { 0x04e2, "\x04\x18\x03\x04\0" },
- { 0x04e3, "\x04\x38\x03\x04\0" },
- { 0x04e4, "\x04\x18\x03\x08\0" },
- { 0x04e5, "\x04\x38\x03\x08\0" },
- { 0x04e6, "\x04\x1e\x03\x08\0" },
- { 0x04e7, "\x04\x3e\x03\x08\0" },
- { 0x04ea, "\x04\xe8\x03\x08\0" },
- { 0x04eb, "\x04\xe9\x03\x08\0" },
- { 0x04ee, "\x04\x23\x03\x04\0" },
- { 0x04ef, "\x04\x43\x03\x04\0" },
- { 0x04f0, "\x04\x23\x03\x08\0" },
- { 0x04f1, "\x04\x43\x03\x08\0" },
- { 0x04f2, "\x04\x23\x03\x0b\0" },
- { 0x04f3, "\x04\x43\x03\x0b\0" },
- { 0x04f4, "\x04\x27\x03\x08\0" },
- { 0x04f5, "\x04\x47\x03\x08\0" },
- { 0x04f8, "\x04\x2b\x03\x08\0" },
- { 0x04f9, "\x04\x4b\x03\x08\0" },
- { 0x0929, "\x09\x28\x09\x3c\0" },
- { 0x0931, "\x09\x30\x09\x3c\0" },
- { 0x0934, "\x09\x33\x09\x3c\0" },
- { 0x0958, "\x09\x15\x09\x3c\0" },
- { 0x0959, "\x09\x16\x09\x3c\0" },
- { 0x095a, "\x09\x17\x09\x3c\0" },
- { 0x095b, "\x09\x1c\x09\x3c\0" },
- { 0x095c, "\x09\x21\x09\x3c\0" },
- { 0x095d, "\x09\x22\x09\x3c\0" },
- { 0x095e, "\x09\x2b\x09\x3c\0" },
- { 0x095f, "\x09\x2f\x09\x3c\0" },
- { 0x09b0, "\x09\xac\x09\xbc\0" },
- { 0x09cb, "\x09\xc7\x09\xbe\0" },
- { 0x09cc, "\x09\xc7\x09\xd7\0" },
- { 0x09dc, "\x09\xa1\x09\xbc\0" },
- { 0x09dd, "\x09\xa2\x09\xbc\0" },
- { 0x09df, "\x09\xaf\x09\xbc\0" },
- { 0x0a59, "\x0a\x16\x0a\x3c\0" },
- { 0x0a5a, "\x0a\x17\x0a\x3c\0" },
- { 0x0a5b, "\x0a\x1c\x0a\x3c\0" },
- { 0x0a5c, "\x0a\x21\x0a\x3c\0" },
- { 0x0a5e, "\x0a\x2b\x0a\x3c\0" },
- { 0x0b48, "\x0b\x47\x0b\x56\0" },
- { 0x0b4b, "\x0b\x47\x0b\x3e\0" },
- { 0x0b4c, "\x0b\x47\x0b\x57\0" },
- { 0x0b5c, "\x0b\x21\x0b\x3c\0" },
- { 0x0b5d, "\x0b\x22\x0b\x3c\0" },
- { 0x0b5f, "\x0b\x2f\x0b\x3c\0" },
- { 0x0b94, "\x0b\x92\x0b\xd7\0" },
- { 0x0bca, "\x0b\xc6\x0b\xbe\0" },
- { 0x0bcb, "\x0b\xc7\x0b\xbe\0" },
- { 0x0bcc, "\x0b\xc6\x0b\xd7\0" },
- { 0x0c48, "\x0c\x46\x0c\x56\0" },
- { 0x0cc0, "\x0c\xbf\x0c\xd5\0" },
- { 0x0cc7, "\x0c\xc6\x0c\xd5\0" },
- { 0x0cc8, "\x0c\xc6\x0c\xd6\0" },
- { 0x0cca, "\x0c\xc6\x0c\xc2\0" },
- { 0x0ccb, "\x0c\xc6\x0c\xc2\x0c\xd5\0" },
- { 0x0d4a, "\x0d\x46\x0d\x3e\0" },
- { 0x0d4b, "\x0d\x47\x0d\x3e\0" },
- { 0x0d4c, "\x0d\x46\x0d\x57\0" },
- { 0x0e33, "\x0e\x4d\x0e\x32\0" },
- { 0x0eb3, "\x0e\xcd\x0e\xb2\0" },
- { 0x0f43, "\x0f\x42\x0f\xb7\0" },
- { 0x0f4d, "\x0f\x4c\x0f\xb7\0" },
- { 0x0f52, "\x0f\x51\x0f\xb7\0" },
- { 0x0f57, "\x0f\x56\x0f\xb7\0" },
- { 0x0f5c, "\x0f\x5b\x0f\xb7\0" },
- { 0x0f69, "\x0f\x40\x0f\xb5\0" },
- { 0x0f73, "\x0f\x71\x0f\x72\0" },
- { 0x0f75, "\x0f\x71\x0f\x74\0" },
- { 0x0f76, "\x0f\xb2\x0f\x80\0" },
- { 0x0f78, "\x0f\xb3\x0f\x80\0" },
- { 0x0f81, "\x0f\x71\x0f\x80\0" },
- { 0x0f93, "\x0f\x92\x0f\xb7\0" },
- { 0x0f9d, "\x0f\x9c\x0f\xb7\0" },
- { 0x0fa2, "\x0f\xa1\x0f\xb7\0" },
- { 0x0fa7, "\x0f\xa6\x0f\xb7\0" },
- { 0x0fac, "\x0f\xab\x0f\xb7\0" },
- { 0x0fb9, "\x0f\x90\x0f\xb5\0" },
- { 0x1e00, "\x00\x41\x03\x25\0" },
- { 0x1e01, "\x00\x61\x03\x25\0" },
- { 0x1e02, "\x00\x42\x03\x07\0" },
- { 0x1e03, "\x00\x62\x03\x07\0" },
- { 0x1e04, "\x00\x42\x03\x23\0" },
- { 0x1e05, "\x00\x62\x03\x23\0" },
- { 0x1e06, "\x00\x42\x03\x31\0" },
- { 0x1e07, "\x00\x62\x03\x31\0" },
- { 0x1e08, "\x00\x43\x03\x27\x03\x01\0" },
- { 0x1e09, "\x00\x63\x03\x27\x03\x01\0" },
- { 0x1e0a, "\x00\x44\x03\x07\0" },
- { 0x1e0b, "\x00\x64\x03\x07\0" },
- { 0x1e0c, "\x00\x44\x03\x23\0" },
- { 0x1e0d, "\x00\x64\x03\x23\0" },
- { 0x1e0e, "\x00\x44\x03\x31\0" },
- { 0x1e0f, "\x00\x64\x03\x31\0" },
- { 0x1e10, "\x00\x44\x03\x27\0" },
- { 0x1e11, "\x00\x64\x03\x27\0" },
- { 0x1e12, "\x00\x44\x03\x2d\0" },
- { 0x1e13, "\x00\x64\x03\x2d\0" },
- { 0x1e14, "\x00\x45\x03\x04\x03\x00\0" },
- { 0x1e15, "\x00\x65\x03\x04\x03\x00\0" },
- { 0x1e16, "\x00\x45\x03\x04\x03\x01\0" },
- { 0x1e17, "\x00\x65\x03\x04\x03\x01\0" },
- { 0x1e18, "\x00\x45\x03\x2d\0" },
- { 0x1e19, "\x00\x65\x03\x2d\0" },
- { 0x1e1a, "\x00\x45\x03\x30\0" },
- { 0x1e1b, "\x00\x65\x03\x30\0" },
- { 0x1e1c, "\x00\x45\x03\x27\x03\x06\0" },
- { 0x1e1d, "\x00\x65\x03\x27\x03\x06\0" },
- { 0x1e1e, "\x00\x46\x03\x07\0" },
- { 0x1e1f, "\x00\x66\x03\x07\0" },
- { 0x1e20, "\x00\x47\x03\x04\0" },
- { 0x1e21, "\x00\x67\x03\x04\0" },
- { 0x1e22, "\x00\x48\x03\x07\0" },
- { 0x1e23, "\x00\x68\x03\x07\0" },
- { 0x1e24, "\x00\x48\x03\x23\0" },
- { 0x1e25, "\x00\x68\x03\x23\0" },
- { 0x1e26, "\x00\x48\x03\x08\0" },
- { 0x1e27, "\x00\x68\x03\x08\0" },
- { 0x1e28, "\x00\x48\x03\x27\0" },
- { 0x1e29, "\x00\x68\x03\x27\0" },
- { 0x1e2a, "\x00\x48\x03\x2e\0" },
- { 0x1e2b, "\x00\x68\x03\x2e\0" },
- { 0x1e2c, "\x00\x49\x03\x30\0" },
- { 0x1e2d, "\x00\x69\x03\x30\0" },
- { 0x1e2e, "\x00\x49\x03\x08\x03\x01\0" },
- { 0x1e2f, "\x00\x69\x03\x08\x03\x01\0" },
- { 0x1e30, "\x00\x4b\x03\x01\0" },
- { 0x1e31, "\x00\x6b\x03\x01\0" },
- { 0x1e32, "\x00\x4b\x03\x23\0" },
- { 0x1e33, "\x00\x6b\x03\x23\0" },
- { 0x1e34, "\x00\x4b\x03\x31\0" },
- { 0x1e35, "\x00\x6b\x03\x31\0" },
- { 0x1e36, "\x00\x4c\x03\x23\0" },
- { 0x1e37, "\x00\x6c\x03\x23\0" },
- { 0x1e38, "\x00\x4c\x03\x23\x03\x04\0" },
- { 0x1e39, "\x00\x6c\x03\x23\x03\x04\0" },
- { 0x1e3a, "\x00\x4c\x03\x31\0" },
- { 0x1e3b, "\x00\x6c\x03\x31\0" },
- { 0x1e3c, "\x00\x4c\x03\x2d\0" },
- { 0x1e3d, "\x00\x6c\x03\x2d\0" },
- { 0x1e3e, "\x00\x4d\x03\x01\0" },
- { 0x1e3f, "\x00\x6d\x03\x01\0" },
- { 0x1e40, "\x00\x4d\x03\x07\0" },
- { 0x1e41, "\x00\x6d\x03\x07\0" },
- { 0x1e42, "\x00\x4d\x03\x23\0" },
- { 0x1e43, "\x00\x6d\x03\x23\0" },
- { 0x1e44, "\x00\x4e\x03\x07\0" },
- { 0x1e45, "\x00\x6e\x03\x07\0" },
- { 0x1e46, "\x00\x4e\x03\x23\0" },
- { 0x1e47, "\x00\x6e\x03\x23\0" },
- { 0x1e48, "\x00\x4e\x03\x31\0" },
- { 0x1e49, "\x00\x6e\x03\x31\0" },
- { 0x1e4a, "\x00\x4e\x03\x2d\0" },
- { 0x1e4b, "\x00\x6e\x03\x2d\0" },
- { 0x1e4c, "\x00\x4f\x03\x03\x03\x01\0" },
- { 0x1e4d, "\x00\x6f\x03\x03\x03\x01\0" },
- { 0x1e4e, "\x00\x4f\x03\x03\x03\x08\0" },
- { 0x1e4f, "\x00\x6f\x03\x03\x03\x08\0" },
- { 0x1e50, "\x00\x4f\x03\x04\x03\x00\0" },
- { 0x1e51, "\x00\x6f\x03\x04\x03\x00\0" },
- { 0x1e52, "\x00\x4f\x03\x04\x03\x01\0" },
- { 0x1e53, "\x00\x6f\x03\x04\x03\x01\0" },
- { 0x1e54, "\x00\x50\x03\x01\0" },
- { 0x1e55, "\x00\x70\x03\x01\0" },
- { 0x1e56, "\x00\x50\x03\x07\0" },
- { 0x1e57, "\x00\x70\x03\x07\0" },
- { 0x1e58, "\x00\x52\x03\x07\0" },
- { 0x1e59, "\x00\x72\x03\x07\0" },
- { 0x1e5a, "\x00\x52\x03\x23\0" },
- { 0x1e5b, "\x00\x72\x03\x23\0" },
- { 0x1e5c, "\x00\x52\x03\x23\x03\x04\0" },
- { 0x1e5d, "\x00\x72\x03\x23\x03\x04\0" },
- { 0x1e5e, "\x00\x52\x03\x31\0" },
- { 0x1e5f, "\x00\x72\x03\x31\0" },
- { 0x1e60, "\x00\x53\x03\x07\0" },
- { 0x1e61, "\x00\x73\x03\x07\0" },
- { 0x1e62, "\x00\x53\x03\x23\0" },
- { 0x1e63, "\x00\x73\x03\x23\0" },
- { 0x1e64, "\x00\x53\x03\x01\x03\x07\0" },
- { 0x1e65, "\x00\x73\x03\x01\x03\x07\0" },
- { 0x1e66, "\x00\x53\x03\x0c\x03\x07\0" },
- { 0x1e67, "\x00\x73\x03\x0c\x03\x07\0" },
- { 0x1e68, "\x00\x53\x03\x23\x03\x07\0" },
- { 0x1e69, "\x00\x73\x03\x23\x03\x07\0" },
- { 0x1e6a, "\x00\x54\x03\x07\0" },
- { 0x1e6b, "\x00\x74\x03\x07\0" },
- { 0x1e6c, "\x00\x54\x03\x23\0" },
- { 0x1e6d, "\x00\x74\x03\x23\0" },
- { 0x1e6e, "\x00\x54\x03\x31\0" },
- { 0x1e6f, "\x00\x74\x03\x31\0" },
- { 0x1e70, "\x00\x54\x03\x2d\0" },
- { 0x1e71, "\x00\x74\x03\x2d\0" },
- { 0x1e72, "\x00\x55\x03\x24\0" },
- { 0x1e73, "\x00\x75\x03\x24\0" },
- { 0x1e74, "\x00\x55\x03\x30\0" },
- { 0x1e75, "\x00\x75\x03\x30\0" },
- { 0x1e76, "\x00\x55\x03\x2d\0" },
- { 0x1e77, "\x00\x75\x03\x2d\0" },
- { 0x1e78, "\x00\x55\x03\x03\x03\x01\0" },
- { 0x1e79, "\x00\x75\x03\x03\x03\x01\0" },
- { 0x1e7a, "\x00\x55\x03\x04\x03\x08\0" },
- { 0x1e7b, "\x00\x75\x03\x04\x03\x08\0" },
- { 0x1e7c, "\x00\x56\x03\x03\0" },
- { 0x1e7d, "\x00\x76\x03\x03\0" },
- { 0x1e7e, "\x00\x56\x03\x23\0" },
- { 0x1e7f, "\x00\x76\x03\x23\0" },
- { 0x1e80, "\x00\x57\x03\x00\0" },
- { 0x1e81, "\x00\x77\x03\x00\0" },
- { 0x1e82, "\x00\x57\x03\x01\0" },
- { 0x1e83, "\x00\x77\x03\x01\0" },
- { 0x1e84, "\x00\x57\x03\x08\0" },
- { 0x1e85, "\x00\x77\x03\x08\0" },
- { 0x1e86, "\x00\x57\x03\x07\0" },
- { 0x1e87, "\x00\x77\x03\x07\0" },
- { 0x1e88, "\x00\x57\x03\x23\0" },
- { 0x1e89, "\x00\x77\x03\x23\0" },
- { 0x1e8a, "\x00\x58\x03\x07\0" },
- { 0x1e8b, "\x00\x78\x03\x07\0" },
- { 0x1e8c, "\x00\x58\x03\x08\0" },
- { 0x1e8d, "\x00\x78\x03\x08\0" },
- { 0x1e8e, "\x00\x59\x03\x07\0" },
- { 0x1e8f, "\x00\x79\x03\x07\0" },
- { 0x1e90, "\x00\x5a\x03\x02\0" },
- { 0x1e91, "\x00\x7a\x03\x02\0" },
- { 0x1e92, "\x00\x5a\x03\x23\0" },
- { 0x1e93, "\x00\x7a\x03\x23\0" },
- { 0x1e94, "\x00\x5a\x03\x31\0" },
- { 0x1e95, "\x00\x7a\x03\x31\0" },
- { 0x1e96, "\x00\x68\x03\x31\0" },
- { 0x1e97, "\x00\x74\x03\x08\0" },
- { 0x1e98, "\x00\x77\x03\x0a\0" },
- { 0x1e99, "\x00\x79\x03\x0a\0" },
- { 0x1e9b, "\x01\x7f\x03\x07\0" },
- { 0x1ea0, "\x00\x41\x03\x23\0" },
- { 0x1ea1, "\x00\x61\x03\x23\0" },
- { 0x1ea2, "\x00\x41\x03\x09\0" },
- { 0x1ea3, "\x00\x61\x03\x09\0" },
- { 0x1ea4, "\x00\x41\x03\x02\x03\x01\0" },
- { 0x1ea5, "\x00\x61\x03\x02\x03\x01\0" },
- { 0x1ea6, "\x00\x41\x03\x02\x03\x00\0" },
- { 0x1ea7, "\x00\x61\x03\x02\x03\x00\0" },
- { 0x1ea8, "\x00\x41\x03\x02\x03\x09\0" },
- { 0x1ea9, "\x00\x61\x03\x02\x03\x09\0" },
- { 0x1eaa, "\x00\x41\x03\x02\x03\x03\0" },
- { 0x1eab, "\x00\x61\x03\x02\x03\x03\0" },
- { 0x1eac, "\x00\x41\x03\x23\x03\x02\0" },
- { 0x1ead, "\x00\x61\x03\x23\x03\x02\0" },
- { 0x1eae, "\x00\x41\x03\x06\x03\x01\0" },
- { 0x1eaf, "\x00\x61\x03\x06\x03\x01\0" },
- { 0x1eb0, "\x00\x41\x03\x06\x03\x00\0" },
- { 0x1eb1, "\x00\x61\x03\x06\x03\x00\0" },
- { 0x1eb2, "\x00\x41\x03\x06\x03\x09\0" },
- { 0x1eb3, "\x00\x61\x03\x06\x03\x09\0" },
- { 0x1eb4, "\x00\x41\x03\x06\x03\x03\0" },
- { 0x1eb5, "\x00\x61\x03\x06\x03\x03\0" },
- { 0x1eb6, "\x00\x41\x03\x23\x03\x06\0" },
- { 0x1eb7, "\x00\x61\x03\x23\x03\x06\0" },
- { 0x1eb8, "\x00\x45\x03\x23\0" },
- { 0x1eb9, "\x00\x65\x03\x23\0" },
- { 0x1eba, "\x00\x45\x03\x09\0" },
- { 0x1ebb, "\x00\x65\x03\x09\0" },
- { 0x1ebc, "\x00\x45\x03\x03\0" },
- { 0x1ebd, "\x00\x65\x03\x03\0" },
- { 0x1ebe, "\x00\x45\x03\x02\x03\x01\0" },
- { 0x1ebf, "\x00\x65\x03\x02\x03\x01\0" },
- { 0x1ec0, "\x00\x45\x03\x02\x03\x00\0" },
- { 0x1ec1, "\x00\x65\x03\x02\x03\x00\0" },
- { 0x1ec2, "\x00\x45\x03\x02\x03\x09\0" },
- { 0x1ec3, "\x00\x65\x03\x02\x03\x09\0" },
- { 0x1ec4, "\x00\x45\x03\x02\x03\x03\0" },
- { 0x1ec5, "\x00\x65\x03\x02\x03\x03\0" },
- { 0x1ec6, "\x00\x45\x03\x23\x03\x02\0" },
- { 0x1ec7, "\x00\x65\x03\x23\x03\x02\0" },
- { 0x1ec8, "\x00\x49\x03\x09\0" },
- { 0x1ec9, "\x00\x69\x03\x09\0" },
- { 0x1eca, "\x00\x49\x03\x23\0" },
- { 0x1ecb, "\x00\x69\x03\x23\0" },
- { 0x1ecc, "\x00\x4f\x03\x23\0" },
- { 0x1ecd, "\x00\x6f\x03\x23\0" },
- { 0x1ece, "\x00\x4f\x03\x09\0" },
- { 0x1ecf, "\x00\x6f\x03\x09\0" },
- { 0x1ed0, "\x00\x4f\x03\x02\x03\x01\0" },
- { 0x1ed1, "\x00\x6f\x03\x02\x03\x01\0" },
- { 0x1ed2, "\x00\x4f\x03\x02\x03\x00\0" },
- { 0x1ed3, "\x00\x6f\x03\x02\x03\x00\0" },
- { 0x1ed4, "\x00\x4f\x03\x02\x03\x09\0" },
- { 0x1ed5, "\x00\x6f\x03\x02\x03\x09\0" },
- { 0x1ed6, "\x00\x4f\x03\x02\x03\x03\0" },
- { 0x1ed7, "\x00\x6f\x03\x02\x03\x03\0" },
- { 0x1ed8, "\x00\x4f\x03\x23\x03\x02\0" },
- { 0x1ed9, "\x00\x6f\x03\x23\x03\x02\0" },
- { 0x1eda, "\x00\x4f\x03\x1b\x03\x01\0" },
- { 0x1edb, "\x00\x6f\x03\x1b\x03\x01\0" },
- { 0x1edc, "\x00\x4f\x03\x1b\x03\x00\0" },
- { 0x1edd, "\x00\x6f\x03\x1b\x03\x00\0" },
- { 0x1ede, "\x00\x4f\x03\x1b\x03\x09\0" },
- { 0x1edf, "\x00\x6f\x03\x1b\x03\x09\0" },
- { 0x1ee0, "\x00\x4f\x03\x1b\x03\x03\0" },
- { 0x1ee1, "\x00\x6f\x03\x1b\x03\x03\0" },
- { 0x1ee2, "\x00\x4f\x03\x1b\x03\x23\0" },
- { 0x1ee3, "\x00\x6f\x03\x1b\x03\x23\0" },
- { 0x1ee4, "\x00\x55\x03\x23\0" },
- { 0x1ee5, "\x00\x75\x03\x23\0" },
- { 0x1ee6, "\x00\x55\x03\x09\0" },
- { 0x1ee7, "\x00\x75\x03\x09\0" },
- { 0x1ee8, "\x00\x55\x03\x1b\x03\x01\0" },
- { 0x1ee9, "\x00\x75\x03\x1b\x03\x01\0" },
- { 0x1eea, "\x00\x55\x03\x1b\x03\x00\0" },
- { 0x1eeb, "\x00\x75\x03\x1b\x03\x00\0" },
- { 0x1eec, "\x00\x55\x03\x1b\x03\x09\0" },
- { 0x1eed, "\x00\x75\x03\x1b\x03\x09\0" },
- { 0x1eee, "\x00\x55\x03\x1b\x03\x03\0" },
- { 0x1eef, "\x00\x75\x03\x1b\x03\x03\0" },
- { 0x1ef0, "\x00\x55\x03\x1b\x03\x23\0" },
- { 0x1ef1, "\x00\x75\x03\x1b\x03\x23\0" },
- { 0x1ef2, "\x00\x59\x03\x00\0" },
- { 0x1ef3, "\x00\x79\x03\x00\0" },
- { 0x1ef4, "\x00\x59\x03\x23\0" },
- { 0x1ef5, "\x00\x79\x03\x23\0" },
- { 0x1ef6, "\x00\x59\x03\x09\0" },
- { 0x1ef7, "\x00\x79\x03\x09\0" },
- { 0x1ef8, "\x00\x59\x03\x03\0" },
- { 0x1ef9, "\x00\x79\x03\x03\0" },
- { 0x1f00, "\x03\xb1\x03\x13\0" },
- { 0x1f01, "\x03\xb1\x03\x14\0" },
- { 0x1f02, "\x03\xb1\x03\x13\x03\x00\0" },
- { 0x1f03, "\x03\xb1\x03\x14\x03\x00\0" },
- { 0x1f04, "\x03\xb1\x03\x13\x03\x01\0" },
- { 0x1f05, "\x03\xb1\x03\x14\x03\x01\0" },
- { 0x1f06, "\x03\xb1\x03\x13\x03\x42\0" },
- { 0x1f07, "\x03\xb1\x03\x14\x03\x42\0" },
- { 0x1f08, "\x03\x91\x03\x13\0" },
- { 0x1f09, "\x03\x91\x03\x14\0" },
- { 0x1f0a, "\x03\x91\x03\x13\x03\x00\0" },
- { 0x1f0b, "\x03\x91\x03\x14\x03\x00\0" },
- { 0x1f0c, "\x03\x91\x03\x13\x03\x01\0" },
- { 0x1f0d, "\x03\x91\x03\x14\x03\x01\0" },
- { 0x1f0e, "\x03\x91\x03\x13\x03\x42\0" },
- { 0x1f0f, "\x03\x91\x03\x14\x03\x42\0" },
- { 0x1f10, "\x03\xb5\x03\x13\0" },
- { 0x1f11, "\x03\xb5\x03\x14\0" },
- { 0x1f12, "\x03\xb5\x03\x13\x03\x00\0" },
- { 0x1f13, "\x03\xb5\x03\x14\x03\x00\0" },
- { 0x1f14, "\x03\xb5\x03\x13\x03\x01\0" },
- { 0x1f15, "\x03\xb5\x03\x14\x03\x01\0" },
- { 0x1f18, "\x03\x95\x03\x13\0" },
- { 0x1f19, "\x03\x95\x03\x14\0" },
- { 0x1f1a, "\x03\x95\x03\x13\x03\x00\0" },
- { 0x1f1b, "\x03\x95\x03\x14\x03\x00\0" },
- { 0x1f1c, "\x03\x95\x03\x13\x03\x01\0" },
- { 0x1f1d, "\x03\x95\x03\x14\x03\x01\0" },
- { 0x1f20, "\x03\xb7\x03\x13\0" },
- { 0x1f21, "\x03\xb7\x03\x14\0" },
- { 0x1f22, "\x03\xb7\x03\x13\x03\x00\0" },
- { 0x1f23, "\x03\xb7\x03\x14\x03\x00\0" },
- { 0x1f24, "\x03\xb7\x03\x13\x03\x01\0" },
- { 0x1f25, "\x03\xb7\x03\x14\x03\x01\0" },
- { 0x1f26, "\x03\xb7\x03\x13\x03\x42\0" },
- { 0x1f27, "\x03\xb7\x03\x14\x03\x42\0" },
- { 0x1f28, "\x03\x97\x03\x13\0" },
- { 0x1f29, "\x03\x97\x03\x14\0" },
- { 0x1f2a, "\x03\x97\x03\x13\x03\x00\0" },
- { 0x1f2b, "\x03\x97\x03\x14\x03\x00\0" },
- { 0x1f2c, "\x03\x97\x03\x13\x03\x01\0" },
- { 0x1f2d, "\x03\x97\x03\x14\x03\x01\0" },
- { 0x1f2e, "\x03\x97\x03\x13\x03\x42\0" },
- { 0x1f2f, "\x03\x97\x03\x14\x03\x42\0" },
- { 0x1f30, "\x03\xb9\x03\x13\0" },
- { 0x1f31, "\x03\xb9\x03\x14\0" },
- { 0x1f32, "\x03\xb9\x03\x13\x03\x00\0" },
- { 0x1f33, "\x03\xb9\x03\x14\x03\x00\0" },
- { 0x1f34, "\x03\xb9\x03\x13\x03\x01\0" },
- { 0x1f35, "\x03\xb9\x03\x14\x03\x01\0" },
- { 0x1f36, "\x03\xb9\x03\x13\x03\x42\0" },
- { 0x1f37, "\x03\xb9\x03\x14\x03\x42\0" },
- { 0x1f38, "\x03\x99\x03\x13\0" },
- { 0x1f39, "\x03\x99\x03\x14\0" },
- { 0x1f3a, "\x03\x99\x03\x13\x03\x00\0" },
- { 0x1f3b, "\x03\x99\x03\x14\x03\x00\0" },
- { 0x1f3c, "\x03\x99\x03\x13\x03\x01\0" },
- { 0x1f3d, "\x03\x99\x03\x14\x03\x01\0" },
- { 0x1f3e, "\x03\x99\x03\x13\x03\x42\0" },
- { 0x1f3f, "\x03\x99\x03\x14\x03\x42\0" },
- { 0x1f40, "\x03\xbf\x03\x13\0" },
- { 0x1f41, "\x03\xbf\x03\x14\0" },
- { 0x1f42, "\x03\xbf\x03\x13\x03\x00\0" },
- { 0x1f43, "\x03\xbf\x03\x14\x03\x00\0" },
- { 0x1f44, "\x03\xbf\x03\x13\x03\x01\0" },
- { 0x1f45, "\x03\xbf\x03\x14\x03\x01\0" },
- { 0x1f48, "\x03\x9f\x03\x13\0" },
- { 0x1f49, "\x03\x9f\x03\x14\0" },
- { 0x1f4a, "\x03\x9f\x03\x13\x03\x00\0" },
- { 0x1f4b, "\x03\x9f\x03\x14\x03\x00\0" },
- { 0x1f4c, "\x03\x9f\x03\x13\x03\x01\0" },
- { 0x1f4d, "\x03\x9f\x03\x14\x03\x01\0" },
- { 0x1f50, "\x03\xc5\x03\x13\0" },
- { 0x1f51, "\x03\xc5\x03\x14\0" },
- { 0x1f52, "\x03\xc5\x03\x13\x03\x00\0" },
- { 0x1f53, "\x03\xc5\x03\x14\x03\x00\0" },
- { 0x1f54, "\x03\xc5\x03\x13\x03\x01\0" },
- { 0x1f55, "\x03\xc5\x03\x14\x03\x01\0" },
- { 0x1f56, "\x03\xc5\x03\x13\x03\x42\0" },
- { 0x1f57, "\x03\xc5\x03\x14\x03\x42\0" },
- { 0x1f59, "\x03\xa5\x03\x14\0" },
- { 0x1f5b, "\x03\xa5\x03\x14\x03\x00\0" },
- { 0x1f5d, "\x03\xa5\x03\x14\x03\x01\0" },
- { 0x1f5f, "\x03\xa5\x03\x14\x03\x42\0" },
- { 0x1f60, "\x03\xc9\x03\x13\0" },
- { 0x1f61, "\x03\xc9\x03\x14\0" },
- { 0x1f62, "\x03\xc9\x03\x13\x03\x00\0" },
- { 0x1f63, "\x03\xc9\x03\x14\x03\x00\0" },
- { 0x1f64, "\x03\xc9\x03\x13\x03\x01\0" },
- { 0x1f65, "\x03\xc9\x03\x14\x03\x01\0" },
- { 0x1f66, "\x03\xc9\x03\x13\x03\x42\0" },
- { 0x1f67, "\x03\xc9\x03\x14\x03\x42\0" },
- { 0x1f68, "\x03\xa9\x03\x13\0" },
- { 0x1f69, "\x03\xa9\x03\x14\0" },
- { 0x1f6a, "\x03\xa9\x03\x13\x03\x00\0" },
- { 0x1f6b, "\x03\xa9\x03\x14\x03\x00\0" },
- { 0x1f6c, "\x03\xa9\x03\x13\x03\x01\0" },
- { 0x1f6d, "\x03\xa9\x03\x14\x03\x01\0" },
- { 0x1f6e, "\x03\xa9\x03\x13\x03\x42\0" },
- { 0x1f6f, "\x03\xa9\x03\x14\x03\x42\0" },
- { 0x1f70, "\x03\xb1\x03\x00\0" },
- { 0x1f71, "\x03\xb1\x03\x01\0" },
- { 0x1f72, "\x03\xb5\x03\x00\0" },
- { 0x1f73, "\x03\xb5\x03\x01\0" },
- { 0x1f74, "\x03\xb7\x03\x00\0" },
- { 0x1f75, "\x03\xb7\x03\x01\0" },
- { 0x1f76, "\x03\xb9\x03\x00\0" },
- { 0x1f77, "\x03\xb9\x03\x01\0" },
- { 0x1f78, "\x03\xbf\x03\x00\0" },
- { 0x1f79, "\x03\xbf\x03\x01\0" },
- { 0x1f7a, "\x03\xc5\x03\x00\0" },
- { 0x1f7b, "\x03\xc5\x03\x01\0" },
- { 0x1f7c, "\x03\xc9\x03\x00\0" },
- { 0x1f7d, "\x03\xc9\x03\x01\0" },
- { 0x1f80, "\x03\xb1\x03\x13\x03\x45\0" },
- { 0x1f81, "\x03\xb1\x03\x14\x03\x45\0" },
- { 0x1f82, "\x03\xb1\x03\x13\x03\x00\x03\x45\0" },
- { 0x1f83, "\x03\xb1\x03\x14\x03\x00\x03\x45\0" },
- { 0x1f84, "\x03\xb1\x03\x13\x03\x01\x03\x45\0" },
- { 0x1f85, "\x03\xb1\x03\x14\x03\x01\x03\x45\0" },
- { 0x1f86, "\x03\xb1\x03\x13\x03\x42\x03\x45\0" },
- { 0x1f87, "\x03\xb1\x03\x14\x03\x42\x03\x45\0" },
- { 0x1f88, "\x03\x91\x03\x13\x03\x45\0" },
- { 0x1f89, "\x03\x91\x03\x14\x03\x45\0" },
- { 0x1f8a, "\x03\x91\x03\x13\x03\x00\x03\x45\0" },
- { 0x1f8b, "\x03\x91\x03\x14\x03\x00\x03\x45\0" },
- { 0x1f8c, "\x03\x91\x03\x13\x03\x01\x03\x45\0" },
- { 0x1f8d, "\x03\x91\x03\x14\x03\x01\x03\x45\0" },
- { 0x1f8e, "\x03\x91\x03\x13\x03\x42\x03\x45\0" },
- { 0x1f8f, "\x03\x91\x03\x14\x03\x42\x03\x45\0" },
- { 0x1f90, "\x03\xb7\x03\x13\x03\x45\0" },
- { 0x1f91, "\x03\xb7\x03\x14\x03\x45\0" },
- { 0x1f92, "\x03\xb7\x03\x13\x03\x00\x03\x45\0" },
- { 0x1f93, "\x03\xb7\x03\x14\x03\x00\x03\x45\0" },
- { 0x1f94, "\x03\xb7\x03\x13\x03\x01\x03\x45\0" },
- { 0x1f95, "\x03\xb7\x03\x14\x03\x01\x03\x45\0" },
- { 0x1f96, "\x03\xb7\x03\x13\x03\x42\x03\x45\0" },
- { 0x1f97, "\x03\xb7\x03\x14\x03\x42\x03\x45\0" },
- { 0x1f98, "\x03\x97\x03\x13\x03\x45\0" },
- { 0x1f99, "\x03\x97\x03\x14\x03\x45\0" },
- { 0x1f9a, "\x03\x97\x03\x13\x03\x00\x03\x45\0" },
- { 0x1f9b, "\x03\x97\x03\x14\x03\x00\x03\x45\0" },
- { 0x1f9c, "\x03\x97\x03\x13\x03\x01\x03\x45\0" },
- { 0x1f9d, "\x03\x97\x03\x14\x03\x01\x03\x45\0" },
- { 0x1f9e, "\x03\x97\x03\x13\x03\x42\x03\x45\0" },
- { 0x1f9f, "\x03\x97\x03\x14\x03\x42\x03\x45\0" },
- { 0x1fa0, "\x03\xc9\x03\x13\x03\x45\0" },
- { 0x1fa1, "\x03\xc9\x03\x14\x03\x45\0" },
- { 0x1fa2, "\x03\xc9\x03\x13\x03\x00\x03\x45\0" },
- { 0x1fa3, "\x03\xc9\x03\x14\x03\x00\x03\x45\0" },
- { 0x1fa4, "\x03\xc9\x03\x13\x03\x01\x03\x45\0" },
- { 0x1fa5, "\x03\xc9\x03\x14\x03\x01\x03\x45\0" },
- { 0x1fa6, "\x03\xc9\x03\x13\x03\x42\x03\x45\0" },
- { 0x1fa7, "\x03\xc9\x03\x14\x03\x42\x03\x45\0" },
- { 0x1fa8, "\x03\xa9\x03\x13\x03\x45\0" },
- { 0x1fa9, "\x03\xa9\x03\x14\x03\x45\0" },
- { 0x1faa, "\x03\xa9\x03\x13\x03\x00\x03\x45\0" },
- { 0x1fab, "\x03\xa9\x03\x14\x03\x00\x03\x45\0" },
- { 0x1fac, "\x03\xa9\x03\x13\x03\x01\x03\x45\0" },
- { 0x1fad, "\x03\xa9\x03\x14\x03\x01\x03\x45\0" },
- { 0x1fae, "\x03\xa9\x03\x13\x03\x42\x03\x45\0" },
- { 0x1faf, "\x03\xa9\x03\x14\x03\x42\x03\x45\0" },
- { 0x1fb0, "\x03\xb1\x03\x06\0" },
- { 0x1fb1, "\x03\xb1\x03\x04\0" },
- { 0x1fb2, "\x03\xb1\x03\x00\x03\x45\0" },
- { 0x1fb3, "\x03\xb1\x03\x45\0" },
- { 0x1fb4, "\x03\xb1\x03\x01\x03\x45\0" },
- { 0x1fb6, "\x03\xb1\x03\x42\0" },
- { 0x1fb7, "\x03\xb1\x03\x42\x03\x45\0" },
- { 0x1fb8, "\x03\x91\x03\x06\0" },
- { 0x1fb9, "\x03\x91\x03\x04\0" },
- { 0x1fba, "\x03\x91\x03\x00\0" },
- { 0x1fbb, "\x03\x91\x03\x01\0" },
- { 0x1fbc, "\x03\x91\x03\x45\0" },
- { 0x1fbe, "\x03\xb9\0" },
- { 0x1fc1, "\x00\xa8\x03\x42\0" },
- { 0x1fc2, "\x03\xb7\x03\x00\x03\x45\0" },
- { 0x1fc3, "\x03\xb7\x03\x45\0" },
- { 0x1fc4, "\x03\xb7\x03\x01\x03\x45\0" },
- { 0x1fc6, "\x03\xb7\x03\x42\0" },
- { 0x1fc7, "\x03\xb7\x03\x42\x03\x45\0" },
- { 0x1fc8, "\x03\x95\x03\x00\0" },
- { 0x1fc9, "\x03\x95\x03\x01\0" },
- { 0x1fca, "\x03\x97\x03\x00\0" },
- { 0x1fcb, "\x03\x97\x03\x01\0" },
- { 0x1fcc, "\x03\x97\x03\x45\0" },
- { 0x1fcd, "\x1f\xbf\x03\x00\0" },
- { 0x1fce, "\x1f\xbf\x03\x01\0" },
- { 0x1fcf, "\x1f\xbf\x03\x42\0" },
- { 0x1fd0, "\x03\xb9\x03\x06\0" },
- { 0x1fd1, "\x03\xb9\x03\x04\0" },
- { 0x1fd2, "\x03\xb9\x03\x08\x03\x00\0" },
- { 0x1fd3, "\x03\xb9\x03\x08\x03\x01\0" },
- { 0x1fd6, "\x03\xb9\x03\x42\0" },
- { 0x1fd7, "\x03\xb9\x03\x08\x03\x42\0" },
- { 0x1fd8, "\x03\x99\x03\x06\0" },
- { 0x1fd9, "\x03\x99\x03\x04\0" },
- { 0x1fda, "\x03\x99\x03\x00\0" },
- { 0x1fdb, "\x03\x99\x03\x01\0" },
- { 0x1fdd, "\x1f\xfe\x03\x00\0" },
- { 0x1fde, "\x1f\xfe\x03\x01\0" },
- { 0x1fdf, "\x1f\xfe\x03\x42\0" },
- { 0x1fe0, "\x03\xc5\x03\x06\0" },
- { 0x1fe1, "\x03\xc5\x03\x04\0" },
- { 0x1fe2, "\x03\xc5\x03\x08\x03\x00\0" },
- { 0x1fe3, "\x03\xc5\x03\x08\x03\x01\0" },
- { 0x1fe4, "\x03\xc1\x03\x13\0" },
- { 0x1fe5, "\x03\xc1\x03\x14\0" },
- { 0x1fe6, "\x03\xc5\x03\x42\0" },
- { 0x1fe7, "\x03\xc5\x03\x08\x03\x42\0" },
- { 0x1fe8, "\x03\xa5\x03\x06\0" },
- { 0x1fe9, "\x03\xa5\x03\x04\0" },
- { 0x1fea, "\x03\xa5\x03\x00\0" },
- { 0x1feb, "\x03\xa5\x03\x01\0" },
- { 0x1fec, "\x03\xa1\x03\x14\0" },
- { 0x1fed, "\x00\xa8\x03\x00\0" },
- { 0x1fee, "\x00\xa8\x03\x01\0" },
- { 0x1fef, "\x00\x60\0" },
- { 0x1ff2, "\x03\xc9\x03\x00\x03\x45\0" },
- { 0x1ff3, "\x03\xc9\x03\x45\0" },
- { 0x1ff4, "\x03\xc9\x03\x01\x03\x45\0" },
- { 0x1ff6, "\x03\xc9\x03\x42\0" },
- { 0x1ff7, "\x03\xc9\x03\x42\x03\x45\0" },
- { 0x1ff8, "\x03\x9f\x03\x00\0" },
- { 0x1ff9, "\x03\x9f\x03\x01\0" },
- { 0x1ffa, "\x03\xa9\x03\x00\0" },
- { 0x1ffb, "\x03\xa9\x03\x01\0" },
- { 0x1ffc, "\x03\xa9\x03\x45\0" },
- { 0x1ffd, "\x00\xb4\0" },
- { 0x2000, "\x20\x02\0" },
- { 0x2001, "\x20\x03\0" },
- { 0x2126, "\x03\xa9\0" },
- { 0x212a, "\x00\x4b\0" },
- { 0x212b, "\x00\x41\x03\x0a\0" },
- { 0x2204, "\x22\x03\x03\x38\0" },
- { 0x2209, "\x22\x08\x03\x38\0" },
- { 0x220c, "\x22\x0b\x03\x38\0" },
- { 0x2224, "\x22\x23\x03\x38\0" },
- { 0x2226, "\x22\x25\x03\x38\0" },
- { 0x2241, "\x00\x7e\x03\x38\0" },
- { 0x2244, "\x22\x43\x03\x38\0" },
- { 0x2247, "\x22\x45\x03\x38\0" },
- { 0x2249, "\x22\x48\x03\x38\0" },
- { 0x2260, "\x00\x3d\x03\x38\0" },
- { 0x2262, "\x22\x61\x03\x38\0" },
- { 0x226d, "\x22\x4d\x03\x38\0" },
- { 0x226e, "\x00\x3c\x03\x38\0" },
- { 0x226f, "\x00\x3e\x03\x38\0" },
- { 0x2270, "\x22\x64\x03\x38\0" },
- { 0x2271, "\x22\x65\x03\x38\0" },
- { 0x2274, "\x22\x72\x03\x38\0" },
- { 0x2275, "\x22\x73\x03\x38\0" },
- { 0x2278, "\x22\x76\x03\x38\0" },
- { 0x2279, "\x22\x77\x03\x38\0" },
- { 0x2280, "\x22\x7a\x03\x38\0" },
- { 0x2281, "\x22\x7b\x03\x38\0" },
- { 0x2284, "\x22\x82\x03\x38\0" },
- { 0x2285, "\x22\x83\x03\x38\0" },
- { 0x2288, "\x22\x86\x03\x38\0" },
- { 0x2289, "\x22\x87\x03\x38\0" },
- { 0x22ac, "\x22\xa2\x03\x38\0" },
- { 0x22ad, "\x22\xa8\x03\x38\0" },
- { 0x22ae, "\x22\xa9\x03\x38\0" },
- { 0x22af, "\x22\xab\x03\x38\0" },
- { 0x22e0, "\x22\x7c\x03\x38\0" },
- { 0x22e1, "\x22\x7d\x03\x38\0" },
- { 0x22e2, "\x22\x91\x03\x38\0" },
- { 0x22e3, "\x22\x92\x03\x38\0" },
- { 0x22ea, "\x22\xb2\x03\x38\0" },
- { 0x22eb, "\x22\xb3\x03\x38\0" },
- { 0x22ec, "\x22\xb4\x03\x38\0" },
- { 0x22ed, "\x22\xb5\x03\x38\0" },
- { 0x2329, "\x30\x08\0" },
- { 0x232a, "\x30\x09\0" },
- { 0x304c, "\x30\x4b\x30\x99\0" },
- { 0x304e, "\x30\x4d\x30\x99\0" },
- { 0x3050, "\x30\x4f\x30\x99\0" },
- { 0x3052, "\x30\x51\x30\x99\0" },
- { 0x3054, "\x30\x53\x30\x99\0" },
- { 0x3056, "\x30\x55\x30\x99\0" },
- { 0x3058, "\x30\x57\x30\x99\0" },
- { 0x305a, "\x30\x59\x30\x99\0" },
- { 0x305c, "\x30\x5b\x30\x99\0" },
- { 0x305e, "\x30\x5d\x30\x99\0" },
- { 0x3060, "\x30\x5f\x30\x99\0" },
- { 0x3062, "\x30\x61\x30\x99\0" },
- { 0x3065, "\x30\x64\x30\x99\0" },
- { 0x3067, "\x30\x66\x30\x99\0" },
- { 0x3069, "\x30\x68\x30\x99\0" },
- { 0x3070, "\x30\x6f\x30\x99\0" },
- { 0x3071, "\x30\x6f\x30\x9a\0" },
- { 0x3073, "\x30\x72\x30\x99\0" },
- { 0x3074, "\x30\x72\x30\x9a\0" },
- { 0x3076, "\x30\x75\x30\x99\0" },
- { 0x3077, "\x30\x75\x30\x9a\0" },
- { 0x3079, "\x30\x78\x30\x99\0" },
- { 0x307a, "\x30\x78\x30\x9a\0" },
- { 0x307c, "\x30\x7b\x30\x99\0" },
- { 0x307d, "\x30\x7b\x30\x9a\0" },
- { 0x3094, "\x30\x46\x30\x99\0" },
- { 0x309e, "\x30\x9d\x30\x99\0" },
- { 0x30ac, "\x30\xab\x30\x99\0" },
- { 0x30ae, "\x30\xad\x30\x99\0" },
- { 0x30b0, "\x30\xaf\x30\x99\0" },
- { 0x30b2, "\x30\xb1\x30\x99\0" },
- { 0x30b4, "\x30\xb3\x30\x99\0" },
- { 0x30b6, "\x30\xb5\x30\x99\0" },
- { 0x30b8, "\x30\xb7\x30\x99\0" },
- { 0x30ba, "\x30\xb9\x30\x99\0" },
- { 0x30bc, "\x30\xbb\x30\x99\0" },
- { 0x30be, "\x30\xbd\x30\x99\0" },
- { 0x30c0, "\x30\xbf\x30\x99\0" },
- { 0x30c2, "\x30\xc1\x30\x99\0" },
- { 0x30c5, "\x30\xc4\x30\x99\0" },
- { 0x30c7, "\x30\xc6\x30\x99\0" },
- { 0x30c9, "\x30\xc8\x30\x99\0" },
- { 0x30d0, "\x30\xcf\x30\x99\0" },
- { 0x30d1, "\x30\xcf\x30\x9a\0" },
- { 0x30d3, "\x30\xd2\x30\x99\0" },
- { 0x30d4, "\x30\xd2\x30\x9a\0" },
- { 0x30d6, "\x30\xd5\x30\x99\0" },
- { 0x30d7, "\x30\xd5\x30\x9a\0" },
- { 0x30d9, "\x30\xd8\x30\x99\0" },
- { 0x30da, "\x30\xd8\x30\x9a\0" },
- { 0x30dc, "\x30\xdb\x30\x99\0" },
- { 0x30dd, "\x30\xdb\x30\x9a\0" },
- { 0x30f4, "\x30\xa6\x30\x99\0" },
- { 0x30f7, "\x30\xef\x30\x99\0" },
- { 0x30f8, "\x30\xf0\x30\x99\0" },
- { 0x30f9, "\x30\xf1\x30\x99\0" },
- { 0x30fa, "\x30\xf2\x30\x99\0" },
- { 0x30fe, "\x30\xfd\x30\x99\0" },
- { 0xf900, "\x8c\x48\0" },
- { 0xf901, "\x66\xf4\0" },
- { 0xf902, "\x8e\xca\0" },
- { 0xf903, "\x8c\xc8\0" },
- { 0xf904, "\x6e\xd1\0" },
- { 0xf905, "\x4e\x32\0" },
- { 0xf906, "\x53\xe5\0" },
- { 0xf907, "\x9f\x9c\0" },
- { 0xf908, "\x9f\x9c\0" },
- { 0xf909, "\x59\x51\0" },
- { 0xf90a, "\x91\xd1\0" },
- { 0xf90b, "\x55\x87\0" },
- { 0xf90c, "\x59\x48\0" },
- { 0xf90d, "\x61\xf6\0" },
- { 0xf90e, "\x76\x69\0" },
- { 0xf90f, "\x7f\x85\0" },
- { 0xf910, "\x86\x3f\0" },
- { 0xf911, "\x87\xba\0" },
- { 0xf912, "\x88\xf8\0" },
- { 0xf913, "\x90\x8f\0" },
- { 0xf914, "\x6a\x02\0" },
- { 0xf915, "\x6d\x1b\0" },
- { 0xf916, "\x70\xd9\0" },
- { 0xf917, "\x73\xde\0" },
- { 0xf918, "\x84\x3d\0" },
- { 0xf919, "\x91\x6a\0" },
- { 0xf91a, "\x99\xf1\0" },
- { 0xf91b, "\x4e\x82\0" },
- { 0xf91c, "\x53\x75\0" },
- { 0xf91d, "\x6b\x04\0" },
- { 0xf91e, "\x72\x1b\0" },
- { 0xf91f, "\x86\x2d\0" },
- { 0xf920, "\x9e\x1e\0" },
- { 0xf921, "\x5d\x50\0" },
- { 0xf922, "\x6f\xeb\0" },
- { 0xf923, "\x85\xcd\0" },
- { 0xf924, "\x89\x64\0" },
- { 0xf925, "\x62\xc9\0" },
- { 0xf926, "\x81\xd8\0" },
- { 0xf927, "\x88\x1f\0" },
- { 0xf928, "\x5e\xca\0" },
- { 0xf929, "\x67\x17\0" },
- { 0xf92a, "\x6d\x6a\0" },
- { 0xf92b, "\x72\xfc\0" },
- { 0xf92c, "\x90\xce\0" },
- { 0xf92d, "\x4f\x86\0" },
- { 0xf92e, "\x51\xb7\0" },
- { 0xf92f, "\x52\xde\0" },
- { 0xf930, "\x64\xc4\0" },
- { 0xf931, "\x6a\xd3\0" },
- { 0xf932, "\x72\x10\0" },
- { 0xf933, "\x76\xe7\0" },
- { 0xf934, "\x80\x01\0" },
- { 0xf935, "\x86\x06\0" },
- { 0xf936, "\x86\x5c\0" },
- { 0xf937, "\x8d\xef\0" },
- { 0xf938, "\x97\x32\0" },
- { 0xf939, "\x9b\x6f\0" },
- { 0xf93a, "\x9d\xfa\0" },
- { 0xf93b, "\x78\x8c\0" },
- { 0xf93c, "\x79\x7f\0" },
- { 0xf93d, "\x7d\xa0\0" },
- { 0xf93e, "\x83\xc9\0" },
- { 0xf93f, "\x93\x04\0" },
- { 0xf940, "\x9e\x7f\0" },
- { 0xf941, "\x8a\xd6\0" },
- { 0xf942, "\x58\xdf\0" },
- { 0xf943, "\x5f\x04\0" },
- { 0xf944, "\x7c\x60\0" },
- { 0xf945, "\x80\x7e\0" },
- { 0xf946, "\x72\x62\0" },
- { 0xf947, "\x78\xca\0" },
- { 0xf948, "\x8c\xc2\0" },
- { 0xf949, "\x96\xf7\0" },
- { 0xf94a, "\x58\xd8\0" },
- { 0xf94b, "\x5c\x62\0" },
- { 0xf94c, "\x6a\x13\0" },
- { 0xf94d, "\x6d\xda\0" },
- { 0xf94e, "\x6f\x0f\0" },
- { 0xf94f, "\x7d\x2f\0" },
- { 0xf950, "\x7e\x37\0" },
- { 0xf951, "\x96\xfb\0" },
- { 0xf952, "\x52\xd2\0" },
- { 0xf953, "\x80\x8b\0" },
- { 0xf954, "\x51\xdc\0" },
- { 0xf955, "\x51\xcc\0" },
- { 0xf956, "\x7a\x1c\0" },
- { 0xf957, "\x7d\xbe\0" },
- { 0xf958, "\x83\xf1\0" },
- { 0xf959, "\x96\x75\0" },
- { 0xf95a, "\x8b\x80\0" },
- { 0xf95b, "\x62\xcf\0" },
- { 0xf95c, "\x6a\x02\0" },
- { 0xf95d, "\x8a\xfe\0" },
- { 0xf95e, "\x4e\x39\0" },
- { 0xf95f, "\x5b\xe7\0" },
- { 0xf960, "\x60\x12\0" },
- { 0xf961, "\x73\x87\0" },
- { 0xf962, "\x75\x70\0" },
- { 0xf963, "\x53\x17\0" },
- { 0xf964, "\x78\xfb\0" },
- { 0xf965, "\x4f\xbf\0" },
- { 0xf966, "\x5f\xa9\0" },
- { 0xf967, "\x4e\x0d\0" },
- { 0xf968, "\x6c\xcc\0" },
- { 0xf969, "\x65\x78\0" },
- { 0xf96a, "\x7d\x22\0" },
- { 0xf96b, "\x53\xc3\0" },
- { 0xf96c, "\x58\x5e\0" },
- { 0xf96d, "\x77\x01\0" },
- { 0xf96e, "\x84\x49\0" },
- { 0xf96f, "\x8a\xaa\0" },
- { 0xf970, "\x6b\xba\0" },
- { 0xf971, "\x8f\xb0\0" },
- { 0xf972, "\x6c\x88\0" },
- { 0xf973, "\x62\xfe\0" },
- { 0xf974, "\x82\xe5\0" },
- { 0xf975, "\x63\xa0\0" },
- { 0xf976, "\x75\x65\0" },
- { 0xf977, "\x4e\xae\0" },
- { 0xf978, "\x51\x69\0" },
- { 0xf979, "\x51\xc9\0" },
- { 0xf97a, "\x68\x81\0" },
- { 0xf97b, "\x7c\xe7\0" },
- { 0xf97c, "\x82\x6f\0" },
- { 0xf97d, "\x8a\xd2\0" },
- { 0xf97e, "\x91\xcf\0" },
- { 0xf97f, "\x52\xf5\0" },
- { 0xf980, "\x54\x42\0" },
- { 0xf981, "\x59\x73\0" },
- { 0xf982, "\x5e\xec\0" },
- { 0xf983, "\x65\xc5\0" },
- { 0xf984, "\x6f\xfe\0" },
- { 0xf985, "\x79\x2a\0" },
- { 0xf986, "\x95\xad\0" },
- { 0xf987, "\x9a\x6a\0" },
- { 0xf988, "\x9e\x97\0" },
- { 0xf989, "\x9e\xce\0" },
- { 0xf98a, "\x52\x9b\0" },
- { 0xf98b, "\x66\xc6\0" },
- { 0xf98c, "\x6b\x77\0" },
- { 0xf98d, "\x8f\x62\0" },
- { 0xf98e, "\x5e\x74\0" },
- { 0xf98f, "\x61\x90\0" },
- { 0xf990, "\x62\x00\0" },
- { 0xf991, "\x64\x9a\0" },
- { 0xf992, "\x6f\x23\0" },
- { 0xf993, "\x71\x49\0" },
- { 0xf994, "\x74\x89\0" },
- { 0xf995, "\x79\xca\0" },
- { 0xf996, "\x7d\xf4\0" },
- { 0xf997, "\x80\x6f\0" },
- { 0xf998, "\x8f\x26\0" },
- { 0xf999, "\x84\xee\0" },
- { 0xf99a, "\x90\x23\0" },
- { 0xf99b, "\x93\x4a\0" },
- { 0xf99c, "\x52\x17\0" },
- { 0xf99d, "\x52\xa3\0" },
- { 0xf99e, "\x54\xbd\0" },
- { 0xf99f, "\x70\xc8\0" },
- { 0xf9a0, "\x88\xc2\0" },
- { 0xf9a1, "\x8a\xaa\0" },
- { 0xf9a2, "\x5e\xc9\0" },
- { 0xf9a3, "\x5f\xf5\0" },
- { 0xf9a4, "\x63\x7b\0" },
- { 0xf9a5, "\x6b\xae\0" },
- { 0xf9a6, "\x7c\x3e\0" },
- { 0xf9a7, "\x73\x75\0" },
- { 0xf9a8, "\x4e\xe4\0" },
- { 0xf9a9, "\x56\xf9\0" },
- { 0xf9aa, "\x5b\xe7\0" },
- { 0xf9ab, "\x5d\xba\0" },
- { 0xf9ac, "\x60\x1c\0" },
- { 0xf9ad, "\x73\xb2\0" },
- { 0xf9ae, "\x74\x69\0" },
- { 0xf9af, "\x7f\x9a\0" },
- { 0xf9b0, "\x80\x46\0" },
- { 0xf9b1, "\x92\x34\0" },
- { 0xf9b2, "\x96\xf6\0" },
- { 0xf9b3, "\x97\x48\0" },
- { 0xf9b4, "\x98\x18\0" },
- { 0xf9b5, "\x4f\x8b\0" },
- { 0xf9b6, "\x79\xae\0" },
- { 0xf9b7, "\x91\xb4\0" },
- { 0xf9b8, "\x96\xb8\0" },
- { 0xf9b9, "\x60\xe1\0" },
- { 0xf9ba, "\x4e\x86\0" },
- { 0xf9bb, "\x50\xda\0" },
- { 0xf9bc, "\x5b\xee\0" },
- { 0xf9bd, "\x5c\x3f\0" },
- { 0xf9be, "\x65\x99\0" },
- { 0xf9bf, "\x6a\x02\0" },
- { 0xf9c0, "\x71\xce\0" },
- { 0xf9c1, "\x76\x42\0" },
- { 0xf9c2, "\x84\xfc\0" },
- { 0xf9c3, "\x90\x7c\0" },
- { 0xf9c4, "\x9f\x8d\0" },
- { 0xf9c5, "\x66\x88\0" },
- { 0xf9c6, "\x96\x2e\0" },
- { 0xf9c7, "\x52\x89\0" },
- { 0xf9c8, "\x67\x7b\0" },
- { 0xf9c9, "\x67\xf3\0" },
- { 0xf9ca, "\x6d\x41\0" },
- { 0xf9cb, "\x6e\x9c\0" },
- { 0xf9cc, "\x74\x09\0" },
- { 0xf9cd, "\x75\x59\0" },
- { 0xf9ce, "\x78\x6b\0" },
- { 0xf9cf, "\x7d\x10\0" },
- { 0xf9d0, "\x98\x5e\0" },
- { 0xf9d1, "\x51\x6d\0" },
- { 0xf9d2, "\x62\x2e\0" },
- { 0xf9d3, "\x96\x78\0" },
- { 0xf9d4, "\x50\x2b\0" },
- { 0xf9d5, "\x5d\x19\0" },
- { 0xf9d6, "\x6d\xea\0" },
- { 0xf9d7, "\x8f\x2a\0" },
- { 0xf9d8, "\x5f\x8b\0" },
- { 0xf9d9, "\x61\x44\0" },
- { 0xf9da, "\x68\x17\0" },
- { 0xf9db, "\x73\x87\0" },
- { 0xf9dc, "\x96\x86\0" },
- { 0xf9dd, "\x52\x29\0" },
- { 0xf9de, "\x54\x0f\0" },
- { 0xf9df, "\x5c\x65\0" },
- { 0xf9e0, "\x66\x13\0" },
- { 0xf9e1, "\x67\x4e\0" },
- { 0xf9e2, "\x68\xa8\0" },
- { 0xf9e3, "\x6c\xe5\0" },
- { 0xf9e4, "\x74\x06\0" },
- { 0xf9e5, "\x75\xe2\0" },
- { 0xf9e6, "\x7f\x79\0" },
- { 0xf9e7, "\x88\xcf\0" },
- { 0xf9e8, "\x88\xe1\0" },
- { 0xf9e9, "\x91\xcc\0" },
- { 0xf9ea, "\x96\xe2\0" },
- { 0xf9eb, "\x53\x3f\0" },
- { 0xf9ec, "\x6e\xba\0" },
- { 0xf9ed, "\x54\x1d\0" },
- { 0xf9ee, "\x71\xd0\0" },
- { 0xf9ef, "\x74\x98\0" },
- { 0xf9f0, "\x85\xfa\0" },
- { 0xf9f1, "\x96\xa3\0" },
- { 0xf9f2, "\x9c\x57\0" },
- { 0xf9f3, "\x9e\x9f\0" },
- { 0xf9f4, "\x67\x97\0" },
- { 0xf9f5, "\x6d\xcb\0" },
- { 0xf9f6, "\x81\xe8\0" },
- { 0xf9f7, "\x7a\xcb\0" },
- { 0xf9f8, "\x7b\x20\0" },
- { 0xf9f9, "\x7c\x92\0" },
- { 0xf9fa, "\x72\xc0\0" },
- { 0xf9fb, "\x70\x99\0" },
- { 0xf9fc, "\x8b\x58\0" },
- { 0xf9fd, "\x4e\xc0\0" },
- { 0xf9fe, "\x83\x36\0" },
- { 0xf9ff, "\x52\x3a\0" },
- { 0xfa00, "\x52\x07\0" },
- { 0xfa01, "\x5e\xa6\0" },
- { 0xfa02, "\x62\xd3\0" },
- { 0xfa03, "\x7c\xd6\0" },
- { 0xfa04, "\x5b\x85\0" },
- { 0xfa05, "\x6d\x1e\0" },
- { 0xfa06, "\x66\xb4\0" },
- { 0xfa07, "\x8f\x3b\0" },
- { 0xfa08, "\x88\x4c\0" },
- { 0xfa09, "\x96\x4d\0" },
- { 0xfa0a, "\x89\x8b\0" },
- { 0xfa0b, "\x5e\xd3\0" },
- { 0xfa0c, "\x51\x40\0" },
- { 0xfa0d, "\x55\xc0\0" },
- { 0xfa10, "\x58\x5a\0" },
- { 0xfa12, "\x66\x74\0" },
- { 0xfa15, "\x51\xde\0" },
- { 0xfa16, "\x73\x2a\0" },
- { 0xfa17, "\x76\xca\0" },
- { 0xfa18, "\x79\x3c\0" },
- { 0xfa19, "\x79\x5e\0" },
- { 0xfa1a, "\x79\x65\0" },
- { 0xfa1b, "\x79\x8f\0" },
- { 0xfa1c, "\x97\x56\0" },
- { 0xfa1d, "\x7c\xbe\0" },
- { 0xfa1e, "\x7f\xbd\0" },
- { 0xfa20, "\x86\x12\0" },
- { 0xfa22, "\x8a\xf8\0" },
- { 0xfa25, "\x90\x38\0" },
- { 0xfa26, "\x90\xfd\0" },
- { 0xfa2a, "\x98\xef\0" },
- { 0xfa2b, "\x98\xfc\0" },
- { 0xfa2c, "\x99\x28\0" },
- { 0xfa2d, "\x9d\xb4\0" },
- { 0xfb1f, "\x05\xf2\x05\xb7\0" },
- { 0xfb2a, "\x05\xe9\x05\xc1\0" },
- { 0xfb2b, "\x05\xe9\x05\xc2\0" },
- { 0xfb2c, "\x05\xe9\x05\xbc\x05\xc1\0" },
- { 0xfb2d, "\x05\xe9\x05\xbc\x05\xc2\0" },
- { 0xfb2e, "\x05\xd0\x05\xb7\0" },
- { 0xfb2f, "\x05\xd0\x05\xb8\0" },
- { 0xfb30, "\x05\xd0\x05\xbc\0" },
- { 0xfb31, "\x05\xd1\x05\xbc\0" },
- { 0xfb32, "\x05\xd2\x05\xbc\0" },
- { 0xfb33, "\x05\xd3\x05\xbc\0" },
- { 0xfb34, "\x05\xd4\x05\xbc\0" },
- { 0xfb35, "\x05\xd5\x05\xbc\0" },
- { 0xfb36, "\x05\xd6\x05\xbc\0" },
- { 0xfb38, "\x05\xd8\x05\xbc\0" },
- { 0xfb39, "\x05\xd9\x05\xbc\0" },
- { 0xfb3a, "\x05\xda\x05\xbc\0" },
- { 0xfb3b, "\x05\xdb\x05\xbc\0" },
- { 0xfb3c, "\x05\xdc\x05\xbc\0" },
- { 0xfb3e, "\x05\xde\x05\xbc\0" },
- { 0xfb40, "\x05\xe0\x05\xbc\0" },
- { 0xfb41, "\x05\xe1\x05\xbc\0" },
- { 0xfb43, "\x05\xe3\x05\xbc\0" },
- { 0xfb44, "\x05\xe4\x05\xbc\0" },
- { 0xfb46, "\x05\xe6\x05\xbc\0" },
- { 0xfb47, "\x05\xe7\x05\xbc\0" },
- { 0xfb48, "\x05\xe8\x05\xbc\0" },
- { 0xfb49, "\x05\xe9\x05\xbc\0" },
- { 0xfb4a, "\x05\xea\x05\xbc\0" },
- { 0xfb4b, "\x05\xd5\x05\xb9\0" },
- { 0xfb4c, "\x05\xd1\x05\xbf\0" },
- { 0xfb4d, "\x05\xdb\x05\xbf\0" },
- { 0xfb4e, "\x05\xe4\x05\xbf\0" }
-};
-
-/*
- * WARNING!
- *
- * NO BUFFER CHECKING AHEAD!
- *
- */
-
-static gint
-e_canonical_decomposition (gunichar ch, gunichar * buf)
-{
- gint len = 0;
-
- if (ch <= 0xffff)
- {
- int start = 0;
- int end = sizeof (e_decomp_table) / sizeof (e_decomp_table[0]);
- while (start != end)
- {
- int half = (start + end) / 2;
- if (ch == e_decomp_table[half].ch) {
- /* Found it. */
- int i;
- /* We store as a double-nul terminated string. */
- for (len = 0; (e_decomp_table[half].expansion[len] || e_decomp_table[half].expansion[len + 1]); len += 2) ;
-
- /* We've counted twice as many bytes as there are
- characters. */
- len /= 2;
-
- for (i = 0; i < len; i ++) {
- buf[i] = (e_decomp_table[half].expansion[2 * i] << 8) | e_decomp_table[half].expansion[2 * i + 1];
- }
- break;
- } else if (ch > e_decomp_table[half].ch) {
- if (start == half) break;
- start = half;
- } else {
- if (end == half) break;
- end = half;
- }
- }
- }
-
- if (len == 0)
- {
- /* Not in our table. */
- *buf = ch;
- len = 1;
- }
-
- /* Supposedly following the Unicode 2.1.9 table means that the
- decompositions come out in canonical order. I haven't tested
- this, but we rely on it here. */
- return len;
-}
-
-static gunichar
-e_stripped_char (gunichar ch)
-{
- gunichar decomp[MAX_DECOMP];
- GUnicodeType utype;
- gint dlen;
-
- utype = g_unichar_type (ch);
-
- switch (utype) {
- case G_UNICODE_CONTROL:
- case G_UNICODE_FORMAT:
- case G_UNICODE_UNASSIGNED:
- case G_UNICODE_COMBINING_MARK:
- /* Ignore those */
- return 0;
- break;
- default:
- /* Convert to lowercase, fall through */
- ch = g_unichar_tolower (ch);
- case G_UNICODE_LOWERCASE_LETTER:
- dlen = e_canonical_decomposition (ch, decomp);
- if (dlen > 0) return *decomp;
- break;
- }
-
- return 0;
-}
-
-gchar *
-e_xml_get_translated_utf8_string_prop_by_name (const xmlNode *parent, const xmlChar *prop_name)
-{
- xmlChar *prop;
- gchar *ret_val = NULL;
- gchar *combined_name;
-
- g_return_val_if_fail (parent != NULL, 0);
- g_return_val_if_fail (prop_name != NULL, 0);
-
- prop = xmlGetProp ((xmlNode *) parent, prop_name);
- if (prop != NULL) {
- ret_val = g_strdup (prop);
- xmlFree (prop);
- return ret_val;
- }
-
- combined_name = g_strdup_printf("_%s", prop_name);
- prop = xmlGetProp ((xmlNode *) parent, combined_name);
- if (prop != NULL) {
- ret_val = g_strdup (gettext (prop));
- xmlFree (prop);
- }
- g_free(combined_name);
-
- return ret_val;
-}
diff --git a/widgets/misc/e-unicode.h b/widgets/misc/e-unicode.h
deleted file mode 100644
index 12c9ef3aa2..0000000000
--- a/widgets/misc/e-unicode.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-unicode.h - utf-8 support functions for gal
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Lauris Kaplinski <lauris@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_UNICODE_H_
-#define _E_UNICODE_H_
-
-#include <sys/types.h>
-#include <glib.h>
-#include <gtk/gtkclist.h>
-#include <gtk/gtkentry.h>
-#include <gtk/gtkmenu.h>
-#include <gtk/gtkwidget.h>
-#include <libxml/tree.h>
-#include <iconv.h>
-
-G_BEGIN_DECLS
-
-#define G_UTF8_IN_GAL
-
-/*
- * UTF-8 searching implementations
- *
- * e_utf8_strstrcase - case insensitive search
- * e_utf8_strstrcasedecomp - case insensitive and decompositing search (i.e. accented
- * letters are treated equal to their base letters, explicit accent marks (unicode
- * not ascii/iso ones) are ignored).
- */
-
-const gchar *e_utf8_strstrcase (const gchar *haystack,
- const gchar *needle);
-const gchar *e_utf8_strstrcasedecomp (const gchar *haystack,
- const gchar *needle);
-gchar *e_utf8_from_gtk_event_key (GtkWidget *widget,
- guint keyval,
- const gchar *string);
-gchar *e_utf8_from_iconv_string (iconv_t ic,
- const gchar *string);
-gchar *e_utf8_from_iconv_string_sized (iconv_t ic,
- const gchar *string,
- gint bytes);
-gchar *e_utf8_to_iconv_string (iconv_t ic,
- const gchar *string);
-gchar *e_utf8_to_iconv_string_sized (iconv_t ic,
- const gchar *string,
- gint bytes);
-gchar *e_utf8_from_charset_string (const gchar *charset,
- const gchar *string);
-gchar *e_utf8_from_charset_string_sized (const gchar *charset,
- const gchar *string,
- gint bytes);
-gchar *e_utf8_to_charset_string (const gchar *charset,
- const gchar *string);
-gchar *e_utf8_to_charset_string_sized (const gchar *charset,
- const gchar *string,
- gint bytes);
-gchar *e_utf8_from_locale_string (const gchar *string);
-gchar *e_utf8_from_locale_string_sized (const gchar *string,
- gint bytes);
-gchar *e_utf8_to_locale_string (const gchar *string);
-gchar *e_utf8_to_locale_string_sized (const gchar *string,
- gint bytes);
-gboolean e_utf8_is_ascii (const gchar *string);
-/*
- * These are simple wrappers that save us some typing
- */
-
-/* NB! This return newly allocated string, not const as gtk+ one */
-gchar *e_utf8_gtk_entry_get_text (GtkEntry *entry);
-void e_utf8_gtk_entry_set_text (GtkEntry *entry,
- const gchar *text);
-gchar *e_utf8_gtk_editable_get_text (GtkEditable *editable);
-void e_utf8_gtk_editable_set_text (GtkEditable *editable,
- const gchar *text);
-gchar *e_utf8_gtk_editable_get_chars (GtkEditable *editable,
- gint start,
- gint end);
-void e_utf8_gtk_editable_insert_text (GtkEditable *editable,
- const gchar *text,
- gint length,
- gint *position);
-gchar *e_utf8_xml1_decode (const gchar *text);
-gchar *e_utf8_xml1_encode (const gchar *text);
-gint e_unichar_to_utf8 (gint c,
- gchar *outbuf);
-gchar *e_unicode_get_utf8 (const gchar *text,
- gunichar *out);
-guint32 gdk_keyval_to_unicode (guint keysym);
-gchar *e_xml_get_translated_utf8_string_prop_by_name (const xmlNode *parent,
- const xmlChar *prop_name);
-
-G_END_DECLS
-
-#endif
-
-
diff --git a/widgets/misc/gal-categories.glade b/widgets/misc/gal-categories.glade
deleted file mode 100644
index 40f034999b..0000000000
--- a/widgets/misc/gal-categories.glade
+++ /dev/null
@@ -1,173 +0,0 @@
-<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
-<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
-
-<glade-interface>
-
-<widget class="GtkDialog" id="categories">
- <property name="title" translatable="yes">categories</property>
- <property name="type">GTK_WINDOW_TOPLEVEL</property>
- <property name="window_position">GTK_WIN_POS_NONE</property>
- <property name="modal">False</property>
- <property name="resizable">True</property>
- <property name="destroy_with_parent">False</property>
- <property name="decorated">True</property>
- <property name="skip_taskbar_hint">False</property>
- <property name="skip_pager_hint">False</property>
- <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
- <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
- <property name="has_separator">False</property>
-
- <child internal-child="vbox">
- <widget class="GtkVBox" id="dialog-vbox1">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
-
- <child internal-child="action_area">
- <widget class="GtkHButtonBox" id="dialog-action_area1">
- <property name="visible">True</property>
- <property name="layout_style">GTK_BUTTONBOX_END</property>
-
- <child>
- <widget class="GtkButton" id="button3">
- <property name="visible">True</property>
- <property name="can_default">True</property>
- <property name="can_focus">True</property>
- <property name="label">gtk-ok</property>
- <property name="use_stock">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="response_id">0</property>
- </widget>
- </child>
-
- <child>
- <widget class="GtkButton" id="button4">
- <property name="visible">True</property>
- <property name="can_default">True</property>
- <property name="can_focus">True</property>
- <property name="label">gtk-cancel</property>
- <property name="use_stock">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="response_id">0</property>
- </widget>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="pack_type">GTK_PACK_END</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkTable" id="table-categories">
- <property name="border_width">12</property>
- <property name="visible">True</property>
- <property name="n_rows">5</property>
- <property name="n_columns">1</property>
- <property name="homogeneous">False</property>
- <property name="row_spacing">6</property>
- <property name="column_spacing">6</property>
-
- <child>
- <widget class="GtkEntry" id="entry-categories">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="editable">True</property>
- <property name="visibility">True</property>
- <property name="max_length">0</property>
- <property name="text" translatable="yes"></property>
- <property name="has_frame">True</property>
- <property name="invisible_char" translatable="yes">*</property>
- <property name="activates_default">False</property>
- </widget>
- <packing>
- <property name="left_attach">0</property>
- <property name="right_attach">1</property>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
- <property name="y_options"></property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label-header">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Item(s) belong to these _categories:</property>
- <property name="use_underline">True</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_CENTER</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- <property name="mnemonic_widget">entry-categories</property>
- </widget>
- <packing>
- <property name="left_attach">0</property>
- <property name="right_attach">1</property>
- <property name="top_attach">0</property>
- <property name="bottom_attach">1</property>
- <property name="x_options">fill</property>
- <property name="y_options"></property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label2">
- <property name="visible">True</property>
- <property name="label" translatable="yes">_Available Categories:</property>
- <property name="use_underline">True</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_CENTER</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="left_attach">0</property>
- <property name="right_attach">1</property>
- <property name="top_attach">2</property>
- <property name="bottom_attach">3</property>
- <property name="x_options">fill</property>
- <property name="y_options"></property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkButton" id="button-ecmld">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Edit Master Category List...</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- </widget>
- <packing>
- <property name="left_attach">0</property>
- <property name="right_attach">1</property>
- <property name="top_attach">4</property>
- <property name="bottom_attach">5</property>
- <property name="y_options">fill</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- </child>
-</widget>
-
-</glade-interface>
diff --git a/widgets/misc/gal-combo-box.c b/widgets/misc/gal-combo-box.c
deleted file mode 100644
index ad941a7133..0000000000
--- a/widgets/misc/gal-combo-box.c
+++ /dev/null
@@ -1,834 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * gtk-combo-box.c - a customizable combobox
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Miguel de Icaza (miguel@gnu.org)
- * Adrian E Feiguin (feiguin@ifir.edu.ar)
- * Paolo Molnaro (lupus@debian.org).
- * Jon K Hellan (hellan@acm.org)
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <gtk/gtkhbox.h>
-#include <gtk/gtktogglebutton.h>
-#include <gtk/gtkarrow.h>
-#include <gtk/gtkeventbox.h>
-#include <gtk/gtkmain.h>
-#include <gtk/gtksignal.h>
-#include <gtk/gtkwindow.h>
-#include <gtk/gtkframe.h>
-#include <gtk/gtkvbox.h>
-#include <gtk/gtktearoffmenuitem.h>
-#include <gdk/gdkkeysyms.h>
-#include "gal-combo-box.h"
-#include "gal/util/e-util.h"
-
-#define PARENT_TYPE GTK_TYPE_HBOX
-static GObjectClass *gal_combo_box_parent_class;
-
-static int gtk_combo_toggle_pressed (GtkToggleButton *tbutton,
- GalComboBox *combo_box);
-static void gtk_combo_popup_tear_off (GalComboBox *combo,
- gboolean set_position);
-static void gtk_combo_set_tearoff_state (GalComboBox *combo,
- gboolean torn_off);
-static void gtk_combo_popup_reparent (GtkWidget *popup, GtkWidget *new_parent,
- gboolean unrealize);
-static gboolean cb_popup_delete (GtkWidget *w, GdkEventAny *event,
- GalComboBox *combo);
-static void gtk_combo_tearoff_bg_copy (GalComboBox *combo);
-
-enum {
- POP_DOWN_WIDGET,
- POP_DOWN_DONE,
- PRE_POP_DOWN,
- POST_POP_HIDE,
- LAST_SIGNAL
-};
-
-static guint gal_combo_box_signals [LAST_SIGNAL] = { 0, };
-
-struct _GalComboBoxPrivate {
- GtkWidget *pop_down_widget;
- GtkWidget *display_widget;
-
- /*
- * Internal widgets used to implement the ComboBox
- */
- GtkWidget *frame;
- GtkWidget *arrow_button;
-
- GtkWidget *toplevel; /* Popup's toplevel when not torn off */
- GtkWidget *tearoff_window; /* Popup's toplevel when torn off */
- guint torn_off;
-
- GtkWidget *tearable; /* The tearoff "button" */
- GtkWidget *popup; /* Popup */
-
- /*
- * Closure for invoking the callbacks above
- */
- void *closure;
-};
-
-static void
-gal_combo_box_finalize (GObject *object)
-{
- GalComboBox *combo_box = GAL_COMBO_BOX (object);
-
- g_free (combo_box->priv);
-
- gal_combo_box_parent_class->finalize (object);
-}
-
-static void
-gal_combo_box_destroy (GtkObject *object)
-{
- GtkObjectClass *klass = (GtkObjectClass *)gal_combo_box_parent_class;
- GalComboBox *combo_box = GAL_COMBO_BOX (object);
-
- if (combo_box->priv->toplevel) {
- gtk_object_destroy (GTK_OBJECT (combo_box->priv->toplevel));
- combo_box->priv->toplevel = NULL;
- }
-
- if (combo_box->priv->tearoff_window) {
- gtk_object_destroy (GTK_OBJECT (combo_box->priv->tearoff_window));
- combo_box->priv->tearoff_window = NULL;
- }
-
- if (klass->destroy)
- klass->destroy (object);
-}
-
-static gboolean
-gal_combo_box_mnemonic_activate (GtkWidget *w, gboolean group_cycling)
-{
- GalComboBox *combo_box = GAL_COMBO_BOX (w);
- gtk_toggle_button_set_active (
- GTK_TOGGLE_BUTTON (combo_box->priv->arrow_button), TRUE);
- return TRUE;
-}
-
-static void
-gal_combo_box_class_init (GObjectClass *object_class)
-{
- GtkWidgetClass *widget_class = (GtkWidgetClass *)object_class;
- gal_combo_box_parent_class = g_type_class_peek_parent (object_class);
-
- object_class->finalize = gal_combo_box_finalize;
- widget_class->mnemonic_activate = gal_combo_box_mnemonic_activate;
- ((GtkObjectClass *)object_class)->destroy = gal_combo_box_destroy;
-
- gal_combo_box_signals [POP_DOWN_WIDGET] = g_signal_new (
- "pop_down_widget",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GalComboBoxClass, pop_down_widget),
- NULL, NULL,
- e_marshal_POINTER__NONE,
- G_TYPE_POINTER, 0, G_TYPE_NONE);
-
- gal_combo_box_signals [POP_DOWN_DONE] = g_signal_new (
- "pop_down_done",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GalComboBoxClass, pop_down_done),
- NULL, NULL,
- e_marshal_BOOLEAN__OBJECT,
- G_TYPE_BOOLEAN, 1, G_TYPE_OBJECT);
-
- gal_combo_box_signals [PRE_POP_DOWN] = g_signal_new (
- "pre_pop_down",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GalComboBoxClass, pre_pop_down),
- NULL, NULL,
- e_marshal_NONE__NONE,
- G_TYPE_NONE, 0);
-
- gal_combo_box_signals [POST_POP_HIDE] = g_signal_new (
- "post_pop_hide",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GalComboBoxClass, post_pop_hide),
- NULL, NULL,
- e_marshal_NONE__NONE,
- G_TYPE_NONE, 0);
-}
-
-static void
-deactivate_arrow (GalComboBox *combo_box)
-{
- GtkToggleButton *arrow;
-
- arrow = GTK_TOGGLE_BUTTON (combo_box->priv->arrow_button);
- g_signal_handlers_block_matched (arrow,
- G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA,
- 0, 0, NULL,
- gtk_combo_toggle_pressed, combo_box);
-
- gtk_toggle_button_set_active (arrow, FALSE);
-
- g_signal_handlers_unblock_matched (arrow,
- G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA,
- 0, 0, NULL,
- gtk_combo_toggle_pressed, combo_box);
-}
-
-/**
- * gal_combo_box_popup_hide_unconditional
- * @combo_box: Combo box
- *
- * Hide popup, whether or not it is torn off.
- */
-static void
-gal_combo_box_popup_hide_unconditional (GalComboBox *combo_box)
-{
- gboolean popup_info_destroyed = FALSE;
-
- g_return_if_fail (combo_box != NULL);
- g_return_if_fail (GAL_IS_COMBO_BOX (combo_box));
-
- gtk_widget_hide (combo_box->priv->toplevel);
- gtk_widget_hide (combo_box->priv->popup);
- if (combo_box->priv->torn_off) {
- GTK_TEAROFF_MENU_ITEM (combo_box->priv->tearable)->torn_off
- = FALSE;
- gtk_combo_set_tearoff_state (combo_box, FALSE);
- }
-
- gtk_grab_remove (combo_box->priv->toplevel);
- gdk_pointer_ungrab (GDK_CURRENT_TIME);
-
- g_object_ref (combo_box->priv->pop_down_widget);
- g_signal_emit (combo_box,
- gal_combo_box_signals [POP_DOWN_DONE], 0,
- combo_box->priv->pop_down_widget, &popup_info_destroyed);
-
- if (popup_info_destroyed){
- gtk_container_remove (
- GTK_CONTAINER (combo_box->priv->frame),
- combo_box->priv->pop_down_widget);
- combo_box->priv->pop_down_widget = NULL;
- }
- g_object_unref (combo_box->priv->pop_down_widget);
- deactivate_arrow (combo_box);
-
- g_signal_emit (combo_box, gal_combo_box_signals [POST_POP_HIDE], 0);
-}
-
-/**
- * gal_combo_box_popup_hide:
- * @combo_box: Combo box
- *
- * Hide popup, but not when it is torn off.
- * This is the external interface - for subclasses and apps which expect a
- * regular combo which doesn't do tearoffs.
- */
-void
-gal_combo_box_popup_hide (GalComboBox *combo_box)
-{
- if (!combo_box->priv->torn_off)
- gal_combo_box_popup_hide_unconditional (combo_box);
- else if (GTK_WIDGET_VISIBLE (combo_box->priv->toplevel)) {
- /* Both popup and tearoff window present. Get rid of just
- the popup shell. */
- gtk_combo_popup_tear_off (combo_box, FALSE);
- deactivate_arrow (combo_box);
- }
-}
-
-/*
- * Find best location for displaying
- */
-void
-gal_combo_box_get_pos (GalComboBox *combo_box, int *x, int *y)
-{
- GtkWidget *wcombo = GTK_WIDGET (combo_box);
- int ph, pw;
-
- gdk_window_get_origin (wcombo->window, x, y);
- *y += wcombo->allocation.height + wcombo->allocation.y;
- *x += wcombo->allocation.x;
-
- ph = combo_box->priv->popup->allocation.height;
- pw = combo_box->priv->popup->allocation.width;
-
- if ((*y + ph) > gdk_screen_height ())
- *y = gdk_screen_height () - ph;
-
- if ((*x + pw) > gdk_screen_width ())
- *x = gdk_screen_width () - pw;
-}
-
-static void
-gal_combo_box_popup_display (GalComboBox *combo_box)
-{
- int x, y;
-
- g_return_if_fail (combo_box != NULL);
- g_return_if_fail (GAL_IS_COMBO_BOX (combo_box));
-
- /*
- * If we have no widget to display on the popdown,
- * create it
- */
- if (!combo_box->priv->pop_down_widget){
- GtkWidget *pw = NULL;
-
- g_signal_emit (combo_box,
- gal_combo_box_signals [POP_DOWN_WIDGET], 0, &pw);
- g_assert (pw != NULL);
- combo_box->priv->pop_down_widget = pw;
- gtk_container_add (GTK_CONTAINER (combo_box->priv->frame), pw);
- }
-
- g_signal_emit (combo_box, gal_combo_box_signals [PRE_POP_DOWN], 0);
-
- if (combo_box->priv->torn_off) {
- /* To give the illusion that tearoff still displays the
- * popup, we copy the image in the popup window to the
- * background. Thus, it won't be blank after reparenting */
- gtk_combo_tearoff_bg_copy (combo_box);
-
- /* We force an unrealize here so that we don't trigger
- * redrawing/ clearing code - we just want to reveal our
- * backing pixmap.
- */
- gtk_combo_popup_reparent (combo_box->priv->popup,
- combo_box->priv->toplevel, TRUE);
- }
-
- gal_combo_box_get_pos (combo_box, &x, &y);
-
- gtk_widget_set_uposition (combo_box->priv->toplevel, x, y);
- gtk_widget_realize (combo_box->priv->popup);
- gtk_widget_show (combo_box->priv->popup);
- gtk_widget_realize (combo_box->priv->toplevel);
- gtk_widget_show (combo_box->priv->toplevel);
-
- gtk_grab_add (combo_box->priv->toplevel);
- gdk_pointer_grab (combo_box->priv->toplevel->window, TRUE,
- GDK_BUTTON_PRESS_MASK |
- GDK_BUTTON_RELEASE_MASK |
- GDK_POINTER_MOTION_MASK,
- NULL, NULL, GDK_CURRENT_TIME);
-}
-
-static int
-gtk_combo_toggle_pressed (GtkToggleButton *tbutton, GalComboBox *combo_box)
-{
- if (tbutton->active)
- gal_combo_box_popup_display (combo_box);
- else
- gal_combo_box_popup_hide_unconditional (combo_box);
-
- return TRUE;
-}
-
-static gint
-gal_combo_box_button_press (GtkWidget *widget, GdkEventButton *event, GalComboBox *combo_box)
-{
- GtkWidget *child;
-
- child = gtk_get_event_widget ((GdkEvent *) event);
- if (child != widget){
- while (child){
- if (child == widget)
- return FALSE;
- child = child->parent;
- }
- }
-
- gal_combo_box_popup_hide (combo_box);
- return TRUE;
-}
-
-/**
- * gal_combo_box_key_press
- * @widget: Widget
- * @event: Event
- * @combo_box: Combo box
- *
- * Key press handler which dismisses popup on escape.
- * Popup is dismissed whether or not popup is torn off.
- */
-static gint
-gal_combo_box_key_press (GtkWidget *widget, GdkEventKey *event,
- GalComboBox *combo_box)
-{
- if (event->keyval == GDK_Escape) {
- gal_combo_box_popup_hide_unconditional (combo_box);
- return TRUE;
- } else
- return FALSE;
-}
-
-static void
-cb_state_change (GtkWidget *widget, GtkStateType old_state, GalComboBox *combo_box)
-{
- GtkStateType const new_state = GTK_WIDGET_STATE(widget);
- gtk_widget_set_state (combo_box->priv->display_widget, new_state);
-}
-
-static void
-gal_combo_box_init (GalComboBox *combo_box)
-{
- GtkWidget *arrow;
- GdkCursor *cursor;
-
- combo_box->priv = g_new0 (GalComboBoxPrivate, 1);
-
- /*
- * Create the arrow
- */
- combo_box->priv->arrow_button = gtk_toggle_button_new ();
- gtk_button_set_relief (GTK_BUTTON (combo_box->priv->arrow_button), GTK_RELIEF_NONE);
- GTK_WIDGET_UNSET_FLAGS (combo_box->priv->arrow_button, GTK_CAN_FOCUS);
-
- arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
- gtk_container_add (GTK_CONTAINER (combo_box->priv->arrow_button), arrow);
- gtk_box_pack_end (GTK_BOX (combo_box), combo_box->priv->arrow_button, FALSE, FALSE, 0);
- g_signal_connect (combo_box->priv->arrow_button, "toggled",
- G_CALLBACK (gtk_combo_toggle_pressed), combo_box);
- gtk_widget_show_all (combo_box->priv->arrow_button);
-
- /*
- * prelight the display widget when mousing over the arrow.
- */
- g_signal_connect (combo_box->priv->arrow_button, "state-changed",
- G_CALLBACK (cb_state_change), combo_box);
-
- /*
- * The pop-down container
- */
-
- combo_box->priv->toplevel = gtk_window_new (GTK_WINDOW_POPUP);
- gtk_widget_ref (combo_box->priv->toplevel);
- gtk_object_sink (GTK_OBJECT (combo_box->priv->toplevel));
- gtk_window_set_policy (GTK_WINDOW (combo_box->priv->toplevel),
- FALSE, TRUE, FALSE);
-
- combo_box->priv->popup = gtk_event_box_new ();
- gtk_container_add (GTK_CONTAINER (combo_box->priv->toplevel),
- combo_box->priv->popup);
- gtk_widget_show (combo_box->priv->popup);
-
- gtk_widget_realize (combo_box->priv->popup);
- cursor = gdk_cursor_new (GDK_TOP_LEFT_ARROW);
- gdk_window_set_cursor (combo_box->priv->popup->window, cursor);
- gdk_cursor_destroy (cursor);
-
- combo_box->priv->torn_off = FALSE;
- combo_box->priv->tearoff_window = NULL;
-
- combo_box->priv->frame = gtk_frame_new (NULL);
- gtk_container_add (GTK_CONTAINER (combo_box->priv->popup),
- combo_box->priv->frame);
- gtk_frame_set_shadow_type (GTK_FRAME (combo_box->priv->frame), GTK_SHADOW_OUT);
-
- g_signal_connect (combo_box->priv->toplevel, "button_press_event",
- G_CALLBACK (gal_combo_box_button_press), combo_box);
- g_signal_connect (combo_box->priv->toplevel, "key_press_event",
- G_CALLBACK (gal_combo_box_key_press), combo_box);
-}
-
-E_MAKE_TYPE (gal_combo_box,
- "MyGalComboBox",
- GalComboBox,
- gal_combo_box_class_init,
- gal_combo_box_init,
- PARENT_TYPE)
-
-/**
- * gal_combo_box_set_display:
- * @combo_box: the Combo Box to modify
- * @display_widget: The widget to be displayed
-
- * Sets the displayed widget for the @combo_box to be @display_widget
- */
-void
-gal_combo_box_set_display (GalComboBox *combo_box, GtkWidget *display_widget)
-{
- g_return_if_fail (combo_box != NULL);
- g_return_if_fail (GAL_IS_COMBO_BOX (combo_box));
- g_return_if_fail (display_widget != NULL);
- g_return_if_fail (GTK_IS_WIDGET (display_widget));
-
- if (combo_box->priv->display_widget &&
- combo_box->priv->display_widget != display_widget)
- gtk_container_remove (GTK_CONTAINER (combo_box),
- combo_box->priv->display_widget);
-
- combo_box->priv->display_widget = display_widget;
-
- gtk_box_pack_start (GTK_BOX (combo_box), display_widget, TRUE, TRUE, 0);
-}
-
-static gboolean
-cb_tearable_enter_leave (GtkWidget *w, GdkEventCrossing *event, gpointer data)
-{
- gboolean const flag = GPOINTER_TO_INT(data);
- gtk_widget_set_state (w, flag ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL);
- return FALSE;
-}
-
-/**
- * gtk_combo_popup_tear_off
- * @combo: Combo box
- * @set_position: Set to position of popup shell if true
- *
- * Tear off the popup
- *
- * FIXME:
- * Gtk popup menus are toplevel windows, not dialogs. I think this is wrong,
- * and make the popups dialogs. But may be there should be a way to make
- * them toplevel. We can do this after creating:
- * GTK_WINDOW (tearoff)->type = GTK_WINDOW_TOPLEVEL;
- */
-static void
-gtk_combo_popup_tear_off (GalComboBox *combo, gboolean set_position)
-{
- int x, y;
-
- if (!combo->priv->tearoff_window) {
- GtkWidget *tearoff;
- gchar *title;
-
- /* FIXME: made this a toplevel, not a dialog ! */
- tearoff = gtk_window_new (GTK_WINDOW_TOPLEVEL);
- gtk_widget_ref (tearoff);
- gtk_object_sink (GTK_OBJECT (tearoff));
- combo->priv->tearoff_window = tearoff;
- gtk_widget_set_app_paintable (tearoff, TRUE);
- g_signal_connect (tearoff, "key_press_event",
- G_CALLBACK (gal_combo_box_key_press),
- combo);
- gtk_widget_realize (tearoff);
- title = g_object_get_data (G_OBJECT (combo),
- "gtk-combo-title");
- if (title)
- gdk_window_set_title (tearoff->window, title);
- gtk_window_set_policy (GTK_WINDOW (tearoff),
- FALSE, TRUE, FALSE);
- gtk_window_set_transient_for
- (GTK_WINDOW (tearoff),
- GTK_WINDOW (gtk_widget_get_toplevel
- GTK_WIDGET (combo)));
- }
-
- if (GTK_WIDGET_VISIBLE (combo->priv->popup)) {
- gtk_widget_hide (combo->priv->toplevel);
-
- gtk_grab_remove (combo->priv->toplevel);
- gdk_pointer_ungrab (GDK_CURRENT_TIME);
- }
-
- gtk_combo_popup_reparent (combo->priv->popup,
- combo->priv->tearoff_window, FALSE);
-
- /* It may have got confused about size */
- gtk_widget_queue_resize (GTK_WIDGET (combo->priv->popup));
-
- if (set_position) {
- gal_combo_box_get_pos (combo, &x, &y);
- gtk_widget_set_uposition (combo->priv->tearoff_window, x, y);
- }
- gtk_widget_show (GTK_WIDGET (combo->priv->popup));
- gtk_widget_show (combo->priv->tearoff_window);
-
-}
-
-/**
- * gtk_combo_set_tearoff_state
- * @combo_box: Combo box
- * @torn_off: TRUE: Tear off. FALSE: Pop down and reattach
- *
- * Set the tearoff state of the popup
- *
- * Compare with gtk_menu_set_tearoff_state in gtk/gtkmenu.c
- */
-static void
-gtk_combo_set_tearoff_state (GalComboBox *combo,
- gboolean torn_off)
-{
- g_return_if_fail (combo != NULL);
- g_return_if_fail (GAL_IS_COMBO_BOX (combo));
-
- if (combo->priv->torn_off != torn_off) {
- combo->priv->torn_off = torn_off;
-
- if (combo->priv->torn_off) {
- gtk_combo_popup_tear_off (combo, TRUE);
- deactivate_arrow (combo);
- } else {
- gtk_widget_hide (combo->priv->tearoff_window);
- gtk_combo_popup_reparent (combo->priv->popup,
- combo->priv->toplevel,
- FALSE);
- }
- }
-}
-
-/**
- * gtk_combo_tearoff_bg_copy
- * @combo_box: Combo box
- *
- * Copy popup window image to the tearoff window.
- */
-static void
-gtk_combo_tearoff_bg_copy (GalComboBox *combo)
-{
- GdkPixmap *pixmap;
- GdkGC *gc;
- GdkGCValues gc_values;
-
- GtkWidget *widget = combo->priv->popup;
-
- if (combo->priv->torn_off) {
- gc_values.subwindow_mode = GDK_INCLUDE_INFERIORS;
- gc = gdk_gc_new_with_values (widget->window,
- &gc_values, GDK_GC_SUBWINDOW);
-
- pixmap = gdk_pixmap_new (widget->window,
- widget->allocation.width,
- widget->allocation.height,
- -1);
-
- gdk_draw_pixmap (pixmap, gc,
- widget->window,
- 0, 0, 0, 0, -1, -1);
- gdk_gc_unref (gc);
-
- gtk_widget_set_usize (combo->priv->tearoff_window,
- widget->allocation.width,
- widget->allocation.height);
-
- gdk_window_set_back_pixmap
- (combo->priv->tearoff_window->window, pixmap, FALSE);
- gdk_pixmap_unref (pixmap);
- }
-}
-
-/**
- * gtk_combo_popup_reparent
- * @popup: Popup
- * @new_parent: New parent
- * @unrealize: Unrealize popup if TRUE.
- *
- * Reparent the popup, taking care of the refcounting
- *
- * Compare with gtk_menu_reparent in gtk/gtkmenu.c
- */
-static void
-gtk_combo_popup_reparent (GtkWidget *popup,
- GtkWidget *new_parent,
- gboolean unrealize)
-{
- GtkObject *object = GTK_OBJECT (popup);
- gboolean was_floating = GTK_OBJECT_FLOATING (object);
-
- g_object_ref (object);
- gtk_object_sink (object);
-
- if (unrealize) {
- g_object_ref (object);
- gtk_container_remove (GTK_CONTAINER (popup->parent), popup);
- gtk_container_add (GTK_CONTAINER (new_parent), popup);
- g_object_unref (object);
- }
- else
- gtk_widget_reparent (GTK_WIDGET (popup), new_parent);
- gtk_widget_set_usize (new_parent, -1, -1);
-
- if (was_floating)
- GTK_OBJECT_SET_FLAGS (object, GTK_FLOATING);
- else
- g_object_unref (object);
-}
-
-/**
- * cb_tearable_button_release
- * @w: Widget
- * @event: Event
- * @combo: Combo box
- *
- * Toggle tearoff state.
- */
-static gboolean
-cb_tearable_button_release (GtkWidget *w, GdkEventButton *event,
- GalComboBox *combo)
-{
- GtkTearoffMenuItem *tearable;
-
- g_return_val_if_fail (w != NULL, FALSE);
- g_return_val_if_fail (GTK_IS_TEAROFF_MENU_ITEM (w), FALSE);
-
- tearable = GTK_TEAROFF_MENU_ITEM (w);
- tearable->torn_off = !tearable->torn_off;
-
- if (!combo->priv->torn_off) {
- gboolean need_connect;
-
- need_connect = (!combo->priv->tearoff_window);
- gtk_combo_set_tearoff_state (combo, TRUE);
- if (need_connect)
- g_signal_connect (combo->priv->tearoff_window,
- "delete_event",
- G_CALLBACK (cb_popup_delete),
- combo);
- } else
- gal_combo_box_popup_hide_unconditional (combo);
-
- return TRUE;
-}
-
-static gboolean
-cb_popup_delete (GtkWidget *w, GdkEventAny *event, GalComboBox *combo)
-{
- gal_combo_box_popup_hide_unconditional (combo);
- return TRUE;
-}
-
-void
-gal_combo_box_construct (GalComboBox *combo_box, GtkWidget *display_widget, GtkWidget *pop_down_widget)
-{
- GtkWidget *tearable;
- GtkWidget *vbox;
-
- g_return_if_fail (combo_box != NULL);
- g_return_if_fail (GAL_IS_COMBO_BOX (combo_box));
- g_return_if_fail (display_widget != NULL);
- g_return_if_fail (GTK_IS_WIDGET (display_widget));
-
- GTK_BOX (combo_box)->spacing = 0;
- GTK_BOX (combo_box)->homogeneous = FALSE;
-
- combo_box->priv->pop_down_widget = pop_down_widget;
- combo_box->priv->display_widget = NULL;
-
- vbox = gtk_vbox_new (FALSE, 5);
- tearable = gtk_tearoff_menu_item_new ();
- g_signal_connect (tearable, "enter-notify-event",
- G_CALLBACK (cb_tearable_enter_leave),
- GINT_TO_POINTER (TRUE));
- g_signal_connect (tearable, "leave-notify-event",
- G_CALLBACK (cb_tearable_enter_leave),
- GINT_TO_POINTER (FALSE));
- g_signal_connect (tearable, "button-release-event",
- G_CALLBACK (cb_tearable_button_release),
- (gpointer) combo_box);
- gtk_box_pack_start (GTK_BOX (vbox), tearable, FALSE, FALSE, 0);
- gtk_box_pack_start (GTK_BOX (vbox), pop_down_widget, TRUE, TRUE, 0);
- combo_box->priv->tearable = tearable;
-
- /*
- * Finish setup
- */
- gal_combo_box_set_display (combo_box, display_widget);
-
- gtk_container_add (GTK_CONTAINER (combo_box->priv->frame), vbox);
- gtk_widget_show_all (combo_box->priv->frame);
-}
-
-GtkWidget *
-gal_combo_box_new (GtkWidget *display_widget, GtkWidget *optional_popdown)
-{
- GalComboBox *combo_box;
-
- g_return_val_if_fail (display_widget != NULL, NULL);
- g_return_val_if_fail (GTK_IS_WIDGET (display_widget), NULL);
-
- combo_box = g_object_new (GAL_COMBO_BOX_TYPE, NULL);
- gal_combo_box_construct (combo_box, display_widget, optional_popdown);
- return GTK_WIDGET (combo_box);
-}
-
-void
-gal_combo_box_set_arrow_relief (GalComboBox *cc, GtkReliefStyle relief)
-{
- g_return_if_fail (cc != NULL);
- g_return_if_fail (GAL_IS_COMBO_BOX (cc));
-
- gtk_button_set_relief (GTK_BUTTON (cc->priv->arrow_button), relief);
-}
-
-/**
- * gal_combo_box_set_title
- * @combo: Combo box
- * @title: Title
- *
- * Set a title to display over the tearoff window.
- *
- * FIXME:
- *
- * This should really change the title even when the popup is already torn off.
- * I guess the tearoff window could attach a listener to title change or
- * something. But I don't think we need the functionality, so I didn't bother
- * to investigate.
- */
-void
-gal_combo_box_set_title (GalComboBox *combo,
- const gchar *title)
-{
- g_return_if_fail (combo != NULL);
- g_return_if_fail (GAL_IS_COMBO_BOX (combo));
-
- g_object_set_data_full (G_OBJECT (combo), "gtk-combo-title",
- g_strdup (title), (GDestroyNotify) g_free);
-}
-
-/**
- * gal_combo_box_set_arrow_sensitive
- * @combo: Combo box
- * @sensitive: Sensitivity value
- *
- * Toggle the sensitivity of the arrow button
- */
-
-void
-gal_combo_box_set_arrow_sensitive (GalComboBox *combo,
- gboolean sensitive)
-{
- g_return_if_fail (combo != NULL);
-
- gtk_widget_set_sensitive (combo->priv->arrow_button, sensitive);
-}
-
-/**
- * gal_combo_box_set_tearable:
- * @combo: Combo box
- * @tearable: whether to allow the @combo to be tearable
- *
- * controls whether the combo box's pop up widget can be torn off.
- */
-void
-gal_combo_box_set_tearable (GalComboBox *combo, gboolean tearable)
-{
- g_return_if_fail (combo != NULL);
- g_return_if_fail (GAL_IS_COMBO_BOX (combo));
-
- if (tearable){
- gtk_widget_show (combo->priv->tearable);
- } else {
- gtk_combo_set_tearoff_state (combo, FALSE);
- gtk_widget_hide (combo->priv->tearable);
- }
-}
diff --git a/widgets/misc/gal-combo-box.h b/widgets/misc/gal-combo-box.h
deleted file mode 100644
index 0a05c52d84..0000000000
--- a/widgets/misc/gal-combo-box.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * gtk-combo-box.h - a customizable combobox
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Miguel de Icaza <miguel@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _GAL_COMBO_BOX_H_
-#define _GAL_COMBO_BOX_H_
-
-#include <gtk/gtkhbox.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-#define GAL_COMBO_BOX_TYPE (gal_combo_box_get_type())
-#define GAL_COMBO_BOX(obj) G_TYPE_CHECK_INSTANCE_CAST (obj, gal_combo_box_get_type (), GalComboBox)
-#define GAL_COMBO_BOX_CLASS(klass) G_TYPE_CHECK_CLASS_CAST (klass, gal_combo_box_get_type (), GalComboBoxClass)
-#define GAL_IS_COMBO_BOX(obj) G_TYPE_CHECK_INSTANCE_TYPE (obj, gal_combo_box_get_type ())
-
-typedef struct _GalComboBox GalComboBox;
-typedef struct _GalComboBoxPrivate GalComboBoxPrivate;
-typedef struct _GalComboBoxClass GalComboBoxClass;
-
-struct _GalComboBox {
- GtkHBox hbox;
- GalComboBoxPrivate *priv;
-};
-
-struct _GalComboBoxClass {
- GtkHBoxClass parent_class;
-
- GtkWidget *(*pop_down_widget) (GalComboBox *cbox);
-
- /*
- * invoked when the popup has been hidden, if the signal
- * returns TRUE, it means it should be killed from the
- */
- gboolean *(*pop_down_done) (GalComboBox *cbox, GtkWidget *);
-
- /*
- * Notification signals.
- */
- void (*pre_pop_down) (GalComboBox *cbox);
- void (*post_pop_hide) (GalComboBox *cbox);
-};
-
-GtkType gal_combo_box_get_type (void);
-void gal_combo_box_construct (GalComboBox *combo_box,
- GtkWidget *display_widget,
- GtkWidget *optional_pop_down_widget);
-void gal_combo_box_get_pos (GalComboBox *combo_box, int *x, int *y);
-
-GtkWidget *gal_combo_box_new (GtkWidget *display_widget,
- GtkWidget *optional_pop_down_widget);
-void gal_combo_box_popup_hide (GalComboBox *combo_box);
-
-void gal_combo_box_set_display (GalComboBox *combo_box,
- GtkWidget *display_widget);
-
-void gal_combo_box_set_title (GalComboBox *combo,
- const gchar *title);
-
-void gal_combo_box_set_tearable (GalComboBox *combo,
- gboolean tearable);
-void gal_combo_box_set_arrow_sensitive (GalComboBox *combo,
- gboolean sensitive);
-void gal_combo_box_set_arrow_relief (GalComboBox *cc,
- GtkReliefStyle relief);
-#ifdef __cplusplus
-};
-#endif /* __cplusplus */
-
-#endif /* _GAL_COMBO_BOX_H_ */
diff --git a/widgets/misc/gal-combo-text.c b/widgets/misc/gal-combo-text.c
deleted file mode 100644
index ba3b4ad7c5..0000000000
--- a/widgets/misc/gal-combo-text.c
+++ /dev/null
@@ -1,433 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * gtk-combo-text.c - A combo box for selecting from a list.
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <ctype.h>
-#include <gal/util/e-util.h>
-#include <gtk/gtksignal.h>
-#include <gtk/gtkentry.h>
-#include <gtk/gtklist.h>
-#include <gtk/gtkscrolledwindow.h>
-#include "gal-combo-text.h"
-
-#define PARENT_TYPE GAL_COMBO_BOX_TYPE
-static GtkObjectClass *gal_combo_text_parent_class;
-
-static gboolean cb_pop_down (GtkWidget *w, GtkWidget *pop_down,
- gpointer dummy);
-
-static void list_unselect_cb (GtkWidget *list, GtkWidget *child,
- gpointer data);
-
-static void update_list_selection (GalComboText *ct, const gchar *text);
-
-static void
-gal_combo_text_destroy (GtkObject *object)
-{
- GalComboText *ct = GAL_COMBO_TEXT (object);
-
- if (ct->elements != NULL) {
- g_hash_table_destroy (ct->elements);
- ct->elements = NULL;
- }
- if (ct->list != NULL) {
- g_signal_handlers_disconnect_matched (ct,
- G_SIGNAL_MATCH_FUNC,
- 0, 0, NULL,
- cb_pop_down, NULL);
-
- g_signal_handlers_disconnect_matched (ct->list,
- G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA,
- 0, 0, NULL,
- list_unselect_cb, ct);
- ct->list = NULL;
- }
-
- (*gal_combo_text_parent_class->destroy) (object);
-}
-
-static void
-gal_combo_text_class_init (GtkObjectClass *object_class)
-{
- object_class->destroy = &gal_combo_text_destroy;
- gal_combo_text_parent_class = g_type_class_ref (PARENT_TYPE);
-}
-
-static void
-gal_combo_text_init (GalComboText *object)
-{
-}
-
-E_MAKE_TYPE (gal_combo_text,
- "GalComboText",
- GalComboText,
- gal_combo_text_class_init,
- gal_combo_text_init,
- PARENT_TYPE)
-
-static gint
-strcase_equal (gconstpointer v, gconstpointer v2)
-{
- return g_strcasecmp ((const gchar*) v, (const gchar*)v2) == 0;
-}
-
-
-/*
- * a char* hash function from ASU
- *
- * This is cut/paste from gutils.c
- * We've got to do this, because this widget will soon move out of the
- * Gnumeric source and into a separate library.
- */
-static guint
-strcase_hash (gconstpointer v)
-{
- const unsigned char *s = (const unsigned char *)v;
- const unsigned char *p;
- guint h = 0, g;
-
- for(p = s; *p != '\0'; p += 1) {
- h = ( h << 4 ) + tolower (*p);
- if ( ( g = h & 0xf0000000 ) ) {
- h = h ^ (g >> 24);
- h = h ^ g;
- }
- }
-
- return h /* % M */;
-}
-
-/**
- * gal_combo_text_set_case_sensitive
- * @combo_text: ComboText widget
- * @val: make case sensitive if TRUE
- *
- * Specifies whether the text entered into the GtkEntry field and the text
- * in the list items is case sensitive. Because the values are stored in a
- * hash, it is not legal to change case sensitivity when the list contains
- * elements.
- *
- * Returns: The function returns -1 if request could not be honored. On
- * success, it returns 0.
- */
-gint
-gal_combo_text_set_case_sensitive (GalComboText *combo, gboolean val)
-{
- if (combo->elements
- && g_hash_table_size (combo->elements) > 0
- && val != combo->case_sensitive)
- return -1;
- else {
- combo->case_sensitive = val;
- if (val != combo->case_sensitive) {
- GHashFunc hashfunc;
- GCompareFunc comparefunc;
-
- g_hash_table_destroy (combo->elements);
- if (combo->case_sensitive) {
- hashfunc = g_str_hash;
- comparefunc = g_str_equal;
- } else {
- hashfunc = strcase_hash;
- comparefunc = strcase_equal;
- }
- combo->elements = g_hash_table_new (hashfunc,
- comparefunc);
- }
- return 0;
- }
-}
-
-static void
-entry_activate_cb (GtkWidget *entry, gpointer data)
-{
- GalComboText *combo = GAL_COMBO_TEXT (data);
-
- update_list_selection (combo,
- gtk_entry_get_text (GTK_ENTRY (combo->entry)));
-}
-
-
-static void
-list_select_cb (GtkWidget *list, GtkWidget *child, gpointer data)
-{
- GalComboText *combo = GAL_COMBO_TEXT (data);
- GtkEntry *entry = GTK_ENTRY (combo->entry);
- gchar *value = (gchar*) g_object_get_data (G_OBJECT (child), "value");
-
- g_return_if_fail (entry && value);
-
- if (combo->cached_entry == child)
- combo->cached_entry = NULL;
-
- gtk_entry_set_text (entry, value);
- gtk_signal_handler_block_by_func (GTK_OBJECT (entry),
- GTK_SIGNAL_FUNC (entry_activate_cb),
- (gpointer) combo);
- g_signal_emit_by_name (entry, "activate");
- gtk_signal_handler_unblock_by_func (GTK_OBJECT (entry),
- GTK_SIGNAL_FUNC (entry_activate_cb),
- (gpointer) combo);
-
- gal_combo_box_popup_hide (GAL_COMBO_BOX (data));
-}
-
-static void
-list_unselect_cb (GtkWidget *list, GtkWidget *child, gpointer data)
-{
- if (GTK_WIDGET_VISIBLE (list)) /* Undo interactive unselect */
- gtk_list_select_child (GTK_LIST (list), child);
-}
-
-static void
-cb_toggle (GtkWidget *child, gpointer data)
-{
- GalComboText *ct = GAL_COMBO_TEXT (data);
-
- gtk_list_select_child (GTK_LIST (ct->list), child);
-}
-
-void
-gal_combo_text_select_item (GalComboText *ct, int elem)
-{
- gtk_list_select_item (GTK_LIST(ct->list), elem);
-}
-
-static void
-update_list_selection (GalComboText *ct, const gchar *text)
-{
- gpointer candidate;
- GtkWidget *child;
-
- gtk_signal_handler_block_by_func (GTK_OBJECT (ct->list),
- GTK_SIGNAL_FUNC (list_select_cb),
- (gpointer) ct);
- gtk_signal_handler_block_by_func (GTK_OBJECT (ct->list),
- GTK_SIGNAL_FUNC (list_unselect_cb),
- (gpointer) ct);
-
- gtk_list_unselect_all (GTK_LIST (ct->list));
- candidate = g_hash_table_lookup (ct->elements, (gconstpointer) text);
- if (candidate && GTK_IS_WIDGET (candidate)) {
- child = GTK_WIDGET (candidate);
- gtk_list_select_child (GTK_LIST (ct->list), child);
- gtk_widget_grab_focus (child);
- }
- gtk_signal_handler_unblock_by_func (GTK_OBJECT (ct->list),
- GTK_SIGNAL_FUNC (list_select_cb),
- (gpointer) ct);
- gtk_signal_handler_unblock_by_func (GTK_OBJECT (ct->list),
- GTK_SIGNAL_FUNC (list_unselect_cb),
- (gpointer) ct);
-}
-
-void
-gal_combo_text_set_text (GalComboText *ct, const gchar *text)
-{
- gtk_entry_set_text (GTK_ENTRY (ct->entry), text);
- update_list_selection (ct, text);
-}
-
-/*
- * We can't just cache the old widget state on entry: If the pointer is
- * dragged, we receive two enter-notify-events, and the original cached
- * value would be overwritten with the GTK_STATE_ACTIVE we just set.
- *
- * However, we know that the gtklist only uses GTK_STATE_SELECTED and
- * GTK_STATE_NORMAL. We're OK if we only cache those two.
- */
-static gboolean
-cb_enter (GtkWidget *w, GdkEventCrossing *event,
- gpointer user)
-{
- GalComboText *ct = user;
- GtkStateType state = GTK_WIDGET_STATE (w);
-
- if (state == GTK_STATE_NORMAL || state == GTK_STATE_SELECTED) {
- ct->cached_entry = w;
- ct->cache_mouse_state = state;
- }
- if (state != GTK_STATE_SELECTED)
- gtk_widget_set_state (w, GTK_STATE_ACTIVE);
-
- return TRUE;
-}
-static gboolean
-cb_exit (GtkWidget *w, GdkEventCrossing *event,
- gpointer user)
-{
- GalComboText *ct = user;
-
- if (ct->cached_entry == w)
- gtk_widget_set_state (w, ct->cache_mouse_state);
-
- return TRUE;
-}
-
-static gboolean
-cb_pop_down (GtkWidget *w, GtkWidget *pop_down, gpointer dummy)
-{
- GalComboText *ct = GAL_COMBO_TEXT (w);
-
- if (ct->cached_entry)
- gtk_widget_set_state (ct->cached_entry, ct->cache_mouse_state);
- ct->cached_entry = NULL;
-
- return FALSE;
-}
-
-typedef struct {
- GalComboText *ct;
- gchar *value;
-} WeakRefClosure;
-
-static void
-cb_remove_from_hash (gpointer data, GObject *where_object_was)
-{
- WeakRefClosure *closure = data;
-
- if (closure->ct->elements)
- g_hash_table_remove (closure->ct->elements, closure->value);
-
- g_free (closure->value);
- g_free (closure);
-}
-
-void
-gal_combo_text_add_item (GalComboText *ct,
- const gchar *item,
- const gchar *value)
-{
- WeakRefClosure *weak_ref_closure;
- GtkWidget *listitem;
- gchar *value_copy;
-
- g_return_if_fail (item);
-
- if (!value)
- value = item;
-
- value_copy = g_strdup (value);
-
- listitem = gtk_list_item_new_with_label (item);
- gtk_widget_show (listitem);
-
- g_object_set_data_full (G_OBJECT (listitem), "value",
- value_copy, g_free);
- g_signal_connect (listitem, "enter-notify-event",
- G_CALLBACK (cb_enter),
- (gpointer) ct);
- g_signal_connect (listitem, "leave-notify-event",
- G_CALLBACK (cb_exit),
- (gpointer) ct);
- g_signal_connect (listitem, "toggle",
- G_CALLBACK (cb_toggle),
- (gpointer) ct);
-
- gtk_container_add (GTK_CONTAINER (ct->list),
- listitem);
-
- g_hash_table_insert (ct->elements, (gpointer)value_copy,
- (gpointer) listitem);
-
- weak_ref_closure = g_new (WeakRefClosure, 1);
- weak_ref_closure->ct = ct;
- weak_ref_closure->value = g_strdup (value_copy);
-
- g_object_weak_ref (G_OBJECT (listitem),
- cb_remove_from_hash,
- weak_ref_closure);
-}
-
-static void
-cb_list_mapped (GtkWidget *widget, gpointer user_data)
-{
- GtkList *list = GTK_LIST (widget);
-
- if (g_list_length (list->selection) > 0)
- gtk_widget_grab_focus (GTK_WIDGET ((list->selection->data)));
-}
-
-void
-gal_combo_text_construct (GalComboText *ct, gboolean const is_scrolled)
-{
- GtkWidget *entry, *list, *scroll, *display_widget;
-
- ct->case_sensitive = FALSE;
- ct->elements = g_hash_table_new (&strcase_hash,
- &strcase_equal);
-
- /* Probably irrelevant, but lets be careful */
- ct->cache_mouse_state = GTK_STATE_NORMAL;
- ct->cached_entry = NULL;
-
- entry = ct->entry = gtk_entry_new ();
- list = ct->list = gtk_list_new ();
- if (is_scrolled) {
- display_widget = scroll = gtk_scrolled_window_new (NULL, NULL);
- gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(scroll),
- GTK_POLICY_NEVER,
- GTK_POLICY_AUTOMATIC);
-
- gtk_scrolled_window_add_with_viewport (
- GTK_SCROLLED_WINDOW(scroll), list);
- gtk_container_set_focus_hadjustment (
- GTK_CONTAINER (list),
- gtk_scrolled_window_get_hadjustment (
- GTK_SCROLLED_WINDOW (scroll)));
- gtk_container_set_focus_vadjustment (
- GTK_CONTAINER (list),
- gtk_scrolled_window_get_vadjustment (
- GTK_SCROLLED_WINDOW (scroll)));
- gtk_widget_set_usize (scroll, 0, 200); /* MAGIC NUMBER */
- } else
- display_widget = list;
-
- g_signal_connect (entry, "activate",
- G_CALLBACK (entry_activate_cb),
- ct);
- g_signal_connect (list, "select-child",
- G_CALLBACK (list_select_cb),
- ct);
- g_signal_connect (list, "unselect-child",
- G_CALLBACK (list_unselect_cb),
- ct);
- g_signal_connect (list, "map",
- G_CALLBACK (cb_list_mapped), NULL);
-
- gtk_widget_show (display_widget);
- gtk_widget_show (entry);
- gal_combo_box_construct (GAL_COMBO_BOX (ct), entry, display_widget);
- g_signal_connect (ct, "pop_down_done",
- G_CALLBACK (cb_pop_down), NULL);
-}
-
-GtkWidget*
-gal_combo_text_new (gboolean const is_scrolled)
-{
- GalComboText *ct;
-
- ct = g_object_new (GAL_COMBO_TEXT_TYPE, NULL);
- gal_combo_text_construct (ct, is_scrolled);
- return GTK_WIDGET (ct);
-}
-
diff --git a/widgets/misc/gal-combo-text.h b/widgets/misc/gal-combo-text.h
deleted file mode 100644
index c507651dd1..0000000000
--- a/widgets/misc/gal-combo-text.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * gal-combo-text.h - A combo box for selecting from a list.
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _GAL_COMBO_TEXT_H
-#define _GAL_COMBO_TEXT_H
-
-#include <gal/widgets/gal-combo-box.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-#define GAL_COMBO_TEXT_TYPE (gal_combo_text_get_type ())
-#define GAL_COMBO_TEXT(obj) G_TYPE_CHECK_INSTANCE_CAST (obj, gal_combo_text_get_type (), GalComboText)
-#define GAL_COMBO_TEXT_CLASS(klass) G_TYPE_CHECK_CLASS_CAST (klass, gal_combo_text_get_type (), GalComboTextClass)
-#define GAL_IS_COMBO_TEXT(obj) G_TYPE_CHECK_INSTANCE_TYPE (obj, gal_combo_text_get_type ())
-
-typedef struct _GalComboText GalComboText;
-/* typedef struct _GalComboTextPrivate GalComboTextPrivate;*/
-typedef struct _GalComboTextClass GalComboTextClass;
-
-struct _GalComboText {
- GalComboBox parent;
-
- GtkWidget *entry;
- GtkWidget *list;
- GtkWidget *scrolled_window;
- GtkStateType cache_mouse_state;
- GtkWidget *cached_entry;
- gboolean case_sensitive;
- GHashTable*elements;
-};
-
-struct _GalComboTextClass {
- GalComboBoxClass parent_class;
-};
-
-
-GtkType gal_combo_text_get_type (void);
-GtkWidget *gal_combo_text_new (gboolean const is_scrolled);
-void gal_combo_text_construct (GalComboText *ct, gboolean const is_scrolled);
-
-gint gal_combo_text_set_case_sensitive (GalComboText *combo_text,
- gboolean val);
-void gal_combo_text_select_item (GalComboText *combo_text,
- int elem);
-void gal_combo_text_set_text (GalComboText *combo_text,
- const gchar *text);
-void gal_combo_text_add_item (GalComboText *combo_text,
- const gchar *item,
- const gchar *value);
-
-#ifdef __cplusplus
-};
-#endif /* __cplusplus */
-
-#endif
diff --git a/widgets/misc/pixmaps/.cvsignore b/widgets/misc/pixmaps/.cvsignore
deleted file mode 100644
index 3dda72986f..0000000000
--- a/widgets/misc/pixmaps/.cvsignore
+++ /dev/null
@@ -1,2 +0,0 @@
-Makefile.in
-Makefile
diff --git a/widgets/misc/pixmaps/cursor_cross.xpm b/widgets/misc/pixmaps/cursor_cross.xpm
deleted file mode 100644
index cf9d0aca33..0000000000
--- a/widgets/misc/pixmaps/cursor_cross.xpm
+++ /dev/null
@@ -1,38 +0,0 @@
-/* XPM */
-static char * cursor_cross_xpm[] = {
-"32 32 3 1",
-" c None",
-". c #000000",
-"+ c #FFFFFF",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ....... ",
-" .+++++.. ",
-" .+++++.. ",
-" .+++++.. ",
-" .+++++.. ",
-" ......+++++...... ",
-" .+++++++++++++++.. ",
-" .+++++++++++++++.. ",
-" .+++++++++++++++.. ",
-" .+++++++++++++++.. ",
-" .+++++++++++++++.. ",
-" ......+++++....... ",
-" .....+++++....... ",
-" .+++++.. ",
-" .+++++.. ",
-" .+++++.. ",
-" ........ ",
-" ....... ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" "};
diff --git a/widgets/misc/pixmaps/cursor_hand_closed.xpm b/widgets/misc/pixmaps/cursor_hand_closed.xpm
deleted file mode 100644
index 61a6de4b88..0000000000
--- a/widgets/misc/pixmaps/cursor_hand_closed.xpm
+++ /dev/null
@@ -1,38 +0,0 @@
-/* XPM */
-static char * cursor_hand_closed_xpm[] = {
-"32 32 3 1",
-" c None",
-". c #000000",
-"+ c #FFFFFF",
-" ",
-" ",
-" ",
-" ",
-" ",
-" .. ",
-" ..++... ",
-" .+++++++.. ",
-" .+++++++++. ",
-" ...+++++++++. ",
-" .++.+++++++++. ",
-" .++++++++++++. ",
-" .+++++++++++. ",
-" .++++++++++. ",
-" .+++++++++. ",
-" .+++++++. ",
-" .++++++. ",
-" .++++++. ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" "};
diff --git a/widgets/misc/pixmaps/cursor_hand_open.xpm b/widgets/misc/pixmaps/cursor_hand_open.xpm
deleted file mode 100644
index 048acc8054..0000000000
--- a/widgets/misc/pixmaps/cursor_hand_open.xpm
+++ /dev/null
@@ -1,38 +0,0 @@
-/* XPM */
-static char * cursor_hand_open_xpm[] = {
-"32 32 3 1",
-" c None",
-". c #000000",
-"+ c #FFFFFF",
-" ",
-" ",
-" .. ",
-" .. .++... ",
-" .++..++.++. ",
-" .++..++.++. . ",
-" .++.++.++..+. ",
-" .++.++.++.++. ",
-" .. .+++++++.++. ",
-" .++..++++++++++. ",
-" .+++.+++++++++. ",
-" .++++++++++++. ",
-" .+++++++++++. ",
-" .++++++++++. ",
-" .+++++++++. ",
-" .+++++++. ",
-" .++++++. ",
-" .++++++. ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" "};
diff --git a/widgets/misc/pixmaps/cursor_zoom_in.xpm b/widgets/misc/pixmaps/cursor_zoom_in.xpm
deleted file mode 100644
index 1caf9e3e2a..0000000000
--- a/widgets/misc/pixmaps/cursor_zoom_in.xpm
+++ /dev/null
@@ -1,37 +0,0 @@
-/* XPM */
-static char * cursor_zoom_in_xpm[] = {
-"32 32 2 1",
-" c None",
-". c #000000",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ...... ",
-" .. .. ",
-" .. .. ",
-" . . ",
-" . ... . ",
-" . ... . ",
-" . ....... . ",
-" . ....... . ",
-" . ... . ",
-" . ... .. ",
-" .. . . ",
-" .. . . . ",
-" ........ . . ",
-" ..... . . . ",
-" . . . ",
-" . . . ",
-" . . . ",
-" . . . ",
-" . . ",
-" . . ",
-" .. ",
-" ",
-" ",
-" ",
-" ",
-" "};
diff --git a/widgets/misc/pixmaps/cursor_zoom_out.xpm b/widgets/misc/pixmaps/cursor_zoom_out.xpm
deleted file mode 100644
index af1b698521..0000000000
--- a/widgets/misc/pixmaps/cursor_zoom_out.xpm
+++ /dev/null
@@ -1,37 +0,0 @@
-/* XPM */
-static char * cursor_zoom_out_xpm[] = {
-"32 32 2 1",
-" c None",
-". c #000000",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ...... ",
-" .. .. ",
-" .. .. ",
-" . . ",
-" . . ",
-" . . ",
-" . ....... . ",
-" . ....... . ",
-" . . ",
-" . .. ",
-" .. . . ",
-" .. . . . ",
-" ........ . . ",
-" ..... . . . ",
-" . . . ",
-" . . . ",
-" . . . ",
-" . . . ",
-" . . ",
-" . . ",
-" .. ",
-" ",
-" ",
-" ",
-" ",
-" "};
diff --git a/widgets/misc/test-color.c b/widgets/misc/test-color.c
deleted file mode 100644
index 364e0644de..0000000000
--- a/widgets/misc/test-color.c
+++ /dev/null
@@ -1,76 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * test-color.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <gal/util/e-i18n.h>
-#include <gnome.h>
-#include "widget-color-combo.h"
-#include "color-palette.h"
-#include "e-colors.h"
-#include "pixmaps/cursor_hand_open.xpm"
-
-/* To compile (from src/widgets):
-
-gcc -I.. -I../.. -L. -Wall -o tester tester.c ../color.c `gnome-config --cflags --libs gnome gnomeui` -lwidgets
-
-*/
-
-gint
-main ( gint argc, gchar* argv[] )
-{
- GtkWidget * dialog;
- GtkWidget * T;
- ColorGroup *cg;
-
- gnome_program_init ("tester", "1.0",
- LIBGNOMEUI_MODULE,
- argc, argv, NULL);
-
- dialog = gnome_dialog_new ("TESTER", GNOME_STOCK_BUTTON_OK,
- GNOME_STOCK_BUTTON_CANCEL, NULL);
-
- cg = color_group_fetch ("fore_color_group", dialog);
- T = color_palette_new ("Color Palette", NULL, cg);
-
- gtk_box_pack_start(GTK_BOX (GNOME_DIALOG (dialog)-> vbox ),
- T, TRUE, TRUE, 5);
- gtk_widget_show_all (T);
-
- cg = color_group_fetch ("fore_color_group", dialog);
- T = color_combo_new (
- gdk_pixbuf_new_from_xpm_data ((char const **)cursor_hand_open_xpm),
- _("Automatic"), &e_black, cg);
- gtk_box_pack_start(GTK_BOX (GNOME_DIALOG (dialog)-> vbox ),
- T, TRUE, TRUE, 5);
- gtk_widget_show_all (T);
-
- cg = color_group_fetch ("back_color_group", dialog);
- T = color_combo_new (
- gdk_pixbuf_new_from_xpm_data ((char const **)cursor_hand_open_xpm),
- _("Automatic"), &e_black, cg);
- gtk_box_pack_start(GTK_BOX (GNOME_DIALOG (dialog)-> vbox ),
- T, TRUE, TRUE, 5);
- gtk_widget_show_all (T);
-
- gnome_dialog_run_and_close ( GNOME_DIALOG (dialog) );
- return 0;
-}
diff --git a/widgets/table/.cvsignore b/widgets/table/.cvsignore
deleted file mode 100644
index b1004fee2c..0000000000
--- a/widgets/table/.cvsignore
+++ /dev/null
@@ -1,13 +0,0 @@
-.deps
-.libs
-.pure
-Makefile
-Makefile.in
-*.lo
-*.la
-table-test
-table-example-1
-table-example-2
-table-size-test
-tree-example-1
-tree-example-2
diff --git a/widgets/table/add-col.xpm b/widgets/table/add-col.xpm
deleted file mode 100644
index 9c5f314c8e..0000000000
--- a/widgets/table/add-col.xpm
+++ /dev/null
@@ -1,22 +0,0 @@
-/* XPM */
-static char * add_col_xpm[] = {
-"16 16 3 1",
-" c None",
-". c #000000",
-"+ c #FFFFFF",
-" ",
-" ",
-" ",
-" ",
-" .............. ",
-" .++++++++++++. ",
-" .++++++++++++. ",
-" ....+++....... ",
-" .+. ",
-" . ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" "};
diff --git a/widgets/table/arrow-down.xpm b/widgets/table/arrow-down.xpm
deleted file mode 100644
index f1e6cb4b3c..0000000000
--- a/widgets/table/arrow-down.xpm
+++ /dev/null
@@ -1,21 +0,0 @@
-/* XPM */
-static const char * arrow_down_xpm[] = {
-"13 16 2 1",
-" c None",
-". c #FF0000",
-" ... ",
-" ... ",
-" ... ",
-" ... ",
-" ... ",
-" ... ",
-" ... ",
-" ... ",
-" ... ",
-".............",
-" ........... ",
-" ......... ",
-" ....... ",
-" ..... ",
-" ... ",
-" . "};
diff --git a/widgets/table/arrow-up.xpm b/widgets/table/arrow-up.xpm
deleted file mode 100644
index 0cc5b9a00c..0000000000
--- a/widgets/table/arrow-up.xpm
+++ /dev/null
@@ -1,21 +0,0 @@
-/* XPM */
-static const char * arrow_up_xpm[] = {
-"13 16 2 1",
-" c None",
-". c #FF0000",
-" . ",
-" ... ",
-" ..... ",
-" ....... ",
-" ......... ",
-" ........... ",
-".............",
-" ... ",
-" ... ",
-" ... ",
-" ... ",
-" ... ",
-" ... ",
-" ... ",
-" ... ",
-" ... "};
diff --git a/widgets/table/check-empty.xpm b/widgets/table/check-empty.xpm
deleted file mode 100644
index 746b20234e..0000000000
--- a/widgets/table/check-empty.xpm
+++ /dev/null
@@ -1,21 +0,0 @@
-/* XPM */
-static const char * check_empty_xpm[] = {
-"16 16 2 1",
-" c None",
-". c #000000",
-" ",
-" ",
-" ............ ",
-" . . ",
-" . . ",
-" . . ",
-" . . ",
-" . . ",
-" . . ",
-" . . ",
-" . . ",
-" . . ",
-" . . ",
-" ............ ",
-" ",
-" "};
diff --git a/widgets/table/check-filled.xpm b/widgets/table/check-filled.xpm
deleted file mode 100644
index c0468fc25b..0000000000
--- a/widgets/table/check-filled.xpm
+++ /dev/null
@@ -1,21 +0,0 @@
-/* XPM */
-static const char * check_filled_xpm[] = {
-"16 16 2 1",
-" c None",
-". c #000000",
-" ",
-" ",
-" ............ ",
-" . . ",
-" . . . ",
-" . .. . ",
-" . ... . ",
-" . . ... . ",
-" . .. ... . ",
-" . ..... . ",
-" . ... . ",
-" . . . ",
-" . . ",
-" ............ ",
-" ",
-" "};
diff --git a/widgets/table/clip.png b/widgets/table/clip.png
deleted file mode 100644
index 27aa5f072f..0000000000
--- a/widgets/table/clip.png
+++ /dev/null
Binary files differ
diff --git a/widgets/table/e-cell-checkbox.c b/widgets/table/e-cell-checkbox.c
deleted file mode 100644
index 5ef4b23a96..0000000000
--- a/widgets/table/e-cell-checkbox.c
+++ /dev/null
@@ -1,67 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-cell-checkbox.c: Checkbox cell renderer
- * Copyright 1999, 2000, Ximian, Inc.
- *
- * Authors:
- * Miguel de Icaza <miguel@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-#include <config.h>
-#include <gtk/gtkenums.h>
-#include <gtk/gtkentry.h>
-#include <gtk/gtkwindow.h>
-#include <gtk/gtksignal.h>
-#include <gdk/gdkkeysyms.h>
-#include <libgnomecanvas/gnome-canvas.h>
-#include "e-cell-checkbox.h"
-#include "gal/util/e-util.h"
-#include "e-table-item.h"
-
-#include "check-empty.xpm"
-#include "check-filled.xpm"
-
-#define PARENT_TYPE e_cell_toggle_get_type ()
-
-static GdkPixbuf *checks [2];
-
-static void
-e_cell_checkbox_class_init (GtkObjectClass *object_class)
-{
- checks [0] = gdk_pixbuf_new_from_xpm_data (check_empty_xpm);
- checks [1] = gdk_pixbuf_new_from_xpm_data (check_filled_xpm);
-}
-
-E_MAKE_TYPE(e_cell_checkbox, "ECellCheckbox", ECellCheckbox, e_cell_checkbox_class_init, NULL, PARENT_TYPE)
-
-/**
- * e_cell_checkbox_new:
- *
- * Creates a new ECell renderer that can be used to render check
- * boxes. the data provided from the model is cast to an integer.
- * zero is used for the off display, and non-zero for checked status.
- *
- * Returns: an ECell object that can be used to render checkboxes.
- */
-ECell *
-e_cell_checkbox_new (void)
-{
- ECellCheckbox *eccb = g_object_new (E_CELL_CHECKBOX_TYPE, NULL);
-
- e_cell_toggle_construct (E_CELL_TOGGLE (eccb), 2, 2, checks);
-
- return (ECell *) eccb;
-}
diff --git a/widgets/table/e-cell-checkbox.h b/widgets/table/e-cell-checkbox.h
deleted file mode 100644
index ab56af27ab..0000000000
--- a/widgets/table/e-cell-checkbox.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-cell-checkbox.h: Checkbox cell renderer
- * Copyright 1999, 2000, Ximian, Inc.
- *
- * Authors:
- * Miguel de Icaza <miguel@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-#ifndef _E_CELL_CHECKBOX_H_
-#define _E_CELL_CHECKBOX_H_
-
-#include <gal/e-table/e-cell-toggle.h>
-
-G_BEGIN_DECLS
-
-#define E_CELL_CHECKBOX_TYPE (e_cell_checkbox_get_type ())
-#define E_CELL_CHECKBOX(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_CELL_CHECKBOX_TYPE, ECellCheckbox))
-#define E_CELL_CHECKBOX_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_CELL_CHECKBOX_TYPE, ECellCheckboxClass))
-#define E_IS_CELL_CHECKBOX(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_CELL_CHECKBOX_TYPE))
-#define E_IS_CELL_CHECKBOX_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_CELL_CHECKBOX_TYPE))
-
-typedef struct {
- ECellToggle parent;
-} ECellCheckbox;
-
-typedef struct {
- ECellToggleClass parent_class;
-} ECellCheckboxClass;
-
-GType e_cell_checkbox_get_type (void);
-ECell *e_cell_checkbox_new (void);
-
-G_END_DECLS
-
-#endif /* _E_CELL_CHECKBOX_H_ */
-
diff --git a/widgets/table/e-cell-combo.c b/widgets/table/e-cell-combo.c
deleted file mode 100644
index 3ff3488ae5..0000000000
--- a/widgets/table/e-cell-combo.c
+++ /dev/null
@@ -1,703 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-cell-combo.c: Combo cell renderer
- * Copyright 2001, Ximian, Inc.
- *
- * Authors:
- * Damon Chaplin <damon@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-/*
- * ECellCombo - a subclass of ECellPopup used to support popup lists like a
- * GtkCombo widget. It only supports a basic popup list of strings at present,
- * with no auto-completion.
- */
-
-/*
- * Notes: (handling pointer grabs and GTK+ grabs is a nightmare!)
- *
- * o We must grab the pointer when we show the popup, so that if any buttons
- * are pressed outside the application we hide the popup.
- *
- * o We have to be careful when popping up any widgets which also grab the
- * pointer at some point, since we will lose our own pointer grab.
- * When we pop up a list it will grab the pointer itself when an item is
- * selected, and release the grab when the button is released.
- * Fortunately we hide the popup at this point, so it isn't a problem.
- * But for other types of widgets in the popup it could cause trouble.
- * - I think GTK+ should provide help for this (nested pointer grabs?).
- *
- * o We must set the 'owner_events' flag of the pointer grab to TRUE so that
- * pointer events get reported to all the application windows as normal.
- * If we don't do this then the widgets in the popup may not work properly.
- *
- * o We must do a gtk_grab_add() so that we only allow events to go to the
- * widgets within the popup (though some special events still get reported
- * to the widget owning the window). Doing th gtk_grab_add() on the toplevel
- * popup window should be fine. We can then check for any events that should
- * close the popup, like the Escape key, or a button press outside the popup.
- */
-
-#include <config.h>
-#include <string.h> /* strcmp() */
-#include <gdk/gdkkeysyms.h>
-#include <gtk/gtk.h>
-#include <glib/gi18n.h>
-#include "gal/util/e-util.h"
-#include "gal/widgets/e-unicode.h"
-#include "e-table-item.h"
-#include "e-cell-combo.h"
-#include "e-cell-text.h"
-
-#define d(x)
-
-
-/* The height to make the popup list if there aren't any items in it. */
-#define E_CELL_COMBO_LIST_EMPTY_HEIGHT 15
-
-/* The object data key used to store the UTF-8 text of the popup list items. */
-#define E_CELL_COMBO_UTF8_KEY "UTF-8-TEXT"
-
-
-static void e_cell_combo_class_init (GObjectClass *object_class);
-static void e_cell_combo_init (ECellCombo *ecc);
-static void e_cell_combo_dispose (GObject *object);
-
-static gint e_cell_combo_do_popup (ECellPopup *ecp,
- GdkEvent *event,
- int row,
- int view_col);
-static void e_cell_combo_select_matching_item (ECellCombo *ecc);
-static void e_cell_combo_show_popup (ECellCombo *ecc,
- int row,
- int view_col);
-static void e_cell_combo_get_popup_pos (ECellCombo *ecc,
- int row,
- int view_col,
- gint *x,
- gint *y,
- gint *height,
- gint *width);
-
-static void e_cell_combo_selection_changed (GtkWidget *popup_list, ECellCombo *ecc);
-
-static gint e_cell_combo_list_button_press (GtkWidget *popup_list, GdkEvent *event, ECellCombo *ecc);
-
-static gint e_cell_combo_button_press (GtkWidget *popup_window,
- GdkEvent *event,
- ECellCombo *ecc);
-static gint e_cell_combo_button_release (GtkWidget *popup_window,
- GdkEventButton *event,
- ECellCombo *ecc);
-static int e_cell_combo_key_press (GtkWidget *popup_window,
- GdkEventKey *event,
- ECellCombo *ecc);
-
-static void e_cell_combo_update_cell (ECellCombo *ecc);
-static void e_cell_combo_restart_edit (ECellCombo *ecc);
-
-
-static ECellPopupClass *parent_class;
-
-
-E_MAKE_TYPE (e_cell_combo, "ECellCombo", ECellCombo,
- e_cell_combo_class_init, e_cell_combo_init,
- e_cell_popup_get_type())
-
-
-static void
-e_cell_combo_class_init (GObjectClass *object_class)
-{
- ECellPopupClass *ecpc = (ECellPopupClass *) object_class;
-
- object_class->dispose = e_cell_combo_dispose;
-
- ecpc->popup = e_cell_combo_do_popup;
-
- parent_class = g_type_class_ref (E_CELL_POPUP_TYPE);
-}
-
-
-static void
-e_cell_combo_init (ECellCombo *ecc)
-{
- GtkWidget *frame;
- AtkObject *a11y;
-
- /* We create one popup window for the ECell, since there will only
- ever be one popup in use at a time. */
- ecc->popup_window = gtk_window_new (GTK_WINDOW_POPUP);
-
- gtk_window_set_policy (GTK_WINDOW (ecc->popup_window),
- TRUE, TRUE, FALSE);
-
- frame = gtk_frame_new (NULL);
- gtk_container_add (GTK_CONTAINER (ecc->popup_window), frame);
- gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
- gtk_widget_show (frame);
-
- ecc->popup_scrolled_window = gtk_scrolled_window_new (NULL, NULL);
- gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (ecc->popup_scrolled_window),
- GTK_POLICY_AUTOMATIC,
- GTK_POLICY_AUTOMATIC);
- GTK_WIDGET_UNSET_FLAGS (GTK_SCROLLED_WINDOW (ecc->popup_scrolled_window)->hscrollbar, GTK_CAN_FOCUS);
- GTK_WIDGET_UNSET_FLAGS (GTK_SCROLLED_WINDOW (ecc->popup_scrolled_window)->vscrollbar, GTK_CAN_FOCUS);
- gtk_container_add (GTK_CONTAINER (frame), ecc->popup_scrolled_window);
- gtk_widget_show (ecc->popup_scrolled_window);
-
- ecc->popup_list = gtk_list_new ();
- gtk_list_set_selection_mode (GTK_LIST (ecc->popup_list),
- GTK_SELECTION_BROWSE);
- gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (ecc->popup_scrolled_window), ecc->popup_list);
- gtk_container_set_focus_vadjustment (GTK_CONTAINER (ecc->popup_list),
- gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (ecc->popup_scrolled_window)));
- gtk_container_set_focus_hadjustment (GTK_CONTAINER (ecc->popup_list),
- gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (ecc->popup_scrolled_window)));
- gtk_widget_show (ecc->popup_list);
-
- a11y = gtk_widget_get_accessible (ecc->popup_list);
- atk_object_set_name (a11y, _("popup list"));
-
- g_signal_connect (ecc->popup_list,
- "selection_changed",
- G_CALLBACK (e_cell_combo_selection_changed),
- ecc);
- g_signal_connect (ecc->popup_list,
- "button_press_event",
- G_CALLBACK (e_cell_combo_list_button_press),
- ecc);
- g_signal_connect (ecc->popup_window,
- "button_press_event",
- G_CALLBACK (e_cell_combo_button_press),
- ecc);
- /* We use connect_after here so the list updates the selection before
- we hide the popup and update the cell. */
- g_signal_connect (ecc->popup_window,
- "button_release_event",
- G_CALLBACK (e_cell_combo_button_release),
- ecc);
- g_signal_connect (ecc->popup_window,
- "key_press_event",
- G_CALLBACK (e_cell_combo_key_press), ecc);
-}
-
-
-/**
- * e_cell_combo_new:
- *
- * Creates a new ECellCombo renderer.
- *
- * Returns: an ECellCombo object.
- */
-ECell *
-e_cell_combo_new (void)
-{
- ECellCombo *ecc = g_object_new (E_CELL_COMBO_TYPE, NULL);
-
- return (ECell*) ecc;
-}
-
-
-/*
- * GObject::dispose method
- */
-static void
-e_cell_combo_dispose (GObject *object)
-{
- ECellCombo *ecc = E_CELL_COMBO (object);
-
- if (ecc->popup_window)
- gtk_widget_destroy (ecc->popup_window);
- ecc->popup_window = NULL;
-
- G_OBJECT_CLASS (parent_class)->dispose (object);
-}
-
-
-
-void
-e_cell_combo_set_popdown_strings (ECellCombo *ecc,
- GList *strings)
-{
- GList *elem;
- GtkWidget *listitem;
-
- g_return_if_fail (E_IS_CELL_COMBO (ecc));
- g_return_if_fail (strings != NULL);
-
- gtk_list_clear_items (GTK_LIST (ecc->popup_list), 0, -1);
- elem = strings;
- while (elem) {
- char *utf8_text = elem->data;
-
- listitem = gtk_list_item_new_with_label (utf8_text);
-
- gtk_widget_show (listitem);
- gtk_container_add (GTK_CONTAINER (ecc->popup_list), listitem);
-
- g_object_set_data_full (G_OBJECT (listitem),
- E_CELL_COMBO_UTF8_KEY,
- g_strdup (utf8_text), g_free);
-
- elem = elem->next;
- }
-}
-
-
-static gint
-e_cell_combo_do_popup (ECellPopup *ecp,
- GdkEvent *event,
- int row,
- int view_col)
-{
- ECellCombo *ecc = E_CELL_COMBO (ecp);
- guint32 time;
- gint error_code;
-
- g_signal_handlers_block_by_func(ecc->popup_list, e_cell_combo_selection_changed, ecc);
- e_cell_combo_show_popup (ecc, row, view_col);
- e_cell_combo_select_matching_item (ecc);
- g_signal_handlers_unblock_by_func(ecc->popup_list, e_cell_combo_selection_changed, ecc);
-
- if (event->type == GDK_BUTTON_PRESS) {
- GTK_LIST (ecc->popup_list)->drag_selection = TRUE;
- time = event->button.time;
- } else {
- time = event->key.time;
- }
-
- error_code = gdk_pointer_grab (ecc->popup_list->window, TRUE,
- GDK_ENTER_NOTIFY_MASK |
- GDK_BUTTON_PRESS_MASK |
- GDK_BUTTON_RELEASE_MASK |
- GDK_POINTER_MOTION_HINT_MASK |
- GDK_BUTTON1_MOTION_MASK,
- NULL, NULL, time);
- if (error_code != 0)
- g_warning ("Failed to get pointer grab (%i)", error_code);
- gtk_grab_add (ecc->popup_window);
- gdk_keyboard_grab (ecc->popup_list->window, TRUE, time);
-
- return TRUE;
-}
-
-
-static void
-e_cell_combo_select_matching_item (ECellCombo *ecc)
-{
- ECellPopup *ecp = E_CELL_POPUP (ecc);
- ECellView *ecv = (ECellView*) ecp->popup_cell_view;
- ECellText *ecell_text = E_CELL_TEXT (ecp->child);
- ETableItem *eti = E_TABLE_ITEM (ecp->popup_cell_view->cell_view.e_table_item_view);
- ETableCol *ecol;
- GtkList *list;
- GtkWidget *listitem;
- GList *elem;
- gboolean found = FALSE;
- char *cell_text, *list_item_text;
-
- 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);
-
- list = GTK_LIST (ecc->popup_list);
- elem = list->children;
- while (elem) {
- listitem = GTK_WIDGET (elem->data);
-
- /* We need to compare against the UTF-8 text. */
- list_item_text = g_object_get_data (G_OBJECT (listitem),
- E_CELL_COMBO_UTF8_KEY);
-
- if (list_item_text && !strcmp (list_item_text, cell_text)) {
- found = TRUE;
- gtk_list_select_child (list, listitem);
- gtk_widget_grab_focus (listitem);
- break;
- }
-
- elem = elem->next;
- }
-
- if (!found) {
- gtk_list_unselect_all (list);
- if (list->children)
- gtk_widget_grab_focus (GTK_WIDGET (list->children->data));
- }
-
- e_cell_text_free_text (ecell_text, cell_text);
-}
-
-
-static void
-e_cell_combo_show_popup (ECellCombo *ecc, int row, int view_col)
-{
- gint x, y, width, height, old_width, old_height;
-
- /* This code is practically copied from GtkCombo. */
- old_width = ecc->popup_window->allocation.width;
- old_height = ecc->popup_window->allocation.height;
-
- e_cell_combo_get_popup_pos (ecc, row, view_col, &x, &y, &height, &width);
-
- /* workaround for gtk_scrolled_window_size_allocate bug */
- if (old_width != width || old_height != height) {
- gtk_widget_hide (GTK_SCROLLED_WINDOW (ecc->popup_scrolled_window)->hscrollbar);
- gtk_widget_hide (GTK_SCROLLED_WINDOW (ecc->popup_scrolled_window)->vscrollbar);
- }
-
- gtk_widget_set_uposition (ecc->popup_window, x, y);
- gtk_widget_set_usize (ecc->popup_window, width, height);
- gtk_widget_realize (ecc->popup_window);
- gdk_window_resize (ecc->popup_window->window, width, height);
- gtk_widget_show (ecc->popup_window);
-
- e_cell_popup_set_shown (E_CELL_POPUP (ecc), TRUE);
- d(g_print("%s: popup_shown = TRUE\n", __FUNCTION__));
-}
-
-
-/* Calculates the size and position of the popup window (like GtkCombo). */
-static void
-e_cell_combo_get_popup_pos (ECellCombo *ecc,
- int row,
- int view_col,
- gint *x,
- gint *y,
- gint *height,
- gint *width)
-{
- ECellPopup *ecp = E_CELL_POPUP (ecc);
- ETableItem *eti = E_TABLE_ITEM (ecp->popup_cell_view->cell_view.e_table_item_view);
- GtkWidget *canvas = GTK_WIDGET (GNOME_CANVAS_ITEM (eti)->canvas);
- GtkBin *popwin;
- GtkScrolledWindow *popup;
- GtkRequisition list_requisition;
- gboolean show_vscroll = FALSE, show_hscroll = FALSE;
- gint avail_height, avail_width, min_height, work_height, screen_width;
- gint column_width, row_height, scrollbar_width;
- double x1, y1;
- double wx, wy;
-
- /* This code is practically copied from GtkCombo. */
- popup = GTK_SCROLLED_WINDOW (ecc->popup_scrolled_window);
- popwin = GTK_BIN (ecc->popup_window);
-
- 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;
-
- scrollbar_width = popup->vscrollbar->requisition.width
- + GTK_SCROLLED_WINDOW_CLASS (GTK_OBJECT_GET_CLASS (popup))->scrollbar_spacing;
-
- 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 ();
- avail_width = screen_width - scrollbar_width;
-
- gtk_widget_size_request (ecc->popup_list, &list_requisition);
- min_height = MIN (list_requisition.height,
- popup->vscrollbar->requisition.height);
- if (!GTK_LIST (ecc->popup_list)->children)
- list_requisition.height += E_CELL_COMBO_LIST_EMPTY_HEIGHT;
-
- /* Calculate the desired width. */
- *width = list_requisition.width
- + 2 * popwin->child->style->xthickness
- + 2 * GTK_CONTAINER (popwin->child)->border_width
- + 2 * GTK_CONTAINER (popup)->border_width
- + 2 * GTK_CONTAINER (GTK_BIN (popup)->child)->border_width
- + 2 * GTK_BIN (popup)->child->style->xthickness;
-
- /* Use at least the same width as the column. */
- if (*width < column_width)
- *width = column_width;
-
- /* If it is larger than the available width, use that instead and show
- the horizontal scrollbar. */
- if (*width > avail_width) {
- *width = avail_width;
- show_hscroll = TRUE;
- }
-
- /* Calculate all the borders etc. that we need to add to the height. */
- work_height = (2 * popwin->child->style->ythickness
- + 2 * GTK_CONTAINER (popwin->child)->border_width
- + 2 * GTK_CONTAINER (popup)->border_width
- + 2 * GTK_CONTAINER (GTK_BIN (popup)->child)->border_width
- + 2 * GTK_BIN (popup)->child->style->xthickness);
-
- /* Add on the height of the horizontal scrollbar if we need it. */
- if (show_hscroll)
- work_height += popup->hscrollbar->requisition.height +
- GTK_SCROLLED_WINDOW_CLASS (GTK_OBJECT_GET_CLASS (popup))->scrollbar_spacing;
-
- /* Check if it fits in the available height. */
- if (work_height + list_requisition.height > avail_height) {
- /* It doesn't fit, so we see if we have the minimum space
- needed. */
- if (work_height + min_height > avail_height
- && *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 -= (work_height + list_requisition.height
- + row_height);
- if (*y < 0)
- *y = 0;
- }
- }
-
- /* Check if we still need the vertical scrollbar. */
- if (work_height + list_requisition.height > avail_height) {
- *width += scrollbar_width;
- show_vscroll = TRUE;
- }
-
- /* 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;
-
- if (show_vscroll)
- *height = avail_height;
- else
- *height = work_height + list_requisition.height;
-}
-
-static void
-e_cell_combo_selection_changed(GtkWidget *popup_list, ECellCombo *ecc)
-{
- if (!GTK_LIST(popup_list)->selection || !GTK_WIDGET_REALIZED(ecc->popup_window))
- return;
-
- e_cell_combo_restart_edit (ecc);
-}
-
-static gint
-e_cell_combo_list_button_press(GtkWidget *popup_list, GdkEvent *event, ECellCombo *ecc)
-{
- g_return_val_if_fail (GTK_IS_LIST(popup_list), FALSE);
-
- e_cell_combo_update_cell (ecc);
- gtk_grab_remove (ecc->popup_window);
- gdk_pointer_ungrab (event->button.time);
- gdk_keyboard_ungrab (event->button.time);
- gtk_widget_hide (ecc->popup_window);
-
- e_cell_popup_set_shown (E_CELL_POPUP (ecc), FALSE);
- d(g_print("%s: popup_shown = FALSE\n", __FUNCTION__));
-
- e_cell_combo_restart_edit (ecc);
-
- return TRUE;
-
-}
-
-/* This handles button press events in the popup window.
- Note that since we have a pointer grab on this window, we also get button
- press events for windows outside the application here, so we hide the popup
- window if that happens. We also get propagated events from child widgets
- which we ignore. */
-static gint
-e_cell_combo_button_press (GtkWidget *popup_window,
- GdkEvent *event,
- ECellCombo *ecc)
-{
- GtkWidget *event_widget;
-
- event_widget = gtk_get_event_widget (event);
-
- /* If the button press was for a widget inside the popup list, but
- not the popup window itself, then we ignore the event and return
- FALSE. Otherwise we will hide the popup.
- Note that since we have a pointer grab on the popup list, button
- presses outside the application will be reported to this window,
- which is why we hide the popup in this case. */
- while (event_widget) {
- event_widget = event_widget->parent;
- if (event_widget == ecc->popup_list)
- return FALSE;
- }
-
- gtk_grab_remove (ecc->popup_window);
- gdk_pointer_ungrab (event->button.time);
- gdk_keyboard_ungrab (event->button.time);
- gtk_widget_hide (ecc->popup_window);
-
- e_cell_popup_set_shown (E_CELL_POPUP (ecc), FALSE);
- d(g_print("%s: popup_shown = FALSE\n", __FUNCTION__));
-
- /* We don't want to update the cell here. Since the list is in browse
- mode there will always be one item selected, so when we popup the
- list one item is selected even if it doesn't match the current text
- in the cell. So if you click outside the popup (which is what has
- happened here) it is better to not update the cell. */
- /*e_cell_combo_update_cell (ecc);*/
- e_cell_combo_restart_edit (ecc);
-
- return TRUE;
-}
-
-
-/* This handles button release events in the popup window. If the button is
- released inside the list, we want to hide the popup window and update the
- cell with the new selection. */
-static gint
-e_cell_combo_button_release (GtkWidget *popup_window,
- GdkEventButton *event,
- ECellCombo *ecc)
-{
- GtkWidget *event_widget;
-
- event_widget = gtk_get_event_widget ((GdkEvent*) event);
-
- /* See if the button was released in the list (or its children). */
- while (event_widget && event_widget != ecc->popup_list)
- event_widget = event_widget->parent;
-
- /* If it wasn't, then we just ignore the event. */
- if (event_widget != ecc->popup_list)
- return FALSE;
-
- /* The button was released inside the list, so we hide the popup and
- update the cell to reflect the new selection. */
- gtk_grab_remove (ecc->popup_window);
- gdk_pointer_ungrab (event->time);
- gdk_keyboard_ungrab (event->time);
- gtk_widget_hide (ecc->popup_window);
-
- e_cell_popup_set_shown (E_CELL_POPUP (ecc), FALSE);
- d(g_print("%s: popup_shown = FALSE\n", __FUNCTION__));
-
- e_cell_combo_update_cell (ecc);
- e_cell_combo_restart_edit (ecc);
-
- return TRUE;
-}
-
-
-/* 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_combo_key_press (GtkWidget *popup_window,
- GdkEventKey *event,
- ECellCombo *ecc)
-{
- /* If the Escape key is pressed we hide the popup. */
- if (event->keyval != GDK_Escape
- && event->keyval != GDK_Return
- && event->keyval != GDK_KP_Enter
- && event->keyval != GDK_ISO_Enter
- && event->keyval != GDK_3270_Enter)
- return FALSE;
-
- gtk_grab_remove (ecc->popup_window);
- gdk_pointer_ungrab (event->time);
- gdk_keyboard_ungrab (event->time);
- gtk_widget_hide (ecc->popup_window);
-
- e_cell_popup_set_shown (E_CELL_POPUP (ecc), FALSE);
- d(g_print("%s: popup_shown = FALSE\n", __FUNCTION__));
-
- if (event->keyval != GDK_Escape)
- e_cell_combo_update_cell (ecc);
-
- e_cell_combo_restart_edit (ecc);
-
- return TRUE;
-}
-
-
-static void
-e_cell_combo_update_cell (ECellCombo *ecc)
-{
- ECellPopup *ecp = E_CELL_POPUP (ecc);
- ECellView *ecv = (ECellView*) ecp->popup_cell_view;
- ECellText *ecell_text = E_CELL_TEXT (ecp->child);
- ETableItem *eti = E_TABLE_ITEM (ecv->e_table_item_view);
- ETableCol *ecol;
- GtkList *list = GTK_LIST (ecc->popup_list);
- GtkListItem *listitem;
- gchar *text, *old_text;
-
- /* Return if no item is selected. */
- if (list->selection == NULL)
- return;
-
- /* Get the text of the selected item. */
- listitem = list->selection->data;
- text = g_object_get_data (G_OBJECT (listitem),
- E_CELL_COMBO_UTF8_KEY);
- g_return_if_fail (text != NULL);
-
- /* Compare it 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 (old_text && strcmp (old_text, text)) {
- e_cell_text_set_value (ecell_text, ecv->e_table_model,
- ecol->col_idx, ecp->popup_row, text);
- }
-
- e_cell_text_free_text (ecell_text, old_text);
-}
-
-
-static void
-e_cell_combo_restart_edit (ECellCombo *ecc)
-{
- /* This doesn't work. ETable stops the edit straight-away again. */
-#if 0
- ECellView *ecv = (ECellView*) ecc->popup_cell_view;
- ETableItem *eti = E_TABLE_ITEM (ecv->e_table_item_view);
-
- e_table_item_enter_edit (eti, ecc->popup_view_col, ecc->popup_row);
-#endif
-}
-
-
-
diff --git a/widgets/table/e-cell-combo.h b/widgets/table/e-cell-combo.h
deleted file mode 100644
index 23d5ac26a4..0000000000
--- a/widgets/table/e-cell-combo.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-cell-combo.h: Combo cell renderer
- * Copyright 2001, Ximian, Inc.
- *
- * Author :
- * Damon Chaplin <damon@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-/*
- * ECellCombo - a subclass of ECellPopup used to support popup lists like a
- * GtkCombo widget. It only supports a basic popup list of strings at present,
- * with no auto-completion. The child ECell of the ECellPopup must be an
- * ECellText or subclass.
- */
-
-#ifndef _E_CELL_COMBO_H_
-#define _E_CELL_COMBO_H_
-
-#include <gal/e-table/e-cell-popup.h>
-
-#define E_CELL_COMBO_TYPE (e_cell_combo_get_type ())
-#define E_CELL_COMBO(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_CELL_COMBO_TYPE, ECellCombo))
-#define E_CELL_COMBO_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_CELL_COMBO_TYPE, ECellComboClass))
-#define E_IS_CELL_COMBO(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_CELL_COMBO_TYPE))
-#define E_IS_CELL_COMBO_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_CELL_COMBO_TYPE))
-
-
-typedef struct {
- ECellPopup parent;
-
- GtkWidget *popup_window;
- GtkWidget *popup_scrolled_window;
- GtkWidget *popup_list;
-} ECellCombo;
-
-typedef struct {
- ECellPopupClass parent_class;
-} ECellComboClass;
-
-
-GType e_cell_combo_get_type (void);
-ECell *e_cell_combo_new (void);
-
-/* These must be UTF-8. */
-void e_cell_combo_set_popdown_strings (ECellCombo *ecc,
- GList *strings);
-
-#endif /* _E_CELL_COMBO_H_ */
diff --git a/widgets/table/e-cell-date.c b/widgets/table/e-cell-date.c
deleted file mode 100644
index 64d9b8132b..0000000000
--- a/widgets/table/e-cell-date.c
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * e-cell-date.c - Date item for e-table.
- * Copyright 2001, Ximian, Inc.
- *
- * Author:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-
-#include "e-cell-date.h"
-
-#include <sys/time.h>
-#include <time.h>
-#include <unistd.h>
-#include <string.h>
-#include <gal/util/e-util.h>
-#include <gal/widgets/e-unicode.h>
-#include <gal/util/e-i18n.h>
-
-#define PARENT_TYPE e_cell_text_get_type ()
-
-static ECellTextClass *parent_class;
-
-static char *
-ecd_get_text(ECellText *cell, ETableModel *model, int col, int row)
-{
- time_t date = GPOINTER_TO_INT (e_table_model_value_at(model, col, row));
- time_t nowdate = time(NULL);
- time_t yesdate;
- struct tm then, now, yesterday;
- char buf[100];
- char *temp;
- gboolean done = FALSE;
-
- if (date == 0) {
- return g_strdup (_("?"));
- }
-
- localtime_r (&date, &then);
- localtime_r (&nowdate, &now);
-
- if (nowdate - date < 60 * 60 * 8 && nowdate > date) {
- e_utf8_strftime_fix_am_pm (buf, 100, _("%l:%M %p"), &then);
- done = TRUE;
- }
-
- if (!done) {
- if (then.tm_mday == now.tm_mday &&
- then.tm_mon == now.tm_mon &&
- then.tm_year == now.tm_year) {
- e_utf8_strftime_fix_am_pm (buf, 100, _("Today %l:%M %p"), &then);
- done = TRUE;
- }
- }
- if (!done) {
- yesdate = nowdate - 60 * 60 * 24;
- localtime_r (&yesdate, &yesterday);
- if (then.tm_mday == yesterday.tm_mday &&
- then.tm_mon == yesterday.tm_mon &&
- then.tm_year == yesterday.tm_year) {
- e_utf8_strftime_fix_am_pm (buf, 100, _("Yesterday %l:%M %p"), &then);
- done = TRUE;
- }
- }
- if (!done) {
- int i;
- for (i = 2; i < 7; i++) {
- yesdate = nowdate - 60 * 60 * 24 * i;
- localtime_r (&yesdate, &yesterday);
- if (then.tm_mday == yesterday.tm_mday &&
- then.tm_mon == yesterday.tm_mon &&
- then.tm_year == yesterday.tm_year) {
- e_utf8_strftime_fix_am_pm (buf, 100, _("%a %l:%M %p"), &then);
- done = TRUE;
- break;
- }
- }
- }
- if (!done) {
- if (then.tm_year == now.tm_year) {
- e_utf8_strftime_fix_am_pm (buf, 100, _("%b %d %l:%M %p"), &then);
- } else {
- e_utf8_strftime_fix_am_pm (buf, 100, _("%b %d %Y"), &then);
- }
- }
- temp = buf;
- while ((temp = strstr (temp, " "))) {
- memmove (temp, temp + 1, strlen (temp));
- }
- temp = e_strdup_strip (buf);
- return temp;
-}
-
-static void
-ecd_free_text(ECellText *cell, char *text)
-{
- g_free(text);
-}
-
-static void
-e_cell_date_class_init (GtkObjectClass *object_class)
-{
- ECellTextClass *ectc = (ECellTextClass *) object_class;
-
- parent_class = g_type_class_ref (PARENT_TYPE);
-
- ectc->get_text = ecd_get_text;
- ectc->free_text = ecd_free_text;
-}
-
-static void
-e_cell_date_init (GtkObject *object)
-{
-}
-
-/**
- * e_cell_date_new:
- * @fontname: font to be used to render on the screen
- * @justify: Justification of the string in the cell.
- *
- * Creates a new ECell renderer that can be used to render dates that
- * that come from the model. The value returned from the model is
- * interpreted as being a time_t.
- *
- * The ECellDate object support a large set of properties that can be
- * configured through the Gtk argument system and allows the user to have
- * a finer control of the way the string is displayed. The arguments supported
- * allow the control of strikeout, bold, color and a date filter.
- *
- * The arguments "strikeout_column", "underline_column", "bold_column"
- * and "color_column" set and return an integer that points to a
- * column in the model that controls these settings. So controlling
- * the way things are rendered is achieved by having special columns
- * in the model that will be used to flag whether the date should be
- * rendered with strikeout, underline, or bolded. In the case of the
- * "color_column" argument, the column in the model is expected to
- * have a string that can be parsed by gdk_color_parse().
- *
- * Returns: an ECell object that can be used to render dates.
- */
-ECell *
-e_cell_date_new (const char *fontname, GtkJustification justify)
-{
- ECellDate *ecd = g_object_new (E_CELL_DATE_TYPE, NULL);
-
- e_cell_text_construct(E_CELL_TEXT(ecd), fontname, justify);
-
- return (ECell *) ecd;
-}
-
-E_MAKE_TYPE(e_cell_date, "ECellDate", ECellDate, e_cell_date_class_init, e_cell_date_init, PARENT_TYPE)
diff --git a/widgets/table/e-cell-date.h b/widgets/table/e-cell-date.h
deleted file mode 100644
index 96d5faa5c3..0000000000
--- a/widgets/table/e-cell-date.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * e-cell-date.h - Date item for e-table.
- * Copyright 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_CELL_DATE_H_
-#define _E_CELL_DATE_H_
-
-#include <gal/e-table/e-cell-text.h>
-
-G_BEGIN_DECLS
-
-#define E_CELL_DATE_TYPE (e_cell_date_get_type ())
-#define E_CELL_DATE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_CELL_DATE_TYPE, ECellDate))
-#define E_CELL_DATE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_CELL_DATE_TYPE, ECellDateClass))
-#define E_IS_CELL_DATE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_CELL_DATE_TYPE))
-#define E_IS_CELL_DATE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_CELL_DATE_TYPE))
-
-typedef struct {
- ECellText base;
-} ECellDate;
-
-typedef struct {
- ECellTextClass parent_class;
-} ECellDateClass;
-
-GType e_cell_date_get_type (void);
-ECell *e_cell_date_new (const char *fontname, GtkJustification justify);
-
-G_END_DECLS
-
-#endif /* _E_CELL_DATE_H_ */
diff --git a/widgets/table/e-cell-float.c b/widgets/table/e-cell-float.c
deleted file mode 100644
index 133be063b3..0000000000
--- a/widgets/table/e-cell-float.c
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * e-cell-float.c - Float item for e-table.
- * Copyright 2001, CodeFactory AB
- * Copyright 2001, Mikael Hallendal <micke@codefactory.se>
- *
- * Derived from e-cell-number by Chris Lahey <clahey@ximian.com>
- * ECellFloat - Float item for e-table.
- *
- * Author:
- * Mikael Hallendal <micke@codefactory.se>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <sys/time.h>
-#include <unistd.h>
-#include <gal/util/e-util.h>
-#include <gal/util/e-i18n.h>
-#include "e-cell-float.h"
-
-#define PARENT_TYPE e_cell_text_get_type ()
-
-static ECellTextClass *parent_class;
-
-static char *
-ecf_get_text(ECellText *cell, ETableModel *model, int col, int row)
-{
- gfloat *fvalue;
-
- fvalue = e_table_model_value_at (model, col, row);
-
- return e_format_number_float (*fvalue);
-}
-
-static void
-ecf_free_text(ECellText *cell, char *text)
-{
- g_free(text);
-}
-
-static void
-e_cell_float_class_init (GtkObjectClass *object_class)
-{
- ECellTextClass *ectc = (ECellTextClass *) object_class;
-
- parent_class = g_type_class_ref (PARENT_TYPE);
-
- ectc->get_text = ecf_get_text;
- ectc->free_text = ecf_free_text;
-}
-
-static void
-e_cell_float_init (GtkObject *object)
-{
-}
-
-/**
- * e_cell_float_new:
- * @fontname: font to be used to render on the screen
- * @justify: Justification of the string in the cell.
- *
- * Creates a new ECell renderer that can be used to render floats that
- * that come from the model. The value returned from the model is
- * interpreted as being an int.
- *
- * See ECellText for other features.
- *
- * Returns: an ECell object that can be used to render floats.
- */
-ECell *
-e_cell_float_new (const char *fontname, GtkJustification justify)
-{
- ECellFloat *ecn = g_object_new (E_CELL_FLOAT_TYPE, NULL);
-
- e_cell_text_construct(E_CELL_TEXT(ecn), fontname, justify);
-
- return (ECell *) ecn;
-}
-
-E_MAKE_TYPE(e_cell_float, "ECellFloat", ECellFloat, e_cell_float_class_init, e_cell_float_init, PARENT_TYPE)
diff --git a/widgets/table/e-cell-float.h b/widgets/table/e-cell-float.h
deleted file mode 100644
index 36874406b2..0000000000
--- a/widgets/table/e-cell-float.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * e-cell-float.h - Float item for e-table.
- * Copyright 2001, CodeFactory AB
- * Copyright 2001, Mikael Hallendal <micke@codefactory.se>
- *
- * Derived from e-cell-number by Chris Lahey <clahey@ximian.com>
- * ECellFloat - Float item for e-table.
- *
- * Author:
- * Mikael Hallendal <micke@codefactory.se>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_CELL_FLOAT_H_
-#define _E_CELL_FLOAT_H_
-
-#include <gal/e-table/e-cell-text.h>
-
-G_BEGIN_DECLS
-
-#define E_CELL_FLOAT_TYPE (e_cell_float_get_type ())
-#define E_CELL_FLOAT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_CELL_FLOAT_TYPE, ECellFloat))
-#define E_CELL_FLOAT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_CELL_FLOAT_TYPE, ECellFloatClass))
-#define E_IS_CELL_FLOAT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_CELL_FLOAT_TYPE))
-#define E_IS_CELL_FLOAT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_CELL_FLOAT_TYPE))
-
-typedef struct {
- ECellText base;
-} ECellFloat;
-
-typedef struct {
- ECellTextClass parent_class;
-} ECellFloatClass;
-
-GType e_cell_float_get_type (void);
-ECell *e_cell_float_new (const char *fontname, GtkJustification justify);
-
-G_END_DECLS
-
-#endif /* _E_CELL_FLOAT_H_ */
diff --git a/widgets/table/e-cell-number.c b/widgets/table/e-cell-number.c
deleted file mode 100644
index 8c8887df5a..0000000000
--- a/widgets/table/e-cell-number.c
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * e-cell-number.c - Number item for e-table.
- * Copyright 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <sys/time.h>
-#include <unistd.h>
-#include <gal/util/e-util.h>
-#include <gal/util/e-i18n.h>
-#include "e-cell-number.h"
-
-#define PARENT_TYPE e_cell_text_get_type ()
-
-static ECellTextClass *parent_class;
-
-static char *
-ecn_get_text(ECellText *cell, ETableModel *model, int col, int row)
-{
- return e_format_number(GPOINTER_TO_INT (e_table_model_value_at(model, col, row)));
-}
-
-static void
-ecn_free_text(ECellText *cell, char *text)
-{
- g_free(text);
-}
-
-static void
-e_cell_number_class_init (GtkObjectClass *object_class)
-{
- ECellTextClass *ectc = (ECellTextClass *) object_class;
-
- parent_class = g_type_class_ref (PARENT_TYPE);
-
- ectc->get_text = ecn_get_text;
- ectc->free_text = ecn_free_text;
-}
-
-static void
-e_cell_number_init (GtkObject *object)
-{
-}
-
-/**
- * e_cell_number_new:
- * @fontname: font to be used to render on the screen
- * @justify: Justification of the string in the cell.
- *
- * Creates a new ECell renderer that can be used to render numbers that
- * that come from the model. The value returned from the model is
- * interpreted as being an int.
- *
- * See ECellText for other features.
- *
- * Returns: an ECell object that can be used to render numbers.
- */
-ECell *
-e_cell_number_new (const char *fontname, GtkJustification justify)
-{
- ECellNumber *ecn = g_object_new (E_CELL_NUMBER_TYPE, NULL);
-
- e_cell_text_construct(E_CELL_TEXT(ecn), fontname, justify);
-
- return (ECell *) ecn;
-}
-
-E_MAKE_TYPE(e_cell_number, "ECellNumber", ECellNumber, e_cell_number_class_init, e_cell_number_init, PARENT_TYPE)
diff --git a/widgets/table/e-cell-number.h b/widgets/table/e-cell-number.h
deleted file mode 100644
index 3cce1ec412..0000000000
--- a/widgets/table/e-cell-number.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * e-cell-number.h - Number item for e-table.
- * Copyright 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_CELL_NUMBER_H_
-#define _E_CELL_NUMBER_H_
-
-#include <gal/e-table/e-cell-text.h>
-
-G_BEGIN_DECLS
-
-#define E_CELL_NUMBER_TYPE (e_cell_number_get_type ())
-#define E_CELL_NUMBER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_CELL_NUMBER_TYPE, ECellNumber))
-#define E_CELL_NUMBER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_CELL_NUMBER_TYPE, ECellNumberClass))
-#define E_IS_CELL_NUMBER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_CELL_NUMBER_TYPE))
-#define E_IS_CELL_NUMBER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_CELL_NUMBER_TYPE))
-
-typedef struct {
- ECellText base;
-} ECellNumber;
-
-typedef struct {
- ECellTextClass parent_class;
-} ECellNumberClass;
-
-GType e_cell_number_get_type (void);
-ECell *e_cell_number_new (const char *fontname, GtkJustification justify);
-
-G_END_DECLS
-
-#endif /* _E_CELL_NUMBER_H_ */
diff --git a/widgets/table/e-cell-pixbuf.c b/widgets/table/e-cell-pixbuf.c
deleted file mode 100644
index 50c3b2cc7a..0000000000
--- a/widgets/table/e-cell-pixbuf.c
+++ /dev/null
@@ -1,417 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-cell-pixbuf.c - An ECell that displays a GdkPixbuf
- * Copyright 2001, Ximian, Inc.
- *
- * Authors:
- * Vladimir Vukicevic <vladimir@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <stdio.h>
-#include <libgnomecanvas/gnome-canvas.h>
-#include "e-cell-pixbuf.h"
-#include <gal/util/e-i18n.h>
-
-#define PARENT_TYPE E_CELL_TYPE
-static ECellClass *parent_class;
-
-typedef struct _ECellPixbufView ECellPixbufView;
-
-struct _ECellPixbufView {
- ECellView cell_view;
- GnomeCanvas *canvas;
-};
-
-/* Object argument IDs */
-enum {
- PROP_0,
-
- PROP_SELECTED_COLUMN,
- PROP_FOCUSED_COLUMN,
- PROP_UNSELECTED_COLUMN
-};
-
-static int
-gnome_print_pixbuf (GnomePrintContext *pc, GdkPixbuf *pixbuf)
-{
- if (gdk_pixbuf_get_has_alpha (pixbuf))
- return gnome_print_rgbaimage (pc,
- gdk_pixbuf_get_pixels (pixbuf),
- gdk_pixbuf_get_width (pixbuf),
- gdk_pixbuf_get_height (pixbuf),
- gdk_pixbuf_get_rowstride (pixbuf));
- else
- return gnome_print_rgbimage (pc,
- gdk_pixbuf_get_pixels (pixbuf),
- gdk_pixbuf_get_width (pixbuf),
- gdk_pixbuf_get_height (pixbuf),
- gdk_pixbuf_get_rowstride (pixbuf));
-}
-
-/*
- * ECellPixbuf functions
- */
-
-ECell *
-e_cell_pixbuf_new (void)
-{
- ECellPixbuf *ecp;
-
- ecp = g_object_new (E_CELL_PIXBUF_TYPE, NULL);
- e_cell_pixbuf_construct (ecp);
-
- return (ECell *) ecp;
-}
-
-void
-e_cell_pixbuf_construct (ECellPixbuf *ecp)
-{
- /* noop */
- return;
-}
-
-/*
- * ECell methods
- */
-
-static ECellView *
-pixbuf_new_view (ECell *ecell, ETableModel *table_model, void *e_table_item_view)
-{
- ECellPixbufView *pixbuf_view = g_new0 (ECellPixbufView, 1);
- ETableItem *eti = E_TABLE_ITEM (e_table_item_view);
- GnomeCanvas *canvas = GNOME_CANVAS_ITEM (eti)->canvas;
-
- pixbuf_view->cell_view.ecell = ecell;
- pixbuf_view->cell_view.e_table_model = table_model;
- pixbuf_view->cell_view.e_table_item_view = e_table_item_view;
- pixbuf_view->canvas = canvas;
-
- return (ECellView *) pixbuf_view;
-}
-
-static void
-pixbuf_kill_view (ECellView *ecell_view)
-{
- ECellPixbufView *pixbuf_view = (ECellPixbufView *) ecell_view;
-
- g_free (pixbuf_view);
-}
-
-static void
-pixbuf_draw (ECellView *ecell_view, GdkDrawable *drawable,
- int model_col, int view_col, int row, ECellFlags flags,
- int x1, int y1, int x2, int y2)
-{
- GdkPixbuf *cell_pixbuf;
- int real_x, real_y, real_w, real_h;
- int pix_w, pix_h;
- ECellPixbuf *ecp;
-
- cell_pixbuf = NULL;
-
- ecp = E_CELL_PIXBUF (ecell_view->ecell);
-
- if (flags & E_CELL_SELECTED) {
- if (GTK_WIDGET_HAS_FOCUS (GNOME_CANVAS_ITEM (ecell_view->e_table_item_view)->canvas)) {
- if (ecp->focused_column != -1)
- cell_pixbuf = (GdkPixbuf *) e_table_model_value_at (ecell_view->e_table_model,
- ecp->focused_column, row);
- } else {
- if (ecp->selected_column != -1)
- cell_pixbuf = (GdkPixbuf *) e_table_model_value_at (ecell_view->e_table_model,
- ecp->selected_column, row);
- }
- } else {
- if (ecp->unselected_column != -1)
- cell_pixbuf = e_table_model_value_at (ecell_view->e_table_model,
- ecp->unselected_column, row);
- }
-
- if (cell_pixbuf == NULL)
- cell_pixbuf = e_table_model_value_at (ecell_view->e_table_model,
- model_col, row);
- /* we can't make sure we really got a pixbuf since, well, it's a Gdk thing */
-
- if (x2 - x1 == 0)
- return;
-
- if (!cell_pixbuf)
- return;
-
- pix_w = gdk_pixbuf_get_width (cell_pixbuf);
- pix_h = gdk_pixbuf_get_height (cell_pixbuf);
-
- /* We center the pixbuf within our allocated space */
- if (x2 - x1 > pix_w) {
- int diff = (x2 - x1) - pix_w;
- real_x = x1 + diff/2;
- real_w = pix_w;
- } else {
- real_x = x1;
- real_w = x2 - x1;
- }
-
- if (y2 - y1 > pix_h) {
- int diff = (y2 - y1) - pix_h;
- real_y = y1 + diff/2;
- real_h = pix_h;
- } else {
- real_y = y1;
- real_h = y2 - y1;
- }
-
-
- gdk_pixbuf_render_to_drawable_alpha (cell_pixbuf,
- drawable,
- 0, 0,
- real_x, real_y,
- real_w, real_h,
- GDK_PIXBUF_ALPHA_FULL,
- 127,
- GDK_RGB_DITHER_NORMAL,
- 0, 0);
-}
-
-static gint
-pixbuf_event (ECellView *ecell_view, GdkEvent *event,
- int model_col, int view_col, int row,
- ECellFlags flags, ECellActions *actions)
-{
- /* noop */
-
- return FALSE;
-}
-
-static gint
-pixbuf_height (ECellView *ecell_view, int model_col, int view_col, int row)
-{
- GdkPixbuf *pixbuf;
- if (row == -1) {
- if (e_table_model_row_count (ecell_view->e_table_model) > 0) {
- row = 0;
- } else {
- return 6;
- }
- }
-
- pixbuf = (GdkPixbuf *) e_table_model_value_at (ecell_view->e_table_model, model_col, row);
- if (!pixbuf)
- return 0;
-
- /* We give ourselves 3 pixels of padding on either side */
- return gdk_pixbuf_get_height (pixbuf) + 6;
-}
-
-/*
- * ECell::print method
- */
-static void
-pixbuf_print (ECellView *ecell_view, GnomePrintContext *context,
- int model_col, int view_col, int row,
- double width, double height)
-{
- GdkPixbuf *pixbuf;
- int scale;
-
- pixbuf = (GdkPixbuf *) e_table_model_value_at (ecell_view->e_table_model, model_col, row);
- if (pixbuf == NULL)
- return;
- scale = gdk_pixbuf_get_height (pixbuf);
-
- gnome_print_gsave(context);
-
- gnome_print_translate (context, 0, (height - scale) / 2);
- gnome_print_scale (context, scale, scale);
- gnome_print_pixbuf (context, pixbuf);
-
- gnome_print_grestore(context);
-}
-
-static gdouble
-pixbuf_print_height (ECellView *ecell_view, GnomePrintContext *context,
- int model_col, int view_col, int row,
- double width)
-{
- GdkPixbuf *pixbuf;
-
- if (row == -1) {
- if (e_table_model_row_count (ecell_view->e_table_model) > 0) {
- row = 0;
- } else {
- return 6;
- }
- }
-
- pixbuf = (GdkPixbuf *) e_table_model_value_at (ecell_view->e_table_model, model_col, row);
- if (!pixbuf)
- return 0;
-
- /* We give ourselves 3 pixels of padding on either side */
- return gdk_pixbuf_get_height (pixbuf);
-}
-
-static gint
-pixbuf_max_width (ECellView *ecell_view, int model_col, int view_col)
-{
- int pw;
- gint num_rows, i;
- gint max_width = -1;
-
- if (model_col == 0) {
- num_rows = e_table_model_row_count (ecell_view->e_table_model);
-
- for (i = 0; i <= num_rows; i++) {
- GdkPixbuf *pixbuf = (GdkPixbuf *) e_table_model_value_at
- (ecell_view->e_table_model,
- model_col,
- i);
- if (!pixbuf)
- continue;
- pw = gdk_pixbuf_get_width (pixbuf);
- if (max_width < pw)
- max_width = pw;
- }
- } else {
- return -1;
- }
-
- return max_width;
-}
-
-static void
-pixbuf_dispose (GObject *object)
-{
- if (G_OBJECT_CLASS (parent_class)->dispose)
- (* G_OBJECT_CLASS (parent_class)->dispose) (object);
-}
-
-static void
-pixbuf_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- ECellPixbuf *pixbuf;
-
- pixbuf = E_CELL_PIXBUF (object);
-
- switch (prop_id) {
- case PROP_SELECTED_COLUMN:
- pixbuf->selected_column = g_value_get_int (value);
- break;
-
- case PROP_FOCUSED_COLUMN:
- pixbuf->focused_column = g_value_get_int (value);
- break;
-
- case PROP_UNSELECTED_COLUMN:
- pixbuf->unselected_column = g_value_get_int (value);
- break;
-
- default:
- return;
- }
-}
-
-/* Get_arg handler for the pixbuf item */
-static void
-pixbuf_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- ECellPixbuf *pixbuf;
-
- pixbuf = E_CELL_PIXBUF (object);
-
- switch (prop_id) {
- case PROP_SELECTED_COLUMN:
- g_value_set_int (value, pixbuf->selected_column);
- break;
-
- case PROP_FOCUSED_COLUMN:
- g_value_set_int (value, pixbuf->focused_column);
- break;
-
- case PROP_UNSELECTED_COLUMN:
- g_value_set_int (value, pixbuf->unselected_column);
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-e_cell_pixbuf_init (GtkObject *object)
-{
- ECellPixbuf *ecp = E_CELL_PIXBUF (object);
-
- ecp->selected_column = -1;
- ecp->focused_column = -1;
- ecp->unselected_column = -1;
-}
-
-static void
-e_cell_pixbuf_class_init (GObjectClass *object_class)
-{
- ECellClass *ecc = (ECellClass *) object_class;
-
- object_class->dispose = pixbuf_dispose;
- object_class->set_property = pixbuf_set_property;
- object_class->get_property = pixbuf_get_property;
-
- ecc->new_view = pixbuf_new_view;
- ecc->kill_view = pixbuf_kill_view;
- ecc->draw = pixbuf_draw;
- ecc->event = pixbuf_event;
- ecc->height = pixbuf_height;
- ecc->print = pixbuf_print;
- ecc->print_height = pixbuf_print_height;
- ecc->max_width = pixbuf_max_width;
-
- parent_class = g_type_class_ref (PARENT_TYPE);
-
- g_object_class_install_property (object_class, PROP_SELECTED_COLUMN,
- g_param_spec_int ("selected_column",
- _("Selected Column"),
- /*_( */"XXX blurb" /*)*/,
- 0, G_MAXINT, 0,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class, PROP_FOCUSED_COLUMN,
- g_param_spec_int ("focused_column",
- _("Focused Column"),
- /*_( */"XXX blurb" /*)*/,
- 0, G_MAXINT, 0,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class, PROP_UNSELECTED_COLUMN,
- g_param_spec_int ("unselected_column",
- _("Unselected Column"),
- /*_( */"XXX blurb" /*)*/,
- 0, G_MAXINT, 0,
- G_PARAM_READWRITE));
-}
-
-E_MAKE_TYPE (e_cell_pixbuf,
- "ECellPixbuf",
- ECellPixbuf,
- e_cell_pixbuf_class_init,
- e_cell_pixbuf_init,
- PARENT_TYPE)
diff --git a/widgets/table/e-cell-pixbuf.h b/widgets/table/e-cell-pixbuf.h
deleted file mode 100644
index 2f12521d58..0000000000
--- a/widgets/table/e-cell-pixbuf.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * e-cell-pixbuf.h - An ECell that displays a GdkPixbuf
- * Copyright 2001, Ximian, Inc.
- *
- * Authors:
- * Vladimir Vukicevic <vladimir@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_CELL_PIXBUF_H_
-#define _E_CELL_PIXBUF_H_
-
-#include <gal/e-table/e-table.h>
-
-#define E_CELL_PIXBUF_TYPE (e_cell_pixbuf_get_type ())
-#define E_CELL_PIXBUF(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_CELL_PIXBUF_TYPE, ECellPixbuf))
-#define E_CELL_PIXBUF_CLASS(k) (G_TYPE_CHECK_INSTANCE_CAST_CLASS ((k), E_CELL_PIXBUF_TYPE, ECellPixbufClass))
-#define E_IS_CELL_PIXBUF(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_CELL_PIXBUF_TYPE))
-#define E_IS_CELL_PIXBUF_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_CELL_PIXBUF_TYPE))
-
-typedef struct _ECellPixbuf ECellPixbuf;
-typedef struct _ECellPixbufClass ECellPixbufClass;
-
-struct _ECellPixbuf {
- ECell parent;
-
- int selected_column;
- int focused_column;
- int unselected_column;
-};
-
-struct _ECellPixbufClass {
- ECellClass parent_class;
-};
-
-GType e_cell_pixbuf_get_type (void);
-ECell *e_cell_pixbuf_new (void);
-void e_cell_pixbuf_construct (ECellPixbuf *ecp);
-
-#endif
diff --git a/widgets/table/e-cell-popup.c b/widgets/table/e-cell-popup.c
deleted file mode 100644
index 50943d6004..0000000000
--- a/widgets/table/e-cell-popup.c
+++ /dev/null
@@ -1,519 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-cell-popup.c: Popup cell renderer
- * Copyright 2001, Ximian, Inc.
- *
- * Authors:
- * Damon Chaplin <damon@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA. */
-
-/*
- * ECellPopup - an abstract ECell class used to support popup selections like
- * a GtkCombo widget. It contains a child ECell, e.g. an ECellText, but when
- * selected it displays an arrow on the right edge which the user can click to
- * show a popup. Subclasses implement the popup class function to show the
- * popup.
- */
-
-#include <config.h>
-#include <gdk/gdkkeysyms.h>
-#include "gal/util/e-util.h"
-#include "e-table-item.h"
-#include "e-cell-popup.h"
-#include "gal/a11y/e-table/gal-a11y-e-cell-popup.h"
-#include "gal/a11y/e-table/gal-a11y-e-cell-registry.h"
-
-#define E_CELL_POPUP_ARROW_WIDTH 16
-#define E_CELL_POPUP_ARROW_XPAD 3
-#define E_CELL_POPUP_ARROW_YPAD 3
-
-
-static void e_cell_popup_class_init (GtkObjectClass *object_class);
-static void e_cell_popup_init (ECellPopup *ecp);
-static void e_cell_popup_dispose (GObject *object);
-
-
-static ECellView* ecp_new_view (ECell *ecell,
- ETableModel *table_model,
- void *e_table_item_view);
-static void ecp_kill_view (ECellView *ecv);
-static void ecp_realize (ECellView *ecv);
-static void ecp_unrealize (ECellView *ecv);
-static void ecp_draw (ECellView *ecv,
- GdkDrawable *drawable,
- int model_col,
- int view_col,
- int row,
- ECellFlags flags,
- int x1,
- int y1,
- int x2,
- int y2);
-static gint ecp_event (ECellView *ecv,
- GdkEvent *event,
- int model_col,
- int view_col,
- int row,
- ECellFlags flags,
- ECellActions *actions);
-static int ecp_height (ECellView *ecv,
- int model_col,
- int view_col,
- int row);
-static void* ecp_enter_edit (ECellView *ecv,
- int model_col,
- int view_col,
- int row);
-static void ecp_leave_edit (ECellView *ecv,
- int model_col,
- int view_col,
- int row,
- void *edit_context);
-static void ecp_print (ECellView *ecv,
- GnomePrintContext *context,
- int model_col,
- int view_col,
- int row,
- double width,
- double height);
-static gdouble ecp_print_height (ECellView *ecv,
- GnomePrintContext *context,
- int model_col,
- int view_col,
- int row,
- double width);
-static int ecp_max_width (ECellView *ecv,
- int model_col,
- int view_col);
-static void ecp_show_tooltip (ECellView *ecv,
- int model_col,
- int view_col,
- int row,
- int col_width,
- ETableTooltip *tooltip);
-static char *ecp_get_bg_color (ECellView *ecell_view, int row);
-
-static gint e_cell_popup_do_popup (ECellPopupView *ecp_view,
- GdkEvent *event,
- int row,
- int model_col);
-
-static ECellClass *parent_class;
-
-
-E_MAKE_TYPE (e_cell_popup, "ECellPopup", ECellPopup, e_cell_popup_class_init,
- e_cell_popup_init, e_cell_get_type())
-
-
-static void
-e_cell_popup_class_init (GtkObjectClass *object_class)
-{
- ECellClass *ecc = (ECellClass *) object_class;
-
- G_OBJECT_CLASS (object_class)->dispose = e_cell_popup_dispose;
-
- ecc->new_view = ecp_new_view;
- ecc->kill_view = ecp_kill_view;
- ecc->realize = ecp_realize;
- ecc->unrealize = ecp_unrealize;
- ecc->draw = ecp_draw;
- ecc->event = ecp_event;
- ecc->height = ecp_height;
- ecc->enter_edit = ecp_enter_edit;
- ecc->leave_edit = ecp_leave_edit;
- ecc->print = ecp_print;
- ecc->print_height = ecp_print_height;
- ecc->max_width = ecp_max_width;
- ecc->show_tooltip = ecp_show_tooltip;
- ecc->get_bg_color = ecp_get_bg_color;
-
- parent_class = g_type_class_ref (E_CELL_TYPE);
- gal_a11y_e_cell_registry_add_cell_type (NULL,
- E_CELL_POPUP_TYPE,
- gal_a11y_e_cell_popup_new);
-}
-
-
-static void
-e_cell_popup_init (ECellPopup *ecp)
-{
- ecp->popup_shown = FALSE;
- ecp->popup_model = NULL;
-}
-
-
-/**
- * e_cell_popup_new:
- *
- * Creates a new ECellPopup renderer.
- *
- * Returns: an ECellPopup object.
- */
-ECell *
-e_cell_popup_new (void)
-{
- ECellPopup *ecp = g_object_new (E_CELL_POPUP_TYPE, NULL);
-
- return (ECell*) ecp;
-}
-
-
-/*
- * GtkObject::destroy method
- */
-static void
-e_cell_popup_dispose (GObject *object)
-{
- ECellPopup *ecp = E_CELL_POPUP (object);
-
- if (ecp->child)
- g_object_unref (ecp->child);
- ecp->child = NULL;
-
- G_OBJECT_CLASS (parent_class)->dispose (object);
-}
-
-
-
-/*
- * ECell::new_view method
- */
-static ECellView *
-ecp_new_view (ECell *ecell, ETableModel *table_model, void *e_table_item_view)
-{
- ECellPopup *ecp = E_CELL_POPUP (ecell);
- ECellPopupView *ecp_view;
-
- /* We must have a child ECell before we create any views. */
- g_return_val_if_fail (ecp->child != NULL, NULL);
-
- ecp_view = g_new0 (ECellPopupView, 1);
-
- ecp_view->cell_view.ecell = ecell;
- ecp_view->cell_view.e_table_model = table_model;
- ecp_view->cell_view.e_table_item_view = e_table_item_view;
-
- ecp_view->child_view = e_cell_new_view (ecp->child, table_model,
- e_table_item_view);
-
- return (ECellView*) ecp_view;
-}
-
-
-/*
- * ECell::kill_view method
- */
-static void
-ecp_kill_view (ECellView *ecv)
-{
- ECellPopupView *ecp_view = (ECellPopupView *) ecv;
-
- if (ecp_view->child_view)
- e_cell_kill_view (ecp_view->child_view);
- g_free (ecp_view);
-}
-
-
-/*
- * ECell::realize method
- */
-static void
-ecp_realize (ECellView *ecv)
-{
- ECellPopupView *ecp_view = (ECellPopupView *) ecv;
-
- e_cell_realize (ecp_view->child_view);
-
- if (parent_class->realize)
- (* parent_class->realize) (ecv);
-}
-
-
-/*
- * ECell::unrealize method
- */
-static void
-ecp_unrealize (ECellView *ecv)
-{
- ECellPopupView *ecp_view = (ECellPopupView *) ecv;
-
- e_cell_unrealize (ecp_view->child_view);
-
- if (parent_class->unrealize)
- (* parent_class->unrealize) (ecv);
-}
-
-
-/*
- * ECell::draw method
- */
-static void
-ecp_draw (ECellView *ecv, GdkDrawable *drawable,
- int model_col, int view_col, int row, ECellFlags flags,
- int x1, int y1, int x2, int y2)
-{
- ECellPopup *ecp = E_CELL_POPUP (ecv->ecell);
- ECellPopupView *ecp_view = (ECellPopupView *) ecv;
- GtkWidget *canvas = GTK_WIDGET (GNOME_CANVAS_ITEM (ecv->e_table_item_view)->canvas);
- GtkShadowType shadow;
- GdkRectangle rect;
- gboolean show_popup_arrow;
-
- /* Display the popup arrow if we are the cursor cell, or the popup
- is shown for this cell. */
- show_popup_arrow = e_table_model_is_cell_editable (ecv->e_table_model, model_col, row) &&
- (flags & E_CELL_CURSOR ||
- (ecp->popup_shown && ecp->popup_view_col == view_col
- && ecp->popup_row == row
- && ecp->popup_model == ((ECellView *) ecp_view)->e_table_model));
-
- if (flags & E_CELL_CURSOR)
- ecp->popup_arrow_shown = show_popup_arrow;
-
- if (show_popup_arrow) {
- e_cell_draw (ecp_view->child_view, drawable, model_col,
- view_col, row, flags,
- x1, y1, x2 - E_CELL_POPUP_ARROW_WIDTH, y2);
-
- rect.x = x2 - E_CELL_POPUP_ARROW_WIDTH;
- rect.y = y1 + 1;
- rect.width = E_CELL_POPUP_ARROW_WIDTH;
- rect.height = y2 - y1 - 2;
-
- if (ecp->popup_shown)
- shadow = GTK_SHADOW_IN;
- else
- shadow = GTK_SHADOW_OUT;
-
- gtk_paint_box (canvas->style, drawable,
- GTK_STATE_NORMAL, shadow,
- &rect, canvas, "ecellpopup",
- rect.x, rect.y, rect.width, rect.height);
- gtk_paint_arrow (canvas->style, drawable,
- GTK_STATE_NORMAL, GTK_SHADOW_NONE,
- &rect, canvas, NULL,
- GTK_ARROW_DOWN, TRUE,
- rect.x + E_CELL_POPUP_ARROW_XPAD,
- rect.y + E_CELL_POPUP_ARROW_YPAD,
- rect.width - E_CELL_POPUP_ARROW_XPAD * 2,
- rect.height - E_CELL_POPUP_ARROW_YPAD * 2);
- } else {
- e_cell_draw (ecp_view->child_view, drawable, model_col,
- view_col, row, flags, x1, y1, x2, y2);
- }
-}
-
-
-/*
- * ECell::event method
- */
-static gint
-ecp_event (ECellView *ecv, GdkEvent *event, int model_col, int view_col,
- int row, ECellFlags flags, ECellActions *actions)
-{
- ECellPopupView *ecp_view = (ECellPopupView *) ecv;
- ECellPopup *ecp = E_CELL_POPUP (ecp_view->cell_view.ecell);
- ETableItem *eti = E_TABLE_ITEM (ecv->e_table_item_view);
- int width;
-
- switch (event->type) {
- case GDK_BUTTON_PRESS:
- if (e_table_model_is_cell_editable (ecv->e_table_model, model_col, row) &&
- flags & E_CELL_CURSOR
- && ecp->popup_arrow_shown) {
- width = e_table_header_col_diff (eti->header, view_col,
- view_col + 1);
-
- /* FIXME: The event coords seem to be relative to the
- text within the cell, so we have to add 4. */
- if (event->button.x + 4 >= width - E_CELL_POPUP_ARROW_WIDTH) {
- return e_cell_popup_do_popup (ecp_view, event, row, view_col);
- }
- }
- break;
- case GDK_KEY_PRESS:
- if (e_table_model_is_cell_editable (ecv->e_table_model, model_col, row) &&
- event->key.state & GDK_MOD1_MASK
- && event->key.keyval == GDK_Down) {
- return e_cell_popup_do_popup (ecp_view, event, row, view_col);
- }
- break;
- default:
- break;
- }
-
- return e_cell_event (ecp_view->child_view, event, model_col, view_col,
- row, flags, actions);
-}
-
-
-/*
- * ECell::height method
- */
-static int
-ecp_height (ECellView *ecv, int model_col, int view_col, int row)
-{
- ECellPopupView *ecp_view = (ECellPopupView *) ecv;
-
- return e_cell_height (ecp_view->child_view, model_col, view_col, row);
-}
-
-
-/*
- * ECellView::enter_edit method
- */
-static void *
-ecp_enter_edit (ECellView *ecv, int model_col, int view_col, int row)
-{
- ECellPopupView *ecp_view = (ECellPopupView *) ecv;
-
- return e_cell_enter_edit (ecp_view->child_view, model_col, view_col, row);
-}
-
-
-/*
- * ECellView::leave_edit method
- */
-static void
-ecp_leave_edit (ECellView *ecv, int model_col, int view_col, int row,
- void *edit_context)
-{
- ECellPopupView *ecp_view = (ECellPopupView *) ecv;
-
- e_cell_leave_edit (ecp_view->child_view, model_col, view_col, row,
- edit_context);
-}
-
-
-static void
-ecp_print (ECellView *ecv, GnomePrintContext *context,
- int model_col, int view_col, int row, double width, double height)
-{
- ECellPopupView *ecp_view = (ECellPopupView *) ecv;
-
- e_cell_print (ecp_view->child_view, context, model_col, view_col, row,
- width, height);
-}
-
-
-static gdouble
-ecp_print_height (ECellView *ecv, GnomePrintContext *context,
- int model_col, int view_col, int row,
- double width)
-{
- ECellPopupView *ecp_view = (ECellPopupView *) ecv;
-
- return e_cell_print_height (ecp_view->child_view, context, model_col,
- view_col, row, width);
-}
-
-
-static int
-ecp_max_width (ECellView *ecv,
- int model_col,
- int view_col)
-{
- ECellPopupView *ecp_view = (ECellPopupView *) ecv;
-
- return e_cell_max_width (ecp_view->child_view, model_col, view_col);
-}
-
-
-static void
-ecp_show_tooltip (ECellView *ecv,
- int model_col,
- int view_col,
- int row,
- int col_width,
- ETableTooltip *tooltip)
-{
- ECellPopupView *ecp_view = (ECellPopupView *) ecv;
-
- e_cell_show_tooltip (ecp_view->child_view, model_col, view_col, row,
- col_width, tooltip);
-}
-
-static char *
-ecp_get_bg_color (ECellView *ecell_view, int row)
-{
- ECellPopupView *ecp_view = (ECellPopupView *) ecell_view;
-
- return e_cell_get_bg_color (ecp_view->child_view, row);
-}
-
-
-
-ECell*
-e_cell_popup_get_child (ECellPopup *ecp)
-{
- g_return_val_if_fail (E_IS_CELL_POPUP (ecp), NULL);
-
- return ecp->child;
-}
-
-
-void
-e_cell_popup_set_child (ECellPopup *ecp,
- ECell *child)
-{
- g_return_if_fail (E_IS_CELL_POPUP (ecp));
-
- if (ecp->child)
- g_object_unref (ecp->child);
-
- ecp->child = child;
- g_object_ref (child);
-}
-
-
-static gint
-e_cell_popup_do_popup (ECellPopupView *ecp_view,
- GdkEvent *event,
- int row,
- int view_col)
-{
- ECellPopup *ecp = E_CELL_POPUP (ecp_view->cell_view.ecell);
- gint (*popup_func) (ECellPopup *ecp, GdkEvent *event, int row, int view_col);
-
- ecp->popup_cell_view = ecp_view;
-
- popup_func = E_CELL_POPUP_CLASS (GTK_OBJECT_GET_CLASS (ecp))->popup;
-
- ecp->popup_view_col = view_col;
- ecp->popup_row = row;
- ecp->popup_model = ((ECellView *) ecp_view)->e_table_model;
-
- return popup_func ? popup_func (ecp, event, row, view_col) : FALSE;
-}
-
-/* This redraws the popup cell. Only use this if you know popup_view_col and
- popup_row are valid. */
-void
-e_cell_popup_queue_cell_redraw (ECellPopup *ecp)
-{
- ETableItem *eti = E_TABLE_ITEM (ecp->popup_cell_view->cell_view.e_table_item_view);
-
- e_table_item_redraw_range (eti, ecp->popup_view_col, ecp->popup_row,
- ecp->popup_view_col, ecp->popup_row);
-}
-
-void
-e_cell_popup_set_shown (ECellPopup *ecp,
- gboolean shown)
-{
- ecp->popup_shown = shown;
- e_cell_popup_queue_cell_redraw (ecp);
-}
diff --git a/widgets/table/e-cell-popup.h b/widgets/table/e-cell-popup.h
deleted file mode 100644
index 26a7429127..0000000000
--- a/widgets/table/e-cell-popup.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-cell-popup.h: Popup cell renderer
- * Copyright 2001, Ximian, Inc.
- *
- * Authors:
- * Damon Chaplin <damon@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-/*
- * ECellPopup - an ECell used to support popup selections like a GtkCombo
- * widget. It contains a child ECell, e.g. an ECellText, but when selected it
- * displays an arrow on the right edge which the user can click to show a
- * popup. It will support subclassing or signals so that different types of
- * popup can be provided.
- */
-
-#ifndef _E_CELL_POPUP_H_
-#define _E_CELL_POPUP_H_
-
-#include <libgnomecanvas/gnome-canvas.h>
-#include <gal/e-table/e-cell.h>
-
-#define E_CELL_POPUP_TYPE (e_cell_popup_get_type ())
-#define E_CELL_POPUP(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_CELL_POPUP_TYPE, ECellPopup))
-#define E_CELL_POPUP_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_CELL_POPUP_TYPE, ECellPopupClass))
-#define E_IS_CELL_POPUP(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_CELL_POPUP_TYPE))
-#define E_IS_CELL_POPUP_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_CELL_POPUP_TYPE))
-
-typedef struct _ECellPopupView ECellPopupView;
-
-typedef struct {
- ECell parent;
-
- ECell *child;
-
- /* This is TRUE if the popup window is shown for the cell being
- edited. While shown we display the arrow indented. */
- gboolean popup_shown;
-
- /* This is TRUE if the popup arrow is shown for the cell being edited.
- This is needed to stop the first click on the cell from popping up
- the popup window. We only popup the window after we have drawn the
- arrow. */
- gboolean popup_arrow_shown;
-
- /* The view in which the popup is shown. */
- ECellPopupView *popup_cell_view;
-
- gint popup_view_col;
- gint popup_row;
- ETableModel *popup_model;
-} ECellPopup;
-
-
-typedef struct {
- ECellClass parent_class;
-
- /* Virtual function for subclasses to override. */
- gint (*popup) (ECellPopup *ecp, GdkEvent *event, int row, int view_col);
-} ECellPopupClass;
-
-
-struct _ECellPopupView {
- ECellView cell_view;
-
- ECellView *child_view;
-};
-
-
-GType e_cell_popup_get_type (void);
-ECell *e_cell_popup_new (void);
-
-/* Get and set the child ECell. */
-ECell *e_cell_popup_get_child (ECellPopup *ecp);
-void e_cell_popup_set_child (ECellPopup *ecp,
- ECell *child);
-
-void e_cell_popup_set_shown (ECellPopup *ecp,
- gboolean shown);
-void e_cell_popup_queue_cell_redraw (ECellPopup *ecp);
-
-void e_cell_popup_set_shown (ECellPopup *ecp,
- gboolean shown);
-void e_cell_popup_queue_cell_redraw (ECellPopup *ecp);
-
-#endif /* _E_CELL_POPUP_H_ */
diff --git a/widgets/table/e-cell-progress.c b/widgets/table/e-cell-progress.c
deleted file mode 100644
index bf7fdd9951..0000000000
--- a/widgets/table/e-cell-progress.c
+++ /dev/null
@@ -1,456 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-cell-progress.c - Progress display cell object.
- * Copyright 1999-2002, Ximian, Inc.
- * Copyright 2001, 2002, Krisztian Pifko <monsta@users.sourceforge.net>
- *
- * Authors:
- * Krisztian Pifko <monsta@users.sourceforge.net>
- *
- * A cell type for displaying progress bars.
- *
- * Derived from ECellToggle of Miguel de Icaza <miguel@ximian.com>.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <string.h>
-
-#include <gtk/gtkenums.h>
-#include <gtk/gtkentry.h>
-#include <gtk/gtkwindow.h>
-#include <gtk/gtksignal.h>
-#include <gdk/gdkkeysyms.h>
-#include <libgnomecanvas/gnome-canvas.h>
-#include "e-cell-progress.h"
-#include "gal/util/e-util.h"
-#include "e-table-item.h"
-
-#define PARENT_TYPE e_cell_get_type ()
-
-typedef struct {
- ECellView cell_view;
- GdkGC *gc;
- GnomeCanvas *canvas;
-} ECellProgressView;
-
-static ECellClass *parent_class;
-
-static void
-eprog_queue_redraw (ECellProgressView *text_view, int view_col, int view_row)
-{
- e_table_item_redraw_range (
- text_view->cell_view.e_table_item_view,
- view_col, view_row, view_col, view_row);
-}
-
-/*
- * ECell::realize method
- */
-static ECellView *
-eprog_new_view (ECell *ecell, ETableModel *table_model, void *e_table_item_view)
-{
- ECellProgressView *progress_view = g_new0 (ECellProgressView, 1);
- ETableItem *eti = E_TABLE_ITEM (e_table_item_view);
- GnomeCanvas *canvas = GNOME_CANVAS_ITEM (eti)->canvas;
-
- progress_view->cell_view.ecell = ecell;
- progress_view->cell_view.e_table_model = table_model;
- progress_view->cell_view.e_table_item_view = e_table_item_view;
- progress_view->canvas = canvas;
-
- return (ECellView *) progress_view;
-}
-
-static void
-eprog_kill_view (ECellView *ecell_view)
-{
- g_free (ecell_view);
-}
-
-static void
-eprog_realize (ECellView *ecell_view)
-{
- ECellProgressView *progress_view = (ECellProgressView *) ecell_view;
-
- progress_view->gc = gdk_gc_new (GTK_WIDGET (progress_view->canvas)->window);
-}
-
-/*
- * ECell::unrealize method
- */
-static void
-eprog_unrealize (ECellView *ecv)
-{
- ECellProgressView *progress_view = (ECellProgressView *) ecv;
-
- gdk_gc_unref (progress_view->gc);
- progress_view->gc = NULL;
-}
-
-static void
-eprog_clear (ECellProgress *progress)
-{
- memset(progress->buffer,0x00,progress->width*progress->height*4);
-}
-
-static void
-eprog_draw_border (ECellProgress *progress, guchar red, guchar green, guchar blue)
-{
- gint i, j, w4, p4, pw4, wpb4, hp1;
-
-/*
- * some speedup
- */
- w4=progress->width*4;
- p4=progress->padding*4;
- pw4=w4*progress->padding;
- wpb4=(progress->width-progress->padding-progress->border)*4;
- hp1=(progress->height-progress->padding-1);
-
- for (i=progress->padding*4;i<(progress->width-progress->padding)*4;i+=4){
- for (j=0;j<progress->border;j++){
- progress->buffer[pw4+j*w4+i]=red;
- progress->buffer[pw4+j*w4+i+1]=green;
- progress->buffer[pw4+j*w4+i+2]=blue;
- progress->buffer[pw4+j*w4+i+3]=255;
- progress->buffer[(progress->height-1-progress->padding)*w4-j*w4+i]=red;
- progress->buffer[(progress->height-1-progress->padding)*w4-j*w4+i+1]=green;
- progress->buffer[(progress->height-1-progress->padding)*w4-j*w4+i+2]=blue;
- progress->buffer[(progress->height-1-progress->padding)*w4-j*w4+i+3]=255;
- }
- }
- for (i=progress->padding+progress->border;i<progress->height-progress->padding-progress->border;i++){
- for (j=0;j<4*progress->border;j+=4){
- progress->buffer[p4+i*w4+j]=red;
- progress->buffer[p4+i*w4+j+1]=green;
- progress->buffer[p4+i*w4+j+2]=blue;
- progress->buffer[p4+i*w4+j+3]=255;
- progress->buffer[i*w4+wpb4+j]=red;
- progress->buffer[i*w4+wpb4+j+1]=green;
- progress->buffer[i*w4+wpb4+j+2]=blue;
- progress->buffer[i*w4+wpb4+j+3]=255;
- }
- }
-}
-
-static void
-eprog_draw_bar (ECellProgress *progress, guchar red, guchar green, guchar blue, gint value)
-{
- gint i, j, w;
-
- w=value*(progress->width-2*(progress->padding+progress->border+1))/progress->max;
- for (i=(progress->padding+progress->border+1)*4;i<(progress->padding+progress->border+1+w)*4;i+=4){
- for (j=0;j<progress->height-2*(progress->padding+progress->border+1);j++){
- progress->buffer[(progress->width*(progress->padding+progress->border+1)*4)+j*progress->width*4+i]=red;
- progress->buffer[(progress->width*(progress->padding+progress->border+1)*4)+j*progress->width*4+i+1]=green;
- progress->buffer[(progress->width*(progress->padding+progress->border+1)*4)+j*progress->width*4+i+2]=blue;
- progress->buffer[(progress->width*(progress->padding+progress->border+1)*4)+j*progress->width*4+i+3]=255;
- }
- }
-}
-
-/*
- * ECell::draw method
- */
-static void
-eprog_draw (ECellView *ecell_view, GdkDrawable *drawable,
- int model_col, int view_col, int row, ECellFlags flags,
- int x1, int y1, int x2, int y2)
-{
- ECellProgress *progress = E_CELL_PROGRESS (ecell_view->ecell);
- gboolean selected;
- GdkPixbuf *image;
- int x, y, width, height;
-
- const int value = GPOINTER_TO_INT (
- e_table_model_value_at (ecell_view->e_table_model, model_col, row));
-
- selected = flags & E_CELL_SELECTED;
-
- if ((value > progress->max)||(value < progress->min)){
- g_warning ("Value from the table model is %d, the states we support are [%d..%d]\n",
- value, progress->min, progress->max);
- return;
- }
-
- image = progress->image;
-
- if ((x2 - x1) < progress->width){
- x = x1;
- width = x2 - x1;
- } else {
- x = x1 + ((x2 - x1) - progress->width) / 2;
- width = progress->width;
- }
-
- if ((y2 - y1) < progress->height){
- y = y1;
- height = y2 - y1;
- } else {
- y = y1 + ((y2 - y1) - progress->height) / 2;
- height = progress->height;
- }
-
- eprog_clear(progress);
-
- eprog_draw_border(progress, progress->red, progress->green, progress->blue);
-
- eprog_draw_bar(progress, progress->red, progress->green, progress->blue, value);
-
- gdk_pixbuf_render_to_drawable_alpha (progress->image, drawable,
- 0, 0,
- x, y,
- progress->width, progress->height,
- GDK_PIXBUF_ALPHA_BILEVEL,
- 128,
- GDK_RGB_DITHER_NORMAL,
- x, y);
-}
-
-static void
-eprog_set_value (ECellProgressView *progress_view, int model_col, int view_col, int row, int value)
-{
- ECell *ecell = progress_view->cell_view.ecell;
- ECellProgress *progress = E_CELL_PROGRESS (ecell);
-
- if (value > progress->max){
- value = progress->max;
- }else if (value < progress->min){
- value = progress->min;
- }
- e_table_model_set_value_at (progress_view->cell_view.e_table_model,
- model_col, row, GINT_TO_POINTER (value));
- eprog_queue_redraw (progress_view, view_col, row);
-}
-
-/*
- * ECell::event method
- */
-static gint
-eprog_event (ECellView *ecell_view, GdkEvent *event, int model_col, int view_col, int row, ECellFlags flags, ECellActions *actions)
-{
- ECellProgressView *progress_view = (ECellProgressView *) ecell_view;
- void *_value = e_table_model_value_at (ecell_view->e_table_model, model_col, row);
- const int value = GPOINTER_TO_INT (_value);
-
-#if 0
- if (!(flags & E_CELL_EDITING))
- return FALSE;
-#endif
-
- switch (event->type){
- case GDK_KEY_PRESS:
- if (event->key.keyval != GDK_space)
- return FALSE;
- /* Fall through */
- case GDK_BUTTON_PRESS:
- if (!e_table_model_is_cell_editable(ecell_view->e_table_model, model_col, row))
- return FALSE;
-
- eprog_set_value (progress_view, model_col, view_col, row, value + 1);
- return TRUE;
-
- default:
- return FALSE;
- }
- return TRUE;
-}
-
-/*
- * ECell::height method
- */
-static int
-eprog_height (ECellView *ecell_view, int model_col, int view_col, int row)
-{
- ECellProgress *progress = E_CELL_PROGRESS (ecell_view->ecell);
-
- return progress->height;
-}
-
-/*
- * ECell::max_width method
- */
-static int
-eprog_max_width (ECellView *ecell_view, int model_col, int view_col)
-{
- ECellProgress *progress = E_CELL_PROGRESS (ecell_view->ecell);
-
- return progress->width;
-}
-
-static void
-eprog_dispose (GObject *object)
-{
- ECellProgress *eprog = E_CELL_PROGRESS (object);
-
- gdk_pixbuf_unref (eprog->image);
- g_free (eprog->image);
- g_free (eprog->buffer);
-
- G_OBJECT_CLASS (parent_class)->dispose (object);
-}
-
-static void
-e_cell_progress_class_init (GObjectClass *object_class)
-{
- ECellClass *ecc = (ECellClass *) object_class;
-
- object_class->dispose = eprog_dispose;
-
- ecc->new_view = eprog_new_view;
- ecc->kill_view = eprog_kill_view;
- ecc->realize = eprog_realize;
- ecc->unrealize = eprog_unrealize;
- ecc->draw = eprog_draw;
- ecc->event = eprog_event;
- ecc->height = eprog_height;
- ecc->max_width = eprog_max_width;
-
- parent_class = g_type_class_ref (PARENT_TYPE);
-}
-
-E_MAKE_TYPE(e_cell_progress, "ECellProgress", ECellProgress, e_cell_progress_class_init, NULL, PARENT_TYPE);
-
-/**
- * e_cell_progress_construct:
- * @eprog: a fresh ECellProgress object
- * @padding: number of pixels used as a padding
- * @border: number of pixels used as a border
- * @min: the minimum value
- * @max: the maximum value
- * @width: the width of the progress bar in pixels
- * @height: the height of the progress bar in pixels
- * @red: the red component of the progress bars rgb color
- * @green: the green component of the progress bars rgb color
- * @blue: the blue component of the progress bars rgb color
- *
- * Constructs the @eprog object with the arguments
- */
-void
-e_cell_progress_construct (ECellProgress *eprog, int padding, int border, int min, int max, int width, int height, guchar red, guchar green, guchar blue)
-{
- eprog->padding = padding;
- eprog->border = border;
- eprog->min = min;
- eprog->max = max;
- eprog->red = red;
- eprog->green = green;
- eprog->blue = blue;
-
- eprog->width = (width<((padding+border)*2+5)) ? ((padding+border)*2+5) : width;
- eprog->height = (height<((padding+border)*2+5)) ? ((padding+border)*2+5) : height;
-
- eprog->buffer=g_new(guchar, eprog->width*eprog->height*4);
-
- eprog_clear(eprog);
- eprog_draw_border(eprog, red, green, blue);
-
- eprog->image = gdk_pixbuf_new_from_data (eprog->buffer,GDK_COLORSPACE_RGB, TRUE, 8, eprog->width, eprog->height, eprog->width*4, NULL, NULL);
-}
-
-/**
- * e_cell_progress_new:
- * @min: the minimum value
- * @max: the maximum value
- * @width: the width of the progress bar in pixels
- * @height: the height of the progress bar in pixels
- *
- * Creates a new ECell renderer that can be used to render progress
- * bars displaying the percentage of the current value between min
- * and max.
- *
- * Returns: an ECell object that can be used to render progress cells.
- */
-ECell *
-e_cell_progress_new (int min, int max, int width, int height)
-{
- ECellProgress *eprog = g_object_new (E_CELL_PROGRESS_TYPE, NULL);
-
- e_cell_progress_construct (eprog, 1, 1, min, max, (width<9) ? 9 : width, (height<9) ? 9 : height, 0x00, 0x00, 0x00);
-
- return (ECell *) eprog;
-}
-
-/**
- * e_cell_progress_set_padding:
- * @eprog: an ECellProgress object
- * @padding: number of pixels used as a padding
- *
- * Sets the padding around the progress bar in the cell.
- */
-void
-e_cell_progress_set_padding (ECellProgress *eprog, int padding)
-{
- eprog->padding = padding;
-
- eprog->width = (eprog->width<((padding+eprog->border)*2+5)) ? ((padding+eprog->border)*2+5) : eprog->width;
- eprog->height = (eprog->height<((padding+eprog->border)*2+5)) ? ((padding+eprog->border)*2+5) : eprog->height;
-
- g_free (eprog->buffer);
- eprog->buffer=g_new (guchar, eprog->width*eprog->height*4);
-
- eprog_clear (eprog);
- eprog_draw_border (eprog, eprog->red, eprog->green, eprog->blue);
-
- eprog->image = gdk_pixbuf_new_from_data (eprog->buffer,GDK_COLORSPACE_RGB, TRUE, 8, eprog->width, eprog->height, eprog->width*4, NULL, NULL);
-}
-
-/**
- * e_cell_progress_set_border:
- * @eprog: an ECellProgress object
- * @border: number of pixels used as a border
- *
- * Sets the border around the progress bar in the cell.
- */
-void
-e_cell_progress_set_border (ECellProgress *eprog, int border)
-{
- eprog->border = border;
-
- eprog->width = (eprog->width<((eprog->padding+border)*2+5)) ? ((eprog->padding+border)*2+5) : eprog->width;
- eprog->height = (eprog->height<((eprog->padding+border)*2+5)) ? ((eprog->padding+border)*2+5) : eprog->height;
-
- g_free (eprog->buffer);
- eprog->buffer=g_new (guchar, eprog->width*eprog->height*4);
-
- eprog_clear (eprog);
- eprog_draw_border (eprog, eprog->red, eprog->green, eprog->blue);
-
- eprog->image = gdk_pixbuf_new_from_data (eprog->buffer,GDK_COLORSPACE_RGB, TRUE, 8, eprog->width, eprog->height, eprog->width*4, NULL, NULL);
-}
-
-/**
- * e_cell_progress_set_color:
- * @eprog: a fresh ECellProgress object
- * @red: the red component of the progress bars rgb color
- * @green: the green component of the progress bars rgb color
- * @blue: the blue component of the progress bars rgb color
- */
-void
-e_cell_progress_set_color (ECellProgress *eprog, guchar red, guchar green, guchar blue)
-{
- eprog->red = red;
- eprog->green = green;
- eprog->blue = blue;
-
- eprog_clear (eprog);
- eprog_draw_border (eprog, red, green, blue);
-}
diff --git a/widgets/table/e-cell-progress.h b/widgets/table/e-cell-progress.h
deleted file mode 100644
index 01a0d0b504..0000000000
--- a/widgets/table/e-cell-progress.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-cell-progress.h - Progress display cell object.
- * Copyright 1999-2002, Ximian, Inc.
- * Copyright 2001, 2002, Krisztian Pifko <monsta@users.sourceforge.net>
- *
- * Authors:
- * Krisztian Pifko <monsta@users.sourceforge.net>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_CELL_PROGRESS_H_
-#define _E_CELL_PROGRESS_H_
-
-#include <libgnomecanvas/gnome-canvas.h>
-#include <gdk-pixbuf/gdk-pixbuf.h>
-#include <gal/e-table/e-cell.h>
-
-G_BEGIN_DECLS
-
-#define E_CELL_PROGRESS_TYPE (e_cell_progress_get_type ())
-#define E_CELL_PROGRESS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_CELL_PROGRESS_TYPE, ECellProgress))
-#define E_CELL_PROGRESS_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_CELL_PROGRESS_TYPE, ECellProgressClass))
-#define E_IS_CELL_PROGRESS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_CELL_PROGRESS_TYPE))
-#define E_IS_CELL_PROGRESS_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_CELL_PROGRESS_TYPE))
-
-typedef struct {
- ECell parent;
-
- int padding;
- int border;
- int min;
- int max;
- guchar red;
- guchar green;
- guchar blue;
-
- guchar *buffer;
- GdkPixbuf *image;
-
- int width;
- int height;
-} ECellProgress;
-
-typedef struct {
- ECellClass parent_class;
-} ECellProgressClass;
-
-GType e_cell_progress_get_type (void);
-ECell *e_cell_progress_new (int min, int max, int width, int height);
-void e_cell_progress_construct (ECellProgress *eprog, int padding, int border,
- int min, int max, int width, int height, guchar red, guchar green, guchar blue);
-void e_cell_progress_set_padding (ECellProgress *eprog, int padding);
-void e_cell_progress_set_border (ECellProgress *eprog, int border);
-void e_cell_progress_set_color (ECellProgress *eprog, guchar red, guchar green, guchar blue);
-
-G_END_DECLS
-
-#endif /* _E_CELL_PROGRESS_H_ */
-
-
diff --git a/widgets/table/e-cell-size.c b/widgets/table/e-cell-size.c
deleted file mode 100644
index 1ba8f6d2e6..0000000000
--- a/widgets/table/e-cell-size.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-cell-size.c: Size item for e-table.
- * Copyright 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <sys/time.h>
-#include <unistd.h>
-#include <gal/util/e-util.h>
-#include "e-cell-size.h"
-
-#define PARENT_TYPE e_cell_text_get_type ()
-
-static ECellTextClass *parent_class;
-
-static char *
-ecd_get_text(ECellText *cell, ETableModel *model, int col, int row)
-{
- gint size = GPOINTER_TO_INT(e_table_model_value_at(model, col, row));
- gfloat fsize;
-
- if (size < 1024) {
- return g_strdup_printf ("%d bytes", size);
- } else {
- fsize = ((gfloat) size) / 1024.0;
- if (fsize < 1024.0) {
- return g_strdup_printf ("%d K", (int)fsize);
- } else {
- fsize /= 1024.0;
- return g_strdup_printf ("%.1f MB", fsize);
- }
- }
-}
-
-static void
-ecd_free_text(ECellText *cell, char *text)
-{
- g_free(text);
-}
-
-static void
-e_cell_size_class_init (GtkObjectClass *object_class)
-{
- ECellTextClass *ectc = (ECellTextClass *) object_class;
-
- parent_class = g_type_class_ref (PARENT_TYPE);
-
- ectc->get_text = ecd_get_text;
- ectc->free_text = ecd_free_text;
-}
-
-static void
-e_cell_size_init (GtkObject *object)
-{
-}
-
-/**
- * e_cell_size_new:
- * @fontname: font to be used to render on the screen
- * @justify: Justification of the string in the cell.
- *
- * Creates a new ECell renderer that can be used to render file sizes
- * that that come from the model. The value returned from the model
- * is interpreted as being a time_t.
- *
- * The ECellSize object support a large set of properties that can be
- * configured through the Gtk argument system and allows the user to
- * have a finer control of the way the string is displayed. The
- * arguments supported allow the control of strikeout, underline,
- * bold, color and a size filter.
- *
- * The arguments "strikeout_column", "underline_column", "bold_column"
- * and "color_column" set and return an integer that points to a
- * column in the model that controls these settings. So controlling
- * the way things are rendered is achieved by having special columns
- * in the model that will be used to flag whether the size should be
- * rendered with strikeout, underline, or bolded. In the case of the
- * "color_column" argument, the column in the model is expected to
- * have a string that can be parsed by gdk_color_parse().
- *
- * Returns: an ECell object that can be used to render file sizes. */
-ECell *
-e_cell_size_new (const char *fontname, GtkJustification justify)
-{
- ECellSize *ecd = g_object_new (E_CELL_SIZE_TYPE, NULL);
-
- e_cell_text_construct(E_CELL_TEXT(ecd), fontname, justify);
-
- return (ECell *) ecd;
-}
-
-E_MAKE_TYPE(e_cell_size, "ECellSize", ECellSize, e_cell_size_class_init, e_cell_size_init, PARENT_TYPE)
diff --git a/widgets/table/e-cell-size.h b/widgets/table/e-cell-size.h
deleted file mode 100644
index 744cc00a98..0000000000
--- a/widgets/table/e-cell-size.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-cell-size.h: Size item for e-table.
- * Copyright 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-#ifndef _E_CELL_SIZE_H_
-#define _E_CELL_SIZE_H_
-
-#include <gal/e-table/e-cell-text.h>
-
-G_BEGIN_DECLS
-
-#define E_CELL_SIZE_TYPE (e_cell_size_get_type ())
-#define E_CELL_SIZE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_CELL_SIZE_TYPE, ECellSize))
-#define E_CELL_SIZE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_CELL_SIZE_TYPE, ECellSizeClass))
-#define E_IS_CELL_SIZE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_CELL_SIZE_TYPE))
-#define E_IS_CELL_SIZE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_CELL_SIZE_TYPE))
-
-typedef struct {
- ECellText base;
-} ECellSize;
-
-typedef struct {
- ECellTextClass parent_class;
-} ECellSizeClass;
-
-GType e_cell_size_get_type (void);
-ECell *e_cell_size_new (const char *fontname, GtkJustification justify);
-
-G_END_DECLS
-
-#endif /* _E_CELL_SIZE_H_ */
diff --git a/widgets/table/e-cell-spin-button.c b/widgets/table/e-cell-spin-button.c
deleted file mode 100644
index b2af02c44d..0000000000
--- a/widgets/table/e-cell-spin-button.c
+++ /dev/null
@@ -1,670 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-cell-spin-button.c: Spin button item for e-table.
- * Copyright 2001, CodeFactory AB
- * Copyright 2001, Mikael Hallendal <micke@codefactory.se>
- *
- * Authors:
- * Mikael Hallendal <micke@codefactory.se>
- *
- * Celltype for drawing a spinbutton in a cell.
- *
- * Used ECellPopup by Damon Chaplin <damon@ximian.com> as base for
- * buttondrawings.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <gtk/gtksignal.h>
-#include <gal/e-table/e-table-item.h>
-#include <gal/e-table/e-table-model.h>
-#include <gal/e-table/e-cell-float.h>
-#include <gal/e-table/e-cell-number.h>
-#include <gal/util/e-util.h>
-#include "e-cell-spin-button.h"
-
-#define E_CELL_SPIN_BUTTON_ARROW_WIDTH 16
-#define PARENT_TYPE e_cell_get_type ()
-
-static void e_cell_spin_button_class_init (GObjectClass *klass);
-static void e_cell_spin_button_init (GtkObject *object);
-
-static void ecsb_dispose (GObject *object);
-
-/* ECell Functions */
-static ECellView * ecsb_new_view (ECell *ecell,
- ETableModel *etm,
- void *eti_view);
-static void ecsb_realize (ECellView *ecv);
-static void ecsb_kill_view (ECellView *ecv);
-static void ecsb_unrealize (ECellView *ecv);
-static void ecsb_draw (ECellView *ecv,
- GdkDrawable *drawable,
- int model_col,
- int view_col,
- int row,
- ECellFlags flags,
- int x1,
- int y1,
- int x2,
- int y2);
-
-static gint ecsb_event (ECellView *ecv,
- GdkEvent *event,
- int model_col,
- int view_col,
- int row,
- ECellFlags flags,
- ECellActions *actions);
-
-static gint ecsb_height (ECellView *ecv,
- int model_col,
- int view_col,
- int row);
-
-static void * ecsb_enter_edit (ECellView *ecv,
- int model_col,
- int view_col,
- int row);
-
-static void ecsb_leave_edit (ECellView *ecv,
- int model_col,
- int view_col,
- int row,
- void *context);
-static void ecsb_focus (ECellView *ecell_view,
- int model_col,
- int view_col,
- int row,
- int x1,
- int y1,
- int x2,
- int y2);
-static void ecsb_unfocus (ECellView *ecell_view);
-
-static void ecsb_show_tooltip (ECellView *ecv,
- int model_col,
- int view_col,
- int row,
- int col_width,
- ETableTooltip *tooltip);
-
-typedef struct {
- ECellView cell_view;
-
- ECellView *child_view;
-} ECellSpinButtonView;
-
-enum {
- STEP,
- LAST_SIGNAL
-};
-
-static guint signals[LAST_SIGNAL] = { 0 };
-static ECell *parent_class;
-
-static void
-e_cell_spin_button_class_init (GObjectClass *klass)
-{
- ECellClass *ecc = (ECellClass *) klass;
- ECellSpinButtonClass *ecsbc = (ECellSpinButtonClass *) klass;
-
- klass->dispose = ecsb_dispose;
-
- ecc->realize = ecsb_realize;
- ecc->unrealize = ecsb_unrealize;
- ecc->new_view = ecsb_new_view;
- ecc->kill_view = ecsb_kill_view;
- ecc->draw = ecsb_draw;
- ecc->event = ecsb_event;
- ecc->height = ecsb_height;
- ecc->enter_edit = ecsb_enter_edit;
- ecc->leave_edit = ecsb_leave_edit;
- ecc->focus = ecsb_focus;
- ecc->unfocus = ecsb_unfocus; ecc->print = NULL;
- ecc->print_height = NULL;
- ecc->max_width = NULL;
- ecc->show_tooltip = ecsb_show_tooltip;
-
- ecsbc->step = NULL;
-
- parent_class = g_type_class_ref (E_CELL_TYPE);
-
- signals[STEP] =
- g_signal_new ("step",
- G_OBJECT_CLASS_TYPE (klass),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ECellSpinButtonClass, step),
- NULL, NULL,
- e_marshal_NONE__POINTER_INT_INT_INT,
- G_TYPE_NONE,
- 4, G_TYPE_POINTER, G_TYPE_INT,
- G_TYPE_INT, G_TYPE_INT);
-}
-
-static void
-e_cell_spin_button_init (GtkObject *object)
-{
- ECellSpinButton *ecsb;
-
- g_return_if_fail (object != NULL);
- g_return_if_fail (M_IS_CELL_SPIN_BUTTON (object));
-
- ecsb = E_CELL_SPIN_BUTTON (object);
-
- ecsb->up_pressed = FALSE;
- ecsb->down_pressed = FALSE;
-}
-
-static ECellView *
-ecsb_new_view (ECell *ecell,
- ETableModel *etm,
- void *eti_view)
-{
- ECellSpinButton *ecsb = E_CELL_SPIN_BUTTON (ecell);
- ECellSpinButtonView *ecsb_view;
-
- g_return_val_if_fail (ecsb->child != NULL, NULL);
-
- ecsb_view = g_new0 (ECellSpinButtonView, 1);
-
- ecsb_view->cell_view.ecell = ecell;
- ecsb_view->cell_view.e_table_model = etm;
- ecsb_view->cell_view.e_table_item_view = eti_view;
-
- ecsb_view->child_view = e_cell_new_view (ecsb->child, etm, eti_view);
-
- return (ECellView *) ecsb_view;
-}
-
-static void
-ecsb_realize (ECellView *ecv)
-{
- ECellSpinButtonView *ecsb_view;
-
- g_return_if_fail (ecv != NULL);
-
- ecsb_view = (ECellSpinButtonView *) ecv;
-
- e_cell_realize (ecsb_view->child_view);
-}
-
-static void
-ecsb_kill_view (ECellView *ecv)
-{
- ECellSpinButtonView *ecsb_view;
-
- g_return_if_fail (ecv != NULL);
-
- ecsb_view = (ECellSpinButtonView *) ecv;
-
- if (ecsb_view->child_view) {
- e_cell_kill_view (ecsb_view->child_view);
- }
-
- g_free (ecsb_view);
-}
-
-static void
-ecsb_unrealize (ECellView *ecv)
-{
- ECellSpinButtonView *ecsb_view;
-
- g_return_if_fail (ecv != NULL);
-
- ecsb_view = (ECellSpinButtonView *) ecv;
-
- e_cell_unrealize (ecsb_view->child_view);
-}
-
-static void
-ecsb_draw (ECellView *ecv,
- GdkDrawable *drawable,
- int model_col,
- int view_col,
- int row,
- ECellFlags flags,
- int x1,
- int y1,
- int x2,
- int y2)
-{
- ECellSpinButton *ecsb;
- ECellSpinButtonView *ecsb_view;
- ETableItem *eti;
- GtkWidget *canvas;
- GtkShadowType shadow = GTK_SHADOW_OUT;
- GdkRectangle rect;
-
- g_return_if_fail (ecv != NULL);
-
- ecsb_view = (ECellSpinButtonView *) ecv;
- ecsb = E_CELL_SPIN_BUTTON (ecsb_view->cell_view.ecell);
-
- eti = E_TABLE_ITEM (ecsb_view->cell_view.e_table_item_view);
- canvas = GTK_WIDGET (GNOME_CANVAS_ITEM (eti)->canvas);
-
- if (eti->editing_col == view_col &&
- eti->editing_row == row) {
-
- /* Draw child (Whats shown under the buttons) */
- e_cell_draw (ecsb_view->child_view,
- drawable, model_col, view_col,
- row, flags,
- x1, y1,
- x2 - E_CELL_SPIN_BUTTON_ARROW_WIDTH, y2);
-
- /* Draw down-arrow */
- rect.x = x2 - E_CELL_SPIN_BUTTON_ARROW_WIDTH;
- rect.y = y1 + (y2 - y1) / 2;
- rect.width = E_CELL_SPIN_BUTTON_ARROW_WIDTH;
- rect.height = (y2 - y1) / 2;
-
- if (ecsb->down_pressed) {
- shadow = GTK_SHADOW_IN;
- } else {
- shadow = GTK_SHADOW_OUT;
- }
-
- gtk_paint_box (canvas->style, drawable,
- GTK_STATE_NORMAL, shadow,
- &rect, canvas, "ecellspinbutton_down",
- rect.x, rect.y, rect.width, rect.height);
-
- gtk_paint_arrow (canvas->style, drawable,
- GTK_STATE_NORMAL, GTK_SHADOW_NONE,
- &rect, canvas, NULL,
- GTK_ARROW_DOWN, TRUE,
- rect.x,
- rect.y,
- rect.width,
- rect.height);
-
- /* Draw up-arrow */
- rect.y = y1;
-
- if (ecsb->up_pressed) {
- shadow = GTK_SHADOW_IN;
- } else {
- shadow = GTK_SHADOW_OUT;
- }
-
- gtk_paint_box (canvas->style, drawable,
- GTK_STATE_NORMAL, shadow,
- &rect, canvas, "ecellspinbutton_up",
- rect.x, rect.y, rect.width, rect.height);
-
- gtk_paint_arrow (canvas->style, drawable,
- GTK_STATE_NORMAL, GTK_SHADOW_NONE,
- &rect, canvas, NULL,
- GTK_ARROW_UP, TRUE,
- rect.x,
- rect.y,
- rect.width,
- rect.height);
- } else {
- /* Draw child */
- e_cell_draw (ecsb_view->child_view,
- drawable, model_col, view_col,
- row, flags,
- x1, y1,
- x2, y2);
- }
-}
-
-static gint
-ecsb_event (ECellView *ecv,
- GdkEvent *event,
- int model_col,
- int view_col,
- int row,
- ECellFlags flags,
- ECellActions *actions)
-{
- ECellSpinButton *ecsb;
- ECellSpinButtonClass *ecsb_class;
- ECellSpinButtonView *ecsb_view;
- ETableItem *eti;
- gint height, width;
-
- g_return_val_if_fail (ecv != NULL, FALSE);
-
- ecsb_view = (ECellSpinButtonView *) ecv;
- ecsb = E_CELL_SPIN_BUTTON (ecsb_view->cell_view.ecell);
- ecsb_class = E_CELL_SPIN_BUTTON_CLASS (GTK_OBJECT_GET_CLASS (ecsb));
- eti = E_TABLE_ITEM (ecsb_view->cell_view.e_table_item_view);
-
- switch (event->type) {
- case GDK_BUTTON_PRESS:
- if (eti->editing_col == view_col &&
- eti->editing_row == row) {
- width = e_table_header_col_diff (eti->header,
- view_col,
- view_col + 1);
- height = e_table_item_row_diff (eti, row, row + 1);
-
- /* Check if inside a button */
- if (event->button.x >= width - E_CELL_SPIN_BUTTON_ARROW_WIDTH) {
- /* Yep, which one? */
- if (event->button.y <= height / 2) {
- ecsb->up_pressed = TRUE;
- g_signal_emit (ecsb,
- signals[STEP], 0,
- ecv,
- STEP_UP,
- view_col,
- row);
- } else {
- ecsb->down_pressed = TRUE;
- g_signal_emit (ecsb,
- signals[STEP], 0,
- ecv,
- STEP_DOWN,
- view_col,
- row);
- }
-
- e_table_item_redraw_range (eti,
- view_col,
- row,
- view_col,
- row);
-
- }
- }
-
- break;
- case GDK_BUTTON_RELEASE:
- ecsb->up_pressed = FALSE;
- ecsb->down_pressed = FALSE;
- e_table_item_redraw_range (eti,
- view_col,
- row,
- view_col,
- row);
- break;
- case GDK_KEY_PRESS:
- break;
- default:
- break;
- }
-
- return e_cell_event (ecsb_view->child_view, event, model_col,
- view_col, row, flags, actions);
-}
-
-static gint
-ecsb_height (ECellView *ecv,
- int model_col,
- int view_col,
- int row)
-{
- ECellSpinButtonView *ecsb_view;
-
- g_return_val_if_fail (ecv != NULL, -1);
-
- ecsb_view = (ECellSpinButtonView *) ecv;
-
- return e_cell_height (ecsb_view->child_view, model_col, view_col, row);
-}
-
-static void *
-ecsb_enter_edit (ECellView *ecv,
- int model_col,
- int view_col,
- int row)
-{
- ECellSpinButtonView *ecsb_view;
-
- g_return_val_if_fail (ecv != NULL, NULL);
-
- ecsb_view = (ECellSpinButtonView *) ecv;
-
- return e_cell_enter_edit (ecsb_view->child_view, model_col,
- view_col, row);
-}
-
-
-static void
-ecsb_leave_edit (ECellView *ecv,
- int model_col,
- int view_col,
- int row,
- void *context)
-{
- ECellSpinButtonView *ecsb_view;
-
- g_return_if_fail (ecv != NULL);
-
- ecsb_view = (ECellSpinButtonView *) ecv;
-
- e_cell_leave_edit (ecsb_view->child_view, model_col, view_col,
- row, context);
-}
-
-static void
-ecsb_focus (ECellView *ecell_view,
- int model_col,
- int view_col,
- int row,
- int x1,
- int y1,
- int x2,
- int y2)
-{
- ECellClass *klass;
- ECellSpinButtonView *ecsb_view;
-
- ecsb_view = (ECellSpinButtonView *) ecell_view;
-
- klass = E_CELL_GET_CLASS (ecell_view->ecell);
-
- if (klass->focus)
- klass->focus (ecell_view, model_col, view_col, row,
- x1, y1, x2, y2);
-}
-
-static void
-ecsb_unfocus (ECellView *ecell_view)
-{
- ECellClass *klass;
- ECellSpinButtonView *ecsb_view;
-
- ecsb_view = (ECellSpinButtonView *) ecell_view;
- klass = E_CELL_GET_CLASS (ecell_view->ecell);
-
- if (klass->unfocus)
- klass->unfocus (ecell_view);
-}
-
-static void
-ecsb_show_tooltip (ECellView *ecv,
- int model_col,
- int view_col,
- int row,
- int col_width,
- ETableTooltip *tooltip)
-{
- ECellSpinButtonView *ecsb_view;
-
- g_return_if_fail (ecv != NULL);
-
- ecsb_view = (ECellSpinButtonView *) ecv;
-
- e_cell_show_tooltip (ecsb_view->child_view, model_col, view_col,
- row, col_width, tooltip);
-}
-
-static void
-ecsb_dispose (GObject *object)
-{
- ECellSpinButton *mcsp;
-
- g_return_if_fail (object != NULL);
- g_return_if_fail (M_IS_CELL_SPIN_BUTTON (object));
-
- mcsp = E_CELL_SPIN_BUTTON (object);
-
- G_OBJECT_CLASS (parent_class)->dispose (object);
-}
-
-ECell *
-e_cell_spin_button_new (gint min,
- gint max,
- gint step,
- ECell *child_cell)
-{
- ECellSpinButton *ecsb;
-
- ecsb = g_object_new (E_CELL_SPIN_BUTTON_TYPE, NULL);
-
- if (!child_cell) {
- child_cell = e_cell_number_new (NULL,
- GTK_JUSTIFY_LEFT);
-
- g_signal_connect (ecsb, "step",
- G_CALLBACK (e_cell_spin_button_step),
- NULL);
- }
-
- ecsb->child = child_cell;
- ecsb->min.i = min;
- ecsb->max.i = max;
- ecsb->step.i = step;
-
- return E_CELL (ecsb);
-}
-
-ECell *
-e_cell_spin_button_new_float (gfloat min,
- gfloat max,
- gfloat step,
- ECell *child_cell)
-{
- ECellSpinButton *ecsb;
-
- ecsb = g_object_new (E_CELL_SPIN_BUTTON_TYPE, NULL);
-
- if (!child_cell) {
- child_cell = e_cell_float_new (NULL, GTK_JUSTIFY_LEFT);
- g_signal_connect (ecsb, "step",
- G_CALLBACK (e_cell_spin_button_step_float),
- NULL);
- }
-
- ecsb->child = child_cell;
- ecsb->min.f = min;
- ecsb->max.f = max;
- ecsb->step.f = step;
-
- return E_CELL (ecsb);
-}
-
-void
-e_cell_spin_button_step (ECellSpinButton *ecsb,
- ECellView *ecv,
- ECellSpinButtonStep direction,
- gint col,
- gint row)
-{
- ECellSpinButtonView *ecsb_view;
-
- ETableModel *etm;
- gint value;
- gint new_value;
- gchar *str_value;
-
- g_return_if_fail (ecsb != NULL);
- g_return_if_fail (M_IS_CELL_SPIN_BUTTON (ecsb));
- g_return_if_fail (ecv != NULL);
-
- ecsb_view = (ECellSpinButtonView *) ecv;
- etm = ecsb_view->cell_view.e_table_model;
-
- value = GPOINTER_TO_INT (e_table_model_value_at (etm, col, row));
- new_value = value;
-
- switch (direction) {
- case STEP_UP:
- new_value = CLAMP (value + ecsb->step.i,
- ecsb->min.i, ecsb->max.i);
- break;
- case STEP_DOWN:
- new_value = CLAMP (value - ecsb->step.i,
- ecsb->min.i, ecsb->max.i);
- break;
- default:
- break;
- };
-
- str_value = g_strdup_printf ("%d", new_value);
-
- e_table_model_set_value_at (etm, col, row, str_value);
-
- g_free (str_value);
-}
-
-void
-e_cell_spin_button_step_float (ECellSpinButton *ecsb,
- ECellView *ecv,
- ECellSpinButtonStep direction,
- gint col,
- gint row)
-{
- ECellSpinButtonView *ecsb_view;
-
- ETableModel *etm;
- gfloat value;
- gfloat new_value;
- gchar *str_value;
-
- g_return_if_fail (ecsb != NULL);
- g_return_if_fail (M_IS_CELL_SPIN_BUTTON (ecsb));
- g_return_if_fail (ecv != NULL);
-
- ecsb_view = (ECellSpinButtonView *) ecv;
- etm = ecsb_view->cell_view.e_table_model;
-
- value = *(gfloat *) e_table_model_value_at (etm, col, row);
-
- switch (direction) {
- case STEP_UP:
- new_value = CLAMP (value + ecsb->step.f,
- ecsb->min.f, ecsb->max.f);
- break;
- case STEP_DOWN:
- new_value = CLAMP (value - ecsb->step.f,
- ecsb->min.f, ecsb->max.f);
- break;
- default:
- new_value = value;
- break;
- };
-
- str_value = g_strdup_printf ("%f", new_value);
-
- e_table_model_set_value_at (etm, col, row, str_value);
-
- g_free (str_value);
-}
-
-E_MAKE_TYPE (e_cell_spin_button, "ECellSpinButton", ECellSpinButton,
- e_cell_spin_button_class_init, e_cell_spin_button_init,
- PARENT_TYPE)
-
diff --git a/widgets/table/e-cell-spin-button.h b/widgets/table/e-cell-spin-button.h
deleted file mode 100644
index 4326c0429c..0000000000
--- a/widgets/table/e-cell-spin-button.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-cell-spin-button.h: Spin button item for e-table.
- * Copyright 2001, CodeFactory AB
- * Copyright 2001, Mikael Hallendal <micke@codefactory.se>
- *
- * Authors:
- * Mikael Hallendal <micke@codefactory.se>
- *
- * Celltype for drawing a spinbutton in a cell.
- *
- * Used ECellPopup by Damon Chaplin <damon@ximian.com> as base for
- * buttondrawings.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef __E_CELL_SPIN_BUTTON_H__
-#define __E_CELL_SPIN_BUTTON_H__
-
-#include <glib.h>
-#include <gtk/gtktypeutils.h>
-#include <gal/e-table/e-cell.h>
-
-#define E_CELL_SPIN_BUTTON_TYPE (e_cell_spin_button_get_type ())
-#define E_CELL_SPIN_BUTTON(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_CELL_SPIN_BUTTON_TYPE, ECellSpinButton))
-#define E_CELL_SPIN_BUTTON_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_CELL_SPIN_BUTTON_TYPE, ECellSpinButtonClass))
-#define M_IS_CELL_SPIN_BUTTON(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_CELL_SPIN_BUTTON_TYPE))
-#define M_IS_CELL_SPIN_BUTTON_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_CELL_SPIN_BUTTON_TYPE))
-
-typedef union {
- gint i;
- gfloat f;
-} ECellSpinButtonData;
-
-typedef enum {
- STEP_UP,
- STEP_DOWN
-} ECellSpinButtonStep;
-
-typedef struct {
- ECell parent;
-
- ECell *child;
-
- ECellSpinButtonData min;
- ECellSpinButtonData max;
- ECellSpinButtonData step;
-
- gboolean up_pressed;
- gboolean down_pressed;
-
-} ECellSpinButton;
-
-typedef struct {
- ECellClass parent_class;
-
- /* Functions */
- void (*step) (ECellSpinButton *mcsb,
- ECellView *ecv,
- ECellSpinButtonStep direction,
- gint col,
- gint row);
-} ECellSpinButtonClass;
-
-GType e_cell_spin_button_get_type (void);
-ECell * e_cell_spin_button_new (gint min,
- gint max,
- gint step,
- ECell *child_cell);
-
-ECell * e_cell_spin_button_new_float (gfloat min,
- gfloat max,
- gfloat step,
- ECell *child_cell);
-
-
-void e_cell_spin_button_step (ECellSpinButton *mcsb,
- ECellView *ecv,
- ECellSpinButtonStep direction,
- gint col,
- gint row);
-
-void e_cell_spin_button_step_float (ECellSpinButton *mcsb,
- ECellView *ecv,
- ECellSpinButtonStep direction,
- gint col,
- gint row);
-
-#endif /* __E_CELL_SPIN_BUTTON__ */
-
diff --git a/widgets/table/e-cell-text.c b/widgets/table/e-cell-text.c
deleted file mode 100644
index cbc0fddca8..0000000000
--- a/widgets/table/e-cell-text.c
+++ /dev/null
@@ -1,2854 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-cell-text.c: Text cell renderer.
- * Copyright 1999, 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Miguel de Icaza <miguel@ximian.com>
- * Chris Lahey <clahey@ximian.com>
- *
- * A lot of code taken from:
- *
- * Text item type for GnomeCanvas widget
- *
- * GnomeCanvas is basically a port of the Tk toolkit's most excellent
- * canvas widget. Tk is copyrighted by the Regents of the University
- * of California, Sun Microsystems, and other parties.
- *
- * Copyright (C) 1998 The Free Software Foundation
- *
- * Author: Federico Mena <federico@nuclecu.unam.mx>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <math.h>
-#include <string.h>
-#include <gdk/gdkx.h> /* for BlackPixel */
-#include <gdk/gdkkeysyms.h>
-#include <gtk/gtk.h>
-#include <libgnomecanvas/gnome-canvas.h>
-#include <libgnomecanvas/gnome-canvas-rect-ellipse.h>
-#include "e-cell-text.h"
-#include "gal/util/e-util.h"
-#include "gal/widgets/e-canvas.h"
-#include "gal/widgets/e-unicode.h"
-#include "e-table-item.h"
-#include "gal/util/e-text-event-processor.h"
-#include "gal/e-text/e-text.h"
-#include "gal/util/e-text-event-processor-emacs-like.h"
-#include "gal/util/e-i18n.h"
-#include "e-table-tooltip.h"
-#include "gal/a11y/e-table/gal-a11y-e-cell-registry.h"
-#include "gal/a11y/e-table/gal-a11y-e-cell-text.h"
-
-#define d(x)
-#define DO_SELECTION 1
-#define VIEW_TO_CELL(view) E_CELL_TEXT (((ECellView *)view)->ecell)
-
-#if d(!)0
-#define e_table_item_leave_edit_(x) (e_table_item_leave_edit((x)), g_print ("%s: e_table_item_leave_edit\n", __FUNCTION__))
-#else
-#define e_table_item_leave_edit_(x) (e_table_item_leave_edit((x)))
-#endif
-
-#define ECT_CLASS(c) (E_CELL_TEXT_CLASS(GTK_OBJECT_GET_CLASS ((c))))
-
-/* This defines a line of text */
-struct line {
- char *text; /* Line's text UTF-8, it is a pointer into the text->text string */
- int length; /* Line's length in BYTES */
- int width; /* Line's width in pixels */
- int ellipsis_length; /* Length before adding ellipsis in BYTES */
-};
-
-/* Object argument IDs */
-enum {
- PROP_0,
-
- PROP_STRIKEOUT_COLUMN,
- PROP_UNDERLINE_COLUMN,
- PROP_BOLD_COLUMN,
- PROP_COLOR_COLUMN,
- PROP_EDITABLE,
- PROP_BG_COLOR_COLUMN
-};
-
-
-enum {
- E_SELECTION_PRIMARY,
- E_SELECTION_CLIPBOARD
-};
-
-/* signals */
-enum {
- TEXT_INSERTED,
- TEXT_DELETED,
- LAST_SIGNAL
-};
-
-static guint signals [LAST_SIGNAL] = { 0 };
-
-static GdkAtom clipboard_atom = GDK_NONE;
-
-#define PARENT_TYPE e_cell_get_type ()
-
-#define UTF8_ATOM gdk_atom_intern ("UTF8_STRING", FALSE)
-
-#define TEXT_PAD 4
-
-typedef struct {
- gpointer lines; /* Text split into lines (private field) */
- int num_lines; /* Number of lines of text */
- int max_width;
- int ref_count;
-} ECellTextLineBreaks;
-
-
-typedef struct _CellEdit CellEdit;
-
-typedef struct {
- ECellView cell_view;
- GdkGC *gc;
- GdkCursor *i_cursor;
- GdkBitmap *stipple; /* Stipple for text */
-
- GnomeCanvas *canvas;
-
- /*
- * During editing.
- */
- CellEdit *edit;
-
-
- int xofs, yofs; /* This gets added to the x
- and y for the cell text. */
- double ellipsis_width[2]; /* The width of the ellipsis. */
-
-} ECellTextView;
-
-struct _CellEdit {
-
- ECellTextView *text_view;
-
- int model_col, view_col, row;
- int cell_width;
-
- PangoLayout *layout;
-
- char *text;
-
- char *old_text;
-
- /*
- * Where the editing is taking place
- */
-
- int xofs_edit, yofs_edit; /* Offset because of editing.
- This is negative compared
- to the other offsets. */
-
- /* This needs to be reworked a bit once we get line wrapping. */
- int selection_start; /* Start of selection - IN BYTES */
- int selection_end; /* End of selection - IN BYTES */
- gboolean select_by_word; /* Current selection is by word */
-
- /* This section is for drag scrolling and blinking cursor. */
- /* Cursor handling. */
- gint timeout_id; /* Current timeout id for scrolling */
- GTimer *timer; /* Timer for blinking cursor and scrolling */
-
- gint lastx, lasty; /* Last x and y motion events */
- gint last_state; /* Last state */
- gulong scroll_start; /* Starting time for scroll (microseconds) */
-
- gint show_cursor; /* Is cursor currently shown */
- gboolean button_down; /* Is mouse button 1 down */
-
- ETextEventProcessor *tep; /* Text Event Processor */
-
- GtkWidget *invisible; /* For selection handling */
- gboolean has_selection; /* TRUE if we have the selection */
- gchar *primary_selection; /* Primary selection text */
- gint primary_length; /* Primary selection text length in BYTES */
- gchar *clipboard_selection; /* Clipboard selection text */
- gint clipboard_length; /* Clipboard selection text length in BYTES */
-
- guint pointer_in : 1;
- guint default_cursor_shown : 1;
- GtkIMContext *im_context;
- gboolean need_im_reset;
- gboolean im_context_signals_registered;
-
- guint16 preedit_length; /* length of preedit string, in bytes */
-
- ECellActions actions;
-};
-
-static void e_cell_text_view_command (ETextEventProcessor *tep, ETextEventProcessorCommand *command, gpointer data);
-
-static void e_cell_text_view_get_selection (CellEdit *edit, GdkAtom selection, guint32 time);
-static void e_cell_text_view_supply_selection (CellEdit *edit, guint time, GdkAtom selection, char *data, gint length);
-
-static void _get_tep (CellEdit *edit);
-
-static gint get_position_from_xy (CellEdit *edit, gint x, gint y);
-static gboolean _blink_scroll_timeout (gpointer data);
-
-static void ect_free_color (gchar *color_spec, GdkColor *color, GdkColormap *colormap);
-static GdkColor* e_cell_text_get_color (ECellTextView *cell_view, gchar *color_spec);
-static void e_cell_text_preedit_changed_cb (GtkIMContext *context, ECellTextView *text_view);
-static void e_cell_text_commit_cb (GtkIMContext *context, const gchar *str, ECellTextView *text_view);
-static gboolean e_cell_text_retrieve_surrounding_cb (GtkIMContext *context, ECellTextView *text_view);
-static gboolean e_cell_text_delete_surrounding_cb (GtkIMContext *context, gint offset, gint n_chars, ECellTextView *text_view);
-static void _insert (ECellTextView *text_view, char *string, int value);
-static void _delete_selection (ECellTextView *text_view);
-static PangoAttrList* build_attr_list (ECellTextView *text_view, int row, int text_length);
-
-static ECellClass *parent_class;
-
-char *
-e_cell_text_get_text (ECellText *cell, ETableModel *model, int col, int row)
-{
- if (ECT_CLASS(cell)->get_text)
- return ECT_CLASS(cell)->get_text (cell, model, col, row);
- else
- return NULL;
-}
-
-void
-e_cell_text_free_text (ECellText *cell, char *text)
-{
- if (ECT_CLASS(cell)->free_text)
- ECT_CLASS(cell)->free_text (cell, text);
-}
-
-void
-e_cell_text_set_value (ECellText *cell, ETableModel *model, int col, int row,
- const char *text)
-{
- if (ECT_CLASS(cell)->set_value)
- ECT_CLASS(cell)->set_value (cell, model, col, row, text);
-}
-
-static char *
-ect_real_get_text (ECellText *cell, ETableModel *model, int col, int row)
-{
- return e_table_model_value_at(model, col, row);
-}
-
-static void
-ect_real_free_text (ECellText *cell, char *text)
-{
-}
-
-/* This is the default method for setting the ETableModel value based on
- the text in the ECellText. This simply uses the text as it is - it assumes
- the value in the model is a char*. Subclasses may parse the text into
- data structures to pass to the model. */
-static void
-ect_real_set_value (ECellText *cell, ETableModel *model, int col, int row,
- const char *text)
-{
- e_table_model_set_value_at (model, col, row, text);
-}
-
-static void
-ect_queue_redraw (ECellTextView *text_view, int view_col, int view_row)
-{
- e_table_item_redraw_range (
- text_view->cell_view.e_table_item_view,
- view_col, view_row, view_col, view_row);
-}
-
-/*
- * Shuts down the editing process
- */
-static void
-ect_stop_editing (ECellTextView *text_view, gboolean commit)
-{
- CellEdit *edit = text_view->edit;
- int row, view_col, model_col;
- char *old_text, *text;
-
- if (!edit)
- return;
-
- row = edit->row;
- view_col = edit->view_col;
- model_col = edit->model_col;
-
- old_text = edit->old_text;
- text = edit->text;
- if (edit->invisible)
- gtk_widget_destroy (edit->invisible);
- if (edit->tep)
- g_object_unref (edit->tep);
- if (edit->primary_selection)
- g_free (edit->primary_selection);
- if (edit->clipboard_selection)
- g_free (edit->clipboard_selection);
- if (! edit->default_cursor_shown){
- gdk_window_set_cursor (GTK_WIDGET(text_view->canvas)->window, NULL);
- edit->default_cursor_shown = TRUE;
- }
- if (edit->timeout_id) {
- g_source_remove (edit->timeout_id);
- edit->timeout_id = 0;
- }
- if (edit->timer) {
- g_timer_stop (edit->timer);
- g_timer_destroy (edit->timer);
- edit->timer = NULL;
- }
-
- g_signal_handlers_disconnect_matched (
- edit->im_context,
- G_SIGNAL_MATCH_DATA, 0, 0,
- NULL, NULL, text_view);
-
- if (edit->layout)
- g_object_unref (edit->layout);
-
- g_free (edit);
-
- text_view->edit = NULL;
- if (commit) {
- /*
- * Accept the currently edited text. if it's the same as what's in the cell, do nothing.
- */
- ECellView *ecell_view = (ECellView *) text_view;
- ECellText *ect = (ECellText *) ecell_view->ecell;
-
- if (strcmp (old_text, text)) {
- e_cell_text_set_value (ect, ecell_view->e_table_model,
- model_col, row, text);
- }
- }
- g_free (text);
- g_free (old_text);
-
- ect_queue_redraw (text_view, view_col, row);
-}
-
-/*
- * Cancels the edits
- */
-static void
-ect_cancel_edit (ECellTextView *text_view)
-{
- ect_stop_editing (text_view, FALSE);
- e_table_item_leave_edit_ (text_view->cell_view.e_table_item_view);
-}
-
-/*
- * ECell::new_view method
- */
-static ECellView *
-ect_new_view (ECell *ecell, ETableModel *table_model, void *e_table_item_view)
-{
- ECellTextView *text_view = g_new0 (ECellTextView, 1);
- GnomeCanvas *canvas = GNOME_CANVAS_ITEM (e_table_item_view)->canvas;
-
- text_view->cell_view.ecell = ecell;
- text_view->cell_view.e_table_model = table_model;
- text_view->cell_view.e_table_item_view = e_table_item_view;
-
- text_view->canvas = canvas;
-
- text_view->xofs = 0.0;
- text_view->yofs = 0.0;
-
- return (ECellView *)text_view;
-}
-
-/*
- * ECell::kill_view method
- */
-static void
-ect_kill_view (ECellView *ecv)
-{
- ECellTextView *text_view = (ECellTextView *) ecv;
-
- g_free (text_view);
-}
-
-/*
- * ECell::realize method
- */
-static void
-ect_realize (ECellView *ecell_view)
-{
- ECellTextView *text_view = (ECellTextView *) ecell_view;
-
- text_view->gc = gdk_gc_new (GTK_WIDGET (text_view->canvas)->window);
-
- text_view->i_cursor = gdk_cursor_new (GDK_XTERM);
-
- if (parent_class->realize)
- (* parent_class->realize) (ecell_view);
-}
-
-/*
- * ECell::unrealize method
- */
-static void
-ect_unrealize (ECellView *ecv)
-{
- ECellTextView *text_view = (ECellTextView *) ecv;
- ECellText *ect = (ECellText*) ecv->ecell;
- GdkColormap *colormap;
-
- gdk_gc_unref (text_view->gc);
- text_view->gc = NULL;
-
- if (text_view->edit){
- ect_cancel_edit (text_view);
- }
-
- if (text_view->stipple)
- gdk_bitmap_unref (text_view->stipple);
-
- gdk_cursor_destroy (text_view->i_cursor);
-
- if (ect->colors) {
- colormap = gtk_widget_get_colormap (GTK_WIDGET (text_view->canvas));
- g_hash_table_foreach (ect->colors, (GHFunc) ect_free_color,
- colormap);
- g_hash_table_destroy (ect->colors);
- ect->colors = NULL;
- }
-
- if (parent_class->unrealize)
- (* parent_class->unrealize) (ecv);
-}
-
-static void
-ect_free_color (gchar *color_spec, GdkColor *color, GdkColormap *colormap)
-{
- g_free (color_spec);
-
- /* This frees the color. Note we don't free it if it is the special
- value. */
- if (color != (GdkColor*) 1) {
- gulong pix = color->pixel;
-
- gdk_colors_free (colormap, &pix, 1, 0);
-
- /* This frees the memory for the GdkColor. */
- gdk_color_free (color);
- }
-}
-
-
-static PangoAttrList*
-build_attr_list (ECellTextView *text_view, int row, int text_length)
-{
-
- ECellView *ecell_view = (ECellView *) text_view;
- ECellText *ect = E_CELL_TEXT (ecell_view->ecell);
- PangoAttrList *attrs = pango_attr_list_new ();
- gboolean bold, strikeout, underline;
-
- bold = ect->bold_column >= 0 &&
- row >= 0 &&
- e_table_model_value_at(ecell_view->e_table_model, ect->bold_column, row);
- strikeout = ect->strikeout_column >= 0 &&
- row >= 0 &&
- e_table_model_value_at(ecell_view->e_table_model, ect->strikeout_column, row);
- underline = ect->underline_column >= 0 &&
- row >= 0 &&
- e_table_model_value_at(ecell_view->e_table_model, ect->underline_column, row);
-
- if (bold || strikeout || underline) {
- if (bold) {
- PangoAttribute *attr = pango_attr_weight_new (PANGO_WEIGHT_BOLD);
- attr->start_index = 0;
- attr->end_index = text_length;
-
- pango_attr_list_insert_before (attrs, attr);
- }
- if (strikeout) {
- PangoAttribute *attr = pango_attr_strikethrough_new (TRUE);
- attr->start_index = 0;
- attr->end_index = text_length;
-
- pango_attr_list_insert_before (attrs, attr);
- }
- if (underline) {
- PangoAttribute *attr = pango_attr_underline_new (TRUE);
- attr->start_index = 0;
- attr->end_index = text_length;
-
- pango_attr_list_insert_before (attrs, attr);
- }
- }
- return attrs;
-}
-
-static PangoLayout *
-layout_with_preedit (ECellTextView *text_view, int row, const char *text, gint width)
-{
- CellEdit *edit = text_view->edit;
- PangoAttrList *attrs ;
- PangoLayout *layout;
- GString *tmp_string = g_string_new (NULL);
- PangoAttrList *preedit_attrs = NULL;
- gchar *preedit_string = NULL;
- gint preedit_length = 0;
- gint text_length = strlen (text);
- gint mlen = MIN(edit->selection_start,text_length);
-
-
- gtk_im_context_get_preedit_string (edit->im_context,
- &preedit_string,&preedit_attrs,
- NULL);
- preedit_length = edit->preedit_length = strlen (preedit_string);;
-
- layout = edit->layout;
-
- g_string_prepend_len (tmp_string, text,text_length);
-
- if (preedit_length) {
-
- /* mlen is the text_length in bytes, not chars
- * check whether we are not inserting into
- * the middle of a utf8 character
- */
-
- if (mlen < text_length) {
- if (!g_utf8_validate (text+mlen, -1, NULL)) {
- gchar *tc;
- tc = g_utf8_find_next_char (text+mlen,NULL);
- if (tc) {
- mlen = (gint) (tc - text);
- }
- }
- }
-
- g_string_insert (tmp_string, mlen, preedit_string);
- }
-
- pango_layout_set_text (layout, tmp_string->str, tmp_string->len);
-
- attrs = (PangoAttrList *) build_attr_list (text_view, row, text_length);
-
- if (preedit_length)
- pango_attr_list_splice (attrs, preedit_attrs, mlen, preedit_length);
- pango_layout_set_attributes (layout, attrs);
- g_string_free (tmp_string, TRUE);
- if (preedit_string)
- g_free (preedit_string);
- if (preedit_attrs)
- pango_attr_list_unref (preedit_attrs);
- pango_attr_list_unref (attrs);
- return layout;
-}
-
-static PangoLayout *
-build_layout (ECellTextView *text_view, int row, const char *text, gint width)
-{
- ECellView *ecell_view = (ECellView *) text_view;
- ECellText *ect = E_CELL_TEXT (ecell_view->ecell);
- PangoAttrList *attrs ;
- PangoLayout *layout;
-
- layout = gtk_widget_create_pango_layout (GTK_WIDGET (((GnomeCanvasItem *)ecell_view->e_table_item_view)->canvas), text);
-
- attrs = (PangoAttrList *) build_attr_list (text_view, row, text ? strlen (text) : 0);
-
- pango_layout_set_attributes (layout, attrs);
- pango_attr_list_unref (attrs);
-
- if (text_view->edit || width <= 0)
- return layout;
-
- pango_layout_set_width (layout, width * PANGO_SCALE);
- pango_layout_set_wrap (layout, PANGO_WRAP_CHAR);
-
- if (pango_layout_get_line_count (layout) > 1) {
- PangoLayoutLine *line = pango_layout_get_line (layout, 0);
- gchar *line_text = g_strdup (pango_layout_get_text (layout));
- gchar *last_char = g_utf8_find_prev_char (line_text, line_text + line->length - 1);
- while (last_char && pango_layout_get_line_count (layout) > 1) {
- gchar *new_text;
- last_char = g_utf8_find_prev_char (line_text, last_char);
- if (last_char)
- *last_char = '\0';
- new_text = g_strconcat (line_text, "...", NULL);
- pango_layout_set_text (layout, new_text, -1);
- g_free (new_text);
- }
- g_free (line_text);
- }
-
- switch (ect->justify) {
- case GTK_JUSTIFY_RIGHT:
- pango_layout_set_alignment (layout, PANGO_ALIGN_RIGHT);
- break;
- case GTK_JUSTIFY_CENTER:
- pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER);
- break;
- case GTK_JUSTIFY_LEFT:
- default:
- break;
- }
-
- return layout;
-}
-
-static PangoLayout *
-generate_layout (ECellTextView *text_view, int model_col, int view_col, int row, int width)
-{
- ECellView *ecell_view = (ECellView *) text_view;
- ECellText *ect = E_CELL_TEXT (ecell_view->ecell);
- PangoLayout *layout;
- CellEdit *edit = text_view->edit;
-
- if (edit && edit->layout && edit->model_col == model_col && edit->row == row) {
- g_object_ref (edit->layout);
- return edit->layout;
- }
-
- if (row >= 0) {
- char *temp = e_cell_text_get_text(ect, ecell_view->e_table_model, model_col, row);
- layout = build_layout (text_view, row, temp ? temp : "?", width);
- e_cell_text_free_text(ect, temp);
- } else
- layout = build_layout (text_view, row, "Mumbo Jumbo", width);
-
- return layout;
-}
-
-
-static void
-draw_pango_rectangle (GdkDrawable *drawable, GdkGC *gc, int x1, int y1, PangoRectangle rect)
-{
- int width = rect.width / PANGO_SCALE;
- int height = rect.height / PANGO_SCALE;
- if (width <= 0)
- width = 1;
- if (height <= 0)
- height = 1;
- gdk_draw_rectangle (drawable, gc, TRUE,
- x1 + rect.x / PANGO_SCALE, y1 + rect.y / PANGO_SCALE, width, height);
-}
-
-static gboolean
-show_pango_rectangle (CellEdit *edit, PangoRectangle rect)
-{
- int x1 = rect.x / PANGO_SCALE;
- int x2 = (rect.x + rect.width) / PANGO_SCALE;
-#if 0
- int y1 = rect.y / PANGO_SCALE;
- int y2 = (rect.y + rect.height) / PANGO_SCALE;
-#endif
-
- int new_xofs_edit = edit->xofs_edit;
- int new_yofs_edit = edit->yofs_edit;
-
- if (x1 < new_xofs_edit)
- new_xofs_edit = x1;
- if (2 + x2 - edit->cell_width > new_xofs_edit)
- new_xofs_edit = 2 + x2 - edit->cell_width;
- if (new_xofs_edit < 0)
- new_xofs_edit = 0;
-
-#if 0
- if (y1 < new_yofs_edit)
- new_yofs_edit = y1;
- if (2 + y2 - edit->cell_height > new_yofs_edit)
- new_yofs_edit = 2 + y2 - edit->cell_height;
- if (new_yofs_edit < 0)
- new_yofs_edit = 0;
-#endif
-
- if (new_xofs_edit != edit->xofs_edit ||
- new_yofs_edit != edit->yofs_edit) {
- edit->xofs_edit = new_xofs_edit;
- edit->yofs_edit = new_yofs_edit;
- return TRUE;
- }
-
- return FALSE;
-}
-
-/*
- * ECell::draw method
- */
-static void
-ect_draw (ECellView *ecell_view, GdkDrawable *drawable,
- int model_col, int view_col, int row, ECellFlags flags,
- int x1, int y1, int x2, int y2)
-{
- PangoLayout *layout;
- ECellTextView *text_view = (ECellTextView *) ecell_view;
- ECellText *ect = E_CELL_TEXT (ecell_view->ecell);
- CellEdit *edit = text_view->edit;
- gboolean selected;
- GdkColor *foreground, *cursor_color;
- GtkWidget *canvas = GTK_WIDGET (text_view->canvas);
- GdkRectangle clip_rect;
- int x_origin, y_origin;
-
- selected = flags & E_CELL_SELECTED;
-
- if (selected) {
- if (flags & E_CELL_FOCUSED)
- foreground = &canvas->style->fg [GTK_STATE_SELECTED];
- else
- foreground = &canvas->style->fg [GTK_STATE_ACTIVE];
- cursor_color = foreground;
- } else {
- foreground = &canvas->style->text [GTK_STATE_NORMAL];
- cursor_color = foreground;
-
- if (ect->color_column != -1) {
- char *color_spec;
- GdkColor *cell_foreground;
-
- color_spec = e_table_model_value_at (ecell_view->e_table_model,
- ect->color_column, row);
- cell_foreground = e_cell_text_get_color (text_view,
- color_spec);
- if (cell_foreground)
- foreground = cell_foreground;
- }
- }
-
- gdk_gc_set_foreground (text_view->gc, foreground);
-
- x1 += 4;
- y1 += 1;
- x2 -= 4;
- y2 -= 1;
-
- x_origin = x1 + ect->x + text_view->xofs - (edit ? edit->xofs_edit : 0);
- y_origin = y1 + ect->y + text_view->yofs - (edit ? edit->yofs_edit : 0);
-
- clip_rect.x = x1;
- clip_rect.y = y1;
- clip_rect.width = x2 - x1;
- clip_rect.height = y2 - y1;
-
- gdk_gc_set_clip_rectangle (text_view->gc, &clip_rect);
- /* clip_rect = &rect;*/
-
- layout = generate_layout (text_view, model_col, view_col, row, x2 - x1);
-
- if (edit && edit->view_col == view_col && edit->row == row) {
- layout = layout_with_preedit (text_view, row, edit->text ? edit->text : "?", x2 - x1);
- }
-
- gdk_draw_layout (drawable, text_view->gc,
- x_origin, y_origin,
- layout);
-
- if (edit && edit->view_col == view_col && edit->row == row) {
- if (edit->selection_start != edit->selection_end) {
- int start_index, end_index;
- PangoLayoutLine *line;
- gint *ranges;
- gint n_ranges, i;
- PangoRectangle logical_rect;
- GdkRegion *clip_region = gdk_region_new ();
- GdkRegion *rect_region;
- GdkGC *selection_gc;
- GdkGC *text_gc;
-
- start_index = MIN (edit->selection_start, edit->selection_end);
- end_index = edit->selection_start ^ edit->selection_end ^ start_index;
-
- if (edit->has_selection) {
- selection_gc = canvas->style->base_gc [GTK_STATE_SELECTED];
- text_gc = canvas->style->text_gc[GTK_STATE_SELECTED];
- } else {
- selection_gc = canvas->style->base_gc [GTK_STATE_ACTIVE];
- text_gc = canvas->style->text_gc[GTK_STATE_ACTIVE];
- }
-
- gdk_gc_set_clip_rectangle (selection_gc, &clip_rect);
-
- line = pango_layout_get_lines (layout)->data;
-
- pango_layout_line_get_x_ranges (line, start_index, end_index, &ranges, &n_ranges);
-
- pango_layout_get_extents (layout, NULL, &logical_rect);
-
- for (i=0; i < n_ranges; i++) {
- GdkRectangle sel_rect;
-
- sel_rect.x = x_origin + ranges[2*i] / PANGO_SCALE;
- sel_rect.y = y_origin;
- sel_rect.width = (ranges[2*i + 1] - ranges[2*i]) / PANGO_SCALE;
- sel_rect.height = logical_rect.height / PANGO_SCALE;
-
- gdk_draw_rectangle (drawable, selection_gc, TRUE,
- sel_rect.x, sel_rect.y, sel_rect.width, sel_rect.height);
-
- gdk_region_union_with_rect (clip_region, &sel_rect);
- }
-
- rect_region = gdk_region_rectangle (&clip_rect);
- gdk_region_intersect (clip_region, rect_region);
- gdk_region_destroy (rect_region);
-
- gdk_gc_set_clip_region (text_gc, clip_region);
- gdk_draw_layout (drawable, text_gc,
- x_origin, y_origin,
- layout);
- gdk_gc_set_clip_region (text_gc, NULL);
- gdk_gc_set_clip_region (selection_gc, NULL);
-
- gdk_region_destroy (clip_region);
- g_free (ranges);
- } else {
- if (edit->show_cursor) {
- PangoRectangle strong_pos, weak_pos;
- pango_layout_get_cursor_pos (layout, edit->selection_start + edit->preedit_length, &strong_pos, &weak_pos);
-
- draw_pango_rectangle (drawable, text_view->gc, x_origin, y_origin, strong_pos);
- if (strong_pos.x != weak_pos.x ||
- strong_pos.y != weak_pos.y ||
- strong_pos.width != weak_pos.width ||
- strong_pos.height != weak_pos.height)
- draw_pango_rectangle (drawable, text_view->gc, x_origin, y_origin, weak_pos);
- }
- }
- }
-
- g_object_unref (layout);
-}
-
-/*
- * Get the background color
- */
-static gchar *
-ect_get_bg_color(ECellView *ecell_view, int row)
-{
- ECellText *ect = E_CELL_TEXT (ecell_view->ecell);
- gchar *color_spec;
-
- if (ect->bg_color_column == -1)
- return NULL;
-
- color_spec = e_table_model_value_at (ecell_view->e_table_model,
- ect->bg_color_column, row);
-
- return color_spec;
-}
-
-
-/*
- * Selects the entire string
- */
-
-static void
-ect_edit_select_all (ECellTextView *text_view)
-{
- g_assert (text_view->edit);
-
- text_view->edit->selection_start = 0;
- text_view->edit->selection_end = strlen (text_view->edit->text);
-}
-
-static gboolean
-key_begins_editing (GdkEventKey *event)
-{
- if (event->length == 0)
- return FALSE;
-
- return TRUE;
-}
-
-/*
- * ECell::event method
- */
-static gint
-ect_event (ECellView *ecell_view, GdkEvent *event, int model_col, int view_col, int row, ECellFlags flags, ECellActions *actions)
-{
- ECellTextView *text_view = (ECellTextView *) ecell_view;
- ETextEventProcessorEvent e_tep_event;
- gboolean edit_display = FALSE;
- gint preedit_len;
- CellEdit *edit = text_view->edit;
- GtkWidget *canvas = GTK_WIDGET (text_view->canvas);
- gint return_val = 0;
- d(gboolean press = FALSE);
-
- if (!(flags & E_CELL_EDITING))
- return 0;
-
- if ( edit && !edit->preedit_length && flags & E_CELL_PREEDIT)
- return TRUE;
-
- if (edit && edit->view_col == view_col && edit->row == row) {
- edit_display = TRUE;
- }
-
- e_tep_event.type = event->type;
- switch (event->type) {
- case GDK_FOCUS_CHANGE:
- break;
- case GDK_KEY_PRESS: /* Fall Through */
- if (edit_display) {
- if (edit->im_context &&
- !edit->im_context_signals_registered) {
-
- g_signal_connect (edit->im_context,
- "preedit_changed",
- G_CALLBACK (\
- e_cell_text_preedit_changed_cb),
- text_view);
-
- g_signal_connect (edit->im_context,
- "commit",
- G_CALLBACK (\
- e_cell_text_commit_cb),
- text_view);
-
- g_signal_connect (edit->im_context,
- "retrieve_surrounding",
- G_CALLBACK (\
- e_cell_text_retrieve_surrounding_cb),
- text_view);
-
- g_signal_connect (edit->im_context,
- "delete_surrounding",
- G_CALLBACK (\
- e_cell_text_delete_surrounding_cb),
- text_view);
-
- edit->im_context_signals_registered = TRUE;
- }
-
- edit->show_cursor = FALSE;
-
- } else {
- if (edit->im_context) {
- g_signal_handlers_disconnect_matched (
- edit->im_context,
- G_SIGNAL_MATCH_DATA, 0, 0,
- NULL, NULL, edit);
- edit->im_context_signals_registered = FALSE;
- }
-
- ect_stop_editing (text_view, TRUE);
- if (edit->timeout_id) {
- g_source_remove(edit->timeout_id);
- edit->timeout_id = 0;
- }
- }
- return_val = TRUE;
- /* Fallthrough */
- case GDK_KEY_RELEASE:
- preedit_len = edit->preedit_length;
- if (edit_display && edit->im_context &&
- gtk_im_context_filter_keypress (\
- edit->im_context,
- (GdkEventKey*)event)) {
-
- edit->need_im_reset = TRUE;
- if (preedit_len && flags & E_CELL_PREEDIT)
- return FALSE;
- else
- return TRUE;
- }
-
- if (event->key.keyval == GDK_Escape){
- ect_cancel_edit (text_view);
- return_val = TRUE;
- break;
- }
-
- if ((!edit_display) &&
- e_table_model_is_cell_editable (ecell_view->e_table_model, model_col, row) &&
- key_begins_editing (&event->key)) {
- e_table_item_enter_edit (text_view->cell_view.e_table_item_view, view_col, row);
- ect_edit_select_all (text_view);
- edit = text_view->edit;
- edit_display = TRUE;
- }
- if (edit_display) {
- GdkEventKey key = event->key;
- if (key.keyval == GDK_KP_Enter || key.keyval == GDK_Return){
- e_table_item_leave_edit_ (text_view->cell_view.e_table_item_view);
- } else {
- e_tep_event.key.time = key.time;
- e_tep_event.key.state = key.state;
- e_tep_event.key.keyval = key.keyval;
-
- /* This is probably ugly hack, but we have to handle UTF-8 input somehow */
-#if 0
- e_tep_event.key.length = key.length;
- e_tep_event.key.string = key.string;
-#else
- e_tep_event.key.string = e_utf8_from_gtk_event_key (canvas, key.keyval, key.string);
- if (e_tep_event.key.string != NULL) {
- e_tep_event.key.length = strlen (e_tep_event.key.string);
- } else {
- e_tep_event.key.length = 0;
- }
-#endif
- _get_tep (edit);
- return_val = e_text_event_processor_handle_event (edit->tep, &e_tep_event);
- if (e_tep_event.key.string)
- g_free (e_tep_event.key.string);
- break;
- }
- }
-
- break;
- case GDK_BUTTON_PRESS: /* Fall Through */
- d(press = TRUE);
- case GDK_BUTTON_RELEASE:
- d(g_print ("%s: %s\n", __FUNCTION__, press ? "GDK_BUTTON_PRESS" : "GDK_BUTTON_RELEASE"));
- event->button.x -= 4;
- event->button.y -= 1;
- if ((!edit_display)
- && e_table_model_is_cell_editable (ecell_view->e_table_model, model_col, row)
- && event->type == GDK_BUTTON_RELEASE
- && event->button.button == 1) {
- GdkEventButton button = event->button;
-
- e_table_item_enter_edit (text_view->cell_view.e_table_item_view, view_col, row);
- edit = text_view->edit;
- edit_display = TRUE;
-
- e_tep_event.button.type = GDK_BUTTON_PRESS;
- e_tep_event.button.time = button.time;
- e_tep_event.button.state = button.state;
- e_tep_event.button.button = button.button;
- e_tep_event.button.position = get_position_from_xy (edit, event->button.x, event->button.y);
- _get_tep (edit);
- edit->actions = 0;
- return_val = e_text_event_processor_handle_event (edit->tep,
- &e_tep_event);
- *actions = edit->actions;
- if (event->button.button == 1) {
- if (event->type == GDK_BUTTON_PRESS)
- edit->button_down = TRUE;
- else
- edit->button_down = FALSE;
- }
- edit->lastx = button.x;
- edit->lasty = button.y;
- edit->last_state = button.state;
-
- e_tep_event.button.type = GDK_BUTTON_RELEASE;
- }
- if (edit_display) {
- GdkEventButton button = event->button;
- e_tep_event.button.time = button.time;
- e_tep_event.button.state = button.state;
- e_tep_event.button.button = button.button;
- e_tep_event.button.position = get_position_from_xy (edit, event->button.x, event->button.y);
- _get_tep (edit);
- edit->actions = 0;
- return_val = e_text_event_processor_handle_event (edit->tep,
- &e_tep_event);
- *actions = edit->actions;
- if (event->button.button == 1) {
- if (event->type == GDK_BUTTON_PRESS)
- edit->button_down = TRUE;
- else
- edit->button_down = FALSE;
- }
- edit->lastx = button.x;
- edit->lasty = button.y;
- edit->last_state = button.state;
- }
- break;
- case GDK_MOTION_NOTIFY:
- event->motion.x -= 4;
- event->motion.y -= 1;
- if (edit_display) {
- GdkEventMotion motion = event->motion;
- e_tep_event.motion.time = motion.time;
- e_tep_event.motion.state = motion.state;
- e_tep_event.motion.position = get_position_from_xy (edit, event->motion.x, event->motion.y);
- _get_tep (edit);
- edit->actions = 0;
- return_val = e_text_event_processor_handle_event (edit->tep,
- &e_tep_event);
- *actions = edit->actions;
- edit->lastx = motion.x;
- edit->lasty = motion.y;
- edit->last_state = motion.state;
- }
- break;
- case GDK_ENTER_NOTIFY:
-#if 0
- edit->pointer_in = TRUE;
-#endif
- if (edit_display) {
- if (edit->default_cursor_shown){
- gdk_window_set_cursor (canvas->window, text_view->i_cursor);
- edit->default_cursor_shown = FALSE;
- }
- }
- break;
- case GDK_LEAVE_NOTIFY:
-#if 0
- text_view->pointer_in = FALSE;
-#endif
- if (edit_display) {
- if (! edit->default_cursor_shown){
- gdk_window_set_cursor (canvas->window, NULL);
- edit->default_cursor_shown = TRUE;
- }
- }
- break;
- default:
- break;
- }
-
- return return_val;
-}
-
-/*
- * ECell::height method
- */
-static int
-ect_height (ECellView *ecell_view, int model_col, int view_col, int row)
-{
- ECellTextView *text_view = (ECellTextView *) ecell_view;
- gint height;
- PangoLayout *layout;
-
- layout = generate_layout (text_view, model_col, view_col, row, 0);
- pango_layout_get_pixel_size (layout, NULL, &height);
- g_object_unref (layout);
- return height + 2;
-}
-
-/*
- * ECellView::enter_edit method
- */
-static void *
-ect_enter_edit (ECellView *ecell_view, int model_col, int view_col, int row)
-{
- ECellTextView *text_view = (ECellTextView *) ecell_view;
- CellEdit *edit;
- ECellText *ect = E_CELL_TEXT(ecell_view->ecell);
- char *temp;
-
- edit = g_new0 (CellEdit, 1);
- text_view->edit = edit;
-
- edit->im_context = E_CANVAS (text_view->canvas)->im_context;
- edit->need_im_reset = FALSE;
- edit->im_context_signals_registered = FALSE;
- edit->view_col = -1;
- edit->model_col = -1;
- edit->row = -1;
-
- edit->text_view = text_view;
- edit->model_col = model_col;
- edit->view_col = view_col;
- edit->row = row;
- edit->cell_width = e_table_header_get_column (
- ((ETableItem *)ecell_view->e_table_item_view)->header,
- view_col)->width - 8;
-
- edit->layout = generate_layout (text_view, model_col, view_col, row, edit->cell_width);
-
- edit->xofs_edit = 0.0;
- edit->yofs_edit = 0.0;
-
- edit->selection_start = 0;
- edit->selection_end = 0;
- edit->select_by_word = FALSE;
-
- edit->timeout_id = g_timeout_add (10, _blink_scroll_timeout, text_view);
- edit->timer = g_timer_new ();
- g_timer_elapsed (edit->timer, &(edit->scroll_start));
- g_timer_start (edit->timer);
-
- edit->lastx = 0;
- edit->lasty = 0;
- edit->last_state = 0;
-
- edit->scroll_start = 0;
- edit->show_cursor = TRUE;
- edit->button_down = FALSE;
-
- edit->tep = NULL;
-
- edit->has_selection = FALSE;
-
- edit->invisible = NULL;
- edit->primary_selection = NULL;
- edit->primary_length = 0;
- edit->clipboard_selection = NULL;
- edit->clipboard_length = 0;
-
- edit->pointer_in = FALSE;
- edit->default_cursor_shown = TRUE;
-
- temp = e_cell_text_get_text(ect, ecell_view->e_table_model, model_col, row);
- edit->old_text = g_strdup (temp);
- e_cell_text_free_text(ect, temp);
- edit->text = g_strdup (edit->old_text);
-
-#if 0
- if (edit->pointer_in){
- if (edit->default_cursor_shown){
- gdk_window_set_cursor (GTK_WIDGET(item->canvas)->window, text_view->i_cursor);
- edit->default_cursor_shown = FALSE;
- }
- }
-#endif
- ect_queue_redraw (text_view, view_col, row);
-
- return NULL;
-}
-
-/*
- * ECellView::leave_edit method
- */
-static void
-ect_leave_edit (ECellView *ecell_view, int model_col, int view_col, int row, void *edit_context)
-{
- ECellTextView *text_view = (ECellTextView *) ecell_view;
- CellEdit *edit = text_view->edit;
-
- if (edit){
- ect_stop_editing (text_view, TRUE);
- } else {
- /*
- * We did invoke this leave edit internally
- */
- }
-}
-
-/*
- * ECellView::save_state method
- */
-static void *
-ect_save_state (ECellView *ecell_view, int model_col, int view_col, int row, void *edit_context)
-{
- ECellTextView *text_view = (ECellTextView *) ecell_view;
- CellEdit *edit = text_view->edit;
-
- int *save_state = g_new (int, 2);
-
- save_state[0] = edit->selection_start;
- save_state[1] = edit->selection_end;
- return save_state;
-}
-
-/*
- * ECellView::load_state method
- */
-static void
-ect_load_state (ECellView *ecell_view, int model_col, int view_col, int row, void *edit_context, void *save_state)
-{
- ECellTextView *text_view = (ECellTextView *) ecell_view;
- CellEdit *edit = text_view->edit;
- int length;
- int *selection = save_state;
-
- length = strlen (edit->text);
-
- edit->selection_start = MIN (selection[0], length);
- edit->selection_end = MIN (selection[1], length);
-
- ect_queue_redraw (text_view, view_col, row);
-}
-
-/*
- * ECellView::free_state method
- */
-static void
-ect_free_state (ECellView *ecell_view, int model_col, int view_col, int row, void *save_state)
-{
- g_free (save_state);
-}
-
-#define FONT_NAME "Sans Regular"
-
-static GnomeFont *
-get_font_for_size (double h)
-{
- GnomeFontFace *face;
- GnomeFont *font;
- double asc, desc, size;
-
- face = gnome_font_face_find (FONT_NAME);
-
- asc = gnome_font_face_get_ascender (face);
- desc = abs (gnome_font_face_get_descender (face));
- size = h * 1000 / (asc + desc);
-
- font = gnome_font_find_closest (FONT_NAME, size);
-
- g_object_unref (face);
- return font;
-}
-
-static void
-ect_print (ECellView *ecell_view, GnomePrintContext *context,
- int model_col, int view_col, int row,
- double width, double height)
-{
- GnomeFont *font = get_font_for_size (16);
- char *string;
- ECellText *ect = E_CELL_TEXT(ecell_view->ecell);
- double ty, ly, text_width;
- gboolean strikeout, underline;
-
- string = e_cell_text_get_text(ect, ecell_view->e_table_model, model_col, row);
- gnome_print_gsave(context);
- if (gnome_print_moveto(context, 2, 2) == -1)
- /* FIXME */;
- if (gnome_print_lineto(context, width - 2, 2) == -1)
- /* FIXME */;
- if (gnome_print_lineto(context, width - 2, height - 2) == -1)
- /* FIXME */;
- if (gnome_print_lineto(context, 2, height - 2) == -1)
- /* FIXME */;
- if (gnome_print_lineto(context, 2, 2) == -1)
- /* FIXME */;
- if (gnome_print_clip(context) == -1)
- /* FIXME */;
-
- ty = (height - gnome_font_get_ascender(font) - gnome_font_get_descender(font)) / 2;
- text_width = gnome_font_get_width_utf8 (font, string);
-
- strikeout = ect->strikeout_column >= 0 && row >= 0 &&
- e_table_model_value_at (ecell_view->e_table_model, ect->strikeout_column, row);
- underline = ect->underline_column >= 0 && row >= 0 &&
- e_table_model_value_at(ecell_view->e_table_model, ect->underline_column, row);
-
- if (underline) {
- ly = ty + gnome_font_get_underline_position (font);
- gnome_print_newpath (context);
- gnome_print_moveto (context, 2, ly);
- gnome_print_lineto (context, MIN (2 + text_width, width - 2), ly);
- gnome_print_setlinewidth (context, gnome_font_get_underline_thickness (font));
- gnome_print_stroke (context);
- }
-
- if (strikeout) {
- ly = ty + (gnome_font_get_ascender (font) - gnome_font_get_underline_thickness (font))/ 2.0;
- gnome_print_newpath (context);
- gnome_print_moveto (context, 2, ly);
- gnome_print_lineto (context, MIN (2 + text_width, width - 2), ly);
- gnome_print_setlinewidth (context, gnome_font_get_underline_thickness (font));
- gnome_print_stroke (context);
- }
-
- gnome_print_moveto(context, 2, ty);
- gnome_print_setfont(context, font);
- gnome_print_show(context, string);
- gnome_print_grestore(context);
- e_cell_text_free_text(ect, string);
- g_object_unref (font);
-}
-
-static gdouble
-ect_print_height (ECellView *ecell_view, GnomePrintContext *context,
- int model_col, int view_col, int row,
- double width)
-{
- return 16;
-}
-
-static int
-ect_max_width (ECellView *ecell_view,
- int model_col,
- int view_col)
-{
- /* New ECellText */
- ECellTextView *text_view = (ECellTextView *) ecell_view;
- int row;
- int number_of_rows;
- int max_width = 0;
-
- number_of_rows = e_table_model_row_count (ecell_view->e_table_model);
-
- for (row = 0; row < number_of_rows; row++) {
- PangoLayout *layout = generate_layout (text_view, model_col, view_col, row, 0);
- int width;
-
- pango_layout_get_pixel_size (layout, &width, NULL);
-
- max_width = MAX (max_width, width);
- g_object_unref (layout);
- }
-
- return max_width + 8;
-}
-
-static int
-ect_max_width_by_row (ECellView *ecell_view,
- int model_col,
- int view_col,
- int row)
-{
- /* New ECellText */
- ECellTextView *text_view = (ECellTextView *) ecell_view;
- int width;
- PangoLayout *layout;
-
- if (row >= e_table_model_row_count (ecell_view->e_table_model))
- return 0;
-
- layout = generate_layout (text_view, model_col, view_col, row, 0);
- pango_layout_get_pixel_size (layout, &width, NULL);
- g_object_unref (layout);
-
- return width + 8;
-}
-
-static gint
-tooltip_event (GtkWidget *window,
- GdkEvent *event,
- ETableTooltip *tooltip)
-{
- gint ret_val = FALSE;
-
- switch (event->type) {
- case GDK_LEAVE_NOTIFY:
- e_canvas_hide_tooltip (E_CANVAS(GNOME_CANVAS_ITEM(tooltip->eti)->canvas));
- break;
- case GDK_BUTTON_PRESS:
- case GDK_BUTTON_RELEASE:
- if (event->type == GDK_BUTTON_RELEASE) {
- e_canvas_hide_tooltip (E_CANVAS(GNOME_CANVAS_ITEM(tooltip->eti)->canvas));
- }
-
- event->button.x = tooltip->cx;
- event->button.y = tooltip->cy;
- g_signal_emit_by_name (tooltip->eti, "event",
- event, &ret_val);
- if (!ret_val)
- gtk_propagate_event (GTK_WIDGET(GNOME_CANVAS_ITEM(tooltip->eti)->canvas), event);
- ret_val = TRUE;
- break;
- case GDK_KEY_PRESS:
- e_canvas_hide_tooltip (E_CANVAS(GNOME_CANVAS_ITEM(tooltip->eti)->canvas));
- g_signal_emit_by_name (tooltip->eti, "event",
- event, &ret_val);
- if (!ret_val)
- gtk_propagate_event (GTK_WIDGET(GNOME_CANVAS_ITEM(tooltip->eti)->canvas), event);
- ret_val = TRUE;
- break;
- default:
- break;
- }
-
- return ret_val;
-}
-
-static void
-ect_show_tooltip (ECellView *ecell_view,
- int model_col,
- int view_col,
- int row,
- int col_width,
- ETableTooltip *tooltip)
-{
- ECellTextView *text_view = (ECellTextView *) ecell_view;
- GtkWidget *canvas;
- double i2c[6];
- ArtPoint origin = {0, 0};
- ArtPoint pixel_origin;
- int canvas_x, canvas_y;
- GnomeCanvasItem *tooltip_text;
- double tooltip_width;
- double tooltip_height;
- double tooltip_x;
- double tooltip_y;
- GnomeCanvasItem *rect;
- ECellText *ect = E_CELL_TEXT(ecell_view->ecell);
- GtkWidget *window;
- PangoLayout *layout;
- int width, height;
-
- tooltip->timer = 0;
-
- layout = generate_layout (text_view, model_col, view_col, row, col_width);
-
- pango_layout_get_pixel_size (layout, &width, &height);
- if (width < col_width - 8) {
- return;
- }
-
- gnome_canvas_item_i2c_affine (GNOME_CANVAS_ITEM (tooltip->eti), i2c);
- art_affine_point (&pixel_origin, &origin, i2c);
-
- gdk_window_get_origin (GTK_WIDGET (text_view->canvas)->window,
- &canvas_x, &canvas_y);
- pixel_origin.x += canvas_x;
- pixel_origin.y += canvas_y;
- pixel_origin.x -= (int) gtk_layout_get_hadjustment (GTK_LAYOUT (text_view->canvas))->value;
- pixel_origin.y -= (int) gtk_layout_get_vadjustment (GTK_LAYOUT (text_view->canvas))->value;
-
- window = gtk_window_new (GTK_WINDOW_POPUP);
- gtk_container_set_border_width (GTK_CONTAINER (window), 1);
-
- canvas = e_canvas_new ();
- gtk_container_add (GTK_CONTAINER (window), canvas);
- GTK_WIDGET_UNSET_FLAGS (canvas, GTK_CAN_FOCUS);
- GTK_WIDGET_UNSET_FLAGS (window, GTK_CAN_FOCUS);
-
- rect = gnome_canvas_item_new (gnome_canvas_root (GNOME_CANVAS (canvas)),
- gnome_canvas_rect_get_type (),
- "x1", (double) 0.0,
- "y1", (double) 0.0,
- "x2", (double) width + 4,
- "y2", (double) height,
- "fill_color_gdk", tooltip->background,
- NULL);
-
- tooltip_text = gnome_canvas_item_new (gnome_canvas_root (GNOME_CANVAS (canvas)),
- e_text_get_type (),
- "anchor", GTK_ANCHOR_NW,
- "bold", (gboolean) ect->bold_column >= 0 && e_table_model_value_at(ecell_view->e_table_model, ect->bold_column, row),
- "strikeout", (gboolean) ect->strikeout_column >= 0 && e_table_model_value_at(ecell_view->e_table_model, ect->strikeout_column, row),
- "underline", (gboolean) ect->underline_column >= 0 && e_table_model_value_at(ecell_view->e_table_model, ect->underline_column, row),
- "fill_color_gdk", tooltip->foreground,
- "text", pango_layout_get_text (layout),
- "editable", FALSE,
- "clip_width", (double) width,
- "clip_height", (double) height,
- "clip", TRUE,
- "line_wrap", FALSE,
- "justification", E_CELL_TEXT (text_view->cell_view.ecell)->justify,
- "draw_background", FALSE,
- NULL);
-
- tooltip_width = width;
- tooltip_height = height;
- tooltip_y = tooltip->y;
-
- switch (E_CELL_TEXT (text_view->cell_view.ecell)->justify) {
- case GTK_JUSTIFY_CENTER:
- tooltip_x = - tooltip_width / 2;
- break;
- case GTK_JUSTIFY_RIGHT:
- tooltip_x = tooltip_width / 2;
- break;
- case GTK_JUSTIFY_FILL:
- case GTK_JUSTIFY_LEFT:
- tooltip_x = tooltip->x;
- break;
- }
-
- gnome_canvas_item_move (tooltip_text, 3.0, 1.0);
- gnome_canvas_item_set (rect,
- "x2", (double) tooltip_width + 6,
- "y2", (double) tooltip->row_height + 1,
- NULL);
- gtk_widget_set_usize (window, tooltip_width + 6,
- tooltip->row_height + 1);
- gnome_canvas_set_scroll_region (GNOME_CANVAS (canvas), 0.0, 0.0,
- (double) tooltip_width + 6,
- (double) tooltip_height);
- gtk_widget_show (canvas);
- gtk_widget_realize (window);
- g_signal_connect (window, "event",
- G_CALLBACK (tooltip_event), tooltip);
-
- e_canvas_popup_tooltip (E_CANVAS(text_view->canvas), window, pixel_origin.x + tooltip->x,
- pixel_origin.y + tooltip->y - 1);
-
- return;
-}
-
-/*
- * GtkObject::destroy method
- */
-static void
-ect_finalize (GObject *object)
-{
- ECellText *ect = E_CELL_TEXT (object);
-
- g_free (ect->font_name);
-
- G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-/* Set_arg handler for the text item */
-static void
-ect_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- ECellText *text;
-
- text = E_CELL_TEXT (object);
-
- switch (prop_id) {
- case PROP_STRIKEOUT_COLUMN:
- text->strikeout_column = g_value_get_int (value);
- break;
-
- case PROP_UNDERLINE_COLUMN:
- text->underline_column = g_value_get_int (value);
- break;
-
- case PROP_BOLD_COLUMN:
- text->bold_column = g_value_get_int (value);
- break;
-
- case PROP_COLOR_COLUMN:
- text->color_column = g_value_get_int (value);
- break;
-
- case PROP_EDITABLE:
- text->editable = g_value_get_boolean (value);
- break;
-
- case PROP_BG_COLOR_COLUMN:
- text->bg_color_column = g_value_get_int (value);
- break;
-
- default:
- return;
- }
-}
-
-/* Get_arg handler for the text item */
-static void
-ect_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- ECellText *text;
-
- text = E_CELL_TEXT (object);
-
- switch (prop_id) {
- case PROP_STRIKEOUT_COLUMN:
- g_value_set_int (value, text->strikeout_column);
- break;
-
- case PROP_UNDERLINE_COLUMN:
- g_value_set_int (value, text->underline_column);
- break;
-
- case PROP_BOLD_COLUMN:
- g_value_set_int (value, text->bold_column);
- break;
-
- case PROP_COLOR_COLUMN:
- g_value_set_int (value, text->color_column);
- break;
-
- case PROP_EDITABLE:
- g_value_set_boolean (value, text->editable);
- break;
-
- case PROP_BG_COLOR_COLUMN:
- g_value_set_int (value, text->bg_color_column);
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static char *ellipsis_default = NULL;
-static gboolean use_ellipsis_default = TRUE;
-
-static void
-e_cell_text_class_init (GObjectClass *object_class)
-{
- ECellClass *ecc = (ECellClass *) object_class;
- ECellTextClass *ectc = (ECellTextClass *) object_class;
- const char *ellipsis_env;
-
- G_OBJECT_CLASS (object_class)->finalize = ect_finalize;
-
- ecc->new_view = ect_new_view;
- ecc->kill_view = ect_kill_view;
- ecc->realize = ect_realize;
- ecc->unrealize = ect_unrealize;
- ecc->draw = ect_draw;
- ecc->event = ect_event;
- ecc->height = ect_height;
- ecc->enter_edit = ect_enter_edit;
- ecc->leave_edit = ect_leave_edit;
- ecc->save_state = ect_save_state;
- ecc->load_state = ect_load_state;
- ecc->free_state = ect_free_state;
- ecc->print = ect_print;
- ecc->print_height = ect_print_height;
- ecc->max_width = ect_max_width;
- ecc->max_width_by_row = ect_max_width_by_row;
- ecc->show_tooltip = ect_show_tooltip;
- ecc->get_bg_color = ect_get_bg_color;
-
- ectc->get_text = ect_real_get_text;
- ectc->free_text = ect_real_free_text;
- ectc->set_value = ect_real_set_value;
-
- object_class->get_property = ect_get_property;
- object_class->set_property = ect_set_property;
-
- parent_class = g_type_class_ref (PARENT_TYPE);
-
- signals [TEXT_INSERTED] =
- g_signal_new ("text_inserted",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (ECellTextClass, text_inserted),
- NULL, NULL,
- e_marshal_VOID__POINTER_INT_INT_INT_INT,
- G_TYPE_NONE, 5,
- G_TYPE_POINTER, G_TYPE_INT, G_TYPE_INT,
- G_TYPE_INT, G_TYPE_INT);
-
- signals [TEXT_DELETED] =
- g_signal_new ("text_deleted",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (ECellTextClass, text_deleted),
- NULL, NULL,
- e_marshal_VOID__POINTER_INT_INT_INT_INT,
- G_TYPE_NONE, 5,
- G_TYPE_POINTER, G_TYPE_INT, G_TYPE_INT,
- G_TYPE_INT, G_TYPE_INT);
-
-
-
- g_object_class_install_property (object_class, PROP_STRIKEOUT_COLUMN,
- g_param_spec_int ("strikeout_column",
- _("Strikeout Column"),
- /*_( */"XXX blurb" /*)*/,
- -1, G_MAXINT, -1,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class, PROP_UNDERLINE_COLUMN,
- g_param_spec_int ("underline_column",
- _("Underline Column"),
- /*_( */"XXX blurb" /*)*/,
- -1, G_MAXINT, -1,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class, PROP_BOLD_COLUMN,
- g_param_spec_int ("bold_column",
- _("Bold Column"),
- /*_( */"XXX blurb" /*)*/,
- -1, G_MAXINT, -1,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class, PROP_COLOR_COLUMN,
- g_param_spec_int ("color_column",
- _("Color Column"),
- /*_( */"XXX blurb" /*)*/,
- -1, G_MAXINT, -1,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class, PROP_EDITABLE,
- g_param_spec_boolean ("editable",
- _("Editable"),
- /*_( */"XXX blurb" /*)*/,
- FALSE,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class, PROP_BG_COLOR_COLUMN,
- g_param_spec_int ("bg_color_column",
- _("BG Color Column"),
- /*_( */"XXX blurb" /*)*/,
- -1, G_MAXINT, -1,
- G_PARAM_READWRITE));
-
- if (!clipboard_atom)
- clipboard_atom = gdk_atom_intern ("CLIPBOARD", FALSE);
-
- ellipsis_env = g_getenv ("GAL_ELLIPSIS");
- if (ellipsis_env) {
- if (*ellipsis_env) {
- ellipsis_default = g_strdup (ellipsis_env);
- } else {
- use_ellipsis_default = FALSE;
- }
- }
-
- gal_a11y_e_cell_registry_add_cell_type (NULL, E_CELL_TEXT_TYPE, gal_a11y_e_cell_text_new);
-}
-
-
-/* IM Context Callbacks */
-
-static void
-e_cell_text_preedit_changed_cb (GtkIMContext *context,
- ECellTextView *tv)
-{
- gchar *preedit_string;
- gint cursor_pos;
- CellEdit *edit=tv->edit;
- gtk_im_context_get_preedit_string (edit->im_context, &preedit_string,
- NULL, &cursor_pos);
-
- edit->preedit_length = strlen (preedit_string);
- cursor_pos = CLAMP (cursor_pos, 0, g_utf8_strlen (preedit_string, -1));
- g_free (preedit_string);
- ect_queue_redraw (tv, edit->view_col, edit->row);
-}
-
-static void
-e_cell_text_commit_cb (GtkIMContext *context,
- const gchar *str,
- ECellTextView *tv)
-{
- CellEdit *edit = tv->edit;
- ETextEventProcessorCommand command;
-
- if (g_utf8_validate (str, strlen (str), NULL)) {
- command.action = E_TEP_INSERT;
- command.position = E_TEP_SELECTION;
- command.string = (gchar *)str;
- command.value = strlen(str);
- e_cell_text_view_command (edit->tep, &command, edit);
- }
-
-}
-
-static gboolean
-e_cell_text_retrieve_surrounding_cb (GtkIMContext *context,
- ECellTextView *tv)
-{
- int cur_pos = 0;
- CellEdit *edit = tv->edit;
-
- cur_pos = g_utf8_pointer_to_offset (edit->text, edit->text + edit->selection_start);
-
- gtk_im_context_set_surrounding (context,
- edit->text,
- strlen (edit->text),
- cur_pos
- );
-
- return TRUE;
-}
-
-static gboolean
-e_cell_text_delete_surrounding_cb (GtkIMContext *context,
- gint offset,
- gint n_chars,
- ECellTextView *tv)
-{
- CellEdit *edit = tv->edit;
-
- gtk_editable_delete_text (GTK_EDITABLE (edit),
- edit->selection_end + offset,
- edit->selection_end + offset + n_chars);
-
- return TRUE;
-}
-
-static void
-e_cell_text_init (ECellText *ect)
-{
- ect->ellipsis = g_strdup (ellipsis_default);
- ect->use_ellipsis = use_ellipsis_default;
- ect->strikeout_column = -1;
- ect->underline_column = -1;
- ect->bold_column = -1;
- ect->color_column = -1;
- ect->bg_color_column = -1;
- ect->editable = TRUE;
-}
-
-E_MAKE_TYPE(e_cell_text, "ECellText", ECellText, e_cell_text_class_init, e_cell_text_init, PARENT_TYPE)
-
-/**
- * e_cell_text_construct:
- * @cell: The cell to construct
- * @fontname: this param is no longer used, but left here for api stability
- * @justify: Justification of the string in the cell
- *
- * constructs the ECellText. To be used by subclasses and language
- * bindings.
- *
- * Returns: The ECellText.
- */
-ECell *
-e_cell_text_construct (ECellText *cell, const char *fontname, GtkJustification justify)
-{
- if(!cell)
- return E_CELL(NULL);
- if(fontname)
- cell->font_name = g_strdup (fontname);
- cell->justify = justify;
- return E_CELL(cell);
-}
-
-/**
- * e_cell_text_new:
- * @fontname: this param is no longer used, but left here for api stability
- * @justify: Justification of the string in the cell.
- *
- * Creates a new ECell renderer that can be used to render strings that
- * that come from the model. The value returned from the model is
- * interpreted as being a char *.
- *
- * The ECellText object support a large set of properties that can be
- * configured through the Gtk argument system and allows the user to have
- * a finer control of the way the string is displayed. The arguments supported
- * allow the control of strikeout, underline, bold, and color.
- *
- * The arguments "strikeout_column", "underline_column", "bold_column"
- * and "color_column" set and return an integer that points to a
- * column in the model that controls these settings. So controlling
- * the way things are rendered is achieved by having special columns
- * in the model that will be used to flag whether the text should be
- * rendered with strikeout, or bolded. In the case of the
- * "color_column" argument, the column in the model is expected to
- * have a string that can be parsed by gdk_color_parse().
- *
- * Returns: an ECell object that can be used to render strings.
- */
-ECell *
-e_cell_text_new (const char *fontname, GtkJustification justify)
-{
- ECellText *ect = g_object_new (E_CELL_TEXT_TYPE, NULL);
-
- e_cell_text_construct(ect, fontname, justify);
-
- return (ECell *) ect;
-}
-
-
-/* fixme: Handle Font attributes */
-/* position is in BYTES */
-
-static gint
-get_position_from_xy (CellEdit *edit, gint x, gint y)
-{
- int index;
- int trailing;
- const char *text;
-
- PangoLayout *layout = generate_layout (edit->text_view, edit->model_col, edit->view_col, edit->row, edit->cell_width);
- ECellTextView *text_view = edit->text_view;
- ECellText *ect = (ECellText *) ((ECellView *)text_view)->ecell;
-
- x -= (ect->x + text_view->xofs - edit->xofs_edit);
- y -= (ect->y + text_view->yofs - edit->yofs_edit);
-
- pango_layout_xy_to_index (layout, x * PANGO_SCALE, y * PANGO_SCALE, &index, &trailing);
-
- text = pango_layout_get_text (layout);
-
- return g_utf8_offset_to_pointer (text + index, trailing) - text;
-}
-
-#define SCROLL_WAIT_TIME 30000
-
-static gboolean
-_blink_scroll_timeout (gpointer data)
-{
- ECellTextView *text_view = (ECellTextView *) data;
- ECellText *ect = E_CELL_TEXT (((ECellView *)text_view)->ecell);
- CellEdit *edit = text_view->edit;
-
- gulong current_time;
- gboolean scroll = FALSE;
- gboolean redraw = FALSE;
- int width, height;
-
- g_timer_elapsed (edit->timer, &current_time);
-
- if (edit->scroll_start + SCROLL_WAIT_TIME > 1000000) {
- if (current_time > edit->scroll_start - (1000000 - SCROLL_WAIT_TIME) &&
- current_time < edit->scroll_start)
- scroll = TRUE;
- } else {
- if (current_time > edit->scroll_start + SCROLL_WAIT_TIME ||
- current_time < edit->scroll_start)
- scroll = TRUE;
- }
-
- pango_layout_get_pixel_size (edit->layout, &width, &height);
-
- if (scroll && edit->button_down) {
- /* FIXME: Copy this for y. */
- if (edit->lastx - ect->x > edit->cell_width) {
- if (edit->xofs_edit < width - edit->cell_width) {
- edit->xofs_edit += 4;
- if (edit->xofs_edit > width - edit->cell_width + 1)
- edit->xofs_edit = width - edit->cell_width + 1;
- redraw = TRUE;
- }
- }
- if (edit->lastx - ect->x < 0 &&
- edit->xofs_edit > 0) {
- edit->xofs_edit -= 4;
- if (edit->xofs_edit < 0)
- edit->xofs_edit = 0;
- redraw = TRUE;
- }
- if (redraw) {
- ETextEventProcessorEvent e_tep_event;
- e_tep_event.type = GDK_MOTION_NOTIFY;
- e_tep_event.motion.state = edit->last_state;
- e_tep_event.motion.time = 0;
- e_tep_event.motion.position = get_position_from_xy (edit, edit->lastx, edit->lasty);
- _get_tep (edit);
- e_text_event_processor_handle_event (edit->tep,
- &e_tep_event);
- edit->scroll_start = current_time;
- }
- }
-
- if (!((current_time / 500000) % 2)) {
- if (!edit->show_cursor)
- redraw = TRUE;
- edit->show_cursor = TRUE;
- } else {
- if (edit->show_cursor)
- redraw = TRUE;
- edit->show_cursor = FALSE;
- }
- if (redraw){
- ect_queue_redraw (text_view, edit->view_col, edit->row);
- }
- return TRUE;
-}
-
-static int
-next_word (CellEdit *edit, int start)
-{
- char *p;
- int length;
-
- length = strlen (edit->text);
- if (start >= length)
- return length;
-
- p = g_utf8_next_char (edit->text + start);
-
- while (*p && g_unichar_validate (g_utf8_get_char (p))) {
- gunichar unival = g_utf8_get_char (p);
- if (g_unichar_isspace (unival))
- return p - edit->text;
- p = g_utf8_next_char (p);
- }
-
- return p - edit->text;
-}
-
-static int
-_get_position (ECellTextView *text_view, ETextEventProcessorCommand *command)
-{
- int length;
- CellEdit *edit = text_view->edit;
- gchar *p;
- int unival;
- int index;
- int trailing;
-
- switch (command->position) {
-
- case E_TEP_VALUE:
- return command->value;
-
- case E_TEP_SELECTION:
- return edit->selection_end;
-
- case E_TEP_START_OF_BUFFER:
- return 0;
-
- /* fixme: this probably confuses TEP */
-
- case E_TEP_END_OF_BUFFER:
- return strlen (edit->text);
-
- case E_TEP_START_OF_LINE:
-
- if (edit->selection_end < 1) return 0;
-
- p = g_utf8_find_prev_char (edit->text, edit->text + edit->selection_end);
-
- if (p == edit->text) return 0;
-
- p = g_utf8_find_prev_char (edit->text, p);
-
- while (p && p > edit->text) {
- if (*p == '\n') return p - edit->text + 1;
- p = g_utf8_find_prev_char (edit->text, p);
- }
-
- return 0;
-
- case E_TEP_END_OF_LINE:
-
- length = strlen (edit->text);
- if (edit->selection_end >= length) return length;
-
- p = g_utf8_next_char (edit->text + edit->selection_end);
-
- while (*p && g_unichar_validate (g_utf8_get_char (p))) {
- if (*p == '\n') return p - edit->text;
- p = g_utf8_next_char (p);
- }
-
- return p - edit->text;
-
- case E_TEP_FORWARD_CHARACTER:
-
- length = strlen (edit->text);
- if (edit->selection_end >= length) return length;
-
- p = g_utf8_next_char (edit->text + edit->selection_end);
-
- return p - edit->text;
-
- case E_TEP_BACKWARD_CHARACTER:
-
- if (edit->selection_end < 1) return 0;
-
- p = g_utf8_find_prev_char (edit->text, edit->text + edit->selection_end);
-
- if (p == NULL) return 0;
-
- return p - edit->text;
-
- case E_TEP_FORWARD_WORD:
- return next_word (edit, edit->selection_end);
-
- case E_TEP_BACKWARD_WORD:
-
- if (edit->selection_end < 1) return 0;
-
- p = g_utf8_find_prev_char (edit->text, edit->text + edit->selection_end);
-
- if (p == edit->text) return 0;
-
- p = g_utf8_find_prev_char (edit->text, p);
-
- while (p && p > edit->text && g_unichar_validate (g_utf8_get_char (p))) {
- unival = g_utf8_get_char (p);
- if (g_unichar_isspace (unival)) {
- return (g_utf8_next_char (p) - edit->text);
- }
- p = g_utf8_find_prev_char (edit->text, p);
- }
-
- return 0;
-
- case E_TEP_FORWARD_LINE:
- pango_layout_move_cursor_visually (edit->layout,
- TRUE,
- edit->selection_end,
- 0,
- TRUE,
- &index,
- &trailing);
- index = g_utf8_offset_to_pointer (edit->text + index, trailing) - edit->text;
- if (index < 0)
- return 0;
- length = strlen (edit->text);
- if (index >= length)
- return length;
- return index;
- case E_TEP_BACKWARD_LINE:
- pango_layout_move_cursor_visually (edit->layout,
- TRUE,
- edit->selection_end,
- 0,
- TRUE,
- &index,
- &trailing);
-
- index = g_utf8_offset_to_pointer (edit->text + index, trailing) - edit->text;
- if (index < 0)
- return 0;
- length = strlen (edit->text);
- if (index >= length)
- return length;
- return index;
- case E_TEP_FORWARD_PARAGRAPH:
- case E_TEP_BACKWARD_PARAGRAPH:
-
- case E_TEP_FORWARD_PAGE:
- case E_TEP_BACKWARD_PAGE:
- return edit->selection_end;
- default:
- return edit->selection_end;
- }
- g_assert_not_reached ();
- return 0; /* Kill warning */
-}
-
-static void
-_delete_selection (ECellTextView *text_view)
-{
- CellEdit *edit = text_view->edit;
- gint length;
- gchar *sp, *ep;
-
- if (edit->selection_end == edit->selection_start) return;
-
- if (edit->selection_end < edit->selection_start) {
- edit->selection_end ^= edit->selection_start;
- edit->selection_start ^= edit->selection_end;
- edit->selection_end ^= edit->selection_start;
- }
-
- sp = edit->text + edit->selection_start;
- ep = edit->text + edit->selection_end;
- length = strlen (ep) + 1;
-
- memmove (sp, ep, length);
-
- edit->selection_end = edit->selection_start;
-
- g_signal_emit (VIEW_TO_CELL (text_view), signals[TEXT_DELETED], 0, text_view, edit->selection_start, ep-sp, edit->row, edit->model_col);
-}
-
-/* fixme: */
-/* NB! We expect value to be length IN BYTES */
-
-static void
-_insert (ECellTextView *text_view, char *string, int value)
-{
- CellEdit *edit = text_view->edit;
- char *temp;
-
- if (value <= 0) return;
-
- edit->selection_start = MIN (strlen(edit->text), edit->selection_start);
-
- temp = g_new (gchar, strlen (edit->text) + value + 1);
-
- strncpy (temp, edit->text, edit->selection_start);
- strncpy (temp + edit->selection_start, string, value);
- strcpy (temp + edit->selection_start + value, edit->text + edit->selection_end);
-
- g_free (edit->text);
-
- edit->text = temp;
-
- edit->selection_start += value;
- edit->selection_end = edit->selection_start;
-
- g_signal_emit (VIEW_TO_CELL (text_view), signals[TEXT_INSERTED], 0, text_view, edit->selection_end-value, value, edit->row, edit->model_col);
-}
-
-static void
-capitalize (CellEdit *edit, int start, int end, ETextEventProcessorCaps type)
-{
- ECellTextView *text_view = edit->text_view;
-
- gboolean first = TRUE;
- int character_length = g_utf8_strlen (edit->text + start, start - end);
- const char *p = edit->text + start;
- const char *text_end = edit->text + end;
- char *new_text = g_new0 (char, character_length * 6 + 1);
- char *output = new_text;
-
- while (p && *p && p < text_end && g_unichar_validate (g_utf8_get_char (p))) {
- gunichar unival = g_utf8_get_char (p);
- gunichar newval = unival;
-
- switch (type) {
- case E_TEP_CAPS_UPPER:
- newval = g_unichar_toupper (unival);
- break;
- case E_TEP_CAPS_LOWER:
- newval = g_unichar_tolower (unival);
- break;
- case E_TEP_CAPS_TITLE:
- if (g_unichar_isalpha (unival)) {
- if (first)
- newval = g_unichar_totitle (unival);
- else
- newval = g_unichar_tolower (unival);
- first = FALSE;
- } else {
- first = TRUE;
- }
- break;
- }
- g_unichar_to_utf8 (newval, output);
- output = g_utf8_next_char (output);
-
- p = g_utf8_next_char (p);
- }
- *output = 0;
-
- edit->selection_end = end;
- edit->selection_start = start;
- _delete_selection (text_view);
-
- _insert (text_view, new_text, output - new_text);
-
- g_free (new_text);
-}
-
-static void
-e_cell_text_view_command (ETextEventProcessor *tep, ETextEventProcessorCommand *command, gpointer data)
-{
- CellEdit *edit = (CellEdit *) data;
- ECellTextView *text_view = edit->text_view;
- ECellText *ect = E_CELL_TEXT (text_view->cell_view.ecell);
-
- gboolean change = FALSE;
- gboolean redraw = FALSE;
-
- int sel_start, sel_end;
-
- /* If the EText isn't editable, then ignore any commands that would
- modify the text. */
- if (!ect->editable && (command->action == E_TEP_DELETE
- || command->action == E_TEP_INSERT
- || command->action == E_TEP_PASTE
- || command->action == E_TEP_GET_SELECTION))
- return;
-
- switch (command->action) {
- case E_TEP_MOVE:
- edit->selection_start = _get_position (text_view, command);
- edit->selection_end = edit->selection_start;
- if (edit->timer) {
- g_timer_reset (edit->timer);
- }
- redraw = TRUE;
- break;
- case E_TEP_SELECT:
- edit->selection_end = _get_position (text_view, command);
- sel_start = MIN(edit->selection_start, edit->selection_end);
- sel_end = MAX(edit->selection_start, edit->selection_end);
- if (sel_start != sel_end) {
- e_cell_text_view_supply_selection (edit, command->time, GDK_SELECTION_PRIMARY,
- edit->text + sel_start,
- sel_end - sel_start);
- } else if (edit->timer) {
- g_timer_reset (edit->timer);
- }
- redraw = TRUE;
- break;
- case E_TEP_DELETE:
- if (edit->selection_end == edit->selection_start) {
- edit->selection_end = _get_position (text_view, command);
- }
- _delete_selection (text_view);
- if (edit->timer) {
- g_timer_reset (edit->timer);
- }
- redraw = TRUE;
- change = TRUE;
- break;
-
- case E_TEP_INSERT:
- if (!edit->preedit_length && edit->selection_end != edit->selection_start) {
- _delete_selection (text_view);
- }
- _insert (text_view, command->string, command->value);
- if (edit->timer) {
- g_timer_reset (edit->timer);
- }
- redraw = TRUE;
- change = TRUE;
- break;
- case E_TEP_COPY:
- sel_start = MIN(edit->selection_start, edit->selection_end);
- sel_end = MAX(edit->selection_start, edit->selection_end);
- if (sel_start != sel_end) {
- e_cell_text_view_supply_selection (edit, command->time, clipboard_atom,
- edit->text + sel_start,
- sel_end - sel_start);
- }
- if (edit->timer) {
- g_timer_reset (edit->timer);
- }
- break;
- case E_TEP_PASTE:
- e_cell_text_view_get_selection (edit, clipboard_atom, command->time);
- if (edit->timer) {
- g_timer_reset (edit->timer);
- }
- redraw = TRUE;
- change = TRUE;
- break;
- case E_TEP_GET_SELECTION:
- e_cell_text_view_get_selection (edit, GDK_SELECTION_PRIMARY, command->time);
- break;
- case E_TEP_ACTIVATE:
- e_table_item_leave_edit_ (text_view->cell_view.e_table_item_view);
- break;
- case E_TEP_SET_SELECT_BY_WORD:
- edit->select_by_word = command->value;
- break;
- case E_TEP_GRAB:
- edit->actions = E_CELL_GRAB;
- break;
- case E_TEP_UNGRAB:
- edit->actions = E_CELL_UNGRAB;
- break;
- case E_TEP_CAPS:
- if (edit->selection_start == edit->selection_end) {
- capitalize (edit, edit->selection_start, next_word (edit, edit->selection_start), command->value);
- } else {
- int selection_start = MIN (edit->selection_start, edit->selection_end);
- int selection_end = edit->selection_start + edit->selection_end - selection_start; /* Slightly faster than MAX */
- capitalize (edit, selection_start, selection_end, command->value);
- }
- if (edit->timer) {
- g_timer_reset (edit->timer);
- }
- redraw = TRUE;
- change = TRUE;
- break;
- case E_TEP_NOP:
- break;
- }
-
- if (change) {
- if (edit->layout)
- g_object_unref (edit->layout);
- edit->layout = build_layout (text_view, edit->row, edit->text, edit->cell_width);
- }
-
- if (!edit->button_down) {
- PangoRectangle strong_pos, weak_pos;
- pango_layout_get_cursor_pos (edit->layout, edit->selection_end, &strong_pos, &weak_pos);
- if (strong_pos.x != weak_pos.x ||
- strong_pos.y != weak_pos.y ||
- strong_pos.width != weak_pos.width ||
- strong_pos.height != weak_pos.height) {
- if (show_pango_rectangle (edit, weak_pos))
- redraw = TRUE;
- }
- if (show_pango_rectangle (edit, strong_pos)) {
- redraw = TRUE;
- }
- }
-
- if (redraw){
- ect_queue_redraw (text_view, edit->view_col, edit->row);
- }
-}
-
-#ifdef DO_SELECTION
-static void
-_selection_clear_event (GtkInvisible *invisible,
- GdkEventSelection *event,
- CellEdit *edit)
-{
- if (event->selection == GDK_SELECTION_PRIMARY) {
- g_free (edit->primary_selection);
- edit->primary_selection = NULL;
- edit->primary_length = 0;
-
- edit->has_selection = FALSE;
-#if 0
- gnome_canvas_item_request_update (GNOME_CANVAS_ITEM(text));
-#endif
-
- } else if (event->selection == clipboard_atom) {
- g_free (edit->clipboard_selection);
- edit->clipboard_selection = NULL;
- edit->clipboard_length = 0;
- }
-}
-
-static void
-_selection_get (GtkInvisible *invisible,
- GtkSelectionData *selection_data,
- guint info,
- guint time_stamp,
- CellEdit *edit)
-{
- switch (info) {
- case E_SELECTION_PRIMARY:
- gtk_selection_data_set (selection_data, UTF8_ATOM,
- 8, edit->primary_selection,
- edit->primary_length);
- break;
- case E_SELECTION_CLIPBOARD:
- gtk_selection_data_set (selection_data, UTF8_ATOM,
- 8, edit->clipboard_selection,
- edit->clipboard_length);
- break;
- }
-}
-
-/* fixme: What happens, if delivered string is not UTF-8? */
-
-static void
-_selection_received (GtkInvisible *invisible,
- GtkSelectionData *selection_data,
- guint time,
- CellEdit *edit)
-{
- if (selection_data->length < 0 ||
- !(selection_data->type == UTF8_ATOM ||
- selection_data->type == GDK_SELECTION_TYPE_STRING)) {
- return;
- } else {
- ETextEventProcessorCommand command;
- command.action = E_TEP_INSERT;
- command.position = E_TEP_SELECTION;
- command.string = selection_data->data;
- command.value = selection_data->length;
- command.time = time;
- e_cell_text_view_command (edit->tep, &command, edit);
- }
-}
-
-static GtkWidget *e_cell_text_view_get_invisible (CellEdit *edit)
-{
- if (edit->invisible == NULL) {
- GtkWidget *invisible = gtk_invisible_new ();
- edit->invisible = invisible;
-
- gtk_selection_add_target (invisible,
- GDK_SELECTION_PRIMARY,
- UTF8_ATOM,
- E_SELECTION_PRIMARY);
- gtk_selection_add_target (invisible,
- clipboard_atom,
- UTF8_ATOM,
- E_SELECTION_CLIPBOARD);
-
- g_signal_connect (invisible, "selection_get",
- G_CALLBACK (_selection_get),
- edit);
- g_signal_connect (invisible, "selection_clear_event",
- G_CALLBACK (_selection_clear_event),
- edit);
- g_signal_connect (invisible, "selection_received",
- G_CALLBACK (_selection_received),
- edit);
- }
- return edit->invisible;
-}
-#endif
-
-static void
-e_cell_text_view_supply_selection (CellEdit *edit, guint time, GdkAtom selection, char *data, gint length)
-{
-#if DO_SELECTION
- gboolean successful;
- GtkWidget *invisible;
-
- invisible = e_cell_text_view_get_invisible (edit);
-
- if (selection == GDK_SELECTION_PRIMARY){
- if (edit->primary_selection) {
- g_free (edit->primary_selection);
- }
- edit->primary_selection = g_strndup (data, length);
- edit->primary_length = length;
- } else if (selection == clipboard_atom) {
- if (edit->clipboard_selection) {
- g_free (edit->clipboard_selection);
- }
- edit->clipboard_selection = g_strndup (data, length);
- edit->clipboard_length = length;
- }
-
- successful = gtk_selection_owner_set (invisible,
- selection,
- time);
-
- if (selection == GDK_SELECTION_PRIMARY)
- edit->has_selection = successful;
-#endif
-}
-
-static void
-e_cell_text_view_get_selection (CellEdit *edit, GdkAtom selection, guint32 time)
-{
-#if DO_SELECTION
- GtkWidget *invisible;
- invisible = e_cell_text_view_get_invisible (edit);
- gtk_selection_convert (invisible,
- selection,
- UTF8_ATOM,
- time);
-#endif
-}
-
-static void
-_get_tep (CellEdit *edit)
-{
- if (!edit->tep) {
- edit->tep = e_text_event_processor_emacs_like_new ();
- g_signal_connect (edit->tep,
- "command",
- G_CALLBACK(e_cell_text_view_command),
- (gpointer) edit);
- }
-}
-
-static GdkColor*
-e_cell_text_get_color (ECellTextView *cell_view, gchar *color_spec)
-{
- ECellText *ect = E_CELL_TEXT (((ECellView*) cell_view)->ecell);
- GdkColormap *colormap;
- GdkColor *color, tmp_color;
-
- /* If the color spec is NULL we use the default color. */
- if (color_spec == NULL)
- return NULL;
-
- /* Create the hash table if we haven't already. */
- if (!ect->colors)
- ect->colors = g_hash_table_new (g_str_hash, g_str_equal);
-
- /* See if we've already allocated the color. Note that we use a
- special value of (GdkColor*) 1 in the hash to indicate that we've
- already tried and failed to allocate the color, so we don't keep
- trying to allocate it. */
- color = g_hash_table_lookup (ect->colors, color_spec);
- if (color == (GdkColor*) 1)
- return NULL;
- if (color)
- return color;
-
- /* Try to parse the color. */
- if (gdk_color_parse (color_spec, &tmp_color)) {
- colormap = gtk_widget_get_colormap (GTK_WIDGET (cell_view->canvas));
-
- /* Try to allocate the color. */
- if (gdk_color_alloc (colormap, &tmp_color))
- color = gdk_color_copy (&tmp_color);
- }
-
- g_hash_table_insert (ect->colors, g_strdup (color_spec),
- color ? color : (GdkColor*) 1);
- return color;
-}
-
-/**
- * e_cell_text_set_selection:
- * @cell_view: the given cell view
- * @col: column of the given cell in the view
- * @row: row of the given cell in the view
- * @start: start offset of the selection
- * @end: end offset of the selection
- *
- * Sets the selection of given text cell.
- * If the current editing cell is not the given cell, this function
- * will return FALSE;
- *
- * If success, the [start, end) part of the text will be selected.
- *
- * This API is most likely to be used by a11y implementations.
- *
- * Returns: whether the action is successful.
- */
-gboolean
-e_cell_text_set_selection (ECellView *cell_view,
- gint col,
- gint row,
- gint start,
- gint end)
-{
- ECellTextView *ectv;
- CellEdit *edit;
- ETextEventProcessorCommand command1, command2;
-
- ectv = (ECellTextView *)cell_view;
- edit = ectv->edit;
- if (!edit)
- return FALSE;
-
- if (edit->view_col != col || edit->row != row)
- return FALSE;
-
- command1.action = E_TEP_MOVE;
- command1.position = E_TEP_VALUE;
- command1.value = start;
- e_cell_text_view_command (edit->tep, &command1, edit);
-
- command2.action = E_TEP_SELECT;
- command2.position = E_TEP_VALUE;
- command2.value = end;
- e_cell_text_view_command (edit->tep, &command2, edit);
-
- return TRUE;
-}
-
-/**
- * e_cell_text_get_selection:
- * @cell_view: the given cell view
- * @col: column of the given cell in the view
- * @row: row of the given cell in the view
- * @start: a pointer to an int value indicates the start offset of the selection
- * @end: a pointer to an int value indicates the end offset of the selection
- *
- * Gets the selection of given text cell.
- * If the current editing cell is not the given cell, this function
- * will return FALSE;
- *
- * This API is most likely to be used by a11y implementations.
- *
- * Returns: whether the action is successful.
- */
-gboolean
-e_cell_text_get_selection (ECellView *cell_view,
- gint col,
- gint row,
- gint *start,
- gint *end)
-{
- ECellTextView *ectv;
- CellEdit *edit;
-
- ectv = (ECellTextView *)cell_view;
- edit = ectv->edit;
- if (!edit)
- return FALSE;
-
- if (edit->view_col != col || edit->row != row)
- return FALSE;
-
- if (start)
- *start = edit->selection_start;
- if (end)
- *end = edit->selection_end;
- return TRUE;
-}
-
-/**
- * e_cell_text_copy_clipboard:
- * @cell_view: the given cell view
- * @col: column of the given cell in the view
- * @row: row of the given cell in the view
- *
- * Copys the selected text to clipboard.
- *
- * This API is most likely to be used by a11y implementations.
- */
-void
-e_cell_text_copy_clipboard (ECellView *cell_view, gint col, gint row)
-{
- ECellTextView *ectv;
- CellEdit *edit;
- ETextEventProcessorCommand command;
-
- ectv = (ECellTextView *)cell_view;
- edit = ectv->edit;
- if (!edit)
- return;
-
- if (edit->view_col != col || edit->row != row)
- return;
-
- command.action = E_TEP_COPY;
- command.time = GDK_CURRENT_TIME;
- e_cell_text_view_command (edit->tep, &command, edit);
-}
-
-/**
- * e_cell_text_paste_clipboard:
- * @cell_view: the given cell view
- * @col: column of the given cell in the view
- * @row: row of the given cell in the view
- *
- * Pastes the text from the clipboardt.
- *
- * This API is most likely to be used by a11y implementations.
- */
-void
-e_cell_text_paste_clipboard (ECellView *cell_view, gint col, gint row)
-{
- ECellTextView *ectv;
- CellEdit *edit;
- ETextEventProcessorCommand command;
-
- ectv = (ECellTextView *)cell_view;
- edit = ectv->edit;
- if (!edit)
- return;
-
- if (edit->view_col != col || edit->row != row)
- return;
-
- command.action = E_TEP_PASTE;
- command.time = GDK_CURRENT_TIME;
- e_cell_text_view_command (edit->tep, &command, edit);
-}
-
-/**
- * e_cell_text_delete_selection:
- * @cell_view: the given cell view
- * @col: column of the given cell in the view
- * @row: row of the given cell in the view
- *
- * Deletes the selected text of the cell.
- *
- * This API is most likely to be used by a11y implementations.
- */
-void
-e_cell_text_delete_selection (ECellView *cell_view, gint col, gint row)
-{
- ECellTextView *ectv;
- CellEdit *edit;
- ETextEventProcessorCommand command;
-
- ectv = (ECellTextView *)cell_view;
- edit = ectv->edit;
- if (!edit)
- return;
-
- if (edit->view_col != col || edit->row != row)
- return;
-
- command.action = E_TEP_DELETE;
- command.position = E_TEP_SELECTION;
- e_cell_text_view_command (edit->tep, &command, edit);
-}
-
-/**
- * e_cell_text_get_text_by_view:
- * @cell_view: the given cell view
- * @col: column of the given cell in the model
- * @row: row of the given cell in the model
- *
- * Get the cell's text directly from CellEdit,
- * during editting this cell, the cell's text value maybe inconsistant
- * with the text got from table_model.
- * The caller should free the text after using it.
- *
- * This API is most likely to be used by a11y implementations.
- */
-char *
-e_cell_text_get_text_by_view (ECellView *cell_view, gint col, gint row)
-{
- ECellTextView *ectv;
- CellEdit *edit;
- gchar *ret, *model_text;
-
- ectv = (ECellTextView *)cell_view;
- edit = ectv->edit;
-
- if (edit && ectv->edit->row == row && ectv->edit->model_col == col) { /* being editted now */
- ret = g_strdup (edit->text);
- } else{
- model_text = e_cell_text_get_text (E_CELL_TEXT (cell_view->ecell),
- cell_view->e_table_model, col, row);
- ret = g_strdup (model_text);
- e_cell_text_free_text (E_CELL_TEXT (cell_view->ecell), model_text);
- }
-
- return ret;
-
-}
diff --git a/widgets/table/e-cell-text.h b/widgets/table/e-cell-text.h
deleted file mode 100644
index 0ef32b9ede..0000000000
--- a/widgets/table/e-cell-text.h
+++ /dev/null
@@ -1,129 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-cell-text.h: Text cell renderer.
- * Copyright 1999, 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Miguel de Icaza <miguel@ximian.com>
- * Chris Lahey <clahey@ximian.com>
- *
- * A lot of code taken from:
- *
- * Text item type for GnomeCanvas widget
- *
- * GnomeCanvas is basically a port of the Tk toolkit's most excellent
- * canvas widget. Tk is copyrighted by the Regents of the University
- * of California, Sun Microsystems, and other parties.
- *
- * Copyright (C) 1998 The Free Software Foundation
- *
- * Author: Federico Mena <federico@nuclecu.unam.mx>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_CELL_TEXT_H_
-#define _E_CELL_TEXT_H_
-#include <gtk/gtkmenu.h>
-#include <libgnomecanvas/gnome-canvas.h>
-#include <gal/e-table/e-cell.h>
-
-G_BEGIN_DECLS
-
-#define E_CELL_TEXT_TYPE (e_cell_text_get_type ())
-#define E_CELL_TEXT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_CELL_TEXT_TYPE, ECellText))
-#define E_CELL_TEXT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_CELL_TEXT_TYPE, ECellTextClass))
-#define E_IS_CELL_TEXT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_CELL_TEXT_TYPE))
-#define E_IS_CELL_TEXT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_CELL_TEXT_TYPE))
-
-typedef struct {
- ECell parent;
-
- GtkJustification justify;
- char *font_name;
-
- double x, y; /* Position at anchor */
-
- gulong pixel; /* Fill color */
-
- /* Clip handling */
- char *ellipsis; /* The ellipsis characters. NULL = "...". */
-
- guint use_ellipsis : 1; /* Whether to use the ellipsis. */
- guint editable : 1; /* Whether the text can be edited. */
-
- int strikeout_column;
- int underline_column;
- int bold_column;
-
- /* This column in the ETable should return a string specifying a color,
- either a color name like "red" or a color spec like "rgb:F/0/0".
- See the XParseColor man page for the formats available. */
- int color_column;
- int bg_color_column;
-
- /* This stores the colors we have allocated. */
- GHashTable *colors;
-} ECellText;
-
-typedef struct {
- ECellClass parent_class;
-
- char *(*get_text) (ECellText *cell, ETableModel *model, int col, int row);
- void (*free_text) (ECellText *cell, char *text);
- void (*set_value) (ECellText *cell, ETableModel *model, int col, int row, const char *text);
- /* signal handlers */
- void (*text_inserted) (ECellText *cell, ECellView *cell_view, int pos, int len, int row, int model_col);
- void (*text_deleted) (ECellText *cell, ECellView *cell_view, int pos, int len, int row, int model_col);
-} ECellTextClass;
-
-GType e_cell_text_get_type (void);
-ECell *e_cell_text_new (const char *fontname, GtkJustification justify);
-ECell *e_cell_text_construct(ECellText *cell, const char *fontname, GtkJustification justify);
-
-/* Gets the value from the model and converts it into a string. In ECellText
- itself, the value is assumed to be a char* and so needs no conversion.
- In subclasses the ETableModel value may be a more complicated datatype. */
-char *e_cell_text_get_text (ECellText *cell, ETableModel *model, int col, int row);
-
-/* Frees the value returned by e_cell_text_get_text(). */
-void e_cell_text_free_text (ECellText *cell, char *text);
-
-/* Sets the ETableModel value, based on the given string. */
-void e_cell_text_set_value (ECellText *cell, ETableModel *model, int col, int row, const char *text);
-
-/* Sets the selection of given text cell */
-gboolean e_cell_text_set_selection (ECellView *cell_view, gint col, gint row, gint start, gint end);
-
-/* Gets the selection of given text cell */
-gboolean e_cell_text_get_selection (ECellView *cell_view, gint col, gint row, gint *start, gint *end);
-
-/* Copys the selected text to the clipboard */
-void e_cell_text_copy_clipboard (ECellView *cell_view, gint col, gint row);
-
-/* Pastes the text from the clipboard */
-void e_cell_text_paste_clipboard (ECellView *cell_view, gint col, gint row);
-
-/* Deletes selected text */
-void e_cell_text_delete_selection (ECellView *cell_view, gint col, gint row);
-
-/* get text directly from view, both col and row are model format */
-char *e_cell_text_get_text_by_view (ECellView *cell_view, gint col, gint row);
-
-G_END_DECLS
-
-#endif /* _E_CELL_TEXT_H_ */
-
-
diff --git a/widgets/table/e-cell-toggle.c b/widgets/table/e-cell-toggle.c
deleted file mode 100644
index 34e8a8b76d..0000000000
--- a/widgets/table/e-cell-toggle.c
+++ /dev/null
@@ -1,489 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-cell-toggle.c - Multi-state image toggle cell object.
- * Copyright 1999, 2000, Ximian, Inc.
- *
- * Authors:
- * Miguel de Icaza <miguel@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <gtk/gtkenums.h>
-#include <gtk/gtkentry.h>
-#include <gtk/gtkwindow.h>
-#include <gtk/gtksignal.h>
-#include <gdk/gdkkeysyms.h>
-#include <libgnomecanvas/gnome-canvas.h>
-#include "e-cell-toggle.h"
-#include "gal/util/e-util.h"
-#include "gal/widgets/e-hsv-utils.h"
-#include "e-table-item.h"
-#include "gal/a11y/e-table/gal-a11y-e-cell-toggle.h"
-#include "gal/a11y/e-table/gal-a11y-e-cell-registry.h"
-
-#define PARENT_TYPE e_cell_get_type ()
-
-typedef struct {
- ECellView cell_view;
- GdkGC *gc;
- GnomeCanvas *canvas;
- GdkPixmap **pixmap_cache;
-} ECellToggleView;
-
-static ECellClass *parent_class;
-
-#define CACHE_SEQ_COUNT 6
-
-static int
-gnome_print_pixbuf (GnomePrintContext *pc, GdkPixbuf *pixbuf)
-{
- if (gdk_pixbuf_get_has_alpha (pixbuf))
- return gnome_print_rgbaimage (pc,
- gdk_pixbuf_get_pixels (pixbuf),
- gdk_pixbuf_get_width (pixbuf),
- gdk_pixbuf_get_height (pixbuf),
- gdk_pixbuf_get_rowstride (pixbuf));
- else
- return gnome_print_rgbimage (pc,
- gdk_pixbuf_get_pixels (pixbuf),
- gdk_pixbuf_get_width (pixbuf),
- gdk_pixbuf_get_height (pixbuf),
- gdk_pixbuf_get_rowstride (pixbuf));
-}
-
-/*
- * ECell::realize method
- */
-static ECellView *
-etog_new_view (ECell *ecell, ETableModel *table_model, void *e_table_item_view)
-{
- ECellToggleView *toggle_view = g_new0 (ECellToggleView, 1);
- ETableItem *eti = E_TABLE_ITEM (e_table_item_view);
- GnomeCanvas *canvas = GNOME_CANVAS_ITEM (eti)->canvas;
- ECellToggle *etog = E_CELL_TOGGLE (ecell);
- int i;
-
- toggle_view->cell_view.ecell = ecell;
- toggle_view->cell_view.e_table_model = table_model;
- toggle_view->cell_view.e_table_item_view = e_table_item_view;
- toggle_view->canvas = canvas;
- toggle_view->pixmap_cache = g_new (GdkPixmap *, etog->n_states * CACHE_SEQ_COUNT);
- for (i = 0; i < etog->n_states * CACHE_SEQ_COUNT; i++)
- toggle_view->pixmap_cache[i] = NULL;
-
- return (ECellView *) toggle_view;
-}
-
-static void
-etog_kill_view (ECellView *ecell_view)
-{
- ECellToggle *etog = E_CELL_TOGGLE (ecell_view->ecell);
- ECellToggleView *toggle_view = (ECellToggleView *) ecell_view;
- int i;
-
- for (i = 0; i < etog->n_states * CACHE_SEQ_COUNT; i++)
- if (toggle_view->pixmap_cache[i])
- gdk_pixmap_unref (toggle_view->pixmap_cache[i]);
- g_free (toggle_view->pixmap_cache);
- g_free (ecell_view);
-}
-
-static void
-etog_realize (ECellView *ecell_view)
-{
- ECellToggleView *toggle_view = (ECellToggleView *) ecell_view;
-
- toggle_view->gc = gdk_gc_new (GTK_WIDGET (toggle_view->canvas)->window);
-}
-
-/*
- * ECell::unrealize method
- */
-static void
-etog_unrealize (ECellView *ecv)
-{
- ECellToggleView *toggle_view = (ECellToggleView *) ecv;
-
- gdk_gc_unref (toggle_view->gc);
- toggle_view->gc = NULL;
-}
-
-#define PIXMAP_CACHE(toggle_view, cache_seq, image_seq) ((toggle_view)->pixmap_cache[(cache_seq) * E_CELL_TOGGLE (((ECellView *) (toggle_view))->ecell)->n_states + (image_seq)])
-
-#define RGB_COLOR(color) (((color).red & 0xff00) << 8 | \
- ((color).green & 0xff00) | \
- ((color).blue & 0xff00) >> 8)
-
-static void
-check_cache (ECellToggleView *toggle_view, int image_seq, int cache_seq)
-{
- ECellView *ecell_view = (ECellView *) toggle_view;
- ECellToggle *etog = E_CELL_TOGGLE (ecell_view->ecell);
-
- if (PIXMAP_CACHE (toggle_view, cache_seq, image_seq) == NULL) {
- GdkPixbuf *image = etog->images[image_seq];
- GdkPixbuf *flat;
- GdkColor color;
- int width = gdk_pixbuf_get_width (image);
- int height = gdk_pixbuf_get_height (image);
-
- PIXMAP_CACHE (toggle_view, cache_seq, image_seq) =
- gdk_pixmap_new (toggle_view->canvas->layout.bin_window, width, height,
- gtk_widget_get_visual (GTK_WIDGET (toggle_view->canvas))->depth);
-
-
- switch (cache_seq % 3) {
- case 0:
- color = GTK_WIDGET (toggle_view->canvas)->style->bg [GTK_STATE_SELECTED];
- break;
- case 1:
- color = GTK_WIDGET (toggle_view->canvas)->style->bg [GTK_STATE_ACTIVE];
- break;
- case 2:
- color = GTK_WIDGET (toggle_view->canvas)->style->base [GTK_STATE_NORMAL];
- break;
- }
-
- if (cache_seq >= 3) {
- e_hsv_tweak (&color, 0.0f, 0.0f, -0.07f);
- }
-
- flat = gdk_pixbuf_composite_color_simple (image,
- width, height,
- GDK_INTERP_BILINEAR,
- 255,
- 1,
- RGB_COLOR (color), RGB_COLOR (color));
-
- gdk_pixbuf_render_to_drawable (flat, PIXMAP_CACHE (toggle_view, cache_seq, image_seq),
- toggle_view->gc,
- 0, 0,
- 0, 0,
- width, height,
- GDK_RGB_DITHER_NORMAL,
- 0, 0);
- gdk_pixbuf_unref (flat);
- }
-}
-
-/*
- * ECell::draw method
- */
-static void
-etog_draw (ECellView *ecell_view, GdkDrawable *drawable,
- int model_col, int view_col, int row, ECellFlags flags,
- int x1, int y1, int x2, int y2)
-{
- ECellToggle *toggle = E_CELL_TOGGLE (ecell_view->ecell);
- gboolean selected;
- ECellToggleView *toggle_view = (ECellToggleView *) ecell_view;
- GdkPixmap *pixmap;
- GdkPixbuf *image;
- int x, y, width, height;
- int cache_seq;
-
- const int value = GPOINTER_TO_INT (
- e_table_model_value_at (ecell_view->e_table_model, model_col, row));
-
- selected = flags & E_CELL_SELECTED;
-
- if (value < 0 || value >= toggle->n_states){
- g_warning ("Value from the table model is %d, the states we support are [0..%d)\n",
- value, toggle->n_states);
- return;
- }
-
- if (flags & E_CELL_SELECTED) {
- if (GTK_WIDGET_HAS_FOCUS (toggle_view->canvas))
- cache_seq = 0;
- else
- cache_seq = 1;
- } else
- cache_seq = 2;
-
- if (E_TABLE_ITEM (ecell_view->e_table_item_view)->alternating_row_colors && (row % 2) == 0)
- cache_seq += 3;
-
- check_cache (toggle_view, value, cache_seq);
-
- pixmap = PIXMAP_CACHE (toggle_view, cache_seq, value);
- image = toggle->images[value];
-
- if ((x2 - x1) < gdk_pixbuf_get_width (image)){
- x = x1;
- width = x2 - x1;
- } else {
- x = x1 + ((x2 - x1) - gdk_pixbuf_get_width (image)) / 2;
- width = gdk_pixbuf_get_width (image);
- }
-
- if ((y2 - y1) < gdk_pixbuf_get_height (image)){
- y = y1;
- height = y2 - y1;
- } else {
- y = y1 + ((y2 - y1) - gdk_pixbuf_get_height (image)) / 2;
- height = gdk_pixbuf_get_height (image);
- }
-
- gdk_draw_pixmap (drawable, toggle_view->gc,
- pixmap,
- 0, 0,
- x, y,
- width, height);
-}
-
-static void
-etog_set_value (ECellToggleView *toggle_view, int model_col, int view_col, int row, int value)
-{
- ECell *ecell = toggle_view->cell_view.ecell;
- ECellToggle *toggle = E_CELL_TOGGLE (ecell);
-
- if (value >= toggle->n_states)
- value = 0;
-
- e_table_model_set_value_at (toggle_view->cell_view.e_table_model,
- model_col, row, GINT_TO_POINTER (value));
-}
-
-/*
- * ECell::event method
- */
-static gint
-etog_event (ECellView *ecell_view, GdkEvent *event, int model_col, int view_col, int row, ECellFlags flags, ECellActions *actions)
-{
- ECellToggleView *toggle_view = (ECellToggleView *) ecell_view;
- void *_value = e_table_model_value_at (ecell_view->e_table_model, model_col, row);
- const int value = GPOINTER_TO_INT (_value);
-
-#if 0
- if (!(flags & E_CELL_EDITING))
- return FALSE;
-#endif
-
- switch (event->type){
- case GDK_KEY_PRESS:
- if (event->key.keyval != GDK_space)
- return FALSE;
- /* Fall through */
- case GDK_BUTTON_PRESS:
- if (!e_table_model_is_cell_editable(ecell_view->e_table_model, model_col, row))
- return FALSE;
-
- etog_set_value (toggle_view, model_col, view_col, row, value + 1);
- return TRUE;
-
- default:
- return FALSE;
- }
- return TRUE;
-}
-
-/*
- * ECell::height method
- */
-static int
-etog_height (ECellView *ecell_view, int model_col, int view_col, int row)
-{
- ECellToggle *toggle = E_CELL_TOGGLE (ecell_view->ecell);
-
- return toggle->height;
-}
-
-/*
- * ECell::print method
- */
-static void
-etog_print (ECellView *ecell_view, GnomePrintContext *context,
- int model_col, int view_col, int row,
- double width, double height)
-{
- ECellToggle *toggle = E_CELL_TOGGLE(ecell_view->ecell);
- GdkPixbuf *image;
- const int value = GPOINTER_TO_INT (
- e_table_model_value_at (ecell_view->e_table_model, model_col, row));
-
- if (value >= toggle->n_states){
- g_warning ("Value from the table model is %d, the states we support are [0..%d)\n",
- value, toggle->n_states);
- return;
- }
-
- gnome_print_gsave(context);
-
- image = toggle->images[value];
-
- gnome_print_translate (context, 0, (height - toggle->height) / 2);
- gnome_print_scale (context, toggle->height, toggle->height);
- gnome_print_pixbuf (context, image);
-
- gnome_print_grestore(context);
-}
-
-static gdouble
-etog_print_height (ECellView *ecell_view, GnomePrintContext *context,
- int model_col, int view_col, int row,
- double width)
-{
- ECellToggle *toggle = E_CELL_TOGGLE (ecell_view->ecell);
-
- return toggle->height;
-}
-
-/*
- * ECell::max_width method
- */
-static int
-etog_max_width (ECellView *ecell_view, int model_col, int view_col)
-{
- ECellToggle *toggle = E_CELL_TOGGLE (ecell_view->ecell);
- int max_width = 0;
- int number_of_rows;
- int row;
-
- number_of_rows = e_table_model_row_count (ecell_view->e_table_model);
- for (row = 0; row < number_of_rows; row++) {
- void *value = e_table_model_value_at (ecell_view->e_table_model,
- model_col, row);
- max_width = MAX (max_width, gdk_pixbuf_get_width (toggle->images[GPOINTER_TO_INT (value)]));
- }
-
- return max_width;
-}
-
-static void
-etog_style_set (ECellView *ecell_view, GtkStyle *previous_style)
-{
- ECellToggle *toggle = E_CELL_TOGGLE (ecell_view->ecell);
- ECellToggleView *toggle_view = (ECellToggleView *) ecell_view;
- int i;
-
- for (i = 0; i < toggle->n_states * CACHE_SEQ_COUNT; i++) {
- if (toggle_view->pixmap_cache[i]) {
- gdk_pixmap_unref (toggle_view->pixmap_cache[i]);
- toggle_view->pixmap_cache[i] = NULL;
- }
- }
-}
-
-static void
-etog_finalize (GObject *object)
-{
- ECellToggle *etog = E_CELL_TOGGLE (object);
- int i;
-
- for (i = 0; i < etog->n_states; i++)
- gdk_pixbuf_unref (etog->images [i]);
-
- g_free (etog->images);
-
- etog->images = NULL;
- etog->n_states = 0;
-
- G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-static void
-e_cell_toggle_class_init (GtkObjectClass *object_class)
-{
- ECellClass *ecc = (ECellClass *) object_class;
-
- G_OBJECT_CLASS (object_class)->finalize = etog_finalize;
-
- ecc->new_view = etog_new_view;
- ecc->kill_view = etog_kill_view;
- ecc->realize = etog_realize;
- ecc->unrealize = etog_unrealize;
- ecc->draw = etog_draw;
- ecc->event = etog_event;
- ecc->height = etog_height;
- ecc->print = etog_print;
- ecc->print_height = etog_print_height;
- ecc->max_width = etog_max_width;
- ecc->style_set = etog_style_set;
-
- parent_class = g_type_class_ref (PARENT_TYPE);
- gal_a11y_e_cell_registry_add_cell_type (NULL,
- E_CELL_TOGGLE_TYPE,
- gal_a11y_e_cell_toggle_new);
-}
-
-static void
-e_cell_toggle_init (GtkObject *object)
-{
- ECellToggle *etog = (ECellToggle *) object;
-
- etog->images = NULL;
- etog->n_states = 0;
-}
-
-E_MAKE_TYPE(e_cell_toggle, "ECellToggle", ECellToggle, e_cell_toggle_class_init, e_cell_toggle_init, PARENT_TYPE)
-
-/**
- * e_cell_toggle_construct:
- * @etog: a fresh ECellToggle object
- * @border: number of pixels used as a border
- * @n_states: number of states the toggle will have
- * @images: a collection of @n_states images, one for each state.
- *
- * Constructs the @etog object with the @border, @n_staes, and @images
- * arguments.
- */
-void
-e_cell_toggle_construct (ECellToggle *etog, int border, int n_states, GdkPixbuf **images)
-{
- int max_height = 0;
- int i;
-
- etog->border = border;
- etog->n_states = n_states;
-
- etog->images = g_new (GdkPixbuf *, n_states);
-
- for (i = 0; i < n_states; i++){
- etog->images [i] = images [i];
- gdk_pixbuf_ref (images [i]);
-
- if (gdk_pixbuf_get_height (images [i]) > max_height)
- max_height = gdk_pixbuf_get_height (images [i]);
- }
-
- etog->height = max_height;
-}
-
-/**
- * e_cell_checkbox_new:
- * @border: number of pixels used as a border
- * @n_states: number of states the toggle will have
- * @images: a collection of @n_states images, one for each state.
- *
- * Creates a new ECell renderer that can be used to render toggle
- * buttons with the images specified in @images. The value returned
- * by ETableModel::get_value is typecase into an integer and clamped
- * to the [0..n_states) range. That will select the image rendered.
- *
- * Returns: an ECell object that can be used to render multi-state
- * toggle cells.
- */
-ECell *
-e_cell_toggle_new (int border, int n_states, GdkPixbuf **images)
-{
- ECellToggle *etog = g_object_new (E_CELL_TOGGLE_TYPE, NULL);
-
- e_cell_toggle_construct (etog, border, n_states, images);
-
- return (ECell *) etog;
-}
diff --git a/widgets/table/e-cell-toggle.h b/widgets/table/e-cell-toggle.h
deleted file mode 100644
index 71d9de3883..0000000000
--- a/widgets/table/e-cell-toggle.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-cell-toggle.h - Multi-state image toggle cell object.
- * Copyright 1999, 2000, Ximian, Inc.
- *
- * Authors:
- * Miguel de Icaza <miguel@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_CELL_TOGGLE_H_
-#define _E_CELL_TOGGLE_H_
-
-#include <libgnomecanvas/gnome-canvas.h>
-#include <gdk-pixbuf/gdk-pixbuf.h>
-#include <gal/e-table/e-cell.h>
-
-G_BEGIN_DECLS
-
-#define E_CELL_TOGGLE_TYPE (e_cell_toggle_get_type ())
-#define E_CELL_TOGGLE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_CELL_TOGGLE_TYPE, ECellToggle))
-#define E_CELL_TOGGLE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_CELL_TOGGLE_TYPE, ECellToggleClass))
-#define E_IS_CELL_TOGGLE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_CELL_TOGGLE_TYPE))
-#define E_IS_CELL_TOGGLE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_CELL_TOGGLE_TYPE))
-
-typedef struct {
- ECell parent;
-
- int border;
- int n_states;
- GdkPixbuf **images;
-
- int height;
-} ECellToggle;
-
-typedef struct {
- ECellClass parent_class;
-} ECellToggleClass;
-
-GType e_cell_toggle_get_type (void);
-ECell *e_cell_toggle_new (int border, int n_states, GdkPixbuf **images);
-void e_cell_toggle_construct (ECellToggle *etog, int border,
- int n_states, GdkPixbuf **images);
-
-G_END_DECLS
-
-#endif /* _E_CELL_TOGGLE_H_ */
-
-
diff --git a/widgets/table/e-cell-tree.c b/widgets/table/e-cell-tree.c
deleted file mode 100644
index a0be81e889..0000000000
--- a/widgets/table/e-cell-tree.c
+++ /dev/null
@@ -1,911 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-cell-tree.c - Tree cell object.
- * Copyright 1999, 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Toshok <toshok@ximian.com>
- *
- * A majority of code taken from:
- *
- * the ECellText renderer.
- * Copyright 1998, The Free Software Foundation
- * Copyright 1999, 2000, Ximian, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-
-#include <ctype.h>
-#include <math.h>
-#include <stdio.h>
-
-#include <gdk/gdkx.h> /* for BlackPixel */
-#include <gtk/gtkenums.h>
-#include <gtk/gtkentry.h>
-#include <gtk/gtkwindow.h>
-#include <gtk/gtkinvisible.h>
-#include <gtk/gtksignal.h>
-#include <gdk/gdkkeysyms.h>
-#include <libgnomecanvas/gnome-canvas.h>
-
-#include "e-tree-table-adapter.h"
-#include "e-tree.h"
-#include "e-tree-model.h"
-#include "gal/util/e-util.h"
-#include "e-table-item.h"
-#include "e-cell-tree.h"
-
-#include "tree-expanded.xpm"
-#include "tree-unexpanded.xpm"
-
-#include "gal/a11y/e-table/gal-a11y-e-cell-registry.h"
-#include "gal/a11y/e-table/gal-a11y-e-cell-tree.h"
-
-#define PARENT_TYPE e_cell_get_type ()
-
-typedef struct {
- ECellView cell_view;
- ECellView *subcell_view;
- GdkGC *gc;
-
- GnomeCanvas *canvas;
- gboolean retro_look;
- gboolean prelit;
- gint animate_timeout;
-
-} ECellTreeView;
-
-static ECellClass *parent_class;
-
-#define INDENT_AMOUNT 16
-
-ECellView *
-e_cell_tree_view_get_subcell_view (ECellView *ect)
-{
- return ((ECellTreeView *)ect)->subcell_view;
-}
-
-static ETreePath
-e_cell_tree_get_node (ETableModel *table_model, int row)
-{
- return e_table_model_value_at (table_model, -1, row);
-}
-
-static ETreeModel*
-e_cell_tree_get_tree_model (ETableModel *table_model, int row)
-{
- return e_table_model_value_at (table_model, -2, row);
-}
-
-static ETreeTableAdapter *
-e_cell_tree_get_tree_table_adapter (ETableModel *table_model, int row)
-{
- return e_table_model_value_at (table_model, -3, row);
-}
-
-static int
-visible_depth_of_node (ETableModel *model, int row)
-{
- ETreeModel *tree_model = e_cell_tree_get_tree_model(model, row);
- ETreeTableAdapter *adapter = e_cell_tree_get_tree_table_adapter(model, row);
- ETreePath path = e_cell_tree_get_node(model, row);
- return (e_tree_model_node_depth (tree_model, path)
- - (e_tree_table_adapter_root_node_is_visible (adapter) ? 0 : 1));
-}
-
-/* If this is changed to not include the width of the expansion pixmap
- if the path is not expandable, then max_width needs to change as
- well. */
-static gint
-offset_of_node (ETableModel *table_model, int row)
-{
- ETreeModel *tree_model = e_cell_tree_get_tree_model(table_model, row);
- ETreePath path = e_cell_tree_get_node(table_model, row);
-
- if (visible_depth_of_node (table_model, row) > 0 ||
- e_tree_model_node_is_expandable(tree_model, path)) {
- return (visible_depth_of_node(table_model, row) + 1) * INDENT_AMOUNT;
- } else {
- return 0;
- }
-}
-
-/*
- * ECell::new_view method
- */
-static ECellView *
-ect_new_view (ECell *ecell, ETableModel *table_model, void *e_table_item_view)
-{
- ECellTree *ect = E_CELL_TREE (ecell);
- ECellTreeView *tree_view = g_new0 (ECellTreeView, 1);
- GnomeCanvas *canvas = GNOME_CANVAS_ITEM (e_table_item_view)->canvas;
-
- tree_view->cell_view.ecell = ecell;
- tree_view->cell_view.e_table_model = table_model;
- tree_view->cell_view.e_table_item_view = e_table_item_view;
-
- /* create our subcell view */
- tree_view->subcell_view = e_cell_new_view (ect->subcell, table_model, e_table_item_view /* XXX */);
-
- tree_view->canvas = canvas;
-
- return (ECellView *)tree_view;
-}
-
-/*
- * ECell::kill_view method
- */
-static void
-ect_kill_view (ECellView *ecv)
-{
- ECellTreeView *tree_view = (ECellTreeView *) ecv;
-
- /* kill our subcell view */
- e_cell_kill_view (tree_view->subcell_view);
-
- g_free (tree_view);
-}
-
-/*
- * ECell::realize method
- */
-static void
-ect_realize (ECellView *ecell_view)
-{
- ECellTreeView *tree_view = (ECellTreeView *) ecell_view;
-
- /* realize our subcell view */
- e_cell_realize (tree_view->subcell_view);
-
- tree_view->gc = gdk_gc_new (GTK_WIDGET (tree_view->canvas)->window);
-
- gdk_gc_set_line_attributes (tree_view->gc, 1,
- GDK_LINE_ON_OFF_DASH, None, None);
- gdk_gc_set_dashes (tree_view->gc, 0, "\1\1", 2);
-
- if (parent_class->realize)
- (* parent_class->realize) (ecell_view);
-}
-
-/*
- * ECell::unrealize method
- */
-static void
-ect_unrealize (ECellView *ecv)
-{
- ECellTreeView *tree_view = (ECellTreeView *) ecv;
-
- /* unrealize our subcell view. */
- e_cell_unrealize (tree_view->subcell_view);
-
- gdk_gc_unref (tree_view->gc);
- tree_view->gc = NULL;
-
- if (parent_class->unrealize)
- (* parent_class->unrealize) (ecv);
-}
-
-static void
-draw_retro_expander (ECellTreeView *ectv, GdkDrawable *drawable, gboolean expanded, GdkRectangle *rect)
-{
- GdkPixbuf *image;
- int image_width, image_height;
- ECellTree *ect = E_CELL_TREE(ectv->cell_view.ecell);
-
- image = expanded ? ect->open_pixbuf : ect->closed_pixbuf;
-
- image_width = gdk_pixbuf_get_width(image);
- image_height = gdk_pixbuf_get_height(image);
-
- gdk_pixbuf_render_to_drawable_alpha (image,
- drawable,
- rect->x, rect->y,
- rect->width - image_width / 2,
- rect->height - image_height / 2,
- image_width, image_height,
- GDK_PIXBUF_ALPHA_BILEVEL,
- 128,
- GDK_RGB_DITHER_NORMAL,
- image_width, 0);
-}
-
-static void
-draw_expander (ECellTreeView *ectv, GdkDrawable *drawable, GtkExpanderStyle expander_style, GtkStateType state, GdkRectangle *rect)
-{
- GtkWidget *tree = GTK_WIDGET (ectv->canvas)->parent;
- gint exp_size;
- gtk_widget_style_get (tree, "expander_size", &exp_size, NULL);
-
- gtk_paint_expander (tree->style, drawable, state, rect, tree, "treeview", rect->x + rect->width - exp_size / 2, rect->y + rect->height / 2, expander_style);
-}
-
-/*
- * ECell::draw method
- */
-static void
-ect_draw (ECellView *ecell_view, GdkDrawable *drawable,
- int model_col, int view_col, int row, ECellFlags flags,
- int x1, int y1, int x2, int y2)
-{
- ECellTreeView *tree_view = (ECellTreeView *)ecell_view;
- ETreeModel *tree_model = e_cell_tree_get_tree_model(ecell_view->e_table_model, row);
- ETreeTableAdapter *tree_table_adapter = e_cell_tree_get_tree_table_adapter(ecell_view->e_table_model, row);
- ETreePath node;
- GdkRectangle rect, *clip_rect = NULL;
- GtkWidget *canvas = GTK_WIDGET (tree_view->canvas);
- GdkGC *fg_gc = canvas->style->fg_gc[GTK_STATE_ACTIVE];
- GdkColor *foreground;
- gboolean selected;
-
- int offset, subcell_offset;
-
- selected = flags & E_CELL_SELECTED;
-
- /* only draw the tree effects if we're the active sort */
- if (/* XXX */ TRUE) {
- GdkPixbuf *node_image;
- int node_image_width = 0, node_image_height = 0;
- ETreePath parent_node;
- ETree *tree = E_TREE (canvas->parent);
-
- gtk_widget_style_get (GTK_WIDGET (tree),
- "retro_look", &tree_view->retro_look,
- NULL);
- tree_view->prelit = FALSE;
-
- node = e_cell_tree_get_node (ecell_view->e_table_model, row);
-
- offset = offset_of_node (ecell_view->e_table_model, row);
- subcell_offset = offset;
-
- node_image = e_tree_model_icon_at (tree_model, node);
-
- if (node_image) {
- node_image_width = gdk_pixbuf_get_width (node_image);
- node_image_height = gdk_pixbuf_get_height (node_image);
- }
-
- /*
- * Be a nice citizen: clip to the region we are supposed to draw on
- */
- rect.x = x1;
- rect.y = y1;
- rect.width = subcell_offset + node_image_width;
- rect.height = y2 - y1;
-
- gdk_gc_set_clip_rectangle (tree_view->gc, &rect);
- gdk_gc_set_clip_rectangle (fg_gc, &rect);
- clip_rect = &rect;
-
- if (selected) {
- foreground = &canvas->style->text [GTK_STATE_SELECTED];
- } else {
- foreground = &canvas->style->text [GTK_STATE_NORMAL];
- }
-
- gdk_gc_set_foreground (tree_view->gc, foreground);
-
- /* draw our lines */
- if (tree_view->retro_look && E_CELL_TREE(tree_view->cell_view.ecell)->draw_lines) {
-
- int depth;
-
- if (visible_depth_of_node (ecell_view->e_table_model, row) > 0
- || e_tree_model_node_get_children (tree_model, node, NULL) > 0)
- gdk_draw_line (drawable, tree_view->gc,
- rect.x + offset - INDENT_AMOUNT / 2 + 1,
- rect.y + rect.height / 2,
- rect.x + offset,
- rect.y + rect.height / 2);
-
- if (visible_depth_of_node (ecell_view->e_table_model, row) != 0) {
- gdk_draw_line (drawable, tree_view->gc,
- rect.x + offset - INDENT_AMOUNT / 2,
- rect.y,
- rect.x + offset - INDENT_AMOUNT / 2,
- (e_tree_table_adapter_node_get_next (tree_table_adapter, node)
- ? rect.y + rect.height
- : rect.y + rect.height / 2));
- }
-
- /* now traverse back up to the root of the tree, checking at
- each level if the node has siblings, and drawing the
- correct vertical pipe for it's configuration. */
- parent_node = e_tree_model_node_get_parent (tree_model, node);
- offset -= INDENT_AMOUNT;
- depth = visible_depth_of_node (ecell_view->e_table_model, row) - 1;
- while (parent_node && depth != 0) {
- if (e_tree_table_adapter_node_get_next(tree_table_adapter, parent_node)) {
- gdk_draw_line (drawable, tree_view->gc,
- rect.x + offset - INDENT_AMOUNT / 2,
- rect.y,
- rect.x + offset - INDENT_AMOUNT / 2,
- rect.y + rect.height);
- }
- parent_node = e_tree_model_node_get_parent (tree_model, parent_node);
- depth --;
- offset -= INDENT_AMOUNT;
- }
- }
-
- /* now draw our icon if we're expandable */
- if (e_tree_model_node_is_expandable (tree_model, node)) {
- gboolean expanded = e_tree_table_adapter_node_is_expanded (tree_table_adapter, node);
- GdkRectangle r;
- if (tree_view->retro_look) {
- r.x = 0;
- r.y = 0;
- r.width = x1 + subcell_offset - INDENT_AMOUNT / 2,
- r.height = y1 + (y2 - y1) / 2,
- draw_retro_expander (tree_view, drawable, expanded, &r);
- } else {
- r = rect;
- r.width -= node_image_width + 2;
- draw_expander (tree_view, drawable, expanded ? GTK_EXPANDER_EXPANDED : GTK_EXPANDER_COLLAPSED, GTK_STATE_NORMAL, &r);
- }
- }
-
- if (node_image) {
- gdk_pixbuf_render_to_drawable_alpha (node_image,
- drawable,
- 0, 0,
- x1 + subcell_offset,
- y1 + (y2 - y1) / 2 - node_image_height / 2,
- node_image_width, node_image_height,
- GDK_PIXBUF_ALPHA_BILEVEL,
- 128,
- GDK_RGB_DITHER_NORMAL,
- node_image_width, 0);
- subcell_offset += node_image_width;
- }
- }
-
- /* Now cause our subcell to draw its contents, shifted by
- subcell_offset pixels */
- e_cell_draw (tree_view->subcell_view, drawable,
- model_col, view_col, row, flags,
- x1 + subcell_offset, y1, x2, y2);
-
- if (clip_rect) {
- gdk_gc_set_clip_rectangle (tree_view->gc, NULL);
- gdk_gc_set_clip_rectangle (fg_gc, NULL);
- }
-}
-
-static void
-adjust_event_position (GdkEvent *event, gint offset)
-{
- switch (event->type) {
- case GDK_BUTTON_PRESS:
- case GDK_BUTTON_RELEASE:
- case GDK_2BUTTON_PRESS:
- case GDK_3BUTTON_PRESS:
- event->button.x += offset;
- break;
- case GDK_MOTION_NOTIFY:
- event->motion.x += offset;
- break;
- default:
- break;
- }
-}
-
-static gboolean
-event_in_expander (GdkEvent *event, gint offset, gint height)
-{
- switch (event->type) {
- case GDK_BUTTON_PRESS:
- return (event->button.x > (offset - INDENT_AMOUNT) && event->button.x < offset);
- case GDK_MOTION_NOTIFY:
- return (event->motion.x > (offset - INDENT_AMOUNT) && event->motion.x < offset &&
- event->motion.y > 2 && event->motion.y < (height - 2));
- default:
- break;
- }
-
- return FALSE;
-}
-
-/*
- * ECell::height method
- */
-static int
-ect_height (ECellView *ecell_view, int model_col, int view_col, int row)
-{
- ECellTreeView *tree_view = (ECellTreeView *) ecell_view;
-
- return (((e_cell_height (tree_view->subcell_view, model_col, view_col, row)) + 1) / 2) * 2;
-}
-
-typedef struct {
- ECellTreeView *ectv;
- ETreeTableAdapter *etta;
- ETreePath node;
- gboolean expanded;
- gboolean finish;
- GdkRectangle area;
-} animate_closure_t;
-
-static gboolean
-animate_expander (gpointer data)
-{
- animate_closure_t *closure = (animate_closure_t *) data;
-
- if (closure->finish) {
- e_tree_table_adapter_node_set_expanded (closure->etta, closure->node, !closure->expanded);
- closure->ectv->animate_timeout = 0;
- g_free (data);
- return FALSE;
- }
-
- draw_expander (closure->ectv, GTK_LAYOUT (closure->ectv->canvas)->bin_window,
- closure->expanded ? GTK_EXPANDER_SEMI_COLLAPSED : GTK_EXPANDER_SEMI_EXPANDED,
- GTK_STATE_NORMAL, &closure->area);
- closure->finish = TRUE;
-
- return TRUE;
-}
-
-/*
- * ECell::event method
- */
-static gint
-ect_event (ECellView *ecell_view, GdkEvent *event, int model_col, int view_col, int row, ECellFlags flags, ECellActions *actions)
-{
- ECellTreeView *tree_view = (ECellTreeView *) ecell_view;
- ETreeModel *tree_model = e_cell_tree_get_tree_model (ecell_view->e_table_model, row);
- ETreeTableAdapter *etta = e_cell_tree_get_tree_table_adapter(ecell_view->e_table_model, row);
- ETreePath node = e_cell_tree_get_node (ecell_view->e_table_model, row);
- int offset = offset_of_node (ecell_view->e_table_model, row);
- gint result;
-
- switch (event->type) {
- case GDK_BUTTON_PRESS:
-
- if (event_in_expander (event, offset, 0)) {
- if (e_tree_model_node_is_expandable (tree_model, node)) {
- gboolean expanded = e_tree_table_adapter_node_is_expanded(etta, node);
- if (tree_view->retro_look)
- e_tree_table_adapter_node_set_expanded (etta, node, !expanded);
- else {
- gint tmp_row = row;
- GdkRectangle area;
- animate_closure_t *closure = g_new0 (animate_closure_t, 1);
- e_table_item_get_cell_geometry (tree_view->cell_view.e_table_item_view,
- &tmp_row, &view_col, &area.x, &area.y, NULL, &area.height);
- area.width = offset - 2;
- draw_expander (tree_view, GTK_LAYOUT (tree_view->canvas)->bin_window,
- expanded ? GTK_EXPANDER_SEMI_EXPANDED : GTK_EXPANDER_SEMI_COLLAPSED,
- GTK_STATE_NORMAL, &area);
- closure->ectv = tree_view;
- closure->etta = etta;
- closure->node = node;
- closure->expanded = expanded;
- closure->area = area;
- tree_view->animate_timeout = g_timeout_add (50, animate_expander, closure);
- }
- return TRUE;
- }
- }
- else if (event->button.x < (offset - INDENT_AMOUNT))
- return FALSE;
- break;
-
- case GDK_MOTION_NOTIFY:
-
- if (!tree_view->retro_look && e_tree_model_node_is_expandable (tree_model, node)) {
- gint height = ect_height (ecell_view, model_col, view_col, row);
- GdkRectangle area;
- gboolean in_expander = event_in_expander (event, offset, height);
-
- if (tree_view->prelit ^ in_expander) {
- gint tmp_row = row;
- e_table_item_get_cell_geometry (tree_view->cell_view.e_table_item_view,
- &tmp_row, &view_col, &area.x, &area.y, NULL, &area.height);
- area.width = offset - 2;
- draw_expander (tree_view, GTK_LAYOUT (tree_view->canvas)->bin_window,
- e_tree_table_adapter_node_is_expanded (etta, node) ? GTK_EXPANDER_EXPANDED : GTK_EXPANDER_COLLAPSED,
- in_expander ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL, &area);
- tree_view->prelit = in_expander;
- return TRUE;
- }
-
- }
- break;
-
- case GDK_LEAVE_NOTIFY:
-
- if (tree_view->prelit) {
- gint tmp_row = row;
- GdkRectangle area;
- e_table_item_get_cell_geometry (tree_view->cell_view.e_table_item_view,
- &tmp_row, &view_col, &area.x, &area.y, NULL, &area.height);
- area.width = offset - 2;
- draw_expander (tree_view, GTK_LAYOUT (tree_view->canvas)->bin_window,
- e_tree_table_adapter_node_is_expanded (etta, node) ? GTK_EXPANDER_EXPANDED : GTK_EXPANDER_COLLAPSED,
- GTK_STATE_NORMAL, &area);
- tree_view->prelit = FALSE;
- }
- return TRUE;
-
- default:
- break;
- }
-
- adjust_event_position (event, -offset);
- result = e_cell_event(tree_view->subcell_view, event, model_col, view_col, row, flags, actions);
- adjust_event_position (event, offset);
-
- return result;
-}
-
-/*
- * ECell::max_width method
- */
-static int
-ect_max_width (ECellView *ecell_view, int model_col, int view_col)
-{
- ECellTreeView *tree_view = (ECellTreeView *) ecell_view;
- int row;
- int number_of_rows;
- int max_width = 0;
- int width = 0;
- int subcell_max_width = 0;
- gboolean per_row = e_cell_max_width_by_row_implemented (tree_view->subcell_view);
-
- number_of_rows = e_table_model_row_count (ecell_view->e_table_model);
-
- if (!per_row)
- subcell_max_width = e_cell_max_width (tree_view->subcell_view, model_col, view_col);
-
- for (row = 0; row < number_of_rows; row++) {
- ETreeModel *tree_model = e_cell_tree_get_tree_model(ecell_view->e_table_model, row);
- ETreePath node;
- GdkPixbuf *node_image;
- int node_image_width = 0, node_image_height = 0;
-
- int offset, subcell_offset;
-#if 0
- gboolean expanded, expandable;
- ETreeTableAdapter *tree_table_adapter = e_cell_tree_get_tree_table_adapter(ecell_view->e_table_model, row);
-#endif
-
- node = e_cell_tree_get_node (ecell_view->e_table_model, row);
-
- offset = offset_of_node (ecell_view->e_table_model, row);
- subcell_offset = offset;
-
- node_image = e_tree_model_icon_at (tree_model, node);
-
- if (node_image) {
- node_image_width = gdk_pixbuf_get_width (node_image);
- node_image_height = gdk_pixbuf_get_height (node_image);
- }
-
- width = subcell_offset + node_image_width;
-
- if (per_row)
- width += e_cell_max_width_by_row (tree_view->subcell_view, model_col, view_col, row);
- else
- width += subcell_max_width;
-
-#if 0
- expandable = e_tree_model_node_is_expandable (tree_model, node);
- expanded = e_tree_table_adapter_node_is_expanded (tree_table_adapter, node);
-
- /* This is unnecessary since this is already handled
- by the offset_of_node function. If that changes,
- this will have to change too. */
-
- if (expandable) {
- GdkPixbuf *image;
-
- image = (expanded
- ? E_CELL_TREE(tree_view->cell_view.ecell)->open_pixbuf
- : E_CELL_TREE(tree_view->cell_view.ecell)->closed_pixbuf);
-
- width += gdk_pixbuf_get_width(image);
- }
-#endif
-
- max_width = MAX (max_width, width);
- }
-
- return max_width;
-}
-
-/*
- * ECellView::show_tooltip method
- */
-static void
-ect_show_tooltip (ECellView *ecell_view, int model_col, int view_col, int row,
- int col_width, ETableTooltip *tooltip)
-{
- ECellTreeView *tree_view = (ECellTreeView *) ecell_view;
- ETreeModel *tree_model = e_cell_tree_get_tree_model (ecell_view->e_table_model, row);
- ETreePath node = e_cell_tree_get_node (ecell_view->e_table_model, row);
- int offset = offset_of_node (ecell_view->e_table_model, row);
- GdkPixbuf *node_image;
-
- node_image = e_tree_model_icon_at (tree_model, node);
- if (node_image)
- offset += gdk_pixbuf_get_width (node_image);
-
- tooltip->x += offset;
- e_cell_show_tooltip (tree_view->subcell_view, model_col, view_col, row, col_width - offset, tooltip);
-}
-
-/*
- * ECellView::get_bg_color method
- */
-static char *
-ect_get_bg_color (ECellView *ecell_view, int row)
-{
- ECellTreeView *tree_view = (ECellTreeView *) ecell_view;
-
- return e_cell_get_bg_color (tree_view->subcell_view, row);
-}
-
-/*
- * ECellView::enter_edit method
- */
-static void *
-ect_enter_edit (ECellView *ecell_view, int model_col, int view_col, int row)
-{
- /* just defer to our subcell's view */
- ECellTreeView *tree_view = (ECellTreeView *) ecell_view;
-
- return e_cell_enter_edit (tree_view->subcell_view, model_col, view_col, row);
-}
-
-/*
- * ECellView::leave_edit method
- */
-static void
-ect_leave_edit (ECellView *ecell_view, int model_col, int view_col, int row, void *edit_context)
-{
- /* just defer to our subcell's view */
- ECellTreeView *tree_view = (ECellTreeView *) ecell_view;
-
- e_cell_leave_edit (tree_view->subcell_view, model_col, view_col, row, edit_context);
-}
-
-static void
-ect_print (ECellView *ecell_view, GnomePrintContext *context,
- int model_col, int view_col, int row,
- double width, double height)
-{
- ECellTreeView *tree_view = (ECellTreeView *) ecell_view;
-
- if (/* XXX only if we're the active sort */ TRUE) {
- ETreeModel *tree_model = e_cell_tree_get_tree_model (ecell_view->e_table_model, row);
- ETreeTableAdapter *tree_table_adapter = e_cell_tree_get_tree_table_adapter(ecell_view->e_table_model, row);
- ETreePath node = e_cell_tree_get_node (ecell_view->e_table_model, row);
- int offset = offset_of_node (ecell_view->e_table_model, row);
- int subcell_offset = offset;
- gboolean expandable = e_tree_model_node_is_expandable (tree_model, node);
- gboolean expanded = e_tree_table_adapter_node_is_expanded (tree_table_adapter, node);
-
- /* draw our lines */
- if (E_CELL_TREE(tree_view->cell_view.ecell)->draw_lines) {
- int depth;
-
- if (!e_tree_model_node_is_root (tree_model, node)
- || e_tree_model_node_get_children (tree_model, node, NULL) > 0) {
- gnome_print_moveto (context,
- offset - INDENT_AMOUNT / 2,
- height / 2);
-
- gnome_print_lineto (context,
- offset,
- height / 2);
- }
-
- if (visible_depth_of_node (ecell_view->e_table_model, row) != 0) {
- gnome_print_moveto (context,
- offset - INDENT_AMOUNT / 2,
- height);
- gnome_print_lineto (context,
- offset - INDENT_AMOUNT / 2,
- (e_tree_table_adapter_node_get_next (tree_table_adapter, node)
- ? 0
- : height / 2));
- }
-
- /* now traverse back up to the root of the tree, checking at
- each level if the node has siblings, and drawing the
- correct vertical pipe for it's configuration. */
- node = e_tree_model_node_get_parent (tree_model, node);
- depth = visible_depth_of_node (ecell_view->e_table_model, row) - 1;
- offset -= INDENT_AMOUNT;
- while (node && depth != 0) {
- if (e_tree_table_adapter_node_get_next(tree_table_adapter, node)) {
- gnome_print_moveto (context,
- offset - INDENT_AMOUNT / 2,
- height);
- gnome_print_lineto (context,
- offset - INDENT_AMOUNT / 2,
- 0);
- }
- node = e_tree_model_node_get_parent (tree_model, node);
- depth --;
- offset -= INDENT_AMOUNT;
- }
- }
-
- /* now draw our icon if we're expandable */
- if (expandable) {
- double image_matrix [6] = {16, 0, 0, 16, 0, 0};
- GdkPixbuf *image = (expanded
- ? E_CELL_TREE(tree_view->cell_view.ecell)->open_pixbuf
- : E_CELL_TREE(tree_view->cell_view.ecell)->closed_pixbuf);
- int image_width, image_height, image_rowstride;
- guchar *image_pixels;
-
- image_width = gdk_pixbuf_get_width(image);
- image_height = gdk_pixbuf_get_height(image);
- image_pixels = gdk_pixbuf_get_pixels(image);
- image_rowstride = gdk_pixbuf_get_rowstride(image);
-
- image_matrix [4] = subcell_offset - INDENT_AMOUNT / 2 - image_width / 2;
- image_matrix [5] = height / 2 - image_height / 2;
-
- gnome_print_gsave (context);
- gnome_print_concat (context, image_matrix);
-
- gnome_print_rgbaimage (context, image_pixels, image_width, image_height, image_rowstride);
- gnome_print_grestore (context);
- }
-
- gnome_print_stroke (context);
-
- if (gnome_print_translate(context, subcell_offset, 0) == -1)
- /* FIXME */;
- width -= subcell_offset;
- }
-
-
- e_cell_print (tree_view->subcell_view, context, model_col, view_col, row, width, height);
-}
-
-static gdouble
-ect_print_height (ECellView *ecell_view, GnomePrintContext *context,
- int model_col, int view_col, int row,
- double width)
-{
- return 12; /* XXX */
-}
-
-/*
- * GObject::dispose method
- */
-static void
-ect_dispose (GObject *object)
-{
- ECellTree *ect = E_CELL_TREE (object);
-
- /* destroy our subcell */
- if (ect->subcell)
- g_object_unref (ect->subcell);
- ect->subcell = NULL;
-
- if (ect->open_pixbuf)
- gdk_pixbuf_unref (ect->open_pixbuf);
- ect->open_pixbuf = NULL;
-
- if (ect->closed_pixbuf)
- gdk_pixbuf_unref (ect->closed_pixbuf);
- ect->closed_pixbuf = NULL;
-
- G_OBJECT_CLASS (parent_class)->dispose (object);
-}
-
-static void
-e_cell_tree_class_init (GObjectClass *object_class)
-{
- ECellClass *ecc = (ECellClass *) object_class;
-
- object_class->dispose = ect_dispose;
-
- ecc->new_view = ect_new_view;
- ecc->kill_view = ect_kill_view;
- ecc->realize = ect_realize;
- ecc->unrealize = ect_unrealize;
- ecc->draw = ect_draw;
- ecc->event = ect_event;
- ecc->height = ect_height;
- ecc->enter_edit = ect_enter_edit;
- ecc->leave_edit = ect_leave_edit;
- ecc->print = ect_print;
- ecc->print_height = ect_print_height;
- ecc->max_width = ect_max_width;
- ecc->show_tooltip = ect_show_tooltip;
- ecc->get_bg_color = ect_get_bg_color;
-
- parent_class = g_type_class_ref (PARENT_TYPE);
-
- gal_a11y_e_cell_registry_add_cell_type (NULL, E_CELL_TREE_TYPE, gal_a11y_e_cell_tree_new);
-}
-
-E_MAKE_TYPE(e_cell_tree, "ECellTree", ECellTree, e_cell_tree_class_init, NULL, PARENT_TYPE)
-
-/**
- * e_cell_tree_construct:
- * @ect: the ECellTree we're constructing.
- * @open_pixbuf: pixbuf to be used instead of the '-' icon.
- * @closed_pixbuf: pixbuf to be used instead of the '+' icon.
- * @draw_lines: whether or not to draw the lines between parents/children/siblings.
- * @subcell: the ECell to render to the right of the tree effects.
- *
- * Constructs an ECellTree. used by subclasses that need to
- * initialize a nested ECellTree. See e_cell_tree_new() for more info.
- *
- **/
-void
-e_cell_tree_construct (ECellTree *ect,
- GdkPixbuf *open_pixbuf,
- GdkPixbuf *closed_pixbuf,
- gboolean draw_lines,
- ECell *subcell)
-{
- ect->subcell = subcell;
- if (subcell) {
- g_object_ref (subcell);
- gtk_object_sink (GTK_OBJECT (subcell));
- }
- if (open_pixbuf)
- ect->open_pixbuf = open_pixbuf;
- else
- ect->open_pixbuf = gdk_pixbuf_new_from_xpm_data ((const char **)tree_expanded_xpm);
- if (closed_pixbuf)
- ect->closed_pixbuf = closed_pixbuf;
- else
- ect->closed_pixbuf = gdk_pixbuf_new_from_xpm_data ((const char **)tree_unexpanded_xpm);
-
- ect->draw_lines = draw_lines;
-}
-
-
-/**
- * e_cell_tree_new:
- * @open_pixbuf: pixbuf to be used instead of the '-' icon.
- * @closed_pixbuf: pixbuf to be used instead of the '+' icon.
- * @draw_lines: whether or not to draw the lines between parents/children/siblings.
- * @subcell: the ECell to render to the right of the tree effects.
- *
- * Creates a new ECell renderer that can be used to render tree
- * effects that come from an ETreeModel. Various assumptions are made
- * as to the fact that the ETableModel the ETable this cell is
- * associated with is in fact an ETreeModel. The cell uses special
- * columns to get at structural information (needed to draw the
- * lines/icons.
- *
- * Return value: an ECell object that can be used to render trees.
- **/
-ECell *
-e_cell_tree_new (GdkPixbuf *open_pixbuf,
- GdkPixbuf *closed_pixbuf,
- gboolean draw_lines,
- ECell *subcell)
-{
- ECellTree *ect = g_object_new (E_CELL_TREE_TYPE, NULL);
-
- e_cell_tree_construct (ect, open_pixbuf, closed_pixbuf, draw_lines, subcell);
-
- return (ECell *) ect;
-}
-
diff --git a/widgets/table/e-cell-tree.h b/widgets/table/e-cell-tree.h
deleted file mode 100644
index dfdd6f0191..0000000000
--- a/widgets/table/e-cell-tree.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-cell-tree.h - Tree cell object.
- * Copyright 1999, 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Toshok <toshok@ximian.com>
- *
- * A majority of code taken from:
- *
- * the ECellText renderer.
- * Copyright 1998, The Free Software Foundation
- * Copyright 1999, 2000, Ximian, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_CELL_TREE_H_
-#define _E_CELL_TREE_H_
-
-#include <libgnomecanvas/gnome-canvas.h>
-#include <gal/e-table/e-cell.h>
-
-G_BEGIN_DECLS
-
-#define E_CELL_TREE_TYPE (e_cell_tree_get_type ())
-#define E_CELL_TREE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_CELL_TREE_TYPE, ECellTree))
-#define E_CELL_TREE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_CELL_TREE_TYPE, ECellTreeClass))
-#define E_IS_CELL_TREE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_CELL_TREE_TYPE))
-#define E_IS_CELL_TREE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_CELL_TREE_TYPE))
-
-
-typedef struct {
- ECell parent;
-
- gboolean draw_lines;
-
- GdkPixbuf *open_pixbuf;
- GdkPixbuf *closed_pixbuf;
-
- ECell *subcell;
-} ECellTree;
-
-typedef struct {
- ECellClass parent_class;
-} ECellTreeClass;
-
-GType e_cell_tree_get_type (void);
-ECell *e_cell_tree_new (GdkPixbuf *open_pixbuf,
- GdkPixbuf *closed_pixbuf,
- gboolean draw_lines,
- ECell *subcell);
-void e_cell_tree_construct (ECellTree *ect,
- GdkPixbuf *open_pixbuf,
- GdkPixbuf *closed_pixbuf,
- gboolean draw_lines,
- ECell *subcell);
-
-ECellView *e_cell_tree_view_get_subcell_view (ECellView *ect);
-
-G_END_DECLS
-
-#endif /* _E_CELL_TREE_H_ */
-
-
diff --git a/widgets/table/e-cell-vbox.c b/widgets/table/e-cell-vbox.c
deleted file mode 100644
index ee18694742..0000000000
--- a/widgets/table/e-cell-vbox.c
+++ /dev/null
@@ -1,486 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-cell-vbox.c - Vbox cell object.
- * Copyright 1999, 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Toshok <toshok@ximian.com>
- * Chris Lahey <clahey@ximian.com>
- *
- * A majority of code taken from:
- *
- * the ECellText renderer.
- * Copyright 1999, 2000, Ximian, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-
-#include <ctype.h>
-#include <math.h>
-#include <stdio.h>
-
-#include <gdk/gdkx.h> /* for BlackPixel */
-#include <gtk/gtkenums.h>
-#include <gtk/gtkentry.h>
-#include <gtk/gtkwindow.h>
-#include <gtk/gtkinvisible.h>
-#include <gtk/gtksignal.h>
-#include <gdk/gdkkeysyms.h>
-
-#include "gal/util/e-util.h"
-#include "gal/a11y/e-table/gal-a11y-e-cell-registry.h"
-#include "gal/a11y/e-table/gal-a11y-e-cell-vbox.h"
-#include "e-table-item.h"
-#include "e-cell-vbox.h"
-
-#define PARENT_TYPE e_cell_get_type ()
-
-static ECellClass *parent_class;
-
-#define INDENT_AMOUNT 16
-
-/*
- * ECell::new_view method
- */
-static ECellView *
-ecv_new_view (ECell *ecell, ETableModel *table_model, void *e_table_item_view)
-{
- ECellVbox *ecv = E_CELL_VBOX (ecell);
- ECellVboxView *vbox_view = g_new0 (ECellVboxView, 1);
- int i;
-
- vbox_view->cell_view.ecell = ecell;
- vbox_view->cell_view.e_table_model = table_model;
- vbox_view->cell_view.e_table_item_view = e_table_item_view;
-
- /* create our subcell view */
- vbox_view->subcell_view_count = ecv->subcell_count;
- vbox_view->subcell_views = g_new (ECellView *, vbox_view->subcell_view_count);
- vbox_view->model_cols = g_new (int, vbox_view->subcell_view_count);
-
- for (i = 0; i < vbox_view->subcell_view_count; i++) {
- vbox_view->subcell_views[i] = e_cell_new_view (ecv->subcells[i], table_model, e_table_item_view /* XXX */);
- vbox_view->model_cols[i] = ecv->model_cols[i];
- }
-
- return (ECellView *)vbox_view;
-}
-
-/*
- * ECell::kill_view method
- */
-static void
-ecv_kill_view (ECellView *ecv)
-{
- ECellVboxView *vbox_view = (ECellVboxView *) ecv;
- int i;
-
- /* kill our subcell view */
- for (i = 0; i < vbox_view->subcell_view_count; i++)
- e_cell_kill_view (vbox_view->subcell_views[i]);
-
- g_free (vbox_view->model_cols);
- g_free (vbox_view->subcell_views);
- g_free (vbox_view);
-}
-
-/*
- * ECell::realize method
- */
-static void
-ecv_realize (ECellView *ecell_view)
-{
- ECellVboxView *vbox_view = (ECellVboxView *) ecell_view;
- int i;
-
- /* realize our subcell view */
- for (i = 0; i < vbox_view->subcell_view_count; i++)
- e_cell_realize (vbox_view->subcell_views[i]);
-
- if (parent_class->realize)
- (* parent_class->realize) (ecell_view);
-}
-
-/*
- * ECell::unrealize method
- */
-static void
-ecv_unrealize (ECellView *ecv)
-{
- ECellVboxView *vbox_view = (ECellVboxView *) ecv;
- int i;
-
- /* unrealize our subcell view. */
- for (i = 0; i < vbox_view->subcell_view_count; i++)
- e_cell_unrealize (vbox_view->subcell_views[i]);
-
- if (parent_class->unrealize)
- (* parent_class->unrealize) (ecv);
-}
-
-/*
- * ECell::draw method
- */
-static void
-ecv_draw (ECellView *ecell_view, GdkDrawable *drawable,
- int model_col, int view_col, int row, ECellFlags flags,
- int x1, int y1, int x2, int y2)
-{
- ECellVboxView *vbox_view = (ECellVboxView *)ecell_view;
-
- int subcell_offset = 0;
- int i;
-
- for (i = 0; i < vbox_view->subcell_view_count; i++) {
- /* Now cause our subcells to draw their contents,
- shifted by subcell_offset pixels */
- int height = e_cell_height (vbox_view->subcell_views[i], vbox_view->model_cols[i], view_col, row);
- e_cell_draw (vbox_view->subcell_views[i], drawable,
- vbox_view->model_cols[i], view_col, row, flags,
- x1, y1 + subcell_offset, x2, y1 + subcell_offset + height);
-
- subcell_offset += e_cell_height (vbox_view->subcell_views[i], vbox_view->model_cols[i], view_col, row);
- }
-}
-
-/*
- * ECell::event method
- */
-static gint
-ecv_event (ECellView *ecell_view, GdkEvent *event, int model_col, int view_col, int row, ECellFlags flags, ECellActions *actions)
-{
- ECellVboxView *vbox_view = (ECellVboxView *)ecell_view;
- int y = 0;
- int i;
- int subcell_offset = 0;
-
- switch (event->type) {
- case GDK_BUTTON_PRESS:
- case GDK_BUTTON_RELEASE:
- case GDK_2BUTTON_PRESS:
- case GDK_3BUTTON_PRESS:
- y = event->button.y;
- break;
- case GDK_MOTION_NOTIFY:
- y = event->motion.y;
- break;
- default:
- /* nada */
- break;
- }
-
-
- for (i = 0; i < vbox_view->subcell_view_count; i++) {
- int height = e_cell_height (vbox_view->subcell_views[i], vbox_view->model_cols[i], view_col, row);
- if (y < subcell_offset + height)
- return e_cell_event(vbox_view->subcell_views[i], event, vbox_view->model_cols[i], view_col, row, flags, actions);
- subcell_offset += height;
- }
- return 0;
-}
-
-/*
- * ECell::height method
- */
-static int
-ecv_height (ECellView *ecell_view, int model_col, int view_col, int row)
-{
- ECellVboxView *vbox_view = (ECellVboxView *)ecell_view;
- int height = 0;
- int i;
-
- for (i = 0; i < vbox_view->subcell_view_count; i++) {
- height += e_cell_height (vbox_view->subcell_views[i], vbox_view->model_cols[i], view_col, row);
- }
- return height;
-}
-
-/*
- * ECell::max_width method
- */
-static int
-ecv_max_width (ECellView *ecell_view, int model_col, int view_col)
-{
- ECellVboxView *vbox_view = (ECellVboxView *)ecell_view;
- int max_width = 0;
- int i;
-
- for (i = 0; i < vbox_view->subcell_view_count; i++) {
- int width = e_cell_max_width (vbox_view->subcell_views[i], vbox_view->model_cols[i], view_col);
- max_width = MAX(width, max_width);
- }
-
- return max_width;
-}
-
-#if 0
-/*
- * ECellView::show_tooltip method
- */
-static void
-ecv_show_tooltip (ECellView *ecell_view, int model_col, int view_col, int row,
- int col_width, ETableTooltip *tooltip)
-{
- ECellVboxView *vbox_view = (ECellVboxView *) ecell_view;
- EVboxModel *vbox_model = e_cell_vbox_get_vbox_model (ecell_view->e_table_model, row);
- EVboxPath node = e_cell_vbox_get_node (ecell_view->e_table_model, row);
- int offset = offset_of_node (ecell_view->e_table_model, row);
- GdkPixbuf *node_image;
-
- node_image = e_vbox_model_icon_at (vbox_model, node);
- if (node_image)
- offset += gdk_pixbuf_get_width (node_image);
-
- tooltip->x += offset;
- e_cell_show_tooltip (vbox_view->subcell_view, model_col, view_col, row, col_width - offset, tooltip);
-}
-
-/*
- * ECellView::get_bg_color method
- */
-static char *
-ecv_get_bg_color (ECellView *ecell_view, int row)
-{
- ECellVboxView *vbox_view = (ECellVboxView *) ecell_view;
-
- return e_cell_get_bg_color (vbox_view->subcell_views[0], row);
-}
-
-/*
- * ECellView::enter_edit method
- */
-static void *
-ecv_enter_edit (ECellView *ecell_view, int model_col, int view_col, int row)
-{
- /* just defer to our subcell's view */
- ECellVboxView *vbox_view = (ECellVboxView *) ecell_view;
-
- return e_cell_enter_edit (vbox_view->subcell_view, model_col, view_col, row);
-}
-
-/*
- * ECellView::leave_edit method
- */
-static void
-ecv_leave_edit (ECellView *ecell_view, int model_col, int view_col, int row, void *edit_context)
-{
- /* just defer to our subcell's view */
- ECellVboxView *vbox_view = (ECellVboxView *) ecell_view;
-
- e_cell_leave_edit (vbox_view->subcell_view, model_col, view_col, row, edit_context);
-}
-
-static void
-ecv_print (ECellView *ecell_view, GnomePrintContext *context,
- int model_col, int view_col, int row,
- double width, double height)
-{
- ECellVboxView *vbox_view = (ECellVboxView *) ecell_view;
-
- if (/* XXX only if we're the active sort */ TRUE) {
- EVboxModel *vbox_model = e_cell_vbox_get_vbox_model (ecell_view->e_table_model, row);
- EVboxTableAdapter *vbox_table_adapter = e_cell_vbox_get_vbox_table_adapter(ecell_view->e_table_model, row);
- EVboxPath node = e_cell_vbox_get_node (ecell_view->e_table_model, row);
- int offset = offset_of_node (ecell_view->e_table_model, row);
- int subcell_offset = offset;
- gboolean expandable = e_vbox_model_node_is_expandable (vbox_model, node);
- gboolean expanded = e_vbox_table_adapter_node_is_expanded (vbox_table_adapter, node);
-
- /* draw our lines */
- if (E_CELL_VBOX(vbox_view->cell_view.ecell)->draw_lines) {
- int depth;
-
- if (!e_vbox_model_node_is_root (vbox_model, node)
- || e_vbox_model_node_get_children (vbox_model, node, NULL) > 0) {
- gnome_print_moveto (context,
- offset - INDENT_AMOUNT / 2,
- height / 2);
-
- gnome_print_lineto (context,
- offset,
- height / 2);
- }
-
- if (visible_depth_of_node (ecell_view->e_table_model, row) != 0) {
- gnome_print_moveto (context,
- offset - INDENT_AMOUNT / 2,
- height);
- gnome_print_lineto (context,
- offset - INDENT_AMOUNT / 2,
- (e_vbox_model_node_get_next (vbox_model, node)
- ? 0
- : height / 2));
- }
-
- /* now traverse back up to the root of the vbox, checking at
- each level if the node has siblings, and drawing the
- correct vertical pipe for it's configuration. */
- node = e_vbox_model_node_get_parent (vbox_model, node);
- depth = visible_depth_of_node (ecell_view->e_table_model, row) - 1;
- offset -= INDENT_AMOUNT;
- while (node && depth != 0) {
- if (e_vbox_model_node_get_next(vbox_model, node)) {
- gnome_print_moveto (context,
- offset - INDENT_AMOUNT / 2,
- height);
- gnome_print_lineto (context,
- offset - INDENT_AMOUNT / 2,
- 0);
- }
- node = e_vbox_model_node_get_parent (vbox_model, node);
- depth --;
- offset -= INDENT_AMOUNT;
- }
- }
-
- /* now draw our icon if we're expandable */
- if (expandable) {
- double image_matrix [6] = {16, 0, 0, 16, 0, 0};
- GdkPixbuf *image = (expanded
- ? E_CELL_VBOX(vbox_view->cell_view.ecell)->open_pixbuf
- : E_CELL_VBOX(vbox_view->cell_view.ecell)->closed_pixbuf);
- int image_width, image_height, image_rowstride;
- guchar *image_pixels;
-
- image_width = gdk_pixbuf_get_width(image);
- image_height = gdk_pixbuf_get_height(image);
- image_pixels = gdk_pixbuf_get_pixels(image);
- image_rowstride = gdk_pixbuf_get_rowstride(image);
-
- image_matrix [4] = subcell_offset - INDENT_AMOUNT / 2 - image_width / 2;
- image_matrix [5] = height / 2 - image_height / 2;
-
- gnome_print_gsave (context);
- gnome_print_concat (context, image_matrix);
-
- gnome_print_rgbaimage (context, image_pixels, image_width, image_height, image_rowstride);
- gnome_print_grestore (context);
- }
-
- gnome_print_stroke (context);
-
- if (gnome_print_translate(context, subcell_offset, 0) == -1)
- /* FIXME */;
- width -= subcell_offset;
- }
-
-
- e_cell_print (vbox_view->subcell_view, context, model_col, view_col, row, width, height);
-}
-
-static gdouble
-ecv_print_height (ECellView *ecell_view, GnomePrintContext *context,
- int model_col, int view_col, int row,
- double width)
-{
- return 12; /* XXX */
-}
-#endif
-
-/*
- * GObject::dispose method
- */
-static void
-ecv_dispose (GObject *object)
-{
- ECellVbox *ecv = E_CELL_VBOX (object);
- int i;
-
- /* destroy our subcell */
- for (i = 0; i < ecv->subcell_count; i++)
- if (ecv->subcells[i])
- g_object_unref (ecv->subcells[i]);
- g_free (ecv->subcells);
- ecv->subcells = NULL;
- ecv->subcell_count = 0;
-
- G_OBJECT_CLASS (parent_class)->dispose (object);
-}
-
-static void
-e_cell_vbox_class_init (GObjectClass *object_class)
-{
- ECellClass *ecc = (ECellClass *) object_class;
-
- object_class->dispose = ecv_dispose;
-
- ecc->new_view = ecv_new_view;
- ecc->kill_view = ecv_kill_view;
- ecc->realize = ecv_realize;
- ecc->unrealize = ecv_unrealize;
- ecc->draw = ecv_draw;
- ecc->event = ecv_event;
- ecc->height = ecv_height;
-#if 0
- ecc->enter_edit = ecv_enter_edit;
- ecc->leave_edit = ecv_leave_edit;
- ecc->print = ecv_print;
- ecc->print_height = ecv_print_height;
-#endif
- ecc->max_width = ecv_max_width;
-#if 0
- ecc->show_tooltip = ecv_show_tooltip;
- ecc->get_bg_color = ecv_get_bg_color;
-#endif
-
- parent_class = g_type_class_ref (PARENT_TYPE);
-
- gal_a11y_e_cell_registry_add_cell_type (NULL, E_CELL_VBOX_TYPE, gal_a11y_e_cell_vbox_new);
-}
-
-static void
-e_cell_vbox_init (GtkObject *object)
-{
- ECellVbox *ecv = E_CELL_VBOX (object);
-
- ecv->subcells = NULL;
- ecv->subcell_count = 0;
-}
-
-E_MAKE_TYPE(e_cell_vbox, "ECellVbox", ECellVbox, e_cell_vbox_class_init, e_cell_vbox_init, PARENT_TYPE);
-
-/**
- * e_cell_vbox_new:
- *
- * Creates a new ECell renderer that can be used to render multiple
- * child cells.
- *
- * Return value: an ECell object that can be used to render multiple
- * child cells.
- **/
-ECell *
-e_cell_vbox_new (void)
-{
- ECellVbox *ecv = g_object_new (E_CELL_VBOX_TYPE, NULL);
-
- return (ECell *) ecv;
-}
-
-void
-e_cell_vbox_append (ECellVbox *vbox, ECell *subcell, int model_col)
-{
- vbox->subcell_count ++;
-
- vbox->subcells = g_renew (ECell *, vbox->subcells, vbox->subcell_count);
- vbox->model_cols = g_renew (int, vbox->model_cols, vbox->subcell_count);
-
- vbox->subcells[vbox->subcell_count - 1] = subcell;
- vbox->model_cols[vbox->subcell_count - 1] = model_col;
-
- if (subcell)
- g_object_ref (subcell);
-}
diff --git a/widgets/table/e-cell-vbox.h b/widgets/table/e-cell-vbox.h
deleted file mode 100644
index f08e106128..0000000000
--- a/widgets/table/e-cell-vbox.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-cell-vbox.h - Vbox cell object.
- * Copyright 1999 - 2002, Ximian, Inc.
- *
- * Authors:
- * Chris Toshok <toshok@ximian.com>
- * Chris Lahey <clahey@ximina.com
- *
- * A majority of code taken from:
- *
- * the ECellText renderer.
- * Copyright 1999, 2000, Ximian, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_CELL_VBOX_H_
-#define _E_CELL_VBOX_H_
-
-#include <libgnomecanvas/gnome-canvas.h>
-#include <gal/e-table/e-cell.h>
-
-G_BEGIN_DECLS
-
-#define E_CELL_VBOX_TYPE (e_cell_vbox_get_type ())
-#define E_CELL_VBOX(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_CELL_VBOX_TYPE, ECellVbox))
-#define E_CELL_VBOX_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_CELL_VBOX_TYPE, ECellVboxClass))
-#define E_IS_CELL_VBOX(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_CELL_VBOX_TYPE))
-#define E_IS_CELL_VBOX_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_CELL_VBOX_TYPE))
-
-typedef struct {
- ECell parent;
-
- int subcell_count;
- ECell **subcells;
- int *model_cols;
-} ECellVbox;
-
-typedef struct {
- ECellView cell_view;
- int subcell_view_count;
- ECellView **subcell_views;
- int *model_cols;
-} ECellVboxView;
-
-typedef struct {
- ECellClass parent_class;
-} ECellVboxClass;
-
-GType e_cell_vbox_get_type (void);
-ECell *e_cell_vbox_new (void);
-void e_cell_vbox_append (ECellVbox *vbox,
- ECell *subcell,
- int model_col);
-
-
-G_END_DECLS
-
-#endif /* _E_CELL_VBOX_H_ */
diff --git a/widgets/table/e-cell.c b/widgets/table/e-cell.c
deleted file mode 100644
index 8deeaa654c..0000000000
--- a/widgets/table/e-cell.c
+++ /dev/null
@@ -1,499 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-cell.c - base class for cell renderers in e-table
- * Copyright 1999, 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Miguel de Icaza <miguel@ximian.com>
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include "e-cell.h"
-#include "gal/util/e-util.h"
-
-#define PARENT_TYPE GTK_TYPE_OBJECT
-
-#define ECVIEW_EC_CLASS(v) (E_CELL_GET_CLASS (v->ecell))
-
-static ECellView *
-ec_new_view (ECell *ecell, ETableModel *table_model, void *e_table_item_view)
-{
- return NULL;
-}
-
-static void
-ec_realize (ECellView *e_cell)
-{
-}
-
-static void
-ec_kill_view (ECellView *ecell_view)
-{
-}
-
-static void
-ec_unrealize (ECellView *e_cell)
-{
-}
-
-static void
-ec_draw (ECellView *ecell_view, GdkDrawable *drawable,
- int model_col, int view_col, int row, ECellFlags flags,
- int x1, int y1, int x2, int y2)
-{
- g_error ("e-cell-draw invoked\n");
-}
-
-static gint
-ec_event (ECellView *ecell_view, GdkEvent *event, int model_col, int view_col, int row, ECellFlags flags, ECellActions *actions)
-{
- g_error ("e-cell-event invoked\n");
- return 0;
-}
-
-static gint
-ec_height (ECellView *ecell_view, int model_col, int view_col, int row)
-{
- g_error ("e-cell-height invoked\n");
- return 0;
-}
-
-static void
-ec_focus (ECellView *ecell_view, int model_col, int view_col, int row, int x1, int y1, int x2, int y2)
-{
- ecell_view->focus_col = view_col;
- ecell_view->focus_row = row;
- ecell_view->focus_x1 = x1;
- ecell_view->focus_y1 = y1;
- ecell_view->focus_x2 = x2;
- ecell_view->focus_y2 = y2;
-}
-
-static void
-ec_unfocus (ECellView *ecell_view)
-{
- ecell_view->focus_col = -1;
- ecell_view->focus_row = -1;
- ecell_view->focus_x1 = -1;
- ecell_view->focus_y1 = -1;
- ecell_view->focus_x2 = -1;
- ecell_view->focus_y2 = -1;
-}
-
-static void *
-ec_enter_edit (ECellView *ecell_view, int model_col, int view_col, int row)
-{
- return NULL;
-}
-
-static void
-ec_leave_edit (ECellView *ecell_view, int model_col, int view_col, int row, void *context)
-{
-}
-
-static void *
-ec_save_state (ECellView *ecell_view, int model_col, int view_col, int row, void *context)
-{
- return NULL;
-}
-
-static void
-ec_load_state (ECellView *ecell_view, int model_col, int view_col, int row, void *context, void *save_state)
-{
-}
-
-static void
-ec_free_state (ECellView *ecell_view, int model_col, int view_col, int row, void *save_state)
-{
-}
-
-static void
-ec_show_tooltip (ECellView *ecell_view, int model_col, int view_col, int row, int col_width, ETableTooltip *tooltip)
-{
- /* Do nothing */
-}
-
-static void
-e_cell_class_init (GtkObjectClass *object_class)
-{
- ECellClass *ecc = (ECellClass *) object_class;
-
- ecc->realize = ec_realize;
- ecc->unrealize = ec_unrealize;
- ecc->new_view = ec_new_view;
- ecc->kill_view = ec_kill_view;
- ecc->draw = ec_draw;
- ecc->event = ec_event;
- ecc->focus = ec_focus;
- ecc->unfocus = ec_unfocus;
- ecc->height = ec_height;
- ecc->enter_edit = ec_enter_edit;
- ecc->leave_edit = ec_leave_edit;
- ecc->save_state = ec_save_state;
- ecc->load_state = ec_load_state;
- ecc->free_state = ec_free_state;
- ecc->print = NULL;
- ecc->print_height = NULL;
- ecc->max_width = NULL;
- ecc->max_width_by_row = NULL;
- ecc->show_tooltip = ec_show_tooltip;
-}
-
-static void
-e_cell_init (GtkObject *object)
-{
-}
-
-E_MAKE_TYPE(e_cell, "ECell", ECell, e_cell_class_init, e_cell_init, PARENT_TYPE)
-
-/**
- * e_cell_event:
- * @ecell_view: The ECellView where the event will be dispatched
- * @event: The GdkEvent.
- * @model_col: the column in the model
- * @view_col: the column in the view
- * @row: the row
- * @flags: flags about the current state
- * @actions: A second return value in case the cell wants to take some action (specifically grabbing & ungrabbing)
- *
- * Dispatches the event @event to the @ecell_view for.
- *
- * Returns: processing state from the GdkEvent handling.
- */
-gint
-e_cell_event (ECellView *ecell_view, GdkEvent *event, int model_col, int view_col, int row, ECellFlags flags, ECellActions *actions)
-{
- return ECVIEW_EC_CLASS(ecell_view)->event (
- ecell_view, event, model_col, view_col, row, flags, actions);
-}
-
-/**
- * e_cell_new_view:
- * @ecell: the Ecell that will create the new view
- * @table_model: the table model the ecell is bound to
- * @e_table_item_view: An ETableItem object (the CanvasItem that reprensents the view of the table)
- *
- * ECell renderers new to be bound to a table_model and to the actual view
- * during their life time to actually render the data. This method is invoked
- * by the ETableItem canvas item to instatiate a new view of the ECell.
- *
- * This is invoked when the ETableModel is attached to the ETableItem (a CanvasItem
- * that can render ETableModels in the screen).
- *
- * Returns: a new ECellView for this @ecell on the @table_model displayed on the @e_table_item_view.
- */
-ECellView *
-e_cell_new_view (ECell *ecell, ETableModel *table_model, void *e_table_item_view)
-{
- return E_CELL_GET_CLASS (ecell)->new_view (
- ecell, table_model, e_table_item_view);
-}
-
-/**
- * e_cell_realize:
- * @ecell_view: The ECellView to be realized.
- *
- * This function is invoked to give a chance to the ECellView to allocate
- * any resources it needs from Gdk, equivalent to the GtkWidget::realize
- * signal.
- */
-void
-e_cell_realize (ECellView *ecell_view)
-{
- ECVIEW_EC_CLASS(ecell_view)->realize (ecell_view);
-}
-
-/**
- * e_cell_kill_view:
- * @ecell_view: view to be destroyed.
- *
- * This method it used to destroy a view of an ECell renderer
- */
-void
-e_cell_kill_view (ECellView *ecell_view)
-{
- ECVIEW_EC_CLASS(ecell_view)->kill_view (ecell_view);
-}
-
-/**
- * e_cell_unrealize:
- * @ecell_view: The ECellView to be unrealized.
- *
- * This function is invoked to give a chance to the ECellView to
- * release any resources it allocated during the realize method,
- * equivalent to the GtkWidget::unrealize signal.
- */
-void
-e_cell_unrealize (ECellView *ecell_view)
-{
- ECVIEW_EC_CLASS(ecell_view)->unrealize (ecell_view);
-}
-
-/**
- * e_cell_draw:
- * @ecell_view: the ECellView to redraw
- * @drawable: draw desination
- * @model_col: the column in the model being drawn.
- * @view_col: the column in the view being drawn (what the model maps to).
- * @row: the row being drawn
- * @flags: rendering flags.
- * @x1: boudary for the rendering
- * @y1: boudary for the rendering
- * @x2: boudary for the rendering
- * @y2: boudary for the rendering
- *
- * This instructs the ECellView to render itself into the drawable. The
- * region to be drawn in given by (x1,y1)-(x2,y2).
- *
- * The most important flags are %E_CELL_SELECTED and %E_CELL_FOCUSED, other
- * flags include alignments and justifications.
- */
-void
-e_cell_draw (ECellView *ecell_view, GdkDrawable *drawable,
- int model_col, int view_col, int row, ECellFlags flags,
- int x1, int y1, int x2, int y2)
-{
- g_return_if_fail (ecell_view != NULL);
- g_return_if_fail (row >= 0);
- g_return_if_fail (row < e_table_model_row_count(ecell_view->e_table_model));
-
- ECVIEW_EC_CLASS(ecell_view)->draw (ecell_view, drawable, model_col, view_col, row, flags, x1, y1, x2, y2);
-}
-
-/**
- * e_cell_print:
- * @ecell_view: the ECellView to redraw
- * @context: The GnomePrintContext where we output our printed data.
- * @model_col: the column in the model being drawn.
- * @view_col: the column in the view being drawn (what the model maps to).
- * @row: the row being drawn
- * @width: width
- * @height: height
- *
- * FIXME:
- */
-void
-e_cell_print (ECellView *ecell_view, GnomePrintContext *context,
- int model_col, int view_col, int row,
- double width, double height)
-{
- if (ECVIEW_EC_CLASS(ecell_view)->print)
- ECVIEW_EC_CLASS(ecell_view)->print (ecell_view, context, model_col, view_col, row, width, height);
-}
-
-/**
- * e_cell_print:
- *
- * FIXME:
- */
-gdouble
-e_cell_print_height (ECellView *ecell_view, GnomePrintContext *context,
- int model_col, int view_col, int row,
- double width)
-{
- if (ECVIEW_EC_CLASS(ecell_view)->print_height)
- return ECVIEW_EC_CLASS(ecell_view)->print_height
- (ecell_view, context, model_col, view_col, row, width);
- else
- return 0.0;
-}
-
-/**
- * e_cell_height:
- * @ecell_view: the ECellView.
- * @model_col: the column in the model
- * @view_col: the column in the view.
- * @row: the row to me measured
- *
- * Returns: the height of the cell at @model_col, @row rendered at
- * @view_col, @row.
- */
-int
-e_cell_height (ECellView *ecell_view, int model_col, int view_col, int row)
-{
- return ECVIEW_EC_CLASS(ecell_view)->height (ecell_view, model_col, view_col, row);
-}
-
-/**
- * e_cell_enter_edit:
- * @ecell_view: the ECellView that will enter editing
- * @model_col: the column in the model
- * @view_col: the column in the view
- * @row: the row
- *
- * Notifies the ECellView that it is about to enter editing mode for
- * @model_col, @row rendered at @view_col, @row.
- */
-void *
-e_cell_enter_edit (ECellView *ecell_view, int model_col, int view_col, int row)
-{
- return ECVIEW_EC_CLASS(ecell_view)->enter_edit (ecell_view, model_col, view_col, row);
-}
-
-/**
- * e_cell_leave_edit:
- * @ecell_view: the ECellView that will leave editing
- * @model_col: the column in the model
- * @view_col: the column in the view
- * @row: the row
- * @edit_context: the editing context
- *
- * Notifies the ECellView that editing is finished at @model_col, @row
- * rendered at @view_col, @row.
- */
-void
-e_cell_leave_edit (ECellView *ecell_view, int model_col, int view_col, int row, void *edit_context)
-{
- ECVIEW_EC_CLASS(ecell_view)->leave_edit (ecell_view, model_col, view_col, row, edit_context);
-}
-
-/**
- * e_cell_save_state:
- * @ecell_view: the ECellView to save
- * @model_col: the column in the model
- * @view_col: the column in the view
- * @row: the row
- * @edit_context: the editing context
- *
- * Returns: The save state.
- *
- * Requests that the ECellView return a void * representing the state
- * of the ECell. This is primarily intended for things like selection
- * or scrolling.
- */
-void *
-e_cell_save_state (ECellView *ecell_view, int model_col, int view_col, int row, void *edit_context)
-{
- if (ECVIEW_EC_CLASS(ecell_view)->save_state)
- return ECVIEW_EC_CLASS(ecell_view)->save_state (ecell_view, model_col, view_col, row, edit_context);
- else
- return NULL;
-}
-
-/**
- * e_cell_load_state:
- * @ecell_view: the ECellView to load
- * @model_col: the column in the model
- * @view_col: the column in the view
- * @row: the row
- * @edit_context: the editing context
- * @save_state: the save state to load from
- *
- * Requests that the ECellView load from the given save state.
- */
-void
-e_cell_load_state (ECellView *ecell_view, int model_col, int view_col, int row, void *edit_context, void *save_state)
-{
- if (ECVIEW_EC_CLASS(ecell_view)->load_state)
- ECVIEW_EC_CLASS(ecell_view)->load_state (ecell_view, model_col, view_col, row, edit_context, save_state);
-}
-
-/**
- * e_cell_load_state:
- * @ecell_view: the ECellView
- * @model_col: the column in the model
- * @view_col: the column in the view
- * @row: the row
- * @edit_context: the editing context
- * @save_state: the save state to free
- *
- * Requests that the ECellView free the given save state.
- */
-void
-e_cell_free_state (ECellView *ecell_view, int model_col, int view_col, int row, void *save_state)
-{
- if (ECVIEW_EC_CLASS(ecell_view)->free_state)
- ECVIEW_EC_CLASS(ecell_view)->free_state (ecell_view, model_col, view_col, row, save_state);
-}
-
-/**
- * e_cell_max_width:
- * @ecell_view: the ECellView that will leave editing
- * @model_col: the column in the model
- * @view_col: the column in the view.
- *
- * Returns: the maximum width for the ECellview at @model_col which
- * is being rendered as @view_col
- */
-int
-e_cell_max_width (ECellView *ecell_view, int model_col, int view_col)
-{
- return ECVIEW_EC_CLASS(ecell_view)->max_width
- (ecell_view, model_col, view_col);
-}
-
-/**
- * e_cell_max_width_by_row:
- * @ecell_view: the ECellView that we are curious about
- * @model_col: the column in the model
- * @view_col: the column in the view.
- * @row: The row in the model.
- *
- * Returns: the maximum width for the ECellview at @model_col which
- * is being rendered as @view_col for the data in @row.
- */
-int
-e_cell_max_width_by_row (ECellView *ecell_view, int model_col, int view_col, int row)
-{
- if (ECVIEW_EC_CLASS(ecell_view)->max_width_by_row)
- return ECVIEW_EC_CLASS(ecell_view)->max_width_by_row
- (ecell_view, model_col, view_col, row);
- else
- return e_cell_max_width (ecell_view, model_col, view_col);
-}
-
-/**
- * e_cell_max_width_by_row_implemented:
- * @ecell_view: the ECellView that we are curious about
- * @model_col: the column in the model
- * @view_col: the column in the view.
- * @row: The row in the model.
- *
- * Returns: the maximum width for the ECellview at @model_col which
- * is being rendered as @view_col for the data in @row.
- */
-gboolean
-e_cell_max_width_by_row_implemented (ECellView *ecell_view)
-{
- return (ECVIEW_EC_CLASS(ecell_view)->max_width_by_row != NULL);
-}
-
-void
-e_cell_show_tooltip (ECellView *ecell_view, int model_col, int view_col,
- int row, int col_width, ETableTooltip *tooltip)
-{
- ECVIEW_EC_CLASS(ecell_view)->show_tooltip
- (ecell_view, model_col, view_col, row, col_width, tooltip);
-}
-
-gchar *
-e_cell_get_bg_color(ECellView *ecell_view, int row)
-{
- if (ECVIEW_EC_CLASS(ecell_view)->get_bg_color)
- return ECVIEW_EC_CLASS(ecell_view)->get_bg_color (ecell_view, row);
- else
- return NULL;
-}
-
-void
-e_cell_style_set(ECellView *ecell_view, GtkStyle *previous_style)
-{
- if (ECVIEW_EC_CLASS(ecell_view)->style_set)
- ECVIEW_EC_CLASS(ecell_view)->style_set (ecell_view, previous_style);
-}
-
diff --git a/widgets/table/e-cell.h b/widgets/table/e-cell.h
deleted file mode 100644
index 2ba74c01f5..0000000000
--- a/widgets/table/e-cell.h
+++ /dev/null
@@ -1,224 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-cell.h
- * Copyright 1999, 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Miguel de Icaza <miguel@ximian.com>
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_CELL_H_
-#define _E_CELL_H_
-
-#include <gdk/gdktypes.h>
-#include <libgnomeprint/gnome-print.h>
-#include <libgnomeprint/gnome-font.h>
-#include <gal/e-table/e-table-model.h>
-#include <gal/e-table/e-table-tooltip.h>
-
-G_BEGIN_DECLS
-
-#define E_CELL_TYPE (e_cell_get_type ())
-#define E_CELL(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_CELL_TYPE, ECell))
-#define E_CELL_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_CELL_TYPE, ECellClass))
-#define E_CELL_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), E_CELL_TYPE, ECellClass))
-#define E_IS_CELL(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_CELL_TYPE))
-#define E_IS_CELL_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_CELL_TYPE))
-
-typedef gboolean (*ETableSearchFunc) (gconstpointer haystack,
- const char *needle);
-
-typedef enum {
- E_CELL_SELECTED = 1 << 0,
-
- E_CELL_JUSTIFICATION = 3 << 1,
- E_CELL_JUSTIFY_CENTER = 0 << 1,
- E_CELL_JUSTIFY_LEFT = 1 << 1,
- E_CELL_JUSTIFY_RIGHT = 2 << 1,
- E_CELL_JUSTIFY_FILL = 3 << 1,
-
- E_CELL_ALIGN_LEFT = 1 << 1,
- E_CELL_ALIGN_RIGHT = 1 << 2,
-
- E_CELL_FOCUSED = 1 << 3,
-
- E_CELL_EDITING = 1 << 4,
-
- E_CELL_CURSOR = 1 << 5,
-
- E_CELL_PREEDIT = 1 << 6
-} ECellFlags;
-
-typedef enum {
- E_CELL_GRAB = 1 << 0,
- E_CELL_UNGRAB = 1 << 1
-} ECellActions;
-
-typedef struct {
- GtkObject object;
-} ECell;
-
-typedef struct {
- ECell *ecell;
- ETableModel *e_table_model;
- void *e_table_item_view;
-
- gint focus_x1, focus_y1, focus_x2, focus_y2;
- gint focus_col, focus_row;
-} ECellView;
-
-#define E_CELL_IS_FOCUSED(ecell_view) (ecell_view->focus_x1 != -1)
-
-typedef struct {
- GtkObjectClass parent_class;
-
- ECellView *(*new_view) (ECell *ecell, ETableModel *table_model, void *e_table_item_view);
- void (*kill_view) (ECellView *ecell_view);
-
- void (*realize) (ECellView *ecell_view);
- void (*unrealize) (ECellView *ecell_view);
-
- void (*draw) (ECellView *ecell_view, GdkDrawable *drawable,
- int model_col, int view_col, int row,
- ECellFlags flags, int x1, int y1, int x2, int y2);
- gint (*event) (ECellView *ecell_view, GdkEvent *event, int model_col, int view_col, int row, ECellFlags flags, ECellActions *actions);
- void (*focus) (ECellView *ecell_view, int model_col, int view_col,
- int row, int x1, int y1, int x2, int y2);
- void (*unfocus) (ECellView *ecell_view);
- int (*height) (ECellView *ecell_view, int model_col, int view_col, int row);
-
- void *(*enter_edit) (ECellView *ecell_view, int model_col, int view_col, int row);
- void (*leave_edit) (ECellView *ecell_view, int model_col, int view_col, int row, void *context);
- void *(*save_state) (ECellView *ecell_view, int model_col, int view_col, int row, void *context);
- void (*load_state) (ECellView *ecell_view, int model_col, int view_col, int row, void *context, void *save_state);
- void (*free_state) (ECellView *ecell_view, int model_col, int view_col, int row, void *save_state);
- void (*print) (ECellView *ecell_view, GnomePrintContext *context,
- int model_col, int view_col, int row,
- gdouble width, gdouble height);
- gdouble (*print_height) (ECellView *ecell_view, GnomePrintContext *context,
- int model_col, int view_col, int row, gdouble width);
- int (*max_width) (ECellView *ecell_view, int model_col, int view_col);
- int (*max_width_by_row) (ECellView *ecell_view, int model_col, int view_col, int row);
- void (*show_tooltip) (ECellView *ecell_view, int model_col, int view_col, int row, int col_width, ETableTooltip *tooltip);
- gchar *(*get_bg_color) (ECellView *ecell_view, int row);
-
- void (*style_set) (ECellView *ecell_view, GtkStyle *previous_style);
-} ECellClass;
-
-GType e_cell_get_type (void);
-
-/* View creation methods. */
-ECellView *e_cell_new_view (ECell *ecell,
- ETableModel *table_model,
- void *e_table_item_view);
-void e_cell_kill_view (ECellView *ecell_view);
-
-/* Cell View methods. */
-gint e_cell_event (ECellView *ecell_view,
- GdkEvent *event,
- int model_col,
- int view_col,
- int row,
- ECellFlags flags,
- ECellActions *actions);
-void e_cell_realize (ECellView *ecell_view);
-void e_cell_unrealize (ECellView *ecell_view);
-void e_cell_draw (ECellView *ecell_view,
- GdkDrawable *drawable,
- int model_col,
- int view_col,
- int row,
- ECellFlags flags,
- int x1,
- int y1,
- int x2,
- int y2);
-void e_cell_print (ECellView *ecell_view,
- GnomePrintContext *context,
- int model_col,
- int view_col,
- int row,
- double width,
- double height);
-gdouble e_cell_print_height (ECellView *ecell_view,
- GnomePrintContext *context,
- int model_col,
- int view_col,
- int row,
- gdouble width);
-int e_cell_max_width (ECellView *ecell_view,
- int model_col,
- int view_col);
-int e_cell_max_width_by_row (ECellView *ecell_view,
- int model_col,
- int view_col,
- int row);
-gboolean e_cell_max_width_by_row_implemented (ECellView *ecell_view);
-void e_cell_show_tooltip (ECellView *ecell_view,
- int model_col,
- int view_col,
- int row,
- int col_width,
- ETableTooltip *tooltip);
-gchar *e_cell_get_bg_color (ECellView *ecell_view,
- int row);
-void e_cell_style_set (ECellView *ecell_view,
- GtkStyle *previous_style);
-
-void e_cell_focus (ECellView *ecell_view,
- int model_col,
- int view_col,
- int row,
- int x1,
- int y1,
- int x2,
- int y2);
-void e_cell_unfocus (ECellView *ecell_view);
-int e_cell_height (ECellView *ecell_view,
- int model_col,
- int view_col,
- int row);
-void *e_cell_enter_edit (ECellView *ecell_view,
- int model_col,
- int view_col,
- int row);
-void e_cell_leave_edit (ECellView *ecell_view,
- int model_col,
- int view_col,
- int row,
- void *edit_context);
-void *e_cell_save_state (ECellView *ecell_view,
- int model_col,
- int view_col,
- int row,
- void *edit_context);
-void e_cell_load_state (ECellView *ecell_view,
- int model_col,
- int view_col,
- int row,
- void *edit_context,
- void *state);
-void e_cell_free_state (ECellView *ecell_view,
- int model_col,
- int view_col,
- int row,
- void *state);
-
-G_END_DECLS
-
-#endif /* _E_CELL_H_ */
diff --git a/widgets/table/e-table-click-to-add.c b/widgets/table/e-table-click-to-add.c
deleted file mode 100644
index 544cbcbd86..0000000000
--- a/widgets/table/e-table-click-to-add.c
+++ /dev/null
@@ -1,601 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-click-to-add.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <gdk/gdkkeysyms.h>
-#include <gtk/gtksignal.h>
-#include <libgnomecanvas/gnome-canvas.h>
-#include <libgnomecanvas/gnome-canvas-util.h>
-#include <libgnomecanvas/gnome-canvas-rect-ellipse.h>
-#include <gdk-pixbuf/gdk-pixbuf.h>
-#include <atk/atkregistry.h>
-#include <atk/atkutil.h>
-#include <atk/atkgobjectaccessible.h>
-#include "e-table-header.h"
-#include "e-table-click-to-add.h"
-#include "e-table-defines.h"
-#include "e-table-one.h"
-#include "gal/e-text/e-text.h"
-#include "gal/widgets/e-canvas.h"
-#include "gal/widgets/e-canvas-utils.h"
-#include "gal/util/e-util.h"
-#include "gal/util/e-i18n.h"
-#include "gal/util/e-marshal.h"
-#include "gal/a11y/e-table/gal-a11y-e-table-click-to-add.h"
-
-enum {
- CURSOR_CHANGE,
- STYLE_SET,
- LAST_SIGNAL
-};
-
-static guint etcta_signals [LAST_SIGNAL] = { 0 };
-
-#define PARENT_OBJECT_TYPE gnome_canvas_group_get_type ()
-
-#define ELEMENTS(x) (sizeof (x) / sizeof (x[0]))
-
-static GnomeCanvasGroupClass *etcta_parent_class;
-
-enum {
- PROP_0,
- PROP_HEADER,
- PROP_MODEL,
- PROP_MESSAGE,
- PROP_WIDTH,
- PROP_HEIGHT
-};
-
-static void
-etcta_cursor_change (GtkObject *object, gint row, gint col, ETableClickToAdd *etcta)
-{
- g_signal_emit (etcta,
- etcta_signals [CURSOR_CHANGE], 0,
- row, col);
-}
-
-static void
-etcta_style_set (ETableClickToAdd *etcta, GtkStyle *previous_style)
-{
- GtkWidget *widget = GTK_WIDGET(GNOME_CANVAS_ITEM(etcta)->canvas);
-
- if (etcta->rect) {
- gnome_canvas_item_set (etcta->rect,
- "outline_color_gdk", &widget->style->fg[GTK_STATE_NORMAL],
- "fill_color_gdk", &widget->style->bg[GTK_STATE_NORMAL],
- NULL );
-
- }
-
- if (etcta->text)
- gnome_canvas_item_set (etcta->text,
- "fill_color_gdk", &widget->style->text[GTK_STATE_NORMAL],
- NULL);
-
-}
-
-static void
-etcta_add_table_header (ETableClickToAdd *etcta, ETableHeader *header)
-{
- etcta->eth = header;
- if (etcta->eth)
- g_object_ref (etcta->eth);
- if (etcta->row)
- gnome_canvas_item_set(GNOME_CANVAS_ITEM(etcta->row),
- "ETableHeader", header,
- NULL);
-}
-
-static void
-etcta_drop_table_header (ETableClickToAdd *etcta)
-{
- if (!etcta->eth)
- return;
-
- g_object_unref (etcta->eth);
- etcta->eth = NULL;
-}
-
-static void
-etcta_add_one (ETableClickToAdd *etcta, ETableModel *one)
-{
- etcta->one = one;
- if (etcta->one)
- g_object_ref (etcta->one);
- if (etcta->row)
- gnome_canvas_item_set(GNOME_CANVAS_ITEM(etcta->row),
- "ETableModel", one,
- NULL);
- g_object_set(etcta->selection,
- "model", one,
- NULL);
-}
-
-static void
-etcta_drop_one (ETableClickToAdd *etcta)
-{
- if (!etcta->one)
- return;
- g_object_unref (etcta->one);
- etcta->one = NULL;
- g_object_set(etcta->selection,
- "model", NULL,
- NULL);
-}
-
-static void
-etcta_add_model (ETableClickToAdd *etcta, ETableModel *model)
-{
- etcta->model = model;
- if (etcta->model)
- g_object_ref (etcta->model);
-}
-
-static void
-etcta_drop_model (ETableClickToAdd *etcta)
-{
- etcta_drop_one (etcta);
- if (!etcta->model)
- return;
- g_object_unref (etcta->model);
- etcta->model = NULL;
-}
-
-static void
-etcta_add_message (ETableClickToAdd *etcta, char *message)
-{
- etcta->message = g_strdup(message);
-}
-
-static void
-etcta_drop_message (ETableClickToAdd *etcta)
-{
- g_free(etcta->message);
- etcta->message = NULL;
-}
-
-
-static void
-etcta_dispose (GObject *object)
-{
- ETableClickToAdd *etcta = E_TABLE_CLICK_TO_ADD (object);
-
- etcta_drop_table_header (etcta);
- etcta_drop_model (etcta);
- etcta_drop_message (etcta);
- if (etcta->selection)
- g_object_unref (etcta->selection);
- etcta->selection = NULL;
-
- if (G_OBJECT_CLASS (etcta_parent_class)->dispose)
- (*G_OBJECT_CLASS (etcta_parent_class)->dispose) (object);
-}
-
-static void
-etcta_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
-{
- GnomeCanvasItem *item;
- ETableClickToAdd *etcta;
-
- item = GNOME_CANVAS_ITEM (object);
- etcta = E_TABLE_CLICK_TO_ADD (object);
-
- switch (prop_id){
- case PROP_HEADER:
- etcta_drop_table_header (etcta);
- etcta_add_table_header (etcta, E_TABLE_HEADER(g_value_get_object (value)));
- break;
- case PROP_MODEL:
- etcta_drop_model (etcta);
- etcta_add_model (etcta, E_TABLE_MODEL(g_value_get_object (value)));
- break;
- case PROP_MESSAGE:
- etcta_drop_message (etcta);
- etcta_add_message (etcta, (char*)g_value_get_string (value));
- break;
- case PROP_WIDTH:
- etcta->width = g_value_get_double (value);
- if (etcta->row)
- gnome_canvas_item_set(etcta->row,
- "minimum_width", etcta->width,
- NULL);
- if (etcta->text)
- gnome_canvas_item_set(etcta->text,
- "width", etcta->width - 4,
- NULL);
- if (etcta->rect)
- gnome_canvas_item_set(etcta->rect,
- "x2", etcta->width - 1,
- NULL);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- return;
-
- }
- gnome_canvas_item_request_update(item);
-}
-
-static void
-create_rect_and_text (ETableClickToAdd *etcta)
-{
- GtkWidget *widget = GTK_WIDGET (GNOME_CANVAS_ITEM(etcta)->canvas);
-
- if (!etcta->rect)
- etcta->rect = gnome_canvas_item_new(GNOME_CANVAS_GROUP(etcta),
- gnome_canvas_rect_get_type(),
- "x1", (double) 0,
- "y1", (double) 0,
- "x2", (double) etcta->width - 1,
- "y2", (double) etcta->height - 1,
- "outline_color_gdk", &widget->style->fg[GTK_STATE_NORMAL],
- "fill_color_gdk", &widget->style->bg[GTK_STATE_NORMAL],
- NULL);
-
- if (!etcta->text)
- etcta->text = gnome_canvas_item_new(GNOME_CANVAS_GROUP(etcta),
- e_text_get_type(),
- "text", etcta->message ? etcta->message : "",
- "anchor", GTK_ANCHOR_NW,
- "width", etcta->width - 4,
- "draw_background", FALSE,
- "fill_color_gdk", &widget->style->text[GTK_STATE_NORMAL],
- NULL);
-}
-
-static void
-etcta_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
-{
- ETableClickToAdd *etcta;
-
- etcta = E_TABLE_CLICK_TO_ADD (object);
-
- switch (prop_id){
- case PROP_HEADER:
- g_value_set_object (value, etcta->eth);
- break;
- case PROP_MODEL:
- g_value_set_object (value, etcta->model);
- break;
- case PROP_MESSAGE:
- g_value_set_string (value, g_strdup(etcta->message));
- break;
- case PROP_WIDTH:
- g_value_set_double (value, etcta->width);
- break;
- case PROP_HEIGHT:
- g_value_set_double (value, etcta->height);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-etcta_realize (GnomeCanvasItem *item)
-{
- ETableClickToAdd *etcta = E_TABLE_CLICK_TO_ADD (item);
-
- create_rect_and_text (etcta);
- e_canvas_item_move_absolute (etcta->text, 2, 2);
-
- if (GNOME_CANVAS_ITEM_CLASS (etcta_parent_class)->realize)
- (*GNOME_CANVAS_ITEM_CLASS (etcta_parent_class)->realize)(item);
-
- e_canvas_item_request_reflow (item);
-}
-
-static void
-etcta_unrealize (GnomeCanvasItem *item)
-{
- if (GNOME_CANVAS_ITEM_CLASS (etcta_parent_class)->unrealize)
- (*GNOME_CANVAS_ITEM_CLASS (etcta_parent_class)->unrealize)(item);
-}
-
-static void finish_editing (ETableClickToAdd *etcta);
-
-static int
-item_key_press (ETableItem *item, int row, int col, GdkEvent *event, ETableClickToAdd *etcta)
-{
- switch (event->key.keyval) {
- case GDK_Return:
- case GDK_KP_Enter:
- case GDK_ISO_Enter:
- case GDK_3270_Enter:
- finish_editing(etcta);
- return TRUE;
- }
- return FALSE;
-}
-
-static void
-set_initial_selection (ETableClickToAdd *etcta)
-{
- e_selection_model_do_something (E_SELECTION_MODEL(etcta->selection),
- 0, e_table_header_prioritized_column (etcta->eth),
- 0);
-}
-
-static void
-finish_editing (ETableClickToAdd *etcta)
-{
- if (etcta->row) {
- ETableModel *one;
-
- e_table_item_leave_edit (E_TABLE_ITEM (etcta->row));
- e_table_one_commit(E_TABLE_ONE(etcta->one));
- etcta_drop_one (etcta);
- gtk_object_destroy(GTK_OBJECT (etcta->row));
- etcta->row = NULL;
-
- one = e_table_one_new(etcta->model);
- etcta_add_one (etcta, one);
- g_object_unref (one);
-
- e_selection_model_clear(E_SELECTION_MODEL(etcta->selection));
-
- etcta->row = gnome_canvas_item_new(GNOME_CANVAS_GROUP(etcta),
- e_table_item_get_type(),
- "ETableHeader", etcta->eth,
- "ETableModel", etcta->one,
- "minimum_width", etcta->width,
- "horizontal_draw_grid", TRUE,
- "vertical_draw_grid", TRUE,
- "selection_model", etcta->selection,
- "cursor_mode", E_CURSOR_SPREADSHEET,
- NULL);
-
- g_signal_connect(etcta->row, "key_press",
- G_CALLBACK(item_key_press), etcta);
-
- set_initial_selection (etcta);
- }
-}
-
-/*
- * Handles the events on the ETableClickToAdd, particularly it creates the ETableItem and passes in some events.
- */
-static int
-etcta_event (GnomeCanvasItem *item, GdkEvent *e)
-{
- ETableClickToAdd *etcta = E_TABLE_CLICK_TO_ADD (item);
-
- switch (e->type){
- case GDK_FOCUS_CHANGE:
- if (!e->focus_change.in)
- return TRUE;
-
- case GDK_BUTTON_PRESS:
- if (etcta->text) {
- gtk_object_destroy(GTK_OBJECT (etcta->text));
- etcta->text = NULL;
- }
- if (etcta->rect) {
- gtk_object_destroy(GTK_OBJECT (etcta->rect));
- etcta->rect = NULL;
- }
- if (!etcta->row) {
- ETableModel *one;
-
- one = e_table_one_new(etcta->model);
- etcta_add_one (etcta, one);
- g_object_unref (one);
-
- e_selection_model_clear(E_SELECTION_MODEL(etcta->selection));
-
- etcta->row = gnome_canvas_item_new(GNOME_CANVAS_GROUP(item),
- e_table_item_get_type(),
- "ETableHeader", etcta->eth,
- "ETableModel", etcta->one,
- "minimum_width", etcta->width,
- "horizontal_draw_grid", TRUE,
- "vertical_draw_grid", TRUE,
- "selection_model", etcta->selection,
- "cursor_mode", E_CURSOR_SPREADSHEET,
- NULL);
-
- g_signal_connect(etcta->row, "key_press",
- G_CALLBACK (item_key_press), etcta);
-
- e_canvas_item_grab_focus (GNOME_CANVAS_ITEM(etcta->row), TRUE);
-
- set_initial_selection (etcta);
- }
- break;
-
- case GDK_KEY_PRESS:
- switch (e->key.keyval) {
- case GDK_Tab:
- case GDK_KP_Tab:
- case GDK_ISO_Left_Tab:
- finish_editing (etcta);
- break;
- default:
- return FALSE;
- break;
- }
- break;
-
- default:
- return FALSE;
- }
- return TRUE;
-}
-
-static void
-etcta_reflow (GnomeCanvasItem *item, int flags)
-{
- ETableClickToAdd *etcta = E_TABLE_CLICK_TO_ADD (item);
-
- double old_height = etcta->height;
-
- if (etcta->text) {
- g_object_get(etcta->text,
- "height", &etcta->height,
- NULL);
- etcta->height += 6;
- }
- if (etcta->row) {
- g_object_get(etcta->row,
- "height", &etcta->height,
- NULL);
- }
-
- if (etcta->rect) {
- g_object_set(etcta->rect,
- "y2", etcta->height - 1,
- NULL);
- }
-
- if (old_height != etcta->height)
- e_canvas_item_request_parent_reflow(item);
-}
-
-static void
-etcta_class_init (ETableClickToAddClass *klass)
-{
- GnomeCanvasItemClass *item_class = GNOME_CANVAS_ITEM_CLASS(klass);
- GObjectClass *object_class = G_OBJECT_CLASS(klass);
-
- etcta_parent_class = g_type_class_ref (PARENT_OBJECT_TYPE);
-
- klass->cursor_change = NULL;
- klass->style_set = etcta_style_set;
-
- object_class->dispose = etcta_dispose;
- object_class->set_property = etcta_set_property;
- object_class->get_property = etcta_get_property;
-
- item_class->realize = etcta_realize;
- item_class->unrealize = etcta_unrealize;
- item_class->event = etcta_event;
-
- g_object_class_install_property (object_class, PROP_HEADER,
- g_param_spec_object ("header",
- _("Header"),
- /*_( */"XXX blurb" /*)*/,
- E_TABLE_HEADER_TYPE,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class, PROP_MODEL,
- g_param_spec_object ("model",
- _("Model"),
- /*_( */"XXX blurb" /*)*/,
- E_TABLE_MODEL_TYPE,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class, PROP_MESSAGE,
- g_param_spec_string ("message",
- _("Message"),
- /*_( */"XXX blurb" /*)*/,
- NULL,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class, PROP_WIDTH,
- g_param_spec_double ("width",
- _("Width"),
- /*_( */"XXX blurb" /*)*/,
- 0.0, G_MAXDOUBLE, 0.0,
- G_PARAM_READWRITE | G_PARAM_LAX_VALIDATION));
-
- g_object_class_install_property (object_class, PROP_HEIGHT,
- g_param_spec_double ("height",
- _("Height"),
- /*_( */"XXX blurb" /*)*/,
- 0.0, G_MAXDOUBLE, 0.0,
- G_PARAM_READABLE | G_PARAM_LAX_VALIDATION));
-
- etcta_signals [CURSOR_CHANGE] =
- g_signal_new ("cursor_change",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableClickToAddClass, cursor_change),
- NULL, NULL,
- e_marshal_VOID__INT_INT,
- G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
-
- etcta_signals [STYLE_SET] =
- g_signal_new ("style_set",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableClickToAddClass, style_set),
- NULL, NULL,
- e_marshal_NONE__OBJECT,
- G_TYPE_NONE, 1, GTK_TYPE_STYLE);
-
- gal_a11y_e_table_click_to_add_init ();
-}
-
-static void
-etcta_init (GnomeCanvasItem *item)
-{
- ETableClickToAdd *etcta = E_TABLE_CLICK_TO_ADD (item);
- AtkObject *a11y;
-
- etcta->one = NULL;
- etcta->model = NULL;
- etcta->eth = NULL;
-
- etcta->message = NULL;
-
- etcta->row = NULL;
- etcta->text = NULL;
- etcta->rect = NULL;
-
- etcta->selection = e_table_selection_model_new();
- g_signal_connect(etcta->selection, "cursor_changed",
- G_CALLBACK (etcta_cursor_change), etcta);
-
- e_canvas_item_set_reflow_callback(item, etcta_reflow);
-
- /* create its a11y object at this time if accessibility is enabled*/
- if (atk_get_root () != NULL) {
- a11y = atk_gobject_accessible_for_object (G_OBJECT (etcta));
- atk_object_set_name (a11y, _("click to add"));
- }
-}
-
-E_MAKE_TYPE(e_table_click_to_add, "ETableClickToAdd", ETableClickToAdd, etcta_class_init, etcta_init, PARENT_OBJECT_TYPE)
-
-
-/* The colors in this need to be themefied. */
-/**
- * e_table_click_to_add_commit:
- * @etcta: The %ETableClickToAdd to commit.
- *
- * This routine commits the current thing being edited and returns to
- * just displaying the click to add message.
- **/
-void
-e_table_click_to_add_commit (ETableClickToAdd *etcta)
-{
- if (etcta->row) {
- e_table_one_commit(E_TABLE_ONE(etcta->one));
- etcta_drop_one (etcta);
- gtk_object_destroy(GTK_OBJECT (etcta->row));
- etcta->row = NULL;
- }
- create_rect_and_text (etcta);
- e_canvas_item_move_absolute (etcta->text, 3, 3);
-}
diff --git a/widgets/table/e-table-click-to-add.h b/widgets/table/e-table-click-to-add.h
deleted file mode 100644
index 42ffd42d07..0000000000
--- a/widgets/table/e-table-click-to-add.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-click-to-add.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_TABLE_CLICK_TO_ADD_H_
-#define _E_TABLE_CLICK_TO_ADD_H_
-
-#include <libxml/tree.h>
-#include <libgnomecanvas/gnome-canvas.h>
-#include <gal/e-table/e-table-header.h>
-#include <gal/e-table/e-table-sort-info.h>
-#include <gal/e-table/e-table-item.h>
-#include <gal/e-table/e-table-selection-model.h>
-
-G_BEGIN_DECLS
-
-#define E_TABLE_CLICK_TO_ADD_TYPE (e_table_click_to_add_get_type ())
-#define E_TABLE_CLICK_TO_ADD(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TABLE_CLICK_TO_ADD_TYPE, ETableClickToAdd))
-#define E_TABLE_CLICK_TO_ADD_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TABLE_CLICK_TO_ADD_TYPE, ETableClickToAddClass))
-#define E_IS_TABLE_CLICK_TO_ADD(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TABLE_CLICK_TO_ADD_TYPE))
-#define E_IS_TABLE_CLICK_TO_ADD_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TABLE_CLICK_TO_ADD_TYPE))
-
-typedef struct {
- GnomeCanvasGroup parent;
-
- ETableModel *one; /* The ETableOne. */
-
- ETableModel *model; /* The backend model. */
- ETableHeader *eth; /* This is just to give to the ETableItem. */
-
- char *message;
-
- GnomeCanvasItem *row; /* If row is NULL, we're sitting with no data and a "Click here" message. */
- GnomeCanvasItem *text; /* If text is NULL, row shouldn't be. */
- GnomeCanvasItem *rect; /* What the heck. Why not. */
-
- gdouble width;
- gdouble height;
-
- ETableSelectionModel *selection;
-} ETableClickToAdd;
-
-typedef struct {
- GnomeCanvasGroupClass parent_class;
-
- /*
- * signals
- */
- void (*cursor_change) (ETableClickToAdd *etcta, gint row, gint col);
- void (*style_set) (ETableClickToAdd *etcta, GtkStyle *previous_style);
-} ETableClickToAddClass;
-
-GType e_table_click_to_add_get_type (void);
-
-void e_table_click_to_add_commit (ETableClickToAdd *etcta);
-
-G_END_DECLS
-
-#endif /* _E_TABLE_CLICK_TO_ADD_H_ */
diff --git a/widgets/table/e-table-col-dnd.h b/widgets/table/e-table-col-dnd.h
deleted file mode 100644
index d31c94ed26..0000000000
--- a/widgets/table/e-table-col-dnd.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-col-dnd.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_TABLE_COL_DND_H_
-#define _E_TABLE_COL_DND_H_
-
-#include <glib.h>
-
-G_BEGIN_DECLS
-
-#define TARGET_ETABLE_COL_TYPE "application/x-etable-column-header"
-
-enum {
- TARGET_ETABLE_COL_HEADER
-};
-
-G_END_DECLS
-
-#endif /* _E_TABLE_COL_DND_H_ */
diff --git a/widgets/table/e-table-col.c b/widgets/table/e-table-col.c
deleted file mode 100644
index 9acc0ba4fd..0000000000
--- a/widgets/table/e-table-col.c
+++ /dev/null
@@ -1,236 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-col.c
- * Copyright 1999, 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Miguel de Icaza <miguel@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include "e-table-col.h"
-#include "gal/util/e-util.h"
-#include "gal/util/e-i18n.h"
-
-static GObjectClass *parent_class;
-
-enum {
- PROP_0,
- PROP_COMPARE_COL,
-};
-
-static void
-etc_dispose (GObject *object)
-{
- ETableCol *etc = E_TABLE_COL (object);
-
- if (etc->ecell)
- g_object_unref (etc->ecell);
- etc->ecell = NULL;
-
- if (etc->pixbuf)
- gdk_pixbuf_unref (etc->pixbuf);
- etc->pixbuf = NULL;
-
- if (etc->text)
- g_free (etc->text);
- etc->text = NULL;
-
- parent_class->dispose (object);
-}
-
-static void
-etc_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
-{
- ETableCol *etc = E_TABLE_COL (object);
-
- switch (prop_id) {
- case PROP_COMPARE_COL:
- etc->compare_col = g_value_get_int (value);
- break;
- default:
- break;
- }
-}
-
-static void
-etc_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
-{
- ETableCol *etc = E_TABLE_COL (object);
-
- switch (prop_id) {
- case PROP_COMPARE_COL:
- g_value_set_int (value, etc->compare_col);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-e_table_col_class_init (GObjectClass *object_class)
-{
- parent_class = g_type_class_peek_parent (object_class);
-
- object_class->dispose = etc_dispose;
- object_class->set_property = etc_set_property;
- object_class->get_property = etc_get_property;
-
- g_object_class_install_property (object_class, PROP_COMPARE_COL,
- g_param_spec_int ("compare_col",
- _( "Width" ),
- "Width",
- 0, G_MAXINT, 0,
- G_PARAM_READWRITE));
-}
-
-static void
-e_table_col_init (ETableCol *etc)
-{
- etc->width = 0;
- etc->sortable = 1;
- etc->groupable = 1;
- etc->justification = GTK_JUSTIFY_LEFT;
- etc->priority = 0;
-}
-
-E_MAKE_TYPE(e_table_col, "ETableCol", ETableCol, e_table_col_class_init, e_table_col_init, G_TYPE_OBJECT)
-
-/**
- * e_table_col_new:
- * @col_idx: the column we represent in the model
- * @text: a title for this column
- * @expansion: FIXME
- * @min_width: minimum width in pixels for this column
- * @ecell: the renderer to be used for this column
- * @compare: comparision function for the elements stored in this column
- * @resizable: whether the column can be resized interactively by the user
- * @priority: FIXME
- *
- * The ETableCol represents a column to be used inside an ETable. The
- * ETableCol objects are inserted inside an ETableHeader (which is just a collection
- * of ETableCols). The ETableHeader is the definition of the order in which
- * columns are shown to the user.
- *
- * The @text argument is the the text that will be shown as a header to the
- * user. @col_idx reflects where the data for this ETableCol object will
- * be fetch from an ETableModel. So even if the user changes the order
- * of the columns being viewed (the ETableCols in the ETableHeader), the
- * column will always point to the same column inside the ETableModel.
- *
- * The @ecell argument is an ECell object that needs to know how to render the
- * data in the ETableModel for this specific row.
- *
- * Returns: the newly created ETableCol object.
- */
-ETableCol *
-e_table_col_new (int col_idx, const char *text, double expansion, int min_width,
- ECell *ecell, GCompareFunc compare, gboolean resizable, gboolean disabled, int priority)
-{
- ETableCol *etc;
-
- g_return_val_if_fail (expansion >= 0, NULL);
- g_return_val_if_fail (min_width >= 0, NULL);
- g_return_val_if_fail (ecell != NULL, NULL);
- g_return_val_if_fail (compare != NULL, NULL);
- g_return_val_if_fail (text != NULL, NULL);
-
- etc = g_object_new (E_TABLE_COL_TYPE, NULL);
-
- etc->is_pixbuf = FALSE;
-
- etc->col_idx = col_idx;
- etc->compare_col = col_idx;
- etc->text = g_strdup (text);
- etc->pixbuf = NULL;
- etc->expansion = expansion;
- etc->min_width = min_width;
- etc->ecell = ecell;
- etc->compare = compare;
- etc->disabled = disabled;
- etc->priority = priority;
-
- etc->selected = 0;
- etc->resizable = resizable;
-
- g_object_ref (etc->ecell);
-
- return etc;
-}
-
-/**
- * e_table_col_new_with_pixbuf:
- * @col_idx: the column we represent in the model
- * @pixbuf: the image to be used for the header
- * @expansion: FIXME
- * @min_width: minimum width in pixels for this column
- * @ecell: the renderer to be used for this column
- * @compare: comparision function for the elements stored in this column
- * @resizable: whether the column can be resized interactively by the user
- *
- * The ETableCol represents a column to be used inside an ETable. The
- * ETableCol objects are inserted inside an ETableHeader (which is just a collection
- * of ETableCols). The ETableHeader is the definition of the order in which
- * columns are shown to the user.
- *
- * The @text argument is the the text that will be shown as a header to the
- * user. @col_idx reflects where the data for this ETableCol object will
- * be fetch from an ETableModel. So even if the user changes the order
- * of the columns being viewed (the ETableCols in the ETableHeader), the
- * column will always point to the same column inside the ETableModel.
- *
- * The @ecell argument is an ECell object that needs to know how to render the
- * data in the ETableModel for this specific row.
- *
- * Returns: the newly created ETableCol object.
- */
-ETableCol *
-e_table_col_new_with_pixbuf (int col_idx, const char *text, GdkPixbuf *pixbuf, double expansion, int min_width,
- ECell *ecell, GCompareFunc compare, gboolean resizable, gboolean disabled, int priority)
-{
- ETableCol *etc;
-
- g_return_val_if_fail (expansion >= 0, NULL);
- g_return_val_if_fail (min_width >= 0, NULL);
- g_return_val_if_fail (ecell != NULL, NULL);
- g_return_val_if_fail (compare != NULL, NULL);
- g_return_val_if_fail (pixbuf != NULL, NULL);
-
- etc = g_object_new (E_TABLE_COL_TYPE, NULL);
-
- etc->is_pixbuf = TRUE;
-
- etc->col_idx = col_idx;
- etc->compare_col = col_idx;
- etc->text = g_strdup(text);
- etc->pixbuf = pixbuf;
- etc->expansion = expansion;
- etc->min_width = min_width;
- etc->ecell = ecell;
- etc->compare = compare;
- etc->disabled = disabled;
- etc->priority = priority;
-
- etc->selected = 0;
- etc->resizable = resizable;
-
- g_object_ref (etc->ecell);
- gdk_pixbuf_ref (etc->pixbuf);
-
- return etc;
-}
diff --git a/widgets/table/e-table-col.h b/widgets/table/e-table-col.h
deleted file mode 100644
index 8f2369c76a..0000000000
--- a/widgets/table/e-table-col.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-col.h
- * Copyright 1999, 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Miguel de Icaza <miguel@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_TABLE_COL_H_
-#define _E_TABLE_COL_H_
-
-#include <gdk-pixbuf/gdk-pixbuf.h>
-#include <gal/e-table/e-cell.h>
-
-G_BEGIN_DECLS
-
-#define E_TABLE_COL_TYPE (e_table_col_get_type ())
-#define E_TABLE_COL(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TABLE_COL_TYPE, ETableCol))
-#define E_TABLE_COL_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TABLE_COL_TYPE, ETableColClass))
-#define E_IS_TABLE_COL(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TABLE_COL_TYPE))
-#define E_IS_TABLE_COL_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TABLE_COL_TYPE))
-#define E_TABLE_COL_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), E_TABLE_COL_TYPE, ETableColClass))
-
-typedef enum {
- E_TABLE_COL_ARROW_NONE = 0,
- E_TABLE_COL_ARROW_UP,
- E_TABLE_COL_ARROW_DOWN
-} ETableColArrow;
-
-/*
- * Information about a single column
- */
-typedef struct {
- GObject base;
- char *text;
- GdkPixbuf *pixbuf;
- int min_width;
- int width;
- double expansion;
- short x;
- GCompareFunc compare;
- ETableSearchFunc search;
- unsigned int is_pixbuf:1;
- unsigned int selected:1;
- unsigned int resizable:1;
- unsigned int disabled:1;
- unsigned int sortable:1;
- unsigned int groupable:1;
- int col_idx;
- int compare_col;
- int priority;
-
- GtkJustification justification;
-
- ECell *ecell;
-} ETableCol;
-
-typedef struct {
- GObjectClass parent_class;
-} ETableColClass;
-
-GType e_table_col_get_type (void);
-ETableCol *e_table_col_new (int col_idx,
- const char *text,
- double expansion,
- int min_width,
- ECell *ecell,
- GCompareFunc compare,
- gboolean resizable,
- gboolean disabled,
- int priority);
-ETableCol *e_table_col_new_with_pixbuf (int col_idx,
- const char *text,
- GdkPixbuf *pixbuf,
- double expansion,
- int min_width,
- ECell *ecell,
- GCompareFunc compare,
- gboolean resizable,
- gboolean disabled,
- int priority);
-
-G_END_DECLS
-
-#endif /* _E_TABLE_COL_H_ */
-
diff --git a/widgets/table/e-table-column-specification.c b/widgets/table/e-table-column-specification.c
deleted file mode 100644
index 2e992414d5..0000000000
--- a/widgets/table/e-table-column-specification.c
+++ /dev/null
@@ -1,150 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-column-specification.c - Savable specification of a column.
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <stdlib.h>
-#include <libxml/parser.h>
-#include <libxml/xmlmemory.h>
-#include "gal/util/e-xml-utils.h"
-#include "gal/util/e-util.h"
-#include "e-table-column-specification.h"
-
-static GObjectClass *etcs_parent_class;
-
-static void
-free_strings (ETableColumnSpecification *etcs)
-{
- g_free(etcs->title);
- etcs->title = NULL;
- g_free(etcs->pixbuf);
- etcs->pixbuf = NULL;
- g_free(etcs->cell);
- etcs->cell = NULL;
- g_free(etcs->compare);
- etcs->compare = NULL;
- g_free(etcs->search);
- etcs->search = NULL;
-}
-
-static void
-etcs_finalize (GObject *object)
-{
- ETableColumnSpecification *etcs = E_TABLE_COLUMN_SPECIFICATION (object);
-
- free_strings(etcs);
-
- etcs_parent_class->finalize (object);
-}
-
-static void
-etcs_class_init (GObjectClass *klass)
-{
- etcs_parent_class = g_type_class_peek_parent (klass);
-
- klass->finalize = etcs_finalize;
-}
-
-static void
-etcs_init (ETableColumnSpecification *specification)
-{
- specification->model_col = 0;
- specification->compare_col = 0;
- specification->title = g_strdup("");
- specification->pixbuf = NULL;
-
- specification->expansion = 0;
- specification->minimum_width = 0;
- specification->resizable = FALSE;
- specification->disabled = FALSE;
-
- specification->cell = NULL;
- specification->compare = NULL;
- specification->search = NULL;
- specification->priority = 0;
-}
-
-E_MAKE_TYPE(e_table_column_specification, "ETableColumnSpecification", ETableColumnSpecification, etcs_class_init, etcs_init, G_TYPE_OBJECT)
-
-ETableColumnSpecification *
-e_table_column_specification_new (void)
-{
- ETableColumnSpecification *etcs = g_object_new (E_TABLE_COLUMN_SPECIFICATION_TYPE, NULL);
-
- return (ETableColumnSpecification *) etcs;
-}
-
-void
-e_table_column_specification_load_from_node (ETableColumnSpecification *etcs,
- const xmlNode *node)
-{
- free_strings(etcs);
-
- etcs->model_col = e_xml_get_integer_prop_by_name (node, "model_col");
- etcs->compare_col = e_xml_get_integer_prop_by_name_with_default (node, "compare_col", etcs->model_col);
- etcs->title = e_xml_get_string_prop_by_name (node, "_title");
- etcs->pixbuf = e_xml_get_string_prop_by_name (node, "pixbuf");
-
- etcs->expansion = e_xml_get_double_prop_by_name (node, "expansion");
- etcs->minimum_width = e_xml_get_integer_prop_by_name (node, "minimum_width");
- etcs->resizable = e_xml_get_bool_prop_by_name (node, "resizable");
- etcs->disabled = e_xml_get_bool_prop_by_name (node, "disabled");
-
- etcs->cell = e_xml_get_string_prop_by_name (node, "cell");
- etcs->compare = e_xml_get_string_prop_by_name (node, "compare");
- etcs->search = e_xml_get_string_prop_by_name (node, "search");
- etcs->priority = e_xml_get_integer_prop_by_name_with_default (node, "priority", 0);
-
- if (etcs->title == NULL)
- etcs->title = g_strdup("");
-}
-
-xmlNode *
-e_table_column_specification_save_to_node (ETableColumnSpecification *specification,
- xmlNode *parent)
-{
- xmlNode *node;
- if (parent)
- node = xmlNewChild(parent, NULL, "ETableColumn", NULL);
- else
- node = xmlNewNode(NULL, "ETableColumn");
-
- e_xml_set_integer_prop_by_name(node, "model_col", specification->model_col);
- if (specification->compare_col != specification->model_col)
- e_xml_set_integer_prop_by_name(node, "compare_col", specification->compare_col);
- e_xml_set_string_prop_by_name(node, "_title", specification->title);
- e_xml_set_string_prop_by_name(node, "pixbuf", specification->pixbuf);
-
- e_xml_set_double_prop_by_name(node, "expansion", specification->expansion);
- e_xml_set_integer_prop_by_name(node, "minimum_width", specification->minimum_width);
- e_xml_set_bool_prop_by_name(node, "resizable", specification->resizable);
- e_xml_set_bool_prop_by_name(node, "disabled", specification->disabled);
-
- e_xml_set_string_prop_by_name(node, "cell", specification->cell);
- e_xml_set_string_prop_by_name(node, "compare", specification->compare);
- e_xml_set_string_prop_by_name(node, "search", specification->search);
- if (specification->priority != 0)
- e_xml_set_integer_prop_by_name (node, "priority", specification->priority);
-
- return node;
-}
-
diff --git a/widgets/table/e-table-column-specification.h b/widgets/table/e-table-column-specification.h
deleted file mode 100644
index 6bf5623398..0000000000
--- a/widgets/table/e-table-column-specification.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-column-specification.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_TABLE_COLUMN_SPECIFICATION_H_
-#define _E_TABLE_COLUMN_SPECIFICATION_H_
-
-#include <glib.h>
-#include <glib-object.h>
-#include <libxml/tree.h>
-
-G_BEGIN_DECLS
-
-#define E_TABLE_COLUMN_SPECIFICATION_TYPE (e_table_column_specification_get_type ())
-#define E_TABLE_COLUMN_SPECIFICATION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TABLE_COLUMN_SPECIFICATION_TYPE, ETableColumnSpecification))
-#define E_TABLE_COLUMN_SPECIFICATION_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TABLE_COLUMN_SPECIFICATION_TYPE, ETableColumnSpecificationClass))
-#define E_IS_TABLE_COLUMN_SPECIFICATION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TABLE_COLUMN_SPECIFICATION_TYPE))
-#define E_IS_TABLE_COLUMN_SPECIFICATION_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TABLE_COLUMN_SPECIFICATION_TYPE))
-#define E_TABLE_COLUMN_SPECIFICATION_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), E_TABLE_COLUMN_SPECIFICATION_TYPE, ETableColumnSpecificationClass))
-
-typedef struct {
- GObject base;
- int model_col;
- int compare_col;
- char *title;
- char *pixbuf;
-
- double expansion;
- int minimum_width;
- guint resizable : 1;
- guint disabled : 1;
-
- char *cell;
- char *compare;
- char *search;
- int priority;
-} ETableColumnSpecification;
-
-typedef struct {
- GObjectClass parent_class;
-} ETableColumnSpecificationClass;
-
-GType e_table_column_specification_get_type (void);
-
-ETableColumnSpecification *e_table_column_specification_new (void);
-
-void e_table_column_specification_load_from_node (ETableColumnSpecification *state,
- const xmlNode *node);
-xmlNode *e_table_column_specification_save_to_node (ETableColumnSpecification *state,
- xmlNode *parent);
-
-G_END_DECLS
-
-#endif /* _E_TABLE_COLUMN_SPECIFICATION_H_ */
diff --git a/widgets/table/e-table-column.c b/widgets/table/e-table-column.c
deleted file mode 100644
index 514a25e74e..0000000000
--- a/widgets/table/e-table-column.c
+++ /dev/null
@@ -1,291 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-column.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include "e-table-column.h"
-
-enum {
- STRUCTURE_CHANGE,
- DIMENSION_CHANGE,
- LAST_SIGNAL
-};
-
-static guint etc_signals [LAST_SIGNAL] = { 0, };
-
-#define PARENT_CLASS GTK_TYPE_OBJECT
-static GtkObjectClass *e_table_column_parent_class;
-
-static void
-e_table_column_finalize (GObject *object)
-{
- ETableColumn *etc = E_TABLE_COLUMN (object);
- const int cols = etc->col_count;
-
- /*
- * Destroy listeners
- */
- for (l = etc->listeners; l; l = l->next)
- g_free (l->data);
- g_slist_free (etc->listeners);
- etc->listeners = NULL;
-
- /*
- * Destroy columns
- */
- for (i = 0; i < cols; i++)
- e_table_column_remove (etc, i);
-
- G_OBJECT_CLASS (e_table_column_parent_class)->finalize (object);
-}
-
-static void
-e_table_column_class_init (GtkObjectClass *object_class)
-{
- G_OBJECT_CLASS (object_class)->finalize = e_table_column_finalize;
-
- e_table_column_parent_class = g_type_class_ref (PARENT_CLASS);
-
- etc_signals [STRUCTURE_CHANGE] =
- g_signal_new ("structure_change",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableColumn, structure_change),
- NULL, NULL,
- e_marshal_NONE__NONE,
- G_TYPE_NONE, 0);
- etc_signals [DIMENSION_CHANGE] =
- g_signal_new ("dimension_change",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableColumn, dimension_change),
- e_marshal_NONE__INT,
- G_TYPE_NONE, 1, G_TYPE_INT);
-}
-
-E_MAKE_TYPE (e_table_column,
- "ETableColumn",
- ETableColumn,
- e_table_column_class_init,
- NULL,
- PARENT_TYPE);
-
-static void
-etc_do_insert (ETableColumn *etc, int pos, ETableCol *val)
-{
- memcpy (&etc->columns [pos+1], &etc->columns [pos],
- sizeof (ETableCol *) * (etc->col_count - pos));
- etc->columns [pos] = val;
-}
-
-void
-e_table_column_add_column (ETableColumn *etc, ETableCol *tc, int pos)
-{
- ETableCol **new_ptr;
-
- g_return_if_fail (etc != NULL);
- g_return_if_fail (E_IS_TABLE_COLUMN (etc));
- g_return_if_fail (tc != NULL);
- g_return_if_fail (pos >= 0 && pos < etc->col_count);
-
- if (pos == -1)
- pos = etc->col_count;
- etc->columns = g_realloc (etc->columns, sizeof (ETableCol *) * (etc->col_count + 1));
- etc_do_insert (etc, pos, tc);
- etc->col_count++;
-
- g_signal_emit (etc, etc_signals [STRUCTURE_CHANGE], 0);
-}
-
-ETableCol *
-e_table_column_get_column (ETableColumn *etc, int column)
-{
- g_return_val_if_fail (etc != NULL, NULL);
- g_return_val_if_fail (E_IS_TABLE_COLUMN (etc), NULL);
-
- if (column < 0)
- return NULL;
-
- if (column >= etc->col_count)
- return NULL;
-
- return etc->columns [column];
-}
-
-int
-e_table_column_count (ETableColumn *etc)
-{
- g_return_val_if_fail (etc != NULL, 0);
- g_return_val_if_fail (E_IS_TABLE_COLUMN (etc), 0);
-
- return etc->col_count;
-}
-
-int
-e_table_column_index (ETableColumn *etc, const char *identifier)
-{
- int i;
-
- g_return_val_if_fail (etc != NULL, 0);
- g_return_val_if_fail (E_IS_TABLE_COLUMN (etc), 0);
- g_return_val_if_fail (identifier != NULL, 0);
-
- for (i = 0; i < etc->col_count; i++){
- ETableCol *tc = etc->columns [i];
-
- if (strcmp (i->id, identifier) == 0)
- return i;
- }
-
- return -1;
-}
-
-int
-e_table_column_get_index_at (ETableColumn *etc, int x_offset)
-{
- int i, total;
-
- g_return_val_if_fail (etc != NULL, 0);
- g_return_val_if_fail (E_IS_TABLE_COLUMN (etc), 0);
- g_return_val_if_fail (identifier != NULL, 0);
-
- total = 0;
- for (i = 0; i < etc->col_count; i++){
- total += etc->columns [i]->width;
-
- if (x_offset < total)
- return i;
- }
-
- return -1;
-}
-
-ETableCol **
-e_table_column_get_columns (ETableColumn *etc)
-{
- ETableCol **ret;
- int i;
-
- g_return_val_if_fail (etc != NULL, 0);
- g_return_val_if_fail (E_IS_TABLE_COLUMN (etc), 0);
-
- ret = g_new (ETableCol *, etc->col_count + 1);
- memcpy (ret, etc->columns, sizeof (ETableCol *) * etc->col_count);
- ret [etc->col_count] = NULL;
-
- return ret;
-}
-
-gboolean
-e_table_column_selection_ok (ETableColumn *etc)
-{
- g_return_val_if_fail (etc != NULL, FALSE);
- g_return_val_if_fail (E_IS_TABLE_COLUMN (etc), FALSE);
-
- return etc->selectable;
-}
-
-int
-ve_table_column_get_selected (ETableColumn *etc)
-{
- int i;
- int selected = 0;
-
- g_return_val_if_fail (etc != NULL, 0);
- g_return_val_if_fail (E_IS_TABLE_COLUMN (etc), 0);
-
- for (i = 0; i < etc->col_count; i++){
- if (etc->columns [i]->selected)
- selected++;
- }
-
- return selected;
-}
-
-int
-e_table_column_total_width (ETableColumn *etc)
-{
- int total;
-
- g_return_val_if_fail (etc != NULL, 0);
- g_return_val_if_fail (E_IS_TABLE_COLUMN (etc), 0);
-
- total = 0;
- for (i = 0; i < etc->col_count; i++)
- total += etc->columns [i].width;
-
- return total;
-}
-
-static void
-etc_do_remove (ETableColumn *etc, int idx)
-{
- memcpy (&etc->columns [idx], &etc->columns [idx+1],
- sizeof (ETableCol *) * etc->col_count - idx);
- etc->col_count--;
-}
-
-void
-e_table_column_move (ETableColumn *etc, int source_index, int target_index)
-{
- g_return_if_fail (etc != NULL);
- g_return_if_fail (E_IS_TABLE_COLUMN (etc));
- g_return_if_fail (source_index >= 0);
- g_return_if_fail (target_index >= 0);
- g_return_if_fail (source_index < etc->col_count);
- g_return_if_fail (target_index < etc->col_count);
-
- old = etc->columns [source_index];
- etc_do_remove (etc, source_index);
- etc_do_insert (etc, target_index, old);
- g_signal_emit (etc, etc_signals [STRUCTURE_CHANGE], 0);
-}
-
-void
-e_table_column_remove (ETableColumn *etc, int idx)
-{
- g_return_if_fail (etc != NULL);
- g_return_if_fail (E_IS_TABLE_COLUMN (etc));
- g_return_if_fail (idx >= 0);
- g_return_if_fail (idx < etc->col_count);
-
- etc_do_remove (etc, idx);
- g_signal_emit (etc, etc_signals [STRUCTURE_CHANGE], 0);
-}
-
-void
-e_table_column_set_selection (ETableColumn *etc, gboolean allow_selection);
-{
-}
-
-void
-e_table_column_set_size (ETableColumn *etc, int idx, int size)
-{
- g_return_if_fail (etc != NULL);
- g_return_if_fail (E_IS_TABLE_COLUMN (etc));
- g_return_if_fail (idx >= 0);
- g_return_if_fail (idx < etc->col_count);
- g_return_if_fail (size > 0);
-
- etc->columns [idx]->width = size;
- g_signal_emit (etc, etc_signals [SIZE_CHANGE], 0, idx);
-}
diff --git a/widgets/table/e-table-config-field.c b/widgets/table/e-table-config-field.c
deleted file mode 100644
index 7c23e10046..0000000000
--- a/widgets/table/e-table-config-field.c
+++ /dev/null
@@ -1,300 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-config-field.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <stdlib.h>
-#include <gtk/gtk.h>
-#include <gtk/gtkbox.h>
-#include "gal/util/e-util.h"
-#include "gal/util/e-i18n.h"
-#include "e-table-config-field.h"
-
-#define PARENT_TYPE (gtk_vbox_get_type())
-
-static GtkVBoxClass *etcf_parent_class;
-
-static void
-etcf_dispose (GObject *object)
-{
- ETableConfigField *etcf = E_TABLE_CONFIG_FIELD (object);
-
- if (etct->spec)
- g_object_unref (etcf->spec);
- etct->spec = NULL;
-
- if (etct->sort_info)
- g_object_unref (etcf->sort_info);
- etct->sort_info = NULL;
-
- G_OBJECT_CLASS (etcf_parent_class)->dispose (object);
-}
-
-static void
-etcf_class_init (GObjectClass *klass)
-{
- etcf_parent_class = g_type_class_ref (PARENT_TYPE);
-
- klass->dispose = etcf_dispose;
-}
-
-static void
-etcf_init (ETableConfigField *etcf)
-{
- etcf->spec = NULL;
- etcf->sort_info = NULL;
-
- etcf->combo = NULL;
- etcf->radio_ascending = NULL;
- etcf->radio_descending = NULL;
- etcf->child_fields = NULL;
-}
-
-E_MAKE_TYPE(e_table_config_field, "ETableConfigField", ETableConfigField, etcf_class_init, etcf_init, PARENT_TYPE)
-
-ETableConfigField *
-e_table_config_field_new (ETableSpecification *spec,
- ETableSortInfo *sort_info,
- gboolean grouping)
-{
- ETableConfigField *etcf = g_object_new (E_TABLE_CONFIG_FIELD_TYPE, NULL);
-
- e_table_config_field_construct (etcf, spec, sort_info, grouping);
-
- return (ETableConfigField *) etcf;
-}
-
-inline static int
-etcf_get_count (ETableConfigField *etcf)
-{
- if (etcf->grouping)
- return e_table_sort_info_grouping_get_count(etcf->sort_info);
- else
- return e_table_sort_info_sorting_get_count(etcf->sort_info);
-}
-
-inline static ETableSortColumn
-etcf_get_nth (ETableConfigField *etcf)
-{
- if (etcf->grouping)
- return e_table_sort_info_grouping_get_nth(etcf->sort_info, etcf->n);
- else
- return e_table_sort_info_sorting_get_nth(etcf->sort_info, etcf->n);
-}
-
-inline static void
-etcf_set_nth (ETableConfigField *etcf, ETableSortColumn column)
-{
- if (etcf->grouping)
- e_table_sort_info_grouping_set_nth(etcf->sort_info, etcf->n, column);
- else
- e_table_sort_info_sorting_set_nth(etcf->sort_info, etcf->n, column);
-}
-
-inline static void
-etcf_truncate (ETableConfigField *etcf)
-{
- if (etcf->grouping)
- e_table_sort_info_grouping_truncate(etcf->sort_info, etcf->n);
- else
- e_table_sort_info_sorting_truncate(etcf->sort_info, etcf->n);
-}
-
-static void
-etcf_set_sensitivity(ETableConfigField *etcf)
-{
- int count = etcf_get_count(etcf);
-
- if (etcf->n >= count) {
- gtk_widget_set_sensitive(etcf->radio_ascending, FALSE);
- gtk_widget_set_sensitive(etcf->radio_descending, FALSE);
- if (etcf->child_fields)
- gtk_widget_set_sensitive(etcf->child_fields, FALSE);
- } else {
- gtk_widget_set_sensitive(etcf->radio_ascending, TRUE);
- gtk_widget_set_sensitive(etcf->radio_descending, TRUE);
- if (etcf->child_fields)
- gtk_widget_set_sensitive(etcf->child_fields, TRUE);
- }
-}
-
-static void
-toggled(GtkWidget *widget, ETableConfigField *etcf)
-{
- int count;
-
- count = etcf_get_count(etcf);
- if (count > etcf->n) {
- ETableSortColumn sort_column;
-
- sort_column = etcf_get_nth(etcf);
- sort_column.ascending = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(etcf->radio_ascending));
- etcf_set_nth(etcf, sort_column);
- }
-}
-
-static void
-changed(GtkWidget *widget, ETableConfigField *etcf)
-{
- ETableColumnSpecification **column;
- gchar *text;
-
- text = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(etcf->combo)->entry));
- for (column = etcf->spec->columns; *column; column++) {
- if (!strcmp((*column)->title_, text)) {
- ETableSortColumn sort_column;
-
- sort_column.ascending = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(etcf->radio_ascending));
- sort_column.column = (*column)->model_col;
-
- etcf_set_nth(etcf, sort_column);
- etcf_set_sensitivity(etcf);
- return;
- }
- }
- etcf_truncate(etcf);
- etcf_set_sensitivity(etcf);
-}
-
-static void
-etcf_setup(ETableConfigField *etcf)
-{
- int count;
- GList *list = NULL;
- ETableColumnSpecification **column;
- ETableColumnSpecification *chosen_column = NULL;
- int model_col = -1;
-
- etcf_set_sensitivity(etcf);
-
- count = etcf_get_count(etcf);
-
- if (count > etcf->n) {
- ETableSortColumn sort_column;
-
- sort_column = etcf_get_nth(etcf);
- model_col = sort_column.column;
- if (sort_column.ascending)
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(etcf->radio_ascending), TRUE);
- else
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(etcf->radio_descending), TRUE);
- }
-
- for (column = etcf->spec->columns; *column; column++) {
- list = g_list_prepend(list, (*column)->title_);
- if (count > etcf->n && chosen_column == NULL && (*column)->model_col == model_col) {
- chosen_column = *column;
- }
- }
- list = g_list_reverse(list);
- list = g_list_prepend(list, "None");
-
- gtk_combo_set_popdown_strings(GTK_COMBO(etcf->combo), list);
- g_list_free(list);
-
- if (chosen_column) {
- gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(etcf->combo)->entry), chosen_column->title_);
- } else {
- gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(etcf->combo)->entry), "None");
- }
-
- g_signal_connect(GTK_COMBO(etcf->combo)->entry, "changed",
- G_CALLBACK (changed), etcf);
- g_signal_connect(etcf->radio_ascending, "toggled",
- G_CALLBACK (toggled), etcf);
- g_signal_connect(etcf->radio_descending, "toggled",
- G_CALLBACK (toggled), etcf);
-}
-
-static ETableConfigField *
-e_table_config_field_construct_nth (ETableConfigField *etcf,
- ETableSpecification *spec,
- ETableSortInfo *sort_info,
- gboolean grouping,
- int n)
-{
- GtkWidget *frame;
- GtkWidget *internal_hbox;
- GtkWidget *internal_vbox1;
- GtkWidget *internal_vbox2;
-
- etcf->spec = spec;
- g_object_ref (spec);
-
- etcf->sort_info = sort_info;
- g_object_ref (sort_info);
-
- etcf->grouping = grouping;
- etcf->n = n;
-
- gtk_box_set_spacing(GTK_BOX(etcf), 6);
-
- frame = gtk_frame_new(n > 0 ? _("Then By") : (grouping ? _("Group By") : _("Sort By")));
- gtk_box_pack_start(GTK_BOX(etcf), frame, FALSE, FALSE, 0);
-
- internal_hbox = gtk_hbox_new(FALSE, 6);
- gtk_container_add(GTK_CONTAINER(frame), internal_hbox);
- gtk_container_set_border_width(GTK_CONTAINER(internal_hbox), 6);
-
- internal_vbox1 = gtk_vbox_new(FALSE, 6);
- gtk_box_pack_start(GTK_BOX(internal_hbox), internal_vbox1, FALSE, FALSE, 0);
-
- etcf->combo = gtk_combo_new();
- gtk_box_pack_start(GTK_BOX(internal_vbox1), etcf->combo, FALSE, FALSE, 0);
-
- internal_vbox2 = gtk_vbox_new(FALSE, 6);
- gtk_box_pack_start(GTK_BOX(internal_hbox), internal_vbox2, FALSE, FALSE, 0);
-
- etcf->radio_ascending = gtk_radio_button_new_with_label (NULL, _("Ascending"));
- gtk_box_pack_start(GTK_BOX(internal_vbox2), etcf->radio_ascending, FALSE, FALSE, 0);
-
- etcf->radio_descending = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON(etcf->radio_ascending), _("Descending"));
- gtk_box_pack_start(GTK_BOX(internal_vbox2), etcf->radio_descending, FALSE, FALSE, 0);
-
- if (n < 3) {
- etcf->child_fields = GTK_WIDGET(g_object_new (E_TABLE_CONFIG_FIELD_TYPE, NULL));
- e_table_config_field_construct_nth(E_TABLE_CONFIG_FIELD(etcf->child_fields), spec, sort_info, grouping, n + 1);
- gtk_box_pack_start(GTK_BOX(etcf), etcf->child_fields, FALSE, FALSE, 0);
- gtk_widget_show(etcf->child_fields);
- } else
- etcf->child_fields = NULL;
-
- etcf_setup(etcf);
-
- gtk_widget_show(etcf->radio_descending);
- gtk_widget_show(etcf->radio_ascending);
- gtk_widget_show(internal_vbox2);
- gtk_widget_show(etcf->combo);
- gtk_widget_show(internal_vbox1);
- gtk_widget_show(internal_hbox);
- gtk_widget_show(frame);
- return etcf;
-}
-
-ETableConfigField *
-e_table_config_field_construct (ETableConfigField *etcf,
- ETableSpecification *spec,
- ETableSortInfo *sort_info,
- gboolean grouping)
-{
- return e_table_config_field_construct_nth(etcf, spec, sort_info, grouping, 0);
-}
diff --git a/widgets/table/e-table-config-field.h b/widgets/table/e-table-config-field.h
deleted file mode 100644
index bb8f540c4a..0000000000
--- a/widgets/table/e-table-config-field.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-config-field.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_TABLE_CONFIG_FIELD_H_
-#define _E_TABLE_CONFIG_FIELD_H_
-
-#include <gtk/gtkvbox.h>
-#include <gal/e-table/e-table-sort-info.h>
-#include <gal/e-table/e-table-specification.h>
-
-G_BEGIN_DECLS
-
-#define E_TABLE_CONFIG_FIELD_TYPE (e_table_config_field_get_type ())
-#define E_TABLE_CONFIG_FIELD(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TABLE_CONFIG_FIELD_TYPE, ETableConfigField))
-#define E_TABLE_CONFIG_FIELD_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TABLE_CONFIG_FIELD_TYPE, ETableConfigFieldClass))
-#define E_IS_TABLE_CONFIG_FIELD(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TABLE_CONFIG_FIELD_TYPE))
-#define E_IS_TABLE_CONFIG_FIELD_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TABLE_CONFIG_FIELD_TYPE))
-
-typedef struct {
- GtkVBox base;
-
- ETableSpecification *spec;
- ETableSortInfo *sort_info;
- guint grouping : 1;
- int n;
-
- GtkWidget *combo;
- GtkWidget *radio_ascending;
- GtkWidget *radio_descending;
-
- GtkWidget *child_fields;
-} ETableConfigField;
-
-typedef struct {
- GtkVBoxClass parent_class;
-} ETableConfigFieldClass;
-
-GType e_table_config_field_get_type (void);
-ETableConfigField *e_table_config_field_new (ETableSpecification *spec,
- ETableSortInfo *sort_info,
- gboolean grouping);
-ETableConfigField *e_table_config_field_construct (ETableConfigField *field,
- ETableSpecification *spec,
- ETableSortInfo *sort_info,
- gboolean grouping);
-
-G_END_DECLS
-
-#endif /* _E_TABLE_CONFIG_FIELD_H_ */
diff --git a/widgets/table/e-table-config-no-group.glade b/widgets/table/e-table-config-no-group.glade
deleted file mode 100644
index 75473b67f2..0000000000
--- a/widgets/table/e-table-config-no-group.glade
+++ /dev/null
@@ -1,2112 +0,0 @@
-<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
-<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
-
-<glade-interface>
-<requires lib="gnome"/>
-
-<widget class="GtkDialog" id="dialog-show-fields">
- <property name="title" translatable="yes">Show Fields</property>
- <property name="type">GTK_WINDOW_TOPLEVEL</property>
- <property name="window_position">GTK_WIN_POS_NONE</property>
- <property name="modal">False</property>
- <property name="resizable">True</property>
- <property name="destroy_with_parent">False</property>
- <property name="decorated">True</property>
- <property name="skip_taskbar_hint">False</property>
- <property name="skip_pager_hint">False</property>
- <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
- <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
- <property name="has_separator">True</property>
-
- <child internal-child="vbox">
- <widget class="GtkVBox" id="dialog-vbox3">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">8</property>
-
- <child internal-child="action_area">
- <widget class="GtkHButtonBox" id="dialog-action_area3">
- <property name="visible">True</property>
- <property name="layout_style">GTK_BUTTONBOX_END</property>
-
- <child>
- <widget class="GtkButton" id="button22">
- <property name="visible">True</property>
- <property name="can_default">True</property>
- <property name="can_focus">True</property>
- <property name="label">gtk-cancel</property>
- <property name="use_stock">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="response_id">-6</property>
- </widget>
- </child>
-
- <child>
- <widget class="GtkButton" id="button20">
- <property name="visible">True</property>
- <property name="can_default">True</property>
- <property name="can_focus">True</property>
- <property name="label">gtk-ok</property>
- <property name="use_stock">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="response_id">-5</property>
- </widget>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="pack_type">GTK_PACK_END</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkVBox" id="vbox2">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="GtkTable" id="table2">
- <property name="visible">True</property>
- <property name="n_rows">1</property>
- <property name="n_columns">5</property>
- <property name="homogeneous">True</property>
- <property name="row_spacing">6</property>
- <property name="column_spacing">6</property>
-
- <child>
- <widget class="GtkLabel" id="label-available">
- <property name="visible">True</property>
- <property name="label" translatable="yes">A_vailable Fields:</property>
- <property name="use_underline">True</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="left_attach">0</property>
- <property name="right_attach">2</property>
- <property name="top_attach">0</property>
- <property name="bottom_attach">1</property>
- <property name="y_options">fill</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label-displayed">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Sh_ow these fields in order:</property>
- <property name="use_underline">True</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="left_attach">3</property>
- <property name="right_attach">5</property>
- <property name="top_attach">0</property>
- <property name="bottom_attach">1</property>
- <property name="y_options">fill</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkTable" id="table3">
- <property name="visible">True</property>
- <property name="n_rows">1</property>
- <property name="n_columns">5</property>
- <property name="homogeneous">True</property>
- <property name="row_spacing">6</property>
- <property name="column_spacing">6</property>
-
- <child>
- <widget class="GtkVBox" id="vbox4">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="Custom" id="custom-available">
- <property name="visible">True</property>
- <property name="creation_function">e_table_proxy_etable_available_new</property>
- <property name="int1">0</property>
- <property name="int2">0</property>
- <property name="last_modification_time">Thu, 21 Feb 2002 05:42:43 GMT</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="left_attach">0</property>
- <property name="right_attach">2</property>
- <property name="top_attach">0</property>
- <property name="bottom_attach">1</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkVBox" id="vbox5">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="Custom" id="custom-shown">
- <property name="visible">True</property>
- <property name="creation_function">e_table_proxy_etable_shown_new</property>
- <property name="int1">0</property>
- <property name="int2">0</property>
- <property name="last_modification_time">Thu, 21 Feb 2002 15:52:40 GMT</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkHBox" id="hbox4">
- <property name="visible">True</property>
- <property name="homogeneous">True</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="GtkButton" id="button-up">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Move _Up</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkButton" id="button-down">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Move _Down</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="left_attach">3</property>
- <property name="right_attach">5</property>
- <property name="top_attach">0</property>
- <property name="bottom_attach">1</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkVBox" id="vbox6">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="GtkButton" id="button-add">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">_Add -&gt;</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkButton" id="button-remove">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">&lt;- _Remove</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <placeholder/>
- </child>
- </widget>
- <packing>
- <property name="left_attach">2</property>
- <property name="right_attach">3</property>
- <property name="top_attach">0</property>
- <property name="bottom_attach">1</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- </child>
-</widget>
-
-<widget class="GtkDialog" id="dialog-group-by">
- <property name="title" translatable="yes">Group</property>
- <property name="type">GTK_WINDOW_TOPLEVEL</property>
- <property name="window_position">GTK_WIN_POS_NONE</property>
- <property name="modal">False</property>
- <property name="resizable">True</property>
- <property name="destroy_with_parent">False</property>
- <property name="decorated">True</property>
- <property name="skip_taskbar_hint">False</property>
- <property name="skip_pager_hint">False</property>
- <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
- <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
- <property name="has_separator">True</property>
-
- <child internal-child="vbox">
- <widget class="GtkVBox" id="dialog-vbox4">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">8</property>
-
- <child internal-child="action_area">
- <widget class="GtkHButtonBox" id="dialog-action_area4">
- <property name="visible">True</property>
- <property name="layout_style">GTK_BUTTONBOX_END</property>
-
- <child>
- <widget class="GtkButton" id="button39">
- <property name="visible">True</property>
- <property name="can_default">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Clear All</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="response_id">0</property>
- </widget>
- </child>
-
- <child>
- <widget class="GtkButton" id="button42">
- <property name="visible">True</property>
- <property name="can_default">True</property>
- <property name="can_focus">True</property>
- <property name="label">gtk-cancel</property>
- <property name="use_stock">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="response_id">-6</property>
- </widget>
- </child>
-
- <child>
- <widget class="GtkButton" id="button41">
- <property name="visible">True</property>
- <property name="can_default">True</property>
- <property name="can_focus">True</property>
- <property name="label">gtk-ok</property>
- <property name="use_stock">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="response_id">-5</property>
- </widget>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="pack_type">GTK_PACK_END</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkVBox" id="vbox24">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">0</property>
-
- <child>
- <widget class="GtkHBox" id="hbox13">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="GtkFrame" id="frame-group-1">
- <property name="visible">True</property>
- <property name="label_xalign">0</property>
- <property name="label_yalign">0.5</property>
- <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
-
- <child>
- <widget class="GtkHBox" id="hbox5">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="GtkVBox" id="vbox7">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">0</property>
-
- <child>
- <widget class="Custom" id="group-combo-1">
- <property name="visible">True</property>
- <property name="creation_function">e_table_proxy_gtk_combo_text_new</property>
- <property name="int1">0</property>
- <property name="int2">0</property>
- <property name="last_modification_time">Fri, 19 Jan 2001 04:52:09 GMT</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkCheckButton" id="checkbutton-group-1">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Show field in View</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkVBox" id="vbox8">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">0</property>
-
- <child>
- <widget class="GtkRadioButton" id="radiobutton-ascending-group-1">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Ascending</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkRadioButton" id="radiobutton-descending-group-1">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Descending</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- <property name="group">radiobutton-ascending-group-1</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label1">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Group Items By</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="type">label_item</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label8">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_CENTER</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label9">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_CENTER</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label10">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_CENTER</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkHBox" id="hbox14">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="GtkLabel" id="label11">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_CENTER</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkFrame" id="frame-group-2">
- <property name="visible">True</property>
- <property name="label_xalign">0</property>
- <property name="label_yalign">0.5</property>
- <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
-
- <child>
- <widget class="GtkHBox" id="hbox6">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="GtkVBox" id="vbox9">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">0</property>
-
- <child>
- <widget class="Custom" id="group-combo-2">
- <property name="visible">True</property>
- <property name="creation_function">e_table_proxy_gtk_combo_text_new</property>
- <property name="int1">0</property>
- <property name="int2">0</property>
- <property name="last_modification_time">Fri, 19 Jan 2001 04:52:14 GMT</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkCheckButton" id="checkbutton-group-2">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Show field in View</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkVBox" id="vbox10">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">0</property>
-
- <child>
- <widget class="GtkRadioButton" id="radiobutton-ascending-group-2">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Ascending</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkRadioButton" id="radiobutton-descending-group-2">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Descending</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- <property name="group">radiobutton-ascending-group-2</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label12">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Then By</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="type">label_item</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label19">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_CENTER</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label18">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_CENTER</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkHBox" id="hbox15">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="GtkLabel" id="label13">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_CENTER</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label12">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_CENTER</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkFrame" id="frame-group-3">
- <property name="visible">True</property>
- <property name="label_xalign">0</property>
- <property name="label_yalign">0.5</property>
- <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
-
- <child>
- <widget class="GtkHBox" id="hbox7">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="GtkVBox" id="vbox11">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">0</property>
-
- <child>
- <widget class="Custom" id="group-combo-3">
- <property name="visible">True</property>
- <property name="creation_function">e_table_proxy_gtk_combo_text_new</property>
- <property name="int1">0</property>
- <property name="int2">0</property>
- <property name="last_modification_time">Fri, 19 Jan 2001 04:52:18 GMT</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkCheckButton" id="checkbutton-group-3">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Show field in View</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkVBox" id="vbox12">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">0</property>
-
- <child>
- <widget class="GtkRadioButton" id="radiobutton-ascending-group-3">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Ascending</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkRadioButton" id="radiobutton-descending-group-3">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Descending</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- <property name="group">radiobutton-ascending-group-3</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label20">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Then By</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="type">label_item</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label17">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_CENTER</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkHBox" id="hbox16">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="GtkLabel" id="label14">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_CENTER</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label16">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_CENTER</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label15">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_CENTER</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkFrame" id="frame-group-4">
- <property name="visible">True</property>
- <property name="label_xalign">0</property>
- <property name="label_yalign">0.5</property>
- <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
-
- <child>
- <widget class="GtkHBox" id="hbox8">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="GtkVBox" id="vbox13">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">0</property>
-
- <child>
- <widget class="Custom" id="group-combo-4">
- <property name="visible">True</property>
- <property name="creation_function">e_table_proxy_gtk_combo_text_new</property>
- <property name="int1">0</property>
- <property name="int2">0</property>
- <property name="last_modification_time">Fri, 19 Jan 2001 04:52:21 GMT</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkCheckButton" id="checkbutton-group-4">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Show field in View</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkVBox" id="vbox14">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">0</property>
-
- <child>
- <widget class="GtkRadioButton" id="radiobutton-ascending-group-4">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Ascending</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkRadioButton" id="radiobutton-descending-group-4">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Descending</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- <property name="group">radiobutton-ascending-group-4</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label21">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Then By</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="type">label_item</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- </child>
-</widget>
-
-<widget class="GtkDialog" id="dialog-sort">
- <property name="title" translatable="yes">Sort</property>
- <property name="type">GTK_WINDOW_TOPLEVEL</property>
- <property name="window_position">GTK_WIN_POS_NONE</property>
- <property name="modal">False</property>
- <property name="resizable">True</property>
- <property name="destroy_with_parent">False</property>
- <property name="decorated">True</property>
- <property name="skip_taskbar_hint">False</property>
- <property name="skip_pager_hint">False</property>
- <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
- <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
- <property name="has_separator">True</property>
-
- <child internal-child="vbox">
- <widget class="GtkVBox" id="vbox15">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">8</property>
-
- <child internal-child="action_area">
- <widget class="GtkHButtonBox" id="hbuttonbox1">
- <property name="visible">True</property>
- <property name="layout_style">GTK_BUTTONBOX_END</property>
-
- <child>
- <widget class="GtkButton" id="button43">
- <property name="visible">True</property>
- <property name="can_default">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Clear All</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="response_id">0</property>
- </widget>
- </child>
-
- <child>
- <widget class="GtkButton" id="button45">
- <property name="visible">True</property>
- <property name="can_default">True</property>
- <property name="can_focus">True</property>
- <property name="label">gtk-cancel</property>
- <property name="use_stock">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="response_id">-6</property>
- </widget>
- </child>
-
- <child>
- <widget class="GtkButton" id="button44">
- <property name="visible">True</property>
- <property name="can_default">True</property>
- <property name="has_default">True</property>
- <property name="can_focus">True</property>
- <property name="label">gtk-ok</property>
- <property name="use_stock">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="response_id">-5</property>
- </widget>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="pack_type">GTK_PACK_END</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkTable" id="table5">
- <property name="visible">True</property>
- <property name="n_rows">4</property>
- <property name="n_columns">1</property>
- <property name="homogeneous">False</property>
- <property name="row_spacing">6</property>
- <property name="column_spacing">6</property>
-
- <child>
- <widget class="GtkFrame" id="frame-sort-4">
- <property name="visible">True</property>
- <property name="label_xalign">0</property>
- <property name="label_yalign">0.5</property>
- <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
-
- <child>
- <widget class="GtkHBox" id="hbox9">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="GtkAlignment" id="alignment1">
- <property name="visible">True</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xscale">1</property>
- <property name="yscale">0</property>
- <property name="top_padding">0</property>
- <property name="bottom_padding">0</property>
- <property name="left_padding">0</property>
- <property name="right_padding">0</property>
-
- <child>
- <widget class="Custom" id="sort-combo-4">
- <property name="visible">True</property>
- <property name="creation_function">e_table_proxy_gtk_combo_text_new</property>
- <property name="int1">0</property>
- <property name="int2">0</property>
- <property name="last_modification_time">Tue, 16 Jan 2001 08:33:52 GMT</property>
- </widget>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkVBox" id="vbox17">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">0</property>
-
- <child>
- <widget class="GtkRadioButton" id="radiobutton-ascending-sort-4">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Ascending</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkRadioButton" id="radiobutton-descending-sort-4">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Descending</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- <property name="group">radiobutton-ascending-sort-4</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label22">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Then By</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="type">label_item</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="left_attach">0</property>
- <property name="right_attach">1</property>
- <property name="top_attach">3</property>
- <property name="bottom_attach">4</property>
- <property name="y_options">fill</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkFrame" id="frame-sort-3">
- <property name="visible">True</property>
- <property name="label_xalign">0</property>
- <property name="label_yalign">0.5</property>
- <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
-
- <child>
- <widget class="GtkHBox" id="hbox10">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="GtkAlignment" id="alignment2">
- <property name="visible">True</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xscale">1</property>
- <property name="yscale">0</property>
- <property name="top_padding">0</property>
- <property name="bottom_padding">0</property>
- <property name="left_padding">0</property>
- <property name="right_padding">0</property>
-
- <child>
- <widget class="Custom" id="sort-combo-3">
- <property name="visible">True</property>
- <property name="creation_function">e_table_proxy_gtk_combo_text_new</property>
- <property name="int1">0</property>
- <property name="int2">0</property>
- <property name="last_modification_time">Tue, 16 Jan 2001 05:22:22 GMT</property>
- </widget>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkVBox" id="vbox19">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">0</property>
-
- <child>
- <widget class="GtkRadioButton" id="radiobutton-ascending-sort-3">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Ascending</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkRadioButton" id="radiobutton-descending-sort-3">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Descending</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- <property name="group">radiobutton-ascending-sort-3</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label23">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Then By</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="type">label_item</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="left_attach">0</property>
- <property name="right_attach">1</property>
- <property name="top_attach">2</property>
- <property name="bottom_attach">3</property>
- <property name="y_options">fill</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkFrame" id="frame-sort-2">
- <property name="visible">True</property>
- <property name="label_xalign">0</property>
- <property name="label_yalign">0.5</property>
- <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
-
- <child>
- <widget class="GtkHBox" id="hbox11">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="GtkAlignment" id="alignment3">
- <property name="visible">True</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xscale">1</property>
- <property name="yscale">0</property>
- <property name="top_padding">0</property>
- <property name="bottom_padding">0</property>
- <property name="left_padding">0</property>
- <property name="right_padding">0</property>
-
- <child>
- <widget class="Custom" id="sort-combo-2">
- <property name="visible">True</property>
- <property name="creation_function">e_table_proxy_gtk_combo_text_new</property>
- <property name="int1">0</property>
- <property name="int2">0</property>
- <property name="last_modification_time">Tue, 16 Jan 2001 05:22:15 GMT</property>
- </widget>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkVBox" id="vbox21">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">0</property>
-
- <child>
- <widget class="GtkRadioButton" id="radiobutton-ascending-sort-2">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Ascending</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkRadioButton" id="radiobutton-descending-sort-2">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Descending</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- <property name="group">radiobutton-ascending-sort-2</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label24">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Then By</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="type">label_item</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="left_attach">0</property>
- <property name="right_attach">1</property>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
- <property name="y_options">fill</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkFrame" id="frame-sort-1">
- <property name="visible">True</property>
- <property name="label_xalign">0</property>
- <property name="label_yalign">0.5</property>
- <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
-
- <child>
- <widget class="GtkHBox" id="hbox12">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="GtkAlignment" id="alignment4">
- <property name="visible">True</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xscale">1</property>
- <property name="yscale">0</property>
- <property name="top_padding">0</property>
- <property name="bottom_padding">0</property>
- <property name="left_padding">0</property>
- <property name="right_padding">0</property>
-
- <child>
- <widget class="Custom" id="sort-combo-1">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="has_focus">True</property>
- <property name="creation_function">e_table_proxy_gtk_combo_text_new</property>
- <property name="int1">0</property>
- <property name="int2">0</property>
- <property name="last_modification_time">Tue, 16 Jan 2001 05:22:00 GMT</property>
- </widget>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkVBox" id="vbox23">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">0</property>
-
- <child>
- <widget class="GtkRadioButton" id="radiobutton-ascending-sort-1">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Ascending</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkRadioButton" id="radiobutton-descending-sort-1">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Descending</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- <property name="group">radiobutton-ascending-sort-1</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label25">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Sort Items By</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="type">label_item</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="left_attach">0</property>
- <property name="right_attach">1</property>
- <property name="top_attach">0</property>
- <property name="bottom_attach">1</property>
- <property name="y_options">fill</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- </child>
-</widget>
-
-<widget class="GtkDialog" id="e-table-config">
- <property name="title" translatable="yes">dialog1</property>
- <property name="type">GTK_WINDOW_TOPLEVEL</property>
- <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
- <property name="modal">True</property>
- <property name="resizable">False</property>
- <property name="destroy_with_parent">False</property>
- <property name="decorated">True</property>
- <property name="skip_taskbar_hint">False</property>
- <property name="skip_pager_hint">False</property>
- <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
- <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
- <property name="has_separator">True</property>
-
- <child internal-child="vbox">
- <widget class="GtkVBox" id="dialog-vbox5">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">0</property>
-
- <child internal-child="action_area">
- <widget class="GtkHButtonBox" id="dialog-action_area5">
- <property name="visible">True</property>
- <property name="layout_style">GTK_BUTTONBOX_END</property>
-
- <child>
- <widget class="GtkButton" id="cancelbutton1">
- <property name="visible">True</property>
- <property name="can_default">True</property>
- <property name="can_focus">True</property>
- <property name="label">gtk-cancel</property>
- <property name="use_stock">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="response_id">-6</property>
- </widget>
- </child>
-
- <child>
- <widget class="GtkButton" id="applybutton1">
- <property name="visible">True</property>
- <property name="can_default">True</property>
- <property name="can_focus">True</property>
- <property name="label">gtk-apply</property>
- <property name="use_stock">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="response_id">-10</property>
- </widget>
- </child>
-
- <child>
- <widget class="GtkButton" id="okbutton1">
- <property name="visible">True</property>
- <property name="can_default">True</property>
- <property name="can_focus">True</property>
- <property name="label">gtk-ok</property>
- <property name="use_stock">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="response_id">-5</property>
- </widget>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="pack_type">GTK_PACK_END</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkFrame" id="top-frame">
- <property name="border_width">2</property>
- <property name="visible">True</property>
- <property name="label_xalign">0</property>
- <property name="label_yalign">0.5</property>
- <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
-
- <child>
- <widget class="GtkTable" id="table1">
- <property name="border_width">2</property>
- <property name="visible">True</property>
- <property name="n_rows">2</property>
- <property name="n_columns">3</property>
- <property name="homogeneous">False</property>
- <property name="row_spacing">2</property>
- <property name="column_spacing">4</property>
-
- <child>
- <widget class="GtkButton" id="button-sort">
- <property name="visible">True</property>
- <property name="can_default">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">_Sort...</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <signal name="clicked" handler="on_sort_clicked"/>
- </widget>
- <packing>
- <property name="left_attach">0</property>
- <property name="right_attach">1</property>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
- <property name="x_options">fill</property>
- <property name="y_options"></property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label-sort">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">True</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="left_attach">1</property>
- <property name="right_attach">2</property>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
- <property name="y_options">fill</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label4">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_CENTER</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="left_attach">2</property>
- <property name="right_attach">3</property>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
- <property name="x_options">fill</property>
- <property name="y_options">fill</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label21">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_CENTER</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="left_attach">2</property>
- <property name="right_attach">3</property>
- <property name="top_attach">0</property>
- <property name="bottom_attach">1</property>
- <property name="x_options">fill</property>
- <property name="y_options">fill</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label-fields">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">True</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="left_attach">1</property>
- <property name="right_attach">2</property>
- <property name="top_attach">0</property>
- <property name="bottom_attach">1</property>
- <property name="y_options">fill</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkButton" id="button-fields">
- <property name="visible">True</property>
- <property name="can_default">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">_Fields Shown...</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <signal name="clicked" handler="on_sort_clicked"/>
- </widget>
- <packing>
- <property name="left_attach">0</property>
- <property name="right_attach">1</property>
- <property name="top_attach">0</property>
- <property name="bottom_attach">1</property>
- <property name="x_options">fill</property>
- <property name="y_options"></property>
- </packing>
- </child>
- </widget>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label26">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Description</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="type">label_item</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- </child>
-</widget>
-
-</glade-interface>
diff --git a/widgets/table/e-table-config.c b/widgets/table/e-table-config.c
deleted file mode 100644
index 4e40c150fd..0000000000
--- a/widgets/table/e-table-config.c
+++ /dev/null
@@ -1,1225 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-config.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- * Miguel de Icaza <miguel@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-/*
- * FIXME:
- * Sort Dialog: when text is selected, the toggle button switches state.
- * Make Clear all work.
- */
-
-#include <config.h>
-
-#include "e-table-config.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <gtk/gtkdialog.h>
-#include <gtk/gtkentry.h>
-#include <gtk/gtklabel.h>
-#include <gtk/gtktogglebutton.h>
-#include <libgnomeui/gnome-propertybox.h>
-#include <glade/glade.h>
-#include "gal/util/e-util.h"
-#include "gal/util/e-i18n.h"
-#include "gal/widgets/e-unicode.h"
-
-#include <e-table-scrolled.h>
-#include <e-table-without.h>
-#include <e-table-memory-store.h>
-
-
-static GObjectClass *config_parent_class;
-
-enum {
- CHANGED,
- LAST_SIGNAL
-};
-
-enum {
- PROP_0,
- PROP_STATE,
-};
-
-static guint e_table_config_signals [LAST_SIGNAL] = { 0, };
-
-static void
-config_finalize (GObject *object)
-{
- ETableConfig *config = E_TABLE_CONFIG (object);
-
- if (config->state)
- g_object_unref (config->state);
- config->state = NULL;
-
- if (config->source_state)
- g_object_unref (config->source_state);
- config->source_state = NULL;
-
- if (config->source_spec)
- g_object_unref (config->source_spec);
- config->source_spec = NULL;
-
- g_free (config->header);
- config->header = NULL;
-
- g_slist_free (config->column_names);
- config->column_names = NULL;
-
- g_free (config->domain);
- config->domain = NULL;
-
- config_parent_class->finalize (object);
-}
-
-static void
-e_table_config_changed (ETableConfig *config, ETableState *state)
-{
- g_return_if_fail (E_IS_TABLE_CONFIG (config));
-
- g_signal_emit(G_OBJECT(config), e_table_config_signals [CHANGED], 0, state);
-}
-
-static void
-config_dialog_changed (ETableConfig *config)
-{
- /* enable the apply/ok buttons */
- gtk_dialog_set_response_sensitive (GTK_DIALOG (config->dialog_toplevel),
- GTK_RESPONSE_APPLY, TRUE);
- gtk_dialog_set_response_sensitive (GTK_DIALOG (config->dialog_toplevel),
- GTK_RESPONSE_OK, TRUE);
-}
-
-static void
-config_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- ETableConfig *config = E_TABLE_CONFIG (object);
-
- switch (prop_id) {
- case PROP_STATE:
- g_value_set_object (value, config->state);
- break;
- default:
- break;
- }
-}
-
-static void
-config_class_init (GObjectClass *object_class)
-{
- ETableConfigClass *klass = E_TABLE_CONFIG_CLASS(object_class);
-
- config_parent_class = g_type_class_peek_parent (klass);
-
- klass->changed = NULL;
-
- object_class->finalize = config_finalize;
- object_class->get_property = config_get_property;
-
- e_table_config_signals [CHANGED] =
- g_signal_new ("changed",
- E_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableConfigClass, changed),
- (GSignalAccumulator) NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
-
- g_object_class_install_property (object_class, PROP_STATE,
- g_param_spec_object ("state",
- _("State"),
- /*_( */"XXX blurb" /*)*/,
- E_TABLE_STATE_TYPE,
- G_PARAM_READABLE));
-
- glade_init ();
-}
-
-static ETableColumnSpecification *
-find_column_in_spec (ETableSpecification *spec, int model_col)
-{
- ETableColumnSpecification **column;
-
- for (column = spec->columns; *column; column++){
- if ((*column)->disabled)
- continue;
- if ((*column)->model_col != model_col)
- continue;
-
- return *column;
- }
-
- return NULL;
-}
-
-static int
-find_model_column_by_name (ETableSpecification *spec, const char *s)
-{
- ETableColumnSpecification **column;
-
- for (column = spec->columns; *column; column++){
-
- if ((*column)->disabled)
- continue;
- if (g_strcasecmp ((*column)->title, s) == 0)
- return (*column)->model_col;
- }
- return -1;
-}
-
-static void
-update_sort_and_group_config_dialog (ETableConfig *config, gboolean is_sort)
-{
- ETableConfigSortWidgets *widgets;
- int count, i;
-
- if (is_sort){
- count = e_table_sort_info_sorting_get_count (
- config->temp_state->sort_info);
- widgets = &config->sort [0];
- } else {
- count = e_table_sort_info_grouping_get_count (
- config->temp_state->sort_info);
- widgets = &config->group [0];
- }
-
- for (i = 0; i < 4; i++){
- gboolean sensitive = (i <= count);
- char *text = "";
-
- gtk_widget_set_sensitive (widgets [i].frames, sensitive);
-
- /*
- * Sorting is set, auto select the text
- */
- g_signal_handler_block (
- widgets [i].radio_ascending,
- widgets [i].toggled_id);
- g_signal_handler_block (
- widgets [i].combo->entry,
- widgets [i].changed_id);
-
- if (i < count){
- GtkToggleButton *a, *d;
- ETableSortColumn col =
- is_sort
- ? e_table_sort_info_sorting_get_nth (
- config->temp_state->sort_info,
- i)
- : e_table_sort_info_grouping_get_nth (
- config->temp_state->sort_info,
- i);
-
- ETableColumnSpecification *column =
- find_column_in_spec (config->source_spec, col.column);
-
- if (!column){
- /*
- * This is a bug in the programmer
- * stuff, but by the time we arrive
- * here, the user has been given a
- * warning
- */
- continue;
- }
-
- text = dgettext (config->domain, column->title);
-
- /*
- * Update radio buttons
- */
- a = GTK_TOGGLE_BUTTON (
- widgets [i].radio_ascending);
- d = GTK_TOGGLE_BUTTON (
- widgets [i].radio_descending);
-
- gtk_toggle_button_set_active (col.ascending ? a:d, 1);
- } else {
- GtkToggleButton *t;
-
- t = GTK_TOGGLE_BUTTON (
- widgets [i].radio_ascending);
-
- if (is_sort)
- g_assert (widgets [i].radio_ascending != config->group [i].radio_ascending);
- else
- g_assert (widgets [i].radio_ascending != config->sort [i].radio_ascending);
- gtk_toggle_button_set_active (t, 1);
- }
-
- /* Set the text */
- gal_combo_text_set_text (widgets [i].combo, text);
-
- g_signal_handler_unblock (
- widgets [i].radio_ascending,
- widgets [i].toggled_id);
- g_signal_handler_unblock (
- widgets [i].combo->entry,
- widgets [i].changed_id);
- }
-}
-
-static void
-config_sort_info_update (ETableConfig *config)
-{
- ETableSortInfo *info = config->state->sort_info;
- GString *res;
- int count, i;
-
- count = e_table_sort_info_sorting_get_count (info);
- res = g_string_new ("");
-
- for (i = 0; i < count; i++) {
- ETableSortColumn col = e_table_sort_info_sorting_get_nth (info, i);
- ETableColumnSpecification *column;
-
- column = find_column_in_spec (config->source_spec, col.column);
- if (!column){
- g_warning ("Could not find column model in specification");
- continue;
- }
-
- g_string_append (res, dgettext (config->domain, (column)->title));
- g_string_append_c (res, ' ');
- g_string_append (
- res,
- col.ascending ?
- _("(Ascending)") : _("(Descending)"));
-
- if ((i + 1) != count)
- g_string_append (res, ", ");
- }
-
- if (res->str [0] == 0)
- g_string_append (res, _("Not sorted"));
-
- gtk_label_set_text (GTK_LABEL(config->sort_label), res->str);
-
- g_string_free (res, TRUE);
-}
-
-static void
-config_group_info_update (ETableConfig *config)
-{
- ETableSortInfo *info = config->state->sort_info;
- GString *res;
- int count, i;
-
- if (!e_table_sort_info_get_can_group (info))
- return;
-
- count = e_table_sort_info_grouping_get_count (info);
- res = g_string_new ("");
-
- for (i = 0; i < count; i++) {
- ETableSortColumn col = e_table_sort_info_grouping_get_nth (info, i);
- ETableColumnSpecification *column;
-
- column = find_column_in_spec (config->source_spec, col.column);
- if (!column){
- g_warning ("Could not find model column in specification");
- continue;
- }
-
- g_string_append (res, dgettext (config->domain, (column)->title));
- g_string_append_c (res, ' ');
- g_string_append (
- res,
- col.ascending ?
- _("(Ascending)") : _("(Descending)"));
-
- if ((i+1) != count)
- g_string_append (res, ", ");
- }
- if (res->str [0] == 0)
- g_string_append (res, _("No grouping"));
-
- gtk_label_set_text (GTK_LABEL (config->group_label), res->str);
- g_string_free (res, TRUE);
-}
-
-static void
-setup_fields (ETableConfig *config)
-{
- int i;
-
- e_table_model_freeze (config->available_model);
- e_table_model_freeze (config->shown_model);
- e_table_without_show_all (config->available_model);
- e_table_subset_variable_clear (config->shown_model);
-
- if (config->temp_state) {
- for (i = 0; i < config->temp_state->col_count; i++) {
- gint j, idx;
- for (j = 0, idx = 0; j < config->temp_state->columns[i]; j++)
- if (!config->source_spec->columns[j]->disabled)
- idx++;
-
- e_table_subset_variable_add (config->shown_model, idx);
- e_table_without_hide (config->available_model, GINT_TO_POINTER(idx));
- }
- }
- e_table_model_thaw (config->available_model);
- e_table_model_thaw (config->shown_model);
-}
-
-static void
-config_fields_info_update (ETableConfig *config)
-{
- ETableColumnSpecification **column;
- GString *res = g_string_new ("");
- int i;
-
- for (i = 0; i < config->state->col_count; i++){
- for (column = config->source_spec->columns; *column; column++){
-
- if ((*column)->disabled)
- continue;
-
- if (config->state->columns [i] != (*column)->model_col)
- continue;
-
- g_string_append (res, dgettext (config->domain, (*column)->title));
- if (column [1])
- g_string_append (res, ", ");
- }
- }
-
- gtk_label_set_text (GTK_LABEL (config->fields_label), res->str);
- g_string_free (res, TRUE);
-}
-
-static void
-do_sort_and_group_config_dialog (ETableConfig *config, gboolean is_sort)
-{
- GtkDialog *dialog;
- int response, running = 1;
-
- config->temp_state = e_table_state_duplicate (config->state);
-
- update_sort_and_group_config_dialog (config, is_sort);
-
- gtk_widget_grab_focus (GTK_WIDGET (
- is_sort
- ? config->sort [0].combo
- : config->group [0].combo));
-
-
- if (is_sort)
- dialog = GTK_DIALOG (config->dialog_sort);
- else
- dialog = GTK_DIALOG (config->dialog_group_by);
-
- gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (config->dialog_toplevel));
-
- do {
- response = gtk_dialog_run (dialog);
- switch (response){
- case 0: /* clear fields */
- if (is_sort){
- e_table_sort_info_sorting_truncate (
- config->temp_state->sort_info, 0);
- } else {
- e_table_sort_info_grouping_truncate (
- config->temp_state->sort_info, 0);
- }
- update_sort_and_group_config_dialog (config, is_sort);
- break;
-
- case GTK_RESPONSE_OK:
- g_object_unref (config->state);
- config->state = config->temp_state;
- config->temp_state = 0;
- running = 0;
- config_dialog_changed (config);
- break;
-
- case GTK_RESPONSE_DELETE_EVENT:
- case GTK_RESPONSE_CANCEL:
- g_object_unref (config->temp_state);
- config->temp_state = 0;
- running = 0;
- break;
- }
-
- } while (running);
- gtk_widget_hide (GTK_WIDGET (dialog));
-
- if (is_sort)
- config_sort_info_update (config);
- else
- config_group_info_update (config);
-}
-
-static void
-do_fields_config_dialog (ETableConfig *config)
-{
- int response, running = 1;
-
- gtk_widget_ensure_style (config->dialog_show_fields);
- gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (config->dialog_show_fields)->vbox), 0);
- gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (config->dialog_show_fields)->action_area), 12);
-
- config->temp_state = e_table_state_duplicate (config->state);
-
- setup_fields (config);
-
- gtk_window_set_transient_for (GTK_WINDOW (config->dialog_show_fields),
- GTK_WINDOW (config->dialog_toplevel));
-
- do {
- response = gtk_dialog_run (GTK_DIALOG(config->dialog_show_fields));
- switch (response){
- case GTK_RESPONSE_OK:
- g_object_unref (config->state);
- config->state = config->temp_state;
- config->temp_state = 0;
- running = 0;
- config_dialog_changed (config);
- break;
-
- case GTK_RESPONSE_DELETE_EVENT:
- case GTK_RESPONSE_CANCEL:
- g_object_unref (config->temp_state);
- config->temp_state = 0;
- running = 0;
- break;
- }
-
- } while (running);
- gtk_widget_hide (GTK_WIDGET (config->dialog_show_fields));
-
- config_fields_info_update (config);
-}
-
-
-ETableMemoryStoreColumnInfo store_columns[] = {
- E_TABLE_MEMORY_STORE_STRING,
- E_TABLE_MEMORY_STORE_INTEGER,
- E_TABLE_MEMORY_STORE_TERMINATOR
-};
-
-static ETableModel *global_store; /* Glade better not be reentrant any time soon. */
-
-static void
-create_global_store (ETableConfig *config)
-{
- int i;
-
- global_store = e_table_memory_store_new (store_columns);
- for (i = 0; config->source_spec->columns[i]; i++) {
-
- char *text;
-
- if (config->source_spec->columns[i]->disabled)
- continue;
-
- text = g_strdup (dgettext (config->domain, config->source_spec->columns[i]->title));
- e_table_memory_store_insert_adopt (E_TABLE_MEMORY_STORE (global_store), -1, NULL, text, i);
- }
-}
-
-char *spec = "<ETableSpecification gettext-domain=\"" E_I18N_DOMAIN "\" no-headers=\"true\" cursor-mode=\"line\" "
- " draw-grid=\"false\" draw-focus=\"true\" selection-mode=\"browse\">"
- "<ETableColumn model_col= \"0\" _title=\"Name\" minimum_width=\"30\" resizable=\"true\" cell=\"string\" compare=\"string\"/>"
- "<ETableState> <column source=\"0\"/>"
- "<grouping/>"
- "</ETableState>"
- "</ETableSpecification>";
-
-GtkWidget *e_table_proxy_etable_shown_new (void);
-
-GtkWidget *
-e_table_proxy_etable_shown_new (void)
-{
- ETableModel *model = NULL;
-
- model = e_table_subset_variable_new (global_store);
-
- return e_table_scrolled_new (model, NULL, spec, NULL);
-}
-
-GtkWidget *e_table_proxy_etable_available_new (void);
-
-GtkWidget *
-e_table_proxy_etable_available_new (void)
-{
- ETableModel *model;
-
- model = e_table_without_new (global_store,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL);
-
- e_table_without_show_all (E_TABLE_WITHOUT (model));
-
- return e_table_scrolled_new (model, NULL, spec, NULL);
-}
-
-static void
-config_button_fields (GtkWidget *widget, ETableConfig *config)
-{
- do_fields_config_dialog (config);
-}
-
-static void
-config_button_sort (GtkWidget *widget, ETableConfig *config)
-{
- do_sort_and_group_config_dialog (config, TRUE);
-}
-
-static void
-config_button_group (GtkWidget *widget, ETableConfig *config)
-{
- do_sort_and_group_config_dialog (config, FALSE);
-}
-
-static void
-dialog_destroyed (gpointer data, GObject *where_object_was)
-{
- ETableConfig *config = data;
- g_object_unref (config);
-}
-
-static void
-dialog_response (GtkWidget *dialog, int response_id, ETableConfig *config)
-{
- if (response_id == GTK_RESPONSE_APPLY
- || response_id == GTK_RESPONSE_OK) {
- e_table_config_changed (config, config->state);
- }
-
- if (response_id == GTK_RESPONSE_CANCEL
- || response_id == GTK_RESPONSE_OK) {
- gtk_widget_destroy (dialog);
- }
-}
-
-/*
- * Invoked by the Glade auto-connect code
- */
-GtkWidget *e_table_proxy_gtk_combo_text_new (void);
-GtkWidget *
-e_table_proxy_gtk_combo_text_new (void)
-{
- return gal_combo_text_new (TRUE);
-}
-
-#if 0
-static GtkWidget *
-configure_dialog (GladeXML *gui, const char *widget_name, ETableConfig *config)
-{
- GtkWidget *w;
-
- w = glade_xml_get_widget (gui, widget_name);
-
- return w;
-}
-#endif
-
-static void
-connect_button (ETableConfig *config, GladeXML *gui, const char *widget_name, GCallback cback)
-{
- GtkWidget *button = glade_xml_get_widget (gui, widget_name);
-
- if (button) {
- g_signal_connect (G_OBJECT (button), "clicked",
- cback, config);
- }
-}
-
-static gint
-get_source_model_col_index (ETableConfig *config, gint idx)
-{
- gint visible_index;
- ETableModel *src_model = E_TABLE_SUBSET (config->available_model)->source;
-
- visible_index = e_table_subset_view_to_model_row (E_TABLE_SUBSET (config->available_model), idx);
-
- return GPOINTER_TO_INT (e_table_model_value_at (src_model, 1, visible_index));
-}
-
-static void
-sort_entry_changed (GtkEntry *entry, ETableConfigSortWidgets *sort)
-{
- ETableConfig *config = sort->e_table_config;
- ETableSortInfo *sort_info = config->temp_state->sort_info;
- ETableConfigSortWidgets *base = &config->sort[0];
- int idx = sort - base;
-
- const char *s = gtk_entry_get_text (entry);
-
- if (s && s [0] && g_hash_table_lookup (sort->combo->elements, s)){
- ETableSortColumn c;
- int col;
-
- col = find_model_column_by_name (config->source_spec, s);
- if (col == -1){
- g_warning ("sort: This should not happen (%s)", s);
- return;
- }
-
- c.ascending = GTK_TOGGLE_BUTTON (
- config->sort [idx].radio_ascending)->active;
- c.column = col;
- e_table_sort_info_sorting_set_nth (sort_info, idx, c);
-
- update_sort_and_group_config_dialog (config, TRUE);
- } else {
- e_table_sort_info_sorting_truncate (sort_info, idx);
- update_sort_and_group_config_dialog (config, TRUE);
- }
-}
-
-static void
-sort_ascending_toggled (GtkToggleButton *t, ETableConfigSortWidgets *sort)
-{
- ETableConfig *config = sort->e_table_config;
- ETableSortInfo *si = config->temp_state->sort_info;
- ETableConfigSortWidgets *base = &config->sort[0];
- int idx = sort - base;
- ETableSortColumn c;
-
- c = e_table_sort_info_sorting_get_nth (si, idx);
- c.ascending = t->active;
- e_table_sort_info_sorting_set_nth (si, idx, c);
-}
-
-static void
-configure_sort_dialog (ETableConfig *config, GladeXML *gui)
-{
- GSList *l;
- int i;
-
- for (i = 0; i < 4; i++){
- char buffer [80];
-
- snprintf (buffer, sizeof (buffer), "sort-combo-%d", i + 1);
- config->sort [i].combo = GAL_COMBO_TEXT (
- glade_xml_get_widget (gui, buffer));
- gtk_widget_show (GTK_WIDGET (config->sort [i].combo));
- gal_combo_text_add_item (config->sort [i].combo, "", "");
-
- snprintf (buffer, sizeof (buffer), "frame-sort-%d", i + 1);
- config->sort [i].frames =
- glade_xml_get_widget (gui, buffer);
-
- snprintf (
- buffer, sizeof (buffer),
- "radiobutton-ascending-sort-%d", i+1);
- config->sort [i].radio_ascending = glade_xml_get_widget (
- gui, buffer);
-
- snprintf (
- buffer, sizeof (buffer),
- "radiobutton-descending-sort-%d", i+1);
- config->sort [i].radio_descending = glade_xml_get_widget (
- gui, buffer);
-
- config->sort [i].e_table_config = config;
- }
-
- for (l = config->column_names; l; l = l->next){
- char *label = l->data;
-
- for (i = 0; i < 4; i++){
- gal_combo_text_add_item (config->sort [i].combo,
- dgettext (config->domain, label), label);
- }
- }
-
- /*
- * After we have runtime modified things, signal connect
- */
- for (i = 0; i < 4; i++){
- config->sort [i].changed_id = g_signal_connect (
- config->sort [i].combo->entry,
- "changed", G_CALLBACK (sort_entry_changed),
- &config->sort [i]);
-
- config->sort [i].toggled_id = g_signal_connect (
- config->sort [i].radio_ascending,
- "toggled", G_CALLBACK (sort_ascending_toggled),
- &config->sort [i]);
- }
-}
-
-static void
-group_entry_changed (GtkEntry *entry, ETableConfigSortWidgets *group)
-{
- ETableConfig *config = group->e_table_config;
- ETableSortInfo *sort_info = config->temp_state->sort_info;
- ETableConfigSortWidgets *base = &config->group[0];
- int idx = group - base;
- const char *s = gtk_entry_get_text (entry);
-
- if (s && s [0] && g_hash_table_lookup (group->combo->elements, s)){
- ETableSortColumn c;
- int col;
-
- col = find_model_column_by_name (config->source_spec, s);
- if (col == -1){
- g_warning ("grouping: this should not happen, %s", s);
- return;
- }
-
- c.ascending = GTK_TOGGLE_BUTTON (
- config->group [idx].radio_ascending)->active;
- c.column = col;
- e_table_sort_info_grouping_set_nth (sort_info, idx, c);
-
- update_sort_and_group_config_dialog (config, FALSE);
- } else {
- e_table_sort_info_grouping_truncate (sort_info, idx);
- update_sort_and_group_config_dialog (config, FALSE);
- }
-}
-
-static void
-group_ascending_toggled (GtkToggleButton *t, ETableConfigSortWidgets *group)
-{
- ETableConfig *config = group->e_table_config;
- ETableSortInfo *si = config->temp_state->sort_info;
- ETableConfigSortWidgets *base = &config->group[0];
- int idx = group - base;
- ETableSortColumn c;
-
- c = e_table_sort_info_grouping_get_nth (si, idx);
- c.ascending = t->active;
- e_table_sort_info_grouping_set_nth (si, idx, c);
-}
-
-static void
-configure_group_dialog (ETableConfig *config, GladeXML *gui)
-{
- GSList *l;
- int i;
-
- for (i = 0; i < 4; i++){
- char buffer [80];
-
- snprintf (buffer, sizeof (buffer), "group-combo-%d", i + 1);
- config->group [i].combo = GAL_COMBO_TEXT (
- glade_xml_get_widget (gui, buffer));
- gtk_widget_show (GTK_WIDGET (config->group [i].combo));
-
- gal_combo_text_add_item (config->group [i].combo, "", "");
-
- snprintf (buffer, sizeof (buffer), "frame-group-%d", i + 1);
- config->group [i].frames =
- glade_xml_get_widget (gui, buffer);
-
- snprintf (
- buffer, sizeof (buffer),
- "radiobutton-ascending-group-%d", i+1);
- config->group [i].radio_ascending = glade_xml_get_widget (
- gui, buffer);
-
- snprintf (
- buffer, sizeof (buffer),
- "radiobutton-descending-group-%d", i+1);
- config->group [i].radio_descending = glade_xml_get_widget (
- gui, buffer);
-
- snprintf (
- buffer, sizeof (buffer),
- "checkbutton-group-%d", i+1);
- config->group [i].view_check = glade_xml_get_widget (
- gui, buffer);
-
- config->group [i].e_table_config = config;
- }
-
-
- for (l = config->column_names; l; l = l->next){
- char *label = l->data;
-
- for (i = 0; i < 4; i++){
- gal_combo_text_add_item (
- config->group [i].combo,
- dgettext (config->domain, label), label);
- }
- }
-
- /*
- * After we have runtime modified things, signal connect
- */
- for (i = 0; i < 4; i++){
- config->group [i].changed_id = g_signal_connect (
- config->group [i].combo->entry,
- "changed", G_CALLBACK (group_entry_changed),
- &config->group [i]);
-
- config->group [i].toggled_id = g_signal_connect (
- config->group [i].radio_ascending,
- "toggled", G_CALLBACK (group_ascending_toggled),
- &config->group [i]);
- }
-}
-
-static void
-add_column (int model_row, gpointer closure)
-{
- GList **columns = closure;
- *columns = g_list_prepend (*columns, GINT_TO_POINTER (model_row));
-}
-
-static void
-config_button_add (GtkWidget *widget, ETableConfig *config)
-{
- GList *columns = NULL;
- GList *column;
- int count;
- int i;
-
- e_table_selected_row_foreach (config->available, add_column, &columns);
- columns = g_list_reverse (columns);
-
- count = g_list_length (columns);
-
- config->temp_state->columns = g_renew (int, config->temp_state->columns, config->temp_state->col_count + count);
- config->temp_state->expansions = g_renew (double, config->temp_state->expansions, config->temp_state->col_count + count);
- i = config->temp_state->col_count;
- for (column = columns; column; column = column->next) {
- config->temp_state->columns[i] = get_source_model_col_index (config, GPOINTER_TO_INT (column->data));
- config->temp_state->expansions[i] = config->source_spec->columns[config->temp_state->columns[i]]->expansion;
- i++;
- }
- config->temp_state->col_count += count;
-
- g_list_free (columns);
-
- setup_fields (config);
-}
-
-static void
-config_button_remove (GtkWidget *widget, ETableConfig *config)
-{
- GList *columns = NULL;
- GList *column;
-
- e_table_selected_row_foreach (config->shown, add_column, &columns);
-
- for (column = columns; column; column = column->next) {
- int row = GPOINTER_TO_INT (column->data);
-
- memmove (config->temp_state->columns + row, config->temp_state->columns + row + 1, sizeof (int) * (config->temp_state->col_count - row - 1));
- memmove (config->temp_state->expansions + row, config->temp_state->expansions + row + 1, sizeof (double) * (config->temp_state->col_count - row - 1));
- config->temp_state->col_count --;
- }
- config->temp_state->columns = g_renew (int, config->temp_state->columns, config->temp_state->col_count);
- config->temp_state->expansions = g_renew (double, config->temp_state->expansions, config->temp_state->col_count);
-
- g_list_free (columns);
-
- setup_fields (config);
-}
-
-static void
-config_button_up (GtkWidget *widget, ETableConfig *config)
-{
- GList *columns = NULL;
- GList *column;
- int *new_shown;
- double *new_expansions;
- int next_col;
- double next_expansion;
- int i;
-
- e_table_selected_row_foreach (config->shown, add_column, &columns);
-
- /* if no columns left, just return */
- if (columns == NULL)
- return;
-
- columns = g_list_reverse (columns);
-
- new_shown = g_new (int, config->temp_state->col_count);
- new_expansions = g_new (double, config->temp_state->col_count);
-
- column = columns;
-
- next_col = config->temp_state->columns[0];
- next_expansion = config->temp_state->expansions[0];
-
- for (i = 1; i < config->temp_state->col_count; i++) {
- if (column && (GPOINTER_TO_INT (column->data) == i)) {
- new_expansions[i - 1] = config->temp_state->expansions[i];
- new_shown[i - 1] = config->temp_state->columns[i];
- column = column->next;
- } else {
- new_shown[i - 1] = next_col;
- next_col = config->temp_state->columns[i];
-
- new_expansions[i - 1] = next_expansion;
- next_expansion = config->temp_state->expansions[i];
- }
- }
-
- new_shown[i - 1] = next_col;
- new_expansions[i - 1] = next_expansion;
-
- g_free (config->temp_state->columns);
- g_free (config->temp_state->expansions);
-
- config->temp_state->columns = new_shown;
- config->temp_state->expansions = new_expansions;
-
- g_list_free (columns);
-
- setup_fields (config);
-}
-
-static void
-config_button_down (GtkWidget *widget, ETableConfig *config)
-{
- GList *columns = NULL;
- GList *column;
- int *new_shown;
- double *new_expansions;
- int next_col;
- double next_expansion;
- int i;
-
- e_table_selected_row_foreach (config->shown, add_column, &columns);
-
- /* if no columns left, just return */
- if (columns == NULL)
- return;
-
-
- new_shown = g_new (int, config->temp_state->col_count);
- new_expansions = g_new (double, config->temp_state->col_count);
-
- column = columns;
-
- next_col = config->temp_state->columns[config->temp_state->col_count - 1];
- next_expansion = config->temp_state->expansions[config->temp_state->col_count - 1];
-
- for (i = config->temp_state->col_count - 1; i > 0; i--) {
- if (column && (GPOINTER_TO_INT (column->data) == i - 1)) {
- new_expansions[i] = config->temp_state->expansions[i - 1];
- new_shown[i] = config->temp_state->columns[i - 1];
- column = column->next;
- } else {
- new_shown[i] = next_col;
- next_col = config->temp_state->columns[i - 1];
-
- new_expansions[i] = next_expansion;
- next_expansion = config->temp_state->expansions[i - 1];
- }
- }
-
- new_shown[0] = next_col;
- new_expansions[0] = next_expansion;
-
- g_free (config->temp_state->columns);
- g_free (config->temp_state->expansions);
-
- config->temp_state->columns = new_shown;
- config->temp_state->expansions = new_expansions;
-
- g_list_free (columns);
-
- setup_fields (config);
-}
-
-static void
-configure_fields_dialog (ETableConfig *config, GladeXML *gui)
-{
- GtkWidget *scrolled;
-
- scrolled = glade_xml_get_widget (gui, "custom-available");
- config->available = e_table_scrolled_get_table (E_TABLE_SCROLLED (scrolled));
- g_object_get (config->available,
- "model", &config->available_model,
- NULL);
- gtk_widget_show_all (scrolled);
-
- scrolled = glade_xml_get_widget (gui, "custom-shown");
- config->shown = e_table_scrolled_get_table (E_TABLE_SCROLLED (scrolled));
- g_object_get (config->shown,
- "model", &config->shown_model,
- NULL);
- gtk_widget_show_all (scrolled);
-
- connect_button (config, gui, "button-add", G_CALLBACK (config_button_add));
- connect_button (config, gui, "button-remove", G_CALLBACK (config_button_remove));
- connect_button (config, gui, "button-up", G_CALLBACK (config_button_up));
- connect_button (config, gui, "button-down", G_CALLBACK (config_button_down));
-
- setup_fields (config);
-}
-
-static void
-setup_gui (ETableConfig *config)
-{
- GladeXML *gui;
-
- create_global_store (config);
-
- if (e_table_sort_info_get_can_group (config->state->sort_info)) {
- gui = glade_xml_new (ETABLE_GLADEDIR "/e-table-config.glade", NULL, E_I18N_DOMAIN);
- } else {
- gui = glade_xml_new (ETABLE_GLADEDIR "/e-table-config-no-group.glade", NULL, E_I18N_DOMAIN);
- }
-
- g_object_unref (global_store);
-
- config->dialog_toplevel = glade_xml_get_widget (
- gui, "e-table-config");
-
- if (config->header)
- gtk_window_set_title (GTK_WINDOW (config->dialog_toplevel), config->header);
-
- config->dialog_show_fields = glade_xml_get_widget (
- gui, "dialog-show-fields");
- config->dialog_group_by = glade_xml_get_widget (
- gui, "dialog-group-by");
- config->dialog_sort = glade_xml_get_widget (
- gui, "dialog-sort");
-
- config->sort_label = glade_xml_get_widget (
- gui, "label-sort");
- config->group_label = glade_xml_get_widget (
- gui, "label-group");
- config->fields_label = glade_xml_get_widget (
- gui, "label-fields");
-
- connect_button (config, gui, "button-sort", G_CALLBACK (config_button_sort));
- connect_button (config, gui, "button-group", G_CALLBACK (config_button_group));
- connect_button (config, gui, "button-fields", G_CALLBACK (config_button_fields));
-
- configure_sort_dialog (config, gui);
- configure_group_dialog (config, gui);
- configure_fields_dialog (config, gui);
-
- g_object_weak_ref (G_OBJECT (config->dialog_toplevel),
- dialog_destroyed, config);
-
- g_signal_connect (config->dialog_toplevel, "response",
- G_CALLBACK (dialog_response), config);
-
- g_object_unref (gui);
-}
-
-static void
-config_init (ETableConfig *config)
-{
- config->domain = NULL;
-}
-
-ETableConfig *
-e_table_config_construct (ETableConfig *config,
- const char *header,
- ETableSpecification *spec,
- ETableState *state,
- GtkWindow *parent_window)
-{
- ETableColumnSpecification **column;
-
- g_return_val_if_fail (config != NULL, NULL);
- g_return_val_if_fail (header != NULL, NULL);
- g_return_val_if_fail (spec != NULL, NULL);
- g_return_val_if_fail (state != NULL, NULL);
-
- config->source_spec = spec;
- config->source_state = state;
- config->header = g_strdup (header);
-
- g_object_ref (config->source_spec);
- g_object_ref (config->source_state);
-
- config->state = e_table_state_duplicate (state);
-
- config->domain = g_strdup (spec->domain);
-
- for (column = config->source_spec->columns; *column; column++){
- char *label = (*column)->title;
-
- if ((*column)->disabled)
- continue;
-
- config->column_names = g_slist_append (
- config->column_names, label);
- }
-
- setup_gui (config);
-
- gtk_window_set_transient_for (GTK_WINDOW (config->dialog_toplevel),
- parent_window);
-
- config_sort_info_update (config);
- config_group_info_update (config);
- config_fields_info_update (config);
-
- return E_TABLE_CONFIG (config);
-}
-
-/**
- * e_table_config_new:
- * @header: The title of the dialog for the ETableConfig.
- * @spec: The specification for the columns to allow.
- * @state: The current state of the configuration.
- *
- * Creates a new ETable config object.
- *
- * Returns: The config object.
- */
-ETableConfig *
-e_table_config_new (const char *header,
- ETableSpecification *spec,
- ETableState *state,
- GtkWindow *parent_window)
-{
- ETableConfig *config = g_object_new (E_TABLE_CONFIG_TYPE, NULL);
-
- if (e_table_config_construct (config, header, spec, state, parent_window) == NULL){
- g_object_unref (config);
- return NULL;
- }
-
- gtk_widget_ensure_style (config->dialog_toplevel);
- gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (config->dialog_toplevel)->vbox), 0);
- gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (config->dialog_toplevel)->action_area), 12);
-
- gtk_dialog_set_response_sensitive (GTK_DIALOG (config->dialog_toplevel),
- GTK_RESPONSE_APPLY, FALSE);
- gtk_widget_show (config->dialog_toplevel);
-
- return E_TABLE_CONFIG (config);
-}
-
-/**
- * e_table_config_raise:
- * @config: The ETableConfig object.
- *
- * Raises the dialog associated with this ETableConfig object.
- */
-void
-e_table_config_raise (ETableConfig *config)
-{
- gdk_window_raise (GTK_WIDGET (config->dialog_toplevel)->window);
-}
-
-E_MAKE_TYPE(e_table_config, "ETableConfig", ETableConfig, config_class_init, config_init, G_TYPE_OBJECT)
diff --git a/widgets/table/e-table-config.glade b/widgets/table/e-table-config.glade
deleted file mode 100644
index f721c7c8fb..0000000000
--- a/widgets/table/e-table-config.glade
+++ /dev/null
@@ -1,2181 +0,0 @@
-<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
-<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
-
-<glade-interface>
-<requires lib="gnome"/>
-
-<widget class="GtkDialog" id="dialog-show-fields">
- <property name="title" translatable="yes">Show Fields</property>
- <property name="type">GTK_WINDOW_TOPLEVEL</property>
- <property name="window_position">GTK_WIN_POS_NONE</property>
- <property name="modal">True</property>
- <property name="resizable">True</property>
- <property name="destroy_with_parent">False</property>
- <property name="decorated">True</property>
- <property name="skip_taskbar_hint">False</property>
- <property name="skip_pager_hint">False</property>
- <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
- <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
- <property name="has_separator">True</property>
-
- <child internal-child="vbox">
- <widget class="GtkVBox" id="dialog-vbox3">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">8</property>
-
- <child internal-child="action_area">
- <widget class="GtkHButtonBox" id="dialog-action_area3">
- <property name="visible">True</property>
- <property name="layout_style">GTK_BUTTONBOX_END</property>
-
- <child>
- <widget class="GtkButton" id="button22">
- <property name="visible">True</property>
- <property name="can_default">True</property>
- <property name="can_focus">True</property>
- <property name="label">gtk-cancel</property>
- <property name="use_stock">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="response_id">-6</property>
- </widget>
- </child>
-
- <child>
- <widget class="GtkButton" id="button20">
- <property name="visible">True</property>
- <property name="can_default">True</property>
- <property name="can_focus">True</property>
- <property name="label">gtk-ok</property>
- <property name="use_stock">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="response_id">-5</property>
- </widget>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="pack_type">GTK_PACK_END</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkVBox" id="vbox2">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="GtkTable" id="table2">
- <property name="visible">True</property>
- <property name="n_rows">1</property>
- <property name="n_columns">5</property>
- <property name="homogeneous">True</property>
- <property name="row_spacing">6</property>
- <property name="column_spacing">6</property>
-
- <child>
- <widget class="GtkLabel" id="label-available">
- <property name="visible">True</property>
- <property name="label" translatable="yes">A_vailable Fields:</property>
- <property name="use_underline">True</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="left_attach">0</property>
- <property name="right_attach">2</property>
- <property name="top_attach">0</property>
- <property name="bottom_attach">1</property>
- <property name="y_options">fill</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label-displayed">
- <property name="visible">True</property>
- <property name="label" translatable="yes">_Show these fields in order:</property>
- <property name="use_underline">True</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="left_attach">3</property>
- <property name="right_attach">5</property>
- <property name="top_attach">0</property>
- <property name="bottom_attach">1</property>
- <property name="y_options">fill</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkTable" id="table3">
- <property name="visible">True</property>
- <property name="n_rows">1</property>
- <property name="n_columns">5</property>
- <property name="homogeneous">True</property>
- <property name="row_spacing">6</property>
- <property name="column_spacing">6</property>
-
- <child>
- <widget class="GtkVBox" id="vbox4">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="Custom" id="custom-available">
- <property name="visible">True</property>
- <property name="creation_function">e_table_proxy_etable_available_new</property>
- <property name="int1">0</property>
- <property name="int2">0</property>
- <property name="last_modification_time">Thu, 21 Feb 2002 16:09:53 GMT</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="left_attach">0</property>
- <property name="right_attach">2</property>
- <property name="top_attach">0</property>
- <property name="bottom_attach">1</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkVBox" id="vbox5">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="Custom" id="custom-shown">
- <property name="visible">True</property>
- <property name="creation_function">e_table_proxy_etable_shown_new</property>
- <property name="int1">0</property>
- <property name="int2">0</property>
- <property name="last_modification_time">Thu, 21 Feb 2002 16:09:58 GMT</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkHBox" id="hbox4">
- <property name="visible">True</property>
- <property name="homogeneous">True</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="GtkButton" id="button-up">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Move _Up</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkButton" id="button-down">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Move _Down</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="left_attach">3</property>
- <property name="right_attach">5</property>
- <property name="top_attach">0</property>
- <property name="bottom_attach">1</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkVBox" id="vbox6">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="GtkButton" id="button-add">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">_Add -&gt;</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkButton" id="button-remove">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">&lt;- _Remove</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <placeholder/>
- </child>
- </widget>
- <packing>
- <property name="left_attach">2</property>
- <property name="right_attach">3</property>
- <property name="top_attach">0</property>
- <property name="bottom_attach">1</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- </child>
-</widget>
-
-<widget class="GtkDialog" id="dialog-group-by">
- <property name="title" translatable="yes">Group</property>
- <property name="type">GTK_WINDOW_TOPLEVEL</property>
- <property name="window_position">GTK_WIN_POS_NONE</property>
- <property name="modal">True</property>
- <property name="resizable">True</property>
- <property name="destroy_with_parent">False</property>
- <property name="decorated">True</property>
- <property name="skip_taskbar_hint">False</property>
- <property name="skip_pager_hint">False</property>
- <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
- <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
- <property name="has_separator">True</property>
-
- <child internal-child="vbox">
- <widget class="GtkVBox" id="dialog-vbox4">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">8</property>
-
- <child internal-child="action_area">
- <widget class="GtkHButtonBox" id="dialog-action_area4">
- <property name="visible">True</property>
- <property name="layout_style">GTK_BUTTONBOX_END</property>
-
- <child>
- <widget class="GtkButton" id="button39">
- <property name="visible">True</property>
- <property name="can_default">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Clear All</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="response_id">0</property>
- </widget>
- </child>
-
- <child>
- <widget class="GtkButton" id="button42">
- <property name="visible">True</property>
- <property name="can_default">True</property>
- <property name="can_focus">True</property>
- <property name="label">gtk-cancel</property>
- <property name="use_stock">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="response_id">-6</property>
- </widget>
- </child>
-
- <child>
- <widget class="GtkButton" id="button41">
- <property name="visible">True</property>
- <property name="can_default">True</property>
- <property name="can_focus">True</property>
- <property name="label">gtk-ok</property>
- <property name="use_stock">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="response_id">-5</property>
- </widget>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="pack_type">GTK_PACK_END</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkVBox" id="vbox24">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">0</property>
-
- <child>
- <widget class="GtkHBox" id="hbox13">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="GtkFrame" id="frame-group-1">
- <property name="visible">True</property>
- <property name="label_xalign">0</property>
- <property name="label_yalign">0.5</property>
- <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
-
- <child>
- <widget class="GtkHBox" id="hbox5">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="GtkVBox" id="vbox7">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">0</property>
-
- <child>
- <widget class="Custom" id="group-combo-1">
- <property name="visible">True</property>
- <property name="creation_function">e_table_proxy_gtk_combo_text_new</property>
- <property name="int1">0</property>
- <property name="int2">0</property>
- <property name="last_modification_time">Fri, 19 Jan 2001 04:52:09 GMT</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkCheckButton" id="checkbutton-group-1">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Show field in View</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkVBox" id="vbox8">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">0</property>
-
- <child>
- <widget class="GtkRadioButton" id="radiobutton-ascending-group-1">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Ascending</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkRadioButton" id="radiobutton-descending-group-1">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Descending</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- <property name="group">radiobutton-ascending-group-1</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label1">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Group Items By</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="type">label_item</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label8">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_CENTER</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label9">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_CENTER</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label10">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_CENTER</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkHBox" id="hbox14">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="GtkLabel" id="label11">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_CENTER</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkFrame" id="frame-group-2">
- <property name="visible">True</property>
- <property name="label_xalign">0</property>
- <property name="label_yalign">0.5</property>
- <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
-
- <child>
- <widget class="GtkHBox" id="hbox6">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="GtkVBox" id="vbox9">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">0</property>
-
- <child>
- <widget class="Custom" id="group-combo-2">
- <property name="visible">True</property>
- <property name="creation_function">e_table_proxy_gtk_combo_text_new</property>
- <property name="int1">0</property>
- <property name="int2">0</property>
- <property name="last_modification_time">Fri, 19 Jan 2001 04:52:14 GMT</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkCheckButton" id="checkbutton-group-2">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Show field in View</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkVBox" id="vbox10">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">0</property>
-
- <child>
- <widget class="GtkRadioButton" id="radiobutton-ascending-group-2">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Ascending</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkRadioButton" id="radiobutton-descending-group-2">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Descending</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- <property name="group">radiobutton-ascending-group-2</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label12">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Then By</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="type">label_item</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label19">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_CENTER</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label18">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_CENTER</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkHBox" id="hbox15">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="GtkLabel" id="label13">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_CENTER</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label12">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_CENTER</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkFrame" id="frame-group-3">
- <property name="visible">True</property>
- <property name="label_xalign">0</property>
- <property name="label_yalign">0.5</property>
- <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
-
- <child>
- <widget class="GtkHBox" id="hbox7">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="GtkVBox" id="vbox11">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">0</property>
-
- <child>
- <widget class="Custom" id="group-combo-3">
- <property name="visible">True</property>
- <property name="creation_function">e_table_proxy_gtk_combo_text_new</property>
- <property name="int1">0</property>
- <property name="int2">0</property>
- <property name="last_modification_time">Fri, 19 Jan 2001 04:52:18 GMT</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkCheckButton" id="checkbutton-group-3">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Show field in View</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkVBox" id="vbox12">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">0</property>
-
- <child>
- <widget class="GtkRadioButton" id="radiobutton-ascending-group-3">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Ascending</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkRadioButton" id="radiobutton-descending-group-3">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Descending</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- <property name="group">radiobutton-ascending-group-3</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label20">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Then By</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="type">label_item</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label17">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_CENTER</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkHBox" id="hbox16">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="GtkLabel" id="label14">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_CENTER</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label16">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_CENTER</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label15">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_CENTER</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkFrame" id="frame-group-4">
- <property name="visible">True</property>
- <property name="label_xalign">0</property>
- <property name="label_yalign">0.5</property>
- <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
-
- <child>
- <widget class="GtkHBox" id="hbox8">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="GtkVBox" id="vbox13">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">0</property>
-
- <child>
- <widget class="Custom" id="group-combo-4">
- <property name="visible">True</property>
- <property name="creation_function">e_table_proxy_gtk_combo_text_new</property>
- <property name="int1">0</property>
- <property name="int2">0</property>
- <property name="last_modification_time">Fri, 19 Jan 2001 04:52:21 GMT</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkCheckButton" id="checkbutton-group-4">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Show field in View</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkVBox" id="vbox14">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">0</property>
-
- <child>
- <widget class="GtkRadioButton" id="radiobutton-ascending-group-4">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Ascending</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkRadioButton" id="radiobutton-descending-group-4">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Descending</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- <property name="group">radiobutton-ascending-group-4</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label21">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Then By</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="type">label_item</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- </child>
-</widget>
-
-<widget class="GtkDialog" id="dialog-sort">
- <property name="title" translatable="yes">Sort</property>
- <property name="type">GTK_WINDOW_TOPLEVEL</property>
- <property name="window_position">GTK_WIN_POS_NONE</property>
- <property name="modal">True</property>
- <property name="resizable">True</property>
- <property name="destroy_with_parent">False</property>
- <property name="decorated">True</property>
- <property name="skip_taskbar_hint">False</property>
- <property name="skip_pager_hint">False</property>
- <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
- <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
- <property name="has_separator">True</property>
-
- <child internal-child="vbox">
- <widget class="GtkVBox" id="vbox15">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">8</property>
-
- <child internal-child="action_area">
- <widget class="GtkHButtonBox" id="hbuttonbox1">
- <property name="visible">True</property>
- <property name="layout_style">GTK_BUTTONBOX_END</property>
-
- <child>
- <widget class="GtkButton" id="button43">
- <property name="visible">True</property>
- <property name="can_default">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Clear All</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="response_id">0</property>
- </widget>
- </child>
-
- <child>
- <widget class="GtkButton" id="button45">
- <property name="visible">True</property>
- <property name="can_default">True</property>
- <property name="can_focus">True</property>
- <property name="label">gtk-cancel</property>
- <property name="use_stock">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="response_id">-6</property>
- </widget>
- </child>
-
- <child>
- <widget class="GtkButton" id="button44">
- <property name="visible">True</property>
- <property name="can_default">True</property>
- <property name="has_default">True</property>
- <property name="can_focus">True</property>
- <property name="label">gtk-ok</property>
- <property name="use_stock">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="response_id">-5</property>
- </widget>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="pack_type">GTK_PACK_END</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkTable" id="table5">
- <property name="visible">True</property>
- <property name="n_rows">4</property>
- <property name="n_columns">1</property>
- <property name="homogeneous">False</property>
- <property name="row_spacing">6</property>
- <property name="column_spacing">6</property>
-
- <child>
- <widget class="GtkFrame" id="frame-sort-4">
- <property name="visible">True</property>
- <property name="label_xalign">0</property>
- <property name="label_yalign">0.5</property>
- <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
-
- <child>
- <widget class="GtkHBox" id="hbox9">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="GtkAlignment" id="alignment1">
- <property name="visible">True</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xscale">1</property>
- <property name="yscale">0</property>
- <property name="top_padding">0</property>
- <property name="bottom_padding">0</property>
- <property name="left_padding">0</property>
- <property name="right_padding">0</property>
-
- <child>
- <widget class="Custom" id="sort-combo-4">
- <property name="visible">True</property>
- <property name="creation_function">e_table_proxy_gtk_combo_text_new</property>
- <property name="int1">0</property>
- <property name="int2">0</property>
- <property name="last_modification_time">Tue, 16 Jan 2001 08:33:52 GMT</property>
- </widget>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkVBox" id="vbox17">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">0</property>
-
- <child>
- <widget class="GtkRadioButton" id="radiobutton-ascending-sort-4">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Ascending</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkRadioButton" id="radiobutton-descending-sort-4">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Descending</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- <property name="group">radiobutton-ascending-sort-4</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label22">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Then By</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="type">label_item</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="left_attach">0</property>
- <property name="right_attach">1</property>
- <property name="top_attach">3</property>
- <property name="bottom_attach">4</property>
- <property name="y_options">fill</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkFrame" id="frame-sort-3">
- <property name="visible">True</property>
- <property name="label_xalign">0</property>
- <property name="label_yalign">0.5</property>
- <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
-
- <child>
- <widget class="GtkHBox" id="hbox10">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="GtkAlignment" id="alignment2">
- <property name="visible">True</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xscale">1</property>
- <property name="yscale">0</property>
- <property name="top_padding">0</property>
- <property name="bottom_padding">0</property>
- <property name="left_padding">0</property>
- <property name="right_padding">0</property>
-
- <child>
- <widget class="Custom" id="sort-combo-3">
- <property name="visible">True</property>
- <property name="creation_function">e_table_proxy_gtk_combo_text_new</property>
- <property name="int1">0</property>
- <property name="int2">0</property>
- <property name="last_modification_time">Tue, 16 Jan 2001 05:22:22 GMT</property>
- </widget>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkVBox" id="vbox19">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">0</property>
-
- <child>
- <widget class="GtkRadioButton" id="radiobutton-ascending-sort-3">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Ascending</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkRadioButton" id="radiobutton-descending-sort-3">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Descending</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- <property name="group">radiobutton-ascending-sort-3</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label23">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Then By</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="type">label_item</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="left_attach">0</property>
- <property name="right_attach">1</property>
- <property name="top_attach">2</property>
- <property name="bottom_attach">3</property>
- <property name="y_options">fill</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkFrame" id="frame-sort-2">
- <property name="visible">True</property>
- <property name="label_xalign">0</property>
- <property name="label_yalign">0.5</property>
- <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
-
- <child>
- <widget class="GtkHBox" id="hbox11">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="GtkAlignment" id="alignment3">
- <property name="visible">True</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xscale">1</property>
- <property name="yscale">0</property>
- <property name="top_padding">0</property>
- <property name="bottom_padding">0</property>
- <property name="left_padding">0</property>
- <property name="right_padding">0</property>
-
- <child>
- <widget class="Custom" id="sort-combo-2">
- <property name="visible">True</property>
- <property name="creation_function">e_table_proxy_gtk_combo_text_new</property>
- <property name="int1">0</property>
- <property name="int2">0</property>
- <property name="last_modification_time">Tue, 16 Jan 2001 05:22:15 GMT</property>
- </widget>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkVBox" id="vbox21">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">0</property>
-
- <child>
- <widget class="GtkRadioButton" id="radiobutton-ascending-sort-2">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Ascending</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkRadioButton" id="radiobutton-descending-sort-2">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Descending</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- <property name="group">radiobutton-ascending-sort-2</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label24">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Then By</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="type">label_item</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="left_attach">0</property>
- <property name="right_attach">1</property>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
- <property name="y_options">fill</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkFrame" id="frame-sort-1">
- <property name="visible">True</property>
- <property name="label_xalign">0</property>
- <property name="label_yalign">0.5</property>
- <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
-
- <child>
- <widget class="GtkHBox" id="hbox12">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="GtkAlignment" id="alignment4">
- <property name="visible">True</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xscale">1</property>
- <property name="yscale">0</property>
- <property name="top_padding">0</property>
- <property name="bottom_padding">0</property>
- <property name="left_padding">0</property>
- <property name="right_padding">0</property>
-
- <child>
- <widget class="Custom" id="sort-combo-1">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="has_focus">True</property>
- <property name="creation_function">e_table_proxy_gtk_combo_text_new</property>
- <property name="int1">0</property>
- <property name="int2">0</property>
- <property name="last_modification_time">Tue, 16 Jan 2001 05:22:00 GMT</property>
- </widget>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkVBox" id="vbox23">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">0</property>
-
- <child>
- <widget class="GtkRadioButton" id="radiobutton-ascending-sort-1">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Ascending</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkRadioButton" id="radiobutton-descending-sort-1">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Descending</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- <property name="group">radiobutton-ascending-sort-1</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label25">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Sort Items By</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="type">label_item</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="left_attach">0</property>
- <property name="right_attach">1</property>
- <property name="top_attach">0</property>
- <property name="bottom_attach">1</property>
- <property name="y_options">fill</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- </child>
-</widget>
-
-<widget class="GtkDialog" id="e-table-config">
- <property name="title" translatable="yes">dialog1</property>
- <property name="type">GTK_WINDOW_TOPLEVEL</property>
- <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
- <property name="modal">True</property>
- <property name="resizable">False</property>
- <property name="destroy_with_parent">False</property>
- <property name="decorated">True</property>
- <property name="skip_taskbar_hint">False</property>
- <property name="skip_pager_hint">False</property>
- <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
- <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
- <property name="has_separator">True</property>
-
- <child internal-child="vbox">
- <widget class="GtkVBox" id="dialog-vbox6">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">0</property>
-
- <child internal-child="action_area">
- <widget class="GtkHButtonBox" id="dialog-action_area6">
- <property name="visible">True</property>
- <property name="layout_style">GTK_BUTTONBOX_END</property>
-
- <child>
- <widget class="GtkButton" id="cancelbutton2">
- <property name="visible">True</property>
- <property name="can_default">True</property>
- <property name="can_focus">True</property>
- <property name="label">gtk-cancel</property>
- <property name="use_stock">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="response_id">-6</property>
- </widget>
- </child>
-
- <child>
- <widget class="GtkButton" id="applybutton2">
- <property name="visible">True</property>
- <property name="can_default">True</property>
- <property name="can_focus">True</property>
- <property name="label">gtk-apply</property>
- <property name="use_stock">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="response_id">-10</property>
- </widget>
- </child>
-
- <child>
- <widget class="GtkButton" id="okbutton2">
- <property name="visible">True</property>
- <property name="can_default">True</property>
- <property name="can_focus">True</property>
- <property name="label">gtk-ok</property>
- <property name="use_stock">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="response_id">-5</property>
- </widget>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="pack_type">GTK_PACK_END</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkFrame" id="top-frame">
- <property name="border_width">2</property>
- <property name="visible">True</property>
- <property name="label_xalign">0</property>
- <property name="label_yalign">0.5</property>
- <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
-
- <child>
- <widget class="GtkTable" id="table1">
- <property name="border_width">2</property>
- <property name="visible">True</property>
- <property name="n_rows">3</property>
- <property name="n_columns">3</property>
- <property name="homogeneous">False</property>
- <property name="row_spacing">2</property>
- <property name="column_spacing">4</property>
-
- <child>
- <widget class="GtkButton" id="button-sort">
- <property name="visible">True</property>
- <property name="can_default">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">_Sort...</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <signal name="clicked" handler="on_sort_clicked"/>
- </widget>
- <packing>
- <property name="left_attach">0</property>
- <property name="right_attach">1</property>
- <property name="top_attach">2</property>
- <property name="bottom_attach">3</property>
- <property name="x_options">fill</property>
- <property name="y_options"></property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkButton" id="button-group">
- <property name="visible">True</property>
- <property name="can_default">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">_Group By...</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <signal name="clicked" handler="on_group_by_clicked"/>
- </widget>
- <packing>
- <property name="left_attach">0</property>
- <property name="right_attach">1</property>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
- <property name="x_options">fill</property>
- <property name="y_options"></property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label-sort">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">True</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="left_attach">1</property>
- <property name="right_attach">2</property>
- <property name="top_attach">2</property>
- <property name="bottom_attach">3</property>
- <property name="y_options">fill</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkButton" id="button-fields">
- <property name="visible">True</property>
- <property name="can_default">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">_Fields Shown...</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <signal name="clicked" handler="on_group_by_clicked"/>
- </widget>
- <packing>
- <property name="left_attach">0</property>
- <property name="right_attach">1</property>
- <property name="top_attach">0</property>
- <property name="bottom_attach">1</property>
- <property name="x_options">fill</property>
- <property name="y_options"></property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label-fields">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">True</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="left_attach">1</property>
- <property name="right_attach">2</property>
- <property name="top_attach">0</property>
- <property name="bottom_attach">1</property>
- <property name="y_options">fill</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label3">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_CENTER</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="left_attach">2</property>
- <property name="right_attach">3</property>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
- <property name="x_options">fill</property>
- <property name="y_options">fill</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label4">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_CENTER</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="left_attach">2</property>
- <property name="right_attach">3</property>
- <property name="top_attach">2</property>
- <property name="bottom_attach">3</property>
- <property name="x_options">fill</property>
- <property name="y_options">fill</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label22">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_CENTER</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="left_attach">2</property>
- <property name="right_attach">3</property>
- <property name="top_attach">0</property>
- <property name="bottom_attach">1</property>
- <property name="x_options">fill</property>
- <property name="y_options">fill</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label-group">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">True</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="left_attach">1</property>
- <property name="right_attach">2</property>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
- <property name="x_options">fill</property>
- <property name="y_options"></property>
- </packing>
- </child>
- </widget>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label26">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Description</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="type">label_item</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- </child>
-</widget>
-
-</glade-interface>
diff --git a/widgets/table/e-table-config.h b/widgets/table/e-table-config.h
deleted file mode 100644
index cad376b955..0000000000
--- a/widgets/table/e-table-config.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-config.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- * Miguel de Icaza <miguel@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_TABLE_CONFIG_H_
-#define _E_TABLE_CONFIG_H_
-
-#include <gal/e-table/e-table-sort-info.h>
-#include <gal/e-table/e-table-specification.h>
-#include <gal/widgets/gal-combo-text.h>
-#include <gal/e-table/e-table-without.h>
-#include <gal/e-table/e-table-subset-variable.h>
-#include <gal/e-table/e-table.h>
-#include <gtk/gtkwindow.h>
-
-G_BEGIN_DECLS
-
-#define E_TABLE_CONFIG_TYPE (e_table_config_get_type ())
-#define E_TABLE_CONFIG(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TABLE_CONFIG_TYPE, ETableConfig))
-#define E_TABLE_CONFIG_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TABLE_CONFIG_TYPE, ETableConfigClass))
-#define E_IS_TABLE_CONFIG(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TABLE_CONFIG_TYPE))
-#define E_IS_TABLE_CONFIG_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TABLE_CONFIG_TYPE))
-#define E_TABLE_CONFIG_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), E_TABLE_CONFIG_TYPE, ETableConfigClass))
-
-typedef struct {
- GalComboText *combo;
- GtkWidget *frames;
- GtkWidget *radio_ascending;
- GtkWidget *radio_descending;
- GtkWidget *view_check; /* Only for group dialog */
- guint changed_id, toggled_id;
- void *e_table_config;
-} ETableConfigSortWidgets;
-
-
-typedef struct {
- GObject parent;
-
- char *header;
-
- /*
- * Our various dialog boxes
- */
- GtkWidget *dialog_toplevel;
- GtkWidget *dialog_show_fields;
- GtkWidget *dialog_group_by;
- GtkWidget *dialog_sort;
-
- /*
- * The state we manipulate
- */
- ETableSpecification *source_spec;
- ETableState *source_state, *state, *temp_state;
-
- GtkWidget *sort_label;
- GtkWidget *group_label;
- GtkWidget *fields_label;
-
- ETableConfigSortWidgets sort [4];
- ETableConfigSortWidgets group [4];
-
- ETable *available;
- ETableWithout *available_model;
- ETable *shown;
- ETableSubsetVariable *shown_model;
- char *domain;
-
- /*
- * List of valid column names
- */
- GSList *column_names;
-} ETableConfig;
-
-typedef struct {
- GObjectClass parent_class;
-
- /* Signals */
- void (*changed) (ETableConfig *config);
-} ETableConfigClass;
-
-GType e_table_config_get_type (void);
-ETableConfig *e_table_config_new (const char *header,
- ETableSpecification *spec,
- ETableState *state,
- GtkWindow *parent_window);
-ETableConfig *e_table_config_construct (ETableConfig *etco,
- const char *header,
- ETableSpecification *spec,
- ETableState *state,
- GtkWindow *parent_window);
-void e_table_config_raise (ETableConfig *config);
-
-G_END_DECLS
-
-#endif /* _E_TABLE_CONFIG_H */
diff --git a/widgets/table/e-table-defines.h b/widgets/table/e-table-defines.h
deleted file mode 100644
index 34585789d4..0000000000
--- a/widgets/table/e-table-defines.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-defines.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef __E_TABLE_DEFINES__
-#define __E_TABLE_DEFINES__ 1
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-#define BUTTON_HEIGHT 10
-#define BUTTON_PADDING 2
-#define GROUP_INDENT (BUTTON_HEIGHT + (BUTTON_PADDING * 2))
-
-/* Padding around the contents of a header button */
-#define HEADER_PADDING 1
-
-#define MIN_ARROW_SIZE 10
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-
-#endif
diff --git a/widgets/table/e-table-example-1.c b/widgets/table/e-table-example-1.c
deleted file mode 100644
index 37ac85770f..0000000000
--- a/widgets/table/e-table-example-1.c
+++ /dev/null
@@ -1,308 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-example-1.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-/* This code is GPL. */
-#include <stdio.h>
-#include <string.h>
-#include <gdk-pixbuf/gdk-pixbuf.h>
-
-#include "gal/e-util/e-cursors.h"
-#include "e-table-simple.h"
-#include "e-table-header.h"
-#include "e-table-header-item.h"
-#include "e-table-item.h"
-#include "e-cell-text.h"
-#include "e-cell-checkbox.h"
-#include "e-table.h"
-
-#include "table-test.h"
-
-/*
- * One way in which we make it simpler to build an ETableModel is through
- * the ETableSimple class. Instead of creating your own ETableModel
- * class, you simply create a new object of the ETableSimple class. You
- * give it a bunch of functions that act as callbacks.
- *
- * You also get to pass a void * to ETableSimple and it gets passed to
- * your callbacks. This would be for having multiple models of the same
- * type. This is just an example though, so we statically define all the
- * data and ignore the void *data parameter.
- *
- * In our example we will be creating a table model with 6 columns and 10
- * rows. This corresponds to having 6 different types of information and
- * 10 different sets of data in our database.
- *
- * The headers will be hard coded, as will be the example data.
- *
- */
-
-/*
- * There are two different meanings to the word "column". The first is
- * the model column. A model column corresponds to a specific type of
- * data. This is very much like the usage in a database table where a
- * column is a field in the database.
- *
- * The second type of column is a view column. A view column
- * corresponds to a visually displayed column. Each view column
- * corresponds to a specific model column, though a model column may
- * have any number of view columns associated with it, from zero to
- * greater than one.
- *
- * Also, a view column doesn't necessarily depend on only one model
- * column. In some cases, the view column renderer can be given a
- * reference to another column to get extra information about its
- * display.
-*/
-
-#define ROWS 10
-#define COLS 4
-
-#define IMPORTANCE_COLUMN 4
-#define COLOR_COLUMN 5
-
-/*
- * Here we define the initial layout of the table. This is an xml
- * format that allows you to change the initial ordering of the
- * columns or to do sorting or grouping initially. This specification
- * shows all 5 columns, but moves the importance column nearer to the
- * front. It also sorts by the "Full Name" column (ascending.)
- * Sorting and grouping take the model column as their arguments
- * (sorting is specified by the "column" argument to the leaf elemnt.
- */
-
-#define INITIAL_SPEC "<ETableSpecification> \
- <columns-shown> \
- <column> 0 </column> \
- <column> 4 </column> \
- <column> 1 </column> \
- <column> 2 </column> \
- <column> 3 </column> \
- </columns-shown> \
- <grouping> <leaf column=\"1\" ascending=\"true\"/> </grouping> \
-</ETableSpecification>"
-
-char *headers [COLS] = {
- "Email",
- "Full Name",
- "Address",
- "Phone"
-};
-
-/*
- * Virtual Column list:
- * 0 Email
- * 1 Full Name
- * 2 Address
- * 3 Phone
- */
-
-char *table_data [ROWS] [COLS];
-
-/*
- * ETableSimple callbacks
- * These are the callbacks that define the behavior of our custom model.
- */
-
-/*
- * Since our model is a constant size, we can just return its size in
- * the column and row count fields.
- */
-
-/* This function returns the number of columns in our ETableModel. */
-static int
-my_col_count (ETableModel *etc, void *data)
-{
- return COLS;
-}
-
-/* This function returns the number of rows in our ETableModel. */
-static int
-my_row_count (ETableModel *etc, void *data)
-{
- return ROWS;
-}
-
-/* This function returns the value at a particular point in our ETableModel. */
-static void *
-my_value_at (ETableModel *etc, int col, int row, void *data)
-{
- return (void *) table_data [row] [col];
-}
-
-/* This function sets the value at a particular point in our ETableModel. */
-static void
-my_set_value_at (ETableModel *etc, int col, int row, const void *val, void *data)
-{
- g_free (table_data [row] [col]);
- table_data [row] [col] = g_strdup (val);
-}
-
-/* This function returns whether a particular cell is editable. */
-static gboolean
-my_is_cell_editable (ETableModel *etc, int col, int row, void *data)
-{
- return TRUE;
-}
-
-/* This function duplicates the value passed to it. */
-static void *
-my_duplicate_value (ETableModel *etc, int col, const void *value, void *data)
-{
- return g_strdup (value);
-}
-
-/* This function frees the value passed to it. */
-static void
-my_free_value (ETableModel *etc, int col, void *value, void *data)
-{
- g_free (value);
-}
-
-/* This function creates an empty value. */
-static void *
-my_initialize_value (ETableModel *etc, int col, void *data)
-{
- return g_strdup ("");
-}
-
-/* This function reports if a value is empty. */
-static gboolean
-my_value_is_empty (ETableModel *etc, int col, const void *value, void *data)
-{
- return !(value && *(char *)value);
-}
-
-/* This function reports if a value is empty. */
-static char *
-my_value_to_string (ETableModel *etc, int col, const void *value, void *data)
-{
- return g_strdup(value);
-}
-
-/* We create a window containing our new table. */
-static void
-create_table (void)
-{
- GtkWidget *e_table, *window, *frame;
- ECell *cell_left_just;
- ETableHeader *e_table_header;
- int i, j;
- ETableModel *e_table_model = NULL;
-
- /* First we fill in the simple data. */
- for (i = 0; i < ROWS; i++){
- for (j = 0; j < COLS; j++)
- table_data [i] [j] = g_strdup ("");
- }
- /* Next we create our model. This uses the functions we defined
- earlier. */
- e_table_model = e_table_simple_new (
- my_col_count, my_row_count, my_value_at,
- my_set_value_at, my_is_cell_editable,
- my_duplicate_value, my_free_value,
- my_initialize_value, my_value_is_empty,
- my_value_to_string,
- NULL);
- /*
- * Next we create a header. The ETableHeader is used in two
- * different way. The first is the full_header. This is the
- * list of possible columns in the view. The second use is
- * completely internal. Many of the ETableHeader functions are
- * for that purpose. The only functions we really need are
- * e_table_header_new and e_table_header_add_col.
- *
- * First we create the header.
- */
- e_table_header = e_table_header_new ();
-
- /*
- * Next we have to build renderers for all of the columns.
- * Since all our columns are text columns, we can simply use
- * the same renderer over and over again. If we had different
- * types of columns, we could use a different renderer for
- * each column.
- */
- cell_left_just = e_cell_text_new (e_table_model, NULL, GTK_JUSTIFY_LEFT);
-
- /*
- * Next we create a column object for each view column and add
- * them to the header. We don't create a column object for
- * the importance column since it will not be shown.
- */
- for (i = 0; i < COLS; i++) {
- /* Create the column. */
- ETableCol *ecol = e_table_col_new (
- i, headers [i],
- 1.0, 20, cell_left_just,
- g_str_compare, TRUE);
- /* Add it to the header. */
- e_table_header_add_column (e_table_header, ecol, i);
- }
-
- /*
- * Here we create a window for our new table. This window
- * will get shown and the person will be able to test their
- * item.
- */
- window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
-
- /* This frame is simply to get a bevel around our table. */
- frame = gtk_frame_new (NULL);
-
- /*
- * Here we create the table. We give it the three pieces of
- * the table we've created, the header, the model, and the
- * initial layout. It does the rest.
- */
- e_table = e_table_new (e_table_header, e_table_model, INITIAL_SPEC);
-
- /* Build the gtk widget hierarchy. */
- gtk_container_add (GTK_CONTAINER (frame), e_table);
- gtk_container_add (GTK_CONTAINER (window), frame);
-
- /* Size the initial window. */
- gtk_widget_set_usize (window, 200, 200);
-
- /* Show it all. */
- gtk_widget_show_all (window);
-}
-
-/* This is the main function which just initializes gnome and call our create_table function */
-
-int
-main (int argc, char *argv [])
-{
- gnome_init ("TableExample", "TableExample", argc, argv);
- e_cursors_init ();
-
- gtk_widget_push_visual (gdk_rgb_get_visual ());
- gtk_widget_push_colormap (gdk_rgb_get_cmap ());
-
- create_table ();
-
- gtk_main ();
-
- e_cursors_shutdown ();
- return 0;
-}
-
diff --git a/widgets/table/e-table-example-2.c b/widgets/table/e-table-example-2.c
deleted file mode 100644
index 2321e4e7dd..0000000000
--- a/widgets/table/e-table-example-2.c
+++ /dev/null
@@ -1,349 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-example-2.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <gdk-pixbuf/gdk-pixbuf.h>
-
-#include "gal/e-util/e-cursors.h"
-#include "e-table-simple.h"
-#include "e-table-header.h"
-#include "e-table-header-item.h"
-#include "e-table-item.h"
-#include "e-cell-text.h"
-#include "e-cell-checkbox.h"
-#include "e-table.h"
-
-#include "table-test.h"
-
-/*
-One way in which we make it simpler to build an ETableModel is through
-the ETableSimple class. Instead of creating your own ETableModel
-class, you simply create a new object of the ETableSimple class. You
-give it a bunch of functions that act as callbacks.
-
-You also get to pass a void * to ETableSimple and it gets passed to
-your callbacks. This would be for having multiple models of the same
-type. This is just an example though, so we statically define all the
-data and ignore the void *data parameter.
-
-In our example we will be creating a table model with 6 columns and 10
-rows. This corresponds to having 6 different types of information and
-10 different sets of data in our database.
-
-The headers will be hard coded, as will be the example data.
-
-*/
-
-/*
- There are two different meanings to the word "column". The first is
- the model column. A model column corresponds to a specific type of
- data. This is very much like the usage in a database table where a
- column is a field in the database.
-
- The second type of column is a view column. A view column
- corresponds to a visually displayed column. Each view column
- corresponds to a specific model column, though a model column may
- have any number of view columns associated with it, from zero to
- greater than one.
-
- Also, a view column doesn't necessarily depend on only one model
- column. In some cases, the view column renderer can be given a
- reference to another column to get extra information about its
- display.
-*/
-
-#define ROWS 10
-#define VIEW_COLS 4
-#define PHYSICAL_COLS 5
-#define VIRTUAL_COLS 6
-
-#define IMPORTANCE_COLUMN 4
-#define COLOR_COLUMN 5
-
-/* Here we define the initial layout of the table. This is an xml
- format that allows you to change the initial ordering of the
- columns or to do sorting or grouping initially. This specification
- shows all 5 columns, but moves the importance column nearer to the
- front. It also sorts by the "Full Name" column (ascending.)
- Sorting and grouping take the model column as their arguments
- (sorting is specified by the "column" argument to the leaf elemnt. */
-#define INITIAL_SPEC "<ETableSpecification> \
- <columns-shown> \
- <column> 0 </column> \
- <column> 4 </column> \
- <column> 1 </column> \
- <column> 2 </column> \
- <column> 3 </column> \
- </columns-shown> \
- <grouping> <leaf column=\"1\" ascending=\"true\"/> </grouping> \
-</ETableSpecification>"
-
-char *headers[VIEW_COLS] = {
- "Email",
- "Full Name",
- "Address",
- "Phone"
-};
-
-/* Virtual Column list:
- 0 Full Name
- 1 Email
- 2 Address
- 3 Phone
- 4 Importance field. This field will be a boolean. It also has a
- special header, so doesn't appear in the headers list.
- 5 Color field. This column is also not displayed. It is also
- not stored in the database. It's calculated based on the
- Importance field.
-*/
-
-char *table_data[ROWS][VIEW_COLS];
-gboolean importance_data[ROWS];
-
-/*
- * ETableSimple callbacks
- * These are the callbacks that define the behavior of our custom model.
- */
-
-/* Since our model is a constant size, we can just return its size in
- the column and row count fields. */
-
-static GdkColor *color1;
-static GdkColor *color2;
-
-static int
-my_col_count (ETableModel *etc, void *data)
-{
- return VIRTUAL_COLS;
-}
-
-static int
-my_row_count (ETableModel *etc, void *data)
-{
- return ROWS;
-}
-
-static void *
-my_value_at (ETableModel *etc, int col, int row, void *data)
-{
- if (col == COLOR_COLUMN){
- if (importance_data[row]){
- return color1;
- } else {
- return color2;
- }
- } else if (col == IMPORTANCE_COLUMN){
- return (gpointer) importance_data[row];
- } else {
- return (void *) table_data [row][col];
- }
-}
-
-static void
-my_set_value_at (ETableModel *etc, int col, int row, const void *val, void *data)
-{
- if (col == COLOR_COLUMN){
- } else if (col == IMPORTANCE_COLUMN){
- importance_data[row] = (gboolean) val;
- } else {
- g_free (table_data [row][col]);
- table_data [row][col] = g_strdup (val);
- }
-}
-
-static gboolean
-my_is_cell_editable (ETableModel *etc, int col, int row, void *data)
-{
- if (col == IMPORTANCE_COLUMN)
- return FALSE;
- else
- return TRUE;
-}
-
-static void *
-my_duplicate_value (ETableModel *etc, int col, const void *value, void *data)
-{
- if (col == COLOR_COLUMN){
- return (void *) value;
- } else if (col == IMPORTANCE_COLUMN){
- return (void *) value;
- } else {
- return g_strdup (value);
- }
-}
-
-static void
-my_free_value (ETableModel *etc, int col, void *value, void *data)
-{
- if (col == COLOR_COLUMN){
- } else if (col == IMPORTANCE_COLUMN){
- } else {
- g_free (value);
- }
-}
-
-static void *
-my_initialize_value (ETableModel *etc, int col, void *data)
-{
- if (col == COLOR_COLUMN){
- return NULL;
- } else if (col == IMPORTANCE_COLUMN){
- return NULL;
- } else {
- return g_strdup ("");
- }
-}
-
-static gboolean
-my_value_is_empty (ETableModel *etc, int col, const void *value, void *data)
-{
- if (col == COLOR_COLUMN){
- return value == NULL;
- } else if (col == IMPORTANCE_COLUMN){
- return value == NULL;
- } else {
- return !(value && *(char *)value);
- }
-}
-
-static char *
-my_value_to_string (ETableModel *etc, int col, const void *value, void *data)
-{
- if (col == COLOR_COLUMN){
- return g_strdup_printf("%d", (int) value);
- } else if (col == IMPORTANCE_COLUMN){
- return g_strdup_printf("%d", (int) value);
- } else {
- return g_strdup(value);
- }
-}
-
-/* We create a window containing our new table. */
-static void
-create_table ()
-{
- GtkWidget *e_table, *window, *frame;
- ECell *cell_left_just;
- ECell *cell_checkbox;
- ETableHeader *e_table_header;
- int i, j;
- ETableModel *e_table_model = NULL;
- ETableCol *ecol;
- GdkPixbuf *pixbuf;
-
- /* First we fill in the simple data. */
- for (i = 0; i < ROWS; i++){
- for (j = 0; j < VIEW_COLS; j++){
- table_data[i][j] = g_strdup ("");
- }
- importance_data[i] = FALSE;
- }
- /* Next we create our model. This uses the functions we defined
- earlier. */
- e_table_model = e_table_simple_new (
- my_col_count, my_row_count, my_value_at,
- my_set_value_at, my_is_cell_editable,
- my_duplicate_value, my_free_value,
- my_initialize_value, my_value_is_empty,
- my_value_to_string,
- NULL);
- /*
- Next we create a header. The ETableHeader is used in two
- different way. The first is the full_header. This is the
- list of possible columns in the view. The second use is
- completely internal. Many of the ETableHeader functions are
- for that purpose. The only functions we really need are
- e_table_header_new and e_table_header_add_col.
-
- First we create the header. */
- e_table_header = e_table_header_new ();
-
- /* Next we have to build renderers for all of the columns.
- Since all our columns are text columns, we can simply use
- the same renderer over and over again. If we had different
- types of columns, we could use a different renderer for
- each column. */
- cell_left_just = e_cell_text_new (e_table_model, NULL, GTK_JUSTIFY_LEFT);
-
- /* Next we create a column object for each view column and add
- them to the header. We don't create a column object for
- the importance column since it will not be shown. */
- for (i = 0; i < VIEW_COLS; i++){
- /* Create the column. */
- ETableCol *ecol = e_table_col_new (
- i, headers [i],
- 1.0, 20, cell_left_just,
- g_str_compare, TRUE);
- /* Add it to the header. */
- e_table_header_add_column (e_table_header, ecol, i);
- }
-
- /* Next we add a special column for the check box. */
-
- cell_checkbox = e_cell_checkbox_new ();
- pixbuf = gdk_pixbuf_new_from_file ("clip.png");
- ecol = e_table_col_new_with_pixbuf (i, pixbuf, 0.0, 18, cell_checkbox, g_int_compare, TRUE);
- e_table_header_add_column (e_table_header, ecol, i);
-
- /*
- * Setup GUI
- */
- /* Here we create a window for our new table. This window
- will get shown and the person will be able to test their
- item. */
- window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
- /* This frame is simply to get a bevel around our table. */
- frame = gtk_frame_new (NULL);
- /* Here we create the table. We give it the three pieces of
- the table we've created, the header, the model, and the
- initial layout. It does the rest. */
- e_table = e_table_new (e_table_header, e_table_model, INITIAL_SPEC);
-
- /* Build the gtk widget hierarchy. */
- gtk_container_add (GTK_CONTAINER (frame), e_table);
- gtk_container_add (GTK_CONTAINER (window), frame);
-
- /* Size the initial window. */
- gtk_widget_set_usize (window, 200, 200);
- /* Show it all. */
- gtk_widget_show_all (window);
-}
-
-
-
-int
-main (int argc, char *argv [])
-{
- gnome_init ("TableExample", "TableExample", argc, argv);
- e_cursors_init ();
-
- gtk_widget_push_colormap (gdk_rgb_get_cmap ());
-
- create_table ();
-
- gtk_main ();
-
- e_cursors_shutdown ();
- return 0;
-}
diff --git a/widgets/table/e-table-extras.c b/widgets/table/e-table-extras.c
deleted file mode 100644
index 81947a6e94..0000000000
--- a/widgets/table/e-table-extras.c
+++ /dev/null
@@ -1,292 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-extras.c - Set of hash table sort of thingies.
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <stdlib.h>
-#include <gtk/gtksignal.h>
-#include "gal/util/e-util.h"
-#include "gal/e-table/e-cell-text.h"
-#include "gal/e-table/e-cell-checkbox.h"
-#include "gal/e-table/e-cell-date.h"
-#include "gal/e-table/e-cell-number.h"
-#include "gal/e-table/e-cell-pixbuf.h"
-#include "gal/e-table/e-cell-size.h"
-#include "gal/e-table/e-cell-tree.h"
-#include "e-table-extras.h"
-#include <string.h>
-
-static GObjectClass *ete_parent_class;
-
-static void
-cell_hash_free(gchar *key,
- ECell *cell,
- gpointer user_data)
-{
- g_free(key);
- if (cell)
- g_object_unref(cell);
-}
-
-static void
-pixbuf_hash_free(gchar *key,
- GdkPixbuf *pixbuf,
- gpointer user_data)
-{
- g_free(key);
- if (pixbuf)
- gdk_pixbuf_unref(pixbuf);
-}
-
-static void
-ete_finalize (GObject *object)
-{
- ETableExtras *ete = E_TABLE_EXTRAS (object);
-
- if (ete->cells) {
- g_hash_table_foreach (ete->cells, (GHFunc) cell_hash_free, NULL);
- g_hash_table_destroy (ete->cells);
- }
-
- if (ete->compares) {
- g_hash_table_foreach (ete->compares, (GHFunc) g_free, NULL);
- g_hash_table_destroy (ete->compares);
- }
-
- if (ete->searches) {
- g_hash_table_foreach (ete->searches, (GHFunc) g_free, NULL);
- g_hash_table_destroy (ete->searches);
- }
-
- if (ete->pixbufs) {
- g_hash_table_foreach (ete->pixbufs, (GHFunc) pixbuf_hash_free, NULL);
- g_hash_table_destroy (ete->pixbufs);
- }
-
- ete->cells = NULL;
- ete->compares = NULL;
- ete->searches = NULL;
- ete->pixbufs = NULL;
-
- ete_parent_class->finalize (object);
-}
-
-static void
-ete_class_init (GObjectClass *klass)
-{
- ete_parent_class = g_type_class_peek_parent (klass);
-
- klass->finalize = ete_finalize;
-}
-
-static gint
-e_strint_compare(gconstpointer data1, gconstpointer data2)
-{
- int int1 = atoi(data1);
- int int2 = atoi(data2);
-
- return g_int_compare(GINT_TO_POINTER(int1), GINT_TO_POINTER(int2));
-}
-
-/* UTF-8 strncasecmp - not optimized */
-
-static gint
-g_utf8_strncasecmp (const gchar *s1,
- const gchar *s2,
- guint n)
-{
- gunichar c1, c2;
-
- g_return_val_if_fail (s1 != NULL && g_utf8_validate (s1, -1, NULL), 0);
- g_return_val_if_fail (s2 != NULL && g_utf8_validate (s2, -1, NULL), 0);
-
- while (n && *s1 && *s2)
- {
-
- n -= 1;
-
- c1 = g_unichar_tolower (g_utf8_get_char (s1));
- c2 = g_unichar_tolower (g_utf8_get_char (s2));
-
- /* Collation is locale-dependent, so this totally fails to do the right thing. */
- if (c1 != c2)
- return c1 < c2 ? -1 : 1;
-
- s1 = g_utf8_next_char (s1);
- s2 = g_utf8_next_char (s2);
- }
-
- if (n == 0 || (*s1 == '\0' && *s2 == '\0'))
- return 0;
-
- return *s1 ? 1 : -1;
-}
-
-static gboolean
-e_string_search(gconstpointer haystack, const char *needle)
-{
- int length;
- if (haystack == NULL)
- return FALSE;
-
- length = g_utf8_strlen (needle, -1);
- if (g_utf8_strncasecmp (haystack, needle, length) == 0)
- return TRUE;
- else
- return FALSE;
-}
-
-static void
-ete_init (ETableExtras *extras)
-{
- extras->cells = g_hash_table_new(g_str_hash, g_str_equal);
- extras->compares = g_hash_table_new(g_str_hash, g_str_equal);
- extras->searches = g_hash_table_new(g_str_hash, g_str_equal);
- extras->pixbufs = g_hash_table_new(g_str_hash, g_str_equal);
-
- e_table_extras_add_compare(extras, "string", g_str_compare);
- e_table_extras_add_compare(extras, "collate", g_collate_compare);
- e_table_extras_add_compare(extras, "integer", g_int_compare);
- e_table_extras_add_compare(extras, "string-integer", e_strint_compare);
-
- e_table_extras_add_search(extras, "string", e_string_search);
-
- e_table_extras_add_cell(extras, "checkbox", e_cell_checkbox_new());
- e_table_extras_add_cell(extras, "date", e_cell_date_new (NULL, GTK_JUSTIFY_LEFT));
- e_table_extras_add_cell(extras, "number", e_cell_number_new (NULL, GTK_JUSTIFY_RIGHT));
- e_table_extras_add_cell(extras, "pixbuf", e_cell_pixbuf_new ());
- e_table_extras_add_cell(extras, "size", e_cell_size_new (NULL, GTK_JUSTIFY_RIGHT));
- e_table_extras_add_cell(extras, "string", e_cell_text_new (NULL, GTK_JUSTIFY_LEFT));
- e_table_extras_add_cell(extras, "tree-string", e_cell_tree_new (NULL, NULL, TRUE, e_cell_text_new (NULL, GTK_JUSTIFY_LEFT)));
-}
-
-E_MAKE_TYPE(e_table_extras, "ETableExtras", ETableExtras, ete_class_init, ete_init, G_TYPE_OBJECT)
-
-ETableExtras *
-e_table_extras_new (void)
-{
- ETableExtras *ete = g_object_new (E_TABLE_EXTRAS_TYPE, NULL);
-
- return (ETableExtras *) ete;
-}
-
-void
-e_table_extras_add_cell (ETableExtras *extras,
- char *id,
- ECell *cell)
-{
- gchar *old_key;
- ECell *old_cell;
-
- if (g_hash_table_lookup_extended (extras->cells, id, (gpointer *)&old_key, (gpointer *)&old_cell)) {
- g_hash_table_remove (extras->cells, old_key);
- g_free (old_key);
- if (old_cell)
- g_object_unref (old_cell);
- }
-
- if (cell) {
- g_object_ref (cell);
- gtk_object_sink (GTK_OBJECT (cell));
- }
- g_hash_table_insert (extras->cells, g_strdup(id), cell);
-}
-
-ECell *
-e_table_extras_get_cell (ETableExtras *extras,
- char *id)
-{
- return g_hash_table_lookup(extras->cells, id);
-}
-
-void
-e_table_extras_add_compare (ETableExtras *extras,
- char *id,
- GCompareFunc compare)
-{
- gchar *old_key;
- GCompareFunc old_compare;
-
- if (g_hash_table_lookup_extended (extras->compares, id, (gpointer *)&old_key, (gpointer *)&old_compare)) {
- g_hash_table_remove (extras->compares, old_key);
- g_free (old_key);
- }
-
- g_hash_table_insert(extras->compares, g_strdup(id), (gpointer) compare);
-}
-
-GCompareFunc
-e_table_extras_get_compare (ETableExtras *extras,
- char *id)
-{
- return (GCompareFunc) g_hash_table_lookup(extras->compares, id);
-}
-
-void
-e_table_extras_add_search (ETableExtras *extras,
- char *id,
- ETableSearchFunc search)
-{
- gchar *old_key;
- ETableSearchFunc old_search;
-
- if (g_hash_table_lookup_extended (extras->searches, id, (gpointer *)&old_key, (gpointer *)&old_search)) {
- g_hash_table_remove (extras->searches, old_key);
- g_free (old_key);
- }
-
- g_hash_table_insert(extras->searches, g_strdup(id), search);
-}
-
-ETableSearchFunc
-e_table_extras_get_search (ETableExtras *extras,
- char *id)
-{
- return g_hash_table_lookup(extras->searches, id);
-}
-
-void
-e_table_extras_add_pixbuf (ETableExtras *extras,
- char *id,
- GdkPixbuf *pixbuf)
-{
- gchar *old_key;
- GdkPixbuf *old_pixbuf;
-
- if (g_hash_table_lookup_extended (extras->pixbufs, id, (gpointer *)&old_key, (gpointer *)&old_pixbuf)) {
- g_hash_table_remove (extras->cells, old_key);
- g_free (old_key);
- if (old_pixbuf)
- gdk_pixbuf_unref (old_pixbuf);
- }
-
- if (pixbuf)
- gdk_pixbuf_ref(pixbuf);
- g_hash_table_insert (extras->pixbufs, g_strdup(id), pixbuf);
-}
-
-GdkPixbuf *
-e_table_extras_get_pixbuf (ETableExtras *extras,
- char *id)
-{
- return g_hash_table_lookup(extras->pixbufs, id);
-}
diff --git a/widgets/table/e-table-extras.h b/widgets/table/e-table-extras.h
deleted file mode 100644
index bd478e0bd8..0000000000
--- a/widgets/table/e-table-extras.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-extras.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_TABLE_EXTRAS_H_
-#define _E_TABLE_EXTRAS_H_
-
-#include <glib-object.h>
-#include <gal/e-table/e-cell.h>
-#include <gdk-pixbuf/gdk-pixbuf.h>
-
-G_BEGIN_DECLS
-
-#define E_TABLE_EXTRAS_TYPE (e_table_extras_get_type ())
-#define E_TABLE_EXTRAS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TABLE_EXTRAS_TYPE, ETableExtras))
-#define E_TABLE_EXTRAS_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TABLE_EXTRAS_TYPE, ETableExtrasClass))
-#define E_IS_TABLE_EXTRAS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TABLE_EXTRAS_TYPE))
-#define E_IS_TABLE_EXTRAS_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TABLE_EXTRAS_TYPE))
-#define E_TABLE_EXTRAS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), E_TABLE_EXTRAS_TYPE, ETableExtrasClass))
-
-typedef struct {
- GObject base;
-
- GHashTable *cells;
- GHashTable *compares;
- GHashTable *pixbufs;
- GHashTable *searches;
-} ETableExtras;
-
-typedef struct {
- GObjectClass parent_class;
-} ETableExtrasClass;
-
-GType e_table_extras_get_type (void);
-ETableExtras *e_table_extras_new (void);
-
-void e_table_extras_add_cell (ETableExtras *extras,
- char *id,
- ECell *cell);
-ECell *e_table_extras_get_cell (ETableExtras *extras,
- char *id);
-
-void e_table_extras_add_compare (ETableExtras *extras,
- char *id,
- GCompareFunc compare);
-GCompareFunc e_table_extras_get_compare (ETableExtras *extras,
- char *id);
-
-void e_table_extras_add_search (ETableExtras *extras,
- char *id,
- ETableSearchFunc search);
-ETableSearchFunc e_table_extras_get_search (ETableExtras *extras,
- char *id);
-
-void e_table_extras_add_pixbuf (ETableExtras *extras,
- char *id,
- GdkPixbuf *pixbuf);
-GdkPixbuf *e_table_extras_get_pixbuf (ETableExtras *extras,
- char *id);
-
-G_END_DECLS
-
-#endif /* _E_TABLE_EXTRAS_H_ */
diff --git a/widgets/table/e-table-field-chooser-dialog.c b/widgets/table/e-table-field-chooser-dialog.c
deleted file mode 100644
index d7e725fd12..0000000000
--- a/widgets/table/e-table-field-chooser-dialog.c
+++ /dev/null
@@ -1,224 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-field-chooser-dialog.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include "e-table-field-chooser-dialog.h"
-#include "gal/util/e-i18n.h"
-#include "gal/util/e-util.h"
-#include <gtk/gtkstock.h>
-
-static void e_table_field_chooser_dialog_init (ETableFieldChooserDialog *card);
-static void e_table_field_chooser_dialog_class_init (ETableFieldChooserDialogClass *klass);
-static void e_table_field_chooser_dialog_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
-static void e_table_field_chooser_dialog_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
-static void e_table_field_chooser_dialog_dispose (GObject *object);
-static void e_table_field_chooser_dialog_response (GtkDialog *dialog, gint id);
-
-#define PARENT_TYPE GTK_TYPE_DIALOG
-static GtkDialogClass *parent_class = NULL;
-
-/* The arguments we take */
-enum {
- PROP_0,
- PROP_DND_CODE,
- PROP_FULL_HEADER,
- PROP_HEADER
-};
-
-E_MAKE_TYPE (e_table_field_chooser_dialog,
- "ETableFieldChooserDialog",
- ETableFieldChooserDialog,
- e_table_field_chooser_dialog_class_init,
- e_table_field_chooser_dialog_init,
- PARENT_TYPE);
-
-static void
-e_table_field_chooser_dialog_class_init (ETableFieldChooserDialogClass *klass)
-{
- GObjectClass *object_class;
- GtkDialogClass *dialog_class;
-
- object_class = (GObjectClass*) klass;
- dialog_class = GTK_DIALOG_CLASS (klass);
-
- parent_class = g_type_class_ref (PARENT_TYPE);
-
- object_class->dispose = e_table_field_chooser_dialog_dispose;
- object_class->set_property = e_table_field_chooser_dialog_set_property;
- object_class->get_property = e_table_field_chooser_dialog_get_property;
-
- dialog_class->response = e_table_field_chooser_dialog_response;
-
- g_object_class_install_property (object_class, PROP_DND_CODE,
- g_param_spec_string ("dnd_code",
- _("DnD code"),
- /*_( */"XXX blurb" /*)*/,
- NULL,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class, PROP_FULL_HEADER,
- g_param_spec_object ("full_header",
- _("Full Header"),
- /*_( */"XXX blurb" /*)*/,
- E_TABLE_HEADER_TYPE,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class, PROP_HEADER,
- g_param_spec_object ("header",
- _("Header"),
- /*_( */"XXX blurb" /*)*/,
- E_TABLE_HEADER_TYPE,
- G_PARAM_READWRITE));
-}
-
-static void
-e_table_field_chooser_dialog_init (ETableFieldChooserDialog *e_table_field_chooser_dialog)
-{
- GtkWidget *widget;
-
- e_table_field_chooser_dialog->etfc = NULL;
- e_table_field_chooser_dialog->dnd_code = g_strdup("");
- e_table_field_chooser_dialog->full_header = NULL;
- e_table_field_chooser_dialog->header = NULL;
-
- gtk_dialog_add_button(GTK_DIALOG(e_table_field_chooser_dialog),
- GTK_STOCK_CLOSE, GTK_RESPONSE_OK);
-
- gtk_window_set_policy(GTK_WINDOW(e_table_field_chooser_dialog), FALSE, TRUE, FALSE);
-
- widget = e_table_field_chooser_new();
- e_table_field_chooser_dialog->etfc = E_TABLE_FIELD_CHOOSER(widget);
-
- g_object_set(widget,
- "dnd_code", e_table_field_chooser_dialog->dnd_code,
- "full_header", e_table_field_chooser_dialog->full_header,
- "header", e_table_field_chooser_dialog->header,
- NULL);
-
- gtk_box_pack_start(GTK_BOX(GTK_DIALOG(e_table_field_chooser_dialog)->vbox),
- widget, TRUE, TRUE, 0);
-
- gtk_widget_show(GTK_WIDGET(widget));
-
- gtk_window_set_title (GTK_WINDOW (e_table_field_chooser_dialog), _("Add a column..."));
-}
-
-GtkWidget*
-e_table_field_chooser_dialog_new (void)
-{
- GtkWidget *widget = g_object_new (E_TABLE_FIELD_CHOOSER_DIALOG_TYPE, NULL);
- return widget;
-}
-
-static void
-e_table_field_chooser_dialog_dispose (GObject *object)
-{
- ETableFieldChooserDialog *etfcd = E_TABLE_FIELD_CHOOSER_DIALOG (object);
-
- if (etfcd->dnd_code)
- g_free (etfcd->dnd_code);
- etfcd->dnd_code = NULL;
-
- if (etfcd->full_header)
- g_object_unref (etfcd->full_header);
- etfcd->full_header = NULL;
-
- if (etfcd->header)
- g_object_unref (etfcd->header);
- etfcd->header = NULL;
-
- G_OBJECT_CLASS (parent_class)->dispose (object);
-}
-
-static void
-e_table_field_chooser_dialog_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
-{
- ETableFieldChooserDialog *etfcd = E_TABLE_FIELD_CHOOSER_DIALOG(object);
- switch (prop_id){
- case PROP_DND_CODE:
- g_free(etfcd->dnd_code);
- etfcd->dnd_code = g_strdup(g_value_get_string (value));
- if (etfcd->etfc)
- g_object_set(etfcd->etfc,
- "dnd_code", etfcd->dnd_code,
- NULL);
- break;
- case PROP_FULL_HEADER:
- if (etfcd->full_header)
- g_object_unref (etfcd->full_header);
- if (g_value_get_object (value))
- etfcd->full_header = E_TABLE_HEADER(g_value_get_object (value));
- else
- etfcd->full_header = NULL;
- if (etfcd->full_header)
- g_object_ref (etfcd->full_header);
- if (etfcd->etfc)
- g_object_set(etfcd->etfc,
- "full_header", etfcd->full_header,
- NULL);
- break;
- case PROP_HEADER:
- if (etfcd->header)
- g_object_unref (etfcd->header);
- if (g_value_get_object (value))
- etfcd->header = E_TABLE_HEADER(g_value_get_object (value));
- else
- etfcd->header = NULL;
- if (etfcd->header)
- g_object_ref (etfcd->header);
- if (etfcd->etfc)
- g_object_set(etfcd->etfc,
- "header", etfcd->header,
- NULL);
- break;
- default:
- break;
- }
-}
-
-static void
-e_table_field_chooser_dialog_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
-{
- ETableFieldChooserDialog *etfcd = E_TABLE_FIELD_CHOOSER_DIALOG(object);
- switch (prop_id) {
- case PROP_DND_CODE:
- g_value_set_string (value, g_strdup (etfcd->dnd_code));
- break;
- case PROP_FULL_HEADER:
- g_value_set_object (value, etfcd->full_header);
- break;
- case PROP_HEADER:
- g_value_set_object (value, etfcd->header);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-e_table_field_chooser_dialog_response (GtkDialog *dialog, int id)
-{
- if (id == GTK_RESPONSE_OK)
- gtk_widget_destroy (GTK_WIDGET (dialog));
-}
diff --git a/widgets/table/e-table-field-chooser-dialog.h b/widgets/table/e-table-field-chooser-dialog.h
deleted file mode 100644
index 83fd5d3738..0000000000
--- a/widgets/table/e-table-field-chooser-dialog.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-field-chooser-dialog.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef __E_TABLE_FIELD_CHOOSER_DIALOG_H__
-#define __E_TABLE_FIELD_CHOOSER_DIALOG_H__
-
-#include <gtk/gtkdialog.h>
-#include <gal/e-table/e-table-field-chooser.h>
-#include <gal/e-table/e-table-header.h>
-
-#ifdef __cplusplus
-extern "C" {
-#pragma }
-#endif /* __cplusplus */
-
-/* ETableFieldChooserDialog - A dialog displaying information about a contact.
- *
- * The following arguments are available:
- *
- * name type read/write description
- * --------------------------------------------------------------------------------
- */
-
-#define E_TABLE_FIELD_CHOOSER_DIALOG_TYPE (e_table_field_chooser_dialog_get_type ())
-#define E_TABLE_FIELD_CHOOSER_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TABLE_FIELD_CHOOSER_DIALOG_TYPE, ETableFieldChooserDialog))
-#define E_TABLE_FIELD_CHOOSER_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TABLE_FIELD_CHOOSER_DIALOG_TYPE, ETableFieldChooserDialogClass))
-#define E_IS_TABLE_FIELD_CHOOSER_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TABLE_FIELD_CHOOSER_DIALOG_TYPE))
-#define E_IS_TABLE_FIELD_CHOOSER_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), E_TABLE_FIELD_CHOOSER_DIALOG_TYPE))
-
-
-typedef struct _ETableFieldChooserDialog ETableFieldChooserDialog;
-typedef struct _ETableFieldChooserDialogClass ETableFieldChooserDialogClass;
-
-struct _ETableFieldChooserDialog
-{
- GtkDialog parent;
-
- /* item specific fields */
- ETableFieldChooser *etfc;
- gchar *dnd_code;
- ETableHeader *full_header;
- ETableHeader *header;
-};
-
-struct _ETableFieldChooserDialogClass
-{
- GtkDialogClass parent_class;
-};
-
-
-GtkWidget *e_table_field_chooser_dialog_new(void);
-GType e_table_field_chooser_dialog_get_type (void);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-
-#endif /* __E_TABLE_FIELD_CHOOSER_DIALOG_H__ */
diff --git a/widgets/table/e-table-field-chooser-item.c b/widgets/table/e-table-field-chooser-item.c
deleted file mode 100644
index cfc73fc102..0000000000
--- a/widgets/table/e-table-field-chooser-item.c
+++ /dev/null
@@ -1,711 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-field-chooser-item.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <string.h>
-#include <gtk/gtksignal.h>
-#include <gtk/gtkdnd.h>
-#include <libgnomecanvas/gnome-canvas.h>
-#include <libgnomecanvas/gnome-canvas-util.h>
-#include <libgnomecanvas/gnome-canvas-polygon.h>
-#include <libgnomecanvas/gnome-canvas-rect-ellipse.h>
-#include <gdk-pixbuf/gdk-pixbuf.h>
-
-#include "gal/util/e-i18n.h"
-#include "gal/util/e-util.h"
-#include "gal/util/e-xml-utils.h"
-#include "gal/widgets/e-canvas.h"
-
-#include "e-table-header.h"
-#include "e-table-col-dnd.h"
-#include "e-table-defines.h"
-#include "e-table-header-utils.h"
-
-#include "e-table-field-chooser-item.h"
-
-#define d(x)
-
-#if 0
-enum {
- BUTTON_PRESSED,
- LAST_SIGNAL
-};
-
-static guint etfci_signals [LAST_SIGNAL] = { 0, };
-#endif
-
-#define PARENT_OBJECT_TYPE gnome_canvas_item_get_type ()
-
-#define ELEMENTS(x) (sizeof (x) / sizeof (x[0]))
-
-static GnomeCanvasItemClass *etfci_parent_class;
-
-static void etfci_drop_table_header (ETableFieldChooserItem *etfci);
-static void etfci_drop_full_header (ETableFieldChooserItem *etfci);
-
-enum {
- PROP_0,
- PROP_FULL_HEADER,
- PROP_HEADER,
- PROP_DND_CODE,
- PROP_WIDTH,
- PROP_HEIGHT
-};
-
-static void
-etfci_dispose (GObject *object)
-{
- ETableFieldChooserItem *etfci = E_TABLE_FIELD_CHOOSER_ITEM (object);
-
- etfci_drop_table_header (etfci);
- etfci_drop_full_header (etfci);
-
- if (etfci->combined_header)
- g_object_unref (etfci->combined_header);
- etfci->combined_header = NULL;
-
- if (etfci->font)
- gdk_font_unref(etfci->font);
- etfci->font = NULL;
-
- if (G_OBJECT_CLASS (etfci_parent_class)->dispose)
- (*G_OBJECT_CLASS (etfci_parent_class)->dispose) (object);
-}
-
-static gint
-etfci_find_button (ETableFieldChooserItem *etfci, double loc)
-{
- int i;
- int count;
- double height = 0;
- GtkStyle *style;
-
- style = GTK_WIDGET (GNOME_CANVAS_ITEM (etfci)->canvas)->style;
-
- count = e_table_header_count(etfci->combined_header);
- for (i = 0; i < count; i++) {
- ETableCol *ecol;
-
- ecol = e_table_header_get_column (etfci->combined_header, i);
- if (ecol->disabled)
- continue;
- height += e_table_header_compute_height (ecol, GTK_WIDGET (GNOME_CANVAS_ITEM (etfci)->canvas));
- if (height > loc)
- return i;
- }
- return MAX(0, count - 1);
-}
-
-static void
-etfci_rebuild_combined (ETableFieldChooserItem *etfci)
-{
- int count;
- GHashTable *hash;
- int i;
-
- if (etfci->combined_header != NULL)
- g_object_unref (etfci->combined_header);
-
- etfci->combined_header = e_table_header_new ();
-
- hash = g_hash_table_new (NULL, NULL);
-
- count = e_table_header_count (etfci->header);
- for (i = 0; i < count; i++) {
- ETableCol *ecol = e_table_header_get_column (etfci->header, i);
- if (ecol->disabled)
- continue;
- g_hash_table_insert (hash, GINT_TO_POINTER (ecol->col_idx), GINT_TO_POINTER (1));
- }
-
- count = e_table_header_count (etfci->full_header);
- for (i = 0; i < count; i++) {
- ETableCol *ecol = e_table_header_get_column (etfci->full_header, i);
- if (ecol->disabled)
- continue;
- if (! (GPOINTER_TO_INT (g_hash_table_lookup (hash, GINT_TO_POINTER (ecol->col_idx)))))
- e_table_header_add_column (etfci->combined_header, ecol, -1);
- }
-
- g_hash_table_destroy (hash);
-}
-
-static void
-etfci_reflow (GnomeCanvasItem *item, gint flags)
-{
- ETableFieldChooserItem *etfci = E_TABLE_FIELD_CHOOSER_ITEM (item);
- double old_height;
- int i;
- int count;
- double height = 0;
- GtkStyle *style;
-
- etfci_rebuild_combined (etfci);
-
- style = GTK_WIDGET (GNOME_CANVAS_ITEM (etfci)->canvas)->style;
-
- old_height = etfci->height;
-
- count = e_table_header_count(etfci->combined_header);
- for (i = 0; i < count; i++) {
- ETableCol *ecol;
-
- ecol = e_table_header_get_column (etfci->combined_header, i);
- if (ecol->disabled)
- continue;
- height += e_table_header_compute_height (ecol, GTK_WIDGET (GNOME_CANVAS_ITEM (etfci)->canvas));
- }
-
- etfci->height = height;
-
- if (old_height != etfci->height)
- e_canvas_item_request_parent_reflow(item);
-
- gnome_canvas_item_request_update(item);
-}
-
-static void
-etfci_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
-{
- ETableFieldChooserItem *etfci = E_TABLE_FIELD_CHOOSER_ITEM (item);
- double i2c [6];
- ArtPoint c1, c2, i1, i2;
-
- if (GNOME_CANVAS_ITEM_CLASS (etfci_parent_class)->update)
- (*GNOME_CANVAS_ITEM_CLASS (etfci_parent_class)->update)(item, affine, clip_path, flags);
-
- i1.x = i1.y = 0;
- i2.x = etfci->width;
- i2.y = etfci->height;
-
- gnome_canvas_item_i2c_affine (item, i2c);
- art_affine_point (&c1, &i1, i2c);
- art_affine_point (&c2, &i2, i2c);
-
- if (item->x1 != c1.x ||
- item->y1 != c1.y ||
- item->x2 != c2.x ||
- item->y2 != c2.y)
- {
- gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2, item->y2);
- item->x1 = c1.x;
- item->y1 = c1.y;
- item->x2 = c2.x;
- item->y2 = c2.y;
-#ifndef NO_WARNINGS
-#warning Group Child bounds !?
-#endif
-#if 0
- gnome_canvas_group_child_bounds (GNOME_CANVAS_GROUP (item->parent), item);
-#endif
- }
- gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2, item->y2);
-}
-
-static void
-etfci_font_load (ETableFieldChooserItem *etfci)
-{
- if (etfci->font)
- gdk_font_unref (etfci->font);
-
- etfci->font = gtk_style_get_font (GTK_WIDGET(GNOME_CANVAS_ITEM(etfci)->canvas)->style);
- gdk_font_ref(etfci->font);
-}
-
-static void
-etfci_drop_full_header (ETableFieldChooserItem *etfci)
-{
- GObject *header;
-
- if (!etfci->full_header)
- return;
-
- header = G_OBJECT (etfci->full_header);
- if (etfci->full_header_structure_change_id)
- g_signal_handler_disconnect (header, etfci->full_header_structure_change_id);
- if (etfci->full_header_dimension_change_id)
- g_signal_handler_disconnect (header, etfci->full_header_dimension_change_id);
- etfci->full_header_structure_change_id = 0;
- etfci->full_header_dimension_change_id = 0;
-
- if (header)
- g_object_unref (header);
- etfci->full_header = NULL;
- etfci->height = 0;
- e_canvas_item_request_reflow(GNOME_CANVAS_ITEM(etfci));
-}
-
-static void
-full_header_structure_changed (ETableHeader *header, ETableFieldChooserItem *etfci)
-{
- e_canvas_item_request_reflow(GNOME_CANVAS_ITEM(etfci));
-}
-
-static void
-full_header_dimension_changed (ETableHeader *header, int col, ETableFieldChooserItem *etfci)
-{
- e_canvas_item_request_reflow(GNOME_CANVAS_ITEM(etfci));
-}
-
-static void
-etfci_add_full_header (ETableFieldChooserItem *etfci, ETableHeader *header)
-{
- etfci->full_header = header;
- g_object_ref (etfci->full_header);
-
- etfci->full_header_structure_change_id = g_signal_connect (
- header, "structure_change",
- G_CALLBACK(full_header_structure_changed), etfci);
- etfci->full_header_dimension_change_id = g_signal_connect (
- header, "dimension_change",
- G_CALLBACK(full_header_dimension_changed), etfci);
- e_canvas_item_request_reflow(GNOME_CANVAS_ITEM(etfci));
-}
-
-static void
-etfci_drop_table_header (ETableFieldChooserItem *etfci)
-{
- GObject *header;
-
- if (!etfci->header)
- return;
-
- header = G_OBJECT (etfci->header);
- if (etfci->table_header_structure_change_id)
- g_signal_handler_disconnect (header, etfci->table_header_structure_change_id);
- if (etfci->table_header_dimension_change_id)
- g_signal_handler_disconnect (header, etfci->table_header_dimension_change_id);
- etfci->table_header_structure_change_id = 0;
- etfci->table_header_dimension_change_id = 0;
-
- if (header)
- g_object_unref (header);
- etfci->header = NULL;
- etfci->height = 0;
- e_canvas_item_request_reflow(GNOME_CANVAS_ITEM(etfci));
-}
-
-static void
-table_header_structure_changed (ETableHeader *header, ETableFieldChooserItem *etfci)
-{
- e_canvas_item_request_reflow(GNOME_CANVAS_ITEM(etfci));
-}
-
-static void
-table_header_dimension_changed (ETableHeader *header, int col, ETableFieldChooserItem *etfci)
-{
- e_canvas_item_request_reflow(GNOME_CANVAS_ITEM(etfci));
-}
-
-static void
-etfci_add_table_header (ETableFieldChooserItem *etfci, ETableHeader *header)
-{
- etfci->header = header;
- g_object_ref (etfci->header);
-
- etfci->table_header_structure_change_id = g_signal_connect (
- header, "structure_change",
- G_CALLBACK(table_header_structure_changed), etfci);
- etfci->table_header_dimension_change_id = g_signal_connect (
- header, "dimension_change",
- G_CALLBACK(table_header_dimension_changed), etfci);
- e_canvas_item_request_reflow(GNOME_CANVAS_ITEM(etfci));
-}
-
-static void
-etfci_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
-{
- GnomeCanvasItem *item;
- ETableFieldChooserItem *etfci;
-
- item = GNOME_CANVAS_ITEM (object);
- etfci = E_TABLE_FIELD_CHOOSER_ITEM (object);
-
- switch (prop_id){
- case PROP_FULL_HEADER:
- etfci_drop_full_header (etfci);
- if (g_value_get_object (value))
- etfci_add_full_header (etfci, E_TABLE_HEADER(g_value_get_object (value)));
- break;
-
- case PROP_HEADER:
- etfci_drop_table_header (etfci);
- if (g_value_get_object (value))
- etfci_add_table_header (etfci, E_TABLE_HEADER(g_value_get_object (value)));
- break;
-
- case PROP_DND_CODE:
- g_free(etfci->dnd_code);
- etfci->dnd_code = g_strdup(g_value_get_string (value));
- break;
-
- case PROP_WIDTH:
- etfci->width = g_value_get_double (value);
- gnome_canvas_item_request_update(item);
- break;
- }
-}
-
-static void
-etfci_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
-{
- GnomeCanvasItem *item;
- ETableFieldChooserItem *etfci;
-
- item = GNOME_CANVAS_ITEM (object);
- etfci = E_TABLE_FIELD_CHOOSER_ITEM (object);
-
- switch (prop_id){
-
- case PROP_DND_CODE:
- g_value_set_string (value, g_strdup (etfci->dnd_code));
- break;
- case PROP_WIDTH:
- g_value_set_double (value, etfci->width);
- break;
- case PROP_HEIGHT:
- g_value_set_double (value, etfci->height);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-etfci_drag_data_get (GtkWidget *widget,
- GdkDragContext *context,
- GtkSelectionData *selection_data,
- guint info,
- guint time,
- ETableFieldChooserItem *etfci)
-{
- if (etfci->drag_col != -1) {
- gchar *string = g_strdup_printf("%d", etfci->drag_col);
- gtk_selection_data_set(selection_data,
- GDK_SELECTION_TYPE_STRING,
- sizeof(string[0]),
- string,
- strlen(string));
- g_free(string);
- }
-}
-
-static void
-etfci_drag_end (GtkWidget *canvas,
- GdkDragContext *context,
- ETableFieldChooserItem *etfci)
-{
- etfci->drag_col = -1;
-}
-
-static void
-etfci_realize (GnomeCanvasItem *item)
-{
- ETableFieldChooserItem *etfci = E_TABLE_FIELD_CHOOSER_ITEM (item);
- GdkWindow *window;
-
- if (GNOME_CANVAS_ITEM_CLASS (etfci_parent_class)-> realize)
- (*GNOME_CANVAS_ITEM_CLASS (etfci_parent_class)->realize)(item);
-
- window = GTK_WIDGET (item->canvas)->window;
-
- if (!etfci->font)
- etfci_font_load (etfci);
-
- etfci->drag_end_id = g_signal_connect (
- item->canvas, "drag_end",
- G_CALLBACK (etfci_drag_end), etfci);
- etfci->drag_data_get_id = g_signal_connect (
- item->canvas, "drag_data_get",
- G_CALLBACK (etfci_drag_data_get), etfci);
- e_canvas_item_request_reflow(GNOME_CANVAS_ITEM(etfci));
-}
-
-static void
-etfci_unrealize (GnomeCanvasItem *item)
-{
- ETableFieldChooserItem *etfci = E_TABLE_FIELD_CHOOSER_ITEM (item);
-
- if (etfci->font)
- gdk_font_unref (etfci->font);
- etfci->font = NULL;
-
- g_signal_handler_disconnect (item->canvas, etfci->drag_end_id);
- etfci->drag_end_id = 0;
- g_signal_handler_disconnect (item->canvas, etfci->drag_data_get_id);
- etfci->drag_data_get_id = 0;
-
- if (GNOME_CANVAS_ITEM_CLASS (etfci_parent_class)->unrealize)
- (*GNOME_CANVAS_ITEM_CLASS (etfci_parent_class)->unrealize)(item);
-}
-
-static void
-etfci_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, int height)
-{
- ETableFieldChooserItem *etfci = E_TABLE_FIELD_CHOOSER_ITEM (item);
- GnomeCanvas *canvas = item->canvas;
- int rows;
- int y1, y2;
- int row;
- GtkStyle *style;
- GtkStateType state;
-
- if (etfci->combined_header == NULL)
- return;
-
- rows = e_table_header_count (etfci->combined_header);
-
- style = GTK_WIDGET (canvas)->style;
- state = GTK_WIDGET_STATE (canvas);
-
- y1 = y2 = 0;
- for (row = 0; row < rows; row++, y1 = y2){
- ETableCol *ecol;
-
- ecol = e_table_header_get_column (etfci->combined_header, row);
-
- if (ecol->disabled)
- continue;
-
- y2 += e_table_header_compute_height (ecol, GTK_WIDGET (canvas));
-
- if (y1 > (y + height))
- break;
-
- if (y2 < y)
- continue;
-
- e_table_header_draw_button (drawable, ecol,
- style, state,
- GTK_WIDGET (canvas),
- -x, y1 - y,
- width, height,
- etfci->width, y2 - y1,
- E_TABLE_COL_ARROW_NONE);
- }
-}
-
-static double
-etfci_point (GnomeCanvasItem *item, double x, double y, int cx, int cy,
- GnomeCanvasItem **actual_item)
-{
- *actual_item = item;
- return 0.0;
-}
-
-static gboolean
-etfci_maybe_start_drag (ETableFieldChooserItem *etfci, int x, int y)
-{
- if (!etfci->maybe_drag)
- return FALSE;
-
- if (MAX (abs (etfci->click_x - x),
- abs (etfci->click_y - y)) <= 3)
- return FALSE;
-
- return TRUE;
-}
-
-static void
-etfci_start_drag (ETableFieldChooserItem *etfci, GdkEvent *event, double x, double y)
-{
- GtkWidget *widget = GTK_WIDGET (GNOME_CANVAS_ITEM (etfci)->canvas);
- GtkTargetList *list;
- GdkDragContext *context;
- ETableCol *ecol;
- GdkPixmap *pixmap;
- int drag_col;
- int button_height;
-
- GtkTargetEntry etfci_drag_types [] = {
- { TARGET_ETABLE_COL_TYPE, 0, TARGET_ETABLE_COL_HEADER },
- };
-
- if (etfci->combined_header == NULL)
- return;
-
- drag_col = etfci_find_button(etfci, y);
-
- if (drag_col < 0 || drag_col > e_table_header_count(etfci->combined_header))
- return;
-
- ecol = e_table_header_get_column (etfci->combined_header, drag_col);
-
- if (ecol->disabled)
- return;
-
- etfci->drag_col = ecol->col_idx;
-
- etfci_drag_types[0].target = g_strdup_printf("%s-%s", etfci_drag_types[0].target, etfci->dnd_code);
- d(g_print ("etfci - %s\n", etfci_drag_types[0].target));
- list = gtk_target_list_new (etfci_drag_types, ELEMENTS (etfci_drag_types));
- context = gtk_drag_begin (widget, list, GDK_ACTION_MOVE, 1, event);
- g_free(etfci_drag_types[0].target);
-
- button_height = e_table_header_compute_height (ecol, widget);
- pixmap = gdk_pixmap_new (widget->window, etfci->width, button_height, -1);
-
- e_table_header_draw_button (pixmap, ecol,
- widget->style, GTK_WIDGET_STATE (widget),
- widget,
- 0, 0,
- etfci->width, button_height,
- etfci->width, button_height,
- E_TABLE_COL_ARROW_NONE);
-
- gtk_drag_set_icon_pixmap (context,
- gdk_window_get_colormap (widget->window),
- pixmap,
- NULL,
- etfci->width / 2,
- button_height / 2);
- gdk_pixmap_unref (pixmap);
- etfci->maybe_drag = FALSE;
-}
-
-/*
- * Handles the events on the ETableFieldChooserItem
- */
-static int
-etfci_event (GnomeCanvasItem *item, GdkEvent *e)
-{
- ETableFieldChooserItem *etfci = E_TABLE_FIELD_CHOOSER_ITEM (item);
- GnomeCanvas *canvas = item->canvas;
- int x, y;
-
- switch (e->type){
- case GDK_MOTION_NOTIFY:
- gnome_canvas_w2c (canvas, e->motion.x, e->motion.y, &x, &y);
-
- if (etfci_maybe_start_drag (etfci, x, y))
- etfci_start_drag (etfci, e, x, y);
- break;
-
- case GDK_BUTTON_PRESS:
- gnome_canvas_w2c (canvas, e->button.x, e->button.y, &x, &y);
-
- if (e->button.button == 1){
- etfci->click_x = x;
- etfci->click_y = y;
- etfci->maybe_drag = TRUE;
- }
- break;
-
- case GDK_BUTTON_RELEASE: {
- etfci->maybe_drag = FALSE;
- break;
- }
-
- default:
- return FALSE;
- }
- return TRUE;
-}
-
-static void
-etfci_class_init (GObjectClass *object_class)
-{
- GnomeCanvasItemClass *item_class = (GnomeCanvasItemClass *) object_class;
-
- etfci_parent_class = g_type_class_ref (PARENT_OBJECT_TYPE);
-
- object_class->dispose = etfci_dispose;
- object_class->set_property = etfci_set_property;
- object_class->get_property = etfci_get_property;
-
- item_class->update = etfci_update;
- item_class->realize = etfci_realize;
- item_class->unrealize = etfci_unrealize;
- item_class->draw = etfci_draw;
- item_class->point = etfci_point;
- item_class->event = etfci_event;
-
- g_object_class_install_property (object_class, PROP_DND_CODE,
- g_param_spec_string ("dnd_code",
- _("DnD code"),
- /*_( */"XXX blurb" /*)*/,
- NULL,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class, PROP_FULL_HEADER,
- g_param_spec_object ("full_header",
- _("Full Header"),
- /*_( */"XXX blurb" /*)*/,
- E_TABLE_HEADER_TYPE,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class, PROP_HEADER,
- g_param_spec_object ("header",
- _("Header"),
- /*_( */"XXX blurb" /*)*/,
- E_TABLE_HEADER_TYPE,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class, PROP_WIDTH,
- g_param_spec_double ("width",
- _("Width"),
- /*_( */"XXX blurb" /*)*/,
- 0, G_MAXDOUBLE, 0,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class, PROP_HEIGHT,
- g_param_spec_double ("height",
- _("Height"),
- /*_( */"XXX blurb" /*)*/,
- 0, G_MAXDOUBLE, 0,
- G_PARAM_READABLE));
-}
-
-static void
-etfci_init (GnomeCanvasItem *item)
-{
- ETableFieldChooserItem *etfci = E_TABLE_FIELD_CHOOSER_ITEM (item);
-
- etfci->full_header = NULL;
- etfci->header = NULL;
- etfci->combined_header = NULL;
-
- etfci->height = etfci->width = 0;
-
- etfci->font = NULL;
-
- etfci->full_header_structure_change_id = 0;
- etfci->full_header_dimension_change_id = 0;
- etfci->table_header_structure_change_id = 0;
- etfci->table_header_dimension_change_id = 0;
-
- etfci->dnd_code = NULL;
-
- etfci->maybe_drag = 0;
- etfci->drag_end_id = 0;
-
- e_canvas_item_set_reflow_callback(item, etfci_reflow);
-}
-
-E_MAKE_TYPE (e_table_field_chooser_item,
- "ETableFieldChooserItem",
- ETableFieldChooserItem,
- etfci_class_init,
- etfci_init,
- PARENT_OBJECT_TYPE);
diff --git a/widgets/table/e-table-field-chooser-item.h b/widgets/table/e-table-field-chooser-item.h
deleted file mode 100644
index 2ed37d37f1..0000000000
--- a/widgets/table/e-table-field-chooser-item.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-field-chooser-item.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_TABLE_FIELD_CHOOSER_ITEM_H_
-#define _E_TABLE_FIELD_CHOOSER_ITEM_H_
-
-#include <libgnomecanvas/gnome-canvas.h>
-#include <libxml/tree.h>
-#include <gal/e-table/e-table-header.h>
-
-G_BEGIN_DECLS
-
-#define E_TABLE_FIELD_CHOOSER_ITEM_TYPE (e_table_field_chooser_item_get_type ())
-#define E_TABLE_FIELD_CHOOSER_ITEM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TABLE_FIELD_CHOOSER_ITEM_TYPE, ETableFieldChooserItem))
-#define E_TABLE_FIELD_CHOOSER_ITEM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TABLE_FIELD_CHOOSER_ITEM_TYPE, ETableFieldChooserItemClass))
-#define E_IS_TABLE_FIELD_CHOOSER_ITEM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TABLE_FIELD_CHOOSER_ITEM_TYPE))
-#define E_IS_TABLE_FIELD_CHOOSER_ITEM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TABLE_FIELD_CHOOSER_ITEM_TYPE))
-
-typedef struct {
- GnomeCanvasItem parent;
- ETableHeader *full_header;
- ETableHeader *header;
- ETableHeader *combined_header;
-
- double height, width;
-
- GdkFont *font;
-
- /*
- * Ids
- */
- int full_header_structure_change_id, full_header_dimension_change_id;
- int table_header_structure_change_id, table_header_dimension_change_id;
-
- gchar *dnd_code;
-
- /*
- * For dragging columns
- */
- guint maybe_drag:1;
- int click_x, click_y;
- int drag_col;
- guint drag_data_get_id;
- guint drag_end_id;
-} ETableFieldChooserItem;
-
-typedef struct {
- GnomeCanvasItemClass parent_class;
-} ETableFieldChooserItemClass;
-
-GType e_table_field_chooser_item_get_type (void);
-
-G_END_DECLS
-
-#endif /* _E_TABLE_FIELD_CHOOSER_ITEM_H_ */
diff --git a/widgets/table/e-table-field-chooser.c b/widgets/table/e-table-field-chooser.c
deleted file mode 100644
index 25b94b2aca..0000000000
--- a/widgets/table/e-table-field-chooser.c
+++ /dev/null
@@ -1,302 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-field-chooser.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <gtk/gtksignal.h>
-#include <gtk/gtk.h>
-#include <gtk/gtkbox.h>
-#include <libgnomecanvas/gnome-canvas-rect-ellipse.h>
-#include "e-table-field-chooser.h"
-#include "e-table-field-chooser-item.h"
-#include <gal/util/e-i18n.h>
-#include <gal/util/e-util.h>
-
-static void e_table_field_chooser_init (ETableFieldChooser *card);
-static void e_table_field_chooser_class_init (ETableFieldChooserClass *klass);
-static void e_table_field_chooser_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
-static void e_table_field_chooser_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
-static void e_table_field_chooser_dispose (GObject *object);
-
-#define PARENT_TYPE GTK_TYPE_VBOX
-static GtkVBoxClass *parent_class = NULL;
-
-/* The arguments we take */
-enum {
- PROP_0,
- PROP_FULL_HEADER,
- PROP_HEADER,
- PROP_DND_CODE
-};
-
-E_MAKE_TYPE (e_table_field_chooser,
- "ETableFieldChooser",
- ETableFieldChooser,
- e_table_field_chooser_class_init,
- e_table_field_chooser_init,
- PARENT_TYPE);
-
-static void
-e_table_field_chooser_class_init (ETableFieldChooserClass *klass)
-{
- GObjectClass *object_class;
- GtkVBoxClass *vbox_class;
-
- object_class = (GObjectClass*) klass;
- vbox_class = (GtkVBoxClass *) klass;
-
- glade_init();
-
- parent_class = g_type_class_ref (GTK_TYPE_VBOX);
-
- object_class->set_property = e_table_field_chooser_set_property;
- object_class->get_property = e_table_field_chooser_get_property;
- object_class->dispose = e_table_field_chooser_dispose;
-
- g_object_class_install_property (object_class, PROP_DND_CODE,
- g_param_spec_string ("dnd_code",
- _("DnD code"),
- /*_( */"XXX blurb" /*)*/,
- NULL,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class, PROP_FULL_HEADER,
- g_param_spec_object ("full_header",
- _("Full Header"),
- /*_( */"XXX blurb" /*)*/,
- E_TABLE_HEADER_TYPE,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class, PROP_HEADER,
- g_param_spec_object ("header",
- _("Header"),
- /*_( */"XXX blurb" /*)*/,
- E_TABLE_HEADER_TYPE,
- G_PARAM_READWRITE));
-}
-
-static void
-ensure_nonzero_step_increments (ETableFieldChooser *etfc)
-{
- GtkAdjustment *va, *ha;
-
- va = gtk_layout_get_vadjustment (GTK_LAYOUT (etfc->canvas));
- ha = gtk_layout_get_hadjustment (GTK_LAYOUT (etfc->canvas));
-
- /*
- it looks pretty complicated to get height of column header
- so use 16 pixels which should be OK
- */
- if (va)
- va->step_increment = 16.0;
- if (ha)
- ha->step_increment = 16.0;
-}
-
-static void allocate_callback(GtkWidget *canvas, GtkAllocation *allocation, ETableFieldChooser *etfc)
-{
- double height;
- etfc->last_alloc = *allocation;
- gnome_canvas_item_set( etfc->item,
- "width", (double) allocation->width,
- NULL );
- g_object_get(etfc->item,
- "height", &height,
- NULL);
- height = MAX(height, allocation->height);
- gnome_canvas_set_scroll_region(GNOME_CANVAS( etfc->canvas ), 0, 0, allocation->width - 1, height - 1);
- gnome_canvas_item_set( etfc->rect,
- "x2", (double) allocation->width,
- "y2", (double) height,
- NULL );
- ensure_nonzero_step_increments (etfc);
-}
-
-static void resize(GnomeCanvas *canvas, ETableFieldChooser *etfc)
-{
- double height;
- g_object_get(etfc->item,
- "height", &height,
- NULL);
-
- height = MAX(height, etfc->last_alloc.height);
-
- gnome_canvas_set_scroll_region (GNOME_CANVAS(etfc->canvas), 0, 0, etfc->last_alloc.width - 1, height - 1);
- gnome_canvas_item_set( etfc->rect,
- "x2", (double) etfc->last_alloc.width,
- "y2", (double) height,
- NULL );
- ensure_nonzero_step_increments (etfc);
-}
-
-static void
-e_table_field_chooser_init (ETableFieldChooser *etfc)
-{
- GladeXML *gui;
- GtkWidget *widget;
-
- gui = glade_xml_new (ETABLE_GLADEDIR "/e-table-field-chooser.glade", NULL, E_I18N_DOMAIN);
- etfc->gui = gui;
-
- widget = glade_xml_get_widget(gui, "vbox-top");
- if (!widget) {
- return;
- }
- gtk_widget_reparent(widget,
- GTK_WIDGET(etfc));
-
- gtk_widget_push_colormap (gdk_rgb_get_cmap ());
-
- etfc->canvas = GNOME_CANVAS(glade_xml_get_widget(gui, "canvas-buttons"));
-
- etfc->rect = gnome_canvas_item_new(gnome_canvas_root( GNOME_CANVAS( etfc->canvas ) ),
- gnome_canvas_rect_get_type(),
- "x1", (double) 0,
- "y1", (double) 0,
- "x2", (double) 100,
- "y2", (double) 100,
- "fill_color", "white",
- NULL );
-
- etfc->item = gnome_canvas_item_new(gnome_canvas_root(etfc->canvas),
- e_table_field_chooser_item_get_type(),
- "width", (double) 100,
- "full_header", etfc->full_header,
- "header", etfc->header,
- "dnd_code", etfc->dnd_code,
- NULL );
-
- g_signal_connect( etfc->canvas, "reflow",
- G_CALLBACK ( resize ),
- etfc);
-
- gnome_canvas_set_scroll_region ( GNOME_CANVAS( etfc->canvas ),
- 0, 0,
- 100, 100 );
-
- /* Connect the signals */
- g_signal_connect (etfc->canvas, "size_allocate",
- G_CALLBACK (allocate_callback),
- etfc);
-
- gtk_widget_pop_colormap ();
- gtk_widget_show_all(widget);
-}
-
-static void
-e_table_field_chooser_dispose (GObject *object)
-{
- ETableFieldChooser *etfc = E_TABLE_FIELD_CHOOSER(object);
-
- g_free (etfc->dnd_code);
- etfc->dnd_code = NULL;
-
- if (etfc->full_header)
- g_object_unref (etfc->full_header);
- etfc->full_header = NULL;
-
- if (etfc->header)
- g_object_unref (etfc->header);
- etfc->header = NULL;
-
- if (etfc->gui)
- g_object_unref (etfc->gui);
- etfc->gui = NULL;
-
- if (G_OBJECT_CLASS (parent_class)->dispose)
- (* G_OBJECT_CLASS (parent_class)->dispose) (object);
-}
-
-GtkWidget*
-e_table_field_chooser_new (void)
-{
- GtkWidget *widget = GTK_WIDGET (g_object_new (E_TABLE_FIELD_CHOOSER_TYPE, NULL));
- return widget;
-}
-
-static void
-e_table_field_chooser_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
-{
- ETableFieldChooser *etfc = E_TABLE_FIELD_CHOOSER(object);
-
- switch (prop_id){
- case PROP_DND_CODE:
- g_free(etfc->dnd_code);
- etfc->dnd_code = g_strdup(g_value_get_string(value));
- if (etfc->item)
- g_object_set(etfc->item,
- "dnd_code", etfc->dnd_code,
- NULL);
- break;
- case PROP_FULL_HEADER:
- if (etfc->full_header)
- g_object_unref (etfc->full_header);
- if (g_value_get_object (value))
- etfc->full_header = E_TABLE_HEADER(g_value_get_object (value));
- else
- etfc->full_header = NULL;
- if (etfc->full_header)
- g_object_ref (etfc->full_header);
- if (etfc->item)
- g_object_set(etfc->item,
- "full_header", etfc->full_header,
- NULL);
- break;
- case PROP_HEADER:
- if (etfc->header)
- g_object_unref (etfc->header);
- if (g_value_get_object (value))
- etfc->header = E_TABLE_HEADER(g_value_get_object (value));
- else
- etfc->header = NULL;
- if (etfc->header)
- g_object_ref (etfc->header);
- if (etfc->item)
- g_object_set(etfc->item,
- "header", etfc->header,
- NULL);
- break;
- default:
- break;
- }
-}
-
-static void
-e_table_field_chooser_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
-{
- ETableFieldChooser *etfc = E_TABLE_FIELD_CHOOSER(object);
-
- switch (prop_id) {
- case PROP_DND_CODE:
- g_value_set_string (value, g_strdup (etfc->dnd_code));
- break;
- case PROP_FULL_HEADER:
- g_value_set_object (value, etfc->full_header);
- break;
- case PROP_HEADER:
- g_value_set_object (value, etfc->header);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
diff --git a/widgets/table/e-table-field-chooser.glade b/widgets/table/e-table-field-chooser.glade
deleted file mode 100644
index f46a8dbd52..0000000000
--- a/widgets/table/e-table-field-chooser.glade
+++ /dev/null
@@ -1,123 +0,0 @@
-<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
-<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd" >
-
-<glade-interface>
- <widget class="GtkDialog" id="dialog-field-chooser">
- <property name="visible">no</property>
- <property name="title" translatable="yes">Field Chooser</property>
- <property name="type">GTK_WINDOW_TOPLEVEL</property>
- <property name="modal">no</property>
- <property name="allow_shrink">no</property>
- <property name="allow_grow">yes</property>
- <property name="window-position">GTK_WIN_POS_NONE</property>
-
- <child internal-child="vbox">
- <widget class="GtkVBox" id="dialog-vbox1">
- <property name="homogeneous">no</property>
- <property name="spacing">8</property>
- <property name="visible">yes</property>
-
- <child internal-child="action_area">
- <widget class="GtkHButtonBox" id="dialog-action_area1">
- <property name="layout_style">GTK_BUTTONBOX_END</property>
- <property name="spacing">8</property>
- <property name="visible">yes</property>
-
- <child>
- <widget class="GtkButton" id="button3">
- <property name="can_default">yes</property>
- <property name="can_focus">yes</property>
- <property name="visible">yes</property>
- <property name="label">gtk-close</property>
- <property name="use_stock">yes</property>
- <property name="use_underline">yes</property>
- </widget>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">no</property>
- <property name="fill">yes</property>
- <property name="pack_type">GTK_PACK_END</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkVBox" id="vbox-top">
- <property name="homogeneous">no</property>
- <property name="spacing">4</property>
- <property name="visible">yes</property>
-
- <child>
- <widget class="GtkLabel" id="label1">
- <property name="label" translatable="yes">To add a column to your table, drag it into
-the location in which you want it to appear.</property>
- <property name="justify">GTK_JUSTIFY_CENTER</property>
- <property name="wrap">no</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- <property name="visible">yes</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">no</property>
- <property name="fill">no</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkScrolledWindow" id="scrolledwindow1">
- <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
- <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
- <property name="width-request">200</property>
- <property name="height-request">200</property>
- <property name="visible">yes</property>
-
- <child>
- <widget class="Custom" id="canvas-buttons">
- <property name="creation_function">e_canvas_new</property>
- <property name="int1">0</property>
- <property name="int2">0</property>
- <property name="last_modification_time">Thu, 08 Jun 2000 07:27:33 GMT</property>
- <property name="visible">yes</property>
- </widget>
- </child>
-
- <child internal-child="hscrollbar">
- <widget class="GtkHScrollbar" id="convertwidget1">
- <property name="update_policy">GTK_UPDATE_CONTINUOUS</property>
- <property name="visible">yes</property>
- </widget>
- </child>
-
- <child internal-child="vscrollbar">
- <widget class="GtkVScrollbar" id="convertwidget2">
- <property name="update_policy">GTK_UPDATE_CONTINUOUS</property>
- <property name="visible">yes</property>
- </widget>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">yes</property>
- <property name="fill">yes</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">yes</property>
- <property name="fill">yes</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">4</property>
- <property name="expand">yes</property>
- <property name="fill">yes</property>
- </packing>
- </child>
- </widget>
-</glade-interface>
diff --git a/widgets/table/e-table-field-chooser.h b/widgets/table/e-table-field-chooser.h
deleted file mode 100644
index 65efeeedbe..0000000000
--- a/widgets/table/e-table-field-chooser.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-field-chooser.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef __E_TABLE_FIELD_CHOOSER_H__
-#define __E_TABLE_FIELD_CHOOSER_H__
-
-#include <glade/glade.h>
-#include <gtk/gtkvbox.h>
-#include <gal/e-table/e-table-header.h>
-
-G_BEGIN_DECLS
-
-/* ETableFieldChooser - A dialog displaying information about a contact.
- *
- * The following arguments are available:
- *
- * name type read/write description
- * --------------------------------------------------------------------------------
- */
-
-#define E_TABLE_FIELD_CHOOSER_TYPE (e_table_field_chooser_get_type ())
-#define E_TABLE_FIELD_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TABLE_FIELD_CHOOSER_TYPE, ETableFieldChooser))
-#define E_TABLE_FIELD_CHOOSER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TABLE_FIELD_CHOOSER_TYPE, ETableFieldChooserClass))
-#define E_IS_TABLE_FIELD_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TABLE_FIELD_CHOOSER_TYPE))
-#define E_IS_TABLE_FIELD_CHOOSER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), E_TABLE_FIELD_CHOOSER_TYPE))
-
-
-typedef struct _ETableFieldChooser ETableFieldChooser;
-typedef struct _ETableFieldChooserClass ETableFieldChooserClass;
-
-struct _ETableFieldChooser
-{
- GtkVBox parent;
-
- /* item specific fields */
- GladeXML *gui;
- GnomeCanvas *canvas;
- GnomeCanvasItem *item;
-
- GnomeCanvasItem *rect;
- GtkAllocation last_alloc;
-
- gchar *dnd_code;
- ETableHeader *full_header;
- ETableHeader *header;
-};
-
-struct _ETableFieldChooserClass
-{
- GtkVBoxClass parent_class;
-};
-
-
-GtkWidget *e_table_field_chooser_new(void);
-GType e_table_field_chooser_get_type (void);
-
-G_END_DECLS
-
-#endif /* __E_TABLE_FIELD_CHOOSER_H__ */
diff --git a/widgets/table/e-table-group-container.c b/widgets/table/e-table-group-container.c
deleted file mode 100644
index 2fc0617e8f..0000000000
--- a/widgets/table/e-table-group-container.c
+++ /dev/null
@@ -1,1503 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-group-container.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <gdk/gdkkeysyms.h>
-#include <gtk/gtksignal.h>
-#include <libgnome/libgnome.h>
-#include <libgnomecanvas/gnome-canvas-rect-ellipse.h>
-#include "e-table-group-container.h"
-#include "e-table-group-leaf.h"
-#include "e-table-item.h"
-#include "gal/util/e-util.h"
-#include "gal/widgets/e-canvas.h"
-#include "gal/widgets/e-canvas-utils.h"
-#include "gal/widgets/e-unicode.h"
-#include "gal/e-text/e-text.h"
-#include "e-table-defines.h"
-
-#define TITLE_HEIGHT 16
-
-#define PARENT_TYPE e_table_group_get_type ()
-
-static GnomeCanvasGroupClass *etgc_parent_class;
-
-/* The arguments we take */
-enum {
- PROP_0,
- PROP_HEIGHT,
- PROP_WIDTH,
- PROP_MINIMUM_WIDTH,
- PROP_FROZEN,
- PROP_TABLE_ALTERNATING_ROW_COLORS,
- PROP_TABLE_HORIZONTAL_DRAW_GRID,
- PROP_TABLE_VERTICAL_DRAW_GRID,
- PROP_TABLE_DRAW_FOCUS,
- PROP_CURSOR_MODE,
- PROP_SELECTION_MODEL,
- PROP_LENGTH_THRESHOLD,
- PROP_UNIFORM_ROW_HEIGHT
-};
-
-static EPrintable *
-etgc_get_printable (ETableGroup *etg);
-
-
-static void
-e_table_group_container_child_node_free (ETableGroupContainer *etgc,
- ETableGroupContainerChildNode *child_node)
-{
- ETableGroup *etg = E_TABLE_GROUP (etgc);
- ETableGroup *child = child_node->child;
-
- gtk_object_destroy (GTK_OBJECT (child));
- e_table_model_free_value (etg->model, etgc->ecol->col_idx,
- child_node->key);
- g_free(child_node->string);
- gtk_object_destroy (GTK_OBJECT (child_node->text));
- gtk_object_destroy (GTK_OBJECT (child_node->rect));
-}
-
-static void
-e_table_group_container_list_free (ETableGroupContainer *etgc)
-{
- ETableGroupContainerChildNode *child_node;
- GList *list;
-
- for (list = etgc->children; list; list = g_list_next (list)) {
- child_node = (ETableGroupContainerChildNode *) list->data;
- e_table_group_container_child_node_free (etgc, child_node);
- }
-
- g_list_free (etgc->children);
- etgc->children = NULL;
-}
-
-static void
-etgc_dispose (GObject *object)
-{
- ETableGroupContainer *etgc = E_TABLE_GROUP_CONTAINER (object);
-
- if (etgc->children)
- e_table_group_container_list_free (etgc);
-
- if (etgc->font)
- gdk_font_unref (etgc->font);
- etgc->font = NULL;
-
- if (etgc->ecol)
- g_object_unref (etgc->ecol);
- etgc->ecol = NULL;
-
- if (etgc->sort_info)
- g_object_unref (etgc->sort_info);
- etgc->sort_info = NULL;
-
- if (etgc->selection_model)
- g_object_unref (etgc->selection_model);
- etgc->selection_model = NULL;
-
- if (etgc->rect)
- gtk_object_destroy (GTK_OBJECT(etgc->rect));
- etgc->rect = NULL;
-
- G_OBJECT_CLASS (etgc_parent_class)->dispose (object);
-}
-
-/**
- * e_table_group_container_construct
- * @parent: The %GnomeCanvasGroup to create a child of.
- * @etgc: The %ETableGroupContainer.
- * @full_header: The full header of the %ETable.
- * @header: The current header of the %ETable.
- * @model: The %ETableModel of the %ETable.
- * @sort_info: The %ETableSortInfo of the %ETable.
- * @n: Which grouping level this is (Starts at 0 and sends n + 1 to any child %ETableGroups.
- *
- * This routine constructs the new %ETableGroupContainer.
- */
-void
-e_table_group_container_construct (GnomeCanvasGroup *parent, ETableGroupContainer *etgc,
- ETableHeader *full_header,
- ETableHeader *header,
- ETableModel *model, ETableSortInfo *sort_info, int n)
-{
- ETableCol *col;
- ETableSortColumn column = e_table_sort_info_grouping_get_nth(sort_info, n);
-
- col = e_table_header_get_column_by_col_idx(full_header, column.column);
- if (col == NULL)
- col = e_table_header_get_column (full_header, e_table_header_count (full_header) - 1);
-
- e_table_group_construct (parent, E_TABLE_GROUP (etgc), full_header, header, model);
- etgc->ecol = col;
- g_object_ref (etgc->ecol);
- etgc->sort_info = sort_info;
- g_object_ref (etgc->sort_info);
- etgc->n = n;
- etgc->ascending = column.ascending;
-
- etgc->font = gtk_style_get_font (GTK_WIDGET (GNOME_CANVAS_ITEM (etgc)->canvas)->style);
-
- gdk_font_ref (etgc->font);
-
- etgc->open = TRUE;
-}
-
-/**
- * e_table_group_container_new
- * @parent: The %GnomeCanvasGroup to create a child of.
- * @full_header: The full header of the %ETable.
- * @header: The current header of the %ETable.
- * @model: The %ETableModel of the %ETable.
- * @sort_info: The %ETableSortInfo of the %ETable.
- * @n: Which grouping level this is (Starts at 0 and sends n + 1 to any child %ETableGroups.
- *
- * %ETableGroupContainer is an %ETableGroup which groups by the nth
- * grouping of the %ETableSortInfo. It creates %ETableGroups as
- * children.
- *
- * Returns: The new %ETableGroupContainer.
- */
-ETableGroup *
-e_table_group_container_new (GnomeCanvasGroup *parent, ETableHeader *full_header,
- ETableHeader *header,
- ETableModel *model, ETableSortInfo *sort_info, int n)
-{
- ETableGroupContainer *etgc;
-
- g_return_val_if_fail (parent != NULL, NULL);
-
- etgc = g_object_new (E_TABLE_GROUP_CONTAINER_TYPE, NULL);
-
- e_table_group_container_construct (parent, etgc, full_header, header,
- model, sort_info, n);
- return E_TABLE_GROUP (etgc);
-}
-
-
-static int
-etgc_event (GnomeCanvasItem *item, GdkEvent *event)
-{
- ETableGroupContainer *etgc = E_TABLE_GROUP_CONTAINER(item);
- gboolean return_val = TRUE;
- gboolean change_focus = FALSE;
- gboolean use_col = FALSE;
- gint start_col = 0;
- gint old_col;
- EFocus direction = E_FOCUS_START;
-
- switch (event->type) {
- case GDK_KEY_PRESS:
- if (event->key.keyval == GDK_Tab ||
- event->key.keyval == GDK_KP_Tab ||
- event->key.keyval == GDK_ISO_Left_Tab) {
- change_focus = TRUE;
- use_col = TRUE;
- start_col = (event->key.state & GDK_SHIFT_MASK) ? -1 : 0;
- direction = (event->key.state & GDK_SHIFT_MASK) ? E_FOCUS_END : E_FOCUS_START;
- } else if (event->key.keyval == GDK_Left ||
- event->key.keyval == GDK_KP_Left) {
- change_focus = TRUE;
- use_col = TRUE;
- start_col = -1;
- direction = E_FOCUS_END;
- } else if (event->key.keyval == GDK_Right ||
- event->key.keyval == GDK_KP_Right) {
- change_focus = TRUE;
- use_col = TRUE;
- start_col = 0;
- direction = E_FOCUS_START;
- } else if (event->key.keyval == GDK_Down ||
- event->key.keyval == GDK_KP_Down) {
- change_focus = TRUE;
- use_col = FALSE;
- direction = E_FOCUS_START;
- } else if (event->key.keyval == GDK_Up ||
- event->key.keyval == GDK_KP_Up) {
- change_focus = TRUE;
- use_col = FALSE;
- direction = E_FOCUS_END;
- } else if (event->key.keyval == GDK_Return ||
- event->key.keyval == GDK_KP_Enter) {
- change_focus = TRUE;
- use_col = FALSE;
- direction = E_FOCUS_START;
- }
- if (change_focus){
- GList *list;
- for (list = etgc->children; list; list = list->next) {
- ETableGroupContainerChildNode *child_node;
- ETableGroup *child;
-
- child_node = (ETableGroupContainerChildNode *)list->data;
- child = child_node->child;
-
- if (e_table_group_get_focus (child)) {
- old_col = e_table_group_get_focus_column (child);
- if (old_col == -1)
- old_col = 0;
- if (start_col == -1)
- start_col = e_table_header_count (e_table_group_get_header (child)) - 1;
-
- if (direction == E_FOCUS_END)
- list = list->prev;
- else
- list = list->next;
-
- if (list) {
- child_node = (ETableGroupContainerChildNode *)list->data;
- child = child_node->child;
- if (use_col)
- e_table_group_set_focus (child, direction, start_col);
- else
- e_table_group_set_focus (child, direction, old_col);
- return 1;
- } else {
- return 0;
- }
- }
- }
- if (direction == E_FOCUS_END)
- list = g_list_last(etgc->children);
- else
- list = etgc->children;
- if (list) {
- ETableGroupContainerChildNode *child_node;
- ETableGroup *child;
-
- child_node = (ETableGroupContainerChildNode *)list->data;
- child = child_node->child;
-
- if (start_col == -1)
- start_col = e_table_header_count (e_table_group_get_header (child)) - 1;
-
- e_table_group_set_focus (child, direction, start_col);
- return 1;
- }
- }
- return_val = FALSE;
- break;
- default:
- return_val = FALSE;
- break;
- }
- if (return_val == FALSE) {
- if (GNOME_CANVAS_ITEM_CLASS(etgc_parent_class)->event)
- return GNOME_CANVAS_ITEM_CLASS (etgc_parent_class)->event (item, event);
- }
- return return_val;
-
-}
-
-/* Realize handler for the text item */
-static void
-etgc_realize (GnomeCanvasItem *item)
-{
- ETableGroupContainer *etgc;
-
- if (GNOME_CANVAS_ITEM_CLASS (etgc_parent_class)->realize)
- (* GNOME_CANVAS_ITEM_CLASS (etgc_parent_class)->realize) (item);
-
- etgc = E_TABLE_GROUP_CONTAINER (item);
-
- e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (etgc));
-}
-
-/* Unrealize handler for the etgc item */
-static void
-etgc_unrealize (GnomeCanvasItem *item)
-{
- ETableGroupContainer *etgc;
-
- etgc = E_TABLE_GROUP_CONTAINER (item);
-
- if (GNOME_CANVAS_ITEM_CLASS (etgc_parent_class)->unrealize)
- (* GNOME_CANVAS_ITEM_CLASS (etgc_parent_class)->unrealize) (item);
-}
-
-static void
-compute_text (ETableGroupContainer *etgc, ETableGroupContainerChildNode *child_node)
-{
- gchar *text;
-
- if (etgc->ecol->text) {
- text = g_strdup_printf ((child_node->count == 1)
- ? _("%s : %s (%d item)")
- : _("%s : %s (%d items)"),
- etgc->ecol->text, child_node->string,
- (gint) child_node->count);
- } else {
- text = g_strdup_printf ((child_node->count == 1)
- ? _("%s (%d item)")
- : _("%s (%d items)"),
- child_node->string,
- (gint) child_node->count);
- }
- gnome_canvas_item_set (child_node->text,
- "text", text,
- NULL);
- g_free (text);
-}
-
-static void
-child_cursor_change (ETableGroup *etg, int row,
- ETableGroupContainer *etgc)
-{
- e_table_group_cursor_change (E_TABLE_GROUP (etgc), row);
-}
-
-static void
-child_cursor_activated (ETableGroup *etg, int row,
- ETableGroupContainer *etgc)
-{
- e_table_group_cursor_activated (E_TABLE_GROUP (etgc), row);
-}
-
-static void
-child_double_click (ETableGroup *etg, int row, int col, GdkEvent *event,
- ETableGroupContainer *etgc)
-{
- e_table_group_double_click (E_TABLE_GROUP (etgc), row, col, event);
-}
-
-static gint
-child_right_click (ETableGroup *etg, int row, int col, GdkEvent *event,
- ETableGroupContainer *etgc)
-{
- return e_table_group_right_click (E_TABLE_GROUP (etgc), row, col, event);
-}
-
-static gint
-child_click (ETableGroup *etg, int row, int col, GdkEvent *event,
- ETableGroupContainer *etgc)
-{
- return e_table_group_click (E_TABLE_GROUP (etgc), row, col, event);
-}
-
-static gint
-child_key_press (ETableGroup *etg, int row, int col, GdkEvent *event,
- ETableGroupContainer *etgc)
-{
- return e_table_group_key_press (E_TABLE_GROUP (etgc), row, col, event);
-}
-
-static gint
-child_start_drag (ETableGroup *etg, int row, int col, GdkEvent *event,
- ETableGroupContainer *etgc)
-{
- return e_table_group_start_drag (E_TABLE_GROUP (etgc), row, col, event);
-}
-
-static ETableGroupContainerChildNode *
-create_child_node (ETableGroupContainer *etgc, void *val)
-{
- ETableGroup *child;
- ETableGroupContainerChildNode *child_node;
- ETableGroup *etg = E_TABLE_GROUP(etgc);
-
- child_node = g_new (ETableGroupContainerChildNode, 1);
- child_node->rect = gnome_canvas_item_new (GNOME_CANVAS_GROUP (etgc),
- gnome_canvas_rect_get_type (),
- "fill_color", "grey70",
- "outline_color", "grey50",
- NULL);
- child_node->text = gnome_canvas_item_new (GNOME_CANVAS_GROUP (etgc),
- e_text_get_type (),
- "anchor", GTK_ANCHOR_SW,
- "fill_color", "black",
- "draw_background", FALSE,
- NULL);
- child = e_table_group_new (GNOME_CANVAS_GROUP (etgc), etg->full_header,
- etg->header, etg->model, etgc->sort_info, etgc->n + 1);
- gnome_canvas_item_set(GNOME_CANVAS_ITEM(child),
- "alternating_row_colors", etgc->alternating_row_colors,
- "horizontal_draw_grid", etgc->horizontal_draw_grid,
- "vertical_draw_grid", etgc->vertical_draw_grid,
- "drawfocus", etgc->draw_focus,
- "cursor_mode", etgc->cursor_mode,
- "selection_model", etgc->selection_model,
- "length_threshold", etgc->length_threshold,
- "uniform_row_height", etgc->uniform_row_height,
- "minimum_width", etgc->minimum_width - GROUP_INDENT,
- NULL);
-
- g_signal_connect (child, "cursor_change",
- G_CALLBACK (child_cursor_change), etgc);
- g_signal_connect (child, "cursor_activated",
- G_CALLBACK (child_cursor_activated), etgc);
- g_signal_connect (child, "double_click",
- G_CALLBACK (child_double_click), etgc);
- g_signal_connect (child, "right_click",
- G_CALLBACK (child_right_click), etgc);
- g_signal_connect (child, "click",
- G_CALLBACK (child_click), etgc);
- g_signal_connect (child, "key_press",
- G_CALLBACK (child_key_press), etgc);
- g_signal_connect (child, "start_drag",
- G_CALLBACK (child_start_drag), etgc);
- child_node->child = child;
- child_node->key = e_table_model_duplicate_value (etg->model, etgc->ecol->col_idx, val);
- child_node->string = e_table_model_value_to_string (etg->model, etgc->ecol->col_idx, val);
- child_node->count = 0;
-
- return child_node;
-}
-
-static void
-etgc_add (ETableGroup *etg, gint row)
-{
- ETableGroupContainer *etgc = E_TABLE_GROUP_CONTAINER (etg);
- void *val = e_table_model_value_at (etg->model, etgc->ecol->col_idx, row);
- GCompareFunc comp = etgc->ecol->compare;
- GList *list = etgc->children;
- ETableGroup *child;
- ETableGroupContainerChildNode *child_node;
- int i = 0;
-
- for (; list; list = g_list_next (list), i++){
- int comp_val;
-
- child_node = list->data;
- comp_val = (*comp)(child_node->key, val);
- if (comp_val == 0) {
- child = child_node->child;
- child_node->count ++;
- e_table_group_add (child, row);
- compute_text (etgc, child_node);
- return;
- }
- if ((comp_val > 0 && etgc->ascending) ||
- (comp_val < 0 && (!etgc->ascending)))
- break;
- }
- child_node = create_child_node (etgc, val);
- child = child_node->child;
- child_node->count = 1;
- e_table_group_add (child, row);
-
- if (list)
- etgc->children = g_list_insert (etgc->children, child_node, i);
- else
- etgc->children = g_list_append (etgc->children, child_node);
-
- compute_text (etgc, child_node);
- e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (etgc));
-}
-
-static void
-etgc_add_array (ETableGroup *etg, const int *array, int count)
-{
- int i;
- ETableGroupContainer *etgc = E_TABLE_GROUP_CONTAINER (etg);
- void *lastval = 0;
- int laststart = 0;
- GCompareFunc comp = etgc->ecol->compare;
- ETableGroupContainerChildNode *child_node;
- ETableGroup *child;
-
- if (count <= 0)
- return;
-
- e_table_group_container_list_free (etgc);
- etgc->children = NULL;
-
- lastval = e_table_model_value_at (etg->model, etgc->ecol->col_idx, array[0]);
-
- for (i = 1; i < count; i++) {
- void *val = e_table_model_value_at (etg->model, etgc->ecol->col_idx, array[i]);
- int comp_val;
-
- comp_val = (*comp)(lastval, val);
- if (comp_val != 0) {
- child_node = create_child_node(etgc, lastval);
- child = child_node->child;
-
- e_table_group_add_array(child, array + laststart, i - laststart);
- child_node->count = i - laststart;
-
- etgc->children = g_list_append (etgc->children, child_node);
- compute_text (etgc, child_node);
- laststart = i;
- lastval = val;
- }
- }
-
- child_node = create_child_node(etgc, lastval);
- child = child_node->child;
-
- e_table_group_add_array(child, array + laststart, i - laststart);
- child_node->count = i - laststart;
-
- etgc->children = g_list_append (etgc->children, child_node);
- compute_text (etgc, child_node);
-
- e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (etgc));
-}
-
-static void
-etgc_add_all (ETableGroup *etg)
-{
- ETableGroupContainer *etgc = E_TABLE_GROUP_CONTAINER (etg);
- ESorter *sorter = etgc->selection_model->sorter;
- int *array;
- int count;
-
- e_sorter_get_sorted_to_model_array(sorter, &array, &count);
-
- etgc_add_array(etg, array, count);
-}
-
-static gboolean
-etgc_remove (ETableGroup *etg, gint row)
-{
- ETableGroupContainer *etgc = E_TABLE_GROUP_CONTAINER(etg);
- GList *list;
-
- for (list = etgc->children ; list; list = g_list_next (list)) {
- ETableGroupContainerChildNode *child_node = list->data;
- ETableGroup *child = child_node->child;
-
- if (e_table_group_remove (child, row)) {
- child_node->count --;
- if (child_node->count == 0) {
- e_table_group_container_child_node_free (etgc, child_node);
- etgc->children = g_list_remove (etgc->children, child_node);
- g_free (child_node);
- } else
- compute_text (etgc, child_node);
-
- e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (etgc));
-
- return TRUE;
- }
- }
- return FALSE;
-}
-
-static int
-etgc_row_count (ETableGroup *etg)
-{
- ETableGroupContainer *etgc = E_TABLE_GROUP_CONTAINER(etg);
- GList *list;
- gint count = 0;
- for (list = etgc->children; list; list = g_list_next(list)) {
- ETableGroup *group = ((ETableGroupContainerChildNode *)list->data)->child;
- gint this_count = e_table_group_row_count(group);
- count += this_count;
- }
- return count;
-}
-
-static void
-etgc_increment (ETableGroup *etg, gint position, gint amount)
-{
- ETableGroupContainer *etgc = E_TABLE_GROUP_CONTAINER(etg);
- GList *list = etgc->children;
-
- for (list = etgc->children ; list; list = g_list_next (list))
- e_table_group_increment (((ETableGroupContainerChildNode *)list->data)->child,
- position, amount);
-}
-
-static void
-etgc_decrement (ETableGroup *etg, gint position, gint amount)
-{
- ETableGroupContainer *etgc = E_TABLE_GROUP_CONTAINER(etg);
- GList *list = etgc->children;
-
- for (list = etgc->children ; list; list = g_list_next (list))
- e_table_group_decrement (((ETableGroupContainerChildNode *)list->data)->child,
- position, amount);
-}
-
-static void
-etgc_set_focus (ETableGroup *etg, EFocus direction, gint view_col)
-{
- ETableGroupContainer *etgc = E_TABLE_GROUP_CONTAINER(etg);
- if (etgc->children) {
- if (direction == E_FOCUS_END)
- e_table_group_set_focus (((ETableGroupContainerChildNode *)g_list_last (etgc->children)->data)->child,
- direction, view_col);
- else
- e_table_group_set_focus (((ETableGroupContainerChildNode *)etgc->children->data)->child,
- direction, view_col);
- }
-}
-
-static gint
-etgc_get_focus_column (ETableGroup *etg)
-{
- ETableGroupContainer *etgc = E_TABLE_GROUP_CONTAINER(etg);
- if (etgc->children) {
- GList *list;
- for (list = etgc->children; list; list = list->next) {
- ETableGroupContainerChildNode *child_node = (ETableGroupContainerChildNode *)list->data;
- ETableGroup *child = child_node->child;
- if (e_table_group_get_focus (child)) {
- return e_table_group_get_focus_column (child);
- }
- }
- }
- return 0;
-}
-
-static void
-etgc_compute_location (ETableGroup *etg, int *x, int *y, int *row, int *col)
-{
- ETableGroupContainer *etgc = E_TABLE_GROUP_CONTAINER(etg);
-
- if (row)
- *row = -1;
- if (col)
- *col = -1;
-
- *x -= GROUP_INDENT;
- *y -= TITLE_HEIGHT;
-
- if (*x >= 0 && *y >= 0 && etgc->children) {
- GList *list;
- for (list = etgc->children; list; list = list->next) {
- ETableGroupContainerChildNode *child_node = (ETableGroupContainerChildNode *)list->data;
- ETableGroup *child = child_node->child;
-
- e_table_group_compute_location (child, x, y, row, col);
- if ((*row != -1) && (*col != -1))
- return;
- }
- }
-}
-
-static void
-etgc_get_cell_geometry (ETableGroup *etg, int *row, int *col, int *x, int *y, int *width, int *height)
-{
- ETableGroupContainer *etgc = E_TABLE_GROUP_CONTAINER(etg);
-
- int ypos;
-
- ypos = 0;
-
- if (etgc->children) {
- GList *list;
- for (list = etgc->children; list; list = list->next) {
- ETableGroupContainerChildNode *child_node = (ETableGroupContainerChildNode *)list->data;
- ETableGroup *child = child_node->child;
- int thisy;
-
- e_table_group_get_cell_geometry (child, row, col, x, &thisy, width, height);
- ypos += thisy;
- if ((*row == -1) || (*col == -1)) {
- ypos += TITLE_HEIGHT;
- *x += GROUP_INDENT;
- *y = ypos;
- return;
- }
- }
- }
-}
-
-static void etgc_thaw (ETableGroup *etg)
-{
- e_canvas_item_request_reflow (GNOME_CANVAS_ITEM(etg));
-}
-
-static void
-etgc_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
-{
- ETableGroup *etg = E_TABLE_GROUP (object);
- ETableGroupContainer *etgc = E_TABLE_GROUP_CONTAINER (object);
- GList *list;
-
- switch (prop_id) {
- case PROP_FROZEN:
- if (g_value_get_boolean (value))
- etg->frozen = TRUE;
- else {
- etg->frozen = FALSE;
- etgc_thaw (etg);
- }
- break;
- case PROP_MINIMUM_WIDTH:
- case PROP_WIDTH:
- etgc->minimum_width = g_value_get_double (value);
-
- for (list = etgc->children; list; list = g_list_next (list)) {
- ETableGroupContainerChildNode *child_node = (ETableGroupContainerChildNode *)list->data;
- g_object_set (child_node->child,
- "minimum_width", etgc->minimum_width - GROUP_INDENT,
- NULL);
- }
- break;
- case PROP_LENGTH_THRESHOLD:
- etgc->length_threshold = g_value_get_int (value);
- for (list = etgc->children; list; list = g_list_next (list)) {
- ETableGroupContainerChildNode *child_node = (ETableGroupContainerChildNode *)list->data;
- g_object_set (child_node->child,
- "length_threshold", etgc->length_threshold,
- NULL);
- }
- break;
- case PROP_UNIFORM_ROW_HEIGHT:
- etgc->uniform_row_height = g_value_get_boolean (value);
- for (list = etgc->children; list; list = g_list_next (list)) {
- ETableGroupContainerChildNode *child_node = (ETableGroupContainerChildNode *)list->data;
- g_object_set (child_node->child,
- "uniform_row_height", etgc->uniform_row_height,
- NULL);
- }
- break;
-
- case PROP_SELECTION_MODEL:
- if (etgc->selection_model)
- g_object_unref (etgc->selection_model);
- etgc->selection_model = E_SELECTION_MODEL(g_value_get_object (value));
- if (etgc->selection_model)
- g_object_ref (etgc->selection_model);
- for (list = etgc->children; list; list = g_list_next (list)) {
- ETableGroupContainerChildNode *child_node = (ETableGroupContainerChildNode *)list->data;
- g_object_set (child_node->child,
- "selection_model", etgc->selection_model,
- NULL);
- }
- break;
-
- case PROP_TABLE_ALTERNATING_ROW_COLORS:
- etgc->alternating_row_colors = g_value_get_boolean (value);
- for (list = etgc->children; list; list = g_list_next (list)) {
- ETableGroupContainerChildNode *child_node = (ETableGroupContainerChildNode *)list->data;
- g_object_set (child_node->child,
- "alternating_row_colors", etgc->alternating_row_colors,
- NULL);
- }
- break;
-
- case PROP_TABLE_HORIZONTAL_DRAW_GRID:
- etgc->horizontal_draw_grid = g_value_get_boolean (value);
- for (list = etgc->children; list; list = g_list_next (list)) {
- ETableGroupContainerChildNode *child_node = (ETableGroupContainerChildNode *)list->data;
- g_object_set (child_node->child,
- "horizontal_draw_grid", etgc->horizontal_draw_grid,
- NULL);
- }
- break;
-
- case PROP_TABLE_VERTICAL_DRAW_GRID:
- etgc->vertical_draw_grid = g_value_get_boolean (value);
- for (list = etgc->children; list; list = g_list_next (list)) {
- ETableGroupContainerChildNode *child_node = (ETableGroupContainerChildNode *)list->data;
- g_object_set (child_node->child,
- "vertical_draw_grid", etgc->vertical_draw_grid,
- NULL);
- }
- break;
-
- case PROP_TABLE_DRAW_FOCUS:
- etgc->draw_focus = g_value_get_boolean (value);
- for (list = etgc->children; list; list = g_list_next (list)) {
- ETableGroupContainerChildNode *child_node = (ETableGroupContainerChildNode *)list->data;
- g_object_set (child_node->child,
- "drawfocus", etgc->draw_focus,
- NULL);
- }
- break;
-
- case PROP_CURSOR_MODE:
- etgc->cursor_mode = g_value_get_int (value);
- for (list = etgc->children; list; list = g_list_next (list)) {
- ETableGroupContainerChildNode *child_node = (ETableGroupContainerChildNode *)list->data;
- g_object_set (child_node->child,
- "cursor_mode", etgc->cursor_mode,
- NULL);
- }
- break;
- default:
- break;
- }
-}
-
-static void
-etgc_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
-{
- ETableGroup *etg = E_TABLE_GROUP (object);
- ETableGroupContainer *etgc = E_TABLE_GROUP_CONTAINER (object);
-
- switch (prop_id) {
- case PROP_FROZEN:
- g_value_set_boolean (value, etg->frozen);
- break;
- case PROP_HEIGHT:
- g_value_set_double (value, etgc->height);
- break;
- case PROP_WIDTH:
- g_value_set_double (value, etgc->width);
- break;
- case PROP_MINIMUM_WIDTH:
- g_value_set_double (value, etgc->minimum_width);
- break;
- case PROP_UNIFORM_ROW_HEIGHT:
- g_value_set_boolean (value, etgc->uniform_row_height);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-etgc_class_init (GObjectClass *object_class)
-{
- GnomeCanvasItemClass *item_class = (GnomeCanvasItemClass *) object_class;
- ETableGroupClass *e_group_class = E_TABLE_GROUP_CLASS(object_class);
-
- object_class->dispose = etgc_dispose;
- object_class->set_property = etgc_set_property;
- object_class->get_property = etgc_get_property;
-
- item_class->event = etgc_event;
- item_class->realize = etgc_realize;
- item_class->unrealize = etgc_unrealize;
-
- etgc_parent_class = g_type_class_ref (PARENT_TYPE);
-
- e_group_class->add = etgc_add;
- e_group_class->add_array = etgc_add_array;
- e_group_class->add_all = etgc_add_all;
- e_group_class->remove = etgc_remove;
- e_group_class->increment = etgc_increment;
- e_group_class->decrement = etgc_decrement;
- e_group_class->row_count = etgc_row_count;
- e_group_class->set_focus = etgc_set_focus;
- e_group_class->get_focus_column = etgc_get_focus_column;
- e_group_class->get_printable = etgc_get_printable;
- e_group_class->compute_location = etgc_compute_location;
- e_group_class->get_cell_geometry = etgc_get_cell_geometry;
-
- g_object_class_install_property (object_class, PROP_TABLE_ALTERNATING_ROW_COLORS,
- g_param_spec_boolean ("alternating_row_colors",
- _( "Alternating Row Colors" ),
- _( "Alternating Row Colors" ),
- FALSE,
- G_PARAM_WRITABLE));
-
- g_object_class_install_property (object_class, PROP_TABLE_HORIZONTAL_DRAW_GRID,
- g_param_spec_boolean ("horizontal_draw_grid",
- _( "Horizontal Draw Grid" ),
- _( "Horizontal Draw Grid" ),
- FALSE,
- G_PARAM_WRITABLE));
-
- g_object_class_install_property (object_class, PROP_TABLE_VERTICAL_DRAW_GRID,
- g_param_spec_boolean ("vertical_draw_grid",
- _( "Vertical Draw Grid" ),
- _( "Vertical Draw Grid" ),
- FALSE,
- G_PARAM_WRITABLE));
-
- g_object_class_install_property (object_class, PROP_TABLE_DRAW_FOCUS,
- g_param_spec_boolean ("drawfocus",
- _( "Draw focus" ),
- _( "Draw focus" ),
- FALSE,
- G_PARAM_WRITABLE));
-
- g_object_class_install_property (object_class, PROP_CURSOR_MODE,
- g_param_spec_int ("cursor_mode",
- _( "Cursor mode" ),
- _( "Cursor mode" ),
- E_CURSOR_LINE, E_CURSOR_SPREADSHEET, E_CURSOR_LINE,
- G_PARAM_WRITABLE));
-
- g_object_class_install_property (object_class, PROP_SELECTION_MODEL,
- g_param_spec_object ("selection_model",
- _( "Selection model" ),
- _( "Selection model" ),
- E_SELECTION_MODEL_TYPE,
- G_PARAM_WRITABLE));
-
- g_object_class_install_property (object_class, PROP_LENGTH_THRESHOLD,
- g_param_spec_int ("length_threshold",
- _( "Length Threshold" ),
- _( "Length Threshold" ),
- -1, G_MAXINT, 0,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class, PROP_UNIFORM_ROW_HEIGHT,
- g_param_spec_boolean ("uniform_row_height",
- _( "Uniform row height" ),
- _( "Uniform row height" ),
- FALSE,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class, PROP_FROZEN,
- g_param_spec_boolean ("frozen",
- _( "Frozen" ),
- _( "Frozen" ),
- FALSE,
- G_PARAM_READWRITE));
-
- 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_WIDTH,
- g_param_spec_double ("width",
- _( "Width" ),
- _( "Width" ),
- 0.0, G_MAXDOUBLE, 0.0,
- G_PARAM_READWRITE));
-
- 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));
-}
-
-static void
-etgc_reflow (GnomeCanvasItem *item, gint flags)
-{
- ETableGroupContainer *etgc = E_TABLE_GROUP_CONTAINER(item);
- gboolean frozen;
-
- g_object_get (etgc,
- "frozen", &frozen,
- NULL);
-
- if (frozen)
- return;
-
-
- if (GTK_OBJECT_FLAGS(etgc)& GNOME_CANVAS_ITEM_REALIZED){
- gdouble running_height = 0;
- gdouble running_width = 0;
- gdouble old_height;
- gdouble old_width;
-
- old_height = etgc->height;
- old_width = etgc->width;
- if (etgc->children == NULL){
- } else {
- GList *list;
- gdouble extra_height = 0;
- gdouble item_height = 0;
- gdouble item_width = 0;
-
- if (etgc->font)
- extra_height += etgc->font->ascent + etgc->font->descent + BUTTON_PADDING * 2;
-
- extra_height = MAX(extra_height, BUTTON_HEIGHT + BUTTON_PADDING * 2);
-
- running_height = extra_height;
-
- for ( list = etgc->children; list; list = g_list_next (list)){
- ETableGroupContainerChildNode *child_node = (ETableGroupContainerChildNode *) list->data;
- ETableGroup *child = child_node->child;
-
- g_object_get (child,
- "width", &item_width,
- NULL);
-
- if (item_width > running_width)
- running_width = item_width;
- }
- for ( list = etgc->children; list; list = g_list_next (list)){
- ETableGroupContainerChildNode *child_node = (ETableGroupContainerChildNode *) list->data;
- ETableGroup *child = child_node->child;
- g_object_get (child,
- "height", &item_height,
- NULL);
-
- e_canvas_item_move_absolute (GNOME_CANVAS_ITEM(child_node->text),
- GROUP_INDENT,
- running_height - BUTTON_PADDING);
-
- e_canvas_item_move_absolute (GNOME_CANVAS_ITEM(child),
- GROUP_INDENT,
- running_height);
-
- gnome_canvas_item_set (GNOME_CANVAS_ITEM(child_node->rect),
- "x1", (double) 0,
- "x2", (double) running_width + GROUP_INDENT,
- "y1", (double) running_height - extra_height,
- "y2", (double) running_height + item_height,
- NULL);
-
- running_height += item_height + extra_height;
- }
- running_height -= extra_height;
- }
- if (running_height != old_height || running_width != old_width) {
- etgc->height = running_height;
- etgc->width = running_width;
- e_canvas_item_request_parent_reflow (item);
- }
- }
-}
-
-static void
-etgc_init (GtkObject *object)
-{
- ETableGroupContainer *container = E_TABLE_GROUP_CONTAINER(object);
- container->children = FALSE;
-
- e_canvas_item_set_reflow_callback (GNOME_CANVAS_ITEM(object), etgc_reflow);
-
- container->alternating_row_colors = 1;
- container->horizontal_draw_grid = 1;
- container->vertical_draw_grid = 1;
- container->draw_focus = 1;
- container->cursor_mode = E_CURSOR_SIMPLE;
- container->length_threshold = -1;
- container->selection_model = NULL;
- container->uniform_row_height = FALSE;
-}
-
-E_MAKE_TYPE (e_table_group_container, "ETableGroupContainer", ETableGroupContainer, etgc_class_init, etgc_init, PARENT_TYPE)
-
-void
-e_table_group_apply_to_leafs (ETableGroup *etg, ETableGroupLeafFn fn, void *closure)
-{
- if (E_IS_TABLE_GROUP_CONTAINER (etg)){
- ETableGroupContainer *etgc = E_TABLE_GROUP_CONTAINER (etg);
- GList *list = etgc->children;
-
- /* Protect from unrefs in the callback functions */
- g_object_ref (etg);
-
- for (list = etgc->children; list; list = list->next){
- ETableGroupContainerChildNode *child_node = list->data;
-
- e_table_group_apply_to_leafs (child_node->child, fn, closure);
- }
-
- g_object_unref (etg);
- } else if (E_IS_TABLE_GROUP_LEAF (etg)){
- (*fn) (E_TABLE_GROUP_LEAF (etg)->item, closure);
- } else {
- g_error ("Unknown ETableGroup found: %s",
- g_type_name (G_TYPE_FROM_INSTANCE (etg)));
- }
-}
-
-
-typedef struct {
- ETableGroupContainer *etgc;
- GList *child;
- EPrintable *child_printable;
-} ETGCPrintContext;
-
-#if 0
-#define CHECK(x) if((x) == -1) return -1;
-
-static gint
-gp_draw_rect (GnomePrintContext *context, gdouble x, gdouble y, gdouble width, gdouble height, gdouble r, gdouble g, gdouble b)
-{
- CHECK(gnome_print_moveto(context, x, y));
- CHECK(gnome_print_lineto(context, x + width, y));
- CHECK(gnome_print_lineto(context, x + width, y - height));
- CHECK(gnome_print_lineto(context, x, y - height));
- CHECK(gnome_print_lineto(context, x, y));
- return gnome_print_fill(context);
-}
-#endif
-
-#define CHECK(x) if((x) == -1) return -1;
-
-static gint
-gp_draw_rect (GnomePrintContext *context, gdouble x, gdouble y, gdouble width, gdouble height)
-{
- CHECK(gnome_print_moveto(context, x, y));
- CHECK(gnome_print_lineto(context, x + width, y));
- CHECK(gnome_print_lineto(context, x + width, y - height));
- CHECK(gnome_print_lineto(context, x, y - height));
- CHECK(gnome_print_lineto(context, x, y));
- return gnome_print_fill(context);
-}
-
-#define TEXT_HEIGHT (12)
-#define TEXT_AREA_HEIGHT (TEXT_HEIGHT + 4)
-
-static void
-e_table_group_container_print_page (EPrintable *ep,
- GnomePrintContext *context,
- gdouble width,
- gdouble height,
- gboolean quantize,
- ETGCPrintContext *groupcontext)
-{
- gdouble yd = height;
- gdouble child_height;
- ETableGroupContainerChildNode *child_node;
- GList *child;
- EPrintable *child_printable;
- gchar *string;
- GnomeFont *font = gnome_font_find ("Helvetica", TEXT_HEIGHT);
-
- child_printable = groupcontext->child_printable;
- child = groupcontext->child;
-
- if (child_printable) {
- if (child)
- child_node = child->data;
- else
- child_node = NULL;
- g_object_ref (child_printable);
- } else {
- if (!child) {
- return;
- } else {
- child_node = child->data;
- child_printable = e_table_group_get_printable(child_node->child);
- if (child_printable)
- g_object_ref (child_printable);
- e_printable_reset(child_printable);
- }
- }
-
- while (1) {
- child_height = e_printable_height(child_printable, context, width - 36, yd - TEXT_AREA_HEIGHT, quantize);
-
- if (gnome_print_gsave(context) == -1)
- /* FIXME */;
- if (gnome_print_moveto(context, 0, yd - child_height - TEXT_AREA_HEIGHT) == -1)
- /* FIXME */;
- if (gnome_print_lineto(context, 36, yd - child_height - TEXT_AREA_HEIGHT) == -1)
- /* FIXME */;
- if (gnome_print_lineto(context, 36, yd - TEXT_AREA_HEIGHT) == -1)
- /* FIXME */;
- if (gnome_print_lineto(context, width, yd - TEXT_AREA_HEIGHT) == -1)
- /* FIXME */;
- if (gnome_print_lineto(context, width, yd) == -1)
- /* FIXME */;
- if (gnome_print_lineto(context, 0, yd) == -1)
- /* FIXME */;
- if (gnome_print_lineto(context, 0, yd - child_height - TEXT_AREA_HEIGHT) == -1)
- /* FIXME */;
- if (gnome_print_setrgbcolor(context, .7, .7, .7) == -1)
- /* FIXME */;
- if (gnome_print_fill(context) == -1)
- /* FIXME */;
- if (gnome_print_grestore(context) == -1)
- /* FIXME */;
-
- if (gnome_print_gsave(context) == -1)
- /* FIXME */;
- if (gnome_print_moveto(context, 0, yd - TEXT_AREA_HEIGHT) == -1)
- /* FIXME */;
- if (gnome_print_lineto(context, width, yd - TEXT_AREA_HEIGHT) == -1)
- /* FIXME */;
- if (gnome_print_lineto(context, width, yd) == -1)
- /* FIXME */;
- if (gnome_print_lineto(context, 0, yd) == -1)
- /* FIXME */;
- if (gnome_print_lineto(context, 0, yd - TEXT_AREA_HEIGHT) == -1)
- /* FIXME */;
- if (gnome_print_clip(context) == -1)
- /* FIXME */;
-
- if (gnome_print_moveto(context, 2, yd - (TEXT_AREA_HEIGHT + gnome_font_get_ascender(font) - gnome_font_get_descender(font)) / 2) == -1)
- /* FIXME */;
- if (gnome_print_setfont(context, font))
- /* FIXME */;
- if (groupcontext->etgc->ecol->text)
- string = g_strdup_printf ("%s : %s (%d item%s)",
- groupcontext->etgc->ecol->text,
- child_node->string,
- (gint) child_node->count,
- child_node->count == 1 ? "" : "s");
- else
- string = g_strdup_printf ("%s (%d item%s)",
- child_node->string,
- (gint) child_node->count,
- child_node->count == 1 ? "" : "s");
- if (gnome_print_show(context, string))
- /* FIXME */;
- g_free(string);
- if (gnome_print_grestore(context) == -1)
- /* FIXME */;
-
- if (gnome_print_gsave(context) == -1)
- /* FIXME */;
- if (gnome_print_translate(context, 36, yd - TEXT_AREA_HEIGHT - child_height) == -1)
- /* FIXME */;
- if (gnome_print_moveto(context, 0, 0) == -1)
- /* FIXME */;
- if (gnome_print_lineto(context, width - 36, 0) == -1)
- /* FIXME */;
- if (gnome_print_lineto(context, width - 36, child_height) == -1)
- /* FIXME */;
- if (gnome_print_lineto(context, 0, child_height) == -1)
- /* FIXME */;
- if (gnome_print_lineto(context, 0, 0) == -1)
- /* FIXME */;
- if (gnome_print_clip(context) == -1)
- /* FIXME */;
- e_printable_print_page(child_printable, context, width - 36, child_height, quantize);
- if (gnome_print_grestore(context) == -1)
- /* FIXME */;
-
- gp_draw_rect(context, 0, yd - child_height - TEXT_AREA_HEIGHT + 1, width, 1);
- gp_draw_rect(context, width - 1, yd, 1, yd - child_height - TEXT_AREA_HEIGHT);
- gp_draw_rect(context, 0, yd, 1, yd - child_height - TEXT_AREA_HEIGHT);
-
- yd -= child_height + TEXT_AREA_HEIGHT;
-
- if (e_printable_data_left(child_printable))
- break;
-
- child = child->next;
- if (!child) {
- child_printable = NULL;
- break;
- }
-
- child_node = child->data;
- if (child_printable)
- g_object_unref (child_printable);
- child_printable = e_table_group_get_printable(child_node->child);
- if (child_printable)
- g_object_ref (child_printable);
- e_printable_reset(child_printable);
- }
-
- gp_draw_rect(context, 0, height, width, 1);
-
- if (groupcontext->child_printable)
- g_object_unref (groupcontext->child_printable);
- groupcontext->child_printable = child_printable;
- groupcontext->child = child;
-
-}
-
-static gboolean
-e_table_group_container_data_left (EPrintable *ep,
- ETGCPrintContext *groupcontext)
-{
- g_signal_stop_emission_by_name(ep, "data_left");
- return groupcontext->child != NULL;
-}
-
-static void
-e_table_group_container_reset (EPrintable *ep,
- ETGCPrintContext *groupcontext)
-{
- groupcontext->child = groupcontext->etgc->children;
- if (groupcontext->child_printable)
- g_object_unref (groupcontext->child_printable);
- groupcontext->child_printable = NULL;
-}
-
-static gdouble
-e_table_group_container_height (EPrintable *ep,
- GnomePrintContext *context,
- gdouble width,
- gdouble max_height,
- gboolean quantize,
- ETGCPrintContext *groupcontext)
-{
- gdouble height = 0;
- gdouble child_height;
- gdouble yd = max_height;
- ETableGroupContainerChildNode *child_node;
- GList *child;
- EPrintable *child_printable;
-
- child_printable = groupcontext->child_printable;
- child = groupcontext->child;
-
- if (child_printable)
- g_object_ref (child_printable);
- else {
- if (!child) {
- g_signal_stop_emission_by_name(ep, "height");
- return 0;
- } else {
- child_node = child->data;
- child_printable = e_table_group_get_printable(child_node->child);
- if (child_printable)
- g_object_ref (child_printable);
- e_printable_reset(child_printable);
- }
- }
-
- if (yd != -1 && yd < TEXT_AREA_HEIGHT)
- return 0;
-
- while (1) {
- child_height = e_printable_height(child_printable, context, width - 36, yd - (yd == -1 ? 0 : TEXT_AREA_HEIGHT), quantize);
-
- height += child_height + TEXT_AREA_HEIGHT;
-
- if (yd != -1) {
- if (!e_printable_will_fit(child_printable, context, width - 36, yd - (yd == -1 ? 0 : TEXT_AREA_HEIGHT), quantize)) {
- break;
- }
-
- yd -= child_height + TEXT_AREA_HEIGHT;
- }
-
- child = child->next;
- if (!child) {
- break;
- }
-
- child_node = child->data;
- if (child_printable)
- g_object_unref (child_printable);
- child_printable = e_table_group_get_printable(child_node->child);
- if (child_printable)
- g_object_ref (child_printable);
- e_printable_reset(child_printable);
- }
- if (child_printable)
- g_object_unref (child_printable);
- g_signal_stop_emission_by_name(ep, "height");
- return height;
-}
-
-static gboolean
-e_table_group_container_will_fit (EPrintable *ep,
- GnomePrintContext *context,
- gdouble width,
- gdouble max_height,
- gboolean quantize,
- ETGCPrintContext *groupcontext)
-{
- gboolean will_fit = TRUE;
- gdouble child_height;
- gdouble yd = max_height;
- ETableGroupContainerChildNode *child_node;
- GList *child;
- EPrintable *child_printable;
-
- child_printable = groupcontext->child_printable;
- child = groupcontext->child;
-
- if (child_printable)
- g_object_ref (child_printable);
- else {
- if (!child) {
- g_signal_stop_emission_by_name(ep, "will_fit");
- return will_fit;
- } else {
- child_node = child->data;
- child_printable = e_table_group_get_printable(child_node->child);
- if (child_printable)
- g_object_ref (child_printable);
- e_printable_reset(child_printable);
- }
- }
-
- if (yd != -1 && yd < TEXT_AREA_HEIGHT)
- will_fit = FALSE;
- else {
- while (1) {
- child_height = e_printable_height(child_printable, context, width - 36, yd - (yd == -1 ? 0 : TEXT_AREA_HEIGHT), quantize);
-
- if (yd != -1) {
- if (!e_printable_will_fit(child_printable, context, width - 36, yd - (yd == -1 ? 0 : TEXT_AREA_HEIGHT), quantize)) {
- will_fit = FALSE;
- break;
- }
-
- yd -= child_height + TEXT_AREA_HEIGHT;
- }
-
- child = child->next;
- if (!child) {
- break;
- }
-
- child_node = child->data;
- if (child_printable)
- g_object_unref (child_printable);
- child_printable = e_table_group_get_printable(child_node->child);
- if (child_printable)
- g_object_ref (child_printable);
- e_printable_reset(child_printable);
- }
- }
-
- if (child_printable)
- g_object_unref (child_printable);
-
- g_signal_stop_emission_by_name(ep, "will_fit");
- return will_fit;
-}
-
-static void
-e_table_group_container_printable_destroy (gpointer data,
- GObject *where_object_was)
-
-{
- ETGCPrintContext *groupcontext = data;
-
- g_object_unref (groupcontext->etgc);
- if (groupcontext->child_printable)
- g_object_ref (groupcontext->child_printable);
- g_free(groupcontext);
-}
-
-static EPrintable *
-etgc_get_printable (ETableGroup *etg)
-{
- ETableGroupContainer *etgc = E_TABLE_GROUP_CONTAINER(etg);
- EPrintable *printable = e_printable_new();
- ETGCPrintContext *groupcontext;
-
- groupcontext = g_new(ETGCPrintContext, 1);
- groupcontext->etgc = etgc;
- g_object_ref (etgc);
- groupcontext->child = etgc->children;
- groupcontext->child_printable = NULL;
-
- g_signal_connect (printable,
- "print_page",
- G_CALLBACK(e_table_group_container_print_page),
- groupcontext);
- g_signal_connect (printable,
- "data_left",
- G_CALLBACK(e_table_group_container_data_left),
- groupcontext);
- g_signal_connect (printable,
- "reset",
- G_CALLBACK(e_table_group_container_reset),
- groupcontext);
- g_signal_connect (printable,
- "height",
- G_CALLBACK(e_table_group_container_height),
- groupcontext);
- g_signal_connect (printable,
- "will_fit",
- G_CALLBACK(e_table_group_container_will_fit),
- groupcontext);
- g_object_weak_ref (G_OBJECT (printable),
- e_table_group_container_printable_destroy,
- groupcontext);
-
- return printable;
-}
diff --git a/widgets/table/e-table-group-container.h b/widgets/table/e-table-group-container.h
deleted file mode 100644
index d1809e48fd..0000000000
--- a/widgets/table/e-table-group-container.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-group-container.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_TABLE_GROUP_CONTAINER_H_
-#define _E_TABLE_GROUP_CONTAINER_H_
-
-#include <libgnomecanvas/gnome-canvas.h>
-#include <gal/e-table/e-table-model.h>
-#include <gal/e-table/e-table-header.h>
-#include <gal/e-table/e-table-group.h>
-#include <gal/e-table/e-table-item.h>
-
-G_BEGIN_DECLS
-
-#define E_TABLE_GROUP_CONTAINER_TYPE (e_table_group_container_get_type ())
-#define E_TABLE_GROUP_CONTAINER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TABLE_GROUP_CONTAINER_TYPE, ETableGroupContainer))
-#define E_TABLE_GROUP_CONTAINER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TABLE_GROUP_CONTAINER_TYPE, ETableGroupContainerClass))
-#define E_IS_TABLE_GROUP_CONTAINER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TABLE_GROUP_CONTAINER_TYPE))
-#define E_IS_TABLE_GROUP_CONTAINER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TABLE_GROUP_CONTAINER_TYPE))
-
-typedef struct {
- ETableGroup group;
-
- /*
- * The ETableCol used to group this set
- */
- ETableCol *ecol;
- gint ascending;
-
- /*
- * List of ETableGroups we stack
- */
- GList *children;
-
- /*
- * The canvas rectangle that contains the children
- */
- GnomeCanvasItem *rect;
-
- GdkFont *font;
-
- gdouble width, height, minimum_width;
-
- ETableSortInfo *sort_info;
- int n;
- int length_threshold;
-
- ESelectionModel *selection_model;
-
- guint alternating_row_colors : 1;
- guint horizontal_draw_grid : 1;
- guint vertical_draw_grid : 1;
- guint draw_focus : 1;
- guint uniform_row_height : 1;
- ECursorMode cursor_mode;
-
- /*
- * State: the ETableGroup is open or closed
- */
- guint open:1;
-} ETableGroupContainer;
-
-typedef struct {
- ETableGroupClass parent_class;
-} ETableGroupContainerClass;
-
-typedef struct {
- ETableGroup *child;
- void *key;
- char *string;
- GnomeCanvasItem *text;
- GnomeCanvasItem *rect;
- gint count;
-} ETableGroupContainerChildNode;
-
-
-ETableGroup *e_table_group_container_new (GnomeCanvasGroup *parent, ETableHeader *full_header, ETableHeader *header,
- ETableModel *model, ETableSortInfo *sort_info, int n);
-void e_table_group_container_construct (GnomeCanvasGroup *parent, ETableGroupContainer *etgc,
- ETableHeader *full_header,
- ETableHeader *header,
- ETableModel *model, ETableSortInfo *sort_info, int n);
-
-GType e_table_group_container_get_type (void);
-
-G_END_DECLS
-
-#endif /* _E_TABLE_GROUP_CONTAINER_H_ */
diff --git a/widgets/table/e-table-group-leaf.c b/widgets/table/e-table-group-leaf.c
deleted file mode 100644
index 083345ed74..0000000000
--- a/widgets/table/e-table-group-leaf.c
+++ /dev/null
@@ -1,686 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-group-leaf.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <gtk/gtksignal.h>
-#include <libgnomecanvas/gnome-canvas-rect-ellipse.h>
-#include "e-table-group-leaf.h"
-#include "e-table-item.h"
-#include "e-table-sorted-variable.h"
-#include "e-table-sorted.h"
-#include "gal/util/e-util.h"
-#include "gal/util/e-i18n.h"
-#include "gal/widgets/e-canvas.h"
-
-#define PARENT_TYPE e_table_group_get_type ()
-
-static GnomeCanvasGroupClass *etgl_parent_class;
-
-/* The arguments we take */
-enum {
- PROP_0,
- PROP_HEIGHT,
- PROP_WIDTH,
- PROP_MINIMUM_WIDTH,
- PROP_FROZEN,
- PROP_TABLE_ALTERNATING_ROW_COLORS,
- PROP_TABLE_HORIZONTAL_DRAW_GRID,
- PROP_TABLE_VERTICAL_DRAW_GRID,
- PROP_TABLE_DRAW_FOCUS,
- PROP_CURSOR_MODE,
- PROP_LENGTH_THRESHOLD,
- PROP_SELECTION_MODEL,
- PROP_UNIFORM_ROW_HEIGHT
-};
-
-static void
-etgl_dispose (GObject *object)
-{
- ETableGroupLeaf *etgl = E_TABLE_GROUP_LEAF(object);
-
- if (etgl->ets) {
- g_object_unref (etgl->ets);
- etgl->ets = NULL;
- }
-
- if (etgl->item) {
- if (etgl->etgl_cursor_change_id != 0)
- g_signal_handler_disconnect (etgl->item,
- etgl->etgl_cursor_change_id);
- if (etgl->etgl_cursor_activated_id != 0)
- g_signal_handler_disconnect (etgl->item,
- etgl->etgl_cursor_activated_id);
- if (etgl->etgl_double_click_id != 0)
- g_signal_handler_disconnect (etgl->item,
- etgl->etgl_double_click_id);
- if (etgl->etgl_right_click_id != 0)
- g_signal_handler_disconnect (etgl->item,
- etgl->etgl_right_click_id);
- if (etgl->etgl_click_id != 0)
- g_signal_handler_disconnect (etgl->item,
- etgl->etgl_click_id);
- if (etgl->etgl_key_press_id != 0)
- g_signal_handler_disconnect (etgl->item,
- etgl->etgl_key_press_id);
- if (etgl->etgl_start_drag_id != 0)
- g_signal_handler_disconnect (etgl->item,
- etgl->etgl_start_drag_id);
-
- etgl->etgl_cursor_change_id = 0;
- etgl->etgl_cursor_activated_id = 0;
- etgl->etgl_double_click_id = 0;
- etgl->etgl_right_click_id = 0;
- etgl->etgl_click_id = 0;
- etgl->etgl_key_press_id = 0;
- etgl->etgl_start_drag_id = 0;
-
- gtk_object_destroy (GTK_OBJECT(etgl->item));
- etgl->item = NULL;
- }
-
- if (etgl->selection_model) {
- g_object_unref (etgl->selection_model);
- etgl->selection_model = NULL;
- }
-
- if (G_OBJECT_CLASS (etgl_parent_class)->dispose)
- G_OBJECT_CLASS (etgl_parent_class)->dispose (object);
-}
-
-static void
-e_table_group_leaf_construct (GnomeCanvasGroup *parent,
- ETableGroupLeaf *etgl,
- ETableHeader *full_header,
- ETableHeader *header,
- ETableModel *model,
- ETableSortInfo *sort_info)
-{
- etgl->is_grouped = e_table_sort_info_grouping_get_count(sort_info) > 0 ? TRUE : FALSE;
-
- if (etgl->is_grouped)
- etgl->ets = E_TABLE_SUBSET(e_table_sorted_variable_new (model,
- full_header,
- sort_info));
- else
- etgl->ets = E_TABLE_SUBSET(e_table_sorted_new (model,
- full_header,
- sort_info));
-
- e_table_group_construct (parent, E_TABLE_GROUP (etgl), full_header, header, model);
-}
-
-/**
- * e_table_group_leaf_new
- * @parent: The %GnomeCanvasGroup to create a child of.
- * @full_header: The full header of the %ETable.
- * @header: The current header of the %ETable.
- * @model: The %ETableModel of the %ETable.
- * @sort_info: The %ETableSortInfo of the %ETable.
- *
- * %ETableGroupLeaf is an %ETableGroup which simply contains an
- * %ETableItem.
- *
- * Returns: The new %ETableGroupLeaf.
- */
-ETableGroup *
-e_table_group_leaf_new (GnomeCanvasGroup *parent,
- ETableHeader *full_header,
- ETableHeader *header,
- ETableModel *model,
- ETableSortInfo *sort_info)
-{
- ETableGroupLeaf *etgl;
-
- g_return_val_if_fail (parent != NULL, NULL);
-
- etgl = g_object_new (E_TABLE_GROUP_LEAF_TYPE, NULL);
-
- e_table_group_leaf_construct (parent, etgl, full_header,
- header, model, sort_info);
- return E_TABLE_GROUP (etgl);
-}
-
-static void
-etgl_cursor_change (GtkObject *object, gint row, ETableGroupLeaf *etgl)
-{
- if (row < E_TABLE_SUBSET(etgl->ets)->n_map)
- e_table_group_cursor_change (E_TABLE_GROUP(etgl),
- E_TABLE_SUBSET(etgl->ets)->map_table[row]);
-}
-
-static void
-etgl_cursor_activated (GtkObject *object, gint view_row, ETableGroupLeaf *etgl)
-{
- if (view_row < E_TABLE_SUBSET(etgl->ets)->n_map)
- e_table_group_cursor_activated (E_TABLE_GROUP(etgl),
- E_TABLE_SUBSET(etgl->ets)->map_table[view_row]);
-}
-
-static void
-etgl_double_click (GtkObject *object, gint model_row, gint model_col, GdkEvent *event,
- ETableGroupLeaf *etgl)
-{
- e_table_group_double_click (E_TABLE_GROUP(etgl), model_row, model_col, event);
-}
-
-static gint
-etgl_key_press (GtkObject *object, gint row, gint col, GdkEvent *event, ETableGroupLeaf *etgl)
-{
- if (row < E_TABLE_SUBSET(etgl->ets)->n_map && row >= 0)
- return e_table_group_key_press (E_TABLE_GROUP(etgl),
- E_TABLE_SUBSET(etgl->ets)->map_table[row],
- col,
- event);
- else
- return 0;
-}
-
-static gint
-etgl_start_drag (GtkObject *object, gint model_row, gint model_col, GdkEvent *event,
- ETableGroupLeaf *etgl)
-{
- return e_table_group_start_drag (E_TABLE_GROUP(etgl), model_row, model_col, event);
-}
-
-static gint
-etgl_right_click (GtkObject *object, gint view_row, gint model_col, GdkEvent *event,
- ETableGroupLeaf *etgl)
-{
- if (view_row < E_TABLE_SUBSET(etgl->ets)->n_map)
- return e_table_group_right_click (E_TABLE_GROUP(etgl),
- E_TABLE_SUBSET(etgl->ets)->map_table[view_row],
- model_col,
- event);
- else
- return 0;
-}
-
-static gint
-etgl_click (GtkObject *object, gint row, gint col, GdkEvent *event, ETableGroupLeaf *etgl)
-{
- if (row < E_TABLE_SUBSET(etgl->ets)->n_map)
- return e_table_group_click (E_TABLE_GROUP(etgl),
- E_TABLE_SUBSET(etgl->ets)->map_table[row],
- col,
- event);
- else
- return 0;
-}
-
-static void
-etgl_reflow (GnomeCanvasItem *item, gint flags)
-{
- ETableGroupLeaf *leaf = E_TABLE_GROUP_LEAF(item);
-
- g_object_get(leaf->item,
- "height", &leaf->height,
- NULL);
- g_object_get(leaf->item,
- "width", &leaf->width,
- NULL);
-
- e_canvas_item_request_parent_reflow (item);
-}
-
-static void
-etgl_realize (GnomeCanvasItem *item)
-{
- ETableGroupLeaf *etgl = E_TABLE_GROUP_LEAF(item);
-
- if (GNOME_CANVAS_ITEM_CLASS (etgl_parent_class)->realize)
- GNOME_CANVAS_ITEM_CLASS (etgl_parent_class)->realize (item);
-
- etgl->item = E_TABLE_ITEM(gnome_canvas_item_new (
- GNOME_CANVAS_GROUP(etgl),
- e_table_item_get_type (),
- "ETableHeader", E_TABLE_GROUP(etgl)->header,
- "ETableModel", etgl->ets,
- "alternating_row_colors", etgl->alternating_row_colors,
- "horizontal_draw_grid", etgl->horizontal_draw_grid,
- "vertical_draw_grid", etgl->vertical_draw_grid,
- "drawfocus", etgl->draw_focus,
- "cursor_mode", etgl->cursor_mode,
- "minimum_width", etgl->minimum_width,
- "length_threshold", etgl->length_threshold,
- "selection_model", etgl->selection_model,
- "uniform_row_height", etgl->uniform_row_height,
- NULL));
-
- etgl->etgl_cursor_change_id = g_signal_connect (etgl->item,
- "cursor_change",
- G_CALLBACK(etgl_cursor_change),
- etgl);
- etgl->etgl_cursor_activated_id = g_signal_connect (etgl->item,
- "cursor_activated",
- G_CALLBACK(etgl_cursor_activated),
- etgl);
- etgl->etgl_double_click_id = g_signal_connect (etgl->item,
- "double_click",
- G_CALLBACK(etgl_double_click),
- etgl);
-
- etgl->etgl_right_click_id = g_signal_connect (etgl->item,
- "right_click",
- G_CALLBACK(etgl_right_click),
- etgl);
- etgl->etgl_click_id = g_signal_connect (etgl->item,
- "click",
- G_CALLBACK(etgl_click),
- etgl);
- etgl->etgl_key_press_id = g_signal_connect (etgl->item,
- "key_press",
- G_CALLBACK(etgl_key_press),
- etgl);
- etgl->etgl_start_drag_id = g_signal_connect (etgl->item,
- "start_drag",
- G_CALLBACK(etgl_start_drag),
- etgl);
-
- e_canvas_item_request_reflow(item);
-}
-
-static void
-etgl_add (ETableGroup *etg, gint row)
-{
- ETableGroupLeaf *etgl = E_TABLE_GROUP_LEAF (etg);
-
- if (E_IS_TABLE_SUBSET_VARIABLE(etgl->ets)) {
- e_table_subset_variable_add (E_TABLE_SUBSET_VARIABLE(etgl->ets), row);
- }
-}
-
-static void
-etgl_add_array (ETableGroup *etg, const gint *array, gint count)
-{
- ETableGroupLeaf *etgl = E_TABLE_GROUP_LEAF (etg);
-
- if (E_IS_TABLE_SUBSET_VARIABLE(etgl->ets)) {
- e_table_subset_variable_add_array (E_TABLE_SUBSET_VARIABLE(etgl->ets), array, count);
- }
-}
-
-static void
-etgl_add_all (ETableGroup *etg)
-{
- ETableGroupLeaf *etgl = E_TABLE_GROUP_LEAF (etg);
-
- if (E_IS_TABLE_SUBSET_VARIABLE(etgl->ets)) {
- e_table_subset_variable_add_all (E_TABLE_SUBSET_VARIABLE(etgl->ets));
- }
-}
-
-static gboolean
-etgl_remove (ETableGroup *etg, gint row)
-{
- ETableGroupLeaf *etgl = E_TABLE_GROUP_LEAF (etg);
-
- if (E_IS_TABLE_SUBSET_VARIABLE(etgl->ets)) {
- return e_table_subset_variable_remove (E_TABLE_SUBSET_VARIABLE(etgl->ets), row);
- }
- return FALSE;
-}
-
-static void
-etgl_increment (ETableGroup *etg, gint position, gint amount)
-{
- ETableGroupLeaf *etgl = E_TABLE_GROUP_LEAF (etg);
-
- if (E_IS_TABLE_SUBSET_VARIABLE(etgl->ets)) {
- e_table_subset_variable_increment (E_TABLE_SUBSET_VARIABLE(etgl->ets), position, amount);
- }
-}
-
-static void
-etgl_decrement (ETableGroup *etg, gint position, gint amount)
-{
- ETableGroupLeaf *etgl = E_TABLE_GROUP_LEAF (etg);
-
- if (E_IS_TABLE_SUBSET_VARIABLE(etgl->ets)) {
- e_table_subset_variable_decrement (E_TABLE_SUBSET_VARIABLE(etgl->ets), position, amount);
- }
-}
-
-static int
-etgl_row_count (ETableGroup *etg)
-{
- ETableGroupLeaf *etgl = E_TABLE_GROUP_LEAF (etg);
-
- return e_table_model_row_count(E_TABLE_MODEL(etgl->ets));
-}
-
-static void
-etgl_set_focus (ETableGroup *etg, EFocus direction, gint view_col)
-{
- ETableGroupLeaf *etgl = E_TABLE_GROUP_LEAF (etg);
-
- if (direction == E_FOCUS_END) {
- e_table_item_set_cursor (etgl->item, view_col, e_table_model_row_count(E_TABLE_MODEL(etgl->ets)) - 1);
- } else {
- e_table_item_set_cursor (etgl->item, view_col, 0);
- }
-}
-
-static gint
-etgl_get_focus_column (ETableGroup *etg)
-{
- ETableGroupLeaf *etgl = E_TABLE_GROUP_LEAF (etg);
-
- return e_table_item_get_focused_column (etgl->item);
-}
-
-static EPrintable *
-etgl_get_printable (ETableGroup *etg)
-{
- ETableGroupLeaf *etgl = E_TABLE_GROUP_LEAF (etg);
-
- return e_table_item_get_printable (etgl->item);
-}
-
-static void
-etgl_compute_location (ETableGroup *etg, int *x, int *y, int *row, int *col)
-{
- ETableGroupLeaf *etgl = E_TABLE_GROUP_LEAF (etg);
-
- e_table_item_compute_location (etgl->item, x, y, row, col);
-}
-
-static void
-etgl_get_cell_geometry (ETableGroup *etg, int *row, int *col, int *x, int *y, int *width, int *height)
-{
- ETableGroupLeaf *etgl = E_TABLE_GROUP_LEAF (etg);
-
- e_table_item_get_cell_geometry (etgl->item, row, col, x, y, width, height);
-}
-
-static void
-etgl_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
-{
- ETableGroup *etg = E_TABLE_GROUP (object);
- ETableGroupLeaf *etgl = E_TABLE_GROUP_LEAF (object);
-
- switch (prop_id) {
- case PROP_FROZEN:
- etg->frozen = g_value_get_boolean (value);
- break;
- case PROP_MINIMUM_WIDTH:
- case PROP_WIDTH:
- etgl->minimum_width = g_value_get_double (value);
- if (etgl->item) {
- gnome_canvas_item_set (GNOME_CANVAS_ITEM(etgl->item),
- "minimum_width", etgl->minimum_width,
- NULL);
- }
- break;
- case PROP_LENGTH_THRESHOLD:
- etgl->length_threshold = g_value_get_int (value);
- if (etgl->item) {
- gnome_canvas_item_set (GNOME_CANVAS_ITEM(etgl->item),
- "length_threshold", etgl->length_threshold,
- NULL);
- }
- break;
- case PROP_SELECTION_MODEL:
- if (etgl->selection_model)
- g_object_unref(etgl->selection_model);
- etgl->selection_model = E_SELECTION_MODEL(g_value_get_object (value));
- if (etgl->selection_model) {
- g_object_ref(etgl->selection_model);
- }
- if (etgl->item) {
- gnome_canvas_item_set (GNOME_CANVAS_ITEM(etgl->item),
- "selection_model", etgl->selection_model,
- NULL);
- }
- break;
-
- case PROP_UNIFORM_ROW_HEIGHT:
- etgl->uniform_row_height = g_value_get_boolean (value);
- if (etgl->item) {
- gnome_canvas_item_set (GNOME_CANVAS_ITEM(etgl->item),
- "uniform_row_height", etgl->uniform_row_height,
- NULL);
- }
- break;
-
- case PROP_TABLE_ALTERNATING_ROW_COLORS:
- etgl->alternating_row_colors = g_value_get_boolean (value);
- if (etgl->item) {
- gnome_canvas_item_set (GNOME_CANVAS_ITEM(etgl->item),
- "alternating_row_colors", etgl->alternating_row_colors,
- NULL);
- }
- break;
-
- case PROP_TABLE_HORIZONTAL_DRAW_GRID:
- etgl->horizontal_draw_grid = g_value_get_boolean (value);
- if (etgl->item) {
- gnome_canvas_item_set (GNOME_CANVAS_ITEM(etgl->item),
- "horizontal_draw_grid", etgl->horizontal_draw_grid,
- NULL);
- }
- break;
-
- case PROP_TABLE_VERTICAL_DRAW_GRID:
- etgl->vertical_draw_grid = g_value_get_boolean (value);
- if (etgl->item) {
- gnome_canvas_item_set (GNOME_CANVAS_ITEM(etgl->item),
- "vertical_draw_grid", etgl->vertical_draw_grid,
- NULL);
- }
- break;
-
- case PROP_TABLE_DRAW_FOCUS:
- etgl->draw_focus = g_value_get_boolean (value);
- if (etgl->item) {
- gnome_canvas_item_set (GNOME_CANVAS_ITEM(etgl->item),
- "drawfocus", etgl->draw_focus,
- NULL);
- }
- break;
-
- case PROP_CURSOR_MODE:
- etgl->cursor_mode = g_value_get_int (value);
- if (etgl->item) {
- gnome_canvas_item_set (GNOME_CANVAS_ITEM(etgl->item),
- "cursor_mode", etgl->cursor_mode,
- NULL);
- }
- break;
- default:
- break;
- }
-}
-
-static void
-etgl_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
-{
- ETableGroup *etg = E_TABLE_GROUP (object);
- ETableGroupLeaf *etgl = E_TABLE_GROUP_LEAF (object);
-
- switch (prop_id) {
- case PROP_FROZEN:
- g_value_set_boolean (value, etg->frozen);
- break;
- case PROP_HEIGHT:
- g_value_set_double (value, etgl->height);
- break;
- case PROP_WIDTH:
- g_value_set_double (value, etgl->width);
- break;
- case PROP_MINIMUM_WIDTH:
- g_value_set_double (value, etgl->minimum_width);
- break;
- case PROP_UNIFORM_ROW_HEIGHT:
- g_value_set_boolean (value, etgl->uniform_row_height);
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-etgl_class_init (GObjectClass *object_class)
-{
- GnomeCanvasItemClass *item_class = (GnomeCanvasItemClass *) object_class;
- ETableGroupClass *e_group_class = E_TABLE_GROUP_CLASS(object_class);
-
- object_class->dispose = etgl_dispose;
- object_class->set_property = etgl_set_property;
- object_class->get_property = etgl_get_property;
-
- item_class->realize = etgl_realize;
-
- etgl_parent_class = g_type_class_ref (PARENT_TYPE);
-
- e_group_class->add = etgl_add;
- e_group_class->add_array = etgl_add_array;
- e_group_class->add_all = etgl_add_all;
- e_group_class->remove = etgl_remove;
- e_group_class->increment = etgl_increment;
- e_group_class->decrement = etgl_decrement;
- e_group_class->row_count = etgl_row_count;
- e_group_class->set_focus = etgl_set_focus;
- e_group_class->get_focus_column = etgl_get_focus_column;
- e_group_class->get_printable = etgl_get_printable;
- e_group_class->compute_location = etgl_compute_location;
- e_group_class->get_cell_geometry = etgl_get_cell_geometry;
-
- g_object_class_install_property (object_class, PROP_TABLE_ALTERNATING_ROW_COLORS,
- g_param_spec_boolean ("alternating_row_colors",
- _( "Alternating Row Colors" ),
- _( "Alternating Row Colors" ),
- FALSE,
- G_PARAM_WRITABLE));
-
- g_object_class_install_property (object_class, PROP_TABLE_HORIZONTAL_DRAW_GRID,
- g_param_spec_boolean ("horizontal_draw_grid",
- _( "Horizontal Draw Grid" ),
- _( "Horizontal Draw Grid" ),
- FALSE,
- G_PARAM_WRITABLE));
-
- g_object_class_install_property (object_class, PROP_TABLE_VERTICAL_DRAW_GRID,
- g_param_spec_boolean ("vertical_draw_grid",
- _( "Vertical Draw Grid" ),
- _( "Vertical Draw Grid" ),
- FALSE,
- G_PARAM_WRITABLE));
-
- g_object_class_install_property (object_class, PROP_TABLE_DRAW_FOCUS,
- g_param_spec_boolean ("drawfocus",
- _( "Draw focus" ),
- _( "Draw focus" ),
- FALSE,
- G_PARAM_WRITABLE));
-
- g_object_class_install_property (object_class, PROP_CURSOR_MODE,
- g_param_spec_int ("cursor_mode",
- _( "Cursor mode" ),
- _( "Cursor mode" ),
- E_CURSOR_LINE, E_CURSOR_SPREADSHEET, E_CURSOR_LINE,
- G_PARAM_WRITABLE));
-
- g_object_class_install_property (object_class, PROP_LENGTH_THRESHOLD,
- g_param_spec_int ("length_threshold",
- _( "Length Threshold" ),
- _( "Length Threshold" ),
- -1, G_MAXINT, 0,
- G_PARAM_WRITABLE));
-
- g_object_class_install_property (object_class, PROP_SELECTION_MODEL,
- g_param_spec_object ("selection_model",
- _( "Selection model" ),
- _( "Selection model" ),
- E_SELECTION_MODEL_TYPE,
- G_PARAM_WRITABLE));
-
- g_object_class_install_property (object_class, PROP_HEIGHT,
- g_param_spec_double ("height",
- _( "Height" ),
- _( "Height" ),
- 0.0, G_MAXDOUBLE, 0.0,
- G_PARAM_READABLE));
-
- g_object_class_install_property (object_class, PROP_WIDTH,
- g_param_spec_double ("width",
- _( "Width" ),
- _( "Width" ),
- 0.0, G_MAXDOUBLE, 0.0,
- G_PARAM_READWRITE));
-
- 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_FROZEN,
- g_param_spec_boolean ("frozen",
- _( "Frozen" ),
- _( "Frozen" ),
- FALSE,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class, PROP_UNIFORM_ROW_HEIGHT,
- g_param_spec_boolean ("uniform_row_height",
- _( "Uniform row height" ),
- _( "Uniform row height" ),
- FALSE,
- G_PARAM_READWRITE));
-}
-
-static void
-etgl_init (GtkObject *object)
-{
- ETableGroupLeaf *etgl = E_TABLE_GROUP_LEAF (object);
-
- etgl->width = 1;
- etgl->height = 1;
- etgl->minimum_width = 0;
-
- etgl->ets = NULL;
- etgl->item = NULL;
-
- etgl->etgl_cursor_change_id = 0;
- etgl->etgl_cursor_activated_id = 0;
- etgl->etgl_double_click_id = 0;
- etgl->etgl_right_click_id = 0;
- etgl->etgl_click_id = 0;
- etgl->etgl_key_press_id = 0;
- etgl->etgl_start_drag_id = 0;
-
- etgl->alternating_row_colors = 1;
- etgl->horizontal_draw_grid = 1;
- etgl->vertical_draw_grid = 1;
- etgl->draw_focus = 1;
- etgl->cursor_mode = E_CURSOR_SIMPLE;
- etgl->length_threshold = -1;
-
- etgl->selection_model = NULL;
- etgl->uniform_row_height = FALSE;
-
- e_canvas_item_set_reflow_callback (GNOME_CANVAS_ITEM(object), etgl_reflow);
-}
-
-E_MAKE_TYPE (e_table_group_leaf, "ETableGroupLeaf", ETableGroupLeaf, etgl_class_init, etgl_init, PARENT_TYPE)
diff --git a/widgets/table/e-table-group-leaf.h b/widgets/table/e-table-group-leaf.h
deleted file mode 100644
index 74fdfd8c03..0000000000
--- a/widgets/table/e-table-group-leaf.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-group-leaf.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_TABLE_GROUP_LEAF_H_
-#define _E_TABLE_GROUP_LEAF_H_
-
-#include <libgnomecanvas/gnome-canvas.h>
-#include <gal/e-table/e-table-group.h>
-#include <gal/e-table/e-table-subset.h>
-#include <gal/e-table/e-table-item.h>
-
-G_BEGIN_DECLS
-
-#define E_TABLE_GROUP_LEAF_TYPE (e_table_group_leaf_get_type ())
-#define E_TABLE_GROUP_LEAF(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TABLE_GROUP_LEAF_TYPE, ETableGroupLeaf))
-#define E_TABLE_GROUP_LEAF_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TABLE_GROUP_LEAF_TYPE, ETableGroupLeafClass))
-#define E_IS_TABLE_GROUP_LEAF(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TABLE_GROUP_LEAF_TYPE))
-#define E_IS_TABLE_GROUP_LEAF_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TABLE_GROUP_LEAF_TYPE))
-
-typedef struct {
- ETableGroup group;
-
- /*
- * Item.
- */
- ETableItem *item;
-
- gdouble height;
- gdouble width;
- gdouble minimum_width;
-
- int length_threshold;
-
- ETableSubset *ets;
- guint is_grouped : 1;
-
- guint alternating_row_colors : 1;
- guint horizontal_draw_grid : 1;
- guint vertical_draw_grid : 1;
- guint draw_focus : 1;
- guint uniform_row_height : 1;
- ECursorMode cursor_mode;
-
- int etgl_cursor_change_id;
- int etgl_cursor_activated_id;
- int etgl_double_click_id;
- int etgl_right_click_id;
- int etgl_click_id;
- int etgl_key_press_id;
- int etgl_start_drag_id;
-
- ESelectionModel *selection_model;
-} ETableGroupLeaf;
-
-typedef struct {
- ETableGroupClass parent_class;
-} ETableGroupLeafClass;
-
-ETableGroup *e_table_group_leaf_new (GnomeCanvasGroup *parent,
- ETableHeader *full_header,
- ETableHeader *header,
- ETableModel *model,
- ETableSortInfo *sort_info);
-GType e_table_group_leaf_get_type (void);
-
-
-G_END_DECLS
-
-#endif /* _E_TABLE_GROUP_LEAF_H_ */
-
diff --git a/widgets/table/e-table-group.c b/widgets/table/e-table-group.c
deleted file mode 100644
index 5bc8841cb4..0000000000
--- a/widgets/table/e-table-group.c
+++ /dev/null
@@ -1,712 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-group.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <gtk/gtksignal.h>
-#include <libgnomecanvas/gnome-canvas-rect-ellipse.h>
-#include "e-table-group.h"
-#include "e-table-group-container.h"
-#include "e-table-group-leaf.h"
-#include "e-table-item.h"
-#include "gal/util/e-util.h"
-
-#define PARENT_TYPE gnome_canvas_group_get_type ()
-
-#define ETG_CLASS(e) (E_TABLE_GROUP_CLASS(GTK_OBJECT_GET_CLASS(e)))
-
-static GnomeCanvasGroupClass *etg_parent_class;
-
-enum {
- CURSOR_CHANGE,
- CURSOR_ACTIVATED,
- DOUBLE_CLICK,
- RIGHT_CLICK,
- CLICK,
- KEY_PRESS,
- START_DRAG,
- LAST_SIGNAL
-};
-
-static guint etg_signals [LAST_SIGNAL] = { 0, };
-
-static gboolean etg_get_focus (ETableGroup *etg);
-
-static void
-etg_dispose (GObject *object)
-{
- ETableGroup *etg = E_TABLE_GROUP(object);
-
- if (etg->header) {
- g_object_unref (etg->header);
- etg->header = NULL;
- }
-
- if (etg->full_header) {
- g_object_unref (etg->full_header);
- etg->full_header = NULL;
- }
-
- if (etg->model) {
- g_object_unref (etg->model);
- etg->model = NULL;
- }
-
- if (G_OBJECT_CLASS (etg_parent_class)->dispose)
- G_OBJECT_CLASS (etg_parent_class)->dispose (object);
-}
-
-/**
- * e_table_group_new
- * @parent: The %GnomeCanvasGroup to create a child of.
- * @full_header: The full header of the %ETable.
- * @header: The current header of the %ETable.
- * @model: The %ETableModel of the %ETable.
- * @sort_info: The %ETableSortInfo of the %ETable.
- * @n: The grouping information object to group by.
- *
- * %ETableGroup is a collection of rows of an %ETable. It's a
- * %GnomeCanvasItem. There are two different forms. If n < the
- * number of groupings in the given %ETableSortInfo, then the
- * %ETableGroup will need to contain other %ETableGroups, thus it
- * creates an %ETableGroupContainer. Otherwise, it will just contain
- * an %ETableItem, and thus it creates an %ETableGroupLeaf.
- *
- * Returns: The new %ETableGroup.
- */
-ETableGroup *
-e_table_group_new (GnomeCanvasGroup *parent,
- ETableHeader *full_header,
- ETableHeader *header,
- ETableModel *model,
- ETableSortInfo *sort_info,
- int n)
-{
- g_return_val_if_fail (model != NULL, NULL);
-
- if (n < e_table_sort_info_grouping_get_count(sort_info)) {
- return e_table_group_container_new (parent, full_header, header, model, sort_info, n);
- } else {
- return e_table_group_leaf_new (parent, full_header, header, model, sort_info);
- }
- return NULL;
-}
-
-/**
- * e_table_group_construct
- * @parent: The %GnomeCanvasGroup to create a child of.
- * @etg: The %ETableGroup to construct.
- * @full_header: The full header of the %ETable.
- * @header: The current header of the %ETable.
- * @model: The %ETableModel of the %ETable.
- *
- * This routine does the base construction of the %ETableGroup.
- */
-void
-e_table_group_construct (GnomeCanvasGroup *parent,
- ETableGroup *etg,
- ETableHeader *full_header,
- ETableHeader *header,
- ETableModel *model)
-{
- etg->full_header = full_header;
- g_object_ref (etg->full_header);
- etg->header = header;
- g_object_ref (etg->header);
- etg->model = model;
- g_object_ref (etg->model);
- g_object_set (G_OBJECT (etg),
- "parent", parent,
- NULL);
-}
-
-/**
- * e_table_group_add
- * @etg: The %ETableGroup to add a row to
- * @row: The row to add.
- *
- * This routine adds the given row from the %ETableModel to this set
- * of rows.
- */
-void
-e_table_group_add (ETableGroup *etg,
- gint row)
-{
- g_return_if_fail (etg != NULL);
- g_return_if_fail (E_IS_TABLE_GROUP (etg));
-
- g_assert (ETG_CLASS (etg)->add != NULL);
- ETG_CLASS (etg)->add (etg, row);
-}
-
-/**
- * e_table_group_add_array
- * @etg: The %ETableGroup to add to
- * @array: The array to add.
- * @count: The number of times to add
- *
- * This routine adds all the rows in the array to this set of rows.
- * It assumes that the array is already sorted properly.
- */
-void
-e_table_group_add_array (ETableGroup *etg,
- const int *array,
- int count)
-{
- g_return_if_fail (etg != NULL);
- g_return_if_fail (E_IS_TABLE_GROUP (etg));
-
- g_assert (ETG_CLASS (etg)->add_array != NULL);
- ETG_CLASS (etg)->add_array (etg, array, count);
-}
-
-/**
- * e_table_group_add_all
- * @etg: The %ETableGroup to add to
- *
- * This routine adds all the rows from the %ETableModel to this set
- * of rows.
- */
-void
-e_table_group_add_all (ETableGroup *etg)
-{
- g_return_if_fail (etg != NULL);
- g_return_if_fail (E_IS_TABLE_GROUP (etg));
-
- g_assert (ETG_CLASS (etg)->add_all != NULL);
- ETG_CLASS (etg)->add_all (etg);
-}
-
-/**
- * e_table_group_remove
- * @etg: The %ETableGroup to remove a row from
- * @row: The row to remove.
- *
- * This routine removes the given row from the %ETableModel from this
- * set of rows.
- *
- * Returns: TRUE if the row was deleted and FALSE if the row was not
- * found.
- */
-gboolean
-e_table_group_remove (ETableGroup *etg,
- gint row)
-{
- g_return_val_if_fail (etg != NULL, FALSE);
- g_return_val_if_fail (E_IS_TABLE_GROUP (etg), FALSE);
-
- g_assert (ETG_CLASS (etg)->remove != NULL);
- return ETG_CLASS (etg)->remove (etg, row);
-}
-
-/**
- * e_table_group_increment
- * @etg: The %ETableGroup to increment
- * @position: The position to increment from
- * @amount: The amount to increment.
- *
- * This routine adds amount to all rows greater than or equal to
- * position. This is to handle when a row gets inserted into the
- * model.
- */
-void
-e_table_group_increment (ETableGroup *etg,
- gint position,
- gint amount)
-{
- g_return_if_fail (etg != NULL);
- g_return_if_fail (E_IS_TABLE_GROUP (etg));
-
- g_assert (ETG_CLASS (etg)->increment != NULL);
- ETG_CLASS (etg)->increment (etg, position, amount);
-}
-
-/**
- * e_table_group_increment
- * @etg: The %ETableGroup to decrement
- * @position: The position to decrement from
- * @amount: The amount to decrement
- *
- * This routine removes amount from all rows greater than or equal to
- * position. This is to handle when a row gets deleted from the
- * model.
- */
-void
-e_table_group_decrement (ETableGroup *etg,
- gint position,
- gint amount)
-{
- g_return_if_fail (etg != NULL);
- g_return_if_fail (E_IS_TABLE_GROUP (etg));
-
- g_assert (ETG_CLASS (etg)->decrement != NULL);
- ETG_CLASS (etg)->decrement (etg, position, amount);
-}
-
-/**
- * e_table_group_increment
- * @etg: The %ETableGroup to count
- *
- * This routine calculates the number of rows shown in this group.
- *
- * Returns: The number of rows.
- */
-gint
-e_table_group_row_count (ETableGroup *etg)
-{
- g_return_val_if_fail (etg != NULL, 0);
- g_return_val_if_fail (E_IS_TABLE_GROUP (etg), -1);
-
- g_assert (ETG_CLASS (etg)->row_count != NULL);
- return ETG_CLASS (etg)->row_count (etg);
-}
-
-/**
- * e_table_group_set_focus
- * @etg: The %ETableGroup to set
- * @direction: The direction the focus is coming from.
- * @view_col: The column to set the focus in.
- *
- * Sets the focus to this widget. Places the focus in the view column
- * coming from direction direction.
- */
-void
-e_table_group_set_focus (ETableGroup *etg,
- EFocus direction,
- gint view_col)
-{
- g_return_if_fail (etg != NULL);
- g_return_if_fail (E_IS_TABLE_GROUP (etg));
-
- g_assert (ETG_CLASS (etg)->set_focus != NULL);
- ETG_CLASS (etg)->set_focus (etg, direction, view_col);
-}
-
-/**
- * e_table_group_get_focus
- * @etg: The %ETableGroup to check
- *
- * Calculates if this group has the focus.
- *
- * Returns: TRUE if this group has the focus.
- */
-gboolean
-e_table_group_get_focus (ETableGroup *etg)
-{
- g_return_val_if_fail (etg != NULL, FALSE);
- g_return_val_if_fail (E_IS_TABLE_GROUP (etg), FALSE);
-
- g_assert (ETG_CLASS (etg)->get_focus != NULL);
- return ETG_CLASS (etg)->get_focus (etg);
-}
-
-/**
- * e_table_group_get_focus_column
- * @etg: The %ETableGroup to check
- *
- * Calculates which column in this group has the focus.
- *
- * Returns: The column index (view column).
- */
-gint
-e_table_group_get_focus_column (ETableGroup *etg)
-{
- g_return_val_if_fail (etg != NULL, FALSE);
- g_return_val_if_fail (E_IS_TABLE_GROUP (etg), -1);
-
- g_assert (ETG_CLASS (etg)->get_focus_column != NULL);
- return ETG_CLASS (etg)->get_focus_column (etg);
-}
-
-/**
- * e_table_group_get_printable
- * @etg: %ETableGroup which will be printed
- *
- * This routine creates and returns an %EPrintable that can be used to
- * print the given %ETableGroup.
- *
- * Returns: The %EPrintable.
- */
-EPrintable *
-e_table_group_get_printable (ETableGroup *etg)
-{
- g_return_val_if_fail (etg != NULL, NULL);
- g_return_val_if_fail (E_IS_TABLE_GROUP (etg), NULL);
-
- g_assert (ETG_CLASS (etg)->get_printable != NULL);
- return ETG_CLASS (etg)->get_printable (etg);
-}
-
-/**
- * e_table_group_compute_location
- * @eti: %ETableGroup to look in.
- * @x: A pointer to the x location to find in the %ETableGroup.
- * @y: A pointer to the y location to find in the %ETableGroup.
- * @row: A pointer to the location to store the found row in.
- * @col: A pointer to the location to store the found col in.
- *
- * This routine locates the pixel location (*x, *y) in the
- * %ETableGroup. If that location is in the %ETableGroup, *row and
- * *col are set to the view row and column where it was found. If
- * that location is not in the %ETableGroup, the height of the
- * %ETableGroup is removed from the value y points to.
- */
-void
-e_table_group_compute_location (ETableGroup *etg, int *x, int *y, int *row, int *col)
-{
- g_return_if_fail (etg != NULL);
- g_return_if_fail (E_IS_TABLE_GROUP (etg));
-
- g_assert (ETG_CLASS (etg)->compute_location != NULL);
- ETG_CLASS (etg)->compute_location (etg, x, y, row, col);
-}
-
-/**
- * e_table_group_get_position
- * @eti: %ETableGroup to look in.
- * @x: A pointer to the location to store the found x location in.
- * @y: A pointer to the location to store the found y location in.
- * @row: A pointer to the row number to find.
- * @col: A pointer to the col number to find.
- *
- * This routine finds the view cell (row, col) in the #ETableGroup.
- * If that location is in the #ETableGroup *@x and *@y are set to the
- * upper left hand corner of the cell found. If that location is not
- * in the #ETableGroup, the number of rows in the #ETableGroup is
- * removed from the value row points to.
- */
-void
-e_table_group_get_cell_geometry (ETableGroup *etg,
- int *row,
- int *col,
- int *x,
- int *y,
- int *width,
- int *height)
-{
- g_return_if_fail (etg != NULL);
- g_return_if_fail (E_IS_TABLE_GROUP (etg));
-
- g_assert (ETG_CLASS (etg)->get_cell_geometry != NULL);
- ETG_CLASS (etg)->get_cell_geometry (etg, row, col, x, y, width, height);
-}
-
-/**
- * e_table_group_cursor_change
- * @eti: %ETableGroup to emit the signal on
- * @row: The new cursor row (model row)
- *
- * This routine emits the "cursor_change" signal.
- */
-void
-e_table_group_cursor_change (ETableGroup *e_table_group, gint row)
-{
- g_return_if_fail (e_table_group != NULL);
- g_return_if_fail (E_IS_TABLE_GROUP (e_table_group));
-
- g_signal_emit (e_table_group,
- etg_signals [CURSOR_CHANGE], 0,
- row);
-}
-
-/**
- * e_table_group_cursor_activated
- * @eti: %ETableGroup to emit the signal on
- * @row: The cursor row (model row)
- *
- * This routine emits the "cursor_activated" signal.
- */
-void
-e_table_group_cursor_activated (ETableGroup *e_table_group, gint row)
-{
- g_return_if_fail (e_table_group != NULL);
- g_return_if_fail (E_IS_TABLE_GROUP (e_table_group));
-
- g_signal_emit (e_table_group,
- etg_signals [CURSOR_ACTIVATED], 0,
- row);
-}
-
-/**
- * e_table_group_double_click
- * @eti: %ETableGroup to emit the signal on
- * @row: The row clicked on (model row)
- * @col: The col clicked on (model col)
- * @event: The event that caused this signal
- *
- * This routine emits the "double_click" signal.
- */
-void
-e_table_group_double_click (ETableGroup *e_table_group, gint row, gint col, GdkEvent *event)
-{
- g_return_if_fail (e_table_group != NULL);
- g_return_if_fail (E_IS_TABLE_GROUP (e_table_group));
-
- g_signal_emit (e_table_group,
- etg_signals [DOUBLE_CLICK], 0,
- row, col, event);
-}
-
-/**
- * e_table_group_right_click
- * @eti: %ETableGroup to emit the signal on
- * @row: The row clicked on (model row)
- * @col: The col clicked on (model col)
- * @event: The event that caused this signal
- *
- * This routine emits the "right_click" signal.
- */
-gint
-e_table_group_right_click (ETableGroup *e_table_group, gint row, gint col, GdkEvent *event)
-{
- gint return_val = 0;
-
- g_return_val_if_fail (e_table_group != NULL, 0);
- g_return_val_if_fail (E_IS_TABLE_GROUP (e_table_group), 0);
-
- g_signal_emit (e_table_group,
- etg_signals [RIGHT_CLICK], 0,
- row, col, event, &return_val);
-
- return return_val;
-}
-
-/**
- * e_table_group_click
- * @eti: %ETableGroup to emit the signal on
- * @row: The row clicked on (model row)
- * @col: The col clicked on (model col)
- * @event: The event that caused this signal
- *
- * This routine emits the "click" signal.
- */
-gint
-e_table_group_click (ETableGroup *e_table_group, gint row, gint col, GdkEvent *event)
-{
- gint return_val = 0;
-
- g_return_val_if_fail (e_table_group != NULL, 0);
- g_return_val_if_fail (E_IS_TABLE_GROUP (e_table_group), 0);
-
- g_signal_emit (e_table_group,
- etg_signals [CLICK], 0,
- row, col, event, &return_val);
-
- return return_val;
-}
-
-/**
- * e_table_group_key_press
- * @eti: %ETableGroup to emit the signal on
- * @row: The cursor row (model row)
- * @col: The cursor col (model col)
- * @event: The event that caused this signal
- *
- * This routine emits the "key_press" signal.
- */
-gint
-e_table_group_key_press (ETableGroup *e_table_group, gint row, gint col, GdkEvent *event)
-{
- gint return_val = 0;
-
- g_return_val_if_fail (e_table_group != NULL, 0);
- g_return_val_if_fail (E_IS_TABLE_GROUP (e_table_group), 0);
-
- g_signal_emit (e_table_group,
- etg_signals [KEY_PRESS], 0,
- row, col, event, &return_val);
-
- return return_val;
-}
-
-/**
- * e_table_group_start_drag
- * @eti: %ETableGroup to emit the signal on
- * @row: The cursor row (model row)
- * @col: The cursor col (model col)
- * @event: The event that caused this signal
- *
- * This routine emits the "start_drag" signal.
- */
-gint
-e_table_group_start_drag (ETableGroup *e_table_group, gint row, gint col, GdkEvent *event)
-{
- gint return_val = 0;
-
- g_return_val_if_fail (e_table_group != NULL, 0);
- g_return_val_if_fail (E_IS_TABLE_GROUP (e_table_group), 0);
-
- g_signal_emit (e_table_group,
- etg_signals [START_DRAG], 0,
- row, col, event, &return_val);
-
- return return_val;
-}
-
-/**
- * e_table_group_get_header
- * @eti: %ETableGroup to check
- *
- * This routine returns the %ETableGroup's header.
- *
- * Returns: The %ETableHeader.
- */
-ETableHeader *
-e_table_group_get_header (ETableGroup *etg)
-{
- g_return_val_if_fail (etg != NULL, NULL);
- g_return_val_if_fail (E_IS_TABLE_GROUP (etg), NULL);
-
- return etg->header;
-}
-
-static int
-etg_event (GnomeCanvasItem *item, GdkEvent *event)
-{
- ETableGroup *etg = E_TABLE_GROUP (item);
- gboolean return_val = TRUE;
-
- switch (event->type) {
-
- case GDK_FOCUS_CHANGE:
- etg->has_focus = event->focus_change.in;
- return_val = FALSE;
-
- default:
- return_val = FALSE;
- }
- if (return_val == FALSE){
- if (GNOME_CANVAS_ITEM_CLASS(etg_parent_class)->event)
- return GNOME_CANVAS_ITEM_CLASS(etg_parent_class)->event (item, event);
- }
- return return_val;
-
-}
-
-static gboolean
-etg_get_focus (ETableGroup *etg)
-{
- return etg->has_focus;
-}
-
-static void
-etg_class_init (GObjectClass *object_class)
-{
- GnomeCanvasItemClass *item_class = (GnomeCanvasItemClass *) object_class;
- ETableGroupClass *klass = (ETableGroupClass *) object_class;
-
- object_class->dispose = etg_dispose;
-
- item_class->event = etg_event;
-
- klass->cursor_change = NULL;
- klass->cursor_activated = NULL;
- klass->double_click = NULL;
- klass->right_click = NULL;
- klass->click = NULL;
- klass->key_press = NULL;
- klass->start_drag = NULL;
-
- klass->add = NULL;
- klass->add_array = NULL;
- klass->add_all = NULL;
- klass->remove = NULL;
- klass->row_count = NULL;
- klass->increment = NULL;
- klass->decrement = NULL;
- klass->set_focus = NULL;
- klass->get_focus = etg_get_focus;
- klass->get_printable = NULL;
- klass->compute_location = NULL;
- klass->get_cell_geometry = NULL;
-
- etg_parent_class = g_type_class_ref (PARENT_TYPE);
-
- etg_signals [CURSOR_CHANGE] =
- g_signal_new ("cursor_change",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableGroupClass, cursor_change),
- NULL, NULL,
- e_marshal_NONE__INT,
- G_TYPE_NONE, 1, G_TYPE_INT);
-
- etg_signals [CURSOR_ACTIVATED] =
- g_signal_new ("cursor_activated",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableGroupClass, cursor_activated),
- NULL, NULL,
- e_marshal_NONE__INT,
- G_TYPE_NONE, 1, G_TYPE_INT);
-
- etg_signals [DOUBLE_CLICK] =
- g_signal_new ("double_click",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableGroupClass, double_click),
- NULL, NULL,
- e_marshal_NONE__INT_INT_BOXED,
- G_TYPE_NONE, 3, G_TYPE_INT,
- G_TYPE_INT, GDK_TYPE_EVENT);
-
- etg_signals [RIGHT_CLICK] =
- g_signal_new ("right_click",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableGroupClass, right_click),
- NULL, NULL,
- e_marshal_INT__INT_INT_BOXED,
- G_TYPE_INT, 3, G_TYPE_INT, G_TYPE_INT, GDK_TYPE_EVENT);
-
- etg_signals [CLICK] =
- g_signal_new ("click",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableGroupClass, click),
- NULL, NULL,
- e_marshal_INT__INT_INT_BOXED,
- G_TYPE_INT, 3, G_TYPE_INT,
- G_TYPE_INT, GDK_TYPE_EVENT);
-
- etg_signals [KEY_PRESS] =
- g_signal_new ("key_press",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableGroupClass, key_press),
- NULL, NULL,
- e_marshal_INT__INT_INT_BOXED,
- G_TYPE_INT, 3, G_TYPE_INT,
- G_TYPE_INT, GDK_TYPE_EVENT);
-
- etg_signals [START_DRAG] =
- g_signal_new ("start_drag",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableGroupClass, start_drag),
- NULL, NULL,
- e_marshal_INT__INT_INT_BOXED,
- G_TYPE_INT, 3, G_TYPE_INT,
- G_TYPE_INT, GDK_TYPE_EVENT);
-}
-
-E_MAKE_TYPE (e_table_group, "ETableGroup", ETableGroup, etg_class_init, NULL, PARENT_TYPE)
diff --git a/widgets/table/e-table-group.h b/widgets/table/e-table-group.h
deleted file mode 100644
index 2ecd34efe1..0000000000
--- a/widgets/table/e-table-group.h
+++ /dev/null
@@ -1,178 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-group.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_TABLE_GROUP_H_
-#define _E_TABLE_GROUP_H_
-
-#include <libgnomecanvas/gnome-canvas.h>
-#include <gal/e-table/e-table-model.h>
-#include <gal/e-table/e-table-header.h>
-#include <gal/e-table/e-table-sort-info.h>
-#include <gal/e-table/e-table-defines.h>
-#include <gal/util/e-util.h>
-#include <gal/widgets/e-printable.h>
-
-G_BEGIN_DECLS
-
-#define E_TABLE_GROUP_TYPE (e_table_group_get_type ())
-#define E_TABLE_GROUP(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TABLE_GROUP_TYPE, ETableGroup))
-#define E_TABLE_GROUP_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TABLE_GROUP_TYPE, ETableGroupClass))
-#define E_IS_TABLE_GROUP(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TABLE_GROUP_TYPE))
-#define E_IS_TABLE_GROUP_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TABLE_GROUP_TYPE))
-
-typedef struct {
- GnomeCanvasGroup group;
-
- /*
- * The full header.
- */
- ETableHeader *full_header;
- ETableHeader *header;
-
- /*
- * The model we pull data from.
- */
- ETableModel *model;
-
- /*
- * Whether we should add indentation and open/close markers,
- * or if we just act as containers of subtables.
- */
- guint transparent : 1;
-
- guint has_focus : 1;
-
- guint frozen : 1;
-} ETableGroup;
-
-typedef struct {
- GnomeCanvasGroupClass parent_class;
-
- /* Signals */
- void (*cursor_change) (ETableGroup *etg, int row);
- void (*cursor_activated) (ETableGroup *etg, int row);
- void (*double_click) (ETableGroup *etg, int row, int col, GdkEvent *event);
- gint (*right_click) (ETableGroup *etg, int row, int col, GdkEvent *event);
- gint (*click) (ETableGroup *etg, int row, int col, GdkEvent *event);
- gint (*key_press) (ETableGroup *etg, int row, int col, GdkEvent *event);
- gint (*start_drag) (ETableGroup *etg, int row, int col, GdkEvent *event);
-
- /* Virtual functions. */
- void (*add) (ETableGroup *etg, gint row);
- void (*add_array) (ETableGroup *etg, const int *array, int count);
- void (*add_all) (ETableGroup *etg);
- gboolean (*remove) (ETableGroup *etg, gint row);
- gint (*row_count) (ETableGroup *etg);
- void (*increment) (ETableGroup *etg, gint position, gint amount);
- void (*decrement) (ETableGroup *etg, gint position, gint amount);
- void (*set_focus) (ETableGroup *etg, EFocus direction, gint view_col);
- gboolean (*get_focus) (ETableGroup *etg);
- gint (*get_focus_column) (ETableGroup *etg);
- EPrintable *(*get_printable) (ETableGroup *etg);
- void (*compute_location) (ETableGroup *etg, int *x, int *y, int *row, int *col);
- void (*get_cell_geometry) (ETableGroup *etg, int *row, int *col, int *x, int *y, int *width, int *height);
-
-} ETableGroupClass;
-
-/* Virtual functions */
-void e_table_group_add (ETableGroup *etg,
- gint row);
-void e_table_group_add_array (ETableGroup *etg,
- const int *array,
- int count);
-void e_table_group_add_all (ETableGroup *etg);
-gboolean e_table_group_remove (ETableGroup *etg,
- gint row);
-void e_table_group_increment (ETableGroup *etg,
- gint position,
- gint amount);
-void e_table_group_decrement (ETableGroup *etg,
- gint position,
- gint amount);
-gint e_table_group_row_count (ETableGroup *etg);
-void e_table_group_set_focus (ETableGroup *etg,
- EFocus direction,
- gint view_col);
-gboolean e_table_group_get_focus (ETableGroup *etg);
-gint e_table_group_get_focus_column (ETableGroup *etg);
-ETableHeader *e_table_group_get_header (ETableGroup *etg);
-EPrintable *e_table_group_get_printable (ETableGroup *etg);
-void e_table_group_compute_location (ETableGroup *etg,
- int *x,
- int *y,
- int *row,
- int *col);
-void e_table_group_get_cell_geometry (ETableGroup *etg,
- int *row,
- int *col,
- int *x,
- int *y,
- int *width,
- int *height);
-ETableGroup *e_table_group_new (GnomeCanvasGroup *parent,
- ETableHeader *full_header,
- ETableHeader *header,
- ETableModel *model,
- ETableSortInfo *sort_info,
- int n);
-void e_table_group_construct (GnomeCanvasGroup *parent,
- ETableGroup *etg,
- ETableHeader *full_header,
- ETableHeader *header,
- ETableModel *model);
-
-/* For emitting the signals */
-void e_table_group_cursor_change (ETableGroup *etg,
- gint row);
-void e_table_group_cursor_activated (ETableGroup *etg,
- gint row);
-void e_table_group_double_click (ETableGroup *etg,
- gint row,
- gint col,
- GdkEvent *event);
-gint e_table_group_right_click (ETableGroup *etg,
- gint row,
- gint col,
- GdkEvent *event);
-gint e_table_group_click (ETableGroup *etg,
- gint row,
- gint col,
- GdkEvent *event);
-gint e_table_group_key_press (ETableGroup *etg,
- gint row,
- gint col,
- GdkEvent *event);
-gint e_table_group_start_drag (ETableGroup *etg,
- gint row,
- gint col,
- GdkEvent *event);
-GType e_table_group_get_type (void);
-
-typedef void (*ETableGroupLeafFn) (void *e_table_item, void *closure);
-void e_table_group_apply_to_leafs (ETableGroup *etg,
- ETableGroupLeafFn fn,
- void *closure);
-
-G_END_DECLS
-
-#endif /* _E_TABLE_GROUP_H_ */
diff --git a/widgets/table/e-table-header-item.c b/widgets/table/e-table-header-item.c
deleted file mode 100644
index 265d29fed0..0000000000
--- a/widgets/table/e-table-header-item.c
+++ /dev/null
@@ -1,1910 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-header-item.c
- * Copyright 1999, 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- * Miguel de Icaza (miguel@gnu.org)
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-
-#include "e-table-header-item.h"
-
-#include <string.h>
-#include <gtk/gtksignal.h>
-#include <gtk/gtkdnd.h>
-#include <gtk/gtkimage.h>
-#include <libgnomecanvas/gnome-canvas.h>
-#include <libgnomecanvas/gnome-canvas-util.h>
-#include <libgnomecanvas/gnome-canvas-polygon.h>
-#include <libgnomecanvas/gnome-canvas-rect-ellipse.h>
-#include <gdk-pixbuf/gdk-pixbuf.h>
-#include <gdk/gdkkeysyms.h>
-#include "gal/widgets/e-cursors.h"
-#include "gal/util/e-i18n.h"
-#include "gal/util/e-util.h"
-#include "gal/util/e-xml-utils.h"
-#include "gal/util/e-marshal.h"
-#include "gal/widgets/e-canvas.h"
-#include "gal/widgets/e-popup-menu.h"
-#include "gal/widgets/e-gui-utils.h"
-#include "e-table-header.h"
-#include "e-table-header-utils.h"
-#include "e-table-col-dnd.h"
-#include "e-table-defines.h"
-#include "e-table-field-chooser-dialog.h"
-#include "e-table-config.h"
-#include "e-table.h"
-
-#include "add-col.xpm"
-#include "remove-col.xpm"
-#include "arrow-up.xpm"
-#include "arrow-down.xpm"
-
-enum {
- BUTTON_PRESSED,
- LAST_SIGNAL
-};
-
-static guint ethi_signals [LAST_SIGNAL] = { 0, };
-
-#define ARROW_DOWN_HEIGHT 16
-#define ARROW_PTR 7
-
-/* Defines the tolerance for proximity of the column division to the cursor position */
-#define TOLERANCE 4
-
-#define ETHI_RESIZING(x) ((x)->resize_col != -1)
-
-#define PARENT_OBJECT_TYPE gnome_canvas_item_get_type ()
-
-#define ELEMENTS(x) (sizeof (x) / sizeof (x[0]))
-#define d(x)
-
-static GnomeCanvasItemClass *ethi_parent_class;
-
-static void ethi_drop_table_header (ETableHeaderItem *ethi);
-
-/*
- * They display the arrows for the drop location.
- */
-
-static GtkWidget *arrow_up, *arrow_down;
-
-/*
- * DnD icons
- */
-static GdkColormap *dnd_colormap;
-static GdkPixmap *remove_col_pixmap, *remove_col_mask;
-static GdkPixmap *add_col_pixmap, *add_col_mask;
-
-enum {
- PROP_0,
- PROP_TABLE_HEADER,
- PROP_FULL_HEADER,
- PROP_DND_CODE,
- PROP_TABLE_FONTSET,
- PROP_SORT_INFO,
- PROP_TABLE,
- PROP_TREE
-};
-
-enum {
- ET_SCROLL_UP = 1 << 0,
- ET_SCROLL_DOWN = 1 << 1,
- ET_SCROLL_LEFT = 1 << 2,
- ET_SCROLL_RIGHT = 1 << 3
-};
-
-static void scroll_off (ETableHeaderItem *ethi);
-static void scroll_on (ETableHeaderItem *ethi, guint scroll_direction);
-
-static void
-ethi_dispose (GObject *object){
- ETableHeaderItem *ethi = E_TABLE_HEADER_ITEM (object);
-
- ethi_drop_table_header (ethi);
-
- scroll_off (ethi);
-
- if (ethi->dnd_code) {
- g_free (ethi->dnd_code);
- ethi->dnd_code = NULL;
- }
-
- if (ethi->sort_info) {
- if (ethi->sort_info_changed_id)
- g_signal_handler_disconnect (ethi->sort_info, ethi->sort_info_changed_id);
- if (ethi->group_info_changed_id)
- g_signal_handler_disconnect (ethi->sort_info, ethi->group_info_changed_id);
- g_object_unref (ethi->sort_info);
- ethi->sort_info = NULL;
- }
-
- if (ethi->full_header)
- g_object_unref (ethi->full_header);
- ethi->full_header = NULL;
-
-
- if (ethi->etfcd)
- g_object_remove_weak_pointer (G_OBJECT (ethi->etfcd), (gpointer *)&ethi->etfcd);
-
-
- if (ethi->config)
- g_object_unref (ethi->config);
- ethi->config = NULL;
-
- if (G_OBJECT_CLASS (ethi_parent_class)->dispose)
- (*G_OBJECT_CLASS (ethi_parent_class)->dispose) (object);
-}
-
-static int
-e_table_header_item_get_height (ETableHeaderItem *ethi)
-{
- ETableHeader *eth;
- int numcols, col;
- int maxheight;
- GtkStyle *style;
-
- g_return_val_if_fail (ethi != NULL, 0);
- g_return_val_if_fail (E_IS_TABLE_HEADER_ITEM (ethi), 0);
-
- eth = ethi->eth;
- numcols = e_table_header_count (eth);
-
- maxheight = 0;
-
- style = GTK_WIDGET (GNOME_CANVAS_ITEM (ethi)->canvas)->style;
-
- for (col = 0; col < numcols; col++) {
- ETableCol *ecol = e_table_header_get_column (eth, col);
- int height;
-
- height = e_table_header_compute_height (ecol,
- GTK_WIDGET (GNOME_CANVAS_ITEM (ethi)->canvas));
-
- if (height > maxheight)
- maxheight = height;
- }
-
- return maxheight;
-}
-
-static void
-ethi_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
-{
- ETableHeaderItem *ethi = E_TABLE_HEADER_ITEM (item);
-
- double i2c [6];
- ArtPoint c1, c2, i1, i2;
-
- if (GNOME_CANVAS_ITEM_CLASS (ethi_parent_class)->update)
- (*GNOME_CANVAS_ITEM_CLASS (ethi_parent_class)->update)(item, affine, clip_path, flags);
-
- if (ethi->sort_info)
- ethi->group_indent_width = e_table_sort_info_grouping_get_count(ethi->sort_info) * GROUP_INDENT;
- else
- ethi->group_indent_width = 0;
-
- ethi->width = e_table_header_total_width (ethi->eth) + ethi->group_indent_width;
-
- i1.x = i1.y = 0;
- i2.x = ethi->width;
- i2.y = ethi->height;
-
- gnome_canvas_item_i2c_affine (item, i2c);
- art_affine_point (&c1, &i1, i2c);
- art_affine_point (&c2, &i2, i2c);
-
- if (item->x1 != c1.x ||
- item->y1 != c1.y ||
- item->x2 != c2.x ||
- item->y2 != c2.y)
- {
- gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2, item->y2);
- item->x1 = c1.x;
- item->y1 = c1.y;
- item->x2 = c2.x;
- item->y2 = c2.y;
-#ifndef NO_WARNINGS
-#warning FOO BAA
-#endif
-#if 0
- gnome_canvas_group_child_bounds (GNOME_CANVAS_GROUP (item->parent), item);
-#endif
- }
- gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2, item->y2);
-}
-
-static void
-ethi_font_set (ETableHeaderItem *ethi, GdkFont *font)
-{
- if (ethi->font)
- gdk_font_unref (ethi->font);
-
- ethi->font = font;
- gdk_font_ref (font);
-
- ethi->height = e_table_header_item_get_height (ethi);
- e_canvas_item_request_reflow(GNOME_CANVAS_ITEM(ethi));
-}
-
-static void
-ethi_font_load (ETableHeaderItem *ethi, const char *fontname)
-{
- GdkFont *font = NULL;
-
- if (fontname != NULL)
- font = gdk_fontset_load (fontname);
-
- if (font == NULL) {
- font = gtk_style_get_font (GTK_WIDGET (GNOME_CANVAS_ITEM (ethi)->canvas)->style);
- gdk_font_ref (font);
- }
-
- ethi_font_set (ethi, font);
- gdk_font_unref (font);
-}
-
-static void
-ethi_drop_table_header (ETableHeaderItem *ethi)
-{
- GObject *header;
-
- if (!ethi->eth)
- return;
-
- header = G_OBJECT (ethi->eth);
- g_signal_handler_disconnect (header, ethi->structure_change_id);
- g_signal_handler_disconnect (header, ethi->dimension_change_id);
-
- g_object_unref (header);
- ethi->eth = NULL;
- ethi->width = 0;
-}
-
-static void
-structure_changed (ETableHeader *header, ETableHeaderItem *ethi)
-{
- gnome_canvas_item_request_update(GNOME_CANVAS_ITEM(ethi));
-}
-
-static void
-dimension_changed (ETableHeader *header, int col, ETableHeaderItem *ethi)
-{
- gnome_canvas_item_request_update(GNOME_CANVAS_ITEM(ethi));
-}
-
-static void
-ethi_add_table_header (ETableHeaderItem *ethi, ETableHeader *header)
-{
- ethi->eth = header;
- g_object_ref (ethi->eth);
-
- ethi->height = e_table_header_item_get_height (ethi);
-
- ethi->structure_change_id = g_signal_connect (
- header, "structure_change",
- G_CALLBACK (structure_changed), ethi);
- ethi->dimension_change_id = g_signal_connect (
- header, "dimension_change",
- G_CALLBACK (dimension_changed), ethi);
- e_canvas_item_request_reflow(GNOME_CANVAS_ITEM(ethi));
- gnome_canvas_item_request_update (GNOME_CANVAS_ITEM(ethi));
-}
-
-static void
-ethi_sort_info_changed (ETableSortInfo *sort_info, ETableHeaderItem *ethi)
-{
- gnome_canvas_item_request_update (GNOME_CANVAS_ITEM(ethi));
-}
-
-static void
-ethi_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- GnomeCanvasItem *item;
- ETableHeaderItem *ethi;
-
- item = GNOME_CANVAS_ITEM (object);
- ethi = E_TABLE_HEADER_ITEM (object);
-
- switch (prop_id){
- case PROP_TABLE_HEADER:
- ethi_drop_table_header (ethi);
- ethi_add_table_header (ethi, E_TABLE_HEADER(g_value_get_object (value)));
- break;
-
- case PROP_FULL_HEADER:
- if (ethi->full_header)
- g_object_unref(ethi->full_header);
- ethi->full_header = E_TABLE_HEADER(g_value_get_object (value));
- if (ethi->full_header)
- g_object_ref(ethi->full_header);
- break;
-
- case PROP_DND_CODE:
- g_free(ethi->dnd_code);
- ethi->dnd_code = g_strdup (g_value_get_string (value));
- break;
-
- case PROP_TABLE_FONTSET:
- ethi_font_load (ethi, g_value_get_string (value));
- break;
-
- case PROP_SORT_INFO:
- if (ethi->sort_info){
- if (ethi->sort_info_changed_id)
- g_signal_handler_disconnect (
- ethi->sort_info,
- ethi->sort_info_changed_id);
-
- if (ethi->group_info_changed_id)
- g_signal_handler_disconnect (
- ethi->sort_info,
- ethi->group_info_changed_id);
- g_object_unref (ethi->sort_info);
- }
- ethi->sort_info = g_value_get_object (value);
- g_object_ref (ethi->sort_info);
- ethi->sort_info_changed_id =
- g_signal_connect (
- ethi->sort_info, "sort_info_changed",
- G_CALLBACK (ethi_sort_info_changed), ethi);
- ethi->group_info_changed_id =
- g_signal_connect (
- ethi->sort_info, "group_info_changed",
- G_CALLBACK(ethi_sort_info_changed), ethi);
- break;
- case PROP_TABLE:
- if (g_value_get_object (value))
- ethi->table = E_TABLE(g_value_get_object (value));
- else
- ethi->table = NULL;
- break;
- case PROP_TREE:
- if (g_value_get_object (value))
- ethi->tree = E_TREE(g_value_get_object (value));
- else
- ethi->tree = NULL;
- break;
- }
- gnome_canvas_item_request_update(item);
-}
-
-static void
-ethi_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- ETableHeaderItem *ethi;
-
- ethi = E_TABLE_HEADER_ITEM (object);
-
- switch (prop_id){
- case PROP_FULL_HEADER:
- g_value_set_object (value, ethi->full_header);
- break;
- case PROP_DND_CODE:
- g_value_set_string (value, g_strdup (ethi->dnd_code));
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static int
-ethi_find_col_by_x (ETableHeaderItem *ethi, int x)
-{
- const int cols = e_table_header_count (ethi->eth);
- int x1 = 0;
- int col;
-
- d(g_print ("%s:%d: x = %d, x1 = %d\n", __FUNCTION__, __LINE__, x, x1));
-
- x1 += ethi->group_indent_width;
-
- if (x < x1) {
- d(g_print ("%s:%d: Returning 0\n", __FUNCTION__, __LINE__));
- return 0;
- }
-
- for (col = 0; col < cols; col++){
- ETableCol *ecol = e_table_header_get_column (ethi->eth, col);
-
- if ((x >= x1) && (x <= x1 + ecol->width)) {
- d(g_print ("%s:%d: Returning %d\n", __FUNCTION__, __LINE__, col));
- return col;
- }
-
- x1 += ecol->width;
- }
- d(g_print ("%s:%d: Returning %d\n", __FUNCTION__, __LINE__, cols - 1));
- return cols - 1;
-}
-
-static int
-ethi_find_col_by_x_nearest (ETableHeaderItem *ethi, int x)
-{
- const int cols = e_table_header_count (ethi->eth);
- int x1 = 0;
- int col;
-
- x1 += ethi->group_indent_width;
-
- if (x < x1)
- return 0;
-
- for (col = 0; col < cols; col++){
- ETableCol *ecol = e_table_header_get_column (ethi->eth, col);
-
- x1 += (ecol->width / 2);
-
- if (x <= x1)
- return col;
-
- x1 += (ecol->width + 1) / 2;
- }
- return col;
-}
-
-static void
-ethi_remove_drop_marker (ETableHeaderItem *ethi)
-{
- if (ethi->drag_mark == -1)
- return;
-
- gtk_widget_hide (arrow_up);
- gtk_widget_hide (arrow_down);
-
- ethi->drag_mark = -1;
-}
-
-static GtkWidget *
-make_shaped_window_from_xpm (const char **xpm)
-{
- GdkPixbuf *pixbuf;
- GdkPixmap *pixmap;
- GdkBitmap *bitmap;
- GtkWidget *win, *pix;
-
- pixbuf = gdk_pixbuf_new_from_xpm_data (xpm);
- gdk_pixbuf_render_pixmap_and_mask (pixbuf, &pixmap, &bitmap, 128);
- gdk_pixbuf_unref (pixbuf);
-
- gtk_widget_push_colormap (gdk_rgb_get_cmap ());
- win = gtk_window_new (GTK_WINDOW_POPUP);
-
- pix = gtk_image_new_from_pixmap (pixmap, bitmap);
- gtk_widget_realize (win);
- gtk_container_add (GTK_CONTAINER (win), pix);
- gtk_widget_shape_combine_mask (win, bitmap, 0, 0);
- gtk_widget_pop_colormap ();
-
- gdk_pixmap_unref (pixmap);
- gdk_bitmap_unref (bitmap);
-
- return win;
-}
-
-static void
-ethi_add_drop_marker (ETableHeaderItem *ethi, int col, gboolean recreate)
-{
- int rx, ry;
- int x;
-
- if (!recreate && ethi->drag_mark == col)
- return;
-
- ethi->drag_mark = col;
-
- x = e_table_header_col_diff (ethi->eth, 0, col);
- if (col > 0)
- x += ethi->group_indent_width;
-
- if (!arrow_up){
- arrow_up = make_shaped_window_from_xpm (arrow_up_xpm);
- arrow_down = make_shaped_window_from_xpm (arrow_down_xpm);
- }
-
- gdk_window_get_origin (
- GTK_WIDGET (GNOME_CANVAS_ITEM (ethi)->canvas)->window,
- &rx, &ry);
-
- rx -= gtk_layout_get_hadjustment (GTK_LAYOUT (GNOME_CANVAS_ITEM (ethi)->canvas))->value;
- ry -= gtk_layout_get_vadjustment (GTK_LAYOUT (GNOME_CANVAS_ITEM (ethi)->canvas))->value;
-
- gtk_widget_set_uposition (arrow_down, rx + x - ARROW_PTR, ry - ARROW_DOWN_HEIGHT);
- gtk_widget_show_all (arrow_down);
-
- gtk_widget_set_uposition (arrow_up, rx + x - ARROW_PTR, ry + ethi->height);
- gtk_widget_show_all (arrow_up);
-}
-
-#define gray50_width 2
-#define gray50_height 2
-static char gray50_bits [] = {
- 0x02, 0x01, };
-
-static void
-ethi_add_destroy_marker (ETableHeaderItem *ethi)
-{
- double x1;
-
- if (ethi->remove_item)
- gtk_object_destroy (GTK_OBJECT (ethi->remove_item));
-
- if (!ethi->stipple)
- ethi->stipple = gdk_bitmap_create_from_data (
- NULL, gray50_bits, gray50_width, gray50_height);
-
- x1 = (double) e_table_header_col_diff (ethi->eth, 0, ethi->drag_col);
- if (ethi->drag_col > 0)
- x1 += ethi->group_indent_width;
-
- ethi->remove_item = gnome_canvas_item_new (
- GNOME_CANVAS_GROUP (GNOME_CANVAS_ITEM (ethi)->canvas->root),
- gnome_canvas_rect_get_type (),
- "x1", x1 + 1,
- "y1", (double) 1,
- "x2", (double) x1 + e_table_header_col_diff (
- ethi->eth, ethi->drag_col, ethi->drag_col+1) - 2,
-
- "y2", (double) ethi->height - 2,
- "fill_color", "red",
- "fill_stipple", ethi->stipple,
- NULL);
-}
-
-static void
-ethi_remove_destroy_marker (ETableHeaderItem *ethi)
-{
- if (!ethi->remove_item)
- return;
-
- gtk_object_destroy (GTK_OBJECT (ethi->remove_item));
- ethi->remove_item = NULL;
-}
-
-#if 0
-static gboolean
-moved (ETableHeaderItem *ethi, guint col, guint model_col)
-{
- if (col == -1)
- return TRUE;
- ecol = e_table_header_get_column (ethi->eth, col);
- if (ecol->col_idx == model_col)
- return FALSE;
- if (col > 0) {
- ecol = e_table_header_get_column (ethi->eth, col - 1);
- if (ecol->col_idx == model_col)
- return FALSE;
- }
- return TRUE;
-}
-#endif
-
-static void
-do_drag_motion(ETableHeaderItem *ethi,
- GdkDragContext *context,
- gint x,
- gint y,
- guint time,
- gboolean recreate)
-{
- d(g_print("In do_drag_motion\n"));
- d(g_print("x = %d, y = %d, ethi->width = %d, ethi->height = %d\n", x, y, ethi->width, ethi->height));
-
- if ((x >= 0) && (x <= (ethi->width)) &&
- (y >= 0) && (y <= (ethi->height))){
- int col;
- d(g_print("In header\n"));
-
- col = ethi_find_col_by_x_nearest (ethi, x);
-
- if (ethi->drag_col != -1 && (col == ethi->drag_col || col == ethi->drag_col + 1)) {
- if (ethi->drag_col != -1)
- ethi_remove_destroy_marker (ethi);
-
- ethi_remove_drop_marker (ethi);
- gdk_drag_status (context, context->suggested_action, time);
- }
- else if (col != -1){
- if (ethi->drag_col != -1)
- ethi_remove_destroy_marker (ethi);
-
- ethi_add_drop_marker (ethi, col, recreate);
- gdk_drag_status (context, context->suggested_action, time);
- } else {
- ethi_remove_drop_marker (ethi);
- if (ethi->drag_col != -1)
- ethi_add_destroy_marker (ethi);
- }
- } else {
- ethi_remove_drop_marker (ethi);
- if (ethi->drag_col != -1)
- ethi_add_destroy_marker (ethi);
- }
-}
-
-static gboolean
-scroll_timeout (gpointer data)
-{
- ETableHeaderItem *ethi = data;
- int dx = 0;
- GtkAdjustment *h, *v;
- double value;
-
- if (ethi->scroll_direction & ET_SCROLL_RIGHT)
- dx += 20;
- if (ethi->scroll_direction & ET_SCROLL_LEFT)
- dx -= 20;
-
- h = GTK_LAYOUT(GNOME_CANVAS_ITEM (ethi)->canvas)->hadjustment;
- v = GTK_LAYOUT(GNOME_CANVAS_ITEM (ethi)->canvas)->vadjustment;
-
- value = h->value;
-
- gtk_adjustment_set_value(h, CLAMP(h->value + dx, h->lower, h->upper - h->page_size));
-
- if (h->value != value)
- do_drag_motion(ethi,
- ethi->last_drop_context,
- ethi->last_drop_x + h->value,
- ethi->last_drop_y + v->value,
- ethi->last_drop_time,
- TRUE);
-
- return TRUE;
-}
-
-static void
-scroll_on (ETableHeaderItem *ethi, guint scroll_direction)
-{
- if (ethi->scroll_idle_id == 0 || scroll_direction != ethi->scroll_direction) {
- if (ethi->scroll_idle_id != 0)
- g_source_remove (ethi->scroll_idle_id);
- ethi->scroll_direction = scroll_direction;
- ethi->scroll_idle_id = g_timeout_add (100, scroll_timeout, ethi);
- }
-}
-
-static void
-scroll_off (ETableHeaderItem *ethi)
-{
- if (ethi->scroll_idle_id) {
- g_source_remove (ethi->scroll_idle_id);
- ethi->scroll_idle_id = 0;
- }
-}
-
-static void
-context_destroyed (gpointer data)
-{
- ETableHeaderItem *ethi = data;
-
- ethi->last_drop_x = 0;
- ethi->last_drop_y = 0;
- ethi->last_drop_time = 0;
- ethi->last_drop_context = NULL;
- scroll_off (ethi);
-
- g_object_unref (ethi);
-}
-
-static void
-context_connect (ETableHeaderItem *ethi, GdkDragContext *context)
-{
- if (g_dataset_get_data (context, "e-table-header-item") == NULL) {
- g_object_ref (ethi);
- g_dataset_set_data_full (context, "e-table-header-item", ethi, context_destroyed);
- }
-}
-
-static gboolean
-ethi_drag_motion (GtkWidget *widget, GdkDragContext *context,
- gint x, gint y, guint time,
- ETableHeaderItem *ethi)
-{
- char *droptype, *headertype;
- guint direction = 0;
-
- gdk_drag_status (context, 0, time);
-
- droptype = gdk_atom_name (GDK_POINTER_TO_ATOM (context->targets->data));
- headertype = g_strdup_printf ("%s-%s", TARGET_ETABLE_COL_TYPE,
- ethi->dnd_code);
-
- if (strcmp (droptype, headertype) != 0) {
- g_free (headertype);
- return FALSE;
- }
-
- g_free (headertype);
-
- d(g_print ("y = %d, widget->allocation.y = %d, GTK_LAYOUT (widget)->vadjustment->value = %f\n", y, widget->allocation.y, GTK_LAYOUT (widget)->vadjustment->value));
-
- if (x < 20)
- direction |= ET_SCROLL_LEFT;
- if (x > widget->allocation.width - 20)
- direction |= ET_SCROLL_RIGHT;
-
- ethi->last_drop_x = x;
- ethi->last_drop_y = y;
- ethi->last_drop_time = time;
- ethi->last_drop_context = context;
- context_connect (ethi, context);
-
- do_drag_motion (ethi,
- context,
- x + GTK_LAYOUT(widget)->hadjustment->value,
- y + GTK_LAYOUT(widget)->vadjustment->value,
- time,
- FALSE);
-
- if (direction != 0)
- scroll_on (ethi, direction);
- else
- scroll_off (ethi);
-
- return TRUE;
-}
-
-static void
-ethi_drag_end (GtkWidget *canvas, GdkDragContext *context, ETableHeaderItem *ethi)
-{
- if (context->action == 0) {
- e_table_header_remove (ethi->eth, ethi->drag_col);
- gnome_canvas_item_request_update(GNOME_CANVAS_ITEM(ethi));
- }
- ethi_remove_drop_marker (ethi);
- ethi_remove_destroy_marker (ethi);
- ethi->drag_col = -1;
- scroll_off (ethi);
-}
-
-static void
-ethi_drag_data_received (GtkWidget *canvas,
- GdkDragContext *drag_context,
- gint x,
- gint y,
- GtkSelectionData *data,
- guint info,
- guint time,
- ETableHeaderItem *ethi)
-{
- int found = FALSE;
- int count;
- int column;
- int drop_col;
- int i;
-
- if (data->data) {
- count = e_table_header_count(ethi->eth);
- column = atoi(data->data);
- drop_col = ethi->drop_col;
- ethi->drop_col = -1;
-
- if (column >= 0) {
- for (i = 0; i < count; i++) {
- ETableCol *ecol = e_table_header_get_column (ethi->eth, i);
- if (ecol->col_idx == column) {
- e_table_header_move(ethi->eth, i, drop_col);
- found = TRUE;
- break;
- }
- }
- if (!found) {
- count = e_table_header_count(ethi->full_header);
- for (i = 0; i < count; i++) {
- ETableCol *ecol = e_table_header_get_column (ethi->full_header, i);
- if (ecol->col_idx == column) {
- e_table_header_add_column (ethi->eth, ecol, drop_col);
- break;
- }
- }
- }
- }
- }
- ethi_remove_drop_marker (ethi);
- gnome_canvas_item_request_update(GNOME_CANVAS_ITEM(ethi));
-}
-
-static void
-ethi_drag_data_get (GtkWidget *canvas,
- GdkDragContext *context,
- GtkSelectionData *selection_data,
- guint info,
- guint time,
- ETableHeaderItem *ethi)
-{
- if (ethi->drag_col != -1) {
- ETableCol *ecol = e_table_header_get_column (ethi->eth, ethi->drag_col);
-
- gchar *string = g_strdup_printf("%d", ecol->col_idx);
- gtk_selection_data_set(selection_data,
- GDK_SELECTION_TYPE_STRING,
- sizeof(string[0]),
- string,
- strlen(string));
- g_free(string);
- }
-}
-
-static gboolean
-ethi_drag_drop (GtkWidget *canvas,
- GdkDragContext *context,
- gint x,
- gint y,
- guint time,
- ETableHeaderItem *ethi)
-{
- gboolean successful = FALSE;
-
- if ((x >= 0) && (x <= (ethi->width)) &&
- (y >= 0) && (y <= (ethi->height))){
- int col;
-
- col = ethi_find_col_by_x_nearest (ethi, x);
-
- ethi_add_drop_marker (ethi, col, FALSE);
-
- ethi->drop_col = col;
-
- if (col != -1) {
- char *target = g_strdup_printf ("%s-%s", TARGET_ETABLE_COL_TYPE, ethi->dnd_code);
- d(g_print ("ethi - %s\n", target));
- gtk_drag_get_data (canvas, context, gdk_atom_intern(target, FALSE), time);
- g_free (target);
- }
- }
- gtk_drag_finish (context, successful, successful, time);
- scroll_off (ethi);
- return successful;
-}
-
-static void
-ethi_drag_leave (GtkWidget *widget, GdkDragContext *context, guint time, ETableHeaderItem *ethi)
-{
- ethi_remove_drop_marker (ethi);
- if (ethi->drag_col != -1)
- ethi_add_destroy_marker (ethi);
-}
-
-static void
-ethi_realize (GnomeCanvasItem *item)
-{
- ETableHeaderItem *ethi = E_TABLE_HEADER_ITEM (item);
- GdkWindow *window;
- GtkTargetEntry ethi_drop_types [] = {
- { TARGET_ETABLE_COL_TYPE, 0, TARGET_ETABLE_COL_HEADER },
- };
-
-
- if (GNOME_CANVAS_ITEM_CLASS (ethi_parent_class)-> realize)
- (*GNOME_CANVAS_ITEM_CLASS (ethi_parent_class)->realize)(item);
-
- window = GTK_WIDGET (item->canvas)->window;
-
- if (!ethi->font)
- ethi_font_set (ethi, gtk_style_get_font (GTK_WIDGET (item->canvas)->style));
-
- /*
- * Now, configure DnD
- */
- ethi_drop_types[0].target = g_strdup_printf("%s-%s", ethi_drop_types[0].target, ethi->dnd_code);
- gtk_drag_dest_set (GTK_WIDGET (item->canvas), 0,
- ethi_drop_types, ELEMENTS (ethi_drop_types),
- GDK_ACTION_MOVE);
- g_free(ethi_drop_types[0].target);
-
- /* Drop signals */
- ethi->drag_motion_id = g_signal_connect (item->canvas, "drag_motion",
- G_CALLBACK (ethi_drag_motion), ethi);
- ethi->drag_leave_id = g_signal_connect (item->canvas, "drag_leave",
- G_CALLBACK (ethi_drag_leave), ethi);
- ethi->drag_drop_id = g_signal_connect (item->canvas, "drag_drop",
- G_CALLBACK (ethi_drag_drop), ethi);
- ethi->drag_data_received_id = g_signal_connect (item->canvas, "drag_data_received",
- G_CALLBACK (ethi_drag_data_received), ethi);
-
- /* Drag signals */
- ethi->drag_end_id = g_signal_connect (item->canvas, "drag_end",
- G_CALLBACK (ethi_drag_end), ethi);
- ethi->drag_data_get_id = g_signal_connect (item->canvas, "drag_data_get",
- G_CALLBACK (ethi_drag_data_get), ethi);
-
-}
-
-static void
-ethi_unrealize (GnomeCanvasItem *item)
-{
- ETableHeaderItem *ethi = E_TABLE_HEADER_ITEM (item);
-
- gdk_font_unref (ethi->font);
-
- g_signal_handler_disconnect (item->canvas, ethi->drag_motion_id);
- g_signal_handler_disconnect (item->canvas, ethi->drag_leave_id);
- g_signal_handler_disconnect (item->canvas, ethi->drag_drop_id);
- g_signal_handler_disconnect (item->canvas, ethi->drag_data_received_id);
-
- g_signal_handler_disconnect (item->canvas, ethi->drag_end_id);
- g_signal_handler_disconnect (item->canvas, ethi->drag_data_get_id);
-
- gtk_drag_dest_unset (GTK_WIDGET (item->canvas));
-
- if (ethi->stipple){
- gdk_bitmap_unref (ethi->stipple);
- ethi->stipple = NULL;
- }
-
- if (GNOME_CANVAS_ITEM_CLASS (ethi_parent_class)->unrealize)
- (*GNOME_CANVAS_ITEM_CLASS (ethi_parent_class)->unrealize)(item);
-}
-
-static void
-ethi_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, int height)
-{
- ETableHeaderItem *ethi = E_TABLE_HEADER_ITEM (item);
- GnomeCanvas *canvas = item->canvas;
- const int cols = e_table_header_count (ethi->eth);
- int x1, x2;
- int col;
- GHashTable *arrows = g_hash_table_new (NULL, NULL);
-
-
- if (ethi->sort_info) {
- int length = e_table_sort_info_grouping_get_count(ethi->sort_info);
- int i;
- for (i = 0; i < length; i++) {
- ETableSortColumn column = e_table_sort_info_grouping_get_nth(ethi->sort_info, i);
- g_hash_table_insert (arrows,
- GINT_TO_POINTER (column.column),
- GINT_TO_POINTER (column.ascending ?
- E_TABLE_COL_ARROW_DOWN :
- E_TABLE_COL_ARROW_UP));
- }
- length = e_table_sort_info_sorting_get_count(ethi->sort_info);
- for (i = 0; i < length; i++) {
- ETableSortColumn column = e_table_sort_info_sorting_get_nth(ethi->sort_info, i);
- g_hash_table_insert (arrows,
- GINT_TO_POINTER (column.column),
- GINT_TO_POINTER (column.ascending ?
- E_TABLE_COL_ARROW_DOWN :
- E_TABLE_COL_ARROW_UP));
- }
- }
-
- ethi->width = e_table_header_total_width (ethi->eth) + ethi->group_indent_width;
- x1 = x2 = 0;
- x2 += ethi->group_indent_width;
- for (col = 0; col < cols; col++, x1 = x2){
- ETableCol *ecol = e_table_header_get_column (ethi->eth, col);
- int col_width;
-
- col_width = ecol->width;
-
- x2 += col_width;
-
- if (x1 > (x + width))
- break;
-
- if (x2 < x)
- continue;
-
- if (x2 <= x1)
- continue;
-
- e_table_header_draw_button (drawable, ecol,
- GTK_WIDGET (canvas)->style,
- GTK_WIDGET_STATE (canvas),
- GTK_WIDGET (canvas),
- x1 - x, -y,
- width, height,
- x2 - x1, ethi->height,
- (ETableColArrow) g_hash_table_lookup (
- arrows, GINT_TO_POINTER (ecol->col_idx)));
- }
-
- g_hash_table_destroy (arrows);
-}
-
-static double
-ethi_point (GnomeCanvasItem *item, double x, double y, int cx, int cy,
- GnomeCanvasItem **actual_item)
-{
- *actual_item = item;
- return 0.0;
-}
-
-/*
- * is_pointer_on_division:
- *
- * Returns whether @pos is a column header division; If @the_total is not NULL,
- * then the actual position is returned here. If @return_ecol is not NULL,
- * then the ETableCol that actually contains this point is returned here
- */
-static gboolean
-is_pointer_on_division (ETableHeaderItem *ethi, int pos, int *the_total, int *return_col)
-{
- const int cols = e_table_header_count (ethi->eth);
- int col, total;
-
- total = 0;
- for (col = 0; col < cols; col++){
- ETableCol *ecol = e_table_header_get_column (ethi->eth, col);
-
- if (col == 0)
- total += ethi->group_indent_width;
-
- total += ecol->width;
-
- if ((total - TOLERANCE < pos)&& (pos < total + TOLERANCE)){
- if (return_col)
- *return_col = col;
- if (the_total)
- *the_total = total;
-
- return TRUE;
- }
- if (return_col)
- *return_col = col;
-
- if (total > pos + TOLERANCE)
- return FALSE;
- }
-
- return FALSE;
-}
-
-#define convert(c,sx,sy,x,y) gnome_canvas_w2c (c,sx,sy,x,y)
-
-static void
-set_cursor (ETableHeaderItem *ethi, int pos)
-{
- int col;
- GtkWidget *canvas = GTK_WIDGET (GNOME_CANVAS_ITEM (ethi)->canvas);
- gboolean resizable = FALSE;
-
- /* We might be invoked before we are realized */
- if (!canvas->window)
- return;
-
- if (is_pointer_on_division (ethi, pos, NULL, &col)) {
- int last_col = ethi->eth->col_count - 1;
- ETableCol *ecol = e_table_header_get_column (ethi->eth, col);
-
- /* Last column is not resizable */
- if (ecol->resizable && col != last_col) {
- int c = col + 1;
-
- /* Column is not resizable if all columns after it
- are also not resizable */
- for (; c <= last_col; c++){
- ETableCol *ecol2;
-
- ecol2 = e_table_header_get_column (ethi->eth, c);
- if (ecol2->resizable) {
- resizable = TRUE;
- break;
- }
- }
- }
- }
-
- if (resizable)
- e_cursor_set (canvas->window, E_CURSOR_SIZE_X);
- else
- gdk_window_set_cursor (canvas->window, NULL);
- /* e_cursor_set (canvas->window, E_CURSOR_ARROW);*/
-}
-
-static void
-ethi_end_resize (ETableHeaderItem *ethi)
-{
- ethi->resize_col = -1;
- ethi->resize_guide = GINT_TO_POINTER (0);
-
- gnome_canvas_item_request_update (GNOME_CANVAS_ITEM(ethi));
-}
-
-static gboolean
-ethi_maybe_start_drag (ETableHeaderItem *ethi, GdkEventMotion *event)
-{
- if (!ethi->maybe_drag)
- return FALSE;
-
- if (ethi->eth->col_count < 2) {
- ethi->maybe_drag = FALSE;
- return FALSE;
- }
-
- if (MAX (abs (ethi->click_x - event->x),
- abs (ethi->click_y - event->y)) <= 3)
- return FALSE;
-
- return TRUE;
-}
-
-static void
-ethi_start_drag (ETableHeaderItem *ethi, GdkEvent *event)
-{
- GtkWidget *widget = GTK_WIDGET (GNOME_CANVAS_ITEM (ethi)->canvas);
- GtkTargetList *list;
- GdkDragContext *context;
- ETableCol *ecol;
- int col_width;
- GdkPixmap *pixmap;
- int group_indent = 0;
- GHashTable *arrows = g_hash_table_new (NULL, NULL);
-
- GtkTargetEntry ethi_drag_types [] = {
- { TARGET_ETABLE_COL_TYPE, 0, TARGET_ETABLE_COL_HEADER },
- };
-
- ethi->drag_col = ethi_find_col_by_x (ethi, event->motion.x);
-
- if (ethi->drag_col == -1)
- return;
-
- if (ethi->sort_info) {
- int length = e_table_sort_info_grouping_get_count(ethi->sort_info);
- int i;
- for (i = 0; i < length; i++) {
- ETableSortColumn column =
- e_table_sort_info_grouping_get_nth(
- ethi->sort_info, i);
- group_indent ++;
- g_hash_table_insert (
- arrows,
- GINT_TO_POINTER (column.column),
- GINT_TO_POINTER (column.ascending ?
- E_TABLE_COL_ARROW_DOWN :
- E_TABLE_COL_ARROW_UP));
- }
- length = e_table_sort_info_sorting_get_count(ethi->sort_info);
- for (i = 0; i < length; i++) {
- ETableSortColumn column =
- e_table_sort_info_sorting_get_nth (
- ethi->sort_info, i);
-
- g_hash_table_insert (
- arrows,
- GINT_TO_POINTER (column.column),
- GINT_TO_POINTER (column.ascending ?
- E_TABLE_COL_ARROW_DOWN :
- E_TABLE_COL_ARROW_UP));
- }
- }
-
- ethi_drag_types[0].target = g_strdup_printf(
- "%s-%s", ethi_drag_types[0].target, ethi->dnd_code);
- list = gtk_target_list_new (
- ethi_drag_types, ELEMENTS (ethi_drag_types));
- context = gtk_drag_begin (widget, list, GDK_ACTION_MOVE, 1, event);
- g_free(ethi_drag_types[0].target);
-
- ecol = e_table_header_get_column (ethi->eth, ethi->drag_col);
- col_width = ecol->width;
- pixmap = gdk_pixmap_new (widget->window, col_width, ethi->height, -1);
-
- e_table_header_draw_button (
- pixmap, ecol,
- widget->style,
- GTK_WIDGET_STATE (widget),
- widget,
- 0, 0,
- col_width, ethi->height,
- col_width, ethi->height,
- (ETableColArrow) g_hash_table_lookup (
- arrows, GINT_TO_POINTER (ecol->col_idx)));
- gtk_drag_set_icon_pixmap (
- context,
- gdk_window_get_colormap (widget->window),
- pixmap,
- NULL,
- col_width / 2,
- ethi->height / 2);
- gdk_pixmap_unref (pixmap);
-
- ethi->maybe_drag = FALSE;
- g_hash_table_destroy (arrows);
-}
-
-typedef struct {
- ETableHeaderItem *ethi;
- int col;
-} EthiHeaderInfo;
-
-static void
-ethi_popup_sort_ascending(GtkWidget *widget, EthiHeaderInfo *info)
-{
- ETableCol *col;
- int model_col;
- int length;
- int i;
- int found = FALSE;
- ETableHeaderItem *ethi = info->ethi;
-
- col = e_table_header_get_column (ethi->eth, info->col);
- model_col = col->col_idx;
-
- length = e_table_sort_info_grouping_get_count(ethi->sort_info);
- for (i = 0; i < length; i++) {
- ETableSortColumn column = e_table_sort_info_grouping_get_nth (
- ethi->sort_info, i);
-
- if (model_col == column.column){
- column.ascending = 1;
- e_table_sort_info_grouping_set_nth (
- ethi->sort_info, i, column);
- found = 1;
- break;
- }
- }
- if (!found) {
- length = e_table_sort_info_sorting_get_count (
- ethi->sort_info);
- for (i = 0; i < length; i++) {
- ETableSortColumn column =
- e_table_sort_info_sorting_get_nth(
- ethi->sort_info, i);
- if (model_col == column.column){
- column.ascending = 1;
- e_table_sort_info_sorting_set_nth (
- ethi->sort_info, i, column);
- found = 1;
- break;
- }
- }
- }
- if (!found) {
- ETableSortColumn column;
- column.column = model_col;
- column.ascending = 1;
- length = e_table_sort_info_sorting_get_count(ethi->sort_info);
- if (length == 0)
- length++;
- e_table_sort_info_sorting_set_nth(ethi->sort_info, length - 1, column);
- }
-}
-
-static void
-ethi_popup_sort_descending(GtkWidget *widget, EthiHeaderInfo *info)
-{
- ETableCol *col;
- int model_col;
- int length;
- int i;
- int found = FALSE;
- ETableHeaderItem *ethi = info->ethi;
-
- col = e_table_header_get_column (ethi->eth, info->col);
- model_col = col->col_idx;
-
- length = e_table_sort_info_grouping_get_count(ethi->sort_info);
- for (i = 0; i < length; i++) {
- ETableSortColumn column = e_table_sort_info_grouping_get_nth(
- ethi->sort_info, i);
- if (model_col == column.column){
- column.ascending = 0;
- e_table_sort_info_grouping_set_nth(
- ethi->sort_info, i, column);
- found = 1;
- break;
- }
- }
- if (!found) {
- length = e_table_sort_info_sorting_get_count (ethi->sort_info);
- for (i = 0; i < length; i++) {
- ETableSortColumn column =
- e_table_sort_info_sorting_get_nth(
- ethi->sort_info, i);
-
- if (model_col == column.column){
- column.ascending = 0;
- e_table_sort_info_sorting_set_nth (
- ethi->sort_info, i, column);
- found = 1;
- break;
- }
- }
- }
- if (!found) {
- ETableSortColumn column;
- column.column = model_col;
- column.ascending = 0;
- length = e_table_sort_info_sorting_get_count (ethi->sort_info);
- if (length == 0)
- length++;
- e_table_sort_info_sorting_set_nth (
- ethi->sort_info, length - 1, column);
- }
-}
-
-static void
-ethi_popup_unsort(GtkWidget *widget, EthiHeaderInfo *info)
-{
- ETableHeaderItem *ethi = info->ethi;
-
- e_table_sort_info_grouping_truncate(ethi->sort_info, 0);
- e_table_sort_info_sorting_truncate(ethi->sort_info, 0);
-}
-
-static void
-ethi_popup_group_field(GtkWidget *widget, EthiHeaderInfo *info)
-{
- ETableCol *col;
- int model_col;
- ETableHeaderItem *ethi = info->ethi;
- ETableSortColumn column;
-
- col = e_table_header_get_column (ethi->eth, info->col);
- model_col = col->col_idx;
-
- column.column = model_col;
- column.ascending = 1;
- e_table_sort_info_grouping_set_nth(ethi->sort_info, 0, column);
- e_table_sort_info_grouping_truncate(ethi->sort_info, 1);
-}
-
-static void
-ethi_popup_group_box(GtkWidget *widget, EthiHeaderInfo *info)
-{
-}
-
-static void
-ethi_popup_remove_column(GtkWidget *widget, EthiHeaderInfo *info)
-{
- e_table_header_remove(info->ethi->eth, info->col);
-}
-
-static void
-ethi_popup_field_chooser(GtkWidget *widget, EthiHeaderInfo *info)
-{
- if (info->ethi->etfcd) {
- gtk_window_present (GTK_WINDOW (info->ethi->etfcd));
-
- return;
- }
-
- info->ethi->etfcd = e_table_field_chooser_dialog_new();
- g_object_add_weak_pointer (G_OBJECT (info->ethi->etfcd), (gpointer *)&info->ethi->etfcd);
-
- g_object_set(info->ethi->etfcd,
- "full_header", info->ethi->full_header,
- "header", info->ethi->eth,
- "dnd_code", info->ethi->dnd_code,
- NULL);
-
- gtk_widget_show(info->ethi->etfcd);
-}
-
-static void
-ethi_popup_alignment(GtkWidget *widget, EthiHeaderInfo *info)
-{
-}
-
-static void
-ethi_popup_best_fit(GtkWidget *widget, EthiHeaderInfo *info)
-{
- ETableHeaderItem *ethi = info->ethi;
- int width;
-
- g_signal_emit_by_name (ethi->eth,
- "request_width",
- info->col, &width);
- /* Add 10 to stop it from "..."ing */
- e_table_header_set_size (ethi->eth, info->col, width + 10);
-
- gnome_canvas_item_request_update (GNOME_CANVAS_ITEM(ethi));
-
-}
-
-static void
-ethi_popup_format_columns(GtkWidget *widget, EthiHeaderInfo *info)
-{
-}
-
-static void
-config_destroyed (gpointer data, GObject *where_object_was)
-{
- ETableHeaderItem *ethi = data;
- ethi->config = NULL;
-}
-
-static void
-apply_changes (ETableConfig *config, ETableHeaderItem *ethi)
-{
- char *state = e_table_state_save_to_string (config->state);
-
- if (ethi->table)
- e_table_set_state (ethi->table, state);
- if (ethi->tree)
- e_tree_set_state (ethi->tree, state);
- g_free (state);
-
- gtk_dialog_set_response_sensitive (GTK_DIALOG (config->dialog_toplevel),
- GTK_RESPONSE_APPLY, FALSE);
-}
-
-static void
-ethi_popup_customize_view(GtkWidget *widget, EthiHeaderInfo *info)
-{
- ETableHeaderItem *ethi = info->ethi;
- ETableState *state;
- ETableSpecification *spec;
-
- if (ethi->config)
- e_table_config_raise (E_TABLE_CONFIG (ethi->config));
- else {
- if (ethi->table) {
- state = e_table_get_state_object(ethi->table);
- spec = ethi->table->spec;
- } else if (ethi->tree) {
- state = e_tree_get_state_object(ethi->tree);
- spec = e_tree_get_spec (ethi->tree);
- } else
- return;
-
- ethi->config = e_table_config_new (
- _("Customize Current View"),
- spec, state, GTK_WINDOW (gtk_widget_get_toplevel (widget)));
- g_object_weak_ref (G_OBJECT (ethi->config),
- config_destroyed, ethi);
- g_signal_connect (
- ethi->config, "changed",
- G_CALLBACK (apply_changes), ethi);
- }
-}
-
-static void
-free_popup_info (GtkWidget *w, EthiHeaderInfo *info)
-{
- g_free (info);
-}
-
-/* Bit 1 is always disabled. */
-/* Bit 2 is disabled if not "sortable". */
-/* Bit 4 is disabled if we don't have a pointer to our table object. */
-static EPopupMenu ethi_context_menu [] = {
- E_POPUP_ITEM (N_("Sort Ascending"), G_CALLBACK(ethi_popup_sort_ascending), 2),
- E_POPUP_ITEM (N_("Sort Descending"), G_CALLBACK(ethi_popup_sort_descending), 2),
- E_POPUP_ITEM (N_("Unsort"), G_CALLBACK(ethi_popup_unsort), 0),
- E_POPUP_SEPARATOR,
- E_POPUP_ITEM (N_("Group By This Field"), G_CALLBACK(ethi_popup_group_field), 16),
- E_POPUP_ITEM (N_("Group By Box"), G_CALLBACK(ethi_popup_group_box), 128),
- E_POPUP_SEPARATOR,
- E_POPUP_ITEM (N_("Remove This Column"), G_CALLBACK(ethi_popup_remove_column), 8),
- E_POPUP_ITEM (N_("Add a Column..."), G_CALLBACK(ethi_popup_field_chooser), 0),
- E_POPUP_SEPARATOR,
- E_POPUP_ITEM (N_("Alignment"), G_CALLBACK(ethi_popup_alignment), 128),
- E_POPUP_ITEM (N_("Best Fit"), G_CALLBACK(ethi_popup_best_fit), 2),
- E_POPUP_ITEM (N_("Format Columns..."), G_CALLBACK(ethi_popup_format_columns), 128),
- E_POPUP_SEPARATOR,
- E_POPUP_ITEM (N_("Customize Current View..."), G_CALLBACK(ethi_popup_customize_view), 4),
- E_POPUP_TERMINATOR
-};
-
-static void
-ethi_header_context_menu (ETableHeaderItem *ethi, GdkEventButton *event)
-{
- EthiHeaderInfo *info = g_new(EthiHeaderInfo, 1);
- ETableCol *col;
- GtkMenu *popup;
- info->ethi = ethi;
- info->col = ethi_find_col_by_x (ethi, event->x);
- col = e_table_header_get_column (ethi->eth, info->col);
-
- popup = e_popup_menu_create_with_domain (ethi_context_menu,
- 1 +
- (col->sortable ? 0 : 2) +
- ((ethi->table || ethi->tree) ? 0 : 4) +
- ((e_table_header_count (ethi->eth) > 1) ? 0 : 8),
- ((e_table_sort_info_get_can_group (ethi->sort_info)) ? 0 : 16) +
- 128, info, E_I18N_DOMAIN);
- g_object_ref (popup);
- gtk_object_sink (GTK_OBJECT (popup));
- g_signal_connect (popup, "selection-done",
- G_CALLBACK (free_popup_info), info);
- e_popup_menu (popup, (GdkEvent *) event);
-}
-
-static void
-ethi_button_pressed (ETableHeaderItem *ethi, GdkEventButton *event)
-{
- g_signal_emit (ethi,
- ethi_signals [BUTTON_PRESSED], 0, event);
-}
-
-static void
-ethi_change_sort_state (ETableHeaderItem *ethi, ETableCol *col)
-{
- int model_col;
- int length;
- int i;
- int found = FALSE;
-
- if (col == NULL)
- return;
-
- model_col = col->col_idx;
-
- length = e_table_sort_info_grouping_get_count(ethi->sort_info);
- for (i = 0; i < length; i++) {
- ETableSortColumn column = e_table_sort_info_grouping_get_nth(ethi->sort_info, i);
- if (model_col == column.column){
- int ascending = column.ascending;
- ascending = ! ascending;
- column.ascending = ascending;
- e_table_sort_info_grouping_set_nth(ethi->sort_info, i, column);
- found = 1;
- break;
- }
- }
-
- if (!col->sortable)
- return;
-
- if (!found) {
- length = e_table_sort_info_sorting_get_count(ethi->sort_info);
- for (i = 0; i < length; i++) {
- ETableSortColumn column = e_table_sort_info_sorting_get_nth(ethi->sort_info, i);
-
- if (model_col == column.column){
- int ascending = column.ascending;
-
- if (ascending == 0){
- /*
- * This means the user has clicked twice
- * already, lets kill sorting now.
- */
- e_table_sort_info_sorting_truncate (ethi->sort_info, i);
- } else {
- ascending = !ascending;
- column.ascending = ascending;
- e_table_sort_info_sorting_set_nth(ethi->sort_info, i, column);
- }
- found = 1;
- break;
- }
- }
- }
-
- if (!found) {
- ETableSortColumn column;
- column.column = model_col;
- column.ascending = 1;
- length = e_table_sort_info_sorting_get_count(ethi->sort_info);
- if (length == 0)
- length++;
- e_table_sort_info_sorting_set_nth(ethi->sort_info, length - 1, column);
- }
-}
-
-/*
- * Handles the events on the ETableHeaderItem, particularly it handles resizing
- */
-static int
-ethi_event (GnomeCanvasItem *item, GdkEvent *e)
-{
- ETableHeaderItem *ethi = E_TABLE_HEADER_ITEM (item);
- GnomeCanvas *canvas = item->canvas;
- const gboolean resizing = ETHI_RESIZING (ethi);
- int x, y, start, col;
- int was_maybe_drag = 0;
-
- switch (e->type){
- case GDK_ENTER_NOTIFY:
- convert (canvas, e->crossing.x, e->crossing.y, &x, &y);
- set_cursor (ethi, x);
- break;
-
- case GDK_LEAVE_NOTIFY:
- gdk_window_set_cursor (GTK_WIDGET (canvas)->window, NULL);
- /* e_cursor_set (GTK_WIDGET (canvas)->window, E_CURSOR_ARROW);*/
- break;
-
- case GDK_MOTION_NOTIFY:
-
- convert (canvas, e->motion.x, e->motion.y, &x, &y);
- if (resizing){
- int new_width;
-
- if (ethi->resize_guide == NULL){
- /* Quick hack until I actually bind the views */
- ethi->resize_guide = GINT_TO_POINTER (1);
-
- gnome_canvas_item_grab (item,
- GDK_POINTER_MOTION_MASK |
- GDK_BUTTON_RELEASE_MASK,
- e_cursor_get (E_CURSOR_SIZE_X),
- e->button.time);
- }
-
- new_width = x - ethi->resize_start_pos;
-
- e_table_header_set_size (ethi->eth, ethi->resize_col, new_width);
-
- gnome_canvas_item_request_update (GNOME_CANVAS_ITEM(ethi));
- } else if (ethi_maybe_start_drag (ethi, &e->motion)){
- ethi_start_drag (ethi, e);
- } else
- set_cursor (ethi, x);
- break;
-
- case GDK_BUTTON_PRESS:
- if (e->button.button > 3)
- return FALSE;
-
- convert (canvas, e->button.x, e->button.y, &x, &y);
-
- if (is_pointer_on_division (ethi, x, &start, &col) && e->button.button == 1){
- ETableCol *ecol;
-
- /*
- * Record the important bits.
- *
- * By setting resize_pos to a non -1 value,
- * we know that we are being resized (used in the
- * other event handlers).
- */
- ecol = e_table_header_get_column (ethi->eth, col);
-
- if (!ecol->resizable)
- break;
- ethi->resize_col = col;
- ethi->resize_start_pos = start - ecol->width;
- ethi->resize_min_width = ecol->min_width;
- } else {
- if (e->button.button == 1){
- ethi->click_x = e->button.x;
- ethi->click_y = e->button.y;
- ethi->maybe_drag = TRUE;
- is_pointer_on_division (ethi, x, &start, &col);
- ethi->selected_col = col;
- e_canvas_item_grab_focus (item, TRUE);
- } else if (e->button.button == 3){
- ethi_header_context_menu (ethi, &e->button);
- } else
- ethi_button_pressed (ethi, &e->button);
- }
- break;
-
- case GDK_2BUTTON_PRESS:
- if (!resizing)
- break;
-
- if (e->button.button != 1)
- break;
- else {
- int width = 0;
- g_signal_emit_by_name (ethi->eth,
- "request_width",
- (int)ethi->resize_col, &width);
- /* Add 10 to stop it from "..."ing */
- e_table_header_set_size (ethi->eth, ethi->resize_col, width + 10);
-
- gnome_canvas_item_request_update (GNOME_CANVAS_ITEM(ethi));
- ethi->maybe_drag = FALSE;
- }
- break;
-
- case GDK_BUTTON_RELEASE: {
- gboolean needs_ungrab = FALSE;
-
- was_maybe_drag = ethi->maybe_drag;
-
- ethi->maybe_drag = FALSE;
-
- if (ethi->resize_col != -1){
- needs_ungrab = (ethi->resize_guide != NULL);
- ethi_end_resize (ethi);
- } else if (was_maybe_drag && ethi->sort_info) {
- ETableCol *col;
-
- col = e_table_header_get_column (ethi->eth, ethi_find_col_by_x (ethi, e->button.x));
- ethi_change_sort_state (ethi, col);
- }
-
- if (needs_ungrab)
- gnome_canvas_item_ungrab (item, e->button.time);
-
- break;
- }
- case GDK_KEY_PRESS:
- if ((e->key.keyval == GDK_F10) && (e->key.state & GDK_SHIFT_MASK)) {
- EthiHeaderInfo *info = g_new(EthiHeaderInfo, 1);
- ETableCol *col;
- GtkMenu *popup;
-
- info->ethi = ethi;
- info->col = ethi->selected_col;
- col = e_table_header_get_column (ethi->eth, info->col);
-
- popup = e_popup_menu_create_with_domain (ethi_context_menu,
- 1 +
- (col->sortable ? 0 : 2) +
- ((ethi->table || ethi->tree) ? 0 : 4) +
- ((e_table_header_count (ethi->eth) > 1) ? 0 : 8),
- ((e_table_sort_info_get_can_group (ethi->sort_info)) ? 0 : 16) +
- 128, info, E_I18N_DOMAIN);
- g_object_ref (popup);
- gtk_object_sink (GTK_OBJECT (popup));
- g_signal_connect (popup, "selection-done",
- G_CALLBACK (free_popup_info), info);
- e_popup_menu (popup, NULL);
- } else if (e->key.keyval == GDK_space) {
- ETableCol *col;
-
- col = e_table_header_get_column (ethi->eth, ethi->selected_col);
- ethi_change_sort_state (ethi, col);
- } else if ((e->key.keyval == GDK_Right) || (e->key.keyval == GDK_KP_Right)) {
- ETableCol *col;
-
- if ((ethi->selected_col < 0) || (ethi->selected_col >= ethi->eth->col_count - 1))
- ethi->selected_col = 0;
- else
- ethi->selected_col++;
- col = e_table_header_get_column (ethi->eth, ethi->selected_col);
- ethi_change_sort_state (ethi, col);
- } else if ((e->key.keyval == GDK_Left) || (e->key.keyval == GDK_KP_Left)) {
- ETableCol *col;
-
- if ((ethi->selected_col <= 0) || (ethi->selected_col >= ethi->eth->col_count))
- ethi->selected_col = ethi->eth->col_count - 1;
- else
- ethi->selected_col--;
- col = e_table_header_get_column (ethi->eth, ethi->selected_col);
- ethi_change_sort_state (ethi, col);
- }
- break;
-
- default:
- return FALSE;
- }
- return TRUE;
-}
-
-static void
-ethi_class_init (GObjectClass *object_class)
-{
- GnomeCanvasItemClass *item_class = (GnomeCanvasItemClass *) object_class;
-
- ethi_parent_class = g_type_class_ref (PARENT_OBJECT_TYPE);
-
- object_class->dispose = ethi_dispose;
- object_class->set_property = ethi_set_property;
- object_class->get_property = ethi_get_property;
-
- item_class->update = ethi_update;
- item_class->realize = ethi_realize;
- item_class->unrealize = ethi_unrealize;
- item_class->draw = ethi_draw;
- item_class->point = ethi_point;
- item_class->event = ethi_event;
-
- g_object_class_install_property (object_class, PROP_DND_CODE,
- g_param_spec_string ("dnd_code",
- _("DnD code"),
- /*_( */"XXX blurb" /*)*/,
- NULL,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class, PROP_TABLE_FONTSET,
- g_param_spec_string ("fontset",
- _("Fontset"),
- /*_( */"XXX blurb" /*)*/,
- NULL,
- G_PARAM_WRITABLE));
-
- g_object_class_install_property (object_class, PROP_FULL_HEADER,
- g_param_spec_object ("full_header",
- _("Full Header"),
- /*_( */"XXX blurb" /*)*/,
- E_TABLE_HEADER_TYPE,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class, PROP_TABLE_HEADER,
- g_param_spec_object ("ETableHeader",
- _("Header"),
- /*_( */"XXX blurb" /*)*/,
- E_TABLE_HEADER_TYPE,
- G_PARAM_WRITABLE));
-
- g_object_class_install_property (object_class, PROP_SORT_INFO,
- g_param_spec_object ("sort_info",
- _("Sort Info"),
- /*_( */"XXX blurb" /*)*/,
- E_TABLE_SORT_INFO_TYPE,
- G_PARAM_WRITABLE));
-
- g_object_class_install_property (object_class, PROP_TABLE,
- g_param_spec_object ("table",
- _("Table"),
- /*_( */"XXX blurb" /*)*/,
- E_TABLE_TYPE,
- G_PARAM_WRITABLE));
-
- g_object_class_install_property (object_class, PROP_TREE,
- g_param_spec_object ("tree",
- _("Tree"),
- /*_( */"XXX blurb" /*)*/,
- E_TREE_TYPE,
- G_PARAM_WRITABLE));
-
- /*
- * Create our pixmaps for DnD
- */
- dnd_colormap = gtk_widget_get_default_colormap ();
- remove_col_pixmap = gdk_pixmap_colormap_create_from_xpm_d (
- NULL, dnd_colormap,
- &remove_col_mask, NULL, remove_col_xpm);
-
- add_col_pixmap = gdk_pixmap_colormap_create_from_xpm_d (
- NULL, dnd_colormap,
- &add_col_mask, NULL, add_col_xpm);
-
- ethi_signals [BUTTON_PRESSED] =
- g_signal_new ("button_pressed",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableHeaderItemClass, button_pressed),
- NULL, NULL,
- e_marshal_NONE__BOXED,
- G_TYPE_NONE, 1, GDK_TYPE_EVENT);
-}
-
-static void
-ethi_init (GnomeCanvasItem *item)
-{
- ETableHeaderItem *ethi = E_TABLE_HEADER_ITEM (item);
-
- ethi->resize_col = -1;
-
- item->x1 = 0;
- item->y1 = 0;
- item->x2 = 0;
- item->y2 = 0;
-
- ethi->drag_col = -1;
- ethi->drag_mark = -1;
-
- ethi->sort_info = NULL;
-
- ethi->sort_info_changed_id = 0;
- ethi->group_info_changed_id = 0;
-
- ethi->group_indent_width = 0;
- ethi->table = NULL;
- ethi->tree = NULL;
-
- ethi->selected_col = 0;
-}
-
-E_MAKE_TYPE (e_table_header_item,
- "ETableHeaderItem",
- ETableHeaderItem,
- ethi_class_init,
- ethi_init,
- PARENT_OBJECT_TYPE)
diff --git a/widgets/table/e-table-header-item.h b/widgets/table/e-table-header-item.h
deleted file mode 100644
index d1e539888c..0000000000
--- a/widgets/table/e-table-header-item.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-header-item.h
- * Copyright 1999, 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- * Miguel de Icaza (miguel@gnu.org)
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_TABLE_HEADER_ITEM_H_
-#define _E_TABLE_HEADER_ITEM_H_
-
-#include <gal/e-table/e-table.h>
-#include <gal/e-table/e-tree.h>
-#include <libgnomecanvas/gnome-canvas.h>
-#include <libxml/tree.h>
-#include <gal/e-table/e-table-header.h>
-#include <gal/e-table/e-table-sort-info.h>
-
-G_BEGIN_DECLS
-
-#define E_TABLE_HEADER_ITEM_TYPE (e_table_header_item_get_type ())
-#define E_TABLE_HEADER_ITEM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TABLE_HEADER_ITEM_TYPE, ETableHeaderItem))
-#define E_TABLE_HEADER_ITEM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TABLE_HEADER_ITEM_TYPE, ETableHeaderItemClass))
-#define E_IS_TABLE_HEADER_ITEM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TABLE_HEADER_ITEM_TYPE))
-#define E_IS_TABLE_HEADER_ITEM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TABLE_HEADER_ITEM_TYPE))
-
-typedef struct {
- GnomeCanvasItem parent;
- ETableHeader *eth;
-
- GdkCursor *change_cursor;
-
- short height, width;
- GdkFont *font;
-
- /*
- * Used during resizing; Could be shorts
- */
- int resize_col;
- int resize_start_pos;
- int resize_min_width;
-
- GtkObject *resize_guide;
-
- int group_indent_width;
-
- /*
- * Ids
- */
- int structure_change_id, dimension_change_id;
-
- /*
- * For dragging columns
- */
- guint maybe_drag:1;
- guint dnd_ready:1;
- int click_x, click_y;
- int drag_col, drop_col, drag_mark;
- guint drag_motion_id, drag_end_id, drag_leave_id, drag_drop_id, drag_data_received_id, drag_data_get_id;
- guint sort_info_changed_id, group_info_changed_id;
- GnomeCanvasItem *remove_item;
- GdkBitmap *stipple;
-
- gchar *dnd_code;
-
- /*
- * For column sorting info
- */
- ETableSortInfo *sort_info;
-
- guint scroll_direction : 4;
- int last_drop_x;
- int last_drop_y;
- int last_drop_time;
- GdkDragContext *last_drop_context;
- int scroll_idle_id;
-
- /* For adding fields. */
- ETableHeader *full_header;
- ETable *table;
- ETree *tree;
- GtkWidget *etfcd;
- void *config;
-
- /* For keyboard navigation*/
- int selected_col;
-
-} ETableHeaderItem;
-
-typedef struct {
- GnomeCanvasItemClass parent_class;
-
- /*
- * signals
- */
- void (*button_pressed) (ETableHeaderItem *ethi, GdkEventButton *button);
-} ETableHeaderItemClass;
-
-GType e_table_header_item_get_type (void);
-
-G_END_DECLS
-
-#endif /* _E_TABLE_HEADER_ITEM_H_ */
diff --git a/widgets/table/e-table-header-utils.c b/widgets/table/e-table-header-utils.c
deleted file mode 100644
index cf99e8ecba..0000000000
--- a/widgets/table/e-table-header-utils.c
+++ /dev/null
@@ -1,480 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-header-utils.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- * Miguel de Icaza <miguel@ximian.com>
- * Federico Mena-Quintero <federico@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "e-table-header-utils.h"
-
-#include <string.h> /* strlen() */
-#include <glib.h>
-#include <gtk/gtkbutton.h>
-#include <gtk/gtkwindow.h>
-#include "e-table-defines.h"
-#include <gal/widgets/e-unicode.h>
-
-
-
-static PangoLayout*
-build_header_layout (GtkWidget *widget, const char *str)
-{
- PangoLayout *layout;
-
- layout = gtk_widget_create_pango_layout (widget, str);
-
-#ifdef FROB_FONT_DESC
- {
- PangoFontDescription *desc;
- desc = pango_font_description_copy (gtk_widget_get_style (widget)->font_desc);
- pango_font_description_set_size (desc,
- pango_font_description_get_size (desc) * 1.2);
-
- pango_font_description_set_weight (desc, PANGO_WEIGHT_BOLD);
- pango_layout_set_font_description (layout, desc);
-
- pango_font_description_free (desc);
- }
-#endif
-
- return layout;
-}
-
-/**
- * e_table_header_compute_height:
- * @ecol: Table column description.
- * @widget: The widget from which to build the PangoLayout.
- *
- * Computes the minimum height required for a table header button.
- *
- * Return value: The height of the button, in pixels.
- **/
-double
-e_table_header_compute_height (ETableCol *ecol, GtkWidget *widget)
-{
- int ythick;
- int height;
- PangoLayout *layout;
-
- g_return_val_if_fail (ecol != NULL, -1);
- g_return_val_if_fail (E_IS_TABLE_COL (ecol), -1);
- g_return_val_if_fail (GTK_IS_WIDGET (widget), -1);
-
- ythick = gtk_widget_get_style (widget)->ythickness;
-
- layout = build_header_layout (widget, ecol->text);
-
- pango_layout_get_pixel_size (layout, NULL, &height);
-
- if (ecol->is_pixbuf) {
- g_assert (ecol->pixbuf != NULL);
- height = MAX (height, gdk_pixbuf_get_height (ecol->pixbuf));
- }
-
- height = MAX (height, MIN_ARROW_SIZE);
-
- height += 2 * (ythick + HEADER_PADDING);
-
- g_object_unref (layout);
-
- return height;
-}
-
-double
-e_table_header_width_extras (GtkStyle *style)
-{
- g_return_val_if_fail (style != NULL, -1);
-
- return 2 * (style->xthickness + HEADER_PADDING);
-}
-
-/* Creates a pixmap that is a composite of a background color and the upper-left
- * corner rectangle of a pixbuf.
- */
-static GdkPixmap *
-make_composite_pixmap (GdkDrawable *drawable, GdkGC *gc,
- GdkPixbuf *pixbuf, GdkColor *bg, int width, int height,
- int dither_xofs, int dither_yofs)
-{
- int pwidth, pheight;
- GdkPixmap *pixmap;
- GdkPixbuf *tmp;
- int color;
-
- pwidth = gdk_pixbuf_get_width (pixbuf);
- pheight = gdk_pixbuf_get_height (pixbuf);
- g_assert (width <= pwidth && height <= pheight);
-
- color = ((bg->red & 0xff00) << 8) | (bg->green & 0xff00) | ((bg->blue & 0xff00) >> 8);
-
- if (width >= pwidth && height >= pheight) {
- tmp = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, width, height);
- if (!tmp)
- return NULL;
-
- gdk_pixbuf_composite_color (pixbuf, tmp,
- 0, 0,
- width, height,
- 0, 0,
- 1.0, 1.0,
- GDK_INTERP_NEAREST,
- 255,
- 0, 0,
- 16,
- color, color);
- } else {
- int x, y, rowstride;
- GdkPixbuf *fade;
- guchar *pixels;
-
- /* Do a nice fade of the pixbuf down and to the right */
-
- fade = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, width, height);
- if (!fade)
- return NULL;
-
- gdk_pixbuf_copy_area (pixbuf,
- 0, 0,
- width, height,
- fade,
- 0, 0);
-
- rowstride = gdk_pixbuf_get_rowstride (fade);
- pixels = gdk_pixbuf_get_pixels (fade);
-
- for (y = 0; y < height; y++) {
- guchar *p;
- int yfactor;
-
- p = pixels + y * rowstride;
-
- if (height < pheight)
- yfactor = height - y;
- else
- yfactor = height;
-
- for (x = 0; x < width; x++) {
- int xfactor;
-
- if (width < pwidth)
- xfactor = width - x;
- else
- xfactor = width;
-
- p[3] = ((int) p[3] * xfactor * yfactor / (width * height));
- p += 4;
- }
- }
-
- tmp = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, width, height);
- if (!tmp) {
- gdk_pixbuf_unref (fade);
- return NULL;
- }
-
- gdk_pixbuf_composite_color (fade, tmp,
- 0, 0,
- width, height,
- 0, 0,
- 1.0, 1.0,
- GDK_INTERP_NEAREST,
- 255,
- 0, 0,
- 16,
- color, color);
-
- gdk_pixbuf_unref (fade);
- }
-
- pixmap = gdk_pixmap_new (drawable, width, height, gdk_rgb_get_visual ()->depth);
- gdk_draw_rgb_image_dithalign (pixmap, gc,
- 0, 0,
- width, height,
- GDK_RGB_DITHER_NORMAL,
- gdk_pixbuf_get_pixels (tmp),
- gdk_pixbuf_get_rowstride (tmp),
- dither_xofs, dither_yofs);
- gdk_pixbuf_unref (tmp);
-
- return pixmap;
-}
-
-/* Default width of the elision arrow in pixels */
-#define ARROW_WIDTH 4
-
-/**
- * e_table_draw_elided_string:
- * @drawable: Destination drawable.
- * @font: Font for the text.
- * @gc: GC to use for drawing.
- * @x: X insertion point for the string.
- * @y: Y insertion point for the string's baseline.
- * @layout: the PangoLayout to draw.
- * @str: the string we're drawing, passed in so we can change the layout if it needs eliding.
- * @max_width: Maximum width in which the string must fit.
- * @center: Whether to center the string in the available area if it does fit.
- *
- * Draws a string, possibly trimming it so that it fits inside the specified
- * maximum width. If it does not fit, an elision indicator is drawn after the
- * last character that does fit.
- **/
-static void
-e_table_draw_elided_string (GdkDrawable *drawable, GdkGC *gc, GtkWidget *widget,
- int x, int y, PangoLayout *layout, char *str,
- int max_width, gboolean center)
-{
- int width;
- int height;
- int index;
- GSList *lines;
- PangoLayoutLine *line;
-
- g_return_if_fail (drawable != NULL);
- g_return_if_fail (gc != NULL);
- g_return_if_fail (layout != NULL);
- g_return_if_fail (max_width >= 0);
-
- pango_layout_get_pixel_size (layout, &width, &height);
-
- gdk_gc_set_clip_rectangle (gc, NULL);
-
- if (width <= max_width) {
- int xpos;
-
- if (center)
- xpos = x + (max_width - width) / 2;
- else
- xpos = x;
-
- gdk_draw_layout (drawable, gc,
- xpos, y,
- layout);
- } else {
- int arrow_width;
- int i;
-
- if (max_width < ARROW_WIDTH + 1)
- arrow_width = max_width - 1;
- else
- arrow_width = ARROW_WIDTH;
-
-
- lines = pango_layout_get_lines (layout);
- line = lines->data;
-
- if (!pango_layout_line_x_to_index (line,
- (max_width - arrow_width) * PANGO_SCALE,
- &index,
- NULL)) {
- g_warning ("pango_layout_line_x_to_index returned false");
- return;
- }
-
- pango_layout_set_text (layout, str, index);
-
- gdk_draw_layout (drawable, gc, x, y, layout);
-
- for (i = 0; i < arrow_width; i++) {
- int h;
-
- h = 2 * i + 1;
-
- gdk_draw_line (drawable, gc,
- x + max_width - i,
- y + height / 2 - i,
- x + max_width - i,
- y + height / 2 + i + 1);
- }
- }
-}
-
-static GtkWidget *g_label;
-
-/**
- * e_table_header_draw_button:
- * @drawable: Destination drawable.
- * @ecol: Table column for the header information.
- * @style: Style to use for drawing the button.
- * @state: State of the table widget.
- * @widget: The table widget.
- * @x: Leftmost coordinate of the button.
- * @y: Topmost coordinate of the button.
- * @width: Width of the region to draw.
- * @height: Height of the region to draw.
- * @button_width: Width for the complete button.
- * @button_height: Height for the complete button.
- * @arrow: Arrow type to use as a sort indicator.
- *
- * Draws a button suitable for a table header.
- **/
-void
-e_table_header_draw_button (GdkDrawable *drawable, ETableCol *ecol,
- GtkStyle *style, GtkStateType state,
- GtkWidget *widget,
- int x, int y, int width, int height,
- int button_width, int button_height,
- ETableColArrow arrow)
-{
- int xthick, ythick;
- int inner_x, inner_y;
- int inner_width, inner_height;
- GdkGC *gc;
- PangoLayout *layout;
-
- g_return_if_fail (drawable != NULL);
- g_return_if_fail (ecol != NULL);
- g_return_if_fail (E_IS_TABLE_COL (ecol));
- g_return_if_fail (style != NULL);
- g_return_if_fail (widget != NULL);
- g_return_if_fail (GTK_IS_WIDGET (widget));
- g_return_if_fail (button_width > 0 && button_height > 0);
-
- if (g_label == NULL) {
- GtkWidget *button = gtk_button_new_with_label("Hi");
- GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- g_label = GTK_BIN(button)->child;
- gtk_container_add (GTK_CONTAINER (window), button);
- gtk_widget_ensure_style (window);
- gtk_widget_ensure_style (button);
- gtk_widget_ensure_style (g_label);
- }
-
- gc = g_label->style->fg_gc[state];
-
- gdk_gc_set_clip_rectangle (gc, NULL);
-
- xthick = style->xthickness;
- ythick = style->ythickness;
-
- /* Button bevel */
-
- gtk_paint_box (style, drawable, state, GTK_SHADOW_OUT,
- NULL, widget, "button",
- x, y, button_width, button_height);
-
- /* Inside area */
-
- inner_width = button_width - 2 * (xthick + HEADER_PADDING);
- inner_height = button_height - 2 * (ythick + HEADER_PADDING);
-
- if (inner_width < 1 || inner_height < 1)
- return; /* nothing fits */
-
- inner_x = x + xthick + HEADER_PADDING;
- inner_y = y + ythick + HEADER_PADDING;
-
- /* Arrow */
-
- switch (arrow) {
- case E_TABLE_COL_ARROW_NONE:
- break;
-
- case E_TABLE_COL_ARROW_UP:
- case E_TABLE_COL_ARROW_DOWN: {
- int arrow_width, arrow_height;
-
- arrow_width = MIN (MIN_ARROW_SIZE, inner_width);
- arrow_height = MIN (MIN_ARROW_SIZE, inner_height);
-
- gtk_paint_arrow (style, drawable, state,
- GTK_SHADOW_NONE, NULL, widget, "header",
- (arrow == E_TABLE_COL_ARROW_UP) ? GTK_ARROW_UP : GTK_ARROW_DOWN,
- TRUE,
- inner_x + inner_width - arrow_width,
- inner_y + (inner_height - arrow_height) / 2,
- arrow_width, arrow_height);
-
- inner_width -= arrow_width + HEADER_PADDING;
- break;
- }
-
- default:
- g_assert_not_reached ();
- return;
- }
-
- if (inner_width < 1)
- return; /* nothing else fits */
-
- layout = build_header_layout (widget, ecol->text);
-
- /* Pixbuf or label */
- if (ecol->is_pixbuf) {
- int pwidth, pheight;
- int clip_width, clip_height;
- int xpos;
- GdkPixmap *pixmap;
-
- g_assert (ecol->pixbuf != NULL);
-
- pwidth = gdk_pixbuf_get_width (ecol->pixbuf);
- pheight = gdk_pixbuf_get_height (ecol->pixbuf);
-
- clip_width = MIN (pwidth, inner_width);
- clip_height = MIN (pheight, inner_height);
-
- xpos = inner_x;
-
- if (inner_width - pwidth > 11) {
- int width;
- int ypos;
-
- pango_layout_get_pixel_size (layout, &width, NULL);
-
- if (width < inner_width - (pwidth + 1)) {
- xpos = inner_x + (inner_width - width - (pwidth + 1)) / 2;
- }
-
- ypos = inner_y;
-
- e_table_draw_elided_string (drawable, gc, widget,
- xpos + pwidth + 1, ypos,
- layout, ecol->text, inner_width - (xpos - inner_x), FALSE);
- }
-
- pixmap = make_composite_pixmap (drawable, gc,
- ecol->pixbuf, &style->bg[state],
- clip_width, clip_height,
- xpos,
- inner_y + (inner_height - clip_height) / 2);
-
- gdk_gc_set_clip_rectangle (gc, NULL);
-
- if (pixmap) {
- gdk_draw_pixmap (drawable, gc, pixmap,
- 0, 0,
- xpos,
- inner_y + (inner_height - clip_height) / 2,
- clip_width, clip_height);
- gdk_pixmap_unref (pixmap);
- }
- } else {
- e_table_draw_elided_string (drawable, gc, widget,
- inner_x, inner_y,
- layout, ecol->text, inner_width, TRUE);
- }
-
- g_object_unref (layout);
-}
diff --git a/widgets/table/e-table-header-utils.h b/widgets/table/e-table-header-utils.h
deleted file mode 100644
index 38defa9261..0000000000
--- a/widgets/table/e-table-header-utils.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-header-utils.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- * Miguel de Icaza <miguel@ximian.com>
- * Federico Mena-Quintero <federico@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef E_TABLE_HEADER_UTILS_H
-#define E_TABLE_HEADER_UTILS_H
-
-#include <gal/e-table/e-table-col.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-double e_table_header_compute_height (ETableCol *ecol,
- GtkWidget *widget);
-double e_table_header_width_extras (GtkStyle *style);
-void e_table_header_draw_button (GdkDrawable *drawable,
- ETableCol *ecol,
- GtkStyle *style,
- GtkStateType state,
- GtkWidget *widget,
- int x,
- int y,
- int width,
- int height,
- int button_width,
- int button_height,
- ETableColArrow arrow);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif
diff --git a/widgets/table/e-table-header.c b/widgets/table/e-table-header.c
deleted file mode 100644
index d810d61bd1..0000000000
--- a/widgets/table/e-table-header.c
+++ /dev/null
@@ -1,952 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-header.c
- * Copyright 1999, 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- * Miguel de Icaza <miguel@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <string.h>
-#include <glib-object.h>
-#include <gtk/gtkimage.h>
-#include <gal/util/e-util.h>
-#include "e-table-header.h"
-#include "e-table-defines.h"
-#include "gal/util/e-util.h"
-
-/* The arguments we take */
-enum {
- PROP_0,
- PROP_SORT_INFO,
- PROP_WIDTH,
- PROP_WIDTH_EXTRAS
-};
-
-enum {
- STRUCTURE_CHANGE,
- DIMENSION_CHANGE,
- EXPANSION_CHANGE,
- REQUEST_WIDTH,
- LAST_SIGNAL
-};
-
-static void eth_set_size (ETableHeader *eth, int idx, int size);
-static void eth_calc_widths (ETableHeader *eth);
-
-static guint eth_signals [LAST_SIGNAL] = { 0, };
-
-static GObjectClass *e_table_header_parent_class;
-
-struct two_ints {
- int column;
- int width;
-};
-
-static void
-eth_set_width (ETableHeader *eth, int width)
-{
- eth->width = width;
-}
-
-static void
-dequeue (ETableHeader *eth, int *column, int *width)
-{
- GSList *head;
- struct two_ints *store;
- head = eth->change_queue;
- eth->change_queue = eth->change_queue->next;
- if (!eth->change_queue)
- eth->change_tail = NULL;
- store = head->data;
- g_slist_free_1(head);
- if (column)
- *column = store->column;
- if (width)
- *width = store->width;
- g_free(store);
-}
-
-static gboolean
-dequeue_idle (ETableHeader *eth)
-{
- int column, width;
-
- dequeue (eth, &column, &width);
- while (eth->change_queue && ((struct two_ints *) eth->change_queue->data)->column == column)
- dequeue (eth, &column, &width);
-
- if (column == -1)
- eth_set_width (eth, width);
- else if (column < eth->col_count)
- eth_set_size (eth, column, width);
- if (eth->change_queue)
- return TRUE;
- else {
- eth_calc_widths (eth);
- eth->idle = 0;
- return FALSE;
- }
-}
-
-static void
-enqueue (ETableHeader *eth, int column, int width)
-{
- struct two_ints *store;
- store = g_new(struct two_ints, 1);
- store->column = column;
- store->width = width;
-
- eth->change_tail = g_slist_last(g_slist_append(eth->change_tail, store));
- if (!eth->change_queue)
- eth->change_queue = eth->change_tail;
-
- if (!eth->idle) {
- eth->idle = g_idle_add_full(G_PRIORITY_LOW, (GSourceFunc) dequeue_idle, eth, NULL);
- }
-}
-
-void
-e_table_header_set_size (ETableHeader *eth, int idx, int size)
-{
- g_return_if_fail (eth != NULL);
- g_return_if_fail (E_IS_TABLE_HEADER (eth));
-
- enqueue (eth, idx, size);
-}
-
-static void
-eth_do_remove (ETableHeader *eth, int idx, gboolean do_unref)
-{
- if (do_unref)
- g_object_unref (eth->columns [idx]);
-
- memmove (&eth->columns [idx], &eth->columns [idx+1],
- sizeof (ETableCol *) * (eth->col_count - idx - 1));
- eth->col_count--;
-}
-
-static void
-eth_finalize (GObject *object)
-{
- ETableHeader *eth = E_TABLE_HEADER (object);
- const int cols = eth->col_count;
- int i;
-
- if (eth->sort_info) {
- if (eth->sort_info_group_change_id)
- g_signal_handler_disconnect(G_OBJECT(eth->sort_info),
- eth->sort_info_group_change_id);
- g_object_unref(eth->sort_info);
- eth->sort_info = NULL;
- }
-
- if (eth->idle)
- g_source_remove(eth->idle);
- eth->idle = 0;
-
- if (eth->change_queue) {
- g_slist_foreach(eth->change_queue, (GFunc) g_free, NULL);
- g_slist_free(eth->change_queue);
- eth->change_queue = NULL;
- }
-
- /*
- * Destroy columns
- */
- for (i = cols - 1; i >= 0; i--){
- eth_do_remove (eth, i, TRUE);
- }
- g_free (eth->columns);
-
- eth->col_count = 0;
- eth->columns = NULL;
-
- if (e_table_header_parent_class->finalize)
- e_table_header_parent_class->finalize (object);
-}
-
-static void
-eth_group_info_changed(ETableSortInfo *info, ETableHeader *eth)
-{
- enqueue(eth, -1, eth->nominal_width);
-}
-
-static void
-eth_set_property (GObject *object, guint prop_id, const GValue *val, GParamSpec *pspec)
-{
- ETableHeader *eth = E_TABLE_HEADER (object);
-
- switch (prop_id) {
- case PROP_WIDTH:
- eth->nominal_width = g_value_get_double (val);
- enqueue(eth, -1, eth->nominal_width);
- break;
- case PROP_WIDTH_EXTRAS:
- eth->width_extras = g_value_get_double (val);
- enqueue(eth, -1, eth->nominal_width);
- break;
- case PROP_SORT_INFO:
- if (eth->sort_info) {
- if (eth->sort_info_group_change_id)
- g_signal_handler_disconnect(G_OBJECT(eth->sort_info), eth->sort_info_group_change_id);
- g_object_unref (eth->sort_info);
- }
- eth->sort_info = E_TABLE_SORT_INFO(g_value_get_object (val));
- if (eth->sort_info) {
- g_object_ref(eth->sort_info);
- eth->sort_info_group_change_id
- = g_signal_connect(G_OBJECT(eth->sort_info), "group_info_changed",
- G_CALLBACK(eth_group_info_changed), eth);
- }
- enqueue(eth, -1, eth->nominal_width);
- break;
- default:
- break;
- }
-}
-
-static void
-eth_get_property (GObject *object, guint prop_id, GValue *val, GParamSpec *pspec)
-{
- ETableHeader *eth = E_TABLE_HEADER (object);
-
- switch (prop_id) {
- case PROP_SORT_INFO:
- g_value_set_object (val, G_OBJECT(eth->sort_info));
- break;
- case PROP_WIDTH:
- g_value_set_double (val, eth->nominal_width);
- break;
- case PROP_WIDTH_EXTRAS:
- g_value_set_double (val, eth->width_extras);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-e_table_header_class_init (GObjectClass *object_class)
-{
- ETableHeaderClass *klass = E_TABLE_HEADER_CLASS (object_class);
-
- object_class->finalize = eth_finalize;
- object_class->set_property = eth_set_property;
- object_class->get_property = eth_get_property;
-
- e_table_header_parent_class = g_type_class_peek_parent (object_class);
-
- g_object_class_install_property (
- object_class, PROP_WIDTH,
- g_param_spec_double ("width", "Width", "Width",
- 0.0, G_MAXDOUBLE, 0.0,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (
- object_class, PROP_WIDTH_EXTRAS,
- g_param_spec_double ("width_extras", "Width of Extras", "Width of Extras",
- 0.0, G_MAXDOUBLE, 0.0,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (
- object_class, PROP_SORT_INFO,
- g_param_spec_object ("sort_info", "Sort Info", "Sort Info",
- E_TABLE_SORT_INFO_TYPE,
- G_PARAM_READWRITE));
-
- eth_signals [STRUCTURE_CHANGE] =
- g_signal_new ("structure_change",
- E_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableHeaderClass, structure_change),
- (GSignalAccumulator) NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
- eth_signals [DIMENSION_CHANGE] =
- g_signal_new ("dimension_change",
- E_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableHeaderClass, dimension_change),
- (GSignalAccumulator) NULL, NULL,
- g_cclosure_marshal_VOID__INT,
- G_TYPE_NONE, 1, G_TYPE_INT);
- eth_signals [EXPANSION_CHANGE] =
- g_signal_new ("expansion_change",
- E_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableHeaderClass, expansion_change),
- (GSignalAccumulator) NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
- eth_signals [REQUEST_WIDTH] =
- g_signal_new ("request_width",
- E_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableHeaderClass, request_width),
- (GSignalAccumulator) NULL, NULL,
- e_marshal_INT__INT,
- G_TYPE_INT, 1, G_TYPE_INT);
-
- klass->structure_change = NULL;
- klass->dimension_change = NULL;
- klass->expansion_change = NULL;
- klass->request_width = NULL;
-}
-
-static void
-e_table_header_init (ETableHeader *eth)
-{
- eth->col_count = 0;
- eth->width = 0;
-
- eth->sort_info = NULL;
- eth->sort_info_group_change_id = 0;
-
- eth->columns = NULL;
-
- eth->change_queue = NULL;
- eth->change_tail = NULL;
-
- eth->width_extras = 0;
-}
-
-/**
- * e_table_header_new:
- *
- * Returns: A new @ETableHeader object.
- */
-ETableHeader *
-e_table_header_new (void)
-{
-
- return (ETableHeader *) g_object_new (E_TABLE_HEADER_TYPE, NULL);
-}
-
-static void
-eth_update_offsets (ETableHeader *eth)
-{
- int i;
- int x = 0;
-
- for (i = 0; i < eth->col_count; i++){
- ETableCol *etc = eth->columns [i];
-
- etc->x = x;
- x += etc->width;
- }
-}
-
-static void
-eth_do_insert (ETableHeader *eth, int pos, ETableCol *val)
-{
- memmove (&eth->columns [pos+1], &eth->columns [pos],
- sizeof (ETableCol *) * (eth->col_count - pos));
- eth->columns [pos] = val;
- eth->col_count ++;
-}
-
-/**
- * e_table_header_add_column:
- * @eth: the table header to add the column to.
- * @tc: the ETableCol definition
- * @pos: position where the ETableCol will go.
- *
- * This function adds the @tc ETableCol definition into the @eth ETableHeader
- * at position @pos. This is the way you add new ETableCols to the
- * ETableHeader. The header will assume ownership of the @tc; you should not
- * unref it after you add it.
- *
- * This function will emit the "structure_change" signal on the @eth object.
- * The ETableCol is assumed
- */
-void
-e_table_header_add_column (ETableHeader *eth, ETableCol *tc, int pos)
-{
- g_return_if_fail (eth != NULL);
- g_return_if_fail (E_IS_TABLE_HEADER (eth));
- g_return_if_fail (tc != NULL);
- g_return_if_fail (E_IS_TABLE_COL (tc));
- g_return_if_fail (pos >= -1 && pos <= eth->col_count);
-
- if (pos == -1)
- pos = eth->col_count;
- eth->columns = g_realloc (eth->columns, sizeof (ETableCol *) * (eth->col_count + 1));
-
- /*
- * We are the primary owners of the column
- */
- g_object_ref (tc);
-
- eth_do_insert (eth, pos, tc);
-
- enqueue(eth, -1, eth->nominal_width);
- g_signal_emit (G_OBJECT (eth), eth_signals [STRUCTURE_CHANGE], 0);
-}
-
-/**
- * e_table_header_get_column:
- * @eth: the ETableHeader to query
- * @column: the column inside the @eth.
- *
- * Returns: The ETableCol at @column in the @eth object
- */
-ETableCol *
-e_table_header_get_column (ETableHeader *eth, int column)
-{
- g_return_val_if_fail (eth != NULL, NULL);
- g_return_val_if_fail (E_IS_TABLE_HEADER (eth), NULL);
-
- if (column < 0)
- return NULL;
-
- if (column >= eth->col_count)
- return NULL;
-
- return eth->columns [column];
-}
-
-/**
- * e_table_header_get_column_by_col_id:
- * @eth: the ETableHeader to query
- * @col_id: the col_id to search for.
- *
- * Returns: The ETableCol with col_idx = @col_idx in the @eth object
- */
-ETableCol *
-e_table_header_get_column_by_col_idx (ETableHeader *eth, int col_idx)
-{
- int i;
- g_return_val_if_fail (eth != NULL, NULL);
- g_return_val_if_fail (E_IS_TABLE_HEADER (eth), NULL);
-
- for (i = 0; i < eth->col_count; i++) {
- if (eth->columns[i]->col_idx == col_idx) {
- return eth->columns [i];
- }
- }
-
- return NULL;
-}
-
-/**
- * e_table_header_count:
- * @eth: the ETableHeader to query
- *
- * Returns: the number of columns in this ETableHeader.
- */
-int
-e_table_header_count (ETableHeader *eth)
-{
- g_return_val_if_fail (eth != NULL, 0);
- g_return_val_if_fail (E_IS_TABLE_HEADER (eth), 0);
-
- return eth->col_count;
-}
-
-/**
- * e_table_header_index:
- * @eth: the ETableHeader to query
- * @col: the column to fetch.
- *
- * ETableHeaders contain the visual list of columns that the user will
- * view. The visible columns will typically map to different columns
- * in the ETableModel (because the user reordered the data for
- * example).
- *
- * Returns: the column in the model that the @col column
- * in the ETableHeader points to. */
-int
-e_table_header_index (ETableHeader *eth, int col)
-{
- g_return_val_if_fail (eth != NULL, -1);
- g_return_val_if_fail (E_IS_TABLE_HEADER (eth), -1);
- g_return_val_if_fail (col >= 0 && col < eth->col_count, -1);
-
- return eth->columns [col]->col_idx;
-}
-
-/**
- * e_table_header_get_index_at:
- * @eth: the ETableHeader to query
- * @x_offset: a pixel count from the beginning of the ETableHeader
- *
- * This will return the ETableHeader column that would contain
- * the @x_offset pixel.
- *
- * Returns: the column that contains pixel @x_offset, or -1
- * if no column inside this ETableHeader contains that pixel.
- */
-int
-e_table_header_get_index_at (ETableHeader *eth, int x_offset)
-{
- int i, total;
-
- g_return_val_if_fail (eth != NULL, 0);
- g_return_val_if_fail (E_IS_TABLE_HEADER (eth), 0);
-
- total = 0;
- for (i = 0; i < eth->col_count; i++){
- total += eth->columns [i]->width;
-
- if (x_offset < total)
- return i;
- }
-
- return -1;
-}
-
-/**
- * e_table_header_get_columns:
- * @eth: The ETableHeader to query
- *
- * Returns: A NULL terminated array of the ETableCols
- * contained in the ETableHeader @eth. Note that every
- * returned ETableCol in the array has been referenced, to release
- * this information you need to g_free the buffer returned
- * and you need to g_object_unref every element returned
- */
-ETableCol **
-e_table_header_get_columns (ETableHeader *eth)
-{
- ETableCol **ret;
- int i;
-
- g_return_val_if_fail (eth != NULL, 0);
- g_return_val_if_fail (E_IS_TABLE_HEADER (eth), 0);
-
- ret = g_new (ETableCol *, eth->col_count + 1);
- memcpy (ret, eth->columns, sizeof (ETableCol *) * eth->col_count);
- ret [eth->col_count] = NULL;
-
- for (i = 0; i < eth->col_count; i++) {
- g_object_ref(ret[i]);
- }
-
- return ret;
-}
-
-/**
- * e_table_header_get_selected:
- * @eth: The ETableHeader to query
- *
- * Returns: The number of selected columns in the @eth object.
- */
-int
-e_table_header_get_selected (ETableHeader *eth)
-{
- int i;
- int selected = 0;
-
- g_return_val_if_fail (eth != NULL, 0);
- g_return_val_if_fail (E_IS_TABLE_HEADER (eth), 0);
-
- for (i = 0; i < eth->col_count; i++){
- if (eth->columns [i]->selected)
- selected++;
- }
-
- return selected;
-}
-
-/**
- * e_table_header_total_width:
- * @eth: The ETableHeader to query
- *
- * Returns: the number of pixels used by the @eth object
- * when rendered on screen
- */
-int
-e_table_header_total_width (ETableHeader *eth)
-{
- int total, i;
-
- g_return_val_if_fail (eth != NULL, 0);
- g_return_val_if_fail (E_IS_TABLE_HEADER (eth), 0);
-
- total = 0;
- for (i = 0; i < eth->col_count; i++)
- total += eth->columns [i]->width;
-
- return total;
-}
-
-/**
- * e_table_header_min_width:
- * @eth: The ETableHeader to query
- *
- * Returns: the minimum number of pixels required by the @eth object.
- **/
-int
-e_table_header_min_width (ETableHeader *eth)
-{
- int total, i;
-
- g_return_val_if_fail (eth != NULL, 0);
- g_return_val_if_fail (E_IS_TABLE_HEADER (eth), 0);
-
- total = 0;
- for (i = 0; i < eth->col_count; i++)
- total += eth->columns [i]->min_width;
-
- return total;
-}
-
-/**
- * e_table_header_move:
- * @eth: The ETableHeader to operate on.
- * @source_index: the source column to move.
- * @target_index: the target location for the column
- *
- * This function moves the column @source_index to @target_index
- * inside the @eth ETableHeader. The signals "dimension_change"
- * and "structure_change" will be emmited
- */
-void
-e_table_header_move (ETableHeader *eth, int source_index, int target_index)
-{
- ETableCol *old;
-
- g_return_if_fail (eth != NULL);
- g_return_if_fail (E_IS_TABLE_HEADER (eth));
- g_return_if_fail (source_index >= 0);
- g_return_if_fail (target_index >= 0);
- g_return_if_fail (source_index < eth->col_count);
- g_return_if_fail (target_index < eth->col_count + 1); /* Can be moved beyond the last item. */
-
- if (source_index < target_index)
- target_index --;
-
- old = eth->columns [source_index];
- eth_do_remove (eth, source_index, FALSE);
- eth_do_insert (eth, target_index, old);
- eth_update_offsets (eth);
-
- g_signal_emit (G_OBJECT (eth), eth_signals [DIMENSION_CHANGE], 0, eth->width);
- g_signal_emit (G_OBJECT (eth), eth_signals [STRUCTURE_CHANGE], 0);
-}
-
-/**
- * e_table_header_remove:
- * @eth: The ETableHeader to operate on.
- * @idx: the index to the column to be removed.
- *
- * Removes the column at @idx position in the ETableHeader @eth.
- * This emmits the "structure_change" signal on the @eth object.
- */
-void
-e_table_header_remove (ETableHeader *eth, int idx)
-{
- g_return_if_fail (eth != NULL);
- g_return_if_fail (E_IS_TABLE_HEADER (eth));
- g_return_if_fail (idx >= 0);
- g_return_if_fail (idx < eth->col_count);
-
- eth_do_remove (eth, idx, TRUE);
- enqueue(eth, -1, eth->nominal_width);
- g_signal_emit (G_OBJECT (eth), eth_signals [STRUCTURE_CHANGE], 0);
-}
-
-/*
- * FIXME: deprecated?
- */
-void
-e_table_header_set_selection (ETableHeader *eth, gboolean allow_selection)
-{
- g_return_if_fail (eth != NULL);
- g_return_if_fail (E_IS_TABLE_HEADER (eth));
-}
-
-static void
-eth_set_size (ETableHeader *eth, int idx, int size)
-{
- double expansion;
- double old_expansion;
- int min_width;
- int left_width;
- int total_extra;
- int expandable_count;
- int usable_width;
- int i;
- g_return_if_fail (eth != NULL);
- g_return_if_fail (E_IS_TABLE_HEADER (eth));
- g_return_if_fail (idx >= 0);
- g_return_if_fail (idx < eth->col_count);
-
- /* If this column is not resizable, don't do anything. */
- if (!eth->columns[idx]->resizable)
- return;
-
- expansion = 0;
- min_width = 0;
- left_width = 0;
- expandable_count = -1;
-
- /* Calculate usable area. */
- for (i = 0; i < idx; i++) {
- left_width += eth->columns[i]->width;
- }
- /* - 1 to account for the last pixel border. */
- usable_width = eth->width - left_width - 1;
-
- if (eth->sort_info)
- usable_width -= e_table_sort_info_grouping_get_count(eth->sort_info) * GROUP_INDENT;
-
- /* Calculate minimum_width of stuff on the right as well as
- * total usable expansion on the right.
- */
- for (; i < eth->col_count; i++) {
- min_width += eth->columns[i]->min_width + eth->width_extras;
- if (eth->columns[i]->resizable) {
- expansion += eth->columns[i]->expansion;
- expandable_count ++;
- }
- }
- /* If there's no room for anything, don't change. */
- if (expansion == 0)
- return;
-
- /* (1) If none of the columns to the right are expandable, use
- * all the expansion space in this column.
- */
- if(expandable_count == 0) {
- eth->columns[idx]->expansion = expansion;
- for (i = idx + 1; i < eth->col_count; i++) {
- eth->columns[i]->expansion = 0;
- }
-
- g_signal_emit (G_OBJECT (eth), eth_signals [EXPANSION_CHANGE], 0);
- return;
- }
-
- total_extra = usable_width - min_width;
- /* If there's no extra space, set all expansions to 0. */
- if (total_extra <= 0) {
- for (i = idx; i < eth->col_count; i++) {
- eth->columns[i]->expansion = 0;
- }
- g_signal_emit (G_OBJECT (eth), eth_signals [EXPANSION_CHANGE], 0);
- return;
- }
-
- /* If you try to resize smaller than the minimum width, it
- * uses the minimum. */
- if (size < eth->columns[idx]->min_width + eth->width_extras)
- size = eth->columns[idx]->min_width + eth->width_extras;
-
- /* If all the extra space will be used up in this column, use
- * all the expansion and set all others to 0.
- */
- if (size >= total_extra + eth->columns[idx]->min_width + eth->width_extras) {
- eth->columns[idx]->expansion = expansion;
- for (i = idx + 1; i < eth->col_count; i++) {
- eth->columns[i]->expansion = 0;
- }
- g_signal_emit (G_OBJECT (eth), eth_signals [EXPANSION_CHANGE], 0);
- return;
- }
-
- /* The old_expansion used by columns to the right. */
- old_expansion = expansion;
- old_expansion -= eth->columns[idx]->expansion;
- /* Set the new expansion so that it will generate the desired size. */
- eth->columns[idx]->expansion = expansion * (((double)(size - (eth->columns[idx]->min_width + eth->width_extras)))/((double)total_extra));
- /* The expansion left for the columns on the right. */
- expansion -= eth->columns[idx]->expansion;
-
- /* (2) If the old columns to the right didn't have any
- * expansion before, expand them evenly. old_expansion > 0 by
- * expansion = SUM(i=idx to col_count -1,
- * columns[i]->min_width) - columns[idx]->min_width) =
- * SUM(non-negatives).
- */
- if (old_expansion == 0) {
- for (i = idx + 1; i < eth->col_count; i++) {
- if (eth->columns[idx]->resizable) {
- /* expandable_count != 0 by (1) */
- eth->columns[i]->expansion = expansion / expandable_count;
- }
- }
- g_signal_emit (G_OBJECT (eth), eth_signals [EXPANSION_CHANGE], 0);
- return;
- }
-
- /* Remove from total_extra the amount used for this column. */
- total_extra -= size - (eth->columns[idx]->min_width + eth->width_extras);
- for (i = idx + 1; i < eth->col_count; i++) {
- if (eth->columns[idx]->resizable) {
- /* old_expansion != 0 by (2) */
- eth->columns[i]->expansion *= expansion / old_expansion;
- }
- }
- g_signal_emit (G_OBJECT (eth), eth_signals [EXPANSION_CHANGE], 0);
-}
-
-/**
- * e_table_header_col_diff:
- * @eth: the ETableHeader to query.
- * @start_col: the starting column
- * @end_col: the ending column.
- *
- * Computes the number of pixels between the columns @start_col and
- * @end_col.
- *
- * Returns: the number of pixels between @start_col and @end_col on the
- * @eth ETableHeader object
- */
-int
-e_table_header_col_diff (ETableHeader *eth, int start_col, int end_col)
-{
- int total, col;
-
- g_return_val_if_fail (eth != NULL, 0);
- g_return_val_if_fail (E_IS_TABLE_HEADER (eth), 0);
-
- if (start_col < 0)
- start_col = 0;
- if (end_col > eth->col_count)
- end_col = eth->col_count;
-
- total = 0;
- for (col = start_col; col < end_col; col++){
-
- total += eth->columns [col]->width;
- }
-
- return total;
-}
-
-static void
-eth_calc_widths (ETableHeader *eth)
-{
- int i;
- int extra;
- double expansion;
- int last_position = 0;
- double next_position = 0;
- int last_resizable = -1;
- int *widths;
- gboolean changed;
-
- widths = g_new (int, eth->col_count);
-
- /* - 1 to account for the last pixel border. */
- extra = eth->width - 1;
- expansion = 0;
- for (i = 0; i < eth->col_count; i++) {
- extra -= eth->columns[i]->min_width + eth->width_extras;
- if (eth->columns[i]->resizable && eth->columns[i]->expansion > 0)
- last_resizable = i;
- expansion += eth->columns[i]->resizable ? eth->columns[i]->expansion : 0;
- widths[i] = eth->columns[i]->min_width + eth->width_extras;
- }
- if (eth->sort_info)
- extra -= e_table_sort_info_grouping_get_count(eth->sort_info) * GROUP_INDENT;
- if (expansion != 0 && extra > 0) {
- for (i = 0; i < last_resizable; i++) {
- next_position += extra * (eth->columns[i]->resizable ? eth->columns[i]->expansion : 0)/expansion;
- widths[i] += next_position - last_position;
- last_position = next_position;
- }
- widths[i] += extra - last_position;
- }
-
- changed = FALSE;
-
- for (i = 0; i < eth->col_count; i++) {
- if (eth->columns[i]->width != widths[i]) {
- changed = TRUE;
- eth->columns[i]->width = widths[i];
- }
- }
- g_free (widths);
- if (changed)
- g_signal_emit (G_OBJECT (eth), eth_signals [DIMENSION_CHANGE], 0, eth->width);
- eth_update_offsets (eth);
-}
-
-void
-e_table_header_update_horizontal (ETableHeader *eth)
-{
- int i;
- int cols;
-
- cols = eth->col_count;
-
- for (i = 0; i < cols; i++) {
- int width = 0;
-
- g_signal_emit_by_name (G_OBJECT (eth),
- "request_width",
- i, &width);
- eth->columns[i]->min_width = width + 10;
- eth->columns[i]->expansion = 1;
- }
- enqueue(eth, -1, eth->nominal_width);
- g_signal_emit (G_OBJECT (eth), eth_signals [EXPANSION_CHANGE], 0);
-}
-
-E_MAKE_TYPE(e_table_header, "ETableHeader", ETableHeader, e_table_header_class_init, e_table_header_init, G_TYPE_OBJECT)
-
-int
-e_table_header_prioritized_column (ETableHeader *eth)
-{
- int best_model_col = 0;
- int best_priority;
- int i;
- int count;
-
- count = e_table_header_count (eth);
- if (count == 0)
- return -1;
- best_priority = e_table_header_get_column (eth, 0)->priority;
- best_model_col = e_table_header_get_column (eth, 0)->col_idx;
- for (i = 1; i < count; i++) {
- int priority = e_table_header_get_column (eth, i)->priority;
- if (priority > best_priority) {
- best_priority = priority;
- best_model_col = e_table_header_get_column (eth, i)->col_idx;
- }
- }
- return best_model_col;
-}
-
-ETableCol *
-e_table_header_prioritized_column_selected (ETableHeader *eth, ETableColCheckFunc check_func, gpointer user_data)
-{
- ETableCol *best_col = NULL;
- int best_priority = G_MININT;
- int i;
- int count;
-
- count = e_table_header_count (eth);
- if (count == 0)
- return NULL;
- for (i = 1; i < count; i++) {
- ETableCol *col = e_table_header_get_column (eth, i);
- if (col) {
- if ((best_col == NULL || col->priority > best_priority) && check_func (col, user_data)) {
- best_priority = col->priority;
- best_col = col;
- }
- }
- }
- return best_col;
-}
diff --git a/widgets/table/e-table-header.h b/widgets/table/e-table-header.h
deleted file mode 100644
index 3a9ae6a0bf..0000000000
--- a/widgets/table/e-table-header.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-header.h
- * Copyright 1999, 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- * Miguel de Icaza <miguel@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_TABLE_COLUMN_H_
-#define _E_TABLE_COLUMN_H_
-
-#include <glib-object.h>
-#include <gdk/gdk.h>
-#include <gal/e-table/e-table-sort-info.h>
-#include <gal/e-table/e-table-col.h>
-
-G_BEGIN_DECLS
-
-typedef struct _ETableHeader ETableHeader;
-
-#define E_TABLE_HEADER_TYPE (e_table_header_get_type ())
-#define E_TABLE_HEADER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TABLE_HEADER_TYPE, ETableHeader))
-#define E_TABLE_HEADER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TABLE_HEADER_TYPE, ETableHeaderClass))
-#define E_IS_TABLE_HEADER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TABLE_HEADER_TYPE))
-#define E_IS_TABLE_HEADER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TABLE_HEADER_TYPE))
-#define E_TABLE_HEADER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), E_TABLE_HEADER_TYPE, ETableHeaderClass))
-
-typedef gboolean (*ETableColCheckFunc) (ETableCol *col, gpointer user_data);
-
-/*
- * A Columnar header.
- */
-struct _ETableHeader {
- GObject base;
-
- int col_count;
- int width;
- int nominal_width;
- int width_extras;
-
- ETableSortInfo *sort_info;
- int sort_info_group_change_id;
-
- ETableCol **columns;
-
- GSList *change_queue, *change_tail;
- gint idle;
-};
-
-typedef struct {
- GObjectClass parent_class;
-
- void (*structure_change) (ETableHeader *eth);
- void (*dimension_change) (ETableHeader *eth, int width);
- void (*expansion_change) (ETableHeader *eth);
- int (*request_width) (ETableHeader *eth, int col);
-} ETableHeaderClass;
-
-GType e_table_header_get_type (void);
-ETableHeader *e_table_header_new (void);
-
-void e_table_header_add_column (ETableHeader *eth,
- ETableCol *tc,
- int pos);
-ETableCol *e_table_header_get_column (ETableHeader *eth,
- int column);
-ETableCol *e_table_header_get_column_by_col_idx (ETableHeader *eth,
- int col_idx);
-int e_table_header_count (ETableHeader *eth);
-int e_table_header_index (ETableHeader *eth,
- int col);
-int e_table_header_get_index_at (ETableHeader *eth,
- int x_offset);
-ETableCol **e_table_header_get_columns (ETableHeader *eth);
-int e_table_header_get_selected (ETableHeader *eth);
-
-int e_table_header_total_width (ETableHeader *eth);
-int e_table_header_min_width (ETableHeader *eth);
-void e_table_header_move (ETableHeader *eth,
- int source_index,
- int target_index);
-void e_table_header_remove (ETableHeader *eth,
- int idx);
-void e_table_header_set_size (ETableHeader *eth,
- int idx,
- int size);
-void e_table_header_set_selection (ETableHeader *eth,
- gboolean allow_selection);
-int e_table_header_col_diff (ETableHeader *eth,
- int start_col,
- int end_col);
-
-void e_table_header_calc_widths (ETableHeader *eth);
-GList *e_table_header_get_selected_indexes (ETableHeader *eth);
-void e_table_header_update_horizontal (ETableHeader *eth);
-int e_table_header_prioritized_column (ETableHeader *eth);
-ETableCol *e_table_header_prioritized_column_selected (ETableHeader *eth,
- ETableColCheckFunc check_func,
- gpointer user_data);
-
-G_END_DECLS
-
-#endif /* _E_TABLE_HEADER_H_ */
-
diff --git a/widgets/table/e-table-item.c b/widgets/table/e-table-item.c
deleted file mode 100644
index 33798cc716..0000000000
--- a/widgets/table/e-table-item.c
+++ /dev/null
@@ -1,3735 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-item.c
- * Copyright 1999, 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- * Miguel de Icaza <miguel@gnu.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-/*
- * TODO:
- * Add a border to the thing, so that focusing works properly.
- */
-#include <config.h>
-
-#include "e-table-item.h"
-
-#include <X11/Xlib.h>
-
-#include <math.h>
-#include <stdio.h>
-#include <gtk/gtksignal.h>
-#include <gtk/gtkmain.h>
-#include <gdk/gdkkeysyms.h>
-#include "e-table-subset.h"
-#include "e-cell.h"
-#include "gal/a11y/e-table/gal-a11y-e-table-item-factory.h"
-#include "gal/widgets/e-hsv-utils.h"
-#include "gal/widgets/e-canvas.h"
-#include "gal/widgets/e-canvas-utils.h"
-#include "gal/util/e-util.h"
-#include "gal/a11y/e-table/gal-a11y-e-table-item.h"
-#include "gal/util/e-i18n.h"
-#include <string.h>
-#include <stdlib.h>
-#include <atk/atk.h>
-
-#define PARENT_OBJECT_TYPE gnome_canvas_item_get_type ()
-
-#define FOCUSED_BORDER 2
-
-#define d(x)
-
-#if d(!)0
-#define e_table_item_leave_edit_(x) (e_table_item_leave_edit((x)), g_print ("%s: e_table_item_leave_edit\n", __FUNCTION__))
-#else
-#define e_table_item_leave_edit_(x) (e_table_item_leave_edit((x)))
-#endif
-
-static void eti_check_cursor_bounds (ETableItem *eti);
-static void eti_cancel_drag_due_to_model_change (ETableItem *eti);
-
-/* FIXME: Do an analysis of which cell functions are needed before
- realize and make sure that all of them are doable by all the cells
- and that all of the others are only done after realization. */
-
-static GnomeCanvasItemClass *eti_parent_class;
-
-enum {
- CURSOR_CHANGE,
- CURSOR_ACTIVATED,
- DOUBLE_CLICK,
- RIGHT_CLICK,
- CLICK,
- KEY_PRESS,
- START_DRAG,
- STYLE_SET,
- SELECTION_MODEL_REMOVED,
- SELECTION_MODEL_ADDED,
- LAST_SIGNAL
-};
-
-static guint eti_signals [LAST_SIGNAL] = { 0, };
-
-enum {
- PROP_0,
- PROP_TABLE_HEADER,
- PROP_TABLE_MODEL,
- PROP_SELECTION_MODEL,
- PROP_TABLE_ALTERNATING_ROW_COLORS,
- PROP_TABLE_HORIZONTAL_DRAW_GRID,
- PROP_TABLE_VERTICAL_DRAW_GRID,
- PROP_TABLE_DRAW_FOCUS,
- PROP_CURSOR_MODE,
- PROP_LENGTH_THRESHOLD,
- PROP_CURSOR_ROW,
- PROP_UNIFORM_ROW_HEIGHT,
-
- PROP_MINIMUM_WIDTH,
- PROP_WIDTH,
- PROP_HEIGHT
-};
-
-#define DOUBLE_CLICK_TIME 250
-#define TRIPLE_CLICK_TIME 500
-
-
-static int eti_get_height (ETableItem *eti);
-static int eti_row_height (ETableItem *eti, int row);
-static void e_table_item_focus (ETableItem *eti, int col, int row, GdkModifierType state);
-static void eti_cursor_change (ESelectionModel *selection, int row, int col, ETableItem *eti);
-static void eti_cursor_activated (ESelectionModel *selection, int row, int col, ETableItem *eti);
-static void eti_selection_change (ESelectionModel *selection, ETableItem *eti);
-static void eti_selection_row_change (ESelectionModel *selection, int row, ETableItem *eti);
-static void e_table_item_redraw_row (ETableItem *eti, int row);
-
-#define ETI_SINGLE_ROW_HEIGHT(eti) ((eti)->uniform_row_height_cache != -1 ? (eti)->uniform_row_height_cache : eti_row_height((eti), -1))
-#define ETI_MULTIPLE_ROW_HEIGHT(eti,row) ((eti)->height_cache && (eti)->height_cache[(row)] != -1 ? (eti)->height_cache[(row)] : eti_row_height((eti),(row)))
-#define ETI_ROW_HEIGHT(eti,row) ((eti)->uniform_row_height ? ETI_SINGLE_ROW_HEIGHT ((eti)) : ETI_MULTIPLE_ROW_HEIGHT((eti),(row)))
-
-inline static gint
-model_to_view_row(ETableItem *eti, int row)
-{
- int i;
- if (row == -1)
- return -1;
- if (eti->uses_source_model) {
- ETableSubset *etss = E_TABLE_SUBSET(eti->table_model);
- if (eti->row_guess >= 0 && eti->row_guess < etss->n_map) {
- if (etss->map_table[eti->row_guess] == row) {
- return eti->row_guess;
- }
- }
- for (i = 0; i < etss->n_map; i++) {
- if (etss->map_table[i] == row)
- return i;
- }
- return -1;
- } else
- return row;
-}
-
-inline static gint
-view_to_model_row(ETableItem *eti, int row)
-{
- if (eti->uses_source_model) {
- ETableSubset *etss = E_TABLE_SUBSET(eti->table_model);
- if (row >= 0 && row < etss->n_map) {
- eti->row_guess = row;
- return etss->map_table[row];
- } else
- return -1;
- } else
- return row;
-}
-
-inline static gint
-model_to_view_col(ETableItem *eti, int col)
-{
- int i;
- if (col == -1)
- return -1;
- for (i = 0; i < eti->cols; i++) {
- ETableCol *ecol = e_table_header_get_column (eti->header, i);
- if (ecol->col_idx == col)
- return i;
- }
- return -1;
-}
-
-inline static gint
-view_to_model_col(ETableItem *eti, int col)
-{
- ETableCol *ecol = e_table_header_get_column (eti->header, col);
- return ecol ? ecol->col_idx : -1;
-}
-
-static void
-grab_cancelled (ECanvas *canvas, GnomeCanvasItem *item, gpointer data)
-{
- ETableItem *eti = data;
-
- eti->grab_cancelled = TRUE;
-}
-
-inline static void
-eti_grab (ETableItem *eti, guint32 time)
-{
- GnomeCanvasItem *item = GNOME_CANVAS_ITEM (eti);
- d(g_print ("%s: time: %d\n", __FUNCTION__, time));
- if (eti->grabbed_count == 0) {
- eti->gtk_grabbed = FALSE;
- eti->grab_cancelled = FALSE;
- if (e_canvas_item_grab(E_CANVAS (item->canvas),
- item,
- GDK_BUTTON1_MOTION_MASK | GDK_BUTTON2_MOTION_MASK | GDK_BUTTON3_MOTION_MASK
- | GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK,
- NULL, time,
- grab_cancelled,
- eti) != GrabSuccess) {
- d(g_print ("%s: gtk_grab_add\n", __FUNCTION__));
- gtk_grab_add (GTK_WIDGET (item->canvas));
- eti->gtk_grabbed = TRUE;
- }
- }
- eti->grabbed_count ++;
-}
-
-inline static void
-eti_ungrab (ETableItem *eti, guint32 time)
-{
- GnomeCanvasItem *item = GNOME_CANVAS_ITEM (eti);
- d(g_print ("%s: time: %d\n", __FUNCTION__, time));
- eti->grabbed_count --;
- if (eti->grabbed_count == 0) {
- if (eti->grab_cancelled) {
- eti->grab_cancelled = FALSE;
- } else {
- if (eti->gtk_grabbed) {
- d(g_print ("%s: gtk_grab_remove\n", __FUNCTION__));
- gtk_grab_remove (GTK_WIDGET (item->canvas));
- eti->gtk_grabbed = FALSE;
- }
- gnome_canvas_item_ungrab(item, time);
- eti->grabbed_col = -1;
- eti->grabbed_row = -1;
- }
- }
-}
-
-inline static gboolean
-eti_editing (ETableItem *eti)
-{
- d(g_print("%s: %s\n", __FUNCTION__, (eti->editing_col == -1) ? "false":"true"));
-
- if (eti->editing_col == -1)
- return FALSE;
- else
- return TRUE;
-}
-
-inline static GdkColor *
-eti_get_cell_background_color (ETableItem *eti, int row, int col, gboolean selected, gboolean *allocatedp)
-{
- ECellView *ecell_view = eti->cell_views [col];
- GtkWidget *canvas = GTK_WIDGET(GNOME_CANVAS_ITEM(eti)->canvas);
- GdkColor *background, bg;
- gchar *color_spec = NULL;
- gboolean allocated = FALSE;
-
- if (selected){
- if (GTK_WIDGET_HAS_FOCUS(canvas))
- background = &canvas->style->bg [GTK_STATE_SELECTED];
- else
- background = &canvas->style->bg [GTK_STATE_ACTIVE];
- } else {
- background = &canvas->style->base [GTK_STATE_NORMAL];
- }
-
- color_spec = e_cell_get_bg_color (ecell_view, row);
-
- if (color_spec != NULL) {
- if (gdk_color_parse (color_spec, &bg)) {
- background = gdk_color_copy (&bg);
- gdk_colormap_alloc_color (gtk_widget_get_colormap (GTK_WIDGET (canvas)), background,
- FALSE, TRUE);
- allocated = TRUE;
- }
- }
-
- if (eti->alternating_row_colors) {
- if (row % 2) {
-
- } else {
- if (!allocated) {
- background = gdk_color_copy (background);
- allocated = TRUE;
- }
- e_hsv_tweak (background, 0.0f, 0.0f, -0.07f);
- gdk_colormap_alloc_color (gtk_widget_get_colormap (GTK_WIDGET (canvas)), background,
- FALSE, TRUE);
- }
- }
- if (allocatedp)
- *allocatedp = allocated;
-
- return background;
-}
-
-inline static GdkColor *
-eti_get_cell_foreground_color (ETableItem *eti, int row, int col, gboolean selected, gboolean *allocated)
-{
- GtkWidget *canvas = GTK_WIDGET(GNOME_CANVAS_ITEM(eti)->canvas);
- GdkColor *foreground;
-
- if (allocated)
- *allocated = FALSE;
-
- if (selected){
- if (GTK_WIDGET_HAS_FOCUS (canvas))
- foreground = &canvas->style->fg [GTK_STATE_SELECTED];
- else
- foreground = &canvas->style->fg [GTK_STATE_ACTIVE];
- } else {
- foreground = &canvas->style->text [GTK_STATE_NORMAL];
- }
-
- return foreground;
-}
-
-static void
-eti_free_save_state (ETableItem *eti)
-{
- if (eti->save_row == -1 ||
- !eti->cell_views_realized)
- return;
-
- e_cell_free_state (eti->cell_views [eti->save_col], view_to_model_col(eti, eti->save_col),
- eti->save_col, eti->save_row, eti->save_state);
- eti->save_row = -1;
- eti->save_col = -1;
- eti->save_state = NULL;
-}
-
-/*
- * During realization, we have to invoke the per-ecell realize routine
- * (On our current setup, we have one e-cell per column.
- *
- * We might want to optimize this to only realize the unique e-cells:
- * ie, a strings-only table, uses the same e-cell for every column, and
- * we might want to avoid realizing each e-cell.
- */
-static void
-eti_realize_cell_views (ETableItem *eti)
-{
- int i;
-
- if (eti->cell_views_realized)
- return;
-
- if (!(GTK_OBJECT_FLAGS(eti) & GNOME_CANVAS_ITEM_REALIZED))
- return;
-
- for (i = 0; i < eti->n_cells; i++)
- e_cell_realize (eti->cell_views [i]);
- eti->cell_views_realized = 1;
-}
-
-static void
-eti_attach_cell_views (ETableItem *eti)
-{
- int i;
-
- g_assert (eti->header);
- g_assert (eti->table_model);
-
- /* this is just c&p from model pre change, but it fixes things */
- eti_cancel_drag_due_to_model_change (eti);
- eti_check_cursor_bounds (eti);
- if (eti_editing (eti))
- e_table_item_leave_edit_(eti);
- eti->motion_row = -1;
- eti->motion_col = -1;
-
- /*
- * Now realize the various ECells
- */
- eti->n_cells = eti->cols;
- eti->cell_views = g_new (ECellView *, eti->n_cells);
-
- for (i = 0; i < eti->n_cells; i++){
- ETableCol *ecol = e_table_header_get_column (eti->header, i);
-
- eti->cell_views [i] = e_cell_new_view (ecol->ecell, eti->table_model, eti);
- }
-
- eti->needs_compute_height = 1;
- e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (eti));
- eti->needs_redraw = 1;
- gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (eti));
-}
-
-/*
- * During unrealization: we invoke every e-cell (one per column in the current
- * setup) to dispose all X resources allocated
- */
-static void
-eti_unrealize_cell_views (ETableItem *eti)
-{
- int i;
-
- if (eti->cell_views_realized == 0)
- return;
-
- eti_free_save_state (eti);
-
- for (i = 0; i < eti->n_cells; i++)
- e_cell_unrealize (eti->cell_views [i]);
- eti->cell_views_realized = 0;
-}
-
-static void
-eti_detach_cell_views (ETableItem *eti)
-{
- int i;
-
- eti_free_save_state (eti);
-
- for (i = 0; i < eti->n_cells; i++){
- e_cell_kill_view (eti->cell_views [i]);
- eti->cell_views [i] = NULL;
- }
-
- g_free (eti->cell_views);
- eti->cell_views = NULL;
- eti->n_cells = 0;
-}
-
-static void
-eti_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
-{
- double i2c [6];
- ArtPoint c1, c2, i1, i2;
- ETableItem *eti = E_TABLE_ITEM (item);
-
- /* Wrong BBox's are the source of redraw nightmares */
-
- gnome_canvas_item_i2c_affine (GNOME_CANVAS_ITEM (eti), i2c);
-
- i1.x = eti->x1;
- i1.y = eti->y1;
- i2.x = eti->x1 + eti->width;
- i2.y = eti->y1 + eti->height;
- art_affine_point (&c1, &i1, i2c);
- art_affine_point (&c2, &i2, i2c);
-
- *x1 = c1.x;
- *y1 = c1.y;
- *x2 = c2.x + 1;
- *y2 = c2.y + 1;
-}
-
-static void
-eti_reflow (GnomeCanvasItem *item, gint flags)
-{
- ETableItem *eti = E_TABLE_ITEM (item);
-
- if (eti->needs_compute_height) {
- int new_height = eti_get_height (eti);
-
- if (new_height != eti->height) {
- eti->height = new_height;
- e_canvas_item_request_parent_reflow (GNOME_CANVAS_ITEM (eti));
- eti->needs_redraw = 1;
- gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (eti));
- }
- eti->needs_compute_height = 0;
- }
- if (eti->needs_compute_width) {
- int new_width = e_table_header_total_width(eti->header);
- if (new_width != eti->width) {
- eti->width = new_width;
- e_canvas_item_request_parent_reflow (GNOME_CANVAS_ITEM (eti));
- eti->needs_redraw = 1;
- gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (eti));
- }
- eti->needs_compute_width = 0;
- }
-}
-
-/*
- * GnomeCanvasItem::update method
- */
-static void
-eti_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
-{
- ArtPoint o1, o2;
- ETableItem *eti = E_TABLE_ITEM (item);
-
- if (GNOME_CANVAS_ITEM_CLASS (eti_parent_class)->update)
- (*GNOME_CANVAS_ITEM_CLASS (eti_parent_class)->update)(item, affine, clip_path, flags);
-
- o1.x = item->x1;
- o1.y = item->y1;
- o2.x = item->x2;
- o2.y = item->y2;
-
- eti_bounds (item, &item->x1, &item->y1, &item->x2, &item->y2);
- if (item->x1 != o1.x ||
- item->y1 != o1.y ||
- item->x2 != o2.x ||
- item->y2 != o2.y) {
- gnome_canvas_request_redraw (item->canvas, o1.x, o1.y, o2.x, o2.y);
- eti->needs_redraw = 1;
- }
-
- if (eti->needs_redraw) {
- gnome_canvas_request_redraw (item->canvas, item->x1, item->y1,
- item->x2, item->y2);
- eti->needs_redraw = 0;
- }
-}
-
-/*
- * eti_remove_table_model:
- *
- * Invoked to release the table model associated with this ETableItem
- */
-static void
-eti_remove_table_model (ETableItem *eti)
-{
- if (!eti->table_model)
- return;
-
- g_signal_handler_disconnect (G_OBJECT (eti->table_model),
- eti->table_model_pre_change_id);
- g_signal_handler_disconnect (G_OBJECT (eti->table_model),
- eti->table_model_no_change_id);
- g_signal_handler_disconnect (G_OBJECT (eti->table_model),
- eti->table_model_change_id);
- g_signal_handler_disconnect (G_OBJECT (eti->table_model),
- eti->table_model_row_change_id);
- g_signal_handler_disconnect (G_OBJECT (eti->table_model),
- eti->table_model_cell_change_id);
- g_signal_handler_disconnect (G_OBJECT (eti->table_model),
- eti->table_model_rows_inserted_id);
- g_signal_handler_disconnect (G_OBJECT (eti->table_model),
- eti->table_model_rows_deleted_id);
- g_object_unref (eti->table_model);
- if (eti->source_model)
- g_object_unref (eti->source_model);
-
- eti->table_model_pre_change_id = 0;
- eti->table_model_no_change_id = 0;
- eti->table_model_change_id = 0;
- eti->table_model_row_change_id = 0;
- eti->table_model_cell_change_id = 0;
- eti->table_model_rows_inserted_id = 0;
- eti->table_model_rows_deleted_id = 0;
- eti->table_model = NULL;
- eti->source_model = NULL;
- eti->uses_source_model = 0;
-}
-
-/*
- * eti_remove_table_model:
- *
- * Invoked to release the table model associated with this ETableItem
- */
-static void
-eti_remove_selection_model (ETableItem *eti)
-{
- if (!eti->selection)
- return;
-
- g_signal_handler_disconnect (eti->selection,
- eti->selection_change_id);
- g_signal_handler_disconnect (eti->selection,
- eti->selection_row_change_id);
- g_signal_handler_disconnect (eti->selection,
- eti->cursor_change_id);
- g_signal_handler_disconnect (eti->selection,
- eti->cursor_activated_id);
- g_object_unref (eti->selection);
-
- eti->selection_change_id = 0;
- eti->selection_row_change_id = 0;
- eti->cursor_activated_id = 0;
- eti->selection = NULL;
-}
-
-/*
- * eti_remove_header_model:
- *
- * Invoked to release the header model associated with this ETableItem
- */
-static void
-eti_remove_header_model (ETableItem *eti)
-{
- if (!eti->header)
- return;
-
- g_signal_handler_disconnect (G_OBJECT (eti->header),
- eti->header_structure_change_id);
- g_signal_handler_disconnect (G_OBJECT (eti->header),
- eti->header_dim_change_id);
- g_signal_handler_disconnect (G_OBJECT (eti->header),
- eti->header_request_width_id);
-
- if (eti->cell_views){
- eti_unrealize_cell_views (eti);
- eti_detach_cell_views (eti);
- }
- g_object_unref (eti->header);
-
-
- eti->header_structure_change_id = 0;
- eti->header_dim_change_id = 0;
- eti->header_request_width_id = 0;
- eti->header = NULL;
-}
-
-/*
- * eti_row_height_real:
- *
- * Returns the height used by row @row. This does not include the one-pixel
- * used as a separator between rows
- */
-static int
-eti_row_height_real (ETableItem *eti, int row)
-{
- const int cols = e_table_header_count (eti->header);
- int col;
- int h, max_h;
-
- g_assert (cols == 0 || eti->cell_views);
-
- max_h = 0;
-
- for (col = 0; col < cols; col++){
- h = e_cell_height (eti->cell_views [col], view_to_model_col(eti, col), col, row);
-
- if (h > max_h)
- max_h = h;
- }
- return max_h;
-}
-
-static void
-confirm_height_cache (ETableItem *eti)
-{
- int i;
-
- if (eti->uniform_row_height || eti->height_cache)
- return;
- eti->height_cache = g_new(int, eti->rows);
- for (i = 0; i < eti->rows; i++) {
- eti->height_cache[i] = -1;
- }
-}
-
-static gboolean
-height_cache_idle(ETableItem *eti)
-{
- int changed = 0;
- int i;
- confirm_height_cache(eti);
- for (i = eti->height_cache_idle_count; i < eti->rows; i++) {
- if (eti->height_cache[i] == -1) {
- eti_row_height(eti, i);
- changed ++;
- if (changed >= 20)
- break;
- }
- }
- if (changed >= 20) {
- eti->height_cache_idle_count = i;
- return TRUE;
- }
- eti->height_cache_idle_id = 0;
- return FALSE;
-}
-
-static void
-free_height_cache (ETableItem *eti)
-{
- if (GNOME_CANVAS_ITEM_REALIZED & GTK_OBJECT_FLAGS (eti)) {
- if (eti->height_cache)
- g_free (eti->height_cache);
- eti->height_cache = NULL;
- eti->height_cache_idle_count = 0;
- eti->uniform_row_height_cache = -1;
-
- if (eti->uniform_row_height && eti->height_cache_idle_id != 0) {
- g_source_remove(eti->height_cache_idle_id);
- eti->height_cache_idle_id = 0;
- }
-
- if ((!eti->uniform_row_height) && eti->height_cache_idle_id == 0)
- eti->height_cache_idle_id = g_idle_add_full(G_PRIORITY_LOW, (GSourceFunc) height_cache_idle, eti, NULL);
- }
-}
-
-static void
-calculate_height_cache (ETableItem *eti)
-{
- free_height_cache(eti);
- confirm_height_cache(eti);
-}
-
-
-/*
- * eti_row_height:
- *
- * Returns the height used by row @row. This does not include the one-pixel
- * used as a separator between rows
- */
-static int
-eti_row_height (ETableItem *eti, int row)
-{
- if (eti->uniform_row_height) {
- eti->uniform_row_height_cache = eti_row_height_real (eti, -1);
- return eti->uniform_row_height_cache;
- } else {
- if (!eti->height_cache) {
- calculate_height_cache (eti);
- }
- if (eti->height_cache[row] == -1) {
- eti->height_cache[row] = eti_row_height_real(eti, row);
- if (row > 0 &&
- eti->length_threshold != -1 &&
- eti->rows > eti->length_threshold &&
- eti->height_cache[row] != eti_row_height(eti, 0)) {
- eti->needs_compute_height = 1;
- e_canvas_item_request_reflow(GNOME_CANVAS_ITEM(eti));
- }
- }
- return eti->height_cache[row];
- }
-}
-
-/*
- * eti_get_height:
- *
- * Returns the height of the ETableItem.
- *
- * The ETableItem might compute the whole height by asking every row its
- * size. There is a special mode (designed to work when there are too
- * many rows in the table that performing the previous step could take
- * too long) set by the ETableItem->length_threshold that would determine
- * when the height is computed by using the first row as the size for
- * every other row in the ETableItem.
- */
-static int
-eti_get_height (ETableItem *eti)
-{
- const int rows = eti->rows;
- int height_extra = eti->horizontal_draw_grid ? 1 : 0;
-
- if (rows == 0)
- return 0;
-
- if (eti->uniform_row_height) {
- int row_height = eti_row_height(eti, -1);
- return ((row_height + height_extra) * rows + height_extra);
- } else {
- int height;
- int row;
- if (eti->length_threshold != -1){
- if (rows > eti->length_threshold){
- int row_height = eti_row_height(eti, 0);
- if (eti->height_cache) {
- height = 0;
- for (row = 0; row < rows; row++) {
- if (eti->height_cache[row] == -1) {
- height += (row_height + height_extra) * (rows - row);
- break;
- }
- else
- height += eti->height_cache[row] + height_extra;
- }
- } else
- height = (eti_row_height (eti, 0) + height_extra) * rows;
-
- /*
- * 1 pixel at the top
- */
- return height + height_extra;
- }
- }
-
- height = height_extra;
- for (row = 0; row < rows; row++)
- height += eti_row_height (eti, row) + height_extra;
-
- return height;
- }
-}
-
-static void
-eti_item_region_redraw (ETableItem *eti, int x0, int y0, int x1, int y1)
-{
- GnomeCanvasItem *item = GNOME_CANVAS_ITEM (eti);
- ArtDRect rect;
- double i2c [6];
-
- rect.x0 = x0;
- rect.y0 = y0;
- rect.x1 = x1;
- rect.y1 = y1;
-
- gnome_canvas_item_i2c_affine (item, i2c);
- art_drect_affine_transform (&rect, &rect, i2c);
-
- gnome_canvas_request_redraw (item->canvas, rect.x0, rect.y0, rect.x1, rect.y1);
-}
-
-/*
- * Computes the distance between @start_row and @end_row in pixels
- */
-int
-e_table_item_row_diff (ETableItem *eti, int start_row, int end_row)
-{
- int height_extra = eti->horizontal_draw_grid ? 1 : 0;
-
- if (start_row < 0)
- start_row = 0;
- if (end_row > eti->rows)
- end_row = eti->rows;
-
- if (eti->uniform_row_height) {
- return ((end_row - start_row) * (eti_row_height(eti, -1) + height_extra));
- } else {
- int row, total;
- total = 0;
- for (row = start_row; row < end_row; row++)
- total += eti_row_height (eti, row) + height_extra;
-
- return total;
- }
-}
-
-static void
-eti_get_region (ETableItem *eti,
- int start_col, int start_row,
- int end_col, int end_row,
- int *x1p, int *y1p,
- int *x2p, int *y2p)
-{
- int x1, y1, x2, y2;
-
- x1 = e_table_header_col_diff (eti->header, 0, start_col);
- y1 = e_table_item_row_diff (eti, 0, start_row);
- x2 = x1 + e_table_header_col_diff (eti->header, start_col, end_col + 1);
- y2 = y1 + e_table_item_row_diff (eti, start_row, end_row + 1);
- if (x1p)
- *x1p = x1;
- if (y1p)
- *y1p = y1;
- if (x2p)
- *x2p = x2;
- if (y2p)
- *y2p = y2;
-}
-
-/*
- * eti_request_region_redraw:
- *
- * Request a canvas redraw on the range (start_col, start_row) to (end_col, end_row).
- * This is inclusive (ie, you can use: 0,0-0,0 to redraw the first cell).
- *
- * The @border argument is a number of pixels around the region that should also be queued
- * for redraw. This is typically used by the focus routines to queue a redraw for the
- * border as well.
- */
-static void
-eti_request_region_redraw (ETableItem *eti,
- int start_col, int start_row,
- int end_col, int end_row, int border)
-{
- int x1, y1, x2, y2;
-
- if (eti->rows > 0) {
-
- eti_get_region (eti,
- start_col, start_row,
- end_col, end_row,
- &x1, &y1, &x2, &y2);
-
- eti_item_region_redraw (eti, eti->x1 + x1 - border,
- eti->y1 + y1 - border,
- eti->x1 + x2 + 1 + border,
- eti->y1 + y2 + 1 + border);
- }
-}
-
-/*
- * eti_request_region_show
- *
- * Request a canvas show on the range (start_col, start_row) to (end_col, end_row).
- * This is inclusive (ie, you can use: 0,0-0,0 to show the first cell).
- */
-static void
-eti_request_region_show (ETableItem *eti,
- int start_col, int start_row,
- int end_col, int end_row, int delay)
-{
- int x1, y1, x2, y2;
-
- eti_get_region (eti,
- start_col, start_row,
- end_col, end_row,
- &x1, &y1, &x2, &y2);
-
- if (delay)
- e_canvas_item_show_area_delayed(GNOME_CANVAS_ITEM(eti), x1, y1, x2, y2, delay);
- else
- e_canvas_item_show_area(GNOME_CANVAS_ITEM(eti), x1, y1, x2, y2);
-}
-
-static void
-eti_show_cursor (ETableItem *eti, int delay)
-{
- int cursor_row;
-
- if (!((GTK_OBJECT_FLAGS(eti) & GNOME_CANVAS_ITEM_REALIZED) && eti->cell_views_realized))
- return;
-
- if (eti->frozen_count > 0) {
- eti->queue_show_cursor = TRUE;
- return;
- }
-
-#if 0
- g_object_get(eti->selection,
- "cursor_row", &cursor_row,
- NULL);
-#else
- cursor_row = e_selection_model_cursor_row (eti->selection);
-#endif
-
- d(g_print ("%s: cursor row: %d\n", __FUNCTION__, cursor_row));
-
- if (cursor_row != -1) {
- cursor_row = model_to_view_row (eti, cursor_row);
- eti_request_region_show (eti,
- 0, cursor_row, eti->cols - 1, cursor_row,
- delay);
- }
-}
-
-static void
-eti_check_cursor_on_screen (ETableItem *eti)
-{
- if (eti->cursor_x1 == -1 ||
- eti->cursor_y1 == -1 ||
- eti->cursor_x2 == -1 ||
- eti->cursor_y2 == -1)
- return;
-
- eti->cursor_on_screen = e_canvas_item_area_shown (GNOME_CANVAS_ITEM(eti),
- eti->cursor_x1,
- eti->cursor_y1,
- eti->cursor_x2,
- eti->cursor_y2);
-
- d(g_print ("%s: cursor on screen: %s\n", __FUNCTION__, eti->cursor_on_screen ? "TRUE" : "FALSE"));
-}
-
-static void
-eti_check_cursor_bounds (ETableItem *eti)
-{
- int x1, y1, x2, y2;
- int cursor_row;
-
- if (!((GTK_OBJECT_FLAGS(eti) & GNOME_CANVAS_ITEM_REALIZED) && eti->cell_views_realized))
- return;
-
- if (eti->frozen_count > 0) {
- return;
- }
-
- if (!((GTK_OBJECT_FLAGS(eti) & GNOME_CANVAS_ITEM_REALIZED) && eti->cell_views_realized))
- return;
-
- if (eti->frozen_count > 0) {
- return;
- }
-
- g_object_get(eti->selection,
- "cursor_row", &cursor_row,
- NULL);
-
- if (cursor_row == -1) {
- eti->cursor_x1 = -1;
- eti->cursor_y1 = -1;
- eti->cursor_x2 = -1;
- eti->cursor_y2 = -1;
- eti->cursor_on_screen = TRUE;
- return;
- }
-
- d(g_print ("%s: model cursor row: %d\n", __FUNCTION__, cursor_row));
-
- cursor_row = model_to_view_row (eti, cursor_row);
-
- d(g_print ("%s: cursor row: %d\n", __FUNCTION__, cursor_row));
-
- eti_get_region (eti,
- 0, cursor_row, eti->cols - 1, cursor_row,
- &x1, &y1, &x2, &y2);
- eti->cursor_x1 = x1;
- eti->cursor_y1 = y1;
- eti->cursor_x2 = x2;
- eti->cursor_y2 = y2;
- eti->cursor_on_screen = e_canvas_item_area_shown (GNOME_CANVAS_ITEM(eti), x1, y1, x2, y2);
-
- d(g_print ("%s: cursor on screen: %s\n", __FUNCTION__, eti->cursor_on_screen ? "TRUE" : "FALSE"));
-}
-
-static void
-eti_maybe_show_cursor(ETableItem *eti, int delay)
-{
- d(g_print ("%s: cursor on screen: %s\n", __FUNCTION__, eti->cursor_on_screen ? "TRUE" : "FALSE"));
- if (eti->cursor_on_screen)
- eti_show_cursor (eti, delay);
- eti_check_cursor_bounds (eti);
-}
-
-static gboolean
-eti_idle_show_cursor_cb (gpointer data)
-{
- ETableItem *eti = data;
-
- if (eti->selection) {
- eti_show_cursor (eti, 0);
- eti_check_cursor_bounds (eti);
- }
-
- eti->cursor_idle_id = 0;
- g_object_unref (eti);
- return FALSE;
-}
-
-static void
-eti_idle_maybe_show_cursor(ETableItem *eti)
-{
- d(g_print ("%s: cursor on screen: %s\n", __FUNCTION__, eti->cursor_on_screen ? "TRUE" : "FALSE"));
- if (eti->cursor_on_screen) {
- g_object_ref (eti);
- if (!eti->cursor_idle_id)
- eti->cursor_idle_id = g_idle_add (eti_idle_show_cursor_cb, eti);
- }
-}
-
-static void
-eti_cancel_drag_due_to_model_change (ETableItem *eti)
-{
- if (eti->maybe_in_drag) {
- eti->maybe_in_drag = FALSE;
- if (!eti->maybe_did_something)
- e_selection_model_do_something(E_SELECTION_MODEL (eti->selection), eti->drag_row, eti->drag_col, eti->drag_state);
- }
- if (eti->in_drag) {
- eti->in_drag = FALSE;
- }
-}
-
-static void
-eti_freeze (ETableItem *eti)
-{
- eti->frozen_count ++;
- d(g_print ("%s: %d\n", __FUNCTION__, eti->frozen_count));
-}
-
-static void
-eti_unfreeze (ETableItem *eti)
-{
- g_return_if_fail (eti->frozen_count > 0);
- eti->frozen_count --;
- d(g_print ("%s: %d\n", __FUNCTION__, eti->frozen_count));
- if (eti->frozen_count == 0 && eti->queue_show_cursor) {
- eti_show_cursor (eti, 0);
- eti_check_cursor_bounds (eti);
- eti->queue_show_cursor = FALSE;
- }
-}
-
-/*
- * Callback routine: invoked before the ETableModel suffers a change
- */
-static void
-eti_table_model_pre_change (ETableModel *table_model, ETableItem *eti)
-{
- eti_cancel_drag_due_to_model_change (eti);
- eti_check_cursor_bounds (eti);
- if (eti_editing (eti))
- e_table_item_leave_edit_(eti);
- eti->motion_row = -1;
- eti->motion_col = -1;
- eti_freeze (eti);
-}
-
-/*
- * Callback routine: invoked when the ETableModel has not suffered a change
- */
-static void
-eti_table_model_no_change (ETableModel *table_model, ETableItem *eti)
-{
- eti_unfreeze (eti);
-}
-
-/*
- * Callback routine: invoked when the ETableModel has suffered a change
- */
-
-static void
-eti_table_model_changed (ETableModel *table_model, ETableItem *eti)
-{
- if (!(GTK_OBJECT_FLAGS(eti) & GNOME_CANVAS_ITEM_REALIZED)) {
- eti_unfreeze (eti);
- return;
- }
-
- eti->rows = e_table_model_row_count (eti->table_model);
-
- free_height_cache(eti);
-
- eti_unfreeze (eti);
-
- eti->needs_compute_height = 1;
- e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (eti));
- eti->needs_redraw = 1;
- gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (eti));
-
- eti_idle_maybe_show_cursor(eti);
-}
-
-static void
-eti_table_model_row_changed (ETableModel *table_model, int row, ETableItem *eti)
-{
- if (!(GTK_OBJECT_FLAGS(eti) & GNOME_CANVAS_ITEM_REALIZED)) {
- eti_unfreeze (eti);
- return;
- }
-
- if ((!eti->uniform_row_height) && eti->height_cache && eti->height_cache[row] != -1 && eti_row_height_real(eti, row) != eti->height_cache[row]) {
- eti_table_model_changed (table_model, eti);
- return;
- }
-
- eti_unfreeze (eti);
-
- e_table_item_redraw_row (eti, row);
-}
-
-static void
-eti_table_model_cell_changed (ETableModel *table_model, int col, int row, ETableItem *eti)
-{
- if (!(GTK_OBJECT_FLAGS(eti) & GNOME_CANVAS_ITEM_REALIZED)) {
- eti_unfreeze (eti);
- return;
- }
-
- if ((!eti->uniform_row_height) && eti->height_cache && eti->height_cache[row] != -1 && eti_row_height_real(eti, row) != eti->height_cache[row]) {
- eti_table_model_changed (table_model, eti);
- return;
- }
-
- eti_unfreeze (eti);
-
- e_table_item_redraw_row (eti, row);
-}
-
-static void
-eti_table_model_rows_inserted (ETableModel *table_model, int row, int count, ETableItem *eti)
-{
- if (!(GTK_OBJECT_FLAGS(eti) & GNOME_CANVAS_ITEM_REALIZED)) {
- eti_unfreeze (eti);
- return;
- }
- eti->rows = e_table_model_row_count (eti->table_model);
-
- if (eti->height_cache) {
- int i;
- eti->height_cache = g_renew(int, eti->height_cache, eti->rows);
- memmove(eti->height_cache + row + count, eti->height_cache + row, (eti->rows - count - row) * sizeof(int));
- for (i = row; i < row + count; i++)
- eti->height_cache[i] = -1;
- }
-
- eti_unfreeze (eti);
-
- eti_idle_maybe_show_cursor(eti);
-
- eti->needs_compute_height = 1;
- e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (eti));
- eti->needs_redraw = 1;
- gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (eti));
-}
-
-static void
-eti_table_model_rows_deleted (ETableModel *table_model, int row, int count, ETableItem *eti)
-{
- if (!(GTK_OBJECT_FLAGS(eti) & GNOME_CANVAS_ITEM_REALIZED)) {
- eti_unfreeze (eti);
- return;
- }
-
- eti->rows = e_table_model_row_count (eti->table_model);
-
- if (eti->height_cache && (eti->rows > row)) {
- memmove(eti->height_cache + row, eti->height_cache + row + count, (eti->rows - row) * sizeof(int));
- }
-
- eti_unfreeze (eti);
-
- eti_idle_maybe_show_cursor(eti);
-
- eti->needs_compute_height = 1;
- e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (eti));
- eti->needs_redraw = 1;
- gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (eti));
-}
-
-/**
- * e_table_item_redraw_range
- * @eti: %ETableItem which will be redrawn
- * @start_col: The first col to redraw.
- * @start_row: The first row to redraw.
- * @end_col: The last col to redraw.
- * @end_row: The last row to redraw.
- *
- * This routine redraws the given %ETableItem in the range given. The
- * range is inclusive at both ends.
- */
-void
-e_table_item_redraw_range (ETableItem *eti,
- int start_col, int start_row,
- int end_col, int end_row)
-{
- int border;
- int cursor_col, cursor_row;
-
- g_return_if_fail (eti != NULL);
- g_return_if_fail (E_IS_TABLE_ITEM (eti));
-
- g_object_get(eti->selection,
- "cursor_col", &cursor_col,
- "cursor_row", &cursor_row,
- NULL);
-
- if ((start_col == cursor_col) ||
- (end_col == cursor_col) ||
- (view_to_model_row(eti, start_row) == cursor_row) ||
- (view_to_model_row(eti, end_row) == cursor_row))
- border = 2;
- else
- border = 0;
-
- eti_request_region_redraw(eti, start_col, start_row, end_col, end_row, border);
-}
-
-static void
-e_table_item_redraw_row (ETableItem *eti,
- int row)
-{
- if (row != -1)
- e_table_item_redraw_range (eti, 0, row, eti->cols - 1, row);
-}
-
-static void
-eti_add_table_model (ETableItem *eti, ETableModel *table_model)
-{
- g_assert (eti->table_model == NULL);
-
- eti->table_model = table_model;
- g_object_ref (eti->table_model);
-
- eti->table_model_pre_change_id = g_signal_connect (
- G_OBJECT (table_model), "model_pre_change",
- G_CALLBACK (eti_table_model_pre_change), eti);
-
- eti->table_model_no_change_id = g_signal_connect (
- G_OBJECT (table_model), "model_no_change",
- G_CALLBACK (eti_table_model_no_change), eti);
-
- eti->table_model_change_id = g_signal_connect (
- G_OBJECT (table_model), "model_changed",
- G_CALLBACK (eti_table_model_changed), eti);
-
- eti->table_model_row_change_id = g_signal_connect (
- G_OBJECT (table_model), "model_row_changed",
- G_CALLBACK (eti_table_model_row_changed), eti);
-
- eti->table_model_cell_change_id = g_signal_connect (
- G_OBJECT (table_model), "model_cell_changed",
- G_CALLBACK (eti_table_model_cell_changed), eti);
-
- eti->table_model_rows_inserted_id = g_signal_connect (
- G_OBJECT (table_model), "model_rows_inserted",
- G_CALLBACK (eti_table_model_rows_inserted), eti);
-
- eti->table_model_rows_deleted_id = g_signal_connect (
- G_OBJECT (table_model), "model_rows_deleted",
- G_CALLBACK (eti_table_model_rows_deleted), eti);
-
- if (eti->header) {
- eti_detach_cell_views (eti);
- eti_attach_cell_views (eti);
- }
-
- if (E_IS_TABLE_SUBSET(table_model)) {
- eti->uses_source_model = 1;
- eti->source_model = E_TABLE_SUBSET(table_model)->source;
- if (eti->source_model)
- g_object_ref(eti->source_model);
- }
-
- eti_freeze (eti);
-
- eti_table_model_changed (table_model, eti);
-}
-
-static void
-eti_add_selection_model (ETableItem *eti, ESelectionModel *selection)
-{
- g_assert (eti->selection == NULL);
-
- eti->selection = selection;
- g_object_ref (eti->selection);
-
- eti->selection_change_id = g_signal_connect (
- selection, "selection_changed",
- G_CALLBACK (eti_selection_change), eti);
-
- eti->selection_row_change_id = g_signal_connect (
- selection, "selection_row_changed",
- G_CALLBACK (eti_selection_row_change), eti);
-
- eti->cursor_change_id = g_signal_connect (
- selection, "cursor_changed",
- G_CALLBACK (eti_cursor_change), eti);
-
- eti->cursor_activated_id = g_signal_connect (
- selection, "cursor_activated",
- G_CALLBACK (eti_cursor_activated), eti);
-
- eti_selection_change(selection, eti);
- g_signal_emit_by_name (G_OBJECT(eti),
- "selection_model_added", eti->selection);
-}
-
-static void
-eti_header_dim_changed (ETableHeader *eth, int col, ETableItem *eti)
-{
- eti->needs_compute_width = 1;
- e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (eti));
- eti->needs_redraw = 1;
- gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (eti));
-}
-
-static void
-eti_header_structure_changed (ETableHeader *eth, ETableItem *eti)
-{
- eti->cols = e_table_header_count (eti->header);
-
- /*
- * There should be at least one column
- * BUT: then you can't remove all columns from a header and add new ones.
- */
- /*g_assert (eti->cols != 0);*/
-
- if (eti->cell_views){
- eti_unrealize_cell_views (eti);
- eti_detach_cell_views (eti);
- eti_attach_cell_views (eti);
- eti_realize_cell_views (eti);
- } else {
- if (eti->table_model) {
- eti_attach_cell_views (eti);
- eti_realize_cell_views (eti);
- }
- }
- eti->needs_compute_width = 1;
- e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (eti));
- eti->needs_redraw = 1;
- gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (eti));
-}
-
-static int
-eti_request_column_width (ETableHeader *eth, int col, ETableItem *eti)
-{
- int width = 0;
-
- if (eti->cell_views && eti->cell_views_realized) {
- width = e_cell_max_width (eti->cell_views[col], view_to_model_col(eti, col), col);
- }
-
- return width;
-}
-
-static void
-eti_add_header_model (ETableItem *eti, ETableHeader *header)
-{
- g_assert (eti->header == NULL);
-
- eti->header = header;
- g_object_ref (header);
-
- eti_header_structure_changed (header, eti);
-
- eti->header_dim_change_id = g_signal_connect (
- G_OBJECT (header), "dimension_change",
- G_CALLBACK (eti_header_dim_changed), eti);
-
- eti->header_structure_change_id = g_signal_connect (
- G_OBJECT (header), "structure_change",
- G_CALLBACK (eti_header_structure_changed), eti);
-
- eti->header_request_width_id = g_signal_connect
- (G_OBJECT (header), "request_width",
- G_CALLBACK (eti_request_column_width), eti);
-}
-
-/*
- * GObject::dispose method
- */
-static void
-eti_dispose (GObject *object)
-{
- ETableItem *eti = E_TABLE_ITEM (object);
-
- eti_remove_header_model (eti);
- eti_remove_table_model (eti);
- eti_remove_selection_model (eti);
-
- if (eti->height_cache_idle_id) {
- g_source_remove(eti->height_cache_idle_id);
- eti->height_cache_idle_id = 0;
- }
- eti->height_cache_idle_count = 0;
-
- if (eti->cursor_idle_id) {
- g_source_remove(eti->cursor_idle_id);
- eti->cursor_idle_id = 0;
- }
-
- if (eti->height_cache)
- g_free (eti->height_cache);
- eti->height_cache = NULL;
-
- e_canvas_hide_tooltip (E_CANVAS(GNOME_CANVAS_ITEM(eti)->canvas));
- if (eti->tooltip) {
- if (eti->tooltip->background)
- gdk_color_free (eti->tooltip->background);
- eti->tooltip->background = NULL;
-
- if (eti->tooltip->foreground)
- gdk_color_free (eti->tooltip->foreground);
- eti->tooltip->foreground = NULL;
-
- if (eti->tooltip->timer) {
- gtk_timeout_remove (eti->tooltip->timer);
- eti->tooltip->timer = 0;
- }
- g_free (eti->tooltip);
- eti->tooltip = NULL;
- }
-
- if (G_OBJECT_CLASS (eti_parent_class)->dispose)
- (*G_OBJECT_CLASS (eti_parent_class)->dispose) (object);
-}
-
-static void
-eti_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
-{
- GnomeCanvasItem *item;
- ETableItem *eti;
- int cursor_col;
-
- item = GNOME_CANVAS_ITEM (object);
- eti = E_TABLE_ITEM (object);
-
- switch (prop_id){
- case PROP_TABLE_HEADER:
- eti_remove_header_model (eti);
- eti_add_header_model (eti, E_TABLE_HEADER(g_value_get_object (value)));
- break;
-
- case PROP_TABLE_MODEL:
- eti_remove_table_model (eti);
- eti_add_table_model (eti, E_TABLE_MODEL(g_value_get_object (value)));
- break;
-
- case PROP_SELECTION_MODEL:
- g_signal_emit_by_name (G_OBJECT(eti),
- "selection_model_removed", eti->selection);
- eti_remove_selection_model (eti);
- if (g_value_get_object (value))
- eti_add_selection_model (eti, E_SELECTION_MODEL(g_value_get_object(value)));
- break;
-
- case PROP_LENGTH_THRESHOLD:
- eti->length_threshold = g_value_get_int (value);
- break;
-
- case PROP_TABLE_ALTERNATING_ROW_COLORS:
- eti->alternating_row_colors = g_value_get_boolean (value);
- break;
-
- case PROP_TABLE_HORIZONTAL_DRAW_GRID:
- eti->horizontal_draw_grid = g_value_get_boolean (value);
- break;
-
- case PROP_TABLE_VERTICAL_DRAW_GRID:
- eti->vertical_draw_grid = g_value_get_boolean (value);
- break;
-
- case PROP_TABLE_DRAW_FOCUS:
- eti->draw_focus = g_value_get_boolean (value);
- break;
-
- case PROP_CURSOR_MODE:
- eti->cursor_mode = g_value_get_int (value);
- break;
-
- case PROP_MINIMUM_WIDTH:
- case PROP_WIDTH:
- if ((eti->minimum_width == eti->width && g_value_get_double(value) > eti->width) ||
- g_value_get_double(value) < eti->width) {
- eti->needs_compute_width = 1;
- e_canvas_item_request_reflow (GNOME_CANVAS_ITEM(eti));
- }
- eti->minimum_width = g_value_get_double (value);
- break;
- case PROP_CURSOR_ROW:
- g_object_get(eti->selection,
- "cursor_col", &cursor_col,
- NULL);
-
- e_table_item_focus (eti, cursor_col != -1 ? cursor_col : 0, view_to_model_row(eti, g_value_get_int (value)), 0);
- break;
- case PROP_UNIFORM_ROW_HEIGHT:
- if (eti->uniform_row_height != g_value_get_boolean (value)) {
- eti->uniform_row_height = g_value_get_boolean (value);
- if (GTK_OBJECT_FLAGS(eti) & GNOME_CANVAS_ITEM_REALIZED) {
- free_height_cache(eti);
- eti->needs_compute_height = 1;
- e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (eti));
- eti->needs_redraw = 1;
- gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (eti));
- }
- }
- break;
- }
- eti->needs_redraw = 1;
- gnome_canvas_item_request_update (GNOME_CANVAS_ITEM(eti));
-}
-
-static void
-eti_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
-{
- GnomeCanvasItem *item;
- ETableItem *eti;
- int row;
-
- item = GNOME_CANVAS_ITEM (object);
- eti = E_TABLE_ITEM (object);
-
- switch (prop_id){
- case PROP_WIDTH:
- g_value_set_double (value, eti->width);
- break;
- case PROP_HEIGHT:
- g_value_set_double (value, eti->height);
- break;
- case PROP_MINIMUM_WIDTH:
- g_value_set_double (value, eti->minimum_width);
- break;
- case PROP_CURSOR_ROW:
- g_object_get(eti->selection,
- "cursor_row", &row,
- NULL);
- g_value_set_int (value, model_to_view_row(eti, row));
- break;
- case PROP_UNIFORM_ROW_HEIGHT:
- g_value_set_boolean (value, eti->uniform_row_height);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-eti_init (GnomeCanvasItem *item)
-{
- ETableItem *eti = E_TABLE_ITEM (item);
-
- eti->motion_row = -1;
- eti->motion_col = -1;
- eti->editing_col = -1;
- eti->editing_row = -1;
- eti->height = 0;
- eti->width = 0;
- eti->minimum_width = 0;
-
- eti->save_col = -1;
- eti->save_row = -1;
- eti->save_state = NULL;
-
- eti->click_count = 0;
-
- eti->height_cache = NULL;
- eti->height_cache_idle_id = 0;
- eti->height_cache_idle_count = 0;
-
- eti->length_threshold = -1;
- eti->uniform_row_height = FALSE;
-
- eti->uses_source_model = 0;
- eti->source_model = NULL;
-
- eti->row_guess = -1;
- eti->cursor_mode = E_CURSOR_SIMPLE;
-
- eti->selection_change_id = 0;
- eti->selection_row_change_id = 0;
- eti->cursor_change_id = 0;
- eti->cursor_activated_id = 0;
- eti->selection = NULL;
-
- eti->old_cursor_row = -1;
-
- eti->needs_redraw = 0;
- eti->needs_compute_height = 0;
-
- eti->in_key_press = 0;
-
- eti->tooltip = g_new0 (ETableTooltip, 1);
- eti->tooltip->timer = 0;
- eti->tooltip->eti = GNOME_CANVAS_ITEM (eti);
- eti->tooltip->background = NULL;
- eti->tooltip->foreground = NULL;
-
- eti->maybe_did_something = TRUE;
-
- eti->grabbed_count = 0;
- eti->gtk_grabbed = 0;
-
- eti->in_drag = 0;
- eti->maybe_in_drag = 0;
- eti->grabbed = 0;
-
- eti->grabbed_col = -1;
- eti->grabbed_row = -1;
-
- eti->cursor_on_screen = FALSE;
- eti->cursor_x1 = -1;
- eti->cursor_y1 = -1;
- eti->cursor_x2 = -1;
- eti->cursor_y2 = -1;
-
- eti->rows = -1;
- eti->cols = -1;
-
- eti->frozen_count = 0;
- eti->queue_show_cursor = FALSE;
-
- e_canvas_item_set_reflow_callback (GNOME_CANVAS_ITEM (eti), eti_reflow);
-}
-
-#define gray50_width 2
-#define gray50_height 2
-static const char gray50_bits[] = {
- 0x02, 0x01, };
-
-static void
-adjustment_changed (GtkAdjustment *adjustment, ETableItem *eti)
-{
- eti_check_cursor_on_screen (eti);
-}
-
-static void
-eti_realize (GnomeCanvasItem *item)
-{
- ETableItem *eti = E_TABLE_ITEM (item);
- GtkWidget *canvas_widget = GTK_WIDGET (item->canvas);
- GdkWindow *window;
-
- if (GNOME_CANVAS_ITEM_CLASS (eti_parent_class)->realize)
- (*GNOME_CANVAS_ITEM_CLASS (eti_parent_class)->realize)(item);
-
-
- eti->rows = e_table_model_row_count (eti->table_model);
-
- /*
- * Gdk Resource allocation
- */
- window = canvas_widget->window;
-
- eti->fill_gc = gdk_gc_new (window);
-
- eti->grid_gc = gdk_gc_new (window);
- gdk_gc_set_foreground (eti->grid_gc, &canvas_widget->style->dark [GTK_STATE_NORMAL]);
- eti->focus_gc = gdk_gc_new (window);
- gdk_gc_set_foreground (eti->focus_gc, &canvas_widget->style->bg [GTK_STATE_NORMAL]);
- gdk_gc_set_background (eti->focus_gc, &canvas_widget->style->fg [GTK_STATE_NORMAL]);
- eti->stipple = gdk_bitmap_create_from_data (NULL, gray50_bits, gray50_width, gray50_height);
- gdk_gc_set_ts_origin (eti->focus_gc, 0, 0);
- gdk_gc_set_stipple (eti->focus_gc, eti->stipple);
- gdk_gc_set_fill (eti->focus_gc, GDK_OPAQUE_STIPPLED);
-
- eti->hadjustment_change_id =
- g_signal_connect (gtk_layout_get_hadjustment(GTK_LAYOUT(item->canvas)), "changed",
- G_CALLBACK (adjustment_changed), eti);
- eti->hadjustment_value_change_id =
- g_signal_connect (gtk_layout_get_hadjustment(GTK_LAYOUT(item->canvas)), "value_changed",
- G_CALLBACK (adjustment_changed), eti);
- eti->vadjustment_change_id =
- g_signal_connect (gtk_layout_get_vadjustment(GTK_LAYOUT(item->canvas)), "changed",
- G_CALLBACK (adjustment_changed), eti);
- eti->vadjustment_value_change_id =
- g_signal_connect (gtk_layout_get_vadjustment(GTK_LAYOUT(item->canvas)), "value_changed",
- G_CALLBACK (adjustment_changed), eti);
-
- if (eti->cell_views == NULL)
- eti_attach_cell_views (eti);
-
- eti_realize_cell_views (eti);
-
- free_height_cache(eti);
-
- if (item->canvas->focused_item == NULL && eti->selection) {
- int row;
-
- row = e_selection_model_cursor_row (E_SELECTION_MODEL (eti->selection));
- row = model_to_view_row(eti, row);
- if (row != -1) {
- e_canvas_item_grab_focus (item, FALSE);
- eti_show_cursor (eti, 0);
- eti_check_cursor_bounds (eti);
- }
- }
-
- eti->needs_compute_height = 1;
- eti->needs_compute_width = 1;
- e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (eti));
- eti->needs_redraw = 1;
- gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (eti));
-}
-
-static void
-eti_unrealize (GnomeCanvasItem *item)
-{
- ETableItem *eti = E_TABLE_ITEM (item);
-
- if (eti->grabbed_count > 0) {
- d(g_print ("%s: eti_ungrab\n", __FUNCTION__));
- eti_ungrab (eti, -1);
- }
-
- if (eti_editing (eti))
- e_table_item_leave_edit_(eti);
-
- if (eti->height_cache_idle_id) {
- g_source_remove(eti->height_cache_idle_id);
- eti->height_cache_idle_id = 0;
- }
-
- if (eti->height_cache)
- g_free (eti->height_cache);
- eti->height_cache = NULL;
- eti->height_cache_idle_count = 0;
-
- e_canvas_hide_tooltip (E_CANVAS(GNOME_CANVAS_ITEM(eti)->canvas));
- if (eti->tooltip) {
- if (eti->tooltip->background) {
- gdk_color_free (eti->tooltip->background);
- eti->tooltip->background = NULL;
- }
- if (eti->tooltip->foreground) {
- gdk_color_free (eti->tooltip->foreground);
- eti->tooltip->foreground = NULL;
- }
- if (eti->tooltip->timer) {
- gtk_timeout_remove (eti->tooltip->timer);
- eti->tooltip->timer = 0;
- }
- }
-
- gdk_gc_unref (eti->fill_gc);
- eti->fill_gc = NULL;
- gdk_gc_unref (eti->grid_gc);
- eti->grid_gc = NULL;
- gdk_gc_unref (eti->focus_gc);
- eti->focus_gc = NULL;
- gdk_bitmap_unref (eti->stipple);
- eti->stipple = NULL;
-
- eti_unrealize_cell_views (eti);
-
- eti->height = 0;
-
- g_signal_handler_disconnect(gtk_layout_get_hadjustment(GTK_LAYOUT(item->canvas)),
- eti->hadjustment_change_id);
- g_signal_handler_disconnect(gtk_layout_get_hadjustment(GTK_LAYOUT(item->canvas)),
- eti->hadjustment_value_change_id);
- g_signal_handler_disconnect(gtk_layout_get_vadjustment(GTK_LAYOUT(item->canvas)),
- eti->vadjustment_change_id);
- g_signal_handler_disconnect(gtk_layout_get_vadjustment(GTK_LAYOUT(item->canvas)),
- eti->vadjustment_value_change_id);
-
- if (GNOME_CANVAS_ITEM_CLASS (eti_parent_class)->unrealize)
- (*GNOME_CANVAS_ITEM_CLASS (eti_parent_class)->unrealize)(item);
-}
-
-
-
-static void
-eti_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, int height)
-{
- ETableItem *eti = E_TABLE_ITEM (item);
- const int rows = eti->rows;
- const int cols = eti->cols;
- int row, col;
- int first_col, last_col, x_offset;
- int first_row, last_row, y_offset, yd;
- int x1, x2;
- int f_x1, f_x2, f_y1, f_y2;
- gboolean f_found;
- double i2c [6];
- ArtPoint eti_base, eti_base_item, lower_right;
- GtkWidget *canvas = GTK_WIDGET(item->canvas);
- int height_extra = eti->horizontal_draw_grid ? 1 : 0;
-
- /*
- * Find out our real position after grouping
- */
- gnome_canvas_item_i2c_affine (item, i2c);
- eti_base_item.x = eti->x1;
- eti_base_item.y = eti->y1;
- art_affine_point (&eti_base, &eti_base_item, i2c);
-
- eti_base_item.x = eti->x1 + eti->width;
- eti_base_item.y = eti->y1 + eti->height;
- art_affine_point (&lower_right, &eti_base_item, i2c);
-
- /*
- * First column to draw, last column to draw
- */
- first_col = -1;
- last_col = x_offset = 0;
- x1 = x2 = floor (eti_base.x);
- for (col = 0; col < cols; col++, x1 = x2){
- ETableCol *ecol = e_table_header_get_column (eti->header, col);
-
- x2 = x1 + ecol->width;
-
- if (x1 > (x + width))
- break;
- if (x2 < x)
- continue;
- if (first_col == -1){
- x_offset = x1 - x;
- first_col = col;
- }
- }
- last_col = col;
-
- /*
- * Nothing to paint
- */
- if (first_col == -1)
- return;
-
- /*
- * Compute row span.
- */
- if (eti->uniform_row_height) {
- first_row = (y - floor (eti_base.y) - height_extra) / (eti_row_height (eti, -1) + height_extra);
- last_row = (y + height - floor (eti_base.y) ) / (eti_row_height (eti, -1) + height_extra) + 1;
- if (first_row > last_row)
- return;
- y_offset = floor (eti_base.y) - y + height_extra + first_row * (eti_row_height (eti, -1) + height_extra);
- if (first_row < 0)
- first_row = 0;
- if (last_row > eti->rows)
- last_row = eti->rows;
- } else {
- int y1, y2;
-
- y_offset = 0;
- first_row = -1;
-
- y1 = y2 = floor (eti_base.y) + height_extra;
- for (row = 0; row < rows; row++, y1 = y2){
-
- y2 += ETI_ROW_HEIGHT (eti, row) + height_extra;
-
- if (y1 > y + height)
- break;
-
- if (y2 < y)
- continue;
-
- if (first_row == -1){
- y_offset = y1 - y;
- first_row = row;
- }
- }
- last_row = row;
-
- if (first_row == -1)
- return;
- }
-
- if (first_row == -1)
- return;
-
- /*
- * Draw cells
- */
- yd = y_offset;
- f_x1 = f_x2 = f_y1 = f_y2 = -1;
- f_found = FALSE;
-
- if (eti->horizontal_draw_grid && first_row == 0){
- gdk_draw_line (
- drawable, eti->grid_gc,
- eti_base.x - x, yd, eti_base.x + eti->width - x, yd);
- }
-
- yd += height_extra;
-
- for (row = first_row; row < last_row; row++){
- int xd, height;
- gboolean selected;
- gint cursor_col, cursor_row;
-
- height = ETI_ROW_HEIGHT (eti, row);
-
- xd = x_offset;
-/* printf ("paint: %d %d\n", yd, yd + height); */
-
- selected = e_selection_model_is_row_selected(E_SELECTION_MODEL (eti->selection), view_to_model_row(eti,row));
-
- g_object_get(eti->selection,
- "cursor_col", &cursor_col,
- "cursor_row", &cursor_row,
- NULL);
-
- for (col = first_col; col < last_col; col++){
- ETableCol *ecol = e_table_header_get_column (eti->header, col);
- ECellView *ecell_view = eti->cell_views [col];
- gboolean col_selected = selected;
- gboolean cursor = FALSE;
- ECellFlags flags;
- gboolean free_background;
- GdkColor *background;
-
- switch (eti->cursor_mode) {
- case E_CURSOR_SIMPLE:
- case E_CURSOR_SPREADSHEET:
- if (cursor_col == ecol->col_idx && cursor_row == view_to_model_row(eti, row)) {
- col_selected = !col_selected;
- cursor = TRUE;
- }
- break;
- case E_CURSOR_LINE:
- /* Nothing */
- break;
- }
-
- background = eti_get_cell_background_color (eti, row, col, col_selected, &free_background);
-
- gdk_gc_set_foreground (eti->fill_gc, background);
- gdk_draw_rectangle (drawable, eti->fill_gc, TRUE,
- xd, yd, ecol->width, height);
-
- if (free_background)
- gdk_color_free (background);
-
- flags = col_selected ? E_CELL_SELECTED : 0;
- flags |= GTK_WIDGET_HAS_FOCUS(canvas) ? E_CELL_FOCUSED : 0;
- flags |= cursor ? E_CELL_CURSOR : 0;
-
- switch (ecol->justification) {
- case GTK_JUSTIFY_LEFT:
- flags |= E_CELL_JUSTIFY_LEFT;
- break;
- case GTK_JUSTIFY_RIGHT:
- flags |= E_CELL_JUSTIFY_RIGHT;
- break;
- case GTK_JUSTIFY_CENTER:
- flags |= E_CELL_JUSTIFY_CENTER;
- break;
- case GTK_JUSTIFY_FILL:
- flags |= E_CELL_JUSTIFY_FILL;
- break;
- }
-
- e_cell_draw (ecell_view, drawable, ecol->col_idx, col, row, flags,
- xd, yd, xd + ecol->width, yd + height);
-
- if (!f_found) {
- switch (eti->cursor_mode) {
- case E_CURSOR_LINE:
- if (view_to_model_row(eti, row) == cursor_row) {
- f_x1 = floor (eti_base.x) - x;
- f_x2 = floor (lower_right.x) - x;
- f_y1 = yd;
- f_y2 = yd + height;
- f_found = TRUE;
- }
- break;
- case E_CURSOR_SIMPLE:
- case E_CURSOR_SPREADSHEET:
- if (view_to_model_col(eti, col) == cursor_col && view_to_model_row(eti, row) == cursor_row) {
- f_x1 = xd;
- f_x2 = xd + ecol->width;
- f_y1 = yd;
- f_y2 = yd + height;
- f_found = TRUE;
- }
- break;
- }
- }
-
- xd += ecol->width;
- }
- yd += height;
-
- if (eti->horizontal_draw_grid) {
- gdk_draw_line (
- drawable, eti->grid_gc,
- eti_base.x - x, yd, eti_base.x + eti->width - x, yd);
-
- yd++;
- }
- }
-
- if (eti->vertical_draw_grid){
- int xd = x_offset;
-
- for (col = first_col; col <= last_col; col++){
- ETableCol *ecol = e_table_header_get_column (eti->header, col);
-
- gdk_draw_line (
- drawable, eti->grid_gc,
- xd, y_offset, xd, yd - 1);
-
- /*
- * This looks wierd, but it is to draw the last line
- */
- if (ecol)
- xd += ecol->width;
- }
- }
-
- /*
- * Draw focus
- */
- if (eti->draw_focus && f_found) {
- gdk_gc_set_ts_origin (eti->focus_gc, f_x1, f_y1);
- gdk_draw_rectangle (drawable, eti->focus_gc, FALSE,
- f_x1, f_y1, f_x2 - f_x1 - 1, f_y2 - f_y1 - 1);
- }
-}
-
-static double
-eti_point (GnomeCanvasItem *item, double x, double y, int cx, int cy,
- GnomeCanvasItem **actual_item)
-{
- *actual_item = item;
-
- return 0.0;
-}
-
-static gboolean
-find_cell (ETableItem *eti, double x, double y, int *view_col_res, int *view_row_res, double *x1_res, double *y1_res)
-{
- const int cols = eti->cols;
- const int rows = eti->rows;
- gdouble x1, y1, x2, y2;
- int col, row;
-
- int height_extra = eti->horizontal_draw_grid ? 1 : 0;
-
- /* FIXME: this routine is inneficient, fix later */
-
- if (eti->grabbed_col >= 0 && eti->grabbed_row >= 0) {
- *view_col_res = eti->grabbed_col;
- *view_row_res = eti->grabbed_row;
- *x1_res = x - eti->x1 - e_table_header_col_diff (eti->header, 0, eti->grabbed_col);
- *y1_res = y - eti->y1 - e_table_item_row_diff (eti, 0, eti->grabbed_row);
- return TRUE;
- }
-
- if (cols == 0 || rows == 0)
- return FALSE;
-
- x -= eti->x1;
- y -= eti->y1;
-
- x1 = 0;
- for (col = 0; col < cols - 1; col++, x1 = x2){
- ETableCol *ecol = e_table_header_get_column (eti->header, col);
-
- if (x < x1)
- return FALSE;
-
- x2 = x1 + ecol->width;
-
- if (x <= x2)
- break;
- }
-
- if (eti->uniform_row_height) {
- if (y < height_extra)
- return FALSE;
- row = (y - height_extra) / (eti_row_height (eti, -1) + height_extra);
- y1 = row * (eti_row_height (eti, -1) + height_extra) + height_extra;
- if (row >= eti->rows)
- return FALSE;
- } else {
- y1 = y2 = height_extra;
- if (y < height_extra)
- return FALSE;
- for (row = 0; row < rows - 1; row++, y1 = y2){
- y2 += ETI_ROW_HEIGHT (eti, row) + height_extra;
-
- if (y <= y2)
- break;
- }
- }
- *view_col_res = col;
- if (x1_res)
- *x1_res = x - x1;
- *view_row_res = row;
- if (y1_res)
- *y1_res = y - y1;
- return TRUE;
-}
-
-static void
-eti_cursor_move (ETableItem *eti, gint row, gint column)
-{
- e_table_item_leave_edit_(eti);
- e_table_item_focus (eti, view_to_model_col(eti, column), view_to_model_row(eti, row), 0);
-}
-
-static void
-eti_cursor_move_left (ETableItem *eti)
-{
- int cursor_col, cursor_row;
- g_object_get(eti->selection,
- "cursor_col", &cursor_col,
- "cursor_row", &cursor_row,
- NULL);
-
- eti_cursor_move (eti, model_to_view_row(eti, cursor_row), model_to_view_col(eti, cursor_col) - 1);
-}
-
-static void
-eti_cursor_move_right (ETableItem *eti)
-{
- int cursor_col, cursor_row;
- g_object_get(eti->selection,
- "cursor_col", &cursor_col,
- "cursor_row", &cursor_row,
- NULL);
-
- eti_cursor_move (eti, model_to_view_row(eti, cursor_row), model_to_view_col(eti, cursor_col) + 1);
-}
-
-#ifdef DO_TOOLTIPS
-static int
-_do_tooltip (ETableItem *eti)
-{
- ECellView *ecell_view;
- gboolean free_color;
- ETableCol *ecol;
- gboolean selected;
- int cursor_row, cursor_col;
-
- e_canvas_hide_tooltip (E_CANVAS(GNOME_CANVAS_ITEM(eti)->canvas));
-
- if (eti_editing (eti))
- return FALSE;
-
- ecell_view = eti->cell_views[eti->tooltip->col];
-
- eti->tooltip->x = e_table_header_col_diff (eti->header, 0, eti->tooltip->col);
-
- eti->tooltip->y = e_table_item_row_diff (eti, 0, eti->tooltip->row);
- eti->tooltip->row_height = ETI_ROW_HEIGHT (eti, eti->tooltip->row);
-
- selected = e_selection_model_is_row_selected(E_SELECTION_MODEL (eti->selection), view_to_model_row(eti,eti->tooltip->row));
-
- if (eti->tooltip->foreground)
- gdk_color_free (eti->tooltip->foreground);
- if (eti->tooltip->background)
- gdk_color_free (eti->tooltip->background);
-
- switch (eti->cursor_mode) {
- case E_CURSOR_SIMPLE:
- case E_CURSOR_SPREADSHEET:
- ecol = e_table_header_get_column (eti->header, eti->tooltip->col);
-
- g_object_get(eti->selection,
- "cursor_row", &cursor_row,
- "cursor_col", &cursor_col,
- NULL);
-
- if (cursor_col == ecol->col_idx && cursor_row == view_to_model_row(eti, eti->tooltip->row))
- selected = !selected;
- break;
- case E_CURSOR_LINE:
- /* Nothing */
- break;
- }
-
- eti->tooltip->background = eti_get_cell_background_color (eti, eti->tooltip->row, eti->tooltip->col, selected, &free_color);
- if (!free_color)
- eti->tooltip->background = gdk_color_copy(eti->tooltip->background);
-
- eti->tooltip->foreground = eti_get_cell_foreground_color (eti, eti->tooltip->row, eti->tooltip->col, selected, &free_color);
- if (!free_color)
- eti->tooltip->foreground = gdk_color_copy(eti->tooltip->foreground);
-
- e_cell_show_tooltip (ecell_view,
- view_to_model_col (eti, eti->tooltip->col),
- eti->tooltip->col,
- eti->tooltip->row,
- eti->header->columns[eti->tooltip->col]->width,
- eti->tooltip);
- return FALSE;
-}
-#endif
-
-static gint
-eti_e_cell_event (ETableItem *item, ECellView *ecell_view, GdkEvent *event, int time, int model_col, int view_col, int row, ECellFlags flags)
-{
- ECellActions actions = 0;
- gint ret_val;
-
- ret_val = e_cell_event (ecell_view, event, model_col, view_col, row, flags, &actions);
-
- if (actions & E_CELL_GRAB) {
- d(g_print ("%s: eti_grab\n", __FUNCTION__));
- eti_grab (item, time);
- item->grabbed_col = view_col;
- item->grabbed_row = row;
- }
-
- if (actions & E_CELL_UNGRAB) {
- d(g_print ("%s: eti_ungrab\n", __FUNCTION__));
- eti_ungrab (item, time);
- item->grabbed_col = -1;
- item->grabbed_row = -1;
- }
-
- return ret_val;
-}
-
-/* FIXME: cursor */
-static int
-eti_event (GnomeCanvasItem *item, GdkEvent *e)
-{
- ETableItem *eti = E_TABLE_ITEM (item);
- ECellView *ecell_view;
- gint return_val = TRUE;
-#if d(!)0
- gboolean leave = FALSE;
-#endif
-
- if (!eti->header)
- return FALSE;
-
- switch (e->type){
- case GDK_BUTTON_PRESS: {
- double x1, y1;
- double realx, realy;
- GdkEventButton button;
- int col, row;
- gint cursor_row, cursor_col;
- gint new_cursor_row, new_cursor_col;
- ECellFlags flags = 0;
-
- d(g_print("%s: GDK_BUTTON_PRESS received, button %d\n", __FUNCTION__, e->button.button));
-
- if (eti->tooltip->timer) {
- gtk_timeout_remove (eti->tooltip->timer);
- eti->tooltip->timer = 0;
- }
-
- switch (e->button.button) {
- case 1: /* Fall through. */
- case 2:
- e_canvas_item_grab_focus(GNOME_CANVAS_ITEM(eti), TRUE);
- gnome_canvas_item_w2i (item, &e->button.x, &e->button.y);
-
- realx = e->button.x;
- realy = e->button.y;
-
- if (!find_cell (eti, realx, realy, &col, &row, &x1, &y1)) {
- if (eti_editing (eti))
- e_table_item_leave_edit_(eti);
- return TRUE;
- }
-
- ecell_view = eti->cell_views [col];
- button = *(GdkEventButton *)e;
- button.x = x1;
- button.y = y1;
-
- g_object_get(eti->selection,
- "cursor_row", &cursor_row,
- "cursor_col", &cursor_col,
- NULL);
-
- if (cursor_col == view_to_model_col (eti, col) && cursor_row == view_to_model_row(eti, row)) {
- flags = E_CELL_CURSOR;
- } else {
- flags = 0;
- }
-
- return_val = eti_e_cell_event (eti, ecell_view, (GdkEvent *) &button, button.time, view_to_model_col(eti, col), col, row, flags);
- if (return_val)
- return TRUE;
-
- g_signal_emit (eti, eti_signals [CLICK], 0,
- row, view_to_model_col(eti, col), &button, &return_val);
-
- if (return_val) {
- eti->click_count = 0;
- return TRUE;
- }
-
- g_object_get(eti->selection,
- "cursor_row", &cursor_row,
- "cursor_col", &cursor_col,
- NULL);
-
- eti->maybe_did_something =
- e_selection_model_maybe_do_something(E_SELECTION_MODEL (eti->selection), view_to_model_row(eti, row), view_to_model_col(eti, col), button.state);
- g_object_get(eti->selection,
- "cursor_row", &new_cursor_row,
- "cursor_col", &new_cursor_col,
- NULL);
-
- if (cursor_row != new_cursor_row || cursor_col != new_cursor_col) {
- eti->click_count = 1;
- } else {
- eti->click_count ++;
- eti->row_guess = row;
-
- if ((!eti_editing(eti)) && e_table_model_is_cell_editable(eti->table_model, cursor_col, row)) {
- e_table_item_enter_edit (eti, col, row);
- }
-
- /*
- * Adjust the event positions
- */
-
- if (eti_editing (eti)) {
- return_val = eti_e_cell_event (eti, ecell_view, (GdkEvent *) &button, button.time,
- view_to_model_col(eti, col), col, row, E_CELL_EDITING | E_CELL_CURSOR);
- if (return_val)
- return TRUE;
- }
- }
-
- if (e->button.button == 1) {
- return_val = TRUE;
-
- eti->maybe_in_drag = TRUE;
- eti->drag_row = new_cursor_row;
- eti->drag_col = new_cursor_col;
- eti->drag_x = realx;
- eti->drag_y = realy;
- eti->drag_state = e->button.state;
- eti->grabbed = TRUE;
- d(g_print ("%s: eti_grab\n", __FUNCTION__));
- eti_grab (eti, e->button.time);
- }
-
- break;
- case 3:
- e_canvas_item_grab_focus(GNOME_CANVAS_ITEM(eti), TRUE);
- gnome_canvas_item_w2i (item, &e->button.x, &e->button.y);
- if (!find_cell (eti, e->button.x, e->button.y, &col, &row, &x1, &y1))
- return TRUE;
-
- e_selection_model_right_click_down(E_SELECTION_MODEL (eti->selection), view_to_model_row(eti, row), view_to_model_col(eti, col), 0);
-
- g_signal_emit (eti, eti_signals [RIGHT_CLICK], 0,
- row, view_to_model_col(eti, col), e, &return_val);
- if (!return_val)
- e_selection_model_right_click_up(E_SELECTION_MODEL (eti->selection));
- break;
- case 4:
- case 5:
- return FALSE;
- break;
-
- }
- break;
- }
-
- case GDK_BUTTON_RELEASE: {
- double x1, y1;
- int col, row;
- gint cursor_row, cursor_col;
-
- d(g_print("%s: GDK_BUTTON_RELEASE received, button %d\n", __FUNCTION__, e->button.button));
-
- if (eti->grabbed_count > 0) {
- d(g_print ("%s: eti_ungrab\n", __FUNCTION__));
- eti_ungrab (eti, e->button.time);
- }
-
- if (e->button.button == 1) {
- if (eti->maybe_in_drag) {
- eti->maybe_in_drag = FALSE;
- if (!eti->maybe_did_something)
- e_selection_model_do_something(E_SELECTION_MODEL (eti->selection), eti->drag_row, eti->drag_col, eti->drag_state);
- }
- if (eti->in_drag) {
- eti->in_drag = FALSE;
- }
- }
-
- if (eti->tooltip->timer) {
- gtk_timeout_remove (eti->tooltip->timer);
- eti->tooltip->timer = 0;
- }
- e_canvas_hide_tooltip (E_CANVAS(GNOME_CANVAS_ITEM(eti)->canvas));
- switch (e->button.button) {
- case 1: /* Fall through. */
- case 2:
-
- gnome_canvas_item_w2i (item, &e->button.x, &e->button.y);
-#if d(!)0
- {
- gboolean cell_found = find_cell (eti, e->button.x, e->button.y, &col, &row, &x1, &y1);
- g_print("%s: find_cell(%f, %f) = %s(%d, %d, %f, %f)\n", __FUNCTION__, e->button.x, e->button.y,
- cell_found?"true":"false", col, row, x1, y1);
- }
-#endif
-
- if (!find_cell (eti, e->button.x, e->button.y, &col, &row, &x1, &y1))
- return TRUE;
-
- g_object_get(eti->selection,
- "cursor_row", &cursor_row,
- "cursor_col", &cursor_col,
- NULL);
-
-
- d(g_print("%s: GDK_BUTTON_RELEASE received, button %d, line: %d\n"
- "eti_editing: %s, row:%d:%d, col:%d:%d\n", __FUNCTION__, e->button.button, __LINE__,
- eti_editing(eti)?"true":"false", cursor_row, view_to_model_row(eti, row), cursor_col, view_to_model_col(eti, col)));
-
- if (eti_editing (eti) && cursor_row == view_to_model_row(eti, row) && cursor_col == view_to_model_col(eti, col)){
-
- d(g_print("%s: GDK_BUTTON_RELEASE received, button %d, line: %d\n", __FUNCTION__, e->button.button, __LINE__))
-;
-
- ecell_view = eti->cell_views [col];
-
- /*
- * Adjust the event positions
- */
- e->button.x = x1;
- e->button.y = y1;
-
- return_val = eti_e_cell_event (eti, ecell_view, e, e->button.time,
- view_to_model_col(eti, col), col, row, E_CELL_EDITING | E_CELL_CURSOR);
- }
- break;
- case 3:
- e_selection_model_right_click_up(E_SELECTION_MODEL (eti->selection));
- return_val = TRUE;
- break;
- case 4:
- case 5:
- return FALSE;
- break;
-
- }
- break;
- }
-
- case GDK_2BUTTON_PRESS: {
- int model_col, model_row;
-#if 0
- double x1, y1;
-#endif
-
- d(g_print("%s: GDK_2BUTTON_PRESS received, button %d\n", __FUNCTION__, e->button.button));
-
- if (e->button.button == 5 ||
- e->button.button == 4)
- return FALSE;
-
- /*
- * click_count is so that if you click on two
- * different rows we don't send a double click signal.
- */
-
- if (eti->click_count >= 2) {
-
- gnome_canvas_item_w2i (item, &e->button.x, &e->button.y);
-
-#if 0
- if (!find_cell (eti, e->button.x, e->button.y, &current_col, &current_row, &x1, &y1))
- return TRUE;
-#endif
-
- g_object_get(eti->selection,
- "cursor_row", &model_row,
- "cursor_col", &model_col,
- NULL);
-
- e->button.x -= e_table_header_col_diff (eti->header, 0, model_to_view_col (eti, model_col));
- e->button.y -= e_table_item_row_diff (eti, 0, model_to_view_row (eti, model_row));
-
- if (e->button.button == 1) {
- if (eti->maybe_in_drag) {
- eti->maybe_in_drag = FALSE;
- if (!eti->maybe_did_something)
- e_selection_model_do_something(E_SELECTION_MODEL (eti->selection), eti->drag_row, eti->drag_col, eti->drag_state);
- }
- if (eti->in_drag) {
- eti->in_drag = FALSE;
- }
- if (eti_editing (eti))
- e_table_item_leave_edit_ (eti);
-
- }
-
- if (eti->grabbed_count > 0) {
- d(g_print ("%s: eti_ungrab\n", __FUNCTION__));
- eti_ungrab (eti, e->button.time);
- }
-
- if (model_row != -1 && model_col != -1) {
- g_signal_emit (eti, eti_signals [DOUBLE_CLICK], 0,
- model_row, model_col, e);
- }
- }
- break;
- }
- case GDK_MOTION_NOTIFY: {
- int col, row, flags;
- double x1, y1;
- gint cursor_col, cursor_row;
-
- gnome_canvas_item_w2i (item, &e->motion.x, &e->motion.y);
-
- if (eti->maybe_in_drag) {
- if (abs (e->motion.x - eti->drag_x) >= 3 ||
- abs (e->motion.y - eti->drag_y) >= 3) {
- gint drag_handled;
-
- eti->maybe_in_drag = 0;
- g_signal_emit (eti, eti_signals [START_DRAG], 0,
- eti->drag_row, eti->drag_col, e, &drag_handled);
- if (drag_handled)
- eti->in_drag = 1;
- else
- eti->in_drag = 0;
- }
- }
-
- if (!find_cell (eti, e->motion.x, e->motion.y, &col, &row, &x1, &y1))
- return TRUE;
-
- if (eti->motion_row != -1 && eti->motion_col != -1 &&
- (row != eti->motion_row || col != eti->motion_col)) {
- GdkEvent *cross = gdk_event_new (GDK_LEAVE_NOTIFY);
- cross->crossing.time = e->motion.time;
- return_val = eti_e_cell_event (eti, eti->cell_views [eti->motion_col],
- cross, cross->crossing.time,
- view_to_model_col(eti, eti->motion_col),
- eti->motion_col, eti->motion_row, 0);
- }
-
- eti->motion_row = row;
- eti->motion_col = col;
-
- g_object_get(eti->selection,
- "cursor_row", &cursor_row,
- "cursor_col", &cursor_col,
- NULL);
-
- e_canvas_hide_tooltip (E_CANVAS(GNOME_CANVAS_ITEM(eti)->canvas));
-
-#ifdef DO_TOOLTIPS
- if (!g_getenv ("GAL_DONT_DO_TOOLTIPS")) {
- if (eti->tooltip->timer)
- gtk_timeout_remove (eti->tooltip->timer);
- eti->tooltip->col = col;
- eti->tooltip->row = row;
- eti->tooltip->cx = e->motion.x;
- eti->tooltip->cy = e->motion.y;
- eti->tooltip->timer = gtk_timeout_add (100, (GSourceFunc)_do_tooltip, eti);
- }
-#endif
-
- flags = 0;
- if (cursor_row == view_to_model_row(eti, row) && cursor_col == view_to_model_col(eti, col)){
- flags = E_CELL_EDITING | E_CELL_CURSOR;
- }
-
- ecell_view = eti->cell_views [col];
-
- /*
- * Adjust the event positions
- */
- e->motion.x = x1;
- e->motion.y = y1;
-
- return_val = eti_e_cell_event (eti, ecell_view, e, e->motion.time,
- view_to_model_col(eti, col), col, row, flags);
- break;
- }
-
- case GDK_KEY_PRESS: {
- gint cursor_row, cursor_col;
- gint handled = TRUE;
-
- d(g_print("%s: GDK_KEY_PRESS received, keyval: %d\n", __FUNCTION__, (int) e->key.keyval));
-
- g_object_get(eti->selection,
- "cursor_row", &cursor_row,
- "cursor_col", &cursor_col,
- NULL);
-
- if (eti->tooltip->timer) {
- gtk_timeout_remove (eti->tooltip->timer);
- eti->tooltip->timer = 0;
- }
- e_canvas_hide_tooltip (E_CANVAS(GNOME_CANVAS_ITEM(eti)->canvas));
-
- if (cursor_row == -1 && cursor_col == -1)
- return FALSE;
-
- eti->in_key_press = TRUE;
-
- switch (e->key.keyval){
- case GDK_Left:
- case GDK_KP_Left:
- if (eti_editing (eti)) {
- handled = FALSE;
- break;
- }
-
- g_signal_emit (eti, eti_signals [KEY_PRESS], 0,
- model_to_view_row(eti, cursor_row), cursor_col, e, &return_val);
- if ((!return_val) && eti->cursor_mode != E_CURSOR_LINE && cursor_col != view_to_model_col(eti, 0))
- eti_cursor_move_left (eti);
- return_val = 1;
- break;
-
- case GDK_Right:
- case GDK_KP_Right:
- if (eti_editing (eti)) {
- handled = FALSE;
- break;
- }
-
- g_signal_emit (eti, eti_signals [KEY_PRESS], 0,
- model_to_view_row(eti, cursor_row), cursor_col, e, &return_val);
- if ((!return_val) && eti->cursor_mode != E_CURSOR_LINE && cursor_col != view_to_model_col(eti, eti->cols - 1))
- eti_cursor_move_right (eti);
- return_val = 1;
- break;
-
- case GDK_Up:
- case GDK_KP_Up:
- case GDK_Down:
- case GDK_KP_Down:
- if ((e->key.state & GDK_MOD1_MASK)
- && ((e->key.keyval == GDK_Down ) || (e->key.keyval == GDK_KP_Down))) {
- gint view_col = model_to_view_col(eti, cursor_col);
- if ((view_col >= 0) && (view_col < eti->cols))
- if (eti_e_cell_event (eti, eti->cell_views [view_col], e, ((GdkEventKey *)e)->time, cursor_col, view_col, model_to_view_row(eti, cursor_row), E_CELL_CURSOR))
- return TRUE;
- } else
- return_val = e_selection_model_key_press(E_SELECTION_MODEL (eti->selection), (GdkEventKey *) e);
- break;
- case GDK_Home:
- case GDK_KP_Home:
- if (eti->cursor_mode != E_CURSOR_LINE) {
- eti_cursor_move (eti, model_to_view_row(eti, cursor_row), 0);
- return_val = TRUE;
- } else
- return_val = e_selection_model_key_press(E_SELECTION_MODEL (eti->selection), (GdkEventKey *) e);
- break;
- case GDK_End:
- case GDK_KP_End:
- if (eti->cursor_mode != E_CURSOR_LINE) {
- eti_cursor_move (eti, model_to_view_row(eti, cursor_row), eti->cols - 1);
- return_val = TRUE;
- } else
- return_val = e_selection_model_key_press(E_SELECTION_MODEL (eti->selection), (GdkEventKey *) e);
- break;
- case GDK_Tab:
- case GDK_KP_Tab:
- case GDK_ISO_Left_Tab:
- if ((e->key.state & GDK_CONTROL_MASK) != 0) {
- return_val = FALSE;
- break;
- }
- if (eti->cursor_mode == E_CURSOR_SPREADSHEET) {
- if ((e->key.state & GDK_SHIFT_MASK) != 0){
- /* shift tab */
- if (cursor_col != view_to_model_col(eti, 0))
- eti_cursor_move_left (eti);
- else if (cursor_row != view_to_model_row(eti, 0))
- eti_cursor_move (eti, model_to_view_row(eti, cursor_row) - 1, eti->cols - 1);
- else
- return_val = FALSE;
- } else {
- if (cursor_col != view_to_model_col (eti, eti->cols - 1))
- eti_cursor_move_right (eti);
- else if (cursor_row != view_to_model_row(eti, eti->rows - 1))
- eti_cursor_move (eti, model_to_view_row(eti, cursor_row) + 1, 0);
- else
- return_val = FALSE;
- }
- g_object_get(eti->selection,
- "cursor_row", &cursor_row,
- "cursor_col", &cursor_col,
- NULL);
-
- if (cursor_col >= 0 && cursor_row >= 0 && return_val &&
- (!eti_editing(eti)) && e_table_model_is_cell_editable(eti->table_model, cursor_col, model_to_view_row (eti, cursor_row))) {
- e_table_item_enter_edit (eti, model_to_view_col(eti, cursor_col), model_to_view_row(eti, cursor_row));
- }
- break;
- } else {
- /* Let tab send you to the next widget. */
- return_val = FALSE;
- break;
- }
-
- case GDK_Return:
- case GDK_KP_Enter:
- case GDK_ISO_Enter:
- case GDK_3270_Enter:
- if (eti_editing (eti)){
- ecell_view = eti->cell_views [eti->editing_col];
- return_val = eti_e_cell_event (eti, ecell_view, e, e->key.time,
- view_to_model_col (eti, eti->editing_col),
- eti->editing_col, eti->editing_row, E_CELL_EDITING | E_CELL_CURSOR | E_CELL_PREEDIT);
- if (!return_val)
- break;
- }
- g_signal_emit (eti, eti_signals [KEY_PRESS], 0,
- model_to_view_row (eti, cursor_row), cursor_col, e, &return_val);
- if (!return_val)
- return_val = e_selection_model_key_press (E_SELECTION_MODEL (eti->selection), (GdkEventKey *) e);
- break;
-
- default:
- handled = FALSE;
- break;
- }
-
- if (!handled) {
- switch (e->key.keyval) {
- case GDK_Scroll_Lock:
- case GDK_Sys_Req:
- case GDK_Shift_L:
- case GDK_Shift_R:
- case GDK_Control_L:
- case GDK_Control_R:
- case GDK_Caps_Lock:
- case GDK_Shift_Lock:
- case GDK_Meta_L:
- case GDK_Meta_R:
- case GDK_Alt_L:
- case GDK_Alt_R:
- case GDK_Super_L:
- case GDK_Super_R:
- case GDK_Hyper_L:
- case GDK_Hyper_R:
- case GDK_ISO_Lock:
- break;
-
- default:
- if (!eti_editing (eti)){
- gint col, row;
- row = model_to_view_row(eti, cursor_row);
- col = model_to_view_col(eti, cursor_col);
- if (col != -1 && row != -1 && e_table_model_is_cell_editable(eti->table_model, cursor_col, row)) {
- e_table_item_enter_edit (eti, col, row);
- }
- }
- if (!eti_editing (eti)){
- g_signal_emit (eti, eti_signals [KEY_PRESS], 0,
- model_to_view_row(eti, cursor_row), cursor_col, e, &return_val);
- if (!return_val)
- e_selection_model_key_press(E_SELECTION_MODEL (eti->selection), (GdkEventKey *) e);
- } else {
- ecell_view = eti->cell_views [eti->editing_col];
- return_val = eti_e_cell_event (eti, ecell_view, e, e->key.time,
- view_to_model_col(eti, eti->editing_col),
- eti->editing_col, eti->editing_row, E_CELL_EDITING | E_CELL_CURSOR);
- if (!return_val)
- e_selection_model_key_press(E_SELECTION_MODEL (eti->selection), (GdkEventKey *) e);
- }
- break;
- }
- }
- eti->in_key_press = FALSE;
- break;
- }
-
- case GDK_KEY_RELEASE: {
- gint cursor_row, cursor_col;
-
- d(g_print("%s: GDK_KEY_RELEASE received, keyval: %d\n", __FUNCTION__, (int) e->key.keyval));
-
- g_object_get(eti->selection,
- "cursor_row", &cursor_row,
- "cursor_col", &cursor_col,
- NULL);
-
- if (cursor_col == -1)
- return FALSE;
-
- if (eti_editing (eti)){
- ecell_view = eti->cell_views [eti->editing_col];
- return_val = eti_e_cell_event (eti, ecell_view, e, e->key.time,
- view_to_model_col(eti, eti->editing_col),
- eti->editing_col, eti->editing_row, E_CELL_EDITING | E_CELL_CURSOR);
- }
- break;
- }
-
- case GDK_LEAVE_NOTIFY:
- d(leave = TRUE);
- case GDK_ENTER_NOTIFY:
- d(g_print("%s: %s received\n", __FUNCTION__, leave ? "GDK_LEAVE_NOTIFY" : "GDK_ENTER_NOTIFY"));
- if (eti->tooltip->timer)
- gtk_timeout_remove (eti->tooltip->timer);
- eti->tooltip->timer = 0;
- if (eti->motion_row != -1 && eti->motion_col != -1)
- return_val = eti_e_cell_event (eti, eti->cell_views [eti->motion_col],
- e, e->crossing.time,
- view_to_model_col(eti, eti->motion_col),
- eti->motion_col, eti->motion_row, 0);
- eti->motion_row = -1;
- eti->motion_col = -1;
-
- break;
-
- case GDK_FOCUS_CHANGE:
- d(g_print("%s: GDK_FOCUS_CHANGE received, %s\n", __FUNCTION__, e->focus_change.in ? "in": "out"));
- if (e->focus_change.in) {
- if (eti->save_row != -1 &&
- eti->save_col != -1 &&
- !eti_editing (eti) &&
- e_table_model_is_cell_editable(eti->table_model, view_to_model_col (eti, eti->save_col), eti->save_row)) {
- e_table_item_enter_edit (eti, eti->save_col, eti->save_row);
- e_cell_load_state (eti->cell_views [eti->editing_col], view_to_model_col(eti, eti->save_col),
- eti->save_col, eti->save_row, eti->edit_ctx, eti->save_state);
- eti_free_save_state (eti);
- }
- } else {
- if (eti_editing (eti)) {
- eti_free_save_state (eti);
-
- eti->save_row = eti->editing_row;
- eti->save_col = eti->editing_col;
- eti->save_state = e_cell_save_state (eti->cell_views [eti->editing_col], view_to_model_col(eti, eti->editing_col),
- eti->editing_col, eti->editing_row, eti->edit_ctx);
- e_table_item_leave_edit_(eti);
- }
- }
-
- default:
- return_val = FALSE;
- }
- /* d(g_print("%s: returning: %s\n", __FUNCTION__, return_val?"true":"false"));*/
-
- return return_val;
-}
-
-static void
-eti_style_set (ETableItem *eti, GtkStyle *previous_style)
-{
- if (!(GTK_OBJECT_FLAGS(eti) & GNOME_CANVAS_ITEM_REALIZED))
- return;
-
- if (eti->cell_views_realized) {
- int i;
- int n_cells = eti->n_cells;
-
- for (i = 0; i < n_cells; i++) {
- e_cell_style_set (eti->cell_views[i], previous_style);
- }
- }
-
- eti->needs_compute_height = 1;
- e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (eti));
- eti->needs_redraw = 1;
- gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (eti));
-
- free_height_cache (eti);
-
- eti_idle_maybe_show_cursor(eti);
-}
-
-static void
-eti_class_init (GObjectClass *object_class)
-{
- GnomeCanvasItemClass *item_class = (GnomeCanvasItemClass *) object_class;
- ETableItemClass *eti_class = (ETableItemClass *) object_class;
-
- eti_parent_class = g_type_class_ref (PARENT_OBJECT_TYPE);
-
- object_class->dispose = eti_dispose;
- object_class->set_property = eti_set_property;
- object_class->get_property = eti_get_property;
-
- item_class->update = eti_update;
- item_class->realize = eti_realize;
- item_class->unrealize = eti_unrealize;
- item_class->draw = eti_draw;
- item_class->point = eti_point;
- item_class->event = eti_event;
-
- eti_class->cursor_change = NULL;
- eti_class->cursor_activated = NULL;
- eti_class->double_click = NULL;
- eti_class->right_click = NULL;
- eti_class->click = NULL;
- eti_class->key_press = NULL;
- eti_class->start_drag = NULL;
- eti_class->style_set = eti_style_set;
- eti_class->selection_model_removed = NULL;
- eti_class->selection_model_added = NULL;
-
- g_object_class_install_property (object_class, PROP_TABLE_HEADER,
- g_param_spec_object ("ETableHeader",
- _( "Table header" ),
- _( "Table header" ),
- E_TABLE_HEADER_TYPE,
- G_PARAM_WRITABLE));
-
- g_object_class_install_property (object_class, PROP_TABLE_MODEL,
- g_param_spec_object ("ETableModel",
- _( "Table model" ),
- _( "Table model" ),
- E_TABLE_MODEL_TYPE,
- G_PARAM_WRITABLE));
-
- g_object_class_install_property (object_class, PROP_SELECTION_MODEL,
- g_param_spec_object ("selection_model",
- _( "Selection model" ),
- _( "Selection model" ),
- E_SELECTION_MODEL_TYPE,
- G_PARAM_WRITABLE));
-
- g_object_class_install_property (object_class, PROP_TABLE_ALTERNATING_ROW_COLORS,
- g_param_spec_boolean ("alternating_row_colors",
- _( "Alternating Row Colors" ),
- _( "Alternating Row Colors" ),
- FALSE,
- G_PARAM_WRITABLE));
-
- g_object_class_install_property (object_class, PROP_TABLE_HORIZONTAL_DRAW_GRID,
- g_param_spec_boolean ("horizontal_draw_grid",
- _( "Horizontal Draw Grid" ),
- _( "Horizontal Draw Grid" ),
- FALSE,
- G_PARAM_WRITABLE));
-
- g_object_class_install_property (object_class, PROP_TABLE_VERTICAL_DRAW_GRID,
- g_param_spec_boolean ("vertical_draw_grid",
- _( "Vertical Draw Grid" ),
- _( "Vertical Draw Grid" ),
- FALSE,
- G_PARAM_WRITABLE));
-
- g_object_class_install_property (object_class, PROP_TABLE_DRAW_FOCUS,
- g_param_spec_boolean ("drawfocus",
- _( "Draw focus" ),
- _( "Draw focus" ),
- FALSE,
- G_PARAM_WRITABLE));
-
- g_object_class_install_property (object_class, PROP_CURSOR_MODE,
- g_param_spec_int ("cursor_mode",
- _( "Cursor mode" ),
- _( "Cursor mode" ),
- E_CURSOR_LINE, E_CURSOR_SPREADSHEET, E_CURSOR_LINE,
- G_PARAM_WRITABLE));
-
- g_object_class_install_property (object_class, PROP_LENGTH_THRESHOLD,
- g_param_spec_int ("length_threshold",
- _( "Length Threshold" ),
- _( "Length Threshold" ),
- -1, G_MAXINT, 0,
- G_PARAM_WRITABLE));
-
- 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_READWRITE));
- g_object_class_install_property (object_class, PROP_HEIGHT,
- g_param_spec_double ("height",
- _( "Height" ),
- _( "Height" ),
- 0.0, G_MAXDOUBLE, 0.0,
- G_PARAM_READABLE));
-
- g_object_class_install_property (object_class, PROP_CURSOR_ROW,
- g_param_spec_int ("cursor_row",
- _( "Cursor row" ),
- _( "Cursor row" ),
- 0, G_MAXINT, 0,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class, PROP_UNIFORM_ROW_HEIGHT,
- g_param_spec_boolean ("uniform_row_height",
- _( "Uniform row height" ),
- _( "Uniform row height" ),
- FALSE,
- G_PARAM_READWRITE));
-
- eti_signals [CURSOR_CHANGE] =
- g_signal_new ("cursor_change",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableItemClass, cursor_change),
- NULL, NULL,
- e_marshal_NONE__INT,
- G_TYPE_NONE, 1, G_TYPE_INT);
-
- eti_signals [CURSOR_ACTIVATED] =
- g_signal_new ("cursor_activated",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableItemClass, cursor_activated),
- NULL, NULL,
- e_marshal_NONE__INT,
- G_TYPE_NONE, 1, G_TYPE_INT);
-
- eti_signals [DOUBLE_CLICK] =
- g_signal_new ("double_click",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableItemClass, double_click),
- NULL, NULL,
- e_marshal_NONE__INT_INT_BOXED,
- G_TYPE_NONE, 3, G_TYPE_INT,
- G_TYPE_INT, GDK_TYPE_EVENT);
-
- eti_signals [START_DRAG] =
- g_signal_new ("start_drag",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableItemClass, start_drag),
- NULL, NULL,
- e_marshal_INT__INT_INT_BOXED,
- G_TYPE_INT, 3, G_TYPE_INT,
- G_TYPE_INT, GDK_TYPE_EVENT);
-
- eti_signals [RIGHT_CLICK] =
- g_signal_new ("right_click",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableItemClass, right_click),
- NULL, NULL,
- e_marshal_INT__INT_INT_BOXED,
- G_TYPE_INT, 3, G_TYPE_INT,
- G_TYPE_INT, GDK_TYPE_EVENT);
-
- eti_signals [CLICK] =
- g_signal_new ("click",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableItemClass, click),
- NULL, NULL,
- e_marshal_INT__INT_INT_BOXED,
- G_TYPE_INT, 3, G_TYPE_INT,
- G_TYPE_INT, GDK_TYPE_EVENT);
-
- eti_signals [KEY_PRESS] =
- g_signal_new ("key_press",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableItemClass, key_press),
- NULL, NULL,
- e_marshal_INT__INT_INT_BOXED,
- G_TYPE_INT, 3, G_TYPE_INT,
- G_TYPE_INT, GDK_TYPE_EVENT);
-
- eti_signals [STYLE_SET] =
- g_signal_new ("style_set",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableItemClass, style_set),
- NULL, NULL,
- e_marshal_NONE__OBJECT,
- G_TYPE_NONE, 1, GTK_TYPE_STYLE);
-
- eti_signals[SELECTION_MODEL_REMOVED] =
- g_signal_new ("selection_model_removed",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
- G_STRUCT_OFFSET (ETableItemClass, selection_model_removed),
- NULL, NULL,
- g_cclosure_marshal_VOID__POINTER,
- G_TYPE_NONE, 1,
- G_TYPE_POINTER);
-
- eti_signals[SELECTION_MODEL_ADDED] =
- g_signal_new ("selection_model_added",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
- G_STRUCT_OFFSET (ETableItemClass, selection_model_added),
- NULL, NULL,
- g_cclosure_marshal_VOID__POINTER,
- G_TYPE_NONE, 1,
- G_TYPE_POINTER);
-
- /* A11y Init */
- gal_a11y_e_table_item_init ();
-}
-
-E_MAKE_TYPE (e_table_item,
- "ETableItem",
- ETableItem,
- eti_class_init,
- eti_init,
- PARENT_OBJECT_TYPE)
-
-/**
- * e_table_item_set_cursor:
- * @eti: %ETableItem which will have the cursor set.
- * @col: Column to select. -1 means the last column.
- * @row: Row to select. -1 means the last row.
- *
- * This routine sets the cursor of the %ETableItem canvas item.
- */
-void
-e_table_item_set_cursor (ETableItem *eti, int col, int row)
-{
- e_table_item_focus(eti, col, view_to_model_row(eti, row), 0);
-}
-
-static void
-e_table_item_focus (ETableItem *eti, int col, int row, GdkModifierType state)
-{
- g_return_if_fail (eti != NULL);
- g_return_if_fail (E_IS_TABLE_ITEM (eti));
-
- if (row == -1) {
- row = view_to_model_row(eti, eti->rows - 1);
- }
-
- if (col == -1) {
- col = eti->cols - 1;
- }
-
- if (row != -1) {
- e_selection_model_do_something(E_SELECTION_MODEL (eti->selection),
- row, col,
- state);
- }
-}
-
-/**
- * e_table_item_get_focused_column:
- * @eti: %ETableItem which will have the cursor retrieved.
- *
- * This routine gets the cursor of the %ETableItem canvas item.
- *
- * Returns: The current cursor column.
- */
-gint
-e_table_item_get_focused_column (ETableItem *eti)
-{
- int cursor_col;
-
- g_return_val_if_fail (eti != NULL, -1);
- g_return_val_if_fail (E_IS_TABLE_ITEM (eti), -1);
-
- g_object_get(eti->selection,
- "cursor_col", &cursor_col,
- NULL);
-
- return cursor_col;
-}
-
-static void
-eti_cursor_change (ESelectionModel *selection, int row, int col, ETableItem *eti)
-{
- int view_row;
- int view_col;
-
- if (!(GTK_OBJECT_FLAGS(eti) & GNOME_CANVAS_ITEM_REALIZED))
- return;
-
- view_row = model_to_view_row(eti, row);
- view_col = model_to_view_col(eti, col);
-
- if (eti->old_cursor_row != -1 && view_row != eti->old_cursor_row)
- e_table_item_redraw_row (eti, eti->old_cursor_row);
-
- if (view_row == -1) {
- e_table_item_leave_edit_(eti);
- eti->old_cursor_row = -1;
- return;
- }
-
- if (! e_table_model_has_change_pending (eti->table_model)) {
- if (!eti->in_key_press) {
- eti_maybe_show_cursor(eti, DOUBLE_CLICK_TIME + 10);
- } else {
- eti_maybe_show_cursor(eti, 0);
- }
- }
-
- e_canvas_item_grab_focus(GNOME_CANVAS_ITEM(eti), FALSE);
- if (eti_editing(eti))
- e_table_item_leave_edit_(eti);
- g_signal_emit (eti, eti_signals [CURSOR_CHANGE], 0,
- view_row);
-
- e_table_item_redraw_row (eti, view_row);
-
- eti->old_cursor_row = view_row;
-}
-
-static void
-eti_cursor_activated (ESelectionModel *selection, int row, int col, ETableItem *eti)
-{
- int view_row;
- int view_col;
-
- if (!(GTK_OBJECT_FLAGS(eti) & GNOME_CANVAS_ITEM_REALIZED))
- return;
-
- view_row = model_to_view_row(eti, row);
- view_col = model_to_view_col(eti, col);
-
- if (view_row != -1 && view_col != -1) {
- if (! e_table_model_has_change_pending (eti->table_model)) {
- if (!eti->in_key_press) {
- eti_show_cursor(eti, DOUBLE_CLICK_TIME + 10);
- } else {
- eti_show_cursor(eti, 0);
- }
- eti_check_cursor_bounds (eti);
- }
- }
-
- if (eti_editing(eti))
- e_table_item_leave_edit_(eti);
-
- if (view_row != -1)
- g_signal_emit (eti, eti_signals [CURSOR_ACTIVATED], 0,
- view_row);
-}
-
-static void
-eti_selection_change (ESelectionModel *selection, ETableItem *eti)
-{
- if (!(GTK_OBJECT_FLAGS(eti) & GNOME_CANVAS_ITEM_REALIZED))
- return;
-
- eti->needs_redraw = TRUE;
- gnome_canvas_item_request_update(GNOME_CANVAS_ITEM(eti));
-}
-
-static void
-eti_selection_row_change (ESelectionModel *selection, int row, ETableItem *eti)
-{
- if (!(GTK_OBJECT_FLAGS(eti) & GNOME_CANVAS_ITEM_REALIZED))
- return;
-
- if (!eti->needs_redraw) {
- e_table_item_redraw_row (eti, model_to_view_row(eti, row));
- }
-}
-
-
-/**
- * e_table_item_enter_edit
- * @eti: %ETableItem which will start being edited
- * @col: The view col to edit.
- * @row: The view row to edit.
- *
- * This routine starts the given %ETableItem editing at the given view
- * column and row.
- */
-void
-e_table_item_enter_edit (ETableItem *eti, int col, int row)
-{
- g_return_if_fail (eti != NULL);
- g_return_if_fail (E_IS_TABLE_ITEM (eti));
-
- d(g_print("%s: %d, %d, eti_editing() = %s\n", __FUNCTION__, col, row, eti_editing(eti)?"true":"false"));
-
- if (eti_editing (eti))
- e_table_item_leave_edit_(eti);
-
- eti->editing_col = col;
- eti->editing_row = row;
-
- eti->edit_ctx = e_cell_enter_edit (eti->cell_views [col], view_to_model_col(eti, col), col, row);
-}
-
-/**
- * e_table_item_leave_edit_
- * @eti: %ETableItem which will stop being edited
- *
- * This routine stops the given %ETableItem from editing.
- */
-void
-e_table_item_leave_edit (ETableItem *eti)
-{
- int col, row;
- void *edit_ctx;
-
- g_return_if_fail (eti != NULL);
- g_return_if_fail (E_IS_TABLE_ITEM (eti));
-
- d(g_print("%s: eti_editing() = %s\n", __FUNCTION__, eti_editing(eti)?"true":"false"));
-
- if (!eti_editing (eti))
- return;
-
- col = eti->editing_col;
- row = eti->editing_row;
- edit_ctx = eti->edit_ctx;
-
- eti->editing_col = -1;
- eti->editing_row = -1;
- eti->edit_ctx = NULL;
-
- e_cell_leave_edit (eti->cell_views [col],
- view_to_model_col(eti, col),
- col, row, edit_ctx);
-}
-
-/**
- * e_table_item_compute_location
- * @eti: %ETableItem to look in.
- * @x: A pointer to the x location to find in the %ETableItem.
- * @y: A pointer to the y location to find in the %ETableItem.
- * @row: A pointer to the location to store the found row in.
- * @col: A pointer to the location to store the found col in.
- *
- * This routine locates the pixel location (*x, *y) in the
- * %ETableItem. If that location is in the %ETableItem, *row and *col
- * are set to the view row and column where it was found. If that
- * location is not in the %ETableItem, the height of the %ETableItem
- * is removed from the value y points to.
- */
-void
-e_table_item_compute_location (ETableItem *eti,
- int *x,
- int *y,
- int *row,
- int *col)
-{
- /* Save the grabbed row but make sure that we don't get flawed
- results because the cursor is grabbed. */
- int grabbed_row = eti->grabbed_row;
- eti->grabbed_row = -1;
-
- if (!find_cell (eti, *x, *y, col, row, NULL, NULL)) {
- *y -= eti->height;
- }
-
- eti->grabbed_row = grabbed_row;
-}
-
-void
-e_table_item_get_cell_geometry (ETableItem *eti,
- int *row,
- int *col,
- int *x,
- int *y,
- int *width,
- int *height)
-{
- if (eti->rows > *row) {
- if (x)
- *x = e_table_header_col_diff (eti->header, 0, *col);
- if (y)
- *y = e_table_item_row_diff (eti, 0, *row);
- if (width)
- *width = e_table_header_col_diff (eti->header, *col, *col + 1);
- if (height)
- *height = ETI_ROW_HEIGHT (eti, *row);
- *row = -1;
- *col = -1;
- } else {
- *row -= eti->rows;
- }
-}
-
-typedef struct {
- ETableItem *item;
- int rows_printed;
-} ETableItemPrintContext;
-
-static gdouble *
-e_table_item_calculate_print_widths (ETableHeader *eth, gdouble width)
-{
- int i;
- double extra;
- double expansion;
- int last_resizable = -1;
- gdouble scale = 1.0L;
- gdouble *widths = g_new(gdouble, e_table_header_count(eth));
- /* - 1 to account for the last pixel border. */
- extra = width - 1;
- expansion = 0;
- for (i = 0; i < eth->col_count; i++) {
- extra -= eth->columns[i]->min_width * scale;
- if (eth->columns[i]->resizable && eth->columns[i]->expansion > 0)
- last_resizable = i;
- expansion += eth->columns[i]->resizable ? eth->columns[i]->expansion : 0;
- widths[i] = eth->columns[i]->min_width * scale;
- }
- for (i = 0; i <= last_resizable; i++) {
- widths[i] += extra * (eth->columns[i]->resizable ? eth->columns[i]->expansion : 0)/expansion;
- }
-
- return widths;
-}
-
-static gdouble
-eti_printed_row_height (ETableItem *eti, gdouble *widths, GnomePrintContext *context, gint row)
-{
- int col;
- int cols = eti->cols;
- gdouble height = 0;
- for (col = 0; col < cols; col++) {
- ECellView *ecell_view = eti->cell_views [col];
- gdouble this_height = e_cell_print_height (ecell_view, context, view_to_model_col(eti, col), col, row,
- widths[col] - 1);
- if (this_height > height)
- height = this_height;
- }
- return height;
-}
-
-#define CHECK(x) if((x) == -1) return -1;
-
-static gint
-gp_draw_rect (GnomePrintContext *context, gdouble x, gdouble y, gdouble width, gdouble height)
-{
- CHECK(gnome_print_moveto(context, x, y));
- CHECK(gnome_print_lineto(context, x + width, y));
- CHECK(gnome_print_lineto(context, x + width, y - height));
- CHECK(gnome_print_lineto(context, x, y - height));
- CHECK(gnome_print_lineto(context, x, y));
- return gnome_print_fill(context);
-}
-
-static void
-e_table_item_print_page (EPrintable *ep,
- GnomePrintContext *context,
- gdouble width,
- gdouble height,
- gboolean quantize,
- ETableItemPrintContext *itemcontext)
-{
- ETableItem *eti = itemcontext->item;
- const int rows = eti->rows;
- const int cols = eti->cols;
- int rows_printed = itemcontext->rows_printed;
- gdouble *widths;
- int row, col;
- gdouble yd = height;
-
- widths = e_table_item_calculate_print_widths (itemcontext->item->header, width);
-
- /*
- * Draw cells
- */
- if (eti->horizontal_draw_grid){
- gp_draw_rect(context, 0, yd, width, 1);
- }
- yd--;
-
- for (row = rows_printed; row < rows; row++){
- gdouble xd = 1, row_height;
-
- row_height = eti_printed_row_height(eti, widths, context, row);
- if (quantize) {
- if (yd - row_height - 1 < 0 && row != rows_printed) {
- break;
- }
- } else {
- if (yd < 0) {
- break;
- }
- }
-
- for (col = 0; col < cols; col++){
- ECellView *ecell_view = eti->cell_views [col];
-
- if (gnome_print_gsave(context) == -1)
- /* FIXME */;
- if (gnome_print_translate(context, xd, yd - row_height) == -1)
- /* FIXME */;
-
- if (gnome_print_moveto(context, 0, 0) == -1)
- /* FIXME */;
- if (gnome_print_lineto(context, widths[col] - 1, 0) == -1)
- /* FIXME */;
- if (gnome_print_lineto(context, widths[col] - 1, row_height) == -1)
- /* FIXME */;
- if (gnome_print_lineto(context, 0, row_height) == -1)
- /* FIXME */;
- if (gnome_print_lineto(context, 0, 0) == -1)
- /* FIXME */;
- if (gnome_print_clip(context) == -1)
- /* FIXME */;
-
- e_cell_print (ecell_view, context, view_to_model_col(eti, col), col, row,
- widths[col] - 1, row_height);
-
- if (gnome_print_grestore(context) == -1)
- /* FIXME */;
-
- xd += widths[col];
- }
- yd -= row_height;
-
- if (eti->horizontal_draw_grid){
- gp_draw_rect(context, 0, yd, width, 1);
- }
- yd--;
- }
-
- itemcontext->rows_printed = row;
-
- if (eti->vertical_draw_grid){
- gdouble xd = 0;
-
- for (col = 0; col < cols; col++){
- gp_draw_rect(context, xd, height, 1, height - yd);
-
- xd += widths[col];
- }
- gp_draw_rect(context, xd, height, 1, height - yd);
- }
-
- g_free (widths);
-}
-
-static gboolean
-e_table_item_data_left (EPrintable *ep,
- ETableItemPrintContext *itemcontext)
-{
- ETableItem *item = itemcontext->item;
- int rows_printed = itemcontext->rows_printed;
-
- g_signal_stop_emission_by_name(ep, "data_left");
- return rows_printed < item->rows;
-}
-
-static void
-e_table_item_reset (EPrintable *ep,
- ETableItemPrintContext *itemcontext)
-{
- itemcontext->rows_printed = 0;
-}
-
-static gdouble
-e_table_item_height (EPrintable *ep,
- GnomePrintContext *context,
- gdouble width,
- gdouble max_height,
- gboolean quantize,
- ETableItemPrintContext *itemcontext)
-{
- ETableItem *item = itemcontext->item;
- const int rows = item->rows;
- int rows_printed = itemcontext->rows_printed;
- gdouble *widths;
- int row;
- gdouble yd = 0;
-
- widths = e_table_item_calculate_print_widths (itemcontext->item->header, width);
-
- /*
- * Draw cells
- */
- yd++;
-
- for (row = rows_printed; row < rows; row++){
- gdouble row_height;
-
- row_height = eti_printed_row_height(item, widths, context, row);
- if (quantize) {
- if (max_height != -1 && yd + row_height + 1 > max_height && row != rows_printed) {
- break;
- }
- } else {
- if (max_height != -1 && yd > max_height) {
- break;
- }
- }
-
- yd += row_height;
-
- yd++;
- }
-
- g_free (widths);
-
- if (max_height != -1 && (!quantize) && yd > max_height)
- yd = max_height;
-
- g_signal_stop_emission_by_name(ep, "height");
- return yd;
-}
-
-static gboolean
-e_table_item_will_fit (EPrintable *ep,
- GnomePrintContext *context,
- gdouble width,
- gdouble max_height,
- gboolean quantize,
- ETableItemPrintContext *itemcontext)
-{
- ETableItem *item = itemcontext->item;
- const int rows = item->rows;
- int rows_printed = itemcontext->rows_printed;
- gdouble *widths;
- int row;
- gdouble yd = 0;
- gboolean ret_val = TRUE;
-
- widths = e_table_item_calculate_print_widths (itemcontext->item->header, width);
-
- /*
- * Draw cells
- */
- yd++;
-
- for (row = rows_printed; row < rows; row++){
- gdouble row_height;
-
- row_height = eti_printed_row_height(item, widths, context, row);
- if (quantize) {
- if (max_height != -1 && yd + row_height + 1 > max_height && row != rows_printed) {
- ret_val = FALSE;
- break;
- }
- } else {
- if (max_height != -1 && yd > max_height) {
- ret_val = FALSE;
- break;
- }
- }
-
- yd += row_height;
-
- yd++;
- }
-
- g_free (widths);
-
- g_signal_stop_emission_by_name(ep, "will_fit");
- return ret_val;
-}
-
-static void
-e_table_item_printable_destroy (gpointer data,
- GObject *where_object_was)
-{
- ETableItemPrintContext *itemcontext = data;
-
- g_object_unref(itemcontext->item);
- g_free(itemcontext);
-}
-
-/**
- * e_table_item_get_printable
- * @eti: %ETableItem which will be printed
- *
- * This routine creates and returns an %EPrintable that can be used to
- * print the given %ETableItem.
- *
- * Returns: The %EPrintable.
- */
-EPrintable *
-e_table_item_get_printable (ETableItem *item)
-{
- EPrintable *printable = e_printable_new();
- ETableItemPrintContext *itemcontext;
-
- itemcontext = g_new(ETableItemPrintContext, 1);
- itemcontext->item = item;
- g_object_ref(item);
- itemcontext->rows_printed = 0;
-
- g_signal_connect (printable,
- "print_page",
- G_CALLBACK(e_table_item_print_page),
- itemcontext);
- g_signal_connect (printable,
- "data_left",
- G_CALLBACK(e_table_item_data_left),
- itemcontext);
- g_signal_connect (printable,
- "reset",
- G_CALLBACK(e_table_item_reset),
- itemcontext);
- g_signal_connect (printable,
- "height",
- G_CALLBACK(e_table_item_height),
- itemcontext);
- g_signal_connect (printable,
- "will_fit",
- G_CALLBACK(e_table_item_will_fit),
- itemcontext);
- g_object_weak_ref (G_OBJECT (printable),
- e_table_item_printable_destroy,
- itemcontext);
-
- return printable;
-}
diff --git a/widgets/table/e-table-item.h b/widgets/table/e-table-item.h
deleted file mode 100644
index e5b5322019..0000000000
--- a/widgets/table/e-table-item.h
+++ /dev/null
@@ -1,231 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-item.h
- * Copyright 1999, 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- * Miguel de Icaza <miguel@gnu.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_TABLE_ITEM_H_
-#define _E_TABLE_ITEM_H_
-
-#include <libgnomecanvas/gnome-canvas.h>
-#include <gal/e-table/e-table-model.h>
-#include <gal/e-table/e-table-header.h>
-#include <gal/e-table/e-table-defines.h>
-#include <gal/e-table/e-table-tooltip.h>
-#include <gal/widgets/e-selection-model.h>
-#include <gal/widgets/e-printable.h>
-
-G_BEGIN_DECLS
-
-#define E_TABLE_ITEM_TYPE (e_table_item_get_type ())
-#define E_TABLE_ITEM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TABLE_ITEM_TYPE, ETableItem))
-#define E_TABLE_ITEM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TABLE_ITEM_TYPE, ETableItemClass))
-#define E_IS_TABLE_ITEM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TABLE_ITEM_TYPE))
-#define E_IS_TABLE_ITEM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TABLE_ITEM_TYPE))
-
-typedef struct {
- GnomeCanvasItem parent;
- ETableModel *table_model;
- ETableHeader *header;
-
- ETableModel *source_model;
- ESelectionModel *selection;
-
- int x1, y1;
- int minimum_width, width, height;
-
- int cols, rows;
-
- int click_count;
-
- /*
- * Ids for the signals we connect to
- */
- int header_dim_change_id;
- int header_structure_change_id;
- int header_request_width_id;
- int table_model_pre_change_id;
- int table_model_no_change_id;
- int table_model_change_id;
- int table_model_row_change_id;
- int table_model_cell_change_id;
- int table_model_rows_inserted_id;
- int table_model_rows_deleted_id;
-
- int selection_change_id;
- int selection_row_change_id;
- int cursor_change_id;
- int cursor_activated_id;
-
- guint cursor_idle_id;
-
- /* View row, -1 means unknown */
- int old_cursor_row;
-
- int hadjustment_change_id;
- int hadjustment_value_change_id;
- int vadjustment_change_id;
- int vadjustment_value_change_id;
-
- GdkGC *fill_gc;
- GdkGC *grid_gc;
- GdkGC *focus_gc;
- GdkBitmap *stipple;
-
- guint alternating_row_colors:1;
- guint horizontal_draw_grid:1;
- guint vertical_draw_grid:1;
- guint draw_focus:1;
- guint uniform_row_height:1;
- guint cell_views_realized:1;
-
- guint needs_redraw : 1;
- guint needs_compute_height : 1;
- guint needs_compute_width : 1;
-
- guint uses_source_model : 1;
-
- guint in_key_press : 1;
-
- guint maybe_in_drag : 1;
- guint in_drag : 1;
- guint grabbed : 1;
-
- guint maybe_did_something : 1;
-
- guint cursor_on_screen : 1;
- guint gtk_grabbed : 1;
-
- guint queue_show_cursor : 1;
- guint grab_cancelled : 1;
-
- int frozen_count;
-
- int cursor_x1;
- int cursor_y1;
- int cursor_x2;
- int cursor_y2;
-
- int drag_col;
- int drag_row;
- int drag_x;
- int drag_y;
- guint drag_state;
-
- /*
- * Realized views, per column
- */
- ECellView **cell_views;
- int n_cells;
-
- int *height_cache;
- int uniform_row_height_cache;
- int height_cache_idle_id;
- int height_cache_idle_count;
-
- /*
- * Lengh Threshold: above this, we stop computing correctly
- * the size
- */
- int length_threshold;
-
- gint row_guess;
- ECursorMode cursor_mode;
-
- int motion_col, motion_row;
-
- /*
- * During editing
- */
- int editing_col, editing_row;
- void *edit_ctx;
-
- int save_col, save_row;
- void *save_state;
-
- int grabbed_col, grabbed_row;
- int grabbed_count;
-
- /*
- * Tooltip
- */
- ETableTooltip *tooltip;
-
-} ETableItem;
-
-typedef struct {
- GnomeCanvasItemClass parent_class;
-
- void (*cursor_change) (ETableItem *eti, int row);
- void (*cursor_activated) (ETableItem *eti, int row);
- void (*double_click) (ETableItem *eti, int row, int col, GdkEvent *event);
- gint (*right_click) (ETableItem *eti, int row, int col, GdkEvent *event);
- gint (*click) (ETableItem *eti, int row, int col, GdkEvent *event);
- gint (*key_press) (ETableItem *eti, int row, int col, GdkEvent *event);
- gint (*start_drag) (ETableItem *eti, int row, int col, GdkEvent *event);
- void (*style_set) (ETableItem *eti, GtkStyle *previous_style);
- void (*selection_model_removed) (ETableItem *eti, ESelectionModel *selection);
- void (*selection_model_added) (ETableItem *eti, ESelectionModel *selection);
-} ETableItemClass;
-GType e_table_item_get_type (void);
-
-
-/*
- * Focus
- */
-void e_table_item_set_cursor (ETableItem *eti,
- int col,
- int row);
-
-gint e_table_item_get_focused_column (ETableItem *eti);
-
-void e_table_item_leave_edit (ETableItem *eti);
-void e_table_item_enter_edit (ETableItem *eti,
- int col,
- int row);
-
-void e_table_item_redraw_range (ETableItem *eti,
- int start_col,
- int start_row,
- int end_col,
- int end_row);
-
-EPrintable *e_table_item_get_printable (ETableItem *eti);
-void e_table_item_compute_location (ETableItem *eti,
- int *x,
- int *y,
- int *row,
- int *col);
-void e_table_item_get_cell_geometry (ETableItem *eti,
- int *row,
- int *col,
- int *x,
- int *y,
- int *width,
- int *height);
-
-int e_table_item_row_diff (ETableItem *eti,
- int start_row,
- int end_row);
-
-G_END_DECLS
-
-#endif /* _E_TABLE_ITEM_H_ */
diff --git a/widgets/table/e-table-memory-callbacks.c b/widgets/table/e-table-memory-callbacks.c
deleted file mode 100644
index 6cd1b9c8a1..0000000000
--- a/widgets/table/e-table-memory-callbacks.c
+++ /dev/null
@@ -1,208 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-memory-callbacks.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include "e-table-memory-callbacks.h"
-#include "gal/util/e-util.h"
-
-static int
-etmc_column_count (ETableModel *etm)
-{
- ETableMemoryCalbacks *etmc = E_TABLE_MEMORY_CALLBACKS(etm);
-
- if (etmc->col_count)
- return etmc->col_count (etm, etmc->data);
- else
- return 0;
-}
-
-static void *
-etmc_value_at (ETableModel *etm, int col, int row)
-{
- ETableMemoryCalbacks *etmc = E_TABLE_MEMORY_CALLBACKS(etm);
-
- if (etmc->value_at)
- return etmc->value_at (etm, col, row, etmc->data);
- else
- return NULL;
-}
-
-static void
-etmc_set_value_at (ETableModel *etm, int col, int row, const void *val)
-{
- ETableMemoryCalbacks *etmc = E_TABLE_MEMORY_CALLBACKS(etm);
-
- if (etmc->set_value_at)
- etmc->set_value_at (etm, col, row, val, etmc->data);
-}
-
-static gboolean
-etmc_is_cell_editable (ETableModel *etm, int col, int row)
-{
- ETableMemoryCalbacks *etmc = E_TABLE_MEMORY_CALLBACKS(etm);
-
- if (etmc->is_cell_editable)
- return etmc->is_cell_editable (etm, col, row, etmc->data);
- else
- return FALSE;
-}
-
-/* The default for etmc_duplicate_value is to return the raw value. */
-static void *
-etmc_duplicate_value (ETableModel *etm, int col, const void *value)
-{
- ETableMemoryCalbacks *etmc = E_TABLE_MEMORY_CALLBACKS(etm);
-
- if (etmc->duplicate_value)
- return etmc->duplicate_value (etm, col, value, etmc->data);
- else
- return (void *)value;
-}
-
-static void
-etmc_free_value (ETableModel *etm, int col, void *value)
-{
- ETableMemoryCalbacks *etmc = E_TABLE_MEMORY_CALLBACKS(etm);
-
- if (etmc->free_value)
- etmc->free_value (etm, col, value, etmc->data);
-}
-
-static void *
-etmc_initialize_value (ETableModel *etm, int col)
-{
- ETableMemoryCalbacks *etmc = E_TABLE_MEMORY_CALLBACKS(etm);
-
- if (etmc->initialize_value)
- return etmc->initialize_value (etm, col, etmc->data);
- else
- return NULL;
-}
-
-static gboolean
-etmc_value_is_empty (ETableModel *etm, int col, const void *value)
-{
- ETableMemoryCalbacks *etmc = E_TABLE_MEMORY_CALLBACKS(etm);
-
- if (etmc->value_is_empty)
- return etmc->value_is_empty (etm, col, value, etmc->data);
- else
- return FALSE;
-}
-
-static char *
-etmc_value_to_string (ETableModel *etm, int col, const void *value)
-{
- ETableMemoryCalbacks *etmc = E_TABLE_MEMORY_CALLBACKS(etm);
-
- if (etmc->value_to_string)
- return etmc->value_to_string (etm, col, value, etmc->data);
- else
- return g_strdup ("");
-}
-
-static void
-etmc_append_row (ETableModel *etm, ETableModel *source, int row)
-{
- ETableMemoryCalbacks *etmc = E_TABLE_MEMORY_CALLBACKS(etm);
-
- if (etmc->append_row)
- etmc->append_row (etm, source, row, etmc->data);
-}
-
-static void
-e_table_memory_callbacks_class_init (GObjectClass *object_class)
-{
- ETableModelClass *model_class = (ETableModelClass *) object_class;
-
- model_class->column_count = etmc_column_count;
- model_class->value_at = etmc_value_at;
- model_class->set_value_at = etmc_set_value_at;
- model_class->is_cell_editable = etmc_is_cell_editable;
- model_class->duplicate_value = etmc_duplicate_value;
- model_class->free_value = etmc_free_value;
- model_class->initialize_value = etmc_initialize_value;
- model_class->value_is_empty = etmc_value_is_empty;
- model_class->value_to_string = etmc_value_to_string;
- model_class->append_row = etmc_append_row;
-
-}
-
-E_MAKE_TYPE(e_table_memory_callbacks, "ETableMemoryCalbacks", ETableMemoryCalbacks, e_table_memory_callbacks_class_init, NULL, E_TABLE_MEMORY_TYPE)
-
-
-/**
- * e_table_memory_callbacks_new:
- * @col_count:
- * @value_at:
- * @set_value_at:
- * @is_cell_editable:
- * @duplicate_value:
- * @free_value:
- * @initialize_value:
- * @value_is_empty:
- * @value_to_string:
- * @data: closure pointer.
- *
- * This initializes a new ETableMemoryCalbacksModel object. ETableMemoryCalbacksModel is
- * an implementaiton of the abstract class ETableModel. The ETableMemoryCalbacksModel
- * is designed to allow people to easily create ETableModels without having
- * to create a new GtkType derived from ETableModel every time they need one.
- *
- * Instead, ETableMemoryCalbacksModel uses a setup based in callback functions, every
- * callback function signature mimics the signature of each ETableModel method
- * and passes the extra @data pointer to each one of the method to provide them
- * with any context they might want to use.
- *
- * Returns: An ETableMemoryCalbacksModel object (which is also an ETableModel
- * object).
- */
-ETableModel *
-e_table_memory_callbacks_new (ETableMemoryCalbacksColumnCountFn col_count,
- ETableMemoryCalbacksValueAtFn value_at,
- ETableMemoryCalbacksSetValueAtFn set_value_at,
- ETableMemoryCalbacksIsCellEditableFn is_cell_editable,
- ETableMemoryCalbacksDuplicateValueFn duplicate_value,
- ETableMemoryCalbacksFreeValueFn free_value,
- ETableMemoryCalbacksInitializeValueFn initialize_value,
- ETableMemoryCalbacksValueIsEmptyFn value_is_empty,
- ETableMemoryCalbacksValueToStringFn value_to_string,
- void *data)
-{
- ETableMemoryCalbacks *et;
-
- et = g_object_new (E_TABLE_MEMORY_CALLBACKS_TYPE, NULL);
-
- et->col_count = col_count;
- et->value_at = value_at;
- et->set_value_at = set_value_at;
- et->is_cell_editable = is_cell_editable;
- et->duplicate_value = duplicate_value;
- et->free_value = free_value;
- et->initialize_value = initialize_value;
- et->value_is_empty = value_is_empty;
- et->value_to_string = value_to_string;
- et->data = data;
-
- return (ETableModel *) et;
- }
diff --git a/widgets/table/e-table-memory-callbacks.h b/widgets/table/e-table-memory-callbacks.h
deleted file mode 100644
index 599ffa01f3..0000000000
--- a/widgets/table/e-table-memory-callbacks.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-memory-callbacks.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_TABLE_MEMORY_CALLBACKS_H_
-#define _E_TABLE_MEMORY_CALLBACKS_H_
-
-#include <gal/e-table/e-table-memory.h>
-
-G_BEGIN_DECLS
-
-#define E_TABLE_MEMORY_CALLBACKS_TYPE (e_table_memory_callbacks_get_type ())
-#define E_TABLE_MEMORY_CALLBACKS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TABLE_MEMORY_CALLBACKS_TYPE, ETableMemoryCalbacks))
-#define E_TABLE_MEMORY_CALLBACKS_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TABLE_MEMORY_CALLBACKS_TYPE, ETableMemoryCalbacksClass))
-#define E_IS_TABLE_MEMORY_CALLBACKS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TABLE_MEMORY_CALLBACKS_TYPE))
-#define E_IS_TABLE_MEMORY_CALLBACKS_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TABLE_MEMORY_CALLBACKS_TYPE))
-#define E_TABLE_MEMORY_CALLBACKS_GET_CLASS(k) (G_TYPE_INSTANCE_GET_CLASS((k), E_TABLE_MEMORY_CALLBACKS_TYPE, ETableMemoryCalbacksClass))
-
-typedef int (*ETableMemoryCalbacksColumnCountFn) (ETableModel *etm, void *data);
-typedef void (*ETableMemoryCalbacksAppendRowFn) (ETableModel *etm, ETableModel *model, int row, void *data);
-
-typedef void *(*ETableMemoryCalbacksValueAtFn) (ETableModel *etm, int col, int row, void *data);
-typedef void (*ETableMemoryCalbacksSetValueAtFn) (ETableModel *etm, int col, int row, const void *val, void *data);
-typedef gboolean (*ETableMemoryCalbacksIsCellEditableFn) (ETableModel *etm, int col, int row, void *data);
-
-typedef void *(*ETableMemoryCalbacksDuplicateValueFn) (ETableModel *etm, int col, const void *val, void *data);
-typedef void (*ETableMemoryCalbacksFreeValueFn) (ETableModel *etm, int col, void *val, void *data);
-typedef void *(*ETableMemoryCalbacksInitializeValueFn) (ETableModel *etm, int col, void *data);
-typedef gboolean (*ETableMemoryCalbacksValueIsEmptyFn) (ETableModel *etm, int col, const void *val, void *data);
-typedef char *(*ETableMemoryCalbacksValueToStringFn) (ETableModel *etm, int col, const void *val, void *data);
-
-typedef struct {
- ETableMemory parent;
-
- ETableMemoryCalbacksColumnCountFn col_count;
- ETableMemoryCalbacksAppendRowFn append_row;
-
- ETableMemoryCalbacksValueAtFn value_at;
- ETableMemoryCalbacksSetValueAtFn set_value_at;
- ETableMemoryCalbacksIsCellEditableFn is_cell_editable;
-
- ETableMemoryCalbacksDuplicateValueFn duplicate_value;
- ETableMemoryCalbacksFreeValueFn free_value;
- ETableMemoryCalbacksInitializeValueFn initialize_value;
- ETableMemoryCalbacksValueIsEmptyFn value_is_empty;
- ETableMemoryCalbacksValueToStringFn value_to_string;
- void *data;
-} ETableMemoryCalbacks;
-
-typedef struct {
- ETableMemoryClass parent_class;
-} ETableMemoryCalbacksClass;
-
-GType e_table_memory_callbacks_get_type (void);
-
-ETableModel *e_table_memory_callbacks_new (ETableMemoryCalbacksColumnCountFn col_count,
-
- ETableMemoryCalbacksValueAtFn value_at,
- ETableMemoryCalbacksSetValueAtFn set_value_at,
- ETableMemoryCalbacksIsCellEditableFn is_cell_editable,
-
- ETableMemoryCalbacksDuplicateValueFn duplicate_value,
- ETableMemoryCalbacksFreeValueFn free_value,
- ETableMemoryCalbacksInitializeValueFn initialize_value,
- ETableMemoryCalbacksValueIsEmptyFn value_is_empty,
- ETableMemoryCalbacksValueToStringFn value_to_string,
- void *data);
-
-G_END_DECLS
-
-#endif /* _E_TABLE_MEMORY_CALLBACKS_H_ */
-
diff --git a/widgets/table/e-table-memory-store.c b/widgets/table/e-table-memory-store.c
deleted file mode 100644
index 69765b32ab..0000000000
--- a/widgets/table/e-table-memory-store.c
+++ /dev/null
@@ -1,583 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-memory-store.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <string.h>
-#include "e-table-memory-store.h"
-#include "gal/util/e-util.h"
-
-#define STORE_LOCATOR(etms, col, row) (*((etms)->priv->store + (row) * (etms)->priv->col_count + (col)))
-
-static ETableMemoryClass *parent_class;
-
-struct _ETableMemoryStorePrivate {
- int col_count;
- ETableMemoryStoreColumnInfo *columns;
- void **store;
-};
-
-static void *
-duplicate_value (ETableMemoryStore *etms, int col, const void *val)
-{
- switch (etms->priv->columns[col].type) {
- case E_TABLE_MEMORY_STORE_COLUMN_TYPE_STRING:
- return g_strdup (val);
- case E_TABLE_MEMORY_STORE_COLUMN_TYPE_PIXBUF:
- if (val)
- gdk_pixbuf_ref ((void *) val);
- return (void *) val;
- case E_TABLE_MEMORY_STORE_COLUMN_TYPE_OBJECT:
- if (val)
- g_object_ref ((void *) val);
- return (void *) val;
- case E_TABLE_MEMORY_STORE_COLUMN_TYPE_CUSTOM:
- if (etms->priv->columns[col].custom.duplicate_value)
- return etms->priv->columns[col].custom.duplicate_value (E_TABLE_MODEL (etms), col, val, NULL);
- break;
- default:
- break;
- }
- return (void *) val;
-}
-
-static void
-free_value (ETableMemoryStore *etms, int col, void *value)
-{
- switch (etms->priv->columns[col].type) {
- case E_TABLE_MEMORY_STORE_COLUMN_TYPE_STRING:
- g_free (value);
- break;
- case E_TABLE_MEMORY_STORE_COLUMN_TYPE_PIXBUF:
- if (value)
- gdk_pixbuf_unref (value);
- break;
- case E_TABLE_MEMORY_STORE_COLUMN_TYPE_OBJECT:
- if (value)
- g_object_unref (value);
- break;
- case E_TABLE_MEMORY_STORE_COLUMN_TYPE_CUSTOM:
- if (etms->priv->columns[col].custom.free_value)
- etms->priv->columns[col].custom.free_value (E_TABLE_MODEL (etms), col, value, NULL);
- break;
- default:
- break;
- }
-}
-
-
-static int
-etms_column_count (ETableModel *etm)
-{
- ETableMemoryStore *etms = E_TABLE_MEMORY_STORE(etm);
-
- return etms->priv->col_count;
-}
-
-static void *
-etms_value_at (ETableModel *etm, int col, int row)
-{
- ETableMemoryStore *etms = E_TABLE_MEMORY_STORE(etm);
-
- return STORE_LOCATOR (etms, col, row);
-}
-
-static void
-etms_set_value_at (ETableModel *etm, int col, int row, const void *val)
-{
- ETableMemoryStore *etms = E_TABLE_MEMORY_STORE(etm);
-
- e_table_model_pre_change (etm);
-
- STORE_LOCATOR (etms, col, row) = duplicate_value (etms, col, val);
-
- e_table_model_cell_changed (etm, col, row);
-}
-
-static gboolean
-etms_is_cell_editable (ETableModel *etm, int col, int row)
-{
- ETableMemoryStore *etms = E_TABLE_MEMORY_STORE(etm);
-
- return etms->priv->columns[col].editable;
-}
-
-/* The default for etms_duplicate_value is to return the raw value. */
-static void *
-etms_duplicate_value (ETableModel *etm, int col, const void *value)
-{
- ETableMemoryStore *etms = E_TABLE_MEMORY_STORE(etm);
-
- return duplicate_value (etms, col, value);
-}
-
-static void
-etms_free_value (ETableModel *etm, int col, void *value)
-{
- ETableMemoryStore *etms = E_TABLE_MEMORY_STORE(etm);
-
- free_value (etms, col, value);
-}
-
-static void *
-etms_initialize_value (ETableModel *etm, int col)
-{
- ETableMemoryStore *etms = E_TABLE_MEMORY_STORE(etm);
-
- switch (etms->priv->columns[col].type) {
- case E_TABLE_MEMORY_STORE_COLUMN_TYPE_STRING:
- return g_strdup ("");
- case E_TABLE_MEMORY_STORE_COLUMN_TYPE_PIXBUF:
- return NULL;
- case E_TABLE_MEMORY_STORE_COLUMN_TYPE_CUSTOM:
- case E_TABLE_MEMORY_STORE_COLUMN_TYPE_OBJECT:
- if (etms->priv->columns[col].custom.initialize_value)
- return etms->priv->columns[col].custom.initialize_value (E_TABLE_MODEL (etms), col, NULL);
- break;
- default:
- break;
- }
- return 0;
-}
-
-static gboolean
-etms_value_is_empty (ETableModel *etm, int col, const void *value)
-{
- ETableMemoryStore *etms = E_TABLE_MEMORY_STORE(etm);
-
- switch (etms->priv->columns[col].type) {
- case E_TABLE_MEMORY_STORE_COLUMN_TYPE_STRING:
- return !(value && *(char *) value);
- case E_TABLE_MEMORY_STORE_COLUMN_TYPE_PIXBUF:
- return value == NULL;
- case E_TABLE_MEMORY_STORE_COLUMN_TYPE_CUSTOM:
- case E_TABLE_MEMORY_STORE_COLUMN_TYPE_OBJECT:
- if (etms->priv->columns[col].custom.value_is_empty)
- return etms->priv->columns[col].custom.value_is_empty (E_TABLE_MODEL (etms), col, value, NULL);
- break;
- default:
- break;
- }
- return value == 0;
-}
-
-static char *
-etms_value_to_string (ETableModel *etm, int col, const void *value)
-{
- ETableMemoryStore *etms = E_TABLE_MEMORY_STORE(etm);
-
- switch (etms->priv->columns[col].type) {
- case E_TABLE_MEMORY_STORE_COLUMN_TYPE_STRING:
- return g_strdup (value);
- case E_TABLE_MEMORY_STORE_COLUMN_TYPE_PIXBUF:
- return g_strdup ("");
- case E_TABLE_MEMORY_STORE_COLUMN_TYPE_CUSTOM:
- case E_TABLE_MEMORY_STORE_COLUMN_TYPE_OBJECT:
- if (etms->priv->columns[col].custom.value_is_empty)
- return etms->priv->columns[col].custom.value_to_string (E_TABLE_MODEL (etms), col, value, NULL);
- break;
- default:
- break;
- }
- return g_strdup_printf ("%d", GPOINTER_TO_INT (value));
-}
-
-static void
-etms_append_row (ETableModel *etm, ETableModel *source, int row)
-{
- ETableMemoryStore *etms = E_TABLE_MEMORY_STORE(etm);
- void **new_data;
- int i;
- int row_count;
-
- new_data = g_new (void *, etms->priv->col_count);
-
- for (i = 0; i < etms->priv->col_count; i++) {
- new_data[i] = e_table_model_value_at (source, i, row);
- }
-
- row_count = e_table_model_row_count (E_TABLE_MODEL (etms));
-
- e_table_memory_store_insert_array (etms, row_count, new_data, NULL);
-}
-
-static void
-etms_finalize (GObject *obj)
-{
- ETableMemoryStore *etms = (ETableMemoryStore *) obj;
-
- if (etms->priv) {
- e_table_memory_store_clear (etms);
-
- g_free (etms->priv->columns);
- g_free (etms->priv->store);
- g_free (etms->priv);
- }
-
- if (G_OBJECT_CLASS (parent_class)->finalize)
- G_OBJECT_CLASS (parent_class)->finalize (obj);
-}
-
-static void
-e_table_memory_store_init (ETableMemoryStore *etms)
-{
- etms->priv = g_new (ETableMemoryStorePrivate, 1);
-
- etms->priv->col_count = 0;
- etms->priv->columns = NULL;
- etms->priv->store = NULL;
-}
-
-static void
-e_table_memory_store_class_init (GObjectClass *object_class)
-{
- ETableModelClass *model_class = (ETableModelClass *) object_class;
-
- parent_class = g_type_class_peek_parent (object_class);
-
- object_class->finalize = etms_finalize;
-
- model_class->column_count = etms_column_count;
- model_class->value_at = etms_value_at;
- model_class->set_value_at = etms_set_value_at;
- model_class->is_cell_editable = etms_is_cell_editable;
- model_class->duplicate_value = etms_duplicate_value;
- model_class->free_value = etms_free_value;
- model_class->initialize_value = etms_initialize_value;
- model_class->value_is_empty = etms_value_is_empty;
- model_class->value_to_string = etms_value_to_string;
- model_class->append_row = etms_append_row;
-}
-
-E_MAKE_TYPE(e_table_memory_store, "ETableMemoryStore", ETableMemoryStore, e_table_memory_store_class_init, e_table_memory_store_init, E_TABLE_MEMORY_TYPE)
-
-/**
- * e_table_memory_store_new:
- * @col_count:
- * @value_at:
- * @set_value_at:
- * @is_cell_editable:
- * @duplicate_value:
- * @free_value:
- * @initialize_value:
- * @value_is_empty:
- * @value_to_string:
- * @data: closure pointer.
- *
- * This initializes a new ETableMemoryStoreModel object. ETableMemoryStoreModel is
- * an implementaiton of the abstract class ETableModel. The ETableMemoryStoreModel
- * is designed to allow people to easily create ETableModels without having
- * to create a new GtkType derived from ETableModel every time they need one.
- *
- * Instead, ETableMemoryStoreModel uses a setup based in callback functions, every
- * callback function signature mimics the signature of each ETableModel method
- * and passes the extra @data pointer to each one of the method to provide them
- * with any context they might want to use.
- *
- * Returns: An ETableMemoryStoreModel object (which is also an ETableModel
- * object).
- */
-ETableModel *
-e_table_memory_store_new (ETableMemoryStoreColumnInfo *columns)
-{
- ETableMemoryStore *et = g_object_new (E_TABLE_MEMORY_STORE_TYPE, NULL);
-
- if (e_table_memory_store_construct (et, columns)) {
- return (ETableModel *) et;
- } else {
- g_object_unref (et);
- return NULL;
- }
-}
-
-ETableModel *
-e_table_memory_store_construct (ETableMemoryStore *etms, ETableMemoryStoreColumnInfo *columns)
-{
- int i;
- for (i = 0; columns[i].type != E_TABLE_MEMORY_STORE_COLUMN_TYPE_TERMINATOR; i++)
- /* Intentionally blank */;
- etms->priv->col_count = i;
-
- etms->priv->columns = g_new (ETableMemoryStoreColumnInfo, etms->priv->col_count + 1);
-
- memcpy (etms->priv->columns, columns, (etms->priv->col_count + 1) * sizeof (ETableMemoryStoreColumnInfo));
-
- return E_TABLE_MODEL (etms);
-}
-
-
-void
-e_table_memory_store_adopt_value_at (ETableMemoryStore *etms, int col, int row, void *value)
-{
- e_table_model_pre_change (E_TABLE_MODEL (etms));
-
- STORE_LOCATOR (etms, col, row) = value;
-
- e_table_model_cell_changed (E_TABLE_MODEL (etms), col, row);
-}
-
-/* The size of these arrays is the number of columns. */
-void
-e_table_memory_store_insert_array (ETableMemoryStore *etms, int row, void **store, gpointer data)
-{
- int row_count;
- int i;
-
- row_count = e_table_model_row_count (E_TABLE_MODEL (etms)) + 1;
- if (row == -1)
- row = row_count - 1;
- etms->priv->store = g_realloc (etms->priv->store, etms->priv->col_count * row_count * sizeof (void *));
- memmove (etms->priv->store + etms->priv->col_count * (row + 1),
- etms->priv->store + etms->priv->col_count * row,
- etms->priv->col_count * (row_count - row - 1) * sizeof (void *));
-
- for (i = 0; i < etms->priv->col_count; i++) {
- STORE_LOCATOR(etms, i, row) = duplicate_value(etms, i, store[i]);
- }
-
- e_table_memory_insert (E_TABLE_MEMORY (etms), row, data);
-}
-
-void
-e_table_memory_store_insert (ETableMemoryStore *etms, int row, gpointer data, ...)
-{
- void **store;
- va_list args;
- int i;
-
- store = g_new (void *, etms->priv->col_count + 1);
-
- va_start (args, data);
- for (i = 0; i < etms->priv->col_count; i++) {
- store[i] = va_arg (args, void *);
- }
- va_end (args);
-
- e_table_memory_store_insert_array (etms, row, store, data);
-
- g_free (store);
-}
-
-void
-e_table_memory_store_insert_adopt_array (ETableMemoryStore *etms, int row, void **store, gpointer data)
-{
- int row_count;
- int i;
-
- row_count = e_table_model_row_count (E_TABLE_MODEL (etms)) + 1;
- if (row == -1)
- row = row_count - 1;
- etms->priv->store = g_realloc (etms->priv->store, etms->priv->col_count * row_count * sizeof (void *));
- memmove (etms->priv->store + etms->priv->col_count * (row + 1),
- etms->priv->store + etms->priv->col_count * row,
- etms->priv->col_count * (row_count - row - 1) * sizeof (void *));
-
- for (i = 0; i < etms->priv->col_count; i++) {
- STORE_LOCATOR(etms, i, row) = store[i];
- }
-
- e_table_memory_insert (E_TABLE_MEMORY (etms), row, data);
-}
-
-void
-e_table_memory_store_insert_adopt (ETableMemoryStore *etms, int row, gpointer data, ...)
-{
- void **store;
- va_list args;
- int i;
-
- store = g_new (void *, etms->priv->col_count + 1);
-
- va_start (args, data);
- for (i = 0; i < etms->priv->col_count; i++) {
- store[i] = va_arg (args, void *);
- }
- va_end (args);
-
- e_table_memory_store_insert_adopt_array (etms, row, store, data);
-
- g_free (store);
-}
-
-/**
- * e_table_memory_store_change_array:
- * @etms: the ETabelMemoryStore.
- * @row: the row we're changing.
- * @store: an array of new values to fill the row
- * @data: the new closure to associate with this row.
- *
- * frees existing values associated with a row and replaces them with
- * duplicates of the values in store.
- *
- */
-void
-e_table_memory_store_change_array (ETableMemoryStore *etms, int row, void **store, gpointer data)
-{
- int i;
-
- g_return_if_fail (row >= 0 && row < e_table_model_row_count (E_TABLE_MODEL (etms)));
-
- e_table_model_pre_change (E_TABLE_MODEL (etms));
-
- for (i = 0; i < etms->priv->col_count; i++) {
- free_value (etms, i, STORE_LOCATOR(etms, i, row));
- STORE_LOCATOR(etms, i, row) = duplicate_value(etms, i, store[i]);
- }
-
- e_table_memory_set_data (E_TABLE_MEMORY (etms), row, data);
- e_table_model_row_changed (E_TABLE_MODEL (etms), row);
-}
-
-/**
- * e_table_memory_store_change:
- * @etms: the ETabelMemoryStore.
- * @row: the row we're changing.
- * @data: the new closure to associate with this row.
- *
- * a varargs version of e_table_memory_store_change_array. you must
- * pass in etms->col_count args.
- */
-void
-e_table_memory_store_change (ETableMemoryStore *etms, int row, gpointer data, ...)
-{
- void **store;
- va_list args;
- int i;
-
- g_return_if_fail (row >= 0 && row < e_table_model_row_count (E_TABLE_MODEL (etms)));
-
- store = g_new0 (void *, etms->priv->col_count + 1);
-
- va_start (args, data);
- for (i = 0; i < etms->priv->col_count; i++) {
- store[i] = va_arg (args, void *);
- }
- va_end (args);
-
- e_table_memory_store_change_array (etms, row, store, data);
-
- g_free (store);
-}
-
-/**
- * e_table_memory_store_change_adopt_array:
- * @etms: the ETableMemoryStore
- * @row: the row we're changing.
- * @store: an array of new values to fill the row
- * @data: the new closure to associate with this row.
- *
- * frees existing values for the row and stores the values from store
- * into it. This function differs from
- * e_table_memory_storage_change_adopt_array in that it does not
- * duplicate the data.
- */
-void
-e_table_memory_store_change_adopt_array (ETableMemoryStore *etms, int row, void **store, gpointer data)
-{
- int i;
-
- g_return_if_fail (row >= 0 && row < e_table_model_row_count (E_TABLE_MODEL (etms)));
-
- for (i = 0; i < etms->priv->col_count; i++) {
- free_value (etms, i, STORE_LOCATOR(etms, i, row));
- STORE_LOCATOR(etms, i, row) = store[i];
- }
-
- e_table_memory_set_data (E_TABLE_MEMORY (etms), row, data);
- e_table_model_row_changed (E_TABLE_MODEL (etms), row);
-}
-
-/**
- * e_table_memory_store_change_adopt
- * @etms: the ETabelMemoryStore.
- * @row: the row we're changing.
- * @data: the new closure to associate with this row.
- *
- * a varargs version of e_table_memory_store_change_adopt_array. you
- * must pass in etms->col_count args.
- */
-void
-e_table_memory_store_change_adopt (ETableMemoryStore *etms, int row, gpointer data, ...)
-{
- void **store;
- va_list args;
- int i;
-
- g_return_if_fail (row >= 0 && row < e_table_model_row_count (E_TABLE_MODEL (etms)));
-
- store = g_new0 (void *, etms->priv->col_count + 1);
-
- va_start (args, data);
- for (i = 0; i < etms->priv->col_count; i++) {
- store[i] = va_arg (args, void *);
- }
- va_end (args);
-
- e_table_memory_store_change_adopt_array (etms, row, store, data);
-
- g_free (store);
-}
-
-void
-e_table_memory_store_remove (ETableMemoryStore *etms, int row)
-{
- ETableModel *model;
- int column_count, row_count;
- int i;
-
- model = E_TABLE_MODEL (etms);
- column_count = e_table_model_column_count (model);
-
- for (i = 0; i < column_count; i ++)
- e_table_model_free_value (model, i, e_table_model_value_at (model, i, row));
-
- row_count = e_table_model_row_count (E_TABLE_MODEL (etms)) - 1;
- memmove (etms->priv->store + etms->priv->col_count * row,
- etms->priv->store + etms->priv->col_count * (row + 1),
- etms->priv->col_count * (row_count - row) * sizeof (void *));
- etms->priv->store = g_realloc (etms->priv->store, etms->priv->col_count * row_count * sizeof (void *));
-
- e_table_memory_remove (E_TABLE_MEMORY (etms), row);
-}
-
-void
-e_table_memory_store_clear (ETableMemoryStore *etms)
-{
- ETableModel *model;
- int row_count, column_count;
- int i, j;
-
- model = E_TABLE_MODEL (etms);
- row_count = e_table_model_row_count (model);
- column_count = e_table_model_column_count (model);
-
- for (i = 0; i < row_count; i ++) {
- for (j = 0; j < column_count; j ++) {
- e_table_model_free_value (model, j, e_table_model_value_at (model, j, i));
- }
- }
-
- e_table_memory_clear (E_TABLE_MEMORY (etms));
-
- g_free (etms->priv->store);
- etms->priv->store = NULL;
-}
diff --git a/widgets/table/e-table-memory-store.h b/widgets/table/e-table-memory-store.h
deleted file mode 100644
index 54306da236..0000000000
--- a/widgets/table/e-table-memory-store.h
+++ /dev/null
@@ -1,138 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-memory-store.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_TABLE_MEMORY_STORE_H_
-#define _E_TABLE_MEMORY_STORE_H_
-
-#include <gal/e-table/e-table-memory.h>
-#include <gal/e-table/e-table-memory-callbacks.h>
-
-G_BEGIN_DECLS
-
-#define E_TABLE_MEMORY_STORE_TYPE (e_table_memory_store_get_type ())
-#define E_TABLE_MEMORY_STORE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TABLE_MEMORY_STORE_TYPE, ETableMemoryStore))
-#define E_TABLE_MEMORY_STORE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TABLE_MEMORY_STORE_TYPE, ETableMemoryStoreClass))
-#define E_IS_TABLE_MEMORY_STORE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TABLE_MEMORY_STORE_TYPE))
-#define E_IS_TABLE_MEMORY_STORE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TABLE_MEMORY_STORE_TYPE))
-#define E_TABLE_MEMORY_STORE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TABLE_MEMORY_STORE_TYPE, ETableMemoryStoreClass))
-
-typedef enum {
- E_TABLE_MEMORY_STORE_COLUMN_TYPE_TERMINATOR,
- E_TABLE_MEMORY_STORE_COLUMN_TYPE_INTEGER,
- E_TABLE_MEMORY_STORE_COLUMN_TYPE_STRING,
- E_TABLE_MEMORY_STORE_COLUMN_TYPE_PIXBUF,
- E_TABLE_MEMORY_STORE_COLUMN_TYPE_OBJECT,
- E_TABLE_MEMORY_STORE_COLUMN_TYPE_CUSTOM
-} ETableMemoryStoreColumnType;
-
-typedef struct {
- ETableMemoryCalbacksDuplicateValueFn duplicate_value;
- ETableMemoryCalbacksFreeValueFn free_value;
- ETableMemoryCalbacksInitializeValueFn initialize_value;
- ETableMemoryCalbacksValueIsEmptyFn value_is_empty;
- ETableMemoryCalbacksValueToStringFn value_to_string;
-} ETableMemoryStoreCustomColumn;
-
-typedef struct {
- ETableMemoryStoreColumnType type;
- ETableMemoryStoreCustomColumn custom;
- guint editable : 1;
-} ETableMemoryStoreColumnInfo;
-
-#define E_TABLE_MEMORY_STORE_TERMINATOR { E_TABLE_MEMORY_STORE_COLUMN_TYPE_TERMINATOR, { NULL }, FALSE }
-#define E_TABLE_MEMORY_STORE_INTEGER { E_TABLE_MEMORY_STORE_COLUMN_TYPE_INTEGER, { NULL }, FALSE }
-#define E_TABLE_MEMORY_STORE_STRING { E_TABLE_MEMORY_STORE_COLUMN_TYPE_STRING, { NULL }, FALSE }
-#define E_TABLE_MEMORY_STORE_PIXBUF { E_TABLE_MEMORY_STORE_COLUMN_TYPE_PIXBUF, { NULL }, FALSE }
-#define E_TABLE_MEMORY_STORE_EDITABLE_STRING { E_TABLE_MEMORY_STORE_COLUMN_TYPE_STRING, { NULL }, TRUE }
-#define E_TABLE_MEMORY_STORE_CUSTOM(editable, duplicate, free, initialize, empty, string) \
- { E_TABLE_MEMORY_STORE_COLUMN_TYPE_CUSTOM, \
- { (duplicate), (free), (initialize), (empty), (string) }, editable }
-#define E_TABLE_MEMORY_STORE_OBJECT(editable, initialize, empty, string) \
- { E_TABLE_MEMORY_STORE_COLUMN_TYPE_CUSTOM, \
- { NULL, NULL, (initialize), (empty), (string) }, editable }
-
-typedef struct _ETableMemoryStorePrivate ETableMemoryStorePrivate;
-
-typedef struct {
- ETableMemory parent;
-
- ETableMemoryStorePrivate *priv;
-} ETableMemoryStore;
-
-typedef struct {
- ETableMemoryClass parent_class;
-} ETableMemoryStoreClass;
-
-GType e_table_memory_store_get_type (void);
-
-/* Object Creation */
-ETableModel *e_table_memory_store_new (ETableMemoryStoreColumnInfo *columns);
-ETableModel *e_table_memory_store_construct (ETableMemoryStore *store,
- ETableMemoryStoreColumnInfo *columns);
-
-/* Adopt a value instead of copying it. */
-void e_table_memory_store_adopt_value_at (ETableMemoryStore *etms,
- int col,
- int row,
- void *value);
-
-/* The size of these arrays is the number of columns. */
-void e_table_memory_store_insert_array (ETableMemoryStore *etms,
- int row,
- void **store,
- gpointer data);
-void e_table_memory_store_insert (ETableMemoryStore *etms,
- int row,
- gpointer data,
- ...);
-void e_table_memory_store_insert_adopt (ETableMemoryStore *etms,
- int row,
- gpointer data,
- ...);
-void e_table_memory_store_insert_adopt_array (ETableMemoryStore *etms,
- int row,
- void **store,
- gpointer data);
-void e_table_memory_store_change_array (ETableMemoryStore *etms,
- int row,
- void **store,
- gpointer data);
-void e_table_memory_store_change (ETableMemoryStore *etms,
- int row,
- gpointer data,
- ...);
-void e_table_memory_store_change_adopt (ETableMemoryStore *etms,
- int row,
- gpointer data,
- ...);
-void e_table_memory_store_change_adopt_array (ETableMemoryStore *etms,
- int row,
- void **store,
- gpointer data);
-void e_table_memory_store_remove (ETableMemoryStore *etms,
- int row);
-void e_table_memory_store_clear (ETableMemoryStore *etms);
-
-G_END_DECLS
-
-#endif /* _E_TABLE_MEMORY_STORE_H_ */
diff --git a/widgets/table/e-table-memory.c b/widgets/table/e-table-memory.c
deleted file mode 100644
index 7d9958bbd6..0000000000
--- a/widgets/table/e-table-memory.c
+++ /dev/null
@@ -1,277 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-memory.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-
-#include "e-table-memory.h"
-
-#include <stdio.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-#include <libxml/parser.h>
-#include <libxml/xmlmemory.h>
-
-#include "gal/util/e-util.h"
-#include "gal/util/e-xml-utils.h"
-#include <string.h>
-
-static ETableModel *parent_class;
-
-struct ETableMemoryPriv {
- gpointer *data;
- int num_rows;
- gint frozen;
-};
-
-
-/* virtual methods */
-
-static void
-etmm_finalize (GObject *object)
-{
- ETableMemory *etmm = E_TABLE_MEMORY (object);
- ETableMemoryPriv *priv = etmm->priv;
-
- /* XXX lots of stuff to free here */
- if (priv) {
- g_free (priv->data);
- g_free (priv);
- }
- etmm->priv = NULL;
-
- G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-static int
-etmm_row_count (ETableModel *etm)
-{
- ETableMemory *etmm = E_TABLE_MEMORY (etm);
-
- return etmm->priv->num_rows;
-}
-
-
-static void
-e_table_memory_class_init (GObjectClass *klass)
-{
- ETableModelClass *table_class = (ETableModelClass *) klass;
-
- parent_class = g_type_class_peek_parent (klass);
-
- klass->finalize = etmm_finalize;
-
- table_class->row_count = etmm_row_count;
-}
-
-static void
-e_table_memory_init (GObject *object)
-{
- ETableMemory *etmm = (ETableMemory *)object;
-
- ETableMemoryPriv *priv;
-
- priv = g_new0 (ETableMemoryPriv, 1);
- etmm->priv = priv;
-
- priv->data = NULL;
- priv->num_rows = 0;
- priv->frozen = 0;
-}
-
-E_MAKE_TYPE(e_table_memory, "ETableMemory", ETableMemory, e_table_memory_class_init, e_table_memory_init, E_TABLE_MODEL_TYPE)
-
-
-
-/**
- * e_table_memory_new
- *
- * XXX docs here.
- *
- * return values: a newly constructed ETableMemory.
- */
-ETableMemory *
-e_table_memory_new (void)
-{
- return g_object_new (E_TABLE_MEMORY_TYPE, NULL);
-}
-
-/**
- * e_table_memory_get_data:
- * @etmm:
- * @row:
- *
- *
- *
- * Return value:
- **/
-gpointer
-e_table_memory_get_data (ETableMemory *etmm, int row)
-{
- g_return_val_if_fail(row >= 0, NULL);
- g_return_val_if_fail(row < etmm->priv->num_rows, NULL);
-
- return etmm->priv->data[row];
-}
-
-/**
- * e_table_memory_set_data:
- * @etmm:
- * @row:
- * @data:
- *
- *
- **/
-void
-e_table_memory_set_data (ETableMemory *etmm, int row, gpointer data)
-{
- g_return_if_fail(row >= 0);
- g_return_if_fail(row < etmm->priv->num_rows);
-
- etmm->priv->data[row] = data;
-}
-
-/**
- * e_table_memory_insert:
- * @table_model:
- * @parent_path:
- * @position:
- * @data:
- *
- *
- *
- * Return value:
- **/
-void
-e_table_memory_insert (ETableMemory *etmm,
- int row,
- gpointer data)
-{
- g_return_if_fail(row >= -1);
- g_return_if_fail(row <= etmm->priv->num_rows);
-
- if (!etmm->priv->frozen)
- e_table_model_pre_change(E_TABLE_MODEL(etmm));
-
- if (row == -1)
- row = etmm->priv->num_rows;
- etmm->priv->data = g_renew(gpointer, etmm->priv->data, etmm->priv->num_rows + 1);
- memmove(etmm->priv->data + row + 1, etmm->priv->data + row, (etmm->priv->num_rows - row) * sizeof (gpointer));
- etmm->priv->data[row] = data;
- etmm->priv->num_rows ++;
- if (!etmm->priv->frozen)
- e_table_model_row_inserted(E_TABLE_MODEL(etmm), row);
-}
-
-
-
-/**
- * e_table_memory_remove:
- * @etable:
- * @path:
- *
- *
- *
- * Return value:
- **/
-gpointer
-e_table_memory_remove (ETableMemory *etmm, int row)
-{
- gpointer ret;
-
- g_return_val_if_fail(row >= 0, NULL);
- g_return_val_if_fail(row < etmm->priv->num_rows, NULL);
-
- if (!etmm->priv->frozen)
- e_table_model_pre_change(E_TABLE_MODEL(etmm));
- ret = etmm->priv->data[row];
- memmove(etmm->priv->data + row, etmm->priv->data + row + 1, (etmm->priv->num_rows - row - 1) * sizeof (gpointer));
- etmm->priv->num_rows --;
- if (!etmm->priv->frozen)
- e_table_model_row_deleted(E_TABLE_MODEL(etmm), row);
- return ret;
-}
-
-/**
- * e_table_memory_clear:
- * @etable:
- * @path:
- *
- *
- *
- * Return value:
- **/
-void
-e_table_memory_clear (ETableMemory *etmm)
-{
- if (!etmm->priv->frozen)
- e_table_model_pre_change(E_TABLE_MODEL(etmm));
- g_free(etmm->priv->data);
- etmm->priv->data = NULL;
- etmm->priv->num_rows = 0;
- if (!etmm->priv->frozen)
- e_table_model_changed(E_TABLE_MODEL(etmm));
-}
-
-/**
- * e_table_memory_freeze:
- * @etmm: the ETableModel to freeze.
- *
- * This function prepares an ETableModel for a period of much change.
- * All signals regarding changes to the table are deferred until we
- * thaw the table.
- *
- **/
-void
-e_table_memory_freeze(ETableMemory *etmm)
-{
- ETableMemoryPriv *priv = etmm->priv;
-
- if (priv->frozen == 0)
- e_table_model_pre_change(E_TABLE_MODEL(etmm));
-
- priv->frozen ++;
-}
-
-/**
- * e_table_memory_thaw:
- * @etmm: the ETableMemory to thaw.
- *
- * This function thaws an ETableMemory. All the defered signals can add
- * up to a lot, we don't know - so we just emit a model_changed
- * signal.
- *
- **/
-void
-e_table_memory_thaw(ETableMemory *etmm)
-{
- ETableMemoryPriv *priv = etmm->priv;
-
- if (priv->frozen > 0)
- priv->frozen --;
- if (priv->frozen == 0) {
- e_table_model_changed(E_TABLE_MODEL(etmm));
- }
-}
diff --git a/widgets/table/e-table-memory.h b/widgets/table/e-table-memory.h
deleted file mode 100644
index c1b3cd45f8..0000000000
--- a/widgets/table/e-table-memory.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-memory.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_TABLE_MEMORY_H_
-#define _E_TABLE_MEMORY_H_
-
-#include <gdk-pixbuf/gdk-pixbuf.h>
-#include <gal/e-table/e-table-model.h>
-
-G_BEGIN_DECLS
-
-#define E_TABLE_MEMORY_TYPE (e_table_memory_get_type ())
-#define E_TABLE_MEMORY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TABLE_MEMORY_TYPE, ETableMemory))
-#define E_TABLE_MEMORY_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TABLE_MEMORY_TYPE, ETableMemoryClass))
-#define E_IS_TABLE_MEMORY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TABLE_MEMORY_TYPE))
-#define E_IS_TABLE_MEMORY_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TABLE_MEMORY_TYPE))
-#define E_TABLE_MEMORY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), E_TABLE_MEMORY_TYPE, ETableMemoryClass))
-
-typedef struct ETableMemory ETableMemory;
-typedef struct ETableMemoryPriv ETableMemoryPriv;
-typedef struct ETableMemoryClass ETableMemoryClass;
-
-struct ETableMemory {
- ETableModel base;
- ETableMemoryPriv *priv;
-};
-
-struct ETableMemoryClass {
- ETableModelClass parent_class;
-};
-
-
-GType e_table_memory_get_type (void);
-void e_table_memory_construct (ETableMemory *etable);
-ETableMemory *e_table_memory_new (void);
-
-/* row operations */
-void e_table_memory_insert (ETableMemory *etable,
- int row,
- gpointer data);
-gpointer e_table_memory_remove (ETableMemory *etable,
- int row);
-void e_table_memory_clear (ETableMemory *etable);
-
-/* Freeze and thaw */
-void e_table_memory_freeze (ETableMemory *etable);
-void e_table_memory_thaw (ETableMemory *etable);
-gpointer e_table_memory_get_data (ETableMemory *etm,
- int row);
-void e_table_memory_set_data (ETableMemory *etm,
- int row,
- gpointer data);
-
-G_END_DECLS
-
-#endif /* _E_TABLE_MEMORY_H */
diff --git a/widgets/table/e-table-model.c b/widgets/table/e-table-model.c
deleted file mode 100644
index 67c443c8c6..0000000000
--- a/widgets/table/e-table-model.c
+++ /dev/null
@@ -1,616 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-model.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <glib-object.h>
-#include "e-table-model.h"
-#include "gal/util/e-util.h"
-#include "gal/util/e-marshal.h"
-
-#define ETM_CLASS(e) (E_TABLE_MODEL_GET_CLASS (e))
-#define ETM_FROZEN(e) (GPOINTER_TO_INT (g_object_get_data (G_OBJECT(e), "frozen")) != 0)
-
-#define d(x)
-
-d(static gint depth = 0;)
-
-
-static GObjectClass *e_table_model_parent_class;
-
-enum {
- MODEL_NO_CHANGE,
- MODEL_CHANGED,
- MODEL_PRE_CHANGE,
- MODEL_ROW_CHANGED,
- MODEL_CELL_CHANGED,
- MODEL_ROWS_INSERTED,
- MODEL_ROWS_DELETED,
- ROW_SELECTION,
- LAST_SIGNAL
-};
-
-static guint e_table_model_signals [LAST_SIGNAL] = { 0, };
-
-/**
- * e_table_model_column_count:
- * @e_table_model: The e-table-model to operate on
- *
- * Returns: the number of columns in the table model.
- */
-int
-e_table_model_column_count (ETableModel *e_table_model)
-{
- g_return_val_if_fail (e_table_model != NULL, 0);
- g_return_val_if_fail (E_IS_TABLE_MODEL (e_table_model), 0);
-
- return ETM_CLASS (e_table_model)->column_count (e_table_model);
-}
-
-
-/**
- * e_table_model_row_count:
- * @e_table_model: the e-table-model to operate on
- *
- * Returns: the number of rows in the Table model.
- */
-int
-e_table_model_row_count (ETableModel *e_table_model)
-{
- g_return_val_if_fail (e_table_model != NULL, 0);
- g_return_val_if_fail (E_IS_TABLE_MODEL (e_table_model), 0);
-
- return ETM_CLASS (e_table_model)->row_count (e_table_model);
-}
-
-/**
- * e_table_model_append_row:
- * @e_table_model: the table model to append the a row to.
- * @source:
- * @row:
- *
- */
-void
-e_table_model_append_row (ETableModel *e_table_model, ETableModel *source, int row)
-{
- g_return_if_fail (e_table_model != NULL);
- g_return_if_fail (E_IS_TABLE_MODEL (e_table_model));
-
- if (ETM_CLASS (e_table_model)->append_row)
- ETM_CLASS (e_table_model)->append_row (e_table_model, source, row);
-}
-
-/**
- * e_table_value_at:
- * @e_table_model: the e-table-model to operate on
- * @col: column in the model to pull data from.
- * @row: row in the model to pull data from.
- *
- * Return value: This function returns the value that is stored
- * by the @e_table_model in column @col and row @row. The data
- * returned can be a pointer or any data value that can be stored
- * inside a pointer.
- *
- * The data returned is typically used by an ECell renderer.
- *
- * The data returned must be valid until the model sends a signal that
- * affect that piece of data. model_changed affects all data.
- * row_changed affects the data in that row. cell_changed affects the
- * data in that cell. rows_deleted affects all data in those rows.
- * rows_inserted and no_change don't affect any data in this way.
- **/
-void *
-e_table_model_value_at (ETableModel *e_table_model, int col, int row)
-{
- g_return_val_if_fail (e_table_model != NULL, NULL);
- g_return_val_if_fail (E_IS_TABLE_MODEL (e_table_model), NULL);
-
- return ETM_CLASS (e_table_model)->value_at (e_table_model, col, row);
-}
-
-/**
- * e_table_model_set_value_at:
- * @e_table_model: the table model to operate on.
- * @col: the column where the data will be stored in the model.
- * @row: the row where the data will be stored in the model.
- * @value: the data to be stored.
- *
- * This function instructs the model to store the value in @data in the
- * the @e_table_model at column @col and row @row. The @data typically
- * comes from one of the ECell rendering objects.
- *
- * There should be an agreement between the Table Model and the user
- * of this function about the data being stored. Typically it will
- * be a pointer to a set of data, or a datum that fits inside a void *.
- */
-void
-e_table_model_set_value_at (ETableModel *e_table_model, int col, int row, const void *value)
-{
- g_return_if_fail (e_table_model != NULL);
- g_return_if_fail (E_IS_TABLE_MODEL (e_table_model));
-
- ETM_CLASS (e_table_model)->set_value_at (e_table_model, col, row, value);
-}
-
-/**
- * e_table_model_is_cell_editable:
- * @e_table_model: the table model to query.
- * @col: column to query.
- * @row: row to query.
- *
- * Returns: %TRUE if the cell in @e_table_model at @col,@row can be
- * edited, %FALSE otherwise
- */
-gboolean
-e_table_model_is_cell_editable (ETableModel *e_table_model, int col, int row)
-{
- g_return_val_if_fail (e_table_model != NULL, FALSE);
- g_return_val_if_fail (E_IS_TABLE_MODEL (e_table_model), FALSE);
-
- return ETM_CLASS (e_table_model)->is_cell_editable (e_table_model, col, row);
-}
-
-
-void *
-e_table_model_duplicate_value (ETableModel *e_table_model, int col, const void *value)
-{
- g_return_val_if_fail (e_table_model != NULL, NULL);
- g_return_val_if_fail (E_IS_TABLE_MODEL (e_table_model), NULL);
-
- if (ETM_CLASS (e_table_model)->duplicate_value)
- return ETM_CLASS (e_table_model)->duplicate_value (e_table_model, col, value);
- else
- return NULL;
-}
-
-void
-e_table_model_free_value (ETableModel *e_table_model, int col, void *value)
-{
- g_return_if_fail (e_table_model != NULL);
- g_return_if_fail (E_IS_TABLE_MODEL (e_table_model));
-
- if (ETM_CLASS (e_table_model)->free_value)
- ETM_CLASS (e_table_model)->free_value (e_table_model, col, value);
-}
-
-gboolean
-e_table_model_has_save_id (ETableModel *e_table_model)
-{
- g_return_val_if_fail (e_table_model != NULL, FALSE);
- g_return_val_if_fail (E_IS_TABLE_MODEL (e_table_model), FALSE);
-
- if (ETM_CLASS (e_table_model)->has_save_id)
- return ETM_CLASS (e_table_model)->has_save_id (e_table_model);
- else
- return FALSE;
-}
-
-char *
-e_table_model_get_save_id (ETableModel *e_table_model, int row)
-{
- g_return_val_if_fail (e_table_model != NULL, "/");
- g_return_val_if_fail (E_IS_TABLE_MODEL (e_table_model), "/");
-
- if (ETM_CLASS (e_table_model)->get_save_id)
- return ETM_CLASS (e_table_model)->get_save_id (e_table_model, row);
- else
- return NULL;
-}
-
-gboolean
-e_table_model_has_change_pending(ETableModel *e_table_model)
-{
- g_return_val_if_fail (e_table_model != NULL, FALSE);
- g_return_val_if_fail (E_IS_TABLE_MODEL (e_table_model), FALSE);
-
- if (ETM_CLASS (e_table_model)->has_change_pending)
- return ETM_CLASS (e_table_model)->has_change_pending (e_table_model);
- else
- return FALSE;
-}
-
-void *
-e_table_model_initialize_value (ETableModel *e_table_model, int col)
-{
- g_return_val_if_fail (e_table_model != NULL, NULL);
- g_return_val_if_fail (E_IS_TABLE_MODEL (e_table_model), NULL);
-
- if (ETM_CLASS (e_table_model)->initialize_value)
- return ETM_CLASS (e_table_model)->initialize_value (e_table_model, col);
- else
- return NULL;
-}
-
-gboolean
-e_table_model_value_is_empty (ETableModel *e_table_model, int col, const void *value)
-{
- g_return_val_if_fail (e_table_model != NULL, FALSE);
- g_return_val_if_fail (E_IS_TABLE_MODEL (e_table_model), FALSE);
-
- if (ETM_CLASS (e_table_model)->value_is_empty)
- return ETM_CLASS (e_table_model)->value_is_empty (e_table_model, col, value);
- else
- return FALSE;
-}
-
-char *
-e_table_model_value_to_string (ETableModel *e_table_model, int col, const void *value)
-{
- g_return_val_if_fail (e_table_model != NULL, NULL);
- g_return_val_if_fail (E_IS_TABLE_MODEL (e_table_model), NULL);
-
- if (ETM_CLASS (e_table_model)->value_to_string)
- return ETM_CLASS (e_table_model)->value_to_string (e_table_model, col, value);
- else
- return g_strdup("");
-}
-
-static void
-e_table_model_finalize (GObject *object)
-{
- if (e_table_model_parent_class->finalize)
- (*e_table_model_parent_class->finalize)(object);
-}
-
-static void
-e_table_model_class_init (GObjectClass *object_class)
-{
- ETableModelClass *klass = E_TABLE_MODEL_CLASS(object_class);
- e_table_model_parent_class = g_type_class_peek_parent (object_class);
-
- object_class->finalize = e_table_model_finalize;
-
- e_table_model_signals [MODEL_NO_CHANGE] =
- g_signal_new ("model_no_change",
- E_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableModelClass, model_no_change),
- (GSignalAccumulator) NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
-
-
- e_table_model_signals [MODEL_CHANGED] =
- g_signal_new ("model_changed",
- E_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableModelClass, model_changed),
- (GSignalAccumulator) NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
-
- e_table_model_signals [MODEL_PRE_CHANGE] =
- g_signal_new ("model_pre_change",
- E_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableModelClass, model_pre_change),
- (GSignalAccumulator) NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
-
- e_table_model_signals [MODEL_ROW_CHANGED] =
- g_signal_new ("model_row_changed",
- E_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableModelClass, model_row_changed),
- (GSignalAccumulator) NULL, NULL,
- g_cclosure_marshal_VOID__INT,
- G_TYPE_NONE, 1, G_TYPE_INT);
-
- e_table_model_signals [MODEL_CELL_CHANGED] =
- g_signal_new ("model_cell_changed",
- E_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableModelClass, model_cell_changed),
- (GSignalAccumulator) NULL, NULL,
- e_marshal_VOID__INT_INT,
- G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
-
- e_table_model_signals [MODEL_ROWS_INSERTED] =
- g_signal_new ("model_rows_inserted",
- E_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableModelClass, model_rows_inserted),
- (GSignalAccumulator) NULL, NULL,
- e_marshal_VOID__INT_INT,
- G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
-
- e_table_model_signals [MODEL_ROWS_DELETED] =
- g_signal_new ("model_rows_deleted",
- E_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableModelClass, model_rows_deleted),
- (GSignalAccumulator) NULL, NULL,
- e_marshal_VOID__INT_INT,
- G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
-
- klass->column_count = NULL;
- klass->row_count = NULL;
- klass->append_row = NULL;
-
- klass->value_at = NULL;
- klass->set_value_at = NULL;
- klass->is_cell_editable = NULL;
-
- klass->has_save_id = NULL;
- klass->get_save_id = NULL;
-
- klass->has_change_pending = NULL;
-
- klass->duplicate_value = NULL;
- klass->free_value = NULL;
- klass->initialize_value = NULL;
- klass->value_is_empty = NULL;
- klass->value_to_string = NULL;
-
- klass->model_no_change = NULL;
- klass->model_changed = NULL;
- klass->model_row_changed = NULL;
- klass->model_cell_changed = NULL;
- klass->model_rows_inserted = NULL;
- klass->model_rows_deleted = NULL;
-}
-
-E_MAKE_TYPE(e_table_model, "ETableModel", ETableModel, e_table_model_class_init, NULL, G_TYPE_OBJECT)
-
-#if d(!)0
-static void
-print_tabs (void)
-{
- int i;
- for (i = 0; i < depth; i++)
- g_print("\t");
-}
-#endif
-
-void
-e_table_model_pre_change (ETableModel *e_table_model)
-{
- g_return_if_fail (e_table_model != NULL);
- g_return_if_fail (E_IS_TABLE_MODEL (e_table_model));
-
- if (ETM_FROZEN (e_table_model))
- return;
-
- d(print_tabs());
- d(g_print("Emitting pre_change on model 0x%p, a %s.\n", e_table_model, gtk_type_name (GTK_OBJECT(e_table_model)->klass->type)));
- d(depth++);
- g_signal_emit (G_OBJECT (e_table_model),
- e_table_model_signals [MODEL_PRE_CHANGE], 0);
- d(depth--);
-}
-
-/**
- * e_table_model_no_change:
- * @e_table_model: the table model to notify of the lack of a change
- *
- * Use this function to notify any views of this table model that
- * the contents of the table model have changed. This will emit
- * the signal "model_no_change" on the @e_table_model object.
- *
- * It is preferable to use the e_table_model_row_changed() and
- * the e_table_model_cell_changed() to notify of smaller changes
- * than to invalidate the entire model, as the views might have
- * ways of caching the information they render from the model.
- */
-void
-e_table_model_no_change (ETableModel *e_table_model)
-{
- g_return_if_fail (e_table_model != NULL);
- g_return_if_fail (E_IS_TABLE_MODEL (e_table_model));
-
- if (ETM_FROZEN (e_table_model))
- return;
-
- d(print_tabs());
- d(g_print("Emitting model_no_change on model 0x%p, a %s.\n", e_table_model, gtk_type_name (GTK_OBJECT(e_table_model)->klass->type)));
- d(depth++);
- g_signal_emit (G_OBJECT (e_table_model),
- e_table_model_signals [MODEL_NO_CHANGE], 0);
- d(depth--);
-}
-
-/**
- * e_table_model_changed:
- * @e_table_model: the table model to notify of the change
- *
- * Use this function to notify any views of this table model that
- * the contents of the table model have changed. This will emit
- * the signal "model_changed" on the @e_table_model object.
- *
- * It is preferable to use the e_table_model_row_changed() and
- * the e_table_model_cell_changed() to notify of smaller changes
- * than to invalidate the entire model, as the views might have
- * ways of caching the information they render from the model.
- */
-void
-e_table_model_changed (ETableModel *e_table_model)
-{
- g_return_if_fail (e_table_model != NULL);
- g_return_if_fail (E_IS_TABLE_MODEL (e_table_model));
-
- if (ETM_FROZEN (e_table_model))
- return;
-
- d(print_tabs());
- d(g_print("Emitting model_changed on model 0x%p, a %s.\n", e_table_model, gtk_type_name (GTK_OBJECT(e_table_model)->klass->type)));
- d(depth++);
- g_signal_emit (G_OBJECT (e_table_model),
- e_table_model_signals [MODEL_CHANGED], 0);
- d(depth--);
-}
-
-/**
- * e_table_model_row_changed:
- * @e_table_model: the table model to notify of the change
- * @row: the row that was changed in the model.
- *
- * Use this function to notify any views of the table model that
- * the contents of row @row have changed in model. This function
- * will emit the "model_row_changed" signal on the @e_table_model
- * object
- */
-void
-e_table_model_row_changed (ETableModel *e_table_model, int row)
-{
- g_return_if_fail (e_table_model != NULL);
- g_return_if_fail (E_IS_TABLE_MODEL (e_table_model));
-
- if (ETM_FROZEN (e_table_model))
- return;
-
- d(print_tabs());
- d(g_print("Emitting row_changed on model 0x%p, a %s, row %d.\n", e_table_model, gtk_type_name (GTK_OBJECT(e_table_model)->klass->type), row));
- d(depth++);
- g_signal_emit (G_OBJECT (e_table_model),
- e_table_model_signals [MODEL_ROW_CHANGED], 0, row);
- d(depth--);
-}
-
-/**
- * e_table_model_cell_changed:
- * @e_table_model: the table model to notify of the change
- * @col: the column.
- * @row: the row
- *
- * Use this function to notify any views of the table model that
- * contents of the cell at @col,@row has changed. This will emit
- * the "model_cell_changed" signal on the @e_table_model
- * object
- */
-void
-e_table_model_cell_changed (ETableModel *e_table_model, int col, int row)
-{
- g_return_if_fail (e_table_model != NULL);
- g_return_if_fail (E_IS_TABLE_MODEL (e_table_model));
-
- if (ETM_FROZEN (e_table_model))
- return;
-
- d(print_tabs());
- d(g_print("Emitting cell_changed on model 0x%p, a %s, row %d, col %d.\n", e_table_model, gtk_type_name (GTK_OBJECT(e_table_model)->klass->type), row, col));
- d(depth++);
- g_signal_emit (G_OBJECT (e_table_model),
- e_table_model_signals [MODEL_CELL_CHANGED], 0, col, row);
- d(depth--);
-}
-
-/**
- * e_table_model_rows_inserted:
- * @e_table_model: the table model to notify of the change
- * @row: the row that was inserted into the model.
- * @count: The number of rows that were inserted.
- *
- * Use this function to notify any views of the table model that
- * @count rows at row @row have been inserted into the model. This
- * function will emit the "model_rows_inserted" signal on the
- * @e_table_model object
- */
-void
-e_table_model_rows_inserted (ETableModel *e_table_model, int row, int count)
-{
- g_return_if_fail (e_table_model != NULL);
- g_return_if_fail (E_IS_TABLE_MODEL (e_table_model));
-
- if (ETM_FROZEN (e_table_model))
- return;
-
- d(print_tabs());
- d(g_print("Emitting row_inserted on model 0x%p, a %s, row %d.\n", e_table_model, gtk_type_name (GTK_OBJECT(e_table_model)->klass->type), row));
- d(depth++);
- g_signal_emit (G_OBJECT (e_table_model),
- e_table_model_signals [MODEL_ROWS_INSERTED], 0, row, count);
- d(depth--);
-}
-
-/**
- * e_table_model_row_inserted:
- * @e_table_model: the table model to notify of the change
- * @row: the row that was inserted into the model.
- *
- * Use this function to notify any views of the table model that the
- * row @row has been inserted into the model. This function will emit
- * the "model_rows_inserted" signal on the @e_table_model object
- */
-void
-e_table_model_row_inserted (ETableModel *e_table_model, int row)
-{
- e_table_model_rows_inserted(e_table_model, row, 1);
-}
-
-/**
- * e_table_model_row_deleted:
- * @e_table_model: the table model to notify of the change
- * @row: the row that was deleted
- * @count: The number of rows deleted
- *
- * Use this function to notify any views of the table model that
- * @count rows at row @row have been deleted from the model. This
- * function will emit the "model_rows_deleted" signal on the
- * @e_table_model object
- */
-void
-e_table_model_rows_deleted (ETableModel *e_table_model, int row, int count)
-{
- g_return_if_fail (e_table_model != NULL);
- g_return_if_fail (E_IS_TABLE_MODEL (e_table_model));
-
- if (ETM_FROZEN (e_table_model))
- return;
-
- d(print_tabs());
- d(g_print("Emitting row_deleted on model 0x%p, a %s, row %d.\n", e_table_model, gtk_type_name (GTK_OBJECT(e_table_model)->klass->type), row));
- d(depth++);
- g_signal_emit (G_OBJECT (e_table_model),
- e_table_model_signals [MODEL_ROWS_DELETED], 0, row, count);
- d(depth--);
-}
-
-/**
- * e_table_model_row_deleted:
- * @e_table_model: the table model to notify of the change
- * @row: the row that was deleted
- *
- * Use this function to notify any views of the table model that the
- * row @row has been deleted from the model. This function will emit
- * the "model_rows_deleted" signal on the @e_table_model object
- */
-void
-e_table_model_row_deleted (ETableModel *e_table_model, int row)
-{
- e_table_model_rows_deleted(e_table_model, row, 1);
-}
-
-void
-e_table_model_freeze (ETableModel *e_table_model)
-{
- e_table_model_pre_change (e_table_model);
- g_object_set_data (G_OBJECT (e_table_model), "frozen", GINT_TO_POINTER (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (e_table_model), "frozen")) + 1));
-}
-
-void
-e_table_model_thaw (ETableModel *e_table_model)
-{
- g_object_set_data (G_OBJECT (e_table_model), "frozen", GINT_TO_POINTER (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (e_table_model), "frozen")) - 1));
- e_table_model_changed (e_table_model);
-}
-
diff --git a/widgets/table/e-table-model.h b/widgets/table/e-table-model.h
deleted file mode 100644
index a08d9712ad..0000000000
--- a/widgets/table/e-table-model.h
+++ /dev/null
@@ -1,173 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-model.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_TABLE_MODEL_H_
-#define _E_TABLE_MODEL_H_
-
-#include <glib-object.h>
-
-G_BEGIN_DECLS
-
-#define E_TABLE_MODEL_TYPE (e_table_model_get_type ())
-#define E_TABLE_MODEL(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TABLE_MODEL_TYPE, ETableModel))
-#define E_TABLE_MODEL_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TABLE_MODEL_TYPE, ETableModelClass))
-#define E_IS_TABLE_MODEL(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TABLE_MODEL_TYPE))
-#define E_IS_TABLE_MODEL_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TABLE_MODEL_TYPE))
-#define E_TABLE_MODEL_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), E_TABLE_MODEL_TYPE, ETableModelClass))
-
-typedef struct {
- GObject base;
-} ETableModel;
-
-typedef struct {
- GObjectClass parent_class;
-
- /*
- * Virtual methods
- */
- int (*column_count) (ETableModel *etm);
- int (*row_count) (ETableModel *etm);
- void (*append_row) (ETableModel *etm, ETableModel *source, int row);
-
- void *(*value_at) (ETableModel *etm, int col, int row);
- void (*set_value_at) (ETableModel *etm, int col, int row, const void *value);
- gboolean (*is_cell_editable) (ETableModel *etm, int col, int row);
-
- gboolean (*has_save_id) (ETableModel *etm);
- char *(*get_save_id) (ETableModel *etm, int row);
-
- gboolean (*has_change_pending) (ETableModel *etm);
-
- /* Allocate a copy of the given value. */
- void *(*duplicate_value) (ETableModel *etm, int col, const void *value);
- /* Free an allocated value. */
- void (*free_value) (ETableModel *etm, int col, void *value);
- /* Return an allocated empty value. */
- void *(*initialize_value) (ETableModel *etm, int col);
- /* Return TRUE if value is equivalent to an empty cell. */
- gboolean (*value_is_empty) (ETableModel *etm, int col, const void *value);
- /* Return an allocated string. */
- char *(*value_to_string) (ETableModel *etm, int col, const void *value);
-
-
- /*
- * Signals
- */
-
- /*
- * These all come after the change has been made.
- * No changes, cancel pre_change: no_change
- * Major structural changes: model_changed
- * Changes only in a row: row_changed
- * Only changes in a cell: cell_changed
- * A row inserted: row_inserted
- * A row deleted: row_deleted
- */
- void (*model_pre_change) (ETableModel *etm);
-
- void (*model_no_change) (ETableModel *etm);
- void (*model_changed) (ETableModel *etm);
- void (*model_row_changed) (ETableModel *etm, int row);
- void (*model_cell_changed) (ETableModel *etm, int col, int row);
- void (*model_rows_inserted) (ETableModel *etm, int row, int count);
- void (*model_rows_deleted) (ETableModel *etm, int row, int count);
-} ETableModelClass;
-
-GType e_table_model_get_type (void);
-
-/**/
-int e_table_model_column_count (ETableModel *e_table_model);
-const char *e_table_model_column_name (ETableModel *e_table_model,
- int col);
-int e_table_model_row_count (ETableModel *e_table_model);
-void e_table_model_append_row (ETableModel *e_table_model,
- ETableModel *source,
- int row);
-
-/**/
-void *e_table_model_value_at (ETableModel *e_table_model,
- int col,
- int row);
-void e_table_model_set_value_at (ETableModel *e_table_model,
- int col,
- int row,
- const void *value);
-gboolean e_table_model_is_cell_editable (ETableModel *e_table_model,
- int col,
- int row);
-
-/**/
-gboolean e_table_model_has_save_id (ETableModel *etm);
-char *e_table_model_get_save_id (ETableModel *etm,
- int row);
-
-/**/
-gboolean e_table_model_has_change_pending (ETableModel *etm);
-
-
-/**/
-void *e_table_model_duplicate_value (ETableModel *e_table_model,
- int col,
- const void *value);
-void e_table_model_free_value (ETableModel *e_table_model,
- int col,
- void *value);
-void *e_table_model_initialize_value (ETableModel *e_table_model,
- int col);
-gboolean e_table_model_value_is_empty (ETableModel *e_table_model,
- int col,
- const void *value);
-char *e_table_model_value_to_string (ETableModel *e_table_model,
- int col,
- const void *value);
-
-/*
- * Routines for emitting signals on the e_table
- */
-void e_table_model_pre_change (ETableModel *e_table_model);
-void e_table_model_no_change (ETableModel *e_table_model);
-void e_table_model_changed (ETableModel *e_table_model);
-void e_table_model_row_changed (ETableModel *e_table_model,
- int row);
-void e_table_model_cell_changed (ETableModel *e_table_model,
- int col,
- int row);
-void e_table_model_rows_inserted (ETableModel *e_table_model,
-int row,
-int count);
-void e_table_model_rows_deleted (ETableModel *e_table_model,
-int row,
-int count);
-
-/**/
-void e_table_model_row_inserted (ETableModel *e_table_model,
-int row);
-void e_table_model_row_deleted (ETableModel *e_table_model,
-int row);
-
-void e_table_model_freeze (ETableModel *e_table_model);
-void e_table_model_thaw (ETableModel *e_table_model);
-
-G_END_DECLS
-
-#endif /* _E_TABLE_MODEL_H_ */
diff --git a/widgets/table/e-table-one.c b/widgets/table/e-table-one.c
deleted file mode 100644
index 486f14862f..0000000000
--- a/widgets/table/e-table-one.c
+++ /dev/null
@@ -1,241 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-one.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include "e-table-one.h"
-#include "gal/util/e-util.h"
-
-static ETableModelClass *parent_class = NULL;
-
-static int
-one_column_count (ETableModel *etm)
-{
- ETableOne *one = E_TABLE_ONE(etm);
-
- if (one->source)
- return e_table_model_column_count(one->source);
- else
- return 0;
-}
-
-static int
-one_row_count (ETableModel *etm)
-{
- return 1;
-}
-
-static void *
-one_value_at (ETableModel *etm, int col, int row)
-{
- ETableOne *one = E_TABLE_ONE(etm);
-
- if (one->data)
- return one->data[col];
- else
- return NULL;
-}
-
-static void
-one_set_value_at (ETableModel *etm, int col, int row, const void *val)
-{
- ETableOne *one = E_TABLE_ONE(etm);
-
- if (one->data && one->source) {
- e_table_model_free_value(one->source, col, one->data[col]);
- one->data[col] = e_table_model_duplicate_value(one->source, col, val);
- }
-}
-
-static gboolean
-one_is_cell_editable (ETableModel *etm, int col, int row)
-{
- ETableOne *one = E_TABLE_ONE(etm);
-
- if (one->source)
- return e_table_model_is_cell_editable(one->source, col, -1);
- else
- return FALSE;
-}
-
-/* The default for one_duplicate_value is to return the raw value. */
-static void *
-one_duplicate_value (ETableModel *etm, int col, const void *value)
-{
- ETableOne *one = E_TABLE_ONE(etm);
-
- if (one->source)
- return e_table_model_duplicate_value(one->source, col, value);
- else
- return (void *)value;
-}
-
-static void
-one_free_value (ETableModel *etm, int col, void *value)
-{
- ETableOne *one = E_TABLE_ONE(etm);
-
- if (one->source)
- e_table_model_free_value(one->source, col, value);
-}
-
-static void *
-one_initialize_value (ETableModel *etm, int col)
-{
- ETableOne *one = E_TABLE_ONE(etm);
-
- if (one->source)
- return e_table_model_initialize_value (one->source, col);
- else
- return NULL;
-}
-
-static gboolean
-one_value_is_empty (ETableModel *etm, int col, const void *value)
-{
- ETableOne *one = E_TABLE_ONE(etm);
-
- if (one->source)
- return e_table_model_value_is_empty (one->source, col, value);
- else
- return FALSE;
-}
-
-static char *
-one_value_to_string (ETableModel *etm, int col, const void *value)
-{
- ETableOne *one = E_TABLE_ONE(etm);
-
- if (one->source)
- return e_table_model_value_to_string (one->source, col, value);
- else
- return g_strdup("");
-}
-
-static void
-one_finalize (GObject *object)
-{
- G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-static void
-one_dispose (GObject *object)
-{
- ETableOne *one = E_TABLE_ONE (object);
-
-
- if (one->data) {
- int i;
- int col_count;
-
- if (one->source) {
- col_count = e_table_model_column_count(one->source);
-
- for (i = 0; i < col_count; i++)
- e_table_model_free_value(one->source, i, one->data[i]);
- }
-
- g_free (one->data);
- }
- one->data = NULL;
-
- if (one->source)
- g_object_unref(one->source);
- one->source = NULL;
-
- G_OBJECT_CLASS (parent_class)->dispose (object);
-}
-
-static void
-e_table_one_class_init (GObjectClass *object_class)
-{
- ETableModelClass *model_class = (ETableModelClass *) object_class;
-
- parent_class = g_type_class_peek_parent (object_class);
-
- model_class->column_count = one_column_count;
- model_class->row_count = one_row_count;
- model_class->value_at = one_value_at;
- model_class->set_value_at = one_set_value_at;
- model_class->is_cell_editable = one_is_cell_editable;
- model_class->duplicate_value = one_duplicate_value;
- model_class->free_value = one_free_value;
- model_class->initialize_value = one_initialize_value;
- model_class->value_is_empty = one_value_is_empty;
- model_class->value_to_string = one_value_to_string;
-
- object_class->dispose = one_dispose;
- object_class->finalize = one_finalize;
-}
-
-static void
-e_table_one_init (GObject *object)
-{
- ETableOne *one = E_TABLE_ONE(object);
-
- one->source = NULL;
- one->data = NULL;
-}
-
-E_MAKE_TYPE(e_table_one, "ETableOne", ETableOne, e_table_one_class_init, e_table_one_init, E_TABLE_MODEL_TYPE)
-
-
-ETableModel *
-e_table_one_new (ETableModel *source)
-{
- ETableOne *eto;
- int col_count;
- int i;
-
- eto = g_object_new (E_TABLE_ONE_TYPE, NULL);
- eto->source = source;
-
- col_count = e_table_model_column_count(source);
- eto->data = g_new(void *, col_count);
- for (i = 0; i < col_count; i++) {
- eto->data[i] = e_table_model_initialize_value(source, i);
- }
-
- if (source)
- g_object_ref(source);
-
- return (ETableModel *) eto;
-}
-
-void
-e_table_one_commit (ETableOne *one)
-{
- if (one->source) {
- int empty = TRUE;
- int col;
- int cols = e_table_model_column_count(one->source);
- for (col = 0; col < cols; col++) {
- if (!e_table_model_value_is_empty(one->source, col, one->data[col])) {
- empty = FALSE;
- break;
- }
- }
- if (!empty) {
- e_table_model_append_row(one->source, E_TABLE_MODEL(one), 0);
- }
- }
-}
diff --git a/widgets/table/e-table-one.h b/widgets/table/e-table-one.h
deleted file mode 100644
index 1c8147d779..0000000000
--- a/widgets/table/e-table-one.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-one.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_TABLE_ONE_H_
-#define _E_TABLE_ONE_H_
-
-#include <gal/e-table/e-table-model.h>
-
-G_BEGIN_DECLS
-
-#define E_TABLE_ONE_TYPE (e_table_one_get_type ())
-#define E_TABLE_ONE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TABLE_ONE_TYPE, ETableOne))
-#define E_TABLE_ONE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TABLE_ONE_TYPE, ETableOneClass))
-#define E_IS_TABLE_ONE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TABLE_ONE_TYPE))
-#define E_IS_TABLE_ONE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TABLE_ONE_TYPE))
-#define E_TABLE_ONE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TABLE_ONE_TYPE, ETableOneClass))
-
-typedef struct {
- ETableModel parent;
-
- ETableModel *source;
- void **data;
-} ETableOne;
-
-typedef struct {
- ETableModelClass parent_class;
-} ETableOneClass;
-
-GType e_table_one_get_type (void);
-
-ETableModel *e_table_one_new (ETableModel *source);
-void e_table_one_commit (ETableOne *one);
-
-G_END_DECLS
-
-#endif /* _E_TABLE_ONE_H_ */
-
diff --git a/widgets/table/e-table-scrolled.c b/widgets/table/e-table-scrolled.c
deleted file mode 100644
index 1786148c78..0000000000
--- a/widgets/table/e-table-scrolled.c
+++ /dev/null
@@ -1,229 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-scrolled.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdio.h>
-#include <libgnomecanvas/gnome-canvas.h>
-#include <gtk/gtksignal.h>
-#include <libxml/parser.h>
-#include <libxml/xmlmemory.h>
-
-#include "e-table.h"
-#include "e-table-scrolled.h"
-#include "gal/util/e-i18n.h"
-
-#define COLUMN_HEADER_HEIGHT 16
-
-#define PARENT_TYPE gtk_scrolled_window_get_type ()
-
-static GtkObjectClass *parent_class;
-
-enum {
- PROP_0,
- PROP_TABLE
-};
-
-static void
-e_table_scrolled_init (GtkObject *object)
-{
- ETableScrolled *ets;
- GtkScrolledWindow *scrolled_window;
-
- ets = E_TABLE_SCROLLED (object);
- scrolled_window = GTK_SCROLLED_WINDOW (object);
-
- GTK_WIDGET_SET_FLAGS (ets, GTK_CAN_FOCUS);
-
- ets->table = g_object_new (E_TABLE_TYPE, NULL);
-
- gtk_scrolled_window_set_policy (scrolled_window, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
- gtk_scrolled_window_set_shadow_type (scrolled_window, GTK_SHADOW_IN);
-}
-
-static void
-e_table_scrolled_real_construct (ETableScrolled *ets)
-{
- gtk_container_add(GTK_CONTAINER(ets), GTK_WIDGET(ets->table));
-
- gtk_widget_show(GTK_WIDGET(ets->table));
-}
-
-ETableScrolled *e_table_scrolled_construct (ETableScrolled *ets,
- ETableModel *etm,
- ETableExtras *ete,
- const char *spec,
- const char *state)
-{
- g_return_val_if_fail(ets != NULL, NULL);
- g_return_val_if_fail(E_IS_TABLE_SCROLLED(ets), NULL);
- g_return_val_if_fail(etm != NULL, NULL);
- g_return_val_if_fail(E_IS_TABLE_MODEL(etm), NULL);
- g_return_val_if_fail(ete == NULL || E_IS_TABLE_EXTRAS(ete), NULL);
- g_return_val_if_fail(spec != NULL, NULL);
-
- e_table_construct(ets->table, etm, ete, spec, state);
-
- e_table_scrolled_real_construct(ets);
-
- return ets;
-}
-
-GtkWidget *e_table_scrolled_new (ETableModel *etm,
- ETableExtras *ete,
- const char *spec,
- const char *state)
-{
- ETableScrolled *ets;
-
- g_return_val_if_fail(etm != NULL, NULL);
- g_return_val_if_fail(E_IS_TABLE_MODEL(etm), NULL);
- g_return_val_if_fail(ete == NULL || E_IS_TABLE_EXTRAS(ete), NULL);
- g_return_val_if_fail(spec != NULL, NULL);
-
- ets = E_TABLE_SCROLLED (gtk_widget_new (e_table_scrolled_get_type (),
- "hadjustment", NULL,
- "vadjustment", NULL,
- NULL));
-
- ets = e_table_scrolled_construct (ets, etm, ete, spec, state);
-
- return GTK_WIDGET (ets);
-}
-
-ETableScrolled *e_table_scrolled_construct_from_spec_file (ETableScrolled *ets,
- ETableModel *etm,
- ETableExtras *ete,
- const char *spec_fn,
- const char *state_fn)
-{
- g_return_val_if_fail(ets != NULL, NULL);
- g_return_val_if_fail(E_IS_TABLE_SCROLLED(ets), NULL);
- g_return_val_if_fail(etm != NULL, NULL);
- g_return_val_if_fail(E_IS_TABLE_MODEL(etm), NULL);
- g_return_val_if_fail(ete == NULL || E_IS_TABLE_EXTRAS(ete), NULL);
- g_return_val_if_fail(spec_fn != NULL, NULL);
-
- e_table_construct_from_spec_file(ets->table, etm, ete, spec_fn, state_fn);
-
- e_table_scrolled_real_construct(ets);
-
- return ets;
-}
-
-GtkWidget *e_table_scrolled_new_from_spec_file (ETableModel *etm,
- ETableExtras *ete,
- const char *spec_fn,
- const char *state_fn)
-{
- ETableScrolled *ets;
-
- g_return_val_if_fail(etm != NULL, NULL);
- g_return_val_if_fail(E_IS_TABLE_MODEL(etm), NULL);
- g_return_val_if_fail(ete == NULL || E_IS_TABLE_EXTRAS(ete), NULL);
- g_return_val_if_fail(spec_fn != NULL, NULL);
-
- ets = E_TABLE_SCROLLED (gtk_widget_new (e_table_scrolled_get_type (),
- "hadjustment", NULL,
- "vadjustment", NULL,
- NULL));
-
- ets = e_table_scrolled_construct_from_spec_file (ets, etm, ete, spec_fn, state_fn);
-
- return GTK_WIDGET (ets);
-}
-
-ETable *
-e_table_scrolled_get_table (ETableScrolled *ets)
-{
- return ets->table;
-}
-
-static void
-ets_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
-{
- ETableScrolled *ets = E_TABLE_SCROLLED (object);
-
- switch (prop_id){
- case PROP_TABLE:
- g_value_set_object (value, ets->table);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-/* Grab_focus handler for the scrolled ETable */
-static void
-ets_grab_focus (GtkWidget *widget)
-{
- ETableScrolled *ets;
-
- ets = E_TABLE_SCROLLED (widget);
-
- gtk_widget_grab_focus (GTK_WIDGET (ets->table));
-}
-
-/* Focus handler for the scrolled ETable */
-static gint
-ets_focus (GtkWidget *container, GtkDirectionType direction)
-{
- ETableScrolled *ets;
-
- ets = E_TABLE_SCROLLED (container);
-
- return gtk_widget_child_focus (GTK_WIDGET (ets->table), direction);
-}
-
-static void
-e_table_scrolled_class_init (ETableScrolledClass *class)
-{
- GObjectClass *object_class;
- GtkWidgetClass *widget_class;
- GtkContainerClass *container_class;
-
- object_class = (GObjectClass *) class;
- widget_class = (GtkWidgetClass *) class;
- container_class = (GtkContainerClass *) class;
-
- parent_class = g_type_class_ref (PARENT_TYPE);
-
- object_class->get_property = ets_get_property;
-
- widget_class->grab_focus = ets_grab_focus;
-
- widget_class->focus = ets_focus;
-
- g_object_class_install_property (object_class, PROP_TABLE,
- g_param_spec_object ("table",
- _( "Table" ),
- _( "Table" ),
- E_TABLE_TYPE,
- G_PARAM_READABLE));
-}
-
-E_MAKE_TYPE(e_table_scrolled, "ETableScrolled", ETableScrolled, e_table_scrolled_class_init, e_table_scrolled_init, PARENT_TYPE)
-
diff --git a/widgets/table/e-table-scrolled.h b/widgets/table/e-table-scrolled.h
deleted file mode 100644
index 40de97e99e..0000000000
--- a/widgets/table/e-table-scrolled.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-scrolled.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_TABLE_SCROLLED_H_
-#define _E_TABLE_SCROLLED_H_
-
-#include <gtk/gtkscrolledwindow.h>
-#include <gal/e-table/e-table-model.h>
-#include <gal/e-table/e-table.h>
-
-G_BEGIN_DECLS
-
-#define E_TABLE_SCROLLED_TYPE (e_table_scrolled_get_type ())
-#define E_TABLE_SCROLLED(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TABLE_SCROLLED_TYPE, ETableScrolled))
-#define E_TABLE_SCROLLED_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TABLE_SCROLLED_TYPE, ETableScrolledClass))
-#define E_IS_TABLE_SCROLLED(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TABLE_SCROLLED_TYPE))
-#define E_IS_TABLE_SCROLLED_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TABLE_SCROLLED_TYPE))
-
-typedef struct {
- GtkScrolledWindow parent;
-
- ETable *table;
-} ETableScrolled;
-
-typedef struct {
- GtkScrolledWindowClass parent_class;
-} ETableScrolledClass;
-
-GType e_table_scrolled_get_type (void);
-
-ETableScrolled *e_table_scrolled_construct (ETableScrolled *ets,
- ETableModel *etm,
- ETableExtras *ete,
- const char *spec,
- const char *state);
-GtkWidget *e_table_scrolled_new (ETableModel *etm,
- ETableExtras *ete,
- const char *spec,
- const char *state);
-
-ETableScrolled *e_table_scrolled_construct_from_spec_file (ETableScrolled *ets,
- ETableModel *etm,
- ETableExtras *ete,
- const char *spec_fn,
- const char *state_fn);
-GtkWidget *e_table_scrolled_new_from_spec_file (ETableModel *etm,
- ETableExtras *ete,
- const char *spec_fn,
- const char *state_fn);
-
-ETable *e_table_scrolled_get_table (ETableScrolled *ets);
-
-G_END_DECLS
-
-#endif /* _E_TABLE_SCROLLED_H_ */
-
diff --git a/widgets/table/e-table-search.c b/widgets/table/e-table-search.c
deleted file mode 100644
index c0460e4524..0000000000
--- a/widgets/table/e-table-search.c
+++ /dev/null
@@ -1,223 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-search.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include "e-table-search.h"
-#include "gal/util/e-util.h"
-
-#include <string.h>
-
-#define d(x)
-
-d(static gint depth = 0);
-
-struct _ETableSearchPrivate {
- guint timeout_id;
-
- char *search_string;
- gunichar last_character;
-};
-
-static GObjectClass *e_table_search_parent_class;
-
-enum {
- SEARCH_SEARCH,
- SEARCH_ACCEPT,
- LAST_SIGNAL
-};
-
-static guint e_table_search_signals [LAST_SIGNAL] = { 0, };
-
-static gboolean
-e_table_search_search (ETableSearch *e_table_search, char *string, ETableSearchFlags flags)
-{
- gboolean ret_val;
- g_return_val_if_fail (e_table_search != NULL, FALSE);
- g_return_val_if_fail (E_IS_TABLE_SEARCH (e_table_search), FALSE);
-
- g_signal_emit (G_OBJECT (e_table_search),
- e_table_search_signals [SEARCH_SEARCH],
- 0, string, flags, &ret_val);
-
- return ret_val;
-}
-
-static void
-e_table_search_accept (ETableSearch *e_table_search)
-{
- g_return_if_fail (e_table_search != NULL);
- g_return_if_fail (E_IS_TABLE_SEARCH (e_table_search));
-
- g_signal_emit (G_OBJECT (e_table_search),
- e_table_search_signals [SEARCH_ACCEPT], 0);
-}
-
-static gboolean
-ets_accept (gpointer data)
-{
- ETableSearch *ets = data;
- e_table_search_accept (ets);
- g_free (ets->priv->search_string);
-
- ets->priv->timeout_id = 0;
- ets->priv->search_string = g_strdup ("");
- ets->priv->last_character = 0;
-
- return FALSE;
-}
-
-static void
-drop_timeout (ETableSearch *ets)
-{
- if (ets->priv->timeout_id) {
- g_source_remove (ets->priv->timeout_id);
- }
- ets->priv->timeout_id = 0;
-}
-
-static void
-add_timeout (ETableSearch *ets)
-{
- drop_timeout (ets);
- ets->priv->timeout_id = g_timeout_add (1000, ets_accept, ets);
-}
-
-static void
-e_table_search_finalize (GObject *object)
-{
- ETableSearch *ets = (ETableSearch *) object;
-
- drop_timeout (ets);
- g_free (ets->priv->search_string);
- g_free (ets->priv);
-
- if (e_table_search_parent_class->finalize)
- (*e_table_search_parent_class->finalize)(object);
-}
-
-static void
-e_table_search_class_init (GObjectClass *object_class)
-{
- ETableSearchClass *klass = E_TABLE_SEARCH_CLASS(object_class);
- e_table_search_parent_class = g_type_class_peek_parent (klass);
-
- object_class->finalize = e_table_search_finalize;
-
- e_table_search_signals [SEARCH_SEARCH] =
- g_signal_new ("search",
- E_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableSearchClass, search),
- (GSignalAccumulator) NULL, NULL,
- e_marshal_BOOLEAN__STRING_INT,
- G_TYPE_BOOLEAN, 2, G_TYPE_STRING, G_TYPE_INT);
-
- e_table_search_signals [SEARCH_ACCEPT] =
- g_signal_new ("accept",
- E_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableSearchClass, accept),
- (GSignalAccumulator) NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
-
- klass->search = NULL;
- klass->accept = NULL;
-}
-
-static void
-e_table_search_init (ETableSearch *ets)
-{
- ets->priv = g_new (ETableSearchPrivate, 1);
-
- ets->priv->timeout_id = 0;
- ets->priv->search_string = g_strdup ("");
- ets->priv->last_character = 0;
-}
-
-
-E_MAKE_TYPE(e_table_search, "ETableSearch", ETableSearch, e_table_search_class_init, e_table_search_init, G_TYPE_OBJECT)
-
-ETableSearch *
-e_table_search_new (void)
-{
- ETableSearch *ets = g_object_new (E_TABLE_SEARCH_TYPE, NULL);
-
- return ets;
-}
-
-/**
- * e_table_search_column_count:
- * @e_table_search: The e-table-search to operate on
- *
- * Returns: the number of columns in the table search.
- */
-void
-e_table_search_input_character (ETableSearch *ets, gunichar character)
-{
- char character_utf8[7];
- char *temp_string;
-
- g_return_if_fail (ets != NULL);
- g_return_if_fail (E_IS_TABLE_SEARCH (ets));
-
- character_utf8 [g_unichar_to_utf8 (character, character_utf8)] = 0;
-
- temp_string = g_strdup_printf ("%s%s", ets->priv->search_string, character_utf8);
- if (e_table_search_search (ets, temp_string,
- ets->priv->last_character != 0 ? E_TABLE_SEARCH_FLAGS_CHECK_CURSOR_FIRST : 0)) {
- g_free (ets->priv->search_string);
- ets->priv->search_string = temp_string;
- add_timeout (ets);
- ets->priv->last_character = character;
- return;
- } else {
- g_free (temp_string);
- }
-
- if (character == ets->priv->last_character) {
- if (ets->priv->search_string && e_table_search_search (ets, ets->priv->search_string, 0)) {
- add_timeout (ets);
- }
- }
-}
-
-gboolean
-e_table_search_backspace (ETableSearch *ets)
-{
- char *end;
-
- g_return_val_if_fail (ets != NULL, FALSE);
- g_return_val_if_fail (E_IS_TABLE_SEARCH (ets), FALSE);
-
- if (!ets->priv->search_string ||
- !*ets->priv->search_string)
- return FALSE;
-
- end = ets->priv->search_string + strlen (ets->priv->search_string);
- end = g_utf8_prev_char (end);
- *end = 0;
- ets->priv->last_character = 0;
- add_timeout (ets);
- return TRUE;
-}
diff --git a/widgets/table/e-table-search.h b/widgets/table/e-table-search.h
deleted file mode 100644
index b3cdd9ff41..0000000000
--- a/widgets/table/e-table-search.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-search.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_TABLE_SEARCH_H_
-#define _E_TABLE_SEARCH_H_
-
-#include <gtk/gtkobject.h>
-
-G_BEGIN_DECLS
-
-#define E_TABLE_SEARCH_TYPE (e_table_search_get_type ())
-#define E_TABLE_SEARCH(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TABLE_SEARCH_TYPE, ETableSearch))
-#define E_TABLE_SEARCH_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TABLE_SEARCH_TYPE, ETableSearchClass))
-#define E_IS_TABLE_SEARCH(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TABLE_SEARCH_TYPE))
-#define E_IS_TABLE_SEARCH_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TABLE_SEARCH_TYPE))
-#define E_TABLE_SEARCH_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), E_TABLE_SEARCH_TYPE, ETableSearchClass))
-
-typedef struct _ETableSearchPrivate ETableSearchPrivate;
-
-typedef enum {
- E_TABLE_SEARCH_FLAGS_CHECK_CURSOR_FIRST = 1 << 0
-} ETableSearchFlags;
-
-typedef struct {
- GObject base;
-
- ETableSearchPrivate *priv;
-} ETableSearch;
-
-typedef struct {
- GObjectClass parent_class;
-
- /*
- * Signals
- */
- gboolean (*search) (ETableSearch *ets, char *string /* utf8 */, ETableSearchFlags flags);
- void (*accept) (ETableSearch *ets);
-} ETableSearchClass;
-
-GType e_table_search_get_type (void);
-ETableSearch *e_table_search_new (void);
-
-/**/
-void e_table_search_input_character (ETableSearch *e_table_search,
- gunichar character);
-gboolean e_table_search_backspace (ETableSearch *e_table_search);
-void e_table_search_cancel (ETableSearch *e_table_search);
-
-G_END_DECLS
-
-#endif /* _E_TABLE_SEARCH_H_ */
diff --git a/widgets/table/e-table-selection-model.c b/widgets/table/e-table-selection-model.c
deleted file mode 100644
index 14edf3d6de..0000000000
--- a/widgets/table/e-table-selection-model.c
+++ /dev/null
@@ -1,347 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-selection-model.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include "e-table-selection-model.h"
-
-#include <string.h>
-#include <gdk/gdkkeysyms.h>
-
-#include "gal/util/e-i18n.h"
-#include "gal/util/e-util.h"
-
-#define PARENT_TYPE e_selection_model_array_get_type ()
-
-static ESelectionModelArray *parent_class;
-
-static gint etsm_get_row_count (ESelectionModelArray *esm);
-
-enum {
- PROP_0,
- PROP_MODEL,
- PROP_HEADER
-};
-
-static void
-save_to_hash(int model_row, gpointer closure)
-{
- ETableSelectionModel *etsm = closure;
- gchar *key = e_table_model_get_save_id(etsm->model, model_row);
-
- g_hash_table_insert(etsm->hash, key, key);
-}
-
-static void
-free_key(gpointer key, gpointer value, gpointer closure)
-{
- g_free(key);
-}
-
-static void
-free_hash(ETableSelectionModel *etsm)
-{
- if (etsm->hash) {
- g_hash_table_foreach(etsm->hash, free_key, NULL);
- g_hash_table_destroy(etsm->hash);
- etsm->hash = NULL;
- }
- if (etsm->cursor_id)
- g_free(etsm->cursor_id);
- etsm->cursor_id = NULL;
-}
-
-static void
-model_pre_change (ETableModel *etm, ETableSelectionModel *etsm)
-{
- free_hash(etsm);
-
- if (etsm->model && e_table_model_has_save_id (etsm->model)) {
- gint cursor_row;
-
- etsm->hash = g_hash_table_new(g_str_hash, g_str_equal);
- e_selection_model_foreach(E_SELECTION_MODEL(etsm), save_to_hash, etsm);
-
- g_object_get(etsm,
- "cursor_row", &cursor_row,
- NULL);
- g_free (etsm->cursor_id);
- if (cursor_row != -1)
- etsm->cursor_id = e_table_model_get_save_id(etm, cursor_row);
- else
- etsm->cursor_id = NULL;
- }
-}
-
-static gint
-model_changed_idle(ETableSelectionModel *etsm)
-{
- ETableModel *etm = etsm->model;
-
- e_selection_model_clear(E_SELECTION_MODEL(etsm));
-
- if (etsm->cursor_id && etm && e_table_model_has_save_id(etm)) {
- int row_count = e_table_model_row_count(etm);
- int cursor_row = -1;
- int cursor_col = -1;
- int i;
- e_selection_model_array_confirm_row_count(E_SELECTION_MODEL_ARRAY(etsm));
- for (i = 0; i < row_count; i++) {
- char *save_id = e_table_model_get_save_id(etm, i);
- if (g_hash_table_lookup(etsm->hash, save_id))
- e_selection_model_change_one_row(E_SELECTION_MODEL(etsm), i, TRUE);
-
- if (etsm->cursor_id && !strcmp(etsm->cursor_id, save_id)) {
- cursor_row = i;
- cursor_col = e_selection_model_cursor_col(E_SELECTION_MODEL(etsm));
- if (cursor_col == -1) {
- if (etsm->eth) {
- cursor_col = e_table_header_prioritized_column (etsm->eth);
- } else
- cursor_col = 0;
- }
- e_selection_model_change_cursor(E_SELECTION_MODEL(etsm), cursor_row, cursor_col);
- g_free(etsm->cursor_id);
- etsm->cursor_id = NULL;
- }
- g_free(save_id);
- }
- free_hash(etsm);
- e_selection_model_cursor_changed (E_SELECTION_MODEL(etsm), cursor_row, cursor_col);
- e_selection_model_selection_changed (E_SELECTION_MODEL(etsm));
- }
- etsm->model_changed_idle_id = 0;
- return FALSE;
-}
-
-static void
-model_changed(ETableModel *etm, ETableSelectionModel *etsm)
-{
- e_selection_model_clear(E_SELECTION_MODEL(etsm));
- if (!etsm->model_changed_idle_id && etm && e_table_model_has_save_id(etm)) {
- etsm->model_changed_idle_id = g_idle_add_full(G_PRIORITY_HIGH, (GSourceFunc) model_changed_idle, etsm, NULL);
- }
-}
-
-static void
-model_row_changed(ETableModel *etm, int row, ETableSelectionModel *etsm)
-{
- free_hash(etsm);
-}
-
-static void
-model_cell_changed(ETableModel *etm, int col, int row, ETableSelectionModel *etsm)
-{
- free_hash(etsm);
-}
-
-#if 1
-static void
-model_rows_inserted(ETableModel *etm, int row, int count, ETableSelectionModel *etsm)
-{
- e_selection_model_array_insert_rows(E_SELECTION_MODEL_ARRAY(etsm), row, count);
- free_hash(etsm);
-}
-
-static void
-model_rows_deleted(ETableModel *etm, int row, int count, ETableSelectionModel *etsm)
-{
- e_selection_model_array_delete_rows(E_SELECTION_MODEL_ARRAY(etsm), row, count);
- free_hash(etsm);
-}
-
-#else
-
-static void
-model_rows_inserted(ETableModel *etm, int row, int count, ETableSelectionModel *etsm)
-{
- model_changed(etm, etsm);
-}
-
-static void
-model_rows_deleted(ETableModel *etm, int row, int count, ETableSelectionModel *etsm)
-{
- model_changed(etm, etsm);
-}
-#endif
-
-inline static void
-add_model(ETableSelectionModel *etsm, ETableModel *model)
-{
- etsm->model = model;
- if (model) {
- g_object_ref(model);
- etsm->model_pre_change_id = g_signal_connect(G_OBJECT(model), "model_pre_change",
- G_CALLBACK(model_pre_change), etsm);
- etsm->model_changed_id = g_signal_connect(G_OBJECT(model), "model_changed",
- G_CALLBACK(model_changed), etsm);
- etsm->model_row_changed_id = g_signal_connect(G_OBJECT(model), "model_row_changed",
- G_CALLBACK(model_row_changed), etsm);
- etsm->model_cell_changed_id = g_signal_connect(G_OBJECT(model), "model_cell_changed",
- G_CALLBACK(model_cell_changed), etsm);
- etsm->model_rows_inserted_id = g_signal_connect(G_OBJECT(model), "model_rows_inserted",
- G_CALLBACK(model_rows_inserted), etsm);
- etsm->model_rows_deleted_id = g_signal_connect(G_OBJECT(model), "model_rows_deleted",
- G_CALLBACK(model_rows_deleted), etsm);
- }
- e_selection_model_array_confirm_row_count(E_SELECTION_MODEL_ARRAY(etsm));
-}
-
-inline static void
-drop_model(ETableSelectionModel *etsm)
-{
- if (etsm->model) {
- g_signal_handler_disconnect(G_OBJECT(etsm->model),
- etsm->model_pre_change_id);
- g_signal_handler_disconnect(G_OBJECT(etsm->model),
- etsm->model_changed_id);
- g_signal_handler_disconnect(G_OBJECT(etsm->model),
- etsm->model_row_changed_id);
- g_signal_handler_disconnect(G_OBJECT(etsm->model),
- etsm->model_cell_changed_id);
- g_signal_handler_disconnect(G_OBJECT(etsm->model),
- etsm->model_rows_inserted_id);
- g_signal_handler_disconnect(G_OBJECT(etsm->model),
- etsm->model_rows_deleted_id);
-
- g_object_unref(etsm->model);
- }
- etsm->model = NULL;
-}
-
-static void
-etsm_dispose (GObject *object)
-{
- ETableSelectionModel *etsm;
-
- etsm = E_TABLE_SELECTION_MODEL (object);
-
- if (etsm->model_changed_idle_id)
- g_source_remove (etsm->model_changed_idle_id);
- etsm->model_changed_idle_id = 0;
-
- drop_model(etsm);
- free_hash(etsm);
-
- if (G_OBJECT_CLASS(parent_class)->dispose)
- G_OBJECT_CLASS(parent_class)->dispose (object);
-}
-
-static void
-etsm_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
-{
- ETableSelectionModel *etsm = E_TABLE_SELECTION_MODEL (object);
-
- switch (prop_id){
- case PROP_MODEL:
- g_value_set_object (value, etsm->model);
- break;
- case PROP_HEADER:
- g_value_set_object (value, etsm->eth);
- break;
- }
-}
-
-static void
-etsm_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
-{
- ETableSelectionModel *etsm = E_TABLE_SELECTION_MODEL (object);
-
- switch (prop_id){
- case PROP_MODEL:
- drop_model(etsm);
- add_model(etsm, g_value_get_object (value) ? E_TABLE_MODEL(g_value_get_object (value)) : NULL);
- break;
- case PROP_HEADER:
- etsm->eth = E_TABLE_HEADER (g_value_get_object (value));
- break;
- }
-}
-
-static void
-e_table_selection_model_init (ETableSelectionModel *selection)
-{
- selection->model = NULL;
- selection->hash = NULL;
- selection->cursor_id = NULL;
-
- selection->model_changed_idle_id = 0;
-}
-
-static void
-e_table_selection_model_class_init (ETableSelectionModelClass *klass)
-{
- GObjectClass *object_class;
- ESelectionModelArrayClass *esma_class;
-
- parent_class = g_type_class_ref (PARENT_TYPE);
-
- object_class = G_OBJECT_CLASS(klass);
- esma_class = E_SELECTION_MODEL_ARRAY_CLASS(klass);
-
- object_class->dispose = etsm_dispose;
- object_class->get_property = etsm_get_property;
- object_class->set_property = etsm_set_property;
-
- esma_class->get_row_count = etsm_get_row_count;
-
- g_object_class_install_property (object_class, PROP_MODEL,
- g_param_spec_object ("model",
- _("Model"),
- /*_( */"XXX blurb" /*)*/,
- E_TABLE_MODEL_TYPE,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class, PROP_HEADER,
- g_param_spec_object ("header",
- _("Header"),
- /*_( */"XXX blurb" /*)*/,
- E_TABLE_HEADER_TYPE,
- G_PARAM_READWRITE));
-}
-
-E_MAKE_TYPE(e_table_selection_model, "ETableSelectionModel", ETableSelectionModel,
- e_table_selection_model_class_init, e_table_selection_model_init, PARENT_TYPE)
-
-/**
- * e_table_selection_model_new
- *
- * This routine creates a new #ETableSelectionModel.
- *
- * Returns: The new #ETableSelectionModel.
- */
-ETableSelectionModel *
-e_table_selection_model_new (void)
-{
- return g_object_new (E_TABLE_SELECTION_MODEL_TYPE, NULL);
-}
-
-static gint
-etsm_get_row_count (ESelectionModelArray *esma)
-{
- ETableSelectionModel *etsm = E_TABLE_SELECTION_MODEL(esma);
-
- if (etsm->model)
- return e_table_model_row_count (etsm->model);
- else
- return 0;
-}
diff --git a/widgets/table/e-table-selection-model.h b/widgets/table/e-table-selection-model.h
deleted file mode 100644
index f3889d6f1b..0000000000
--- a/widgets/table/e-table-selection-model.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-selection-model.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_TABLE_SELECTION_MODEL_H_
-#define _E_TABLE_SELECTION_MODEL_H_
-
-#include <gtk/gtkobject.h>
-#include <gal/widgets/e-selection-model-array.h>
-#include <gal/e-table/e-table-model.h>
-#include <gal/e-table/e-table-header.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-#define E_TABLE_SELECTION_MODEL_TYPE (e_table_selection_model_get_type ())
-#define E_TABLE_SELECTION_MODEL(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TABLE_SELECTION_MODEL_TYPE, ETableSelectionModel))
-#define E_TABLE_SELECTION_MODEL_CLASS(k) (G_TYPE-CHECK_CLASS_CAST((k), E_TABLE_SELECTION_MODEL_TYPE, ETableSelectionModelClass))
-#define E_IS_TABLE_SELECTION_MODEL(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TABLE_SELECTION_MODEL_TYPE))
-#define E_IS_TABLE_SELECTION_MODEL_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TABLE_SELECTION_MODEL_TYPE))
-
-typedef struct {
- ESelectionModelArray base;
-
- ETableModel *model;
- ETableHeader *eth;
-
- guint model_pre_change_id;
- guint model_changed_id;
- guint model_row_changed_id;
- guint model_cell_changed_id;
- guint model_rows_inserted_id;
- guint model_rows_deleted_id;
-
- guint model_changed_idle_id;
-
- guint selection_model_changed : 1;
- guint group_info_changed : 1;
-
- GHashTable *hash;
- char *cursor_id;
-} ETableSelectionModel;
-
-typedef struct {
- ESelectionModelArrayClass parent_class;
-} ETableSelectionModelClass;
-
-GType e_table_selection_model_get_type (void);
-ETableSelectionModel *e_table_selection_model_new (void);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-
-#endif /* _E_TABLE_SELECTION_MODEL_H_ */
diff --git a/widgets/table/e-table-simple.c b/widgets/table/e-table-simple.c
deleted file mode 100644
index b7cf8f66be..0000000000
--- a/widgets/table/e-table-simple.c
+++ /dev/null
@@ -1,289 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-simple.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- * Miguel de Icaza <miguel.ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include "e-table-simple.h"
-#include "gal/util/e-util.h"
-
-static int
-simple_column_count (ETableModel *etm)
-{
- ETableSimple *simple = E_TABLE_SIMPLE(etm);
-
- if (simple->col_count)
- return simple->col_count (etm, simple->data);
- else
- return 0;
-}
-
-static int
-simple_row_count (ETableModel *etm)
-{
- ETableSimple *simple = E_TABLE_SIMPLE(etm);
-
- if (simple->row_count)
- return simple->row_count (etm, simple->data);
- else
- return 0;
-}
-
-static void
-simple_append_row (ETableModel *etm, ETableModel *source, int row)
-{
- ETableSimple *simple = E_TABLE_SIMPLE(etm);
-
- if (simple->append_row)
- simple->append_row (etm, source, row, simple->data);
-}
-
-static void *
-simple_value_at (ETableModel *etm, int col, int row)
-{
- ETableSimple *simple = E_TABLE_SIMPLE(etm);
-
- if (simple->value_at)
- return simple->value_at (etm, col, row, simple->data);
- else
- return NULL;
-}
-
-static void
-simple_set_value_at (ETableModel *etm, int col, int row, const void *val)
-{
- ETableSimple *simple = E_TABLE_SIMPLE(etm);
-
- if (simple->set_value_at)
- simple->set_value_at (etm, col, row, val, simple->data);
-}
-
-static gboolean
-simple_is_cell_editable (ETableModel *etm, int col, int row)
-{
- ETableSimple *simple = E_TABLE_SIMPLE(etm);
-
- if (simple->is_cell_editable)
- return simple->is_cell_editable (etm, col, row, simple->data);
- else
- return FALSE;
-}
-
-static gboolean
-simple_has_save_id (ETableModel *etm)
-{
- ETableSimple *simple = E_TABLE_SIMPLE(etm);
-
- if (simple->has_save_id)
- return simple->has_save_id (etm, simple->data);
- else
- return FALSE;
-}
-
-static char *
-simple_get_save_id (ETableModel *etm, int row)
-{
- ETableSimple *simple = E_TABLE_SIMPLE(etm);
-
- if (simple->get_save_id)
- return simple->get_save_id (etm, row, simple->data);
- else
- return NULL;
-}
-
-/* The default for simple_duplicate_value is to return the raw value. */
-static void *
-simple_duplicate_value (ETableModel *etm, int col, const void *value)
-{
- ETableSimple *simple = E_TABLE_SIMPLE(etm);
-
- if (simple->duplicate_value)
- return simple->duplicate_value (etm, col, value, simple->data);
- else
- return (void *)value;
-}
-
-static void
-simple_free_value (ETableModel *etm, int col, void *value)
-{
- ETableSimple *simple = E_TABLE_SIMPLE(etm);
-
- if (simple->free_value)
- simple->free_value (etm, col, value, simple->data);
-}
-
-static void *
-simple_initialize_value (ETableModel *etm, int col)
-{
- ETableSimple *simple = E_TABLE_SIMPLE(etm);
-
- if (simple->initialize_value)
- return simple->initialize_value (etm, col, simple->data);
- else
- return NULL;
-}
-
-static gboolean
-simple_value_is_empty (ETableModel *etm, int col, const void *value)
-{
- ETableSimple *simple = E_TABLE_SIMPLE(etm);
-
- if (simple->value_is_empty)
- return simple->value_is_empty (etm, col, value, simple->data);
- else
- return FALSE;
-}
-
-static char *
-simple_value_to_string (ETableModel *etm, int col, const void *value)
-{
- ETableSimple *simple = E_TABLE_SIMPLE(etm);
-
- if (simple->value_to_string)
- return simple->value_to_string (etm, col, value, simple->data);
- else
- return g_strdup ("");
-}
-
-static void
-e_table_simple_class_init (GObjectClass *object_class)
-{
- ETableModelClass *model_class = (ETableModelClass *) object_class;
-
- model_class->column_count = simple_column_count;
- model_class->row_count = simple_row_count;
- model_class->append_row = simple_append_row;
-
- model_class->value_at = simple_value_at;
- model_class->set_value_at = simple_set_value_at;
- model_class->is_cell_editable = simple_is_cell_editable;
-
- model_class->has_save_id = simple_has_save_id;
- model_class->get_save_id = simple_get_save_id;
-
- model_class->duplicate_value = simple_duplicate_value;
- model_class->free_value = simple_free_value;
- model_class->initialize_value = simple_initialize_value;
- model_class->value_is_empty = simple_value_is_empty;
- model_class->value_to_string = simple_value_to_string;
-}
-
-E_MAKE_TYPE(e_table_simple, "ETableSimple", ETableSimple, e_table_simple_class_init, NULL, E_TABLE_MODEL_TYPE)
-
-/**
- * e_table_simple_new:
- * @col_count:
- * @row_count:
- * @value_at:
- * @set_value_at:
- * @is_cell_editable:
- * @duplicate_value:
- * @free_value:
- * @initialize_value:
- * @value_is_empty:
- * @value_to_string:
- * @data: closure pointer.
- *
- * This initializes a new ETableSimpleModel object. ETableSimpleModel is
- * an implementaiton of the abstract class ETableModel. The ETableSimpleModel
- * is designed to allow people to easily create ETableModels without having
- * to create a new GtkType derived from ETableModel every time they need one.
- *
- * Instead, ETableSimpleModel uses a setup based in callback functions, every
- * callback function signature mimics the signature of each ETableModel method
- * and passes the extra @data pointer to each one of the method to provide them
- * with any context they might want to use.
- *
- * Returns: An ETableSimpleModel object (which is also an ETableModel
- * object).
- */
-ETableModel *
-e_table_simple_new (ETableSimpleColumnCountFn col_count,
- ETableSimpleRowCountFn row_count,
- ETableSimpleAppendRowFn append_row,
-
- ETableSimpleValueAtFn value_at,
- ETableSimpleSetValueAtFn set_value_at,
- ETableSimpleIsCellEditableFn is_cell_editable,
-
- ETableSimpleHasSaveIdFn has_save_id,
- ETableSimpleGetSaveIdFn get_save_id,
-
- ETableSimpleDuplicateValueFn duplicate_value,
- ETableSimpleFreeValueFn free_value,
- ETableSimpleInitializeValueFn initialize_value,
- ETableSimpleValueIsEmptyFn value_is_empty,
- ETableSimpleValueToStringFn value_to_string,
- void *data)
-{
- ETableSimple *et = g_object_new (E_TABLE_SIMPLE_TYPE, NULL);
-
- et->col_count = col_count;
- et->row_count = row_count;
- et->append_row = append_row;
-
- et->value_at = value_at;
- et->set_value_at = set_value_at;
- et->is_cell_editable = is_cell_editable;
-
- et->has_save_id = has_save_id;
- et->get_save_id = get_save_id;
-
- et->duplicate_value = duplicate_value;
- et->free_value = free_value;
- et->initialize_value = initialize_value;
- et->value_is_empty = value_is_empty;
- et->value_to_string = value_to_string;
- et->data = data;
-
- return (ETableModel *) et;
-}
-
-void *
-e_table_simple_string_duplicate_value (ETableModel *etm, int col, const void *val, void *data)
-{
- return g_strdup (val);
-}
-
-void
-e_table_simple_string_free_value (ETableModel *etm, int col, void *val, void *data)
-{
- g_free (val);
-}
-
-void *
-e_table_simple_string_initialize_value (ETableModel *etm, int col, void *data)
-{
- return g_strdup ("");
-}
-
-gboolean
-e_table_simple_string_value_is_empty (ETableModel *etm, int col, const void *val, void *data)
-{
- return !(val && * (char *) val);
-}
-
-char *
-e_table_simple_string_value_to_string (ETableModel *etm, int col, const void *val, void *data)
-{
- return g_strdup (val);
-}
diff --git a/widgets/table/e-table-simple.h b/widgets/table/e-table-simple.h
deleted file mode 100644
index 39800c3118..0000000000
--- a/widgets/table/e-table-simple.h
+++ /dev/null
@@ -1,122 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-simple.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- * Miguel de Icaza <miguel@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_TABLE_SIMPLE_H_
-#define _E_TABLE_SIMPLE_H_
-
-#include <gal/e-table/e-table-model.h>
-
-G_BEGIN_DECLS
-
-#define E_TABLE_SIMPLE_TYPE (e_table_simple_get_type ())
-#define E_TABLE_SIMPLE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TABLE_SIMPLE_TYPE, ETableSimple))
-#define E_TABLE_SIMPLE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TABLE_SIMPLE_TYPE, ETableSimpleClass))
-#define E_IS_TABLE_SIMPLE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TABLE_SIMPLE_TYPE))
-#define E_IS_TABLE_SIMPLE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TABLE_SIMPLE_TYPE))
-#define E_TABLE_SIMPLE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), E_TABLE_SIMPLE_TYPE, ETableSimpleClass))
-
-typedef int (*ETableSimpleColumnCountFn) (ETableModel *etm, void *data);
-typedef int (*ETableSimpleRowCountFn) (ETableModel *etm, void *data);
-typedef void (*ETableSimpleAppendRowFn) (ETableModel *etm, ETableModel *model, int row, void *data);
-
-typedef void *(*ETableSimpleValueAtFn) (ETableModel *etm, int col, int row, void *data);
-typedef void (*ETableSimpleSetValueAtFn) (ETableModel *etm, int col, int row, const void *val, void *data);
-typedef gboolean (*ETableSimpleIsCellEditableFn) (ETableModel *etm, int col, int row, void *data);
-
-typedef gboolean (*ETableSimpleHasSaveIdFn) (ETableModel *etm, void *data);
-typedef char *(*ETableSimpleGetSaveIdFn) (ETableModel *etm, int row, void *data);
-
-typedef void *(*ETableSimpleDuplicateValueFn) (ETableModel *etm, int col, const void *val, void *data);
-typedef void (*ETableSimpleFreeValueFn) (ETableModel *etm, int col, void *val, void *data);
-typedef void *(*ETableSimpleInitializeValueFn) (ETableModel *etm, int col, void *data);
-typedef gboolean (*ETableSimpleValueIsEmptyFn) (ETableModel *etm, int col, const void *val, void *data);
-typedef char *(*ETableSimpleValueToStringFn) (ETableModel *etm, int col, const void *val, void *data);
-
-typedef struct {
- ETableModel parent;
-
- ETableSimpleColumnCountFn col_count;
- ETableSimpleRowCountFn row_count;
- ETableSimpleAppendRowFn append_row;
-
- ETableSimpleValueAtFn value_at;
- ETableSimpleSetValueAtFn set_value_at;
- ETableSimpleIsCellEditableFn is_cell_editable;
-
- ETableSimpleHasSaveIdFn has_save_id;
- ETableSimpleGetSaveIdFn get_save_id;
-
- ETableSimpleDuplicateValueFn duplicate_value;
- ETableSimpleFreeValueFn free_value;
- ETableSimpleInitializeValueFn initialize_value;
- ETableSimpleValueIsEmptyFn value_is_empty;
- ETableSimpleValueToStringFn value_to_string;
- void *data;
-} ETableSimple;
-
-typedef struct {
- ETableModelClass parent_class;
-} ETableSimpleClass;
-
-GType e_table_simple_get_type (void);
-ETableModel *e_table_simple_new (ETableSimpleColumnCountFn col_count,
- ETableSimpleRowCountFn row_count,
- ETableSimpleAppendRowFn append_row,
- ETableSimpleValueAtFn value_at,
- ETableSimpleSetValueAtFn set_value_at,
- ETableSimpleIsCellEditableFn is_cell_editable,
- ETableSimpleHasSaveIdFn has_save_id,
- ETableSimpleGetSaveIdFn get_save_id,
- ETableSimpleDuplicateValueFn duplicate_value,
- ETableSimpleFreeValueFn free_value,
- ETableSimpleInitializeValueFn initialize_value,
- ETableSimpleValueIsEmptyFn value_is_empty,
- ETableSimpleValueToStringFn value_to_string,
- void *data);
-
-
-/* Helper functions for if your values are all just strings. */
-void *e_table_simple_string_duplicate_value (ETableModel *etm,
- int col,
- const void *val,
- void *data);
-void e_table_simple_string_free_value (ETableModel *etm,
- int col,
- void *val,
- void *data);
-void *e_table_simple_string_initialize_value (ETableModel *etm,
- int col,
- void *data);
-gboolean e_table_simple_string_value_is_empty (ETableModel *etm,
- int col,
- const void *val,
- void *data);
-char *e_table_simple_string_value_to_string (ETableModel *etm,
- int col,
- const void *val,
- void *data);
-
-G_END_DECLS
-
-#endif /* _E_TABLE_SIMPLE_H_ */
diff --git a/widgets/table/e-table-size-test.c b/widgets/table/e-table-size-test.c
deleted file mode 100644
index 05a4245899..0000000000
--- a/widgets/table/e-table-size-test.c
+++ /dev/null
@@ -1,307 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-size-test.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <gnome.h>
-#include <gdk-pixbuf/gdk-pixbuf.h>
-#include "gal/e-util/e-cursors.h"
-#include "e-table-simple.h"
-#include "e-table-header.h"
-#include "e-table-header-item.h"
-#include "e-table-item.h"
-#include "e-cell-text.h"
-#include "e-cell-checkbox.h"
-#include "e-table.h"
-
-#include "table-test.h"
-
-/*
- * One way in which we make it simpler to build an ETableModel is through
- * the ETableSimple class. Instead of creating your own ETableModel
- * class, you simply create a new object of the ETableSimple class. You
- * give it a bunch of functions that act as callbacks.
- *
- * You also get to pass a void * to ETableSimple and it gets passed to
- * your callbacks. This would be for having multiple models of the same
- * type. This is just an example though, so we statically define all the
- * data and ignore the void *data parameter.
- *
- * In our example we will be creating a table model with 6 columns and 10
- * rows. This corresponds to having 6 different types of information and
- * 10 different sets of data in our database.
- *
- * The headers will be hard coded, as will be the example data.
- *
- */
-
-/*
- * There are two different meanings to the word "column". The first is
- * the model column. A model column corresponds to a specific type of
- * data. This is very much like the usage in a database table where a
- * column is a field in the database.
- *
- * The second type of column is a view column. A view column
- * corresponds to a visually displayed column. Each view column
- * corresponds to a specific model column, though a model column may
- * have any number of view columns associated with it, from zero to
- * greater than one.
- *
- * Also, a view column doesn't necessarily depend on only one model
- * column. In some cases, the view column renderer can be given a
- * reference to another column to get extra information about its
- * display.
-*/
-
-#define ROWS 5000
-#define COLS 4
-
-#define IMPORTANCE_COLUMN 4
-#define COLOR_COLUMN 5
-
-/*
- * Here we define the initial layout of the table. This is an xml
- * format that allows you to change the initial ordering of the
- * columns or to do sorting or grouping initially. This specification
- * shows all 5 columns, but moves the importance column nearer to the
- * front. It also sorts by the "Full Name" column (ascending.)
- * Sorting and grouping take the model column as their arguments
- * (sorting is specified by the "column" argument to the leaf elemnt.
- */
-
-#define INITIAL_SPEC "<ETableSpecification> \
- <columns-shown> \
- <column> 0 </column> \
- <column> 4 </column> \
- <column> 1 </column> \
- <column> 2 </column> \
- <column> 3 </column> \
- </columns-shown> \
- <grouping> <leaf column=\"1\" ascending=\"true\"/> </grouping> \
-</ETableSpecification>"
-
-char *headers [COLS] = {
- "Email",
- "Full Name",
- "Address",
- "Phone"
-};
-
-/*
- * Virtual Column list:
- * 0 Email
- * 1 Full Name
- * 2 Address
- * 3 Phone
- */
-
-/*
- * ETableSimple callbacks
- * These are the callbacks that define the behavior of our custom model.
- */
-
-/*
- * Since our model is a constant size, we can just return its size in
- * the column and row count fields.
- */
-
-/* This function returns the number of columns in our ETableModel. */
-static int
-my_col_count (ETableModel *etc, void *data)
-{
- return COLS;
-}
-
-/* This function returns the number of rows in our ETableModel. */
-static int
-my_row_count (ETableModel *etc, void *data)
-{
- return ROWS;
-}
-
-/* This function returns the value at a particular point in our ETableModel. */
-static void *
-my_value_at (ETableModel *etc, int col, int row, void *data)
-{
- static guchar t[] = {'A', 0xc3, 0x84, 0xc3, 0x95, 0xc3, 0x94, 0xc3, 0xb5, 0x00};
-
-#if 0
- if (col == 1) return "toshok@ximian.com";
-#else
- if (col == 1) return t;
-#endif
- else if (col == 2) return "Chris Toshok";
- else if (col == 3) return "43 Vicksburg, SF";
- else if (col == 4) return "415-867-5309";
- else return NULL;
-}
-
-/* This function sets the value at a particular point in our ETableModel. */
-static void
-my_set_value_at (ETableModel *etc, int col, int row, const void *val, void *data)
-{
-}
-
-/* This function returns whether a particular cell is editable. */
-static gboolean
-my_is_cell_editable (ETableModel *etc, int col, int row, void *data)
-{
- return FALSE;
-}
-
-/* This function duplicates the value passed to it. */
-static void *
-my_duplicate_value (ETableModel *etc, int col, const void *value, void *data)
-{
- return g_strdup (value);
-}
-
-/* This function frees the value passed to it. */
-static void
-my_free_value (ETableModel *etc, int col, void *value, void *data)
-{
- g_free (value);
-}
-
-/* This function creates an empty value. */
-static void *
-my_initialize_value (ETableModel *etc, int col, void *data)
-{
- return g_strdup ("");
-}
-
-/* This function reports if a value is empty. */
-static gboolean
-my_value_is_empty (ETableModel *etc, int col, const void *value, void *data)
-{
- return !(value && *(char *)value);
-}
-
-/* This function reports if a value is empty. */
-static char *
-my_value_to_string (ETableModel *etc, int col, const void *value, void *data)
-{
- return g_strdup(value);
-}
-
-/* We create a window containing our new table. */
-static void
-create_table (void)
-{
- GtkWidget *e_table, *window, *frame;
- ECell *cell_left_just;
- ETableHeader *e_table_header;
- ETableModel *e_table_model = NULL;
- int i;
-
- /* Next we create our model. This uses the functions we defined
- earlier. */
- e_table_model = e_table_simple_new (
- my_col_count, my_row_count, my_value_at,
- my_set_value_at, my_is_cell_editable,
- my_duplicate_value, my_free_value,
- my_initialize_value, my_value_is_empty,
- my_value_to_string,
- NULL);
- /*
- * Next we create a header. The ETableHeader is used in two
- * different way. The first is the full_header. This is the
- * list of possible columns in the view. The second use is
- * completely internal. Many of the ETableHeader functions are
- * for that purpose. The only functions we really need are
- * e_table_header_new and e_table_header_add_col.
- *
- * First we create the header.
- */
- e_table_header = e_table_header_new ();
-
- /*
- * Next we have to build renderers for all of the columns.
- * Since all our columns are text columns, we can simply use
- * the same renderer over and over again. If we had different
- * types of columns, we could use a different renderer for
- * each column.
- */
- cell_left_just = e_cell_text_new (e_table_model, NULL, GTK_JUSTIFY_LEFT);
-
- /*
- * Next we create a column object for each view column and add
- * them to the header. We don't create a column object for
- * the importance column since it will not be shown.
- */
- for (i = 0; i < COLS; i++) {
- /* Create the column. */
- ETableCol *ecol = e_table_col_new (
- i, headers [i],
- 1.0, 20, cell_left_just,
- g_str_compare, TRUE);
- /* Add it to the header. */
- e_table_header_add_column (e_table_header, ecol, i);
- }
-
- /*
- * Here we create a window for our new table. This window
- * will get shown and the person will be able to test their
- * item.
- */
- window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
-
- /* This frame is simply to get a bevel around our table. */
- frame = gtk_frame_new (NULL);
-
- /*
- * Here we create the table. We give it the three pieces of
- * the table we've created, the header, the model, and the
- * initial layout. It does the rest.
- */
- e_table = e_table_new (e_table_header, e_table_model, INITIAL_SPEC);
-
- /* Build the gtk widget hierarchy. */
- gtk_container_add (GTK_CONTAINER (frame), e_table);
- gtk_container_add (GTK_CONTAINER (window), frame);
-
- /* Size the initial window. */
- gtk_widget_set_usize (window, 300, 200);
-
- /* Show it all. */
- gtk_widget_show_all (window);
-}
-
-/* This is the main function which just initializes gnome and call our create_table function */
-
-int
-main (int argc, char *argv [])
-{
- gnome_init ("TableExample", "TableExample", argc, argv);
- e_cursors_init ();
-
- gtk_widget_push_colormap (gdk_rgb_get_cmap ());
-
- create_table ();
-
- gtk_main ();
-
- e_cursors_shutdown ();
- return 0;
-}
-
diff --git a/widgets/table/e-table-sort-info.c b/widgets/table/e-table-sort-info.c
deleted file mode 100644
index ba8f9050ab..0000000000
--- a/widgets/table/e-table-sort-info.c
+++ /dev/null
@@ -1,481 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-sort-info.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-
-#include "e-table-sort-info.h"
-
-#include "gal/util/e-util.h"
-#include "gal/util/e-xml-utils.h"
-#include <string.h>
-
-#define ETM_CLASS(e) (E_TABLE_SORT_INFO_GET_CLASS (e))
-
-static GObjectClass *e_table_sort_info_parent_class;
-
-enum {
- SORT_INFO_CHANGED,
- GROUP_INFO_CHANGED,
- LAST_SIGNAL
-};
-
-static guint e_table_sort_info_signals [LAST_SIGNAL] = { 0, };
-
-static void
-etsi_finalize (GObject *object)
-{
- ETableSortInfo *etsi = E_TABLE_SORT_INFO (object);
-
- if (etsi->groupings)
- g_free(etsi->groupings);
- etsi->groupings = NULL;
-
- if (etsi->sortings)
- g_free(etsi->sortings);
- etsi->sortings = NULL;
-
- G_OBJECT_CLASS (e_table_sort_info_parent_class)->finalize (object);
-}
-
-static void
-e_table_sort_info_init (ETableSortInfo *info)
-{
- info->group_count = 0;
- info->groupings = NULL;
- info->sort_count = 0;
- info->sortings = NULL;
- info->frozen = 0;
- info->sort_info_changed = 0;
- info->group_info_changed = 0;
- info->can_group = 1;
-}
-
-static void
-e_table_sort_info_class_init (ETableSortInfoClass *klass)
-{
- GObjectClass * object_class = G_OBJECT_CLASS (klass);
-
- e_table_sort_info_parent_class = g_type_class_peek_parent (klass);
-
- object_class->finalize = etsi_finalize;
-
- e_table_sort_info_signals [SORT_INFO_CHANGED] =
- g_signal_new ("sort_info_changed",
- E_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableSortInfoClass, sort_info_changed),
- (GSignalAccumulator) NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
-
- e_table_sort_info_signals [GROUP_INFO_CHANGED] =
- g_signal_new ("group_info_changed",
- E_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableSortInfoClass, group_info_changed),
- (GSignalAccumulator) NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
-
- klass->sort_info_changed = NULL;
- klass->group_info_changed = NULL;
-}
-
-E_MAKE_TYPE(e_table_sort_info, "ETableSortInfo", ETableSortInfo,
- e_table_sort_info_class_init, e_table_sort_info_init, G_TYPE_OBJECT)
-
-static void
-e_table_sort_info_sort_info_changed (ETableSortInfo *info)
-{
- g_return_if_fail (info != NULL);
- g_return_if_fail (E_IS_TABLE_SORT_INFO (info));
-
- if (info->frozen) {
- info->sort_info_changed = 1;
- } else {
- g_signal_emit (G_OBJECT (info), e_table_sort_info_signals [SORT_INFO_CHANGED], 0);
- }
-}
-
-static void
-e_table_sort_info_group_info_changed (ETableSortInfo *info)
-{
- g_return_if_fail (info != NULL);
- g_return_if_fail (E_IS_TABLE_SORT_INFO (info));
-
- if (info->frozen) {
- info->group_info_changed = 1;
- } else {
- g_signal_emit (G_OBJECT (info), e_table_sort_info_signals [GROUP_INFO_CHANGED], 0);
- }
-}
-
-/**
- * e_table_sort_info_freeze:
- * @info: The ETableSortInfo object
- *
- * This functions allows the programmer to cluster various changes to the
- * ETableSortInfo (grouping and sorting) without having the object emit
- * "group_info_changed" or "sort_info_changed" signals on each change.
- *
- * To thaw, invoke the e_table_sort_info_thaw() function, which will
- * trigger any signals that might have been queued.
- */
-void
-e_table_sort_info_freeze (ETableSortInfo *info)
-{
- info->frozen++;
-}
-
-/**
- * e_table_sort_info_thaw:
- * @info: The ETableSortInfo object
- *
- * This functions allows the programmer to cluster various changes to the
- * ETableSortInfo (grouping and sorting) without having the object emit
- * "group_info_changed" or "sort_info_changed" signals on each change.
- *
- * This function will flush any pending signals that might be emited by
- * this object.
- */
-void
-e_table_sort_info_thaw (ETableSortInfo *info)
-{
- info->frozen--;
- if (info->frozen != 0)
- return;
-
- if (info->sort_info_changed) {
- info->sort_info_changed = 0;
- e_table_sort_info_sort_info_changed(info);
- }
- if (info->group_info_changed) {
- info->group_info_changed = 0;
- e_table_sort_info_group_info_changed(info);
- }
-}
-
-/**
- * e_table_sort_info_grouping_get_count:
- * @info: The ETableSortInfo object
- *
- * Returns: the number of grouping criteria in the object.
- */
-guint
-e_table_sort_info_grouping_get_count (ETableSortInfo *info)
-{
- if (info->can_group)
- return info->group_count;
- else
- return 0;
-}
-
-static void
-e_table_sort_info_grouping_real_truncate (ETableSortInfo *info, int length)
-{
- if (length < info->group_count) {
- info->group_count = length;
- }
- if (length > info->group_count) {
- info->groupings = g_realloc(info->groupings, length * sizeof(ETableSortColumn));
- info->group_count = length;
- }
-}
-
-/**
- * e_table_sort_info_grouping_truncate:
- * @info: The ETableSortInfo object
- * @lenght: position where the truncation happens.
- *
- * This routine can be used to reduce or grow the number of grouping
- * criteria in the object.
- */
-void
-e_table_sort_info_grouping_truncate (ETableSortInfo *info, int length)
-{
- e_table_sort_info_grouping_real_truncate(info, length);
- e_table_sort_info_group_info_changed(info);
-}
-
-/**
- * e_table_sort_info_grouping_get_nth:
- * @info: The ETableSortInfo object
- * @n: Item information to fetch.
- *
- * Returns: the description of the @n-th grouping criteria in the @info object.
- */
-ETableSortColumn
-e_table_sort_info_grouping_get_nth (ETableSortInfo *info, int n)
-{
- if (info->can_group && n < info->group_count) {
- return info->groupings[n];
- } else {
- ETableSortColumn fake = {0, 0};
- return fake;
- }
-}
-
-/**
- * e_table_sort_info_grouping_set_nth:
- * @info: The ETableSortInfo object
- * @n: Item information to fetch.
- * @column: new values for the grouping
- *
- * Sets the grouping criteria for index @n to be given by @column (a column number and
- * whether it is ascending or descending).
- */
-void
-e_table_sort_info_grouping_set_nth (ETableSortInfo *info, int n, ETableSortColumn column)
-{
- if (n >= info->group_count) {
- e_table_sort_info_grouping_real_truncate(info, n + 1);
- }
- info->groupings[n] = column;
- e_table_sort_info_group_info_changed(info);
-}
-
-
-/**
- * e_table_sort_info_get_count:
- * @info: The ETableSortInfo object
- *
- * Returns: the number of sorting criteria in the object.
- */
-guint
-e_table_sort_info_sorting_get_count (ETableSortInfo *info)
-{
- return info->sort_count;
-}
-
-static void
-e_table_sort_info_sorting_real_truncate (ETableSortInfo *info, int length)
-{
- if (length < info->sort_count) {
- info->sort_count = length;
- }
- if (length > info->sort_count) {
- info->sortings = g_realloc(info->sortings, length * sizeof(ETableSortColumn));
- info->sort_count = length;
- }
-}
-
-/**
- * e_table_sort_info_sorting_truncate:
- * @info: The ETableSortInfo object
- * @lenght: position where the truncation happens.
- *
- * This routine can be used to reduce or grow the number of sort
- * criteria in the object.
- */
-void
-e_table_sort_info_sorting_truncate (ETableSortInfo *info, int length)
-{
- e_table_sort_info_sorting_real_truncate (info, length);
- e_table_sort_info_sort_info_changed(info);
-}
-
-/**
- * e_table_sort_info_sorting_get_nth:
- * @info: The ETableSortInfo object
- * @n: Item information to fetch.
- *
- * Returns: the description of the @n-th grouping criteria in the @info object.
- */
-ETableSortColumn
-e_table_sort_info_sorting_get_nth (ETableSortInfo *info, int n)
-{
- if (n < info->sort_count) {
- return info->sortings[n];
- } else {
- ETableSortColumn fake = {0, 0};
- return fake;
- }
-}
-
-/**
- * e_table_sort_info_sorting_get_nth:
- * @info: The ETableSortInfo object
- * @n: Item information to fetch.
- * @column: new values for the sorting
- *
- * Sets the sorting criteria for index @n to be given by @column (a
- * column number and whether it is ascending or descending).
- */
-void
-e_table_sort_info_sorting_set_nth (ETableSortInfo *info, int n, ETableSortColumn column)
-{
- if (n >= info->sort_count) {
- e_table_sort_info_sorting_real_truncate(info, n + 1);
- }
- info->sortings[n] = column;
- e_table_sort_info_sort_info_changed(info);
-}
-
-/**
- * e_table_sort_info_new:
- *
- * This creates a new e_table_sort_info object that contains no
- * grouping and no sorting defined as of yet. This object is used
- * to keep track of multi-level sorting and multi-level grouping of
- * the ETable.
- *
- * Returns: A new %ETableSortInfo object
- */
-ETableSortInfo *
-e_table_sort_info_new (void)
-{
- return g_object_new (E_TABLE_SORT_INFO_TYPE, NULL);
-}
-
-/**
- * e_table_sort_info_load_from_node:
- * @info: The ETableSortInfo object
- * @node: pointer to the xmlNode that describes the sorting and grouping information
- * @state_version:
- *
- * This loads the state for the %ETableSortInfo object @info from the
- * xml node @node.
- */
-void
-e_table_sort_info_load_from_node (ETableSortInfo *info,
- xmlNode *node,
- gdouble state_version)
-{
- int i;
- xmlNode *grouping;
-
- if (state_version <= 0.05) {
- i = 0;
- for (grouping = node->xmlChildrenNode; grouping && !strcmp (grouping->name, "group"); grouping = grouping->xmlChildrenNode) {
- ETableSortColumn column;
- column.column = e_xml_get_integer_prop_by_name (grouping, "column");
- column.ascending = e_xml_get_bool_prop_by_name (grouping, "ascending");
- e_table_sort_info_grouping_set_nth(info, i++, column);
- }
- i = 0;
- for (; grouping && !strcmp (grouping->name, "leaf"); grouping = grouping->xmlChildrenNode) {
- ETableSortColumn column;
- column.column = e_xml_get_integer_prop_by_name (grouping, "column");
- column.ascending = e_xml_get_bool_prop_by_name (grouping, "ascending");
- e_table_sort_info_sorting_set_nth(info, i++, column);
- }
- } else {
- gint gcnt = 0;
- gint scnt = 0;
- for (grouping = node->children; grouping; grouping = grouping->next) {
- ETableSortColumn column;
-
- if (grouping->type != XML_ELEMENT_NODE)
- continue;
-
- if (!strcmp (grouping->name, "group")) {
- column.column = e_xml_get_integer_prop_by_name (grouping, "column");
- column.ascending = e_xml_get_bool_prop_by_name (grouping, "ascending");
- e_table_sort_info_grouping_set_nth(info, gcnt++, column);
- } else if (!strcmp (grouping->name, "leaf")) {
- column.column = e_xml_get_integer_prop_by_name (grouping, "column");
- column.ascending = e_xml_get_bool_prop_by_name (grouping, "ascending");
- e_table_sort_info_sorting_set_nth(info, scnt++, column);
- }
- }
- }
- g_signal_emit (G_OBJECT (info), e_table_sort_info_signals [SORT_INFO_CHANGED], 0);
-}
-
-/**
- * e_table_sort_info_save_to_node:
- * @info: The ETableSortInfo object
- * @parent: xmlNode that will be hosting the saved state of the @info object.
- *
- * This function is used
- *
- * Returns: the node that has been appended to @parent as a child containing
- * the sorting and grouping information for this ETableSortInfo object.
- */
-xmlNode *
-e_table_sort_info_save_to_node (ETableSortInfo *info,
- xmlNode *parent)
-{
- xmlNode *grouping;
- xmlNode *node;
- int i;
- const int sort_count = e_table_sort_info_sorting_get_count (info);
- const int group_count = e_table_sort_info_grouping_get_count (info);
-
- grouping = xmlNewChild (parent, NULL, "grouping", NULL);
-
- for (i = 0; i < group_count; i++) {
- ETableSortColumn column = e_table_sort_info_grouping_get_nth(info, i);
- xmlNode *new_node = xmlNewChild(grouping, NULL, "group", NULL);
-
- e_xml_set_integer_prop_by_name (new_node, "column", column.column);
- e_xml_set_bool_prop_by_name (new_node, "ascending", column.ascending);
- node = new_node;
- }
-
- for (i = 0; i < sort_count; i++) {
- ETableSortColumn column = e_table_sort_info_sorting_get_nth(info, i);
- xmlNode *new_node = xmlNewChild(grouping, NULL, "leaf", NULL);
-
- e_xml_set_integer_prop_by_name (new_node, "column", column.column);
- e_xml_set_bool_prop_by_name (new_node, "ascending", column.ascending);
- node = new_node;
- }
-
- return grouping;
-}
-
-ETableSortInfo *
-e_table_sort_info_duplicate (ETableSortInfo *info)
-{
- ETableSortInfo *new_info;
-
- new_info = e_table_sort_info_new();
-
- new_info->group_count = info->group_count;
- new_info->groupings = g_new(ETableSortColumn, new_info->group_count);
- memmove(new_info->groupings, info->groupings, sizeof (ETableSortColumn) * new_info->group_count);
-
- new_info->sort_count = info->sort_count;
- new_info->sortings = g_new(ETableSortColumn, new_info->sort_count);
- memmove(new_info->sortings, info->sortings, sizeof (ETableSortColumn) * new_info->sort_count);
-
- new_info->can_group = info->can_group;
-
- return new_info;
-}
-
-void
-e_table_sort_info_set_can_group (ETableSortInfo *info,
- gboolean can_group)
-{
- info->can_group = can_group;
-}
-
-gboolean
-e_table_sort_info_get_can_group (ETableSortInfo *info)
-{
- return info->can_group;
-}
-
-
diff --git a/widgets/table/e-table-sort-info.h b/widgets/table/e-table-sort-info.h
deleted file mode 100644
index 4710fbd453..0000000000
--- a/widgets/table/e-table-sort-info.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-sort-info.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_TABLE_SORT_INFO_H_
-#define _E_TABLE_SORT_INFO_H_
-
-#include <glib-object.h>
-#include <libxml/tree.h>
-
-G_BEGIN_DECLS
-
-#define E_TABLE_SORT_INFO_TYPE (e_table_sort_info_get_type ())
-#define E_TABLE_SORT_INFO(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TABLE_SORT_INFO_TYPE, ETableSortInfo))
-#define E_TABLE_SORT_INFO_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TABLE_SORT_INFO_TYPE, ETableSortInfoClass))
-#define E_IS_TABLE_SORT_INFO(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TABLE_SORT_INFO_TYPE))
-#define E_IS_TABLE_SORT_INFO_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TABLE_SORT_INFO_TYPE))
-#define E_TABLE_SORT_INFO_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), E_TABLE_SORT_INFO_TYPE, ETableSortInfoClass))
-
-typedef struct _ETableSortColumn ETableSortColumn;
-
-struct _ETableSortColumn {
- guint column : 31;
- guint ascending : 1;
-};
-
-typedef struct {
- GObject base;
-
- gint group_count;
- ETableSortColumn *groupings;
- gint sort_count;
- ETableSortColumn *sortings;
-
- guint frozen : 1;
- guint sort_info_changed : 1;
- guint group_info_changed : 1;
-
- guint can_group : 1;
-} ETableSortInfo;
-
-typedef struct {
- GObjectClass parent_class;
-
- /*
- * Signals
- */
- void (*sort_info_changed) (ETableSortInfo *info);
- void (*group_info_changed) (ETableSortInfo *info);
-} ETableSortInfoClass;
-
-GType e_table_sort_info_get_type (void);
-
-void e_table_sort_info_freeze (ETableSortInfo *info);
-void e_table_sort_info_thaw (ETableSortInfo *info);
-
-guint e_table_sort_info_grouping_get_count (ETableSortInfo *info);
-void e_table_sort_info_grouping_truncate (ETableSortInfo *info,
- int length);
-ETableSortColumn e_table_sort_info_grouping_get_nth (ETableSortInfo *info,
- int n);
-void e_table_sort_info_grouping_set_nth (ETableSortInfo *info,
- int n,
- ETableSortColumn column);
-
-guint e_table_sort_info_sorting_get_count (ETableSortInfo *info);
-void e_table_sort_info_sorting_truncate (ETableSortInfo *info,
- int length);
-ETableSortColumn e_table_sort_info_sorting_get_nth (ETableSortInfo *info,
- int n);
-void e_table_sort_info_sorting_set_nth (ETableSortInfo *info,
- int n,
- ETableSortColumn column);
-
-ETableSortInfo *e_table_sort_info_new (void);
-void e_table_sort_info_load_from_node (ETableSortInfo *info,
- xmlNode *node,
- gdouble state_version);
-xmlNode *e_table_sort_info_save_to_node (ETableSortInfo *info,
- xmlNode *parent);
-ETableSortInfo *e_table_sort_info_duplicate (ETableSortInfo *info);
-void e_table_sort_info_set_can_group (ETableSortInfo *info,
- gboolean can_group);
-gboolean e_table_sort_info_get_can_group (ETableSortInfo *info);
-
-G_END_DECLS
-
-#endif /* _E_TABLE_SORT_INFO_H_ */
diff --git a/widgets/table/e-table-sorted-variable.c b/widgets/table/e-table-sorted-variable.c
deleted file mode 100644
index ac3a7d5067..0000000000
--- a/widgets/table/e-table-sorted-variable.c
+++ /dev/null
@@ -1,230 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-sorted-variable.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <stdlib.h>
-#include <string.h>
-#include "gal/util/e-util.h"
-#include "e-table-sorted-variable.h"
-#include "e-table-sorting-utils.h"
-
-#define d(x)
-
-#define INCREMENT_AMOUNT 100
-
-/* maximum insertions between an idle event that we will do without scheduling an idle sort */
-#define ETSV_INSERT_MAX (4)
-
-static ETableSubsetVariableClass *etsv_parent_class;
-
-static void etsv_sort_info_changed (ETableSortInfo *info, ETableSortedVariable *etsv);
-static void etsv_sort (ETableSortedVariable *etsv);
-static void etsv_add (ETableSubsetVariable *etssv, gint row);
-static void etsv_add_all (ETableSubsetVariable *etssv);
-
-static void
-etsv_dispose (GObject *object)
-{
- ETableSortedVariable *etsv = E_TABLE_SORTED_VARIABLE (object);
-
- if (etsv->sort_info_changed_id)
- g_signal_handler_disconnect (G_OBJECT (etsv->sort_info),
- etsv->sort_info_changed_id);
- etsv->sort_info_changed_id = 0;
-
- if (etsv->sort_idle_id) {
- g_source_remove(etsv->sort_idle_id);
- etsv->sort_idle_id = 0;
- }
- if (etsv->insert_idle_id) {
- g_source_remove(etsv->insert_idle_id);
- etsv->insert_idle_id = 0;
- }
-
- if (etsv->sort_info)
- g_object_unref(etsv->sort_info);
- etsv->sort_info = NULL;
-
- if (etsv->full_header)
- g_object_unref(etsv->full_header);
- etsv->full_header = NULL;
-
- G_OBJECT_CLASS (etsv_parent_class)->dispose (object);
-}
-
-static void
-etsv_class_init (GObjectClass *object_class)
-{
- ETableSubsetVariableClass *etssv_class = E_TABLE_SUBSET_VARIABLE_CLASS(object_class);
-
- etsv_parent_class = g_type_class_peek_parent (object_class);
-
- object_class->dispose = etsv_dispose;
-
- etssv_class->add = etsv_add;
- etssv_class->add_all = etsv_add_all;
-}
-
-static void
-etsv_init (ETableSortedVariable *etsv)
-{
- etsv->full_header = NULL;
- etsv->sort_info = NULL;
-
- etsv->sort_info_changed_id = 0;
-
- etsv->sort_idle_id = 0;
- etsv->insert_count = 0;
-}
-
-E_MAKE_TYPE(e_table_sorted_variable, "ETableSortedVariable", ETableSortedVariable, etsv_class_init, etsv_init, E_TABLE_SUBSET_VARIABLE_TYPE)
-
-static gboolean
-etsv_sort_idle(ETableSortedVariable *etsv)
-{
- g_object_ref(etsv);
- etsv_sort(etsv);
- etsv->sort_idle_id = 0;
- etsv->insert_count = 0;
- g_object_unref(etsv);
- return FALSE;
-}
-
-static gboolean
-etsv_insert_idle(ETableSortedVariable *etsv)
-{
- etsv->insert_count = 0;
- etsv->insert_idle_id = 0;
- return FALSE;
-}
-
-
-static void
-etsv_add (ETableSubsetVariable *etssv,
- gint row)
-{
- ETableModel *etm = E_TABLE_MODEL(etssv);
- ETableSubset *etss = E_TABLE_SUBSET(etssv);
- ETableSortedVariable *etsv = E_TABLE_SORTED_VARIABLE (etssv);
- int i;
-
- e_table_model_pre_change (etm);
-
- if (etss->n_map + 1 > etssv->n_vals_allocated) {
- etssv->n_vals_allocated += INCREMENT_AMOUNT;
- etss->map_table = g_realloc (etss->map_table, (etssv->n_vals_allocated) * sizeof(int));
- }
- i = etss->n_map;
- if (etsv->sort_idle_id == 0) {
- /* this is to see if we're inserting a lot of things between idle loops.
- If we are, we're busy, its faster to just append and perform a full sort later */
- etsv->insert_count++;
- if (etsv->insert_count > ETSV_INSERT_MAX) {
- /* schedule a sort, and append instead */
- etsv->sort_idle_id = g_idle_add_full(50, (GSourceFunc) etsv_sort_idle, etsv, NULL);
- } else {
- /* make sure we have an idle handler to reset the count every now and then */
- if (etsv->insert_idle_id == 0) {
- etsv->insert_idle_id = g_idle_add_full(40, (GSourceFunc) etsv_insert_idle, etsv, NULL);
- }
- i = e_table_sorting_utils_insert(etss->source, etsv->sort_info, etsv->full_header, etss->map_table, etss->n_map, row);
- memmove(etss->map_table + i + 1, etss->map_table + i, (etss->n_map - i) * sizeof(int));
- }
- }
- etss->map_table[i] = row;
- etss->n_map++;
-
- e_table_model_row_inserted (etm, i);
-}
-
-static void
-etsv_add_all (ETableSubsetVariable *etssv)
-{
- ETableModel *etm = E_TABLE_MODEL(etssv);
- ETableSubset *etss = E_TABLE_SUBSET(etssv);
- ETableSortedVariable *etsv = E_TABLE_SORTED_VARIABLE (etssv);
- int rows;
- int i;
-
- e_table_model_pre_change(etm);
-
- rows = e_table_model_row_count(etss->source);
-
- if (etss->n_map + rows > etssv->n_vals_allocated){
- etssv->n_vals_allocated += MAX(INCREMENT_AMOUNT, rows);
- etss->map_table = g_realloc (etss->map_table, etssv->n_vals_allocated * sizeof(int));
- }
- for (i = 0; i < rows; i++)
- etss->map_table[etss->n_map++] = i;
-
- if (etsv->sort_idle_id == 0) {
- etsv->sort_idle_id = g_idle_add_full(50, (GSourceFunc) etsv_sort_idle, etsv, NULL);
- }
-
- e_table_model_changed (etm);
-}
-
-ETableModel *
-e_table_sorted_variable_new (ETableModel *source, ETableHeader *full_header, ETableSortInfo *sort_info)
-{
- ETableSortedVariable *etsv = g_object_new (E_TABLE_SORTED_VARIABLE_TYPE, NULL);
- ETableSubsetVariable *etssv = E_TABLE_SUBSET_VARIABLE (etsv);
-
- if (e_table_subset_variable_construct (etssv, source) == NULL){
- g_object_unref (etsv);
- return NULL;
- }
-
- etsv->sort_info = sort_info;
- g_object_ref(etsv->sort_info);
- etsv->full_header = full_header;
- g_object_ref(etsv->full_header);
-
- etsv->sort_info_changed_id = g_signal_connect (G_OBJECT (sort_info), "sort_info_changed",
- G_CALLBACK (etsv_sort_info_changed), etsv);
-
- return E_TABLE_MODEL(etsv);
-}
-
-static void
-etsv_sort_info_changed (ETableSortInfo *info, ETableSortedVariable *etsv)
-{
- etsv_sort(etsv);
-}
-
-static void
-etsv_sort(ETableSortedVariable *etsv)
-{
- ETableSubset *etss = E_TABLE_SUBSET(etsv);
- static int reentering = 0;
- if (reentering)
- return;
- reentering = 1;
-
- e_table_model_pre_change(E_TABLE_MODEL(etsv));
-
- e_table_sorting_utils_sort(etss->source, etsv->sort_info, etsv->full_header, etss->map_table, etss->n_map);
-
- e_table_model_changed (E_TABLE_MODEL(etsv));
- reentering = 0;
-}
diff --git a/widgets/table/e-table-sorted-variable.h b/widgets/table/e-table-sorted-variable.h
deleted file mode 100644
index 546d04b240..0000000000
--- a/widgets/table/e-table-sorted-variable.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-sorted-variable.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_TABLE_SORTED_VARIABLE_H_
-#define _E_TABLE_SORTED_VARIABLE_H_
-
-#include <glib-object.h>
-#include <gal/e-table/e-table-model.h>
-#include <gal/e-table/e-table-subset-variable.h>
-#include <gal/e-table/e-table-sort-info.h>
-#include <gal/e-table/e-table-header.h>
-
-G_BEGIN_DECLS
-
-#define E_TABLE_SORTED_VARIABLE_TYPE (e_table_sorted_variable_get_type ())
-#define E_TABLE_SORTED_VARIABLE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TABLE_SORTED_VARIABLE_TYPE, ETableSortedVariable))
-#define E_TABLE_SORTED_VARIABLE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TABLE_SORTED_VARIABLE_TYPE, ETableSortedVariableClass))
-#define E_IS_TABLE_SORTED_VARIABLE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TABLE_SORTED_VARIABLE_TYPE))
-#define E_IS_TABLE_SORTED_VARIABLE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TABLE_SORTED_VARIABLE_TYPE))
-#define E_TABLE_SORTED_VARIABLE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), E_TABLE_SORTED_VARIABLE_TYPE, ETableSortedVariableClass))
-
-typedef struct {
- ETableSubsetVariable base;
-
- ETableSortInfo *sort_info;
-
- ETableHeader *full_header;
-
- int sort_info_changed_id;
- int sort_idle_id;
- int insert_idle_id;
- int insert_count;
-
-} ETableSortedVariable;
-
-typedef struct {
- ETableSubsetVariableClass parent_class;
-} ETableSortedVariableClass;
-
-GType e_table_sorted_variable_get_type (void);
-ETableModel *e_table_sorted_variable_new (ETableModel *etm, ETableHeader *header, ETableSortInfo *sort_info);
-
-G_END_DECLS
-
-#endif /* _E_TABLE_SORTED_VARIABLE_H_ */
diff --git a/widgets/table/e-table-sorted.c b/widgets/table/e-table-sorted.c
deleted file mode 100644
index a5b5acb8cf..0000000000
--- a/widgets/table/e-table-sorted.c
+++ /dev/null
@@ -1,310 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-sorted.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <stdlib.h>
-#include <string.h>
-#include "gal/util/e-util.h"
-#include "e-table-sorted.h"
-#include "e-table-sorting-utils.h"
-
-#define d(x)
-
-#define INCREMENT_AMOUNT 100
-
-/* maximum insertions between an idle event that we will do without scheduling an idle sort */
-#define ETS_INSERT_MAX (4)
-
-static ETableSubsetClass *ets_parent_class;
-
-static void ets_sort_info_changed (ETableSortInfo *info, ETableSorted *ets);
-static void ets_sort (ETableSorted *ets);
-static void ets_proxy_model_changed (ETableSubset *etss, ETableModel *source);
-static void ets_proxy_model_row_changed (ETableSubset *etss, ETableModel *source, int row);
-static void ets_proxy_model_cell_changed (ETableSubset *etss, ETableModel *source, int col, int row);
-static void ets_proxy_model_rows_inserted (ETableSubset *etss, ETableModel *source, int row, int count);
-static void ets_proxy_model_rows_deleted (ETableSubset *etss, ETableModel *source, int row, int count);
-
-static void
-ets_dispose (GObject *object)
-{
- ETableSorted *ets = E_TABLE_SORTED (object);
-
- if (ets->sort_idle_id)
- g_source_remove(ets->sort_idle_id);
- ets->sort_idle_id = 0;
-
- if (ets->insert_idle_id)
- g_source_remove(ets->insert_idle_id);
- ets->insert_idle_id = 0;
-
- if (ets->sort_info) {
- g_signal_handler_disconnect (G_OBJECT (ets->sort_info),
- ets->sort_info_changed_id);
- g_object_unref(ets->sort_info);
- ets->sort_info = NULL;
- }
-
- if (ets->full_header)
- g_object_unref(ets->full_header);
- ets->full_header = NULL;
-
- G_OBJECT_CLASS (ets_parent_class)->dispose (object);
-}
-
-static void
-ets_class_init (GObjectClass *object_class)
-{
- ETableSubsetClass *etss_class = E_TABLE_SUBSET_CLASS(object_class);
-
- ets_parent_class = g_type_class_peek_parent (object_class);
-
- etss_class->proxy_model_changed = ets_proxy_model_changed;
- etss_class->proxy_model_row_changed = ets_proxy_model_row_changed;
- etss_class->proxy_model_cell_changed = ets_proxy_model_cell_changed;
- etss_class->proxy_model_rows_inserted = ets_proxy_model_rows_inserted;
- etss_class->proxy_model_rows_deleted = ets_proxy_model_rows_deleted;
-
- object_class->dispose = ets_dispose;
-}
-
-static void
-ets_init (ETableSorted *ets)
-{
- ets->full_header = NULL;
- ets->sort_info = NULL;
-
- ets->sort_info_changed_id = 0;
-
- ets->sort_idle_id = 0;
- ets->insert_count = 0;
-}
-
-E_MAKE_TYPE(e_table_sorted, "ETableSorted", ETableSorted, ets_class_init, ets_init, E_TABLE_SUBSET_TYPE)
-
-static gboolean
-ets_sort_idle(ETableSorted *ets)
-{
- g_object_ref(ets);
- ets_sort(ets);
- ets->sort_idle_id = 0;
- ets->insert_count = 0;
- g_object_unref(ets);
- return FALSE;
-}
-
-static gboolean
-ets_insert_idle(ETableSorted *ets)
-{
- ets->insert_count = 0;
- ets->insert_idle_id = 0;
- return FALSE;
-}
-
-ETableModel *
-e_table_sorted_new (ETableModel *source, ETableHeader *full_header, ETableSortInfo *sort_info)
-{
- ETableSorted *ets = g_object_new (E_TABLE_SORTED_TYPE, NULL);
- ETableSubset *etss = E_TABLE_SUBSET (ets);
-
- if (ets_parent_class->proxy_model_pre_change)
- (ets_parent_class->proxy_model_pre_change) (etss, source);
-
- if (e_table_subset_construct (etss, source, 0) == NULL){
- g_object_unref (ets);
- return NULL;
- }
-
- ets->sort_info = sort_info;
- g_object_ref(ets->sort_info);
- ets->full_header = full_header;
- g_object_ref(ets->full_header);
-
- ets_proxy_model_changed(etss, source);
-
- ets->sort_info_changed_id = g_signal_connect (G_OBJECT (sort_info), "sort_info_changed",
- G_CALLBACK (ets_sort_info_changed), ets);
-
- return E_TABLE_MODEL(ets);
-}
-
-static void
-ets_sort_info_changed (ETableSortInfo *info, ETableSorted *ets)
-{
- ets_sort(ets);
-}
-
-static void
-ets_proxy_model_changed (ETableSubset *subset, ETableModel *source)
-{
- int rows, i;
-
- rows = e_table_model_row_count(source);
-
- g_free(subset->map_table);
- subset->n_map = rows;
- subset->map_table = g_new(int, rows);
-
- for (i = 0; i < rows; i++) {
- subset->map_table[i] = i;
- }
-
- if (!E_TABLE_SORTED(subset)->sort_idle_id)
- E_TABLE_SORTED(subset)->sort_idle_id = g_idle_add_full(50, (GSourceFunc) ets_sort_idle, subset, NULL);
-
- e_table_model_changed(E_TABLE_MODEL(subset));
-}
-
-static void
-ets_proxy_model_row_changed (ETableSubset *subset, ETableModel *source, int row)
-{
- if (!E_TABLE_SORTED(subset)->sort_idle_id)
- E_TABLE_SORTED(subset)->sort_idle_id = g_idle_add_full(50, (GSourceFunc) ets_sort_idle, subset, NULL);
-
- if (ets_parent_class->proxy_model_row_changed)
- (ets_parent_class->proxy_model_row_changed) (subset, source, row);
-}
-
-static void
-ets_proxy_model_cell_changed (ETableSubset *subset, ETableModel *source, int col, int row)
-{
- ETableSorted *ets = E_TABLE_SORTED(subset);
- if (e_table_sorting_utils_affects_sort(ets->sort_info, ets->full_header, col))
- ets_proxy_model_row_changed(subset, source, row);
- else if (ets_parent_class->proxy_model_cell_changed)
- (ets_parent_class->proxy_model_cell_changed) (subset, source, col, row);
-}
-
-static void
-ets_proxy_model_rows_inserted (ETableSubset *etss, ETableModel *source, int row, int count)
-{
- ETableModel *etm = E_TABLE_MODEL(etss);
- ETableSorted *ets = E_TABLE_SORTED(etss);
- int i;
- gboolean full_change = FALSE;
-
- if (count == 0) {
- e_table_model_no_change (etm);
- return;
- }
-
- if (row != etss->n_map) {
- full_change = TRUE;
- for (i = 0; i < etss->n_map; i++) {
- if (etss->map_table[i] >= row) {
- etss->map_table[i] += count;
- }
- }
- }
-
- etss->map_table = g_realloc (etss->map_table, (etss->n_map + count) * sizeof(int));
-
- for (; count > 0; count --) {
- if (!full_change)
- e_table_model_pre_change (etm);
- i = etss->n_map;
- if (ets->sort_idle_id == 0) {
- /* this is to see if we're inserting a lot of things between idle loops.
- If we are, we're busy, its faster to just append and perform a full sort later */
- ets->insert_count++;
- if (ets->insert_count > ETS_INSERT_MAX) {
- /* schedule a sort, and append instead */
- ets->sort_idle_id = g_idle_add_full(50, (GSourceFunc) ets_sort_idle, ets, NULL);
- } else {
- /* make sure we have an idle handler to reset the count every now and then */
- if (ets->insert_idle_id == 0) {
- ets->insert_idle_id = g_idle_add_full(40, (GSourceFunc) ets_insert_idle, ets, NULL);
- }
- i = e_table_sorting_utils_insert(etss->source, ets->sort_info, ets->full_header, etss->map_table, etss->n_map, row);
- memmove(etss->map_table + i + 1, etss->map_table + i, (etss->n_map - i) * sizeof(int));
- }
- }
- etss->map_table[i] = row;
- etss->n_map++;
- if (!full_change) {
- e_table_model_row_inserted (etm, i);
- }
-
- d(g_print("inserted row %d", row));
- row++;
- }
- if (full_change)
- e_table_model_changed (etm);
- else
- e_table_model_no_change (etm);
- d(e_table_subset_print_debugging(etss));
-}
-
-static void
-ets_proxy_model_rows_deleted (ETableSubset *etss, ETableModel *source, int row, int count)
-{
- ETableModel *etm = E_TABLE_MODEL(etss);
- int i;
- gboolean shift;
- int j;
-
- shift = row == etss->n_map - count;
-
- for (j = 0; j < count; j++) {
- for (i = 0; i < etss->n_map; i++){
- if (etss->map_table[i] == row + j) {
- if (shift)
- e_table_model_pre_change (etm);
- memmove (etss->map_table + i, etss->map_table + i + 1, (etss->n_map - i - 1) * sizeof(int));
- etss->n_map --;
- if (shift)
- e_table_model_row_deleted (etm, i);
- }
- }
- }
- if (!shift) {
- for (i = 0; i < etss->n_map; i++) {
- if (etss->map_table[i] >= row)
- etss->map_table[i] -= count;
- }
-
- e_table_model_changed (etm);
- } else {
- e_table_model_no_change (etm);
- }
-
- d(g_print("deleted row %d count %d", row, count));
- d(e_table_subset_print_debugging(etss));
-}
-
-static void
-ets_sort(ETableSorted *ets)
-{
- ETableSubset *etss = E_TABLE_SUBSET(ets);
- static int reentering = 0;
- if (reentering)
- return;
- reentering = 1;
-
- e_table_model_pre_change(E_TABLE_MODEL(ets));
-
- e_table_sorting_utils_sort(etss->source, ets->sort_info, ets->full_header, etss->map_table, etss->n_map);
-
- e_table_model_changed (E_TABLE_MODEL(ets));
- reentering = 0;
-}
diff --git a/widgets/table/e-table-sorted.h b/widgets/table/e-table-sorted.h
deleted file mode 100644
index e1265b0a08..0000000000
--- a/widgets/table/e-table-sorted.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-sorted.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_TABLE_SORTED_H_
-#define _E_TABLE_SORTED_H_
-
-#include <glib-object.h>
-#include <gal/e-table/e-table-model.h>
-#include <gal/e-table/e-table-subset.h>
-#include <gal/e-table/e-table-sort-info.h>
-#include <gal/e-table/e-table-header.h>
-
-G_BEGIN_DECLS
-
-#define E_TABLE_SORTED_TYPE (e_table_sorted_get_type ())
-#define E_TABLE_SORTED(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TABLE_SORTED_TYPE, ETableSorted))
-#define E_TABLE_SORTED_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TABLE_SORTED_TYPE, ETableSortedClass))
-#define E_IS_TABLE_SORTED(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TABLE_SORTED_TYPE))
-#define E_IS_TABLE_SORTED_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TABLE_SORTED_TYPE))
-#define E_TABLE_SORTED_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TABLE_SORTED_TYPE, ETableSortedClass))
-
-typedef struct {
- ETableSubset base;
-
- ETableSortInfo *sort_info;
-
- ETableHeader *full_header;
-
- int sort_info_changed_id;
- int sort_idle_id;
- int insert_idle_id;
- int insert_count;
-
-} ETableSorted;
-
-typedef struct {
- ETableSubsetClass parent_class;
-} ETableSortedClass;
-
-GType e_table_sorted_get_type (void);
-ETableModel *e_table_sorted_new (ETableModel *etm, ETableHeader *header, ETableSortInfo *sort_info);
-
-G_END_DECLS
-
-#endif /* _E_TABLE_SORTED_H_ */
diff --git a/widgets/table/e-table-sorter.c b/widgets/table/e-table-sorter.c
deleted file mode 100644
index a92af49f4d..0000000000
--- a/widgets/table/e-table-sorter.c
+++ /dev/null
@@ -1,462 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-sorter.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <stdlib.h>
-#include <string.h>
-#include "gal/util/e-i18n.h"
-#include "gal/util/e-util.h"
-#include "e-table-sorter.h"
-
-#define d(x)
-
-/* The arguments we take */
-enum {
- PROP_0,
- PROP_SORT_INFO
-};
-
-#define PARENT_TYPE e_sorter_get_type()
-
-#define INCREMENT_AMOUNT 100
-
-static ESorterClass *parent_class;
-
-static void ets_model_changed (ETableModel *etm, ETableSorter *ets);
-static void ets_model_row_changed (ETableModel *etm, int row, ETableSorter *ets);
-static void ets_model_cell_changed (ETableModel *etm, int col, int row, ETableSorter *ets);
-static void ets_model_rows_inserted (ETableModel *etm, int row, int count, ETableSorter *ets);
-static void ets_model_rows_deleted (ETableModel *etm, int row, int count, ETableSorter *ets);
-static void ets_sort_info_changed (ETableSortInfo *info, ETableSorter *ets);
-static void ets_clean (ETableSorter *ets);
-static void ets_sort (ETableSorter *ets);
-static void ets_backsort (ETableSorter *ets);
-
-static gint ets_model_to_sorted (ESorter *sorter, int row);
-static gint ets_sorted_to_model (ESorter *sorter, int row);
-static void ets_get_model_to_sorted_array (ESorter *sorter, int **array, int *count);
-static void ets_get_sorted_to_model_array (ESorter *sorter, int **array, int *count);
-static gboolean ets_needs_sorting (ESorter *ets);
-
-static void
-ets_dispose (GObject *object)
-{
- ETableSorter *ets = E_TABLE_SORTER (object);
-
- if (ets->sort_info) {
- if (ets->table_model_changed_id)
- g_signal_handler_disconnect (ets->source,
- ets->table_model_changed_id);
- if (ets->table_model_row_changed_id)
- g_signal_handler_disconnect (ets->source,
- ets->table_model_row_changed_id);
- if (ets->table_model_cell_changed_id)
- g_signal_handler_disconnect (ets->source,
- ets->table_model_cell_changed_id);
- if (ets->table_model_rows_inserted_id)
- g_signal_handler_disconnect (ets->source,
- ets->table_model_rows_inserted_id);
- if (ets->table_model_rows_deleted_id)
- g_signal_handler_disconnect (ets->source,
- ets->table_model_rows_deleted_id);
- if (ets->sort_info_changed_id)
- g_signal_handler_disconnect (ets->sort_info,
- ets->sort_info_changed_id);
- if (ets->group_info_changed_id)
- g_signal_handler_disconnect (ets->sort_info,
- ets->group_info_changed_id);
-
- ets->table_model_changed_id = 0;
- ets->table_model_row_changed_id = 0;
- ets->table_model_cell_changed_id = 0;
- ets->table_model_rows_inserted_id = 0;
- ets->table_model_rows_deleted_id = 0;
- ets->sort_info_changed_id = 0;
- ets->group_info_changed_id = 0;
-
- g_object_unref(ets->sort_info);
- ets->sort_info = NULL;
- }
-
- if (ets->full_header)
- g_object_unref(ets->full_header);
- ets->full_header = NULL;
-
- if (ets->source)
- g_object_unref(ets->source);
- ets->source = NULL;
-
- G_OBJECT_CLASS (parent_class)->dispose (object);
-}
-
-static void
-ets_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
-{
- ETableSorter *ets = E_TABLE_SORTER (object);
-
- switch (prop_id) {
- case PROP_SORT_INFO:
- if (ets->sort_info) {
- if (ets->sort_info_changed_id)
- g_signal_handler_disconnect(ets->sort_info, ets->sort_info_changed_id);
- if (ets->group_info_changed_id)
- g_signal_handler_disconnect(ets->sort_info, ets->group_info_changed_id);
- g_object_unref(ets->sort_info);
- }
-
- ets->sort_info = E_TABLE_SORT_INFO(g_value_get_object (value));
- g_object_ref(ets->sort_info);
- ets->sort_info_changed_id = g_signal_connect (ets->sort_info, "sort_info_changed",
- G_CALLBACK (ets_sort_info_changed), ets);
- ets->group_info_changed_id = g_signal_connect (ets->sort_info, "group_info_changed",
- G_CALLBACK (ets_sort_info_changed), ets);
-
- ets_clean (ets);
- break;
- default:
- break;
- }
-}
-
-static void
-ets_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
-{
- ETableSorter *ets = E_TABLE_SORTER (object);
- switch (prop_id) {
- case PROP_SORT_INFO:
- g_value_set_object (value, ets->sort_info);
- break;
- }
-}
-
-static void
-ets_class_init (ETableSorterClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS(klass);
- ESorterClass *sorter_class = E_SORTER_CLASS(klass);
-
- parent_class = g_type_class_peek_parent (klass);
-
- object_class->dispose = ets_dispose;
- object_class->set_property = ets_set_property;
- object_class->get_property = ets_get_property;
-
- sorter_class->model_to_sorted = ets_model_to_sorted ;
- sorter_class->sorted_to_model = ets_sorted_to_model ;
- sorter_class->get_model_to_sorted_array = ets_get_model_to_sorted_array ;
- sorter_class->get_sorted_to_model_array = ets_get_sorted_to_model_array ;
- sorter_class->needs_sorting = ets_needs_sorting ;
-
- g_object_class_install_property (object_class, PROP_SORT_INFO,
- g_param_spec_object ("sort_info",
- _("Sort Info"),
- /*_( */"XXX blurb" /*)*/,
- E_TABLE_SORT_INFO_TYPE,
- G_PARAM_READWRITE));
-}
-
-static void
-ets_init (ETableSorter *ets)
-{
- ets->full_header = NULL;
- ets->sort_info = NULL;
- ets->source = NULL;
-
- ets->needs_sorting = -1;
-
- ets->table_model_changed_id = 0;
- ets->table_model_row_changed_id = 0;
- ets->table_model_cell_changed_id = 0;
- ets->table_model_rows_inserted_id = 0;
- ets->table_model_rows_deleted_id = 0;
- ets->sort_info_changed_id = 0;
- ets->group_info_changed_id = 0;
-}
-
-E_MAKE_TYPE(e_table_sorter, "ETableSorter", ETableSorter, ets_class_init, ets_init, PARENT_TYPE)
-
-ETableSorter *
-e_table_sorter_new (ETableModel *source, ETableHeader *full_header, ETableSortInfo *sort_info)
-{
- ETableSorter *ets = g_object_new (E_TABLE_SORTER_TYPE, NULL);
-
- ets->sort_info = sort_info;
- g_object_ref(ets->sort_info);
- ets->full_header = full_header;
- g_object_ref(ets->full_header);
- ets->source = source;
- g_object_ref(ets->source);
-
- ets->table_model_changed_id = g_signal_connect (source, "model_changed",
- G_CALLBACK (ets_model_changed), ets);
- ets->table_model_row_changed_id = g_signal_connect (source, "model_row_changed",
- G_CALLBACK (ets_model_row_changed), ets);
- ets->table_model_cell_changed_id = g_signal_connect (source, "model_cell_changed",
- G_CALLBACK (ets_model_cell_changed), ets);
- ets->table_model_rows_inserted_id = g_signal_connect (source, "model_rows_inserted",
- G_CALLBACK (ets_model_rows_inserted), ets);
- ets->table_model_rows_deleted_id = g_signal_connect (source, "model_rows_deleted",
- G_CALLBACK (ets_model_rows_deleted), ets);
- ets->sort_info_changed_id = g_signal_connect (sort_info, "sort_info_changed",
- G_CALLBACK (ets_sort_info_changed), ets);
- ets->group_info_changed_id = g_signal_connect (sort_info, "group_info_changed",
- G_CALLBACK (ets_sort_info_changed), ets);
-
- return ets;
-}
-
-static void
-ets_model_changed (ETableModel *etm, ETableSorter *ets)
-{
- ets_clean(ets);
-}
-
-static void
-ets_model_row_changed (ETableModel *etm, int row, ETableSorter *ets)
-{
- ets_clean(ets);
-}
-
-static void
-ets_model_cell_changed (ETableModel *etm, int col, int row, ETableSorter *ets)
-{
- ets_clean(ets);
-}
-
-static void
-ets_model_rows_inserted (ETableModel *etm, int row, int count, ETableSorter *ets)
-{
- ets_clean(ets);
-}
-
-static void
-ets_model_rows_deleted (ETableModel *etm, int row, int count, ETableSorter *ets)
-{
- ets_clean(ets);
-}
-
-static void
-ets_sort_info_changed (ETableSortInfo *info, ETableSorter *ets)
-{
- d(g_print ("sort info changed\n"));
- ets_clean(ets);
-}
-
-static ETableSorter *ets_closure;
-static void **vals_closure;
-static int cols_closure;
-static int *ascending_closure;
-static GCompareFunc *compare_closure;
-
-/* FIXME: Make it not cache the second and later columns (as if anyone cares.) */
-
-static int
-qsort_callback(const void *data1, const void *data2)
-{
- gint row1 = *(int *)data1;
- gint row2 = *(int *)data2;
- int j;
- int sort_count = e_table_sort_info_sorting_get_count(ets_closure->sort_info) + e_table_sort_info_grouping_get_count(ets_closure->sort_info);
- int comp_val = 0;
- int ascending = 1;
- for (j = 0; j < sort_count; j++) {
- comp_val = (*(compare_closure[j]))(vals_closure[cols_closure * row1 + j], vals_closure[cols_closure * row2 + j]);
- ascending = ascending_closure[j];
- if (comp_val != 0)
- break;
- }
- if (comp_val == 0) {
- if (row1 < row2)
- comp_val = -1;
- if (row1 > row2)
- comp_val = 1;
- }
- if (!ascending)
- comp_val = -comp_val;
- return comp_val;
-}
-
-static void
-ets_clean(ETableSorter *ets)
-{
- g_free(ets->sorted);
- ets->sorted = NULL;
-
- g_free(ets->backsorted);
- ets->backsorted = NULL;
-
- ets->needs_sorting = -1;
-}
-
-
-static void
-ets_sort(ETableSorter *ets)
-{
- int rows;
- int i;
- int j;
- int cols;
- int group_cols;
-
- if (ets->sorted)
- return;
-
- rows = e_table_model_row_count(ets->source);
- group_cols = e_table_sort_info_grouping_get_count(ets->sort_info);
- cols = e_table_sort_info_sorting_get_count(ets->sort_info) + group_cols;
-
- ets->sorted = g_new(int, rows);
- for (i = 0; i < rows; i++)
- ets->sorted[i] = i;
-
- cols_closure = cols;
- ets_closure = ets;
-
- vals_closure = g_new(void *, rows * cols);
- ascending_closure = g_new(int, cols);
- compare_closure = g_new(GCompareFunc, cols);
-
- for (j = 0; j < cols; j++) {
- ETableSortColumn column;
- ETableCol *col;
-
- if (j < group_cols)
- column = e_table_sort_info_grouping_get_nth(ets->sort_info, j);
- else
- column = e_table_sort_info_sorting_get_nth(ets->sort_info, j - group_cols);
-
- col = e_table_header_get_column_by_col_idx(ets->full_header, column.column);
- if (col == NULL)
- col = e_table_header_get_column (ets->full_header, e_table_header_count (ets->full_header) - 1);
-
- for (i = 0; i < rows; i++) {
- vals_closure[i * cols + j] = e_table_model_value_at (ets->source, col->col_idx, i);
- }
-
- compare_closure[j] = col->compare;
- ascending_closure[j] = column.ascending;
- }
-
- qsort(ets->sorted, rows, sizeof(int), qsort_callback);
-
- g_free(vals_closure);
- g_free(ascending_closure);
- g_free(compare_closure);
-}
-
-static void
-ets_backsort(ETableSorter *ets)
-{
- int i, rows;
-
- if (ets->backsorted)
- return;
-
- ets_sort(ets);
-
- rows = e_table_model_row_count(ets->source);
- ets->backsorted = g_new0(int, rows);
-
- for (i = 0; i < rows; i++) {
- ets->backsorted[ets->sorted[i]] = i;
- }
-}
-
-
-static gint
-ets_model_to_sorted (ESorter *es, int row)
-{
- ETableSorter *ets = E_TABLE_SORTER(es);
- int rows = e_table_model_row_count(ets->source);
-
- g_return_val_if_fail(row >= 0, -1);
- g_return_val_if_fail(row < rows, -1);
-
- if (ets_needs_sorting(es))
- ets_backsort(ets);
-
- if (ets->backsorted)
- return ets->backsorted[row];
- else
- return row;
-}
-
-static gint
-ets_sorted_to_model (ESorter *es, int row)
-{
- ETableSorter *ets = E_TABLE_SORTER(es);
- int rows = e_table_model_row_count(ets->source);
-
- g_return_val_if_fail(row >= 0, -1);
- g_return_val_if_fail(row < rows, -1);
-
- if (ets_needs_sorting(es))
- ets_sort(ets);
-
- if (ets->sorted)
- return ets->sorted[row];
- else
- return row;
-}
-
-static void
-ets_get_model_to_sorted_array (ESorter *es, int **array, int *count)
-{
- ETableSorter *ets = E_TABLE_SORTER(es);
- if (array || count) {
- ets_backsort(ets);
-
- if (array)
- *array = ets->backsorted;
- if (count)
- *count = e_table_model_row_count(ets->source);
- }
-}
-
-static void
-ets_get_sorted_to_model_array (ESorter *es, int **array, int *count)
-{
- ETableSorter *ets = E_TABLE_SORTER(es);
- if (array || count) {
- ets_sort(ets);
-
- if (array)
- *array = ets->sorted;
- if (count)
- *count = e_table_model_row_count(ets->source);
- }
-}
-
-
-static gboolean
-ets_needs_sorting(ESorter *es)
-{
- ETableSorter *ets = E_TABLE_SORTER(es);
- if (ets->needs_sorting < 0) {
- if (e_table_sort_info_sorting_get_count(ets->sort_info) + e_table_sort_info_grouping_get_count(ets->sort_info))
- ets->needs_sorting = 1;
- else
- ets->needs_sorting = 0;
- }
- return ets->needs_sorting;
-}
diff --git a/widgets/table/e-table-sorter.h b/widgets/table/e-table-sorter.h
deleted file mode 100644
index 67be48715a..0000000000
--- a/widgets/table/e-table-sorter.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-sorter.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_TABLE_SORTER_H_
-#define _E_TABLE_SORTER_H_
-
-#include <glib-object.h>
-#include <gal/util/e-sorter.h>
-#include <gal/e-table/e-table-model.h>
-#include <gal/e-table/e-table-subset-variable.h>
-#include <gal/e-table/e-table-sort-info.h>
-#include <gal/e-table/e-table-header.h>
-
-G_BEGIN_DECLS
-
-#define E_TABLE_SORTER_TYPE (e_table_sorter_get_type ())
-#define E_TABLE_SORTER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TABLE_SORTER_TYPE, ETableSorter))
-#define E_TABLE_SORTER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TABLE_SORTER_TYPE, ETableSorterClass))
-#define E_IS_TABLE_SORTER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TABLE_SORTER_TYPE))
-#define E_IS_TABLE_SORTER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TABLE_SORTER_TYPE))
-
-typedef struct {
- ESorter base;
-
- ETableModel *source;
- ETableHeader *full_header;
- ETableSortInfo *sort_info;
-
- /* If needs_sorting is 0, then model_to_sorted and sorted_to_model are no-ops. */
- int needs_sorting;
-
- int *sorted;
- int *backsorted;
-
- int table_model_changed_id;
- int table_model_row_changed_id;
- int table_model_cell_changed_id;
- int table_model_rows_inserted_id;
- int table_model_rows_deleted_id;
- int sort_info_changed_id;
- int group_info_changed_id;
-} ETableSorter;
-
-typedef struct {
- ESorterClass parent_class;
-} ETableSorterClass;
-
-GType e_table_sorter_get_type (void);
-ETableSorter *e_table_sorter_new (ETableModel *etm,
- ETableHeader *full_header,
- ETableSortInfo *sort_info);
-G_END_DECLS
-
-#endif /* _E_TABLE_SORTER_H_ */
diff --git a/widgets/table/e-table-sorting-utils.c b/widgets/table/e-table-sorting-utils.c
deleted file mode 100644
index 80a9564a36..0000000000
--- a/widgets/table/e-table-sorting-utils.c
+++ /dev/null
@@ -1,349 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-sorting-utils.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <string.h>
-#include <e-table-sorting-utils.h>
-#include <gal/util/e-util.h>
-
-#define d(x)
-
-/* This takes source rows. */
-static int
-etsu_compare(ETableModel *source, ETableSortInfo *sort_info, ETableHeader *full_header, int row1, int row2)
-{
- int j;
- int sort_count = e_table_sort_info_sorting_get_count(sort_info);
- int comp_val = 0;
- int ascending = 1;
-
- for (j = 0; j < sort_count; j++) {
- ETableSortColumn column = e_table_sort_info_sorting_get_nth(sort_info, j);
- ETableCol *col;
- col = e_table_header_get_column_by_col_idx(full_header, column.column);
- if (col == NULL)
- col = e_table_header_get_column (full_header, e_table_header_count (full_header) - 1);
- comp_val = (*col->compare)(e_table_model_value_at (source, col->compare_col, row1),
- e_table_model_value_at (source, col->compare_col, row2));
- ascending = column.ascending;
- if (comp_val != 0)
- break;
- }
- if (comp_val == 0) {
- if (row1 < row2)
- comp_val = -1;
- if (row1 > row2)
- comp_val = 1;
- }
- if (!ascending)
- comp_val = -comp_val;
- return comp_val;
-}
-
-typedef struct {
- int cols;
- void **vals;
- int *ascending;
- GCompareFunc *compare;
-} ETableSortClosure;
-
-typedef struct {
- ETreeModel *tree;
- ETableSortInfo *sort_info;
- ETableHeader *full_header;
-} ETreeSortClosure;
-
-/* FIXME: Make it not cache the second and later columns (as if anyone cares.) */
-
-static int
-e_sort_callback(const void *data1, const void *data2, gpointer user_data)
-{
- gint row1 = *(int *)data1;
- gint row2 = *(int *)data2;
- ETableSortClosure *closure = user_data;
- int j;
- int sort_count = closure->cols;
- int comp_val = 0;
- int ascending = 1;
- for (j = 0; j < sort_count; j++) {
- comp_val = (*(closure->compare[j]))(closure->vals[closure->cols * row1 + j], closure->vals[closure->cols * row2 + j]);
- ascending = closure->ascending[j];
- if (comp_val != 0)
- break;
- }
- if (comp_val == 0) {
- if (row1 < row2)
- comp_val = -1;
- if (row1 > row2)
- comp_val = 1;
- }
- if (!ascending)
- comp_val = -comp_val;
- return comp_val;
-}
-
-void
-e_table_sorting_utils_sort(ETableModel *source, ETableSortInfo *sort_info, ETableHeader *full_header, int *map_table, int rows)
-{
- int total_rows;
- int i;
- int j;
- int cols;
- ETableSortClosure closure;
-
- g_return_if_fail(source != NULL);
- g_return_if_fail(E_IS_TABLE_MODEL(source));
- g_return_if_fail(sort_info != NULL);
- g_return_if_fail(E_IS_TABLE_SORT_INFO(sort_info));
- g_return_if_fail(full_header != NULL);
- g_return_if_fail(E_IS_TABLE_HEADER(full_header));
-
- total_rows = e_table_model_row_count(source);
- cols = e_table_sort_info_sorting_get_count(sort_info);
- closure.cols = cols;
-
- closure.vals = g_new(void *, total_rows * cols);
- closure.ascending = g_new(int, cols);
- closure.compare = g_new(GCompareFunc, cols);
-
- for (j = 0; j < cols; j++) {
- ETableSortColumn column = e_table_sort_info_sorting_get_nth(sort_info, j);
- ETableCol *col;
- col = e_table_header_get_column_by_col_idx(full_header, column.column);
- if (col == NULL)
- col = e_table_header_get_column (full_header, e_table_header_count (full_header) - 1);
- for (i = 0; i < rows; i++) {
- closure.vals[map_table[i] * cols + j] = e_table_model_value_at (source, col->compare_col, map_table[i]);
- }
- closure.compare[j] = col->compare;
- closure.ascending[j] = column.ascending;
- }
-
- e_sort(map_table, rows, sizeof(int), e_sort_callback, &closure);
-
- g_free(closure.vals);
- g_free(closure.ascending);
- g_free(closure.compare);
-}
-
-gboolean
-e_table_sorting_utils_affects_sort (ETableSortInfo *sort_info,
- ETableHeader *full_header,
- int col)
-{
- int j;
- int cols;
-
- g_return_val_if_fail(sort_info != NULL, TRUE);
- g_return_val_if_fail(E_IS_TABLE_SORT_INFO(sort_info), TRUE);
- g_return_val_if_fail(full_header != NULL, TRUE);
- g_return_val_if_fail(E_IS_TABLE_HEADER(full_header), TRUE);
-
- cols = e_table_sort_info_sorting_get_count(sort_info);
-
- for (j = 0; j < cols; j++) {
- ETableSortColumn column = e_table_sort_info_sorting_get_nth(sort_info, j);
- ETableCol *tablecol;
- tablecol = e_table_header_get_column_by_col_idx(full_header, column.column);
- if (tablecol == NULL)
- tablecol = e_table_header_get_column (full_header, e_table_header_count (full_header) - 1);
- if (col == tablecol->compare_col)
- return TRUE;
- }
- return FALSE;
-}
-
-
-/* FIXME: This could be done in time log n instead of time n with a binary search. */
-int
-e_table_sorting_utils_insert(ETableModel *source, ETableSortInfo *sort_info, ETableHeader *full_header, int *map_table, int rows, int row)
-{
- int i;
-
- i = 0;
- /* handle insertions when we have a 'sort group' */
- while (i < rows && etsu_compare(source, sort_info, full_header, map_table[i], row) < 0)
- i++;
-
- return i;
-}
-
-/* FIXME: This could be done in time log n instead of time n with a binary search. */
-int
-e_table_sorting_utils_check_position (ETableModel *source, ETableSortInfo *sort_info, ETableHeader *full_header, int *map_table, int rows, int view_row)
-{
- int i;
- int row;
-
- i = view_row;
- row = map_table[i];
-
- i = view_row;
- if (i < rows - 1 && etsu_compare(source, sort_info, full_header, map_table[i + 1], row) < 0) {
- i ++;
- while (i < rows - 1 && etsu_compare(source, sort_info, full_header, map_table[i], row) < 0)
- i ++;
- } else if (i > 0 && etsu_compare(source, sort_info, full_header, map_table[i - 1], row) > 0) {
- i --;
- while (i > 0 && etsu_compare(source, sort_info, full_header, map_table[i], row) > 0)
- i --;
- }
- return i;
-}
-
-
-
-
-/* This takes source rows. */
-static int
-etsu_tree_compare(ETreeModel *source, ETableSortInfo *sort_info, ETableHeader *full_header, ETreePath path1, ETreePath path2)
-{
- int j;
- int sort_count = e_table_sort_info_sorting_get_count(sort_info);
- int comp_val = 0;
- int ascending = 1;
-
- for (j = 0; j < sort_count; j++) {
- ETableSortColumn column = e_table_sort_info_sorting_get_nth(sort_info, j);
- ETableCol *col;
- col = e_table_header_get_column_by_col_idx(full_header, column.column);
- if (col == NULL)
- col = e_table_header_get_column (full_header, e_table_header_count (full_header) - 1);
- comp_val = (*col->compare)(e_tree_model_value_at (source, path1, col->compare_col),
- e_tree_model_value_at (source, path2, col->compare_col));
- ascending = column.ascending;
- if (comp_val != 0)
- break;
- }
- if (!ascending)
- comp_val = -comp_val;
- return comp_val;
-}
-
-static int
-e_sort_tree_callback(const void *data1, const void *data2, gpointer user_data)
-{
- ETreePath *path1 = *(ETreePath *)data1;
- ETreePath *path2 = *(ETreePath *)data2;
- ETreeSortClosure *closure = user_data;
-
- return etsu_tree_compare(closure->tree, closure->sort_info, closure->full_header, path1, path2);
-}
-
-void
-e_table_sorting_utils_tree_sort(ETreeModel *source, ETableSortInfo *sort_info, ETableHeader *full_header, ETreePath *map_table, int count)
-{
- ETableSortClosure closure;
- int cols;
- int i, j;
- int *map;
- ETreePath *map_copy;
- g_return_if_fail(source != NULL);
- g_return_if_fail(E_IS_TREE_MODEL(source));
- g_return_if_fail(sort_info != NULL);
- g_return_if_fail(E_IS_TABLE_SORT_INFO(sort_info));
- g_return_if_fail(full_header != NULL);
- g_return_if_fail(E_IS_TABLE_HEADER(full_header));
-
- cols = e_table_sort_info_sorting_get_count(sort_info);
- closure.cols = cols;
-
- closure.vals = g_new(void *, count * cols);
- closure.ascending = g_new(int, cols);
- closure.compare = g_new(GCompareFunc, cols);
-
- for (j = 0; j < cols; j++) {
- ETableSortColumn column = e_table_sort_info_sorting_get_nth(sort_info, j);
- ETableCol *col;
-
- col = e_table_header_get_column_by_col_idx(full_header, column.column);
- if (col == NULL)
- col = e_table_header_get_column (full_header, e_table_header_count (full_header) - 1);
-
- for (i = 0; i < count; i++) {
- closure.vals[i * cols + j] = e_tree_model_value_at (source, map_table[i], col->compare_col);
- }
- closure.ascending[j] = column.ascending;
- closure.compare[j] = col->compare;
- }
-
- map = g_new(int, count);
- for (i = 0; i < count; i++) {
- map[i] = i;
- }
-
- e_sort(map, count, sizeof(int), e_sort_callback, &closure);
-
- map_copy = g_new(ETreePath, count);
- for (i = 0; i < count; i++) {
- map_copy[i] = map_table[i];
- }
- for (i = 0; i < count; i++) {
- map_table[i] = map_copy[map[i]];
- }
-
- g_free(map);
- g_free(map_copy);
-
- g_free(closure.vals);
- g_free(closure.ascending);
- g_free(closure.compare);
-}
-
-/* FIXME: This could be done in time log n instead of time n with a binary search. */
-int
-e_table_sorting_utils_tree_check_position (ETreeModel *source, ETableSortInfo *sort_info, ETableHeader *full_header, ETreePath *map_table, int count, int old_index)
-{
- int i;
- ETreePath path;
-
- i = old_index;
- path = map_table[i];
-
- if (i < count - 1 && etsu_tree_compare(source, sort_info, full_header, map_table[i + 1], path) < 0) {
- i ++;
- while (i < count - 1 && etsu_tree_compare(source, sort_info, full_header, map_table[i], path) < 0)
- i ++;
- } else if (i > 0 && etsu_tree_compare(source, sort_info, full_header, map_table[i - 1], path) > 0) {
- i --;
- while (i > 0 && etsu_tree_compare(source, sort_info, full_header, map_table[i], path) > 0)
- i --;
- }
- return i;
-}
-
-/* FIXME: This does not pay attention to making sure that it's a stable insert. This needs to be fixed. */
-int
-e_table_sorting_utils_tree_insert(ETreeModel *source, ETableSortInfo *sort_info, ETableHeader *full_header, ETreePath *map_table, int count, ETreePath path)
-{
- size_t start;
- size_t end;
- ETreeSortClosure closure;
-
- closure.tree = source;
- closure.sort_info = sort_info;
- closure.full_header = full_header;
-
- e_bsearch(&path, map_table, count, sizeof(ETreePath), e_sort_tree_callback, &closure, &start, &end);
- return end;
-}
diff --git a/widgets/table/e-table-sorting-utils.h b/widgets/table/e-table-sorting-utils.h
deleted file mode 100644
index 794ead0ac9..0000000000
--- a/widgets/table/e-table-sorting-utils.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-sorting-utils.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_TABLE_SORTING_UTILS_H_
-#define _E_TABLE_SORTING_UTILS_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-#include <gal/e-table/e-table-model.h>
-#include <gal/e-table/e-tree-model.h>
-#include <gal/e-table/e-table-sort-info.h>
-#include <gal/e-table/e-table-header.h>
-gboolean e_table_sorting_utils_affects_sort (ETableSortInfo *sort_info,
- ETableHeader *full_header,
- int col);
-
-
-
-void e_table_sorting_utils_sort (ETableModel *source,
- ETableSortInfo *sort_info,
- ETableHeader *full_header,
- int *map_table,
- int rows);
-int e_table_sorting_utils_insert (ETableModel *source,
- ETableSortInfo *sort_info,
- ETableHeader *full_header,
- int *map_table,
- int rows,
- int row);
-int e_table_sorting_utils_check_position (ETableModel *source,
- ETableSortInfo *sort_info,
- ETableHeader *full_header,
- int *map_table,
- int rows,
- int view_row);
-
-
-
-void e_table_sorting_utils_tree_sort (ETreeModel *source,
- ETableSortInfo *sort_info,
- ETableHeader *full_header,
- ETreePath *map_table,
- int count);
-int e_table_sorting_utils_tree_check_position (ETreeModel *source,
- ETableSortInfo *sort_info,
- ETableHeader *full_header,
- ETreePath *map_table,
- int count,
- int old_index);
-int e_table_sorting_utils_tree_insert (ETreeModel *source,
- ETableSortInfo *sort_info,
- ETableHeader *full_header,
- ETreePath *map_table,
- int count,
- ETreePath path);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* _E_TABLE_SORTING_UTILS_H_ */
diff --git a/widgets/table/e-table-specification.c b/widgets/table/e-table-specification.c
deleted file mode 100644
index 3fcc28689d..0000000000
--- a/widgets/table/e-table-specification.c
+++ /dev/null
@@ -1,432 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-specification.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "e-table-specification.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-#include <libxml/parser.h>
-#include <libxml/xmlmemory.h>
-#include "gal/util/e-util.h"
-#include "gal/util/e-xml-utils.h"
-
-static GObjectClass *etsp_parent_class;
-
-static void
-etsp_finalize (GObject *object)
-{
- ETableSpecification *etsp = E_TABLE_SPECIFICATION (object);
- int i;
-
- if (etsp->columns) {
- for (i = 0; etsp->columns[i]; i++) {
- g_object_unref (etsp->columns[i]);
- }
- g_free (etsp->columns);
- etsp->columns = NULL;
- }
-
- if (etsp->state)
- g_object_unref (etsp->state);
- etsp->state = NULL;
-
- g_free (etsp->click_to_add_message);
- etsp->click_to_add_message = NULL;
-
- g_free (etsp->domain);
- etsp->domain = NULL;
-
- etsp_parent_class->finalize (object);
-}
-
-static void
-etsp_class_init (GObjectClass *klass)
-{
- etsp_parent_class = g_type_class_peek_parent (klass);
-
- klass->finalize = etsp_finalize;
-}
-
-static void
-etsp_init (ETableSpecification *etsp)
-{
- etsp->columns = NULL;
- etsp->state = NULL;
-
- etsp->alternating_row_colors = TRUE;
- etsp->no_headers = FALSE;
- etsp->click_to_add = FALSE;
- etsp->click_to_add_end = FALSE;
- etsp->horizontal_draw_grid = FALSE;
- etsp->vertical_draw_grid = FALSE;
- etsp->draw_focus = TRUE;
- etsp->horizontal_scrolling = FALSE;
- etsp->horizontal_resize = FALSE;
- etsp->allow_grouping = TRUE;
-
- etsp->cursor_mode = E_CURSOR_SIMPLE;
- etsp->selection_mode = GTK_SELECTION_MULTIPLE;
-
- etsp->click_to_add_message = NULL;
- etsp->domain = NULL;
-}
-
-E_MAKE_TYPE (e_table_specification, "ETableSpecification", ETableSpecification, etsp_class_init, etsp_init, G_TYPE_OBJECT)
-
-/**
- * e_table_specification_new:
- *
- * Creates a new %ETableSpecification object. This object is used to hold the
- * information about the rendering information for ETable.
- *
- * Returns: a newly created %ETableSpecification object.
- */
-ETableSpecification *
-e_table_specification_new (void)
-{
- ETableSpecification *etsp = g_object_new (E_TABLE_SPECIFICATION_TYPE, NULL);
-
- return (ETableSpecification *) etsp;
-}
-
-/**
- * e_table_specification_load_from_file:
- * @specification: An ETableSpecification that you want to modify
- * @filename: a filename that contains an ETableSpecification
- *
- * This routine modifies @specification to reflect the state described
- * by the file @filename.
- *
- * Returns: TRUE on success, FALSE on failure.
- */
-gboolean
-e_table_specification_load_from_file (ETableSpecification *specification,
- const char *filename)
-{
- xmlDoc *doc;
-
- if (!g_file_test (filename, G_FILE_TEST_EXISTS))
- return FALSE;
-
- doc = xmlParseFile (filename);
- if (doc) {
- xmlNode *node = xmlDocGetRootElement (doc);
- e_table_specification_load_from_node (specification, node);
- xmlFreeDoc (doc);
- return TRUE;
- }
- return FALSE;
-}
-
-/**
- * e_table_specification_load_from_string:
- * @specification: An ETableSpecification that you want to modify
- * @xml: a stringified representation of an ETableSpecification description.
- *
- * This routine modifies @specification to reflect the state described
- * by @xml. @xml is typically returned by e_table_specification_save_to_string
- * or it can be embedded in your source code.
- *
- * Returns: TRUE on success, FALSE on failure.
- */
-gboolean
-e_table_specification_load_from_string (ETableSpecification *specification,
- const char *xml)
-{
- xmlDoc *doc;
- doc = xmlParseMemory ( (char *) xml, strlen (xml));
- if (doc) {
- xmlNode *node = xmlDocGetRootElement (doc);
- e_table_specification_load_from_node (specification, node);
- xmlFreeDoc (doc);
- return TRUE;
- }
-
- return FALSE;
-}
-
-/**
- * e_table_specification_load_from_node:
- * @specification: An ETableSpecification that you want to modify
- * @node: an xmlNode with an XML ETableSpecification description.
- *
- * This routine modifies @specification to reflect the state described
- * by @node.
- */
-void
-e_table_specification_load_from_node (ETableSpecification *specification,
- const xmlNode *node)
-{
- char *temp;
- xmlNode *children;
- GList *list = NULL, *list2;
- int i;
-
- specification->no_headers = e_xml_get_bool_prop_by_name (node, "no-headers");
- specification->click_to_add = e_xml_get_bool_prop_by_name (node, "click-to-add");
- specification->click_to_add_end = e_xml_get_bool_prop_by_name (node, "click-to-add-end") && specification->click_to_add;
- specification->alternating_row_colors = e_xml_get_bool_prop_by_name_with_default (node, "alternating-row-colors", TRUE);
- specification->horizontal_draw_grid = e_xml_get_bool_prop_by_name (node, "horizontal-draw-grid");
- specification->vertical_draw_grid = e_xml_get_bool_prop_by_name (node, "vertical-draw-grid");
- if (e_xml_get_bool_prop_by_name_with_default(node, "draw-grid", TRUE) ==
- e_xml_get_bool_prop_by_name_with_default(node, "draw-grid", FALSE)) {
- specification->horizontal_draw_grid =
- specification->vertical_draw_grid = e_xml_get_bool_prop_by_name (node, "draw-grid");
- }
- specification->draw_focus = e_xml_get_bool_prop_by_name_with_default (node, "draw-focus", TRUE);
- specification->horizontal_scrolling = e_xml_get_bool_prop_by_name_with_default (node, "horizontal-scrolling", FALSE);
- specification->horizontal_resize = e_xml_get_bool_prop_by_name_with_default (node, "horizontal-resize", FALSE);
- specification->allow_grouping = e_xml_get_bool_prop_by_name_with_default (node, "allow-grouping", TRUE);
-
- specification->selection_mode = GTK_SELECTION_MULTIPLE;
- temp = e_xml_get_string_prop_by_name (node, "selection-mode");
- if (temp && !g_strcasecmp (temp, "single")) {
- specification->selection_mode = GTK_SELECTION_SINGLE;
- } else if (temp && !g_strcasecmp (temp, "browse")) {
- specification->selection_mode = GTK_SELECTION_BROWSE;
- } else if (temp && !g_strcasecmp (temp, "extended")) {
- specification->selection_mode = GTK_SELECTION_EXTENDED;
- }
- g_free (temp);
-
- specification->cursor_mode = E_CURSOR_SIMPLE;
- temp = e_xml_get_string_prop_by_name (node, "cursor-mode");
- if (temp && !g_strcasecmp (temp, "line")) {
- specification->cursor_mode = E_CURSOR_LINE;
- } else if (temp && !g_strcasecmp (temp, "spreadsheet")) {
- specification->cursor_mode = E_CURSOR_SPREADSHEET;
- }
- g_free (temp);
-
- g_free (specification->click_to_add_message);
- specification->click_to_add_message =
- e_xml_get_string_prop_by_name (
- node, "_click-to-add-message");
-
- g_free (specification->domain);
- specification->domain =
- e_xml_get_string_prop_by_name (
- node, "gettext-domain");
- if (specification->domain && !*specification->domain) {
- g_free (specification->domain);
- specification->domain = NULL;
- }
-
- if (specification->state)
- g_object_unref (specification->state);
- specification->state = NULL;
- if (specification->columns) {
- for (i = 0; specification->columns[i]; i++) {
- g_object_unref (specification->columns[i]);
- }
- g_free (specification->columns);
- }
- specification->columns = NULL;
-
- for (children = node->xmlChildrenNode; children; children = children->next) {
- if (!strcmp (children->name, "ETableColumn")) {
- ETableColumnSpecification *col_spec = e_table_column_specification_new ();
-
- e_table_column_specification_load_from_node (col_spec, children);
- list = g_list_append (list, col_spec);
- } else if (specification->state == NULL && !strcmp (children->name, "ETableState")) {
- specification->state = e_table_state_new ();
- e_table_state_load_from_node (specification->state, children);
- e_table_sort_info_set_can_group (specification->state->sort_info, specification->allow_grouping);
- }
- }
-
- if (specification->state == NULL) {
- /* Make the default state. */
- specification->state = e_table_state_vanilla (g_list_length (list));
- }
-
- specification->columns = g_new (ETableColumnSpecification *, g_list_length (list) + 1);
- for (list2 = list, i = 0; list2; list2 = g_list_next (list2), i++) {
- specification->columns[i] = list2->data;
- }
- specification->columns[i] = NULL;
- g_list_free (list);
-}
-
-/**
- * e_table_specification_save_to_file:
- * @specification: An %ETableSpecification that you want to save
- * @filename: a file name to store the specification.
- *
- * This routine stores the @specification into @filename.
- *
- * Returns: 0 on success or -1 on error.
- */
-int
-e_table_specification_save_to_file (ETableSpecification *specification,
- const char *filename)
-{
- xmlDoc *doc;
- int ret;
-
- g_return_val_if_fail (specification != NULL, -1);
- g_return_val_if_fail (filename != NULL, -1);
- g_return_val_if_fail (E_IS_TABLE_SPECIFICATION (specification), -1);
-
- if ((doc = xmlNewDoc ("1.0")) == NULL)
- return -1;
-
- xmlDocSetRootElement (doc, e_table_specification_save_to_node (specification, doc));
-
- ret = e_xml_save_file (filename, doc);
-
- xmlFreeDoc (doc);
-
- return ret;
-}
-
-/**
- * e_table_specification_save_to_string:
- * @specification: An %ETableSpecification that you want to stringify
- *
- * Saves the state of @specification to a string.
- *
- * Returns: an g_alloc() allocated string containing the stringified
- * representation of @specification. This stringified representation
- * uses XML as a convenience.
- */
-char *
-e_table_specification_save_to_string (ETableSpecification *specification)
-{
- char *ret_val;
- xmlChar *string;
- int length;
- xmlDoc *doc;
-
- g_return_val_if_fail (specification != NULL, NULL);
- g_return_val_if_fail (E_IS_TABLE_SPECIFICATION (specification), NULL);
-
- doc = xmlNewDoc ("1.0");
- xmlDocSetRootElement (doc, e_table_specification_save_to_node (specification, doc));
- xmlDocDumpMemory (doc, &string, &length);
-
- ret_val = g_strdup (string);
- xmlFree (string);
- return ret_val;
-}
-
-/**
- * e_table_specification_save_to_node:
- * @specification: An ETableSpecification that you want to store.
- * @doc: Node where the specification is saved
- *
- * This routine saves the %ETableSpecification state in the object @specification
- * into the xmlDoc represented by @doc.
- *
- * Returns: The node that has been attached to @doc with the contents
- * of the ETableSpecification.
- */
-xmlNode *
-e_table_specification_save_to_node (ETableSpecification *specification,
- xmlDoc *doc)
-{
- xmlNode *node;
- char *s;
-
- g_return_val_if_fail (doc != NULL, NULL);
- g_return_val_if_fail (specification != NULL, NULL);
- g_return_val_if_fail (E_IS_TABLE_SPECIFICATION (specification), NULL);
-
- node = xmlNewNode (NULL, "ETableSpecification");
- e_xml_set_bool_prop_by_name (node, "no-headers", specification->no_headers);
- e_xml_set_bool_prop_by_name (node, "click-to-add", specification->click_to_add);
- e_xml_set_bool_prop_by_name (node, "click-to-add-end", specification->click_to_add_end && specification->click_to_add);
- e_xml_set_bool_prop_by_name (node, "alternating-row-colors", specification->alternating_row_colors);
- e_xml_set_bool_prop_by_name (node, "horizontal-draw-grid", specification->horizontal_draw_grid);
- e_xml_set_bool_prop_by_name (node, "vertical-draw-grid", specification->vertical_draw_grid);
- e_xml_set_bool_prop_by_name (node, "draw-focus", specification->draw_focus);
- e_xml_set_bool_prop_by_name (node, "horizontal-scrolling", specification->horizontal_scrolling);
- e_xml_set_bool_prop_by_name (node, "horizontal-resize", specification->horizontal_resize);
- e_xml_set_bool_prop_by_name (node, "allow-grouping", specification->allow_grouping);
-
- switch (specification->selection_mode){
- case GTK_SELECTION_SINGLE:
- s = "single";
- break;
- case GTK_SELECTION_BROWSE:
- s = "browse";
- break;
- default:
- case GTK_SELECTION_EXTENDED:
- s = "extended";
- }
- xmlSetProp (node, "selection-mode", s);
- if (specification->cursor_mode == E_CURSOR_LINE)
- s = "line";
- else
- s = "cell";
- xmlSetProp (node, "cursor-mode", s);
-
- xmlSetProp (node, "_click-to-add-message", specification->click_to_add_message);
- xmlSetProp (node, "gettext-domain", specification->domain);
-
- if (specification->columns){
- int i;
-
- for (i = 0; specification->columns [i]; i++)
- e_table_column_specification_save_to_node (
- specification->columns [i],
- node);
- }
-
- if (specification->state)
- e_table_state_save_to_node (specification->state, node);
-
- return node;
-}
-
-/**
- * e_table_specification_duplicate:
- * @spec: specification to duplicate
- *
- * This creates a copy of the %ETableSpecification @spec
- *
- * Returns: The duplicated %ETableSpecification.
- */
-ETableSpecification *
-e_table_specification_duplicate (ETableSpecification *spec)
-{
- ETableSpecification *new_spec;
- char *spec_str;
-
- g_return_val_if_fail (spec != NULL, NULL);
- g_return_val_if_fail (E_IS_TABLE_SPECIFICATION (spec), NULL);
-
- new_spec = e_table_specification_new ();
- spec_str = e_table_specification_save_to_string (spec);
- e_table_specification_load_from_string (new_spec, spec_str);
- g_free (spec_str);
-
- return new_spec;
-}
diff --git a/widgets/table/e-table-specification.h b/widgets/table/e-table-specification.h
deleted file mode 100644
index 961752b9b8..0000000000
--- a/widgets/table/e-table-specification.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-specification.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_TABLE_SPECIFICATION_H_
-#define _E_TABLE_SPECIFICATION_H_
-
-#include <glib-object.h>
-#include <libxml/tree.h>
-#include <gal/widgets/e-selection-model.h>
-#include <gal/e-table/e-table-state.h>
-#include <gal/e-table/e-table-column-specification.h>
-#include <gal/e-table/e-table-defines.h>
-
-G_BEGIN_DECLS
-
-#define E_TABLE_SPECIFICATION_TYPE (e_table_specification_get_type ())
-#define E_TABLE_SPECIFICATION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TABLE_SPECIFICATION_TYPE, ETableSpecification))
-#define E_TABLE_SPECIFICATION_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TABLE_SPECIFICATION_TYPE, ETableSpecificationClass))
-#define E_IS_TABLE_SPECIFICATION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TABLE_SPECIFICATION_TYPE))
-#define E_IS_TABLE_SPECIFICATION_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TABLE_SPECIFICATION_TYPE))
-#define E_TABLE_SPECIFICATION_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), E_TABLE_SPECIFICATION_TYPE, ETableSpecificationClass))
-
-typedef struct {
- GObject base;
-
- ETableColumnSpecification **columns;
- ETableState *state;
-
- guint alternating_row_colors : 1;
- guint no_headers : 1;
- guint click_to_add : 1;
- guint click_to_add_end : 1;
- guint horizontal_draw_grid : 1;
- guint vertical_draw_grid : 1;
- guint draw_focus : 1;
- guint horizontal_scrolling : 1;
- guint horizontal_resize : 1;
- guint allow_grouping : 1;
- GtkSelectionMode selection_mode;
- ECursorMode cursor_mode;
-
- char *click_to_add_message;
- char *domain;
-} ETableSpecification;
-
-typedef struct {
- GObjectClass parent_class;
-} ETableSpecificationClass;
-
-GType e_table_specification_get_type (void);
-ETableSpecification *e_table_specification_new (void);
-
-gboolean e_table_specification_load_from_file (ETableSpecification *specification,
- const char *filename);
-gboolean e_table_specification_load_from_string (ETableSpecification *specification,
- const char *xml);
-void e_table_specification_load_from_node (ETableSpecification *specification,
- const xmlNode *node);
-
-int e_table_specification_save_to_file (ETableSpecification *specification,
- const char *filename);
-char *e_table_specification_save_to_string (ETableSpecification *specification);
-xmlNode *e_table_specification_save_to_node (ETableSpecification *specification,
- xmlDoc *doc);
-ETableSpecification *e_table_specification_duplicate (ETableSpecification *spec);
-
-G_END_DECLS
-
-#endif /* _E_TABLE_SPECIFICATION_H_ */
diff --git a/widgets/table/e-table-state.c b/widgets/table/e-table-state.c
deleted file mode 100644
index c66e5933e0..0000000000
--- a/widgets/table/e-table-state.c
+++ /dev/null
@@ -1,299 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-state.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdlib.h>
-#include <string.h>
-
-#include <libxml/parser.h>
-#include <libxml/xmlmemory.h>
-#include "gal/util/e-util.h"
-#include "gal/util/e-xml-utils.h"
-#include "e-table-state.h"
-
-
-#define STATE_VERSION 0.1
-
-static GObjectClass *etst_parent_class;
-
-static void
-etst_dispose (GObject *object)
-{
- ETableState *etst = E_TABLE_STATE (object);
-
- if (etst->sort_info) {
- g_object_unref (etst->sort_info);
- etst->sort_info = NULL;
- }
-
- G_OBJECT_CLASS (etst_parent_class)->dispose (object);
-}
-
-static void
-etst_finalize (GObject *object)
-{
- ETableState *etst = E_TABLE_STATE (object);
-
- if (etst->columns) {
- g_free (etst->columns);
- etst->columns = NULL;
- }
-
- if (etst->expansions) {
- g_free (etst->expansions);
- etst->expansions = NULL;
- }
-
- G_OBJECT_CLASS (etst_parent_class)->finalize (object);
-}
-
-static void
-etst_class_init (GObjectClass *klass)
-{
- etst_parent_class = g_type_class_peek_parent (klass);
-
- klass->dispose = etst_dispose;
- klass->finalize = etst_finalize;
-}
-
-static void
-etst_init (ETableState *state)
-{
- state->columns = NULL;
- state->expansions = NULL;
- state->sort_info = e_table_sort_info_new();
-}
-
-E_MAKE_TYPE(e_table_state, "ETableState", ETableState, etst_class_init, etst_init, G_TYPE_OBJECT)
-
-ETableState *
-e_table_state_new (void)
-{
- return (ETableState *) g_object_new (E_TABLE_STATE_TYPE, NULL);
-}
-
-ETableState *
-e_table_state_vanilla (int col_count)
-{
- GString *str;
- int i;
- ETableState *res;
-
- str = g_string_new ("<ETableState>\n");
- for (i = 0; i < col_count; i++)
- g_string_append_printf (str, " <column source=\"%d\"/>\n", i);
- g_string_append (str, " <grouping></grouping>\n");
- g_string_append (str, "</ETableState>\n");
-
- res = e_table_state_new ();
- e_table_state_load_from_string (res, str->str);
-
- g_string_free (str, TRUE);
- return res;
-}
-
-gboolean
-e_table_state_load_from_file (ETableState *state,
- const char *filename)
-{
- xmlDoc *doc;
-
- if (!g_file_test (filename, G_FILE_TEST_EXISTS))
- return FALSE;
-
- doc = xmlParseFile (filename);
- if (doc) {
- xmlNode *node = xmlDocGetRootElement(doc);
- e_table_state_load_from_node(state, node);
- xmlFreeDoc(doc);
- return TRUE;
- }
- return FALSE;
-}
-
-void
-e_table_state_load_from_string (ETableState *state,
- const char *xml)
-{
- xmlDoc *doc;
- doc = xmlParseMemory ((char *) xml, strlen(xml));
- if (doc) {
- xmlNode *node = xmlDocGetRootElement(doc);
- e_table_state_load_from_node(state, node);
- xmlFreeDoc(doc);
- }
-}
-
-typedef struct {
- int column;
- double expansion;
-} int_and_double;
-
-void
-e_table_state_load_from_node (ETableState *state,
- const xmlNode *node)
-{
- xmlNode *children;
- GList *list = NULL, *iterator;
- gdouble state_version;
- int i;
-
- state_version = e_xml_get_double_prop_by_name_with_default (
- node, "state-version", STATE_VERSION);
-
- if (state->sort_info)
- g_object_unref (state->sort_info);
-
- state->sort_info = NULL;
- children = node->xmlChildrenNode;
- for (; children; children = children->next) {
- if (!strcmp (children->name, "column")) {
- int_and_double *column_info = g_new(int_and_double, 1);
-
- column_info->column = e_xml_get_integer_prop_by_name(
- children, "source");
- column_info->expansion =
- e_xml_get_double_prop_by_name_with_default(
- children, "expansion", 1);
-
- list = g_list_append (list, column_info);
- } else if (state->sort_info == NULL &&
- !strcmp (children->name, "grouping")) {
- state->sort_info = e_table_sort_info_new();
- e_table_sort_info_load_from_node(
- state->sort_info, children, state_version);
- }
- }
- g_free(state->columns);
- g_free(state->expansions);
- state->col_count = g_list_length(list);
- state->columns = g_new(int, state->col_count);
- state->expansions = g_new(double, state->col_count);
-
- for (iterator = list, i = 0; iterator; i++) {
- int_and_double *column_info = iterator->data;
-
- state->columns [i] = column_info->column;
- state->expansions [i] = column_info->expansion;
- g_free (column_info);
- iterator = g_list_next (iterator);
- }
- g_list_free(list);
-}
-
-void
-e_table_state_save_to_file (ETableState *state,
- const char *filename)
-{
- xmlDoc *doc;
-
- if ((doc = xmlNewDoc ("1.0")) == NULL)
- return;
-
- xmlDocSetRootElement (doc, e_table_state_save_to_node (state, NULL));
-
- e_xml_save_file (filename, doc);
-
- xmlFreeDoc (doc);
-}
-
-char *
-e_table_state_save_to_string (ETableState *state)
-{
- char *ret_val;
- xmlChar *string;
- int length;
- xmlDoc *doc;
-
- doc = xmlNewDoc("1.0");
- xmlDocSetRootElement(doc, e_table_state_save_to_node(state, NULL));
- xmlDocDumpMemory(doc, &string, &length);
- xmlFreeDoc(doc);
-
- ret_val = g_strdup(string);
- xmlFree(string);
- return ret_val;
-}
-
-xmlNode *
-e_table_state_save_to_node (ETableState *state,
- xmlNode *parent)
-{
- int i;
- xmlNode *node;
-
- if (parent)
- node = xmlNewChild (parent, NULL, "ETableState", NULL);
- else
- node = xmlNewNode (NULL, "ETableState");
-
- e_xml_set_double_prop_by_name(node, "state-version", STATE_VERSION);
-
- for (i = 0; i < state->col_count; i++) {
- int column = state->columns[i];
- double expansion = state->expansions[i];
- xmlNode *new_node;
-
- new_node = xmlNewChild(node, NULL, "column", NULL);
- e_xml_set_integer_prop_by_name (new_node, "source", column);
- if (expansion >= -1)
- e_xml_set_double_prop_by_name(new_node, "expansion", expansion);
- }
-
-
- e_table_sort_info_save_to_node(state->sort_info, node);
-
- return node;
-}
-
-/**
- * e_table_state_duplicate:
- * @state: The ETableState to duplicate
- *
- * This creates a copy of the %ETableState @state
- *
- * Returns: The duplicated %ETableState.
- */
-ETableState *
-e_table_state_duplicate (ETableState *state)
-{
- ETableState *new_state;
- char *copy;
-
- g_return_val_if_fail (state != NULL, NULL);
- g_return_val_if_fail (E_IS_TABLE_STATE (state), NULL);
-
- new_state = e_table_state_new ();
- copy = e_table_state_save_to_string (state);
- e_table_state_load_from_string (new_state, copy);
- g_free (copy);
-
- e_table_sort_info_set_can_group
- (new_state->sort_info,
- e_table_sort_info_get_can_group (state->sort_info));
-
- return new_state;
-}
diff --git a/widgets/table/e-table-state.h b/widgets/table/e-table-state.h
deleted file mode 100644
index 47e0c7b9b8..0000000000
--- a/widgets/table/e-table-state.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-state.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_TABLE_STATE_H_
-#define _E_TABLE_STATE_H_
-
-#include <glib-object.h>
-#include <libxml/tree.h>
-#include <gal/e-table/e-table-sort-info.h>
-
-G_BEGIN_DECLS
-
-#define E_TABLE_STATE_TYPE (e_table_state_get_type ())
-#define E_TABLE_STATE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TABLE_STATE_TYPE, ETableState))
-#define E_TABLE_STATE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TABLE_STATE_TYPE, ETableStateClass))
-#define E_IS_TABLE_STATE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TABLE_STATE_TYPE))
-#define E_IS_TABLE_STATE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TABLE_STATE_TYPE))
-#define E_TABLE_STATE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), E_TABLE_STATE_TYPE, ETableStateClass))
-
-typedef struct {
- GObject base;
-
- ETableSortInfo *sort_info;
- int col_count;
- int *columns;
- double *expansions;
-} ETableState;
-
-typedef struct {
- GObjectClass parent_class;
-} ETableStateClass;
-
-GType e_table_state_get_type (void);
-ETableState *e_table_state_new (void);
-
-ETableState *e_table_state_vanilla (int col_count);
-
-gboolean e_table_state_load_from_file (ETableState *state,
- const char *filename);
-void e_table_state_load_from_string (ETableState *state,
- const char *xml);
-void e_table_state_load_from_node (ETableState *state,
- const xmlNode *node);
-
-void e_table_state_save_to_file (ETableState *state,
- const char *filename);
-char *e_table_state_save_to_string (ETableState *state);
-xmlNode *e_table_state_save_to_node (ETableState *state,
- xmlNode *parent);
-ETableState *e_table_state_duplicate (ETableState *state);
-
-G_END_DECLS
-
-#endif /* _E_TABLE_STATE_H_ */
diff --git a/widgets/table/e-table-subset-variable.c b/widgets/table/e-table-subset-variable.c
deleted file mode 100644
index efe6529806..0000000000
--- a/widgets/table/e-table-subset-variable.c
+++ /dev/null
@@ -1,250 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-subset-variable.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <stdlib.h>
-#include <string.h>
-#include "gal/util/e-util.h"
-#include "e-table-subset-variable.h"
-
-#define ETSSV_CLASS(e) (E_TABLE_SUBSET_VARIABLE_GET_CLASS (e))
-
-#define INCREMENT_AMOUNT 10
-
-static void
-etssv_add (ETableSubsetVariable *etssv,
- gint row)
-{
- ETableModel *etm = E_TABLE_MODEL(etssv);
- ETableSubset *etss = E_TABLE_SUBSET(etssv);
-
- e_table_model_pre_change(etm);
-
- if (etss->n_map + 1 > etssv->n_vals_allocated){
- etssv->n_vals_allocated += INCREMENT_AMOUNT;
- etss->map_table = g_realloc (etss->map_table, etssv->n_vals_allocated * sizeof(int));
- }
-
- etss->map_table[etss->n_map++] = row;
-
- e_table_model_row_inserted (etm, etss->n_map - 1);
-}
-
-static void
-etssv_add_array (ETableSubsetVariable *etssv,
- const gint *array,
- gint count)
-{
- ETableModel *etm = E_TABLE_MODEL(etssv);
- ETableSubset *etss = E_TABLE_SUBSET(etssv);
- int i;
-
- e_table_model_pre_change(etm);
-
- if (etss->n_map + count > etssv->n_vals_allocated){
- etssv->n_vals_allocated += MAX(INCREMENT_AMOUNT, count);
- etss->map_table = g_realloc (etss->map_table, etssv->n_vals_allocated * sizeof(int));
- }
- for (i = 0; i < count; i++)
- etss->map_table[etss->n_map++] = array[i];
-
- e_table_model_changed (etm);
-}
-
-static void
-etssv_add_all (ETableSubsetVariable *etssv)
-{
- ETableModel *etm = E_TABLE_MODEL(etssv);
- ETableSubset *etss = E_TABLE_SUBSET(etssv);
- int rows;
- int i;
-
- e_table_model_pre_change(etm);
-
- rows = e_table_model_row_count(etss->source);
- if (etss->n_map + rows > etssv->n_vals_allocated){
- etssv->n_vals_allocated += MAX(INCREMENT_AMOUNT, rows);
- etss->map_table = g_realloc (etss->map_table, etssv->n_vals_allocated * sizeof(int));
- }
- for (i = 0; i < rows; i++)
- etss->map_table[etss->n_map++] = i;
-
- e_table_model_changed (etm);
-}
-
-static gboolean
-etssv_remove (ETableSubsetVariable *etssv,
- gint row)
-{
- ETableModel *etm = E_TABLE_MODEL(etssv);
- ETableSubset *etss = E_TABLE_SUBSET(etssv);
- int i;
-
- for (i = 0; i < etss->n_map; i++){
- if (etss->map_table[i] == row) {
- e_table_model_pre_change (etm);
- memmove (etss->map_table + i, etss->map_table + i + 1, (etss->n_map - i - 1) * sizeof(int));
- etss->n_map --;
-
- e_table_model_row_deleted (etm, i);
- return TRUE;
- }
- }
- return FALSE;
-}
-
-static void
-etssv_class_init (GObjectClass *object_class)
-{
- ETableSubsetVariableClass *klass = E_TABLE_SUBSET_VARIABLE_CLASS(object_class);
-
- klass->add = etssv_add;
- klass->add_array = etssv_add_array;
- klass->add_all = etssv_add_all;
- klass->remove = etssv_remove;
-}
-
-E_MAKE_TYPE(e_table_subset_variable, "ETableSubsetVariable", ETableSubsetVariable, etssv_class_init, NULL, E_TABLE_SUBSET_TYPE)
-
-ETableModel *
-e_table_subset_variable_construct (ETableSubsetVariable *etssv,
- ETableModel *source)
-{
- if (e_table_subset_construct (E_TABLE_SUBSET(etssv), source, 1) == NULL)
- return NULL;
- E_TABLE_SUBSET(etssv)->n_map = 0;
-
- return E_TABLE_MODEL (etssv);
-}
-
-ETableModel *
-e_table_subset_variable_new (ETableModel *source)
-{
- ETableSubsetVariable *etssv = g_object_new (E_TABLE_SUBSET_VARIABLE_TYPE, NULL);
-
- if (e_table_subset_variable_construct (etssv, source) == NULL){
- g_object_unref (etssv);
- return NULL;
- }
-
- return (ETableModel *) etssv;
-}
-
-void
-e_table_subset_variable_add (ETableSubsetVariable *etssv,
- gint row)
-{
- g_return_if_fail (etssv != NULL);
- g_return_if_fail (E_IS_TABLE_SUBSET_VARIABLE(etssv));
-
- if (ETSSV_CLASS(etssv)->add)
- ETSSV_CLASS (etssv)->add (etssv, row);
-}
-
-void
-e_table_subset_variable_add_array (ETableSubsetVariable *etssv,
- const gint *array,
- gint count)
-{
- g_return_if_fail (etssv != NULL);
- g_return_if_fail (E_IS_TABLE_SUBSET_VARIABLE(etssv));
-
- if (ETSSV_CLASS(etssv)->add_array)
- ETSSV_CLASS (etssv)->add_array (etssv, array, count);
-}
-
-void
-e_table_subset_variable_add_all (ETableSubsetVariable *etssv)
-{
- g_return_if_fail (etssv != NULL);
- g_return_if_fail (E_IS_TABLE_SUBSET_VARIABLE(etssv));
-
- if (ETSSV_CLASS(etssv)->add_all)
- ETSSV_CLASS (etssv)->add_all (etssv);
-}
-
-gboolean
-e_table_subset_variable_remove (ETableSubsetVariable *etssv,
- gint row)
-{
- g_return_val_if_fail (etssv != NULL, FALSE);
- g_return_val_if_fail (E_IS_TABLE_SUBSET_VARIABLE(etssv), FALSE);
-
- if (ETSSV_CLASS(etssv)->remove)
- return ETSSV_CLASS (etssv)->remove (etssv, row);
- else
- return FALSE;
-}
-
-void
-e_table_subset_variable_clear (ETableSubsetVariable *etssv)
-{
- ETableModel *etm = E_TABLE_MODEL(etssv);
- ETableSubset *etss = E_TABLE_SUBSET(etssv);
-
- e_table_model_pre_change (etm);
- etss->n_map = 0;
- g_free (etss->map_table);
- etss->map_table = g_new (unsigned int, 1);
- etssv->n_vals_allocated = 1;
-
- e_table_model_changed (etm);
-}
-
-void
-e_table_subset_variable_increment (ETableSubsetVariable *etssv,
- gint position,
- gint amount)
-{
- int i;
- ETableSubset *etss = E_TABLE_SUBSET(etssv);
- for (i = 0; i < etss->n_map; i++) {
- if (etss->map_table[i] >= position)
- etss->map_table[i] += amount;
- }
-}
-
-void
-e_table_subset_variable_decrement (ETableSubsetVariable *etssv,
- gint position,
- gint amount)
-{
- int i;
- ETableSubset *etss = E_TABLE_SUBSET(etssv);
- for (i = 0; i < etss->n_map; i++) {
- if (etss->map_table[i] >= position)
- etss->map_table[i] -= amount;
- }
-}
-
-void
-e_table_subset_variable_set_allocation (ETableSubsetVariable *etssv,
- gint total)
-{
- ETableSubset *etss = E_TABLE_SUBSET(etssv);
- if (total <= 0)
- total = 1;
- if (total > etss->n_map){
- etss->map_table = g_realloc (etss->map_table, total * sizeof(int));
- }
-}
diff --git a/widgets/table/e-table-subset-variable.h b/widgets/table/e-table-subset-variable.h
deleted file mode 100644
index 2dc0914f9b..0000000000
--- a/widgets/table/e-table-subset-variable.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-subset-variable.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_TABLE_SUBSET_VARIABLE_H_
-#define _E_TABLE_SUBSET_VARIABLE_H_
-
-#include <glib-object.h>
-#include <gal/e-table/e-table-subset.h>
-
-G_BEGIN_DECLS
-
-#define E_TABLE_SUBSET_VARIABLE_TYPE (e_table_subset_variable_get_type ())
-#define E_TABLE_SUBSET_VARIABLE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TABLE_SUBSET_VARIABLE_TYPE, ETableSubsetVariable))
-#define E_TABLE_SUBSET_VARIABLE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TABLE_SUBSET_VARIABLE_TYPE, ETableSubsetVariableClass))
-#define E_IS_TABLE_SUBSET_VARIABLE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TABLE_SUBSET_VARIABLE_TYPE))
-#define E_IS_TABLE_SUBSET_VARIABLE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TABLE_SUBSET_VARIABLE_TYPE))
-#define E_TABLE_SUBSET_VARIABLE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), E_TABLE_SUBSET_VARIABLE_TYPE, ETableSubsetVariableClass))
-
-typedef struct {
- ETableSubset base;
-
- int n_vals_allocated;
-} ETableSubsetVariable;
-
-typedef struct {
- ETableSubsetClass parent_class;
-
- void (*add) (ETableSubsetVariable *ets,
- gint row);
- void (*add_array) (ETableSubsetVariable *ets,
- const gint *array,
- gint count);
- void (*add_all) (ETableSubsetVariable *ets);
- gboolean (*remove) (ETableSubsetVariable *ets,
- gint row);
-} ETableSubsetVariableClass;
-
-GType e_table_subset_variable_get_type (void);
-ETableModel *e_table_subset_variable_new (ETableModel *etm);
-ETableModel *e_table_subset_variable_construct (ETableSubsetVariable *etssv,
- ETableModel *source);
-void e_table_subset_variable_add (ETableSubsetVariable *ets,
- gint row);
-void e_table_subset_variable_add_array (ETableSubsetVariable *ets,
- const gint *array,
- gint count);
-void e_table_subset_variable_add_all (ETableSubsetVariable *ets);
-gboolean e_table_subset_variable_remove (ETableSubsetVariable *ets,
- gint row);
-void e_table_subset_variable_clear (ETableSubsetVariable *ets);
-void e_table_subset_variable_increment (ETableSubsetVariable *ets,
- gint position,
- gint amount);
-void e_table_subset_variable_decrement (ETableSubsetVariable *ets,
- gint position,
- gint amount);
-void e_table_subset_variable_set_allocation (ETableSubsetVariable *ets,
- gint total);
-G_END_DECLS
-
-#endif /* _E_TABLE_SUBSET_VARIABLE_H_ */
-
diff --git a/widgets/table/e-table-subset.c b/widgets/table/e-table-subset.c
deleted file mode 100644
index a237ba2d94..0000000000
--- a/widgets/table/e-table-subset.c
+++ /dev/null
@@ -1,482 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-subset.c - Implements a table that contains a subset of another table.
- * Copyright 1999, 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- * Miguel de Icaza <miguel@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <stdlib.h>
-#include "gal/util/e-util.h"
-#include "e-table-subset.h"
-
-static void etss_proxy_model_pre_change_real (ETableSubset *etss, ETableModel *etm);
-static void etss_proxy_model_no_change_real (ETableSubset *etss, ETableModel *etm);
-static void etss_proxy_model_changed_real (ETableSubset *etss, ETableModel *etm);
-static void etss_proxy_model_row_changed_real (ETableSubset *etss, ETableModel *etm, int row);
-static void etss_proxy_model_cell_changed_real (ETableSubset *etss, ETableModel *etm, int col, int row);
-static void etss_proxy_model_rows_inserted_real (ETableSubset *etss, ETableModel *etm, int row, int count);
-static void etss_proxy_model_rows_deleted_real (ETableSubset *etss, ETableModel *etm, int row, int count);
-
-#define d(x)
-
-static ETableModelClass *etss_parent_class;
-
-#define ETSS_CLASS(object) (E_TABLE_SUBSET_GET_CLASS(object))
-
-#define VALID_ROW(etss, row) (row >= -1 && row < etss->n_map)
-#define MAP_ROW(etss, row) (row == -1 ? -1 : etss->map_table[row])
-
-static gint
-etss_get_view_row (ETableSubset *etss, int row)
-{
- const int n = etss->n_map;
- const int * const map_table = etss->map_table;
- int i;
-
- int end = MIN(etss->n_map, etss->last_access + 10);
- int start = MAX(0, etss->last_access - 10);
- int initial = MAX (MIN (etss->last_access, end), start);
-
- for (i = initial; i < end; i++) {
- if (map_table [i] == row){
- d(g_print("a) Found %d from %d\n", i, etss->last_access));
- etss->last_access = i;
- return i;
- }
- }
-
- for (i = initial - 1; i >= start; i--) {
- if (map_table [i] == row){
- d(g_print("b) Found %d from %d\n", i, etss->last_access));
- etss->last_access = i;
- return i;
- }
- }
-
- for (i = 0; i < n; i++){
- if (map_table [i] == row){
- d(g_print("c) Found %d from %d\n", i, etss->last_access));
- etss->last_access = i;
- return i;
- }
- }
- return -1;
-}
-
-static void
-etss_dispose (GObject *object)
-{
- ETableSubset *etss = E_TABLE_SUBSET (object);
-
- if (etss->source) {
- g_signal_handler_disconnect (G_OBJECT (etss->source),
- etss->table_model_pre_change_id);
- g_signal_handler_disconnect (G_OBJECT (etss->source),
- etss->table_model_no_change_id);
- g_signal_handler_disconnect (G_OBJECT (etss->source),
- etss->table_model_changed_id);
- g_signal_handler_disconnect (G_OBJECT (etss->source),
- etss->table_model_row_changed_id);
- g_signal_handler_disconnect (G_OBJECT (etss->source),
- etss->table_model_cell_changed_id);
- g_signal_handler_disconnect (G_OBJECT (etss->source),
- etss->table_model_rows_inserted_id);
- g_signal_handler_disconnect (G_OBJECT (etss->source),
- etss->table_model_rows_deleted_id);
-
- g_object_unref (etss->source);
- etss->source = NULL;
-
- etss->table_model_changed_id = 0;
- etss->table_model_row_changed_id = 0;
- etss->table_model_cell_changed_id = 0;
- etss->table_model_rows_inserted_id = 0;
- etss->table_model_rows_deleted_id = 0;
- }
-
- G_OBJECT_CLASS (etss_parent_class)->dispose (object);
-}
-
-static void
-etss_finalize (GObject *object)
-{
- ETableSubset *etss = E_TABLE_SUBSET (object);
-
- g_free (etss->map_table);
- etss->map_table = NULL;
-
- G_OBJECT_CLASS (etss_parent_class)->finalize (object);
-}
-
-static int
-etss_column_count (ETableModel *etm)
-{
- ETableSubset *etss = (ETableSubset *)etm;
-
- return e_table_model_column_count (etss->source);
-}
-
-static int
-etss_row_count (ETableModel *etm)
-{
- ETableSubset *etss = (ETableSubset *)etm;
-
- return etss->n_map;
-}
-
-static void *
-etss_value_at (ETableModel *etm, int col, int row)
-{
- ETableSubset *etss = (ETableSubset *)etm;
-
- g_return_val_if_fail (VALID_ROW (etss, row), NULL);
-
- etss->last_access = row;
- d(g_print("g) Setting last_access to %d\n", row));
- return e_table_model_value_at (etss->source, col, MAP_ROW(etss, row));
-}
-
-static void
-etss_set_value_at (ETableModel *etm, int col, int row, const void *val)
-{
- ETableSubset *etss = (ETableSubset *)etm;
-
- g_return_if_fail (VALID_ROW (etss, row));
-
- etss->last_access = row;
- d(g_print("h) Setting last_access to %d\n", row));
- e_table_model_set_value_at (etss->source, col, MAP_ROW(etss, row), val);
-}
-
-static gboolean
-etss_is_cell_editable (ETableModel *etm, int col, int row)
-{
- ETableSubset *etss = (ETableSubset *)etm;
-
- g_return_val_if_fail (VALID_ROW (etss, row), FALSE);
-
- return e_table_model_is_cell_editable (etss->source, col, MAP_ROW(etss, row));
-}
-
-static gboolean
-etss_has_save_id (ETableModel *etm)
-{
- return TRUE;
-}
-
-static char *
-etss_get_save_id (ETableModel *etm, int row)
-{
- ETableSubset *etss = (ETableSubset *)etm;
-
- g_return_val_if_fail (VALID_ROW (etss, row), NULL);
-
- if (e_table_model_has_save_id (etss->source))
- return e_table_model_get_save_id (etss->source, MAP_ROW(etss, row));
- else
- return g_strdup_printf ("%d", MAP_ROW(etss, row));
-}
-
-static void
-etss_append_row (ETableModel *etm, ETableModel *source, int row)
-{
- ETableSubset *etss = (ETableSubset *)etm;
- e_table_model_append_row (etss->source, source, row);
-}
-
-static void *
-etss_duplicate_value (ETableModel *etm, int col, const void *value)
-{
- ETableSubset *etss = (ETableSubset *)etm;
-
- return e_table_model_duplicate_value (etss->source, col, value);
-}
-
-static void
-etss_free_value (ETableModel *etm, int col, void *value)
-{
- ETableSubset *etss = (ETableSubset *)etm;
-
- e_table_model_free_value (etss->source, col, value);
-}
-
-static void *
-etss_initialize_value (ETableModel *etm, int col)
-{
- ETableSubset *etss = (ETableSubset *)etm;
-
- return e_table_model_initialize_value (etss->source, col);
-}
-
-static gboolean
-etss_value_is_empty (ETableModel *etm, int col, const void *value)
-{
- ETableSubset *etss = (ETableSubset *)etm;
-
- return e_table_model_value_is_empty (etss->source, col, value);
-}
-
-static char *
-etss_value_to_string (ETableModel *etm, int col, const void *value)
-{
- ETableSubset *etss = (ETableSubset *)etm;
-
- return e_table_model_value_to_string (etss->source, col, value);
-}
-
-static void
-etss_class_init (GObjectClass *object_class)
-{
- ETableSubsetClass *klass = (ETableSubsetClass *) object_class;
- ETableModelClass *table_class = (ETableModelClass *) object_class;
-
- etss_parent_class = g_type_class_peek_parent (klass);
-
- object_class->dispose = etss_dispose;
- object_class->finalize = etss_finalize;
-
- table_class->column_count = etss_column_count;
- table_class->row_count = etss_row_count;
- table_class->append_row = etss_append_row;
-
- table_class->value_at = etss_value_at;
- table_class->set_value_at = etss_set_value_at;
- table_class->is_cell_editable = etss_is_cell_editable;
-
- table_class->has_save_id = etss_has_save_id;
- table_class->get_save_id = etss_get_save_id;
-
- table_class->duplicate_value = etss_duplicate_value;
- table_class->free_value = etss_free_value;
- table_class->initialize_value = etss_initialize_value;
- table_class->value_is_empty = etss_value_is_empty;
- table_class->value_to_string = etss_value_to_string;
-
- klass->proxy_model_pre_change = etss_proxy_model_pre_change_real;
- klass->proxy_model_no_change = etss_proxy_model_no_change_real;
- klass->proxy_model_changed = etss_proxy_model_changed_real;
- klass->proxy_model_row_changed = etss_proxy_model_row_changed_real;
- klass->proxy_model_cell_changed = etss_proxy_model_cell_changed_real;
- klass->proxy_model_rows_inserted = etss_proxy_model_rows_inserted_real;
- klass->proxy_model_rows_deleted = etss_proxy_model_rows_deleted_real;
-}
-
-static void
-etss_init (ETableSubset *etss)
-{
- etss->last_access = 0;
-}
-
-E_MAKE_TYPE(e_table_subset, "ETableSubset", ETableSubset, etss_class_init, etss_init, E_TABLE_MODEL_TYPE)
-
-static void
-etss_proxy_model_pre_change_real (ETableSubset *etss, ETableModel *etm)
-{
- e_table_model_pre_change (E_TABLE_MODEL (etss));
-}
-
-static void
-etss_proxy_model_no_change_real (ETableSubset *etss, ETableModel *etm)
-{
- e_table_model_no_change (E_TABLE_MODEL (etss));
-}
-
-static void
-etss_proxy_model_changed_real (ETableSubset *etss, ETableModel *etm)
-{
- e_table_model_changed (E_TABLE_MODEL (etss));
-}
-
-static void
-etss_proxy_model_row_changed_real (ETableSubset *etss, ETableModel *etm, int row)
-{
- int view_row = etss_get_view_row (etss, row);
- if (view_row != -1)
- e_table_model_row_changed (E_TABLE_MODEL (etss), view_row);
- else
- e_table_model_no_change (E_TABLE_MODEL (etss));
-}
-
-static void
-etss_proxy_model_cell_changed_real (ETableSubset *etss, ETableModel *etm, int col, int row)
-{
- int view_row = etss_get_view_row (etss, row);
- if (view_row != -1)
- e_table_model_cell_changed (E_TABLE_MODEL (etss), col, view_row);
- else
- e_table_model_no_change (E_TABLE_MODEL (etss));
-}
-
-static void
-etss_proxy_model_rows_inserted_real (ETableSubset *etss, ETableModel *etm, int row, int count)
-{
- e_table_model_no_change (E_TABLE_MODEL (etss));
-}
-
-static void
-etss_proxy_model_rows_deleted_real (ETableSubset *etss, ETableModel *etm, int row, int count)
-{
- e_table_model_no_change (E_TABLE_MODEL (etss));
-}
-
-static void
-etss_proxy_model_pre_change (ETableModel *etm, ETableSubset *etss)
-{
- if (ETSS_CLASS(etss)->proxy_model_pre_change)
- (ETSS_CLASS(etss)->proxy_model_pre_change) (etss, etm);
-}
-
-static void
-etss_proxy_model_no_change (ETableModel *etm, ETableSubset *etss)
-{
- if (ETSS_CLASS(etss)->proxy_model_no_change)
- (ETSS_CLASS(etss)->proxy_model_no_change) (etss, etm);
-}
-
-static void
-etss_proxy_model_changed (ETableModel *etm, ETableSubset *etss)
-{
- if (ETSS_CLASS(etss)->proxy_model_changed)
- (ETSS_CLASS(etss)->proxy_model_changed) (etss, etm);
-}
-
-static void
-etss_proxy_model_row_changed (ETableModel *etm, int row, ETableSubset *etss)
-{
- if (ETSS_CLASS(etss)->proxy_model_row_changed)
- (ETSS_CLASS(etss)->proxy_model_row_changed) (etss, etm, row);
-}
-
-static void
-etss_proxy_model_cell_changed (ETableModel *etm, int row, int col, ETableSubset *etss)
-{
- if (ETSS_CLASS(etss)->proxy_model_cell_changed)
- (ETSS_CLASS(etss)->proxy_model_cell_changed) (etss, etm, col, row);
-}
-
-static void
-etss_proxy_model_rows_inserted (ETableModel *etm, int row, int col, ETableSubset *etss)
-{
- if (ETSS_CLASS(etss)->proxy_model_rows_inserted)
- (ETSS_CLASS(etss)->proxy_model_rows_inserted) (etss, etm, row, col);
-}
-
-static void
-etss_proxy_model_rows_deleted (ETableModel *etm, int row, int col, ETableSubset *etss)
-{
- if (ETSS_CLASS(etss)->proxy_model_rows_deleted)
- (ETSS_CLASS(etss)->proxy_model_rows_deleted) (etss, etm, row, col);
-}
-
-ETableModel *
-e_table_subset_construct (ETableSubset *etss, ETableModel *source, int nvals)
-{
- unsigned int *buffer;
- int i;
-
- if (nvals) {
- buffer = (unsigned int *) g_malloc (sizeof (unsigned int) * nvals);
- if (buffer == NULL)
- return NULL;
- } else
- buffer = NULL;
- etss->map_table = buffer;
- etss->n_map = nvals;
- etss->source = source;
- g_object_ref (source);
-
- /* Init */
- for (i = 0; i < nvals; i++)
- etss->map_table [i] = i;
-
- etss->table_model_pre_change_id = g_signal_connect (G_OBJECT (source), "model_pre_change",
- G_CALLBACK (etss_proxy_model_pre_change), etss);
- etss->table_model_no_change_id = g_signal_connect (G_OBJECT (source), "model_no_change",
- G_CALLBACK (etss_proxy_model_no_change), etss);
- etss->table_model_changed_id = g_signal_connect (G_OBJECT (source), "model_changed",
- G_CALLBACK (etss_proxy_model_changed), etss);
- etss->table_model_row_changed_id = g_signal_connect (G_OBJECT (source), "model_row_changed",
- G_CALLBACK (etss_proxy_model_row_changed), etss);
- etss->table_model_cell_changed_id = g_signal_connect (G_OBJECT (source), "model_cell_changed",
- G_CALLBACK (etss_proxy_model_cell_changed), etss);
- etss->table_model_rows_inserted_id = g_signal_connect (G_OBJECT (source), "model_rows_inserted",
- G_CALLBACK (etss_proxy_model_rows_inserted), etss);
- etss->table_model_rows_deleted_id = g_signal_connect (G_OBJECT (source), "model_rows_deleted",
- G_CALLBACK (etss_proxy_model_rows_deleted), etss);
-
- return E_TABLE_MODEL (etss);
-}
-
-ETableModel *
-e_table_subset_new (ETableModel *source, const int nvals)
-{
- ETableSubset *etss = g_object_new (E_TABLE_SUBSET_TYPE, NULL);
-
- if (e_table_subset_construct (etss, source, nvals) == NULL){
- g_object_unref (etss);
- return NULL;
- }
-
- return (ETableModel *) etss;
-}
-
-int
-e_table_subset_model_to_view_row (ETableSubset *ets,
- int model_row)
-{
- int i;
- for (i = 0; i < ets->n_map; i++) {
- if (ets->map_table[i] == model_row)
- return i;
- }
- return -1;
-}
-
-int
-e_table_subset_view_to_model_row (ETableSubset *ets,
- int view_row)
-{
- if (view_row >= 0 && view_row < ets->n_map)
- return ets->map_table[view_row];
- else
- return -1;
-}
-
-ETableModel *
-e_table_subset_get_toplevel (ETableSubset *table)
-{
- g_return_val_if_fail (table != NULL, NULL);
- g_return_val_if_fail (E_IS_TABLE_SUBSET (table), NULL);
-
- if (E_IS_TABLE_SUBSET (table->source))
- return e_table_subset_get_toplevel (E_TABLE_SUBSET (table->source));
- else
- return table->source;
-}
-
-void
-e_table_subset_print_debugging (ETableSubset *table_model)
-{
- int i;
- for (i = 0; i < table_model->n_map; i++) {
- g_print("%8d\n", table_model->map_table[i]);
- }
-}
diff --git a/widgets/table/e-table-subset.h b/widgets/table/e-table-subset.h
deleted file mode 100644
index 505aa6c305..0000000000
--- a/widgets/table/e-table-subset.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-subset.h - Implements a table that contains a subset of another table.
- * Copyright 1999, 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- * Miguel de Icaza <miguel@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_TABLE_SUBSET_H_
-#define _E_TABLE_SUBSET_H_
-
-#include <glib-object.h>
-#include <gal/e-table/e-table-model.h>
-
-G_BEGIN_DECLS
-
-#define E_TABLE_SUBSET_TYPE (e_table_subset_get_type ())
-#define E_TABLE_SUBSET(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TABLE_SUBSET_TYPE, ETableSubset))
-#define E_TABLE_SUBSET_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TABLE_SUBSET_TYPE, ETableSubsetClass))
-#define E_IS_TABLE_SUBSET(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TABLE_SUBSET_TYPE))
-#define E_IS_TABLE_SUBSET_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TABLE_SUBSET_TYPE))
-#define E_TABLE_SUBSET_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), E_TABLE_SUBSET_TYPE, ETableSubsetClass))
-
-typedef struct {
- ETableModel base;
-
- ETableModel *source;
- int n_map;
- int *map_table;
-
- int last_access;
-
- int table_model_pre_change_id;
- int table_model_no_change_id;
- int table_model_changed_id;
- int table_model_row_changed_id;
- int table_model_cell_changed_id;
- int table_model_rows_inserted_id;
- int table_model_rows_deleted_id;
-} ETableSubset;
-
-typedef struct {
- ETableModelClass parent_class;
-
- void (*proxy_model_pre_change) (ETableSubset *etss, ETableModel *etm);
- void (*proxy_model_no_change) (ETableSubset *etss, ETableModel *etm);
- void (*proxy_model_changed) (ETableSubset *etss, ETableModel *etm);
- void (*proxy_model_row_changed) (ETableSubset *etss, ETableModel *etm, int row);
- void (*proxy_model_cell_changed) (ETableSubset *etss, ETableModel *etm, int col, int row);
- void (*proxy_model_rows_inserted) (ETableSubset *etss, ETableModel *etm, int row, int count);
- void (*proxy_model_rows_deleted) (ETableSubset *etss, ETableModel *etm, int row, int count);
-} ETableSubsetClass;
-
-GType e_table_subset_get_type (void);
-ETableModel *e_table_subset_new (ETableModel *etm,
- int n_vals);
-ETableModel *e_table_subset_construct (ETableSubset *ets,
- ETableModel *source,
- int nvals);
-
-int e_table_subset_model_to_view_row (ETableSubset *ets,
- int model_row);
-int e_table_subset_view_to_model_row (ETableSubset *ets,
- int view_row);
-
-ETableModel *e_table_subset_get_toplevel (ETableSubset *table_model);
-
-void e_table_subset_print_debugging (ETableSubset *table_model);
-
-G_END_DECLS
-
-#endif /* _E_TABLE_SUBSET_H_ */
-
diff --git a/widgets/table/e-table-tooltip.h b/widgets/table/e-table-tooltip.h
deleted file mode 100644
index 81c00f9e34..0000000000
--- a/widgets/table/e-table-tooltip.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-tooltip.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_TABLE_TOOLTIP_H_
-#define _E_TABLE_TOOLTIP_H_
-
-#include <libgnomecanvas/gnome-canvas.h>
-
-G_BEGIN_DECLS
-
-typedef struct {
- gint timer;
- int col, row;
- int row_height;
- int x, y;
- int cx, cy;
- GdkColor *foreground;
- GdkColor *background;
- GnomeCanvasItem *eti;
-} ETableTooltip;
-
-G_END_DECLS
-
-#endif
diff --git a/widgets/table/e-table-tree.h b/widgets/table/e-table-tree.h
deleted file mode 100644
index 5648fc2f06..0000000000
--- a/widgets/table/e-table-tree.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-tree.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_TABLE_TREE_H_
-#define _E_TABLE_TREE_H_
-
-#include <gal/e-table/e-table-model.h>
-
-G_BEGIN_DECLS
-
-typedef struct {
- char *title;
-
- union {
- ETableModel *table;
- GList *children;
- } u;
-
- guint expanded :1;
- guint is_leaf :1;
-} ETableGroup;
-
-ETableGroup *e_table_group_new (const char *title, ETableModel *table);
-ETableGroup *e_table_group_new_leaf (const char *title);
-
-G_END_DECLS
-
-#endif /* _E_TABLE_TREE_H_ */
diff --git a/widgets/table/e-table-utils.c b/widgets/table/e-table-utils.c
deleted file mode 100644
index eec4fc79d5..0000000000
--- a/widgets/table/e-table-utils.c
+++ /dev/null
@@ -1,191 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-utils.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include "gal/util/e-i18n.h"
-#include "gal/util/e-util.h"
-#include "gal/widgets/e-unicode.h"
-#include "e-table-utils.h"
-#include "e-table-header-utils.h"
-
-ETableHeader *
-e_table_state_to_header (GtkWidget *widget, ETableHeader *full_header, ETableState *state)
-{
- ETableHeader *nh;
- const int max_cols = e_table_header_count (full_header);
- int column;
- GValue *val = g_new0 (GValue, 1);
-
- g_return_val_if_fail (widget, NULL);
- g_return_val_if_fail (full_header, NULL);
- g_return_val_if_fail (state, NULL);
-
- nh = e_table_header_new ();
- g_value_init (val, G_TYPE_DOUBLE);
- g_value_set_double (val, e_table_header_width_extras (widget->style));
- g_object_set_property (G_OBJECT(nh), "width_extras", val);
- g_free (val);
-
- for (column = 0; column < state->col_count; column++) {
- int col;
- double expansion;
- ETableCol *table_col;
-
- col = state->columns[column];
- expansion = state->expansions[column];
-
- if (col >= max_cols)
- continue;
-
- table_col = e_table_header_get_column (full_header, col);
-
- if (expansion >= -1)
- table_col->expansion = expansion;
-
- e_table_header_add_column (nh, table_col, -1);
- }
-
- return nh;
-}
-
-static ETableCol *
-et_col_spec_to_col (ETableColumnSpecification *col_spec,
- ETableExtras *ete,
- const char *domain)
-{
- ETableCol *col = NULL;
- ECell *cell = NULL;
- GCompareFunc compare = NULL;
- ETableSearchFunc search = NULL;
-
- if (col_spec->cell)
- cell = e_table_extras_get_cell(ete, col_spec->cell);
- if (col_spec->compare)
- compare = e_table_extras_get_compare(ete, col_spec->compare);
- if (col_spec->search)
- search = e_table_extras_get_search(ete, col_spec->search);
-
- if (cell && compare) {
- char *title = dgettext (domain, col_spec->title);
-
- title = g_strdup (title);
-
- if (col_spec->pixbuf && *col_spec->pixbuf) {
- GdkPixbuf *pixbuf;
-
- pixbuf = e_table_extras_get_pixbuf(
- ete, col_spec->pixbuf);
- if (pixbuf) {
- col = e_table_col_new_with_pixbuf (
- col_spec->model_col, title,
- pixbuf, col_spec->expansion,
- col_spec->minimum_width,
- cell, compare, col_spec->resizable, col_spec->disabled, col_spec->priority);
- }
- }
- if (col == NULL && col_spec->title && *col_spec->title) {
- col = e_table_col_new (
- col_spec->model_col, title,
- col_spec->expansion, col_spec->minimum_width,
- cell, compare, col_spec->resizable, col_spec->disabled, col_spec->priority);
- }
- col->search = search;
-
- g_free (title);
- }
- if (col && col_spec->compare_col != col_spec->model_col)
- g_object_set (col,
- "compare_col", col_spec->compare_col,
- NULL);
- return col;
-}
-
-ETableHeader *
-e_table_spec_to_full_header (ETableSpecification *spec,
- ETableExtras *ete)
-{
- ETableHeader *nh;
- int column;
-
- g_return_val_if_fail (spec, NULL);
- g_return_val_if_fail (ete, NULL);
-
- nh = e_table_header_new ();
-
- for (column = 0; spec->columns[column]; column++) {
- ETableCol *col = et_col_spec_to_col (
- spec->columns[column], ete, spec->domain);
-
- if (col) {
- e_table_header_add_column (nh, col, -1);
- g_object_unref (col);
- }
- }
-
- return nh;
-}
-
-static gboolean
-check_col (ETableCol *col, gpointer user_data)
-{
- return col->search ? TRUE : FALSE;
-}
-
-ETableCol *
-e_table_util_calculate_current_search_col (ETableHeader *header, ETableHeader *full_header, ETableSortInfo *sort_info, gboolean always_search)
-{
- int i;
- int count;
- ETableCol *col = NULL;
- count = e_table_sort_info_grouping_get_count (sort_info);
- for (i = 0; i < count; i++) {
- ETableSortColumn column = e_table_sort_info_grouping_get_nth(sort_info, i);
-
- col = e_table_header_get_column (full_header, column.column);
-
- if (col && col->search)
- break;
-
- col = NULL;
- }
-
- if (col == NULL) {
- count = e_table_sort_info_sorting_get_count (sort_info);
- for (i = 0; i < count; i++) {
- ETableSortColumn column = e_table_sort_info_sorting_get_nth(sort_info, i);
-
- col = e_table_header_get_column (full_header, column.column);
-
- if (col && col->search)
- break;
-
- col = NULL;
- }
- }
-
- if (col == NULL && always_search) {
- col = e_table_header_prioritized_column_selected (header, check_col, NULL);
- }
-
- return col;
-}
diff --git a/widgets/table/e-table-utils.h b/widgets/table/e-table-utils.h
deleted file mode 100644
index 3c7fd937b6..0000000000
--- a/widgets/table/e-table-utils.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-utils.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_TABLE_UTILS_H_
-#define _E_TABLE_UTILS_H_
-
-#include <gal/e-table/e-table-header.h>
-#include <gal/e-table/e-table-state.h>
-#include <gal/e-table/e-table-specification.h>
-#include <gal/e-table/e-table-extras.h>
-
-G_BEGIN_DECLS
-
-ETableHeader *e_table_state_to_header (GtkWidget *widget,
- ETableHeader *full_header,
- ETableState *state);
-
-ETableHeader *e_table_spec_to_full_header (ETableSpecification *spec,
- ETableExtras *ete);
-
-ETableCol *e_table_util_calculate_current_search_col (ETableHeader *header,
- ETableHeader *full_header,
- ETableSortInfo *sort_info,
- gboolean always_search);
-
-G_END_DECLS
-
-#endif /* _E_TABLE_UTILS_H_ */
-
diff --git a/widgets/table/e-table-without.c b/widgets/table/e-table-without.c
deleted file mode 100644
index e49076be0f..0000000000
--- a/widgets/table/e-table-without.c
+++ /dev/null
@@ -1,392 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-without.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <stdlib.h>
-#include <string.h>
-#include "gal/util/e-util.h"
-#include "e-table-without.h"
-
-#define PARENT_TYPE E_TABLE_SUBSET_TYPE
-
-#define INCREMENT_AMOUNT 10
-
-static ETableSubsetClass *parent_class;
-
-struct _ETableWithoutPrivate {
- GHashTable *hash;
-
- GHashFunc hash_func;
- GCompareFunc compare_func;
-
- ETableWithoutGetKeyFunc get_key_func;
- ETableWithoutDuplicateKeyFunc duplicate_key_func;
- ETableWithoutFreeKeyFunc free_gotten_key_func;
- ETableWithoutFreeKeyFunc free_duplicated_key_func;
-
- void *closure;
-};
-
-static gboolean
-check (ETableWithout *etw, int model_row)
-{
- gboolean ret_val;
- void *key;
- ETableSubset *etss = E_TABLE_SUBSET (etw);
-
- if (etw->priv->get_key_func)
- key = etw->priv->get_key_func (etss->source, model_row, etw->priv->closure);
- else
- key = GINT_TO_POINTER (model_row);
- ret_val = (g_hash_table_lookup (etw->priv->hash, key) != NULL);
- if (etw->priv->free_gotten_key_func)
- etw->priv->free_gotten_key_func (key, etw->priv->closure);
- return ret_val;
-}
-
-static gboolean
-check_with_key (ETableWithout *etw, void *key, int model_row)
-{
- gboolean ret_val;
- void *key2;
- ETableSubset *etss = E_TABLE_SUBSET (etw);
-
- if (etw->priv->get_key_func)
- key2 = etw->priv->get_key_func (etss->source, model_row, etw->priv->closure);
- else
- key2 = GINT_TO_POINTER (model_row);
- if (etw->priv->compare_func)
- ret_val = (etw->priv->compare_func (key, key2));
- else
- ret_val = (key == key2);
- if (etw->priv->free_gotten_key_func)
- etw->priv->free_gotten_key_func (key2, etw->priv->closure);
- return ret_val;
-}
-
-static gint
-etw_view_to_model_row (ETableWithout *etw, int view_row)
-{
- ETableSubset *etss = E_TABLE_SUBSET (etw);
- return etss->map_table[view_row];
-}
-
-static void
-add_row (ETableWithout *etw, int model_row)
-{
- ETableSubset *etss = E_TABLE_SUBSET (etw);
-
- e_table_model_pre_change (E_TABLE_MODEL (etw));
-
- etss->map_table = g_renew (int, etss->map_table, etss->n_map + 1);
-
- etss->map_table[etss->n_map++] = model_row;
-
- e_table_model_row_inserted (E_TABLE_MODEL (etw), etss->n_map - 1);
-}
-
-static void
-remove_row (ETableWithout *etw, int view_row)
-{
- ETableSubset *etss = E_TABLE_SUBSET (etw);
-
- e_table_model_pre_change (E_TABLE_MODEL (etw));
- memmove (etss->map_table + view_row, etss->map_table + view_row + 1, (etss->n_map - view_row - 1) * sizeof (int));
- etss->n_map --;
- e_table_model_row_deleted (E_TABLE_MODEL (etw), view_row);
-}
-
-static void
-delete_hash_element (gpointer key,
- gpointer value,
- gpointer closure)
-{
- ETableWithout *etw = closure;
- if (etw->priv->free_duplicated_key_func)
- etw->priv->free_duplicated_key_func (key, etw->priv->closure);
-}
-
-static void
-etw_dispose (GObject *object)
-{
- ETableWithout *etw = E_TABLE_WITHOUT (object);
-
- if (etw->priv) {
- if (etw->priv->hash) {
- g_hash_table_foreach (etw->priv->hash, delete_hash_element, etw);
- g_hash_table_destroy (etw->priv->hash);
- etw->priv->hash = NULL;
- }
- g_free (etw->priv);
- etw->priv = NULL;
- }
-
- if (G_OBJECT_CLASS (parent_class)->dispose)
- (* G_OBJECT_CLASS (parent_class)->dispose) (object);
-}
-
-static void
-etw_proxy_model_rows_inserted (ETableSubset *etss, ETableModel *etm, int model_row, int count)
-{
- int i;
- ETableWithout *etw = E_TABLE_WITHOUT (etss);
- gboolean shift = FALSE;
-
- /* i is View row */
- if (model_row != etss->n_map) {
- for (i = 0; i < etss->n_map; i++) {
- if (etss->map_table[i] > model_row)
- etss->map_table[i] += count;
- }
- shift = TRUE;
- }
-
- /* i is Model row */
- for (i = model_row; i < model_row + count; i++) {
- if (!check (etw, i)) {
- add_row (etw, i);
- }
- }
- if (shift)
- e_table_model_changed (E_TABLE_MODEL (etw));
- else
- e_table_model_no_change (E_TABLE_MODEL (etw));
-}
-
-static void
-etw_proxy_model_rows_deleted (ETableSubset *etss, ETableModel *etm, int model_row, int count)
-{
- int i; /* View row */
- ETableWithout *etw = E_TABLE_WITHOUT (etss);
- gboolean shift = FALSE;
-
- for (i = 0; i < etss->n_map; i++) {
- if (etss->map_table[i] >= model_row && etss->map_table[i] < model_row + count) {
- remove_row (etw, i);
- i--;
- } else if (etss->map_table[i] >= model_row + count) {
- etss->map_table[i] -= count;
- shift = TRUE;
- }
- }
- if (shift)
- e_table_model_changed (E_TABLE_MODEL (etw));
- else
- e_table_model_no_change (E_TABLE_MODEL (etw));
-}
-
-static void
-etw_proxy_model_changed (ETableSubset *etss, ETableModel *etm)
-{
- int i; /* Model row */
- int j; /* View row */
- int row_count;
- ETableWithout *etw = E_TABLE_WITHOUT (etss);
-
- g_free (etss->map_table);
- row_count = e_table_model_row_count (etm);
- etss->map_table = g_new (int, row_count);
-
- for (i = 0, j = 0; i < row_count; i++) {
- if (!check (etw, i)) {
- etss->map_table[j++] = i;
- }
- }
- etss->n_map = j;
-
- if (parent_class->proxy_model_changed)
- parent_class->proxy_model_changed (etss, etm);
-}
-
-static void
-etw_class_init (ETableWithoutClass *klass)
-{
- ETableSubsetClass *etss_class = E_TABLE_SUBSET_CLASS (klass);
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- parent_class = g_type_class_ref (PARENT_TYPE);
-
- object_class->dispose = etw_dispose;
-
- etss_class->proxy_model_rows_inserted = etw_proxy_model_rows_inserted;
- etss_class->proxy_model_rows_deleted = etw_proxy_model_rows_deleted;
- etss_class->proxy_model_changed = etw_proxy_model_changed;
-}
-
-static void
-etw_init (ETableWithout *etw)
-{
- etw->priv = g_new (ETableWithoutPrivate, 1);
- etw->priv->hash_func = NULL;
- etw->priv->compare_func = NULL;
- etw->priv->get_key_func = NULL;
- etw->priv->duplicate_key_func = NULL;
- etw->priv->free_gotten_key_func = NULL;
- etw->priv->free_duplicated_key_func = NULL;
-}
-
-E_MAKE_TYPE(e_table_without, "ETableWithout", ETableWithout, etw_class_init, etw_init, PARENT_TYPE)
-
-ETableModel *
-e_table_without_construct (ETableWithout *etw,
- ETableModel *source,
- GHashFunc hash_func,
- GCompareFunc compare_func,
- ETableWithoutGetKeyFunc get_key_func,
- ETableWithoutDuplicateKeyFunc duplicate_key_func,
- ETableWithoutFreeKeyFunc free_gotten_key_func,
- ETableWithoutFreeKeyFunc free_duplicated_key_func,
- void *closure)
-{
- if (e_table_subset_construct (E_TABLE_SUBSET(etw), source, 1) == NULL)
- return NULL;
- E_TABLE_SUBSET(etw)->n_map = 0;
-
- etw->priv->hash_func = hash_func;
- etw->priv->compare_func = compare_func;
- etw->priv->get_key_func = get_key_func;
- etw->priv->duplicate_key_func = duplicate_key_func;
- etw->priv->free_gotten_key_func = free_gotten_key_func;
- etw->priv->free_duplicated_key_func = free_duplicated_key_func;
- etw->priv->closure = closure;
-
- etw->priv->hash = g_hash_table_new (etw->priv->hash_func, etw->priv->compare_func);
-
- return E_TABLE_MODEL (etw);
-}
-
-ETableModel *
-e_table_without_new (ETableModel *source,
- GHashFunc hash_func,
- GCompareFunc compare_func,
- ETableWithoutGetKeyFunc get_key_func,
- ETableWithoutDuplicateKeyFunc duplicate_key_func,
- ETableWithoutFreeKeyFunc free_gotten_key_func,
- ETableWithoutFreeKeyFunc free_duplicated_key_func,
- void *closure)
-{
- ETableWithout *etw = g_object_new (E_TABLE_WITHOUT_TYPE, NULL);
-
- if (e_table_without_construct (etw,
- source,
- hash_func,
- compare_func,
- get_key_func,
- duplicate_key_func,
- free_gotten_key_func,
- free_duplicated_key_func,
- closure)
- == NULL) {
- g_object_unref (etw);
- return NULL;
- }
-
- return (ETableModel *) etw;
-}
-
-void e_table_without_hide (ETableWithout *etw,
- void *key)
-{
- int i; /* View row */
- ETableSubset *etss = E_TABLE_SUBSET (etw);
-
- if (etw->priv->duplicate_key_func)
- key = etw->priv->duplicate_key_func (key, etw->priv->closure);
-
- g_hash_table_insert (etw->priv->hash, key, key);
- for (i = 0; i < etss->n_map; i++) {
- if (check_with_key (etw, key, etw_view_to_model_row (etw, i))) {
- remove_row (etw, i);
- i --;
- }
- }
-}
-
-/* An adopted key will later be freed using the free_duplicated_key function. */
-void e_table_without_hide_adopt (ETableWithout *etw,
- void *key)
-{
- int i; /* View row */
- ETableSubset *etss = E_TABLE_SUBSET (etw);
-
- g_hash_table_insert (etw->priv->hash, key, key);
- for (i = 0; i < etss->n_map; i++) {
- if (check_with_key (etw, key, etw_view_to_model_row (etw, i))) {
- remove_row (etw, i);
- i --;
- }
- }
-}
-
-void
-e_table_without_show (ETableWithout *etw,
- void *key)
-{
- int i; /* Model row */
- ETableSubset *etss = E_TABLE_SUBSET (etw);
- int count;
- void *old_key;
-
- count = e_table_model_row_count (etss->source);
-
- for (i = 0; i < count; i++) {
- if (check_with_key (etw, key, i)) {
- add_row (etw, i);
- }
- }
- if (g_hash_table_lookup_extended (etw->priv->hash, key, &old_key, NULL)) {
-#if 0
- if (etw->priv->free_duplicated_key_func)
- etw->priv->free_duplicated_key_func (key, etw->priv->closure);
-#endif
- g_hash_table_remove (etw->priv->hash, key);
- }
-}
-
-void
-e_table_without_show_all (ETableWithout *etw)
-{
- int i; /* Model row */
- int row_count;
- ETableSubset *etss = E_TABLE_SUBSET (etw);
-
- e_table_model_pre_change (E_TABLE_MODEL (etw));
-
- if (etw->priv->hash) {
- g_hash_table_foreach (etw->priv->hash, delete_hash_element, etw);
- g_hash_table_destroy (etw->priv->hash);
- etw->priv->hash = NULL;
- }
- etw->priv->hash = g_hash_table_new (etw->priv->hash_func, etw->priv->compare_func);
-
- row_count = e_table_model_row_count (E_TABLE_MODEL(etss->source));
- g_free (etss->map_table);
- etss->map_table = g_new (int, row_count);
-
- for (i = 0; i < row_count; i++) {
- etss->map_table[i] = i;
- }
- etss->n_map = row_count;
-
- e_table_model_changed (E_TABLE_MODEL (etw));
-}
diff --git a/widgets/table/e-table-without.h b/widgets/table/e-table-without.h
deleted file mode 100644
index 6bcbdcdc65..0000000000
--- a/widgets/table/e-table-without.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table-without.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_TABLE_WITHOUT_H_
-#define _E_TABLE_WITHOUT_H_
-
-#include <gtk/gtkobject.h>
-#include <gal/e-table/e-table-subset.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-#define E_TABLE_WITHOUT_TYPE (e_table_without_get_type ())
-#define E_TABLE_WITHOUT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TABLE_WITHOUT_TYPE, ETableWithout))
-#define E_TABLE_WITHOUT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TABLE_WITHOUT_TYPE, ETableWithoutClass))
-#define E_IS_TABLE_WITHOUT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TABLE_WITHOUT_TYPE))
-#define E_IS_TABLE_WITHOUT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TABLE_WITHOUT_TYPE))
-
-typedef struct _ETableWithoutPrivate ETableWithoutPrivate;
-typedef void *(*ETableWithoutGetKeyFunc) (ETableModel *source,
- int row,
- void *closure);
-typedef void *(*ETableWithoutDuplicateKeyFunc) (const void *key,
- void *closure);
-typedef void (*ETableWithoutFreeKeyFunc) (void *key,
- void *closure);
-
-typedef struct {
- ETableSubset base;
-
- ETableWithoutPrivate *priv;
-} ETableWithout;
-
-typedef struct {
- ETableSubsetClass parent_class;
-
-} ETableWithoutClass;
-
-GType e_table_without_get_type (void);
-ETableModel *e_table_without_new (ETableModel *source,
- GHashFunc hash_func,
- GCompareFunc compare_func,
- ETableWithoutGetKeyFunc get_key_func,
- ETableWithoutDuplicateKeyFunc duplicate_key_func,
- ETableWithoutFreeKeyFunc free_gotten_key_func,
- ETableWithoutFreeKeyFunc free_duplicated_key_func,
- void *closure);
-ETableModel *e_table_without_construct (ETableWithout *etw,
- ETableModel *source,
- GHashFunc hash_func,
- GCompareFunc compare_func,
- ETableWithoutGetKeyFunc get_key_func,
- ETableWithoutDuplicateKeyFunc duplicate_key_func,
- ETableWithoutFreeKeyFunc free_gotten_key_func,
- ETableWithoutFreeKeyFunc free_duplicated_key_func,
- void *closure);
-void e_table_without_hide (ETableWithout *etw,
- void *key);
-void e_table_without_hide_adopt (ETableWithout *etw,
- void *key);
-void e_table_without_show (ETableWithout *etw,
- void *key);
-void e_table_without_show_all (ETableWithout *etw);
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-
-#endif /* _E_TABLE_WITHOUT_H_ */
-
diff --git a/widgets/table/e-table.c b/widgets/table/e-table.c
deleted file mode 100644
index 3a849fbf26..0000000000
--- a/widgets/table/e-table.c
+++ /dev/null
@@ -1,3349 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table.c - A graphical view of a Table.
- * Copyright 1999, 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- * Miguel de Icaza <miguel@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <gdk/gdk.h>
-#include <gdk/gdkkeysyms.h>
-#include <gtk/gtksignal.h>
-#include <libgnomecanvas/gnome-canvas.h>
-#include <libgnomecanvas/gnome-canvas-rect-ellipse.h>
-
-#include "gal/util/e-i18n.h"
-#include "gal/util/e-util.h"
-#include "gal/widgets/e-canvas.h"
-#include "gal/widgets/e-canvas-background.h"
-#include "gal/widgets/e-canvas-vbox.h"
-#include "gal/widgets/e-unicode.h"
-#include "e-table.h"
-#include "e-table-header-item.h"
-#include "e-table-header-utils.h"
-#include "e-table-subset.h"
-#include "e-table-item.h"
-#include "e-table-group.h"
-#include "e-table-group-leaf.h"
-#include "e-table-click-to-add.h"
-#include "e-table-specification.h"
-#include "e-table-state.h"
-#include "e-table-column-specification.h"
-
-#include "e-table-utils.h"
-
-#include <atk/atk.h>
-#include "gal/a11y/e-table/gal-a11y-e-table.h"
-
-#define COLUMN_HEADER_HEIGHT 16
-
-#define PARENT_TYPE gtk_table_get_type ()
-
-#define d(x)
-
-#if d(!)0
-#define e_table_item_leave_edit_(x) (e_table_item_leave_edit((x)), g_print ("%s: e_table_item_leave_edit\n", __FUNCTION__))
-#else
-#define e_table_item_leave_edit_(x) (e_table_item_leave_edit((x)))
-#endif
-
-static GtkObjectClass *parent_class;
-
-enum {
- CURSOR_CHANGE,
- CURSOR_ACTIVATED,
- SELECTION_CHANGE,
- DOUBLE_CLICK,
- RIGHT_CLICK,
- CLICK,
- KEY_PRESS,
- START_DRAG,
- STATE_CHANGE,
- WHITE_SPACE_EVENT,
-
- TABLE_DRAG_BEGIN,
- TABLE_DRAG_END,
- TABLE_DRAG_DATA_GET,
- TABLE_DRAG_DATA_DELETE,
-
- TABLE_DRAG_LEAVE,
- TABLE_DRAG_MOTION,
- TABLE_DRAG_DROP,
- TABLE_DRAG_DATA_RECEIVED,
-
- LAST_SIGNAL
-};
-
-enum {
- PROP_0,
- PROP_LENGTH_THRESHOLD,
- PROP_MODEL,
- PROP_UNIFORM_ROW_HEIGHT,
- PROP_ALWAYS_SEARCH,
- PROP_USE_CLICK_TO_ADD
-};
-
-enum {
- ET_SCROLL_UP = 1 << 0,
- ET_SCROLL_DOWN = 1 << 1,
- ET_SCROLL_LEFT = 1 << 2,
- ET_SCROLL_RIGHT = 1 << 3
-};
-
-static guint et_signals [LAST_SIGNAL] = { 0 };
-
-static void e_table_fill_table (ETable *e_table, ETableModel *model);
-static gboolean changed_idle (gpointer data);
-
-static void et_grab_focus (GtkWidget *widget);
-
-static void et_drag_begin (GtkWidget *widget,
- GdkDragContext *context,
- ETable *et);
-static void et_drag_end (GtkWidget *widget,
- GdkDragContext *context,
- ETable *et);
-static void et_drag_data_get(GtkWidget *widget,
- GdkDragContext *context,
- GtkSelectionData *selection_data,
- guint info,
- guint time,
- ETable *et);
-static void et_drag_data_delete(GtkWidget *widget,
- GdkDragContext *context,
- ETable *et);
-
-static void et_drag_leave(GtkWidget *widget,
- GdkDragContext *context,
- guint time,
- ETable *et);
-static gboolean et_drag_motion(GtkWidget *widget,
- GdkDragContext *context,
- gint x,
- gint y,
- guint time,
- ETable *et);
-static gboolean et_drag_drop(GtkWidget *widget,
- GdkDragContext *context,
- gint x,
- gint y,
- guint time,
- ETable *et);
-static void et_drag_data_received(GtkWidget *widget,
- GdkDragContext *context,
- gint x,
- gint y,
- GtkSelectionData *selection_data,
- guint info,
- guint time,
- ETable *et);
-
-static gint et_focus (GtkWidget *container, GtkDirectionType direction);
-
-static void scroll_off (ETable *et);
-static void scroll_on (ETable *et, guint scroll_direction);
-
-static void
-et_disconnect_model (ETable *et)
-{
- if (et->model == NULL)
- return;
-
- if (et->table_model_change_id != 0)
- g_signal_handler_disconnect (G_OBJECT (et->model),
- et->table_model_change_id);
- if (et->table_row_change_id != 0)
- g_signal_handler_disconnect (G_OBJECT (et->model),
- et->table_row_change_id);
- if (et->table_cell_change_id != 0)
- g_signal_handler_disconnect (G_OBJECT (et->model),
- et->table_cell_change_id);
- if (et->table_rows_inserted_id != 0)
- g_signal_handler_disconnect (G_OBJECT (et->model),
- et->table_rows_inserted_id);
- if (et->table_rows_deleted_id != 0)
- g_signal_handler_disconnect (G_OBJECT (et->model),
- et->table_rows_deleted_id);
-
- et->table_model_change_id = 0;
- et->table_row_change_id = 0;
- et->table_cell_change_id = 0;
- et->table_rows_inserted_id = 0;
- et->table_rows_deleted_id = 0;
-}
-
-static void
-e_table_state_change (ETable *et)
-{
- g_signal_emit (G_OBJECT (et), et_signals [STATE_CHANGE], 0);
-}
-
-#define CHECK_HORIZONTAL(et) if ((et)->horizontal_scrolling || (et)->horizontal_resize) e_table_header_update_horizontal (et->header);
-
-static void
-clear_current_search_col (ETable *et)
-{
- et->search_col_set = FALSE;
-}
-
-static ETableCol *
-current_search_col (ETable *et)
-{
- if (!et->search_col_set) {
- et->current_search_col =
- e_table_util_calculate_current_search_col (et->header,
- et->full_header,
- et->sort_info,
- et->always_search);
- et->search_col_set = TRUE;
- }
-
- return et->current_search_col;
-}
-
-static void
-et_size_request (GtkWidget *widget, GtkRequisition *request)
-{
- ETable *et = E_TABLE (widget);
- if (GTK_WIDGET_CLASS (parent_class)->size_request)
- GTK_WIDGET_CLASS (parent_class)->size_request (widget, request);
- if (et->horizontal_resize)
- request->width = MAX (request->width, et->header_width);
-}
-
-static void
-set_header_width (ETable *et)
-{
- if (et->horizontal_resize) {
- et->header_width = e_table_header_min_width (et->header);
- gtk_widget_queue_resize (GTK_WIDGET (et));
- }
-}
-
-static void
-structure_changed (ETableHeader *header, ETable *et)
-{
- e_table_state_change (et);
- set_header_width (et);
- clear_current_search_col (et);
-}
-
-static void
-expansion_changed (ETableHeader *header, ETable *et)
-{
- e_table_state_change (et);
- set_header_width (et);
-}
-
-static void
-dimension_changed (ETableHeader *header, int total_width, ETable *et)
-{
- set_header_width (et);
-}
-
-static void
-disconnect_header (ETable *e_table)
-{
- if (e_table->header == NULL)
- return;
-
- if (e_table->structure_change_id)
- g_signal_handler_disconnect (G_OBJECT (e_table->header),
- e_table->structure_change_id);
- if (e_table->expansion_change_id)
- g_signal_handler_disconnect (G_OBJECT (e_table->header),
- e_table->expansion_change_id);
- if (e_table->dimension_change_id)
- g_signal_handler_disconnect (G_OBJECT (e_table->header),
- e_table->dimension_change_id);
-
- g_object_unref(e_table->header);
- e_table->header = NULL;
-}
-
-static void
-connect_header (ETable *e_table, ETableState *state)
-{
- if (e_table->header != NULL)
- disconnect_header (e_table);
-
- e_table->header = e_table_state_to_header (GTK_WIDGET(e_table), e_table->full_header, state);
-
- e_table->structure_change_id =
- g_signal_connect (G_OBJECT (e_table->header), "structure_change",
- G_CALLBACK (structure_changed), e_table);
- e_table->expansion_change_id =
- g_signal_connect (G_OBJECT (e_table->header), "expansion_change",
- G_CALLBACK (expansion_changed), e_table);
- e_table->dimension_change_id =
- g_signal_connect (G_OBJECT (e_table->header), "dimension_change",
- G_CALLBACK (dimension_changed), e_table);
-}
-
-static void
-et_dispose (GObject *object)
-{
- ETable *et = E_TABLE (object);
-
- et_disconnect_model (et);
-
- if (et->search) {
- if (et->search_search_id)
- g_signal_handler_disconnect (G_OBJECT (et->search),
- et->search_search_id);
- if (et->search_accept_id)
- g_signal_handler_disconnect (G_OBJECT (et->search),
- et->search_accept_id);
- g_object_unref (et->search);
- et->search = NULL;
- }
-
- if (et->group_info_change_id) {
- g_signal_handler_disconnect (G_OBJECT (et->sort_info),
- et->group_info_change_id);
- et->group_info_change_id = 0;
- }
-
- if (et->sort_info_change_id) {
- g_signal_handler_disconnect (G_OBJECT (et->sort_info),
- et->sort_info_change_id);
- et->sort_info_change_id = 0;
- }
-
- if (et->reflow_idle_id) {
- g_source_remove(et->reflow_idle_id);
- et->reflow_idle_id = 0;
- }
-
- scroll_off (et);
-
- disconnect_header (et);
-
- if (et->model) {
- g_object_unref (et->model);
- et->model = NULL;
- }
-
- if (et->full_header) {
- g_object_unref (et->full_header);
- et->full_header = NULL;
- }
-
- if (et->sort_info) {
- g_object_unref (et->sort_info);
- et->sort_info = NULL;
- }
-
- if (et->sorter) {
- g_object_unref (et->sorter);
- et->sorter = NULL;
- }
-
- if (et->selection) {
- g_object_unref (et->selection);
- et->selection = NULL;
- }
-
- if (et->spec) {
- g_object_unref (et->spec);
- et->spec = NULL;
- }
-
- if (et->header_canvas != NULL) {
- gtk_widget_destroy (GTK_WIDGET (et->header_canvas));
- et->header_canvas = NULL;
- }
-
- if (et->site != NULL) {
- e_table_drag_source_unset (et);
- et->site = NULL;
- }
-
- if (et->table_canvas != NULL) {
- gtk_widget_destroy (GTK_WIDGET (et->table_canvas));
- et->table_canvas = NULL;
- }
-
- if (et->rebuild_idle_id != 0) {
- g_source_remove (et->rebuild_idle_id);
- et->rebuild_idle_id = 0;
- }
-
- g_free(et->click_to_add_message);
- et->click_to_add_message = NULL;
-
- g_free(et->domain);
- et->domain = NULL;
-
- (*G_OBJECT_CLASS (parent_class)->dispose)(object);
-}
-
-static void
-et_unrealize (GtkWidget *widget)
-{
- scroll_off (E_TABLE (widget));
-
- if (GTK_WIDGET_CLASS (parent_class)->unrealize)
- GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
-}
-
-static gboolean
-check_row (ETable *et, int model_row, int col, ETableSearchFunc search, char *string)
-{
- const void *value;
-
- value = e_table_model_value_at (et->model, col, model_row);
-
- return search (value, string);
-}
-
-static gboolean
-et_search_search (ETableSearch *search, char *string, ETableSearchFlags flags, ETable *et)
-{
- int cursor;
- int rows;
- int i;
- ETableCol *col = current_search_col (et);
-
- if (col == NULL)
- return FALSE;
-
- rows = e_table_model_row_count (et->model);
-
- g_object_get(et->selection,
- "cursor_row", &cursor,
- NULL);
-
- if ((flags & E_TABLE_SEARCH_FLAGS_CHECK_CURSOR_FIRST) && cursor < rows && cursor >= 0 && check_row (et, cursor, col->col_idx, col->search, string))
- return TRUE;
-
- cursor = e_sorter_model_to_sorted (E_SORTER (et->sorter), cursor);
-
- for (i = cursor + 1; i < rows; i++) {
- int model_row = e_sorter_sorted_to_model (E_SORTER (et->sorter), i);
- if (check_row (et, model_row, col->col_idx, col->search, string)) {
- e_selection_model_select_as_key_press(E_SELECTION_MODEL (et->selection), model_row, col->col_idx, GDK_CONTROL_MASK);
- return TRUE;
- }
- }
-
- for (i = 0; i < cursor; i++) {
- int model_row = e_sorter_sorted_to_model (E_SORTER (et->sorter), i);
- if (check_row (et, model_row, col->col_idx, col->search, string)) {
- e_selection_model_select_as_key_press(E_SELECTION_MODEL (et->selection), model_row, col->col_idx, GDK_CONTROL_MASK);
- return TRUE;
- }
- }
-
- cursor = e_sorter_sorted_to_model (E_SORTER (et->sorter), cursor);
-
- /* Check if the cursor row is the only matching row. */
- return (!(flags & E_TABLE_SEARCH_FLAGS_CHECK_CURSOR_FIRST) && cursor < rows && cursor >= 0 && check_row (et, cursor, col->col_idx, col->search, string));
-}
-
-static void
-et_search_accept (ETableSearch *search, ETable *et)
-{
- int cursor;
- ETableCol *col = current_search_col (et);
-
- if (col == NULL)
- return;
-
- g_object_get(et->selection,
- "cursor_row", &cursor,
- NULL);
- e_selection_model_select_as_key_press(E_SELECTION_MODEL (et->selection), cursor, col->col_idx, 0);
-}
-
-static void
-init_search (ETable *e_table)
-{
- if (e_table->search != NULL)
- return;
-
- e_table->search = e_table_search_new();
-
- e_table->search_search_id =
- g_signal_connect (G_OBJECT (e_table->search), "search",
- G_CALLBACK (et_search_search), e_table);
- e_table->search_accept_id =
- g_signal_connect (G_OBJECT (e_table->search), "accept",
- G_CALLBACK (et_search_accept), e_table);
-}
-
-static void
-et_finalize (GObject *object)
-{
- ETable *et = E_TABLE (object);
-
- g_free (et->click_to_add_message);
- et->click_to_add_message = NULL;
-
- g_free(et->domain);
- et->domain = NULL;
- G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-static void
-e_table_init (GtkObject *object)
-{
- ETable *e_table = E_TABLE (object);
- GtkTable *gtk_table = GTK_TABLE (object);
-
- GTK_WIDGET_SET_FLAGS (e_table, GTK_CAN_FOCUS);
-
- gtk_table->homogeneous = FALSE;
-
- e_table->sort_info = NULL;
- e_table->group_info_change_id = 0;
- e_table->sort_info_change_id = 0;
- e_table->structure_change_id = 0;
- e_table->expansion_change_id = 0;
- e_table->dimension_change_id = 0;
- e_table->reflow_idle_id = 0;
- e_table->scroll_idle_id = 0;
-
- e_table->alternating_row_colors = 1;
- e_table->horizontal_draw_grid = 1;
- e_table->vertical_draw_grid = 1;
- e_table->draw_focus = 1;
- e_table->cursor_mode = E_CURSOR_SIMPLE;
- e_table->length_threshold = 200;
- e_table->uniform_row_height = FALSE;
-
- e_table->need_rebuild = 0;
- e_table->rebuild_idle_id = 0;
-
- e_table->horizontal_scrolling = FALSE;
- e_table->horizontal_resize = FALSE;
-
- e_table->click_to_add_message = NULL;
- e_table->domain = NULL;
-
- e_table->drop_row = -1;
- e_table->drop_col = -1;
- e_table->site = NULL;
-
- e_table->do_drag = 0;
-
- e_table->sorter = NULL;
- e_table->selection = e_table_selection_model_new();
- e_table->cursor_loc = E_TABLE_CURSOR_LOC_NONE;
- e_table->spec = NULL;
-
- e_table->always_search = g_getenv ("GAL_ALWAYS_SEARCH") ? TRUE : FALSE;
-
- e_table->search = NULL;
- e_table->search_search_id = 0;
- e_table->search_accept_id = 0;
-
- e_table->current_search_col = NULL;
-
- e_table->header_width = 0;
-}
-
-/* Grab_focus handler for the ETable */
-static void
-et_grab_focus (GtkWidget *widget)
-{
- ETable *e_table;
-
- e_table = E_TABLE (widget);
-
- gtk_widget_grab_focus (GTK_WIDGET (e_table->table_canvas));
-}
-
-/* Focus handler for the ETable */
-static gint
-et_focus (GtkWidget *container, GtkDirectionType direction)
-{
- ETable *e_table;
-
- e_table = E_TABLE (container);
-
- if (GTK_CONTAINER (container)->focus_child) {
- gtk_container_set_focus_child (GTK_CONTAINER (container), NULL);
- return FALSE;
- }
-
- return gtk_widget_child_focus (GTK_WIDGET (e_table->table_canvas), direction);
-}
-
-static void
-set_header_canvas_width (ETable *e_table)
-{
- double oldwidth, oldheight, width;
-
- if (!(e_table->header_item && e_table->header_canvas && e_table->table_canvas))
- return;
-
- gnome_canvas_get_scroll_region (GNOME_CANVAS (e_table->table_canvas),
- NULL, NULL, &width, NULL);
- gnome_canvas_get_scroll_region (GNOME_CANVAS (e_table->header_canvas),
- NULL, NULL, &oldwidth, &oldheight);
-
- if (oldwidth != width ||
- oldheight != E_TABLE_HEADER_ITEM (e_table->header_item)->height - 1)
- gnome_canvas_set_scroll_region (
- GNOME_CANVAS (e_table->header_canvas),
- 0, 0, width, /* COLUMN_HEADER_HEIGHT - 1 */
- E_TABLE_HEADER_ITEM (e_table->header_item)->height - 1);
-
-}
-
-static void
-header_canvas_size_allocate (GtkWidget *widget, GtkAllocation *alloc, ETable *e_table)
-{
- set_header_canvas_width (e_table);
-
- /* When the header item is created ->height == 0,
- as the font is only created when everything is realized.
- So we set the usize here as well, so that the size of the
- header is correct */
- if (GTK_WIDGET (e_table->header_canvas)->allocation.height !=
- E_TABLE_HEADER_ITEM (e_table->header_item)->height)
- gtk_widget_set_usize (GTK_WIDGET (e_table->header_canvas), -2,
- E_TABLE_HEADER_ITEM (e_table->header_item)->height);
-}
-
-static void
-group_info_changed (ETableSortInfo *info, ETable *et)
-{
- gboolean will_be_grouped = e_table_sort_info_grouping_get_count(info) > 0;
- clear_current_search_col (et);
- if (et->is_grouped || will_be_grouped) {
- et->need_rebuild = TRUE;
- if (!et->rebuild_idle_id) {
- gtk_object_destroy (GTK_OBJECT (et->group));
- et->group = NULL;
- et->rebuild_idle_id = g_idle_add_full (20, changed_idle, et, NULL);
- }
- }
- e_table_state_change (et);
-}
-
-static void
-sort_info_changed (ETableSortInfo *info, ETable *et)
-{
- clear_current_search_col (et);
- e_table_state_change (et);
-}
-
-static void
-e_table_setup_header (ETable *e_table)
-{
- char *pointer;
- e_table->header_canvas = GNOME_CANVAS (e_canvas_new ());
-
- gtk_widget_show (GTK_WIDGET (e_table->header_canvas));
-
- pointer = g_strdup_printf("%p", e_table);
-
- e_table->header_item = gnome_canvas_item_new (
- gnome_canvas_root (e_table->header_canvas),
- e_table_header_item_get_type (),
- "ETableHeader", e_table->header,
- "full_header", e_table->full_header,
- "sort_info", e_table->sort_info,
- "dnd_code", pointer,
- "table", e_table,
- NULL);
-
- g_free(pointer);
-
- g_signal_connect (
- G_OBJECT (e_table->header_canvas), "size_allocate",
- G_CALLBACK (header_canvas_size_allocate), e_table);
-
- gtk_widget_set_usize (GTK_WIDGET (e_table->header_canvas), -2,
- E_TABLE_HEADER_ITEM (e_table->header_item)->height);
-}
-
-static gboolean
-table_canvas_reflow_idle (ETable *e_table)
-{
- gdouble height, width;
- gdouble item_height;
- gdouble oldheight, oldwidth;
- GtkAllocation *alloc = &(GTK_WIDGET (e_table->table_canvas)->allocation);
-
- g_object_get (e_table->canvas_vbox,
- "height", &height,
- "width", &width,
- NULL);
- item_height = height;
- height = MAX ((int)height, alloc->height);
- width = MAX((int)width, alloc->width);
- /* I have no idea why this needs to be -1, but it works. */
- gnome_canvas_get_scroll_region (GNOME_CANVAS (e_table->table_canvas),
- NULL, NULL, &oldwidth, &oldheight);
-
- if (oldwidth != width - 1 ||
- oldheight != height - 1) {
- gnome_canvas_set_scroll_region (GNOME_CANVAS (e_table->table_canvas),
- 0, 0, width - 1, height - 1);
- set_header_canvas_width (e_table);
- }
- e_table->reflow_idle_id = 0;
- return FALSE;
-}
-
-static void
-table_canvas_size_allocate (GtkWidget *widget, GtkAllocation *alloc,
- ETable *e_table)
-{
- gdouble width;
- gdouble height;
- gdouble item_height;
- GValue *val = g_new0 (GValue, 1);
- g_value_init (val, G_TYPE_DOUBLE);
-
- width = alloc->width;
- g_value_set_double (val, width);
- g_object_get (e_table->canvas_vbox,
- "height", &height,
- NULL);
- item_height = height;
- height = MAX ((int)height, alloc->height);
-
- g_object_set (e_table->canvas_vbox,
- "width", width,
- NULL);
- g_object_set_property (G_OBJECT (e_table->header), "width", val);
- g_free (val);
- if (e_table->reflow_idle_id)
- g_source_remove(e_table->reflow_idle_id);
- table_canvas_reflow_idle(e_table);
-}
-
-static void
-table_canvas_reflow (GnomeCanvas *canvas, ETable *e_table)
-{
- if (!e_table->reflow_idle_id)
- e_table->reflow_idle_id = g_idle_add_full (400, (GSourceFunc) table_canvas_reflow_idle, e_table, NULL);
-}
-
-static void
-click_to_add_cursor_change (ETableClickToAdd *etcta, int row, int col, ETable *et)
-{
- if (et->cursor_loc == E_TABLE_CURSOR_LOC_TABLE) {
- e_selection_model_clear(E_SELECTION_MODEL (et->selection));
- }
- et->cursor_loc = E_TABLE_CURSOR_LOC_ETCTA;
-}
-
-static void
-group_cursor_change (ETableGroup *etg, int row, ETable *et)
-{
- ETableCursorLoc old_cursor_loc;
-
- old_cursor_loc = et->cursor_loc;
-
- et->cursor_loc = E_TABLE_CURSOR_LOC_TABLE;
- g_signal_emit (G_OBJECT (et), et_signals [CURSOR_CHANGE], 0, row);
-
- if (old_cursor_loc == E_TABLE_CURSOR_LOC_ETCTA && et->click_to_add)
- e_table_click_to_add_commit(E_TABLE_CLICK_TO_ADD(et->click_to_add));
-}
-
-static void
-group_cursor_activated (ETableGroup *etg, int row, ETable *et)
-{
- g_signal_emit (G_OBJECT (et), et_signals [CURSOR_ACTIVATED], 0, row);
-}
-
-static void
-group_double_click (ETableGroup *etg, int row, int col, GdkEvent *event, ETable *et)
-{
- g_signal_emit (G_OBJECT (et), et_signals [DOUBLE_CLICK], 0, row, col, event);
-}
-
-static gint
-group_right_click (ETableGroup *etg, int row, int col, GdkEvent *event, ETable *et)
-{
- int return_val = 0;
- g_signal_emit (G_OBJECT (et), et_signals [RIGHT_CLICK], 0, row, col, event, &return_val);
- return return_val;
-}
-
-static gint
-group_click (ETableGroup *etg, int row, int col, GdkEvent *event, ETable *et)
-{
- int return_val = 0;
- g_signal_emit (G_OBJECT (et), et_signals [CLICK], 0, row, col, event, &return_val);
- return return_val;
-}
-
-static gint
-group_key_press (ETableGroup *etg, int row, int col, GdkEvent *event, ETable *et)
-{
- int return_val = 0;
- GdkEventKey *key = (GdkEventKey *) event;
- int y, row_local, col_local;
- GtkAdjustment *vadj;
-
- switch (key->keyval) {
- case GDK_Page_Down:
- case GDK_KP_Page_Down:
- vadj = gtk_layout_get_vadjustment (GTK_LAYOUT (et->table_canvas));
- y = CLAMP(vadj->value + (2 * vadj->page_size - 50), 0, vadj->upper);
- y -= vadj->value;
- e_table_get_cell_at (et, 30, y, &row_local, &col_local);
-
- if (row_local == -1)
- row_local = e_table_model_row_count (et->model) - 1;
-
- row_local = e_table_view_to_model_row (et, row_local);
- col_local = e_selection_model_cursor_col (E_SELECTION_MODEL (et->selection));
- e_selection_model_select_as_key_press (E_SELECTION_MODEL (et->selection), row_local, col_local, key->state);
- return_val = 1;
- break;
- case GDK_Page_Up:
- case GDK_KP_Page_Up:
- vadj = gtk_layout_get_vadjustment (GTK_LAYOUT (et->table_canvas));
- y = CLAMP(vadj->value - (vadj->page_size - 50), 0, vadj->upper);
- y -= vadj->value;
- e_table_get_cell_at (et, 30, y, &row_local, &col_local);
-
- if (row_local == -1)
- row_local = 0;
-
- row_local = e_table_view_to_model_row (et, row_local);
- col_local = e_selection_model_cursor_col (E_SELECTION_MODEL (et->selection));
- e_selection_model_select_as_key_press (E_SELECTION_MODEL (et->selection), row_local, col_local, key->state);
- return_val = 1;
- break;
- case GDK_BackSpace:
- init_search (et);
- if (e_table_search_backspace (et->search))
- return TRUE;
- /* Fall through */
- default:
- init_search (et);
- if ((key->state & ~(GDK_SHIFT_MASK | GDK_LOCK_MASK)) == 0
- && ((key->keyval >= GDK_a && key->keyval <= GDK_z) ||
- (key->keyval >= GDK_A && key->keyval <= GDK_Z) ||
- (key->keyval >= GDK_0 && key->keyval <= GDK_9)))
- e_table_search_input_character (et->search, key->keyval);
- g_signal_emit (G_OBJECT (et), et_signals [KEY_PRESS], 0,
- row, col, event, &return_val);
- break;
- }
- return return_val;
-}
-
-static gint
-group_start_drag (ETableGroup *etg, int row, int col, GdkEvent *event, ETable *et)
-{
- int return_val = 0;
- g_signal_emit (G_OBJECT (et), et_signals [START_DRAG], 0,
- row, col, event, &return_val);
- return return_val;
-}
-
-static void
-et_table_model_changed (ETableModel *model, ETable *et)
-{
- et->need_rebuild = TRUE;
- if (!et->rebuild_idle_id) {
- gtk_object_destroy (GTK_OBJECT (et->group));
- et->group = NULL;
- et->rebuild_idle_id = g_idle_add_full (20, changed_idle, et, NULL);
- }
-}
-
-static void
-et_table_row_changed (ETableModel *table_model, int row, ETable *et)
-{
- if (!et->need_rebuild) {
- if (e_table_group_remove (et->group, row))
- e_table_group_add (et->group, row);
- CHECK_HORIZONTAL(et);
- }
-}
-
-static void
-et_table_cell_changed (ETableModel *table_model, int view_col, int row, ETable *et)
-{
- et_table_row_changed (table_model, row, et);
-}
-
-static void
-et_table_rows_inserted (ETableModel *table_model, int row, int count, ETable *et)
-{
- /* This number has already been decremented. */
- int row_count = e_table_model_row_count(table_model);
- if (!et->need_rebuild) {
- int i;
- if (row != row_count - count)
- e_table_group_increment(et->group, row, count);
- for (i = 0; i < count; i++)
- e_table_group_add (et->group, row + i);
- CHECK_HORIZONTAL(et);
- }
-}
-
-static void
-et_table_rows_deleted (ETableModel *table_model, int row, int count, ETable *et)
-{
- int row_count = e_table_model_row_count(table_model);
- if (!et->need_rebuild) {
- int i;
- for (i = 0; i < count; i++)
- e_table_group_remove (et->group, row + i);
- if (row != row_count)
- e_table_group_decrement(et->group, row, count);
- CHECK_HORIZONTAL(et);
- }
-}
-
-static void
-et_build_groups (ETable *et)
-{
- gboolean was_grouped = et->is_grouped;
-
- et->is_grouped = e_table_sort_info_grouping_get_count(et->sort_info) > 0;
-
- et->group = e_table_group_new (GNOME_CANVAS_GROUP (et->canvas_vbox),
- et->full_header,
- et->header,
- et->model,
- et->sort_info,
- 0);
-
- if (et->use_click_to_add_end)
- e_canvas_vbox_add_item_start(E_CANVAS_VBOX(et->canvas_vbox), GNOME_CANVAS_ITEM(et->group));
- else
- e_canvas_vbox_add_item(E_CANVAS_VBOX(et->canvas_vbox), GNOME_CANVAS_ITEM(et->group));
-
- gnome_canvas_item_set(GNOME_CANVAS_ITEM(et->group),
- "alternating_row_colors", et->alternating_row_colors,
- "horizontal_draw_grid", et->horizontal_draw_grid,
- "vertical_draw_grid", et->vertical_draw_grid,
- "drawfocus", et->draw_focus,
- "cursor_mode", et->cursor_mode,
- "length_threshold", et->length_threshold,
- "uniform_row_height", et->uniform_row_height,
- "selection_model", et->selection,
- NULL);
-
- g_signal_connect (G_OBJECT (et->group), "cursor_change",
- G_CALLBACK (group_cursor_change), et);
- g_signal_connect (G_OBJECT (et->group), "cursor_activated",
- G_CALLBACK (group_cursor_activated), et);
- g_signal_connect (G_OBJECT (et->group), "double_click",
- G_CALLBACK (group_double_click), et);
- g_signal_connect (G_OBJECT (et->group), "right_click",
- G_CALLBACK (group_right_click), et);
- g_signal_connect (G_OBJECT (et->group), "click",
- G_CALLBACK (group_click), et);
- g_signal_connect (G_OBJECT (et->group), "key_press",
- G_CALLBACK (group_key_press), et);
- g_signal_connect (G_OBJECT (et->group), "start_drag",
- G_CALLBACK (group_start_drag), et);
-
-
- if (!(et->is_grouped) && was_grouped)
- et_disconnect_model (et);
-
- if (et->is_grouped && (!was_grouped)) {
- et->table_model_change_id = g_signal_connect (G_OBJECT (et->model), "model_changed",
- G_CALLBACK (et_table_model_changed), et);
-
- et->table_row_change_id = g_signal_connect (G_OBJECT (et->model), "model_row_changed",
- G_CALLBACK (et_table_row_changed), et);
-
- et->table_cell_change_id = g_signal_connect (G_OBJECT (et->model), "model_cell_changed",
- G_CALLBACK (et_table_cell_changed), et);
-
- et->table_rows_inserted_id = g_signal_connect (G_OBJECT (et->model), "model_rows_inserted",
- G_CALLBACK (et_table_rows_inserted), et);
-
- et->table_rows_deleted_id = g_signal_connect (G_OBJECT (et->model), "model_rows_deleted",
- G_CALLBACK (et_table_rows_deleted), et);
-
- }
-
- if (et->is_grouped)
- e_table_fill_table (et, et->model);
-}
-
-static gboolean
-changed_idle (gpointer data)
-{
- ETable *et = E_TABLE (data);
-
- if (et->need_rebuild) {
- if (et->group)
- gtk_object_destroy (GTK_OBJECT (et->group));
- et_build_groups(et);
- g_object_set (et->canvas_vbox,
- "width", (double) GTK_WIDGET (et->table_canvas)->allocation.width,
- NULL);
-
- if (GTK_WIDGET_REALIZED(et->table_canvas))
- table_canvas_size_allocate (GTK_WIDGET(et->table_canvas), &GTK_WIDGET(et->table_canvas)->allocation, et);
- }
-
- et->need_rebuild = 0;
- et->rebuild_idle_id = 0;
-
- CHECK_HORIZONTAL(et);
-
- return FALSE;
-}
-
-static void
-et_canvas_realize (GtkWidget *canvas, ETable *e_table)
-{
- gnome_canvas_item_set(
- e_table->white_item,
- "fill_color_gdk", &GTK_WIDGET(e_table->table_canvas)->style->base[GTK_STATE_NORMAL],
- NULL);
-
- CHECK_HORIZONTAL(e_table);
- set_header_width (e_table);
-}
-
-static gint
-white_item_event (GnomeCanvasItem *white_item, GdkEvent *event, ETable *e_table)
-{
- int return_val = 0;
- g_signal_emit (GTK_OBJECT (e_table), et_signals [WHITE_SPACE_EVENT], 0,
- event, &return_val);
- return return_val;
-}
-
-static void
-et_eti_leave_edit (ETable *et)
-{
- GnomeCanvas *canvas = et->table_canvas;
-
- if (GTK_WIDGET_HAS_FOCUS(canvas)) {
- GnomeCanvasItem *item = GNOME_CANVAS(canvas)->focused_item;
-
- if (E_IS_TABLE_ITEM(item)) {
- e_table_item_leave_edit_(E_TABLE_ITEM(item));
- }
- }
-}
-
-static gint
-et_canvas_root_event (GnomeCanvasItem *root, GdkEvent *event, ETable *e_table)
-{
- switch (event->type) {
- case GDK_BUTTON_PRESS:
- case GDK_2BUTTON_PRESS:
- case GDK_BUTTON_RELEASE:
- if (event->button.button != 4 && event->button.button != 5) {
- et_eti_leave_edit (e_table);
- return TRUE;
- }
- break;
- default:
- break;
- }
-
- return FALSE;
-}
-
-/* Finds the first descendant of the group that is an ETableItem and focuses it */
-static void
-focus_first_etable_item (ETableGroup *group)
-{
- GnomeCanvasGroup *cgroup;
- GList *l;
-
- cgroup = GNOME_CANVAS_GROUP (group);
-
- for (l = cgroup->item_list; l; l = l->next) {
- GnomeCanvasItem *i;
-
- i = GNOME_CANVAS_ITEM (l->data);
-
- if (E_IS_TABLE_GROUP (i))
- focus_first_etable_item (E_TABLE_GROUP (i));
- else if (E_IS_TABLE_ITEM (i)) {
- e_table_item_set_cursor (E_TABLE_ITEM (i), 0, 0);
- gnome_canvas_item_grab_focus (i);
- }
- }
-}
-
-/* Handler for focus events in the table_canvas; we have to repaint ourselves
- * always, and also give the focus to some ETableItem if we get focused.
- */
-static gint
-table_canvas_focus_event_cb (GtkWidget *widget, GdkEventFocus *event, gpointer data)
-{
- GnomeCanvas *canvas;
- ECanvas *ecanvas;
- ETable *etable;
-
- gtk_widget_queue_draw (widget);
- canvas = GNOME_CANVAS (widget);
- ecanvas = E_CANVAS (widget);
-
- if (!event->in) {
- gtk_im_context_focus_out(ecanvas->im_context);
- return FALSE;
- } else {
- gtk_im_context_focus_in(ecanvas->im_context);
- }
-
- etable = E_TABLE (data);
-
- if (e_table_model_row_count(etable->model) < 1
- && (etable->click_to_add)
- && !(E_TABLE_CLICK_TO_ADD(etable->click_to_add)->row)) {
- gnome_canvas_item_grab_focus (etable->canvas_vbox);
- gnome_canvas_item_grab_focus (etable->click_to_add);
- } else if (!canvas->focused_item && etable->group) {
- focus_first_etable_item (etable->group);
- } else if (canvas->focused_item) {
- ESelectionModel *selection = (ESelectionModel *)etable->selection;
-
- /* check whether click_to_add already got the focus */
- if (etable->click_to_add) {
- GnomeCanvasItem *row = E_TABLE_CLICK_TO_ADD(etable->click_to_add)->row;
- if (canvas->focused_item == row)
- return TRUE;
- }
-
- if (e_selection_model_cursor_row (selection) == -1)
- focus_first_etable_item (etable->group);
- }
-
- return TRUE;
-}
-
-static gboolean
-canvas_vbox_event (ECanvasVbox *vbox, GdkEventKey *key, ETable *etable)
-{
- GnomeCanvas *canvas;
-
- canvas = GNOME_CANVAS (etable->table_canvas);
- switch (key->keyval) {
- case GDK_Tab:
- case GDK_KP_Tab:
- case GDK_ISO_Left_Tab:
- if ((key->state & GDK_CONTROL_MASK) && etable->click_to_add) {
- gnome_canvas_item_grab_focus (etable->click_to_add);
- break;
- }
- default:
- return FALSE;
- }
-
- return TRUE;
-}
-
-static gboolean
-click_to_add_event (ETableClickToAdd *etcta, GdkEventKey *key, ETable *etable)
-{
- GnomeCanvas *canvas;
-
- canvas = GNOME_CANVAS (etable->table_canvas);
- switch (key->keyval) {
- case GDK_Tab:
- case GDK_KP_Tab:
- case GDK_ISO_Left_Tab:
- if (key->state & GDK_CONTROL_MASK) {
- if (etable->group) {
- if (e_table_model_row_count(etable->model) > 0)
- focus_first_etable_item (etable->group);
- else
- gtk_widget_child_focus (
- gtk_widget_get_toplevel(GTK_WIDGET(etable->table_canvas)), GTK_DIR_TAB_FORWARD);
- break;
- }
- }
- default:
- return FALSE;
- }
-
- return FALSE;
-}
-
-static void
-e_table_setup_table (ETable *e_table, ETableHeader *full_header, ETableHeader *header,
- ETableModel *model)
-{
- e_table->table_canvas = GNOME_CANVAS (e_canvas_new ());
- g_signal_connect (
- G_OBJECT (e_table->table_canvas), "size_allocate",
- G_CALLBACK (table_canvas_size_allocate), e_table);
- g_signal_connect (
- G_OBJECT (e_table->table_canvas), "focus_in_event",
- G_CALLBACK (table_canvas_focus_event_cb), e_table);
- g_signal_connect (
- G_OBJECT (e_table->table_canvas), "focus_out_event",
- G_CALLBACK (table_canvas_focus_event_cb), e_table);
-
- g_signal_connect (
- G_OBJECT (e_table), "drag_begin",
- G_CALLBACK (et_drag_begin), e_table);
- g_signal_connect (
- G_OBJECT (e_table), "drag_end",
- G_CALLBACK (et_drag_end), e_table);
- g_signal_connect (
- G_OBJECT (e_table), "drag_data_get",
- G_CALLBACK (et_drag_data_get), e_table);
- g_signal_connect (
- G_OBJECT (e_table), "drag_data_delete",
- G_CALLBACK (et_drag_data_delete), e_table);
- g_signal_connect (
- G_OBJECT (e_table), "drag_motion",
- G_CALLBACK (et_drag_motion), e_table);
- g_signal_connect (
- G_OBJECT (e_table), "drag_leave",
- G_CALLBACK (et_drag_leave), e_table);
- g_signal_connect (
- G_OBJECT (e_table), "drag_drop",
- G_CALLBACK (et_drag_drop), e_table);
- g_signal_connect (
- G_OBJECT (e_table), "drag_data_received",
- G_CALLBACK (et_drag_data_received), e_table);
-
- g_signal_connect (G_OBJECT(e_table->table_canvas), "reflow",
- G_CALLBACK (table_canvas_reflow), e_table);
-
- gtk_widget_show (GTK_WIDGET (e_table->table_canvas));
-
-
- e_table->white_item = gnome_canvas_item_new(
- gnome_canvas_root(e_table->table_canvas),
- e_canvas_background_get_type(),
- "fill_color_gdk", &GTK_WIDGET(e_table->table_canvas)->style->base[GTK_STATE_NORMAL],
- NULL);
-
- g_signal_connect (G_OBJECT (e_table->white_item), "event",
- G_CALLBACK (white_item_event), e_table);
-
- g_signal_connect (G_OBJECT(e_table->table_canvas), "realize",
- G_CALLBACK(et_canvas_realize), e_table);
-
- g_signal_connect (G_OBJECT(gnome_canvas_root (e_table->table_canvas)), "event",
- G_CALLBACK(et_canvas_root_event), e_table);
-
- e_table->canvas_vbox = gnome_canvas_item_new(
- gnome_canvas_root(e_table->table_canvas),
- e_canvas_vbox_get_type(),
- "spacing", 10.0,
- NULL);
-
- g_signal_connect (
- G_OBJECT (e_table->canvas_vbox), "event",
- G_CALLBACK (canvas_vbox_event), e_table);
-
- et_build_groups(e_table);
-
- if (e_table->use_click_to_add) {
- e_table->click_to_add = gnome_canvas_item_new (
- GNOME_CANVAS_GROUP(e_table->canvas_vbox),
- e_table_click_to_add_get_type (),
- "header", e_table->header,
- "model", e_table->model,
- "message", e_table->click_to_add_message,
- NULL);
-
- if (e_table->use_click_to_add_end)
- e_canvas_vbox_add_item (
- E_CANVAS_VBOX(e_table->canvas_vbox),
- e_table->click_to_add);
- else
- e_canvas_vbox_add_item_start (
- E_CANVAS_VBOX(e_table->canvas_vbox),
- e_table->click_to_add);
-
- g_signal_connect (
- G_OBJECT (e_table->click_to_add), "event",
- G_CALLBACK (click_to_add_event), e_table);
- g_signal_connect (
- G_OBJECT (e_table->click_to_add), "cursor_change",
- G_CALLBACK (click_to_add_cursor_change), e_table);
- }
-}
-
-static void
-e_table_fill_table (ETable *e_table, ETableModel *model)
-{
- e_table_group_add_all (e_table->group);
-}
-
-/**
- * e_table_set_state_object:
- * @e_table: The #ETable object to modify
- * @state: The #ETableState to use
- *
- * This routine sets the state of the #ETable from the given
- * #ETableState.
- *
- **/
-void
-e_table_set_state_object(ETable *e_table, ETableState *state)
-{
- GValue *val = g_new0 (GValue, 1);
- g_value_init (val, G_TYPE_DOUBLE);
-
- connect_header (e_table, state);
-
- g_value_set_double (val, (double) (GTK_WIDGET(e_table->table_canvas)->allocation.width));
- g_object_set_property (G_OBJECT (e_table->header), "width", val);
- g_free (val);
-
- if (e_table->sort_info) {
- if (e_table->group_info_change_id)
- g_signal_handler_disconnect (G_OBJECT (e_table->sort_info),
- e_table->group_info_change_id);
- if (e_table->sort_info_change_id)
- g_signal_handler_disconnect (G_OBJECT (e_table->sort_info),
- e_table->sort_info_change_id);
- g_object_unref(e_table->sort_info);
- }
- if (state->sort_info) {
- e_table->sort_info = e_table_sort_info_duplicate(state->sort_info);
- e_table_sort_info_set_can_group (e_table->sort_info, e_table->allow_grouping);
- e_table->group_info_change_id =
- g_signal_connect (G_OBJECT (e_table->sort_info), "group_info_changed",
- G_CALLBACK (group_info_changed), e_table);
- e_table->sort_info_change_id =
- g_signal_connect (G_OBJECT (e_table->sort_info), "sort_info_changed",
- G_CALLBACK (sort_info_changed), e_table);
- }
- else
- e_table->sort_info = NULL;
-
- if (e_table->sorter)
- g_object_set(e_table->sorter,
- "sort_info", e_table->sort_info,
- NULL);
- if (e_table->header_item)
- g_object_set(e_table->header_item,
- "ETableHeader", e_table->header,
- "sort_info", e_table->sort_info,
- NULL);
- if (e_table->click_to_add)
- g_object_set(e_table->click_to_add,
- "header", e_table->header,
- NULL);
-
- e_table->need_rebuild = TRUE;
- if (!e_table->rebuild_idle_id)
- e_table->rebuild_idle_id = g_idle_add_full (20, changed_idle, e_table, NULL);
-}
-
-/**
- * e_table_set_state:
- * @e_table: The #ETable object to modify
- * @state_str: a string representing an #ETableState
- *
- * This routine sets the state of the #ETable from a string.
- *
- **/
-void
-e_table_set_state (ETable *e_table,
- const gchar *state_str)
-{
- ETableState *state;
-
- g_return_if_fail(e_table != NULL);
- g_return_if_fail(E_IS_TABLE(e_table));
- g_return_if_fail(state_str != NULL);
-
- state = e_table_state_new();
- e_table_state_load_from_string(state, state_str);
-
- if (state->col_count > 0)
- e_table_set_state_object(e_table, state);
-
- g_object_unref(state);
-}
-
-/**
- * e_table_load_state:
- * @e_table: The #ETable object to modify
- * @filename: name of the file to use
- *
- * This routine sets the state of the #ETable from a file.
- *
- **/
-void
-e_table_load_state (ETable *e_table,
- const gchar *filename)
-{
- ETableState *state;
-
- g_return_if_fail(e_table != NULL);
- g_return_if_fail(E_IS_TABLE(e_table));
- g_return_if_fail(filename != NULL);
-
- state = e_table_state_new();
- e_table_state_load_from_file(state, filename);
-
- if (state->col_count > 0)
- e_table_set_state_object(e_table, state);
-
- g_object_unref(state);
-}
-
-/**
- * e_table_get_state_object:
- * @e_table: #ETable object to act on
- *
- * Builds an #ETableState corresponding to the current state of the
- * #ETable.
- *
- * Return value:
- * The %ETableState object generated.
- **/
-ETableState *
-e_table_get_state_object (ETable *e_table)
-{
- ETableState *state;
- int full_col_count;
- int i, j;
-
- state = e_table_state_new();
- if (state->sort_info)
- g_object_unref (state->sort_info);
- state->sort_info = e_table->sort_info;
- g_object_ref(state->sort_info);
-
-
- state->col_count = e_table_header_count (e_table->header);
- full_col_count = e_table_header_count (e_table->full_header);
- state->columns = g_new(int, state->col_count);
- state->expansions = g_new(double, state->col_count);
- for (i = 0; i < state->col_count; i++) {
- ETableCol *col = e_table_header_get_column(e_table->header, i);
- state->columns[i] = -1;
- for (j = 0; j < full_col_count; j++) {
- if (col->col_idx == e_table_header_index(e_table->full_header, j)) {
- state->columns[i] = j;
- break;
- }
- }
- state->expansions[i] = col->expansion;
- }
-
- return state;
-}
-
-/**
- * e_table_get_state:
- * @e_table: The #ETable to act on.
- *
- * Builds a state object based on the current state and returns the
- * string corresponding to that state.
- *
- * Return value:
- * A string describing the current state of the #ETable.
- **/
-gchar *e_table_get_state (ETable *e_table)
-{
- ETableState *state;
- gchar *string;
-
- state = e_table_get_state_object(e_table);
- string = e_table_state_save_to_string(state);
- g_object_unref(state);
- return string;
-}
-
-/**
- * e_table_save_state:
- * @e_table: The #ETable to act on
- * @filename: name of the file to save to
- *
- * Saves the state of the @e_table object into the file pointed by
- * @filename.
- *
- **/
-void
-e_table_save_state (ETable *e_table,
- const gchar *filename)
-{
- ETableState *state;
-
- state = e_table_get_state_object(e_table);
- e_table_state_save_to_file(state, filename);
- g_object_unref(state);
-}
-
-static void
-et_selection_model_selection_changed (ETableGroup *etg, ETable *et)
-{
- g_signal_emit (G_OBJECT (et), et_signals [SELECTION_CHANGE], 0);
-}
-
-static void
-et_selection_model_selection_row_changed (ETableGroup *etg, int row, ETable *et)
-{
- g_signal_emit (G_OBJECT (et), et_signals [SELECTION_CHANGE], 0);
-}
-
-static ETable *
-et_real_construct (ETable *e_table, ETableModel *etm, ETableExtras *ete,
- ETableSpecification *specification, ETableState *state)
-{
- int row = 0;
- int col_count, i;
- GValue *val = g_new0 (GValue, 1);
- g_value_init (val, G_TYPE_OBJECT);
-
- if (ete)
- g_object_ref(ete);
- else {
- ete = e_table_extras_new();
- }
-
- e_table->domain = g_strdup (specification->domain);
-
- e_table->use_click_to_add = specification->click_to_add;
- e_table->use_click_to_add_end = specification->click_to_add_end;
- e_table->click_to_add_message = g_strdup (dgettext (e_table->domain, specification->click_to_add_message));
- e_table->alternating_row_colors = specification->alternating_row_colors;
- e_table->horizontal_draw_grid = specification->horizontal_draw_grid;
- e_table->vertical_draw_grid = specification->vertical_draw_grid;
- e_table->draw_focus = specification->draw_focus;
- e_table->cursor_mode = specification->cursor_mode;
- e_table->full_header = e_table_spec_to_full_header(specification, ete);
- g_object_ref (e_table->full_header);
-
- col_count = e_table_header_count (e_table->full_header);
- for (i = 0; i < col_count; i++) {
- ETableCol *col = e_table_header_get_column(e_table->full_header, i);
- if (col && col->search) {
- e_table->current_search_col = col;
- e_table->search_col_set = TRUE;
- break;
- }
- }
-
- e_table->model = etm;
- g_object_ref (etm);
-
- gtk_widget_push_colormap (gdk_rgb_get_cmap ());
-
- connect_header (e_table, state);
- e_table->horizontal_scrolling = specification->horizontal_scrolling;
- e_table->horizontal_resize = specification->horizontal_resize;
- e_table->allow_grouping = specification->allow_grouping;
-
- e_table->sort_info = state->sort_info;
- g_object_ref (state->sort_info);
- e_table_sort_info_set_can_group (e_table->sort_info, e_table->allow_grouping);
-
- e_table->group_info_change_id =
- g_signal_connect (G_OBJECT (e_table->sort_info), "group_info_changed",
- G_CALLBACK (group_info_changed), e_table);
-
- e_table->sort_info_change_id =
- g_signal_connect (G_OBJECT (e_table->sort_info), "sort_info_changed",
- G_CALLBACK (sort_info_changed), e_table);
-
-
- g_value_set_object (val, e_table->sort_info);
- g_object_set_property (G_OBJECT(e_table->header), "sort_info", val);
- g_free (val);
-
- e_table->sorter = e_table_sorter_new(etm, e_table->full_header, e_table->sort_info);
-
- g_object_set (e_table->selection,
- "model", etm,
- "selection_mode", specification->selection_mode,
- "cursor_mode", specification->cursor_mode,
- "sorter", e_table->sorter,
- "header", e_table->header,
- NULL);
-
- g_signal_connect(e_table->selection, "selection_changed",
- G_CALLBACK (et_selection_model_selection_changed), e_table);
- g_signal_connect(e_table->selection, "selection_row_changed",
- G_CALLBACK (et_selection_model_selection_row_changed), e_table);
-
- if (!specification->no_headers) {
- e_table_setup_header (e_table);
- }
- e_table_setup_table (e_table, e_table->full_header, e_table->header, etm);
- e_table_fill_table (e_table, etm);
-
- gtk_layout_get_vadjustment (GTK_LAYOUT (e_table->table_canvas))->step_increment = 20;
- gtk_adjustment_changed(gtk_layout_get_vadjustment (GTK_LAYOUT (e_table->table_canvas)));
- gtk_layout_get_hadjustment (GTK_LAYOUT (e_table->table_canvas))->step_increment = 20;
- gtk_adjustment_changed(gtk_layout_get_hadjustment (GTK_LAYOUT (e_table->table_canvas)));
-
- if (!specification->no_headers) {
- /*
- * The header
- */
- gtk_table_attach (GTK_TABLE (e_table), GTK_WIDGET (e_table->header_canvas),
- 0, 1, 0 + row, 1 + row,
- GTK_FILL | GTK_EXPAND,
- GTK_FILL, 0, 0);
- row ++;
- }
- gtk_table_attach (GTK_TABLE (e_table), GTK_WIDGET (e_table->table_canvas),
- 0, 1, 0 + row, 1 + row,
- GTK_FILL | GTK_EXPAND,
- GTK_FILL | GTK_EXPAND,
- 0, 0);
-
- gtk_widget_pop_colormap ();
-
- g_object_unref(ete);
-
- return e_table;
-}
-
-/**
- * e_table_construct:
- * @e_table: The newly created #ETable object.
- * @etm: The model for this table.
- * @ete: An optional #ETableExtras. (%NULL is valid.)
- * @spec_str: The spec.
- * @state_str: An optional state. (%NULL is valid.)
- *
- * This is the internal implementation of e_table_new() for use by
- * subclasses or language bindings. See e_table_new() for details.
- *
- * Return value:
- * The passed in value @e_table or %NULL if there's an error.
- **/
-ETable *
-e_table_construct (ETable *e_table, ETableModel *etm, ETableExtras *ete,
- const char *spec_str, const char *state_str)
-{
- ETableSpecification *specification;
- ETableState *state;
-
- g_return_val_if_fail(e_table != NULL, NULL);
- g_return_val_if_fail(E_IS_TABLE(e_table), NULL);
- g_return_val_if_fail(etm != NULL, NULL);
- g_return_val_if_fail(E_IS_TABLE_MODEL(etm), NULL);
- g_return_val_if_fail(ete == NULL || E_IS_TABLE_EXTRAS(ete), NULL);
- g_return_val_if_fail(spec_str != NULL, NULL);
-
- g_object_ref (etm);
-
- specification = e_table_specification_new();
- g_object_ref (specification);
- if (!e_table_specification_load_from_string(specification, spec_str)) {
- g_object_unref(specification);
- return NULL;
- }
-
- if (state_str) {
- state = e_table_state_new();
- g_object_ref (state);
- e_table_state_load_from_string(state, state_str);
- if (state->col_count <= 0) {
- g_object_unref(state);
- state = specification->state;
- g_object_ref(state);
- }
- } else {
- state = specification->state;
- g_object_ref(state);
- }
-
- e_table = et_real_construct (e_table, etm, ete, specification, state);
-
- e_table->spec = specification;
- g_object_unref(state);
-
- return e_table;
-}
-
-/**
- * e_table_construct_from_spec_file:
- * @e_table: The newly created #ETable object.
- * @etm: The model for this table.
- * @ete: An optional #ETableExtras. (%NULL is valid.)
- * @spec_fn: The filename of the spec.
- * @state_fn: An optional state file. (%NULL is valid.)
- *
- * This is the internal implementation of e_table_new_from_spec_file()
- * for use by subclasses or language bindings. See
- * e_table_new_from_spec_file() for details.
- *
- * Return value:
- * The passed in value @e_table or %NULL if there's an error.
- **/
-ETable *
-e_table_construct_from_spec_file (ETable *e_table, ETableModel *etm, ETableExtras *ete,
- const char *spec_fn, const char *state_fn)
-{
- ETableSpecification *specification;
- ETableState *state;
-
- g_return_val_if_fail(e_table != NULL, NULL);
- g_return_val_if_fail(E_IS_TABLE(e_table), NULL);
- g_return_val_if_fail(etm != NULL, NULL);
- g_return_val_if_fail(E_IS_TABLE_MODEL(etm), NULL);
- g_return_val_if_fail(ete == NULL || E_IS_TABLE_EXTRAS(ete), NULL);
- g_return_val_if_fail(spec_fn != NULL, NULL);
-
- specification = e_table_specification_new();
- if (!e_table_specification_load_from_file(specification, spec_fn)) {
- g_object_unref(specification);
- return NULL;
- }
-
- if (state_fn) {
- state = e_table_state_new();
- if (!e_table_state_load_from_file(state, state_fn)) {
- g_object_unref(state);
- state = specification->state;
- g_object_ref(state);
- }
- if (state->col_count <= 0) {
- g_object_unref(state);
- state = specification->state;
- g_object_ref(state);
- }
- } else {
- state = specification->state;
- g_object_ref(state);
- }
-
- e_table = et_real_construct (e_table, etm, ete, specification, state);
-
- e_table->spec = specification;
- g_object_unref(state);
-
- return e_table;
-}
-
-/**
- * e_table_new:
- * @etm: The model for this table.
- * @ete: An optional #ETableExtras. (%NULL is valid.)
- * @spec: The spec.
- * @state: An optional state. (%NULL is valid.)
- *
- * This function creates an #ETable from the given parameters. The
- * #ETableModel is a table model to be represented. The #ETableExtras
- * is an optional set of pixbufs, cells, and sorting functions to be
- * used when interpreting the spec. If you pass in %NULL it uses the
- * default #ETableExtras. (See e_table_extras_new()).
- *
- * @spec is the specification of the set of viewable columns and the
- * default sorting state and such. @state is an optional string
- * specifying the current sorting state and such. If @state is NULL,
- * then the default state from the spec will be used.
- *
- * Return value:
- * The newly created #ETable or %NULL if there's an error.
- **/
-GtkWidget *
-e_table_new (ETableModel *etm, ETableExtras *ete, const char *spec, const char *state)
-{
- ETable *e_table;
-
- g_return_val_if_fail(etm != NULL, NULL);
- g_return_val_if_fail(E_IS_TABLE_MODEL(etm), NULL);
- g_return_val_if_fail(ete == NULL || E_IS_TABLE_EXTRAS(ete), NULL);
- g_return_val_if_fail(spec != NULL, NULL);
-
- e_table = g_object_new (E_TABLE_TYPE, NULL);
-
- e_table = e_table_construct (e_table, etm, ete, spec, state);
-
- return GTK_WIDGET (e_table);
-}
-
-/**
- * e_table_new_from_spec_file:
- * @etm: The model for this table.
- * @ete: An optional #ETableExtras. (%NULL is valid.)
- * @spec_fn: The filename of the spec.
- * @state_fn: An optional state file. (%NULL is valid.)
- *
- * This is very similar to e_table_new(), except instead of passing in
- * strings you pass in the file names of the spec and state to load.
- *
- * @spec_fn is the filename of the spec to load. If this file doesn't
- * exist, e_table_new_from_spec_file will return %NULL.
- *
- * @state_fn is the filename of the initial state to load. If this is
- * %NULL or if the specified file doesn't exist, the default state
- * from the spec file is used.
- *
- * Return value:
- * The newly created #ETable or %NULL if there's an error.
- **/
-GtkWidget *
-e_table_new_from_spec_file (ETableModel *etm, ETableExtras *ete, const char *spec_fn, const char *state_fn)
-{
- ETable *e_table;
-
- g_return_val_if_fail(etm != NULL, NULL);
- g_return_val_if_fail(E_IS_TABLE_MODEL(etm), NULL);
- g_return_val_if_fail(ete == NULL || E_IS_TABLE_EXTRAS(ete), NULL);
- g_return_val_if_fail(spec_fn != NULL, NULL);
-
- e_table = g_object_new (E_TABLE_TYPE, NULL);
-
- e_table = e_table_construct_from_spec_file (e_table, etm, ete, spec_fn, state_fn);
-
- return GTK_WIDGET (e_table);
-}
-
-#if 0
-static xmlNode *
-et_build_column_spec (ETable *e_table)
-{
- xmlNode *columns_shown;
- gint i;
- gint col_count;
-
- columns_shown = xmlNewNode (NULL, "columns-shown");
-
- col_count = e_table_header_count (e_table->header);
- for (i = 0; i < col_count; i++){
- gchar *text = g_strdup_printf ("%d", e_table_header_index(e_table->header, i));
- xmlNewChild (columns_shown, NULL, "column", text);
- g_free (text);
- }
-
- return columns_shown;
-}
-
-static xmlNode *
-et_build_grouping_spec (ETable *e_table)
-{
- xmlNode *node;
- xmlNode *grouping;
- int i;
- const int sort_count = e_table_sort_info_sorting_get_count (e_table->sort_info);
- const int group_count = e_table_sort_info_grouping_get_count (e_table->sort_info);
-
- grouping = xmlNewNode (NULL, "grouping");
- node = grouping;
-
- for (i = 0; i < group_count; i++) {
- ETableSortColumn column = e_table_sort_info_grouping_get_nth(e_table->sort_info, i);
- xmlNode *new_node = xmlNewChild(node, NULL, "group", NULL);
-
- e_xml_set_integer_prop_by_name (new_node, "column", column.column);
- e_xml_set_integer_prop_by_name (new_node, "ascending", column.ascending);
- node = new_node;
- }
-
- for (i = 0; i < sort_count; i++) {
- ETableSortColumn column = e_table_sort_info_sorting_get_nth(e_table->sort_info, i);
- xmlNode *new_node = xmlNewChild(node, NULL, "leaf", NULL);
-
- e_xml_set_integer_prop_by_name (new_node, "column", column.column);
- e_xml_set_integer_prop_by_name (new_node, "ascending", column.ascending);
- node = new_node;
- }
-
- return grouping;
-}
-
-static xmlDoc *
-et_build_tree (ETable *e_table)
-{
- xmlDoc *doc;
- xmlNode *root;
-
- doc = xmlNewDoc ("1.0");
- if (doc == NULL)
- return NULL;
-
- root = xmlNewDocNode (doc, NULL, "ETableSpecification", NULL);
- xmlDocSetRootElement (doc, root);
- xmlAddChild (root, et_build_column_spec (e_table));
- xmlAddChild (root, et_build_grouping_spec (e_table));
-
- return doc;
-}
-
-gchar *
-e_table_get_specification (ETable *e_table)
-{
- xmlDoc *doc;
- xmlChar *buffer;
- gint size;
-
- g_return_val_if_fail(e_table != NULL, NULL);
- g_return_val_if_fail(E_IS_TABLE(e_table), NULL);
-
- doc = et_build_tree (e_table);
- xmlDocDumpMemory (doc, &buffer, &size);
- xmlFreeDoc (doc);
-
- return buffer;
-}
-
-int
-e_table_set_specification (ETable *e_table, const char *spec)
-{
- xmlDoc *xmlSpec;
- int ret;
-
- g_return_val_if_fail(e_table != NULL, -1);
- g_return_val_if_fail(E_IS_TABLE(e_table), -1);
- g_return_val_if_fail(spec != NULL, -1);
-
- /* doesn't work yet, sigh */
- xmlSpec = xmlParseMemory ((char *)spec, strlen(spec));
- ret = et_real_set_specification(e_table, xmlSpec);
- xmlFreeDoc (xmlSpec);
-
- return ret;
-}
-
-void
-e_table_save_specification (ETable *e_table, const char *filename)
-{
- xmlDoc *doc = et_build_tree (e_table);
-
- g_return_if_fail(e_table != NULL);
- g_return_if_fail(E_IS_TABLE(e_table));
- g_return_if_fail(filename != NULL);
-
- e_xml_save_file (filename, doc);
-
- xmlFreeDoc (doc);
-}
-
-int
-e_table_load_specification (ETable *e_table, gchar *filename)
-{
- xmlDoc *xmlSpec;
- int ret;
-
- g_return_val_if_fail(e_table != NULL, -1);
- g_return_val_if_fail(E_IS_TABLE(e_table), -1);
- g_return_val_if_fail(filename != NULL, -1);
-
- /* doesn't work yet, yay */
- xmlSpec = xmlParseFile (filename);
- ret = et_real_set_specification(e_table, xmlSpec);
- xmlFreeDoc (xmlSpec);
-
- return ret;
-}
-#endif
-
-/**
- * e_table_set_cursor_row:
- * @e_table: The #ETable to set the cursor row of
- * @row: The row number
- *
- * Sets the cursor row and the selection to the given row number.
- **/
-void
-e_table_set_cursor_row (ETable *e_table, int row)
-{
- g_return_if_fail(e_table != NULL);
- g_return_if_fail(E_IS_TABLE(e_table));
- g_return_if_fail(row >= 0);
-
- g_object_set(e_table->selection,
- "cursor_row", row,
- NULL);
-}
-
-/**
- * e_table_get_cursor_row:
- * @e_table: The #ETable to query
- *
- * Calculates the cursor row. -1 means that we don't have a cursor.
- *
- * Return value:
- * Cursor row
- **/
-int
-e_table_get_cursor_row (ETable *e_table)
-{
- int row;
- g_return_val_if_fail(e_table != NULL, -1);
- g_return_val_if_fail(E_IS_TABLE(e_table), -1);
-
- g_object_get(e_table->selection,
- "cursor_row", &row,
- NULL);
- return row;
-}
-
-/**
- * e_table_selected_row_foreach:
- * @e_table: The #ETable to act on
- * @callback: The callback function to call
- * @closure: The value passed to the callback's closure argument
- *
- * Calls the given @callback function once for every selected row.
- *
- * If you change the selection or delete or add rows to the table
- * during these callbacks, problems can occur. A standard thing to do
- * is to create a list of rows or objects the function is called upon
- * and then act upon that list. (In inverse order if it's rows.)
- **/
-void
-e_table_selected_row_foreach (ETable *e_table,
- EForeachFunc callback,
- gpointer closure)
-{
- g_return_if_fail(e_table != NULL);
- g_return_if_fail(E_IS_TABLE(e_table));
-
- e_selection_model_foreach(E_SELECTION_MODEL (e_table->selection),
- callback,
- closure);
-}
-
-/**
- * e_table_selected_count:
- * @e_table: The #ETable to query
- *
- * Counts the number of selected rows.
- *
- * Return value:
- * The number of rows selected.
- **/
-gint
-e_table_selected_count (ETable *e_table)
-{
- g_return_val_if_fail(e_table != NULL, -1);
- g_return_val_if_fail(E_IS_TABLE(e_table), -1);
-
- return e_selection_model_selected_count(E_SELECTION_MODEL (e_table->selection));
-}
-
-/**
- * e_table_select_all:
- * @table: The #ETable to modify
- *
- * Selects all the rows in @table.
- **/
-void
-e_table_select_all (ETable *table)
-{
- g_return_if_fail (table != NULL);
- g_return_if_fail (E_IS_TABLE (table));
-
- e_selection_model_select_all (E_SELECTION_MODEL (table->selection));
-}
-
-/**
- * e_table_invert_selection:
- * @table: The #ETable to modify
- *
- * Inverts the selection in @table.
- **/
-void
-e_table_invert_selection (ETable *table)
-{
- g_return_if_fail (table != NULL);
- g_return_if_fail (E_IS_TABLE (table));
-
- e_selection_model_invert_selection (E_SELECTION_MODEL (table->selection));
-}
-
-
-/**
- * e_table_get_printable:
- * @e_table: #ETable to query
- *
- * Used for printing your #ETable.
- *
- * Return value:
- * The #EPrintable to print.
- **/
-EPrintable *
-e_table_get_printable (ETable *e_table)
-{
- g_return_val_if_fail(e_table != NULL, NULL);
- g_return_val_if_fail(E_IS_TABLE(e_table), NULL);
-
- return e_table_group_get_printable(e_table->group);
-}
-
-/**
- * e_table_right_click_up:
- * @table: The #ETable to modify.
- *
- * Call this function when you're done handling the right click if you
- * return TRUE from the "right_click" signal.
- **/
-void
-e_table_right_click_up (ETable *table)
-{
- e_selection_model_right_click_up(E_SELECTION_MODEL(table->selection));
-}
-
-/**
- * e_table_commit_click_to_add:
- * @table: The #ETable to modify
- *
- * Commits the current values in the click to add to the table.
- **/
-void
-e_table_commit_click_to_add (ETable *table)
-{
- et_eti_leave_edit (table);
- if (table->click_to_add)
- e_table_click_to_add_commit(E_TABLE_CLICK_TO_ADD(table->click_to_add));
-}
-
-static void
-et_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- ETable *etable = E_TABLE (object);
-
- switch (prop_id){
- case PROP_MODEL:
- g_value_set_object (value, etable->model);
- break;
- case PROP_UNIFORM_ROW_HEIGHT:
- g_value_set_boolean (value, etable->uniform_row_height);
- break;
- case PROP_ALWAYS_SEARCH:
- g_value_set_boolean (value, etable->always_search);
- break;
- case PROP_USE_CLICK_TO_ADD:
- g_value_set_boolean (value, etable->use_click_to_add);
- break;
- default:
- break;
- }
-}
-
-typedef struct {
- char *arg;
- gboolean setting;
-} bool_closure;
-
-static void
-et_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- ETable *etable = E_TABLE (object);
-
- switch (prop_id){
- case PROP_LENGTH_THRESHOLD:
- etable->length_threshold = g_value_get_int (value);
- if (etable->group) {
- gnome_canvas_item_set (GNOME_CANVAS_ITEM(etable->group),
- "length_threshold", etable->length_threshold,
- NULL);
- }
- break;
- case PROP_UNIFORM_ROW_HEIGHT:
- etable->uniform_row_height = g_value_get_boolean (value);
- if (etable->group) {
- gnome_canvas_item_set (GNOME_CANVAS_ITEM(etable->group),
- "uniform_row_height", etable->uniform_row_height,
- NULL);
- }
- break;
- case PROP_ALWAYS_SEARCH:
- if (etable->always_search == g_value_get_boolean (value))
- return;
-
- etable->always_search = g_value_get_boolean (value);
- clear_current_search_col (etable);
- break;
- case PROP_USE_CLICK_TO_ADD:
- if (etable->use_click_to_add == g_value_get_boolean (value))
- return;
-
- etable->use_click_to_add = g_value_get_boolean (value);
- clear_current_search_col (etable);
-
- if (etable->use_click_to_add) {
- etable->click_to_add = gnome_canvas_item_new
- (GNOME_CANVAS_GROUP(etable->canvas_vbox),
- e_table_click_to_add_get_type (),
- "header", etable->header,
- "model", etable->model,
- "message", etable->click_to_add_message,
- NULL);
-
- if (etable->use_click_to_add_end)
- e_canvas_vbox_add_item (E_CANVAS_VBOX(etable->canvas_vbox),
- etable->click_to_add);
- else
- e_canvas_vbox_add_item_start (E_CANVAS_VBOX(etable->canvas_vbox),
- etable->click_to_add);
-
- g_signal_connect (G_OBJECT (etable->click_to_add), "cursor_change",
- G_CALLBACK (click_to_add_cursor_change), etable);
- } else {
- gtk_object_destroy (GTK_OBJECT (etable->click_to_add));
- etable->click_to_add = NULL;
- }
- break;
- }
-}
-
-static void
-set_scroll_adjustments (ETable *table,
- GtkAdjustment *hadjustment,
- GtkAdjustment *vadjustment)
-{
- if (vadjustment != NULL) {
- vadjustment->step_increment = 20;
- gtk_adjustment_changed(vadjustment);
- }
- if (hadjustment != NULL) {
- hadjustment->step_increment = 20;
- gtk_adjustment_changed(hadjustment);
- }
-
- if (table->table_canvas != NULL) {
- gtk_layout_set_hadjustment (GTK_LAYOUT(table->table_canvas),
- hadjustment);
- gtk_layout_set_vadjustment (GTK_LAYOUT(table->table_canvas),
- vadjustment);
- }
-
- if (table->header_canvas != NULL)
- gtk_layout_set_hadjustment (GTK_LAYOUT(table->header_canvas),
- hadjustment);
-}
-
-/**
- * e_table_get_next_row:
- * @e_table: The #ETable to query
- * @model_row: The model row to go from
- *
- * This function is used when your table is sorted, but you're using
- * model row numbers. It returns the next row in sorted order as a model row.
- *
- * Return value:
- * The model row number.
- **/
-gint
-e_table_get_next_row (ETable *e_table,
- gint model_row)
-{
- g_return_val_if_fail(e_table != NULL, -1);
- g_return_val_if_fail(E_IS_TABLE(e_table), -1);
-
- if (e_table->sorter) {
- int i;
- i = e_sorter_model_to_sorted(E_SORTER (e_table->sorter), model_row);
- i++;
- if (i < e_table_model_row_count(e_table->model)) {
- return e_sorter_sorted_to_model(E_SORTER (e_table->sorter), i);
- } else
- return -1;
- } else
- if (model_row < e_table_model_row_count(e_table->model) - 1)
- return model_row + 1;
- else
- return -1;
-}
-
-/**
- * e_table_get_prev_row:
- * @e_table: The #ETable to query
- * @model_row: The model row to go from
- *
- * This function is used when your table is sorted, but you're using
- * model row numbers. It returns the previous row in sorted order as
- * a model row.
- *
- * Return value:
- * The model row number.
- **/
-gint
-e_table_get_prev_row (ETable *e_table,
- gint model_row)
-{
- g_return_val_if_fail(e_table != NULL, -1);
- g_return_val_if_fail(E_IS_TABLE(e_table), -1);
-
- if (e_table->sorter) {
- int i;
- i = e_sorter_model_to_sorted(E_SORTER (e_table->sorter), model_row);
- i--;
- if (i >= 0)
- return e_sorter_sorted_to_model(E_SORTER (e_table->sorter), i);
- else
- return -1;
- } else
- return model_row - 1;
-}
-
-/**
- * e_table_model_to_view_row:
- * @e_table: The #ETable to query
- * @model_row: The model row number
- *
- * Turns a model row into a view row.
- *
- * Return value:
- * The view row number.
- **/
-gint
-e_table_model_to_view_row (ETable *e_table,
- gint model_row)
-{
- g_return_val_if_fail(e_table != NULL, -1);
- g_return_val_if_fail(E_IS_TABLE(e_table), -1);
-
- if (e_table->sorter)
- return e_sorter_model_to_sorted(E_SORTER (e_table->sorter), model_row);
- else
- return model_row;
-}
-
-/**
- * e_table_view_to_model_row:
- * @e_table: The #ETable to query
- * @view_row: The view row number
- *
- * Turns a view row into a model row.
- *
- * Return value:
- * The model row number.
- **/
-gint
-e_table_view_to_model_row (ETable *e_table,
- gint view_row)
-{
- g_return_val_if_fail(e_table != NULL, -1);
- g_return_val_if_fail(E_IS_TABLE(e_table), -1);
-
- if (e_table->sorter)
- return e_sorter_sorted_to_model (E_SORTER (e_table->sorter), view_row);
- else
- return view_row;
-}
-
-/**
- * e_table_get_cell_at:
- * @table: An #ETable widget
- * @x: X coordinate for the pixel
- * @y: Y coordinate for the pixel
- * @row_return: Pointer to return the row value
- * @col_return: Pointer to return the column value
- *
- * Return the row and column for the cell in which the pixel at (@x, @y) is
- * contained.
- **/
-void
-e_table_get_cell_at (ETable *table,
- int x, int y,
- int *row_return, int *col_return)
-{
- g_return_if_fail (table != NULL);
- g_return_if_fail (E_IS_TABLE (table));
- g_return_if_fail (row_return != NULL);
- g_return_if_fail (col_return != NULL);
-
- /* FIXME it would be nice if it could handle a NULL row_return or
- * col_return gracefully. */
-
- x += GTK_LAYOUT(table->table_canvas)->hadjustment->value;
- y += GTK_LAYOUT(table->table_canvas)->vadjustment->value;
- e_table_group_compute_location(table->group, &x, &y, row_return, col_return);
-}
-
-/**
- * e_table_get_cell_geometry:
- * @table: The #ETable.
- * @row: The row to get the geometry of.
- * @col: The col to get the geometry of.
- * @x_return: Returns the x coordinate of the upper left hand corner of the cell with respect to the widget.
- * @y_return: Returns the y coordinate of the upper left hand corner of the cell with respect to the widget.
- * @width_return: Returns the width of the cell.
- * @height_return: Returns the height of the cell.
- *
- * Returns the x, y, width, and height of the given cell. These can
- * all be #NULL and they just won't be set.
- **/
-void
-e_table_get_cell_geometry (ETable *table,
- int row, int col,
- int *x_return, int *y_return,
- int *width_return, int *height_return)
-{
- g_return_if_fail (table != NULL);
- g_return_if_fail (E_IS_TABLE (table));
-
- e_table_group_get_cell_geometry(table->group, &row, &col, x_return, y_return, width_return, height_return);
-
- if (x_return && table->table_canvas)
- (*x_return) -= GTK_LAYOUT(table->table_canvas)->hadjustment->value;
- if (y_return) {
- if (table->table_canvas)
- (*y_return) -= GTK_LAYOUT(table->table_canvas)->vadjustment->value;
- if (table->header_canvas)
- (*y_return) += GTK_WIDGET(table->header_canvas)->allocation.height;
- }
-}
-
-/**
- * e_table_get_selection_model:
- * @table: The #ETable to query
- *
- * Returns the table's #ESelectionModel in case you want to access it
- * directly.
- *
- * Return value:
- * The #ESelectionModel.
- **/
-ESelectionModel *
-e_table_get_selection_model (ETable *table)
-{
- g_return_val_if_fail (table != NULL, NULL);
- g_return_val_if_fail (E_IS_TABLE (table), NULL);
-
- return E_SELECTION_MODEL (table->selection);
-}
-
-struct _ETableDragSourceSite
-{
- GdkModifierType start_button_mask;
- GtkTargetList *target_list; /* Targets for drag data */
- GdkDragAction actions; /* Possible actions */
- GdkColormap *colormap; /* Colormap for drag icon */
- GdkPixmap *pixmap; /* Icon for drag data */
- GdkBitmap *mask;
-
- /* Stored button press information to detect drag beginning */
- gint state;
- gint x, y;
- gint row, col;
-};
-
-typedef enum
-{
- GTK_DRAG_STATUS_DRAG,
- GTK_DRAG_STATUS_WAIT,
- GTK_DRAG_STATUS_DROP
-} GtkDragStatus;
-
-typedef struct _GtkDragDestInfo GtkDragDestInfo;
-typedef struct _GtkDragSourceInfo GtkDragSourceInfo;
-
-struct _GtkDragDestInfo
-{
- GtkWidget *widget; /* Widget in which drag is in */
- GdkDragContext *context; /* Drag context */
- GtkDragSourceInfo *proxy_source; /* Set if this is a proxy drag */
- GtkSelectionData *proxy_data; /* Set while retrieving proxied data */
- gboolean dropped : 1; /* Set after we receive a drop */
- guint32 proxy_drop_time; /* Timestamp for proxied drop */
- gboolean proxy_drop_wait : 1; /* Set if we are waiting for a
- * status reply before sending
- * a proxied drop on.
- */
- gint drop_x, drop_y; /* Position of drop */
-};
-
-struct _GtkDragSourceInfo
-{
- GtkWidget *widget;
- GtkTargetList *target_list; /* Targets for drag data */
- GdkDragAction possible_actions; /* Actions allowed by source */
- GdkDragContext *context; /* drag context */
- GtkWidget *icon_window; /* Window for drag */
- GtkWidget *ipc_widget; /* GtkInvisible for grab, message passing */
- GdkCursor *cursor; /* Cursor for drag */
- gint hot_x, hot_y; /* Hot spot for drag */
- gint button; /* mouse button starting drag */
-
- GtkDragStatus status; /* drag status */
- GdkEvent *last_event; /* motion event waiting for response */
-
- gint start_x, start_y; /* Initial position */
- gint cur_x, cur_y; /* Current Position */
-
- GList *selections; /* selections we've claimed */
-
- GtkDragDestInfo *proxy_dest; /* Set if this is a proxy drag */
-
- guint drop_timeout; /* Timeout for aborting drop */
- guint destroy_icon : 1; /* If true, destroy icon_window
- */
-};
-
-/* Drag & drop stuff. */
-/* Target */
-
-/**
- * e_table_drag_get_data:
- * @table:
- * @row:
- * @col:
- * @context:
- * @target:
- * @time:
- *
- *
- **/
-void
-e_table_drag_get_data (ETable *table,
- int row,
- int col,
- GdkDragContext *context,
- GdkAtom target,
- guint32 time)
-{
- g_return_if_fail(table != NULL);
- g_return_if_fail(E_IS_TABLE(table));
-
- gtk_drag_get_data(GTK_WIDGET(table),
- context,
- target,
- time);
-}
-
-/**
- * e_table_drag_highlight:
- * @table: The #ETable to highlight
- * @row: The row number of the cell to highlight
- * @col: The column number of the cell to highlight
- *
- * Set col to -1 to highlight the entire row. If row is -1, this is
- * identical to e_table_drag_unhighlight().
- **/
-void
-e_table_drag_highlight (ETable *table,
- int row,
- int col)
-{
- g_return_if_fail(table != NULL);
- g_return_if_fail(E_IS_TABLE(table));
-
- if (row != -1) {
- int x, y, width, height;
- if (col == -1) {
- e_table_get_cell_geometry (table, row, 0, &x, &y, &width, &height);
- x = 0;
- width = GTK_WIDGET (table->table_canvas)->allocation.width;
- } else {
- e_table_get_cell_geometry (table, row, col, &x, &y, &width, &height);
- x += GTK_LAYOUT(table->table_canvas)->hadjustment->value;
- }
- y += GTK_LAYOUT(table->table_canvas)->vadjustment->value;
-
- if (table->drop_highlight == NULL) {
- table->drop_highlight =
- gnome_canvas_item_new (gnome_canvas_root (table->table_canvas),
- gnome_canvas_rect_get_type (),
- "fill_color", NULL,
- /* "outline_color", "black",
- "width_pixels", 1,*/
- "outline_color_gdk", &(GTK_WIDGET (table)->style->fg[GTK_STATE_NORMAL]),
- NULL);
- }
- gnome_canvas_item_set (table->drop_highlight,
- "x1", (double) x,
- "x2", (double) x + width - 1,
- "y1", (double) y,
- "y2", (double) y + height - 1,
- NULL);
- } else {
- if (table->drop_highlight) {
- gtk_object_destroy (GTK_OBJECT (table->drop_highlight));
- table->drop_highlight = NULL;
- }
- }
-}
-
-/**
- * e_table_drag_unhighlight:
- * @table: The #ETable to unhighlight
- *
- * Removes the highlight from an #ETable.
- **/
-void
-e_table_drag_unhighlight (ETable *table)
-{
- g_return_if_fail(table != NULL);
- g_return_if_fail(E_IS_TABLE(table));
-
- if (table->drop_highlight) {
- gtk_object_destroy (GTK_OBJECT (table->drop_highlight));
- table->drop_highlight = NULL;
- }
-}
-
-void e_table_drag_dest_set (ETable *table,
- GtkDestDefaults flags,
- const GtkTargetEntry *targets,
- gint n_targets,
- GdkDragAction actions)
-{
- g_return_if_fail(table != NULL);
- g_return_if_fail(E_IS_TABLE(table));
-
- gtk_drag_dest_set(GTK_WIDGET(table),
- flags,
- targets,
- n_targets,
- actions);
-}
-
-void e_table_drag_dest_set_proxy (ETable *table,
- GdkWindow *proxy_window,
- GdkDragProtocol protocol,
- gboolean use_coordinates)
-{
- g_return_if_fail(table != NULL);
- g_return_if_fail(E_IS_TABLE(table));
-
- gtk_drag_dest_set_proxy(GTK_WIDGET(table),
- proxy_window,
- protocol,
- use_coordinates);
-}
-
-/*
- * There probably should be functions for setting the targets
- * as a GtkTargetList
- */
-
-void
-e_table_drag_dest_unset (GtkWidget *widget)
-{
- g_return_if_fail(widget != NULL);
- g_return_if_fail(E_IS_TABLE(widget));
-
- gtk_drag_dest_unset(widget);
-}
-
-/* Source side */
-
-static gint
-et_real_start_drag (ETable *table, int row, int col, GdkEvent *event)
-{
- GtkDragSourceInfo *info;
- GdkDragContext *context;
- ETableDragSourceSite *site;
-
- if (table->do_drag) {
- site = table->site;
-
- site->state = 0;
- context = e_table_drag_begin (table, row, col,
- site->target_list,
- site->actions,
- 1, event);
-
- if (context) {
- info = g_dataset_get_data (context, "gtk-info");
-
- if (info && !info->icon_window) {
- if (site->pixmap)
- gtk_drag_set_icon_pixmap (context,
- site->colormap,
- site->pixmap,
- site->mask, -2, -2);
- else
- gtk_drag_set_icon_default (context);
- }
- }
- return TRUE;
- }
- return FALSE;
-}
-
-/**
- * e_table_drag_source_set:
- * @table: The #ETable to set up as a drag site
- * @start_button_mask: Mask of allowed buttons to start drag
- * @targets: Table of targets for this source
- * @n_targets: Number of targets in @targets
- * @actions: Actions allowed for this source
- *
- * Registers this table as a drag site, and possibly adds default behaviors.
- **/
-void
-e_table_drag_source_set (ETable *table,
- GdkModifierType start_button_mask,
- const GtkTargetEntry *targets,
- gint n_targets,
- GdkDragAction actions)
-{
- ETableDragSourceSite *site;
- GtkWidget *canvas;
-
- g_return_if_fail(table != NULL);
- g_return_if_fail(E_IS_TABLE(table));
-
- canvas = GTK_WIDGET(table->table_canvas);
- site = table->site;
-
- gtk_widget_add_events (canvas,
- gtk_widget_get_events (canvas) |
- GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
- GDK_BUTTON_MOTION_MASK | GDK_STRUCTURE_MASK);
-
- table->do_drag = TRUE;
-
- if (site) {
- if (site->target_list)
- gtk_target_list_unref (site->target_list);
- } else {
- site = g_new0 (ETableDragSourceSite, 1);
- table->site = site;
- }
-
- site->start_button_mask = start_button_mask;
-
- if (targets)
- site->target_list = gtk_target_list_new (targets, n_targets);
- else
- site->target_list = NULL;
-
- site->actions = actions;
-}
-
-/**
- * e_table_drag_source_unset:
- * @table: The #ETable to un set up as a drag site
- *
- * Unregisters this #ETable as a drag site.
- **/
-void
-e_table_drag_source_unset (ETable *table)
-{
- ETableDragSourceSite *site;
-
- g_return_if_fail (table != NULL);
- g_return_if_fail (E_IS_TABLE(table));
-
- site = table->site;
-
- if (site) {
- if (site->target_list)
- gtk_target_list_unref (site->target_list);
- g_free (site);
- table->site = NULL;
- }
- table->do_drag = FALSE;
-}
-
-/* There probably should be functions for setting the targets
- * as a GtkTargetList
- */
-
-/**
- * e_table_drag_begin:
- * @table: The #ETable to drag from
- * @row: The row number of the cell
- * @col: The col number of the cell
- * @targets: The list of targets supported by the drag
- * @actions: The available actions supported by the drag
- * @button: The button held down for the drag
- * @event: The event that initiated the drag
- *
- * Start a drag from this cell.
- *
- * Return value:
- * The drag context.
- **/
-GdkDragContext *
-e_table_drag_begin (ETable *table,
- int row,
- int col,
- GtkTargetList *targets,
- GdkDragAction actions,
- gint button,
- GdkEvent *event)
-{
- g_return_val_if_fail (table != NULL, NULL);
- g_return_val_if_fail (E_IS_TABLE(table), NULL);
-
- table->drag_row = row;
- table->drag_col = col;
-
- return gtk_drag_begin(GTK_WIDGET(table),
- targets,
- actions,
- button,
- event);
-}
-
-static void
-et_drag_begin (GtkWidget *widget,
- GdkDragContext *context,
- ETable *et)
-{
- g_signal_emit (G_OBJECT (et), et_signals [TABLE_DRAG_BEGIN], 0,
- et->drag_row, et->drag_col, context);
-}
-
-static void
-et_drag_end (GtkWidget *widget,
- GdkDragContext *context,
- ETable *et)
-{
- g_signal_emit (G_OBJECT (et), et_signals [TABLE_DRAG_END], 0,
- et->drag_row, et->drag_col, context);
-}
-
-static void
-et_drag_data_get(GtkWidget *widget,
- GdkDragContext *context,
- GtkSelectionData *selection_data,
- guint info,
- guint time,
- ETable *et)
-{
- g_signal_emit (G_OBJECT (et), et_signals [TABLE_DRAG_DATA_GET], 0,
- et->drag_row, et->drag_col, context, selection_data,
- info, time);
-}
-
-static void
-et_drag_data_delete(GtkWidget *widget,
- GdkDragContext *context,
- ETable *et)
-{
- g_signal_emit (G_OBJECT (et), et_signals [TABLE_DRAG_DATA_DELETE], 0,
- et->drag_row, et->drag_col, context);
-}
-
-static gboolean
-do_drag_motion(ETable *et,
- GdkDragContext *context,
- gint x,
- gint y,
- guint time)
-{
- gboolean ret_val;
- int row = -1, col = -1;
- GtkWidget *widget;
-
- widget = GTK_WIDGET (et);
-
- e_table_get_cell_at (et, x, y, &row, &col);
-
- if (row != et->drop_row && col != et->drop_row) {
- g_signal_emit (G_OBJECT (et), et_signals [TABLE_DRAG_LEAVE], 0,
- et->drop_row, et->drop_col, context, time);
- }
- et->drop_row = row;
- et->drop_col = col;
- g_signal_emit (G_OBJECT (et), et_signals [TABLE_DRAG_MOTION], 0,
- et->drop_row, et->drop_col, context, x, y, time, &ret_val);
-
- return ret_val;
-}
-
-static gboolean
-scroll_timeout (gpointer data)
-{
- ETable *et = data;
- int dx = 0, dy = 0;
- GtkAdjustment *h, *v;
- double hvalue, vvalue;
-
- if (et->scroll_direction & ET_SCROLL_DOWN)
- dy += 20;
- if (et->scroll_direction & ET_SCROLL_UP)
- dy -= 20;
-
- if (et->scroll_direction & ET_SCROLL_RIGHT)
- dx += 20;
- if (et->scroll_direction & ET_SCROLL_LEFT)
- dx -= 20;
-
- h = GTK_LAYOUT(et->table_canvas)->hadjustment;
- v = GTK_LAYOUT(et->table_canvas)->vadjustment;
-
- hvalue = h->value;
- vvalue = v->value;
-
- gtk_adjustment_set_value(h, CLAMP(h->value + dx, h->lower, h->upper - h->page_size));
- gtk_adjustment_set_value(v, CLAMP(v->value + dy, v->lower, v->upper - v->page_size));
-
- if (h->value != hvalue ||
- v->value != vvalue)
- do_drag_motion(et,
- et->last_drop_context,
- et->last_drop_x,
- et->last_drop_y,
- et->last_drop_time);
-
-
- return TRUE;
-}
-
-static void
-scroll_on (ETable *et, guint scroll_direction)
-{
- if (et->scroll_idle_id == 0 || scroll_direction != et->scroll_direction) {
- if (et->scroll_idle_id != 0)
- g_source_remove (et->scroll_idle_id);
- et->scroll_direction = scroll_direction;
- et->scroll_idle_id = g_timeout_add (100, scroll_timeout, et);
- }
-}
-
-static void
-scroll_off (ETable *et)
-{
- if (et->scroll_idle_id) {
- g_source_remove (et->scroll_idle_id);
- et->scroll_idle_id = 0;
- }
-}
-
-static void
-context_destroyed (gpointer data)
-{
- ETable *et = data;
- /* if (!GTK_OBJECT_DESTROYED (et)) */
-#ifndef NO_WARNINGS
-#warning FIXME
-#endif
- {
- et->last_drop_x = 0;
- et->last_drop_y = 0;
- et->last_drop_time = 0;
- et->last_drop_context = NULL;
- scroll_off (et);
- }
- g_object_unref (et);
-}
-
-static void
-context_connect (ETable *et, GdkDragContext *context)
-{
- if (g_dataset_get_data (context, "e-table") == NULL) {
- g_object_ref (et);
- g_dataset_set_data_full (context, "e-table", et, context_destroyed);
- }
-}
-
-static void
-et_drag_leave(GtkWidget *widget,
- GdkDragContext *context,
- guint time,
- ETable *et)
-{
- g_signal_emit (G_OBJECT (et), et_signals [TABLE_DRAG_LEAVE], 0,
- et->drop_row, et->drop_col, context, time);
- et->drop_row = -1;
- et->drop_col = -1;
-
- scroll_off (et);
-}
-
-static gboolean
-et_drag_motion(GtkWidget *widget,
- GdkDragContext *context,
- gint x,
- gint y,
- guint time,
- ETable *et)
-{
- gboolean ret_val;
- guint direction = 0;
-
- et->last_drop_x = x;
- et->last_drop_y = y;
- et->last_drop_time = time;
- et->last_drop_context = context;
- context_connect (et, context);
-
- ret_val = do_drag_motion (et,
- context,
- x,
- y,
- time);
-
-
- if (y < 20)
- direction |= ET_SCROLL_UP;
- if (y > widget->allocation.height - 20)
- direction |= ET_SCROLL_DOWN;
- if (x < 20)
- direction |= ET_SCROLL_LEFT;
- if (x > widget->allocation.width - 20)
- direction |= ET_SCROLL_RIGHT;
-
- if (direction != 0)
- scroll_on (et, direction);
- else
- scroll_off (et);
-
- return ret_val;
-}
-
-static gboolean
-et_drag_drop(GtkWidget *widget,
- GdkDragContext *context,
- gint x,
- gint y,
- guint time,
- ETable *et)
-{
- gboolean ret_val;
- int row, col;
-
- e_table_get_cell_at (et, x, y, &row, &col);
-
- if (row != et->drop_row && col != et->drop_row) {
- g_signal_emit (G_OBJECT (et), et_signals [TABLE_DRAG_LEAVE], 0,
- et->drop_row, et->drop_col, context, time);
- g_signal_emit (G_OBJECT (et), et_signals [TABLE_DRAG_MOTION], 0,
- row, col, context, x, y, time, &ret_val);
- }
- et->drop_row = row;
- et->drop_col = col;
- g_signal_emit (G_OBJECT (et), et_signals [TABLE_DRAG_DROP], 0,
- et->drop_row, et->drop_col, context, x, y, time, &ret_val);
- et->drop_row = -1;
- et->drop_col = -1;
-
- scroll_off (et);
-
- return ret_val;
-}
-
-static void
-et_drag_data_received(GtkWidget *widget,
- GdkDragContext *context,
- gint x,
- gint y,
- GtkSelectionData *selection_data,
- guint info,
- guint time,
- ETable *et)
-{
- int row, col;
-
- e_table_get_cell_at (et, x, y, &row, &col);
-
- g_signal_emit (G_OBJECT (et), et_signals [TABLE_DRAG_DATA_RECEIVED], 0,
- row, col, context, x, y, selection_data, info, time);
-}
-
-static void
-e_table_class_init (ETableClass *class)
-{
- GObjectClass *object_class;
- GtkWidgetClass *widget_class;
- GtkContainerClass *container_class;
-
- object_class = (GObjectClass *) class;
- widget_class = (GtkWidgetClass *) class;
- container_class = (GtkContainerClass *) class;
-
- parent_class = g_type_class_peek_parent (class);
-
- object_class->dispose = et_dispose;
- object_class->finalize = et_finalize;
- object_class->set_property = et_set_property;
- object_class->get_property = et_get_property;
-
- widget_class->grab_focus = et_grab_focus;
- widget_class->unrealize = et_unrealize;
- widget_class->size_request = et_size_request;
-
- widget_class->focus = et_focus;
-
- class->cursor_change = NULL;
- class->cursor_activated = NULL;
- class->selection_change = NULL;
- class->double_click = NULL;
- class->right_click = NULL;
- class->click = NULL;
- class->key_press = NULL;
- class->start_drag = et_real_start_drag;
- class->state_change = NULL;
- class->white_space_event = NULL;
-
- class->table_drag_begin = NULL;
- class->table_drag_end = NULL;
- class->table_drag_data_get = NULL;
- class->table_drag_data_delete = NULL;
-
- class->table_drag_leave = NULL;
- class->table_drag_motion = NULL;
- class->table_drag_drop = NULL;
- class->table_drag_data_received = NULL;
-
- et_signals [CURSOR_CHANGE] =
- g_signal_new ("cursor_change",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableClass, cursor_change),
- NULL, NULL,
- e_marshal_NONE__INT,
- G_TYPE_NONE, 1, G_TYPE_INT);
-
- et_signals [CURSOR_ACTIVATED] =
- g_signal_new ("cursor_activated",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableClass, cursor_activated),
- NULL, NULL,
- e_marshal_NONE__INT,
- G_TYPE_NONE, 1, G_TYPE_INT);
-
- et_signals [SELECTION_CHANGE] =
- g_signal_new ("selection_change",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableClass, selection_change),
- NULL, NULL,
- e_marshal_NONE__NONE,
- G_TYPE_NONE, 0);
-
- et_signals [DOUBLE_CLICK] =
- g_signal_new ("double_click",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableClass, double_click),
- NULL, NULL,
- e_marshal_NONE__INT_INT_BOXED,
- G_TYPE_NONE, 3, G_TYPE_INT,
- G_TYPE_INT, GDK_TYPE_EVENT);
-
- et_signals [RIGHT_CLICK] =
- g_signal_new ("right_click",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableClass, right_click),
- NULL, NULL,
- e_marshal_INT__INT_INT_BOXED,
- G_TYPE_INT, 3, G_TYPE_INT,
- G_TYPE_INT, GDK_TYPE_EVENT);
-
- et_signals [CLICK] =
- g_signal_new ("click",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableClass, click),
- NULL, NULL,
- e_marshal_INT__INT_INT_BOXED,
- G_TYPE_INT, 3, G_TYPE_INT,
- G_TYPE_INT, GDK_TYPE_EVENT);
-
- et_signals [KEY_PRESS] =
- g_signal_new ("key_press",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableClass, key_press),
- NULL, NULL,
- e_marshal_INT__INT_INT_BOXED,
- G_TYPE_INT, 3, G_TYPE_INT,
- G_TYPE_INT, GDK_TYPE_EVENT);
-
- et_signals [START_DRAG] =
- g_signal_new ("start_drag",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableClass, start_drag),
- NULL, NULL,
- e_marshal_INT__INT_INT_BOXED,
- G_TYPE_INT, 3, G_TYPE_INT,
- G_TYPE_INT, GDK_TYPE_EVENT);
-
- et_signals [STATE_CHANGE] =
- g_signal_new ("state_change",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableClass, state_change),
- NULL, NULL,
- e_marshal_NONE__NONE,
- G_TYPE_NONE, 0);
-
- et_signals [WHITE_SPACE_EVENT] =
- g_signal_new ("white_space_event",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableClass, white_space_event),
- NULL, NULL,
- e_marshal_INT__BOXED,
- G_TYPE_INT, 1, GDK_TYPE_EVENT);
-
- et_signals[TABLE_DRAG_BEGIN] =
- g_signal_new ("table_drag_begin",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableClass, table_drag_begin),
- NULL, NULL,
- e_marshal_NONE__INT_INT_OBJECT,
- G_TYPE_NONE, 3,
- G_TYPE_INT,
- G_TYPE_INT,
- GDK_TYPE_DRAG_CONTEXT);
- et_signals[TABLE_DRAG_END] =
- g_signal_new ("table_drag_end",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableClass, table_drag_end),
- NULL, NULL,
- e_marshal_NONE__INT_INT_OBJECT,
- G_TYPE_NONE, 3,
- G_TYPE_INT,
- G_TYPE_INT,
- GDK_TYPE_DRAG_CONTEXT);
- et_signals[TABLE_DRAG_DATA_GET] =
- g_signal_new ("table_drag_data_get",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableClass, table_drag_data_get),
- NULL, NULL,
- e_marshal_NONE__INT_INT_OBJECT_BOXED_UINT_UINT,
- G_TYPE_NONE, 6,
- G_TYPE_INT,
- G_TYPE_INT,
- GDK_TYPE_DRAG_CONTEXT,
- GTK_TYPE_SELECTION_DATA | G_SIGNAL_TYPE_STATIC_SCOPE,
- G_TYPE_UINT,
- G_TYPE_UINT);
- et_signals[TABLE_DRAG_DATA_DELETE] =
- g_signal_new ("table_drag_data_delete",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableClass, table_drag_data_delete),
- NULL, NULL,
- e_marshal_NONE__INT_INT_OBJECT,
- G_TYPE_NONE, 3,
- G_TYPE_INT,
- G_TYPE_INT,
- GDK_TYPE_DRAG_CONTEXT);
-
- et_signals[TABLE_DRAG_LEAVE] =
- g_signal_new ("table_drag_leave",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableClass, table_drag_leave),
- NULL, NULL,
- e_marshal_NONE__INT_INT_OBJECT_UINT,
- G_TYPE_NONE, 4,
- G_TYPE_INT,
- G_TYPE_INT,
- GDK_TYPE_DRAG_CONTEXT,
- G_TYPE_UINT);
- et_signals[TABLE_DRAG_MOTION] =
- g_signal_new ("table_drag_motion",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableClass, table_drag_motion),
- NULL, NULL,
- e_marshal_BOOLEAN__INT_INT_OBJECT_INT_INT_UINT,
- G_TYPE_BOOLEAN, 6,
- G_TYPE_INT,
- G_TYPE_INT,
- GDK_TYPE_DRAG_CONTEXT,
- G_TYPE_INT,
- G_TYPE_INT,
- G_TYPE_UINT);
- et_signals[TABLE_DRAG_DROP] =
- g_signal_new ("table_drag_drop",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableClass, table_drag_drop),
- NULL, NULL,
- e_marshal_BOOLEAN__INT_INT_OBJECT_INT_INT_UINT,
- G_TYPE_BOOLEAN, 6,
- G_TYPE_INT,
- G_TYPE_INT,
- GDK_TYPE_DRAG_CONTEXT,
- G_TYPE_INT,
- G_TYPE_INT,
- G_TYPE_UINT);
- et_signals[TABLE_DRAG_DATA_RECEIVED] =
- g_signal_new ("table_drag_data_received",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableClass, table_drag_data_received),
- NULL, NULL,
- e_marshal_NONE__INT_INT_OBJECT_INT_INT_BOXED_UINT_UINT,
- G_TYPE_NONE, 8,
- G_TYPE_INT,
- G_TYPE_INT,
- GDK_TYPE_DRAG_CONTEXT,
- G_TYPE_INT,
- G_TYPE_INT,
- GTK_TYPE_SELECTION_DATA | G_SIGNAL_TYPE_STATIC_SCOPE,
- G_TYPE_UINT,
- G_TYPE_UINT);
-
- class->set_scroll_adjustments = set_scroll_adjustments;
-
- widget_class->set_scroll_adjustments_signal =
- g_signal_new ("set_scroll_adjustments",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETableClass, set_scroll_adjustments),
- NULL, NULL,
- e_marshal_NONE__OBJECT_OBJECT,
- G_TYPE_NONE, 2, GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
-
- g_object_class_install_property (object_class, PROP_LENGTH_THRESHOLD,
- g_param_spec_int ("length_threshold",
- _("Length Threshold"),
- /*_( */"XXX blurb" /*)*/,
- 0, G_MAXINT, 0,
- G_PARAM_WRITABLE));
-
- g_object_class_install_property (object_class, PROP_UNIFORM_ROW_HEIGHT,
- g_param_spec_boolean ("uniform_row_height",
- _("Uniform row height"),
- /*_( */"XXX blurb" /*)*/,
- FALSE,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class, PROP_ALWAYS_SEARCH,
- g_param_spec_boolean ("always_search",
- _("Always Search"),
- /*_( */"XXX blurb" /*)*/,
- FALSE,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class, PROP_USE_CLICK_TO_ADD,
- g_param_spec_boolean ("use_click_to_add",
- _("Use click to add"),
- /*_( */"XXX blurb" /*)*/,
- FALSE,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class, PROP_MODEL,
- g_param_spec_object ("model",
- _("Model"),
- /*_( */"XXX blurb" /*)*/,
- E_TABLE_MODEL_TYPE,
- G_PARAM_READABLE));
-
- gal_a11y_e_table_init ();
-}
-
-E_MAKE_TYPE(e_table, "ETable", ETable, e_table_class_init, e_table_init, PARENT_TYPE)
diff --git a/widgets/table/e-table.dia b/widgets/table/e-table.dia
deleted file mode 100644
index 5aeb01228c..0000000000
--- a/widgets/table/e-table.dia
+++ /dev/null
Binary files differ
diff --git a/widgets/table/e-table.h b/widgets/table/e-table.h
deleted file mode 100644
index f025318905..0000000000
--- a/widgets/table/e-table.h
+++ /dev/null
@@ -1,358 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-table.h - A graphical view of a Table.
- * Copyright 1999, 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- * Miguel de Icaza <miguel@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_TABLE_H_
-#define _E_TABLE_H_
-
-#include <libgnomecanvas/gnome-canvas.h>
-#include <gtk/gtkdnd.h>
-#include <gtk/gtktable.h>
-#include <libxml/tree.h>
-#include <gal/e-table/e-table-model.h>
-#include <gal/e-table/e-table-header.h>
-#include <gal/e-table/e-table-group.h>
-#include <gal/e-table/e-table-sort-info.h>
-#include <gal/e-table/e-table-item.h>
-#include <gal/e-table/e-table-selection-model.h>
-#include <gal/e-table/e-table-extras.h>
-#include <gal/e-table/e-table-specification.h>
-#include <gal/widgets/e-printable.h>
-#include <gal/e-table/e-table-state.h>
-#include <gal/e-table/e-table-sorter.h>
-#include <gal/e-table/e-table-search.h>
-
-G_BEGIN_DECLS
-
-#define E_TABLE_TYPE (e_table_get_type ())
-#define E_TABLE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TABLE_TYPE, ETable))
-#define E_TABLE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TABLE_TYPE, ETableClass))
-#define E_IS_TABLE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TABLE_TYPE))
-#define E_IS_TABLE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TABLE_TYPE))
-
-typedef struct _ETableDragSourceSite ETableDragSourceSite;
-
-typedef enum {
- E_TABLE_CURSOR_LOC_NONE = 0,
- E_TABLE_CURSOR_LOC_ETCTA = 1 << 0,
- E_TABLE_CURSOR_LOC_TABLE = 1 << 1
-} ETableCursorLoc;
-
-typedef struct {
- GtkTable parent;
-
- ETableModel *model;
-
- ETableHeader *full_header, *header;
-
- GnomeCanvasItem *canvas_vbox;
- ETableGroup *group;
-
- ETableSortInfo *sort_info;
- ETableSorter *sorter;
-
- ETableSelectionModel *selection;
- ETableCursorLoc cursor_loc;
- ETableSpecification *spec;
-
- ETableSearch *search;
-
- ETableCol *current_search_col;
-
- guint search_search_id;
- guint search_accept_id;
-
- int table_model_change_id;
- int table_row_change_id;
- int table_cell_change_id;
- int table_rows_inserted_id;
- int table_rows_deleted_id;
-
- int group_info_change_id;
- int sort_info_change_id;
-
- int structure_change_id;
- int expansion_change_id;
- int dimension_change_id;
-
- int reflow_idle_id;
- int scroll_idle_id;
-
- GnomeCanvas *header_canvas, *table_canvas;
-
- GnomeCanvasItem *header_item, *root;
-
- GnomeCanvasItem *white_item;
-
- gint length_threshold;
-
- gint rebuild_idle_id;
- guint need_rebuild:1;
-
- /*
- * Configuration settings
- */
- guint alternating_row_colors : 1;
- guint horizontal_draw_grid : 1;
- guint vertical_draw_grid : 1;
- guint draw_focus : 1;
- guint row_selection_active : 1;
-
- guint horizontal_scrolling : 1;
- guint horizontal_resize : 1;
-
- guint is_grouped : 1;
-
- guint scroll_direction : 4;
-
- guint do_drag : 1;
-
- guint uniform_row_height : 1;
- guint allow_grouping : 1;
-
- guint always_search : 1;
- guint search_col_set : 1;
-
- char *click_to_add_message;
- GnomeCanvasItem *click_to_add;
- gboolean use_click_to_add;
- gboolean use_click_to_add_end;
-
- ECursorMode cursor_mode;
-
- int drop_row;
- int drop_col;
- GnomeCanvasItem *drop_highlight;
- int last_drop_x;
- int last_drop_y;
- int last_drop_time;
- GdkDragContext *last_drop_context;
-
- int drag_row;
- int drag_col;
- ETableDragSourceSite *site;
-
- int header_width;
-
- char *domain;
-} ETable;
-
-typedef struct {
- GtkTableClass parent_class;
-
- void (*cursor_change) (ETable *et, int row);
- void (*cursor_activated) (ETable *et, int row);
- void (*selection_change) (ETable *et);
- void (*double_click) (ETable *et, int row, int col, GdkEvent *event);
- gint (*right_click) (ETable *et, int row, int col, GdkEvent *event);
- gint (*click) (ETable *et, int row, int col, GdkEvent *event);
- gint (*key_press) (ETable *et, int row, int col, GdkEvent *event);
- gint (*start_drag) (ETable *et, int row, int col, GdkEvent *event);
- void (*state_change) (ETable *et);
- gint (*white_space_event) (ETable *et, GdkEvent *event);
-
- void (*set_scroll_adjustments) (ETable *table,
- GtkAdjustment *hadjustment,
- GtkAdjustment *vadjustment);
-
- /* Source side drag signals */
- void (* table_drag_begin) (ETable *table,
- int row,
- int col,
- GdkDragContext *context);
- void (* table_drag_end) (ETable *table,
- int row,
- int col,
- GdkDragContext *context);
- void (* table_drag_data_get) (ETable *table,
- int row,
- int col,
- GdkDragContext *context,
- GtkSelectionData *selection_data,
- guint info,
- guint time);
- void (* table_drag_data_delete) (ETable *table,
- int row,
- int col,
- GdkDragContext *context);
-
- /* Target side drag signals */
- void (* table_drag_leave) (ETable *table,
- int row,
- int col,
- GdkDragContext *context,
- guint time);
- gboolean (* table_drag_motion) (ETable *table,
- int row,
- int col,
- GdkDragContext *context,
- gint x,
- gint y,
- guint time);
- gboolean (* table_drag_drop) (ETable *table,
- int row,
- int col,
- GdkDragContext *context,
- gint x,
- gint y,
- guint time);
- void (* table_drag_data_received) (ETable *table,
- int row,
- int col,
- GdkDragContext *context,
- gint x,
- gint y,
- GtkSelectionData *selection_data,
- guint info,
- guint time);
-} ETableClass;
-GType e_table_get_type (void);
-ETable *e_table_construct (ETable *e_table,
- ETableModel *etm,
- ETableExtras *ete,
- const char *spec,
- const char *state);
-GtkWidget *e_table_new (ETableModel *etm,
- ETableExtras *ete,
- const char *spec,
- const char *state);
-
-/* Create an ETable using files. */
-ETable *e_table_construct_from_spec_file (ETable *e_table,
- ETableModel *etm,
- ETableExtras *ete,
- const char *spec_fn,
- const char *state_fn);
-GtkWidget *e_table_new_from_spec_file (ETableModel *etm,
- ETableExtras *ete,
- const char *spec_fn,
- const char *state_fn);
-
-/* To save the state */
-gchar *e_table_get_state (ETable *e_table);
-void e_table_save_state (ETable *e_table,
- const gchar *filename);
-ETableState *e_table_get_state_object (ETable *e_table);
-
-/* note that it is more efficient to provide the state at creation time */
-void e_table_set_state (ETable *e_table,
- const gchar *state);
-void e_table_set_state_object (ETable *e_table,
- ETableState *state);
-void e_table_load_state (ETable *e_table,
- const gchar *filename);
-void e_table_set_cursor_row (ETable *e_table,
- int row);
-
-/* -1 means we don't have the cursor. This is in model rows. */
-int e_table_get_cursor_row (ETable *e_table);
-void e_table_selected_row_foreach (ETable *e_table,
- EForeachFunc callback,
- gpointer closure);
-gint e_table_selected_count (ETable *e_table);
-EPrintable *e_table_get_printable (ETable *e_table);
-gint e_table_get_next_row (ETable *e_table,
- gint model_row);
-gint e_table_get_prev_row (ETable *e_table,
- gint model_row);
-gint e_table_model_to_view_row (ETable *e_table,
- gint model_row);
-gint e_table_view_to_model_row (ETable *e_table,
- gint view_row);
-void e_table_get_cell_at (ETable *table,
- int x,
- int y,
- int *row_return,
- int *col_return);
-void e_table_get_cell_geometry (ETable *table,
- int row,
- int col,
- int *x_return,
- int *y_return,
- int *width_return,
- int *height_return);
-
-/* Useful accessor functions. */
-ESelectionModel *e_table_get_selection_model (ETable *table);
-
-/* Drag & drop stuff. */
-/* Target */
-void e_table_drag_get_data (ETable *table,
- int row,
- int col,
- GdkDragContext *context,
- GdkAtom target,
- guint32 time);
-void e_table_drag_highlight (ETable *table,
- int row,
- int col); /* col == -1 to highlight entire row. */
-void e_table_drag_unhighlight (ETable *table);
-void e_table_drag_dest_set (ETable *table,
- GtkDestDefaults flags,
- const GtkTargetEntry *targets,
- gint n_targets,
- GdkDragAction actions);
-void e_table_drag_dest_set_proxy (ETable *table,
- GdkWindow *proxy_window,
- GdkDragProtocol protocol,
- gboolean use_coordinates);
-
-/* There probably should be functions for setting the targets
- * as a GtkTargetList
- */
-void e_table_drag_dest_unset (GtkWidget *widget);
-
-/* Source side */
-void e_table_drag_source_set (ETable *table,
- GdkModifierType start_button_mask,
- const GtkTargetEntry *targets,
- gint n_targets,
- GdkDragAction actions);
-void e_table_drag_source_unset (ETable *table);
-
-/* There probably should be functions for setting the targets
- * as a GtkTargetList
- */
-GdkDragContext *e_table_drag_begin (ETable *table,
- int row,
- int col,
- GtkTargetList *targets,
- GdkDragAction actions,
- gint button,
- GdkEvent *event);
-
-/* selection stuff */
-void e_table_select_all (ETable *table);
-void e_table_invert_selection (ETable *table);
-
-/* This function is only needed in single_selection_mode. */
-void e_table_right_click_up (ETable *table);
-
-void e_table_commit_click_to_add (ETable *table);
-
-void e_table_commit_click_to_add (ETable *table);
-
-G_END_DECLS
-
-#endif /* _E_TABLE_H_ */
-
diff --git a/widgets/table/e-tree-memory-callbacks.c b/widgets/table/e-tree-memory-callbacks.c
deleted file mode 100644
index b6fe3fc375..0000000000
--- a/widgets/table/e-tree-memory-callbacks.c
+++ /dev/null
@@ -1,275 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-tree-memory-callbacks.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <gtk/gtksignal.h>
-#include "gal/util/e-util.h"
-#include "e-tree-memory-callbacks.h"
-
-#define PARENT_TYPE E_TREE_MEMORY_TYPE
-
-static GdkPixbuf *
-etmc_icon_at (ETreeModel *etm, ETreePath node)
-{
- ETreeMemoryCallbacks *etmc = E_TREE_MEMORY_CALLBACKS(etm);
-
- return etmc->icon_at (etm, node, etmc->model_data);
-}
-
-static int
-etmc_column_count (ETreeModel *etm)
-{
- ETreeMemoryCallbacks *etmc = E_TREE_MEMORY_CALLBACKS(etm);
-
- if (etmc->column_count)
- return etmc->column_count (etm, etmc->model_data);
- else
- return 0;
-}
-
-
-static gboolean
-etmc_has_save_id (ETreeModel *etm)
-{
- ETreeMemoryCallbacks *etmc = E_TREE_MEMORY_CALLBACKS(etm);
-
- if (etmc->has_save_id)
- return etmc->has_save_id (etm, etmc->model_data);
- else
- return FALSE;
-}
-
-static char *
-etmc_get_save_id (ETreeModel *etm, ETreePath node)
-{
- ETreeMemoryCallbacks *etmc = E_TREE_MEMORY_CALLBACKS(etm);
-
- if (etmc->get_save_id)
- return etmc->get_save_id (etm, node, etmc->model_data);
- else
- return NULL;
-}
-
-static gboolean
-etmc_has_get_node_by_id (ETreeModel *etm)
-{
- ETreeMemoryCallbacks *etmc = E_TREE_MEMORY_CALLBACKS(etm);
-
- if (etmc->has_get_node_by_id)
- return etmc->has_get_node_by_id (etm, etmc->model_data);
- else
- return FALSE;
-}
-
-static ETreePath
-etmc_get_node_by_id (ETreeModel *etm, const char *save_id)
-{
- ETreeMemoryCallbacks *etmc = E_TREE_MEMORY_CALLBACKS(etm);
-
- if (etmc->get_node_by_id)
- return etmc->get_node_by_id (etm, save_id, etmc->model_data);
- else
- return NULL;
-}
-
-
-static void *
-etmc_value_at (ETreeModel *etm, ETreePath node, int col)
-{
- ETreeMemoryCallbacks *etmc = E_TREE_MEMORY_CALLBACKS(etm);
-
- return etmc->value_at (etm, node, col, etmc->model_data);
-}
-
-static void
-etmc_set_value_at (ETreeModel *etm, ETreePath node, int col, const void *val)
-{
- ETreeMemoryCallbacks *etmc = E_TREE_MEMORY_CALLBACKS(etm);
-
- etmc->set_value_at (etm, node, col, val, etmc->model_data);
-}
-
-static gboolean
-etmc_is_editable (ETreeModel *etm, ETreePath node, int col)
-{
- ETreeMemoryCallbacks *etmc = E_TREE_MEMORY_CALLBACKS(etm);
-
- return etmc->is_editable (etm, node, col, etmc->model_data);
-}
-
-
-/* The default for etmc_duplicate_value is to return the raw value. */
-static void *
-etmc_duplicate_value (ETreeModel *etm, int col, const void *value)
-{
- ETreeMemoryCallbacks *etmc = E_TREE_MEMORY_CALLBACKS(etm);
-
- if (etmc->duplicate_value)
- return etmc->duplicate_value (etm, col, value, etmc->model_data);
- else
- return (void *)value;
-}
-
-static void
-etmc_free_value (ETreeModel *etm, int col, void *value)
-{
- ETreeMemoryCallbacks *etmc = E_TREE_MEMORY_CALLBACKS(etm);
-
- if (etmc->free_value)
- etmc->free_value (etm, col, value, etmc->model_data);
-}
-
-static void *
-etmc_initialize_value (ETreeModel *etm, int col)
-{
- ETreeMemoryCallbacks *etmc = E_TREE_MEMORY_CALLBACKS(etm);
-
- if (etmc->initialize_value)
- return etmc->initialize_value (etm, col, etmc->model_data);
- else
- return NULL;
-}
-
-static gboolean
-etmc_value_is_empty (ETreeModel *etm, int col, const void *value)
-{
- ETreeMemoryCallbacks *etmc = E_TREE_MEMORY_CALLBACKS(etm);
-
- if (etmc->value_is_empty)
- return etmc->value_is_empty (etm, col, value, etmc->model_data);
- else
- return FALSE;
-}
-
-static char *
-etmc_value_to_string (ETreeModel *etm, int col, const void *value)
-{
- ETreeMemoryCallbacks *etmc = E_TREE_MEMORY_CALLBACKS(etm);
-
- if (etmc->value_to_string)
- return etmc->value_to_string (etm, col, value, etmc->model_data);
- else
- return g_strdup ("");
-}
-
-static void
-e_tree_memory_callbacks_class_init (GtkObjectClass *object_class)
-{
- ETreeModelClass *model_class = (ETreeModelClass *) object_class;
-
- model_class->icon_at = etmc_icon_at;
-
- model_class->column_count = etmc_column_count;
-
- model_class->has_save_id = etmc_has_save_id;
- model_class->get_save_id = etmc_get_save_id;
-
- model_class->has_get_node_by_id = etmc_has_get_node_by_id;
- model_class->get_node_by_id = etmc_get_node_by_id;
-
- model_class->value_at = etmc_value_at;
- model_class->set_value_at = etmc_set_value_at;
- model_class->is_editable = etmc_is_editable;
-
- model_class->duplicate_value = etmc_duplicate_value;
- model_class->free_value = etmc_free_value;
- model_class->initialize_value = etmc_initialize_value;
- model_class->value_is_empty = etmc_value_is_empty;
- model_class->value_to_string = etmc_value_to_string;
-}
-
-E_MAKE_TYPE(e_tree_memory_callbacks, "ETreeMemoryCallbacks", ETreeMemoryCallbacks, e_tree_memory_callbacks_class_init, NULL, PARENT_TYPE)
-
-/**
- * e_tree_memory_callbacks_new:
- *
- * This initializes a new ETreeMemoryCallbacksModel object.
- * ETreeMemoryCallbacksModel is an implementaiton of the somewhat
- * abstract class ETreeMemory. The ETreeMemoryCallbacksModel is
- * designed to allow people to easily create ETreeMemorys without
- * having to create a new GtkType derived from ETreeMemory every time
- * they need one.
- *
- * Instead, ETreeMemoryCallbacksModel uses a setup based in callback functions, every
- * callback function signature mimics the signature of each ETreeModel method
- * and passes the extra @data pointer to each one of the method to provide them
- * with any context they might want to use.
- *
- * ETreeMemoryCallbacks is to ETreeMemory as ETableSimple is to ETableModel.
- *
- * Return value: An ETreeMemoryCallbacks object (which is also an
- * ETreeMemory and thus an ETreeModel object).
- *
- */
-ETreeModel *
-e_tree_memory_callbacks_new (ETreeMemoryCallbacksIconAtFn icon_at,
-
- ETreeMemoryCallbacksColumnCountFn column_count,
-
- ETreeMemoryCallbacksHasSaveIdFn has_save_id,
- ETreeMemoryCallbacksGetSaveIdFn get_save_id,
-
- ETreeMemoryCallbacksHasGetNodeByIdFn has_get_node_by_id,
- ETreeMemoryCallbacksGetNodeByIdFn get_node_by_id,
-
- ETreeMemoryCallbacksValueAtFn value_at,
- ETreeMemoryCallbacksSetValueAtFn set_value_at,
- ETreeMemoryCallbacksIsEditableFn is_editable,
-
- ETreeMemoryCallbacksDuplicateValueFn duplicate_value,
- ETreeMemoryCallbacksFreeValueFn free_value,
- ETreeMemoryCallbacksInitializeValueFn initialize_value,
- ETreeMemoryCallbacksValueIsEmptyFn value_is_empty,
- ETreeMemoryCallbacksValueToStringFn value_to_string,
-
- gpointer model_data)
-{
- ETreeMemoryCallbacks *etmc;
-
- etmc = g_object_new (E_TREE_MEMORY_CALLBACKS_TYPE, NULL);
-
- etmc->icon_at = icon_at;
-
- etmc->column_count = column_count;
-
- etmc->has_save_id = has_save_id;
- etmc->get_save_id = get_save_id;
-
- etmc->has_get_node_by_id = has_get_node_by_id;
- etmc->get_node_by_id = get_node_by_id;
-
- etmc->value_at = value_at;
- etmc->set_value_at = set_value_at;
- etmc->is_editable = is_editable;
-
- etmc->duplicate_value = duplicate_value;
- etmc->free_value = free_value;
- etmc->initialize_value = initialize_value;
- etmc->value_is_empty = value_is_empty;
- etmc->value_to_string = value_to_string;
-
- etmc->model_data = model_data;
-
- return (ETreeModel*)etmc;
-}
-
diff --git a/widgets/table/e-tree-memory-callbacks.h b/widgets/table/e-tree-memory-callbacks.h
deleted file mode 100644
index 0f75fa98be..0000000000
--- a/widgets/table/e-tree-memory-callbacks.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-tree-memory-callbacks.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-
-#ifndef _E_TREE_MEMORY_CALLBACKS_H_
-#define _E_TREE_MEMORY_CALLBACKS_H_
-
-#include <gal/e-table/e-tree-memory.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-#define E_TREE_MEMORY_CALLBACKS_TYPE (e_tree_memory_callbacks_get_type ())
-#define E_TREE_MEMORY_CALLBACKS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TREE_MEMORY_CALLBACKS_TYPE, ETreeMemoryCallbacks))
-#define E_TREE_MEMORY_CALLBACKS_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TREE_MEMORY_CALLBACKS_TYPE, ETreeMemoryCallbacksClass))
-#define E_IS_TREE_MEMORY_CALLBACKS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TREE_MEMORY_CALLBACKS_TYPE))
-#define E_IS_TREE_MEMORY_CALLBACKS_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TREE_MEMORY_CALLBACKS_TYPE))
-
-
-typedef GdkPixbuf* (*ETreeMemoryCallbacksIconAtFn) (ETreeModel *etree, ETreePath path, void *model_data);
-
-typedef gint (*ETreeMemoryCallbacksColumnCountFn) (ETreeModel *etree, void *model_data);
-
-typedef gboolean (*ETreeMemoryCallbacksHasSaveIdFn) (ETreeModel *etree, void *model_data);
-typedef gchar *(*ETreeMemoryCallbacksGetSaveIdFn) (ETreeModel *etree, ETreePath path, void *model_data);
-
-typedef gboolean (*ETreeMemoryCallbacksHasGetNodeByIdFn) (ETreeModel *etree, void *model_data);
-typedef ETreePath (*ETreeMemoryCallbacksGetNodeByIdFn) (ETreeModel *etree, const char *save_id, void *model_data);
-
-typedef void* (*ETreeMemoryCallbacksValueAtFn) (ETreeModel *etree, ETreePath path, int col, void *model_data);
-typedef void (*ETreeMemoryCallbacksSetValueAtFn) (ETreeModel *etree, ETreePath path, int col, const void *val, void *model_data);
-typedef gboolean (*ETreeMemoryCallbacksIsEditableFn) (ETreeModel *etree, ETreePath path, int col, void *model_data);
-
-typedef void *(*ETreeMemoryCallbacksDuplicateValueFn) (ETreeModel *etm, int col, const void *val, void *data);
-typedef void (*ETreeMemoryCallbacksFreeValueFn) (ETreeModel *etm, int col, void *val, void *data);
-typedef void *(*ETreeMemoryCallbacksInitializeValueFn) (ETreeModel *etm, int col, void *data);
-typedef gboolean (*ETreeMemoryCallbacksValueIsEmptyFn) (ETreeModel *etm, int col, const void *val, void *data);
-typedef char *(*ETreeMemoryCallbacksValueToStringFn) (ETreeModel *etm, int col, const void *val, void *data);
-
-typedef struct {
- ETreeMemory parent;
-
- ETreeMemoryCallbacksIconAtFn icon_at;
-
- ETreeMemoryCallbacksColumnCountFn column_count;
-
- ETreeMemoryCallbacksHasSaveIdFn has_save_id;
- ETreeMemoryCallbacksGetSaveIdFn get_save_id;
-
- ETreeMemoryCallbacksHasGetNodeByIdFn has_get_node_by_id;
- ETreeMemoryCallbacksGetNodeByIdFn get_node_by_id;
-
- ETreeMemoryCallbacksValueAtFn value_at;
- ETreeMemoryCallbacksSetValueAtFn set_value_at;
- ETreeMemoryCallbacksIsEditableFn is_editable;
-
- ETreeMemoryCallbacksDuplicateValueFn duplicate_value;
- ETreeMemoryCallbacksFreeValueFn free_value;
- ETreeMemoryCallbacksInitializeValueFn initialize_value;
- ETreeMemoryCallbacksValueIsEmptyFn value_is_empty;
- ETreeMemoryCallbacksValueToStringFn value_to_string;
-
- gpointer model_data;
-} ETreeMemoryCallbacks;
-
-typedef struct {
- ETreeMemoryClass parent_class;
-} ETreeMemoryCallbacksClass;
-
-GType e_tree_memory_callbacks_get_type (void);
-
-ETreeModel *e_tree_memory_callbacks_new (ETreeMemoryCallbacksIconAtFn icon_at,
-
- ETreeMemoryCallbacksColumnCountFn column_count,
-
- ETreeMemoryCallbacksHasSaveIdFn has_save_id,
- ETreeMemoryCallbacksGetSaveIdFn get_save_id,
-
- ETreeMemoryCallbacksHasGetNodeByIdFn has_get_node_by_id,
- ETreeMemoryCallbacksGetNodeByIdFn get_node_by_id,
-
- ETreeMemoryCallbacksValueAtFn value_at,
- ETreeMemoryCallbacksSetValueAtFn set_value_at,
- ETreeMemoryCallbacksIsEditableFn is_editable,
-
- ETreeMemoryCallbacksDuplicateValueFn duplicate_value,
- ETreeMemoryCallbacksFreeValueFn free_value,
- ETreeMemoryCallbacksInitializeValueFn initialize_value,
- ETreeMemoryCallbacksValueIsEmptyFn value_is_empty,
- ETreeMemoryCallbacksValueToStringFn value_to_string,
-
- gpointer model_data);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* _E_TREE_MEMORY_CALLBACKS_H_ */
diff --git a/widgets/table/e-tree-memory.c b/widgets/table/e-tree-memory.c
deleted file mode 100644
index 3f178455df..0000000000
--- a/widgets/table/e-tree-memory.c
+++ /dev/null
@@ -1,717 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-tree-memory.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- * Chris Toshok <toshok@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-
-#include <stdio.h>
-#include <errno.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <stdlib.h>
-
-#include <libxml/parser.h>
-#include <libxml/xmlmemory.h>
-
-#include "gal/util/e-util.h"
-#include "gal/util/e-xml-utils.h"
-#include "e-tree-memory.h"
-
-#define TREEPATH_CHUNK_AREA_SIZE (30 * sizeof (ETreeMemoryPath))
-
-static ETreeModelClass *parent_class;
-static GMemChunk *node_chunk;
-
-enum {
- FILL_IN_CHILDREN,
- LAST_SIGNAL
-};
-
-static guint signals [LAST_SIGNAL] = { 0, };
-
-typedef struct ETreeMemoryPath ETreeMemoryPath;
-
-struct ETreeMemoryPath {
- gpointer node_data;
-
- guint children_computed : 1;
-
- /* parent/child/sibling pointers */
- ETreeMemoryPath *parent;
- ETreeMemoryPath *next_sibling;
- ETreeMemoryPath *prev_sibling;
- ETreeMemoryPath *first_child;
- ETreeMemoryPath *last_child;
-
- gint num_children;
-};
-
-struct ETreeMemoryPriv {
- ETreeMemoryPath *root;
- gboolean expanded_default; /* whether nodes are created expanded or collapsed by default */
- gint frozen;
- GFunc destroy_func;
- gpointer destroy_user_data;
-};
-
-
-/* ETreeMemoryPath functions */
-
-static inline void
-check_children (ETreeMemory *memory, ETreePath node)
-{
- ETreeMemoryPath *path = node;
- if (!path->children_computed) {
- g_signal_emit (G_OBJECT (memory), signals[FILL_IN_CHILDREN], 0, node);
- path->children_computed = TRUE;
- }
-}
-
-static int
-e_tree_memory_path_depth (ETreeMemoryPath *path)
-{
- int depth = 0;
-
- g_return_val_if_fail(path != NULL, -1);
-
- for ( path = path->parent; path; path = path->parent)
- depth ++;
- return depth;
-}
-
-static void
-e_tree_memory_path_insert (ETreeMemoryPath *parent, int position, ETreeMemoryPath *child)
-{
- g_return_if_fail (position <= parent->num_children && position >= -1);
-
- child->parent = parent;
-
- if (parent->first_child == NULL)
- parent->first_child = child;
-
- if (position == -1 || position == parent->num_children) {
- child->prev_sibling = parent->last_child;
- if (parent->last_child)
- parent->last_child->next_sibling = child;
- parent->last_child = child;
- } else {
- ETreeMemoryPath *c;
- for (c = parent->first_child; c; c = c->next_sibling) {
- if (position == 0) {
- child->next_sibling = c;
- child->prev_sibling = c->prev_sibling;
-
- if (child->next_sibling)
- child->next_sibling->prev_sibling = child;
- if (child->prev_sibling)
- child->prev_sibling->next_sibling = child;
-
- if (parent->first_child == c)
- parent->first_child = child;
- break;
- }
- position --;
- }
- }
-
- parent->num_children++;
-}
-
-static void
-e_tree_path_unlink (ETreeMemoryPath *path)
-{
- ETreeMemoryPath *parent = path->parent;
-
- /* unlink first/last child if applicable */
- if (parent) {
- if (path == parent->first_child)
- parent->first_child = path->next_sibling;
- if (path == parent->last_child)
- parent->last_child = path->prev_sibling;
-
- parent->num_children --;
- }
-
- /* unlink prev/next sibling links */
- if (path->next_sibling)
- path->next_sibling->prev_sibling = path->prev_sibling;
- if (path->prev_sibling)
- path->prev_sibling->next_sibling = path->next_sibling;
-
- path->parent = NULL;
- path->next_sibling = NULL;
- path->prev_sibling = NULL;
-}
-
-
-
-/**
- * e_tree_memory_freeze:
- * @etmm: the ETreeModel to freeze.
- *
- * This function prepares an ETreeModel for a period of much change.
- * All signals regarding changes to the tree are deferred until we
- * thaw the tree.
- *
- **/
-void
-e_tree_memory_freeze(ETreeMemory *etmm)
-{
- ETreeMemoryPriv *priv = etmm->priv;
-
- if (priv->frozen == 0)
- e_tree_model_pre_change(E_TREE_MODEL(etmm));
-
- priv->frozen ++;
-}
-
-/**
- * e_tree_memory_thaw:
- * @etmm: the ETreeMemory to thaw.
- *
- * This function thaws an ETreeMemory. All the defered signals can add
- * up to a lot, we don't know - so we just emit a model_changed
- * signal.
- *
- **/
-void
-e_tree_memory_thaw(ETreeMemory *etmm)
-{
- ETreeMemoryPriv *priv = etmm->priv;
-
- if (priv->frozen > 0)
- priv->frozen --;
- if (priv->frozen == 0) {
- e_tree_model_node_changed(E_TREE_MODEL(etmm), priv->root);
- }
-}
-
-
-/* virtual methods */
-
-static void
-etmm_dispose (GObject *object)
-{
- ETreeMemory *etmm = E_TREE_MEMORY (object);
- ETreeMemoryPriv *priv = etmm->priv;
-
- if (priv) {
- /* XXX lots of stuff to free here */
-
- if (priv->root)
- e_tree_memory_node_remove (etmm, priv->root);
-
- g_free (priv);
- }
- etmm->priv = NULL;
-
- G_OBJECT_CLASS (parent_class)->dispose (object);
-}
-
-static ETreePath
-etmm_get_root (ETreeModel *etm)
-{
- ETreeMemoryPriv *priv = E_TREE_MEMORY(etm)->priv;
- return priv->root;
-}
-
-static ETreePath
-etmm_get_parent (ETreeModel *etm, ETreePath node)
-{
- ETreeMemoryPath *path = node;
- return path->parent;
-}
-
-static ETreePath
-etmm_get_first_child (ETreeModel *etm, ETreePath node)
-{
- ETreeMemoryPath *path = node;
-
- check_children (E_TREE_MEMORY (etm), node);
- return path->first_child;
-}
-
-static ETreePath
-etmm_get_last_child (ETreeModel *etm, ETreePath node)
-{
- ETreeMemoryPath *path = node;
-
- check_children (E_TREE_MEMORY (etm), node);
- return path->last_child;
-}
-
-static ETreePath
-etmm_get_next (ETreeModel *etm, ETreePath node)
-{
- ETreeMemoryPath *path = node;
- return path->next_sibling;
-}
-
-static ETreePath
-etmm_get_prev (ETreeModel *etm, ETreePath node)
-{
- ETreeMemoryPath *path = node;
- return path->prev_sibling;
-}
-
-static gboolean
-etmm_is_root (ETreeModel *etm, ETreePath node)
-{
- ETreeMemoryPath *path = node;
- return e_tree_memory_path_depth (path) == 0;
-}
-
-static gboolean
-etmm_is_expandable (ETreeModel *etm, ETreePath node)
-{
- ETreeMemoryPath *path = node;
-
- check_children (E_TREE_MEMORY (etm), node);
- return path->first_child != NULL;
-}
-
-static guint
-etmm_get_children (ETreeModel *etm, ETreePath node, ETreePath **nodes)
-{
- ETreeMemoryPath *path = node;
- guint n_children;
-
- check_children (E_TREE_MEMORY (etm), node);
-
- n_children = path->num_children;
-
- if (nodes) {
- ETreeMemoryPath *p;
- int i = 0;
-
- (*nodes) = g_new (ETreePath, n_children);
- for (p = path->first_child; p; p = p->next_sibling) {
- (*nodes)[i++] = p;
- }
- }
-
- return n_children;
-}
-
-static guint
-etmm_depth (ETreeModel *etm, ETreePath path)
-{
- return e_tree_memory_path_depth(path);
-}
-
-static gboolean
-etmm_get_expanded_default (ETreeModel *etm)
-{
- ETreeMemory *etmm = E_TREE_MEMORY (etm);
- ETreeMemoryPriv *priv = etmm->priv;
-
- return priv->expanded_default;
-}
-
-static void
-etmm_clear_children_computed (ETreeMemoryPath *path)
-{
- for (path = path->first_child; path; path = path->next_sibling) {
- path->children_computed = FALSE;
- etmm_clear_children_computed (path);
- }
-}
-
-static void
-etmm_node_request_collapse (ETreeModel *etm, ETreePath node)
-{
- if (node)
- etmm_clear_children_computed (node);
-
- if (parent_class->node_request_collapse) {
- parent_class->node_request_collapse (etm, node);
- }
-}
-
-
-static void
-e_tree_memory_class_init (ETreeMemoryClass *klass)
-{
- ETreeModelClass *tree_class = (ETreeModelClass *) klass;
- GObjectClass *object_class = (GObjectClass *) klass;
-
- parent_class = g_type_class_peek_parent (klass);
-
- node_chunk = g_mem_chunk_create (ETreeMemoryPath, TREEPATH_CHUNK_AREA_SIZE, G_ALLOC_AND_FREE);
-
- signals [FILL_IN_CHILDREN] =
- g_signal_new ("fill_in_children",
- E_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETreeMemoryClass, fill_in_children),
- (GSignalAccumulator) NULL, NULL,
- g_cclosure_marshal_VOID__POINTER,
- G_TYPE_NONE, 1, G_TYPE_POINTER);
-
- object_class->dispose = etmm_dispose;
-
- tree_class->get_root = etmm_get_root;
- tree_class->get_prev = etmm_get_prev;
- tree_class->get_next = etmm_get_next;
- tree_class->get_first_child = etmm_get_first_child;
- tree_class->get_last_child = etmm_get_last_child;
- tree_class->get_parent = etmm_get_parent;
-
- tree_class->is_root = etmm_is_root;
- tree_class->is_expandable = etmm_is_expandable;
- tree_class->get_children = etmm_get_children;
- tree_class->depth = etmm_depth;
- tree_class->get_expanded_default = etmm_get_expanded_default;
-
- tree_class->node_request_collapse = etmm_node_request_collapse;
-
- klass->fill_in_children = NULL;
-}
-
-static void
-e_tree_memory_init (GObject *object)
-{
- ETreeMemory *etmm = (ETreeMemory *)object;
-
- ETreeMemoryPriv *priv;
-
- priv = g_new0 (ETreeMemoryPriv, 1);
- etmm->priv = priv;
-
- priv->root = NULL;
- priv->frozen = 0;
- priv->expanded_default = 0;
- priv->destroy_func = NULL;
- priv->destroy_user_data = NULL;
-}
-
-E_MAKE_TYPE(e_tree_memory, "ETreeMemory", ETreeMemory, e_tree_memory_class_init, e_tree_memory_init, E_TREE_MODEL_TYPE)
-
-
-
-/**
- * e_tree_memory_construct:
- * @etree:
- *
- *
- **/
-void
-e_tree_memory_construct (ETreeMemory *etmm)
-{
-}
-
-/**
- * e_tree_memory_new
- *
- * XXX docs here.
- *
- * return values: a newly constructed ETreeMemory.
- */
-ETreeMemory *
-e_tree_memory_new (void)
-{
- return (ETreeMemory *) g_object_new (E_TREE_MEMORY_TYPE, NULL);
-}
-
-void
-e_tree_memory_set_expanded_default (ETreeMemory *etree, gboolean expanded)
-{
- etree->priv->expanded_default = expanded;
-}
-
-/**
- * e_tree_memory_node_get_data:
- * @etmm:
- * @node:
- *
- *
- *
- * Return value:
- **/
-gpointer
-e_tree_memory_node_get_data (ETreeMemory *etmm, ETreePath node)
-{
- ETreeMemoryPath *path = node;
-
- g_return_val_if_fail (path, NULL);
-
- return path->node_data;
-}
-
-/**
- * e_tree_memory_node_set_data:
- * @etmm:
- * @node:
- * @node_data:
- *
- *
- **/
-void
-e_tree_memory_node_set_data (ETreeMemory *etmm, ETreePath node, gpointer node_data)
-{
- ETreeMemoryPath *path = node;
-
- g_return_if_fail (path);
-
- path->node_data = node_data;
-}
-
-/**
- * e_tree_memory_node_insert:
- * @tree_model:
- * @parent_path:
- * @position:
- * @node_data:
- *
- *
- *
- * Return value:
- **/
-ETreePath
-e_tree_memory_node_insert (ETreeMemory *tree_model,
- ETreePath parent_node,
- int position,
- gpointer node_data)
-{
- ETreeMemoryPriv *priv;
- ETreeMemoryPath *new_path;
- ETreeMemoryPath *parent_path = parent_node;
-
- g_return_val_if_fail(tree_model != NULL, NULL);
-
- priv = tree_model->priv;
-
- g_return_val_if_fail (parent_path != NULL || priv->root == NULL, NULL);
-
- priv = tree_model->priv;
-
- if (!tree_model->priv->frozen)
- e_tree_model_pre_change(E_TREE_MODEL(tree_model));
-
- new_path = g_chunk_new0 (ETreeMemoryPath, node_chunk);
-
- new_path->node_data = node_data;
- new_path->children_computed = FALSE;
-
- if (parent_path != NULL) {
- e_tree_memory_path_insert (parent_path, position, new_path);
- if (!tree_model->priv->frozen)
- e_tree_model_node_inserted (E_TREE_MODEL(tree_model), parent_path, new_path);
- } else {
- priv->root = new_path;
- if (!tree_model->priv->frozen)
- e_tree_model_node_changed(E_TREE_MODEL(tree_model), new_path);
- }
-
- return new_path;
-}
-
-ETreePath e_tree_memory_node_insert_id (ETreeMemory *etree, ETreePath parent, int position, gpointer node_data, char *id)
-{
- return e_tree_memory_node_insert(etree, parent, position, node_data);
-}
-
-/**
- * e_tree_memory_node_insert_before:
- * @etree:
- * @parent:
- * @sibling:
- * @node_data:
- *
- *
- *
- * Return value:
- **/
-ETreePath
-e_tree_memory_node_insert_before (ETreeMemory *etree,
- ETreePath parent,
- ETreePath sibling,
- gpointer node_data)
-{
- ETreeMemoryPath *child;
- ETreeMemoryPath *parent_path = parent;
- ETreeMemoryPath *sibling_path = sibling;
- int position = 0;
-
- g_return_val_if_fail(etree != NULL, NULL);
-
- if (sibling != NULL) {
- for (child = parent_path->first_child; child; child = child->next_sibling) {
- if (child == sibling_path)
- break;
- position ++;
- }
- } else
- position = parent_path->num_children;
- return e_tree_memory_node_insert (etree, parent, position, node_data);
-}
-
-/* just blows away child data, doesn't take into account unlinking/etc */
-static void
-child_free(ETreeMemory *etree, ETreeMemoryPath *node)
-{
- ETreeMemoryPath *child, *next;
-
- child = node->first_child;
- while (child) {
- next = child->next_sibling;
- child_free(etree, child);
- child = next;
- }
-
- if (etree->priv->destroy_func) {
- etree->priv->destroy_func (node->node_data, etree->priv->destroy_user_data);
- }
-
- g_chunk_free(node, node_chunk);
-}
-
-/**
- * e_tree_memory_node_remove:
- * @etree:
- * @path:
- *
- *
- *
- * Return value:
- **/
-gpointer
-e_tree_memory_node_remove (ETreeMemory *etree, ETreePath node)
-{
- ETreeMemoryPath *path = node;
- ETreeMemoryPath *parent = path->parent;
- ETreeMemoryPath *sibling;
- gpointer ret = path->node_data;
- int old_position = 0;
-
- g_return_val_if_fail(etree != NULL, NULL);
-
- if (!etree->priv->frozen) {
- e_tree_model_pre_change(E_TREE_MODEL(etree));
- for (old_position = 0, sibling = path;
- sibling;
- old_position++, sibling = sibling->prev_sibling)
- /* Empty intentionally*/;
- old_position --;
- }
-
- /* unlink this node - we only have to unlink the root node being removed,
- since the others are only references from this node */
- e_tree_path_unlink (path);
-
- /*printf("removing %d nodes from position %d\n", visible, base);*/
- if (!etree->priv->frozen)
- e_tree_model_node_removed(E_TREE_MODEL(etree), parent, path, old_position);
-
- child_free(etree, path);
-
- if (path == etree->priv->root)
- etree->priv->root = NULL;
-
- if (!etree->priv->frozen)
- e_tree_model_node_deleted(E_TREE_MODEL(etree), path);
-
- return ret;
-}
-
-typedef struct {
- ETreeMemory *memory;
- gpointer closure;
- ETreeMemorySortCallback callback;
-} MemoryAndClosure;
-
-static int
-sort_callback(const void *data1, const void *data2, gpointer user_data)
-{
- ETreePath path1 = *(ETreePath *)data1;
- ETreePath path2 = *(ETreePath *)data2;
- MemoryAndClosure *mac = user_data;
- return (*mac->callback) (mac->memory, path1, path2, mac->closure);
-}
-
-void
-e_tree_memory_sort_node (ETreeMemory *etmm,
- ETreePath node,
- ETreeMemorySortCallback callback,
- gpointer user_data)
-{
- ETreeMemoryPath **children;
- ETreeMemoryPath *child;
- int count;
- int i;
- ETreeMemoryPath *path = node;
- MemoryAndClosure mac;
- ETreeMemoryPath *last;
-
- e_tree_model_pre_change (E_TREE_MODEL (etmm));
-
- i = 0;
- for (child = path->first_child; child; child = child->next_sibling)
- i++;
-
- children = g_new(ETreeMemoryPath *, i);
-
- count = i;
-
- for (child = path->first_child, i = 0;
- child;
- child = child->next_sibling, i++) {
- children[i] = child;
- }
-
- mac.memory = etmm;
- mac.closure = user_data;
- mac.callback = callback;
-
- e_sort (children, count, sizeof (ETreeMemoryPath *), sort_callback, &mac);
-
- path->first_child = NULL;
- last = NULL;
- for (i = 0;
- i < count;
- i++) {
- children[i]->prev_sibling = last;
- if (last)
- last->next_sibling = children[i];
- else
- path->first_child = children[i];
- last = children[i];
- }
- if (last)
- last->next_sibling = NULL;
-
- path->last_child = last;
-
- g_free(children);
-
- e_tree_model_node_changed(E_TREE_MODEL(etmm), node);
-}
-
-void
-e_tree_memory_set_node_destroy_func (ETreeMemory *etmm,
- GFunc destroy_func,
- gpointer user_data)
-{
- etmm->priv->destroy_func = destroy_func;
- etmm->priv->destroy_user_data = user_data;
-}
diff --git a/widgets/table/e-tree-memory.h b/widgets/table/e-tree-memory.h
deleted file mode 100644
index ce0003b60a..0000000000
--- a/widgets/table/e-tree-memory.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-tree-memory.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- * Chris Toshok <toshok@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_TREE_MEMORY_H_
-#define _E_TREE_MEMORY_H_
-
-#include <gdk-pixbuf/gdk-pixbuf.h>
-#include <gal/e-table/e-tree-model.h>
-
-G_BEGIN_DECLS
-
-#define E_TREE_MEMORY_TYPE (e_tree_memory_get_type ())
-#define E_TREE_MEMORY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TREE_MEMORY_TYPE, ETreeMemory))
-#define E_TREE_MEMORY_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TREE_MEMORY_TYPE, ETreeMemoryClass))
-#define E_IS_TREE_MEMORY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TREE_MEMORY_TYPE))
-#define E_IS_TREE_MEMORY_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TREE_MEMORY_TYPE))
-#define E_TREE_MEMORY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), E_TREE_MEMORY_TYPE, ETreeMemoryClass))
-
-typedef struct ETreeMemory ETreeMemory;
-typedef struct ETreeMemoryPriv ETreeMemoryPriv;
-typedef struct ETreeMemoryClass ETreeMemoryClass;
-
-typedef int (*ETreeMemorySortCallback) (ETreeMemory *etmm, ETreePath path1, ETreePath path2, gpointer closure);
-
-struct ETreeMemory {
- ETreeModel base;
- ETreeMemoryPriv *priv;
-};
-
-struct ETreeMemoryClass {
- ETreeModelClass parent_class;
-
- /* signals */
- void (*fill_in_children) (ETreeMemory *model, ETreePath node);
-};
-
-
-GType e_tree_memory_get_type (void);
-void e_tree_memory_construct (ETreeMemory *etree);
-ETreeMemory *e_tree_memory_new (void);
-
-/* node operations */
-ETreePath e_tree_memory_node_insert (ETreeMemory *etree,
- ETreePath parent,
- int position,
- gpointer node_data);
-ETreePath e_tree_memory_node_insert_id (ETreeMemory *etree,
- ETreePath parent,
- int position,
- gpointer node_data,
- char *id);
-ETreePath e_tree_memory_node_insert_before (ETreeMemory *etree,
- ETreePath parent,
- ETreePath sibling,
- gpointer node_data);
-gpointer e_tree_memory_node_remove (ETreeMemory *etree,
- ETreePath path);
-
-/* Freeze and thaw */
-void e_tree_memory_freeze (ETreeMemory *etree);
-void e_tree_memory_thaw (ETreeMemory *etree);
-void e_tree_memory_set_expanded_default (ETreeMemory *etree,
- gboolean expanded);
-gpointer e_tree_memory_node_get_data (ETreeMemory *etm,
- ETreePath node);
-void e_tree_memory_node_set_data (ETreeMemory *etm,
- ETreePath node,
- gpointer node_data);
-void e_tree_memory_sort_node (ETreeMemory *etm,
- ETreePath node,
- ETreeMemorySortCallback callback,
- gpointer user_data);
-void e_tree_memory_set_node_destroy_func (ETreeMemory *etmm,
- GFunc destroy_func,
- gpointer user_data);
-
-G_END_DECLS
-
-#endif /* _E_TREE_MEMORY_H */
-
diff --git a/widgets/table/e-tree-model.c b/widgets/table/e-tree-model.c
deleted file mode 100644
index 6ca0e17af9..0000000000
--- a/widgets/table/e-tree-model.c
+++ /dev/null
@@ -1,1098 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-tree-model.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- * Chris Toshok <toshok@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-
-#include <stdio.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-#include <libxml/parser.h>
-#include <libxml/xmlmemory.h>
-
-#include <gtk/gtksignal.h>
-#include "gal/util/e-util.h"
-#include "gal/util/e-xml-utils.h"
-#include "e-tree-model.h"
-
-#define ETM_CLASS(e) (E_TREE_MODEL_GET_CLASS(e))
-
-#define d(x)
-
-static GObjectClass *parent_class;
-
-enum {
- PRE_CHANGE,
- NO_CHANGE,
- NODE_CHANGED,
- NODE_DATA_CHANGED,
- NODE_COL_CHANGED,
- NODE_INSERTED,
- NODE_REMOVED,
- NODE_DELETED,
- NODE_REQUEST_COLLAPSE,
- LAST_SIGNAL
-};
-
-static guint e_tree_model_signals [LAST_SIGNAL] = {0, };
-
-
-static void
-e_tree_model_class_init (GObjectClass *klass)
-{
- ETreeModelClass *tree_class = (ETreeModelClass *) klass;
-
- parent_class = g_type_class_peek_parent (klass);
-
- e_tree_model_signals [PRE_CHANGE] =
- g_signal_new ("pre_change",
- E_OBJECT_CLASS_TYPE (klass),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETreeModelClass, pre_change),
- (GSignalAccumulator) NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
-
- e_tree_model_signals [NO_CHANGE] =
- g_signal_new ("no_change",
- E_OBJECT_CLASS_TYPE (klass),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETreeModelClass, no_change),
- (GSignalAccumulator) NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
-
- e_tree_model_signals [NODE_CHANGED] =
- g_signal_new ("node_changed",
- E_OBJECT_CLASS_TYPE (klass),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETreeModelClass, node_changed),
- (GSignalAccumulator) NULL, NULL,
- g_cclosure_marshal_VOID__POINTER,
- G_TYPE_NONE, 1, G_TYPE_POINTER);
-
- e_tree_model_signals [NODE_DATA_CHANGED] =
- g_signal_new ("node_data_changed",
- E_OBJECT_CLASS_TYPE (klass),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETreeModelClass, node_data_changed),
- (GSignalAccumulator) NULL, NULL,
- g_cclosure_marshal_VOID__POINTER,
- G_TYPE_NONE, 1, G_TYPE_POINTER);
-
- e_tree_model_signals [NODE_COL_CHANGED] =
- g_signal_new ("node_col_changed",
- E_OBJECT_CLASS_TYPE (klass),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETreeModelClass, node_col_changed),
- (GSignalAccumulator) NULL, NULL,
- e_marshal_VOID__POINTER_INT,
- G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_INT);
-
- e_tree_model_signals [NODE_INSERTED] =
- g_signal_new ("node_inserted",
- E_OBJECT_CLASS_TYPE (klass),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETreeModelClass, node_inserted),
- (GSignalAccumulator) NULL, NULL,
- e_marshal_VOID__POINTER_POINTER,
- G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
-
- e_tree_model_signals [NODE_REMOVED] =
- g_signal_new ("node_removed",
- E_OBJECT_CLASS_TYPE (klass),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETreeModelClass, node_removed),
- (GSignalAccumulator) NULL, NULL,
- e_marshal_VOID__POINTER_POINTER_INT,
- G_TYPE_NONE, 3, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_INT);
-
- e_tree_model_signals [NODE_DELETED] =
- g_signal_new ("node_deleted",
- E_OBJECT_CLASS_TYPE (klass),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETreeModelClass, node_deleted),
- (GSignalAccumulator) NULL, NULL,
- g_cclosure_marshal_VOID__POINTER,
- G_TYPE_NONE, 1, G_TYPE_POINTER);
-
- e_tree_model_signals [NODE_REQUEST_COLLAPSE] =
- g_signal_new ("node_request_collapse",
- E_OBJECT_CLASS_TYPE (klass),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETreeModelClass, node_request_collapse),
- (GSignalAccumulator) NULL, NULL,
- g_cclosure_marshal_VOID__POINTER,
- G_TYPE_NONE, 1, G_TYPE_POINTER);
-
- tree_class->get_root = NULL;
-
- tree_class->get_parent = NULL;
- tree_class->get_first_child = NULL;
- tree_class->get_last_child = NULL;
- tree_class->get_next = NULL;
- tree_class->get_prev = NULL;
-
- tree_class->is_root = NULL;
- tree_class->is_expandable = NULL;
- tree_class->get_children = NULL;
- tree_class->depth = NULL;
-
- tree_class->icon_at = NULL;
-
- tree_class->get_expanded_default = NULL;
- tree_class->column_count = NULL;
-
- tree_class->has_save_id = NULL;
- tree_class->get_save_id = NULL;
- tree_class->has_get_node_by_id = NULL;
- tree_class->get_node_by_id = NULL;
-
- tree_class->has_change_pending = NULL;
-
- tree_class->value_at = NULL;
- tree_class->set_value_at = NULL;
- tree_class->is_editable = NULL;
-
- tree_class->duplicate_value = NULL;
- tree_class->free_value = NULL;
- tree_class->initialize_value = NULL;
- tree_class->value_is_empty = NULL;
- tree_class->value_to_string = NULL;
-
- tree_class->pre_change = NULL;
- tree_class->no_change = NULL;
- tree_class->node_changed = NULL;
- tree_class->node_data_changed = NULL;
- tree_class->node_col_changed = NULL;
- tree_class->node_inserted = NULL;
- tree_class->node_removed = NULL;
- tree_class->node_deleted = NULL;
- tree_class->node_request_collapse = NULL;
-}
-
-E_MAKE_TYPE(e_tree_model, "ETreeModel", ETreeModel, e_tree_model_class_init, NULL, G_TYPE_OBJECT)
-
-
-/* signals */
-
-/**
- * e_tree_model_node_changed:
- * @tree_model:
- * @node:
- *
- *
- *
- * Return value:
- **/
-void
-e_tree_model_pre_change (ETreeModel *tree_model)
-{
- g_return_if_fail (tree_model != NULL);
- g_return_if_fail (E_IS_TREE_MODEL (tree_model));
-
- d(g_print("Emitting pre_change on model 0x%p, a %s.\n", tree_model, gtk_type_name (GTK_OBJECT(tree_model)->klass->type)));
-
- g_signal_emit (G_OBJECT (tree_model), e_tree_model_signals [PRE_CHANGE], 0);
-}
-
-/**
- * e_tree_model_node_changed:
- * @tree_model:
- * @node:
- *
- *
- *
- * Return value:
- **/
-void
-e_tree_model_no_change (ETreeModel *tree_model)
-{
- g_return_if_fail (tree_model != NULL);
- g_return_if_fail (E_IS_TREE_MODEL (tree_model));
-
- d(g_print("Emitting no_change on model 0x%p, a %s.\n", tree_model, gtk_type_name (GTK_OBJECT(tree_model)->klass->type)));
-
- g_signal_emit (G_OBJECT (tree_model), e_tree_model_signals [NO_CHANGE], 0);
-}
-
-/**
- * e_tree_model_node_changed:
- * @tree_model:
- * @node:
- *
- *
- *
- * Return value:
- **/
-void
-e_tree_model_node_changed (ETreeModel *tree_model, ETreePath node)
-{
- g_return_if_fail (tree_model != NULL);
- g_return_if_fail (E_IS_TREE_MODEL (tree_model));
-
- d(g_print("Emitting node_changed on model 0x%p, a %s.\n", tree_model, gtk_type_name (GTK_OBJECT(tree_model)->klass->type)));
-
- g_signal_emit (G_OBJECT (tree_model), e_tree_model_signals [NODE_CHANGED], 0, node);
-}
-
-/**
- * e_tree_model_node_data_changed:
- * @tree_model:
- * @node:
- *
- *
- *
- * Return value:
- **/
-void
-e_tree_model_node_data_changed (ETreeModel *tree_model, ETreePath node)
-{
- g_return_if_fail (tree_model != NULL);
- g_return_if_fail (E_IS_TREE_MODEL (tree_model));
-
- d(g_print("Emitting node_data_changed on model 0x%p, a %s.\n", tree_model, gtk_type_name (GTK_OBJECT(tree_model)->klass->type)));
-
- g_signal_emit (G_OBJECT (tree_model), e_tree_model_signals [NODE_DATA_CHANGED], 0, node);
-}
-
-/**
- * e_tree_model_node_col_changed:
- * @tree_model:
- * @node:
- *
- *
- *
- * Return value:
- **/
-void
-e_tree_model_node_col_changed (ETreeModel *tree_model, ETreePath node, int col)
-{
- g_return_if_fail (tree_model != NULL);
- g_return_if_fail (E_IS_TREE_MODEL (tree_model));
-
- d(g_print("Emitting node_col_changed on model 0x%p, a %s.\n", tree_model, gtk_type_name (GTK_OBJECT(tree_model)->klass->type)));
-
- g_signal_emit (G_OBJECT (tree_model), e_tree_model_signals [NODE_COL_CHANGED], 0, node, col);
-}
-
-/**
- * e_tree_model_node_inserted:
- * @tree_model:
- * @parent_node:
- * @inserted_node:
- *
- *
- **/
-void
-e_tree_model_node_inserted (ETreeModel *tree_model,
- ETreePath parent_node,
- ETreePath inserted_node)
-{
- g_return_if_fail (tree_model != NULL);
- g_return_if_fail (E_IS_TREE_MODEL (tree_model));
-
- d(g_print("Emitting node_inserted on model 0x%p, a %s.\n", tree_model, gtk_type_name (GTK_OBJECT(tree_model)->klass->type)));
-
- g_signal_emit (G_OBJECT (tree_model), e_tree_model_signals [NODE_INSERTED], 0,
- parent_node, inserted_node);
-}
-
-/**
- * e_tree_model_node_removed:
- * @tree_model:
- * @parent_node:
- * @removed_node:
- *
- *
- **/
-void
-e_tree_model_node_removed (ETreeModel *tree_model, ETreePath parent_node, ETreePath removed_node, int old_position)
-{
- g_return_if_fail (tree_model != NULL);
- g_return_if_fail (E_IS_TREE_MODEL (tree_model));
-
- d(g_print("Emitting node_removed on model 0x%p, a %s.\n", tree_model, gtk_type_name (GTK_OBJECT(tree_model)->klass->type)));
-
- g_signal_emit (G_OBJECT (tree_model), e_tree_model_signals [NODE_REMOVED], 0,
- parent_node, removed_node, old_position);
-}
-
-/**
- * e_tree_model_node_deleted:
- * @tree_model:
- * @deleted_node:
- *
- *
- **/
-void
-e_tree_model_node_deleted (ETreeModel *tree_model, ETreePath deleted_node)
-{
- g_return_if_fail (tree_model != NULL);
- g_return_if_fail (E_IS_TREE_MODEL (tree_model));
-
- d(g_print("Emitting node_deleted on model 0x%p, a %s.\n", tree_model, gtk_type_name (GTK_OBJECT(tree_model)->klass->type)));
-
- g_signal_emit (G_OBJECT (tree_model), e_tree_model_signals [NODE_DELETED], 0, deleted_node);
-}
-
-/**
- * e_tree_model_node_request_collapse:
- * @tree_model:
- * @collapsed_node:
- *
- *
- **/
-void
-e_tree_model_node_request_collapse (ETreeModel *tree_model, ETreePath collapsed_node)
-{
- g_return_if_fail (tree_model != NULL);
- g_return_if_fail (E_IS_TREE_MODEL (tree_model));
-
- d(g_print("Emitting node_request_collapse on model 0x%p, a %s.\n", tree_model, gtk_type_name (GTK_OBJECT(tree_model)->klass->type)));
-
- g_signal_emit (G_OBJECT (tree_model), e_tree_model_signals [NODE_REQUEST_COLLAPSE], 0, collapsed_node);
-}
-
-
-
-/**
- * e_tree_model_new
- *
- * XXX docs here.
- *
- * return values: a newly constructed ETreeModel.
- */
-ETreeModel *
-e_tree_model_new ()
-{
- return (ETreeModel *) g_object_new (E_TREE_MODEL_TYPE, NULL);
-}
-
-/**
- * e_tree_model_get_root
- * @etree: the ETreeModel of which we want the root node.
- *
- * Accessor for the root node of @etree.
- *
- * return values: the ETreePath corresponding to the root node.
- */
-ETreePath
-e_tree_model_get_root (ETreeModel *etree)
-{
- g_return_val_if_fail (etree != NULL, NULL);
- g_return_val_if_fail (E_IS_TREE_MODEL (etree), NULL);
-
- if (ETM_CLASS(etree)->get_root)
- return ETM_CLASS(etree)->get_root(etree);
- else
- return NULL;
-}
-
-/**
- * e_tree_model_node_get_parent:
- * @etree:
- * @path:
- *
- *
- *
- * Return value:
- **/
-ETreePath
-e_tree_model_node_get_parent (ETreeModel *etree, ETreePath node)
-{
- g_return_val_if_fail(etree != NULL, NULL);
- if (ETM_CLASS(etree)->get_parent)
- return ETM_CLASS(etree)->get_parent(etree, node);
- else
- return NULL;
-}
-
-/**
- * e_tree_model_node_get_first_child:
- * @etree:
- * @node:
- *
- *
- *
- * Return value:
- **/
-ETreePath
-e_tree_model_node_get_first_child (ETreeModel *etree, ETreePath node)
-{
- g_return_val_if_fail (etree != NULL, NULL);
- g_return_val_if_fail (E_IS_TREE_MODEL (etree), NULL);
-
- if (ETM_CLASS(etree)->get_first_child)
- return ETM_CLASS(etree)->get_first_child(etree, node);
- else
- return NULL;
-}
-
-/**
- * e_tree_model_node_get_last_child:
- * @etree:
- * @node:
- *
- *
- *
- * Return value:
- **/
-ETreePath
-e_tree_model_node_get_last_child (ETreeModel *etree, ETreePath node)
-{
- g_return_val_if_fail (etree != NULL, NULL);
- g_return_val_if_fail (E_IS_TREE_MODEL (etree), NULL);
-
- if (ETM_CLASS(etree)->get_last_child)
- return ETM_CLASS(etree)->get_last_child(etree, node);
- else
- return NULL;
-}
-
-
-/**
- * e_tree_model_node_get_next:
- * @etree:
- * @node:
- *
- *
- *
- * Return value:
- **/
-ETreePath
-e_tree_model_node_get_next (ETreeModel *etree, ETreePath node)
-{
- g_return_val_if_fail (etree != NULL, NULL);
- g_return_val_if_fail (E_IS_TREE_MODEL (etree), NULL);
-
- if (ETM_CLASS(etree)->get_next)
- return ETM_CLASS(etree)->get_next(etree, node);
- else
- return NULL;
-}
-
-/**
- * e_tree_model_node_get_prev:
- * @etree:
- * @node:
- *
- *
- *
- * Return value:
- **/
-ETreePath
-e_tree_model_node_get_prev (ETreeModel *etree, ETreePath node)
-{
- g_return_val_if_fail (etree != NULL, NULL);
- g_return_val_if_fail (E_IS_TREE_MODEL (etree), NULL);
-
- if (ETM_CLASS(etree)->get_prev)
- return ETM_CLASS(etree)->get_prev(etree, node);
- else
- return NULL;
-}
-
-/**
- * e_tree_model_node_is_root:
- * @etree:
- * @path:
- *
- *
- *
- * Return value:
- **/
-gboolean
-e_tree_model_node_is_root (ETreeModel *etree, ETreePath node)
-{
- g_return_val_if_fail(etree != NULL, FALSE);
-
- if (ETM_CLASS(etree)->is_root)
- return ETM_CLASS(etree)->is_root(etree, node);
- else
- return FALSE;
-}
-
-/**
- * e_tree_model_node_is_expandable:
- * @etree:
- * @path:
- *
- *
- *
- * Return value:
- **/
-gboolean
-e_tree_model_node_is_expandable (ETreeModel *etree, ETreePath node)
-{
- g_return_val_if_fail(etree != NULL, FALSE);
- g_return_val_if_fail(node != NULL, FALSE);
-
- if (ETM_CLASS(etree)->is_expandable)
- return ETM_CLASS(etree)->is_expandable(etree, node);
- else
- return FALSE;
-}
-
-guint
-e_tree_model_node_get_children (ETreeModel *etree, ETreePath node, ETreePath **nodes)
-{
- g_return_val_if_fail(etree != NULL, 0);
- if (ETM_CLASS(etree)->get_children)
- return ETM_CLASS(etree)->get_children (etree, node, nodes);
- else
- return 0;
-}
-
-/**
- * e_tree_model_node_depth:
- * @etree:
- * @path:
- *
- *
- *
- * Return value:
- **/
-guint
-e_tree_model_node_depth (ETreeModel *etree, ETreePath node)
-{
- g_return_val_if_fail (etree != NULL, 0);
- g_return_val_if_fail (E_IS_TREE_MODEL (etree), 0);
-
- if (ETM_CLASS(etree)->depth)
- return ETM_CLASS(etree)->depth(etree, node);
- else
- return 0;
-}
-
-/**
- * e_tree_model_icon_at
- * @etree: The ETreeModel.
- * @path: The ETreePath to the node we're getting the icon of.
- *
- * XXX docs here.
- *
- * return values: the GdkPixbuf associated with this node.
- */
-GdkPixbuf *
-e_tree_model_icon_at (ETreeModel *etree, ETreePath node)
-{
- g_return_val_if_fail (etree != NULL, NULL);
- g_return_val_if_fail (E_IS_TREE_MODEL (etree), NULL);
-
- if (ETM_CLASS(etree)->icon_at)
- return ETM_CLASS(etree)->icon_at (etree, node);
- else
- return NULL;
-}
-
-/**
- * e_tree_model_get_expanded_default
- * @etree: The ETreeModel.
- *
- * XXX docs here.
- *
- * return values: Whether nodes should be expanded by default.
- */
-gboolean
-e_tree_model_get_expanded_default (ETreeModel *etree)
-{
- g_return_val_if_fail (etree != NULL, FALSE);
- g_return_val_if_fail (E_IS_TREE_MODEL (etree), FALSE);
-
- if (ETM_CLASS(etree)->get_expanded_default)
- return ETM_CLASS(etree)->get_expanded_default (etree);
- else
- return FALSE;
-}
-
-/**
- * e_tree_model_column_count
- * @etree: The ETreeModel.
- *
- * XXX docs here.
- *
- * return values: The number of columns
- */
-gint
-e_tree_model_column_count (ETreeModel *etree)
-{
- g_return_val_if_fail (etree != NULL, 0);
- g_return_val_if_fail (E_IS_TREE_MODEL (etree), 0);
-
- if (ETM_CLASS(etree)->column_count)
- return ETM_CLASS(etree)->column_count (etree);
- else
- return 0;
-}
-
-/**
- * e_tree_model_has_save_id
- * @etree: The ETreeModel.
- *
- * XXX docs here.
- *
- * return values: Whether this tree has valid save id data.
- */
-gboolean
-e_tree_model_has_save_id (ETreeModel *etree)
-{
- g_return_val_if_fail (etree != NULL, FALSE);
- g_return_val_if_fail (E_IS_TREE_MODEL (etree), FALSE);
-
- if (ETM_CLASS(etree)->has_save_id)
- return ETM_CLASS(etree)->has_save_id (etree);
- else
- return FALSE;
-}
-
-/**
- * e_tree_model_get_save_id
- * @etree: The ETreeModel.
- * @node: The ETreePath.
- *
- * XXX docs here.
- *
- * return values: The save id for this path.
- */
-gchar *
-e_tree_model_get_save_id (ETreeModel *etree, ETreePath node)
-{
- g_return_val_if_fail (etree != NULL, NULL);
- g_return_val_if_fail (E_IS_TREE_MODEL (etree), NULL);
-
- if (ETM_CLASS(etree)->get_save_id)
- return ETM_CLASS(etree)->get_save_id (etree, node);
- else
- return NULL;
-}
-
-/**
- * e_tree_model_has_get_node_by_id
- * @etree: The ETreeModel.
- *
- * XXX docs here.
- *
- * return values: Whether this tree can quickly get a node from its save id.
- */
-gboolean
-e_tree_model_has_get_node_by_id (ETreeModel *etree)
-{
- g_return_val_if_fail (etree != NULL, FALSE);
- g_return_val_if_fail (E_IS_TREE_MODEL (etree), FALSE);
-
- if (ETM_CLASS(etree)->has_get_node_by_id)
- return ETM_CLASS(etree)->has_get_node_by_id (etree);
- else
- return FALSE;
-}
-
-/**
- * e_tree_model_get_node_by_id
- * @etree: The ETreeModel.
- * @node: The ETreePath.
- *
- * get_node_by_id(get_save_id(node)) should be the original node.
- * Likewise if get_node_by_id is not NULL, then
- * get_save_id(get_node_by_id(string)) should be a copy of the
- * original string.
- *
- * return values: The path for this save id.
- */
-ETreePath
-e_tree_model_get_node_by_id (ETreeModel *etree, const char *save_id)
-{
- g_return_val_if_fail (etree != NULL, NULL);
- g_return_val_if_fail (E_IS_TREE_MODEL (etree), NULL);
-
- if (ETM_CLASS(etree)->get_node_by_id)
- return ETM_CLASS(etree)->get_node_by_id (etree, save_id);
- else
- return NULL;
-}
-
-/**
- * e_tree_model_has_change_pending
- * @etree: The ETreeModel.
- *
- * XXX docs here.
- *
- * return values: Whether this tree has valid save id data.
- */
-gboolean
-e_tree_model_has_change_pending (ETreeModel *etree)
-{
- g_return_val_if_fail (etree != NULL, FALSE);
- g_return_val_if_fail (E_IS_TREE_MODEL (etree), FALSE);
-
- if (ETM_CLASS(etree)->has_change_pending)
- return ETM_CLASS(etree)->has_change_pending (etree);
- else
- return FALSE;
-}
-
-/**
- * e_tree_model_value_at:
- * @etree: The ETreeModel.
- * @node: The ETreePath to the node we're getting the data from.
- * @col: the column to retrieve data from
- *
- * Return value: This function returns the value that is stored by the
- * @etree in column @col and node @node. The data returned can be a
- * pointer or any data value that can be stored inside a pointer.
- *
- * The data returned is typically used by an ECell renderer.
- *
- * The data returned must be valid until the model sends a signal that
- * affect that piece of data. node_changed and node_deleted affect
- * all data in tha t node and all nodes under that node.
- * node_data_changed affects the data in that node. node_col_changed
- * affects the data in that node for that column. node_inserted,
- * node_removed, and no_change don't affect any data in this way.
- **/
-void *
-e_tree_model_value_at (ETreeModel *etree, ETreePath node, int col)
-{
- g_return_val_if_fail (etree != NULL, NULL);
- g_return_val_if_fail (E_IS_TREE_MODEL (etree), NULL);
-
- if (ETM_CLASS(etree)->value_at)
- return ETM_CLASS(etree)->value_at (etree, node, col);
- else
- return NULL;
-}
-
-/**
- * e_tree_model_icon_of_node
- * @etree: The ETreeModel.
- * @path: The ETreePath to the node we're getting the icon of.
- *
- * XXX docs here.
- *
- * return values: the GdkPixbuf associated with this node.
- */
-void
-e_tree_model_set_value_at (ETreeModel *etree, ETreePath node, int col, const void *val)
-{
- g_return_if_fail (etree != NULL);
- g_return_if_fail (E_IS_TREE_MODEL (etree));
-
- if (ETM_CLASS(etree)->set_value_at)
- ETM_CLASS(etree)->set_value_at (etree, node, col, val);
-}
-
-/**
- * e_tree_model_node_is_editable:
- * @etree:
- * @path:
- *
- *
- *
- * Return value:
- **/
-gboolean
-e_tree_model_node_is_editable (ETreeModel *etree, ETreePath node, int col)
-{
- g_return_val_if_fail(etree != NULL, FALSE);
-
- if (ETM_CLASS(etree)->is_editable)
- return ETM_CLASS(etree)->is_editable(etree, node, col);
- else
- return FALSE;
-}
-
-/**
- * e_tree_model_duplicate_value:
- * @etree:
- * @path:
- *
- *
- *
- * Return value:
- **/
-void *
-e_tree_model_duplicate_value (ETreeModel *etree, int col, const void *value)
-{
- g_return_val_if_fail(etree != NULL, NULL);
-
- if (ETM_CLASS(etree)->duplicate_value)
- return ETM_CLASS(etree)->duplicate_value(etree, col, value);
- else
- return NULL;
-}
-
-/**
- * e_tree_model_free_value:
- * @etree:
- * @path:
- *
- *
- *
- * Return value:
- **/
-void
-e_tree_model_free_value (ETreeModel *etree, int col, void *value)
-{
- g_return_if_fail(etree != NULL);
-
- if (ETM_CLASS(etree)->free_value)
- ETM_CLASS(etree)->free_value(etree, col, value);
-}
-
-/**
- * e_tree_model_initialize_value:
- * @etree:
- * @path:
- *
- *
- *
- * Return value:
- **/
-void *
-e_tree_model_initialize_value (ETreeModel *etree, int col)
-{
- g_return_val_if_fail(etree != NULL, NULL);
-
- if (ETM_CLASS(etree)->initialize_value)
- return ETM_CLASS(etree)->initialize_value(etree, col);
- else
- return NULL;
-}
-
-/**
- * e_tree_model_value_is_empty:
- * @etree:
- * @path:
- *
- *
- *
- * Return value:
- **/
-gboolean
-e_tree_model_value_is_empty (ETreeModel *etree, int col, const void *value)
-{
- g_return_val_if_fail(etree != NULL, TRUE);
-
- if (ETM_CLASS(etree)->value_is_empty)
- return ETM_CLASS(etree)->value_is_empty(etree, col, value);
- else
- return TRUE;
-}
-
-/**
- * e_tree_model_value_to_string:
- * @etree:
- * @path:
- *
- *
- *
- * Return value:
- **/
-char *
-e_tree_model_value_to_string (ETreeModel *etree, int col, const void *value)
-{
- g_return_val_if_fail(etree != NULL, g_strdup(""));
-
- if (ETM_CLASS(etree)->value_to_string)
- return ETM_CLASS(etree)->value_to_string(etree, col, value);
- else
- return g_strdup("");
-}
-
-/**
- * e_tree_model_node_traverse:
- * @model:
- * @path:
- * @func:
- * @data:
- *
- *
- **/
-void
-e_tree_model_node_traverse (ETreeModel *model, ETreePath path, ETreePathFunc func, gpointer data)
-{
- ETreePath child;
-
- g_return_if_fail (model != NULL);
- g_return_if_fail (E_IS_TREE_MODEL (model));
- g_return_if_fail (path != NULL);
-
- child = e_tree_model_node_get_first_child (model, path);
-
- while (child) {
- ETreePath next_child;
-
- next_child = e_tree_model_node_get_next (model, child);
- e_tree_model_node_traverse (model, child, func, data);
- if (func (model, child, data))
- return;
-
- child = next_child;
- }
-}
-
-/**
- * e_tree_model_node_traverse_preorder:
- * @model:
- * @path:
- * @func:
- * @data:
- *
- *
- **/
-void
-e_tree_model_node_traverse_preorder (ETreeModel *model, ETreePath path, ETreePathFunc func, gpointer data)
-{
- ETreePath child;
-
- g_return_if_fail (model != NULL);
- g_return_if_fail (E_IS_TREE_MODEL (model));
- g_return_if_fail (path != NULL);
-
- child = e_tree_model_node_get_first_child (model, path);
-
- while (child) {
- ETreePath next_child;
-
- if (func (model, child, data))
- return;
-
- next_child = e_tree_model_node_get_next (model, child);
- e_tree_model_node_traverse_preorder (model, child, func, data);
-
- child = next_child;
- }
-}
-
-/**
- * e_tree_model_node_traverse_preorder:
- * @model:
- * @path:
- * @func:
- * @data:
- *
- *
- **/
-static ETreePath
-e_tree_model_node_real_traverse (ETreeModel *model, ETreePath path, ETreePath end_path, gboolean forward_direction, ETreePathFunc func, gpointer data)
-{
- ETreePath child;
-
- g_return_val_if_fail (model != NULL, NULL);
- g_return_val_if_fail (E_IS_TREE_MODEL (model), NULL);
- g_return_val_if_fail (path != NULL, NULL);
-
- if (forward_direction)
- child = e_tree_model_node_get_first_child (model, path);
- else
- child = e_tree_model_node_get_last_child (model, path);
-
- while (child) {
- ETreePath result;
-
- if (forward_direction && (child == end_path || func (model, child, data)))
- return child;
-
- if ((result = e_tree_model_node_real_traverse (model, child, end_path, forward_direction, func, data)))
- return result;
-
- if (!forward_direction && (child == end_path || func (model, child, data)))
- return child;
-
- if (forward_direction)
- child = e_tree_model_node_get_next (model, child);
- else
- child = e_tree_model_node_get_prev (model, child);
- }
- return NULL;
-}
-
-/**
- * e_tree_model_node_traverse_preorder:
- * @model:
- * @path:
- * @func:
- * @data:
- *
- *
- **/
-ETreePath
-e_tree_model_node_find (ETreeModel *model, ETreePath path, ETreePath end_path, gboolean forward_direction, ETreePathFunc func, gpointer data)
-{
- ETreePath result;
- ETreePath next;
-
- g_return_val_if_fail (model != NULL, NULL);
- g_return_val_if_fail (E_IS_TREE_MODEL (model), NULL);
-
- /* Just search the whole tree in this case. */
- if (path == NULL) {
- ETreePath root;
- root = e_tree_model_get_root (model);
-
- if (forward_direction && (end_path == root || func (model, root, data)))
- return root;
-
- if ((result = e_tree_model_node_real_traverse (model, root, end_path, forward_direction, func, data)))
- return result;
-
- if (!forward_direction && (end_path == root || func (model, root, data)))
- return root;
-
- return NULL;
- }
-
- while (1) {
-
- if (forward_direction) {
- if ((result = e_tree_model_node_real_traverse (model, path, end_path, forward_direction, func, data)))
- return result;
- next = e_tree_model_node_get_next (model, path);
- } else {
- next = e_tree_model_node_get_prev (model, path);
- if (next && (result = e_tree_model_node_real_traverse (model, next, end_path, forward_direction, func, data)))
- return result;
- }
-
- while (next == NULL) {
- path = e_tree_model_node_get_parent (model, path);
-
- if (path == NULL)
- return NULL;
-
- if (forward_direction)
- next = e_tree_model_node_get_next (model, path);
- else
- next = path;
- }
-
- if (end_path == next || func (model, next, data))
- return next;
-
- path = next;
- }
-}
-
diff --git a/widgets/table/e-tree-model.h b/widgets/table/e-tree-model.h
deleted file mode 100644
index c9574388e1..0000000000
--- a/widgets/table/e-tree-model.h
+++ /dev/null
@@ -1,227 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-tree-model.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- * Chris Toshok <toshok@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_TREE_MODEL_H_
-#define _E_TREE_MODEL_H_
-
-#include <gdk-pixbuf/gdk-pixbuf.h>
-#include <glib-object.h>
-
-
-G_BEGIN_DECLS
-
-
-#define E_TREE_MODEL_TYPE (e_tree_model_get_type ())
-#define E_TREE_MODEL(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TREE_MODEL_TYPE, ETreeModel))
-#define E_TREE_MODEL_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TREE_MODEL_TYPE, ETreeModelClass))
-#define E_IS_TREE_MODEL(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TREE_MODEL_TYPE))
-#define E_IS_TREE_MODEL_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TREE_MODEL_TYPE))
-#define E_TREE_MODEL_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), E_TREE_MODEL_TYPE, ETreeModelClass))
-
-typedef void * ETreePath;
-typedef struct ETreeModel ETreeModel;
-typedef struct ETreeModelClass ETreeModelClass;
-typedef gint (*ETreePathCompareFunc)(ETreeModel *model, ETreePath path1, ETreePath path2);
-typedef gboolean (*ETreePathFunc)(ETreeModel *model, ETreePath path, gpointer data);
-
-struct ETreeModel {
- GObject base;
-};
-
-struct ETreeModelClass {
- GObjectClass parent_class;
-
- /*
- * Virtual methods
- */
- ETreePath (*get_root) (ETreeModel *etm);
-
- ETreePath (*get_parent) (ETreeModel *etm, ETreePath node);
- ETreePath (*get_first_child) (ETreeModel *etm, ETreePath node);
- ETreePath (*get_last_child) (ETreeModel *etm, ETreePath node);
- ETreePath (*get_next) (ETreeModel *etm, ETreePath node);
- ETreePath (*get_prev) (ETreeModel *etm, ETreePath node);
-
- gboolean (*is_root) (ETreeModel *etm, ETreePath node);
- gboolean (*is_expandable) (ETreeModel *etm, ETreePath node);
- guint (*get_children) (ETreeModel *etm, ETreePath node, ETreePath **paths);
- guint (*depth) (ETreeModel *etm, ETreePath node);
-
- GdkPixbuf *(*icon_at) (ETreeModel *etm, ETreePath node);
-
- gboolean (*get_expanded_default) (ETreeModel *etm);
- gint (*column_count) (ETreeModel *etm);
-
- gboolean (*has_save_id) (ETreeModel *etm);
- gchar *(*get_save_id) (ETreeModel *etm, ETreePath node);
-
- gboolean (*has_get_node_by_id) (ETreeModel *etm);
- ETreePath (*get_node_by_id) (ETreeModel *etm, const char *save_id);
-
- gboolean (*has_change_pending) (ETreeModel *etm);
-
- /*
- * ETable analogs
- */
- void *(*value_at) (ETreeModel *etm, ETreePath node, int col);
- void (*set_value_at) (ETreeModel *etm, ETreePath node, int col, const void *val);
- gboolean (*is_editable) (ETreeModel *etm, ETreePath node, int col);
-
- void *(*duplicate_value) (ETreeModel *etm, int col, const void *value);
- void (*free_value) (ETreeModel *etm, int col, void *value);
- void *(*initialize_value) (ETreeModel *etm, int col);
- gboolean (*value_is_empty) (ETreeModel *etm, int col, const void *value);
- char *(*value_to_string) (ETreeModel *etm, int col, const void *value);
-
- /*
- * Signals
- */
-
- /* During node_remove, the ETreePath of the child is removed
- * from the tree but is still a valid ETreePath. At
- * node_deleted, the ETreePath is no longer valid.
- */
-
- void (*pre_change) (ETreeModel *etm);
- void (*no_change) (ETreeModel *etm);
- void (*node_changed) (ETreeModel *etm, ETreePath node);
- void (*node_data_changed) (ETreeModel *etm, ETreePath node);
- void (*node_col_changed) (ETreeModel *etm, ETreePath node, int col);
- void (*node_inserted) (ETreeModel *etm, ETreePath parent, ETreePath inserted_node);
- void (*node_removed) (ETreeModel *etm, ETreePath parent, ETreePath removed_node, int old_position);
- void (*node_deleted) (ETreeModel *etm, ETreePath deleted_node);
-
- /* This signal requests that any viewers of the tree that
- * collapse and expand nodes collapse this node.
- */
- void (*node_request_collapse) (ETreeModel *etm, ETreePath node);
-};
-
-
-GType e_tree_model_get_type (void);
-ETreeModel *e_tree_model_new (void);
-
-/* tree traversal operations */
-ETreePath e_tree_model_get_root (ETreeModel *etree);
-ETreePath e_tree_model_node_get_parent (ETreeModel *etree,
- ETreePath path);
-ETreePath e_tree_model_node_get_first_child (ETreeModel *etree,
- ETreePath path);
-ETreePath e_tree_model_node_get_last_child (ETreeModel *etree,
- ETreePath path);
-ETreePath e_tree_model_node_get_next (ETreeModel *etree,
- ETreePath path);
-ETreePath e_tree_model_node_get_prev (ETreeModel *etree,
- ETreePath path);
-
-/* node accessors */
-gboolean e_tree_model_node_is_root (ETreeModel *etree,
- ETreePath path);
-gboolean e_tree_model_node_is_expandable (ETreeModel *etree,
- ETreePath path);
-guint e_tree_model_node_get_children (ETreeModel *etree,
- ETreePath path,
- ETreePath **paths);
-guint e_tree_model_node_depth (ETreeModel *etree,
- ETreePath path);
-GdkPixbuf *e_tree_model_icon_at (ETreeModel *etree,
- ETreePath path);
-gboolean e_tree_model_get_expanded_default (ETreeModel *model);
-gint e_tree_model_column_count (ETreeModel *model);
-gboolean e_tree_model_has_save_id (ETreeModel *model);
-gchar *e_tree_model_get_save_id (ETreeModel *model,
- ETreePath node);
-gboolean e_tree_model_has_get_node_by_id (ETreeModel *model);
-ETreePath e_tree_model_get_node_by_id (ETreeModel *model,
- const char *save_id);
-gboolean e_tree_model_has_change_pending (ETreeModel *model);
-void *e_tree_model_value_at (ETreeModel *etree,
- ETreePath node,
- int col);
-void e_tree_model_set_value_at (ETreeModel *etree,
- ETreePath node,
- int col,
- const void *val);
-gboolean e_tree_model_node_is_editable (ETreeModel *etree,
- ETreePath node,
- int col);
-void *e_tree_model_duplicate_value (ETreeModel *etree,
- int col,
- const void *value);
-void e_tree_model_free_value (ETreeModel *etree,
- int col,
- void *value);
-void *e_tree_model_initialize_value (ETreeModel *etree,
- int col);
-gboolean e_tree_model_value_is_empty (ETreeModel *etree,
- int col,
- const void *value);
-char *e_tree_model_value_to_string (ETreeModel *etree,
- int col,
- const void *value);
-
-/* depth first traversal of path's descendents, calling func on each one */
-void e_tree_model_node_traverse (ETreeModel *model,
- ETreePath path,
- ETreePathFunc func,
- gpointer data);
-void e_tree_model_node_traverse_preorder (ETreeModel *model,
- ETreePath path,
- ETreePathFunc func,
- gpointer data);
-ETreePath e_tree_model_node_find (ETreeModel *model,
- ETreePath path,
- ETreePath end_path,
- gboolean forward_direction,
- ETreePathFunc func,
- gpointer data);
-
-/*
-** Routines for emitting signals on the ETreeModel
-*/
-void e_tree_model_pre_change (ETreeModel *tree_model);
-void e_tree_model_no_change (ETreeModel *tree_model);
-void e_tree_model_node_changed (ETreeModel *tree_model,
- ETreePath node);
-void e_tree_model_node_data_changed (ETreeModel *tree_model,
- ETreePath node);
-void e_tree_model_node_col_changed (ETreeModel *tree_model,
- ETreePath node,
- int col);
-void e_tree_model_node_inserted (ETreeModel *tree_model,
- ETreePath parent_node,
- ETreePath inserted_node);
-void e_tree_model_node_removed (ETreeModel *tree_model,
- ETreePath parent_node,
- ETreePath removed_node,
- int old_position);
-void e_tree_model_node_deleted (ETreeModel *tree_model,
- ETreePath deleted_node);
-void e_tree_model_node_request_collapse (ETreeModel *tree_model,
- ETreePath deleted_node);
-
-
-G_END_DECLS
-
-#endif /* _E_TREE_MODEL_H */
diff --git a/widgets/table/e-tree-scrolled.c b/widgets/table/e-tree-scrolled.c
deleted file mode 100644
index a72a246b69..0000000000
--- a/widgets/table/e-tree-scrolled.c
+++ /dev/null
@@ -1,228 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-tree-scrolled.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdio.h>
-#include <libgnomecanvas/gnome-canvas.h>
-#include <gtk/gtksignal.h>
-#include <libxml/parser.h>
-#include <libxml/xmlmemory.h>
-#include <gal/util/e-util.h>
-#include <gal/util/e-i18n.h>
-
-#include "e-tree-scrolled.h"
-
-#define COLUMN_HEADER_HEIGHT 16
-
-#define PARENT_TYPE gtk_scrolled_window_get_type ()
-
-static GtkObjectClass *parent_class;
-
-enum {
- PROP_0,
- PROP_TREE
-};
-
-static void
-e_tree_scrolled_init (GtkObject *object)
-{
- ETreeScrolled *ets;
- GtkScrolledWindow *scrolled_window;
-
- ets = E_TREE_SCROLLED (object);
- scrolled_window = GTK_SCROLLED_WINDOW (object);
-
- GTK_WIDGET_SET_FLAGS (ets, GTK_CAN_FOCUS);
-
- ets->tree = g_object_new (E_TREE_TYPE, NULL);
-
- gtk_scrolled_window_set_policy (scrolled_window, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
- gtk_scrolled_window_set_shadow_type (scrolled_window, GTK_SHADOW_IN);
-}
-
-static void
-e_tree_scrolled_real_construct (ETreeScrolled *ets)
-{
- gtk_container_add(GTK_CONTAINER(ets), GTK_WIDGET(ets->tree));
-
- gtk_widget_show(GTK_WIDGET(ets->tree));
-}
-
-ETreeScrolled *e_tree_scrolled_construct (ETreeScrolled *ets,
- ETreeModel *etm,
- ETableExtras *ete,
- const char *spec,
- const char *state)
-{
- g_return_val_if_fail(ets != NULL, NULL);
- g_return_val_if_fail(E_IS_TREE_SCROLLED(ets), NULL);
- g_return_val_if_fail(etm != NULL, NULL);
- g_return_val_if_fail(E_IS_TREE_MODEL(etm), NULL);
- g_return_val_if_fail(ete == NULL || E_IS_TABLE_EXTRAS(ete), NULL);
- g_return_val_if_fail(spec != NULL, NULL);
-
- e_tree_construct(ets->tree, etm, ete, spec, state);
-
- e_tree_scrolled_real_construct(ets);
-
- return ets;
-}
-
-GtkWidget *e_tree_scrolled_new (ETreeModel *etm,
- ETableExtras *ete,
- const char *spec,
- const char *state)
-{
- ETreeScrolled *ets;
-
- g_return_val_if_fail(etm != NULL, NULL);
- g_return_val_if_fail(E_IS_TREE_MODEL(etm), NULL);
- g_return_val_if_fail(ete == NULL || E_IS_TABLE_EXTRAS(ete), NULL);
- g_return_val_if_fail(spec != NULL, NULL);
-
- ets = E_TREE_SCROLLED (gtk_widget_new (e_tree_scrolled_get_type (),
- "hadjustment", NULL,
- "vadjustment", NULL,
- NULL));
-
- ets = e_tree_scrolled_construct (ets, etm, ete, spec, state);
-
- return GTK_WIDGET (ets);
-}
-
-ETreeScrolled *e_tree_scrolled_construct_from_spec_file (ETreeScrolled *ets,
- ETreeModel *etm,
- ETableExtras *ete,
- const char *spec_fn,
- const char *state_fn)
-{
- g_return_val_if_fail(ets != NULL, NULL);
- g_return_val_if_fail(E_IS_TREE_SCROLLED(ets), NULL);
- g_return_val_if_fail(etm != NULL, NULL);
- g_return_val_if_fail(E_IS_TREE_MODEL(etm), NULL);
- g_return_val_if_fail(ete == NULL || E_IS_TABLE_EXTRAS(ete), NULL);
- g_return_val_if_fail(spec_fn != NULL, NULL);
-
- e_tree_construct_from_spec_file(ets->tree, etm, ete, spec_fn, state_fn);
-
- e_tree_scrolled_real_construct(ets);
-
- return ets;
-}
-
-GtkWidget *e_tree_scrolled_new_from_spec_file (ETreeModel *etm,
- ETableExtras *ete,
- const char *spec_fn,
- const char *state_fn)
-{
- ETreeScrolled *ets;
-
- g_return_val_if_fail(etm != NULL, NULL);
- g_return_val_if_fail(E_IS_TREE_MODEL(etm), NULL);
- g_return_val_if_fail(ete == NULL || E_IS_TABLE_EXTRAS(ete), NULL);
- g_return_val_if_fail(spec_fn != NULL, NULL);
-
- ets = E_TREE_SCROLLED (gtk_widget_new (e_tree_scrolled_get_type (),
- "hadjustment", NULL,
- "vadjustment", NULL,
- NULL));
- ets = e_tree_scrolled_construct_from_spec_file (ets, etm, ete, spec_fn, state_fn);
-
- return GTK_WIDGET (ets);
-}
-
-ETree *
-e_tree_scrolled_get_tree (ETreeScrolled *ets)
-{
- return ets->tree;
-}
-
-static void
-ets_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
-{
- ETreeScrolled *ets = E_TREE_SCROLLED (object);
-
- switch (prop_id){
- case PROP_TREE:
- g_value_set_object (value, ets->tree);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-/* Grab_focus handler for the scrolled ETree */
-static void
-ets_grab_focus (GtkWidget *widget)
-{
- ETreeScrolled *ets;
-
- ets = E_TREE_SCROLLED (widget);
-
- gtk_widget_grab_focus (GTK_WIDGET (ets->tree));
-}
-
-/* Focus handler for the scrolled ETree */
-static gint
-ets_focus (GtkWidget *container, GtkDirectionType direction)
-{
- ETreeScrolled *ets;
-
- ets = E_TREE_SCROLLED (container);
-
- return gtk_widget_child_focus (GTK_WIDGET (ets->tree), direction);
-}
-
-static void
-e_tree_scrolled_class_init (ETreeScrolledClass *class)
-{
- GObjectClass *object_class;
- GtkWidgetClass *widget_class;
- GtkContainerClass *container_class;
-
- object_class = (GObjectClass *) class;
- widget_class = (GtkWidgetClass *) class;
- container_class = (GtkContainerClass *) class;
-
- parent_class = g_type_class_ref (PARENT_TYPE);
-
- object_class->get_property = ets_get_property;
-
- widget_class->grab_focus = ets_grab_focus;
-
- widget_class->focus = ets_focus;
-
- g_object_class_install_property (object_class, PROP_TREE,
- g_param_spec_object ("tree",
- _( "Tree" ),
- _( "Tree" ),
- E_TREE_TYPE,
- G_PARAM_READABLE));
-}
-
-E_MAKE_TYPE(e_tree_scrolled, "ETreeScrolled", ETreeScrolled, e_tree_scrolled_class_init, e_tree_scrolled_init, PARENT_TYPE)
-
diff --git a/widgets/table/e-tree-scrolled.h b/widgets/table/e-tree-scrolled.h
deleted file mode 100644
index f861b71138..0000000000
--- a/widgets/table/e-tree-scrolled.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-tree-scrolled.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_TREE_SCROLLED_H_
-#define _E_TREE_SCROLLED_H_
-
-#include <gtk/gtkscrolledwindow.h>
-#include <gal/e-table/e-tree-model.h>
-#include <gal/e-table/e-tree.h>
-
-G_BEGIN_DECLS
-
-#define E_TREE_SCROLLED_TYPE (e_tree_scrolled_get_type ())
-#define E_TREE_SCROLLED(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TREE_SCROLLED_TYPE, ETreeScrolled))
-#define E_TREE_SCROLLED_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TREE_SCROLLED_TYPE, ETreeScrolledClass))
-#define E_IS_TREE_SCROLLED(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TREE_SCROLLED_TYPE))
-#define E_IS_TREE_SCROLLED_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TREE_SCROLLED_TYPE))
-
-typedef struct {
- GtkScrolledWindow parent;
-
- ETree *tree;
-} ETreeScrolled;
-
-typedef struct {
- GtkScrolledWindowClass parent_class;
-} ETreeScrolledClass;
-
-GType e_tree_scrolled_get_type (void);
-
-ETreeScrolled *e_tree_scrolled_construct (ETreeScrolled *ets,
- ETreeModel *etm,
- ETableExtras *ete,
- const char *spec,
- const char *state);
-GtkWidget *e_tree_scrolled_new (ETreeModel *etm,
- ETableExtras *ete,
- const char *spec,
- const char *state);
-
-ETreeScrolled *e_tree_scrolled_construct_from_spec_file (ETreeScrolled *ets,
- ETreeModel *etm,
- ETableExtras *ete,
- const char *spec_fn,
- const char *state_fn);
-GtkWidget *e_tree_scrolled_new_from_spec_file (ETreeModel *etm,
- ETableExtras *ete,
- const char *spec_fn,
- const char *state_fn);
-
-ETree *e_tree_scrolled_get_tree (ETreeScrolled *ets);
-
-G_END_DECLS
-
-#endif /* _E_TREE_SCROLLED_H_ */
diff --git a/widgets/table/e-tree-selection-model.c b/widgets/table/e-tree-selection-model.c
deleted file mode 100644
index 6d45b6257c..0000000000
--- a/widgets/table/e-tree-selection-model.c
+++ /dev/null
@@ -1,816 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-tree-selection-model.c
- * Copyright 2000, 2001, 2003 Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- * Mike Kestner <mkestner@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include "e-tree-selection-model.h"
-#include <gal/util/e-i18n.h>
-#include <gal/util/e-util.h>
-#include <gdk/gdkkeysyms.h>
-#include <gal/e-table/e-tree-table-adapter.h>
-
-#define PARENT_TYPE e_selection_model_get_type ()
-
-static ESelectionModelClass *parent_class;
-
-enum {
- PROP_0,
- PROP_CURSOR_ROW,
- PROP_CURSOR_COL,
- PROP_MODEL,
- PROP_ETTA,
-};
-
-struct ETreeSelectionModelPriv {
- ETreeTableAdapter *etta;
- ETreeModel *model;
-
- GHashTable *paths;
- ETreePath cursor_path;
- ETreePath start_path;
- gint cursor_col;
- gchar *cursor_save_id;
-
- gint tree_model_pre_change_id;
- gint tree_model_no_change_id;
- gint tree_model_node_changed_id;
- gint tree_model_node_data_changed_id;
- gint tree_model_node_col_changed_id;
- gint tree_model_node_inserted_id;
- gint tree_model_node_removed_id;
- gint tree_model_node_deleted_id;
-};
-
-static gint
-get_cursor_row (ETreeSelectionModel *etsm)
-{
- if (etsm->priv->cursor_path)
- return e_tree_table_adapter_row_of_node(etsm->priv->etta, etsm->priv->cursor_path);
-
- return -1;
-}
-
-static void
-clear_selection (ETreeSelectionModel *etsm)
-{
- g_hash_table_destroy (etsm->priv->paths);
- etsm->priv->paths = g_hash_table_new (NULL, NULL);
-}
-
-static void
-change_one_path (ETreeSelectionModel *etsm, ETreePath path, gboolean grow)
-{
- if (!path)
- return;
-
- if (grow)
- g_hash_table_insert (etsm->priv->paths, path, path);
- else if (g_hash_table_lookup (etsm->priv->paths, path))
- g_hash_table_remove (etsm->priv->paths, path);
-}
-
-static void
-select_single_path (ETreeSelectionModel *etsm, ETreePath path)
-{
- clear_selection (etsm);
- change_one_path(etsm, path, TRUE);
- etsm->priv->cursor_path = path;
- etsm->priv->start_path = NULL;
-}
-
-static void
-select_range (ETreeSelectionModel *etsm, gint start, gint end)
-{
- gint i;
-
- if (start > end) {
- i = start;
- start = end;
- end = i;
- }
-
- for (i = start; i <= end; i++) {
- ETreePath path = e_tree_table_adapter_node_at_row (etsm->priv->etta, i);
- if (path)
- g_hash_table_insert (etsm->priv->paths, path, path);
- }
-}
-
-static void
-free_id (ETreeSelectionModel *etsm)
-{
- g_free (etsm->priv->cursor_save_id);
- etsm->priv->cursor_save_id = NULL;
-}
-
-static void
-restore_cursor (ETreeSelectionModel *etsm, ETreeModel *etm)
-{
- clear_selection (etsm);
- etsm->priv->cursor_path = NULL;
-
- if (etsm->priv->cursor_save_id) {
- etsm->priv->cursor_path = e_tree_model_get_node_by_id (etm, etsm->priv->cursor_save_id);
- if (etsm->priv->cursor_path != NULL && etsm->priv->cursor_col == -1)
- etsm->priv->cursor_col = 0;
-
- select_single_path(etsm, etsm->priv->cursor_path);
- }
-
- e_selection_model_selection_changed(E_SELECTION_MODEL(etsm));
-
- if (etsm->priv->cursor_path) {
- gint cursor_row = get_cursor_row (etsm);
- e_selection_model_cursor_changed(E_SELECTION_MODEL(etsm), cursor_row, etsm->priv->cursor_col);
- } else {
- e_selection_model_cursor_changed(E_SELECTION_MODEL(etsm), -1, -1);
- e_selection_model_cursor_activated(E_SELECTION_MODEL(etsm), -1, -1);
-
- }
-
- free_id (etsm);
-}
-
-static void
-etsm_pre_change (ETreeModel *etm, ETreeSelectionModel *etsm)
-{
- g_free (etsm->priv->cursor_save_id);
- etsm->priv->cursor_save_id = NULL;
-
- if (e_tree_model_has_get_node_by_id (etm) && e_tree_model_has_save_id (etm) && etsm->priv->cursor_path) {
- etsm->priv->cursor_save_id = e_tree_model_get_save_id (etm, etsm->priv->cursor_path);
- }
-}
-
-static void
-etsm_no_change (ETreeModel *etm, ETreeSelectionModel *etsm)
-{
- free_id (etsm);
-}
-
-static void
-etsm_node_changed (ETreeModel *etm, ETreePath node, ETreeSelectionModel *etsm)
-{
- restore_cursor (etsm, etm);
-}
-
-static void
-etsm_node_data_changed (ETreeModel *etm, ETreePath node, ETreeSelectionModel *etsm)
-{
- free_id (etsm);
-}
-
-static void
-etsm_node_col_changed (ETreeModel *etm, ETreePath node, int col, ETreeSelectionModel *etsm)
-{
- free_id (etsm);
-}
-
-static void
-etsm_node_inserted (ETreeModel *etm, ETreePath parent, ETreePath child, ETreeSelectionModel *etsm)
-{
- restore_cursor (etsm, etm);
-}
-
-static void
-etsm_node_removed (ETreeModel *etm, ETreePath parent, ETreePath child, int old_position, ETreeSelectionModel *etsm)
-{
- restore_cursor (etsm, etm);
-}
-
-static void
-etsm_node_deleted (ETreeModel *etm, ETreePath child, ETreeSelectionModel *etsm)
-{
- restore_cursor (etsm, etm);
-}
-
-
-static void
-add_model(ETreeSelectionModel *etsm, ETreeModel *model)
-{
- ETreeSelectionModelPriv *priv = etsm->priv;
-
- priv->model = model;
-
- if (!priv->model)
- return;
-
- g_object_ref(priv->model);
- priv->tree_model_pre_change_id = g_signal_connect_after (G_OBJECT (priv->model), "pre_change",
- G_CALLBACK (etsm_pre_change), etsm);
- priv->tree_model_no_change_id = g_signal_connect_after (G_OBJECT (priv->model), "no_change",
- G_CALLBACK (etsm_no_change), etsm);
- priv->tree_model_node_changed_id = g_signal_connect_after (G_OBJECT (priv->model), "node_changed",
- G_CALLBACK (etsm_node_changed), etsm);
- priv->tree_model_node_data_changed_id = g_signal_connect_after (G_OBJECT (priv->model), "node_data_changed",
- G_CALLBACK (etsm_node_data_changed), etsm);
- priv->tree_model_node_col_changed_id = g_signal_connect_after (G_OBJECT (priv->model), "node_col_changed",
- G_CALLBACK (etsm_node_col_changed), etsm);
- priv->tree_model_node_inserted_id = g_signal_connect_after (G_OBJECT (priv->model), "node_inserted",
- G_CALLBACK (etsm_node_inserted), etsm);
- priv->tree_model_node_removed_id = g_signal_connect_after (G_OBJECT (priv->model), "node_removed",
- G_CALLBACK (etsm_node_removed), etsm);
- priv->tree_model_node_deleted_id = g_signal_connect_after (G_OBJECT (priv->model), "node_deleted",
- G_CALLBACK (etsm_node_deleted), etsm);
-}
-
-static void
-drop_model(ETreeSelectionModel *etsm)
-{
- ETreeSelectionModelPriv *priv = etsm->priv;
-
- if (!priv->model)
- return;
-
- g_signal_handler_disconnect (G_OBJECT (priv->model),
- priv->tree_model_pre_change_id);
- g_signal_handler_disconnect (G_OBJECT (priv->model),
- priv->tree_model_no_change_id);
- g_signal_handler_disconnect (G_OBJECT (priv->model),
- priv->tree_model_node_changed_id);
- g_signal_handler_disconnect (G_OBJECT (priv->model),
- priv->tree_model_node_data_changed_id);
- g_signal_handler_disconnect (G_OBJECT (priv->model),
- priv->tree_model_node_col_changed_id);
- g_signal_handler_disconnect (G_OBJECT (priv->model),
- priv->tree_model_node_inserted_id);
- g_signal_handler_disconnect (G_OBJECT (priv->model),
- priv->tree_model_node_removed_id);
- g_signal_handler_disconnect (G_OBJECT (priv->model),
- priv->tree_model_node_deleted_id);
-
- g_object_unref (priv->model);
- priv->model = NULL;
-
- priv->tree_model_pre_change_id = 0;
- priv->tree_model_no_change_id = 0;
- priv->tree_model_node_changed_id = 0;
- priv->tree_model_node_data_changed_id = 0;
- priv->tree_model_node_col_changed_id = 0;
- priv->tree_model_node_inserted_id = 0;
- priv->tree_model_node_removed_id = 0;
- priv->tree_model_node_deleted_id = 0;
-}
-
-static void
-etsm_dispose (GObject *object)
-{
- ETreeSelectionModel *etsm = E_TREE_SELECTION_MODEL (object);
-
- drop_model(etsm);
-
- if (G_OBJECT_CLASS (parent_class)->dispose)
- (* G_OBJECT_CLASS (parent_class)->dispose) (object);
-}
-
-static void
-etsm_finalize (GObject *object)
-{
- ETreeSelectionModel *etsm = E_TREE_SELECTION_MODEL (object);
-
- if (etsm->priv) {
- clear_selection (etsm);
- g_hash_table_destroy (etsm->priv->paths);
- g_free (etsm->priv);
- etsm->priv = NULL;
- }
-
- if (G_OBJECT_CLASS (parent_class)->finalize)
- (* G_OBJECT_CLASS (parent_class)->finalize) (object);
-}
-
-static void
-etsm_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
-{
- ETreeSelectionModel *etsm = E_TREE_SELECTION_MODEL (object);
-
- switch (prop_id){
- case PROP_CURSOR_ROW:
- g_value_set_int (value, get_cursor_row(etsm));
- break;
-
- case PROP_CURSOR_COL:
- g_value_set_int (value, etsm->priv->cursor_col);
- break;
-
- case PROP_MODEL:
- g_value_set_object (value, etsm->priv->model);
- break;
-
- case PROP_ETTA:
- g_value_set_object (value, etsm->priv->etta);
- break;
- }
-}
-
-static void
-etsm_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
-{
- ESelectionModel *esm = E_SELECTION_MODEL (object);
- ETreeSelectionModel *etsm = E_TREE_SELECTION_MODEL (object);
-
- switch (prop_id){
- case PROP_CURSOR_ROW:
- e_selection_model_do_something(esm, g_value_get_int (value), etsm->priv->cursor_col, 0);
- break;
-
- case PROP_CURSOR_COL:
- e_selection_model_do_something(esm, get_cursor_row(etsm), g_value_get_int(value), 0);
- break;
-
- case PROP_MODEL:
- drop_model(etsm);
- add_model(etsm, E_TREE_MODEL (g_value_get_object(value)));
- break;
-
- case PROP_ETTA:
- etsm->priv->etta = E_TREE_TABLE_ADAPTER (g_value_get_object (value));
- break;
- }
-}
-
-static gboolean
-etsm_is_path_selected (ETreeSelectionModel *etsm, ETreePath path)
-{
- if (path && g_hash_table_lookup (etsm->priv->paths, path))
- return TRUE;
-
- return FALSE;
-}
-
-/**
- * e_selection_model_is_row_selected
- * @selection: #ESelectionModel to check
- * @n: The row to check
- *
- * This routine calculates whether the given row is selected.
- *
- * Returns: %TRUE if the given row is selected
- */
-static gboolean
-etsm_is_row_selected (ESelectionModel *selection,
- gint row)
-{
- ETreeSelectionModel *etsm = E_TREE_SELECTION_MODEL(selection);
- ETreePath path;
-
- g_return_val_if_fail(row < e_table_model_row_count(E_TABLE_MODEL(etsm->priv->etta)), FALSE);
- g_return_val_if_fail(row >= 0, FALSE);
- g_return_val_if_fail(etsm != NULL, FALSE);
-
- path = e_tree_table_adapter_node_at_row(etsm->priv->etta, row);
- return etsm_is_path_selected (etsm, path);
-}
-
-
-typedef struct {
- ETreeSelectionModel *etsm;
- EForeachFunc callback;
- gpointer closure;
-} ModelAndCallback;
-
-static void
-etsm_row_foreach_cb (gpointer key, gpointer value, gpointer user_data)
-{
- ETreePath path = key;
- ModelAndCallback *mac = user_data;
- int row = e_tree_table_adapter_row_of_node(mac->etsm->priv->etta, path);
- if (row >= 0)
- mac->callback(row, mac->closure);
-}
-
-/**
- * e_selection_model_foreach
- * @selection: #ESelectionModel to traverse
- * @callback: The callback function to call back.
- * @closure: The closure
- *
- * This routine calls the given callback function once for each
- * selected row, passing closure as the closure.
- */
-static void
-etsm_foreach (ESelectionModel *selection,
- EForeachFunc callback,
- gpointer closure)
-{
- ETreeSelectionModel *etsm = E_TREE_SELECTION_MODEL(selection);
- ModelAndCallback mac;
-
- mac.etsm = etsm;
- mac.callback = callback;
- mac.closure = closure;
-
- g_hash_table_foreach(etsm->priv->paths, etsm_row_foreach_cb, &mac);
-}
-
-/**
- * e_selection_model_clear
- * @selection: #ESelectionModel to clear
- *
- * This routine clears the selection to no rows selected.
- */
-static void
-etsm_clear(ESelectionModel *selection)
-{
- ETreeSelectionModel *etsm = E_TREE_SELECTION_MODEL(selection);
-
- clear_selection (etsm);
-
- etsm->priv->cursor_path = NULL;
- e_selection_model_selection_changed(E_SELECTION_MODEL(etsm));
- e_selection_model_cursor_changed(E_SELECTION_MODEL(etsm), -1, -1);
-}
-
-/**
- * e_selection_model_selected_count
- * @selection: #ESelectionModel to count
- *
- * This routine calculates the number of rows selected.
- *
- * Returns: The number of rows selected in the given model.
- */
-static gint
-etsm_selected_count (ESelectionModel *selection)
-{
- ETreeSelectionModel *etsm = E_TREE_SELECTION_MODEL(selection);
-
- return g_hash_table_size (etsm->priv->paths);
-}
-
-static int
-etsm_row_count (ESelectionModel *selection)
-{
- ETreeSelectionModel *etsm = E_TREE_SELECTION_MODEL(selection);
- return e_table_model_row_count(E_TABLE_MODEL(etsm->priv->etta));
-}
-
-/**
- * e_selection_model_select_all
- * @selection: #ESelectionModel to select all
- *
- * This routine selects all the rows in the given
- * #ESelectionModel.
- */
-static void
-etsm_select_all (ESelectionModel *selection)
-{
- ETreeSelectionModel *etsm = E_TREE_SELECTION_MODEL(selection);
- ETreePath root;
-
- root = e_tree_model_get_root(etsm->priv->model);
- if (root == NULL)
- return;
-
- clear_selection (etsm);
- select_range (etsm, 0, etsm_row_count (selection) - 1);
-
- if (etsm->priv->cursor_path == NULL)
- etsm->priv->cursor_path = e_tree_table_adapter_node_at_row(etsm->priv->etta, 0);
-
- e_selection_model_selection_changed(E_SELECTION_MODEL(etsm));
- e_selection_model_cursor_changed(E_SELECTION_MODEL(etsm), get_cursor_row(etsm), etsm->priv->cursor_col);
-}
-
-/**
- * e_selection_model_invert_selection
- * @selection: #ESelectionModel to invert
- *
- * This routine inverts all the rows in the given
- * #ESelectionModel.
- */
-static void
-etsm_invert_selection (ESelectionModel *selection)
-{
- ETreeSelectionModel *etsm = E_TREE_SELECTION_MODEL(selection);
- gint count = etsm_row_count (selection);
- gint i;
-
- for (i = 0; i < count; i++) {
- ETreePath path = e_tree_table_adapter_node_at_row (etsm->priv->etta, i);
- if (!path)
- continue;
- if (g_hash_table_lookup (etsm->priv->paths, path))
- g_hash_table_remove (etsm->priv->paths, path);
- else
- g_hash_table_insert (etsm->priv->paths, path, path);
- }
-
- etsm->priv->cursor_col = -1;
- etsm->priv->cursor_path = NULL;
- etsm->priv->start_path = NULL;
- e_selection_model_selection_changed(E_SELECTION_MODEL(etsm));
- e_selection_model_cursor_changed(E_SELECTION_MODEL(etsm), -1, -1);
-}
-
-static void
-etsm_change_one_row(ESelectionModel *selection, int row, gboolean grow)
-{
- ETreeSelectionModel *etsm = E_TREE_SELECTION_MODEL(selection);
- ETreePath path;
-
- g_return_if_fail(row < e_table_model_row_count(E_TABLE_MODEL(etsm->priv->etta)));
- g_return_if_fail(row >= 0);
- g_return_if_fail(selection != NULL);
-
- path = e_tree_table_adapter_node_at_row(etsm->priv->etta, row);
-
- if (!path)
- return;
-
- change_one_path (etsm, path, grow);
-}
-
-static void
-etsm_change_cursor (ESelectionModel *selection, int row, int col)
-{
- ETreeSelectionModel *etsm;
-
- g_return_if_fail(selection != NULL);
- g_return_if_fail(E_IS_SELECTION_MODEL(selection));
-
- etsm = E_TREE_SELECTION_MODEL(selection);
-
- if (row == -1) {
- etsm->priv->cursor_path = NULL;
- } else {
- etsm->priv->cursor_path = e_tree_table_adapter_node_at_row(etsm->priv->etta, row);
- }
- etsm->priv->cursor_col = col;
-}
-
-static gint
-etsm_cursor_row (ESelectionModel *selection)
-{
- return get_cursor_row(E_TREE_SELECTION_MODEL(selection));
-}
-
-static gint
-etsm_cursor_col (ESelectionModel *selection)
-{
- ETreeSelectionModel *etsm = E_TREE_SELECTION_MODEL(selection);
- return etsm->priv->cursor_col;
-}
-
-static void
-etsm_select_single_row (ESelectionModel *selection, gint row)
-{
- ETreeSelectionModel *etsm = E_TREE_SELECTION_MODEL(selection);
- ETreePath path = e_tree_table_adapter_node_at_row (etsm->priv->etta, row);
-
- g_return_if_fail (path != NULL);
-
- select_single_path (etsm, path);
-
- e_selection_model_selection_changed(E_SELECTION_MODEL(etsm));
-}
-
-static void
-etsm_toggle_single_row (ESelectionModel *selection, gint row)
-{
- ETreeSelectionModel *etsm = E_TREE_SELECTION_MODEL(selection);
- ETreePath path = e_tree_table_adapter_node_at_row(etsm->priv->etta, row);
-
- g_return_if_fail (path);
-
- if (g_hash_table_lookup (etsm->priv->paths, path))
- g_hash_table_remove (etsm->priv->paths, path);
- else
- g_hash_table_insert (etsm->priv->paths, path, path);
-
- etsm->priv->start_path = NULL;
- e_selection_model_selection_changed(E_SELECTION_MODEL(etsm));
-}
-
-static void
-etsm_real_move_selection_end (ETreeSelectionModel *etsm, gint row)
-{
- ETreePath end_path = e_tree_table_adapter_node_at_row (etsm->priv->etta, row);
- gint start;
-
- g_return_if_fail (end_path);
-
- start = e_tree_table_adapter_row_of_node(etsm->priv->etta, etsm->priv->start_path);
- clear_selection (etsm);
- select_range (etsm, start, row);
-}
-
-static void
-etsm_move_selection_end (ESelectionModel *selection, gint row)
-{
- ETreeSelectionModel *etsm = E_TREE_SELECTION_MODEL(selection);
-
- g_return_if_fail (etsm->priv->cursor_path);
-
- etsm_real_move_selection_end (etsm, row);
- e_selection_model_selection_changed(E_SELECTION_MODEL(selection));
-}
-
-static void
-etsm_set_selection_end (ESelectionModel *selection, gint row)
-{
- ETreeSelectionModel *etsm = E_TREE_SELECTION_MODEL(selection);
-
- g_return_if_fail (etsm->priv->cursor_path);
-
- if (!etsm->priv->start_path)
- etsm->priv->start_path = etsm->priv->cursor_path;
- etsm_real_move_selection_end(etsm, row);
- e_selection_model_selection_changed(E_SELECTION_MODEL(etsm));
-}
-
-struct foreach_path_t {
- ETreeForeachFunc callback;
- gpointer closure;
-};
-
-static void
-foreach_path (gpointer key, gpointer value, gpointer data)
-{
- ETreePath path = key;
- struct foreach_path_t *c = data;
- c->callback (path, c->closure);
-}
-
-void
-e_tree_selection_model_foreach (ETreeSelectionModel *etsm, ETreeForeachFunc callback, gpointer closure)
-{
- if (etsm->priv->paths) {
- struct foreach_path_t c;
- c.callback = callback;
- c.closure = closure;
- g_hash_table_foreach(etsm->priv->paths, foreach_path, &c);
- return;
- }
-}
-
-void
-e_tree_selection_model_select_single_path (ETreeSelectionModel *etsm, ETreePath path)
-{
- select_single_path (etsm, path);
-
- e_selection_model_selection_changed(E_SELECTION_MODEL(etsm));
-}
-
-void
-e_tree_selection_model_select_paths (ETreeSelectionModel *etsm, GPtrArray *paths)
-{
- ETreePath path;
- int i;
-
- for (i=0;i<paths->len;i++) {
- path = paths->pdata[i];
- change_one_path(etsm, path, TRUE);
- }
-
- e_selection_model_selection_changed(E_SELECTION_MODEL(etsm));
-}
-
-void
-e_tree_selection_model_add_to_selection (ETreeSelectionModel *etsm, ETreePath path)
-{
- change_one_path(etsm, path, TRUE);
-
- e_selection_model_selection_changed(E_SELECTION_MODEL(etsm));
-}
-
-void
-e_tree_selection_model_change_cursor (ETreeSelectionModel *etsm, ETreePath path)
-{
- int row;
-
- etsm->priv->cursor_path = path;
-
- row = get_cursor_row(etsm);
-
- E_SELECTION_MODEL (etsm)->old_selection = -1;
-
- e_selection_model_cursor_changed(E_SELECTION_MODEL(etsm), row, etsm->priv->cursor_col);
- e_selection_model_cursor_activated(E_SELECTION_MODEL(etsm), row, etsm->priv->cursor_col);
-}
-
-ETreePath
-e_tree_selection_model_get_cursor (ETreeSelectionModel *etsm)
-{
- return etsm->priv->cursor_path;
-}
-
-
-static void
-e_tree_selection_model_init (ETreeSelectionModel *etsm)
-{
- ETreeSelectionModelPriv *priv;
- priv = g_new(ETreeSelectionModelPriv, 1);
- etsm->priv = priv;
-
- priv->etta = NULL;
- priv->model = NULL;
-
- priv->paths = g_hash_table_new (NULL, NULL);
-
- priv->cursor_path = NULL;
- priv->start_path = NULL;
- priv->cursor_col = -1;
- priv->cursor_save_id = NULL;
-
- priv->tree_model_pre_change_id = 0;
- priv->tree_model_no_change_id = 0;
- priv->tree_model_node_changed_id = 0;
- priv->tree_model_node_data_changed_id = 0;
- priv->tree_model_node_col_changed_id = 0;
- priv->tree_model_node_inserted_id = 0;
- priv->tree_model_node_removed_id = 0;
- priv->tree_model_node_deleted_id = 0;
-}
-
-static void
-e_tree_selection_model_class_init (ETreeSelectionModelClass *klass)
-{
- GObjectClass *object_class;
- ESelectionModelClass *esm_class;
-
- parent_class = g_type_class_ref (PARENT_TYPE);
-
- object_class = G_OBJECT_CLASS(klass);
- esm_class = E_SELECTION_MODEL_CLASS(klass);
-
- object_class->dispose = etsm_dispose;
- object_class->finalize = etsm_finalize;
- object_class->get_property = etsm_get_property;
- object_class->set_property = etsm_set_property;
-
- esm_class->is_row_selected = etsm_is_row_selected ;
- esm_class->foreach = etsm_foreach ;
- esm_class->clear = etsm_clear ;
- esm_class->selected_count = etsm_selected_count ;
- esm_class->select_all = etsm_select_all ;
- esm_class->invert_selection = etsm_invert_selection ;
- esm_class->row_count = etsm_row_count ;
-
- esm_class->change_one_row = etsm_change_one_row ;
- esm_class->change_cursor = etsm_change_cursor ;
- esm_class->cursor_row = etsm_cursor_row ;
- esm_class->cursor_col = etsm_cursor_col ;
-
- esm_class->select_single_row = etsm_select_single_row ;
- esm_class->toggle_single_row = etsm_toggle_single_row ;
- esm_class->move_selection_end = etsm_move_selection_end ;
- esm_class->set_selection_end = etsm_set_selection_end ;
-
- g_object_class_install_property (object_class, PROP_CURSOR_ROW,
- g_param_spec_int ("cursor_row",
- _("Cursor Row"),
- /*_( */"XXX blurb" /*)*/,
- 0, G_MAXINT, 0,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class, PROP_CURSOR_COL,
- g_param_spec_int ("cursor_col",
- _("Cursor Column"),
- /*_( */"XXX blurb" /*)*/,
- 0, G_MAXINT, 0,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class, PROP_MODEL,
- g_param_spec_object ("model",
- _("Model"),
- "XXX blurb",
- E_TREE_MODEL_TYPE,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class, PROP_ETTA,
- g_param_spec_object ("etta",
- "ETTA",
- "XXX blurb",
- E_TREE_TABLE_ADAPTER_TYPE,
- G_PARAM_READWRITE));
-
-}
-
-ESelectionModel *
-e_tree_selection_model_new (void)
-{
- return g_object_new (E_TREE_SELECTION_MODEL_TYPE, NULL);
-}
-
-E_MAKE_TYPE(e_tree_selection_model, "ETreeSelectionModel", ETreeSelectionModel,
- e_tree_selection_model_class_init, e_tree_selection_model_init, PARENT_TYPE)
diff --git a/widgets/table/e-tree-selection-model.h b/widgets/table/e-tree-selection-model.h
deleted file mode 100644
index 44ebf08f31..0000000000
--- a/widgets/table/e-tree-selection-model.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-tree-selection-model.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_TREE_SELECTION_MODEL_H_
-#define _E_TREE_SELECTION_MODEL_H_
-
-#include <gdk/gdktypes.h>
-#include <gtk/gtkobject.h>
-#include <gal/util/e-sorter.h>
-#include <gal/widgets/e-selection-model.h>
-#include <gal/e-table/e-tree-model.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-typedef void (*ETreeForeachFunc) (ETreePath path,
- gpointer closure);
-
-typedef struct ETreeSelectionModelPriv ETreeSelectionModelPriv;
-
-#define E_TREE_SELECTION_MODEL_TYPE (e_tree_selection_model_get_type ())
-#define E_TREE_SELECTION_MODEL(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TREE_SELECTION_MODEL_TYPE, ETreeSelectionModel))
-#define E_TREE_SELECTION_MODEL_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TREE_SELECTION_MODEL_TYPE, ETreeSelectionModelClass))
-#define E_IS_TREE_SELECTION_MODEL(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TREE_SELECTION_MODEL_TYPE))
-#define E_IS_TREE_SELECTION_MODEL_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TREE_SELECTION_MODEL_TYPE))
-
-typedef struct {
- ESelectionModel base;
-
- ETreeSelectionModelPriv *priv;
-} ETreeSelectionModel;
-
-typedef struct {
- ESelectionModelClass parent_class;
-} ETreeSelectionModelClass;
-
-
-GType e_tree_selection_model_get_type (void);
-ESelectionModel *e_tree_selection_model_new (void);
-void e_tree_selection_model_foreach (ETreeSelectionModel *etsm,
- ETreeForeachFunc callback,
- gpointer closure);
-void e_tree_selection_model_select_single_path (ETreeSelectionModel *etsm,
- ETreePath path);
-void e_tree_selection_model_select_paths (ETreeSelectionModel *etsm, GPtrArray *paths);
-
-void e_tree_selection_model_add_to_selection (ETreeSelectionModel *etsm,
- ETreePath path);
-void e_tree_selection_model_change_cursor (ETreeSelectionModel *etsm,
- ETreePath path);
-ETreePath e_tree_selection_model_get_cursor (ETreeSelectionModel *etsm);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-
-#endif /* _E_TREE_SELECTION_MODEL_H_ */
diff --git a/widgets/table/e-tree-simple.c b/widgets/table/e-tree-simple.c
deleted file mode 100644
index e8dff1e05a..0000000000
--- a/widgets/table/e-tree-simple.c
+++ /dev/null
@@ -1,208 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-tree-simple.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include "gal/util/e-util.h"
-#include "e-tree-simple.h"
-
-static int
-simple_column_count (ETableModel *etm)
-{
- ETreeSimple *simple = E_TREE_SIMPLE(etm);
-
- if (simple->col_count)
- return simple->col_count (etm, simple->model_data);
- else
- return 0;
-}
-
-/* The default for simple_duplicate_value is to return the raw value. */
-static void *
-simple_duplicate_value (ETableModel *etm, int col, const void *value)
-{
- ETreeSimple *simple = E_TREE_SIMPLE(etm);
-
- if (simple->duplicate_value)
- return simple->duplicate_value (etm, col, value, simple->model_data);
- else
- return (void *)value;
-}
-
-static void
-simple_free_value (ETableModel *etm, int col, void *value)
-{
- ETreeSimple *simple = E_TREE_SIMPLE(etm);
-
- if (simple->free_value)
- simple->free_value (etm, col, value, simple->model_data);
-}
-
-static void *
-simple_initialize_value (ETableModel *etm, int col)
-{
- ETreeSimple *simple = E_TREE_SIMPLE(etm);
-
- if (simple->initialize_value)
- return simple->initialize_value (etm, col, simple->model_data);
- else
- return NULL;
-}
-
-static gboolean
-simple_value_is_empty (ETableModel *etm, int col, const void *value)
-{
- ETreeSimple *simple = E_TREE_SIMPLE(etm);
-
- if (simple->value_is_empty)
- return simple->value_is_empty (etm, col, value, simple->model_data);
- else
- return FALSE;
-}
-
-static char *
-simple_value_to_string (ETableModel *etm, int col, const void *value)
-{
- ETreeSimple *simple = E_TREE_SIMPLE(etm);
-
- if (simple->value_to_string)
- return simple->value_to_string (etm, col, value, simple->model_data);
- else
- return g_strdup ("");
-}
-
-static void *
-simple_value_at (ETreeModel *etm, ETreePath *node, int col)
-{
- ETreeSimple *simple = E_TREE_SIMPLE(etm);
-
- return simple->value_at (etm, node, col, simple->model_data);
-}
-
-static GdkPixbuf *
-simple_icon_at (ETreeModel *etm, ETreePath *node)
-{
- ETreeSimple *simple = E_TREE_SIMPLE(etm);
-
- return simple->icon_at (etm, node, simple->model_data);
-}
-
-static void
-simple_set_value_at (ETreeModel *etm, ETreePath *node, int col, const void *val)
-{
- ETreeSimple *simple = E_TREE_SIMPLE(etm);
-
- simple->set_value_at (etm, node, col, val, simple->model_data);
-}
-
-static gboolean
-simple_is_editable (ETreeModel *etm, ETreePath *node, int col)
-{
- ETreeSimple *simple = E_TREE_SIMPLE(etm);
-
- return simple->is_editable (etm, node, col, simple->model_data);
-}
-
-static void
-e_tree_simple_class_init (GObjectClass *object_class)
-{
- ETreeModelClass *model_class = (ETreeModelClass *) object_class;
- ETableModelClass *table_model_class = (ETableModelClass *) object_class;
-
- table_model_class->column_count = simple_column_count;
- table_model_class->duplicate_value = simple_duplicate_value;
- table_model_class->free_value = simple_free_value;
- table_model_class->initialize_value = simple_initialize_value;
- table_model_class->value_is_empty = simple_value_is_empty;
- table_model_class->value_to_string = simple_value_to_string;
-
- model_class ->icon_at = simple_icon_at;
- model_class ->value_at = simple_value_at;
- model_class ->set_value_at = simple_set_value_at;
- model_class ->is_editable = simple_is_editable;
-}
-
-E_MAKE_TYPE(e_tree_simple, "ETreeSimple", ETreeSimple, e_tree_simple_class_init, NULL, E_TREE_MODEL_TYPE)
-
-/**
- * e_tree_simple_new:
- * @col_count:
- * @duplicate_value:
- * @free_value:
- * @initialize_value:
- * @value_is_empty:
- * @value_to_string:
- * @icon_at:
- * @value_at:
- * @set_value_at:
- * @is_editable:
- * @model_data:
- *
- * This initializes a new ETreeSimpleModel object. ETreeSimpleModel is
- * an implementaiton of the abstract class ETreeModel. The ETreeSimpleModel
- * is designed to allow people to easily create ETreeModels without having
- * to create a new GtkType derived from ETreeModel every time they need one.
- *
- * Instead, ETreeSimpleModel uses a setup based in callback functions, every
- * callback function signature mimics the signature of each ETreeModel method
- * and passes the extra @data pointer to each one of the method to provide them
- * with any context they might want to use.
- *
- * ETreeSimple is to ETreeModel as ETableSimple is to ETableModel.
- *
- * Return value: An ETreeSimple object (which is also an ETreeModel
- * object).
- **/
-ETreeModel *
-e_tree_simple_new (ETableSimpleColumnCountFn col_count,
- ETableSimpleDuplicateValueFn duplicate_value,
- ETableSimpleFreeValueFn free_value,
- ETableSimpleInitializeValueFn initialize_value,
- ETableSimpleValueIsEmptyFn value_is_empty,
- ETableSimpleValueToStringFn value_to_string,
-
- ETreeSimpleIconAtFn icon_at,
- ETreeSimpleValueAtFn value_at,
- ETreeSimpleSetValueAtFn set_value_at,
- ETreeSimpleIsEditableFn is_editable,
-
- gpointer model_data)
-{
- ETreeSimple *etg = g_object_new (E_TREE_SIMPLE_TYPE, NULL);
-
- etg->col_count = col_count;
- etg->duplicate_value = duplicate_value;
- etg->free_value = free_value;
- etg->initialize_value = initialize_value;
- etg->value_is_empty = value_is_empty;
- etg->value_to_string = value_to_string;
-
- etg->icon_at = icon_at;
- etg->value_at = value_at;
- etg->set_value_at = set_value_at;
- etg->is_editable = is_editable;
-
- etg->model_data = model_data;
-
- return (ETreeModel*)etg;
-}
-
diff --git a/widgets/table/e-tree-simple.h b/widgets/table/e-tree-simple.h
deleted file mode 100644
index f9980c9544..0000000000
--- a/widgets/table/e-tree-simple.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-tree-simple.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_TREE_SIMPLE_H_
-#define _E_TREE_SIMPLE_H_
-
-#include <gal/e-table/e-tree-model.h>
-#include <gal/e-table/e-table-simple.h>
-
-G_BEGIN_DECLS
-
-#define E_TREE_SIMPLE_TYPE (e_tree_simple_get_type ())
-#define E_TREE_SIMPLE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TREE_SIMPLE_TYPE, ETreeSimple))
-#define E_TREE_SIMPLE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TREE_SIMPLE_TYPE, ETreeSimpleClass))
-#define E_IS_TREE_SIMPLE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TREE_SIMPLE_TYPE))
-#define E_IS_TREE_SIMPLE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TREE_SIMPLE_TYPE))
-#define E_TREE_SIMPLE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), E_TREE_SIMPLE_TYPE, ETreeSimpleClass))
-
-
-typedef GdkPixbuf* (*ETreeSimpleIconAtFn) (ETreeModel *etree, ETreePath *path, void *model_data);
-typedef void* (*ETreeSimpleValueAtFn) (ETreeModel *etree, ETreePath *path, int col, void *model_data);
-typedef void (*ETreeSimpleSetValueAtFn) (ETreeModel *etree, ETreePath *path, int col, const void *val, void *model_data);
-typedef gboolean (*ETreeSimpleIsEditableFn) (ETreeModel *etree, ETreePath *path, int col, void *model_data);
-
-typedef struct {
- ETreeModel parent;
-
- /* Table methods */
- ETableSimpleColumnCountFn col_count;
- ETableSimpleDuplicateValueFn duplicate_value;
- ETableSimpleFreeValueFn free_value;
- ETableSimpleInitializeValueFn initialize_value;
- ETableSimpleValueIsEmptyFn value_is_empty;
- ETableSimpleValueToStringFn value_to_string;
-
- /* Tree methods */
- ETreeSimpleIconAtFn icon_at;
- ETreeSimpleValueAtFn value_at;
- ETreeSimpleSetValueAtFn set_value_at;
- ETreeSimpleIsEditableFn is_editable;
-
- gpointer model_data;
-} ETreeSimple;
-
-typedef struct {
- ETreeModelClass parent_class;
-} ETreeSimpleClass;
-
-GType e_tree_simple_get_type (void);
-
-ETreeModel *e_tree_simple_new (ETableSimpleColumnCountFn col_count,
- ETableSimpleDuplicateValueFn duplicate_value,
- ETableSimpleFreeValueFn free_value,
- ETableSimpleInitializeValueFn initialize_value,
- ETableSimpleValueIsEmptyFn value_is_empty,
- ETableSimpleValueToStringFn value_to_string,
- ETreeSimpleIconAtFn icon_at,
- ETreeSimpleValueAtFn value_at,
- ETreeSimpleSetValueAtFn set_value_at,
- ETreeSimpleIsEditableFn is_editable,
- gpointer model_data);
-
-G_END_DECLS
-
-#endif /* _E_TREE_SIMPLE_H_ */
diff --git a/widgets/table/e-tree-sorted-variable.c b/widgets/table/e-tree-sorted-variable.c
deleted file mode 100644
index bb73b8b776..0000000000
--- a/widgets/table/e-tree-sorted-variable.c
+++ /dev/null
@@ -1,477 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-tree-sorted-variable.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <stdlib.h>
-#include <string.h>
-#include "gal/util/e-util.h"
-#include "e-tree-sorted-variable.h"
-
-#define d(x)
-
-#define INCREMENT_AMOUNT 100
-
-/* maximum insertions between an idle event that we will do without scheduling an idle sort */
-#define ETSV_INSERT_MAX (4)
-
-static ETreeModelClass *etsv_parent_class;
-
-struct ETreePath {
- GNode node;
-};
-
-struct ETreeSortedVariablePrivate {
- GNode *root;
-};
-
-static void etsv_proxy_model_changed (ETableModel *etm, ETreeSortedVariable *etsv);
-#if 0
-static void etsv_proxy_model_row_changed (ETableModel *etm, int row, ETreeSortedVariable *etsv);
-static void etsv_proxy_model_cell_changed (ETableModel *etm, int col, int row, ETreeSortedVariable *etsv);
-#endif
-static void etsv_sort_info_changed (ETableSortInfo *info, ETreeSortedVariable *etsv);
-static void etsv_sort (ETreeSortedVariable *etsv);
-static void etsv_add (ETreeSortedVariable *etsv, gint row);
-static void etsv_add_all (ETreeSortedVariable *etsv);
-
-static void
-etsv_dispose (GObject *object)
-{
- ETreeSortedVariable *etsv = E_TREE_SORTED_VARIABLE (object);
-
- if (etsv->table_model_changed_id)
- g_signal_handler_disconnect (G_OBJECT (etss->source),
- etsv->table_model_changed_id);
- etsv->table_model_changed_id = 0;
-
-#if 0
- g_signal_handler_disconnect (etss->source,
- etsv->table_model_row_changed_id);
- g_signal_handler_disconnect (etss->source,
- etsv->table_model_cell_changed_id);
-
- etsv->table_model_row_changed_id = 0;
- etsv->table_model_cell_changed_id = 0;
-#endif
- if (etsv->sort_info_changed_id)
- g_signal_handler_disconnect (etsv->sort_info,
- etsv->sort_info_changed_id);
- etsv->sort_info_changed_id = 0;
-
- if (etsv->sort_idle_id)
- g_source_remove(etsv->sort_idle_id);
- etsv->sort_idle_id = 0;
-
- if (etsv->insert_idle_id)
- g_source_remove(etsv->insert_idle_id);
- etsv->insert_idle_id = 0;
-
- if (etsv->sort_info)
- g_object_unref(etsv->sort_info);
- etsv->sort_info = NULL;
-
- if (etsv->full_header)
- g_object_unref(etsv->full_header);
- etsv->full_header = NULL;
-
- G_OBJECT_CLASS (etsv_parent_class)->dispose (object);
-}
-
-static void
-etsv_class_init (GObjectClass *object_class)
-{
- ETreeSortedVariableClass *etsv_class = E_TREE_MODEL_CLASS(object_class);
-
- etsv_parent_class = g_type_class_peek_parent (object_class);
-
- object_class->dispose = etsv_dispose;
-
- etsv_class->add = etsv_add;
- etsv_class->add_all = etsv_add_all;
-}
-
-static void
-etsv_init (ETreeSortedVariable *etsv)
-{
- etsv->full_header = NULL;
- etsv->sort_info = NULL;
-
- etsv->table_model_changed_id = 0;
- etsv->table_model_row_changed_id = 0;
- etsv->table_model_cell_changed_id = 0;
- etsv->sort_info_changed_id = 0;
-
- etsv->sort_idle_id = 0;
- etsv->insert_count = 0;
-}
-
-E_MAKE_TYPE(e_tree_sorted_variable, "ETreeSortedVariable", ETreeSortedVariable, etsv_class_init, etsv_init, E_TREE_MODEL_TYPE)
-
-static gboolean
-etsv_sort_idle(ETreeSortedVariable *etsv)
-{
- g_object_ref(etsv);
- etsv_sort(etsv);
- etsv->sort_idle_id = 0;
- etsv->insert_count = 0;
- g_object_unref(etsv);
- return FALSE;
-}
-
-static gboolean
-etsv_insert_idle(ETreeSortedVariable *etsv)
-{
- etsv->insert_count = 0;
- etsv->insert_idle_id = 0;
- return FALSE;
-}
-
-
-ETableModel *
-e_tree_sorted_variable_new (ETreeModel *source, ETableHeader *full_header, ETableSortInfo *sort_info)
-{
- ETreeSortedVariable *etsv = g_object_new (E_TREE_SORTED_VARIABLE_TYPE, NULL);
- ETreeSortedVariable *etsv = E_TABLE_SUBSET_VARIABLE (etsv);
-
- if (e_table_subset_variable_construct (etsv, source) == NULL){
- g_object_unref (etsv);
- return NULL;
- }
-
- etsv->sort_info = sort_info;
- g_object_ref(etsv->sort_info);
- etsv->full_header = full_header;
- g_object_ref(etsv->full_header);
-
- etsv->table_model_changed_id = g_signal_connect (source, "model_changed",
- G_CALLBACK (etsv_proxy_model_changed), etsv);
-#if 0
- etsv->table_model_row_changed_id = g_signal_connect (source, "model_row_changed",
- G_CALLBACK (etsv_proxy_model_row_changed), etsv);
- etsv->table_model_cell_changed_id = g_signal_connect (source, "model_cell_changed",
- G_CALLBACK (etsv_proxy_model_cell_changed), etsv);
-#endif
- etsv->sort_info_changed_id = g_signal_connect (sort_info, "sort_info_changed",
- G_CALLBACK (etsv_sort_info_changed), etsv);
-
- return E_TABLE_MODEL(etsv);
-}
-
-static void
-etsv_proxy_model_changed (ETableModel *etm, ETreeSortedVariable *etsv)
-{
- /* FIXME: do_resort (); */
-}
-#if 0
-static void
-etsv_proxy_model_row_changed (ETableModel *etm, int row, ETreeSortedVariable *etsv)
-{
- ETreeSortedVariable *etsv = E_TABLE_SUBSET_VARIABLE(etsv);
-
- if (e_table_subset_variable_remove(etsv, row))
- e_table_subset_variable_add (etsv, row);
-}
-
-static void
-etsv_proxy_model_cell_changed (ETableModel *etm, int col, int row, ETreeSortedVariable *etsv)
-{
- ETreeSortedVariable *etsv = E_TABLE_SUBSET_VARIABLE(etsv);
-
- if (e_table_subset_variable_remove(etsv, row))
- e_table_subset_variable_add (etsv, row);
-}
-#endif
-
-static void
-etsv_sort_info_changed (ETableSortInfo *info, ETreeSortedVariable *etsv)
-{
- etsv_sort(etsv);
-}
-
-/* This takes source rows. */
-static int
-etsv_compare(ETreeSortedVariable *etsv, const ETreePath *path1, const ETreePath *path2)
-{
- int j;
- int sort_count = e_table_sort_info_sorting_get_count(etsv->sort_info);
- int comp_val = 0;
- int ascending = 1;
-
- for (j = 0; j < sort_count; j++) {
- ETableSortColumn column = e_table_sort_info_sorting_get_nth(etsv->sort_info, j);
- ETableCol *col;
- col = e_table_header_get_column_by_col_idx(etsv->full_header, column.column);
- if (col == NULL)
- col = e_table_header_get_column (etsv->full_header, e_table_header_count (etsv->full_header) - 1);
- comp_val = (*col->compare)(e_tree_model_value_at (etsv->source, path1, col->col_idx),
- e_tree_model_value_at (etsv->source, path2, col->col_idx));
- ascending = column.ascending;
- if (comp_val != 0)
- break;
- }
- if (comp_val == 0) {
- if (row1 < row2)
- comp_val = -1;
- if (row1 > row2)
- comp_val = 1;
- }
- if (!ascending)
- comp_val = -comp_val;
- return comp_val;
-}
-
-
-static ETreeSortedVariable *etsv_closure;
-int cols_closure;
-int *ascending_closure;
-int *col_idx_closure;
-GCompareFunc *compare_closure;
-
-static int
-etsv_compare_closure(const ETreePath *path1, const ETreePath *path2)
-{
- int j;
- int sort_count = e_table_sort_info_sorting_get_count(etsv_closure->sort_info);
- int comp_val = 0;
- int ascending = 1;
- for (j = 0; j < sort_count; j++) {
-
- comp_val = (*(compare_closure[j]))(e_tree_model_value_at (etsv_closure->source, path1, col_idx_closure[j]),
- e_tree_model_value_at (etsv_closure->source, path2, col_idx_closure[j]));
- ascending = ascending_closure[j];
- if (comp_val != 0)
- break;
- }
- if (comp_val == 0) {
- if (row1 < row2)
- comp_val = -1;
- if (row1 > row2)
- comp_val = 1;
- }
- if (!ascending)
- comp_val = -comp_val;
- return comp_val;
-}
-
-static int
-qsort_callback(const void *data1, const void *data2)
-{
- GNode *node1 = *(GNode **)data1;
- GNode *node2 = *(GNode **)data2;
- return etsv_compare_closure(node1->data, node2->data);
-}
-
-static int
-qsort_callback_source(const void *data1, const void *data2)
-{
- return etsv_compare_closure(data1, data2);
-}
-
-static void
-etsv_setup_closures(ETreeSortedVariable *etsv)
-{
- int j;
- int cols;
-
- cols = e_table_sort_info_sorting_get_count(etsv->sort_info);
- cols_closure = cols;
- etsv_closure = etsv;
-
- ascending_closure = g_new(int, cols);
- col_idx_closure = g_new(int, cols);
- compare_closure = g_new(GCompareFunc, cols);
-
- for (j = 0; j < cols; j++) {
- ETableSortColumn column = e_table_sort_info_sorting_get_nth(etsv->sort_info, j);
- ETableCol *col;
-
- col = e_table_header_get_column_by_col_idx(etsv->full_header, column.column);
- if (col == NULL) {
- col = e_table_header_get_column (etsv->full_header, e_table_header_count (etsv->full_header) - 1);
- }
-
- ascending_closure[j] = column.ascending;
- col_idx_closure[j] = col->col_idx;
- compare_closure[j] = col->compare;
- }
-}
-
-static void
-etsv_free_closures(ETreeSortedVariable *etsv)
-{
- g_free(ascending_closure);
- g_free(col_idx_closure);
- g_free(compare_closure);
-
-}
-
-static void
-etsv_sort_node(ETreeSortedVariable *etsv, GNode *node)
-{
- gint n;
- gint i;
- GNode **children;
- GNode *child;
- GNode *prev;
-
- n = g_node_n_children(node);
- children = g_new(GNode *, n);
- for (i = 0, child = node->children; child && i; child = child->next, i++) {
- children[i] = child;
- }
- qsort(children, n, sizeof(GNode *), qsort_callback);
-
- prev = NULL;
- for (i = 0; i < n; i++) {
- children[i]->prev = prev;
- if (prev) prev->next = children[i];
- prev = children[i];
- children[i]->next = NULL;
- }
-}
-
-static void
-etsv_sort_tree(ETreeSortedVariable *etsv, GNode *root)
-{
- GNode *childr;
-
- etsv_sort_node(etsv, node);
-
- for (child = node->child; child; child = child->next) {
- etsv_sort_tree(etsv, child);
- }
-}
-
-static void
-etsv_sort(ETreeSortedVariable *etsv)
-{
- static int reentering = 0;
- if (reentering)
- return;
- reentering = 1;
-
- e_table_model_pre_change(E_TABLE_MODEL(etsv));
-
- etsv_setup_closures(etsv);
-
- etsv_sort_tree(etsv, etsv->root);
-
- etsv_free_closures(etsv);
-
- e_table_model_changed (E_TABLE_MODEL(etsv));
- reentering = 0;
-}
-
-static void
-etsv_add_node (ETreeSortedVariable *etsv, ETreePath *path, GNode *root)
-{
- GNode *node;
- GNode *new_node;
- for (node = root; node; node = node->next) {
- if (e_tree_model_node_is_ancestor(etsv->source, path, node->data)) {
- etsv_add_node(etsv, path, node->data);
- return;
- }
- }
- new_node = g_node_new(path);
- for (node = root; node; ) {
- if (e_tree_model_node_is_ancestor(etsv->source, node->data, path)) {
- GNode *next;
- next = node->next;
- g_node_unlink(node);
- g_node_prepend(new_node, node);
- node = next;
- } else
- node = node->next;
- }
-
- etsv_sort_node(etsv, new_node);
-
-
-#if 0
- g_node_prepend(root, new_node);
- etsv_sort_node(etsv, root);
-#else
- /* Insert sort to be a bit faster than the above prepend and then sort. */
- for (node = root; node; node = node->next) {
- if (etsv_compare(etsv, path, node->data) > 0) {
- g_node_insert_before (root, node, new_node);
- return;
- }
- }
- g_node_append(root, new_node);
-#endif
-}
-
-etsv_add(ETreeSortedVariable *etsv, gint row)
-{
- ETreeModel *source = etsv->source;
- ETreePath *path;
-
- path = e_table_model_value_at (E_TABLE_MODEL(source), -1, row);
- etsv_add_node(etsv, path, etsv->root);
-}
-
-/* Optimize by doing the qsorts as we build. But we'll do that later. */
-static void
-etsv_add_all_node (ETreeSortedVariable *etsv, ETreePath *path, GNode *node)
-{
- ETreeModel *source = etsv->source;
- ETreePath **children;
- int n;
- int i;
-
- n = e_tree_model_node_get_children(source, path, &children);
- qsort(children, n, sizeof(ETreePath *), qsort_callback_source);
-
- for (i = n - 1; i >= 0; i--) {
- GNode *new_child = g_node_new(children[i]);
- g_node_prepend(path, new_child);
- etsv_add_all_node (etsv, children[i], new_child)
- }
-
- g_free(children);
-}
-
-static void
-etsv_add_all (ETreeSortedVariable *etsv)
-{
- GNode *node;
- ETreePath *path;
-
- e_table_model_pre_change(etm);
-
- if (etsv->root)
- g_node_destroy(etsv->root);
-
- etsv_setup_closures(etsv);
-
- path = e_tree_model_get_root(etsv->source);
- node = g_node_new(path);
- etsv_add_all_node(etsv, path, node);
- etsv->root = node;
-
- etsv_free_closures(etsv);
-
- e_tree_model_node_changed (etsv, etsv->root);
-}
diff --git a/widgets/table/e-tree-sorted-variable.h b/widgets/table/e-tree-sorted-variable.h
deleted file mode 100644
index 35c4c22ffd..0000000000
--- a/widgets/table/e-tree-sorted-variable.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-tree-sorted-variable.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_TREE_SORTED_VARIABLE_H_
-#define _E_TREE_SORTED_VARIABLE_H_
-
-#include <glib-object.h>
-#include <gal/e-tree/e-tree-model.h>
-#include <gal/e-table/e-table-subset-variable.h>
-#include <gal/e-table/e-table-sort-info.h>
-#include <gal/e-table/e-table-header.h>
-
-G_BEGIN_DECLS
-
-#define E_TREE_SORTED_VARIABLE_TYPE (e_tree_sorted_variable_get_type ())
-#define E_TREE_SORTED_VARIABLE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TREE_SORTED_VARIABLE_TYPE, ETreeSortedVariable))
-#define E_TREE_SORTED_VARIABLE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TREE_SORTED_VARIABLE_TYPE, ETreeSortedVariableClass))
-#define E_IS_TREE_SORTED_VARIABLE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TREE_SORTED_VARIABLE_TYPE))
-#define E_IS_TREE_SORTED_VARIABLE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TREE_SORTED_VARIABLE_TYPE))
-#define E_TREE_SORTED_VARIABLE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TREE_SORTED_VARIABLE_TYPE, ETreeSortedVariableClass))
-
-typedef struct {
- ETreeModel base;
-
- ETableSortInfo *sort_info;
-
- ETableHeader *full_header;
-
- int table_model_changed_id;
- int table_model_row_changed_id;
- int table_model_cell_changed_id;
- int sort_info_changed_id;
- int sort_idle_id;
- int insert_idle_id;
- int insert_count;
-
-} ETreeSortedVariable;
-
-typedef struct {
- ETreeModelClass parent_class;
-} ETreeSortedVariableClass;
-
-GType e_tree_sorted_variable_get_type (void);
-ETableModel *e_tree_sorted_variable_new (ETreeModel *etm,
- ETableHeader *header,
- ETableSortInfo *sort_info);
-
-ETreeModel *e_tree_sorted_get_toplevel (ETreeSortedVariable *tree_model);
-
-void e_tree_sorted_variable_add (ETreeSortedVariable *ets,
- gint row);
-void e_tree_sorted_variable_add_all (ETreeSortedVariable *ets);
-gboolean e_tree_sorted_variable_remove (ETreeSortedVariable *ets,
- gint row);
-void e_tree_sorted_variable_increment (ETreeSortedVariable *ets,
- gint position,
- gint amount);
-void e_tree_sorted_variable_decrement (ETreeSortedVariable *ets,
- gint position,
- gint amount);
-void e_tree_sorted_variable_set_allocation (ETreeSortedVariable *ets,
- gint total);
-G_END_DECLS
-
-#endif /* _E_TREE_SORTED_VARIABLE_H_ */
diff --git a/widgets/table/e-tree-sorted.c b/widgets/table/e-tree-sorted.c
deleted file mode 100644
index 20ecdad63f..0000000000
--- a/widgets/table/e-tree-sorted.c
+++ /dev/null
@@ -1,1390 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-tree-sorted.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- * Chris Toshok <toshok@ximian.com>
- *
- * Adapted from the gtree code and ETableModel.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-/* FIXME: Overall e-tree-sorted.c needs to be made more efficient. */
-
-
-#include <config.h>
-
-#include "e-tree-sorted.h"
-
-#include <stdio.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <string.h>
-
-#include <libxml/parser.h>
-#include <libxml/xmlmemory.h>
-
-#include "gal/util/e-util.h"
-#include "gal/util/e-xml-utils.h"
-#include "e-table-sorting-utils.h"
-
-/* maximum insertions between an idle event that we will do without scheduling an idle sort */
-#define ETS_INSERT_MAX (4)
-
-#define TREEPATH_CHUNK_AREA_SIZE (30 * sizeof (ETreeSortedPath))
-
-#define d(x)
-
-static ETreeModel *parent_class;
-static GMemChunk *node_chunk;
-
-enum {
- NODE_RESORTED,
- LAST_SIGNAL
-};
-
-static guint signals [LAST_SIGNAL] = {0, };
-
-typedef struct ETreeSortedPath ETreeSortedPath;
-
-struct ETreeSortedPath {
- ETreePath corresponding;
-
- /* parent/child/sibling pointers */
- ETreeSortedPath *parent;
- gint num_children;
- ETreeSortedPath **children;
- int position;
- int orig_position;
-
- guint needs_resort : 1;
- guint child_needs_resort : 1;
- guint resort_all_children : 1;
- guint needs_regen_to_sort : 1;
-};
-
-struct ETreeSortedPriv {
- ETreeModel *source;
- ETreeSortedPath *root;
-
- ETableSortInfo *sort_info;
- ETableHeader *full_header;
-
- ETreeSortedPath *last_access;
-
- int tree_model_pre_change_id;
- int tree_model_no_change_id;
- int tree_model_node_changed_id;
- int tree_model_node_data_changed_id;
- int tree_model_node_col_changed_id;
- int tree_model_node_inserted_id;
- int tree_model_node_removed_id;
- int tree_model_node_deleted_id;
- int tree_model_node_request_collapse_id;
-
- int sort_info_changed_id;
- int sort_idle_id;
- int insert_idle_id;
- int insert_count;
-
- guint in_resort_idle : 1;
- guint nested_resort_idle : 1;
-};
-
-enum {
- ARG_0,
-
- ARG_SORT_INFO
-};
-
-static void ets_sort_info_changed (ETableSortInfo *sort_info, ETreeSorted *ets);
-static void resort_node (ETreeSorted *ets, ETreeSortedPath *path, gboolean resort_all_children, gboolean needs_regen, gboolean send_signals);
-static void mark_path_needs_resort (ETreeSorted *ets, ETreeSortedPath *path, gboolean needs_rebuild, gboolean resort_all_children);
-static void schedule_resort (ETreeSorted *ets, ETreeSortedPath *path, gboolean needs_regen, gboolean resort_all_children);
-static void free_path (ETreeSortedPath *path);
-static void generate_children(ETreeSorted *ets, ETreeSortedPath *path);
-static void regenerate_children(ETreeSorted *ets, ETreeSortedPath *path);
-
-
-
-/* idle callbacks */
-
-static gboolean
-ets_sort_idle(gpointer user_data)
-{
- ETreeSorted *ets = user_data;
- if (ets->priv->in_resort_idle) {
- ets->priv->nested_resort_idle = TRUE;
- return FALSE;
- }
- ets->priv->in_resort_idle = TRUE;
- if (ets->priv->root) {
- do {
- ets->priv->nested_resort_idle = FALSE;
- resort_node (ets, ets->priv->root, FALSE, FALSE, TRUE);
- } while (ets->priv->nested_resort_idle);
- }
- ets->priv->in_resort_idle = FALSE;
- ets->priv->sort_idle_id = 0;
- return FALSE;
-}
-
-#define ETS_SORT_IDLE_ACTIVATED(ets) ((ets)->priv->sort_idle_id != 0)
-
-inline static void
-ets_stop_sort_idle (ETreeSorted *ets)
-{
- if (ets->priv->sort_idle_id) {
- g_source_remove(ets->priv->sort_idle_id);
- ets->priv->sort_idle_id = 0;
- }
-}
-
-static gboolean
-ets_insert_idle(ETreeSorted *ets)
-{
- ets->priv->insert_count = 0;
- ets->priv->insert_idle_id = 0;
- return FALSE;
-}
-
-
-
-/* Helper functions */
-
-#define CHECK_AROUND_LAST_ACCESS
-
-static inline ETreeSortedPath *
-check_last_access (ETreeSorted *ets, ETreePath corresponding)
-{
-#ifdef CHECK_AROUND_LAST_ACCESS
- ETreeSortedPath *parent;
-#endif
-
- if (ets->priv->last_access == NULL)
- return NULL;
-
- if (ets->priv->last_access == corresponding) {
- d(g_print("Found last access %p at %p.", ets->priv->last_access, ets->priv->last_access));
- return ets->priv->last_access;
- }
-
-#ifdef CHECK_AROUND_LAST_ACCESS
- parent = ets->priv->last_access->parent;
- if (parent && parent->children) {
- int position = ets->priv->last_access->position;
- int end = MIN(parent->num_children, position + 10);
- int start = MAX(0, position - 10);
- int initial = MAX (MIN (position, end), start);
- int i;
-
- for (i = initial; i < end; i++) {
- if (parent->children[i] && parent->children[i]->corresponding == corresponding) {
- d(g_print("Found last access %p at %p.", ets->priv->last_access, parent->children[i]));
- return parent->children[i];
- }
- }
-
- for (i = initial - 1; i >= start; i--) {
- if (parent->children[i] && parent->children[i]->corresponding == corresponding) {
- d(g_print("Found last access %p at %p.", ets->priv->last_access, parent->children[i]));
- return parent->children[i];
- }
- }
- }
-#endif
- return NULL;
-}
-
-static ETreeSortedPath *
-find_path(ETreeSorted *ets, ETreePath corresponding)
-{
- int depth;
- ETreePath *sequence;
- int i;
- ETreeSortedPath *path;
- ETreeSortedPath *check_last;
-
- if (corresponding == NULL)
- return NULL;
-
- check_last = check_last_access (ets, corresponding);
- if (check_last) {
- d(g_print(" (find_path)\n"));
- return check_last;
- }
-
- depth = e_tree_model_node_depth(ets->priv->source, corresponding);
-
- sequence = g_new(ETreePath, depth + 1);
-
- sequence[0] = corresponding;
-
- for (i = 0; i < depth; i++)
- sequence[i + 1] = e_tree_model_node_get_parent(ets->priv->source, sequence[i]);
-
- path = ets->priv->root;
-
- for (i = depth - 1; i >= 0 && path != NULL; i --) {
- int j;
-
- if (path->num_children == -1) {
- path = NULL;
- break;
- }
-
- for (j = 0; j < path->num_children; j++) {
- if (path->children[j]->corresponding == sequence[i]) {
- break;
- }
- }
-
- if (j < path->num_children) {
- path = path->children[j];
- } else {
- path = NULL;
- }
- }
- g_free (sequence);
-
- d(g_print("Didn't find last access %p. Setting to %p. (find_path)\n", ets->priv->last_access, path));
- ets->priv->last_access = path;
-
- return path;
-}
-
-static ETreeSortedPath *
-find_child_path(ETreeSorted *ets, ETreeSortedPath *parent, ETreePath corresponding)
-{
- int i;
-
- if (corresponding == NULL)
- return NULL;
-
- if (parent->num_children == -1) {
- return NULL;
- }
-
- for (i = 0; i < parent->num_children; i++)
- if (parent->children[i]->corresponding == corresponding)
- return parent->children[i];
-
- return NULL;
-}
-
-static ETreeSortedPath *
-find_or_create_path(ETreeSorted *ets, ETreePath corresponding)
-{
- int depth;
- ETreePath *sequence;
- int i;
- ETreeSortedPath *path;
- ETreeSortedPath *check_last;
-
- if (corresponding == NULL)
- return NULL;
-
- check_last = check_last_access (ets, corresponding);
- if (check_last) {
- d(g_print(" (find_or_create_path)\n"));
- return check_last;
- }
-
- depth = e_tree_model_node_depth(ets->priv->source, corresponding);
-
- sequence = g_new(ETreePath, depth + 1);
-
- sequence[0] = corresponding;
-
- for (i = 0; i < depth; i++)
- sequence[i + 1] = e_tree_model_node_get_parent(ets->priv->source, sequence[i]);
-
- path = ets->priv->root;
-
- for (i = depth - 1; i >= 0 && path != NULL; i --) {
- int j;
-
- if (path->num_children == -1) {
- generate_children(ets, path);
- }
-
- for (j = 0; j < path->num_children; j++) {
- if (path->children[j]->corresponding == sequence[i]) {
- break;
- }
- }
-
- if (j < path->num_children) {
- path = path->children[j];
- } else {
- path = NULL;
- }
- }
- g_free (sequence);
-
- d(g_print("Didn't find last access %p. Setting to %p. (find_or_create_path)\n", ets->priv->last_access, path));
- ets->priv->last_access = path;
-
- return path;
-}
-
-static void
-free_children (ETreeSortedPath *path)
-{
- int i;
-
- if (path == NULL)
- return;
-
- for (i = 0; i < path->num_children; i++) {
- free_path(path->children[i]);
- }
-
- g_free(path->children);
- path->children = NULL;
- path->num_children = -1;
-}
-
-static void
-free_path (ETreeSortedPath *path)
-{
- free_children(path);
- g_chunk_free(path, node_chunk);
-}
-
-static ETreeSortedPath *
-new_path (ETreeSortedPath *parent, ETreePath corresponding)
-{
- ETreeSortedPath *path;
-
- path = g_chunk_new0 (ETreeSortedPath, node_chunk);
-
- path->corresponding = corresponding;
- path->parent = parent;
- path->num_children = -1;
- path->children = NULL;
- path->position = -1;
- path->orig_position = -1;
- path->child_needs_resort = 0;
- path->resort_all_children = 0;
- path->needs_resort = 0;
- path->needs_regen_to_sort = 0;
-
- return path;
-}
-
-static gboolean
-reposition_path (ETreeSorted *ets, ETreeSortedPath *path)
-{
- int new_index;
- int old_index = path->position;
- ETreeSortedPath *parent = path->parent;
- gboolean changed = FALSE;
- if (parent) {
- if (ets->priv->sort_idle_id == 0) {
- if (ets->priv->insert_count > ETS_INSERT_MAX) {
- /* schedule a sort, and append instead */
- schedule_resort(ets, parent, TRUE, FALSE);
- } else {
- /* make sure we have an idle handler to reset the count every now and then */
- if (ets->priv->insert_idle_id == 0) {
- ets->priv->insert_idle_id = g_idle_add_full(40, (GSourceFunc) ets_insert_idle, ets, NULL);
- }
-
- new_index = e_table_sorting_utils_tree_check_position
- (E_TREE_MODEL(ets),
- ets->priv->sort_info,
- ets->priv->full_header,
- (ETreePath *) parent->children,
- parent->num_children,
- old_index);
-
- if (new_index > old_index) {
- int i;
- ets->priv->insert_count++;
- memmove(parent->children + old_index, parent->children + old_index + 1, sizeof (ETreePath) * (new_index - old_index));
- parent->children[new_index] = path;
- for (i = old_index; i <= new_index; i++)
- parent->children[i]->position = i;
- changed = TRUE;
- e_tree_model_node_changed(E_TREE_MODEL(ets), parent);
- e_tree_sorted_node_resorted(ets, parent);
- } else if (new_index < old_index) {
- int i;
- ets->priv->insert_count++;
- memmove(parent->children + new_index + 1, parent->children + new_index, sizeof (ETreePath) * (old_index - new_index));
- parent->children[new_index] = path;
- for (i = new_index; i <= old_index; i++)
- parent->children[i]->position = i;
- changed = TRUE;
- e_tree_model_node_changed(E_TREE_MODEL(ets), parent);
- e_tree_sorted_node_resorted(ets, parent);
- }
- }
- } else
- mark_path_needs_resort(ets, parent, TRUE, FALSE);
- }
- return changed;
-}
-
-static void
-regenerate_children(ETreeSorted *ets, ETreeSortedPath *path)
-{
- ETreeSortedPath **children;
- int i;
-
- children = g_new(ETreeSortedPath *, path->num_children);
- for (i = 0; i < path->num_children; i++)
- children[path->children[i]->orig_position] = path->children[i];
- g_free(path->children);
- path->children = children;
-}
-
-static void
-generate_children(ETreeSorted *ets, ETreeSortedPath *path)
-{
- ETreePath child;
- int i;
- int count;
-
- free_children(path);
-
- count = 0;
- for (child = e_tree_model_node_get_first_child(ets->priv->source, path->corresponding);
- child;
- child = e_tree_model_node_get_next(ets->priv->source, child)) {
- count ++;
- }
-
- path->num_children = count;
- path->children = g_new(ETreeSortedPath *, count);
- for (child = e_tree_model_node_get_first_child(ets->priv->source, path->corresponding), i = 0;
- child;
- child = e_tree_model_node_get_next(ets->priv->source, child), i++) {
- path->children[i] = new_path(path, child);
- path->children[i]->position = i;
- path->children[i]->orig_position = i;
- }
- if (path->num_children > 0)
- schedule_resort (ets, path, FALSE, TRUE);
-}
-
-static void
-resort_node (ETreeSorted *ets, ETreeSortedPath *path, gboolean resort_all_children, gboolean needs_regen, gboolean send_signals)
-{
- gboolean needs_resort;
- if (path) {
- needs_resort = path->needs_resort || resort_all_children;
- needs_regen = path->needs_regen_to_sort || needs_regen;
- if (path->num_children > 0) {
- if (needs_resort && send_signals)
- e_tree_model_pre_change(E_TREE_MODEL(ets));
- if (needs_resort) {
- int i;
- d(g_print("Start sort of node %p\n", path));
- if (needs_regen)
- regenerate_children(ets, path);
- d(g_print("Regened sort of node %p\n", path));
- e_table_sorting_utils_tree_sort (E_TREE_MODEL(ets),
- ets->priv->sort_info,
- ets->priv->full_header,
- (ETreePath *) path->children,
- path->num_children);
- d(g_print("Renumbering sort of node %p\n", path));
- for (i = 0; i < path->num_children; i++) {
- path->children[i]->position = i;
- }
- d(g_print("End sort of node %p\n", path));
- }
- if (path->resort_all_children)
- resort_all_children = TRUE;
- if ((resort_all_children || path->child_needs_resort) && path->num_children >= 0) {
- int i;
- for (i = 0; i < path->num_children; i++) {
- resort_node(ets, path->children[i], resort_all_children, needs_regen, send_signals && !needs_resort);
- }
- path->child_needs_resort = 0;
- }
- }
- path->needs_resort = 0;
- path->child_needs_resort = 0;
- path->needs_regen_to_sort = 0;
- path->resort_all_children = 0;
- if (needs_resort && send_signals && path->num_children > 0) {
- e_tree_model_node_changed(E_TREE_MODEL(ets), path);
- e_tree_sorted_node_resorted(ets, path);
- }
- }
-}
-
-static void
-mark_path_child_needs_resort (ETreeSorted *ets, ETreeSortedPath *path)
-{
- if (path == NULL)
- return;
- if (!path->child_needs_resort) {
- path->child_needs_resort = 1;
- mark_path_child_needs_resort (ets, path->parent);
- }
-}
-
-static void
-mark_path_needs_resort (ETreeSorted *ets, ETreeSortedPath *path, gboolean needs_regen, gboolean resort_all_children)
-{
- if (path == NULL)
- return;
- if (path->num_children == 0)
- return;
- path->needs_resort = 1;
- path->needs_regen_to_sort = needs_regen;
- path->resort_all_children = resort_all_children;
- mark_path_child_needs_resort(ets, path->parent);
-}
-
-static void
-schedule_resort (ETreeSorted *ets, ETreeSortedPath *path, gboolean needs_regen, gboolean resort_all_children)
-{
- ets->priv->insert_count = 0;
- if (ets->priv->insert_idle_id != 0) {
- g_source_remove(ets->priv->insert_idle_id);
- ets->priv->insert_idle_id = 0;
- }
-
- if (path == NULL)
- return;
- if (path->num_children == 0)
- return;
-
- mark_path_needs_resort(ets, path, needs_regen, resort_all_children);
- if (ets->priv->sort_idle_id == 0) {
- ets->priv->sort_idle_id = g_idle_add_full(50, (GSourceFunc) ets_sort_idle, ets, NULL);
- } else if (ets->priv->in_resort_idle) {
- ets->priv->nested_resort_idle = TRUE;
- }
-}
-
-
-
-/* virtual methods */
-
-static void
-ets_dispose (GObject *object)
-{
- ETreeSorted *ets = E_TREE_SORTED (object);
- ETreeSortedPriv *priv = ets->priv;
-
- /* FIXME lots of stuff to free here */
- if (!priv) {
- G_OBJECT_CLASS (parent_class)->dispose (object);
- return;
- }
-
- if (priv->source) {
- g_signal_handler_disconnect (G_OBJECT (priv->source),
- priv->tree_model_pre_change_id);
- g_signal_handler_disconnect (G_OBJECT (priv->source),
- priv->tree_model_no_change_id);
- g_signal_handler_disconnect (G_OBJECT (priv->source),
- priv->tree_model_node_changed_id);
- g_signal_handler_disconnect (G_OBJECT (priv->source),
- priv->tree_model_node_data_changed_id);
- g_signal_handler_disconnect (G_OBJECT (priv->source),
- priv->tree_model_node_col_changed_id);
- g_signal_handler_disconnect (G_OBJECT (priv->source),
- priv->tree_model_node_inserted_id);
- g_signal_handler_disconnect (G_OBJECT (priv->source),
- priv->tree_model_node_removed_id);
- g_signal_handler_disconnect (G_OBJECT (priv->source),
- priv->tree_model_node_deleted_id);
- g_signal_handler_disconnect (G_OBJECT (priv->source),
- priv->tree_model_node_request_collapse_id);
-
- g_object_unref (priv->source);
- priv->source = NULL;
-
- priv->tree_model_pre_change_id = 0;
- priv->tree_model_no_change_id = 0;
- priv->tree_model_node_changed_id = 0;
- priv->tree_model_node_data_changed_id = 0;
- priv->tree_model_node_col_changed_id = 0;
- priv->tree_model_node_inserted_id = 0;
- priv->tree_model_node_removed_id = 0;
- priv->tree_model_node_deleted_id = 0;
- priv->tree_model_node_request_collapse_id = 0;
- }
-
- if (priv->sort_info) {
- g_signal_handler_disconnect (G_OBJECT (priv->sort_info),
- priv->sort_info_changed_id);
- priv->sort_info_changed_id = 0;
-
- g_object_unref (priv->sort_info);
- priv->sort_info = NULL;
- }
-
- ets_stop_sort_idle (ets);
- if (ets->priv->insert_idle_id) {
- g_source_remove(ets->priv->insert_idle_id);
- ets->priv->insert_idle_id = 0;
- }
-
- if (priv->full_header)
- g_object_unref(priv->full_header);
-
-}
-
-static void
-ets_finalize (GObject *object)
-{
- ETreeSorted *ets = (ETreeSorted *) object;
-
- if (ets->priv->root)
- free_path(ets->priv->root);
-
- g_free (ets->priv);
- ets->priv = NULL;
-
- G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-static ETreePath
-ets_get_root (ETreeModel *etm)
-{
- ETreeSortedPriv *priv = E_TREE_SORTED(etm)->priv;
- if (priv->root == NULL) {
- ETreeSorted *ets = E_TREE_SORTED(etm);
- ETreePath corresponding = e_tree_model_get_root(ets->priv->source);
-
- if (corresponding) {
- priv->root = new_path(NULL, corresponding);
- }
- }
- if (priv->root && priv->root->num_children == -1) {
- generate_children(E_TREE_SORTED(etm), priv->root);
- }
-
- return priv->root;
-}
-
-static ETreePath
-ets_get_parent (ETreeModel *etm, ETreePath node)
-{
- ETreeSortedPath *path = node;
- return path->parent;
-}
-
-static ETreePath
-ets_get_first_child (ETreeModel *etm, ETreePath node)
-{
- ETreeSortedPath *path = node;
- ETreeSorted *ets = E_TREE_SORTED(etm);
-
- if (path->num_children == -1)
- generate_children(ets, path);
-
- if (path->num_children > 0)
- return path->children[0];
- else
- return NULL;
-}
-
-static ETreePath
-ets_get_last_child (ETreeModel *etm, ETreePath node)
-{
- ETreeSortedPath *path = node;
- ETreeSorted *ets = E_TREE_SORTED(etm);
-
- if (path->num_children == -1)
- generate_children(ets, path);
-
- if (path->num_children > 0)
- return path->children[path->num_children - 1];
- else
- return NULL;
-}
-
-static ETreePath
-ets_get_next (ETreeModel *etm, ETreePath node)
-{
- ETreeSortedPath *path = node;
- ETreeSortedPath *parent = path->parent;
- if (parent) {
- if (parent->num_children > path->position + 1)
- return parent->children[path->position + 1];
- else
- return NULL;
- } else
- return NULL;
-}
-
-static ETreePath
-ets_get_prev (ETreeModel *etm, ETreePath node)
-{
- ETreeSortedPath *path = node;
- ETreeSortedPath *parent = path->parent;
- if (parent) {
- if (path->position - 1 >= 0)
- return parent->children[path->position - 1];
- else
- return NULL;
- } else
- return NULL;
-}
-
-static gboolean
-ets_is_root (ETreeModel *etm, ETreePath node)
-{
- ETreeSortedPath *path = node;
- ETreeSorted *ets = E_TREE_SORTED(etm);
-
- return e_tree_model_node_is_root (ets->priv->source, path->corresponding);
-}
-
-static gboolean
-ets_is_expandable (ETreeModel *etm, ETreePath node)
-{
- ETreeSortedPath *path = node;
- ETreeSorted *ets = E_TREE_SORTED(etm);
- gboolean expandable = e_tree_model_node_is_expandable (ets->priv->source, path->corresponding);
-
- if (path->num_children == -1) {
- generate_children(ets, node);
- }
-
- return expandable;
-}
-
-static guint
-ets_get_children (ETreeModel *etm, ETreePath node, ETreePath **nodes)
-{
- ETreeSortedPath *path = node;
- guint n_children;
-
- if (path->num_children == -1) {
- generate_children(E_TREE_SORTED(etm), node);
- }
-
- n_children = path->num_children;
-
- if (nodes) {
- int i;
-
- (*nodes) = g_malloc (sizeof (ETreePath) * n_children);
- for (i = 0; i < n_children; i ++) {
- (*nodes)[i] = path->children[i];
- }
- }
-
- return n_children;
-}
-
-static guint
-ets_depth (ETreeModel *etm, ETreePath node)
-{
- ETreeSortedPath *path = node;
- ETreeSorted *ets = E_TREE_SORTED(etm);
-
- return e_tree_model_node_depth(ets->priv->source, path->corresponding);
-}
-
-static GdkPixbuf *
-ets_icon_at (ETreeModel *etm, ETreePath node)
-{
- ETreeSortedPath *path = node;
- ETreeSorted *ets = E_TREE_SORTED(etm);
-
- return e_tree_model_icon_at(ets->priv->source, path->corresponding);
-}
-
-static gboolean
-ets_get_expanded_default (ETreeModel *etm)
-{
- ETreeSorted *ets = E_TREE_SORTED(etm);
-
- return e_tree_model_get_expanded_default(ets->priv->source);
-}
-
-static gint
-ets_column_count (ETreeModel *etm)
-{
- ETreeSorted *ets = E_TREE_SORTED(etm);
-
- return e_tree_model_column_count(ets->priv->source);
-}
-
-
-static gboolean
-ets_has_save_id (ETreeModel *etm)
-{
- return TRUE;
-}
-
-static gchar *
-ets_get_save_id (ETreeModel *etm, ETreePath node)
-{
- ETreeSorted *ets = E_TREE_SORTED(etm);
- ETreeSortedPath *path = node;
-
- if (e_tree_model_has_save_id(ets->priv->source))
- return e_tree_model_get_save_id(ets->priv->source, path->corresponding);
- else
- return g_strdup_printf("%p", path->corresponding);
-}
-
-static gboolean
-ets_has_get_node_by_id (ETreeModel *etm)
-{
- ETreeSorted *ets = E_TREE_SORTED(etm);
- return e_tree_model_has_get_node_by_id(ets->priv->source);
-}
-
-static ETreePath
-ets_get_node_by_id (ETreeModel *etm, const char *save_id)
-{
- ETreeSorted *ets = E_TREE_SORTED(etm);
- ETreePath node;
-
- node = e_tree_model_get_node_by_id (ets->priv->source, save_id);
-
- return find_path(ets, node);
-}
-
-static gboolean
-ets_has_change_pending (ETreeModel *etm)
-{
- ETreeSorted *ets = E_TREE_SORTED(etm);
-
- return ets->priv->sort_idle_id != 0;
-}
-
-
-static void *
-ets_value_at (ETreeModel *etm, ETreePath node, int col)
-{
- ETreeSorted *ets = E_TREE_SORTED(etm);
- ETreeSortedPath *path = node;
-
- return e_tree_model_value_at(ets->priv->source, path->corresponding, col);
-}
-
-static void
-ets_set_value_at (ETreeModel *etm, ETreePath node, int col, const void *val)
-{
- ETreeSorted *ets = E_TREE_SORTED(etm);
- ETreeSortedPath *path = node;
-
- e_tree_model_set_value_at (ets->priv->source, path->corresponding, col, val);
-}
-
-static gboolean
-ets_is_editable (ETreeModel *etm, ETreePath node, int col)
-{
- ETreeSorted *ets = E_TREE_SORTED(etm);
- ETreeSortedPath *path = node;
-
- return e_tree_model_node_is_editable (ets->priv->source, path->corresponding, col);
-}
-
-
-/* The default for ets_duplicate_value is to return the raw value. */
-static void *
-ets_duplicate_value (ETreeModel *etm, int col, const void *value)
-{
- ETreeSorted *ets = E_TREE_SORTED(etm);
-
- return e_tree_model_duplicate_value (ets->priv->source, col, value);
-}
-
-static void
-ets_free_value (ETreeModel *etm, int col, void *value)
-{
- ETreeSorted *ets = E_TREE_SORTED(etm);
-
- e_tree_model_free_value (ets->priv->source, col, value);
-}
-
-static void *
-ets_initialize_value (ETreeModel *etm, int col)
-{
- ETreeSorted *ets = E_TREE_SORTED(etm);
-
- return e_tree_model_initialize_value (ets->priv->source, col);
-}
-
-static gboolean
-ets_value_is_empty (ETreeModel *etm, int col, const void *value)
-{
- ETreeSorted *ets = E_TREE_SORTED(etm);
-
- return e_tree_model_value_is_empty (ets->priv->source, col, value);
-}
-
-static char *
-ets_value_to_string (ETreeModel *etm, int col, const void *value)
-{
- ETreeSorted *ets = E_TREE_SORTED(etm);
-
- return e_tree_model_value_to_string (ets->priv->source, col, value);
-}
-
-/* Proxy functions */
-
-static void
-ets_proxy_pre_change (ETreeModel *etm, ETreeSorted *ets)
-{
- e_tree_model_pre_change(E_TREE_MODEL(ets));
-}
-
-static void
-ets_proxy_no_change (ETreeModel *etm, ETreeSorted *ets)
-{
- e_tree_model_no_change(E_TREE_MODEL(ets));
-}
-
-static void
-ets_proxy_node_changed (ETreeModel *etm, ETreePath node, ETreeSorted *ets)
-{
- ets->priv->last_access = NULL;
- d(g_print("Setting last access %p. (ets_proxy_node_changed)\n", ets->priv->last_access));
-
- if (e_tree_model_node_is_root(ets->priv->source, node)) {
- ets_stop_sort_idle (ets);
-
- if (ets->priv->root) {
- free_path(ets->priv->root);
- }
- ets->priv->root = new_path(NULL, node);
- e_tree_model_node_changed(E_TREE_MODEL(ets), ets->priv->root);
- return;
- } else {
- ETreeSortedPath *path = find_path(ets, node);
-
- if (path) {
- free_children(path);
- if (!reposition_path(ets, path)) {
- e_tree_model_node_changed(E_TREE_MODEL(ets), path);
- } else {
- e_tree_model_no_change(E_TREE_MODEL(ets));
- }
- } else {
- e_tree_model_no_change(E_TREE_MODEL(ets));
- }
- }
-}
-
-static void
-ets_proxy_node_data_changed (ETreeModel *etm, ETreePath node, ETreeSorted *ets)
-{
- ETreeSortedPath *path = find_path(ets, node);
-
- if (path) {
- if (!reposition_path(ets, path))
- e_tree_model_node_data_changed(E_TREE_MODEL(ets), path);
- else
- e_tree_model_no_change(E_TREE_MODEL(ets));
- } else
- e_tree_model_no_change(E_TREE_MODEL(ets));
-}
-
-static void
-ets_proxy_node_col_changed (ETreeModel *etm, ETreePath node, int col, ETreeSorted *ets)
-{
- ETreeSortedPath *path = find_path(ets, node);
-
- if (path) {
- gboolean changed = FALSE;
- if (e_table_sorting_utils_affects_sort(ets->priv->sort_info, ets->priv->full_header, col))
- changed = reposition_path(ets, path);
- if (!changed)
- e_tree_model_node_col_changed(E_TREE_MODEL(ets), path, col);
- else
- e_tree_model_no_change(E_TREE_MODEL(ets));
- } else
- e_tree_model_no_change(E_TREE_MODEL(ets));
-}
-
-static void
-ets_proxy_node_inserted (ETreeModel *etm, ETreePath parent, ETreePath child, ETreeSorted *ets)
-{
- ETreeSortedPath *parent_path = find_path(ets, parent);
-
- if (parent_path && parent_path->num_children != -1) {
- int i;
- int j;
- ETreeSortedPath *path;
- int position = parent_path->num_children;
- ETreePath counter;
-
- for (counter = e_tree_model_node_get_next(etm, child);
- counter;
- counter = e_tree_model_node_get_next(etm, counter))
- position --;
-
- if (position != parent_path->num_children) {
- for (i = 0; i < parent_path->num_children; i++) {
- if (parent_path->children[i]->orig_position >= position)
- parent_path->children[i]->orig_position++;
- }
- }
-
- i = parent_path->num_children;
- path = new_path(parent_path, child);
- path->orig_position = position;
- if (!ETS_SORT_IDLE_ACTIVATED (ets)) {
- ets->priv->insert_count++;
- if (ets->priv->insert_count > ETS_INSERT_MAX) {
- /* schedule a sort, and append instead */
- schedule_resort(ets, parent_path, TRUE, FALSE);
- } else {
- /* make sure we have an idle handler to reset the count every now and then */
- if (ets->priv->insert_idle_id == 0) {
- ets->priv->insert_idle_id = g_idle_add_full(40, (GSourceFunc) ets_insert_idle, ets, NULL);
- }
- i = e_table_sorting_utils_tree_insert
- (ets->priv->source,
- ets->priv->sort_info,
- ets->priv->full_header,
- (ETreePath *) parent_path->children,
- parent_path->num_children,
- path);
- }
- } else {
- mark_path_needs_resort(ets, parent_path, TRUE, FALSE);
- }
- parent_path->num_children ++;
- parent_path->children = g_renew(ETreeSortedPath *, parent_path->children, parent_path->num_children);
- memmove(parent_path->children + i + 1, parent_path->children + i, (parent_path->num_children - 1 - i) * sizeof(int));
- parent_path->children[i] = path;
- for (j = i; j < parent_path->num_children; j++) {
- parent_path->children[j]->position = j;
- }
- e_tree_model_node_inserted(E_TREE_MODEL(ets), parent_path, parent_path->children[i]);
- } else if (ets->priv->root == NULL && parent == NULL) {
- if (child) {
- ets->priv->root = new_path(NULL, child);
- e_tree_model_node_inserted(E_TREE_MODEL(ets), NULL, ets->priv->root);
- } else {
- e_tree_model_no_change(E_TREE_MODEL(ets));
- }
- } else {
- e_tree_model_no_change(E_TREE_MODEL(ets));
- }
-}
-
-static void
-ets_proxy_node_removed (ETreeModel *etm, ETreePath parent, ETreePath child, int old_position, ETreeSorted *ets)
-{
- ETreeSortedPath *parent_path = find_path(ets, parent);
- ETreeSortedPath *path;
-
- if (parent_path)
- path = find_child_path(ets, parent_path, child);
- else
- path = find_path(ets, child);
-
- d(g_print("Setting last access %p. (ets_proxy_node_removed)\n ", ets->priv->last_access));
- ets->priv->last_access = NULL;
-
- if (path && parent_path && parent_path->num_children != -1) {
- int i;
- for (i = 0; i < parent_path->num_children; i++) {
- if (parent_path->children[i]->orig_position > old_position)
- parent_path->children[i]->orig_position --;
- }
-
- i = path->position;
-
- parent_path->num_children --;
- memmove(parent_path->children + i, parent_path->children + i + 1, sizeof(ETreeSortedPath *) * (parent_path->num_children - i));
- for (; i < parent_path->num_children; i++) {
- parent_path->children[i]->position = i;
- }
- e_tree_model_node_removed(E_TREE_MODEL(ets), parent_path, path, path->position);
- free_path(path);
- } else if (path && path == ets->priv->root) {
- ets->priv->root = NULL;
- e_tree_model_node_removed(E_TREE_MODEL(ets), NULL, path, -1);
- free_path(path);
- }
-}
-
-static void
-ets_proxy_node_deleted (ETreeModel *etm, ETreePath child, ETreeSorted *ets)
-{
- e_tree_model_node_deleted(E_TREE_MODEL(ets), NULL);
-}
-
-static void
-ets_proxy_node_request_collapse (ETreeModel *etm, ETreePath node, ETreeSorted *ets)
-{
- ETreeSortedPath *path = find_path(ets, node);
- if (path) {
- e_tree_model_node_request_collapse(E_TREE_MODEL(ets), path);
- }
-}
-
-static void
-ets_sort_info_changed (ETableSortInfo *sort_info, ETreeSorted *ets)
-{
- schedule_resort(ets, ets->priv->root, TRUE, TRUE);
-}
-
-
-
-/* Initialization and creation */
-
-static void
-e_tree_sorted_class_init (ETreeSortedClass *klass)
-{
- ETreeModelClass *tree_class = E_TREE_MODEL_CLASS (klass);
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- parent_class = g_type_class_peek_parent (klass);
-
- node_chunk = g_mem_chunk_create (ETreeSortedPath, TREEPATH_CHUNK_AREA_SIZE, G_ALLOC_AND_FREE);
-
- klass->node_resorted = NULL;
-
- object_class->dispose = ets_dispose;
- object_class->finalize = ets_finalize;
-
- tree_class->get_root = ets_get_root;
- tree_class->get_parent = ets_get_parent;
- tree_class->get_first_child = ets_get_first_child;
- tree_class->get_last_child = ets_get_last_child;
- tree_class->get_prev = ets_get_prev;
- tree_class->get_next = ets_get_next;
-
- tree_class->is_root = ets_is_root;
- tree_class->is_expandable = ets_is_expandable;
- tree_class->get_children = ets_get_children;
- tree_class->depth = ets_depth;
-
- tree_class->icon_at = ets_icon_at;
-
- tree_class->get_expanded_default = ets_get_expanded_default;
- tree_class->column_count = ets_column_count;
-
- tree_class->has_save_id = ets_has_save_id;
- tree_class->get_save_id = ets_get_save_id;
-
- tree_class->has_get_node_by_id = ets_has_get_node_by_id;
- tree_class->get_node_by_id = ets_get_node_by_id;
-
- tree_class->has_change_pending = ets_has_change_pending;
-
- tree_class->value_at = ets_value_at;
- tree_class->set_value_at = ets_set_value_at;
- tree_class->is_editable = ets_is_editable;
-
- tree_class->duplicate_value = ets_duplicate_value;
- tree_class->free_value = ets_free_value;
- tree_class->initialize_value = ets_initialize_value;
- tree_class->value_is_empty = ets_value_is_empty;
- tree_class->value_to_string = ets_value_to_string;
-
- signals [NODE_RESORTED] =
- g_signal_new ("node_resorted",
- E_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETreeSortedClass, node_resorted),
- (GSignalAccumulator) NULL, NULL,
- g_cclosure_marshal_VOID__POINTER,
- G_TYPE_NONE, 1, G_TYPE_POINTER);
-}
-
-static void
-e_tree_sorted_init (GObject *object)
-{
- ETreeSorted *ets = (ETreeSorted *)object;
-
- ETreeSortedPriv *priv;
-
- priv = g_new0 (ETreeSortedPriv, 1);
- ets->priv = priv;
-
- priv->root = NULL;
- priv->source = NULL;
-
- priv->sort_info = NULL;
- priv->full_header = NULL;
-
- priv->last_access = NULL;
-
- priv->tree_model_pre_change_id = 0;
- priv->tree_model_no_change_id = 0;
- priv->tree_model_node_changed_id = 0;
- priv->tree_model_node_data_changed_id = 0;
- priv->tree_model_node_col_changed_id = 0;
- priv->tree_model_node_inserted_id = 0;
- priv->tree_model_node_removed_id = 0;
- priv->tree_model_node_deleted_id = 0;
- priv->tree_model_node_request_collapse_id = 0;
-
- priv->sort_info_changed_id = 0;
- priv->sort_idle_id = 0;
- priv->insert_idle_id = 0;
- priv->insert_count = 0;
-
- priv->in_resort_idle = 0;
- priv->nested_resort_idle = 0;
-}
-
-E_MAKE_TYPE(e_tree_sorted, "ETreeSorted", ETreeSorted, e_tree_sorted_class_init, e_tree_sorted_init, E_TREE_MODEL_TYPE)
-
-/**
- * e_tree_sorted_construct:
- * @etree:
- *
- *
- **/
-void
-e_tree_sorted_construct (ETreeSorted *ets, ETreeModel *source, ETableHeader *full_header, ETableSortInfo *sort_info)
-{
- ets->priv->source = source;
- if (source)
- g_object_ref(source);
-
- ets->priv->full_header = full_header;
- if (full_header)
- g_object_ref(full_header);
-
- e_tree_sorted_set_sort_info (ets, sort_info);
-
- ets->priv->tree_model_pre_change_id = g_signal_connect (G_OBJECT (source), "pre_change",
- G_CALLBACK (ets_proxy_pre_change), ets);
- ets->priv->tree_model_no_change_id = g_signal_connect (G_OBJECT (source), "no_change",
- G_CALLBACK (ets_proxy_no_change), ets);
- ets->priv->tree_model_node_changed_id = g_signal_connect (G_OBJECT (source), "node_changed",
- G_CALLBACK (ets_proxy_node_changed), ets);
- ets->priv->tree_model_node_data_changed_id = g_signal_connect (G_OBJECT (source), "node_data_changed",
- G_CALLBACK (ets_proxy_node_data_changed), ets);
- ets->priv->tree_model_node_col_changed_id = g_signal_connect (G_OBJECT (source), "node_col_changed",
- G_CALLBACK (ets_proxy_node_col_changed), ets);
- ets->priv->tree_model_node_inserted_id = g_signal_connect (G_OBJECT (source), "node_inserted",
- G_CALLBACK (ets_proxy_node_inserted), ets);
- ets->priv->tree_model_node_removed_id = g_signal_connect (G_OBJECT (source), "node_removed",
- G_CALLBACK (ets_proxy_node_removed), ets);
- ets->priv->tree_model_node_deleted_id = g_signal_connect (G_OBJECT (source), "node_deleted",
- G_CALLBACK (ets_proxy_node_deleted), ets);
- ets->priv->tree_model_node_request_collapse_id = g_signal_connect (G_OBJECT (source), "node_request_collapse",
- G_CALLBACK (ets_proxy_node_request_collapse), ets);
-
-}
-
-/**
- * e_tree_sorted_new
- *
- * FIXME docs here.
- *
- * return values: a newly constructed ETreeSorted.
- */
-ETreeSorted *
-e_tree_sorted_new (ETreeModel *source, ETableHeader *full_header, ETableSortInfo *sort_info)
-{
- ETreeSorted *ets = g_object_new (E_TREE_SORTED_TYPE, NULL);
-
- e_tree_sorted_construct(ets, source, full_header, sort_info);
-
- return ets;
-}
-
-ETreePath
-e_tree_sorted_view_to_model_path (ETreeSorted *ets,
- ETreePath view_path)
-{
- ETreeSortedPath *path = view_path;
- if (path) {
- ets->priv->last_access = path;
- d(g_print("Setting last access %p. (e_tree_sorted_view_to_model_path)\n", ets->priv->last_access));
- return path->corresponding;
- } else
- return NULL;
-}
-
-ETreePath
-e_tree_sorted_model_to_view_path (ETreeSorted *ets,
- ETreePath model_path)
-{
- return find_or_create_path(ets, model_path);
-}
-
-int
-e_tree_sorted_orig_position (ETreeSorted *ets,
- ETreePath path)
-{
- ETreeSortedPath *sorted_path = path;
- return sorted_path->orig_position;
-}
-
-int
-e_tree_sorted_node_num_children (ETreeSorted *ets,
- ETreePath path)
-{
- ETreeSortedPath *sorted_path = path;
-
- if (sorted_path->num_children == -1) {
- generate_children(ets, sorted_path);
- }
-
- return sorted_path->num_children;
-}
-
-void
-e_tree_sorted_node_resorted (ETreeSorted *sorted, ETreePath node)
-{
- g_return_if_fail (sorted != NULL);
- g_return_if_fail (E_IS_TREE_SORTED (sorted));
-
- g_signal_emit (G_OBJECT (sorted), signals [NODE_RESORTED], 0, node);
-}
-
-void
-e_tree_sorted_set_sort_info (ETreeSorted *ets, ETableSortInfo *sort_info)
-{
-
- g_return_if_fail (ets != NULL);
-
-
- if (ets->priv->sort_info) {
- if (ets->priv->sort_info_changed_id != 0)
- g_signal_handler_disconnect (G_OBJECT (ets->priv->sort_info),
- ets->priv->sort_info_changed_id);
- ets->priv->sort_info_changed_id = 0;
- g_object_unref (ets->priv->sort_info);
- }
-
- ets->priv->sort_info = sort_info;
- if (sort_info) {
- g_object_ref(sort_info);
- ets->priv->sort_info_changed_id = g_signal_connect (G_OBJECT (ets->priv->sort_info), "sort_info_changed",
- G_CALLBACK (ets_sort_info_changed), ets);
- }
-
- if (ets->priv->root)
- schedule_resort (ets, ets->priv->root, TRUE, TRUE);
-}
-
-ETableSortInfo*
-e_tree_sorted_get_sort_info (ETreeSorted *ets)
-{
- return ets->priv->sort_info;
-}
-
diff --git a/widgets/table/e-tree-sorted.h b/widgets/table/e-tree-sorted.h
deleted file mode 100644
index 41f123dc0b..0000000000
--- a/widgets/table/e-tree-sorted.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-tree-sorted.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_TREE_SORTED_H_
-#define _E_TREE_SORTED_H_
-
-#include <gdk-pixbuf/gdk-pixbuf.h>
-#include <gal/e-table/e-tree-model.h>
-#include <gal/e-table/e-table-sort-info.h>
-#include <gal/e-table/e-table-header.h>
-
-G_BEGIN_DECLS
-
-#define E_TREE_SORTED_TYPE (e_tree_sorted_get_type ())
-#define E_TREE_SORTED(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TREE_SORTED_TYPE, ETreeSorted))
-#define E_TREE_SORTED_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TREE_SORTED_TYPE, ETreeSortedClass))
-#define E_IS_TREE_SORTED(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TREE_SORTED_TYPE))
-#define E_IS_TREE_SORTED_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TREE_SORTED_TYPE))
-#define E_TREE_SORTED_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), E_TREE_SORTED_TYPE, ETreeSortedClass))
-
-typedef struct ETreeSorted ETreeSorted;
-typedef struct ETreeSortedPriv ETreeSortedPriv;
-typedef struct ETreeSortedClass ETreeSortedClass;
-
-struct ETreeSorted {
- ETreeModel base;
-
- ETreeSortedPriv *priv;
-};
-
-struct ETreeSortedClass {
- ETreeModelClass parent_class;
-
- /* Signals */
- void (*node_resorted) (ETreeSorted *etm, ETreePath node);
-};
-
-
-GType e_tree_sorted_get_type (void);
-void e_tree_sorted_construct (ETreeSorted *etree,
- ETreeModel *source,
- ETableHeader *full_header,
- ETableSortInfo *sort_info);
-ETreeSorted *e_tree_sorted_new (ETreeModel *source,
- ETableHeader *full_header,
- ETableSortInfo *sort_info);
-
-ETreePath e_tree_sorted_view_to_model_path (ETreeSorted *ets,
- ETreePath view_path);
-ETreePath e_tree_sorted_model_to_view_path (ETreeSorted *ets,
- ETreePath model_path);
-int e_tree_sorted_orig_position (ETreeSorted *ets,
- ETreePath path);
-int e_tree_sorted_node_num_children (ETreeSorted *ets,
- ETreePath path);
-
-void e_tree_sorted_node_resorted (ETreeSorted *tree_model,
- ETreePath node);
-
-ETableSortInfo* e_tree_sorted_get_sort_info (ETreeSorted *tree_model);
-void e_tree_sorted_set_sort_info (ETreeSorted *tree_model,
- ETableSortInfo *sort_info);
-
-G_END_DECLS
-
-#endif /* _E_TREE_SORTED_H */
diff --git a/widgets/table/e-tree-table-adapter.c b/widgets/table/e-tree-table-adapter.c
deleted file mode 100644
index e1bda25eba..0000000000
--- a/widgets/table/e-tree-table-adapter.c
+++ /dev/null
@@ -1,1174 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-tree-table-adapter.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- * Chris Toshok <toshok@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdlib.h>
-#include <string.h>
-
-#include <libxml/tree.h>
-#include <libxml/parser.h>
-#include "gal/util/e-util.h"
-#include "gal/util/e-xml-utils.h"
-#include "e-tree-table-adapter.h"
-#include "e-table-sorting-utils.h"
-
-#define PARENT_TYPE E_TABLE_MODEL_TYPE
-#define d(x)
-
-#define INCREMENT_AMOUNT 100
-
-static ETableModelClass *parent_class;
-
-typedef struct {
- ETreePath path;
- guint32 num_visible_children;
- guint32 index;
-
- guint expanded : 1;
- guint expandable : 1;
- guint expandable_set : 1;
-} node_t;
-
-struct ETreeTableAdapterPriv {
- ETreeModel *source;
- ETableSortInfo *sort_info;
- ETableHeader *header;
-
- int n_map;
- int n_vals_allocated;
- node_t **map_table;
- GHashTable *nodes;
- GNode *root;
-
- guint root_visible : 1;
- guint remap_needed : 1;
-
- int last_access;
-
- int pre_change_id;
- int no_change_id;
- int node_changed_id;
- int node_data_changed_id;
- int node_col_changed_id;
- int node_inserted_id;
- int node_removed_id;
- int node_request_collapse_id;
- int sort_info_changed_id;
-};
-
-static GNode *
-lookup_gnode(ETreeTableAdapter *etta, ETreePath path)
-{
- GNode *gnode;
-
- if (!path)
- return NULL;
-
- gnode = g_hash_table_lookup(etta->priv->nodes, path);
-
- return gnode;
-}
-
-static void
-resize_map(ETreeTableAdapter *etta, int size)
-{
- if (size > etta->priv->n_vals_allocated) {
- etta->priv->n_vals_allocated = MAX(etta->priv->n_vals_allocated + INCREMENT_AMOUNT, size);
- etta->priv->map_table = g_renew (node_t *, etta->priv->map_table, etta->priv->n_vals_allocated);
- }
-
- etta->priv->n_map = size;
-}
-
-static void
-move_map_elements(ETreeTableAdapter *etta, int to, int from, int count)
-{
- if (count <= 0 || from >= etta->priv->n_map)
- return;
- memmove(etta->priv->map_table + to, etta->priv->map_table + from, count * sizeof (node_t *));
- etta->priv->remap_needed = TRUE;
-}
-
-static gint
-fill_map(ETreeTableAdapter *etta, gint index, GNode *gnode)
-{
- GNode *p;
-
- if ((gnode != etta->priv->root) || etta->priv->root_visible)
- etta->priv->map_table[index++] = gnode->data;
-
- for (p = gnode->children; p; p = p->next)
- index = fill_map(etta, index, p);
-
- etta->priv->remap_needed = TRUE;
- return index;
-}
-
-static void
-remap_indices(ETreeTableAdapter *etta)
-{
- int i;
- for (i = 0; i < etta->priv->n_map; i++)
- etta->priv->map_table[i]->index = i;
- etta->priv->remap_needed = FALSE;
-}
-
-static node_t *
-get_node(ETreeTableAdapter *etta, ETreePath path)
-{
- GNode *gnode = lookup_gnode(etta, path);
-
- if (!gnode)
- return NULL;
-
- return (node_t *)gnode->data;
-}
-
-static void
-resort_node(ETreeTableAdapter *etta, GNode *gnode, gboolean recurse)
-{
- node_t *node = (node_t *)gnode->data;
- ETreePath *paths, path;
- GNode *prev, *curr;
- int i, count;
- gboolean sort_needed;
-
- if (node->num_visible_children == 0)
- return;
-
- sort_needed = etta->priv->sort_info && e_table_sort_info_sorting_get_count (etta->priv->sort_info) > 0;
-
- for (i = 0, path = e_tree_model_node_get_first_child(etta->priv->source, node->path); path;
- path = e_tree_model_node_get_next(etta->priv->source, path), i++);
-
- count = i;
- if (count <= 1)
- return;
-
- paths = g_new0(ETreePath, count);
-
- for (i = 0, path = e_tree_model_node_get_first_child(etta->priv->source, node->path); path;
- path = e_tree_model_node_get_next(etta->priv->source, path), i++)
- paths[i] = path;
-
- if (count > 1 && sort_needed)
- e_table_sorting_utils_tree_sort(etta->priv->source, etta->priv->sort_info, etta->priv->header, paths, count);
-
- prev = NULL;
- for (i = 0; i < count; i++) {
- curr = lookup_gnode(etta, paths[i]);
- if (!curr)
- continue;
-
- if (prev)
- prev->next = curr;
- else
- gnode->children = curr;
-
- curr->prev = prev;
- curr->next = NULL;
- prev = curr;
- if (recurse)
- resort_node(etta, curr, recurse);
- }
-
- g_free(paths);
-}
-
-static gint
-get_row(ETreeTableAdapter *etta, ETreePath path)
-{
- node_t *node = get_node(etta, path);
- if (!node)
- return -1;
-
- if (etta->priv->remap_needed)
- remap_indices(etta);
-
- return node->index;
-}
-
-static ETreePath
-get_path (ETreeTableAdapter *etta, int row)
-{
- if (row == -1 && etta->priv->n_map > 0)
- row = etta->priv->n_map - 1;
- else if (row < 0 || row >= etta->priv->n_map)
- return NULL;
-
- return etta->priv->map_table [row]->path;
-}
-
-static void
-kill_gnode(GNode *node, ETreeTableAdapter *etta)
-{
- g_hash_table_remove(etta->priv->nodes, ((node_t *)node->data)->path);
-
- while (node->children) {
- GNode *next = node->children->next;
- kill_gnode(node->children, etta);
- node->children = next;
- }
-
- g_free(node->data);
- if (node == etta->priv->root)
- etta->priv->root = NULL;
- g_node_destroy(node);
-}
-
-static void
-update_child_counts(GNode *gnode, gint delta)
-{
- while (gnode) {
- node_t *node = (node_t *) gnode->data;
- node->num_visible_children += delta;
- gnode = gnode->parent;
- }
-}
-
-static int
-delete_children(ETreeTableAdapter *etta, GNode *gnode)
-{
- node_t *node = (node_t *)gnode->data;
- int to_remove = node ? node->num_visible_children : 0;
-
- if (to_remove == 0)
- return 0;
-
- while (gnode->children) {
- GNode *next = gnode->children->next;
- kill_gnode(gnode->children, etta);
- gnode->children = next;
- }
-
- return to_remove;
-}
-
-static void
-delete_node(ETreeTableAdapter *etta, ETreePath parent, ETreePath path)
-{
- int to_remove = 1;
- int parent_row = get_row(etta, parent);
- int row = get_row(etta, path);
- GNode *gnode = lookup_gnode(etta, path);
- GNode *parent_gnode = lookup_gnode(etta, parent);
-
- e_table_model_pre_change(E_TABLE_MODEL(etta));
-
- if (row == -1) {
- e_table_model_no_change(E_TABLE_MODEL(etta));
- return;
- }
-
- to_remove += delete_children(etta, gnode);
- kill_gnode(gnode, etta);
-
- move_map_elements(etta, row, row + to_remove, etta->priv->n_map - row - to_remove);
- resize_map(etta, etta->priv->n_map - to_remove);
-
- if (parent_gnode != NULL) {
- node_t *parent_node = parent_gnode->data;
- gboolean expandable = e_tree_model_node_is_expandable(etta->priv->source, parent);
-
- update_child_counts(parent_gnode, - to_remove);
- if (parent_node->expandable != expandable) {
- e_table_model_pre_change(E_TABLE_MODEL(etta));
- parent_node->expandable = expandable;
- e_table_model_row_changed(E_TABLE_MODEL(etta), parent_row);
- }
-
- resort_node (etta, parent_gnode, FALSE);
- }
-
- e_table_model_rows_deleted(E_TABLE_MODEL(etta), row, to_remove);
-}
-
-static GNode *
-create_gnode(ETreeTableAdapter *etta, ETreePath path)
-{
- GNode *gnode;
- node_t *node;
-
- node = g_new0(node_t, 1);
- node->path = path;
- node->index = -1;
- node->expanded = e_tree_model_get_expanded_default(etta->priv->source);
- node->expandable = e_tree_model_node_is_expandable(etta->priv->source, path);
- node->expandable_set = 1;
- node->num_visible_children = 0;
- gnode = g_node_new(node);
- g_hash_table_insert(etta->priv->nodes, path, gnode);
- return gnode;
-}
-
-static gint
-insert_children(ETreeTableAdapter *etta, GNode *gnode)
-{
- ETreePath path, tmp;
- int count = 0;
- int pos = 0;
-
- path = ((node_t *)gnode->data)->path;
- for (tmp = e_tree_model_node_get_first_child(etta->priv->source, path);
- tmp;
- tmp = e_tree_model_node_get_next(etta->priv->source, tmp), pos++) {
- GNode *child = create_gnode(etta, tmp);
- node_t *node = (node_t *) child->data;
- if (node->expanded)
- node->num_visible_children = insert_children(etta, child);
- g_node_prepend(gnode, child);
- count += node->num_visible_children + 1;
- }
- g_node_reverse_children(gnode);
- return count;
-}
-
-static void
-generate_tree(ETreeTableAdapter *etta, ETreePath path)
-{
- GNode *gnode;
- node_t *node;
- int size;
-
- e_table_model_pre_change(E_TABLE_MODEL(etta));
-
- g_assert(e_tree_model_node_is_root(etta->priv->source, path));
-
- if (etta->priv->root)
- kill_gnode(etta->priv->root, etta);
- resize_map(etta, 0);
-
- gnode = create_gnode(etta, path);
- node = (node_t *) gnode->data;
- node->expanded = TRUE;
- node->num_visible_children = insert_children(etta, gnode);
- if (etta->priv->sort_info && e_table_sort_info_sorting_get_count(etta->priv->sort_info) > 0)
- resort_node(etta, gnode, TRUE);
-
- etta->priv->root = gnode;
- size = etta->priv->root_visible ? node->num_visible_children + 1 : node->num_visible_children;
- resize_map(etta, size);
- fill_map(etta, 0, gnode);
- e_table_model_changed(E_TABLE_MODEL(etta));
-}
-
-static void
-insert_node(ETreeTableAdapter *etta, ETreePath parent, ETreePath path)
-{
- GNode *gnode, *parent_gnode;
- node_t *node, *parent_node;
- gboolean expandable;
- int size, row;
-
- e_table_model_pre_change(E_TABLE_MODEL(etta));
-
- if (get_node(etta, path)) {
- e_table_model_no_change(E_TABLE_MODEL(etta));
- return;
- }
-
- parent_gnode = lookup_gnode(etta, parent);
- if (!parent_gnode) {
- ETreePath grandparent = e_tree_model_node_get_parent(etta->priv->source, parent);
- if (e_tree_model_node_is_root(etta->priv->source, parent))
- generate_tree(etta, parent);
- else
- insert_node(etta, grandparent, parent);
- e_table_model_changed(E_TABLE_MODEL(etta));
- return;
- }
-
- parent_node = (node_t *) parent_gnode->data;
-
- if (parent_gnode != etta->priv->root) {
- expandable = e_tree_model_node_is_expandable(etta->priv->source, parent);
- if (parent_node->expandable != expandable) {
- e_table_model_pre_change(E_TABLE_MODEL(etta));
- parent_node->expandable = expandable;
- parent_node->expandable_set = 1;
- e_table_model_row_changed(E_TABLE_MODEL(etta), parent_node->index);
- }
- }
-
- if (!e_tree_table_adapter_node_is_expanded (etta, parent)) {
- e_table_model_no_change(E_TABLE_MODEL(etta));
- return;
- }
-
- gnode = create_gnode(etta, path);
- node = (node_t *) gnode->data;
-
- if (node->expanded)
- node->num_visible_children = insert_children(etta, gnode);
-
- g_node_append(parent_gnode, gnode);
- update_child_counts(parent_gnode, node->num_visible_children + 1);
- resort_node(etta, parent_gnode, FALSE);
- resort_node(etta, gnode, TRUE);
-
- size = node->num_visible_children + 1;
- resize_map(etta, etta->priv->n_map + size);
- if (parent_gnode == etta->priv->root)
- row = 0;
- else {
- gint new_size = parent_node->num_visible_children + 1;
- gint old_size = new_size - size;
- row = parent_node->index;
- move_map_elements(etta, row + new_size, row + old_size, etta->priv->n_map - row - new_size);
- }
- fill_map(etta, row, parent_gnode);
- e_table_model_rows_inserted(E_TABLE_MODEL(etta), get_row(etta, path), size);
-}
-
-typedef struct {
- GSList *paths;
- gboolean expanded;
-} check_expanded_closure;
-
-static gboolean
-check_expanded(GNode *gnode, gpointer data)
-{
- check_expanded_closure *closure = (check_expanded_closure *) data;
- node_t *node = (node_t *) gnode->data;
-
- if (node->expanded != closure->expanded)
- closure->paths = g_slist_prepend(closure->paths, node->path);
-
- return FALSE;
-}
-
-static void
-update_node(ETreeTableAdapter *etta, ETreePath path)
-{
- check_expanded_closure closure;
- ETreePath parent = e_tree_model_node_get_parent(etta->priv->source, path);
- GNode *gnode = lookup_gnode(etta, path);
- GSList *l;
-
- closure.expanded = e_tree_model_get_expanded_default (etta->priv->source);
- closure.paths = NULL;
-
- if (gnode)
- g_node_traverse(gnode, G_POST_ORDER, G_TRAVERSE_ALL, -1, check_expanded, &closure);
-
- if (e_tree_model_node_is_root(etta->priv->source, path))
- generate_tree(etta, path);
- else {
- delete_node(etta, parent, path);
- insert_node(etta, parent, path);
- }
-
- for (l = closure.paths; l; l = l->next)
- if (lookup_gnode(etta, l->data))
- e_tree_table_adapter_node_set_expanded (etta, l->data, !closure.expanded);
-
- g_slist_free(closure.paths);
-}
-
-static void
-etta_finalize (GObject *object)
-{
- ETreeTableAdapter *etta = E_TREE_TABLE_ADAPTER (object);
-
- if (etta->priv->root) {
- kill_gnode(etta->priv->root, etta);
- etta->priv->root = NULL;
- }
-
- g_hash_table_destroy (etta->priv->nodes);
-
- g_free (etta->priv->map_table);
-
- g_free (etta->priv);
-
- G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-static void
-etta_dispose (GObject *object)
-{
- ETreeTableAdapter *etta = E_TREE_TABLE_ADAPTER (object);
-
- if (etta->priv->sort_info) {
- g_signal_handler_disconnect(G_OBJECT (etta->priv->sort_info),
- etta->priv->sort_info_changed_id);
- g_object_unref(etta->priv->sort_info);
- etta->priv->sort_info = NULL;
- }
-
- if (etta->priv->header) {
- g_object_unref(etta->priv->header);
- etta->priv->header = NULL;
- }
-
- if (etta->priv->source) {
- g_signal_handler_disconnect (G_OBJECT (etta->priv->source),
- etta->priv->pre_change_id);
- g_signal_handler_disconnect (G_OBJECT (etta->priv->source),
- etta->priv->no_change_id);
- g_signal_handler_disconnect (G_OBJECT (etta->priv->source),
- etta->priv->node_changed_id);
- g_signal_handler_disconnect (G_OBJECT (etta->priv->source),
- etta->priv->node_data_changed_id);
- g_signal_handler_disconnect (G_OBJECT (etta->priv->source),
- etta->priv->node_col_changed_id);
- g_signal_handler_disconnect (G_OBJECT (etta->priv->source),
- etta->priv->node_inserted_id);
- g_signal_handler_disconnect (G_OBJECT (etta->priv->source),
- etta->priv->node_removed_id);
- g_signal_handler_disconnect (G_OBJECT (etta->priv->source),
- etta->priv->node_request_collapse_id);
-
- g_object_unref (etta->priv->source);
- etta->priv->source = NULL;
- }
-
- G_OBJECT_CLASS (parent_class)->dispose (object);
-}
-
-static int
-etta_column_count (ETableModel *etm)
-{
- ETreeTableAdapter *etta = (ETreeTableAdapter *)etm;
-
- return e_tree_model_column_count (etta->priv->source);
-}
-
-static gboolean
-etta_has_save_id (ETableModel *etm)
-{
- ETreeTableAdapter *etta = (ETreeTableAdapter *)etm;
-
- return e_tree_model_has_save_id (etta->priv->source);
-}
-
-static gchar *
-etta_get_save_id (ETableModel *etm, int row)
-{
- ETreeTableAdapter *etta = (ETreeTableAdapter *)etm;
-
- return e_tree_model_get_save_id (etta->priv->source, get_path(etta, row));
-}
-
-static gboolean
-etta_has_change_pending (ETableModel *etm)
-{
- ETreeTableAdapter *etta = (ETreeTableAdapter *)etm;
-
- return e_tree_model_has_change_pending (etta->priv->source);
-}
-
-
-static int
-etta_row_count (ETableModel *etm)
-{
- ETreeTableAdapter *etta = (ETreeTableAdapter *)etm;
-
- return etta->priv->n_map;
-}
-
-static void *
-etta_value_at (ETableModel *etm, int col, int row)
-{
- ETreeTableAdapter *etta = (ETreeTableAdapter *)etm;
-
- switch (col) {
- case -1:
- if (row == -1)
- return NULL;
- return get_path (etta, row);
- case -2:
- return etta->priv->source;
- case -3:
- return etta;
- default:
- return e_tree_model_value_at (etta->priv->source, get_path (etta, row), col);
- }
-}
-
-static void
-etta_set_value_at (ETableModel *etm, int col, int row, const void *val)
-{
- ETreeTableAdapter *etta = (ETreeTableAdapter *)etm;
-
- e_tree_model_set_value_at (etta->priv->source, get_path (etta, row), col, val);
-}
-
-static gboolean
-etta_is_cell_editable (ETableModel *etm, int col, int row)
-{
- ETreeTableAdapter *etta = (ETreeTableAdapter *)etm;
-
- return e_tree_model_node_is_editable (etta->priv->source, get_path (etta, row), col);
-}
-
-static void
-etta_append_row (ETableModel *etm, ETableModel *source, int row)
-{
-}
-
-static void *
-etta_duplicate_value (ETableModel *etm, int col, const void *value)
-{
- ETreeTableAdapter *etta = (ETreeTableAdapter *)etm;
-
- return e_tree_model_duplicate_value (etta->priv->source, col, value);
-}
-
-static void
-etta_free_value (ETableModel *etm, int col, void *value)
-{
- ETreeTableAdapter *etta = (ETreeTableAdapter *)etm;
-
- e_tree_model_free_value (etta->priv->source, col, value);
-}
-
-static void *
-etta_initialize_value (ETableModel *etm, int col)
-{
- ETreeTableAdapter *etta = (ETreeTableAdapter *)etm;
-
- return e_tree_model_initialize_value (etta->priv->source, col);
-}
-
-static gboolean
-etta_value_is_empty (ETableModel *etm, int col, const void *value)
-{
- ETreeTableAdapter *etta = (ETreeTableAdapter *)etm;
-
- return e_tree_model_value_is_empty (etta->priv->source, col, value);
-}
-
-static char *
-etta_value_to_string (ETableModel *etm, int col, const void *value)
-{
- ETreeTableAdapter *etta = (ETreeTableAdapter *)etm;
-
- return e_tree_model_value_to_string (etta->priv->source, col, value);
-}
-
-static void
-etta_class_init (ETreeTableAdapterClass *klass)
-{
- ETableModelClass *table_class = (ETableModelClass *) klass;
- GObjectClass *object_class = (GObjectClass *) klass;
-
- parent_class = g_type_class_peek_parent (klass);
-
- object_class->dispose = etta_dispose;
- object_class->finalize = etta_finalize;
-
- table_class->column_count = etta_column_count;
- table_class->row_count = etta_row_count;
- table_class->append_row = etta_append_row;
-
- table_class->value_at = etta_value_at;
- table_class->set_value_at = etta_set_value_at;
- table_class->is_cell_editable = etta_is_cell_editable;
-
- table_class->has_save_id = etta_has_save_id;
- table_class->get_save_id = etta_get_save_id;
-
- table_class->has_change_pending = etta_has_change_pending;
- table_class->duplicate_value = etta_duplicate_value;
- table_class->free_value = etta_free_value;
- table_class->initialize_value = etta_initialize_value;
- table_class->value_is_empty = etta_value_is_empty;
- table_class->value_to_string = etta_value_to_string;
-}
-
-static void
-etta_init (ETreeTableAdapter *etta)
-{
- etta->priv = g_new(ETreeTableAdapterPriv, 1);
-
- etta->priv->source = NULL;
- etta->priv->sort_info = NULL;
-
- etta->priv->n_map = 0;
- etta->priv->n_vals_allocated = 0;
- etta->priv->map_table = NULL;
- etta->priv->nodes = NULL;
- etta->priv->root = NULL;
-
- etta->priv->root_visible = TRUE;
- etta->priv->remap_needed = TRUE;
-
- etta->priv->pre_change_id = 0;
- etta->priv->no_change_id = 0;
- etta->priv->node_changed_id = 0;
- etta->priv->node_data_changed_id = 0;
- etta->priv->node_col_changed_id = 0;
- etta->priv->node_inserted_id = 0;
- etta->priv->node_removed_id = 0;
- etta->priv->node_request_collapse_id = 0;
-}
-
-E_MAKE_TYPE(e_tree_table_adapter, "ETreeTableAdapter", ETreeTableAdapter, etta_class_init, etta_init, PARENT_TYPE)
-
-static void
-etta_proxy_pre_change (ETreeModel *etm, ETreeTableAdapter *etta)
-{
- e_table_model_pre_change(E_TABLE_MODEL(etta));
-}
-
-static void
-etta_proxy_no_change (ETreeModel *etm, ETreeTableAdapter *etta)
-{
- e_table_model_no_change(E_TABLE_MODEL(etta));
-}
-
-static void
-etta_proxy_node_changed (ETreeModel *etm, ETreePath path, ETreeTableAdapter *etta)
-{
- update_node(etta, path);
-
- e_table_model_changed(E_TABLE_MODEL(etta));
-}
-
-static void
-etta_proxy_node_data_changed (ETreeModel *etm, ETreePath path, ETreeTableAdapter *etta)
-{
- int row = get_row(etta, path);
-
- if (row == -1) {
- e_table_model_no_change(E_TABLE_MODEL(etta));
- return;
- }
-
- e_table_model_row_changed(E_TABLE_MODEL(etta), row);
-}
-
-static void
-etta_proxy_node_col_changed (ETreeModel *etm, ETreePath path, int col, ETreeTableAdapter *etta)
-{
- int row = get_row(etta, path);
-
- if (row == -1) {
- e_table_model_no_change(E_TABLE_MODEL(etta));
- return;
- }
-
- e_table_model_cell_changed(E_TABLE_MODEL(etta), col, row);
-}
-
-static void
-etta_proxy_node_inserted (ETreeModel *etm, ETreePath parent, ETreePath child, ETreeTableAdapter *etta)
-{
- if (e_tree_model_node_is_root(etm, child))
- generate_tree(etta, child);
- else
- insert_node(etta, parent, child);
-
- e_table_model_changed(E_TABLE_MODEL(etta));
-}
-
-static void
-etta_proxy_node_removed (ETreeModel *etm, ETreePath parent, ETreePath child, int old_position, ETreeTableAdapter *etta)
-{
- delete_node(etta, parent, child);
- e_table_model_changed(E_TABLE_MODEL(etta));
-}
-
-static void
-etta_proxy_node_request_collapse (ETreeModel *etm, ETreePath node, ETreeTableAdapter *etta)
-{
- e_tree_table_adapter_node_set_expanded(etta, node, FALSE);
-}
-
-static void
-etta_sort_info_changed (ETableSortInfo *sort_info, ETreeTableAdapter *etta)
-{
- if (!etta->priv->root)
- return;
-
- e_table_model_pre_change(E_TABLE_MODEL(etta));
- resort_node(etta, etta->priv->root, TRUE);
- fill_map(etta, 0, etta->priv->root);
- e_table_model_changed(E_TABLE_MODEL(etta));
-}
-
-ETableModel *
-e_tree_table_adapter_construct (ETreeTableAdapter *etta, ETreeModel *source, ETableSortInfo *sort_info, ETableHeader *header)
-{
- ETreePath root;
-
- etta->priv->source = source;
- g_object_ref (source);
-
- etta->priv->sort_info = sort_info;
- if (sort_info) {
- g_object_ref(sort_info);
- etta->priv->sort_info_changed_id = g_signal_connect (G_OBJECT (sort_info), "sort_info_changed",
- G_CALLBACK (etta_sort_info_changed), etta);
- }
-
- etta->priv->header = header;
- if (header)
- g_object_ref(header);
-
- etta->priv->nodes = g_hash_table_new(NULL, NULL);
-
- root = e_tree_model_get_root (source);
-
- if (root)
- generate_tree(etta, root);
-
- etta->priv->pre_change_id = g_signal_connect(G_OBJECT(source), "pre_change",
- G_CALLBACK (etta_proxy_pre_change), etta);
- etta->priv->no_change_id = g_signal_connect (G_OBJECT (source), "no_change",
- G_CALLBACK (etta_proxy_no_change), etta);
- etta->priv->node_changed_id = g_signal_connect (G_OBJECT (source), "node_changed",
- G_CALLBACK (etta_proxy_node_changed), etta);
- etta->priv->node_data_changed_id = g_signal_connect (G_OBJECT (source), "node_data_changed",
- G_CALLBACK (etta_proxy_node_data_changed), etta);
- etta->priv->node_col_changed_id = g_signal_connect (G_OBJECT (source), "node_col_changed",
- G_CALLBACK (etta_proxy_node_col_changed), etta);
- etta->priv->node_inserted_id = g_signal_connect (G_OBJECT (source), "node_inserted",
- G_CALLBACK (etta_proxy_node_inserted), etta);
- etta->priv->node_removed_id = g_signal_connect (G_OBJECT (source), "node_removed",
- G_CALLBACK (etta_proxy_node_removed), etta);
- etta->priv->node_request_collapse_id = g_signal_connect (G_OBJECT (source), "node_request_collapse",
- G_CALLBACK (etta_proxy_node_request_collapse), etta);
-
- return E_TABLE_MODEL (etta);
-}
-
-ETableModel *
-e_tree_table_adapter_new (ETreeModel *source, ETableSortInfo *sort_info, ETableHeader *header)
-{
- ETreeTableAdapter *etta = g_object_new (E_TREE_TABLE_ADAPTER_TYPE, NULL);
-
- e_tree_table_adapter_construct (etta, source, sort_info, header);
-
- return (ETableModel *) etta;
-}
-
-typedef struct {
- xmlNode *root;
- gboolean expanded_default;
- ETreeModel *model;
-} TreeAndRoot;
-
-static void
-save_expanded_state_func (gpointer keyp, gpointer value, gpointer data)
-{
- ETreePath path = keyp;
- node_t *node = ((GNode *)value)->data;
- TreeAndRoot *tar = data;
- xmlNode *xmlnode;
-
- if (node->expanded != tar->expanded_default) {
- gchar *save_id = e_tree_model_get_save_id(tar->model, path);
- xmlnode = xmlNewChild (tar->root, NULL, "node", NULL);
- e_xml_set_string_prop_by_name(xmlnode, "id", save_id);
- g_free(save_id);
- }
-}
-
-void
-e_tree_table_adapter_save_expanded_state (ETreeTableAdapter *etta, const char *filename)
-{
- TreeAndRoot tar;
- xmlDocPtr doc;
- xmlNode *root;
-
- g_return_if_fail(etta != NULL);
-
- doc = xmlNewDoc ("1.0");
- root = xmlNewDocNode (doc, NULL, (xmlChar *) "expanded_state", NULL);
- xmlDocSetRootElement (doc, root);
-
- tar.model = etta->priv->source;
- tar.root = root;
- tar.expanded_default = e_tree_model_get_expanded_default(etta->priv->source);
-
- e_xml_set_integer_prop_by_name (root, "vers", 2);
- e_xml_set_bool_prop_by_name (root, "default", tar.expanded_default);
-
- g_hash_table_foreach (etta->priv->nodes, save_expanded_state_func, &tar);
-
- e_xml_save_file (filename, doc);
- xmlFreeDoc (doc);
-}
-
-static xmlDoc *
-open_file (ETreeTableAdapter *etta, const char *filename)
-{
- xmlDoc *doc;
- xmlNode *root;
- int vers;
- gboolean model_default, saved_default;
-
- if (!g_file_test (filename, G_FILE_TEST_EXISTS))
- return NULL;
-
- doc = xmlParseFile (filename);
- if (!doc)
- return NULL;
-
- root = xmlDocGetRootElement (doc);
- if (root == NULL || strcmp (root->name, "expanded_state")) {
- xmlFreeDoc (doc);
- return NULL;
- }
-
- vers = e_xml_get_integer_prop_by_name_with_default (root, "vers", 0);
- if (vers > 2) {
- xmlFreeDoc (doc);
- return NULL;
- }
- model_default = e_tree_model_get_expanded_default (etta->priv->source);
- saved_default = e_xml_get_bool_prop_by_name_with_default (root, "default", !model_default);
- if (saved_default != model_default) {
- xmlFreeDoc (doc);
- return NULL;
- }
-
- return doc;
-}
-
-void
-e_tree_table_adapter_load_expanded_state (ETreeTableAdapter *etta, const char *filename)
-{
- xmlDoc *doc;
- xmlNode *root, *child;
- gboolean model_default;
-
- g_return_if_fail(etta != NULL);
-
- doc = open_file(etta, filename);
- if (!doc)
- return;
-
- root = xmlDocGetRootElement (doc);
-
- e_table_model_pre_change(E_TABLE_MODEL(etta));
-
- model_default = e_tree_model_get_expanded_default(etta->priv->source);
-
- for (child = root->xmlChildrenNode; child; child = child->next) {
- char *id;
- ETreePath path;
-
- if (strcmp (child->name, "node")) {
- d(g_warning ("unknown node '%s' in %s", child->name, filename));
- continue;
- }
-
- id = e_xml_get_string_prop_by_name_with_default (child, "id", "");
-
- if (!strcmp(id, "")) {
- g_free(id);
- continue;
- }
-
- path = e_tree_model_get_node_by_id(etta->priv->source, id);
- if (path)
- e_tree_table_adapter_node_set_expanded(etta, path, !model_default);
-
- g_free (id);
- }
-
- xmlFreeDoc (doc);
-
- e_table_model_changed (E_TABLE_MODEL (etta));
-}
-
-void
-e_tree_table_adapter_root_node_set_visible (ETreeTableAdapter *etta, gboolean visible)
-{
- int size;
-
- if (etta->priv->root_visible == visible)
- return;
-
- e_table_model_pre_change (E_TABLE_MODEL(etta));
-
- etta->priv->root_visible = visible;
- if (!visible) {
- ETreePath root = e_tree_model_get_root(etta->priv->source);
- if (root)
- e_tree_table_adapter_node_set_expanded(etta, root, TRUE);
- }
- size = (visible ? 1 : 0) + (etta->priv->root ? ((node_t *)etta->priv->root->data)->num_visible_children : 0);
- resize_map(etta, size);
- if (etta->priv->root)
- fill_map(etta, 0, etta->priv->root);
- e_table_model_changed(E_TABLE_MODEL(etta));
-}
-
-void
-e_tree_table_adapter_node_set_expanded (ETreeTableAdapter *etta, ETreePath path, gboolean expanded)
-{
- GNode *gnode = lookup_gnode(etta, path);
- node_t *node;
- int row;
-
- if (!expanded && (!gnode || (e_tree_model_node_is_root (etta->priv->source, path) && !etta->priv->root_visible)))
- return;
-
- if (!gnode && expanded) {
- ETreePath parent = e_tree_model_node_get_parent(etta->priv->source, path);
- g_return_if_fail(parent != NULL);
- e_tree_table_adapter_node_set_expanded(etta, parent, expanded);
- gnode = lookup_gnode(etta, path);
- }
- g_return_if_fail(gnode != NULL);
-
- node = (node_t *) gnode->data;
-
- if (expanded == node->expanded)
- return;
-
- node->expanded = expanded;
-
- row = get_row(etta, path);
- if (row == -1)
- return;
-
- e_table_model_pre_change (E_TABLE_MODEL(etta));
- e_table_model_pre_change (E_TABLE_MODEL(etta));
- e_table_model_row_changed(E_TABLE_MODEL(etta), row);
-
-
- if (expanded) {
- int num_children = insert_children(etta, gnode);
- update_child_counts(gnode, num_children);
- if (etta->priv->sort_info && e_table_sort_info_sorting_get_count(etta->priv->sort_info) > 0)
- resort_node(etta, gnode, TRUE);
- resize_map(etta, etta->priv->n_map + num_children);
- move_map_elements(etta, row + 1 + num_children, row + 1, etta->priv->n_map - row - 1 - num_children);
- fill_map(etta, row, gnode);
- if (num_children != 0) {
- e_table_model_rows_inserted(E_TABLE_MODEL(etta), row + 1, num_children);
- } else
- e_table_model_no_change(E_TABLE_MODEL(etta));
- } else {
- int num_children = delete_children(etta, gnode);
- if (num_children == 0) {
- e_table_model_no_change(E_TABLE_MODEL(etta));
- return;
- }
- move_map_elements(etta, row + 1, row + 1 + num_children, etta->priv->n_map - row - 1 - num_children);
- update_child_counts(gnode, - num_children);
- resize_map(etta, etta->priv->n_map - num_children);
- e_table_model_rows_deleted(E_TABLE_MODEL(etta), row + 1, num_children);
- }
-}
-
-void
-e_tree_table_adapter_node_set_expanded_recurse (ETreeTableAdapter *etta, ETreePath path, gboolean expanded)
-{
- ETreePath children;
-
- e_tree_table_adapter_node_set_expanded(etta, path, expanded);
-
- for (children = e_tree_model_node_get_first_child(etta->priv->source, path);
- children;
- children = e_tree_model_node_get_next(etta->priv->source, children)) {
- e_tree_table_adapter_node_set_expanded_recurse(etta, children, expanded);
- }
-}
-
-ETreePath
-e_tree_table_adapter_node_at_row (ETreeTableAdapter *etta, int row)
-{
- return get_path(etta, row);
-}
-
-int
-e_tree_table_adapter_row_of_node (ETreeTableAdapter *etta, ETreePath path)
-{
- return get_row(etta, path);
-}
-
-gboolean
-e_tree_table_adapter_root_node_is_visible(ETreeTableAdapter *etta)
-{
- return etta->priv->root_visible;
-}
-
-void
-e_tree_table_adapter_show_node (ETreeTableAdapter *etta, ETreePath path)
-{
- ETreePath parent;
-
- parent = e_tree_model_node_get_parent(etta->priv->source, path);
-
- while (parent) {
- e_tree_table_adapter_node_set_expanded(etta, parent, TRUE);
- parent = e_tree_model_node_get_parent(etta->priv->source, parent);
- }
-}
-
-gboolean
-e_tree_table_adapter_node_is_expanded (ETreeTableAdapter *etta, ETreePath path)
-{
- node_t *node = get_node(etta, path);
- if (!e_tree_model_node_is_expandable (etta->priv->source, path) || !node)
- return FALSE;
-
- return node->expanded;
-}
-
-void
-e_tree_table_adapter_set_sort_info (ETreeTableAdapter *etta, ETableSortInfo *sort_info)
-{
- if (etta->priv->sort_info) {
- g_signal_handler_disconnect(G_OBJECT(etta->priv->sort_info),
- etta->priv->sort_info_changed_id);
- g_object_unref(etta->priv->sort_info);
- }
-
- etta->priv->sort_info = sort_info;
- if (sort_info) {
- g_object_ref(sort_info);
- etta->priv->sort_info_changed_id = g_signal_connect(G_OBJECT(sort_info), "sort_info_changed",
- G_CALLBACK(etta_sort_info_changed), etta);
- }
-
- if (!etta->priv->root)
- return;
-
- e_table_model_pre_change(E_TABLE_MODEL(etta));
- resort_node(etta, etta->priv->root, TRUE);
- fill_map(etta, 0, etta->priv->root);
- e_table_model_changed(E_TABLE_MODEL(etta));
-}
-
-ETreePath
-e_tree_table_adapter_node_get_next (ETreeTableAdapter *etta, ETreePath path)
-{
- GNode *node = lookup_gnode (etta, path);
-
- if (node && node->next)
- return ((node_t *)node->next->data)->path;
-
- return NULL;
-}
diff --git a/widgets/table/e-tree-table-adapter.h b/widgets/table/e-tree-table-adapter.h
deleted file mode 100644
index 8ce1c78097..0000000000
--- a/widgets/table/e-tree-table-adapter.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-tree-table-adapter.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- * Chris Toshok <toshok@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_TREE_TABLE_ADAPTER_H_
-#define _E_TREE_TABLE_ADAPTER_H_
-
-#include <glib-object.h>
-#include <gal/e-table/e-table-model.h>
-#include <gal/e-table/e-tree-model.h>
-#include <gal/e-table/e-table-sort-info.h>
-#include <gal/e-table/e-table-header.h>
-
-G_BEGIN_DECLS
-
-#define E_TREE_TABLE_ADAPTER_TYPE (e_tree_table_adapter_get_type ())
-#define E_TREE_TABLE_ADAPTER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TREE_TABLE_ADAPTER_TYPE, ETreeTableAdapter))
-#define E_TREE_TABLE_ADAPTER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TREE_TABLE_ADAPTER_TYPE, ETreeTableAdapterClass))
-#define E_IS_TREE_TABLE_ADAPTER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TREE_TABLE_ADAPTER_TYPE))
-#define E_IS_TREE_TABLE_ADAPTER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TREE_TABLE_ADAPTER_TYPE))
-#define E_TREE_TABLE_ADAPTER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TREE_TABLE_ADAPTER_TYPE, ETreeTableAdapterClass))
-
-typedef struct ETreeTableAdapterPriv ETreeTableAdapterPriv;
-
-typedef struct {
- ETableModel base;
-
- ETreeTableAdapterPriv *priv;
-} ETreeTableAdapter;
-
-typedef struct {
- ETableModelClass parent_class;
-} ETreeTableAdapterClass;
-
-GType e_tree_table_adapter_get_type (void);
-ETableModel *e_tree_table_adapter_new (ETreeModel *source,
- ETableSortInfo *sort_info,
- ETableHeader *header);
-ETableModel *e_tree_table_adapter_construct (ETreeTableAdapter *ets,
- ETreeModel *source,
- ETableSortInfo *sort_info,
- ETableHeader *header);
-
-ETreePath e_tree_table_adapter_node_get_next (ETreeTableAdapter *etta,
- ETreePath path);
-gboolean e_tree_table_adapter_node_is_expanded (ETreeTableAdapter *etta,
- ETreePath path);
-void e_tree_table_adapter_node_set_expanded (ETreeTableAdapter *etta,
- ETreePath path,
- gboolean expanded);
-void e_tree_table_adapter_node_set_expanded_recurse (ETreeTableAdapter *etta,
- ETreePath path,
- gboolean expanded);
-void e_tree_table_adapter_root_node_set_visible (ETreeTableAdapter *etta,
- gboolean visible);
-ETreePath e_tree_table_adapter_node_at_row (ETreeTableAdapter *etta,
- int row);
-int e_tree_table_adapter_row_of_node (ETreeTableAdapter *etta,
- ETreePath path);
-gboolean e_tree_table_adapter_root_node_is_visible (ETreeTableAdapter *etta);
-
-void e_tree_table_adapter_show_node (ETreeTableAdapter *etta,
- ETreePath path);
-
-void e_tree_table_adapter_save_expanded_state (ETreeTableAdapter *etta,
- const char *filename);
-void e_tree_table_adapter_load_expanded_state (ETreeTableAdapter *etta,
- const char *filename);
-
-void e_tree_table_adapter_set_sort_info (ETreeTableAdapter *etta,
- ETableSortInfo *sort_info);
-
-G_END_DECLS
-
-#endif /* _E_TREE_TABLE_ADAPTER_H_ */
diff --git a/widgets/table/e-tree.c b/widgets/table/e-tree.c
deleted file mode 100644
index fa3dafa2fa..0000000000
--- a/widgets/table/e-tree.c
+++ /dev/null
@@ -1,3324 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-tree.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdio.h>
-#include <gdk/gdkkeysyms.h>
-#include <gtk/gtksignal.h>
-#include <libgnomecanvas/gnome-canvas-rect-ellipse.h>
-#include <atk/atkregistry.h>
-
-#include <gal/util/e-i18n.h>
-#include <gal/util/e-util.h>
-#include <gal/util/e-marshal.h>
-#include <gal/widgets/e-canvas.h>
-#include <gal/widgets/e-canvas-background.h>
-
-#include <gal/e-table/e-table-column-specification.h>
-#include <gal/e-table/e-table-header-item.h>
-#include <gal/e-table/e-table-header.h>
-#include <gal/e-table/e-table-item.h>
-#include <gal/e-table/e-table-sort-info.h>
-#include <gal/e-table/e-table-utils.h>
-
-#ifdef E_TREE_USE_TREE_SELECTION
-#include <gal/e-table/e-tree-selection-model.h>
-#else
-#include <gal/e-table/e-table-selection-model.h>
-#endif
-
-#include <gal/e-table/e-tree-table-adapter.h>
-
-#include "e-tree.h"
-#include "gal/util/e-marshal.h"
-#include "gal/a11y/e-table/gal-a11y-e-tree.h"
-
-#define COLUMN_HEADER_HEIGHT 16
-
-#define PARENT_TYPE gtk_table_get_type ()
-
-static GtkObjectClass *parent_class;
-
-#define d(x)
-
-#if d(!)0
-#define e_table_item_leave_edit_(x) (e_table_item_leave_edit((x)), g_print ("%s: e_table_item_leave_edit\n", __FUNCTION__))
-#else
-#define e_table_item_leave_edit_(x) (e_table_item_leave_edit((x)))
-#endif
-
-enum {
- CURSOR_CHANGE,
- CURSOR_ACTIVATED,
- SELECTION_CHANGE,
- DOUBLE_CLICK,
- RIGHT_CLICK,
- CLICK,
- KEY_PRESS,
- START_DRAG,
- STATE_CHANGE,
- WHITE_SPACE_EVENT,
-
- TREE_DRAG_BEGIN,
- TREE_DRAG_END,
- TREE_DRAG_DATA_GET,
- TREE_DRAG_DATA_DELETE,
-
- TREE_DRAG_LEAVE,
- TREE_DRAG_MOTION,
- TREE_DRAG_DROP,
- TREE_DRAG_DATA_RECEIVED,
-
- LAST_SIGNAL
-};
-
-enum {
- PROP_0,
- PROP_LENGTH_THRESHOLD,
- PROP_HORIZONTAL_DRAW_GRID,
- PROP_VERTICAL_DRAW_GRID,
- PROP_DRAW_FOCUS,
- PROP_ETTA,
- PROP_UNIFORM_ROW_HEIGHT,
- PROP_ALWAYS_SEARCH
-};
-
-enum {
- ET_SCROLL_UP = 1 << 0,
- ET_SCROLL_DOWN = 1 << 1,
- ET_SCROLL_LEFT = 1 << 2,
- ET_SCROLL_RIGHT = 1 << 3
-};
-
-struct ETreePriv {
- ETreeModel *model;
- ETreeTableAdapter *etta;
-
- ETableHeader *full_header, *header;
-
- guint structure_change_id, expansion_change_id;
-
- ETableSortInfo *sort_info;
- ESorter *sorter;
-
- guint sort_info_change_id, group_info_change_id;
-
- ESelectionModel *selection;
- ETableSpecification *spec;
-
- ETableSearch *search;
-
- ETableCol *current_search_col;
-
- guint search_search_id;
- guint search_accept_id;
-
- int reflow_idle_id;
- int scroll_idle_id;
- int hover_idle_id;
-
- int table_model_change_id;
- int table_row_change_id;
- int table_cell_change_id;
-
- GnomeCanvas *header_canvas, *table_canvas;
-
- GnomeCanvasItem *header_item, *root;
-
- GnomeCanvasItem *white_item;
- GnomeCanvasItem *item;
-
- gint length_threshold;
-
- /*
- * Configuration settings
- */
- guint alternating_row_colors : 1;
- guint horizontal_draw_grid : 1;
- guint vertical_draw_grid : 1;
- guint draw_focus : 1;
- guint row_selection_active : 1;
-
- guint horizontal_scrolling : 1;
-
- guint scroll_direction : 4;
-
- guint do_drag : 1;
-
- guint uniform_row_height : 1;
-
- guint search_col_set : 1;
- guint always_search : 1;
-
- ECursorMode cursor_mode;
-
- int drop_row;
- ETreePath drop_path;
- int drop_col;
-
- GnomeCanvasItem *drop_highlight;
- int last_drop_x;
- int last_drop_y;
- int last_drop_time;
- GdkDragContext *last_drop_context;
-
- int hover_x;
- int hover_y;
-
- int drag_row;
- ETreePath drag_path;
- int drag_col;
- ETreeDragSourceSite *site;
-
- GList *expanded_list;
-};
-
-static guint et_signals [LAST_SIGNAL] = { 0, };
-
-static void et_grab_focus (GtkWidget *widget);
-
-static void et_drag_begin (GtkWidget *widget,
- GdkDragContext *context,
- ETree *et);
-static void et_drag_end (GtkWidget *widget,
- GdkDragContext *context,
- ETree *et);
-static void et_drag_data_get(GtkWidget *widget,
- GdkDragContext *context,
- GtkSelectionData *selection_data,
- guint info,
- guint time,
- ETree *et);
-static void et_drag_data_delete(GtkWidget *widget,
- GdkDragContext *context,
- ETree *et);
-
-static void et_drag_leave(GtkWidget *widget,
- GdkDragContext *context,
- guint time,
- ETree *et);
-static gboolean et_drag_motion(GtkWidget *widget,
- GdkDragContext *context,
- gint x,
- gint y,
- guint time,
- ETree *et);
-static gboolean et_drag_drop(GtkWidget *widget,
- GdkDragContext *context,
- gint x,
- gint y,
- guint time,
- ETree *et);
-static void et_drag_data_received(GtkWidget *widget,
- GdkDragContext *context,
- gint x,
- gint y,
- GtkSelectionData *selection_data,
- guint info,
- guint time,
- ETree *et);
-
-
-static void scroll_off (ETree *et);
-static void scroll_on (ETree *et, guint scroll_direction);
-static void hover_off (ETree *et);
-static void hover_on (ETree *et, int x, int y);
-static void context_destroyed (gpointer data, GObject *ctx);
-
-static void
-et_disconnect_from_etta (ETree *et)
-{
- if (et->priv->table_model_change_id != 0)
- g_signal_handler_disconnect (G_OBJECT (et->priv->etta),
- et->priv->table_model_change_id);
- if (et->priv->table_row_change_id != 0)
- g_signal_handler_disconnect (G_OBJECT (et->priv->etta),
- et->priv->table_row_change_id);
- if (et->priv->table_cell_change_id != 0)
- g_signal_handler_disconnect (G_OBJECT (et->priv->etta),
- et->priv->table_cell_change_id);
-
- et->priv->table_model_change_id = 0;
- et->priv->table_row_change_id = 0;
- et->priv->table_cell_change_id = 0;
-}
-
-static void
-clear_current_search_col (ETree *et)
-{
- et->priv->search_col_set = FALSE;
-}
-
-static ETableCol *
-current_search_col (ETree *et)
-{
- if (!et->priv->search_col_set) {
- et->priv->current_search_col =
- e_table_util_calculate_current_search_col (et->priv->header,
- et->priv->full_header,
- et->priv->sort_info,
- et->priv->always_search);
- et->priv->search_col_set = TRUE;
- }
-
- return et->priv->current_search_col;
-}
-
-static void
-e_tree_state_change (ETree *et)
-{
- g_signal_emit (G_OBJECT (et), et_signals [STATE_CHANGE], 0);
-}
-
-static void
-change_trigger (GtkObject *object, ETree *et)
-{
- e_tree_state_change (et);
-}
-
-static void
-search_col_change_trigger (GtkObject *object, ETree *et)
-{
- clear_current_search_col (et);
- e_tree_state_change (et);
-}
-
-static void
-disconnect_header (ETree *e_tree)
-{
- if (e_tree->priv->header == NULL)
- return;
-
- if (e_tree->priv->structure_change_id)
- g_signal_handler_disconnect (G_OBJECT (e_tree->priv->header),
- e_tree->priv->structure_change_id);
- if (e_tree->priv->expansion_change_id)
- g_signal_handler_disconnect (G_OBJECT (e_tree->priv->header),
- e_tree->priv->expansion_change_id);
- if (e_tree->priv->sort_info) {
- if (e_tree->priv->sort_info_change_id)
- g_signal_handler_disconnect (G_OBJECT (e_tree->priv->sort_info),
- e_tree->priv->sort_info_change_id);
- if (e_tree->priv->group_info_change_id)
- g_signal_handler_disconnect (G_OBJECT (e_tree->priv->sort_info),
- e_tree->priv->group_info_change_id);
-
- g_object_unref(e_tree->priv->sort_info);
- }
- g_object_unref(e_tree->priv->header);
- e_tree->priv->header = NULL;
- e_tree->priv->sort_info = NULL;
-}
-
-static void
-connect_header (ETree *e_tree, ETableState *state)
-{
- GValue *val = g_new0 (GValue, 1);
-
- if (e_tree->priv->header != NULL)
- disconnect_header (e_tree);
-
- e_tree->priv->header = e_table_state_to_header (GTK_WIDGET(e_tree), e_tree->priv->full_header, state);
-
- e_tree->priv->structure_change_id =
- g_signal_connect (G_OBJECT (e_tree->priv->header), "structure_change",
- G_CALLBACK (search_col_change_trigger), e_tree);
- e_tree->priv->expansion_change_id =
- g_signal_connect (G_OBJECT (e_tree->priv->header), "expansion_change",
- G_CALLBACK (change_trigger), e_tree);
-
- if (state->sort_info) {
- e_tree->priv->sort_info = e_table_sort_info_duplicate(state->sort_info);
- e_table_sort_info_set_can_group (e_tree->priv->sort_info, FALSE);
- e_tree->priv->sort_info_change_id =
- g_signal_connect (G_OBJECT (e_tree->priv->sort_info), "sort_info_changed",
- G_CALLBACK (search_col_change_trigger), e_tree);
- e_tree->priv->group_info_change_id =
- g_signal_connect (G_OBJECT (e_tree->priv->sort_info), "group_info_changed",
- G_CALLBACK (search_col_change_trigger), e_tree);
- } else
- e_tree->priv->sort_info = NULL;
-
- g_value_init (val, G_TYPE_OBJECT);
- g_value_set_object (val, e_tree->priv->sort_info);
- g_object_set_property (G_OBJECT(e_tree->priv->header), "sort_info", val);
- g_free (val);
-}
-
-static void
-et_dispose (GObject *object)
-{
- ETree *et = E_TREE (object);
-
- if (et->priv) {
-
- if (et->priv->search) {
- if (et->priv->search_search_id)
- g_signal_handler_disconnect (et->priv->search,
- et->priv->search_search_id);
- if (et->priv->search_accept_id)
- g_signal_handler_disconnect (et->priv->search,
- et->priv->search_accept_id);
- g_object_unref (et->priv->search);
- }
-
- if (et->priv->reflow_idle_id)
- g_source_remove(et->priv->reflow_idle_id);
- et->priv->reflow_idle_id = 0;
-
- scroll_off (et);
- hover_off (et);
- e_free_string_list (et->priv->expanded_list);
-
- et_disconnect_from_etta (et);
-
- g_object_unref (et->priv->etta);
- g_object_unref (et->priv->model);
- g_object_unref (et->priv->full_header);
- disconnect_header (et);
- g_object_unref (et->priv->selection);
- if (et->priv->spec)
- g_object_unref (et->priv->spec);
- et->priv->spec = NULL;
-
- if (et->priv->sorter)
- g_object_unref (et->priv->sorter);
- et->priv->sorter = NULL;
-
- if (et->priv->header_canvas)
- gtk_widget_destroy (GTK_WIDGET (et->priv->header_canvas));
- et->priv->header_canvas = NULL;
-
- if (et->priv->site)
- e_tree_drag_source_unset (et);
-
- if (et->priv->last_drop_context)
- g_object_weak_unref (G_OBJECT(et->priv->last_drop_context), context_destroyed, et);
- et->priv->last_drop_context = NULL;
-
- gtk_widget_destroy (GTK_WIDGET (et->priv->table_canvas));
-
- g_free(et->priv);
- et->priv = NULL;
- }
-
- if (G_OBJECT_CLASS (parent_class)->dispose)
- G_OBJECT_CLASS (parent_class)->dispose (object);
-}
-
-static void
-et_unrealize (GtkWidget *widget)
-{
- scroll_off (E_TREE (widget));
- hover_off (E_TREE (widget));
-
- if (GTK_WIDGET_CLASS (parent_class)->unrealize)
- GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
-}
-
-typedef struct {
- ETree *et;
- char *string;
-} SearchSearchStruct;
-
-static gboolean
-search_search_callback (ETreeModel *model, ETreePath path, gpointer data)
-{
- SearchSearchStruct *cb_data = data;
- const void *value;
- ETableCol *col = current_search_col (cb_data->et);
-
- value = e_tree_model_value_at (model, path, cb_data->et->priv->current_search_col->col_idx);
-
- return col->search (value, cb_data->string);
-}
-
-static gboolean
-et_search_search (ETableSearch *search, char *string, ETableSearchFlags flags, ETree *et)
-{
- ETreePath cursor;
- ETreePath found;
- SearchSearchStruct cb_data;
- ETableCol *col = current_search_col (et);
-
- if (col == NULL)
- return FALSE;
-
- cb_data.et = et;
- cb_data.string = string;
-
- cursor = e_tree_get_cursor (et);
-
- if (cursor && (flags & E_TABLE_SEARCH_FLAGS_CHECK_CURSOR_FIRST)) {
- const void *value;
-
- value = e_tree_model_value_at (et->priv->model, cursor, col->col_idx);
-
- if (col->search (value, string)) {
- return TRUE;
- }
- }
-
- found = e_tree_model_node_find (et->priv->model, cursor, NULL, E_TREE_FIND_NEXT_FORWARD, search_search_callback, &cb_data);
- if (found == NULL)
- found = e_tree_model_node_find (et->priv->model, NULL, cursor, E_TREE_FIND_NEXT_FORWARD, search_search_callback, &cb_data);
-
- if (found && found != cursor) {
- int model_row;
-
- e_tree_table_adapter_show_node (et->priv->etta, found);
- model_row = e_tree_table_adapter_row_of_node (et->priv->etta, found);
-
- cursor = found;
-
- e_selection_model_select_as_key_press(E_SELECTION_MODEL (et->priv->selection), model_row, col->col_idx, GDK_CONTROL_MASK);
- return TRUE;
- } else if (cursor && !(flags & E_TABLE_SEARCH_FLAGS_CHECK_CURSOR_FIRST)) {
- const void *value;
-
- value = e_tree_model_value_at (et->priv->model, cursor, col->col_idx);
-
- return col->search (value, string);
- } else
- return FALSE;
-}
-
-static void
-et_search_accept (ETableSearch *search, ETree *et)
-{
- ETableCol *col = current_search_col (et);
- int cursor;
-
- if (col == NULL)
- return;
-
- g_object_get(et->priv->selection,
- "cursor_row", &cursor,
- NULL);
- e_selection_model_select_as_key_press(E_SELECTION_MODEL (et->priv->selection), cursor, col->col_idx, 0);
-}
-
-static void
-e_tree_init (GtkObject *object)
-{
- ETree *e_tree = E_TREE (object);
- GtkTable *gtk_table = GTK_TABLE (object);
-
- GTK_WIDGET_SET_FLAGS (e_tree, GTK_CAN_FOCUS);
-
- gtk_table->homogeneous = FALSE;
-
- e_tree->priv = g_new(ETreePriv, 1);
-
- e_tree->priv->model = NULL;
- e_tree->priv->etta = NULL;
-
- e_tree->priv->full_header = NULL;
- e_tree->priv->header = NULL;
-
- e_tree->priv->structure_change_id = 0;
- e_tree->priv->expansion_change_id = 0;
- e_tree->priv->sort_info_change_id = 0;
- e_tree->priv->group_info_change_id = 0;
-
- e_tree->priv->sort_info = NULL;
- e_tree->priv->sorter = NULL;
- e_tree->priv->reflow_idle_id = 0;
- e_tree->priv->scroll_idle_id = 0;
- e_tree->priv->hover_idle_id = 0;
-
- e_tree->priv->table_model_change_id = 0;
- e_tree->priv->table_row_change_id = 0;
- e_tree->priv->table_cell_change_id = 0;
-
- e_tree->priv->alternating_row_colors = 1;
- e_tree->priv->horizontal_draw_grid = 1;
- e_tree->priv->vertical_draw_grid = 1;
- e_tree->priv->draw_focus = 1;
- e_tree->priv->cursor_mode = E_CURSOR_SIMPLE;
- e_tree->priv->length_threshold = 200;
- e_tree->priv->uniform_row_height = FALSE;
-
- e_tree->priv->row_selection_active = FALSE;
- e_tree->priv->horizontal_scrolling = FALSE;
- e_tree->priv->scroll_direction = 0;
-
- e_tree->priv->drop_row = -1;
- e_tree->priv->drop_path = NULL;
- e_tree->priv->drop_col = -1;
- e_tree->priv->drop_highlight = NULL;
-
- e_tree->priv->last_drop_x = 0;
- e_tree->priv->last_drop_y = 0;
- e_tree->priv->last_drop_time = 0;
- e_tree->priv->last_drop_context = NULL;
-
- e_tree->priv->hover_x = 0;
- e_tree->priv->hover_y = 0;
-
- e_tree->priv->drag_row = -1;
- e_tree->priv->drag_path = NULL;
- e_tree->priv->drag_col = -1;
-
- e_tree->priv->expanded_list = NULL;
-
- e_tree->priv->site = NULL;
- e_tree->priv->do_drag = FALSE;
-
-#ifdef E_TREE_USE_TREE_SELECTION
- e_tree->priv->selection = E_SELECTION_MODEL(e_tree_selection_model_new());
-#else
- e_tree->priv->selection = E_SELECTION_MODEL(e_table_selection_model_new());
-#endif
- e_tree->priv->spec = NULL;
-
- e_tree->priv->header_canvas = NULL;
- e_tree->priv->table_canvas = NULL;
-
- e_tree->priv->header_item = NULL;
- e_tree->priv->root = NULL;
-
- e_tree->priv->white_item = NULL;
- e_tree->priv->item = NULL;
-
- e_tree->priv->search = e_table_search_new();
-
- e_tree->priv->search_search_id =
- g_signal_connect (G_OBJECT (e_tree->priv->search), "search",
- G_CALLBACK (et_search_search), e_tree);
- e_tree->priv->search_accept_id =
- g_signal_connect (G_OBJECT (e_tree->priv->search), "accept",
- G_CALLBACK (et_search_accept), e_tree);
-
- e_tree->priv->current_search_col = NULL;
- e_tree->priv->search_col_set = FALSE;
- e_tree->priv->always_search = g_getenv ("GAL_ALWAYS_SEARCH") ? TRUE : FALSE;
-}
-
-/* Grab_focus handler for the ETree */
-static void
-et_grab_focus (GtkWidget *widget)
-{
- ETree *e_tree;
-
- e_tree = E_TREE (widget);
-
- gtk_widget_grab_focus (GTK_WIDGET (e_tree->priv->table_canvas));
-}
-
-/* Focus handler for the ETree */
-static gint
-et_focus (GtkWidget *container, GtkDirectionType direction)
-{
- ETree *e_tree;
-
- e_tree = E_TREE (container);
-
- if (GTK_CONTAINER (container)->focus_child) {
- gtk_container_set_focus_child (GTK_CONTAINER (container), NULL);
- return FALSE;
- }
-
- return gtk_widget_child_focus (GTK_WIDGET (e_tree->priv->table_canvas), direction);
-}
-
-static void
-set_header_canvas_width (ETree *e_tree)
-{
- double oldwidth, oldheight, width;
-
- if (!(e_tree->priv->header_item && e_tree->priv->header_canvas && e_tree->priv->table_canvas))
- return;
-
- gnome_canvas_get_scroll_region (GNOME_CANVAS (e_tree->priv->table_canvas),
- NULL, NULL, &width, NULL);
- gnome_canvas_get_scroll_region (GNOME_CANVAS (e_tree->priv->header_canvas),
- NULL, NULL, &oldwidth, &oldheight);
-
- if (oldwidth != width ||
- oldheight != E_TABLE_HEADER_ITEM (e_tree->priv->header_item)->height - 1)
- gnome_canvas_set_scroll_region (
- GNOME_CANVAS (e_tree->priv->header_canvas),
- 0, 0, width, /* COLUMN_HEADER_HEIGHT - 1 */
- E_TABLE_HEADER_ITEM (e_tree->priv->header_item)->height - 1);
-
-}
-
-static void
-header_canvas_size_allocate (GtkWidget *widget, GtkAllocation *alloc, ETree *e_tree)
-{
- set_header_canvas_width (e_tree);
-
- /* When the header item is created ->height == 0,
- as the font is only created when everything is realized.
- So we set the usize here as well, so that the size of the
- header is correct */
- if (GTK_WIDGET (e_tree->priv->header_canvas)->allocation.height !=
- E_TABLE_HEADER_ITEM (e_tree->priv->header_item)->height)
- gtk_widget_set_usize (GTK_WIDGET (e_tree->priv->header_canvas), -1,
- E_TABLE_HEADER_ITEM (e_tree->priv->header_item)->height);
-}
-
-static void
-e_tree_setup_header (ETree *e_tree)
-{
- char *pointer;
- e_tree->priv->header_canvas = GNOME_CANVAS (e_canvas_new ());
- GTK_WIDGET_UNSET_FLAGS (e_tree->priv->header_canvas, GTK_CAN_FOCUS);
-
- gtk_widget_show (GTK_WIDGET (e_tree->priv->header_canvas));
-
- pointer = g_strdup_printf("%p", e_tree);
-
- e_tree->priv->header_item = gnome_canvas_item_new (
- gnome_canvas_root (e_tree->priv->header_canvas),
- e_table_header_item_get_type (),
- "ETableHeader", e_tree->priv->header,
- "full_header", e_tree->priv->full_header,
- "sort_info", e_tree->priv->sort_info,
- "dnd_code", pointer,
- "tree", e_tree,
- NULL);
-
- g_free(pointer);
-
- g_signal_connect (
- e_tree->priv->header_canvas, "size_allocate",
- G_CALLBACK (header_canvas_size_allocate), e_tree);
-
- gtk_widget_set_usize (GTK_WIDGET (e_tree->priv->header_canvas), -1,
- E_TABLE_HEADER_ITEM (e_tree->priv->header_item)->height);
-}
-
-static gboolean
-tree_canvas_reflow_idle (ETree *e_tree)
-{
- gdouble height, width;
- gdouble item_height;
- gdouble oldheight, oldwidth;
- GtkAllocation *alloc = &(GTK_WIDGET (e_tree->priv->table_canvas)->allocation);
-
- g_object_get (e_tree->priv->item,
- "height", &height,
- "width", &width,
- NULL);
- item_height = height;
- height = MAX ((int)height, alloc->height);
- width = MAX((int)width, alloc->width);
- /* I have no idea why this needs to be -1, but it works. */
- gnome_canvas_get_scroll_region (GNOME_CANVAS (e_tree->priv->table_canvas),
- NULL, NULL, &oldwidth, &oldheight);
-
- if (oldwidth != width - 1 ||
- oldheight != height - 1) {
- gnome_canvas_set_scroll_region (GNOME_CANVAS (e_tree->priv->table_canvas),
- 0, 0, width - 1, height - 1);
- set_header_canvas_width (e_tree);
- }
- e_tree->priv->reflow_idle_id = 0;
- return FALSE;
-}
-
-static void
-tree_canvas_size_allocate (GtkWidget *widget, GtkAllocation *alloc,
- ETree *e_tree)
-{
- gdouble width;
- gdouble height;
- gdouble item_height;
- GtkAdjustment *adj = GTK_LAYOUT(e_tree->priv->table_canvas)->vadjustment;
- ETreePath path = e_tree_get_cursor (e_tree);
- gint x, y, w, h;
- GValue *val = g_new0 (GValue, 1);
- g_value_init (val, G_TYPE_DOUBLE);
-
- width = alloc->width;
- g_value_set_double (val, width);
- g_object_get (e_tree->priv->item,
- "height", &height,
- NULL);
- item_height = height;
- height = MAX ((int)height, alloc->height);
-
- g_object_set (e_tree->priv->item,
- "width", width,
- NULL);
- g_object_set_property (G_OBJECT (e_tree->priv->header), "width", val);
- g_free (val);
-
- if (e_tree->priv->reflow_idle_id)
- g_source_remove(e_tree->priv->reflow_idle_id);
- tree_canvas_reflow_idle(e_tree);
-
- x = y = w = h = 0;
- if (path) {
- int row = e_tree_row_of_node(e_tree, path);
- int col = 0;
-
- if (row >= 0)
- e_table_item_get_cell_geometry (E_TABLE_ITEM (e_tree->priv->item),
- &row, &col, &x, &y, &w, &h);
- }
-
- if (y < adj->value || y + h > adj->value + adj->page_size)
- gtk_adjustment_set_value(adj, CLAMP(y - adj->page_size / 2, adj->lower, adj->upper - adj->page_size));
-}
-
-static void
-tree_canvas_reflow (GnomeCanvas *canvas, ETree *e_tree)
-{
- if (!e_tree->priv->reflow_idle_id)
- e_tree->priv->reflow_idle_id = g_idle_add_full (400, (GSourceFunc) tree_canvas_reflow_idle, e_tree, NULL);
-}
-
-static void
-item_cursor_change (ETableItem *eti, int row, ETree *et)
-{
- ETreePath path = e_tree_table_adapter_node_at_row(et->priv->etta, row);
- g_signal_emit (et,
- et_signals [CURSOR_CHANGE], 0,
- row, path);
-}
-
-static void
-item_cursor_activated (ETableItem *eti, int row, ETree *et)
-{
- ETreePath path = e_tree_table_adapter_node_at_row(et->priv->etta, row);
- g_signal_emit (et,
- et_signals [CURSOR_ACTIVATED], 0,
- row, path);
- d(g_print("%s: Emitted CURSOR_ACTIVATED signal on row: %d and path: 0x%p\n", __FUNCTION__, row, path));
-}
-
-static void
-item_double_click (ETableItem *eti, int row, int col, GdkEvent *event, ETree *et)
-{
- ETreePath path = e_tree_table_adapter_node_at_row(et->priv->etta, row);
- g_signal_emit (et,
- et_signals [DOUBLE_CLICK], 0,
- row, path, col, event);
-}
-
-static gint
-item_right_click (ETableItem *eti, int row, int col, GdkEvent *event, ETree *et)
-{
- int return_val = 0;
- ETreePath path = e_tree_table_adapter_node_at_row(et->priv->etta, row);
- g_signal_emit (et,
- et_signals [RIGHT_CLICK], 0,
- row, path, col, event, &return_val);
- return return_val;
-}
-
-static gint
-item_click (ETableItem *eti, int row, int col, GdkEvent *event, ETree *et)
-{
- int return_val = 0;
- ETreePath path = e_tree_table_adapter_node_at_row(et->priv->etta, row);
- g_signal_emit (et,
- et_signals [CLICK], 0,
- row, path, col, event, &return_val);
- return return_val;
-}
-
-static gint
-item_key_press (ETableItem *eti, int row, int col, GdkEvent *event, ETree *et)
-{
- int return_val = 0;
- GdkEventKey *key = (GdkEventKey *) event;
- ETreePath path;
- int y, row_local, col_local;
- GtkAdjustment *vadj;
-
- switch (key->keyval) {
- case GDK_Page_Down:
- case GDK_KP_Page_Down:
- vadj = gtk_layout_get_vadjustment (GTK_LAYOUT (et->priv->table_canvas));
- y = CLAMP(vadj->value + (2 * vadj->page_size - 50), 0, vadj->upper);
- y -= vadj->value;
- e_tree_get_cell_at (et, 30, y, &row_local, &col_local);
-
- if (row_local == -1)
- row_local = e_table_model_row_count (E_TABLE_MODEL(et->priv->etta)) - 1;
-
- row_local = e_tree_view_to_model_row (et, row_local);
- col_local = e_selection_model_cursor_col (E_SELECTION_MODEL (et->priv->selection));
- e_selection_model_select_as_key_press (E_SELECTION_MODEL (et->priv->selection), row_local, col_local, key->state);
-
- return_val = 1;
- break;
- case GDK_Page_Up:
- case GDK_KP_Page_Up:
- vadj = gtk_layout_get_vadjustment (GTK_LAYOUT (et->priv->table_canvas));
- y = CLAMP(vadj->value - (vadj->page_size - 50), 0, vadj->upper);
- y -= vadj->value;
- e_tree_get_cell_at (et, 30, y, &row_local, &col_local);
-
- if (row_local == -1)
- row_local = e_table_model_row_count (E_TABLE_MODEL(et->priv->etta)) - 1;
-
- row_local = e_tree_view_to_model_row (et, row_local);
- col_local = e_selection_model_cursor_col (E_SELECTION_MODEL (et->priv->selection));
- e_selection_model_select_as_key_press (E_SELECTION_MODEL (et->priv->selection), row_local, col_local, key->state);
-
- return_val = 1;
- break;
- case '=':
- case GDK_Right:
- case GDK_KP_Right:
- /* Only allow if the Shift modifier is used -- eg. Ctrl-Equal shouldn't be handled. */
- if (key->state & ~(GDK_SHIFT_MASK | GDK_LOCK_MASK))
- break;
- if (row != -1) {
- path = e_tree_table_adapter_node_at_row(et->priv->etta, row);
- if (path)
- e_tree_table_adapter_node_set_expanded (et->priv->etta, path, TRUE);
- }
- return_val = 1;
- break;
- case '-':
- case GDK_Left:
- case GDK_KP_Left:
- /* Only allow if the Shift modifier is used -- eg. Ctrl-Minus shouldn't be handled. */
- if (key->state & ~(GDK_SHIFT_MASK | GDK_LOCK_MASK))
- break;
- if (row != -1) {
- path = e_tree_table_adapter_node_at_row(et->priv->etta, row);
- if (path)
- e_tree_table_adapter_node_set_expanded (et->priv->etta, path, FALSE);
- }
- return_val = 1;
- break;
- case GDK_BackSpace:
- if (e_table_search_backspace (et->priv->search))
- return TRUE;
- /* Fallthrough */
- default:
- if ((key->state & ~(GDK_SHIFT_MASK | GDK_LOCK_MASK)) == 0
- && ((key->keyval >= GDK_a && key->keyval <= GDK_z) ||
- (key->keyval >= GDK_A && key->keyval <= GDK_Z) ||
- (key->keyval >= GDK_0 && key->keyval <= GDK_9))) {
- e_table_search_input_character (et->priv->search, key->keyval);
- }
- path = e_tree_table_adapter_node_at_row(et->priv->etta, row);
- g_signal_emit (et,
- et_signals [KEY_PRESS], 0,
- row, path, col, event, &return_val);
- break;
- }
- return return_val;
-}
-
-static gint
-item_start_drag (ETableItem *eti, int row, int col, GdkEvent *event, ETree *et)
-{
- ETreePath path;
- gint return_val = 0;
-
- path = e_tree_table_adapter_node_at_row(et->priv->etta, row);
-
- g_signal_emit (et,
- et_signals [START_DRAG], 0,
- row, path, col, event, &return_val);
-
- return return_val;
-}
-
-static void
-et_selection_model_selection_changed (ETableSelectionModel *etsm, ETree *et)
-{
- g_signal_emit (et,
- et_signals [SELECTION_CHANGE], 0);
-}
-
-static void
-et_selection_model_selection_row_changed (ETableSelectionModel *etsm, int row, ETree *et)
-{
- g_signal_emit (et,
- et_signals [SELECTION_CHANGE], 0);
-}
-
-static void
-et_build_item (ETree *et)
-{
- et->priv->item = gnome_canvas_item_new(GNOME_CANVAS_GROUP (gnome_canvas_root(et->priv->table_canvas)),
- e_table_item_get_type(),
- "ETableHeader", et->priv->header,
- "ETableModel", et->priv->etta,
- "selection_model", et->priv->selection,
- "alternating_row_colors", et->priv->alternating_row_colors,
- "horizontal_draw_grid", et->priv->horizontal_draw_grid,
- "vertical_draw_grid", et->priv->vertical_draw_grid,
- "drawfocus", et->priv->draw_focus,
- "cursor_mode", et->priv->cursor_mode,
- "length_threshold", et->priv->length_threshold,
- "uniform_row_height", et->priv->uniform_row_height,
- NULL);
-
- g_signal_connect (et->priv->item, "cursor_change",
- G_CALLBACK (item_cursor_change), et);
- g_signal_connect (et->priv->item, "cursor_activated",
- G_CALLBACK (item_cursor_activated), et);
- g_signal_connect (et->priv->item, "double_click",
- G_CALLBACK (item_double_click), et);
- g_signal_connect (et->priv->item, "right_click",
- G_CALLBACK (item_right_click), et);
- g_signal_connect (et->priv->item, "click",
- G_CALLBACK (item_click), et);
- g_signal_connect (et->priv->item, "key_press",
- G_CALLBACK (item_key_press), et);
- g_signal_connect (et->priv->item, "start_drag",
- G_CALLBACK (item_start_drag), et);
-}
-
-static void
-et_canvas_style_set (GtkWidget *widget, GtkStyle *prev_style)
-{
- gnome_canvas_item_set(
- E_TREE(widget)->priv->white_item,
- "fill_color_gdk", &widget->style->base[GTK_STATE_NORMAL],
- NULL);
-}
-
-static gint
-white_item_event (GnomeCanvasItem *white_item, GdkEvent *event, ETree *e_tree)
-{
- int return_val = 0;
- g_signal_emit (e_tree,
- et_signals [WHITE_SPACE_EVENT], 0,
- event, &return_val);
- return return_val;
-}
-
-static gint
-et_canvas_root_event (GnomeCanvasItem *root, GdkEvent *event, ETree *e_tree)
-{
- switch (event->type) {
- case GDK_BUTTON_PRESS:
- case GDK_2BUTTON_PRESS:
- case GDK_BUTTON_RELEASE:
- if (event->button.button != 4 && event->button.button != 5) {
- if (GTK_WIDGET_HAS_FOCUS(root->canvas)) {
- GnomeCanvasItem *item = GNOME_CANVAS(root->canvas)->focused_item;
-
- if (E_IS_TABLE_ITEM(item)) {
- e_table_item_leave_edit_(E_TABLE_ITEM(item));
- return TRUE;
- }
- }
- }
- break;
- default:
- break;
- }
-
- return FALSE;
-}
-
-/* Handler for focus events in the table_canvas; we have to repaint ourselves
- * and give the focus to some ETableItem.
- */
-static gint
-table_canvas_focus_event_cb (GtkWidget *widget, GdkEventFocus *event, gpointer data)
-{
- GnomeCanvas *canvas;
- ETree *tree;
-
- gtk_widget_queue_draw (widget);
-
- if (!event->in)
- return TRUE;
-
- canvas = GNOME_CANVAS (widget);
- tree = E_TREE (data);
-
- if (!canvas->focused_item) {
- e_table_item_set_cursor (E_TABLE_ITEM (tree->priv->item), 0, 0);
- gnome_canvas_item_grab_focus (tree->priv->item);
- }
-
- return TRUE;
-}
-
-static void
-e_tree_setup_table (ETree *e_tree)
-{
- e_tree->priv->table_canvas = GNOME_CANVAS (e_canvas_new ());
- g_signal_connect (
- e_tree->priv->table_canvas, "size_allocate",
- G_CALLBACK (tree_canvas_size_allocate), e_tree);
- g_signal_connect (
- e_tree->priv->table_canvas, "focus_in_event",
- G_CALLBACK (table_canvas_focus_event_cb), e_tree);
- g_signal_connect (
- e_tree->priv->table_canvas, "focus_out_event",
- G_CALLBACK (table_canvas_focus_event_cb), e_tree);
-
- g_signal_connect (
- e_tree->priv->table_canvas, "drag_begin",
- G_CALLBACK (et_drag_begin), e_tree);
- g_signal_connect (
- e_tree->priv->table_canvas, "drag_end",
- G_CALLBACK (et_drag_end), e_tree);
- g_signal_connect (
- e_tree->priv->table_canvas, "drag_data_get",
- G_CALLBACK (et_drag_data_get), e_tree);
- g_signal_connect (
- e_tree->priv->table_canvas, "drag_data_delete",
- G_CALLBACK (et_drag_data_delete), e_tree);
- g_signal_connect (
- e_tree, "drag_motion",
- G_CALLBACK (et_drag_motion), e_tree);
- g_signal_connect (
- e_tree, "drag_leave",
- G_CALLBACK (et_drag_leave), e_tree);
- g_signal_connect (
- e_tree, "drag_drop",
- G_CALLBACK (et_drag_drop), e_tree);
- g_signal_connect (
- e_tree, "drag_data_received",
- G_CALLBACK (et_drag_data_received), e_tree);
-
- g_signal_connect (e_tree->priv->table_canvas, "reflow",
- G_CALLBACK (tree_canvas_reflow), e_tree);
-
- gtk_widget_show (GTK_WIDGET (e_tree->priv->table_canvas));
-
- e_tree->priv->white_item = gnome_canvas_item_new(
- gnome_canvas_root(e_tree->priv->table_canvas),
- e_canvas_background_get_type(),
- "fill_color_gdk", &GTK_WIDGET(e_tree->priv->table_canvas)->style->base[GTK_STATE_NORMAL],
- NULL);
-
- g_signal_connect (e_tree->priv->white_item, "event",
- G_CALLBACK (white_item_event), e_tree);
- g_signal_connect (
- gnome_canvas_root (e_tree->priv->table_canvas), "event",
- G_CALLBACK(et_canvas_root_event), e_tree);
-
- et_build_item(e_tree);
-}
-
-/**
- * e_tree_set_search_column:
- * @e_tree: #ETree object that will be modified
- * @col: Column index to use for searches
- *
- * This routine sets the current search column to be used for keypress
- * searches of the #ETree. If -1 is passed in for column, the current
- * search column is cleared.
- */
-void
-e_tree_set_search_column (ETree *e_tree, gint col)
-{
- if (col == -1) {
- clear_current_search_col (e_tree);
- return;
- }
-
- e_tree->priv->search_col_set = TRUE;
- e_tree->priv->current_search_col = e_table_header_get_column (e_tree->priv->full_header, col);
-}
-
-void
-e_tree_set_state_object(ETree *e_tree, ETableState *state)
-{
- GValue *val = g_new0 (GValue, 1);
- g_value_init (val, G_TYPE_DOUBLE);
-
- connect_header (e_tree, state);
-
- g_value_set_double (val, (double) (GTK_WIDGET(e_tree->priv->table_canvas)->allocation.width));
- g_object_set_property (G_OBJECT (e_tree->priv->header), "width", val);
- g_free (val);
-
- if (e_tree->priv->header_item)
- g_object_set(e_tree->priv->header_item,
- "ETableHeader", e_tree->priv->header,
- "sort_info", e_tree->priv->sort_info,
- NULL);
-
- if (e_tree->priv->item)
- g_object_set(e_tree->priv->item,
- "ETableHeader", e_tree->priv->header,
- NULL);
-
- if (e_tree->priv->etta)
- e_tree_table_adapter_set_sort_info (e_tree->priv->etta, e_tree->priv->sort_info);
-
- e_tree_state_change (e_tree);
-}
-
-/**
- * e_tree_set_state:
- * @e_tree: #ETree object that will be modified
- * @state_str: a string with the XML representation of the #ETableState.
- *
- * This routine sets the state (as described by #ETableState) of the
- * #ETree object.
- */
-void
-e_tree_set_state (ETree *e_tree,
- const gchar *state_str)
-{
- ETableState *state;
-
- g_return_if_fail(e_tree != NULL);
- g_return_if_fail(E_IS_TREE(e_tree));
- g_return_if_fail(state_str != NULL);
-
- state = e_table_state_new();
- e_table_state_load_from_string(state, state_str);
-
- if (state->col_count > 0)
- e_tree_set_state_object(e_tree, state);
-
- g_object_unref(state);
-}
-
-/**
- * e_tree_load_state:
- * @e_tree: #ETree object that will be modified
- * @filename: name of the file containing the state to be loaded into the #ETree
- *
- * An #ETableState will be loaded form the file pointed by @filename into the
- * @e_tree object.
- */
-void
-e_tree_load_state (ETree *e_tree,
- const gchar *filename)
-{
- ETableState *state;
-
- g_return_if_fail(e_tree != NULL);
- g_return_if_fail(E_IS_TREE(e_tree));
- g_return_if_fail(filename != NULL);
-
- state = e_table_state_new();
- e_table_state_load_from_file(state, filename);
-
- if (state->col_count > 0)
- e_tree_set_state_object(e_tree, state);
-
- g_object_unref(state);
-}
-
-/**
- * e_tree_get_state_object:
- * @e_tree: #ETree object to act on
- *
- * Builds an #ETableState corresponding to the current state of the
- * #ETree.
- *
- * Return value:
- * The %ETableState object generated.
- **/
-ETableState *
-e_tree_get_state_object (ETree *e_tree)
-{
- ETableState *state;
- int full_col_count;
- int i, j;
-
- state = e_table_state_new();
- state->sort_info = e_tree->priv->sort_info;
- if (state->sort_info)
- g_object_ref(state->sort_info);
-
- state->col_count = e_table_header_count (e_tree->priv->header);
- full_col_count = e_table_header_count (e_tree->priv->full_header);
- state->columns = g_new(int, state->col_count);
- state->expansions = g_new(double, state->col_count);
- for (i = 0; i < state->col_count; i++) {
- ETableCol *col = e_table_header_get_column(e_tree->priv->header, i);
- state->columns[i] = -1;
- for (j = 0; j < full_col_count; j++) {
- if (col->col_idx == e_table_header_index(e_tree->priv->full_header, j)) {
- state->columns[i] = j;
- break;
- }
- }
- state->expansions[i] = col->expansion;
- }
-
- return state;
-}
-
-/**
- * e_tree_get_state:
- * @e_tree: The #ETree to act on
- *
- * Builds a state object based on the current state and returns the
- * string corresponding to that state.
- *
- * Return value:
- * A string describing the current state of the #ETree.
- **/
-gchar *
-e_tree_get_state (ETree *e_tree)
-{
- ETableState *state;
- gchar *string;
-
- state = e_tree_get_state_object(e_tree);
- string = e_table_state_save_to_string(state);
- g_object_unref(state);
- return string;
-}
-
-/**
- * e_tree_save_state:
- * @e_tree: The #ETree to act on
- * @filename: name of the file to save to
- *
- * Saves the state of the @e_tree object into the file pointed by
- * @filename.
- **/
-void
-e_tree_save_state (ETree *e_tree,
- const gchar *filename)
-{
- ETableState *state;
-
- state = e_tree_get_state_object(e_tree);
- e_table_state_save_to_file(state, filename);
- g_object_unref(state);
-}
-
-/**
- * e_tree_get_spec:
- * @e_tree: The #ETree to query
- *
- * Returns the specification object.
- *
- * Return value:
- **/
-ETableSpecification *
-e_tree_get_spec (ETree *e_tree)
-{
- return e_tree->priv->spec;
-}
-
-static void
-et_table_model_changed (ETableModel *model, ETree *et)
-{
- if (et->priv->horizontal_scrolling)
- e_table_header_update_horizontal(et->priv->header);
-}
-
-static void
-et_table_row_changed (ETableModel *table_model, int row, ETree *et)
-{
- et_table_model_changed (table_model, et);
-}
-
-static void
-et_table_cell_changed (ETableModel *table_model, int view_col, int row, ETree *et)
-{
- et_table_model_changed (table_model, et);
-}
-
-static void
-et_connect_to_etta (ETree *et)
-{
- et->priv->table_model_change_id = g_signal_connect (et->priv->etta, "model_changed",
- G_CALLBACK (et_table_model_changed), et);
-
- et->priv->table_row_change_id = g_signal_connect (et->priv->etta, "model_row_changed",
- G_CALLBACK (et_table_row_changed), et);
-
- et->priv->table_cell_change_id = g_signal_connect (et->priv->etta, "model_cell_changed",
- G_CALLBACK (et_table_cell_changed), et);
-
-}
-
-static ETree *
-et_real_construct (ETree *e_tree, ETreeModel *etm, ETableExtras *ete,
- ETableSpecification *specification, ETableState *state)
-{
- int row = 0;
-
- if (ete)
- g_object_ref(ete);
- else
- ete = e_table_extras_new();
-
- e_tree->priv->alternating_row_colors = specification->alternating_row_colors;
- e_tree->priv->horizontal_draw_grid = specification->horizontal_draw_grid;
- e_tree->priv->vertical_draw_grid = specification->vertical_draw_grid;
- e_tree->priv->draw_focus = specification->draw_focus;
- e_tree->priv->cursor_mode = specification->cursor_mode;
- e_tree->priv->full_header = e_table_spec_to_full_header(specification, ete);
-
- connect_header (e_tree, state);
-
- e_tree->priv->horizontal_scrolling = specification->horizontal_scrolling;
-
- e_tree->priv->model = etm;
- g_object_ref (etm);
-
- e_tree->priv->etta = E_TREE_TABLE_ADAPTER(e_tree_table_adapter_new(e_tree->priv->model, e_tree->priv->sort_info, e_tree->priv->full_header));
-
- et_connect_to_etta (e_tree);
-
- gtk_widget_push_colormap (gdk_rgb_get_cmap ());
-
- e_tree->priv->sorter = e_sorter_new();
-
- g_object_set (e_tree->priv->selection,
- "sorter", e_tree->priv->sorter,
-#ifdef E_TREE_USE_TREE_SELECTION
- "model", e_tree->priv->model,
- "etta", e_tree->priv->etta,
-#else
- "model", e_tree->priv->etta,
-#endif
- "selection_mode", specification->selection_mode,
- "cursor_mode", specification->cursor_mode,
- NULL);
-
- g_signal_connect(e_tree->priv->selection, "selection_changed",
- G_CALLBACK (et_selection_model_selection_changed), e_tree);
- g_signal_connect(e_tree->priv->selection, "selection_row_changed",
- G_CALLBACK (et_selection_model_selection_row_changed), e_tree);
-
- if (!specification->no_headers) {
- e_tree_setup_header (e_tree);
- }
- e_tree_setup_table (e_tree);
-
- gtk_layout_get_vadjustment (GTK_LAYOUT (e_tree->priv->table_canvas))->step_increment = 20;
- gtk_adjustment_changed(gtk_layout_get_vadjustment (GTK_LAYOUT (e_tree->priv->table_canvas)));
- gtk_layout_get_hadjustment (GTK_LAYOUT (e_tree->priv->table_canvas))->step_increment = 20;
- gtk_adjustment_changed(gtk_layout_get_hadjustment (GTK_LAYOUT (e_tree->priv->table_canvas)));
-
- if (!specification->no_headers) {
- /*
- * The header
- */
- gtk_table_attach (GTK_TABLE (e_tree), GTK_WIDGET (e_tree->priv->header_canvas),
- 0, 1, 0 + row, 1 + row,
- GTK_FILL | GTK_EXPAND,
- GTK_FILL, 0, 0);
- row ++;
- }
- gtk_table_attach (GTK_TABLE (e_tree), GTK_WIDGET (e_tree->priv->table_canvas),
- 0, 1, 0 + row, 1 + row,
- GTK_FILL | GTK_EXPAND,
- GTK_FILL | GTK_EXPAND,
- 0, 0);
-
- gtk_widget_pop_colormap ();
-
- g_object_unref(ete);
-
- return e_tree;
-}
-
-/**
- * e_tree_construct:
- * @e_tree: The newly created #ETree object.
- * @etm: The model for this table.
- * @ete: An optional #ETableExtras. (%NULL is valid.)
- * @spec_str: The spec.
- * @state_str: An optional state. (%NULL is valid.)
- *
- * This is the internal implementation of e_tree_new() for use by
- * subclasses or language bindings. See e_tree_new() for details.
- *
- * Return value:
- * The passed in value @e_tree or %NULL if there's an error.
- **/
-ETree *
-e_tree_construct (ETree *e_tree, ETreeModel *etm, ETableExtras *ete,
- const char *spec_str, const char *state_str)
-{
- ETableSpecification *specification;
- ETableState *state;
-
- g_return_val_if_fail(e_tree != NULL, NULL);
- g_return_val_if_fail(E_IS_TREE(e_tree), NULL);
- g_return_val_if_fail(etm != NULL, NULL);
- g_return_val_if_fail(E_IS_TREE_MODEL(etm), NULL);
- g_return_val_if_fail(ete == NULL || E_IS_TABLE_EXTRAS(ete), NULL);
- g_return_val_if_fail(spec_str != NULL, NULL);
-
- specification = e_table_specification_new();
- e_table_specification_load_from_string(specification, spec_str);
- if (state_str) {
- state = e_table_state_new();
- e_table_state_load_from_string(state, state_str);
- if (state->col_count <= 0) {
- g_object_unref(state);
- state = specification->state;
- g_object_ref(state);
- }
- } else {
- state = specification->state;
- g_object_ref(state);
- }
-
- e_tree = et_real_construct (e_tree, etm, ete, specification, state);
-
- e_tree->priv->spec = specification;
- g_object_unref(state);
-
- return e_tree;
-}
-
-/**
- * e_tree_construct_from_spec_file:
- * @e_tree: The newly created #ETree object.
- * @etm: The model for this tree
- * @ete: An optional #ETableExtras (%NULL is valid.)
- * @spec_fn: The filename of the spec
- * @state_fn: An optional state file (%NULL is valid.)
- *
- * This is the internal implementation of e_tree_new_from_spec_file()
- * for use by subclasses or language bindings. See
- * e_tree_new_from_spec_file() for details.
- *
- * Return value:
- * The passed in value @e_tree or %NULL if there's an error.
- **/
-ETree *
-e_tree_construct_from_spec_file (ETree *e_tree, ETreeModel *etm, ETableExtras *ete,
- const char *spec_fn, const char *state_fn)
-{
- ETableSpecification *specification;
- ETableState *state;
-
- g_return_val_if_fail(e_tree != NULL, NULL);
- g_return_val_if_fail(E_IS_TREE(e_tree), NULL);
- g_return_val_if_fail(etm != NULL, NULL);
- g_return_val_if_fail(E_IS_TREE_MODEL(etm), NULL);
- g_return_val_if_fail(ete == NULL || E_IS_TABLE_EXTRAS(ete), NULL);
- g_return_val_if_fail(spec_fn != NULL, NULL);
-
- specification = e_table_specification_new();
- if (!e_table_specification_load_from_file(specification, spec_fn)) {
- g_object_unref(specification);
- return NULL;
- }
-
- if (state_fn) {
- state = e_table_state_new();
- if (!e_table_state_load_from_file(state, state_fn)) {
- g_object_unref(state);
- state = specification->state;
- g_object_ref(state);
- }
- if (state->col_count <= 0) {
- g_object_unref(state);
- state = specification->state;
- g_object_ref(state);
- }
- } else {
- state = specification->state;
- g_object_ref(state);
- }
-
- e_tree = et_real_construct (e_tree, etm, ete, specification, state);
-
- e_tree->priv->spec = specification;
- g_object_unref(state);
-
- return e_tree;
-}
-
-/**
- * e_tree_new:
- * @etm: The model for this tree
- * @ete: An optional #ETableExtras (%NULL is valid.)
- * @spec: The spec
- * @state: An optional state (%NULL is valid.)
- *
- * This function creates an #ETree from the given parameters. The
- * #ETreeModel is a tree model to be represented. The #ETableExtras
- * is an optional set of pixbufs, cells, and sorting functions to be
- * used when interpreting the spec. If you pass in %NULL it uses the
- * default #ETableExtras. (See e_table_extras_new()).
- *
- * @spec is the specification of the set of viewable columns and the
- * default sorting state and such. @state is an optional string
- * specifying the current sorting state and such. If @state is NULL,
- * then the default state from the spec will be used.
- *
- * Return value:
- * The newly created #ETree or %NULL if there's an error.
- **/
-GtkWidget *
-e_tree_new (ETreeModel *etm, ETableExtras *ete, const char *spec, const char *state)
-{
- ETree *e_tree, *ret_val;
-
- g_return_val_if_fail(etm != NULL, NULL);
- g_return_val_if_fail(E_IS_TREE_MODEL(etm), NULL);
- g_return_val_if_fail(ete == NULL || E_IS_TABLE_EXTRAS(ete), NULL);
- g_return_val_if_fail(spec != NULL, NULL);
-
- e_tree = g_object_new (E_TREE_TYPE, NULL);
-
- ret_val = e_tree_construct (e_tree, etm, ete, spec, state);
-
- if (ret_val == NULL) {
- g_object_unref (e_tree);
- }
-
- return (GtkWidget *) ret_val;
-}
-
-/**
- * e_tree_new_from_spec_file:
- * @etm: The model for this tree.
- * @ete: An optional #ETableExtras. (%NULL is valid.)
- * @spec_fn: The filename of the spec.
- * @state_fn: An optional state file. (%NULL is valid.)
- *
- * This is very similar to e_tree_new(), except instead of passing in
- * strings you pass in the file names of the spec and state to load.
- *
- * @spec_fn is the filename of the spec to load. If this file doesn't
- * exist, e_tree_new_from_spec_file will return %NULL.
- *
- * @state_fn is the filename of the initial state to load. If this is
- * %NULL or if the specified file doesn't exist, the default state
- * from the spec file is used.
- *
- * Return value:
- * The newly created #ETree or %NULL if there's an error.
- **/
-GtkWidget *
-e_tree_new_from_spec_file (ETreeModel *etm, ETableExtras *ete, const char *spec_fn, const char *state_fn)
-{
- ETree *e_tree, *ret_val;
-
- g_return_val_if_fail(etm != NULL, NULL);
- g_return_val_if_fail(E_IS_TREE_MODEL(etm), NULL);
- g_return_val_if_fail(ete == NULL || E_IS_TABLE_EXTRAS(ete), NULL);
- g_return_val_if_fail(spec_fn != NULL, NULL);
-
- e_tree = g_object_new (E_TREE_TYPE, NULL);
-
- ret_val = e_tree_construct_from_spec_file (e_tree, etm, ete, spec_fn, state_fn);
-
- if (ret_val == NULL) {
- g_object_unref (e_tree);
- }
-
- return (GtkWidget *) ret_val;
-}
-
-void
-e_tree_set_cursor (ETree *e_tree, ETreePath path)
-{
-#ifndef E_TREE_USE_TREE_SELECTION
- int row;
-#endif
- g_return_if_fail(e_tree != NULL);
- g_return_if_fail(E_IS_TREE(e_tree));
- g_return_if_fail(path != NULL);
-
-#ifdef E_TREE_USE_TREE_SELECTION
- e_tree_selection_model_select_single_path (E_TREE_SELECTION_MODEL(e_tree->priv->selection), path);
- e_tree_selection_model_change_cursor (E_TREE_SELECTION_MODEL(e_tree->priv->selection), path);
-#else
- row = e_tree_table_adapter_row_of_node(E_TREE_TABLE_ADAPTER(e_tree->priv->etta), path);
-
- if (row == -1)
- return;
-
- g_object_set(e_tree->priv->selection,
- "cursor_row", row,
- NULL);
-#endif
-}
-
-ETreePath
-e_tree_get_cursor (ETree *e_tree)
-{
-#ifdef E_TREE_USE_TREE_SELECTION
- return e_tree_selection_model_get_cursor (E_TREE_SELECTION_MODEL(e_tree->priv->selection));
-#else
- int row;
- ETreePath path;
- g_return_val_if_fail(e_tree != NULL, NULL);
- g_return_val_if_fail(E_IS_TREE(e_tree), NULL);
-
- g_object_get(e_tree->priv->selection,
- "cursor_row", &row,
- NULL);
- if (row == -1)
- return NULL;
- path = e_tree_table_adapter_node_at_row(E_TREE_TABLE_ADAPTER(e_tree->priv->etta), row);
- return path;
-#endif
-}
-
-void
-e_tree_selected_row_foreach (ETree *e_tree,
- EForeachFunc callback,
- gpointer closure)
-{
- g_return_if_fail(e_tree != NULL);
- g_return_if_fail(E_IS_TREE(e_tree));
-
- e_selection_model_foreach(e_tree->priv->selection,
- callback,
- closure);
-}
-
-#ifdef E_TREE_USE_TREE_SELECTION
-void
-e_tree_selected_path_foreach (ETree *e_tree,
- ETreeForeachFunc callback,
- gpointer closure)
-{
- g_return_if_fail(e_tree != NULL);
- g_return_if_fail(E_IS_TREE(e_tree));
-
- e_tree_selection_model_foreach(E_TREE_SELECTION_MODEL (e_tree->priv->selection),
- callback,
- closure);
-}
-
-/* Standard functions */
-static void
-et_foreach_recurse (ETreeModel *model,
- ETreePath path,
- ETreeForeachFunc callback,
- gpointer closure)
-{
- ETreePath child;
-
- callback(path, closure);
-
- child = e_tree_model_node_get_first_child(E_TREE_MODEL(model), path);
- for ( ; child; child = e_tree_model_node_get_next(E_TREE_MODEL(model), child))
- if (child)
- et_foreach_recurse (model, child, callback, closure);
-}
-
-void
-e_tree_path_foreach (ETree *e_tree,
- ETreeForeachFunc callback,
- gpointer closure)
-{
- ETreePath root;
-
- g_return_if_fail(e_tree != NULL);
- g_return_if_fail(E_IS_TREE(e_tree));
-
- root = e_tree_model_get_root (e_tree->priv->model);
-
- if (root)
- et_foreach_recurse (e_tree->priv->model,
- root,
- callback,
- closure);
-}
-#endif
-
-EPrintable *
-e_tree_get_printable (ETree *e_tree)
-{
- g_return_val_if_fail(e_tree != NULL, NULL);
- g_return_val_if_fail(E_IS_TREE(e_tree), NULL);
-
- return e_table_item_get_printable(E_TABLE_ITEM(e_tree->priv->item));
-}
-
-static void
-et_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- ETree *etree = E_TREE (object);
-
- switch (prop_id){
- case PROP_ETTA:
- g_value_set_object (value, etree->priv->etta);
- break;
- case PROP_UNIFORM_ROW_HEIGHT:
- g_value_set_boolean (value, etree->priv->uniform_row_height);
- break;
- case PROP_ALWAYS_SEARCH:
- g_value_set_boolean (value, etree->priv->always_search);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-typedef struct {
- char *arg;
- gboolean setting;
-} bool_closure;
-
-static void
-et_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- ETree *etree = E_TREE (object);
-
- switch (prop_id){
- case PROP_LENGTH_THRESHOLD:
- etree->priv->length_threshold = g_value_get_int (value);
- if (etree->priv->item) {
- gnome_canvas_item_set (GNOME_CANVAS_ITEM(etree->priv->item),
- "length_threshold", etree->priv->length_threshold,
- NULL);
- }
- break;
-
- case PROP_HORIZONTAL_DRAW_GRID:
- etree->priv->horizontal_draw_grid = g_value_get_boolean (value);
- if (etree->priv->item) {
- gnome_canvas_item_set (GNOME_CANVAS_ITEM(etree->priv->item),
- "horizontal_draw_grid", etree->priv->horizontal_draw_grid,
- NULL);
- }
- break;
-
- case PROP_VERTICAL_DRAW_GRID:
- etree->priv->vertical_draw_grid = g_value_get_boolean (value);
- if (etree->priv->item) {
- gnome_canvas_item_set (GNOME_CANVAS_ITEM(etree->priv->item),
- "vertical_draw_grid", etree->priv->vertical_draw_grid,
- NULL);
- }
- break;
-
- case PROP_DRAW_FOCUS:
- etree->priv->draw_focus = g_value_get_boolean (value);
- if (etree->priv->item) {
- gnome_canvas_item_set (GNOME_CANVAS_ITEM(etree->priv->item),
- "drawfocus", etree->priv->draw_focus,
- NULL);
- }
- break;
-
- case PROP_UNIFORM_ROW_HEIGHT:
- etree->priv->uniform_row_height = g_value_get_boolean (value);
- if (etree->priv->item) {
- gnome_canvas_item_set (GNOME_CANVAS_ITEM(etree->priv->item),
- "uniform_row_height", etree->priv->uniform_row_height,
- NULL);
- }
- break;
-
- case PROP_ALWAYS_SEARCH:
- if (etree->priv->always_search == g_value_get_boolean (value))
- return;
- etree->priv->always_search = g_value_get_boolean (value);
- clear_current_search_col (etree);
- break;
- }
-}
-
-static void
-set_scroll_adjustments (ETree *tree,
- GtkAdjustment *hadjustment,
- GtkAdjustment *vadjustment)
-{
- if (vadjustment != NULL) {
- vadjustment->step_increment = 20;
- gtk_adjustment_changed(vadjustment);
- }
- if (hadjustment != NULL) {
- hadjustment->step_increment = 20;
- gtk_adjustment_changed(hadjustment);
- }
-
- if (tree->priv) {
- gtk_layout_set_hadjustment (GTK_LAYOUT(tree->priv->table_canvas),
- hadjustment);
- gtk_layout_set_vadjustment (GTK_LAYOUT(tree->priv->table_canvas),
- vadjustment);
-
- if (tree->priv->header_canvas != NULL)
- gtk_layout_set_hadjustment (GTK_LAYOUT(tree->priv->header_canvas),
- hadjustment);
- }
-}
-
-gint
-e_tree_get_next_row (ETree *e_tree,
- gint model_row)
-{
- g_return_val_if_fail(e_tree != NULL, -1);
- g_return_val_if_fail(E_IS_TREE(e_tree), -1);
-
- if (e_tree->priv->sorter) {
- int i;
- i = e_sorter_model_to_sorted(E_SORTER (e_tree->priv->sorter), model_row);
- i++;
- if (i < e_table_model_row_count(E_TABLE_MODEL(e_tree->priv->etta))) {
- return e_sorter_sorted_to_model(E_SORTER (e_tree->priv->sorter), i);
- } else
- return -1;
- } else
- if (model_row < e_table_model_row_count(E_TABLE_MODEL(e_tree->priv->etta)) - 1)
- return model_row + 1;
- else
- return -1;
-}
-
-gint
-e_tree_get_prev_row (ETree *e_tree,
- gint model_row)
-{
- g_return_val_if_fail(e_tree != NULL, -1);
- g_return_val_if_fail(E_IS_TREE(e_tree), -1);
-
- if (e_tree->priv->sorter) {
- int i;
- i = e_sorter_model_to_sorted(E_SORTER (e_tree->priv->sorter), model_row);
- i--;
- if (i >= 0)
- return e_sorter_sorted_to_model(E_SORTER (e_tree->priv->sorter), i);
- else
- return -1;
- } else
- return model_row - 1;
-}
-
-gint
-e_tree_model_to_view_row (ETree *e_tree,
- gint model_row)
-{
- g_return_val_if_fail(e_tree != NULL, -1);
- g_return_val_if_fail(E_IS_TREE(e_tree), -1);
-
- if (e_tree->priv->sorter)
- return e_sorter_model_to_sorted(E_SORTER (e_tree->priv->sorter), model_row);
- else
- return model_row;
-}
-
-gint
-e_tree_view_to_model_row (ETree *e_tree,
- gint view_row)
-{
- g_return_val_if_fail(e_tree != NULL, -1);
- g_return_val_if_fail(E_IS_TREE(e_tree), -1);
-
- if (e_tree->priv->sorter)
- return e_sorter_sorted_to_model (E_SORTER (e_tree->priv->sorter), view_row);
- else
- return view_row;
-}
-
-
-gboolean
-e_tree_node_is_expanded (ETree *et, ETreePath path)
-{
- g_return_val_if_fail(path, FALSE);
-
- return e_tree_table_adapter_node_is_expanded (et->priv->etta, path);
-}
-
-void
-e_tree_node_set_expanded (ETree *et, ETreePath path, gboolean expanded)
-{
- g_return_if_fail (et != NULL);
- g_return_if_fail (E_IS_TREE(et));
-
- e_tree_table_adapter_node_set_expanded (et->priv->etta, path, expanded);
-}
-
-void
-e_tree_node_set_expanded_recurse (ETree *et, ETreePath path, gboolean expanded)
-{
- g_return_if_fail (et != NULL);
- g_return_if_fail (E_IS_TREE(et));
-
- e_tree_table_adapter_node_set_expanded_recurse (et->priv->etta, path, expanded);
-}
-
-void
-e_tree_root_node_set_visible (ETree *et, gboolean visible)
-{
- g_return_if_fail (et != NULL);
- g_return_if_fail (E_IS_TREE(et));
-
- e_tree_table_adapter_root_node_set_visible (et->priv->etta, visible);
-}
-
-ETreePath
-e_tree_node_at_row (ETree *et, int row)
-{
- ETreePath path;
-
- path = e_tree_table_adapter_node_at_row (et->priv->etta, row);
-
- return path;
-}
-
-int
-e_tree_row_of_node (ETree *et, ETreePath path)
-{
- return e_tree_table_adapter_row_of_node (et->priv->etta, path);
-}
-
-gboolean
-e_tree_root_node_is_visible(ETree *et)
-{
- return e_tree_table_adapter_root_node_is_visible (et->priv->etta);
-}
-
-void
-e_tree_show_node (ETree *et, ETreePath path)
-{
- g_return_if_fail (et != NULL);
- g_return_if_fail (E_IS_TREE(et));
-
- e_tree_table_adapter_show_node (et->priv->etta, path);
-}
-
-void
-e_tree_save_expanded_state (ETree *et, char *filename)
-{
- g_return_if_fail (et != NULL);
- g_return_if_fail (E_IS_TREE(et));
-
- e_tree_table_adapter_save_expanded_state (et->priv->etta, filename);
-}
-
-void
-e_tree_load_expanded_state (ETree *et, char *filename)
-{
- e_tree_table_adapter_load_expanded_state (et->priv->etta, filename);
-}
-
-gint
-e_tree_row_count (ETree *et)
-{
- return e_table_model_row_count (E_TABLE_MODEL(et->priv->etta));
-}
-
-GtkWidget *
-e_tree_get_tooltip (ETree *et)
-{
- return E_CANVAS(et->priv->table_canvas)->tooltip_window;
-}
-
-static ETreePath
-find_next_in_range (ETree *et, gint start, gint end, ETreePathFunc func, gpointer data)
-{
- ETreePath path;
- gint row;
-
- for (row = start; row <= end; row++) {
- path = e_tree_table_adapter_node_at_row (et->priv->etta, row);
- if (path && func (et->priv->model, path, data))
- return path;
- }
-
- return NULL;
-}
-
-static ETreePath
-find_prev_in_range (ETree *et, gint start, gint end, ETreePathFunc func, gpointer data)
-{
- ETreePath path;
- gint row;
-
- for (row = start; row >= end; row--) {
- path = e_tree_table_adapter_node_at_row (et->priv->etta, row);
- if (path && func (et->priv->model, path, data))
- return path;
- }
-
- return NULL;
-}
-
-gboolean
-e_tree_find_next (ETree *et, ETreeFindNextParams params, ETreePathFunc func, gpointer data)
-{
- ETreePath cursor, found;
- gint row, row_count;
-
- cursor = e_tree_get_cursor (et);
- row = e_tree_table_adapter_row_of_node (et->priv->etta, cursor);
- row_count = e_table_model_row_count (E_TABLE_MODEL (et->priv->etta));
-
- if (params & E_TREE_FIND_NEXT_FORWARD)
- found = find_next_in_range (et, row + 1, row_count - 1, func, data);
- else
- found = find_prev_in_range (et, row == -1 ? -1 : row - 1, 0, func, data);
-
- if (found) {
- e_tree_table_adapter_show_node (et->priv->etta, found);
- e_tree_set_cursor (et, found);
- return TRUE;
- }
-
- if (params & E_TREE_FIND_NEXT_WRAP) {
- if (params & E_TREE_FIND_NEXT_FORWARD)
- found = find_next_in_range (et, 0, row, func, data);
- else
- found = find_prev_in_range (et, row_count - 1, row, func, data);
-
- if (found && found != cursor) {
- e_tree_table_adapter_show_node (et->priv->etta, found);
- e_tree_set_cursor (et, found);
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-void
-e_tree_right_click_up (ETree *et)
-{
- e_selection_model_right_click_up(et->priv->selection);
-}
-
-/**
- * e_tree_get_model:
- * @et: the ETree
- *
- * Returns the model upon which this ETree is based.
- *
- * Returns: the model
- **/
-ETreeModel *
-e_tree_get_model (ETree *et)
-{
- g_return_val_if_fail (et != NULL, NULL);
- g_return_val_if_fail (E_IS_TREE (et), NULL);
-
- return et->priv->model;
-}
-
-/**
- * e_tree_get_selection_model:
- * @et: the ETree
- *
- * Returns the selection model of this ETree.
- *
- * Returns: the selection model
- **/
-ESelectionModel *
-e_tree_get_selection_model (ETree *et)
-{
- g_return_val_if_fail (et != NULL, NULL);
- g_return_val_if_fail (E_IS_TREE (et), NULL);
-
- return et->priv->selection;
-}
-
-/**
- * e_tree_get_table_adapter:
- * @et: the ETree
- *
- * Returns the table adapter this ETree uses.
- *
- * Returns: the model
- **/
-ETreeTableAdapter *
-e_tree_get_table_adapter (ETree *et)
-{
- g_return_val_if_fail (et != NULL, NULL);
- g_return_val_if_fail (E_IS_TREE (et), NULL);
-
- return et->priv->etta;
-}
-
-ETableItem *
-e_tree_get_item(ETree * et)
-{
- g_return_val_if_fail (et != NULL, NULL);
- g_return_val_if_fail (E_IS_TREE (et), NULL);
-
- return E_TABLE_ITEM (et->priv->item);
-}
-
-
-struct _ETreeDragSourceSite
-{
- GdkModifierType start_button_mask;
- GtkTargetList *target_list; /* Targets for drag data */
- GdkDragAction actions; /* Possible actions */
- GdkColormap *colormap; /* Colormap for drag icon */
- GdkPixmap *pixmap; /* Icon for drag data */
- GdkBitmap *mask;
-
- /* Stored button press information to detect drag beginning */
- gint state;
- gint x, y;
- gint row, col;
-};
-
-typedef enum
-{
- GTK_DRAG_STATUS_DRAG,
- GTK_DRAG_STATUS_WAIT,
- GTK_DRAG_STATUS_DROP
-} GtkDragStatus;
-
-typedef struct _GtkDragDestInfo GtkDragDestInfo;
-typedef struct _GtkDragSourceInfo GtkDragSourceInfo;
-
-struct _GtkDragDestInfo
-{
- GtkWidget *widget; /* Widget in which drag is in */
- GdkDragContext *context; /* Drag context */
- GtkDragSourceInfo *proxy_source; /* Set if this is a proxy drag */
- GtkSelectionData *proxy_data; /* Set while retrieving proxied data */
- gboolean dropped : 1; /* Set after we receive a drop */
- guint32 proxy_drop_time; /* Timestamp for proxied drop */
- gboolean proxy_drop_wait : 1; /* Set if we are waiting for a
- * status reply before sending
- * a proxied drop on.
- */
- gint drop_x, drop_y; /* Position of drop */
-};
-
-struct _GtkDragSourceInfo
-{
- GtkWidget *widget;
- GtkTargetList *target_list; /* Targets for drag data */
- GdkDragAction possible_actions; /* Actions allowed by source */
- GdkDragContext *context; /* drag context */
- GtkWidget *icon_window; /* Window for drag */
- GtkWidget *ipc_widget; /* GtkInvisible for grab, message passing */
- GdkCursor *cursor; /* Cursor for drag */
- gint hot_x, hot_y; /* Hot spot for drag */
- gint button; /* mouse button starting drag */
-
- GtkDragStatus status; /* drag status */
- GdkEvent *last_event; /* motion event waiting for response */
-
- gint start_x, start_y; /* Initial position */
- gint cur_x, cur_y; /* Current Position */
-
- GList *selections; /* selections we've claimed */
-
- GtkDragDestInfo *proxy_dest; /* Set if this is a proxy drag */
-
- guint drop_timeout; /* Timeout for aborting drop */
- guint destroy_icon : 1; /* If true, destroy icon_window
- */
-};
-
-/* Drag & drop stuff. */
-/* Target */
-
-void
-e_tree_drag_get_data (ETree *tree,
- int row,
- int col,
- GdkDragContext *context,
- GdkAtom target,
- guint32 time)
-{
- ETreePath path;
- g_return_if_fail(tree != NULL);
- g_return_if_fail(E_IS_TREE(tree));
-
- path = e_tree_table_adapter_node_at_row(tree->priv->etta, row);
-
- gtk_drag_get_data(GTK_WIDGET(tree),
- context,
- target,
- time);
-
-}
-
-/**
- * e_tree_drag_highlight:
- * @tree:
- * @row:
- * @col:
- *
- * Set col to -1 to highlight the entire row.
- * Set row to -1 to turn off the highlight.
- */
-void
-e_tree_drag_highlight (ETree *tree,
- int row,
- int col)
-{
- g_return_if_fail(tree != NULL);
- g_return_if_fail(E_IS_TREE(tree));
-
- if (row != -1) {
- int x, y, width, height;
- if (col == -1) {
- e_tree_get_cell_geometry (tree, row, 0, &x, &y, &width, &height);
- x = 0;
- width = GTK_WIDGET (tree->priv->table_canvas)->allocation.width;
- } else {
- e_tree_get_cell_geometry (tree, row, col, &x, &y, &width, &height);
- x += GTK_LAYOUT(tree->priv->table_canvas)->hadjustment->value;
- }
- y += GTK_LAYOUT(tree->priv->table_canvas)->vadjustment->value;
-
- if (tree->priv->drop_highlight == NULL) {
- tree->priv->drop_highlight =
- gnome_canvas_item_new (gnome_canvas_root (tree->priv->table_canvas),
- gnome_canvas_rect_get_type (),
- "fill_color", NULL,
- /* "outline_color", "black",
- "width_pixels", 1,*/
- "outline_color_gdk", &(GTK_WIDGET (tree)->style->fg[GTK_STATE_NORMAL]),
- NULL);
- }
- gnome_canvas_item_set (tree->priv->drop_highlight,
- "x1", (double) x,
- "x2", (double) x + width - 1,
- "y1", (double) y,
- "y2", (double) y + height - 1,
- NULL);
- } else {
- gtk_object_destroy (GTK_OBJECT (tree->priv->drop_highlight));
- tree->priv->drop_highlight = NULL;
- }
-}
-
-void
-e_tree_drag_unhighlight (ETree *tree)
-{
- g_return_if_fail(tree != NULL);
- g_return_if_fail(E_IS_TREE(tree));
-
- if (tree->priv->drop_highlight) {
- gtk_object_destroy (GTK_OBJECT (tree->priv->drop_highlight));
- tree->priv->drop_highlight = NULL;
- }
-}
-
-void e_tree_drag_dest_set (ETree *tree,
- GtkDestDefaults flags,
- const GtkTargetEntry *targets,
- gint n_targets,
- GdkDragAction actions)
-{
- g_return_if_fail(tree != NULL);
- g_return_if_fail(E_IS_TREE(tree));
-
- gtk_drag_dest_set(GTK_WIDGET(tree),
- flags,
- targets,
- n_targets,
- actions);
-}
-
-void e_tree_drag_dest_set_proxy (ETree *tree,
- GdkWindow *proxy_window,
- GdkDragProtocol protocol,
- gboolean use_coordinates)
-{
- g_return_if_fail(tree != NULL);
- g_return_if_fail(E_IS_TREE(tree));
-
- gtk_drag_dest_set_proxy(GTK_WIDGET(tree),
- proxy_window,
- protocol,
- use_coordinates);
-}
-
-/*
- * There probably should be functions for setting the targets
- * as a GtkTargetList
- */
-
-void
-e_tree_drag_dest_unset (GtkWidget *widget)
-{
- g_return_if_fail(widget != NULL);
- g_return_if_fail(E_IS_TREE(widget));
-
- gtk_drag_dest_unset(widget);
-}
-
-/* Source side */
-
-static gint
-et_real_start_drag (ETree *tree, int row, ETreePath path, int col, GdkEvent *event)
-{
- GtkDragSourceInfo *info;
- GdkDragContext *context;
- ETreeDragSourceSite *site;
-
- if (tree->priv->do_drag) {
- site = tree->priv->site;
-
- site->state = 0;
- context = e_tree_drag_begin (tree, row, col,
- site->target_list,
- site->actions,
- 1, event);
-
- if (context) {
- info = g_dataset_get_data (context, "gtk-info");
-
- if (info && !info->icon_window) {
- if (site->pixmap)
- gtk_drag_set_icon_pixmap (context,
- site->colormap,
- site->pixmap,
- site->mask, -2, -2);
- else
- gtk_drag_set_icon_default (context);
- }
- }
- return TRUE;
- }
- return FALSE;
-}
-
-void
-e_tree_drag_source_set (ETree *tree,
- GdkModifierType start_button_mask,
- const GtkTargetEntry *targets,
- gint n_targets,
- GdkDragAction actions)
-{
- ETreeDragSourceSite *site;
- GtkWidget *canvas;
-
- g_return_if_fail(tree != NULL);
- g_return_if_fail(E_IS_TREE(tree));
-
- canvas = GTK_WIDGET(tree->priv->table_canvas);
- site = tree->priv->site;
-
- tree->priv->do_drag = TRUE;
-
- gtk_widget_add_events (canvas,
- gtk_widget_get_events (canvas) |
- GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
- GDK_BUTTON_MOTION_MASK | GDK_STRUCTURE_MASK);
-
- if (site) {
- if (site->target_list)
- gtk_target_list_unref (site->target_list);
- } else {
- site = g_new0 (ETreeDragSourceSite, 1);
- tree->priv->site = site;
- }
-
- site->start_button_mask = start_button_mask;
-
- if (targets)
- site->target_list = gtk_target_list_new (targets, n_targets);
- else
- site->target_list = NULL;
-
- site->actions = actions;
-}
-
-void
-e_tree_drag_source_unset (ETree *tree)
-{
- ETreeDragSourceSite *site;
-
- g_return_if_fail (tree != NULL);
- g_return_if_fail (E_IS_TREE(tree));
-
- site = tree->priv->site;
-
- if (site) {
- if (site->target_list)
- gtk_target_list_unref (site->target_list);
- g_free (site);
- tree->priv->site = NULL;
- }
-}
-
-/* There probably should be functions for setting the targets
- * as a GtkTargetList
- */
-
-GdkDragContext *
-e_tree_drag_begin (ETree *tree,
- int row,
- int col,
- GtkTargetList *targets,
- GdkDragAction actions,
- gint button,
- GdkEvent *event)
-{
- ETreePath path;
- g_return_val_if_fail (tree != NULL, NULL);
- g_return_val_if_fail (E_IS_TREE(tree), NULL);
-
- path = e_tree_table_adapter_node_at_row(tree->priv->etta, row);
-
- tree->priv->drag_row = row;
- tree->priv->drag_path = path;
- tree->priv->drag_col = col;
-
- return gtk_drag_begin(GTK_WIDGET (tree->priv->table_canvas),
- targets,
- actions,
- button,
- event);
-}
-
-/**
- * e_tree_get_cell_at:
- * @tree: An ETree widget
- * @x: X coordinate for the pixel
- * @y: Y coordinate for the pixel
- * @row_return: Pointer to return the row value
- * @col_return: Pointer to return the column value
- *
- * Return the row and column for the cell in which the pixel at (@x, @y) is
- * contained.
- **/
-void
-e_tree_get_cell_at (ETree *tree,
- int x, int y,
- int *row_return, int *col_return)
-{
- g_return_if_fail (tree != NULL);
- g_return_if_fail (E_IS_TREE (tree));
- g_return_if_fail (row_return != NULL);
- g_return_if_fail (col_return != NULL);
-
- /* FIXME it would be nice if it could handle a NULL row_return or
- * col_return gracefully. */
-
- if (row_return)
- *row_return = -1;
- if (col_return)
- *col_return = -1;
-
- x += GTK_LAYOUT(tree->priv->table_canvas)->hadjustment->value;
- y += GTK_LAYOUT(tree->priv->table_canvas)->vadjustment->value;
- e_table_item_compute_location(E_TABLE_ITEM(tree->priv->item), &x, &y, row_return, col_return);
-}
-
-/**
- * e_tree_get_cell_geometry:
- * @tree: The tree.
- * @row: The row to get the geometry of.
- * @col: The col to get the geometry of.
- * @x_return: Returns the x coordinate of the upper right hand corner of the cell with respect to the widget.
- * @y_return: Returns the y coordinate of the upper right hand corner of the cell with respect to the widget.
- * @width_return: Returns the width of the cell.
- * @height_return: Returns the height of the cell.
- *
- * Computes the data about this cell.
- **/
-void
-e_tree_get_cell_geometry (ETree *tree,
- int row, int col,
- int *x_return, int *y_return,
- int *width_return, int *height_return)
-{
- g_return_if_fail (tree != NULL);
- g_return_if_fail (E_IS_TREE (tree));
- g_return_if_fail (row >= 0);
- g_return_if_fail (col >= 0);
-
- /* FIXME it would be nice if it could handle a NULL row_return or
- * col_return gracefully. */
-
- e_table_item_get_cell_geometry(E_TABLE_ITEM(tree->priv->item), &row, &col, x_return, y_return, width_return, height_return);
-
- if (x_return)
- (*x_return) -= GTK_LAYOUT(tree->priv->table_canvas)->hadjustment->value;
- if (y_return)
- (*y_return) -= GTK_LAYOUT(tree->priv->table_canvas)->vadjustment->value;
-}
-
-static void
-et_drag_begin (GtkWidget *widget,
- GdkDragContext *context,
- ETree *et)
-{
- g_signal_emit (et,
- et_signals [TREE_DRAG_BEGIN], 0,
- et->priv->drag_row,
- et->priv->drag_path,
- et->priv->drag_col,
- context);
-}
-
-static void
-et_drag_end (GtkWidget *widget,
- GdkDragContext *context,
- ETree *et)
-{
- g_signal_emit (et,
- et_signals [TREE_DRAG_END], 0,
- et->priv->drag_row,
- et->priv->drag_path,
- et->priv->drag_col,
- context);
-}
-
-static void
-et_drag_data_get(GtkWidget *widget,
- GdkDragContext *context,
- GtkSelectionData *selection_data,
- guint info,
- guint time,
- ETree *et)
-{
- g_signal_emit (et,
- et_signals [TREE_DRAG_DATA_GET], 0,
- et->priv->drag_row,
- et->priv->drag_path,
- et->priv->drag_col,
- context,
- selection_data,
- info,
- time);
-}
-
-static void
-et_drag_data_delete(GtkWidget *widget,
- GdkDragContext *context,
- ETree *et)
-{
- g_signal_emit (et,
- et_signals [TREE_DRAG_DATA_DELETE], 0,
- et->priv->drag_row,
- et->priv->drag_path,
- et->priv->drag_col,
- context);
-}
-
-static gboolean
-do_drag_motion(ETree *et,
- GdkDragContext *context,
- gint x,
- gint y,
- guint time)
-{
- gboolean ret_val = FALSE;
- int row, col;
- ETreePath path;
- GtkWidget *widget;
-
- widget = GTK_WIDGET (et);
-
- e_tree_get_cell_at (et,
- x,
- y,
- &row,
- &col);
- if (row != et->priv->drop_row && col != et->priv->drop_col) {
- g_signal_emit (et,
- et_signals [TREE_DRAG_LEAVE], 0,
- et->priv->drop_row,
- et->priv->drop_path,
- et->priv->drop_col,
- context,
- time);
- }
-
- path = e_tree_table_adapter_node_at_row(et->priv->etta, row);
-
- et->priv->drop_row = row;
- et->priv->drop_path = path;
- et->priv->drop_col = col;
- g_signal_emit (et,
- et_signals [TREE_DRAG_MOTION], 0,
- et->priv->drop_row,
- et->priv->drop_path,
- et->priv->drop_col,
- context,
- x,
- y,
- time,
- &ret_val);
-
- return ret_val;
-}
-
-static gboolean
-scroll_timeout (gpointer data)
-{
- ETree *et = data;
- int dx = 0, dy = 0;
- GtkAdjustment *v, *h;
- double vvalue, hvalue;
-
- if (et->priv->scroll_direction & ET_SCROLL_DOWN)
- dy += 20;
- if (et->priv->scroll_direction & ET_SCROLL_UP)
- dy -= 20;
-
- if (et->priv->scroll_direction & ET_SCROLL_RIGHT)
- dx += 20;
- if (et->priv->scroll_direction & ET_SCROLL_LEFT)
- dx -= 20;
-
- h = GTK_LAYOUT(et->priv->table_canvas)->hadjustment;
- v = GTK_LAYOUT(et->priv->table_canvas)->vadjustment;
-
- hvalue = h->value;
- vvalue = v->value;
-
- gtk_adjustment_set_value(h, CLAMP(h->value + dx, h->lower, h->upper - h->page_size));
- gtk_adjustment_set_value(v, CLAMP(v->value + dy, v->lower, v->upper - v->page_size));
-
- if (h->value != hvalue ||
- v->value != vvalue)
- do_drag_motion(et,
- et->priv->last_drop_context,
- et->priv->last_drop_x,
- et->priv->last_drop_y,
- et->priv->last_drop_time);
-
-
- return TRUE;
-}
-
-static void
-scroll_on (ETree *et, guint scroll_direction)
-{
- if (et->priv->scroll_idle_id == 0 || scroll_direction != et->priv->scroll_direction) {
- if (et->priv->scroll_idle_id != 0)
- g_source_remove (et->priv->scroll_idle_id);
- et->priv->scroll_direction = scroll_direction;
- et->priv->scroll_idle_id = g_timeout_add (100, scroll_timeout, et);
- }
-}
-
-static void
-scroll_off (ETree *et)
-{
- if (et->priv->scroll_idle_id) {
- g_source_remove (et->priv->scroll_idle_id);
- et->priv->scroll_idle_id = 0;
- }
-}
-
-static gboolean
-hover_timeout (gpointer data)
-{
- ETree *et = data;
- int x = et->priv->hover_x;
- int y = et->priv->hover_y;
- int row, col;
- ETreePath path;
-
- e_tree_get_cell_at (et,
- x,
- y,
- &row,
- &col);
-
- path = e_tree_table_adapter_node_at_row(et->priv->etta, row);
- if (path && e_tree_model_node_is_expandable (et->priv->model, path)) {
- if (!e_tree_table_adapter_node_is_expanded (et->priv->etta, path)) {
- if (e_tree_model_has_save_id (et->priv->model) && e_tree_model_has_get_node_by_id (et->priv->model))
- et->priv->expanded_list = g_list_prepend (et->priv->expanded_list, e_tree_model_get_save_id (et->priv->model, path));
- e_tree_table_adapter_node_set_expanded (et->priv->etta, path, TRUE);
- }
- }
-
- return TRUE;
-}
-
-static void
-hover_on (ETree *et, int x, int y)
-{
- et->priv->hover_x = x;
- et->priv->hover_y = y;
- if (et->priv->hover_idle_id != 0)
- g_source_remove (et->priv->hover_idle_id);
- et->priv->hover_idle_id = g_timeout_add (500, hover_timeout, et);
-}
-
-static void
-hover_off (ETree *et)
-{
- if (et->priv->hover_idle_id) {
- g_source_remove (et->priv->hover_idle_id);
- et->priv->hover_idle_id = 0;
- }
-}
-
-static void
-collapse_drag (ETree *et, ETreePath drop)
-{
- GList *list;
-
- /* We only want to leave open parents of the node dropped in. Not the node itself. */
- if (drop) {
- drop = e_tree_model_node_get_parent (et->priv->model, drop);
- }
-
- for (list = et->priv->expanded_list; list; list = list->next) {
- char *save_id = list->data;
- ETreePath path;
-
- path = e_tree_model_get_node_by_id (et->priv->model, save_id);
- if (path) {
- ETreePath search;
- gboolean found = FALSE;
-
- for (search = drop; search; search = e_tree_model_node_get_parent (et->priv->model, search)) {
- if (path == search) {
- found = TRUE;
- break;
- }
- }
-
- if (!found)
- e_tree_table_adapter_node_set_expanded (et->priv->etta, path, FALSE);
- }
- g_free (save_id);
- }
- g_list_free (et->priv->expanded_list);
- et->priv->expanded_list = NULL;
-}
-
-static void
-context_destroyed (gpointer data, GObject *ctx)
-{
- ETree *et = data;
- if (et->priv) {
- et->priv->last_drop_x = 0;
- et->priv->last_drop_y = 0;
- et->priv->last_drop_time = 0;
- et->priv->last_drop_context = NULL;
- collapse_drag (et, NULL);
- scroll_off (et);
- hover_off (et);
- }
- g_object_unref (et);
-}
-
-static void
-context_connect (ETree *et, GdkDragContext *context)
-{
- if (context == et->priv->last_drop_context)
- return;
-
- if (et->priv->last_drop_context)
- g_object_weak_unref (G_OBJECT(et->priv->last_drop_context), context_destroyed, et);
- else
- g_object_ref (et);
-
- g_object_weak_ref (G_OBJECT(context), context_destroyed, et);
-}
-
-static void
-et_drag_leave(GtkWidget *widget,
- GdkDragContext *context,
- guint time,
- ETree *et)
-{
- g_signal_emit (et,
- et_signals [TREE_DRAG_LEAVE], 0,
- et->priv->drop_row,
- et->priv->drop_path,
- et->priv->drop_col,
- context,
- time);
- et->priv->drop_row = -1;
- et->priv->drop_col = -1;
-
- scroll_off (et);
- hover_off (et);
-}
-
-static gboolean
-et_drag_motion(GtkWidget *widget,
- GdkDragContext *context,
- gint x,
- gint y,
- guint time,
- ETree *et)
-{
- int ret_val;
- guint direction = 0;
-
- et->priv->last_drop_x = x;
- et->priv->last_drop_y = y;
- et->priv->last_drop_time = time;
- context_connect (et, context);
- et->priv->last_drop_context = context;
-
- if (et->priv->hover_idle_id != 0) {
- if (abs (et->priv->hover_x - x) > 3 ||
- abs (et->priv->hover_y - y) > 3) {
- hover_on (et, x, y);
- }
- } else {
- hover_on (et, x, y);
- }
-
- ret_val = do_drag_motion (et,
- context,
- x,
- y,
- time);
-
- if (y < 20)
- direction |= ET_SCROLL_UP;
- if (y > widget->allocation.height - 20)
- direction |= ET_SCROLL_DOWN;
- if (x < 20)
- direction |= ET_SCROLL_LEFT;
- if (x > widget->allocation.width - 20)
- direction |= ET_SCROLL_RIGHT;
-
- if (direction != 0)
- scroll_on (et, direction);
- else
- scroll_off (et);
-
- return ret_val;
-}
-
-static gboolean
-et_drag_drop(GtkWidget *widget,
- GdkDragContext *context,
- gint x,
- gint y,
- guint time,
- ETree *et)
-{
- gboolean ret_val = FALSE;
- int row, col;
- ETreePath path;
- e_tree_get_cell_at(et,
- x,
- y,
- &row,
- &col);
- path = e_tree_table_adapter_node_at_row(et->priv->etta, row);
-
- if (row != et->priv->drop_row && col != et->priv->drop_row) {
- g_signal_emit (et,
- et_signals [TREE_DRAG_LEAVE], 0,
- et->priv->drop_row,
- et->priv->drop_path,
- et->priv->drop_col,
- context,
- time);
- g_signal_emit (et,
- et_signals [TREE_DRAG_MOTION], 0,
- row,
- path,
- col,
- context,
- x,
- y,
- time,
- &ret_val);
- }
- et->priv->drop_row = row;
- et->priv->drop_path = path;
- et->priv->drop_col = col;
-
- g_signal_emit (et,
- et_signals [TREE_DRAG_DROP], 0,
- et->priv->drop_row,
- et->priv->drop_path,
- et->priv->drop_col,
- context,
- x,
- y,
- time,
- &ret_val);
-
- et->priv->drop_row = -1;
- et->priv->drop_path = NULL;
- et->priv->drop_col = -1;
-
- collapse_drag (et, path);
-
- scroll_off (et);
- return ret_val;
-}
-
-static void
-et_drag_data_received(GtkWidget *widget,
- GdkDragContext *context,
- gint x,
- gint y,
- GtkSelectionData *selection_data,
- guint info,
- guint time,
- ETree *et)
-{
- int row, col;
- ETreePath path;
- e_tree_get_cell_at(et,
- x,
- y,
- &row,
- &col);
- path = e_tree_table_adapter_node_at_row(et->priv->etta, row);
- g_signal_emit (et,
- et_signals [TREE_DRAG_DATA_RECEIVED], 0,
- row,
- path,
- col,
- context,
- x,
- y,
- selection_data,
- info,
- time);
-}
-
-static void
-e_tree_class_init (ETreeClass *class)
-{
- GObjectClass *object_class;
- GtkWidgetClass *widget_class;
- GtkContainerClass *container_class;
-
- object_class = (GObjectClass *) class;
- widget_class = (GtkWidgetClass *) class;
- container_class = (GtkContainerClass *) class;
-
- parent_class = g_type_class_ref (PARENT_TYPE);
-
- object_class->dispose = et_dispose;
- object_class->set_property = et_set_property;
- object_class->get_property = et_get_property;
-
- widget_class->grab_focus = et_grab_focus;
- widget_class->unrealize = et_unrealize;
- widget_class->style_set = et_canvas_style_set;
- widget_class->focus = et_focus;
-
- class->cursor_change = NULL;
- class->cursor_activated = NULL;
- class->selection_change = NULL;
- class->double_click = NULL;
- class->right_click = NULL;
- class->click = NULL;
- class->key_press = NULL;
- class->start_drag = et_real_start_drag;
- class->state_change = NULL;
- class->white_space_event = NULL;
-
- class->tree_drag_begin = NULL;
- class->tree_drag_end = NULL;
- class->tree_drag_data_get = NULL;
- class->tree_drag_data_delete = NULL;
-
- class->tree_drag_leave = NULL;
- class->tree_drag_motion = NULL;
- class->tree_drag_drop = NULL;
- class->tree_drag_data_received = NULL;
-
- et_signals [CURSOR_CHANGE] =
- g_signal_new ("cursor_change",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETreeClass, cursor_change),
- NULL, NULL,
- e_marshal_NONE__INT_POINTER,
- G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_POINTER);
-
- et_signals [CURSOR_ACTIVATED] =
- g_signal_new ("cursor_activated",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETreeClass, cursor_activated),
- NULL, NULL,
- e_marshal_NONE__INT_POINTER,
- G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_POINTER);
-
- et_signals [SELECTION_CHANGE] =
- g_signal_new ("selection_change",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETreeClass, selection_change),
- NULL, NULL,
- e_marshal_NONE__NONE,
- G_TYPE_NONE, 0);
-
- et_signals [DOUBLE_CLICK] =
- g_signal_new ("double_click",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETreeClass, double_click),
- NULL, NULL,
- e_marshal_NONE__INT_POINTER_INT_BOXED,
- G_TYPE_NONE, 4, G_TYPE_INT,
- G_TYPE_POINTER, G_TYPE_INT, GDK_TYPE_EVENT);
-
- et_signals [RIGHT_CLICK] =
- g_signal_new ("right_click",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETreeClass, right_click),
- NULL, NULL,
- e_marshal_INT__INT_POINTER_INT_BOXED,
- G_TYPE_INT, 4, G_TYPE_INT, G_TYPE_POINTER,
- G_TYPE_INT, GDK_TYPE_EVENT);
-
- et_signals [CLICK] =
- g_signal_new ("click",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETreeClass, click),
- NULL, NULL,
- e_marshal_INT__INT_POINTER_INT_BOXED,
- G_TYPE_INT, 4, G_TYPE_INT, G_TYPE_POINTER,
- G_TYPE_INT, GDK_TYPE_EVENT);
-
- et_signals [KEY_PRESS] =
- g_signal_new ("key_press",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETreeClass, key_press),
- NULL, NULL,
- e_marshal_INT__INT_POINTER_INT_BOXED,
- G_TYPE_INT, 4, G_TYPE_INT, G_TYPE_POINTER,
- G_TYPE_INT, GDK_TYPE_EVENT);
-
- et_signals [START_DRAG] =
- g_signal_new ("start_drag",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETreeClass, start_drag),
- NULL, NULL,
- e_marshal_NONE__INT_POINTER_INT_BOXED,
- G_TYPE_NONE, 4, G_TYPE_INT, G_TYPE_POINTER,
- G_TYPE_INT, GDK_TYPE_EVENT);
-
- et_signals [STATE_CHANGE] =
- g_signal_new ("state_change",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETreeClass, state_change),
- NULL, NULL,
- e_marshal_NONE__NONE,
- G_TYPE_NONE, 0);
-
- et_signals [WHITE_SPACE_EVENT] =
- g_signal_new ("white_space_event",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETreeClass, white_space_event),
- NULL, NULL,
- e_marshal_INT__POINTER,
- G_TYPE_INT, 1, GDK_TYPE_EVENT);
-
- et_signals[TREE_DRAG_BEGIN] =
- g_signal_new ("tree_drag_begin",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETreeClass, tree_drag_begin),
- NULL, NULL,
- e_marshal_NONE__INT_POINTER_INT_BOXED,
- G_TYPE_NONE, 4,
- G_TYPE_INT,
- G_TYPE_POINTER,
- G_TYPE_INT,
- GDK_TYPE_DRAG_CONTEXT);
- et_signals[TREE_DRAG_END] =
- g_signal_new ("tree_drag_end",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETreeClass, tree_drag_end),
- NULL, NULL,
- e_marshal_NONE__INT_POINTER_INT_BOXED,
- G_TYPE_NONE, 4,
- G_TYPE_INT,
- G_TYPE_POINTER,
- G_TYPE_INT,
- GDK_TYPE_DRAG_CONTEXT);
- et_signals[TREE_DRAG_DATA_GET] =
- g_signal_new ("tree_drag_data_get",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETreeClass, tree_drag_data_get),
- NULL, NULL,
- e_marshal_NONE__INT_POINTER_INT_OBJECT_BOXED_UINT_UINT,
- G_TYPE_NONE, 7,
- G_TYPE_INT,
- G_TYPE_POINTER,
- G_TYPE_INT,
- GDK_TYPE_DRAG_CONTEXT,
- GTK_TYPE_SELECTION_DATA | G_SIGNAL_TYPE_STATIC_SCOPE,
- G_TYPE_UINT,
- G_TYPE_UINT);
- et_signals[TREE_DRAG_DATA_DELETE] =
- g_signal_new ("tree_drag_data_delete",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETreeClass, tree_drag_data_delete),
- NULL, NULL,
- e_marshal_NONE__INT_POINTER_INT_OBJECT,
- G_TYPE_NONE, 4,
- G_TYPE_INT,
- G_TYPE_POINTER,
- G_TYPE_INT,
- GDK_TYPE_DRAG_CONTEXT);
-
- et_signals[TREE_DRAG_LEAVE] =
- g_signal_new ("tree_drag_leave",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETreeClass, tree_drag_leave),
- NULL, NULL,
- e_marshal_NONE__INT_POINTER_INT_OBJECT_UINT,
- G_TYPE_NONE, 5,
- G_TYPE_INT,
- G_TYPE_POINTER,
- G_TYPE_INT,
- GDK_TYPE_DRAG_CONTEXT,
- G_TYPE_UINT);
- et_signals[TREE_DRAG_MOTION] =
- g_signal_new ("tree_drag_motion",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETreeClass, tree_drag_motion),
- NULL, NULL,
- e_marshal_BOOLEAN__INT_POINTER_INT_OBJECT_INT_INT_UINT,
- G_TYPE_BOOLEAN, 7,
- G_TYPE_INT,
- G_TYPE_POINTER,
- G_TYPE_INT,
- GDK_TYPE_DRAG_CONTEXT,
- G_TYPE_INT,
- G_TYPE_INT,
- G_TYPE_UINT);
- et_signals[TREE_DRAG_DROP] =
- g_signal_new ("tree_drag_drop",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETreeClass, tree_drag_drop),
- NULL, NULL,
- e_marshal_BOOLEAN__INT_POINTER_INT_OBJECT_INT_INT_UINT,
- G_TYPE_BOOLEAN, 7,
- G_TYPE_INT,
- G_TYPE_POINTER,
- G_TYPE_INT,
- GDK_TYPE_DRAG_CONTEXT,
- G_TYPE_INT,
- G_TYPE_INT,
- G_TYPE_UINT);
- et_signals[TREE_DRAG_DATA_RECEIVED] =
- g_signal_new ("tree_drag_data_received",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETreeClass, tree_drag_data_received),
- NULL, NULL,
- e_marshal_NONE__INT_POINTER_INT_OBJECT_INT_INT_BOXED_UINT_UINT,
- G_TYPE_NONE, 9,
- G_TYPE_INT,
- G_TYPE_POINTER,
- G_TYPE_INT,
- GDK_TYPE_DRAG_CONTEXT,
- G_TYPE_INT,
- G_TYPE_INT,
- GTK_TYPE_SELECTION_DATA,
- G_TYPE_UINT,
- G_TYPE_UINT);
-
- class->set_scroll_adjustments = set_scroll_adjustments;
-
- widget_class->set_scroll_adjustments_signal =
- g_signal_new ("set_scroll_adjustments",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETreeClass, set_scroll_adjustments),
- NULL, NULL,
- e_marshal_NONE__POINTER_POINTER,
- G_TYPE_NONE, 2, GTK_TYPE_ADJUSTMENT,
- GTK_TYPE_ADJUSTMENT);
-
- g_object_class_install_property (object_class, PROP_LENGTH_THRESHOLD,
- g_param_spec_int ("length_threshold",
- _( "Length Threshold" ),
- _( "Length Threshold" ),
- 0, G_MAXINT, 0,
- G_PARAM_WRITABLE));
- g_object_class_install_property (object_class, PROP_HORIZONTAL_DRAW_GRID,
- g_param_spec_boolean ("horizontal_draw_grid",
- _( "Horizontal Draw Grid" ),
- _( "Horizontal Draw Grid" ),
- FALSE,
- G_PARAM_WRITABLE));
- g_object_class_install_property (object_class, PROP_VERTICAL_DRAW_GRID,
- g_param_spec_boolean ("vertical_draw_grid",
- _( "Vertical Draw Grid" ),
- _( "Vertical Draw Grid" ),
- FALSE,
- G_PARAM_WRITABLE));
- g_object_class_install_property (object_class, PROP_DRAW_FOCUS,
- g_param_spec_boolean ("drawfocus",
- _( "Draw focus" ),
- _( "Draw focus" ),
- FALSE,
- G_PARAM_WRITABLE));
-
- g_object_class_install_property (object_class, PROP_ETTA,
- g_param_spec_object ("ETreeTableAdapter",
- _( "ETree table adapter" ),
- _( "ETree table adapter" ),
- E_TREE_TABLE_ADAPTER_TYPE,
- G_PARAM_READABLE));
-
- g_object_class_install_property (object_class, PROP_UNIFORM_ROW_HEIGHT,
- g_param_spec_boolean ("uniform_row_height",
- _( "Uniform row height" ),
- _( "Uniform row height" ),
- FALSE,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class, PROP_ALWAYS_SEARCH,
- g_param_spec_boolean ("always_search",
- _( "Always search" ),
- _( "Always search" ),
- FALSE,
- G_PARAM_READWRITE));
-
- gtk_widget_class_install_style_property (widget_class,
- g_param_spec_boolean ("retro_look",
- _("Retro Look"),
- _("Draw lines and +/- expanders."),
- FALSE,
- G_PARAM_READABLE));
-
- gtk_widget_class_install_style_property (widget_class,
- g_param_spec_int ("expander_size",
- _("Expander Size"),
- _("Size of the expander arrow"),
- 0,
- G_MAXINT,
- 10,
- G_PARAM_READABLE));
-
- gal_a11y_e_tree_init ();
-}
-
-E_MAKE_TYPE(e_tree, "ETree", ETree, e_tree_class_init, e_tree_init, PARENT_TYPE)
diff --git a/widgets/table/e-tree.h b/widgets/table/e-tree.h
deleted file mode 100644
index 197ef05fef..0000000000
--- a/widgets/table/e-tree.h
+++ /dev/null
@@ -1,312 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-tree.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Chris Lahey <clahey@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef _E_TREE_H_
-#define _E_TREE_H_
-
-#include <gtk/gtkdnd.h>
-#include <gtk/gtktable.h>
-#include <libxml/tree.h>
-#include <libgnomecanvas/gnome-canvas.h>
-#include <gal/widgets/e-printable.h>
-
-#include <gal/e-table/e-table-extras.h>
-#include <gal/e-table/e-table-specification.h>
-#include <gal/e-table/e-table-state.h>
-#include <gal/e-table/e-tree-model.h>
-#include <gal/e-table/e-tree-table-adapter.h>
-#include <gal/e-table/e-table-item.h>
-
-#define E_TREE_USE_TREE_SELECTION
-
-#ifdef E_TREE_USE_TREE_SELECTION
-#include <gal/e-table/e-tree-selection-model.h>
-#endif
-
-G_BEGIN_DECLS
-
-#define E_TREE_TYPE (e_tree_get_type ())
-#define E_TREE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TREE_TYPE, ETree))
-#define E_TREE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TREE_TYPE, ETreeClass))
-#define E_IS_TREE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TREE_TYPE))
-#define E_IS_TREE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TREE_TYPE))
-typedef struct _ETreeDragSourceSite ETreeDragSourceSite;
-typedef struct ETreePriv ETreePriv;
-
-typedef struct {
- GtkTable parent;
-
- ETreePriv *priv;
-} ETree;
-
-typedef struct {
- GtkTableClass parent_class;
-
- void (*cursor_change) (ETree *et, int row, ETreePath path);
- void (*cursor_activated) (ETree *et, int row, ETreePath path);
- void (*selection_change) (ETree *et);
- void (*double_click) (ETree *et, int row, ETreePath path, int col, GdkEvent *event);
- gint (*right_click) (ETree *et, int row, ETreePath path, int col, GdkEvent *event);
- gint (*click) (ETree *et, int row, ETreePath path, int col, GdkEvent *event);
- gint (*key_press) (ETree *et, int row, ETreePath path, int col, GdkEvent *event);
- gint (*start_drag) (ETree *et, int row, ETreePath path, int col, GdkEvent *event);
- gint (*state_change) (ETree *et);
- gint (*white_space_event) (ETree *et, GdkEvent *event);
-
- void (*set_scroll_adjustments) (ETree *tree,
- GtkAdjustment *hadjustment,
- GtkAdjustment *vadjustment);
-
- /* Source side drag signals */
- void (* tree_drag_begin) (ETree *tree,
- int row,
- ETreePath path,
- int col,
- GdkDragContext *context);
- void (* tree_drag_end) (ETree *tree,
- int row,
- ETreePath path,
- int col,
- GdkDragContext *context);
- void (* tree_drag_data_get) (ETree *tree,
- int row,
- ETreePath path,
- int col,
- GdkDragContext *context,
- GtkSelectionData *selection_data,
- guint info,
- guint time);
- void (* tree_drag_data_delete) (ETree *tree,
- int row,
- ETreePath path,
- int col,
- GdkDragContext *context);
-
- /* Target side drag signals */
- void (* tree_drag_leave) (ETree *tree,
- int row,
- ETreePath path,
- int col,
- GdkDragContext *context,
- guint time);
- gboolean (* tree_drag_motion) (ETree *tree,
- int row,
- ETreePath path,
- int col,
- GdkDragContext *context,
- gint x,
- gint y,
- guint time);
- gboolean (* tree_drag_drop) (ETree *tree,
- int row,
- ETreePath path,
- int col,
- GdkDragContext *context,
- gint x,
- gint y,
- guint time);
- void (* tree_drag_data_received) (ETree *tree,
- int row,
- ETreePath path,
- int col,
- GdkDragContext *context,
- gint x,
- gint y,
- GtkSelectionData *selection_data,
- guint info,
- guint time);
-} ETreeClass;
-
-GType e_tree_get_type (void);
-ETree *e_tree_construct (ETree *e_tree,
- ETreeModel *etm,
- ETableExtras *ete,
- const char *spec,
- const char *state);
-GtkWidget *e_tree_new (ETreeModel *etm,
- ETableExtras *ete,
- const char *spec,
- const char *state);
-
-/* Create an ETree using files. */
-ETree *e_tree_construct_from_spec_file (ETree *e_tree,
- ETreeModel *etm,
- ETableExtras *ete,
- const char *spec_fn,
- const char *state_fn);
-GtkWidget *e_tree_new_from_spec_file (ETreeModel *etm,
- ETableExtras *ete,
- const char *spec_fn,
- const char *state_fn);
-
-/* To save the state */
-gchar *e_tree_get_state (ETree *e_tree);
-void e_tree_save_state (ETree *e_tree,
- const gchar *filename);
-ETableState *e_tree_get_state_object (ETree *e_tree);
-ETableSpecification *e_tree_get_spec (ETree *e_tree);
-
-/* note that it is more efficient to provide the state at creation time */
-void e_tree_set_search_column (ETree *e_tree,
- gint col);
-void e_tree_set_state (ETree *e_tree,
- const gchar *state);
-void e_tree_set_state_object (ETree *e_tree,
- ETableState *state);
-void e_tree_load_state (ETree *e_tree,
- const gchar *filename);
-void e_tree_set_cursor (ETree *e_tree,
- ETreePath path);
-
-/* NULL means we don't have the cursor. */
-ETreePath e_tree_get_cursor (ETree *e_tree);
-void e_tree_selected_row_foreach (ETree *e_tree,
- EForeachFunc callback,
- gpointer closure);
-#ifdef E_TREE_USE_TREE_SELECTION
-void e_tree_selected_path_foreach (ETree *e_tree,
- ETreeForeachFunc callback,
- gpointer closure);
-void e_tree_path_foreach (ETree *e_tree,
- ETreeForeachFunc callback,
- gpointer closure);
-#endif
-gint e_tree_selected_count (ETree *e_tree);
-EPrintable *e_tree_get_printable (ETree *e_tree);
-gint e_tree_get_next_row (ETree *e_tree,
- gint model_row);
-gint e_tree_get_prev_row (ETree *e_tree,
- gint model_row);
-gint e_tree_model_to_view_row (ETree *e_tree,
- gint model_row);
-gint e_tree_view_to_model_row (ETree *e_tree,
- gint view_row);
-void e_tree_get_cell_at (ETree *tree,
- int x,
- int y,
- int *row_return,
- int *col_return);
-void e_tree_get_cell_geometry (ETree *tree,
- int row,
- int col,
- int *x_return,
- int *y_return,
- int *width_return,
- int *height_return);
-
-/* Useful accessors */
-ETreeModel * e_tree_get_model (ETree *et);
-ESelectionModel *e_tree_get_selection_model (ETree *et);
-ETreeTableAdapter *e_tree_get_table_adapter (ETree *et);
-
-/* Drag & drop stuff. */
-/* Target */
-void e_tree_drag_get_data (ETree *tree,
- int row,
- int col,
- GdkDragContext *context,
- GdkAtom target,
- guint32 time);
-void e_tree_drag_highlight (ETree *tree,
- int row,
- int col); /* col == -1 to highlight entire row. */
-void e_tree_drag_unhighlight (ETree *tree);
-void e_tree_drag_dest_set (ETree *tree,
- GtkDestDefaults flags,
- const GtkTargetEntry *targets,
- gint n_targets,
- GdkDragAction actions);
-void e_tree_drag_dest_set_proxy (ETree *tree,
- GdkWindow *proxy_window,
- GdkDragProtocol protocol,
- gboolean use_coordinates);
-
-/* There probably should be functions for setting the targets
- * as a GtkTargetList
- */
-void e_tree_drag_dest_unset (GtkWidget *widget);
-
-/* Source side */
-void e_tree_drag_source_set (ETree *tree,
- GdkModifierType start_button_mask,
- const GtkTargetEntry *targets,
- gint n_targets,
- GdkDragAction actions);
-void e_tree_drag_source_unset (ETree *tree);
-
-/* There probably should be functions for setting the targets
- * as a GtkTargetList
- */
-GdkDragContext *e_tree_drag_begin (ETree *tree,
- int row,
- int col,
- GtkTargetList *targets,
- GdkDragAction actions,
- gint button,
- GdkEvent *event);
-
-/* Adapter functions */
-gboolean e_tree_node_is_expanded (ETree *et,
- ETreePath path);
-void e_tree_node_set_expanded (ETree *et,
- ETreePath path,
- gboolean expanded);
-void e_tree_node_set_expanded_recurse (ETree *et,
- ETreePath path,
- gboolean expanded);
-void e_tree_root_node_set_visible (ETree *et,
- gboolean visible);
-ETreePath e_tree_node_at_row (ETree *et,
- int row);
-int e_tree_row_of_node (ETree *et,
- ETreePath path);
-gboolean e_tree_root_node_is_visible (ETree *et);
-void e_tree_show_node (ETree *et,
- ETreePath path);
-void e_tree_save_expanded_state (ETree *et,
- char *filename);
-void e_tree_load_expanded_state (ETree *et,
- char *filename);
-int e_tree_row_count (ETree *et);
-GtkWidget *e_tree_get_tooltip (ETree *et);
-
-typedef enum {
- E_TREE_FIND_NEXT_BACKWARD = 0,
- E_TREE_FIND_NEXT_FORWARD = 1 << 0,
- E_TREE_FIND_NEXT_WRAP = 1 << 1
-} ETreeFindNextParams;
-
-gboolean e_tree_find_next (ETree *et,
- ETreeFindNextParams params,
- ETreePathFunc func,
- gpointer data);
-
-/* This function is only needed in single_selection_mode. */
-void e_tree_right_click_up (ETree *et);
-
-ETableItem * e_tree_get_item(ETree * et);
-
-G_END_DECLS
-
-#endif /* _E_TREE_H_ */
-
diff --git a/widgets/table/image1.png b/widgets/table/image1.png
deleted file mode 100644
index 8326ac241f..0000000000
--- a/widgets/table/image1.png
+++ /dev/null
Binary files differ
diff --git a/widgets/table/image2.png b/widgets/table/image2.png
deleted file mode 100644
index e6a4c75dbe..0000000000
--- a/widgets/table/image2.png
+++ /dev/null
Binary files differ
diff --git a/widgets/table/image3.png b/widgets/table/image3.png
deleted file mode 100644
index 50e16e8620..0000000000
--- a/widgets/table/image3.png
+++ /dev/null
Binary files differ
diff --git a/widgets/table/remove-col.xpm b/widgets/table/remove-col.xpm
deleted file mode 100644
index ff1024f0c9..0000000000
--- a/widgets/table/remove-col.xpm
+++ /dev/null
@@ -1,22 +0,0 @@
-/* XPM */
-static char * remove_col_xpm[] = {
-"16 16 3 1",
-" c None",
-". c #000000",
-"+ c #FF0000",
-"... ...",
-".++. .++.",
-".+++. .+++.",
-" .+++. .+++. ",
-" .+++. .+++. ",
-" .+++..+++. ",
-" .++++++. ",
-" .++++. ",
-" .++++. ",
-" .++++++. ",
-" .+++..+++. ",
-" .+++. .+++. ",
-" .+++. .+++. ",
-".+++. .+++.",
-".++. .++.",
-"... ..."};
diff --git a/widgets/table/sample.table b/widgets/table/sample.table
deleted file mode 100644
index e1909a2bf7..0000000000
--- a/widgets/table/sample.table
+++ /dev/null
@@ -1,45 +0,0 @@
-Col1 Col2 Address Title Dorks
-c1.a c2.a a.a tit-1 DorkA
-c1.b c2.b a.b tit-2 DDork
-c1.c c2.c a.c tit-1 DorkB
-c1.d c2.d a.d tit-2 ADork
-c1.e c2.e a.e tit-1 DorkC
-c1.f c2.f a.f tit-2 UDork
-c1.g c2.g a.g tit-3 Dork---
-j k k tit-1 DorkA
-aaa1 bbb ccc ddd eee
-aaa2 bbb ccc ddd eee
-aaa3 bbb ccc ddd eee
-aaa4 bbb ccc ddd eee
-aaa5 bbb ccc ddd eee
-aaa6 bbb ccc ddd eee
-aaa7 bbb ccc ddd eee
-aaa8 bbb ccc ddd eee
-aaa9 bbb ccc ddd eee
-aaa10 bbb ccc ddd eee
-aaa11 bbb ccc ddd eee
-aaa12 bbb ccc ddd eee
-aaa13 bbb ccc ddd eee
-aaa14 bbb ccc ddd eee
-aaa15 bbb ccc ddd eee
-aaa16 bbb ccc ddd eee
-aaa17 bbb ccc ddd eee
-aaa18 bbb ccc ddd eee
-aaa19 bbb ccc ddd eee
-aaa20 bbb ccc ddd eee
-aaa21 bbb ccc ddd eee
-aaa22 bbb ccc ddd eee
-aaa23 bbb ccc ddd eee
-aaa24 bbb ccc ddd eee
-aaa25 bbb ccc ddd eee
-aaa26 bbb ccc ddd eee
-aaa27 bbb ccc ddd eee
-aaa28 bbb ccc ddd eee
-aaa29 bbb ccc ddd eee
-aaa30 bbb ccc ddd eee
-aaa31 bbb ccc ddd eee
-aaa32 bbb ccc ddd eee
-aaa33 bbb ccc ddd eee
-aaa34 bbb ccc ddd eee
-aaa35 bbb ccc ddd eee
-aaa36 bbb ccc ddd eee
diff --git a/widgets/table/spec.xml b/widgets/table/spec.xml
deleted file mode 100644
index a8e524484c..0000000000
--- a/widgets/table/spec.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<ETableSpecification no-headers="false" click-to-add="false"
- draw-grid="true" cursor-mode="simple"
- _click-to-add-message="">
- <ETableColumn model_col="0" _title="Email" expansion="1.0" minimum_width="20" resizable="true" cell="cell_left_just" compare="string"/>
- <ETableColumn model_col="1" _title="Full Name" expansion="1.0" minimum_width="20" resizable="true" cell="cell_left_just" compare="string"/>
- <ETableColumn model_col="2" _title="Address" expansion="1.0" minimum_width="20" resizable="true" cell="cell_left_just" compare="string"/>
- <ETableColumn model_col="3" _title="Phone" expansion="1.0" minimum_width="20" resizable="true" cell="cell_left_just" compare="string"/>
- <ETableState>
- <column source="0"/>
- <column source="3"/>
- <column source="1"/>
- <column source="2"/>
- <grouping>
- <group column="2" ascending="true">
- <leaf column="1" ascending="true"/>
- </group>
- </grouping>
- <!-- Column that's been added by hand. Not implemented yet.
- <ETableColumn model_col="custom-string" _title="Custom" expansion="1.0" minimum_widgth="20" resizable="true" cell="string" compare="string"/> -->
- </ETableState>
-</ETableSpecification>
diff --git a/widgets/table/table-test.c b/widgets/table/table-test.c
deleted file mode 100644
index fe211e9d21..0000000000
--- a/widgets/table/table-test.c
+++ /dev/null
@@ -1,62 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * table-test.c
- * Copyright 1999, 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Miguel de Icaza (miguel@gnu.org)
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <stdio.h>
-#include <string.h>
-#include <fcntl.h>
-#include <gnome.h>
-#include "gal/widgets/e-cursors.h"
-#include "table-test.h"
-
-int
-main (int argc, char *argv [])
-{
-
- if (isatty (0)){
- int fd;
-
- close (0);
- fd = open ("sample.table", O_RDONLY);
- if (fd == -1){
- fprintf (stderr, "Could not find sample.table, try feeding a table on stdin");
- exit (1);
- }
- dup2 (fd, 0);
- }
-
- gnome_init ("TableTest", "TableTest", argc, argv);
- e_cursors_init ();
-
-
-/* table_browser_test (); */
-/* multi_cols_test (); */
-/* check_test (); */
-
- e_table_test ();
-
- gtk_main ();
-
- e_cursors_shutdown ();
- return 0;
-}
diff --git a/widgets/table/table-test.h b/widgets/table/table-test.h
deleted file mode 100644
index d0442ca64b..0000000000
--- a/widgets/table/table-test.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * table-test.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Miguel de Icaza (miguel@gnu.org)
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-void table_browser_test (void);
-void multi_cols_test (void);
-void check_test (void);
-void e_table_test (void);
diff --git a/widgets/table/test-check.c b/widgets/table/test-check.c
deleted file mode 100644
index 7fe4c126e6..0000000000
--- a/widgets/table/test-check.c
+++ /dev/null
@@ -1,221 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * test-check.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Miguel de Icaza (miguel@gnu.org)
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <stdio.h>
-#include <string.h>
-#include <gnome.h>
-#include "e-table-simple.h"
-#include "e-table-header.h"
-#include "e-table-header-item.h"
-#include "e-table-item.h"
-#include "gal/widgets/e-cursors.h"
-#include "gal/widgets/e-canvas-utils.h"
-#include "gal/widgets/e-canvas.h"
-#include "gal/util/e-util.h"
-#include "e-cell-text.h"
-#include "e-cell-checkbox.h"
-
-#include "table-test.h"
-
-#define LINES 4
-
-static struct {
- int value;
- char *string;
-} my_table [LINES] = {
- { 0, "Buy food" },
- { 1, "Breathe " },
- { 0, "Cancel gdb session with shrink" },
- { 1, "Make screenshots" },
-};
-/*
- * ETableSimple callbacks
- */
-static int
-col_count (ETableModel *etc, void *data)
-{
- return 2;
-}
-
-static int
-row_count (ETableModel *etc, void *data)
-{
- return LINES;
-}
-
-static void *
-value_at (ETableModel *etc, int col, int row, void *data)
-{
- g_assert (col < 2);
- g_assert (row < LINES);
-
- if (col == 0)
- return GINT_TO_POINTER (my_table [row].value);
- else
- return my_table [row].string;
-
-}
-
-static void
-set_value_at (ETableModel *etc, int col, int row, const void *val, void *data)
-{
- g_assert (col < 2);
- g_assert (row < LINES);
-
- if (col == 0) {
- my_table [row].value = GPOINTER_TO_INT (val);
- printf ("Value at %d,%d set to %d\n", col, row, GPOINTER_TO_INT (val));
- } else {
- my_table [row].string = g_strdup (val);
- printf ("Value at %d,%d set to %s\n", col, row, (char *) val);
- }
-}
-
-static gboolean
-is_cell_editable (ETableModel *etc, int col, int row, void *data)
-{
- return TRUE;
-}
-
-static void *
-duplicate_value (ETableModel *etc, int col, const void *value, void *data)
-{
- if (col == 0) {
- return (void *) value;
- } else {
- return g_strdup (value);
- }
-}
-
-static void
-free_value (ETableModel *etc, int col, void *value, void *data)
-{
- if (col != 0) {
- g_free (value);
- }
-}
-
-static void *
-initialize_value (ETableModel *etc, int col, void *data)
-{
- if (col == 0)
- return NULL;
- else
- return g_strdup ("");
-}
-
-static gboolean
-value_is_empty (ETableModel *etc, int col, const void *value, void *data)
-{
- if (col == 0)
- return value == NULL;
- else
- return !(value && *(char *)value);
-}
-
-static char *
-value_to_string (ETableModel *etc, int col, const void *value, void *data)
-{
- if (col == 0)
- return g_strdup_printf("%d", (int) value);
- else
- return g_strdup(value);
-}
-
-static void
-set_canvas_size (GnomeCanvas *canvas, GtkAllocation *alloc)
-{
- gnome_canvas_set_scroll_region (canvas, 0, 0, alloc->width, alloc->height);
-}
-
-void
-check_test (void)
-{
- GtkWidget *canvas, *window;
- ETableModel *e_table_model;
- ETableHeader *e_table_header;
- ETableCol *col_0, *col_1;
- ECell *cell_left_just, *cell_image_check;
- GdkPixbuf *pixbuf;
- GnomeCanvasItem *item;
-
- gtk_widget_push_colormap (gdk_rgb_get_cmap ());
-
- e_table_model = e_table_simple_new (
- col_count, row_count, value_at,
- set_value_at, is_cell_editable,
- duplicate_value, free_value,
- initialize_value, value_is_empty,
- value_to_string,
- NULL);
-
- /*
- * Header
- */
- e_table_header = e_table_header_new ();
-
- cell_left_just = e_cell_text_new (e_table_model, NULL, GTK_JUSTIFY_LEFT);
-
- cell_image_check = e_cell_checkbox_new ();
- pixbuf = gdk_pixbuf_new_from_file ("clip.png");
- col_0 = e_table_col_new_with_pixbuf (0, pixbuf, 0.0, 18, cell_image_check, g_int_compare, TRUE);
- gdk_pixbuf_unref (pixbuf);
- e_table_header_add_column (e_table_header, col_0, 0);
-
- col_1 = e_table_col_new (1, "Item Name", 1.0, 20, cell_left_just, g_str_compare, TRUE);
- e_table_header_add_column (e_table_header, col_1, 1);
- e_table_col_set_arrow (col_1, E_TABLE_COL_ARROW_DOWN);
-
- /*
- * GUI
- */
- window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
- canvas = e_canvas_new ();
-
- g_signal_connect (canvas, "size_allocate",
- G_CALLBACK (set_canvas_size), NULL);
-
- gtk_container_add (GTK_CONTAINER (window), canvas);
- gtk_widget_show_all (window);
- gnome_canvas_item_new (
- gnome_canvas_root (GNOME_CANVAS (canvas)),
- e_table_header_item_get_type (),
- "ETableHeader", e_table_header,
- NULL);
-
- item = gnome_canvas_item_new (
- gnome_canvas_root (GNOME_CANVAS (canvas)),
- e_table_item_get_type (),
- "ETableHeader", e_table_header,
- "ETableModel", e_table_model,
- "drawgrid", TRUE,
- "drawfocus", TRUE,
-#if 0
- "spreadsheet", TRUE,
-#endif
- "cursor_mode", E_TABLE_CURSOR_SIMPLE,
- NULL);
- e_canvas_item_move_absolute (item, 0, 30);
-}
-
diff --git a/widgets/table/test-cols.c b/widgets/table/test-cols.c
deleted file mode 100644
index e4873633e5..0000000000
--- a/widgets/table/test-cols.c
+++ /dev/null
@@ -1,265 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * test-cols.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Miguel de Icaza (miguel@gnu.org)
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <stdio.h>
-#include <string.h>
-#include <gnome.h>
-#include "gal/widgets/e-canvas-utils.h"
-#include "gal/widgets/e-canvas.h"
-#include "gal/widgets/e-cursors.h"
-#include "gal/util/e-util.h"
-#include "e-table-simple.h"
-#include "e-table-header.h"
-#include "e-table-header-item.h"
-#include "e-table-item.h"
-#include "e-cell-text.h"
-#include "e-cell-toggle.h"
-
-#include "table-test.h"
-
-#define LINES 4
-
-static struct {
- int value;
- char *string;
-} my_table [LINES] = {
- { 0, "You are not" },
- { 1, "A beautiful and unique " },
- { 0, "Snowflake" },
- { 2, "You are not your wallet" },
-};
-/*
- * ETableSimple callbacks
- */
-static int
-col_count (ETableModel *etc, void *data)
-{
- return 2;
-}
-
-static int
-row_count (ETableModel *etc, void *data)
-{
- return LINES;
-}
-
-static void *
-value_at (ETableModel *etc, int col, int row, void *data)
-{
- g_assert (col < 2);
- g_assert (row < LINES);
-
- if (col == 0)
- return GINT_TO_POINTER (my_table [row].value);
- else
- return my_table [row].string;
-
-}
-
-static void
-set_value_at (ETableModel *etc, int col, int row, const void *val, void *data)
-{
- g_assert (col < 2);
- g_assert (row < LINES);
-
- if (col == 0){
- my_table [row].value = GPOINTER_TO_INT (val);
- printf ("Value at %d,%d set to %d\n", col, row, GPOINTER_TO_INT (val));
- } else {
- my_table [row].string = g_strdup (val);
- printf ("Value at %d,%d set to %s\n", col, row, (char *) val);
- }
-}
-
-static gboolean
-is_cell_editable (ETableModel *etc, int col, int row, void *data)
-{
- return TRUE;
-}
-
-static void *
-duplicate_value (ETableModel *etc, int col, const void *value, void *data)
-{
- if (col == 0){
- return (void *)value;
- } else {
- return g_strdup (value);
- }
-}
-
-static void
-free_value (ETableModel *etc, int col, void *value, void *data)
-{
- if (col != 0){
- g_free (value);
- }
-}
-
-static void *
-initialize_value (ETableModel *etc, int col, void *data)
-{
- if (col == 0)
- return NULL;
- else
- return g_strdup ("");
-}
-
-static gboolean
-value_is_empty (ETableModel *etc, int col, const void *value, void *data)
-{
- if (col == 0)
- return value == NULL;
- else
- return !(value && *(char *)value);
-}
-
-static char *
-value_to_string (ETableModel *etc, int col, const void *value, void *data)
-{
- if (col == 0)
- return g_strdup_printf("%d", (int) value);
- else
- return g_strdup(value);
-}
-
-static void
-set_canvas_size (GnomeCanvas *canvas, GtkAllocation *alloc)
-{
- gnome_canvas_set_scroll_region (canvas, 0, 0, alloc->width, alloc->height);
-}
-
-void
-multi_cols_test (void)
-{
- GtkWidget *canvas, *window;
- ETableModel *e_table_model;
- ETableHeader *e_table_header, *e_table_header_multiple;
- ETableCol *col_0, *col_1;
- ECell *cell_left_just, *cell_image_toggle;
- GnomeCanvasItem *item;
-
- gtk_widget_push_colormap (gdk_rgb_get_cmap ());
-
- e_table_model = e_table_simple_new (
- col_count, row_count, value_at,
- set_value_at, is_cell_editable,
- duplicate_value, free_value,
- initialize_value, value_is_empty,
- value_to_string,
- NULL);
-
- /*
- * Header
- */
- e_table_header = e_table_header_new ();
-
- cell_left_just = e_cell_text_new (e_table_model, NULL, GTK_JUSTIFY_LEFT);
-
- {
- GdkPixbuf **images = g_new (GdkPixbuf *, 3);
- int i;
-
- images [0] = gdk_pixbuf_new_from_file ("image1.png");
- images [1] = gdk_pixbuf_new_from_file ("image2.png");
- images [2] = gdk_pixbuf_new_from_file ("image3.png");
-
- cell_image_toggle = e_cell_toggle_new (0, 3, images);
-
- for (i = 0; i < 3; i++)
- gdk_pixbuf_unref (images [i]);
-
- g_free (images);
- }
-
- col_1 = e_table_col_new (1, "Item Name", 1.0, 20, cell_left_just, g_str_compare, TRUE);
- e_table_header_add_column (e_table_header, col_1, 0);
-
- col_0 = e_table_col_new (0, "A", 0.0, 48, cell_image_toggle, g_int_compare, TRUE);
- e_table_header_add_column (e_table_header, col_0, 1);
-
- /*
- * Second test
- */
- e_table_header_multiple = e_table_header_new ();
- e_table_header_add_column (e_table_header_multiple, col_0, 0);
- e_table_header_add_column (e_table_header_multiple, col_1, 1);
- e_table_header_add_column (e_table_header_multiple, col_1, 2);
-
- /*
- * GUI
- */
- window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
- canvas = e_canvas_new ();
-
- g_signal_connect (canvas, "size_allocate",
- G_CALLBACK (set_canvas_size), NULL);
-
- gtk_container_add (GTK_CONTAINER (window), canvas);
- gtk_widget_show_all (window);
-
- gnome_canvas_item_new (
- gnome_canvas_root (GNOME_CANVAS (canvas)),
- e_table_header_item_get_type (),
- "ETableHeader", e_table_header,
- NULL);
-
- item = gnome_canvas_item_new (
- gnome_canvas_root (GNOME_CANVAS (canvas)),
- e_table_item_get_type (),
- "ETableHeader", e_table_header,
- "ETableModel", e_table_model,
- "drawgrid", TRUE,
- "drawfocus", TRUE,
- "cursor_mode", E_TABLE_CURSOR_SIMPLE,
-#if 0
- "spreadsheet", TRUE,
-#endif
- NULL);
-
- e_canvas_item_move_absolute (item, 0, 30);
-
- gnome_canvas_item_new (
- gnome_canvas_root (GNOME_CANVAS (canvas)),
- e_table_header_item_get_type (),
- "ETableHeader", e_table_header_multiple,
- NULL);
- item = gnome_canvas_item_new (
- gnome_canvas_root (GNOME_CANVAS (canvas)),
- e_table_item_get_type (),
- "ETableHeader", e_table_header_multiple,
- "ETableModel", e_table_model,
- "drawgrid", TRUE,
- "drawfocus", TRUE,
-#if 0
- "spreadsheet", TRUE,
-#endif
- "cursor_mode", E_TABLE_CURSOR_SIMPLE,
- NULL);
- e_canvas_item_move_absolute (item, 300, 30);
-}
-
-
-
-
-
diff --git a/widgets/table/test-table.c b/widgets/table/test-table.c
deleted file mode 100644
index b44b62bf42..0000000000
--- a/widgets/table/test-table.c
+++ /dev/null
@@ -1,478 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * test-table.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Miguel de Icaza (miguel@gnu.org)
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <stdio.h>
-#include <string.h>
-#include <gnome.h>
-#include "gal/widgets/e-cursors.h"
-#include "gal/widgets/e-canvas.h"
-#include "e-table-simple.h"
-#include "e-table-header.h"
-#include "e-table-header-item.h"
-#include "e-table-item.h"
-#include "e-cell-text.h"
-#include "e-table.h"
-#include "e-table-config.h"
-
-#include "table-test.h"
-
-
-
-char buffer [1024];
-char **column_labels;
-char ***table_data;
-int cols = 0;
-int lines = 0;
-int lines_alloc = 0;
-
-static void
-parse_headers (void)
-{
- char *p, *s;
- int in_value = 0, i;
-
- fgets (buffer, sizeof (buffer)-1, stdin);
-
- for (p = buffer; *p; p++){
- if (*p == ' ' || *p == '\t'){
- if (in_value){
- cols++;
- in_value = 0;
- }
- } else
- in_value = 1;
- }
- if (in_value)
- cols++;
-
- if (!cols){
- fprintf (stderr, "No columns in first row\n");
- exit (1);
- }
-
- column_labels = g_new0 (char *, cols);
-
- p = buffer;
- for (i = 0; (s = strtok (p, " \t")) != NULL; i++){
- column_labels [i] = g_strdup (s);
- if (strchr (column_labels [i], '\n'))
- *strchr (column_labels [i], '\n') = 0;
- p = NULL;
- }
-
- printf ("%d headers:\n", cols);
- for (i = 0; i < cols; i++){
- printf ("header %d: %s\n", i, column_labels [i]);
- }
-}
-
-static char **
-load_line (char *buffer, int cols)
-{
- char **line = g_new0 (char *, cols);
- char *p;
- int i;
-
- for (i = 0; i < cols; i++){
- p = strtok (buffer, " \t\n");
- if (p == NULL){
- for (; i < cols; i++)
- line [i] = g_strdup ("");
- return line;
- } else
- line [i] = g_strdup (p);
- buffer = NULL;
- }
- return line;
-}
-
-static void
-append_line (char **line)
-{
- if (lines <= lines_alloc){
- lines_alloc = lines + 50;
- table_data = g_renew (char **, table_data, lines_alloc);
- }
- table_data [lines] = line;
- lines++;
-}
-
-static void
-load_data (void)
-{
- int i;
-
- {
- static int loaded;
-
- if (loaded)
- return;
-
- loaded = TRUE;
- }
-
-
- parse_headers ();
-
- while (fgets (buffer, sizeof (buffer)-1, stdin) != NULL){
- char **line;
-
- if (buffer [0] == '\n')
- continue;
- line = load_line (buffer, cols);
- append_line (line);
- }
-
- for (i = 0; i < lines; i++){
- int j;
-
- printf ("Line %d: ", i);
- for (j = 0; j < cols; j++)
- printf ("[%s] ", table_data [i][j]);
- printf ("\n");
- }
-}
-
-/*
- * ETableSimple callbacks
- */
-static int
-col_count (ETableModel *etc, void *data)
-{
- return cols;
-}
-
-static int
-row_count (ETableModel *etc, void *data)
-{
- return lines;
-}
-
-static void
-append_row (ETableModel *etm, ETableModel *model, int row, void *data)
-{
- abort ();
-}
-
-static void *
-value_at (ETableModel *etc, int col, int row, void *data)
-{
- g_assert (col < cols);
- g_assert (row < lines);
-
- fprintf (stderr, "value_at[%d,%d]\n", col, row);
-
- return (void *) table_data [row][col];
-}
-
-static void
-set_value_at (ETableModel *etc, int col, int row, const void *val, void *data)
-{
- g_assert (col < cols);
- g_assert (row < lines);
-
- g_free (table_data [row][col]);
- table_data [row][col] = g_strdup (val);
-
- printf ("Value at %d,%d set to %s\n", col, row, (char *) val);
-}
-
-static gboolean
-is_cell_editable (ETableModel *etc, int col, int row, void *data)
-{
- return TRUE;
-}
-
-static gboolean
-has_save_id (ETableModel *etm, void *data)
-{
- return FALSE;
-}
-
-static char *
-get_save_id (ETableModel *etm, int row, void *data)
-{
- abort ();
-}
-
-static void *
-duplicate_value (ETableModel *etc, int col, const void *value, void *data)
-{
- return g_strdup (value);
-}
-
-static void
-free_value (ETableModel *etc, int col, void *value, void *data)
-{
- g_free (value);
-}
-
-static void *
-initialize_value (ETableModel *etc, int col, void *data)
-{
- return g_strdup ("");
-}
-
-static gboolean
-value_is_empty (ETableModel *etc, int col, const void *value, void *data)
-{
- return !(value && *(char *)value);
-}
-
-static char *
-value_to_string (ETableModel *etc, int col, const void *value, void *data)
-{
- return g_strdup(value);
-}
-
-#ifdef BIT_ROT
-static void
-set_canvas_size (GnomeCanvas *canvas, GtkAllocation *alloc)
-{
- gnome_canvas_set_scroll_region (canvas, 0, 0, alloc->width, alloc->height);
-}
-
-void
-table_browser_test (void)
-{
- GtkWidget *canvas, *window;
- ETableModel *e_table_model;
- ETableHeader *e_table_header;
- ECell *cell_left_just;
- GnomeCanvasItem *group;
- int i;
- int priority = 20;
-
- load_data ();
-
- /*
- * Data model
- */
- e_table_model = e_table_simple_new (
- col_count, row_count, append_row,
-
- value_at, set_value_at, is_cell_editable,
-
- has_save_id, get_save_id,
-
- duplicate_value, free_value,
- initialize_value, value_is_empty,
- value_to_string,
- NULL);
-
- /*
- * Header
- */
- e_table_header = e_table_header_new ();
- cell_left_just = e_cell_text_new (NULL, GTK_JUSTIFY_LEFT);
-
- for (i = 0; i < cols; i++){
- ETableCol *ecol = e_table_col_new (
- i, column_labels [i],
- 1.0, 20, cell_left_just,
- g_str_compare, TRUE,
- priority);
-
- e_table_header_add_column (e_table_header, ecol, i);
- }
-
- /*
- * Setup GUI
- */
- window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
- canvas = e_canvas_new ();
-
- g_signal_connect (canvas, "size_allocate",
- G_CALLBACK (set_canvas_size), NULL);
-
- gtk_container_add (GTK_CONTAINER (window), canvas);
- gtk_widget_show_all (window);
- gnome_canvas_item_new (
- gnome_canvas_root (GNOME_CANVAS (canvas)),
- e_table_header_item_get_type (),
- "ETableHeader", e_table_header,
- NULL);
-
- group = gnome_canvas_item_new (
- gnome_canvas_root (GNOME_CANVAS (canvas)),
- gnome_canvas_group_get_type (),
- "x", 30.0,
- "y", 30.0,
- NULL);
-
- gnome_canvas_item_new (
- GNOME_CANVAS_GROUP (group),
- e_table_item_get_type (),
- "ETableHeader", e_table_header,
- "ETableModel", e_table_model,
- "drawgrid", TRUE,
- "drawfocus", TRUE,
-#if 0
- "spreadsheet", TRUE,
-#endif
- NULL);
-}
-#endif
-
-static void
-save_spec (GtkWidget *button, ETable *e_table)
-{
-#ifdef BIT_ROT
- e_table_save_specification (e_table, "e-table-test.xml");
-#endif
-}
-
-#ifdef BIT_ROT
-static void
-row_selection_test (ETable *table, int row, gboolean selected)
-{
- if (selected)
- g_print ("Row %d selected\n", row);
- else
- g_print ("Row %d unselected\n", row);
-}
-#endif
-
-static void
-toggle_grid (void *nothing, ETable *etable)
-{
- static gboolean shown;
-
- g_object_get (etable, "drawgrid", &shown, NULL);
- g_object_set (etable, "drawgrid", !shown, NULL);
-}
-
-static void
-do_e_table_demo (const char *state)
-{
- GtkWidget *e_table, *window, *frame, *vbox, *button, *bhide;
- ECell *cell_left_just;
- ETableHeader *full_header;
- int i;
- GString *spec;
-
- /*
- * Data model
- */
- static ETableModel *e_table_model = NULL;
-
- if (e_table_model == NULL)
- e_table_model =
- e_table_simple_new (col_count, row_count, append_row,
- value_at, set_value_at, is_cell_editable,
- has_save_id, get_save_id,
- duplicate_value, free_value,
- initialize_value, value_is_empty,
- value_to_string,
- NULL);
-
- full_header = e_table_header_new ();
- cell_left_just = e_cell_text_new (NULL, GTK_JUSTIFY_LEFT);
-
- spec = g_string_new ("\
-<ETableSpecification \
-cursor-mode=\"line\" \
-selection-mode=\"browse\" \
-draw-focus=\"true\">");
- for (i = 0; i < cols; i++) {
- char *colspec =
- g_strdup_printf ("\
- <ETableColumn model_col=\"%d\" \
-_title=\"%s\" \
-minimum_width=\"20\" \
-resizable=\"true\" \
-cell=\"string\" \
-compare=\"string\"/>\n", i, column_labels[i]);
- g_string_append (spec, colspec);
- g_free (colspec);
- }
- g_string_append (spec, "</ETableSpecification>");
- e_table = e_table_new (e_table_model, NULL, spec->str, state);
-
- /* This makes value_at not called just to determine row height. */
- g_object_set (e_table,
- "uniform_row_height", 1,
- NULL);
-
- g_string_free (spec, TRUE);
-
- window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
- frame = gtk_frame_new (NULL);
-#ifdef BIT_ROT
- g_signal_connect (e_table, "row_selection",
- G_CALLBACK(row_selection_test), NULL);
-#endif
-
- vbox = gtk_vbox_new (FALSE, 0);
- gtk_box_pack_start (GTK_BOX (vbox), e_table, TRUE, TRUE, 0);
- gtk_container_add (GTK_CONTAINER (frame), vbox);
- gtk_container_add (GTK_CONTAINER (window), frame);
-
-#if 0
- /*
- * gadgets
- */
- button = gtk_button_new_with_label ("Save spec");
- g_signal_connect (button, "clicked",
- G_CALLBACK (save_spec), e_table);
- gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
-
- bhide = gtk_button_new_with_label ("Toggle Grid");
- g_signal_connect (bhide, "clicked",
- G_CALLBACk (toggle_grid), e_table);
- gtk_box_pack_start (GTK_BOX (vbox), bhide, FALSE, FALSE, 0);
-#endif
-
- gtk_widget_set_usize (window, 400, 200);
- gtk_widget_show_all (window);
-
-#ifdef BIT_ROT
- if (getenv ("TEST")){
- e_table_do_gui_config (NULL, E_TABLE(e_table));
- }
-#endif
-}
-
-void
-e_table_test (void)
-{
- load_data ();
-
- if (1){/*getenv ("DO")){*/
- do_e_table_demo ("\
-<ETableState>\n\
- <column source=\"0\"/>\n\
- <column source=\"1\"/>\n\
- <column source=\"2\"/>\n\
- <column source=\"3\"/>\n\
- <column source=\"4\"/>\n\
- <grouping></grouping>\n\
-</ETableState>");
-#if 0
- do_e_table_demo ("<ETableSpecification> <columns-shown> <column> 0 </column> <column> 0 </column> <column> 1 </column> <column> 2 </column> <column> 3 </column> <column> 4 </column> </columns-shown> <grouping> <group column=\"3\" ascending=\"true\"> <group column=\"4\" ascending=\"false\"> <leaf column=\"2\" ascending=\"true\"/> </group> </group> </grouping> </ETableSpecification>");
- do_e_table_demo ("<ETableSpecification> <columns-shown> <column> 0 </column> <column> 1 </column> <column> 2 </column> <column> 3 </column> <column> 4 </column> </columns-shown> <grouping> <group column=\"4\" ascending=\"true\"> <leaf column=\"2\" ascending=\"true\"/> </group> </grouping> </ETableSpecification>");
- do_e_table_demo ("<ETableSpecification> <columns-shown> <column> 0 </column> <column> 1 </column> <column> 2 </column> <column> 3 </column> <column> 4 </column> </columns-shown> <grouping> <group column=\"3\" ascending=\"true\"> <leaf column=\"2\" ascending=\"true\"/> </group> </grouping> </ETableSpecification>");
-#endif
- }
-}
diff --git a/widgets/table/tree-expanded.xpm b/widgets/table/tree-expanded.xpm
deleted file mode 100644
index d9bda3694d..0000000000
--- a/widgets/table/tree-expanded.xpm
+++ /dev/null
@@ -1,23 +0,0 @@
-/* XPM */
-static char * tree_expanded_xpm[] = {
-"16 16 4 1",
-" c None",
-". c #FFFFFF",
-"* c #000000",
-"+ c #666666",
-" ",
-" ",
-" ",
-" ",
-" +++++++++ ",
-" +.......+ ",
-" +.......+ ",
-" +.......+ ",
-" +.*****.+ ",
-" +.......+ ",
-" +.......+ ",
-" +.......+ ",
-" +++++++++ ",
-" ",
-" ",
-" "};
diff --git a/widgets/table/tree-unexpanded.xpm b/widgets/table/tree-unexpanded.xpm
deleted file mode 100644
index e1b48448ba..0000000000
--- a/widgets/table/tree-unexpanded.xpm
+++ /dev/null
@@ -1,23 +0,0 @@
-/* XPM */
-static char * tree_unexpanded_xpm[] = {
-"16 16 4 1",
-" c None",
-". c #FFFFFF",
-"* c #000000",
-"+ c #666666",
-" ",
-" ",
-" ",
-" ",
-" +++++++++ ",
-" +.......+ ",
-" +...*...+ ",
-" +...*...+ ",
-" +.*****.+ ",
-" +...*...+ ",
-" +...*...+ ",
-" +.......+ ",
-" +++++++++ ",
-" ",
-" ",
-" "};
diff --git a/widgets/text/.cvsignore b/widgets/text/.cvsignore
deleted file mode 100644
index 792b9f5af2..0000000000
--- a/widgets/text/.cvsignore
+++ /dev/null
@@ -1,11 +0,0 @@
-.deps
-.libs
-.pure
-Makefile
-Makefile.in
-*.lo
-*.la
-e-text-test
-e-entry-test
-e-text-model-test
-e-completion-test \ No newline at end of file
diff --git a/widgets/text/e-completion-callbacks.c b/widgets/text/e-completion-callbacks.c
deleted file mode 100644
index bccc400fab..0000000000
--- a/widgets/text/e-completion-callbacks.c
+++ /dev/null
@@ -1,98 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-completion-callbacks.c - A callback based ECompletion.
- * Copyright 2003
- *
- * Authors:
- * Chris Toshok <toshok@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <string.h>
-#include <stdio.h>
-#include <gtk/gtk.h>
-#include "gal/util/e-util.h"
-#include "e-completion-callbacks.h"
-
-static void e_completion_callbacks_class_init (ECompletionCallbacksClass *klass);
-static void e_completion_callbacks_init (ECompletionCallbacks *complete);
-
-static void callbacks_request_completion (ECompletion *comp, const gchar *search_text, gint pos, gint limit);
-static void callbacks_end_completion (ECompletion *comp);
-
-#define PARENT_TYPE E_COMPLETION_TYPE
-static ECompletionClass *parent_class;
-
-
-
-E_MAKE_TYPE (e_completion_callbacks,
- "ECompletionCallbacks",
- ECompletionCallbacks,
- e_completion_callbacks_class_init,
- e_completion_callbacks_init,
- PARENT_TYPE)
-
-static void
-e_completion_callbacks_class_init (ECompletionCallbacksClass *klass)
-{
- ECompletionClass *comp_class = (ECompletionClass *) klass;
-
- parent_class = g_type_class_ref (PARENT_TYPE);
-
- comp_class->request_completion = callbacks_request_completion;
- comp_class->end_completion = callbacks_end_completion;
-}
-
-static void
-e_completion_callbacks_init (ECompletionCallbacks *complete)
-{
-}
-
-static void
-callbacks_request_completion (ECompletion *comp, const gchar *search_text, gint pos, gint limit)
-{
- ECompletionCallbacks *cc = E_COMPLETION_CALLBACKS (comp);
-
- cc->request_completion (cc, search_text, pos, limit, cc->data);
-}
-
-static void
-callbacks_end_completion (ECompletion *comp)
-{
- ECompletionCallbacks *cc = E_COMPLETION_CALLBACKS (comp);
-
- cc->end_completion (cc, cc->data);
-}
-
-ECompletionCallbacks*
-e_completion_callbacks_new (ECompletionCallbacksRequestCompletionFn request_completion,
- ECompletionCallbacksEndCompletionFn end_completion,
- gpointer data)
-{
- ECompletionCallbacks *cc;
-
- g_return_val_if_fail (request_completion != NULL, NULL);
- g_return_val_if_fail (end_completion != NULL, NULL);
-
- cc = gtk_type_new (E_COMPLETION_CALLBACKS_TYPE);
-
- cc->request_completion = request_completion;
- cc->end_completion = end_completion;
- cc->data = data;
-
- return cc;
-}
diff --git a/widgets/text/e-completion-callbacks.h b/widgets/text/e-completion-callbacks.h
deleted file mode 100644
index 2661c16022..0000000000
--- a/widgets/text/e-completion-callbacks.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-completion-callback.h - A callback based completion object.
- * Copyright 2003, Ximian, Inc.
- *
- * Authors:
- * Chris Toshok <toshok@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef E_COMPLETION_CALLBACKS_H
-#define E_COMPLETION_CALLBACKS_H
-
-#include <gtk/gtkobject.h>
-#include "e-completion.h"
-
-G_BEGIN_DECLS
-
-#define E_COMPLETION_CALLBACKS_TYPE (e_completion_callbacks_get_type ())
-#define E_COMPLETION_CALLBACKS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_COMPLETION_CALLBACKS_TYPE, ECompletionCallbacks))
-#define E_COMPLETION_CALLBACKS_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), E_COMPLETION_CALLBACKS_TYPE, ECompletionCallbacksClass))
-#define E_IS_COMPLETION_CALLBACKS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_COMPLETION_CALLBACKS_TYPE))
-#define E_IS_COMPLETION_CALLBACKS_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_COMPLETION_CALLBACKS_TYPE))
-
-typedef struct _ECompletionCallbacks ECompletionCallbacks;
-typedef struct _ECompletionCallbacksClass ECompletionCallbacksClass;
-struct _ECompletionCallbacksPrivate;
-
-typedef void (*ECompletionCallbacksRequestCompletionFn) (ECompletionCallbacks *comp, const gchar *search_text, gint pos, gint limit, gpointer data);
-typedef void (*ECompletionCallbacksEndCompletionFn) (ECompletionCallbacks *comp, gpointer data);
-
-struct _ECompletionCallbacks {
- ECompletion parent;
-
- ECompletionCallbacksRequestCompletionFn request_completion;
- ECompletionCallbacksEndCompletionFn end_completion;
-
- gpointer data;
-};
-
-struct _ECompletionCallbacksClass {
- ECompletionClass parent_class;
-};
-
-GtkType e_completion_callbacks_get_type (void);
-
-ECompletionCallbacks* e_completion_callbacks_new (ECompletionCallbacksRequestCompletionFn request_completion,
- ECompletionCallbacksEndCompletionFn end_completion,
- gpointer data);
-
-G_END_DECLS
-
-
-#endif /* E_COMPLETION_CALLBACKS_H */
-
diff --git a/widgets/text/e-completion-match.c b/widgets/text/e-completion-match.c
deleted file mode 100644
index d13ba15973..0000000000
--- a/widgets/text/e-completion-match.c
+++ /dev/null
@@ -1,184 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-completion-match.c
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Jon Trowbridge <trow@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <string.h>
-#include <gal/widgets/e-unicode.h>
-#include "e-completion-match.h"
-
-static void
-e_completion_match_destroy (ECompletionMatch *match)
-{
- if (match) {
- g_free (match->match_text);
- g_free (match->menu_text);
- if (match->destroy)
- match->destroy (match);
- g_free (match);
- }
-}
-
-void
-e_completion_match_construct (ECompletionMatch *match)
-{
- g_return_if_fail (match != NULL);
-
- match->match_text = NULL;
- match->menu_text = NULL;
- match->score = 0;
- match->sort_major = 0;
- match->sort_minor = 0;
- match->user_data = NULL;
- match->ref = 1;
- match->destroy = NULL;
-}
-
-void
-e_completion_match_ref (ECompletionMatch *match)
-{
- g_return_if_fail (match != NULL);
- g_return_if_fail (match->ref > 0);
-
- ++match->ref;
-}
-
-void
-e_completion_match_unref (ECompletionMatch *match)
-{
- if (match) {
- g_return_if_fail (match->ref > 0);
-
- --match->ref;
- if (match->ref == 0) {
- e_completion_match_destroy (match);
- }
- }
-}
-
-void
-e_completion_match_set_text (ECompletionMatch *match,
- const gchar *match_text,
- const gchar *menu_text)
-{
- g_return_if_fail (match != NULL);
-
- /* We silently drop any entries w/ invalid utf8.
- This is not optimal behavior. */
-
- if (match_text && ! g_utf8_validate (match_text, -1, NULL)) {
- match_text = NULL;
- }
-
- if (menu_text && ! g_utf8_validate (menu_text, -1, NULL)) {
- menu_text = NULL;
- }
-
- if (match->match_text && match->match_text != match_text) {
- g_free (match->match_text);
- }
- match->match_text = g_strdup (match_text);
-
- if (match->menu_text && match->menu_text != menu_text) {
- g_free (match->menu_text);
- }
- match->menu_text = g_strdup (menu_text);
-}
-
-const gchar *
-e_completion_match_get_match_text (ECompletionMatch *match)
-{
- g_return_val_if_fail (match != NULL, NULL);
- return match->match_text;
-}
-
-const gchar *
-e_completion_match_get_menu_text (ECompletionMatch *match)
-{
- g_return_val_if_fail (match != NULL, NULL);
- return match->menu_text;
-}
-
-gint
-e_completion_match_compare (const ECompletionMatch *a, const ECompletionMatch *b)
-{
- gint rv;
-
- /* Deal with NULL arguments. */
- if (!(a || b)) {
- if (!(a && b))
- return 0;
- return a ? -1 : 1;
- }
-
- if ( (rv = (b->sort_major < a->sort_major) - (a->sort_major < b->sort_major)) )
- return rv;
-
- /* Sort the scores high->low. */
- if ( (rv = (b->score > a->score) - (a->score > b->score)) )
- return rv;
-
- if ( (rv = (b->sort_minor < a->sort_minor) - (a->sort_minor < b->sort_minor)) )
- return rv;
-
- return 0;
-}
-
-gint
-e_completion_match_compare_alpha (const ECompletionMatch *a, const ECompletionMatch *b)
-{
- gint rv, rv2;
-
- /* Deal with NULL arguments. */
- if (!(a || b)) {
- if (!(a && b))
- return 0;
- return a ? -1 : 1;
- }
-
- /* The sort_major trumps everything. */
- if ( (rv = (b->sort_major < a->sort_major) - (a->sort_major < b->sort_major)) )
- return rv;
-
- /* Sort the scores high->low. */
- if ( (rv = (b->score > a->score) - (a->score > b->score)) )
- return rv;
-
- /* When the match text is the same, we use the minor fields */
- rv2 = strcmp (a->match_text, b->match_text);
- if ( !rv2 && (rv = (b->sort_minor < a->sort_minor) - (a->sort_minor < b->sort_minor)) )
- return rv;
-
- return strcmp (a->menu_text, b->menu_text);
-}
-
-ECompletionMatch *
-e_completion_match_new (const gchar *match_text, const gchar *menu_text, double score)
-{
- ECompletionMatch *match = g_new0 (ECompletionMatch, 1);
-
- e_completion_match_construct (match);
- e_completion_match_set_text (match, match_text, menu_text);
- match->score = score;
-
- return match;
-}
diff --git a/widgets/text/e-completion-match.h b/widgets/text/e-completion-match.h
deleted file mode 100644
index 162373add4..0000000000
--- a/widgets/text/e-completion-match.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-completion-match.h
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Jon Trowbridge <trow@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#ifndef __E_COMPLETION_MATCH_H__
-#define __E_COMPLETION_MATCH_H__
-
-#include <glib.h>
-#include <gtk/gtkwidget.h>
-
-G_BEGIN_DECLS
-
-typedef struct _ECompletionMatch ECompletionMatch;
-
-struct _ECompletionMatch {
- gchar *match_text; /* in utf8 */
- gchar *menu_text; /* in utf8 */
- double score;
- gint sort_major;
- gint sort_minor;
- gpointer user_data;
-
- gint ref;
- void (*destroy) (ECompletionMatch *);
-};
-
-typedef void (*ECompletionMatchFn) (ECompletionMatch *, gpointer closure);
-
-void e_completion_match_construct (ECompletionMatch *);
-void e_completion_match_ref (ECompletionMatch *);
-void e_completion_match_unref (ECompletionMatch *);
-
-void e_completion_match_set_text (ECompletionMatch *, const gchar *match_text, const gchar *label_text);
-const gchar *e_completion_match_get_match_text (ECompletionMatch *);
-const gchar *e_completion_match_get_menu_text (ECompletionMatch *);
-
-gint e_completion_match_compare (const ECompletionMatch *, const ECompletionMatch *);
-gint e_completion_match_compare_alpha (const ECompletionMatch *, const ECompletionMatch *);
-
-ECompletionMatch *e_completion_match_new (const gchar *match_text, const gchar *menu_text, double score);
-
-
-
-
-G_END_DECLS
-
-#endif /* __E_COMPLETION_MATCH_H__ */
-
diff --git a/widgets/text/e-completion-view.c b/widgets/text/e-completion-view.c
deleted file mode 100644
index f9728de60c..0000000000
--- a/widgets/text/e-completion-view.c
+++ /dev/null
@@ -1,859 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * e-completion-view.c - A text completion selection widget
- * Copyright 2000, 2001, Ximian, Inc.
- *
- * Authors:
- * Miguel de Icaza <miguel@ximian.com>
- * Adapted by Jon Trowbridge <trow@ximian.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-
-#include "e-completion-view.h"
-
-#include <math.h>
-#include <gdk/gdkkeysyms.h>
-#include <gal/e-table/e-table-simple.h>
-#include <gal/e-table/e-table-scrolled.h>
-#include <gal/util/e-i18n.h>
-#include "gal/util/e-marshal.h"
-
-enum {
- E_COMPLETION_VIEW_NONEMPTY,
- E_COMPLETION_VIEW_ADDED,
- E_COMPLETION_VIEW_FULL,
- E_COMPLETION_VIEW_BROWSE,
- E_COMPLETION_VIEW_UNBROWSE,
- E_COMPLETION_VIEW_ACTIVATE,
- E_COMPLETION_VIEW_LAST_SIGNAL
-};
-
-static guint e_completion_view_signals[E_COMPLETION_VIEW_LAST_SIGNAL] = { 0 };
-
-static void e_completion_view_disconnect (ECompletionView *cv);
-static ETable *e_completion_view_table (ECompletionView *cv);
-static void e_completion_view_clear_choices (ECompletionView *cv);
-static void e_completion_view_set_cursor_row (ECompletionView *cv, gint r);
-static void e_completion_view_select (ECompletionView *cv, gint r);
-
-static gint e_completion_view_key_press_handler (GtkWidget *w, GdkEventKey *key_event, gpointer user_data);
-
-static void e_completion_view_class_init (ECompletionViewClass *klass);
-static void e_completion_view_init (ECompletionView *completion);
-static void e_completion_view_dispose (GObject *object);
-
-#define PARENT_TYPE GTK_TYPE_EVENT_BOX
-static GtkObjectClass *parent_class;
-
-
-
-static gint
-e_completion_view_local_key_press_handler (GtkWidget *w, GdkEventKey *ev)
-{
- return e_completion_view_key_press_handler (w, ev, w);
-}
-
-static void
-e_completion_view_paint (GtkWidget *widget, GdkRectangle *area)
-{
- gint i;
-
- g_return_if_fail (widget != NULL);
- g_return_if_fail (E_IS_COMPLETION_VIEW (widget));
- g_return_if_fail (area != NULL);
-
- if (!GTK_WIDGET_DRAWABLE (widget))
- return;
-
- for (i = 0; i < E_COMPLETION_VIEW (widget)->border_width; ++i) {
-
- gdk_draw_rectangle (widget->window,
- widget->style->black_gc,
- FALSE, i, i,
- widget->allocation.width-1-2*i,
- widget->allocation.height-1-2*i);
-
- }
-
-}
-
-#if 0
-static void
-e_completion_view_draw (GtkWidget *widget, GdkRectangle *area)
-{
- GtkBin *bin;
- GdkRectangle child_area;
-
- g_return_if_fail (widget != NULL);
- g_return_if_fail (E_IS_COMPLETION_VIEW (widget));
- g_return_if_fail (area != NULL);
-
- if (GTK_WIDGET_DRAWABLE (widget)) {
- bin = GTK_BIN (widget);
-
- e_completion_view_paint (widget, area);
-
- if (bin->child && gtk_widget_intersect (bin->child, area, &child_area))
- gtk_widget_draw (bin->child, &child_area);
- }
-}
-#endif
-
-static gint
-e_completion_view_expose_event (GtkWidget *widget, GdkEventExpose *event)
-{
- GtkBin *bin;
- GdkEventExpose child_event;
-
- g_return_val_if_fail (widget != NULL, FALSE);
- g_return_val_if_fail (E_IS_COMPLETION_VIEW (widget), FALSE);
- g_return_val_if_fail (event != NULL, FALSE);
-
- if (GTK_WIDGET_DRAWABLE (widget)) {
- bin = GTK_BIN (widget);
-
- e_completion_view_paint (widget, &event->area);
-
- child_event = *event;
- if (bin->child &&
- GTK_WIDGET_NO_WINDOW (bin->child) &&
- gtk_widget_intersect (bin->child, &event->area, &child_event.area))
- gtk_widget_send_expose (bin->child, (GdkEvent*) &child_event);
- }
-
- return FALSE;
-}
-
-static void
-e_completion_view_size_request (GtkWidget *widget, GtkRequisition *requisition)
-{
- GtkBin *bin;
-
- g_return_if_fail (widget != NULL);
- g_return_if_fail (E_IS_COMPLETION_VIEW (widget));
- g_return_if_fail (requisition != NULL);
-
- bin = GTK_BIN (widget);
-
- requisition->width = 2 * E_COMPLETION_VIEW (widget)->border_width;
- requisition->height = 2 * E_COMPLETION_VIEW (widget)->border_width;
-
- if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) {
- GtkRequisition child_requisition;
-
- gtk_widget_size_request (bin->child, &child_requisition);
-
- requisition->width += child_requisition.width;
- requisition->height += child_requisition.height;
- }
-
- requisition->height = MAX (100, requisition->height);
-}
-
-static void
-e_completion_view_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
-{
- GtkBin *bin;
- GtkAllocation child_allocation;
-
- g_return_if_fail (widget != NULL);
- g_return_if_fail (E_IS_COMPLETION_VIEW (widget));
- g_return_if_fail (allocation != NULL);
-
- bin = GTK_BIN (widget);
- widget->allocation = *allocation;
-
- child_allocation.x = E_COMPLETION_VIEW (widget)->border_width;
- child_allocation.width = MAX(0, (gint)allocation->width - child_allocation.x * 2);
-
- child_allocation.y = E_COMPLETION_VIEW (widget)->border_width;
- child_allocation.height = MAX (0, (gint)allocation->height - child_allocation.y * 2);
-
- if (GTK_WIDGET_REALIZED (widget)) {
- gdk_window_move_resize (widget->window,
- allocation->x,
- allocation->y,
- allocation->width,
- allocation->height);
- }
-
- if (bin->child) {
- gtk_widget_size_allocate (bin->child, &child_allocation);
- }
-}
-
-E_MAKE_TYPE (e_completion_view,
- "ECompletionView",
- ECompletionView,
- e_completion_view_class_init,
- e_completion_view_init,
- PARENT_TYPE)
-
-static void
-e_completion_view_class_init (ECompletionViewClass *klass)
-{
- GObjectClass *object_class = (GObjectClass *) klass;
- GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
-
- parent_class = g_type_class_ref (PARENT_TYPE);
-
- e_completion_view_signals[E_COMPLETION_VIEW_NONEMPTY] =
- g_signal_new ("nonempty",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ECompletionViewClass, nonempty),
- NULL, NULL,
- e_marshal_NONE__NONE,
- G_TYPE_NONE, 0);
-
- e_completion_view_signals[E_COMPLETION_VIEW_ADDED] =
- g_signal_new ("added",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ECompletionViewClass, added),
- NULL, NULL,
- e_marshal_NONE__NONE,
- G_TYPE_NONE, 0);
-
- e_completion_view_signals[E_COMPLETION_VIEW_FULL] =
- g_signal_new ("full",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ECompletionViewClass, full),
- NULL, NULL,
- e_marshal_NONE__NONE,
- G_TYPE_NONE, 0);
-
- e_completion_view_signals[E_COMPLETION_VIEW_BROWSE] =
- g_signal_new ("browse",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ECompletionViewClass, browse),
- NULL, NULL,
- e_marshal_NONE__POINTER,
- G_TYPE_NONE, 1,
- G_TYPE_POINTER);
-
- e_completion_view_signals[E_COMPLETION_VIEW_UNBROWSE] =
- g_signal_new ("unbrowse",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ECompletionViewClass, unbrowse),
- NULL, NULL,
- e_marshal_NONE__NONE,
- G_TYPE_NONE, 0);
-
- e_completion_view_signals[E_COMPLETION_VIEW_ACTIVATE] =
- g_signal_new ("activate",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ECompletionViewClass, activate),
- NULL, NULL,
- e_marshal_NONE__POINTER,
- G_TYPE_NONE, 1,
- G_TYPE_POINTER);
-
- object_class->dispose = e_completion_view_dispose;
-
- widget_class->key_press_event = e_completion_view_local_key_press_handler;
- widget_class->expose_event = e_completion_view_expose_event;
- widget_class->size_request = e_completion_view_size_request;
- widget_class->size_allocate = e_completion_view_size_allocate;
-}
-
-static void
-e_completion_view_init (ECompletionView *completion)
-{
- completion->border_width = 2;
- completion->choices = g_ptr_array_new ();
-}
-
-static void
-e_completion_view_dispose (GObject *object)
-{
- ECompletionView *cv = E_COMPLETION_VIEW (object);
-
- e_completion_view_disconnect (cv);
-
- if (cv->choices) {
- e_completion_view_clear_choices (cv);
-
- g_ptr_array_free (cv->choices, TRUE);
- cv->choices = NULL;
- }
-
- if (cv->key_widget) {
- g_signal_handler_disconnect (cv->key_widget, cv->key_signal_id);
- g_object_unref (cv->key_widget);
- cv->key_widget = NULL;
- }
-
- if (cv->completion)
- g_object_unref (cv->completion);
- cv->completion = NULL;
-
- if (G_OBJECT_CLASS (parent_class)->dispose)
- (G_OBJECT_CLASS (parent_class)->dispose) (object);
-}
-
-static void
-e_completion_view_disconnect (ECompletionView *cv)
-{
- g_return_if_fail (cv != NULL);
- g_return_if_fail (E_IS_COMPLETION_VIEW (cv));
-
- if (cv->begin_signal_id)
- g_signal_handler_disconnect (cv->completion, cv->begin_signal_id);
- if (cv->comp_signal_id)
- g_signal_handler_disconnect (cv->completion, cv->comp_signal_id);
- if (cv->end_signal_id)
- g_signal_handler_disconnect (cv->completion, cv->end_signal_id);
-
- cv->begin_signal_id = 0;
- cv->comp_signal_id = 0;
- cv->end_signal_id = 0;
-}
-
-static ETable *
-e_completion_view_table (ECompletionView *cv)
-{
- return e_table_scrolled_get_table (E_TABLE_SCROLLED (cv->table));
-}
-
-static void
-e_completion_view_clear_choices (ECompletionView *cv)
-{
- ECompletionMatch *match;
- GPtrArray *m;
- int i;
-
- g_return_if_fail (E_IS_COMPLETION_VIEW (cv));
-
- m = cv->choices;
- for (i = 0; i < m->len; i++) {
- match = g_ptr_array_index (m, i);
- e_completion_match_unref (match);
- }
- g_ptr_array_set_size (m, 0);
-}
-
-static void
-e_completion_view_set_cursor_row (ECompletionView *cv, gint r)
-{
- ETable *table;
- GtkAdjustment *adj;
- gint x, y1, y2, r1, r2, c;
- double fracline;
- gint iteration_count=0;
-
- g_return_if_fail (cv != NULL);
- g_return_if_fail (E_IS_COMPLETION_VIEW (cv));
-#ifndef G_DISABLE_CHECKS
- /* choices->len is unsigned, but it is reasonable for r to be
- * < 0 */
- if (r > 0) {
- g_return_if_fail (r < cv->choices->len);
- }
-#endif
-
- adj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (cv->table));
-
- table = e_completion_view_table (cv);
-
- if (r < 0) {
- e_selection_model_clear (E_SELECTION_MODEL(table->selection));
-
- /* Move back to the top when we clear the selection */
- gtk_adjustment_set_value (adj, adj->lower);
- return;
- }
-
- e_table_set_cursor_row (table, r);
-
- /* OK, now the tricky bit. We try to insure that this row is
- visible. */
-
- /* If we are selecting the first or last row, then it is easy. We just
- cram the vadjustment all the way up/down. */
- if (r == 0) {
- gtk_adjustment_set_value (adj, adj->lower);
- return;
- } else if (r == cv->choices->len - 1) {
- gtk_adjustment_set_value (adj, adj->upper - adj->page_size);
- return;
- }
-
- fracline = ((adj->upper - adj->lower - adj->page_size) / (gint)cv->choices->len) / 4;
-
- while (iteration_count < 100) {
- x = GTK_LAYOUT(table->table_canvas)->hadjustment->value;
- y1 = GTK_LAYOUT(table->table_canvas)->vadjustment->value;
-
- y2 = y1 + cv->table->allocation.height;
-
- e_table_group_compute_location (e_completion_view_table (cv)->group, &x, &y1, &r1, &c);
- e_table_group_compute_location (e_completion_view_table (cv)->group, &x, &y2, &r2, &c);
-
- if (r <= r1) {
- gtk_adjustment_set_value (adj, adj->value - fracline);
- } else if (r >= r2) {
- gtk_adjustment_set_value (adj, adj->value + fracline);
- } else
- return;
-
- ++iteration_count;
- }
-
- g_assert_not_reached ();
-}
-
-static void
-e_completion_view_select (ECompletionView *cv, gint r)
-{
- ECompletionMatch *match;
-
- match = g_ptr_array_index (cv->choices, r);
-
- cv->selection = r;
- e_completion_view_set_cursor_row (cv, r);
- g_signal_emit (cv, e_completion_view_signals[E_COMPLETION_VIEW_ACTIVATE], 0, match);
-}
-
-static gint
-e_completion_view_key_press_handler (GtkWidget *w, GdkEventKey *key_event, gpointer user_data)
-{
- ECompletionView *cv = E_COMPLETION_VIEW (user_data);
- gint dir = 0;
- gboolean key_handled = TRUE, complete_key = FALSE, uncomplete_key = FALSE, is_space = FALSE;
-
- /* FIXME: This is totally lame.
- The ECompletionView should be able to specify multiple completion/uncompletion keys, or just
- have sensible defaults. */
-
- if ((cv->complete_key && key_event->keyval == cv->complete_key)
- || ((key_event->keyval == GDK_n || key_event->keyval == GDK_N) && (key_event->state & GDK_CONTROL_MASK)))
- complete_key = TRUE;
-
- if ((cv->uncomplete_key && key_event->keyval == cv->uncomplete_key)
- || ((key_event->keyval == GDK_p || key_event->keyval == GDK_P) && (key_event->state & GDK_CONTROL_MASK)))
- uncomplete_key = TRUE;
-
- /* Start up a completion.*/
- if (complete_key && !cv->editable) {
- g_signal_emit (cv, e_completion_view_signals[E_COMPLETION_VIEW_BROWSE], 0, NULL);
- goto stop_emission;
- }
-
- /* Stop our completion. */
- if (uncomplete_key && cv->editable && cv->selection < 0) {
- e_completion_view_set_cursor_row (cv, -1);
- g_signal_emit (cv, e_completion_view_signals[E_COMPLETION_VIEW_UNBROWSE], 0);
- goto stop_emission;
- }
-
- if (!cv->editable)
- return FALSE;
-
- switch (key_event->keyval) {
-
- case GDK_n:
- case GDK_N:
- /* We (heart) emacs: treat ctrl-n as down */
- if (! (key_event->state & GDK_CONTROL_MASK))
- return FALSE;
-
- case GDK_Down:
- case GDK_KP_Down:
- dir = 1;
- break;
-
- case GDK_p:
- case GDK_P:
- /* Treat ctrl-p as up */
- if (! (key_event->state & GDK_CONTROL_MASK))
- return FALSE;
-
- case GDK_Up:
- case GDK_KP_Up:
- dir = -1;
- break;
-
- case GDK_Tab:
- /* If our cursor is still up in the entry, move down into
- the popup. Otherwise unbrowse. */
- if (cv->choices->len > 0) {
- if (cv->selection < 0) {
- cv->selection = 0;
- dir = 0;
- } else {
- cv->selection = -1;
- dir = 0;
- key_handled = FALSE;
- }
- }
- break;
-
- case GDK_space:
- case GDK_KP_Space:
- is_space = TRUE;
-
- case GDK_Return:
- case GDK_KP_Enter:
- if (cv->selection < 0) {
- /* We don't have a selection yet, move to the first selection if there is
- more than one option. If there is only one option, select it automatically. */
-
- /* Let space pass through. */
- if (is_space)
- return FALSE;
-
- if (cv->choices->len == 1) {
- e_completion_view_select (cv, 0);
- goto stop_emission;
- } else {
- cv->selection = 0;
- dir = 0;
- }
-
- } else {
- /* Our cursor is down in the pop-up, so we make our selection. */
- e_completion_view_select (cv, cv->selection);
- goto stop_emission;
- }
- break;
-
- case GDK_Escape:
- /* Unbrowse hack */
- cv->selection = -1;
- dir = 0;
- break;
-
- default:
- return FALSE;
- }
-
- cv->selection += dir;
-
- if (cv->selection >= (int)cv->choices->len) {
- cv->selection = cv->choices->len - 1;
- /* Don't re-emit the browse signal */
- goto stop_emission;
- }
-
- e_completion_view_set_cursor_row (cv, cv->selection);
-
- if (cv->selection >= 0)
- g_signal_emit (cv, e_completion_view_signals[E_COMPLETION_VIEW_BROWSE], 0,
- g_ptr_array_index (cv->choices, cv->selection));
- else
- g_signal_emit (cv, e_completion_view_signals[E_COMPLETION_VIEW_UNBROWSE], 0);
-
- stop_emission:
-
- if (key_handled)
- g_signal_stop_emission_by_name (w, "key_press_event");
-
- return key_handled;
-}
-
-static void
-begin_completion_cb (ECompletion *completion, const gchar *txt, gint pos, gint limit, gpointer user_data)
-{
- ECompletionView *cv = E_COMPLETION_VIEW (user_data);
-
- e_table_model_pre_change (cv->model);
- e_completion_view_clear_choices (cv);
- cv->have_all_choices = FALSE;
-
- e_table_model_changed (cv->model);
-}
-
-static void
-completion_cb (ECompletion *completion, ECompletionMatch *match, gpointer user_data)
-{
- ECompletionView *cv = E_COMPLETION_VIEW (user_data);
- gint r = cv->choices->len;
- gboolean first = (cv->choices->len == 0);
-
- e_table_model_pre_change (cv->model);
-
- e_completion_match_ref (match);
- g_ptr_array_add (cv->choices, match);
-
- e_table_model_row_inserted (cv->model, r);
-
- if (first)
- g_signal_emit (cv, e_completion_view_signals[E_COMPLETION_VIEW_NONEMPTY], 0);
-
- g_signal_emit (cv, e_completion_view_signals[E_COMPLETION_VIEW_ADDED], 0);
-}
-
-static void
-end_completion_cb (ECompletion *completion, gpointer user_data)
-{
- ECompletionView *cv = E_COMPLETION_VIEW (user_data);
-
- /* Do a final refresh of the table. */
- e_table_model_pre_change (cv->model);
- e_table_model_changed (cv->model);
-
- cv->have_all_choices = TRUE;
- g_signal_emit (cv, e_completion_view_signals[E_COMPLETION_VIEW_FULL], 0);
-}
-
-/*** Table Callbacks ***/
-
-/* XXX toshok - we need to add sorting to this etable, through the use
- of undisplayed fields of all the sort keys we want to use */
-static char *simple_spec =
-"<ETableSpecification no-headers=\"true\" draw-grid=\"false\" cursor-mode=\"line\" alternating-row-colors=\"false\" gettext-domain=\"" E_I18N_DOMAIN "\">"
-" <ETableColumn model_col=\"0\" _title=\"Node\" expansion=\"1.0\" "
-" minimum_width=\"16\" resizable=\"true\" cell=\"string\" "
-" compare=\"string\"/> "
-" <ETableState> "
-" <column source=\"0\"/> "
-" <grouping></grouping> "
-" </ETableState> "
-"</ETableSpecification>";
-
-static gint
-table_col_count (ETableModel *etm, gpointer data)
-{
- return 1;
-}
-
-static gint
-table_row_count (ETableModel *etm, gpointer data)
-{
- ECompletionView *cv = E_COMPLETION_VIEW (data);
- return cv->choices->len;
-}
-
-static gboolean
-table_is_cell_editable (ETableModel *etm, gint c, gint r, gpointer data)
-{
- return FALSE;
-}
-
-static gpointer
-table_value_at (ETableModel *etm, gint c, gint r, gpointer data)
-{
- ECompletionView *cv = E_COMPLETION_VIEW (data);
- ECompletionMatch *match;
-
- match = g_ptr_array_index (cv->choices, r);
-
- return (gpointer) e_completion_match_get_menu_text (match);
-}
-
-static gchar *
-table_value_to_string (ETableModel *em, gint col, gconstpointer val, gpointer data)
-{
- return (gchar *) val;
-}
-
-static void
-table_click_cb (ETable *et, gint r, gint c, GdkEvent *ev, gpointer data)
-{
- ECompletionView *cv = E_COMPLETION_VIEW (data);
-
- e_completion_view_select (cv, r);
-}
-
-void
-e_completion_view_construct (ECompletionView *cv, ECompletion *completion)
-{
- g_return_if_fail (cv != NULL);
- g_return_if_fail (E_IS_COMPLETION_VIEW (cv));
- g_return_if_fail (completion != NULL);
- g_return_if_fail (E_IS_COMPLETION (completion));
-
- /* Make sure we don't call construct twice. */
- g_return_if_fail (cv->completion == NULL);
-
- GTK_WIDGET_SET_FLAGS (GTK_WIDGET (cv), GTK_CAN_FOCUS);
-
- cv->completion = completion;
- g_object_ref (completion);
-
- cv->begin_signal_id = g_signal_connect (completion,
- "completion_started",
- G_CALLBACK (begin_completion_cb),
- cv);
- cv->comp_signal_id = g_signal_connect (completion,
- "completion_found",
- G_CALLBACK (completion_cb),
- cv);
- cv->end_signal_id = g_signal_connect (completion,
- "completion_finished",
- G_CALLBACK (end_completion_cb),
- cv);
-
- cv->model = e_table_simple_new (table_col_count,
- table_row_count,
- NULL,
-
- table_value_at,
- NULL,
- table_is_cell_editable,
-
- NULL, NULL,
-
- NULL, NULL, NULL, NULL,
- table_value_to_string,
- cv);
-
- cv->table = e_table_scrolled_new (cv->model, NULL, simple_spec, NULL);
- g_object_unref (cv->model);
-
- gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (cv->table), GTK_SHADOW_NONE);
- gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (cv->table), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
-
- gtk_container_add (GTK_CONTAINER (cv), cv->table);
- gtk_widget_show_all (cv->table);
-
- g_signal_connect (e_completion_view_table (cv),
- "click",
- G_CALLBACK (table_click_cb),
- cv);
-
- cv->selection = -1;
-}
-
-GtkWidget *
-e_completion_view_new (ECompletion *completion)
-{
- gpointer p;
-
- g_return_val_if_fail (completion != NULL, NULL);
- g_return_val_if_fail (E_IS_COMPLETION (completion), NULL);
-
- p = g_object_new (E_COMPLETION_VIEW_TYPE, NULL);
-
- e_completion_view_construct (E_COMPLETION_VIEW (p), completion);
-
- return GTK_WIDGET (p);
-}
-
-void
-e_completion_view_connect_keys (ECompletionView *cv, GtkWidget *w)
-{
- g_return_if_fail (cv != NULL);
- g_return_if_fail (E_IS_COMPLETION_VIEW (cv));
- g_return_if_fail (w == NULL || GTK_IS_WIDGET (w));
-
- if (cv->key_widget) {
- g_signal_handler_disconnect (cv->key_widget, cv->key_signal_id);
- g_object_unref (cv->key_widget);
- }
-
- if (w) {
- cv->key_widget = w;
- g_object_ref (w);
-
- cv->key_signal_id = g_signal_connect (w,
- "key_press_event",
- G_CALLBACK (e_completion_view_key_press_handler),
- cv);
- } else {
- cv->key_widget = NULL;
- cv->key_signal_id = 0;
- }
-}
-
-void
-e_completion_view_set_complete_key (ECompletionView *cv, gint keyval)
-{
- g_return_if_fail (cv != NULL);
- g_return_if_fail (E_IS_COMPLETION_VIEW (cv));
-
- cv->complete_key = keyval;
-}
-
-void
-e_completion_view_set_uncomplete_key (ECompletionView *cv, gint keyval)
-{
- g_return_if_fail (cv != NULL);
- g_return_if_fail (E_IS_COMPLETION_VIEW (cv));
-
- cv->uncomplete_key = keyval;
-}
-
-void
-e_completion_view_set_width (ECompletionView *cv, gint width)
-{
- GtkWidget *w;
- gint y, r, dummy, line_height, final_height;
- double drop_room, lines;
-
- g_return_if_fail (cv != NULL);
- g_return_if_fail (E_IS_COMPLETION_VIEW (cv));
- g_return_if_fail (width > 0);
-
- w = GTK_WIDGET (cv);
-
- if (! GTK_WIDGET_REALIZED (w)) {
- gtk_widget_set_usize (w, width, -1);
- return;
- }
-
- /* A Horrible Hack(tm) to figure out the height of a single table row */
-
- for (line_height=5, r=0; r == 0