Call me anal
[squirrelmail.git] / plugins / squirrelspell / sqspell_functions.php
1 <?php
2
3 /**
4 * sqspell_functions.php
5 *
6 * All SquirrelSpell-wide functions are in this file.
7 *
8 * @author Konstantin Riabitsev <icon at duke.edu>
9 * @copyright &copy; 1999-2007 The SquirrelMail Project Team
10 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
11 * @version $Id$
12 * @package plugins
13 * @subpackage squirrelspell
14 */
15
16 /** globalize configuration vars **/
17 global $SQSPELL_APP, $SQSPELL_APP_DEFAULT, $SQSPELL_WORDS_FILE, $SQSPELL_CRYPTO;
18
19 /**
20 * load plugin configuration
21 * @todo allow storing configuration file in config/ directory
22 */
23 include_once(SM_PATH . 'plugins/squirrelspell/sqspell_config.php');
24
25 /**
26 * Workaround for including function squirrelspell_version() in SM 1.5 CVS,
27 * where plugins' setup.php is not included by default.
28 */
29 include_once(SM_PATH . 'plugins/squirrelspell/setup.php');
30
31 /** Hooked functions **/
32
33 /**
34 * Register option page block (internal function)
35 * @since 1.5.1 (sqspell 0.5)
36 * @return void
37 */
38 function squirrelspell_optpage_block_function() {
39 global $optpage_blocks;
40
41 /**
42 * Dependency on JavaScript is checked by SquirrelMail scripts
43 * Register Squirrelspell with the $optpage_blocks array.
44 */
45 $optpage_blocks[] =
46 array(
47 'name' => _("SpellChecker Options"),
48 'url' => '../plugins/squirrelspell/sqspell_options.php',
49 'desc' => _("Here you may set up how your personal dictionary is stored, edit it, or choose which languages should be available to you when spell-checking."),
50 'js' => TRUE);
51 }
52
53 /**
54 * This function adds a "Check Spelling" link to the "Compose" row
55 * during message composition (internal function).
56 * @since 1.5.1 (sqspell 0.5)
57 * @return void
58 */
59 function squirrelspell_setup_function() {
60 /**
61 * Check if this browser is capable of displaying SquirrelSpell
62 * correctly.
63 */
64 if (checkForJavascript()) {
65
66 global $oTemplate, $base_uri, $nbsp;
67
68 $output = addButton(_("Check Spelling"),
69 'check_spelling',
70 array('onclick' => 'window.open(\'' . $base_uri
71 . 'plugins/squirrelspell/sqspell_interface.php\', \'sqspell\', \'status=yes,width=550,height=370,resizable=yes\')')) . $nbsp;
72
73 return array('compose_button_row' => $output);
74 }
75 }
76
77 /**
78 * Upgrade dictionaries (internal function)
79 *
80 * Transparently upgrades user's dictionaries when message listing is loaded
81 * @since 1.5.1 (sqspell 0.5)
82 */
83 function squirrelspell_upgrade_function() {
84 global $data_dir, $username;
85
86 if (! sqspell_check_version(0,5)) {
87 $langs=sqspell_getSettings_old(null);
88 $words=sqspell_getWords_old();
89 sqspell_saveSettings($langs);
90 foreach ($langs as $lang) {
91 $lang_words=sqspell_getLang_old($words,$lang);
92 $aLang_words=explode("\n",$lang_words);
93 $new_words=array();
94 foreach($aLang_words as $word) {
95 if (! preg_match("/^#/",$word) && trim($word)!='') {
96 $new_words[]=$word;
97 }
98 }
99 sqspell_writeWords($new_words,$lang);
100 }
101 // bump up version number
102 setPref($data_dir,$username,'sqspell_version','0.5');
103 }
104 }
105
106 /** Internal functions **/
107
108 /**
109 * This function is the GUI wrapper for the options page. SquirrelSpell
110 * uses it for creating all Options pages.
111 *
112 * @param string $title The title of the page to display
113 * @param string $scriptsrc This is used to link a file.js into the
114 * <script src="file.js"></script> format. This
115 * allows to separate javascript from the rest of the
116 * plugin and place it into the js/ directory.
117 * @param string $body The body of the message to display.
118 * @return void
119 */
120 function sqspell_makePage($title, $scriptsrc, $body){
121 global $color;
122
123 if (! sqgetGlobalVar('MOD', $MOD, SQ_GET) ) {
124 $MOD = 'options_main';
125 }
126
127 displayPageHeader($color);
128 echo "&nbsp;<br />\n";
129 /**
130 * Check if we need to link in a script.
131 */
132 if($scriptsrc) {
133 echo "<script type=\"text/javascript\" src=\"js/$scriptsrc\"></script>\n";
134 }
135 echo html_tag( 'table', '', 'center', '', 'width="95%" border="0" cellpadding="2" cellspacing="0"' ) . "\n"
136 . html_tag( 'tr', "\n" .
137 html_tag( 'td', '<strong>' . $title .'</strong>', 'center', $color[9] )
138 ) . "\n"
139 . html_tag( 'tr', "\n" .
140 html_tag( 'td', '<hr />', 'left' )
141 ) . "\n"
142 . html_tag( 'tr', "\n" .
143 html_tag( 'td', $body, 'left' )
144 ) . "\n";
145 /**
146 * Generate a nice "Return to Options" link, unless this is the
147 * starting page.
148 */
149 if ($MOD != "options_main"){
150 echo html_tag( 'tr', "\n" .
151 html_tag( 'td', '<hr />', 'left' )
152 ) . "\n"
153 . html_tag( 'tr', "\n" .
154 html_tag( 'td', '<a href="sqspell_options.php">'
155 . _("Back to &quot;SpellChecker Options&quot; page")
156 . '</a>',
157 'center' )
158 ) . "\n";
159 }
160 /**
161 * Close the table and display the version.
162 */
163 echo html_tag( 'tr', "\n" .
164 html_tag( 'td', '<hr />', 'left' )
165 ) . "\n"
166 . html_tag( 'tr',
167 html_tag( 'td', 'SquirrelSpell ' . squirrelspell_version(), 'center', $color[9] )
168 ) . "\n</table>\n";
169 echo '</body></html>';
170 }
171
172 /**
173 * Function similar to the one above. This one is a general wrapper
174 * for the Squirrelspell pop-up window. It's called form nearly
175 * everywhere, except the check_me module, since that one is highly
176 * customized.
177 *
178 * @param string $onload Used to indicate and pass the name of a js function
179 * to call in a <body onload="function()" for automatic
180 * onload script execution.
181 * @param string $title Title of the page.
182 * @param string $scriptsrc If defined, link this javascript source page into
183 * the document using <script src="file.js"> format.
184 * @param string $body The content to include.
185 * @return void
186 */
187 function sqspell_makeWindow($onload, $title, $scriptsrc, $body){
188 global $color;
189
190 displayHtmlHeader($title,
191 ($scriptsrc ? "\n<script type=\"text/javascript\" src=\"js/$scriptsrc\"></script>\n" : ''));
192
193 echo "<body text=\"$color[8]\" bgcolor=\"$color[4]\" link=\"$color[7]\" "
194 . "vlink=\"$color[7]\" alink=\"$color[7]\"";
195 /**
196 * Provide an onload="jsfunction()" if asked to.
197 */
198 if ($onload) {
199 echo " onload=\"$onload\"";
200 }
201 /**
202 * Draw the rest of the page.
203 */
204 echo ">\n"
205 . html_tag( 'table', "\n" .
206 html_tag( 'tr', "\n" .
207 html_tag( 'td', '<strong>' . $title . '</strong>', 'center', $color[9] )
208 ) . "\n" .
209 html_tag( 'tr', "\n" .
210 html_tag( 'td', '<hr />', 'left' )
211 ) . "\n" .
212 html_tag( 'tr', "\n" .
213 html_tag( 'td', $body, 'left' )
214 ) . "\n" .
215 html_tag( 'tr', "\n" .
216 html_tag( 'td', '<hr />', 'left' )
217 ) . "\n" .
218 html_tag( 'tr', "\n" .
219 html_tag( 'td', 'SquirrelSpell ' . squirrelspell_version(), 'center', $color[9] )
220 ) ,
221 '', '', 'width="100%" border="0" cellpadding="2"' );
222
223 global $oTemplate;
224 $oTemplate->display('footer.tpl');
225 }
226
227 /**
228 * Encryption function used by plugin (old format)
229 *
230 * This function does the encryption and decryption of the user
231 * dictionary. It is only available when PHP is compiled with
232 * mcrypt support (--with-mcrypt). See doc/CRYPTO for more
233 * information.
234 *
235 * @param $mode A string with either of the two recognized values:
236 * "encrypt" or "decrypt".
237 * @param $ckey The key to use for processing (the user's password
238 * in our case.
239 * @param $input Content to decrypt or encrypt, according to $mode.
240 * @return encrypted/decrypted content, or "PANIC" if the
241 * process bails out.
242 * @since 1.5.1 (sqspell 0.5)
243 * @deprecated
244 */
245 function sqspell_crypto_old($mode, $ckey, $input){
246 /**
247 * Double-check if we have the mcrypt_generic function. Bail out if
248 * not so.
249 */
250 if (!function_exists('mcrypt_generic')) {
251 return 'PANIC';
252 }
253 /**
254 * Setup mcrypt routines.
255 */
256 $td = mcrypt_module_open(MCRYPT_Blowfish, "", MCRYPT_MODE_ECB, "");
257 $iv = mcrypt_create_iv(mcrypt_enc_get_iv_size ($td), MCRYPT_RAND);
258 mcrypt_generic_init($td, $ckey, $iv);
259 /**
260 * See what we have to do depending on $mode.
261 * 'encrypt' -- Encrypt the content.
262 * 'decrypt' -- Decrypt the content.
263 */
264 switch ($mode){
265 case 'encrypt':
266 $crypto = mcrypt_generic($td, $input);
267 break;
268 case 'decrypt':
269 $crypto = mdecrypt_generic($td, $input);
270 /**
271 * See if it decrypted successfully. If so, it should contain
272 * the string "# SquirrelSpell". If not, then bail out.
273 */
274 if (!strstr($crypto, "# SquirrelSpell")){
275 $crypto='PANIC';
276 }
277 break;
278 }
279 /**
280 * Finish up the mcrypt routines and return the processed content.
281 */
282 if (function_exists('mcrypt_generic_deinit')) {
283 // php 4.1.1+ syntax
284 mcrypt_generic_deinit ($td);
285 mcrypt_module_close ($td);
286 } else {
287 // older deprecated function
288 mcrypt_generic_end ($td);
289 }
290 return $crypto;
291 }
292
293 /**
294 * Encryption function used by plugin
295 *
296 * This function does the encryption and decryption of the user
297 * dictionary. It is only available when PHP is compiled with
298 * mcrypt support (--with-mcrypt). See doc/CRYPTO for more
299 * information.
300 *
301 * @param $mode A string with either of the two recognized values:
302 * "encrypt" or "decrypt".
303 * @param $ckey The key to use for processing (the user's password
304 * in our case.
305 * @param $input Content to decrypt or encrypt, according to $mode.
306 * @return encrypted/decrypted content, or "PANIC" if the
307 * process bails out.
308 */
309 function sqspell_crypto($mode, $ckey, $input){
310 /**
311 * Double-check if we have the mcrypt_generic function. Bail out if
312 * not so.
313 */
314 if (!function_exists('mcrypt_generic')) {
315 return 'PANIC';
316 }
317 /**
318 * Setup mcrypt routines.
319 */
320 $td = mcrypt_module_open(MCRYPT_Blowfish, "", MCRYPT_MODE_ECB, "");
321 $iv = mcrypt_create_iv(mcrypt_enc_get_iv_size ($td), MCRYPT_RAND);
322 mcrypt_generic_init($td, $ckey, $iv);
323 /**
324 * See what we have to do depending on $mode.
325 * 'encrypt' -- Encrypt the content.
326 * 'decrypt' -- Decrypt the content.
327 */
328 switch ($mode){
329 case 'encrypt':
330 $crypto = mcrypt_generic($td, '{sqspell}'.$input);
331 break;
332 case 'decrypt':
333 $crypto = mdecrypt_generic($td, $input);
334 if (preg_match("/^\{sqspell\}(.*)/",$crypto,$match)){
335 $crypto = trim($match[1]);
336 } else {
337 $crypto='PANIC';
338 }
339 break;
340 }
341 /**
342 * Finish up the mcrypt routines and return the processed content.
343 */
344 if (function_exists('mcrypt_generic_deinit')) {
345 // php 4.1.1+ syntax
346 mcrypt_generic_deinit ($td);
347 mcrypt_module_close ($td);
348 } else {
349 // older deprecated function
350 mcrypt_generic_end ($td);
351 }
352 return $crypto;
353 }
354
355 /**
356 * This function transparently upgrades the 0.2 dictionary format to the
357 * 0.3 format, since user-defined languages have been added in 0.3 and
358 * the new format keeps user dictionaries selection in the file.
359 *
360 * This function will be retired soon, as it's been a while since anyone
361 * has been using SquirrelSpell-0.2.
362 *
363 * @param $words_string Contents of the 0.2-style user dictionary.
364 * @return Contents of the 0.3-style user dictionary.
365 * @deprecated
366 */
367 function sqspell_upgradeWordsFile($words_string){
368 global $SQSPELL_APP_DEFAULT, $SQSPELL_VERSION;
369 /**
370 * Define just one dictionary for this user -- the default.
371 * If the user wants more, s/he can set them up in personal
372 * preferences. See doc/UPGRADING for more info.
373 */
374 $new_words_string =
375 substr_replace($words_string,
376 "# SquirrelSpell User Dictionary $SQSPELL_VERSION\n# "
377 . "Last Revision: " . date("Y-m-d")
378 . "\n# LANG: $SQSPELL_APP_DEFAULT\n# $SQSPELL_APP_DEFAULT",
379 0, strpos($words_string, "\n")) . "# End\n";
380 sqspell_writeWords($new_words_string);
381 return $new_words_string;
382 }
383
384 /**
385 * gets list of available dictionaries from user's prefs.
386 * Function was modified in 1.5.1 (sqspell 0.5).
387 * Older function is suffixed with '_old'
388 * @return array list of dictionaries used by end user.
389 */
390 function sqspell_getSettings(){
391 global $data_dir, $username, $SQSPELL_APP_DEFAULT, $SQSPELL_APP;
392
393 $ret=array();
394
395 $sLangs=getPref($data_dir,$username,'sqspell_langs','');
396 if ($sLangs=='') {
397 $ret[0]=$SQSPELL_APP_DEFAULT;
398 } else {
399 $aLangs = explode(',',$sLangs);
400 foreach ($aLangs as $lang) {
401 if (array_key_exists($lang,$SQSPELL_APP)) {
402 $ret[]=$lang;
403 }
404 }
405 }
406 return $ret;
407 }
408
409 /**
410 * Saves user's language preferences
411 * @param array $langs languages array (first key is default language)
412 * @since 1.5.1 (sqspell 0.5)
413 */
414 function sqspell_saveSettings($langs) {
415 global $data_dir, $username;
416 setPref($data_dir,$username,'sqspell_langs',implode(',',$langs));
417 }
418
419 /**
420 * Get list of enabled languages.
421 *
422 * Right now it just returns an array with the dictionaries
423 * available to the user for spell-checking. It will probably
424 * do more in the future, as features are added.
425 *
426 * @param string $words The contents of the user's ".words" file.
427 * @return array a strings array with dictionaries available
428 * to this user, e.g. {"English", "Spanish"}, etc.
429 * @since 1.5.1 (sqspell 0.5)
430 * @deprecated
431 */
432 function sqspell_getSettings_old($words){
433 global $SQSPELL_APP, $SQSPELL_APP_DEFAULT;
434 /**
435 * Check if there is more than one dictionary configured in the
436 * system config.
437 */
438 if (sizeof($SQSPELL_APP) > 1){
439 /**
440 * Now load the user prefs. Check if $words was empty -- a bit of
441 * a dirty fall-back. TODO: make it so this is not required.
442 */
443 if(!$words){
444 $words=sqspell_getWords_old();
445 }
446 if ($words){
447 /**
448 * This user has a ".words" file.
449 * Find which dictionaries s/he wants to use and load them into
450 * the $langs array.
451 */
452 preg_match("/# LANG: (.*)/i", $words, $matches);
453 $langs=explode(", ", $matches[1]);
454 } else {
455 /**
456 * User doesn't have a personal dictionary. Grab the default
457 * system setting.
458 */
459 $langs[0]=$SQSPELL_APP_DEFAULT;
460 }
461 } else {
462 /**
463 * There is no need to read the ".words" file as there is only one
464 * dictionary defined system-wide.
465 */
466 $langs[0]=$SQSPELL_APP_DEFAULT;
467 }
468 return $langs;
469 }
470
471 /**
472 * Get user dictionary for selected language
473 * Function was modified in 1.5.1 (sqspell 0.5).
474 * Older function is suffixed with '_old'
475 * @param string $lang language
476 * @param array words stored in selected language dictionary
477 */
478 function sqspell_getLang($lang) {
479 global $data_dir, $username,$SQSPELL_CRYPTO;
480 $sWords=getPref($data_dir,$username,'sqspell_dict_' . $lang,'');
481 if (preg_match("/^\{crypt\}(.*)/i",$sWords,$match)) {
482 /**
483 * Dictionary is encrypted or mangled. Try to decrypt it.
484 * If fails, complain loudly.
485 *
486 * $old_key would be a value submitted by one of the modules with
487 * the user's old mailbox password. I admin, this is rather dirty,
488 * but efficient. ;)
489 */
490 if (sqgetGlobalVar('old_key', $old_key, SQ_POST)) {
491 $clear_key=$old_key;
492 } else {
493 sqgetGlobalVar('key', $key, SQ_COOKIE);
494 sqgetGlobalVar('onetimepad', $onetimepad, SQ_SESSION);
495 /**
496 * Get user's password (the key).
497 */
498 $clear_key = OneTimePadDecrypt($key, $onetimepad);
499 }
500 /**
501 * Invoke the decryption routines.
502 */
503 $sWords=sqspell_crypto("decrypt", $clear_key, $match[1]);
504 /**
505 * See if decryption failed.
506 */
507 if ($sWords=="PANIC"){
508 sqspell_handle_crypt_panic($lang);
509 // script execution stops here
510 } else {
511 /**
512 * OK! Phew. Set the encryption flag to true so we can later on
513 * encrypt it again before saving to HDD.
514 */
515 $SQSPELL_CRYPTO=true;
516 }
517 } else {
518 /**
519 * No encryption is/was used. Set $SQSPELL_CRYPTO to false,
520 * in case we have to save the dictionary later.
521 */
522 $SQSPELL_CRYPTO=false;
523 }
524 // rebuild word list and remove empty entries
525 $aWords=array();
526 foreach (explode(',',$sWords) as $word) {
527 if (trim($word) !='') {
528 $aWords[]=trim($word);
529 }
530 }
531 return $aWords;
532 }
533
534 /**
535 * Get user's dictionary (old format)
536 *
537 * This function returns only user-defined dictionary words that correspond
538 * to the requested language.
539 *
540 * @param $words The contents of the user's ".words" file.
541 * @param $lang Which language words to return, e.g. requesting
542 * "English" will return ONLY the words from user's
543 * English dictionary, disregarding any others.
544 * @return The list of words corresponding to the language
545 * requested.
546 * @since 1.5.1 (sqspell 0.5)
547 * @deprecated
548 */
549 function sqspell_getLang_old($words, $lang){
550 $start=strpos($words, "# $lang\n");
551 /**
552 * strpos() will return -1 if no # $lang\n string was found.
553 * Use this to return a zero-length value and indicate that no
554 * words are present in the requested dictionary.
555 */
556 if (!$start) return '';
557 /**
558 * The words list will end with a new directive, which will start
559 * with "#". Locate the next "#" and thus find out where the
560 * words end.
561 */
562 $end=strpos($words, "#", $start+1);
563 $lang_words = substr($words, $start, $end-$start);
564 return $lang_words;
565 }
566
567 /**
568 * Saves user's dictionary (old format)
569 *
570 * This function operates the user dictionary. If the format is
571 * clear-text, then it just reads the file and returns it. However, if
572 * the file is encrypted (well, "garbled"), then it tries to decrypt
573 * it, checks whether the decryption was successful, troubleshoots if
574 * not, then returns the clear-text dictionary to the app.
575 *
576 * @return the contents of the user's ".words" file, decrypted if
577 * necessary.
578 * @since 1.5.1 (sqspell 0.5)
579 * @deprecated
580 */
581 function sqspell_getWords_old(){
582 global $SQSPELL_WORDS_FILE, $SQSPELL_CRYPTO;
583 $words="";
584 if (file_exists($SQSPELL_WORDS_FILE)){
585 /**
586 * Gobble it up.
587 */
588 $fp=fopen($SQSPELL_WORDS_FILE, 'r');
589 $words=fread($fp, filesize($SQSPELL_WORDS_FILE));
590 fclose($fp);
591 }
592 /**
593 * Check if this is an encrypted file by looking for
594 * the string "# SquirrelSpell" in it (the crypto
595 * function does that).
596 */
597 if ($words && !strstr($words, "# SquirrelSpell")){
598 /**
599 * This file is encrypted or mangled. Try to decrypt it.
600 * If fails, complain loudly.
601 *
602 * $old_key would be a value submitted by one of the modules with
603 * the user's old mailbox password. I admin, this is rather dirty,
604 * but efficient. ;)
605 */
606 sqgetGlobalVar('key', $key, SQ_COOKIE);
607 sqgetGlobalVar('onetimepad', $onetimepad, SQ_SESSION);
608
609 sqgetGlobalVar('old_key', $old_key, SQ_POST);
610
611 if ($old_key != '') {
612 $clear_key=$old_key;
613 } else {
614 /**
615 * Get user's password (the key).
616 */
617 $clear_key = OneTimePadDecrypt($key, $onetimepad);
618 }
619 /**
620 * Invoke the decryption routines.
621 */
622 $words=sqspell_crypto_old("decrypt", $clear_key, $words);
623 /**
624 * See if decryption failed.
625 */
626 if ($words=="PANIC"){
627 sqspell_handle_crypt_panic();
628 // script execution stops here.
629 } else {
630 /**
631 * OK! Phew. Set the encryption flag to true so we can later on
632 * encrypt it again before saving to HDD.
633 */
634 $SQSPELL_CRYPTO=true;
635 }
636 } else {
637 /**
638 * No encryption is/was used. Set $SQSPELL_CRYPTO to false,
639 * in case we have to save the dictionary later.
640 */
641 $SQSPELL_CRYPTO=false;
642 }
643 /**
644 * Check if we need to upgrade the dictionary from version 0.2.x
645 * This is going away soon.
646 */
647 if (strstr($words, "Dictionary v0.2")){
648 $words=sqspell_upgradeWordsFile($words);
649 }
650 return $words;
651 }
652
653 /**
654 * Saves user's dictionary
655 * Function was replaced in 1.5.1 (sqspell 0.5).
656 * Older function is suffixed with '_old'
657 * @param array $words words that should be stored in dictionary
658 * @param string $lang language
659 */
660 function sqspell_writeWords($words,$lang){
661 global $SQSPELL_CRYPTO,$username,$data_dir;
662
663 $sWords = implode(',',$words);
664 if ($SQSPELL_CRYPTO){
665 /**
666 * User wants to encrypt the file. So be it.
667 * Get the user's password to use as a key.
668 */
669 sqgetGlobalVar('key', $key, SQ_COOKIE);
670 sqgetGlobalVar('onetimepad', $onetimepad, SQ_SESSION);
671
672 $clear_key=OneTimePadDecrypt($key, $onetimepad);
673 /**
674 * Try encrypting it. If fails, scream bloody hell.
675 */
676 $save_words = sqspell_crypto("encrypt", $clear_key, $sWords);
677 if ($save_words == 'PANIC'){
678 // FIXME: handle errors here
679
680 }
681 $save_words='{crypt}'.$save_words;
682 } else {
683 $save_words=$sWords;
684 }
685 setPref($data_dir,$username,'sqspell_dict_'.$lang,$save_words);
686 }
687
688 /**
689 * Writes user dictionary into the $username.words file, then changes mask
690 * to 0600. If encryption is needed -- does that, too.
691 *
692 * @param $words The contents of the ".words" file to write.
693 * @return void
694 * @since 1.5.1 (sqspell 0.5)
695 * @deprecated
696 */
697 function sqspell_writeWords_old($words){
698 global $SQSPELL_WORDS_FILE, $SQSPELL_CRYPTO;
699 /**
700 * if $words is empty, create a template entry by calling the
701 * sqspell_makeDummy() function.
702 */
703 if (!$words){
704 $words=sqspell_makeDummy();
705 }
706 if ($SQSPELL_CRYPTO){
707 /**
708 * User wants to encrypt the file. So be it.
709 * Get the user's password to use as a key.
710 */
711 sqgetGlobalVar('key', $key, SQ_COOKIE);
712 sqgetGlobalVar('onetimepad', $onetimepad, SQ_SESSION);
713
714 $clear_key=OneTimePadDecrypt($key, $onetimepad);
715 /**
716 * Try encrypting it. If fails, scream bloody hell.
717 */
718 $save_words = sqspell_crypto("encrypt", $clear_key, $words);
719 if ($save_words == 'PANIC'){
720 /**
721 * AAAAAAAAH! I'm not handling this yet, since obviously
722 * the admin of the site forgot to compile the MCRYPT support in
723 * when upgrading an existing PHP installation.
724 * I will add a handler for this case later, when I can come up
725 * with some work-around... Right now, do nothing. Let the Admin's
726 * head hurt.. ;)))
727 */
728 /** save some hairs on admin's head and store error message in logs */
729 error_log('SquirrelSpell: php does not have mcrypt support');
730 }
731 } else {
732 $save_words = $words;
733 }
734 /**
735 * Do the actual writing.
736 */
737 $fp=fopen($SQSPELL_WORDS_FILE, "w");
738 fwrite($fp, $save_words);
739 fclose($fp);
740 chmod($SQSPELL_WORDS_FILE, 0600);
741 }
742
743 /**
744 * Deletes user's dictionary
745 * Function was modified in 1.5.1 (sqspell 0.5). Older function is suffixed
746 * with '_old'
747 * @param string $lang dictionary
748 */
749 function sqspell_deleteWords($lang) {
750 global $data_dir, $username;
751 removePref($data_dir,$username,'sqspell_dict_'.$lang);
752 }
753
754 /**
755 * Deletes user's dictionary when it is corrupted.
756 * @since 1.5.1 (sqspell 0.5)
757 * @deprecated
758 */
759 function sqspell_deleteWords_old(){
760 /**
761 * So I open the door to my enemies,
762 * and I ask can we wipe the slate clean,
763 * but they tell me to please go...
764 * uhm... Well, this just erases the user dictionary file.
765 */
766 global $SQSPELL_WORDS_FILE;
767 if (file_exists($SQSPELL_WORDS_FILE)){
768 unlink($SQSPELL_WORDS_FILE);
769 }
770 }
771 /**
772 * Creates an empty user dictionary for the sake of saving prefs or
773 * whatever.
774 *
775 * @return The template to use when storing the user dictionary.
776 * @deprecated
777 */
778 function sqspell_makeDummy(){
779 global $SQSPELL_VERSION, $SQSPELL_APP_DEFAULT;
780 $words = "# SquirrelSpell User Dictionary $SQSPELL_VERSION\n"
781 . "# Last Revision: " . date('Y-m-d')
782 . "\n# LANG: $SQSPELL_APP_DEFAULT\n# End\n";
783 return $words;
784 }
785
786 /**
787 * This function checks for security attacks. A $MOD variable is
788 * provided in the QUERY_STRING and includes one of the files from the
789 * modules directory ($MOD.mod). See if someone is trying to get out
790 * of the modules directory by providing dots, unicode strings, or
791 * slashes.
792 *
793 * @param string $rMOD the name of the module requested to include.
794 * @return void, since it bails out with an access error if needed.
795 */
796 function sqspell_ckMOD($rMOD){
797 if (strstr($rMOD, '.')
798 || strstr($rMOD, '/')
799 || strstr($rMOD, '%')
800 || strstr($rMOD, "\\")){
801 echo _("Invalid URL");
802 exit;
803 }
804 }
805
806 /**
807 * Used to check internal version of SquirrelSpell dictionary
808 * @param integer $major main version number
809 * @param integer $minor second version number
810 * @return boolean true if stored dictionary version is $major.$minor or newer
811 * @since 1.5.1 (sqspell 0.5)
812 */
813 function sqspell_check_version($major,$minor) {
814 global $data_dir, $username;
815 // 0.4 version is internal version number that is used to indicate upgrade from
816 // separate files to generic SquirrelMail prefs storage.
817 $sqspell_version=getPref($data_dir,$username,'sqspell_version','0.4');
818
819 $aVersion=explode('.',$sqspell_version);
820
821 if ($aVersion[0] < $major ||
822 ( $aVersion[0] == $major && $aVersion[1] < $minor)) {
823 return false;
824 }
825 return true;
826 }
827
828 /**
829 * Displays form that allows to enter different password for dictionary decryption.
830 * If language is not set, function provides form to handle older dictionary files.
831 * @param string $lang language
832 * @since 1.5.1 (sqspell 0.5)
833 */
834 function sqspell_handle_crypt_panic($lang=false) {
835 if (! sqgetGlobalVar('SCRIPT_NAME',$SCRIPT_NAME,SQ_SERVER))
836 $SCRIPT_NAME='';
837
838 /**
839 * AAAAAAAAAAAH!!!!! OK, ok, breathe!
840 * Let's hope the decryption failed because the user changed his
841 * password. Bring up the option to key in the old password
842 * or wipe the file and start over if everything else fails.
843 *
844 * The _("SquirrelSpell...) line has to be on one line, otherwise
845 * gettext will bork. ;(
846 */
847 $msg = html_tag( 'p', "\n" .
848 '<strong>' . _("ATTENTION:") . '</strong><br />'
849 . _("SquirrelSpell was unable to decrypt your personal dictionary. This is most likely due to the fact that you have changed your mailbox password. In order to proceed, you will have to supply your old password so that SquirrelSpell can decrypt your personal dictionary. It will be re-encrypted with your new password after this. If you haven't encrypted your dictionary, then it got mangled and is no longer valid. You will have to delete it and start anew. This is also true if you don't remember your old password -- without it, the encrypted data is no longer accessible.") ,
850 'left' ) . "\n"
851 . (($lang) ? html_tag('p',sprintf(_("Your %s dictionary is encrypted with password that differs from your current password."),
852 htmlspecialchars($lang)),'left') : '')
853 . '<blockquote>' . "\n"
854 . '<form method="post" onsubmit="return AYS()">' . "\n"
855 . '<input type="hidden" name="MOD" value="crypto_badkey" />' . "\n"
856 . (($lang) ?
857 '<input type="hidden" name="dict_lang" value="'.htmlspecialchars($lang).'" />' :
858 '<input type="hidden" name="old_setup" value="yes" />')
859 . html_tag( 'p', "\n" .
860 '<input type="checkbox" name="delete_words" value="ON" id="delete_words" />'
861 . '<label for="delete_words">'
862 . _("Delete my dictionary and start a new one")
863 . '</label><br /><label for="old_key">'
864 . _("Decrypt my dictionary with my old password:")
865 . '</label><input type="text" name="old_key" id="old_key" size="10" />' ,
866 'left' ) . "\n"
867 . '</blockquote>' . "\n"
868 . html_tag( 'p', "\n"
869 . '<input type="submit" value="'
870 . _("Proceed") . ' &gt;&gt;" />' ,
871 'center' ) . "\n"
872 . '</form>' . "\n";
873 /**
874 * Add some string vars so they can be i18n'd.
875 */
876 $msg .= "<script type=\"text/javascript\"><!--\n"
877 . "var ui_choice = \"" . _("You must make a choice") ."\";\n"
878 . "var ui_candel = \"" . _("You can either delete your dictionary or type in the old password. Not both.") . "\";\n"
879 . "var ui_willdel = \"" . _("This will delete your personal dictionary file. Proceed?") . "\";\n"
880 . "//--></script>\n";
881 /**
882 * See if this happened in the pop-up window or when accessing
883 * the SpellChecker options page.
884 * This is a dirty solution, I agree.
885 * TODO: make this prettier.
886 */
887 if (strstr($SCRIPT_NAME, "sqspell_options")){
888 sqspell_makePage(_("Error Decrypting Dictionary"),
889 "decrypt_error.js", $msg);
890 } else {
891 sqspell_makeWindow(null, _("Error Decrypting Dictionary"),
892 "decrypt_error.js", $msg);
893 }
894 exit;
895 }
896
897 /**
898 * SquirrelSpell version. Don't modify, since it identifies the format
899 * of the user dictionary files and messing with this can do ugly
900 * stuff. :)
901 * @global string $SQSPELL_VERSION
902 * @deprecated
903 */
904 $SQSPELL_VERSION="v0.3.8";