Files
cdrtool/_Main.cs
Doug Macintosh 336b0dbb7e first real commit
2026-03-08 17:05:59 -04:00

619 lines
20 KiB
C#

#define PROD_ // also change in LicenseFile.cs too, prevents compilation of the licensekey making bits
/*
* Created by SharpDevelop.
* User: D Macintosh
* Date: 10/25/2022
* Time: 9:32 PM
*
* To change this template use Tools | Options | Coding | Edit Standard Headers.
*/
using System;
using System.Collections.Generic;
using System.Net;
using System.IO;
using System.Text;
using Newtonsoft.Json.Linq;
using System.Threading;
using System.Reflection;
namespace cdrtool
{
class cdrtool
{
public static string product = "CDR-Tool";
public static string version = "1.6.7";
public static int debug = 1;
public static int mode = 1;
public static int major_errs = 0;
public static int MAX_RETRY = 3;
public static int MIN_INT = 10; // minimum interval for timer in minutes
public static int MAX_INT = 360; // maximum interval for timer
public static int webMaxWait = 20; //max wait time in minutes for webaccess
public static bool logappend = true;
public static string logname = "logfile.txt";
public static string licfile = "license.txt";
public static StreamWriter outfile;
public static string username;
public static string password;
public static string company;
public static bool licensed;
public static string dirpath = "";
public static string token = "";
public static int begin = 8;
public static int end = 20;
public static int interval = 0;
public static bool checkPrevMonth = true;
public static int prevMonOffset = 1;
public static string mfa = ""; // 6-digit MFA code
public static int mfa_delay = 120; // wait time for email to arrive in seconds
public static string ssh_user;
public static string ssh_pass;
public static string ssh_host;
public static string ssh_path = "." + Path.DirectorySeparatorChar ;
public static int ssh_port = 22;
public static bool sftp = false;
public static StringBuilder adminLog = new StringBuilder();
public static StringBuilder auditLog = new StringBuilder();
public static int adlvl = 2;
/* see https://denhamcoder.net/2018/08/25/embedding-net-assemblies-inside-net-assemblies/ */ // still needs external copy during compilation!
// Loads NewtonsoftJson lib into memory as .dll
public static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
string name = new AssemblyName(args.Name).Name;
string embname = "other";
if (name == "BouncyCastle.Cryptography")
{
embname = "CDRTool.Embedded.BouncyCastle.Cryptography.dll";
}
else if (name == "Google.Apis")
{
embname = "CDRTool.Embedded.Google.Apis.dll";
}
else if (name == "Google.Apis.Auth")
{
embname = "CDRTool.Embedded.Google.Apis.Auth.dll";
}
else if (name == "Google.Apis.Core")
{
embname = "CDRTool.Embedded.Google.Apis.Core.dll";
}
else if (name == "Google.Apis.Gmail.v1")
{
embname = "CDRTool.Embedded.Google.Apis.Gmail.v1.dll";
}
else if (name == "Microsoft.Bcl.AsyncInterfaces")
{
embname = "CDRTool.Embedded.Microsoft.Bcl.AsyncInterfaces.dll";
}
else if (name == "Microsoft.Extensions.DependencyInjection.Abstractions")
{
embname = "CDRTool.Embedded.Microsoft.Extensions.DependencyInjection.Abstractions.dll";
}
else if (name == "Microsoft.Extensions.Logging.Abstractions")
{
embname = "CDRTool.Embedded.Microsoft.Extensions.Logging.Abstractions.dll";
}
else if (name == "Newtonsoft.Json")
{
embname = "CDRTool.Embedded.Newtonsoft.Json.dll";
}
else if (name == "Renci.SshNet")
{
embname = "CDRTool.Embedded.Renci.SshNet.dll";
}
else if (name == "System.Buffers")
{
embname = "CDRTool.Embedded.System.Buffers.dll";
}
else if (name == "System.CodeDom")
{
embname = "CDRTool.Embedded.System.CodeDom.dll";
}
else if (name == "System.Diagnostics.DiagnosticSource")
{
embname = "CDRTool.Embedded.System.Diagnostics.DiagnosticSource.dll";
}
else if (name == "System.Formats.Asn1")
{
embname = "CDRTool.Embedded.System.Formats.Asn1.dll";
}
else if (name == "System.Memory")
{
embname = "CDRTool.Embedded.System.Memory.dll";
}
else if (name == "System.Numerics.Vectors")
{
embname = "CDRTool.Embedded.System.Numerics.Vectors.dll";
}
else if (name == "System.Runtime.CompilerServices.Unsafe")
{
embname = "CDRTool.Embedded.System.Runtime.CompilerServices.Unsafe.dll";
}
else if (name == "System.Threading.Tasks.Extensions")
{
embname = "CDRTool.Embedded.System.Threading.Tasks.Extensions.dll";
}
else if (name == "System.ValueTuple")
{
embname = "CDRTool.Embedded.System.ValueTuple.dll";
}
else
{
embname = "something_bad";
}
//Console.WriteLine("returning assy: " + name);
using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(embname))
{
var assemblyData = new Byte[stream.Length];
stream.Read(assemblyData, 0, assemblyData.Length);
return Assembly.Load(assemblyData);
}
}
public static void Main(string[] args)
{
// Load Embedded Resources
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
//foreach (var resource in Assembly.GetExecutingAssembly().GetManifestResourceNames()) Console.WriteLine("Resource: " + resource);
Main2(args);
}
public static async void Main2(string[] args)
{
#if !PROD_
// LicenseFile.makeLicenseFile(licfile, "Support", 5, false);
LicenseFile.makeLicenseFile("license.txt", "Support", 1, true);
Console.WriteLine(LicenseFile.validate("license.txt"));
return;
#endif
// Clears 'async' compiler error
await System.Threading.Tasks.Task.CompletedTask;
// Enforce TLS1.2 Sep2017
ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072 | (SecurityProtocolType)768 | (SecurityProtocolType)192;
// Logging file
outfile = new StreamWriter(@""+logname,logappend);
outfile.AutoFlush = true;
string ban2 = product+" v"+version+" (c) 2022-2026 Sommet Consulting Inc.";
ban2 = "\u2551 " + ban2 + " \u2551";
string ban1 = "\u2554";
for ( int i = 2; i < ban2.Length; i++) { ban1 += "\u2550"; }
ban1 += "\u2557";
string ban3 = "\u255a";
for ( int i = 2; i < ban2.Length; i++) { ban3 += "\u2550"; }
ban3 += "\u255d";
Logger.Log(ban1); Logger.Log(ban2); Logger.Log(ban3);
//Logger.Log("--- UNLICENSED, FOR EVALUATION USE ONLY ---");
dynamic license;
Arguments myargs = new Arguments(args);
CookieContainer cookiejar = new CookieContainer();
if ( (myargs.Count < 1 ) || myargs.Exists("help") || myargs.Exists("h") )
{
Logger.Log(" usage: " + System.Diagnostics.Process.GetCurrentProcess().ProcessName + " [-options]");
//Console.WriteLine("retry: -retries n");
//Logger.Log("--- UNLICENSED, FOR EVALUATION USE ONLY ---");
Logger.Log(" login: -u user -p passwd");
Logger.Log(" time: -begin 8 -end 20 -interval 60");
Logger.Log(" path: -path " + ( Path.DirectorySeparatorChar.ToString()=="\\" ? "C:" : "") + "/directory/subdir");
Logger.Log(" sftp: -sh sftp.server -su user -sp passwd -sport 22 -spath CustomPath");
//Logger.Log(" debug: -debug n");
//Console.WriteLine("-fiddler"); // not needed with Fiddler v5.x
return;
}
WebProxy proxyObject = null;
#if !PROD_
{
//cdrtool Creds
if (myargs.Exists("dm"))
{
username = "Doug.Macintosh@rci.rogers.com";
password = "Rogers1!";
//clientInfo = "logging in as Doug Macintosh";
}
if (myargs.IsTrue("fiddler"))
{
Logger.Log("Enabling Fiddler Proxy");
proxyObject = new WebProxy("http://127.0.0.1:8888/"); // Fiddler proxy
//System.Net.WebRequest.DefaultWebProxy = new System.Net.WebProxy("127.0.0.1", 8888);
}
//}
#endif
if (myargs.Exists("debug"))
{
debug = int.Parse(myargs.Single("debug"));
Logger.Log(5, "Setting debug level to {0}", debug);
}
//}
if (myargs.Exists("path"))
{
dirpath = myargs.Single("path");
}
else
{
dirpath = "." + Path.DirectorySeparatorChar.ToString();
}
if (dirpath.EndsWith(Path.DirectorySeparatorChar.ToString())) { } else { dirpath += Path.DirectorySeparatorChar.ToString();}
Logger.Log(0,"Setting filestore path to {0}", dirpath);
int b = begin;
int e = end;
if (myargs.Exists("begin"))
{
b = int.Parse(myargs.Single("begin"));
}
if (myargs.Exists("end"))
{
e = int.Parse(myargs.Single("end"));
}
if ( ( e > b) && ( ( e > 0) && ( e <= 24 )) )
{
end = e;
}
else
{
Logger.Log(0,"Invalid parameter for end hour. Must be 0-24h and greater than begin hour.");
return;
}
if ( ( b < e ) && ( ( b >= 0 ) && ( b < 24 ) ) )
{
begin = b;
}
else
{
Logger.Log(0,"Invalid parameter for start hour. Must be 0-24h and less than end hour.");
return;
}
if (myargs.Exists("interval"))
{
int i = int.Parse(myargs.Single("interval"));
if ( ( i >= MIN_INT ) && ( i <= MAX_INT ) )
{
interval = i;
}
else
{
Logger.Log(0,"Invalid parameter for interval in minutes. Must be 10-360min");
return;
}
}
if (interval > 0)
{
Logger.Log(0,"Setting Timer Period {0}h to {1}h, {2}min interval", begin, end, interval);
}
else
{
Logger.Log(0,"Single Shot Mode. (set time: parameters to enable repetition).");
}
if (myargs.Exists("offset"))
{
prevMonOffset = int.Parse(myargs.Single("offset"));
Logger.Log(0, "Setting History File offset to -{0}", prevMonOffset);
}
if ((myargs.Exists("sh")) && (myargs.Exists("su")) && (myargs.Exists("sp")) )
{
ssh_host = myargs.Single("sh");
ssh_user = myargs.Single("su");
ssh_pass = myargs.Single("sp");
if (myargs.Exists("sport"))
{
ssh_port = int.Parse(myargs.Single("sport"));
}
if (myargs.Exists("spath"))
{
ssh_path = (myargs.Single("spath"));
}
sftp = true;
Logger.Log(0, "Uploading files as {3} to server: {0}:{1}{4}{2}", ssh_host, ssh_port, ssh_path, ssh_user, Path.DirectorySeparatorChar);
}
if ((myargs.Exists("u")) && (myargs.Exists("p")))
{
username = myargs.Single("u");
password = myargs.Single("p");
Logger.Log(0, "Setting authorized account to: {0}", username);
}
#if !PROD_
else if (myargs.Exists("dm"))
{
//already done
}
#endif
else
{
Logger.Log(0,"No valid login credentials found. Exiting.");
return;
}
// ***MAIN
//sftp.Upload_file("./CURRENT.csv", "10.0.0.3", 2222, "doug", "D4t4Guru");
//return;
do {
var now = DateTime.Now;
var start = new DateTime(now.Year, now.Month, now.Day, begin, 0, 0, now.Kind);
// Logger.Log(5," day of week: {0}", now.DayOfWeek);
TimeSpan span = now - start; // - TimeSpan.FromSeconds(1);
int m = (interval>0) ? interval - ((( span.Hours * 60 ) + span.Minutes ) % interval) : 0; //minutes to next logical interval
var nextTrigger = now + TimeSpan.FromMinutes(m>0 ? m:interval) - TimeSpan.FromSeconds(span.Seconds); // sync to next logical interval
Logger.Log(5," next event at: {0}",nextTrigger);
if( ( interval == 0 ) || ( now.Hour >= begin && now.Hour <= end))
{
// Work loop
bool LoggedIn = false;
int tries = 1;
//Login
do
{
Logger.Log(0,"Initiating connection...");
tries++;
try
{
LoggedIn = WebRoutines.Login( username, password, ref token, ref cookiejar, proxyObject );
if (!LoggedIn) { Logger.Log(1," retrying {0}",tries); }
}
catch (Exception)
{
Logger.Log("Error attempting to login to SIP Portal website");
if (!LoggedIn) { Logger.Log(1," retrying {0}",tries); }
}
}
while (!LoggedIn && (tries <= MAX_RETRY) );
if ( !LoggedIn )
{
Logger.Log("Aborting due to inability to login to SIP Portal website");
break; // DWMM Jan26
}
else
{
try
{
#if !PROD_
LicenseFile.makeLicenseFile(licfile, "Support", 5, false);
#endif
license = JObject.Parse(LicenseFile.validate(licfile));
}
catch (Exception ex)
{
Logger.Log("ERROR: Invalid License File!");
Logger.Log(5,ex.Message);
Logger.Log("Exiting.");
return;
}
string validity = (
((bool)license.Perpetual ? "Perpetual License: " : "License: ") + product + " has " +
((DateTime.Now <= (DateTime)license.ValidTo) ? (license.Type + " valid through " + license.ValidTo) :
((bool)license.Perpetual ? "Right to Use only." : "Expired on " + license.ValidTo)));
if (checkPrevMonth) Logger.Log(validity);
licensed = !validity.Contains("Expire");
if (licensed && checkPrevMonth) Logger.Log("For assistance please contact support@sommetconsulting.ca");
}
// Get Parameters
string wfr_guid = "";
string ch_guid = "";
string act_guid = "";
string co_guid = "";
string did_guid = "";
string year = "";
string mtd = "";
bool gotParams = false;
tries = 1;
do
{
try
{
if (licensed)
{
Logger.Log("Setting up...");
gotParams = WebRoutines.GetGUIDs(token, ref wfr_guid, ref ch_guid, ref act_guid, ref co_guid, ref did_guid,
ref year, ref mtd, ref cookiejar, proxyObject);
}
}
catch (Exception ex)
{
Logger.Log("Error navigating SIP Portal");
Logger.Log(5, ex.Message);
if (!gotParams) { tries++; Logger.Log(0, " retrying {0}", tries); }
}
}
while (!gotParams && (tries < MAX_RETRY));
if (!gotParams)
{
Logger.Log("Aborting due to inability to navigate SIP Portal.");
break; //return;
}
// Get files
string filename = "CURRENT.csv";
//filename = ""; // use system filename
bool gotMTDFile = false;
tries = 1;
do
{
try
{
if (licensed)
{
gotMTDFile = WebRoutines.GetMTDFile(dirpath, filename, token, ref act_guid, ref co_guid, ref did_guid,
ref year, ref mtd, ref cookiejar, proxyObject);
}
}
catch (Exception ex)
{
Logger.Log("Error attempting to download MTD File.");
Logger.Log(5, ex.Message);
if (!gotMTDFile) { tries++; Logger.Log(0, " retrying {0}", tries); }
}
}
while (!gotMTDFile && (tries < MAX_RETRY));
if (!gotMTDFile)
{
Logger.Log("Exiting due to inability to download Month-to-Date file.");
break; // return;
}
bool gotCDRHistoryFile = false;
tries = 1;
do
{
try
{
if (checkPrevMonth && licensed)
{
filename = ""; // use system filename
gotCDRHistoryFile = WebRoutines.GetCDRHistoryFile(dirpath, filename, prevMonOffset, token, ref act_guid, ref co_guid, ref did_guid,
ref year, ref mtd, ref cookiejar, proxyObject);
}
else
{
gotCDRHistoryFile = true;
}
}
catch (Exception ex)
{
Logger.Log("Error attempting to download History File.");
Logger.Log(5, ex.Message);
if (!gotCDRHistoryFile) { tries++; Logger.Log(0, " retrying {0}", tries); }
}
}
while (!gotCDRHistoryFile && (tries < MAX_RETRY));
if (!gotCDRHistoryFile)
{
Logger.Log("Aborting due to inability to download CDR Monthly History file.");
break; // return;
}
checkPrevMonth = false;
Logger.Log(3,"Trigger hour {0} Now hour {1}", nextTrigger.Hour, now.Hour);
//if (( interval > 0) && ( nextTrigger.Hour <= ( now.Hour + 1)) ) // NEED TO HANDLE MIDNIGHT ROLLOVER STILL
if ( (interval > 0) ) // NEED TO HANDLE MIDNIGHT ROLLOVER STILL
{
Logger.Log(0,"Completed CDR processing. Next event at {0:00}h{1:00}", nextTrigger.Hour, nextTrigger.Minute);
}
else
{
Logger.Log(0,"Completed CDR processing.");
}
// LOG OUT
bool LoggedOut = WebRoutines.Logout(token, ref cookiejar, ref proxyObject);
//break; // exit while() loop we are using as in 'IF'
} //END OF WORK LOOP
now = DateTime.Now; // reset and clean up in case we started just before the next cycle was to start
// Moved stuff
span = now - start; // - TimeSpan.FromSeconds(1);
m = (interval > 0) ? interval - (((span.Hours * 60) + span.Minutes) % interval) : 0; //minutes to next logical interval
nextTrigger = now + TimeSpan.FromMinutes(m > 0 ? m : interval) - TimeSpan.FromSeconds(span.Seconds); // sync to next logical interval
//Logger.Log(0, " span {0} m:{1} next trigger {2})", span, m, nextTrigger);
if ( ( now.Hour < begin || now.Hour > end || nextTrigger.Hour < begin || nextTrigger.Hour > end) && ( interval > 0 ) )
{
nextTrigger = new DateTime(now.Year, now.Month, now.Day, now.Hour, 0, 0, now.Kind) ;
nextTrigger += TimeSpan.FromHours( (24 - now.Hour + begin) % 24 );
Logger.Log(0,"Going to sleep until {0:00}h{1:00}", nextTrigger.Hour, nextTrigger.Minute); // begin is always less than end in any given 24h cycle
checkPrevMonth = true;
}
if (interval > 0)
{
//now = DateTime.Now;
// if ((nextTrigger - now) < TimeSpan.FromSeconds(1)) now -= TimeSpan.FromSeconds(1);
//nextTrigger += TimeSpan.FromMinutes(interval);
//Logger.Log(3,"values adjusted: trig:{0} now:{1}", nextTrigger, now);
//Logger.Log(3, " thread sleeping {0}", (nextTrigger - now));
Logger.Log(5, " thread sleeping {0} ({1} - {2})", (nextTrigger - now), (nextTrigger), (now.ToString("HH:mm:ss.fff")));
token = ""; // reset auth token for session
Thread.Sleep(nextTrigger - now + TimeSpan.FromSeconds(0.5));
}
}
while ( ( licensed || checkPrevMonth) && (interval > 0));
} // end of MAIN()
} // cdrtool class
public static class IDictionaryExtensions
{
public static TKey FindKeyByValue<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TValue value)
{
if (dictionary == null)
throw new ArgumentNullException("dictionary");
foreach (KeyValuePair<TKey, TValue> pair in dictionary)
if (value.Equals(pair.Value)) return pair.Key;
throw new Exception("the value is not found in the dictionary");
}
}
}