#include "ldap_plugin.h"
#include <vobject.h>
#include <vcc.h>

#define VCARDATTR 0
#define LDAPATTR 1
#define VCARDPROP 2

char *vcardattrs[][4][3] = {
//Normal Stuff
{{"TEL"}, {"homePhone"}, {"HOME", NULL}, {NULL}},
{{"TEL"}, {"companyPhone"}, {"WORK", NULL}, {"1"}},
{{"TEL"}, {"facsimileTelephoneNumber"}, {"FAX", "WORK", NULL}, {NULL}},
{{"TEL"}, {"mobile"}, {"CELL", NULL}, {NULL}},
{{"TEL"}, {"carPhone"}, {"CAR", NULL}, {"1"}},
{{"TEL"}, {"telephoneNumber"}, {"WORK", "VOICE", NULL}, {NULL}},
{{"TEL"}, {"homeFacsimileTelephoneNumber"}, {"HOME", "FAX", NULL}, {"1"}},
{{"TEL"}, {"otherPhone"}, {"VOICE", NULL}, {"1"}},
{{"TEL"}, {"otherFax"}, {"FAX", NULL}, {"1"}},
{{"TEL"}, {"otherFacsimileTelephoneNumber"}, {"FAX", NULL}, {"1"}},
{{"TEL"}, {"callbackPhone"}, {"X-EVOLUTION-CALLBACK", NULL}, {"1"}},
{{"TEL"}, {"internationaliSDNNumber"}, {"ISDN", NULL}, {NULL}},
{{"TEL"}, {"pager"}, {"PAGER", NULL}, {NULL}},
{{"TEL"}, {"primaryPhone"}, {"PREF", NULL}, {"1"}},
{{"TEL"}, {"radio"}, {"X-EVOLUTION-RADIO", NULL}, {"1"}},
{{"TEL"}, {"telex"}, {"X-EVOLUTION-TELEX", NULL}, {"1"}},
{{"TEL"}, {"tty"}, {"X-EVOLUTION-TTYTDD", NULL}, {"1"}},
{{"TEL"}, {"assistantPhone"}, {"X-EVOLUTION-ASSISTANT", NULL}, {"1"}},
{{"BDAY"}, {"birthDate"}, {NULL}, {"1"}},
{{"X-EVOLUTION-SPOUSE"}, {"spouseName"}, {NULL}, {"1"}},
{{"CATEGORIES"}, {"category"}, {NULL}, {"1"}},
{{"ROLE"}, {"businessRole"}, {NULL}, {"1"}},
{{"X-EVOLUTION-ASSISTANT"}, {"assistantName"}, {NULL}, {"1"}},
{{"X-EVOLUTION-MANAGER"}, {"managerName"}, {NULL}, {"1"}},
{{"X-EVOLUTION-ANNIVERSARY"}, {"anniversary"}, {NULL}, {"1"}},
{{"X-EVOLUTION-OFFICE"}, {"roomNumber"}, {NULL}, {NULL}},
{{"NICKNAME"}, {"displayName"}, {NULL}, {NULL}},
{{"CALURI"}, {"calendarURI"}, {NULL}, {"1"}},
{{"FBURL"}, {"freeBusyURI"}, {NULL}, {"1"}},
{{"X-EVOLUTION-FILE-AS"}, {"fileAs"}, {NULL}, {"1"}},
//{{"ORG"}, {"o"}, {NULL}, {"ORGNAME", NULL}},
{{"URL"}, {"labeledURI"}, {NULL}, {NULL}},
{{"EMAIL"}, {"mail"}, {"INTERNET", NULL}, {NULL}},
{{"EMAIL"}, {"mail"}, {NULL}, {NULL}},
{{"TITLE"}, {"title"}, {NULL}, {NULL}},
// //Should be made by autodetection
{{"NOTE"}, {"note"}, {NULL}, {"1"}},
{{"ADR"}, {NULL}, {NULL}, {NULL}},
//{{"ADR"}, {"postalAddress"}, {"WORK", NULL}, {"BOX", NULL}},
//{{"ADR"}, {"homePostalAddress"}, {"HOME", NULL}, {"BOX", NULL}},
//{{"ADR"}, {"homePostalAddress"}, {"HOME", "PREF", NULL}, {"BOX", NULL}},
{{"LABEL"}, {"otherPostalAddress"}, {"POSTAL", NULL}, {"1"}},
{{"LABEL"}, {"homePostalAddress"}, {"HOME", NULL}, {NULL}},
{{"LABEL"}, {"postalAddress"}, {"WORK", NULL}, {NULL}},
{{"LABEL"}, {"otherPostalAddress"}, {"POSTAL", "PREF", NULL}, {"1"}},
{{"LABEL"}, {"homePostalAddress"}, {"HOME", "PREF", NULL}, {NULL}},
{{"LABEL"}, {"postalAddress"}, {"WORK", "PREF", NULL}, {NULL}},
// //Special Entries or entries being ignored
{{"N"}, {NULL}, {NULL}, {NULL}},
{{"X-MOZILLA-HTML"}, {NULL}, {NULL}, {NULL}},
{{""}, {"objectClass"}, {NULL}, {NULL}},
{{""}, {"uid"}, {NULL}, {NULL}},
{{"FN"}, {"cn"}, {NULL}, {NULL}},
{{"VERSION"}, {NULL}, {NULL}, {NULL}},
{{"UID"}, {NULL}, {NULL}, {NULL}},
NULL};

char *quoted_encode(char *string) {
	char *data;
	char buffer[1024];
	int i = 0;
	int chr = 0;
	data = malloc(1024 * sizeof(char));

	strcpy(data, string);
	for (i = 0; i < strlen(data); i++) {
		if (data[i] == '=') {
			data[i] = 0;
			sprintf(buffer, "%s%s%s", data, "=3D", &data[i + 1]);
			i = i + 2;
			strcpy(data, buffer);
		}
	}

	while(1) {
		//Found new char to encode
		i = strcspn(data, "\n\r ");
		chr = data[i];
		data[i] = 0;
		if (!chr) { break; }
		sprintf(buffer, "%s=%02X%s", data, chr, &data[i + 1]);
		strcpy(data, buffer);
	}
	return data;
}

char *quoted_decode(char *string)
{
	int i = 0;
	char *data;
	char hex[1024];
	char buffer[1024];
	data = malloc(1024 * sizeof(char));
	strcpy(data, string);

	while(1) {
		//Found new char to decode
		i = i + strcspn(&data[i], "=");
		if (!data[i]) { break; }
		data[i] = 0;

		strcpy(hex, "0x");
		strncat(hex, &data[i + 1], 2);

		sprintf(buffer, "%s%c%s", data, ((int)(strtod(hex, NULL))), &data[i + 3]);
		strcpy(data, buffer);
		i++;
	}
	return data;
}

GString *ldap2vcard(ldap_connection *conn, LDAPMod **ldapdata)
{
	VObjectO *prop;
	VObjectO *vcard;
	int i = 0, n = 0, x = 0, k = 0;
	GString *vcardstr;
	char var1[1024], var2[1024], var3[1024], var4[1024], var5[1024];
	char *title = "", *first = "", *middle = "", *last = "", *suffix = "", *orgname = NULL, *orgunit = NULL;

	ldap_debug(conn, 2, "Converting ldap to vcard");

	vcard = newVObjectO(VCCardPropO);
	addPropValueO(vcard, VCVersionPropO, "2.1");

	//Walk through all the ldap attributes
	for (n = 0; ldapdata[n]; n++) {
		for (x = 0; ldapdata[n]->mod_values[x]; x++) {
			i = 0;
			ldap_debug(conn, 2, "Converting: %s=%s", ldapdata[n]->mod_type, ldapdata[n]->mod_values[x]);

			//Handle with names
			//First the common name
			if (!strcmp(ldapdata[n]->mod_type, "cn")) {
				switch (sscanf(ldapdata[n]->mod_values[x], "%s %s %s %s %s", var1, var2, var3, var4, var5)) {
					case 1:
						last = var1;
						break;
					case 2:
						first = var1;
						last = var2;
						break;
					case 3:
						first = var1;
						middle = var2;
						last = var3;
						break;
					case 4:
						title = var1;
						first = var2;
						middle = var3;
						last = var4;
						break;
					case 5:
						title = var1;
						first = var2;
						middle = var3;
						last = var4;
						suffix = var5;
						break;
				}
			}
			//the givenName
			if (!strcmp(ldapdata[n]->mod_type, "givenName")) {
				if (strcmp(ldapdata[n]->mod_values[x], first)) {
					ldap_debug(conn, 1, "First names do not match");
					first = ldapdata[n]->mod_values[x];
				}
				goto next;
			}
			//familyName
			if (!strcmp(ldapdata[n]->mod_type, "sn")) {
				if (strcmp(ldapdata[n]->mod_values[x], last)) {
					ldap_debug(conn, 1, "Last names do not match");
					last = ldapdata[n]->mod_values[x];
				}
				goto next;
			}

			//department handling
			if (!strcmp(ldapdata[n]->mod_type, "o")) {
				orgname = strdup(ldapdata[n]->mod_values[x]);
				goto next;
			}

			if (!strcmp(ldapdata[n]->mod_type, "ou")) {
				orgunit = strdup(ldapdata[n]->mod_values[x]);
				goto next;
			}

			//convert entries
			while (vcardattrs[i][VCARDATTR][0]) {
				if (vcardattrs[i][LDAPATTR][0]) {
					if (strcmp(ldapdata[n]->mod_type, vcardattrs[i][LDAPATTR][0]) == 0) {
						if (vcardattrs[i][VCARDATTR][0][0]) {
							//Found the entry in our array. Now convert it
							prop = addPropValueO(vcard, vcardattrs[i][VCARDATTR][0], ldapdata[n]->mod_values[x]);
							k = 0;
							while (vcardattrs[i][VCARDPROP][k]) {
								addPropO(prop, vcardattrs[i][VCARDPROP][k]);
								k++;
							}
							//Handle for quoted-printable
							if (!strcmp(vcardattrs[i][VCARDATTR][0], "ADR") || !strcmp(vcardattrs[i][VCARDATTR][0], "NOTE") || !strcmp(vcardattrs[i][VCARDATTR][0], "LABEL")) {
								addPropO(prop, VCQuotedPrintablePropO);
							}
						}
						goto next;
					}
				}
				i++;
			}

			//We could not find the attribute in our database.
			ldap_debug(conn, 1, "Could not match ldapattribute: %s", ldapdata[n]->mod_type);
			next:
			;
		}
	}

	prop = addPropO(vcard,"N");
	addPropValueO(prop, VCGivenNamePropO, first);
	addPropValueO(prop, VCAdditionalNamesPropO, middle);
	addPropValueO(prop, VCFamilyNamePropO, last);
	addPropValueO(prop, VCNameSuffixesPropO, suffix);
	addPropValueO(prop, VCNamePrefixesPropO, title);

	if (orgname || orgunit)
		prop = addPropO(vcard, "ORG");
	if (orgname)
		addPropValueO(prop, "ORGNAME", orgname);
	if (orgunit)
		addPropValueO(prop, "OUN", orgunit);

	  /* convert VObjectO to string */
	vcardstr = g_string_new(writeMemVObjectO(0,0,vcard));
	deleteVObjectO(vcard);

	ldap_debug(conn, 3, "VCARD: %i\n%s\n", &vcardstr, vcardstr->str);
	return vcardstr;
}

const char *propNamesO[][4] = {
    { VC7bitPropO, 0, 0, 0 },
    { VC8bitPropO, 0, 0, 0 },
    { VCAAlarmPropO, 0, 0, 0 },
    { VCAdditionalNamesPropO, 0, 0, 0 },
    { VCAdrPropO, 0, 0, 0 },
    { VCAgentPropO, 0, 0, 0 },
    { VCAIFFPropO, 0, 0, 0 },
    { VCAOLPropO, 0, 0, 0 },
    { VCAppleLinkPropO, 0, 0, 0 },
    { VCAttachPropO, 0, 0, 0 },
    { VCAttendeePropO, 0, 0, 0 },
    { VCATTMailPropO, 0, 0, 0 },
    { VCAudioContentPropO, 0, 0, 0 },
    { VCAVIPropO, 0, 0, 0 },
    { VCBase64PropO, 0, 0, 0 },
    { VCBBSPropO, 0, 0, 0 },
    { VCBirthDatePropO, 0, 0, 0 },
    { VCBMPPropO, 0, 0, 0 },
    { VCBodyPropO, 0, 0, 0 },
    { VCBusinessRolePropO, 0, 0, 0 },
    { VCCalPropO, 0, 0, 0 },
    { VCCaptionPropO, 0, 0, 0 },
    { VCCardPropO, 0, 0, 0 },
    { VCCarPropO, 0, 0, 0 },
    { VCCategoriesPropO, 0, 0, 0 },
    { VCCellularPropO, 0, 0, 0 },
    { VCCGMPropO, 0, 0, 0 },
    { VCCharSetPropO, 0, 0, 0 },
    { VCCIDPropO, 0, 0, 0 },
    { VCCISPropO, 0, 0, 0 },
    { VCCityPropO, 0, 0, 0 },
    { VCClassPropO, 0, 0, 0 },
    { VCCommentPropO, 0, 0, 0 },
    { VCCompletedPropO, 0, 0, 0 },
    { VCContentIDPropO, 0, 0, 0 },
    { VCCountryNamePropO, 0, 0, 0 },
    { VCDAlarmPropO, 0, 0, 0 },
    { VCDataSizePropO, 0, 0, 0 },
    { VCDayLightPropO, 0, 0, 0 },
    { VCDCreatedPropO, 0, 0, 0 },
    { VCDeliveryLabelPropO, 0, 0, 0 },
    { VCDescriptionPropO, 0, 0, 0 },
    { VCDIBPropO, 0, 0, 0 },
    { VCDisplayStringPropO, 0, 0, 0 },
    { VCDomesticPropO, 0, 0, 0 },
    { VCDTendPropO, 0, 0, 0 },
    { VCDTstartPropO, 0, 0, 0 },
    { VCDuePropO, 0, 0, 0 },
    { VCEmailAddressPropO, 0, 0, 0 },
    { VCEncodingPropO, 0, 0, 0 },
    { VCEndPropO, 0, 0, 0 },
    { VCEventPropO, 0, 0, 0 },
    { VCEWorldPropO, 0, 0, 0 },
    { VCExNumPropO, 0, 0, 0 },
    { VCExpDatePropO, 0, 0, 0 },
    { VCExpectPropO, 0, 0, 0 },
    { VCExtAddressPropO, 0, 0, 0 },
    { VCFamilyNamePropO, 0, 0, 0 },
    { VCFaxPropO, 0, 0, 0 },
    { VCFullNamePropO, 0, 0, 0 },
    { VCGeoLocationPropO, 0, 0, 0 },
    { VCGeoPropO, 0, 0, 0 },
    { VCGIFPropO, 0, 0, 0 },
    { VCGivenNamePropO, 0, 0, 0 },
    { VCGroupingPropO, 0, 0, 0 },
    { VCHomePropO, 0, 0, 0 },
    { VCIBMMailPropO, 0, 0, 0 },
    { VCInlinePropO, 0, 0, 0 },
    { VCInternationalPropO, 0, 0, 0 },
    { VCInternetPropO, 0, 0, 0 },
    { VCISDNPropO, 0, 0, 0 },
    { VCJPEGPropO, 0, 0, 0 },
    { VCLanguagePropO, 0, 0, 0 },
    { VCLastModifiedPropO, 0, 0, 0 },
    { VCLastRevisedPropO, 0, 0, 0 },
    { VCLocationPropO, 0, 0, 0 },
    { VCLogoPropO, 0, 0, 0 },
    { VCMailerPropO, 0, 0, 0 },
    { VCMAlarmPropO, 0, 0, 0 },
    { VCMCIMailPropO, 0, 0, 0 },
    { VCMessagePropO, 0, 0, 0 },
    { VCMETPropO, 0, 0, 0 },
    { VCModemPropO, 0, 0, 0 },
    { VCMPEG2PropO, 0, 0, 0 },
    { VCMPEGPropO, 0, 0, 0 },
    { VCMSNPropO, 0, 0, 0 },
    { VCNamePrefixesPropO, 0, 0, 0 },
    { VCNamePropO, 0, 0, 0 },
    { VCNameSuffixesPropO, 0, 0, 0 },
    { VCNotePropO, 0, 0, 0 },
    { VCOrgNamePropO, 0, 0, 0 },
    { VCOrgPropO, 0, 0, 0 },
    { VCOrgUnit2PropO, 0, 0, 0 },
    { VCOrgUnit3PropO, 0, 0, 0 },
    { VCOrgUnit4PropO, 0, 0, 0 },
    { VCOrgUnitPropO, 0, 0, 0 },
    { VCPagerPropO, 0, 0, 0 },
    { VCPAlarmPropO, 0, 0, 0 },
    { VCParcelPropO, 0, 0, 0 },
    { VCPartPropO, 0, 0, 0 },
    { VCPCMPropO, 0, 0, 0 },
    { VCPDFPropO, 0, 0, 0 },
    { VCPGPPropO, 0, 0, 0 },
    { VCPhotoPropO, 0, 0, 0 },
    { VCPICTPropO, 0, 0, 0 },
    { VCPMBPropO, 0, 0, 0 },
    { VCPostalBoxPropO, 0, 0, 0 },
    { VCPostalCodePropO, 0, 0, 0 },
    { VCPostalPropO, 0, 0, 0 },
    { VCPowerSharePropO, 0, 0, 0 },
    { VCPreferredPropO, 0, 0, 0 },
    { VCPriorityPropO, 0, 0, 0 },
    { VCProcedureNamePropO, 0, 0, 0 },
    { VCProdIdPropO, 0, 0, 0 },
    { VCProdigyPropO, 0, 0, 0 },
    { VCPronunciationPropO, 0, 0, 0 },
    { VCPSPropO, 0, 0, 0 },
    { VCPublicKeyPropO, 0, 0, 0 },
    { VCQPPropO, 0, 0, 0 },
    { VCQuickTimePropO, 0, 0, 0 },
    { VCQuotedPrintablePropO, 0, 0, 0 },
    { VCRDatePropO, 0, 0, 0 },
    { VCRegionPropO, 0, 0, 0 },
    { VCRelatedToPropO, 0, 0, 0 },
    { VCRepeatCountPropO, 0, 0, 0 },
    { VCResourcesPropO, 0, 0, 0 },
    { VCRNumPropO, 0, 0, 0 },
    { VCRolePropO, 0, 0, 0 },
    { VCRRulePropO, 0, 0, 0 },
    { VCRSVPPropO, 0, 0, 0 },
    { VCRunTimePropO, 0, 0, 0 },
    { VCSequencePropO, 0, 0, 0 },
    { VCSnoozeTimePropO, 0, 0, 0 },
    { VCStartPropO, 0, 0, 0 },
    { VCStatusPropO, 0, 0, 0 },
    { VCStreetAddressPropO, 0, 0, 0 },
    { VCSubTypePropO, 0, 0, 0 },
    { VCSummaryPropO, 0, 0, 0 },
    { VCTelephonePropO, 0, 0, 0 },
    { VCTIFFPropO, 0, 0, 0 },
    { VCTimeZonePropO, 0, 0, 0 },
    { VCTitlePropO, 0, 0, 0 },
    { VCTLXPropO, 0, 0, 0 },
    { VCTodoPropO, 0, 0, 0 },
    { VCTranspPropO, 0, 0, 0 },
    { VCUniqueStringPropO, 0, 0, 0 },
    { VCURLPropO, 0, 0, 0 },
    { VCURLValuePropO, 0, 0, 0 },
    { VCValuePropO, 0, 0, 0 },
    { VCVersionPropO, 0, 0, 0 },
    { VCVideoPropO, 0, 0, 0 },
    { VCVoicePropO, 0, 0, 0 },
    { VCWAVEPropO, 0, 0, 0 },
    { VCWMFPropO, 0, 0, 0 },
    { VCWorkPropO, 0, 0, 0 },
    { VCX400PropO, 0, 0, 0 },
    { VCX509PropO, 0, 0, 0 },
    { VCXRulePropO, 0, 0, 0 },
    { VCDTStampPropO, 0, 0, 0 },
    { VCPctCompletePropO, 0, 0, 0 },
    { VCTzidPropO, 0, 0, 0 },
    { VCAlarmPropO, 0, 0, 0 },
    { VCTriggerPropO, 0, 0, 0 },
    { VCRelatedPropO, 0, 0, 0 },
    { VCActionPropO, 0, 0, 0 },
    { XEvoAlarmUidO, 0, 0, 0 },
    { VCFreqPropO, 0, 0, 0 },
    { VCUntilPropO, 0, 0, 0 },
    { VCIntervalPropO, 0, 0, 0 },
    { VCByDayPropO, 0, 0, 0 },
    { VCBySetPosPropO, 0, 0, 0 },
    { XEvolutionSpouseO, 0, 0, 0 },
    { XEvolutionAssistantO, 0, 0, 0 },
    { XEvolutionManagerO, 0, 0, 0 },
    { XEvolutionOfficeO, 0, 0, 0 },
    { XEvolutionAnniversaryO, 0, 0, 0 },
    { VCNicknameO, 0, 0, 0 },
    { VCCalendarURIO, 0, 0, 0 },
    { VCFBURLO, 0, 0, 0 },
    { NULL,0,0,0 }
    };

int checkprops(VObjectO *v, int i)
{
	VObjectO *prop;
	int n = 0, k = 0;

	while (vcardattrs[i][VCARDPROP][k]) {
		if (!isAPropertyOfO(v, vcardattrs[i][VCARDPROP][k])) {
			//Property did not match
			return 1;
		}
		k++;
	}

	k = 0;
	while (propNamesO[k][0]) {
		prop = isAPropertyOfO(v, propNamesO[k][0]);
		if(prop)
		{
			n = 0;
			if (strcmp(fakeCStringO(vObjectUStringZValueO(prop)), "")) {
				goto next;
			}
			while (vcardattrs[i][VCARDPROP][n]) {
				if (!strcmp(vcardattrs[i][VCARDPROP][n], propNamesO[k][0])) {
					goto next;
				}
				if (!strcmp(propNamesO[k][0], "QUOTED-PRINTABLE")) {
					goto next;
				}
				if (!strcmp(propNamesO[k][0], "ENCODING:QERA")) {
					goto next;
				}
				n++;
			}
			return 1;
			next:
			;
		}
		k++;
	}
	return 0;
}

void printprops(ldap_connection *conn, VObjectO *v)
{
	VObjectO *prop;
	char buffer[2048];
	int n = 0, k = 0;

	strcpy(buffer, "Properties: ");

	k = 0;
	while (propNamesO[k][0]) {
		prop = isAPropertyOfO(v, propNamesO[k][0]);
		if(prop)
		{
			strcat(buffer, propNamesO[k][0]);
			if (strcmp(fakeCStringO(vObjectUStringZValueO(prop)), "")) {
				strcat(buffer, ":");
				strcat(buffer, fakeCStringO(vObjectUStringZValueO(prop)));
			}
			strcat(buffer, ";");
		}
		k++;
	}
	ldap_debug(conn, 1, "%s", buffer);
}

void VObjectOErrorHander(char *errstr)
{
  printf("VObjectO parse failed: %s\n", errstr);
}

LDAPMod **vcard2ldap(ldap_connection *conn, char *origvcard)
{
	int i = 0, n = 0, x = 0, k = 0, m = 0, count = 0;
	const char *attributes;
	GString *name = g_string_new("");
	LDAPMod **ldapentries = NULL;
	char *vcardline, *valueline, value[1024], *vcardname;
	char *vcard;
	char *first = NULL, *last = NULL, *middle = NULL, *prefix = NULL, *suffix = NULL;
	VObjectO *v, *prop, *vcontact;
	VObjectIteratorO iter;
	char buffer[2048];

	ldap_debug(conn, 3, "converting vcard to ldap");
	ldap_debug(conn, 3, "VCARD: %s", origvcard);
	ldapentries = g_malloc0(1024 * sizeof(LDAPMod *));

	registerMimeErrorHandlerO(VObjectOErrorHander);
	vcontact = Parse_MIMEO(origvcard, strlen(origvcard));

	initPropIteratorO(&iter,vcontact);

	while(moreIterationO(&iter))
	{
		v = nextVObjectO(&iter);
		attributes = vObjectNameO(v);

		//Name handling
		if (!strcmp(attributes,VCNamePropO)) {
			/* last name */
			prop = isAPropertyOfO(vcontact, "FN");
			if (!prop) {
				ldap_debug(conn, 1, "VCARD is missing FN attribute");
				//Adding FN
				ldapentries[count] = malloc(sizeof(LDAPMod));
				ldapentries[count]->mod_type = "cn";
				ldapentries[count]->mod_values = malloc(2 * sizeof(char *));
				ldapentries[count]->mod_values[0] = "test"; //TODO
				ldapentries[count]->mod_values[1] = NULL;
				count++;
			}

			prop = isAPropertyOfO(v, VCFamilyNamePropO);
			if (prop) {
				ldapentries[count] = malloc(sizeof(LDAPMod));
				ldapentries[count]->mod_type = "sn";
				ldapentries[count]->mod_values = malloc(2 * sizeof(char *));
				ldapentries[count]->mod_values[0] = strdup(fakeCStringO(vObjectUStringZValueO(prop)));
				ldapentries[count]->mod_values[1] = NULL;
				count++;
			}

			/* first name */
			prop = isAPropertyOfO(v, VCGivenNamePropO);
			if (prop) {
				ldapentries[count] = malloc(sizeof(LDAPMod));
				ldapentries[count]->mod_type = "givenName";
				ldapentries[count]->mod_values = malloc(2 * sizeof(char *));
				ldapentries[count]->mod_values[0] = strdup(fakeCStringO(vObjectUStringZValueO(prop)));
				ldapentries[count]->mod_values[1] = NULL;
				count++;
			}
			goto next;
		}

		//Categories handling
		if(!strcmp(attributes,VCCategoriesPropO)) {
			if (!conn->evolution_support) {
				//No evolution support and evo property
				ldap_debug(conn, 1, "Detected evolution property CATEGORIES but ldap server lacks evolution support");
				goto next;
			}
			x = 0;
			ldapentries[count] = malloc(sizeof(LDAPMod));
			ldapentries[count]->mod_type = "category";
			ldapentries[count]->mod_values = malloc(1024 * sizeof(char *));

			strcpy(value, fakeCStringO(vObjectUStringZValueO(v)));
			vcardname = value;
			for (i = 0; value[i]; i++) {
				if (value[i] == ',') {
					value[i] = 0;
					ldapentries[count]->mod_values[x] = strdup(vcardname);
					ldapentries[count]->mod_values[x + 1] = NULL;
					vcardname = &value[i + 1];
					x++;
				}
			}
			ldapentries[count]->mod_values[x] = strdup(vcardname);
			ldapentries[count]->mod_values[x + 1] = NULL;
			count++;
			goto next;
		}

		//department handling
		if (!strcmp(attributes,"ORG")) {
			prop = isAPropertyOfO(v, "ORGNAME");
			if (prop) {
				ldapentries[count] = malloc(sizeof(LDAPMod));
				ldapentries[count]->mod_type = "o";
				ldapentries[count]->mod_values = malloc(2 * sizeof(char *));
				ldapentries[count]->mod_values[0] = strdup(fakeCStringO(vObjectUStringZValueO(prop)));
				ldapentries[count]->mod_values[1] = NULL;
				count++;
			}

			prop = isAPropertyOfO(v, "OUN");
			if (prop) {
				ldapentries[count] = malloc(sizeof(LDAPMod));
				ldapentries[count]->mod_type = "ou";
				ldapentries[count]->mod_values = malloc(2 * sizeof(char *));
				ldapentries[count]->mod_values[0] = strdup(fakeCStringO(vObjectUStringZValueO(prop)));
				ldapentries[count]->mod_values[1] = NULL;
				count++;
			}
			goto next;
		}

		i = 0;
		while (vcardattrs[i][0][0]) {
			ldap_debug(conn, 4, "Comparing %s to %s\n", vcardattrs[i][VCARDATTR][0], attributes);
			if (!strcmp(attributes, vcardattrs[i][VCARDATTR][0])) {
				//Found the entry in our array.
				if (vcardattrs[i][LDAPATTR][0]) {
					// It needs to be converted
					//Now check if the properties match
					if (checkprops(v, i)) {
						//did not match
						goto nextattr;
					}
					//Search for the attribute in the existing LDAPMod array
					n = 0;
					while (ldapentries[n]) {
						if (!strcmp(ldapentries[n]->mod_type, vcardattrs[i][LDAPATTR][0])) {
							//Found existing LDAPMod entry
							x = 0;
							while (ldapentries[n]->mod_values[x]) {
								x++;
							}
							ldapentries[n]->mod_values[x] = strdup(fakeCStringO(vObjectUStringZValueO(v)));
							ldapentries[n]->mod_values[x + 1] = NULL;
							//next vcard part
							goto next;
						}
						n++;
					}

					if (!conn->evolution_support && vcardattrs[i][3][0]) {
						//No evolution support and evo property
						ldap_debug(conn, 1, "Detected evolution property %s but ldap server lacks evolution support", vcardattrs[i][0][0]);
						goto next;
					}

					//Now convert it to a new LDAPMod entry
					ldapentries[count] = malloc(sizeof(LDAPMod));
					ldapentries[count]->mod_type = strdup(vcardattrs[i][LDAPATTR][0]);
					ldapentries[count]->mod_values = malloc(1024 * sizeof(char *));
					ldapentries[count]->mod_values[0] = strdup(fakeCStringO(vObjectUStringZValueO(v)));
					ldapentries[count]->mod_values[1] = NULL;
					ldap_debug(conn, 2, "Converted %s to %s=%s\n", attributes, ldapentries[n]->mod_type, ldapentries[n]->mod_values[0]);
					count++;
				}
				goto next;
			}
			nextattr:
			i++;
		}
		//We could not find the attribute in our database.
		ldap_debug(conn, 1, "Could not match vcard attribute: %s Possible dataloss!", attributes);
		printprops(conn, v);

		next:
		;
	}

	ldapentries[count] = malloc(sizeof(LDAPMod));
	ldapentries[count]->mod_op = 0;
	ldapentries[count]->mod_type = "objectClass";
	ldapentries[count]->mod_values = malloc(6 * sizeof(char *));
	ldapentries[count]->mod_values[0] = "top";
	ldapentries[count]->mod_values[1] = "person";
	ldapentries[count]->mod_values[2] = "organizationalPerson";
	ldapentries[count]->mod_values[3] = "inetOrgPerson";
	if (conn->evolution_support) {
		ldapentries[count]->mod_values[4] = "evolutionPerson";
	}
	ldapentries[count]->mod_values[5] = NULL;

	count++;
	ldapentries[count] = NULL;

	ldap_modify_entry(conn, ldapentries);

	ldap_debug(conn, 2, "end: vcard2ldap");
	return ldapentries;
}
