summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--VERSION2
-rw-r--r--alpine/osdep/mswin.rc8
-rw-r--r--alpine/osdep/mswinver.c5
-rwxr-xr-xconfigure20
-rw-r--r--doc/alpine.12
-rw-r--r--doc/tech-notes/index.html2
-rw-r--r--include/config.wnt.h6
-rw-r--r--mapi/pmapi.c2
-rw-r--r--mapi/pmapi.rc8
-rw-r--r--pico/osdep/mswin_spell.c1094
-rw-r--r--pith/pine.hlp28
-rw-r--r--po/Makefile.in2
12 files changed, 589 insertions, 590 deletions
diff --git a/VERSION b/VERSION
index 3983e5a6..2a7d0a45 100644
--- a/VERSION
+++ b/VERSION
@@ -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);
}
diff --git a/configure b/configure
index 46b7bf3d..2666e094 100755
--- a/configure
+++ b/configure
@@ -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 &lt;/style&gt;
- <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 &lt;/style&gt;
<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