From c80bc292b555c6666930790c399f6fac6226c468 Mon Sep 17 00:00:00 2001 From: Vadim Dashevskiy Date: Sat, 21 Jul 2012 10:11:53 +0000 Subject: Skype and IMO2sProxy added, not adapted yet git-svn-id: http://svn.miranda-ng.org/main/trunk@1091 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/IMO2sProxy/src/imolib/Makefile | 14 + plugins/IMO2sProxy/src/imolib/imo_request.c | 388 ++++++++++++++ plugins/IMO2sProxy/src/imolib/imo_request.h | 36 ++ plugins/IMO2sProxy/src/imolib/imo_skype.c | 707 +++++++++++++++++++++++++ plugins/IMO2sProxy/src/imolib/imo_skype.h | 37 ++ plugins/IMO2sProxy/src/imolib/io_layer.c | 175 ++++++ plugins/IMO2sProxy/src/imolib/io_layer.h | 25 + plugins/IMO2sProxy/src/imolib/io_layer_win32.c | 440 +++++++++++++++ plugins/IMO2sProxy/src/imolib/skypetst.c | 211 ++++++++ 9 files changed, 2033 insertions(+) create mode 100644 plugins/IMO2sProxy/src/imolib/Makefile create mode 100644 plugins/IMO2sProxy/src/imolib/imo_request.c create mode 100644 plugins/IMO2sProxy/src/imolib/imo_request.h create mode 100644 plugins/IMO2sProxy/src/imolib/imo_skype.c create mode 100644 plugins/IMO2sProxy/src/imolib/imo_skype.h create mode 100644 plugins/IMO2sProxy/src/imolib/io_layer.c create mode 100644 plugins/IMO2sProxy/src/imolib/io_layer.h create mode 100644 plugins/IMO2sProxy/src/imolib/io_layer_win32.c create mode 100644 plugins/IMO2sProxy/src/imolib/skypetst.c (limited to 'plugins/IMO2sProxy/src/imolib') diff --git a/plugins/IMO2sProxy/src/imolib/Makefile b/plugins/IMO2sProxy/src/imolib/Makefile new file mode 100644 index 0000000000..30775becec --- /dev/null +++ b/plugins/IMO2sProxy/src/imolib/Makefile @@ -0,0 +1,14 @@ +CFLAGS = -I../common/ -lcurl -lpthread -lm -O0 -g +CC = gcc +COMMON = ../common/fifo.c ../common/cJSON.c +OBJS = imo_request.c imo_skype.c skypetst.c io_layer.c + +.PHONY: all skypetst clean + +all : skypetst + +skypetst: $(COMMON) $(OBJS) + $(CC) -o skypetst $(COMMON) $(OBJS) $(CFLAGS) + +clean : + rm skypetst diff --git a/plugins/IMO2sProxy/src/imolib/imo_request.c b/plugins/IMO2sProxy/src/imolib/imo_request.c new file mode 100644 index 0000000000..732a7e3e48 --- /dev/null +++ b/plugins/IMO2sProxy/src/imolib/imo_request.c @@ -0,0 +1,388 @@ +/* Module: imo_request.c + Purpose: Posts XMLHHTP-Requests to imo.im server + Author: leecher + Date: 30.08.2009 +*/ +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#define LockMutex(x) EnterCriticalSection (&x) +#define UnlockMutex(x) LeaveCriticalSection(&x) +#define InitMutex(x) InitializeCriticalSection(&x) +#define ExitMutex(x) DeleteCriticalSection(&x) +#define mutex_t CRITICAL_SECTION +#else +#include +#define LockMutex(x) pthread_mutex_lock(&x) +#define UnlockMutex(x) pthread_mutex_unlock(&x) +#define InitMutex(x) pthread_mutex_init(&x, NULL); +#define ExitMutex(x) +#define mutex_t pthread_mutex_t +#endif +#include +#include +#include +#include +#include "fifo.h" +#include "imo_request.h" +#include "io_layer.h" + +#define SSID_LENGTH 16 + +struct _tagIMORQ +{ + IOLAYER *hIO; + char szSessId[SSID_LENGTH+2]; + unsigned long send_ack; // Some Sending ACK number + unsigned long send_seq; // Within one ACK there seems to be a SEQ-Number? + unsigned long *psend_ack; // Pointer to send_ack to use + unsigned long *psend_seq; // Pointer to send_seq to use + mutex_t mutex; // Mutex for securing psend_ack and psend_seq read/write + BOOL bIsClone; // Indicates that the current handle is a clone + char *pszHost; // Login host + char szReqURL[32]; // Request-URL +}; + +static IOLAYER *(*IoLayer_Init)(void) = +#ifdef WIN32 +IoLayerW32_Init; +#else +IoLayerCURL_Init; +#endif + +// Forward declaration of private functions +static size_t add_data(char *data, size_t size, size_t nmemb, void *ctx); +static IMORQ *Init(void); + +// ----------------------------------------------------------------------------- +// Interface +// ----------------------------------------------------------------------------- + +void ImoRq_SetIOLayer(IOLAYER *(*fp_Init)(void)) +{ + IoLayer_Init = fp_Init; +} + +// ----------------------------------------------------------------------------- + +IMORQ *ImoRq_Init(void) +{ + + IMORQ *hRq; + + if (hRq = Init()) + { + /* Create session ID */ + ImoRq_CreateID (hRq->szSessId, SSID_LENGTH+1); + + hRq->psend_seq = &hRq->send_seq; + hRq->psend_ack = &hRq->send_ack; + InitMutex(hRq->mutex); + + /* Disptch version of imo.im protocol */ + switch (IMO_API_VERSION) + { + case 0: + hRq->pszHost = "https://o.imo.im/"; + break; + case 1: + hRq->pszHost = "https://imo.im/"; + break; + } + sprintf (hRq->szReqURL, "%simo", hRq->pszHost); + + /* Fetch start page to get cookies */ + if (hRq->hIO->Get (hRq->hIO, hRq->pszHost, NULL)) + + /* Get new session ID from system */ + { + char *pszRPC = ImoRq_ResetRPC (hRq), *pszRPCRes; + if (pszRPC) + { + if ((pszRPCRes = strstr(pszRPC, "ssid\":\"")) || (pszRPCRes = strstr(pszRPC, "ssid\": \""))) + strcpy (hRq->szSessId, strtok (pszRPCRes+7, "\"")); + } + } else { + ImoRq_Exit(hRq); + hRq = NULL; + } + } + + return hRq; +} + +// ----------------------------------------------------------------------------- + +IMORQ *ImoRq_Clone (IMORQ *hRq) +{ + IMORQ *hDup; + + if (!(hDup = Init())) return NULL; + strcpy (hDup->szSessId, hRq->szSessId); + hDup->psend_seq = hRq->psend_seq; + hDup->psend_ack = hRq->psend_ack; + hDup->mutex = hRq->mutex; + hDup->bIsClone = TRUE; + hDup->pszHost = hRq->pszHost; + strcpy (hDup->szReqURL, hRq->szReqURL); + return hDup; +} + +// ----------------------------------------------------------------------------- + +void ImoRq_Exit (IMORQ *hRq) +{ + if (hRq->hIO) hRq->hIO->Exit(hRq->hIO); + if (!hRq->bIsClone) ExitMutex (hRq->mutex); + free (hRq); +} +// ----------------------------------------------------------------------------- + +void ImoRq_Cancel (IMORQ *hRq) +{ + if (hRq->hIO) hRq->hIO->Cancel(hRq->hIO); +} + +// ----------------------------------------------------------------------------- + +char *ImoRq_PostImo(IMORQ *hRq, char *pszMethod, cJSON *data) +{ + TYP_FIFO *hPostString; + char *pszData, *pszEscData; + unsigned int uiCount = -1; + + if (!(pszData = cJSON_Print(data))) return NULL; +printf ("-> %s\n", pszData); +#ifdef _WIN32 +OutputDebugString (pszData); +OutputDebugString ("\n"); +#endif + pszEscData = hRq->hIO->EscapeString(hRq->hIO, pszData); + free (pszData); + if (!pszEscData || !(hPostString = Fifo_Init(strlen(pszEscData)+32))) + { + if (pszEscData) hRq->hIO->FreeEscapeString (pszEscData); + return NULL; + } + Fifo_AddString (hPostString, "method="); + Fifo_AddString (hPostString, pszMethod); + Fifo_AddString (hPostString, "&data="); + Fifo_AddString (hPostString, pszEscData); + hRq->hIO->FreeEscapeString (pszEscData); + pszEscData = Fifo_Get(hPostString, &uiCount); + pszData = hRq->hIO->Post (hRq->hIO, hRq->szReqURL, pszEscData, + uiCount-1, NULL); + Fifo_Exit(hPostString); +printf ("<- %s\n", pszData); + return pszData; +} + +// ----------------------------------------------------------------------------- + +char *ImoRq_PostSystem(IMORQ *hRq, char *pszMethod, char *pszSysTo, char *pszSysFrom, cJSON *data, int bFreeData) +{ + cJSON *root, *msgs, *msg, *to, *from; + char *pszRet; + + if (!(root=cJSON_CreateObject())) return NULL; + LockMutex (hRq->mutex); + cJSON_AddNumberToObject (root, "ack", *hRq->psend_ack); + if (*hRq->szSessId) cJSON_AddStringToObject (root, "ssid", hRq->szSessId); + else cJSON_AddNumberToObject (root, "ssid", 0); + cJSON_AddItemToObject (root, "messages", (msgs = cJSON_CreateArray())); + if (data) + { + msg=cJSON_CreateObject(); + cJSON_AddItemToObject(msg, "data", data); + to = cJSON_CreateObject(); + cJSON_AddStringToObject (to, "system", pszSysTo); + cJSON_AddItemToObject(msg, "to", to); + from = cJSON_CreateObject(); + cJSON_AddStringToObject (from, "system", pszSysFrom); + if (*hRq->szSessId) cJSON_AddStringToObject (from, "ssid", hRq->szSessId); + else cJSON_AddNumberToObject (from, "ssid", 0); + cJSON_AddItemToObject(msg, "from", from); + cJSON_AddNumberToObject (msg, "seq", (*hRq->psend_seq)++); + cJSON_AddItemToArray (msgs, msg); + } + UnlockMutex (hRq->mutex); + pszRet = ImoRq_PostImo (hRq, pszMethod, root); + if (data && !bFreeData) + { + msg->child = data->next; + data->next = NULL; + } + cJSON_Delete (root); + return pszRet; +} + +// ----------------------------------------------------------------------------- + +char *ImoRq_ResetRPC(IMORQ *hRq) +{ + cJSON *root, *ssid; + char *pszRet; + + if (!(root=cJSON_CreateObject())) return NULL; + cJSON_AddStringToObject (root, "method", (IMO_API_VERSION==0?"get_ssid":"get_cookie_and_ssid")); + ssid=cJSON_CreateObject(); + cJSON_AddStringToObject (ssid, "ssid", hRq->szSessId); + if (IMO_API_VERSION > 0) + { + cJSON_AddStringToObject (ssid, "kind", "reui"); + cJSON_AddStringToObject (ssid, "version", "1336611734.48"); + } + cJSON_AddItemToObject(root, "data", ssid); + if (IMO_API_VERSION == 0) *hRq->szSessId = 0; + pszRet = ImoRq_PostSystem (hRq, "rest_rpc", (IMO_API_VERSION==0?"ssid":"session"), "client", root, 1); + LockMutex (hRq->mutex); + *hRq->psend_seq=0; + UnlockMutex (hRq->mutex); + return pszRet; +} + +// ----------------------------------------------------------------------------- + +char *ImoRq_UserActivity(IMORQ *hRq) +{ + cJSON *ssid; + + ssid=cJSON_CreateObject(); + cJSON_AddStringToObject (ssid, "ssid", hRq->szSessId); + return ImoRq_PostToSys (hRq, "observed_user_activity", "session", ssid, 1, NULL); +} + +// ----------------------------------------------------------------------------- + +char *ImoRq_Echo(IMORQ *hRq) +{ + cJSON *data; + time_t t; + char szTime[16], *pszRet; + + if (!(data=cJSON_CreateObject())) return NULL; + sprintf (szTime, "%ld", time(&t)*1000); + cJSON_AddStringToObject (data, "t", szTime); + pszRet = ImoRq_PostImo (hRq, "echo", data); + cJSON_Delete (data); + return pszRet; +} + +// ----------------------------------------------------------------------------- + +char *ImoRq_Reui_Session(IMORQ *hRq) +{ + cJSON *ssid; + + ssid=cJSON_CreateObject(); + cJSON_AddStringToObject (ssid, "ssid", hRq->szSessId); + return ImoRq_PostToSys (hRq, "reui_session", "session", ssid, 1, NULL); +} + +// ----------------------------------------------------------------------------- + +char *ImoRq_PostToSys(IMORQ *hRq, char *pszMethod, char *pszSysTo, cJSON *data, int bFreeData, int *pireqid) +{ + cJSON *root; + char *pszRet; + + if (!(root=cJSON_CreateObject())) return NULL; + cJSON_AddStringToObject (root, "method", pszMethod); + if (pireqid) cJSON_AddNumberToObject(root, "request_id", *pireqid); + cJSON_AddItemToObject(root, "data", data); + pszRet = ImoRq_PostSystem (hRq, "forward_to_server", pszSysTo, "client", root, bFreeData); + if (!bFreeData) + { + data->prev->next = data->next; + if (data->next) data->next->prev = data->prev; + data->prev = data->next = NULL; + cJSON_Delete (root); + } + return pszRet; +} +// ----------------------------------------------------------------------------- + +char *ImoRq_PostAmy(IMORQ *hRq, char *pszMethod, cJSON *data) +{ + return ImoRq_PostToSys (hRq, pszMethod, "im", data, FALSE, NULL); +} + +// ----------------------------------------------------------------------------- + +char *ImoRq_SessId(IMORQ *hRq) +{ + return hRq->szSessId; +} + +// ----------------------------------------------------------------------------- + +char *ImoRq_GetLastError(IMORQ *hRq) +{ + return hRq->hIO->GetLastError (hRq->hIO); +} + +// ----------------------------------------------------------------------------- +char *ImoRq_GetHost(IMORQ *hRq) +{ + return hRq->pszHost; +} + +// ----------------------------------------------------------------------------- +void ImoRq_UpdateAck(IMORQ *hRq, unsigned long lAck) +{ + LockMutex (hRq->mutex); + *hRq->psend_ack = lAck; + UnlockMutex (hRq->mutex); +} +// ----------------------------------------------------------------------------- +unsigned long ImoRq_GetSeq(IMORQ *hRq) +{ + unsigned long lRet; + + LockMutex (hRq->mutex); + lRet = *hRq->psend_seq; + UnlockMutex (hRq->mutex); + return lRet; +} +// ----------------------------------------------------------------------------- + +void ImoRq_CreateID(char *pszID, int cbID) +{ + int i, r; + time_t curtime; + + srand(time(&curtime)); + for (i=0; ihIO->Get (hRq->hIO, pszURL, pdwLength); +} + +// ----------------------------------------------------------------------------- + +static IMORQ *Init(void) +{ + IMORQ *hRq = calloc(1, sizeof(IMORQ)); + + /* Setup CURL */ + if (!hRq) return NULL; + if (!(hRq->hIO = IoLayer_Init())) + { + ImoRq_Exit(hRq); + return NULL; + } + return hRq; +} + diff --git a/plugins/IMO2sProxy/src/imolib/imo_request.h b/plugins/IMO2sProxy/src/imolib/imo_request.h new file mode 100644 index 0000000000..42da000bc2 --- /dev/null +++ b/plugins/IMO2sProxy/src/imolib/imo_request.h @@ -0,0 +1,36 @@ +#ifndef _IMO_REQUEST_H_ +#define _IMO_REQUEST_H_ + +#include "cJSON.h" + +// 1 - New imo.im api +// 0 - o.imo.im api +#define IMO_API_VERSION 1 + +struct _tagIMORQ; +typedef struct _tagIMORQ IMORQ; + +#ifdef _IOLAYER_H_ +void ImoRq_SetIOLayer(IOLAYER *(*fp_Init)(void)); +#endif + +IMORQ *ImoRq_Init(void); +IMORQ *ImoRq_Clone (IMORQ *hRq); +void ImoRq_Cancel (IMORQ *hRq); +void ImoRq_Exit (IMORQ *hRq); + +char *ImoRq_SessId(IMORQ *hRq); +char *ImoRq_GetLastError(IMORQ *hRq); +char *ImoRq_GetHost(IMORQ *hRq); +char *ImoRq_PostAmy(IMORQ *hRq, char *pszMethod, cJSON *data); +void ImoRq_CreateID(char *pszID, int cbID); +char *ImoRq_PostSystem(IMORQ *hRq, char *pszMethod, char *pszSysTo, char *pszSysFrom, cJSON *data, int bFreeData); +char *ImoRq_PostToSys(IMORQ *hRq, char *pszMethod, char *pszSysTo, cJSON *data, int bFreeData, int *pireqid); +void ImoRq_UpdateAck(IMORQ *hRq, unsigned long lAck); +unsigned long ImoRq_GetSeq(IMORQ *hRq); +char *ImoRq_UserActivity(IMORQ *hRq); +char *ImoRq_ResetRPC(IMORQ *hRq); +char *ImoRq_Reui_Session(IMORQ *hRq); +char *ImoRq_Echo(IMORQ *hRq); +char *ImoRq_HTTPGet(IMORQ *hRq, char *pszURL, unsigned int *pdwLength); +#endif diff --git a/plugins/IMO2sProxy/src/imolib/imo_skype.c b/plugins/IMO2sProxy/src/imolib/imo_skype.c new file mode 100644 index 0000000000..f2bca4d7b8 --- /dev/null +++ b/plugins/IMO2sProxy/src/imolib/imo_skype.c @@ -0,0 +1,707 @@ +/* Module: imo_skype.c + Purpose: Communication layer for imo.im Skype + Author: leecher + Date: 30.08.2009 +*/ +#include +#include +#include +#include "imo_request.h" +#include "imo_skype.h" + +#ifdef _WIN64 +#pragma comment (lib, "bufferoverflowU.lib") +#endif + +#define PROTO "prpl-skype" + +struct _tagIMOSKYPE +{ + IMORQ *hRq; + IMORQ *hPoll; + char *pszUser; + IMOSTATCB StatusCb; + char *pszLastRes; + void *pUser; + int request_id; +}; + +static int CheckReturn (IMOSKYPE *hSkype, char *pszMsg, char *pszExpected); +static int ManageBuddy(IMOSKYPE *hSkype, char *pszAction, char *pszBuddy, char *pszGroup); + +// ----------------------------------------------------------------------------- +// Interface +// ----------------------------------------------------------------------------- + +IMOSKYPE *ImoSkype_Init(IMOSTATCB StatusCb, void *pUser) +{ + IMOSKYPE *hSkype = calloc(1, sizeof(IMOSKYPE)); + + if (!hSkype) return NULL; + if (!(hSkype->hRq = ImoRq_Init()) || !(hSkype->hPoll = ImoRq_Clone(hSkype->hRq))) + { + ImoSkype_Exit(hSkype); + return NULL; + } + hSkype->StatusCb = StatusCb; + hSkype->pUser = pUser; + return hSkype; +} + +// ----------------------------------------------------------------------------- + +void ImoSkype_Exit(IMOSKYPE *hSkype) +{ + if (!hSkype) return; + if (hSkype->hRq) ImoRq_Exit(hSkype->hRq); + if (hSkype->hPoll) ImoRq_Exit(hSkype->hPoll); + if (hSkype->pszUser) free(hSkype->pszUser); + free (hSkype); +} + +// ----------------------------------------------------------------------------- + +void ImoSkype_CancelPolling(IMOSKYPE *hSkype) +{ + if (hSkype->hPoll) + ImoRq_Cancel(hSkype->hPoll); +} + +// ----------------------------------------------------------------------------- + +char *ImoSkype_GetLastError(IMOSKYPE *hSkype) +{ + char *pszRet = ImoRq_GetLastError(hSkype->hRq); + + if (!pszRet || !*pszRet) return hSkype->pszLastRes; + return pszRet; +} + +// ----------------------------------------------------------------------------- + +char *ImoSkype_GetUserHandle(IMOSKYPE *hSkype) +{ + return hSkype->pszUser; +} + +// ----------------------------------------------------------------------------- + +// -1 - Error +// 0 - Login failed +// 1 - Login successful +int ImoSkype_Login(IMOSKYPE *hSkype, char *pszUser, char *pszPass) +{ + cJSON *root; + char *pszRet; + int iRet = -1; + + if (!hSkype) return 0; + if (IMO_API_VERSION == 0) + { + if (!(root=cJSON_CreateObject())) return 0; + cJSON_AddStringToObject(root, "ssid", ImoRq_SessId(hSkype->hRq)); + if (pszRet = ImoRq_PostToSys(hSkype->hRq, "cookie_login", "session", root, 1, NULL)) + iRet = CheckReturn(hSkype, pszRet, "ok")>0; + } + + if (!(root=cJSON_CreateObject())) return 0; + if (hSkype->pszUser) free (hSkype->pszUser); + cJSON_AddStringToObject(root, "uid", hSkype->pszUser = strdup(pszUser)); + cJSON_AddStringToObject(root, "proto", PROTO); + cJSON_AddStringToObject(root, "passwd", pszPass); + cJSON_AddNullToObject(root, "captcha"); // Uh-oh, thay may get annoying in the future! :( + cJSON_AddStringToObject(root, "ssid", ImoRq_SessId(hSkype->hRq)); + if (pszRet = ImoRq_PostAmy(hSkype->hRq, "account_login", root)) + iRet = CheckReturn(hSkype, pszRet, "ok")>0; + cJSON_Delete(root); + + return iRet; +} + +// ----------------------------------------------------------------------------- + +// -1 - Error +// 0 - Logout failed +// 1 - Logout successful +int ImoSkype_Logout(IMOSKYPE *hSkype) +{ + cJSON *root; + char *pszRet; + int iRet = -1; + + if (!hSkype || !(root=cJSON_CreateObject())) return 0; + cJSON_AddStringToObject(root, "ssid", ImoRq_SessId(hSkype->hRq)); + if (pszRet = ImoRq_PostToSys(hSkype->hRq, "signoff_all", "session", root, 1, NULL)) + iRet = CheckReturn(hSkype, pszRet, "ok")>0; + return iRet; +} + +// ----------------------------------------------------------------------------- + +// -1 - Error +// 0 - Received unknown answer +// 1 - Got back information, called notification callback +// 2 - Received PING [deprecated] +int ImoSkype_Poll(IMOSKYPE *hSkype) +{ + char *pszRet; + + if (!hSkype || !hSkype->hPoll) return 0; + pszRet = ImoRq_PostSystem(hSkype->hPoll, "forward_to_server", NULL, NULL, NULL, 1); + if (!pszRet) return -1; + return CheckReturn (hSkype, pszRet, "ping"); +} + +// ----------------------------------------------------------------------------- + +int ImoSkype_KeepAlive(IMOSKYPE *hSkype) +{ + char *pszRet; + + /* In case we want to receive Promo-Infos... + { + cJSON *edata = cJSON_CreateObject(), *root; + + root=cJSON_CreateObject(); + cJSON_AddStringToObject(edata, "kind", "web"); + cJSON_AddNumberToObject(edata, "quantity", 1); + cJSON_AddItemToObject(root, "edata", edata); + if (pszRet = ImoRq_PostToSys(hSkype->hRq, "get_promos", "promo", root, 1)) + CheckReturn(hSkype, pszRet, "ok"); + } + */ + + if (!hSkype) return 0; + pszRet = ImoRq_UserActivity(hSkype->hPoll); + if (!pszRet) return -1; + return CheckReturn (hSkype, pszRet, "ok"); +} + +// ----------------------------------------------------------------------------- + +// pszStatus: +// Valid states: +// typing +// typed +// not_typing +// +// -1 - Error +// 0 - Typing notification failed +// 1 - Typing notification successful +int ImoSkype_Typing(IMOSKYPE *hSkype, char *pszBuddy, char *pszStatus) +{ + cJSON *root; + char *pszRet; + int iRet = -1; + + if (!hSkype || !hSkype->pszUser || !(root=cJSON_CreateObject())) return 0; + cJSON_AddStringToObject(root, "uid", hSkype->pszUser); + cJSON_AddStringToObject(root, "proto", PROTO); + cJSON_AddStringToObject(root, "ssid", ImoRq_SessId(hSkype->hRq)); + cJSON_AddStringToObject(root, "buid", pszBuddy); + cJSON_AddStringToObject(root, "typing_state", pszStatus); + if (pszRet = ImoRq_PostAmy(hSkype->hRq, "im_typing", root)) + iRet = CheckReturn(hSkype, pszRet, "ok")>0; + cJSON_Delete(root); + return iRet; +} + +// ----------------------------------------------------------------------------- + +// -1 - Error +// 0 - Sending failed +// 1 - Send pending +int ImoSkype_SendMessage(IMOSKYPE *hSkype, char *pszBuddy, char *pszMessage, int *prequest_id) +{ + cJSON *root; + char *pszRet; + int iRet = -1; + + if (!hSkype || !hSkype->pszUser || !(root=cJSON_CreateObject())) return 0; + cJSON_AddStringToObject(root, "ssid", ImoRq_SessId(hSkype->hRq)); + cJSON_AddStringToObject(root, "uid", hSkype->pszUser); + cJSON_AddStringToObject(root, "proto", PROTO); + cJSON_AddStringToObject(root, "buid", pszBuddy); + cJSON_AddStringToObject(root, "msg", pszMessage); + if (pszRet = (IMO_API_VERSION==0?ImoRq_PostAmy(hSkype->hRq, "send_im", root):ImoRq_PostToSys (hSkype->hRq, "send_im", "im", root, 0, &hSkype->request_id))) + iRet = CheckReturn(hSkype, pszRet, "ok")>0; + if (prequest_id) *prequest_id = hSkype->request_id; + hSkype->request_id++; + cJSON_Delete(root); + return iRet; +} + +// ----------------------------------------------------------------------------- + +// pszStatus: +// Valid states: +// available +// away +// busy +// invisible +// +// -1 - Error +// 0 - Failed +// 1 - OK +int ImoSkype_SetStatus(IMOSKYPE *hSkype, char *pszStatus, char *pszStatusMsg) +{ + cJSON *root; + char *pszRet; + int iRet = -1; + + /* + if (!hSkype->pszUser || !(root=cJSON_CreateObject())) return 0; + cJSON_AddStringToObject(root, "uid", hSkype->pszUser); + cJSON_AddStringToObject(root, "proto", PROTO); + cJSON_AddStringToObject(root, "ssid", ImoRq_SessId(hSkype->hRq)); + cJSON_AddStringToObject(root, "ad", ""); + cJSON_AddStringToObject(root, "primitive", pszStatus); + cJSON_AddStringToObject(root, "status", pszStatusMsg); + if (pszRet = ImoRq_PostAmy(hSkype->hRq, "set_status", root)) + iRet = CheckReturn(hSkype, pszRet, "ok")>0; + */ + + if (!hSkype || !hSkype->pszUser || !(root=cJSON_CreateObject())) return 0; + cJSON_AddStringToObject(root, "ssid", ImoRq_SessId(hSkype->hRq)); + cJSON_AddStringToObject(root, "ad", ""); + cJSON_AddStringToObject(root, "primitive", pszStatus); + cJSON_AddStringToObject(root, "status", pszStatusMsg); + cJSON_AddFalseToObject (root, "auto_away"); + if (pszRet = ImoRq_PostToSys(hSkype->hRq, "set_status", "session", root, 0, NULL)) + iRet = CheckReturn(hSkype, pszRet, "ok")>0; + + cJSON_Delete(root); + return iRet; +} + +// ----------------------------------------------------------------------------- + +// -1 - Error +// 0 - Failed +// 1 - OK +int ImoSkype_AddBuddy(IMOSKYPE *hSkype, char *pszBuddy) +{ + return ManageBuddy (hSkype, "add_buddy", pszBuddy, "Offline"); +} + +// ----------------------------------------------------------------------------- + +// pszGroup = "Offline" if the user if offline, otherwise "Skype" or "Buddies" +// -1 - Error +// 0 - Failed +// 1 - OK +int ImoSkype_DelBuddy(IMOSKYPE *hSkype, char *pszBuddy, char *pszGroup) +{ + int iRet = ManageBuddy (hSkype, "del_buddy", pszBuddy, pszGroup); + + if (iRet<1 && strcmp(pszGroup, "Skype")==0) + return ManageBuddy (hSkype, "del_buddy", pszBuddy, "Buddies"); + return iRet; +} +// ----------------------------------------------------------------------------- + +int ImoSkype_BlockBuddy(IMOSKYPE *hSkype, char *pszBuddy) +{ + return ManageBuddy (hSkype, "block_buddy", pszBuddy, NULL); +} + +// ----------------------------------------------------------------------------- + +int ImoSkype_UnblockBuddy(IMOSKYPE *hSkype, char *pszBuddy) +{ + return ManageBuddy (hSkype, "unblock_buddy", pszBuddy, NULL); +} + +// ----------------------------------------------------------------------------- + +int ImoSkype_ChangeAlias(IMOSKYPE *hSkype, char *pszBuddy, char *pszNewAlias) +{ + cJSON *root; + char *pszRet; + int iRet = -1; + + if (!hSkype->pszUser || !(root=cJSON_CreateObject())) return 0; + cJSON_AddStringToObject(root, "ssid", ImoRq_SessId(hSkype->hRq)); + cJSON_AddStringToObject(root, "uid", hSkype->pszUser); + cJSON_AddStringToObject(root, "proto", PROTO); + cJSON_AddStringToObject(root, "buid", pszBuddy); + cJSON_AddStringToObject(root, "alias", pszNewAlias); + if (pszRet = ImoRq_PostAmy(hSkype->hRq, "change_buddy_alias", root)) + iRet = CheckReturn(hSkype, pszRet, "ok")>0; + cJSON_Delete(root); + return iRet; +} + +// ----------------------------------------------------------------------------- + +int ImoSkype_StartVoiceCall(IMOSKYPE *hSkype, char *pszBuddy) +{ + cJSON *root; + char *pszRet; + int iRet = -1; + + if (!hSkype->pszUser || !(root=cJSON_CreateObject())) return 0; + cJSON_AddStringToObject(root, "ssid", ImoRq_SessId(hSkype->hRq)); + cJSON_AddStringToObject(root, "uid", hSkype->pszUser); + cJSON_AddStringToObject(root, "proto", PROTO); + cJSON_AddStringToObject(root, "buid", pszBuddy); + if (pszRet = ImoRq_PostToSys (hSkype->hRq, "start_audio_chat", "av", root, 1, NULL)) + iRet = CheckReturn(hSkype, pszRet, "ok")>0; + return iRet; +} + +// ----------------------------------------------------------------------------- + +int ImoSkype_Ping(IMOSKYPE *hSkype) +{ + char *pszRet; + int iRet = -1; + + if (pszRet = ImoRq_Echo(hSkype->hRq)) + iRet = CheckReturn(hSkype, pszRet, "ok")>0; + return iRet; +} + +// ----------------------------------------------------------------------------- + +char *ImoSkype_GetAvatar(IMOSKYPE *hSkype, char *pszID, unsigned int *pdwLength) +{ + char szURL[256]; + + sprintf (szURL, "%sb/%s", ImoRq_GetHost(hSkype->hRq), pszID); + return ImoRq_HTTPGet (hSkype->hRq, szURL, pdwLength); +} + +// ----------------------------------------------------------------------------- + +int ImoSkype_GetUnreadMsgs(IMOSKYPE *hSkype) +{ + cJSON *root; + char *pszRet; + int iRet = -1; + + if (!hSkype->pszUser || !(root=cJSON_CreateObject())) return 0; + cJSON_AddStringToObject(root, "ssid", ImoRq_SessId(hSkype->hRq)); + cJSON_AddStringToObject(root, "uid", hSkype->pszUser); + cJSON_AddStringToObject(root, "proto", PROTO); + if (pszRet = ImoRq_PostAmy(hSkype->hRq, "get_unread_msgs", root)) + iRet = CheckReturn(hSkype, pszRet, "ok")>0; + cJSON_Delete(root); + return iRet; +} + +// ----------------------------------------------------------------------------- + +int ImoSkype_GetAlpha(IMOSKYPE *hSkype) +{ + cJSON *root; + char *pszRet; + int iRet = -1; + + if (!hSkype->pszUser || !(root=cJSON_CreateObject())) return 0; + cJSON_AddStringToObject(root, "ssid", ImoRq_SessId(hSkype->hRq)); + cJSON_AddStringToObject(root, "uid", hSkype->pszUser); + cJSON_AddStringToObject(root, "proto", PROTO); + if (pszRet = ImoRq_PostToSys (hSkype->hRq, "get_alpha_for_user", "alpha", root, 1, NULL)) + iRet = CheckReturn(hSkype, pszRet, "ok")>0; + return iRet; +} + +// ----------------------------------------------------------------------------- + + +int ImoSkype_CreateSharedGroup(IMOSKYPE *hSkype, char *pszName) +{ + cJSON *root; + char *pszRet; + int iRet = -1; + + if (!hSkype->pszUser || !(root=cJSON_CreateObject())) return 0; + cJSON_AddStringToObject(root, "ssid", ImoRq_SessId(hSkype->hRq)); + cJSON_AddStringToObject(root, "uid", hSkype->pszUser); + cJSON_AddStringToObject(root, "proto", PROTO); + cJSON_AddFalseToObject(root, "is_native"); // TRUE would be great, but not yet supported? + cJSON_AddStringToObject(root, "name", pszName); + if (pszRet = ImoRq_PostAmy(hSkype->hRq, "create_shared_group", root)) + iRet = CheckReturn(hSkype, pszRet, "ok")>0; + cJSON_Delete(root); + return iRet; +} + +// ----------------------------------------------------------------------------- + +int ImoSkype_GroupInvite(IMOSKYPE *hSkype, char *pszGroup, char *pszUser) +{ + cJSON *root; + char *pszRet, *p, *pszGroupDup = strdup(pszGroup); + int iRet = -1; + + if (p=strrchr(pszGroupDup, ';')) *p=0; + if (!hSkype->pszUser || !(root=cJSON_CreateObject())) return 0; + cJSON_AddStringToObject(root, "ssid", ImoRq_SessId(hSkype->hRq)); + cJSON_AddStringToObject(root, "uid", hSkype->pszUser); + cJSON_AddStringToObject(root, "proto", PROTO); + cJSON_AddStringToObject(root, "gid", pszGroupDup); + cJSON_AddStringToObject(root, "iproto", PROTO); + cJSON_AddStringToObject(root, "iuid", hSkype->pszUser); + cJSON_AddStringToObject(root, "ibuid", pszUser); + if (pszRet = ImoRq_PostAmy(hSkype->hRq, "invite_to_group", root)) + iRet = CheckReturn(hSkype, pszRet, "ok")>0; + free (pszGroupDup); + cJSON_Delete(root); + return iRet; +} + +// ----------------------------------------------------------------------------- + +int ImoSkype_GroupKick(IMOSKYPE *hSkype, char *pszGroup, char *pszUser) +{ + cJSON *root; + char *pszRet, *p, *pszGroupDup = strdup(pszGroup), szBUID[256]; + int iRet = -1; + + if (p=strrchr(pszGroupDup, ';')) *p=0; + sprintf (szBUID, "%s;%s;"PROTO, pszGroupDup, pszUser); + if (!hSkype->pszUser || !(root=cJSON_CreateObject())) return 0; + cJSON_AddStringToObject(root, "ssid", ImoRq_SessId(hSkype->hRq)); + cJSON_AddStringToObject(root, "uid", hSkype->pszUser); + cJSON_AddStringToObject(root, "proto", PROTO); + cJSON_AddStringToObject(root, "buid", szBUID); + if (pszRet = ImoRq_PostAmy(hSkype->hRq, "kick_member", root)) + iRet = CheckReturn(hSkype, pszRet, "ok")>0; + free (pszGroupDup); + cJSON_Delete(root); + return iRet; +} + +// ----------------------------------------------------------------------------- + +int ImoSkype_GroupTopic(IMOSKYPE *hSkype, char *pszGroup, char *pszTopic) +{ + cJSON *root; + char *pszRet, *p, *pszGroupDup = strdup(pszGroup); + int iRet = -1; + + if (p=strrchr(pszGroupDup, ';')) *p=0; + if (!hSkype->pszUser || !(root=cJSON_CreateObject())) return 0; + cJSON_AddStringToObject(root, "ssid", ImoRq_SessId(hSkype->hRq)); + cJSON_AddStringToObject(root, "uid", hSkype->pszUser); + cJSON_AddStringToObject(root, "proto", PROTO); + cJSON_AddStringToObject(root, "gid", pszGroupDup); + cJSON_AddStringToObject(root, "topic", pszTopic); + if (pszRet = ImoRq_PostAmy(hSkype->hRq, "set_group_topic", root)) + iRet = CheckReturn(hSkype, pszRet, "ok")>0; + free (pszGroupDup); + cJSON_Delete(root); + return iRet; +} + +// ----------------------------------------------------------------------------- + +int ImoSkype_GroupLeave(IMOSKYPE *hSkype, char *pszGroup) +{ + cJSON *root; + char *pszRet, *p, *pszGroupDup = strdup(pszGroup); + int iRet = -1; + + if (p=strrchr(pszGroupDup, ';')) *p=0; + if (!hSkype->pszUser || !(root=cJSON_CreateObject())) return 0; + cJSON_AddStringToObject(root, "ssid", ImoRq_SessId(hSkype->hRq)); + cJSON_AddStringToObject(root, "uid", hSkype->pszUser); + cJSON_AddStringToObject(root, "proto", PROTO); + cJSON_AddStringToObject(root, "gid", pszGroupDup); + if (pszRet = ImoRq_PostAmy(hSkype->hRq, "leave_group", root)) + iRet = CheckReturn(hSkype, pszRet, "ok")>0; + free (pszGroupDup); + cJSON_Delete(root); + return iRet; +} + +// ----------------------------------------------------------------------------- +// Static +// ----------------------------------------------------------------------------- +static void PostDisconnect(IMOSKYPE *hSkype) +{ + cJSON *arr, *root; + + if (arr = cJSON_CreateArray()) + { + if (!(root=cJSON_CreateObject())) return; + cJSON_AddStringToObject(root, "name", "disconnect"); + cJSON_AddItemToArray (arr, root); + hSkype->StatusCb(arr, hSkype->pUser); + cJSON_Delete(arr); + } +} + +// 0 - Unexpected answer +// 1 - Got back JSON data, notified callback +// 2 - Received expected message pszExpected [deprecated] +static int CheckReturn (IMOSKYPE *hSkype, char *pszMsg, char *pszExpected) +{ + cJSON *root, *data, *msgs, *msg, *sys, *arr, *prefs, *pref; + char *pszMethod, *pszSys; + + hSkype->pszLastRes = pszMsg; + if (root = cJSON_Parse(pszMsg)) + { + // Now let's see if this one is interesting for our system + if ((data = cJSON_GetObjectItem(root,"method")) && + (pszMethod = data->valuestring) && + strcmp(pszMethod, "forward_to_client") == 0 && + (data = cJSON_GetObjectItem(root,"data")) && + (msgs = cJSON_GetObjectItem(data,"messages"))) + { + int i, iCount = cJSON_GetArraySize(msgs); + + if (!iCount && pszExpected && strcmp(pszExpected, "ok") == 0) + { + if ((sys = cJSON_GetObjectItem(data,"ack")) && (unsigned long)sys->valueint >= ImoRq_GetSeq(hSkype->hRq)) + return 2; // imoim ACKnowledged this + else + { + if (sys && sys->valueint==0) + { + // ACK error, reset to 0, better reset the connection + PostDisconnect(hSkype); + } + return 0; // No ACK, sequence number not incremented :( + } + } + for (i=0; ivaluestring) && + strcmp (pszSys, "client") == 0) + { + if (sys = cJSON_GetObjectItem(msg,"seq")) + { + ImoRq_UpdateAck(hSkype->hRq, sys->valueint+1); + ImoRq_UpdateAck(hSkype->hPoll, sys->valueint+1); + } + + // Callback is only called for system IM + if ((sys = cJSON_GetObjectItem(msg,"from")) && + (pszSys = cJSON_GetObjectItem(sys, "system")->valuestring)) + { + if ((strcmp (pszSys, "im") == 0 || strcmp (pszSys, "av") == 0) && + (data = cJSON_GetObjectItem(msg,"data")) && + (arr = cJSON_CreateArray())) + { + // Pack data into array for Callback backwards + // compatibility + cJSON *next; + + next = data->next; + data->next = NULL; + cJSON_AddItemToArray (arr, data); + hSkype->StatusCb(arr, hSkype->pUser); + data->next = next; + free(arr); + } + else if (strcmp (pszSys, "internal") == 0 && + (data = cJSON_GetObjectItem(msg,"data")) && + (arr = cJSON_CreateArray())) + { + // Pack ACK msgs into a fake "ack" method so that callback + // function can dispatch them without interface change + cJSON *next; + + cJSON_AddStringToObject (data, "name", "ack"); + next = data->next; + data->next = NULL; + cJSON_AddItemToArray (arr, data); + hSkype->StatusCb(arr, hSkype->pUser); + data->next = next; + free(arr); + } + // Ensure to disable annoying autoaway + else if (strcmp (pszSys, "preference") == 0 && + (data = cJSON_GetObjectItem(msg,"data")) && + (prefs = cJSON_GetObjectItem(data, "preferences"))) + { + int j, nPrefs = cJSON_GetArraySize(prefs); + cJSON *kind, *thispref, *value, *prefdata; + + for (j=0; jvaluestring, "impref") == 0 && + (thispref = cJSON_GetObjectItem(pref, "pref")) && + strcmp (thispref->valuestring, "auto_away") == 0 && + (value = cJSON_GetObjectItem(pref, "value")) && + value->type == cJSON_True && hSkype->pszUser && + (prefdata = cJSON_CreateObject())) + { + cJSON *accs, *acc, *setprefs, *newpref; + + if (accs = cJSON_CreateArray()) + { + if (acc = cJSON_CreateObject()) + { + cJSON_AddStringToObject(acc, "uid", hSkype->pszUser); + cJSON_AddStringToObject(acc, "proto", PROTO); + cJSON_AddItemToArray (accs, acc); + } + cJSON_AddItemToObject(prefdata, "accounts", accs); + } + if (setprefs = cJSON_CreateArray()) + { + if (newpref = cJSON_CreateObject()) + { + cJSON_AddStringToObject(newpref, "kind", kind->valuestring); + cJSON_AddStringToObject(newpref, "pref", thispref->valuestring); + cJSON_AddFalseToObject (newpref, "value"); + cJSON_AddItemToArray (setprefs, newpref); + } + cJSON_AddItemToObject(prefdata, "preferences", setprefs); + } + ImoRq_PostToSys (hSkype->hRq, "set", "preference", prefdata, 1, NULL); + } + } + } + else if (strcmp (pszSys, "reset") == 0) + { + // System requested to reset connection + // Let's issue a "disconnect" to the callback to let it handle + // this situation + } + } + } + } + } + } + cJSON_Delete(root); + return 1; + } + else + { + if (pszExpected && strcmp(pszMsg, pszExpected)==0) + return 2; + } + return 0; +} + +// ----------------------------------------------------------------------------- + +static int ManageBuddy(IMOSKYPE *hSkype, char *pszAction, char *pszBuddy, char *pszGroup) +{ + cJSON *root; + char *pszRet; + int iRet = -1; + + if (!hSkype->pszUser || !(root=cJSON_CreateObject())) return 0; + cJSON_AddStringToObject(root, "ssid", ImoRq_SessId(hSkype->hRq)); + cJSON_AddStringToObject(root, "uid", hSkype->pszUser); + cJSON_AddStringToObject(root, "proto", PROTO); + cJSON_AddStringToObject(root, "buid", pszBuddy); + if (pszGroup) cJSON_AddStringToObject(root, "group", pszGroup); + if (pszRet = ImoRq_PostAmy(hSkype->hRq, pszAction, root)) + iRet = CheckReturn(hSkype, pszRet, "ok")>0; + cJSON_Delete(root); + return iRet; +} diff --git a/plugins/IMO2sProxy/src/imolib/imo_skype.h b/plugins/IMO2sProxy/src/imolib/imo_skype.h new file mode 100644 index 0000000000..d9e1697ed6 --- /dev/null +++ b/plugins/IMO2sProxy/src/imolib/imo_skype.h @@ -0,0 +1,37 @@ +#include "cJSON.h" + +struct _tagIMOSKYPE; +typedef struct _tagIMOSKYPE IMOSKYPE; +// 0 - Message received, you may delete the cJSON object now +// 1 - Don't delete cJSON object, callback will take care of freeing +typedef int(*IMOSTATCB)(cJSON *pMsg, void *pUser); + +IMOSKYPE *ImoSkype_Init(IMOSTATCB StatusCb, void *pUser); +void ImoSkype_Exit(IMOSKYPE *hSkype); +void ImoSkype_CancelPolling(IMOSKYPE *hSkype); +char *ImoSkype_GetLastError(IMOSKYPE *hSkype); +char *ImoSkype_GetUserHandle(IMOSKYPE *hSkype); + +int ImoSkype_Login(IMOSKYPE *hSkype, char *pszUser, char *pszPass); +int ImoSkype_Logout(IMOSKYPE *hSkype); +int ImoSkype_Poll(IMOSKYPE *hSkype); +int ImoSkype_Typing(IMOSKYPE *hSkype, char *pszBuddy, char *pszStatus); +int ImoSkype_SetStatus(IMOSKYPE *hSkype, char *pszStatus, char *pszStatusMsg); +int ImoSkype_SendMessage(IMOSKYPE *hSkype, char *pszBuddy, char *pszMessage, int *prequest_id); +int ImoSkype_AddBuddy(IMOSKYPE *hSkype, char *pszBuddy); +int ImoSkype_DelBuddy(IMOSKYPE *hSkype, char *pszBuddy, char *pszGroup); +int ImoSkype_BlockBuddy(IMOSKYPE *hSkype, char *pszBuddy); +int ImoSkype_UnblockBuddy(IMOSKYPE *hSkype, char *pszBuddy); +int ImoSkype_ChangeAlias(IMOSKYPE *hSkype, char *pszBuddy, char *pszNewAlias); +int ImoSkype_StartVoiceCall(IMOSKYPE *hSkype, char *pszBuddy); +int ImoSkype_KeepAlive(IMOSKYPE *hSkype); +int ImoSkype_Ping(IMOSKYPE *hSkype); +char *ImoSkype_GetAvatar(IMOSKYPE *hSkype, char *pszID, unsigned int *pdwLength); +int ImoSkype_GetUnreadMsgs(IMOSKYPE *hSkype); +int ImoSkype_GetAlpha(IMOSKYPE *hSkype); + +int ImoSkype_CreateSharedGroup(IMOSKYPE *hSkype, char *pszName); +int ImoSkype_GroupInvite(IMOSKYPE *hSkype, char *pszGroup, char *pszUser); +int ImoSkype_GroupKick(IMOSKYPE *hSkype, char *pszGroup, char *pszUser); +int ImoSkype_GroupTopic(IMOSKYPE *hSkype, char *pszGroup, char *pszTopic); +int ImoSkype_GroupLeave(IMOSKYPE *hSkype, char *pszGroup); diff --git a/plugins/IMO2sProxy/src/imolib/io_layer.c b/plugins/IMO2sProxy/src/imolib/io_layer.c new file mode 100644 index 0000000000..1e18464682 --- /dev/null +++ b/plugins/IMO2sProxy/src/imolib/io_layer.c @@ -0,0 +1,175 @@ +/* Module: io_layer.c + Purpose: IO Layer for Internet communication using libcurl + Author: leecher + Date: 30.08.2009 +*/ +#include +#include +#include +#include +#include "fifo.h" +#include "io_layer.h" + +typedef struct +{ + IOLAYER vtbl; + CURL *hCurl; + TYP_FIFO *hResult; + char szErrorBuf[CURL_ERROR_SIZE+1]; +} IOLAYER_INST; + +static void IoLayer_Exit (IOLAYER *hPIO); +static char *IoLayer_Post(IOLAYER *hPIO, char *pszUrl, char *pszPostFields, unsigned int cbPostFields, unsigned int *pdwLength); +static char *IoLayer_Get(IOLAYER *hPIO, char *pszUrl, unsigned int *pdwLength); +static void IoLayer_Cancel(IOLAYER *hIO); +static char *IoLayer_GetLastError(IOLAYER *hIO); +static char *IoLayer_EscapeString(IOLAYER *hIO, char *pszData); +static void IoLayer_FreeEscapeString(char *pszData); +static size_t add_data(char *data, size_t size, size_t nmemb, void *ctx); + +// ----------------------------------------------------------------------------- +// Interface +// ----------------------------------------------------------------------------- + +IOLAYER *IoLayerCURL_Init(void) +{ + IOLAYER_INST *hIO; + + if (!(hIO = calloc(1, sizeof(IOLAYER_INST)))) + return NULL; + + if (!(hIO->hCurl = curl_easy_init())) + { + free (hIO); + return NULL; + } + + if (!(hIO->hResult = Fifo_Init(1024))) + { + IoLayer_Exit((IOLAYER*)hIO); + return NULL; + } + + curl_easy_setopt(hIO->hCurl, CURLOPT_USERAGENT, "XMLHttpRequest/1.0"); + curl_easy_setopt(hIO->hCurl, CURLOPT_HEADER, 0); + curl_easy_setopt(hIO->hCurl, CURLOPT_AUTOREFERER, 1); +// curl_easy_setopt(hRq->hCurl, CURLOPT_RETURNTRANSFER, 1); + curl_easy_setopt(hIO->hCurl, CURLOPT_SSL_VERIFYPEER, 0); + curl_easy_setopt(hIO->hCurl, CURLOPT_SSL_VERIFYHOST, 0); + curl_easy_setopt(hIO->hCurl, CURLOPT_ERRORBUFFER, hIO->szErrorBuf); + curl_easy_setopt(hIO->hCurl, CURLOPT_COOKIEFILE, "cookies.txt"); + curl_easy_setopt(hIO->hCurl, CURLOPT_COOKIEJAR, "cookies.txt"); + curl_easy_setopt(hIO->hCurl, CURLOPT_WRITEFUNCTION, add_data); + curl_easy_setopt(hIO->hCurl, CURLOPT_FILE, hIO); + + // Init Vtbl + hIO->vtbl.Exit = IoLayer_Exit; + hIO->vtbl.Post = IoLayer_Post; + hIO->vtbl.Get = IoLayer_Get; + hIO->vtbl.Cancel = IoLayer_Cancel; + hIO->vtbl.GetLastError = IoLayer_GetLastError; + hIO->vtbl.EscapeString = IoLayer_EscapeString; + hIO->vtbl.FreeEscapeString = IoLayer_FreeEscapeString; + + return (IOLAYER*)hIO; +} + +// ----------------------------------------------------------------------------- + +static void IoLayer_Exit (IOLAYER *hPIO) +{ + IOLAYER_INST *hIO = (IOLAYER_INST*)hPIO; + + if (hIO->hCurl) curl_easy_cleanup(hIO->hCurl); + if (hIO->hResult) Fifo_Exit(hIO->hResult); + free (hIO); +} + +// ----------------------------------------------------------------------------- + +static char *IoLayer_Post(IOLAYER *hPIO, char *pszUrl, char *pszPostFields, unsigned int cbPostFields, unsigned int *pdwLength) +{ + IOLAYER_INST *hIO = (IOLAYER_INST*)hPIO; + + curl_easy_setopt(hIO->hCurl, CURLOPT_POST, 1); + curl_easy_setopt(hIO->hCurl, CURLOPT_URL, pszUrl); + curl_easy_setopt(hIO->hCurl, CURLOPT_POSTFIELDS, pszPostFields); + curl_easy_setopt(hIO->hCurl, CURLOPT_POSTFIELDSIZE, cbPostFields); + if (curl_easy_perform(hIO->hCurl)) return NULL; + if (!pdwLength) + { + // Get string + Fifo_Add (hIO->hResult, "", 1); + return Fifo_Get (hIO->hResult, NULL); + } + else + { + // Get binary, return size of buffer + *pdwLength = (unsigned int)-1; + return Fifo_Get (hIO->hResult, pdwLength); + } +} + +// ----------------------------------------------------------------------------- + +static char *IoLayer_Get(IOLAYER *hPIO, char *pszUrl, unsigned int *pdwLength) +{ + IOLAYER_INST *hIO = (IOLAYER_INST*)hPIO; + + curl_easy_setopt(hIO->hCurl, CURLOPT_POST, 0); + curl_easy_setopt(hIO->hCurl, CURLOPT_URL, pszUrl); + if (curl_easy_perform(hIO->hCurl)) return NULL; + if (!pdwLength) + { + // Get string + Fifo_Add (hIO->hResult, "", 1); + return Fifo_Get (hIO->hResult, NULL); + } + else + { + // Get binary, return size of buffer + *pdwLength = (unsigned int)-1; + return Fifo_Get (hIO->hResult, pdwLength); + } +} + +// ----------------------------------------------------------------------------- + +static void IoLayer_Cancel(IOLAYER *hIO) +{ + // FIXME: Currently not implemented +} + +// ----------------------------------------------------------------------------- + +static char *IoLayer_GetLastError(IOLAYER *hIO) +{ + return ((IOLAYER_INST*)hIO)->szErrorBuf; +} + +// ----------------------------------------------------------------------------- + +static char *IoLayer_EscapeString(IOLAYER *hIO, char *pszData) +{ + return curl_easy_escape(((IOLAYER_INST*)hIO)->hCurl, pszData, 0); +} + +// ----------------------------------------------------------------------------- + +static void IoLayer_FreeEscapeString(char *pszData) +{ + curl_free(pszData); +} + +// ----------------------------------------------------------------------------- +// Static +// ----------------------------------------------------------------------------- + +static size_t add_data(char *data, size_t size, size_t nmemb, void *ctx) +{ + IOLAYER_INST *hIO = (IOLAYER_INST*)ctx; + + if (Fifo_Add(hIO->hResult, data, size * nmemb)) return size * nmemb; + return 0; +} + diff --git a/plugins/IMO2sProxy/src/imolib/io_layer.h b/plugins/IMO2sProxy/src/imolib/io_layer.h new file mode 100644 index 0000000000..13e10cf888 --- /dev/null +++ b/plugins/IMO2sProxy/src/imolib/io_layer.h @@ -0,0 +1,25 @@ +#ifndef _IOLAYER_H_ +#define _IOLAYER_H_ + +struct _tagIOLAYER; +typedef struct _tagIOLAYER IOLAYER; + +struct _tagIOLAYER +{ + void (*Exit) (IOLAYER *hIO); + + char *(*Post) (IOLAYER *hIO, char *pszURL, char *pszPostFields, unsigned int cbPostFields, unsigned int *pdwLength); + char *(*Get) (IOLAYER *hIO, char *pszURL, unsigned int *pdwLength); + void (*Cancel) (IOLAYER *hIO); + char *(*GetLastError) (IOLAYER *hIO); + char *(*EscapeString) (IOLAYER *hIO, char *pszData); + void (*FreeEscapeString) (char *pszData); +}; + +#ifdef WIN32 +IOLAYER *IoLayerW32_Init(void); +IOLAYER *IoLayerNETLIB_Init(void); +#endif +IOLAYER *IoLayerCURL_Init(void); + +#endif diff --git a/plugins/IMO2sProxy/src/imolib/io_layer_win32.c b/plugins/IMO2sProxy/src/imolib/io_layer_win32.c new file mode 100644 index 0000000000..1fd425ced7 --- /dev/null +++ b/plugins/IMO2sProxy/src/imolib/io_layer_win32.c @@ -0,0 +1,440 @@ +/* Module: io_layer_win32.c + Purpose: IO Layer for Internet communication using WININET (Win32) + Author: leecher + Date: 30.08.2009 +*/ +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#include +#include +#include "fifo.h" +#include "io_layer.h" + +#ifndef LongToPtr +#define DWORD_PTR DWORD +#endif + +/* Set this to use asynchronous I/O + This is needed as synchronous WININET functions tend to block forever on connection + loss or other occasions leading to a deadlock of the whole application + */ +#define ASYNC +#define ASYNC_CONN_TIMEOUT 5000 // Connection timeout in ms +#define ASYNC_REQ_TIMEOUT 40000 // HttpSendRequest timeout in ms in async mode (Should be at least 30 sec!) + +#pragma comment(lib,"wininet.lib") + +#define INET_FLAGS INTERNET_FLAG_IGNORE_CERT_CN_INVALID | INTERNET_FLAG_IGNORE_CERT_DATE_INVALID | \ + INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_UI | \ + INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_SECURE + +typedef struct +{ + IOLAYER vtbl; + HINTERNET hInet; + HINTERNET hRequest; +#ifdef ASYNC + INTERNET_ASYNC_RESULT stAsyncRes; + HANDLE hConnectedEvent; + HANDLE hRequestCompleteEvent; +#endif + TYP_FIFO *hResult; + LPVOID lpErrorBuf; +} IOLAYER_INST; + +static void IoLayer_Exit (IOLAYER *hPIO); +static char *IoLayer_Post(IOLAYER *hPIO, char *pszURL, char *pszPostFields, unsigned int cbPostFields, unsigned int *pdwLength); +static char *IoLayer_Get(IOLAYER *hIO, char *pszURL, unsigned int *pdwLength); +static void IoLayer_Cancel(IOLAYER *hIO); +static char *IoLayer_GetLastError(IOLAYER *hIO); +static char *IoLayer_EscapeString(IOLAYER *hPIO, char *pszData); +static void IoLayer_FreeEscapeString(char *pszData); +static void FetchLastError (IOLAYER_INST *hIO); +#ifdef ASYNC +static void __stdcall Callback(HINTERNET hInternet, DWORD dwContext, DWORD dwInternetStatus, + LPVOID lpStatusInfo, DWORD dwStatusInfoLen); +#endif + +// ----------------------------------------------------------------------------- +// Interface +// ----------------------------------------------------------------------------- + +IOLAYER *IoLayerW32_Init(void) +{ + IOLAYER_INST *hIO; + + if (!(hIO = calloc(1, sizeof(IOLAYER_INST)))) + return NULL; + + // Init Inet + if (!(hIO->hInet = InternetOpen ("Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13", + INTERNET_OPEN_TYPE_PRECONFIG, NULL, "", +#ifdef ASYNC + INTERNET_FLAG_ASYNC +#else + 0 +#endif + ))) + { + free (hIO); + return NULL; + } + + if (!(hIO->hResult = Fifo_Init(1024))) + { + IoLayer_Exit((IOLAYER*)hIO); + return NULL; + } + +#ifdef ASYNC + if (InternetSetStatusCallback(hIO->hInet, (INTERNET_STATUS_CALLBACK)&Callback) == INTERNET_INVALID_STATUS_CALLBACK) + { + IoLayer_Exit((IOLAYER*)hIO); + return NULL; + } + + hIO->hConnectedEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + hIO->hRequestCompleteEvent = CreateEvent(NULL, FALSE, FALSE, NULL); +#endif + + //InternetSetCookie ("https://o.imo.im/", "proto", "prpl-skype"); + + // Init Vtbl + hIO->vtbl.Exit = IoLayer_Exit; + hIO->vtbl.Post = IoLayer_Post; + hIO->vtbl.Get = IoLayer_Get; + hIO->vtbl.Cancel = IoLayer_Cancel; + hIO->vtbl.GetLastError = IoLayer_GetLastError; + hIO->vtbl.EscapeString = IoLayer_EscapeString; + hIO->vtbl.FreeEscapeString = IoLayer_FreeEscapeString; + + return (IOLAYER*)hIO; +} +// ----------------------------------------------------------------------------- + +static void IoLayer_Exit (IOLAYER *hPIO) +{ + IOLAYER_INST *hIO = (IOLAYER_INST*)hPIO; + + if (hIO->hInet) InternetCloseHandle (hIO->hInet); + if (hIO->lpErrorBuf) LocalFree(hIO->lpErrorBuf); + if (hIO->hResult) Fifo_Exit(hIO->hResult); + +#ifdef ASYNC + if (hIO->hConnectedEvent) CloseHandle (hIO->hConnectedEvent); + if (hIO->hRequestCompleteEvent) CloseHandle (hIO->hRequestCompleteEvent); +#endif + free (hIO); +} + +// ----------------------------------------------------------------------------- + +static char *IoLayer_Post(IOLAYER *hPIO, char *pszURL, char *pszPostFields, unsigned int cbPostFields, unsigned int *pdwLength) +{ + IOLAYER_INST *hIO = (IOLAYER_INST*)hPIO; + URL_COMPONENTS urlInfo = {0}; + HINTERNET hUrl; + DWORD dwFlags = 0, cbFlags = sizeof(dwFlags), dwRemaining = 0; + char szHostName[INTERNET_MAX_HOST_NAME_LENGTH], + szURLPath[INTERNET_MAX_URL_LENGTH], *p; +#ifdef ASYNC + INTERNET_BUFFERS InetBuff={0}; + InetBuff.dwStructSize = sizeof(InetBuff); + + ResetEvent (hIO->hConnectedEvent); + ResetEvent (hIO->hRequestCompleteEvent); +#endif + +//OutputDebugString(pszPostFields); + urlInfo.dwStructSize = sizeof (URL_COMPONENTS); + urlInfo.lpszHostName = szHostName; + urlInfo.dwHostNameLength = sizeof(szHostName); + urlInfo.lpszUrlPath = szURLPath; + urlInfo.dwUrlPathLength = sizeof(szURLPath); + if (!InternetCrackUrl(pszURL, strlen(pszURL), 0, &urlInfo)) return NULL; + /* + if (!pszPostFields) + { + if (pszPostFields=strchr (pszURL, '?')) + cbPostFields = strlen(pszPostFields); + } + */ + if (!(hUrl = InternetConnect (hIO->hInet, szHostName, + INTERNET_DEFAULT_HTTPS_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, (DWORD_PTR)hIO))) + { +#ifdef ASYNC + if (GetLastError() == ERROR_IO_PENDING) + { + if (WaitForSingleObject(hIO->hConnectedEvent, ASYNC_CONN_TIMEOUT) == WAIT_OBJECT_0) + { + hUrl = (HINTERNET)hIO->stAsyncRes.dwResult; + hIO->stAsyncRes.dwResult = 0; + SetLastError(hIO->stAsyncRes.dwError); + } + } + if (!hUrl) +#endif + { + FetchLastError (hIO); + return NULL; + } + } + + hIO->hRequest = HttpOpenRequest (hUrl, pszPostFields?"POST":"GET", szURLPath, NULL, "https://imo.im/", NULL, + INET_FLAGS, (DWORD_PTR)hIO); + if (!hIO->hRequest) + { +#ifdef ASYNC + if (GetLastError() == ERROR_IO_PENDING) + { + if (WaitForSingleObject(hIO->hConnectedEvent, ASYNC_CONN_TIMEOUT) == WAIT_OBJECT_0) + { + hIO->hRequest = (HINTERNET)hIO->stAsyncRes.dwResult; + hIO->stAsyncRes.dwResult = 0; + SetLastError(hIO->stAsyncRes.dwError); + } + } + if (!hUrl) +#endif + { + FetchLastError (hIO); + InternetCloseHandle (hUrl); + return NULL; + } + } + + InternetQueryOption (hIO->hRequest, INTERNET_OPTION_SECURITY_FLAGS, (LPVOID)&dwFlags, &cbFlags); + dwFlags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA; + InternetSetOption (hIO->hRequest, INTERNET_OPTION_SECURITY_FLAGS, &dwFlags, sizeof (dwFlags)); + + /* + { + char szCookies[4096]; + DWORD cbCookies, dwIndex=0; + + OutputDebugString ("Sending headers:\n"); + do + { + cbCookies=sizeof(szCookies); + if (!HttpQueryInfo (hIO->hRequest, HTTP_QUERY_FLAG_REQUEST_HEADERS|HTTP_QUERY_RAW_HEADERS_CRLF, szCookies, &cbCookies, &dwIndex) || + GetLastError() != ERROR_SUCCESS) + break; + OutputDebugString (szCookies); + } while (1); + } + */ + +// ASYNC: This needs to block for at least 30 seconds on poll! + if (!(HttpSendRequest (hIO->hRequest, "Content-Type: application/x-www-form-urlencoded; charset=UTF-8\r\n" + "X-Requested-With: XMLHttpRequest", -1, + pszPostFields, cbPostFields))) + { +#ifdef ASYNC + BOOL bRes = FALSE; + + if (GetLastError() == ERROR_IO_PENDING) + { + if (WaitForSingleObject(hIO->hRequestCompleteEvent, ASYNC_REQ_TIMEOUT) == WAIT_OBJECT_0) + { + bRes = hIO->stAsyncRes.dwResult; + hIO->stAsyncRes.dwResult = 0; + SetLastError(hIO->stAsyncRes.dwError); + } + } + if (!bRes) +#endif + { + FetchLastError (hIO); + InternetCloseHandle (hIO->hRequest); + hIO->hRequest = NULL; + InternetCloseHandle (hUrl); + return NULL; + } + } +#ifdef ASYNC + else WaitForSingleObject(hIO->hRequestCompleteEvent, ASYNC_REQ_TIMEOUT); +#endif + + /* + { + char szCookies[4096]; + DWORD cbCookies, dwIndex=0; + + OutputDebugString ("Received headers:\n"); + do + { + cbCookies=sizeof(szCookies); + if (!HttpQueryInfo (hIO->hRequest, HTTP_QUERY_FLAG_REQUEST_HEADERS|HTTP_QUERY_RAW_HEADERS_CRLF, szCookies, &cbCookies, &dwIndex) || + GetLastError() != ERROR_SUCCESS) + break; + OutputDebugString (szCookies); + } while (1); + } + */ + +#ifdef ASYNC + do + { + if (!InternetQueryDataAvailable (hIO->hRequest, &InetBuff.dwBufferLength, 0, 0)) + { + BOOL bRes = FALSE; + + if (GetLastError() == ERROR_IO_PENDING) + { + if (WaitForSingleObject(hIO->hRequestCompleteEvent, ASYNC_REQ_TIMEOUT) == WAIT_OBJECT_0) + { + bRes = hIO->stAsyncRes.dwResult; + hIO->stAsyncRes.dwResult = 0; + SetLastError(hIO->stAsyncRes.dwError); + } + } + if (!bRes) break; + } + if (InetBuff.dwBufferLength == 0) break; + if (InetBuff.lpvBuffer = Fifo_AllocBuffer (hIO->hResult, InetBuff.dwBufferLength)) + { + if (!InternetReadFileEx (hIO->hRequest, &InetBuff, 0, (DWORD_PTR)hIO)) + { + BOOL bRes=FALSE; + + if (GetLastError() == ERROR_IO_PENDING) + { + if (WaitForSingleObject(hIO->hRequestCompleteEvent, ASYNC_REQ_TIMEOUT) == WAIT_OBJECT_0) + { + bRes = hIO->stAsyncRes.dwResult; + hIO->stAsyncRes.dwResult = 0; + SetLastError(hIO->stAsyncRes.dwError); + } + } + if (!bRes) break; + } + } + } + while(InetBuff.dwBufferLength); +#else + while (InternetQueryDataAvailable (hIO->hRequest, &dwRemaining, 0, 0) && dwRemaining > 0) + { + if (p = Fifo_AllocBuffer (hIO->hResult, dwRemaining)) + InternetReadFile (hIO->hRequest, p, dwRemaining, &dwRemaining); + } +#endif + + if (!pdwLength) + { + // Get string + Fifo_Add (hIO->hResult, "", 1); + p = Fifo_Get (hIO->hResult, NULL); + } + else + { + // Get binary, return size of buffer + *pdwLength = (unsigned int)-1; + p = Fifo_Get (hIO->hResult, pdwLength); + } + InternetCloseHandle (hIO->hRequest); + hIO->hRequest = NULL; + InternetCloseHandle (hUrl); +OutputDebugString(p); +OutputDebugString("\n"); + return p; +} + +// ----------------------------------------------------------------------------- + +static char *IoLayer_Get(IOLAYER *hIO, char *pszURL, unsigned int *pdwLength) +{ + return IoLayer_Post (hIO, pszURL, NULL, 0, pdwLength); +} + +// ----------------------------------------------------------------------------- + +static void IoLayer_Cancel(IOLAYER *hPIO) +{ + IOLAYER_INST *hIO = (IOLAYER_INST*)hPIO; + +#ifdef ASYNC + if (hIO->hRequest) + { + hIO->stAsyncRes.dwResult = 0; + hIO->stAsyncRes.dwError = ERROR_CANCELLED; + SetEvent(hIO->hRequestCompleteEvent); + } +#else + if (hIO->hRequest && InternetCloseHandle(hIO->hRequest)) + hIO->hRequest = NULL; +#endif +} + +// ----------------------------------------------------------------------------- + +static char *IoLayer_GetLastError(IOLAYER *hIO) +{ + return (char*)((IOLAYER_INST*)hIO)->lpErrorBuf; +} + +// ----------------------------------------------------------------------------- + +static char *IoLayer_EscapeString(IOLAYER *hPIO, char *pszData) +{ + IOLAYER_INST *hIO = (IOLAYER_INST*)hPIO; + TYP_FIFO *hFifo; + char szBuf[8], *pszRet; + unsigned char *p; + + if (!(hFifo = Fifo_Init(strlen(pszData)))) return NULL; + for (p=pszData; *p; p++) + { + if (isalnum(*p)) Fifo_Add (hFifo, p, 1); + else { + wsprintf (szBuf, "%%%02X", *p); + Fifo_Add (hFifo, szBuf, 3); + } + } + Fifo_Add (hFifo, "", 1); + if (pszRet = Fifo_Get(hFifo, NULL)) + pszRet = strdup(pszRet); + Fifo_Exit(hFifo); + return pszRet; +} + +// ----------------------------------------------------------------------------- + +static void IoLayer_FreeEscapeString(char *pszData) +{ + free (pszData); +} + +// ----------------------------------------------------------------------------- +// Static +// ----------------------------------------------------------------------------- + +static void FetchLastError (IOLAYER_INST *hIO) +{ + if (hIO->lpErrorBuf) LocalFree(hIO->lpErrorBuf); + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, + GetLastError(), MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT), + (LPTSTR)&hIO->lpErrorBuf, 0, NULL); +} + +#ifdef ASYNC +static void __stdcall Callback(HINTERNET hInternet, DWORD dwContext, DWORD dwInternetStatus, + LPVOID lpStatusInfo, DWORD dwStatusInfoLen) +{ + IOLAYER_INST *hIO = (IOLAYER_INST*)dwContext; + + + switch(dwInternetStatus) + { + case INTERNET_STATUS_HANDLE_CREATED: + SetEvent (hIO->hConnectedEvent); + break; + case INTERNET_STATUS_REQUEST_COMPLETE: + hIO->stAsyncRes = *((INTERNET_ASYNC_RESULT *)lpStatusInfo); + SetEvent(hIO->hRequestCompleteEvent); + break; + } +} +#endif \ No newline at end of file diff --git a/plugins/IMO2sProxy/src/imolib/skypetst.c b/plugins/IMO2sProxy/src/imolib/skypetst.c new file mode 100644 index 0000000000..5c80533eaf --- /dev/null +++ b/plugins/IMO2sProxy/src/imolib/skypetst.c @@ -0,0 +1,211 @@ +/* Module: skypetst.c + Purpose: Very simple and straight forward testing application for Skype imo.im service + Author: leecher + Date: 30.08.2009 +*/ + +#include +#include +#include +#include +#include +#ifdef WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#else +#include +#include +#endif +#include "imo_skype.h" + +static IMOSKYPE *m_hInst = NULL; + +// ----------------------------------------------------------------------------- +// Static +// ----------------------------------------------------------------------------- +static int StatusCallback (cJSON *pMsg, void *pUser) +{ + char *pszName; + cJSON *pContent = cJSON_GetArrayItem(pMsg, 0); + + if (!pContent) return; + pszName = cJSON_GetObjectItem(pContent,"name")->valuestring; + + if (!strcmp(pszName, "recv_im")) + { + // I got a message! + cJSON *pEdata = cJSON_GetObjectItem(pContent,"edata"); + + if (pEdata) + { + time_t timestamp = (time_t)cJSON_GetObjectItem(pEdata, "timestamp")->valueint; + char szTimestamp[32]; + + strftime (szTimestamp, sizeof(szTimestamp), "%d.%m.%Y %H.%M.%S", localtime(×tamp)); + printf ("[%s] %s: %s\n", szTimestamp, + cJSON_GetObjectItem(pEdata, "alias")->valuestring, + cJSON_GetObjectItem(pEdata, "msg")->valuestring); + } + } + else if (!strcmp(pszName, "signed_on")) + { + // I just signed on. + cJSON *pEdata = cJSON_GetObjectItem(pContent,"edata"); + char *pszAlias; + + if (pEdata && (pszAlias = cJSON_GetObjectItem(pEdata, "alias")->valuestring)) + { + printf ("My alias is: %s\n", pszAlias); + } + } + else if (!strcmp(pszName, "buddy_added") || !strcmp(pszName, "buddy_status")) + { + // Here comes the contact list + cJSON *pArray = cJSON_GetObjectItem(pContent,"edata"), *pItem; + int i, iCount; + + if (pArray) + { + for (i=0, iCount = cJSON_GetArraySize(pArray); ivaluestring, + cJSON_GetObjectItem(pItem, "buid")->valuestring, + cJSON_GetObjectItem(pItem, "primitive")->valuestring); + } + } + } + } + else + { + char *pszMsg = cJSON_Print(pMsg); + fprintf (stderr, "%s\n\n", pszMsg); + free (pszMsg); + } + + return 0; +} + +// ----------------------------------------------------------------------------- + +static void DispatcherThread(void *pDummy) +{ + while (1) + ImoSkype_Poll(m_hInst); +} + +// ----------------------------------------------------------------------------- + +#ifdef WIN32 +static HANDLE m_hThread; + +static int Dispatcher_Start(void) +{ + DWORD ThreadID; + + return (m_hThread=CreateThread(NULL, 0, + (LPTHREAD_START_ROUTINE)DispatcherThread, NULL, 0, &ThreadID))!=0; + +} + +static int Dispatcher_Stop(void) +{ + return TerminateThread (m_hThread, 0); +} + +#else +static pthread_t m_hThread; + +static int Dispatcher_Start(void) +{ + return pthread_create(&m_hThread, NULL, DispatcherThread, NULL)==0; +} + +static int Dispatcher_Stop(void) +{ + if (pthread_cancel(m_hThread)) + { + m_hThread=0; + return 1; + } + return 0; +} +#endif + +// ----------------------------------------------------------------------------- +// EIP +// ----------------------------------------------------------------------------- + +int main(int argc, char **argv) +{ + int iRet = -1; + + if (argc<3) + { + printf ("Usage: %s [username] [password]\n", argv[0]); + return -1; + } + + /* Logon */ + if (!(m_hInst = ImoSkype_Init(StatusCallback, NULL))) + { + fprintf (stderr, "Initializing failed.\n"); + return -1; + } + if (ImoSkype_Login(m_hInst, argv[1], argv[2]) == 1) + { + /* Dispatch loop */ + char szLine[4096]={0}; + + Dispatcher_Start(); + printf ("> "); + fflush(stdout); + while (gets(szLine)) + { + if (strcmp(szLine, "exit") == 0) break; + if (strcmp(szLine, "help") == 0) + { + printf ("msg [buddy] [message]\nstatus [available|away|busy|invisible] \nexit\n"); + } else + if (strncmp(szLine, "msg ", 4) == 0) + { + char *pszBuddy; + + if (pszBuddy = strtok (szLine+4, " ")) + { + if (ImoSkype_SendMessage(m_hInst, pszBuddy, pszBuddy+strlen(pszBuddy)+1)) + printf ("Sent.\n"); + else + printf ("Sending failed: %s.\n", ImoSkype_GetLastError(m_hInst)); + } + } else + if (strncmp(szLine, "status ", 7) == 0) + { + char *pszStatus; + + if (pszStatus = strtok (szLine+7, " ")) + { + if (ImoSkype_SetStatus(m_hInst, pszStatus, pszStatus+strlen(pszStatus)+1)) + printf ("Status set.\n"); + else + printf ("Setting status failed: %s.\n", ImoSkype_GetLastError(m_hInst)); + } + } + memset (szLine, 0, sizeof(szLine)); + printf ("> "); + fflush(stdout); + } + Dispatcher_Stop(); + ImoSkype_Logout(m_hInst); + } + else + { + fprintf (stderr, "Login failed: %s\n", ImoSkype_GetLastError(m_hInst)); + return -1; + } + + ImoSkype_Exit(m_hInst); + return iRet; +} -- cgit v1.2.3