Changeset

64:582afbb2b23d

clix.vcard, squishy: Add plugin that fetches and converts peoples vCards to the text format.
author Kim Alvefur <zash@zash.se>
date Sun, 14 Aug 2011 21:30:08 +0200
parents 63:bbbef9f4a798
children 65:65076d194b85
files clix/vcard.lua squishy
diffstat 2 files changed, 251 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /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
--- 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");