void VObject::fromNativeEncoding() { bool is_30 = !wcscmp(getVersion(), TEXT("3.0")); for (int index = propertiesCount() - 1; index >= 0; index--) { VProperty *vprop = getProperty(index); if (vprop->equalsEncoding(TEXT("QUOTED-PRINTABLE"))) { // remove this, we cannot recreate it vprop->removeParameter(TEXT("ENCODING")); } WCHAR *native = vprop->getValue(); // in the worst case every comma/linebreak is replaced with // two characters and each \n with =0D=0A WCHAR *foreign = new WCHAR[6 * wcslen(native) + 1]; WCHAR curr; int in = 0, out = 0; // line break is encoded with either one or two // characters on different platforms const int linebreaklen = wcslen(SYNC4J_LINEBREAK); // use backslash for special characters, // if necessary do quoted-printable encoding bool doquoted = !is_30 && wcsstr(native, SYNC4J_LINEBREAK) != NULL; while ((curr = native[in]) != 0) { in++; switch (curr) { case ',': if (!is_30) { // normal character foreign[out] = curr; out++; break; } // no break! case ';': case '\\': foreign[out] = '\\'; out++; foreign[out] = curr; out++; break; case SEMICOLON_REPLACEMENT: foreign[out] = ';'; out++; break; default: if (doquoted && (curr == '=' || (unsigned char)curr >= 128)) { // escape = and non-ASCII characters swprintf(foreign + out, 4, TEXT("=%02X"), (unsigned int)(unsigned char)curr); out += 3; } else if (!wcsncmp(native + in - 1, SYNC4J_LINEBREAK, linebreaklen)) { // line break if (is_30) { foreign[out] = '\\'; out++; foreign[out] = 'n'; out++; } else { wcscpy(foreign + out, TEXT("=0D=0A")); out += 6; } in += linebreaklen - 1; } else { foreign[out] = curr; out++; } break; } } foreign[out] = 0; vprop->setValue(foreign); delete [] foreign; if (doquoted) { // we have used quoted-printable encoding vprop->addParameter(TEXT("ENCODING"), TEXT("QUOTED-PRINTABLE")); } } }
VProperty* VConverter::readFieldHeader(WCHAR* buffer) { WCHAR* headerIndex = NULL; WCHAR* quotaIndex = NULL; quotaIndex = wcschr(buffer, '"'); headerIndex = wcschr(buffer, ':'); if(!headerIndex) return NULL; bool quota = false; // If the header contains a quotation mark, // then rescan it starting directly after the _quotation mark_ // (not after the end of the header, as in the original code) // to find the real end of the header. // // The reason for this code apparently is that the simple search above // might have found a headerIndex which points into the middle of // the quoted string. // // A better solution would be to always scan the header properly. if(quotaIndex && quotaIndex < headerIndex) { quota = true; int len = int(wcslen(buffer)); for(int i = int(quotaIndex - buffer) + 1; i < len; i++) { if(buffer[i] == '"') quota = !quota; if(buffer[i] == ':' && !quota) { headerIndex = &buffer[i]; break; } } } if(quota) return NULL; VProperty* prop = new VProperty(NULL); WCHAR* header = new WCHAR[wcslen(buffer) + 1]; buffer[headerIndex - buffer] = '\0'; wcscpy(header, buffer); // Shift the remaing string to the front of the buffer. // Using wcscpy() for that is incorrect because the standard // does not guarantee in which order bytes are moved! // wcscpy(buffer, ++headerIndex); ++headerIndex; memmove(buffer, headerIndex, (wcslen(headerIndex) + 1) * sizeof(*headerIndex)); //if the header is folded (in .ics files) //we need to remove the folding WCHAR* headerFolding = NULL; if ((headerFolding = wcsstr(header, TEXT("\n ")))) { header[headerFolding - header] = '\0'; } WCHAR seps[] = TEXT(";"); WCHAR *token; bool first = true; token = wcstok( header, seps ); while( token != NULL ) { if (first) { WCHAR* group = new WCHAR[wcslen(token) + 1]; if(extractGroup(token, group)) prop->addParameter(TEXT("GROUP"), group); else delete [] group; group= NULL; prop->setName(token); first = false; } else { WCHAR* paramIndex; paramIndex = wcschr(token, '='); if(paramIndex) { WCHAR* paramName = new WCHAR[wcslen(token) + 1]; token[paramIndex - token] = '\0'; wcscpy(paramName, token); ++paramIndex; memmove(token, paramIndex, (wcslen(paramIndex) + 1) * sizeof(*paramIndex)); WCHAR* paramVal = new WCHAR[wcslen(token) + 1]; wcscpy(paramVal, token); prop->addParameter(paramName, paramVal); delete [] paramName; paramName = NULL; delete [] paramVal; paramVal = NULL; } else { prop->addParameter(token,NULL); } } token = wcstok( NULL, seps ); } delete [] header; header = NULL; delete token; token = NULL; return prop; }
VProperty* ToDo::getVPropertyFromiCalProperty(const WCHAR* name, iCalProperty* prop) { if(name && prop) { VProperty *vprop = new VProperty(name, prop->getValue()); if(prop->getAltre()) vprop->addParameter(TEXT("ALTREP"), prop->getAltre()); if(prop->getCn()) vprop->addParameter(TEXT("CN"), prop->getCn()); if(prop->getCutype()) vprop->addParameter(TEXT("CUTYPE"), prop->getCutype()); if(prop->getDelegatedFrom()) vprop->addParameter(TEXT("DELEGATED-FROM"), prop->getDelegatedFrom()); if(prop->getDelegatedTo()) vprop->addParameter(TEXT("DELEGATED-TO"), prop->getDelegatedTo()); if(prop->getDir()) vprop->addParameter(TEXT("DIR"), prop->getDir()); if(prop->getEncoding()) vprop->addParameter(TEXT("ENCODING"), prop->getEncoding()); if(prop->getFormatType()) vprop->addParameter(TEXT("FMTTYPE"), prop->getFormatType()); if(prop->getFbType()) vprop->addParameter(TEXT("FBTYPE"), prop->getFbType()); if(prop->getLanguage()) vprop->addParameter(TEXT("LANGUAGE"), prop->getLanguage()); if(prop->getMember()) vprop->addParameter(TEXT("MEMBER"), prop->getMember()); if(prop->getPartStat()) vprop->addParameter(TEXT("PARTSTAT"), prop->getPartStat()); if(prop->getRange()) vprop->addParameter(TEXT("RANGE"), prop->getRange()); if(prop->getTrigRel()) vprop->addParameter(TEXT("RELATED"), prop->getTrigRel()); if(prop->getRelated()) vprop->addParameter(TEXT("RELTYPE"), prop->getRelated()); if(prop->getRole()) vprop->addParameter(TEXT("ROLE"), prop->getRole()); if(prop->getRsvp()) vprop->addParameter(TEXT("RSVP"), prop->getRsvp()); if(prop->getSentBy()) vprop->addParameter(TEXT("SENT-BY"), prop->getSentBy()); if(prop->getTzID()) vprop->addParameter(TEXT("TZID"), prop->getTzID()); if(prop->getValueType()) vprop->addParameter(TEXT("VALUE"), prop->getValueType()); if(prop->getXParam()) { ArrayList* xParamList = new ArrayList(); xParamList = prop->getXParam(); for(int i = 0; i<xParamList->size(); i++) { WKeyValuePair* xParam = (WKeyValuePair*)xParamList->get(i); if(xParam->getKey()) if(xParam->getValue()) vprop->addParameter(xParam->getKey(), xParam->getValue()); else vprop->addParameter(xParam->getKey(), NULL); } delete xParamList; xParamList = NULL; } return vprop; } else return NULL; }
// // Format and return a vCard string from the propertyMap. // wstring& WinContact::toString() { vCard = L""; // // Conversion: WinContact -> vObject. // ---------------------------------- // VObject* vo = new VObject(); wstring element; VProperty* vp = NULL; bool found = false; vp = new VProperty(L"BEGIN", L"VCARD"); vo->addProperty(vp); delete vp; vp = NULL; vp = new VProperty(L"VERSION", VCARD_VERSION); vo->addProperty(vp); delete vp; vp = NULL; // ------- Name ------- // Add only if at least 1 property is supported, but include // all elements in the right order. found = false; vp = new VProperty(L"N"); if (getProperty(L"LastName", element)) found = true; vp->addValue(element.c_str()); if (getProperty(L"FirstName", element)) found = true; vp->addValue(element.c_str()); if (getProperty(L"MiddleName", element)) found = true; vp->addValue(element.c_str()); if (getProperty(L"Title", element)) found = true; vp->addValue(element.c_str()); if (getProperty(L"Suffix", element)) found = true; vp->addValue(element.c_str()); if (found) { vo->addProperty(vp); } delete vp; vp = NULL; if (getProperty(L"Birthday", element)) { vp = new VProperty(L"BDAY", element.c_str()); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"Body", element)) { vp = new VProperty(L"NOTE", element.c_str()); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"BusinessFaxNumber", element)) { vp = new VProperty(L"TEL", element.c_str()); vp->addParameter(L"WORK", NULL); vp->addParameter(L"FAX", NULL); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"BusinessTelephoneNumber", element)) { vp = new VProperty(L"TEL", element.c_str()); vp->addParameter(L"VOICE", NULL); vp->addParameter(L"WORK", NULL); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"Business2TelephoneNumber", element)) { vp = new VProperty(L"TEL", element.c_str()); vp->addParameter(L"VOICE", NULL); vp->addParameter(L"WORK", NULL); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"BusinessWebPage", element)) { vp = new VProperty(L"URL", element.c_str()); vp->addParameter(L"WORK", NULL); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"CarTelephoneNumber", element)) { vp = new VProperty(L"TEL", element.c_str()); vp->addParameter(L"CAR", NULL); vp->addParameter(L"VOICE", NULL); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"Categories", element)) { vp = new VProperty(L"CATEGORIES", element.c_str()); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"CompanyMainTelephoneNumber", element)) { vp = new VProperty(L"TEL", element.c_str()); vp->addParameter(L"WORK", NULL); vp->addParameter(L"PREF", NULL); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"FileAs", element)) { vp = new VProperty(L"FN", element.c_str()); vo->addProperty(vp); delete vp; vp = NULL; } // Mapping is: // Email1Address <-> EMAIL;INTERNET: // Email2Address <-> EMAIL;INTERNET;HOME: // Email3Address <-> EMAIL;INTERNET;WORK: if (getProperty(L"Email1Address", element)) { vp = new VProperty(L"EMAIL", element.c_str()); vp->addParameter(L"INTERNET", NULL); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"Email2Address", element)) { vp = new VProperty(L"EMAIL", element.c_str()); vp->addParameter(L"INTERNET", NULL); vp->addParameter(L"HOME", NULL); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"Email3Address", element)) { vp = new VProperty(L"EMAIL", element.c_str()); vp->addParameter(L"INTERNET", NULL); vp->addParameter(L"WORK", NULL); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"JobTitle", element)) { vp = new VProperty(L"TITLE", element.c_str()); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"HomeTelephoneNumber", element)) { vp = new VProperty(L"TEL", element.c_str()); vp->addParameter(L"VOICE", NULL); vp->addParameter(L"HOME", NULL); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"Home2TelephoneNumber", element)) { vp = new VProperty(L"TEL", element.c_str()); vp->addParameter(L"VOICE", NULL); vp->addParameter(L"HOME", NULL); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"HomeFaxNumber", element)) { vp = new VProperty(L"TEL", element.c_str()); vp->addParameter(L"HOME", NULL); vp->addParameter(L"FAX", NULL); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"HomeWebPage", element)) { vp = new VProperty(L"URL", element.c_str()); vp->addParameter(L"HOME", NULL); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"Importance", element)) { vp = new VProperty(L"PRIORITY", element.c_str()); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"MobileTelephoneNumber", element)) { vp = new VProperty(L"TEL", element.c_str()); vp->addParameter(L"CELL", NULL); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"NickName", element)) { vp = new VProperty(L"NICKNAME", element.c_str()); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"OtherFaxNumber", element)) { vp = new VProperty(L"TEL", element.c_str()); vp->addParameter(L"FAX", NULL); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"OtherTelephoneNumber", element)) { vp = new VProperty(L"TEL", element.c_str()); vp->addParameter(L"VOICE", NULL); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"PagerNumber", element)) { vp = new VProperty(L"TEL", element.c_str()); vp->addParameter(L"PAGER", NULL); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"PrimaryTelephoneNumber", element)) { vp = new VProperty(L"TEL", element.c_str()); vp->addParameter(L"PREF", NULL); vp->addParameter(L"VOICE", NULL); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"Profession", element)) { vp = new VProperty(L"ROLE", element.c_str()); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"Sensitivity", element)) { long sensitivity = _wtoi(element.c_str()); vp = new VProperty(TEXT("CLASS")); if(sensitivity == winPrivate) { vp->addValue(TEXT("PRIVATE")); } else if (sensitivity == winConfidential) { vp->addValue(TEXT("CONFIDENTIAL")); } else { // default value vp->addValue(TEXT("PUBLIC")); } vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"WebPage", element)) { vp = new VProperty(L"URL", element.c_str()); vo->addProperty(vp); delete vp; vp = NULL; } // ----- ORG ----- // Add only if at least 1 property is supported, but include // all elements in the right order. found = false; vp = new VProperty(L"ORG"); if (getProperty(L"CompanyName", element)) found = true; vp->addValue(element.c_str()); if (getProperty(L"Department", element)) found = true; vp->addValue(element.c_str()); if (getProperty(L"OfficeLocation", element)) found = true; vp->addValue(element.c_str()); if (found) { vo->addProperty(vp); } delete vp; vp = NULL; // ----- Address HOME ----- // Add only if at least 1 property is supported, but include // all elements in the right order. // "AddressPostOfficeBox" is not supported by WM. // "AddressExtended" is not supported by Outlook/WM. found = false; vp = new VProperty(L"ADR"); vp->addParameter(L"HOME", NULL); if (getProperty(L"HomeAddressPostOfficeBox", element)) found = true; vp->addValue(element.c_str()); if (getProperty(L"HomeAddressExtended", element)) found = true; vp->addValue(element.c_str()); if (getProperty(L"HomeAddressStreet", element)) found = true; vp->addValue(element.c_str()); if (getProperty(L"HomeAddressCity", element)) found = true; vp->addValue(element.c_str()); if (getProperty(L"HomeAddressState", element)) found = true; vp->addValue(element.c_str()); if (getProperty(L"HomeAddressPostalCode", element)) found = true; vp->addValue(element.c_str()); if (getProperty(L"HomeAddressCountry", element)) found = true; vp->addValue(element.c_str()); if (found) { vo->addProperty(vp); } delete vp; vp = NULL; // ----- Address ----- // Add only if at least 1 property is supported, but include // all elements in the right order. // "AddressPostOfficeBox" is not supported by WM. // "AddressExtended" is not supported by Outlook/WM. found = false; vp = new VProperty(L"ADR"); if (getProperty(L"OtherAddressPostOfficeBox", element)) found = true; vp->addValue(element.c_str()); if (getProperty(L"OtherAddressExtended", element)) found = true; vp->addValue(element.c_str()); if (getProperty(L"OtherAddressStreet", element)) found = true; vp->addValue(element.c_str()); if (getProperty(L"OtherAddressCity", element)) found = true; vp->addValue(element.c_str()); if (getProperty(L"OtherAddressState", element)) found = true; vp->addValue(element.c_str()); if (getProperty(L"OtherAddressPostalCode", element)) found = true; vp->addValue(element.c_str()); if (getProperty(L"OtherAddressCountry", element)) found = true; vp->addValue(element.c_str()); if (found) { vo->addProperty(vp); } delete vp; vp = NULL; // ----- Address WORK ----- // Add only if at least 1 property is supported, but include // all elements in the right order. // "AddressPostOfficeBox" is not supported by WM. // "AddressExtended" is not supported by Outlook/WM. found = false; vp = new VProperty(L"ADR"); vp->addParameter(L"WORK", NULL); if (getProperty(L"BusinessAddressPostOfficeBox", element)) found = true; vp->addValue(element.c_str()); if (getProperty(L"BusinessAddressExtended", element)) found = true; vp->addValue(element.c_str()); if (getProperty(L"BusinessAddressStreet", element)) found = true; vp->addValue(element.c_str()); if (getProperty(L"BusinessAddressCity", element)) found = true; vp->addValue(element.c_str()); if (getProperty(L"BusinessAddressState", element)) found = true; vp->addValue(element.c_str()); if (getProperty(L"BusinessAddressPostalCode", element)) found = true; vp->addValue(element.c_str()); if (getProperty(L"BusinessAddressCountry", element)) found = true; vp->addValue(element.c_str()); if (found) { vo->addProperty(vp); } delete vp; vp = NULL; //PHOTO if (getProperty(L"Photo", element)) { vp = new VProperty(L"PHOTO", element.c_str()); if (element != L"") { vp->addParameter(L"CONTENT-VALUE", L"UNCHANGED"); vp->addParameter(L"ENCODING", L"b"); if (photoType.length() > 0) { vp->addParameter(L"TYPE", photoType.c_str()); } } vo->addProperty(vp); delete vp; vp = NULL; } // // ---- Funambol defined properties ---- // Support for other fields that don't have a // specific correspondence in vCard. if (getProperty(L"Anniversary", element)) { vp = new VProperty(L"X-ANNIVERSARY"); vp->addValue(element.c_str()); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(TEXT("BillingInformation"), element)) { vp = new VProperty(TEXT("X-FUNAMBOL-BILLINGINFO"), element.c_str()); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"CallbackTelephoneNumber", element)) { vp = new VProperty(L"TEL", element.c_str()); vp->addParameter(L"X-FUNAMBOL-CALLBACK", NULL); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"Children", element)) { vp = new VProperty(L"X-FUNAMBOL-CHILDREN", element.c_str()); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"Companies", element)) { vp = new VProperty(L"X-FUNAMBOL-COMPANIES", element.c_str()); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"CustomerID", element)) { vp = new VProperty(L"X-FUNAMBOL-CUSTOMERID", element.c_str()); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"Folder", element)) { vp = new VProperty(L"X-FUNAMBOL-FOLDER"); vp->addValue(element.c_str()); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"Gender", element)) { vp = new VProperty(L"X-FUNAMBOL-GENDER", element.c_str()); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"GovernmentIDNumber", element)) { vp = new VProperty(L"X-FUNAMBOL-GOVERNMENTID", element.c_str()); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"Hobby", element)) { vp = new VProperty(L"X-FUNAMBOL-HOBBIES", element.c_str()); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"IMAddress", element)) { vp = new VProperty(L"EMAIL", element.c_str()); vp->addParameter(L"INTERNET", NULL); vp->addParameter(L"HOME", NULL); vp->addParameter(L"X-FUNAMBOL-INSTANTMESSENGER", NULL); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"IM2Address", element)) { vp = new VProperty(L"EMAIL", element.c_str()); vp->addParameter(L"INTERNET", NULL); vp->addParameter(L"HOME", NULL); vp->addParameter(L"X-FUNAMBOL-INSTANTMESSENGER", NULL); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"IM3Address", element)) { vp = new VProperty(L"EMAIL", element.c_str()); vp->addParameter(L"INTERNET", NULL); vp->addParameter(L"HOME", NULL); vp->addParameter(L"X-FUNAMBOL-INSTANTMESSENGER", NULL); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"Initials", element)) { vp = new VProperty(L"X-FUNAMBOL-INITIALS", element.c_str()); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"Language", element)) { vp = new VProperty(L"X-FUNAMBOL-LANGUAGES", element.c_str()); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"ManagerName", element)) { vp = new VProperty(L"X-MANAGER", element.c_str()); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"Mileage", element)) { vp = new VProperty(L"X-FUNAMBOL-MILEAGE", element.c_str()); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"OrganizationalIDNumber", element)) { vp = new VProperty(L"X-FUNAMBOL-ORGANIZATIONALID", element.c_str()); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"RadioTelephoneNumber", element)) { vp = new VProperty(L"TEL", element.c_str()); vp->addParameter(L"X-FUNAMBOL-RADIO", NULL); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"Spouse", element)) { vp = new VProperty(L"X-SPOUSE", element.c_str()); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"Subject", element)) { vp = new VProperty(L"X-FUNAMBOL-SUBJECT", element.c_str()); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"TelexNumber", element)) { vp = new VProperty(L"TEL", element.c_str()); vp->addParameter(L"X-FUNAMBOL-TELEX", NULL); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"YomiCompanyName", element)) { vp = new VProperty(L"X-FUNAMBOL-YOMICOMPANYNAME", element.c_str()); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"YomiFirstName", element)) { vp = new VProperty(L"X-FUNAMBOL-YOMIFIRSTNAME", element.c_str()); vo->addProperty(vp); delete vp; vp = NULL; } if (getProperty(L"YomiLastName", element)) { vp = new VProperty(L"X-FUNAMBOL-YOMILASTNAME", element.c_str()); vo->addProperty(vp); delete vp; vp = NULL; } vp = new VProperty(L"END", L"VCARD"); vo->addProperty(vp); delete vp; vp = NULL; // // Format the vCard. // ----------------- // WCHAR* tmp = vo->toString(); if (tmp) { vCard = tmp; delete [] tmp; } if (vo) { delete vo; vo = NULL; } return vCard; }