home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / top2src.zip / CENSOR.C < prev    next >
C/C++ Source or Header  |  2000-07-13  |  14KB  |  348 lines

  1. /******************************************************************************
  2. CENSOR.C     Profanity censor functions.
  3.  
  4.     Copyright 1993 - 2000 Paul J. Sidorsky
  5.  
  6.     This program is free software; you can redistribute it and/or modify
  7.     it under the terms of the GNU General Public License, version 2, as
  8.     published by the Free Software Foundation.
  9.  
  10.     This program is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.     GNU General Public License for more details.
  14.  
  15.     You should have received a copy of the GNU General Public License
  16.     along with this program; if not, write to the Free Software
  17.     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18.  
  19. This module contains the profanity censor.
  20. ******************************************************************************/
  21.  
  22. #include "top.h"
  23.  
  24. /* load_censor_words() - Loads words to censor from CENSOR.CFG.
  25.    Parameters:  None.
  26.    Returns:  TRUE on success, FALSE if an error occurred.
  27. */
  28. char load_censor_words(void)
  29.     {
  30.     FILE *fil; /* CENSOR.CFG file stream. */
  31.     XINT d, count = 0; /* Loop counter, number of words loaded. */
  32.     char loadstr[256]; /* Loading buffer. */
  33.  
  34.     numcensorwords = 0;
  35.  
  36.     /* Open the file. */
  37.     sprintf(outbuf, "%sCENSOR.CFG", cfg.toppath);
  38.     fil = fopen(outbuf, "rt");
  39.     if (fil == NULL)
  40.         {
  41.         return 0;
  42.         }
  43.  
  44.     /* Count the number of non-comment lines in the file to get an
  45.        approximate estimation of the number of words. */
  46.     rewind(fil);
  47.     while(!feof(fil))
  48.         {
  49.         fgets(loadstr, 256, fil);
  50.         if (loadstr[0] != ';')
  51.             {
  52.             count++;
  53.             }
  54.         }
  55.  
  56.     /* Round up to the nearest multiple of three, then divide the counted
  57.        number of lines by three, because there are three lines per word
  58.        definition. */
  59.     count += (count % 3);
  60.     count /= 3;
  61.  
  62.     /* Allocate memory for the counted number of definition. */
  63.     cwords = calloc(count, sizeof(censor_word_typ));
  64.     if (cwords == NULL)
  65.         {
  66.         fclose(fil);
  67.         return 0;
  68.         }
  69.  
  70.     /* Load and process each line. */
  71.     rewind(fil);
  72.     for (d = 0; d < count; d++)
  73.         {
  74.         /* Keep reading until a non-comment line is found. */
  75.         do
  76.             {
  77.             fgets(loadstr, 256, fil);
  78.             }
  79.         while(loadstr[0] == ';');
  80.  
  81.         /* Set the whole-word flag and level.  See CENSOR.CFG comments for
  82.            more information. */
  83.         if (toupper(loadstr[0]) == 'W')
  84.             {
  85.             cwords[d].wholeword = 1;
  86.             cwords[d].level = atoi(&loadstr[1]);
  87.             }
  88.         else
  89.             {
  90.             cwords[d].wholeword = 0;
  91.             cwords[d].level = atoi(loadstr);
  92.             }
  93.  
  94.         /* Load the word to be censored. */
  95.         fgets(loadstr, 256, fil);
  96.         stripcr(loadstr);
  97.         /* All censor text is dynamically allocated to save space. */
  98.         cwords[d].word = malloc(strlen(loadstr) + 1);
  99.         if (cwords[d].word == NULL)
  100.             {
  101.             fclose(fil);
  102.             return 0;
  103.             }
  104.         strcpy(cwords[d].word, loadstr);
  105.  
  106.         /* Load the replacement text, if any. */
  107.         fgets(loadstr, 256, fil);
  108.         stripcr(loadstr);
  109.         cwords[d].changeto = malloc(strlen(loadstr) + 1);
  110.         if (cwords[d].changeto == NULL)
  111.             {
  112.             fclose(fil);
  113.             return 0;
  114.             }
  115.         strcpy(cwords[d].changeto, loadstr);
  116.         }
  117.  
  118.     fclose(fil);
  119.  
  120.     /* Set the global censor word counter. */
  121.     numcensorwords = count;
  122.  
  123.     return 1;
  124.     }
  125.  
  126. /* censorinput() - Censors a string of text.
  127.    Parameters:  str - String containing text to be censored, and buffer to
  128.                       hold the new, possibly modified string.
  129.    Returns:  TRUE if the string should be blocked, FALSE if the string is
  130.              permitted.
  131.    Notes:  Changed text is not considered in the return code.  So long as
  132.            the final string is displayable, even if the censor has changed
  133.            the contents, it will return TRUE.  str must be at least
  134.            MAXSTRLEN+1 characters long.
  135. */
  136. char censorinput(char *str)
  137.     {
  138.     /* Counter, current character, current newstring character, current
  139.        unfiltered string character, word replacement flag. */
  140.     XINT d, p = 0, np = 0, fp = 0, flg;
  141.     /* New string, filtered string. */
  142.     char newstr[512], filtstr[512];
  143.  
  144.     /* The censor uses three strings.  filtstr contains a colour-code
  145.        filtered copy of the string and is used for word detection.  newstr
  146.        contains the new string including colour codes and modified text.
  147.        str is used as the actual source.  The reason the filtered string
  148.        cannot be used is because the colour codes still need to be
  149.        displayed later. */
  150.  
  151.     /* Initialize the strings. */
  152.     filter_string(filtstr, str);
  153.     newstr[0] = '\0';
  154.     
  155.     /* Loop for each character in the filtered string.  The censor tests
  156.        for offensive text beginning at every position in the string. */
  157.     for (p = 0; p < strlen(filtstr); p++)
  158.         {
  159.         /* Loop through known offensive text. */
  160.         for (d = 0, flg = 0; d < numcensorwords; d++)
  161.             {
  162.             /* Only test if this text is not longer than the remainder of
  163.                the string to be tested. */
  164.             if (strlen(&filtstr[p]) >= strlen(cwords[d].word))
  165.                 {
  166.                 /* Look for the text starting at the current position. */
  167.                 if (!strnicmp(&filtstr[p], cwords[d].word,
  168.                               strlen(cwords[d].word)))
  169.                     {
  170.                     if (cwords[d].wholeword)
  171.                         {
  172.                         /* The criteria for a "whole word" is if there is
  173.                            a whitespace character before and after the word.
  174.                            The start and end of the string is considered
  175.                            whitespace. */
  176.                         if (p > 0)
  177.                             {
  178.                             if (isalpha(str[p - 1]))
  179.                                 {
  180.                                 /* An alpha character was found preceding
  181.                                    the text, don't censor. */
  182.                                 continue;
  183.                                 }
  184.                             }
  185.                         if (isalpha(filtstr[p + strlen(cwords[d].word)]))
  186.                             {
  187.                             /* An alpha character was found after the
  188.                                text, don't censor. */
  189.                             continue;
  190.                             }
  191.                         }
  192.  
  193.                     /* If we've gotten to this point, the censor found a
  194.                        match and needs to respond. */
  195.                     switch(cwords[d].level)
  196.                         {
  197.                         /* Level 1:  Immediate disconnection. */
  198.                         case 1:
  199.                             top_output(OUT_SCREEN, getlang("CensorToss1"),
  200.                                        cwords[d].word);
  201. /* od_sleep() uses seconds in OS/2, milliseconds in DOS/Win32. */
  202. #ifdef __OS2__
  203.                             od_sleep(1);
  204. #else
  205.                             od_sleep(1000);
  206. #endif
  207.                             od_exit(10, TRUE);
  208.                             /* This line is never reached but included for
  209.                                completeness. */
  210.                             return 1;
  211.                         /* Level 2 - Warn, toss if applicable, don't allow. */
  212.                         case 2:
  213.                             /* Warn the user. */
  214.                             top_output(OUT_SCREEN, getlang("CensorWarn2"),
  215.                                        cwords[d].word);
  216.                             /* Reset the high warning counter and timer. */
  217.                             censorwarningshigh++;
  218.                             lastcensorwarnhigh = time(NULL);
  219.                             /* Do a warning check, toss if too many. */
  220.                             if (censorwarningshigh >= cfg.maxcensorwarnhigh)
  221.                                 {
  222.                                 top_output(OUT_SCREEN, getlang("CensorToss2"),
  223.                                            cwords[d].word);
  224. #ifdef __OS2__
  225.                                 od_sleep(1);
  226. #else
  227.                                 od_sleep(1000);
  228. #endif
  229.                                 od_exit(10, TRUE);
  230.                                 }
  231.                             /* Block the text. */
  232.                             return 1;
  233.                         /* Level 3 - Warn without tossing, don't allow. */
  234.                         case 3:
  235.                             /* Warn the user. */
  236.                             top_output(OUT_SCREEN, getlang("CensorWarn3"),
  237.                                        cwords[d].word);
  238.                             /* Reset the high warning counter and timer. */
  239.                             censorwarningshigh++;
  240.                             lastcensorwarnhigh = time(NULL);
  241.                             /* Block the text. */
  242.                             return 1;
  243.                         /* Level 4 - Warn, toss if applicable, allow. */
  244.                         case 4:
  245.                             /* Warn the user. */
  246.                             top_output(OUT_SCREEN, getlang("CensorWarn4"),
  247.                                        cwords[d].word);
  248.                             /* Reset the low warning counter and timer. */
  249.                             censorwarningslow++;
  250.                             lastcensorwarnlow = time(NULL);
  251.                             /* Do a warning check, toss if too many. */
  252.                             if (censorwarningslow >= cfg.maxcensorwarnlow)
  253.                                 {
  254.                                 top_output(OUT_SCREEN, getlang("CensorToss4"),
  255.                                            cwords[d].word);
  256. #ifdef __OS2__
  257.                                 od_sleep(1);
  258. #else
  259.                                 od_sleep(1000);
  260. #endif
  261.                                 od_exit(10, TRUE);
  262.                                 }
  263.                             /* The text will still be allowed. */
  264.                             break;
  265.                         /* Warn, don't toss, allow. */
  266.                         case 5:
  267.                             /* Warn the user. */
  268.                             top_output(OUT_SCREEN, getlang("CensorWarn5"),
  269.                                        cwords[d].word);
  270.                             /* Reset the low warning counter and timer. */
  271.                             censorwarningslow++;
  272.                             lastcensorwarnlow = time(NULL);
  273.                             /* The text will still be allowed. */
  274.                             break;
  275.                         }
  276.  
  277.                     /* Change the text if there is replacement text
  278.                        available.  Note that this can occur even if one
  279.                        of the actions above was not taken.  This is
  280.                        known as level 6 of the censor (replace only). */
  281.                     if (cwords[d].changeto[0])
  282.                         {
  283.                         XINT e; /* Word position counter. */
  284.  
  285.                         /* Flag that the text is being replaced. */
  286.                         flg = 1;
  287.                         /* Skip any colour codes that preceed the text to
  288.                            be replaced.  The colour codes are still copied
  289.                            into the new string. */
  290.                         while(str[fp] == '^')
  291.                             {
  292.                             newstr[np++] = str[fp++];
  293.                             newstr[np++] = str[fp++];
  294.                             newstr[np] = '\0';
  295.                             }
  296.                         /* Append the replacement text and reset the
  297.                            newstring pointer. */
  298.                         strcat(newstr, cwords[d].changeto);
  299.                         np = strlen(newstr);
  300.                         /* Advance the copy pointer past the old text.  It
  301.                            is assumed that the new text won't need to be
  302.                            censored. */
  303.                         p += (strlen(cwords[d].word) - 1);
  304.                         /* Advance the unfiltered pointer past the old
  305.                            text. */
  306.                         for (e = 0; e < strlen(cwords[d].word); e++)
  307.                             {
  308.                             fp++;
  309.                             }
  310.                         /* Notify the user of the replacement. */
  311.                         top_output(OUT_SCREEN, getlang("CensorReplace"));
  312.                         /* Break out of the word-check loop to begin
  313.                            testing the next position. */
  314.                         break;
  315.                         }
  316.                     }
  317.                 }
  318.             }
  319.  
  320.         /* Only copy the text if the text replacer didn't do it above. */
  321.         if (!flg)
  322.             {
  323.             /* Skip any colour codes that preceed the text to
  324.                be replaced.  The colour codes are still copied
  325.                into the new string. */
  326.             while(str[fp] == '^')
  327.                 {
  328.                 newstr[np++] = str[fp++];
  329.                 newstr[np++] = str[fp++];
  330.                 newstr[np] = '\0';
  331.                 }
  332.             /* Copy this character into the new string. */
  333.             newstr[np++] = str[fp++];
  334.             newstr[np] = '\0';
  335.             }
  336.         }
  337.  
  338.     /* Copy the new string to the original buffer.  The string is truncated
  339.        if it is longer than MAXSTRLEN because TOP's message routines can't
  340.        handle larger strings. */
  341.     memset(str, 0, MAXSTRLEN + 1);
  342.     strncpy(str, newstr, MAXSTRLEN);
  343.  
  344.     /* The string was permitted. */
  345.     return 0;
  346.     }
  347.  
  348.