webService Error - c#

I am using Log Me In Rescue API to pull some reports from their web service (consumed as a web reference via Visual Studio 2010).
the report works.
However, when I try to run another report it gives me a:
getReport_PollRateExceeded
I spoke to Log Me In Rescue tech support staff, and they stated this is not an issue with their API, it's an issue with the code that i'm using. They had no limits on the number of reports you could pull from the server (they even allow you to do it real time).
I am querying their server only once ever 30 or so seconds, so i can't possibly be going over any set limit in .NET that i can think off.
The web service API can be found here:
https://secure.logmeinrescue.com/API/API.asmx
Their Wiki is here:
http://logmeinwiki.com/wiki/Rescue:API
The code i'm using is:
private void myReport_DoWork(object sender, DoWorkEventArgs e)
{
LMIR.getReportRet response = new LMIR.getReportRet();
while (response.ToString() != "getReport_OK")
{
response = proxy.getReport(iTechID, NODE_REF.NODE, sAuthCodes, out sReports);
}
}
I do not call that worker process again, until the user REQUESTS it, i even disable the request button in favor of a progress bar, waiting for the runworkercompleted() routine to finish.
But, sure enough, if i request within that 30 second limit, i receive the pollRateExceeded.
So i'm a b it confused.
Is this something that can be fixed in the app.config file?
I have since created a short program:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Net;
using System.Web;
using System.Windows.Forms;
using System.Xml;
using System.Xml.Linq;
using testLMIR.LMIR;
using System.Collections;
using System.Text.RegularExpressions;
namespace testLMIR
{
public partial class Form1 : Form
{
string sUser = "";
string sPass = "";
int iNodeID = 74249;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
LMIR.API proxy = new LMIR.API();
proxy.CookieContainer = new CookieContainer();
sUser = textBox1.Text.ToString();
sPass = textBox2.Text.ToString();
loginRet oLogin = proxy.login(sUser, sPass);
Console.WriteLine(oLogin.ToString());
string sAuthCode = "";
requestAuthCodeRet oAuthCodeReq = proxy.requestAuthCode(sUser, sPass, out sAuthCode);
string sReport = "";
getReportRet oGetReport = proxy.getReport(iNodeID,NODE_REF.NODE, sAuthCode, out sReport);
Console.WriteLine(oGetReport + "<br />");
Thread.Sleep(10000);
oGetReport = proxy.getReport(iNodeID, NODE_REF.NODE, sAuthCode, out sReport);
Console.WriteLine(oGetReport + "<br />");
Thread.Sleep(10000);
oGetReport = proxy.getReport(iNodeID, NODE_REF.NODE, sAuthCode, out sReport);
Console.WriteLine(oGetReport + "<br />");
Thread.Sleep(10000);
}
}
}
This program will take the login from 2 text boxes on the form, and take action when the button is pressed. Here's the results:
login_OK
getReport_OK<br />
getReport_PollRateExceeded<br />
getReport_PollRateExceeded<br />
If i'm reading this information correctly, i can see that even 30 seconds later, i still couldn't pull the report.
I highly doubt this is a limitation of the program, no?

Tight looping like that without any termination point other than success looks like a bad idea to me. What if the authentication has changed, for example? You'd hammer the service as hard as you could. I'd have a maximum retry limit if I were you. I'd also add some logging into your code, so you can see how often you do need to retry.
However, if the tech support staff claim that they don't have a limit, but it looks like you do, it's easy enough to find out for sure: log the traffic. Use Wireshark or Fiddler to log requests and responses. If you can show that the "PollRateExceeded" error is definitely from their service, I would certainly hope they'd look into that.
I suggest you write a short program which just pulls the report twice, ten seconds apart. If that does work, then you need to work out why it doesn't work for you in your normal code. If it doesn't work, send them that code, which should be short and complete. Give them the network trace at the same time. It'll be hard for them to argue with that.

According to the LMIR engineering team, the pollrateexceeded does indeed exist; you cannot request more than 1 piece of information in a 60 second period; only PinCodes will work with that. Anything else is 1 request per minute. No way around that, at this time.

Related

How to read the rating of a file efficiently in a C# WinForms app (or other extended file attributes)?

I'm a beginner programmer and I've been banging my head on my desk for a while because of this problem. Basically, I'm trying to write some code for an application I'm making that will be able to read the rating of multiple thousands of files quickly inside a specified folder.
I was actually able to write something that works, the problem is the performance. Here is the code in its entirety, I will explain why it is problematic in more detail below:
using System.Collections.Generic;
using System.Windows.Forms;
using Microsoft.WindowsAPICodePack.Shell;
using System.Diagnostics;
namespace Tests
{
public partial class Form1 : Form
{
List<string> Files = new List<string>();
public Form1()
{
InitializeComponent();
}
private void event_Form1_Shown(object sender, EventArgs e)
{
string File = #"D:\Downloads\1.png";
int NumberOfLoops = 5000;
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < NumberOfLoops; i++)
{
var file = ShellFile.FromFilePath(File);
int Rating = Convert.ToInt32(file.Properties.System.Rating.Value);
if (Rating == 0)
{
Files.Add(File);
}
}
sw.Stop();
MessageBox.Show("Time: " + sw.ElapsedMilliseconds.ToString() + "ms (" + NumberOfLoops.ToString() + "x)");
}
}
}
On my system, reading the rating of this one file 5000 times takes around 6200ms (local harddrive) and 21500ms if the file is on a network share.
The problem is, as I eluded before, that this code will be used to read the rating of way more files than 5000 (sometimes hundreds of thousands) and the performance is absolutely abysymal. What I have also learned is that Windows uses some form of caching for reading this kind of metadata from a file more rapidly once it has been read before, so reading a specific file's metadata over and over is the absolute best scenario in terms of performance.
But even though it might not be accurate, it is still a useful test to do in order to have some kind of benchmark to compare different methods of reading file extended attributes to see which one takes the least amount of time to complete. In real-world use, the app will actually have to read the ratings of a gigantic pool of different files, which slows things down by a factor of around 25 times by my testing (the 21500ms operation takes 578000ms for example, which is around 10 minutes so you can see why this is becoming a problem).
Since I know I'm a beginner and that my code is probably super inefficient, I started looking around for other methods of doing the same thing. So using this solution from a thread on a similar problem, I came up with this code:
using System.Collections.Generic;
using System.Windows.Forms;
using System.Diagnostics;
namespace Tests
{
public partial class Form1 : Form
{
List<string> Files = new List<string>();
Shell32.Shell app = new Shell32.Shell();
public Form1()
{
InitializeComponent();
}
private void event_Form1_Shown(object sender, EventArgs e)
{
string Folder = #"D:\Downloads\";
string File = "1.png";
int NumberOfLoops = 5000;
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < NumberOfLoops; i++)
{
var folderObj = app.NameSpace(Folder);
var filesObj = folderObj.Items();
var headers = new Dictionary<string, int>();
for (int j = 0; j < short.MaxValue; j++)
{
string header = folderObj.GetDetailsOf(null, j);
if (String.IsNullOrEmpty(header))
break;
if (!headers.ContainsKey(header)) headers.Add(header, j);
}
var testFile = filesObj.Item(File);
if (folderObj.GetDetailsOf(testFile, headers["Rating"]) == "Unrated")
{
Files.Add(Folder + File);
}
}
sw.Stop();
MessageBox.Show("Time: " + sw.ElapsedMilliseconds.ToString() + "ms (" + NumberOfLoops.ToString() + "x)");
}
}
}
Unfortunately, this method is even slower than the one before, clocking in at around 6700ms on my local harddrive and 23000ms on a network share. I also found these other solutions which seemed to be doing something to what I want, but I couldn't get them to work for various reasons:
https://stackoverflow.com/a/65349545 : the StorageFile.GetFileFromPathAsync call gives me an error even if I added Microsoft.Windows.SDK.Contracts into the project NuGet packages.
https://stackoverflow.com/a/48096438 : Using the popular TagLib-Sharp library, but unfortunately even though I was able to compile the code using this solution, I was not able to read the rating from a file (I was able to read the tags though, which are similar but not quite the thing I was looking for).
https://stackoverflow.com/a/29308647/19518435: This solution looked promising, but as another commenter mentionned, I have no idea what the FolderItem2 is supposed to be referencing. EDIT: Got this solution to work with some help, but unfortunately it is not really on par in terms of performance, see EDIT1 below for more details.
Ideally, I would like to find a way for this "benchmark" I've made to take around 1000ms or less (so in the realms of around 6-7 times faster than the first two methods).
I am really motivated to get this to work, but frankly I am out of ideas. It's kind of a frustrating situation because I know my code is probably very unoptimised or there might be a way more obvious way to do what I'm trying to achieve, but since I am very inexperienced I don't really know what else to try. So that's why I'm turning to you, any help would be greatly appreciated!
EDIT1: Was able to make two more methods work with some help, but unfortunately both are not very good in terms of performance. I compiled all 4 in this GitHub repo if anyone wants to take a second look at them, because I feel like there's a good chance my bad implementation is affecting performance: https://github.com/user-727/FileRatingReader

How can I scrape data from a Webpage after searching desired data using HTML Agility

I want to get information from this website
into my ASPX page using the HTML Agility Pack. But I cannot do that, since the data is loaded after I search the data in the webpage.
I need some data to be done continuously after an interval of 5 mins.
Results for searches in the website you've mentioned are rendered dynamically using Javascript and the data comes as Json response via Ajax. HtmlAgilityPack is intended to parse Html, not Json.
Consider using Selenium or iMacros drivers for .Net, or WebBrowser class provided Microsoft Framework. These tools run a browser in background, so they can run Javascript code in that page and render Html you want to scrape.
Just need to set up proper time out, so they will keep waiting until search results appear onto the page.
As #derloopkat already said. Just use Selenium.
The site uses javascript and ajax to update the HTML of the page. Even if you did a HTTP request like with the following url:
https://enquiry.indianrail.gov.in/ntes/NTES?action=getTrainsViaStn&viaStn=NDLS&toStn=null&withinHrs=2&trainType=ALL&6iop0ssrpi=1m1ol4ha86
You will only get back the following:
(function(){location.reload();/*ho ho ho ho*/})()
Meaning that the last parameter of the url:
&6iop0ssrpi=1m1ol4ha86
Is somekind of "password"(for lack of better word). That makes sure you can't just replay the replay the requests. Now you could try to crack this. But it is obscured in a javascript file that is 3396 lines of very dense code. So it is very hard(maybe even impossible) to find out what to send the server in order to receive the data you want.
Even better is that the response from the server will never be HTML but rather JSON. Formatted like this:
_obj_1511003507337 = {
trainsInStnDataFound:"trainRunningDataFound",
allTrains:[
{
trainNo:"14316",
startDate:"18 Nov 2017",
trainName:"INTERCITY EXP",
trnName:function(){return _LANG==="en-us"?"INTERCITY EXP":"इंटरसिटीएक्स."},
trainSrc:"NDLS",
trainDstn:"BE",
runsOn:"NA",
schArr:"Source",
schDep:"16:35, 18 Nov",
schHalt:"Source",
actArr:"Source",
delayArr:"RIGHT TIME",
actDep:"16:35, 18 Nov",
delayDep:"RIGHT TIME",
actHalt:"Source",
trainType:"MEX",
pfNo:"9"
} ,
trainNo:"12625",
startDate:"16 Nov 2017",
trainName:"KERALA EXPRESS",
trnName:function() { return _LANG === "en-us" ? "KERALA EXPRESS" : "केरलएक्स."},
trainSrc:"TVC",
trainDstn:"NDLS",
runsOn:"NA",
schArr:"13:45, 18 Nov",
schDep:"Destination",
schHalt:"Destination",
actArr:"16:56, 18 Nov",
delayArr:"03:11",
actDep:"Destination",
delayDep:"RIGHT TIME",
actHalt:"Destination",
trainType:"SUF",
pfNo:"4"
}
]
}
Here is the solution to get the HTML and data using Selenium.
using System;
using System.Collections.Generic;
using System.Net;
using HtmlAgilityPack;
using OpenQA.Selenium.Firefox;
using OpenQA.Selenium;
using System.Threading;
namespace test
{
class Program
{
public static void Main(string[] args)
{
string url = "https://www.google.com";
IWebDriver driver = new FirefoxDriver();
driver.Navigate().GoToUrl("https://enquiry.indianrail.gov.in");
Console.WriteLine("Step 1");
driver.FindElement(By.XPath("//a[#id='ui-id-2']")).Click();
Thread.Sleep(10000);
Console.WriteLine("Step 2");
driver.FindElement(By.XPath("//input[#id='viaStation']")).SendKeys("NEW DELHI [NDLS]");
Thread.Sleep(2000);
Console.WriteLine("Step 3");
driver.FindElement(By.XPath("//button[#id='viaStnGoBtn']")).Click();
//PRESS A KEY WHEN THE HTML IS FULLY LOADED
Console.ReadKey();
HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
doc.LoadHtml(driver.PageSource);
HtmlNodeCollection nodeCol = doc.DocumentNode.SelectNodes("//body//tr[#class='altBG']");
foreach(HtmlNode node in nodeCol){
Console.WriteLine("Trip:");
foreach(HtmlNode child in node.ChildNodes)
{
Console.WriteLine("\t" + child.InnerText);
}
}
//Console.WriteLine(doc.DocumentNode.InnerHtml);
Console.ReadKey();
}
The Thread.Sleep()'s should not be necessary. I just put them in as a precaution. Also the speed can be optimized if you use a different driver like PhantomJS which is a headless driver.

Can't get cached items back from memcached?

I just setup memcached on a ubuntu system i have on my network. Didn't change any options so everything is default. I think tried to connect to the server using Enyim. It doesn't fail but when i try to retrieve the items they are always null. I'm not much of a low level won't but i've been able to discern things from wireshark before so i decided to give it a try. I'haven't been able to discern anything but i noticed the first .Store() command i sent actually sent network packets to the correct address. Every .Store() command did absolutely nothing.
Here is my app.config:
I've tried both "Binary" & "Text" Protocols and they did the same thing.
Here is my c# code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using Enyim.Caching;
using Enyim.Caching.Configuration;
using Enyim.Caching.Memcached;
namespace MemCacheTest
{
internal class Program
{
private static void Main(string[] args)
{
//var config = new MemcachedClientConfiguration();
//config.Servers.Add(new IPEndPoint(new IPAddress(new byte[] {10, 0, 0, 1}), 11211));
//config.Protocol = MemcachedProtocol.Binary;
var mc = new MemcachedClient();
for (var i = 0; i < 100; i++)
mc.Store(StoreMode.Set, "Hello", "World");
mc.Store(StoreMode.Set, "MyKey", "Hello World");
Console.WriteLine(mc.Get("MyKey"));
Console.WriteLine("It should have failed!!!");
Console.ReadLine();
}
}
}
Does anyone know whats going on or how i could determine what is wrong? I thought it was strange that i wasn't getting any exceptions so i set an invalid ip address in the config file. Same results.
The short answer: If your service is running check your port, it should be blocked somehow. (did you add an exception for port 11211 in Ubuntu firewall(iptables)?)
telnet 10.0.0.1 11211 If you have a telnet client on your server this will show the port is inaccessible.
Enyim doesn't throw you an error even the port is inaccessible. yes, it's strange.
To add to dasun answer. When you install memcached by default its configured to only listen on the "lo/localhost" interface. Its the only security memcache really has. Even if you try to telnet locally and do specify the lo interface for example:
telnet 10.0.0.1 11211
it will fail. To fix you have to go into the memcached.conf file and comment out
# -l 127.0.0.1
and then restart the service

How do I automate SAP GUI with c#

I would like to automate an SAP GUI window using the C# language. I am able to do it in VBScript but code reuse is horrible. Besides Id like to use threading instead of having 80 or more processes running. Where can I find any documentation and samples of how to do this? Here is the code I am working with. Basically, the problem I am facing is - how do I make a connection to SAP GUI then create an SAP GUI on the fly then start making transactions and entering text in some fields.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using White.Core.Factory;
using White.Core.UIItems.Finders;
using White.Core.InputDevices;
using System.Threading;
using System.Diagnostics;
using SAP.Connector;
using SAP;
namespace SAP_Automation
{
class Program
{
public static void Main(string[] args)
{
string ExeSourceFile = #"C:\Program Files\SAP\SapSetup\setup\SAL\SapLogon.s8l";
White.Core.Application _application;
White.Core.UIItems.WindowItems.Window _mainWindow;
var c = SAP.Connector.Connection.GetConnection("**");
var c = new SAPConnection("ASHOST=*; GWHOST=*; GWSERV=*; ASHOST=*; SYSNR=00;USER=user; PASSWD=**;");
c.Open();
}
}
}
}
As you can see I can create a connection but I dont know how to create a session to the GUI and start entering text in fields. Any examples and samples would be appreciated.
This might be necro-threading but I was in a similar situation where I work. We needed SAP GUI Automation for testing purposes that could integrate with the rest of our homegrown automation platform written in C#. I helped create a proposal for one solution that took advantage of a SAP provided library for GUI automation that could be used as the basis for an automation layer for SAP.
Does the following file exist on your SAP file installation? x:\Program Files\SAP\FrontEnd\SAPGui\sapfewse.ocx?
If so, add it to Visual Studio (or whatever IDE you're using) as a reference. It is basically a class library which contains a bunch of SAP specific objects that will allow you to interact with. It is very effective because it exposes most of what you need from the SAP GUI. We discovered in other attempts that a lot of the objects in SAP were not available.
This is an early proof of concept I did. Start SAP with a connection string, enter credentials, navigate to a transaction code.
using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using SAPFEWSELib;
namespace SAPGuiAutomated
{
//created a class for the SAP app, connection, and session objects as well as for common methods.
public class SAPActive
{
public static GuiApplication SapGuiApp { get; set; }
public static GuiConnection SapConnection { get; set; }
public static GuiSession SapSession { get; set; }
public static void openSap(string env)
{
SAPActive.SapGuiApp = new GuiApplication();
string connectString = null;
if (env.ToUpper().Equals("DEFAULT"))
{
connectString = "1.0 Test ERP (DEFAULT)";
}
else
{
connectString = env;
}
SAPActive.SapConnection = SAPActive.SapGuiApp.OpenConnection(connectString, Sync: true); //creates connection
SAPActive.SapSession = (GuiSession)SAPActive.SapConnection.Sessions.Item(0); //creates the Gui session off the connection you made
}
public void login(string myclient, string mylogin, string mypass, string mylang)
{
GuiTextField client = (GuiTextField)SAPActive.SapSession.ActiveWindow.FindByName("RSYST-MANDT", "GuiTextField");
GuiTextField login = (GuiTextField)SAPActive.SapSession.ActiveWindow.FindByName("RSYST-BNAME", "GuiTextField");
GuiTextField pass = (GuiTextField)SAPActive.SapSession.ActiveWindow.FindByName("RSYST-BCODE", "GuiPasswordField");
GuiTextField language = (GuiTextField)SAPActive.SapSession.ActiveWindow.FindByName("RSYST-LANGU", "GuiTextField");
client.SetFocus();
client.text = myclient;
login.SetFocus();
login.Text = mylogin;
pass.SetFocus();
pass.Text = mypass;
language.SetFocus();
language.Text = mylang;
//Press the green checkmark button which is about the same as the enter key
GuiButton btn = (GuiButton)SapSession.FindById("/app/con[0]/ses[0]/wnd[0]/tbar[0]/btn[0]");
btn.SetFocus();
btn.Press();
}
}
//--------------------------//
//main method somewhere else
public static void Main(string[] args)
{
SAPActive.openSAP("my connection string");
SAPActive.login("10", "jdoe", "password", "EN");
SAPActive.SapSession.StartTransaction("VA03");
}
You're right there is not a lot of documentation on this subject. Below are a few sources that helped me get started
-Original source of our plan
http://scn.sap.com/thread/1729689
-Documentation on the API (For VB and javascript but the general rules and objects are identical). Definitely read the portion on the SAP GUI Runtime hierarchy. It'll answer a lot of questions.
http://www.synactive.com/download/sap%20gui%20scripting/sap%20gui%20scripting%20api.pdf
It is very important here to understand what UI Automation can do and what its limitations are. It was designed to automate a user interface's capabilities. You can click buttons, enter text in a textbox, move windows, etcetera, whatever a user can do using the mouse and keyboard.
What it can not do is bridge the tall wall that the operating system puts up between processes. A wall that prevents a process from accessing the memory of another process. This is a very important security and safety feature. It for one prevents a process from accessing data that should be private to a process. Like a password. And for another it stops a crashing process from affecting other processes that run on the machine. You can kill a process with Task Manager and everything keeps motoring along happily as though nothing happened.
A consequence of this is that creating a SAPConnection object in your program is a connection that only your program can use. There is no mechanism to somehow pass this object to another process with UI Automation. At best you could use the data you retrieve from the connection to affect what buttons you click.
The kind of process interop that would allow sharing data between processes is well supported in .NET. Low-level approaches are socket and named pipes, high-level are Remoting and WCF. Older programs have COM Automation support, Office is a good example of that. That however requires two to tango, both programs must be written to take advantage of it.
So if you are trying to automate an existing SAP application and this app does not otherwise explicitly support automation, the kind that an Office program supports, then you are pretty much stuck with just filling text boxes and clicking buttons.
You can automate any kind of application (browser, desktop, java, etc) with UiPath.
Here's a tutorial on how to automate data entry, menu navigation and screen scraping on SAP.
You can
use it from code (SDK). It has a tool that auto-generates C# code
create and run workflows (visual automation) directly from UiPath Studio.
Here's a sample of the C# auto-generated code:
// Attach window menu
UiNode wnd3 = UiFactory.Instance.NewUiNode().FromSelector("<wnd app='sap business one.exe' cls='#32768' idx='1' />");
// Click 'Business Pa...' menu
UiNode uiClickBusinessPamenu_3 = wnd3.FindFirst(UiFindScope.UI_FIND_DESCENDANTS, "<ctrl name='Business Partners' role='popup menu' /><ctrl automationid='2561' />");
uiClickBusinessPamenu_3.Click(88, 9, UiClickType.UI_CLICK_SINGLE, UiMouseButton.UI_BTN_LEFT, UiInputMethod.UI_HARDWARE_EVENTS);
// Attach window 'SAP Business'
UiNode wnd4 = UiFactory.Instance.NewUiNode().FromSelector("<wnd app='sap business one.exe' cls='TMFrameClass' title='SAP Business One 9.0 - OEC Computers' />");
// Click 'Add' button
UiNode uiClickAddbutton_4 = wnd4.FindFirst(UiFindScope.UI_FIND_DESCENDANTS, "<wnd cls='ToolbarWindow32' title='View' /><ctrl name='View' role='tool bar' /><ctrl name='Add' role='push button' />");
uiClickAddbutton_4.Click(13, 24, UiClickType.UI_CLICK_SINGLE, UiMouseButton.UI_BTN_LEFT, UiInputMethod.UI_HARDWARE_EVENTS);
Here's how workflow automation of SAP Business One menus, buttons or typing looks like:
And finally the SDK documentation is located here... in case you don't want to use workflows.
Note: I work at UiPath. You should also try other automation tools like Automation Anywhere, WinAutomation, Jacada, Selenium, Ranorex use them side by side and choose the one that suits better your needs.

C# redirect standardinput with PGP -ka command

I am having a problem which seems really daft. I must be missing something silly. We have a PGP keyring that is on one of our production servers. The user account it belongs to is not allowed to be logged on as interactively for security. Our problem is we sometimes need to add new keys and can not do this easily. So we thought we could create a quick console app that would be run as its ID and would call the PGP commands via the command line.
The command gets called but it asks for input to confirm what we are doing. Our problem is the "y" we send to standardinput is never displayed and the key is not verified.
here is the code:
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;
using System.DirectoryServices;
using System.Threading;
namespace TestConsoleApp
{
class RegExValidator
{
private System.Diagnostics.Process myProcess;
public RegExValidator()
{
}
public static void Main(string[] args)
{
RegExValidator myValidator = new RegExValidator();
myValidator.InstallKeys("C:\\Test\\batch.asc", "batch.asc");
}
private void InstallKeys(string keyPath, string keyName)
{
myProcess = new System.Diagnostics.Process();
myProcess.StartInfo.RedirectStandardInput = true;
myProcess.StartInfo.CreateNoWindow = false;
myProcess.StartInfo.UseShellExecute = false;
myProcess.StartInfo.FileName = "pgp";
myProcess.StartInfo.Arguments = "-ka " + keyPath + "";
myProcess.Start();
StreamWriter myInput = myProcess.StandardInput;
myInput.AutoFlush = true;
Thread.Sleep(3000);
myInput.WriteLine("y");
myInput.WriteLine(Environment.NewLine);
}
}
}
This is the output we get on the command line.
C:\Test>TestConsoleApp.exe
Pretty Good Privacy(tm) Version 6.5.2
(c) 1999 Network Associates Inc.
Uses the BSafe(tm) Toolkit, which is copyright RSA Data Security, Inc.
Export of this software may be restricted by the U.S. government.
WARNING: Environmental variable TZ is not defined, so GMT timestamps
may be wrong. See the PGP User's Guide to properly define TZ
Looking for new keys...
DSS 2048/1024 0xDE053A3D 2007/05/29 Batch Interface <batch#netgiro.com>
sig? 0xDE053A3D (Unknown signator, can't be checked)
keyfile contains 1 new keys. Add these keys to keyring ? (Y/n)
C:\Test>
Can anyone help?
Thanks
EDIT
We tried this process but instead of PGP we just moved a file and we got the Y/N box and that worked. It would seem that you may not be able to do it with PGP. No idea why though.
The message
keyfile contains 1 new keys. Add these keys to keyring ? (Y/n)
suggests replying with an Uppercase Y. try changing your call to:
myInput.WriteLine("Y");
(I have no PGP installed for checking, but have encountered other command line interfaces that insisted on case.)
Another thing to try is flushing stream buffers, which clears all buffers for the stream and causes any buffered data to be written to the underlying device:
myInput.WriteLine("Y");
myInput.Flush();

Categories

Resources