Ejemplo n.º 1
0
INT_PTR __cdecl CJabberProto::JabberGetAvatarInfo(WPARAM wParam, LPARAM lParam)
{
	if (!m_options.EnableAvatars)
		return GAIR_NOAVATAR;

	PROTO_AVATAR_INFORMATIONT* AI = (PROTO_AVATAR_INFORMATIONT*)lParam;

	ptrA szHashValue( getStringA(AI->hContact, "AvatarHash"));
	if (szHashValue == NULL) {
		debugLogA("No avatar");
		return GAIR_NOAVATAR;
	}

	TCHAR tszFileName[MAX_PATH];
	GetAvatarFileName(AI->hContact, tszFileName, SIZEOF(tszFileName));
	_tcsncpy(AI->filename, tszFileName, SIZEOF(AI->filename));

	AI->format = (AI->hContact == NULL) ? PA_FORMAT_PNG : getByte(AI->hContact, "AvatarType", 0);

	if (::_taccess(AI->filename, 0) == 0) {
		ptrA szSavedHash( getStringA(AI->hContact, "AvatarSaved"));
		if (szSavedHash != NULL && !strcmp(szSavedHash, szHashValue)) {
			debugLogA("Avatar is Ok: %s == %s", szSavedHash, szHashValue);
			return GAIR_SUCCESS;
		}
	}

	if ((wParam & GAIF_FORCE) != 0 && AI->hContact != NULL && m_bJabberOnline) {
		ptrT tszJid( getTStringA(AI->hContact, "jid"));
		if (tszJid != NULL) {
			JABBER_LIST_ITEM *item = ListGetItemPtr(LIST_ROSTER, tszJid);
			if (item != NULL) {
				BOOL isXVcard = getByte(AI->hContact, "AvatarXVcard", 0);

				TCHAR szJid[JABBER_MAX_JID_LEN]; szJid[0] = 0;
				if (item->arResources.getCount() != NULL && !isXVcard)
					if (TCHAR *bestResName = ListGetBestClientResourceNamePtr(tszJid))
						mir_sntprintf(szJid, SIZEOF(szJid), _T("%s/%s"), tszJid, bestResName);

				if (szJid[0] == 0)
					_tcsncpy_s(szJid, SIZEOF(szJid), tszJid, _TRUNCATE);

				debugLogA("Rereading %s for %S", isXVcard ? JABBER_FEAT_VCARD_TEMP : JABBER_FEAT_AVATAR, szJid);

				m_ThreadInfo->send((isXVcard) ?
					XmlNodeIq( AddIQ(&CJabberProto::OnIqResultGetVCardAvatar, JABBER_IQ_TYPE_GET, szJid)) << XCHILDNS(_T("vCard"), JABBER_FEAT_VCARD_TEMP) :
					XmlNodeIq( AddIQ(&CJabberProto::OnIqResultGetClientAvatar, JABBER_IQ_TYPE_GET, szJid)) << XQUERY(JABBER_FEAT_AVATAR));
				return GAIR_WAITFOR;
			}
		}
	}

	debugLogA("No avatar");
	return GAIR_NOAVATAR;
}
Ejemplo n.º 2
0
void CJabberProto::IbbSendThread(JABBER_IBB_TRANSFER *jibb)
{
    debugLogA("Thread started: type=ibb_send");

    jibb->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    jibb->bStreamInitialized = FALSE;
    jibb->bStreamClosed = FALSE;
    jibb->state = JIBB_SENDING;

    m_ThreadInfo->send(
        XmlNodeIq( AddIQ(&CJabberProto::OnIbbInitiateResult, JABBER_IQ_TYPE_SET, jibb->dstJID, 0, -1, jibb))
        << XCHILDNS(_T("open"), JABBER_FEAT_IBB) << XATTR(_T("sid"), jibb->sid) << XATTRI(_T("block-size"), JABBER_IBB_BLOCK_SIZE)
        << XATTR(_T("stanza"), _T("message")));

    WaitForSingleObject(jibb->hEvent, INFINITE);
    CloseHandle(jibb->hEvent);
    jibb->hEvent = NULL;

    if (jibb->bStreamInitialized) {
        jibb->wPacketId = 0;

        BOOL bSent = (this->*jibb->pfnSend)(JABBER_IBB_BLOCK_SIZE, jibb->ft);

        if (!jibb->bStreamClosed) {
            jibb->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

            m_ThreadInfo->send(
                XmlNodeIq( AddIQ(&CJabberProto::OnIbbCloseResult, JABBER_IQ_TYPE_SET, jibb->dstJID, 0, -1, jibb))
                << XCHILDNS(_T("close"), JABBER_FEAT_IBB) << XATTR(_T("sid"), jibb->sid));

            WaitForSingleObject(jibb->hEvent, INFINITE);
            CloseHandle(jibb->hEvent);
            jibb->hEvent = NULL;

            if (jibb->bStreamClosed && bSent)
                jibb->state = JIBB_DONE;
        }
        else jibb->state = JIBB_ERROR;
    }

    (this->*jibb->pfnFinal)((jibb->state==JIBB_DONE)?TRUE:FALSE, jibb->ft);
    jibb->ft = NULL;
    JabberIbbFreeJibb(jibb);
}
Ejemplo n.º 3
0
HJHANDLER CJabberProto::AddTemporaryIqHandler(JABBER_HANDLER_FUNC Func, int iIqTypes, int iIqId, void *pUserData, DWORD dwTimeout, int iPriority)
{
	sHandlerData *d = (sHandlerData*)malloc(sizeof(sHandlerData));
	d->Func = Func;
	d->pUserData = pUserData;
	CJabberIqInfo *pInfo = AddIQ(&CJabberProto::ExternalTempIqHandler, iIqTypes, NULL, 0, iIqId, d, iPriority);
	if (pInfo && dwTimeout > 0)
		pInfo->SetTimeout(dwTimeout);
	return (HJHANDLER)pInfo;
}
Ejemplo n.º 4
0
int CJabberProto::SendGetVcard(const TCHAR *jid)
{
	if (!m_bJabberOnline) return 0;

	CJabberIqInfo *pInfo = AddIQ(&CJabberProto::OnIqResultGetVcard, JABBER_IQ_TYPE_GET, jid);
	m_ThreadInfo->send(XmlNodeIq(pInfo) << XCHILDNS(_T("vCard"), JABBER_FEAT_VCARD_TEMP)
		<< XATTR(_T("prodid"), _T("-//HandGen//NONSGML vGen v1.0//EN")) << XATTR(_T("version"), _T("2.0")));

	return pInfo->GetIqId();
}
Ejemplo n.º 5
0
HWND __cdecl CJabberProto::SearchAdvanced(HWND hwndDlg)
{
	if (!m_bJabberOnline || !hwndDlg)
		return 0;	//error

	JabberSearchData * dat=(JabberSearchData *)GetWindowLongPtr(hwndDlg,GWLP_USERDATA);
	if (!dat)
		return 0; //error

	// check if server connected (at least one field exists)
	if (dat->nJSInfCount == 0)
		return 0;

	// formating request
	BOOL fRequestNotEmpty=FALSE;

	// get server name
	TCHAR szServerName[100];
	GetDlgItemText(hwndDlg, IDC_SERVER, szServerName, SIZEOF(szServerName));

	// formating query
	CJabberIqInfo *pInfo = AddIQ(&CJabberProto::OnIqResultAdvancedSearch, JABBER_IQ_TYPE_SET, szServerName);
	XmlNodeIq iq(pInfo);
	HXML query = iq << XQUERY(_T("jabber:iq:search"));

	if (m_tszSelectedLang)
		iq << XATTR(_T("xml:lang"), m_tszSelectedLang); // i'm sure :)

	// next can be 2 cases:
	// Forms: XEP-0055 Example 7
	if (dat->fSearchRequestIsXForm) {
		fRequestNotEmpty=TRUE;
		HXML n = JabberFormGetData(GetDlgItem(hwndDlg, IDC_FRAME), dat->xNode);
		xmlAddChild(query, n);
		xi.destroyNode(n);
    }
	else { //and Simple fields: XEP-0055 Example 3
		for (int i=0; i<dat->nJSInfCount; i++) {
			TCHAR szFieldValue[100];
			GetWindowText(dat->pJSInf[i].hwndValueItem, szFieldValue, SIZEOF(szFieldValue));
			if (szFieldValue[0] != 0) {
				xmlAddChild(query, dat->pJSInf[i].szFieldName, szFieldValue);
				fRequestNotEmpty=TRUE;
	}	}	}

	if (fRequestNotEmpty) {
		m_ThreadInfo->send(iq);
		return (HWND)pInfo->GetIqId();
	}
	return 0;
}
Ejemplo n.º 6
0
void CJabberProto::RetrieveMessageArchive(MCONTACT hContact, JABBER_LIST_ITEM *pItem)
{
	if (pItem->bHistoryRead)
		return;

	pItem->bHistoryRead = TRUE;

	XmlNodeIq iq( AddIQ(&CJabberProto::OnIqResultGetCollectionList, JABBER_IQ_TYPE_GET));
	HXML list = iq << XCHILDNS( _T("list"), JABBER_FEAT_ARCHIVE) << XATTR(_T("with"), pItem->jid);

	time_t tmLast = getDword(hContact, "LastCollection", 0);
	if (tmLast) {
		TCHAR buf[40];
		list << XATTR(_T("start"), time2str(tmLast, buf, SIZEOF(buf)));
	}
	m_ThreadInfo->send(iq);
}
Ejemplo n.º 7
0
void CJabberProto::OnIqResultGetCollectionList(HXML iqNode, CJabberIqInfo*)
{
	const TCHAR *to = xmlGetAttrValue(iqNode, _T("to"));
	if (to == NULL || mir_tstrcmp( xmlGetAttrValue(iqNode, _T("type")), _T("result")))
		return;

	HXML list = xmlGetChild(iqNode, "list");
	if (!list || mir_tstrcmp( xmlGetAttrValue(list, _T("xmlns")), JABBER_FEAT_ARCHIVE))
		return;

	MCONTACT hContact = NULL;
	time_t tmLast = 0;

	for (int nodeIdx = 1; ; nodeIdx++) {
		HXML itemNode = xmlGetNthChild(list, _T("chat"), nodeIdx);
		if (!itemNode)
			break;

		const TCHAR* start = xmlGetAttrValue(itemNode, _T("start"));
		const TCHAR* with  = xmlGetAttrValue(itemNode, _T("with"));
		if (!start || !with)
			continue;

		if (hContact == NULL) {
			if ((hContact = HContactFromJID(with)) == NULL)
				continue;

			tmLast = getDword(hContact, "LastCollection", 0);
		}

		m_ThreadInfo->send(
			XmlNodeIq( AddIQ(&CJabberProto::OnIqResultGetCollection, JABBER_IQ_TYPE_GET))
				<< XCHILDNS( _T("retrieve"), JABBER_FEAT_ARCHIVE) << XATTR(_T("with"), with) << XATTR(_T("start"), start));

		time_t tmThis = str2time(start);
		if ( tmThis > tmLast) {
			tmLast = tmThis;
			setDword(hContact, "LastCollection", tmLast+1);
		}
	}
}
Ejemplo n.º 8
0
int CJabberProto::SearchRenewFields(HWND hwndDlg, JabberSearchData * dat)
{
	TCHAR szServerName[100];
	EnableWindow(GetDlgItem(hwndDlg, IDC_GO),FALSE);
	GetDlgItemText(hwndDlg,IDC_SERVER,szServerName,SIZEOF(szServerName));
	dat->CurrentHeight = 0;
	dat->curPos = 0;
	SetScrollPos(GetDlgItem(hwndDlg, IDC_VSCROLL), SB_CTL, 0, FALSE);

	JabberSearchFreeData(hwndDlg, dat);
	JabberSearchRefreshFrameScroll(hwndDlg, dat);

	SetDlgItemText(hwndDlg,IDC_INSTRUCTIONS,m_bJabberOnline ? TranslateT("Please wait...\r\nConnecting search server...") : TranslateT("You have to be connected to server"));

	if (!m_bJabberOnline)
		return 0;

	searchHandleDlg = hwndDlg;

	CJabberIqInfo *pInfo = AddIQ(&CJabberProto::OnIqResultGetSearchFields, JABBER_IQ_TYPE_GET, szServerName);
	m_ThreadInfo->send( XmlNodeIq(pInfo) << XQUERY(_T("jabber:iq:search")));
	return pInfo->GetIqId();
}
Ejemplo n.º 9
0
JabberCapsBits CJabberProto::GetResourceCapabilites(const TCHAR *jid, BOOL appendBestResource)
{
	TCHAR fullJid[JABBER_MAX_JID_LEN];
	if (appendBestResource)
		GetClientJID(jid, fullJid, SIZEOF(fullJid));
	else
		_tcsncpy(fullJid, jid, SIZEOF(fullJid));

	pResourceStatus r(ResourceInfoFromJID(fullJid));
	if (r == NULL)
		return JABBER_RESOURCE_CAPS_ERROR;

	// XEP-0115 mode
	if (r->m_tszCapsNode && r->m_tszCapsVer) {
		JabberCapsBits jcbCaps = 0, jcbExtCaps = 0;
		BOOL bRequestSent = FALSE;
		JabberCapsBits jcbMainCaps = m_clientCapsManager.GetClientCaps(r->m_tszCapsNode, r->m_tszCapsVer);

		if (jcbMainCaps == JABBER_RESOURCE_CAPS_TIMEOUT && !r->m_dwDiscoInfoRequestTime)
			jcbMainCaps = JABBER_RESOURCE_CAPS_ERROR;

		if (jcbMainCaps == JABBER_RESOURCE_CAPS_UNINIT) {
			// send disco#info query

			CJabberIqInfo *pInfo = AddIQ(&CJabberProto::OnIqResultCapsDiscoInfo, JABBER_IQ_TYPE_GET, fullJid, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_CHILD_TAG_NODE);
			pInfo->SetTimeout(JABBER_RESOURCE_CAPS_QUERY_TIMEOUT);
			m_clientCapsManager.SetClientCaps(r->m_tszCapsNode, r->m_tszCapsVer, JABBER_RESOURCE_CAPS_IN_PROGRESS, pInfo->GetIqId());
			r->m_dwDiscoInfoRequestTime = pInfo->GetRequestTime();

			TCHAR queryNode[512];
			mir_sntprintf(queryNode, SIZEOF(queryNode), _T("%s#%s"), r->m_tszCapsNode, r->m_tszCapsVer);
			m_ThreadInfo->send(XmlNodeIq(pInfo) << XQUERY(JABBER_FEAT_DISCO_INFO) << XATTR(_T("node"), queryNode));

			bRequestSent = TRUE;
		}
		else if (jcbMainCaps == JABBER_RESOURCE_CAPS_IN_PROGRESS)
			bRequestSent = TRUE;
		else if (jcbMainCaps != JABBER_RESOURCE_CAPS_TIMEOUT)
			jcbCaps |= jcbMainCaps;

		if (jcbMainCaps != JABBER_RESOURCE_CAPS_TIMEOUT && r->m_tszCapsExt) {
			TCHAR *caps = mir_tstrdup(r->m_tszCapsExt);

			TCHAR *token = _tcstok(caps, _T(" "));
			while (token) {
				switch (jcbExtCaps = m_clientCapsManager.GetClientCaps(r->m_tszCapsNode, token)) {
				case JABBER_RESOURCE_CAPS_ERROR:
					break;

				case JABBER_RESOURCE_CAPS_UNINIT:
					{
						// send disco#info query

						CJabberIqInfo *pInfo = AddIQ(&CJabberProto::OnIqResultCapsDiscoInfo, JABBER_IQ_TYPE_GET, fullJid, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_CHILD_TAG_NODE);
						pInfo->SetTimeout(JABBER_RESOURCE_CAPS_QUERY_TIMEOUT);
						m_clientCapsManager.SetClientCaps(r->m_tszCapsNode, token, JABBER_RESOURCE_CAPS_IN_PROGRESS, pInfo->GetIqId());

						m_ThreadInfo->send(
							XmlNodeIq(pInfo) << XQUERY(JABBER_FEAT_DISCO_INFO) << XATTR(_T("node"), CMString(FORMAT, _T("%s#%s"), r->m_tszCapsNode, token)));

						bRequestSent = TRUE;
					}
					break;

				case JABBER_RESOURCE_CAPS_IN_PROGRESS:
					bRequestSent = TRUE;
					break;

				default:
					jcbCaps |= jcbExtCaps;
				}

				token = _tcstok(NULL, _T(" "));
			}

			mir_free(caps);
		}

		if (bRequestSent)
			return JABBER_RESOURCE_CAPS_IN_PROGRESS;

		return jcbCaps | r->m_jcbManualDiscoveredCaps;
	}

	// capability mode (version request + service discovery)

	// no version info:
	if (!r->m_tszSoftwareVersion && !r->m_tszSoftware) {
		// version request not sent:
		if (!r->m_dwVersionRequestTime) {
			// send version query

			CJabberIqInfo *pInfo = AddIQ(&CJabberProto::OnIqResultVersion, JABBER_IQ_TYPE_GET, fullJid, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_HCONTACT | JABBER_IQ_PARSE_CHILD_TAG_NODE);
			pInfo->SetTimeout(JABBER_RESOURCE_CAPS_QUERY_TIMEOUT);
			r->m_dwVersionRequestTime = pInfo->GetRequestTime();

			XmlNodeIq iq(pInfo);
			iq << XQUERY(JABBER_FEAT_VERSION);
			m_ThreadInfo->send(iq);
			return JABBER_RESOURCE_CAPS_IN_PROGRESS;
		}
		// version not received:
		else if (r->m_dwVersionRequestTime != -1) {
			// no timeout?
			if (GetTickCount() - r->m_dwVersionRequestTime < JABBER_RESOURCE_CAPS_QUERY_TIMEOUT)
				return JABBER_RESOURCE_CAPS_IN_PROGRESS;

			// timeout
			r->m_dwVersionRequestTime = -1;
		}
		// no version information, try direct service discovery
		if (!r->m_dwDiscoInfoRequestTime) {
			// send disco#info query

			CJabberIqInfo *pInfo = AddIQ(&CJabberProto::OnIqResultCapsDiscoInfo, JABBER_IQ_TYPE_GET, fullJid, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_CHILD_TAG_NODE);
			pInfo->SetTimeout(JABBER_RESOURCE_CAPS_QUERY_TIMEOUT);
			r->m_dwDiscoInfoRequestTime = pInfo->GetRequestTime();

			XmlNodeIq iq(pInfo);
			iq << XQUERY(JABBER_FEAT_DISCO_INFO);
			m_ThreadInfo->send(iq);

			return JABBER_RESOURCE_CAPS_IN_PROGRESS;
		}
		else if (r->m_dwDiscoInfoRequestTime == -1)
			return r->m_jcbCachedCaps | r->m_jcbManualDiscoveredCaps;
		else if (GetTickCount() - r->m_dwDiscoInfoRequestTime < JABBER_RESOURCE_CAPS_QUERY_TIMEOUT)
			return JABBER_RESOURCE_CAPS_IN_PROGRESS;
		else
			r->m_dwDiscoInfoRequestTime = -1;
		// version request timeout:
		return JABBER_RESOURCE_CAPS_NONE;
	}

	// version info available:
	if (r->m_tszSoftware && r->m_tszSoftwareVersion) {
		JabberCapsBits jcbMainCaps = m_clientCapsManager.GetClientCaps(r->m_tszSoftware, r->m_tszSoftwareVersion);
		if (jcbMainCaps == JABBER_RESOURCE_CAPS_ERROR) {
			// Bombus hack:
			if (!_tcscmp(r->m_tszSoftware, _T("Bombus")) || !_tcscmp(r->m_tszSoftware, _T("BombusMod"))) {
				jcbMainCaps = JABBER_CAPS_SI | JABBER_CAPS_SI_FT | JABBER_CAPS_IBB | JABBER_CAPS_MESSAGE_EVENTS | JABBER_CAPS_MESSAGE_EVENTS_NO_DELIVERY | JABBER_CAPS_DATA_FORMS | JABBER_CAPS_LAST_ACTIVITY | JABBER_CAPS_VERSION | JABBER_CAPS_COMMANDS | JABBER_CAPS_VCARD_TEMP;
				m_clientCapsManager.SetClientCaps(r->m_tszSoftware, r->m_tszSoftwareVersion, jcbMainCaps);
			}
			// Neos hack:
			else if (!_tcscmp(r->m_tszSoftware, _T("neos"))) {
				jcbMainCaps = JABBER_CAPS_OOB | JABBER_CAPS_MESSAGE_EVENTS | JABBER_CAPS_MESSAGE_EVENTS_NO_DELIVERY | JABBER_CAPS_LAST_ACTIVITY | JABBER_CAPS_VERSION;
				m_clientCapsManager.SetClientCaps(r->m_tszSoftware, r->m_tszSoftwareVersion, jcbMainCaps);
			}
			// sim hack:
			else if (!_tcscmp(r->m_tszSoftware, _T("sim"))) {
				jcbMainCaps = JABBER_CAPS_OOB | JABBER_CAPS_VERSION | JABBER_CAPS_MESSAGE_EVENTS | JABBER_CAPS_MESSAGE_EVENTS_NO_DELIVERY;
				m_clientCapsManager.SetClientCaps(r->m_tszSoftware, r->m_tszSoftwareVersion, jcbMainCaps);
			}
		}

		else if (jcbMainCaps == JABBER_RESOURCE_CAPS_UNINIT) {
			// send disco#info query

			CJabberIqInfo *pInfo = AddIQ(&CJabberProto::OnIqResultCapsDiscoInfo, JABBER_IQ_TYPE_GET, fullJid, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_CHILD_TAG_NODE);
			pInfo->SetTimeout(JABBER_RESOURCE_CAPS_QUERY_TIMEOUT);
			m_clientCapsManager.SetClientCaps(r->m_tszSoftware, r->m_tszSoftwareVersion, JABBER_RESOURCE_CAPS_IN_PROGRESS, pInfo->GetIqId());
			r->m_dwDiscoInfoRequestTime = pInfo->GetRequestTime();

			XmlNodeIq iq(pInfo);
			iq << XQUERY(JABBER_FEAT_DISCO_INFO);
			m_ThreadInfo->send(iq);

			jcbMainCaps = JABBER_RESOURCE_CAPS_IN_PROGRESS;
		}
		return jcbMainCaps | r->m_jcbManualDiscoveredCaps;
	}

	return JABBER_RESOURCE_CAPS_NONE;
}
Ejemplo n.º 10
0
void CJabberProto::SetServerVcard(BOOL bPhotoChanged, TCHAR* szPhotoFileName)
{
	if (!m_bJabberOnline) return;

	int  i;
	char idstr[33];

	XmlNodeIq iq(AddIQ(&CJabberProto::OnIqResultSetVcard, JABBER_IQ_TYPE_SET));
	HXML v = iq << XCHILDNS(_T("vCard"), JABBER_FEAT_VCARD_TEMP);

	AppendVcardFromDB(v, "FN", "FullName");

	HXML n = v << XCHILD(_T("N"));
	AppendVcardFromDB(n, "GIVEN", "FirstName");
	AppendVcardFromDB(n, "MIDDLE", "MiddleName");
	AppendVcardFromDB(n, "FAMILY", "LastName");

	AppendVcardFromDB(v, "NICKNAME", "Nick");
	AppendVcardFromDB(v, "BDAY", "BirthDate");
	AppendVcardFromDB(v, "GENDER", "GenderString");

	for (i = 0;; i++) {
		mir_snprintf(idstr, "e-mail%d", i);
		ptrT email(getTStringA(idstr));
		if (email == NULL)
			break;

		HXML e = v << XCHILD(_T("EMAIL"), email);
		AppendVcardFromDB(e, "USERID", idstr);

		mir_snprintf(idstr, "e-mailFlag%d", i);
		WORD nFlag = getWord(idstr, 0);
		if (nFlag & JABBER_VCEMAIL_HOME)     e << XCHILD(_T("HOME"));
		if (nFlag & JABBER_VCEMAIL_WORK)     e << XCHILD(_T("WORK"));
		if (nFlag & JABBER_VCEMAIL_INTERNET) e << XCHILD(_T("INTERNET"));
		if (nFlag & JABBER_VCEMAIL_X400)     e << XCHILD(_T("X400"));
	}

	n = v << XCHILD(_T("ADR"));
	n << XCHILD(_T("HOME"));
	AppendVcardFromDB(n, "STREET", "Street");
	AppendVcardFromDB(n, "EXTADR", "Street2");
	AppendVcardFromDB(n, "EXTADD", "Street2");	// for compatibility with client using old vcard format
	AppendVcardFromDB(n, "LOCALITY", "City");
	AppendVcardFromDB(n, "REGION", "State");
	AppendVcardFromDB(n, "PCODE", "ZIP");
	AppendVcardFromDB(n, "CTRY", "Country");
	AppendVcardFromDB(n, "COUNTRY", "Country");	// for compatibility with client using old vcard format

	n = v << XCHILD(_T("ADR"));
	n << XCHILD(_T("WORK"));
	AppendVcardFromDB(n, "STREET", "CompanyStreet");
	AppendVcardFromDB(n, "EXTADR", "CompanyStreet2");
	AppendVcardFromDB(n, "EXTADD", "CompanyStreet2");	// for compatibility with client using old vcard format
	AppendVcardFromDB(n, "LOCALITY", "CompanyCity");
	AppendVcardFromDB(n, "REGION", "CompanyState");
	AppendVcardFromDB(n, "PCODE", "CompanyZIP");
	AppendVcardFromDB(n, "CTRY", "CompanyCountry");
	AppendVcardFromDB(n, "COUNTRY", "CompanyCountry");	// for compatibility with client using old vcard format

	n = v << XCHILD(_T("ORG"));
	AppendVcardFromDB(n, "ORGNAME", "Company");
	AppendVcardFromDB(n, "ORGUNIT", "CompanyDepartment");

	AppendVcardFromDB(v, "TITLE", "CompanyPosition");
	AppendVcardFromDB(v, "ROLE", "Role");
	AppendVcardFromDB(v, "URL", "Homepage");
	AppendVcardFromDB(v, "DESC", "About");

	for (i = 0;; i++) {
		mir_snprintf(idstr, "Phone%d", i);
		ptrT phone(getTStringA(idstr));
		if (phone == NULL)
			break;

		n = v << XCHILD(_T("TEL"));
		AppendVcardFromDB(n, "NUMBER", idstr);

		mir_snprintf(idstr, "PhoneFlag%d", i);
		WORD nFlag = getWord(idstr, 0);
		if (nFlag & JABBER_VCTEL_HOME)  n << XCHILD(_T("HOME"));
		if (nFlag & JABBER_VCTEL_WORK)  n << XCHILD(_T("WORK"));
		if (nFlag & JABBER_VCTEL_VOICE) n << XCHILD(_T("VOICE"));
		if (nFlag & JABBER_VCTEL_FAX)   n << XCHILD(_T("FAX"));
		if (nFlag & JABBER_VCTEL_PAGER) n << XCHILD(_T("PAGER"));
		if (nFlag & JABBER_VCTEL_MSG)   n << XCHILD(_T("MSG"));
		if (nFlag & JABBER_VCTEL_CELL)  n << XCHILD(_T("CELL"));
		if (nFlag & JABBER_VCTEL_VIDEO) n << XCHILD(_T("VIDEO"));
		if (nFlag & JABBER_VCTEL_BBS)   n << XCHILD(_T("BBS"));
		if (nFlag & JABBER_VCTEL_MODEM) n << XCHILD(_T("MODEM"));
		if (nFlag & JABBER_VCTEL_ISDN)  n << XCHILD(_T("ISDN"));
		if (nFlag & JABBER_VCTEL_PCS)   n << XCHILD(_T("PCS"));
	}

	TCHAR szAvatarName[MAX_PATH], *szFileName;
	GetAvatarFileName(NULL, szAvatarName, _countof(szAvatarName));
	if (bPhotoChanged)
		szFileName = szPhotoFileName;
	else
		szFileName = szAvatarName;

	// Set photo element, also update the global jabberVcardPhotoFileName to reflect the update
	debugLog(_T("Before update, file name = %s"), szFileName);
	if (szFileName == NULL || szFileName[0] == 0) {
		v << XCHILD(_T("PHOTO"));
		DeleteFile(szAvatarName);
		delSetting("AvatarSaved");
		delSetting("AvatarHash");
	}
	else {
		debugLog(_T("Saving picture from %s"), szFileName);

		struct _stat st;
		if (_tstat(szFileName, &st) >= 0) {
			// Note the FILE_SHARE_READ attribute so that the CopyFile can succeed
			HANDLE hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
			if (hFile != INVALID_HANDLE_VALUE) {
				ptrA buffer((char*)mir_alloc(st.st_size));
				if (buffer != NULL) {
					DWORD nRead;
					if (ReadFile(hFile, buffer, st.st_size, &nRead, NULL)) {
						ptrA str(mir_base64_encode((PBYTE)(LPSTR)buffer, nRead));
						if (str != NULL) {
							n = v << XCHILD(_T("PHOTO"));
							TCHAR *szFileType;
							switch (ProtoGetBufferFormat(buffer)) {
								case PA_FORMAT_PNG:  szFileType = _T("image/png");   break;
								case PA_FORMAT_GIF:  szFileType = _T("image/gif");   break;
								case PA_FORMAT_BMP:  szFileType = _T("image/bmp");   break;
								default:             szFileType = _T("image/jpeg");  break;
							}
							n << XCHILD(_T("TYPE"), szFileType);
							n << XCHILD(_T("BINVAL"), _A2T(str));

							// NEED TO UPDATE OUR AVATAR HASH:
							BYTE digest[MIR_SHA1_HASH_SIZE];
							mir_sha1_ctx sha1ctx;
							mir_sha1_init(&sha1ctx);
							mir_sha1_append(&sha1ctx, (BYTE*)(LPSTR)buffer, nRead);
							mir_sha1_finish(&sha1ctx, digest);

							char buf[MIR_SHA1_HASH_SIZE * 2 + 1];
							bin2hex(digest, sizeof(digest), buf);

							m_options.AvatarType = ProtoGetBufferFormat(buffer);

							if (bPhotoChanged) {
								DeleteFile(szAvatarName);

								GetAvatarFileName(NULL, szAvatarName, _countof(szAvatarName));
								CopyFile(szFileName, szAvatarName, FALSE);
							}

							setString("AvatarHash", buf);
							setString("AvatarSaved", buf);
						}
					}
				}
				CloseHandle(hFile);
			}
		}
	}

	m_ThreadInfo->send(iq);
}