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