PageRenderTime 55ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/silc-toolkit-1.1.10/lib/silcvcard/silcvcard.c

#
C | 463 lines | 393 code | 36 blank | 34 comment | 97 complexity | 852b7981ba740237543953259b713365 MD5 | raw file
Possible License(s): GPL-2.0
  1. /*
  2. silcvcard.c
  3. Author: Pekka Riikonen <priikone@silcnet.org>
  4. Copyright (C) 2002 - 2005 Pekka Riikonen
  5. The contents of this file are subject to one of the Licenses specified
  6. in the COPYING file; You may not use this file except in compliance
  7. with the License.
  8. The software distributed under the License is distributed on an "AS IS"
  9. basis, in the hope that it will be useful, but WITHOUT WARRANTY OF ANY
  10. KIND, either expressed or implied. See the COPYING file for more
  11. information.
  12. */
  13. /* $Id$ */
  14. /* Implementation of the VCard (RFC 2426) */
  15. #include "silc.h"
  16. #define VCARD_HEADER "BEGIN:VCARD\n"
  17. #define VCARD_VERSION "VERSION:3.0\n"
  18. #define VCARD_FOOTER "END:VCARD\n"
  19. /* Encode VCard */
  20. unsigned char *silc_vcard_encode(SilcVCard vcard, SilcUInt32 *vcard_len)
  21. {
  22. SilcBufferStruct buffer;
  23. int i;
  24. if (!vcard->full_name || !vcard->family_name || !vcard->first_name)
  25. return NULL;
  26. memset(&buffer, 0, sizeof(buffer));
  27. silc_buffer_strformat(
  28. &buffer,
  29. VCARD_HEADER,
  30. VCARD_VERSION,
  31. "FN:", vcard->full_name, "\n",
  32. "N:", vcard->family_name, ";", vcard->first_name, ";",
  33. vcard->middle_names, ";", vcard->prefix, ";", vcard->suffix, "\n",
  34. SILC_STRFMT_END);
  35. if (vcard->nickname)
  36. silc_buffer_strformat(&buffer,
  37. "NICKNAME:", vcard->nickname, "\n",
  38. SILC_STRFMT_END);
  39. if (vcard->bday)
  40. silc_buffer_strformat(&buffer,
  41. "BDAY:", vcard->bday, "\n",
  42. SILC_STRFMT_END);
  43. if (vcard->title)
  44. silc_buffer_strformat(&buffer,
  45. "TITLE:", vcard->title, "\n",
  46. SILC_STRFMT_END);
  47. if (vcard->role)
  48. silc_buffer_strformat(&buffer,
  49. "ROLE:", vcard->role, "\n",
  50. SILC_STRFMT_END);
  51. if (vcard->org_name)
  52. silc_buffer_strformat(&buffer,
  53. "ORG:", vcard->org_name, ";", vcard->org_unit, "\n",
  54. SILC_STRFMT_END);
  55. if (vcard->categories)
  56. silc_buffer_strformat(&buffer,
  57. "CATEGORIES:", vcard->categories, "\n",
  58. SILC_STRFMT_END);
  59. if (vcard->catclass)
  60. silc_buffer_strformat(&buffer,
  61. "CLASS:", vcard->catclass, "\n",
  62. SILC_STRFMT_END);
  63. if (vcard->url)
  64. silc_buffer_strformat(&buffer,
  65. "URL:", vcard->url, "\n",
  66. SILC_STRFMT_END);
  67. if (vcard->label)
  68. silc_buffer_strformat(&buffer,
  69. "LABEL;", vcard->url, "\n",
  70. SILC_STRFMT_END);
  71. for (i = 0; i < vcard->num_addrs; i++) {
  72. silc_buffer_strformat(&buffer,
  73. "ADR;TYPE=",
  74. vcard->addrs[i].type, ":",
  75. vcard->addrs[i].pbox, ";",
  76. vcard->addrs[i].ext_addr, ";",
  77. vcard->addrs[i].street_addr, ";",
  78. vcard->addrs[i].city, ";",
  79. vcard->addrs[i].state, ";",
  80. vcard->addrs[i].code, ";",
  81. vcard->addrs[i].country, "\n",
  82. SILC_STRFMT_END);
  83. }
  84. for (i = 0; i < vcard->num_tels; i++) {
  85. silc_buffer_strformat(&buffer,
  86. "TEL;TYPE=",
  87. vcard->tels[i].type, ":",
  88. vcard->tels[i].telnum, "\n",
  89. SILC_STRFMT_END);
  90. }
  91. for (i = 0; i < vcard->num_emails; i++) {
  92. silc_buffer_strformat(&buffer,
  93. "EMAIL;TYPE=",
  94. vcard->emails[i].type, ":",
  95. vcard->emails[i].address, "\n",
  96. SILC_STRFMT_END);
  97. }
  98. if (vcard->note)
  99. silc_buffer_strformat(&buffer,
  100. "NOTE:", vcard->note, "\n",
  101. SILC_STRFMT_END);
  102. if (vcard->rev)
  103. silc_buffer_strformat(&buffer,
  104. "REV:", vcard->rev, "\n",
  105. SILC_STRFMT_END);
  106. silc_buffer_strformat(&buffer, VCARD_FOOTER, SILC_STRFMT_END);
  107. if (vcard_len)
  108. *vcard_len = silc_buffer_truelen(&buffer);
  109. return buffer.head;
  110. }
  111. /* Take one token */
  112. #define VCARD_TOKEN(x) \
  113. if (!(x)) { \
  114. (x) = silc_memdup(val + off, i - off); \
  115. off = i + 1; \
  116. continue; \
  117. }
  118. /* Take on TYPE= token and prepare for next token, accept the
  119. type also without TYPE= as it is possible */
  120. #define VCARD_TYPETOKEN(x) \
  121. if (!(x)) { \
  122. int tmpi = 0; \
  123. if (!strncasecmp(val + off, "TYPE=", 5)) \
  124. tmpi = 5; \
  125. (x) = silc_memdup(val + off + tmpi, i - off - tmpi - 1); \
  126. tmpi = off + tmpi + strlen((x)) + 1; \
  127. off = i; \
  128. i = tmpi; \
  129. }
  130. /* Take last token */
  131. #define VCARD_LASTTOKEN(x) \
  132. if (!(x)) { \
  133. if (off < len) \
  134. (x) = silc_memdup(val + off, len - off); \
  135. } \
  136. /* Get one (single) field */
  137. #define VCARD_FIELD(val, c, x) \
  138. do { \
  139. if (!strncasecmp(val, (c), strlen((c)))) { \
  140. int tmpl = strlen((c)); \
  141. if ((x)) \
  142. break; \
  143. if (len - tmpl > 0) \
  144. (x) = silc_memdup(val + tmpl, len - tmpl); \
  145. goto next; \
  146. } \
  147. } while(0)
  148. /* Decode VCard */
  149. SilcBool silc_vcard_decode(const unsigned char *data, SilcUInt32 data_len,
  150. SilcVCard vcard)
  151. {
  152. unsigned char *val;
  153. SilcBool has_begin = FALSE, has_end = FALSE;
  154. int len, i, off = 0;
  155. val = (unsigned char *)data;
  156. while (val) {
  157. len = 0;
  158. for (i = (val - data); i < data_len; i++) {
  159. if (data[i] == '\0' || data[i] == '\n') {
  160. len = i - (val - data);
  161. break;
  162. }
  163. }
  164. if (!len || len > data_len - (val - data))
  165. break;
  166. /* Check for mandatory header and footer */
  167. if (!strncasecmp(val, VCARD_HEADER, strlen(VCARD_HEADER))) {
  168. has_begin = TRUE;
  169. goto next;
  170. }
  171. if (!strncasecmp(val, VCARD_FOOTER, strlen(VCARD_FOOTER))) {
  172. has_end = TRUE;
  173. goto next;
  174. }
  175. /* Get single fields */
  176. VCARD_FIELD(val, "FN:", vcard->full_name);
  177. VCARD_FIELD(val, "NICKNAME:", vcard->nickname);
  178. VCARD_FIELD(val, "BDAY:", vcard->bday);
  179. VCARD_FIELD(val, "TITLE:", vcard->title);
  180. VCARD_FIELD(val, "ROLE:", vcard->role);
  181. VCARD_FIELD(val, "CATEGORIES:", vcard->categories);
  182. VCARD_FIELD(val, "CLASS:", vcard->catclass);
  183. VCARD_FIELD(val, "URL:", vcard->url);
  184. VCARD_FIELD(val, "LABEL;", vcard->label);
  185. VCARD_FIELD(val, "NOTE:", vcard->note);
  186. VCARD_FIELD(val, "REV:", vcard->rev);
  187. /* Get multi-column fields */
  188. if (!strncasecmp(val, "N:", 2)) {
  189. if (vcard->family_name)
  190. break;
  191. if (len - 2) {
  192. off = 2;
  193. for (i = off; i < len; i++)
  194. if (val[i] == ';') {
  195. VCARD_TOKEN(vcard->family_name);
  196. VCARD_TOKEN(vcard->first_name);
  197. VCARD_TOKEN(vcard->middle_names);
  198. VCARD_TOKEN(vcard->prefix);
  199. }
  200. if (!vcard->family_name && !vcard->first_name) {
  201. VCARD_LASTTOKEN(vcard->family_name);
  202. off += (len - off);
  203. }
  204. if (!vcard->first_name) {
  205. VCARD_LASTTOKEN(vcard->first_name);
  206. } else {
  207. VCARD_LASTTOKEN(vcard->suffix);
  208. }
  209. }
  210. goto next;
  211. }
  212. if (!strncasecmp(val, "ORG:", 4)) {
  213. if (vcard->org_name)
  214. continue;
  215. if (len - 4) {
  216. off = 4;
  217. for (i = off; i < len; i++) {
  218. if (val[i] == ';') {
  219. VCARD_TOKEN(vcard->org_name);
  220. break;
  221. }
  222. }
  223. /* It's possible to have ORG without last ';', so check for it */
  224. if (!vcard->org_name) {
  225. VCARD_LASTTOKEN(vcard->org_name);
  226. } else {
  227. VCARD_LASTTOKEN(vcard->org_unit);
  228. }
  229. }
  230. goto next;
  231. }
  232. if (!strncasecmp(val, "ADR;", 4)) {
  233. vcard->addrs = silc_realloc(vcard->addrs, sizeof(*vcard->addrs) *
  234. (vcard->num_addrs + 1));
  235. memset(&vcard->addrs[vcard->num_addrs], 0, sizeof(*vcard->addrs));
  236. if (len - 4) {
  237. off = 4;
  238. for (i = off; i < len; i++)
  239. if (val[i] == ';') {
  240. VCARD_TYPETOKEN(vcard->addrs[vcard->num_addrs].type);
  241. VCARD_TOKEN(vcard->addrs[vcard->num_addrs].pbox);
  242. VCARD_TOKEN(vcard->addrs[vcard->num_addrs].ext_addr);
  243. VCARD_TOKEN(vcard->addrs[vcard->num_addrs].street_addr);
  244. VCARD_TOKEN(vcard->addrs[vcard->num_addrs].city);
  245. VCARD_TOKEN(vcard->addrs[vcard->num_addrs].state);
  246. VCARD_TOKEN(vcard->addrs[vcard->num_addrs].code);
  247. }
  248. VCARD_LASTTOKEN(vcard->addrs[vcard->num_addrs].country);
  249. }
  250. vcard->num_addrs++;
  251. goto next;
  252. }
  253. if (!strncasecmp(val, "TEL;", 4)) {
  254. vcard->tels = silc_realloc(vcard->tels, sizeof(*vcard->tels) *
  255. (vcard->num_tels + 1));
  256. memset(&vcard->tels[vcard->num_tels], 0, sizeof(*vcard->tels));
  257. if (len - 4) {
  258. off = 4;
  259. for (i = off; i < len; i++)
  260. if (val[i] == ':') {
  261. i++;
  262. VCARD_TYPETOKEN(vcard->tels[vcard->num_tels].type);
  263. break;
  264. }
  265. VCARD_LASTTOKEN(vcard->tels[vcard->num_tels].telnum);
  266. }
  267. vcard->num_tels++;
  268. goto next;
  269. }
  270. if (!strncasecmp(val, "EMAIL;", 6)) {
  271. vcard->emails = silc_realloc(vcard->emails, sizeof(*vcard->emails) *
  272. (vcard->num_emails + 1));
  273. memset(&vcard->emails[vcard->num_emails], 0, sizeof(*vcard->emails));
  274. if (len - 6) {
  275. off = 6;
  276. for (i = off; i < len; i++)
  277. if (val[i] == ':') {
  278. i++;
  279. VCARD_TYPETOKEN(vcard->emails[vcard->num_emails].type);
  280. break;
  281. }
  282. VCARD_LASTTOKEN(vcard->emails[vcard->num_emails].address);
  283. }
  284. vcard->num_emails++;
  285. goto next;
  286. }
  287. next:
  288. val = strchr(val, '\n');
  289. if (!val)
  290. break;
  291. val++;
  292. if (!val || !(*val))
  293. break;
  294. }
  295. if (!has_begin || !has_end || !vcard->full_name) {
  296. silc_vcard_free(vcard);
  297. return FALSE;
  298. }
  299. return TRUE;
  300. }
  301. /* Allocate vcard context */
  302. SilcVCard silc_vcard_alloc(void)
  303. {
  304. SilcVCard vcard = silc_calloc(1, sizeof(*vcard));
  305. if (!vcard)
  306. return NULL;
  307. vcard->dynamic = TRUE;
  308. return vcard;
  309. }
  310. /* Free the vcard structure */
  311. void silc_vcard_free(SilcVCard vcard)
  312. {
  313. int i;
  314. silc_free(vcard->full_name);
  315. silc_free(vcard->family_name);
  316. silc_free(vcard->first_name);
  317. silc_free(vcard->middle_names);
  318. silc_free(vcard->prefix);
  319. silc_free(vcard->suffix);
  320. silc_free(vcard->nickname);
  321. silc_free(vcard->bday);
  322. silc_free(vcard->title);
  323. silc_free(vcard->role);
  324. silc_free(vcard->org_name);
  325. silc_free(vcard->org_unit);
  326. silc_free(vcard->categories);
  327. silc_free(vcard->catclass);
  328. silc_free(vcard->url);
  329. silc_free(vcard->label);
  330. for (i = 0; i < vcard->num_addrs; i++) {
  331. silc_free(vcard->addrs[i].type);
  332. silc_free(vcard->addrs[i].pbox);
  333. silc_free(vcard->addrs[i].ext_addr);
  334. silc_free(vcard->addrs[i].street_addr);
  335. silc_free(vcard->addrs[i].city);
  336. silc_free(vcard->addrs[i].state);
  337. silc_free(vcard->addrs[i].code);
  338. silc_free(vcard->addrs[i].country);
  339. }
  340. silc_free(vcard->addrs);
  341. for (i = 0; i < vcard->num_tels; i++) {
  342. silc_free(vcard->tels[i].type);
  343. silc_free(vcard->tels[i].telnum);
  344. }
  345. silc_free(vcard->tels);
  346. for (i = 0; i < vcard->num_emails; i++) {
  347. silc_free(vcard->emails[i].type);
  348. silc_free(vcard->emails[i].address);
  349. }
  350. silc_free(vcard->emails);
  351. silc_free(vcard->note);
  352. silc_free(vcard->rev);
  353. if (!vcard->dynamic)
  354. memset(vcard, 0, sizeof(*vcard));
  355. if (vcard->dynamic) {
  356. memset(vcard, 0, sizeof(*vcard));
  357. silc_free(vcard);
  358. }
  359. }
  360. /* Print card to file stream */
  361. void silc_vcard_fprintf(SilcVCard vcard, FILE *stream)
  362. {
  363. int i;
  364. fprintf(stream, "%s", VCARD_HEADER);
  365. fprintf(stream, "%s", VCARD_VERSION);
  366. if (vcard->full_name)
  367. fprintf(stream, "FN:%s\n", vcard->full_name);
  368. if (vcard->family_name)
  369. fprintf(stream, "N:%s;%s;%s;%s;%s\n",
  370. vcard->family_name,
  371. vcard->first_name ? vcard->first_name : "",
  372. vcard->middle_names ? vcard->middle_names : "",
  373. vcard->prefix ? vcard->prefix : "",
  374. vcard->suffix ? vcard->suffix : "");
  375. if (vcard->nickname)
  376. fprintf(stream, "NICKNAME:%s\n", vcard->nickname);
  377. if (vcard->bday)
  378. fprintf(stream, "BDAY:%s\n", vcard->bday);
  379. if (vcard->title)
  380. fprintf(stream, "TITLE:%s\n", vcard->title);
  381. if (vcard->role)
  382. fprintf(stream, "ROLE:%s\n", vcard->role);
  383. if (vcard->org_name)
  384. fprintf(stream, "ORG:%s;%s\n", vcard->org_name,
  385. vcard->org_unit ? vcard->org_unit : "");
  386. if (vcard->categories)
  387. fprintf(stream, "CATEGORIES:%s\n", vcard->categories);
  388. if (vcard->catclass)
  389. fprintf(stream, "CLASS:%s\n", vcard->catclass);
  390. if (vcard->url)
  391. fprintf(stream, "URL:%s\n", vcard->url);
  392. if (vcard->label)
  393. fprintf(stream, "LABEL;%s\n", vcard->label);
  394. for (i = 0; i < vcard->num_addrs; i++) {
  395. fprintf(stream, "ADR;TYPE=%s:%s;%s;%s;%s;%s;%s;%s\n",
  396. vcard->addrs[i].type,
  397. vcard->addrs[i].pbox ? vcard->addrs[i].pbox : "",
  398. vcard->addrs[i].ext_addr ? vcard->addrs[i].ext_addr : "",
  399. vcard->addrs[i].street_addr ? vcard->addrs[i].street_addr : "",
  400. vcard->addrs[i].city ? vcard->addrs[i].city : "",
  401. vcard->addrs[i].state ? vcard->addrs[i].state : "",
  402. vcard->addrs[i].code ? vcard->addrs[i].code : "",
  403. vcard->addrs[i].country ? vcard->addrs[i].country : "");
  404. }
  405. for (i = 0; i < vcard->num_tels; i++) {
  406. fprintf(stream, "TEL;TYPE=%s:%s\n",
  407. vcard->tels[i].type,
  408. vcard->tels[i].telnum ? vcard->tels[i].telnum : "");
  409. }
  410. for (i = 0; i < vcard->num_emails; i++) {
  411. fprintf(stream, "EMAIL;TYPE=%s:%s\n",
  412. vcard->emails[i].type,
  413. vcard->emails[i].address ? vcard->emails[i].address : "");
  414. }
  415. if (vcard->note)
  416. fprintf(stream, "NOTE:%s\n", vcard->note);
  417. if (vcard->rev)
  418. fprintf(stream, "REV:%s\n", vcard->rev);
  419. fprintf(stream, "%s", VCARD_FOOTER);
  420. fflush(stream);
  421. }