From: Paul Mangan Date: Mon, 10 May 2004 10:22:28 +0000 (+0000) Subject: sync with 0.9.10claws57 HEAD X-Git-Tag: gtk2_win32_last_merge~415 X-Git-Url: http://git.claws-mail.org/?p=claws.git;a=commitdiff_plain;h=06656e67f1f676fcc031c087a9c586a9eef599dd sync with 0.9.10claws57 HEAD --- diff --git a/AUTHORS b/AUTHORS index 8be22e385..2893b1e99 100644 --- a/AUTHORS +++ b/AUTHORS @@ -38,10 +38,11 @@ sylpheed-claws translation team [es] Ricardo Mones Lastra [fr] Melvin Hadasht [hr] Dragan - [it] Alessandro Maestri + [it] Andrea Spadaccini [ja] Rui Hirokawa [pl] Emil [ru] Ruslan N. Balkin + [ru] Pavlo Bohmat [sk] Andrej Kacian [sr] Urke MMI [zh_CN] Hansom Young @@ -200,3 +201,5 @@ contributors (beside the above; based on Changelog) Matthias Förste David Chalmers Chad Robinson + Edgar Toernig + Fabien Vantard diff --git a/ChangeLog b/ChangeLog index 1e9d727cd..9cf0880c4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,162 @@ +2004-03-19 + + * src/defs.h + src/inc.[ch]: changed the method of updating the progress dialog + to reduce the overhead on a fast network. + +2004-03-16 + + * src/nntp.c: nntp_session_new(): attempt to authenticate at the + beginning of a session (thanks to Shiino Yuki and IWAMOTO, Kouichi). + * src/news.c + src/nntp.c: destroy session when socket error occurred. + +2004-03-12 + + * src/mainwindow.c + src/summaryview.[ch]: added a function to filter selected + messages. + +2004-03-12 + + * src/filter.[ch] + src/prefs_filter.c: rewrote the filtering system (the UI is not + implemented yet). + +2004-03-09 + + * src/filter.c: fixed the matching algorithm of "not contain" flag + (also match if a header not exist, and handle same multiple + headers). + * src/imageview.c: get_resized_size(): fixed a typo that caused + resizing problem. + +2004-03-02 + + * src/folder.c + src/mh.c: only update FolderItem::last_num when removing the last + number of message in MH folders, and don't scan in other case + (fixes wrong message count on moving). + +2004-03-02 + + * src/folderview.c + src/summaryview.c: always move messages by default when using DnD + (except for News folder). Copy messages if Ctrl-key is pressed. + * src/mainwindow.c: main_window_empty_trash() + src/summaryview.c: summary_execute(): added missing + statusbar_pop_all(). + +2004-02-29 + + * version 0.9.10 + +2004-02-26 + + * src/prefs_common.c: made the default of "inc_local" FALSE. + +2004-02-26 + + * src/account.c + src/folderview.c: toggle online mode when checking IMAP4 accounts. + Pop status bar after that. + * src/inc.c: code cleanup. + * src/mainwindow.[ch]: added main_window_get() and + main_window_toggle_online_if_offline(). + * src/prefs_common.c: prefs_common_read_config(): fixed a bug that + made it offline mode on first execution. + +2004-02-25 + + * src/imageview.c: enabled automatic resize on window resize. + restrict the minimum size to 16 pixels to prevent crash. + imageview_init(): don't cache images when using imlib. + imageview_show_image(): fixed memory leak. + * src/mimeview.c: mimeview_init(): call imageview_init(). + +2004-02-24 + + * src/codeconv.[ch]: added ISO-2022-JP-3 encoding. + +2004-02-24 + + * src/codeconv.c + src/mainwindow.c + src/messageview.c: added KOI8-U encoding. + * src/prefs_common.c: prefs_message_create(): modified the string + of resizing image option. + +2004-02-19 + + * src/addressbook.c: addressbook_list_selected(): corrected its + argument. + * src/imageview.[ch]: keep original image data in ImageView, and + enabled the toggle of resizing. + * src/messageview.[ch] + src/mimeview.[ch]: handle ImageView in MimeView instead of + MessageView. + +2004-02-16 + + * src/imap.c + src/news.c + src/summaryview.c: removed statusbar_pop_all() from imap.c and + news.c (do it in summaryview.c). + +2004-02-12 + + * src/inc.[ch] + src/pop.[ch]: made inc_drop_message() the virtual function of + Pop3Session and removed the dependency of pop.c on inc.h. + +2004-02-12 + + * src/mainwindow.c + src/messageview.[ch] + src/textview.c: added statusbar to the message view with new window. + +2004-02-10 + + * src/inc.[ch]: use hash table for progressive update. + changed update interval to 2 sec. + * src/folder.[ch] + src/mh.c + src/procmsg.c + src/summaryview.c: added FolderItem::unmarked_num to correct the + folder message counting. + +2004-02-09 + + * src/inc.[ch]: update folderview progressively. + * src/foldersel.c: display full id for selected item. + +2004-02-06 + + * src/folderview.[ch]: code cleanup. + folderview_append_item(): new. It appends the folder to the folder + view. + * src/foldersel.c: foldersel_new_folder(): use + folderview_append_item(). + +2004-02-06 + + * src/foldersel.c: implemented 'create new folder' function. + * src/folder.[ch]: folder_find_child_item_by_name(): new. + * src/utils.h: AUTORELEASE_STR(): convert malloc'd string into + auto-release (alloca'd) one. + +2004-02-05 + + * src/folderview.c: put together folderview_new_imap_folder_cb() into + folderview_new_folder_cb(). + +2004-02-04 + + * src/compose.c: compose_write_to_file(): removed redundant strlen() + (thanks to Alfons). + * src/textview.c: textview_button_pressed(): select correct account + when address is clicked. + 2004-01-29 * version 0.9.9 @@ -5879,7 +6038,7 @@ * src/alertpanel.c: alertpanel_create(): fixed truncated message. * src/rfc2015.c: rfc2015_decrypt_message(): fixed the case problem - of content-type (thanks to René Rebe for the patch). + of content-type (thanks to Ren?Rebe for the patch). * src/codeconv.c: code_get_code_conv_func(): fixed the ISO-8859-1 detection. * src/prefs_common.c: prefs_send_create(): made some more character diff --git a/ChangeLog-gtk2.claws b/ChangeLog-gtk2.claws index 4cc8314f0..fb14e004c 100644 --- a/ChangeLog-gtk2.claws +++ b/ChangeLog-gtk2.claws @@ -1,3 +1,7 @@ +2004-05-10 [paul] 0.9.10claws57 + + * sync with 0.9.10claws57 HEAD + 2004-05-05 [paul] 0.9.9.claws1 * ChangeLog-gtk2 ** REMOVED ** diff --git a/ChangeLog.claws b/ChangeLog.claws index 4c25467ec..f793b5988 100644 --- a/ChangeLog.claws +++ b/ChangeLog.claws @@ -1,3 +1,834 @@ +2004-05-09 [christoph] 0.9.10claws57 + + * src/folderview.c + check for folder class functions and not folder type to detect + valid drag targets + +2004-05-08 [christoph] 0.9.10claws56 + + * src/sgpgme.c + fix date output for signature expire times + + (Patch by Edgar Toernig ) + +2004-05-06 [christoph] 0.9.10claws55 + + * src/gtk/prefswindow.c + change window type to DIALOG + + * src/folder.[ch] + * src/folderview.c + * src/news_gtk.c + o add folder_remove() + o change FolderUpdate hook flag names (NEW -> ADD, DESTROY -> REMOVE) + o add new "sort" field to Folder, no longer sort folders by type + higher sort values will be first in the folder list, new folders get 0 + and will be added to the end + + * src/mainwindow.c + * src/gtk/Makefile.am + * src/gtk/foldersort.(c|h|glade) ** NEW ** + add dialog to allow users to change the folder order + +2004-05-04 [paul] 0.9.10claws54 + + * src/inc.c + Display account_name in statusbar when retrieving + messages from a pop account + * src/prefs_account.c + display account name in title of prefs_account + window + * src/prefs_folder_item.c + display folder name in title of prefs_folder window + + all 3 patches submitted by Fabien Vantard + + * AUTHORS + add Fabien Vantard + +2004-05-04 [paul] 0.9.10claws53 + + * src/prefs_actions.c + src/prefs_template.c + 'Esc' Key exits alertpanel + Patch submitted by Fabien Vantard + +2004-04-26 [christoph] 0.9.10claws52 + + * src/gtk/about.c + * src/gtk/colorsel.c + * src/gtk/description_window.c + * src/gtk/filesel.c + * src/gtk/gtkaspell.c + * src/gtk/inputdialog.c + * src/gtk/pluginwindow.c + * src/gtk/progressdialog.c + o remove gtk_window_set_position(..., GTK_WIN_POS_CENTER) because + it does not work correctly with xinerama + o lock incorporation while the plugin window is open + +2004-04-23 [paul] 0.9.10claws51 + + * po/POTFILES.in + update location of inputdialog.c + + * src/gtk/about.c + update Copyright string + + * src/msgcache.c + src/prefs_common.c + src/prefs_themes.c + improve the english a little + +2004-04-22 [christoph] 0.9.10claws50 + + * src/folderutils.[ch] + add folderutils_mark_all_read() + + * src/folderview.c + readd "mark all read" from popup menu, now works + in all folders and not only the opened folder + +2004-04-21 [christoph] 0.9.10claws49 + + * src/Makefile.am + * src/inputdialog.[ch] ** REMOVED ** + * src/gtk/Makefile.am + * src/gtk/inputdialog.[ch] ** NEW ** + move inputdialog.[ch] into gtk directory + + * src/mh_gtk.c + remove check for missing IMAP folder account + +2004-04-20 [christoph] 0.9.10claws48 + + * src/mainwindow.c + * src/foldersel.c + remove new/rename/delete folder GUI functions because + they are always active, even for news folders, and can + not be easily made folder class dependent + + * src/gtk/menu.[ch] + make menu_translate() public + + * src/Makefile.am + * src/folder.[ch] + * src/folderview.[ch] + * src/imap_gtk.[ch] ** NEW ** + * src/main.c + * src/mh_gtk.[ch] ** NEW ** + * src/news_gtk.[ch] ** NEW ** + o dynamically build FolderView popup menus from a folder + specific part, with callbacks to seperated code, and + a common part + o remove the folder class specifiy code from folderview.c + +2004-04-15 [luke] 0.9.10claws47 + + * src/prefs_folder_item.c + o remove buttons for applying 'scan for new mail' + and 'process at startup' to sub folders + o add 'apply to sub folder' check buttons for all + properties and set folder prefs accordingly + o replace multiple gtk_widget_show() with one + gtk_widget_show_all() on container + +2004-04-14 [darko] 0.9.10claws46 + + * src/gtk/Makefile.am + * src/gtk/pluginwindow.c + load plugins from to $(prefix)/lib/sylpheed/plugins + in file selection dialog + * src/plugins/clamav/clamav_plugin.c + const correctness + +2004-04-14 [christoph] 0.9.10claws45 + + * src/folder.c + * src/plugins/image_viewer/viewer.c + fix g_warnings + +2004-04-10 [alfons] 0.9.10claws44 + + * src/compose.c + appropriate auto account selection when forwarding + (fixes bug #476, "forward as attachment does not listen + to account rules") + +2004-04-09 [alfons] 0.9.10claws43 + + * src/summaryview.c + make quick search combo matching case sensitive + +2004-04-06 [alfons] 0.9.10claws42 + + * src/addr_compl.c + use cursor position to prevent clearing the entire entry + +2004-04-06 [alfons] 0.9.10claws41 + + * src/folderview.c + fix bug #472, "filter not updated when renaming folder" + +2004-04-06 [alfons] 0.9.10claws40 + + * src/messageview.[ch] + src/summaryview.c + reflect changes to Show all headers to main view + and message view (only affects detached message + view). see also bug #473, 'Show All Headers + "problem"'. + +2004-04-03 [alfons] 0.9.10claws39 + + * src/matcher.c + free address list + +2004-04-03 [alfons] 0.9.10claws38 + + * src/matcher_parser_parse.y + src/matcher.[ch] + prepare address look up matcher type; marginally + tested, and not hooked into the UI yet. + + basically it accepts the result of the left hand + side of the matcher (the "criteria"): + + from all_in_addressbook "" + ~to_or_cc any_in_addressbook "" + + the first case matches all addresses found in the + from header, and the second case matches if any + (at least one) of the addresses in to or cc headers + are not in the address book. + + the string argument is not used yet, but is intended + to match a group of addresses + +2004-04-02 [luke] 0.9.10claws37 + + * src/prefs_folder_item.c + Add two buttons to apply 'scan for new mail' + and 'process at startup' to sub folders + +2004-04-02 [luke] + * tools/textviewer.sh + better filename extension matching plus some support for + MS Excel, MS Powerpoint and HTML + +2004-03-29 [christoph] 0.9.10claws36 + + * src/folder.h + * src/folderutils.[ch] + * src/mainwindow.c + add delete duplicates for all folders + +2004-03-29 [alfons] 0.9.10claws35 + + * src/folder.c + don't pass NULL to XXXprintf(); fixes Solaris crashes + when selecting top-level folder node (thanks to + Alex S. Moore) + +2004-03-28 [keith] 0.9.10claws34 + + * src/textview.c + prepend "http://" to URIs of the form "www.example.com" + +2004-03-28 [paul] 0.9.10claws33 + + * src/common/nntp.c + src/common/smtp.c + src/folder.c + src/imap.c + src/inc.c + src/news.c + src/pop.c + revise 'translatable string' policy: + don't translate debug_print() or log_print(), + translate log_message() and log_warning() + + * po/zh_CN.po + update submitted by Hansom Young + +2004-03-25 [alfons] 0.9.10claws32 + + * src/prefs_common.c + I mean this one: Return the GList... + +2004-03-25 [alfons] 0.9.10claws31 + + * src/prefs_common.h + add new members at the end of prefs_common, so + they get properly initialized + +2004-03-24 [christoph] 0.9.10claws30 + + * src/imap.c + o NULL is a valid GSList + +2004-03-24 [alfons] 0.9.10claws29 + + * src/prefs_common.[ch] + src/summaryview.c + src/common/defs.h + add history to quick search (patch submitted by + Ivan Francolin Martinez - thanks!) + +2004-03-24 [alfons] 0.9.10claws28 + + * src/imap.c + NULL output pointer parameter + +2004-03-21 [alfons] 0.9.10claws27 + + * src/addrindex.[ch] + src/addr_compl.c + complete addresses on nicks and aliases + +2004-03-21 [alfons] 0.9.10claws26 + + * src/import.c + src/inc.c + src/mbox.[ch] + disable filters on import mbox (patch submitted + by Edgar Toernig) + +2004-03-21 [darko] 0.9.10claws25 + + * src/addr_compl.c + select the address when only one match is found while + doing address completion with tab key (feature + request #914720) + +2004-03-21 [alfons] 0.9.10claws24 + + * src/messageview.c + src/toolbar.c + don't `navigate-delete` when a summary view's selection does not + match the accompanying message view's message + +2004-03-20 [alfons] 0.9.10claws23 + + * src/summaryview.c + hide ext search button on initial display (should fix bug #459, + "Toggling quick-search at 1st time: minor UI inconsistency") + +2004-03-20 [alfons] 0.9.10claws22 + + * src/summaryview.[ch] + add function to get selected msginfo, if there's + only one selected + +2004-03-20 [paul] 0.9.10claws21 + + * sync with 0.9.10cvs7 + see ChangeLog 2004-03-19 + +2004-03-19 [paul] 0.9.10claws20 + + * src/common/nntp.c + src/common/smtp.c + src/common/ssl.c + src/folder.c + src/imap.c + src/inc.c + src/news.c + src/pop.c + don't translate strings in debug_print(), log_print(), + log_message(), and log_warning() + +2004-03-19 [alfons] 0.9.10claws19 + + better next/previous/delete/focus navigation with separate + message view + + * src/toolbar.c + call summaryview_delete() instead of messageview_delete() + * src/messageview.c + disable messageview_delete() + +2004-03-18 [paul] 0.9.10claws18 + + * sync with 0.9.10cvs6 + see ChangeLog 2004-03-16 + +2004-03-17 [alfons] 0.9.10claws17 + + * src/gtk/filesel.c + remove bogus semicolon after if() (sometimes it pays to + read LKML :) + +2004-03-15 [darko] 0.9.10claws16 + + * src/gtk/filesel.c + support full path in place of a filename + * src/mimeview.c + store directory attachments were saved to and + use it when saving attachments + * src/prefs_common.[hc] + store directory attachments were last saved to + +2004-03-15 [paul] 0.9.10claws15 + + * src/folderview.c + fix bug where unsubscribing a newsgroup would destroy + (most of the) filtering rules + +2004-03-15 [paul] 0.9.10claws14 + + * src/folderview.c + fix Bug 458, 'Folder View remaining empty after + removing a NEWS account' (was also true of IMAP + accounts) + +2004-03-15 [paul] 0.9.10claws13 + + * src/folderview.c + fix folderview invisibility of newly subscribed + newsgroups + +2004-03-13 [paul] 0.9.10claws12 + + * src/compose.c + src/plugins/dillo_viewer/dillo_prefs.c + src/plugins/image_viewer/viewerprefs.c + gettextise some forgotten parts + +2004-03-13 [alfons] 0.9.10claws11 + + * src/imap.c + make sure the correct type is passed to sscanf() + +2004-03-13 [paul] 0.9.10claws10 + + * sync with 0.9.10cvs5 + see ChangeLog 2004-03-02 and 2004-03-12, + specifically: + 'always move messages by default when using DnD (except + for News folder). Copy messages if Ctrl-key is pressed.' + and 'added a function to filter selected messages' + +2004-03-12 [christoph] 0.9.10claws9 + + * src/codeconv.c + add parameter check to conv_unmime_header_overwrite() + + * src/imap.c + o fix spelling + o fix removing of NEW flag when UNREAD is unset + + * src/procmime.c + decode MIME-headers + + (Closes 437 i18n attachment display error.) + +2004-03-12 [paul] 0.9.10claws8 + + * po/it.po + update. submitted by Andrea Spadaccini + + * tools/Makefile.am + add 'textviewer.sh' + +2004-03-12 [alfons] 0.9.10claws7 + + * src/imap.c + o quiet compiler and typecast Folder * to IMAP Folder * + o wake up and fix my previous incompatible type assignment bug + +2004-03-12 [alfons] 0.9.10claws6 + + * src/imap.c + don't mix up pointers to int, guint32 _and_ + unsigned int + +2004-03-12 [christoph] 0.9.10claws5 + + * src/folderview.c + Add error requester when renaming a folder failed + + * src/imap.c + Check new FolderItem name for namespace seperator + before renaming + + (Closes Bug 443 Bad named IMAP folders won't be displayed) + +2004-03-11 [christoph] 0.9.10claws4 + + * src/folder.[ch] + * src/imap.c + * src/procmsg.h + syncronize flags in cache with IMAP folder flags + + Adapted a patch submitted by Simon 'corecode' Schubert + + + +2004-03-11 [alfons] 0.9.10claws3 + + * src/textview.[ch] + remove dead code that at one time controlled display of + URIs in status bar + +2004-03-10 [paul] 0.9.10claws2 + + * po/it.po + updated by Lupino + +2004-03-09 [alfons] 0.9.10claws1 + + * src/matcher.c + we're not using yywrap, but we may, so close yyin instead + of initial FILE * + +2004-03-08 [paul] 0.9.10claws + + * 0.9.10claws released + +2004-03-08 [paul] 0.9.9claws41 + + * po/es.po + po/ja.po + po/ru.po + po/sk.po + po/sr.po + po/zh_CN.po + update translations. submitted by Ricardo Mones Lastra, + Rui Hirokawa, Pavlo Bohmat, Andrej Kacian, Urke MMI, + Hansom Young + +2004-03-06 [paul] 0.9.9claws40 + + * src/stock_pixmap.c + fix crash: g_strdup(DEFAULT_PIXMAP_THEME) + patch submitted by Pawel Pekala + +2004-03-06 [alfons] 0.9.9claws39 + + * src/addrindex.c + allow nick name completion again + +2004-03-02 [match] 0.9.9claws38 + + * configure.ac + added definition of USE_LDAP_TLS to support TLS. + * src/ldapctrl.[ch] + * src/ldapquery.c + * src/ldapserver.[ch] + * src/addressbook.c + * src/addrindex.c + * src/editldap.c + included LDAP TLS support. + +2004-03-02 [christoph] 0.9.9claws37 + + * src/folder.[ch] + o add more documentation for FolderClass + o remove usused FolderClass virtual functions + + * src/imap.c + * src/mh.c + * src/news.c + change creation of FolderClass because static initializations + for structs suck in C89 + +2004-03-01 [paul] + + * sync with 0.9.10 + +2004-02-28 [keith] 0.9.9claws36 + + * src/common/utils.c + Fix treatment of whitespace in quicksearch bar (leading + spaces and >1 space between commands and parameters). + +2004-02-27 [alfons] 0.9.9claws35 + + * src/compose.[ch] + Explicitly remove draft timeout to fix nasty race between + compose_send_cb() (which destroys the compose window) and + compose_defer_auto_save_draft() (which expects compose + window to exist). Should fix Keith's and Fred Marton's + bug report (#128, "crash after complaining about character + set conversion") + +2004-02-27 [luke] 0.9.9claws34 + + * src/folder.c + Do folder_item_apply_processing() even if no processing + rules for the folder exist (so global processing is applied) + +2004-02-26 [thorsten] 0.9.9claws33 + + * src/mimeview.c + Remove misleading static declaration + +2004-02-26 [alfons] 0.9.9claws32 + + * src/procmime.[ch] + src/compose.c + src/mimeview.c + src/textview.c + use/add procmime_get_content_type_str() as a safe wrapper + for returning a Content-Type type string; should fix + bug #444, 0.9.7..0.9.9 crashes with "Content-Type: type= + - attachments." + +2004-02-26 [thorsten] 0.9.9claws31 + + * src/mimeview.c + Restructure save_as/save_all + +2004-02-26 [alfons] 0.9.9claws30 + + * src/procmime.c + clean up (2) + +2004-02-26 [alfons] 0.9.9claws29 + + * src/procmime.c + clean up (1) + +2004-02-24 [luke] + + * tools/textviewer.sh + tweaks from Johann Koenig, recognition of shell + scripts in particular + +2004-02-24 [paul] 0.9.9claws28 + + * sync with 0.9.9cvs13 + see ChangeLog 2004-02-24 + +2004-02-23 [paul] 0.9.9claws27 + + * src/inc.c + one alertpanel on pop3 authentication error will suffice + + * src/prefs_fonts.c + remove unnecessary printf + +2004-02-22 [alfons] 0.9.9claws26 + + * src/messageview.c + put back a lost check + +2004-02-21 [alfons] 0.9.9claws25 + + * src/folderview.c + don't forget to save folder properties after renaming folder + +2004-02-20 [paul] 0.9.9.claws24 + + * src/addressbook.c + sync with 0.9.9cvs11, see ChangeLog 2004-02-19 + + * src/inc.c + complete sync with 0.9.9cvs9's 'update folderview + progressively' + + * configure.ac + require gettext >= 0.12.1 + +2004-02-17 [match] 0.9.9claws23 + + * src/compose.c + keep the peace - change style. + +2004-02-17 [alfons] 0.9.9claws22 + + * src/filtering.c + make MATCHACTION_STOP cancel filtering / processing; + clean up and document it to make it a little bit more clear; + +2004-02-17 [alfons] 0.9.9claws21 + + %X marks the cursor spot for reply quote format + + * src/quote_fmt_lex.l + src/quote_fmt.c + add %X token + + * src/quote_fmt.h + src/quote_fmt_parse.y + handle %X token + + * src/compose.c + handle %X token for replies only (for now) + +2004-02-17 [paul] 0.9.9claws20 + + * po/sk.po + updated by Andrej Kacian + + * src/news.c + remove unneeded include + + * src/prefs_fonts.c + be a little more user-friendly with the labels + + * configure.ac + a change forgotten in the last commit: + SYLPHEED_ACLOCAL_INCLUDE(m4) + +2004-02-17 [paul] 0.9.9claws19 + + * ac/* ** REMOVED ** + ac/ ** REMOVED ** + intl/Makefile.in ** REMOVED ** + m4/ ** NEW ** + m4/missing ** NEW ** + m4/missing/gdk-pixbuf.m4 ** NEW ** + m4/missing/gettext.m4 ** NEW ** + m4/missing/gpgme.m4 ** NEW ** + m4/missing/imlib.m4 ** NEW ** + m4/.cvsignore ** NEW ** + m4/Makefile.am ** NEW ** + m4/README ** NEW ** + m4/aclocal-include.m4 ** NEW ** + m4/aspell.m4 ** NEW ** + m4/check-type.m4 ** NEW ** + m4/gnupg-check-typedef.m4 ** NEW ** + m4/openssl.m4 ** NEW ** + m4/spamassassin.m4 ** NEW ** + po/ChangeLog ** REMOVED ** + po/Makefile.in.in ** REMOVED ** + po/Rules-quot ** REMOVED ** + po/boldquot.sed ** REMOVED ** + po/en@boldquot.header ** REMOVED ** + po/en@quot.header ** REMOVED ** + po/insert-header.sin ** REMOVED ** + po/quot.sed ** REMOVED ** + po/remove-potcdate.sed ** REMOVED ** + po/remove-potcdate.sin ** REMOVED ** + po/stamp-po ** REMOVED ** + Makefile.am + autogen.sh + configure.ac + enable building with automake 1.8.x + add 'autopoint' to autogen.sh and remove all + auto-generated files, remove ac/ in favour of + m4/ + +2004-02-17 [alfons] 0.9.9claws18 + + * src/summaryview.c + MSG_IS_NEWS() is not stored at all, and is bogus + +2004-02-17 [martin] 0.9.9claws17 + + * src/prefs_themes.c + fix crash when installing wrong theme and output an + error message + +2004-02-16 [christoph] 0.9.9claws16 + + * src/compose.c + * src/stock_pixmap.[ch] + * src/toolbar.[ch] + * src/pixmaps/linewrapcurrent.xpm ** NEW ** + add "Wrap current paragraph" to compose toolbar + +2004-02-15 [alfons] 0.9.9claws15 + + * src/folderview.c + refine previous commit to make sure other hook functions + get their grab of the pie too + +2004-02-15 [alfons] 0.9.9claws14 + + * src/folderview.c + fix sync breakage so we don't pass invalid pointer types + +2004-02-15 [match] 0.9.9claws13 + + * src/ldapquery.[ch] + * src/ldapserver.h + * src/addrindex.[ch] + tweak threading calls. + * src/addr_compl.[ch] + add alias into completion list. + * src/addressbook.c + fix ldap browse. + improve context menu behavior. + change menu sequence. + add send mail from addressbook. + * src/addrselect.[ch] + * src/compose.[ch] + add send mail from addressbook. + +2004-02-15 [christoph] 0.9.9claws12 + + * src/folderutils.c + skip deleting when duplist is empty + + * src/folderview.[ch] + * src/mainwindow.c + * src/summaryview.[ch] + call folderutils_delete_duplicates() from mainwindow code + +2004-02-15 [alfons] 0.9.9claws11 + + * src/common/utils.c + add prefix for italian ms o(e) + +2004-02-14 [paul] 0.9.9claws10 + + * src/foldersel.c + fix updating of the folder view when creating a + new folder + +2004-02-13 [paul] 0.9.9claws9 + + * src/plugins/clamav/clamav_plugin.c + remove GUI code + +2004-02-13 [paul] 0.9.9claws8 + + * sync with 0.9.9cvs9 + see ChangeLog 2004-02-09, 2004-02-10, 2004-02-12 + +2004-02-13 [alfons] 0.9.9claws7 + + * src/common/utils.c + fix wrong type of argument for ctype functions (pass unsigned + char instead of signed char) + +2004-02-12 [alfons] 0.9.9claws6 + + * src/compose.[ch] + don't select text in header entry when composing to a + default address, but rather give the header entry a + different color / style (same as the folder new color) + +2004-02-12 [alfons] 0.9.9claws5 + + * src/plugins/clamav/clamav_plugin.c + don't exit(2) on libclamav init error - show a warning. + (tested by damaging a clamav database file.) + +2004-02-12 [paul] 0.9.9claws4 + + * sync with 0.9.9cvs4 + see ChangeLog 2004-02-04, 2004-02-05, and 2004-02-06 + +2004-02-11 [luke] 0.9.9claws3 + + * src/mimeview.c + remove redundant check introduced in 0.9.9claws1 + +2004-02-11 [luke] 0.9.9claws2 + + * src/mimeview.c + fix compilation of my previous commit without gpg enabled + +2004-02-10 [luke] 0.9.9claws1 + + * src/mimeview.c + add borders to icons to indicate the privacy status for + the message part (unknown/bad/good) + 2004-02-06 [paul] 0.9.9claws 0.9.9claws released @@ -129,7 +960,7 @@ 2004-01-25 [paul] 0.9.8claws48 - src/prefs_ext_prog.c + * src/prefs_ext_prog.c apply Alfons' patch to check for NULL pointers fixes bug #424 diff --git a/ChangeLog.jp b/ChangeLog.jp index 4d44e7b49..9f5b4e080 100644 --- a/ChangeLog.jp +++ b/ChangeLog.jp @@ -1,3 +1,162 @@ +2004-03-19 + + * src/defs.h + src/inc.[ch]: ¿ÊĽ¥À¥¤¥¢¥í¥°¤Î¹¹¿·ÊýË¡¤òÊѹ¹¤·¡¢¹â®¤Ê¥Í¥Ã¥È¥ï¡¼¥¯ + ¤Ë¤ª¤±¤ë¥ª¡¼¥Ð¡¼¥Ø¥Ã¥É¤ò·Ú¸º¡£ + +2004-03-16 + + * src/nntp.c: nntp_session_new(): ¥»¥Ã¥·¥ç¥ó¤Î³«»Ï»þ¤Ëǧ¾Ú¤ò»î¤ß¤ë + ¤è¤¦¤Ë¤·¤¿(Shiino Yuki ¤µ¤ó¡¢ IWAMOTO, Kouichi ¤µ¤ó thanks)¡£ + * src/news.c + src/nntp.c: ¥½¥±¥Ã¥È¥¨¥é¡¼¤¬È¯À¸¤·¤¿¤È¤­¤Ï¥»¥Ã¥·¥ç¥ó¤òÇË´þ¤¹¤ë + ¤è¤¦¤Ë¤·¤¿¡£ + +2004-03-12 + + * src/mainwindow.c + src/summaryview.[ch]: ÁªÂòÃæ¤Î¥á¥Ã¥»¡¼¥¸¤ò¿¶¤êʬ¤±¤ëµ¡Ç½¤òÄɲᣠ+ +2004-03-12 + + * src/filter.[ch] + src/prefs_filter.c: ¥Õ¥£¥ë¥¿¥·¥¹¥Æ¥à¤òºÆ¼ÂÁõ(UI ¤Ï̤¼ÂÁõ)¡£ + +2004-03-09 + + * src/filter.c: ¡Ö´Þ¤Þ¤Ê¤¤¡×¥Õ¥é¥°¤Î¥Þ¥Ã¥Á¥ó¥°¥¢¥ë¥´¥ê¥º¥à¤ò½¤Àµ + (¥Ø¥Ã¥À¤¬Â¸ºß¤·¤Ê¤¤¾ì¹ç¤Ç¤â¥Þ¥Ã¥Á¤·¡¢Ê£¿ô¤ÎƱ°ì¥Ø¥Ã¥À¤òÀµ¤·¤¯°·¤¦ + ¤è¤¦¤Ë¤·¤¿)¡£ + * src/imageview.c: get_resized_size(): ¥ê¥µ¥¤¥º¤ÎÌäÂê¤òµ¯¤³¤·¤Æ¤¤¤¿ + typo ¤ò½¤Àµ¡£ + +2004-03-02 + + * src/folder.c + src/mh.c: MH ¥Õ¥©¥ë¥À¤ÎºÇ¸å¤ÎÈÖ¹æ¤Î¥á¥Ã¥»¡¼¥¸¤òºï½ü¤·¤¿¤È¤­ + FolderItem::last_num ¤Î¤ß¤ò¹¹¿·¤·¡¢¤½¤Î¾¤Î¾ì¹ç¤Ï¥¹¥­¥ã¥ó¤·¤Ê¤¤ + ¤è¤¦¤Ë¤·¤¿(°ÜÆ°»þ¤Ë¥á¥Ã¥»¡¼¥¸¿ô¤Î·×»»¤ò¸í¤ë¥Ð¥°¤ò½¤Àµ)¡£ + +2004-03-02 + + * src/folderview.c + src/summaryview.c: DnD »ÈÍÑ»þ¤Ï¾ï¤Ë¥Ç¥Õ¥©¥ë¥È¤Ç¥á¥Ã¥»¡¼¥¸¤ò°ÜÆ°¤¹¤ë + ¤è¤¦¤Ë¤·¤¿(¥Ë¥å¡¼¥¹¥Õ¥©¥ë¥À¤ò½ü¤¯)¡£ Ctrl ¥­¡¼¤¬²¡¤µ¤ì¤¿¾ì¹ç¤Ï + ¥á¥Ã¥»¡¼¥¸¤ò¥³¥Ô¡¼¤¹¤ë¤è¤¦¤Ë¤·¤¿¡£ + * src/mainwindow.c: main_window_empty_trash() + src/summaryview.c: summary_execute(): ÉÔ­¤·¤Æ¤¤¤¿ + statusbar_pop_all() ¤òÄɲᣠ+ +2004-02-29 + + * version 0.9.10 + +2004-02-26 + + * src/prefs_common.c: "inc_local" ¤Î¥Ç¥Õ¥©¥ë¥È¤ò FALSE ¤Ë¤·¤¿¡£ + +2004-02-26 + + * src/account.c + src/folderview.c: IMAP4 ¥¢¥«¥¦¥ó¥È¤ò¥Á¥§¥Ã¥¯¤¹¤ë¤È¤­¤Ï¥ª¥ó¥é¥¤¥ó + ¥â¡¼¥É¤ËÀÚ¤êÂؤ¨¤ë¤è¤¦¤Ë¤·¤¿¡£¤½¤Î¸å¥¹¥Æ¡¼¥¿¥¹¥Ð¡¼¤ò pop ¤¹¤ë¤è¤¦¤Ë + ¤·¤¿¡£ + * src/inc.c: ¥³¡¼¥É¤ÎÀ°Íý¡£ + * src/mainwindow.[ch]: main_window_get() ¤È + main_window_toggle_online_if_offline() ¤òÄɲᣠ+ * src/prefs_common.c: prefs_common_read_config(): ½é²óµ¯Æ°»þ¤Ë + ¥ª¥Õ¥é¥¤¥ó¥â¡¼¥É¤Ë¤·¤Æ¤·¤Þ¤Ã¤Æ¤¤¤¿¥Ð¥°¤ò½¤Àµ¡£ + +2004-02-25 + + * src/imageview.c: ¥¦¥£¥ó¥É¥¦¤Î¥ê¥µ¥¤¥º»þ¤Ë¼«Æ°¥ê¥µ¥¤¥º¤¹¤ë¤è¤¦¤Ë¤·¤¿¡£ + ¥¯¥é¥Ã¥·¥å¤òËɤ°¤¿¤á¤ËºÇ¾®¥µ¥¤¥º¤ò16¥Ô¥¯¥»¥ë¤ËÀ©¸Â¡£ + imageview_init(): imlib »ÈÍÑ»þ¤Ï²èÁü¤ò¥­¥ã¥Ã¥·¥å¤·¤Ê¤¤¤è¤¦¤Ë¤·¤¿¡£ + imageview_show_image(): ¥á¥â¥ê¥ê¡¼¥¯¤ò½¤Àµ¡£ + * src/mimeview.c: mimeview_init(): imageview_init() ¤ò¸Æ¤Ö¤è¤¦¤Ë¤·¤¿¡£ + +2004-02-24 + + * src/codeconv.[ch]: ISO-2022-JP-3 ¥¨¥ó¥³¡¼¥Ç¥£¥ó¥°¤òÄɲᣠ+ +2004-02-24 + + * src/codeconv.c + src/mainwindow.c + src/messageview.c: KOI8-U ¥¨¥ó¥³¡¼¥Ç¥£¥ó¥°¤òÄɲᣠ+ * src/prefs_common.c: prefs_message_create(): ²èÁü¥ê¥µ¥¤¥º¥ª¥×¥·¥ç¥ó + ¤Îʸ»úÎó¤ò½¤Àµ¡£ + +2004-02-19 + + * src/addressbook.c: addressbook_list_selected(): °ú¿ô¤ò½¤Àµ¡£ + * src/imageview.[ch]: ¸µ¤Î²èÁü¥Ç¡¼¥¿¤ò ImageView ¤ËÊÝ»ý¤·¡¢ + ¥ê¥µ¥¤¥º¤ÎÀÚ¤êÂؤ¨¤¬¤Ç¤­¤ë¤è¤¦¤Ë¤·¤¿¡£ + * src/messageview.[ch] + src/mimeview.[ch]: MessageView ¤Ç¤Ê¤¯ MimeView ¤Ç ImageView ¤ò + °·¤¦¤è¤¦¤Ë¤·¤¿¡£ + +2004-02-16 + + * src/imap.c + src/news.c + src/summaryview.c: imap.c ¤È news.c ¤«¤é statusbar_pop_all() ¤ò + ½üµî(summaryview.c Æâ¤Ç¼Â¹Ô)¡£ + +2004-02-12 + + * src/inc.[ch] + src/pop.[ch]: inc_drop_message() ¤ò Pop3Session ¤Î²¾ÁÛ´Ø¿ô¤Ë¤·¡¢ + pop3.c ¤Î inc.h ¤Ø¤Î°Í¸¤ò½üµî¡£ + +2004-02-12 + + * src/mainwindow.c + src/messageview.[ch] + src/textview.c: ¿·µ¬¥¦¥£¥ó¥É¥¦¤Î¥á¥Ã¥»¡¼¥¸¥Ó¥å¡¼¤Ë¥¹¥Æ¡¼¥¿¥¹¥Ð¡¼¤ò + Äɲᣠ+ +2004-02-10 + + * src/inc.[ch]: Ã༡¹¹¿·¤Ë¥Ï¥Ã¥·¥å¥Æ¡¼¥Ö¥ë¤ò»ÈÍÑ¡£ + ¹¹¿·´Ö³Ö¤ò2ÉäËÊѹ¹¡£ + * src/folder.[ch] + src/mh.c + src/procmsg.c + src/summaryview.c: ¥Õ¥©¥ë¥À¤Î¥á¥Ã¥»¡¼¥¸¿ô¤Î½¸·×¤òÊäÀµ¤¹¤ë¤¿¤á¤Ë + FolderItem::unmarked_num ¤òÄɲᣠ+ +2004-02-09 + + * src/inc.[ch]: ¥Õ¥©¥ë¥À¥Ó¥å¡¼¤òÃ༡¹¹¿·¤¹¤ë¤è¤¦¤Ë¤·¤¿¡£ + * src/foldersel.c: ÁªÂò¹àÌܤδ°Á´¤Ê ID ¤òɽ¼¨¡£ + +2004-02-06 + + * src/folderview.[ch]: ¥³¡¼¥É¤ÎÀ°Íý¡£ + folderview_append_item(): ¿·µ¬¡£¥Õ¥©¥ë¥À¤ò¥Õ¥©¥ë¥À¥Ó¥å¡¼¤ËÄɲ乤롣 + * src/foldersel.c: foldersel_new_folder(): folderview_append_item() + ¤ò»ÈÍÑ¡£ + +2004-02-06 + + * src/foldersel.c: ¡Ö¿·µ¬¥Õ¥©¥ë¥À¤òºîÀ®¡×µ¡Ç½¤ò¼ÂÁõ¡£ + * src/folder.[ch]: folder_find_child_item_by_name(): ¿·µ¬¡£ + * src/utils.h: AUTORELEASE_STR(): malloc ʸ»úÎó¤ò¼«Æ°³«Êü(alloca) + ʸ»úÎó¤ËÊÑ´¹¡£ + +2004-02-05 + + * src/folderview.c: folderview_new_imap_folder_cb() ¤ò + folderview_new_folder_cb() ¤Ë¤Þ¤È¤á¤¿¡£ + +2004-02-04 + + * src/compose.c: compose_write_to_file(): ̵ÂÌ¤Ê strlen() ¤ò½üµî + (Alfons ¤µ¤ó thanks)¡£ + * src/textview.c: textview_button_pressed(): ¥¢¥É¥ì¥¹¤ò¥¯¥ê¥Ã¥¯¤·¤¿ + ¤È¤­Àµ¤·¤¤¥¢¥«¥¦¥ó¥È¤òÁªÂò¤¹¤ë¤è¤¦¤Ë¤·¤¿¡£ + 2004-01-29 * version 0.9.9 diff --git a/configure.ac b/configure.ac index 04c1de5de..7dd859d7f 100644 --- a/configure.ac +++ b/configure.ac @@ -8,10 +8,10 @@ PACKAGE=sylpheed dnl version number MAJOR_VERSION=0 MINOR_VERSION=9 -MICRO_VERSION=9 +MICRO_VERSION=10 INTERFACE_AGE=0 BINARY_AGE=0 -EXTRA_VERSION=1 +EXTRA_VERSION=57 if test $EXTRA_VERSION -eq 0; then VERSION=${MAJOR_VERSION}.${MINOR_VERSION}.${MICRO_VERSION}claws else diff --git a/intl/.cvsignore b/intl/.cvsignore index 3b6496f88..70845e08e 100644 --- a/intl/.cvsignore +++ b/intl/.cvsignore @@ -1,2 +1 @@ -Makefile -po2tbl.sed +Makefile.in diff --git a/po/.cvsignore b/po/.cvsignore index ca5ebc2cf..32b7c043d 100644 --- a/po/.cvsignore +++ b/po/.cvsignore @@ -1,6 +1,16 @@ -POTFILES -Makefile.in Makefile +Makefile.in +Makefile.in.in +Makevars.template +POTFILES +Rules-quot +boldquot.sed +en@boldquot.header +en@quot.header +insert-header.sin +quot.sed +remove-potcdate.sed +remove-potcdate.sin sylpheed.pot -cat-id-tbl.c +*.po~ *.gmo diff --git a/po/POTFILES.in b/po/POTFILES.in index 6afa358f7..919d5eca5 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -38,6 +38,7 @@ src/gtk/colorlabel.c src/gtk/description_window.c src/gtk/gtkaspell.c src/gtk/gtkutils.c +src/gtk/inputdialog.c src/gtk/logwindow.c src/gtk/pluginwindow.c src/gtk/prefswindow.c @@ -50,7 +51,6 @@ src/importldif.c src/importmutt.c src/importpine.c src/inc.c -src/inputdialog.c src/ldif.c src/main.c src/mainwindow.c diff --git a/src/Makefile.am b/src/Makefile.am index 10f9b9190..f6ac02819 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -61,12 +61,12 @@ sylpheed_SOURCES = \ headerview.c \ html.c \ imap.c \ + imap_gtk.c \ import.c \ importldif.c \ importmutt.c \ importpine.c \ inc.c \ - inputdialog.c \ jpilot.c \ ldapctrl.c \ ldaplocate.c \ @@ -85,10 +85,12 @@ sylpheed_SOURCES = \ message_search.c \ messageview.c \ mh.c \ + mh_gtk.c \ mimeview.c \ msgcache.c \ mutt.c \ news.c \ + news_gtk.c \ noticeview.c \ passphrase.c \ pgpmime.c \ @@ -187,12 +189,12 @@ sylpheedinclude_HEADERS = \ headerview.h \ html.h \ imap.h \ + imap_gtk.h \ import.h \ importldif.h \ importmutt.h \ importpine.h \ inc.h \ - inputdialog.h \ jpilot.h \ ldapctrl.h \ ldaplocate.h \ @@ -212,10 +214,12 @@ sylpheedinclude_HEADERS = \ message_search.h \ messageview.h \ mh.h \ + mh_gtk.h \ mimeview.h \ msgcache.h \ mutt.h \ news.h \ + news_gtk.h \ noticeview.h \ passphrase.h \ pgpmime.h \ @@ -304,6 +308,7 @@ EXTRA_DIST = \ pixmaps/key.xpm \ pixmaps/ldap.xpm \ pixmaps/linewrap.xpm \ + pixmaps/linewrapcurrent.xpm \ pixmaps/locked.xpm \ pixmaps/mail_attach.xpm \ pixmaps/mail_compose.xpm \ diff --git a/src/addr_compl.c b/src/addr_compl.c index ff14740eb..4a41bfadb 100644 --- a/src/addr_compl.c +++ b/src/addr_compl.c @@ -179,7 +179,8 @@ static void add_address1(const char *str, address_entry *ae) * \return 0 if entry appended successfully, or -1 * if failure. */ -static gint add_address(const gchar *name, const gchar *address, const gchar *alias) +static gint add_address(const gchar *name, const gchar *address, + const gchar *nick, const gchar *alias) { address_entry *ae; @@ -196,7 +197,13 @@ static gint add_address(const gchar *name, const gchar *address, const gchar *al add_address1(name, ae); add_address1(address, ae); - add_address1(alias, ae); + + if (nick != NULL) + add_address1(nick, ae); + + if ( alias != NULL ) { + add_address1(alias, ae); + } return 0; } @@ -1073,8 +1080,21 @@ static gboolean address_completion_complete_address_in_entry(GtkEntry *entry, g_free( new ); } + /* Select the address if there is only one match */ + if (ncount == 2) { + /* Display selected address in entry field */ + gchar *addr = get_complete_address(1); + + if (addr) { + replace_address_in_edit(entry, addr, cursor_pos); + g_free(addr); + } + + /* Discard the window */ + clear_completion_cache(); + } /* Make sure that drop-down appears uniform! */ - if( ncount == 0 ) { + else if( ncount == 0 ) { addrcompl_add_queue( g_strdup( searchTerm ) ); } g_free( searchTerm ); diff --git a/src/addressbook.c b/src/addressbook.c index 2c6405286..619024cd4 100644 --- a/src/addressbook.c +++ b/src/addressbook.c @@ -176,6 +176,10 @@ static void addressbook_tree_selected (GtkCTree *ctree, GtkCTreeNode *node, gint column, gpointer data); +static void addressbook_select_row_tree (GtkCTree *ctree, + GtkCTreeNode *node, + gint column, + gpointer data); static void addressbook_list_selected (GtkCList *clist, gint row, gint column, @@ -354,9 +358,9 @@ static void addressbook_treenode_cut_cb ( void ); static void addressbook_treenode_copy_cb ( void ); static void addressbook_treenode_paste_cb ( void ); -#ifdef USE_LDAP +static void addressbook_mail_to_cb ( void ); + static void addressbook_browse_entry_cb ( void ); -#endif static GtkItemFactoryEntry addressbook_entries[] = { @@ -388,6 +392,8 @@ static GtkItemFactoryEntry addressbook_entries[] = {N_("/_Address/---"), NULL, NULL, 0, ""}, {N_("/_Address/_Edit"), "Return", addressbook_edit_address_cb, 0, NULL}, {N_("/_Address/_Delete"), NULL, addressbook_delete_address_cb, 0, NULL}, + {N_("/_Address/---"), NULL, NULL, 0, ""}, + {N_("/_Address/_Mail To"), NULL, addressbook_mail_to_cb, 0, NULL}, {N_("/_Tools/---"), NULL, NULL, 0, ""}, {N_("/_Tools/Import _LDIF file..."), NULL, addressbook_import_ldif_cb, 0, NULL}, {N_("/_Tools/Import M_utt file..."), NULL, addressbook_import_mutt_cb, 0, NULL}, @@ -401,13 +407,13 @@ static GtkItemFactoryEntry addressbook_entries[] = static GtkItemFactoryEntry addressbook_tree_popup_entries[] = { - {N_("/New _Address"), NULL, addressbook_new_address_cb, 0, NULL}, - {N_("/New _Group"), NULL, addressbook_new_group_cb, 0, NULL}, - {N_("/New _Folder"), NULL, addressbook_new_folder_cb, 0, NULL}, - {N_("/---"), NULL, NULL, 0, ""}, {N_("/_Edit"), NULL, addressbook_treenode_edit_cb, 0, NULL}, {N_("/_Delete"), NULL, addressbook_treenode_delete_cb, 0, NULL}, {N_("/---"), NULL, NULL, 0, ""}, + {N_("/New _Address"), NULL, addressbook_new_address_cb, 0, NULL}, + {N_("/New _Group"), NULL, addressbook_new_group_cb, 0, NULL}, + {N_("/New _Folder"), NULL, addressbook_new_folder_cb, 0, NULL}, + {N_("/---"), NULL, NULL, 0, ""}, {N_("/C_ut"), NULL, addressbook_treenode_cut_cb, 0, NULL}, {N_("/_Copy"), NULL, addressbook_treenode_copy_cb, 0, NULL}, {N_("/_Paste"), NULL, addressbook_treenode_paste_cb, 0, NULL} @@ -415,22 +421,22 @@ static GtkItemFactoryEntry addressbook_tree_popup_entries[] = static GtkItemFactoryEntry addressbook_list_popup_entries[] = { + {N_("/_Edit"), NULL, addressbook_edit_address_cb, 0, NULL}, + {N_("/_Delete"), NULL, addressbook_delete_address_cb, 0, NULL}, + {N_("/---"), NULL, NULL, 0, ""}, {N_("/New _Address"), NULL, addressbook_new_address_cb, 0, NULL}, {N_("/New _Group"), NULL, addressbook_new_group_cb, 0, NULL}, {N_("/New _Folder"), NULL, addressbook_new_folder_cb, 0, NULL}, {N_("/---"), NULL, NULL, 0, ""}, - {N_("/_Edit"), NULL, addressbook_edit_address_cb, 0, NULL}, - {N_("/_Delete"), NULL, addressbook_delete_address_cb, 0, NULL}, - {N_("/---"), NULL, NULL, 0, ""}, {N_("/C_ut"), NULL, addressbook_clip_cut_cb, 0, NULL}, {N_("/_Copy"), NULL, addressbook_clip_copy_cb, 0, NULL}, {N_("/_Paste"), NULL, addressbook_clip_paste_cb, 0, NULL}, {N_("/---"), NULL, NULL, 0, ""}, -#ifdef USE_LDAP {N_("/Pa_ste Address"), NULL, addressbook_clip_paste_address_cb, 0, NULL}, + {N_("/_Mail To"), NULL, addressbook_mail_to_cb, 0, NULL} +#ifdef USE_LDAP + , {N_("/_Browse Entry"), NULL, addressbook_browse_entry_cb, 0, NULL} -#else - {N_("/Pa_ste Address"), NULL, addressbook_clip_paste_address_cb, 0, NULL} #endif }; @@ -478,6 +484,7 @@ static ErrMsgTableEntry _lutErrorsLDAP_[] = { { LDAPRC_CRITERIA, N_("Error in LDAP search criteria") }, { LDAPRC_NOENTRIES, N_("No LDAP entries found for search criteria") }, { LDAPRC_STOP_FLAG, N_("LDAP search terminated on request") }, + { LDAPRC_TLS, N_("Error starting TLS connection") }, { 0, NULL } }; #endif @@ -689,6 +696,9 @@ static void addressbook_create(void) g_signal_connect(G_OBJECT(ctree), "button_release_event", G_CALLBACK(addressbook_tree_button_released), NULL); + /* TEMPORARY */ + g_signal_connect(G_OBJECT(ctree), "select_row", + G_CALLBACK(addressbook_select_row_tree), NULL); clist_vbox = gtk_vbox_new(FALSE, 4); @@ -1166,8 +1176,7 @@ static void addressbook_to_clicked(GtkButton *button, gpointer data) Compose *compose; AddrSelectItem *item; AddrItemObject *aio; - const gchar *addr; - gchar *tmpaddr; + gchar *addr; compose = addrbook.target_compose; if( ! compose ) return; @@ -1188,10 +1197,10 @@ static void addressbook_to_clicked(GtkButton *button, gpointer data) aio = item->addressItem; if( aio->type == ADDR_ITEM_PERSON || aio->type == ADDR_ITEM_EMAIL ) { - tmpaddr = addressbook_format_address( aio ); + addr = addressbook_format_address( aio ); compose_entry_append( - compose, tmpaddr, (ComposeEntryType) data ); - g_free( tmpaddr ); + compose, addr, (ComposeEntryType) data ); + g_free( addr ); } else if( aio->type == ADDR_ITEM_GROUP ) { ItemGroup *group = ( ItemGroup * ) aio; @@ -1199,11 +1208,11 @@ static void addressbook_to_clicked(GtkButton *button, gpointer data) while( nodeMail ) { ItemEMail *email = nodeMail->data; - tmpaddr = addressbook_format_address( + addr = addressbook_format_address( ( AddrItemObject * ) email ); compose_entry_append( - compose, tmpaddr, (ComposeEntryType) data ); - g_free( tmpaddr ); + compose, addr, (ComposeEntryType) data ); + g_free( addr ); nodeMail = g_list_next( nodeMail ); } } @@ -1223,6 +1232,7 @@ static void addressbook_menubar_set_sensitive( gboolean sensitive ) { menu_set_sensitive( addrbook.menu_factory, "/Address/New Address", sensitive ); menu_set_sensitive( addrbook.menu_factory, "/Address/New Group", sensitive ); menu_set_sensitive( addrbook.menu_factory, "/Address/New Folder", sensitive ); + menu_set_sensitive( addrbook.menu_factory, "/Address/Mail To", sensitive ); gtk_widget_set_sensitive( addrbook.reg_btn, sensitive ); gtk_widget_set_sensitive( addrbook.del_btn, sensitive ); } @@ -1454,8 +1464,11 @@ static void addressbook_list_menu_setup( void ) { canDelete = canEdit; - /* Disable edit if more than one row selected */ - if( GTK_CLIST(clist)->selection && GTK_CLIST(clist)->selection->next ) canEdit = FALSE; + /* Disable edit or browse if more than one row selected */ + if( GTK_CLIST(clist)->selection && GTK_CLIST(clist)->selection->next ) { + canEdit = FALSE; + canBrowse = FALSE; + } /* Now go finalize menu items */ menu_set_sensitive( addrbook.list_factory, "/Edit", canEdit ); @@ -1466,22 +1479,25 @@ static void addressbook_list_menu_setup( void ) { menu_set_sensitive( addrbook.list_factory, "/Paste", canPaste ); menu_set_sensitive( addrbook.list_factory, "/Paste Address", canPaste ); + menu_set_sensitive( addrbook.list_factory, "/Mail To", canCopy ); + menu_set_sensitive( addrbook.menu_factory, "/Edit/Cut", canCut ); menu_set_sensitive( addrbook.menu_factory, "/Edit/Copy", canCopy ); menu_set_sensitive( addrbook.menu_factory, "/Edit/Paste", canPaste ); menu_set_sensitive( addrbook.menu_factory, "/Edit/Paste Address", canPaste ); - menu_set_sensitive( addrbook.tree_factory, "/Cut", canCut ); - menu_set_sensitive( addrbook.tree_factory, "/Copy", canCopy ); - menu_set_sensitive( addrbook.tree_factory, "/Paste", canPaste ); + menu_set_sensitive( addrbook.tree_factory, "/Cut", canCut ); + menu_set_sensitive( addrbook.tree_factory, "/Copy", canCopy ); + menu_set_sensitive( addrbook.tree_factory, "/Paste", canPaste ); - menu_set_sensitive( addrbook.menu_factory, "/Address/Edit", canEdit ); - menu_set_sensitive( addrbook.menu_factory, "/Address/Delete", canDelete ); + menu_set_sensitive( addrbook.menu_factory, "/Address/Edit", canEdit ); + menu_set_sensitive( addrbook.menu_factory, "/Address/Delete", canDelete ); + menu_set_sensitive( addrbook.menu_factory, "/Address/Mail To", canCopy ); gtk_widget_set_sensitive( addrbook.del_btn, canDelete ); #ifdef USE_LDAP - menu_set_sensitive( addrbook.list_factory, "/Browse Entry", canBrowse ); + menu_set_sensitive( addrbook.list_factory, "/Browse Entry", canBrowse ); #endif } @@ -1492,12 +1508,19 @@ static void addressbook_list_selected(GtkCList *clist, gint row, gint column, /* Handle double click */ if (prefs_common.add_address_by_click && addrbook.target_compose) - addressbook_to_clicked(NULL, NULL); + addressbook_to_clicked(NULL, GINT_TO_POINTER(COMPOSE_TO)); else addressbook_edit_address_cb(NULL, 0, NULL); } } +static void addressbook_select_row_tree (GtkCTree *ctree, + GtkCTreeNode *node, + gint column, + gpointer data) +{ +} + /** * Add list of items into tree node below specified tree node. * \param treeNode Tree node. @@ -1772,6 +1795,11 @@ static void addressbook_list_select_clear( void ) { addrselect_list_clear( _addressSelect_ ); } +/** + * Add specified address item to selected address list. + * \param aio Address item object. + * \param ds Datasource. + */ static void addressbook_list_select_add( AddrItemObject *aio, AddressDataSource *ds ) { gchar *cacheID; @@ -1781,10 +1809,28 @@ static void addressbook_list_select_add( AddrItemObject *aio, AddressDataSource g_free( cacheID ); } +/** + * Remove specified address item from selected address list. + * \param aio Address item object. + */ static void addressbook_list_select_remove( AddrItemObject *aio ) { addrselect_list_remove( _addressSelect_, aio ); } +/** + * Invoke EMail compose window with addresses in selected address list. + */ +static void addressbook_mail_to_cb( void ) { + GList *listAddress; + + if( ! addrselect_test_empty( _addressSelect_ ) ) { + listAddress = addrselect_build_list( _addressSelect_ ); + compose_new_with_list( NULL, listAddress ); + mgu_free_dlist( listAddress ); + listAddress = NULL; + } +} + static void addressbook_list_row_selected( GtkCTree *clist, GtkCTreeNode *node, gint column, @@ -2322,7 +2368,14 @@ static void addressbook_treenode_delete_cb( AdapterFolder *adapter = ADAPTER_FOLDER(obj); ItemFolder *folder = adapter->itemFolder; + adapter->itemFolder = NULL; + /* + printf( "remove folder for ::%s::\n", obj->name ); + printf( " folder name ::%s::\n", ADDRITEM_NAME(folder) ); + printf( "-------------- remove results\n" ); + */ addrindex_remove_results( ds, folder ); + /* printf( "-------------- remove node\n" ); */ gtk_ctree_remove_node( ctree, node ); return; } @@ -3537,6 +3590,23 @@ static void addressbook_search_idle( gpointer data ) { */ } +/** + * Search completion callback function. This removes the query from the idle + * list. + * + * \param queryID Query ID of search request. + */ +void addressbook_clear_idler( gint queryID ) { + gpointer ptrQID; + + /* Remove idler function */ + /* printf( "addressbook_clear_idler::%d::\n", queryID ); */ + ptrQID = GINT_TO_POINTER( queryID ); + if( ptrQID ) { + gtk_idle_remove_by_data( ptrQID ); + } +} + /** * Search completion callback function. This removes the query from the idle * list. @@ -3687,6 +3757,7 @@ static void addressbook_lup_clicked( GtkButton *button, gpointer data ) { parentNode = node; } addressbook_perform_search( ds, searchTerm, parentNode ); + gtk_widget_grab_focus( addrbook.entry ); g_free( searchTerm ); } @@ -3694,7 +3765,6 @@ static void addressbook_lup_clicked( GtkButton *button, gpointer data ) { /** * Browse address entry for highlighted entry. */ -#ifdef USE_LDAP static void addressbook_browse_entry_cb(void) { GtkCTree *clist = GTK_CTREE(addrbook.clist); @@ -3706,19 +3776,19 @@ static void addressbook_browse_entry_cb(void) if(addrbook.listSelected == NULL) return; - + obj = gtk_ctree_node_get_row_data(clist, addrbook.listSelected); if (obj == NULL) return; - + ds = addressbook_find_datasource(GTK_CTREE_NODE(addrbook.treeSelected)); if(ds == NULL) return; - + iface = ds->interface; - if(iface->haveLibrary == NULL) + if(! iface->haveLibrary ) return; - + person = NULL; if (obj->type == ADDR_ITEM_EMAIL) { email = ( ItemEMail * ) obj; @@ -3741,7 +3811,6 @@ static void addressbook_browse_entry_cb(void) #endif } } -#endif /* ********************************************************************** diff --git a/src/addrindex.c b/src/addrindex.c index 6527fc2da..76f029361 100644 --- a/src/addrindex.c +++ b/src/addrindex.c @@ -1,6 +1,6 @@ /* * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 2001-2003 Match Grun + * Copyright (C) 2001-2004 Match Grun * * 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 @@ -95,6 +95,7 @@ #define ATTAG_LDAP_MAX_AGE "max-age" #define ATTAG_LDAP_DYN_SEARCH "dyn-search" #define ATTAG_LDAP_MATCH_OPT "match-opt" +#define ATTAG_LDAP_ENABLE_TLS "enable-tls" #define ELTAG_LDAP_ATTR_SRCH "attribute" #define ATTAG_LDAP_ATTR_NAME "name" @@ -1349,11 +1350,13 @@ static AddressDataSource *addrindex_parse_ldap( XMLFile *file ) { gchar *serverName = NULL; gchar *criteria = NULL; gboolean bDynSearch; + gboolean bTLS; gint iMatch; /* printf( "addrindex_parse_ldap\n" ); */ /* Set up some defaults */ bDynSearch = FALSE; + bTLS = FALSE; iMatch = LDAPCTL_MATCH_BEGINWITH; ds = addrindex_create_datasource( ADDR_IF_LDAP ); @@ -1408,6 +1411,12 @@ static AddressDataSource *addrindex_parse_ldap( XMLFile *file ) { iMatch = LDAPCTL_MATCH_CONTAINS; } } + else if( strcmp( name, ATTAG_LDAP_ENABLE_TLS ) == 0 ) { + bTLS = FALSE; + if( strcmp( value, ATVAL_BOOLEAN_YES ) == 0 ) { + bTLS = TRUE; + } + } attr = g_list_next( attr ); } @@ -1415,6 +1424,7 @@ static AddressDataSource *addrindex_parse_ldap( XMLFile *file ) { ldapsvr_set_name( server, serverName ); ldapsvr_set_search_flag( server, bDynSearch ); ldapctl_set_matching_option( ctl, iMatch ); + ldapctl_set_tls( ctl, bTLS ); g_free( serverName ); ldapsvr_set_control( server, ctl ); ds->rawDataSource = server; @@ -1474,6 +1484,10 @@ static void addrindex_write_ldap( FILE *fp, AddressDataSource *ds, gint lvl ) { ( ctl->matchingOption == LDAPCTL_MATCH_CONTAINS ) ? ATVAL_LDAP_MATCH_CONTAINS : ATVAL_LDAP_MATCH_BEGIN ); + addrindex_write_attr( fp, ATTAG_LDAP_ENABLE_TLS, + ctl->enableTLS ? + ATVAL_BOOLEAN_YES : ATVAL_BOOLEAN_NO ); + fputs(" >\n", fp); /* Output attributes */ @@ -1487,7 +1501,6 @@ static void addrindex_write_ldap( FILE *fp, AddressDataSource *ds, gint lvl ) { /* End of element */ addrindex_write_elem_e( fp, lvl, TAG_DS_LDAP ); - } #else @@ -2737,8 +2750,11 @@ void addrindex_remove_results( AddressDataSource *ds, ItemFolder *folder ) { AddressCache *cache; gint queryID = 0; + /* printf( "addrindex_remove_results/start\n" ); */ + /* Test for folder */ if( folder->folderType != ADDRFOLDER_QUERY_RESULTS ) return; + /* printf( "folder name ::%s::\n", ADDRITEM_NAME(folder) ); */ adbase = ( AddrBookBase * ) ds->rawDataSource; if( adbase == NULL ) return; cache = adbase->addressCache; @@ -2748,13 +2764,26 @@ void addrindex_remove_results( AddressDataSource *ds, ItemFolder *folder ) { if( ds->type == ADDR_IF_LDAP ) { #ifdef USE_LDAP - LdapQuery *qry; + LdapQuery *qry; + gboolean delFlag; qry = ( LdapQuery * ) folder->folderData; queryID = ADDRQUERY_ID(qry); - ldapquery_remove_results( qry ); + /* printf( "calling ldapquery_remove_results...queryID=%d\n", queryID ); */ + delFlag = ldapquery_remove_results( qry ); + /* printf( "calling ldapquery_remove_results...done\n" ); */ + /* + if( delFlag ) { + printf( "delFlag IS-TRUE\n" ); + } + else { + printf( "delFlag IS-FALSE\n" ); + addressbook_clear_idler( queryID ); + } + */ #endif } + /* printf( "addrindex_remove_results/end\n" ); */ /* Delete query request */ if( queryID > 0 ) { @@ -2776,13 +2805,14 @@ void addrindex_remove_results( AddressDataSource *ds, ItemFolder *folder ) { * \return TRUE if data loaded, FALSE if address index not loaded. */ gboolean addrindex_load_completion( - gint (*callBackFunc) ( const gchar *, const gchar *, const gchar * ) ) + gint (*callBackFunc) ( const gchar *, const gchar *, + const gchar *, const gchar * ) ) { AddressDataSource *ds; GList *nodeIf, *nodeDS; GList *listP, *nodeP; GList *nodeM; - gchar *sName, *sAddress, *sAlias, *sFriendly; + gchar *sName; nodeIf = addrindex_get_interface_list( _addressIndex_ ); while( nodeIf ) { @@ -2816,25 +2846,18 @@ gboolean addrindex_load_completion( nodeM = person->listEMail; /* Figure out name to use */ - sName = person->nickName; + sName = ADDRITEM_NAME(person); if( sName == NULL || *sName == '\0' ) { - sName = ADDRITEM_NAME(person); + sName = person->nickName; } /* Process each E-Mail address */ while( nodeM ) { ItemEMail *email = nodeM->data; - /* Have mail */ - sFriendly = sName; - sAddress = email->address; - if( sAddress || *sAddress != '\0' ) { - sAlias = ADDRITEM_NAME(email); - if( sAlias && *sAlias != '\0' ) { - sFriendly = sAlias; - } - ( callBackFunc ) ( sFriendly, sAddress, sName ); - } - + + callBackFunc( sName, email->address, person->nickName, + ADDRITEM_NAME(email) ); + nodeM = g_list_next( nodeM ); } nodeP = g_list_next( nodeP ); diff --git a/src/addrindex.h b/src/addrindex.h index 94789c595..d58d42f24 100644 --- a/src/addrindex.h +++ b/src/addrindex.h @@ -175,10 +175,8 @@ void addrindex_remove_results ( AddressDataSource *ds, gboolean addrindex_load_completion( gint (*callBackFunc) - ( const gchar *, const gchar *, const gchar * ) ); -gint addrindex_setup_explicit_search( - AddressDataSource *ds, const gchar *searchTerm, ItemFolder *folder, - void *callBackEnd, void *callBackEntry ); + ( const gchar *, const gchar *, + const gchar *, const gchar * ) ); #endif /* __ADDRINDEX_H__ */ diff --git a/src/addrselect.c b/src/addrselect.c index 319acdccb..49ab23d2e 100644 --- a/src/addrselect.c +++ b/src/addrselect.c @@ -28,10 +28,11 @@ #include "addressitem.h" #include "mgutils.h" -/* -* Create a selection record from an address cache item. -* Enter: aio Item object. -*/ +/** + * Create a selection record from an address cache item. + * \param aio Item object. + * \return Address select item. + */ AddrSelectItem *addrselect_create_item( AddrItemObject *aio ) { AddrSelectItem *item = NULL; @@ -45,10 +46,11 @@ AddrSelectItem *addrselect_create_item( AddrItemObject *aio ) { return item; } -/* -* Create a selection record from an address object (in tree node). -* Enter: obj Address object. -*/ +/** + * Create a selection record from an address object (in tree node). + * \param obj Address object. + * \return Address select item. + */ AddrSelectItem *addrselect_create_node( AddressObject *obj ) { AddrSelectItem *item = NULL; @@ -62,10 +64,11 @@ AddrSelectItem *addrselect_create_node( AddressObject *obj ) { return item; } -/* -* Create a copy of a selection record. -* Enter: item Address entry to copy. -*/ +/** + * Create a copy of a selection record. + * Enter: item Address entry to copy. + * \return Address select item. + */ AddrSelectItem *addrselect_item_copy( AddrSelectItem *item ) { AddrSelectItem *copy = NULL; @@ -79,9 +82,10 @@ AddrSelectItem *addrselect_item_copy( AddrSelectItem *item ) { return copy; } -/* -* Free selection record. -*/ +/** + * Free selection record. + * \return Address select item. + */ void addrselect_item_free( AddrSelectItem *item ) { if( item ) { g_free( item->uid ); @@ -94,14 +98,21 @@ void addrselect_item_free( AddrSelectItem *item ) { g_free( item ); } -/* -* Properties. -*/ +/** + * Specify cache ID for specified item. + * \param item Address select item. + * \param value Cache ID. + */ void addrselect_set_cache_id( AddrSelectItem *item, const gchar *value ) { g_return_if_fail( item != NULL ); item->cacheID = mgu_replace_string( item->cacheID, value ); } +/** + * Print address selection item. + * \param item Address select item. + * \param stream Output stream. + */ void addrselect_item_print( AddrSelectItem *item, FILE *stream ) { fprintf( stream, "Select Record\n" ); fprintf( stream, "obj type: %d\n", item->objectType ); @@ -110,10 +121,10 @@ void addrselect_item_print( AddrSelectItem *item, FILE *stream ) { fprintf( stream, "---\n" ); } -/* -* Create a new selection. -* Return: Initialized object. -*/ +/** + * Create a new address selection object. + * \return Initialized object. + */ AddrSelectList *addrselect_list_create() { AddrSelectList *asl; @@ -122,10 +133,10 @@ AddrSelectList *addrselect_list_create() { return asl; } -/* -* Clear list of selection records. -* Enter: asl List to process. -*/ +/** + * Clear list of selection records. + * \param asl List to process. + */ void addrselect_list_clear( AddrSelectList *asl ) { GList *node; @@ -143,10 +154,10 @@ void addrselect_list_clear( AddrSelectList *asl ) { asl->listSelect = NULL; } -/* -* Free selection list. -* Enter: asl List to free. -*/ +/** + * Free selection list. + * \param asl List to free. + */ void addrselect_list_free( AddrSelectList *asl ) { g_return_if_fail( asl != NULL ); @@ -156,22 +167,23 @@ void addrselect_list_free( AddrSelectList *asl ) { g_free( asl ); } -/* -* Test whether selection is empty. -* Enter: asl List to test. -* Return: TRUE if list is empty. -*/ +/** + * Test whether selection is empty. + * \param asl List to test. + * \return TRUE if list is empty. + */ gboolean addrselect_test_empty( AddrSelectList *asl ) { g_return_val_if_fail( asl != NULL, TRUE ); return ( asl->listSelect == NULL ); } -/* -* Return list of AddrSelectItem objects. -* Enter: asl List to process. -* Return: List of selection items. The list should should be g_list_free() -* when done. Items contained in the list should not be freed!!! -*/ +/** + * Return list of AddrSelectItem objects. + * \param asl List to process. + * \return List of selection items. The list should should be freed with + * g_list_free() when done. Items contained in the + * list should not be freed!!! + */ GList *addrselect_get_list( AddrSelectList *asl ) { GList *node, *list; @@ -185,6 +197,11 @@ GList *addrselect_get_list( AddrSelectList *asl ) { return list; } +/** + * Format address item. + * \param aio Item. + * \return Formatted address. + */ static gchar *addrselect_format_address( AddrItemObject * aio ) { gchar *buf = NULL; gchar *name = NULL; @@ -232,11 +249,11 @@ static gchar *addrselect_format_address( AddrItemObject * aio ) { return buf; } -/* -* Print formatted addresses list to specified stream. -* Enter: asl List to process. -* stream Stream. -*/ +/** + * Print formatted addresses list to specified stream. + * \param asl List to process. + * \param stream Stream. + */ void addrselect_list_print( AddrSelectList *asl, FILE *stream ) { GList *node; @@ -282,11 +299,11 @@ void addrselect_list_print( AddrSelectList *asl, FILE *stream ) { fprintf( stream, "show selection...<<<\n" ); } -/* -* Print address items to specified stream. -* Enter: asl List to process. -* stream Stream. -*/ +/** + * Print address items to specified stream. + * \param asl List to process. + * \param stream Stream. + */ void addrselect_list_show( AddrSelectList *asl, FILE *stream ) { GList *node; @@ -303,12 +320,12 @@ void addrselect_list_show( AddrSelectList *asl, FILE *stream ) { fprintf( stream, "show selection...<<<\n" ); } -/* -* Test whether specified object is in list. -* Enter: list List to check. -* aio Object to test. -* Return item found, or NULL if not in list. -*/ +/** + * Test whether specified object is in list. + * \param list List to check. + * \param aio Object to test. + * \param item found, or NULL if not in list. + */ static AddrSelectItem *addrselect_list_find( GList *list, AddrItemObject *aio ) { GList *node; @@ -323,13 +340,12 @@ static AddrSelectItem *addrselect_list_find( GList *list, AddrItemObject *aio ) return NULL; } -/* -* Add a single object into the list. -* Enter: asl Address selection object. -* obj Address object. -* cacheID Cache ID. Should be g_free() after calling function. -* Return: Adjusted list. -*/ +/** + * Add a single object into the list. + * \param asl Address selection object. + * \param aio Address object. + * \param cacheID Cache ID. Should be freed after calling function. + */ void addrselect_list_add_obj( AddrSelectList *asl, AddrItemObject *aio, gchar *cacheID ) { AddrSelectItem *item; @@ -349,13 +365,12 @@ void addrselect_list_add_obj( AddrSelectList *asl, AddrItemObject *aio, gchar *c /* addrselect_list_show( asl, stdout ); */ } -/* -* Add a single item into the list. -* Enter: asl Address selection object. -* item Address select item. -* cacheID Cache ID. Should be g_free() after calling function. -* Return: Adjusted list. -*/ +/** + * Add a single item into the list. + * \param asl Address selection object. + * \param item Address select item. + * \param cacheID Cache ID. Should be g_free() after calling function. + */ void addrselect_list_add( AddrSelectList *asl, AddrSelectItem *item, gchar *cacheID ) { g_return_if_fail( asl != NULL ); if( item == NULL ) return; @@ -367,11 +382,11 @@ void addrselect_list_add( AddrSelectList *asl, AddrSelectItem *item, gchar *cach asl->listSelect = g_list_append( asl->listSelect, item ); } -/* -* Remove specified object from list. -* Enter: asl Address selection object. -* aio Object to remove. -*/ +/** + * Remove specified object from list. + * \param asl Address selection object. + * \param aio Object to remove. + */ void addrselect_list_remove( AddrSelectList *asl, AddrItemObject *aio ) { GList *node; AddrSelectItem *item; @@ -392,6 +407,52 @@ void addrselect_list_remove( AddrSelectList *asl, AddrItemObject *aio ) { /* addrselect_list_show( list, stdout ); */ } +/** + * Build list of formatted addresses. + * \param asl List to process. + * \return List of addresses, formatted as character strings. List should be + * freed when no longer required. + */ +GList *addrselect_build_list( AddrSelectList *asl ) { + GList *list; + GList *node; + + g_return_val_if_fail(asl != NULL, NULL); + list = NULL; + node = asl->listSelect; + while( node != NULL ) { + AddrSelectItem *item; + AddrItemObject *aio; + gchar *addr; + + item = node->data; + aio = ( AddrItemObject * ) item->addressItem; + if( aio ) { + if( aio->type == ADDR_ITEM_GROUP ) { + ItemGroup *group = ( ItemGroup * ) aio; + GList *node = group->listEMail; + while( node ) { + ItemEMail *email = node->data; + addr = addrselect_format_address( + ( AddrItemObject * ) email ); + if( addr ) { + list = g_list_append( list, addr ); + } + node = g_list_next( node ); + } + } + else { + addr = addrselect_format_address( aio ); + if( addr ) { + list = g_list_append( list, addr ); + } + } + } + node = g_list_next( node ); + } + return list; +} + /* * End of Source. */ diff --git a/src/addrselect.h b/src/addrselect.h index 78d7e2b4b..38abe89f8 100644 --- a/src/addrselect.h +++ b/src/addrselect.h @@ -70,6 +70,7 @@ void addrselect_list_show ( AddrSelectList *asl, FILE *stream ); void addrselect_list_print ( AddrSelectList *asl, FILE *stream ); +GList *addrselect_build_list ( AddrSelectList *asl ); #endif /* __ADDR_SELECT_H__ */ diff --git a/src/codeconv.c b/src/codeconv.c index 3d26457c4..fc0702c65 100644 --- a/src/codeconv.c +++ b/src/codeconv.c @@ -869,6 +869,7 @@ CodeConvFunc conv_get_code_conv_func(const gchar *src_charset_str, switch (src_charset) { case C_ISO_2022_JP: case C_ISO_2022_JP_2: + case C_ISO_2022_JP_3: if (dest_charset == C_AUTO && conv_get_current_charset() == C_EUC_JP) code_conv = conv_jistodisp; @@ -909,8 +910,9 @@ CodeConvFunc conv_get_code_conv_func(const gchar *src_charset_str, if (dest_charset == C_AUTO && conv_get_current_charset() == C_EUC_JP) code_conv = conv_euctodisp; - else if (dest_charset == C_ISO_2022_JP || - dest_charset == C_ISO_2022_JP_2) + else if (dest_charset == C_ISO_2022_JP || + dest_charset == C_ISO_2022_JP_2 || + dest_charset == C_ISO_2022_JP_3) code_conv = conv_euctojis; break; default: @@ -1059,6 +1061,7 @@ static const struct { {C_KOI8_U, CS_KOI8_U}, {C_ISO_2022_JP, CS_ISO_2022_JP}, {C_ISO_2022_JP_2, CS_ISO_2022_JP_2}, + {C_ISO_2022_JP_3, CS_ISO_2022_JP_3}, {C_EUC_JP, CS_EUC_JP}, {C_EUC_JP, CS_EUCJP}, {C_SHIFT_JIS, CS_SHIFT_JIS}, @@ -1108,6 +1111,7 @@ static const struct { {"ru_RU" , C_ISO_8859_5 , C_KOI8_R}, {"tg_TJ" , C_KOI8_T , C_KOI8_T}, {"ru_UA" , C_KOI8_U , C_KOI8_U}, + {"uk_UA.CP1251" , C_WINDOWS_1251, C_KOI8_U}, {"uk_UA" , C_KOI8_U , C_KOI8_U}, {"be_BY" , C_WINDOWS_1251, C_WINDOWS_1251}, @@ -1453,6 +1457,7 @@ gboolean conv_is_multibyte_encoding(CharSet encoding) case C_EUC_CN: case C_ISO_2022_JP: case C_ISO_2022_JP_2: + case C_ISO_2022_JP_3: case C_ISO_2022_KR: case C_ISO_2022_CN: case C_SHIFT_JIS: @@ -1488,6 +1493,8 @@ void conv_unmime_header_overwrite(gchar *str) CharSet cur_charset; const gchar *locale; + g_return_if_fail(str != NULL); + cur_charset = conv_get_current_charset(); #warning FIXME_GTK2 diff --git a/src/codeconv.h b/src/codeconv.h index 9bd19d232..1e8387635 100644 --- a/src/codeconv.h +++ b/src/codeconv.h @@ -1,6 +1,6 @@ /* * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2003 Hiroyuki Yamamoto + * Copyright (C) 1999-2004 Hiroyuki Yamamoto * * 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 @@ -72,6 +72,7 @@ typedef enum C_KOI8_U, C_ISO_2022_JP, C_ISO_2022_JP_2, + C_ISO_2022_JP_3, C_EUC_JP, C_SHIFT_JIS, C_ISO_2022_KR, @@ -141,6 +142,7 @@ struct _CodeConverter #define CS_KOI8_U "KOI8-U" #define CS_ISO_2022_JP "ISO-2022-JP" #define CS_ISO_2022_JP_2 "ISO-2022-JP-2" +#define CS_ISO_2022_JP_3 "ISO-2022-JP-3" #define CS_EUC_JP "EUC-JP" #define CS_EUCJP "EUCJP" #define CS_SHIFT_JIS "Shift_JIS" diff --git a/src/common/defs.h b/src/common/defs.h index 922dd4b9d..8a516af60 100644 --- a/src/common/defs.h +++ b/src/common/defs.h @@ -1,6 +1,6 @@ /* * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2003 Hiroyuki Yamamoto + * Copyright (C) 1999-2004 Hiroyuki Yamamoto * * 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 @@ -59,6 +59,7 @@ #define ACTIONS_RC "actionsrc" #define RENDERER_RC "rendererrc" #define COMMAND_HISTORY "command_history" +#define QUICKSEARCH_HISTORY "quicksearch_history" #define TEMPLATE_DIR "templates" #define TMP_DIR "tmp" #define NEWSGROUP_LIST ".newsgroup_list" @@ -112,6 +113,8 @@ #define MAX_ENTRY_LENGTH 8191 #define COLOR_DIM 35000 #define UI_REFRESH_INTERVAL 50000 /* usec */ +#define FOLDER_UPDATE_INTERVAL 1500 /* msec */ +#define PROGRESS_UPDATE_INTERVAL 200 /* msec */ #define SESSION_TIMEOUT 60 /* sec */ #define MAX_HISTORY_SIZE 16 diff --git a/src/common/nntp.c b/src/common/nntp.c index bd0023c46..6bcc83eca 100644 --- a/src/common/nntp.c +++ b/src/common/nntp.c @@ -1,6 +1,6 @@ /* * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2003 Hiroyuki Yamamoto + * Copyright (C) 1999-2004 Hiroyuki Yamamoto * * 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 @@ -41,7 +41,7 @@ static void nntp_session_destroy(Session *session); static gint nntp_ok (SockInfo *sock, gchar *argbuf); -static void nntp_gen_send (SockInfo *sock, +static gint nntp_gen_send (SockInfo *sock, const gchar *format, ...); static gint nntp_gen_recv (SockInfo *sock, @@ -97,8 +97,32 @@ Session *nntp_session_new(const gchar *server, gushort port, gchar *buf, session->group = NULL; if (userid && passwd) { + gint ok; + session->userid = g_strdup(userid); session->passwd = g_strdup(passwd); + + ok = nntp_gen_send(sock, "AUTHINFO USER %s", session->userid); + if (ok != NN_SUCCESS) { + session_destroy(SESSION(session)); + return NULL; + } + ok = nntp_ok(sock, NULL); + if (ok == NN_AUTHCONT) { + ok = nntp_gen_send(sock, "AUTHINFO PASS %s", + session->passwd); + if (ok != NN_SUCCESS) { + session_destroy(SESSION(session)); + return NULL; + } + ok = nntp_ok(sock, NULL); + if (ok != NN_SUCCESS) + session->auth_failed = TRUE; + } + if (ok == NN_SOCKET) { + session_destroy(SESSION(session)); + return NULL; + } } return SESSION(session); @@ -134,7 +158,7 @@ gint nntp_group(NNTPSession *session, const gchar *group, ok = nntp_gen_command(session, buf, "GROUP %s", group); - if (ok != NN_SUCCESS) { + if (ok != NN_SUCCESS && ok != NN_SOCKET && ok != NN_AUTHREQ) { ok = nntp_mode(session, FALSE); if (ok == NN_SUCCESS) ok = nntp_gen_command(session, buf, "GROUP %s", group); @@ -291,9 +315,6 @@ gint nntp_mode(NNTPSession *session, gboolean stream) { gint ok; - if (session->auth_failed) - return NN_AUTHREQ; - ok = nntp_gen_command(session, NULL, "MODE %s", stream ? "STREAM" : "READER"); @@ -327,7 +348,7 @@ static gint nntp_ok(SockInfo *sock, gchar *argbuf) return ok; } -static void nntp_gen_send(SockInfo *sock, const gchar *format, ...) +static gint nntp_gen_send(SockInfo *sock, const gchar *format, ...) { gchar buf[NNTPBUFSIZE]; va_list args; @@ -344,7 +365,12 @@ static void nntp_gen_send(SockInfo *sock, const gchar *format, ...) } strcat(buf, "\r\n"); - sock_write_all(sock, buf, strlen(buf)); + if (sock_write_all(sock, buf, strlen(buf)) < 0) { + log_warning(_("Error occurred while sending command\n")); + return NN_SOCKET; + } + + return NN_SUCCESS; } static gint nntp_gen_recv(SockInfo *sock, gchar *buf, gint size) @@ -373,7 +399,9 @@ static gint nntp_gen_command(NNTPSession *session, gchar *argbuf, va_end(args); sock = SESSION(session)->sock; - nntp_gen_send(sock, "%s", buf); + ok = nntp_gen_send(sock, "%s", buf); + if (ok != NN_SUCCESS) + return ok; ok = nntp_ok(sock, argbuf); if (ok == NN_AUTHREQ) { if (!session->userid || !session->passwd) { @@ -381,11 +409,15 @@ static gint nntp_gen_command(NNTPSession *session, gchar *argbuf, return ok; } - nntp_gen_send(sock, "AUTHINFO USER %s", session->userid); + ok = nntp_gen_send(sock, "AUTHINFO USER %s", session->userid); + if (ok != NN_SUCCESS) + return ok; ok = nntp_ok(sock, NULL); if (ok == NN_AUTHCONT) { - nntp_gen_send(sock, "AUTHINFO PASS %s", - session->passwd); + ok = nntp_gen_send(sock, "AUTHINFO PASS %s", + session->passwd); + if (ok != NN_SUCCESS) + return ok; ok = nntp_ok(sock, NULL); } if (ok != NN_SUCCESS) { @@ -393,18 +425,20 @@ static gint nntp_gen_command(NNTPSession *session, gchar *argbuf, return ok; } - nntp_gen_send(sock, "%s", buf); + ok = nntp_gen_send(sock, "%s", buf); + if (ok != NN_SUCCESS) + return ok; ok = nntp_ok(sock, argbuf); } else if (ok == NN_AUTHCONT) { - nntp_gen_send(sock, "AUTHINFO PASS %s", session->passwd); - ok = nntp_ok(sock, NULL); - - if (ok != NN_SUCCESS) { + ok = nntp_gen_send(sock, "AUTHINFO PASS %s", + session->passwd); + if (ok != NN_SUCCESS) { session->auth_failed = TRUE; - return ok; - } - } + return ok; + } + ok = nntp_ok(sock, NULL); + } return ok; } diff --git a/src/common/ssl.c b/src/common/ssl.c index 23b672acf..a5b102258 100644 --- a/src/common/ssl.c +++ b/src/common/ssl.c @@ -101,8 +101,7 @@ gboolean ssl_init_socket_with_method(SockInfo *sockinfo, SSLMethod method) /* Get the cipher */ - debug_print(_("SSL connection using %s\n"), - SSL_get_cipher(ssl)); + debug_print("SSL connection using %s\n", SSL_get_cipher(ssl)); /* Get server's certificate (note: beware of dynamic allocation) */ if ((server_cert = SSL_get_peer_certificate(ssl)) == NULL) { diff --git a/src/common/utils.c b/src/common/utils.c index aef3c9641..e969b635e 100644 --- a/src/common/utils.c +++ b/src/common/utils.c @@ -3420,6 +3420,7 @@ int subject_get_prefix_length(const gchar *subject) "Fw\\:", /* "Fw:" Forward */ "Enc\\:", /* "Enc:" Forward (Brazilian Outlook) */ "Odp\\:", /* "Odp:" Re (Polish Outlook) */ + "Rif\\:" /* "Rif:" (Italian Outlook) */ /* add more */ }; const int PREFIXES = sizeof prefixes / sizeof prefixes[0]; @@ -3543,14 +3544,15 @@ gchar *expand_search_string(const gchar *search_string) return copy_str; matcherstr = g_string_sized_new(16); - cmd_start = cmd_end = copy_str; - while (cmd_end && *cmd_end) { + cmd_start = copy_str; + while (cmd_start && *cmd_start) { /* skip all white spaces */ - while (*cmd_end && isspace(*cmd_end)) - cmd_end++; + while (*cmd_start && isspace((guchar)*cmd_start)) + cmd_start++; + cmd_end = cmd_start; /* extract a command */ - while (*cmd_end && !isspace(*cmd_end)) + while (*cmd_end && !isspace((guchar)*cmd_end)) cmd_end++; /* save character */ @@ -3593,7 +3595,8 @@ gchar *expand_search_string(const gchar *search_string) break; /* extract a parameter, allow quotes */ - cmd_end++; + while (*cmd_end && isspace((guchar)*cmd_end)) + cmd_end++; cmd_start = cmd_end; if (*cmd_start == '"') { term_char = '"'; @@ -3606,9 +3609,6 @@ gchar *expand_search_string(const gchar *search_string) while ((*cmd_end) && (*cmd_end != term_char)) cmd_end++; - if (*cmd_end && (*cmd_end != term_char)) - break; - if (*cmd_end == '"') cmd_end++; @@ -3640,10 +3640,9 @@ gchar *expand_search_string(const gchar *search_string) } } - if (*cmd_end) { + if (*cmd_end) cmd_end++; - cmd_start = cmd_end; - } + cmd_start = cmd_end; } g_free(copy_str); @@ -3658,7 +3657,7 @@ guint g_stricase_hash(gconstpointer gptr) const char *str; for (str = gptr; str && *str; str++) { - if (isupper(*str)) hash_result += (*str + ' '); + if (isupper((guchar)*str)) hash_result += (*str + ' '); else hash_result += *str; } @@ -3728,7 +3727,7 @@ gint quote_cmd_argument(gchar * result, guint size, for(p = path ; * p != '\0' ; p ++) { - if (isalnum(* p) || (* p == '/')) { + if (isalnum((guchar)*p) || (* p == '/')) { if (remaining > 0) { * result_p = * p; result_p ++; diff --git a/src/common/utils.h b/src/common/utils.h index 434c6f9a2..9c74c45aa 100644 --- a/src/common/utils.h +++ b/src/common/utils.h @@ -130,6 +130,14 @@ ptr = __tmp; \ } +#define AUTORELEASE_STR(str, iffail) \ +{ \ + gchar *__str; \ + Xstrdup_a(__str, str, iffail); \ + g_free(str); \ + str = __str; \ +} + #define FILE_OP_ERROR(file, func) \ { \ fprintf(stderr, "%s: ", file); \ diff --git a/src/compose.c b/src/compose.c index 6da76b243..c6874a79d 100644 --- a/src/compose.c +++ b/src/compose.c @@ -171,7 +171,8 @@ static GList *compose_list = NULL; Compose *compose_generic_new (PrefsAccount *account, const gchar *to, FolderItem *item, - GPtrArray *attach_files); + GPtrArray *attach_files, + GList *listAddress ); static Compose *compose_create (PrefsAccount *account, ComposeMode mode); @@ -300,6 +301,9 @@ static void compose_create_header_entry (Compose *compose); static void compose_add_header_entry (Compose *compose, gchar *header, gchar *text); static void compose_update_priority_menu_item(Compose * compose); +static void compose_add_field_list ( Compose *compose, + GList *listAddress ); + /* callback functions */ static gboolean compose_edit_size_alloc (GtkEditable *widget, @@ -489,6 +493,7 @@ static void compose_check_forwards_go (Compose *compose); static gboolean compose_send_control_enter (Compose *compose); static gint compose_defer_auto_save_draft (Compose *compose); +static PrefsAccount *compose_guess_forward_account_from_msginfo (MsgInfo *msginfo); static GtkItemFactoryEntry compose_popup_entries[] = { @@ -652,7 +657,8 @@ static GtkItemFactoryEntry compose_entries[] = {N_("/_Message/---"), NULL, NULL, 0, ""}, {N_("/_Message/Si_gn"), NULL, compose_toggle_sign_cb , 0, ""}, {N_("/_Message/_Encrypt"), NULL, compose_toggle_encrypt_cb, 0, ""}, - {N_("/_Message/Mode/MIME"), NULL, compose_set_gnupg_mode_cb, GNUPG_MODE_DETACH, ""}, + {N_("/_Message/Mode"), NULL, NULL, 0, ""}, + {N_("/_Message/Mode/MIME"), NULL, compose_set_gnupg_mode_cb, GNUPG_MODE_DETACH, ""}, {N_("/_Message/Mode/Inline"), NULL, compose_set_gnupg_mode_cb, GNUPG_MODE_INLINE, "/Message/Mode/MIME"}, #endif /* USE_GPGME */ {N_("/_Message/---"), NULL, NULL, 0, ""}, @@ -682,23 +688,27 @@ static GtkTargetEntry compose_mime_types[] = Compose *compose_new(PrefsAccount *account, const gchar *mailto, GPtrArray *attach_files) { - return compose_generic_new(account, mailto, NULL, attach_files); + return compose_generic_new(account, mailto, NULL, attach_files, NULL); } Compose *compose_new_with_folderitem(PrefsAccount *account, FolderItem *item) { - return compose_generic_new(account, NULL, item, NULL); + return compose_generic_new(account, NULL, item, NULL, NULL); +} + +Compose *compose_new_with_list( PrefsAccount *account, GList *listAddress ) +{ + return compose_generic_new( account, NULL, NULL, NULL, listAddress ); } Compose *compose_generic_new(PrefsAccount *account, const gchar *mailto, FolderItem *item, - GPtrArray *attach_files) + GPtrArray *attach_files, GList *listAddress ) { Compose *compose; GtkTextView *textview; GtkTextBuffer *textbuf; GtkTextIter iter; GtkItemFactory *ifactory; - gboolean grab_focus_on_last = TRUE; if (item && item->prefs && item->prefs->enable_default_account) account = account_find_from_id(item->prefs->default_account); @@ -733,8 +743,7 @@ Compose *compose_generic_new(PrefsAccount *account, const gchar *mailto, FolderI } else if (item && item->prefs->enable_default_to) { compose_entry_append(compose, item->prefs->default_to, COMPOSE_TO); - compose_entry_select(compose, item->prefs->default_to); - grab_focus_on_last = FALSE; + compose_entry_mark_default_to(compose, item->prefs->default_to); } if (item && item->ret_rcpt) { menu_set_toggle(ifactory, "/Message/Request Return Receipt", TRUE); @@ -749,6 +758,7 @@ Compose *compose_generic_new(PrefsAccount *account, const gchar *mailto, FolderI */ menu_set_sensitive(ifactory, "/Message/Request Return Receipt", FALSE); } + compose_add_field_list( compose, listAddress ); if (attach_files) { gint i; @@ -772,9 +782,7 @@ Compose *compose_generic_new(PrefsAccount *account, const gchar *mailto, FolderI g_free(folderidentifier); } - /* Grab focus on last header only if no default_to was set */ - if (grab_focus_on_last) - gtk_widget_grab_focus(compose->header_last->entry); + gtk_widget_grab_focus(compose->header_last->entry); undo_unblock(compose->undostruct); @@ -921,8 +929,10 @@ static void compose_generic_reply(MsgInfo *msginfo, gboolean quote, Compose *compose; PrefsAccount *account = NULL; PrefsAccount *reply_account; - GtkTextBuffer *buffer; + GtkTextView *textview; + GtkTextBuffer *textbuf; GtkTextIter iter; + int cursor_pos; g_return_if_fail(msginfo != NULL); g_return_if_fail(msginfo->folder != NULL); @@ -970,6 +980,9 @@ static void compose_generic_reply(MsgInfo *msginfo, gboolean quote, to_sender, followup_and_reply_to); compose_show_first_last_header(compose, TRUE); + textview = (GTK_TEXT_VIEW(compose->text)); + textbuf = gtk_text_view_get_buffer(textview); + #ifdef USE_ASPELL if (msginfo->folder && msginfo->folder->prefs && msginfo->folder->prefs && @@ -998,9 +1011,15 @@ static void compose_generic_reply(MsgInfo *msginfo, gboolean quote, if (quote && prefs_common.linewrap_quote) compose_wrap_line_all(compose); - buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(compose->text)); - gtk_text_buffer_get_start_iter(buffer, &iter); - gtk_text_buffer_place_cursor(buffer, &iter); + cursor_pos = quote_fmt_get_cursor_pos(); + gtk_text_buffer_get_start_iter(textbuf, &iter); + gtk_text_buffer_get_iter_at_offset(textbuf, &iter, cursor_pos); + gtk_text_buffer_place_cursor(textbuf, &iter); + + if (quote && prefs_common.linewrap_quote) { + compose_wrap_line_all(compose); + gtk_text_view_set_editable(GTK_TEXT_VIEW(compose->text), TRUE); + } gtk_widget_grab_focus(compose->text); @@ -1029,33 +1048,10 @@ Compose *compose_forward(PrefsAccount *account, MsgInfo *msginfo, g_return_val_if_fail(msginfo != NULL, NULL); g_return_val_if_fail(msginfo->folder != NULL, NULL); - if (msginfo->folder->prefs->enable_default_account) - account = account_find_from_id(msginfo->folder->prefs->default_account); - if (!account) - account = msginfo->folder->folder->account; - if (!account && msginfo->to && prefs_common.forward_account_autosel) { - gchar *to; - Xstrdup_a(to, msginfo->to, return NULL); - extract_address(to); - account = account_find_from_address(to); - } - - if (!account && prefs_common.forward_account_autosel) { - gchar cc[BUFFSIZE]; - if (!procheader_get_header_from_msginfo(msginfo,cc,sizeof(cc),"CC:")){ /* Found a CC header */ - extract_address(cc); - account = account_find_from_address(cc); - } - } - - if (account == NULL) { + if (!account && + !(account = compose_guess_forward_account_from_msginfo + (msginfo))) account = cur_account; - /* - account = msginfo->folder->folder->account; - if (!account) account = cur_account; - */ - } - g_return_val_if_fail(account != NULL, NULL); compose = compose_create(account, COMPOSE_FORWARD); @@ -1158,19 +1154,17 @@ Compose *compose_forward_multiple(PrefsAccount *account, GSList *msginfo_list) gchar *msgfile; g_return_val_if_fail(msginfo_list != NULL, NULL); - - for (msginfo = msginfo_list; msginfo != NULL; msginfo = msginfo->next) { - if ( ((MsgInfo *)msginfo->data)->folder == NULL ) + + for (msginfo = msginfo_list; msginfo != NULL; msginfo = msginfo->next) + if (((MsgInfo *)msginfo->data)->folder == NULL) return NULL; - } - if (account == NULL) { + /* guess account from first selected message */ + if (!account && + !(account = compose_guess_forward_account_from_msginfo + (msginfo_list->data))) account = cur_account; - /* - account = msginfo->folder->folder->account; - if (!account) account = cur_account; - */ - } + g_return_val_if_fail(account != NULL, NULL); for (msginfo = msginfo_list; msginfo != NULL; msginfo = msginfo->next) { @@ -1386,7 +1380,8 @@ Compose *compose_redirect(PrefsAccount *account, MsgInfo *msginfo) gtk_widget_set_sensitive(compose->toolbar->attach_btn, FALSE); gtk_widget_set_sensitive(compose->toolbar->sig_btn, FALSE); gtk_widget_set_sensitive(compose->toolbar->exteditor_btn, FALSE); - gtk_widget_set_sensitive(compose->toolbar->linewrap_btn, FALSE); + gtk_widget_set_sensitive(compose->toolbar->linewrap_current_btn, FALSE); + gtk_widget_set_sensitive(compose->toolbar->linewrap_all_btn, FALSE); return compose; } @@ -1452,16 +1447,36 @@ void compose_entry_append(Compose *compose, const gchar *address, compose_add_header_entry(compose, header, (gchar *)address); } -void compose_entry_select (Compose *compose, const gchar *mailto) +void compose_entry_mark_default_to(Compose *compose, const gchar *mailto) { - GSList *header_list; + static GtkStyle *bold_style = NULL; + static GdkColor bold_color; + GSList *h_list; + GtkEntry *entry; - for (header_list = compose->header_list; header_list != NULL; header_list = header_list->next) { - GtkEntry * entry = GTK_ENTRY(((ComposeHeaderEntry *)header_list->data)->entry); - - if (gtk_entry_get_text(entry) && !g_strcasecmp(gtk_entry_get_text(entry), mailto)) { - gtk_entry_select_region(entry, 0, -1); - gtk_widget_grab_focus(GTK_WIDGET(entry)); + for (h_list = compose->header_list; h_list != NULL; h_list = h_list->next) { + entry = GTK_ENTRY(((ComposeHeaderEntry *)h_list->data)->entry); + if (gtk_entry_get_text(entry) && + !g_strcasecmp(gtk_entry_get_text(entry), mailto)) { + gtk_widget_ensure_style(GTK_WIDGET(entry)); + if (!bold_style) { + PangoFontDescription *font_desc = NULL; + gtkut_convert_int_to_gdk_color + (prefs_common.color_new, &bold_color); + bold_style = gtk_style_copy(gtk_widget_get_style + (GTK_WIDGET(entry))); + if (BOLD_FONT) + font_desc = pango_font_description_from_string + (BOLD_FONT); + if (font_desc) { + if (bold_style->font_desc) + pango_font_description_free + (bold_style->font_desc); + bold_style->font_desc = font_desc; + } + bold_style->fg[GTK_STATE_NORMAL] = bold_color; + } + gtk_widget_set_style(GTK_WIDGET(entry), bold_style); } } } @@ -1495,7 +1510,10 @@ void compose_toolbar_cb(gint action, gpointer data) case A_EXTEDITOR: compose_ext_editor_cb(compose, 0, NULL); break; - case A_LINEWRAP: + case A_LINEWRAP_CURRENT: + compose_wrap_line(compose); + break; + case A_LINEWRAP_ALL: compose_wrap_line_all(compose); break; case A_ADDRBOOK: @@ -3621,7 +3639,6 @@ static gint compose_write_to_file(Compose *compose, const gchar *file, gtk_text_buffer_get_start_iter(buffer, &start); gtk_text_buffer_get_end_iter(buffer, &end); chars = gtk_text_buffer_get_text(buffer, &start, &end, FALSE); - len = strlen(chars); if (is_ascii_str(chars)) { buf = chars; chars = NULL; @@ -5378,6 +5395,7 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode) compose->exteditor_pid = -1; compose->exteditor_readdes = -1; compose->exteditor_tag = -1; + compose->draft_timeout_tag = -1; #if USE_ASPELL menu_set_sensitive(ifactory, "/Spelling", FALSE); @@ -6322,7 +6340,8 @@ static void compose_set_ext_editor_sensitive(Compose *compose, gtk_widget_set_sensitive(compose->toolbar->insert_btn, sensitive); gtk_widget_set_sensitive(compose->toolbar->sig_btn, sensitive); gtk_widget_set_sensitive(compose->toolbar->exteditor_btn, sensitive); - gtk_widget_set_sensitive(compose->toolbar->linewrap_btn, sensitive); + gtk_widget_set_sensitive(compose->toolbar->linewrap_current_btn, sensitive); + gtk_widget_set_sensitive(compose->toolbar->linewrap_all_btn, sensitive); } /** @@ -6532,6 +6551,11 @@ static void compose_send_cb(gpointer data, guint action, GtkWidget *widget) _("Yes"), _("No"), NULL) != G_ALERTDEFAULT) return; + if (compose->draft_timeout_tag != -1) { /* CLAWS: disable draft timeout */ + gtk_timeout_remove(compose->draft_timeout_tag); + compose->draft_timeout_tag = -1; + } + compose_allow_user_actions (compose, FALSE); compose->sending = TRUE; val = compose_send(compose); @@ -7640,11 +7664,13 @@ static void text_inserted(GtkTextBuffer *buffer, GtkTextIter *iter, if (prefs_common.autosave && gtk_text_buffer_get_char_count(buffer) % prefs_common.autosave_length == 0) - gtk_timeout_add(500, (GtkFunction) compose_defer_auto_save_draft, compose); + compose->draft_timeout_tag = gtk_timeout_add + (500, (GtkFunction) compose_defer_auto_save_draft, compose); } static gint compose_defer_auto_save_draft(Compose *compose) { + compose->draft_timeout_tag = -1; compose_draft_cb((gpointer)compose, 2, NULL); return FALSE; } @@ -7726,3 +7752,60 @@ static void compose_check_forwards_go(Compose *compose) } #endif +/*! + *\brief Guess originating forward account from MsgInfo and several + * "common preference" settings. Return NULL if no guess. + */ +static PrefsAccount *compose_guess_forward_account_from_msginfo(MsgInfo *msginfo) +{ + PrefsAccount *account = NULL; + + g_return_val_if_fail(msginfo, NULL); + g_return_val_if_fail(msginfo->folder, NULL); + g_return_val_if_fail(msginfo->folder->prefs, NULL); + + if (msginfo->folder->prefs->enable_default_account) + account = account_find_from_id(msginfo->folder->prefs->default_account); + + if (!account) + account = msginfo->folder->folder->account; + + if (!account && msginfo->to && prefs_common.forward_account_autosel) { + gchar *to; + Xstrdup_a(to, msginfo->to, return NULL); + extract_address(to); + account = account_find_from_address(to); + } + + if (!account && prefs_common.forward_account_autosel) { + gchar cc[BUFFSIZE]; + if (!procheader_get_header_from_msginfo + (msginfo, cc,sizeof cc , "CC:")) { /* Found a CC header */ + extract_address(cc); + account = account_find_from_address(cc); + } + } + + return account; +} + +/** + * Add entry field for each address in list. + * \param compose E-Mail composition object. + * \param listAddress List of (formatted) E-Mail addresses. + */ +static void compose_add_field_list( Compose *compose, GList *listAddress ) { + GList *node; + gchar *addr; + node = listAddress; + while( node ) { + addr = ( gchar * ) node->data; + compose_entry_append( compose, addr, COMPOSE_TO ); + node = g_list_next( node ); + } +} + +/* + * End of Source. + */ + diff --git a/src/compose.h b/src/compose.h index 7641e2d58..b678658eb 100644 --- a/src/compose.h +++ b/src/compose.h @@ -207,6 +207,8 @@ struct _Compose gchar *redirect_filename; gboolean remove_references; + + guint draft_timeout_tag; }; struct _AttachInfo @@ -227,6 +229,9 @@ Compose *compose_new (PrefsAccount *account, Compose *compose_new_with_folderitem (PrefsAccount *account, FolderItem *item); +Compose *compose_new_with_list (PrefsAccount *account, + GList *listAddress); + void compose_reply_mode (ComposeMode mode, GSList *msginfo_list, gchar *body); @@ -261,7 +266,7 @@ void compose_entry_append (Compose *compose, const gchar *address, ComposeEntryType type); -void compose_entry_select (Compose *compose, +void compose_entry_mark_default_to (Compose *compose, const gchar *address); gint compose_send (Compose *compose); diff --git a/src/filtering.c b/src/filtering.c index fb79d43bd..7b68fa03d 100644 --- a/src/filtering.c +++ b/src/filtering.c @@ -284,7 +284,7 @@ static gboolean filteringaction_apply(FilteringAction * action, MsgInfo * info) return TRUE; case MATCHACTION_STOP: - return TRUE; + return FALSE; case MATCHACTION_HIDE: info->hidden = TRUE; @@ -318,6 +318,17 @@ static gboolean filtering_match_condition(FilteringProp *filtering, MsgInfo *inf return matcherlist_match(filtering->matchers, info); } +/*! + *\brief Apply a rule on message. + * + *\param filtering List of filtering rules. + *\param info Message to apply rules on. + *\param final Variable returning TRUE or FALSE if one of the + * encountered actions was final. + * See also \ref filtering_is_final_action. + * + *\return gboolean TRUE to continue applying rules. + */ static gboolean filtering_apply_rule(FilteringProp *filtering, MsgInfo *info, gboolean * final) { @@ -332,7 +343,7 @@ static gboolean filtering_apply_rule(FilteringProp *filtering, MsgInfo *info, action = tmp->data; if (FALSE == (result = filteringaction_apply(action, info))) { - g_warning("action %s could not be applied", + g_warning("No further processing after rule %s\n", filteringaction_to_string(buf, sizeof buf, action)); } @@ -344,6 +355,14 @@ static gboolean filtering_apply_rule(FilteringProp *filtering, MsgInfo *info, return result; } +/*! + *\brief Check if an action is "final", i.e. should break further + * processing. + * + *\param filtering_action Action to check. + * + *\return gboolean TRUE if \a filtering_action is final. + */ static gboolean filtering_is_final_action(FilteringAction *filtering_action) { switch(filtering_action->type) { @@ -360,15 +379,15 @@ static gboolean filter_msginfo(GSList * filtering_list, MsgInfo * info) { GSList *l; gboolean final; - gboolean applied; + gboolean apply_next; g_return_val_if_fail(info != NULL, TRUE); - for (l = filtering_list, final = FALSE, applied = FALSE; l != NULL; l = g_slist_next(l)) { + for (l = filtering_list, final = FALSE, apply_next = FALSE; l != NULL; l = g_slist_next(l)) { FilteringProp * filtering = (FilteringProp *) l->data; if (filtering_match_condition(filtering, info)) { - applied = filtering_apply_rule(filtering, info, &final); + apply_next = filtering_apply_rule(filtering, info, &final); if (final) break; } @@ -376,13 +395,26 @@ static gboolean filter_msginfo(GSList * filtering_list, MsgInfo * info) /* put in inbox if a final rule could not be applied, or * the last rule was not a final one. */ - if ((final && !applied) || !final) { + if ((final && !apply_next) || !final) { return FALSE; } return TRUE; } +/*! + *\brief Filter a message against a list of rules. + * + *\param flist List of filter rules. + *\param info Message. + * + *\return gboolean TRUE if filter rules handled the message. + * + *\note Returning FALSE means the message was not handled, + * and that the calling code should do the default + * processing. E.g. \ref inc.c::inc_start moves the + * message to the inbox. + */ gboolean filter_message_by_msginfo(GSList *flist, MsgInfo *info) { return filter_msginfo(flist, info); diff --git a/src/folder.c b/src/folder.c index 71f7688aa..91b6a2fcb 100644 --- a/src/folder.c +++ b/src/folder.c @@ -166,6 +166,7 @@ void folder_init(Folder *folder, const gchar *name) /* Init folder data */ folder->account = NULL; + folder->sort = 0; folder->inbox = NULL; folder->outbox = NULL; folder->draft = NULL; @@ -175,17 +176,10 @@ void folder_init(Folder *folder, const gchar *name) void folder_destroy(Folder *folder) { - FolderUpdateData hookdata; - g_return_if_fail(folder != NULL); g_return_if_fail(folder->klass->destroy_folder != NULL); - folder_list = g_list_remove(folder_list, folder); - - hookdata.folder = folder; - hookdata.update_flags = FOLDER_DESTROY_FOLDER; - hookdata.item = NULL; - hooks_invoke(FOLDER_UPDATE_HOOKLIST, &hookdata); + folder_remove(folder); folder_tree_destroy(folder); @@ -229,6 +223,8 @@ void folder_set_xml(Folder *folder, XMLTag *tag) } else if (!strcmp(attr->name, "collapsed")) { if (rootitem != NULL) rootitem->collapsed = *attr->value == '1' ? TRUE : FALSE; + } else if (!strcmp(attr->name, "sort")) { + folder->sort = atoi(attr->value); } } } @@ -248,6 +244,7 @@ XMLTag *folder_get_xml(Folder *folder) xml_tag_add_attr(tag, "collapsed", g_strdup(rootitem->collapsed ? "1" : "0")); } + xml_tag_add_attr(tag, "sort", g_strdup_printf("%d", folder->sort)); return tag; } @@ -281,7 +278,7 @@ FolderItem *folder_item_new(Folder *folder, const gchar *name, const gchar *path item->threaded = TRUE; item->ret_rcpt = FALSE; item->opened = FALSE; - item->node = NULL; + item->node = g_node_new(item); item->folder = NULL; item->account = NULL; item->apply_sub = FALSE; @@ -301,7 +298,7 @@ void folder_item_append(FolderItem *parent, FolderItem *item) g_return_if_fail(item != NULL); item->folder = parent->folder; - item->node = g_node_append_data(parent->node, item); + g_node_append(parent->node, item->node); } static gboolean folder_item_remove_func(GNode *node, gpointer data) @@ -571,6 +568,17 @@ void folder_set_name(Folder *folder, const gchar *name) } } +void folder_set_sort(Folder *folder, guint sort) +{ + g_return_if_fail(folder != NULL); + + if (folder->sort != sort) { + folder_remove(folder); + folder->sort = sort; + folder_add(folder); + } +} + gboolean folder_tree_destroy_func(GNode *node, gpointer data) { FolderItem *item = (FolderItem *) node->data; @@ -607,27 +615,28 @@ void folder_add(Folder *folder) for (i = 0, cur = folder_list; cur != NULL; cur = cur->next, i++) { cur_folder = FOLDER(cur->data); - if (FOLDER_TYPE(folder) == F_MH) { - if (FOLDER_TYPE(cur_folder) != F_MH) break; - } else if (FOLDER_TYPE(folder) == F_MBOX) { - if (FOLDER_TYPE(cur_folder) != F_MH && - FOLDER_TYPE(cur_folder) != F_MBOX) break; - } else if (FOLDER_TYPE(folder) == F_IMAP) { - if (FOLDER_TYPE(cur_folder) != F_MH && - FOLDER_TYPE(cur_folder) != F_MBOX && - FOLDER_TYPE(cur_folder) != F_IMAP) break; - } else if (FOLDER_TYPE(folder) == F_NEWS) { - if (FOLDER_TYPE(cur_folder) != F_MH && - FOLDER_TYPE(cur_folder) != F_MBOX && - FOLDER_TYPE(cur_folder) != F_IMAP && - FOLDER_TYPE(cur_folder) != F_NEWS) break; - } + if (cur_folder->sort < folder->sort) + break; } folder_list = g_list_insert(folder_list, folder, i); hookdata.folder = folder; - hookdata.update_flags = FOLDER_NEW_FOLDER; + hookdata.update_flags = FOLDER_ADD_FOLDER; + hookdata.item = NULL; + hooks_invoke(FOLDER_UPDATE_HOOKLIST, &hookdata); +} + +void folder_remove(Folder *folder) +{ + FolderUpdateData hookdata; + + g_return_if_fail(folder != NULL); + + folder_list = g_list_remove(folder_list, folder); + + hookdata.folder = folder; + hookdata.update_flags = FOLDER_REMOVE_FOLDER; hookdata.item = NULL; hooks_invoke(FOLDER_UPDATE_HOOKLIST, &hookdata); } @@ -766,14 +775,15 @@ void folder_scan_tree(Folder *folder) FolderItem *folder_create_folder(FolderItem *parent, const gchar *name) { FolderItem *new_item; - FolderUpdateData hookdata; new_item = parent->folder->klass->create_folder(parent->folder, parent, name); if (new_item) { + FolderUpdateData hookdata; + new_item->cache = msgcache_new(); hookdata.folder = new_item->folder; - hookdata.update_flags = FOLDER_TREE_CHANGED | FOLDER_NEW_FOLDERITEM; + hookdata.update_flags = FOLDER_TREE_CHANGED | FOLDER_ADD_FOLDERITEM; hookdata.item = new_item; hooks_invoke(FOLDER_UPDATE_HOOKLIST, &hookdata); } @@ -781,6 +791,26 @@ FolderItem *folder_create_folder(FolderItem *parent, const gchar *name) return new_item; } +gint folder_item_rename(FolderItem *item, gchar *newname) +{ + gint retval; + + g_return_val_if_fail(item != NULL, -1); + g_return_val_if_fail(newname != NULL, -1); + + retval = item->folder->klass->rename_folder(item->folder, item, newname); + + if (retval >= 0) { + FolderItemUpdateData hookdata; + + hookdata.item = item; + hookdata.update_flags = FOLDER_TREE_CHANGED; + hooks_invoke(FOLDER_ITEM_UPDATE_HOOKLIST, &hookdata); + } + + return retval; +} + struct TotalMsgCount { guint new_msgs; @@ -1022,6 +1052,20 @@ FolderItem *folder_find_item_from_path(const gchar *path) return d[1]; } +FolderItem *folder_find_child_item_by_name(FolderItem *item, const gchar *name) +{ + GNode *node; + FolderItem *child; + + for (node = item->node->children; node != NULL; node = node->next) { + child = FOLDER_ITEM(node->data); + if (strcmp2(g_basename(child->path), name) == 0) + return child; + } + + return NULL; +} + FolderClass *folder_get_class_from_string(const gchar *str) { GSList *classlist; @@ -1343,22 +1387,21 @@ static gint folder_sort_folder_list(gconstpointer a, gconstpointer b) gint folder_item_open(FolderItem *item) { + gchar *buf; if((item->folder->klass->scan_required != NULL) && (item->folder->klass->scan_required(item->folder, item))) { folder_item_scan_full(item, TRUE); } - + folder_item_syncronize_flags(item); + /* Processing */ - if(item->prefs->processing != NULL) { - gchar *buf; - - buf = g_strdup_printf(_("Processing (%s)...\n"), item->path); - debug_print("%s\n", buf); - g_free(buf); + buf = g_strdup_printf(_("Processing (%s)...\n"), + item->path ? item->path : item->name); + debug_print("%s\n", buf); + g_free(buf); - folder_item_apply_processing(item); + folder_item_apply_processing(item); - debug_print("done.\n"); - } + debug_print("done.\n"); return 0; } @@ -1655,6 +1698,60 @@ gint folder_item_scan_full(FolderItem *item, gboolean filtering) return 0; } +gint folder_item_syncronize_flags(FolderItem *item) +{ + MsgInfoList *msglist = NULL; + GSList *cur; + GRelation *relation; + gint ret = 0; + + g_return_val_if_fail(item != NULL, -1); + g_return_val_if_fail(item->folder != NULL, -1); + g_return_val_if_fail(item->folder->klass != NULL, -1); + if(item->folder->klass->get_flags == NULL) + return 0; + + if (item->cache == NULL) + folder_item_read_cache(item); + + msglist = msgcache_get_msg_list(item->cache); + + relation = g_relation_new(2); + g_relation_index(relation, 0, g_direct_hash, g_direct_equal); + if ((ret = item->folder->klass->get_flags( + item->folder, item, msglist, relation)) == 0) { + GTuples *tuples; + MsgInfo *msginfo; + MsgPermFlags permflags; + gboolean skip; + + for (cur = msglist; cur != NULL; cur = g_slist_next(cur)) { + msginfo = (MsgInfo *) cur->data; + + tuples = g_relation_select(relation, msginfo, 0); + skip = tuples->len < 1; + if (!skip) + permflags = GPOINTER_TO_INT(g_tuples_index(tuples, 0, 1)); + g_tuples_destroy(tuples); + if (skip) + continue; + + if (msginfo->flags.perm_flags != permflags) { + procmsg_msginfo_set_flags(msginfo, + permflags & ~msginfo->flags.perm_flags, 0); + procmsg_msginfo_unset_flags(msginfo, + ~permflags & msginfo->flags.perm_flags, 0); + } + } + } + g_relation_destroy(relation); + + for (cur = msglist; cur != NULL; cur = g_slist_next(cur)) + procmsg_msginfo_free((MsgInfo *) cur->data); + + return ret; +} + gint folder_item_scan(FolderItem *item) { return folder_item_scan_full(item, TRUE); @@ -1770,16 +1867,20 @@ void folder_item_read_cache(FolderItem *item) g_return_if_fail(item != NULL); - cache_file = folder_item_get_cache_file(item); - mark_file = folder_item_get_mark_file(item); - item->cache = msgcache_read_cache(item, cache_file); - if (!item->cache) { + if (item->path != NULL) { + cache_file = folder_item_get_cache_file(item); + mark_file = folder_item_get_mark_file(item); + item->cache = msgcache_read_cache(item, cache_file); + if (!item->cache) { + item->cache = msgcache_new(); + folder_item_scan_full(item, TRUE); + } + msgcache_read_mark(item->cache, mark_file); + g_free(cache_file); + g_free(mark_file); + } else { item->cache = msgcache_new(); - folder_item_scan_full(item, TRUE); } - msgcache_read_mark(item->cache, mark_file); - g_free(cache_file); - g_free(mark_file); folder_clean_cache_memory(); } @@ -2394,9 +2495,6 @@ static gint do_copy_msgs(FolderItem *dest, GSList *msglist, gboolean remove_sour } } - if (folder->klass->finished_copy) - folder->klass->finished_copy(folder, dest); - g_relation_destroy(relation); return lastnum; } @@ -2530,9 +2628,6 @@ gint folder_item_remove_all_msg(FolderItem *item) result = folder->klass->remove_all_msg(folder, item); if (result == 0) { - if (folder->klass->finished_remove) - folder->klass->finished_remove(folder, item); - folder_item_free_cache(item); item->cache = msgcache_new(); diff --git a/src/folder.h b/src/folder.h index 0896a6202..607a5323b 100644 --- a/src/folder.h +++ b/src/folder.h @@ -1,3 +1,5 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + /* * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client * Copyright (C) 1999-2003 Hiroyuki Yamamoto @@ -98,10 +100,10 @@ typedef enum typedef enum { - FOLDER_NEW_FOLDER = 1 << 0, - FOLDER_DESTROY_FOLDER = 1 << 1, + FOLDER_ADD_FOLDER = 1 << 0, + FOLDER_REMOVE_FOLDER = 1 << 1, FOLDER_TREE_CHANGED = 1 << 2, - FOLDER_NEW_FOLDERITEM = 1 << 3, + FOLDER_ADD_FOLDERITEM = 1 << 3, FOLDER_REMOVE_FOLDERITEM = 1 << 4, } FolderUpdateFlags; @@ -109,6 +111,7 @@ typedef enum { F_ITEM_UPDATE_MSGCNT = 1 << 0, F_ITEM_UPDATE_CONTENT = 1 << 1, + F_ITEM_UPDATE_NAME = 1 << 2, } FolderItemUpdateFlags; typedef void (*FolderUIFunc) (Folder *folder, @@ -117,7 +120,7 @@ typedef void (*FolderUIFunc) (Folder *folder, typedef void (*FolderDestroyNotify) (Folder *folder, FolderItem *item, gpointer data); -typedef void (*FolderItemFunc) (FolderItem *item, +typedef void (*FolderItemFunc) (FolderItem *item, gpointer data); @@ -134,6 +137,7 @@ struct _Folder gchar *name; PrefsAccount *account; + guint sort; FolderItem *inbox; FolderItem *outbox; @@ -153,95 +157,406 @@ struct _Folder struct _FolderClass { + /** + * A numeric identifier for the FolderClass. Will be removed in the future + */ FolderType type; + /** + * A string identifier for the FolderClass. Currently used in folderlist.xml. + * Should be lowercase. + */ gchar *idstr; + /** + * A string for the User Interface that identifies the FolderClass to the + * user. Can be upper and lowercase unlike the idstr. + */ gchar *uistr; - + /* virtual functions */ /* Folder funtions */ + /** + * Create a new \c Folder of this \c FolderClass. + * + * \param name The name of the new Folder + * \param path The path of the new Folder + * \return The new \c Folder, or \c NULL when creating the \c Folder + * failed + */ Folder *(*new_folder) (const gchar *name, const gchar *path); + /** + * Destroy a \c Folder of this \c FolderClass, frees all resources + * allocated by the Folder + * + * \param folder The \c Folder that should be destroyed. + */ void (*destroy_folder) (Folder *folder); + /** + * Set the Folder's internal attributes from an \c XMLTag. Also sets the + * parameters of the root-FolderItem of the \c Folder. If \c NULL + * the default function of the basic \¢ FolderClass is used, so it + * must not be \c NULL if one of the parent \c FolderClasses has a \c set_xml + * function. In that case the parent \c FolderClass' \c set_xml function + * can be used or it has to be called with the \c folder and \c tag by + * the implementation. + * + * \param folder The \c Folder which's attributes should be updated + * \param tag The \c XMLTag containing the \c XMLAttrs for the attributes + */ void (*set_xml) (Folder *folder, XMLTag *tag); + /** + * Get an \c XMLTag for the attributes of the \c Folder and the root-FolderItem + * of the \c Folder. If \c NULL the default implementation for the basic + * FolderClass will be used, so it must not be \c NULL if one of the + * parent \c FolderClasses has it's own implementation for \c get_xml. + * In that case the parent FolderClass' \c get_xml function can be + * used or the \c XMLTag has to be fetched from the parent's \c get_xml + * function and then the \c FolderClass specific attributes can be + * added to it. + * + * \param Folder The \c Folder which's attributes should be set in the + * \c XMLTag's \c XMLAttrs + * \return XMLTag An \c XMLTag with \c XMLAttrs containing the \c Folder's + * attributes. + */ XMLTag *(*get_xml) (Folder *folder); + /** + * Rebuild the folder tree from the folder's data + * \todo New implementations of MH and IMAP are actually syncronizing + * the tree with the folder by reusing the old \c FolderItems. + * Claws still destroys the old tree before calling this function. + * + * \param folder The folder which's tree should be rebuild + * \return 0 on success, a negative number otherwise + */ gint (*scan_tree) (Folder *folder); gint (*create_tree) (Folder *folder); /* FolderItem functions */ + /** + * Create a new \c FolderItem structure for the \c FolderClass. + * \c FolderClasses can have their own \c FolderItem structure with + * extra attributes. + * + * \param folder The \c Folder for that a \c FolderItem should be + * created + * \return The new \c FolderItem or NULL in case of an error + */ FolderItem *(*item_new) (Folder *folder); + /** + * Destroy a \c FolderItem from this \c FolderClass. The \c FolderClass + * has to free all private resources used by the \c FolderItem. + * + * \param folder The \c Folder of the \c FolderItem + * \param item The \c FolderItem that should be destroyed + */ void (*item_destroy) (Folder *folder, FolderItem *item); + /** + * Set the \c FolderItem's internal attributes from an \c XMLTag. If + * \c NULL the default function of the basic \c FolderClass is used, so it + * must not be \c NULL if one of the parent \c FolderClasses has a \c item_set_xml + * function. In that case the parent \c FolderClass' \c item_set_xml function + * can be used or it has to be called with the \c folder, \c item and \c tag by + * the implementation. + * + * \param folder The \c Folder of the \c FolderItem + * \param item The \c FolderItems which's attributes should be set + * \param tag The \c XMLTag with \c XMLAttrs for the \c FolderItem's + * attributes + */ void (*item_set_xml) (Folder *folder, FolderItem *item, XMLTag *tag); + /** + * Get an \c XMLTag for the attributes of the \c FolderItem If \c NULL + * the default implementation for the basic \c FolderClass will be used, + * so it must not be \c NULL if one of the parent \c FolderClasses has + * it's own implementation for \c item_get_xml. In that case the parent + * FolderClass' \c item_get_xml function can be used or the \c XMLTag + * has to be fetched from the parent's \c item_get_xml function and + * then the \c FolderClass specific attributes can be added to it. + * + * \param folder The \c Folder of the \c FolderItem + * \parem item The \c FolderItem which's attributes should be set in + * the \c XMLTag's \c XMLAttrs + * \return An \c XMLTag with \c XMLAttrs containing the \c FolderItem's + * attributes. + */ XMLTag *(*item_get_xml) (Folder *folder, FolderItem *item); + /** + * Get a local path for the \c FolderItem where Sylpheed can save + * it's cache data. For local directory based folders this can be the + * real path. For other folders it can be the local cache directory. + * + * \param folder The \c Folder of the \c FolderItem + * \param item The \c FolderItem for that a path should be returned + * \return A path for the \c FolderItem + */ gchar *(*item_get_path) (Folder *folder, FolderItem *item); + /** + * Create a new \c FolderItem. The function must use folder_item_append + * to add the new \c FolderItem to the folder tree + * + * \param folder The \c Folder in which a new \c FolderItem should be + * created + * \param parent \c The parent \c FolderItem for the new \c FolderItem + * \parem name The name for the new \c FolderItem + * \return The new \c FolderItem + */ FolderItem *(*create_folder) (Folder *folder, FolderItem *parent, const gchar *name); + /** + * Rename a \c FolderItem + * + * \param folder The \c Folder of the \c FolderItem that should be + * renamed + * \param item The \c FolderItem that should be renamed + * \param name The new name of the \c FolderItem + * \return 0 on success, a negative number otherwise + */ gint (*rename_folder) (Folder *folder, FolderItem *item, const gchar *name); + /** + * Remove a \c FolderItem from the \c Folder + * + * \param folder The \c Folder that contains the \c FolderItem + * \param item The \c FolderItem that should be removed + * \return 0 on sucess, a negative number otherwise + */ gint (*remove_folder) (Folder *folder, FolderItem *item); + /** + * Close a \c FolderItem. Called when the user deselects a + * \c FolderItem. + * + * \attention In Sylpheed-Main operations can only be done on the + * \c FolderItem that is opened in the SummaryView. This + * \c FolderItem will be closed when you select a new + * \c FolderItem in the FolderView. In Claws operations can + * be done any time on any folder and you should not expect + * that all \c FolderItems get closed after operations + * + * \param folder The \c Folder that contains the \c FolderItem + * \param item The \c FolderItem that should be closed + * \return 0 on success, a negative number otherwise + */ gint (*close) (Folder *folder, FolderItem *item); + /** + * Get the list of message numbers for the messages in the \c FolderItem + * + * \param folder The \c Folder that contains the \c FolderItem + * \param item The \c FolderItem for which the message numbers should + * be fetched + * \param list Pointer to a GSList where message numbers have to be + * added. Because of the implementation of the GSList that + * changes the pointer of the GSList itself when the first + * item is added this is a pointer to a pointer to a + * GSList structure. Use *item = g_slist_...(*item, ...) + * operations to modify the list. + * \param old_uids_valid In some \c Folders the old UIDs can be invalid. + * Set this pointer to a gboolean to TRUE if the + * old UIDs are still valid, otherwise set it to + * FALSE and the folder system will discard it's + * cache data of the previously know UIDs + * \return The number of message numbers add to the list on success, + * a negative number otherwise. + */ gint (*get_num_list) (Folder *folder, FolderItem *item, GSList **list, gboolean *old_uids_valid); - void (*update_mark) (Folder *folder, - FolderItem *item); - void (*finished_copy) (Folder *folder, - FolderItem *item); - void (*finished_remove) (Folder *folder, - FolderItem *item); + /** + * Tell the folder system if a \c FolderItem should be scanned + * (cache data syncronized with the folder content) when it is required + * because the \c FolderItem's content changed. If NULL the folder + * system will not do automatic scanning of \c FolderItems + * + * \param folder The \c Folder that contains the \c FolderItem + * \param item The \c FolderItem which's content should be checked + * \return TRUE if the \c FolderItem should be scanned, FALSE otherwise + */ gboolean (*scan_required) (Folder *folder, FolderItem *item); /* Message functions */ + /** + * Get a MsgInfo for a message in a \c FolderItem + * + * \param folder The \c Folder containing the message + * \param item The \c FolderItem containing the message + * \param num The message number of the message + * \return A pointer to a \c MsgInfo decribing the message or \c + * NULL in case of an error + */ MsgInfo *(*get_msginfo) (Folder *folder, FolderItem *item, gint num); - GSList *(*get_msginfos) (Folder *folder, + /** + * Get \c MsgInfos for a list of message numbers + * + * \param folder The \c Folder containing the message + * \param item The \c FolderItem containing the message + * \param msgnum_list A list of message numbers for which the + * \c MsgInfos should be fetched + * \return A list of \c MsgInfos for the messages in the \c msgnum_list + * that really exist. Messages that are not found can simply + * be left out. + */ + MsgInfoList *(*get_msginfos) (Folder *folder, FolderItem *item, MsgNumberList *msgnum_list); - /* return value is locale charset */ - gchar *(*fetch_msg) (Folder *folder, + /** + * Get the filename for a message. This can either be the real message + * file for local folders or a temporary file for remote folders. + * + * \param folder The \c Folder containing the message + * \param item The \c FolderItem containing the message + * \param num The message number of the message + * \return A string with the filename of the message file. The returned + * string has to be freed with \c g_free(). If message is not + * available return NULL. + */ + gchar *(*fetch_msg) (Folder *folder, FolderItem *item, gint num); + /** + * Add a single message file to a folder with the given flags (if + * flag handling is supported by the folder) + * + * \param folder The target \c Folder for the message + * \param dest the target \c FolderItem for the message + * \param file The file that contains the message + * \param flags The flags the new message should have in the folder + * \return 0 on success, a negative number otherwise + */ gint (*add_msg) (Folder *folder, FolderItem *dest, const gchar *file, MsgFlags *flags); + /** + * Add multiple messages to a \c FolderItem. If NULL the folder + * system will add messages with \c add_msg one by one + * + * \param folder The target \c Folder for the messages + * \param dest the target \c FolderItem for the messages + * \param file_list A list of \c MsgFileInfos which contain the + * filenames and flags for the new messages + * \param relation Insert tuples of (MsgFileInfo, new message number) to + * provide feedback for the folder system which new + * message number a \c MsgFileInfo got in dest. Insert + * 0 if the new message number is unknown. + */ gint (*add_msgs) (Folder *folder, FolderItem *dest, GSList *file_list, GRelation *relation); + /** + * Copy a message to a FolderItem + * + * \param folder The \c Folder of the destination FolderItem + * \param dest The destination \c FolderItem for the message + * \param msginfo The message that should be copied + * \return The message number the copied message got, 0 if it is + * unknown because message numbers are assigned by an external + * system and not available after copying or a negative number + * if an error occuried + */ gint (*copy_msg) (Folder *folder, FolderItem *dest, MsgInfo *msginfo); + /** + * Copy multiple messages to a \c FolderItem. If \c NULL the folder + * system will use \c copy_msg to copy messages one by one. + * + * \param folder The \c Folder of the destination FolderItem + * \param dest The destination \c FolderItem for the message + * \param msglist A list of \c MsgInfos which should be copied to dest + * \param relation Insert tuples of (MsgInfo, new message number) to + * provide feedback for the folder system which new + * message number a \c MsgInfo got in dest. Insert + * 0 if the new message number is unknown. + * \return 0 on success, a negative number otherwise + */ gint (*copy_msgs) (Folder *folder, FolderItem *dest, MsgInfoList *msglist, GRelation *relation); + /** + * Remove a message from a \c FolderItem. + * + * \param folder The \c Folder of the message + * \param item The \c FolderItem containing the message + * \param num The message number of the message + * \return 0 on success, a negative number otherwise + */ gint (*remove_msg) (Folder *folder, FolderItem *item, gint num); + /** + * Remove all messages in a \ c FolderItem + * + * \param folder The \c Folder of the \c FolderItem + * \param item The \FolderItem which's messages should be deleted + * \return 0 on succes, a negative number otherwise + */ gint (*remove_all_msg) (Folder *folder, FolderItem *item); + /** + * Check if a message has been modified by someone else + * + * \param folder The \c Folder of the message + * \param item The \c FolderItem containing the message + * \param msginfo The \c MsgInfo for the message that should be checked + * \return \c TRUE if the message was modified, \c FALSE otherwise + */ gboolean (*is_msg_changed) (Folder *folder, FolderItem *item, MsgInfo *msginfo); + /** + * Update a message's flags in the folder data. If NULL only the + * internal flag management will be used. The function has to set + * \c msginfo->flags.perm_flags. It does not have to set the flags + * that it got as \c newflags. If a flag can not be set in this + * \c FolderClass the function can refuse to set it. Flags that are not + * supported by the \c FolderClass should not be refused. They will be + * managed by the internal cache in this case. + * + * \param folder The \c Folder of the message + * \param item The \c FolderItem of the message + * \param msginfo The \c MsgInfo for the message which's flags should be + * updated + * \param newflags The flags the message should get + */ void (*change_flags) (Folder *folder, FolderItem *item, MsgInfo *msginfo, MsgPermFlags newflags); + /** + * Get the flags for a list of messages. Flags that are not supported + * by the folder should be preserved. They can be copied from + * \c msginfo->flags.perm_flags + * + * \param folder The \c Folder of the messages + * \param item The \c FolderItem of the messages + * \param msglist The list of \c MsgInfos for which the flags should + * be returned + * \param msgflags A \c GRelation for tuples of (MsgInfo, new permanent + * flags for MsgInfo). Add tuples for the messages in msglist + * \return 0 on success, a negative number otherwise + */ + gint (*get_flags) (Folder *folder, + FolderItem *item, + MsgInfoList *msglist, + GRelation *msgflags); }; struct _FolderItem @@ -353,15 +668,19 @@ void folder_set_ui_func (Folder *folder, gpointer data); void folder_set_name (Folder *folder, const gchar *name); +void folder_set_sort (Folder *folder, + guint sort); void folder_tree_destroy (Folder *folder); void folder_add (Folder *folder); +void folder_remove (Folder *folder); GList *folder_get_list (void); gint folder_read_list (void); void folder_write_list (void); void folder_scan_tree (Folder *folder); FolderItem *folder_create_folder(FolderItem *parent, const gchar *name); +gint folder_item_rename (FolderItem *item, gchar *newname); void folder_update_op_count (void); void folder_func_to_all_folders (FolderItemFunc function, gpointer data); @@ -377,6 +696,8 @@ Folder *folder_find_from_name (const gchar *name, FolderClass *klass); FolderItem *folder_find_item_from_path (const gchar *path); FolderClass *folder_get_class_from_string (const gchar *str); +FolderItem *folder_find_child_item_by_name (FolderItem *item, + const gchar *name); gchar *folder_get_identifier (Folder *folder); gchar *folder_item_get_identifier (FolderItem *item); FolderItem *folder_find_item_from_identifier (const gchar *identifier); diff --git a/src/foldersel.c b/src/foldersel.c index 1e5138c16..893a5d768 100644 --- a/src/foldersel.c +++ b/src/foldersel.c @@ -1,6 +1,6 @@ /* * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2003 Hiroyuki Yamamoto + * Copyright (C) 1999-2004 Hiroyuki Yamamoto * * 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 @@ -60,6 +60,7 @@ static GtkWidget *ok_button; static GtkWidget *cancel_button; static FolderItem *folder_item; +static FolderItem *selected_item; static gboolean cancelled; static gboolean finished; @@ -97,6 +98,8 @@ FolderItem *foldersel_folder_sel(Folder *cur_folder, { GtkCTreeNode *node; + selected_item = NULL; + if (!window) { foldersel_create(); foldersel_init(); @@ -132,9 +135,11 @@ FolderItem *foldersel_folder_sel(Folder *cur_folder, gtk_entry_set_text(GTK_ENTRY(entry), ""); gtk_clist_clear(GTK_CLIST(ctree)); - if (!cancelled && folder_item && folder_item->path) + if (!cancelled && + selected_item && selected_item->path) { + folder_item = selected_item; return folder_item; - else + } else return NULL; } @@ -146,11 +151,10 @@ static void foldersel_create(void) window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(window), _("Select folder")); - gtk_widget_set_size_request(window, 300, 400); - gtk_container_set_border_width(GTK_CONTAINER(window), BORDER_WIDTH); + gtk_container_set_border_width(GTK_CONTAINER(window), 4); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); gtk_window_set_modal(GTK_WINDOW(window), TRUE); - gtk_window_set_policy(GTK_WINDOW(window), TRUE, TRUE, TRUE); + gtk_window_set_policy(GTK_WINDOW(window), FALSE, TRUE, FALSE); gtk_window_set_wmclass (GTK_WINDOW(window), "folder_selection", "Sylpheed"); g_signal_connect(G_OBJECT(window), "delete_event", @@ -163,6 +167,7 @@ static void foldersel_create(void) gtk_container_add(GTK_CONTAINER(window), vbox); scrolledwin = gtk_scrolled_window_new(NULL, NULL); + gtk_widget_set_size_request(window, 300, 360); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); gtk_box_pack_start(GTK_BOX(vbox), scrolledwin, TRUE, TRUE, 0); @@ -185,6 +190,7 @@ static void foldersel_create(void) G_CALLBACK(foldersel_selected), NULL); entry = gtk_entry_new(); + gtk_entry_set_editable(GTK_ENTRY(entry), FALSE); gtk_box_pack_start(GTK_BOX(vbox), entry, FALSE, FALSE, 0); g_signal_connect(G_OBJECT(entry), "activate", G_CALLBACK(foldersel_activated), NULL); @@ -192,7 +198,7 @@ static void foldersel_create(void) gtkut_button_set_create(&confirm_area, &ok_button, _("OK"), &cancel_button, _("Cancel"), - NULL, NULL); + NULL, NULL); gtk_box_pack_end(GTK_BOX(vbox), confirm_area, FALSE, FALSE, 0); gtk_widget_grab_default(ok_button); @@ -307,12 +313,16 @@ static void foldersel_set_tree(Folder *cur_folder, FolderSelectionType type) static void foldersel_selected(GtkCList *clist, gint row, gint column, GdkEvent *event, gpointer data) { - FolderItem *item; GdkEventButton *ev = (GdkEventButton *)event; - item = gtk_clist_get_row_data(clist, row); - if (item) gtk_entry_set_text(GTK_ENTRY(entry), - item->path ? item->path : ""); + selected_item = gtk_clist_get_row_data(clist, row); + if (selected_item && selected_item->path) { + gchar *id; + id = folder_item_get_identifier(selected_item); + gtk_entry_set_text(GTK_ENTRY(entry), id); + g_free(id); + } else + gtk_entry_set_text(GTK_ENTRY(entry), ""); if (ev && GDK_2BUTTON_PRESS == ev->type) gtk_button_clicked(GTK_BUTTON(ok_button)); @@ -320,13 +330,6 @@ static void foldersel_selected(GtkCList *clist, gint row, gint column, static void foldersel_ok(GtkButton *button, gpointer data) { - GList *list; - - list = GTK_CLIST(ctree)->selection; - if (list) - folder_item = gtk_ctree_node_get_row_data - (GTK_CTREE(ctree), GTK_CTREE_NODE(list->data)); - finished = TRUE; } diff --git a/src/folderutils.c b/src/folderutils.c index 099631b7b..039637284 100644 --- a/src/folderutils.c +++ b/src/folderutils.c @@ -23,16 +23,21 @@ #include "prefs_common.h" #include "folderutils.h" -void folderutils_delete_duplicates(FolderItem *item) +gint folderutils_delete_duplicates(FolderItem *item, + DeleteDuplicatesMode mode) { GHashTable *table; GSList *msglist, *cur, *duplist = NULL; - + guint dups; + + if (item->folder->klass->remove_msg == NULL) + return -1; + debug_print("Deleting duplicated messages...\n"); msglist = folder_item_get_msg_list(item); if (msglist == NULL) - return; + return 0; table = g_hash_table_new(g_str_hash, g_str_equal); for (cur = msglist; cur != NULL; cur = g_slist_next(cur)) { @@ -56,22 +61,31 @@ void folderutils_delete_duplicates(FolderItem *item) } } - if (prefs_common.immediate_exec) { - FolderItem *trash = item->folder->trash; + if (duplist) { + switch (mode) { + case DELETE_DUPLICATES_REMOVE: { + FolderItem *trash = item->folder->trash; - if (item->stype == F_TRASH || trash == NULL) - folder_item_remove_msgs(item, duplist); - else - folder_item_move_msgs(trash, duplist); - } else { - for (cur = duplist; cur != NULL; cur = g_slist_next(cur)) { - MsgInfo *msginfo = (MsgInfo *) cur->data; + if (item->stype == F_TRASH || trash == NULL) + folder_item_remove_msgs(item, duplist); + else + folder_item_move_msgs(trash, duplist); + break; + } + case DELETE_DUPLICATES_SETFLAG: + for (cur = duplist; cur != NULL; cur = g_slist_next(cur)) { + MsgInfo *msginfo = (MsgInfo *) cur->data; - procmsg_msginfo_set_to_folder(msginfo, NULL); - procmsg_msginfo_unset_flags(msginfo, MSG_MARKED, MSG_MOVE | MSG_COPY); - procmsg_msginfo_set_flags(msginfo, MSG_DELETED, 0); + procmsg_msginfo_set_to_folder(msginfo, NULL); + procmsg_msginfo_unset_flags(msginfo, MSG_MARKED, MSG_MOVE | MSG_COPY); + procmsg_msginfo_set_flags(msginfo, MSG_DELETED, 0); + } + break; + default: + break; } } + dups = g_slist_length(duplist); g_slist_free(duplist); g_hash_table_destroy(table); @@ -83,6 +97,30 @@ void folderutils_delete_duplicates(FolderItem *item) } g_slist_free(msglist); - debug_print("done.\n"); + + return dups; +} + +void folderutils_mark_all_read(FolderItem *item) +{ + MsgInfoList *msglist, *cur; + + g_return_if_fail(item != NULL); + + msglist = folder_item_get_msg_list(item); + if (msglist == NULL) + return; + + folder_item_update_freeze(); + for (cur = msglist; cur != NULL; cur = g_slist_next(cur)) { + MsgInfo *msginfo = cur->data; + + if (msginfo->flags.perm_flags & (MSG_NEW | MSG_UNREAD)) + procmsg_msginfo_unset_flags(msginfo, MSG_NEW | MSG_UNREAD, 0); + procmsg_msginfo_free(msginfo); + } + folder_item_update_thaw(); + + g_slist_free(msglist); } diff --git a/src/folderutils.h b/src/folderutils.h index 2c2d96b87..7fdb1e87c 100644 --- a/src/folderutils.h +++ b/src/folderutils.h @@ -20,8 +20,15 @@ #ifndef FOLDERUTILS_H #define FOLDERUTILS_H 1 +typedef enum { + DELETE_DUPLICATES_REMOVE, + DELETE_DUPLICATES_SETFLAG, +} DeleteDuplicatesMode; + #include "folder.h" -void folderutils_delete_duplicates(FolderItem *item); +gint folderutils_delete_duplicates(FolderItem *item, + DeleteDuplicatesMode mode); +void folderutils_mark_all_read (FolderItem *item); #endif /* FOLDERUTILS_H */ diff --git a/src/folderview.c b/src/folderview.c index 71caae308..ba7cbefad 100644 --- a/src/folderview.c +++ b/src/folderview.c @@ -44,7 +44,6 @@ #include "summaryview.h" #include "summary_search.h" #include "inputdialog.h" -#include "grouplistdialog.h" #include "manage_window.h" #include "alertpanel.h" #include "menu.h" @@ -62,6 +61,7 @@ #include "inc.h" #include "statusbar.h" #include "hooks.h" +#include "folderutils.h" typedef enum { @@ -143,15 +143,9 @@ static void folderview_append_folder (FolderView *folderview, static void folderview_update_node (FolderView *folderview, GtkCTreeNode *node); -static GtkCTreeNode *folderview_find_by_name (GtkCTree *ctree, - GtkCTreeNode *node, - const gchar *name); - static gint folderview_clist_compare (GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2); -static gint folderview_compare_name (gconstpointer a, - gconstpointer b); /* callback functions */ static gboolean folderview_button_pressed (GtkWidget *ctree, @@ -180,56 +174,9 @@ static void folderview_col_resized (GtkCList *clist, gint width, FolderView *folderview); -static void folderview_download_cb (FolderView *folderview, - guint action, - GtkWidget *widget); - -static void folderview_update_tree_cb (FolderView *folderview, - guint action, - GtkWidget *widget); - static void mark_all_read_cb (FolderView *folderview, guint action, GtkWidget *widget); -static void folderview_new_folder_cb (FolderView *folderview, - guint action, - GtkWidget *widget); -#if 0 -static void folderview_new_mbox_folder_cb(FolderView *folderview, - guint action, - GtkWidget *widget); -#endif -static void folderview_rename_folder_cb (FolderView *folderview, - guint action, - GtkWidget *widget); -#if 0 -static void folderview_rename_mbox_folder_cb(FolderView *folderview, - guint action, - GtkWidget *widget); -#endif -static void folderview_delete_folder_cb (FolderView *folderview, - guint action, - GtkWidget *widget); -static void folderview_remove_mailbox_cb(FolderView *folderview, - guint action, - GtkWidget *widget); - -static void folderview_new_imap_folder_cb(FolderView *folderview, - guint action, - GtkWidget *widget); -static void folderview_rm_imap_server_cb (FolderView *folderview, - guint action, - GtkWidget *widget); - -static void folderview_new_news_group_cb(FolderView *folderview, - guint action, - GtkWidget *widget); -static void folderview_rm_news_group_cb (FolderView *folderview, - guint action, - GtkWidget *widget); -static void folderview_rm_news_server_cb(FolderView *folderview, - guint action, - GtkWidget *widget); static void folderview_search_cb (FolderView *folderview, guint action, @@ -273,96 +220,84 @@ void folderview_create_folder_node (FolderView *folderview, FolderItem *item); gboolean folderview_update_folder (gpointer source, gpointer userdata); -gboolean folderview_update_item (gpointer source, +gboolean folderview_update_item_claws (gpointer source, gpointer data); - static void folderview_processing_cb(FolderView *folderview, guint action, GtkWidget *widget); -static void folderview_move_to(FolderView *folderview, FolderItem *from_folder, - FolderItem *to_folder); -static void folderview_move_to_cb(FolderView *folderview); - -#if 0 -static GtkItemFactoryEntry folderview_mbox_popup_entries[] = -{ - {N_("/Create _new folder..."), NULL, folderview_new_mbox_folder_cb, 0, NULL}, - {N_("/_Rename folder..."), NULL, folderview_rename_mbox_folder_cb, 0, NULL}, - {N_("/M_ove folder..."), NULL, folderview_move_to_cb, 0, NULL}, - {N_("/_Delete folder"), NULL, folderview_delete_folder_cb, 0, NULL}, - {N_("/---"), NULL, NULL, 0, ""}, - {N_("/Remove _mailbox"), NULL, folderview_remove_mailbox_cb, 0, NULL}, - {N_("/---"), NULL, NULL, 0, ""}, - {N_("/_Properties..."), NULL, NULL, 0, NULL}, - {N_("/_Processing..."), NULL, folderview_processing_cb, 0, NULL}, -}; -#endif -static GtkItemFactoryEntry folderview_mail_popup_entries[] = +GHashTable *folderview_popups; + +static GtkItemFactoryEntry folderview_common_popup_entries[] = { {N_("/Mark all _read"), NULL, mark_all_read_cb, 0, NULL}, - {N_("/---"), NULL, NULL, 0, ""}, - {N_("/Create _new folder..."), NULL, folderview_new_folder_cb, 0, NULL}, - {N_("/_Rename folder..."), NULL, folderview_rename_folder_cb, 0, NULL}, - {N_("/M_ove folder..."), NULL, folderview_move_to_cb, 0, NULL}, - {N_("/_Delete folder"), NULL, folderview_delete_folder_cb, 0, NULL}, - {N_("/---"), NULL, NULL, 0, ""}, - {N_("/_Check for new messages"), - NULL, folderview_update_tree_cb, 0, NULL}, - {N_("/R_ebuild folder tree"), NULL, folderview_update_tree_cb, 1, NULL}, - {N_("/---"), NULL, NULL, 0, ""}, - {N_("/Remove _mailbox"), NULL, folderview_remove_mailbox_cb, 0, NULL}, - {N_("/---"), NULL, NULL, 0, ""}, {N_("/_Search folder..."), NULL, folderview_search_cb, 0, NULL}, {N_("/_Properties..."), NULL, folderview_property_cb, 0, NULL}, {N_("/_Processing..."), NULL, folderview_processing_cb, 0, NULL}, }; -static GtkItemFactoryEntry folderview_imap_popup_entries[] = +GtkTargetEntry folderview_drag_types[] = { - {N_("/Mark all _read"), NULL, mark_all_read_cb, 0, NULL}, - {N_("/---"), NULL, NULL, 0, ""}, - {N_("/Create _new folder..."), NULL, folderview_new_imap_folder_cb, 0, NULL}, - {N_("/_Rename folder..."), NULL, folderview_rename_folder_cb, 0, NULL}, - {N_("/M_ove folder..."), NULL, folderview_move_to_cb, 0, NULL}, - {N_("/_Delete folder"), NULL, folderview_delete_folder_cb, 0, NULL}, - {N_("/---"), NULL, NULL, 0, ""}, - {N_("/Down_load"), NULL, folderview_download_cb, 0, NULL}, - {N_("/---"), NULL, NULL, 0, ""}, - {N_("/_Check for new messages"), - NULL, folderview_update_tree_cb, 0, NULL}, - {N_("/R_ebuild folder tree"), NULL, folderview_update_tree_cb, 1, NULL}, - {N_("/---"), NULL, NULL, 0, ""}, - {N_("/Remove _IMAP4 account"), NULL, folderview_rm_imap_server_cb, 0, NULL}, - {N_("/---"), NULL, NULL, 0, ""}, - {N_("/_Search folder..."), NULL, folderview_search_cb, 0, NULL}, - {N_("/_Properties..."), NULL, folderview_property_cb, 0, NULL}, - {N_("/_Processing..."), NULL, folderview_processing_cb, 0, NULL}, + {"text/plain", GTK_TARGET_SAME_APP, TARGET_DUMMY} }; -static GtkItemFactoryEntry folderview_news_popup_entries[] = +void folderview_initialize(void) { - {N_("/Mark all _read"), NULL, mark_all_read_cb, 0, NULL}, - {N_("/---"), NULL, NULL, 0, ""}, - {N_("/_Subscribe to newsgroup..."), - NULL, folderview_new_news_group_cb, 0, NULL}, - {N_("/_Remove newsgroup"), NULL, folderview_rm_news_group_cb, 0, NULL}, - {N_("/---"), NULL, NULL, 0, ""}, - {N_("/Down_load"), NULL, folderview_download_cb, 0, NULL}, - {N_("/---"), NULL, NULL, 0, ""}, - {N_("/_Check for new messages"), - NULL, folderview_update_tree_cb, 0, NULL}, - {N_("/---"), NULL, NULL, 0, ""}, - {N_("/Remove _news account"), NULL, folderview_rm_news_server_cb, 0, NULL}, - {N_("/---"), NULL, NULL, 0, ""}, - {N_("/_Search folder..."), NULL, folderview_search_cb, 0, NULL}, - {N_("/_Properties..."), NULL, folderview_property_cb, 0, NULL}, - {N_("/_Processing..."), NULL, folderview_processing_cb, 0, NULL}, -}; + FolderViewPopup *fpopup; + guint i, n_entries; + GSList *entries = NULL; -GtkTargetEntry folderview_drag_types[] = + fpopup = g_new0(FolderViewPopup, 1); + + n_entries = sizeof(folderview_common_popup_entries) / + sizeof(folderview_common_popup_entries[0]); + for (i = 0; i < n_entries; i++) + entries = g_slist_append(entries, &folderview_common_popup_entries[i]); + + fpopup->klass = "common"; + fpopup->path = ""; + fpopup->entries = entries; + fpopup->set_sensitivity = NULL; + + folderview_popups = g_hash_table_new(g_str_hash, g_str_equal); + g_hash_table_insert(folderview_popups, "common", fpopup); +} + +static GtkItemFactory *create_ifactory(FolderView *folderview, FolderViewPopup *fpopup) { - {"text/plain", GTK_TARGET_SAME_APP, TARGET_DUMMY} -}; + GSList *entries; + GtkItemFactory *factory; + FolderViewPopup *fpopup_common; + GtkWidget *popup; + + factory = gtk_item_factory_new(GTK_TYPE_MENU, fpopup->path, NULL); + gtk_item_factory_set_translate_func(factory, menu_translate, + NULL, NULL); + + for (entries = fpopup->entries; entries != NULL; entries = g_slist_next(entries)) + gtk_item_factory_create_item(factory, entries->data, folderview, 1); + + fpopup_common = g_hash_table_lookup(folderview_popups, "common"); + if (fpopup_common != fpopup) + for (entries = fpopup_common->entries; entries != NULL; entries = g_slist_next(entries)) + gtk_item_factory_create_item(factory, entries->data, folderview, 1); + + popup = gtk_item_factory_get_widget(factory, fpopup->path); + gtk_signal_connect(GTK_OBJECT(popup), "selection_done", + GTK_SIGNAL_FUNC(folderview_popup_close), + folderview); + + return factory; +} + +static void create_ifactories(gpointer key, gpointer value, gpointer data) +{ + FolderView *folderview = data; + FolderViewPopup *fpopup = value; + GtkItemFactory *factory; + + factory = create_ifactory(folderview, fpopup); + g_hash_table_insert(folderview->popups, fpopup->klass, factory); +} FolderView *folderview_create(void) { @@ -370,19 +305,6 @@ FolderView *folderview_create(void) GtkWidget *scrolledwin; GtkWidget *ctree; gchar *titles[N_FOLDER_COLS]; - GtkWidget *mail_popup; - GtkWidget *news_popup; - GtkWidget *imap_popup; -#if 0 - GtkWidget *mbox_popup; -#endif - GtkItemFactory *mail_factory; - GtkItemFactory *news_factory; - GtkItemFactory *imap_factory; -#if 0 - GtkItemFactory *mbox_factory; -#endif - gint n_entries; gint i; debug_print("Creating folder view...\n"); @@ -428,38 +350,15 @@ FolderView *folderview_create(void) gtk_ctree_set_indent(GTK_CTREE(ctree), CTREE_INDENT); gtk_clist_set_compare_func(GTK_CLIST(ctree), folderview_clist_compare); + /* create popup factories */ + folderview->popups = g_hash_table_new(g_str_hash, g_str_equal); + g_hash_table_foreach(folderview_popups, create_ifactories, folderview); + /* don't let title buttons take key focus */ for (i = 0; i < N_FOLDER_COLS; i++) GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(ctree)->column[i].button, GTK_CAN_FOCUS); - /* popup menu */ - n_entries = sizeof(folderview_mail_popup_entries) / - sizeof(folderview_mail_popup_entries[0]); - mail_popup = menu_create_items(folderview_mail_popup_entries, - n_entries, - "", &mail_factory, - folderview); - n_entries = sizeof(folderview_imap_popup_entries) / - sizeof(folderview_imap_popup_entries[0]); - imap_popup = menu_create_items(folderview_imap_popup_entries, - n_entries, - "", &imap_factory, - folderview); - n_entries = sizeof(folderview_news_popup_entries) / - sizeof(folderview_news_popup_entries[0]); - news_popup = menu_create_items(folderview_news_popup_entries, - n_entries, - "", &news_factory, - folderview); -#if 0 - n_entries = sizeof(folderview_mbox_popup_entries) / - sizeof(folderview_mbox_popup_entries[0]); - mbox_popup = menu_create_items(folderview_mbox_popup_entries, - n_entries, - "", &mbox_factory, - folderview); -#endif g_signal_connect(G_OBJECT(ctree), "key_press_event", G_CALLBACK(folderview_key_pressed), @@ -489,21 +388,6 @@ FolderView *folderview_create(void) G_CALLBACK(folderview_col_resized), folderview); - g_signal_connect(G_OBJECT(mail_popup), "selection_done", - G_CALLBACK(folderview_popup_close), - folderview); - g_signal_connect(G_OBJECT(imap_popup), "selection_done", - G_CALLBACK(folderview_popup_close), - folderview); - g_signal_connect(G_OBJECT(news_popup), "selection_done", - G_CALLBACK(folderview_popup_close), - folderview); -#if 0 - g_signal_connect(G_OBJECT(mbox_popup), "selection_done", - G_CALLBACK(folderview_popup_close), - folderview); -#endif - /* drop callback */ gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT, summary_drag_types, 1, @@ -523,21 +407,11 @@ FolderView *folderview_create(void) folderview->scrolledwin = scrolledwin; folderview->ctree = ctree; - folderview->mail_popup = mail_popup; - folderview->mail_factory = mail_factory; - folderview->imap_popup = imap_popup; - folderview->imap_factory = imap_factory; - folderview->news_popup = news_popup; - folderview->news_factory = news_factory; -#if 0 - folderview->mbox_popup = mbox_popup; - folderview->mbox_factory = mbox_factory; -#endif folderview->folder_update_callback_id = hooks_register_hook(FOLDER_UPDATE_HOOKLIST, folderview_update_folder, (gpointer) folderview); folderview->folder_item_update_callback_id = - hooks_register_hook(FOLDER_ITEM_UPDATE_HOOKLIST, folderview_update_item, (gpointer) folderview); + hooks_register_hook(FOLDER_ITEM_UPDATE_HOOKLIST, folderview_update_item_claws, (gpointer) folderview); gtk_widget_show_all(scrolledwin); @@ -689,8 +563,13 @@ void folderview_select(FolderView *folderview, FolderItem *item) static void mark_all_read_cb(FolderView *folderview, guint action, GtkWidget *widget) { - if (folderview->selected) - summary_mark_all_read(folderview->summaryview); + FolderItem *item; + + item = folderview_get_selected(folderview); + if (item == NULL) + return; + + folderutils_mark_all_read(item); } static void folderview_select_node(FolderView *folderview, GtkCTreeNode *node) @@ -783,6 +662,48 @@ void folderview_update_msg_num(FolderView *folderview, GtkCTreeNode *row) folderview_update_node(folderview, row); } +void folderview_append_item(FolderItem *item) +{ + GList *list; + + g_return_if_fail(item != NULL); + g_return_if_fail(item->folder != NULL); + if (folder_item_parent(item)) return; + + for (list = folderview_list; list != NULL; list = list->next) { + FolderView *folderview = (FolderView *)list->data; + GtkCTree *ctree = GTK_CTREE(folderview->ctree); + GtkCTreeNode *node, *child; + + node = gtk_ctree_find_by_row_data(ctree, NULL, + folder_item_parent(item)); + if (node) { + child = gtk_ctree_find_by_row_data(ctree, node, item); + if (!child) { + gchar *text[N_FOLDER_COLS] = + {NULL, "0", "0", "0"}; + + gtk_clist_freeze(GTK_CLIST(ctree)); + + text[COL_FOLDER] = item->name; + child = gtk_ctree_insert_node + (ctree, node, NULL, text, + FOLDER_SPACING, + folderxpm, folderxpmmask, + folderopenxpm, folderopenxpmmask, + FALSE, FALSE); + gtk_ctree_node_set_row_data(ctree, child, item); + gtk_ctree_expand(ctree, node); + folderview_update_node(folderview, child); + folderview_sort_folders(folderview, node, + item->folder); + + gtk_clist_thaw(GTK_CLIST(ctree)); + } + } + } +} + static void folderview_set_folders(FolderView *folderview) { GList *list; @@ -1235,7 +1156,32 @@ static void folderview_update_node(FolderView *folderview, GtkCTreeNode *node) folderview_update_node(folderview, node); } -gboolean folderview_update_item(gpointer source, gpointer data) +#if !CLAWS /* keep it here for syncs */ +void folderview_update_item(FolderItem *item, gboolean update_summary) +{ + GList *list; + FolderView *folderview; + GtkCTree *ctree; + GtkCTreeNode *node; + + g_return_if_fail(item != NULL); + + for (list = folderview_list; list != NULL; list = list->next) { + folderview = (FolderView *)list->data; + ctree = GTK_CTREE(folderview->ctree); + + node = gtk_ctree_find_by_row_data(ctree, NULL, item); + if (node) { + folderview_update_node(folderview, node); + if (update_summary && folderview->opened == node) + summary_show(folderview->summaryview, + item, FALSE); + } + } +} +#endif + +gboolean folderview_update_item_claws(gpointer source, gpointer data) { FolderItemUpdateData *update_info = (FolderItemUpdateData *)source; FolderView *folderview = (FolderView *)data; @@ -1250,7 +1196,7 @@ gboolean folderview_update_item(gpointer source, gpointer data) node = gtk_ctree_find_by_row_data(ctree, NULL, update_info->item); if (node) { - if (update_info->update_flags & F_ITEM_UPDATE_MSGCNT) + if (update_info->update_flags & (F_ITEM_UPDATE_MSGCNT | F_ITEM_UPDATE_NAME)) folderview_update_node(folderview, node); if ((update_info->update_flags & F_ITEM_UPDATE_CONTENT) && (folderview->opened == node)) summary_show(folderview->summaryview, update_info->item); @@ -1259,6 +1205,26 @@ gboolean folderview_update_item(gpointer source, gpointer data) return FALSE; } +static void folderview_update_item_foreach_func(gpointer key, gpointer val, + gpointer data) +{ + /* CLAWS: share this joy with other hook functions ... */ + folder_item_update((FolderItem *)key, + (FolderItemUpdateFlags)GPOINTER_TO_INT(data)); +} + +void folderview_update_item_foreach(GHashTable *table, gboolean update_summary) +{ + GList *list; + FolderItemUpdateFlags flags; + + flags = update_summary ? F_ITEM_UPDATE_CONTENT | F_ITEM_UPDATE_MSGCNT + : 0; + for (list = folderview_list; list != NULL; list = list->next) + g_hash_table_foreach(table, folderview_update_item_foreach_func, + GINT_TO_POINTER(flags)); +} + static gboolean folderview_gnode_func(GtkCTree *ctree, guint depth, GNode *gnode, GtkCTreeNode *cnode, gpointer data) @@ -1291,36 +1257,37 @@ static void folderview_expand_func(GtkCTree *ctree, GtkCTreeNode *node, } } -#define SET_SPECIAL_FOLDER(ctree, item) \ -{ \ - if (item) { \ - GtkCTreeNode *node, *parent, *sibling; \ - \ - node = gtk_ctree_find_by_row_data(ctree, root, item); \ - if (!node) \ - g_warning("%s not found.\n", item->path); \ - else { \ - parent = GTK_CTREE_ROW(node)->parent; \ - if (prev && parent == GTK_CTREE_ROW(prev)->parent) \ - sibling = GTK_CTREE_ROW(prev)->sibling; \ - else \ - sibling = GTK_CTREE_ROW(parent)->children; \ - while (sibling) { \ - FolderItem *tmp; \ - \ - tmp = gtk_ctree_node_get_row_data \ - (ctree, sibling); \ - if (tmp->stype != F_NORMAL) \ - sibling = GTK_CTREE_ROW(sibling)->sibling; \ - else \ - break; \ - } \ - if (node != sibling) \ - gtk_ctree_move(ctree, node, parent, sibling); \ - } \ - \ - prev = node; \ - } \ +static void set_special_folder(GtkCTree *ctree, FolderItem *item, + GtkCTreeNode *root, GtkCTreeNode **prev) +{ + if (item) { + GtkCTreeNode *node, *parent, *sibling; + + node = gtk_ctree_find_by_row_data(ctree, root, item); + if (!node) + g_warning("%s not found.\n", item->path); + else { + parent = GTK_CTREE_ROW(node)->parent; + if (*prev && parent == GTK_CTREE_ROW(*prev)->parent) + sibling = GTK_CTREE_ROW(*prev)->sibling; + else + sibling = GTK_CTREE_ROW(parent)->children; + while (sibling) { + FolderItem *tmp; + + tmp = gtk_ctree_node_get_row_data + (ctree, sibling); + if (tmp->stype != F_NORMAL) + sibling = GTK_CTREE_ROW(sibling)->sibling; + else + break; + } + if (node != sibling) + gtk_ctree_move(ctree, node, parent, sibling); + } + + *prev = node; + } } static void folderview_sort_folders(FolderView *folderview, GtkCTreeNode *root, @@ -1333,11 +1300,11 @@ static void folderview_sort_folders(FolderView *folderview, GtkCTreeNode *root, if (root && GTK_CTREE_ROW(root)->parent) return; - SET_SPECIAL_FOLDER(ctree, folder->inbox); - SET_SPECIAL_FOLDER(ctree, folder->outbox); - SET_SPECIAL_FOLDER(ctree, folder->draft); - SET_SPECIAL_FOLDER(ctree, folder->queue); - SET_SPECIAL_FOLDER(ctree, folder->trash); + set_special_folder(ctree, folder->inbox, root, &prev); + set_special_folder(ctree, folder->outbox, root, &prev); + set_special_folder(ctree, folder->draft, root, &prev); + set_special_folder(ctree, folder->queue, root, &prev); + set_special_folder(ctree, folder->trash, root, &prev); } static void folderview_append_folder(FolderView *folderview, Folder *folder) @@ -1354,95 +1321,6 @@ static void folderview_append_folder(FolderView *folderview, Folder *folder) folderview_sort_folders(folderview, root, folder); } -void folderview_new_folder(FolderView *folderview) -{ - GtkCTree *ctree = GTK_CTREE(folderview->ctree); - FolderItem *item; - - if (!folderview->selected) return; - - item = gtk_ctree_node_get_row_data(ctree, folderview->selected); - g_return_if_fail(item != NULL); - g_return_if_fail(item->folder != NULL); - - switch (FOLDER_TYPE(item->folder)) { -#if 0 - case F_MBOX: - folderview_new_mbox_folder_cb(folderview, 0, NULL); - break; -#endif - case F_MH: - case F_MAILDIR: - folderview_new_folder_cb(folderview, 0, NULL); - break; - case F_IMAP: - folderview_new_imap_folder_cb(folderview, 0, NULL); - break; - case F_NEWS: - default: - break; - } -} - -void folderview_rename_folder(FolderView *folderview) -{ - GtkCTree *ctree = GTK_CTREE(folderview->ctree); - FolderItem *item; - - if (!folderview->selected) return; - - item = gtk_ctree_node_get_row_data(ctree, folderview->selected); - g_return_if_fail(item != NULL); - g_return_if_fail(item->folder != NULL); - if (!item->path) return; - if (item->stype != F_NORMAL) return; - - switch (FOLDER_TYPE(item->folder)) { -#if 0 - case F_MBOX: - folderview_rename_mbox_folder_cb(folderview, 0, NULL); - break; -#endif - case F_MH: - case F_MAILDIR: - case F_IMAP: - folderview_rename_folder_cb(folderview, 0, NULL); - break; - case F_NEWS: - default: - break; - } -} - -void folderview_delete_folder(FolderView *folderview) -{ - GtkCTree *ctree = GTK_CTREE(folderview->ctree); - FolderItem *item; - - if (!folderview->selected) return; - - item = gtk_ctree_node_get_row_data(ctree, folderview->selected); - g_return_if_fail(item != NULL); - g_return_if_fail(item->folder != NULL); - if (!item->path) return; - if (item->stype != F_NORMAL) return; - - switch (FOLDER_TYPE(item->folder)) { - case F_MH: -#if 0 - case F_MBOX: -#endif - case F_MAILDIR: - case F_IMAP: - folderview_delete_folder_cb(folderview, 0, NULL); - break; - case F_NEWS: - default: - break; - } -} - - /* callback functions */ static gboolean folderview_button_pressed(GtkWidget *ctree, GdkEventButton *event, @@ -1452,20 +1330,9 @@ static gboolean folderview_button_pressed(GtkWidget *ctree, GdkEventButton *even gint prev_row = -1, row = -1, column = -1; FolderItem *item; Folder *folder; + FolderViewPopup *fpopup; + GtkItemFactory *fpopup_factory; GtkWidget *popup; - gboolean mark_all_read = FALSE; - gboolean new_folder = FALSE; - gboolean rename_folder = FALSE; - gboolean move_folder = FALSE; - gboolean delete_folder = FALSE; - gboolean download_msg = FALSE; - gboolean update_tree = FALSE; - gboolean rescan_tree = FALSE; - gboolean remove_tree = FALSE; - gboolean search_folder = FALSE; - gboolean folder_property = FALSE; - gboolean folder_processing = FALSE; - gboolean folder_scoring = FALSE; if (!event) return FALSE; @@ -1507,106 +1374,28 @@ static gboolean folderview_button_pressed(GtkWidget *ctree, GdkEventButton *even g_return_val_if_fail(item->folder != NULL, FALSE); folder = item->folder; - if (folderview->mainwin->lock_count == 0) { - new_folder = TRUE; - if (folder_item_parent(item) == NULL) { - update_tree = remove_tree = TRUE; - if (folder->account) - folder_property = TRUE; - } else - mark_all_read = search_folder = folder_property = TRUE; - - if (FOLDER_IS_LOCAL(folder) || FOLDER_TYPE(folder) == F_IMAP /* || FOLDER_TYPE(folder) == F_MBOX */) { - if (folder_item_parent(item) == NULL) - update_tree = rescan_tree = TRUE; - else if (item->stype == F_NORMAL) - move_folder = rename_folder = delete_folder = folder_scoring = folder_processing = TRUE; - else if (item->stype == F_INBOX) - folder_scoring = folder_processing = TRUE; - else if (item->stype == F_TRASH) - folder_processing = TRUE; - else if (item->stype == F_OUTBOX) - folder_processing = TRUE; - if (0 == item->total_msgs) - search_folder = FALSE; - } else if (FOLDER_TYPE(folder) == F_NEWS) { - if (folder_item_parent(item) != NULL) - delete_folder = folder_scoring = folder_processing = TRUE; - } - if (FOLDER_TYPE(folder) == F_IMAP || - FOLDER_TYPE(folder) == F_NEWS) { - if (folder_item_parent(item) != NULL && - item->no_select == FALSE && - !prefs_common.work_offline) - download_msg = TRUE; - } - if (item->unread_msgs < 1) - mark_all_read = FALSE; + fpopup = g_hash_table_lookup(folderview_popups, folder->klass->idstr); + if (fpopup != NULL) + fpopup_factory = g_hash_table_lookup(folderview->popups, folder->klass->idstr); + else { + fpopup = g_hash_table_lookup(folderview_popups, "common"); + fpopup_factory = g_hash_table_lookup(folderview->popups, "common"); } -#define SET_SENS(factory, name, sens) \ - menu_set_sensitive(folderview->factory, name, sens) - - mark_all_read = mark_all_read && - (item == folderview->summaryview->folder_item); - - if (FOLDER_IS_LOCAL(folder)) { - popup = folderview->mail_popup; - menu_set_insensitive_all(GTK_MENU_SHELL(popup)); - SET_SENS(mail_factory, "/Mark all read", mark_all_read); - SET_SENS(mail_factory, "/Create new folder...", new_folder); - SET_SENS(mail_factory, "/Rename folder...", rename_folder); - SET_SENS(mail_factory, "/Move folder...", move_folder); - SET_SENS(mail_factory, "/Delete folder", delete_folder); - SET_SENS(mail_factory, "/Check for new messages", update_tree); - SET_SENS(mail_factory, "/Rebuild folder tree", rescan_tree); - SET_SENS(mail_factory, "/Remove mailbox", remove_tree); - SET_SENS(mail_factory, "/Search folder...", search_folder); - SET_SENS(mail_factory, "/Properties...", folder_property); - SET_SENS(mail_factory, "/Processing...", folder_processing); - } else if (FOLDER_TYPE(folder) == F_IMAP) { - popup = folderview->imap_popup; - menu_set_insensitive_all(GTK_MENU_SHELL(popup)); - SET_SENS(imap_factory, "/Mark all read", mark_all_read); - SET_SENS(imap_factory, "/Create new folder...", new_folder); - SET_SENS(imap_factory, "/Rename folder...", rename_folder); - SET_SENS(imap_factory, "/Move folder...", move_folder); - SET_SENS(imap_factory, "/Delete folder", delete_folder); - SET_SENS(imap_factory, "/Download", download_msg); - SET_SENS(imap_factory, "/Check for new messages", update_tree); - SET_SENS(imap_factory, "/Rebuild folder tree", rescan_tree); - SET_SENS(imap_factory, "/Remove IMAP4 account", remove_tree); - SET_SENS(imap_factory, "/Search folder...", search_folder); - SET_SENS(imap_factory, "/Properties...", folder_property); - SET_SENS(imap_factory, "/Processing...", folder_processing); - } else if (FOLDER_TYPE(folder) == F_NEWS) { - popup = folderview->news_popup; - menu_set_insensitive_all(GTK_MENU_SHELL(popup)); - SET_SENS(news_factory, "/Mark all read", mark_all_read); - SET_SENS(news_factory, "/Subscribe to newsgroup...", new_folder); - SET_SENS(news_factory, "/Remove newsgroup", delete_folder); - SET_SENS(news_factory, "/Download", download_msg); - SET_SENS(news_factory, "/Check for new messages", update_tree); - SET_SENS(news_factory, "/Remove news account", remove_tree); - SET_SENS(news_factory, "/Search folder...", search_folder); - SET_SENS(news_factory, "/Properties...", folder_property); - SET_SENS(news_factory, "/Processing...", folder_processing); -#if 0 - } else if (FOLDER_TYPE(folder) == F_MBOX) { - popup = folderview->mbox_popup; - menu_set_insensitive_all(GTK_MENU_SHELL(popup)); - SET_SENS(mbox_factory, "/Create new folder...", new_folder); - SET_SENS(mbox_factory, "/Rename folder...", rename_folder); - SET_SENS(mbox_factory, "/Move folder...", move_folder); - SET_SENS(mbox_factory, "/Delete folder", delete_folder); - SET_SENS(news_factory, "/Properties...", folder_property); - SET_SENS(mbox_factory, "/Processing...", folder_processing); -#endif - } else - return FALSE; + if (fpopup->set_sensitivity != NULL) + fpopup->set_sensitivity(fpopup_factory, item); + +#define SET_SENS(name, sens) \ + menu_set_sensitive(fpopup_factory, name, sens) + + SET_SENS("/Mark all read", item->unread_msgs >= 1); + SET_SENS("/Search folder...", item->total_msgs >= 1); + SET_SENS("/Properties...", TRUE); + SET_SENS("/Processing...", item->node->parent != NULL); #undef SET_SENS + popup = gtk_item_factory_get_widget(fpopup_factory, fpopup->path); gtk_menu_popup(GTK_MENU(popup), NULL, NULL, NULL, NULL, event->button, event->time); @@ -1783,7 +1572,7 @@ static void folderview_tree_collapsed(GtkCTree *ctree, GtkCTreeNode *node, item = gtk_ctree_node_get_row_data(ctree, node); g_return_if_fail(item != NULL); - item->collapsed= TRUE; + item->collapsed = TRUE; folderview_update_node(folderview, node); } @@ -1818,755 +1607,58 @@ static void folderview_col_resized(GtkCList *clist, gint column, gint width, } } -static GtkCTreeNode *folderview_find_by_name(GtkCTree *ctree, - GtkCTreeNode *node, - const gchar *name) +void folderview_create_folder_node_recursive(FolderView *folderview, FolderItem *item) { - FolderItem *item; - - if (!node) - node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list); - if (!node) - return NULL; - - node = GTK_CTREE_ROW(node)->children; + GNode *srcnode; - while (node) { - item = gtk_ctree_node_get_row_data(ctree, node); - if (!folderview_compare_name(item, name)) - return node; - node = GTK_CTREE_ROW(node)->sibling; + folderview_create_folder_node(folderview, item); + + srcnode = item->folder->node; + srcnode = g_node_find(srcnode, G_PRE_ORDER, G_TRAVERSE_ALL, item); + srcnode = srcnode->children; + while (srcnode != NULL) { + if (srcnode && srcnode->data) { + FolderItem *next_item = (FolderItem*) srcnode->data; + folderview_create_folder_node_recursive(folderview, next_item); + } + srcnode = srcnode->next; } - - return NULL; } -static void folderview_download_func(Folder *folder, FolderItem *item, - gpointer data) +void folderview_create_folder_node(FolderView *folderview, FolderItem *item) { - GList *list; + GtkCTree *ctree = GTK_CTREE(folderview->ctree); + gchar *text[N_FOLDER_COLS] = {NULL, "0", "0", "0"}; + GtkCTreeNode *node, *parent_node; + + parent_node = gtk_ctree_find_by_row_data(ctree, NULL, folder_item_parent(item)); + if (parent_node == NULL) + return; - for (list = folderview_list; list != NULL; list = list->next) { - FolderView *folderview = (FolderView *)list->data; - MainWindow *mainwin = folderview->mainwin; - gchar *str; + gtk_clist_freeze(GTK_CLIST(ctree)); - str = g_strdup_printf - (_("Downloading messages in %s ..."), item->path); - main_window_progress_set(mainwin, - GPOINTER_TO_INT(data), item->total_msgs); - STATUSBAR_PUSH(mainwin, str); - STATUSBAR_POP(mainwin); - g_free(str); - } + text[COL_FOLDER] = item->name; + node = gtk_ctree_insert_node(ctree, parent_node, NULL, text, + FOLDER_SPACING, + folderxpm, folderxpmmask, + folderopenxpm, folderopenxpmmask, + FALSE, FALSE); + gtk_ctree_expand(ctree, parent_node); + gtk_ctree_node_set_row_data(ctree, node, item); + if (normal_style) + gtk_ctree_node_set_row_style(ctree, node, normal_style); + folderview_sort_folders(folderview, folderview->selected, item->folder); + + gtk_clist_thaw(GTK_CLIST(ctree)); +} + +static void folderview_search_cb(FolderView *folderview, guint action, + GtkWidget *widget) +{ + summary_search(folderview->summaryview); } -static void folderview_download_cb(FolderView *folderview, guint action, - GtkWidget *widget) -{ - GtkCTree *ctree = GTK_CTREE(folderview->ctree); - MainWindow *mainwin = folderview->mainwin; - FolderItem *item; - - if (!folderview->selected) return; - - item = gtk_ctree_node_get_row_data(ctree, folderview->selected); - g_return_if_fail(item != NULL); - g_return_if_fail(item->folder != NULL); -#if 0 - if (!prefs_common.online_mode) { - if (alertpanel(_("Offline"), - _("You are offline. Go online?"), - _("Yes"), _("No"), NULL) == G_ALERTDEFAULT) - main_window_toggle_online(folderview->mainwin, TRUE); - else - return; - } -#endif - main_window_cursor_wait(mainwin); - inc_lock(); - main_window_lock(mainwin); - gtk_widget_set_sensitive(folderview->ctree, FALSE); - main_window_progress_on(mainwin); - GTK_EVENTS_FLUSH(); - folder_set_ui_func(item->folder, folderview_download_func, NULL); - if (folder_item_fetch_all_msg(item) < 0) { - gchar *name; - - name = trim_string(item->name, 32); - alertpanel_error(_("Error occurred while downloading messages in `%s'."), name); - g_free(name); - } - folder_set_ui_func(item->folder, NULL, NULL); - main_window_progress_off(mainwin); - gtk_widget_set_sensitive(folderview->ctree, TRUE); - main_window_unlock(mainwin); - inc_unlock(); - main_window_cursor_normal(mainwin); -} - -static void folderview_update_tree_cb(FolderView *folderview, guint action, - GtkWidget *widget) -{ - GtkCTree *ctree = GTK_CTREE(folderview->ctree); - FolderItem *item; - - if (!folderview->selected) return; - - summary_show(folderview->summaryview, NULL); - - item = gtk_ctree_node_get_row_data(ctree, folderview->selected); - g_return_if_fail(item != NULL); - g_return_if_fail(item->folder != NULL); - - if (action == 0) - folderview_check_new(item->folder); - else - folderview_rescan_tree(item->folder); -} - -void folderview_create_folder_node_recursive(FolderView *folderview, FolderItem *item) -{ - GNode *srcnode; - - folderview_create_folder_node(folderview, item); - - srcnode = item->folder->node; - srcnode = g_node_find(srcnode, G_PRE_ORDER, G_TRAVERSE_ALL, item); - srcnode = srcnode->children; - while (srcnode != NULL) { - if (srcnode && srcnode->data) { - FolderItem *next_item = (FolderItem*) srcnode->data; - folderview_create_folder_node_recursive(folderview, next_item); - } - srcnode = srcnode->next; - } -} - -void folderview_create_folder_node(FolderView *folderview, FolderItem *item) -{ - GtkCTree *ctree = GTK_CTREE(folderview->ctree); - gchar *text[N_FOLDER_COLS] = {NULL, "0", "0", "0"}; - GtkCTreeNode *node, *parent_node; - - parent_node = gtk_ctree_find_by_row_data(ctree, NULL, folder_item_parent(item)); - if (parent_node == NULL) - return; - - gtk_clist_freeze(GTK_CLIST(ctree)); - - text[COL_FOLDER] = item->name; - node = gtk_ctree_insert_node(ctree, parent_node, NULL, text, - FOLDER_SPACING, - folderxpm, folderxpmmask, - folderopenxpm, folderopenxpmmask, - FALSE, FALSE); - gtk_ctree_expand(ctree, parent_node); - gtk_ctree_node_set_row_data(ctree, node, item); - if (normal_style) - gtk_ctree_node_set_row_style(ctree, node, normal_style); - folderview_sort_folders(folderview, folderview->selected, item->folder); - - gtk_clist_thaw(GTK_CLIST(ctree)); -} - -static void folderview_new_folder_cb(FolderView *folderview, guint action, - GtkWidget *widget) -{ - GtkCTree *ctree = GTK_CTREE(folderview->ctree); - FolderItem *item; - FolderItem *new_item; - gchar *new_folder; - gchar *name, *name_; - - if (!folderview->selected) return; - - item = gtk_ctree_node_get_row_data(ctree, folderview->selected); - g_return_if_fail(item != NULL); - g_return_if_fail(item->folder != NULL); - - new_folder = input_dialog(_("New folder"), - _("Input the name of new folder:"), - _("NewFolder")); - if (!new_folder) return; - - if (FOLDER_TYPE(item->folder) != F_MBOX) { - if (strchr(new_folder, G_DIR_SEPARATOR) != NULL) { - alertpanel_error(_("`%c' can't be included in folder name."), - G_DIR_SEPARATOR); - g_free(new_folder); - return; - } - } - - name_ = trim_string(new_folder, 32); - Xstrdup_a(name, name_, {g_free(new_folder); return;}); - g_free(name_); - - /* find whether the directory already exists */ - if (folderview_find_by_name(ctree, folderview->selected, new_folder)) { - alertpanel_error(_("The folder `%s' already exists."), name); - g_free(new_folder); - return; - } - - new_item = folder_create_folder(item, new_folder); - if (!new_item) { - alertpanel_error(_("Can't create the folder `%s'."), name); - g_free(new_folder); - return; - } - g_free(new_folder); - - folder_write_list(); -} - -#if 0 -static void folderview_new_mbox_folder_cb(FolderView *folderview, guint action, - GtkWidget *widget) -{ - GtkCTree *ctree = GTK_CTREE(folderview->ctree); - FolderItem *item; - FolderItem *new_item; - gchar *new_folder; - - if (!folderview->selected) return; - - item = gtk_ctree_node_get_row_data(ctree, folderview->selected); - g_return_if_fail(item != NULL); - g_return_if_fail(item->folder != NULL); - - new_folder = input_dialog(_("New folder"), - _("Input the name of new folder:"), - _("NewFolder")); - if (!new_folder) return; - - /* find whether the directory already exists */ - if (folderview_find_by_name(ctree, folderview->selected, new_folder)) { - alertpanel_error(_("The folder `%s' already exists."), - new_folder); - g_free(new_folder); - return; - } - - new_item = folder_create_folder(item, new_folder); - g_free(new_folder); - if (!new_item) return; - - folder_write_list(); -} -#endif - -static void folderview_rename_folder_cb(FolderView *folderview, guint action, - GtkWidget *widget) -{ - GtkCTree *ctree = GTK_CTREE(folderview->ctree); - FolderItem *item; - gchar *new_folder; - gchar *name, *name_; - gchar *message; - gchar *old_path; - gchar *old_id; - gchar *new_id; - - if (!folderview->selected) return; - - item = gtk_ctree_node_get_row_data(ctree, folderview->selected); - g_return_if_fail(item != NULL); - g_return_if_fail(item->path != NULL); - g_return_if_fail(item->folder != NULL); - - name_ = trim_string(item->name, 32); - Xstrdup_a(name, name_, return); - g_free(name_); - message = g_strdup_printf(_("Input new name for `%s':"), name); - new_folder = input_dialog(_("Rename folder"), message, - g_basename(item->path)); - g_free(message); - if (!new_folder) return; - - if (strchr(new_folder, G_DIR_SEPARATOR) != NULL) { - alertpanel_error(_("`%c' can't be included in folder name."), - G_DIR_SEPARATOR); - g_free(new_folder); - return; - } - - if (folderview_find_by_name - (ctree, GTK_CTREE_ROW(folderview->selected)->parent, - new_folder)) { - name = trim_string(new_folder, 32); - alertpanel_error(_("The folder `%s' already exists."), name); - g_free(name); - g_free(new_folder); - return; - } - - Xstrdup_a(old_path, item->path, {g_free(new_folder); return;}); - old_id = folder_item_get_identifier(item); - - if (item->folder->klass->rename_folder(item->folder, item, new_folder) < 0) { - g_free(old_id); - g_free(new_folder); - return; - } - g_free(new_folder); - - /* if (FOLDER_TYPE(item->folder) == F_MH) - prefs_filtering_rename_path(old_path, item->path); */ - new_id = folder_item_get_identifier(item); - prefs_filtering_rename_path(old_id, new_id); - - g_free(old_id); - g_free(new_id); - - gtk_clist_freeze(GTK_CLIST(ctree)); - - folderview_update_node(folderview, folderview->selected); - folderview_sort_folders(folderview, - GTK_CTREE_ROW(folderview->selected)->parent, - item->folder); - if (folderview->opened == folderview->selected || - gtk_ctree_is_ancestor(ctree, - folderview->selected, - folderview->opened)) { - GtkCTreeNode *node = folderview->opened; - folderview_unselect(folderview); - folderview_select_node(folderview, node); - } - - gtk_clist_thaw(GTK_CLIST(ctree)); - - folder_write_list(); -} - -#if 0 -static void folderview_rename_mbox_folder_cb(FolderView *folderview, - guint action, - GtkWidget *widget) -{ - GtkCTree *ctree = GTK_CTREE(folderview->ctree); - FolderItem *item; - gchar *new_folder; - gchar *message; - - if (!folderview->selected) return; - - item = gtk_ctree_node_get_row_data(ctree, folderview->selected); - g_return_if_fail(item != NULL); - g_return_if_fail(item->path != NULL); - g_return_if_fail(item->folder != NULL); - - message = g_strdup_printf(_("Input new name for `%s':"), - g_basename(item->path)); - new_folder = input_dialog(_("Rename folder"), message, - g_basename(item->path)); - g_free(message); - if (!new_folder) return; - - if (folderview_find_by_name - (ctree, GTK_CTREE_ROW(folderview->selected)->parent, - new_folder)) { - alertpanel_error(_("The folder `%s' already exists."), - new_folder); - g_free(new_folder); - return; - } - - if (item->folder->klass->rename_folder(item->folder, item, new_folder) < 0) { - g_free(new_folder); - return; - } - g_free(new_folder); - - gtk_clist_freeze(GTK_CLIST(ctree)); - - folderview_update_node(folderview, folderview->selected); - folderview_sort_folders(folderview, - GTK_CTREE_ROW(folderview->selected)->parent, - item->folder); - if (folderview->opened == folderview->selected) { - if (!GTK_CTREE_ROW(folderview->opened)->children) - gtk_ctree_expand(ctree, folderview->opened); - summary_show(folderview->summaryview, item); - } - - gtk_clist_thaw(GTK_CLIST(ctree)); - - folder_write_list(); -} -#endif - -static void folderview_delete_folder_cb(FolderView *folderview, guint action, - GtkWidget *widget) -{ - GtkCTree *ctree = GTK_CTREE(folderview->ctree); - FolderItem *item; - gchar *message, *name, *name_; - AlertValue avalue; - gchar *old_path; - gchar *old_id; - - if (!folderview->selected) return; - - item = gtk_ctree_node_get_row_data(ctree, folderview->selected); - g_return_if_fail(item != NULL); - g_return_if_fail(item->path != NULL); - g_return_if_fail(item->folder != NULL); - - name_ = trim_string(item->name, 32); - Xstrdup_a(name, name_, return); - g_free(name_); - message = g_strdup_printf - (_("All folder(s) and message(s) under `%s' will be deleted.\n" - "Do you really want to delete?"), name); - avalue = alertpanel(_("Delete folder"), message, - _("Yes"), _("+No"), NULL); - g_free(message); - if (avalue != G_ALERTDEFAULT) return; - - Xstrdup_a(old_path, item->path, return); - old_id = folder_item_get_identifier(item); - - if (folderview->opened == folderview->selected || - gtk_ctree_is_ancestor(ctree, - folderview->selected, - folderview->opened)) { - summary_clear_all(folderview->summaryview); - folderview->opened = NULL; - } - - if (item->folder->klass->remove_folder(item->folder, item) < 0) { - alertpanel_error(_("Can't remove the folder `%s'."), name); - if (folderview->opened == folderview->selected) - summary_show(folderview->summaryview, - folderview->summaryview->folder_item); - g_free(old_id); - return; - } - - folder_write_list(); - - prefs_filtering_delete_path(old_id); - g_free(old_id); - -} - -static void folderview_remove_mailbox_cb(FolderView *folderview, guint action, - GtkWidget *widget) -{ - GtkCTree *ctree = GTK_CTREE(folderview->ctree); - GtkCTreeNode *node; - FolderItem *item; - gchar *name, *name_; - gchar *message; - AlertValue avalue; - - if (!folderview->selected) return; - node = folderview->selected; - item = gtk_ctree_node_get_row_data(ctree, node); - g_return_if_fail(item != NULL); - g_return_if_fail(item->folder != NULL); - if (folder_item_parent(item)) return; - - name_ = trim_string(item->folder->name, 32); - Xstrdup_a(name, name_, return); - g_free(name_); - message = g_strdup_printf - (_("Really remove the mailbox `%s' ?\n" - "(The messages are NOT deleted from the disk)"), name); - avalue = alertpanel(_("Remove mailbox"), message, - _("Yes"), _("+No"), NULL); - g_free(message); - if (avalue != G_ALERTDEFAULT) return; - - folderview_unselect(folderview); - summary_clear_all(folderview->summaryview); - - folder_destroy(item->folder); -} - -static void folderview_new_imap_folder_cb(FolderView *folderview, guint action, - GtkWidget *widget) -{ - GtkCTree *ctree = GTK_CTREE(folderview->ctree); - FolderItem *item; - FolderItem *new_item; - gchar *new_folder; - gchar *name, *name_; - gchar *p; - - if (!folderview->selected) return; - - item = gtk_ctree_node_get_row_data(ctree, folderview->selected); - g_return_if_fail(item != NULL); - g_return_if_fail(item->folder != NULL); - g_return_if_fail(FOLDER_TYPE(item->folder) == F_IMAP); - g_return_if_fail(item->folder->account != NULL); - - new_folder = input_dialog - (_("New folder"), - _("Input the name of new folder:\n" - "(if you want to create a folder to store subfolders,\n" - " append `/' at the end of the name)"), - _("NewFolder")); - if (!new_folder) return; - - if ((p = strchr(new_folder, G_DIR_SEPARATOR)) != NULL && - *(p + 1) != '\0') { - alertpanel_error(_("`%c' can't be included in folder name."), - G_DIR_SEPARATOR); - g_free(new_folder); - return; - } - - name_ = trim_string(new_folder, 32); - Xstrdup_a(name, name_, return); - g_free(name_); - - /* find whether the directory already exists */ - if (folderview_find_by_name(ctree, folderview->selected, new_folder)) { - alertpanel_error(_("The folder `%s' already exists."), name); - g_free(new_folder); - return; - } - - new_item = folder_create_folder(item, new_folder); - if (!new_item) { - alertpanel_error(_("Can't create the folder `%s'."), name); - g_free(new_folder); - return; - } - g_free(new_folder); - - folder_write_list(); -} - -static void folderview_rm_imap_server_cb(FolderView *folderview, guint action, - GtkWidget *widget) -{ - GtkCTree *ctree = GTK_CTREE(folderview->ctree); - FolderItem *item; - PrefsAccount *account; - gchar *name, *name_; - gchar *message; - AlertValue avalue; - - if (!folderview->selected) return; - - item = gtk_ctree_node_get_row_data(ctree, folderview->selected); - g_return_if_fail(item != NULL); - g_return_if_fail(item->folder != NULL); - g_return_if_fail(FOLDER_TYPE(item->folder) == F_IMAP); - g_return_if_fail(item->folder->account != NULL); - - name_ = trim_string(item->folder->name, 32); - Xstrdup_a(name, name_, return); - g_free(name_); - message = g_strdup_printf(_("Really delete IMAP4 account `%s'?"), name); - avalue = alertpanel(_("Delete IMAP4 account"), message, - _("Yes"), _("+No"), NULL); - g_free(message); - - if (avalue != G_ALERTDEFAULT) return; - - if (folderview->opened == folderview->selected || - gtk_ctree_is_ancestor(ctree, - folderview->selected, - folderview->opened)) { - summary_clear_all(folderview->summaryview); - folderview->opened = NULL; - } - - account = item->folder->account; - folder_destroy(item->folder); - account_destroy(account); - gtk_ctree_remove_node(ctree, folderview->selected); - account_set_menu(); - main_window_reflect_prefs_all(); - folder_write_list(); -} - -static void folderview_new_news_group_cb(FolderView *folderview, guint action, - GtkWidget *widget) -{ - GtkCTree *ctree = GTK_CTREE(folderview->ctree); - gchar *text[N_FOLDER_COLS] = {NULL, "0", "0", "0"}; - GtkCTreeNode *servernode, *node; - Folder *folder; - FolderItem *item; - FolderItem *rootitem; - FolderItem *newitem; - GSList *new_subscr; - GSList *cur; - GNode *gnode; - - if (!folderview->selected) return; - - item = gtk_ctree_node_get_row_data(ctree, folderview->selected); - g_return_if_fail(item != NULL); - folder = item->folder; - g_return_if_fail(folder != NULL); - g_return_if_fail(FOLDER_TYPE(folder) == F_NEWS); - g_return_if_fail(folder->account != NULL); - - if (GTK_CTREE_ROW(folderview->selected)->parent != NULL) - servernode = GTK_CTREE_ROW(folderview->selected)->parent; - else - servernode = folderview->selected; - - rootitem = gtk_ctree_node_get_row_data(ctree, servernode); - - new_subscr = grouplist_dialog(folder); - - /* remove unsubscribed newsgroups */ - for (gnode = folder->node->children; gnode != NULL; ) { - GNode *next = gnode->next; - - item = FOLDER_ITEM(gnode->data); - if (g_slist_find_custom(new_subscr, item->path, - (GCompareFunc)g_strcasecmp) != NULL) { - gnode = next; - continue; - } - - node = gtk_ctree_find_by_row_data(ctree, servernode, item); - if (!node) { - gnode = next; - continue; - } - - if (folderview->opened == node) { - summary_clear_all(folderview->summaryview); - folderview->opened = NULL; - } - - gtk_ctree_remove_node(ctree, node); - folder_item_remove(item); - - gnode = next; - } - - gtk_clist_freeze(GTK_CLIST(ctree)); - - /* add subscribed newsgroups */ - for (cur = new_subscr; cur != NULL; cur = cur->next) { - gchar *name = (gchar *)cur->data; - - if (folderview_find_by_name(ctree, servernode, name) != NULL) - continue; - - text[COL_FOLDER] = name; - node = gtk_ctree_insert_node(ctree, servernode, NULL, text, - FOLDER_SPACING, - folderxpm, folderxpmmask, - folderopenxpm, folderopenxpmmask, - FALSE, FALSE); - gtk_ctree_expand(ctree, servernode); - - newitem = folder_item_new(folder, name, name); - folder_item_append(rootitem, newitem); - gtk_ctree_node_set_row_data(ctree, node, newitem); - } - - folderview_sort_folders(folderview, servernode, folder); - gtk_clist_thaw(GTK_CLIST(ctree)); - - slist_free_strings(new_subscr); - g_slist_free(new_subscr); - - folder_write_list(); -} - -static void folderview_rm_news_group_cb(FolderView *folderview, guint action, - GtkWidget *widget) -{ - GtkCTree *ctree = GTK_CTREE(folderview->ctree); - FolderItem *item; - gchar *name, *name_; - gchar *message; - AlertValue avalue; - - if (!folderview->selected) return; - - item = gtk_ctree_node_get_row_data(ctree, folderview->selected); - g_return_if_fail(item != NULL); - g_return_if_fail(item->folder != NULL); - g_return_if_fail(FOLDER_TYPE(item->folder) == F_NEWS); - g_return_if_fail(item->folder->account != NULL); - - name_ = trim_string(item->path, 32); - Xstrdup_a(name, name_, return); - g_free(name_); - message = g_strdup_printf(_("Really delete newsgroup `%s'?"), name); - avalue = alertpanel(_("Delete newsgroup"), message, - _("Yes"), _("+No"), NULL); - g_free(message); - if (avalue != G_ALERTDEFAULT) return; - - if (folderview->opened == folderview->selected) { - summary_clear_all(folderview->summaryview); - folderview->opened = NULL; - } - - folder_item_remove(item); - folder_write_list(); - - prefs_filtering_delete_path(name); -} - -static void folderview_rm_news_server_cb(FolderView *folderview, guint action, - GtkWidget *widget) -{ - GtkCTree *ctree = GTK_CTREE(folderview->ctree); - FolderItem *item; - PrefsAccount *account; - gchar *name, *name_; - gchar *message; - AlertValue avalue; - - if (!folderview->selected) return; - - item = gtk_ctree_node_get_row_data(ctree, folderview->selected); - g_return_if_fail(item != NULL); - g_return_if_fail(item->folder != NULL); - g_return_if_fail(FOLDER_TYPE(item->folder) == F_NEWS); - g_return_if_fail(item->folder->account != NULL); - - name_ = trim_string(item->folder->name, 32); - Xstrdup_a(name, name_, return); - g_free(name_); - message = g_strdup_printf(_("Really delete news account `%s'?"), name); - avalue = alertpanel(_("Delete news account"), message, - _("Yes"), _("+No"), NULL); - g_free(message); - - if (avalue != G_ALERTDEFAULT) return; - - if (folderview->opened == folderview->selected || - gtk_ctree_is_ancestor(ctree, - folderview->selected, - folderview->opened)) { - summary_clear_all(folderview->summaryview); - folderview->opened = NULL; - } - - account = item->folder->account; - folder_destroy(item->folder); - account_destroy(account); - gtk_ctree_remove_node(ctree, folderview->selected); - account_set_menu(); - main_window_reflect_prefs_all(); - folder_write_list(); -} - -static void folderview_search_cb(FolderView *folderview, guint action, - GtkWidget *widget) -{ - summary_search(folderview->summaryview); -} - -static void folderview_property_cb(FolderView *folderview, guint action, +static void folderview_property_cb(FolderView *folderview, guint action, GtkWidget *widget) { GtkCTree *ctree = GTK_CTREE(folderview->ctree); @@ -2605,25 +1697,8 @@ static void folderview_recollapse_nodes(FolderView *folderview, GtkCTreeNode *no g_slist_free(done); } -static void folderview_move_to_cb(FolderView *folderview) -{ - FolderItem *from_folder = NULL, *to_folder = NULL; - - if (folderview->selected) - from_folder = gtk_ctree_node_get_row_data(GTK_CTREE(folderview->ctree), folderview->selected); - if (!from_folder || FOLDER_TYPE(from_folder->folder) == F_NEWS) - return; - - to_folder = foldersel_folder_sel(from_folder->folder, FOLDER_SEL_MOVE, NULL); - - if (!to_folder || FOLDER_TYPE(to_folder->folder) == F_NEWS) - return; - - folderview_move_to(folderview, from_folder, to_folder); -} - -static void folderview_move_to(FolderView *folderview, FolderItem *from_folder, - FolderItem *to_folder) +void folderview_move_folder(FolderView *folderview, FolderItem *from_folder, + FolderItem *to_folder) { FolderItem *from_parent = NULL; FolderItem *new_folder = NULL; @@ -2631,6 +1706,10 @@ static void folderview_move_to(FolderView *folderview, FolderItem *from_folder, gchar *buf; gint status; + g_return_if_fail(folderview != NULL); + g_return_if_fail(from_folder != NULL); + g_return_if_fail(to_folder != NULL); + src_node = gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree), NULL, from_folder); from_parent = folder_item_parent(from_folder); buf = g_strdup_printf(_("Moving %s to %s..."), from_folder->name, to_folder->name); @@ -2693,15 +1772,6 @@ static gint folderview_clist_compare(GtkCList *clist, return g_strcasecmp(item1->name, item2->name); } -static gint folderview_compare_name(gconstpointer a, gconstpointer b) -{ - const FolderItem *item = a; - const gchar *name = b; - - if (!item->path) return -1; - return strcmp2(g_basename(item->path), name); -} - static void folderview_processing_cb(FolderView *folderview, guint action, GtkWidget *widget) { @@ -2804,8 +1874,8 @@ static void folderview_drag_data_get(GtkWidget *widget, { FolderItem *item; GList *cur; - gchar *source=NULL; - + gchar *source = NULL; + for (cur = GTK_CLIST(folderview->ctree)->selection; cur != NULL; cur = cur->next) { item = gtk_ctree_node_get_row_data @@ -2836,7 +1906,7 @@ gboolean folderview_update_folder(gpointer source, gpointer userdata) ctree = folderview->ctree; g_return_val_if_fail(ctree != NULL, FALSE); - if (hookdata->update_flags & FOLDER_NEW_FOLDERITEM) + if (hookdata->update_flags & FOLDER_ADD_FOLDERITEM) folderview_create_folder_node(folderview, hookdata->item); else if (hookdata->update_flags & FOLDER_REMOVE_FOLDERITEM) { GtkCTreeNode *node; @@ -2844,7 +1914,7 @@ gboolean folderview_update_folder(gpointer source, gpointer userdata) node = gtk_ctree_find_by_row_data(GTK_CTREE(ctree), NULL, hookdata->item); if (node != NULL) gtk_ctree_remove_node(GTK_CTREE(ctree), node); - } else if (hookdata->update_flags & (FOLDER_TREE_CHANGED | FOLDER_NEW_FOLDER | FOLDER_DESTROY_FOLDER)) + } else if (hookdata->update_flags & (FOLDER_TREE_CHANGED | FOLDER_ADD_FOLDER | FOLDER_REMOVE_FOLDER)) folderview_set(folderview); return FALSE; @@ -2869,6 +1939,8 @@ static gboolean folderview_drag_motion_cb(GtkWidget *widget, if (gtk_clist_get_selection_info (GTK_CLIST(widget), x - 24, y - 24, &row, &column)) { + GtkWidget *srcwidget; + if (y > height - 24 && height + vpos < total_height) gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5)); @@ -2879,26 +1951,23 @@ static gboolean folderview_drag_motion_cb(GtkWidget *widget, item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node); src_item = folderview->summaryview->folder_item; - if (item && item->folder && item->path && - src_item && src_item != item) { - switch (FOLDER_TYPE(item->folder)) { - case F_MH: -#if 0 - case F_MBOX: -#endif - case F_IMAP: + srcwidget = gtk_drag_get_source_widget(context); + if (srcwidget == folderview->summaryview->ctree) { + /* comes from summaryview */ + /* we are copying messages, so only accept folder items that are not + the source item, are no root items and can copy messages */ + if (item && item->folder && folder_item_parent(item) != NULL && src_item && + src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL) acceptable = TRUE; - break; - default: - break; - } - } else if (item && item->folder && folder_item_get_path(item) && - src_item && src_item != item) { - /* a root folder - acceptable only from folderview */ - if (FOLDER_TYPE(item->folder) == F_MH || FOLDER_TYPE(item->folder) == F_IMAP) + } else if (srcwidget == folderview->ctree) { + /* comes from folderview */ + /* we are moving folder items, only accept folders that are not + the source items and can copy messages and create folder items */ + if (item && item->folder && src_item && src_item != item && + FOLDER_CLASS(item->folder)->copy_msg != NULL && + FOLDER_CLASS(item->folder)->create_folder != NULL) acceptable = TRUE; } - } if (acceptable || (src_item && src_item == item)) @@ -2958,26 +2027,23 @@ static void folderview_drag_received_cb(GtkWidget *widget, /* re-check (due to acceptable possibly set for folder moves */ if (!(item && item->folder && item->path && - src_item && src_item != item && - (FOLDER_TYPE(item->folder) == F_MH || FOLDER_TYPE(item->folder) == F_IMAP))) { + src_item && src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL)) { return; } if (item && src_item) { switch (drag_context->action) { - case GDK_ACTION_COPY: - summary_copy_selected_to(folderview->summaryview, item); - gtk_drag_finish(drag_context, TRUE, FALSE, time); - break; - case GDK_ACTION_MOVE: - case GDK_ACTION_DEFAULT: - default: - if (FOLDER_TYPE(src_item->folder) != FOLDER_TYPE(item->folder) || - (FOLDER_TYPE(item->folder) == F_IMAP && - src_item->folder != item->folder)) + case GDK_ACTION_COPY: summary_copy_selected_to(folderview->summaryview, item); - else - summary_move_selected_to(folderview->summaryview, item); - gtk_drag_finish(drag_context, TRUE, TRUE, time); + gtk_drag_finish(drag_context, TRUE, FALSE, time); + break; + case GDK_ACTION_MOVE: + case GDK_ACTION_DEFAULT: + default: + if (FOLDER_CLASS(src_item->folder)->remove_msg == NULL) + summary_copy_selected_to(folderview->summaryview, item); + else + summary_move_selected_to(folderview->summaryview, item); + gtk_drag_finish(drag_context, TRUE, TRUE, time); } } else gtk_drag_finish(drag_context, FALSE, FALSE, time); @@ -3001,7 +2067,7 @@ static void folderview_drag_received_cb(GtkWidget *widget, return; } - folderview_move_to(folderview, src_item, item); + folderview_move_folder(folderview, src_item, item); gtk_drag_finish(drag_context, TRUE, TRUE, time); } folderview->nodes_to_recollapse = NULL; @@ -3015,3 +2081,35 @@ static void folderview_drag_end_cb(GtkWidget *widget, g_slist_free(folderview->nodes_to_recollapse); folderview->nodes_to_recollapse = NULL; } + +FolderItem *folderview_get_selected(FolderView *folderview) +{ + return (FolderItem *) gtk_ctree_node_get_row_data( + GTK_CTREE(folderview->ctree), folderview->selected); +} + +void folderview_register_popup(FolderViewPopup *fpopup) +{ + GList *folderviews; + + for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) { + FolderView *folderview = folderviews->data; + GtkItemFactory *factory; + + factory = create_ifactory(folderview, fpopup); + g_hash_table_insert(folderview->popups, fpopup->klass, factory); + } + g_hash_table_insert(folderview_popups, fpopup->klass, fpopup); +} + +void folderview_unregister_popup(FolderViewPopup *fpopup) +{ + GList *folderviews; + + for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) { + FolderView *folderview = folderviews->data; + + g_hash_table_remove(folderview->popups, fpopup->klass); + } + g_hash_table_remove(folderview_popups, fpopup->klass); +} diff --git a/src/folderview.h b/src/folderview.h index b93a49f51..f589a7673 100644 --- a/src/folderview.h +++ b/src/folderview.h @@ -1,6 +1,6 @@ /* * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2002 Hiroyuki Yamamoto + * Copyright (C) 1999-2004 Hiroyuki Yamamoto * * 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 @@ -21,6 +21,7 @@ #define __FOLDERVIEW_H__ typedef struct _FolderView FolderView; +typedef struct _FolderViewPopup FolderViewPopup; #include #include @@ -34,19 +35,8 @@ struct _FolderView { GtkWidget *scrolledwin; GtkWidget *ctree; - GtkWidget *mail_popup; - GtkWidget *imap_popup; - GtkWidget *news_popup; -#if 0 - GtkWidget *mbox_popup; -#endif - - GtkItemFactory *mail_factory; - GtkItemFactory *imap_factory; - GtkItemFactory *news_factory; -#if 0 - GtkItemFactory *mbox_factory; -#endif + + GHashTable *popups; GtkCTreeNode *selected; GtkCTreeNode *opened; @@ -71,6 +61,15 @@ struct _FolderView GtkTargetList *target_list; /* DnD */ }; +struct _FolderViewPopup +{ + gchar *klass; + gchar *path; + GSList *entries; + void (*set_sensitivity) (GtkItemFactory *menu, FolderItem *item); +}; + +void folderview_initialize (void); FolderView *folderview_create (void); void folderview_init (FolderView *folderview); void folderview_set (FolderView *folderview); @@ -78,20 +77,31 @@ void folderview_set_all (void); void folderview_select (FolderView *folderview, FolderItem *item); void folderview_unselect (FolderView *folderview); +FolderItem *folderview_get_selected (FolderView *folderview); void folderview_select_next_unread (FolderView *folderview); void folderview_update_msg_num (FolderView *folderview, GtkCTreeNode *row); + +void folderview_append_item (FolderItem *item); + void folderview_rescan_tree (Folder *folder); void folderview_rescan_all (void); gint folderview_check_new (Folder *folder); void folderview_check_new_all (void); -void folderview_new_folder (FolderView *folderview); -void folderview_rename_folder (FolderView *folderview); -void folderview_delete_folder (FolderView *folderview); +void folderview_update_item_foreach (GHashTable *table, + gboolean update_summary); +void folderview_update_all_updated (gboolean update_summary); + +void folderview_move_folder (FolderView *folderview, + FolderItem *from_folder, + FolderItem *to_folder); void folderview_set_target_folder_color (gint color_op); void folderview_reflect_prefs_pixmap_theme (FolderView *folderview); +void folderview_register_popup (FolderViewPopup *fpopup); +void folderview_unregister_popup (FolderViewPopup *fpopup); + #endif /* __FOLDERVIEW_H__ */ diff --git a/src/gtk/Makefile.am b/src/gtk/Makefile.am index a841b8778..a54ab8a68 100644 --- a/src/gtk/Makefile.am +++ b/src/gtk/Makefile.am @@ -1,3 +1,5 @@ +PLUGINDIR = $(pkglibdir)/plugins/ + noinst_LTLIBRARIES = libsylpheedgtk.la EXTRA_DIST = \ @@ -9,6 +11,7 @@ libsylpheedgtk_la_SOURCES = \ colorsel.c \ description_window.c \ filesel.c \ + foldersort.c \ gtkaspell.c \ gtksctree.c \ gtkshruler.c \ @@ -16,6 +19,7 @@ libsylpheedgtk_la_SOURCES = \ gtkutils.c \ gtkvscrollbutton.c \ logwindow.c \ + inputdialog.c \ manage_window.c \ menu.c \ pluginwindow.c \ @@ -31,12 +35,14 @@ sylpheedgtkinclude_HEADERS = \ colorsel.h \ description_window.h \ filesel.h \ + foldersort.h \ gtkaspell.h \ gtksctree.h \ gtkshruler.h \ gtksctree.h \ gtkutils.h \ gtkvscrollbutton.h \ + inputdialog.h \ logwindow.h \ manage_window.h \ menu.h \ @@ -52,7 +58,8 @@ AM_CPPFLAGS = \ -I.. \ $(GTK_CFLAGS) \ $(OPENSSL_CFLAGS) \ - $(ASPELL_CFLAGS) + $(ASPELL_CFLAGS) \ + -DPLUGINDIR=\"$(PLUGINDIR)\" libsylpheedgtk_la_LIBADD = \ ../common/libsylpheedcommon.la \ diff --git a/src/gtk/about.c b/src/gtk/about.c index 063c44677..fe1ef6b6b 100644 --- a/src/gtk/about.c +++ b/src/gtk/about.c @@ -91,7 +91,6 @@ static void about_create(void) gtk_window_set_title(GTK_WINDOW(window), _("About")); gtk_container_set_border_width(GTK_CONTAINER(window), 8); gtk_widget_set_size_request(window, 518, 358); - gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(gtk_widget_hide_on_delete), NULL); g_signal_connect(G_OBJECT(window), "key_press_event", @@ -165,7 +164,7 @@ static void about_create(void) gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); label = gtk_label_new - ("Copyright (C) 1999-2003 Hiroyuki Yamamoto "); + ("Copyright (C) 1999-2004 Hiroyuki Yamamoto "); gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); hbox = gtk_hbox_new(FALSE, 0); diff --git a/src/gtk/colorsel.c b/src/gtk/colorsel.c index 60bdf82db..19203074e 100644 --- a/src/gtk/colorsel.c +++ b/src/gtk/colorsel.c @@ -49,7 +49,6 @@ gint colorsel_select_color_rgb(gchar *title, gint rgbvalue) gint result; color_dialog = GTK_COLOR_SELECTION_DIALOG(gtk_color_selection_dialog_new(title)); - gtk_window_set_position(GTK_WINDOW(color_dialog), GTK_WIN_POS_CENTER); gtk_window_set_modal(GTK_WINDOW(color_dialog), TRUE); gtk_window_set_policy(GTK_WINDOW(color_dialog), FALSE, FALSE, FALSE); manage_window_set_transient(GTK_WINDOW(color_dialog)); diff --git a/src/gtk/description_window.c b/src/gtk/description_window.c index e463318e1..5482de8f4 100644 --- a/src/gtk/description_window.c +++ b/src/gtk/description_window.c @@ -64,7 +64,6 @@ static void description_create(DescriptionWindow * dwindow) gtk_window_set_title(GTK_WINDOW(dwindow->window), gettext(dwindow->title)); gtk_container_set_border_width(GTK_CONTAINER(dwindow->window), 8); - gtk_window_set_position(GTK_WINDOW(dwindow->window), GTK_WIN_POS_CENTER); gtk_window_set_modal(GTK_WINDOW(dwindow->window), TRUE); gtk_window_set_policy(GTK_WINDOW(dwindow->window), FALSE, TRUE, FALSE); diff --git a/src/gtk/filesel.c b/src/gtk/filesel.c index 4305b0c21..e74cb2b4b 100644 --- a/src/gtk/filesel.c +++ b/src/gtk/filesel.c @@ -59,6 +59,8 @@ gchar *filesel_select_file(const gchar *title, const gchar *file) { static gchar *filename = NULL; static gchar *cwd = NULL; + gchar *startdir = NULL; + gchar *realfile = NULL; filesel_create(title, FALSE); @@ -69,15 +71,27 @@ gchar *filesel_select_file(const gchar *title, const gchar *file) filename = NULL; } - if (!cwd) + /* try to extract the directory and filename from file */ + if (file) { + startdir = g_dirname(file); + realfile = g_basename(file); + } else { + realfile = file; + } + + /* use sylpheed's startup directory if we can't find anything useful */ + if (!startdir || !strcmp(startdir, ".")) { cwd = g_strconcat(sylpheed_get_startup_dir(), G_DIR_SEPARATOR_S, NULL); + } else { + cwd = g_strconcat(startdir, G_DIR_SEPARATOR_S, NULL); + } gtk_file_selection_set_filename(GTK_FILE_SELECTION(filesel), cwd); - if (file) { + if (realfile) { gtk_file_selection_set_filename(GTK_FILE_SELECTION(filesel), - file); - filesel_oldfilename = g_strdup(file); + realfile); + filesel_oldfilename = g_strdup(realfile); } else { filesel_oldfilename = NULL; } @@ -108,6 +122,9 @@ gchar *filesel_select_file(const gchar *title, const gchar *file) if (filesel_oldfilename) g_free(filesel_oldfilename); + if (startdir) + g_free(startdir); + manage_window_focus_out(filesel, NULL, NULL); gtk_widget_destroy(filesel); GTK_EVENTS_FLUSH(); @@ -177,7 +194,6 @@ GList *filesel_select_multiple_files(const gchar *title, const gchar *file) static void filesel_create(const gchar *title, gboolean multiple_files) { filesel = gtk_file_selection_new(title); - gtk_window_set_position(GTK_WINDOW(filesel), GTK_WIN_POS_CENTER); gtk_window_set_modal(GTK_WINDOW(filesel), TRUE); gtk_window_set_wmclass (GTK_WINDOW(filesel), "file_selection", "Sylpheed"); diff --git a/src/gtk/foldersort.c b/src/gtk/foldersort.c index aaca22f60..c06597aa4 100644 --- a/src/gtk/foldersort.c +++ b/src/gtk/foldersort.c @@ -132,7 +132,7 @@ void foldersort_open() GtkWidget *folderlist; GtkWidget *label2; - window = gtk_window_new(GTK_WINDOW_DIALOG); + window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_object_set_data(GTK_OBJECT(window), "window", window); gtk_container_set_border_width(GTK_CONTAINER(window), 4); gtk_window_set_title(GTK_WINDOW(window), diff --git a/src/gtk/gtkaspell.c b/src/gtk/gtkaspell.c index 7e340880a..89299d9aa 100644 --- a/src/gtk/gtkaspell.c +++ b/src/gtk/gtkaspell.c @@ -2406,7 +2406,7 @@ static void gtkaspell_alert_dialog(gchar *message) dialog = gtk_dialog_new(); gtk_window_set_policy(GTK_WINDOW(dialog), FALSE, FALSE, FALSE); - gtk_window_set_position(GTK_WINDOW(dialog),GTK_WIN_POS_MOUSE); + gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_MOUSE); gtk_signal_connect_object(GTK_OBJECT(dialog), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(dialog)); diff --git a/src/gtk/inputdialog.c b/src/gtk/inputdialog.c index 3111c70a1..2eb11f909 100644 --- a/src/gtk/inputdialog.c +++ b/src/gtk/inputdialog.c @@ -77,7 +77,7 @@ static void cancel_clicked (GtkWidget *widget, static gint delete_event (GtkWidget *widget, GdkEventAny *event, gpointer data); -static void key_pressed (GtkWidget *widget, +static gboolean key_pressed (GtkWidget *widget, GdkEventKey *event, gpointer data); static void entry_activated (GtkEditable *editable); @@ -166,13 +166,13 @@ static void input_dialog_create(void) dialog = gtk_dialog_new(); gtk_window_set_policy(GTK_WINDOW(dialog), FALSE, FALSE, FALSE); - gtk_widget_set_usize(dialog, INPUT_DIALOG_WIDTH, -1); + gtk_widget_set_size_request(dialog, INPUT_DIALOG_WIDTH, -1); gtk_container_set_border_width (GTK_CONTAINER(GTK_DIALOG(dialog)->action_area), 5); - gtk_signal_connect(GTK_OBJECT(dialog), "delete_event", - GTK_SIGNAL_FUNC(delete_event), NULL); - gtk_signal_connect(GTK_OBJECT(dialog), "key_press_event", - GTK_SIGNAL_FUNC(key_pressed), NULL); + g_signal_connect(G_OBJECT(dialog), "delete_event", + G_CALLBACK(delete_event), NULL); + g_signal_connect(G_OBJECT(dialog), "key_press_event", + G_CALLBACK(key_pressed), NULL); MANAGE_WINDOW_SIGNALS_CONNECT(dialog); gtk_widget_realize(dialog); @@ -190,13 +190,13 @@ static void input_dialog_create(void) entry = gtk_entry_new(); gtk_box_pack_start(GTK_BOX(vbox), entry, FALSE, FALSE, 0); - gtk_signal_connect(GTK_OBJECT(entry), "activate", - GTK_SIGNAL_FUNC(entry_activated), NULL); + g_signal_connect(G_OBJECT(entry), "activate", + G_CALLBACK(entry_activated), NULL); combo = gtk_combo_new(); gtk_box_pack_start(GTK_BOX(vbox), combo, FALSE, FALSE, 0); - gtk_signal_connect(GTK_OBJECT(GTK_COMBO(combo)->entry), "activate", - GTK_SIGNAL_FUNC(combo_activated), NULL); + g_signal_connect(G_OBJECT(GTK_COMBO(combo)->entry), "activate", + G_CALLBACK(combo_activated), NULL); gtkut_button_set_create(&confirm_area, &ok_button, _("OK"), @@ -206,10 +206,10 @@ static void input_dialog_create(void) confirm_area); gtk_widget_grab_default(ok_button); - gtk_signal_connect(GTK_OBJECT(ok_button), "clicked", - GTK_SIGNAL_FUNC(ok_clicked), NULL); - gtk_signal_connect(GTK_OBJECT(cancel_button), "clicked", - GTK_SIGNAL_FUNC(cancel_clicked), NULL); + g_signal_connect(G_OBJECT(ok_button), "clicked", + G_CALLBACK(ok_clicked), NULL); + g_signal_connect(G_OBJECT(cancel_button), "clicked", + G_CALLBACK(cancel_clicked), NULL); gtk_widget_show_all(GTK_DIALOG(dialog)->vbox); @@ -274,8 +274,8 @@ static void input_dialog_set(const gchar *title, const gchar *message, gtk_label_set_text(GTK_LABEL(msg_label), message); if (default_string && *default_string) { gtk_entry_set_text(GTK_ENTRY(entry_), default_string); - gtk_entry_set_position(GTK_ENTRY(entry_), 0); - gtk_entry_select_region(GTK_ENTRY(entry_), 0, -1); + gtk_editable_set_position(GTK_EDITABLE(entry_), 0); + gtk_editable_select_region(GTK_EDITABLE(entry_), 0, -1); } else gtk_entry_set_text(GTK_ENTRY(entry_), ""); @@ -303,12 +303,14 @@ static gint delete_event(GtkWidget *widget, GdkEventAny *event, gpointer data) return TRUE; } -static void key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data) +static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data) { if (event && event->keyval == GDK_Escape) { ack = FALSE; fin = TRUE; } + + return FALSE; } static void entry_activated(GtkEditable *editable) diff --git a/src/gtk/menu.c b/src/gtk/menu.c index d844410e6..08cfb52d6 100644 --- a/src/gtk/menu.c +++ b/src/gtk/menu.c @@ -35,8 +35,6 @@ #include "menu.h" #include "utils.h" -static gchar *menu_translate(const gchar *path, gpointer data); - static void menu_item_add_accel( GtkWidget *widget, guint accel_signal_id, GtkAccelGroup *accel_group, guint accel_key, GdkModifierType accel_mods, GtkAccelFlags accel_flags, gpointer user_data); @@ -90,7 +88,7 @@ GtkWidget *popupmenu_create(GtkWidget *window, GtkItemFactoryEntry *entries, return gtk_item_factory_get_widget(factory, path); } -static gchar *menu_translate(const gchar *path, gpointer data) +gchar *menu_translate(const gchar *path, gpointer data) { gchar *retval; diff --git a/src/gtk/menu.h b/src/gtk/menu.h index d8fdf83c0..8e3170355 100644 --- a/src/gtk/menu.h +++ b/src/gtk/menu.h @@ -53,11 +53,12 @@ GtkWidget *menu_create_items (GtkItemFactoryEntry *entries, const gchar *path, GtkItemFactory **factory, gpointer data); -GtkWidget *popupmenu_create(GtkWidget *window, +GtkWidget *popupmenu_create (GtkWidget *window, GtkItemFactoryEntry *entries, - guint n_entries, + guint n_entries, const gchar *path, gpointer data); +gchar *menu_translate (const gchar *path, gpointer data); GString *menu_factory_get_rc (const gchar *path); void menu_factory_clear_rc (const gchar *rc_str); diff --git a/src/gtk/pluginwindow.c b/src/gtk/pluginwindow.c index 044f64a54..99a2ec9b3 100644 --- a/src/gtk/pluginwindow.c +++ b/src/gtk/pluginwindow.c @@ -46,6 +46,7 @@ static void close_cb(GtkButton *button, PluginWindow *pluginwindow) gtk_widget_destroy(pluginwindow->window); g_free(pluginwindow); plugin_save_list(); + inc_unlock(); } static void set_plugin_list(PluginWindow *pluginwindow) @@ -119,7 +120,7 @@ static void load_cb(GtkButton *button, PluginWindow *pluginwindow) { gchar *file, *error = NULL; - file = filesel_select_file(_("Select Plugin to load"), ""); + file = filesel_select_file(_("Select Plugin to load"), PLUGINDIR); if (file == NULL) return; @@ -156,8 +157,6 @@ void pluginwindow_create() gtk_container_set_border_width(GTK_CONTAINER(window), 8); gtk_window_set_default_size(GTK_WINDOW(window), 480, 300); gtk_window_set_title(GTK_WINDOW(window), _("Plugins")); - gtk_window_set_position(GTK_WINDOW(window), - GTK_WIN_POS_CENTER); gtk_window_set_modal(GTK_WINDOW(window), TRUE); vbox1 = gtk_vbox_new(FALSE, 4); @@ -259,5 +258,6 @@ void pluginwindow_create() set_plugin_list(pluginwindow); + inc_lock(); gtk_widget_show(window); } diff --git a/src/gtk/progressdialog.c b/src/gtk/progressdialog.c index f9672d8dd..e7b4a0799 100644 --- a/src/gtk/progressdialog.c +++ b/src/gtk/progressdialog.c @@ -58,7 +58,6 @@ ProgressDialog *progress_dialog_create(void) window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_widget_set_usize(window, 460, -1); gtk_container_set_border_width(GTK_CONTAINER(window), 8); - gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); gtk_window_set_policy(GTK_WINDOW(window), FALSE, TRUE, TRUE); gtk_widget_realize(window); diff --git a/src/imap.c b/src/imap.c index 9e3abfca6..fe78554b6 100644 --- a/src/imap.c +++ b/src/imap.c @@ -435,57 +435,56 @@ static gboolean imap_scan_required (Folder *folder, static void imap_change_flags (Folder *folder, FolderItem *item, MsgInfo *msginfo, - MsgPermFlags newflags); + MsgPermFlags newflags); +static gint imap_get_flags (Folder *folder, + FolderItem *item, + MsgInfoList *msglist, + GRelation *msgflags); static gchar *imap_folder_get_path (Folder *folder); static gchar *imap_item_get_path (Folder *folder, FolderItem *item); -static FolderClass imap_class = -{ - F_IMAP, - "imap", - "IMAP4", - - /* Folder functions */ - imap_folder_new, - imap_folder_destroy, - NULL, - NULL, - imap_scan_tree, - imap_create_tree, - - /* FolderItem functions */ - imap_folder_item_new, - imap_folder_item_destroy, - NULL, - NULL, - imap_item_get_path, - imap_create_folder, - imap_rename_folder, - imap_remove_folder, - imap_close, - imap_get_num_list, - NULL, - NULL, - NULL, - imap_scan_required, - - /* Message functions */ - imap_get_msginfo, - imap_get_msginfos, - imap_fetch_msg, - imap_add_msg, - imap_add_msgs, - imap_copy_msg, - imap_copy_msgs, - imap_remove_msg, - imap_remove_all_msg, - imap_is_msg_changed, - imap_change_flags, -}; +static FolderClass imap_class; FolderClass *imap_get_class(void) { + if (imap_class.idstr == NULL) { + imap_class.type = F_IMAP; + imap_class.idstr = "imap"; + imap_class.uistr = "IMAP4"; + + /* Folder functions */ + imap_class.new_folder = imap_folder_new; + imap_class.destroy_folder = imap_folder_destroy; + imap_class.scan_tree = imap_scan_tree; + imap_class.create_tree = imap_create_tree; + + /* FolderItem functions */ + imap_class.item_new = imap_folder_item_new; + imap_class.item_destroy = imap_folder_item_destroy; + imap_class.item_get_path = imap_item_get_path; + imap_class.create_folder = imap_create_folder; + imap_class.rename_folder = imap_rename_folder; + imap_class.remove_folder = imap_remove_folder; + imap_class.close = imap_close; + imap_class.get_num_list = imap_get_num_list; + imap_class.scan_required = imap_scan_required; + + /* Message functions */ + imap_class.get_msginfo = imap_get_msginfo; + imap_class.get_msginfos = imap_get_msginfos; + imap_class.fetch_msg = imap_fetch_msg; + imap_class.add_msg = imap_add_msg; + imap_class.add_msgs = imap_add_msgs; + imap_class.copy_msg = imap_copy_msg; + imap_class.copy_msgs = imap_copy_msgs; + imap_class.remove_msg = imap_remove_msg; + imap_class.remove_all_msg = imap_remove_all_msg; + imap_class.is_msg_changed = imap_is_msg_changed; + imap_class.change_flags = imap_change_flags; + imap_class.get_flags = imap_get_flags; + } + return &imap_class; } @@ -666,13 +665,13 @@ static IMAPSession *imap_session_get(Folder *folder) /* Check if this is the first try to establish a connection, if yes we don't try to reconnect */ if (rfolder->session == NULL) { - log_warning(_("Connecting %s failed"), + log_warning(_("Connecting to %s failed"), folder->account->recv_server); session_destroy(SESSION(session)); session = NULL; } else { log_warning(_("IMAP4 connection to %s has been" - " disconnected. Reconnecting...\n"), + " disconnected. Reconnecting...\n"), folder->account->recv_server); session_destroy(SESSION(session)); /* Clear folders session to make imap_session_get create @@ -1718,6 +1717,12 @@ static gint imap_rename_folder(Folder *folder, FolderItem *item, g_return_val_if_fail(item->path != NULL, -1); g_return_val_if_fail(name != NULL, -1); + if (strchr(name, imap_get_path_separator(IMAP_FOLDER(folder), item->path)) != NULL) { + g_warning(_("New folder name must not contain the namespace " + "path separator")); + return -1; + } + session = imap_session_get(folder); if (!session) return -1; @@ -2465,7 +2470,8 @@ static gint imap_select(IMAPSession *session, IMAPFolder *folder, { gchar *real_path; gint ok; - gint exists_, recent_, unseen_, uid_validity_; + gint exists_, recent_, unseen_; + guint32 uid_validity_; if (!exists || !recent || !unseen || !uid_validity) { if (session->mbox && strcmp(session->mbox, path) == 0) @@ -2717,6 +2723,7 @@ static gint imap_cmd_do_select(IMAPSession *session, const gchar *folder, GPtrArray *argbuf; gchar *select_cmd; gchar *folder_; + unsigned int uid_validity_; *exists = *recent = *unseen = *uid_validity = 0; argbuf = g_ptr_array_new(); @@ -2749,11 +2756,12 @@ static gint imap_cmd_do_select(IMAPSession *session, const gchar *folder, resp_str = search_array_contain_str(argbuf, "UIDVALIDITY"); if (resp_str) { - if (sscanf(resp_str, "OK [UIDVALIDITY %u] ", uid_validity) + if (sscanf(resp_str, "OK [UIDVALIDITY %u] ", &uid_validity_) != 1) { g_warning("imap_cmd_select(): invalid UIDVALIDITY line.\n"); THROW; } + *uid_validity = uid_validity_; } resp_str = search_array_contain_str(argbuf, "UNSEEN"); @@ -2850,7 +2858,7 @@ static gint imap_cmd_search(IMAPSession *session, const gchar *criteria, for (p = strlist; *p != NULL; ++p) { guint msgnum; - if (sscanf(*p, "%d", &msgnum) == 1) + if (sscanf(*p, "%u", &msgnum) == 1) *list = g_slist_append(*list, GINT_TO_POINTER(msgnum)); } g_strfreev(strlist); @@ -2934,7 +2942,7 @@ static gint imap_cmd_append(IMAPSession *session, const gchar *destfolder, gint size; gchar *destfolder_; gchar *flag_str; - guint32 new_uid_; + unsigned int new_uid_; gchar *ret = NULL; gchar buf[BUFFSIZE]; FILE *fp; @@ -2963,7 +2971,7 @@ static gint imap_cmd_append(IMAPSession *session, const gchar *destfolder, } g_free(ret); - log_print("IMAP4> %s\n", _("(sending file...)")); + log_print("IMAP4> %s\n", "(sending file...)"); while (fgets(buf, sizeof(buf), fp) != NULL) { strretchomp(buf); @@ -3014,13 +3022,13 @@ static gint imap_cmd_append(IMAPSession *session, const gchar *destfolder, static MsgNumberList *imapset_to_numlist(IMAPSet imapset) { gchar **ranges, **range; - guint32 low, high; + unsigned int low, high; MsgNumberList *uids = NULL; ranges = g_strsplit(imapset, ",", 0); for (range = ranges; *range != NULL; range++) { printf("%s\n", *range); - if(sscanf(*range, "%u:%u", &low, &high) == 1) + if (sscanf(*range, "%u:%u", &low, &high) == 1) uids = g_slist_prepend(uids, GINT_TO_POINTER(low)); else { int i; @@ -3753,7 +3761,7 @@ gint imap_get_num_list(Folder *folder, FolderItem *_item, GSList **msgnum_list, IMAPFolderItem *item = (IMAPFolderItem *)_item; IMAPSession *session; gint ok, nummsgs = 0, exists, recent, uid_val, uid_next, unseen; - GSList *uidlist; + GSList *uidlist = NULL; gchar *dir; gboolean selected_folder; @@ -4057,3 +4065,152 @@ void imap_change_flags(Folder *folder, FolderItem *item, MsgInfo *msginfo, MsgPe return; } + +static gint compare_msginfo(gconstpointer a, gconstpointer b) +{ + return ((MsgInfo *)a)->msgnum - ((MsgInfo *)b)->msgnum; +} + +static guint gslist_find_next_num(MsgNumberList **list, guint num) +{ + GSList *elem; + + g_return_val_if_fail(list != NULL, -1); + + for (elem = *list; elem != NULL; elem = g_slist_next(elem)) + if (GPOINTER_TO_INT(elem->data) >= num) + break; + *list = elem; + return elem != NULL ? GPOINTER_TO_INT(elem->data) : (gint)-1; +} + +/* + * NEW and DELETED flags are not syncronized + * - The NEW/RECENT flags in IMAP folders can not really be directly + * modified by Sylpheed + * - The DELETE/DELETED flag in IMAP and Sylpheed don't have the same + * meaning, in IMAP it always removes the messages from the FolderItem + * in Sylpheed it can mean to move the message to trash + */ +static gint imap_get_flags(Folder *folder, FolderItem *item, + MsgInfoList *msginfo_list, GRelation *msgflags) +{ + IMAPSession *session; + GSList *sorted_list; + /* + GSList *new = NULL, *p_new; + GSList *deleted = NULL, *p_deleted; + */ + GSList *unseen = NULL, *answered = NULL, *flagged = NULL; + GSList *p_unseen, *p_answered, *p_flagged; + GSList *elem; + GSList *seq_list, *cur; + gboolean reverse_seen = FALSE; + GString *cmd_buf; + gint ok; + gint exists_cnt, recent_cnt, unseen_cnt, uid_next; + guint32 uidvalidity; + + g_return_val_if_fail(folder != NULL, -1); + g_return_val_if_fail(item != NULL, -1); + if (msginfo_list == NULL) + return 0; + + session = imap_session_get(folder); + g_return_val_if_fail(session != NULL, -1); + + ok = imap_select(session, IMAP_FOLDER(folder), item->path, + NULL, NULL, NULL, NULL); + if (ok != IMAP_SUCCESS) + return -1; + + ok = imap_status(session, IMAP_FOLDER(folder), item->path, + &exists_cnt, &recent_cnt, &uid_next, &uidvalidity, &unseen_cnt); + + if (unseen_cnt > exists_cnt / 2) + reverse_seen = TRUE; + + cmd_buf = g_string_new(NULL); + + sorted_list = g_slist_sort(g_slist_copy(msginfo_list), compare_msginfo); + + seq_list = imap_get_seq_set_from_msglist(msginfo_list); + + for (cur = seq_list; cur != NULL; cur = g_slist_next(cur)) { + IMAPSet imapset = cur->data; +/* + g_string_sprintf(cmd_buf, "RECENT UID %s", imapset); + imap_cmd_search(session, cmd_buf->str, &p_new); + new = g_slist_concat(new, p_new); +*/ + g_string_sprintf(cmd_buf, "%sSEEN UID %s", reverse_seen ? "" : "UN", imapset); + imap_cmd_search(session, cmd_buf->str, &p_unseen); + unseen = g_slist_concat(unseen, p_unseen); + + g_string_sprintf(cmd_buf, "ANSWERED UID %s", imapset); + imap_cmd_search(session, cmd_buf->str, &p_answered); + answered = g_slist_concat(answered, p_answered); + + g_string_sprintf(cmd_buf, "FLAGGED UID %s", imapset); + imap_cmd_search(session, cmd_buf->str, &p_flagged); + flagged = g_slist_concat(flagged, p_flagged); +/* + g_string_sprintf(cmd_buf, "DELETED UID %s", imapset); + imap_cmd_search(session, cmd_buf->str, &p_deleted); + deleted = g_slist_concat(deleted, p_deleted); +*/ + } + +/* + p_new = new; +*/ + p_unseen = unseen; + p_answered = answered; + p_flagged = flagged; +/* + p_deleted = deleted; +*/ + for (elem = sorted_list; elem != NULL; elem = g_slist_next(elem)) { + MsgInfo *msginfo; + MsgPermFlags flags; + gboolean wasnew; + + msginfo = (MsgInfo *) elem->data; + flags = msginfo->flags.perm_flags; + wasnew = (flags & MSG_NEW); + flags &= ~((reverse_seen ? 0 : MSG_UNREAD | MSG_NEW) | MSG_REPLIED | MSG_MARKED); + if (reverse_seen) + flags |= MSG_UNREAD | (wasnew ? MSG_NEW : 0); + /* + if (gslist_find_next_num(&p_new, msginfo->msgnum) == msginfo->msgnum) + flags |= MSG_NEW; + */ + if (gslist_find_next_num(&p_unseen, msginfo->msgnum) == msginfo->msgnum) { + if (!reverse_seen) { + flags |= MSG_UNREAD | (wasnew ? MSG_NEW : 0); + } else { + flags &= ~(MSG_UNREAD | MSG_NEW); + } + } + if (gslist_find_next_num(&p_answered, msginfo->msgnum) == msginfo->msgnum) + flags |= MSG_REPLIED; + if (gslist_find_next_num(&p_flagged, msginfo->msgnum) == msginfo->msgnum) + flags |= MSG_MARKED; + /* + if (gslist_find_next_num(&p_deleted, msginfo->msgnum) == msginfo->msgnum) + MSG_SET_PERM_FLAGS(msginfo->flags, MSG_DELETED); + */ + g_relation_insert(msgflags, msginfo, GINT_TO_POINTER(flags)); + } + + imap_seq_set_free(seq_list); + /* g_slist_free(deleted); */ + g_slist_free(flagged); + g_slist_free(answered); + g_slist_free(unseen); + /* new not freed in original patch ??? */ + g_slist_free(sorted_list); + g_string_free(cmd_buf, TRUE); + + return 0; +} diff --git a/src/import.c b/src/import.c index 925825816..6f5c31576 100644 --- a/src/import.c +++ b/src/import.c @@ -120,7 +120,7 @@ gint import_mbox(FolderItem *default_dest) if (!dest) { g_warning("Can't find the folder.\n"); } else { - ok = proc_mbox(dest, filename); + ok = proc_mbox(dest, filename, FALSE); } g_free(filename); diff --git a/src/inc.c b/src/inc.c index 2de2414e1..a3b8d4b6a 100644 --- a/src/inc.c +++ b/src/inc.c @@ -1,6 +1,6 @@ /* * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2003 Hiroyuki Yamamoto + * Copyright (C) 1999-2004 Hiroyuki Yamamoto * * 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 @@ -94,9 +94,22 @@ static void inc_session_destroy (IncSession *session); static gint inc_start (IncProgressDialog *inc_dialog); static IncState inc_pop3_session_do (IncSession *session); +static void inc_timer_start (IncProgressDialog *inc_dialog, + IncSession *inc_session); +static void inc_timer_stop (IncProgressDialog *inc_dialog); + +static void inc_progress_dialog_update (IncProgressDialog *inc_dialog, + IncSession *inc_session); + static void inc_progress_dialog_set_label (IncProgressDialog *inc_dialog, IncSession *inc_session); +static void inc_progress_dialog_set_progress + (IncProgressDialog *inc_dialog, + IncSession *inc_session); + +static gint inc_progress_timer_func (gpointer data); +static gint inc_folder_timer_func (gpointer data); static gint inc_recv_data_progressive (Session *session, guint cur_len, @@ -108,6 +121,8 @@ static gint inc_recv_data_finished (Session *session, static gint inc_recv_message (Session *session, const gchar *msg, gpointer data); +static gint inc_drop_message (Pop3Session *session, + const gchar *file); static void inc_put_error (IncState istate, const gchar *msg); @@ -379,6 +394,8 @@ static IncProgressDialog *inc_progress_dialog_create(gboolean autocheck) } dialog->dialog = progress; + dialog->progress_timer_id = 0; + dialog->folder_timer_id = 0; dialog->queue_list = NULL; dialog->cur_row = 0; @@ -438,8 +455,20 @@ static IncSession *inc_session_new(PrefsAccount *account) return NULL; session = g_new0(IncSession, 1); + session->session = pop3_session_new(account); session->session->data = session; + POP3_SESSION(session->session)->drop_message = inc_drop_message; + session_set_recv_message_notify(session->session, + inc_recv_message, session); + session_set_recv_data_progressive_notify(session->session, + inc_recv_data_progressive, + session); + session_set_recv_data_notify(session->session, + inc_recv_data_finished, session); + + session->folder_table = g_hash_table_new(NULL, NULL); + session->tmp_folder_table = g_hash_table_new(NULL, NULL); return session; } @@ -449,6 +478,8 @@ static void inc_session_destroy(IncSession *session) g_return_if_fail(session != NULL); session_destroy(session->session); + g_hash_table_destroy(session->folder_table); + g_hash_table_destroy(session->tmp_folder_table); g_free(session); } @@ -531,13 +562,6 @@ static gint inc_start(IncProgressDialog *inc_dialog) SET_PIXMAP_AND_TEXT(currentxpm, currentxpmmask, _("Retrieving")); - session_set_recv_message_notify(session->session, - inc_recv_message, session); - session_set_recv_data_progressive_notify - (session->session, inc_recv_data_progressive, session); - session_set_recv_data_notify(session->session, - inc_recv_data_finished, session); - /* begin POP3 session */ inc_state = inc_pop3_session_do(session); @@ -582,13 +606,8 @@ static gint inc_start(IncProgressDialog *inc_dialog) if (pop3_session->error_val == PS_AUTHFAIL) { if(!prefs_common.no_recv_err_panel) { if((prefs_common.recv_dialog_mode == RECV_DIALOG_ALWAYS) || - ((prefs_common.recv_dialog_mode == RECV_DIALOG_MANUAL) && focus_window)) { + ((prefs_common.recv_dialog_mode == RECV_DIALOG_MANUAL) && focus_window)) manage_window_focus_in(inc_dialog->dialog->window, NULL, NULL); - } - alertpanel_error - (_("Authorization for %s on %s failed"), - pop3_session->user, - pop3_session->ac_prefs->recv_server); } } @@ -607,8 +626,6 @@ static gint inc_start(IncProgressDialog *inc_dialog) folder_item_scan(processing); msglist = folder_item_get_msg_list(processing); - folder_item_update_freeze(); - /* process messages */ for(msglist_element = msglist; msglist_element != NULL; msglist_element = msglist_element->next) { msginfo = (MsgInfo *) msglist_element->data; @@ -618,8 +635,6 @@ static gint inc_start(IncProgressDialog *inc_dialog) } g_slist_free(msglist); - folder_item_update_thaw(); - statusbar_pop_all(); new_msgs += pop3_session->cur_total_num; @@ -682,7 +697,7 @@ static gint inc_start(IncProgressDialog *inc_dialog) g_list_remove(inc_dialog->queue_list, session); } - if (prefs_common.close_recv_dialog) + if (prefs_common.close_recv_dialog || !inc_dialog->show_dialog) inc_progress_dialog_destroy(inc_dialog); else { gtk_window_set_title(GTK_WINDOW(inc_dialog->dialog->window), @@ -755,6 +770,7 @@ static IncState inc_pop3_session_do(IncSession *session) session->inc_state != INC_CANCEL) gtk_main_iteration(); + inc_timer_stop(inc_dialog); statusbar_pop_all(); if (session->inc_state == INC_SUCCESS) { @@ -791,6 +807,40 @@ static IncState inc_pop3_session_do(IncSession *session) return session->inc_state; } +static void inc_timer_start(IncProgressDialog *inc_dialog, + IncSession *inc_session) +{ + if (inc_dialog->progress_timer_id == 0) { + inc_dialog->progress_timer_id = + gtk_timeout_add(PROGRESS_UPDATE_INTERVAL, + inc_progress_timer_func, inc_session); + } + if (inc_dialog->folder_timer_id == 0) { + inc_dialog->folder_timer_id = + gtk_timeout_add(FOLDER_UPDATE_INTERVAL, + inc_folder_timer_func, inc_session); + } +} + +static void inc_timer_stop(IncProgressDialog *inc_dialog) +{ + if (inc_dialog->progress_timer_id) { + gtk_timeout_remove(inc_dialog->progress_timer_id); + inc_dialog->progress_timer_id = 0; + } + if (inc_dialog->folder_timer_id) { + gtk_timeout_remove(inc_dialog->folder_timer_id); + inc_dialog->folder_timer_id = 0; + } +} + +static void inc_progress_dialog_update(IncProgressDialog *inc_dialog, + IncSession *inc_session) +{ + inc_progress_dialog_set_label(inc_dialog, inc_session); + inc_progress_dialog_set_progress(inc_dialog, inc_session); +} + static void inc_progress_dialog_set_label(IncProgressDialog *inc_dialog, IncSession *inc_session) { @@ -809,8 +859,9 @@ static void inc_progress_dialog_set_label(IncProgressDialog *inc_dialog, case POP3_GETAUTH_PASS: case POP3_GETAUTH_APOP: progress_dialog_set_label(dialog, _("Authenticating...")); - statusbar_print_all(_("Retrieving messages from %s..."), - SESSION(session)->server); + statusbar_print_all(_("Retrieving messages from %s (%s) ..."), + SESSION(session)->server, + session->ac_prefs->account_name); break; case POP3_GETRANGE_STAT: progress_dialog_set_label @@ -829,16 +880,7 @@ static void inc_progress_dialog_set_label(IncProgressDialog *inc_dialog, (dialog, _("Getting the size of messages (LIST)...")); break; case POP3_RETR: - gtk_progress_set_show_text - (GTK_PROGRESS(inc_dialog->mainwin->progressbar), TRUE); - g_snprintf(buf, sizeof(buf), "%d / %d", - session->cur_msg, session->count); - gtk_progress_set_format_string - (GTK_PROGRESS(inc_dialog->mainwin->progressbar), buf); - inc_recv_data_progressive - (SESSION(session), 0, - session->msg[session->cur_msg].size, - inc_session); + case POP3_RETR_RECV: break; case POP3_DELETE: if (session->msg[session->cur_msg].recv_time < @@ -856,16 +898,93 @@ static void inc_progress_dialog_set_label(IncProgressDialog *inc_dialog, } } +static void inc_progress_dialog_set_progress(IncProgressDialog *inc_dialog, + IncSession *inc_session) +{ + gchar buf[MSGBUFSIZE]; + Pop3Session *pop3_session = POP3_SESSION(inc_session->session); + gchar *total_size_str; + gint cur_total; + gint total; + + if (!pop3_session->new_msg_exist) return; + + cur_total = inc_session->cur_total_bytes; + total = pop3_session->total_bytes; + if (pop3_session->state == POP3_RETR || + pop3_session->state == POP3_RETR_RECV) { + Xstrdup_a(total_size_str, to_human_readable(total), return); + g_snprintf(buf, sizeof(buf), + _("Retrieving message (%d / %d) (%s / %s)"), + pop3_session->cur_msg, pop3_session->count, + to_human_readable(cur_total), total_size_str); + progress_dialog_set_label(inc_dialog->dialog, buf); + } + + progress_dialog_set_percentage + (inc_dialog->dialog,(gfloat)cur_total / (gfloat)total); + + gtk_progress_set_show_text + (GTK_PROGRESS(inc_dialog->mainwin->progressbar), TRUE); + g_snprintf(buf, sizeof(buf), "%d / %d", + pop3_session->cur_msg, pop3_session->count); + gtk_progress_set_format_string + (GTK_PROGRESS(inc_dialog->mainwin->progressbar), buf); + gtk_progress_bar_update + (GTK_PROGRESS_BAR(inc_dialog->mainwin->progressbar), + (gfloat)cur_total / (gfloat)total); + + if (pop3_session->cur_total_num > 0) { + g_snprintf(buf, sizeof(buf), + _("Retrieving (%d message(s) (%s) received)"), + pop3_session->cur_total_num, + to_human_readable + (pop3_session->cur_total_recv_bytes)); + gtk_clist_set_text(GTK_CLIST(inc_dialog->dialog->clist), + inc_dialog->cur_row, 2, buf); + } +} + +static gboolean hash_remove_func(gpointer key, gpointer value, gpointer data) +{ + return TRUE; +} + +static gint inc_progress_timer_func(gpointer data) +{ + IncSession *inc_session = (IncSession *)data; + IncProgressDialog *inc_dialog; + + inc_dialog = (IncProgressDialog *)inc_session->data; + + inc_progress_dialog_update(inc_dialog, inc_session); + + return TRUE; +} + +static gint inc_folder_timer_func(gpointer data) +{ + IncSession *inc_session = (IncSession *)data; + IncProgressDialog *inc_dialog; + + inc_dialog = (IncProgressDialog *)inc_session->data; + + if (g_hash_table_size(inc_session->tmp_folder_table) > 0) { + folderview_update_item_foreach(inc_session->tmp_folder_table, + FALSE); + g_hash_table_foreach_remove(inc_session->tmp_folder_table, + hash_remove_func, NULL); + } + + return TRUE; +} + static gint inc_recv_data_progressive(Session *session, guint cur_len, guint total_len, gpointer data) { - gchar buf[MSGBUFSIZE]; IncSession *inc_session = (IncSession *)data; Pop3Session *pop3_session = POP3_SESSION(session); - IncProgressDialog *inc_dialog; - ProgressDialog *dialog; gint cur_total; - gchar *total_size; g_return_val_if_fail(inc_session != NULL, -1); @@ -876,26 +995,10 @@ static gint inc_recv_data_progressive(Session *session, guint cur_len, if (!pop3_session->new_msg_exist) return 0; - inc_dialog = (IncProgressDialog *)inc_session->data; - dialog = inc_dialog->dialog; - cur_total = pop3_session->cur_total_bytes + cur_len; if (cur_total > pop3_session->total_bytes) cur_total = pop3_session->total_bytes; - - Xstrdup_a(total_size, to_human_readable(pop3_session->total_bytes), - return FALSE); - g_snprintf(buf, sizeof(buf), - _("Retrieving message (%d / %d) (%s / %s)"), - pop3_session->cur_msg, pop3_session->count, - to_human_readable(cur_total), total_size); - progress_dialog_set_label(dialog, buf); - progress_dialog_set_percentage - (dialog, (gfloat)cur_total / (gfloat)pop3_session->total_bytes); - if (inc_dialog->mainwin) - gtk_progress_bar_update - (GTK_PROGRESS_BAR(inc_dialog->mainwin->progressbar), - (gfloat)cur_total / (gfloat)pop3_session->total_bytes); + inc_session->cur_total_bytes = cur_total; return 0; } @@ -903,25 +1006,25 @@ static gint inc_recv_data_progressive(Session *session, guint cur_len, static gint inc_recv_data_finished(Session *session, guint len, gpointer data) { IncSession *inc_session = (IncSession *)data; - Pop3Session *pop3_session = POP3_SESSION(session); IncProgressDialog *inc_dialog; - gchar *msg; g_return_val_if_fail(inc_session != NULL, -1); inc_dialog = (IncProgressDialog *)inc_session->data; - inc_recv_data_progressive(session, 0, len, inc_session); - inc_progress_dialog_set_label(inc_dialog, inc_session); - - if (pop3_session->cur_total_num == 0) return 0; + inc_recv_data_progressive(session, 0, 0, inc_session); - msg = g_strdup_printf(_("Retrieving (%d message(s) (%s) received)"), - pop3_session->cur_total_num, - to_human_readable - (pop3_session->cur_total_recv_bytes)); - gtk_clist_set_text(GTK_CLIST(inc_dialog->dialog->clist), - inc_dialog->cur_row, 2, msg); - g_free(msg); + if (POP3_SESSION(session)->state == POP3_RETR) { + if (inc_dialog->progress_timer_id == 0) { + inc_timer_start(inc_dialog, inc_session); + inc_progress_dialog_update(inc_dialog, inc_session); + } + } else if (POP3_SESSION(session)->state == POP3_LOGOUT) { + inc_progress_dialog_update(inc_dialog, inc_session); + if (inc_dialog->progress_timer_id) { + inc_folder_timer_func(data); + inc_timer_stop(inc_dialog); + } + } return 0; } @@ -934,16 +1037,48 @@ static gint inc_recv_message(Session *session, const gchar *msg, gpointer data) g_return_val_if_fail(inc_session != NULL, -1); inc_dialog = (IncProgressDialog *)inc_session->data; - inc_progress_dialog_set_label(inc_dialog, inc_session); + + switch (POP3_SESSION(session)->state) { + case POP3_GETAUTH_USER: + case POP3_GETAUTH_PASS: + case POP3_GETAUTH_APOP: + case POP3_GETRANGE_STAT: + case POP3_GETRANGE_LAST: + case POP3_GETRANGE_UIDL: + case POP3_GETSIZE_LIST: + inc_progress_dialog_update(inc_dialog, inc_session); + break; + case POP3_RETR: + inc_recv_data_progressive(session, 0, 0, inc_session); + if (inc_dialog->progress_timer_id == 0) { + inc_timer_start(inc_dialog, inc_session); + inc_progress_dialog_update(inc_dialog, inc_session); + } + break; + case POP3_LOGOUT: + inc_progress_dialog_update(inc_dialog, inc_session); + if (inc_dialog->progress_timer_id) { + inc_folder_timer_func(data); + inc_timer_stop(inc_dialog); + } + break; + default: + break; + } return 0; } -gint inc_drop_message(const gchar *file, Pop3Session *session) +static gint inc_drop_message(Pop3Session *session, const gchar *file) { FolderItem *inbox; FolderItem *dropfolder; + IncSession *inc_session = (IncSession *)(SESSION(session)->data); + IncProgressDialog *inc_dialog; gint msgnum; + gint val; + + g_return_val_if_fail(inc_session != NULL, -1); if (session->ac_prefs->inbox) { inbox = folder_find_item_from_identifier @@ -966,6 +1101,8 @@ gint inc_drop_message(const gchar *file, Pop3Session *session) return -1; } + inc_dialog = (IncProgressDialog *)inc_session->data; + return 0; } @@ -1101,8 +1238,7 @@ static gint inc_dialog_delete_cb(GtkWidget *widget, GdkEventAny *event, static gint inc_spool_account(PrefsAccount *account) { FolderItem *inbox; - gchar *mbox; - const gchar *logname; + gchar *mbox, *logname; gint result; logname = g_get_user_name(); @@ -1180,7 +1316,7 @@ static gint get_spool(FolderItem *dest, const gchar *mbox) debug_print("Getting new messages from %s into %s...\n", mbox, dest->path); - msgs = proc_mbox(dest, tmp_mbox); + msgs = proc_mbox(dest, tmp_mbox, TRUE); unlink(tmp_mbox); if (msgs >= 0) empty_mbox(mbox); diff --git a/src/inc.h b/src/inc.h index 09c352ba4..217d464aa 100644 --- a/src/inc.h +++ b/src/inc.h @@ -1,6 +1,6 @@ /* * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2003 Hiroyuki Yamamoto + * Copyright (C) 1999-2004 Hiroyuki Yamamoto * * 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 @@ -58,6 +58,9 @@ struct _IncProgressDialog gboolean show_dialog; + guint progress_timer_id; + guint folder_timer_id; + GList *queue_list; /* list of IncSession */ gint cur_row; }; @@ -67,6 +70,11 @@ struct _IncSession Session *session; IncState inc_state; + GHashTable *folder_table; /* table of destination folders */ + GHashTable *tmp_folder_table; /* for progressive update */ + + gint cur_total_bytes; + gpointer data; }; @@ -80,8 +88,6 @@ void inc_all_account_mail (MainWindow *mainwin, gboolean autocheck, gboolean notify); void inc_progress_update (Pop3Session *session); -gint inc_drop_message (const gchar *file, - Pop3Session *session); void inc_pop_before_smtp (PrefsAccount *acc); diff --git a/src/ldapquery.c b/src/ldapquery.c index 59f2d7566..9cfd50421 100644 --- a/src/ldapquery.c +++ b/src/ldapquery.c @@ -1,6 +1,6 @@ /* * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 2003 Match Grun + * Copyright (C) 2003-2004 Match Grun * * 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 @@ -518,9 +518,10 @@ static GList *ldapqry_build_items_fl( ItemPerson *person; ItemEMail *email; ItemFolder *folder; - GList *listReturn; + GList *listReturn = NULL; - listReturn = NULL; + folder = ADDRQUERY_FOLDER(qry); + if( folder == NULL ) return listReturn; if( listAddr == NULL ) return listReturn; /* Find longest first name in list */ @@ -555,21 +556,6 @@ static GList *ldapqry_build_items_fl( } } - /* Create new folder for results */ - if( ADDRQUERY_FOLDER(qry) == NULL ) { - folder = addritem_create_item_folder(); - addritem_folder_set_name( folder, ADDRQUERY_NAME(qry) ); - addritem_folder_set_remarks( folder, "" ); - addrcache_id_folder( cache, folder ); - addrcache_add_folder( cache, folder ); - ADDRQUERY_FOLDER(qry) = folder; - - /* Specify folder type and back reference */ - folder->folderType = ADDRFOLDER_QUERY_RESULTS; - folder->folderData = ( gpointer ) qry; - folder->isHidden = TRUE; - } - /* Add person into folder */ person = addritem_create_item_person(); addritem_person_set_common_name( person, fullName ); @@ -708,6 +694,7 @@ static gint ldapqry_connect( LdapQuery *qry ) { LdapControl *ctl; LDAP *ld; gint rc; + gint version; /* Initialize connection */ /* printf( "===ldapqry_connect===\n" ); */ @@ -733,6 +720,29 @@ static gint ldapqry_connect( LdapQuery *qry ) { printf( "connected to LDAP host %s on port %d\n", ctl->hostName, ctl->port ); */ +#ifdef USE_LDAP_TLS + /* Handle TLS */ + version = LDAP_VERSION3; + rc = ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version ); + if( rc == LDAP_OPT_SUCCESS ) { + ctl->version = LDAP_VERSION3; + } + + if( ctl->version == LDAP_VERSION3 ) { + if( ctl->enableTLS ) { + ADDRQUERY_RETVAL(qry) = LDAPRC_TLS; + rc = ldap_start_tls_s( ld, NULL, NULL ); + /* + printf( "rc=%d\n", rc ); + printf( "LDAP Status: set_option: %s\n", ldap_err2string( rc ) ); + */ + if( rc != LDAP_SUCCESS ) { + return ADDRQUERY_RETVAL(qry); + } + } + } +#endif + /* Bind to the server, if required */ ADDRQUERY_RETVAL(qry) = LDAPRC_BIND; if( ctl->bindDN ) { @@ -792,6 +802,7 @@ static gint ldapqry_search_retrieve( LdapQuery *qry ) { LDAPMessage *result, *e; char **attribs; gchar *criteria; + gboolean searchFlag; gboolean entriesFound; gboolean first; struct timeval timeout; @@ -829,17 +840,26 @@ static gint ldapqry_search_retrieve( LdapQuery *qry ) { return ADDRQUERY_RETVAL(qry); } ADDRQUERY_RETVAL(qry) = LDAPRC_SEARCH; - if( rc != LDAP_SUCCESS ) { + + /* Test valid returns */ + searchFlag = FALSE; + if( rc == LDAP_ADMINLIMIT_EXCEEDED ) { + searchFlag = TRUE; + } + else if( rc == LDAP_SUCCESS ) { + searchFlag = TRUE; + } + else if( rc == LDAP_PARTIAL_RESULTS ) { + searchFlag = TRUE; + } + else { /* + printf( "LDAP Error: ldap_search_st: %d\n", rc ); printf( "LDAP Error: ldap_search_st: %s\n", ldap_err2string( rc ) ); */ return ADDRQUERY_RETVAL(qry); } ADDRQUERY_RETVAL(qry) = LDAPRC_STOP_FLAG; - if( ldapqry_get_stop_flag( qry ) ) { - return ADDRQUERY_RETVAL(qry); - } - ldapqry_touch( qry ); /* printf( "Total results are: %d\n", ldap_count_entries( ld, result ) ); @@ -847,7 +867,7 @@ static gint ldapqry_search_retrieve( LdapQuery *qry ) { /* Process results */ first = TRUE; - while( TRUE ) { + while( searchFlag ) { ldapqry_touch( qry ); if( qry->entriesRead >= ctl->maxEntries ) break; @@ -865,7 +885,6 @@ static gint ldapqry_search_retrieve( LdapQuery *qry ) { e = ldap_next_entry( ld, e ); } if( e == NULL ) break; - entriesFound = TRUE; /* Setup a critical section here */ @@ -881,18 +900,19 @@ static gint ldapqry_search_retrieve( LdapQuery *qry ) { else { g_list_free( listEMail ); } - pthread_mutex_unlock( qry->mutexEntry ); } /* Free up and disconnect */ ldap_msgfree( result ); - if( entriesFound ) { - ADDRQUERY_RETVAL(qry) = LDAPRC_SUCCESS; - } - else { - ADDRQUERY_RETVAL(qry) = LDAPRC_NOENTRIES; + if( searchFlag ) { + if( entriesFound ) { + ADDRQUERY_RETVAL(qry) = LDAPRC_SUCCESS; + } + else { + ADDRQUERY_RETVAL(qry) = LDAPRC_NOENTRIES; + } } return ADDRQUERY_RETVAL(qry); @@ -1028,9 +1048,6 @@ static void ldapqry_destroyer( void * ptr ) { qry->control = NULL; qry->thread = NULL; ldapqry_set_busy_flag( qry, FALSE ); - /* - printf( "...destroy exiting\n" ); - */ } /** @@ -1045,6 +1062,7 @@ void ldapqry_cancel( LdapQuery *qry ) { */ if( ldapqry_get_busy_flag( qry ) ) { if( qry->thread ) { + /* printf( "calling pthread_cancel\n" ); */ pthread_cancel( * qry->thread ); } } @@ -1260,17 +1278,13 @@ static gint ldapqry_locate_retrieve( LdapQuery *qry ) { */ return ADDRQUERY_RETVAL(qry); } - ADDRQUERY_RETVAL(qry) = LDAPRC_STOP_FLAG; - if( ldapqry_get_stop_flag( qry ) ) { - return ADDRQUERY_RETVAL(qry); - } - ldapqry_touch( qry ); /* printf( "Total results are: %d\n", ldap_count_entries( ld, result ) ); */ /* Process results */ + ADDRQUERY_RETVAL(qry) = LDAPRC_STOP_FLAG; first = TRUE; while( TRUE ) { ldapqry_touch( qry ); @@ -1352,8 +1366,11 @@ gint ldapqry_perform_locate( LdapQuery *qry ) { /** * Remove results (folder and data) for specified LDAP query. * \param qry Query object to process. + * \return TRUE if folder deleted successfully. */ -void ldapquery_remove_results( LdapQuery *qry ) { +gboolean ldapquery_remove_results( LdapQuery *qry ) { + gboolean retVal = FALSE; + /* Set query as aged - will be retired on a later call */ ldapqry_set_aged_flag( qry, TRUE ); /* @@ -1364,13 +1381,17 @@ void ldapquery_remove_results( LdapQuery *qry ) { /* Query is still busy - cancel query */ /* printf( "\tquery is still busy running...\n" ); */ ldapqry_set_stop_flag( qry, TRUE ); - ldapqry_cancel( qry ); + + /* ldapqry_cancel( qry ); */ } else { /* Delete folder */ /* printf( "\tquery can be deleted!\n" ); */ - ldapqry_delete_folder( qry ); + /* ldapqry_delete_folder( qry ); */ + retVal = TRUE; + /* printf( "\tquery deleted!\n" ); */ } + return retVal; } #endif /* USE_LDAP */ diff --git a/src/ldapquery.h b/src/ldapquery.h index 59b28cf25..eaa0e24f2 100644 --- a/src/ldapquery.h +++ b/src/ldapquery.h @@ -99,7 +99,7 @@ gint ldapqry_read_data_th ( LdapQuery *qry ); void ldapqry_cancel ( LdapQuery *qry ); void ldapqry_age ( LdapQuery *qry, gint maxAge ); void ldapqry_delete_folder ( LdapQuery *qry ); -void ldapquery_remove_results ( LdapQuery *qry ); +gboolean ldapquery_remove_results( LdapQuery *qry ); #endif /* USE_LDAP */ diff --git a/src/ldapserver.c b/src/ldapserver.c index 51615824f..35a640f37 100644 --- a/src/ldapserver.c +++ b/src/ldapserver.c @@ -1,6 +1,6 @@ /* * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 2003 Match Grun + * Copyright (C) 2003-2004 Match Grun * * 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 @@ -609,6 +609,7 @@ LdapQuery *ldapsvr_new_dynamic_search( LdapServer *server, QueryRequest *req ) LdapQuery *qry; gchar *name; gchar *searchTerm; + ItemFolder *folder; g_return_val_if_fail( server != NULL, NULL ); g_return_val_if_fail( req != NULL, NULL ); @@ -616,7 +617,14 @@ LdapQuery *ldapsvr_new_dynamic_search( LdapServer *server, QueryRequest *req ) /* Retire any aged queries */ /* // ldapsvr_retire_query( server ); */ + /* Name of folder and query */ searchTerm = req->searchTerm; + name = g_strdup_printf( "Search '%s'", searchTerm ); + + /* Create a folder for the search results */ + folder = addrcache_add_new_folder( server->addressCache, NULL ); + addritem_folder_set_name( folder, name ); + addritem_folder_set_remarks( folder, "" ); /* Construct a query */ qry = ldapqry_create(); @@ -626,8 +634,13 @@ LdapQuery *ldapsvr_new_dynamic_search( LdapServer *server, QueryRequest *req ) ldapqry_set_callback_entry( qry, req->callBackEntry ); ldapqry_set_callback_end( qry, req->callBackEnd ); + /* Specify folder type and back reference */ + ADDRQUERY_FOLDER(qry) = folder; + folder->folderType = ADDRFOLDER_QUERY_RESULTS; + folder->folderData = ( gpointer ) qry; + folder->isHidden = TRUE; + /* Name the query */ - name = g_strdup_printf( "Search for '%s'", searchTerm ); ldapqry_set_name( qry, name ); g_free( name ); @@ -646,7 +659,7 @@ LdapQuery *ldapsvr_new_dynamic_search( LdapServer *server, QueryRequest *req ) * * \param server LdapServer. * \param req Query request. - * \param folder Folder that will be used to contain search results; may be NULL. + * \param folder Folder that will be used to contain search results. * \return LdapQuery object, or NULL if none created. */ LdapQuery *ldapsvr_new_explicit_search( @@ -658,12 +671,13 @@ LdapQuery *ldapsvr_new_explicit_search( g_return_val_if_fail( server != NULL, NULL ); g_return_val_if_fail( req != NULL, NULL ); - searchTerm = req->searchTerm; + g_return_val_if_fail( folder != NULL, NULL ); /* Retire any aged queries */ /* // ldapsvr_retire_query( server ); */ /* Name the query */ + searchTerm = req->searchTerm; name = g_strdup_printf( "Explicit search for '%s'", searchTerm ); /* Construct a query */ @@ -675,12 +689,10 @@ LdapQuery *ldapsvr_new_explicit_search( ldapqry_set_callback_end( qry, req->callBackEnd ); ldapqry_set_callback_entry( qry, req->callBackEntry ); - if( folder ) { - /* Specify folder type and back reference */ - ADDRQUERY_FOLDER(qry) = folder; - folder->folderType = ADDRFOLDER_QUERY_RESULTS; - folder->folderData = ( gpointer ) qry; - } + /* Specify folder type and back reference */ + ADDRQUERY_FOLDER(qry) = folder; + folder->folderType = ADDRFOLDER_QUERY_RESULTS; + folder->folderData = ( gpointer ) qry; /* Setup server */ ldapsvr_add_query( server, qry ); diff --git a/src/main.c b/src/main.c index 43adc18eb..1eddfb144 100644 --- a/src/main.c +++ b/src/main.c @@ -73,6 +73,9 @@ #include "log.h" #include "prefs_toolbar.h" #include "plugin.h" +#include "mh_gtk.h" +#include "imap_gtk.h" +#include "news_gtk.h" #if USE_GPGME # include "sgpgme.h" @@ -274,6 +277,10 @@ int main(int argc, char *argv[]) gtkut_widget_init(); + folderview_initialize(); + mh_gtk_init(); + imap_gtk_init(); + news_gtk_init(); mainwin = main_window_create (prefs_common.sep_folder | prefs_common.sep_msg << 1); folderview = mainwin->folderview; diff --git a/src/mainwindow.c b/src/mainwindow.c index 2c21dff63..54b86b5b6 100644 --- a/src/mainwindow.c +++ b/src/mainwindow.c @@ -88,6 +88,8 @@ #include "progressindicator.h" #include "localfolder.h" #include "filtering.h" +#include "folderutils.h" +#include "foldersort.h" #define AC_LABEL_WIDTH 240 @@ -143,21 +145,15 @@ static void message_window_size_allocate_cb (GtkWidget *widget, GtkAllocation *allocation, gpointer data); -static void new_folder_cb (MainWindow *mainwin, - guint action, - GtkWidget *widget); -static void rename_folder_cb (MainWindow *mainwin, - guint action, - GtkWidget *widget); -static void delete_folder_cb (MainWindow *mainwin, - guint action, - GtkWidget *widget); static void update_folderview_cb (MainWindow *mainwin, guint action, GtkWidget *widget); static void add_mailbox_cb (MainWindow *mainwin, guint action, GtkWidget *widget); +static void foldersort_cb (MainWindow *mainwin, + guint action, + GtkWidget *widget); static void import_mbox_cb (MainWindow *mainwin, guint action, GtkWidget *widget); @@ -293,6 +289,9 @@ static void attract_by_subject_cb(MainWindow *mainwin, static void delete_duplicated_cb (MainWindow *mainwin, guint action, GtkWidget *widget); +static void delete_duplicated_all_cb (MainWindow *mainwin, + guint action, + GtkWidget *widget); static void filter_cb (MainWindow *mainwin, guint action, GtkWidget *widget); @@ -433,16 +432,9 @@ gboolean mainwindow_progressindicator_hook (gpointer source, static GtkItemFactoryEntry mainwin_entries[] = { {N_("/_File"), NULL, NULL, 0, ""}, - {N_("/_File/_Folder"), NULL, NULL, 0, ""}, - {N_("/_File/_Folder/Create _new folder..."), - NULL, new_folder_cb, 0, NULL}, - {N_("/_File/_Folder/_Rename folder..."),NULL, rename_folder_cb, 0, NULL}, - {N_("/_File/_Folder/_Delete folder"), NULL, delete_folder_cb, 0, NULL}, - {N_("/_File/_Folder/---"), NULL, NULL, 0, ""}, - {N_("/_File/_Folder/_Check for new messages in all folders"), - NULL, update_folderview_cb, 0, NULL}, {N_("/_File/_Add mailbox"), NULL, NULL, 0, ""}, {N_("/_File/_Add mailbox/MH..."), NULL, add_mailbox_cb, 0, NULL}, + {N_("/_File/Change folder order"), NULL, foldersort_cb, 0, NULL}, {N_("/_File/_Import mbox file..."), NULL, import_mbox_cb, 0, NULL}, {N_("/_File/_Export to mbox file..."), NULL, export_mbox_cb, 0, NULL}, {N_("/_File/Empty _trash"), "D", empty_trash_cb, 0, NULL}, @@ -580,6 +572,8 @@ static GtkItemFactoryEntry mainwin_entries[] = CODESET_ACTION(C_ISO_8859_5)}, {N_("/_View/_Code set/Cyrillic (KOI8-_R)"), CODESET_ACTION(C_KOI8_R)}, + {N_("/_View/_Code set/Cyrillic (KOI8-U)"), + CODESET_ACTION(C_KOI8_U)}, {N_("/_View/_Code set/Cyrillic (Windows-1251)"), CODESET_ACTION(C_WINDOWS_1251)}, CODESET_SEPARATOR, @@ -676,7 +670,10 @@ static GtkItemFactoryEntry mainwin_entries[] = {N_("/_Tools/_Harvest addresses/from _Messages..."), NULL, addr_harvest_msg_cb, 0, NULL}, {N_("/_Tools/---"), NULL, NULL, 0, ""}, - {N_("/_Tools/_Filter messages"), NULL, filter_cb, 0, NULL}, + {N_("/_Tools/_Filter all messages in folder"), + NULL, filter_cb, 0, NULL}, + {N_("/_Tools/Filter _selected messages"), + NULL, filter_cb, 1, NULL}, {N_("/_Tools/_Create filter rule"), NULL, NULL, 0, ""}, {N_("/_Tools/_Create filter rule/_Automatically"), NULL, create_filter_cb, FILTER_BY_AUTO, NULL}, @@ -698,8 +695,14 @@ static GtkItemFactoryEntry mainwin_entries[] = {N_("/_Tools/---"), NULL, NULL, 0, ""}, {N_("/_Tools/Actio_ns"), NULL, NULL, 0, ""}, {N_("/_Tools/---"), NULL, NULL, 0, ""}, + {N_("/_Tools/_Check for new messages in all folders"), + NULL, update_folderview_cb, 0, NULL}, {N_("/_Tools/Delete du_plicated messages"), + NULL, NULL, 0, ""}, + {N_("/_Tools/Delete du_plicated messages/In selected folder"), NULL, delete_duplicated_cb, 0, NULL}, + {N_("/_Tools/Delete du_plicated messages/In all folders"), + NULL, delete_duplicated_all_cb, 0, NULL}, {N_("/_Tools/---"), NULL, NULL, 0, ""}, {N_("/_Tools/E_xecute"), "X", execute_summary_cb, 0, NULL}, #ifdef USE_OPENSSL @@ -914,22 +917,22 @@ MainWindow *main_window_create(SeparateType type) summaryview->messageview = messageview; summaryview->window = window; - mainwin->vbox = vbox; - mainwin->menubar = menubar; - mainwin->menu_factory = ifactory; - mainwin->handlebox = handlebox; - mainwin->vbox_body = vbox_body; - mainwin->hbox_stat = hbox_stat; - mainwin->statusbar = statusbar; - mainwin->progressbar = progressbar; - mainwin->statuslabel = statuslabel; - mainwin->ac_button = ac_button; - mainwin->ac_label = ac_label; - - mainwin->online_switch = online_switch; + messageview->statusbar = statusbar; + mainwin->vbox = vbox; + mainwin->menubar = menubar; + mainwin->menu_factory = ifactory; + mainwin->handlebox = handlebox; + mainwin->vbox_body = vbox_body; + mainwin->hbox_stat = hbox_stat; + mainwin->statusbar = statusbar; + mainwin->progressbar = progressbar; + mainwin->statuslabel = statuslabel; + mainwin->online_switch = online_switch; + mainwin->online_pixmap = online_pixmap; + mainwin->offline_pixmap = offline_pixmap; + mainwin->ac_button = ac_button; + mainwin->ac_label = ac_label; mainwin->offline_switch = offline_switch; - mainwin->online_pixmap = online_pixmap; - mainwin->offline_pixmap = offline_pixmap; /* set context IDs for status bar */ mainwin->mainwin_cid = gtk_statusbar_get_context_id @@ -941,6 +944,8 @@ MainWindow *main_window_create(SeparateType type) mainwin->messageview_cid = gtk_statusbar_get_context_id (GTK_STATUSBAR(statusbar), "Message View"); + messageview->statusbar_cid = mainwin->messageview_cid; + /* allocate colors for summary view and folder view */ summaryview->color_marked.red = summaryview->color_marked.green = 0; summaryview->color_marked.blue = (guint16)65535; @@ -1688,10 +1693,10 @@ void main_window_set_menu_sensitive(MainWindow *mainwin) gchar *const entry; SensitiveCond cond; } entry[] = { - {"/File/Folder" , M_UNLOCKED}, {"/File/Add mailbox" , M_UNLOCKED}, {"/File/Add mailbox/MH..." , M_UNLOCKED}, + {"/File/Change folder order" , M_UNLOCKED}, {"/File/Export to mbox file..." , M_UNLOCKED}, {"/File/Empty trash" , M_UNLOCKED}, {"/File/Work offline" , M_UNLOCKED}, @@ -1740,13 +1745,14 @@ void main_window_set_menu_sensitive(MainWindow *mainwin) {"/Message/Cancel a news message" , M_TARGET_EXIST|M_ALLOW_DELETE|M_UNLOCKED|M_NEWS}, {"/Message/Mark" , M_TARGET_EXIST}, - {"/Tools/Add sender to address book", M_SINGLE_TARGET_EXIST}, - {"/Tools/Harvest addresses" , M_UNLOCKED}, - {"/Tools/Filter messages" , M_MSG_EXIST|M_EXEC|M_UNLOCKED}, - {"/Tools/Create filter rule" , M_SINGLE_TARGET_EXIST|M_UNLOCKED}, - {"/Tools/Actions" , M_TARGET_EXIST|M_UNLOCKED}, - {"/Tools/Execute" , M_DELAY_EXEC}, - {"/Tools/Delete duplicated messages", M_MSG_EXIST|M_ALLOW_DELETE|M_UNLOCKED}, + {"/Tools/Add sender to address book" , M_SINGLE_TARGET_EXIST}, + {"/Tools/Harvest addresses" , M_UNLOCKED}, + {"/Tools/Filter all messages in folder", M_MSG_EXIST|M_EXEC|M_UNLOCKED}, + {"/Tools/Filter selected messages" , M_TARGET_EXIST|M_EXEC|M_UNLOCKED}, + {"/Tools/Create filter rule" , M_SINGLE_TARGET_EXIST|M_UNLOCKED}, + {"/Tools/Actions" , M_TARGET_EXIST|M_UNLOCKED}, + {"/Tools/Execute" , M_DELAY_EXEC}, + {"/Tools/Delete duplicated messages/In selected folder" , M_MSG_EXIST|M_ALLOW_DELETE|M_UNLOCKED}, {"/Configuration", M_UNLOCKED}, @@ -2308,22 +2314,10 @@ static void update_folderview_cb(MainWindow *mainwin, guint action, folderview_check_new_all(); } -static void new_folder_cb(MainWindow *mainwin, guint action, - GtkWidget *widget) -{ - folderview_new_folder(mainwin->folderview); -} - -static void rename_folder_cb(MainWindow *mainwin, guint action, - GtkWidget *widget) -{ - folderview_rename_folder(mainwin->folderview); -} - -static void delete_folder_cb(MainWindow *mainwin, guint action, - GtkWidget *widget) +static void foldersort_cb(MainWindow *mainwin, guint action, + GtkWidget *widget) { - folderview_delete_folder(mainwin->folderview); + foldersort_open(); } static void import_mbox_cb(MainWindow *mainwin, guint action, @@ -2707,12 +2701,52 @@ static void attract_by_subject_cb(MainWindow *mainwin, guint action, static void delete_duplicated_cb(MainWindow *mainwin, guint action, GtkWidget *widget) { - summary_delete_duplicated(mainwin->summaryview); + FolderItem *item; + + item = folderview_get_selected(mainwin->folderview); + if (item) { + main_window_cursor_wait(mainwin); + STATUSBAR_PUSH(mainwin, _("Deleting duplicated messages...")); + + folderutils_delete_duplicates(item, prefs_common.immediate_exec ? + DELETE_DUPLICATES_REMOVE : DELETE_DUPLICATES_SETFLAG); + + STATUSBAR_POP(mainwin); + main_window_cursor_normal(mainwin); + } +} + +struct DelDupsData +{ + guint dups; + guint folders; +}; + +static void deldup_all(FolderItem *item, gpointer _data) +{ + struct DelDupsData *data = _data; + gint result; + + result = folderutils_delete_duplicates(item, DELETE_DUPLICATES_REMOVE); + if (result >= 0) { + data->dups += result; + data->folders += 1; + } +} + +static void delete_duplicated_all_cb(MainWindow *mainwin, guint action, + GtkWidget *widget) +{ + struct DelDupsData data = {0, 0}; + + folder_func_to_all_folders(deldup_all, &data); + alertpanel_notice(_("Deleted %d duplicate message(s) in %d folders.\n"), + data.dups, data.folders); } static void filter_cb(MainWindow *mainwin, guint action, GtkWidget *widget) { - summary_filter(mainwin->summaryview); + summary_filter(mainwin->summaryview, (gboolean)action); } static void execute_summary_cb(MainWindow *mainwin, guint action, diff --git a/src/matcher.c b/src/matcher.c index c4bb3d29a..de1bdea55 100644 --- a/src/matcher.c +++ b/src/matcher.c @@ -1,6 +1,6 @@ /* * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 2002 by the Sylpheed Claws Team and Hiroyuki Yamamoto + * Copyright (C) 2002-2004 by the Sylpheed Claws Team and Hiroyuki Yamamoto * * 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 @@ -28,6 +28,7 @@ #include "intl.h" #include "matcher_parser.h" #include "prefs_gtk.h" +#include "addr_compl.h" #include /*! @@ -109,6 +110,8 @@ static const MatchParser matchparser_tab[] = { {MATCHTYPE_MATCH, "match"}, {MATCHTYPE_REGEXPCASE, "regexpcase"}, {MATCHTYPE_REGEXP, "regexp"}, + {MATCHTYPE_ANY_IN_ADDRESSBOOK, "any_in_addressbook"}, + {MATCHTYPE_ALL_IN_ADDRESSBOOK, "all_in_addressbook"}, /* actions */ {MATCHACTION_SCORE, "score"}, /* for backward compatibility */ @@ -262,6 +265,41 @@ MatcherProp *matcherprop_copy(const MatcherProp *src) /* ************** match ******************************/ +static gboolean match_with_addresses_in_addressbook + (MatcherProp *prop, const gchar *str, gint type) +{ + GSList *address_list = NULL; + GSList *walk; + gboolean res = FALSE; + + if (str == NULL || *str == 0) + return FALSE; + + /* XXX: perhaps complete with comments too */ + address_list = address_list_append(address_list, str); + if (!address_list) + return FALSE; + + start_address_completion(); + res = FALSE; + for (walk = address_list; walk != NULL; walk = walk->next) { + gboolean found = complete_address(walk->data) ? TRUE : FALSE; + + g_free(walk->data); + if (!found && type == MATCHTYPE_ALL_IN_ADDRESSBOOK) { + res = FALSE; + break; + } else if (found) + res = TRUE; + } + + g_slist_free(address_list); + + end_address_completion(); + + return res; +} + /*! *\brief Find out if a string matches a condition * @@ -301,6 +339,11 @@ static gboolean matcherprop_string_match(MatcherProp *prop, const gchar *str) return TRUE; else return FALSE; + + case MATCHTYPE_ALL_IN_ADDRESSBOOK: + case MATCHTYPE_ANY_IN_ADDRESSBOOK: + return match_with_addresses_in_addressbook + (prop, str, prop->matchtype); case MATCHTYPE_MATCH: return (strstr(str, prop->expr) != NULL); @@ -1077,6 +1120,8 @@ gchar *matcherprop_to_string(MatcherProp *matcher) case MATCHTYPE_MATCHCASE: case MATCHTYPE_REGEXP: case MATCHTYPE_REGEXPCASE: + case MATCHTYPE_ALL_IN_ADDRESSBOOK: + case MATCHTYPE_ANY_IN_ADDRESSBOOK: quoted_expr = matcher_quote_str(matcher->expr); if (matcher->header) { gchar * quoted_header; @@ -1457,7 +1502,7 @@ void prefs_matcher_read_config(void) if (f != NULL) { matcher_parser_start_parsing(f); - fclose(f); + fclose(matcher_parserin); } else { /* previous version compatibily */ diff --git a/src/matcher.h b/src/matcher.h index 8cfb0cf4f..c8d2484b7 100644 --- a/src/matcher.h +++ b/src/matcher.h @@ -104,6 +104,8 @@ enum { MT_(MATCH), MT_(REGEXPCASE), MT_(REGEXP), + MT_(ANY_IN_ADDRESSBOOK), + MT_(ALL_IN_ADDRESSBOOK), /* actions */ MA_(SCORE), MA_(EXECUTE), diff --git a/src/matcher_parser_parse.y b/src/matcher_parser_parse.y index 62c7d634c..01dfb764a 100644 --- a/src/matcher_parser_parse.y +++ b/src/matcher_parser_parse.y @@ -225,6 +225,7 @@ int matcher_parserwrap(void) %token MATCHER_NOT_MESSAGE MATCHER_BODY_PART MATCHER_NOT_BODY_PART %token MATCHER_TEST MATCHER_NOT_TEST MATCHER_MATCHCASE MATCHER_MATCH %token MATCHER_REGEXPCASE MATCHER_REGEXP MATCHER_SCORE MATCHER_MOVE +%token MATCHER_ANY_IN_ADDRESSBOOK MATCHER_ALL_IN_ADDRESSBOOK %token MATCHER_COPY MATCHER_DELETE MATCHER_MARK MATCHER_UNMARK %token MATCHER_LOCK MATCHER_UNLOCK %token MATCHER_EXECUTE @@ -395,6 +396,14 @@ MATCHER_MATCHCASE { match_type = MATCHTYPE_REGEXP; } +| MATCHER_ANY_IN_ADDRESSBOOK +{ + match_type = MATCHTYPE_ANY_IN_ADDRESSBOOK; +} +| MATCHER_ALL_IN_ADDRESSBOOK +{ + match_type = MATCHTYPE_ALL_IN_ADDRESSBOOK; +} ; condition: diff --git a/src/mbox.c b/src/mbox.c index db19a6099..e3acab807 100644 --- a/src/mbox.c +++ b/src/mbox.c @@ -56,7 +56,7 @@ } \ } -gint proc_mbox(FolderItem *dest, const gchar *mbox) +gint proc_mbox(FolderItem *dest, const gchar *mbox, gboolean apply_filter) { FILE *mbox_fp; gchar buf[MSGBUFSIZE], from_line[MSGBUFSIZE]; @@ -214,7 +214,7 @@ gint proc_mbox(FolderItem *dest, const gchar *mbox) } msginfo = folder_item_get_msginfo(dropfolder, msgnum); - if (!procmsg_msginfo_filter(msginfo)) + if (!apply_filter || !procmsg_msginfo_filter(msginfo)) folder_item_move_msg(dest, msginfo); procmsg_msginfo_free(msginfo); diff --git a/src/mbox.h b/src/mbox.h index 240d56db1..ef3c6a12e 100644 --- a/src/mbox.h +++ b/src/mbox.h @@ -34,7 +34,8 @@ typedef enum { /* file name should be locale encode. */ gint proc_mbox (FolderItem *dest, - const gchar *mbox); + const gchar *mbox, + gboolean apply_filter); gint lock_mbox (const gchar *base, LockType type); gint unlock_mbox (const gchar *base, diff --git a/src/messageview.c b/src/messageview.c index c77fc8818..19c24b664 100644 --- a/src/messageview.c +++ b/src/messageview.c @@ -1,6 +1,6 @@ /* * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2003 Hiroyuki Yamamoto + * Copyright (C) 1999-2004 Hiroyuki Yamamoto * * 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 @@ -196,6 +196,8 @@ static GtkItemFactoryEntry msgview_entries[] = CODESET_ACTION(C_ISO_8859_5)}, {N_("/_View/_Code set/Cyrillic (KOI8-_R)"), CODESET_ACTION(C_KOI8_R)}, + {N_("/_View/_Code set/Cyrillic (KOI8-U)"), + CODESET_ACTION(C_KOI8_U)}, {N_("/_View/_Code set/Cyrillic (Windows-1251)"), CODESET_ACTION(C_CP1251)}, CODESET_SEPARATOR, @@ -237,7 +239,7 @@ static GtkItemFactoryEntry msgview_entries[] = {N_("/_View/---"), NULL, NULL, 0, ""}, {N_("/_View/Mess_age source"), NULL, view_source_cb, 0, NULL}, - {N_("/_View/Show all _header"), NULL, show_all_header_cb, 0, ""}, + {N_("/_View/Show all _headers"),NULL, show_all_header_cb, 0, ""}, {N_("/_Message"), NULL, NULL, 0, ""}, {N_("/_Message/Compose _new message"), @@ -319,20 +321,23 @@ MessageView *messageview_create(MainWindow *mainwin) GTK_WIDGET_PTR(mimeview), TRUE, TRUE, 0); gtk_widget_show(vbox); - messageview->vbox = vbox; - messageview->new_window = FALSE; - messageview->window = NULL; - messageview->headerview = headerview; - messageview->mimeview = mimeview; + messageview->vbox = vbox; + messageview->new_window = FALSE; + messageview->window = NULL; + messageview->headerview = headerview; + messageview->mimeview = mimeview; messageview->noticeview = noticeview; messageview->mainwin = mainwin; + + messageview->statusbar = NULL; + messageview->statusbar_cid = 0; + messageview->msginfo_update_callback_id = hooks_register_hook(MSGINFO_UPDATE_HOOKLIST, messageview_update_msg, (gpointer) messageview); return messageview; } - GList *messageview_get_msgview_list(void) { return msgview_list; @@ -354,22 +359,32 @@ void messageview_add_toolbar(MessageView *msgview, GtkWidget *window) GtkWidget *handlebox; GtkWidget *vbox; GtkWidget *menubar; + GtkWidget *statusbar; GtkItemFactory *ifactory; guint n_menu_entries; vbox = gtk_vbox_new(FALSE, 0); gtk_widget_show(vbox); gtk_container_add(GTK_CONTAINER(window), vbox); - + n_menu_entries = sizeof(msgview_entries) / sizeof(msgview_entries[0]); menubar = menubar_create(window, msgview_entries, n_menu_entries, "", msgview); + gtk_widget_show(menubar); gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0); handlebox = gtk_handle_box_new(); gtk_box_pack_start(GTK_BOX(vbox), handlebox, FALSE, FALSE, 0); msgview->toolbar = toolbar_create(TOOLBAR_MSGVIEW, handlebox, (gpointer)msgview); + + statusbar = gtk_statusbar_new(); + gtk_widget_show(statusbar); + gtk_box_pack_end(GTK_BOX(vbox), statusbar, FALSE, FALSE, 0); + msgview->statusbar = statusbar; + msgview->statusbar_cid = gtk_statusbar_get_context_id + (GTK_STATUSBAR(statusbar), "Message View"); + msgview->handlebox = handlebox; msgview->menubar = menubar; @@ -383,8 +398,8 @@ void messageview_add_toolbar(MessageView *msgview, GtkWidget *window) MessageView *messageview_create_with_new_window(MainWindow *mainwin) { - GtkWidget *window; MessageView *msgview; + GtkWidget *window; window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(window), _("Sylpheed - Message View")); @@ -765,35 +780,47 @@ void messageview_destroy(MessageView *messageview) void messageview_delete(MessageView *msgview) { - MsgInfo *msginfo = (MsgInfo *) msgview->msginfo; + MsgInfo *msginfo = NULL; FolderItem *trash = NULL; PrefsAccount *ac = NULL; - g_return_if_fail(msginfo != NULL); - - /* to get the trash folder, we have to choose either - * the folder's or account's trash default - we prefer - * the one in the account prefs */ - if (msginfo->folder) { - if (NULL != (ac = account_find_from_item(msginfo->folder))) - trash = account_get_special_folder(ac, F_TRASH); - if (!trash && msginfo->folder->folder) - trash = msginfo->folder->folder->trash; - /* if still not found, use the default */ - if (!trash) - trash = folder_get_default_trash(); - } - - g_return_if_fail(trash != NULL); - - if (prefs_common.immediate_exec) - /* TODO: Delete from trash */ - folder_item_move_msg(trash, msginfo); - else { - procmsg_msginfo_set_to_folder(msginfo, trash); - procmsg_msginfo_set_flags(msginfo, MSG_DELETED, 0); - /* NOTE: does not update to next message in summaryview */ - } + if (msgview->msginfo && msgview->mainwin && msgview->mainwin->summaryview) + msginfo = summary_get_selected_msg(msgview->mainwin->summaryview); + + /* need a procmsg_msginfo_equal() */ + if (msginfo && msgview->msginfo && + msginfo->msgnum == msgview->msginfo->msgnum && + msginfo->folder == msgview->msginfo->folder) { + summary_delete(msgview->mainwin->summaryview); + } else { + msginfo = msgview->msginfo; + + g_return_if_fail(msginfo != NULL); + + /* to get the trash folder, we have to choose either + * the folder's or account's trash default - we prefer + * the one in the account prefs */ + if (msginfo->folder) { + if (NULL != (ac = account_find_from_item(msginfo->folder))) + trash = account_get_special_folder(ac, F_TRASH); + if (!trash && msginfo->folder->folder) + trash = msginfo->folder->folder->trash; + /* if still not found, use the default */ + if (!trash) + trash = folder_get_default_trash(); + } + + g_return_if_fail(trash != NULL); + + if (prefs_common.immediate_exec) + /* TODO: Delete from trash */ + folder_item_move_msg(trash, msginfo); + else { + procmsg_msginfo_set_to_folder(msginfo, trash); + procmsg_msginfo_set_flags(msginfo, MSG_DELETED, 0); + /* NOTE: does not update to next message in summaryview */ + } + } } /* @@ -891,6 +918,7 @@ gboolean messageview_search_string_backward(MessageView *messageview, TextView *text; text = messageview_get_current_textview(messageview); + if (text) return textview_search_string_backward(text, str, case_sens); return FALSE; @@ -1188,6 +1216,7 @@ static void show_all_header_cb(gpointer data, guint action, GtkWidget *widget) messageview_show(messageview, msginfo, GTK_CHECK_MENU_ITEM(widget)->active); procmsg_msginfo_free(msginfo); + main_window_set_menu_sensitive(messageview->mainwin); } static void compose_cb(gpointer data, guint action, GtkWidget *widget) @@ -1383,3 +1412,22 @@ static gboolean messageview_update_msg(gpointer source, gpointer data) return FALSE; } + +void messageview_set_menu_sensitive(MessageView *messageview) +{ + GtkItemFactory *ifactory; + GtkWidget *menuitem; + + if (!messageview && !messageview->new_window) + return; + /* do some smart things */ + if (!messageview->menubar) return; + ifactory = gtk_item_factory_from_widget(messageview->menubar); + if (!ifactory) return; + if (messageview->mainwin->type == SEPARATE_MESSAGE) { + menuitem = gtk_item_factory_get_widget(ifactory, "/View/Show all headers"); + gtk_check_menu_item_set_active + (GTK_CHECK_MENU_ITEM(menuitem), + messageview->mimeview->textview->show_all_headers); + } +} diff --git a/src/messageview.h b/src/messageview.h index 4d0533ccd..a4d59f0c7 100644 --- a/src/messageview.h +++ b/src/messageview.h @@ -1,6 +1,6 @@ /* * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2003 Hiroyuki Yamamoto + * Copyright (C) 1999-2004 Hiroyuki Yamamoto * * 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 @@ -49,6 +49,8 @@ struct _MessageView HeaderView *headerview; MimeView *mimeview; NoticeView *noticeview; + GtkWidget *statusbar; + gint statusbar_cid; MainWindow *mainwin; @@ -104,4 +106,7 @@ void messageview_add_toolbar (MessageView *msgview, GtkWidget *vbox); void messageview_reflect_prefs_pixmap_theme (void); gchar *messageview_get_selection (MessageView *msgview); + +void messageview_set_menu_sensitive (MessageView *msgview); + #endif /* __MESSAGEVIEW_H__ */ diff --git a/src/mh.c b/src/mh.c index a6ce2708d..ff971b680 100644 --- a/src/mh.c +++ b/src/mh.c @@ -107,52 +107,41 @@ static gboolean mh_rename_folder_func (GNode *node, static gchar *mh_item_get_path (Folder *folder, FolderItem *item); -static FolderClass mh_class = -{ - F_MH, - "mh", - "MH", - - /* Folder functions */ - mh_folder_new, - mh_folder_destroy, - folder_local_set_xml, - folder_local_get_xml, - mh_scan_tree, - mh_create_tree, - - /* FolderItem functions */ - NULL, - NULL, - NULL, - NULL, - mh_item_get_path, - mh_create_folder, - mh_rename_folder, - mh_remove_folder, - NULL, - mh_get_num_list, - NULL, - NULL, - NULL, - NULL, - - /* Message functions */ - mh_get_msginfo, - NULL, - mh_fetch_msg, - mh_add_msg, - mh_add_msgs, - mh_copy_msg, - NULL, - mh_remove_msg, - mh_remove_all_msg, - mh_is_msg_changed, - NULL, -}; +static FolderClass mh_class; FolderClass *mh_get_class(void) { + if (mh_class.idstr == NULL) { + mh_class.type = F_MH; + mh_class.idstr = "mh"; + mh_class.uistr = "MH"; + + /* Folder functions */ + mh_class.new_folder = mh_folder_new; + mh_class.destroy_folder = mh_folder_destroy; + mh_class.set_xml = folder_local_set_xml; + mh_class.get_xml = folder_local_get_xml; + mh_class.scan_tree = mh_scan_tree; + mh_class.create_tree = mh_create_tree; + + /* FolderItem functions */ + mh_class.item_get_path = mh_item_get_path; + mh_class.create_folder = mh_create_folder; + mh_class.rename_folder = mh_rename_folder; + mh_class.remove_folder = mh_remove_folder; + mh_class.get_num_list = mh_get_num_list; + + /* Message functions */ + mh_class.get_msginfo = mh_get_msginfo; + mh_class.fetch_msg = mh_fetch_msg; + mh_class.add_msg = mh_add_msg; + mh_class.add_msgs = mh_add_msgs; + mh_class.copy_msg = mh_copy_msg; + mh_class.remove_msg = mh_remove_msg; + mh_class.remove_all_msg = mh_remove_all_msg; + mh_class.is_msg_changed = mh_is_msg_changed; + } + return &mh_class; } diff --git a/src/mimeview.c b/src/mimeview.c index 39bf43123..6809bb694 100644 --- a/src/mimeview.c +++ b/src/mimeview.c @@ -84,6 +84,11 @@ static void mimeview_show_message_part (MimeView *mimeview, MimeInfo *partinfo); static void mimeview_change_view_type (MimeView *mimeview, MimeViewType type); +gchar *mimeview_get_filename_for_part (MimeInfo *partinfo, + const gchar *basedir, + gint number); +static gboolean mimeview_write_part (const gchar *filename, + MimeInfo *partinfo); static void mimeview_selected (GtkCTree *ctree, GtkCTreeNode *node, @@ -537,7 +542,7 @@ static MimeViewer *get_viewer_for_mimeinfo(MimeView *mimeview, MimeInfo *partinf if (filename != NULL) content_type = procmime_get_mime_type(filename); } else { - content_type = g_strdup_printf("%s/%s", procmime_get_type_str(partinfo->type), partinfo->subtype); + content_type = procmime_get_content_type_str(partinfo->type, partinfo->subtype); } if (content_type != NULL) { @@ -960,106 +965,137 @@ static void mimeview_drag_data_get(GtkWidget *widget, g_free(filename); } +/** + * Returns a filename (with path) for an attachment + * \param partinfo The attachment to save + * \param basedir The target directory + * \param number Used for dummy filename if attachment is unnamed + */ +gchar *mimeview_get_filename_for_part(MimeInfo *partinfo, + const gchar *basedir, + gint number) +{ + gchar *fullname; + gchar *filename; + + filename = g_strdup(get_part_name(partinfo)); + if (!filename || !*filename) + filename = g_strdup_printf("noname.%d", number); + subst_for_shellsafe_filename(filename); + + fullname = g_strconcat + (basedir, G_DIR_SEPARATOR_S, (filename[0] == G_DIR_SEPARATOR) + ? &filename[1] : filename, NULL); + subst_chars(fullname, "/\\", G_DIR_SEPARATOR); + + g_free(filename); + return fullname; +} + +/** + * Write a single attachment to file + * \param filename Filename with path + * \param partinfo Attachment to save + */ +static gboolean mimeview_write_part(const gchar *filename, + MimeInfo *partinfo) +{ + gchar *dir; + + dir= g_dirname(filename); + if (!is_dir_exist(dir)) + make_dir_hier(dir); + g_free(dir); + + if (is_file_exist(filename)) { + AlertValue aval; + gchar *res; + + res = g_strdup_printf(_("Overwrite existing file '%s'?"), + filename); + aval = alertpanel(_("Overwrite"), res, _("OK"), + _("Cancel"), NULL); + g_free(res); + if (G_ALERTDEFAULT != aval) return FALSE; + } + + if (procmime_get_part(filename, partinfo) < 0) { + alertpanel_error + (_("Can't save the part of multipart message.")); + return FALSE; + } + + return TRUE; +} + +/** + * Menu callback: Save all attached files + * \param mimeview Current display + */ static void mimeview_save_all(MimeView *mimeview) { + MimeInfo *partinfo; gchar *dirname; - gchar *defname = NULL; - MimeInfo *attachment; - gchar buf[1024]; + gchar *startdir = NULL; + gint number = 1; if (!mimeview->opened) return; if (!mimeview->file) return; + if (!mimeview->mimeinfo) return; - attachment = mimeview->mimeinfo; - g_return_if_fail(attachment != NULL); + partinfo = mimeview->mimeinfo; + if (prefs_common.attach_save_dir) + startdir = g_strconcat(prefs_common.attach_save_dir, + G_DIR_SEPARATOR_S, NULL); - dirname = filesel_select_file(_("Save as"), defname); - if (!dirname) return; + dirname = filesel_select_file(_("Select destination folder"), startdir); + if (!dirname) { + if (startdir) g_free(startdir); + return; + } if (!is_dir_exist (dirname)) { alertpanel_error(_("`%s' is not a directory."), dirname); - g_free (dirname); - dirname = NULL; + if (startdir) g_free(startdir); return; } - - { /* add a / after the dirname, in case the user didn't */ - gchar *dirname_tmp = NULL; - int dirname_last_char = strlen (dirname) - 1; - - if (dirname[dirname_last_char] != G_DIR_SEPARATOR) { - dirname_tmp = g_strconcat (dirname, G_DIR_SEPARATOR_S, NULL); - g_free (dirname); - dirname = dirname_tmp; - } - } - /* for each attachment, extract it in the selected dir. */ - while (attachment != NULL) { - if (attachment->type != MIMETYPE_MESSAGE && - attachment->type != MIMETYPE_MULTIPART && - attachment->disposition != DISPOSITIONTYPE_INLINE) { - static guint subst_cnt = 1; - gchar *attachdir; - gchar *attachname = g_strdup(get_part_name(attachment)); - AlertValue aval = G_ALERTDEFAULT; - gchar *res; - - if (!attachname || !strlen(attachname)) - attachname = g_strdup_printf("noname.%d",subst_cnt++); - subst_chars(attachname, ":?*&|<>\t\r\n", '_'); - g_snprintf(buf, sizeof(buf), "%s%s", - dirname, - (attachname[0] == G_DIR_SEPARATOR) - ? &attachname[1] - : attachname); - subst_chars(buf, "/\\", G_DIR_SEPARATOR); - attachdir = g_dirname(buf); - make_dir_hier(attachdir); - g_free(attachdir); - - if (is_file_exist(buf)) { - res = g_strdup_printf(_("Overwrite existing file '%s'?"), - attachname); - aval = alertpanel(_("Overwrite"), res, _("OK"), - _("Cancel"), NULL); - g_free(res); - } - g_free(attachname); - - if ((G_ALERTDEFAULT != aval) || (procmime_get_part(buf, attachment) < 0)) - alertpanel_error(_("Can't save the part of multipart message.")); + if (dirname[strlen(dirname)-1] == G_DIR_SEPARATOR) + dirname[strlen(dirname)-1] = '\0'; + + while (partinfo != NULL) { + if (partinfo->type != MIMETYPE_MESSAGE && + partinfo->type != MIMETYPE_MULTIPART && + partinfo->disposition != DISPOSITIONTYPE_INLINE) { + gchar *filename = mimeview_get_filename_for_part + (partinfo, dirname, number++); + + mimeview_write_part(filename, partinfo); + g_free(filename); } - attachment = procmime_mimeinfo_next(attachment); + partinfo = procmime_mimeinfo_next(partinfo); } -} -static void mimeview_display_as_text(MimeView *mimeview) -{ - MimeInfo *partinfo; + if (prefs_common.attach_save_dir) + g_free(prefs_common.attach_save_dir); - if (!mimeview->opened) return; + prefs_common.attach_save_dir = g_strdup(dirname); - partinfo = mimeview_get_selected_part(mimeview); - if (!partinfo) { - partinfo = (MimeInfo *) gtk_object_get_data - (GTK_OBJECT(mimeview->popupmenu), - "pop_partinfo"); - gtk_object_set_data(GTK_OBJECT(mimeview->popupmenu), - "pop_partinfo", NULL); - - } - g_return_if_fail(partinfo != NULL); - mimeview_show_message_part(mimeview, partinfo); + if (startdir) g_free(startdir); } +/** + * Menu callback: Save the selected attachment + * \param mimeview Current display + */ static void mimeview_save_as(MimeView *mimeview) { gchar *filename; gchar *defname = NULL; + gchar *filepath = NULL; + gchar *filedir = NULL; MimeInfo *partinfo; - gchar *res; const gchar *partname = NULL; if (!mimeview->opened) return; @@ -1077,24 +1113,51 @@ static void mimeview_save_as(MimeView *mimeview) if ((partname = get_part_name(partinfo)) != NULL) { Xstrdup_a(defname, partname, return); - subst_for_filename(defname); + subst_for_shellsafe_filename(defname); } - filename = filesel_select_file(_("Save as"), defname); - if (!filename) return; - if (is_file_exist(filename)) { - AlertValue aval; - res = g_strdup_printf(_("Overwrite existing file '%s'?"), - filename); - aval = alertpanel(_("Overwrite"), res, _("OK"), - _("Cancel"), NULL); - g_free(res); - if (G_ALERTDEFAULT != aval) return; + if (prefs_common.attach_save_dir) + filepath = g_strconcat(prefs_common.attach_save_dir, + G_DIR_SEPARATOR_S, defname, NULL); + else + filepath = g_strdup(defname); + + filename = filesel_select_file(_("Save as"), filepath); + if (!filename) { + g_free(filepath); + return; } - if (procmime_get_part(filename, partinfo) < 0) - alertpanel_error - (_("Can't save the part of multipart message.")); + mimeview_write_part(filename, partinfo); + + filedir = g_dirname(filename); + if (filedir && strcmp(filedir, ".")) { + if (prefs_common.attach_save_dir) + g_free(prefs_common.attach_save_dir); + prefs_common.attach_save_dir = g_strdup(filedir); + } + + g_free(filedir); + g_free(filepath); +} + +static void mimeview_display_as_text(MimeView *mimeview) +{ + MimeInfo *partinfo; + + if (!mimeview->opened) return; + + partinfo = mimeview_get_selected_part(mimeview); + if (!partinfo) { + partinfo = (MimeInfo *) gtk_object_get_data + (GTK_OBJECT(mimeview->popupmenu), + "pop_partinfo"); + gtk_object_set_data(GTK_OBJECT(mimeview->popupmenu), + "pop_partinfo", NULL); + + } + g_return_if_fail(partinfo != NULL); + mimeview_show_message_part(mimeview, partinfo); } static void mimeview_launch(MimeView *mimeview) @@ -1207,7 +1270,7 @@ static void mimeview_view_file(const gchar *filename, MimeInfo *partinfo, } else { gchar *content_type; - content_type = g_strdup_printf("%s/%s", procmime_get_type_str(partinfo->type), partinfo->subtype); + content_type = procmime_get_content_type_str(partinfo->type, partinfo->subtype); g_snprintf(m_buf, sizeof(m_buf), mime_cmdline, content_type, "%s"); g_free(content_type); @@ -1421,7 +1484,8 @@ static void icon_list_append_icon (MimeView *mimeview, MimeInfo *mimeinfo) GtkWidget *vbox; GtkWidget *button; gchar *tip; - const gchar *desc = NULL; + const gchar *desc = NULL; + gchar *content_type; StockPixmap stockp; vbox = mimeview->icon_vbox; @@ -1470,16 +1534,17 @@ static void icon_list_append_icon (MimeView *mimeview, MimeInfo *mimeinfo) desc = get_part_name(mimeinfo); } + content_type = procmime_get_content_type_str(mimeinfo->type, + mimeinfo->subtype); + if (desc && *desc) - tip = g_strdup_printf("%s\n%s/%s\n%s", desc, - procmime_get_type_str(mimeinfo->type), - mimeinfo->subtype, - to_human_readable(mimeinfo->length)); + tip = g_strdup_printf("%s\n%s\n%s", desc, content_type, + to_human_readable(mimeinfo->length)); else - tip = g_strdup_printf("%s/%s\n%s", - procmime_get_type_str(mimeinfo->type), - mimeinfo->subtype, - to_human_readable(mimeinfo->length)); + tip = g_strdup_printf("%s\n%s", content_type, + to_human_readable(mimeinfo->length)); + + g_free(content_type); gtk_tooltips_set_tip(mimeview->tooltips, button, tip, NULL); g_free(tip); diff --git a/src/msgcache.c b/src/msgcache.c index 6273f54cc..43cf899b7 100644 --- a/src/msgcache.c +++ b/src/msgcache.c @@ -84,7 +84,7 @@ void msgcache_add_msg(MsgCache *cache, MsgInfo *msginfo) cache->memusage += procmsg_msginfo_memusage(msginfo); cache->last_access = time(NULL); - debug_print("Cache size: %d messages, %d byte\n", g_hash_table_size(cache->msgnum_table), cache->memusage); + debug_print("Cache size: %d messages, %d bytes\n", g_hash_table_size(cache->msgnum_table), cache->memusage); } void msgcache_remove_msg(MsgCache *cache, guint msgnum) diff --git a/src/news.c b/src/news.c index d0c81e80c..9ffd5e833 100644 --- a/src/news.c +++ b/src/news.c @@ -1,6 +1,6 @@ /* * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2003 Hiroyuki Yamamoto + * Copyright (C) 1999-2004 Hiroyuki Yamamoto * * 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 @@ -131,52 +131,30 @@ static gchar *news_folder_get_path (Folder *folder); gchar *news_item_get_path (Folder *folder, FolderItem *item); -static FolderClass news_class = -{ - F_NEWS, - "news", - "News", - - /* Folder functions */ - news_folder_new, - news_folder_destroy, - NULL, - NULL, - NULL, - NULL, - - /* FolderItem functions */ - NULL, - NULL, - NULL, - NULL, - news_item_get_path, - NULL, - NULL, - NULL, - NULL, - news_get_num_list, - NULL, - NULL, - NULL, - news_scan_required, - - /* Message functions */ - news_get_msginfo, - news_get_msginfos, - news_fetch_msg, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, -}; +static FolderClass news_class; FolderClass *news_get_class(void) { + if (news_class.idstr == NULL) { + news_class.type = F_NEWS; + news_class.idstr = "news"; + news_class.uistr = "News"; + + /* Folder functions */ + news_class.new_folder = news_folder_new; + news_class.destroy_folder = news_folder_destroy; + + /* FolderItem functions */ + news_class.item_get_path = news_item_get_path; + news_class.get_num_list = news_get_num_list; + news_class.scan_required = news_scan_required; + + /* Message functions */ + news_class.get_msginfo = news_get_msginfo; + news_class.get_msginfos = news_get_msginfos; + news_class.fetch_msg = news_fetch_msg; + }; + return &news_class; } @@ -296,8 +274,8 @@ static NNTPSession *news_session_get(Folder *folder) if (nntp_mode(NNTP_SESSION(rfolder->session), FALSE) != NN_SUCCESS) { - log_warning("NNTP connection to %s:%d has been" - " disconnected. Reconnecting...\n", + log_warning(_("NNTP connection to %s:%d has been" + " disconnected. Reconnecting...\n"), folder->account->nntp_server, folder->account->set_nntpport ? folder->account->nntpport : NNTP_PORT); @@ -338,7 +316,10 @@ static gchar *news_fetch_msg(Folder *folder, FolderItem *item, gint num) ok = news_select_group(session, item->path, NULL, NULL, NULL); if (ok != NN_SUCCESS) { - g_warning("can't select group %s\n", item->path); + if (ok == NN_SOCKET) { + session_destroy(SESSION(session)); + REMOTE_FOLDER(folder)->session = NULL; + } g_free(filename); return NULL; } @@ -346,10 +327,12 @@ static gchar *news_fetch_msg(Folder *folder, FolderItem *item, gint num) debug_print("getting article %d...\n", num); ok = news_get_article(NNTP_SESSION(REMOTE_FOLDER(folder)->session), num, filename); - if (ok < 0) { + if (ok != NN_SUCCESS) { g_warning("can't read article %d\n", num); - session_destroy(SESSION(session)); - REMOTE_FOLDER(folder)->session = NULL; + if (ok == NN_SOCKET) { + session_destroy(SESSION(session)); + REMOTE_FOLDER(folder)->session = NULL; + } g_free(filename); return NULL; } @@ -402,6 +385,7 @@ GSList *news_get_group_list(Folder *folder) if ((fp = fopen(filename, "rb")) == NULL) { NNTPSession *session; + gint ok; session = news_session_get(folder); if (!session) { @@ -409,12 +393,17 @@ GSList *news_get_group_list(Folder *folder) return NULL; } - if (nntp_list(session) != NN_SUCCESS) { + ok = nntp_list(session); + if (ok != NN_SUCCESS) { + if (ok == NN_SOCKET) { + session_destroy(SESSION(session)); + REMOTE_FOLDER(folder)->session = NULL; + } g_free(filename); return NULL; } if (recv_write_to_file(SESSION(session)->sock, filename) < 0) { - log_warning("can't retrieve newsgroup list\n"); + log_warning(_("can't retrieve newsgroup list\n")); session_destroy(SESSION(session)); REMOTE_FOLDER(folder)->session = NULL; g_free(filename); @@ -527,7 +516,11 @@ gint news_post_stream(Folder *folder, FILE *fp) ok = nntp_post(session, fp); if (ok != NN_SUCCESS) { - log_warning("can't post article.\n"); + log_warning(_("can't post article.\n")); + if (ok == NN_SOCKET) { + session_destroy(SESSION(session)); + REMOTE_FOLDER(folder)->session = NULL; + } return -1; } @@ -538,20 +531,25 @@ static gint news_get_article_cmd(NNTPSession *session, const gchar *cmd, gint num, gchar *filename) { gchar *msgid; + gint ok; - if (nntp_get_article(session, cmd, num, &msgid) - != NN_SUCCESS) - return -1; + ok = nntp_get_article(session, cmd, num, &msgid); + if (ok != NN_SUCCESS) + return ok; debug_print("Message-Id = %s, num = %d\n", msgid, num); g_free(msgid); - if (recv_write_to_file(SESSION(session)->sock, filename) < 0) { - log_warning("can't retrieve article %d\n", num); - return -1; + ok = recv_write_to_file(SESSION(session)->sock, filename); + if (ok < 0) { + log_warning(_("can't retrieve article %d\n"), num); + if (ok == -2) + return NN_SOCKET; + else + return NN_IOERR; } - return 0; + return NN_SUCCESS; } static gint news_get_article(NNTPSession *session, gint num, gchar *filename) @@ -592,6 +590,8 @@ static gint news_select_group(NNTPSession *session, const gchar *group, ok = nntp_group(session, group, num, first, last); if (ok == NN_SUCCESS) session->group = g_strdup(group); + else + log_warning(_("can't select group: %s\n"), group); return ok; } @@ -842,6 +842,7 @@ MsgInfo *news_get_msginfo(Folder *folder, FolderItem *item, gint num) NNTPSession *session; MsgInfo *msginfo = NULL; gchar buf[NNTPBUFSIZE]; + gint ok; session = news_session_get(folder); g_return_val_if_fail(session != NULL, NULL); @@ -851,8 +852,13 @@ MsgInfo *news_get_msginfo(Folder *folder, FolderItem *item, gint num) log_message(_("getting xover %d in %s...\n"), num, item->path); - if (nntp_xover(session, num, num) != NN_SUCCESS) { + ok = nntp_xover(session, num, num); + if (ok != NN_SUCCESS) { log_warning(_("can't get xover\n")); + if (ok == NN_SOCKET) { + session_destroy(SESSION(session)); + REMOTE_FOLDER(item->folder)->session = NULL; + } return NULL; } @@ -876,8 +882,13 @@ MsgInfo *news_get_msginfo(Folder *folder, FolderItem *item, gint num) msginfo->flags.tmp_flags = MSG_NEWS; msginfo->newsgroups = g_strdup(item->path); - if (nntp_xhdr(session, "to", num, num) != NN_SUCCESS) { + ok = nntp_xhdr(session, "to", num, num); + if (ok != NN_SUCCESS) { log_warning(_("can't get xhdr\n")); + if (ok == NN_SOCKET) { + session_destroy(SESSION(session)); + REMOTE_FOLDER(item->folder)->session = NULL; + } return msginfo; } @@ -890,8 +901,13 @@ MsgInfo *news_get_msginfo(Folder *folder, FolderItem *item, gint num) READ_TO_LISTEND("xhdr (to)"); - if (nntp_xhdr(session, "cc", num, num) != NN_SUCCESS) { + ok = nntp_xhdr(session, "cc", num, num); + if (ok != NN_SUCCESS) { log_warning(_("can't get xhdr\n")); + if (ok == NN_SOCKET) { + session_destroy(SESSION(session)); + REMOTE_FOLDER(item->folder)->session = NULL; + } return msginfo; } @@ -914,14 +930,20 @@ static GSList *news_get_msginfos_for_range(NNTPSession *session, FolderItem *ite GSList *llast = NULL; MsgInfo *msginfo; guint count = 0, lines = (end - begin + 2) * 3; + gint ok; g_return_val_if_fail(session != NULL, NULL); g_return_val_if_fail(item != NULL, NULL); log_message(_("getting xover %d - %d in %s...\n"), begin, end, item->path); - if (nntp_xover(session, begin, end) != NN_SUCCESS) { + ok = nntp_xover(session, begin, end); + if (ok != NN_SUCCESS) { log_warning(_("can't get xover\n")); + if (ok == NN_SOCKET) { + session_destroy(SESSION(session)); + REMOTE_FOLDER(item->folder)->session = NULL; + } return NULL; } @@ -957,8 +979,13 @@ static GSList *news_get_msginfos_for_range(NNTPSession *session, FolderItem *ite } } - if (nntp_xhdr(session, "to", begin, end) != NN_SUCCESS) { + ok = nntp_xhdr(session, "to", begin, end); + if (ok != NN_SUCCESS) { log_warning(_("can't get xhdr\n")); + if (ok == NN_SOCKET) { + session_destroy(SESSION(session)); + REMOTE_FOLDER(item->folder)->session = NULL; + } return newlist; } @@ -987,8 +1014,13 @@ static GSList *news_get_msginfos_for_range(NNTPSession *session, FolderItem *ite llast = llast->next; } - if (nntp_xhdr(session, "cc", begin, end) != NN_SUCCESS) { + ok = nntp_xhdr(session, "cc", begin, end); + if (ok != NN_SUCCESS) { log_warning(_("can't get xhdr\n")); + if (ok == NN_SOCKET) { + session_destroy(SESSION(session)); + REMOTE_FOLDER(item->folder)->session = NULL; + } return newlist; } diff --git a/src/plugins/clamav/clamav_plugin.c b/src/plugins/clamav/clamav_plugin.c index 5d96c1fc8..35be5cf22 100644 --- a/src/plugins/clamav/clamav_plugin.c +++ b/src/plugins/clamav/clamav_plugin.c @@ -74,7 +74,7 @@ static gboolean scan_func(GNode *node, gpointer data) gchar *outfile; int ret; unsigned long int size; - char *virname; + const char *virname; outfile = procmime_get_tmp_file_name(mimeinfo); if (procmime_get_part(outfile, mimeinfo) < 0) @@ -125,10 +125,11 @@ static gboolean mail_filtering_hook(gpointer source, gpointer data) if (config.clamav_enable_arc) params.scan_archive = TRUE; - if((ret = cl_loaddbdir(cl_retdbdir(), ¶ms.root, &no))) { + if ((ret = cl_loaddbdir(cl_retdbdir(), ¶ms.root, &no))) { debug_print("cl_loaddbdir: %s\n", cl_strerror(ret)); - exit(2); + return FALSE; } + debug_print("Database loaded (containing in total %d signatures)\n", no); cl_buildtrie(params.root); diff --git a/src/plugins/dillo_viewer/dillo_prefs.c b/src/plugins/dillo_viewer/dillo_prefs.c index 67e8cb935..7f4178e96 100644 --- a/src/plugins/dillo_viewer/dillo_prefs.c +++ b/src/plugins/dillo_viewer/dillo_prefs.c @@ -71,7 +71,7 @@ void dillo_prefs_init(void) prefs_set_default(param); prefs_read_config(param, PREFS_BLOCK_NAME, COMMON_RC); - prefs_page.page.path = "Message View/Dillo Browser"; + prefs_page.page.path = _("Message View/Dillo Browser"); prefs_page.page.create_widget = create_dillo_prefs_page; prefs_page.page.destroy_widget = destroy_dillo_prefs_page; prefs_page.page.save_page = save_dillo_prefs; diff --git a/src/plugins/image_viewer/viewer.c b/src/plugins/image_viewer/viewer.c index 73564e035..73ef60166 100644 --- a/src/plugins/image_viewer/viewer.c +++ b/src/plugins/image_viewer/viewer.c @@ -196,6 +196,9 @@ static void image_viewer_load_image(ImageViewer *imageviewer) { gchar *imgfile; + if (imageviewer->mimeinfo == NULL) + return; + imgfile = procmime_get_tmp_file_name(imageviewer->mimeinfo); if (procmime_get_part(imgfile, imageviewer->mimeinfo) < 0) { g_warning("Can't get mimepart file"); diff --git a/src/plugins/image_viewer/viewerprefs.c b/src/plugins/image_viewer/viewerprefs.c index 612176d6a..fa534c133 100644 --- a/src/plugins/image_viewer/viewerprefs.c +++ b/src/plugins/image_viewer/viewerprefs.c @@ -150,7 +150,7 @@ void image_viewer_prefs_init(void) prefs_set_default(param); prefs_read_config(param, PREFS_BLOCK_NAME, COMMON_RC); - imageviewer_page.page.path = "Message View/Image Viewer"; + imageviewer_page.page.path = _("Message View/Image Viewer"); imageviewer_page.page.create_widget = imageviewer_create_widget_func; imageviewer_page.page.destroy_widget = imageviewer_destroy_widget_func; imageviewer_page.page.save_page = imageviewer_save_func; diff --git a/src/pop.c b/src/pop.c index 2fd15a9b6..942cf9adf 100644 --- a/src/pop.c +++ b/src/pop.c @@ -1,6 +1,6 @@ /* * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2003 Hiroyuki Yamamoto + * Copyright (C) 1999-2004 Hiroyuki Yamamoto * * 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 @@ -35,7 +35,6 @@ #include "md5.h" #include "prefs_account.h" #include "utils.h" -#include "inc.h" #include "recv.h" #include "log.h" @@ -149,7 +148,7 @@ static gint pop3_getauth_apop_send(Pop3Session *session) if ((start = strchr(session->greeting, '<')) == NULL) { log_warning(_("Required APOP timestamp not found " - "in greeting\n")); + "in greeting\n")); session->error_val = PS_PROTOCOL; return -1; } @@ -345,7 +344,7 @@ static gint pop3_retr_recv(Pop3Session *session, const gchar *data, guint len) g_free(mail_receive_data.data); /* drop_ok: 0: success 1: don't receive -1: error */ - drop_ok = inc_drop_message(file, session); + drop_ok = session->drop_message(session, file); g_free(file); if (drop_ok < 0) { session->error_val = PS_IOERR; @@ -625,16 +624,17 @@ static Pop3State pop3_lookup_next(Pop3Session *session) msg->recv_time != RECV_TIME_KEEP && session->current_time - msg->recv_time >= ac->msg_leave_time * 24 * 60 * 60) { - log_print(_("POP3: Deleting expired message %d\n"), - session->cur_msg); + log_message + (_("POP3: Deleting expired message %d\n"), + session->cur_msg); pop3_delete_send(session); return POP3_DELETE; } if (size_limit_over) - log_print + log_message (_("POP3: Skipping message %d (%d bytes)\n"), - session->cur_msg, size); + session->cur_msg, size); if (size == 0 || msg->received || size_limit_over) { session->cur_total_bytes += size; diff --git a/src/pop.h b/src/pop.h index cfdea46e8..bf62212bd 100644 --- a/src/pop.h +++ b/src/pop.h @@ -1,6 +1,6 @@ /* * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2003 Hiroyuki Yamamoto + * Copyright (C) 1999-2004 Hiroyuki Yamamoto * * 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 @@ -143,6 +143,10 @@ struct _Pop3Session gchar *error_msg; gpointer data; + + /* virtual method to drop message */ + gint (*drop_message) (Pop3Session *session, + const gchar *file); }; #define POPBUFSIZE 512 diff --git a/src/prefs_account.c b/src/prefs_account.c index e631a1aad..2e40678aa 100644 --- a/src/prefs_account.c +++ b/src/prefs_account.c @@ -711,9 +711,12 @@ PrefsAccount *prefs_account_open(PrefsAccount *ac_prefs) _("Preferences for new account")); gtk_widget_hide(dialog.apply_btn); } else { + gchar *title; prefs_set_dialog(param); - gtk_window_set_title(GTK_WINDOW(dialog.window), - _("Account preferences")); + title = g_strdup_printf (_("%s - Account preferences"), + ac_prefs->account_name); + gtk_window_set_title(GTK_WINDOW(dialog.window), title); + g_free (title); gtk_widget_show(dialog.apply_btn); } diff --git a/src/prefs_actions.c b/src/prefs_actions.c index 381bbbc8a..853c9a36a 100644 --- a/src/prefs_actions.c +++ b/src/prefs_actions.c @@ -545,7 +545,7 @@ static void prefs_actions_delete_cb(GtkWidget *w, gpointer data) if (alertpanel(_("Delete action"), _("Do you really want to delete this action?"), - _("Yes"), _("No"), NULL) == G_ALERTALTERNATE) + _("Yes"), _("No"), NULL) != G_ALERTDEFAULT) return; action = gtk_clist_get_row_data(clist, row); diff --git a/src/prefs_common.c b/src/prefs_common.c index 7eb2e8b70..43972e7d7 100644 --- a/src/prefs_common.c +++ b/src/prefs_common.c @@ -661,6 +661,8 @@ static PrefParam param[] = { {"attach_desc", "TRUE", &prefs_common.attach_desc, P_BOOL, &message.chkbtn_attach_desc, prefs_set_data_from_toggle, prefs_set_toggle}, + {"attach_save_directory", NULL, + &prefs_common.attach_save_dir, P_STRING, NULL, NULL, NULL}, /* MIME viewer */ {"mime_image_viewer", "display '%s'", @@ -874,43 +876,56 @@ PrefsCommon *prefs_common_get(void) return &prefs_common; } -void prefs_common_read_config(void) +/* + * Read history list from the specified history file + */ +GList *prefs_common_read_history(const gchar *history) { FILE *fp; gchar *path; gchar buf[PREFSBUFSIZE]; + GList *tmp = NULL; - prefs_read_config(param, "Common", COMMON_RC); - - path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, COMMAND_HISTORY, + path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, history, NULL); if ((fp = fopen(path, "rb")) == NULL) { if (ENOENT != errno) FILE_OP_ERROR(path, "fopen"); g_free(path); - return; + return NULL; } g_free(path); while (fgets(buf, sizeof(buf), fp) != NULL) { g_strstrip(buf); if (buf[0] == '\0') continue; - prefs_common.mime_open_cmd_history = - add_history(prefs_common.mime_open_cmd_history, buf); + tmp = add_history(tmp, buf); } fclose(fp); + tmp = g_list_reverse(tmp); + + return tmp; +} + +void prefs_common_read_config(void) +{ + prefs_read_config(param, "Common", COMMON_RC); + prefs_common.mime_open_cmd_history = - g_list_reverse(prefs_common.mime_open_cmd_history); + prefs_common_read_history(COMMAND_HISTORY); + prefs_common.summary_quicksearch_history = + prefs_common_read_history(QUICKSEARCH_HISTORY); } -void prefs_common_save_config(void) +/* + * Save history list to the specified history file + */ +void prefs_common_save_history(const gchar *history, GList *list) { GList *cur; FILE *fp; gchar *path; - prefs_save_config(param, "Common", COMMON_RC); - - path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, COMMAND_HISTORY, + path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, history, NULL); if ((fp = fopen(path, "wb")) == NULL) { FILE_OP_ERROR(path, "fopen"); @@ -918,8 +933,7 @@ void prefs_common_save_config(void) return; } - for (cur = prefs_common.mime_open_cmd_history; - cur != NULL; cur = cur->next) { + for (cur = list; cur != NULL; cur = cur->next) { fputs((gchar *)cur->data, fp); fputc('\n', fp); } @@ -928,6 +942,16 @@ void prefs_common_save_config(void) g_free(path); } +void prefs_common_save_config(void) +{ + prefs_save_config(param, "Common", COMMON_RC); + + prefs_common_save_history(COMMAND_HISTORY, + prefs_common.mime_open_cmd_history); + prefs_common_save_history(QUICKSEARCH_HISTORY, + prefs_common.summary_quicksearch_history); +} + void prefs_common_open(void) { if (prefs_rc_is_readonly(COMMON_RC)) @@ -1959,7 +1983,7 @@ static void prefs_message_create(void) gtk_box_pack_start (GTK_BOX (hbox_linespc), label_linespc, FALSE, FALSE, 0); - PACK_CHECK_BUTTON(hbox1, chkbtn_headspc, _("Leave space on head")); + PACK_CHECK_BUTTON(hbox1, chkbtn_headspc, _("Indent text")); PACK_FRAME(vbox1, frame_scr, _("Scroll")); diff --git a/src/prefs_common.h b/src/prefs_common.h index b568e07bd..ed5f310ea 100644 --- a/src/prefs_common.h +++ b/src/prefs_common.h @@ -243,6 +243,7 @@ struct _PrefsCommon gchar *mime_image_viewer; gchar *mime_audio_player; gchar *mime_open_cmd; + gchar *attach_save_dir; GList *mime_open_cmd_history; @@ -301,6 +302,8 @@ struct _PrefsCommon gint summary_quicksearch_type; gulong color_new; + + GList *summary_quicksearch_history; }; extern PrefsCommon prefs_common; diff --git a/src/prefs_folder_item.c b/src/prefs_folder_item.c index e14d5687a..eea85f30f 100644 --- a/src/prefs_folder_item.c +++ b/src/prefs_folder_item.c @@ -588,12 +588,18 @@ static GSList *prefs_pages = NULL; void prefs_folder_item_open(FolderItem *item) { + gchar *id, *title; + if (prefs_pages == NULL) { register_general_page(); register_compose_page(); } - prefswindow_open(_("Settings for folder"), prefs_pages, item); + id = folder_item_get_identifier (item); + title = g_strdup_printf (_("%s - Settings for folder"), id); + g_free (id); + prefswindow_open(title, prefs_pages, item); + g_free (title); } void prefs_folder_item_register_page(PrefsPage *page) diff --git a/src/prefs_fonts.c b/src/prefs_fonts.c index d81e873a1..b9cd6f91d 100644 --- a/src/prefs_fonts.c +++ b/src/prefs_fonts.c @@ -95,7 +95,6 @@ static void prefs_font_select(GtkButton *button, GtkEntry *entry) "clicked", GTK_SIGNAL_FUNC(prefs_font_selection_ok), entry); - printf("%i\n", font_sel_conn_id); font_name = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1); gtk_font_selection_dialog_set_font_name(GTK_FONT_SELECTION_DIALOG(font_sel_win), font_name); @@ -151,7 +150,7 @@ void prefs_fonts_create_widget(PrefsPage *_page, GtkWindow *window, gtk_table_set_row_spacings(GTK_TABLE(table), 4); gtk_table_set_col_spacings(GTK_TABLE(table), 8); - tmplabel = gtk_label_new (_("Folder View")); + tmplabel = gtk_label_new (_("Folder List")); gtk_widget_show (tmplabel); gtk_table_attach (GTK_TABLE (table), tmplabel, 0, 1, 0, 1, (GtkAttachOptions) GTK_FILL, @@ -173,7 +172,7 @@ void prefs_fonts_create_widget(PrefsPage *_page, GtkWindow *window, gtk_signal_connect (GTK_OBJECT(tmpbutton), "clicked", GTK_SIGNAL_FUNC(prefs_font_select), entry_folderviewfont); - tmplabel = gtk_label_new (_("Summary View")); + tmplabel = gtk_label_new (_("Message List")); gtk_widget_show (tmplabel); gtk_table_attach (GTK_TABLE (table), tmplabel, 0, 1, 1, 2, (GtkAttachOptions) GTK_FILL, @@ -195,7 +194,7 @@ void prefs_fonts_create_widget(PrefsPage *_page, GtkWindow *window, gtk_signal_connect (GTK_OBJECT(tmpbutton), "clicked", GTK_SIGNAL_FUNC(prefs_font_select), entry_summaryviewfont); - tmplabel = gtk_label_new (_("Message View")); + tmplabel = gtk_label_new (_("Message")); gtk_widget_show (tmplabel); gtk_table_attach (GTK_TABLE (table), tmplabel, 0, 1, 2, 3, (GtkAttachOptions) GTK_FILL, diff --git a/src/prefs_template.c b/src/prefs_template.c index 9762153f0..af02d363d 100644 --- a/src/prefs_template.c +++ b/src/prefs_template.c @@ -544,7 +544,7 @@ static void prefs_template_delete_cb(void) if (alertpanel(_("Delete template"), _("Do you really want to delete this template?"), - _("Yes"), _("No"), NULL) == G_ALERTALTERNATE) + _("Yes"), _("No"), NULL) != G_ALERTDEFAULT) return; tmpl = gtk_clist_get_row_data(clist, row); diff --git a/src/prefs_themes.c b/src/prefs_themes.c index e46369f0d..0350ac484 100644 --- a/src/prefs_themes.c +++ b/src/prefs_themes.c @@ -1,6 +1,6 @@ /* * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 2003 Hiroyuki Yamamoto & the Sylpheed-Claws team + * Copyright (C) 2003-2004 Hiroyuki Yamamoto & the Sylpheed-Claws team * * 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 @@ -476,7 +476,7 @@ static void prefs_themes_btn_install_clicked_cb(GtkWidget *widget, gpointer data } if (getuid() == 0) { val = alertpanel(alert_title, - _("Do you want to install theme for system's all users?"), + _("Do you want to install theme for all users?"), _("Yes"), _("No"), _("Cancel")); switch (val) { case G_ALERTDEFAULT: @@ -507,17 +507,21 @@ static void prefs_themes_btn_install_clicked_cb(GtkWidget *widget, gpointer data prefs_themes_foreach_file(source, prefs_themes_file_install, cinfo); if (cinfo->status == NULL) { GList *insted; - - alertpanel_notice(_("Theme installed succesfully")); + /* update interface to show newly installed theme */ prefs_themes_get_themes_and_names(tdata); insted = g_list_find_custom(tdata->themes, (gpointer)(cinfo->dest), (GCompareFunc)strcmp2); - tdata->displayed = (gchar *)(insted->data); - prefs_themes_set_themes_menu(GTK_OPTION_MENU(tdata->page->op_menu), tdata); - prefs_themes_display_global_stats(tdata); - prefs_themes_get_theme_info(tdata); + if (NULL != insted) { + alertpanel_notice(_("Theme installed succesfully")); + tdata->displayed = (gchar *)(insted->data); + prefs_themes_set_themes_menu(GTK_OPTION_MENU(tdata->page->op_menu), tdata); + prefs_themes_display_global_stats(tdata); + prefs_themes_get_theme_info(tdata); + } + else + alertpanel_error(_("Failed installing theme")); } else alertpanel_error(_("File %s failed\nwhile installing theme."), cinfo->status); @@ -706,7 +710,7 @@ static gchar *prefs_themes_get_theme_stats(const gchar *dirname) dinfo = g_new0(DirInfo, 1); prefs_themes_foreach_file(dirname, prefs_themes_file_stats, dinfo); - stats = g_strdup_printf(_("%d files (%d icons), size is %s"), + stats = g_strdup_printf(_("%d files (%d icons), size: %s"), dinfo->files, dinfo->pixms, to_human_readable(dinfo->bytes)); g_free(dinfo); diff --git a/src/procmime.c b/src/procmime.c index 9cc84d347..9c01df12e 100644 --- a/src/procmime.c +++ b/src/procmime.c @@ -77,7 +77,7 @@ static gboolean free_func(GNode *node, gpointer data) { MimeInfo *mimeinfo = (MimeInfo *) node->data; - if(mimeinfo->tmpfile) + if (mimeinfo->tmpfile) unlink(mimeinfo->filename); g_free(mimeinfo->filename); @@ -193,7 +193,7 @@ MimeInfo *procmime_scan_message(MsgInfo *msginfo) MimeInfo *mimeinfo; filename = procmsg_get_message_file(msginfo); - if(!filename) + if (!filename) return NULL; if (msginfo->folder->stype != F_QUEUE && msginfo->folder->stype != F_DRAFT) @@ -233,11 +233,11 @@ gboolean procmime_decode_content(MimeInfo *mimeinfo) g_return_val_if_fail(mimeinfo != NULL, FALSE); - if(mimeinfo->encoding_type == ENC_BINARY) + if (mimeinfo->encoding_type == ENC_BINARY) return TRUE; infp = fopen(mimeinfo->filename, "rb"); - if(!infp) { + if (!infp) { perror("fopen"); return FALSE; } @@ -279,7 +279,7 @@ gboolean procmime_decode_content(MimeInfo *mimeinfo) gboolean flag = FALSE; while ((ftell(infp) < readend) && (fgets(buf, sizeof(buf), infp) != NULL)) { - if(!flag && strncmp(buf,"begin ", 6)) continue; + if (!flag && strncmp(buf,"begin ", 6)) continue; if (flag) { len = fromuutobits(outbuf, buf); @@ -302,7 +302,7 @@ gboolean procmime_decode_content(MimeInfo *mimeinfo) fclose(infp); stat(tmpfilename, &statbuf); - if(mimeinfo->tmpfile) + if (mimeinfo->tmpfile) unlink(mimeinfo->filename); g_free(mimeinfo->filename); mimeinfo->filename = tmpfilename; @@ -323,7 +323,7 @@ gint procmime_get_part(const gchar *outfile, MimeInfo *mimeinfo) g_return_val_if_fail(outfile != NULL, -1); g_return_val_if_fail(mimeinfo != NULL, -1); - if(mimeinfo->encoding_type != ENC_BINARY && !procmime_decode_content(mimeinfo)) + if (mimeinfo->encoding_type != ENC_BINARY && !procmime_decode_content(mimeinfo)) return -1; if ((infp = fopen(mimeinfo->filename, "rb")) == NULL) { @@ -439,7 +439,7 @@ void renderer_write_config(void) g_free(rcpath); - for(cur = renderer_list ; cur != NULL ; cur = cur->next) { + for (cur = renderer_list ; cur != NULL ; cur = cur->next) { struct ContentRenderer * renderer; renderer = cur->data; fprintf(pfile->fp, "%s %s\n", renderer->content_type, @@ -496,9 +496,9 @@ FILE *procmime_get_text_content(MimeInfo *mimeinfo) renderer = NULL; - content_type = g_strdup_printf("%s/%s", procmime_get_type_str(mimeinfo->type), - mimeinfo->subtype); - for(cur = renderer_list ; cur != NULL ; cur = cur->next) { + content_type = procmime_get_content_type_str(mimeinfo->type, + mimeinfo->subtype); + for (cur = renderer_list ; cur != NULL ; cur = cur->next) { struct ContentRenderer * cr; cr = cur->data; @@ -946,6 +946,21 @@ const gchar *procmime_get_type_str(MimeMediaType type) return NULL; } +/*! + *\brief Safe wrapper for content type string. + * + *\return const gchar * Pointer to content type string. + */ +gchar *procmime_get_content_type_str(MimeMediaType type, + const char *subtype) +{ + const gchar *type_str = NULL; + + if (subtype == NULL || !(type_str = procmime_get_type_str(type))) + return g_strdup("unknown"); + return g_strdup_printf("%s/%s", type_str, subtype); +} + void procmime_parse_mimepart(MimeInfo *parent, gchar *content_type, gchar *content_encoding, @@ -974,7 +989,7 @@ void procmime_parse_message_rfc822(MimeInfo *mimeinfo) FILE *fp; gint mime_major, mime_minor, a; - if(mimeinfo->encoding_type != ENC_BINARY && + if (mimeinfo->encoding_type != ENC_BINARY && mimeinfo->encoding_type != ENC_7BIT && mimeinfo->encoding_type != ENC_8BIT) procmime_decode_content(mimeinfo); @@ -982,6 +997,12 @@ void procmime_parse_message_rfc822(MimeInfo *mimeinfo) fp = fopen(mimeinfo->filename, "rb"); fseek(fp, mimeinfo->offset, SEEK_SET); procheader_get_header_fields(fp, hentry); + if (hentry[0].body != NULL) + conv_unmime_header_overwrite(hentry[0].body); + if (hentry[2].body != NULL) + conv_unmime_header_overwrite(hentry[2].body); + if (hentry[4].body != NULL) + conv_unmime_header_overwrite(hentry[4].body); content_start = ftell(fp); fclose(fp); @@ -1066,6 +1087,12 @@ void procmime_parse_multipart(MimeInfo *mimeinfo) hentry[i].body = NULL; } procheader_get_header_fields(fp, hentry); + if (hentry[0].body != NULL) + conv_unmime_header_overwrite(hentry[0].body); + if (hentry[2].body != NULL) + conv_unmime_header_overwrite(hentry[2].body); + if (hentry[4].body != NULL) + conv_unmime_header_overwrite(hentry[4].body); lastoffset = ftell(fp); } } @@ -1083,18 +1110,18 @@ static void add_to_mimeinfo_parameters(gchar **parts, MimeInfo *mimeinfo) for (strarray = parts; *strarray != NULL; strarray++) { gchar **parameters_parts; - parameters_parts = g_strsplit(*strarray, "=", 2); + parameters_parts = g_strsplit(*strarray, "=", 1); if ((parameters_parts[0] != NULL) && (parameters_parts[1] != NULL)) { gchar *firstspace; g_strstrip(parameters_parts[0]); g_strstrip(parameters_parts[1]); g_strdown(parameters_parts[0]); - if(parameters_parts[1][0] == '"') + if (parameters_parts[1][0] == '"') extract_quote(parameters_parts[1], '"'); else if ((firstspace = strchr(parameters_parts[1], ' ')) != NULL) *firstspace = '\0'; - if(g_hash_table_lookup(mimeinfo->parameters, + if (g_hash_table_lookup(mimeinfo->parameters, parameters_parts[0]) == NULL) g_hash_table_insert(mimeinfo->parameters, g_strdup(parameters_parts[0]), @@ -1128,13 +1155,11 @@ static void procmime_parse_content_type(const gchar *content_type, MimeInfo *mim if ((str == NULL) || (str[0] == '\0') || (strchr(str, '/') == NULL)) { mimeinfo->type = MIMETYPE_TEXT; mimeinfo->subtype = g_strdup("plain"); - if(g_hash_table_lookup(mimeinfo->parameters, + if (g_hash_table_lookup(mimeinfo->parameters, "charset") == NULL) g_hash_table_insert(mimeinfo->parameters, g_strdup("charset"), g_strdup("us-ascii")); - g_strfreev(content_type_parts); - return; } else { mimeinfo->type = MIMETYPE_UNKNOWN; for (typetablearray = mime_type_table; typetablearray->str != NULL; typetablearray++) { @@ -1225,7 +1250,7 @@ void procmime_parse_mimepart(MimeInfo *parent, } else { mimeinfo->type = MIMETYPE_TEXT; mimeinfo->subtype = g_strdup("plain"); - if(g_hash_table_lookup(mimeinfo->parameters, + if (g_hash_table_lookup(mimeinfo->parameters, "charset") == NULL) g_hash_table_insert(mimeinfo->parameters, g_strdup("charset"), g_strdup("us-ascii")); } @@ -1285,7 +1310,7 @@ static gboolean output_func(GNode *node, gpointer data) MimeInfo *mimeinfo = (MimeInfo *) node->data; depth = g_node_depth(node); - for(i = 0; i < depth; i++) + for (i = 0; i < depth; i++) printf(" "); printf("%s/%s (offset:%d length:%d encoding: %d)\n", typenames[mimeinfo->type], mimeinfo->subtype, mimeinfo->offset, mimeinfo->length, mimeinfo->encoding_type); @@ -1340,7 +1365,7 @@ MimeInfo *procmime_scan_queue_file(gchar *filename) g_return_val_if_fail(filename != NULL, NULL); /* Open file */ - if((fp = fopen(filename, "rb")) == NULL) + if ((fp = fopen(filename, "rb")) == NULL) return NULL; /* Skip queue header */ while (fgets(buf, sizeof(buf), fp) != NULL) diff --git a/src/quote_fmt.c b/src/quote_fmt.c index 3ac7d9a0f..bc6cbb6ae 100644 --- a/src/quote_fmt.c +++ b/src/quote_fmt.c @@ -54,6 +54,7 @@ static gchar *quote_desc_strings[] = { "%Q", N_("Quoted message body"), /* quoted message */ "%m", N_("Message body without signature"), /* message with no signature */ "%q", N_("Quoted message body without signature"), /* quoted message with no signature */ + "%X", N_("Cursor position"), /* X marks the cursor spot */ "", NULL, "?x{expr}", N_("Insert expr if x is set\nx is one of the characters above after %"), "", NULL, diff --git a/src/quote_fmt.h b/src/quote_fmt.h index f192f3169..4d352bd22 100644 --- a/src/quote_fmt.h +++ b/src/quote_fmt.h @@ -12,4 +12,6 @@ void quote_fmt_init(MsgInfo *info, const gchar *my_quote_str, gint quote_fmtparse(void); void quote_fmt_scan_string(const gchar *str); +gint quote_fmtparse_get_cursor_pos(void); + #endif /* __QUOTE_FMT_H__ */ diff --git a/src/quote_fmt_lex.l b/src/quote_fmt_lex.l index f5ac10c95..5c35a7d7a 100644 --- a/src/quote_fmt_lex.l +++ b/src/quote_fmt_lex.l @@ -49,6 +49,7 @@ static int firsttime = 1; } %} +"%X" /* cursor pos */ return SET_CURSOR_POS; "%c" /* cc */ return SHOW_CC; "%d" /* date */ return SHOW_DATE; "%D" /* date */ { BEGIN S_DATE; return SHOW_DATE_EXPR; } diff --git a/src/quote_fmt_parse.y b/src/quote_fmt_parse.y index 605cbd9a0..722c69e07 100644 --- a/src/quote_fmt_parse.y +++ b/src/quote_fmt_parse.y @@ -52,6 +52,8 @@ static const gchar *quote_str = NULL; static const gchar *body = NULL; static gint error = 0; +static gint cursor_pos = 0; + static void add_visibility(gboolean val) { stacksize++; @@ -94,6 +96,11 @@ gchar *quote_fmt_get_buffer(void) return buffer; } +gint quote_fmt_get_cursor_pos(void) +{ + return cursor_pos; +} + #define INSERT(buf) \ if (stacksize != 0 && visible[stacksize - 1]) \ add_buffer(buf) @@ -118,6 +125,7 @@ void quote_fmt_init(MsgInfo *info, const gchar *my_quote_str, *buffer = 0; bufsize = 0; error = 0; + cursor_pos = 0; } void quote_fmterror(char *str) @@ -156,6 +164,7 @@ static int isseparator(int ch) %token OPARENT CPARENT %token CHARACTER %token SHOW_DATE_EXPR +%token SET_CURSOR_POS %start quote_fmt @@ -507,6 +516,10 @@ special: | SHOW_CPARENT { INSERT("}"); + } + | SET_CURSOR_POS + { + cursor_pos = bufsize; }; query: diff --git a/src/sgpgme.c b/src/sgpgme.c index 1dddabdee..b37dac536 100644 --- a/src/sgpgme.c +++ b/src/sgpgme.c @@ -214,7 +214,7 @@ gchar *sgpgme_sigstat_info_full(GpgmeCtx ctx, GpgmeSigStat status) format = _("Signature expires %s\n"); else format = _("Signature expired %s\n"); - g_string_sprintfa(siginfo, format, time); + g_string_sprintfa(siginfo, format, timestr); } g_string_append(siginfo, "\n"); diff --git a/src/stock_pixmap.c b/src/stock_pixmap.c index 2ba7c2fbb..3905cbf5f 100644 --- a/src/stock_pixmap.c +++ b/src/stock_pixmap.c @@ -52,6 +52,7 @@ #include "pixmaps/key.xpm" #include "pixmaps/ldap.xpm" #include "pixmaps/linewrap.xpm" +#include "pixmaps/linewrapcurrent.xpm" #include "pixmaps/mark.xpm" #include "pixmaps/locked.xpm" #include "pixmaps/new.xpm" @@ -160,6 +161,7 @@ static StockPixmapData pixmaps[] = {jpilot_xpm , NULL, NULL, "jpilot", NULL}, {key_xpm , NULL, NULL, "key", NULL}, {ldap_xpm , NULL, NULL, "ldap", NULL}, + {linewrapcurrent_xpm , NULL, NULL, "linewrapcurrent", NULL}, {linewrap_xpm , NULL, NULL, "linewrap", NULL}, {locked_xpm , NULL, NULL, "locked", NULL}, {mail_xpm , NULL, NULL, "mail", NULL}, @@ -272,7 +274,7 @@ gint stock_pixmap_gdk(GtkWidget *window, StockPixmap icon, } else { /* even the path does not exist (deleted between two sessions), so set the preferences to the internal theme */ - prefs_common.pixmap_theme_path = DEFAULT_PIXMAP_THEME; + prefs_common.pixmap_theme_path = g_strdup(DEFAULT_PIXMAP_THEME); } } pix_d->pixmap = pix; diff --git a/src/stock_pixmap.h b/src/stock_pixmap.h index 15dd17f44..7feafdd27 100644 --- a/src/stock_pixmap.h +++ b/src/stock_pixmap.h @@ -60,7 +60,8 @@ typedef enum STOCK_PIXMAP_JPILOT, STOCK_PIXMAP_KEY, STOCK_PIXMAP_LDAP, - STOCK_PIXMAP_LINEWRAP, + STOCK_PIXMAP_LINEWRAP_CURRENT, + STOCK_PIXMAP_LINEWRAP_ALL, STOCK_PIXMAP_LOCKED, STOCK_PIXMAP_MAIL, STOCK_PIXMAP_MAIL_ATTACH, diff --git a/src/summaryview.c b/src/summaryview.c index 7692dcd9d..18dc25ebb 100644 --- a/src/summaryview.c +++ b/src/summaryview.c @@ -1,8 +1,8 @@ /* * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2003 Hiroyuki Yamamoto + * Copyright (C) 1999-2004 Hiroyuki Yamamoto * - * This program is free software; you can redistributte it and/or modify + * 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. @@ -203,11 +203,6 @@ static void summary_copy_row_to (SummaryView *summaryview, GtkCTreeNode *row, FolderItem *to_folder); -static void summary_delete_duplicated_func - (GtkCTree *ctree, - GtkCTreeNode *node, - SummaryView *summaryview); - static void summary_execute_move (SummaryView *summaryview); static void summary_execute_move_func (GtkCTree *ctree, GtkCTreeNode *node, @@ -663,10 +658,16 @@ SummaryView *summary_create(void) gtk_widget_show(search_type); - search_string = gtk_entry_new(); - + search_string = gtk_combo_new(); gtk_box_pack_start(GTK_BOX(hbox_search), search_string, FALSE, FALSE, 2); - + gtk_combo_set_value_in_list(GTK_COMBO(search_string), FALSE, TRUE); + gtk_combo_set_case_sensitive(GTK_COMBO(search_string), TRUE); + if (prefs_common.summary_quicksearch_history) + gtk_combo_set_popdown_strings(GTK_COMBO(search_string), + prefs_common.summary_quicksearch_history); + gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(search_string)->entry), ""); + gtk_widget_show(search_string); + gtkut_button_set_create(&search_hbbox, &search_description, _("Extended Symbols"), NULL, NULL, NULL, NULL); g_signal_connect(G_OBJECT(search_description), "clicked", @@ -676,15 +677,18 @@ SummaryView *summary_create(void) gtk_widget_show(search_string); gtk_widget_show(hbox_search); - g_signal_connect(G_OBJECT(search_string), "key_press_event", - G_CALLBACK(summary_searchbar_pressed), - summaryview); + g_signal_connect(G_OBJECT(GTK_COMBO(search_string)->entry), + "key_press_event", + G_CALLBACK(summary_searchbar_pressed), + summaryview); - g_signal_connect(G_OBJECT(search_string), "focus_in_event", + g_signal_connect(G_OBJECT(GTK_COMBO(search_string)->entry), + "focus_in_event", G_CALLBACK(summary_searchbar_focus_evt), summaryview); - g_signal_connect(G_OBJECT(search_string), "focus_out_event", + g_signal_connect(G_OBJECT(GTK_COMBO(search_string)->entry), + "focus_out_event", G_CALLBACK(summary_searchbar_focus_evt), summaryview); @@ -728,6 +732,10 @@ SummaryView *summary_create(void) gtk_widget_show_all(vbox); + /* hide widgets that shouldn't be displayed */ + if (prefs_common.summary_quicksearch_type != S_SEARCH_EXTENDED) + gtk_widget_hide(search_description); + return summaryview; } @@ -923,7 +931,7 @@ gboolean summary_show(SummaryView *summaryview, FolderItem *item) if (item != summaryview->folder_item) { /* changing folder, reset search */ - gtk_entry_set_text(GTK_ENTRY(summaryview->search_string), ""); + gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(summaryview->search_string)->entry), ""); } /* STATUSBAR_POP(summaryview->mainwin); */ @@ -1024,12 +1032,12 @@ gboolean summary_show(SummaryView *summaryview, FolderItem *item) summary_set_hide_read_msgs_menu(summaryview, FALSE); } - if (strlen(gtk_entry_get_text(GTK_ENTRY(summaryview->search_string))) > 0) { + if (strlen(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(summaryview->search_string)->entry))) > 0) { GSList *not_killed; - gint search_type = GPOINTER_TO_INT(g_object_get_data( + gint search_type = GPOINTER_TO_INT(gtk_object_get_user_data( GTK_OBJECT(GTK_MENU_ITEM(gtk_menu_get_active( - GTK_MENU(summaryview->search_type)))), MENU_VAL_ID)); - const gchar *search_string = gtk_entry_get_text(GTK_ENTRY(summaryview->search_string)); + GTK_MENU(summaryview->search_type)))))); + const gchar *search_string = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(summaryview->search_string)->entry)); gchar *searched_header = NULL; MatcherList * tmp_list = NULL; @@ -1283,6 +1291,22 @@ SummarySelection summary_get_selection_type(SummaryView *summaryview) return selection; } +/*! + *\return MsgInfo * Selected message if there's one selected; + * if multiple selected, or none, return NULL. + */ +MsgInfo *summary_get_selected_msg(SummaryView *summaryview) +{ + /* summaryview->selected may be valid when multiple + * messages were selected */ + GList *sellist = GTK_CLIST(summaryview->ctree)->selection; + + if (sellist == NULL || sellist->next) + return NULL; + + return GTKUT_CTREE_NODE_GET_ROW_DATA(sellist->data); +} + GSList *summary_get_selected_msg_list(SummaryView *summaryview) { GSList *mlist = NULL; @@ -2407,8 +2431,7 @@ static void summary_set_header(SummaryView *summaryview, gchar *text[], text[col_pos[S_COL_FROM]] = msginfo->fromname ? msginfo->fromname : _("(No From)"); - if (prefs_common.swap_from && msginfo->from && msginfo->to && - !MSG_IS_NEWS(msginfo->flags)) { + if (prefs_common.swap_from && msginfo->from && msginfo->to) { gchar *addr = NULL; Xstrdup_a(addr, msginfo->from, return); @@ -2523,6 +2546,7 @@ static void summary_display_msg_full(SummaryView *summaryview, summary_set_menu_sensitive(summaryview); toolbar_main_set_sensitive(summaryview->mainwin); + messageview_set_menu_sensitive(summaryview->messageview); summary_unlock(summaryview); } @@ -2946,8 +2970,8 @@ void summary_mark_all_read(SummaryView *summaryview) for (node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list); node != NULL; node = gtkut_ctree_node_next(ctree, node)) summary_mark_row_as_read(summaryview, node); - gtk_clist_thaw(clist); folder_item_update_thaw(); + gtk_clist_thaw(clist); summary_status_show(summaryview); } @@ -3150,18 +3174,6 @@ void summary_delete(SummaryView *summaryview) main_window_cursor_normal(summaryview->mainwin); } -void summary_delete_duplicated(SummaryView *summaryview) -{ - main_window_cursor_wait(summaryview->mainwin); - STATUSBAR_PUSH(summaryview->mainwin, - _("Deleting duplicated messages...")); - - folderutils_delete_duplicates(summaryview->folder_item); - - STATUSBAR_POP(summaryview->mainwin); - main_window_cursor_normal(summaryview->mainwin); -} - static void summary_unmark_row(SummaryView *summaryview, GtkCTreeNode *row) { GtkCTree *ctree = GTK_CTREE(summaryview->ctree); @@ -3954,7 +3966,7 @@ void summary_collapse_threads(SummaryView *summaryview) gtk_ctree_node_moveto(ctree, summaryview->selected, -1, 0.5, 0); } -void summary_filter(SummaryView *summaryview) +void summary_filter(SummaryView *summaryview, gboolean selected_only) { if (!filtering_rules) { alertpanel_error(_("No filter rules defined.")); @@ -3986,10 +3998,20 @@ void summary_filter(SummaryView *summaryview) summary_status_show(summaryview); } else { - gtk_ctree_pre_recursive(GTK_CTREE(summaryview->ctree), NULL, - GTK_CTREE_FUNC(summary_filter_func), - summaryview); - + if (selected_only) { + GList *cur; + + for (cur = GTK_CLIST(summaryview->ctree)->selection; + cur != NULL; cur = cur->next) { + summary_filter_func(GTK_CTREE(summaryview->ctree), + GTK_CTREE_NODE(cur->data), + summaryview); + } + } else { + gtk_ctree_pre_recursive(GTK_CTREE(summaryview->ctree), NULL, + GTK_CTREE_FUNC(summary_filter_func), + summaryview); + } gtk_clist_thaw(GTK_CLIST(summaryview->ctree)); } @@ -4557,9 +4579,19 @@ static gboolean summary_key_pressed(GtkWidget *widget, GdkEventKey *event, static gboolean summary_searchbar_pressed(GtkWidget *widget, GdkEventKey *event, SummaryView *summaryview) { - if (event != NULL && event->keyval == GDK_Return) + if (event != NULL && event->keyval == GDK_Return) { + gchar *search_string = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(summaryview->search_string)->entry)); + if (search_string && strlen(search_string) != 0) { + prefs_common.summary_quicksearch_history = + add_history(prefs_common.summary_quicksearch_history, + search_string); + gtk_combo_set_popdown_strings(GTK_COMBO(summaryview->search_string), + prefs_common.summary_quicksearch_history); + } summary_show(summaryview, summaryview->folder_item); - return FALSE; + gtk_signal_emit_stop_by_name(GTK_OBJECT(widget), "key_press_event"); + } + return TRUE; } static gboolean summary_searchbar_focus_evt(GtkWidget *widget, GdkEventFocus *event, @@ -4591,7 +4623,7 @@ static void summary_searchtype_changed(GtkMenuItem *widget, gpointer data) gtk_widget_hide(sw->search_description); } - if (gtk_entry_get_text(GTK_ENTRY(sw->search_string))) + if (gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(sw->search_string)->entry))) summary_show(sw, sw->folder_item); } @@ -5442,7 +5474,7 @@ static void summary_find_answers (SummaryView *summaryview, MsgInfo *msg) S_SEARCH_EXTENDED); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(summaryview->toggle_search), TRUE); - gtk_entry_set_text(GTK_ENTRY(summaryview->search_string), buf); + gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(summaryview->search_string)->entry), buf); g_free(buf); summary_show(summaryview, summaryview->folder_item); node = gtk_ctree_node_nth(GTK_CTREE(summaryview->ctree), 0); diff --git a/src/summaryview.h b/src/summaryview.h index b84b071c7..e2834980d 100644 --- a/src/summaryview.h +++ b/src/summaryview.h @@ -1,6 +1,6 @@ /* * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2003 Hiroyuki Yamamoto + * Copyright (C) 1999-2004 Hiroyuki Yamamoto * * 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 @@ -179,6 +179,7 @@ void summary_unlock (SummaryView *summaryview); gboolean summary_is_locked (SummaryView *summaryview); SummarySelection summary_get_selection_type (SummaryView *summaryview); +MsgInfo *summary_get_selected_msg (SummaryView *summaryview); GSList *summary_get_selected_msg_list (SummaryView *summaryview); void summary_select_prev_unread (SummaryView *summaryview); @@ -204,7 +205,8 @@ void summary_expand_threads (SummaryView *summaryview); void summary_collapse_threads (SummaryView *summaryview); void summary_toggle_ignore_thread (SummaryView *summaryview); -void summary_filter (SummaryView *summaryview); +void summary_filter (SummaryView *summaryview, + gboolean selected_only); void summary_filter_open (SummaryView *summaryview, PrefsFilterType type, gint processing_rule); @@ -216,7 +218,6 @@ void summary_sort (SummaryView *summaryview, FolderSortType sort_type); void summary_delete (SummaryView *summaryview); -void summary_delete_duplicated (SummaryView *summaryview); void summary_cancel (SummaryView *summaryview); diff --git a/src/textview.c b/src/textview.c index 433392661..d78235420 100644 --- a/src/textview.c +++ b/src/textview.c @@ -119,6 +119,18 @@ static GdkColor bad_sig_color = { (gushort)0 }; +#define TEXTVIEW_STATUSBAR_PUSH(textview, str) \ +{ \ + gtk_statusbar_push(GTK_STATUSBAR(textview->messageview->statusbar), \ + textview->messageview->statusbar_cid, str); \ +} + +#define TEXTVIEW_STATUSBAR_POP(textview) \ +{ \ + gtk_statusbar_pop(GTK_STATUSBAR(textview->messageview->statusbar), \ + textview->messageview->statusbar_cid); \ +} + static void textview_show_ertf (TextView *textview, FILE *fp, CodeConverter *conv); @@ -1008,6 +1020,19 @@ static gchar *make_email_string(const gchar *bp, const gchar *ep) return result; } +static gchar *make_http_string(const gchar *bp, const gchar *ep) +{ + /* returns an http: URI; */ + gchar *tmp; + gchar *result; + + tmp = g_strndup(bp, ep - bp); + result = g_strconcat("http://", tmp, NULL); + g_free(tmp); + + return result; +} + #define ADD_TXT_POS(bp_, ep_, pti_) \ if ((last->next = alloca(sizeof(struct txtpos))) != NULL) { \ last = last->next; \ @@ -1052,7 +1077,7 @@ static void textview_make_clickable_parts(TextView *textview, {"http://", strcasestr, get_uri_part, make_uri_string}, {"https://", strcasestr, get_uri_part, make_uri_string}, {"ftp://", strcasestr, get_uri_part, make_uri_string}, - {"www.", strcasestr, get_uri_part, make_uri_string}, + {"www.", strcasestr, get_uri_part, make_http_string}, {"mailto:", strcasestr, get_uri_part, make_uri_string}, {"@", strcasestr, get_email_part, make_email_string} }; @@ -1278,6 +1303,7 @@ void textview_clear(TextView *textview) buffer = gtk_text_view_get_buffer(text); gtk_text_buffer_set_text(buffer, "\0", -1); + TEXTVIEW_STATUSBAR_POP(textview); textview_uri_list_remove_all(textview->uri_list); textview->uri_list = NULL; @@ -1885,13 +1911,8 @@ static gint show_url_timeout_cb(gpointer data) { TextView *textview = (TextView *)data; - if (textview->messageview->mainwin) - if (textview->show_url_msgid) - gtk_statusbar_remove(GTK_STATUSBAR( - textview->messageview->mainwin->statusbar), - textview->messageview->mainwin->folderview_cid, - textview->show_url_msgid); - return FALSE; + TEXTVIEW_STATUSBAR_POP(textview); + return FALSE; } /*! @@ -2001,20 +2022,9 @@ static gboolean textview_uri_button_pressed(GtkTextTag *tag, GObject *obj, if (event->type == GDK_MOTION_NOTIFY || (event->type == GDK_BUTTON_PRESS && bevent->button == 1)) { if (textview->messageview->mainwin) { - if (textview->show_url_msgid) { - gtk_timeout_remove(textview->show_url_timeout_tag); - gtk_statusbar_remove(GTK_STATUSBAR( - textview->messageview->mainwin->statusbar), - textview->messageview->mainwin->folderview_cid, - textview->show_url_msgid); - textview->show_url_msgid = 0; - } - textview->show_url_msgid = gtk_statusbar_push( - GTK_STATUSBAR(textview->messageview->mainwin->statusbar), - textview->messageview->mainwin->folderview_cid, - trimmed_uri); - textview->show_url_timeout_tag = gtk_timeout_add( 4000, show_url_timeout_cb, textview ); - gtkut_widget_wait_for_draw(textview->messageview->mainwin->hbox_stat); + TEXTVIEW_STATUSBAR_PUSH(textview, trimmed_uri); + textview->show_url_timeout_tag = gtk_timeout_add + (4000, show_url_timeout_cb, textview); } return TRUE; } diff --git a/src/toolbar.c b/src/toolbar.c index cbf66bc24..ed4dbd9d2 100644 --- a/src/toolbar.c +++ b/src/toolbar.c @@ -139,7 +139,9 @@ static void toolbar_sig_cb (GtkWidget *widget, gpointer data); static void toolbar_ext_editor_cb (GtkWidget *widget, gpointer data); -static void toolbar_linewrap_cb (GtkWidget *widget, +static void toolbar_linewrap_current_cb (GtkWidget *widget, + gpointer data); +static void toolbar_linewrap_all_cb (GtkWidget *widget, gpointer data); static void toolbar_addrbook_cb (GtkWidget *widget, gpointer data); @@ -154,36 +156,37 @@ struct { gchar *index_str; const gchar *descr; } toolbar_text [] = { - { "A_RECEIVE_ALL", N_("Receive Mail on all Accounts") }, - { "A_RECEIVE_CUR", N_("Receive Mail on current Account") }, - { "A_SEND_QUEUED", N_("Send Queued Message(s)") }, - { "A_COMPOSE_EMAIL", N_("Compose Email") }, - { "A_COMPOSE_NEWS", N_("Compose News") }, - { "A_REPLY_MESSAGE", N_("Reply to Message") }, - { "A_REPLY_SENDER", N_("Reply to Sender") }, - { "A_REPLY_ALL", N_("Reply to All") }, - { "A_REPLY_ML", N_("Reply to Mailing-list") }, - { "A_FORWARD", N_("Forward Message") }, - { "A_DELETE", N_("Delete Message") }, - { "A_EXECUTE", N_("Execute") }, - { "A_GOTO_NEXT", N_("Goto Next Message") }, - { "A_IGNORE_THREAD", N_("Ignore thread") }, - { "A_PRINT", N_("Print") }, - - { "A_SEND", N_("Send Message") }, - { "A_SENDL", N_("Put into queue folder and send later") }, - { "A_DRAFT", N_("Save to draft folder") }, - { "A_INSERT", N_("Insert file") }, - { "A_ATTACH", N_("Attach file") }, - { "A_SIG", N_("Insert signature") }, - { "A_EXTEDITOR", N_("Edit with external editor") }, - { "A_LINEWRAP", N_("Wrap all long lines") }, - { "A_ADDRBOOK", N_("Address book") }, + { "A_RECEIVE_ALL", N_("Receive Mail on all Accounts") }, + { "A_RECEIVE_CUR", N_("Receive Mail on current Account") }, + { "A_SEND_QUEUED", N_("Send Queued Message(s)") }, + { "A_COMPOSE_EMAIL", N_("Compose Email") }, + { "A_COMPOSE_NEWS", N_("Compose News") }, + { "A_REPLY_MESSAGE", N_("Reply to Message") }, + { "A_REPLY_SENDER", N_("Reply to Sender") }, + { "A_REPLY_ALL", N_("Reply to All") }, + { "A_REPLY_ML", N_("Reply to Mailing-list") }, + { "A_FORWARD", N_("Forward Message") }, + { "A_DELETE", N_("Delete Message") }, + { "A_EXECUTE", N_("Execute") }, + { "A_GOTO_NEXT", N_("Goto Next Message") }, + { "A_IGNORE_THREAD", N_("Ignore thread") }, + { "A_PRINT", N_("Print") }, + + { "A_SEND", N_("Send Message") }, + { "A_SENDL", N_("Put into queue folder and send later") }, + { "A_DRAFT", N_("Save to draft folder") }, + { "A_INSERT", N_("Insert file") }, + { "A_ATTACH", N_("Attach file") }, + { "A_SIG", N_("Insert signature") }, + { "A_EXTEDITOR", N_("Edit with external editor") }, + { "A_LINEWRAP_CURRENT", N_("Wrap long lines of current paragraph") }, + { "A_LINEWRAP_ALL", N_("Wrap all long lines") }, + { "A_ADDRBOOK", N_("Address book") }, #ifdef USE_ASPELL - { "A_CHECK_SPELLING",N_("Check spelling") }, + { "A_CHECK_SPELLING", N_("Check spelling") }, #endif - { "A_SYL_ACTIONS", N_("Sylpheed Actions Feature") }, - { "A_SEPARATOR", "Separator" } + { "A_SYL_ACTIONS", N_("Sylpheed Actions Feature") }, + { "A_SEPARATOR", "Separator" } }; /* struct holds configuration files and a list of @@ -311,7 +314,8 @@ GList *toolbar_get_action_items(ToolbarType source) else if (source == TOOLBAR_COMPOSE) { gint comp_items[] = { A_SEND, A_SENDL, A_DRAFT, A_INSERT, A_ATTACH, A_SIG, - A_EXTEDITOR, A_LINEWRAP, A_ADDRBOOK, + A_EXTEDITOR, A_LINEWRAP_CURRENT, + A_LINEWRAP_ALL, A_ADDRBOOK, #ifdef USE_ASPELL A_CHECK_SPELLING, #endif @@ -419,18 +423,19 @@ static void toolbar_set_default_compose(void) gint icon; gchar *text; } default_toolbar[] = { - { A_SEND, STOCK_PIXMAP_MAIL_SEND, _("Send") }, - { A_SENDL, STOCK_PIXMAP_MAIL_SEND_QUEUE, _("Send later") }, - { A_DRAFT, STOCK_PIXMAP_MAIL, _("Draft") }, - { A_SEPARATOR, 0, ("") }, - { A_INSERT, STOCK_PIXMAP_INSERT_FILE, _("Insert") }, - { A_ATTACH, STOCK_PIXMAP_MAIL_ATTACH, _("Attach") }, - { A_SIG, STOCK_PIXMAP_MAIL_SIGN, _("Signature") }, - { A_SEPARATOR, 0, ("") }, - { A_EXTEDITOR, STOCK_PIXMAP_EDIT_EXTERN, _("Editor") }, - { A_LINEWRAP, STOCK_PIXMAP_LINEWRAP, _("Linewrap") }, - { A_SEPARATOR, 0, ("") }, - { A_ADDRBOOK, STOCK_PIXMAP_ADDRESS_BOOK, _("Address") } + { A_SEND, STOCK_PIXMAP_MAIL_SEND, _("Send") }, + { A_SENDL, STOCK_PIXMAP_MAIL_SEND_QUEUE, _("Send later") }, + { A_DRAFT, STOCK_PIXMAP_MAIL, _("Draft") }, + { A_SEPARATOR, 0, ("") }, + { A_INSERT, STOCK_PIXMAP_INSERT_FILE, _("Insert") }, + { A_ATTACH, STOCK_PIXMAP_MAIL_ATTACH, _("Attach") }, + { A_SIG, STOCK_PIXMAP_MAIL_SIGN, _("Signature") }, + { A_SEPARATOR, 0, ("") }, + { A_EXTEDITOR, STOCK_PIXMAP_EDIT_EXTERN, _("Editor") }, + { A_LINEWRAP_CURRENT, STOCK_PIXMAP_LINEWRAP_CURRENT, _("Wrap paragraph") }, + { A_LINEWRAP_ALL, STOCK_PIXMAP_LINEWRAP_ALL, _("Wrap all") }, + { A_SEPARATOR, 0, ("") }, + { A_ADDRBOOK, STOCK_PIXMAP_ADDRESS_BOOK, _("Address") } }; gint i; @@ -889,17 +894,16 @@ static void toolbar_delete_cb(GtkWidget *widget, gpointer data) { ToolbarItem *toolbar_item = (ToolbarItem*)data; MainWindow *mainwin; - MessageView *msgview; g_return_if_fail(toolbar_item != NULL); + g_return_if_fail(toolbar_item->parent); switch (toolbar_item->type) { case TOOLBAR_MSGVIEW: - msgview = (MessageView*)toolbar_item->parent; - messageview_delete(msgview); + messageview_delete((MessageView *)toolbar_item->parent); break; case TOOLBAR_MAIN: - mainwin = (MainWindow*)toolbar_item->parent; + mainwin = (MainWindow *)toolbar_item->parent; summary_delete(mainwin->summaryview); break; default: @@ -1138,9 +1142,14 @@ static void toolbar_ext_editor_cb(GtkWidget *widget, gpointer data) compose_toolbar_cb(A_EXTEDITOR, data); } -static void toolbar_linewrap_cb(GtkWidget *widget, gpointer data) +static void toolbar_linewrap_current_cb(GtkWidget *widget, gpointer data) { - compose_toolbar_cb(A_LINEWRAP, data); + compose_toolbar_cb(A_LINEWRAP_CURRENT, data); +} + +static void toolbar_linewrap_all_cb(GtkWidget *widget, gpointer data) +{ + compose_toolbar_cb(A_LINEWRAP_ALL, data); } #ifdef USE_ASPELL @@ -1258,7 +1267,8 @@ static void toolbar_buttons_cb(GtkWidget *widget, { A_ATTACH, toolbar_attach_cb }, { A_SIG, toolbar_sig_cb }, { A_EXTEDITOR, toolbar_ext_editor_cb }, - { A_LINEWRAP, toolbar_linewrap_cb }, + { A_LINEWRAP_CURRENT, toolbar_linewrap_current_cb }, + { A_LINEWRAP_ALL, toolbar_linewrap_all_cb }, { A_ADDRBOOK, toolbar_addrbook_cb }, #ifdef USE_ASPELL { A_CHECK_SPELLING, toolbar_check_spelling_cb }, @@ -1532,10 +1542,16 @@ Toolbar *toolbar_create(ToolbarType type, toolbar_data->exteditor_btn, _("Edit with external editor"), NULL); break; - case A_LINEWRAP: - toolbar_data->linewrap_btn = item; + case A_LINEWRAP_CURRENT: + toolbar_data->linewrap_current_btn = item; + gtk_tooltips_set_tip(GTK_TOOLTIPS(toolbar_tips), + toolbar_data->linewrap_current_btn, + _("Wrap long lines of current paragraph"), NULL); + break; + case A_LINEWRAP_ALL: + toolbar_data->linewrap_all_btn = item; gtk_tooltips_set_tip(GTK_TOOLTIPS(toolbar_tips), - toolbar_data->linewrap_btn, + toolbar_data->linewrap_all_btn, _("Wrap all long lines"), NULL); break; case A_ADDRBOOK: @@ -1757,8 +1773,10 @@ void toolbar_comp_set_sensitive(gpointer data, gboolean sensitive) gtk_widget_set_sensitive(compose->toolbar->sig_btn, sensitive); if (compose->toolbar->exteditor_btn) gtk_widget_set_sensitive(compose->toolbar->exteditor_btn, sensitive); - if (compose->toolbar->linewrap_btn) - gtk_widget_set_sensitive(compose->toolbar->linewrap_btn, sensitive); + if (compose->toolbar->linewrap_current_btn) + gtk_widget_set_sensitive(compose->toolbar->linewrap_current_btn, sensitive); + if (compose->toolbar->linewrap_all_btn) + gtk_widget_set_sensitive(compose->toolbar->linewrap_all_btn, sensitive); if (compose->toolbar->addrbook_btn) gtk_widget_set_sensitive(compose->toolbar->addrbook_btn, sensitive); #ifdef USE_ASPELL @@ -1776,32 +1794,33 @@ void toolbar_comp_set_sensitive(gpointer data, gboolean sensitive) **/ void toolbar_init(Toolbar * toolbar) { - toolbar->toolbar = NULL; - toolbar->get_btn = NULL; - toolbar->getall_btn = NULL; - toolbar->send_btn = NULL; - toolbar->compose_mail_btn = NULL; - toolbar->compose_news_btn = NULL; - toolbar->reply_btn = NULL; - toolbar->replysender_btn = NULL; - toolbar->replyall_btn = NULL; - toolbar->replylist_btn = NULL; - toolbar->fwd_btn = NULL; - toolbar->delete_btn = NULL; - toolbar->next_btn = NULL; - toolbar->exec_btn = NULL; + toolbar->toolbar = NULL; + toolbar->get_btn = NULL; + toolbar->getall_btn = NULL; + toolbar->send_btn = NULL; + toolbar->compose_mail_btn = NULL; + toolbar->compose_news_btn = NULL; + toolbar->reply_btn = NULL; + toolbar->replysender_btn = NULL; + toolbar->replyall_btn = NULL; + toolbar->replylist_btn = NULL; + toolbar->fwd_btn = NULL; + toolbar->delete_btn = NULL; + toolbar->next_btn = NULL; + toolbar->exec_btn = NULL; /* compose buttons */ - toolbar->sendl_btn = NULL; - toolbar->draft_btn = NULL; - toolbar->insert_btn = NULL; - toolbar->attach_btn = NULL; - toolbar->sig_btn = NULL; - toolbar->exteditor_btn = NULL; - toolbar->linewrap_btn = NULL; - toolbar->addrbook_btn = NULL; + toolbar->sendl_btn = NULL; + toolbar->draft_btn = NULL; + toolbar->insert_btn = NULL; + toolbar->attach_btn = NULL; + toolbar->sig_btn = NULL; + toolbar->exteditor_btn = NULL; + toolbar->linewrap_current_btn = NULL; + toolbar->linewrap_all_btn = NULL; + toolbar->addrbook_btn = NULL; #ifdef USE_ASPELL - toolbar->spellcheck_btn = NULL; + toolbar->spellcheck_btn = NULL; #endif toolbar_destroy(toolbar); diff --git a/src/toolbar.h b/src/toolbar.h index aa9b28ef0..6e491d3d2 100644 --- a/src/toolbar.h +++ b/src/toolbar.h @@ -78,7 +78,8 @@ struct _Toolbar { GtkWidget *attach_btn; GtkWidget *sig_btn; GtkWidget *exteditor_btn; - GtkWidget *linewrap_btn; + GtkWidget *linewrap_current_btn; + GtkWidget *linewrap_all_btn; GtkWidget *addrbook_btn; #ifdef USE_ASPELL GtkWidget *spellcheck_btn; @@ -158,7 +159,8 @@ enum { A_ATTACH, A_SIG, A_EXTEDITOR, - A_LINEWRAP, + A_LINEWRAP_CURRENT, + A_LINEWRAP_ALL, A_ADDRBOOK, #ifdef USE_ASPELL A_CHECK_SPELLING,