how to use xpath in vala on a node object - xpath

How do I use XPath in Vala on a Xml.Node object?
The only examples I can find is were a Context is created from a Doc object, but I don't have a Xml.Doc object to begin with. Is there a way I can convert Xml.Node into Xml.Doc? Or is there some other way?
The example I'm looking at is : https://live.gnome.org/Vala/XmlSample
Thanks.

The Xml.Node class has a Xml.Doc doc member. You should be able to use that to get the relevant Xml.Doc for a node.

I will be interested on this too, here is what I have been doing so far (I am just learning Vala)
// Get the node's name
string node_name = iter->name;
switch (node_name){
case "host":
this.host = (string) iter->get_content ();
break;
case "username":
this.username = (string) iter->get_content ();
break;
case "password":
this.password = (string) iter->get_content ();
break;
case "database":
this.database = (string) iter->get_content ();
break;
case "port":
this.port = (int)iter->get_content ();
break;
}
But for obvious reasons this works fine with a very small and simple xml but when you get to a more complex and bigger xml then your performance will suffer greatly.

Related

override GetAll to change Sort - example required

I am trying to override an AsyncCrudAppService call - "GetAll" in order to change the returned sort order.
Firstly, is overriding the method, in fact, the correct way to do this?
If yes, could I have an example as I'm a bit lost on how to do this with a PagedResultDto<T> return type?
If not please let me know where I can find out how.
Technically you can, but really shouldn't do sorting in GetAll() if it can be avoided. CRUD App Services also define virtual method ApplySorting() which is already used by GetAll and can also be overridden.
You can pass the string to dynamically sort by when calling the GetAll() and it will already work.
await _myAppService.GetAll(new PagedAndSortedResultRequestDto() { Sorting = "Name DESC", MaxResultCount = pageSize, SkipCount = skipCount })
If you'd like to have more control over sorting behavior, like use something default or pass in better-formatted query strings, override ApplySorting()
protected override IQueryable<SomeEntity> ApplySorting(IQueryable<SomeEntity> query, PagedAndSortedResultRequestDto input)
{
var sortBy = "LastModificationTime DESC,CreationTime DESC";
switch (input.Sorting?.ToLower())
{
case "name-asc":
sortBy = "Name";
break;
case "name-desc":
sortBy = "Name DESC";
break;
}
input.Sorting = sortBy;
return base.ApplySorting(query, input);
}

Apache Camel XPath with nodelist

I would like to concatenate all values from the Apache Camel XPath result and add it to the message context. The header should look like: "|value1|value2|valueN|"
My route looks like:
from("direct:test")
.setHeader("key").xpath("//Identifier", List.class)
.to("mock:result")
What is the best way for doing that? Is there a way to implement an own result type?
As Willem said, you have to write your own processor.
For such a little thing, my favourite way is to declare a function in the class containing the route definition returning an anonymous Processor like this:
private Processor setHeaderWithIdentifiers() {
return exchange -> {
List<String> identifiers = new ArrayList<>();
NodeList nodes = XPathBuilder.xpath("//Identifier").evaluate(exchange, NodeList.class);
for (int i = 0; i < nodes.getLength(); i++) {
identifiers.add(nodes.item(i).getNodeValue());
}
// StringUtils from Apache Commons 3
String idAsString = StringUtils.join(identifiers, "|");
exchange.getIn().setHeader("key", idAsString);
};
}
With that, you do not need to find any complex XPath functions and the code remains clear to understand as long the Processor code remains short.

Searching a list using an array as the parameter list using LINQ

I currently have some code that looks like this
string[] contains = new string[]{"marge", "homer", "lisa", "bart", "maggie"};
string[] actions = new string[]{"get dye", "mmm beer", "blow saxophone", "have a cow", "bang"};
for (int i = 0; i < someActions.Count; ++i)
{
if (someActions.Contains(contains[i]))
callRoutine(actions[i]);
}
(this is a very trivial example - someActions is a List)
I'm wondering if there is a way in LINQ to do the same as loop? I'm thinking of something along the lines of
int i = position in contains or 0
callRoutine(actions[i]);
The problem is that I don't know how to use an array as the search parameter. Various searches suggest I need to use IEnumerable to do this, but I'm not sure.
Any help would be appreciated here.
Paul
This wouldn't work nicely with your current data setup.
If you are flexible on your data, you could try this:
var namesToActions = new Dictionary<string, string>()
{
{ "marge" , "get dye" },
{ "homer", "mmm beer"},
{ "lisa", "blow saxophone"},
{ "bart", "have a cow"},
{ "maggie", "bang"}
};
someActions.ForEach(a => callRoutine(namesToActions[a]));
Switching to a Dictionary makes it a little easier to perform the type of Linq action you're looking for and provides additional flexibility and quicker lookup times.
I'm not sure what your purpose is, but if you want to convert your for loop into a linq statement, you can do this:
var i = 0;
someActions.ForEach(x =>
{
if (someActions.Contains(contains[i]))
callRoutine(actions[i]);
i++;
});
someActions.Intersect(contains).ForEach(callRoutine);
OR
someActions.Intersect(contains).ForEach(i=>callRoutine(i));

ASP.NET MVC - Integrating zetetic security with NHibernate Membership Provider

zetetic has a pretty sweet encryption library that includes support for bcrypt2. It looks like it should be straightforward enough to incorporate into an ASP.NET Membership Provider (in fact, instructions for the default provider can be found here). I am using an NHibernate Membership Provider (found here) which seems to hard code the SHA1 hash format in it's EncodePassword function. My question is, how should this be adapted to work with BCrypt2 (specifically Zetetic's wrapper). This is something I greatly fear getting wrong, and I'm reluctant to take a stab at it myself lest it should "work" but have some hidden flaw that I am not qualified to find.
private string EncodePassword(string password)
{
string encodedPassword = password;
switch (PasswordFormat)
{
case MembershipPasswordFormat.Clear:
break;
case MembershipPasswordFormat.Encrypted:
encodedPassword =
Convert.ToBase64String(EncryptPassword(Encoding.Unicode.GetBytes(password)));
break;
case MembershipPasswordFormat.Hashed:
HMACSHA1 hash = new HMACSHA1();
hash.Key = HexToByte(_machineKey.ValidationKey);
encodedPassword =
Convert.ToBase64String(hash.ComputeHash(Encoding.Unicode.GetBytes(password)));
break;
default:
throw new ProviderException("Unsupported password format.");
}
return encodedPassword;
}
Are you modifying the NHibernate-based membership provider, or stuck using it out of the box? If the latter, it doesn't look like there's any extensibility.
The ASP.NET SqlMembershipProvider works by accepting the name of a hash algorithm, conjures an instance via HashAlgorithm.Create(name) and then behaves a little differently if the algorithm type turns out to be a KeyedHashAlgorithm or regular (non-keyed) HashAlgorithm. The Zetetic.Security package is just providing a little bit of glue to make BCrypt and PBKDF2 compatible with that model.
The sample code from NHMembershipProvider can't take advantage of that because it's very directly relying on HMACSHA1. I'd note that HMACSHA1 is not a secure algorithm for this purpose, nor is using a static salt for all users acceptable (it's scarcely better than no salt). The app ValidationKey and HMACSHA1 are meant for message integrity only.
Here's a sample:
public class HashDemo
{
private static readonly RNGCryptoServiceProvider s_rng = new RNGCryptoServiceProvider();
public string HashPassword(string pwd, string hashName)
{
var alg = HashAlgorithm.Create(hashName);
if (alg == null)
throw new ArgumentException("Invalid hash name", "hashName");
byte[] tohash = System.Text.Encoding.UTF8.GetBytes(pwd);
var ka = alg as KeyedHashAlgorithm;
if (ka != null)
{
if (ka.Key == null || ka.Key.Length == 0)
{
byte[] key = new byte[20];
s_rng.GetBytes(key);
ka.Key = key;
}
else
{
s_rng.GetBytes(ka.Key);
}
// TODO: return base64(ka.Key || alg.ComputeHash(tohash))
}
else
{
var salt = new byte[20];
s_rng.GetBytes(salt);
using (var ms = new System.IO.MemoryStream(salt))
{
ms.Write(tohash, 0, tohash.Length);
tohash = ms.ToArray();
}
// TODO: return base64(salt || alg.ComputeHash(tohash))
}
}
}

How do I read the Received Date from Outlook MSG files -without- the Outlook API?

I need to read stuff from an Outlook msg file. Currently I'm using a class from CodeProject.com project to accomplish this, since deploying VSTO and Outlook on a server is not an option.
This class gets To, From, CC, Subject, Body, and everything else I need from the msg file, except Date information (such as Received Date and Sent Date).
There is some (really, really low-level) documentation on how to get stuff out of msg files on MSDN, but it's a little beyond the scope of this project and doesn't mention dates at all.
Ideally I'd be able to have a drop-in replacement for the class I am using now (OutlookStorage.cs in the previously mentioned CodeProject) or be able to modify the existing class a bit. To modify, I would need the correct 4 character hexidecimal prop identifier for received date. For instance, Subject is listed as PR_SUBJECT = "0037" and Body is listed as PR_BOY = "1000".
If you're using OutlookStorage.cs from CodeProject, then add the following:
private const string PR_RECEIVED_DATE="007D";
private const string PR_RECEIVED_DATE_2 = "0047";
...
/// <summary>
/// Gets the date the message was received.
/// </summary>
public DateTime ReceivedDate
{
get
{
if (_dateRevieved == DateTime.MinValue)
{
string dateMess = this.GetMapiPropertyString(OutlookStorage.PR_RECEIVED_DATE);
if (String.IsNullOrEmpty(dateMess))
{
dateMess = this.GetMapiPropertyString(OutlookStorage.PR_RECEIVED_DATE_2);
}
_dateRevieved = ExtractDate(dateMess);
}
return _dateRevieved;
//return ExtractDate(dateMess);
}
}
private DateTime _dateRevieved = DateTime.MinValue;
private DateTime ExtractDate(string dateMess)
{
string matchStr = "Date:";
string[] lines = dateMess.Split(new String[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
foreach (string line in lines)
{
if (line.StartsWith(matchStr))
{
string dateStr = line.Substring(matchStr.Length);
DateTime response;
if (DateTime.TryParse(dateStr, out response))
{
return response;
}
}
}
return DateTime.MinValue;
}
I think the Aspose library will do what you want, ok it a 3rd party lib so may not be what you want. There are a few vbs scripts around that get basic infomation out of msg files that could be translated.
Got a hint from this:
string fullFileName = "c:\message.msg";
DateTime dateRevieved = new DateTime();
StreamReader sr = new StreamReader(fullFileName, Encoding.Default);
string full = sr.ReadToEnd();
string date;
int iStart;
int iLast;
string caption;
//This -should- handle all manner of screwage
//The ONLY way it would not is if someone guessed the -exact- to-the-second
//time that they send the message, put it in their subject in the right format
while (true) { //not an infinite loop, I swear!
caption = "Date:";
if (full.IndexOf("Date:") > -1) { //full shortens with each date is removed
string temp = "";
iStart = full.LastIndexOf(caption);
temp = full.Remove(0, iStart + caption.Length);
full = full.Substring(0, iStart);
iLast = temp.IndexOf("\r\n");
if (iLast < 0) {
date = temp;
} else {
date = temp.Substring(0, iLast);
}
date = date.Trim();
if (date.Contains(subject) || subject.Contains(date)) {
continue; //would only happen if someone is trying to screw me
}
try {
dateRevieved = DateTime.Parse(date); //will fail if not a date
break; //if not a date breaks out of while loop
} catch {
continue; //try with a smaller subset of the msg
}
} else {
break;
}
}
This is kind of a hack compared to the ways you can get other things from msg files using something this lovely project. Still, it's stood up to everything I have thrown against it, and as noted the -only- way to fool it is to put the exact to-the-second date in the subject line in the proper format.
to combine your two posts I would suggest the following solution:
To modify, I would need the correct 4 character hexidecimal prop identifier for recieved date. For instance, Subject is listed as PR_SUBJECT = "0037" and Body is listed as PR_BOY = "1000".
Look for "007D".
Use the method you posted in your second post on the received data to eliminate the problem when the same (date) string is inside the subject.
I have to mention that this method doesn't seem to work on internal eMails: In mails I receive from colleagues, there is no substg1.0_007Dxxxx-Property.
Here, the date seems to be hidden in substg1.0_0047xxxx.
All the best!
inno

Resources