1 /* (c) 2001-2005 by Marcin Wiacek, Michal Cihar... */
2
3 #include <string.h>
4 #include <stdio.h>
5 #include <stdarg.h>
6 #include <ctype.h>
7
8 #include <gammu-misc.h>
9 #include <gammu-bitmap.h>
10
11 #include "../misc/coding/coding.h"
12 #include "../debug.h"
13 #include "gsmpbk.h"
14 #include "gsmmisc.h"
15
GSM_StringToMemoryType(const char * s)16 GSM_MemoryType GSM_StringToMemoryType(const char *s) {
17 if (strcmp(s, "ME") == 0) return MEM_ME;
18 else if (strcmp(s, "SM") == 0) return MEM_SM;
19 else if (strcmp(s, "SR") == 0) return MEM_SR;
20 else if (strcmp(s, "ON") == 0) return MEM_ON;
21 else if (strcmp(s, "DC") == 0) return MEM_DC;
22 else if (strcmp(s, "RC") == 0) return MEM_RC;
23 else if (strcmp(s, "MC") == 0) return MEM_MC;
24 else if (strcmp(s, "MT") == 0) return MEM_MT;
25 else if (strcmp(s, "FD") == 0) return MEM_FD;
26 else if (strcmp(s, "VM") == 0) return MEM_VM;
27 else if (strcmp(s, "SL") == 0) return MEM_SL;
28 else if (strcmp(s, "QD") == 0) return MEM_QD;
29 else {
30 return 0;
31 }
32 }
33
GSM_PhonebookGetEntryName(const GSM_MemoryEntry * entry)34 unsigned char *GSM_PhonebookGetEntryName (const GSM_MemoryEntry *entry)
35 {
36 /* We possibly store here "LastName, FirstName" so allocate enough memory */
37 static char dest[(GSM_PHONEBOOK_TEXT_LENGTH*2+2+1)*2];
38 static char split[] = { '\0', ',', '\0', ' ', '\0', '\0'};
39 int i;
40 int first = -1, last = -1, name = -1;
41 int len = 0;
42
43 for (i = 0; i < entry->EntriesNum; i++) {
44 switch (entry->Entries[i].EntryType) {
45 case PBK_Text_LastName:
46 last = i;
47 break;
48 case PBK_Text_FirstName:
49 first = i;
50 break;
51 case PBK_Text_Name:
52 name = i;
53 break;
54 default:
55 break;
56 }
57 }
58
59 if (name != -1) {
60 CopyUnicodeString(dest, entry->Entries[name].Text);
61 } else {
62 if (last != -1 && first != -1) {
63 len = UnicodeLength(entry->Entries[last].Text);
64 CopyUnicodeString(dest, entry->Entries[last].Text);
65 CopyUnicodeString(dest + 2*len, split);
66 CopyUnicodeString(dest + 2*len + 4, entry->Entries[first].Text);
67 } else if (last != -1) {
68 CopyUnicodeString(dest, entry->Entries[last].Text);
69 } else if (first != -1) {
70 CopyUnicodeString(dest, entry->Entries[first].Text);
71 } else {
72 return NULL;
73 }
74 }
75
76 return dest;
77 }
78
GSM_PhonebookFindDefaultNameNumberGroup(const GSM_MemoryEntry * entry,int * Name,int * Number,int * Group)79 void GSM_PhonebookFindDefaultNameNumberGroup(const GSM_MemoryEntry *entry, int *Name, int *Number, int *Group)
80 {
81 int i;
82
83 *Name = -1;
84 *Number = -1;
85 *Group = -1;
86 for (i = 0; i < entry->EntriesNum; i++) {
87 switch (entry->Entries[i].EntryType) {
88 case PBK_Number_General : if (*Number == -1) *Number = i; break;
89 case PBK_Text_Name : if (*Name == -1) *Name = i; break;
90 case PBK_Caller_Group : if (*Group == -1) *Group = i; break;
91 default : break;
92 }
93 }
94 if ((*Number) == -1) {
95 for (i = 0; i < entry->EntriesNum; i++) {
96 switch (entry->Entries[i].EntryType) {
97 case PBK_Number_Mobile:
98 case PBK_Number_General:
99 case PBK_Number_Fax:
100 case PBK_Number_Pager:
101 case PBK_Number_Other:
102 *Number = i;
103 break;
104 default:
105 break;
106 }
107 if (*Number != -1) break;
108 }
109 }
110 if ((*Name) == -1) {
111 for (i = 0; i < entry->EntriesNum; i++) {
112 if (entry->Entries[i].EntryType != PBK_Text_LastName) continue;
113 *Name = i;
114 break;
115 }
116 }
117 if ((*Name) == -1) {
118 for (i = 0; i < entry->EntriesNum; i++) {
119 if (entry->Entries[i].EntryType != PBK_Text_FirstName) continue;
120 *Name = i;
121 break;
122 }
123 }
124 }
125
126
GSM_EncodeVCARD(GSM_Debug_Info * di,char * Buffer,const size_t buff_len,size_t * Length,GSM_MemoryEntry * pbk,const gboolean header,const GSM_VCardVersion Version)127 GSM_Error GSM_EncodeVCARD(GSM_Debug_Info *di, char *Buffer, const size_t buff_len, size_t *Length, GSM_MemoryEntry *pbk, const gboolean header, const GSM_VCardVersion Version)
128 {
129 int Name, Number, Group, i;
130 int firstname = -1, secondname = -1, lastname = -1;
131 int address = -1, city = -1, state = -1, zip = -1, country = -1;
132 int workaddress = -1, workcity = -1, workstate = -1, workzip = -1, workcountry = -1;
133 unsigned char buffer[1024];
134 int pos;
135 gboolean ignore;
136 GSM_Error error;
137 GSM_BinaryPicture *bitmap;
138
139 GSM_PhonebookFindDefaultNameNumberGroup(pbk, &Name, &Number, &Group);
140
141 if (header) {
142 error = VC_StoreLine(Buffer, buff_len, Length, "BEGIN:VCARD");
143 if (error != ERR_NONE) return error;
144 }
145 if (Version == Nokia_VCard10 || Version == SonyEricsson_VCard10) {
146 if (Name != -1) {
147 error = VC_StoreLine(Buffer, buff_len, Length, "N:%s",
148 DecodeUnicodeString(pbk->Entries[Name].Text));
149 if (error != ERR_NONE) return error;
150 }
151 if (Number != -1) {
152 error = VC_StoreLine(Buffer, buff_len, Length, "TEL:%s",
153 DecodeUnicodeString(pbk->Entries[Number].Text));
154 if (error != ERR_NONE) return error;
155 }
156 } else if (Version == Nokia_VCard21 || Version == SonyEricsson_VCard21_Phone || Version == SonyEricsson_VCard21) {
157 if (header) {
158 error = VC_StoreLine(Buffer, buff_len, Length, "VERSION:2.1");
159 if (error != ERR_NONE) return error;
160 }
161
162 if (Version != SonyEricsson_VCard21_Phone) {
163 error = VC_StoreLine(Buffer, buff_len, Length, "X-GAMMU-LOCATION:%d", pbk->Location);
164 if (error != ERR_NONE) return error;
165
166 error = VC_StoreLine(Buffer, buff_len, Length, "X-GAMMU-MEMORY:%s", GSM_MemoryTypeToString(pbk->MemoryType));
167 if (error != ERR_NONE) return error;
168 }
169
170 for (i=0; i < pbk->EntriesNum; i++) {
171 ignore = FALSE;
172 pbk->Entries[i].AddError = ERR_NONE;
173 switch(pbk->Entries[i].EntryType) {
174 case PBK_Text_Name:
175 error = VC_Store(Buffer, buff_len, Length, "N");
176 if (error != ERR_NONE) return error;
177 break;
178 case PBK_Text_NickName:
179 error = VC_Store(Buffer, buff_len, Length, "NICKNAME");
180 if (error != ERR_NONE) return error;
181 break;
182 case PBK_Text_FormalName:
183 error = VC_Store(Buffer, buff_len, Length, "FN");
184 if (error != ERR_NONE) return error;
185 break;
186 case PBK_Text_NamePrefix:
187 error = VC_Store(Buffer, buff_len, Length, "X-NAME-PREFIX");
188 if (error != ERR_NONE) return error;
189 break;
190 case PBK_Text_NameSuffix:
191 error = VC_Store(Buffer, buff_len, Length, "X-NAME-SUFFIX");
192 if (error != ERR_NONE) return error;
193 break;
194 case PBK_Text_FirstName:
195 firstname = i;
196 ignore = TRUE;
197 break;
198 case PBK_Text_SecondName:
199 secondname = i;
200 ignore = TRUE;
201 break;
202 case PBK_Text_LastName:
203 lastname = i;
204 ignore = TRUE;
205 break;
206 case PBK_Text_StreetAddress:
207 if (pbk->Entries[i].Location == PBK_Location_Work) {
208 workaddress = i;
209 } else {
210 address = i;
211 }
212 ignore = TRUE;
213 break;
214 case PBK_Text_City:
215 if (pbk->Entries[i].Location == PBK_Location_Work) {
216 workcity = i;
217 } else {
218 city = i;
219 }
220 ignore = TRUE;
221 break;
222 case PBK_Text_State:
223 if (pbk->Entries[i].Location == PBK_Location_Work) {
224 workstate = i;
225 } else {
226 state = i;
227 }
228 ignore = TRUE;
229 break;
230 case PBK_Text_Zip:
231 if (pbk->Entries[i].Location == PBK_Location_Work) {
232 workzip = i;
233 } else {
234 zip = i;
235 }
236 ignore = TRUE;
237 break;
238 case PBK_Text_Country:
239 if (pbk->Entries[i].Location == PBK_Location_Work) {
240 workcountry = i;
241 } else {
242 country = i;
243 }
244 ignore = TRUE;
245 break;
246 case PBK_Date:
247 error = VC_StoreDate(Buffer, buff_len, Length, &(pbk->Entries[i].Date), "BDAY");
248 if (error != ERR_NONE) return error;
249 ignore = TRUE;
250 break;
251 case PBK_LastModified:
252 error = VC_StoreDateTime(Buffer, buff_len, Length, &(pbk->Entries[i].Date), "LAST-MODIFIED");
253 if (error != ERR_NONE) return error;
254 ignore = TRUE;
255 break;
256 case PBK_Number_General:
257 case PBK_Number_Video:
258 case PBK_Number_Other:
259 case PBK_Number_Pager:
260 case PBK_Number_Mobile :
261 case PBK_Number_Fax :
262 case PBK_Number_Messaging :
263 if (UnicodeLength(pbk->Entries[i].Text) == 0) {
264 ignore = TRUE;
265 break;
266 }
267 error = VC_Store(Buffer, buff_len, Length, "TEL");
268 if (error != ERR_NONE) return error;
269
270 if (Version != SonyEricsson_VCard21 && Number == i) {
271 error = VC_Store(Buffer, buff_len, Length, ";PREF");
272 if (error != ERR_NONE) return error;
273 }
274 switch (pbk->Entries[i].Location) {
275 case PBK_Location_Home:
276 error = VC_Store(Buffer, buff_len, Length, ";HOME");
277 if (error != ERR_NONE) return error;
278 break;
279 case PBK_Location_Work:
280 error = VC_Store(Buffer, buff_len, Length, ";WORK");
281 if (error != ERR_NONE) return error;
282 break;
283 case PBK_Location_Unknown:
284 break;
285 }
286 switch (pbk->Entries[i].EntryType) {
287 case PBK_Number_Other:
288 error = VC_Store(Buffer, buff_len, Length, ";OTHER");
289 if (error != ERR_NONE) return error;
290 break;
291 case PBK_Number_Pager:
292 error = VC_Store(Buffer, buff_len, Length, ";PAGER");
293 if (error != ERR_NONE) return error;
294 break;
295 case PBK_Number_Mobile:
296 error = VC_Store(Buffer, buff_len, Length, ";CELL");
297 if (error != ERR_NONE) return error;
298 break;
299 case PBK_Number_Fax:
300 error = VC_Store(Buffer, buff_len, Length, ";FAX");
301 if (error != ERR_NONE) return error;
302 break;
303 case PBK_Number_Messaging:
304 error = VC_Store(Buffer, buff_len, Length, ";MSG");
305 if (error != ERR_NONE) return error;
306 break;
307 case PBK_Number_Video:
308 error = VC_Store(Buffer, buff_len, Length, ";VIDEO");
309 if (error != ERR_NONE) return error;
310 break;
311 default:
312 break;
313 }
314 break;
315 case PBK_Text_Note :
316 if (UnicodeLength(pbk->Entries[i].Text) == 0) {
317 ignore = TRUE;
318 break;
319 }
320 error = VC_Store(Buffer, buff_len, Length, "NOTE");
321 if (error != ERR_NONE) return error;
322 break;
323 case PBK_Text_Postal :
324 if (UnicodeLength(pbk->Entries[i].Text) == 0) {
325 ignore = TRUE;
326 break;
327 }
328 /* Don't ask why. Nokia phones save postal address
329 * double - once like LABEL, second like ADR
330 */
331 error = VC_StoreText(Buffer, buff_len, Length, pbk->Entries[i].Text, "LABEL", FALSE);
332 if (error != ERR_NONE) return error;
333 if (pbk->Entries[i].Location == PBK_Location_Work) {
334 error = VC_Store(Buffer, buff_len, Length, "ADR;WORK");
335 } else if (pbk->Entries[i].Location == PBK_Location_Home) {
336 error = VC_Store(Buffer, buff_len, Length, "ADR;HOME");
337 } else {
338 error = VC_Store(Buffer, buff_len, Length, "ADR");
339 }
340 if (error != ERR_NONE) return error;
341 break;
342 case PBK_Text_Email :
343 case PBK_Text_Email2 :
344 if (UnicodeLength(pbk->Entries[i].Text) == 0) {
345 ignore = TRUE;
346 break;
347 }
348 error = VC_Store(Buffer, buff_len, Length, "EMAIL");
349 if (error != ERR_NONE) return error;
350 break;
351 case PBK_Text_URL :
352 if (UnicodeLength(pbk->Entries[i].Text) == 0) {
353 ignore = TRUE;
354 break;
355 }
356 error = VC_Store(Buffer, buff_len, Length, "URL");
357 if (error != ERR_NONE) return error;
358 break;
359 case PBK_Text_LUID :
360 if (UnicodeLength(pbk->Entries[i].Text) == 0) {
361 ignore = TRUE;
362 break;
363 }
364 error = VC_Store(Buffer, buff_len, Length, "X-IRMC-LUID");
365 if (error != ERR_NONE) return error;
366 break;
367 case PBK_Text_VOIP :
368 if (UnicodeLength(pbk->Entries[i].Text) == 0) {
369 ignore = TRUE;
370 break;
371 }
372 error = VC_Store(Buffer, buff_len, Length, "X-SIP;VOIP");
373 if (error != ERR_NONE) return error;
374 break;
375 case PBK_Text_SWIS :
376 if (UnicodeLength(pbk->Entries[i].Text) == 0) {
377 ignore = TRUE;
378 break;
379 }
380 error = VC_Store(Buffer, buff_len, Length, "X-SIP;SWIS");
381 if (error != ERR_NONE) return error;
382 break;
383 case PBK_Text_WVID :
384 if (UnicodeLength(pbk->Entries[i].Text) == 0) {
385 ignore = TRUE;
386 break;
387 }
388 error = VC_Store(Buffer, buff_len, Length, "X-WV-ID");
389 if (error != ERR_NONE) return error;
390 break;
391 case PBK_Text_SIP :
392 if (UnicodeLength(pbk->Entries[i].Text) == 0) {
393 ignore = TRUE;
394 break;
395 }
396 error = VC_Store(Buffer, buff_len, Length, "X-SIP");
397 if (error != ERR_NONE) return error;
398 break;
399 case PBK_Text_DTMF :
400 if (UnicodeLength(pbk->Entries[i].Text) == 0) {
401 ignore = TRUE;
402 break;
403 }
404 error = VC_Store(Buffer, buff_len, Length, "X-DTMF");
405 if (error != ERR_NONE) return error;
406 break;
407 case PBK_PushToTalkID:
408 if (UnicodeLength(pbk->Entries[i].Text) == 0) {
409 ignore = TRUE;
410 break;
411 }
412 error = VC_Store(Buffer, buff_len, Length, "X-SIP;POC");
413 if (error != ERR_NONE) return error;
414 break;
415 case PBK_Text_JobTitle:
416 if (UnicodeLength(pbk->Entries[i].Text) == 0) {
417 ignore = TRUE;
418 break;
419 }
420 error = VC_Store(Buffer, buff_len, Length, "TITLE");
421 if (error != ERR_NONE) return error;
422 break;
423 case PBK_Text_Company:
424 if (UnicodeLength(pbk->Entries[i].Text) == 0) {
425 ignore = TRUE;
426 break;
427 }
428 error = VC_Store(Buffer, buff_len, Length, "ORG");
429 if (error != ERR_NONE) return error;
430 break;
431 case PBK_Photo:
432 bitmap = &(pbk->Entries[i].Picture);
433 error = VC_Store(Buffer, buff_len, Length, "PHOTO;TYPE=");
434 if (error != ERR_NONE) return error;
435 switch (bitmap->Type) {
436 case PICTURE_BMP:
437 error = VC_Store(Buffer, buff_len, Length, "BMP;");
438 break;
439 case PICTURE_GIF:
440 error = VC_Store(Buffer, buff_len, Length, "GIF;");
441 break;
442 case PICTURE_JPG:
443 error = VC_Store(Buffer, buff_len, Length, "JPEG;");
444 break;
445 case PICTURE_ICN:
446 error = VC_Store(Buffer, buff_len, Length, "ICO;");
447 break;
448 case PICTURE_PNG:
449 error = VC_Store(Buffer, buff_len, Length, "PNG;");
450 break;
451 default:
452 smfprintf(di, "Unknown picture format: %d\n", bitmap->Type);
453 error = VC_Store(Buffer, buff_len, Length, "UNKNOWN;");
454 break;
455 }
456 if (error != ERR_NONE) return error;
457 error = VC_Store(Buffer, buff_len, Length, "ENCODING=BASE64:");
458 if (error != ERR_NONE) return error;
459 error = VC_StoreBase64(Buffer, buff_len, Length, bitmap->Buffer, bitmap->Length);
460 if (error != ERR_NONE) return error;
461 ignore = TRUE;
462 break;
463 case PBK_Caller_Group:
464 error = VC_StoreLine(Buffer, buff_len, Length, "X-CALLER-GROUP:%d", pbk->Entries[i].Number);
465 if (error != ERR_NONE) return error;
466 ignore = TRUE;
467 break;
468 case PBK_Private:
469 error = VC_StoreLine(Buffer, buff_len, Length, "X-PRIVATE:%d", pbk->Entries[i].Number);
470 if (error != ERR_NONE) return error;
471 ignore = TRUE;
472 break;
473 /* Not supported fields */
474 case PBK_Category:
475 case PBK_RingtoneID:
476 case PBK_PictureID:
477 case PBK_Text_UserID:
478 case PBK_CallLength:
479 case PBK_Text_Custom1:
480 case PBK_Text_Custom2:
481 case PBK_Text_Custom3:
482 case PBK_Text_Custom4:
483 case PBK_Text_PictureName:
484 pbk->Entries[i].AddError = ERR_NOTSUPPORTED;
485 ignore = TRUE;
486 break;
487 }
488 if (!ignore) {
489 error = VC_StoreText(Buffer, buff_len, Length, pbk->Entries[i].Text, "", FALSE);
490 if (error != ERR_NONE) return error;
491 }
492 }
493 /* Save name if it is composed from parts */
494 if (firstname != -1 || secondname != -1 || lastname != -1) {
495 pos = 0;
496 if (lastname != -1) {
497 CopyUnicodeString(buffer + 2*pos, pbk->Entries[lastname].Text);
498 pos += UnicodeLength(pbk->Entries[lastname].Text);
499 }
500 buffer[2*pos] = 0;
501 buffer[2*pos + 1] = ';';
502 pos++;
503 if (firstname != -1) {
504 CopyUnicodeString(buffer + 2*pos, pbk->Entries[firstname].Text);
505 pos += UnicodeLength(pbk->Entries[firstname].Text);
506 }
507 if (secondname != -1) {
508 buffer[2*pos] = 0;
509 buffer[2*pos + 1] = ' ';
510 pos++;
511 CopyUnicodeString(buffer + 2*pos, pbk->Entries[secondname].Text);
512 pos += UnicodeLength(pbk->Entries[secondname].Text);
513 }
514 buffer[2*pos] = 0;
515 buffer[2*pos + 1] = 0;
516 error = VC_StoreText(Buffer, buff_len, Length, buffer, "N", FALSE);
517 if (error != ERR_NONE) return error;
518 }
519 /* Save workaddress if it is composed from parts */
520 if (workaddress != -1 || workcity != -1 || workstate != -1 || workzip != -1 || workcountry != -1) {
521 pos = 0;
522 buffer[2*pos] = 0;
523 buffer[2*pos + 1] = ';';
524 pos++;
525 buffer[2*pos] = 0;
526 buffer[2*pos + 1] = ';';
527 pos++;
528 if (workaddress != -1) {
529 CopyUnicodeString(buffer + 2*pos, pbk->Entries[workaddress].Text);
530 pos += UnicodeLength(pbk->Entries[workaddress].Text);
531 }
532 buffer[2*pos] = 0;
533 buffer[2*pos + 1] = ';';
534 pos++;
535 if (workcity != -1) {
536 CopyUnicodeString(buffer + 2*pos, pbk->Entries[workcity].Text);
537 pos += UnicodeLength(pbk->Entries[workcity].Text);
538 }
539 buffer[2*pos] = 0;
540 buffer[2*pos + 1] = ';';
541 pos++;
542 if (workstate != -1) {
543 CopyUnicodeString(buffer + 2*pos, pbk->Entries[workstate].Text);
544 pos += UnicodeLength(pbk->Entries[workstate].Text);
545 }
546 buffer[2*pos] = 0;
547 buffer[2*pos + 1] = ';';
548 pos++;
549 if (workzip != -1) {
550 CopyUnicodeString(buffer + 2*pos, pbk->Entries[workzip].Text);
551 pos += UnicodeLength(pbk->Entries[workzip].Text);
552 }
553 buffer[2*pos] = 0;
554 buffer[2*pos + 1] = ';';
555 pos++;
556 if (workcountry != -1) {
557 CopyUnicodeString(buffer + 2*pos, pbk->Entries[workcountry].Text);
558 pos += UnicodeLength(pbk->Entries[workcountry].Text);
559 }
560 buffer[2*pos] = 0;
561 buffer[2*pos + 1] = 0;
562 error = VC_StoreText(Buffer, buff_len, Length, buffer, "ADR;WORK", FALSE);
563 if (error != ERR_NONE) return error;
564 }
565 /* Save address if it is composed from parts */
566 if (address != -1 || city != -1 || state != -1 || zip != -1 || country != -1) {
567 pos = 0;
568 buffer[2*pos] = 0;
569 buffer[2*pos + 1] = ';';
570 pos++;
571 buffer[2*pos] = 0;
572 buffer[2*pos + 1] = ';';
573 pos++;
574 if (address != -1) {
575 CopyUnicodeString(buffer + 2*pos, pbk->Entries[address].Text);
576 pos += UnicodeLength(pbk->Entries[address].Text);
577 }
578 buffer[2*pos] = 0;
579 buffer[2*pos + 1] = ';';
580 pos++;
581 if (city != -1) {
582 CopyUnicodeString(buffer + 2*pos, pbk->Entries[city].Text);
583 pos += UnicodeLength(pbk->Entries[city].Text);
584 }
585 buffer[2*pos] = 0;
586 buffer[2*pos + 1] = ';';
587 pos++;
588 if (state != -1) {
589 CopyUnicodeString(buffer + 2*pos, pbk->Entries[state].Text);
590 pos += UnicodeLength(pbk->Entries[state].Text);
591 }
592 buffer[2*pos] = 0;
593 buffer[2*pos + 1] = ';';
594 pos++;
595 if (zip != -1) {
596 CopyUnicodeString(buffer + 2*pos, pbk->Entries[zip].Text);
597 pos += UnicodeLength(pbk->Entries[zip].Text);
598 }
599 buffer[2*pos] = 0;
600 buffer[2*pos + 1] = ';';
601 pos++;
602 if (country != -1) {
603 CopyUnicodeString(buffer + 2*pos, pbk->Entries[country].Text);
604 pos += UnicodeLength(pbk->Entries[country].Text);
605 }
606 buffer[2*pos] = 0;
607 buffer[2*pos + 1] = 0;
608 error = VC_StoreText(Buffer, buff_len, Length, buffer, "ADR;HOME", FALSE);
609 if (error != ERR_NONE) return error;
610 }
611 } else {
612 return ERR_NOTSUPPORTED;
613 }
614 if (header) {
615 error = VC_StoreLine(Buffer, buff_len, Length, "END:VCARD");
616 if (error != ERR_NONE) return error;
617 }
618 return ERR_NONE;
619 }
620
GSM_TweakInternationalNumber(unsigned char * Number,const GSM_NumberType numType)621 void GSM_TweakInternationalNumber(unsigned char *Number, const GSM_NumberType numType)
622 {
623 /* Checks if International number needs to be corrected */
624 char* pos; /* current position in the buffer */
625 char buf[500]; /* Taken from DecodeUnicodeString(). How to get length of the encoded unicode string? There may be embedded 0s. */
626
627 if (numType == NUMBER_INTERNATIONAL_NUMBERING_PLAN_ISDN || numType + 1 == NUMBER_INTERNATIONAL_NUMBERING_PLAN_ISDN) {
628 sprintf(buf+1,"%s",DecodeUnicodeString(Number)); /* leave 1 free char before the number, we'll need it */
629 /* International number may be without + (e.g. (Sony)Ericsson)
630 we can add it, but must handle numbers in the form:
631 NNNNNN N - any digit (char)
632 *code#NNNNNN any number of Ns
633 *[*]code*NNNNNN[...]
634 other combinations (like *code1*code2*number#)
635 will have to be added if found in real life
636 Or does somebody know the exact allowed syntax
637 from some standard?
638 */
639 pos=buf+1;
640 if (*pos=='*') { /* Code? Skip it. */
641 /* probably with code */
642 while (*pos=='*') { /* skip leading asterisks */
643 *(pos-1)=*pos; /* shift the chars by one */
644 pos++;
645 }
646 while ((*pos!='*')&&(*pos!='#')) { /* skip code - anything except * or # */
647 *(pos-1)=*pos;
648 pos++;
649 }
650 *(pos-1)=*pos; /* shift the last delimiter */
651 pos++;
652 }
653 /* check the guessed location, if + is correctly there */
654 if (*pos=='+') {
655 /* yes, just shift the rest of the string */
656 while (*pos) {
657 *(pos-1) = *pos;
658 pos++;
659 }
660 *(pos-1)=0; /* kill the last char, which now got doubled */
661 } else {
662 /* no, insert + and exit, no more shifting */
663 *(pos-1)='+';
664 }
665 EncodeUnicode(Number,buf,strlen(buf));
666 }
667 }
668
669
670 #define CHECK_NUM_ENTRIES { \
671 if (Pbk->EntriesNum >= GSM_PHONEBOOK_ENTRIES) { error = ERR_MOREMEMORY; goto vcard_done; } \
672 Pbk->Entries[Pbk->EntriesNum].AddError = ERR_NONE; \
673 }
674
675 /**
676 * \bug We should avoid using static buffers here.
677 */
GSM_DecodeVCARD(GSM_Debug_Info * di,char * Buffer,size_t * Pos,GSM_MemoryEntry * Pbk,GSM_VCardVersion Version)678 GSM_Error GSM_DecodeVCARD(GSM_Debug_Info *di, char *Buffer, size_t *Pos, GSM_MemoryEntry *Pbk, GSM_VCardVersion Version)
679 {
680 char Buff[20000];
681 int Level = 0;
682 char *s;
683 int pos;
684 int version = 1;
685 GSM_Error error;
686 char *Line = NULL;
687 GSM_EntryLocation location;
688
689 Buff[0] = 0;
690 Pbk->EntriesNum = 0;
691 if (Version != SonyEricsson_VCard21_Phone) {
692 Pbk->Location = 0;
693 Pbk->MemoryType = MEM_MT;
694 }
695
696 while (1) {
697 free(Line);
698 Line = NULL;
699 error = GSM_GetVCSLine(&Line, Buffer, Pos, strlen(Buffer), TRUE);
700 if (error != ERR_NONE) goto vcard_done;
701 if (strlen(Line) == 0) break;
702 switch (Level) {
703 case 0:
704 if (strstr(Line,"BEGIN:VCARD")) Level = 1;
705 break;
706 case 1:
707 CHECK_NUM_ENTRIES;
708 if (strstr(Line,"END:VCARD")) {
709 goto vcard_complete;
710 }
711 if (strstr(Line, "VERSION:") != NULL) {
712 version = atoi(Line + 8);
713 dbgprintf(di, "vCard version %d\n", version);
714 }
715 if (ReadVCALText(Line, "N", Buff, (version >= 3), NULL)) {
716 pos = 0;
717 s = VCALGetTextPart(Buff, &pos);
718 if (s == NULL) {
719 CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text,Buff);
720 Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_Name;
721 Pbk->Entries[Pbk->EntriesNum].Location = PBK_Location_Unknown;
722 Pbk->EntriesNum++;
723 continue;
724 } else {
725 CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text, s);
726 /* Skip empty name */
727 if (UnicodeLength(Pbk->Entries[Pbk->EntriesNum].Text) > 0) {
728 Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_LastName;
729 Pbk->Entries[Pbk->EntriesNum].Location = PBK_Location_Unknown;
730 Pbk->EntriesNum++;
731 }
732
733 s = VCALGetTextPart(Buff, &pos);
734 if (s == NULL) continue;
735 CHECK_NUM_ENTRIES;
736 CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text, s);
737 Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_FirstName;
738 Pbk->Entries[Pbk->EntriesNum].Location = PBK_Location_Unknown;
739 Pbk->EntriesNum++;
740 continue;
741 }
742 }
743 if (strncmp(Line, "PHOTO;JPEG;BASE64:", 18) == 0 ||
744 strncmp(Line, "PHOTO;BASE64;JPEG:", 18) == 0 ||
745 strncmp(Line, "PHOTO;TYPE=JPEG;BASE64:", 23) == 0 ||
746 strncmp(Line, "PHOTO;BASE64;TYPE=JPEG:", 23) == 0 ||
747 strncmp(Line, "PHOTO;TYPE=JPEG;ENCODING=BASE64:", 32) == 0 ||
748 strncmp(Line, "PHOTO;ENCODING=BASE64;TYPE=JPEG:", 32) == 0 ||
749 strncmp(Line, "PHOTO;JPEG;ENCODING=BASE64:", 27) == 0 ||
750 strncmp(Line, "PHOTO;ENCODING=BASE64;JPEG:", 27) == 0) {
751 /* Find : (it should be there we matched it above) */
752 s = strchr(Line, ':');
753 s++;
754 /* Skip whitespace */
755 while (isspace((int)*s) && *s) s++;
756
757 Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Photo;
758 Pbk->Entries[Pbk->EntriesNum].Location = PBK_Location_Unknown;
759 Pbk->Entries[Pbk->EntriesNum].Picture.Type = PICTURE_JPG;
760
761 /* We allocate here more memory than is actually required */
762 Pbk->Entries[Pbk->EntriesNum].Picture.Buffer = (unsigned char *)malloc(strlen(s));
763 if (Pbk->Entries[Pbk->EntriesNum].Picture.Buffer == NULL)
764 return ERR_MOREMEMORY;
765
766 Pbk->Entries[Pbk->EntriesNum].Picture.Length =
767 DecodeBASE64(s, Pbk->Entries[Pbk->EntriesNum].Picture.Buffer, strlen(s));
768 Pbk->EntriesNum++;
769 continue;
770 }
771
772 if (ReadVCALText(Line, "TEL", Buff, (version >= 3), &location) ||
773 ReadVCALText(Line, "TEL;VOICE", Buff, (version >= 3), &location) ||
774 ReadVCALText(Line, "TEL;MAIN", Buff, (version >= 3), &location)) {
775 if (Buff[1] == '+') {
776 GSM_TweakInternationalNumber(Buff, NUMBER_INTERNATIONAL_NUMBERING_PLAN_ISDN);
777 }
778 CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text,Buff);
779 Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Number_General;
780 Pbk->Entries[Pbk->EntriesNum].Location = location;
781 Pbk->Entries[Pbk->EntriesNum].SMSList[0] = 0;
782 Pbk->Entries[Pbk->EntriesNum].VoiceTag = 0;
783 Pbk->EntriesNum++;
784 continue;
785 }
786 if (ReadVCALText(Line, "TEL;VIDEO", Buff, (version >= 3), &location)) {
787 if (Buff[1] == '+') {
788 GSM_TweakInternationalNumber(Buff, NUMBER_INTERNATIONAL_NUMBERING_PLAN_ISDN);
789 }
790 CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text,Buff);
791 Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Number_Video;
792 Pbk->Entries[Pbk->EntriesNum].Location = location;
793 Pbk->Entries[Pbk->EntriesNum].SMSList[0] = 0;
794 Pbk->Entries[Pbk->EntriesNum].VoiceTag = 0;
795 Pbk->EntriesNum++;
796 continue;
797 }
798 if (ReadVCALText(Line, "TEL;CELL", Buff, (version >= 3), &location) ||
799 ReadVCALText(Line, "TEL;CELL;VOICE", Buff, (version >= 3), &location)) {
800 if (Buff[1] == '+') {
801 GSM_TweakInternationalNumber(Buff, NUMBER_INTERNATIONAL_NUMBERING_PLAN_ISDN);
802 }
803 CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text,Buff);
804 Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Number_Mobile;
805 Pbk->Entries[Pbk->EntriesNum].Location = location;
806 Pbk->Entries[Pbk->EntriesNum].SMSList[0] = 0;
807 Pbk->Entries[Pbk->EntriesNum].VoiceTag = 0;
808 Pbk->EntriesNum++;
809 continue;
810 }
811 if (ReadVCALText(Line, "TEL;OTHER", Buff, (version >= 3), &location) ||
812 ReadVCALText(Line, "TEL;OTHER;VOICE", Buff, (version >= 3), &location)) {
813 if (Buff[1] == '+') {
814 GSM_TweakInternationalNumber(Buff, NUMBER_INTERNATIONAL_NUMBERING_PLAN_ISDN);
815 }
816 CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text,Buff);
817 Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Number_Other;
818 Pbk->Entries[Pbk->EntriesNum].Location = location;
819 Pbk->Entries[Pbk->EntriesNum].SMSList[0] = 0;
820 Pbk->Entries[Pbk->EntriesNum].VoiceTag = 0;
821 Pbk->EntriesNum++;
822 continue;
823 }
824 if (ReadVCALText(Line, "TEL;PAGER", Buff, (version >= 3), &location) ||
825 ReadVCALText(Line, "TEL;PAGER;VOICE", Buff, (version >= 3), &location)) {
826 if (Buff[1] == '+') {
827 GSM_TweakInternationalNumber(Buff, NUMBER_INTERNATIONAL_NUMBERING_PLAN_ISDN);
828 }
829 CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text,Buff);
830 Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Number_Other;
831 Pbk->Entries[Pbk->EntriesNum].Location = location;
832 Pbk->Entries[Pbk->EntriesNum].SMSList[0] = 0;
833 Pbk->Entries[Pbk->EntriesNum].VoiceTag = 0;
834 Pbk->EntriesNum++;
835 continue;
836 }
837 if (ReadVCALText(Line, "TEL;MSG", Buff, (version >= 3), &location) ||
838 ReadVCALText(Line, "TEL;MSG;VOICE", Buff, (version >= 3), &location)) {
839 if (Buff[1] == '+') {
840 GSM_TweakInternationalNumber(Buff, NUMBER_INTERNATIONAL_NUMBERING_PLAN_ISDN);
841 }
842 CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text,Buff);
843 Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Number_Other;
844 Pbk->Entries[Pbk->EntriesNum].Location = location;
845 Pbk->Entries[Pbk->EntriesNum].SMSList[0] = 0;
846 Pbk->Entries[Pbk->EntriesNum].VoiceTag = 0;
847 Pbk->EntriesNum++;
848 continue;
849 }
850 /* FAX + VOICE looks like nonsense */
851 if (ReadVCALText(Line, "TEL;FAX", Buff, (version >= 3), &location) ||
852 ReadVCALText(Line, "TEL;FAX;VOICE", Buff, (version >= 3), &location)) {
853 if (Buff[1] == '+') {
854 GSM_TweakInternationalNumber(Buff, NUMBER_INTERNATIONAL_NUMBERING_PLAN_ISDN);
855 }
856 CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text,Buff);
857 Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Number_Fax;
858 Pbk->Entries[Pbk->EntriesNum].Location = location;
859 Pbk->Entries[Pbk->EntriesNum].SMSList[0] = 0;
860 Pbk->Entries[Pbk->EntriesNum].VoiceTag = 0;
861 Pbk->EntriesNum++;
862 continue;
863 }
864 if (ReadVCALText(Line, "TITLE", Buff, (version >= 3), &location)) {
865 CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text,Buff);
866 Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_JobTitle;
867 Pbk->Entries[Pbk->EntriesNum].Location = location;
868 Pbk->EntriesNum++;
869 continue;
870 }
871 if (ReadVCALText(Line, "NOTE", Buff, (version >= 3), &location)) {
872 CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text,Buff);
873 Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_Note;
874 Pbk->Entries[Pbk->EntriesNum].Location = location;
875 Pbk->EntriesNum++;
876 continue;
877 }
878 if (ReadVCALText(Line, "LABEL", Buff, (version >= 3), &location) ||
879 ReadVCALText(Line, "ADR", Buff, (version >= 3), &location)) {
880 pos = 0;
881 s = VCALGetTextPart(Buff, &pos); /* PO box, ignore for now */
882 if (s == NULL) {
883 CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text,Buff);
884 Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_Postal;
885 Pbk->Entries[Pbk->EntriesNum].Location = location;
886 Pbk->EntriesNum++;
887 continue;
888 } else {
889 s = VCALGetTextPart(Buff, &pos); /* Don't know ... */
890
891 s = VCALGetTextPart(Buff, &pos);
892 if (s == NULL) continue;
893 CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text, s);
894 Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_StreetAddress;
895 Pbk->Entries[Pbk->EntriesNum].Location = location;
896 Pbk->EntriesNum++;
897 CHECK_NUM_ENTRIES;
898
899 s = VCALGetTextPart(Buff, &pos);
900 if (s == NULL) continue;
901 CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text, s);
902 Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_City;
903 Pbk->Entries[Pbk->EntriesNum].Location = location;
904 Pbk->EntriesNum++;
905 CHECK_NUM_ENTRIES;
906
907 s = VCALGetTextPart(Buff, &pos);
908 if (s == NULL) continue;
909 CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text, s);
910 Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_State;
911 Pbk->Entries[Pbk->EntriesNum].Location = location;
912 Pbk->EntriesNum++;
913 CHECK_NUM_ENTRIES;
914
915 s = VCALGetTextPart(Buff, &pos);
916 if (s == NULL) continue;
917 CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text, s);
918 Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_Zip;
919 Pbk->Entries[Pbk->EntriesNum].Location = location;
920 Pbk->EntriesNum++;
921 CHECK_NUM_ENTRIES;
922
923 s = VCALGetTextPart(Buff, &pos);
924 if (s == NULL) continue;
925 CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text, s);
926 Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_Country;
927 Pbk->Entries[Pbk->EntriesNum].Location = location;
928 Pbk->EntriesNum++;
929 continue;
930 }
931 }
932 if (ReadVCALText(Line, "EMAIL", Buff, (version >= 3), &location) ||
933 ReadVCALText(Line, "EMAIL;OTHER", Buff, (version >= 3), &location) ||
934 ReadVCALText(Line, "EMAIL;INTERNET", Buff, (version >= 3), &location)) {
935 CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text,Buff);
936 Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_Email;
937 Pbk->Entries[Pbk->EntriesNum].Location = location;
938 Pbk->EntriesNum++;
939 continue;
940 }
941 if (ReadVCALText(Line, "X-IRMC-LUID", Buff, (version >= 3), &location)) {
942 CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text,Buff);
943 Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_LUID;
944 Pbk->Entries[Pbk->EntriesNum].Location = location;
945 Pbk->EntriesNum++;
946 continue;
947 }
948 if (ReadVCALText(Line, "X-DTMF", Buff, (version >= 3), &location)) {
949 CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text,Buff);
950 Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_DTMF;
951 Pbk->Entries[Pbk->EntriesNum].Location = location;
952 Pbk->EntriesNum++;
953 continue;
954 }
955 if (ReadVCALText(Line, "X-SIP", Buff, (version >= 3), &location)) {
956 CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text,Buff);
957 Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_SIP;
958 Pbk->Entries[Pbk->EntriesNum].Location = location;
959 Pbk->EntriesNum++;
960 continue;
961 }
962 if (ReadVCALText(Line, "X-SIP;VOIP", Buff, (version >= 3), &location)) {
963 CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text,Buff);
964 Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_VOIP;
965 Pbk->Entries[Pbk->EntriesNum].Location = location;
966 Pbk->EntriesNum++;
967 continue;
968 }
969 if (ReadVCALText(Line, "X-WV-ID", Buff, (version >= 3), &location)) {
970 CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text,Buff);
971 Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_WVID;
972 Pbk->Entries[Pbk->EntriesNum].Location = location;
973 Pbk->EntriesNum++;
974 continue;
975 }
976 if (ReadVCALText(Line, "X-SIP;SWIS", Buff, (version >= 3), &location)) {
977 CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text,Buff);
978 Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_SWIS;
979 Pbk->Entries[Pbk->EntriesNum].Location = location;
980 Pbk->EntriesNum++;
981 continue;
982 }
983 if (ReadVCALText(Line, "X-SIP;POC", Buff, (version >= 3), &location)) {
984 CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text,Buff);
985 Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_PushToTalkID;
986 Pbk->Entries[Pbk->EntriesNum].Location = location;
987 Pbk->EntriesNum++;
988 continue;
989 }
990 if (ReadVCALText(Line, "URL", Buff, (version >= 3), &location)) {
991 CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text,Buff);
992 Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_URL;
993 Pbk->Entries[Pbk->EntriesNum].Location = location;
994 Pbk->EntriesNum++;
995 continue;
996 }
997 if (ReadVCALText(Line, "ORG", Buff, (version >= 3), &location)) {
998 CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text,Buff);
999 Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_Company;
1000 Pbk->Entries[Pbk->EntriesNum].Location = location;
1001 Pbk->EntriesNum++;
1002 continue;
1003 }
1004 if (ReadVCALText(Line, "NICKNAME", Buff, (version >= 3), &location)) {
1005 CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text,Buff);
1006 Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_NickName;
1007 Pbk->Entries[Pbk->EntriesNum].Location = location;
1008 Pbk->EntriesNum++;
1009 continue;
1010 }
1011 if (ReadVCALText(Line, "FN", Buff, (version >= 3), &location)) {
1012 CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text,Buff);
1013 Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_FormalName;
1014 Pbk->Entries[Pbk->EntriesNum].Location = location;
1015 Pbk->EntriesNum++;
1016 continue;
1017 }
1018 if (ReadVCALText(Line, "X-NAME-PREFIX", Buff, (version >= 3), &location)) {
1019 CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text,Buff);
1020 Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_NamePrefix;
1021 Pbk->Entries[Pbk->EntriesNum].Location = location;
1022 Pbk->EntriesNum++;
1023 continue;
1024 }
1025 if (ReadVCALText(Line, "X-NAME-SUFFIX", Buff, (version >= 3), &location)) {
1026 CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text,Buff);
1027 Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_NameSuffix;
1028 Pbk->Entries[Pbk->EntriesNum].Location = location;
1029 Pbk->EntriesNum++;
1030 continue;
1031 }
1032 if (ReadVCALText(Line, "CATEGORIES", Buff, (version >= 3), &location)) {
1033 CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text,Buff);
1034 Pbk->Entries[Pbk->EntriesNum].Number = -1;
1035 Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Category;
1036 Pbk->Entries[Pbk->EntriesNum].Location = location;
1037 Pbk->EntriesNum++;
1038 continue;
1039 }
1040 if (ReadVCALText(Line, "BDAY", Buff, (version >= 3), NULL)) {
1041 if (ReadVCALDateTime(DecodeUnicodeString(Buff), &Pbk->Entries[Pbk->EntriesNum].Date)) {
1042 Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Date;
1043 Pbk->Entries[Pbk->EntriesNum].Location = PBK_Location_Unknown;
1044 Pbk->EntriesNum++;
1045 continue;
1046 }
1047 }
1048 if (ReadVCALText(Line, "LAST-MODIFIED", Buff, (version >= 3), NULL)) {
1049 if (ReadVCALDateTime(DecodeUnicodeString(Buff), &Pbk->Entries[Pbk->EntriesNum].Date)) {
1050 Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_LastModified;
1051 Pbk->Entries[Pbk->EntriesNum].Location = PBK_Location_Unknown;
1052 Pbk->EntriesNum++;
1053 continue;
1054 }
1055 }
1056 if (ReadVCALText(Line, "X-PRIVATE", Buff, (version >= 3), NULL)) {
1057 Pbk->Entries[Pbk->EntriesNum].Number = atoi(DecodeUnicodeString(Buff));
1058 Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Private;
1059 Pbk->Entries[Pbk->EntriesNum].Location = PBK_Location_Unknown;
1060 Pbk->EntriesNum++;
1061 continue;
1062 }
1063 if (ReadVCALText(Line, "X-CALLER-GROUP", Buff, (version >= 3), NULL)) {
1064 Pbk->Entries[Pbk->EntriesNum].Number = atoi(DecodeUnicodeString(Buff));
1065 Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Caller_Group;
1066 Pbk->Entries[Pbk->EntriesNum].Location = PBK_Location_Unknown;
1067 Pbk->EntriesNum++;
1068 continue;
1069 }
1070 if (ReadVCALText(Line, "X-GAMMU-LOCATION", Buff, (version >= 3), NULL)) {
1071 Pbk->Location = atoi(DecodeUnicodeString(Buff));
1072 }
1073 if (ReadVCALText(Line, "X-GAMMU-MEMORY", Buff, (version >= 3), NULL)) {
1074 Pbk->MemoryType = GSM_StringToMemoryType(DecodeUnicodeString(Buff));
1075 }
1076 break;
1077 }
1078 }
1079
1080 vcard_complete:
1081 if (Pbk->EntriesNum == 0) error = ERR_EMPTY;
1082 else error = ERR_NONE;
1083
1084 vcard_done:
1085 free(Line);
1086 Line=NULL;
1087 return error;
1088 }
1089
GSM_FreeMemoryEntry(GSM_MemoryEntry * Entry)1090 void GSM_FreeMemoryEntry(GSM_MemoryEntry *Entry)
1091 {
1092 int i;
1093
1094 for (i = 0; i < Entry->EntriesNum; i++) {
1095 switch (Entry->Entries[i].EntryType) {
1096 case PBK_Photo:
1097 free(Entry->Entries[i].Picture.Buffer);
1098 Entry->Entries[i].Picture.Buffer = NULL;
1099 Entry->Entries[i].Picture.Length = 0;
1100 break;
1101 default:
1102 break;
1103 }
1104 }
1105 }
1106
1107 /* How should editor hadle tabs in this file? Add editor commands here.
1108 * vim: noexpandtab sw=8 ts=8 sts=8:
1109 */
1110