/**
 * +----------------------------------------------------------------------------+
 * |                          Jeffrey M. Hunter                                 |
 * |                      jhunter@idevelopment.info                             |
 * |                         www.idevelopment.info                              |
 * |----------------------------------------------------------------------------|
 * |      Copyright (c) 1998-2011 Jeffrey M. Hunter. All rights reserved.       |
 * |----------------------------------------------------------------------------|
 * | FILE       : Mail.js                                                       |
 * | CLASS      : Miscellaneous Functions                                       |
 * | PURPOSE    : Demonstrates how to send email using Microsoft Collaboration  |
 * |              Data Objects (CDO).                                           |
 * | PARAMETERS : For a list of parameters and descriptions, see the function   |
 * |              showHelpMessageExtended().                                    |
 * | TRACING    : Set the WSHTRACE Windows environment variable to the level    |
 * |              (1-n) of tracing you would like to capture.                   |
 * | USAGE      :                                                               |
 * |                                                                            |
 * |              cscript Mail.js [recipient list]                              |
 * |                              -from   [sender]                              |
 * |                              -cc     [list]                                |
 * |                              -bcc    [list]                                |
 * |                              -s      "Subject"                             |
 * |                              -b      "Message Body"                        |
 * |                              -file   "Text File"                           |
 * |                              -a      "File Attachment"                     |
 * |                              -smtp   smtpserver.domain.com                 |
 * |                              -?      Extended Help Message                 |
 * |                              //NoLogo                                      |
 * |                                                                            |
 * | NOTE       : As with any code, ensure to test this script in a development |
 * |              environment before attempting to run it in production.        |
 * +----------------------------------------------------------------------------+
 **/

// -----------------------------------------------------------------------------
//   EXPLICIT VARIABLE DECLARATION & STANDARD GLOBALS
// -----------------------------------------------------------------------------

var g_SCRIPT_VERSION="1.0";
var g_strScriptPath, g_strScriptName, g_strScriptFolder, g_strScriptNameNoExt;
var g_bytTraceLevel;
var g_objShell;
var strBannerText, i;


// -----------------------------------------------------------------------------
//   DECLARATION OF SCRIPT GLOBALS
// -----------------------------------------------------------------------------

var strTo, strFrom, strCC, strBCC, strSubject, strTextBody;
var blnHelp = false;
var strAttachment;
var strSMTPServer;
var arrAttachment = new Array();


// -----------------------------------------------------------------------------
//   SET STANDARD GLOBALS & CREATE GLOBAL OBJECTS
// -----------------------------------------------------------------------------

g_strScriptPath = WScript.ScriptFullName;
g_strScriptName = WScript.ScriptName;
g_strScriptFolder = g_strScriptPath.substring(0, g_strScriptPath.length - g_strScriptName.length);
i = g_strScriptName.indexOf('.');

if (i >= 0) {
    g_strScriptNameNoExt = g_strScriptName.substring(0, i);
} else {
    g_strScriptNameNoExt = g_strScriptName;
}

g_objShell = new ActiveXObject("WScript.Shell");


// -----------------------------------------------------------------------------
//   SHOW SIGNON BANNER
// -----------------------------------------------------------------------------

strBannerText =
        "\n" +
        g_strScriptName + " - Version " + g_SCRIPT_VERSION + "\n" +
        "Copyright (c) 1998-2011 Jeffrey M. Hunter. All rights reserved.\n";
WScript.Echo(strBannerText);


// -----------------------------------------------------------------------------
//   SETUP TRACING CONTROL FROM THE "WSHTRACE" WINDOWS ENVIRONMENT VARIABLE
// -----------------------------------------------------------------------------

i = g_objShell.Environment("Process").Item("WSHTRACE");

if (isNumeric(i)) {
    g_bytTraceLevel = parseInt(i);
    WScript.Echo("\n" + "DEBUGGING TURNED ON AT LEVEL: " + g_bytTraceLevel + "\n");
} else {
    g_bytTraceLevel = 0;
}


// -----------------------------------------------------------------------------
//   CALL MAIN FUNCTION
// -----------------------------------------------------------------------------

i = main();


// -----------------------------------------------------------------------------
//   CLEAN UP AND EXIT SCRIPT
// -----------------------------------------------------------------------------

g_objShell = null;

trace(2, "D: Exit Code = " + i);
WScript.Quit(i);



// ------------------------------------------------------------------------------
// --------------------------- <  END OF SCRIPT  > ------------------------------
// ------------------------------------------------------------------------------



/**
 * -----------------------------------------------------------------------------
 * main
 *
 * Main function used to enclose the primary script logic.
 *
 * Returns
 *      Exit code from primary script logic.
 * -----------------------------------------------------------------------------
 **/

function main() {

    trace(1, ">  main");
    
    // --------------------------------------------
    // Set all mail variables to some default value
    // --------------------------------------------
    strTo="";
    strFrom="MailScript@localhost";
    strSubject="Subject";
    strTextBody="";
    strSMTPServer="";

    // ------------------------
    // Set all script arguments
    // ------------------------
    if (!setScriptArguments()) {
        showHelpMessage();
        trace(2, "D: Failed with setting script arguments. Returning error.");
        trace(1, "<  main(1)");
        return 1;
    }
    
    // ---------------------------------------
    // Check to see if the user requested help
    // ---------------------------------------
    if (blnHelp) {
        showHelpMessageExtended();
        trace(2, "D: Exiting with script usage message requested by user.");
        trace(1, "<  main(1)");
        return 0;
    }
    
    // ----------------------------------------
    // Check to see if the user entered a valid
    // recipient email address.
    // ----------------------------------------
    if (strTo == "") {
        showHelpMessage();
        WScript.Echo("ERROR: No valid email address.");
        trace(2, "D: No valid email address.");
        trace(1, "<  main(1)");
        return 1;
    }
        
    // -------------------------------------------------------
    // Check that the local SMTP service is running or
    // that the user provided an SMTP server used to send this
    // email. If neither, then prompt user with the error and
    // exit this script.
    // -------------------------------------------------------
    if (strSMTPServer == "") {
        if (!serviceCheck("localhost", "SMTPSVC")) {
            var strErrorMessage =
    	            "\n" +
    	            "ERROR: Could not find the local SMTP service running \n" +
    	            "       and no SMTP server was provided as an argument \n" +
    	            "       to this script. If you want to use the local \n" +
    	            "       SMTP service, ensure that it is installed and \n" +
    	            "       running. If not, you will need to specify an \n" +
    	            "       external SMTP server using the '-smtp [server]' \n" +
    	            "       argument to this script. For more help with \n" +
    	            "       script arguments, use: \n\n" +
    	            "       cscript Mail.js -?";
    	    WScript.Echo(strErrorMessage);
            trace(2, "D: Exiting with no SMTP error.");
            trace(1, "<  main(1)");
            return 1;
    	}
	}
	
    mail(   strTo
          , strFrom
          , strCC
          , strBCC
          , strSubject
          , strTextBody
          , arrAttachment
          , strSMTPServer);

    trace(1, "<  main(0)");
    
    return(0);
        
}


/**
 * -----------------------------------------------------------------------------
 * mail
 *
 * Used to generate and send an email using either a local or external SMTP
 * server.
 * -----------------------------------------------------------------------------
 **/
function mail(   strTo
               , strFrom
               , strCC
               , strBCC
               , strSubject
               , strTextBody
               , arrAttachment
               , strSMTPServer) {

    trace(1, ">  mail");

    var objCDOConfiguration, objCDOConfigurationFields, objMessage;
    var strMsSchema, i;
    
    objCDOConfiguration = new ActiveXObject("CDO.Configuration");
    
    if (strSMTPServer != "") {
        strMsSchema = "http://schemas.microsoft.com/cdo/configuration/";
        objCDOConfiguration.Fields.Item(strMsSchema + "sendusing") = 2;
        objCDOConfiguration.Fields.Item(strMsSchema + "smtpserverport") = 25;
        objCDOConfiguration.Fields.Item(strMsSchema + "smtpserver") = strSMTPServer;
        objCDOConfiguration.Fields.Item(strMsSchema + "smtpconnectiontimeout") = 60;
        objCDOConfiguration.Fields.Update();
    }
    
    objMessage = new ActiveXObject("CDO.Message");
    objMessage.Configuration = objCDOConfiguration;
    
    objMessage.To       = strTo;
    objMessage.From     = strFrom;
    objMessage.CC       = strCC;
    objMessage.BCC      = strBCC;
    objMessage.Subject  = strSubject;
    objMessage.TextBody = strTextBody;

    for (i=0; i<arrAttachment.length; i++) {
        objMessage.AddAttachment(arrAttachment[i]);
    }
    
    objMessage.Send();
    
    WScript.Echo();
    WScript.Echo("Successfully sent email.\n");
    WScript.Echo("To            : " + objMessage.To);
    WScript.Echo("From          : " + objMessage.From);
    WScript.Echo("CC            : " + objMessage.CC);
    WScript.Echo("BCC           : " + objMessage.BCC);
    WScript.Echo("Subject       : " + objMessage.Subject);
    WScript.Echo("Body          : " + objMessage.TextBody.substring(0, 30) + " ...");
    WScript.Echo("SMTP Server   : " + strSMTPServer)
    for (i=0; i<arrAttachment.length; i++) {
        WScript.Echo("Attachment[" + i + "] : " + arrAttachment[i]);
    }

    trace(1, "<  mail");
        
}


/**
 * -----------------------------------------------------------------------------
 * readTextFile
 *
 * Read a text file and return the contents
 * -----------------------------------------------------------------------------
 **/

function readTextFile(strFileName) {
    
    trace(1, ">  readTextFile");
    
    var objFSO;
    var objTextFile;
    var strReadLine="";
    
    objFSO = new ActiveXObject("Scripting.FileSystemObject");
    
    if(objFSO.FileExists(strFileName)) {
        
        objTextFile = objFSO.OpenTextFile(strFileName,1);
    
        while(!objTextFile.AtEndOfStream) {
            strReadLine = strReadLine + objTextFile.ReadLine() + "\n";
        }
        objTextFile.Close();
    } else {
        strReadLine="Error reading file: " + strFileName;
    }

    trace(1, "<  readTextFile");
    
    return(strReadLine);
	
}


/**
 * -----------------------------------------------------------------------------
 * showHelpMessage
 *
 * Display help message for this script.
 * -----------------------------------------------------------------------------
 **/

function showHelpMessage() {

    trace(1, ">  showHelpMessage");
    
    var strMessage;
    
    strMessage = 
        "Usage: cscript " + g_strScriptName + " [recipient list] \n" +
        "                       -from   [sender] \n" +
        "                       -cc     [list] \n" +
        "                       -bcc    [list] \n" +
        "                       -s      \"Subject\" \n" +
        "                       -b      \"Message Body\" \n" +
        "                       -file   \"Text File\" \n" +
        "                       -a      \"File Attachment\" \n" +
        "                       -smtp   smtpserver.domain.com \n" +
        "                       -?      Extended Help Message \n" +
        "                       //NoLogo \n\n";

    WScript.Echo(strMessage);

    trace(1, "<  showHelpMessage");

}


/**
 * -----------------------------------------------------------------------------
 * showHelpMessageExtended
 *
 * Display extended help message for this script.
 * -----------------------------------------------------------------------------
 **/

function showHelpMessageExtended() {

    trace(1, ">  showHelpMessageExtended");
    
    var strMessage;
    
    showHelpMessage();
    
    strMessage = 
        " Parameter Descriptions:\n" +
        " ---------------------------------------------------------------\n" +
        " [list]              A list of email addresses delimited by\n" +
        "                     a single comma with no spaces between \n" +
        "                     the comma(s).\n" +
        " -from [sender]      The sender of the email message using the\n" +
        "                     format: sender@domain.com.\n" +
        " -cc [list]          All carbon copy recipients.\n" +
        " -bcc [list]         All blind carbon copy recipients.\n" +
        " -s \"Subject\"        Subject of the email message, enclosed \n" +
        "                     by double quotes.\n" +
        " -b \"Body\"           The content (or body) of the message, \n" +
        "                     enclosed by double quotes.\n" +
        " -file [Text File]   The name of a text file whose contents will\n" +
        "                     be included as part (or all) of the body.\n" +
        "                     This parameter can be used in conjunction \n" +
        "                     with the -b Message Body parameter.\n" +
        " -a [File Name]      Name of a file to be included as an \n" +
        "                     attatchment to the email message. You can\n" +
        "                     include this parameter more than once.\n" +
        " -smtp [server]      Name of an external SMTP server that will\n" +
        "                     be used to send this email message. Used \n" +
        "                     you do not have a local SMTP service\n" +
        "                     running.\n" +
        " -p                  Instructs this script to look for piped\n" +
        "                     input from an external program. This is\n" +
        "                     specified with the pipe character |. \n" +
        "                     Note that when piping input to this script,\n" +
        "                     the piping must be done to cscript.exe then\n" +
        "                     followed by the script name.\n" +
        " -?                  Help screen. (This screen)\n\n" +
        " Examples:\n" +
        " ---------------------------------------------------------------\n" +
        " cscript " + g_strScriptName + " jhunter@iDevelopment.info \n" +
        "                 -s \"Message Subject\" \n" +
        "                 -b \"Body of the message...\" \n" +
        "                 -cc ahunter@iDevelopment.info,admin@iDevelopment.info\n" +
        "                 -a \"c:\\web\\images\\image1.jpg\" \n" +
        "                 -a \"c:\\web\\images\\image2.jpg\" \n" +
        "                 -smtp smtp.mydomain.com \n\n" +
        " type message.txt | cscript " + g_strScriptName + " jhunter@iDevelopment.info -p\n" +
        "\n";

    WScript.Echo(strMessage);

    trace(1, "<  showHelpMessageExtended");

}


/**
 * -----------------------------------------------------------------------------
 * trace
 * 
 * Debug script tracing by using the g_bytTraceLevel and WSHTRACE environment 
 * variable
 *
 * Parameters
 *     bytLevel    Trace level. Used to control if trace information will be
 *                 printed. Only display if <= WSHTRACE
 *                 nLevel  Tracing Information
 *                 ------  ----------------------------------------------------
 *                   1     Includes sub routine "enter" and "exit" data. Also
 *                         includes sub routine arguments (A[n]:) as well as 
 *                         critical errors (E:).
 *                   2     Includes all nLevel 1 plus debugging and warning
 *                         tracing information.
 *     strText     Text to display
 * 
 * Notes
 *     The following tokens may be used at the beginning of each Trace
 *     line to make reading trace information easier to read:
 *
 *     >  "Sub Routine"    Use at the begining of a sub routine to indicate 
 *                         entering the sub routine code.
 *     <  "Sub Routine"    Use when exiting sub routine code.
 *     A[n]:               Used when tracing sub routine arguments.
 *     D:                  Used to print debugging text to the trace file.
 *     V:                  Used to print out a variable name to the trace file.
 *     W:                  Used to indicate a warning message to the trace file.
 *     E:                  Used to indicate a critical error to the trace file.
 * -----------------------------------------------------------------------------
 **/

function trace(bytLevel, strText) {

    if (g_bytTraceLevel >= bytLevel) {
        WScript.Echo(strText);
    }

}


/**
 * -----------------------------------------------------------------------------
 * setScriptArguments
 *
 * Sets all required parameters used for mailing. All parameters are passed
 * by reference.
 * -----------------------------------------------------------------------------
 **/

function setScriptArguments() {

    trace(1, ">  setScriptArguments");
    
    var i, strArgValue;
    var colArgs = WScript.Arguments;

    if (colArgs.Length == 0) {
        trace(2, "D: User didn't enter any parameters.");
        trace(1, "<  setScriptArguments");
        return (false);
    }

    for (i=0; i<colArgs.Length; i++) {

        strArgValue = colArgs.Item(i).toLowerCase();

        trace(2, "D: Looking at: " + strArgValue);

        // --------------------------
        // Is this a named parameter?
        // --------------------------
        if (/^-/.test(strArgValue)) {
        
            if ((strArgValue == "-help") || (strArgValue == "-?")) {
                blnHelp=true;
                trace(2, "D: User requested help.");
                trace(1, "<  setScriptArguments");
                return (true);
            }

            if (strArgValue == "-from") {
                if (i+1 > colArgs.length-1) {
                    trace(2, "D: Exiting with error in -from.");
                    trace(1, "<  setScriptArguments");
                    return (false);
                }
                strFrom = colArgs.Item(i+1);
                i++;
            }
            
            if (strArgValue == "-cc") {
                if (i+1 > colArgs.length-1) {
                    trace(2, "D: Exiting with error in -cc.");
                    trace(1, "<  setScriptArguments");
                    return (false);
                }
                strCC = colArgs.Item(i+1);
                i++;
            }
            
            if (strArgValue == "-bcc") {
                if (i+1 > colArgs.length-1) {
                    trace(2, "D: Exiting with error in -bcc.");
                    trace(1, "<  setScriptArguments");
                    return (false);
                }
                strBCC = colArgs.Item(i+1);
                i++;
            }

            if (strArgValue == "-s") {
                if (i+1 > colArgs.length-1) {
                    trace(2, "D: Exiting with error in -s.");
                    trace(1, "<  setScriptArguments");
                    return (false);
                }
                strSubject = colArgs.Item(i+1);
                i++;
            }

            if (strArgValue == "-b") {
                if (i+1 > colArgs.length-1) {
                    trace(2, "D: Exiting with error in -b.");
                    trace(1, "<  setScriptArguments");
                    return (false);
                }
                strTextBody = strTextBody+colArgs.Item(i+1);
                i++;
            }
            
            if (strArgValue == "-a") {
                if (i+1 > colArgs.length-1) {
                    trace(2, "D: Exiting with error in -a.");
                    trace(1, "<  setScriptArguments");
                    return (false);
                }
                arrAttachment.push(colArgs.Item(i+1));
                i++;
            }

            if (strArgValue == "-smtp") {
                if (i+1 > colArgs.length-1) {
                    trace(2, "D: Exiting with error in -smtp.");
                    trace(1, "<  setScriptArguments");
                    return (false);
                }
                strSMTPServer=colArgs.Item(i+1);
                i++;
            }
            
            if (strArgValue == "-file") {
                if (i+1 > colArgs.length-1) {
                    trace(2, "D: Exiting with error in -file.");
                    trace(1, "<  setScriptArguments");
                    return (false);
                }
                strTextBody = strTextBody + readTextFile(colArgs.Item(i+1));
                i++;
            }
            
            if (strArgValue == "-p") {
                while(!WScript.StdIn.AtEndOfStream) {
                    strTextBody = strTextBody + WScript.StdIn.ReadAll();
                }
            }

        } else {

            if (/@/.test(strArgValue)) { 
                strTo = strArgValue;
            } else {
                trace(2, "D: This is not an email address or an argument.");
                trace(2, "D: Skipping this argument value.");
            }
        }

    }
    
    trace(1, "<  setScriptArguments");
    return (true);
    
}


/**
 * -----------------------------------------------------------------------------
 * isNumeric
 *
 * Determines if a value is numeric. This is equivalent to the VBScript
 * IsNumeric function.
 * -----------------------------------------------------------------------------
 **/

function isNumeric(s) {

    trace(1, ">  isNumeric");
    
    if (s == null) {
        return false;
    }
    
    if (s.length == 0) {
        return false;
    }
    
    for (var i=0; i<s.length; ++i) {
        if ("0123456789".indexOf(s.charAt(i)) < 0) {
            return false;
        }
    }
    
    trace(1, "<  isNumeric");
    
    return true;

}


/**
 * -----------------------------------------------------------------------------
 * serviceCheck
 *
 * Checks if the local SMTP service is installed and running using WMI.
 * -----------------------------------------------------------------------------
 **/

function serviceCheck(strMachineName, strServiceName) {

    trace(1, ">  serviceCheck");
    
    var strWMI;
    var objServiceName;

    try {
        strWMI = "WinMgmts://" + strMachineName + "/root/cimv2:Win32_Service='" + strServiceName + "'";
        objServiceName = GetObject(strWMI);
	    if (objServiceName.State == "Running") {
	        trace(1, "D: SMTP service is running. Returning true.");
	        trace(1, "<  serviceCheck");
	        return(true);
	    }
    } catch(e) {
        trace(2, "D: Service is not installed.");
        trace(1, "<  serviceCheck");
    	return(false);
    }
    
    trace(1, "D: SMTP service is not running. Returning false.");
    trace(1, "<  serviceCheck");
	return(false);
	
}

