# HG changeset patch # User Kim Alvefur # Date 1313350208 -7200 # Node ID 582afbb2b23d7f4c94a0bc5af88a1e9b81bd2825 # Parent bbbef9f4a798554690824e5c0c8a0ba37ff0fde2 clix.vcard, squishy: Add plugin that fetches and converts peoples vCards to the text format. diff -r bbbef9f4a798 -r 582afbb2b23d clix/vcard.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/clix/vcard.lua Sun Aug 14 21:30:08 2011 +0200 @@ -0,0 +1,250 @@ +local t_insert, t_concat = table.insert, table.concat; + +local vCard_dtd = { + VERSION = "ignore", --MUST be 3.0, so parsing is redundant + FN = "text", + N = { + values = { + "FAMILY", + "GIVEN", + "MIDDLE", + "PREFIX", + "SUFFIX", + }, + }, + NICKNAME = "text", + PHOTO = { + props_verbatim = { ENCODING = { "b" } }, + props = { "TYPE" }, + value = "BINVAL", --{ "EXTVAL", }, + }, + BDAY = "text", + ADR = { + types = { + "HOME", + "WORK", + "POSTAL", + "PARCEL", + "DOM", + "INTL", + "PREF", + }, + values = { + "POBOX", + "EXTADD", + "STREET", + "LOCALITY", + "REGION", + "PCODE", + "CTRY", + } + }, + LABEL = { + types = { + "HOME", + "WORK", + "POSTAL", + "PARCEL", + "DOM", + "INTL", + "PREF", + }, + value = "LINE", + }, + TEL = { + types = { + "HOME", + "WORK", + "VOICE", + "FAX", + "PAGER", + "MSG", + "CELL", + "VIDEO", + "BBS", + "MODEM", + "ISDN", + "PCS", + "PREF", + }, + value = "NUMBER", + }, + EMAIL = { + types = { + "HOME", + "WORK", + "INTERNET", + "PREF", + "X400", + }, + value = "USERID", + }, + JABBERID = "text", + MAILER = "text", + TZ = "text", + GEO = { + values = { + "LAT", + "LON", + }, + }, + TITLE = "text", + ROLE = "text", + LOGO = "copy of PHOTO", + AGENT = "text", + ORG = { + values = { + behaviour = "repeat-last", + "ORGNAME", + "ORGUNIT", + } + }, + CATEGORIES = { + values = "KEYWORD", + }, + NOTE = "text", + PRODID = "text", + REV = "text", + SORTSTRING = "text", + SOUND = "copy of PHOTO", + UID = "text", + URL = "text", + CLASS = { + names = { -- The item.name is the value if it's one of these. + "PUBLIC", + "PRIVATE", + "CONFIDENTIAL", + }, + }, + KEY = { + props = { "TYPE" }, + value = "CRED", + }, + DESC = "text", +}; +vCard_dtd.LOGO = vCard_dtd.PHOTO; +vCard_dtd.SOUND = vCard_dtd.PHOTO; + +--TODO BINVAL OR EXTVAL + +local function vCard_esc(s) + return s:gsub("[,;\\]", "\\%1"):gsub("\n","\\n"); +end + +local function vCard_prop(item) + local prop_name = item.name; + local prop_def = vCard_dtd[prop_name]; + if not prop_def then return nil end + + local value, params = "", {}; + + if prop_def == "text" then + value = item:get_text(); + elseif type(prop_def) == "table" then + if prop_def.value then --single item + value = item:get_child_text(prop_def.value) or ""; + elseif prop_def.values then --array + local value_names = prop_def.values; + value = {}; + for i=1,#value_names do + t_insert(value, item:get_child_text(value_names[i]) or ""); + --TODO ORG with >1 sub items + end + elseif prop_def.names then + local names = prop_def.names; + for i=1,#names do + if item:get_child(names[i]) then + value = names[i]; + break; + end + end + end + + if prop_def.props_verbatim then + for k,v in pairs(prop_def.props_verbatim) do + params[k] = v; + end + end + + if prop_def.types then + local types = prop_def.types; + params.TYPE = {}; + for i=1,#types do + if item:get_child(types[i]) then + t_insert(params.TYPE, types[i]:lower()); + end + end + if #params.TYPE == 0 then + params.TYPE = nil; + end + end + + if prop_def.props then + local props = prop_def.props; + for i=1,#props do + local prop = props[i] + local p = item:get_child_text(prop); + if p then + params[prop] = params[prop] or {}; + t_insert(params[prop], p); + end + end + end + else + return nil + end + + if type(value) == "table" then + for i=1,#value do + value[i]=vCard_esc(value[i]); + end + value = t_concat(value, ";"); + else + value = vCard_esc(value); + end + + if next(params) then + local sparams = ""; + for k,v in pairs(params) do + sparams = sparams .. (";%s=%s"):format(k, t_concat(v,",")); + end + params = sparams; + else + params = ""; + end + + --TODO: Split long lines + return ("%s%s:%s"):format(item.name, params, value); +end + +return function (opts, arg) + if opts.short_help then + print("Fetch someones vCard"); + return; + end + if (#arg == 0 or opts.help) then + return 0; + end + local function on_connect(conn) + conn:add_plugin("vcard"); + conn:get_vcard(arg[1], function(reply) + local vCard = reply:get_child("vCard", "vcard-temp"); + if vCard then + print("BEGIN:VCARD"); + print("VERSION:3.0"); + for i = 1,#vCard do + local item = vCard[i]; + if item.name then + local s = vCard_prop(item); + if s then print(s); end + else + conn:debug("Unhandled vCard field: %s", item.name); + end + end + print("END:VCARD"); + end + verse.quit(); + end); + end + clix_connect(opts, on_connect); +end diff -r bbbef9f4a798 -r 582afbb2b23d squishy --- a/squishy Sun Aug 14 21:27:41 2011 +0200 +++ b/squishy Sun Aug 14 21:30:08 2011 +0200 @@ -6,6 +6,7 @@ Module "clix.raw" "clix/raw.lua" Module "clix.roster" "clix/roster.lua" Module "clix.export" "clix/export.lua" +Module "clix.vcard" "clix/vcard.lua" if GetOption "with-verse" then Module("verse")(GetOption "with-verse");