Source for file sqspell_functions.php

Documentation is available at sqspell_functions.php

  1. <?php
  2. /**
  3.  * sqspell_functions.php
  4.  * ----------------------
  5.  * All SquirrelSpell-wide functions are in this file.
  6.  *
  7.  * Copyright (c) 1999-2018 The SquirrelMail Project Team
  8.  * Licensed under the GNU GPL. For full terms see the file COPYING.
  9.  *
  10.  * @author Konstantin Riabitsev <icon@duke.edu>
  11.  * @version $Id: sqspell_functions.php 14749 2018-01-16 23:36:07Z pdontthink $
  12.  * @package plugins
  13.  * @subpackage squirrelspell
  14.  */
  15.  
  16. /**
  17.  * This function is the GUI wrapper for the options page. SquirrelSpell
  18.  * uses it for creating all Options pages.
  19.  *
  20.  * @param  string $title     The title of the page to display
  21.  * @param  string $scriptsrc This is used to link a file.js into the
  22.  *                     <script src="file.js"></script> format. This
  23.  *                     allows to separate javascript from the rest of the
  24.  *                     plugin and place it into the js/ directory.
  25.  * @param  string $body      The body of the message to display.
  26.  * @return            void 
  27.  */
  28. function sqspell_makePage($title$scriptsrc$body){
  29.   global $color$SQSPELL_VERSION;
  30.  
  31.   if (sqgetGlobalVar('MOD'$MODSQ_GET) ) {
  32.       $MOD 'options_main';
  33.   }
  34.  
  35.   displayPageHeader($color'None');
  36.   echo "&nbsp;<br />\n";
  37.   /**
  38.    * Check if we need to link in a script.
  39.    */
  40.   if($scriptsrc{
  41.     echo "<script type=\"text/javascript\" src=\"js/$scriptsrc\"></script>\n";
  42.   }
  43.   echo html_tag'table''''center''''width="95%" border="0" cellpadding="2" cellspacing="0"' "\n"
  44.     . html_tag'tr'"\n" .
  45.           html_tag'td''<strong>' $title .'</strong>''center'$color[9)
  46.       "\n"
  47.     . html_tag'tr'"\n" .
  48.           html_tag'td''<hr />''left' )
  49.       "\n"
  50.     . html_tag'tr'"\n" .
  51.           html_tag'td'$body'left' )
  52.       "\n";
  53.   /**
  54.    * Generate a nice "Return to Options" link, unless this is the
  55.    * starting page.
  56.    */
  57.   if ($MOD != "options_main"){
  58.     // this is a hack to avoid having to change the strings
  59.     // in all our translations for this misspelled word
  60.     global $squirrelmail_language;
  61.     if (strpos($squirrelmail_language'en_'=== 0)
  62.         $text 'Back to &quot;Spell Checker Options&quot; page';
  63.     else
  64.         $text _("Back to &quot;SpellChecker Options&quot; page");
  65.     echo html_tag'tr'"\n" .
  66.                 html_tag'td''<hr />''left' )
  67.             "\n"
  68.       . html_tag'tr'"\n" .
  69.             html_tag'td''<a href="sqspell_options.php">'
  70.                 . $text
  71.                 . '</a>',
  72.             'center' )
  73.         "\n";
  74.   }
  75.   /**
  76.    * Close the table and display the version.
  77.    */
  78.   echo html_tag'tr'"\n" .
  79.               html_tag'td''<hr />''left' )
  80.           "\n"
  81.     . html_tag'tr',
  82.           html_tag'td''SquirrelSpell ' $SQSPELL_VERSION'center'$color[9)
  83.       "\n</table>\n";
  84.   echo '</body></html>';
  85. }
  86.  
  87. /**
  88.  * Function similar to the one above. This one is a general wrapper
  89.  * for the Squirrelspell pop-up window. It's called form nearly
  90.  * everywhere, except the check_me module, since that one is highly
  91.  * customized.
  92.  *
  93.  * @param  string $onload    Used to indicate and pass the name of a js function
  94.  *                     to call in a <body onload="function()" for automatic
  95.  *                     onload script execution.
  96.  * @param  string $title     Title of the page.
  97.  * @param  string $scriptsrc If defined, link this javascript source page into
  98.  *                     the document using <script src="file.js"> format.
  99.  * @param  string $body      The content to include.
  100.  * @return            void 
  101.  */
  102. function sqspell_makeWindow($onload$title$scriptsrc$body){
  103.   global $color$SQSPELL_VERSION;
  104.  
  105.   displayHtmlHeader($title,
  106.       ($scriptsrc "\n<script type=\"text/javascript\" src=\"js/$scriptsrc\"></script>\n''));
  107.  
  108.   echo "<body text=\"$color[8]\" bgcolor=\"$color[4]\" link=\"$color[7]\" "
  109.       . "vlink=\"$color[7]\" alink=\"$color[7]\"";
  110.   /**
  111.    * Provide an onload="jsfunction()" if asked to.
  112.    */
  113.   if ($onload{
  114.       echo " onload=\"$onload\"";
  115.   }
  116.   /**
  117.    * Draw the rest of the page.
  118.    */
  119.   echo ">\n"
  120.     . html_tag'table'"\n" .
  121.           html_tag'tr'"\n" .
  122.               html_tag'td''<strong>' $title '</strong>''center'$color[9)
  123.           "\n" .
  124.           html_tag'tr'"\n" .
  125.               html_tag'td''<hr />''left' )
  126.           "\n" .
  127.           html_tag'tr'"\n" .
  128.               html_tag'td'$body'left' )
  129.           "\n" .
  130.           html_tag'tr'"\n" .
  131.               html_tag'td''<hr />''left' )
  132.           "\n" .
  133.           html_tag'tr'"\n" .
  134.               html_tag'td''SquirrelSpell ' $SQSPELL_VERSION'center'$color[9)
  135.           ,
  136.       '''''width="100%" border="0" cellpadding="2"' )
  137.     . "</body>\n</html>\n";
  138. }
  139.  
  140. /**
  141.  * This function does the encryption and decryption of the user
  142.  * dictionary. It is only available when PHP is compiled with
  143.  * mcrypt support (--with-mcrypt). See doc/CRYPTO for more
  144.  * information.
  145.  *
  146.  * @param  $mode  A string with either of the two recognized values:
  147.  *                 "encrypt" or "decrypt".
  148.  * @param  $ckey  The key to use for processing (the user's password
  149.  *                 in our case.
  150.  * @param  $input Content to decrypt or encrypt, according to $mode.
  151.  * @return        encrypted/decrypted content, or "PANIC" if the
  152.  *                 process bails out.
  153.  */
  154. function sqspell_crypto($mode$ckey$input){
  155.   /**
  156.    * Double-check if we have the mcrypt_generic function. Bail out if
  157.    * not so.
  158.    */
  159.   if (!function_exists('mcrypt_generic')) {
  160.     return 'PANIC';
  161.   }
  162.   /**
  163.    * Setup mcrypt routines.
  164.    */
  165.   $td mcrypt_module_open(MCRYPT_Blowfish""MCRYPT_MODE_ECB"");
  166.   $iv mcrypt_create_iv(mcrypt_enc_get_iv_size ($td)MCRYPT_RAND);
  167.   mcrypt_generic_init($td$ckey$iv);
  168.   /**
  169.    * See what we have to do depending on $mode.
  170.    * 'encrypt' -- Encrypt the content.
  171.    * 'decrypt' -- Decrypt the content.
  172.    */
  173.   switch ($mode){
  174.   case 'encrypt':
  175.     $crypto mcrypt_generic($td$input);
  176.     break;
  177.   case 'decrypt':
  178.     $crypto mdecrypt_generic($td$input);
  179.     /**
  180.      * See if it decrypted successfully. If so, it should contain
  181.      * the string "# SquirrelSpell". If not, then bail out.
  182.      */
  183.     if (!strstr($crypto"# SquirrelSpell")){
  184.       $crypto='PANIC';
  185.     }
  186.     break;
  187.   }
  188.   /**
  189.    * Finish up the mcrypt routines and return the processed content.
  190.    */
  191.   mcrypt_generic_deinit ($td);
  192.   mcrypt_module_close ($td);
  193.   return $crypto;
  194. }
  195.  
  196. /**
  197.  * This function transparently upgrades the 0.2 dictionary format to the
  198.  * 0.3 format, since user-defined languages have been added in 0.3 and
  199.  * the new format keeps user dictionaries selection in the file.
  200.  *
  201.  * This function will be retired soon, as it's been a while since anyone
  202.  * has been using SquirrelSpell-0.2.
  203.  *
  204.  * @param  $words_string Contents of the 0.2-style user dictionary.
  205.  * @return               Contents of the 0.3-style user dictionary.
  206.  */
  207. function sqspell_upgradeWordsFile($words_string){
  208.   global $SQSPELL_APP_DEFAULT$SQSPELL_VERSION;
  209.   /**
  210.    * Define just one dictionary for this user -- the default.
  211.    * If the user wants more, s/he can set them up in personal
  212.    * preferences. See doc/UPGRADING for more info.
  213.    */
  214.   $new_words_string =
  215.      substr_replace($words_string,
  216.                     "# SquirrelSpell User Dictionary $SQSPELL_VERSION\n# "
  217.                     . "Last Revision: " date("Y-m-d")
  218.                     . "\n# LANG: $SQSPELL_APP_DEFAULT\n# $SQSPELL_APP_DEFAULT",
  219.                     0strpos($words_string"\n")) "# End\n";
  220.   sqspell_writeWords($new_words_string);
  221.   return $new_words_string;
  222. }
  223.  
  224. /**
  225.  * Right now it just returns an array with the dictionaries
  226.  * available to the user for spell-checking. It will probably
  227.  * do more in the future, as features are added.
  228.  *
  229.  * @param string $words The contents of the user's ".words" file.
  230.  * @return array a strings array with dictionaries available
  231.  *                 to this user, e.g. {"English", "Spanish"}, etc.
  232.  */
  233. function sqspell_getSettings($words){
  234.   global $SQSPELL_APP$SQSPELL_APP_DEFAULT;
  235.   /**
  236.    * Check if there is more than one dictionary configured in the
  237.    * system config.
  238.    */
  239.   if (sizeof($SQSPELL_APP1){
  240.     /**
  241.      * Now load the user prefs. Check if $words was empty -- a bit of
  242.      * a dirty fall-back. TODO: make it so this is not required.
  243.      */
  244.     if(!$words){
  245.       $words=sqspell_getWords();
  246.     }
  247.     if ($words){
  248.       /**
  249.        * This user has a ".words" file.
  250.        * Find which dictionaries s/he wants to use and load them into
  251.        * the $langs array.
  252.        */
  253.       preg_match("/# LANG: (.*)/i"$words$matches);
  254.       $langs=explode(", "$matches[1]);
  255.     else {
  256.       /**
  257.        * User doesn't have a personal dictionary. Grab the default
  258.        * system setting.
  259.        */
  260.       $langs[0]=$SQSPELL_APP_DEFAULT;
  261.     }
  262.   else {
  263.     /**
  264.      * There is no need to read the ".words" file as there is only one
  265.      * dictionary defined system-wide.
  266.      */
  267.     $langs[0]=$SQSPELL_APP_DEFAULT;
  268.   }
  269.   return $langs;
  270. }
  271.  
  272. /**
  273.  * This function returns only user-defined dictionary words that correspond
  274.  * to the requested language.
  275.  *
  276.  * @param  $words The contents of the user's ".words" file.
  277.  * @param  $lang  Which language words to return, e.g. requesting
  278.  *                 "English" will return ONLY the words from user's
  279.  *                 English dictionary, disregarding any others.
  280.  * @return        The list of words corresponding to the language
  281.  *                 requested.
  282.  */
  283. function sqspell_getLang($words$lang){
  284.   $start=strpos($words"$lang\n");
  285.   /**
  286.    * strpos() will return -1 if no # $lang\n string was found.
  287.    * Use this to return a zero-length value and indicate that no
  288.    * words are present in the requested dictionary.
  289.    */
  290.   if (!$startreturn '';
  291.   /**
  292.    * The words list will end with a new directive, which will start
  293.    * with "#". Locate the next "#" and thus find out where the
  294.    * words end.
  295.    */
  296.   $end=strpos($words"#"$start+1);
  297.   $lang_words substr($words$start$end-$start);
  298.   return $lang_words;
  299. }
  300.  
  301. /**
  302.  * This function operates the user dictionary. If the format is
  303.  * clear-text, then it just reads the file and returns it. However, if
  304.  * the file is encrypted (well, "garbled"), then it tries to decrypt
  305.  * it, checks whether the decryption was successful, troubleshoots if
  306.  * not, then returns the clear-text dictionary to the app.
  307.  *
  308.  * @return the contents of the user's ".words" file, decrypted if
  309.  *          necessary.
  310.  */
  311. function sqspell_getWords(){
  312.   global $SQSPELL_WORDS_FILE$SQSPELL_CRYPTO;
  313.   $words="";
  314.   if (file_exists($SQSPELL_WORDS_FILE)){
  315.     /**
  316.      * Gobble it up.
  317.      */
  318.     $fp=fopen($SQSPELL_WORDS_FILE'r');
  319.     $words=fread($fpfilesize($SQSPELL_WORDS_FILE));
  320.     fclose($fp);
  321.   }
  322.   /**
  323.    * Check if this is an encrypted file by looking for
  324.    * the string "# SquirrelSpell" in it (the crypto
  325.    * function does that).
  326.    */
  327.   if ($words && !strstr($words"# SquirrelSpell")){
  328.     /**
  329.      * This file is encrypted or mangled. Try to decrypt it.
  330.      * If fails, complain loudly.
  331.      *
  332.      * $old_key would be a value submitted by one of the modules with
  333.      * the user's old mailbox password. I admin, this is rather dirty,
  334.      * but efficient. ;)
  335.      */
  336.     sqgetGlobalVar('key'$keySQ_COOKIE);
  337.     sqgetGlobalVar('onetimepad'$onetimepadSQ_SESSION);
  338.  
  339.     sqgetGlobalVar('old_key'$old_keySQ_POST);
  340.  
  341.     if ($old_key != ''{
  342.         $clear_key=$old_key;
  343.     else {
  344.       /**
  345.        * Get user's password (the key).
  346.        */
  347.       $clear_key OneTimePadDecrypt($key$onetimepad);
  348.     }
  349.     /**
  350.      * Invoke the decryption routines.
  351.      */
  352.     $words=sqspell_crypto("decrypt"$clear_key$words);
  353.     /**
  354.      * See if decryption failed.
  355.      */
  356.     if ($words=="PANIC"){
  357.       /**
  358.        * AAAAAAAAAAAH!!!!! OK, ok, breathe!
  359.        * Let's hope the decryption failed because the user changed his
  360.        * password. Bring up the option to key in the old password
  361.        * or wipe the file and start over if everything else fails.
  362.        *
  363.        * The _("SquirrelSpell...) line has to be on one line, otherwise
  364.        * gettext will bork. ;(
  365.        */
  366.       $msg html_tag'p'"\n" .
  367.                      '<strong>' _("ATTENTION:"'</strong><br />'
  368.                      .  _("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.",
  369.                  'left' .  "\n"
  370.      . '<blockquote>' "\n"
  371.      . '<form method="post" onsubmit="return AYS()">' "\n"
  372.      . '<input type="hidden" name="MOD" value="crypto_badkey">' "\n"
  373.      . html_tag'p',  "\n" .
  374.            '<input type="checkbox" name="delete_words" value="ON">'
  375.            . _("Delete my dictionary and start a new one"'<br />'
  376.            . _("Decrypt my dictionary with my old password:")
  377.            . '<input name="old_key" size=\"10\">' ,
  378.        'left' "\n"
  379.      . '</blockquote>' "\n"
  380.      . html_tag'p'"\n" .
  381.            '<input type="submit" value="'
  382.            . _("Proceed"' &gt;&gt;">' ,
  383.        'center' "\n"
  384.      . '</form>' "\n";
  385.       /**
  386.        * Add some string vars so they can be i18n'd.
  387.        */
  388.       $msg .= "<script type='text/javascript'><!--\n"
  389.      . "var ui_choice = \"" _("You must make a choice"."\";\n"
  390.      . "var ui_candel = \"" _("You can either delete your dictionary or type in the old password. Not both.""\";\n"
  391.      . "var ui_willdel = \"" _("This will delete your personal dictionary file. Proceed?""\";\n"
  392.      . "//--></script>\n";
  393.       /**
  394.        * See if this happened in the pop-up window or when accessing
  395.        * the SpellChecker options page.
  396.        * This is a dirty solution, I agree. TODO: make this prettier.
  397.        */
  398.       global $SCRIPT_NAME;
  399.       if (strstr($SCRIPT_NAME"sqspell_options")){
  400.     sqspell_makePage(_("Error Decrypting Dictionary"),
  401.               "decrypt_error.js"$msg);
  402.       else {
  403.     sqspell_makeWindow(null_("Error Decrypting Dictionary"),
  404.                "decrypt_error.js"$msg);
  405.       }
  406.       exit;
  407.     else {
  408.       /**
  409.        * OK! Phew. Set the encryption flag to true so we can later on
  410.        * encrypt it again before saving to HDD.
  411.        */
  412.       $SQSPELL_CRYPTO=true;
  413.     }
  414.   else {
  415.     /**
  416.      * No encryption is/was used. Set $SQSPELL_CRYPTO to false,
  417.      * in case we have to save the dictionary later.
  418.      */
  419.     $SQSPELL_CRYPTO=false;
  420.   }
  421.   /**
  422.    * Check if we need to upgrade the dictionary from version 0.2.x
  423.    * This is going away soon.
  424.    */
  425.   if (strstr($words"Dictionary v0.2")){
  426.     $words=sqspell_upgradeWordsFile($words);
  427.   }
  428.   return $words;
  429. }
  430.  
  431. /**
  432.  * Writes user dictionary into the $username.words file, then changes mask
  433.  * to 0600. If encryption is needed -- does that, too.
  434.  *
  435.  * @param  $words The contents of the ".words" file to write.
  436.  * @return        void 
  437.  */
  438. function sqspell_writeWords($words){
  439.   global $SQSPELL_WORDS_FILE$SQSPELL_CRYPTO;
  440.   /**
  441.    * if $words is empty, create a template entry by calling the
  442.    * sqspell_makeDummy() function.
  443.    */
  444.   if (!$words){
  445.     $words=sqspell_makeDummy();
  446.   }
  447.   if ($SQSPELL_CRYPTO){
  448.     /**
  449.      * User wants to encrypt the file. So be it.
  450.      * Get the user's password to use as a key.
  451.      */
  452.     sqgetGlobalVar('key'$keySQ_COOKIE);
  453.     sqgetGlobalVar('onetimepad'$onetimepadSQ_SESSION);
  454.  
  455.     $clear_key=OneTimePadDecrypt($key$onetimepad);
  456.     /**
  457.      * Try encrypting it. If fails, scream bloody hell.
  458.      */
  459.     $save_words sqspell_crypto("encrypt"$clear_key$words);
  460.     if ($save_words == 'PANIC'){
  461.       /**
  462.        * AAAAAAAAH! I'm not handling this yet, since obviously
  463.        * the admin of the site forgot to compile the MCRYPT support in
  464.        * when upgrading an existing PHP installation.
  465.        * I will add a handler for this case later, when I can come up
  466.        * with some work-around... Right now, do nothing. Let the Admin's
  467.        * head hurt.. ;)))
  468.        */
  469.     }
  470.   else {
  471.     $save_words $words;
  472.   }
  473.   /**
  474.    * Do the actual writing.
  475.    */
  476.   $fp=fopen($SQSPELL_WORDS_FILE"w");
  477.   fwrite($fp$save_words);
  478.   fclose($fp);
  479.   chmod($SQSPELL_WORDS_FILE0600);
  480. }
  481.  
  482. function sqspell_deleteWords(){
  483.   /**
  484.    * So I open the door to my enemies,
  485.    * and I ask can we wipe the slate clean,
  486.    * but they tell me to please go...
  487.    * uhm... Well, this just erases the user dictionary file.
  488.    */
  489.   global $SQSPELL_WORDS_FILE;
  490.   if (file_exists($SQSPELL_WORDS_FILE)){
  491.     unlink($SQSPELL_WORDS_FILE);
  492.   }
  493. }
  494. /**
  495.  * Creates an empty user dictionary for the sake of saving prefs or
  496.  * whatever.
  497.  *
  498.  * @return The template to use when storing the user dictionary.
  499.  */
  500. function sqspell_makeDummy(){
  501.   global $SQSPELL_VERSION$SQSPELL_APP_DEFAULT;
  502.   $words "# SquirrelSpell User Dictionary $SQSPELL_VERSION\n"
  503.      . "# Last Revision: " date('Y-m-d')
  504.      . "\n# LANG: $SQSPELL_APP_DEFAULT\n# End\n";
  505.   return $words;
  506. }
  507.  
  508. /**
  509.  * This function checks for security attacks. A $MOD variable is
  510.  * provided in the QUERY_STRING and includes one of the files from the
  511.  * modules directory ($MOD.mod). See if someone is trying to get out
  512.  * of the modules directory by providing dots, unicode strings, or
  513.  * slashes.
  514.  *
  515.  * @param  string $rMOD the name of the module requested to include.
  516.  * @return void, since it bails out with an access error if needed.
  517.  */
  518. function sqspell_ckMOD($rMOD){
  519.   if (strstr($rMOD'.')
  520.       || strstr($rMOD'/')
  521.       || strstr($rMOD'%')
  522.       || strstr($rMOD"\\")){
  523.     echo _("Invalid URL");
  524.     exit;
  525.   }
  526. }
  527.  
  528. /**
  529.  * SquirrelSpell version. Don't modify, since it identifies the format
  530.  * of the user dictionary files and messing with this can do ugly
  531.  * stuff. :)
  532.  */
  533. $SQSPELL_VERSION="v0.3.8";

Documentation generated on Tue, 17 Apr 2018 04:26:59 +0200 by phpDocumentor 1.4.3