diff options
| author | Sam Varshavchik | 2013-08-19 16:39:41 -0400 | 
|---|---|---|
| committer | Sam Varshavchik | 2013-08-25 14:43:51 -0400 | 
| commit | 9c45d9ad13fdf439d44d7443ae75da15ea0223ed (patch) | |
| tree | 7a81a04cb51efb078ee350859a64be2ebc6b8813 /sqwebmail/sqispell.c | |
| parent | a9520698b770168d1f33d6301463bb70a19655ec (diff) | |
| download | courier-libs-9c45d9ad13fdf439d44d7443ae75da15ea0223ed.tar.bz2 | |
Initial checkin
Imported from subversion report, converted to git. Updated all paths in
scripts and makefiles, reflecting the new directory hierarchy.
Diffstat (limited to 'sqwebmail/sqispell.c')
| -rw-r--r-- | sqwebmail/sqispell.c | 677 | 
1 files changed, 677 insertions, 0 deletions
| diff --git a/sqwebmail/sqispell.c b/sqwebmail/sqispell.c new file mode 100644 index 0000000..e695353 --- /dev/null +++ b/sqwebmail/sqispell.c @@ -0,0 +1,677 @@ +#include "config.h" +/* +** Copyright 1998 - 2001 Double Precision, Inc.  See COPYING for +** distribution information. +*/ + + +/* +*/ +#include	"sqwebmail.h" +#include	"maildir.h" +#include	"folder.h" +#include	"cgi/cgi.h" +#include	"rfc2045/rfc2045.h" +#include	"maildir/maildirmisc.h" +#include	"buf.h" +#include	"ispell.h" +#include	"filter.h" +#include	"newmsg.h" +#include	<stdio.h> +#include	<string.h> +#include	<fcntl.h> +#include	<ctype.h> + +extern const char *sqwebmail_content_charset; +extern void output_form(const char *); +extern const char *sqwebmail_content_ispelldict; +extern void output_attrencoded(const char *); + +static void spelladd(const char *); +static int search_spell(const char *, unsigned, unsigned); + +int spell_start(const char *c) +{ +char	*filename=maildir_find(INBOX "." DRAFTS, c); + +	if (!c)	return (-1); + +	if (search_spell(filename, 0, 0) == 0) +		return (-1); + +	return (0); +} + +/* +** Search for misspelled words. +*/ + +static struct rfc2045 *findtext(struct rfc2045 *); + +static char *spell_check(const char *, unsigned, unsigned, +	const char *, const char *, const char *, int *); + +static int search_spell(const char *filename, unsigned parnum, unsigned pos) +{ +struct	rfc2045	*rfcp, *textp; +struct	buf newtext, current_line; +off_t start_pos, end_pos, start_body; +int	made_replacements, has_misspelling; +char *new_line; +unsigned paragraph; +const char	*ignoreword=""; +const char	*replacefrom=""; +const char	*replaceto=""; +int	checked=0; +off_t	dummy; +FILE	*fp=0; +int	x; + +	x=maildir_safeopen(filename, O_RDONLY, 0); +	if (x >= 0) +		if ((fp=fdopen(x, "r")) == 0) +			close(x); + +	if (!fp)	return (0); +	rfcp=rfc2045_fromfp(fp); +	if (!rfcp)	enomem(); + +	textp=findtext(rfcp); + +	if (!textp) +	{ +		rfc2045_free(rfcp); +		fclose(fp); +		return (0); +	} + +	buf_init(&newtext); +	buf_init(¤t_line); + +        rfc2045_mimepos(textp, &start_pos, &end_pos, &start_body, +		&dummy, &dummy); +        if (fseek(fp, start_body, SEEK_SET) == -1) +                enomem(); + +	made_replacements=0; +	has_misspelling=0; +	paragraph=0; +        for ( ; start_body < end_pos; start_body++) +	{ +	int	c=getc(fp); + +		if (c < 0)	enomem(); +		if (c != '\n') +		{ +			buf_append(¤t_line, c); +			continue; +		} +		buf_append(¤t_line, '\0'); +		if (parnum) +		{ +			--parnum; +			buf_cat(&newtext, current_line.ptr); +			buf_cat(&newtext, "\n"); +			current_line.cnt=0; +			++paragraph; +			continue; +		} + +		if (!checked) +		{ +		int	l; + +			checked=1; +			if ((l=strlen(cgi("word"))) > 0) +			{ + +/* Ok, what should we do? */ + +			const char *newword=cgi("REPLACE"); + +				if (!*newword || strcmp(newword, "#other") == 0) +					newword=cgi("OTHER"); +				/* +				** Perhaps they entered the word without +				** checking this checkmark. +				*/ +				else if (*newword == '#') +					newword=""; + +				if (*newword && pos + l <= strlen(current_line.ptr)) +				{ +				struct buf tempbuf; + +					buf_init(&tempbuf); +					buf_cpyn(&tempbuf, current_line.ptr, +						pos); +					buf_cat(&tempbuf, newword); +					buf_cat(&tempbuf, +						current_line.ptr+pos+l); +					pos += strlen(newword); +					if (*cgi("REPLACEALL")) +					{ +						replacefrom=cgi("word"); +						replaceto=newword; +					} +					buf_append(&tempbuf, '\0'); +					buf_cpy(¤t_line, tempbuf.ptr); +					buf_append(¤t_line, '\0'); +					buf_free(&tempbuf); +					made_replacements=1; +				} +				else +				{ +					pos += l; +					if (strcmp(cgi("REPLACE"), +						"#ignoreall") == 0) +						ignoreword=cgi("word"); +				} + +				if (strcmp(cgi("REPLACE"), +						"#insert") == 0) +				{ +					spelladd(cgi("word")); +				} +			} +		} + + +		if (*current_line.ptr == '>') +		{ +			buf_cat(&newtext, current_line.ptr); +			buf_cat(&newtext, "\n"); +			pos=0; +			current_line.cnt=0; +			++paragraph; +			continue; +		} +		if (!has_misspelling) +		{ +			new_line=spell_check(current_line.ptr, paragraph, pos, +				ignoreword, replacefrom, replaceto, +				&has_misspelling); +			if (new_line) +			{ +				buf_cat(&newtext, new_line); +				free(new_line); +				made_replacements=1; +			} +			else	buf_cat(&newtext, current_line.ptr); +		} +		else	buf_cat(&newtext, current_line.ptr); +		buf_cat(&newtext, "\n"); +		pos=0; +		current_line.cnt=0; +		++paragraph; +	} +	if (current_line.cnt) +		buf_cat(&newtext, "\n"); +	rfc2045_free(rfcp); +	fclose(fp); +	if (made_replacements) +	{ +	char	*p=newmsg_createdraft_do(filename, newtext.ptr, +					 NEWMSG_SQISPELL); + +		if (p)	free(p); + +		if (*cgi("error")) +		{ +			has_misspelling=0;	/* Abort spell checking */ +		} +	} + +	buf_free(&newtext); +	buf_free(¤t_line); + +	if (*ignoreword) +	{ +	static char *p=0; + +		if (p)	free(p); +		p=malloc(strlen(cgi("globignore")) + 2 + strlen(ignoreword)); + +		if (!p)	enomem(); + +		strcpy(p, cgi("globignore")); +		if (*p)	strcat(p, ":"); +		strcat(p, ignoreword); +		cgi_put("globignore", p); +	} + +	if (*replacefrom) +	{ +	static char *p=0; + +		if (p)	free(p); +		p=malloc(strlen(cgi("globreplace"))+3 +			+strlen(replacefrom)+strlen(replaceto)); + +		if (!p)	enomem(); +		strcpy(p, cgi("globreplace")); +		if (*p)	strcat(p, ":"); +		strcat(strcat(strcat(p, replacefrom), ":"), replaceto); +		cgi_put("globreplace", p); +		free(p); +	} +	if (has_misspelling)	return (1); +	return (0); +} + +static struct rfc2045 *findtext(struct rfc2045 *rfcp) +{ +struct rfc2045 *textp; +const char *content_type; +const char *content_transfer_encoding; +const char *charset; + +	rfc2045_mimeinfo(rfcp, &content_type, +		&content_transfer_encoding, &charset); +	if (strncmp(content_type, "text/", 5) == 0) +		textp=rfcp; +	else +	{ +		for (textp=rfcp->firstpart; textp; textp=textp->next) +		{ +			if (textp->isdummy)	continue; +			rfc2045_mimeinfo(textp, &content_type, +				&content_transfer_encoding, &charset); +			if (strncmp(content_type, "text/", 5) == 0) +				break; +		} +	} +	return (textp); +} + +/* +** Ok, check a single paragraph, starting at position #pos. +** +** If some replacements were made due to previous saved 'replace all' words, +** return the text of the modified line.  Otherwise return NULL. +** +** Set *hasmisspelled to 1 if there are some misspellings in this line. +*/ + +static struct	ispell	*ispellptr; +static char *ispellline=0; +static unsigned paragraph; + +static int spellignore(const char *); +static char *spellreplace(const char *); + +static char *spell_check(const char *line, unsigned pnum, unsigned pos, +	const char *ignoreword, +	const char *replacefrom, +	const char *replaceto, +	int *hasmisspelled) +{ +struct ispell_misspelled	*msp, *np; +char	*newline=0; +const char *newword; +char	*w; + +	if (strlen(line) <= pos)	return (0);	/* Sanity check */ + +	ispellptr=ispell_run(sqwebmail_content_ispelldict, line+pos); +	if (!ispellptr)	enomem(); +	for (msp=ispellptr->first_misspelled; msp; msp=msp->next) +		if (msp->misspelled_word) +			msp->word_pos += pos; + +	for (msp=ispellptr->first_misspelled; msp; msp=msp->next) +	{ +		if ((*ignoreword && +			strcmp(msp->misspelled_word, ignoreword) == 0) +			|| spellignore(msp->misspelled_word)) +		{ +			msp->misspelled_word=0; +			continue; +		} + +		newword=0; +		if ( *replacefrom && +			strcmp(msp->misspelled_word, replacefrom) == 0) +			newword=replaceto; + +		w=0; +		if (newword || +			(newword=w=spellreplace(msp->misspelled_word)) != 0) +		{ +		char	*p=malloc(strlen(newline ? newline:line)+strlen(newword)+1); + +			if (!p)	enomem(); +			memcpy(p, (newline ? newline:line), msp->word_pos); +			strcpy(p+msp->word_pos, newword); +			strcat(p, (newline ? newline:line)+msp->word_pos+ +				strlen(msp->misspelled_word)); +			if (newline)	free(newline); +			newline=p; +			for (np=msp; (np=np->next) != 0; ) +				np->word_pos += strlen(newword)-strlen(msp->misspelled_word); +			msp->misspelled_word=0; +			if (w) +				free(w); +			continue; +		} +		*hasmisspelled=1; +		paragraph=pnum; +		break; +	} +	if (!hasmisspelled) +	{ +		ispell_free(ispellptr); +		ispellptr=0; +	} +	else +	{ +		if (ispellline)	free(ispellline); +		if ((ispellline=malloc(strlen( newline ? newline:line)+1)) == 0) +			enomem(); +		strcpy(ispellline, newline ? newline:line); +	} +	return (newline); +} + +static void showfunc(const char *p, size_t n, void *dummy) +{ +	while (n) +	{ +		if (*p == ' ') +			printf(" "); +		else if (*p != '\n') +			putchar(*p); +		p++; +		--n; +	} +} + +static void show_part(const char *ptr, size_t cnt) +{ +	unicode_char *uc; +	size_t ucsize; +	int conv_err; + +	if (libmail_u_convert_tou_tobuf(ptr, cnt, +					sqwebmail_content_charset, +					&uc, +					&ucsize, +					&conv_err) == 0) +	{ +		if (conv_err) +		{ +			free(uc); +			uc=NULL; +		} +	} + + +	if (uc) +	{ + +		struct filter_info info; + +		filter_start(&info, sqwebmail_content_charset, +			     &showfunc, NULL); +		filter(&info, uc, ucsize); +		filter_end(&info); + +		free(uc); +	} +} + +void spell_show() +{ +const char *draftmessage=cgi("draftmessage"); +struct ispell_misspelled *msp; +struct ispell_suggestion *isps; +size_t	p, l=strlen(ispellline), n; +const char *ignorelab=getarg("IGNORE"); +const char *ignorealllab=getarg("IGNOREALL"); +const char *replacelab=getarg("REPLACE"); +const char *replacealllab=getarg("REPLACEALL"); +const char *insertlab=getarg("INSERT"); +const char *continuelab=getarg("CONTINUE"); +const char *finishlab=getarg("FINISH"); + +	if (!ispellptr)	enomem(); + +	if (!ignorelab)		ignorelab=""; +	if (!ignorealllab)	ignorealllab=""; +	if (!replacelab)	replacelab=""; +	if (!replacealllab)	replacealllab=""; +	if (!continuelab)	continuelab=""; +	if (!finishlab)		finishlab=""; + +	for (msp=ispellptr->first_misspelled; msp; msp=msp->next) +		if (msp->misspelled_word)	break; +	if (!msp)	enomem(); + +	CHECKFILENAME(draftmessage); + +	printf("<input type=\"hidden\" name=\"form\" value=\"spellchk\" />\n"); +	printf("<input type=\"hidden\" name=\"pos\" value=\"%s\" />\n", cgi("pos")); +	if (*cgi("globignore")) +	{ +		printf("<input type=\"hidden\" name=\"globignore\" value=\""); +		output_attrencoded(cgi("globignore")); +		printf("\" />\n"); +	} +	if (*cgi("globreplace")) +	{ +		printf("<input type=\"hidden\" name=\"globreplace\" value=\""); +		output_attrencoded(cgi("globreplace")); +		printf("\" />\n"); +	} + +	printf("<input type=\"hidden\" name=\"draftmessage\" value=\""); +	output_attrencoded(draftmessage); +	printf("\" />"); +	printf("<input type=\"hidden\" name=\"row\" value=\"%u\" /><input type=\"hidden\" name=\"col\" value=\"%u\" /><input type=\"hidden\" name=\"word\" value=\"", +		(unsigned)paragraph, +		(unsigned)msp->word_pos); +	output_attrencoded(msp->misspelled_word); + +	printf("\" /><table border=\"0\" cellspacing=\"0\" cellpadding=\"1\" " +	       "class=\"box-small-outer\"><tr><td>"); +	printf("<table border=\"0\" cellspacing=\"0\" class=\"spellcheck-background\"><tr><td>"); + +	printf("<table border=\"1\" cellspacing=\"0\" cellpadding=\"8\" class=\"spellcheck-excerpt\"><tr><td align=\"center\"><span style=\"color: #000000\" class=\"spellcheck-excerpt\">"); + +	if (msp->word_pos > 30) +	{ +		p=msp->word_pos-30; +		for (n=p; n<msp->word_pos; n++) +			if (ispellline[n] == ' ') +			{ +				while (n < p && ispellline[n] == ' ') +					++n; +				p=n; +				break; +			} +		printf("... "); +	} +	else +		p=0; + + +	show_part(ispellline+p, msp->word_pos-p); +	printf("<strong>"); +	show_part(ispellline+msp->word_pos, strlen(msp->misspelled_word)); +	printf("</strong>"); + +	p=msp->word_pos+strlen(msp->misspelled_word); +	if (l-p < 30) +	{ +		n=l-p; +	} +	else	n=30; + +	while (n) +	{ +		if (ispellline[n+p] != ' ') +		{ +			--n; +			continue; +		} +		while (n && ispellline[n+p-1] == ' ') +			--n; +		break; +	} + +	show_part(ispellline+p, n); + +	if (n != l-p) +		printf(" ..."); +	printf("</span></td></tr></table><br />"); +	printf("<table border=\"1\" cellpadding=\"8\" class=\"spellcheck-main\"><tr><td>"); + +	printf("<table border=\"0\">"); +	for (isps=msp->first_suggestion; isps; isps=isps->next) +	{ +		printf("<tr><td>%s</td><td><input type=\"radio\" name=\"REPLACE\" value=\"%s\" /></td><td>%s</td></tr>\n", +			replacelab, +			isps->suggested_word, +			isps->suggested_word); +		replacelab=" "; +	} +	printf("<tr><td>%s</td><td><input type=\"radio\" name=\"REPLACE\" value=\"#other\" /></td><td><input type=\"text\" name=\"OTHER\" size=\"20\" /></td></tr>\n", +		replacelab); +	printf("<tr><td> </td><td><input type=\"radio\" name=\"REPLACE\" value=\"#insert\" /></td><td>%s</td></tr>\n", +		insertlab); + +	printf("<tr><td> </td><td><input type=\"checkbox\" name=\"REPLACEALL\" /></td><td>%s</td></tr>\n", +		replacealllab); +	printf("<tr><td> </td><td colspan=\"2\"><hr width=\"100%%\" /></td></tr>\n"); +	printf("<tr><td> </td><td><input type=\"radio\" name=\"REPLACE\" value=\"#ignore\" /></td><td>%s</td></tr>\n", +		ignorelab); +	printf("<tr><td> </td><td><input type=\"radio\" name=\"REPLACE\" value=\"#ignoreall\" /></td><td>%s</td></tr>\n", +		ignorealllab); +	printf("</table>"); +	printf("</td></tr></table><br />"); +	printf("<table border=\"1\" cellpadding=\"8\" class=\"spellcheck-continue\"><tr><td>"); +	printf("<input type=\"submit\" name=\"continue\" value=\"%s\" />\n", +			continuelab); +	printf("<input type=\"submit\" name=\"finish\" value=\"%s\" />\n", +			finishlab); +	printf("</td></tr></table>\n"); +	printf("</td></tr></table>\n"); +	printf("</td></tr></table>\n"); +} + +static FILE *opendict(const char *mode) +{ +FILE	*fp; +char	*p=malloc(sqwebmail_content_ispelldict ? +			strlen(sqwebmail_content_ispelldict)+20:20); + +	if (!p)	enomem(); +	strcat(strcpy(p, sqwebmail_content_ispelldict ? +			"sqwebmail-dict-":"sqwebmail-dict"), +		sqwebmail_content_ispelldict ? sqwebmail_content_ispelldict:""); +	fp=fopen(p, mode); +	free(p); +	return (fp); +} + +static int spellignore(const char *word) +{ +char	buf[100]; +const char *c; +char	*p, *q; +FILE	*fp=opendict("r"); + +	if (!fp)	return (0); +	while (fgets(buf, sizeof(buf), fp) != NULL) +	{ +		if ((p=strchr(buf, '\n')) != 0)	*p=0; +		if (strcmp(word, buf) == 0) +		{ +			fclose(fp); +			return (1); +		} +	} +	fclose(fp); + +	c=cgi("globignore"); + +	p=malloc(strlen(c)+1); +	if (!p)	enomem(); +	strcpy(p, c); + +	for (q=p; (q=strtok(q, ":")) != 0; q=0) +		if (strcmp(q, word) == 0) +		{ +			free(p); +			return (1); +		} + +	return (0); +} + +static void spelladd(const char *word) +{ +FILE	*fp=opendict("a"); + +	if (fp) +	{ +		fprintf(fp, "%s\n", word); +		fclose(fp); +	} +} + +static char *spellreplace(const char *word) +{ +char	*p, *q, *r; +const char *c=cgi("globreplace"); + +	p=malloc(strlen(c)+1); +	if (!p)	enomem(); +	strcpy(p, c); +	for (q=p; (q=strtok(q, ":")) != 0 && (r=strtok(0, ":")) != 0; q=0) +	{ +		if (strcmp(q, word) == 0) +		{ +			q=malloc(strlen(r)+1); +			if (!q)	enomem(); +			strcpy(q, r); +			free(p); +			return (q); +		} +	} +	free(p); +	return (0); +} + +void spell_check_continue() +{ +const char *filename=cgi("draftmessage"); +unsigned parnum=atol(cgi("row")); +unsigned pos=atol(cgi("col")); +char	*draftfilename; + +	CHECKFILENAME(filename); +	draftfilename=maildir_find(INBOX "." DRAFTS, filename); +	if (!draftfilename) +	{ +		output_form("folder.html"); +		return; +	} + +	if (search_spell(draftfilename, parnum, pos) && +		*cgi("continue")) +		output_form("spellchk.html"); +	else +	{ +		cgi_put("draft", cgi("draftmessage")); +		cgi_put("previewmsg","SPELLCHK"); +		output_form("newmsg.html"); +	} +	free(draftfilename); +} + +void ispell_cleanup() +{ +	if(ispellline) free(ispellline); +	ispellline=NULL; +} | 
