void VObject::insertProperty(VProperty* property) { if (propertiesCount() == 0 || wcscmp(getProperty(propertiesCount()-1)->getName(),TEXT("END"))) addProperty(property); else { VProperty* lastProperty = getProperty(TEXT("END")); removeProperty(TEXT("END")); addProperty(property); addProperty(lastProperty); } }
WCHAR* ToDo::toString() { if(propertiesCount()<1 || wcscmp(getProperty(0)->getName(),TEXT("BEGIN")) || wcscmp(getProperty(0)->getValue(),TEXT("VTODO")) || wcscmp(getProperty(propertiesCount()-1)->getName(),TEXT("END")) || wcscmp(getProperty(propertiesCount()-1)->getValue(),TEXT("VTODO"))) { addFirstProperty(new VProperty(TEXT("BEGIN"), TEXT("VTODO"))); addProperty(new VProperty(TEXT("END"), TEXT("VTODO"))); } return ((VObject*)this)->toString(); }
void VObject::removeAllProperies(WCHAR* propName) { for(int i = 0, m = propertiesCount(); i < m ; i++) if(!wcscmp(getProperty(i)->getName(), propName)) { removeProperty(i); --i; --m; } }
ArrayList* ToDo::getRRule() { if(!rRule) for(int i = 0; i < propertiesCount(); i++) if(!wcscmp(getProperty(i)->getName(),TEXT("RRULE")) && getProperty(i)->getValue()) { if(!rRule) rRule = new ArrayList(); rRule->add((ArrayElement&) *getiCalPropertyFromVProperty(getProperty(i))); } return rRule; }
ArrayList* ToDo::getRelated() { if(!related) for(int i = 0; i < propertiesCount(); i++) if(!wcscmp(getProperty(i)->getName(),TEXT("RELATED")) && getProperty(i)->getValue()) { if(!related) related = new ArrayList(); related->add((ArrayElement&) *getiCalPropertyFromVProperty(getProperty(i))); } return related; }
ArrayList* ToDo::getResources() { if(!resources) for(int i = 0; i < propertiesCount(); i++) if(!wcscmp(getProperty(i)->getName(),TEXT("RESOURCES")) && getProperty(i)->getValue()) { if(!resources) resources = new ArrayList(); resources->add((ArrayElement&) *getiCalPropertyFromVProperty(getProperty(i))); } return resources; }
ArrayList*ToDo::getRStatus() { if(!rStatus) for(int i = 0; i < propertiesCount(); i++) if(!wcscmp(getProperty(i)->getName(),TEXT("REQUEST-STATUS")) && getProperty(i)->getValue()) { if(!rStatus) rStatus = new ArrayList(); rStatus->add((ArrayElement&) *getiCalPropertyFromVProperty(getProperty(i))); } return rStatus; }
ArrayList* ToDo::getExDate() { if(!exDate) for(int i = 0; i < propertiesCount(); i++) if(!wcscmp(getProperty(i)->getName(),TEXT("EXDATE")) && getProperty(i)->getValue()) { if(!exDate) exDate = new ArrayList(); exDate->add((ArrayElement&) *getiCalPropertyFromVProperty(getProperty(i))); } return exDate; }
ArrayList* ToDo::getContact() { if(!contact) for(int i = 0; i < propertiesCount(); i++) if(!wcscmp(getProperty(i)->getName(),TEXT("CONTACT")) && getProperty(i)->getValue()) { if(!contact) contact = new ArrayList(); contact->add((ArrayElement&) *getiCalPropertyFromVProperty(getProperty(i))); } return contact; }
ArrayList* ToDo::getCategories() { if(!categories) for(int i = 0; i < propertiesCount(); i++) if(!wcscmp(getProperty(i)->getName(),TEXT("CATEGORIES")) && getProperty(i)->getValue()) { if(!categories) categories = new ArrayList(); categories->add((ArrayElement&) *getiCalPropertyFromVProperty(getProperty(i))); } return categories; }
ArrayList* ToDo::getAttendee() { if(!attendee) for(int i = 0; i < propertiesCount(); i++) if(!wcscmp(getProperty(i)->getName(),TEXT("ATTENDEE")) && getProperty(i)->getValue()) { if(!attendee) attendee = new ArrayList(); attendee->add((ArrayElement&) *getiCalPropertyFromVProperty(getProperty(i))); } return attendee; }
ArrayList* ToDo::getXProp() { if(!xProp) for(int i = 0; i < propertiesCount(); i++) if((wcsstr(getProperty(i)->getName(),TEXT("X-")) == getProperty(i)->getName()) && getProperty(i)->getValue()) { if(!xProp) xProp = new ArrayList(); WKeyValuePair *kvp = new WKeyValuePair(getProperty(i)->getName(), getProperty(i)->getValue()); xProp->add((ArrayElement&) *kvp); delete kvp; kvp = NULL; } return xProp; }
void ToDo::setXProp(ArrayList& list) { if (xProp) { xProp->clear(); } else { xProp = new ArrayList(); } for(int i = 0, m = propertiesCount(); i < m ; i++) if(wcsstr(getProperty(i)->getName(),TEXT("X-")) == getProperty(i)->getName()) { removeProperty(i); --i; --m; } int s = list.size(); for (int j=0; j<s; ++j) { xProp->add(*list[j]); insertProperty(new VProperty( ((WKeyValuePair*)list[j])->getKey(), ((WKeyValuePair*)list[j])->getValue())); } }
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")); } } }
void VObject::toNativeEncoding() { bool is_30 = !wcscmp(getVersion(), TEXT("3.0")); // line break is encoded with either one or two // characters on different platforms const int linebreaklen = wcslen(SYNC4J_LINEBREAK); for (int index = propertiesCount() - 1; index >= 0; index--) { VProperty *vprop = getProperty(index); WCHAR *foreign = vprop->getValue(); // the native encoding is always shorter than the foreign one WCHAR *native = new WCHAR[wcslen(foreign) + 1]; if (vprop->equalsEncoding(TEXT("QUOTED-PRINTABLE"))) { int in = 0, out = 0; WCHAR curr; // this is a very crude quoted-printable decoder, // based on Wikipedia's explanation of quoted-printable while ((curr = foreign[in]) != 0) { in++; if (curr == '=') { WCHAR values[2]; values[0] = foreign[in]; in++; if (!values[0]) { // incomplete?! break; } values[1] = foreign[in]; in++; if (values[0] == '\r' && values[1] == '\n') { // soft line break, ignore it } else { native[out] = (hex2int(values[0]) << 4) | hex2int(values[1]); out++; // replace \r\n with \n? if ( linebreaklen == 1 && out >= 2 && native[out - 2] == '\r' && native[out - 1] == '\n' ) { native[out - 2] = SYNC4J_LINEBREAK[0]; out--; } // the conversion to wchar on Windows is // probably missing here } } else { native[out] = curr; out++; } } native[out] = 0; out++; } else { wcscpy(native, foreign); } // decode escaped characters after backslash: // \n is line break only in 3.0 WCHAR curr; int in = 0, out = 0; while ((curr = native[in]) != 0) { in++; switch (curr) { case '\\': curr = native[in]; in++; switch (curr) { case 'n': if (is_30) { // replace with line break wcsncpy(native + out, SYNC4J_LINEBREAK, linebreaklen); out += linebreaklen; } else { // normal escaped character native[out] = curr; out++; } break; case 0: // unexpected end of string break; default: // just copy next character native[out] = curr; out++; break; } break; case ';': // field separator - must replace with something special // so that we can encode it again in fromNativeEncoding() native[out] = SEMICOLON_REPLACEMENT; out++; break; default: native[out] = curr; out++; } } native[out] = 0; out++; // charset handling: // - doesn't exist at the moment, vCards have to be in ASCII or UTF-8 // - an explicit CHARSET parameter is removed because its parameter // value might differ between 2.1 and 3.0 (quotation marks allowed in // 3.0 but not 2.1) and thus would require extra code to convert it; // when charsets really get supported this needs to be addressed WCHAR *charset = vprop->getParameterValue(TEXT("CHARSET")); if (charset) { // proper decoding of the value and the property value text // would go here, for the time being we just remove the // value if (_wcsicmp(charset, TEXT("UTF-8")) && _wcsicmp(charset, TEXT("\"UTF-8\""))) { LOG.error("ignoring unsupported charset"); } vprop->removeParameter(TEXT("CHARSET")); } vprop->setValue(native); delete [] native; } }
bool VObject::removeProperty(int index) { if(index < 0 || index >= propertiesCount()) return false; properties->removeElementAt(index); return true; }