ScriptReplaceSubstring

From 40tude Dialog Wiki

Replace arbitrary substrings in outgoing newsgroup articles

This script replaces strings in your outgoing articles in defined newsgroups, e.g every instance of »dialog« will be changed to »DIALOG« in the group "news.software.readers".

Install & Setup

Please note that this script is realized as an include-file! To make it work, you have to copy&paste the script into a new custom script (e.g. "INCLUDE_ReplaceSubstring"). The script is configured in the first parts, please adjust it there to fit your needs. Then safe it. Don't compile the custom script! After that, add the following lines to your OnBeforeSending-Script:

{$I INCLUDE_ReplaceSubstring.ds}

and

result := result AND ReplaceSubstringsInNewsgroupArticles(Message, Servername, IsEmail);

It could look like this:

program OnBeforeSendingMessage;

{$I INCLUDE_ReplaceSubstring.ds}

function OnBeforeSendingMessage(var Message: TStringlist; Servername: string; IsEmail: boolean):boolean;
begin
  result:=true;

  //possibly some calls to scripts

  result := result AND ReplaceSubstringsInNewsgroupArticles(Message, Servername, IsEmail);
end;

begin
end.

Now compile this OnBeforeSending-Script to get your include-file to work. Please note that whenever you reconfigure the ReplaceSubstring custom script, you have to recompile the OnBeforeSending-Script to apply the changes.

Code

//----------- ReplaceSubstringsInNewsgroupArticles
//            Version 1 (beta) - Date: 2005/02/26
//            Check the source code or save your data before use.

// Replaces specific strings in your outgoing articles in defined newsgroups
// E.g replaces every instance of "dialog" with "*DIALOG*"

// You can adapt this script to your needs by modifying the three values 
// below the notes. The rules are defined in the middle of the script.

// Ignore the warning when compiling the script.

// Note: This script has a couple of deficits:
// 1) Your text will not be reformatted. That means if you replace
//    text with a much longer or shorter string, you can end up with
//    weird looking text formatting like overly long lines that might
//    provoke mocking comments from other neticens.
//    If you feel the need for a reformatting option in this script,
//    and can't do it yourself, please ask (very nicely) in your 40tude 
//    Dialog newsgroup for help.
// 2) You can provoke even weirder results when the result of pattern #1
//    has the key of pattern #2 as a substring.
//    ( In this case, I'd think the deficit at the user's side though. )
// 3) If you replace with non-ascii characters, unexpected things can happen.
//    That might range from undeclared 8bit characters if the source was
//    us-ascii to wrongly coded non-us-ascii characters if the used
//    character encoding does not match the current Windows encoding.
// 4) Truth be told, I don't speak Object Pascal, so it's very likely
//    that I wrote pretty strange or complicated code.
//    If you notice anything, feel free to correct it.

// ***** --USER-->  You can specify the maximum number of patterns here. 
// ***** --USER-->  If you get an error when sending a message (array out
// ***** --USER-->  of bounds or some such), try to increase this number
// ***** --USER-->  to at least equal the number of replacement rules you
// ***** --USER-->  defined below.
// ***** --USER-->  Leave it as it is for the moment
const RSINA_MAX_REPLACEMENT_PATTERNS = 20;

// ***** --USER-->  Lines starting with any of the characters defined here
// ***** --USER-->  (between the inverted commas) will not be processed. 
const RSINA_QUOTE_CHARACTERS = '|>';

// ***** --USER-->  false: text in the signature will not be processed
// ***** --USER-->  true:  text in the signature *will* be processed
const RSINA_PROCESS_SIG = false;

// ***** --USER-->  Now scroll down about one page to finish the setup of the script


type RSINA_TPatterns = Array [1..RSINA_MAX_REPLACEMENT_PATTERNS] of record 
                        key : string;
                        value : string;
                        newsgroup : string;
                        flags : TReplaceFlags;
                      end;
                                             
//For ease of use in the Init-method, we will keep these two variables global.
var RSINA_Patterns : RSINA_TPatterns;
    RSINA_PatternCount : integer;

procedure RSINA_AddPattern(key, value, newsgroup : string; ignoreCase : boolean );
begin
  RSINA_PatternCount := RSINA_PatternCount + 1;
  
  if ignoreCase then begin
    RSINA_Patterns[RSINA_PatternCount].flags := [rfReplaceAll, rfIgnoreCase];
  end
  else begin
    RSINA_Patterns[RSINA_PatternCount].flags := [rfReplaceAll];
  end;
  RSINA_Patterns[RSINA_PatternCount].key := key;
  RSINA_Patterns[RSINA_PatternCount].value := value;
  RSINA_Patterns[RSINA_PatternCount].newsgroup := newsgroup;
end;


procedure RSINA_Init();
begin

// ***** --USER-->  +-----------------------------------------------------------+
// ***** --USER-->  |           ***** Define your rules *HERE* *****            |
// ***** --USER-->  |                                                           |
// ***** --USER-->  | A call to RSINA_AddPattern defines a replacement rule.    |
// ***** --USER-->  | It takes four paramters (the first three of them have to  |
// ***** --USER-->  | be enclosed in inverted commas):                          |
// ***** --USER-->  |   1) the substring to be replaced                         |
// ***** --USER-->  |   2) the replacement. Use only US-ASCII characters here!  |
// ***** --USER-->  |   3) a string that needs to be part of the newsgroup      |
// ***** --USER-->  |      name for the rule to apply                           |
// ***** --USER-->  |   4) true for 'ignore case'                               |
// ***** --USER-->  |      false for 'match case'                               |

  //make dialog uppercase in news.software.readers
  RSINA_AddPattern('dialog', 'DIALOG', 'news.software.readers', true); 

  //make the goddess, HOSHI, uppercase in all newsgroups with 'startrek' in its name
  RSINA_AddPattern('hoshi', '*HOSHI*', 'startrek', true);
  
// ***** --USER-->  |        ***** Nothing to see below this point *****        |
// ***** --USER-->  +-----------------------------------------------------------+

end;


const RSINA_NEWSGROUP_HEADER = 'Newsgroups: ';

function ReplaceSubstringsInNewsgroupArticles(var Message: TStringlist; Servername: string; IsEmail: boolean):boolean;
var i, j : integer;
    isHeader, isSig : boolean;
    newsgroups : string;
begin
  result:=true; //We cannot fail ;)
  if IsEmail then exit;
  
  //init
  isHeader := true;
  isSig := false;
  RSINA_PatternCount := 0;
  RSINA_Init();
  
  //For all lines of the article
  for i:=0 to Message.count-1 do begin

    //look for the Newsgroups: header
    if isHeader then begin
      if AnsiPos(RSINA_NEWSGROUP_HEADER, message.strings[i])=1 then begin

        newsgroups := Copy(message.strings[i], Length(RSINA_NEWSGROUP_HEADER)+1, Length(message.strings[i])-Length(RSINA_NEWSGROUP_HEADER));

        //it might pay on some older computers to check here whether any further
        //processing is neccesary, based on the newsgroup header.
      end;
    end;
    
    isSig := isSig OR (message.strings[i]='-- ');

    //do the replacing if this is an unquoted body line
    if (Not isHeader) AND ((NOT isSig) OR RSINA_PROCESS_SIG) AND (Length(message.strings[i])>0) then begin
      if AnsiPos(message.strings[i][1], RSINA_QUOTE_CHARACTERS)=0 then begin

        //for all patterns
        for j:=1 to RSINA_PatternCount do begin
          if AnsiPos(RSINA_Patterns[j].newsgroup, newsgroups)>0 then begin
            message.strings[i] := StringReplace( message.strings[i], RSINA_Patterns[j].key, RSINA_Patterns[j].value, RSINA_Patterns[j].flags);
          end;
        end;

      end;
    end;

    isHeader := isHeader AND (message.strings[i]<>'');
    
  end; //for
end;

--Korbinian