diff options
-rw-r--r-- | VERSION | 2 | ||||
-rw-r--r-- | alpine/osdep/mswin.rc | 8 | ||||
-rw-r--r-- | alpine/osdep/mswinver.c | 5 | ||||
-rwxr-xr-x | configure | 20 | ||||
-rw-r--r-- | doc/alpine.1 | 2 | ||||
-rw-r--r-- | doc/tech-notes/index.html | 2 | ||||
-rw-r--r-- | include/config.wnt.h | 6 | ||||
-rw-r--r-- | mapi/pmapi.c | 2 | ||||
-rw-r--r-- | mapi/pmapi.rc | 8 | ||||
-rw-r--r-- | pico/osdep/mswin_spell.c | 1094 | ||||
-rw-r--r-- | pith/pine.hlp | 28 | ||||
-rw-r--r-- | po/Makefile.in | 2 |
12 files changed, 589 insertions, 590 deletions
@@ -1 +1 @@ -2.19.8 +2.19.9 diff --git a/alpine/osdep/mswin.rc b/alpine/osdep/mswin.rc index 61cd7d7c..37835b9c 100644 --- a/alpine/osdep/mswin.rc +++ b/alpine/osdep/mswin.rc @@ -244,8 +244,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,01,0,0 - PRODUCTVERSION 2,01,0,0 + FILEVERSION 2,19,9,0 + PRODUCTVERSION 2,19,9,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -267,12 +267,12 @@ BEGIN #else VALUE "FileDescription", "Alpine\0" #endif - VALUE "FileVersion", "2.19.8\0" + VALUE "FileVersion", "2.19.9\0" VALUE "InternalName", "alpine\0" VALUE "LegalCopyright", "Copyright 2006-2009\0" VALUE "OriginalFilename", "alpine.exe\0" VALUE "ProductName", "alpine\0" - VALUE "ProductVersion", "2.19.8\0" + VALUE "ProductVersion", "2.19.9\0" END END BLOCK "VarFileInfo" diff --git a/alpine/osdep/mswinver.c b/alpine/osdep/mswinver.c index e968022b..8723ee1a 100644 --- a/alpine/osdep/mswinver.c +++ b/alpine/osdep/mswinver.c @@ -13,7 +13,8 @@ */ #define VER_MAJOR 2 -#define VER_MINOR 1 +#define VER_MINOR 19 + extern char datestamp[]; @@ -33,7 +34,7 @@ mswin_majorver() int mswin_minorver() { - return(VER_MINOR); + return(VER_MINOR 19); } @@ -1,7 +1,7 @@ #! /bin/sh # From configure.ac Rev:9 by chappa@washington.edu. # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for alpine 2.19.8. +# Generated by GNU Autoconf 2.69 for alpine 2.19.9. # # Report bugs to <chappa@washington.edu>. # @@ -730,8 +730,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='alpine' PACKAGE_TARNAME='alpine' -PACKAGE_VERSION='2.19.8' -PACKAGE_STRING='alpine 2.19.8' +PACKAGE_VERSION='2.19.9' +PACKAGE_STRING='alpine 2.19.9' PACKAGE_BUGREPORT='chappa@washington.edu' PACKAGE_URL='' @@ -1596,7 +1596,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures alpine 2.19.8 to adapt to many kinds of systems. +\`configure' configures alpine 2.19.9 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1666,7 +1666,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of alpine 2.19.8:";; + short | recursive ) echo "Configuration of alpine 2.19.9:";; esac cat <<\_ACEOF @@ -1952,7 +1952,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -alpine configure 2.19.8 +alpine configure 2.19.9 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2558,7 +2558,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by alpine $as_me 2.19.8, which was +It was created by alpine $as_me 2.19.9, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -3379,7 +3379,7 @@ fi # Define the identity of the package. PACKAGE='alpine' - VERSION='2.19.8' + VERSION='2.19.9' cat >>confdefs.h <<_ACEOF @@ -20335,7 +20335,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by alpine $as_me 2.19.8, which was +This file was extended by alpine $as_me 2.19.9, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -20401,7 +20401,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -alpine config.status 2.19.8 +alpine config.status 2.19.9 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/doc/alpine.1 b/doc/alpine.1 index 1816fc68..ef750f83 100644 --- a/doc/alpine.1 +++ b/doc/alpine.1 @@ -1,4 +1,4 @@ -.TH alpine 1 "Version 2.19.8" +.TH alpine 1 "Version 2.19.9" .SH NAME alpine \- an Alternatively Licensed Program for Internet News and Email .SH SYNTAX diff --git a/doc/tech-notes/index.html b/doc/tech-notes/index.html index f99eeaeb..60a59bba 100644 --- a/doc/tech-notes/index.html +++ b/doc/tech-notes/index.html @@ -3,7 +3,7 @@ <BODY> <H1>Alpine Technical Notes</H1> -Version 2.19.8, March 2014 +Version 2.19.9, March 2014 <H2><A NAME="TOC">Table of Contents</A></H2><P> diff --git a/include/config.wnt.h b/include/config.wnt.h index 644ce1eb..a6634dd8 100644 --- a/include/config.wnt.h +++ b/include/config.wnt.h @@ -454,13 +454,13 @@ #define PACKAGE_NAME "alpine" /* Define to the full name and version of this package. */ -#define PACKAGE_STRING "alpine 2.19.8" +#define PACKAGE_STRING "alpine 2.19.9" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "alpine" /* Define to the version of this package. */ -#define PACKAGE_VERSION "2.19.8" +#define PACKAGE_VERSION "2.19.9" /* Program users use to change their password */ /* #undef PASSWD_PROG */ @@ -552,7 +552,7 @@ #define UTF8_INTERNAL /* Version number of package */ -#define VERSION "2.19.8" +#define VERSION "2.19.9" /* Windows is just too different */ #ifndef _WINDOWS diff --git a/mapi/pmapi.c b/mapi/pmapi.c index 290492b9..57be211f 100644 --- a/mapi/pmapi.c +++ b/mapi/pmapi.c @@ -1952,7 +1952,7 @@ BOOL APIENTRY DllMain( now = time((time_t *)0); tm_now = localtime(&now); - fprintf(ms_global->dfd, "pmapi32.dll for Alpine Version 2.19.3\r\n"); + fprintf(ms_global->dfd, "pmapi32.dll for Alpine Version 2.19.9\r\n"); fprintf(ms_global->dfd, " Build date: %s\r\n", datestamp); fprintf(ms_global->dfd, " please report all bugs to chappa@gmx.com\r\n"); diff --git a/mapi/pmapi.rc b/mapi/pmapi.rc index 653329f3..7fa070f0 100644 --- a/mapi/pmapi.rc +++ b/mapi/pmapi.rc @@ -98,8 +98,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,01,0,0 - PRODUCTVERSION 2,01,0,0 + FILEVERSION 2,19,9,0 + PRODUCTVERSION 2,19,9,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x29L @@ -117,14 +117,14 @@ BEGIN VALUE "Comments", "alpine info: http://www.washington.edu/alpine\0" VALUE "CompanyName", "University of Washington\0" VALUE "FileDescription", "Simple MAPI DLL for Alpine for Windows\0" - VALUE "FileVersion", "2.19.8\0" + VALUE "FileVersion", "2.19.9\0" VALUE "InternalName", "pmapi32\0" VALUE "LegalCopyright", "Copyright ? 2006-2009\0" VALUE "LegalTrademarks", "Apache License, Version 2.0\0" VALUE "OriginalFilename", "pmapi32.dll\0" VALUE "PrivateBuild", " \0" VALUE "ProductName", "Simple MAPI for Alpine for Windows\0" - VALUE "ProductVersion", "2.19.8\0" + VALUE "ProductVersion", "2.19.9\0" VALUE "SpecialBuild", " \0" END END diff --git a/pico/osdep/mswin_spell.c b/pico/osdep/mswin_spell.c index 1379beb6..e921cfcd 100644 --- a/pico/osdep/mswin_spell.c +++ b/pico/osdep/mswin_spell.c @@ -1,547 +1,547 @@ -/*
- * ========================================================================
- * MSWIN_SPELL.C
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * ========================================================================
- */
-
-#include "../headers.h"
-
-#include "mswin_aspell.h"
-#include "mswin_spell.h"
-
-#include <windowsx.h>
-
-typedef struct WORD_INFO
-{
- ASPELLINFO *aspellinfo; // Aspell information
-
- const char *utf8_err_message; // Error message, if any
-
- char *word_utf8; // utf-8
- LPTSTR word_lptstr;
-
- int word_doto; // UCS
- LINE *word_dotp; //
- int word_size; //
-} WORD_INFO;
-
-extern HINSTANCE ghInstance;
-extern HWND ghTTYWnd;
-
-/*
- * Function prototypes
- */
-static int get_next_bad_word(WORD_INFO *word_info);
-static void free_word_info_words(WORD_INFO *word_info);
-static INT_PTR CALLBACK spell_dlg_proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
-
-/*
- * spell() - check for potentially missspelled words and offer them for
- * correction. Microsoft Windows specific version.
- */
-int
-spell(int f, int n)
-{
- int w_marko_bak;
- LINE *w_markp_bak;
- WORD_INFO word_info;
- ASPELLINFO *aspellinfo;
-
- emlwrite(_("Checking spelling..."), NULL); /* greetings! */
-
- memset(&word_info, 0, sizeof(WORD_INFO));
-
- aspellinfo = speller_init(NULL);
- if(!aspellinfo ||
- (word_info.utf8_err_message = speller_get_error_message(aspellinfo)))
- {
- if(word_info.utf8_err_message)
- emlwrite((char *)word_info.utf8_err_message, NULL); /* sad greetings! */
- else
- emlwrite(_("Spelling: initializing Aspell failed"), NULL);
-
- speller_close(aspellinfo);
- return -1;
- }
-
- // Back up current mark.
- w_marko_bak = curwp->w_marko;
- w_markp_bak = curwp->w_markp;
-
- setimark(0, 1);
- gotobob(0, 1);
-
- word_info.aspellinfo = aspellinfo;
-
- if(get_next_bad_word(&word_info))
- {
- DialogBoxParam(ghInstance, MAKEINTRESOURCE(DLG_SPELL), ghTTYWnd,
- spell_dlg_proc, (LPARAM)&word_info);
- }
-
- // Restore original mark if possible.
- if(curwp->w_markp)
- {
- // Clear any set marks.
- setmark(0, 1);
-
- if(w_markp_bak && llength(w_markp_bak))
- {
- // Make sure we don't set mark off the line.
- if(w_marko_bak >= llength(w_markp_bak))
- w_marko_bak = llength(w_markp_bak) - 1;
-
- curwp->w_marko = w_marko_bak;
- curwp->w_markp = w_markp_bak;
- }
- }
-
- if(word_info.utf8_err_message)
- emlwrite((char *)word_info.utf8_err_message, NULL);
- else
- emlwrite(_("Done checking spelling"), NULL);
-
- speller_close(aspellinfo);
- free_word_info_words(&word_info);
-
- swapimark(0, 1);
- curwp->w_flag |= WFHARD|WFMODE;
-
- update();
- return 1;
-}
-
-/*
- * handle_cb_editchange() - combobox contents have changed so enable/disable
- * the Change and Change All buttons accordingly.
- */
-static void
-handle_cb_editchange(HWND hDlg, HWND hwnd_combo)
-{
- int text_len = ComboBox_GetTextLength(hwnd_combo);
-
- Button_Enable(GetDlgItem(hDlg, ID_BUTTON_CHANGE), !!text_len);
- Button_Enable(GetDlgItem(hDlg, ID_BUTTON_CHANGEALL), !!text_len);
-}
-
-/*
- * spell_dlg_proc_set_word() - Set up the dialog to display spelling
- * information and suggestions for the current word.
- */
-static void
-spell_dlg_proc_set_word(HWND hDlg, WORD_INFO *word_info)
-{
- TCHAR dlg_title[256];
- HWND hwnd_combo = GetDlgItem(hDlg, ID_COMBO_SUGGESTIONS);
-
- // Clear the combobox.
- ComboBox_ResetContent(hwnd_combo);
-
- // Set the dialog box title
- _sntprintf(dlg_title, ARRAYSIZE(dlg_title), TEXT("Not in Dictionary: %s"),
- word_info->word_lptstr);
- dlg_title[ARRAYSIZE(dlg_title) - 1] = 0;
- SetWindowText(hDlg, dlg_title);
-
- // Populate the combobox with suggestions
- if(speller_suggestion_init(word_info->aspellinfo, word_info->word_utf8, -1))
- {
- const char *suggestion_utf8;
-
- while(suggestion_utf8 = speller_suggestion_getnext(word_info->aspellinfo))
- {
- LPTSTR suggestion_lptstr = utf8_to_lptstr((LPSTR)suggestion_utf8);
-
- if(suggestion_lptstr)
- {
- ComboBox_AddString(hwnd_combo, suggestion_lptstr);
- fs_give((void **)&suggestion_lptstr);
- }
- }
-
- // Select the first one.
- ComboBox_SetCurSel(hwnd_combo, 0);
-
- speller_suggestion_close(word_info->aspellinfo);
- }
-
- handle_cb_editchange(hDlg, hwnd_combo);
-}
-
-/*
- * spell_dlg_next_word() - Move to the next misspelled word and display
- * the information for it. If no more bad words, kill the dialog.
- */
-static void
-spell_dlg_next_word(HWND hDlg, WORD_INFO *word_info)
-{
- if(!get_next_bad_word(word_info))
- {
- EndDialog(hDlg, 0);
- return;
- }
-
- spell_dlg_proc_set_word(hDlg, word_info);
-}
-
-/*
- * chword_n() - change the given word_len pointed to by the curwp->w_dot
- * pointers to the word in cb
- */
-static void
-chword_n(int wb_len, UCS *cb)
-{
- ldelete(wb_len, NULL); /* not saved in kill buffer */
-
- while(*cb != '\0')
- linsert(1, *cb++);
-
- curwp->w_flag |= WFEDIT;
-}
-
-/*
- * replace_all() - replace all instances of oldword with newword from
- * the current '.' on. Mark is where curwp will get restored to.
- */
-static void
-replace_all(UCS *oldword, int oldword_len, UCS *newword)
-{
- int wrap;
-
- // Mark should be at "." right now - ie the start of the word we're
- // checking. We're going to use mark below to restore curwp since
- // chword_n can potentially realloc LINES and it knows about markp.
- assert(curwp->w_markp);
- assert(curwp->w_markp == curwp->w_dotp);
- assert(curwp->w_marko == curwp->w_doto);
-
- curwp->w_bufp->b_mode |= MDEXACT; /* case sensitive */
- while(forscan(&wrap, oldword, NULL, 0, 1))
- {
- if(wrap)
- break; /* wrap NOT allowed! */
-
- /*
- * We want to minimize the number of substrings that we report
- * as matching a misspelled word...
- */
- if(lgetc(curwp->w_dotp, 0).c != '>')
- {
- LINE *lp = curwp->w_dotp; /* for convenience */
- int off = curwp->w_doto;
-
- if(off == 0 || !ucs4_isalpha(lgetc(lp, off - 1).c))
- {
- off += oldword_len;
-
- if(off == llength(lp) || !ucs4_isalpha(lgetc(lp, off).c))
- {
- // Replace this word
- chword_n(oldword_len, newword);
- }
- }
- }
-
- forwchar(0, 1); /* move on... */
-
- }
- curwp->w_bufp->b_mode ^= MDEXACT; /* case insensitive */
-
- curwp->w_dotp = curwp->w_markp;
- curwp->w_doto = curwp->w_marko;
-}
-
-/*
- * handle_button_change() - Someone pressed the Change or Change All button.
- * So deal with it.
- */
-static void
-handle_button_change(HWND hDlg, WORD_INFO *word_info, int do_replace_all)
-{
- int str_lptstr_len;
- TCHAR str_lptstr[128];
-
- // Get the length of what they want to change to.
- str_lptstr_len = ComboBox_GetText(GetDlgItem(hDlg, ID_COMBO_SUGGESTIONS),
- str_lptstr, ARRAYSIZE(str_lptstr));
- if(str_lptstr_len)
- {
- UCS *str_ucs4;
- char *str_utf8;
-
- // Notify the speller so it'll suggest this word next time around.
- str_utf8 = lptstr_to_utf8(str_lptstr);
- if(str_utf8)
- {
- speller_replace_word(word_info->aspellinfo,
- word_info->word_utf8, -1, str_utf8, -1);
- fs_give((void **)&str_utf8);
- }
-
- str_ucs4 = lptstr_to_ucs4(str_lptstr);
- if(!str_ucs4)
- {
- // Uh oh - massive error.
- word_info->utf8_err_message = _("Spelling: lptstr_to_ucs4() failed");
- EndDialog(hDlg, -1);
- return;
- }
-
- // Move back to start of this word.
- curwp->w_doto = word_info->word_doto;
- curwp->w_dotp = word_info->word_dotp;
-
- if(do_replace_all)
- {
- int i;
- int word_size;
- UCS word[128];
-
- word_size = word_info->word_size;
- if(word_size >= ARRAYSIZE(word) - 1)
- word_size = ARRAYSIZE(word) - 1;
-
- for(i = 0; i < word_size; i++)
- word[i] = lgetc(curwp->w_dotp, curwp->w_doto + i).c;
-
- word[i] = 0;
-
- replace_all(word, word_size, str_ucs4);
-
- // Skip over the word we just inserted.
- forwchar(FALSE, (int)ucs4_strlen(str_ucs4));
- }
- else
- {
- // Swap it with the new improved version.
- chword_n(word_info->word_size, str_ucs4);
- }
- fs_give((void **)&str_ucs4);
- }
-
- update();
- spell_dlg_next_word(hDlg, word_info);
-}
-
-/*
- * center_dialog() - Center a dialog with respect to its parent.
- */
-static void
-center_dialog(HWND hDlg)
-{
- int dx;
- int dy;
- RECT rcDialog;
- RECT rcParent;
-
- GetWindowRect(GetParent(hDlg), &rcParent);
- GetWindowRect(hDlg, &rcDialog);
-
- dx = ((rcParent.right - rcParent.left) -
- (rcDialog.right - rcDialog.left)) / 2 + rcParent.left - rcDialog.left;
-
- dy = ((rcParent.bottom - rcParent.top) -
- (rcDialog.bottom - rcDialog.top)) / 2 + rcParent.top - rcDialog.top;
-
- OffsetRect(&rcDialog, dx, dy);
-
- SetWindowPos(hDlg, NULL, rcDialog.left, rcDialog.top, 0, 0,
- SWP_NOSIZE | SWP_NOZORDER);
-}
-
-/*
- * spell_dlg_on_command() - Handle the WM_COMMAND stuff for the spell dialog.
- */
-static void
-spell_dlg_on_command(HWND hDlg, int id, HWND hwndCtl, UINT codeNotify)
-{
- WORD_INFO *word_info =
- (WORD_INFO *)(LONG_PTR)GetWindowLongPtr(hDlg, GWLP_USERDATA);
-
- switch(id)
- {
- case ID_COMBO_SUGGESTIONS:
- if(codeNotify == CBN_EDITCHANGE)
- handle_cb_editchange(hDlg, hwndCtl);
- break;
-
- case ID_BUTTON_CHANGE:
- handle_button_change(hDlg, word_info, 0);
- break;
-
- case ID_BUTTON_CHANGEALL:
- handle_button_change(hDlg, word_info, 1);
- break;
-
- case ID_BUTTON_IGNOREONCE:
- spell_dlg_next_word(hDlg, word_info);
- break;
-
- case ID_BUTTON_IGNOREALL:
- speller_ignore_all(word_info->aspellinfo, word_info->word_utf8, -1);
- spell_dlg_next_word(hDlg, word_info);
- break;
-
- case ID_BUTTON_ADD_TO_DICT:
- speller_add_to_dictionary(word_info->aspellinfo, word_info->word_utf8, -1);
- spell_dlg_next_word(hDlg, word_info);
- break;
-
- case ID_BUTTON_CANCEL:
- EndDialog(hDlg, 0);
- break;
- }
-}
-
-/*
- * spell_dlg_proc() - Main spell dialog proc.
- */
-static INT_PTR CALLBACK
-spell_dlg_proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
-{
- WORD_INFO *word_info;
-
- switch(message)
- {
- case WM_INITDIALOG:
- center_dialog(hDlg);
-
- // Limit how much junk they can type in.
- ComboBox_LimitText(GetDlgItem(hDlg, ID_COMBO_SUGGESTIONS), 128);
-
- word_info = (WORD_INFO *)lParam;
- SetWindowLongPtr(hDlg, GWLP_USERDATA, (LONG_PTR)word_info);
-
- spell_dlg_proc_set_word(hDlg, word_info);
- return TRUE;
-
- case WM_COMMAND:
- HANDLE_WM_COMMAND(hDlg, wParam, lParam, spell_dlg_on_command);
- return TRUE;
- }
-
- return FALSE;
-}
-
-/*
- * get_next_word() - Get the next word from dot. And skip words in
- * quoted lines.
- */
-static int
-get_next_word(WORD_INFO *word_info)
-{
- // Skip quoted lines
- while(lgetc(curwp->w_dotp, 0).c == '>')
- {
- if(curwp->w_dotp == curbp->b_linep)
- return 0;
-
- curwp->w_dotp = lforw(curwp->w_dotp);
- curwp->w_doto = 0;
- curwp->w_flag |= WFMOVE;
- }
-
- // Move to a word.
- while(inword() == FALSE)
- {
- if(forwchar(FALSE, 1) == FALSE)
- {
- // There is no next word.
- return 0;
- }
- }
-
- // If mark is currently set, clear it.
- if(curwp->w_markp)
- setmark(0, 1);
-
- // Set mark to beginning of this word.
- curwp->w_markp = curwp->w_dotp;
- curwp->w_marko = curwp->w_doto;
-
- // Get word length
- word_info->word_doto = curwp->w_doto;
- word_info->word_dotp = curwp->w_dotp;
- word_info->word_size = 0;
-
- while((inword() != FALSE) && (word_info->word_dotp == curwp->w_dotp))
- {
- word_info->word_size++;
-
- if(forwchar(FALSE, 1) == FALSE)
- break;
- }
-
- word_info->word_utf8 = ucs4_to_utf8_cpystr_n(
- (UCS *)&word_info->word_dotp->l_text[word_info->word_doto],
- word_info->word_size);
- return 1;
-}
-
-/*
- * get_next_word() - free the word_info members word_utf8 and word_lptstr.
- */
-static void
-free_word_info_words(WORD_INFO *word_info)
-{
- if(word_info->word_utf8)
- {
- fs_give((void **)&word_info->word_utf8);
- word_info->word_utf8 = NULL;
- }
-
- if(word_info->word_lptstr)
- {
- fs_give((void **)&word_info->word_lptstr);
- word_info->word_lptstr = NULL;
- }
-}
-
-/*
- * get_next_bad_word() - Search from '.' for the next word we think is
- * rotten. Mark it and highlight it.
- */
-static int
-get_next_bad_word(WORD_INFO *word_info)
-{
- free_word_info_words(word_info);
-
- while(get_next_word(word_info))
- {
- int ret;
-
- /* pass over words that contain @ */
- if(strchr(word_info->word_utf8, '@'))
- ret = 1;
- else
- ret = speller_check_word(word_info->aspellinfo, word_info->word_utf8, -1);
-
- if(ret == -1)
- {
- word_info->utf8_err_message =
- speller_get_error_message(word_info->aspellinfo);
- if(!word_info->utf8_err_message)
- word_info->utf8_err_message = _("Spelling: speller_check_word() failed");
- return 0;
- }
- else if(ret == 0)
- {
- // Highlight word.
- update();
-
- word_info->word_lptstr = utf8_to_lptstr(word_info->word_utf8);
- return 1;
- }
-
- free_word_info_words(word_info);
- }
-
- return 0;
-}
+/* + * ======================================================================== + * MSWIN_SPELL.C + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +#include "../headers.h" + +#include "mswin_aspell.h" +#include "mswin_spell.h" + +#include <windowsx.h> + +typedef struct WORD_INFO +{ + ASPELLINFO *aspellinfo; // Aspell information + + const char *utf8_err_message; // Error message, if any + + char *word_utf8; // utf-8 + LPTSTR word_lptstr; + + int word_doto; // UCS + LINE *word_dotp; // + int word_size; // +} WORD_INFO; + +extern HINSTANCE ghInstance; +extern HWND ghTTYWnd; + +/* + * Function prototypes + */ +static int get_next_bad_word(WORD_INFO *word_info); +static void free_word_info_words(WORD_INFO *word_info); +static INT_PTR CALLBACK spell_dlg_proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); + +/* + * spell() - check for potentially missspelled words and offer them for + * correction. Microsoft Windows specific version. + */ +int +spell(int f, int n) +{ + int w_marko_bak; + LINE *w_markp_bak; + WORD_INFO word_info; + ASPELLINFO *aspellinfo; + + emlwrite(_("Checking spelling..."), NULL); /* greetings! */ + + memset(&word_info, 0, sizeof(WORD_INFO)); + + aspellinfo = speller_init(NULL); + if(!aspellinfo || + (word_info.utf8_err_message = speller_get_error_message(aspellinfo))) + { + if(word_info.utf8_err_message) + emlwrite((char *)word_info.utf8_err_message, NULL); /* sad greetings! */ + else + emlwrite(_("Spelling: initializing Aspell failed"), NULL); + + speller_close(aspellinfo); + return -1; + } + + // Back up current mark. + w_marko_bak = curwp->w_marko; + w_markp_bak = curwp->w_markp; + + setimark(0, 1); + gotobob(0, 1); + + word_info.aspellinfo = aspellinfo; + + if(get_next_bad_word(&word_info)) + { + DialogBoxParam(ghInstance, MAKEINTRESOURCE(DLG_SPELL), ghTTYWnd, + spell_dlg_proc, (LPARAM)&word_info); + } + + // Restore original mark if possible. + if(curwp->w_markp) + { + // Clear any set marks. + setmark(0, 1); + + if(w_markp_bak && llength(w_markp_bak)) + { + // Make sure we don't set mark off the line. + if(w_marko_bak >= llength(w_markp_bak)) + w_marko_bak = llength(w_markp_bak) - 1; + + curwp->w_marko = w_marko_bak; + curwp->w_markp = w_markp_bak; + } + } + + if(word_info.utf8_err_message) + emlwrite((char *)word_info.utf8_err_message, NULL); + else + emlwrite(_("Done checking spelling"), NULL); + + speller_close(aspellinfo); + free_word_info_words(&word_info); + + swapimark(0, 1); + curwp->w_flag |= WFHARD|WFMODE; + + update(); + return 1; +} + +/* + * handle_cb_editchange() - combobox contents have changed so enable/disable + * the Change and Change All buttons accordingly. + */ +static void +handle_cb_editchange(HWND hDlg, HWND hwnd_combo) +{ + int text_len = ComboBox_GetTextLength(hwnd_combo); + + Button_Enable(GetDlgItem(hDlg, ID_BUTTON_CHANGE), !!text_len); + Button_Enable(GetDlgItem(hDlg, ID_BUTTON_CHANGEALL), !!text_len); +} + +/* + * spell_dlg_proc_set_word() - Set up the dialog to display spelling + * information and suggestions for the current word. + */ +static void +spell_dlg_proc_set_word(HWND hDlg, WORD_INFO *word_info) +{ + TCHAR dlg_title[256]; + HWND hwnd_combo = GetDlgItem(hDlg, ID_COMBO_SUGGESTIONS); + + // Clear the combobox. + ComboBox_ResetContent(hwnd_combo); + + // Set the dialog box title + _sntprintf(dlg_title, ARRAYSIZE(dlg_title), TEXT("Not in Dictionary: %s"), + word_info->word_lptstr); + dlg_title[ARRAYSIZE(dlg_title) - 1] = 0; + SetWindowText(hDlg, dlg_title); + + // Populate the combobox with suggestions + if(speller_suggestion_init(word_info->aspellinfo, word_info->word_utf8, -1)) + { + const char *suggestion_utf8; + + while(suggestion_utf8 = speller_suggestion_getnext(word_info->aspellinfo)) + { + LPTSTR suggestion_lptstr = utf8_to_lptstr((LPSTR)suggestion_utf8); + + if(suggestion_lptstr) + { + ComboBox_AddString(hwnd_combo, suggestion_lptstr); + fs_give((void **)&suggestion_lptstr); + } + } + + // Select the first one. + ComboBox_SetCurSel(hwnd_combo, 0); + + speller_suggestion_close(word_info->aspellinfo); + } + + handle_cb_editchange(hDlg, hwnd_combo); +} + +/* + * spell_dlg_next_word() - Move to the next misspelled word and display + * the information for it. If no more bad words, kill the dialog. + */ +static void +spell_dlg_next_word(HWND hDlg, WORD_INFO *word_info) +{ + if(!get_next_bad_word(word_info)) + { + EndDialog(hDlg, 0); + return; + } + + spell_dlg_proc_set_word(hDlg, word_info); +} + +/* + * chword_n() - change the given word_len pointed to by the curwp->w_dot + * pointers to the word in cb + */ +static void +chword_n(int wb_len, UCS *cb) +{ + ldelete(wb_len, NULL); /* not saved in kill buffer */ + + while(*cb != '\0') + linsert(1, *cb++); + + curwp->w_flag |= WFEDIT; +} + +/* + * replace_all() - replace all instances of oldword with newword from + * the current '.' on. Mark is where curwp will get restored to. + */ +static void +replace_all(UCS *oldword, int oldword_len, UCS *newword) +{ + int wrap; + + // Mark should be at "." right now - ie the start of the word we're + // checking. We're going to use mark below to restore curwp since + // chword_n can potentially realloc LINES and it knows about markp. + assert(curwp->w_markp); + assert(curwp->w_markp == curwp->w_dotp); + assert(curwp->w_marko == curwp->w_doto); + + curwp->w_bufp->b_mode |= MDEXACT; /* case sensitive */ + while(forscan(&wrap, oldword, 0, NULL, 0, 1)) + { + if(wrap) + break; /* wrap NOT allowed! */ + + /* + * We want to minimize the number of substrings that we report + * as matching a misspelled word... + */ + if(lgetc(curwp->w_dotp, 0).c != '>') + { + LINE *lp = curwp->w_dotp; /* for convenience */ + int off = curwp->w_doto; + + if(off == 0 || !ucs4_isalpha(lgetc(lp, off - 1).c)) + { + off += oldword_len; + + if(off == llength(lp) || !ucs4_isalpha(lgetc(lp, off).c)) + { + // Replace this word + chword_n(oldword_len, newword); + } + } + } + + forwchar(0, 1); /* move on... */ + + } + curwp->w_bufp->b_mode ^= MDEXACT; /* case insensitive */ + + curwp->w_dotp = curwp->w_markp; + curwp->w_doto = curwp->w_marko; +} + +/* + * handle_button_change() - Someone pressed the Change or Change All button. + * So deal with it. + */ +static void +handle_button_change(HWND hDlg, WORD_INFO *word_info, int do_replace_all) +{ + int str_lptstr_len; + TCHAR str_lptstr[128]; + + // Get the length of what they want to change to. + str_lptstr_len = ComboBox_GetText(GetDlgItem(hDlg, ID_COMBO_SUGGESTIONS), + str_lptstr, ARRAYSIZE(str_lptstr)); + if(str_lptstr_len) + { + UCS *str_ucs4; + char *str_utf8; + + // Notify the speller so it'll suggest this word next time around. + str_utf8 = lptstr_to_utf8(str_lptstr); + if(str_utf8) + { + speller_replace_word(word_info->aspellinfo, + word_info->word_utf8, -1, str_utf8, -1); + fs_give((void **)&str_utf8); + } + + str_ucs4 = lptstr_to_ucs4(str_lptstr); + if(!str_ucs4) + { + // Uh oh - massive error. + word_info->utf8_err_message = _("Spelling: lptstr_to_ucs4() failed"); + EndDialog(hDlg, -1); + return; + } + + // Move back to start of this word. + curwp->w_doto = word_info->word_doto; + curwp->w_dotp = word_info->word_dotp; + + if(do_replace_all) + { + int i; + int word_size; + UCS word[128]; + + word_size = word_info->word_size; + if(word_size >= ARRAYSIZE(word) - 1) + word_size = ARRAYSIZE(word) - 1; + + for(i = 0; i < word_size; i++) + word[i] = lgetc(curwp->w_dotp, curwp->w_doto + i).c; + + word[i] = 0; + + replace_all(word, word_size, str_ucs4); + + // Skip over the word we just inserted. + forwchar(FALSE, (int)ucs4_strlen(str_ucs4)); + } + else + { + // Swap it with the new improved version. + chword_n(word_info->word_size, str_ucs4); + } + fs_give((void **)&str_ucs4); + } + + update(); + spell_dlg_next_word(hDlg, word_info); +} + +/* + * center_dialog() - Center a dialog with respect to its parent. + */ +static void +center_dialog(HWND hDlg) +{ + int dx; + int dy; + RECT rcDialog; + RECT rcParent; + + GetWindowRect(GetParent(hDlg), &rcParent); + GetWindowRect(hDlg, &rcDialog); + + dx = ((rcParent.right - rcParent.left) - + (rcDialog.right - rcDialog.left)) / 2 + rcParent.left - rcDialog.left; + + dy = ((rcParent.bottom - rcParent.top) - + (rcDialog.bottom - rcDialog.top)) / 2 + rcParent.top - rcDialog.top; + + OffsetRect(&rcDialog, dx, dy); + + SetWindowPos(hDlg, NULL, rcDialog.left, rcDialog.top, 0, 0, + SWP_NOSIZE | SWP_NOZORDER); +} + +/* + * spell_dlg_on_command() - Handle the WM_COMMAND stuff for the spell dialog. + */ +static void +spell_dlg_on_command(HWND hDlg, int id, HWND hwndCtl, UINT codeNotify) +{ + WORD_INFO *word_info = + (WORD_INFO *)(LONG_PTR)GetWindowLongPtr(hDlg, GWLP_USERDATA); + + switch(id) + { + case ID_COMBO_SUGGESTIONS: + if(codeNotify == CBN_EDITCHANGE) + handle_cb_editchange(hDlg, hwndCtl); + break; + + case ID_BUTTON_CHANGE: + handle_button_change(hDlg, word_info, 0); + break; + + case ID_BUTTON_CHANGEALL: + handle_button_change(hDlg, word_info, 1); + break; + + case ID_BUTTON_IGNOREONCE: + spell_dlg_next_word(hDlg, word_info); + break; + + case ID_BUTTON_IGNOREALL: + speller_ignore_all(word_info->aspellinfo, word_info->word_utf8, -1); + spell_dlg_next_word(hDlg, word_info); + break; + + case ID_BUTTON_ADD_TO_DICT: + speller_add_to_dictionary(word_info->aspellinfo, word_info->word_utf8, -1); + spell_dlg_next_word(hDlg, word_info); + break; + + case ID_BUTTON_CANCEL: + EndDialog(hDlg, 0); + break; + } +} + +/* + * spell_dlg_proc() - Main spell dialog proc. + */ +static INT_PTR CALLBACK +spell_dlg_proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + WORD_INFO *word_info; + + switch(message) + { + case WM_INITDIALOG: + center_dialog(hDlg); + + // Limit how much junk they can type in. + ComboBox_LimitText(GetDlgItem(hDlg, ID_COMBO_SUGGESTIONS), 128); + + word_info = (WORD_INFO *)lParam; + SetWindowLongPtr(hDlg, GWLP_USERDATA, (LONG_PTR)word_info); + + spell_dlg_proc_set_word(hDlg, word_info); + return TRUE; + + case WM_COMMAND: + HANDLE_WM_COMMAND(hDlg, wParam, lParam, spell_dlg_on_command); + return TRUE; + } + + return FALSE; +} + +/* + * get_next_word() - Get the next word from dot. And skip words in + * quoted lines. + */ +static int +get_next_word(WORD_INFO *word_info) +{ + // Skip quoted lines + while(lgetc(curwp->w_dotp, 0).c == '>') + { + if(curwp->w_dotp == curbp->b_linep) + return 0; + + curwp->w_dotp = lforw(curwp->w_dotp); + curwp->w_doto = 0; + curwp->w_flag |= WFMOVE; + } + + // Move to a word. + while(inword() == FALSE) + { + if(forwchar(FALSE, 1) == FALSE) + { + // There is no next word. + return 0; + } + } + + // If mark is currently set, clear it. + if(curwp->w_markp) + setmark(0, 1); + + // Set mark to beginning of this word. + curwp->w_markp = curwp->w_dotp; + curwp->w_marko = curwp->w_doto; + + // Get word length + word_info->word_doto = curwp->w_doto; + word_info->word_dotp = curwp->w_dotp; + word_info->word_size = 0; + + while((inword() != FALSE) && (word_info->word_dotp == curwp->w_dotp)) + { + word_info->word_size++; + + if(forwchar(FALSE, 1) == FALSE) + break; + } + + word_info->word_utf8 = ucs4_to_utf8_cpystr_n( + (UCS *)&word_info->word_dotp->l_text[word_info->word_doto], + word_info->word_size); + return 1; +} + +/* + * get_next_word() - free the word_info members word_utf8 and word_lptstr. + */ +static void +free_word_info_words(WORD_INFO *word_info) +{ + if(word_info->word_utf8) + { + fs_give((void **)&word_info->word_utf8); + word_info->word_utf8 = NULL; + } + + if(word_info->word_lptstr) + { + fs_give((void **)&word_info->word_lptstr); + word_info->word_lptstr = NULL; + } +} + +/* + * get_next_bad_word() - Search from '.' for the next word we think is + * rotten. Mark it and highlight it. + */ +static int +get_next_bad_word(WORD_INFO *word_info) +{ + free_word_info_words(word_info); + + while(get_next_word(word_info)) + { + int ret; + + /* pass over words that contain @ */ + if(strchr(word_info->word_utf8, '@')) + ret = 1; + else + ret = speller_check_word(word_info->aspellinfo, word_info->word_utf8, -1); + + if(ret == -1) + { + word_info->utf8_err_message = + speller_get_error_message(word_info->aspellinfo); + if(!word_info->utf8_err_message) + word_info->utf8_err_message = _("Spelling: speller_check_word() failed"); + return 0; + } + else if(ret == 0) + { + // Highlight word. + update(); + + word_info->word_lptstr = utf8_to_lptstr(word_info->word_utf8); + return 1; + } + + free_word_info_words(word_info); + } + + return 0; +} diff --git a/pith/pine.hlp b/pith/pine.hlp index 6231a466..af3d8207 100644 --- a/pith/pine.hlp +++ b/pith/pine.hlp @@ -181,28 +181,16 @@ Additions include: <P> <UL> - <LI> Style tag in body of html message causes Alpine to not write its content - until a new </style> - <LI> Pico: New subcommand of the search command, allows to reverse the - direction of search. <LI> Upgrade UW-IMAP to Panda IMAP from <A HREF="https://github.com/jonabbey/panda-imap">https://github.com/jonabbey/panda-imap</A>. - <LI> S/MIME: When a signed message is received from a user whose - certificate has not been imported, should the certificate fail to - validate, the user will be shown a warning, and asked how to proceed. + <LI> S/MIME: Add screen to manage certificates. <LI> Replace tabs by spaces in From and Subject fields to control for size in screen of these fields. Change only in index screen display. <LI> Add support to selective expunge through a subcommand of the select-apply commands. Read more in the <A HREF="h_index_cmd_expunge">help</A> for the expunge command. - <LI> Alpine does not attempt to automatically reopen a collection - that was not opened due to cancellation by the user. - Instead, the user must try to open it explicitly. - <LI> Alpine searches for a certificate that matches an email address in - all addresses in a certificate (instead of just the first - one) but when it tries to unlock the certificate, it asks - for the password for the first email address in that - certificate. + <LI> Pico: New subcommand of the search command, allows to reverse the + direction of search. <LI> Add /tls1, /tls1_1, /tls1_2 and /dtls1 to the definition of a server to use different ways to connect using ssl, for example {server.com/tls1} will attempt to connect to @@ -212,6 +200,16 @@ Additions include: Conversely, however, the /ssl flag does not imply any of these flags; the /ssl flag means SSLv3 or, if not available, SSLv2 in the SSL port. + <LI> Alpine does not attempt to automatically reopen a collection + that was not opened due to cancellation by the user. + Instead, the user must try to open it explicitly. + <LI> Alpine searches for a certificate that matches an email address in + all addresses in a certificate (instead of just the first + one) but when it tries to unlock the certificate, it asks + for the password for the first email address in that + certificate. + <LI> Style tag in body of html message causes Alpine to not write its content + until a new </style> <LI> Experimental: Write the content-type of a message in lowercase, as some non-compliant servers do not understand uppercase content-type, such as those of GMX.de. diff --git a/po/Makefile.in b/po/Makefile.in index 22554d5f..ac0522be 100644 --- a/po/Makefile.in +++ b/po/Makefile.in @@ -11,7 +11,7 @@ # Origin: gettext-0.16 PACKAGE = alpine -VERSION = 2.19.8 +VERSION = 2.19.9 PACKAGE_BUGREPORT = chappa@washington.edu SHELL = /bin/sh |