summaryrefslogtreecommitdiff
path: root/protocols/IcqOscarJ/src/icq_xtraz.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'protocols/IcqOscarJ/src/icq_xtraz.cpp')
-rw-r--r--protocols/IcqOscarJ/src/icq_xtraz.cpp466
1 files changed, 466 insertions, 0 deletions
diff --git a/protocols/IcqOscarJ/src/icq_xtraz.cpp b/protocols/IcqOscarJ/src/icq_xtraz.cpp
new file mode 100644
index 0000000000..2b73274365
--- /dev/null
+++ b/protocols/IcqOscarJ/src/icq_xtraz.cpp
@@ -0,0 +1,466 @@
+// ---------------------------------------------------------------------------80
+// ICQ plugin for Miranda Instant Messenger
+// ________________________________________
+//
+// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede
+// Copyright © 2001-2002 Jon Keating, Richard Hughes
+// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater
+// Copyright © 2004-2010 Joe Kucera
+//
+// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// -----------------------------------------------------------------------------
+// DESCRIPTION:
+//
+// Internal Xtraz API
+//
+// -----------------------------------------------------------------------------
+#include "icqoscar.h"
+
+
+void CIcqProto::handleXtrazNotify(DWORD dwUin, DWORD dwMID, DWORD dwMID2, WORD wCookie, char* szMsg, int nMsgLen, BOOL bThruDC)
+{
+ char *szNotify = strstrnull(szMsg, "<NOTIFY>");
+ char *szQuery = strstrnull(szMsg, "<QUERY>");
+
+ HANDLE hContact = HContactFromUIN(dwUin, NULL);
+ if (hContact) // user sent us xtraz, he supports it
+ SetContactCapabilities(hContact, CAPF_XTRAZ);
+
+ if (szNotify && szQuery)
+ { // valid request
+ char *szWork, *szEnd;
+ int nNotifyLen, nQueryLen;
+
+ szNotify += 8;
+ szQuery += 7;
+ szEnd = strstrnull(szMsg, "</NOTIFY>");
+ if (!szEnd) szEnd = szMsg + nMsgLen;
+ nNotifyLen = (szEnd - szNotify);
+ szEnd = strstrnull(szMsg, "</QUERY>");
+ if (!szEnd) szEnd = szNotify;
+ szNotify = DemangleXml(szNotify, nNotifyLen);
+ nQueryLen = (szEnd - szQuery);
+ szQuery = DemangleXml(szQuery, nQueryLen);
+ szWork = strstrnull(szQuery, "<PluginID>");
+ szEnd = strstrnull(szQuery, "</PluginID>");
+#ifdef _DEBUG
+ NetLog_Server("Query: %s", szQuery);
+ NetLog_Server("Notify: %s", szNotify);
+#endif
+ if (szWork && szEnd)
+ { // this is our plugin
+ szWork += 10;
+ *szEnd = '\0';
+
+ if (!stricmpnull(szWork, "srvMng") && strstrnull(szNotify, "AwayStat"))
+ {
+ char *szSender = strstrnull(szNotify, "<senderId>");
+ char *szEndSend = strstrnull(szNotify, "</senderId>");
+
+ if (szSender && szEndSend)
+ {
+ szSender += 10;
+ *szEndSend = '\0';
+
+ if ((DWORD)atoi(szSender) == dwUin)
+ {
+ BYTE dwXId = m_bXStatusEnabled ? getContactXStatus(NULL) : 0;
+
+ if (dwXId && validateStatusMessageRequest(hContact, MTYPE_SCRIPT_NOTIFY))
+ { // apply privacy rules
+ NotifyEventHooks(m_modeMsgsEvent, (WPARAM)MTYPE_SCRIPT_NOTIFY, (LPARAM)dwUin);
+
+ char *tmp = getSettingStringUtf(NULL, DBSETTING_XSTATUS_NAME, "");
+ char *szXName = MangleXml(tmp, strlennull(tmp));
+ SAFE_FREE(&tmp);
+
+ tmp = getSettingStringUtf(NULL, DBSETTING_XSTATUS_MSG, "");
+ char *szXMsg = MangleXml(tmp, strlennull(tmp));
+ SAFE_FREE(&tmp);
+
+ int nResponseLen = 212 + strlennull(szXName) + strlennull(szXMsg) + UINMAXLEN + 2;
+ char *szResponse = (char*)_alloca(nResponseLen + 1);
+ // send response
+ null_snprintf(szResponse, nResponseLen,
+ "<ret event=\"OnRemoteNotification\">"
+ "<srv><id>cAwaySrv</id>"
+ "<val srv_id=\"cAwaySrv\"><Root>"
+ "<CASXtraSetAwayMessage></CASXtraSetAwayMessage>"
+ "<uin>%d</uin>"
+ "<index>%d</index>"
+ "<title>%s</title>"
+ "<desc>%s</desc></Root></val></srv></ret>",
+ m_dwLocalUIN, dwXId, szXName, szXMsg);
+
+ SAFE_FREE(&szXName);
+ SAFE_FREE(&szXMsg);
+
+ struct rates_xstatus_response: public rates_queue_item {
+ protected:
+ virtual rates_queue_item* copyItem(rates_queue_item *aDest = NULL) {
+ rates_xstatus_response *pDest = (rates_xstatus_response*)aDest;
+ if (!pDest)
+ pDest = new rates_xstatus_response(ppro, wGroup);
+
+ pDest->bThruDC = bThruDC;
+ pDest->dwMsgID1 = dwMsgID1;
+ pDest->dwMsgID2 = dwMsgID2;
+ pDest->wCookie = wCookie;
+ pDest->szResponse = null_strdup(szResponse);
+
+ return rates_queue_item::copyItem(pDest);
+ };
+ public:
+ rates_xstatus_response(CIcqProto *ppro, WORD wGroup): rates_queue_item(ppro, wGroup), szResponse(NULL) { };
+ virtual ~rates_xstatus_response() { if (bCreated) SAFE_FREE(&szResponse); };
+
+ virtual void execute() {
+ ppro->SendXtrazNotifyResponse(dwUin, dwMsgID1, dwMsgID2, wCookie, szResponse, strlennull(szResponse), bThruDC);
+ };
+
+ BOOL bThruDC;
+ DWORD dwMsgID1;
+ DWORD dwMsgID2;
+ WORD wCookie;
+ char *szResponse;
+ };
+
+ m_ratesMutex->Enter();
+ WORD wGroup = m_rates->getGroupFromSNAC(ICQ_MSG_FAMILY, ICQ_MSG_RESPONSE);
+ m_ratesMutex->Leave();
+
+ rates_xstatus_response rr(this, wGroup);
+ rr.hContact = hContact;
+ rr.dwUin = dwUin;
+ rr.bThruDC = bThruDC;
+ rr.dwMsgID1 = dwMID;
+ rr.dwMsgID2 = dwMID2;
+ rr.wCookie = wCookie;
+ rr.szResponse = szResponse;
+
+ handleRateItem(&rr, RQT_RESPONSE, 0, !bThruDC);
+ }
+ else if (dwXId)
+ NetLog_Server("Privacy: Ignoring XStatus request");
+ else
+ NetLog_Server("Error: We are not in XStatus, skipping");
+ }
+ else
+ NetLog_Server("Error: Invalid sender information");
+ }
+ else
+ NetLog_Server("Error: Missing sender information");
+ }
+ else
+ NetLog_Server("Error: Unknown plugin \"%s\" in Xtraz message", szWork);
+ }
+ else
+ NetLog_Server("Error: Missing PluginID in Xtraz message");
+
+ SAFE_FREE(&szNotify);
+ SAFE_FREE(&szQuery);
+ }
+ else
+ NetLog_Server("Error: Invalid Xtraz Notify message");
+}
+
+
+void CIcqProto::handleXtrazNotifyResponse(DWORD dwUin, HANDLE hContact, WORD wCookie, char* szMsg, int nMsgLen)
+{
+ char *szMem, *szRes, *szEnd;
+ int nResLen;
+
+#ifdef _DEBUG
+ NetLog_Server("Received Xtraz Notify Response");
+#endif
+
+ szRes = strstrnull(szMsg, "<RES>");
+ szEnd = strstrnull(szMsg, "</RES>");
+
+ if (szRes && szEnd)
+ { // valid response
+ char *szNode, *szWork;
+
+ szRes += 5;
+ nResLen = szEnd - szRes;
+
+ szMem = szRes = DemangleXml(szRes, nResLen);
+
+#ifdef _DEBUG
+ NetLog_Server("Response: %s", szRes);
+#endif
+
+ BroadcastAck(hContact, ICQACKTYPE_XTRAZNOTIFY_RESPONSE, ACKRESULT_SUCCESS, (HANDLE)wCookie, (LPARAM)szRes);
+
+NextVal:
+ szNode = strstrnull(szRes, "<val srv_id=");
+ if (szNode) szEnd = strstrnull(szNode, ">"); else szEnd = NULL;
+
+ if (szNode && szEnd)
+ {
+ *(szEnd-1) = '\0';
+ szNode += 13; //one more than the length of the string to skip ' or " too
+ szWork = szEnd + 1;
+
+ if (!stricmpnull(szNode, "cAwaySrv"))
+ {
+ int bChanged = FALSE;
+
+ *szEnd = ' ';
+ szNode = strstrnull(szWork, "<index>");
+ szEnd = strstrnull(szWork, "</index>");
+ if (szNode && szEnd)
+ {
+ szNode += 7;
+ *szEnd = '\0';
+ if (atoi(szNode) != getContactXStatus(hContact))
+ { // this is strange - but go on
+ NetLog_Server("Warning: XStatusIds do not match!");
+ }
+ *szEnd = ' ';
+ }
+ szNode = strstrnull(szWork, "<title>");
+ szEnd = strstrnull(szWork, "</title>");
+ if (szNode && szEnd)
+ { // we got XStatus title, save it
+ char *szXName, *szOldXName;
+ szNode += 7;
+ *szEnd = '\0';
+ szXName = DemangleXml(szNode, strlennull(szNode));
+ // check if the name changed
+ szOldXName = getSettingStringUtf(hContact, DBSETTING_XSTATUS_NAME, NULL);
+ if (strcmpnull(szOldXName, szXName))
+ bChanged = TRUE;
+ SAFE_FREE(&szOldXName);
+ setSettingStringUtf(hContact, DBSETTING_XSTATUS_NAME, szXName);
+ SAFE_FREE(&szXName);
+ *szEnd = ' ';
+ }
+ szNode = strstrnull(szWork, "<desc>");
+ szEnd = strstrnull(szWork, "</desc>");
+ if (szNode && szEnd)
+ { // we got XStatus mode msg, save it
+ char *szXMsg, *szOldXMsg;
+ szNode += 6;
+ *szEnd = '\0';
+ szXMsg = DemangleXml(szNode, strlennull(szNode));
+ // check if the decription changed
+ szOldXMsg = getSettingStringUtf(hContact, DBSETTING_XSTATUS_NAME, NULL);
+ if (strcmpnull(szOldXMsg, szXMsg))
+ bChanged = TRUE;
+ SAFE_FREE(&szOldXMsg);
+ setSettingStringUtf(hContact, DBSETTING_XSTATUS_MSG, szXMsg);
+ SAFE_FREE(&szXMsg);
+ }
+ BroadcastAck(hContact, ICQACKTYPE_XSTATUS_RESPONSE, ACKRESULT_SUCCESS, (HANDLE)wCookie, 0);
+ if (bChanged)
+ NotifyEventHooks(hxstatuschanged, (WPARAM)hContact, 0);
+ }
+ else
+ {
+ char *szSrvEnd = strstrnull(szEnd, "</srv>");
+
+ if (szSrvEnd && strstrnull(szSrvEnd, "<val srv_id="))
+ { // check all values !
+ szRes = szSrvEnd + 6; // after first value
+ goto NextVal;
+ }
+ // no next val, we were unable to handle packet, write error
+ NetLog_Server("Error: Unknown serverId \"%s\" in Xtraz response", szNode);
+ }
+ }
+ else
+ NetLog_Server("Error: Missing serverId in Xtraz response");
+
+ SAFE_FREE(&szMem);
+ }
+ else
+ NetLog_Server("Error: Invalid Xtraz Notify response");
+}
+
+
+static char* getXmlPidItem(const char* szData, int nLen)
+{
+ const char *szPid, *szEnd;
+
+ szPid = strstrnull(szData, "<PID>");
+ szEnd = strstrnull(szData, "</PID>");
+
+ if (szPid && szEnd)
+ {
+ szPid += 5;
+
+ return DemangleXml(szPid, szEnd - szPid);
+ }
+ return NULL;
+}
+
+
+void CIcqProto::handleXtrazInvitation(DWORD dwUin, DWORD dwMID, DWORD dwMID2, WORD wCookie, char* szMsg, int nMsgLen, BOOL bThruDC)
+{
+ HANDLE hContact;
+ char* szPluginID;
+
+ hContact = HContactFromUIN(dwUin, NULL);
+ if (hContact) // user sent us xtraz, he supports it
+ SetContactCapabilities(hContact, CAPF_XTRAZ);
+
+ szPluginID = getXmlPidItem(szMsg, nMsgLen);
+ if (!strcmpnull(szPluginID, "ICQChatRecv"))
+ { // it is a invitation to multi-user chat
+ }
+ else
+ {
+ NetLog_Uni(bThruDC, "Error: Unknown plugin \"%s\" in Xtraz message", szPluginID);
+ }
+ SAFE_FREE(&szPluginID);
+}
+
+
+void CIcqProto::handleXtrazData(DWORD dwUin, DWORD dwMID, DWORD dwMID2, WORD wCookie, char* szMsg, int nMsgLen, BOOL bThruDC)
+{
+ HANDLE hContact;
+ char* szPluginID;
+
+ hContact = HContactFromUIN(dwUin, NULL);
+ if (hContact) // user sent us xtraz, he supports it
+ SetContactCapabilities(hContact, CAPF_XTRAZ);
+
+ szPluginID = getXmlPidItem(szMsg, nMsgLen);
+ if (!strcmpnull(szPluginID, "viewCard"))
+ { // it is a greeting card
+ char *szWork, *szEnd, *szUrl, *szNum;
+
+ szWork = strstrnull(szMsg, "<InD>");
+ szEnd = strstrnull(szMsg, "</InD>");
+ if (szWork && szEnd)
+ {
+ int nDataLen = szEnd - szWork;
+
+ szUrl = (char*)_alloca(nDataLen);
+ memcpy(szUrl, szWork+5, nDataLen);
+ szUrl[nDataLen - 5] = '\0';
+
+ if (!_strnicmp(szUrl, "view_", 5))
+ {
+ szNum = szUrl + 5;
+ szWork = strstrnull(szUrl, ".html");
+ if (szWork)
+ {
+ strcpy(szWork, ".php");
+ strcat(szWork, szWork+5);
+ }
+ while (szWork = strstrnull(szUrl, "&amp;"))
+ { // unescape &amp; code
+ strcpy(szWork+1, szWork+5);
+ }
+ szWork = (char*)SAFE_MALLOC(nDataLen + MAX_PATH);
+ ICQTranslateUtfStatic(LPGEN("Greeting card:"), szWork, MAX_PATH);
+ strcat(szWork, "\r\nhttp://www.icq.com/friendship/pages/view_page_");
+ strcat(szWork, szNum);
+
+ // Create message to notify user
+ {
+ CCSDATA ccs;
+ PROTORECVEVENT pre = {0};
+ int bAdded;
+
+ ccs.szProtoService = PSR_MESSAGE;
+ ccs.hContact = HContactFromUIN(dwUin, &bAdded);
+ ccs.wParam = 0;
+ ccs.lParam = (LPARAM)&pre;
+ pre.timestamp = time(NULL);
+ pre.szMessage = szWork;
+ pre.flags = PREF_UTF;
+
+ CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs);
+ }
+ SAFE_FREE(&szWork);
+ }
+ else
+ NetLog_Uni(bThruDC, "Error: Non-standard greeting card message");
+ }
+ else
+ NetLog_Uni(bThruDC, "Error: Malformed greeting card message");
+ }
+ else
+ {
+ NetLog_Uni(bThruDC, "Error: Unknown plugin \"%s\" in Xtraz message", szPluginID);
+ }
+ SAFE_FREE(&szPluginID);
+}
+
+
+// Functions really sending Xtraz stuff
+DWORD CIcqProto::SendXtrazNotifyRequest(HANDLE hContact, char* szQuery, char* szNotify, int bForced)
+{
+ char *szQueryBody;
+ char *szNotifyBody;
+ DWORD dwUin;
+ int nBodyLen;
+ char *szBody;
+ DWORD dwCookie;
+
+ if (getContactUid(hContact, &dwUin, NULL))
+ return 0; // Invalid contact
+
+ if (!CheckContactCapabilities(hContact, CAPF_XTRAZ) && !bForced)
+ return 0; // Contact does not support xtraz, do not send anything
+
+ szQueryBody = MangleXml(szQuery, strlennull(szQuery));
+ szNotifyBody = MangleXml(szNotify, strlennull(szNotify));
+ nBodyLen = strlennull(szQueryBody) + strlennull(szNotifyBody) + 41;
+ szBody = (char*)_alloca(nBodyLen);
+ nBodyLen = null_snprintf(szBody, nBodyLen, "<N><QUERY>%s</QUERY><NOTIFY>%s</NOTIFY></N>", szQueryBody, szNotifyBody);
+ SAFE_FREE((void**)&szQueryBody);
+ SAFE_FREE((void**)&szNotifyBody);
+
+ // Set up the ack type
+ cookie_message_data *pCookieData = CreateMessageCookie(MTYPE_SCRIPT_NOTIFY, ACKTYPE_CLIENT);
+ dwCookie = AllocateCookie(CKT_MESSAGE, 0, hContact, (void*)pCookieData);
+
+ // have we a open DC, send through that
+ if (m_bDCMsgEnabled && IsDirectConnectionOpen(hContact, DIRECTCONN_STANDARD, 0))
+ icq_sendXtrazRequestDirect(hContact, dwCookie, szBody, nBodyLen, MTYPE_SCRIPT_NOTIFY);
+ else
+ icq_sendXtrazRequestServ(dwUin, dwCookie, szBody, nBodyLen, pCookieData);
+
+ return dwCookie;
+}
+
+
+void CIcqProto::SendXtrazNotifyResponse(DWORD dwUin, DWORD dwMID, DWORD dwMID2, WORD wCookie, char* szResponse, int nResponseLen, BOOL bThruDC)
+{
+ char *szResBody = MangleXml(szResponse, nResponseLen);
+ int nBodyLen = strlennull(szResBody) + 21;
+ char *szBody = (char*)_alloca(nBodyLen);
+ HANDLE hContact = HContactFromUIN(dwUin, NULL);
+
+ if (hContact != INVALID_HANDLE_VALUE && !CheckContactCapabilities(hContact, CAPF_XTRAZ))
+ {
+ SAFE_FREE(&szResBody);
+ return; // Contact does not support xtraz, do not send anything
+ }
+
+ nBodyLen = null_snprintf(szBody, nBodyLen, "<NR><RES>%s</RES></NR>", szResBody);
+ SAFE_FREE(&szResBody);
+
+ // Was request received thru DC and have we a open DC, send through that
+ if (bThruDC && IsDirectConnectionOpen(hContact, DIRECTCONN_STANDARD, 0))
+ icq_sendXtrazResponseDirect(hContact, wCookie, szBody, nBodyLen, MTYPE_SCRIPT_NOTIFY);
+ else
+ icq_sendXtrazResponseServ(dwUin, dwMID, dwMID2, wCookie, szBody, nBodyLen, MTYPE_SCRIPT_NOTIFY);
+}