BrowsersURLsShortcutsSandboxie: Open URLs and shortcuts in Sandboxie

Overview:
This JScript add-in creates five new DOpus commands to handle five related tasks. They deal with extracting URLs from a piece of text, creating *.url shortcut files from them, choosing and launching a browser that opens these URLs, and dealing with Sandboxie and multiple sandboxes. The Sandboxie options can be turned off, and do not appear if Sandboxie is not installed.

1. LaunchBrowser is a simple function to choose a browser and launch it either within a chosen sandbox or outside Sandboxie.

2. OpenURLsInClip extracts possible URLs from within a text clip, without redundancy. The user can then edit or save the list of URLs, or open a chosen browser inside a chosen sandbox or outside Sandboxie. For example, if a webpage has a number of URLs as hyperlinks, then copying the page source into the clipboard and running OpenURLsInClip will provide a list of all the URLs and the choice of opening them.

3. URLShortcutsFromClip begins the same way by extracting clips from text and offering the option to view or edit the list. Then each URL may or may not be saved to a *.url shortcut file, possibly in a sequence. Individual icons, or a default icon, can be provided for each shortcut file. An earlier version of this command is at Button-script to create a .url file with icon from URL in clipboard.

4. OpenURLShortcuts opens *.url shortcut files with a chosen browser in a chosen sandbox.

5. ViewClip views "text" clips with the DOPus standalone viewer, views "files" clips with any CSV viewer, and attempts to open any other clip as a *.jpg file in the DOpus viewer.

Installation:
Download the add-in below. Then go to Preferences - - > Toolbars - - > Scripts. Then drag the file into the list of add-in scripts.

The five commands mentioned above will now be available. But they need to be added as five separate buttons within the DOpus toolbars. They have no parameters.

Configuration:
You will need to configure the add-in by telling it your browsers, your Sandboxie sandboxes (optional), your preferred text editor and CSV viewer, and your favicon directory. Go to Preferences - - > Toolbars - - > Scripts, select this script BrowsersURLsShortcutsSandboxie, and click configure. There are many options, and each displays a short note below when highlighted.

  • Any number of browsers may be entered, together with an alias or command for each, although the script will need some simple editing at the beginning if any more than four are required. Aliases such as Firefox and IExplore, if they exist, are simpler than full paths to .exe or .lnk files. The command for the Edge Browser is still unclear.
  • Any number of sandboxes may be used (edit for more than four), or the Sandboxie options may be turned off.
  • Any text editor and any CSV viewer may be used, including most obviously Excel. Nirsoft has a simple CSV viewer at http://www.nirsoft.net/utils/csv_file_view.html.
  • The configuration assumes that favicons for *.url files will all be in the same directory, and asks for a default favicon.

Thanks very much to tbone for all sorts of help and advice, and particulary for the configuration helper at Helper: ConfigHelper (easier config item handling). Similar thanks to leo and jon for their encouragement and help.

Download:
Version 1.0, Julianon 17/09/15
BrowsersURLsShortcutsSandboxie.js.txt (90.8 KB)

Script Code:
This is the same as the download, so you can see how it works without downloading it:

// BrowsersURLsShortcutsSandboxie
// (C) 2015 JulianON
// V1.0 17/09/15
// MD5 at end of file
// This is a script for Directory Opus.
// See http://www.gpsoft.com.au/DScripts/redirect.asp?page=scripts for development information. 
 
// *********************************************************
function OnInit (data) {
  //uid added via script wizard (do not change after publishing this script)
  var uid = "D8488485-519B-4EE3-9624-1052E2172B32" // Created new GUID 15/09/15
  //resource center url added via script wizard (required for updating)
  // var url = 
  data.name = "BrowsersURLsShortcutsSandboxie";
  data.desc = "Five commands to handle browsers, Sandboxie, URL shortcuts and clips.                LaunchBrowser: Opens a chosen browser with or without Sandboxie.                    OpenURLsInClip: Extracts URLs from a text clip, and opens them in a browser or edits them.        URLShortcutsFromClip: Extracts URLs from a text clip, and creats shortcut *.url files.        OpenURLSchorcuts: Extracts URLS from text clip and opens them in a chosen browser.        ViewClip: Views text clips and files clips, an attempts to view any other clip as a *.jpg file." ;
  data.copyright = "(C) 2015 JulianON";
  data.version = "1.0";
  data.default_enable = true;
  
  // Create a new ScriptCommand object and initialize it to add the command to Opus
  var cmd = data.AddCommand ();
  cmd.name = "LaunchBrowser";
  cmd.method = "OnLaunchBrowser";
  cmd.desc = data.desc;
  cmd.label = "Choose and Launch Browser, with or wothout Sandboxie.";
  //  cmd.template = "NUMBER/N,FROM/K/N,NODESELECT/S";
  
  var cmd = data.AddCommand ();
  cmd.name = "OpenURLsInClip";
  cmd.method = "OnOpenURLsInClip";
  cmd.desc = data.desc;
  cmd.label = "Extract URLs from a text clip and open them in a browser.";
  //  cmd.template = "NUMBER/N,FROM/K/N,NODESELECT/S";
  
  var cmd = data.AddCommand ();
  cmd.name = "OpenURLShortcuts";
  cmd.method = "OnOpenURLShortcuts";
  cmd.desc = data.desc;
  cmd.label = "Open selected URL shortcut files in a chosen browser, with or without Sandboxie.";
  //  cmd.template = "NUMBER/N,FROM/K/N,NODESELECT/S";
  
  var cmd = data.AddCommand ();
  cmd.name = "URLShortcutsFromClip";
  cmd.method = "OnURLShortcutsFromClip";
  cmd.desc = data.desc;
  cmd.label = "Extract URLs from a text clip and create shortcuts.";
  //  cmd.template = "NUMBER/N,FROM/K/N,NODESELECT/S";

  var cmd = data.AddCommand ();
  cmd.name = "ViewClip";
  cmd.method = "OnViewClip";
  cmd.desc = data.desc;
  cmd.label = "Extract URLs from a text clip and create shortcuts.";
  //  cmd.template = "NUMBER/N,FROM/K/N,NODESELECT/S";

// *********************************************************
function ConfigHelper (data){ //v1.2 Copied and adapted from tbone's demonstrator script addin http://resource.dopus.com/viewtopic.php?f=35&t=22979
  var t=this; t.d=data; t.c=data.config; t.cd=DOpus.Create.Map();
  t.add=function(name, val, des){ t.l={n:name,ln:name.
    toLowerCase()}; return t.val(val).des(des);}
  t.des=function(des){ if (!des) return t; if (t.cd.empty)
    t.d.config_desc=t.cd; t.cd(t.l.n)=des; return t;}
  t.val=function(val){ var l=t.l; if (l.v!==l.x&&typeof l.v=="object")
    l.v.push_back(val);else l.v=t.c[l.n]=val;return t;}
  t.trn=function(){return t.des(t("script.config."+t.l.ln));}}

  var cfg = new ConfigHelper(data);

  cfg.add ("BROWSER - - - - - - - - - - - -", "", "Choose the browsers to be displayed as options.");
  cfg.add ("Browser 1", "&Firefox", "Leave blank or precede the name by ~ if not needed.\r\nAvoid 'A' and 'C' as accelerator key (or edit the script).");
  cfg.add ("Browser 1 command", "Firefox", "Use an alias, or give the full path.");
  cfg.add ("Browser 2", "&Internet Explorer", "Leave blank or precede the name by ~ if not needed.\r\nAvoid 'A' and 'C' as accelerator key (or edit the script).");
  cfg.add ("Browser 2 command", "IExplore", "Use an alias, or give the full path.");
  cfg.add ("Browser 3", "Chro&me", "Leave blank or precede the name by ~ if not needed.\r\nAvoid 'A' and 'C' as accelerator key (or edit the script).");
  cfg.add ("Browser 3 command", "Chrome", "Use an alias, or give the full path.");
  cfg.add ("Browser 4", "Ed&ge", "Leave blank or precede the name by ~ if not needed.\r\nAvoid 'A', 'E' and 'C' as accelerator key (or edit the script).");
  cfg.add ("Browser 4 command", "<Unknown>", "The command for the Windows 10 Edge browser is still unclear.\r\nFurther browsers may be added by editing the script file.");
  cfg.add ("CSV - - - - - - - - - - - - - - - - -", "", 'Required by "ViewClip" for viewing a "files" clip.  Nirsoft has a *.csv viewer at\r\nhttp://www.nirsoft.net/utils/csv_file_view.html');
  cfg.add ("CSV command", "%@Data%\\DataForVallaHome\\WebSave\\Programs\\NirSoft\\NirSoft\\csvfileview.exe", 'Give an alias or a command.  Omit for default, which is probably Excel.\r\nThe obvious choices for the command are the alias "Excel" or a text editor.');
  cfg.add ("FAVICON BANK - - - - - - - - -", "", 'Favicons associated with each URL shortcut should be stored in this directory.\r\nThis is required only by the command "URLShortcutsFromClip".');
  cfg.add ("Favicon directory", "%@Data%\\DataForVallaHome\\WebSave\\Favicons\\", "Choose the directory where favicons are stored.");
  cfg.add ("Favicon name default", "Internet", "Choose the name of the default favicon, without extension.\r\nThis should be an *.ico file in the default favicon directory.");
  cfg.add ("FILE EDITOR - - - - - - - - - - -", "", 'Choose the editor to be used if editing is required.  The DOpus standalone viewer can be launched with "Show", but no editing is then possible.');
  cfg.add ("File editor choice", "UEStudio", "Enter an alias or the full path, or leave blank to use the system alias.\r\nSome common editor aliases are: Notepad, Notepad++, UltraEdit.");
  cfg.add ("SANDBOXIE - - - - - - - - - - -", "", "Is Sandboxie installed, and what sandboxes have been created?");
  cfg.add ("Sandboxie options shown", true, "This only activates Sandboxie options if Sandboxie is actually installed.\r\nMore precisely, the file 'C:\\Program Files\\Sandboxie\\Start.exe' must exist.");
  cfg.add ("Sandboxie Sandbox 1", "De&FaultBox", "Sandboxie requires the Default sandbox, the others are arbitrary.\r\nAvoid 'A', 'N' or 'C' as accelerator keys (or edit the script).");
  cfg.add ("Sandboxie Sandbox 2", "&BodgieBox", "Leave blank or precede the name by ~ if not needed.\r\nAvoid 'A', 'N' or 'C' as accelerator keys (or edit the script).");
  cfg.add ("Sandboxie Sandbox 3", "&OrderBox", "Leave blank or precede the name by ~ if not needed.\r\nAvoid 'A', 'N' or 'C' as accelerator keys (or edit the script).");
  cfg.add ("Sandboxie Sandbox 4", "&TrueBox", "Leave blank or precede the name by ~ if not needed.  Avoid 'A', 'N' or 'C' as accelerator keys.  Edit the script to add more sandboxes");
}

// *********************************************************
function OnAboutScript (data){ 
  var cmd = DOpus.Create.Command ();
  if (!cmd.Commandlist ('s').exists ("ScriptWizard")) {
    if (DOpus.Dlg.Request ("The 'ScriptWizard' add-in has not been found.\n\n"+
"Install 'ScriptWizard' from [resource.dopus.com].\nThe add-in enables this dialog and also offers "+
"easy updating of scripts and many more.","Yes, take me there!|Cancel", "No About.. ", data.window))
    cmd.RunCommand ('http://resource.dopus.com/viewtopic.php?f=35&t=23179');}
  else
    cmd.RunCommand ('ScriptWizard ABOUT WIN='+data.window+' FILE="'+Script.File+'"');
}

// *********************************************************
function DoCfg (scriptCmdData) { // PROCESS THE USER CONFIGURATION
  var TheSandboxArray = new Array
  var TheBrowserArray = new Array
  var TheBrowserCommandArray = new Array
  var nn = 0
  var ii = 0

  for (nn = 0;nn < 20; nn++) { // BROWSERS
    if (typeof Script.Config ["Browser " + nn] == "string") {
      if (!(Script.Config ["Browser " + nn] == "") && !(Script.Config ["Browser " + nn].substr (0, 1) == "~")) {
        TheBrowserArray [ii] = Script.Config ["Browser " + nn]
        TheBrowserCommandArray [ii] = Script.Config ["Browser " + nn + " Command"]
        ii++
      }
    }
  }

  ii = 0
  for (nn = 0;nn < 20; nn++) { // SANDBOXES
    if (typeof Script.Config ["Sandboxie Sandbox " + nn] == "string") {
      if (!(Script.Config ["Sandboxie Sandbox " + nn] == "") || !(Script.Config ["Sandboxie Sandbox " + nn].substr (0, 1) == "~")) {
        TheSandboxArray [ii] = Script.Config ["Sandboxie Sandbox " + nn]
        ii++
      }
    }
  }
  
  var BlnSandboxie = Script.Config ["Sandboxie options shown"] // SHOW SANDBOXIE OPTIONS
  var TheEditor = Script.Config ["File editor choice"] // FILE EDITOR
  var TheFaviconDirectory = Script.Config ["Favicon directory"] // FAVICON DIRECTORY
  var TheFaviconDefault = Script.Config ["Favicon name default"] // DEFAULT FAVICON
  var TheCSVViewer = Script.Config ["CSV command"] // DEFAULT CSV VIEWER  
  return {TheBrowserArray: TheBrowserArray, TheBrowserCommandArray: TheBrowserCommandArray, TheEditor: TheEditor, TheFaviconDirectory: TheFaviconDirectory, TheFaviconDefault: TheFaviconDefault, BlnSandboxie: BlnSandboxie, TheSandboxArray: TheSandboxArray, TheCSVViewer: TheCSVViewer}
} 

// *******************************************************
function OnLaunchBrowser (scriptCmdData) { // First of five addon functions.
  DOpus.Output ("- - - - - - - ->")
 
// *******************************************************
// This function chooses a browser,
// then chooses whether Sandboxie is to be run, and which sandbox to use.
// *******************************************************

// STEP 1: INTRODUCE THE VARIABLES, WITH THE USER CONFIGURATION.
  var TheButtons = "|"
  var TheChoice = ""
  var TheCancel = "Continue"
  var TheCommand = ""
  var TheBrowser = ""
  var TheSandboxieStart = "C:\\Program Files\\Sandboxie\\Start.exe" // This may possibly need editing.
  var nn = 0
  var ii = 0
  var TheTemp = 0
  var TheChoice = 0
  var TheFSO = new ActiveXObject ("Scripting.FileSystemObject")

  var TheCfg = DoCfg ()
  var TheBrowserArray = TheCfg.TheBrowserArray
  var TheBrowserCommandArray = TheCfg.TheBrowserCommandArray 
  var TheSandboxArray = TheCfg.TheSandboxArray
  var BlnSandboxie = TheCfg.BlnSandboxie

//STEP 2: ASK WHICH BROWSER TO USE, OR CANCEL.
  var TheDlg = DOpus.Dlg
  TheDlg.title = ""
  TheDlg.message = "Choose a browser."
  for (nn = 0; nn < TheBrowserArray.length; nn++) 
    TheButtons = TheButtons + TheBrowserArray [nn] + "|"
  TheButtons = TheButtons + "&Cancel"  
  TheDlg.buttons = TheButtons
  TheChoice = TheDlg.show
  
//STEP 3: ACT ON THE CHOICE.
  if (TheChoice == 0) 
    TheCancel = "The operation has been cancelled."
  if (TheChoice > 0 && TheChoice < TheBrowserArray.length + 1) {
    TheBrowser = TheBrowserArray [TheChoice - 1]
    TheCommand = '"' + TheBrowserCommandArray [TheChoice - 1] + '" '
  }

//STEP 4: IF SANDBOXIE IS INSTALLED, ASK ABOUT SANDBOXING AND WHICH BOX.
  if (TheCancel == "Continue" && TheFSO.FileExists (TheSandboxieStart) && BlnSandboxie) {
    TheDlg = DOpus.Dlg
    TheDlg.title = ""
    TheDlg.message = "Choose the sandbox, or choose to be unsandboxed."
    TheButtons = "|"
    for (nn = 0; nn < TheSandboxArray.length; nn++)
      TheButtons = TheButtons + TheSandboxArray [nn] + "|"
    TheButtons = TheButtons + "&Ask Sandboxie|&Not sandboxed|&Cancel|"
    TheDlg.buttons = TheButtons
    TheChoice = TheDlg.show

// STEP 5: ACT ON THE CHOICE.
    for (nn = 0; nn < TheSandboxArray.length; nn++)
      TheSandboxArray [nn] = TheSandboxArray [nn].replace ("&","")
    if (TheChoice == 0)
      TheCancel = "The operation has been cancelled."
    if (TheChoice > 0 && TheChoice < TheSandboxArray.length + 1)
      TheCommand = '"' + TheSandboxieStart + '" ' + "/Box:" + TheSandboxArray [TheChoice - 1] + " " + TheCommand
    if (TheChoice == TheSandboxArray.length + 1)
      TheCommand = '"' + TheSandboxieStart + '" ' + "/Box:__Ask__ " + TheCommand
    if (TheChoice == TheSandboxArray.length + 2)
      TheCommand = '"' + TheSandboxieStart + '" ' + "/dfp " + TheCommand
  }

// STEP 6: ISSUE THE BROWSER COMMAND OR THE CANCEL MESSAGE
  if (TheCancel == "Continue") {
    TheCommand = TheCommand + "about:blank"
    DOpus.Output ("TheCommand is: " + TheCommand)
  scriptCmdData.func.command.RunCommand (TheCommand)
//    scriptCmdData.Func.Command.RunCommand (TheCommand)
  } else {
    DOpus.Output (TheCancel)
    TheDlg = DOpus.Dlg
    TheDlg.title = ""
    TheDlg.message = TheCancel
    TheDlg.buttons = "&OK"
    TheDlg.icon = "warn"
    TheDlg.show
  }
  
  DOpus.Output ("<- - - - - - - -")
}

// *********************************************************
function OnOpenURLsInClip (scriptCmdData) { // Second of five addon functions.
  DOpus.Output ("- - - - - - - ->")

  // ***************************************************************************************
  // This function extracts possible URLs from the clip in the clipboard.
  // Then it allows the user to edit this list of URLs, or open them with a chosen browser. 
  // Then it allows the user to choose whether it is sandboxed, and which sandbox to use.  
  // Then it attempts to open all the discovered URLs.
  // ***************************************************************************************

  // STEP 1: INTRODUCE THE VARIABLES.
  TheClip = "|" // The clip that was already in the clipboard.
  TheClipMessage = "" // The list of URLs, or an error message.
  TheButtons = "|" // The lists of buttons in the dialogue boxes.
  TheFullCancel = "Continue" // Altered if the whole job is cancelled.
  TheCancel = "Continue" // Altered if the particular URL is cancelled.
  TheCommand = "" // The command that will open the browser.
  TheBrowser = "" // The chosen Browser.
  TheSandboxieStart = "C:\\Program Files\\Sandboxie\\Start.exe"
  var nn = 0
  var TheTemp = 0
  var TheChoice = 0 // Set each time a popup button is run
  TheURLArray = new Array // The array of extracted URLs.
  TheFSO = new ActiveXObject ("Scripting.FileSystemObject") // The file system object.
  TheWSShell = new ActiveXObject ("WScript.Shell")

  var TheCfg = DoCfg ()
  var TheBrowserArray = TheCfg.TheBrowserArray 
  var TheBrowserCommandArray = TheCfg.TheBrowserCommandArray 
  var TheEditor = TheCfg.TheEditor
  var TheSandboxArray = TheCfg.TheSandboxArray
  var BlnSandboxie = TheCfg.BlnSandboxie

// STEP 2: INPUT THE CLIP FROM THE CLIPBOARD, AND IF IT IS TEXT, EXTRACT ITS URLS.
  if (DOpus.GetClipFormat == "text") {
    TheClip = DOpus.GetClip
    DoExtractURLs (TheClip, "http") // See function below.
    DoExtractURLs (TheClip, "www.") // See function below.

    if (TheURLArray.length == 0) {
      TheClipMessage = "The clip contains no URLs.\r\n\r\nA browser may still be opened with a blank page."
      TheURLArray [0]= "about:blank "
    } else {
      if (TheURLArray.length == 1)
        TheClipMessage = "There is one possible URL in the clip.  It is also listed in the JScript log file:\r\n\r\n" + TheURLArray [0] + "\r\n"
      if (TheURLArray.length > 1) {
        TheClipMessage = "There are " + TheURLArray.length + " possible URLs in the clip.  They are also listed in the JScript log file:\r\n\r\n"
        for (nn = 0; nn < TheURLArray.length; nn++) {
          if (nn < 21) 
            TheClipMessage = TheClipMessage + TheURLArray [nn] + "\r\n"
        }
        if (TheURLArray.length > 21) {
          TheTemp = TheURLArray.length - 20
          TheClipMessage = TheClipMessage + " . . . plus " + TheTemp + " further URLs.\r\n"
        }
      }
      TheClipMessage = TheClipMessage + '\r\nTo edit one or more of these URLs, to open only some of the URLs, or to save the list, choose "Edit or save the list of URLs".'
    }
    
  } else { 
  
    TheClipMessage = "The clip is not text.\r\nThe browser may still be opened with a blank page."
    TheURLArray [0] = "about:blank "
  }    

  DOpus.Output ("Number of URLs in the array = " + TheURLArray.length)
  for (nn = 0; nn < TheURLArray.length; nn++)
    DOpus.Output (TheURLArray [nn])

//STEP 3: ASK WHICH BROWSER TO USE, OR EDIT THE URLS, OR CANCEL.
  var TheDlg = DOpus.Dlg
  TheDlg.title = ""
  TheDlg.message = TheClipMessage
  for (nn = 0; nn < TheBrowserArray.length; nn++) 
    TheButtons = TheButtons + TheBrowserArray [nn] + "|"
  if (TheURLArray [0] == "about:blank ") {
    TheButtons = TheButtons + "&Cancel"  
  } else {
    TheButtons = TheButtons + "&Edit or save the list of URLs|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - &Cancel - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"
  }
  TheDlg.buttons = TheButtons
  TheChoice = TheDlg.show
  
//STEP 4: ACT ON THE CHOICE.
  if (TheChoice == 0) 
    TheCancel = "The operation has been cancelled."
  if (TheChoice > 0 && TheChoice < TheBrowserArray.length + 1) {
    TheBrowser = TheBrowserCommandArray [TheChoice - 1]
    TheCommand = '"' + TheBrowser + '" '
  }
  if (TheChoice == TheBrowserArray.length + 1) { // The user has chosen to edit the URL list.
    ObjURLs = new DoTempFile ("TheURLArray")
    TheURLFile = ObjURLs.File
    for (nn = 0; nn < TheURLArray.length; nn++) {
      if (nn > 0)
        TheURLFile.Write ("\r\n")
      TheURLFile.Write (TheURLArray [nn])
    }
    TheURLFile.Close()
    DOpus.Output ('"' + ObjURLs.Path + '"')
    scriptCmdData.Func.Command.RunCommand (TheEditor + ' "' + ObjURLs.Path + '"')
    TheCancel = ""
  }
  
//STEP 5: IF SANDBOXIE IS INSTALLED, ASK ABOUT SANDBOXING AND WHICH BOX.
  if (TheCancel == "Continue" && TheFSO.FileExists (TheSandboxieStart) && BlnSandboxie) {
    TheDlg = DOpus.Dlg
    TheDlg.title = ""
    TheDlg.message = "Choose the sandbox, or choose to be unsandboxed."
    TheButtons = "|"
    for (nn = 0; nn < TheSandboxArray.length; nn++)
      TheButtons = TheButtons + TheSandboxArray [nn] + "|"
    TheButtons = TheButtons + "&Ask Sandboxie|&Not sandboxed|&Cancel|"
    TheDlg.buttons = TheButtons
    TheChoice = TheDlg.show

// STEP 6: ACT ON THE CHOICE.
    for (nn = 0; nn < TheSandboxArray.length; nn++)
      TheSandboxArray [nn] = TheSandboxArray [nn].replace ("&","")
    if (TheChoice == 0)
      TheCancel = "The operation has been cancelled."
    if (TheChoice > 0 && TheChoice < TheSandboxArray.length + 1)
      TheCommand = '"' + TheSandboxieStart + '" ' + "/Box:" + TheSandboxArray [TheChoice - 1] + " " + TheCommand
    if (TheChoice == TheSandboxArray.length + 1)
      TheCommand = '"' + TheSandboxieStart + '" ' + "/Box:__Ask__ " + TheCommand
    if (TheChoice == TheSandboxArray.length + 2)
      TheCommand = '"' + TheSandboxieStart + '" ' + "/dfp " + TheCommand
  }

// STEP 7: IF ALL IS STILL OK, ISSUE THE BROWSER COMMAND OR COMMANDS
  if (TheCancel == "Continue") {
    if (TheBrowser == "IExplore") {
      for (nn = 0; nn < TheURLArray.length; nn++) {
      DOpus.Output ("The final command is: " + TheCommand + TheURLArray [nn])
        scriptCmdData.Func.Command.RunCommand (TheCommand + TheURLArray [nn])
      }
    } else {
      for (nn = 0; nn < TheURLArray.length; nn++)
        TheCommand = TheCommand + TheURLArray [nn]
        DOpus.Output ("TheCommand is: " + TheCommand)
      scriptCmdData.Func.Command.RunCommand (TheCommand)
    }
  }
  
// STEP 8: ISSUE ANY CANCEL NOTIFICATION.
  if (!(TheCancel == "Continue" || TheCancel == "")) {
    DOpus.Output (TheCancel)
    TheDlg = scriptCmdData.Func.Dlg
    TheDlg.title = ""
    TheDlg.message = TheCancel
    TheDlg.buttons = "OK"
    TheDlg.icon = "warn"
    TheDlg.show
  }
  
  DOpus.Output ("<- - - - - - - -")
}
 
// *********************************************************
function OnOpenURLShortcuts (scriptCmdData) { // Third of five addon functions.
  DOpus.Output ("- - - - - - - ->")

// *******************************************************
// This function Opens selected URL shortcut files in a chosen browser, 
// with or without Sandboxie.
// The script can be applied to any text file (with any extension).
// *******************************************************

//STEP 1: INTRODUCE THE VARIABLES.
  var TheMessage = "" // The list of selected files.
  var TheButtons = "" // The list of buttons in the dialogue box.
  var TheBrowser = "" //The chosen browser.
  var TheCommand = "" // The command that will open the browser.
  var TheCancel = "Continue" // Altered if the job is cancelled.
  var TheSandboxieStart = "C:\\Program Files\\Sandboxie\\Start.exe"
  var TheChoice = 0 // Set each time a popup button is run
  var TheNumberOfFiles = 0 // The number of selected files.
  var TheFSO = new ActiveXObject ("Scripting.FileSystemObject")

  var TheCfg = DoCfg ()
  var TheBrowserArray = TheCfg.TheBrowserArray 
  var TheBrowserCommandArray = TheCfg.TheBrowserCommandArray 
  var TheEditor = TheCfg.TheEditor
  var TheSandboxArray = TheCfg.TheSandboxArray
  var BlnSandboxie = TheCfg.BlnSandboxie

  TheEnumFiles = new Enumerator (scriptCmdData.func.sourcetab.selected)

//STEP 2: EXAMINE THE SELECTED FILES.
  TheNumberOfFiles = scriptCmdData.func.sourcetab.selstats.selfiles
  
  if (TheNumberOfFiles == 0) {
    DOpus.Output ("No files have been selected.")
    TheMessage = "No files have been selected.\r\n\r\nA browser may still be launched."
  } else {  
    if (TheNumberOfFiles == 1) {
      DOpus.Output ("One file has been selected.")
      TheMessage = "One file has been selected:\r\n\r\n"
    }
    if (TheNumberOfFiles > 1) {
      DOpus.Output (TheNumberOfFiles + " files have been selected.")
      TheMessage = TheNumberOfFiles + " files have been selected:\r\n\r\n"
    }
    TheEnumFiles.moveFirst ()
    while (!TheEnumFiles.atEnd ()) {
      DOpus.Output (TheEnumFiles.item ())
      TheMessage = TheMessage + TheEnumFiles.item () + "\r\n"
      TheEnumFiles.moveNext ()
    }
    TheMessage = TheMessage + "\r\nChoose a browser:"
  }
      
//STEP 3: ASK WHICH BROWSER TO USE.
  var TheDlg = DOpus.Dlg
  TheDlg.title = ""
  TheDlg.message = TheMessage
  for (nn = 0; nn < TheBrowserArray.length; nn++) 
    TheButtons = TheButtons + TheBrowserArray [nn] + "|"
  if (TheNumberOfFiles ==0) {
    TheButtons = TheButtons + "&Cancel"  
  } else {  
    TheButtons = TheButtons + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - &Cancel - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"  
  }
  TheDlg.buttons = TheButtons
  TheChoice = TheDlg.show
  
//STEP 4: ACT ON THE CHOICE.
  if (TheChoice == 0) 
    TheCancel = "The operation has been cancelled."
  if (TheChoice > 0 && TheChoice < TheBrowserArray.length + 1) {
    TheBrowser = TheBrowserCommandArray [TheChoice - 1]
    TheCommand = TheBrowser + " "
  }

//STEP 5: IF SANDBOXIE IS INSTALLED, ASK ABOUT SANDBOXING AND WHICH BOX.
  if (TheCancel == "Continue" && TheFSO.FileExists (TheSandboxieStart) && BlnSandboxie) {
    TheDlg = DOpus.Dlg
    TheDlg.title = ""
    TheDlg.message = "Choose the sandbox, or choose to be unsandboxed."
    TheButtons = "|"
    for (nn = 0; nn < TheSandboxArray.length; nn++)
      TheButtons = TheButtons + TheSandboxArray [nn] + "|"
    TheButtons = TheButtons + "&Ask Sandboxie|&Not sandboxed|&Cancel|"
    TheDlg.buttons = TheButtons
    TheChoice = TheDlg.show

// STEP 6: ACT ON THE CHOICE.
    for (nn = 0; nn < TheSandboxArray.length; nn++)
      TheSandboxArray [nn] = TheSandboxArray [nn].replace ("&","")
    if (TheChoice == 0)
      TheCancel = "The operation has been cancelled."
    if (TheChoice > 0 && TheChoice < TheSandboxArray.length + 1)
      TheCommand = '"' + TheSandboxieStart + '" ' + "/Box:" + TheSandboxArray [TheChoice - 1] + " " + TheCommand
    if (TheChoice == TheSandboxArray.length + 1)
      TheCommand = '"' + TheSandboxieStart + '" ' + "/Box:__Ask__ " + TheCommand
    if (TheChoice == TheSandboxArray.length + 2)
      TheCommand = '"' + TheSandboxieStart + '" ' + "/dfp " + TheCommand
  }

// STEP 7: IF ALL IS STILL OK, ISSUE THE BROWSER COMMAND OR COMMANDS
  if (TheCancel == "Continue" && TheNumberOfFiles == 0)
    scriptCmdData.Func.Command.RunCommand (TheCommand + "about:blank")
  if (TheCancel == "Continue" && TheNumberOfFiles > 0) {
    TheEnumFiles.moveFirst ()
    if (TheBrowser == "IExplore") {
      while (!TheEnumFiles.atEnd ()) {
        DOpus.Output (TheCommand + ' "' + TheEnumFiles.item () + '"')
        scriptCmdData.Func.Command.RunCommand (TheCommand + ' "' + TheEnumFiles.item () + '"')
        TheEnumFiles.moveNext ()
      }
    } else {
      while (!TheEnumFiles.atEnd ()) {
        TheCommand = TheCommand + '"' + TheEnumFiles.item () + '" '
        TheEnumFiles.moveNext ()
      }
      DOpus.Output (TheCommand)
      scriptCmdData.Func.Command.RunCommand (TheCommand)
    }
  }
  
// STEP 8: ISSUE ANY CANCEL NOTIFICATION.
  if (!(TheCancel == "Continue")) {
    DOpus.Output (TheCancel)
    TheDlg = scriptCmdData.Func.Dlg
    TheDlg.title = ""
    TheDlg.message = TheCancel
    TheDlg.buttons = "&OK"
    TheDlg.icon = "warn"
    TheDlg.show
  }
  
  DOpus.Output ("<- - - - - - - -")
}

// *********************************************************
function OnURLShortcutsFromClip (scriptCmdData) { // Fourth of five addon functions.
  DOpus.Output ("- - - - - - - ->")

// ***************************************************************************************
// This function extracts possible URLs from the clip in the clipboard.
// Then it allows the user to create corresponding .url files, or edit the list of URLs.
// It also allows the user to choose favicons for each file in turn.  
// Then it writes the .url files into the source directory.
// ***************************************************************************************

// STEP 1: INTRODUCE THE VARIABLES AND INPUT EDITOR AND FAVICONS FROM CONFIGURATION.
  var TheClip = "" // The clip that was already in the clipboard.
  var TheClipMessage = "" // The list of URLs, or an error message.
  var TheFullCancel = "Continue" // Altered if the whole job is cancelled.
  var TheCancel = "Continue" // Altered if the particular URL is cancelled.
  var TheFileName = "" // The user enters this filename for each .url file.
  var TheSourceFilePath = "" // Found immediately onClick is run.
  var TheFilePath = "" // The filename preceded by the source file path.
  var TheTempString = "" 
  var TheChoice = 0 // Set each time a popup button is run
  var nn = 0 // The index of hte URL currently being processed. 
  var ii = 0 // Used when the remaining filenames or favicons are set.
  var TheTemp = 0 
  var TheFileCount = 0 // The number of .url files produced so far.
  TheURLArray = new Array // The array of extracted URLs.
  var TheFilePathArray = new Array // The array of filepaths of hte .url files.
  var TheFaviconArray = new Array // The array of the favicons that have been set.

  var TheSourceFilePath = scriptCmdData.Func.SourceTab.Path + "\\"
  var TheURLFile = new Object // The file in the file system.
  var TheDlg = new Object // Popup dialogue.
  var TheFSO = new ActiveXObject ("Scripting.FileSystemObject"); // The file system object.
  var TheWSShell = new ActiveXObject("WScript.Shell") // The WScript shell.

  var TheCfg = DoCfg ()
  var TheEditor = TheCfg.TheEditor
  var TheFaviconDirectory = TheCfg.TheFaviconDirectory
  var TheFaviconDefault = TheCfg.TheFaviconDefault

// STEP 2: INPUT THE CLIP FROM THE CLIPBOARD, AND IF IT IS TEXT, EXTRACT ITS URLS.
  if (DOpus.GetClipFormat == "text") {
    TheClip = DOpus.GetClip
    DoExtractURLs (TheClip, "http") // See function below.
    DoExtractURLs (TheClip, "www.") // See function below.
    if (TheURLArray.length == 0) 
      TheFullCancel = "The clip contains no URLs.\r\n\r\nThe operation is therefore cancelled."
    if (TheURLArray.length > 0) {
      if (TheURLArray.length == 1)
        TheClipMessage = "There is one possible URL in the clip.  It is also listed in the JScript log file:\r\n\r\n" + TheURLArray [0] + "\r\n"
      if (TheURLArray.length > 1) {
        TheClipMessage = "There are " + TheURLArray.length + " possible URLs in the clip.  They are also listed in the JScript log file:\r\n\r\n"
        for (nn = 0; nn < TheURLArray.length; nn++) {
          if (nn < 21) 
            TheClipMessage = TheClipMessage + TheURLArray [nn] + "\r\n"
        }
        if (TheURLArray.length > 21) {
          TheTemp = TheURLArray.length - 20
          TheClipMessage = TheClipMessage + " . . . plus " + TheTemp + " further URLs.\r\n"
        }
      }
      DOpus.Output ("Number of URLs in the array = " + TheURLArray.length)
      for (nn = 0; nn < TheURLArray.length; nn++)
        DOpus.Output (TheURLArray [nn])
    }
    
  } else { 
  
    TheFullCancel = "The clip is not text. The operation is therefore cancelled."
  }    

// STEP 3: PRESENT THE RESULTS, AND ASK ABOUT EACH URL IN TURN.
  if (TheFullCancel == "Continue") {
    for (nn = 0; nn < TheURLArray.length; nn++) { // Process the URL indexed by nn.
      TheURL = TheURLArray [nn]
      TheCancel = "Continue"

      while (TheFilePathArray [nn] == undefined && TheFullCancel == "Continue") { // The user must do something
        if (!(TheCancel == "Continue" || TheCancel == " ")) {
          TheDlg = scriptCmdData.Func.Dlg // This error message only shows if the "while" loop has to be run two or more times.
          TheDlg.title = "Invalid Filename"
          TheDlg.message = TheCancel
          TheDlgIcon = "warn"
          TheDlg.buttons = "&OK"
          TheDlg.show
        }
        TheCancel = "Continue"
        TheDlg = scriptCmdData.Func.Dlg // The user inputs the filename for the .url file, or cancels
        TheDlg.title = "Create URL shortcut file"
        TheTemp = nn + 1
        TheDlg.message = TheClipMessage + "\r\nEnter a filename to create a .url file corresponding to URL number " + TheTemp +  ":\r\n\r\n" + TheURLArray [nn]
        TheDlg.icon = ""
        if (nn == 0) {
          TheDlg.buttons = "Create this .url &file|Create files for &all URLs in a sequence *01, *02, . . .|&Edit the list of URLs|- - - - - - - - - - - - - - - - &Ignore this URL - - - - - - - - - - - - - - - -|- - - - - - - - - - - - - - - - &Cancel the whole job - - - - - - - - - - - - - - - -"
         } else {
          TheDlg.buttons = "Create this .url &file|Create files for &all remaining URLs in a sequence *01, *02, . . .|&Edit the list of URLs|- - - - - - - - - - - - - - - - &Ignore this URL - - - - - - - - - - - - - - - -|- - - - - - - - - - - - - - - - &Cancel the rest of the job - - - - - - - - - - - - - - - -"
        }
        TheDlg.max = 256
        TheChoice = TheDlg.show
        TheFileName = TheDlg.input
      
// STEP 4: ACT ON THE RESPONSE.
        if (TheChoice == 0) { // The user has cancelled the whole job.
          Temp = TheFilePathArray.length - nn
          TheFilePathArray [nn] = "" 
          TheCancel = " "
          TheFullCancel = "The operation was cancelled."
        }
        if (TheChoice == 4) { // The user has cancelled creation of a file for this URL.
          TheFilePathArray [nn] = "" 
          TheCancel = " " 
         }
        if (TheChoice == 3) { // The user has chosen to edit the list of URLs.
          ObjURLs = new DoTempFile ("TheURLArray")
          TheURLFile = ObjURLs.File
          for (nn = 0; nn < TheURLArray.length; nn++) {
            if (nn > 0)
              TheURLFile.Write ("\r\n")
            TheURLFile.Write (TheURLArray [nn])
          }  
          TheURLFile.Close()
          DOpus.Output (TheEditor + ' "' + ObjURLs.Path + '"')
          scriptCmdData.Func.Command.RunCommand (TheEditor + ' "' + ObjURLs.Path + '"')
          TheCancel = " "
          TheFullCancel = "Text file of URLs produced."
        }
        if (TheChoice == 1) { // The user has chosen to create a file for this particular URL.
          TheCancel = DoCheckFilename (TheFileName) // SEE FUNCTION DoCheckFileName BELOW
          if (TheCancel == "Continue") {
            TheFilePath = TheSourceFilePath + TheFileName + ".url"
            if (TheFSO.FileExists (TheFilePath)) {
              TheCancel = "There is already a file in this directory named:\r\n\r\n" + TheFileName + ".url"
            } else {
              TheFilePathArray [nn] = TheFilePath
            }
          }
        }
        if (TheChoice == 2) { // The user has chosen to create filenames in sequence for all remaining URLs.
          TheCancel = DoCheckFilename (TheFileName) // SEE FUNCTION DoCheckFileName BELOW
          if (TheCancel == "Continue") {
            for (ii = 1; ii < TheURLArray.length - nn + 1; ii++) {
              TheTempString = ii.toString()
              if (ii < 10)
                TheTempString = "0" + TheTempString
              if (ii < 100 && TheTemp > 100)
                TheTempString = "0" + TheTempString
              TheFilePath = TheSourceFilePath + TheFileName + TheTempString + ".url"
              if (TheFSO.FileExists (TheFilePath)) {
              TheCancel = "There is already a file in this directory named:\r\n\r\n" + TheFileName + TheTempString + ".url"
              } else {
              TheFilePathArray [nn + ii - 1] = TheFilePath
              }
            }
            DOpus.Output (TheFilePathArray [nn] + " " + TheFilePathArray [nn+1] + " . . . |" + TheFilePathArray [TheURLArray.length - nn - 1] + "|")
          }
        }  
      }   // THIS ENDS THE while BEGUN IN STEP 3.
      

// STEP 5: IF THINGS ARE OK, ASK FOR THE FAVICON FILENAME, WHICH IS NOT CHECKED.
      if (!(TheFilePathArray [nn] == "") && TheFaviconArray [nn] == undefined && TheCancel == "Continue" && TheFullCancel == "Continue") { 
        TheDlg = scriptCmdData.Func.Dlg // The user inputs the favicon filename, or uses the default, or cancels.
        TheDlg.title = "Favicon name selection"
        TheDlg.message = 'Enter the favicon name, without extension.\r\n\r\nAlternatively, the default input yields "Internet.ico".'
        if (nn == 0) {
          TheDlg.buttons = "&Use this favicon|Use this favicon for &all files|&Ignore this URL|&Cancel the whole job"
        } else {
          TheDlg.buttons = "&Use this favicon|Use this favicon for &all remaining files|&Ignore this URL|&Cancel the remaining job"
        }
        TheDlg.max = 256
        TheDlg.defvalue = TheFaviconDefault
        TheDlg.select = true
        TheChoice = TheDlg.show
        TheFaviconArray [nn] = TheDlg.input
        if (TheFaviconArray [nn] == "" || TheFaviconArray [nn] == undefined) 
          TheFaviconArray [nn] = TheFaviconDefault

// STEP 6: ACT ON THE CHOICE. 
// The case TheChoice = 1, where favicon for a single file is entered, needs no further processing.
        if (TheChoice == 0) {
          TheCancel = " "
          TheFullCancel = "The operation was cancelled."
        }
        if (TheChoice == 3) 
          TheCancel = " "
        if (TheChoice == 2) { // The user has chosen to use the same icon for all remaining files.
          for (ii = nn + 1; ii < TheURLArray.length + 1; ii++) 
            TheFaviconArray [ii] = TheFaviconArray [nn]
        }
      } //COMPLETES THE if BEGUN AT THE TOP OF STEP 5.

// STEP 6: IF ALL IS OK, CREATE THE FILE.  THEN ISSUE A CONCLUSION.
      if (TheFullCancel == "Continue") {
        if (TheCancel == "Continue") {
          TheURLFile = TheFSO.CreateTextFile(TheFilePathArray [nn]) // Create the file.
          TheFileCount = TheFileCount + 1
          TheURLFile.Write ("[InternetShortcut]\r\n") // Write the four lines tino this file.
          TheURLFile.Write ("URL=" + TheURLArray [nn] + "\r\n")
          TheURLFile.Write ("IconFile=" + TheFaviconDirectory + TheFaviconArray [nn] + ".ico\r\n") 
          TheURLFile.Write ("IconIndex=0\r\n")
          TheURLFile.Close()
        } else {
          if (!(TheCancel == " ")) { // Issue an error message.
            TheDlg = scriptCmdData.Func.Dlg
            TheDlg.title = "Operation cancelled A"
            TheDlg.message = TheCancel
            TheDlg.buttons = "&OK"
            TheDlg.icon = "warn"
            TheDlg.show
          }  
        }
      }
    } // COMPLETES THE for BEGUN AT THE TOP OF STEP 3
  } // COMPLETES THE if BEGUN AT THE TOP OF STEP 3

  TheTemp = TheURLArray.length - TheFileCount
  TheTempString = "Number of URL files created = " + TheFileCount + "\r\n" + "Number of URLs unprocessed = " + TheTemp 
  DOpus.Output (TheTempString)
  TheDlg = scriptCmdData.Func.Dlg // Summarise the results.
  TheDlg.title = ""
  if (TheFullCancel == "Continue") { // If there are no errors or cancelling.
    TheDlg.message = TheTempString
    TheDlgicon = ""
  } else { // Otherwise TheFullCancel contains the required error message.
    TheDlg.message = TheFullCancel + "\r\n\r\n" + TheTempString
    TheDlg.icon = "warn"
  }
  TheDlg.buttons = "&OK"
  TheDlg.show
  
  DOpus.Output ("<- - - - - - - -")
}

// *********************************************************
function OnViewClip (scriptCmdData) { // Fifth of five addon functions.
  DOpus.Output ("- - - - - - - ->")
 
// *******************************************************
// This function attempts to view the clip on the clipboard.
// Text is viewed in the DOpus standalone viewer.
// Files are viewed in the CSV viewer (see configuration).
// Other clips are attempted to be viewed as .jpg files in the DOpus viewer.
// *******************************************************

  var TheSelFileStem = ""
  var TheSelFileExt = ""
  var TheSelFileDate = ""
  var TheSelFileSize = ""
  var TheSelFileDetails = ""
  var TheTempFile = new Object
  var TheFSO = new ActiveXObject ("Scripting.FileSystemObject"); // The file system object.
  var TheWSShell = new ActiveXObject("WScript.Shell") // The WScript shell.
  var TheClip = DOpus.GetClip

  var TheCfg = DoCfg ()
  var TheCSVViewer = TheCfg.TheCSVViewer

// Case 1: The clip is text.
  if (DOpus.GetClipFormat == "text") {
    DOpus.Output ('The clip type is "text".')
    ObjTempFile = new DoTempFile ("ThePastedData")
    TheTempFile = ObjTempFile.File
    TheTempFile.Write (TheClip)
    TheTempFile.Close()
    DOpus.Output ('Show "' + ObjTempFile.Path + '"')
    scriptCmdData.Func.Command.RunCommand ('Show "' + ObjTempFile.Path + '"')
  }

// Case 2: The clip is a list of folders and files.
  if (DOpus.GetClipFormat == "files") {
    DOpus.Output ('The clip type is "files".')
    ObjTempFile = new DoTempFile ("ThePastedData", "csv")
    TheTempFile = ObjTempFile.File
    TheTempFile.Write ("Filename Stem,Ext,Date Modified,Bytes,Type\r\n")
  
    TheEnumFiles = new Enumerator (TheClip)
    TheEnumFiles.moveFirst ()
    while (!TheEnumFiles.atEnd ()) { // Then enumerate the files.
      TheSelFileStem = TheEnumFiles.item ().name_stem
      TheSelFileExt = TheEnumFiles.item ().ext
      TheSelFileExt = TheSelFileExt.substr (1)
	    TheSelFileDate = DoMask (new Date (TheEnumFiles.item ().modify)).TheStandardDateTime
      if (TheEnumFiles.item ().is_dir) {
        TheSelFileSize = ""
        TheSelFileDetails = TheSelFileStem + "," + TheSelFileExt + "," + TheSelFileDate + "," + TheSelFileSize + ",Folder"
	  } else {
        TheSelFileSize = TheEnumFiles.item ().size
        TheSelFileDetails = TheSelFileStem + "," + TheSelFileExt + "," + TheSelFileDate + "," + TheSelFileSize + ",File"
      }
      TheTempFile.Write (TheSelFileDetails + "\r\n")
      TheEnumFiles.moveNext ()
    }
    TheTempFile.Close()
    DOpus.Output (TheCSVViewer + ' "' + ObjTempFile.Path + '"')
    scriptCmdData.Func.Command.RunCommand ('"' + TheCSVViewer + '" "' + ObjTempFile.Path + '"')
  }

// Case 3: The clip is neither text nor files.  Try to view it as a JPG image.
  if (DOpus.GetClipFormat == "") {
    DOpus.Output ("The clip type is neither text nor files. Attempt to view as a *.jpg file.")
    ObjTempFile = new DoTempFile ("ThePastedData", "jpg", false)  // The file is named, but not created.
    TheTempPath = ObjTempFile.Path
    scriptCmdData.Func.Command.RunCommand ('Clipboard Paste=jpg ' + TheClip + ' As "' + TheTempPath + '"')
    DOpus.Output ('Show "' + TheTempPath + '"')
    scriptCmdData.Func.Command.RunCommand ('Show "' + TheTempPath + '"')
  }

  DOpus.Output ("<- - - - - - - -")
}

// *********************************************************
// The remaining functions are helper functions 
// for the five add-on functions above.
// *********************************************************
function DoCheckFilename (TheString) { //String
  TheCancel = new String ("Continue")

  if (TheString == undefined) {
    TheCancel = " "
  } else {
    TheString = DoTrim (TheString) // SEE FUNCTION DoTrim BELOW
    if (TheString.length == 0) 
      TheCancel = "The filename cannot be empty or consist only of spaces."
  }

  if (TheCancel == "Continue") {
    if (!(TheString.indexOf ("/") == -1 && TheString.indexOf ("\\") == -1 && TheString.indexOf ("<") == -1)) 
      TheCancel = 'The characters \r\n\r\n/ \\ < > : | ? * " \r\n\r\nare not permitted in filenames, and the following is therefore not a valid filename:\r\n\r\n' + TheString
    if (!(TheString.indexOf (">") == -1 && TheString.indexOf (":") == -1 && TheString.indexOf ("|") == -1)) 
      TheCancel = 'The characters \r\n\r\n/ \\ < > : | ? * " \r\n\r\nare not permitted in filenames, and the following is therefore not a valid filename:\r\n\r\n' + TheString
    if (!(TheString.indexOf ("?") == -1 && TheString.indexOf ("*") == -1 && TheString.indexOf ('"') == -1)) 
      TheCancel = 'The characters \r\n\r\n/ \\ < > : | ? * " \r\n\r\nare not permitted in filenames, and the following is therefore not a valid filename:\r\n\r\n' + TheString
  }
  return TheCancel
} 

// *********************************************************
function DoExtractURLs (TheText, ThePrefix) { // String, String
  var TheExtractedArray = new Array
  TheExtractedArray [0] = ""
//  var TheURLArray = new Array
  var TheURL = ""
  var TheDistinct = true
  var nn = 0
  var ii = 0

  TheText = TheText.replace (/(\r\n|\n|\r)/gm," ")
  TheExtractedArray = TheText.split (ThePrefix)
  TheURLIndex = 0
  
  for (nn = 1; nn < TheExtractedArray.length; nn++) {
    TheURL = TheExtractedArray [nn] + " "
    TheURL = TheURL.substring(0, TheURL.indexOf(" "))
    while (TheURL.substr (TheURL.length - 1) == "." || TheURL.substr (TheURL.length - 1) == ">") 
      TheURL = TheURL.substr (0, TheURL.length - 1)
    TheURL = ThePrefix + TheURL + " "
    TheDistinct = true
    for (ii = 0; ii < TheURLArray.length; ii++) {
      if (TheURL == TheURLArray [ii] || "http://" + TheURL == TheURLArray [ii] || "https://" + TheURL == TheURLArray [ii])
        TheDistinct = false
    }
    if (TheDistinct == true) {
      TheURLArray [TheURLIndex] = TheURL
      TheURLIndex++
    }
  }
}

// *********************************************************
function DoTempFile (TheText, TheExt, Create, ms) { // String, String, Boolean, Boolean
  var Today = new Date
  var TheFSO = new ActiveXObject ("Scripting.FileSystemObject")
  var TheWSShell = new ActiveXObject("WScript.Shell") 
  var TheTempFileDir = ""
  if (arguments.length < 2) // The last three parameters are optional and have defaults.
    TheExt = "txt"
  if (arguments.length < 3)
    Create = true
  if (arguments.length < 4)
    ms = false
    
  var TheTempFileDir = TheWSShell.ExpandEnvironmentStrings("%TEMP%\\DOpus") 
  if (!(TheFSO.FolderExists (TheTempFileDir)))
    TheFSO.CreateFolder (TheTempFileDir)

  var TheStamp = DoMask (Today).TheReverseDateTime
  if (ms)
    TheStamp = TheStamp + DoMask (Today).ms
  this.Ext = TheExt
  this.Name = TheText + TheStamp + "." + TheExt
  this.Path = TheTempFileDir + "\\" + this.Name
  if (Create)
    this.File = TheFSO.CreateTextFile (this.Path)
}

// *********************************************************
function DoMask (ObjDate) { // Date
  var dd = DoBuffer (ObjDate.getDate ())
  var MM = DoBuffer (ObjDate.getMonth () + 1)
  var yy = DoBuffer (ObjDate.getFullYear ())
  var HH = DoBuffer (ObjDate.getHours ())
  var mm = DoBuffer (ObjDate.getDate ())
  var ss = DoBuffer (ObjDate.getSeconds ())
  var ms = DoBuffer (ObjDate.getMilliseconds (), 3)

  var TheStandardDate = dd + "/" + MM + "/" + yy
  var TheStandardDateTime = dd + "/" + MM + "/" + yy + " " + HH+ ":" + mm + ":" + ss
  var TheReverseDateTime = yy + MM + dd + "@" + HH + mm + ss
  return {dd: dd, MM: MM, yy: yy, HH: HH, mm: mm, ss: ss, TheStandardDate: TheStandardDate, TheStandardDateTime: TheStandardDateTime, TheReverseDateTime:TheReverseDateTime}
}

// *********************************************************
function DoBuffer (TheNumber, TheLength) { // Non-negative whole numbers.
  if (arguments.length < 2)
    TheLength = 2
  var StrNumber = TheNumber.toString () //This will be the buffered or truncated number.
  
  while (StrNumber.length < TheLength) // This bit adds zeroes at the front.
    StrNumber = "0" + StrNumber
  if (StrNumber.length > TheLength) // This bit truncates from the left.
    StrNumber = StrNumber.substr (StrNumber.length - TheLength)
  return StrNumber
}

// *********************************************************
function DoTrim (TheString) { //String
  while (TheString.substr (0,1) == " ") 
    TheString = TheString.substr (1)
  while (TheString.substr (TheString.length-1) == " ") 
    TheString = TheString.substr (0, TheString.length-1)
  return TheString
}

//MD5 = "7d63776b15a829bab404d5e2a02b483a"; DATE = "2015.09.17 - 17:07:22"