diff options
Diffstat (limited to 'protocols/JabberG')
32 files changed, 502 insertions, 112 deletions
diff --git a/protocols/JabberG/jabber_10.vcxproj b/protocols/JabberG/jabber_10.vcxproj index febb753f0a..e1f795ede5 100644 --- a/protocols/JabberG/jabber_10.vcxproj +++ b/protocols/JabberG/jabber_10.vcxproj @@ -201,6 +201,7 @@ </Link>
</ItemDefinitionGroup>
<ItemGroup>
+ <ClCompile Include="src\jabber_archive.cpp" />
<ClCompile Include="src\stdafx.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
diff --git a/protocols/JabberG/jabber_10.vcxproj.filters b/protocols/JabberG/jabber_10.vcxproj.filters index 9b905f80ff..4f8501af1d 100644 --- a/protocols/JabberG/jabber_10.vcxproj.filters +++ b/protocols/JabberG/jabber_10.vcxproj.filters @@ -177,6 +177,9 @@ <ClCompile Include="src\stdafx.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="src\jabber_archive.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\jabber.h">
diff --git a/protocols/JabberG/jabber_11.vcxproj b/protocols/JabberG/jabber_11.vcxproj index 4e75869570..f30cd91381 100644 --- a/protocols/JabberG/jabber_11.vcxproj +++ b/protocols/JabberG/jabber_11.vcxproj @@ -205,6 +205,7 @@ </Link>
</ItemDefinitionGroup>
<ItemGroup>
+ <ClCompile Include="src\jabber_archive.cpp" />
<ClCompile Include="src\stdafx.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
diff --git a/protocols/JabberG/jabber_11.vcxproj.filters b/protocols/JabberG/jabber_11.vcxproj.filters index 9b905f80ff..4f8501af1d 100644 --- a/protocols/JabberG/jabber_11.vcxproj.filters +++ b/protocols/JabberG/jabber_11.vcxproj.filters @@ -177,6 +177,9 @@ <ClCompile Include="src\stdafx.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="src\jabber_archive.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\jabber.h">
diff --git a/protocols/JabberG/src/jabber.h b/protocols/JabberG/src/jabber.h index b8e7a1f4d5..9e27954ffd 100644 --- a/protocols/JabberG/src/jabber.h +++ b/protocols/JabberG/src/jabber.h @@ -745,6 +745,9 @@ TCHAR* __stdcall JabberStripJid(const TCHAR *jid, TCHAR* dest, size_t des int __stdcall JabberGetPictureType(const char* buf);
int __stdcall JabberGetPacketID(HXML n);
+TCHAR* time2str(time_t _time, TCHAR *buf, size_t bufLen);
+time_t str2time(const TCHAR*);
+
#define JabberUnixToDosT JabberUnixToDosW
#define JabberBase64DecodeT JabberBase64DecodeW
diff --git a/protocols/JabberG/src/jabber_adhoc.cpp b/protocols/JabberG/src/jabber_adhoc.cpp index c19589ee73..95f54ab015 100644 --- a/protocols/JabberG/src/jabber_adhoc.cpp +++ b/protocols/JabberG/src/jabber_adhoc.cpp @@ -115,7 +115,7 @@ int CJabberProto::AdHoc_RequestListOfCommands(TCHAR * szResponder, HWND hwndDlg) {
int iqId = (int)hwndDlg;
IqAdd(iqId, IQ_PROC_DISCOCOMMANDS, &CJabberProto::OnIqResult_ListOfCommands);
- m_ThreadInfo->send(XmlNodeIq(_T("get"), iqId, szResponder) << XQUERY(_T(JABBER_FEAT_DISCO_ITEMS))
+ m_ThreadInfo->send( XmlNodeIq(_T("get"), iqId, szResponder) << XQUERY(_T(JABBER_FEAT_DISCO_ITEMS))
<< XATTR(_T("node"), _T(JABBER_FEAT_COMMANDS)));
return iqId;
}
@@ -183,17 +183,16 @@ int CJabberProto::AdHoc_OnJAHMCommandListResult(HWND hwndDlg, HXML iqNode, Jabbe if (queryNode && xmlGetChild(queryNode ,0) && validResponse) {
dat->CommandsNode = xi.copyNode(queryNode);
- nodeIdx = 1;
int ypos = 20;
for (nodeIdx = 1; ; nodeIdx++) {
HXML itemNode = xmlGetNthChild(queryNode, _T("item"), nodeIdx);
- if (itemNode) {
- const TCHAR *name = xmlGetAttrValue(itemNode, _T("name"));
- if ( !name) name = xmlGetAttrValue(itemNode, _T("node"));
- ypos = AdHoc_AddCommandRadio(GetDlgItem(hwndDlg,IDC_FRAME), TranslateTS(name), nodeIdx, ypos, (nodeIdx==1) ? 1 : 0);
- dat->CurrentHeight = ypos;
- }
- else break;
+ if (!itemNode)
+ break;
+
+ const TCHAR *name = xmlGetAttrValue(itemNode, _T("name"));
+ if ( !name) name = xmlGetAttrValue(itemNode, _T("node"));
+ ypos = AdHoc_AddCommandRadio(GetDlgItem(hwndDlg,IDC_FRAME), TranslateTS(name), nodeIdx, ypos, (nodeIdx==1) ? 1 : 0);
+ dat->CurrentHeight = ypos;
} }
if (nodeIdx>1) {
diff --git a/protocols/JabberG/src/jabber_agent.cpp b/protocols/JabberG/src/jabber_agent.cpp index 928beab4e0..62343fd63a 100644 --- a/protocols/JabberG/src/jabber_agent.cpp +++ b/protocols/JabberG/src/jabber_agent.cpp @@ -102,7 +102,7 @@ public: int iqId = m_proto->SerialNext();
m_proto->IqAdd(iqId, IQ_PROC_GETREGISTER, &CJabberProto::OnIqResultGetRegister);
- m_proto->m_ThreadInfo->send(XmlNodeIq(_T("get"), iqId, m_jid) << XQUERY(_T(JABBER_FEAT_REGISTER)));
+ m_proto->m_ThreadInfo->send( XmlNodeIq(_T("get"), iqId, m_jid) << XQUERY(_T(JABBER_FEAT_REGISTER)));
// Enable WS_EX_CONTROLPARENT on IDC_FRAME (so tab stop goes through all its children)
LONG frameExStyle = GetWindowLongPtr(GetDlgItem(m_hwnd, IDC_FRAME), GWL_EXSTYLE);
diff --git a/protocols/JabberG/src/jabber_archive.cpp b/protocols/JabberG/src/jabber_archive.cpp new file mode 100644 index 0000000000..74ef786e00 --- /dev/null +++ b/protocols/JabberG/src/jabber_archive.cpp @@ -0,0 +1,308 @@ +/*
+
+Jabber Protocol Plugin for Miranda IM
+Copyright (C) 2002-04 Santithorn Bunchua
+Copyright (C) 2005-12 George Hazan
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include "jabber.h"
+#include "jabber_iq.h"
+#include "jabber_caps.h"
+
+void CJabberProto::EnableArchive(bool bEnable)
+{
+ m_ThreadInfo->send( XmlNodeIq(_T("set"), SerialNext())
+ << XCHILDNS( _T("auto"), _T(JABBER_FEAT_ARCHIVE)) << XATTR(_T("save"), (bEnable) ? _T("true") : _T("false")));
+}
+
+void CJabberProto::RetrieveMessageArchive(HANDLE hContact, JABBER_LIST_ITEM *pItem)
+{
+ if (pItem->bHistoryRead)
+ return;
+
+ pItem->bHistoryRead = TRUE;
+
+ int iqId = SerialNext();
+ XmlNodeIq iq(_T("get"), iqId);
+ HXML list = iq << XCHILDNS( _T("list"), _T(JABBER_FEAT_ARCHIVE)) << XATTR(_T("with"), pItem->jid);
+
+ time_t tmLast = JGetDword(hContact, "LastCollection", 0);
+ if (tmLast) {
+ TCHAR buf[40];
+ list << XATTR(_T("start"), time2str(tmLast, buf, SIZEOF(buf)));
+ }
+
+ IqAdd(iqId, IQ_PROC_NONE, &CJabberProto::OnIqResultGetCollectionList);
+ m_ThreadInfo->send(iq);
+}
+
+void CJabberProto::OnIqResultGetCollectionList(HXML iqNode)
+{
+ const TCHAR *to = xmlGetAttrValue(iqNode, _T("to"));
+ if (to == NULL || lstrcmp( xmlGetAttrValue(iqNode, _T("type")), _T("result")))
+ return;
+
+ HXML list = xmlGetChild(iqNode, "list");
+ if (!list || lstrcmp( xmlGetAttrValue(list, _T("xmlns")), _T(JABBER_FEAT_ARCHIVE)))
+ return;
+
+ HANDLE 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 = JGetDword(hContact, "LastCollection", 0);
+ }
+
+ int iqId = SerialNext();
+ IqAdd(iqId, IQ_PROC_NONE, &CJabberProto::OnIqResultGetCollection);
+ m_ThreadInfo->send(
+ XmlNodeIq(_T("get"), iqId)
+ << XCHILDNS( _T("retrieve"), _T(JABBER_FEAT_ARCHIVE)) << XATTR(_T("with"), with) << XATTR(_T("start"), start));
+
+ time_t tmThis = str2time(start);
+ if ( tmThis > tmLast) {
+ tmLast = tmThis;
+ JSetDword(hContact, "LastCollection", tmLast+1);
+ }
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static DWORD dwPreviousTimeStamp = -1;
+static HANDLE hPreviousContact = INVALID_HANDLE_VALUE;
+static HANDLE hPreviousDbEvent = NULL;
+
+// Returns TRUE if the event already exist in the database
+BOOL IsDuplicateEvent(HANDLE hContact, DBEVENTINFO& dbei)
+{
+ HANDLE hExistingDbEvent;
+ DWORD dwEventTimeStamp;
+ DBEVENTINFO dbeiExisting;
+
+ // get last event
+ if (!(hExistingDbEvent = (HANDLE)CallService(MS_DB_EVENT_FINDLAST, (WPARAM)hContact, 0)))
+ return FALSE;
+
+ ZeroMemory(&dbeiExisting, sizeof(dbeiExisting));
+ dbeiExisting.cbSize = sizeof(dbeiExisting);
+ CallService(MS_DB_EVENT_GET, (WPARAM)hExistingDbEvent, (LPARAM)&dbeiExisting);
+ dwEventTimeStamp = dbeiExisting.timestamp;
+
+ // compare with last timestamp
+ if (dbei.timestamp > dwEventTimeStamp) {
+ // remember event
+ hPreviousDbEvent = hExistingDbEvent;
+ dwPreviousTimeStamp = dwEventTimeStamp;
+ return FALSE;
+ }
+
+ if (hContact != hPreviousContact) {
+ hPreviousContact = hContact;
+ // remember event
+ hPreviousDbEvent = hExistingDbEvent;
+ dwPreviousTimeStamp = dwEventTimeStamp;
+
+ // get first event
+ if (!(hExistingDbEvent = (HANDLE)CallService(MS_DB_EVENT_FINDFIRST, (WPARAM)hContact, 0)))
+ return FALSE;
+
+ ZeroMemory(&dbeiExisting, sizeof(dbeiExisting));
+ dbeiExisting.cbSize = sizeof(dbeiExisting);
+ CallService(MS_DB_EVENT_GET, (WPARAM)hExistingDbEvent, (LPARAM)&dbeiExisting);
+ dwEventTimeStamp = dbeiExisting.timestamp;
+
+ // compare with first timestamp
+ if (dbei.timestamp <= dwEventTimeStamp) {
+ // remember event
+ dwPreviousTimeStamp = dwEventTimeStamp;
+ hPreviousDbEvent = hExistingDbEvent;
+
+ if ( dbei.timestamp != dwEventTimeStamp )
+ return FALSE;
+ }
+ }
+
+ // check for equal timestamps
+ if (dbei.timestamp == dwPreviousTimeStamp) {
+ ZeroMemory(&dbeiExisting, sizeof(dbeiExisting));
+ dbeiExisting.cbSize = sizeof(dbeiExisting);
+ CallService(MS_DB_EVENT_GET, (WPARAM)hPreviousDbEvent, (LPARAM)&dbeiExisting);
+
+ if ((dbei.timestamp == dbeiExisting.timestamp) &&
+ (dbei.eventType == dbeiExisting.eventType) &&
+ (dbei.cbBlob == dbeiExisting.cbBlob) &&
+ ((dbei.flags&DBEF_SENT) == (dbeiExisting.flags&DBEF_SENT)))
+ return TRUE;
+
+ // find event with another timestamp
+ hExistingDbEvent = (HANDLE)CallService(MS_DB_EVENT_FINDNEXT, (WPARAM)hPreviousDbEvent, 0);
+ while (hExistingDbEvent != NULL) {
+ ZeroMemory(&dbeiExisting, sizeof(dbeiExisting));
+ dbeiExisting.cbSize = sizeof(dbeiExisting);
+ CallService(MS_DB_EVENT_GET, (WPARAM)hExistingDbEvent, (LPARAM)&dbeiExisting);
+
+ if (dbeiExisting.timestamp != dwPreviousTimeStamp) {
+ // use found event
+ hPreviousDbEvent = hExistingDbEvent;
+ dwPreviousTimeStamp = dbeiExisting.timestamp;
+ break;
+ }
+
+ hPreviousDbEvent = hExistingDbEvent;
+ hExistingDbEvent = (HANDLE)CallService(MS_DB_EVENT_FINDNEXT, (WPARAM)hExistingDbEvent, 0);
+ }
+ }
+
+ hExistingDbEvent = hPreviousDbEvent;
+
+ if (dbei.timestamp <= dwPreviousTimeStamp) {
+ // look back
+ while (hExistingDbEvent != NULL) {
+ ZeroMemory(&dbeiExisting, sizeof(dbeiExisting));
+ dbeiExisting.cbSize = sizeof(dbeiExisting);
+ CallService(MS_DB_EVENT_GET, (WPARAM)hExistingDbEvent, (LPARAM)&dbeiExisting);
+
+ if (dbei.timestamp > dbeiExisting.timestamp) {
+ // remember event
+ hPreviousDbEvent = hExistingDbEvent;
+ dwPreviousTimeStamp = dbeiExisting.timestamp;
+ return FALSE;
+ }
+
+ // Compare event with import candidate
+ if ((dbei.timestamp == dbeiExisting.timestamp) &&
+ (dbei.eventType == dbeiExisting.eventType) &&
+ (dbei.cbBlob == dbeiExisting.cbBlob) &&
+ ((dbei.flags & DBEF_SENT) == (dbeiExisting.flags & DBEF_SENT)))
+ {
+ // remember event
+ hPreviousDbEvent = hExistingDbEvent;
+ dwPreviousTimeStamp = dbeiExisting.timestamp;
+ return TRUE;
+ }
+
+ // Get previous event in chain
+ hExistingDbEvent = (HANDLE)CallService(MS_DB_EVENT_FINDPREV, (WPARAM)hExistingDbEvent, 0);
+ }
+ }
+ else {
+ // look forward
+ while (hExistingDbEvent != NULL) {
+ ZeroMemory(&dbeiExisting, sizeof(dbeiExisting));
+ dbeiExisting.cbSize = sizeof(dbeiExisting);
+ CallService(MS_DB_EVENT_GET, (WPARAM)hExistingDbEvent, (LPARAM)&dbeiExisting);
+
+ if (dbei.timestamp < dbeiExisting.timestamp) {
+ // remember event
+ hPreviousDbEvent = hExistingDbEvent;
+ dwPreviousTimeStamp = dbeiExisting.timestamp;
+ return FALSE;
+ }
+
+ // Compare event with import candidate
+ if ((dbei.timestamp == dbeiExisting.timestamp) &&
+ (dbei.eventType == dbeiExisting.eventType) &&
+ (dbei.cbBlob == dbeiExisting.cbBlob) &&
+ ((dbei.flags&DBEF_SENT) == (dbeiExisting.flags&DBEF_SENT)))
+ {
+ // remember event
+ hPreviousDbEvent = hExistingDbEvent;
+ dwPreviousTimeStamp = dbeiExisting.timestamp;
+ return TRUE;
+ }
+
+ // Get next event in chain
+ hExistingDbEvent = (HANDLE)CallService(MS_DB_EVENT_FINDNEXT, (WPARAM)hExistingDbEvent, 0);
+ }
+ }
+ // reset last event
+ hPreviousContact = INVALID_HANDLE_VALUE;
+ return FALSE;
+}
+
+void CJabberProto::OnIqResultGetCollection(HXML iqNode)
+{
+ if ( lstrcmp( xmlGetAttrValue(iqNode, _T("type")), _T("result")))
+ return;
+
+ HXML chatNode = xmlGetChild(iqNode, "chat");
+ if (!chatNode || lstrcmp( xmlGetAttrValue(chatNode, _T("xmlns")), _T(JABBER_FEAT_ARCHIVE)))
+ return;
+
+ const TCHAR* start = xmlGetAttrValue(chatNode, _T("start"));
+ const TCHAR* with = xmlGetAttrValue(chatNode, _T("with"));
+ if (!start || !with)
+ return;
+
+ HANDLE hContact = HContactFromJID(with);
+ time_t tmStart = str2time(start);
+ if (hContact == 0 || tmStart == 0)
+ return;
+
+ _tzset();
+
+ for (int nodeIdx = 0; ; nodeIdx++) {
+ HXML itemNode = xmlGetChild(chatNode, nodeIdx);
+ if (!itemNode)
+ break;
+
+ int from;
+ const TCHAR *itemName = xmlGetName(itemNode);
+ if ( !lstrcmp(itemName, _T("to")))
+ from = DBEF_SENT;
+ else if ( !lstrcmp(itemName, _T("from")))
+ from = 0;
+ else
+ continue;
+
+ HXML body = xmlGetChild(itemNode, "body");
+ if (!body)
+ continue;
+
+ const TCHAR *tszBody = xmlGetText(body);
+ const TCHAR *tszSecs = xmlGetAttrValue(itemNode, _T("secs"));
+ if (!tszBody || !tszSecs)
+ continue;
+
+ mir_ptr<char> szEventText( mir_utf8encodeT(tszBody));
+
+ DBEVENTINFO dbei = { sizeof(DBEVENTINFO) };
+ dbei.eventType = EVENTTYPE_MESSAGE;
+ dbei.szModule = m_szModuleName;
+ dbei.cbBlob = (DWORD)strlen(szEventText);
+ dbei.flags = DBEF_READ + DBEF_UTF + from;
+ dbei.pBlob = (PBYTE)(char*)szEventText;
+ dbei.timestamp = tmStart + _ttol(tszSecs) - timezone;
+ if ( !IsDuplicateEvent(hContact, dbei))
+ CallService(MS_DB_EVENT_ADD, (WPARAM)hContact, (LPARAM)&dbei);
+ }
+}
diff --git a/protocols/JabberG/src/jabber_bookmarks.cpp b/protocols/JabberG/src/jabber_bookmarks.cpp index bd8014d42a..79e105b679 100644 --- a/protocols/JabberG/src/jabber_bookmarks.cpp +++ b/protocols/JabberG/src/jabber_bookmarks.cpp @@ -272,7 +272,7 @@ void CJabberDlgBookmarks::UpdateData() int iqId = m_proto->SerialNext();
m_proto->IqAdd(iqId, IQ_PROC_DISCOBOOKMARKS, &CJabberProto::OnIqResultDiscoBookmarks);
- m_proto->m_ThreadInfo->send(XmlNodeIq(_T("get"), iqId) << XQUERY(_T(JABBER_FEAT_PRIVATE_STORAGE))
+ m_proto->m_ThreadInfo->send( XmlNodeIq(_T("get"), iqId) << XQUERY(_T(JABBER_FEAT_PRIVATE_STORAGE))
<< XCHILDNS(_T("storage"), _T("storage:bookmarks")));
}
diff --git a/protocols/JabberG/src/jabber_byte.cpp b/protocols/JabberG/src/jabber_byte.cpp index e9c4a443cd..63160e8985 100644 --- a/protocols/JabberG/src/jabber_byte.cpp +++ b/protocols/JabberG/src/jabber_byte.cpp @@ -444,7 +444,7 @@ void CJabberProto::ByteSendViaProxy(JABBER_BYTE_TRANSFER *jbt) if (jbt == NULL) return;
if ((buffer=(char*)mir_alloc(JABBER_NETWORK_BUFFER_SIZE)) == NULL) {
- m_ThreadInfo->send(XmlNodeIq(_T("error"), jbt->iqId, jbt->srcJID)
+ m_ThreadInfo->send( XmlNodeIq(_T("error"), jbt->iqId, jbt->srcJID)
<< XCHILD(_T("error")) << XATTRI(_T("code"), 406) << XATTR(_T("type"), _T("auth"))
<< XCHILDNS(_T("not-acceptable"), _T("urn:ietf:params:xml:ns:xmpp-stanzas")));
return;
@@ -494,7 +494,7 @@ void CJabberProto::ByteSendViaProxy(JABBER_BYTE_TRANSFER *jbt) (this->*jbt->pfnFinal)((jbt->state == JBT_DONE) ? TRUE : FALSE, jbt->ft);
jbt->ft = NULL;
if ( !validStreamhost)
- m_ThreadInfo->send(XmlNodeIq(_T("error"), jbt->iqId, jbt->srcJID)
+ m_ThreadInfo->send( XmlNodeIq(_T("error"), jbt->iqId, jbt->srcJID)
<< XCHILD(_T("error")) << XATTRI(_T("code"), 404) << XATTR(_T("type"), _T("cancel"))
<< XCHILDNS(_T("item-not-found"), _T("urn:ietf:params:xml:ns:xmpp-stanzas")));
}
@@ -688,7 +688,7 @@ void __cdecl CJabberProto::ByteReceiveThread(JABBER_BYTE_TRANSFER *jbt) if ( !validStreamhost && szId && from) {
Log("bytestream_recv_connection session not completed");
- m_ThreadInfo->send(XmlNodeIq(_T("error"), szId, from)
+ m_ThreadInfo->send( XmlNodeIq(_T("error"), szId, from)
<< XCHILD(_T("error")) << XATTRI(_T("code"), 404) << XATTR(_T("type"), _T("cancel"))
<< XCHILDNS(_T("item-not-found"), _T("urn:ietf:params:xml:ns:xmpp-stanzas")));
}
diff --git a/protocols/JabberG/src/jabber_caps.cpp b/protocols/JabberG/src/jabber_caps.cpp index 8c5f3f484b..55911fd311 100644 --- a/protocols/JabberG/src/jabber_caps.cpp +++ b/protocols/JabberG/src/jabber_caps.cpp @@ -27,49 +27,51 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "version.h"
const JabberFeatCapPair g_JabberFeatCapPairs[] = {
- { _T(JABBER_FEAT_DISCO_INFO), JABBER_CAPS_DISCO_INFO, _T("Supports Service Discovery info"), },
- { _T(JABBER_FEAT_DISCO_ITEMS), JABBER_CAPS_DISCO_ITEMS, _T("Supports Service Discovery items list"), },
- { _T(JABBER_FEAT_ENTITY_CAPS), JABBER_CAPS_ENTITY_CAPS, _T("Can inform about its Jabber capabilities"), },
- { _T(JABBER_FEAT_SI), JABBER_CAPS_SI, _T("Supports stream initiation (for filetransfers for ex.)"), },
- { _T(JABBER_FEAT_SI_FT), JABBER_CAPS_SI_FT, _T("Supports stream initiation for file transfers"), },
- { _T(JABBER_FEAT_BYTESTREAMS), JABBER_CAPS_BYTESTREAMS, _T("Supports file transfers via SOCKS5 Bytestreams"), },
- { _T(JABBER_FEAT_IBB), JABBER_CAPS_IBB, _T("Supports file transfers via In-Band Bytestreams"), },
- { _T(JABBER_FEAT_OOB), JABBER_CAPS_OOB, _T("Supports file transfers via Out-of-Band Bytestreams"), },
- { _T(JABBER_FEAT_OOB2), JABBER_CAPS_OOB, _T("Supports file transfers via Out-of-Band Bytestreams"), },
- { _T(JABBER_FEAT_COMMANDS), JABBER_CAPS_COMMANDS, _T("Supports execution of Ad-Hoc commands"), },
- { _T(JABBER_FEAT_REGISTER), JABBER_CAPS_REGISTER, _T("Supports in-band registration"), },
- { _T(JABBER_FEAT_MUC), JABBER_CAPS_MUC, _T("Supports multi-user chat"), },
- { _T(JABBER_FEAT_CHATSTATES), JABBER_CAPS_CHATSTATES, _T("Can report chat state in a chat session"), },
- { _T(JABBER_FEAT_LAST_ACTIVITY), JABBER_CAPS_LAST_ACTIVITY, _T("Can report information about the last activity of the user"), },
- { _T(JABBER_FEAT_VERSION), JABBER_CAPS_VERSION, _T("Can report own version information"), },
- { _T(JABBER_FEAT_ENTITY_TIME), JABBER_CAPS_ENTITY_TIME, _T("Can report local time of the user"), },
- { _T(JABBER_FEAT_PING), JABBER_CAPS_PING, _T("Can send and receive ping requests"), },
- { _T(JABBER_FEAT_DATA_FORMS), JABBER_CAPS_DATA_FORMS, _T("Supports data forms"), },
- { _T(JABBER_FEAT_MESSAGE_EVENTS), JABBER_CAPS_MESSAGE_EVENTS, _T("Can request and respond to events relating to the delivery, display, and composition of messages"), },
- { _T(JABBER_FEAT_VCARD_TEMP), JABBER_CAPS_VCARD_TEMP, _T("Supports vCard"), },
- { _T(JABBER_FEAT_AVATAR), JABBER_CAPS_AVATAR, _T("Supports iq-based avatars"), },
- { _T(JABBER_FEAT_XHTML), JABBER_CAPS_XHTML, _T("Supports XHTML formatting of chat messages"), },
- { _T(JABBER_FEAT_AGENTS), JABBER_CAPS_AGENTS, _T("Supports Jabber Browsing"), },
- { _T(JABBER_FEAT_BROWSE), JABBER_CAPS_BROWSE, _T("Supports Jabber Browsing"), },
- { _T(JABBER_FEAT_FEATURE_NEG), JABBER_CAPS_FEATURE_NEG, _T("Can negotiate options for specific features"), },
- { _T(JABBER_FEAT_AMP), JABBER_CAPS_AMP, _T("Can request advanced processing of message stanzas"), },
- { _T(JABBER_FEAT_USER_MOOD), JABBER_CAPS_USER_MOOD, _T("Can report information about user moods"), },
- { _T(JABBER_FEAT_USER_MOOD_NOTIFY), JABBER_CAPS_USER_MOOD_NOTIFY, _T("Receives information about user moods"), },
- { _T(JABBER_FEAT_PUBSUB), JABBER_CAPS_PUBSUB, _T("Supports generic publish-subscribe functionality"), },
- { _T(JABBER_FEAT_SECUREIM), JABBER_CAPS_SECUREIM, _T("Supports SecureIM plugin for Miranda NG"), },
- { _T(JABBER_FEAT_PRIVACY_LISTS), JABBER_CAPS_PRIVACY_LISTS, _T("Can block communications from particular other users using Privacy lists"), },
- { _T(JABBER_FEAT_MESSAGE_RECEIPTS), JABBER_CAPS_MESSAGE_RECEIPTS, _T("Supports Message Receipts"), },
- { _T(JABBER_FEAT_USER_TUNE), JABBER_CAPS_USER_TUNE, _T("Can report information about the music to which a user is listening"), },
- { _T(JABBER_FEAT_USER_TUNE_NOTIFY), JABBER_CAPS_USER_TUNE_NOTIFY, _T("Receives information about the music to which a user is listening"), },
- { _T(JABBER_FEAT_PRIVATE_STORAGE), JABBER_CAPS_PRIVATE_STORAGE, _T("Supports private XML Storage (for bookmakrs and other)"), },
- { _T(JABBER_FEAT_ATTENTION), JABBER_CAPS_ATTENTION, _T("Supports attention requests ('nudge')"), },
- { _T(JABBER_FEAT_ATTENTION_0), JABBER_CAPS_ATTENTION_0, _T("Supports attention requests ('nudge')"), },
- { _T(JABBER_FEAT_USER_ACTIVITY), JABBER_CAPS_USER_ACTIVITY, _T("Can report information about user activity"), },
- { _T(JABBER_FEAT_USER_ACTIVITY_NOTIFY), JABBER_CAPS_USER_ACTIVITY_NOTIFY, _T("Receives information about user activity"), },
- { _T(JABBER_FEAT_MIRANDA_NOTES), JABBER_CAPS_MIRANDA_NOTES, _T("Supports Miranda NG notes extension"), },
- { _T(JABBER_FEAT_JINGLE), JABBER_CAPS_JINGLE, _T("Supports Jingle"), },
- { _T(JABBER_FEAT_ROSTER_EXCHANGE), JABBER_CAPS_ROSTER_EXCHANGE, _T("Supports Roster Exchange"), },
- { _T(JABBER_FEAT_GTALK_PMUC), JABBER_CAPS_GTALK_PMUC, _T("Supports GTalk private multi-user chat"), },
+ { _T(JABBER_FEAT_DISCO_INFO), JABBER_CAPS_DISCO_INFO, _T("Supports Service Discovery info") },
+ { _T(JABBER_FEAT_DISCO_ITEMS), JABBER_CAPS_DISCO_ITEMS, _T("Supports Service Discovery items list") },
+ { _T(JABBER_FEAT_ENTITY_CAPS), JABBER_CAPS_ENTITY_CAPS, _T("Can inform about its Jabber capabilities") },
+ { _T(JABBER_FEAT_SI), JABBER_CAPS_SI, _T("Supports stream initiation (for filetransfers for ex.)") },
+ { _T(JABBER_FEAT_SI_FT), JABBER_CAPS_SI_FT, _T("Supports stream initiation for file transfers") },
+ { _T(JABBER_FEAT_BYTESTREAMS), JABBER_CAPS_BYTESTREAMS, _T("Supports file transfers via SOCKS5 Bytestreams") },
+ { _T(JABBER_FEAT_IBB), JABBER_CAPS_IBB, _T("Supports file transfers via In-Band Bytestreams") },
+ { _T(JABBER_FEAT_OOB), JABBER_CAPS_OOB, _T("Supports file transfers via Out-of-Band Bytestreams") },
+ { _T(JABBER_FEAT_OOB2), JABBER_CAPS_OOB, _T("Supports file transfers via Out-of-Band Bytestreams") },
+ { _T(JABBER_FEAT_COMMANDS), JABBER_CAPS_COMMANDS, _T("Supports execution of Ad-Hoc commands") },
+ { _T(JABBER_FEAT_REGISTER), JABBER_CAPS_REGISTER, _T("Supports in-band registration") },
+ { _T(JABBER_FEAT_MUC), JABBER_CAPS_MUC, _T("Supports multi-user chat") },
+ { _T(JABBER_FEAT_CHATSTATES), JABBER_CAPS_CHATSTATES, _T("Can report chat state in a chat session") },
+ { _T(JABBER_FEAT_LAST_ACTIVITY), JABBER_CAPS_LAST_ACTIVITY, _T("Can report information about the last activity of the user") },
+ { _T(JABBER_FEAT_VERSION), JABBER_CAPS_VERSION, _T("Can report own version information") },
+ { _T(JABBER_FEAT_ENTITY_TIME), JABBER_CAPS_ENTITY_TIME, _T("Can report local time of the user") },
+ { _T(JABBER_FEAT_PING), JABBER_CAPS_PING, _T("Can send and receive ping requests") },
+ { _T(JABBER_FEAT_DATA_FORMS), JABBER_CAPS_DATA_FORMS, _T("Supports data forms") },
+ { _T(JABBER_FEAT_MESSAGE_EVENTS), JABBER_CAPS_MESSAGE_EVENTS, _T("Can request and respond to events relating to the delivery, display, and composition of messages") },
+ { _T(JABBER_FEAT_VCARD_TEMP), JABBER_CAPS_VCARD_TEMP, _T("Supports vCard") },
+ { _T(JABBER_FEAT_AVATAR), JABBER_CAPS_AVATAR, _T("Supports iq-based avatars") },
+ { _T(JABBER_FEAT_XHTML), JABBER_CAPS_XHTML, _T("Supports XHTML formatting of chat messages") },
+ { _T(JABBER_FEAT_AGENTS), JABBER_CAPS_AGENTS, _T("Supports Jabber Browsing") },
+ { _T(JABBER_FEAT_BROWSE), JABBER_CAPS_BROWSE, _T("Supports Jabber Browsing") },
+ { _T(JABBER_FEAT_FEATURE_NEG), JABBER_CAPS_FEATURE_NEG, _T("Can negotiate options for specific features") },
+ { _T(JABBER_FEAT_AMP), JABBER_CAPS_AMP, _T("Can request advanced processing of message stanzas") },
+ { _T(JABBER_FEAT_USER_MOOD), JABBER_CAPS_USER_MOOD, _T("Can report information about user moods") },
+ { _T(JABBER_FEAT_USER_MOOD_NOTIFY), JABBER_CAPS_USER_MOOD_NOTIFY, _T("Receives information about user moods") },
+ { _T(JABBER_FEAT_PUBSUB), JABBER_CAPS_PUBSUB, _T("Supports generic publish-subscribe functionality") },
+ { _T(JABBER_FEAT_SECUREIM), JABBER_CAPS_SECUREIM, _T("Supports SecureIM plugin for Miranda NG") },
+ { _T(JABBER_FEAT_PRIVACY_LISTS), JABBER_CAPS_PRIVACY_LISTS, _T("Can block communications from particular other users using Privacy lists") },
+ { _T(JABBER_FEAT_MESSAGE_RECEIPTS), JABBER_CAPS_MESSAGE_RECEIPTS, _T("Supports Message Receipts") },
+ { _T(JABBER_FEAT_USER_TUNE), JABBER_CAPS_USER_TUNE, _T("Can report information about the music to which a user is listening") },
+ { _T(JABBER_FEAT_USER_TUNE_NOTIFY), JABBER_CAPS_USER_TUNE_NOTIFY, _T("Receives information about the music to which a user is listening") },
+ { _T(JABBER_FEAT_PRIVATE_STORAGE), JABBER_CAPS_PRIVATE_STORAGE, _T("Supports private XML Storage (for bookmakrs and other)") },
+ { _T(JABBER_FEAT_ATTENTION), JABBER_CAPS_ATTENTION, _T("Supports attention requests ('nudge')") },
+ { _T(JABBER_FEAT_ATTENTION_0), JABBER_CAPS_ATTENTION_0, _T("Supports attention requests ('nudge')") },
+ { _T(JABBER_FEAT_ARCHIVE_AUTO), JABBER_CAPS_ARCHIVE_AUTO, _T("Supports chat history retrieving") },
+ { _T(JABBER_FEAT_ARCHIVE_MANAGE), JABBER_CAPS_ARCHIVE_MANAGE, _T("Supports chat history management") },
+ { _T(JABBER_FEAT_USER_ACTIVITY), JABBER_CAPS_USER_ACTIVITY, _T("Can report information about user activity") },
+ { _T(JABBER_FEAT_USER_ACTIVITY_NOTIFY), JABBER_CAPS_USER_ACTIVITY_NOTIFY, _T("Receives information about user activity") },
+ { _T(JABBER_FEAT_MIRANDA_NOTES), JABBER_CAPS_MIRANDA_NOTES, _T("Supports Miranda NG notes extension") },
+ { _T(JABBER_FEAT_JINGLE), JABBER_CAPS_JINGLE, _T("Supports Jingle") },
+ { _T(JABBER_FEAT_ROSTER_EXCHANGE), JABBER_CAPS_ROSTER_EXCHANGE, _T("Supports Roster Exchange") },
+ { _T(JABBER_FEAT_GTALK_PMUC), JABBER_CAPS_GTALK_PMUC, _T("Supports GTalk private multi-user chat") },
{ NULL, 0, NULL}
};
@@ -150,12 +152,15 @@ void CJabberProto::OnIqResultCapsDiscoInfo(HXML, CJabberIqInfo* pInfo) HXML feature;
for (int i = 1; (feature = xmlGetNthChild(query, _T("feature"), i)) != NULL; i++) {
const TCHAR *featureName = xmlGetAttrValue(feature, _T("var"));
- if (featureName) {
- for (int j = 0; g_JabberFeatCapPairs[j].szFeature; j++) {
- if ( !_tcscmp(g_JabberFeatCapPairs[j].szFeature, featureName)) {
- jcbCaps |= g_JabberFeatCapPairs[j].jcbCap;
- break;
- } } } }
+ if (!featureName)
+ continue;
+
+ for (int j = 0; g_JabberFeatCapPairs[j].szFeature; j++)
+ if ( !_tcscmp(g_JabberFeatCapPairs[j].szFeature, featureName)) {
+ jcbCaps |= g_JabberFeatCapPairs[j].jcbCap;
+ break;
+ }
+ }
// no version info support and no XEP-0115 support?
if (r && r->dwVersionRequestTime == -1 && !r->version && !r->software && !r->szCapsNode) {
@@ -167,6 +172,7 @@ void CJabberProto::OnIqResultCapsDiscoInfo(HXML, CJabberIqInfo* pInfo) if ( !m_clientCapsManager.SetClientCaps(pInfo->GetIqId(), jcbCaps))
if (r)
r->jcbCachedCaps = jcbCaps;
+
JabberUserInfoUpdate(pInfo->GetHContact());
}
else {
@@ -244,7 +250,7 @@ JabberCapsBits CJabberProto::GetResourceCapabilites(const TCHAR *jid, BOOL appen TCHAR queryNode[512];
mir_sntprintf(queryNode, SIZEOF(queryNode), _T("%s#%s"), r->szCapsNode, r->szCapsVer);
- m_ThreadInfo->send(XmlNodeIq(pInfo) << XQUERY(_T(JABBER_FEAT_DISCO_INFO)) << XATTR(_T("node"), queryNode));
+ m_ThreadInfo->send( XmlNodeIq(pInfo) << XQUERY(_T(JABBER_FEAT_DISCO_INFO)) << XATTR(_T("node"), queryNode));
bRequestSent = TRUE;
}
diff --git a/protocols/JabberG/src/jabber_caps.h b/protocols/JabberG/src/jabber_caps.h index d9597590fe..ac9b1f28ef 100644 --- a/protocols/JabberG/src/jabber_caps.h +++ b/protocols/JabberG/src/jabber_caps.h @@ -114,7 +114,15 @@ typedef unsigned __int64 JabberCapsBits; #define JABBER_CAPS_USER_TUNE_NOTIFY ((JabberCapsBits)1<<32)
#define JABBER_FEAT_PRIVATE_STORAGE "jabber:iq:private"
#define JABBER_CAPS_PRIVATE_STORAGE ((JabberCapsBits)1<<33)
-#define JABBER_FEAT_CAPTCHA "urn:xmpp:captcha"
+
+#define JABBER_FEAT_ARCHIVE "urn:xmpp:archive"
+#define JABBER_FEAT_ARCHIVE_AUTO "urn:xmpp:archive:auto"
+#define JABBER_CAPS_ARCHIVE_AUTO ((JabberCapsBits)1<<34)
+#define JABBER_FEAT_ARCHIVE_MANAGE "urn:xmpp:archive:manage"
+#define JABBER_CAPS_ARCHIVE_MANAGE ((JabberCapsBits)1<<35)
+
+#define JABBER_FEAT_CAPTCHA "urn:xmpp:captcha"
+
// deferred
#define JABBER_FEAT_ATTENTION "http://www.xmpp.org/extensions/xep-0224.html#ns"
#define JABBER_CAPS_ATTENTION ((JabberCapsBits)1<<34)
@@ -270,7 +278,7 @@ struct JabberFeatCapPair {
const TCHAR *szFeature;
JabberCapsBits jcbCap;
- const TCHAR *szDescription;
+ const TCHAR *tszDescription;
};
struct JabberFeatCapPairDynamic
diff --git a/protocols/JabberG/src/jabber_chat.cpp b/protocols/JabberG/src/jabber_chat.cpp index df395a6ab2..94252d1047 100644 --- a/protocols/JabberG/src/jabber_chat.cpp +++ b/protocols/JabberG/src/jabber_chat.cpp @@ -854,18 +854,18 @@ public: void CJabberProto::AdminSet(const TCHAR *to, const TCHAR *ns, const TCHAR *szItem, const TCHAR *itemVal, const TCHAR *var, const TCHAR *varVal)
{
- m_ThreadInfo->send(XmlNodeIq(_T("set"), SerialNext(), to) << XQUERY(ns) << XCHILD(_T("item")) << XATTR(szItem, itemVal) << XATTR(var, varVal));
+ m_ThreadInfo->send( XmlNodeIq(_T("set"), SerialNext(), to) << XQUERY(ns) << XCHILD(_T("item")) << XATTR(szItem, itemVal) << XATTR(var, varVal));
}
void CJabberProto::AdminSetReason(const TCHAR *to, const TCHAR *ns, const TCHAR *szItem, const TCHAR *itemVal, const TCHAR *var, const TCHAR *varVal , const TCHAR *rsn)
-{ m_ThreadInfo->send(XmlNodeIq(_T("set"), SerialNext(), to) << XQUERY(ns) << XCHILD(_T("item")) << XATTR(szItem, itemVal) << XATTR(var, varVal) << XCHILD(_T("reason"), rsn));
+{ m_ThreadInfo->send( XmlNodeIq(_T("set"), SerialNext(), to) << XQUERY(ns) << XCHILD(_T("item")) << XATTR(szItem, itemVal) << XATTR(var, varVal) << XCHILD(_T("reason"), rsn));
}
void CJabberProto::AdminGet(const TCHAR *to, const TCHAR *ns, const TCHAR *var, const TCHAR *varVal, JABBER_IQ_PFUNC foo)
{
int id = SerialNext();
IqAdd(id, IQ_PROC_NONE, foo);
- m_ThreadInfo->send(XmlNodeIq(_T("get"), id, to) << XQUERY(ns) << XCHILD(_T("item")) << XATTR(var, varVal));
+ m_ThreadInfo->send( XmlNodeIq(_T("get"), id, to) << XQUERY(ns) << XCHILD(_T("item")) << XATTR(var, varVal));
}
// Member info dialog
@@ -1548,7 +1548,7 @@ int CJabberProto::JabberGcEventHook(WPARAM, LPARAM lParam) case GC_USER_CHANMGR:
int iqId = SerialNext();
IqAdd(iqId, IQ_PROC_NONE, &CJabberProto::OnIqResultGetMuc);
- m_ThreadInfo->send(XmlNodeIq(_T("get"), iqId, item->jid) << XQUERY(xmlnsOwner));
+ m_ThreadInfo->send( XmlNodeIq(_T("get"), iqId, item->jid) << XQUERY(xmlnsOwner));
break;
}
diff --git a/protocols/JabberG/src/jabber_db_utils.h b/protocols/JabberG/src/jabber_db_utils.h index 60becf5ad9..349416839a 100644 --- a/protocols/JabberG/src/jabber_db_utils.h +++ b/protocols/JabberG/src/jabber_db_utils.h @@ -213,6 +213,7 @@ struct CJabberOptions CMOption<BYTE> UseTLS;
CMOption<BYTE> AcceptNotes;
CMOption<BYTE> AutosaveNotes;
+ CMOption<BYTE> EnableMsgArchive;
CMOption<BYTE> RcMarkMessagesAsRead;
CMOption<DWORD> ConnectionKeepAliveInterval;
CMOption<DWORD> ConnectionKeepAliveTimeout;
@@ -238,6 +239,7 @@ struct CJabberOptions DisableFrame(proto, "DisableFrame", TRUE),
EnableAvatars(proto, "EnableAvatars", TRUE),
EnableRemoteControl(proto, "EnableRemoteControl", FALSE),
+ EnableMsgArchive(proto, "EnableMsgArchive", FALSE),
EnableUserActivity(proto, "EnableUserActivity", TRUE),
EnableUserMood(proto, "EnableUserMood", TRUE),
EnableUserTune(proto, "EnableUserTune", FALSE),
diff --git a/protocols/JabberG/src/jabber_disco.cpp b/protocols/JabberG/src/jabber_disco.cpp index b6322ea0c6..e65d1c512e 100644 --- a/protocols/JabberG/src/jabber_disco.cpp +++ b/protocols/JabberG/src/jabber_disco.cpp @@ -1473,9 +1473,9 @@ void CJabberProto::ServiceDiscoveryShowMenu(CJabberSDNode *pNode, HTREELISTITEM break;
case SD_ACT_UNREGISTER:
- m_ThreadInfo->send(XmlNodeIq(_T("set"), SerialNext(), pNode->GetJid()) << XQUERY(_T(JABBER_FEAT_REGISTER)) << XCHILD(_T("remove")));
+ m_ThreadInfo->send( XmlNodeIq(_T("set"), SerialNext(), pNode->GetJid()) << XQUERY(_T(JABBER_FEAT_REGISTER)) << XCHILD(_T("remove")));
- m_ThreadInfo->send(XmlNodeIq(_T("set"), SerialNext()) << XQUERY(_T(JABBER_FEAT_IQ_ROSTER))
+ m_ThreadInfo->send( XmlNodeIq(_T("set"), SerialNext()) << XQUERY(_T(JABBER_FEAT_IQ_ROSTER))
<< XCHILD(_T("item")) << XATTR(_T("jid"), pNode->GetJid()) << XATTR(_T("subscription"), _T("remove")));
break;
diff --git a/protocols/JabberG/src/jabber_events.cpp b/protocols/JabberG/src/jabber_events.cpp index 4af605937f..2562e0c5f0 100644 --- a/protocols/JabberG/src/jabber_events.cpp +++ b/protocols/JabberG/src/jabber_events.cpp @@ -52,11 +52,11 @@ int CJabberProto::OnContactDeleted(WPARAM wParam, LPARAM) JabberStripJid(m_ThreadInfo->fullJID, szStrippedJid, SIZEOF(szStrippedJid));
TCHAR *szDog = _tcschr(szStrippedJid, _T('@'));
if (szDog && _tcsicmp(szDog + 1, dbv.ptszVal))
- m_ThreadInfo->send(XmlNodeIq(_T("set"), SerialNext(), dbv.ptszVal) << XQUERY(_T(JABBER_FEAT_REGISTER)) << XCHILD(_T("remove")));
+ m_ThreadInfo->send( XmlNodeIq(_T("set"), SerialNext(), dbv.ptszVal) << XQUERY(_T(JABBER_FEAT_REGISTER)) << XCHILD(_T("remove")));
}
// Remove from roster, server also handles the presence unsubscription process.
- m_ThreadInfo->send(XmlNodeIq(_T("set"), SerialNext()) << XQUERY(_T(JABBER_FEAT_IQ_ROSTER))
+ m_ThreadInfo->send( XmlNodeIq(_T("set"), SerialNext()) << XQUERY(_T(JABBER_FEAT_IQ_ROSTER))
<< XCHILD(_T("item")) << XATTR(_T("jid"), dbv.ptszVal) << XATTR(_T("subscription"), _T("remove")));
}
diff --git a/protocols/JabberG/src/jabber_ft.cpp b/protocols/JabberG/src/jabber_ft.cpp index 240e6d4bef..b9a354713a 100644 --- a/protocols/JabberG/src/jabber_ft.cpp +++ b/protocols/JabberG/src/jabber_ft.cpp @@ -491,7 +491,7 @@ BOOL CJabberProto::FtHandleIbbRequest(HXML iqNode, BOOL bOpen) item->jibb = jibb;
JForkThread((JThreadFunc)&CJabberProto::IbbReceiveThread, jibb);
- m_ThreadInfo->send(XmlNodeIq(_T("result"), id, from));
+ m_ThreadInfo->send( XmlNodeIq(_T("result"), id, from));
return TRUE;
}
// stream already open
@@ -507,7 +507,7 @@ BOOL CJabberProto::FtHandleIbbRequest(HXML iqNode, BOOL bOpen) item->jibb->bStreamClosed = TRUE;
SetEvent(item->jibb->hEvent);
- m_ThreadInfo->send(XmlNodeIq(_T("result"), id, from));
+ m_ThreadInfo->send( XmlNodeIq(_T("result"), id, from));
return TRUE;
}
diff --git a/protocols/JabberG/src/jabber_groupchat.cpp b/protocols/JabberG/src/jabber_groupchat.cpp index 407fe2f433..e80628ec8f 100644 --- a/protocols/JabberG/src/jabber_groupchat.cpp +++ b/protocols/JabberG/src/jabber_groupchat.cpp @@ -323,11 +323,9 @@ void CJabberProto::GroupchatJoinRoom(const TCHAR *server, const TCHAR *room, con if (lasteventtime > 0) {
_tzset();
lasteventtime += _timezone + 1;
- struct tm* time = localtime(&lasteventtime);
+
TCHAR lasteventdate[20 + 1];
- mir_sntprintf(lasteventdate, SIZEOF(lasteventdate), _T("%04d-%02d-%02dT%02d:%02d:%02dZ"),
- time->tm_year+1900, time->tm_mon+1, time->tm_mday, time->tm_hour, time->tm_min, time->tm_sec);
- x << XCHILD(_T("history")) << XATTR(_T("since"), lasteventdate);
+ x << XCHILD(_T("history")) << XATTR(_T("since"), time2str(lasteventtime, lasteventdate, SIZEOF(lasteventdate)));
}
}
@@ -1088,7 +1086,7 @@ void CJabberProto::GroupchatProcessPresence(HXML node) // Request room config
int iqId = SerialNext();
IqAdd(iqId, IQ_PROC_NONE, &CJabberProto::OnIqResultGetMuc);
- m_ThreadInfo->send(XmlNodeIq(_T("get"), iqId, item->jid) << XQUERY(xmlnsOwner));
+ m_ThreadInfo->send( XmlNodeIq(_T("get"), iqId, item->jid) << XQUERY(xmlnsOwner));
}
mir_free(room);
diff --git a/protocols/JabberG/src/jabber_ibb.cpp b/protocols/JabberG/src/jabber_ibb.cpp index 53137d50fc..dc66ce2196 100644 --- a/protocols/JabberG/src/jabber_ibb.cpp +++ b/protocols/JabberG/src/jabber_ibb.cpp @@ -56,7 +56,7 @@ BOOL CJabberProto::OnFtHandleIbbIq(HXML iqNode, CJabberIqInfo* pInfo) bOk = OnIbbRecvdData(xmlGetText(pInfo->GetChildNode()), sid, seq);
if (bOk)
- m_ThreadInfo->send(XmlNodeIq(_T("result"), pInfo));
+ m_ThreadInfo->send( XmlNodeIq(_T("result"), pInfo));
else
m_ThreadInfo->send(
XmlNodeIq(_T("error"), pInfo)
@@ -151,7 +151,7 @@ void __cdecl CJabberProto::IbbReceiveThread(JABBER_IBB_TRANSFER *jibb) jibb->hEvent = NULL;
if (jibb->state == JIBB_ERROR)
- m_ThreadInfo->send(XmlNodeIq(_T("set"), SerialNext(), jibb->dstJID) << XCHILDNS(_T("close"), _T(JABBER_FEAT_IBB)) << XATTR(_T("sid"), jibb->sid));
+ m_ThreadInfo->send( XmlNodeIq(_T("set"), SerialNext(), jibb->dstJID) << XCHILDNS(_T("close"), _T(JABBER_FEAT_IBB)) << XATTR(_T("sid"), jibb->sid));
if (jibb->bStreamClosed && jibb->dwTransferredSize == ft->dwExpectedRecvFileSize)
jibb->state = JIBB_DONE;
diff --git a/protocols/JabberG/src/jabber_iq_handlers.cpp b/protocols/JabberG/src/jabber_iq_handlers.cpp index ecf0064d61..da82862354 100644 --- a/protocols/JabberG/src/jabber_iq_handlers.cpp +++ b/protocols/JabberG/src/jabber_iq_handlers.cpp @@ -391,7 +391,7 @@ BOOL CJabberProto::OnIqRequestLastActivity(HXML, CJabberIqInfo *pInfo) // XEP-0199: XMPP Ping support
BOOL CJabberProto::OnIqRequestPing(HXML, CJabberIqInfo *pInfo)
{
- m_ThreadInfo->send(XmlNodeIq(_T("result"), pInfo) << XATTR(_T("from"), m_ThreadInfo->fullJID));
+ m_ThreadInfo->send( XmlNodeIq(_T("result"), pInfo) << XATTR(_T("from"), m_ThreadInfo->fullJID));
return TRUE;
}
@@ -505,7 +505,7 @@ BOOL CJabberProto::OnIqRequestAvatar(HXML, CJabberIqInfo *pInfo) fclose(in);
char* str = JabberBase64Encode(buffer, bytes);
- m_ThreadInfo->send(XmlNodeIq(_T("result"), pInfo) << XQUERY(_T(JABBER_FEAT_AVATAR)) << XCHILD(_T("query"), _A2T(str)) << XATTR(_T("mimetype"), szMimeType));
+ m_ThreadInfo->send( XmlNodeIq(_T("result"), pInfo) << XQUERY(_T(JABBER_FEAT_AVATAR)) << XCHILD(_T("query"), _A2T(str)) << XATTR(_T("mimetype"), szMimeType));
mir_free(str);
mir_free(buffer);
return TRUE;
diff --git a/protocols/JabberG/src/jabber_iqid.cpp b/protocols/JabberG/src/jabber_iqid.cpp index 664167b73f..74f8333634 100644 --- a/protocols/JabberG/src/jabber_iqid.cpp +++ b/protocols/JabberG/src/jabber_iqid.cpp @@ -67,16 +67,21 @@ void CJabberProto::OnIqResultServerDiscoInfo(HXML iqNode) << XQUERY(_T(JABBER_FEAT_GTALK_SHARED_STATUS)) << XATTR(_T("version"), _T("2")));
}
}
+
if (m_ThreadInfo) {
HXML feature;
for (i = 1; (feature = xmlGetNthChild(query, _T("feature"), i)) != NULL; i++) {
const TCHAR *featureName = xmlGetAttrValue(feature, _T("var"));
- if (featureName) {
- for (int j = 0; g_JabberFeatCapPairs[j].szFeature; j++) {
- if ( !_tcscmp(g_JabberFeatCapPairs[j].szFeature, featureName)) {
- m_ThreadInfo->jabberServerCaps |= g_JabberFeatCapPairs[j].jcbCap;
- break;
- } } } } }
+ if (!featureName)
+ continue;
+
+ for (int j = 0; g_JabberFeatCapPairs[j].szFeature; j++)
+ if ( !_tcscmp(g_JabberFeatCapPairs[j].szFeature, featureName)) {
+ m_ThreadInfo->jabberServerCaps |= g_JabberFeatCapPairs[j].jcbCap;
+ break;
+ }
+ }
+ }
OnProcessLoginRq(m_ThreadInfo, JABBER_LOGIN_SERVERINFO);
} }
@@ -126,9 +131,11 @@ void CJabberProto::OnProcessLoginRq(ThreadData* info, DWORD rq) info->dwLoginRqs |= rq;
- if ((info->dwLoginRqs & JABBER_LOGIN_ROSTER) && (info->dwLoginRqs & JABBER_LOGIN_BOOKMARKS) &&
- (info->dwLoginRqs & JABBER_LOGIN_SERVERINFO) && !(info->dwLoginRqs & JABBER_LOGIN_BOOKMARKS_AJ))
- {
+ DWORD dwMask = JABBER_LOGIN_ROSTER | JABBER_LOGIN_BOOKMARKS | JABBER_LOGIN_SERVERINFO;
+ if ((info->dwLoginRqs & dwMask) == dwMask && !(info->dwLoginRqs & JABBER_LOGIN_BOOKMARKS_AJ)) {
+ if (info->jabberServerCaps & JABBER_CAPS_ARCHIVE_AUTO)
+ EnableArchive(m_options.EnableMsgArchive != 0);
+
if (jabberChatDllPresent && m_options.AutoJoinBookmarks) {
LIST<JABBER_LIST_ITEM> ll(10);
LISTFOREACH(i, this, LIST_BOOKMARK)
@@ -153,7 +160,8 @@ void CJabberProto::OnProcessLoginRq(ThreadData* info, DWORD rq) TCHAR* nick = JabberNickFromJID(m_szJabberJID);
GroupchatJoinRoom(server, p, nick, item->password, true);
mir_free(nick);
- } }
+ }
+ }
ll.destroy();
}
@@ -196,7 +204,7 @@ void CJabberProto::OnLoggedIn() m_ThreadInfo->jabberServerCaps = JABBER_RESOURCE_CAPS_NONE;
iqId = SerialNext();
IqAdd(iqId, IQ_PROC_NONE, &CJabberProto::OnIqResultServerDiscoInfo);
- m_ThreadInfo->send(XmlNodeIq(_T("get"), iqId, _A2T(m_ThreadInfo->server)) << XQUERY(_T(JABBER_FEAT_DISCO_INFO)));
+ m_ThreadInfo->send( XmlNodeIq(_T("get"), iqId, _A2T(m_ThreadInfo->server)) << XQUERY(_T(JABBER_FEAT_DISCO_INFO)));
QueryPrivacyLists(m_ThreadInfo);
diff --git a/protocols/JabberG/src/jabber_list.cpp b/protocols/JabberG/src/jabber_list.cpp index 28608e5121..25f69bebed 100644 --- a/protocols/JabberG/src/jabber_list.cpp +++ b/protocols/JabberG/src/jabber_list.cpp @@ -151,8 +151,8 @@ JABBER_LIST_ITEM *CJabberProto::ListAdd(JABBER_LIST list, const TCHAR *jid) bUseResource=TRUE;
}
}
- item = (JABBER_LIST_ITEM*)mir_alloc(sizeof(JABBER_LIST_ITEM));
- ZeroMemory(item, sizeof(JABBER_LIST_ITEM));
+
+ item = (JABBER_LIST_ITEM*)mir_calloc(sizeof(JABBER_LIST_ITEM));
item->list = list;
item->jid = s;
item->itemResource.status = ID_STATUS_OFFLINE;
diff --git a/protocols/JabberG/src/jabber_list.h b/protocols/JabberG/src/jabber_list.h index 24beee26c7..7c7d3d2014 100644 --- a/protocols/JabberG/src/jabber_list.h +++ b/protocols/JabberG/src/jabber_list.h @@ -183,6 +183,7 @@ struct JABBER_LIST_ITEM BOOL bAutoJoin;
BOOL bUseResource;
+ BOOL bHistoryRead;
};
struct JABBER_HTTP_AVATARS
diff --git a/protocols/JabberG/src/jabber_menu.cpp b/protocols/JabberG/src/jabber_menu.cpp index 95c0ee8b36..0ee785ef41 100644 --- a/protocols/JabberG/src/jabber_menu.cpp +++ b/protocols/JabberG/src/jabber_menu.cpp @@ -1085,6 +1085,10 @@ int CJabberProto::OnProcessSrmmEvent(WPARAM, LPARAM lParam) if ( !hDialogsList)
hDialogsList = (HANDLE)CallService(MS_UTILS_ALLOCWINDOWLIST, 0, 0);
WindowList_Add(hDialogsList, event->hwndWindow, event->hContact);
+
+ JABBER_LIST_ITEM *pItem = GetItemFromContact(event->hContact);
+ if (pItem && (m_ThreadInfo->jabberServerCaps & JABBER_CAPS_ARCHIVE_AUTO) && m_options.EnableMsgArchive)
+ RetrieveMessageArchive(event->hContact, pItem);
}
else if (event->uType == MSG_WINDOW_EVT_CLOSING) {
if (hDialogsList)
@@ -1110,12 +1114,11 @@ int CJabberProto::OnProcessSrmmEvent(WPARAM, LPARAM lParam) r->bMessageSessionActive = FALSE;
JabberCapsBits jcb = GetResourceCapabilites(jid, TRUE);
- if (jcb & JABBER_CAPS_CHATSTATES) {
- int iqId = SerialNext();
+ if (jcb & JABBER_CAPS_CHATSTATES)
m_ThreadInfo->send(
- XmlNode(_T("message")) << XATTR(_T("to"), jid) << XATTR(_T("type"), _T("chat")) << XATTRID(iqId)
+ XmlNode(_T("message")) << XATTR(_T("to"), jid) << XATTR(_T("type"), _T("chat")) << XATTRID( SerialNext())
<< XCHILDNS(_T("gone"), _T(JABBER_FEAT_CHATSTATES)));
- } } } }
+ } } }
return 0;
}
diff --git a/protocols/JabberG/src/jabber_opt.cpp b/protocols/JabberG/src/jabber_opt.cpp index cdf57f3f91..d86da765e8 100644 --- a/protocols/JabberG/src/jabber_opt.cpp +++ b/protocols/JabberG/src/jabber_opt.cpp @@ -836,6 +836,7 @@ public: m_otvOptions.AddOption(LPGENT("Messaging") _T("/") LPGENT("Enable user activity receiving"), m_proto->m_options.EnableUserActivity);
m_otvOptions.AddOption(LPGENT("Messaging") _T("/") LPGENT("Receive notes"), m_proto->m_options.AcceptNotes);
m_otvOptions.AddOption(LPGENT("Messaging") _T("/") LPGENT("Automatically save received notes"), m_proto->m_options.AutosaveNotes);
+ m_otvOptions.AddOption(LPGENT("Messaging") _T("/") LPGENT("Enable server-side history"), m_proto->m_options.EnableMsgArchive);
m_otvOptions.AddOption(LPGENT("Server options") _T("/") LPGENT("Disable SASL authentication (for old servers)"), m_proto->m_options.Disable3920auth);
m_otvOptions.AddOption(LPGENT("Server options") _T("/") LPGENT("Enable stream compression (if possible)"), m_proto->m_options.EnableZlib);
diff --git a/protocols/JabberG/src/jabber_privacy.cpp b/protocols/JabberG/src/jabber_privacy.cpp index c2ec58912e..6865acb1bf 100644 --- a/protocols/JabberG/src/jabber_privacy.cpp +++ b/protocols/JabberG/src/jabber_privacy.cpp @@ -279,7 +279,7 @@ void CJabberProto::OnIqResultPrivacyLists(HXML iqNode, CJabberIqInfo* pInfo) if (m_pDlgPrivacyLists) {
int iqId = SerialNext();
IqAdd(iqId, IQ_PROC_NONE, &CJabberProto::OnIqResultPrivacyList);
- m_ThreadInfo->send(XmlNodeIq(_T("get"), iqId) << XQUERY(_T(JABBER_FEAT_PRIVACY_LISTS)) << XCHILD(_T("list")) << XATTR(_T("name"), listName));
+ m_ThreadInfo->send( XmlNodeIq(_T("get"), iqId) << XQUERY(_T(JABBER_FEAT_PRIVACY_LISTS)) << XCHILD(_T("list")) << XATTR(_T("name"), listName));
} } }
const TCHAR *szName = NULL;
diff --git a/protocols/JabberG/src/jabber_proto.cpp b/protocols/JabberG/src/jabber_proto.cpp index 68d8d7bd8e..5d110f17e8 100644 --- a/protocols/JabberG/src/jabber_proto.cpp +++ b/protocols/JabberG/src/jabber_proto.cpp @@ -636,7 +636,7 @@ int __cdecl CJabberProto::FileDeny(HANDLE, HANDLE hTransfer, const TCHAR *) switch (ft->type) {
case FT_OOB:
- m_ThreadInfo->send(XmlNodeIq(_T("error"), ft->iqId, ft->jid) << XCHILD(_T("error"), _T("File transfer refused")) << XATTRI(_T("code"), 406));
+ m_ThreadInfo->send( XmlNodeIq(_T("error"), ft->iqId, ft->jid) << XCHILD(_T("error"), _T("File transfer refused")) << XATTRI(_T("code"), 406));
break;
case FT_BYTESTREAM:
@@ -900,7 +900,7 @@ HANDLE __cdecl CJabberProto::SearchByEmail(const TCHAR *email) int iqId = SerialNext();
IqAdd(iqId, IQ_PROC_GETSEARCH, &CJabberProto::OnIqResultSetSearch);
- m_ThreadInfo->send(XmlNodeIq(_T("set"), iqId, _A2T(szServerName)) << XQUERY(_T("jabber:iq:search"))
+ m_ThreadInfo->send( XmlNodeIq(_T("set"), iqId, _A2T(szServerName)) << XQUERY(_T("jabber:iq:search"))
<< XCHILD(_T("email"), email));
return (HANDLE)iqId;
}
diff --git a/protocols/JabberG/src/jabber_proto.h b/protocols/JabberG/src/jabber_proto.h index 96fd2665c4..7b0970ef86 100644 --- a/protocols/JabberG/src/jabber_proto.h +++ b/protocols/JabberG/src/jabber_proto.h @@ -397,6 +397,14 @@ struct CJabberProto : public PROTO_INTERFACE, public MZeroedObject void ContactMenuAdhocCommands(struct CJabberAdhocStartupParams* param);
+ //---- jabber_archive.c --------------------------------------------------------------
+
+ void EnableArchive(bool bEnable);
+ void RetrieveMessageArchive(HANDLE hContact, JABBER_LIST_ITEM *pItem);
+
+ void OnIqResultGetCollection(HXML iqNode);
+ void OnIqResultGetCollectionList(HXML iqNode);
+
//---- jabber_bookmarks.c ------------------------------------------------------------
INT_PTR __cdecl OnMenuHandleBookmarks(WPARAM wParam, LPARAM lParam);
@@ -893,6 +901,7 @@ struct CJabberProto : public PROTO_INTERFACE, public MZeroedObject //---- jabber_util.c -----------------------------------------------------------------
+ JABBER_LIST_ITEM* GetItemFromContact(HANDLE hContact);
JABBER_RESOURCE_STATUS* ResourceInfoFromJID(const TCHAR *jid);
void SerialInit(void);
diff --git a/protocols/JabberG/src/jabber_search.cpp b/protocols/JabberG/src/jabber_search.cpp index 87557a4fef..4e65cda1a2 100644 --- a/protocols/JabberG/src/jabber_search.cpp +++ b/protocols/JabberG/src/jabber_search.cpp @@ -467,7 +467,7 @@ int CJabberProto::SearchRenewFields(HWND hwndDlg, JabberSearchData * dat) int iqId = SerialNext();
IqAdd(iqId, IQ_PROC_GETSEARCHFIELDS, &CJabberProto::OnIqResultGetSearchFields);
- m_ThreadInfo->send(XmlNodeIq(_T("get"), iqId, szServerName) << XQUERY(_T("jabber:iq:search")));
+ m_ThreadInfo->send( XmlNodeIq(_T("get"), iqId, szServerName) << XQUERY(_T("jabber:iq:search")));
return iqId;
}
diff --git a/protocols/JabberG/src/jabber_thread.cpp b/protocols/JabberG/src/jabber_thread.cpp index b116a87ca6..213de6f0a6 100644 --- a/protocols/JabberG/src/jabber_thread.cpp +++ b/protocols/JabberG/src/jabber_thread.cpp @@ -478,7 +478,7 @@ LBL_FatalError: if (m_ThreadInfo->jabberServerCaps & JABBER_CAPS_PING) {
CJabberIqInfo* pInfo = m_iqManager.AddHandler(&CJabberProto::OnPingReply, JABBER_IQ_TYPE_GET, NULL, 0, -1, this);
pInfo->SetTimeout(m_options.ConnectionKeepAliveTimeout);
- info->send(XmlNodeIq(pInfo) << XATTR(_T("from"), m_ThreadInfo->fullJID) << XCHILDNS(_T("ping"), _T(JABBER_FEAT_PING)));
+ info->send( XmlNodeIq(pInfo) << XATTR(_T("from"), m_ThreadInfo->fullJID) << XCHILDNS(_T("ping"), _T(JABBER_FEAT_PING)));
}
else info->send(" \t ");
continue;
@@ -627,7 +627,7 @@ recvRest: void CJabberProto::PerformRegistration(ThreadData* info)
{
iqIdRegGetReg = SerialNext();
- info->send(XmlNodeIq(_T("get"), iqIdRegGetReg, NULL) << XQUERY(_T(JABBER_FEAT_REGISTER)));
+ info->send( XmlNodeIq(_T("get"), iqIdRegGetReg, NULL) << XQUERY(_T(JABBER_FEAT_REGISTER)));
SendMessage(info->reg_hwndDlg, WM_JABBER_REGDLG_UPDATE, 50, (LPARAM)TranslateT("Requesting registration instruction..."));
}
@@ -637,7 +637,7 @@ void CJabberProto::PerformIqAuth(ThreadData* info) if (info->type == JABBER_SESSION_NORMAL) {
int iqId = SerialNext();
IqAdd(iqId, IQ_PROC_NONE, &CJabberProto::OnIqResultGetAuth);
- info->send(XmlNodeIq(_T("get"), iqId) << XQUERY(_T("jabber:iq:auth")) << XCHILD(_T("username"), info->username));
+ info->send( XmlNodeIq(_T("get"), iqId) << XQUERY(_T("jabber:iq:auth")) << XCHILD(_T("username"), info->username));
}
else if (info->type == JABBER_SESSION_REGISTER)
PerformRegistration(info);
@@ -1886,7 +1886,7 @@ BOOL CJabberProto::OnProcessJingle(HXML node) LPCTSTR from = xmlGetAttrValue(node, _T("from"));
if (szAction && !_tcscmp(szAction, _T("session-initiate"))) {
// if this is a Jingle 'session-initiate' and noone processed it yet, reply with "unsupported-applications"
- m_ThreadInfo->send(XmlNodeIq(_T("result"), idStr, from));
+ m_ThreadInfo->send( XmlNodeIq(_T("result"), idStr, from));
XmlNodeIq iq(_T("set"), SerialNext(), from);
HXML jingleNode = iq << XCHILDNS(_T("jingle"), _T(JABBER_FEAT_JINGLE));
diff --git a/protocols/JabberG/src/jabber_userinfo.cpp b/protocols/JabberG/src/jabber_userinfo.cpp index 0cad014101..09aa3094b6 100644 --- a/protocols/JabberG/src/jabber_userinfo.cpp +++ b/protocols/JabberG/src/jabber_userinfo.cpp @@ -276,8 +276,8 @@ static void sttFillResourceInfo(CJabberProto* ppro, HWND hwndTree, HTREEITEM hti for (i = 0; g_JabberFeatCapPairs[i].szFeature; i++)
if (jcb & g_JabberFeatCapPairs[i].jcbCap) {
TCHAR szDescription[ 1024 ];
- if (g_JabberFeatCapPairs[i].szDescription)
- mir_sntprintf(szDescription, SIZEOF(szDescription), _T("%s (%s)"), TranslateTS(g_JabberFeatCapPairs[i].szDescription), g_JabberFeatCapPairs[i].szFeature);
+ if (g_JabberFeatCapPairs[i].tszDescription)
+ mir_sntprintf(szDescription, SIZEOF(szDescription), _T("%s (%s)"), TranslateTS(g_JabberFeatCapPairs[i].tszDescription), g_JabberFeatCapPairs[i].szFeature);
else
mir_sntprintf(szDescription, SIZEOF(szDescription), _T("%s"), g_JabberFeatCapPairs[i].szFeature);
sttFillInfoLine(hwndTree, htiCaps, NULL, NULL, szDescription, sttInfoLineId(resource, INFOLINE_CAPS, i));
diff --git a/protocols/JabberG/src/jabber_util.cpp b/protocols/JabberG/src/jabber_util.cpp index 3c9dbc4b71..924270fc27 100644 --- a/protocols/JabberG/src/jabber_util.cpp +++ b/protocols/JabberG/src/jabber_util.cpp @@ -197,6 +197,17 @@ JABBER_RESOURCE_STATUS* CJabberProto::ResourceInfoFromJID(const TCHAR *jid) return r;
}
+JABBER_LIST_ITEM* CJabberProto::GetItemFromContact(HANDLE hContact)
+{
+ DBVARIANT dbv;
+ if (JGetStringT(hContact, "jid", &dbv))
+ return NULL;
+
+ JABBER_LIST_ITEM *pItem = ListGetItemPtr(LIST_ROSTER, dbv.ptszVal);
+ db_free(&dbv);
+ return pItem;
+}
+
TCHAR* JabberPrepareJid(LPCTSTR jid)
{
if ( !jid) return NULL;
@@ -1254,6 +1265,31 @@ void CJabberProto::RebuildInfoFrame() }
////////////////////////////////////////////////////////////////////////
+// time2str & str2time
+
+TCHAR* time2str(time_t _time, TCHAR *buf, size_t bufLen)
+{
+ struct tm* T = localtime(&_time);
+ mir_sntprintf(buf, bufLen, _T("%04d-%02d-%02dT%02d:%02d:%02dZ"),
+ T->tm_year+1900, T->tm_mon+1, T->tm_mday, T->tm_hour, T->tm_min, T->tm_sec);
+ return buf;
+}
+
+time_t str2time(const TCHAR *buf)
+{
+ struct tm T = { 0 };
+ if ( _stscanf(buf, _T("%04d-%02d-%02dT%02d:%02d:%02dZ"), &T.tm_year, &T.tm_mon, &T.tm_mday, &T.tm_hour, &T.tm_min, &T.tm_sec) != 6) {
+ int boo;
+ if ( _stscanf(buf, _T("%04d-%02d-%02dT%02d:%02d:%02d.%dZ"), &T.tm_year, &T.tm_mon, &T.tm_mday, &T.tm_hour, &T.tm_min, &T.tm_sec, &boo) != 7)
+ return 0;
+ }
+
+ T.tm_year -= 1900;
+ T.tm_mon--;
+ return mktime(&T);
+}
+
+////////////////////////////////////////////////////////////////////////
// case-insensitive _tcsstr
const TCHAR *JabberStrIStr(const TCHAR *str, const TCHAR *substr)
{
|