How do I read the data from a TYPE_MIME_PART item? - lotus-domino

It kinda works, but the problem is that it seems that the MIME_PART structure is not initialized ? all it's properties has the same values, even if I try to open a different mime item.
MIME_PART *pMime;
DHANDLE hPart;
char *pText;
WORD textLen;
if (error = NSFMimePartGetPart(bidLinksItem, &hPart)) {
goto exit;
}
pMime = OSLock(MIME_PART, hPart);
textLen = (pMime->wByteCount) - pMime->wHeadersLen - pMime->wBoundaryLen;
pText = (char *)pMime + sizeof(MIME_PART) + wHeadersLen;
char *itemText = (char *)malloc(textLen);
memcpy(itemText, pText, textLen);
itemText[textLen] = '\0';
OSUnlock(hPart);
The itemText string has most of the content, but since the MIME_PART structure is not properly set, the pointer to the text is off...
So how do I properly set the MIME_PART?

Your code should do something like this instead:
DHANDLE hPart;
char *pchPart;
if (error = NSFMimePartGetPart(bidLinksItem, &hPart)) {
goto exit;
}
pchPart = OSLock(char, hPart);
In other words, lock the handle as type char instead of type MIME_PART. At this point, pchPart points to the beginning of the raw part data -- starting with a boundary (if present) and the headers. You can use NSFMimePartGetInfoByBLOCKID to get the length of the boundary and headers.
I realize this contradicts the documentation, but I've confirmed with a subject matter expert: The documentation is wrong.

Wrong answer, but the comments may be useful. My other answer is more correct.
This question could be improved. For example, you could show some sample data and describe the results when you try to read that data with your code.
But I'll try to answer based on the information I have. You calculated the text length like this:
textLen = (pMime->wByteCount) - pMime->wHeadersLen - pMime->wBoundaryLen;
That looks right to me, but then you do this:
pText = (char *)pMime + sizeof(MIME_PART) + wHeadersLen;
Is wHeadersLen guaranteed to be equal to pMime->wHeadersLen? Also, you didn't consider the boundary length. Shouldn't you calculate the address like this instead?
pText = (char *)pMime + sizeof(MIME_PART) + pMime->wHeadersLen + pMime->wBoundaryLen;

Related

OpenEdge dynamic buffers... how do I avoid error 7328? ("unambiguous buffer field/reference for buffers known to a query")

Althogh I've been supporting (and extending) a legacy OE application for 10 years plus, I've never before been forced into the scary world of dynamic buffers... However, my luck has finally run out.
Let me start by saying I cannot believe how opaque the little OE documentation I could find is... the only Progress guide seems to be in the online documentation for v10.2 (thanks to the contributer to one of the forums for even that snippet.)
Anyway, this should be almost trivial. Except that it doesn't work;
DEFINE VARIABLE hFileBuffer AS WIDGET-HANDLE.
DEFINE VARIABLE hFieldBuffer AS WIDGET-HANDLE.
DEFINE VARIABLE cWhere AS CHARACTER.
DEFINE VARIABLE hQuery AS HANDLE.
CREATE BUFFER hFileBuffer FOR TABLE "_File".
CREATE BUFFER hFieldBuffer FOR TABLE "_Field".
CREATE QUERY hQuery.
hQuery:SET-BUFFERS(hFileBuffer).
hQuery:ADD-BUFFER(hFieldBuffer).
cWhere = SUBSTITUTE(
"FOR EACH _File " +
" NO-LOCK, " +
" EACH _Field " +
" WHERE _Field.File-recid = _File._File-recid " +
" NO-LOCK"
).
message cWhere.
pause.
hQuery:Query-PREPARE(cWhere).
hQuery:Query-OPEN().
DELETE OBJECT hQuery.
DELETE OBJECT hFileBuffer.
DELETE OBJECT hFieldBuffer.
ASSIGN hQuery = ?
hFileBuffer = ?
hFieldBuffer = ?.
The output from "message" is (after removing redundant spaces):
FOR EACH _File NO-LOCK, EACH _Field WHERE _Field.File-recid = _File._File-recid NO-LOCK
which looks fine to me.
However I then get:
_Field File-recid must be a quoted constant or an unabbreviated, unambiguous buffer/field reference for buffers known to query . (7328)
I just cannot see what is ambiguous about "_Field.File-recid" or "_File._File-recid". Or am I missing something? (I should add that the equivalent works in good ol'-fashioned static OpenEdge!)
Hoping someone wiser than I can advise,
Allan.
There are two issues in your dynamic query string:
a) It's RECID(_file) and not _file._file-recid (no _file-recid field on _file)
b) It's _field._file-recid and not _field.file-recid (underscore missing)
cWhere = SUBSTITUTE(
"FOR EACH _File " +
" NO-LOCK, " +
" EACH _Field " +
" WHERE _Field._File-recid = recid(_file)" +
" NO-LOCK"
).
You can enable the display of hidden fields in the Data Dictionary:
Just an example on ABL Dojo to watch your query fly:
def var hbfile as handle no-undo.
def var hbfield as handle no-undo.
def var hq as handle no-undo.
def var cquery as char no-undo.
create buffer hbfile for table '_file'.
create buffer hbfield for table '_field'.
create query hq.
hq:set-buffers( hbfile, hbfield ).
cquery = substitute(
'for each &1 where &1._hidden = false'
+ ', each &2 where &2._file-recid = recid( &1 )'
+ ' break by &1._file-name',
hbfile:name,
hbfield:name
).
hq:query-prepare( cquery ).
hq:query-open().
do while hq:get-next():
if hq:first-of( 1 ) then
message hbfile::_file-name.
message ' ' hbfield::_field-name.
end.
finally:
delete object hq no-error.
delete object hbfile no-error.
delete object hbfield no-error.
end finally.
A few additional issues with your snippet:
buffer handles are regular handles, no need for the meaningless widget- prefix
when working with dynamic buffers, it really helps to use the :name of the dynamic buffer, this allows you to change names without causing the query to fail

Getting the name of the variable as a string in GD Script

I have been looking for a solution everywhere on the internet but nowhere I can see a single script which lets me read the name of a variable as a string in Godot 3.1
What I want to do:
Save path names as variables.
Compare the name of the path variable as a string to the value of another string and print the path value.
Eg -
var Apple = "mypath/folder/apple.png"
var myArray = ["Apple", "Pear"]
Function that compares the Variable name as String to the String -
if (myArray[myposition] == **the required function that outputs variable name as String**(Apple) :
print (Apple) #this prints out the path.
Thanks in advance!
I think your approach here might be a little oversimplified for what you're trying to accomplish. It basically seems to work out to if (array[apple]) == apple then apple, which doesn't really solve a programmatic problem. More complexity seems required.
First, you might have a function to return all of your icon names, something like this.
func get_avatar_names():
var avatar_names = []
var folder_path = "res://my/path"
var avatar_dir = Directory.new()
avatar_dir.open(folder_path)
avatar_dir.list_dir_begin(true, true)
while true:
var avatar_file = avatar_dir.get_next()
if avatar_file == "":
break
else:
var avatar_name = avatar_file.trim_suffix(".png")
avatar_names.append(avatar_name)
return avatar_names
Then something like this back in the main function, where you have your list of names you care about at the moment, and for each name, check the list of avatar names, and if you have a match, reconstruct the path and do other work:
var some_names = ["Jim","Apple","Sally"]
var avatar_names = get_avatar_names()
for name in some_names:
if avatar_names.has(name):
var img_path = "res://my/path/" + name + ".png"
# load images, additional work, etc...
That's the approach I would take here, hope this makes sense and helps.
I think the current answer is best for the approach you desire, but the performance is pretty bad with string comparisons.
I would suggest adding an enumeration for efficient comparisons. unfortunately Godot does enums differently then this, it seems like your position is an int so we can define a dictionary like this to search for the index and print it out with the int value.
var fruits = {0:"Apple",1:"Pear"}
func myfunc():
var myposition = 0
if fruits.has(myposition):
print(fruits[myposition])
output: Apple
If your position was string based then an enum could be used with slightly less typing and different considerations.
reference: https://docs.godotengine.org/en/latest/tutorials/scripting/gdscript/gdscript_basics.html#enums
Can't you just use the str() function to convert any data type to stirng?
var = str(var)

How can this code be written shorter/clearer?

newRow("OrderReference") = line.Substring(line.IndexOf("*1003") + 5, line.IndexOf("*", line.IndexOf("*1003") + 5) - line.IndexOf("*1003") - 5)
There you have it. Very long and ugly. I was thinking about this:
Dim indexPlus = line.IndexOf("*1003") + 5
Dim indexMinus = line.IndexOf("*1003") - 5
newRow("OrderReference") = line.Substring(indexPlus, line.IndexOf("*", indexPlus) - indexMinus)
But that introduces new and meaningless vars. Unsatisfying.
Maybe RegEx is the savior here?
Unfortunately I mustn't change the input data :-(
The input data consist of the BWA-format (popular with books). Here you can see the part in question:
All codes in this example set are required. Only corresponding values change.
I don't even think your second code works. It seems more like this.
Dim index = line.IndexOf("*1003") + 5
newRow("OrderReference") = line.Substring(index, line.IndexOf("*", indexPlus) - index)
10 - 5 - 2 isn't the same as 10 - (5 - 2) but instead it's the same as 10 - (5 + 2).
Next time, check out the codereview stack exchange.
Given that your data is always constant, and what you're looking for always begins with "*1003", you don't need to use Regex (Even though you could). Just use what you're already using but with some corrections.
using System;
public class Program
{
public static void Main()
{
string input = "L10113540 VD44444 VD2002100234949 000116161 04201261\r\n";
input += " KN00010000000129000LPEUR003000001*1003A.Muller-Schulz*1017Bastei\r\n";
input += "Lubbe.61204 Laund.Meine Schuld*1019KL*102990300*1030NO*1032EUR*1131KT";
int start = input.IndexOf("*1003");
int end = input.IndexOf("*", start + 1);
string result = input.Substring(start + 5, end - start - 5);
Console.WriteLine(result);
// Your code
start = input.IndexOf("*1003") + 5;
end = input.IndexOf("*1003") - 5;
result = input.Substring(start, input.IndexOf("*", start) - end);
Console.WriteLine(result);
}
}
Result
A.Muller-Schulz
A.Muller-Schulz*1017Baste
You can see that what you posted in your question, doesn't give the results you want. All you're really looking for is just the next asterisk after the first "*1003". You can see the difference between your code and what I've given.
.NET Fiddle Example

how to make a function that prints a variable number of parameters in pascal?

I want to let the user give me a variable number of strings (as virables).
example :
begin
cout('Hello').(' ').('world')
end.
this will print: "Hello world"
I know I just can let him input a string but I want to this code to work...
I think a record will help nut I dont know how
thank you
Im not sure what is that code example you have written ... but i try to help you.
Program test;
uses crt;
var string1,string2,string3:string;
begin
write("Write to first string : "); readln(string1);
write("Write to second string: "); readln(string2);
write("Write to third string : "); readln(string3);
String2:= string1 +" "+ string3; // it will add first with third string to one with one space
String3:= string2 +" "+ string1;// also 2.+ 1.
clrscr; //clearscreen (in CRT)
writeln("1. = 1.");
writeln("2. = 1. + 3.");
writeln("3. = 2. + 1.");
writeln;
writeln(string1);
writelm(string2);
writeln(string3);
I havent tested this (i have written it now for you) i think you will read it and learn how to addict or how to do simple with strings.

How to filter out some vulnerability causing characters in query string?

I need to filter out characters like /?-^%{}[];$=*`#|&#'\"<>()+,\. I need replace this with empty string if it is there in the query string. Please help me out. I am using this in ASP pages.
Best idea would be to use a function something along the lines of:
Public Function MakeSQLSafe(ByVal sql As String) As String
'first i'd avoid putting quote chars in as they might be valid? just double them up.
Dim strIllegalChars As String = "/?-^%{}[];$=*`#|&#\<>()+,\"
'replace single quotes with double so they don't cause escape character
If sql.Contains("'") Then
sql = sql.Replace("'", "''")
End If
'need to double up double quotes from what I remember to get them through
If sql.Contains("""") Then
sql = sql.Replace("""", """""")
End If
'remove illegal chars
For Each c As Char In strIllegalChars
If sql.Contains(c.ToString) Then
sql = sql.Replace(c.ToString, "")
End If
Next
Return sql
End Function
This hasn't been tested and it could probably be made more efficient, but it should get you going. Wherever you execute your sql in your app, just wrap the sql in this function to clean the string before execution:
ExecuteSQL(MakeSQLSafe(strSQL))
Hope that helps
As with any string sanitisation, you're much better off working with a whitelist that dictates which characters are allowed, rather than a blacklist of characters that aren't.
This question about filtering HTML tags resulted in an accepted answer suggesting the use of a regular expression to match against a whitelist: How do I filter all HTML tags except a certain whitelist? - I suggest you do something very similar.
I'm using URL Routing and I found this works well, pass each part of your URL to this function. It's more than you need as it converts characters like "&" to "and", but you can modify it to suit:
public static string CleanUrl(this string urlpart) {
// convert accented characters to regular ones
string cleaned = urlpart.Trim().anglicized();
// do some pretty conversions
cleaned = Regex.Replace(cleaned, " ", "-");
cleaned = Regex.Replace(cleaned, "#", "no.");
cleaned = Regex.Replace(cleaned, "&", "and");
cleaned = Regex.Replace(cleaned, "%", "percent");
cleaned = Regex.Replace(cleaned, "#", "at");
// strip all illegal characters like punctuation
cleaned = Regex.Replace(cleaned, "[^A-Za-z0-9- ]", "");
// convert spaces to dashes
cleaned = Regex.Replace(cleaned, " +", "-");
// If we're left with nothing after everything is stripped and cleaned
if (cleaned.Length == 0)
cleaned = "no-description";
// return lowercased string
return cleaned.ToLower();
}
// Convert accented characters to standardized ones
private static string anglicized(this string urlpart) {
string beforeConversion = "àÀâÂäÄáÁéÉèÈêÊëËìÌîÎïÏòÒôÔöÖùÙûÛüÜçÇ’ñ";
string afterConversion = "aAaAaAaAeEeEeEeEiIiIiIoOoOoOuUuUuUcC'n";
string cleaned = urlpart;
for (int i = 0; i < beforeConversion.Length; i++) {
cleaned = Regex.Replace(urlpart, afterConversion[i].ToString(), afterConversion[i].ToString());
}
return cleaned;
// Spanish : ÁÉÍÑÓÚÜ¡¿áéíñóúü"
}