clix/vcard.lua

Sun, 14 Aug 2011 21:34:28 +0200

author
Kim Alvefur <zash@zash.se>
date
Sun, 14 Aug 2011 21:34:28 +0200
changeset 65
65076d194b85
parent 64
582afbb2b23d
child 67
776d97484dc5
permissions
-rw-r--r--

clix.vcard: Fix debug.

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);
						else
							conn:debug("Unhandled vCard field: %s", item.name);
						end
					end
				end
				print("END:VCARD");
			end
			verse.quit();
		end);
	end
	clix_connect(opts, on_connect);
end

mercurial