sqispell.c
上传用户:s81996212
上传日期:2007-01-04
资源大小:722k
文件大小:14k
源码类别:

WEB邮件程序

开发平台:

C/C++

  1. /*
  2. ** Copyright 1998 - 1999 Double Precision, Inc.  See COPYING for
  3. ** distribution information.
  4. */
  5. /*
  6. ** $Id: sqispell.c,v 1.13 2000/03/14 18:58:35 mrsam Exp $
  7. */
  8. #include "sqwebmail.h"
  9. #include "maildir.h"
  10. #include "folder.h"
  11. #include "cgi/cgi.h"
  12. #include "rfc2045/rfc2045.h"
  13. #include "maildir/maildirmisc.h"
  14. #include "buf.h"
  15. #include "ispell.h"
  16. #include "filter.h"
  17. #include <stdio.h>
  18. #include <string.h>
  19. #include <fcntl.h>
  20. #include <ctype.h>
  21. extern void output_form(const char *);
  22. extern char form_args[];
  23. extern const char *sqwebmail_content_ispelldict;
  24. extern void output_attrencoded(const char *);
  25. extern char *newmsg_createdraft_do(const char *, const char *, int);
  26. static void spelladd(const char *);
  27. static int search_spell(const char *, unsigned, unsigned);
  28. int spell_start(const char *c)
  29. {
  30. char *filename=maildir_find(DRAFTS, c);
  31. if (!c) return (-1);
  32. if (search_spell(filename, 0, 0) == 0)
  33. return (-1);
  34. return (0);
  35. }
  36. /*
  37. ** Search for misspelled words.
  38. */
  39. static struct rfc2045 *findtext(struct rfc2045 *);
  40. static char *spell_check(const char *, unsigned, unsigned,
  41. const char *, const char *, const char *, int *);
  42. static int search_spell(const char *filename, unsigned parnum, unsigned pos)
  43. {
  44. struct rfc2045 *rfcp, *textp;
  45. struct buf newtext, current_line;
  46. off_t start_pos, end_pos, start_body;
  47. int made_replacements, has_misspelling;
  48. char *new_line;
  49. unsigned paragraph;
  50. const char *ignoreword="";
  51. const char *replacefrom="";
  52. const char *replaceto="";
  53. int checked=0;
  54. off_t dummy;
  55. FILE *fp=0;
  56. int x;
  57. x=maildir_safeopen(filename, O_RDONLY, 0);
  58. if (x >= 0)
  59. if ((fp=fdopen(x, "r")) == 0)
  60. close(x);
  61. if (!fp) return (0);
  62. rfcp=rfc2045_fromfp(fp);
  63. if (!rfcp) enomem();
  64. textp=findtext(rfcp);
  65. if (!textp)
  66. {
  67. rfc2045_free(rfcp);
  68. fclose(fp);
  69. return (0);
  70. }
  71. buf_init(&newtext);
  72. buf_init(&current_line);
  73.         rfc2045_mimepos(textp, &start_pos, &end_pos, &start_body,
  74. &dummy, &dummy);
  75.         if (fseek(fp, start_body, SEEK_SET) == -1)
  76.                 enomem();
  77. made_replacements=0;
  78. has_misspelling=0;
  79. paragraph=0;
  80.         for ( ; start_body < end_pos; start_body++)
  81. {
  82. int c=getc(fp);
  83. if (c < 0) enomem();
  84. if (c != 'n')
  85. {
  86. buf_append(&current_line, c);
  87. continue;
  88. }
  89. buf_append(&current_line, '');
  90. if (parnum)
  91. {
  92. --parnum;
  93. buf_cat(&newtext, current_line.ptr);
  94. buf_cat(&newtext, "n");
  95. current_line.cnt=0;
  96. ++paragraph;
  97. continue;
  98. }
  99. if (!checked)
  100. {
  101. int l;
  102. checked=1;
  103. if ((l=strlen(cgi("word"))) > 0)
  104. {
  105. /* Ok, what should we do? */
  106. const char *newword=cgi("REPLACE");
  107. if (!*newword || strcmp(newword, "#other") == 0)
  108. newword=cgi("OTHER");
  109. /*
  110. ** Perhaps they entered the word without
  111. ** checking this checkmark.
  112. */
  113. else if (*newword == '#')
  114. newword="";
  115. if (*newword && pos + l <= strlen(current_line.ptr))
  116. {
  117. struct buf tempbuf;
  118. buf_init(&tempbuf);
  119. buf_cpyn(&tempbuf, current_line.ptr,
  120. pos);
  121. buf_cat(&tempbuf, newword);
  122. buf_cat(&tempbuf,
  123. current_line.ptr+pos+l);
  124. pos += strlen(newword);
  125. if (*cgi("REPLACEALL"))
  126. {
  127. replacefrom=cgi("word");
  128. replaceto=newword;
  129. }
  130. buf_append(&tempbuf, '');
  131. buf_cpy(&current_line, tempbuf.ptr);
  132. buf_append(&current_line, '');
  133. buf_free(&tempbuf);
  134. made_replacements=1;
  135. }
  136. else
  137. {
  138. pos += l;
  139. if (strcmp(cgi("REPLACE"),
  140. "#ignoreall") == 0)
  141. ignoreword=cgi("word");
  142. }
  143. if (strcmp(cgi("REPLACE"),
  144. "#insert") == 0)
  145. {
  146. spelladd(cgi("word"));
  147. }
  148. }
  149. }
  150. if (*current_line.ptr == '>')
  151. {
  152. buf_cat(&newtext, current_line.ptr);
  153. buf_cat(&newtext, "n");
  154. pos=0;
  155. current_line.cnt=0;
  156. ++paragraph;
  157. continue;
  158. }
  159. if (!has_misspelling)
  160. {
  161. new_line=spell_check(current_line.ptr, paragraph, pos,
  162. ignoreword, replacefrom, replaceto,
  163. &has_misspelling);
  164. if (new_line)
  165. {
  166. buf_cat(&newtext, new_line);
  167. free(new_line);
  168. made_replacements=1;
  169. }
  170. else buf_cat(&newtext, current_line.ptr);
  171. }
  172. else buf_cat(&newtext, current_line.ptr);
  173. buf_cat(&newtext, "n");
  174. pos=0;
  175. current_line.cnt=0;
  176. ++paragraph;
  177. }
  178. if (current_line.cnt)
  179. buf_cat(&newtext, "n");
  180. rfc2045_free(rfcp);
  181. fclose(fp);
  182. if (made_replacements)
  183. {
  184. char *p=newmsg_createdraft_do(filename, newtext.ptr, 1);
  185. if (p) free(p);
  186. if (*cgi("error"))
  187. {
  188. has_misspelling=0; /* Abort spell checking */
  189. }
  190. }
  191. buf_free(&newtext);
  192. buf_free(&current_line);
  193. if (*ignoreword)
  194. {
  195. static char *p=0;
  196. if (p) free(p);
  197. p=malloc(strlen(cgi("globignore")) + 2 + strlen(ignoreword));
  198. if (!p) enomem();
  199. strcpy(p, cgi("globignore"));
  200. if (*p) strcat(p, ":");
  201. strcat(p, ignoreword);
  202. cgi_put("globignore", p);
  203. }
  204. if (*replacefrom)
  205. {
  206. static char *p=0;
  207. if (p) free(p);
  208. p=malloc(strlen(cgi("globreplace"))+3
  209. +strlen(replacefrom)+strlen(replaceto));
  210. if (!p) enomem();
  211. strcpy(p, cgi("globreplace"));
  212. if (*p) strcat(p, ":");
  213. strcat(strcat(strcat(p, replacefrom), ":"), replaceto);
  214. cgi_put("globreplace", p);
  215. free(p);
  216. }
  217. if (has_misspelling) return (1);
  218. return (0);
  219. }
  220. static struct rfc2045 *findtext(struct rfc2045 *rfcp)
  221. {
  222. struct rfc2045 *textp;
  223. const char *content_type;
  224. const char *content_transfer_encoding;
  225. const char *charset;
  226. rfc2045_mimeinfo(rfcp, &content_type,
  227. &content_transfer_encoding, &charset);
  228. if (strncmp(content_type, "text/", 5) == 0)
  229. textp=rfcp;
  230. else
  231. {
  232. for (textp=rfcp->firstpart; textp; textp=textp->next)
  233. {
  234. if (textp->isdummy) continue;
  235. rfc2045_mimeinfo(textp, &content_type,
  236. &content_transfer_encoding, &charset);
  237. if (strncmp(content_type, "text/", 5) == 0)
  238. break;
  239. }
  240. }
  241. return (textp);
  242. }
  243. /*
  244. ** Ok, check a single paragraph, starting at position #pos.
  245. **
  246. ** If some replacements were made due to previous saved 'replace all' words,
  247. ** return the text of the modified line.  Otherwise return NULL.
  248. **
  249. ** Set *hasmisspelled to 1 if there are some misspellings in this line.
  250. */
  251. static struct ispell *ispellptr;
  252. static char *ispellline=0;
  253. static unsigned paragraph;
  254. static int spellignore(const char *);
  255. static char *spellreplace(const char *);
  256. static char *spell_check(const char *line, unsigned pnum, unsigned pos,
  257. const char *ignoreword,
  258. const char *replacefrom,
  259. const char *replaceto,
  260. int *hasmisspelled)
  261. {
  262. struct ispell_misspelled *msp, *np;
  263. char *newline=0;
  264. const char *newword;
  265. char *w;
  266. if (strlen(line) <= pos) return (0); /* Sanity check */
  267. ispellptr=ispell_run(sqwebmail_content_ispelldict, line+pos);
  268. if (!ispellptr) enomem();
  269. for (msp=ispellptr->first_misspelled; msp; msp=msp->next)
  270. if (msp->misspelled_word)
  271. msp->word_pos += pos;
  272. for (msp=ispellptr->first_misspelled; msp; msp=msp->next)
  273. {
  274. if ((*ignoreword &&
  275. strcmp(msp->misspelled_word, ignoreword) == 0)
  276. || spellignore(msp->misspelled_word))
  277. {
  278. msp->misspelled_word=0;
  279. continue;
  280. }
  281. newword=0;
  282. if ( *replacefrom &&
  283. strcmp(msp->misspelled_word, replacefrom) == 0)
  284. newword=replaceto;
  285. w=0;
  286. if (newword ||
  287. (newword=w=spellreplace(msp->misspelled_word)) != 0)
  288. {
  289. char *p=malloc(strlen(newline ? newline:line)+strlen(newword)+1);
  290. if (!p) enomem();
  291. memcpy(p, (newline ? newline:line), msp->word_pos);
  292. strcpy(p+msp->word_pos, newword);
  293. strcat(p, (newline ? newline:line)+msp->word_pos+
  294. strlen(msp->misspelled_word));
  295. if (newline) free(newline);
  296. newline=p;
  297. for (np=msp; (np=np->next) != 0; )
  298. np->word_pos += strlen(newword)-strlen(msp->misspelled_word);
  299. msp->misspelled_word=0;
  300. if (w)
  301. free(w);
  302. continue;
  303. }
  304. *hasmisspelled=1;
  305. paragraph=pnum;
  306. break;
  307. }
  308. if (!hasmisspelled)
  309. {
  310. ispell_free(ispellptr);
  311. ispellptr=0;
  312. }
  313. else
  314. {
  315. if (ispellline) free(ispellline);
  316. if ((ispellline=malloc(strlen( newline ? newline:line)+1)) == 0)
  317. enomem();
  318. strcpy(ispellline, newline ? newline:line);
  319. }
  320. return (newline);
  321. }
  322. static void showfunc(const char *p, size_t n)
  323. {
  324. while (n)
  325. {
  326. if (*p == ' ')
  327. printf("&nbsp;");
  328. else if (*p != 'n')
  329. putchar(*p);
  330. p++;
  331. --n;
  332. }
  333. }
  334. void spell_show()
  335. {
  336. const char *draftmessage=cgi("draftmessage");
  337. struct ispell_misspelled *msp;
  338. struct ispell_suggestion *isps;
  339. size_t p, l=strlen(ispellline), n;
  340. char *ignorelab=strtok(form_args, "|");
  341. char *ignorealllab=strtok(NULL, "|");
  342. char *replacelab=strtok(NULL, "|");
  343. char *replacealllab=strtok(NULL, "|");
  344. char *insertlab=strtok(NULL, "|");
  345. char *continuelab=strtok(NULL, "|");
  346. char *finishlab=strtok(NULL, "|");
  347. if (!ispellptr) enomem();
  348. if (!ignorelab) ignorelab="";
  349. if (!ignorealllab) ignorealllab="";
  350. if (!replacelab) replacelab="";
  351. if (!replacealllab) replacealllab="";
  352. if (!continuelab) continuelab="";
  353. if (!finishlab) finishlab="";
  354. for (msp=ispellptr->first_misspelled; msp; msp=msp->next)
  355. if (msp->misspelled_word) break;
  356. if (!msp) enomem();
  357. CHECKFILENAME(draftmessage);
  358. printf("<INPUT TYPE=HIDDEN NAME=form VALUE="spellchk">n");
  359. printf("<INPUT TYPE=HIDDEN NAME=pos VALUE="%s">n", cgi("pos"));
  360. if (*cgi("globignore"))
  361. {
  362. printf("<INPUT TYPE=HIDDEN NAME=globignore VALUE="");
  363. output_attrencoded(cgi("globignore"));
  364. printf("">n");
  365. }
  366. if (*cgi("globreplace"))
  367. {
  368. printf("<INPUT TYPE=HIDDEN NAME=globreplace VALUE="");
  369. output_attrencoded(cgi("globreplace"));
  370. printf("">n");
  371. }
  372. printf("<INPUT TYPE=HIDDEN NAME=draftmessage VALUE="");
  373. output_attrencoded(draftmessage);
  374. printf("">");
  375. printf("<INPUT TYPE=HIDDEN NAME=row VALUE="%u"><INPUT TYPE=HIDDEN NAME=col VALUE="%u"><INPUT TYPE=HIDDEN NAME=word VALUE="",
  376. (unsigned)paragraph,
  377. (unsigned)msp->word_pos);
  378. output_attrencoded(msp->misspelled_word);
  379. printf(""><TABLE BORDER=0 CELLSPACING=0><TR><TD>");
  380. printf("<TABLE BORDER=1 WIDTH="100%%" BGCOLOR="#EEEEEE" CELLSPACING=0 CELLPADDING=8><TR><TD ALIGN=CENTER><TT><FONT COLOR="#000000">");
  381. if (msp->word_pos > 30)
  382. {
  383. p=msp->word_pos-30;
  384. for (n=p; n<msp->word_pos; n++)
  385. if (ispellline[n] == ' ')
  386. {
  387. while (n < p && ispellline[n] == ' ')
  388. ++n;
  389. p=n;
  390. break;
  391. }
  392. printf("...&nbsp;");
  393. }
  394. else
  395. p=0;
  396. filter_start(FILTER_FOR_DISPLAY, &showfunc);
  397. filter(ispellline+p, msp->word_pos-p);
  398. filter_end();
  399. printf("<B>");
  400. filter_start(FILTER_FOR_DISPLAY, &showfunc);
  401. filter(ispellline+msp->word_pos, strlen(msp->misspelled_word));
  402. filter_end();
  403. printf("</B>");
  404. p=msp->word_pos+strlen(msp->misspelled_word);
  405. if (l-p < 30)
  406. {
  407. n=l-p;
  408. }
  409. else n=30;
  410. while (n)
  411. {
  412. if (ispellline[n+p] != ' ')
  413. {
  414. --n;
  415. continue;
  416. }
  417. while (n && ispellline[n+p-1] == ' ')
  418. --n;
  419. break;
  420. }
  421. filter_start(FILTER_FOR_DISPLAY, &showfunc);
  422. filter(ispellline+p, n);
  423. filter_end();
  424. if (n != l-p)
  425. printf("&nbsp;...");
  426. printf("</FONT></TT></TD></TR></TABLE><BR>");
  427. printf("<TABLE BORDER=1 BGCOLOR="#FFFFC0" CELLPADDING=8><TR><TD>");
  428. printf("<TABLE BORDER=0 WIDTH="100%%"><TR><TD>");
  429. for (isps=msp->first_suggestion; isps; isps=isps->next)
  430. {
  431. printf("<TR><TD>%s</TD><TD><INPUT BORDER=0 TYPE=RADIO NAME=REPLACE VALUE="%s"></TD><TD>%s</TD></TR>n",
  432. replacelab,
  433. isps->suggested_word,
  434. isps->suggested_word);
  435. replacelab=" ";
  436. }
  437. printf("<TR><TD>%s</TD><TD><INPUT BORDER=0 TYPE=RADIO NAME=REPLACE VALUE="#other"></TD><TD><INPUT TYPE=TEXT NAME=OTHER WIDTH=20></TD></TR>n",
  438. replacelab);
  439. printf("<TR><TD> </TD><TD><INPUT BORDER=0 TYPE=RADIO NAME=REPLACE VALUE="#insert"></TD><TD>%s</TD></TR>n",
  440. insertlab);
  441. printf("<TR><TD> </TD><TD><INPUT BORDER=0 TYPE=CHECKBOX NAME=REPLACEALL></TD><TD>%s</TD></TR>n",
  442. replacealllab);
  443. printf("<TR><TD> </TD><TD COLSPAN=2><HR WIDTH="100%%"></TD></TR>n");
  444. printf("<TR><TD> </TD><TD><INPUT BORDER=0 TYPE=RADIO NAME=REPLACE VALUE="#ignore"></TD><TD>%s</TD></TR>n",
  445. ignorelab);
  446. printf("<TR><TD> </TD><TD><INPUT BORDER=0 TYPE=RADIO NAME=REPLACE VALUE="#ignoreall"></TD><TD>%s</TD></TR>n",
  447. ignorealllab);
  448. printf("</TABLE>");
  449. printf("</TR></TD></TABLE><BR>");
  450. printf("<TABLE BORDER=1 CELLPADDING=8 BGCOLOR="#EEEEEE" WIDTH="100%%"><TR><TD>");
  451. printf("<INPUT TYPE=SUBMIT NAME="continue" VALUE="%s">n",
  452. continuelab);
  453. printf("<INPUT TYPE=SUBMIT NAME="finish" VALUE="%s">n",
  454. finishlab);
  455. printf("</TD></TR></TABLE>n");
  456. printf("</TD></TR></TABLE>n");
  457. }
  458. static FILE *opendict(const char *mode)
  459. {
  460. FILE *fp;
  461. char *p=malloc(sqwebmail_content_ispelldict ?
  462. strlen(sqwebmail_content_ispelldict)+20:20);
  463. if (!p) enomem();
  464. strcat(strcpy(p, sqwebmail_content_ispelldict ?
  465. "sqwebmail-dict-":"sqwebmail-dict"),
  466. sqwebmail_content_ispelldict ? sqwebmail_content_ispelldict:"");
  467. fp=fopen(p, mode);
  468. free(p);
  469. return (fp);
  470. }
  471. static int spellignore(const char *word)
  472. {
  473. char buf[100];
  474. const char *c;
  475. char *p, *q;
  476. FILE *fp=opendict("r");
  477. if (!fp) return (0);
  478. while (fgets(buf, sizeof(buf), fp) != NULL)
  479. {
  480. if ((p=strchr(buf, 'n')) != 0) *p=0;
  481. if (strcmp(word, buf) == 0)
  482. {
  483. fclose(fp);
  484. return (1);
  485. }
  486. }
  487. fclose(fp);
  488. c=cgi("globignore");
  489. p=malloc(strlen(c)+1);
  490. if (!p) enomem();
  491. strcpy(p, c);
  492. for (q=p; (q=strtok(q, ":")) != 0; q=0)
  493. if (strcmp(q, word) == 0)
  494. {
  495. free(p);
  496. return (1);
  497. }
  498. return (0);
  499. }
  500. static void spelladd(const char *word)
  501. {
  502. FILE *fp=opendict("a");
  503. if (fp)
  504. {
  505. fprintf(fp, "%sn", word);
  506. fclose(fp);
  507. }
  508. }
  509. static char *spellreplace(const char *word)
  510. {
  511. char *p, *q, *r;
  512. const char *c=cgi("globreplace");
  513. p=malloc(strlen(c)+1);
  514. if (!p) enomem();
  515. strcpy(p, c);
  516. for (q=p; (q=strtok(q, ":")) != 0 && (r=strtok(0, ":")) != 0; q=0)
  517. {
  518. if (strcmp(q, word) == 0)
  519. {
  520. q=malloc(strlen(r)+1);
  521. if (!q) enomem();
  522. strcpy(q, r);
  523. free(p);
  524. return (q);
  525. }
  526. }
  527. free(p);
  528. return (0);
  529. }
  530. void spell_check_continue()
  531. {
  532. const char *filename=cgi("draftmessage");
  533. unsigned parnum=atol(cgi("row"));
  534. unsigned pos=atol(cgi("col"));
  535. char *draftfilename;
  536. CHECKFILENAME(filename);
  537. draftfilename=maildir_find(DRAFTS, filename);
  538. if (!draftfilename)
  539. {
  540. output_form("folder.html");
  541. return;
  542. }
  543. if (search_spell(draftfilename, parnum, pos) &&
  544. *cgi("continue"))
  545. output_form("spellchk.html");
  546. else
  547. {
  548. cgi_put("draft", cgi("draftmessage"));
  549. cgi_put("previewmsg","SPELLCHK");
  550. output_form("newmsg.html");
  551. }
  552. free(draftfilename);
  553. }
  554. void ispell_cleanup()
  555. {
  556. if(ispellline) free(ispellline);
  557. ispellline=NULL;
  558. }