clix/vcard.lua

changeset 67
776d97484dc5
parent 65
65076d194b85
child 98
5ad042476235
equal deleted inserted replaced
66:13d6d39f5952 67:776d97484dc5
1 local t_insert, t_concat = table.insert, table.concat; 1 local t_insert, t_concat = table.insert, table.concat;
2
3 local vCard_dtd = {
4 VERSION = "ignore", --MUST be 3.0, so parsing is redundant
5 FN = "text",
6 N = {
7 values = {
8 "FAMILY",
9 "GIVEN",
10 "MIDDLE",
11 "PREFIX",
12 "SUFFIX",
13 },
14 },
15 NICKNAME = "text",
16 PHOTO = {
17 props_verbatim = { ENCODING = { "b" } },
18 props = { "TYPE" },
19 value = "BINVAL", --{ "EXTVAL", },
20 },
21 BDAY = "text",
22 ADR = {
23 types = {
24 "HOME",
25 "WORK",
26 "POSTAL",
27 "PARCEL",
28 "DOM",
29 "INTL",
30 "PREF",
31 },
32 values = {
33 "POBOX",
34 "EXTADD",
35 "STREET",
36 "LOCALITY",
37 "REGION",
38 "PCODE",
39 "CTRY",
40 }
41 },
42 LABEL = {
43 types = {
44 "HOME",
45 "WORK",
46 "POSTAL",
47 "PARCEL",
48 "DOM",
49 "INTL",
50 "PREF",
51 },
52 value = "LINE",
53 },
54 TEL = {
55 types = {
56 "HOME",
57 "WORK",
58 "VOICE",
59 "FAX",
60 "PAGER",
61 "MSG",
62 "CELL",
63 "VIDEO",
64 "BBS",
65 "MODEM",
66 "ISDN",
67 "PCS",
68 "PREF",
69 },
70 value = "NUMBER",
71 },
72 EMAIL = {
73 types = {
74 "HOME",
75 "WORK",
76 "INTERNET",
77 "PREF",
78 "X400",
79 },
80 value = "USERID",
81 },
82 JABBERID = "text",
83 MAILER = "text",
84 TZ = "text",
85 GEO = {
86 values = {
87 "LAT",
88 "LON",
89 },
90 },
91 TITLE = "text",
92 ROLE = "text",
93 LOGO = "copy of PHOTO",
94 AGENT = "text",
95 ORG = {
96 values = {
97 behaviour = "repeat-last",
98 "ORGNAME",
99 "ORGUNIT",
100 }
101 },
102 CATEGORIES = {
103 values = "KEYWORD",
104 },
105 NOTE = "text",
106 PRODID = "text",
107 REV = "text",
108 SORTSTRING = "text",
109 SOUND = "copy of PHOTO",
110 UID = "text",
111 URL = "text",
112 CLASS = {
113 names = { -- The item.name is the value if it's one of these.
114 "PUBLIC",
115 "PRIVATE",
116 "CONFIDENTIAL",
117 },
118 },
119 KEY = {
120 props = { "TYPE" },
121 value = "CRED",
122 },
123 DESC = "text",
124 };
125 vCard_dtd.LOGO = vCard_dtd.PHOTO;
126 vCard_dtd.SOUND = vCard_dtd.PHOTO;
127
128 --TODO BINVAL OR EXTVAL
129
130 local function vCard_esc(s)
131 return s:gsub("[,;\\]", "\\%1"):gsub("\n","\\n");
132 end
133
134 local function vCard_prop(item)
135 local prop_name = item.name;
136 local prop_def = vCard_dtd[prop_name];
137 if not prop_def then return nil end
138
139 local value, params = "", {};
140
141 if prop_def == "text" then
142 value = item:get_text();
143 elseif type(prop_def) == "table" then
144 if prop_def.value then --single item
145 value = item:get_child_text(prop_def.value) or "";
146 elseif prop_def.values then --array
147 local value_names = prop_def.values;
148 value = {};
149 for i=1,#value_names do
150 t_insert(value, item:get_child_text(value_names[i]) or "");
151 --TODO ORG with >1 sub items
152 end
153 elseif prop_def.names then
154 local names = prop_def.names;
155 for i=1,#names do
156 if item:get_child(names[i]) then
157 value = names[i];
158 break;
159 end
160 end
161 end
162
163 if prop_def.props_verbatim then
164 for k,v in pairs(prop_def.props_verbatim) do
165 params[k] = v;
166 end
167 end
168
169 if prop_def.types then
170 local types = prop_def.types;
171 params.TYPE = {};
172 for i=1,#types do
173 if item:get_child(types[i]) then
174 t_insert(params.TYPE, types[i]:lower());
175 end
176 end
177 if #params.TYPE == 0 then
178 params.TYPE = nil;
179 end
180 end
181
182 if prop_def.props then
183 local props = prop_def.props;
184 for i=1,#props do
185 local prop = props[i]
186 local p = item:get_child_text(prop);
187 if p then
188 params[prop] = params[prop] or {};
189 t_insert(params[prop], p);
190 end
191 end
192 end
193 else
194 return nil
195 end
196
197 if type(value) == "table" then
198 for i=1,#value do
199 value[i]=vCard_esc(value[i]);
200 end
201 value = t_concat(value, ";");
202 else
203 value = vCard_esc(value);
204 end
205
206 if next(params) then
207 local sparams = "";
208 for k,v in pairs(params) do
209 sparams = sparams .. (";%s=%s"):format(k, t_concat(v,","));
210 end
211 params = sparams;
212 else
213 params = "";
214 end
215
216 --TODO: Split long lines
217 return ("%s%s:%s"):format(item.name, params, value);
218 end
219 2
220 return function (opts, arg) 3 return function (opts, arg)
221 if opts.short_help then 4 if opts.short_help then
222 print("Fetch someones vCard"); 5 print("Fetch someones vCard or set your own");
223 return; 6 return;
224 end 7 end
225 if (#arg == 0 or opts.help) then 8 if ((#arg == 0 and not opts.set) or opts.help) then
226 return 0; 9 return 0;
227 end 10 end
228 local function on_connect(conn) 11 local function on_connect(conn)
229 conn:add_plugin("vcard"); 12 conn:add_plugin("vcard");
230 conn:get_vcard(arg[1], function(reply) 13 if not opts.set then -- get
231 local vCard = reply:get_child("vCard", "vcard-temp"); 14 conn:get_vcard(arg[1], function(vCard)
232 if vCard then 15 print(vCard and vCard._text or "No vCard returned")
233 print("BEGIN:VCARD"); 16 conn:close();
234 print("VERSION:3.0"); 17 end);
235 for i = 1,#vCard do 18 else
236 local item = vCard[i]; 19 conn:set_vcard(opts.stdin and io.stdin:read"*a"
237 if item.name then 20 or (opts.file and io.open(opts.file):read"*a") or arg[1],
238 local s = vCard_prop(item); 21 function() conn:close() end)
239 if s then 22 end
240 print(s);
241 else
242 conn:debug("Unhandled vCard field: %s", item.name);
243 end
244 end
245 end
246 print("END:VCARD");
247 end
248 verse.quit();
249 end);
250 end 23 end
251 clix_connect(opts, on_connect); 24 clix_connect(opts, on_connect);
252 end 25 end

mercurial