00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "vcard.h"
00023 #include <string.h>
00024 #include <stdlib.h>
00025 #include <ctype.h>
00026 #include <sstream>
00027
00028 namespace Barry { namespace Sync {
00029
00030
00031
00032
00033 namespace {
00034
00035 void ToLower(std::string &str)
00036 {
00037 size_t i = 0;
00038 while( i < str.size() ) {
00039 str[i] = tolower(str[i]);
00040 i++;
00041 }
00042 }
00043
00044 }
00045
00046
00047
00048
00049 vCard::vCard()
00050 : m_gCardData(0)
00051 {
00052 }
00053
00054 vCard::~vCard()
00055 {
00056 if( m_gCardData ) {
00057 g_free(m_gCardData);
00058 }
00059 }
00060
00061 void vCard::AddAddress(const char *rfc_type, const Barry::PostalAddress &address)
00062 {
00063
00064 vAttrPtr label = NewAttr("LABEL");
00065 AddParam(label, "TYPE", rfc_type);
00066 AddValue(label, address.GetLabel().c_str());
00067 AddAttr(label);
00068
00069
00070 vAttrPtr adr = NewAttr("ADR");
00071 AddParam(adr, "TYPE", rfc_type);
00072 AddValue(adr, address.Address3.c_str());
00073 AddValue(adr, address.Address2.c_str());
00074 AddValue(adr, address.Address1.c_str());
00075 AddValue(adr, address.City.c_str());
00076 AddValue(adr, address.Province.c_str());
00077 AddValue(adr, address.PostalCode.c_str());
00078 AddValue(adr, address.Country.c_str());
00079 AddAttr(adr);
00080 }
00081
00082 void vCard::AddCategories(const Barry::CategoryList &categories)
00083 {
00084 if( !categories.size() )
00085 return;
00086
00087 vAttrPtr cat = NewAttr("CATEGORIES");
00088 Barry::CategoryList::const_iterator i = categories.begin();
00089 for( ; i < categories.end(); ++i ) {
00090 AddValue(cat, i->c_str());
00091 }
00092 AddAttr(cat);
00093 }
00094
00095
00096
00097 void vCard::AddPhoneCond(const std::string &phone)
00098 {
00099 if( phone.size() ) {
00100 vAttrPtr tel = NewAttr("TEL", phone.c_str());
00101 AddAttr(tel);
00102 }
00103 }
00104
00105
00106 void vCard::AddPhoneCond(const char *rfc_type, const std::string &phone)
00107 {
00108 if( phone.size() ) {
00109 vAttrPtr tel = NewAttr("TEL", phone.c_str());
00110 AddParam(tel, "TYPE", rfc_type);
00111 AddAttr(tel);
00112 }
00113 }
00114
00115 void vCard::ParseAddress(vAttr &adr, Barry::PostalAddress &address)
00116 {
00117
00118 address.Address3 = adr.GetValue(0);
00119 address.Address2 = adr.GetValue(1);
00120 address.Address1 = adr.GetValue(2);
00121 address.City = adr.GetValue(3);
00122 address.Province = adr.GetValue(4);
00123 address.PostalCode = adr.GetValue(5);
00124 address.Country = adr.GetValue(6);
00125 }
00126
00127 void vCard::ParseCategories(vAttr &cat, Barry::CategoryList &cats)
00128 {
00129 int i = 0;
00130 std::string value = cat.GetValue(i);
00131 while( value.size() ) {
00132 cats.push_back(value);
00133 i++;
00134 value = cat.GetValue(i);
00135 }
00136 }
00137
00138
00139
00140
00141
00142 const std::string& vCard::ToVCard(const Barry::Contact &con)
00143 {
00144
00145 std::ostringstream oss;
00146 con.Dump(oss);
00147
00148
00149
00150 Clear();
00151 SetFormat( b_vformat_new() );
00152 if( !Format() )
00153 throw ConvertError("resource error allocating vformat");
00154
00155
00156 m_BarryContact = con;
00157
00158
00159
00160
00161
00162 AddAttr(NewAttr("PRODID", "-//OpenSync//NONSGML Barry Contact Record//EN"));
00163
00164 std::string fullname = con.GetFullName();
00165 if( fullname.size() ) {
00166 AddAttr(NewAttr("FN", fullname.c_str()));
00167 }
00168 else {
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179 }
00180
00181 if( con.FirstName.size() || con.LastName.size() ) {
00182 vAttrPtr name = NewAttr("N");
00183 AddValue(name, con.LastName.c_str());
00184 AddValue(name, con.FirstName.c_str());
00185 AddValue(name, "");
00186 AddValue(name, con.Prefix.c_str());
00187 AddValue(name, "");
00188 AddAttr(name);
00189 }
00190
00191 if( con.WorkAddress.HasData() )
00192 AddAddress("work", con.WorkAddress);
00193 if( con.HomeAddress.HasData() )
00194 AddAddress("home", con.HomeAddress);
00195
00196
00197
00198
00199 AddPhoneCond("voice,pref", con.Phone);
00200 AddPhoneCond("fax", con.Fax);
00201 AddPhoneCond("voice,work", con.WorkPhone);
00202 AddPhoneCond("voice,work", con.WorkPhone2);
00203 AddPhoneCond("voice,home", con.HomePhone);
00204 AddPhoneCond("voice,home", con.HomePhone2);
00205 AddPhoneCond("msg,cell", con.MobilePhone);
00206 AddPhoneCond("msg,pager", con.Pager);
00207 AddPhoneCond("voice", con.OtherPhone);
00208
00209
00210 Barry::Contact::EmailList::const_iterator eai = con.EmailAddresses.begin();
00211 for( unsigned int i = 0; eai != con.EmailAddresses.end(); ++eai, ++i ) {
00212 const std::string& e = con.GetEmail(i);
00213 if( e.size() ) {
00214 vAttrPtr email = NewAttr("EMAIL", e.c_str());
00215 if( i == 0 ) {
00216 AddParam(email, "TYPE", "internet,pref");
00217 }
00218 else {
00219 AddParam(email, "TYPE", "internet");
00220 }
00221 AddAttr(email);
00222 }
00223 }
00224
00225 if( con.JobTitle.size() ) {
00226 AddAttr(NewAttr("TITLE", con.JobTitle.c_str()));
00227 AddAttr(NewAttr("ROLE", con.JobTitle.c_str()));
00228 }
00229
00230 if( con.Company.size() ) {
00231
00232 vAttrPtr org = NewAttr("ORG", con.Company.c_str());
00233 AddValue(org, "");
00234 AddAttr(org);
00235 }
00236
00237 if( con.Birthday.HasData() )
00238 AddAttr(NewAttr("BDAY", con.Birthday.ToYYYYMMDD().c_str()));
00239
00240 if( con.Notes.size() )
00241 AddAttr(NewAttr("NOTE", con.Notes.c_str()));
00242 if( con.URL.size() )
00243 AddAttr(NewAttr("URL", con.URL.c_str()));
00244 if( con.Categories.size() )
00245 AddCategories(con.Categories);
00246
00247
00248 if (con.Image.size()) {
00249 vAttrPtr photo = NewAttr("PHOTO");
00250 AddEncodedValue(photo, VF_ENCODING_BASE64, con.Image.c_str(), con.Image.size());
00251 AddParam(photo, "ENCODING", "BASE64");
00252 AddAttr(photo);
00253 }
00254
00255
00256 m_gCardData = b_vformat_to_string(Format(), VFORMAT_CARD_30);
00257 m_vCardData = m_gCardData;
00258
00259
00260 return m_vCardData;
00261 }
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279 class SlidingPair
00280 {
00281 std::string &m_first;
00282 std::string &m_second;
00283 int m_evolutionSlot1, m_evolutionSlot2;
00284 public:
00285 static const int DefaultSlot = 99;
00286 SlidingPair(std::string &first, std::string &second)
00287 : m_first(first)
00288 , m_second(second)
00289 , m_evolutionSlot1(DefaultSlot)
00290 , m_evolutionSlot2(DefaultSlot)
00291 {
00292 }
00293
00294 bool assign(const std::string &value, const char *type_str, int evolutionSlot)
00295 {
00296 bool used = false;
00297
00298 if( strstr(type_str, "pref") || evolutionSlot < m_evolutionSlot1 ) {
00299 m_second = m_first;
00300 m_evolutionSlot2 = m_evolutionSlot1;
00301
00302 m_first = value;
00303 m_evolutionSlot1 = evolutionSlot;
00304
00305 used = true;
00306 }
00307 else if( evolutionSlot < m_evolutionSlot2 ) {
00308 m_second = value;
00309 m_evolutionSlot2 = evolutionSlot;
00310 used = true;
00311 }
00312 else if( m_first.size() == 0 ) {
00313 m_first = value;
00314 m_evolutionSlot1 = evolutionSlot;
00315 used = true;
00316 }
00317 else if( m_second.size() == 0 ) {
00318 m_second = value;
00319 m_evolutionSlot2 = evolutionSlot;
00320 used = true;
00321 }
00322
00323 return used;
00324 }
00325 };
00326
00327
00328
00329
00330 const Barry::Contact& vCard::ToBarry(const char *vcard, uint32_t RecordId)
00331 {
00332 using namespace std;
00333
00334
00335
00336
00337
00338 Clear();
00339
00340
00341 m_vCardData = vcard;
00342
00343
00344 SetFormat( b_vformat_new_from_string(vcard) );
00345 if( !Format() )
00346 throw ConvertError("resource error allocating vformat");
00347
00348
00349
00350
00351
00352
00353 Barry::Contact &con = m_BarryContact;
00354 con.SetIds(Barry::Contact::GetDefaultRecType(), RecordId);
00355
00356 vAttr name = GetAttrObj("N");
00357 if( name.Get() ) {
00358
00359 con.LastName = name.GetValue(0);
00360 con.FirstName = name.GetValue(1);
00361 con.Prefix = name.GetValue(3);
00362 }
00363
00364 vAttr adr = GetAttrObj("ADR");
00365 for( int i = 0; adr.Get(); adr = GetAttrObj("ADR", ++i) )
00366 {
00367 std::string type = adr.GetAllParams("TYPE");
00368 ToLower(type);
00369
00370
00371 if( strstr(type.c_str(), "work") )
00372 ParseAddress(adr, con.WorkAddress);
00373 if( strstr(type.c_str(), "home") )
00374 ParseAddress(adr, con.HomeAddress);
00375 }
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389 SlidingPair HomePair(con.HomePhone, con.HomePhone2);
00390 SlidingPair WorkPair(con.WorkPhone, con.WorkPhone2);
00391 SlidingPair OtherPair(con.Phone, con.OtherPhone);
00392
00393
00394
00395
00396 vAttr tel = GetAttrObj("TEL");
00397 for( int i = 0; tel.Get(); tel = GetAttrObj("TEL", ++i) )
00398 {
00399
00400 std::string stype = tel.GetAllParams("TYPE");
00401
00402
00403
00404
00405
00406
00407 int evolutionSlot = atoi(tel.GetAllParams("X-EVOLUTION-UI-SLOT").c_str());
00408 if( evolutionSlot == 0 )
00409 evolutionSlot = SlidingPair::DefaultSlot;
00410
00411
00412
00413 ToLower(stype);
00414
00415
00416 const char *type = stype.c_str();
00417 bool used = false;
00418
00419
00420
00421
00422
00423 bool mobile_type = strstr(type, "cell") ||
00424 strstr(type, "pcs") ||
00425 strstr(type, "car");
00426 bool fax_type = strstr(type, "fax");
00427 bool pager_type = strstr(type, "pager");
00428 if( fax_type && (mobile_type || pager_type) ) {
00429
00430
00431
00432
00433 continue;
00434 }
00435
00436
00437 if( strstr(type, "pref") ) {
00438
00439 if( strstr(type, "cell") ) {
00440 used = OtherPair.assign(tel.GetValue(), type, evolutionSlot);
00441 }
00442
00443 else if( strstr(type, "voice") && con.Phone.size() == 0 ) {
00444 used = OtherPair.assign(tel.GetValue(), type, evolutionSlot);
00445 }
00446 }
00447
00448
00449
00450 if( strstr(type, "fax") && (strstr(type, "pref") || con.Fax.size() == 0) ) {
00451 con.Fax = tel.GetValue();
00452 used = true;
00453 }
00454
00455 else if( mobile_type && (strstr(type, "pref") || con.MobilePhone.size() == 0) ) {
00456 con.MobilePhone = tel.GetValue();
00457 used = true;
00458 }
00459
00460 else if( strstr(type, "pager") && (strstr(type, "pref") || con.Pager.size() == 0) ) {
00461 con.Pager = tel.GetValue();
00462 used = true;
00463 }
00464
00465
00466
00467 else if( strstr(type, "bbs") || strstr(type, "video") || strstr(type, "modem") ) {
00468 }
00469 else if( strstr(type, "isdn") ) {
00470 }
00471
00472 else {
00473 if( strstr(type, "work") ) {
00474 used = WorkPair.assign(tel.GetValue(), type, evolutionSlot);
00475 }
00476
00477 if( strstr(type, "home") ) {
00478 used = HomePair.assign(tel.GetValue(), type, evolutionSlot);
00479 }
00480 }
00481
00482
00483
00484 if( !used && con.OtherPhone.size() == 0 ) {
00485 OtherPair.assign(tel.GetValue(), type, evolutionSlot);
00486 }
00487 }
00488
00489
00490
00491
00492 vAttr email = GetAttrObj("EMAIL");
00493 for( int i = 0; email.Get(); email = GetAttrObj("EMAIL", ++i) )
00494 {
00495 std::string type = email.GetAllParams("TYPE");
00496 ToLower(type);
00497
00498 bool of_interest = (i == 0 || strstr(type.c_str(), "pref"));
00499 bool x400 = strstr(type.c_str(), "x400");
00500
00501 if( of_interest && !x400 ) {
00502 con.EmailAddresses.insert(con.EmailAddresses.begin(), email.GetValue());
00503 }
00504 else {
00505 con.EmailAddresses.push_back( email.GetValue() );
00506 }
00507 }
00508
00509
00510
00511 con.JobTitle = GetAttr("TITLE");
00512 if( !con.JobTitle.size() )
00513 con.JobTitle = GetAttr("ROLE");
00514
00515 con.Company = GetAttr("ORG");
00516 con.Notes = GetAttr("NOTE");
00517 con.URL = GetAttr("URL");
00518 if( GetAttr("BDAY").size() && !con.Birthday.FromYYYYMMDD( GetAttr("BDAY") ) )
00519 throw ConvertError("Unable to parse BDAY field");
00520
00521
00522 vAttr photo = GetAttrObj("PHOTO");
00523 if (photo.Get()) {
00524 std::string sencoding = photo.GetAllParams("ENCODING");
00525
00526 ToLower(sencoding);
00527
00528 const char *encoding = sencoding.c_str();
00529
00530 if (strstr(encoding, "quoted-printable")) {
00531 photo.Get()->encoding = VF_ENCODING_QP;
00532
00533 con.Image = photo.GetDecodedValue();
00534 }
00535 else if (strstr(encoding, "b")) {
00536 photo.Get()->encoding = VF_ENCODING_BASE64;
00537
00538 con.Image = photo.GetDecodedValue();
00539 }
00540
00541
00542 }
00543
00544 vAttr cat = GetAttrObj("CATEGORIES");
00545 if( cat.Get() )
00546 ParseCategories(cat, con.Categories);
00547
00548
00549
00550 if( !con.GetFullName().size() && !con.Company.size() )
00551 throw ConvertError("FN and ORG fields both blank in VCARD data");
00552
00553 return m_BarryContact;
00554 }
00555
00556
00557 char* vCard::ExtractVCard()
00558 {
00559 char *ret = m_gCardData;
00560 m_gCardData = 0;
00561 return ret;
00562 }
00563
00564 void vCard::Clear()
00565 {
00566 vBase::Clear();
00567 m_vCardData.clear();
00568 m_BarryContact.Clear();
00569
00570 if( m_gCardData ) {
00571 g_free(m_gCardData);
00572 m_gCardData = 0;
00573 }
00574 }
00575
00576 }}
00577