Reading artist metadata from DBus in lua script - weird output - lua

I'm trying to reading in DBus metadata from nuvolaplayer in a Lua script. The (track) title and album fields display as expect, but the artist data appears oddly:
lgi.rec 0x7f9ee8005c90:GLib.Variant Underwater Dub Dictionary
Where "Sly & Robbie" is expected in place of "lgi.rec 0x7f9ee8005c90:GLib.Variant".
When I look at the value using d-feet, I can see that the xesam:artist field differs from the others in being surrounded by []s.
Here's the code I'm using:
local lgi = require 'lgi'
local Gio = lgi.require 'Gio'
local core = require 'lgi.core'
local GLib = lgi.require 'GLib'
local type,unpack = type,unpack
local bus = Gio.bus_get_sync(Gio.BusType.SESSION)
local ret,err = bus:call(
"org.mpris.MediaPlayer2.nuvolaplayer",
--"org.gnome.Rhythmbox3",
"/org/mpris/MediaPlayer2",
"org.freedesktop.DBus.Properties",
"GetAll",
GLib.Variant.new_tuple(
{
GLib.Variant("s","org.mpris.MediaPlayer2.Player")
}, 1),
nil,
Gio.DBusConnectionFlags.NONE,
-1, -- Timeout
nil, -- Cancellable
function(conn, res)
local ret, err = bus:call_finish(res)
print("here",err)
local returnValue1, returnValue2 = unpack(ret.value)
if not err then
print("META", returnValue1.Metadata["xesam:artist"],
returnValue1.Metadata["xesam:album"],
returnValue1.Metadata["xesam:title"])
end
end
)
local main_loop = GLib.MainLoop()
main_loop:run()

The field xesam:artist is a list/array of strings (artists). Maybe Lua needs special handling of this type for printing, for example iterate the array and extract plain strings from it.

Related

Profinet LUA dissector without ports to extract specific bits

How can I make a Lua dissector/post-dissector/chained dissector that would get attached under the PROFINET IO Cyclic Service Data Unit and for example extract only the last 3 bits of the 5th byte, highlighted in the image below?
All the examples of Lua dissectors I could find are attached to some ports. Profinet does not use TCP/IP layer so there are no ports to attach to.
You should be able to achieve what you want using the following example as a rough guide, where I illustrate both how to add the field to the tree as well as to grab the data and do something with it (e.g., append the relevant data to the Info column):
local pn_io_post = Proto("PNIOPost", "PNIO Postdissector")
local pf = {
afield = ProtoField.uint8("pn_io_post.afield", "A Field", base.DEC, nil, 0x03, "A Field Description")
}
pn_io_post.fields = pf
local pn_io_data = Field.new("pn_io")
function pn_io_post.dissector(tvbuf, pinfo, tree)
local pn_io_post_tree
local pn_io_data_ex = pn_io_data()
if pn_io_data_ex ~= nil then
local pn_io_data_tvb = pn_io_data_ex.range()
local afield
pn_io_post_tree = tree:add(pn_io_post, pn_io_data_tvb(0, -1))
pn_io_post_tree:add(pf.afield, pn_io_data_tvb(4, 1))
afield = pn_io_data_tvb(4, 1):uint()
afield = bit.band(0x03, afield)
pinfo.cols.info:append(" [A Field = " .. afield .. "]")
end
end
register_postdissector(pn_io_post)

LUA: Looking for a specific table by its variable

I'm currently starting work on a text adventure game in Lua--no addons, just pure Lua for my first project. In essence, here is my problem; I'm trying to find out how I can do a "reverse lookup" of a table using one of its variables. Here's an example of what I've tried to do:
print("What are you trying to take?")
bag = {}
gold = {name="Gold",ap=3}
x = io.read("*l")
if x == "Gold" then
table.insert(bag,gold)
print("You took the " .. gold.name .. ".")
end
Obviously, writing a line like this with every single object in the game would be very... exhausting--especially since I think I'll be able to use this solution for not just taking items but movement from room to room using a reverse lookup with each room's (x,y) coordinates. Anyone have any ideas on how to make a more flexible system that can find a table by the player typing in one of its variables? Thanks in advance!
-blockchainporter
This doesn't directly answer your question as you asked it, but I think it would serve the purpose of what you are trying to do. I create a table called 'loot' which can hold many objects, and the player can place any of these in their 'bag' by typing the name.
bag = {}
loot = {
{name="Gold", qty=3},
{name="Axe", qty=1},
}
print("What are you trying to take?")
x = io.read("*l")
i = 1
while loot[i] do
if (x == loot[i].name) then
table.insert(bag, table.remove(loot,i))
else
i = i + 1
end
end
For bonus points, you could check 'bag' to see if the player has some of that item already and then just update the quantity...
while loot[i] do
if (x == loot[i].name) then
j, found = 1, nil
while bag[j] do
if (x == bag[j].name) then
found = true
bag[j].qty = bag[j].qty + loot[i].qty
table.remove(loot,i)
end
j = j + 1
end
if (not found) then
table.insert(bag, table.remove(loot,i))
end
else
i = i + 1
end
end
Again, this isn't a 'reverse lookup' solution like you asked for... but I think it is closer to what you are trying to do by letting a user choose to loot something.
My disclaimer is that I don't use IO functions in my own lua usage, so I have to assume that your x = io.read("*l") is correct.
PS. If you only ever want objects to have a name and qty, and never any other properties (like condition, enchantment, or whatever) then you could also simplify my solution by using key/val pairs:
bag = {}
loot = { ["Gold"] = 3, ["Axe"] = 1 }
print("What are you trying to take?")
x = io.read("*l")
for name, qty in pairs(loot) do
if x == name then
bag.name = (bag.name or 0) + qty
loot.name = nil
end
end
I have a few notes to start before I specifically address your question. (I just want to do this before I forget, so please bear with me!)
I recommend printing to the terminal using stderr instead of stdout--the Lua function print uses the latter. When I am writing a Lua script, I often create a C-style function called eprintf to print formatted output to stderr. I implement it like this:
local function eprintf(fmt, ...)
io.stderr:write(string.format(fmt, ...))
return
end
Just be aware that, unlike print, this function does not automatically append a newline character to the output string; to do so, remember to put \n at the end of your fmt string.
Next, it may be useful to define a helper function that calls io.read("*l") to get an entire line of input. In writing some example code to help answer your question, I called my function getline--like the C++ function that has similar behavior--and defined it like this:
local function getline()
local read = tostring(io.read("*l"))
return read
end
If I correctly understand what it is you are trying to do, the player will have an inventory--which you have called bag--and he can put items into it by entering item names into stdin. So, for instance, if the player found a treasure chest with gold, a sword, and a potion in it and he wanted to take the gold, he would type Gold into stdin and it would be placed in his inventory.
Based on what you have so far, it looks like you are using Lua tables to create these items: each table has a name index and another called ap; and, if a player's text input matches an item's name, the player picks that up item.
I would recommend creating an Item class, which you could abstract nicely by placing it in its own script and then loading it as needed with require. This is a very basic Item class module I wrote:
----------------
-- Item class --
----------------
local Item = {__name = "Item"}
Item.__metatable = "metatable"
Item.__index = Item
-- __newindex metamethod.
function Item.__newindex(self, k, v)
local err = string.format(
"type `Item` does not have member `%s`",
tostring(k)
)
return error(err, 2)
end
-- Item constructor
function Item.new(name_in, ap_in)
assert((name_in ~= nil) and (ap_in ~= nil))
local self = {
name = name_in,
ap = ap_in
}
return setmetatable(self, Item)
end
return Item
From there, I wrote a main driver to encapsulate some of the behavior you described in your question. (Yes, I know my Lua code looks more like C.)
#!/usr/bin/lua
-------------
-- Modules --
-------------
local Item = assert(require("Item"))
local function eprintf(fmt, ...)
io.stderr:write(string.format(fmt, ...))
return
end
local function printf(fmt, ...)
io.stdout:write(string.format(fmt, ...))
return
end
local function getline()
local read = tostring(io.read("*l"))
return read
end
local function main(argc, argv)
local gold = Item.new("Gold", 3)
printf("gold.name = %s\ngold.ap = %i\n", gold.name, gold.ap)
return 0
end
main(#arg, arg)
Now, as for the reverse search which you described, at this point all you should have to do is check the user's input against an Item's name. Here it is in the main function:
local function main(argc, argv)
local gold = Item.new("Gold", 3)
local bag = {}
eprintf("What are you trying to take? ")
local input = getline()
if (input == gold.name) then
table.insert(bag, gold)
eprintf("You took the %s.\n", gold.name)
else
eprintf("Unrecognized item `%s`.\n", input)
end
return 0
end
I hope this helps!

Lua LGI unpack GLib.Variant object

I'm trying to get password from keyring for awesome-wm session (using DBus via lgi library).
I'm able to find keyring entry path, open communication session and unlock entry.
Then I call GetSecrets method and store result into secret variable.
According to the documentation it is supposed to be a struct Secret. Seems like lgi cannot handle this type and passes it as userdata type (at least I wasn't able to make it give access to struct fields). Is there a way to get struct Secret value field contents without writing custom C handler?
Here is the code:
local bus = Gio.bus_get_sync(Gio.BusType.SESSION, nil)
local attr = {}
attr[1] = {attribute = "value"} -- attribute-value pair to search for
-- search for secret path
local name = "org.freedesktop.secrets"
local object = "/org/freedesktop/secrets"
local interface = "org.freedesktop.Secret.Service"
local method = "SearchItems"
local message = Gio.DBusMessage.new_method_call(name, object, interface, method)
message:set_body(GLib.Variant("(a{ss})", attr))
local result, err = bus:send_message_with_reply_sync(message, Gio.DBusSendMessageFlags.NONE,
-1, nil)
local location
for _, l in result:get_body():pairs() do
if #l > 0 then location = l[1] end
end
print(location) -- returns "/org/freedesktop/secrets/collection/Default/1"
-- open session
local name = "org.freedesktop.secrets"
local object = "/org/freedesktop/secrets"
local interface = "org.freedesktop.Secret.Service"
local method = "OpenSession"
local message = Gio.DBusMessage.new_method_call(name, object, interface, method)
message:set_body(GLib.Variant("(sv)", {"plain", GLib.Variant("s", "")}))
local result, err = bus:send_message_with_reply_sync(message, Gio.DBusSendMessageFlags.NONE,
-1, nil)
local session = result:get_body()[2]
print(session) -- returns "/org/freedesktop/secrets/session/s4"
-- unlock key
local name = "org.freedesktop.secrets"
local object = "/org/freedesktop/secrets"
local interface = "org.freedesktop.Secret.Service"
local method = "Unlock"
local message = Gio.DBusMessage.new_method_call(name, object, interface, method)
message:set_body(GLib.Variant("(ao)", {{location}}))
local result, err = bus:send_message_with_reply_sync(message, Gio.DBusSendMessageFlags.NONE,
-1, nil)
-- at this point key property "Locked" if false. tested using d-feet
-- get secret
local name = "org.freedesktop.secrets"
local object = "/org/freedesktop/secrets"
local interface = "org.freedesktop.Secret.Service"
local method = "GetSecrets"
local message = Gio.DBusMessage.new_method_call(name, object, interface, method)
message:set_body(GLib.Variant("(aoo)", {{location},session}))
local result, err = bus:send_message_with_reply_sync(message, Gio.DBusSendMessageFlags.NONE,
-1, nil)
local secret = result:get_body()
print(#secret) -- returns "1"
print(secret) -- returns table address
print(type(secret)) -- returns "userdata"
-- lock key
local name = "org.freedesktop.secrets"
local object = "/org/freedesktop/secrets"
local interface = "org.freedesktop.Secret.Service"
local method = "Lock"
local message = Gio.DBusMessage.new_method_call(name, object, interface, method)
message:set_body(GLib.Variant("(ao)", {{location}}))
local result, err = bus:send_message_with_reply_sync(message, Gio.DBusSendMessageFlags.NONE,
-1, nil)
-- close session
local name = "org.freedesktop.secrets"
local object = location
local interface = "org.freedesktop.Secret.Session"
local method = "Close"
local message = Gio.DBusMessage.new_method_call(name, object, interface, method)
local result, err = bus:send_message_with_reply_sync(message, Gio.DBusSendMessageFlags.NONE,
-1, nil)
edit
When I do print(secret), lgi.rec 0x7f57d0014960:GLib.Variant is returned.
So, secret is an object. How can I retrieve value field from GLib.Variant object?
edit 2
secret:get_data_as_bytes():get_data() dumps struct in bytearray form; secret:print() returns formatted string of struct. I wonder if there's a better way.
edit 3
type of secret variable is (a{o(oayays)})
Code to recreate an object of that type:
local lgi = require 'lgi'
local Gio = lgi.require 'Gio'
local GLib = lgi.require 'GLib'
local var = GLib.Variant("(a{o(oayays)})", {{["/path/to/object"]={"/path/to/session","parameters","value","content_type"}}})
(Note that I didn't install this password manager or try any of this at all)
Last time I asked the author of LGI about such issue, the answer was:
I have submitted fix to Variant which restores this functionality. So
an example of use will be:
local function called_from_C(userdata)
local variant = GLib.Variant(userdata)
print(variant)
end
if you have to support older (well, released :) lgi versions, you can
use undocumented way:
local core = require 'lgi.core'
local function called_from_C(userdata)
local variant = core.record.new(GLib.Variant, userdata)
print(variant)
end
Note that there is other ways. To work around another such bugs, I also once created a C Lua plugin and just wrote that code in C. That's actually rather trivial with Lua [2].
Another way, if you use LuaJIT, is to use the built-in FFI to just-in-time compile the struct definition into a Lua object [1].
Finally, if the question is more about how to unpack "working" GVariant values once they are consumed properly by LGI, look at my code for this here https://github.com/Elv13/wirefu/blob/master/proxy.lua
[1] http://luajit.org/ext_ffi_api.html
[2] https://github.com/Elv13/lua_async_binding/blob/master/src/luabridge.c#L407
Finally I've found a solution. To unpack a value of a complex type, for example (a{o(oayays)}), one should use get_child_value function.
secret:get_child_value(0):get_child_value(0):get_child_value(1):get_child_value(2).value
Explanation: index tuple; index array; index dict; index tuple

Issues with LUA copy

I am using the following program to copy one file another. I am often seeing source and destination is not exactly the same (md5sum is different). Are there anything wrong with the below code?
local size = 2^13 -- good buffer size (8K)
local params = {...}
local srcfile = params[1]
local outfile = params[1] .. "_copy"
print (srcfile)
print (outfile)
local inf = io.open(srcfile, "r")
local of = io.open(outfile, "w")
while true do
local block = inf:read(size)
print(size)
if not block then break end
of:write(block)
end
inf:close()
of:close()
Thanks,
GL
You may want to use binary mode to ensure endline characters were not modified.
local inf = io.open(srcfile, "rb")
local of = io.open(outfile, "wb")

Wireshark Lua Dissector - How to use a TAP?

I would like to do some analysis on top of my custom protocol that is dissected via my lua dissector. Therefore I tried to do this
myproto_proto = Proto("myproto", "Myproto Protocol")
m_dest = ProtoField.uint16("myproto.dest", "Destination", base.HEX)
m_src = ProtoField.uint16("myproto.src", "Source", base.HEX)
myproto_proto.fields = { sm_dest, sm_src }
dofile(MYPROTO_PROTO_PATH.."parser.lua")
function myproto_proto.dissector(buffer, pinfo, tree)
pinfo.cols.protocol = "MYPROTO"
local subtree = tree:add(myproto_proto, buffer(), "Myproto Protocol Data")
parse_msg(buffer, pinfo, subtree) -- does the actual parsing and sets the fields
end
udp_table = DissectorTable.get("udp.port")
udp_table:add(9000,myproto_proto)
-- LISTENER / TAP
f_test = Field.new("myproto.dest") -- fails because "field does not exist"
local function my_tap()
local window = TextWindow.new("Myproto Tap")
local tap = Listener.new(nil, "myproto")
local counter = 0
function remove()
tap:remove()
end
window:set_atclose(remove)
function tap.packet(pinfo, buffer)
counter = counter + 1
end
function tap.draw(t)
window:append("Counter: \t" .. counter .. "\n")
end
function tap.reset()
window:clear()
counter = 0
end
retap_packets()
end
register_menu("My Tap", my_tap, MENU_TOOLS_UNSORTED)
My problem is, I'm unable to access the dissected data with a field extractor. So how else could I get the dissected data in my lua tap?
Thanks in advance.
It's a known problem that custom Lua Field objects aren't usable in OSX (it apparently works in Windows XP but not Windows 7).
There are a few ways to pass data from your dissector to your tap.
Option 1: Use a shared Lua table
Create a global dictionary that is keyed by the packet number (from pinfo.number, which is visible to both dissector and tap).
-- we omit the 'local' keyword to make `dict` a global variable
dict = {}
In your dissector, add the packet data to the dictionary:
dict[pinfo.number] = { dest = m_dest, src = m_src }
In your tap, you can access the data by a simple lookup.
print('dest', dict[pinfo.number].dest )
XXX: Requires a global; Duplicates storage for a variable that is already held in the protocol tree (and should be accessible from the tap).
Option 2: Use pinfo.private
This was added in the dev build (1.7.0). It's similar to the solution above. pinfo.private is a PrivateTable, which is a hash table that stores only strings.
In your dissector, add your data to the packet's private table:
pinfo.private["src"] = tostring(m_src)
pinfo.private["dest"] = tostring(m_dest)
In your tap, access the data from the pinfo object:
print('dest', pinfo.private["dest"] )
XXX: Can only store string values
Option 3: Reparse the buffer
In your tap, call your parser (i.e., from parser.lua) to reparse the data in buffer, which is passed to the tap.
XXX: Duplicates work already done by dissector (can double processing time for X-large capture files)

Resources