static int do_vals2text( LDAP *ld, char *buf, /* NULL for "use internal" */ char **vals, char *label, int labelwidth, /* 0 means use default */ unsigned int syntaxid, writeptype writeproc, void *writeparm, char *eol, int rdncount, char *urlprefix ) { int i, html, writeoutval, freebuf, notascii; char *p, *s, *outval; if ( vals == NULL ) { return( LDAP_SUCCESS ); } html = ( urlprefix != NULL ); switch( LDAP_GET_SYN_TYPE( syntaxid )) { case LDAP_SYN_TYPE_TEXT: case LDAP_SYN_TYPE_BOOLEAN: break; /* we only bother with these two types... */ default: return( LDAP_SUCCESS ); } if ( labelwidth == 0 || labelwidth < 0 ) { labelwidth = DEF_LABEL_WIDTH; } if ( buf == NULL ) { if (( buf = malloc( LDAP_DTMPL_BUFSIZ )) == NULL ) { ld->ld_errno = LDAP_NO_MEMORY; return( ld->ld_errno ); } freebuf = 1; } else { freebuf = 0; } output_label( buf, label, labelwidth, writeproc, writeparm, eol, html ); for ( i = 0; vals[ i ] != NULL; ++i ) { for ( p = vals[ i ]; *p != '\0'; ++p ) { if ( !isascii( *p )) { break; } } notascii = ( *p != '\0' ); outval = notascii ? "(unable to display non-ASCII text value)" : vals[ i ]; writeoutval = 0; /* if non-zero, write outval after switch */ switch( syntaxid ) { case LDAP_SYN_CASEIGNORESTR: ++writeoutval; break; case LDAP_SYN_RFC822ADDR: if ( html ) { strcpy( buf, "<DD><A HREF=\"mailto:" ); strcat_escaped( buf, outval ); sprintf( buf + strlen( buf ), "\">%s</A><BR>%s", outval, eol ); (*writeproc)( writeparm, buf, strlen( buf )); } else { ++writeoutval; } break; case LDAP_SYN_DN: /* for now */ output_dn( buf, outval, labelwidth, rdncount, writeproc, writeparm, eol, urlprefix ); break; case LDAP_SYN_MULTILINESTR: if ( i > 0 && !html ) { output_label( buf, label, labelwidth, writeproc, writeparm, eol, html ); } p = s = outval; while (( s = strchr( s, '$' )) != NULL ) { *s++ = '\0'; while ( isspace( *s )) { ++s; } if ( html ) { sprintf( buf, "<DD>%s<BR>%s", p, eol ); } else { sprintf( buf, "%-*s%s%s", labelwidth, " ", p, eol ); } (*writeproc)( writeparm, buf, strlen( buf )); p = s; } outval = p; ++writeoutval; break; case LDAP_SYN_BOOLEAN: outval = toupper( outval[ 0 ] ) == 'T' ? "TRUE" : "FALSE"; ++writeoutval; break; case LDAP_SYN_TIME: case LDAP_SYN_DATE: outval = time2text( outval, syntaxid == LDAP_SYN_DATE ); ++writeoutval; break; case LDAP_SYN_LABELEDURL: if ( !notascii && ( p = strchr( outval, '$' )) != NULL ) { *p++ = '\0'; while ( isspace( *p )) { ++p; } s = outval; } else if ( !notascii && ( s = strchr( outval, ' ' )) != NULL ) { *s++ = '\0'; while ( isspace( *s )) { ++s; } p = outval; } else { s = "URL"; p = outval; } /* * at this point `s' points to the label & `p' to the URL */ if ( html ) { sprintf( buf, "<DD><A HREF=\"%s\">%s</A><BR>%s", p, s, eol ); } else { sprintf( buf, "%-*s%s%s%-*s%s%s", labelwidth, " ", s, eol, labelwidth + 2, " ",p , eol ); } (*writeproc)( writeparm, buf, strlen( buf )); break; default: sprintf( buf, " Can't display item type %ld%s", syntaxid, eol ); (*writeproc)( writeparm, buf, strlen( buf )); } if ( writeoutval ) { if ( html ) { sprintf( buf, "<DD>%s<BR>%s", outval, eol ); } else { sprintf( buf, "%-*s%s%s", labelwidth, " ", outval, eol ); } (*writeproc)( writeparm, buf, strlen( buf )); } } if ( freebuf ) { free( buf ); } return( LDAP_SUCCESS ); }
void CIcqProto::handleUserOnline(BYTE *buf, size_t wLen, serverthread_info*) { DWORD dwPort = 0; DWORD dwRealIP = 0; DWORD dwUIN; uid_str szUID; DWORD dwDirectConnCookie = 0; DWORD dwWebPort = 0; DWORD dwFT1 = 0, dwFT2 = 0, dwFT3 = 0; const char *szClient = NULL; BYTE bClientId = 0; WORD wVersion = 0; WORD wTLVCount; WORD wWarningLevel; WORD wStatusFlags; WORD wStatus = 0, wOldStatus = 0; BYTE nTCPFlag = 0; char szStrBuf[MAX_PATH]; // Unpack the sender's user ID if (!unpackUID(&buf, &wLen, &dwUIN, &szUID)) return; // Syntax check if (wLen < 4) return; // Warning level? unpackWord(&buf, &wWarningLevel); wLen -= 2; // TLV count unpackWord(&buf, &wTLVCount); wLen -= 2; // Ignore status notification if the user is not already on our list MCONTACT hContact = HContactFromUID(dwUIN, szUID, NULL); if (hContact == INVALID_CONTACT_ID) { debugLogA("Ignoring user online (%s)", strUID(dwUIN, szUID)); return; } // Read user info TLVs oscar_tlv_chain *pChain; oscar_tlv *pTLV; // Syntax check if (wLen < 4) return; // Get chain if (!(pChain = readIntoTLVChain(&buf, wLen, wTLVCount))) return; // Get Class word WORD wClass = pChain->getWord(0x01, 1); int nIsICQ = wClass & CLASS_ICQ; if (dwUIN) { // Get DC info TLV pTLV = pChain->getTLV(0x0C, 1); if (pTLV && (pTLV->wLen >= 15)) { BYTE *pBuffer = pTLV->pData; nIsICQ = TRUE; unpackDWord(&pBuffer, &dwRealIP); unpackDWord(&pBuffer, &dwPort); unpackByte(&pBuffer, &nTCPFlag); unpackWord(&pBuffer, &wVersion); unpackDWord(&pBuffer, &dwDirectConnCookie); unpackDWord(&pBuffer, &dwWebPort); // Web front port pBuffer += 4; // Client features // Get faked time signatures, used to identify clients if (pTLV->wLen >= 0x23) { unpackDWord(&pBuffer, &dwFT1); unpackDWord(&pBuffer, &dwFT2); unpackDWord(&pBuffer, &dwFT3); } } // Get Status info TLV pTLV = pChain->getTLV(0x06, 1); if (pTLV && (pTLV->wLen >= 4)) { BYTE *pBuffer = pTLV->pData; unpackWord(&pBuffer, &wStatusFlags); unpackWord(&pBuffer, &wStatus); } else if (!nIsICQ) { // Connected thru AIM client, guess by user class if (wClass & CLASS_AWAY) wStatus = ID_STATUS_AWAY; else if (wClass & CLASS_WIRELESS) wStatus = ID_STATUS_ONTHEPHONE; else wStatus = ID_STATUS_ONLINE; wStatusFlags = 0; } else { // Huh? No status TLV? Lets guess then... wStatusFlags = 0; wStatus = ICQ_STATUS_ONLINE; } } else { nIsICQ = FALSE; if (wClass & CLASS_AWAY) wStatus = ID_STATUS_AWAY; else if (wClass & CLASS_WIRELESS) wStatus = ID_STATUS_ONTHEPHONE; else wStatus = ID_STATUS_ONLINE; wStatusFlags = 0; } debugLogA("Flags are %x", wStatusFlags); debugLogA("Status is %x", wStatus); // Get IP TLV DWORD dwIP = pChain->getDWord(0x0A, 1); // Get Online Since TLV DWORD dwOnlineSince = pChain->getDWord(0x03, 1); // Get Away Since TLV DWORD dwAwaySince = pChain->getDWord(0x29, 1); // Get Member Since TLV DWORD dwMemberSince = pChain->getDWord(0x05, 1); // Get Idle timer TLV WORD wIdleTimer = pChain->getWord(0x04, 1); time_t tIdleTS = 0; if (wIdleTimer) { time(&tIdleTS); tIdleTS -= (wIdleTimer*60); } if (wIdleTimer) debugLogA("Idle timer is %u.", wIdleTimer); debugLogA("Online since %s", time2text(dwOnlineSince)); if (dwAwaySince) debugLogA("Status was set on %s", time2text(dwAwaySince)); // Check client capabilities if (hContact != NULL) { wOldStatus = getContactStatus(hContact); // Collect all Capability info from TLV chain BYTE *capBuf = NULL; WORD capLen = 0; // Get Location Capability Info TLVs oscar_tlv *pFullTLV = pChain->getTLV(0x0D, 1); oscar_tlv *pShortTLV = pChain->getTLV(0x19, 1); if (pFullTLV && (pFullTLV->wLen >= BINARY_CAP_SIZE)) capLen += pFullTLV->wLen; if (pShortTLV && (pShortTLV->wLen >= 2)) capLen += (pShortTLV->wLen * 8); capBuf = (BYTE*)_alloca(capLen + BINARY_CAP_SIZE); if (capLen) { BYTE *pCapability = capBuf; capLen = 0; // we need to recount that if (pFullTLV && (pFullTLV->wLen >= BINARY_CAP_SIZE)) { // copy classic Capabilities BYTE *cData = pFullTLV->pData; int cLen = pFullTLV->wLen; while (cLen) { // be impervious to duplicates (AOL sends them sometimes) if (!capLen || !MatchCapability(capBuf, capLen, (capstr*)cData, BINARY_CAP_SIZE)) { // not present, add memcpy(pCapability, cData, BINARY_CAP_SIZE); capLen += BINARY_CAP_SIZE; pCapability += BINARY_CAP_SIZE; } cData += BINARY_CAP_SIZE; cLen -= BINARY_CAP_SIZE; } } if (pShortTLV && (pShortTLV->wLen >= 2)) { // copy short Capabilities capstr tmp; BYTE *cData = pShortTLV->pData; int cLen = pShortTLV->wLen; memcpy(tmp, capShortCaps, BINARY_CAP_SIZE); while (cLen) { // be impervious to duplicates (AOL sends them sometimes) tmp[2] = cData[0]; tmp[3] = cData[1]; if (!capLen || !MatchCapability(capBuf, capLen, &tmp, BINARY_CAP_SIZE)) { // not present, add memcpy(pCapability, tmp, BINARY_CAP_SIZE); capLen += BINARY_CAP_SIZE; pCapability += BINARY_CAP_SIZE; } cData += 2; cLen -= 2; } } debugLogA("Detected %d capability items.", capLen / BINARY_CAP_SIZE); } if (capLen) { // Update the contact's capabilies if present in packet SetCapabilitiesFromBuffer(hContact, capBuf, capLen, wOldStatus == ID_STATUS_OFFLINE); char *szCurrentClient = wOldStatus == ID_STATUS_OFFLINE ? NULL : getSettingStringUtf(hContact, "MirVer", NULL); szClient = detectUserClient(hContact, nIsICQ, wClass, dwOnlineSince, szCurrentClient, wVersion, dwFT1, dwFT2, dwFT3, dwDirectConnCookie, dwWebPort, capBuf, capLen, &bClientId, szStrBuf); // Check if the client changed, if not do not change if (szCurrentClient && !strcmpnull(szCurrentClient, szClient)) szClient = (const char*)-1; SAFE_FREE(&szCurrentClient); } else if (wOldStatus == ID_STATUS_OFFLINE) { // Remove the contact's capabilities if coming from offline ClearAllContactCapabilities(hContact); // no capability debugLogA("No capability info TLVs"); szClient = detectUserClient(hContact, nIsICQ, wClass, dwOnlineSince, NULL, wVersion, dwFT1, dwFT2, dwFT3, dwDirectConnCookie, dwWebPort, NULL, capLen, &bClientId, szStrBuf); } else // Capabilities not present in update packet, do not touch szClient = (const char*)-1; // we don't want to client be overwritten // handle Xtraz status char *moodData = NULL; WORD moodSize = 0; unpackSessionDataItem(pChain, 0x0E, (BYTE**)&moodData, &moodSize, NULL); if (capLen || wOldStatus == ID_STATUS_OFFLINE) handleXStatusCaps(dwUIN, szUID, hContact, capBuf, capLen, moodData, moodSize); else handleXStatusCaps(dwUIN, szUID, hContact, NULL, 0, moodData, moodSize); // Determine support for extended status messages if (pChain->getWord(0x08, 1) == 0x0A06) SetContactCapabilities(hContact, CAPF_STATUS_MESSAGES); else if (wOldStatus == ID_STATUS_OFFLINE) ClearContactCapabilities(hContact, CAPF_STATUS_MESSAGES); if (wOldStatus == ID_STATUS_OFFLINE) { if (CheckContactCapabilities(hContact, CAPF_SRV_RELAY)) debugLogA("Supports advanced messages"); else debugLogA("Does NOT support advanced messages"); } if (!nIsICQ) { // AIM clients does not advertise these, but do support them SetContactCapabilities(hContact, CAPF_UTF | CAPF_TYPING); // Server relayed messages are only supported by ICQ clients ClearContactCapabilities(hContact, CAPF_SRV_RELAY); if (dwUIN && wOldStatus == ID_STATUS_OFFLINE) debugLogA("Logged in with AIM client"); } if (nIsICQ && wVersion < 8) { ClearContactCapabilities(hContact, CAPF_SRV_RELAY); if (wOldStatus == ID_STATUS_OFFLINE) debugLogA("Forcing simple messages due to compability issues"); } // Process Avatar Hash pTLV = pChain->getTLV(0x1D, 1); if (pTLV) handleAvatarContactHash(dwUIN, szUID, hContact, pTLV->pData, pTLV->wLen); else handleAvatarContactHash(dwUIN, szUID, hContact, NULL, 0); // Process Status Note parseStatusNote(dwUIN, szUID, hContact, pChain); } // Free TLV chain disposeChain(&pChain); // Save contacts details in database if (hContact != NULL) { setDword(hContact, "LogonTS", dwOnlineSince); setDword(hContact, "AwayTS", dwAwaySince); setDword(hContact, "IdleTS", tIdleTS); if (dwMemberSince) setDword(hContact, "MemberTS", dwMemberSince); if (nIsICQ) { // on AIM these are not used setDword(hContact, "DirectCookie", dwDirectConnCookie); setByte(hContact, "DCType", (BYTE)nTCPFlag); setWord(hContact, "UserPort", (WORD)(dwPort & 0xffff)); setWord(hContact, "Version", wVersion); } else { delSetting(hContact, "DirectCookie"); delSetting(hContact, "DCType"); delSetting(hContact, "UserPort"); delSetting(hContact, "Version"); } // if no detection, set uknown if (!szClient) szClient = (nIsICQ ? "Unknown" : "Unknown AIM"); if (szClient != (char*)-1) { db_set_utf(hContact, m_szModuleName, "MirVer", szClient); setByte(hContact, "ClientID", bClientId); } if (wOldStatus == ID_STATUS_OFFLINE) { setDword(hContact, "IP", dwIP); setDword(hContact, "RealIP", dwRealIP); } else { // if not first notification only write significant information if (dwIP) setDword(hContact, "IP", dwIP); if (dwRealIP) setDword(hContact, "RealIP", dwRealIP); } setWord(hContact, "Status", (WORD)IcqStatusToMiranda(wStatus)); // Update info? if (dwUIN) { // check if the local copy of user details is up-to-date if (IsMetaInfoChanged(hContact)) icq_QueueUser(hContact); } } LPCTSTR ptszStatus = pcli->pfnGetStatusModeDescription(IcqStatusToMiranda(wStatus), 0); if (wOldStatus != IcqStatusToMiranda(wStatus)) { // And a small log notice... if status was changed if (nIsICQ) debugLogA("%u changed status to %S (v%d).", dwUIN, ptszStatus, wVersion); else debugLogA("%s changed status to %S.", strUID(dwUIN, szUID), ptszStatus); } if (szClient == cliSpamBot) { if (getByte("KillSpambots", DEFAULT_KILLSPAM_ENABLED) && db_get_b(hContact, "CList", "NotOnList", 0)) { // kill spammer icq_DequeueUser(dwUIN); icq_sendRemoveContact(dwUIN, NULL); AddToSpammerList(dwUIN); if (getByte("PopupsSpamEnabled", DEFAULT_SPAM_POPUPS_ENABLED)) ShowPopupMsg(hContact, LPGEN("Spambot Detected"), LPGEN("Contact deleted & further events blocked."), POPTYPE_SPAM); CallService(MS_DB_CONTACT_DELETE, hContact, 0); debugLogA("Contact %u deleted", dwUIN); } } }
static void SetValue(CIcqProto* ppro, HWND hwndDlg, int idCtrl, MCONTACT hContact, char* szModule, char* szSetting, int special) { DBVARIANT dbv = { 0 }; char str[MAX_PATH]; char* pstr = NULL; int unspecified = 0; int bUtf = 0, bDbv = 0, bAlloc = 0; dbv.type = DBVT_DELETED; if ((hContact == NULL) && ((int)szModule < 0x100)) { dbv.type = (BYTE)szModule; switch ((int)szModule) { case DBVT_BYTE: dbv.cVal = (BYTE)szSetting; break; case DBVT_WORD: dbv.wVal = (WORD)szSetting; break; case DBVT_DWORD: dbv.dVal = (DWORD)szSetting; break; case DBVT_ASCIIZ: dbv.pszVal = pstr = szSetting; break; default: unspecified = 1; dbv.type = DBVT_DELETED; } } else { if (szModule == NULL) unspecified = 1; else { unspecified = db_get(hContact, szModule, szSetting, &dbv); bDbv = 1; } } if (!unspecified) { switch (dbv.type) { case DBVT_BYTE: unspecified = (special == SVS_ZEROISUNSPEC && dbv.bVal == 0); pstr = _itoa(special == SVS_SIGNED ? dbv.cVal : dbv.bVal, str, 10); break; case DBVT_WORD: if (special == SVS_ICQVERSION) { if (dbv.wVal != 0) { char szExtra[80]; mir_snprintf(str, "%d", dbv.wVal); pstr = str; if (hContact && ppro->IsDirectConnectionOpen(hContact, DIRECTCONN_STANDARD, 1)) { ICQTranslateUtfStatic(LPGEN(" (DC Established)"), szExtra, _countof(szExtra)); mir_strcat(str, (char*)szExtra); bUtf = 1; } } else unspecified = 1; } else if (special == SVS_STATUSID) { char *pszStatus = MirandaStatusToStringUtf(dbv.wVal); BYTE bXStatus = ppro->getContactXStatus(hContact); if (bXStatus) { char *pXName = ppro->getSettingStringUtf(hContact, DBSETTING_XSTATUS_NAME, NULL); if (pXName == NULL) // give default name pXName = ICQTranslateUtf(nameXStatus[bXStatus - 1]); mir_snprintf(str, "%s (%s)", pszStatus, pXName); SAFE_FREE((void**)&pXName); } else strncpy_s(str, pszStatus, _TRUNCATE); bUtf = 1; SAFE_FREE(&pszStatus); pstr = str; unspecified = 0; } else { unspecified = (special == SVS_ZEROISUNSPEC && dbv.wVal == 0); pstr = _itoa(special == SVS_SIGNED ? dbv.sVal : dbv.wVal, str, 10); } break; case DBVT_DWORD: unspecified = (special == SVS_ZEROISUNSPEC && dbv.dVal == 0); if (special == SVS_IP) { struct in_addr ia; ia.S_un.S_addr = htonl(dbv.dVal); pstr = inet_ntoa(ia); if (dbv.dVal == 0) unspecified = 1; } else if (special == SVS_TIMESTAMP) { if (dbv.dVal == 0) unspecified = 1; else pstr = time2text(dbv.dVal); } else pstr = _itoa(special == SVS_SIGNED ? dbv.lVal : dbv.dVal, str, 10); break; case DBVT_ASCIIZ: case DBVT_WCHAR: unspecified = (special == SVS_ZEROISUNSPEC && dbv.pszVal[0] == '\0'); if (!unspecified && pstr != szSetting) { pstr = ppro->getSettingStringUtf(hContact, szModule, szSetting, NULL); bUtf = 1; bAlloc = 1; } if (idCtrl == IDC_UIN) SetDlgItemText(hwndDlg, IDC_UINSTATIC, TranslateT("ScreenName:")); break; default: pstr = str; mir_strcpy(str, "???"); break; } } EnableDlgItem(hwndDlg, idCtrl, !unspecified); if (unspecified) SetDlgItemText(hwndDlg, idCtrl, TranslateT("<not specified>")); else if (bUtf) SetDlgItemTextUtf(hwndDlg, idCtrl, pstr); else SetDlgItemTextA(hwndDlg, idCtrl, pstr); if (bDbv) db_free(&dbv); if (bAlloc) SAFE_FREE(&pstr); }