From fd67a89688262e4e58337c33728488f5f29196a8 Mon Sep 17 00:00:00 2001 From: Szymon Tokarz Date: Wed, 17 Oct 2012 21:05:02 +0000 Subject: Tlen protocol adopted - code moved to trunk\protocols folder - update project files (based on rev: 27, 228, 204, 350, 279, 280, 1374, 278) - changed code organisation to c++ convention (based on rev: 1092, 503, 504) - changed code to Miranda NG convention (based on rev: 49, 54, 312, 401, 321, 358, 410, 441, 477, 483, 496, 507, 515, 644, 652, 743, 956, 1206, 667, 1040, 1590, 1857) - folders restructurization (based on rev: 1890) - code cleaning (based on rev: 270, 398, 409) - this commit includes adopted sources of tlen_czaty.dll (former mucc.dll) plugin witch is now deprecated and will be removed -- wsx22{at}o2.pl git-svn-id: http://svn.miranda-ng.org/main/trunk@1972 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- protocols/Tlen/src/codec/gsm.h | 65 + protocols/Tlen/src/codec/gsm_codec.c | 283 ++++ protocols/Tlen/src/codec/gsm_long.c | 183 +++ protocols/Tlen/src/codec/gsm_lpc.c | 208 +++ protocols/Tlen/src/codec/gsm_preprocess.c | 103 ++ protocols/Tlen/src/codec/gsm_rpe.c | 248 +++ protocols/Tlen/src/codec/gsm_short.c | 211 +++ protocols/Tlen/src/commons.h | 32 + protocols/Tlen/src/crypto/aes.c | 1336 ++++++++++++++++ protocols/Tlen/src/crypto/bignum.c | 2097 ++++++++++++++++++++++++++ protocols/Tlen/src/crypto/padlock.c | 162 ++ protocols/Tlen/src/crypto/polarssl/aes.h | 167 ++ protocols/Tlen/src/crypto/polarssl/bignum.h | 587 +++++++ protocols/Tlen/src/crypto/polarssl/bn_mul.h | 738 +++++++++ protocols/Tlen/src/crypto/polarssl/config.h | 625 ++++++++ protocols/Tlen/src/crypto/polarssl/padlock.h | 100 ++ protocols/Tlen/src/jabber.h | 507 +++++++ protocols/Tlen/src/jabber_iq.cpp | 114 ++ protocols/Tlen/src/jabber_iq.h | 61 + protocols/Tlen/src/jabber_iqid.cpp | 642 ++++++++ protocols/Tlen/src/jabber_list.cpp | 315 ++++ protocols/Tlen/src/jabber_list.h | 90 ++ protocols/Tlen/src/jabber_misc.cpp | 218 +++ protocols/Tlen/src/jabber_opt.cpp | 710 +++++++++ protocols/Tlen/src/jabber_svc.cpp | 1364 +++++++++++++++++ protocols/Tlen/src/jabber_thread.cpp | 1467 ++++++++++++++++++ protocols/Tlen/src/jabber_util.cpp | 647 ++++++++ protocols/Tlen/src/jabber_ws.cpp | 160 ++ protocols/Tlen/src/jabber_xml.cpp | 568 +++++++ protocols/Tlen/src/jabber_xml.h | 79 + protocols/Tlen/src/resource.h | 147 ++ protocols/Tlen/src/tlen.cpp | 524 +++++++ protocols/Tlen/src/tlen_advsearch.cpp | 113 ++ protocols/Tlen/src/tlen_avatar.cpp | 427 ++++++ protocols/Tlen/src/tlen_avatar.h | 34 + protocols/Tlen/src/tlen_file.cpp | 708 +++++++++ protocols/Tlen/src/tlen_file.h | 34 + protocols/Tlen/src/tlen_muc.cpp | 1069 +++++++++++++ protocols/Tlen/src/tlen_muc.h | 45 + protocols/Tlen/src/tlen_p2p_new.cpp | 352 +++++ protocols/Tlen/src/tlen_p2p_old.cpp | 535 +++++++ protocols/Tlen/src/tlen_p2p_old.h | 70 + protocols/Tlen/src/tlen_picture.cpp | 320 ++++ protocols/Tlen/src/tlen_picture.h | 33 + protocols/Tlen/src/tlen_presence.cpp | 318 ++++ protocols/Tlen/src/tlen_presence.h | 29 + protocols/Tlen/src/tlen_userinfo.cpp | 335 ++++ protocols/Tlen/src/tlen_voice.cpp | 1121 ++++++++++++++ protocols/Tlen/src/tlen_voice.h | 70 + 49 files changed, 20371 insertions(+) create mode 100644 protocols/Tlen/src/codec/gsm.h create mode 100644 protocols/Tlen/src/codec/gsm_codec.c create mode 100644 protocols/Tlen/src/codec/gsm_long.c create mode 100644 protocols/Tlen/src/codec/gsm_lpc.c create mode 100644 protocols/Tlen/src/codec/gsm_preprocess.c create mode 100644 protocols/Tlen/src/codec/gsm_rpe.c create mode 100644 protocols/Tlen/src/codec/gsm_short.c create mode 100644 protocols/Tlen/src/commons.h create mode 100644 protocols/Tlen/src/crypto/aes.c create mode 100644 protocols/Tlen/src/crypto/bignum.c create mode 100644 protocols/Tlen/src/crypto/padlock.c create mode 100644 protocols/Tlen/src/crypto/polarssl/aes.h create mode 100644 protocols/Tlen/src/crypto/polarssl/bignum.h create mode 100644 protocols/Tlen/src/crypto/polarssl/bn_mul.h create mode 100644 protocols/Tlen/src/crypto/polarssl/config.h create mode 100644 protocols/Tlen/src/crypto/polarssl/padlock.h create mode 100644 protocols/Tlen/src/jabber.h create mode 100644 protocols/Tlen/src/jabber_iq.cpp create mode 100644 protocols/Tlen/src/jabber_iq.h create mode 100644 protocols/Tlen/src/jabber_iqid.cpp create mode 100644 protocols/Tlen/src/jabber_list.cpp create mode 100644 protocols/Tlen/src/jabber_list.h create mode 100644 protocols/Tlen/src/jabber_misc.cpp create mode 100644 protocols/Tlen/src/jabber_opt.cpp create mode 100644 protocols/Tlen/src/jabber_svc.cpp create mode 100644 protocols/Tlen/src/jabber_thread.cpp create mode 100644 protocols/Tlen/src/jabber_util.cpp create mode 100644 protocols/Tlen/src/jabber_ws.cpp create mode 100644 protocols/Tlen/src/jabber_xml.cpp create mode 100644 protocols/Tlen/src/jabber_xml.h create mode 100644 protocols/Tlen/src/resource.h create mode 100644 protocols/Tlen/src/tlen.cpp create mode 100644 protocols/Tlen/src/tlen_advsearch.cpp create mode 100644 protocols/Tlen/src/tlen_avatar.cpp create mode 100644 protocols/Tlen/src/tlen_avatar.h create mode 100644 protocols/Tlen/src/tlen_file.cpp create mode 100644 protocols/Tlen/src/tlen_file.h create mode 100644 protocols/Tlen/src/tlen_muc.cpp create mode 100644 protocols/Tlen/src/tlen_muc.h create mode 100644 protocols/Tlen/src/tlen_p2p_new.cpp create mode 100644 protocols/Tlen/src/tlen_p2p_old.cpp create mode 100644 protocols/Tlen/src/tlen_p2p_old.h create mode 100644 protocols/Tlen/src/tlen_picture.cpp create mode 100644 protocols/Tlen/src/tlen_picture.h create mode 100644 protocols/Tlen/src/tlen_presence.cpp create mode 100644 protocols/Tlen/src/tlen_presence.h create mode 100644 protocols/Tlen/src/tlen_userinfo.cpp create mode 100644 protocols/Tlen/src/tlen_voice.cpp create mode 100644 protocols/Tlen/src/tlen_voice.h (limited to 'protocols/Tlen/src') diff --git a/protocols/Tlen/src/codec/gsm.h b/protocols/Tlen/src/codec/gsm.h new file mode 100644 index 0000000000..f522739d10 --- /dev/null +++ b/protocols/Tlen/src/codec/gsm.h @@ -0,0 +1,65 @@ +/* + +Tlen Protocol Plugin for Miranda NG +Copyright (C) 2004 Piotr Piastucki + +This program is based on GSM 06.10 source code developed by +Jutta Degener and Carsten Bormann, +Copyright 1992, 1993, 1994 by Jutta Degener and Carsten Bormann, +Technische Universitaet Berlin + +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 + +#define P_MAX 8 /* order p of LPC analysis, typically 8..14 */ + +typedef struct { + int LARpp[2][8]; /* LAR coefficients for previous and current frame */ + int j; /* current frame index in LARpp[j][] */ + int qLARs[8]; /* quantized LARs for current frame */ + int u[8]; /* used by short term analysis filter */ + int v[9]; /* used by short term synthesis filter */ + int subframe; /* subframe index (0..3)*/ + short dp0[ 280 ]; /* previous short-term filter output/prediction, used by long term analysis*/ + int e[160]; /* errors (residuals) */ + int nrp; /* long term synthesis */ + int Nc[4], bc[4]; /* long-term lag and gain for current frame */ + int Mc[4]; /* RPE grid index (0..3) */ + int xMaxc[4]; /* RPE maximum error quantized and encoded (mantissa + exp) */ + int xMc[52]; /* quantized residuals (errors) 4 * 13 */ + + int z1; /* preprocessing.c, Offset_com. */ + int z2; /* Offset_com. */ + int mp; /* Preemphasis */ + int msr; /* decoder.c, Postprocessing */ + + unsigned char gsmFrame[33]; +}gsm_state; + +extern gsm_state * gsm_create() ; +extern void gsm_release(gsm_state *ptr); +extern void gsm_encode(gsm_state *state, short *in); +extern void gsm_decode(gsm_state *state, short *out); + +extern void gsm_preprocessing( gsm_state *state, short *in, short *out); +extern void shortTermAnalysis(gsm_state *state, short *in); +extern void longTermAnalysis(gsm_state *state, short *in); +extern void encodeRPE(gsm_state *state); +extern void decodeRPE(gsm_state *state); +extern void longTermSynthesis(gsm_state *state); +extern void shortTermSynthesis(gsm_state *state, short *in, short *out); +extern void gsm_postprocessing( gsm_state *state, short *in, short *out); diff --git a/protocols/Tlen/src/codec/gsm_codec.c b/protocols/Tlen/src/codec/gsm_codec.c new file mode 100644 index 0000000000..afa1ef32de --- /dev/null +++ b/protocols/Tlen/src/codec/gsm_codec.c @@ -0,0 +1,283 @@ +/* + +Tlen Protocol Plugin for Miranda NG +Copyright (C) 2004-2007 Piotr Piastucki + +This program is based on GSM 06.10 source code developed by +Jutta Degener and Carsten Bormann, +Copyright 1992, 1993, 1994 by Jutta Degener and Carsten Bormann, +Technische Universitaet Berlin + +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 "gsm.h" +#include +#include +#include +#define GSM_MAGIC 0xD + +gsm_state * gsm_create() +{ + gsm_state * state = (gsm_state *)malloc(sizeof(gsm_state)); + memset(state, 0, sizeof(gsm_state)); + state->nrp = 40; + return state; +} + +void gsm_release(gsm_state *ptr) +{ + free(ptr); +} + +void gsm_encode(gsm_state *state, short *in) +{ int i, j; + unsigned char *c = state->gsmFrame; + short temp_in[160]; + + gsm_preprocessing(state, in, temp_in); + shortTermAnalysis(state, temp_in); + for (i = 0; i < 4; i++) { + state->subframe = i; + longTermAnalysis(state, temp_in + 40 * i); + encodeRPE(state); + for (j = 0; j < 40; j++) { + int ii = (int) state->dp0[120 + i * 40 + j] + state->e[i * 40 + j]; + if (ii<-32768) ii = -32768; + else if (ii>32767) ii=32767; + state->dp0[120 + i * 40 + j] = ii; + } + } + memcpy(state->dp0, state->dp0 + 160, 120 * sizeof(short)); + state->j ^= 1; + *c++ = ((GSM_MAGIC & 0xF) << 4) + | ((state->qLARs[0] >> 2) & 0xF); + *c++ = ((state->qLARs[0] & 0x3) << 6) + | (state->qLARs[1] & 0x3F); + *c++ = ((state->qLARs[2] & 0x1F) << 3) + | ((state->qLARs[3] >> 2) & 0x7); + *c++ = ((state->qLARs[3] & 0x3) << 6) + | ((state->qLARs[4] & 0xF) << 2) + | ((state->qLARs[5] >> 2) & 0x3); + *c++ = ((state->qLARs[5] & 0x3) << 6) + | ((state->qLARs[6] & 0x7) << 3) + | (state->qLARs[7] & 0x7); + *c++ = ((state->Nc[0] & 0x7F) << 1) + | ((state->bc[0] >> 1) & 0x1); + *c++ = ((state->bc[0] & 0x1) << 7) + | ((state->Mc[0] & 0x3) << 5) + | ((state->xMaxc[0] >> 1) & 0x1F); + *c++ = ((state->xMaxc[0] & 0x1) << 7) + | ((state->xMc[0] & 0x7) << 4) + | ((state->xMc[1] & 0x7) << 1) + | ((state->xMc[2] >> 2) & 0x1); + *c++ = ((state->xMc[2] & 0x3) << 6) + | ((state->xMc[3] & 0x7) << 3) + | (state->xMc[4] & 0x7); + *c++ = ((state->xMc[5] & 0x7) << 5) + | ((state->xMc[6] & 0x7) << 2) + | ((state->xMc[7] >> 1) & 0x3); + *c++ = ((state->xMc[7] & 0x1) << 7) + | ((state->xMc[8] & 0x7) << 4) + | ((state->xMc[9] & 0x7) << 1) + | ((state->xMc[10] >> 2) & 0x1); + *c++ = ((state->xMc[10] & 0x3) << 6) + | ((state->xMc[11] & 0x7) << 3) + | (state->xMc[12] & 0x7); + *c++ = ((state->Nc[1] & 0x7F) << 1) + | ((state->bc[1] >> 1) & 0x1); + *c++ = ((state->bc[1] & 0x1) << 7) + | ((state->Mc[1] & 0x3) << 5) + | ((state->xMaxc[1] >> 1) & 0x1F); + *c++ = ((state->xMaxc[1] & 0x1) << 7) + | ((state->xMc[13] & 0x7) << 4) + | ((state->xMc[14] & 0x7) << 1) + | ((state->xMc[15] >> 2) & 0x1); + *c++ = ((state->xMc[15] & 0x3) << 6) + | ((state->xMc[16] & 0x7) << 3) + | (state->xMc[17] & 0x7); + *c++ = ((state->xMc[18] & 0x7) << 5) + | ((state->xMc[19] & 0x7) << 2) + | ((state->xMc[20] >> 1) & 0x3); + *c++ = ((state->xMc[20] & 0x1) << 7) + | ((state->xMc[21] & 0x7) << 4) + | ((state->xMc[22] & 0x7) << 1) + | ((state->xMc[23] >> 2) & 0x1); + *c++ = ((state->xMc[23] & 0x3) << 6) + | ((state->xMc[24] & 0x7) << 3) + | (state->xMc[25] & 0x7); + *c++ = ((state->Nc[2] & 0x7F) << 1) + | ((state->bc[2] >> 1) & 0x1); + *c++ = ((state->bc[2] & 0x1) << 7) + | ((state->Mc[2] & 0x3) << 5) + | ((state->xMaxc[2] >> 1) & 0x1F); + *c++ = ((state->xMaxc[2] & 0x1) << 7) + | ((state->xMc[26] & 0x7) << 4) + | ((state->xMc[27] & 0x7) << 1) + | ((state->xMc[28] >> 2) & 0x1); + *c++ = ((state->xMc[28] & 0x3) << 6) + | ((state->xMc[29] & 0x7) << 3) + | (state->xMc[30] & 0x7); + *c++ = ((state->xMc[31] & 0x7) << 5) + | ((state->xMc[32] & 0x7) << 2) + | ((state->xMc[33] >> 1) & 0x3); + *c++ = ((state->xMc[33] & 0x1) << 7) + | ((state->xMc[34] & 0x7) << 4) + | ((state->xMc[35] & 0x7) << 1) + | ((state->xMc[36] >> 2) & 0x1); + *c++ = ((state->xMc[36] & 0x3) << 6) + | ((state->xMc[37] & 0x7) << 3) + | (state->xMc[38] & 0x7); + *c++ = ((state->Nc[3] & 0x7F) << 1) + | ((state->bc[3] >> 1) & 0x1); + *c++ = ((state->bc[3] & 0x1) << 7) + | ((state->Mc[3] & 0x3) << 5) + | ((state->xMaxc[3] >> 1) & 0x1F); + *c++ = ((state->xMaxc[3] & 0x1) << 7) + | ((state->xMc[39] & 0x7) << 4) + | ((state->xMc[40] & 0x7) << 1) + | ((state->xMc[41] >> 2) & 0x1); + *c++ = ((state->xMc[41] & 0x3) << 6) + | ((state->xMc[42] & 0x7) << 3) + | (state->xMc[43] & 0x7); + *c++ = ((state->xMc[44] & 0x7) << 5) + | ((state->xMc[45] & 0x7) << 2) + | ((state->xMc[46] >> 1) & 0x3); + *c++ = ((state->xMc[46] & 0x1) << 7) + | ((state->xMc[47] & 0x7) << 4) + | ((state->xMc[48] & 0x7) << 1) + | ((state->xMc[49] >> 2) & 0x1); + *c++ = ((state->xMc[49] & 0x3) << 6) + | ((state->xMc[50] & 0x7) << 3) + | (state->xMc[51] & 0x7); +} + +void gsm_decode(gsm_state *state, short *out) +{ + int i; + unsigned char *c = state->gsmFrame; + + if (((*c >> 4) & 0x0F) != GSM_MAGIC) return ; + state->qLARs[0] = (*c++ & 0xF) << 2; + state->qLARs[0] |= (*c >> 6) & 0x3; + state->qLARs[1] = *c++ & 0x3F; + state->qLARs[2] = (*c >> 3) & 0x1F; + state->qLARs[3] = (*c++ & 0x7) << 2; + state->qLARs[3] |= (*c >> 6) & 0x3; + state->qLARs[4] = (*c >> 2) & 0xF; + state->qLARs[5] = (*c++ & 0x3) << 2; + state->qLARs[5] |= (*c >> 6) & 0x3; + state->qLARs[6] = (*c >> 3) & 0x7; + state->qLARs[7] = *c++ & 0x7; + state->Nc[0] = (*c >> 1) & 0x7F; + state->bc[0] = (*c++ & 0x1) << 1; + state->bc[0] |= (*c >> 7) & 0x1; + state->Mc[0] = (*c >> 5) & 0x3; + state->xMaxc[0] = (*c++ & 0x1F) << 1; + state->xMaxc[0] |= (*c >> 7) & 0x1; + state->xMc[0] = (*c >> 4) & 0x7; + state->xMc[1] = (*c >> 1) & 0x7; + state->xMc[2] = (*c++ & 0x1) << 2; + state->xMc[2] |= (*c >> 6) & 0x3; + state->xMc[3] = (*c >> 3) & 0x7; + state->xMc[4] = *c++ & 0x7; + state->xMc[5] = (*c >> 5) & 0x7; + state->xMc[6] = (*c >> 2) & 0x7; + state->xMc[7] = (*c++ & 0x3) << 1; + state->xMc[7] |= (*c >> 7) & 0x1; + state->xMc[8] = (*c >> 4) & 0x7; + state->xMc[9] = (*c >> 1) & 0x7; + state->xMc[10] = (*c++ & 0x1) << 2; + state->xMc[10] |= (*c >> 6) & 0x3; + state->xMc[11] = (*c >> 3) & 0x7; + state->xMc[12] = *c++ & 0x7; + state->Nc[1] = (*c >> 1) & 0x7F; + state->bc[1] = (*c++ & 0x1) << 1; + state->bc[1] |= (*c >> 7) & 0x1; + state->Mc[1] = (*c >> 5) & 0x3; + state->xMaxc[1] = (*c++ & 0x1F) << 1; + state->xMaxc[1] |= (*c >> 7) & 0x1; + state->xMc[13] = (*c >> 4) & 0x7; + state->xMc[14] = (*c >> 1) & 0x7; + state->xMc[15] = (*c++ & 0x1) << 2; + state->xMc[15] |= (*c >> 6) & 0x3; + state->xMc[16] = (*c >> 3) & 0x7; + state->xMc[17] = *c++ & 0x7; + state->xMc[18] = (*c >> 5) & 0x7; + state->xMc[19] = (*c >> 2) & 0x7; + state->xMc[20] = (*c++ & 0x3) << 1; + state->xMc[20] |= (*c >> 7) & 0x1; + state->xMc[21] = (*c >> 4) & 0x7; + state->xMc[22] = (*c >> 1) & 0x7; + state->xMc[23] = (*c++ & 0x1) << 2; + state->xMc[23] |= (*c >> 6) & 0x3; + state->xMc[24] = (*c >> 3) & 0x7; + state->xMc[25] = *c++ & 0x7; + state->Nc[2] = (*c >> 1) & 0x7F; + state->bc[2] = (*c++ & 0x1) << 1; + state->bc[2] |= (*c >> 7) & 0x1; + state->Mc[2] = (*c >> 5) & 0x3; + state->xMaxc[2] = (*c++ & 0x1F) << 1; + state->xMaxc[2] |= (*c >> 7) & 0x1; + state->xMc[26] = (*c >> 4) & 0x7; + state->xMc[27] = (*c >> 1) & 0x7; + state->xMc[28] = (*c++ & 0x1) << 2; + state->xMc[28] |= (*c >> 6) & 0x3; + state->xMc[29] = (*c >> 3) & 0x7; + state->xMc[30] = *c++ & 0x7; + state->xMc[31] = (*c >> 5) & 0x7; + state->xMc[32] = (*c >> 2) & 0x7; + state->xMc[33] = (*c++ & 0x3) << 1; + state->xMc[33] |= (*c >> 7) & 0x1; + state->xMc[34] = (*c >> 4) & 0x7; + state->xMc[35] = (*c >> 1) & 0x7; + state->xMc[36] = (*c++ & 0x1) << 2; + state->xMc[36] |= (*c >> 6) & 0x3; + state->xMc[37] = (*c >> 3) & 0x7; + state->xMc[38] = *c++ & 0x7; + state->Nc[3] = (*c >> 1) & 0x7F; + state->bc[3] = (*c++ & 0x1) << 1; + state->bc[3] |= (*c >> 7) & 0x1; + state->Mc[3] = (*c >> 5) & 0x3; + state->xMaxc[3] = (*c++ & 0x1F) << 1; + state->xMaxc[3] |= (*c >> 7) & 0x1; + state->xMc[39] = (*c >> 4) & 0x7; + state->xMc[40] = (*c >> 1) & 0x7; + state->xMc[41] = (*c++ & 0x1) << 2; + state->xMc[41] |= (*c >> 6) & 0x3; + state->xMc[42] = (*c >> 3) & 0x7; + state->xMc[43] = *c++ & 0x7; + state->xMc[44] = (*c >> 5) & 0x7; + state->xMc[45] = (*c >> 2) & 0x7; + state->xMc[46] = (*c++ & 0x3) << 1; + state->xMc[46] |= (*c >> 7) & 0x1; + state->xMc[47] = (*c >> 4) & 0x7; + state->xMc[48] = (*c >> 1) & 0x7; + state->xMc[49] = (*c++ & 0x1) << 2; + state->xMc[49] |= (*c >> 6) & 0x3; + state->xMc[50] = (*c >> 3) & 0x7; + state->xMc[51] = *c & 0x7; + + for (i = 0; i < 4; i++) { + state->subframe = i; + decodeRPE(state); + longTermSynthesis(state); + } + memcpy(state->dp0, state->dp0 + 160, 120 * sizeof(short)); + shortTermSynthesis(state, &state->dp0[120], out); + gsm_postprocessing(state, out, out); + state->j ^= 1; +} diff --git a/protocols/Tlen/src/codec/gsm_long.c b/protocols/Tlen/src/codec/gsm_long.c new file mode 100644 index 0000000000..56d83f7873 --- /dev/null +++ b/protocols/Tlen/src/codec/gsm_long.c @@ -0,0 +1,183 @@ +/* + +Tlen Protocol Plugin for Miranda NG +Copyright (C) 2004-2007 Piotr Piastucki + +This program is based on GSM 06.10 source code developed by +Jutta Degener and Carsten Bormann, +Copyright 1992, 1993, 1994 by Jutta Degener and Carsten Bormann, +Technische Universitaet Berlin + +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 "gsm.h" +#include +#include +#include + +/* Decision levels */ +const static int gsm_DLB[4] = { 6554, 16384, 26214, 32767 }; +/* Quantization levels */ +const static int gsm_QLB[4] = { 3277, 11469, 21299, 32767 }; + +/* + * Long term parameters calculation - lag (Nc) and gain (bc). + */ +static void longTermLTPCalculation(gsm_state *state, short *in, short *in_1) +{ + int k, lambda; + int Nc, bc; + float in_1_float_base[120], * in_1_float = in_1_float_base + 120; + float in_float[40]; + float L_result, L_max, L_power; + + for (k = -120; k < 0; k++) in_1_float[k] = (float)in_1[k]; + for (k = 0; k < 40; k++) in_float[k] = (float)in[k]; + + /* Search for the maximum cross-correlation and coding of the LTP lag */ + + L_max = 0; + Nc = 40; /* index for the maximum cross-correlation */ + + for (lambda = 40; lambda < 121; lambda++) { + for (L_result = 0, L_power = 0, k = 0; k < 40; k++) { + L_result += in_float[k] * in_1_float[k - lambda]; +// L_power += in_1_float[k - lambda] * in_1_float[k - lambda]; + } +// L_result = L_result / L_power; + if (L_result > L_max) { + Nc = lambda; + L_max = L_result; + } + } + state->Nc[state->subframe] = Nc; + if (L_max <= 0.) { + state->bc[state->subframe] = 0; + return; + } + /* Compute the power of the reconstructed short term residual signal dp[..] */ + in_1_float -= Nc; + L_power = 0; + for (k = 0; k < 40; k++) { + float f = in_1_float[k]; + L_power += f * f; + } + if (L_max >= L_power) { //1.0 + state->bc[state->subframe] = 3; + return; + } + /* Coding of the LTP gain + * Table gsm_DLB must be used to obtain the level DLB[i] for the + * quantization of the LTP gain b to get the coded version bc. + */ +// lambda = L_max * 32768.; + lambda = (int)(L_max * 32768. / L_power); + for (bc = 0; bc <= 2; ++bc) if (lambda <= gsm_DLB[bc]) break; + state->bc[state->subframe] = bc; +} + +/* + * Here we decode the bc parameter and compute samples of the estimate out[0..39]. + * The decoding of bc needs the gsm_QLB table. + * The long term residual signal e[0..39] is then calculated to be fed to the + * RPE encoding section. + */ +static void longTermAnalysisFilter(int Nc, int bc, short *in, short *in_1, short *out, int *e) +{ + int gain, k, l; + gain = gsm_QLB[bc]; + for (k = 0; k < 40; k++) { + l = (gain * (int)in_1[k - Nc] + 16384) >> 15; + if (l < -32768) l = -32768; + else if (l > 32767) l = 32767; + out[k] = l; + e[k] = in[k] - l; + } +} + +/* + * This procedure uses the bcr and Ncr parameter to realize the + * long term synthesis filtering. The decoding of bcr needs table gsm_QLB. + */ +static void longTermSynthesisFilter(gsm_state * state, int Ncr, int bcr, int *e, short *out) +{ + int k; + int brp, Nr; + + /* Check the limits of Nr. */ + Nr = Ncr < 40 || Ncr > 120 ? state->nrp : Ncr; + state->nrp = Nr; + /* Decoding of the LTP gain bcr */ + brp = gsm_QLB[ bcr ]; + + /* Computation of the reconstructed short term residual + * signal drp[0..39] + */ + for (k = 0; k < 40; k++) { + int temp = (brp * (int)out[ k-Nr ] + 16384) >> 15; + out[k] = e[k] + temp; + } +} + +/* + * This procedure performs long term analysis. + */ +void longTermAnalysis(gsm_state *state, short *in) +{ + short *in_1 = state->dp0 + 120 + state->subframe * 40; + short *out = state->dp0 + 120 + state->subframe * 40; + int *e = state->e + state->subframe * 40; +/* + + int i; + printf("Long-term in: \n"); + for (i=0;i<40;i++) { + printf("%7d ", in[i]); + } + printf("\n"); + */ + longTermLTPCalculation(state, in, in_1); + /* printf("Nc: %d, bc: %d \n", state->Nc[state->subframe], state->bc[state->subframe]); + */ + longTermAnalysisFilter(state->Nc[state->subframe], state->bc[state->subframe], in, in_1, out, e); +/* + printf("Long-term out: \n"); + for (i=0;i<40;i++) { + printf("%7d ", out[i]); + } + printf("\n"); + */ +} + +/* + * This procedure performs long term synthesis. + */ +void longTermSynthesis(gsm_state *state) +{ + int Nc = state->Nc[state->subframe]; + int bc = state->bc[state->subframe]; + int *e = state->e + state->subframe * 40; + short *out = state->dp0 + 120 + state->subframe * 40; + //int i; + longTermSynthesisFilter(state, Nc, bc, e, out); + /* + printf("Long-term reconstructed: \n"); + for (i=0;i<160;i++) { + printf("%7d ", state->dp0[i]); + } + printf("\n"); + */ +} diff --git a/protocols/Tlen/src/codec/gsm_lpc.c b/protocols/Tlen/src/codec/gsm_lpc.c new file mode 100644 index 0000000000..538a03ad92 --- /dev/null +++ b/protocols/Tlen/src/codec/gsm_lpc.c @@ -0,0 +1,208 @@ +/* + +Tlen Protocol Plugin for Miranda NG +Copyright (C) 2004-2007 Piotr Piastucki + +This program is based on GSM 06.10 source code developed by +Jutta Degener and Carsten Bormann, +Copyright 1992, 1993, 1994 by Jutta Degener and Carsten Bormann, +Technische Universitaet Berlin + +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. + +*/ + +/* LPC- and Reflection Coefficients + * The next two functions calculate linear prediction coefficients + * and/or the related reflection coefficients from the first P_MAX+1 + * values of the autocorrelation function. + */ +#include "gsm.h" /* for P_MAX */ +#include +#include +#include + +/* Compute the autocorrelation + * ,--, + * ac(l) = > x(i) * x(i-l) for all i + * `--' + * for lags l between 0 and lag-1, and x(i) == 0 for i < 0 or i >= n + * @param n: number of samples + * @param lax: max lag (order) + * @param in: [0...n-1] samples x + * @param out: [0...lag-1] autocorrelation + */ +static void autocorrelation(int n, float const *x, int lag, float *ac) +{ + float d; + int i, j; + for (j = 0; j < lag; j++) { + for (i = j, d = 0; i < n; i++) d += x[i] * x[i-j]; + ac[j] = d; + } + d = (float)fabs(ac[0]); + if (d != 0) { + for (j = 0; j < lag; j++) ac[j] /= d; + } +} + +/* The Levinson-Durbin algorithm was invented by N. Levinson in 1947 + * and modified by J. Durbin in 1959. + * @param in: [0...p] autocorrelation values + * @param out: [0...p-1] reflection coefficients + * @param lpc: [0...p-1] LPC coefficients + * @return minimum mean square error + */ +/* +static float levinson_durbin (float const *ac, float *ref, float *lpc) +{ + int i, j; + float r, error = ac[0]; + + if (ac[0] == 0) { + for (i = 0; i < P_MAX; i++) ref[i] = 0; + return 0; + } + + for (i = 0; i < P_MAX; i++) { + + r = -ac[i + 1]; + for (j = 0; j < i; j++) r -= lpc[j] * ac[i - j]; + ref[i] = r /= error; + + // Update LPC coefficients and total error. + lpc[i] = r; + for (j = 0; j < i / 2; j++) { + float tmp = lpc[j]; + lpc[j] = r * lpc[i - 1 - j]; + lpc[i - 1 - j] += r * tmp; + } + if (i % 2) lpc[j] += lpc[j] * r; + + error *= 1 - r * r; + } + return error; +} +*/ +/* I. Schur's recursion from 1917 is related to the Levinson-Durbin method, + * but faster on parallel architectures; where Levinson-Durbin would take time + * proportional to p * log(p), Schur only requires time proportional to p. The + * GSM coder uses an integer version of the Schur recursion. + * @param in: [0...p] autocorrelation values + * @param out: [0...p-1] reflection coefficients + * @return the minimum mean square error + */ +static float schur(float const *ac, float *ref) +{ + int i, m; + float error=ac[0], r, G[2][P_MAX]; + + if (ac[0] == 0.0) { + for (i = 0; i < P_MAX; i++) ref[i] = 0; + return 0; + } + + /* Initialize the rows of the generator matrix G to ac[1...p]. */ + for (i = 0; i < P_MAX; i++) G[0][i] = G[1][i] = ac[i + 1]; + + for (i = 0;;) { + /* Calculate this iteration's reflection coefficient and error. */ + ref[i] = r = -G[1][0] / error; + error += G[1][0] * r; + + if (++i >= P_MAX) return error; + + /* Update the generator matrix. Unlike Levinson-Durbin's summing of + * reflection coefficients, this loop could be executed in parallel + * by p processors in constant time. + */ + for (m = 0; m < P_MAX - i; m++) { + G[1][m] = G[1][m + 1] + r * G[0][m]; + G[0][m] = G[1][m + 1] * r + G[0][m]; + } + } +} + + + /* 0..7 IN/OUT */ +static void rToLAR(int *r) +/* + * The following scaling for r[..] and LAR[..] has been used: + * + * r[..] = integer( real_r[..]*32768. ); -1 <= real_r < 1. + * LAR[..] = integer( real_LAR[..] * 16384 ); + * with -1.625 <= real_LAR <= 1.625 + */ +{ + int temp; + int i; + + /* Computation of the LAR[0..7] from the r[0..7] + */ + for (i = 0; i < 8; i++) { + temp = abs(r[i]); //GSM_ABS(temp); + if (temp < 22118) { + temp >>= 1; + } else if (temp < 31130) { + temp -= 11059; + } else { + temp -= 26112; + temp <<= 2; + } + r[i] = r[i] < 0 ? -temp : temp; + } +} + +static void quantizeLARs(int *LARs, int *qLARs) +{ int qA[]={20480, 20480, 20480, 20480, 13964, 15360, 8534, 9036}; + int qB[]={0, 0, 2048, -2560, 94, -1792, -341, -1144}; + int qMin[]={-32, -32, -16, -16, -8, -8, -4, -4}; + int qMax[]={31, 31, 15, 15, 7, 7, 3, 3}; + int i; + for (i = 0; i < 8; i++) { + int temp; + temp = (((LARs[i] * qA[i]) >> 15) + qB[i] + 256) >> 9; + if (temp < qMin[i]) temp = 0; + else if (temp > qMax[i]) temp = qMax[i] - qMin[i]; + else temp = temp - qMin[i]; + qLARs[i] = temp; + } +} + +void lpcAnalysis(gsm_state *state, short *in) +{ float error; + float samples[160]; + float ac[9]; + float ref[8]; + int i; + int * qLARs = state->qLARs; + for (i = 0; i < 160; i++) { + samples[i] = in[i]; + } + autocorrelation(160, samples, 9, ac); + error=schur(ac, ref); + /* + printf("reff: "); + for (i=0;i<8;i++) { + printf("%5.5f ", ref[i]);//((float)i_lpc[i])/32768.0f); + } + printf("\n"); + */ + for (i = 0; i < 8; i++) { + qLARs[i] = (int) (32768 * ref[i]); + } + rToLAR(qLARs); + quantizeLARs(qLARs, qLARs); +} diff --git a/protocols/Tlen/src/codec/gsm_preprocess.c b/protocols/Tlen/src/codec/gsm_preprocess.c new file mode 100644 index 0000000000..462b8e6c17 --- /dev/null +++ b/protocols/Tlen/src/codec/gsm_preprocess.c @@ -0,0 +1,103 @@ +/* + +Tlen Protocol Plugin for Miranda NG +Copyright (C) 2004-2007 Piotr Piastucki + +This program is based on GSM 06.10 source code developed by +Jutta Degener and Carsten Bormann, +Copyright 1992, 1993, 1994 by Jutta Degener and Carsten Bormann, +Technische Universitaet Berlin + +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 "gsm.h" +#include + +/* 4.2.0 .. 4.2.3 PREPROCESSING SECTION + * + * After A-law to linear conversion (or directly from the + * Ato D converter) the following scaling is assumed for + * input to the RPE-LTP algorithm: + * + * + * Where S is the sign bit, v a valid bit, and * a "don't care" bit. + * The original signal is called sop[..] + * + */ + + +void gsm_preprocessing( gsm_state *state, short *in, short *out) +{ + int z1 = state->z1; + int z2 = state->z2; + int mp = state->mp; + int so, s1; + int msp, lsp; + + int k = 160; + + while (k--) { + /* Downscaling of the input signal + * in: 0.1.....................12 + * S.v.v.v.v.v.v.v.v.v.v.v.v.*.*.* + * out: 0.1................... 12 + * S.S.v.v.v.v.v.v.v.v.v.v.v.v.0.0 + */ + so = (*in >> 3) << 2; + in++; + /* 4.2.2 Offset compensation + * + * This part implements a high-pass filter and requires extended + * arithmetic precision for the recursive part of this filter. + * The input of this procedure is the array so[0...159] and the + * output the array sof[ 0...159 ]. + */ + /* Compute the non-recursive part + */ + s1 = (so - z1) << 15; + z1 = so; + msp = z2 >> 15; + lsp = z2 - (msp << 15); + s1 += ((lsp * 32735) + 16384) >> 15; + z2 = msp * 32735 + s1; + /* 4.2.3 Preemphasis + */ + msp = (-28180 * mp + 16384) >> 15; + mp = (z2 + 16384) >> 15; + *out++ = mp + msp; + } + state->z1 = z1; + state->z2 = z2; + state->mp = mp; +/* + printf("preprocessed: \n"); + for (k=0;k<160;k++) { + printf("%7d ", out[k]);//((float)i_lpc[i])/32768.0f); + } + printf("\n"); + */ +} + +void gsm_postprocessing( gsm_state *state, short *in, short *out) +{ + int k; + int msr = state->msr; + for (k = 160; k--; in++, out++) { + msr = *in + ((msr * 28180 + 16384) >>15); /* Deemphasis */ + *out = (msr + msr ) & 0xFFF8; /* Truncation & Upscaling */ + } + state->msr = msr; +} diff --git a/protocols/Tlen/src/codec/gsm_rpe.c b/protocols/Tlen/src/codec/gsm_rpe.c new file mode 100644 index 0000000000..21c5419672 --- /dev/null +++ b/protocols/Tlen/src/codec/gsm_rpe.c @@ -0,0 +1,248 @@ +/* + +Tlen Protocol Plugin for Miranda NG +Copyright (C) 2004-2007 Piotr Piastucki + +This program is based on GSM 06.10 source code developed by +Jutta Degener and Carsten Bormann, +Copyright 1992, 1993, 1994 by Jutta Degener and Carsten Bormann, +Technische Universitaet Berlin + +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 "gsm.h" +#include +#include +#include + +static const int gsm_H[11] = {-134, -374, 0, 2054, 5741, 8192, 5741, 2054, 0, -374, -134 }; +static const int gsm_NRFAC[8] = { 29128, 26215, 23832, 21846, 20165, 18725, 17476, 16384 }; +static const int gsm_FAC[8] = { 18431, 20479, 22527, 24575, 26623, 28671, 30719, 32767 }; +/* + * The coefficients of the weighting filter are stored in the gsm_H table. + * The following scaling is used: + * + * gsm_H[0..10] = integer( real_H[ 0..10] * 8192 ); + */ +static void weightingFilter (int *e, int *x) +{ + int L_result; + int k, i; + for (k = 0; k < 40; k++) { + L_result = 4096; + for (i = 0; i < 11; i++) { + int ix = i + k; + if (ix>4 && ix<45) L_result += e[ix - 5] * gsm_H[i]; + } + L_result >>= 13; + x[k] = (L_result < -32768 ? -32768 : (L_result > 32767 ? 32767 : L_result)); + } +} + +/* + * The signal x[0..39] is used to select the RPE grid which is + * represented by Mc. + */ +static void gridSelection( int *x, int *xM, int *Mc_out) +{ + int m, i; + int L_result, L_temp; + int EM, Mc; + + EM = 0; + Mc = 0; + + for (m = 0; m < 4; m++) { + L_result = 0; + for (i = 0; i < 13; i++) { + int temp = x[m + 3*i] >> 2; + L_temp = temp * temp << 1; + L_result += L_temp; + } + if (L_result > EM) { + Mc = m; + EM = L_result; + } + } + /* Down-sampling by a factor 3 to get the selected xM[0..12] + * RPE sequence. + */ + for (i = 0; i < 13; i ++) xM[i] = x[Mc + 3*i]; + *Mc_out = Mc; +} + +/* + * This procedure computes the reconstructed long term residual signal + * ep[0..39] for the LTP analysis filter. The inputs are the Mc + * which is the grid position selection and the xMp[0..12] decoded + * RPE samples which are upsampled by a factor of 3 by inserting zero + * values. + */ +static void gridPositioning (int Mc, int *xMp, int *ep) +{ + int i, k; + for (k = 0; k < 40; k++) ep[k] = 0; + for (i = 0; i < 13; i++) { + ep[ Mc + (3*i) ] = xMp[i]; + } +} + +static void APCMXmaxcToExpMant (int xmaxc, int *exp_out, int *mant_out ) +{ + int exp, mant; + /* Compute exponent and mantissa of the decoded version of xmaxc + */ + exp = 0; + if (xmaxc > 15) exp = (xmaxc >> 3) - 1; + mant = xmaxc - (exp << 3); + + if (mant == 0) { + exp = -4; + mant = 7; + } + else { + while (mant < 8) { + mant = mant << 1 | 1; + exp--; + } + mant -= 8; + } + + *exp_out = exp; + *mant_out = mant; +} + +static void APCMQuantization (int *xM, int *xMc, int *mant_out, int *exp_out, int *xmaxc_out) +{ + int i, itest; + int xmax, xmaxc, temp, temp1, temp2; + int exp, mant; + + + /* Find the maximum absolute value xmax of xM[0..12]. + */ + + xmax = 0; + for (i = 0; i < 13; i++) { + temp = abs(xM[i]); + if (temp > xmax) xmax = temp; + } + if (xmax > 32767) xmax = 32767; + /* Qantizing and coding of xmax to get xmaxc. + */ + + exp = 0; + temp = xmax >> 9; + itest = 0; + + for (i = 0; i < 6; i++) { + if (temp != 0) exp++; + temp = temp >> 1; + } + + temp = exp + 5; + + xmaxc = (xmax >> temp) + (exp << 3); + + /* Quantizing and coding of the xM[0..12] RPE sequence + * to get the xMc[0..12] + */ + APCMXmaxcToExpMant( xmaxc, &exp, &mant ); + + /* This computation uses the fact that the decoded version of xmaxc + * can be calculated by using the exponent and the mantissa part of + * xmaxc (logarithmic table). + * So, this method avoids any division and uses only a scaling + * of the RPE samples by a function of the exponent. A direct + * multiplication by the inverse of the mantissa (NRFAC[0..7] + * found in table 4.5) gives the 3 bit coded version xMc[0..12] + * of the RPE samples. + */ + + /* Direct computation of xMc[0..12] using table 4.5 + */ + temp = (mant|8)<<(5+exp); + temp1 = 6 - exp; + temp2 = gsm_NRFAC[ mant ]; + for (i = 0; i < 13; i++) { + xMc[i] = ((xM[i] << temp1) * temp2 >> 27) + 4; + } + + /* NOTE: This equation is used to make all the xMc[i] positive. + */ + + *mant_out = mant; + *exp_out = exp; + *xmaxc_out = xmaxc; +} + +static void APCMDequantization (int *xMc, int mant, int exp, int *xMp) +{ + int i, temp1, temp2, temp3; + temp1 = gsm_FAC[ mant ]; + temp2 = 6 - exp; + if (temp2 <= 0) { + temp3 = 1 >> (1 - temp2); + } else { + temp3 = 1 << (temp2 - 1); + } + for (i = 0; i < 13; i++) { + xMp[i] = ((((((xMc[i]<<1)-7)<<12)*temp1+16384)>>15)+temp3)>>temp2; + } +} + +void encodeRPE(gsm_state *state) +{ int x[40]; + int xM[13], xMp[13]; + int mant, exp; + int *Mc = state->Mc + state->subframe; + int *xMaxc = state->xMaxc + state->subframe; + int *xMc = state->xMc + state->subframe * 13; + int *e = state->e + state->subframe * 40; + //int i; + /* + printf("RPE in: \n"); + for (i=0;i<40;i++) { + printf("%7d ", e[i]); + } + printf("\n"); + */ + weightingFilter(e, x); + /* + printf("RPE weighting filter: \n"); + for (i=0;i<40;i++) { + printf("%7d ", x[i]); + } + printf("\n"); + */ + gridSelection(x, xM, Mc); + APCMQuantization(xM, xMc, &mant, &exp, xMaxc); + /* printf("RPE Mc(grid #)=%d xmaxc=%d mant=%d exp=%d \n", *Mc, *xMaxc, mant, exp); */ + APCMDequantization(xMc, mant, exp, xMp); + gridPositioning(*Mc, xMp, e); +} + +void decodeRPE(gsm_state *state) +{ + int exp, mant; + int xMp[ 13 ]; + int *xMc = state->xMc + state->subframe * 13; + int *e = state->e + state->subframe * 40; + + APCMXmaxcToExpMant(state->xMaxc[state->subframe], &exp, &mant); + APCMDequantization(xMc, mant, exp, xMp); + gridPositioning(state->Mc[state->subframe], xMp, e); +} diff --git a/protocols/Tlen/src/codec/gsm_short.c b/protocols/Tlen/src/codec/gsm_short.c new file mode 100644 index 0000000000..4b02515a72 --- /dev/null +++ b/protocols/Tlen/src/codec/gsm_short.c @@ -0,0 +1,211 @@ +/* + +Tlen Protocol Plugin for Miranda NG +Copyright (C) 2004-2007 Piotr Piastucki + +This program is based on GSM 06.10 source code developed by +Jutta Degener and Carsten Bormann, +Copyright 1992, 1993, 1994 by Jutta Degener and Carsten Bormann, +Technische Universitaet Berlin + +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 "gsm.h" +#include +#include +#include +extern void lpcAnalysis(gsm_state *state, short *in); + +/* + * Dequantize LAR coefficients + */ +static void dequantizeLARs(int *qLARs, int *LARs) +{ + int dqA[]={13107, 13107, 13107, 13107, 19223, 17476, 31454, 29708}; + int dqB[]={0, 0, 2048, -2560, 94, -1792, -341, -1144}; + int dqMin[]={-32, -32, -16, -16, -8, -8, -4, -4}; + int i; + for (i = 0; i < 8; i++) { + int temp; + temp = ((((qLARs[i] + dqMin[i]) << 10) - (dqB[i] << 1)) * dqA[i] + 16384) >> 15; + LARs[i] = temp + temp; + } +} +/* + * Interpolate LAR coefficients (samples 0..12) + */ +static void interpolateLARs_0_12 (int *LARpp_j_1, int *LARpp_j, int *LARp) +{ int i; + for (i = 0; i < 8; i++) { + LARp[i] = (LARpp_j_1[i] >> 1) + (LARpp_j_1[i] >> 2) + (LARpp_j[i] >> 2); + } +} +/* + * Interpolate LAR coefficients (samples 13..26) + */ +static void interpolateLARs_13_26 (int *LARpp_j_1, int *LARpp_j, int *LARp) +{ int i; + for (i = 0; i < 8; i++) { + LARp[i] = (LARpp_j_1[i] >> 1) + (LARpp_j[i] >> 1); + } +} +/* + * Interpolate LAR coefficients (samples 27..39) + */ +static void interpolateLARs_27_39 (int *LARpp_j_1, int *LARpp_j, int *LARp) +{ int i; + for (i = 0; i < 8; i++) { + LARp[i] = (LARpp_j[i] >> 1) + (LARpp_j_1[i] >> 2) + (LARpp_j[i] >> 2); + } +} +/* + * Interpolate LAR coefficients (samples 40..159) + */ +static void interpolateLARs_40_159 (int *LARpp_j_1, int *LARpp_j, int *LARp) +{ int i; + for (i = 0; i < 8; i++) { + LARp[i] = LARpp_j[i]; + } +} +/* + * Convert LAR coefficients to reflection coefficients + */ +static void LARToR( int * LARp) +{ + int i; + int temp; + for (i = 0; i < 8; i++) { + temp = abs(LARp[i]); + if (temp < 11059) temp <<= 1; + else if (temp < 20070) temp += 11059; + else temp = (temp >> 2) + 26112; + LARp[i] = LARp[i] < 0 ? -temp : temp; + } +} + +/* + * This procedure computes the short term residual signal d[..] to be fed + * to the RPE-LTP loop from the s[..] signal and from the local rp[..] + * array (quantized reflection coefficients). As the call of this + * procedure can be done in many ways (see the interpolation of the LAR + * coefficient), it is assumed that the computation begins with index + * k_start (for arrays d[..] and s[..]) and stops with index k_end + * (k_start and k_end are defined in 4.2.9.1). This procedure also + * needs to keep the array u[0..7] in memory for each call. + */ +static void shortTermAnalysisFilter (gsm_state * state, int * rp, int len, short * in) +{ + int * u = state->u; + int i; + int di, ui, sav, rpi; + for (; len--; in++) { + di = sav = *in; + for (i = 0; i < 8; i++) { + ui = u[i]; + rpi = rp[i]; + u[i] = sav; + sav = ui + ((rpi * di + 16384) >> 15); + di = di + ((rpi * ui + 16384) >> 15); + } + *in = di; + } +} + +static void shortTermSynthesisFilter(gsm_state * state, int * rrp, int len, short * in, short *out) +{ + int * v = state->v; + int i; + int sri; + for (; len--; in++, out++) { + sri = *in; + for (i = 8; i--;) { + sri -= (rrp[i] * v[i] + 16384) >> 15; + if (sri < -32768) sri = -32768; + else if (sri > 32767) sri = 32767; + v[i+1] = v[i] + ((rrp[i] * sri + 16384) >> 15); + if (v[i+1] < -32768) v[i+1] = -32768; + else if (v[i+1] > 32767) v[i+1] = 32767; + } + *out = v[0] = sri; + } +} + +void shortTermAnalysis(gsm_state *state, short *in) +{ + int * qLARs = state->qLARs; + int * LARpp_j = state->LARpp[state->j]; + int * LARpp_j_1 = state->LARpp[state->j ^1]; + int LARp[8]; +// int i; + + lpcAnalysis(state, in);//i_samples); +/* + printf("short term in: \n"); + for (i=0;i<160;i++) { + printf("%7d ", in[i]);//((float)i_lpc[i])/32768.0f); + } + printf("\n"); + */ + dequantizeLARs(qLARs, LARpp_j); + interpolateLARs_0_12(LARpp_j_1, LARpp_j, LARp); + LARToR(LARp); + shortTermAnalysisFilter(state, LARp, 13, in); + interpolateLARs_13_26(LARpp_j_1, LARpp_j, LARp); + LARToR(LARp); + shortTermAnalysisFilter(state, LARp, 14, in+13); + interpolateLARs_27_39(LARpp_j_1, LARpp_j, LARp); + LARToR(LARp); + shortTermAnalysisFilter(state, LARp, 13, in+27); + interpolateLARs_40_159(LARpp_j_1, LARpp_j, LARp); + LARToR(LARp); + shortTermAnalysisFilter(state, LARp, 120, in+40); + /* + printf("short-term residuals: \n"); + for (i=0;i<160;i++) { + printf("%7d ", in[i]);//((float)i_lpc[i])/32768.0f); + } + printf("\n"); + */ +} + +void shortTermSynthesis(gsm_state *state, short *in, short *out) +{ + int * qLARs = state->qLARs; + int * LARpp_j = state->LARpp[state->j]; + int * LARpp_j_1 = state->LARpp[state->j ^1]; + int LARp[8]; +// int i; + + dequantizeLARs(qLARs, LARpp_j); + interpolateLARs_0_12(LARpp_j_1, LARpp_j, LARp); + LARToR(LARp); + shortTermSynthesisFilter(state, LARp, 13, in, out); + interpolateLARs_13_26(LARpp_j_1, LARpp_j, LARp); + LARToR(LARp); + shortTermSynthesisFilter(state, LARp, 14, in+13, out+13); + interpolateLARs_27_39(LARpp_j_1, LARpp_j, LARp); + LARToR(LARp); + shortTermSynthesisFilter(state, LARp, 13, in+27, out+27); + interpolateLARs_40_159(LARpp_j_1, LARpp_j, LARp); + LARToR(LARp); + shortTermSynthesisFilter(state, LARp, 120, in+40, out+40); + /* + printf("samples[reconstructed]: \n"); + for (i=0;i<160;i++) { + printf("%7d ", out[i]); + } + */ +} diff --git a/protocols/Tlen/src/commons.h b/protocols/Tlen/src/commons.h new file mode 100644 index 0000000000..af5a9bbcd7 --- /dev/null +++ b/protocols/Tlen/src/commons.h @@ -0,0 +1,32 @@ +#ifndef _TLENCOMMONS_INC +#define _TLENCOMMONS_INC + + +#define TLENMUCC_MAJOR_VERSION 2 +#define TLENMUCC_MINOR_VERSION 0 +#define TLENMUCC_RELEASE_NUM 5 +#define TLENMUCC_BUILD_NUM 0 +#define TLENMUCC_VERSION_STRING "2.0.5.0" + + + +//consts for tlen.dll +#define TLEN_MAJOR_VERSION TLENMUCC_MAJOR_VERSION +#define TLEN_MINOR_VERSION TLENMUCC_MINOR_VERSION +#define TLEN_RELEASE_NUM TLENMUCC_RELEASE_NUM +#define TLEN_BUILD_NUM TLENMUCC_BUILD_NUM + +#define TLEN_FILEVERSION_STRING TLEN_MAJOR_VERSION,TLEN_MINOR_VERSION,TLEN_RELEASE_NUM,TLEN_BUILD_NUM +#define TLEN_VERSION_STRING TLENMUCC_VERSION_STRING + +//consts for tlen_czaty.dll +#define MUCC_MAJOR_VERSION TLENMUCC_MAJOR_VERSION +#define MUCC_MINOR_VERSION TLENMUCC_MINOR_VERSION +#define MUCC_RELEASE_NUM TLENMUCC_RELEASE_NUM +#define MUCC_BUILD_NUM TLENMUCC_BUILD_NUM + +#define MUCC_FILEVERSION_STRING MUCC_MAJOR_VERSION,MUCC_MINOR_VERSION,MUCC_RELEASE_NUM,MUCC_BUILD_NUM +#define MUCC_VERSION_STRING TLENMUCC_VERSION_STRING + + +#endif //ifndef _TLENCOMMONS_INC diff --git a/protocols/Tlen/src/crypto/aes.c b/protocols/Tlen/src/crypto/aes.c new file mode 100644 index 0000000000..7bccdf93a1 --- /dev/null +++ b/protocols/Tlen/src/crypto/aes.c @@ -0,0 +1,1336 @@ +/* + * FIPS-197 compliant AES implementation + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * 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. + */ +/* + * The AES block cipher was designed by Vincent Rijmen and Joan Daemen. + * + * http://csrc.nist.gov/encryption/aes/rijndael/Rijndael.pdf + * http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf + */ + +#include "polarssl/config.h" + +#if defined(POLARSSL_AES_C) + +#include "polarssl/aes.h" +#include "polarssl/padlock.h" + +/* + * 32-bit integer manipulation macros (little endian) + */ +#ifndef GET_ULONG_LE +#define GET_ULONG_LE(n,b,i) \ +{ \ + (n) = ( (unsigned long) (b)[(i) ] ) \ + | ( (unsigned long) (b)[(i) + 1] << 8 ) \ + | ( (unsigned long) (b)[(i) + 2] << 16 ) \ + | ( (unsigned long) (b)[(i) + 3] << 24 ); \ +} +#endif + +#ifndef PUT_ULONG_LE +#define PUT_ULONG_LE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) >> 24 ); \ +} +#endif + +#if defined(POLARSSL_AES_ROM_TABLES) +/* + * Forward S-box + */ +static const unsigned char FSb[256] = +{ + 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, + 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, + 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, + 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, + 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, + 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, + 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, + 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, + 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, + 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, + 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, + 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, + 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, + 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, + 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, + 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, + 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, + 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, + 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, + 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, + 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, + 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, + 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, + 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, + 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, + 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, + 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, + 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, + 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, + 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, + 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, + 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 +}; + +/* + * Forward tables + */ +#define FT \ +\ + V(A5,63,63,C6), V(84,7C,7C,F8), V(99,77,77,EE), V(8D,7B,7B,F6), \ + V(0D,F2,F2,FF), V(BD,6B,6B,D6), V(B1,6F,6F,DE), V(54,C5,C5,91), \ + V(50,30,30,60), V(03,01,01,02), V(A9,67,67,CE), V(7D,2B,2B,56), \ + V(19,FE,FE,E7), V(62,D7,D7,B5), V(E6,AB,AB,4D), V(9A,76,76,EC), \ + V(45,CA,CA,8F), V(9D,82,82,1F), V(40,C9,C9,89), V(87,7D,7D,FA), \ + V(15,FA,FA,EF), V(EB,59,59,B2), V(C9,47,47,8E), V(0B,F0,F0,FB), \ + V(EC,AD,AD,41), V(67,D4,D4,B3), V(FD,A2,A2,5F), V(EA,AF,AF,45), \ + V(BF,9C,9C,23), V(F7,A4,A4,53), V(96,72,72,E4), V(5B,C0,C0,9B), \ + V(C2,B7,B7,75), V(1C,FD,FD,E1), V(AE,93,93,3D), V(6A,26,26,4C), \ + V(5A,36,36,6C), V(41,3F,3F,7E), V(02,F7,F7,F5), V(4F,CC,CC,83), \ + V(5C,34,34,68), V(F4,A5,A5,51), V(34,E5,E5,D1), V(08,F1,F1,F9), \ + V(93,71,71,E2), V(73,D8,D8,AB), V(53,31,31,62), V(3F,15,15,2A), \ + V(0C,04,04,08), V(52,C7,C7,95), V(65,23,23,46), V(5E,C3,C3,9D), \ + V(28,18,18,30), V(A1,96,96,37), V(0F,05,05,0A), V(B5,9A,9A,2F), \ + V(09,07,07,0E), V(36,12,12,24), V(9B,80,80,1B), V(3D,E2,E2,DF), \ + V(26,EB,EB,CD), V(69,27,27,4E), V(CD,B2,B2,7F), V(9F,75,75,EA), \ + V(1B,09,09,12), V(9E,83,83,1D), V(74,2C,2C,58), V(2E,1A,1A,34), \ + V(2D,1B,1B,36), V(B2,6E,6E,DC), V(EE,5A,5A,B4), V(FB,A0,A0,5B), \ + V(F6,52,52,A4), V(4D,3B,3B,76), V(61,D6,D6,B7), V(CE,B3,B3,7D), \ + V(7B,29,29,52), V(3E,E3,E3,DD), V(71,2F,2F,5E), V(97,84,84,13), \ + V(F5,53,53,A6), V(68,D1,D1,B9), V(00,00,00,00), V(2C,ED,ED,C1), \ + V(60,20,20,40), V(1F,FC,FC,E3), V(C8,B1,B1,79), V(ED,5B,5B,B6), \ + V(BE,6A,6A,D4), V(46,CB,CB,8D), V(D9,BE,BE,67), V(4B,39,39,72), \ + V(DE,4A,4A,94), V(D4,4C,4C,98), V(E8,58,58,B0), V(4A,CF,CF,85), \ + V(6B,D0,D0,BB), V(2A,EF,EF,C5), V(E5,AA,AA,4F), V(16,FB,FB,ED), \ + V(C5,43,43,86), V(D7,4D,4D,9A), V(55,33,33,66), V(94,85,85,11), \ + V(CF,45,45,8A), V(10,F9,F9,E9), V(06,02,02,04), V(81,7F,7F,FE), \ + V(F0,50,50,A0), V(44,3C,3C,78), V(BA,9F,9F,25), V(E3,A8,A8,4B), \ + V(F3,51,51,A2), V(FE,A3,A3,5D), V(C0,40,40,80), V(8A,8F,8F,05), \ + V(AD,92,92,3F), V(BC,9D,9D,21), V(48,38,38,70), V(04,F5,F5,F1), \ + V(DF,BC,BC,63), V(C1,B6,B6,77), V(75,DA,DA,AF), V(63,21,21,42), \ + V(30,10,10,20), V(1A,FF,FF,E5), V(0E,F3,F3,FD), V(6D,D2,D2,BF), \ + V(4C,CD,CD,81), V(14,0C,0C,18), V(35,13,13,26), V(2F,EC,EC,C3), \ + V(E1,5F,5F,BE), V(A2,97,97,35), V(CC,44,44,88), V(39,17,17,2E), \ + V(57,C4,C4,93), V(F2,A7,A7,55), V(82,7E,7E,FC), V(47,3D,3D,7A), \ + V(AC,64,64,C8), V(E7,5D,5D,BA), V(2B,19,19,32), V(95,73,73,E6), \ + V(A0,60,60,C0), V(98,81,81,19), V(D1,4F,4F,9E), V(7F,DC,DC,A3), \ + V(66,22,22,44), V(7E,2A,2A,54), V(AB,90,90,3B), V(83,88,88,0B), \ + V(CA,46,46,8C), V(29,EE,EE,C7), V(D3,B8,B8,6B), V(3C,14,14,28), \ + V(79,DE,DE,A7), V(E2,5E,5E,BC), V(1D,0B,0B,16), V(76,DB,DB,AD), \ + V(3B,E0,E0,DB), V(56,32,32,64), V(4E,3A,3A,74), V(1E,0A,0A,14), \ + V(DB,49,49,92), V(0A,06,06,0C), V(6C,24,24,48), V(E4,5C,5C,B8), \ + V(5D,C2,C2,9F), V(6E,D3,D3,BD), V(EF,AC,AC,43), V(A6,62,62,C4), \ + V(A8,91,91,39), V(A4,95,95,31), V(37,E4,E4,D3), V(8B,79,79,F2), \ + V(32,E7,E7,D5), V(43,C8,C8,8B), V(59,37,37,6E), V(B7,6D,6D,DA), \ + V(8C,8D,8D,01), V(64,D5,D5,B1), V(D2,4E,4E,9C), V(E0,A9,A9,49), \ + V(B4,6C,6C,D8), V(FA,56,56,AC), V(07,F4,F4,F3), V(25,EA,EA,CF), \ + V(AF,65,65,CA), V(8E,7A,7A,F4), V(E9,AE,AE,47), V(18,08,08,10), \ + V(D5,BA,BA,6F), V(88,78,78,F0), V(6F,25,25,4A), V(72,2E,2E,5C), \ + V(24,1C,1C,38), V(F1,A6,A6,57), V(C7,B4,B4,73), V(51,C6,C6,97), \ + V(23,E8,E8,CB), V(7C,DD,DD,A1), V(9C,74,74,E8), V(21,1F,1F,3E), \ + V(DD,4B,4B,96), V(DC,BD,BD,61), V(86,8B,8B,0D), V(85,8A,8A,0F), \ + V(90,70,70,E0), V(42,3E,3E,7C), V(C4,B5,B5,71), V(AA,66,66,CC), \ + V(D8,48,48,90), V(05,03,03,06), V(01,F6,F6,F7), V(12,0E,0E,1C), \ + V(A3,61,61,C2), V(5F,35,35,6A), V(F9,57,57,AE), V(D0,B9,B9,69), \ + V(91,86,86,17), V(58,C1,C1,99), V(27,1D,1D,3A), V(B9,9E,9E,27), \ + V(38,E1,E1,D9), V(13,F8,F8,EB), V(B3,98,98,2B), V(33,11,11,22), \ + V(BB,69,69,D2), V(70,D9,D9,A9), V(89,8E,8E,07), V(A7,94,94,33), \ + V(B6,9B,9B,2D), V(22,1E,1E,3C), V(92,87,87,15), V(20,E9,E9,C9), \ + V(49,CE,CE,87), V(FF,55,55,AA), V(78,28,28,50), V(7A,DF,DF,A5), \ + V(8F,8C,8C,03), V(F8,A1,A1,59), V(80,89,89,09), V(17,0D,0D,1A), \ + V(DA,BF,BF,65), V(31,E6,E6,D7), V(C6,42,42,84), V(B8,68,68,D0), \ + V(C3,41,41,82), V(B0,99,99,29), V(77,2D,2D,5A), V(11,0F,0F,1E), \ + V(CB,B0,B0,7B), V(FC,54,54,A8), V(D6,BB,BB,6D), V(3A,16,16,2C) + +#define V(a,b,c,d) 0x##a##b##c##d +static const unsigned long FT0[256] = { FT }; +#undef V + +#define V(a,b,c,d) 0x##b##c##d##a +static const unsigned long FT1[256] = { FT }; +#undef V + +#define V(a,b,c,d) 0x##c##d##a##b +static const unsigned long FT2[256] = { FT }; +#undef V + +#define V(a,b,c,d) 0x##d##a##b##c +static const unsigned long FT3[256] = { FT }; +#undef V + +#undef FT + +/* + * Reverse S-box + */ +static const unsigned char RSb[256] = +{ + 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, + 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, + 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, + 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, + 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, + 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, + 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, + 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, + 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, + 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, + 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, + 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, + 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, + 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, + 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, + 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, + 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, + 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, + 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, + 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, + 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, + 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, + 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, + 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, + 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, + 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, + 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, + 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, + 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, + 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, + 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D +}; + +/* + * Reverse tables + */ +#define RT \ +\ + V(50,A7,F4,51), V(53,65,41,7E), V(C3,A4,17,1A), V(96,5E,27,3A), \ + V(CB,6B,AB,3B), V(F1,45,9D,1F), V(AB,58,FA,AC), V(93,03,E3,4B), \ + V(55,FA,30,20), V(F6,6D,76,AD), V(91,76,CC,88), V(25,4C,02,F5), \ + V(FC,D7,E5,4F), V(D7,CB,2A,C5), V(80,44,35,26), V(8F,A3,62,B5), \ + V(49,5A,B1,DE), V(67,1B,BA,25), V(98,0E,EA,45), V(E1,C0,FE,5D), \ + V(02,75,2F,C3), V(12,F0,4C,81), V(A3,97,46,8D), V(C6,F9,D3,6B), \ + V(E7,5F,8F,03), V(95,9C,92,15), V(EB,7A,6D,BF), V(DA,59,52,95), \ + V(2D,83,BE,D4), V(D3,21,74,58), V(29,69,E0,49), V(44,C8,C9,8E), \ + V(6A,89,C2,75), V(78,79,8E,F4), V(6B,3E,58,99), V(DD,71,B9,27), \ + V(B6,4F,E1,BE), V(17,AD,88,F0), V(66,AC,20,C9), V(B4,3A,CE,7D), \ + V(18,4A,DF,63), V(82,31,1A,E5), V(60,33,51,97), V(45,7F,53,62), \ + V(E0,77,64,B1), V(84,AE,6B,BB), V(1C,A0,81,FE), V(94,2B,08,F9), \ + V(58,68,48,70), V(19,FD,45,8F), V(87,6C,DE,94), V(B7,F8,7B,52), \ + V(23,D3,73,AB), V(E2,02,4B,72), V(57,8F,1F,E3), V(2A,AB,55,66), \ + V(07,28,EB,B2), V(03,C2,B5,2F), V(9A,7B,C5,86), V(A5,08,37,D3), \ + V(F2,87,28,30), V(B2,A5,BF,23), V(BA,6A,03,02), V(5C,82,16,ED), \ + V(2B,1C,CF,8A), V(92,B4,79,A7), V(F0,F2,07,F3), V(A1,E2,69,4E), \ + V(CD,F4,DA,65), V(D5,BE,05,06), V(1F,62,34,D1), V(8A,FE,A6,C4), \ + V(9D,53,2E,34), V(A0,55,F3,A2), V(32,E1,8A,05), V(75,EB,F6,A4), \ + V(39,EC,83,0B), V(AA,EF,60,40), V(06,9F,71,5E), V(51,10,6E,BD), \ + V(F9,8A,21,3E), V(3D,06,DD,96), V(AE,05,3E,DD), V(46,BD,E6,4D), \ + V(B5,8D,54,91), V(05,5D,C4,71), V(6F,D4,06,04), V(FF,15,50,60), \ + V(24,FB,98,19), V(97,E9,BD,D6), V(CC,43,40,89), V(77,9E,D9,67), \ + V(BD,42,E8,B0), V(88,8B,89,07), V(38,5B,19,E7), V(DB,EE,C8,79), \ + V(47,0A,7C,A1), V(E9,0F,42,7C), V(C9,1E,84,F8), V(00,00,00,00), \ + V(83,86,80,09), V(48,ED,2B,32), V(AC,70,11,1E), V(4E,72,5A,6C), \ + V(FB,FF,0E,FD), V(56,38,85,0F), V(1E,D5,AE,3D), V(27,39,2D,36), \ + V(64,D9,0F,0A), V(21,A6,5C,68), V(D1,54,5B,9B), V(3A,2E,36,24), \ + V(B1,67,0A,0C), V(0F,E7,57,93), V(D2,96,EE,B4), V(9E,91,9B,1B), \ + V(4F,C5,C0,80), V(A2,20,DC,61), V(69,4B,77,5A), V(16,1A,12,1C), \ + V(0A,BA,93,E2), V(E5,2A,A0,C0), V(43,E0,22,3C), V(1D,17,1B,12), \ + V(0B,0D,09,0E), V(AD,C7,8B,F2), V(B9,A8,B6,2D), V(C8,A9,1E,14), \ + V(85,19,F1,57), V(4C,07,75,AF), V(BB,DD,99,EE), V(FD,60,7F,A3), \ + V(9F,26,01,F7), V(BC,F5,72,5C), V(C5,3B,66,44), V(34,7E,FB,5B), \ + V(76,29,43,8B), V(DC,C6,23,CB), V(68,FC,ED,B6), V(63,F1,E4,B8), \ + V(CA,DC,31,D7), V(10,85,63,42), V(40,22,97,13), V(20,11,C6,84), \ + V(7D,24,4A,85), V(F8,3D,BB,D2), V(11,32,F9,AE), V(6D,A1,29,C7), \ + V(4B,2F,9E,1D), V(F3,30,B2,DC), V(EC,52,86,0D), V(D0,E3,C1,77), \ + V(6C,16,B3,2B), V(99,B9,70,A9), V(FA,48,94,11), V(22,64,E9,47), \ + V(C4,8C,FC,A8), V(1A,3F,F0,A0), V(D8,2C,7D,56), V(EF,90,33,22), \ + V(C7,4E,49,87), V(C1,D1,38,D9), V(FE,A2,CA,8C), V(36,0B,D4,98), \ + V(CF,81,F5,A6), V(28,DE,7A,A5), V(26,8E,B7,DA), V(A4,BF,AD,3F), \ + V(E4,9D,3A,2C), V(0D,92,78,50), V(9B,CC,5F,6A), V(62,46,7E,54), \ + V(C2,13,8D,F6), V(E8,B8,D8,90), V(5E,F7,39,2E), V(F5,AF,C3,82), \ + V(BE,80,5D,9F), V(7C,93,D0,69), V(A9,2D,D5,6F), V(B3,12,25,CF), \ + V(3B,99,AC,C8), V(A7,7D,18,10), V(6E,63,9C,E8), V(7B,BB,3B,DB), \ + V(09,78,26,CD), V(F4,18,59,6E), V(01,B7,9A,EC), V(A8,9A,4F,83), \ + V(65,6E,95,E6), V(7E,E6,FF,AA), V(08,CF,BC,21), V(E6,E8,15,EF), \ + V(D9,9B,E7,BA), V(CE,36,6F,4A), V(D4,09,9F,EA), V(D6,7C,B0,29), \ + V(AF,B2,A4,31), V(31,23,3F,2A), V(30,94,A5,C6), V(C0,66,A2,35), \ + V(37,BC,4E,74), V(A6,CA,82,FC), V(B0,D0,90,E0), V(15,D8,A7,33), \ + V(4A,98,04,F1), V(F7,DA,EC,41), V(0E,50,CD,7F), V(2F,F6,91,17), \ + V(8D,D6,4D,76), V(4D,B0,EF,43), V(54,4D,AA,CC), V(DF,04,96,E4), \ + V(E3,B5,D1,9E), V(1B,88,6A,4C), V(B8,1F,2C,C1), V(7F,51,65,46), \ + V(04,EA,5E,9D), V(5D,35,8C,01), V(73,74,87,FA), V(2E,41,0B,FB), \ + V(5A,1D,67,B3), V(52,D2,DB,92), V(33,56,10,E9), V(13,47,D6,6D), \ + V(8C,61,D7,9A), V(7A,0C,A1,37), V(8E,14,F8,59), V(89,3C,13,EB), \ + V(EE,27,A9,CE), V(35,C9,61,B7), V(ED,E5,1C,E1), V(3C,B1,47,7A), \ + V(59,DF,D2,9C), V(3F,73,F2,55), V(79,CE,14,18), V(BF,37,C7,73), \ + V(EA,CD,F7,53), V(5B,AA,FD,5F), V(14,6F,3D,DF), V(86,DB,44,78), \ + V(81,F3,AF,CA), V(3E,C4,68,B9), V(2C,34,24,38), V(5F,40,A3,C2), \ + V(72,C3,1D,16), V(0C,25,E2,BC), V(8B,49,3C,28), V(41,95,0D,FF), \ + V(71,01,A8,39), V(DE,B3,0C,08), V(9C,E4,B4,D8), V(90,C1,56,64), \ + V(61,84,CB,7B), V(70,B6,32,D5), V(74,5C,6C,48), V(42,57,B8,D0) + +#define V(a,b,c,d) 0x##a##b##c##d +static const unsigned long RT0[256] = { RT }; +#undef V + +#define V(a,b,c,d) 0x##b##c##d##a +static const unsigned long RT1[256] = { RT }; +#undef V + +#define V(a,b,c,d) 0x##c##d##a##b +static const unsigned long RT2[256] = { RT }; +#undef V + +#define V(a,b,c,d) 0x##d##a##b##c +static const unsigned long RT3[256] = { RT }; +#undef V + +#undef RT + +/* + * Round constants + */ +static const unsigned long RCON[10] = +{ + 0x00000001, 0x00000002, 0x00000004, 0x00000008, + 0x00000010, 0x00000020, 0x00000040, 0x00000080, + 0x0000001B, 0x00000036 +}; + +#else + +/* + * Forward S-box & tables + */ +static unsigned char FSb[256]; +static unsigned long FT0[256]; +static unsigned long FT1[256]; +static unsigned long FT2[256]; +static unsigned long FT3[256]; + +/* + * Reverse S-box & tables + */ +static unsigned char RSb[256]; +static unsigned long RT0[256]; +static unsigned long RT1[256]; +static unsigned long RT2[256]; +static unsigned long RT3[256]; + +/* + * Round constants + */ +static unsigned long RCON[10]; + +/* + * Tables generation code + */ +#define ROTL8(x) ( ( x << 8 ) & 0xFFFFFFFF ) | ( x >> 24 ) +#define XTIME(x) ( ( x << 1 ) ^ ( ( x & 0x80 ) ? 0x1B : 0x00 ) ) +#define MUL(x,y) ( ( x && y ) ? pow[(log[x]+log[y]) % 255] : 0 ) + +static int aes_init_done = 0; + +static void aes_gen_tables( void ) +{ + int i, x, y, z; + int pow[256]; + int log[256]; + + /* + * compute pow and log tables over GF(2^8) + */ + for( i = 0, x = 1; i < 256; i++ ) + { + pow[i] = x; + log[x] = i; + x = ( x ^ XTIME( x ) ) & 0xFF; + } + + /* + * calculate the round constants + */ + for( i = 0, x = 1; i < 10; i++ ) + { + RCON[i] = (unsigned long) x; + x = XTIME( x ) & 0xFF; + } + + /* + * generate the forward and reverse S-boxes + */ + FSb[0x00] = 0x63; + RSb[0x63] = 0x00; + + for( i = 1; i < 256; i++ ) + { + x = pow[255 - log[i]]; + + y = x; y = ( (y << 1) | (y >> 7) ) & 0xFF; + x ^= y; y = ( (y << 1) | (y >> 7) ) & 0xFF; + x ^= y; y = ( (y << 1) | (y >> 7) ) & 0xFF; + x ^= y; y = ( (y << 1) | (y >> 7) ) & 0xFF; + x ^= y ^ 0x63; + + FSb[i] = (unsigned char) x; + RSb[x] = (unsigned char) i; + } + + /* + * generate the forward and reverse tables + */ + for( i = 0; i < 256; i++ ) + { + x = FSb[i]; + y = XTIME( x ) & 0xFF; + z = ( y ^ x ) & 0xFF; + + FT0[i] = ( (unsigned long) y ) ^ + ( (unsigned long) x << 8 ) ^ + ( (unsigned long) x << 16 ) ^ + ( (unsigned long) z << 24 ); + + FT1[i] = ROTL8( FT0[i] ); + FT2[i] = ROTL8( FT1[i] ); + FT3[i] = ROTL8( FT2[i] ); + + x = RSb[i]; + + RT0[i] = ( (unsigned long) MUL( 0x0E, x ) ) ^ + ( (unsigned long) MUL( 0x09, x ) << 8 ) ^ + ( (unsigned long) MUL( 0x0D, x ) << 16 ) ^ + ( (unsigned long) MUL( 0x0B, x ) << 24 ); + + RT1[i] = ROTL8( RT0[i] ); + RT2[i] = ROTL8( RT1[i] ); + RT3[i] = ROTL8( RT2[i] ); + } +} + +#endif + +/* + * AES key schedule (encryption) + */ +int aes_setkey_enc( aes_context *ctx, const unsigned char *key, unsigned int keysize ) +{ + unsigned int i; + unsigned long *RK; + +#if !defined(POLARSSL_AES_ROM_TABLES) + if( aes_init_done == 0 ) + { + aes_gen_tables(); + aes_init_done = 1; + } +#endif + + switch( keysize ) + { + case 128: ctx->nr = 10; break; + case 192: ctx->nr = 12; break; + case 256: ctx->nr = 14; break; + default : return( POLARSSL_ERR_AES_INVALID_KEY_LENGTH ); + } + +#if defined(PADLOCK_ALIGN16) + ctx->rk = RK = PADLOCK_ALIGN16( ctx->buf ); +#else + ctx->rk = RK = ctx->buf; +#endif + + for( i = 0; i < (keysize >> 5); i++ ) + { + GET_ULONG_LE( RK[i], key, i << 2 ); + } + + switch( ctx->nr ) + { + case 10: + + for( i = 0; i < 10; i++, RK += 4 ) + { + RK[4] = RK[0] ^ RCON[i] ^ + ( (unsigned long) FSb[ ( RK[3] >> 8 ) & 0xFF ] ) ^ + ( (unsigned long) FSb[ ( RK[3] >> 16 ) & 0xFF ] << 8 ) ^ + ( (unsigned long) FSb[ ( RK[3] >> 24 ) & 0xFF ] << 16 ) ^ + ( (unsigned long) FSb[ ( RK[3] ) & 0xFF ] << 24 ); + + RK[5] = RK[1] ^ RK[4]; + RK[6] = RK[2] ^ RK[5]; + RK[7] = RK[3] ^ RK[6]; + } + break; + + case 12: + + for( i = 0; i < 8; i++, RK += 6 ) + { + RK[6] = RK[0] ^ RCON[i] ^ + ( (unsigned long) FSb[ ( RK[5] >> 8 ) & 0xFF ] ) ^ + ( (unsigned long) FSb[ ( RK[5] >> 16 ) & 0xFF ] << 8 ) ^ + ( (unsigned long) FSb[ ( RK[5] >> 24 ) & 0xFF ] << 16 ) ^ + ( (unsigned long) FSb[ ( RK[5] ) & 0xFF ] << 24 ); + + RK[7] = RK[1] ^ RK[6]; + RK[8] = RK[2] ^ RK[7]; + RK[9] = RK[3] ^ RK[8]; + RK[10] = RK[4] ^ RK[9]; + RK[11] = RK[5] ^ RK[10]; + } + break; + + case 14: + + for( i = 0; i < 7; i++, RK += 8 ) + { + RK[8] = RK[0] ^ RCON[i] ^ + ( (unsigned long) FSb[ ( RK[7] >> 8 ) & 0xFF ] ) ^ + ( (unsigned long) FSb[ ( RK[7] >> 16 ) & 0xFF ] << 8 ) ^ + ( (unsigned long) FSb[ ( RK[7] >> 24 ) & 0xFF ] << 16 ) ^ + ( (unsigned long) FSb[ ( RK[7] ) & 0xFF ] << 24 ); + + RK[9] = RK[1] ^ RK[8]; + RK[10] = RK[2] ^ RK[9]; + RK[11] = RK[3] ^ RK[10]; + + RK[12] = RK[4] ^ + ( (unsigned long) FSb[ ( RK[11] ) & 0xFF ] ) ^ + ( (unsigned long) FSb[ ( RK[11] >> 8 ) & 0xFF ] << 8 ) ^ + ( (unsigned long) FSb[ ( RK[11] >> 16 ) & 0xFF ] << 16 ) ^ + ( (unsigned long) FSb[ ( RK[11] >> 24 ) & 0xFF ] << 24 ); + + RK[13] = RK[5] ^ RK[12]; + RK[14] = RK[6] ^ RK[13]; + RK[15] = RK[7] ^ RK[14]; + } + break; + + default: + + break; + } + + return( 0 ); +} + +/* + * AES key schedule (decryption) + */ +int aes_setkey_dec( aes_context *ctx, const unsigned char *key, unsigned int keysize ) +{ + int i, j; + aes_context cty; + unsigned long *RK; + unsigned long *SK; + int ret; + + switch( keysize ) + { + case 128: ctx->nr = 10; break; + case 192: ctx->nr = 12; break; + case 256: ctx->nr = 14; break; + default : return( POLARSSL_ERR_AES_INVALID_KEY_LENGTH ); + } + +#if defined(PADLOCK_ALIGN16) + ctx->rk = RK = PADLOCK_ALIGN16( ctx->buf ); +#else + ctx->rk = RK = ctx->buf; +#endif + + ret = aes_setkey_enc( &cty, key, keysize ); + if( ret != 0 ) + return( ret ); + + SK = cty.rk + cty.nr * 4; + + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + + for( i = ctx->nr - 1, SK -= 8; i > 0; i--, SK -= 8 ) + { + for( j = 0; j < 4; j++, SK++ ) + { + *RK++ = RT0[ FSb[ ( *SK ) & 0xFF ] ] ^ + RT1[ FSb[ ( *SK >> 8 ) & 0xFF ] ] ^ + RT2[ FSb[ ( *SK >> 16 ) & 0xFF ] ] ^ + RT3[ FSb[ ( *SK >> 24 ) & 0xFF ] ]; + } + } + + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + + memset( &cty, 0, sizeof( aes_context ) ); + + return( 0 ); +} + +#define AES_FROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ +{ \ + X0 = *RK++ ^ FT0[ ( Y0 ) & 0xFF ] ^ \ + FT1[ ( Y1 >> 8 ) & 0xFF ] ^ \ + FT2[ ( Y2 >> 16 ) & 0xFF ] ^ \ + FT3[ ( Y3 >> 24 ) & 0xFF ]; \ + \ + X1 = *RK++ ^ FT0[ ( Y1 ) & 0xFF ] ^ \ + FT1[ ( Y2 >> 8 ) & 0xFF ] ^ \ + FT2[ ( Y3 >> 16 ) & 0xFF ] ^ \ + FT3[ ( Y0 >> 24 ) & 0xFF ]; \ + \ + X2 = *RK++ ^ FT0[ ( Y2 ) & 0xFF ] ^ \ + FT1[ ( Y3 >> 8 ) & 0xFF ] ^ \ + FT2[ ( Y0 >> 16 ) & 0xFF ] ^ \ + FT3[ ( Y1 >> 24 ) & 0xFF ]; \ + \ + X3 = *RK++ ^ FT0[ ( Y3 ) & 0xFF ] ^ \ + FT1[ ( Y0 >> 8 ) & 0xFF ] ^ \ + FT2[ ( Y1 >> 16 ) & 0xFF ] ^ \ + FT3[ ( Y2 >> 24 ) & 0xFF ]; \ +} + +#define AES_RROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ +{ \ + X0 = *RK++ ^ RT0[ ( Y0 ) & 0xFF ] ^ \ + RT1[ ( Y3 >> 8 ) & 0xFF ] ^ \ + RT2[ ( Y2 >> 16 ) & 0xFF ] ^ \ + RT3[ ( Y1 >> 24 ) & 0xFF ]; \ + \ + X1 = *RK++ ^ RT0[ ( Y1 ) & 0xFF ] ^ \ + RT1[ ( Y0 >> 8 ) & 0xFF ] ^ \ + RT2[ ( Y3 >> 16 ) & 0xFF ] ^ \ + RT3[ ( Y2 >> 24 ) & 0xFF ]; \ + \ + X2 = *RK++ ^ RT0[ ( Y2 ) & 0xFF ] ^ \ + RT1[ ( Y1 >> 8 ) & 0xFF ] ^ \ + RT2[ ( Y0 >> 16 ) & 0xFF ] ^ \ + RT3[ ( Y3 >> 24 ) & 0xFF ]; \ + \ + X3 = *RK++ ^ RT0[ ( Y3 ) & 0xFF ] ^ \ + RT1[ ( Y2 >> 8 ) & 0xFF ] ^ \ + RT2[ ( Y1 >> 16 ) & 0xFF ] ^ \ + RT3[ ( Y0 >> 24 ) & 0xFF ]; \ +} + +/* + * AES-ECB block encryption/decryption + */ +int aes_crypt_ecb( aes_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ) +{ + int i; + unsigned long *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; + +#if defined(POLARSSL_PADLOCK_C) && defined(POLARSSL_HAVE_X86) + if( padlock_supports( PADLOCK_ACE ) ) + { + if( padlock_xcryptecb( ctx, mode, input, output ) == 0 ) + return( 0 ); + + // If padlock data misaligned, we just fall back to + // unaccelerated mode + // + } +#endif + + RK = ctx->rk; + + GET_ULONG_LE( X0, input, 0 ); X0 ^= *RK++; + GET_ULONG_LE( X1, input, 4 ); X1 ^= *RK++; + GET_ULONG_LE( X2, input, 8 ); X2 ^= *RK++; + GET_ULONG_LE( X3, input, 12 ); X3 ^= *RK++; + + if( mode == AES_DECRYPT ) + { + for( i = (ctx->nr >> 1) - 1; i > 0; i-- ) + { + AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); + AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); + } + + AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); + + X0 = *RK++ ^ \ + ( (unsigned long) RSb[ ( Y0 ) & 0xFF ] ) ^ + ( (unsigned long) RSb[ ( Y3 >> 8 ) & 0xFF ] << 8 ) ^ + ( (unsigned long) RSb[ ( Y2 >> 16 ) & 0xFF ] << 16 ) ^ + ( (unsigned long) RSb[ ( Y1 >> 24 ) & 0xFF ] << 24 ); + + X1 = *RK++ ^ \ + ( (unsigned long) RSb[ ( Y1 ) & 0xFF ] ) ^ + ( (unsigned long) RSb[ ( Y0 >> 8 ) & 0xFF ] << 8 ) ^ + ( (unsigned long) RSb[ ( Y3 >> 16 ) & 0xFF ] << 16 ) ^ + ( (unsigned long) RSb[ ( Y2 >> 24 ) & 0xFF ] << 24 ); + + X2 = *RK++ ^ \ + ( (unsigned long) RSb[ ( Y2 ) & 0xFF ] ) ^ + ( (unsigned long) RSb[ ( Y1 >> 8 ) & 0xFF ] << 8 ) ^ + ( (unsigned long) RSb[ ( Y0 >> 16 ) & 0xFF ] << 16 ) ^ + ( (unsigned long) RSb[ ( Y3 >> 24 ) & 0xFF ] << 24 ); + + X3 = *RK++ ^ \ + ( (unsigned long) RSb[ ( Y3 ) & 0xFF ] ) ^ + ( (unsigned long) RSb[ ( Y2 >> 8 ) & 0xFF ] << 8 ) ^ + ( (unsigned long) RSb[ ( Y1 >> 16 ) & 0xFF ] << 16 ) ^ + ( (unsigned long) RSb[ ( Y0 >> 24 ) & 0xFF ] << 24 ); + } + else /* AES_ENCRYPT */ + { + for( i = (ctx->nr >> 1) - 1; i > 0; i-- ) + { + AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); + AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); + } + + AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); + + X0 = *RK++ ^ \ + ( (unsigned long) FSb[ ( Y0 ) & 0xFF ] ) ^ + ( (unsigned long) FSb[ ( Y1 >> 8 ) & 0xFF ] << 8 ) ^ + ( (unsigned long) FSb[ ( Y2 >> 16 ) & 0xFF ] << 16 ) ^ + ( (unsigned long) FSb[ ( Y3 >> 24 ) & 0xFF ] << 24 ); + + X1 = *RK++ ^ \ + ( (unsigned long) FSb[ ( Y1 ) & 0xFF ] ) ^ + ( (unsigned long) FSb[ ( Y2 >> 8 ) & 0xFF ] << 8 ) ^ + ( (unsigned long) FSb[ ( Y3 >> 16 ) & 0xFF ] << 16 ) ^ + ( (unsigned long) FSb[ ( Y0 >> 24 ) & 0xFF ] << 24 ); + + X2 = *RK++ ^ \ + ( (unsigned long) FSb[ ( Y2 ) & 0xFF ] ) ^ + ( (unsigned long) FSb[ ( Y3 >> 8 ) & 0xFF ] << 8 ) ^ + ( (unsigned long) FSb[ ( Y0 >> 16 ) & 0xFF ] << 16 ) ^ + ( (unsigned long) FSb[ ( Y1 >> 24 ) & 0xFF ] << 24 ); + + X3 = *RK++ ^ \ + ( (unsigned long) FSb[ ( Y3 ) & 0xFF ] ) ^ + ( (unsigned long) FSb[ ( Y0 >> 8 ) & 0xFF ] << 8 ) ^ + ( (unsigned long) FSb[ ( Y1 >> 16 ) & 0xFF ] << 16 ) ^ + ( (unsigned long) FSb[ ( Y2 >> 24 ) & 0xFF ] << 24 ); + } + + PUT_ULONG_LE( X0, output, 0 ); + PUT_ULONG_LE( X1, output, 4 ); + PUT_ULONG_LE( X2, output, 8 ); + PUT_ULONG_LE( X3, output, 12 ); + + return( 0 ); +} + +/* + * AES-CBC buffer encryption/decryption + */ +int aes_crypt_cbc( aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + int i; + unsigned char temp[16]; + + if( length % 16 ) + return( POLARSSL_ERR_AES_INVALID_INPUT_LENGTH ); + +#if defined(POLARSSL_PADLOCK_C) && defined(POLARSSL_HAVE_X86) + if( padlock_supports( PADLOCK_ACE ) ) + { + if( padlock_xcryptcbc( ctx, mode, length, iv, input, output ) == 0 ) + return( 0 ); + + // If padlock data misaligned, we just fall back to + // unaccelerated mode + // + } +#endif + + if( mode == AES_DECRYPT ) + { + while( length > 0 ) + { + memcpy( temp, input, 16 ); + aes_crypt_ecb( ctx, mode, input, output ); + + for( i = 0; i < 16; i++ ) + output[i] = (unsigned char)( output[i] ^ iv[i] ); + + memcpy( iv, temp, 16 ); + + input += 16; + output += 16; + length -= 16; + } + } + else + { + while( length > 0 ) + { + for( i = 0; i < 16; i++ ) + output[i] = (unsigned char)( input[i] ^ iv[i] ); + + aes_crypt_ecb( ctx, mode, output, output ); + memcpy( iv, output, 16 ); + + input += 16; + output += 16; + length -= 16; + } + } + + return( 0 ); +} + +#if defined(POLARSSL_CIPHER_MODE_CFB) +/* + * AES-CFB128 buffer encryption/decryption + */ +int aes_crypt_cfb128( aes_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + int c; + size_t n = *iv_off; + + if( mode == AES_DECRYPT ) + { + while( length-- ) + { + if( n == 0 ) + aes_crypt_ecb( ctx, AES_ENCRYPT, iv, iv ); + + c = *input++; + *output++ = (unsigned char)( c ^ iv[n] ); + iv[n] = (unsigned char) c; + + n = (n + 1) & 0x0F; + } + } + else + { + while( length-- ) + { + if( n == 0 ) + aes_crypt_ecb( ctx, AES_ENCRYPT, iv, iv ); + + iv[n] = *output++ = (unsigned char)( iv[n] ^ *input++ ); + + n = (n + 1) & 0x0F; + } + } + + *iv_off = n; + + return( 0 ); +} +#endif /*POLARSSL_CIPHER_MODE_CFB */ + +#if defined(POLARSSL_CIPHER_MODE_CTR) +/* + * AES-CTR buffer encryption/decryption + */ +int aes_crypt_ctr( aes_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[16], + unsigned char stream_block[16], + const unsigned char *input, + unsigned char *output ) +{ + int c, i, cb; + size_t n = *nc_off; + + while( length-- ) + { + if( n == 0 ) { + aes_crypt_ecb( ctx, AES_ENCRYPT, nonce_counter, stream_block ); + + i = 15; + do { + nonce_counter[i]++; + cb = nonce_counter[i] == 0; + } while( i-- && cb ); + + } + c = *input++; + *output++ = (unsigned char)( c ^ stream_block[n] ); + + n = (n + 1) & 0x0F; + } + + *nc_off = n; + + return( 0 ); +} +#endif /* POLARSSL_CIPHER_MODE_CTR */ + +#if defined(POLARSSL_SELF_TEST) + +#include + +/* + * AES test vectors from: + * + * http://csrc.nist.gov/archive/aes/rijndael/rijndael-vals.zip + */ +static const unsigned char aes_test_ecb_dec[3][16] = +{ + { 0x44, 0x41, 0x6A, 0xC2, 0xD1, 0xF5, 0x3C, 0x58, + 0x33, 0x03, 0x91, 0x7E, 0x6B, 0xE9, 0xEB, 0xE0 }, + { 0x48, 0xE3, 0x1E, 0x9E, 0x25, 0x67, 0x18, 0xF2, + 0x92, 0x29, 0x31, 0x9C, 0x19, 0xF1, 0x5B, 0xA4 }, + { 0x05, 0x8C, 0xCF, 0xFD, 0xBB, 0xCB, 0x38, 0x2D, + 0x1F, 0x6F, 0x56, 0x58, 0x5D, 0x8A, 0x4A, 0xDE } +}; + +static const unsigned char aes_test_ecb_enc[3][16] = +{ + { 0xC3, 0x4C, 0x05, 0x2C, 0xC0, 0xDA, 0x8D, 0x73, + 0x45, 0x1A, 0xFE, 0x5F, 0x03, 0xBE, 0x29, 0x7F }, + { 0xF3, 0xF6, 0x75, 0x2A, 0xE8, 0xD7, 0x83, 0x11, + 0x38, 0xF0, 0x41, 0x56, 0x06, 0x31, 0xB1, 0x14 }, + { 0x8B, 0x79, 0xEE, 0xCC, 0x93, 0xA0, 0xEE, 0x5D, + 0xFF, 0x30, 0xB4, 0xEA, 0x21, 0x63, 0x6D, 0xA4 } +}; + +static const unsigned char aes_test_cbc_dec[3][16] = +{ + { 0xFA, 0xCA, 0x37, 0xE0, 0xB0, 0xC8, 0x53, 0x73, + 0xDF, 0x70, 0x6E, 0x73, 0xF7, 0xC9, 0xAF, 0x86 }, + { 0x5D, 0xF6, 0x78, 0xDD, 0x17, 0xBA, 0x4E, 0x75, + 0xB6, 0x17, 0x68, 0xC6, 0xAD, 0xEF, 0x7C, 0x7B }, + { 0x48, 0x04, 0xE1, 0x81, 0x8F, 0xE6, 0x29, 0x75, + 0x19, 0xA3, 0xE8, 0x8C, 0x57, 0x31, 0x04, 0x13 } +}; + +static const unsigned char aes_test_cbc_enc[3][16] = +{ + { 0x8A, 0x05, 0xFC, 0x5E, 0x09, 0x5A, 0xF4, 0x84, + 0x8A, 0x08, 0xD3, 0x28, 0xD3, 0x68, 0x8E, 0x3D }, + { 0x7B, 0xD9, 0x66, 0xD5, 0x3A, 0xD8, 0xC1, 0xBB, + 0x85, 0xD2, 0xAD, 0xFA, 0xE8, 0x7B, 0xB1, 0x04 }, + { 0xFE, 0x3C, 0x53, 0x65, 0x3E, 0x2F, 0x45, 0xB5, + 0x6F, 0xCD, 0x88, 0xB2, 0xCC, 0x89, 0x8F, 0xF0 } +}; + +#if defined(POLARSSL_CIPHER_MODE_CFB) +/* + * AES-CFB128 test vectors from: + * + * http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf + */ +static const unsigned char aes_test_cfb128_key[3][32] = +{ + { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, + 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C }, + { 0x8E, 0x73, 0xB0, 0xF7, 0xDA, 0x0E, 0x64, 0x52, + 0xC8, 0x10, 0xF3, 0x2B, 0x80, 0x90, 0x79, 0xE5, + 0x62, 0xF8, 0xEA, 0xD2, 0x52, 0x2C, 0x6B, 0x7B }, + { 0x60, 0x3D, 0xEB, 0x10, 0x15, 0xCA, 0x71, 0xBE, + 0x2B, 0x73, 0xAE, 0xF0, 0x85, 0x7D, 0x77, 0x81, + 0x1F, 0x35, 0x2C, 0x07, 0x3B, 0x61, 0x08, 0xD7, + 0x2D, 0x98, 0x10, 0xA3, 0x09, 0x14, 0xDF, 0xF4 } +}; + +static const unsigned char aes_test_cfb128_iv[16] = +{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F +}; + +static const unsigned char aes_test_cfb128_pt[64] = +{ + 0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96, + 0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A, + 0xAE, 0x2D, 0x8A, 0x57, 0x1E, 0x03, 0xAC, 0x9C, + 0x9E, 0xB7, 0x6F, 0xAC, 0x45, 0xAF, 0x8E, 0x51, + 0x30, 0xC8, 0x1C, 0x46, 0xA3, 0x5C, 0xE4, 0x11, + 0xE5, 0xFB, 0xC1, 0x19, 0x1A, 0x0A, 0x52, 0xEF, + 0xF6, 0x9F, 0x24, 0x45, 0xDF, 0x4F, 0x9B, 0x17, + 0xAD, 0x2B, 0x41, 0x7B, 0xE6, 0x6C, 0x37, 0x10 +}; + +static const unsigned char aes_test_cfb128_ct[3][64] = +{ + { 0x3B, 0x3F, 0xD9, 0x2E, 0xB7, 0x2D, 0xAD, 0x20, + 0x33, 0x34, 0x49, 0xF8, 0xE8, 0x3C, 0xFB, 0x4A, + 0xC8, 0xA6, 0x45, 0x37, 0xA0, 0xB3, 0xA9, 0x3F, + 0xCD, 0xE3, 0xCD, 0xAD, 0x9F, 0x1C, 0xE5, 0x8B, + 0x26, 0x75, 0x1F, 0x67, 0xA3, 0xCB, 0xB1, 0x40, + 0xB1, 0x80, 0x8C, 0xF1, 0x87, 0xA4, 0xF4, 0xDF, + 0xC0, 0x4B, 0x05, 0x35, 0x7C, 0x5D, 0x1C, 0x0E, + 0xEA, 0xC4, 0xC6, 0x6F, 0x9F, 0xF7, 0xF2, 0xE6 }, + { 0xCD, 0xC8, 0x0D, 0x6F, 0xDD, 0xF1, 0x8C, 0xAB, + 0x34, 0xC2, 0x59, 0x09, 0xC9, 0x9A, 0x41, 0x74, + 0x67, 0xCE, 0x7F, 0x7F, 0x81, 0x17, 0x36, 0x21, + 0x96, 0x1A, 0x2B, 0x70, 0x17, 0x1D, 0x3D, 0x7A, + 0x2E, 0x1E, 0x8A, 0x1D, 0xD5, 0x9B, 0x88, 0xB1, + 0xC8, 0xE6, 0x0F, 0xED, 0x1E, 0xFA, 0xC4, 0xC9, + 0xC0, 0x5F, 0x9F, 0x9C, 0xA9, 0x83, 0x4F, 0xA0, + 0x42, 0xAE, 0x8F, 0xBA, 0x58, 0x4B, 0x09, 0xFF }, + { 0xDC, 0x7E, 0x84, 0xBF, 0xDA, 0x79, 0x16, 0x4B, + 0x7E, 0xCD, 0x84, 0x86, 0x98, 0x5D, 0x38, 0x60, + 0x39, 0xFF, 0xED, 0x14, 0x3B, 0x28, 0xB1, 0xC8, + 0x32, 0x11, 0x3C, 0x63, 0x31, 0xE5, 0x40, 0x7B, + 0xDF, 0x10, 0x13, 0x24, 0x15, 0xE5, 0x4B, 0x92, + 0xA1, 0x3E, 0xD0, 0xA8, 0x26, 0x7A, 0xE2, 0xF9, + 0x75, 0xA3, 0x85, 0x74, 0x1A, 0xB9, 0xCE, 0xF8, + 0x20, 0x31, 0x62, 0x3D, 0x55, 0xB1, 0xE4, 0x71 } +}; +#endif /* POLARSSL_CIPHER_MODE_CFB */ + +#if defined(POLARSSL_CIPHER_MODE_CTR) +/* + * AES-CTR test vectors from: + * + * http://www.faqs.org/rfcs/rfc3686.html + */ + +static const unsigned char aes_test_ctr_key[3][16] = +{ + { 0xAE, 0x68, 0x52, 0xF8, 0x12, 0x10, 0x67, 0xCC, + 0x4B, 0xF7, 0xA5, 0x76, 0x55, 0x77, 0xF3, 0x9E }, + { 0x7E, 0x24, 0x06, 0x78, 0x17, 0xFA, 0xE0, 0xD7, + 0x43, 0xD6, 0xCE, 0x1F, 0x32, 0x53, 0x91, 0x63 }, + { 0x76, 0x91, 0xBE, 0x03, 0x5E, 0x50, 0x20, 0xA8, + 0xAC, 0x6E, 0x61, 0x85, 0x29, 0xF9, 0xA0, 0xDC } +}; + +static const unsigned char aes_test_ctr_nonce_counter[3][16] = +{ + { 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }, + { 0x00, 0x6C, 0xB6, 0xDB, 0xC0, 0x54, 0x3B, 0x59, + 0xDA, 0x48, 0xD9, 0x0B, 0x00, 0x00, 0x00, 0x01 }, + { 0x00, 0xE0, 0x01, 0x7B, 0x27, 0x77, 0x7F, 0x3F, + 0x4A, 0x17, 0x86, 0xF0, 0x00, 0x00, 0x00, 0x01 } +}; + +static const unsigned char aes_test_ctr_pt[3][48] = +{ + { 0x53, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x62, + 0x6C, 0x6F, 0x63, 0x6B, 0x20, 0x6D, 0x73, 0x67 }, + + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F }, + + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x20, 0x21, 0x22, 0x23 } +}; + +static const unsigned char aes_test_ctr_ct[3][48] = +{ + { 0xE4, 0x09, 0x5D, 0x4F, 0xB7, 0xA7, 0xB3, 0x79, + 0x2D, 0x61, 0x75, 0xA3, 0x26, 0x13, 0x11, 0xB8 }, + { 0x51, 0x04, 0xA1, 0x06, 0x16, 0x8A, 0x72, 0xD9, + 0x79, 0x0D, 0x41, 0xEE, 0x8E, 0xDA, 0xD3, 0x88, + 0xEB, 0x2E, 0x1E, 0xFC, 0x46, 0xDA, 0x57, 0xC8, + 0xFC, 0xE6, 0x30, 0xDF, 0x91, 0x41, 0xBE, 0x28 }, + { 0xC1, 0xCF, 0x48, 0xA8, 0x9F, 0x2F, 0xFD, 0xD9, + 0xCF, 0x46, 0x52, 0xE9, 0xEF, 0xDB, 0x72, 0xD7, + 0x45, 0x40, 0xA4, 0x2B, 0xDE, 0x6D, 0x78, 0x36, + 0xD5, 0x9A, 0x5C, 0xEA, 0xAE, 0xF3, 0x10, 0x53, + 0x25, 0xB2, 0x07, 0x2F } +}; + +static const int aes_test_ctr_len[3] = + { 16, 32, 36 }; +#endif /* POLARSSL_CIPHER_MODE_CTR */ + +/* + * Checkup routine + */ +int aes_self_test( int verbose ) +{ + int i, j, u, v; + unsigned char key[32]; + unsigned char buf[64]; + unsigned char prv[16]; + unsigned char iv[16]; +#if defined(POLARSSL_CIPHER_MODE_CTR) || defined(POLARSSL_CIPHER_MODE_CFB) + size_t offset; +#endif +#if defined(POLARSSL_CIPHER_MODE_CTR) + int len; + unsigned char nonce_counter[16]; + unsigned char stream_block[16]; +#endif + aes_context ctx; + + memset( key, 0, 32 ); + + /* + * ECB mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + v = i & 1; + + if( verbose != 0 ) + printf( " AES-ECB-%3d (%s): ", 128 + u * 64, + ( v == AES_DECRYPT ) ? "dec" : "enc" ); + + memset( buf, 0, 16 ); + + if( v == AES_DECRYPT ) + { + aes_setkey_dec( &ctx, key, 128 + u * 64 ); + + for( j = 0; j < 10000; j++ ) + aes_crypt_ecb( &ctx, v, buf, buf ); + + if( memcmp( buf, aes_test_ecb_dec[u], 16 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + } + else + { + aes_setkey_enc( &ctx, key, 128 + u * 64 ); + + for( j = 0; j < 10000; j++ ) + aes_crypt_ecb( &ctx, v, buf, buf ); + + if( memcmp( buf, aes_test_ecb_enc[u], 16 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + } + + if( verbose != 0 ) + printf( "passed\n" ); + } + + if( verbose != 0 ) + printf( "\n" ); + + /* + * CBC mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + v = i & 1; + + if( verbose != 0 ) + printf( " AES-CBC-%3d (%s): ", 128 + u * 64, + ( v == AES_DECRYPT ) ? "dec" : "enc" ); + + memset( iv , 0, 16 ); + memset( prv, 0, 16 ); + memset( buf, 0, 16 ); + + if( v == AES_DECRYPT ) + { + aes_setkey_dec( &ctx, key, 128 + u * 64 ); + + for( j = 0; j < 10000; j++ ) + aes_crypt_cbc( &ctx, v, 16, iv, buf, buf ); + + if( memcmp( buf, aes_test_cbc_dec[u], 16 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + } + else + { + aes_setkey_enc( &ctx, key, 128 + u * 64 ); + + for( j = 0; j < 10000; j++ ) + { + unsigned char tmp[16]; + + aes_crypt_cbc( &ctx, v, 16, iv, buf, buf ); + + memcpy( tmp, prv, 16 ); + memcpy( prv, buf, 16 ); + memcpy( buf, tmp, 16 ); + } + + if( memcmp( prv, aes_test_cbc_enc[u], 16 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + } + + if( verbose != 0 ) + printf( "passed\n" ); + } + + if( verbose != 0 ) + printf( "\n" ); + +#if defined(POLARSSL_CIPHER_MODE_CFB) + /* + * CFB128 mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + v = i & 1; + + if( verbose != 0 ) + printf( " AES-CFB128-%3d (%s): ", 128 + u * 64, + ( v == AES_DECRYPT ) ? "dec" : "enc" ); + + memcpy( iv, aes_test_cfb128_iv, 16 ); + memcpy( key, aes_test_cfb128_key[u], 16 + u * 8 ); + + offset = 0; + aes_setkey_enc( &ctx, key, 128 + u * 64 ); + + if( v == AES_DECRYPT ) + { + memcpy( buf, aes_test_cfb128_ct[u], 64 ); + aes_crypt_cfb128( &ctx, v, 64, &offset, iv, buf, buf ); + + if( memcmp( buf, aes_test_cfb128_pt, 64 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + } + else + { + memcpy( buf, aes_test_cfb128_pt, 64 ); + aes_crypt_cfb128( &ctx, v, 64, &offset, iv, buf, buf ); + + if( memcmp( buf, aes_test_cfb128_ct[u], 64 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + } + + if( verbose != 0 ) + printf( "passed\n" ); + } + + if( verbose != 0 ) + printf( "\n" ); +#endif /* POLARSSL_CIPHER_MODE_CFB */ + +#if defined(POLARSSL_CIPHER_MODE_CTR) + /* + * CTR mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + v = i & 1; + + if( verbose != 0 ) + printf( " AES-CTR-128 (%s): ", + ( v == AES_DECRYPT ) ? "dec" : "enc" ); + + memcpy( nonce_counter, aes_test_ctr_nonce_counter[u], 16 ); + memcpy( key, aes_test_ctr_key[u], 16 ); + + offset = 0; + aes_setkey_enc( &ctx, key, 128 ); + + if( v == AES_DECRYPT ) + { + len = aes_test_ctr_len[u]; + memcpy( buf, aes_test_ctr_ct[u], len ); + + aes_crypt_ctr( &ctx, len, &offset, nonce_counter, stream_block, buf, buf ); + + if( memcmp( buf, aes_test_ctr_pt[u], len ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + } + else + { + len = aes_test_ctr_len[u]; + memcpy( buf, aes_test_ctr_pt[u], len ); + + aes_crypt_ctr( &ctx, len, &offset, nonce_counter, stream_block, buf, buf ); + + if( memcmp( buf, aes_test_ctr_ct[u], len ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + } + + if( verbose != 0 ) + printf( "passed\n" ); + } + + if( verbose != 0 ) + printf( "\n" ); +#endif /* POLARSSL_CIPHER_MODE_CTR */ + + return( 0 ); +} + +#endif + +#endif diff --git a/protocols/Tlen/src/crypto/bignum.c b/protocols/Tlen/src/crypto/bignum.c new file mode 100644 index 0000000000..eabfbfe6f9 --- /dev/null +++ b/protocols/Tlen/src/crypto/bignum.c @@ -0,0 +1,2097 @@ +/* + * Multi-precision integer library + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * 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. + */ +/* + * This MPI implementation is based on: + * + * http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf + * http://www.stillhq.com/extracted/gnupg-api/mpi/ + * http://math.libtomcrypt.com/files/tommath.pdf + */ + +#include "polarssl/config.h" + +#if defined(POLARSSL_BIGNUM_C) + +#include "polarssl/bignum.h" +#include "polarssl/bn_mul.h" + +#include + +#define ciL (sizeof(t_uint)) /* chars in limb */ +#define biL (ciL << 3) /* bits in limb */ +#define biH (ciL << 2) /* half limb size */ + +/* + * Convert between bits/chars and number of limbs + */ +#define BITS_TO_LIMBS(i) (((i) + biL - 1) / biL) +#define CHARS_TO_LIMBS(i) (((i) + ciL - 1) / ciL) + +/* + * Initialize one MPI + */ +void mpi_init( mpi *X ) +{ + if( X == NULL ) + return; + + X->s = 1; + X->n = 0; + X->p = NULL; +} + +/* + * Unallocate one MPI + */ +void mpi_free( mpi *X ) +{ + if( X == NULL ) + return; + + if( X->p != NULL ) + { + memset( X->p, 0, X->n * ciL ); + free( X->p ); + } + + X->s = 1; + X->n = 0; + X->p = NULL; +} + +/* + * Enlarge to the specified number of limbs + */ +int mpi_grow( mpi *X, size_t nblimbs ) +{ + t_uint *p; + + if( nblimbs > POLARSSL_MPI_MAX_LIMBS ) + return( 1 ); + + if( X->n < nblimbs ) + { + if( ( p = (t_uint *) malloc( nblimbs * ciL ) ) == NULL ) + return( 1 ); + + memset( p, 0, nblimbs * ciL ); + + if( X->p != NULL ) + { + memcpy( p, X->p, X->n * ciL ); + memset( X->p, 0, X->n * ciL ); + free( X->p ); + } + + X->n = nblimbs; + X->p = p; + } + + return( 0 ); +} + +/* + * Copy the contents of Y into X + */ +int mpi_copy( mpi *X, const mpi *Y ) +{ + int ret; + size_t i; + + if( X == Y ) + return( 0 ); + + for( i = Y->n - 1; i > 0; i-- ) + if( Y->p[i] != 0 ) + break; + i++; + + X->s = Y->s; + + MPI_CHK( mpi_grow( X, i ) ); + + memset( X->p, 0, X->n * ciL ); + memcpy( X->p, Y->p, i * ciL ); + +cleanup: + + return( ret ); +} + +/* + * Swap the contents of X and Y + */ +void mpi_swap( mpi *X, mpi *Y ) +{ + mpi T; + + memcpy( &T, X, sizeof( mpi ) ); + memcpy( X, Y, sizeof( mpi ) ); + memcpy( Y, &T, sizeof( mpi ) ); +} + +/* + * Set value from integer + */ +int mpi_lset( mpi *X, t_sint z ) +{ + int ret; + + MPI_CHK( mpi_grow( X, 1 ) ); + memset( X->p, 0, X->n * ciL ); + + X->p[0] = ( z < 0 ) ? -z : z; + X->s = ( z < 0 ) ? -1 : 1; + +cleanup: + + return( ret ); +} + +/* + * Get a specific bit + */ +int mpi_get_bit( mpi *X, size_t pos ) +{ + if( X->n * biL <= pos ) + return( 0 ); + + return ( X->p[pos / biL] >> ( pos % biL ) ) & 0x01; +} + +/* + * Set a bit to a specific value of 0 or 1 + */ +int mpi_set_bit( mpi *X, size_t pos, unsigned char val ) +{ + int ret = 0; + size_t off = pos / biL; + size_t idx = pos % biL; + + if( val != 0 && val != 1 ) + return POLARSSL_ERR_MPI_BAD_INPUT_DATA; + + if( X->n * biL <= pos ) + { + if( val == 0 ) + return ( 0 ); + + MPI_CHK( mpi_grow( X, off + 1 ) ); + } + + X->p[off] = ( X->p[off] & ~( 0x01 << idx ) ) | ( val << idx ); + +cleanup: + + return( ret ); +} + +/* + * Return the number of least significant bits + */ +size_t mpi_lsb( const mpi *X ) +{ + size_t i, j, count = 0; + + for( i = 0; i < X->n; i++ ) + for( j = 0; j < biL; j++, count++ ) + if( ( ( X->p[i] >> j ) & 1 ) != 0 ) + return( count ); + + return( 0 ); +} + +/* + * Return the number of most significant bits + */ +size_t mpi_msb( const mpi *X ) +{ + size_t i, j; + + for( i = X->n - 1; i > 0; i-- ) + if( X->p[i] != 0 ) + break; + + for( j = biL; j > 0; j-- ) + if( ( ( X->p[i] >> ( j - 1 ) ) & 1 ) != 0 ) + break; + + return( ( i * biL ) + j ); +} + +/* + * Return the total size in bytes + */ +size_t mpi_size( const mpi *X ) +{ + return( ( mpi_msb( X ) + 7 ) >> 3 ); +} + +/* + * Convert an ASCII character to digit value + */ +static int mpi_get_digit( t_uint *d, int radix, char c ) +{ + *d = 255; + + if( c >= 0x30 && c <= 0x39 ) *d = c - 0x30; + if( c >= 0x41 && c <= 0x46 ) *d = c - 0x37; + if( c >= 0x61 && c <= 0x66 ) *d = c - 0x57; + + if( *d >= (t_uint) radix ) + return( POLARSSL_ERR_MPI_INVALID_CHARACTER ); + + return( 0 ); +} + +/* + * Import from an ASCII string + */ +int mpi_read_string( mpi *X, int radix, const char *s ) +{ + int ret; + size_t i, j, slen, n; + t_uint d; + mpi T; + + if( radix < 2 || radix > 16 ) + return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); + + mpi_init( &T ); + + slen = strlen( s ); + + if( radix == 16 ) + { + n = BITS_TO_LIMBS( slen << 2 ); + + MPI_CHK( mpi_grow( X, n ) ); + MPI_CHK( mpi_lset( X, 0 ) ); + + for( i = slen, j = 0; i > 0; i--, j++ ) + { + if( i == 1 && s[i - 1] == '-' ) + { + X->s = -1; + break; + } + + MPI_CHK( mpi_get_digit( &d, radix, s[i - 1] ) ); + X->p[j / (2 * ciL)] |= d << ( (j % (2 * ciL)) << 2 ); + } + } + else + { + MPI_CHK( mpi_lset( X, 0 ) ); + + for( i = 0; i < slen; i++ ) + { + if( i == 0 && s[i] == '-' ) + { + X->s = -1; + continue; + } + + MPI_CHK( mpi_get_digit( &d, radix, s[i] ) ); + MPI_CHK( mpi_mul_int( &T, X, radix ) ); + + if( X->s == 1 ) + { + MPI_CHK( mpi_add_int( X, &T, d ) ); + } + else + { + MPI_CHK( mpi_sub_int( X, &T, d ) ); + } + } + } + +cleanup: + + mpi_free( &T ); + + return( ret ); +} + +/* + * Helper to write the digits high-order first + */ +static int mpi_write_hlp( mpi *X, int radix, char **p ) +{ + int ret; + t_uint r; + + if( radix < 2 || radix > 16 ) + return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); + + MPI_CHK( mpi_mod_int( &r, X, radix ) ); + MPI_CHK( mpi_div_int( X, NULL, X, radix ) ); + + if( mpi_cmp_int( X, 0 ) != 0 ) + MPI_CHK( mpi_write_hlp( X, radix, p ) ); + + if( r < 10 ) + *(*p)++ = (char)( r + 0x30 ); + else + *(*p)++ = (char)( r + 0x37 ); + +cleanup: + + return( ret ); +} + +/* + * Export into an ASCII string + */ +int mpi_write_string( const mpi *X, int radix, char *s, size_t *slen ) +{ + int ret = 0; + size_t n; + char *p; + mpi T; + + if( radix < 2 || radix > 16 ) + return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); + + n = mpi_msb( X ); + if( radix >= 4 ) n >>= 1; + if( radix >= 16 ) n >>= 1; + n += 3; + + if( *slen < n ) + { + *slen = n; + return( POLARSSL_ERR_MPI_BUFFER_TOO_SMALL ); + } + + p = s; + mpi_init( &T ); + + if( X->s == -1 ) + *p++ = '-'; + + if( radix == 16 ) + { + int c; + size_t i, j, k; + + for( i = X->n, k = 0; i > 0; i-- ) + { + for( j = ciL; j > 0; j-- ) + { + c = ( X->p[i - 1] >> ( ( j - 1 ) << 3) ) & 0xFF; + + if( c == 0 && k == 0 && ( i + j + 3 ) != 0 ) + continue; + + p += sprintf( p, "%02X", c ); + k = 1; + } + } + } + else + { + MPI_CHK( mpi_copy( &T, X ) ); + + if( T.s == -1 ) + T.s = 1; + + MPI_CHK( mpi_write_hlp( &T, radix, &p ) ); + } + + *p++ = '\0'; + *slen = p - s; + +cleanup: + + mpi_free( &T ); + + return( ret ); +} + +#if defined(POLARSSL_FS_IO) +/* + * Read X from an opened file + */ +int mpi_read_file( mpi *X, int radix, FILE *fin ) +{ + t_uint d; + size_t slen; + char *p; + char s[1024]; + + memset( s, 0, sizeof( s ) ); + if( fgets( s, sizeof( s ) - 1, fin ) == NULL ) + return( POLARSSL_ERR_MPI_FILE_IO_ERROR ); + + slen = strlen( s ); + if( s[slen - 1] == '\n' ) { slen--; s[slen] = '\0'; } + if( s[slen - 1] == '\r' ) { slen--; s[slen] = '\0'; } + + p = s + slen; + while( --p >= s ) + if( mpi_get_digit( &d, radix, *p ) != 0 ) + break; + + return( mpi_read_string( X, radix, p + 1 ) ); +} + +/* + * Write X into an opened file (or stdout if fout == NULL) + */ +int mpi_write_file( const char *p, const mpi *X, int radix, FILE *fout ) +{ + int ret; + size_t n, slen, plen; + char s[2048]; + + n = sizeof( s ); + memset( s, 0, n ); + n -= 2; + + MPI_CHK( mpi_write_string( X, radix, s, (size_t *) &n ) ); + + if( p == NULL ) p = ""; + + plen = strlen( p ); + slen = strlen( s ); + s[slen++] = '\r'; + s[slen++] = '\n'; + + if( fout != NULL ) + { + if( fwrite( p, 1, plen, fout ) != plen || + fwrite( s, 1, slen, fout ) != slen ) + return( POLARSSL_ERR_MPI_FILE_IO_ERROR ); + } + else + printf( "%s%s", p, s ); + +cleanup: + + return( ret ); +} +#endif /* POLARSSL_FS_IO */ + +/* + * Import X from unsigned binary data, big endian + */ +int mpi_read_binary( mpi *X, const unsigned char *buf, size_t buflen ) +{ + int ret; + size_t i, j, n; + + for( n = 0; n < buflen; n++ ) + if( buf[n] != 0 ) + break; + + MPI_CHK( mpi_grow( X, CHARS_TO_LIMBS( buflen - n ) ) ); + MPI_CHK( mpi_lset( X, 0 ) ); + + for( i = buflen, j = 0; i > n; i--, j++ ) + X->p[j / ciL] |= ((t_uint) buf[i - 1]) << ((j % ciL) << 3); + +cleanup: + + return( ret ); +} + +/* + * Export X into unsigned binary data, big endian + */ +int mpi_write_binary( const mpi *X, unsigned char *buf, size_t buflen ) +{ + size_t i, j, n; + + n = mpi_size( X ); + + if( buflen < n ) + return( POLARSSL_ERR_MPI_BUFFER_TOO_SMALL ); + + memset( buf, 0, buflen ); + + for( i = buflen - 1, j = 0; n > 0; i--, j++, n-- ) + buf[i] = (unsigned char)( X->p[j / ciL] >> ((j % ciL) << 3) ); + + return( 0 ); +} + +/* + * Left-shift: X <<= count + */ +int mpi_shift_l( mpi *X, size_t count ) +{ + int ret; + size_t i, v0, t1; + t_uint r0 = 0, r1; + + v0 = count / (biL ); + t1 = count & (biL - 1); + + i = mpi_msb( X ) + count; + + if( X->n * biL < i ) + MPI_CHK( mpi_grow( X, BITS_TO_LIMBS( i ) ) ); + + ret = 0; + + /* + * shift by count / limb_size + */ + if( v0 > 0 ) + { + for( i = X->n; i > v0; i-- ) + X->p[i - 1] = X->p[i - v0 - 1]; + + for( ; i > 0; i-- ) + X->p[i - 1] = 0; + } + + /* + * shift by count % limb_size + */ + if( t1 > 0 ) + { + for( i = v0; i < X->n; i++ ) + { + r1 = X->p[i] >> (biL - t1); + X->p[i] <<= t1; + X->p[i] |= r0; + r0 = r1; + } + } + +cleanup: + + return( ret ); +} + +/* + * Right-shift: X >>= count + */ +int mpi_shift_r( mpi *X, size_t count ) +{ + size_t i, v0, v1; + t_uint r0 = 0, r1; + + v0 = count / biL; + v1 = count & (biL - 1); + + /* + * shift by count / limb_size + */ + if( v0 > 0 ) + { + for( i = 0; i < X->n - v0; i++ ) + X->p[i] = X->p[i + v0]; + + for( ; i < X->n; i++ ) + X->p[i] = 0; + } + + /* + * shift by count % limb_size + */ + if( v1 > 0 ) + { + for( i = X->n; i > 0; i-- ) + { + r1 = X->p[i - 1] << (biL - v1); + X->p[i - 1] >>= v1; + X->p[i - 1] |= r0; + r0 = r1; + } + } + + return( 0 ); +} + +/* + * Compare unsigned values + */ +int mpi_cmp_abs( const mpi *X, const mpi *Y ) +{ + size_t i, j; + + for( i = X->n; i > 0; i-- ) + if( X->p[i - 1] != 0 ) + break; + + for( j = Y->n; j > 0; j-- ) + if( Y->p[j - 1] != 0 ) + break; + + if( i == 0 && j == 0 ) + return( 0 ); + + if( i > j ) return( 1 ); + if( j > i ) return( -1 ); + + for( ; i > 0; i-- ) + { + if( X->p[i - 1] > Y->p[i - 1] ) return( 1 ); + if( X->p[i - 1] < Y->p[i - 1] ) return( -1 ); + } + + return( 0 ); +} + +/* + * Compare signed values + */ +int mpi_cmp_mpi( const mpi *X, const mpi *Y ) +{ + size_t i, j; + + for( i = X->n; i > 0; i-- ) + if( X->p[i - 1] != 0 ) + break; + + for( j = Y->n; j > 0; j-- ) + if( Y->p[j - 1] != 0 ) + break; + + if( i == 0 && j == 0 ) + return( 0 ); + + if( i > j ) return( X->s ); + if( j > i ) return( -X->s ); + + if( X->s > 0 && Y->s < 0 ) return( 1 ); + if( Y->s > 0 && X->s < 0 ) return( -1 ); + + for( ; i > 0; i-- ) + { + if( X->p[i - 1] > Y->p[i - 1] ) return( X->s ); + if( X->p[i - 1] < Y->p[i - 1] ) return( -X->s ); + } + + return( 0 ); +} + +/* + * Compare signed values + */ +int mpi_cmp_int( const mpi *X, t_sint z ) +{ + mpi Y; + t_uint p[1]; + + *p = ( z < 0 ) ? -z : z; + Y.s = ( z < 0 ) ? -1 : 1; + Y.n = 1; + Y.p = p; + + return( mpi_cmp_mpi( X, &Y ) ); +} + +/* + * Unsigned addition: X = |A| + |B| (HAC 14.7) + */ +int mpi_add_abs( mpi *X, const mpi *A, const mpi *B ) +{ + int ret; + size_t i, j; + t_uint *o, *p, c; + + if( X == B ) + { + const mpi *T = A; A = X; B = T; + } + + if( X != A ) + MPI_CHK( mpi_copy( X, A ) ); + + /* + * X should always be positive as a result of unsigned additions. + */ + X->s = 1; + + for( j = B->n; j > 0; j-- ) + if( B->p[j - 1] != 0 ) + break; + + MPI_CHK( mpi_grow( X, j ) ); + + o = B->p; p = X->p; c = 0; + + for( i = 0; i < j; i++, o++, p++ ) + { + *p += c; c = ( *p < c ); + *p += *o; c += ( *p < *o ); + } + + while( c != 0 ) + { + if( i >= X->n ) + { + MPI_CHK( mpi_grow( X, i + 1 ) ); + p = X->p + i; + } + + *p += c; c = ( *p < c ); i++; + } + +cleanup: + + return( ret ); +} + +/* + * Helper for mpi substraction + */ +static void mpi_sub_hlp( size_t n, t_uint *s, t_uint *d ) +{ + size_t i; + t_uint c, z; + + for( i = c = 0; i < n; i++, s++, d++ ) + { + z = ( *d < c ); *d -= c; + c = ( *d < *s ) + z; *d -= *s; + } + + while( c != 0 ) + { + z = ( *d < c ); *d -= c; + c = z; i++; d++; + } +} + +/* + * Unsigned substraction: X = |A| - |B| (HAC 14.9) + */ +int mpi_sub_abs( mpi *X, const mpi *A, const mpi *B ) +{ + mpi TB; + int ret; + size_t n; + + if( mpi_cmp_abs( A, B ) < 0 ) + return( POLARSSL_ERR_MPI_NEGATIVE_VALUE ); + + mpi_init( &TB ); + + if( X == B ) + { + MPI_CHK( mpi_copy( &TB, B ) ); + B = &TB; + } + + if( X != A ) + MPI_CHK( mpi_copy( X, A ) ); + + /* + * X should always be positive as a result of unsigned substractions. + */ + X->s = 1; + + ret = 0; + + for( n = B->n; n > 0; n-- ) + if( B->p[n - 1] != 0 ) + break; + + mpi_sub_hlp( n, B->p, X->p ); + +cleanup: + + mpi_free( &TB ); + + return( ret ); +} + +/* + * Signed addition: X = A + B + */ +int mpi_add_mpi( mpi *X, const mpi *A, const mpi *B ) +{ + int ret, s = A->s; + + if( A->s * B->s < 0 ) + { + if( mpi_cmp_abs( A, B ) >= 0 ) + { + MPI_CHK( mpi_sub_abs( X, A, B ) ); + X->s = s; + } + else + { + MPI_CHK( mpi_sub_abs( X, B, A ) ); + X->s = -s; + } + } + else + { + MPI_CHK( mpi_add_abs( X, A, B ) ); + X->s = s; + } + +cleanup: + + return( ret ); +} + +/* + * Signed substraction: X = A - B + */ +int mpi_sub_mpi( mpi *X, const mpi *A, const mpi *B ) +{ + int ret, s = A->s; + + if( A->s * B->s > 0 ) + { + if( mpi_cmp_abs( A, B ) >= 0 ) + { + MPI_CHK( mpi_sub_abs( X, A, B ) ); + X->s = s; + } + else + { + MPI_CHK( mpi_sub_abs( X, B, A ) ); + X->s = -s; + } + } + else + { + MPI_CHK( mpi_add_abs( X, A, B ) ); + X->s = s; + } + +cleanup: + + return( ret ); +} + +/* + * Signed addition: X = A + b + */ +int mpi_add_int( mpi *X, const mpi *A, t_sint b ) +{ + mpi _B; + t_uint p[1]; + + p[0] = ( b < 0 ) ? -b : b; + _B.s = ( b < 0 ) ? -1 : 1; + _B.n = 1; + _B.p = p; + + return( mpi_add_mpi( X, A, &_B ) ); +} + +/* + * Signed substraction: X = A - b + */ +int mpi_sub_int( mpi *X, const mpi *A, t_sint b ) +{ + mpi _B; + t_uint p[1]; + + p[0] = ( b < 0 ) ? -b : b; + _B.s = ( b < 0 ) ? -1 : 1; + _B.n = 1; + _B.p = p; + + return( mpi_sub_mpi( X, A, &_B ) ); +} + +/* + * Helper for mpi multiplication + */ +static void mpi_mul_hlp( size_t i, t_uint *s, t_uint *d, t_uint b ) +{ + t_uint c = 0, t = 0; + +#if defined(MULADDC_HUIT) + for( ; i >= 8; i -= 8 ) + { + MULADDC_INIT + MULADDC_HUIT + MULADDC_STOP + } + + for( ; i > 0; i-- ) + { + MULADDC_INIT + MULADDC_CORE + MULADDC_STOP + } +#else + for( ; i >= 16; i -= 16 ) + { + MULADDC_INIT + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_STOP + } + + for( ; i >= 8; i -= 8 ) + { + MULADDC_INIT + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_STOP + } + + for( ; i > 0; i-- ) + { + MULADDC_INIT + MULADDC_CORE + MULADDC_STOP + } +#endif + + t++; + + do { + *d += c; c = ( *d < c ); d++; + } + while( c != 0 ); +} + +/* + * Baseline multiplication: X = A * B (HAC 14.12) + */ +int mpi_mul_mpi( mpi *X, const mpi *A, const mpi *B ) +{ + int ret; + size_t i, j; + mpi TA, TB; + + mpi_init( &TA ); mpi_init( &TB ); + + if( X == A ) { MPI_CHK( mpi_copy( &TA, A ) ); A = &TA; } + if( X == B ) { MPI_CHK( mpi_copy( &TB, B ) ); B = &TB; } + + for( i = A->n; i > 0; i-- ) + if( A->p[i - 1] != 0 ) + break; + + for( j = B->n; j > 0; j-- ) + if( B->p[j - 1] != 0 ) + break; + + MPI_CHK( mpi_grow( X, i + j ) ); + MPI_CHK( mpi_lset( X, 0 ) ); + + for( i++; j > 0; j-- ) + mpi_mul_hlp( i - 1, A->p, X->p + j - 1, B->p[j - 1] ); + + X->s = A->s * B->s; + +cleanup: + + mpi_free( &TB ); mpi_free( &TA ); + + return( ret ); +} + +/* + * Baseline multiplication: X = A * b + */ +int mpi_mul_int( mpi *X, const mpi *A, t_sint b ) +{ + mpi _B; + t_uint p[1]; + + _B.s = 1; + _B.n = 1; + _B.p = p; + p[0] = b; + + return( mpi_mul_mpi( X, A, &_B ) ); +} + +/* + * Division by mpi: A = Q * B + R (HAC 14.20) + */ +int mpi_div_mpi( mpi *Q, mpi *R, const mpi *A, const mpi *B ) +{ + int ret; + size_t i, n, t, k; + mpi X, Y, Z, T1, T2; + + if( mpi_cmp_int( B, 0 ) == 0 ) + return( POLARSSL_ERR_MPI_DIVISION_BY_ZERO ); + + mpi_init( &X ); mpi_init( &Y ); mpi_init( &Z ); + mpi_init( &T1 ); mpi_init( &T2 ); + + if( mpi_cmp_abs( A, B ) < 0 ) + { + if( Q != NULL ) MPI_CHK( mpi_lset( Q, 0 ) ); + if( R != NULL ) MPI_CHK( mpi_copy( R, A ) ); + return( 0 ); + } + + MPI_CHK( mpi_copy( &X, A ) ); + MPI_CHK( mpi_copy( &Y, B ) ); + X.s = Y.s = 1; + + MPI_CHK( mpi_grow( &Z, A->n + 2 ) ); + MPI_CHK( mpi_lset( &Z, 0 ) ); + MPI_CHK( mpi_grow( &T1, 2 ) ); + MPI_CHK( mpi_grow( &T2, 3 ) ); + + k = mpi_msb( &Y ) % biL; + if( k < biL - 1 ) + { + k = biL - 1 - k; + MPI_CHK( mpi_shift_l( &X, k ) ); + MPI_CHK( mpi_shift_l( &Y, k ) ); + } + else k = 0; + + n = X.n - 1; + t = Y.n - 1; + mpi_shift_l( &Y, biL * (n - t) ); + + while( mpi_cmp_mpi( &X, &Y ) >= 0 ) + { + Z.p[n - t]++; + mpi_sub_mpi( &X, &X, &Y ); + } + mpi_shift_r( &Y, biL * (n - t) ); + + for( i = n; i > t ; i-- ) + { + if( X.p[i] >= Y.p[t] ) + Z.p[i - t - 1] = ~0; + else + { +#if defined(POLARSSL_HAVE_LONGLONG) + t_dbl r; + + r = (t_dbl) X.p[i] << biL; + r |= (t_dbl) X.p[i - 1]; + r /= Y.p[t]; + if( r > ((t_dbl) 1 << biL) - 1) + r = ((t_dbl) 1 << biL) - 1; + + Z.p[i - t - 1] = (t_uint) r; +#else + /* + * __udiv_qrnnd_c, from gmp/longlong.h + */ + t_uint q0, q1, r0, r1; + t_uint d0, d1, d, m; + + d = Y.p[t]; + d0 = ( d << biH ) >> biH; + d1 = ( d >> biH ); + + q1 = X.p[i] / d1; + r1 = X.p[i] - d1 * q1; + r1 <<= biH; + r1 |= ( X.p[i - 1] >> biH ); + + m = q1 * d0; + if( r1 < m ) + { + q1--, r1 += d; + while( r1 >= d && r1 < m ) + q1--, r1 += d; + } + r1 -= m; + + q0 = r1 / d1; + r0 = r1 - d1 * q0; + r0 <<= biH; + r0 |= ( X.p[i - 1] << biH ) >> biH; + + m = q0 * d0; + if( r0 < m ) + { + q0--, r0 += d; + while( r0 >= d && r0 < m ) + q0--, r0 += d; + } + r0 -= m; + + Z.p[i - t - 1] = ( q1 << biH ) | q0; +#endif + } + + Z.p[i - t - 1]++; + do + { + Z.p[i - t - 1]--; + + MPI_CHK( mpi_lset( &T1, 0 ) ); + T1.p[0] = (t < 1) ? 0 : Y.p[t - 1]; + T1.p[1] = Y.p[t]; + MPI_CHK( mpi_mul_int( &T1, &T1, Z.p[i - t - 1] ) ); + + MPI_CHK( mpi_lset( &T2, 0 ) ); + T2.p[0] = (i < 2) ? 0 : X.p[i - 2]; + T2.p[1] = (i < 1) ? 0 : X.p[i - 1]; + T2.p[2] = X.p[i]; + } + while( mpi_cmp_mpi( &T1, &T2 ) > 0 ); + + MPI_CHK( mpi_mul_int( &T1, &Y, Z.p[i - t - 1] ) ); + MPI_CHK( mpi_shift_l( &T1, biL * (i - t - 1) ) ); + MPI_CHK( mpi_sub_mpi( &X, &X, &T1 ) ); + + if( mpi_cmp_int( &X, 0 ) < 0 ) + { + MPI_CHK( mpi_copy( &T1, &Y ) ); + MPI_CHK( mpi_shift_l( &T1, biL * (i - t - 1) ) ); + MPI_CHK( mpi_add_mpi( &X, &X, &T1 ) ); + Z.p[i - t - 1]--; + } + } + + if( Q != NULL ) + { + mpi_copy( Q, &Z ); + Q->s = A->s * B->s; + } + + if( R != NULL ) + { + mpi_shift_r( &X, k ); + mpi_copy( R, &X ); + + R->s = A->s; + if( mpi_cmp_int( R, 0 ) == 0 ) + R->s = 1; + } + +cleanup: + + mpi_free( &X ); mpi_free( &Y ); mpi_free( &Z ); + mpi_free( &T1 ); mpi_free( &T2 ); + + return( ret ); +} + +/* + * Division by int: A = Q * b + R + * + * Returns 0 if successful + * 1 if memory allocation failed + * POLARSSL_ERR_MPI_DIVISION_BY_ZERO if b == 0 + */ +int mpi_div_int( mpi *Q, mpi *R, const mpi *A, t_sint b ) +{ + mpi _B; + t_uint p[1]; + + p[0] = ( b < 0 ) ? -b : b; + _B.s = ( b < 0 ) ? -1 : 1; + _B.n = 1; + _B.p = p; + + return( mpi_div_mpi( Q, R, A, &_B ) ); +} + +/* + * Modulo: R = A mod B + */ +int mpi_mod_mpi( mpi *R, const mpi *A, const mpi *B ) +{ + int ret; + + if( mpi_cmp_int( B, 0 ) < 0 ) + return POLARSSL_ERR_MPI_NEGATIVE_VALUE; + + MPI_CHK( mpi_div_mpi( NULL, R, A, B ) ); + + while( mpi_cmp_int( R, 0 ) < 0 ) + MPI_CHK( mpi_add_mpi( R, R, B ) ); + + while( mpi_cmp_mpi( R, B ) >= 0 ) + MPI_CHK( mpi_sub_mpi( R, R, B ) ); + +cleanup: + + return( ret ); +} + +/* + * Modulo: r = A mod b + */ +int mpi_mod_int( t_uint *r, const mpi *A, t_sint b ) +{ + size_t i; + t_uint x, y, z; + + if( b == 0 ) + return( POLARSSL_ERR_MPI_DIVISION_BY_ZERO ); + + if( b < 0 ) + return POLARSSL_ERR_MPI_NEGATIVE_VALUE; + + /* + * handle trivial cases + */ + if( b == 1 ) + { + *r = 0; + return( 0 ); + } + + if( b == 2 ) + { + *r = A->p[0] & 1; + return( 0 ); + } + + /* + * general case + */ + for( i = A->n, y = 0; i > 0; i-- ) + { + x = A->p[i - 1]; + y = ( y << biH ) | ( x >> biH ); + z = y / b; + y -= z * b; + + x <<= biH; + y = ( y << biH ) | ( x >> biH ); + z = y / b; + y -= z * b; + } + + /* + * If A is negative, then the current y represents a negative value. + * Flipping it to the positive side. + */ + if( A->s < 0 && y != 0 ) + y = b - y; + + *r = y; + + return( 0 ); +} + +/* + * Fast Montgomery initialization (thanks to Tom St Denis) + */ +static void mpi_montg_init( t_uint *mm, const mpi *N ) +{ + t_uint x, m0 = N->p[0]; + + x = m0; + x += ( ( m0 + 2 ) & 4 ) << 1; + x *= ( 2 - ( m0 * x ) ); + + if( biL >= 16 ) x *= ( 2 - ( m0 * x ) ); + if( biL >= 32 ) x *= ( 2 - ( m0 * x ) ); + if( biL >= 64 ) x *= ( 2 - ( m0 * x ) ); + + *mm = ~x + 1; +} + +/* + * Montgomery multiplication: A = A * B * R^-1 mod N (HAC 14.36) + */ +static void mpi_montmul( mpi *A, const mpi *B, const mpi *N, t_uint mm, const mpi *T ) +{ + size_t i, n, m; + t_uint u0, u1, *d; + + memset( T->p, 0, T->n * ciL ); + + d = T->p; + n = N->n; + m = ( B->n < n ) ? B->n : n; + + for( i = 0; i < n; i++ ) + { + /* + * T = (T + u0*B + u1*N) / 2^biL + */ + u0 = A->p[i]; + u1 = ( d[0] + u0 * B->p[0] ) * mm; + + mpi_mul_hlp( m, B->p, d, u0 ); + mpi_mul_hlp( n, N->p, d, u1 ); + + *d++ = u0; d[n + 1] = 0; + } + + memcpy( A->p, d, (n + 1) * ciL ); + + if( mpi_cmp_abs( A, N ) >= 0 ) + mpi_sub_hlp( n, N->p, A->p ); + else + /* prevent timing attacks */ + mpi_sub_hlp( n, A->p, T->p ); +} + +/* + * Montgomery reduction: A = A * R^-1 mod N + */ +static void mpi_montred( mpi *A, const mpi *N, t_uint mm, const mpi *T ) +{ + t_uint z = 1; + mpi U; + + U.n = U.s = z; + U.p = &z; + + mpi_montmul( A, &U, N, mm, T ); +} + +/* + * Sliding-window exponentiation: X = A^E mod N (HAC 14.85) + */ +int mpi_exp_mod( mpi *X, const mpi *A, const mpi *E, const mpi *N, mpi *_RR ) +{ + int ret; + size_t wbits, wsize, one = 1; + size_t i, j, nblimbs; + size_t bufsize, nbits; + t_uint ei, mm, state; + mpi RR, T, W[64]; + + if( mpi_cmp_int( N, 0 ) < 0 || ( N->p[0] & 1 ) == 0 ) + return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); + + /* + * Init temps and window size + */ + mpi_montg_init( &mm, N ); + mpi_init( &RR ); mpi_init( &T ); + memset( W, 0, sizeof( W ) ); + + i = mpi_msb( E ); + + wsize = ( i > 671 ) ? 6 : ( i > 239 ) ? 5 : + ( i > 79 ) ? 4 : ( i > 23 ) ? 3 : 1; + + j = N->n + 1; + MPI_CHK( mpi_grow( X, j ) ); + MPI_CHK( mpi_grow( &W[1], j ) ); + MPI_CHK( mpi_grow( &T, j * 2 ) ); + + /* + * If 1st call, pre-compute R^2 mod N + */ + if( _RR == NULL || _RR->p == NULL ) + { + MPI_CHK( mpi_lset( &RR, 1 ) ); + MPI_CHK( mpi_shift_l( &RR, N->n * 2 * biL ) ); + MPI_CHK( mpi_mod_mpi( &RR, &RR, N ) ); + + if( _RR != NULL ) + memcpy( _RR, &RR, sizeof( mpi ) ); + } + else + memcpy( &RR, _RR, sizeof( mpi ) ); + + /* + * W[1] = A * R^2 * R^-1 mod N = A * R mod N + */ + if( mpi_cmp_mpi( A, N ) >= 0 ) + mpi_mod_mpi( &W[1], A, N ); + else mpi_copy( &W[1], A ); + + mpi_montmul( &W[1], &RR, N, mm, &T ); + + /* + * X = R^2 * R^-1 mod N = R mod N + */ + MPI_CHK( mpi_copy( X, &RR ) ); + mpi_montred( X, N, mm, &T ); + + if( wsize > 1 ) + { + /* + * W[1 << (wsize - 1)] = W[1] ^ (wsize - 1) + */ + j = one << (wsize - 1); + + MPI_CHK( mpi_grow( &W[j], N->n + 1 ) ); + MPI_CHK( mpi_copy( &W[j], &W[1] ) ); + + for( i = 0; i < wsize - 1; i++ ) + mpi_montmul( &W[j], &W[j], N, mm, &T ); + + /* + * W[i] = W[i - 1] * W[1] + */ + for( i = j + 1; i < (one << wsize); i++ ) + { + MPI_CHK( mpi_grow( &W[i], N->n + 1 ) ); + MPI_CHK( mpi_copy( &W[i], &W[i - 1] ) ); + + mpi_montmul( &W[i], &W[1], N, mm, &T ); + } + } + + nblimbs = E->n; + bufsize = 0; + nbits = 0; + wbits = 0; + state = 0; + + while( 1 ) + { + if( bufsize == 0 ) + { + if( nblimbs-- == 0 ) + break; + + bufsize = sizeof( t_uint ) << 3; + } + + bufsize--; + + ei = (E->p[nblimbs] >> bufsize) & 1; + + /* + * skip leading 0s + */ + if( ei == 0 && state == 0 ) + continue; + + if( ei == 0 && state == 1 ) + { + /* + * out of window, square X + */ + mpi_montmul( X, X, N, mm, &T ); + continue; + } + + /* + * add ei to current window + */ + state = 2; + + nbits++; + wbits |= (ei << (wsize - nbits)); + + if( nbits == wsize ) + { + /* + * X = X^wsize R^-1 mod N + */ + for( i = 0; i < wsize; i++ ) + mpi_montmul( X, X, N, mm, &T ); + + /* + * X = X * W[wbits] R^-1 mod N + */ + mpi_montmul( X, &W[wbits], N, mm, &T ); + + state--; + nbits = 0; + wbits = 0; + } + } + + /* + * process the remaining bits + */ + for( i = 0; i < nbits; i++ ) + { + mpi_montmul( X, X, N, mm, &T ); + + wbits <<= 1; + + if( (wbits & (one << wsize)) != 0 ) + mpi_montmul( X, &W[1], N, mm, &T ); + } + + /* + * X = A^E * R * R^-1 mod N = A^E mod N + */ + mpi_montred( X, N, mm, &T ); + +cleanup: + + for( i = (one << (wsize - 1)); i < (one << wsize); i++ ) + mpi_free( &W[i] ); + + mpi_free( &W[1] ); mpi_free( &T ); + + if( _RR == NULL ) + mpi_free( &RR ); + + return( ret ); +} + +/* + * Greatest common divisor: G = gcd(A, B) (HAC 14.54) + */ +int mpi_gcd( mpi *G, const mpi *A, const mpi *B ) +{ + int ret; + size_t lz, lzt; + mpi TG, TA, TB; + + mpi_init( &TG ); mpi_init( &TA ); mpi_init( &TB ); + + MPI_CHK( mpi_copy( &TA, A ) ); + MPI_CHK( mpi_copy( &TB, B ) ); + + lz = mpi_lsb( &TA ); + lzt = mpi_lsb( &TB ); + + if ( lzt < lz ) + lz = lzt; + + MPI_CHK( mpi_shift_r( &TA, lz ) ); + MPI_CHK( mpi_shift_r( &TB, lz ) ); + + TA.s = TB.s = 1; + + while( mpi_cmp_int( &TA, 0 ) != 0 ) + { + MPI_CHK( mpi_shift_r( &TA, mpi_lsb( &TA ) ) ); + MPI_CHK( mpi_shift_r( &TB, mpi_lsb( &TB ) ) ); + + if( mpi_cmp_mpi( &TA, &TB ) >= 0 ) + { + MPI_CHK( mpi_sub_abs( &TA, &TA, &TB ) ); + MPI_CHK( mpi_shift_r( &TA, 1 ) ); + } + else + { + MPI_CHK( mpi_sub_abs( &TB, &TB, &TA ) ); + MPI_CHK( mpi_shift_r( &TB, 1 ) ); + } + } + + MPI_CHK( mpi_shift_l( &TB, lz ) ); + MPI_CHK( mpi_copy( G, &TB ) ); + +cleanup: + + mpi_free( &TG ); mpi_free( &TA ); mpi_free( &TB ); + + return( ret ); +} + +int mpi_fill_random( mpi *X, size_t size, int (*f_rng)(void *), void *p_rng ) +{ + int ret; + size_t k; + unsigned char *p; + + MPI_CHK( mpi_grow( X, size ) ); + MPI_CHK( mpi_lset( X, 0 ) ); + + p = (unsigned char *) X->p; + for( k = 0; k < X->n * ciL; k++ ) + *p++ = (unsigned char) f_rng( p_rng ); + +cleanup: + return( ret ); +} + +#if defined(POLARSSL_GENPRIME) + +/* + * Modular inverse: X = A^-1 mod N (HAC 14.61 / 14.64) + */ +int mpi_inv_mod( mpi *X, const mpi *A, const mpi *N ) +{ + int ret; + mpi G, TA, TU, U1, U2, TB, TV, V1, V2; + + if( mpi_cmp_int( N, 0 ) <= 0 ) + return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); + + mpi_init( &TA ); mpi_init( &TU ); mpi_init( &U1 ); mpi_init( &U2 ); + mpi_init( &G ); mpi_init( &TB ); mpi_init( &TV ); + mpi_init( &V1 ); mpi_init( &V2 ); + + MPI_CHK( mpi_gcd( &G, A, N ) ); + + if( mpi_cmp_int( &G, 1 ) != 0 ) + { + ret = POLARSSL_ERR_MPI_NOT_ACCEPTABLE; + goto cleanup; + } + + MPI_CHK( mpi_mod_mpi( &TA, A, N ) ); + MPI_CHK( mpi_copy( &TU, &TA ) ); + MPI_CHK( mpi_copy( &TB, N ) ); + MPI_CHK( mpi_copy( &TV, N ) ); + + MPI_CHK( mpi_lset( &U1, 1 ) ); + MPI_CHK( mpi_lset( &U2, 0 ) ); + MPI_CHK( mpi_lset( &V1, 0 ) ); + MPI_CHK( mpi_lset( &V2, 1 ) ); + + do + { + while( ( TU.p[0] & 1 ) == 0 ) + { + MPI_CHK( mpi_shift_r( &TU, 1 ) ); + + if( ( U1.p[0] & 1 ) != 0 || ( U2.p[0] & 1 ) != 0 ) + { + MPI_CHK( mpi_add_mpi( &U1, &U1, &TB ) ); + MPI_CHK( mpi_sub_mpi( &U2, &U2, &TA ) ); + } + + MPI_CHK( mpi_shift_r( &U1, 1 ) ); + MPI_CHK( mpi_shift_r( &U2, 1 ) ); + } + + while( ( TV.p[0] & 1 ) == 0 ) + { + MPI_CHK( mpi_shift_r( &TV, 1 ) ); + + if( ( V1.p[0] & 1 ) != 0 || ( V2.p[0] & 1 ) != 0 ) + { + MPI_CHK( mpi_add_mpi( &V1, &V1, &TB ) ); + MPI_CHK( mpi_sub_mpi( &V2, &V2, &TA ) ); + } + + MPI_CHK( mpi_shift_r( &V1, 1 ) ); + MPI_CHK( mpi_shift_r( &V2, 1 ) ); + } + + if( mpi_cmp_mpi( &TU, &TV ) >= 0 ) + { + MPI_CHK( mpi_sub_mpi( &TU, &TU, &TV ) ); + MPI_CHK( mpi_sub_mpi( &U1, &U1, &V1 ) ); + MPI_CHK( mpi_sub_mpi( &U2, &U2, &V2 ) ); + } + else + { + MPI_CHK( mpi_sub_mpi( &TV, &TV, &TU ) ); + MPI_CHK( mpi_sub_mpi( &V1, &V1, &U1 ) ); + MPI_CHK( mpi_sub_mpi( &V2, &V2, &U2 ) ); + } + } + while( mpi_cmp_int( &TU, 0 ) != 0 ); + + while( mpi_cmp_int( &V1, 0 ) < 0 ) + MPI_CHK( mpi_add_mpi( &V1, &V1, N ) ); + + while( mpi_cmp_mpi( &V1, N ) >= 0 ) + MPI_CHK( mpi_sub_mpi( &V1, &V1, N ) ); + + MPI_CHK( mpi_copy( X, &V1 ) ); + +cleanup: + + mpi_free( &TA ); mpi_free( &TU ); mpi_free( &U1 ); mpi_free( &U2 ); + mpi_free( &G ); mpi_free( &TB ); mpi_free( &TV ); + mpi_free( &V1 ); mpi_free( &V2 ); + + return( ret ); +} + +static const int small_prime[] = +{ + 3, 5, 7, 11, 13, 17, 19, 23, + 29, 31, 37, 41, 43, 47, 53, 59, + 61, 67, 71, 73, 79, 83, 89, 97, + 101, 103, 107, 109, 113, 127, 131, 137, + 139, 149, 151, 157, 163, 167, 173, 179, + 181, 191, 193, 197, 199, 211, 223, 227, + 229, 233, 239, 241, 251, 257, 263, 269, + 271, 277, 281, 283, 293, 307, 311, 313, + 317, 331, 337, 347, 349, 353, 359, 367, + 373, 379, 383, 389, 397, 401, 409, 419, + 421, 431, 433, 439, 443, 449, 457, 461, + 463, 467, 479, 487, 491, 499, 503, 509, + 521, 523, 541, 547, 557, 563, 569, 571, + 577, 587, 593, 599, 601, 607, 613, 617, + 619, 631, 641, 643, 647, 653, 659, 661, + 673, 677, 683, 691, 701, 709, 719, 727, + 733, 739, 743, 751, 757, 761, 769, 773, + 787, 797, 809, 811, 821, 823, 827, 829, + 839, 853, 857, 859, 863, 877, 881, 883, + 887, 907, 911, 919, 929, 937, 941, 947, + 953, 967, 971, 977, 983, 991, 997, -103 +}; + +/* + * Miller-Rabin primality test (HAC 4.24) + */ +int mpi_is_prime( mpi *X, int (*f_rng)(void *), void *p_rng ) +{ + int ret, xs; + size_t i, j, n, s; + mpi W, R, T, A, RR; + + if( mpi_cmp_int( X, 0 ) == 0 || + mpi_cmp_int( X, 1 ) == 0 ) + return( POLARSSL_ERR_MPI_NOT_ACCEPTABLE ); + + if( mpi_cmp_int( X, 2 ) == 0 ) + return( 0 ); + + mpi_init( &W ); mpi_init( &R ); mpi_init( &T ); mpi_init( &A ); + mpi_init( &RR ); + + xs = X->s; X->s = 1; + + /* + * test trivial factors first + */ + if( ( X->p[0] & 1 ) == 0 ) + return( POLARSSL_ERR_MPI_NOT_ACCEPTABLE ); + + for( i = 0; small_prime[i] > 0; i++ ) + { + t_uint r; + + if( mpi_cmp_int( X, small_prime[i] ) <= 0 ) + return( 0 ); + + MPI_CHK( mpi_mod_int( &r, X, small_prime[i] ) ); + + if( r == 0 ) + return( POLARSSL_ERR_MPI_NOT_ACCEPTABLE ); + } + + /* + * W = |X| - 1 + * R = W >> lsb( W ) + */ + MPI_CHK( mpi_sub_int( &W, X, 1 ) ); + s = mpi_lsb( &W ); + MPI_CHK( mpi_copy( &R, &W ) ); + MPI_CHK( mpi_shift_r( &R, s ) ); + + i = mpi_msb( X ); + /* + * HAC, table 4.4 + */ + n = ( ( i >= 1300 ) ? 2 : ( i >= 850 ) ? 3 : + ( i >= 650 ) ? 4 : ( i >= 350 ) ? 8 : + ( i >= 250 ) ? 12 : ( i >= 150 ) ? 18 : 27 ); + + for( i = 0; i < n; i++ ) + { + /* + * pick a random A, 1 < A < |X| - 1 + */ + mpi_fill_random( &A, X->n, f_rng, p_rng ); + + if( mpi_cmp_mpi( &A, &W ) >= 0 ) + { + j = mpi_msb( &A ) - mpi_msb( &W ); + MPI_CHK( mpi_shift_r( &A, j + 1 ) ); + } + A.p[0] |= 3; + + /* + * A = A^R mod |X| + */ + MPI_CHK( mpi_exp_mod( &A, &A, &R, X, &RR ) ); + + if( mpi_cmp_mpi( &A, &W ) == 0 || + mpi_cmp_int( &A, 1 ) == 0 ) + continue; + + j = 1; + while( j < s && mpi_cmp_mpi( &A, &W ) != 0 ) + { + /* + * A = A * A mod |X| + */ + MPI_CHK( mpi_mul_mpi( &T, &A, &A ) ); + MPI_CHK( mpi_mod_mpi( &A, &T, X ) ); + + if( mpi_cmp_int( &A, 1 ) == 0 ) + break; + + j++; + } + + /* + * not prime if A != |X| - 1 or A == 1 + */ + if( mpi_cmp_mpi( &A, &W ) != 0 || + mpi_cmp_int( &A, 1 ) == 0 ) + { + ret = POLARSSL_ERR_MPI_NOT_ACCEPTABLE; + break; + } + } + +cleanup: + + X->s = xs; + + mpi_free( &W ); mpi_free( &R ); mpi_free( &T ); mpi_free( &A ); + mpi_free( &RR ); + + return( ret ); +} + +/* + * Prime number generation + */ +int mpi_gen_prime( mpi *X, size_t nbits, int dh_flag, + int (*f_rng)(void *), void *p_rng ) +{ + int ret; + size_t k, n; + mpi Y; + + if( nbits < 3 || nbits > 4096 ) + return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); + + mpi_init( &Y ); + + n = BITS_TO_LIMBS( nbits ); + + mpi_fill_random( X, n, f_rng, p_rng ); + + k = mpi_msb( X ); + if( k < nbits ) MPI_CHK( mpi_shift_l( X, nbits - k ) ); + if( k > nbits ) MPI_CHK( mpi_shift_r( X, k - nbits ) ); + + X->p[0] |= 3; + + if( dh_flag == 0 ) + { + while( ( ret = mpi_is_prime( X, f_rng, p_rng ) ) != 0 ) + { + if( ret != POLARSSL_ERR_MPI_NOT_ACCEPTABLE ) + goto cleanup; + + MPI_CHK( mpi_add_int( X, X, 2 ) ); + } + } + else + { + MPI_CHK( mpi_sub_int( &Y, X, 1 ) ); + MPI_CHK( mpi_shift_r( &Y, 1 ) ); + + while( 1 ) + { + if( ( ret = mpi_is_prime( X, f_rng, p_rng ) ) == 0 ) + { + if( ( ret = mpi_is_prime( &Y, f_rng, p_rng ) ) == 0 ) + break; + + if( ret != POLARSSL_ERR_MPI_NOT_ACCEPTABLE ) + goto cleanup; + } + + if( ret != POLARSSL_ERR_MPI_NOT_ACCEPTABLE ) + goto cleanup; + + MPI_CHK( mpi_add_int( &Y, X, 1 ) ); + MPI_CHK( mpi_add_int( X, X, 2 ) ); + MPI_CHK( mpi_shift_r( &Y, 1 ) ); + } + } + +cleanup: + + mpi_free( &Y ); + + return( ret ); +} + +#endif + +#if defined(POLARSSL_SELF_TEST) + +#define GCD_PAIR_COUNT 3 + +static const int gcd_pairs[GCD_PAIR_COUNT][3] = +{ + { 693, 609, 21 }, + { 1764, 868, 28 }, + { 768454923, 542167814, 1 } +}; + +/* + * Checkup routine + */ +int mpi_self_test( int verbose ) +{ + int ret, i; + mpi A, E, N, X, Y, U, V; + + mpi_init( &A ); mpi_init( &E ); mpi_init( &N ); mpi_init( &X ); + mpi_init( &Y ); mpi_init( &U ); mpi_init( &V ); + + MPI_CHK( mpi_read_string( &A, 16, + "EFE021C2645FD1DC586E69184AF4A31E" \ + "D5F53E93B5F123FA41680867BA110131" \ + "944FE7952E2517337780CB0DB80E61AA" \ + "E7C8DDC6C5C6AADEB34EB38A2F40D5E6" ) ); + + MPI_CHK( mpi_read_string( &E, 16, + "B2E7EFD37075B9F03FF989C7C5051C20" \ + "34D2A323810251127E7BF8625A4F49A5" \ + "F3E27F4DA8BD59C47D6DAABA4C8127BD" \ + "5B5C25763222FEFCCFC38B832366C29E" ) ); + + MPI_CHK( mpi_read_string( &N, 16, + "0066A198186C18C10B2F5ED9B522752A" \ + "9830B69916E535C8F047518A889A43A5" \ + "94B6BED27A168D31D4A52F88925AA8F5" ) ); + + MPI_CHK( mpi_mul_mpi( &X, &A, &N ) ); + + MPI_CHK( mpi_read_string( &U, 16, + "602AB7ECA597A3D6B56FF9829A5E8B85" \ + "9E857EA95A03512E2BAE7391688D264A" \ + "A5663B0341DB9CCFD2C4C5F421FEC814" \ + "8001B72E848A38CAE1C65F78E56ABDEF" \ + "E12D3C039B8A02D6BE593F0BBBDA56F1" \ + "ECF677152EF804370C1A305CAF3B5BF1" \ + "30879B56C61DE584A0F53A2447A51E" ) ); + + if( verbose != 0 ) + printf( " MPI test #1 (mul_mpi): " ); + + if( mpi_cmp_mpi( &X, &U ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); + + MPI_CHK( mpi_div_mpi( &X, &Y, &A, &N ) ); + + MPI_CHK( mpi_read_string( &U, 16, + "256567336059E52CAE22925474705F39A94" ) ); + + MPI_CHK( mpi_read_string( &V, 16, + "6613F26162223DF488E9CD48CC132C7A" \ + "0AC93C701B001B092E4E5B9F73BCD27B" \ + "9EE50D0657C77F374E903CDFA4C642" ) ); + + if( verbose != 0 ) + printf( " MPI test #2 (div_mpi): " ); + + if( mpi_cmp_mpi( &X, &U ) != 0 || + mpi_cmp_mpi( &Y, &V ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); + + MPI_CHK( mpi_exp_mod( &X, &A, &E, &N, NULL ) ); + + MPI_CHK( mpi_read_string( &U, 16, + "36E139AEA55215609D2816998ED020BB" \ + "BD96C37890F65171D948E9BC7CBAA4D9" \ + "325D24D6A3C12710F10A09FA08AB87" ) ); + + if( verbose != 0 ) + printf( " MPI test #3 (exp_mod): " ); + + if( mpi_cmp_mpi( &X, &U ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); + +#if defined(POLARSSL_GENPRIME) + MPI_CHK( mpi_inv_mod( &X, &A, &N ) ); + + MPI_CHK( mpi_read_string( &U, 16, + "003A0AAEDD7E784FC07D8F9EC6E3BFD5" \ + "C3DBA76456363A10869622EAC2DD84EC" \ + "C5B8A74DAC4D09E03B5E0BE779F2DF61" ) ); + + if( verbose != 0 ) + printf( " MPI test #4 (inv_mod): " ); + + if( mpi_cmp_mpi( &X, &U ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); +#endif + + if( verbose != 0 ) + printf( " MPI test #5 (simple gcd): " ); + + for ( i = 0; i < GCD_PAIR_COUNT; i++) + { + MPI_CHK( mpi_lset( &X, gcd_pairs[i][0] ) ); + MPI_CHK( mpi_lset( &Y, gcd_pairs[i][1] ) ); + + MPI_CHK( mpi_gcd( &A, &X, &Y ) ); + + if( mpi_cmp_int( &A, gcd_pairs[i][2] ) != 0 ) + { + if( verbose != 0 ) + printf( "failed at %d\n", i ); + + return( 1 ); + } + } + + if( verbose != 0 ) + printf( "passed\n" ); + +cleanup: + + if( ret != 0 && verbose != 0 ) + printf( "Unexpected error, return code = %08X\n", ret ); + + mpi_free( &A ); mpi_free( &E ); mpi_free( &N ); mpi_free( &X ); + mpi_free( &Y ); mpi_free( &U ); mpi_free( &V ); + + if( verbose != 0 ) + printf( "\n" ); + + return( ret ); +} + +#endif + +#endif diff --git a/protocols/Tlen/src/crypto/padlock.c b/protocols/Tlen/src/crypto/padlock.c new file mode 100644 index 0000000000..2e2e4775ff --- /dev/null +++ b/protocols/Tlen/src/crypto/padlock.c @@ -0,0 +1,162 @@ +/* + * VIA PadLock support functions + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * 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. + */ +/* + * This implementation is based on the VIA PadLock Programming Guide: + * + * http://www.via.com.tw/en/downloads/whitepapers/initiatives/padlock/ + * programming_guide.pdf + */ + +#include "polarssl/config.h" + +#if defined(POLARSSL_PADLOCK_C) + +#include "polarssl/padlock.h" + +#if defined(POLARSSL_HAVE_X86) + +/* + * PadLock detection routine + */ +int padlock_supports( int feature ) +{ + static int flags = -1; + int ebx, edx; + + if( flags == -1 ) + { + asm( "movl %%ebx, %0 \n" \ + "movl $0xC0000000, %%eax \n" \ + "cpuid \n" \ + "cmpl $0xC0000001, %%eax \n" \ + "movl $0, %%edx \n" \ + "jb unsupported \n" \ + "movl $0xC0000001, %%eax \n" \ + "cpuid \n" \ + "unsupported: \n" \ + "movl %%edx, %1 \n" \ + "movl %2, %%ebx \n" + : "=m" (ebx), "=m" (edx) + : "m" (ebx) + : "eax", "ecx", "edx" ); + + flags = edx; + } + + return( flags & feature ); +} + +/* + * PadLock AES-ECB block en(de)cryption + */ +int padlock_xcryptecb( aes_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ) +{ + int ebx; + unsigned long *rk; + unsigned long *blk; + unsigned long *ctrl; + unsigned char buf[256]; + + rk = ctx->rk; + blk = PADLOCK_ALIGN16( buf ); + memcpy( blk, input, 16 ); + + ctrl = blk + 4; + *ctrl = 0x80 | ctx->nr | ( ( ctx->nr + ( mode^1 ) - 10 ) << 9 ); + + asm( "pushfl; popfl \n" \ + "movl %%ebx, %0 \n" \ + "movl $1, %%ecx \n" \ + "movl %2, %%edx \n" \ + "movl %3, %%ebx \n" \ + "movl %4, %%esi \n" \ + "movl %4, %%edi \n" \ + ".byte 0xf3,0x0f,0xa7,0xc8\n" \ + "movl %1, %%ebx \n" + : "=m" (ebx) + : "m" (ebx), "m" (ctrl), "m" (rk), "m" (blk) + : "ecx", "edx", "esi", "edi" ); + + memcpy( output, blk, 16 ); + + return( 0 ); +} + +/* + * PadLock AES-CBC buffer en(de)cryption + */ +int padlock_xcryptcbc( aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + int ebx; + size_t count; + unsigned long *rk; + unsigned long *iw; + unsigned long *ctrl; + unsigned char buf[256]; + + if( ( (long) input & 15 ) != 0 || + ( (long) output & 15 ) != 0 ) + return( POLARSSL_ERR_PADLOCK_DATA_MISALIGNED ); + + rk = ctx->rk; + iw = PADLOCK_ALIGN16( buf ); + memcpy( iw, iv, 16 ); + + ctrl = iw + 4; + *ctrl = 0x80 | ctx->nr | ( ( ctx->nr + (mode^1) - 10 ) << 9 ); + + count = (length + 15) >> 4; + + asm( "pushfl; popfl \n" \ + "movl %%ebx, %0 \n" \ + "movl %2, %%ecx \n" \ + "movl %3, %%edx \n" \ + "movl %4, %%ebx \n" \ + "movl %5, %%esi \n" \ + "movl %6, %%edi \n" \ + "movl %7, %%eax \n" \ + ".byte 0xf3,0x0f,0xa7,0xd0\n" \ + "movl %1, %%ebx \n" + : "=m" (ebx) + : "m" (ebx), "m" (count), "m" (ctrl), + "m" (rk), "m" (input), "m" (output), "m" (iw) + : "eax", "ecx", "edx", "esi", "edi" ); + + memcpy( iv, iw, 16 ); + + return( 0 ); +} + +#endif + +#endif diff --git a/protocols/Tlen/src/crypto/polarssl/aes.h b/protocols/Tlen/src/crypto/polarssl/aes.h new file mode 100644 index 0000000000..efc13daf5b --- /dev/null +++ b/protocols/Tlen/src/crypto/polarssl/aes.h @@ -0,0 +1,167 @@ +/** + * \file aes.h + * + * \brief AES block cipher + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * 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. + */ +#ifndef POLARSSL_AES_H +#define POLARSSL_AES_H + +#include + +#define AES_ENCRYPT 1 +#define AES_DECRYPT 0 + +#define POLARSSL_ERR_AES_INVALID_KEY_LENGTH -0x0020 /**< Invalid key length. */ +#define POLARSSL_ERR_AES_INVALID_INPUT_LENGTH -0x0022 /**< Invalid data input length. */ + +/** + * \brief AES context structure + */ +typedef struct +{ + int nr; /*!< number of rounds */ + unsigned long *rk; /*!< AES round keys */ + unsigned long buf[68]; /*!< unaligned data */ +} +aes_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief AES key schedule (encryption) + * + * \param ctx AES context to be initialized + * \param key encryption key + * \param keysize must be 128, 192 or 256 + * + * \return 0 if successful, or POLARSSL_ERR_AES_INVALID_KEY_LENGTH + */ +int aes_setkey_enc( aes_context *ctx, const unsigned char *key, unsigned int keysize ); + +/** + * \brief AES key schedule (decryption) + * + * \param ctx AES context to be initialized + * \param key decryption key + * \param keysize must be 128, 192 or 256 + * + * \return 0 if successful, or POLARSSL_ERR_AES_INVALID_KEY_LENGTH + */ +int aes_setkey_dec( aes_context *ctx, const unsigned char *key, unsigned int keysize ); + +/** + * \brief AES-ECB block encryption/decryption + * + * \param ctx AES context + * \param mode AES_ENCRYPT or AES_DECRYPT + * \param input 16-byte input block + * \param output 16-byte output block + * + * \return 0 if successful + */ +int aes_crypt_ecb( aes_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ); + +/** + * \brief AES-CBC buffer encryption/decryption + * Length should be a multiple of the block + * size (16 bytes) + * + * \param ctx AES context + * \param mode AES_ENCRYPT or AES_DECRYPT + * \param length length of the input data + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if successful, or POLARSSL_ERR_AES_INVALID_INPUT_LENGTH + */ +int aes_crypt_cbc( aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); + +/** + * \brief AES-CFB128 buffer encryption/decryption. + * + * \param ctx AES context + * \param mode AES_ENCRYPT or AES_DECRYPT + * \param length length of the input data + * \param iv_off offset in IV (updated after use) + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if successful + */ +int aes_crypt_cfb128( aes_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); + +/* + * \brief AES-CTR buffer encryption/decryption + * + * Warning: You have to keep the maximum use of your counter in mind! + * + * \param length The length of the data + * \param nc_off The offset in the current stream_block (for resuming + * within current cipher stream). The offset pointer to + * should be 0 at the start of a stream. + * \param nonce_counter The 128-bit nonce and counter. + * \param stream_block The saved stream-block for resuming. Is overwritten + * by the function. + * \param input The input data stream + * \param output The output data stream + * + * \return 0 if successful + */ +int aes_crypt_ctr( aes_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[16], + unsigned char stream_block[16], + const unsigned char *input, + unsigned char *output ); +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int aes_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* aes.h */ diff --git a/protocols/Tlen/src/crypto/polarssl/bignum.h b/protocols/Tlen/src/crypto/polarssl/bignum.h new file mode 100644 index 0000000000..7938406708 --- /dev/null +++ b/protocols/Tlen/src/crypto/polarssl/bignum.h @@ -0,0 +1,587 @@ +/** + * \file bignum.h + * + * \brief Multi-precision integer library + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * 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. + */ +#ifndef POLARSSL_BIGNUM_H +#define POLARSSL_BIGNUM_H + +#include +#include + +#define POLARSSL_ERR_MPI_FILE_IO_ERROR -0x0002 /**< An error occurred while reading from or writing to a file. */ +#define POLARSSL_ERR_MPI_BAD_INPUT_DATA -0x0004 /**< Bad input parameters to function. */ +#define POLARSSL_ERR_MPI_INVALID_CHARACTER -0x0006 /**< There is an invalid character in the digit string. */ +#define POLARSSL_ERR_MPI_BUFFER_TOO_SMALL -0x0008 /**< The output buffer is too small to write too. */ +#define POLARSSL_ERR_MPI_NEGATIVE_VALUE -0x000A /**< The input arguments are negative or result in illegal output. */ +#define POLARSSL_ERR_MPI_DIVISION_BY_ZERO -0x000C /**< The input argument for division is zero, which is not allowed. */ +#define POLARSSL_ERR_MPI_NOT_ACCEPTABLE -0x000E /**< The input arguments are not acceptable. */ + +#define MPI_CHK(f) if( ( ret = f ) != 0 ) goto cleanup + +/* + * Maximum size MPIs are allowed to grow to in number of limbs. + */ +#define POLARSSL_MPI_MAX_LIMBS 10000 + +/* + * Define the base integer type, architecture-wise + */ +#if defined(POLARSSL_HAVE_INT8) +typedef signed char t_sint; +typedef unsigned char t_uint; +typedef unsigned short t_udbl; +#else +#if defined(POLARSSL_HAVE_INT16) +typedef signed short t_sint; +typedef unsigned short t_uint; +typedef unsigned long t_udbl; +#else + typedef signed long t_sint; + typedef unsigned long t_uint; + #if defined(_MSC_VER) && defined(_M_IX86) + typedef unsigned __int64 t_udbl; + #else + #if defined(__amd64__) || defined(__x86_64__) || \ + defined(__ppc64__) || defined(__powerpc64__) || \ + defined(__ia64__) || defined(__alpha__) + typedef unsigned int t_udbl __attribute__((mode(TI))); + #else + #if defined(POLARSSL_HAVE_LONGLONG) + typedef unsigned long long t_udbl; + #endif + #endif + #endif +#endif +#endif + +/** + * \brief MPI structure + */ +typedef struct +{ + int s; /*!< integer sign */ + size_t n; /*!< total # of limbs */ + t_uint *p; /*!< pointer to limbs */ +} +mpi; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Initialize one MPI + * + * \param X One MPI to initialize. + */ +void mpi_init( mpi *X ); + +/** + * \brief Unallocate one MPI + * + * \param X One MPI to unallocate. + */ +void mpi_free( mpi *X ); + +/** + * \brief Enlarge to the specified number of limbs + * + * \param X MPI to grow + * \param nblimbs The target number of limbs + * + * \return 0 if successful, + * 1 if memory allocation failed + */ +int mpi_grow( mpi *X, size_t nblimbs ); + +/** + * \brief Copy the contents of Y into X + * + * \param X Destination MPI + * \param Y Source MPI + * + * \return 0 if successful, + * 1 if memory allocation failed + */ +int mpi_copy( mpi *X, const mpi *Y ); + +/** + * \brief Swap the contents of X and Y + * + * \param X First MPI value + * \param Y Second MPI value + */ +void mpi_swap( mpi *X, mpi *Y ); + +/** + * \brief Set value from integer + * + * \param X MPI to set + * \param z Value to use + * + * \return 0 if successful, + * 1 if memory allocation failed + */ +int mpi_lset( mpi *X, t_sint z ); + +/* + * \brief Get a specific bit from X + * + * \param X MPI to use + * \param pos Zero-based index of the bit in X + * + * \return Either a 0 or a 1 + */ +int mpi_get_bit( mpi *X, size_t pos ); + +/* + * \brief Set a bit of X to a specific value of 0 or 1 + * + * \note Will grow X if necessary to set a bit to 1 in a not yet + * existing limb. Will not grow if bit should be set to 0 + * + * \param X MPI to use + * \param pos Zero-based index of the bit in X + * \param val The value to set the bit to (0 or 1) + * + * \return 0 if successful, + * 1 if memory allocation failed, + * POLARSSL_ERR_MPI_BAD_INPUT_DATA if val is not 0 or 1 + */ +int mpi_set_bit( mpi *X, size_t pos, unsigned char val ); + +/** + * \brief Return the number of least significant bits + * + * \param X MPI to use + */ +size_t mpi_lsb( const mpi *X ); + +/** + * \brief Return the number of most significant bits + * + * \param X MPI to use + */ +size_t mpi_msb( const mpi *X ); + +/** + * \brief Return the total size in bytes + * + * \param X MPI to use + */ +size_t mpi_size( const mpi *X ); + +/** + * \brief Import from an ASCII string + * + * \param X Destination MPI + * \param radix Input numeric base + * \param s Null-terminated string buffer + * + * \return 0 if successful, or an POLARSSL_ERR_MPI_XXX error code + */ +int mpi_read_string( mpi *X, int radix, const char *s ); + +/** + * \brief Export into an ASCII string + * + * \param X Source MPI + * \param radix Output numeric base + * \param s String buffer + * \param slen String buffer size + * + * \return 0 if successful, or an POLARSSL_ERR_MPI_XXX error code. + * *slen is always updated to reflect the amount + * of data that has (or would have) been written. + * + * \note Call this function with *slen = 0 to obtain the + * minimum required buffer size in *slen. + */ +int mpi_write_string( const mpi *X, int radix, char *s, size_t *slen ); + +/** + * \brief Read X from an opened file + * + * \param X Destination MPI + * \param radix Input numeric base + * \param fin Input file handle + * + * \return 0 if successful, or an POLARSSL_ERR_MPI_XXX error code + */ +int mpi_read_file( mpi *X, int radix, FILE *fin ); + +/** + * \brief Write X into an opened file, or stdout if fout is NULL + * + * \param p Prefix, can be NULL + * \param X Source MPI + * \param radix Output numeric base + * \param fout Output file handle (can be NULL) + * + * \return 0 if successful, or an POLARSSL_ERR_MPI_XXX error code + * + * \note Set fout == NULL to print X on the console. + */ +int mpi_write_file( const char *p, const mpi *X, int radix, FILE *fout ); + +/** + * \brief Import X from unsigned binary data, big endian + * + * \param X Destination MPI + * \param buf Input buffer + * \param buflen Input buffer size + * + * \return 0 if successful, + * 1 if memory allocation failed + */ +int mpi_read_binary( mpi *X, const unsigned char *buf, size_t buflen ); + +/** + * \brief Export X into unsigned binary data, big endian + * + * \param X Source MPI + * \param buf Output buffer + * \param buflen Output buffer size + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_BUFFER_TOO_SMALL if buf isn't large enough + */ +int mpi_write_binary( const mpi *X, unsigned char *buf, size_t buflen ); + +/** + * \brief Left-shift: X <<= count + * + * \param X MPI to shift + * \param count Amount to shift + * + * \return 0 if successful, + * 1 if memory allocation failed + */ +int mpi_shift_l( mpi *X, size_t count ); + +/** + * \brief Right-shift: X >>= count + * + * \param X MPI to shift + * \param count Amount to shift + * + * \return 0 if successful, + * 1 if memory allocation failed + */ +int mpi_shift_r( mpi *X, size_t count ); + +/** + * \brief Compare unsigned values + * + * \param X Left-hand MPI + * \param Y Right-hand MPI + * + * \return 1 if |X| is greater than |Y|, + * -1 if |X| is lesser than |Y| or + * 0 if |X| is equal to |Y| + */ +int mpi_cmp_abs( const mpi *X, const mpi *Y ); + +/** + * \brief Compare signed values + * + * \param X Left-hand MPI + * \param Y Right-hand MPI + * + * \return 1 if X is greater than Y, + * -1 if X is lesser than Y or + * 0 if X is equal to Y + */ +int mpi_cmp_mpi( const mpi *X, const mpi *Y ); + +/** + * \brief Compare signed values + * + * \param X Left-hand MPI + * \param z The integer value to compare to + * + * \return 1 if X is greater than z, + * -1 if X is lesser than z or + * 0 if X is equal to z + */ +int mpi_cmp_int( const mpi *X, t_sint z ); + +/** + * \brief Unsigned addition: X = |A| + |B| + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * 1 if memory allocation failed + */ +int mpi_add_abs( mpi *X, const mpi *A, const mpi *B ); + +/** + * \brief Unsigned substraction: X = |A| - |B| + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_NEGATIVE_VALUE if B is greater than A + */ +int mpi_sub_abs( mpi *X, const mpi *A, const mpi *B ); + +/** + * \brief Signed addition: X = A + B + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * 1 if memory allocation failed + */ +int mpi_add_mpi( mpi *X, const mpi *A, const mpi *B ); + +/** + * \brief Signed substraction: X = A - B + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * 1 if memory allocation failed + */ +int mpi_sub_mpi( mpi *X, const mpi *A, const mpi *B ); + +/** + * \brief Signed addition: X = A + b + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param b The integer value to add + * + * \return 0 if successful, + * 1 if memory allocation failed + */ +int mpi_add_int( mpi *X, const mpi *A, t_sint b ); + +/** + * \brief Signed substraction: X = A - b + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param b The integer value to subtract + * + * \return 0 if successful, + * 1 if memory allocation failed + */ +int mpi_sub_int( mpi *X, const mpi *A, t_sint b ); + +/** + * \brief Baseline multiplication: X = A * B + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * 1 if memory allocation failed + */ +int mpi_mul_mpi( mpi *X, const mpi *A, const mpi *B ); + +/** + * \brief Baseline multiplication: X = A * b + * Note: b is an unsigned integer type, thus + * Negative values of b are ignored. + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param b The integer value to multiply with + * + * \return 0 if successful, + * 1 if memory allocation failed + */ +int mpi_mul_int( mpi *X, const mpi *A, t_sint b ); + +/** + * \brief Division by mpi: A = Q * B + R + * + * \param Q Destination MPI for the quotient + * \param R Destination MPI for the rest value + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * 1 if memory allocation failed, + * POLARSSL_ERR_MPI_DIVISION_BY_ZERO if B == 0 + * + * \note Either Q or R can be NULL. + */ +int mpi_div_mpi( mpi *Q, mpi *R, const mpi *A, const mpi *B ); + +/** + * \brief Division by int: A = Q * b + R + * + * \param Q Destination MPI for the quotient + * \param R Destination MPI for the rest value + * \param A Left-hand MPI + * \param b Integer to divide by + * + * \return 0 if successful, + * 1 if memory allocation failed, + * POLARSSL_ERR_MPI_DIVISION_BY_ZERO if b == 0 + * + * \note Either Q or R can be NULL. + */ +int mpi_div_int( mpi *Q, mpi *R, const mpi *A, t_sint b ); + +/** + * \brief Modulo: R = A mod B + * + * \param R Destination MPI for the rest value + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * 1 if memory allocation failed, + * POLARSSL_ERR_MPI_DIVISION_BY_ZERO if B == 0, + * POLARSSL_ERR_MPI_NEGATIVE_VALUE if B < 0 + */ +int mpi_mod_mpi( mpi *R, const mpi *A, const mpi *B ); + +/** + * \brief Modulo: r = A mod b + * + * \param r Destination t_uint + * \param A Left-hand MPI + * \param b Integer to divide by + * + * \return 0 if successful, + * 1 if memory allocation failed, + * POLARSSL_ERR_MPI_DIVISION_BY_ZERO if b == 0, + * POLARSSL_ERR_MPI_NEGATIVE_VALUE if b < 0 + */ +int mpi_mod_int( t_uint *r, const mpi *A, t_sint b ); + +/** + * \brief Sliding-window exponentiation: X = A^E mod N + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param E Exponent MPI + * \param N Modular MPI + * \param _RR Speed-up MPI used for recalculations + * + * \return 0 if successful, + * 1 if memory allocation failed, + * POLARSSL_ERR_MPI_BAD_INPUT_DATA if N is negative or even + * + * \note _RR is used to avoid re-computing R*R mod N across + * multiple calls, which speeds up things a bit. It can + * be set to NULL if the extra performance is unneeded. + */ +int mpi_exp_mod( mpi *X, const mpi *A, const mpi *E, const mpi *N, mpi *_RR ); + +/** + * \brief Fill an MPI X with size bytes of random + * + * \param X Destination MPI + * \param size Size in bytes + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful, + * 1 if memory allocation failed + */ +int mpi_fill_random( mpi *X, size_t size, int (*f_rng)(void *), void *p_rng ); + +/** + * \brief Greatest common divisor: G = gcd(A, B) + * + * \param G Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * 1 if memory allocation failed + */ +int mpi_gcd( mpi *G, const mpi *A, const mpi *B ); + +/** + * \brief Modular inverse: X = A^-1 mod N + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param N Right-hand MPI + * + * \return 0 if successful, + * 1 if memory allocation failed, + * POLARSSL_ERR_MPI_BAD_INPUT_DATA if N is negative or nil + POLARSSL_ERR_MPI_NOT_ACCEPTABLE if A has no inverse mod N + */ +int mpi_inv_mod( mpi *X, const mpi *A, const mpi *N ); + +/** + * \brief Miller-Rabin primality test + * + * \param X MPI to check + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful (probably prime), + * 1 if memory allocation failed, + * POLARSSL_ERR_MPI_NOT_ACCEPTABLE if X is not prime + */ +int mpi_is_prime( mpi *X, int (*f_rng)(void *), void *p_rng ); + +/** + * \brief Prime number generation + * + * \param X Destination MPI + * \param nbits Required size of X in bits ( 3 <= nbits <= 4096 ) + * \param dh_flag If 1, then (X-1)/2 will be prime too + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful (probably prime), + * 1 if memory allocation failed, + * POLARSSL_ERR_MPI_BAD_INPUT_DATA if nbits is < 3 + */ +int mpi_gen_prime( mpi *X, size_t nbits, int dh_flag, + int (*f_rng)(void *), void *p_rng ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mpi_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* bignum.h */ diff --git a/protocols/Tlen/src/crypto/polarssl/bn_mul.h b/protocols/Tlen/src/crypto/polarssl/bn_mul.h new file mode 100644 index 0000000000..59a32857cb --- /dev/null +++ b/protocols/Tlen/src/crypto/polarssl/bn_mul.h @@ -0,0 +1,738 @@ +/** + * \file bn_mul.h + * + * \brief Multi-precision integer library + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * 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. + */ +/* + * Multiply source vector [s] with b, add result + * to destination vector [d] and set carry c. + * + * Currently supports: + * + * . IA-32 (386+) . AMD64 / EM64T + * . IA-32 (SSE2) . Motorola 68000 + * . PowerPC, 32-bit . MicroBlaze + * . PowerPC, 64-bit . TriCore + * . SPARC v8 . ARM v3+ + * . Alpha . MIPS32 + * . C, longlong . C, generic + */ +#ifndef POLARSSL_BN_MUL_H +#define POLARSSL_BN_MUL_H + +#include "polarssl/config.h" + +#if defined(POLARSSL_HAVE_ASM) + +#if defined(__GNUC__) +#if defined(__i386__) + +#define MULADDC_INIT \ + asm( " \ + movl %%ebx, %0; \ + movl %5, %%esi; \ + movl %6, %%edi; \ + movl %7, %%ecx; \ + movl %8, %%ebx; \ + " + +#define MULADDC_CORE \ + " \ + lodsl; \ + mull %%ebx; \ + addl %%ecx, %%eax; \ + adcl $0, %%edx; \ + addl (%%edi), %%eax; \ + adcl $0, %%edx; \ + movl %%edx, %%ecx; \ + stosl; \ + " + +#if defined(POLARSSL_HAVE_SSE2) + +#define MULADDC_HUIT \ + " \ + movd %%ecx, %%mm1; \ + movd %%ebx, %%mm0; \ + movd (%%edi), %%mm3; \ + paddq %%mm3, %%mm1; \ + movd (%%esi), %%mm2; \ + pmuludq %%mm0, %%mm2; \ + movd 4(%%esi), %%mm4; \ + pmuludq %%mm0, %%mm4; \ + movd 8(%%esi), %%mm6; \ + pmuludq %%mm0, %%mm6; \ + movd 12(%%esi), %%mm7; \ + pmuludq %%mm0, %%mm7; \ + paddq %%mm2, %%mm1; \ + movd 4(%%edi), %%mm3; \ + paddq %%mm4, %%mm3; \ + movd 8(%%edi), %%mm5; \ + paddq %%mm6, %%mm5; \ + movd 12(%%edi), %%mm4; \ + paddq %%mm4, %%mm7; \ + movd %%mm1, (%%edi); \ + movd 16(%%esi), %%mm2; \ + pmuludq %%mm0, %%mm2; \ + psrlq $32, %%mm1; \ + movd 20(%%esi), %%mm4; \ + pmuludq %%mm0, %%mm4; \ + paddq %%mm3, %%mm1; \ + movd 24(%%esi), %%mm6; \ + pmuludq %%mm0, %%mm6; \ + movd %%mm1, 4(%%edi); \ + psrlq $32, %%mm1; \ + movd 28(%%esi), %%mm3; \ + pmuludq %%mm0, %%mm3; \ + paddq %%mm5, %%mm1; \ + movd 16(%%edi), %%mm5; \ + paddq %%mm5, %%mm2; \ + movd %%mm1, 8(%%edi); \ + psrlq $32, %%mm1; \ + paddq %%mm7, %%mm1; \ + movd 20(%%edi), %%mm5; \ + paddq %%mm5, %%mm4; \ + movd %%mm1, 12(%%edi); \ + psrlq $32, %%mm1; \ + paddq %%mm2, %%mm1; \ + movd 24(%%edi), %%mm5; \ + paddq %%mm5, %%mm6; \ + movd %%mm1, 16(%%edi); \ + psrlq $32, %%mm1; \ + paddq %%mm4, %%mm1; \ + movd 28(%%edi), %%mm5; \ + paddq %%mm5, %%mm3; \ + movd %%mm1, 20(%%edi); \ + psrlq $32, %%mm1; \ + paddq %%mm6, %%mm1; \ + movd %%mm1, 24(%%edi); \ + psrlq $32, %%mm1; \ + paddq %%mm3, %%mm1; \ + movd %%mm1, 28(%%edi); \ + addl $32, %%edi; \ + addl $32, %%esi; \ + psrlq $32, %%mm1; \ + movd %%mm1, %%ecx; \ + " + +#define MULADDC_STOP \ + " \ + emms; \ + movl %4, %%ebx; \ + movl %%ecx, %1; \ + movl %%edi, %2; \ + movl %%esi, %3; \ + " \ + : "=m" (t), "=m" (c), "=m" (d), "=m" (s) \ + : "m" (t), "m" (s), "m" (d), "m" (c), "m" (b) \ + : "eax", "ecx", "edx", "esi", "edi" \ + ); + +#else + +#define MULADDC_STOP \ + " \ + movl %4, %%ebx; \ + movl %%ecx, %1; \ + movl %%edi, %2; \ + movl %%esi, %3; \ + " \ + : "=m" (t), "=m" (c), "=m" (d), "=m" (s) \ + : "m" (t), "m" (s), "m" (d), "m" (c), "m" (b) \ + : "eax", "ecx", "edx", "esi", "edi" \ + ); +#endif /* SSE2 */ +#endif /* i386 */ + +#if defined(__amd64__) || defined (__x86_64__) + +#define MULADDC_INIT \ + asm( "movq %0, %%rsi " :: "m" (s)); \ + asm( "movq %0, %%rdi " :: "m" (d)); \ + asm( "movq %0, %%rcx " :: "m" (c)); \ + asm( "movq %0, %%rbx " :: "m" (b)); \ + asm( "xorq %r8, %r8 " ); + +#define MULADDC_CORE \ + asm( "movq (%rsi),%rax " ); \ + asm( "mulq %rbx " ); \ + asm( "addq $8, %rsi " ); \ + asm( "addq %rcx, %rax " ); \ + asm( "movq %r8, %rcx " ); \ + asm( "adcq $0, %rdx " ); \ + asm( "nop " ); \ + asm( "addq %rax, (%rdi) " ); \ + asm( "adcq %rdx, %rcx " ); \ + asm( "addq $8, %rdi " ); + +#define MULADDC_STOP \ + asm( "movq %%rcx, %0 " : "=m" (c)); \ + asm( "movq %%rdi, %0 " : "=m" (d)); \ + asm( "movq %%rsi, %0 " : "=m" (s) :: \ + "rax", "rcx", "rdx", "rbx", "rsi", "rdi", "r8" ); + +#endif /* AMD64 */ + +#if defined(__mc68020__) || defined(__mcpu32__) + +#define MULADDC_INIT \ + asm( "movl %0, %%a2 " :: "m" (s)); \ + asm( "movl %0, %%a3 " :: "m" (d)); \ + asm( "movl %0, %%d3 " :: "m" (c)); \ + asm( "movl %0, %%d2 " :: "m" (b)); \ + asm( "moveq #0, %d0 " ); + +#define MULADDC_CORE \ + asm( "movel %a2@+, %d1 " ); \ + asm( "mulul %d2, %d4:%d1 " ); \ + asm( "addl %d3, %d1 " ); \ + asm( "addxl %d0, %d4 " ); \ + asm( "moveq #0, %d3 " ); \ + asm( "addl %d1, %a3@+ " ); \ + asm( "addxl %d4, %d3 " ); + +#define MULADDC_STOP \ + asm( "movl %%d3, %0 " : "=m" (c)); \ + asm( "movl %%a3, %0 " : "=m" (d)); \ + asm( "movl %%a2, %0 " : "=m" (s) :: \ + "d0", "d1", "d2", "d3", "d4", "a2", "a3" ); + +#define MULADDC_HUIT \ + asm( "movel %a2@+, %d1 " ); \ + asm( "mulul %d2, %d4:%d1 " ); \ + asm( "addxl %d3, %d1 " ); \ + asm( "addxl %d0, %d4 " ); \ + asm( "addl %d1, %a3@+ " ); \ + asm( "movel %a2@+, %d1 " ); \ + asm( "mulul %d2, %d3:%d1 " ); \ + asm( "addxl %d4, %d1 " ); \ + asm( "addxl %d0, %d3 " ); \ + asm( "addl %d1, %a3@+ " ); \ + asm( "movel %a2@+, %d1 " ); \ + asm( "mulul %d2, %d4:%d1 " ); \ + asm( "addxl %d3, %d1 " ); \ + asm( "addxl %d0, %d4 " ); \ + asm( "addl %d1, %a3@+ " ); \ + asm( "movel %a2@+, %d1 " ); \ + asm( "mulul %d2, %d3:%d1 " ); \ + asm( "addxl %d4, %d1 " ); \ + asm( "addxl %d0, %d3 " ); \ + asm( "addl %d1, %a3@+ " ); \ + asm( "movel %a2@+, %d1 " ); \ + asm( "mulul %d2, %d4:%d1 " ); \ + asm( "addxl %d3, %d1 " ); \ + asm( "addxl %d0, %d4 " ); \ + asm( "addl %d1, %a3@+ " ); \ + asm( "movel %a2@+, %d1 " ); \ + asm( "mulul %d2, %d3:%d1 " ); \ + asm( "addxl %d4, %d1 " ); \ + asm( "addxl %d0, %d3 " ); \ + asm( "addl %d1, %a3@+ " ); \ + asm( "movel %a2@+, %d1 " ); \ + asm( "mulul %d2, %d4:%d1 " ); \ + asm( "addxl %d3, %d1 " ); \ + asm( "addxl %d0, %d4 " ); \ + asm( "addl %d1, %a3@+ " ); \ + asm( "movel %a2@+, %d1 " ); \ + asm( "mulul %d2, %d3:%d1 " ); \ + asm( "addxl %d4, %d1 " ); \ + asm( "addxl %d0, %d3 " ); \ + asm( "addl %d1, %a3@+ " ); \ + asm( "addxl %d0, %d3 " ); + +#endif /* MC68000 */ + +#if defined(__powerpc__) || defined(__ppc__) +#if defined(__powerpc64__) || defined(__ppc64__) + +#if defined(__MACH__) && defined(__APPLE__) + +#define MULADDC_INIT \ + asm( "ld r3, %0 " :: "m" (s)); \ + asm( "ld r4, %0 " :: "m" (d)); \ + asm( "ld r5, %0 " :: "m" (c)); \ + asm( "ld r6, %0 " :: "m" (b)); \ + asm( "addi r3, r3, -8 " ); \ + asm( "addi r4, r4, -8 " ); \ + asm( "addic r5, r5, 0 " ); + +#define MULADDC_CORE \ + asm( "ldu r7, 8(r3) " ); \ + asm( "mulld r8, r7, r6 " ); \ + asm( "mulhdu r9, r7, r6 " ); \ + asm( "adde r8, r8, r5 " ); \ + asm( "ld r7, 8(r4) " ); \ + asm( "addze r5, r9 " ); \ + asm( "addc r8, r8, r7 " ); \ + asm( "stdu r8, 8(r4) " ); + +#define MULADDC_STOP \ + asm( "addze r5, r5 " ); \ + asm( "addi r4, r4, 8 " ); \ + asm( "addi r3, r3, 8 " ); \ + asm( "std r5, %0 " : "=m" (c)); \ + asm( "std r4, %0 " : "=m" (d)); \ + asm( "std r3, %0 " : "=m" (s) :: \ + "r3", "r4", "r5", "r6", "r7", "r8", "r9" ); + +#else + +#define MULADDC_INIT \ + asm( "ld %%r3, %0 " :: "m" (s)); \ + asm( "ld %%r4, %0 " :: "m" (d)); \ + asm( "ld %%r5, %0 " :: "m" (c)); \ + asm( "ld %%r6, %0 " :: "m" (b)); \ + asm( "addi %r3, %r3, -8 " ); \ + asm( "addi %r4, %r4, -8 " ); \ + asm( "addic %r5, %r5, 0 " ); + +#define MULADDC_CORE \ + asm( "ldu %r7, 8(%r3) " ); \ + asm( "mulld %r8, %r7, %r6 " ); \ + asm( "mulhdu %r9, %r7, %r6 " ); \ + asm( "adde %r8, %r8, %r5 " ); \ + asm( "ld %r7, 8(%r4) " ); \ + asm( "addze %r5, %r9 " ); \ + asm( "addc %r8, %r8, %r7 " ); \ + asm( "stdu %r8, 8(%r4) " ); + +#define MULADDC_STOP \ + asm( "addze %r5, %r5 " ); \ + asm( "addi %r4, %r4, 8 " ); \ + asm( "addi %r3, %r3, 8 " ); \ + asm( "std %%r5, %0 " : "=m" (c)); \ + asm( "std %%r4, %0 " : "=m" (d)); \ + asm( "std %%r3, %0 " : "=m" (s) :: \ + "r3", "r4", "r5", "r6", "r7", "r8", "r9" ); + +#endif + +#else /* PPC32 */ + +#if defined(__MACH__) && defined(__APPLE__) + +#define MULADDC_INIT \ + asm( "lwz r3, %0 " :: "m" (s)); \ + asm( "lwz r4, %0 " :: "m" (d)); \ + asm( "lwz r5, %0 " :: "m" (c)); \ + asm( "lwz r6, %0 " :: "m" (b)); \ + asm( "addi r3, r3, -4 " ); \ + asm( "addi r4, r4, -4 " ); \ + asm( "addic r5, r5, 0 " ); + +#define MULADDC_CORE \ + asm( "lwzu r7, 4(r3) " ); \ + asm( "mullw r8, r7, r6 " ); \ + asm( "mulhwu r9, r7, r6 " ); \ + asm( "adde r8, r8, r5 " ); \ + asm( "lwz r7, 4(r4) " ); \ + asm( "addze r5, r9 " ); \ + asm( "addc r8, r8, r7 " ); \ + asm( "stwu r8, 4(r4) " ); + +#define MULADDC_STOP \ + asm( "addze r5, r5 " ); \ + asm( "addi r4, r4, 4 " ); \ + asm( "addi r3, r3, 4 " ); \ + asm( "stw r5, %0 " : "=m" (c)); \ + asm( "stw r4, %0 " : "=m" (d)); \ + asm( "stw r3, %0 " : "=m" (s) :: \ + "r3", "r4", "r5", "r6", "r7", "r8", "r9" ); + +#else + +#define MULADDC_INIT \ + asm( "lwz %%r3, %0 " :: "m" (s)); \ + asm( "lwz %%r4, %0 " :: "m" (d)); \ + asm( "lwz %%r5, %0 " :: "m" (c)); \ + asm( "lwz %%r6, %0 " :: "m" (b)); \ + asm( "addi %r3, %r3, -4 " ); \ + asm( "addi %r4, %r4, -4 " ); \ + asm( "addic %r5, %r5, 0 " ); + +#define MULADDC_CORE \ + asm( "lwzu %r7, 4(%r3) " ); \ + asm( "mullw %r8, %r7, %r6 " ); \ + asm( "mulhwu %r9, %r7, %r6 " ); \ + asm( "adde %r8, %r8, %r5 " ); \ + asm( "lwz %r7, 4(%r4) " ); \ + asm( "addze %r5, %r9 " ); \ + asm( "addc %r8, %r8, %r7 " ); \ + asm( "stwu %r8, 4(%r4) " ); + +#define MULADDC_STOP \ + asm( "addze %r5, %r5 " ); \ + asm( "addi %r4, %r4, 4 " ); \ + asm( "addi %r3, %r3, 4 " ); \ + asm( "stw %%r5, %0 " : "=m" (c)); \ + asm( "stw %%r4, %0 " : "=m" (d)); \ + asm( "stw %%r3, %0 " : "=m" (s) :: \ + "r3", "r4", "r5", "r6", "r7", "r8", "r9" ); + +#endif + +#endif /* PPC32 */ +#endif /* PPC64 */ + +#if defined(__sparc__) + +#define MULADDC_INIT \ + asm( "ld %0, %%o0 " :: "m" (s)); \ + asm( "ld %0, %%o1 " :: "m" (d)); \ + asm( "ld %0, %%o2 " :: "m" (c)); \ + asm( "ld %0, %%o3 " :: "m" (b)); + +#define MULADDC_CORE \ + asm( "ld [%o0], %o4 " ); \ + asm( "inc 4, %o0 " ); \ + asm( "ld [%o1], %o5 " ); \ + asm( "umul %o3, %o4, %o4 " ); \ + asm( "addcc %o4, %o2, %o4 " ); \ + asm( "rd %y, %g1 " ); \ + asm( "addx %g1, 0, %g1 " ); \ + asm( "addcc %o4, %o5, %o4 " ); \ + asm( "st %o4, [%o1] " ); \ + asm( "addx %g1, 0, %o2 " ); \ + asm( "inc 4, %o1 " ); + +#define MULADDC_STOP \ + asm( "st %%o2, %0 " : "=m" (c)); \ + asm( "st %%o1, %0 " : "=m" (d)); \ + asm( "st %%o0, %0 " : "=m" (s) :: \ + "g1", "o0", "o1", "o2", "o3", "o4", "o5" ); + +#endif /* SPARCv8 */ + +#if defined(__microblaze__) || defined(microblaze) + +#define MULADDC_INIT \ + asm( "lwi r3, %0 " :: "m" (s)); \ + asm( "lwi r4, %0 " :: "m" (d)); \ + asm( "lwi r5, %0 " :: "m" (c)); \ + asm( "lwi r6, %0 " :: "m" (b)); \ + asm( "andi r7, r6, 0xffff" ); \ + asm( "bsrli r6, r6, 16 " ); + +#define MULADDC_CORE \ + asm( "lhui r8, r3, 0 " ); \ + asm( "addi r3, r3, 2 " ); \ + asm( "lhui r9, r3, 0 " ); \ + asm( "addi r3, r3, 2 " ); \ + asm( "mul r10, r9, r6 " ); \ + asm( "mul r11, r8, r7 " ); \ + asm( "mul r12, r9, r7 " ); \ + asm( "mul r13, r8, r6 " ); \ + asm( "bsrli r8, r10, 16 " ); \ + asm( "bsrli r9, r11, 16 " ); \ + asm( "add r13, r13, r8 " ); \ + asm( "add r13, r13, r9 " ); \ + asm( "bslli r10, r10, 16 " ); \ + asm( "bslli r11, r11, 16 " ); \ + asm( "add r12, r12, r10 " ); \ + asm( "addc r13, r13, r0 " ); \ + asm( "add r12, r12, r11 " ); \ + asm( "addc r13, r13, r0 " ); \ + asm( "lwi r10, r4, 0 " ); \ + asm( "add r12, r12, r10 " ); \ + asm( "addc r13, r13, r0 " ); \ + asm( "add r12, r12, r5 " ); \ + asm( "addc r5, r13, r0 " ); \ + asm( "swi r12, r4, 0 " ); \ + asm( "addi r4, r4, 4 " ); + +#define MULADDC_STOP \ + asm( "swi r5, %0 " : "=m" (c)); \ + asm( "swi r4, %0 " : "=m" (d)); \ + asm( "swi r3, %0 " : "=m" (s) :: \ + "r3", "r4" , "r5" , "r6" , "r7" , "r8" , \ + "r9", "r10", "r11", "r12", "r13" ); + +#endif /* MicroBlaze */ + +#if defined(__tricore__) + +#define MULADDC_INIT \ + asm( "ld.a %%a2, %0 " :: "m" (s)); \ + asm( "ld.a %%a3, %0 " :: "m" (d)); \ + asm( "ld.w %%d4, %0 " :: "m" (c)); \ + asm( "ld.w %%d1, %0 " :: "m" (b)); \ + asm( "xor %d5, %d5 " ); + +#define MULADDC_CORE \ + asm( "ld.w %d0, [%a2+] " ); \ + asm( "madd.u %e2, %e4, %d0, %d1 " ); \ + asm( "ld.w %d0, [%a3] " ); \ + asm( "addx %d2, %d2, %d0 " ); \ + asm( "addc %d3, %d3, 0 " ); \ + asm( "mov %d4, %d3 " ); \ + asm( "st.w [%a3+], %d2 " ); + +#define MULADDC_STOP \ + asm( "st.w %0, %%d4 " : "=m" (c)); \ + asm( "st.a %0, %%a3 " : "=m" (d)); \ + asm( "st.a %0, %%a2 " : "=m" (s) :: \ + "d0", "d1", "e2", "d4", "a2", "a3" ); + +#endif /* TriCore */ + +#if defined(__arm__) + +#define MULADDC_INIT \ + asm( "ldr r0, %0 " :: "m" (s)); \ + asm( "ldr r1, %0 " :: "m" (d)); \ + asm( "ldr r2, %0 " :: "m" (c)); \ + asm( "ldr r3, %0 " :: "m" (b)); + +#define MULADDC_CORE \ + asm( "ldr r4, [r0], #4 " ); \ + asm( "mov r5, #0 " ); \ + asm( "ldr r6, [r1] " ); \ + asm( "umlal r2, r5, r3, r4 " ); \ + asm( "adds r7, r6, r2 " ); \ + asm( "adc r2, r5, #0 " ); \ + asm( "str r7, [r1], #4 " ); + +#define MULADDC_STOP \ + asm( "str r2, %0 " : "=m" (c)); \ + asm( "str r1, %0 " : "=m" (d)); \ + asm( "str r0, %0 " : "=m" (s) :: \ + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7" ); + +#endif /* ARMv3 */ + +#if defined(__alpha__) + +#define MULADDC_INIT \ + asm( "ldq $1, %0 " :: "m" (s)); \ + asm( "ldq $2, %0 " :: "m" (d)); \ + asm( "ldq $3, %0 " :: "m" (c)); \ + asm( "ldq $4, %0 " :: "m" (b)); + +#define MULADDC_CORE \ + asm( "ldq $6, 0($1) " ); \ + asm( "addq $1, 8, $1 " ); \ + asm( "mulq $6, $4, $7 " ); \ + asm( "umulh $6, $4, $6 " ); \ + asm( "addq $7, $3, $7 " ); \ + asm( "cmpult $7, $3, $3 " ); \ + asm( "ldq $5, 0($2) " ); \ + asm( "addq $7, $5, $7 " ); \ + asm( "cmpult $7, $5, $5 " ); \ + asm( "stq $7, 0($2) " ); \ + asm( "addq $2, 8, $2 " ); \ + asm( "addq $6, $3, $3 " ); \ + asm( "addq $5, $3, $3 " ); + +#define MULADDC_STOP \ + asm( "stq $3, %0 " : "=m" (c)); \ + asm( "stq $2, %0 " : "=m" (d)); \ + asm( "stq $1, %0 " : "=m" (s) :: \ + "$1", "$2", "$3", "$4", "$5", "$6", "$7" ); + +#endif /* Alpha */ + +#if defined(__mips__) + +#define MULADDC_INIT \ + asm( "lw $10, %0 " :: "m" (s)); \ + asm( "lw $11, %0 " :: "m" (d)); \ + asm( "lw $12, %0 " :: "m" (c)); \ + asm( "lw $13, %0 " :: "m" (b)); + +#define MULADDC_CORE \ + asm( "lw $14, 0($10) " ); \ + asm( "multu $13, $14 " ); \ + asm( "addi $10, $10, 4 " ); \ + asm( "mflo $14 " ); \ + asm( "mfhi $9 " ); \ + asm( "addu $14, $12, $14 " ); \ + asm( "lw $15, 0($11) " ); \ + asm( "sltu $12, $14, $12 " ); \ + asm( "addu $15, $14, $15 " ); \ + asm( "sltu $14, $15, $14 " ); \ + asm( "addu $12, $12, $9 " ); \ + asm( "sw $15, 0($11) " ); \ + asm( "addu $12, $12, $14 " ); \ + asm( "addi $11, $11, 4 " ); + +#define MULADDC_STOP \ + asm( "sw $12, %0 " : "=m" (c)); \ + asm( "sw $11, %0 " : "=m" (d)); \ + asm( "sw $10, %0 " : "=m" (s) :: \ + "$9", "$10", "$11", "$12", "$13", "$14", "$15" ); + +#endif /* MIPS */ +#endif /* GNUC */ + +#if (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__) + +#define MULADDC_INIT \ + __asm mov esi, s \ + __asm mov edi, d \ + __asm mov ecx, c \ + __asm mov ebx, b + +#define MULADDC_CORE \ + __asm lodsd \ + __asm mul ebx \ + __asm add eax, ecx \ + __asm adc edx, 0 \ + __asm add eax, [edi] \ + __asm adc edx, 0 \ + __asm mov ecx, edx \ + __asm stosd + +#if defined(POLARSSL_HAVE_SSE2) + +#define EMIT __asm _emit + +#define MULADDC_HUIT \ + EMIT 0x0F EMIT 0x6E EMIT 0xC9 \ + EMIT 0x0F EMIT 0x6E EMIT 0xC3 \ + EMIT 0x0F EMIT 0x6E EMIT 0x1F \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCB \ + EMIT 0x0F EMIT 0x6E EMIT 0x16 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xD0 \ + EMIT 0x0F EMIT 0x6E EMIT 0x66 EMIT 0x04 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xE0 \ + EMIT 0x0F EMIT 0x6E EMIT 0x76 EMIT 0x08 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xF0 \ + EMIT 0x0F EMIT 0x6E EMIT 0x7E EMIT 0x0C \ + EMIT 0x0F EMIT 0xF4 EMIT 0xF8 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCA \ + EMIT 0x0F EMIT 0x6E EMIT 0x5F EMIT 0x04 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xDC \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x08 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xEE \ + EMIT 0x0F EMIT 0x6E EMIT 0x67 EMIT 0x0C \ + EMIT 0x0F EMIT 0xD4 EMIT 0xFC \ + EMIT 0x0F EMIT 0x7E EMIT 0x0F \ + EMIT 0x0F EMIT 0x6E EMIT 0x56 EMIT 0x10 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xD0 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0x6E EMIT 0x66 EMIT 0x14 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xE0 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCB \ + EMIT 0x0F EMIT 0x6E EMIT 0x76 EMIT 0x18 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xF0 \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x04 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0x6E EMIT 0x5E EMIT 0x1C \ + EMIT 0x0F EMIT 0xF4 EMIT 0xD8 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCD \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x10 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xD5 \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x08 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCF \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x14 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xE5 \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x0C \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCA \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x18 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xF5 \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x10 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCC \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x1C \ + EMIT 0x0F EMIT 0xD4 EMIT 0xDD \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x14 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCE \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x18 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCB \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x1C \ + EMIT 0x83 EMIT 0xC7 EMIT 0x20 \ + EMIT 0x83 EMIT 0xC6 EMIT 0x20 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0x7E EMIT 0xC9 + +#define MULADDC_STOP \ + EMIT 0x0F EMIT 0x77 \ + __asm mov c, ecx \ + __asm mov d, edi \ + __asm mov s, esi \ + +#else + +#define MULADDC_STOP \ + __asm mov c, ecx \ + __asm mov d, edi \ + __asm mov s, esi \ + +#endif /* SSE2 */ +#endif /* MSVC */ + +#endif /* POLARSSL_HAVE_ASM */ + +#if !defined(MULADDC_CORE) +#if defined(POLARSSL_HAVE_LONGLONG) + +#define MULADDC_INIT \ +{ \ + t_udbl r; \ + t_uint r0, r1; + +#define MULADDC_CORE \ + r = *(s++) * (t_udbl) b; \ + r0 = r; \ + r1 = r >> biL; \ + r0 += c; r1 += (r0 < c); \ + r0 += *d; r1 += (r0 < *d); \ + c = r1; *(d++) = r0; + +#define MULADDC_STOP \ +} + +#else +#define MULADDC_INIT \ +{ \ + t_uint s0, s1, b0, b1; \ + t_uint r0, r1, rx, ry; \ + b0 = ( b << biH ) >> biH; \ + b1 = ( b >> biH ); + +#define MULADDC_CORE \ + s0 = ( *s << biH ) >> biH; \ + s1 = ( *s >> biH ); s++; \ + rx = s0 * b1; r0 = s0 * b0; \ + ry = s1 * b0; r1 = s1 * b1; \ + r1 += ( rx >> biH ); \ + r1 += ( ry >> biH ); \ + rx <<= biH; ry <<= biH; \ + r0 += rx; r1 += (r0 < rx); \ + r0 += ry; r1 += (r0 < ry); \ + r0 += c; r1 += (r0 < c); \ + r0 += *d; r1 += (r0 < *d); \ + c = r1; *(d++) = r0; + +#define MULADDC_STOP \ +} + +#endif /* C (generic) */ +#endif /* C (longlong) */ + +#endif /* bn_mul.h */ diff --git a/protocols/Tlen/src/crypto/polarssl/config.h b/protocols/Tlen/src/crypto/polarssl/config.h new file mode 100644 index 0000000000..61500a75ee --- /dev/null +++ b/protocols/Tlen/src/crypto/polarssl/config.h @@ -0,0 +1,625 @@ +/** + * \file config.h + * + * \brief Configuration options (set of defines) + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * 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. + * + * This set of compile-time options may be used to enable + * or disable features selectively, and reduce the global + * memory footprint. + */ +#ifndef POLARSSL_CONFIG_H +#define POLARSSL_CONFIG_H + +#ifndef _CRT_SECURE_NO_DEPRECATE +#define _CRT_SECURE_NO_DEPRECATE 1 +#endif + +/** + * \name SECTION: System support + * + * This section sets system specific settings. + * \{ + */ + +/** + * \def POLARSSL_HAVE_INT8 + * + * The system uses 8-bit wide native integers. + * + * Uncomment if native integers are 8-bit wide. +#define POLARSSL_HAVE_INT8 + */ + +/** + * \def POLARSSL_HAVE_INT16 + * + * The system uses 16-bit wide native integers. + * + * Uncomment if native integers are 16-bit wide. +#define POLARSSL_HAVE_INT16 + */ + +/** + * \def POLARSSL_HAVE_LONGLONG + * + * The compiler supports the use of long long. + * + * Uncomment if the compiler supports long long. +#define POLARSSL_HAVE_LONGLONG + */ + +/** + * \def POLARSSL_HAVE_ASM + * + * The compiler has support for asm() + * + * Uncomment to enable the use of assembly code. + * + * Requires support for asm() in compiler. + * + * Used in: + * library/timing.c + * library/padlock.c + * include/polarssl/bn_mul.h + * + */ +#define POLARSSL_HAVE_ASM + +/** + * \def POLARSSL_HAVE_SSE2 + * + * CPI supports SSE2 instruction set. + * + * Uncomment if the CPU supports SSE2 (IA-32 specific). + * +#define POLARSSL_HAVE_SSE2 + */ +/* \} name */ + +/** + * \name SECTION: PolarSSL feature support + * + * This section sets support for features that are or are not needed + * within the modules that are enabled. + * \{ + */ + +/** + * \def POLARSSL_AES_ROM_TABLES + * + * Store the AES tables in ROM. + * + * Uncomment this macro to store the AES tables in ROM. + * +#define POLARSSL_AES_ROM_TABLES + */ + +/** + * \def POLARSSL_CIPHER_MODE_CFB + * + * Enable Cipher Feedback mode (CFB) for symmetric ciphers. + */ +#define POLARSSL_CIPHER_MODE_CFB + +/** + * \def POLARSSL_CIPHER_MODE_CTR + * + * Enable Counter Block Cipher mode (CTR) for symmetric ciphers. + */ +#define POLARSSL_CIPHER_MODE_CTR + +/** + * \def POLARSSL_DEBUG_MSG + * + * Requires: POLARSSL_DEBUG_C + * + * Enable all SSL/TLS debugging messages. + */ +#define POLARSSL_DEBUG_MSG + +/** + * \def POLARSSL_GENPRIME + * + * Requires: POLARSSL_BIGNUM_C, POLARSSL_RSA_C + * + * Enable the RSA prime-number generation code. + */ +#define POLARSSL_GENPRIME + +/** + * \def POLARSSL_FS_IO + * + * Enable functions that use the filesystem. + */ +#define POLARSSL_FS_IO + +/** + * \def POLARSSL_PKCS1_V21 + * + * Requires: POLARSSL_MD_C, POLARSSL_RSA_C + * + * Enable support for PKCS#1 v2.1 encoding. + * This enables support for RSAES-OAEP and RSASSA-PSS operations. + */ +#define POLARSSL_PKCS1_V21 + +/** + * \def POLARSSL_RSA_NO_CRT + * + * Do not use the Chinese Remainder Theorem for the RSA private operation. + * + * Uncomment this macro to disable the use of CRT in RSA. + * +#define POLARSSL_RSA_NO_CRT + */ + +/** + * \def POLARSSL_SELF_TEST + * + * Enable the checkup functions (*_self_test). + */ +#define POLARSSL_SELF_TEST + +/** + * \def POLARSSL_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION + * + * If set, the X509 parser will not break-off when parsing an X509 certificate + * and encountering an unknown critical extension. + * + * Uncomment to prevent an error. + * +#define POLARSSL_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION + */ +/* \} name */ + +/** + * \name SECTION: PolarSSL modules + * + * This section enables or disables entire modules in PolarSSL + * \{ + */ + +/** + * \def POLARSSL_AES_C + * + * Enable the AES block cipher. + * + * Module: library/aes.c + * Caller: library/ssl_tls.c + * library/pem.c + * + * This module enables the following ciphersuites: + * SSL_RSA_AES_128_SHA + * SSL_RSA_AES_256_SHA + * SSL_EDH_RSA_AES_256_SHA + */ +#define POLARSSL_AES_C + +/** + * \def POLARSSL_ARC4_C + * + * Enable the ARCFOUR stream cipher. + * + * Module: library/arc4.c + * Caller: library/ssl_tls.c + * + * This module enables the following ciphersuites: + * SSL_RSA_RC4_128_MD5 + * SSL_RSA_RC4_128_SHA + */ +#define POLARSSL_ARC4_C + +/** + * \def POLARSSL_BASE64_C + * + * Enable the Base64 module. + * + * Module: library/base64.c + * Caller: library/pem.c + * + * This module is required for PEM support (required by X.509). + */ +#define POLARSSL_BASE64_C + +/** + * \def POLARSSL_BIGNUM_C + * + * Enable the multo-precision integer library. + * + * Module: library/bignum.c + * Caller: library/dhm.c + * library/rsa.c + * library/ssl_tls.c + * library/x509parse.c + * + * This module is required for RSA and DHM support. + */ +#define POLARSSL_BIGNUM_C + +/** + * \def POLARSSL_CAMELLIA_C + * + * Enable the Camellia block cipher. + * + * Module: library/camellia.c + * Caller: library/ssl_tls.c + * + * This module enabled the following cipher suites: + * SSL_RSA_CAMELLIA_128_SHA + * SSL_RSA_CAMELLIA_256_SHA + * SSL_EDH_RSA_CAMELLIA_256_SHA + */ +#define POLARSSL_CAMELLIA_C + +/** + * \def POLARSSL_CERTS_C + * + * Enable the test certificates. + * + * Module: library/certs.c + * Caller: + * + * This module is used for testing (ssl_client/server). + */ +#define POLARSSL_CERTS_C + +/** + * \def POLARSSL_CIPHER_C + * + * Enable the generic cipher layer. + * + * Module: library/cipher.c + * Caller: + * + * Uncomment to enable generic cipher wrappers. + */ +#define POLARSSL_CIPHER_C + +/** + * \def POLARSSL_DEBUG_C + * + * Enable the debug functions. + * + * Module: library/debug.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * + * This module provides debugging functions. + */ +#define POLARSSL_DEBUG_C + +/** + * \def POLARSSL_DES_C + * + * Enable the DES block cipher. + * + * Module: library/des.c + * Caller: library/ssl_tls.c + * + * This module enables the following ciphersuites: + * SSL_RSA_DES_168_SHA + * SSL_EDH_RSA_DES_168_SHA + */ +#define POLARSSL_DES_C + +/** + * \def POLARSSL_DHM_C + * + * Enable the Diffie-Hellman-Merkle key exchange. + * + * Module: library/dhm.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * This module enables the following ciphersuites: + * SSL_EDH_RSA_DES_168_SHA + * SSL_EDH_RSA_AES_256_SHA + * SSL_EDH_RSA_CAMELLIA_256_SHA + */ +#define POLARSSL_DHM_C + +/** + * \def POLARSSL_ERROR_C + * + * Enable error code to error string conversion. + * + * Module: library/error.c + * Caller: + * + * This module enables err_strerror(). + */ +#define POLARSSL_ERROR_C + +/** + * \def POLARSSL_HAVEGE_C + * + * Enable the HAVEGE random generator. + * + * Module: library/havege.c + * Caller: + * + * Requires: POLARSSL_TIMING_C + * + * This module enables the HAVEGE random number generator. + */ +#define POLARSSL_HAVEGE_C + +/** + * \def POLARSSL_MD_C + * + * Enable the generic message digest layer. + * + * Module: library/md.c + * Caller: + * + * Uncomment to enable generic message digest wrappers. + */ +#define POLARSSL_MD_C + +/** + * \def POLARSSL_MD2_C + * + * Enable the MD2 hash algorithm + * + * Module: library/md2.c + * Caller: library/x509parse.c + * + * Uncomment to enable support for (rare) MD2-signed X.509 certs. + * +#define POLARSSL_MD2_C + */ + +/** + * \def POLARSSL_MD4_C + * + * Enable the MD4 hash algorithm + * + * Module: library/md4.c + * Caller: library/x509parse.c + * + * Uncomment to enable support for (rare) MD4-signed X.509 certs. + * +#define POLARSSL_MD4_C + */ + +/** + * \def POLARSSL_MD5_C + * + * Enable the MD5 hash algorithm + * + * Module: library/md5.c + * Caller: library/ssl_tls.c + * library/x509parse.c + * + * This module is required for SSL/TLS and X.509. + */ +#define POLARSSL_MD5_C + +/** + * \def POLARSSL_NET_C + * + * Enable the TCP/IP networking routines. + * + * Module: library/net.c + * Caller: + * + * This module provides TCP/IP networking routines. + */ +#define POLARSSL_NET_C + +/** + * \def POLARSSL_PADLOCK_C + * + * Enable VIA Padlock support on x86. + * + * Module: library/padlock.c + * Caller: library/aes.c + * + * This modules adds support for the VIA PadLock on x86. + */ +#define POLARSSL_PADLOCK_C + +/** + * \def POLARSSL_PEM_C + * + * Enable PEM decoding + * + * Module: library/pem.c + * Caller: library/x509parse.c + * + * Requires: POLARSSL_BASE64_C + * + * This modules adds support for decoding PEM files. + */ +#define POLARSSL_PEM_C + +/** + * \def POLARSSL_PKCS11_C + * + * Enable support for PKCS#11 smartcard support. + * + * Module: library/ssl_srv.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * Requires: POLARSSL_SSL_TLS_C + * + * This module is required for SSL/TLS PKCS #11 smartcard support. + * Requires the presence of the PKCS#11 helper library (libpkcs11-helper) +#define POLARSSL_PKCS11_C + */ + +/** + * \def POLARSSL_RSA_C + * + * Enable the RSA public-key cryptosystem. + * + * Module: library/rsa.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * library/x509.c + * + * Requires: POLARSSL_BIGNUM_C + * + * This module is required for SSL/TLS and MD5-signed certificates. + */ +#define POLARSSL_RSA_C + +/** + * \def POLARSSL_SHA1_C + * + * Enable the SHA1 cryptographic hash algorithm. + * + * Module: library/sha1.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * library/x509parse.c + * + * This module is required for SSL/TLS and SHA1-signed certificates. + */ +#define POLARSSL_SHA1_C + +/** + * \def POLARSSL_SHA2_C + * + * Enable the SHA-224 and SHA-256 cryptographic hash algorithms. + * + * Module: library/sha2.c + * Caller: library/md_wrap.c + * library/x509parse.c + * + * This module adds support for SHA-224 and SHA-256. + */ +#define POLARSSL_SHA2_C + +/** + * \def POLARSSL_SHA4_C + * + * Enable the SHA-384 and SHA-512 cryptographic hash algorithms. + * + * Module: library/sha4.c + * Caller: library/md_wrap.c + * library/x509parse.c + * + * This module adds support for SHA-384 and SHA-512. + */ +#define POLARSSL_SHA4_C + +/** + * \def POLARSSL_SSL_CLI_C + * + * Enable the SSL/TLS client code. + * + * Module: library/ssl_cli.c + * Caller: + * + * Requires: POLARSSL_SSL_TLS_C + * + * This module is required for SSL/TLS client support. + */ +#define POLARSSL_SSL_CLI_C + +/* + * \def POLARSSL_SSL_SRV_C + * + * Enable the SSL/TLS server code. + * + * Module: library/ssl_srv.c + * Caller: + * + * Requires: POLARSSL_SSL_TLS_C + * + * This module is required for SSL/TLS server support. + */ +#define POLARSSL_SSL_SRV_C + +/** + * \def POLARSSL_SSL_TLS_C + * + * Enable the generic SSL/TLS code. + * + * Module: library/ssl_tls.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * Requires: POLARSSL_MD5_C, POLARSSL_SHA1_C, POLARSSL_X509_PARSE_C + * + * This module is required for SSL/TLS. + */ +#define POLARSSL_SSL_TLS_C + +/** + * \def POLARSSL_TIMING_C + * + * Enable the portable timing interface. + * + * Module: library/timing.c + * Caller: library/havege.c + * + * This module is used by the HAVEGE random number generator. + */ +#define POLARSSL_TIMING_C + +/** + * \def POLARSSL_VERSION_C + * + * Enable run-time version information. + * + * Module: library/version.c + * + * This module provides run-time version information. + */ +#define POLARSSL_VERSION_C + +/** + * \def POLARSSL_X509_PARSE_C + * + * Enable X.509 certificate parsing. + * + * Module: library/x509parse.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * + * Requires: POLARSSL_BIGNUM_C, POLARSSL_RSA_C + * + * This module is required for X.509 certificate parsing. + */ +#define POLARSSL_X509_PARSE_C + +/** + * \def POLARSSL_XTEA_C + * + * Enable the XTEA block cipher. + * + * Module: library/xtea.c + * Caller: + */ +#define POLARSSL_XTEA_C +/* \} name */ + +#endif /* config.h */ diff --git a/protocols/Tlen/src/crypto/polarssl/padlock.h b/protocols/Tlen/src/crypto/polarssl/padlock.h new file mode 100644 index 0000000000..08fbe825c9 --- /dev/null +++ b/protocols/Tlen/src/crypto/polarssl/padlock.h @@ -0,0 +1,100 @@ +/** + * \file padlock.h + * + * \brief VIA PadLock ACE for HW encryption/decryption supported by some processors + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * 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. + */ +#ifndef POLARSSL_PADLOCK_H +#define POLARSSL_PADLOCK_H + +#include "polarssl/aes.h" + +#define POLARSSL_ERR_PADLOCK_DATA_MISALIGNED -0x0030 /**< Input data should be aligned. */ + +#if defined(POLARSSL_HAVE_ASM) && defined(__GNUC__) && defined(__i386__) + +#ifndef POLARSSL_HAVE_X86 +#define POLARSSL_HAVE_X86 +#endif + +#define PADLOCK_RNG 0x000C +#define PADLOCK_ACE 0x00C0 +#define PADLOCK_PHE 0x0C00 +#define PADLOCK_PMM 0x3000 + +#define PADLOCK_ALIGN16(x) (unsigned long *) (16 + ((long) x & ~15)) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief PadLock detection routine + * + * \param The feature to detect + * + * \return 1 if CPU has support for the feature, 0 otherwise + */ +int padlock_supports( int feature ); + +/** + * \brief PadLock AES-ECB block en(de)cryption + * + * \param ctx AES context + * \param mode AES_ENCRYPT or AES_DECRYPT + * \param input 16-byte input block + * \param output 16-byte output block + * + * \return 0 if success, 1 if operation failed + */ +int padlock_xcryptecb( aes_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ); + +/** + * \brief PadLock AES-CBC buffer en(de)cryption + * + * \param ctx AES context + * \param mode AES_ENCRYPT or AES_DECRYPT + * \param length length of the input data + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if success, 1 if operation failed + */ +int padlock_xcryptcbc( aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); + +#ifdef __cplusplus +} +#endif + +#endif /* HAVE_X86 */ + +#endif /* padlock.h */ diff --git a/protocols/Tlen/src/jabber.h b/protocols/Tlen/src/jabber.h new file mode 100644 index 0000000000..450b84c1f8 --- /dev/null +++ b/protocols/Tlen/src/jabber.h @@ -0,0 +1,507 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Tlen Protocol Plugin for Miranda NG +Copyright (C) 2002-2004 Santithorn Bunchua +Copyright (C) 2004-2007 Piotr Piastucki + +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. + +*/ + +#ifndef _JABBER_H_ +#define _JABBER_H_ + +#define MIRANDA_VER 0x0A00 + +#undef _WIN32_WINNT +#undef _WIN32_IE +#define _WIN32_WINNT 0x0501 +#define _WIN32_IE 0x0501 + +#define __try +#define __except(x) if (0) +#define __finally + +#define _try __try +#define _except __except +#define _finally __finally + + +#include "m_stdhdr.h" + + +#ifdef _DEBUG +#define _CRTDBG_MAP_ALLOC +#include +#include +#endif +#define ENABLE_LOGGING + +/******************************************************************* + * Global compilation flags + *******************************************************************/ + +/******************************************************************* + * Global header files + *******************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "jabber_xml.h" +#include "crypto/polarssl/aes.h" +#include "crypto/polarssl/bignum.h" + +/******************************************************************* + * Global constants + *******************************************************************/ +#define TLEN_DEFAULT_PORT 443 +#define JABBER_IQID "mim_" +#define TLEN_REGISTER "http://reg.tlen.pl/" +#define TLEN_MAX_SEARCH_RESULTS_PER_PAGE 20 + +// User-defined message +#define WM_TLEN_REFRESH (WM_USER + 100) +// Error code +#define JABBER_ERROR_REDIRECT 302 +#define JABBER_ERROR_BAD_REQUEST 400 +#define JABBER_ERROR_UNAUTHORIZED 401 +#define JABBER_ERROR_PAYMENT_REQUIRED 402 +#define JABBER_ERROR_FORBIDDEN 403 +#define JABBER_ERROR_NOT_FOUND 404 +#define JABBER_ERROR_NOT_ALLOWED 405 +#define JABBER_ERROR_NOT_ACCEPTABLE 406 +#define JABBER_ERROR_REGISTRATION_REQUIRED 407 +#define JABBER_ERROR_REQUEST_TIMEOUT 408 +#define JABBER_ERROR_CONFLICT 409 +#define JABBER_ERROR_INTERNAL_SERVER_ERROR 500 +#define JABBER_ERROR_NOT_IMPLEMENTED 501 +#define JABBER_ERROR_REMOTE_SERVER_ERROR 502 +#define JABBER_ERROR_SERVICE_UNAVAILABLE 503 +#define JABBER_ERROR_REMOTE_SERVER_TIMEOUT 504 + +#define TLEN_ALERTS_ACCEPT_ALL 0 +#define TLEN_ALERTS_IGNORE_NIR 1 +#define TLEN_ALERTS_IGNORE_ALL 2 + +#define TLEN_IMAGES_ACCEPT_ALL 0 +#define TLEN_IMAGES_IGNORE_NIR 1 +#define TLEN_IMAGES_IGNORE_ALL 2 + +#define TLEN_MUC_ASK 0 +#define TLEN_MUC_ACCEPT_IR 1 +#define TLEN_MUC_ACCEPT_ALL 2 +#define TLEN_MUC_IGNORE_NIR 3 +#define TLEN_MUC_IGNORE_ALL 4 + +#define IDC_STATIC (-1) + +/******************************************************************* + * Global data structures and data type definitions + *******************************************************************/ +typedef HANDLE JABBER_SOCKET; + +typedef enum { + LIST_ROSTER, // Roster list + LIST_CHATROOM, // Groupchat room currently joined + LIST_FILE, // Current file transfer session + LIST_INVITATIONS,// Invitations to be sent + LIST_SEARCH, // Rooms names being searched + LIST_VOICE, + LIST_PICTURE +} JABBER_LIST; + +typedef enum { + IQ_PROC_NONE, + IQ_PROC_GETSEARCH +} JABBER_IQ_PROCID; + +typedef enum { + SUB_NONE, + SUB_TO, + SUB_FROM, + SUB_BOTH +} JABBER_SUBSCRIPTION; + +typedef struct { + char *szOnline; + char *szAway; + char *szNa; + char *szDnd; + char *szFreechat; + char *szInvisible; +} JABBER_MODEMSGS; + +typedef struct { + char mailBase[256]; + char mailMsg[256]; + int mailMsgMthd; + char mailIndex[256]; + int mailIndexMthd; + char mailLogin[256]; + int mailLoginMthd; + char mailCompose[256]; + int mailComposeMthd; + char avatarGet[256]; + int avatarGetMthd; + char avatarUpload[256]; + int avatarUploadMthd; + char avatarRemove[256]; + int avatarRemoveMthd; +} TlenConfiguration; + +typedef struct { + BOOL useEncryption; + BOOL reconnect; + BOOL rosterSync; + BOOL offlineAsInvisible; + BOOL leaveOfflineMessage; + int offlineMessageOption; + BOOL ignoreAdvertisements; + int alertPolicy; + int groupChatPolicy; + int voiceChatPolicy; + int imagePolicy; + BOOL enableAvatars; + BOOL enableVersion; + BOOL useNudge; + BOOL logAlerts; + BOOL useNewP2P; + BOOL sendKeepAlive; + BOOL savePassword; +} TlenOptions; + + +struct JABBER_IQ_FUNC_STRUCT; +struct JABBER_LIST_ITEM_STRUCT; +struct TLEN_VOICE_CONTROL_STRUCT; + + +struct TlenProtocol : public PROTO_INTERFACE, public MZeroedObject +{ + typedef PROTO_INTERFACE CSuper; + + TlenProtocol( const char*, const TCHAR* ); + ~TlenProtocol(); + + //==================================================================================== + // PROTO_INTERFACE + //==================================================================================== + + virtual HANDLE __cdecl AddToList( int flags, PROTOSEARCHRESULT* psr ); + virtual HANDLE __cdecl AddToListByEvent( int flags, int iContact, HANDLE hDbEvent ); + + virtual int __cdecl Authorize(HANDLE hDbEvent); + virtual int __cdecl AuthDeny(HANDLE hDbEvent, const PROTOCHAR* szReason); + virtual int __cdecl AuthRecv(HANDLE hContact, PROTORECVEVENT*); + virtual int __cdecl AuthRequest(HANDLE hContact, const PROTOCHAR* szMessage); + + virtual HANDLE __cdecl ChangeInfo(int iInfoType, void* pInfoData); + + virtual HANDLE __cdecl FileAllow(HANDLE hContact, HANDLE hTransfer, const PROTOCHAR* szPath); + virtual int __cdecl FileCancel(HANDLE hContact, HANDLE hTransfer); + virtual int __cdecl FileDeny(HANDLE hContact, HANDLE hTransfer, const PROTOCHAR* szReason); + virtual int __cdecl FileResume(HANDLE hTransfer, int* action, const PROTOCHAR** szFilename); + + virtual DWORD_PTR __cdecl GetCaps(int type, HANDLE hContact = NULL); + virtual HICON __cdecl GetIcon(int iconIndex); + virtual int __cdecl GetInfo(HANDLE hContact, int infoType); + + virtual HANDLE __cdecl SearchBasic(const PROTOCHAR* id); + virtual HANDLE __cdecl SearchByEmail(const PROTOCHAR* email); + virtual HANDLE __cdecl SearchByName(const PROTOCHAR* nick, const PROTOCHAR* firstName, const PROTOCHAR* lastName); + virtual HWND __cdecl SearchAdvanced(HWND owner); + virtual HWND __cdecl CreateExtendedSearchUI(HWND owner); + + virtual int __cdecl RecvContacts(HANDLE hContact, PROTORECVEVENT*); + virtual int __cdecl RecvFile(HANDLE hContact, PROTOFILEEVENT*); + virtual int __cdecl RecvMsg(HANDLE hContact, PROTORECVEVENT*); + virtual int __cdecl RecvUrl(HANDLE hContact, PROTORECVEVENT*); + + virtual int __cdecl SendContacts(HANDLE hContact, int flags, int nContacts, HANDLE* hContactsList); + virtual HANDLE __cdecl SendFile(HANDLE hContact, const PROTOCHAR* szDescription, PROTOCHAR** ppszFiles); + virtual int __cdecl SendMsg(HANDLE hContact, int flags, const char* msg); + virtual int __cdecl SendUrl(HANDLE hContact, int flags, const char* url); + + virtual int __cdecl SetApparentMode(HANDLE hContact, int mode); + virtual int __cdecl SetStatus(int iNewStatus); + + virtual HANDLE __cdecl GetAwayMsg(HANDLE hContact); + virtual int __cdecl RecvAwayMsg(HANDLE hContact, int mode, PROTORECVEVENT* evt); + virtual int __cdecl SendAwayMsg(HANDLE hContact, HANDLE hProcess, const char* msg); + virtual int __cdecl SetAwayMsg(int iStatus, const PROTOCHAR* msg); + + virtual int __cdecl UserIsTyping(HANDLE hContact, int type); + + virtual int __cdecl OnEvent(PROTOEVENTTYPE iEventType, WPARAM wParam, LPARAM lParam); + + + + + + HANDLE hNetlibUser; + HANDLE hFileNetlibUser; + + JABBER_MODEMSGS modeMsgs; + + struct ThreadDataStruct *threadData; + HANDLE hTlenNudge; + HANDLE hMenuMUC; + HANDLE hMenuChats; + HANDLE hMenuInbox; + HANDLE hMenuContactMUC; + HANDLE hMenuContactVoice; + HANDLE hMenuContactGrantAuth; + HANDLE hMenuContactRequestAuth; + HANDLE hMenuPicture; + + HANDLE* hServices; + unsigned serviceNum; + HANDLE* hHooks; + unsigned hookNum; + + + int listsCount; + struct JABBER_LIST_ITEM_STRUCT *lists; + CRITICAL_SECTION csLists; + + int iqCount; + int iqAlloced; + struct JABBER_IQ_FUNC_STRUCT *iqList; + CRITICAL_SECTION csIqList; + + CRITICAL_SECTION csSerial; + unsigned int serial; + BOOL isOnline; + BOOL isConnected; + + CRITICAL_SECTION modeMsgMutex; + + HANDLE hMenuRoot; + + char *searchJID; + int searchID; + int searchIndex; + char *searchQuery; + int searchQueryLen; + + CRITICAL_SECTION csSend; + + HWND voiceDlgHWND; + struct TLEN_VOICE_CONTROL_STRUCT *playbackControl; + struct TLEN_VOICE_CONTROL_STRUCT *recordingControl; + int framesAvailableForPlayback; + int availOverrunValue; + + TlenOptions tlenOptions; + +}; + + + +typedef struct ThreadDataStruct{ + HANDLE hThread; + char *streamId; + char username[128]; + char password[128]; + char server[128]; + char manualHost[128]; + char avatarToken[128]; + char avatarHash[64]; + int avatarFormat; + WORD port; + BOOL useEncryption; + + JABBER_SOCKET s; //HANDLE from CallService(MS_NETLIB_OPENCONNECTION (jabber_ws.c:68) + aes_context aes_in_context; + aes_context aes_out_context; + unsigned char aes_in_iv[16]; + unsigned char aes_out_iv[16]; + + BOOL useAES; + TlenConfiguration tlenConfig; + TlenProtocol *proto; +} ThreadData; + + +typedef enum { FT_CONNECTING, FT_INITIALIZING, FT_RECEIVING, FT_DONE, FT_ERROR, FT_DENIED, FT_SWITCH } JABBER_FILE_STATE; +typedef enum { FT_RECV, FT_SEND} JABBER_FILE_MODE; +typedef struct TLEN_FILE_TRANSFER_STRUCT{ + HANDLE hContact; + JABBER_SOCKET s; + NETLIBNEWCONNECTIONPROC_V2 pfnNewConnectionV2; + JABBER_FILE_STATE state; + char *jid; + int fileId; + char *iqId; + int mode; + + // Used by file receiving only + char *hostName; + WORD wPort; + char *localName; + WORD wLocalPort; + char *szSavePath; + long fileReceivedBytes; + long fileTotalSize; + + // Used by file sending only + HANDLE hFileEvent; + int fileCount; + char **files; + long *filesSize; + //long fileTotalSize; // Size of the current file (file being sent) + long allFileTotalSize; + long allFileReceivedBytes; + char *szDescription; + int currentFile; + + // New p2p + BOOL newP2P; + char *id2; + SOCKET udps; + aes_context aes_context; + unsigned char aes_iv[16]; + TlenProtocol *proto; + +} TLEN_FILE_TRANSFER; + +typedef struct { + PROTOSEARCHRESULT hdr; + char jid[256]; +} JABBER_SEARCH_RESULT; + +typedef struct { + char *iqId; + PROTOSEARCHRESULT hdr; + char jid[256]; +} TLEN_CONFERENCE; + + +typedef struct { + int id; + TCHAR *name; +} JABBER_FIELD_MAP; + + +/******************************************************************* + * Global variables + *******************************************************************/ +extern HINSTANCE hInst; +extern HANDLE hMainThread; + +/******************************************************************* + * Function declarations + *******************************************************************/ +void uninitMenuItems(TlenProtocol *proto); +HICON GetIcolibIcon(int iconId); +void ReleaseIcolibIcon(HICON hIcon); + +void JabberLog(TlenProtocol *proto, const char *fmt, ...); +void __cdecl JabberServerThread(ThreadData *info); +// jabber_ws.cpp +BOOL JabberWsInit(TlenProtocol *proto); +void JabberWsUninit(TlenProtocol *proto); +JABBER_SOCKET JabberWsConnect(TlenProtocol *proto, char *host, WORD port); +int JabberWsSend(TlenProtocol *proto, JABBER_SOCKET s, char *data, int datalen); +int JabberWsRecv(TlenProtocol *proto, JABBER_SOCKET s, char *data, long datalen); +int JabberWsSendAES(TlenProtocol *proto, char *data, int datalen, aes_context *aes_ctx, unsigned char *aes_iv); +int JabberWsRecvAES(TlenProtocol *proto, char *data, long datalen, aes_context *aes_ctx, unsigned char *aes_iv); +// jabber_util.cpp +HANDLE HookEventObj_Ex(const char *name, TlenProtocol *proto, MIRANDAHOOKOBJ hook); +HANDLE CreateServiceFunction_Ex(const char *name, TlenProtocol *proto, MIRANDASERVICEOBJ service); +void UnhookEvents_Ex(TlenProtocol *proto); +void DestroyServices_Ex(TlenProtocol *proto); +void JabberSerialInit(TlenProtocol *proto); +void JabberSerialUninit(TlenProtocol *proto); +unsigned int JabberSerialNext(TlenProtocol *proto); +int JabberSend(TlenProtocol *proto, const char *fmt, ...); +HANDLE JabberHContactFromJID(TlenProtocol *proto, const char *jid); +char *JabberJIDFromHContact(TlenProtocol *proto, HANDLE hContact); +char *JabberLoginFromJID(const char *jid); +char *JabberResourceFromJID(const char *jid); +char *JabberNickFromJID(const char *jid); +char *JabberLocalNickFromJID(const char *jid); +char *TlenGroupEncode(const char *str); +char *TlenGroupDecode(const char *str); +char *JabberSha1(char *str); +char *TlenSha1(char *str, int len); +char *TlenPasswordHash(const char *str); +void TlenUrlDecode(char *str); +char *TlenUrlEncode(const char *str); +char *JabberTextEncode(const char *str); +char *JabberTextDecode(const char *str); +char *JabberBase64Encode(const char *buffer, int bufferLen); +char *JabberBase64Decode(const char *buffer, int *resultLen); +int JabberGetPictureType(const char* buf); +void TlenLogMessage(TlenProtocol *proto, HANDLE hContact, DWORD flags, const char *message); +BOOL IsAuthorized(TlenProtocol *proto, const char *jid); +//char *JabberGetVersionText(); +time_t JabberIsoToUnixTime(char *stamp); +time_t TlenTimeToUTC(time_t time); +void JabberSendPresence(TlenProtocol *proto,int status); +void JabberStringAppend(char **str, int *sizeAlloced, const char *fmt, ...); +//char *JabberGetClientJID(char *jid); +// jabber_misc.cpp +void JabberDBAddEvent(TlenProtocol *proto, HANDLE hContact, int eventType, DWORD flags, PBYTE pBlob, DWORD cbBlob); +void JabberDBAddAuthRequest(TlenProtocol *proto, char *jid, char *nick); +HANDLE JabberDBCreateContact(TlenProtocol *proto, char *jid, char *nick, BOOL temporary); +void JabberContactListCreateGroup(char *groupName); +unsigned long JabberForkThread(void (__cdecl *threadcode)(void*), unsigned long stacksize, void *arg); +// jabber_svc.cpp +int TlenRunSearch(TlenProtocol *proto); +// jabber_opt.cpp +void TlenLoadOptions(TlenProtocol *proto); +// tlen_voice.cpp +int TlenVoiceCancelAll(TlenProtocol *proto); +// jabber_advsearch.cpp +extern JABBER_FIELD_MAP tlenFieldGender[]; +extern JABBER_FIELD_MAP tlenFieldLookfor[]; +extern JABBER_FIELD_MAP tlenFieldStatus[]; +extern JABBER_FIELD_MAP tlenFieldOccupation[]; +extern JABBER_FIELD_MAP tlenFieldPlan[]; +// tlen_advsearch.cpp +INT_PTR CALLBACK TlenAdvSearchDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); +char *TlenAdvSearchCreateQuery(HWND hwndDlg, int iqId); + + +#endif + diff --git a/protocols/Tlen/src/jabber_iq.cpp b/protocols/Tlen/src/jabber_iq.cpp new file mode 100644 index 0000000000..01ce67129b --- /dev/null +++ b/protocols/Tlen/src/jabber_iq.cpp @@ -0,0 +1,114 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Tlen Protocol Plugin for Miranda NG +Copyright (C) 2002-2004 Santithorn Bunchua + +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" + + +void JabberIqInit(TlenProtocol *proto) +{ + InitializeCriticalSection(&proto->csIqList); + proto->iqList = NULL; + proto->iqCount = 0; + proto->iqAlloced = 0; +} + +void JabberIqUninit(TlenProtocol *proto) +{ + if (proto->iqList) mir_free(proto->iqList); + proto->iqList = NULL; + proto->iqCount = 0; + proto->iqAlloced = 0; + DeleteCriticalSection(&proto->csIqList); +} + +static void JabberIqRemove(TlenProtocol *proto, int index) +{ + EnterCriticalSection(&proto->csIqList); + if (index >= 0 && indexiqCount) { + memmove(proto->iqList+index, proto->iqList+index+1, sizeof(JABBER_IQ_FUNC)*(proto->iqCount-index-1)); + proto->iqCount--; + } + LeaveCriticalSection(&proto->csIqList); +} + +static void JabberIqExpire(TlenProtocol *proto) +{ + int i; + time_t expire; + + EnterCriticalSection(&proto->csIqList); + expire = time(NULL) - 120; // 2 minute + i = 0; + while (i < proto->iqCount) { + if (proto->iqList[i].requestTime < expire) + JabberIqRemove(proto, i); + else + i++; + } + LeaveCriticalSection(&proto->csIqList); +} + +JABBER_IQ_PFUNC JabberIqFetchFunc(TlenProtocol *proto, int iqId) +{ + int i; + JABBER_IQ_PFUNC res; + + EnterCriticalSection(&proto->csIqList); + JabberIqExpire(proto); + for (i=0; iiqCount && proto->iqList[i].iqId != iqId; i++); + if (i < proto->iqCount) { + res = proto->iqList[i].func; + JabberIqRemove(proto, i); + } + else { + res = (JABBER_IQ_PFUNC) NULL; + } + LeaveCriticalSection(&proto->csIqList); + return res; +} + +void JabberIqAdd(TlenProtocol *proto, unsigned int iqId, JABBER_IQ_PROCID procId, JABBER_IQ_PFUNC func) +{ + int i; + + EnterCriticalSection(&proto->csIqList); + if (procId == IQ_PROC_NONE) + i = proto->iqCount; + else + for (i=0; iiqCount && proto->iqList[i].procId != procId; i++); + + if (i >= proto->iqCount && proto->iqCount >= proto->iqAlloced) { + proto->iqAlloced = proto->iqCount + 8; + proto->iqList = (JABBER_IQ_FUNC*)mir_realloc(proto->iqList, sizeof(JABBER_IQ_FUNC)*proto->iqAlloced); + } + + if (proto->iqList != NULL) { + proto->iqList[i].iqId = iqId; + proto->iqList[i].procId = procId; + proto->iqList[i].func = func; + proto->iqList[i].requestTime = time(NULL); + if (i == proto->iqCount) proto->iqCount++; + } + LeaveCriticalSection(&proto->csIqList); +} + diff --git a/protocols/Tlen/src/jabber_iq.h b/protocols/Tlen/src/jabber_iq.h new file mode 100644 index 0000000000..d521c85c66 --- /dev/null +++ b/protocols/Tlen/src/jabber_iq.h @@ -0,0 +1,61 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Tlen Protocol Plugin for Miranda NG +Copyright (C) 2002-2004 Santithorn Bunchua +Copyright (C) 2004-2007 Piotr Piastucki + +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. + +*/ +#ifndef _JABBER_IQ_H_ +#define _JABBER_IQ_H_ + +#include "jabber_xml.h" +#include "jabber.h" + +typedef void (*JABBER_IQ_PFUNC)(TlenProtocol *proto, XmlNode *iqNode); + +typedef struct JABBER_IQ_FUNC_STRUCT { + int iqId; // id to match IQ get/set with IQ result + JABBER_IQ_PROCID procId; // must be unique in the list, except for IQ_PROC_NONE which can have multiple entries + JABBER_IQ_PFUNC func; // callback function + time_t requestTime; // time the request was sent, used to remove relinquent entries +} JABBER_IQ_FUNC; + +void JabberIqInit(TlenProtocol *proto); +void JabberIqUninit(TlenProtocol *proto); +JABBER_IQ_PFUNC JabberIqFetchFunc(TlenProtocol *proto, int iqId); +void JabberIqAdd(TlenProtocol *proto, unsigned int iqId, JABBER_IQ_PROCID procId, JABBER_IQ_PFUNC func); + +void JabberIqResultAuth(TlenProtocol *proto, XmlNode *iqNode); +void JabberIqResultRoster(TlenProtocol *proto, XmlNode *iqNode); +void TlenIqResultVcard(TlenProtocol *proto, XmlNode *iqNode); +void JabberIqResultSearch(TlenProtocol *proto, XmlNode *iqNode); +void TlenIqResultVersion(TlenProtocol *proto, XmlNode *iqNode); +void TlenIqResultInfo(TlenProtocol *proto, XmlNode *iqNode); +void TlenIqResultTcfg(TlenProtocol *proto, XmlNode *iqNode); + +void TlenIqResultChatGroups(TlenProtocol *proto, XmlNode *iqNode); +void TlenIqResultChatRooms(TlenProtocol *proto, XmlNode *iqNode); +void TlenIqResultUserRooms(TlenProtocol *proto, XmlNode *iqNode); +void TlenIqResultUserNicks(TlenProtocol *proto, XmlNode *iqNode); +void TlenIqResultRoomSearch(TlenProtocol *proto, XmlNode *iqNode); +void TlenIqResultRoomInfo(TlenProtocol *proto, XmlNode *iqNode); +void TlenIqResultChatRoomUsers(TlenProtocol *proto, XmlNode *iqNode); +//void JabberIqResultSetPassword(XmlNode *iqNode, void *userdata); + +#endif + diff --git a/protocols/Tlen/src/jabber_iqid.cpp b/protocols/Tlen/src/jabber_iqid.cpp new file mode 100644 index 0000000000..2fde1bb6df --- /dev/null +++ b/protocols/Tlen/src/jabber_iqid.cpp @@ -0,0 +1,642 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Tlen Protocol Plugin for Miranda NG +Copyright (C) 2002-2004 Santithorn Bunchua +Copyright (C) 2004-2007 Piotr Piastucki + +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 "resource.h" +#include "jabber_list.h" +#include "jabber_iq.h" +#include "tlen_muc.h" + +void JabberIqResultAuth(TlenProtocol *proto, XmlNode *iqNode) +{ + char *type; + + // RECVED: authentication result + // ACTION: if successfully logged in, continue by requesting roster list and set my initial status + if ((type=JabberXmlGetAttrValue(iqNode, "type")) == NULL) return; + + if (!strcmp(type, "result")) { + DBVARIANT dbv; + + if (DBGetContactSetting(NULL, proto->m_szModuleName, "Nick", &dbv)) + DBWriteContactSettingString(NULL, proto->m_szModuleName, "Nick", proto->threadData->username); + else + DBFreeVariant(&dbv); +// iqId = JabberSerialNext(); +// JabberIqAdd(iqId, IQ_PROC_NONE, JabberIqResultGetRoster); +// JabberSend(info, "", iqId); + + JabberSend(proto, ""); + JabberSend(proto, ""); + } + // What to do if password error? etc... + else if (!strcmp(type, "error")) { + char text[128]; + + JabberSend(proto, ""); + _snprintf(text, sizeof(text), "%s %s@%s.", TranslateT("Authentication failed for"), proto->threadData->username, proto->threadData->server); + MessageBoxA(NULL, text, Translate("Tlen Authentication"), MB_OK|MB_ICONSTOP|MB_SETFOREGROUND); + ProtoBroadcastAck(proto->m_szModuleName, NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_WRONGPASSWORD); + proto->threadData = NULL; // To disallow auto reconnect + } +} + +void JabberResultSetRoster(TlenProtocol *proto, XmlNode *queryNode) { + DBVARIANT dbv; + XmlNode *itemNode, *groupNode; + JABBER_LIST_ITEM *item; + HANDLE hContact; + char *jid, *name, *nick; + int i; + char *str; + + for (i=0; inumChild; i++) { + itemNode = queryNode->child[i]; + if (!strcmp(itemNode->name, "item")) { + if ((jid=JabberXmlGetAttrValue(itemNode, "jid")) != NULL) { + str = JabberXmlGetAttrValue(itemNode, "subscription"); + if (!strcmp(str, "remove")) { + if ((hContact=JabberHContactFromJID(proto, jid)) != NULL) { + if (DBGetContactSettingWord(hContact, proto->m_szModuleName, "Status", ID_STATUS_OFFLINE) != ID_STATUS_OFFLINE) + DBWriteContactSettingWord(hContact, proto->m_szModuleName, "Status", ID_STATUS_OFFLINE); + } + JabberListRemove(proto, LIST_ROSTER, jid); + } else { + item = JabberListAdd(proto, LIST_ROSTER, jid); + if (item != NULL) { + if (str == NULL) item->subscription = SUB_NONE; + else if (!strcmp(str, "both")) item->subscription = SUB_BOTH; + else if (!strcmp(str, "to")) item->subscription = SUB_TO; + else if (!strcmp(str, "from")) item->subscription = SUB_FROM; + else item->subscription = SUB_NONE; + if ((name=JabberXmlGetAttrValue(itemNode, "name")) != NULL) { + nick = JabberTextDecode(name); + } else { + nick = JabberLocalNickFromJID(jid); + } + if (nick != NULL) { + if (item->nick) mir_free(item->nick); + item->nick = nick; + + if ((hContact=JabberHContactFromJID(proto, jid)) == NULL) { + // Received roster has a new JID. + // Add the jid (with empty resource) to Miranda contact list. + hContact = JabberDBCreateContact(proto, jid, nick, FALSE); + } + DBWriteContactSettingString(hContact, "CList", "MyHandle", nick); + if (item->group) mir_free(item->group); + if ((groupNode=JabberXmlGetChild(itemNode, "group")) != NULL && groupNode->text != NULL) { + item->group = TlenGroupDecode(groupNode->text); + JabberContactListCreateGroup(item->group); + // Don't set group again if already correct, or Miranda may show wrong group count in some case + if (!DBGetContactSetting(hContact, "CList", "Group", &dbv)) { + if (strcmp(dbv.pszVal, item->group)) + DBWriteContactSettingString(hContact, "CList", "Group", item->group); + DBFreeVariant(&dbv); + } else + DBWriteContactSettingString(hContact, "CList", "Group", item->group); + } else { + item->group = NULL; + DBDeleteContactSetting(hContact, "CList", "Group"); + } + } + } + } + } + } + } +} + +void JabberIqResultRoster(TlenProtocol *proto, XmlNode *iqNode) +{ + XmlNode *queryNode; + char *type; + char *str; + + // RECVED: roster information + // ACTION: populate LIST_ROSTER and create contact for any new rosters + if ((type=JabberXmlGetAttrValue(iqNode, "type")) == NULL) return; + if ((queryNode=JabberXmlGetChild(iqNode, "query")) == NULL) return; + + if (!strcmp(type, "result")) { + str = JabberXmlGetAttrValue(queryNode, "xmlns"); + if (str != NULL && !strcmp(str, "jabber:iq:roster")) { + DBVARIANT dbv; + XmlNode *itemNode, *groupNode; + JABBER_SUBSCRIPTION sub; + JABBER_LIST_ITEM *item; + HANDLE hContact; + char *jid, *name, *nick; + int i, oldStatus; + + for (i=0; inumChild; i++) { + itemNode = queryNode->child[i]; + if (!strcmp(itemNode->name, "item")) { + str = JabberXmlGetAttrValue(itemNode, "subscription"); + if (str == NULL) sub = SUB_NONE; + else if (!strcmp(str, "both")) sub = SUB_BOTH; + else if (!strcmp(str, "to")) sub = SUB_TO; + else if (!strcmp(str, "from")) sub = SUB_FROM; + else sub = SUB_NONE; + //if (str != NULL && (!strcmp(str, "to") || !strcmp(str, "both"))) { + if ((jid=JabberXmlGetAttrValue(itemNode, "jid")) != NULL) { + if ((name=JabberXmlGetAttrValue(itemNode, "name")) != NULL) { + nick = JabberTextDecode(name); + } else { + nick = JabberLocalNickFromJID(jid); + } + if (nick != NULL) { + item = JabberListAdd(proto, LIST_ROSTER, jid); + if (item->nick) mir_free(item->nick); + item->nick = nick; + item->subscription = sub; + if ((hContact=JabberHContactFromJID(proto, jid)) == NULL) { + // Received roster has a new JID. + // Add the jid (with empty resource) to Miranda contact list. + hContact = JabberDBCreateContact(proto, jid, nick, FALSE); + } + DBWriteContactSettingString(hContact, "CList", "MyHandle", nick); + if (item->group) mir_free(item->group); + if ((groupNode=JabberXmlGetChild(itemNode, "group")) != NULL && groupNode->text != NULL) { + item->group = TlenGroupDecode(groupNode->text); + JabberContactListCreateGroup(item->group); + // Don't set group again if already correct, or Miranda may show wrong group count in some case + if (!DBGetContactSetting(hContact, "CList", "Group", &dbv)) { + if (strcmp(dbv.pszVal, item->group)) + DBWriteContactSettingString(hContact, "CList", "Group", item->group); + DBFreeVariant(&dbv); + } + else + DBWriteContactSettingString(hContact, "CList", "Group", item->group); + } + else { + item->group = NULL; + DBDeleteContactSetting(hContact, "CList", "Group"); + } + if (!DBGetContactSetting(hContact, proto->m_szModuleName, "AvatarHash", &dbv)) { + if (item->avatarHash) mir_free(item->avatarHash); + item->avatarHash = mir_strdup(dbv.pszVal); + JabberLog(proto, "Setting hash [%s] = %s", nick, item->avatarHash); + DBFreeVariant(&dbv); + } + item->avatarFormat = DBGetContactSettingDword(hContact, proto->m_szModuleName, "AvatarFormat", PA_FORMAT_UNKNOWN); + } + } + } + } + // Delete orphaned contacts (if roster sync is enabled) + if (DBGetContactSettingByte(NULL, proto->m_szModuleName, "RosterSync", FALSE) == TRUE) { + HANDLE *list; + int listSize, listAllocSize; + + listSize = listAllocSize = 0; + list = NULL; + hContact = db_find_first(); + while (hContact != NULL) { + str = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0); + if (str != NULL && !strcmp(str, proto->m_szModuleName)) { + if (!DBGetContactSetting(hContact, proto->m_szModuleName, "jid", &dbv)) { + if (!JabberListExist(proto, LIST_ROSTER, dbv.pszVal)) { + JabberLog(proto, "Syncing roster: preparing to delete %s (hContact=0x%x)", dbv.pszVal, hContact); + if (listSize >= listAllocSize) { + listAllocSize = listSize + 100; + if ((list=(HANDLE *) mir_realloc(list, listAllocSize)) == NULL) { + listSize = 0; + break; + } + } + list[listSize++] = hContact; + } + DBFreeVariant(&dbv); + } + } + hContact = db_find_next(hContact); + } + for (i=0; ihMenuMUC, (LPARAM) &clmi); + if (proto->hMenuChats != NULL){ + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM) proto->hMenuChats, (LPARAM) &clmi); + } + } + + proto->isOnline = TRUE; + JabberLog(proto, "Status changed via THREADSTART"); + oldStatus = proto->m_iStatus; + JabberSendPresence(proto, proto->m_iDesiredStatus); + ProtoBroadcastAck(proto->m_szModuleName, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE) oldStatus, proto->m_iStatus); + ////////////////////////////////// + } + } +} + + +// Tlen actually use jabber:iq:search for other users vCard or jabber:iq:register for own vCard +void TlenIqResultVcard(TlenProtocol *proto, XmlNode *iqNode) +{ + XmlNode *queryNode, *itemNode, *n; + char *type, *jid; + char text[128]; + HANDLE hContact; + char *nText; + +// JabberLog(" iqIdGetVcard (tlen)"); + if ((type=JabberXmlGetAttrValue(iqNode, "type")) == NULL) return; + + if (!strcmp(type, "result")) { + BOOL hasFirst, hasLast, hasNick, hasEmail, hasCity, hasAge, hasGender, hasSchool, hasLookFor, hasOccupation; + DBVARIANT dbv; + int i; + + if ((queryNode=JabberXmlGetChild(iqNode, "query")) == NULL) return; + if ((itemNode=JabberXmlGetChild(queryNode, "item")) == NULL) return; + if ((jid=JabberXmlGetAttrValue(itemNode, "jid")) != NULL) { + if (DBGetContactSetting(NULL, proto->m_szModuleName, "LoginServer", &dbv)) return; + if (strchr(jid, '@') != NULL) { + sprintf(text, "%s", jid); + } else { + sprintf(text, "%s@%s", jid, dbv.pszVal); // Add @tlen.pl + } + DBFreeVariant(&dbv); + if ((hContact=JabberHContactFromJID(proto, text)) == NULL) { + if (DBGetContactSetting(NULL, proto->m_szModuleName, "LoginName", &dbv)) return; + if (strcmp(dbv.pszVal, jid)) { + DBFreeVariant(&dbv); + return; + } + DBFreeVariant(&dbv); + } + } else { + hContact = NULL; + } + hasFirst = hasLast = hasNick = hasEmail = hasCity = hasAge = hasGender = hasOccupation = hasLookFor = hasSchool = FALSE; + for (i=0; inumChild; i++) { + n = itemNode->child[i]; + if (n == NULL || n->name == NULL) continue; + if (!strcmp(n->name, "first")) { + if (n->text != NULL) { + hasFirst = TRUE; + nText = JabberTextDecode(n->text); + DBWriteContactSettingString(hContact, proto->m_szModuleName, "FirstName", nText); + mir_free(nText); + } + } + else if (!strcmp(n->name, "last")) { + if (n->text != NULL) { + hasLast = TRUE; + nText = JabberTextDecode(n->text); + DBWriteContactSettingString(hContact, proto->m_szModuleName, "LastName", nText); + mir_free(nText); + } + } + else if (!strcmp(n->name, "nick")) { + if (n->text != NULL) { + hasNick = TRUE; + nText = JabberTextDecode(n->text); + DBWriteContactSettingString(hContact, proto->m_szModuleName, "Nick", nText); + mir_free(nText); + } + } + else if (!strcmp(n->name, "email")) { + if (n->text != NULL) { + hasEmail = TRUE; + nText = JabberTextDecode(n->text); + DBWriteContactSettingString(hContact, proto->m_szModuleName, "e-mail", nText); + mir_free(nText); + } + } + else if (!strcmp(n->name, "c")) { + if (n->text != NULL) { + hasCity = TRUE; + nText = JabberTextDecode(n->text); + DBWriteContactSettingString(hContact, proto->m_szModuleName, "City", nText); + mir_free(nText); + } + } + else if (!strcmp(n->name, "b")) { + if (n->text != NULL) { + WORD nAge; + hasAge = TRUE; + nAge = atoi(n->text); + DBWriteContactSettingWord(hContact, proto->m_szModuleName, "Age", nAge); + } + } + else if (!strcmp(n->name, "s")) { + if (n->text != NULL && n->text[1] == '\0' && (n->text[0] == '1' || n->text[0] == '2')) { + hasGender = TRUE; + DBWriteContactSettingByte(hContact, proto->m_szModuleName, "Gender", (BYTE) (n->text[0] == '1'?'M':'F')); + } + } + else if (!strcmp(n->name, "e")) { + if (n->text != NULL) { + hasSchool = TRUE; + nText = JabberTextDecode(n->text); + DBWriteContactSettingString(hContact, proto->m_szModuleName, "School", nText); + mir_free(nText); + } + } + else if (!strcmp(n->name, "j")) { + if (n->text != NULL) { + WORD nOccupation; + hasOccupation = TRUE; + nOccupation = atoi(n->text); + DBWriteContactSettingWord(hContact, proto->m_szModuleName, "Occupation", nOccupation); + } + } + else if (!strcmp(n->name, "r")) { + if (n->text != NULL) { + WORD nLookFor; + hasLookFor = TRUE; + nLookFor = atoi(n->text); + DBWriteContactSettingWord(hContact, proto->m_szModuleName, "LookingFor", nLookFor); + } + } + else if (!strcmp(n->name, "g")) { // voice chat enabled + if (n->text != NULL) { + BYTE bVoice; + bVoice = atoi(n->text); + DBWriteContactSettingWord(hContact, proto->m_szModuleName, "VoiceChat", bVoice); + } + } + else if (!strcmp(n->name, "v")) { // status visibility + if (n->text != NULL) { + BYTE bPublic; + bPublic = atoi(n->text); + DBWriteContactSettingWord(hContact, proto->m_szModuleName, "PublicStatus", bPublic); + } + } + } + if (!hasFirst) + DBDeleteContactSetting(hContact, proto->m_szModuleName, "FirstName"); + if (!hasLast) + DBDeleteContactSetting(hContact, proto->m_szModuleName, "LastName"); + // We are not removing "Nick" +// if (!hasNick) +// DBDeleteContactSetting(hContact, m_szModuleName, "Nick"); + if (!hasEmail) + DBDeleteContactSetting(hContact, proto->m_szModuleName, "e-mail"); + if (!hasCity) + DBDeleteContactSetting(hContact, proto->m_szModuleName, "City"); + if (!hasAge) + DBDeleteContactSetting(hContact, proto->m_szModuleName, "Age"); + if (!hasGender) + DBDeleteContactSetting(hContact, proto->m_szModuleName, "Gender"); + if (!hasSchool) + DBDeleteContactSetting(hContact, proto->m_szModuleName, "School"); + if (!hasOccupation) + DBDeleteContactSetting(hContact, proto->m_szModuleName, "Occupation"); + if (!hasLookFor) + DBDeleteContactSetting(hContact, proto->m_szModuleName, "LookingFor"); + ProtoBroadcastAck(proto->m_szModuleName, hContact, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, (HANDLE) 1, 0); + } +} + +void JabberIqResultSearch(TlenProtocol *proto, XmlNode *iqNode) +{ + XmlNode *queryNode, *itemNode, *n; + char *type, *jid, *str; + int id, i, found; + JABBER_SEARCH_RESULT jsr = {0}; + DBVARIANT dbv = {0}; + + found = 0; +// JabberLog(" iqIdGetSearch"); + if ((type=JabberXmlGetAttrValue(iqNode, "type")) == NULL) return; + if ((str=JabberXmlGetAttrValue(iqNode, "id")) == NULL) return; + id = atoi(str+strlen(JABBER_IQID)); + + if (!strcmp(type, "result")) { + if ((queryNode=JabberXmlGetChild(iqNode, "query")) == NULL) return; + if (!DBGetContactSetting(NULL, proto->m_szModuleName, "LoginServer", &dbv)) { + jsr.hdr.cbSize = sizeof(JABBER_SEARCH_RESULT); + jsr.hdr.flags = PSR_TCHAR; + for (i=0; inumChild; i++) { + itemNode = queryNode->child[i]; + if (!strcmp(itemNode->name, "item")) { + if ((jid=JabberXmlGetAttrValue(itemNode, "jid")) != NULL) { + if (strchr(jid, '@') != NULL) { + _snprintf(jsr.jid, sizeof(jsr.jid), "%s", jid); + } else { + _snprintf(jsr.jid, sizeof(jsr.jid), "%s@%s", jid, dbv.pszVal); + } + jsr.jid[sizeof(jsr.jid)-1] = '\0'; + jsr.hdr.id = mir_a2t(jid); + if ((n=JabberXmlGetChild(itemNode, "nick")) != NULL && n->text != NULL){ + char* buf = JabberTextDecode(n->text); + jsr.hdr.nick = mir_a2t(buf); + mir_free(buf); + } else { + jsr.hdr.nick = mir_tstrdup(TEXT("")); + } + if ((n=JabberXmlGetChild(itemNode, "first")) != NULL && n->text != NULL){ + char* buf = JabberTextDecode(n->text); + jsr.hdr.firstName = mir_a2t(buf); + mir_free(buf); + } else { + jsr.hdr.firstName = mir_tstrdup(TEXT("")); + } + if ((n=JabberXmlGetChild(itemNode, "last")) != NULL && n->text != NULL){ + char* buf = JabberTextDecode(n->text); + jsr.hdr.lastName = mir_a2t(buf); + mir_free(buf); + } else { + jsr.hdr.lastName = mir_tstrdup(TEXT("")); + } + if ((n=JabberXmlGetChild(itemNode, "email"))!=NULL && n->text!=NULL){ + char* buf = JabberTextDecode(n->text); + jsr.hdr.email = mir_a2t(buf); + mir_free(buf); + } else { + jsr.hdr.email = mir_tstrdup(TEXT("")); + } + + ProtoBroadcastAck(proto->m_szModuleName, NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE) id, (LPARAM) &jsr); + found = 1; + mir_free(jsr.hdr.id); + mir_free(jsr.hdr.nick); + mir_free(jsr.hdr.firstName); + mir_free(jsr.hdr.lastName); + mir_free(jsr.hdr.email); + } + } + } + if (proto->searchJID != NULL) { + if (!found) { + if (strchr(proto->searchJID, '@') != NULL) { + _snprintf(jsr.jid, sizeof(jsr.jid), "%s", proto->searchJID); + } else { + _snprintf(jsr.jid, sizeof(jsr.jid), "%s@%s", proto->searchJID, dbv.pszVal); + } + jsr.jid[sizeof(jsr.jid)-1] = '\0'; + jsr.hdr.nick = mir_tstrdup(TEXT("")); + jsr.hdr.firstName = mir_tstrdup(TEXT("")); + jsr.hdr.lastName = mir_tstrdup(TEXT("")); + jsr.hdr.email = mir_tstrdup(TEXT("")); + jsr.hdr.id = mir_tstrdup(TEXT("")); + ProtoBroadcastAck(proto->m_szModuleName, NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE) id, (LPARAM) &jsr); + mir_free(jsr.hdr.nick); + mir_free(jsr.hdr.firstName); + mir_free(jsr.hdr.lastName); + mir_free(jsr.hdr.email); + } + mir_free(proto->searchJID); + proto->searchJID = NULL; + } + DBFreeVariant(&dbv); + } + found = 0; + if (queryNode->numChild == TLEN_MAX_SEARCH_RESULTS_PER_PAGE) { + found = TlenRunSearch(proto); + } + if (!found) { + ProtoBroadcastAck(proto->m_szModuleName, NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE) id, 0); + } + } else if (!strcmp(type, "error")) { + // ProtoBroadcastAck(proto->m_szModuleName, NULL, ACKTYPE_SEARCH, ACKRESULT_FAILED, (HANDLE) id, 0); + // There is no ACKRESULT_FAILED for ACKTYPE_SEARCH :) look at findadd.c + // So we will just send a SUCCESS + ProtoBroadcastAck(proto->m_szModuleName, NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE) id, 0); + } +} + + +void GetConfigItem(XmlNode *node, char *dest, BOOL bMethod, int *methodDest) { + strcpy(dest, node->text); + TlenUrlDecode(dest); + if (bMethod) { + char *method = JabberXmlGetAttrValue(node, "method"); + if (method != NULL && !strcmpi(method, "POST")) { + *methodDest = REQUEST_POST; + } else { + *methodDest = REQUEST_GET; + } + } +} + +void TlenIqResultTcfg(TlenProtocol *proto, XmlNode *iqNode) +{ + XmlNode *queryNode, *miniMailNode, *node; + char *type; + + if ((type=JabberXmlGetAttrValue(iqNode, "type")) == NULL) return; + if (!strcmp(type, "result")) { + if ((queryNode=JabberXmlGetChild(iqNode, "query")) == NULL) return; + if ((miniMailNode=JabberXmlGetChild(queryNode, "mini-mail")) == NULL) return; + if ((node=JabberXmlGetChild(miniMailNode, "base")) != NULL) { + GetConfigItem(node, proto->threadData->tlenConfig.mailBase, FALSE, NULL); + } + if ((node=JabberXmlGetChild(miniMailNode, "msg")) != NULL) { + GetConfigItem(node, proto->threadData->tlenConfig.mailMsg, TRUE, &proto->threadData->tlenConfig.mailMsgMthd); + } + if ((node=JabberXmlGetChild(miniMailNode, "index")) != NULL) { + GetConfigItem(node, proto->threadData->tlenConfig.mailIndex, TRUE, &proto->threadData->tlenConfig.mailIndexMthd); + } + if ((node=JabberXmlGetChild(miniMailNode, "login")) != NULL) { + GetConfigItem(node, proto->threadData->tlenConfig.mailLogin, TRUE, &proto->threadData->tlenConfig.mailLoginMthd); + } + if ((node=JabberXmlGetChild(miniMailNode, "compose")) != NULL) { + GetConfigItem(node, proto->threadData->tlenConfig.mailCompose, TRUE, &proto->threadData->tlenConfig.mailComposeMthd); + } + if ((node=JabberXmlGetChild(miniMailNode, "avatar-get")) != NULL) { + GetConfigItem(node, proto->threadData->tlenConfig.avatarGet, TRUE, &proto->threadData->tlenConfig.avatarGetMthd); + } + if ((node=JabberXmlGetChild(miniMailNode, "avatar-upload")) != NULL) { + GetConfigItem(node, proto->threadData->tlenConfig.avatarUpload, TRUE, &proto->threadData->tlenConfig.avatarUploadMthd); + } + if ((node=JabberXmlGetChild(miniMailNode, "avatar-remove")) != NULL) { + GetConfigItem(node, proto->threadData->tlenConfig.avatarRemove, TRUE, &proto->threadData->tlenConfig.avatarRemoveMthd); + } + } +} + +void TlenIqResultVersion(TlenProtocol *proto, XmlNode *iqNode) +{ + XmlNode *queryNode = JabberXmlGetChild(iqNode, "query"); + if (queryNode != NULL) { + char* from; + if (( from=JabberXmlGetAttrValue( iqNode, "from" )) != NULL ) { + JABBER_LIST_ITEM *item; + if (( item=JabberListGetItemPtr( proto, LIST_ROSTER, from )) != NULL) { + HANDLE hContact; + XmlNode *n; + if ( item->software ) mir_free( item->software ); + if ( item->version ) mir_free( item->version ); + if ( item->system ) mir_free( item->system ); + if (( n=JabberXmlGetChild( queryNode, "name" )) != NULL && n->text ) { + item->software = JabberTextDecode( n->text ); + } else + item->software = NULL; + if (( n=JabberXmlGetChild( queryNode, "version" )) != NULL && n->text ) + item->version = JabberTextDecode( n->text ); + else + item->version = NULL; + if (( n=JabberXmlGetChild( queryNode, "os" )) != NULL && n->text ) + item->system = JabberTextDecode( n->text ); + else + item->system = NULL; + if (( hContact=JabberHContactFromJID(proto, item->jid )) != NULL ) { + if (item->software != NULL) { + DBWriteContactSettingString(hContact, proto->m_szModuleName, "MirVer", item->software); + } else { + DBDeleteContactSetting(hContact, proto->m_szModuleName, "MirVer"); + } + } + } + } + } +} + +void TlenIqResultInfo(TlenProtocol *proto, XmlNode *iqNode) +{ + XmlNode *queryNode = JabberXmlGetChild(iqNode, "query"); + if (queryNode != NULL) { + char* from; + if (( from=JabberXmlGetAttrValue( queryNode, "from" )) != NULL ) { + JABBER_LIST_ITEM *item; + if (( item=JabberListGetItemPtr( proto, LIST_ROSTER, from )) != NULL) { + HANDLE hContact; + XmlNode *version = JabberXmlGetChild(queryNode, "version"); + item->protocolVersion = JabberTextDecode(version->text); + if (( hContact=JabberHContactFromJID(proto, item->jid )) != NULL ) { + if (item->software == NULL) { + char str[128]; + mir_snprintf(str, sizeof(str), "Tlen Protocol %s", item->protocolVersion); + DBWriteContactSettingString(hContact, proto->m_szModuleName, "MirVer", str); + } + } + } + } + } +} + diff --git a/protocols/Tlen/src/jabber_list.cpp b/protocols/Tlen/src/jabber_list.cpp new file mode 100644 index 0000000000..de9fe21c78 --- /dev/null +++ b/protocols/Tlen/src/jabber_list.cpp @@ -0,0 +1,315 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Tlen Protocol Plugin for Miranda NG +Copyright (C) 2002-2004 Santithorn Bunchua +Copyright (C) 2004-2007 Piotr Piastucki + +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_list.h" + + +static void JabberListFreeItemInternal(JABBER_LIST_ITEM *item); + +void JabberListInit(TlenProtocol *proto) +{ + proto->lists = NULL; + proto->listsCount = 0; + InitializeCriticalSection(&proto->csLists); +} + +void JabberListUninit(TlenProtocol *proto) +{ + JabberListWipe(proto); + DeleteCriticalSection(&proto->csLists); +} + +void JabberListWipe(TlenProtocol *proto) +{ + int i; + + EnterCriticalSection(&proto->csLists); + for (i=0; ilistsCount; i++) + JabberListFreeItemInternal(&(proto->lists[i])); + if (proto->lists != NULL) { + mir_free(proto->lists); + proto->lists = NULL; + } + proto->listsCount=0; + LeaveCriticalSection(&proto->csLists); +} + +void JabberListWipeSpecial(TlenProtocol *proto) +{ + int i; + EnterCriticalSection(&proto->csLists); + for (i=0; ilistsCount; i++) { + if (proto->lists[i].list != LIST_FILE && proto->lists[i].list != LIST_VOICE) { + JabberListFreeItemInternal(&(proto->lists[i])); + proto->listsCount--; + memmove(proto->lists+i, proto->lists+i+1, sizeof(JABBER_LIST_ITEM)*(proto->listsCount-i)); + i--; + } + } + proto->lists = (JABBER_LIST_ITEM *) mir_realloc(proto->lists, sizeof(JABBER_LIST_ITEM)*proto->listsCount); + LeaveCriticalSection(&proto->csLists); +} + +static void JabberListFreeItemInternal(JABBER_LIST_ITEM *item) +{ + if (item == NULL) + return; + + if (item->jid) mir_free(item->jid); + if (item->nick) mir_free(item->nick); + if (item->statusMessage) mir_free(item->statusMessage); + if (item->group) mir_free(item->group); + if (item->messageEventIdStr) mir_free(item->messageEventIdStr); +// if (item->type) mir_free(item->type); + //if (item->ft) JabberFileFreeFt(item->ft); // No need to free (it is always free when exit from JabberFileServerThread()) + if (item->roomName) mir_free(item->roomName); + if (item->version) mir_free(item->version); + if (item->software) mir_free(item->software); + if (item->system) mir_free(item->system); + if (item->avatarHash) mir_free(item->avatarHash); + + if (item->protocolVersion) mir_free(item->protocolVersion); + if (item->id2) mir_free(item->id2); +} + +static char * GetItemId(JABBER_LIST list, const char *jid) +{ + char *s, *p, *q; + s = mir_strdup(jid); + if (list != LIST_PICTURE) { + _strlwr(s); + // strip resouce name if any + if ((p=strchr(s, '@')) != NULL) { + if ((q=strchr(p, '/')) != NULL) + *q = '\0'; + } + } + return s; +} + + +int JabberListExist(TlenProtocol *proto, JABBER_LIST list, const char *jid) +{ + int i; + size_t len; + char *s, *p; + s = GetItemId(list, jid); + len = strlen(s); + + EnterCriticalSection(&proto->csLists); + for (i=0; ilistsCount; i++) + if (proto->lists[i].list == list) { + p = proto->lists[i].jid; + if (p && strlen(p) >= len && (p[(int)len] == '\0' || p[(int)len] == '/') && !strncmp(p, s, len)) { + LeaveCriticalSection(&proto->csLists); + mir_free(s); + return i+1; + } + } + LeaveCriticalSection(&proto->csLists); + mir_free(s); + return 0; +} + +JABBER_LIST_ITEM *JabberListAdd(TlenProtocol *proto, JABBER_LIST list, const char *jid) +{ + char *s; + JABBER_LIST_ITEM *item; + + EnterCriticalSection(&proto->csLists); + if ((item=JabberListGetItemPtr(proto, list, jid)) != NULL) { + LeaveCriticalSection(&proto->csLists); + return item; + } + + s = GetItemId(list, jid); + proto->lists = (JABBER_LIST_ITEM *) mir_realloc(proto->lists, sizeof(JABBER_LIST_ITEM)*(proto->listsCount+1)); + item = &(proto->lists[proto->listsCount]); + memset(item, 0, sizeof(JABBER_LIST_ITEM)); + item->list = list; + item->jid = s; + item->nick = NULL; + item->status = ID_STATUS_OFFLINE; + item->statusMessage = NULL; + item->group = NULL; + item->messageEventIdStr = NULL; + item->wantComposingEvent = FALSE; + item->isTyping = FALSE; +// item->type = NULL; + item->ft = NULL; + item->roomName = NULL; + item->version = NULL; + item->software = NULL; + item->system = NULL; + item->avatarHash = NULL; + item->avatarFormat = PA_FORMAT_UNKNOWN; + item->newAvatarDownloading = FALSE; + item->versionRequested = FALSE; + item->infoRequested = FALSE; + proto->listsCount++; + LeaveCriticalSection(&proto->csLists); + + return item; +} + +void JabberListRemove(TlenProtocol *proto, JABBER_LIST list, const char *jid) +{ + int i; + + EnterCriticalSection(&proto->csLists); + i = JabberListExist(proto, list, jid); + if (!i) { + LeaveCriticalSection(&proto->csLists); + return; + } + i--; + JabberListFreeItemInternal(&(proto->lists[i])); + proto->listsCount--; + memmove(proto->lists+i, proto->lists+i+1, sizeof(JABBER_LIST_ITEM)*(proto->listsCount-i)); + proto->lists = (JABBER_LIST_ITEM *) mir_realloc(proto->lists, sizeof(JABBER_LIST_ITEM)*proto->listsCount); + LeaveCriticalSection(&proto->csLists); +} + +void JabberListRemoveList(TlenProtocol *proto, JABBER_LIST list) +{ + int i; + + i = 0; + while ((i=JabberListFindNext(proto, list, i)) >= 0) { + JabberListRemoveByIndex(proto, i); + } +} + +void JabberListRemoveByIndex(TlenProtocol *proto, int index) +{ + EnterCriticalSection(&proto->csLists); + if (index >= 0 && indexlistsCount) { + JabberListFreeItemInternal(&(proto->lists[index])); + proto->listsCount--; + memmove(proto->lists+index, proto->lists+index+1, sizeof(JABBER_LIST_ITEM)*(proto->listsCount-index)); + proto->lists = (JABBER_LIST_ITEM *) mir_realloc(proto->lists, sizeof(JABBER_LIST_ITEM)*proto->listsCount); + } + LeaveCriticalSection(&proto->csLists); +} + +void JabberListAddResource(TlenProtocol *proto, JABBER_LIST list, const char *jid, int status, const char *statusMessage) +{ + int i; + + EnterCriticalSection(&proto->csLists); + i = JabberListExist(proto, list, jid); + if (!i) { + LeaveCriticalSection(&proto->csLists); + return; + } + i--; + + if (proto->lists[i].statusMessage != NULL) + mir_free(proto->lists[i].statusMessage); + if (statusMessage) + proto->lists[i].statusMessage = mir_strdup(statusMessage); + else + proto->lists[i].statusMessage = NULL; + LeaveCriticalSection(&proto->csLists); +} + +void JabberListRemoveResource(TlenProtocol *proto, JABBER_LIST list, const char *jid) +{ + int i; + EnterCriticalSection(&proto->csLists); + i = JabberListExist(proto, list, jid); + if (!i) { + LeaveCriticalSection(&proto->csLists); + return; + } + i--; + LeaveCriticalSection(&proto->csLists); +} + +int JabberListFindNext(TlenProtocol *proto, JABBER_LIST list, int fromOffset) +{ + int i; + + EnterCriticalSection(&proto->csLists); + i = (fromOffset >= 0) ? fromOffset : 0; + for (; ilistsCount; i++) + if (proto->lists[i].list == list) { + LeaveCriticalSection(&proto->csLists); + return i; + } + LeaveCriticalSection(&proto->csLists); + return -1; +} + +JABBER_LIST_ITEM *JabberListGetItemPtr(TlenProtocol *proto, JABBER_LIST list, const char *jid) +{ + int i; + + EnterCriticalSection(&proto->csLists); + i = JabberListExist(proto, list, jid); + if (!i) { + LeaveCriticalSection(&proto->csLists); + return NULL; + } + i--; + LeaveCriticalSection(&proto->csLists); + return &(proto->lists[i]); +} + +JABBER_LIST_ITEM *JabberListFindItemPtrById2(TlenProtocol *proto, JABBER_LIST list, const char *id) +{ + + int i; + size_t len; + char *p; + + len = strlen(id); + + EnterCriticalSection(&proto->csLists); + for (i=0; ilistsCount; i++) { + if (proto->lists[i].list == list) { + p = proto->lists[i].id2; + if (p != NULL) { + if (!strncmp(p, id, len)) { + LeaveCriticalSection(&proto->csLists); + return &(proto->lists[i]); + } + } + } + } + LeaveCriticalSection(&proto->csLists); + return NULL; +} + +JABBER_LIST_ITEM *JabberListGetItemPtrFromIndex(TlenProtocol *proto, int index) +{ + EnterCriticalSection(&proto->csLists); + if (index >= 0 && indexlistsCount) { + LeaveCriticalSection(&proto->csLists); + return &(proto->lists[index]); + } + LeaveCriticalSection(&proto->csLists); + return NULL; +} + diff --git a/protocols/Tlen/src/jabber_list.h b/protocols/Tlen/src/jabber_list.h new file mode 100644 index 0000000000..30eb1abbdb --- /dev/null +++ b/protocols/Tlen/src/jabber_list.h @@ -0,0 +1,90 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Tlen Protocol Plugin for Miranda NG +Copyright (C) 2002-2004 Santithorn Bunchua +Copyright (C) 2004-2007 Piotr Piastucki + +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" + +#ifndef _JABBER_LIST_H_ +#define _JABBER_LIST_H_ + +typedef struct JABBER_LIST_ITEM_STRUCT { + JABBER_LIST list; + char *jid; + char *id2; + + // LIST_ROSTER + // jid = jid of the contact + char *nick; + int status; // Main status, currently useful for transport where no resource information is kept. + // On normal contact, this is the same status as shown on contact list. + JABBER_SUBSCRIPTION subscription; + char *statusMessage; // Status message when the update is to JID with no resource specified (e.g. transport user) + char *software; + char *version; + char *system; + char *group; + char *protocolVersion; + int avatarFormat; + char *avatarHash; + BOOL newAvatarDownloading; + BOOL versionRequested; + BOOL infoRequested; + int idMsgAckPending; + char *messageEventIdStr; + BOOL wantComposingEvent; + BOOL isTyping; + + // LIST_ROOM + // jid = room JID + // char *name; // room name + //char *type; // room type + + // LIST_CHATROOM + // jid = room JID + // char *nick; // my nick in this chat room (SPECIAL: in UTF8) + // JABBER_RESOURCE_STATUS *resource; // participant nicks in this room + char *roomName; + + // LIST_FILE + struct TLEN_FILE_TRANSFER_STRUCT *ft; +} JABBER_LIST_ITEM; + + +void JabberListInit(TlenProtocol *proto); +void JabberListUninit(TlenProtocol *proto); +void JabberListWipe(TlenProtocol *proto); +void JabberListWipeSpecial(TlenProtocol *proto); +int JabberListExist(TlenProtocol *proto, JABBER_LIST list, const char *jid); +JABBER_LIST_ITEM *JabberListAdd(TlenProtocol *proto, JABBER_LIST list, const char *jid); +void JabberListRemove(TlenProtocol *proto, JABBER_LIST list, const char *jid); +void JabberListRemoveList(TlenProtocol *proto, JABBER_LIST list); +void JabberListRemoveByIndex(TlenProtocol *proto, int index); +int JabberListFindNext(TlenProtocol *proto, JABBER_LIST list, int fromOffset); +JABBER_LIST_ITEM *JabberListGetItemPtr(TlenProtocol *proto, JABBER_LIST list, const char *jid); +JABBER_LIST_ITEM *JabberListGetItemPtrFromIndex(TlenProtocol *proto, int index); +JABBER_LIST_ITEM *JabberListFindItemPtrById2(TlenProtocol *proto, JABBER_LIST list, const char *id); + +void JabberListAddResource(TlenProtocol *proto, JABBER_LIST list, const char *jid, int status, const char *statusMessage); +void JabberListRemoveResource(TlenProtocol *proto, JABBER_LIST list, const char *jid); + +#endif + diff --git a/protocols/Tlen/src/jabber_misc.cpp b/protocols/Tlen/src/jabber_misc.cpp new file mode 100644 index 0000000000..c9db7eed21 --- /dev/null +++ b/protocols/Tlen/src/jabber_misc.cpp @@ -0,0 +1,218 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Tlen Protocol Plugin for Miranda NG +Copyright (C) 2002-2004 Santithorn Bunchua +Copyright (C) 2004-2007 Piotr Piastucki + +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_list.h" + +void JabberDBAddEvent(TlenProtocol *proto, HANDLE hContact, int eventType, DWORD flags, PBYTE pBlob, DWORD cbBlob) +{ + DBEVENTINFO dbei = {0}; + dbei.cbSize = sizeof(DBEVENTINFO); + dbei.szModule = proto->m_szModuleName; + dbei.timestamp = (DWORD) time(NULL); + dbei.flags = flags; + dbei.eventType = eventType; + dbei.cbBlob = cbBlob; + dbei.pBlob = pBlob; + CallService(MS_DB_EVENT_ADD, (WPARAM) hContact, (LPARAM) &dbei); +} +void JabberDBAddAuthRequest(TlenProtocol *proto, char *jid, char *nick) +{ + char *s; + PBYTE pCurBlob; + PBYTE pBlob; + DWORD cbBlob; + HANDLE hContact; + + if ((hContact=JabberHContactFromJID(proto, jid)) == NULL) { + hContact = (HANDLE) CallService(MS_DB_CONTACT_ADD, 0, 0); + CallService(MS_PROTO_ADDTOCONTACT, (WPARAM) hContact, (LPARAM) proto->m_szModuleName); + // strip resource if present + s = JabberLoginFromJID(jid); + _strlwr(s); + DBWriteContactSettingString(hContact, proto->m_szModuleName, "jid", s); + mir_free(s); + } + else { + DBDeleteContactSetting(hContact, proto->m_szModuleName, "Hidden"); + } + DBWriteContactSettingString(hContact, proto->m_szModuleName, "Nick", nick); + JabberLog(proto, "auth request: %s, %s", jid, nick); + //blob is: uin(DWORD), hContact(HANDLE), nick(ASCIIZ), first(ASCIIZ), last(ASCIIZ), email(ASCIIZ), reason(ASCIIZ) + //blob is: 0(DWORD), hContact(HANDLE), nick(ASCIIZ), ""(ASCIIZ), ""(ASCIIZ), email(ASCIIZ), ""(ASCIIZ) + cbBlob = sizeof(DWORD) + sizeof(HANDLE) + (int)strlen(nick) + (int)strlen(jid) + 5; + pBlob = pCurBlob = (PBYTE) mir_alloc(cbBlob); + *((PDWORD)pCurBlob) = 0; pCurBlob += sizeof(DWORD); + *((PHANDLE)pCurBlob) = hContact; pCurBlob += sizeof(DWORD); + strcpy((char *) pCurBlob, nick); pCurBlob += strlen(nick)+1; + *pCurBlob = '\0'; pCurBlob++; //firstName + *pCurBlob = '\0'; pCurBlob++; //lastName + strcpy((char *) pCurBlob, jid); pCurBlob += strlen(jid)+1; + *pCurBlob = '\0'; //reason + JabberDBAddEvent(proto, NULL, EVENTTYPE_AUTHREQUEST, 0, pBlob, cbBlob); +} + +char *JabberJIDFromHContact(TlenProtocol *proto, HANDLE hContact) +{ + char *p = NULL; + DBVARIANT dbv; + if (!DBGetContactSetting(hContact, proto->m_szModuleName, "jid", &dbv)) { + p = mir_strdup(dbv.pszVal); + DBFreeVariant(&dbv); + } + return p; +} + +HANDLE JabberHContactFromJID(TlenProtocol *proto, const char *jid) +{ + HANDLE hContact, hContactMatched; + DBVARIANT dbv; + char *szProto; + char *p; + if (jid == NULL) return (HANDLE) NULL; + hContactMatched = NULL; + hContact = db_find_first(); + while (hContact != NULL) { + szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0); + if (szProto != NULL && !strcmp(proto->m_szModuleName, szProto)) { + if (!DBGetContactSetting(hContact, proto->m_szModuleName, "jid", &dbv)) { + if ((p=dbv.pszVal) != NULL) { + if (!stricmp(p, jid)) { // exact match (node@domain/resource) + hContactMatched = hContact; + DBFreeVariant(&dbv); + break; + } + } + DBFreeVariant(&dbv); + } + } + hContact = db_find_next(hContact); + } + if (hContactMatched != NULL) { + return hContactMatched; + } + return NULL; +} + +HANDLE JabberDBCreateContact(TlenProtocol *proto, char *jid, char *nick, BOOL temporary) +{ + HANDLE hContact; + if (jid == NULL || jid[0] == '\0') + return NULL; + + if ((hContact=JabberHContactFromJID(proto, jid)) == NULL) { + hContact = (HANDLE) CallService(MS_DB_CONTACT_ADD, 0, 0); + CallService(MS_PROTO_ADDTOCONTACT, (WPARAM) hContact, (LPARAM) proto->m_szModuleName); + DBWriteContactSettingString(hContact, proto->m_szModuleName, "jid", jid); + if (nick != NULL && nick[0] != '\0') + DBWriteContactSettingString(hContact, proto->m_szModuleName, "Nick", nick); + if (temporary) + DBWriteContactSettingByte(hContact, "CList", "NotOnList", 1); + } + return hContact; +} + +static void JabberContactListCreateClistGroup(char *groupName) +{ + char str[33], newName[128]; + int i; + DBVARIANT dbv; + char *name; + + for (i=0;;i++) { + itoa(i, str, 10); + if (DBGetContactSetting(NULL, "CListGroups", str, &dbv)) + break; + name = dbv.pszVal; + if (name[0] != '\0' && !strcmp(name+1, groupName)) { + // Already exist, no need to create + DBFreeVariant(&dbv); + return; + } + DBFreeVariant(&dbv); + } + + // Create new group with id = i (str is the text representation of i) + newName[0] = 1 | GROUPF_EXPANDED; + strncpy(newName+1, groupName, sizeof(newName)-1); + newName[sizeof(newName)-1] = '\0'; + DBWriteContactSettingString(NULL, "CListGroups", str, newName); + CallService(MS_CLUI_GROUPADDED, i+1, 0); +} + +void JabberContactListCreateGroup(char *groupName) +{ + char name[128]; + char *p; + + if (groupName == NULL || groupName[0] == '\0' || groupName[0] == '\\') return; + + strncpy(name, groupName, sizeof(name)); + name[sizeof(name)-1] = '\0'; + for (p=name; *p != '\0'; p++) { + if (*p == '\\') { + *p = '\0'; + JabberContactListCreateClistGroup(name); + *p = '\\'; + } + } + JabberContactListCreateClistGroup(name); +} + + +struct FORK_ARG { + HANDLE hEvent; + void (__cdecl *threadcode)(void*); + void *arg; +}; + +static void __cdecl forkthread_r(struct FORK_ARG *fa) +{ + void (*callercode)(void*) = fa->threadcode; + void *arg = fa->arg; + Thread_Push(0); + SetEvent(fa->hEvent); + callercode(arg); + Thread_Pop(); + return; +} + +unsigned long JabberForkThread( + void (__cdecl *threadcode)(void*), + unsigned long stacksize, + void *arg +) +{ + unsigned long rc; + struct FORK_ARG fa; + + fa.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + fa.threadcode = threadcode; + fa.arg = arg; + rc = _beginthread((void (__cdecl *)(void*))forkthread_r, stacksize, &fa); + if ((unsigned long) -1L != rc) { + WaitForSingleObject(fa.hEvent, INFINITE); + } + CloseHandle(fa.hEvent); + return rc; +} diff --git a/protocols/Tlen/src/jabber_opt.cpp b/protocols/Tlen/src/jabber_opt.cpp new file mode 100644 index 0000000000..297ac34cae --- /dev/null +++ b/protocols/Tlen/src/jabber_opt.cpp @@ -0,0 +1,710 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Tlen Protocol Plugin for Miranda NG +Copyright (C) 2002-2004 Santithorn Bunchua +Copyright (C) 2004-2007 Piotr Piastucki + +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_list.h" +#include "tlen_voice.h" +#include +#include "resource.h" + +static INT_PTR CALLBACK TlenBasicOptDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); +static INT_PTR CALLBACK TlenVoiceOptDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); +static INT_PTR CALLBACK TlenAdvOptDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); +static INT_PTR CALLBACK TlenPopupsDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); + +typedef struct TabDefStruct { + DLGPROC dlgProc; + DWORD dlgId; + TCHAR *tabName; +} TabDef; + +static TabDef tabPages[] = { + {TlenBasicOptDlgProc, IDD_OPTIONS_BASIC, LPGENT("General")}, + {TlenVoiceOptDlgProc, IDD_OPTIONS_VOICE, LPGENT("Voice Chats")}, + {TlenAdvOptDlgProc, IDD_OPTIONS_ADVANCED, LPGENT("Advanced")}, + {TlenPopupsDlgProc, IDD_OPTIONS_POPUPS, LPGENT("Notifications")} + }; + +void TlenLoadOptions(TlenProtocol *proto) +{ + proto->tlenOptions.savePassword = DBGetContactSettingByte(NULL, proto->m_szModuleName, "SavePassword", TRUE); + proto->tlenOptions.useEncryption = DBGetContactSettingByte(NULL, proto->m_szModuleName, "UseEncryption", TRUE); + proto->tlenOptions.reconnect = DBGetContactSettingByte(NULL, proto->m_szModuleName, "Reconnect", TRUE); + proto->tlenOptions.alertPolicy = DBGetContactSettingWord(NULL, proto->m_szModuleName, "AlertPolicy", TLEN_ALERTS_IGNORE_NIR); + proto->tlenOptions.rosterSync = DBGetContactSettingByte(NULL, proto->m_szModuleName, "RosterSync", FALSE); + proto->tlenOptions.offlineAsInvisible = DBGetContactSettingByte(NULL, proto->m_szModuleName, "OfflineAsInvisible", FALSE); + proto->tlenOptions.leaveOfflineMessage = DBGetContactSettingByte(NULL, proto->m_szModuleName, "LeaveOfflineMessage", TRUE); + proto->tlenOptions.offlineMessageOption = DBGetContactSettingWord(NULL, proto->m_szModuleName, "OfflineMessageOption", 0); + proto->tlenOptions.ignoreAdvertisements = DBGetContactSettingByte(NULL, proto->m_szModuleName, "IgnoreAdvertisements", TRUE); + proto->tlenOptions.groupChatPolicy = DBGetContactSettingWord(NULL, proto->m_szModuleName, "GroupChatPolicy", TLEN_MUC_ASK); + proto->tlenOptions.voiceChatPolicy = DBGetContactSettingWord(NULL, proto->m_szModuleName, "VoiceChatPolicy", TLEN_MUC_ASK); + proto->tlenOptions.imagePolicy = DBGetContactSettingWord(NULL, proto->m_szModuleName, "ImagePolicy",TLEN_IMAGES_IGNORE_NIR); + proto->tlenOptions.enableAvatars = DBGetContactSettingByte(NULL, proto->m_szModuleName, "EnableAvatars", TRUE); + proto->tlenOptions.enableVersion = DBGetContactSettingByte(NULL, proto->m_szModuleName, "EnableVersion", TRUE); + proto->tlenOptions.useNudge = DBGetContactSettingByte(NULL, proto->m_szModuleName, "UseNudge", FALSE); + proto->tlenOptions.logAlerts = DBGetContactSettingByte(NULL, proto->m_szModuleName, "LogAlerts", TRUE); + proto->tlenOptions.sendKeepAlive = DBGetContactSettingByte(NULL, proto->m_szModuleName, "KeepAlive", TRUE); + proto->tlenOptions.useNewP2P = TRUE; +} + +static int changed = 0; + +static void ApplyChanges(TlenProtocol *proto, int i) { + changed &= ~i; + if (changed == 0) { + TlenLoadOptions(proto); + } +} + +static void MarkChanges(int i, HWND hWnd) { + SendMessage(GetParent(hWnd), PSM_CHANGED, 0, 0); + changed |= i; +} + + +int TlenOptionsInit(void *ptr, WPARAM wParam, LPARAM lParam) +{ + int i; + TlenProtocol *proto = (TlenProtocol *)ptr; + + OPTIONSDIALOGPAGE odp = { 0 }; + odp.cbSize = sizeof(odp); + odp.hInstance = hInst; + odp.ptszGroup = LPGENT("Network"); + odp.ptszTitle = proto->m_tszUserName; + odp.flags = ODPF_BOLDGROUPS | ODPF_TCHAR; + odp.dwInitParam = (LPARAM)proto; + for (i = 0; i < SIZEOF(tabPages); i++) { + odp.pszTemplate = MAKEINTRESOURCEA(tabPages[i].dlgId); + odp.pfnDlgProc = tabPages[i].dlgProc; + odp.ptszTab = tabPages[i].tabName; + Options_AddPage(wParam, &odp); + } +/* + if (ServiceExists(MS_POPUP_ADDPOPUP)) { + ZeroMemory(&odp,sizeof(odp)); + odp.cbSize = sizeof(odp); + odp.position = 100000000; + odp.hInstance = hInst; + odp.flags = ODPF_BOLDGROUPS | ODPF_TCHAR; + odp.ptszGroup = TranslateT("PopUps"); + odp.ptszTitle = proto->m_tszUserName; + odp.dwInitParam = (LPARAM)proto; + odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPTIONS_POPUPS); + odp.pfnDlgProc = TlenPopupsDlgProc; + Options_AddPage(wParam, &odp); + } +*/ + return 0; +} + +static LRESULT CALLBACK JabberValidateUsernameWndProc(HWND hwndEdit, UINT msg, WPARAM wParam, LPARAM lParam) +{ + WNDPROC oldProc = (WNDPROC) GetWindowLongPtr(hwndEdit, GWLP_USERDATA); + + switch (msg) { + case WM_CHAR: + if (strchr("\"&'/:<>@", wParam&0xff) != NULL) + return 0; + break; + } + return CallWindowProc(oldProc, hwndEdit, msg, wParam, lParam); +} + +INT_PTR CALLBACK TlenAccMgrUIDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + char text[256]; + WNDPROC oldProc; + + TlenProtocol *proto = (TlenProtocol *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + switch (msg) { + case WM_INITDIALOG: + { + DBVARIANT dbv; + proto = (TlenProtocol *)lParam; + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)proto); + TranslateDialogDefault(hwndDlg); + if (!DBGetContactSettingTString(NULL, proto->m_szModuleName, "LoginName", &dbv)) { + SetDlgItemText(hwndDlg, IDC_EDIT_USERNAME, dbv.ptszVal); + DBFreeVariant(&dbv); + } + if (!DBGetContactSetting(NULL, proto->m_szModuleName, "Password", &dbv)) { + CallService(MS_DB_CRYPT_DECODESTRING, strlen(dbv.pszVal)+1, (LPARAM) dbv.pszVal); + SetDlgItemTextA(hwndDlg, IDC_EDIT_PASSWORD, dbv.pszVal); + DBFreeVariant(&dbv); + } + CheckDlgButton(hwndDlg, IDC_SAVEPASSWORD, DBGetContactSettingByte(NULL, proto->m_szModuleName, "SavePassword", TRUE)); + + oldProc = (WNDPROC) GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_EDIT_USERNAME), GWLP_WNDPROC); + SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_EDIT_USERNAME), GWLP_USERDATA, (LONG_PTR) oldProc); + SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_EDIT_USERNAME), GWLP_WNDPROC, (LONG_PTR) JabberValidateUsernameWndProc); + return TRUE; + } + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDC_EDIT_USERNAME: + case IDC_EDIT_PASSWORD: + if ((HWND)lParam == GetFocus() && HIWORD(wParam) == EN_CHANGE) + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + break; + case IDC_SAVEPASSWORD: + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + break; + case IDC_REGISTERACCOUNT: + CallService(MS_UTILS_OPENURL, (WPARAM) 1, (LPARAM) TLEN_REGISTER); + break; + } + break; + case WM_NOTIFY: + switch (((LPNMHDR) lParam)->code) { + case PSN_APPLY: + { + BOOL reconnectRequired = FALSE; + DBVARIANT dbv; + + GetDlgItemTextA(hwndDlg, IDC_EDIT_USERNAME, text, sizeof(text)); + if (DBGetContactSetting(NULL, proto->m_szModuleName, "LoginName", &dbv) || strcmp(text, dbv.pszVal)) + reconnectRequired = TRUE; + if (dbv.pszVal != NULL) DBFreeVariant(&dbv); + DBWriteContactSettingString(NULL, proto->m_szModuleName, "LoginName", strlwr(text)); + + if (IsDlgButtonChecked(hwndDlg, IDC_SAVEPASSWORD)) { + GetDlgItemTextA(hwndDlg, IDC_EDIT_PASSWORD, text, sizeof(text)); + CallService(MS_DB_CRYPT_ENCODESTRING, sizeof(text), (LPARAM) text); + if (DBGetContactSetting(NULL, proto->m_szModuleName, "Password", &dbv) || strcmp(text, dbv.pszVal)) + reconnectRequired = TRUE; + if (dbv.pszVal != NULL) DBFreeVariant(&dbv); + DBWriteContactSettingString(NULL, proto->m_szModuleName, "Password", text); + } + else + DBDeleteContactSetting(NULL, proto->m_szModuleName, "Password"); + + DBWriteContactSettingByte(NULL, proto->m_szModuleName, "SavePassword", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_SAVEPASSWORD)); + if (reconnectRequired && proto->isConnected) + MessageBox(hwndDlg, TranslateT("These changes will take effect the next time you connect to the Tlen network."), TranslateT("Tlen Protocol Option"), MB_OK|MB_SETFOREGROUND); + TlenLoadOptions(proto); + return TRUE; + } + } + break; + } + return FALSE; +} + +static INT_PTR CALLBACK TlenBasicOptDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + char text[256]; + WNDPROC oldProc; + + TlenProtocol *proto = (TlenProtocol *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + switch (msg) { + case WM_INITDIALOG: + { + DBVARIANT dbv; + proto = (TlenProtocol *)lParam; + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)proto); + TranslateDialogDefault(hwndDlg); + if (!DBGetContactSettingTString(NULL, proto->m_szModuleName, "LoginName", &dbv)) { + SetDlgItemText(hwndDlg, IDC_EDIT_USERNAME, dbv.ptszVal); + DBFreeVariant(&dbv); + } + if (!DBGetContactSetting(NULL, proto->m_szModuleName, "Password", &dbv)) { + CallService(MS_DB_CRYPT_DECODESTRING, strlen(dbv.pszVal)+1, (LPARAM) dbv.pszVal); + SetDlgItemTextA(hwndDlg, IDC_EDIT_PASSWORD, dbv.pszVal); + DBFreeVariant(&dbv); + } + CheckDlgButton(hwndDlg, IDC_SAVEPASSWORD, DBGetContactSettingByte(NULL, proto->m_szModuleName, "SavePassword", TRUE)); + + CheckDlgButton(hwndDlg, IDC_RECONNECT, proto->tlenOptions.reconnect); + CheckDlgButton(hwndDlg, IDC_ROSTER_SYNC, proto->tlenOptions.rosterSync); + CheckDlgButton(hwndDlg, IDC_SHOW_OFFLINE, proto->tlenOptions.offlineAsInvisible); + CheckDlgButton(hwndDlg, IDC_OFFLINE_MESSAGE, proto->tlenOptions.leaveOfflineMessage); + CheckDlgButton(hwndDlg, IDC_IGNORE_ADVERTISEMENTS, proto->tlenOptions.ignoreAdvertisements); + CheckDlgButton(hwndDlg, IDC_AVATARS, proto->tlenOptions.enableAvatars); + CheckDlgButton(hwndDlg, IDC_VERSIONINFO, proto->tlenOptions.enableVersion); + CheckDlgButton(hwndDlg, IDC_NUDGE_SUPPORT, proto->tlenOptions.useNudge); + CheckDlgButton(hwndDlg, IDC_LOG_ALERTS, proto->tlenOptions.logAlerts); + + SendDlgItemMessage(hwndDlg, IDC_ALERT_POLICY, CB_ADDSTRING, 0, (LPARAM)TranslateT("Accept all alerts")); + SendDlgItemMessage(hwndDlg, IDC_ALERT_POLICY, CB_ADDSTRING, 0, (LPARAM)TranslateT("Ignore alerts from unauthorized contacts")); + SendDlgItemMessage(hwndDlg, IDC_ALERT_POLICY, CB_ADDSTRING, 0, (LPARAM)TranslateT("Ignore all alerts")); + SendDlgItemMessage(hwndDlg, IDC_ALERT_POLICY, CB_SETCURSEL, proto->tlenOptions.alertPolicy, 0); + + SendDlgItemMessage(hwndDlg, IDC_MUC_POLICY, CB_ADDSTRING, 0, (LPARAM)TranslateT("Always ask me")); + SendDlgItemMessage(hwndDlg, IDC_MUC_POLICY, CB_ADDSTRING, 0, (LPARAM)TranslateT("Accept invitations from authorized contacts")); + SendDlgItemMessage(hwndDlg, IDC_MUC_POLICY, CB_ADDSTRING, 0, (LPARAM)TranslateT("Accept all invitations")); + SendDlgItemMessage(hwndDlg, IDC_MUC_POLICY, CB_ADDSTRING, 0, (LPARAM)TranslateT("Ignore invitations from unauthorized contacts")); + SendDlgItemMessage(hwndDlg, IDC_MUC_POLICY, CB_ADDSTRING, 0, (LPARAM)TranslateT("Ignore all invitation")); + SendDlgItemMessage(hwndDlg, IDC_MUC_POLICY, CB_SETCURSEL, proto->tlenOptions.groupChatPolicy, 0); + + SendDlgItemMessage(hwndDlg, IDC_IMAGE_POLICY, CB_ADDSTRING, 0, (LPARAM)TranslateT("Accept all images")); + SendDlgItemMessage(hwndDlg, IDC_IMAGE_POLICY, CB_ADDSTRING, 0, (LPARAM)TranslateT("Ignore images from unauthorized contacts")); + SendDlgItemMessage(hwndDlg, IDC_IMAGE_POLICY, CB_ADDSTRING, 0, (LPARAM)TranslateT("Ignore all images")); + SendDlgItemMessage(hwndDlg, IDC_IMAGE_POLICY, CB_SETCURSEL, proto->tlenOptions.imagePolicy, 0); + + SendDlgItemMessage(hwndDlg, IDC_OFFLINE_MESSAGE_OPTION, CB_ADDSTRING, 0, (LPARAM)TranslateT("")); + //SendDlgItemMessage(hwndDlg, IDC_OFFLINE_MESSAGE_OPTION, CB_ADDSTRING, 0, (LPARAM)TranslateT("")); + SendDlgItemMessage(hwndDlg, IDC_OFFLINE_MESSAGE_OPTION, CB_ADDSTRING, 0, (LPARAM)TranslateT("Online")); + SendDlgItemMessage(hwndDlg, IDC_OFFLINE_MESSAGE_OPTION, CB_ADDSTRING, 0, (LPARAM)TranslateT("Away")); + SendDlgItemMessage(hwndDlg, IDC_OFFLINE_MESSAGE_OPTION, CB_ADDSTRING, 0, (LPARAM)TranslateT("NA")); + SendDlgItemMessage(hwndDlg, IDC_OFFLINE_MESSAGE_OPTION, CB_ADDSTRING, 0, (LPARAM)TranslateT("DND")); + SendDlgItemMessage(hwndDlg, IDC_OFFLINE_MESSAGE_OPTION, CB_ADDSTRING, 0, (LPARAM)TranslateT("Free for chat")); + SendDlgItemMessage(hwndDlg, IDC_OFFLINE_MESSAGE_OPTION, CB_ADDSTRING, 0, (LPARAM)TranslateT("Invisible")); + SendDlgItemMessage(hwndDlg, IDC_OFFLINE_MESSAGE_OPTION, CB_SETCURSEL, proto->tlenOptions.offlineMessageOption, 0); + + oldProc = (WNDPROC) GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_EDIT_USERNAME), GWLP_WNDPROC); + SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_EDIT_USERNAME), GWLP_USERDATA, (LONG_PTR) oldProc); + SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_EDIT_USERNAME), GWLP_WNDPROC, (LONG_PTR) JabberValidateUsernameWndProc); + return TRUE; + } + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDC_EDIT_USERNAME: + case IDC_EDIT_PASSWORD: + if ((HWND)lParam == GetFocus() && HIWORD(wParam) == EN_CHANGE) + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + break; + // Fall through + case IDC_SAVEPASSWORD: + case IDC_RECONNECT: + case IDC_ROSTER_SYNC: + case IDC_IGNORE_ADVERTISEMENTS: + case IDC_SHOW_OFFLINE: + case IDC_OFFLINE_MESSAGE: + MarkChanges(1, hwndDlg); + break; + case IDC_LOG_ALERTS: + CheckDlgButton(hwndDlg, IDC_NUDGE_SUPPORT, BST_UNCHECKED); + MarkChanges(1, hwndDlg); + break; + case IDC_NUDGE_SUPPORT: + CheckDlgButton(hwndDlg, IDC_LOG_ALERTS, BST_UNCHECKED); + MarkChanges(1, hwndDlg); + break; + case IDC_REGISTERACCOUNT: + CallService(MS_UTILS_OPENURL, (WPARAM) 1, (LPARAM) TLEN_REGISTER); + break; + case IDC_OFFLINE_MESSAGE_OPTION: + case IDC_ALERT_POLICY: + case IDC_MUC_POLICY: + if (HIWORD(wParam) == CBN_SELCHANGE) + MarkChanges(1, hwndDlg); + break; + default: + MarkChanges(1, hwndDlg); + break; + } + break; + case WM_NOTIFY: + switch (((LPNMHDR) lParam)->code) { + case PSN_APPLY: + { + BOOL reconnectRequired = FALSE; + DBVARIANT dbv; + + GetDlgItemTextA(hwndDlg, IDC_EDIT_USERNAME, text, sizeof(text)); + if (DBGetContactSetting(NULL, proto->m_szModuleName, "LoginName", &dbv) || strcmp(text, dbv.pszVal)) + reconnectRequired = TRUE; + if (dbv.pszVal != NULL) DBFreeVariant(&dbv); + DBWriteContactSettingString(NULL, proto->m_szModuleName, "LoginName", strlwr(text)); + + if (IsDlgButtonChecked(hwndDlg, IDC_SAVEPASSWORD)) { + GetDlgItemTextA(hwndDlg, IDC_EDIT_PASSWORD, text, sizeof(text)); + CallService(MS_DB_CRYPT_ENCODESTRING, sizeof(text), (LPARAM) text); + if (DBGetContactSetting(NULL, proto->m_szModuleName, "Password", &dbv) || strcmp(text, dbv.pszVal)) + reconnectRequired = TRUE; + if (dbv.pszVal != NULL) DBFreeVariant(&dbv); + DBWriteContactSettingString(NULL, proto->m_szModuleName, "Password", text); + } + else + DBDeleteContactSetting(NULL, proto->m_szModuleName, "Password"); + + DBWriteContactSettingByte(NULL, proto->m_szModuleName, "SavePassword", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_SAVEPASSWORD)); + DBWriteContactSettingByte(NULL, proto->m_szModuleName, "Reconnect", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_RECONNECT)); + DBWriteContactSettingByte(NULL, proto->m_szModuleName, "RosterSync", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_ROSTER_SYNC)); + DBWriteContactSettingByte(NULL, proto->m_szModuleName, "OfflineAsInvisible", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_SHOW_OFFLINE)); + DBWriteContactSettingByte(NULL, proto->m_szModuleName, "IgnoreAdvertisements", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_IGNORE_ADVERTISEMENTS)); + DBWriteContactSettingByte(NULL, proto->m_szModuleName, "LeaveOfflineMessage", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_OFFLINE_MESSAGE)); + DBWriteContactSettingWord(NULL, proto->m_szModuleName, "OfflineMessageOption", (WORD) SendDlgItemMessage(hwndDlg, IDC_OFFLINE_MESSAGE_OPTION, CB_GETCURSEL, 0, 0)); + DBWriteContactSettingWord(NULL, proto->m_szModuleName, "AlertPolicy", (WORD) SendDlgItemMessage(hwndDlg, IDC_ALERT_POLICY, CB_GETCURSEL, 0, 0)); + DBWriteContactSettingWord(NULL, proto->m_szModuleName, "GroupChatPolicy", (WORD) SendDlgItemMessage(hwndDlg, IDC_MUC_POLICY, CB_GETCURSEL, 0, 0)); + DBWriteContactSettingWord(NULL, proto->m_szModuleName, "ImagePolicy", (WORD) SendDlgItemMessage(hwndDlg, IDC_IMAGE_POLICY, CB_GETCURSEL, 0, 0)); + DBWriteContactSettingByte(NULL, proto->m_szModuleName, "EnableAvatars", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_AVATARS)); + DBWriteContactSettingByte(NULL, proto->m_szModuleName, "EnableVersion", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_VERSIONINFO)); + DBWriteContactSettingByte(NULL, proto->m_szModuleName, "UseNudge", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_NUDGE_SUPPORT)); + DBWriteContactSettingByte(NULL, proto->m_szModuleName, "LogAlerts", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_LOG_ALERTS)); + if (reconnectRequired && proto->isConnected) + MessageBox(hwndDlg, TranslateT("These changes will take effect the next time you connect to the Tlen network."), TranslateT("Tlen Protocol Option"), MB_OK|MB_SETFOREGROUND); + ApplyChanges(proto, 1); + return TRUE; + } + } + break; + } + return FALSE; +} + +static INT_PTR CALLBACK TlenVoiceOptDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + TlenProtocol *proto = (TlenProtocol *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + switch (msg) { + case WM_INITDIALOG: + { + proto = (TlenProtocol *)lParam; + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)proto); + SendDlgItemMessage(hwndDlg, IDC_VOICE_POLICY, CB_ADDSTRING, 0, (LPARAM)TranslateT("Always ask me")); + SendDlgItemMessage(hwndDlg, IDC_VOICE_POLICY, CB_ADDSTRING, 0, (LPARAM)TranslateT("Accept invitations from authorized contacts")); + SendDlgItemMessage(hwndDlg, IDC_VOICE_POLICY, CB_ADDSTRING, 0, (LPARAM)TranslateT("Accept all invitations")); + SendDlgItemMessage(hwndDlg, IDC_VOICE_POLICY, CB_ADDSTRING, 0, (LPARAM)TranslateT("Ignore invitations from unauthorized contacts")); + SendDlgItemMessage(hwndDlg, IDC_VOICE_POLICY, CB_ADDSTRING, 0, (LPARAM)TranslateT("Ignore all invitation")); + SendDlgItemMessage(hwndDlg, IDC_VOICE_POLICY, CB_SETCURSEL, proto->tlenOptions.voiceChatPolicy, 0); + TlenVoiceBuildInDeviceList(proto, GetDlgItem(hwndDlg, IDC_VOICE_DEVICE_IN)); + TlenVoiceBuildOutDeviceList(proto, GetDlgItem(hwndDlg, IDC_VOICE_DEVICE_OUT)); + return TRUE; + } + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDC_VOICE_POLICY: + case IDC_VOICE_DEVICE_IN: + case IDC_VOICE_DEVICE_OUT: + if (HIWORD(wParam) == CBN_SELCHANGE) + MarkChanges(2, hwndDlg); + break; + } + break; + case WM_NOTIFY: + switch (((LPNMHDR) lParam)->code) { + case PSN_APPLY: + { + DBWriteContactSettingWord(NULL, proto->m_szModuleName, "VoiceChatPolicy", (WORD) SendDlgItemMessage(hwndDlg, IDC_VOICE_POLICY, CB_GETCURSEL, 0, 0)); + DBWriteContactSettingWord(NULL, proto->m_szModuleName, "VoiceDeviceIn", (WORD) SendDlgItemMessage(hwndDlg, IDC_VOICE_DEVICE_IN, CB_GETCURSEL, 0, 0)); + DBWriteContactSettingWord(NULL, proto->m_szModuleName, "VoiceDeviceOut", (WORD) SendDlgItemMessage(hwndDlg, IDC_VOICE_DEVICE_OUT, CB_GETCURSEL, 0, 0)); + ApplyChanges(proto, 2); + return TRUE; + } + } + break; + } + + return FALSE; +} + +static INT_PTR CALLBACK TlenAdvOptDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + char text[256]; + BOOL bChecked; + TlenProtocol *proto = (TlenProtocol *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + + switch (msg) { + case WM_INITDIALOG: + { + DBVARIANT dbv; + proto = (TlenProtocol *)lParam; + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)proto); + TranslateDialogDefault(hwndDlg); + if (!DBGetContactSettingTString(NULL, proto->m_szModuleName, "LoginServer", &dbv)) { + SetDlgItemText(hwndDlg, IDC_EDIT_LOGIN_SERVER, dbv.ptszVal); + DBFreeVariant(&dbv); + } else { + SetDlgItemText(hwndDlg, IDC_EDIT_LOGIN_SERVER, _T("tlen.pl")); + } + + EnableWindow(GetDlgItem(hwndDlg, IDC_HOST), TRUE); + EnableWindow(GetDlgItem(hwndDlg, IDC_HOSTPORT), TRUE); + + if (!DBGetContactSettingTString(NULL, proto->m_szModuleName, "ManualHost", &dbv)) { + SetDlgItemText(hwndDlg, IDC_HOST, dbv.ptszVal); + DBFreeVariant(&dbv); + } else + SetDlgItemText(hwndDlg, IDC_HOST, _T("s1.tlen.pl")); + SetDlgItemInt(hwndDlg, IDC_HOSTPORT, DBGetContactSettingWord(NULL, proto->m_szModuleName, "ManualPort", TLEN_DEFAULT_PORT), FALSE); + + CheckDlgButton(hwndDlg, IDC_KEEPALIVE, DBGetContactSettingByte(NULL, proto->m_szModuleName, "KeepAlive", TRUE)); + + CheckDlgButton(hwndDlg, IDC_USE_SSL, DBGetContactSettingByte(NULL, proto->m_szModuleName, "UseEncryption", TRUE)); + + CheckDlgButton(hwndDlg, IDC_VISIBILITY_SUPPORT, DBGetContactSettingByte(NULL, proto->m_szModuleName, "VisibilitySupport", FALSE)); + // File transfer options + bChecked = FALSE; + if (DBGetContactSettingByte(NULL, proto->m_szModuleName, "UseFileProxy", FALSE) == TRUE) { + bChecked = TRUE; + CheckDlgButton(hwndDlg, IDC_FILE_USE_PROXY, TRUE); + } + EnableWindow(GetDlgItem(hwndDlg, IDC_FILE_PROXY_TYPE_LABEL), bChecked); + EnableWindow(GetDlgItem(hwndDlg, IDC_FILE_PROXY_TYPE), bChecked); + EnableWindow(GetDlgItem(hwndDlg, IDC_FILE_PROXY_HOST_LABEL), bChecked); + EnableWindow(GetDlgItem(hwndDlg, IDC_FILE_PROXY_HOST), bChecked); + EnableWindow(GetDlgItem(hwndDlg, IDC_FILE_PROXY_PORT_LABEL), bChecked); + EnableWindow(GetDlgItem(hwndDlg, IDC_FILE_PROXY_PORT), bChecked); + EnableWindow(GetDlgItem(hwndDlg, IDC_FILE_PROXY_USE_AUTH), bChecked); + if (DBGetContactSettingByte(NULL, proto->m_szModuleName, "FileProxyAuth", FALSE) == TRUE) { + CheckDlgButton(hwndDlg, IDC_FILE_PROXY_USE_AUTH, TRUE); + } else { + bChecked = FALSE; + } + EnableWindow(GetDlgItem(hwndDlg, IDC_FILE_PROXY_USER_LABEL), bChecked); + EnableWindow(GetDlgItem(hwndDlg, IDC_FILE_PROXY_USER), bChecked); + EnableWindow(GetDlgItem(hwndDlg, IDC_FILE_PROXY_PASSWORD_LABEL), bChecked); + EnableWindow(GetDlgItem(hwndDlg, IDC_FILE_PROXY_PASSWORD), bChecked); + + SendDlgItemMessage(hwndDlg, IDC_FILE_PROXY_TYPE, CB_ADDSTRING, 0, (LPARAM)TranslateT("Forwarding")); + SendDlgItemMessage(hwndDlg, IDC_FILE_PROXY_TYPE, CB_ADDSTRING, 0, (LPARAM)TranslateT("SOCKS4")); + SendDlgItemMessage(hwndDlg, IDC_FILE_PROXY_TYPE, CB_ADDSTRING, 0, (LPARAM)TranslateT("SOCKS5")); + SendDlgItemMessage(hwndDlg, IDC_FILE_PROXY_TYPE, CB_SETCURSEL, DBGetContactSettingWord(NULL, proto->m_szModuleName, "FileProxyType", 0), 0); + if (!DBGetContactSettingTString(NULL, proto->m_szModuleName, "FileProxyHost", &dbv)) { + SetDlgItemText(hwndDlg, IDC_FILE_PROXY_HOST, dbv.ptszVal); + DBFreeVariant(&dbv); + } + SetDlgItemInt(hwndDlg, IDC_FILE_PROXY_PORT, DBGetContactSettingWord(NULL, proto->m_szModuleName, "FileProxyPort", 0), FALSE); + if (!DBGetContactSettingTString(NULL, proto->m_szModuleName, "FileProxyUsername", &dbv)) { + SetDlgItemText(hwndDlg, IDC_FILE_PROXY_USER, dbv.ptszVal); + DBFreeVariant(&dbv); + } + if (!DBGetContactSetting(NULL, proto->m_szModuleName, "FileProxyPassword", &dbv)) { + CallService(MS_DB_CRYPT_DECODESTRING, strlen(dbv.pszVal)+1, (LPARAM) dbv.pszVal); + SetDlgItemTextA(hwndDlg, IDC_FILE_PROXY_PASSWORD, dbv.pszVal); + DBFreeVariant(&dbv); + } + return TRUE; + } + case WM_COMMAND: + { + switch (LOWORD(wParam)) { + case IDC_FILE_PROXY_TYPE: + if (HIWORD(wParam) == CBN_SELCHANGE) + MarkChanges(4, hwndDlg); + break; + case IDC_EDIT_LOGIN_SERVER: + case IDC_HOST: + case IDC_HOSTPORT: + case IDC_FILE_PROXY_HOST: + case IDC_FILE_PROXY_PORT: + case IDC_FILE_PROXY_USER: + case IDC_FILE_PROXY_PASSWORD: + if ((HWND)lParam == GetFocus() && HIWORD(wParam) == EN_CHANGE) + MarkChanges(4, hwndDlg); + break; + case IDC_FILE_USE_PROXY: + bChecked = IsDlgButtonChecked(hwndDlg, IDC_FILE_USE_PROXY); + EnableWindow(GetDlgItem(hwndDlg, IDC_FILE_PROXY_TYPE_LABEL), bChecked); + EnableWindow(GetDlgItem(hwndDlg, IDC_FILE_PROXY_TYPE), bChecked); + EnableWindow(GetDlgItem(hwndDlg, IDC_FILE_PROXY_HOST_LABEL), bChecked); + EnableWindow(GetDlgItem(hwndDlg, IDC_FILE_PROXY_HOST), bChecked); + EnableWindow(GetDlgItem(hwndDlg, IDC_FILE_PROXY_PORT_LABEL), bChecked); + EnableWindow(GetDlgItem(hwndDlg, IDC_FILE_PROXY_PORT), bChecked); + EnableWindow(GetDlgItem(hwndDlg, IDC_FILE_PROXY_USE_AUTH), bChecked); + case IDC_FILE_PROXY_USE_AUTH: + bChecked = IsDlgButtonChecked(hwndDlg, IDC_FILE_PROXY_USE_AUTH) & IsDlgButtonChecked(hwndDlg, IDC_FILE_USE_PROXY); + EnableWindow(GetDlgItem(hwndDlg, IDC_FILE_PROXY_USER_LABEL), bChecked); + EnableWindow(GetDlgItem(hwndDlg, IDC_FILE_PROXY_USER), bChecked); + EnableWindow(GetDlgItem(hwndDlg, IDC_FILE_PROXY_PASSWORD_LABEL), bChecked); + EnableWindow(GetDlgItem(hwndDlg, IDC_FILE_PROXY_PASSWORD), bChecked); + MarkChanges(4, hwndDlg); + break; + case IDC_KEEPALIVE: + case IDC_VISIBILITY_SUPPORT: + case IDC_USE_SSL: + MarkChanges(4, hwndDlg); + break; + } + } + break; + case WM_NOTIFY: + { + switch (((LPNMHDR) lParam)->code) { + case PSN_APPLY: + { + WORD port; + BOOL useEncryption; + BOOL reconnectRequired = FALSE; + DBVARIANT dbv; + GetDlgItemTextA(hwndDlg, IDC_EDIT_LOGIN_SERVER, text, sizeof(text)); + if (DBGetContactSetting(NULL, proto->m_szModuleName, "LoginServer", &dbv) || strcmp(text, dbv.pszVal)) + reconnectRequired = TRUE; + if (dbv.pszVal != NULL) DBFreeVariant(&dbv); + DBWriteContactSettingString(NULL, proto->m_szModuleName, "LoginServer", strlwr(text)); + + GetDlgItemTextA(hwndDlg, IDC_HOST, text, sizeof(text)); + if (DBGetContactSetting(NULL, proto->m_szModuleName, "ManualHost", &dbv) || strcmp(text, dbv.pszVal)) + reconnectRequired = TRUE; + if (dbv.pszVal != NULL) DBFreeVariant(&dbv); + DBWriteContactSettingString(NULL, proto->m_szModuleName, "ManualHost", text); + + port = (WORD) GetDlgItemInt(hwndDlg, IDC_HOSTPORT, NULL, FALSE); + if (DBGetContactSettingWord(NULL, proto->m_szModuleName, "ManualPort", TLEN_DEFAULT_PORT) != port) + reconnectRequired = TRUE; + DBWriteContactSettingWord(NULL, proto->m_szModuleName, "ManualPort", port); + + proto->tlenOptions.sendKeepAlive = IsDlgButtonChecked(hwndDlg, IDC_KEEPALIVE); + DBWriteContactSettingByte(NULL, proto->m_szModuleName, "KeepAlive", (BYTE) proto->tlenOptions.sendKeepAlive); + + useEncryption = IsDlgButtonChecked(hwndDlg, IDC_USE_SSL); + if (DBGetContactSettingByte(NULL, proto->m_szModuleName, "UseEncryption", TRUE) != useEncryption) + reconnectRequired = TRUE; + DBWriteContactSettingByte(NULL, proto->m_szModuleName, "UseEncryption", (BYTE) useEncryption); + + DBWriteContactSettingByte(NULL, proto->m_szModuleName, "VisibilitySupport", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_VISIBILITY_SUPPORT)); + // File transfer options + DBWriteContactSettingByte(NULL, proto->m_szModuleName, "UseFileProxy", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_FILE_USE_PROXY)); + DBWriteContactSettingWord(NULL, proto->m_szModuleName, "FileProxyType", (WORD) SendDlgItemMessage(hwndDlg, IDC_FILE_PROXY_TYPE, CB_GETCURSEL, 0, 0)); + GetDlgItemTextA(hwndDlg, IDC_FILE_PROXY_HOST, text, sizeof(text)); + DBWriteContactSettingString(NULL, proto->m_szModuleName, "FileProxyHost", text); + DBWriteContactSettingWord(NULL, proto->m_szModuleName, "FileProxyPort", (WORD) GetDlgItemInt(hwndDlg, IDC_FILE_PROXY_PORT, NULL, FALSE)); + DBWriteContactSettingByte(NULL, proto->m_szModuleName, "FileProxyAuth", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_FILE_PROXY_USE_AUTH)); + GetDlgItemTextA(hwndDlg, IDC_FILE_PROXY_USER, text, sizeof(text)); + DBWriteContactSettingString(NULL, proto->m_szModuleName, "FileProxyUsername", text); + GetDlgItemTextA(hwndDlg, IDC_FILE_PROXY_PASSWORD, text, sizeof(text)); + CallService(MS_DB_CRYPT_ENCODESTRING, sizeof(text), (LPARAM) text); + DBWriteContactSettingString(NULL, proto->m_szModuleName, "FileProxyPassword", text); + if (reconnectRequired && proto->isConnected) + MessageBox(hwndDlg, TranslateT("These changes will take effect the next time you connect to the Tlen network."), TranslateT("Tlen Protocol Option"), MB_OK|MB_SETFOREGROUND); + ApplyChanges(proto, 4); + return TRUE; + } + } + } + break; + case WM_DESTROY: + break; + } + + return FALSE; +} + +#define POPUP_DEFAULT_COLORBKG 0xDCBDA5 +#define POPUP_DEFAULT_COLORTXT 0x000000 + +static void MailPopupPreview(DWORD colorBack, DWORD colorText, char *title, char *emailInfo, int delay) +{ + POPUPDATAEX ppd; + char * lpzContactName; + char * lpzText; + HICON hIcon; + lpzContactName = title; + lpzText = emailInfo; + ZeroMemory(&ppd, sizeof(ppd)); + ppd.lchContact = NULL; + hIcon = GetIcolibIcon(IDI_MAIL); + ppd.lchIcon = CopyIcon(hIcon); + ReleaseIcolibIcon(hIcon); + strcpy(ppd.lpzContactName, lpzContactName); + strcpy(ppd.lpzText, lpzText); + ppd.colorBack = colorBack; + ppd.colorText = colorText; + ppd.PluginWindowProc = NULL; + ppd.PluginData=NULL; + if ( ServiceExists( MS_POPUP_ADDPOPUPEX )) { + ppd.iSeconds = delay; + CallService(MS_POPUP_ADDPOPUPEX, (WPARAM)&ppd, 0); + + } + else if ( ServiceExists( MS_POPUP_ADDPOPUP )) { + CallService(MS_POPUP_ADDPOPUP, (WPARAM)&ppd, 0); + } +} + +static INT_PTR CALLBACK TlenPopupsDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + TlenProtocol *proto = (TlenProtocol *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + switch (msg) { + case WM_INITDIALOG: + { + BYTE delayMode; + proto = (TlenProtocol *)lParam; + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)proto); + TranslateDialogDefault(hwndDlg); + CheckDlgButton(hwndDlg, IDC_ENABLEPOPUP, DBGetContactSettingByte(NULL, proto->m_szModuleName, "MailPopupEnabled", TRUE)); + SendDlgItemMessage(hwndDlg, IDC_COLORBKG, CPM_SETCOLOUR, 0, DBGetContactSettingDword(NULL, proto->m_szModuleName, "MailPopupBack", POPUP_DEFAULT_COLORBKG)); + SendDlgItemMessage(hwndDlg, IDC_COLORTXT, CPM_SETCOLOUR, 0, DBGetContactSettingDword(NULL, proto->m_szModuleName, "MailPopupText", POPUP_DEFAULT_COLORTXT)); + SetDlgItemInt(hwndDlg, IDC_DELAY, DBGetContactSettingDword(NULL, proto->m_szModuleName, "MailPopupDelay", 4), FALSE); + delayMode = DBGetContactSettingByte(NULL, proto->m_szModuleName, "MailPopupDelayMode", 0); + if (delayMode == 1) { + CheckDlgButton(hwndDlg, IDC_DELAY_CUSTOM, TRUE); + } else if (delayMode == 2) { + CheckDlgButton(hwndDlg, IDC_DELAY_PERMANENT, TRUE); + } else { + CheckDlgButton(hwndDlg, IDC_DELAY_POPUP, TRUE); + } + return TRUE; + } + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDC_COLORTXT: + case IDC_COLORBKG: + case IDC_ENABLEPOPUP: + case IDC_DELAY: + case IDC_DELAY_POPUP: + case IDC_DELAY_CUSTOM: + case IDC_DELAY_PERMANENT: + MarkChanges(8, hwndDlg); + break; + case IDC_PREVIEW: + { + int delay; + char title[256]; + if (IsDlgButtonChecked(hwndDlg, IDC_DELAY_POPUP)) { + delay=0; + } else if (IsDlgButtonChecked(hwndDlg, IDC_DELAY_PERMANENT)) { + delay=-1; + } else { + delay=GetDlgItemInt(hwndDlg, IDC_DELAY, NULL, FALSE); + } + _snprintf(title, sizeof(title), Translate("%s mail"), proto->m_szProtoName); + MailPopupPreview((DWORD) SendDlgItemMessage(hwndDlg,IDC_COLORBKG,CPM_GETCOLOUR,0,0), + (DWORD) SendDlgItemMessage(hwndDlg,IDC_COLORTXT,CPM_GETCOLOUR,0,0), + title, + "From: test@test.test\nSubject: test", + delay); + } + + } + break; + + + case WM_NOTIFY: + switch (((LPNMHDR) lParam)->code) { + case PSN_APPLY: + { + BYTE delayMode; + DBWriteContactSettingByte(NULL, proto->m_szModuleName, "MailPopupEnabled", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_ENABLEPOPUP)); + DBWriteContactSettingDword(NULL, proto->m_szModuleName, "MailPopupBack", (DWORD) SendDlgItemMessage(hwndDlg,IDC_COLORBKG,CPM_GETCOLOUR,0,0)); + DBWriteContactSettingDword(NULL, proto->m_szModuleName, "MailPopupText", (DWORD) SendDlgItemMessage(hwndDlg,IDC_COLORTXT,CPM_GETCOLOUR,0,0)); + DBWriteContactSettingDword(NULL, proto->m_szModuleName, "MailPopupDelay", (DWORD) GetDlgItemInt(hwndDlg,IDC_DELAY, NULL, FALSE)); + delayMode=0; + if (IsDlgButtonChecked(hwndDlg, IDC_DELAY_CUSTOM)) { + delayMode=1; + } else if (IsDlgButtonChecked(hwndDlg, IDC_DELAY_PERMANENT)) { + delayMode=2; + + } + DBWriteContactSettingByte(NULL, proto->m_szModuleName, "MailPopupDelayMode", delayMode); + ApplyChanges(proto, 8); + return TRUE; + } + } + break; + + } + return FALSE; +} + diff --git a/protocols/Tlen/src/jabber_svc.cpp b/protocols/Tlen/src/jabber_svc.cpp new file mode 100644 index 0000000000..345490df30 --- /dev/null +++ b/protocols/Tlen/src/jabber_svc.cpp @@ -0,0 +1,1364 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Tlen Protocol Plugin for Miranda NG +Copyright (C) 2002-2004 Santithorn Bunchua +Copyright (C) 2004-2007 Piotr Piastucki + +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 +#include +#include +#include +#include "resource.h" +#include "jabber_list.h" +#include "jabber_iq.h" +#include "tlen_p2p_old.h" +#include "tlen_avatar.h" +#include "tlen_file.h" + +extern int TlenOnModulesLoaded(void *ptr, WPARAM wParam, LPARAM lParam); +extern int TlenOptionsInit(void *ptr, WPARAM wParam, LPARAM lParam); +extern int TlenPreShutdown(void *ptr, WPARAM wParam, LPARAM lParam); +extern int TlenSystemModulesLoaded(void *ptr, WPARAM wParam, LPARAM lParam); +extern int TlenPrebuildContactMenu(void *ptr, WPARAM wParam, LPARAM lParam); + + +DWORD_PTR __cdecl TlenProtocol::GetCaps(int type, HANDLE hContact) +{ + if (type == PFLAGNUM_1) + return PF1_IM|PF1_AUTHREQ|PF1_SERVERCLIST|PF1_MODEMSG|PF1_BASICSEARCH|PF1_SEARCHBYEMAIL|PF1_EXTSEARCH|PF1_EXTSEARCHUI|PF1_SEARCHBYNAME|PF1_FILE;//|PF1_VISLIST|PF1_INVISLIST; + if (type == PFLAGNUM_2) + return PF2_ONLINE|PF2_INVISIBLE|PF2_SHORTAWAY|PF2_LONGAWAY|PF2_HEAVYDND|PF2_FREECHAT; + if (type == PFLAGNUM_3) + return PF2_ONLINE|PF2_INVISIBLE|PF2_SHORTAWAY|PF2_LONGAWAY|PF2_HEAVYDND|PF2_FREECHAT; + if (type == PFLAGNUM_4) + return PF4_FORCEAUTH|PF4_NOCUSTOMAUTH|PF4_SUPPORTTYPING|PF4_AVATARS|PF4_IMSENDOFFLINE|PF4_OFFLINEFILES; + if (type == PFLAG_UNIQUEIDTEXT) + return (DWORD_PTR) Translate("Tlen login"); + if (type == PFLAG_UNIQUEIDSETTING) + return (DWORD_PTR) "jid"; + return 0; +} + +INT_PTR TlenGetName(void *ptr, LPARAM wParam, LPARAM lParam) +{ + TlenProtocol *proto = (TlenProtocol *)ptr; + strncpy((char *) lParam, proto->m_szProtoName, wParam); + return 0; +} + +HICON __cdecl TlenProtocol::GetIcon(int iconIndex) +{ + if ((iconIndex&0xffff) == PLI_PROTOCOL) { + HICON hIcon = GetIcolibIcon(IDI_TLEN); + HICON hIconCopy = CopyIcon(hIcon); + ReleaseIcolibIcon(hIcon); + return hIconCopy; + } + return (HICON) NULL; +} + +int TlenRunSearch(TlenProtocol *proto) { + int iqId = 0; + if (!proto->isOnline) return 0; + if (proto->searchQuery != NULL && proto->searchIndex < 10) { + iqId = proto->searchID; + JabberIqAdd(proto, iqId, IQ_PROC_GETSEARCH, JabberIqResultSearch); + if (proto->searchIndex == 0) { + JabberSend(proto, "%s", iqId, proto->searchQuery); + } else { + JabberSend(proto, "%s%d", iqId, proto->searchQuery, proto->searchIndex * TLEN_MAX_SEARCH_RESULTS_PER_PAGE); + } + proto->searchIndex ++; + } + return iqId; +} + +void TlenResetSearchQuery(TlenProtocol *proto) { + if (proto->searchQuery != NULL) { + mir_free(proto->searchQuery); + proto->searchQuery = NULL; + } + proto->searchQueryLen = 0; + proto->searchIndex = 0; + proto->searchID = JabberSerialNext(proto); +} + +HANDLE __cdecl TlenProtocol::SearchBasic(const PROTOCHAR* id) +{ + char *jid; + int iqId = 0; + if (!isOnline) return 0; + if (id == NULL) return 0; + char* id_A = mir_t2a(id); + if ((jid=JabberTextEncode(id_A)) != NULL) { + searchJID = mir_strdup(id_A); + TlenResetSearchQuery(this); + JabberStringAppend(&searchQuery, &searchQueryLen, "%s", jid); + iqId = TlenRunSearch(this); + mir_free(jid); + } + mir_free(id_A); + return (HANDLE)iqId; +} + +HANDLE __cdecl TlenProtocol::SearchByEmail(const PROTOCHAR* email) +{ + char *emailEnc; + int iqId = 0; + + if (!isOnline) return 0; + if (email == NULL) return 0; + + char* email_A = mir_t2a(email); + if ((emailEnc=JabberTextEncode(email_A)) != NULL) { + TlenResetSearchQuery(this); + JabberStringAppend(&searchQuery, &searchQueryLen, "%s", emailEnc); + iqId = TlenRunSearch(this); + mir_free(emailEnc); + } + mir_free(email_A); + return (HANDLE)iqId; +} + +HANDLE __cdecl TlenProtocol::SearchByName(const PROTOCHAR* nickT, const PROTOCHAR* firstNameT, const PROTOCHAR* lastNameT) +{ + + char* nick = mir_t2a(nickT); + char* firstName = mir_t2a(firstNameT); + char* lastName = mir_t2a(lastNameT); + + char *p; + int iqId = 0; + + if (!isOnline) return 0; + + TlenResetSearchQuery(this); + + if (nick != NULL && nick[0] != '\0') { + if ((p=JabberTextEncode(nick)) != NULL) { + JabberStringAppend(&searchQuery, &searchQueryLen, "%s", p); + mir_free(p); + } + } + if (firstName != NULL && firstName[0] != '\0') { + if ((p=JabberTextEncode(firstName)) != NULL) { + JabberStringAppend(&searchQuery, &searchQueryLen, "%s", p); + mir_free(p); + } + } + if (lastName != NULL && lastName[0] != '\0') { + if ((p=JabberTextEncode(lastName)) != NULL) { + JabberStringAppend(&searchQuery, &searchQueryLen, "%s", p); + mir_free(p); + } + } + + iqId = TlenRunSearch(this); + return (HANDLE)iqId; +} + +HWND __cdecl TlenProtocol::CreateExtendedSearchUI(HWND owner) +{ + return (HWND) CreateDialog(hInst, MAKEINTRESOURCE(IDD_ADVSEARCH), owner, TlenAdvSearchDlgProc); +} + +HWND __cdecl TlenProtocol::SearchAdvanced(HWND owner) +{ + int iqId; + if (!isOnline) return 0; + + TlenResetSearchQuery(this); + iqId = JabberSerialNext(this); + if ((searchQuery = TlenAdvSearchCreateQuery(owner, iqId)) != NULL) { + iqId = TlenRunSearch(this); + } + return (HWND)iqId; +} + + +static HANDLE AddToListByJID(TlenProtocol *proto, const char *newJid, DWORD flags) +{ + HANDLE hContact; + char *jid, *nick; + + if ((hContact=JabberHContactFromJID(proto, newJid)) == NULL) { + // not already there: add + jid = mir_strdup(newJid); _strlwr(jid); + hContact = (HANDLE) CallService(MS_DB_CONTACT_ADD, 0, 0); + CallService(MS_PROTO_ADDTOCONTACT, (WPARAM) hContact, (LPARAM) proto->m_szModuleName); + DBWriteContactSettingString(hContact, proto->m_szModuleName, "jid", jid); + if ((nick=JabberNickFromJID(newJid)) == NULL) + nick = mir_strdup(newJid); + DBWriteContactSettingString(hContact, "CList", "MyHandle", nick); + mir_free(nick); + mir_free(jid); + + // Note that by removing or disable the "NotOnList" will trigger + // the plugin to add a particular contact to the roster list. + // See DBSettingChanged hook at the bottom part of this source file. + // But the add module will delete "NotOnList". So we will not do it here. + // Also because we need "MyHandle" and "Group" info, which are set after + // PS_ADDTOLIST is called but before the add dialog issue deletion of + // "NotOnList". + // If temporary add, "NotOnList" won't be deleted, and that's expected. + DBWriteContactSettingByte(hContact, "CList", "NotOnList", 1); + if (flags & PALF_TEMPORARY) + DBWriteContactSettingByte(hContact, "CList", "Hidden", 1); + } + else { + // already exist + // Set up a dummy "NotOnList" when adding permanently only + if (!(flags&PALF_TEMPORARY)) + DBWriteContactSettingByte(hContact, "CList", "NotOnList", 1); + } + + return hContact; +} + +HANDLE __cdecl TlenProtocol::AddToList(int flags, PROTOSEARCHRESULT *psr) +{ + HANDLE hContact; + JABBER_SEARCH_RESULT *jsr = (JABBER_SEARCH_RESULT*)psr; + if (jsr->hdr.cbSize != sizeof(JABBER_SEARCH_RESULT)) + return (int) NULL; + hContact = AddToListByJID(this, jsr->jid, flags); // wParam is flag e.g. PALF_TEMPORARY + return hContact; +} + +HANDLE __cdecl TlenProtocol::AddToListByEvent( int flags, int iContact, HANDLE hDbEvent ) +{ + DBEVENTINFO dbei; + HANDLE hContact; + char *nick, *firstName, *lastName, *jid; + + ZeroMemory(&dbei, sizeof(dbei)); + dbei.cbSize = sizeof(dbei); + if ((dbei.cbBlob=CallService(MS_DB_EVENT_GETBLOBSIZE, (WPARAM)hDbEvent, 0)) == (DWORD)(-1)) + return (HANDLE) NULL; + if ((dbei.pBlob=(PBYTE) mir_alloc(dbei.cbBlob)) == NULL) + return (HANDLE) NULL; + if (CallService(MS_DB_EVENT_GET, (WPARAM)hDbEvent, (LPARAM) &dbei)) { + mir_free(dbei.pBlob); + return (HANDLE) NULL; + } + if (strcmp(dbei.szModule, m_szModuleName)) { + mir_free(dbei.pBlob); + return (HANDLE) NULL; + } + +/* + // EVENTTYPE_CONTACTS is when adding from when we receive contact list (not used in Jabber) + // EVENTTYPE_ADDED is when adding from when we receive "You are added" (also not used in Jabber) + // Jabber will only handle the case of EVENTTYPE_AUTHREQUEST + // EVENTTYPE_AUTHREQUEST is when adding from the authorization request dialog +*/ + + if (dbei.eventType != EVENTTYPE_AUTHREQUEST) { + mir_free(dbei.pBlob); + return (HANDLE) NULL; + } + + nick = (char *)dbei.pBlob + sizeof(DWORD)*2; + firstName = nick + strlen(nick) + 1; + lastName = firstName + strlen(firstName) + 1; + jid = lastName + strlen(lastName) + 1; + + hContact = (HANDLE) AddToListByJID(this, jid, flags); + mir_free(dbei.pBlob); + + return hContact; +} + +int __cdecl TlenProtocol::Authorize(HANDLE hDbEvent) +{ + DBEVENTINFO dbei; + char *nick, *firstName, *lastName, *jid; + + if (!isOnline) + return 1; + + memset(&dbei, sizeof(dbei), 0); + dbei.cbSize = sizeof(dbei); + if (( dbei.cbBlob=CallService( MS_DB_EVENT_GETBLOBSIZE, ( WPARAM )hDbEvent, 0 )) == ( DWORD )( -1 )) + return 1; + if ((dbei.pBlob=(PBYTE) mir_alloc(dbei.cbBlob)) == NULL) + return 1; + if ( CallService( MS_DB_EVENT_GET, ( WPARAM )hDbEvent, ( LPARAM )&dbei )){ + mir_free(dbei.pBlob); + return 1; + } + if (dbei.eventType != EVENTTYPE_AUTHREQUEST) { + mir_free(dbei.pBlob); + return 1; + } + if (strcmp(dbei.szModule, m_szModuleName)) { + mir_free(dbei.pBlob); + return 1; + } + + nick = (char *)dbei.pBlob + sizeof(DWORD)*2; + firstName = nick + strlen(nick) + 1; + lastName = firstName + strlen(firstName) + 1; + jid = lastName + strlen(lastName) + 1; + + JabberSend(this, "", jid); + + // Automatically add this user to my roster if option is enabled + if (DBGetContactSettingByte(NULL, m_szModuleName, "AutoAdd", TRUE) == TRUE) { + HANDLE hContact; + JABBER_LIST_ITEM *item; + + if ((item=JabberListGetItemPtr(this, LIST_ROSTER, jid)) == NULL || (item->subscription != SUB_BOTH && item->subscription != SUB_TO)) { + JabberLog(this, "Try adding contact automatically jid=%s", jid); + if ((hContact=AddToListByJID(this, jid, 0)) != NULL) { + // Trigger actual add by removing the "NotOnList" added by AddToListByJID() + // See AddToListByJID() and JabberDbSettingChanged(). + DBDeleteContactSetting(hContact, "CList", "NotOnList"); + } + } + } + + mir_free(dbei.pBlob); + return 0; +} + +int __cdecl TlenProtocol::AuthDeny(HANDLE hDbEvent, const PROTOCHAR* szReason) +{ + DBEVENTINFO dbei; + char *nick, *firstName, *lastName, *jid; + + if (!isOnline) + return 1; + + memset(&dbei, sizeof(dbei), 0); + dbei.cbSize = sizeof(dbei); + if ((dbei.cbBlob=CallService(MS_DB_EVENT_GETBLOBSIZE, (WPARAM)hDbEvent/*hContact*/, 0)) == (DWORD)(-1)) + return 1; + if ((dbei.pBlob=(PBYTE) mir_alloc(dbei.cbBlob)) == NULL) + return 1; + if (CallService(MS_DB_EVENT_GET, (WPARAM)hDbEvent/*hContact*/, (LPARAM) &dbei)) { + mir_free(dbei.pBlob); + return 1; + } + if (dbei.eventType != EVENTTYPE_AUTHREQUEST) { + mir_free(dbei.pBlob); + return 1; + } + if (strcmp(dbei.szModule, m_szModuleName)) { + mir_free(dbei.pBlob); + return 1; + } + + nick = (char *)dbei.pBlob + sizeof(DWORD)*2; + firstName = nick + strlen(nick) + 1; + lastName = firstName + strlen(firstName) + 1; + jid = lastName + strlen(lastName) + 1; + + JabberSend(this, "", jid); + JabberSend(this, "", jid); + mir_free(dbei.pBlob); + return 0; +} + +static void TlenConnect(TlenProtocol *proto, int initialStatus) +{ + if (!proto->isConnected) { + ThreadData *thread; + int oldStatus; + + thread = (ThreadData *) mir_alloc(sizeof(ThreadData)); + memset(thread, 0, sizeof(ThreadData)); + thread->proto = proto; + proto->m_iDesiredStatus = initialStatus; + + oldStatus = proto->m_iStatus; + proto->m_iStatus = ID_STATUS_CONNECTING; + ProtoBroadcastAck(proto->m_szModuleName, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE) oldStatus, proto->m_iStatus); + thread->hThread = (HANDLE) JabberForkThread((void (__cdecl *)(void*))JabberServerThread, 0, thread); + } +} + +int __cdecl TlenProtocol::SetStatus(int iNewStatus) +{ + int oldStatus; + HANDLE s; + + m_iDesiredStatus = iNewStatus; + + if (iNewStatus == ID_STATUS_OFFLINE) { + if (threadData) { + if (isConnected) { + JabberSendPresence(this, ID_STATUS_OFFLINE); + } + + // TODO bug? s = proto; + s = threadData->s; + + threadData = NULL; + if (isConnected) { + Sleep(200); +// JabberSend(s, ""); + // Force closing connection + isConnected = FALSE; + isOnline = FALSE; + Netlib_CloseHandle(s); + } + } + else { + if (m_iStatus != ID_STATUS_OFFLINE) { + oldStatus = m_iStatus; + m_iStatus = ID_STATUS_OFFLINE; + ProtoBroadcastAck(m_szModuleName, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE) oldStatus, m_iStatus); + } + } + } + else if (iNewStatus != m_iStatus) { + if (!isConnected) + TlenConnect(this, iNewStatus); + else { + // change status + oldStatus = m_iStatus; + // send presence update + JabberSendPresence(this, iNewStatus); + ProtoBroadcastAck(m_szModuleName, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE) oldStatus, m_iStatus); + } + } + return 0; +} + +INT_PTR TlenGetStatus(void *ptr, LPARAM wParam, LPARAM lParam) +{ + TlenProtocol *proto = (TlenProtocol *)ptr; + return proto->m_iStatus; +} + + +int __cdecl TlenProtocol::SetAwayMsg(int iStatus, const PROTOCHAR* msg) +{ + char **szMsg; + char *newModeMsg; + + JabberLog(this, "SetAwayMsg called, wParam=%d lParam=%s", iStatus, msg); + + newModeMsg = JabberTextEncode(mir_t2a(msg)); //TODO TCHAR + + EnterCriticalSection(&modeMsgMutex); + + switch (iStatus) { + case ID_STATUS_ONLINE: + szMsg = &modeMsgs.szOnline; + break; + case ID_STATUS_AWAY: + case ID_STATUS_ONTHEPHONE: + case ID_STATUS_OUTTOLUNCH: + szMsg = &modeMsgs.szAway; + break; + case ID_STATUS_NA: + szMsg = &modeMsgs.szNa; + break; + case ID_STATUS_DND: + case ID_STATUS_OCCUPIED: + szMsg = &modeMsgs.szDnd; + break; + case ID_STATUS_FREECHAT: + szMsg = &modeMsgs.szFreechat; + break; + case ID_STATUS_INVISIBLE: + szMsg = &modeMsgs.szInvisible; + break; + default: + LeaveCriticalSection(&modeMsgMutex); + return 1; + } + + if ((*szMsg == NULL && newModeMsg == NULL) || + (*szMsg != NULL && newModeMsg != NULL && !strcmp(*szMsg, newModeMsg))) { + // Message is the same, no update needed + if (newModeMsg != NULL) mir_free(newModeMsg); + } + else { + // Update with the new mode message + if (*szMsg != NULL) mir_free(*szMsg); + *szMsg = newModeMsg; + // Send a presence update if needed + if (iStatus == m_iStatus) { + JabberSendPresence(this, m_iStatus); + } + } + + LeaveCriticalSection(&modeMsgMutex); + return 0; +} + +int __cdecl TlenProtocol::GetInfo(HANDLE hContact, int infoType) +{ + DBVARIANT dbv; + int iqId; + char *nick, *pNick; + + if (!isOnline) return 1; + if (hContact == NULL) { + iqId = JabberSerialNext(this); + JabberIqAdd(this, iqId, IQ_PROC_NONE, TlenIqResultVcard); + JabberSend(this, "", iqId); + } else { + if (DBGetContactSetting(hContact, m_szModuleName, "jid", &dbv)) return 1; + if ((nick=JabberNickFromJID(dbv.pszVal)) != NULL) { + if ((pNick=JabberTextEncode(nick)) != NULL) { + iqId = JabberSerialNext(this); + JabberIqAdd(this, iqId, IQ_PROC_NONE, TlenIqResultVcard); + JabberSend(this, "%s", iqId, pNick); + mir_free(pNick); + } + mir_free(nick); + } + DBFreeVariant(&dbv); + } + return 0; +} + +int __cdecl TlenProtocol::SetApparentMode(HANDLE hContact, int mode) +{ + DBVARIANT dbv; + int oldMode; + char *jid; + + if (!isOnline) return 0; + if (!DBGetContactSettingByte(NULL, m_szModuleName, "VisibilitySupport", FALSE)) return 0; + if (mode != 0 && mode != ID_STATUS_ONLINE && mode != ID_STATUS_OFFLINE) return 1; + oldMode = DBGetContactSettingWord(hContact, m_szModuleName, "ApparentMode", 0); + if ((int) mode == oldMode) return 1; + DBWriteContactSettingWord(hContact, m_szModuleName, "ApparentMode", (WORD) mode); + if (!DBGetContactSetting(hContact, m_szModuleName, "jid", &dbv)) { + jid = dbv.pszVal; + switch (mode) { + case ID_STATUS_ONLINE: + if (m_iStatus == ID_STATUS_INVISIBLE || oldMode == ID_STATUS_OFFLINE) + JabberSend(this, "available", jid); + break; + case ID_STATUS_OFFLINE: + if (m_iStatus != ID_STATUS_INVISIBLE || oldMode == ID_STATUS_ONLINE) + JabberSend(this, "", jid); + break; + case 0: + if (oldMode == ID_STATUS_ONLINE && m_iStatus == ID_STATUS_INVISIBLE) + JabberSend(this, "", jid); + else if (oldMode == ID_STATUS_OFFLINE && m_iStatus != ID_STATUS_INVISIBLE) + JabberSend(this, "available", jid); + break; + } + DBFreeVariant(&dbv); + } + return 0; +} + +typedef struct{ + TlenProtocol *proto; + HANDLE hContact; +} SENDACKTHREADDATA; + +static void __cdecl JabberSendMessageAckThread(void *ptr) +{ + SENDACKTHREADDATA *data = (SENDACKTHREADDATA *)ptr; + SleepEx(10, TRUE); + ProtoBroadcastAck(data->proto->m_szModuleName, data->hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, (HANDLE) 1, 0); + mir_free(data); +} + +static void __cdecl TlenSendMessageFailedThread(void *ptr) +{ + SENDACKTHREADDATA *data = (SENDACKTHREADDATA *)ptr; + SleepEx(10, TRUE); + ProtoBroadcastAck(data->proto->m_szModuleName, data->hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, (HANDLE) 2, 0); + mir_free(data); +} + +static void __cdecl TlenGetAwayMsgThread(void *ptr) +{ + DBVARIANT dbv; + JABBER_LIST_ITEM *item; + SENDACKTHREADDATA *data = (SENDACKTHREADDATA *)ptr; + if (!DBGetContactSetting(data->hContact, data->proto->m_szModuleName, "jid", &dbv)) { + if ((item=JabberListGetItemPtr(data->proto, LIST_ROSTER, dbv.pszVal)) != NULL) { + DBFreeVariant(&dbv); + if (item->statusMessage != NULL) { + ProtoBroadcastAck(data->proto->m_szModuleName, data->hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE) 1, (LPARAM) item->statusMessage); + return; + } + } + else { + DBFreeVariant(&dbv); + } + } + ProtoBroadcastAck(data->proto->m_szModuleName, data->hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE) 1, (LPARAM) ""); + mir_free(data); +} + +INT_PTR TlenSendAlert(void *ptr, LPARAM wParam, LPARAM lParam) +{ + HANDLE hContact = ( HANDLE )wParam; + DBVARIANT dbv; + TlenProtocol *proto = (TlenProtocol *)ptr; + if (proto->isOnline && !DBGetContactSetting(hContact, proto->m_szModuleName, "jid", &dbv)) { + JabberSend(proto, "", dbv.pszVal); + + DBFreeVariant(&dbv); + } + return 0; +} + +int __cdecl TlenProtocol::SendMsg(HANDLE hContact, int flags, const char* msg) +{ + DBVARIANT dbv; + char *msgEnc; + JABBER_LIST_ITEM *item; + int id; + char msgType[16]; + + if (!isOnline || DBGetContactSetting(hContact, m_szModuleName, "jid", &dbv)) { + SENDACKTHREADDATA *tdata = (SENDACKTHREADDATA*) mir_alloc(sizeof(SENDACKTHREADDATA)); + tdata->proto = this; + tdata->hContact = hContact; + JabberForkThread(TlenSendMessageFailedThread, 0, (void *) tdata); + return 2; + } + if (!strcmp(msg, "")) { + SENDACKTHREADDATA *tdata = (SENDACKTHREADDATA*) mir_alloc(sizeof(SENDACKTHREADDATA)); + tdata->proto = this; + tdata->hContact = hContact; + JabberSend(this, "", dbv.pszVal); + JabberForkThread(JabberSendMessageAckThread, 0, (void *) tdata); + } else if (!strcmp(msg, "")) { + SENDACKTHREADDATA *tdata = (SENDACKTHREADDATA*) mir_alloc(sizeof(SENDACKTHREADDATA)); + tdata->proto = this; + tdata->hContact = hContact; + id = JabberSerialNext(this); + JabberSend(this, "", dbv.pszVal, "pic", 0x757f044, id); + JabberForkThread(JabberSendMessageAckThread, 0, (void *) tdata); + } else { + if ((msgEnc=JabberTextEncode(msg)) != NULL) { + if (JabberListExist(this, LIST_CHATROOM, dbv.pszVal) && strchr(dbv.pszVal, '/') == NULL) { + strcpy(msgType, "groupchat"); + } else if (DBGetContactSettingByte(hContact, m_szModuleName, "bChat", FALSE)) { + strcpy(msgType, "privchat"); + } else { + strcpy(msgType, "chat"); + } + if (!strcmp(msgType, "groupchat") || DBGetContactSettingByte(NULL, m_szModuleName, "MsgAck", FALSE) == FALSE) { + SENDACKTHREADDATA *tdata = (SENDACKTHREADDATA*) mir_alloc(sizeof(SENDACKTHREADDATA)); + tdata->proto = this; + tdata->hContact = hContact; + if (!strcmp(msgType, "groupchat")) { + JabberSend(this, "%s", dbv.pszVal, msgType, msgEnc); + } else if (!strcmp(msgType, "privchat")) { + JabberSend(this, "%s", dbv.pszVal, msgEnc); + } else { + id = JabberSerialNext(this); + JabberSend(this, "%s", dbv.pszVal, msgType, id, msgEnc); + } + JabberForkThread(JabberSendMessageAckThread, 0, (void *) tdata); + } + else { + id = JabberSerialNext(this); + if ((item=JabberListGetItemPtr(this, LIST_ROSTER, dbv.pszVal)) != NULL) + item->idMsgAckPending = id; + JabberSend(this, "%s", dbv.pszVal, msgType, id, msgEnc); + } + } + mir_free(msgEnc); + } + DBFreeVariant(&dbv); + return 1; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// JabberGetAvatarInfo - retrieves the avatar info + +static INT_PTR TlenGetAvatarInfo(void *ptr, LPARAM wParam, LPARAM lParam) +{ + BOOL downloadingAvatar = FALSE; + char *avatarHash = NULL; + JABBER_LIST_ITEM *item = NULL; + DBVARIANT dbv; + TlenProtocol *proto = (TlenProtocol *)ptr; + PROTO_AVATAR_INFORMATIONT* AI = ( PROTO_AVATAR_INFORMATIONT* )lParam; + if (!proto->tlenOptions.enableAvatars) return GAIR_NOAVATAR; + + if (AI->hContact != NULL) { + if (!DBGetContactSetting(AI->hContact, proto->m_szModuleName, "jid", &dbv)) { + item = JabberListGetItemPtr(proto, LIST_ROSTER, dbv.pszVal); + DBFreeVariant(&dbv); + if (item != NULL) { + downloadingAvatar = item->newAvatarDownloading; + avatarHash = item->avatarHash; + } + } + } else { + if (proto->threadData != NULL) { + avatarHash = proto->threadData->avatarHash; + } + } + if ((avatarHash == NULL || avatarHash[0] == '\0') && !downloadingAvatar) { + return GAIR_NOAVATAR; + } + if (avatarHash != NULL && !downloadingAvatar) { + TlenGetAvatarFileName(proto, item, AI->filename, sizeof(AI->filename)); + AI->format = ( AI->hContact == NULL ) ? proto->threadData->avatarFormat : item->avatarFormat; + return GAIR_SUCCESS; + } + if (( wParam & GAIF_FORCE ) != 0 && AI->hContact != NULL && proto->isOnline) { + /* get avatar */ + return GAIR_WAITFOR; + } + return GAIR_NOAVATAR; +} + +HANDLE __cdecl TlenProtocol::GetAwayMsg(HANDLE hContact) +{ + SENDACKTHREADDATA *tdata = (SENDACKTHREADDATA*) mir_alloc(sizeof(SENDACKTHREADDATA)); + tdata->proto = this; + tdata->hContact = hContact; + JabberForkThread((void (__cdecl *)(void*))TlenGetAwayMsgThread, 0, (void *) tdata); + return (HANDLE)1; +} + +int __cdecl TlenProtocol::RecvAwayMsg(HANDLE hContact, int mode, PROTORECVEVENT* evt) +{ + return 0; +} + +int __cdecl TlenProtocol::SendAwayMsg(HANDLE hContact, HANDLE hProcess, const char* msg) +{ + return 0; +} + +HANDLE __cdecl TlenProtocol::FileAllow(HANDLE hContact, HANDLE hTransfer, const PROTOCHAR* szPath) +{ + TLEN_FILE_TRANSFER *ft; + JABBER_LIST_ITEM *item; + char *nick; + + if (!isOnline) return 0; + + ft = (TLEN_FILE_TRANSFER *) hTransfer; + ft->szSavePath = mir_strdup(mir_t2a(szPath)); //TODO convert to PROTOCHAR* + if ((item=JabberListAdd(this, LIST_FILE, ft->iqId)) != NULL) { + item->ft = ft; + } + nick = JabberNickFromJID(ft->jid); + if (ft->newP2P) { + JabberSend(this, "", ft->jid, ft->jid, ft->iqId); + } else { + JabberSend(this, "", nick, ft->iqId); + } + mir_free(nick); + return (HANDLE)hTransfer; +} + +int __cdecl TlenProtocol::FileDeny(HANDLE hContact, HANDLE hTransfer, const PROTOCHAR* szReason) +{ + TLEN_FILE_TRANSFER *ft; + char *nick; + + if (!isOnline) return 1; + + ft = (TLEN_FILE_TRANSFER *) hTransfer; + nick = JabberNickFromJID(ft->jid); + if (ft->newP2P) { + JabberSend(this, "", ft->iqId, nick);\ + } else { + JabberSend(this, "", ft->iqId, nick);\ + } + mir_free(nick); + TlenP2PFreeFileTransfer(ft); + return 0; +} + +int __cdecl TlenProtocol::FileResume(HANDLE hTransfer, int* action, const PROTOCHAR** szFilename) { + return 0; +} + +int __cdecl TlenProtocol::FileCancel(HANDLE hContact, HANDLE hTransfer) +{ + TLEN_FILE_TRANSFER *ft = (TLEN_FILE_TRANSFER *) hTransfer; + JabberLog(this, "Invoking FileCancel()"); + if (ft->s != NULL) { + ft->state = FT_ERROR; + Netlib_CloseHandle(ft->s); + ft->s = NULL; + if (ft->hFileEvent != NULL) { + HANDLE hEvent = ft->hFileEvent; + ft->hFileEvent = NULL; + SetEvent(hEvent); + } + } else { + TlenP2PFreeFileTransfer(ft); + } + return 0; +} + +HANDLE __cdecl TlenProtocol::SendFile(HANDLE hContact, const PROTOCHAR* szDescription, PROTOCHAR** ppszFiles) +{ + TLEN_FILE_TRANSFER *ft; + int i, j; + struct _stat statbuf; + DBVARIANT dbv; + char *nick, *p, idStr[10]; + JABBER_LIST_ITEM *item; + int id; + + if (!isOnline) return 0; +// if (DBGetContactSettingWord(ccs->hContact, m_szModuleName, "Status", ID_STATUS_OFFLINE) == ID_STATUS_OFFLINE) return 0; + if (DBGetContactSetting(hContact, m_szModuleName, "jid", &dbv)) return 0; + ft = TlenFileCreateFT(this, dbv.pszVal); + for (ft->fileCount=0; ppszFiles[ft->fileCount]; ft->fileCount++); + ft->files = (char **) mir_alloc(sizeof(char *) * ft->fileCount); + ft->filesSize = (long *) mir_alloc(sizeof(long) * ft->fileCount); + ft->allFileTotalSize = 0; + for (i=j=0; ifileCount; i++) { + char* ppszFiles_i_A = mir_t2a(ppszFiles[i]); + if (_stat(ppszFiles_i_A, &statbuf)) + JabberLog(this, "'%s' is an invalid filename", ppszFiles[i]); + else { + ft->filesSize[j] = statbuf.st_size; + ft->files[j++] = mir_strdup(ppszFiles_i_A); + ft->allFileTotalSize += statbuf.st_size; + } + mir_free(ppszFiles_i_A); + } + ft->fileCount = j; + ft->szDescription = mir_t2a(szDescription); + ft->hContact = hContact; + ft->currentFile = 0; + DBFreeVariant(&dbv); + + id = JabberSerialNext(this); + _snprintf(idStr, sizeof(idStr), "%d", id); + if ((item=JabberListAdd(this, LIST_FILE, idStr)) != NULL) { + ft->iqId = mir_strdup(idStr); + nick = JabberNickFromJID(ft->jid); + item->ft = ft; + if (tlenOptions.useNewP2P) { + JabberSend(this, "", + ft->jid, ft->jid, idStr, ft->fileCount, ft->allFileTotalSize, ft->fileCount); + + ft->newP2P = TRUE; + } else { + if (ft->fileCount == 1) { + char* ppszFiles_0_A = mir_t2a(ppszFiles[0]); + if ((p=strrchr(ppszFiles_0_A, '\\')) != NULL) { + p++; + } else { + p = ppszFiles_0_A; + } + p = JabberTextEncode(p); + JabberSend(this, "", nick, p, idStr, ft->allFileTotalSize); + mir_free(ppszFiles[0]); + mir_free(p); + } else { + JabberSend(this, "", nick, idStr, ft->fileCount, ft->allFileTotalSize); + } + } + mir_free(nick); + } + + return (HANDLE) ft; +} + +int __cdecl TlenProtocol::SendContacts(HANDLE hContact, int flags, int nContacts, HANDLE* hContactsList){ + return 0; +} + +int __cdecl TlenProtocol::SendUrl(HANDLE hContact, int flags, const char* urlt){ + return 0; +} + +int __cdecl TlenProtocol::RecvMsg(HANDLE hContact, PROTORECVEVENT* evt) +{ + return Proto_RecvMessage(hContact, evt); +} + +int __cdecl TlenProtocol::RecvFile(HANDLE hContact, PROTOFILEEVENT* evt) +{ + return Proto_RecvFile(hContact, evt); +} + +int __cdecl TlenProtocol::RecvUrl(HANDLE hContact, PROTORECVEVENT*){ + return 0; +} + +static char* settingToChar( DBCONTACTWRITESETTING* cws ) +{ + switch( cws->value.type ) { + case DBVT_ASCIIZ: + return mir_strdup( cws->value.pszVal ); + case DBVT_UTF8: + return mir_utf8decode(mir_strdup(cws->value.pszVal), NULL); + } + return NULL; +} + +int JabberDbSettingChanged(void *ptr, WPARAM wParam, LPARAM lParam) +{ + DBCONTACTWRITESETTING *cws = (DBCONTACTWRITESETTING *) lParam; + TlenProtocol *proto = (TlenProtocol *)ptr; + // no action for hContact == NULL or when offline + if ((HANDLE) wParam == NULL) return 0; + if (!proto->isConnected) return 0; + + if (!strcmp(cws->szModule, "CList")) { + HANDLE hContact; + DBVARIANT dbv; + JABBER_LIST_ITEM *item; + char *szProto, *nick, *jid, *group; + + hContact = (HANDLE) wParam; + szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0); + if (szProto == NULL || strcmp(szProto, proto->m_szModuleName)) return 0; +// if (DBGetContactSettingByte(hContact, proto->m_szModuleName, "ChatRoom", 0) != 0) return 0; + // A contact's group is changed + if (!strcmp(cws->szSetting, "Group")) { + if (!DBGetContactSetting(hContact, proto->m_szModuleName, "jid", &dbv)) { + if ((item=JabberListGetItemPtr(proto, LIST_ROSTER, dbv.pszVal)) != NULL) { + DBFreeVariant(&dbv); + if (!DBGetContactSetting(hContact, "CList", "MyHandle", &dbv)) { + nick = JabberTextEncode(dbv.pszVal); + DBFreeVariant(&dbv); + } else if (!DBGetContactSetting(hContact, proto->m_szModuleName, "Nick", &dbv)) { + nick = JabberTextEncode(dbv.pszVal); + DBFreeVariant(&dbv); + } else { + nick = JabberNickFromJID(item->jid); + } + if (nick != NULL) { + // Note: we need to compare with item->group to prevent infinite loop + if (cws->value.type == DBVT_DELETED && item->group != NULL) { + JabberLog(proto, "Group set to nothing"); + JabberSend(proto, "", nick, item->jid); + } else if (cws->value.pszVal != NULL) { + char *newGroup = settingToChar(cws); + if (item->group == NULL || strcmp(newGroup, item->group)) { + JabberLog(proto, "Group set to %s", newGroup); + if ((group=TlenGroupEncode(newGroup)) != NULL) { + JabberSend(proto, "%s", nick, item->jid, group); + mir_free(group); + } + } + mir_free(newGroup); + } + mir_free(nick); + } + } + else { + DBFreeVariant(&dbv); + } + } + } + // A contact is renamed + else if (!strcmp(cws->szSetting, "MyHandle")) { + char *newNick; + +// hContact = (HANDLE) wParam; +// szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0); +// if (szProto == NULL || strcmp(szProto, proto->m_szModuleName)) return 0; + + if (!DBGetContactSetting(hContact, proto->m_szModuleName, "jid", &dbv)) { + jid = dbv.pszVal; + if ((item=JabberListGetItemPtr(proto, LIST_ROSTER, dbv.pszVal)) != NULL) { + if (cws->value.type == DBVT_DELETED) { + newNick = mir_strdup((char *) CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM) hContact, GCDNF_NOMYHANDLE)); + } else if (cws->value.pszVal != NULL) { + newNick = settingToChar(cws); + } else { + newNick = NULL; + } + // Note: we need to compare with item->nick to prevent infinite loop + if (newNick != NULL && (item->nick == NULL || (item->nick != NULL && strcmp(item->nick, newNick)))) { + if ((nick=JabberTextEncode(newNick)) != NULL) { + JabberLog(proto, "Nick set to %s", newNick); + if (item->group != NULL && (group=TlenGroupEncode(item->group)) != NULL) { + JabberSend(proto, "%s", nick, jid, group); + mir_free(group); + } else { + JabberSend(proto, "", nick, jid); + } + mir_free(nick); + } + } + if (newNick != NULL) mir_free(newNick); + } + DBFreeVariant(&dbv); + } + } + // A temporary contact has been added permanently + else if (!strcmp(cws->szSetting, "NotOnList")) { + char *jid, *nick, *pGroup; + + if (cws->value.type==DBVT_DELETED || (cws->value.type==DBVT_BYTE && cws->value.bVal==0)) { + if (!DBGetContactSetting(hContact, proto->m_szModuleName, "jid", &dbv)) { + jid = mir_strdup(dbv.pszVal); + DBFreeVariant(&dbv); + JabberLog(proto, "Add %s permanently to list", jid); + if (!DBGetContactSetting(hContact, "CList", "MyHandle", &dbv)) { + nick = JabberTextEncode(dbv.pszVal); //Utf8Encode + DBFreeVariant(&dbv); + } + else { + nick = JabberNickFromJID(jid); + } + if (nick != NULL) { + JabberLog(proto, "jid=%s nick=%s", jid, nick); + if (!DBGetContactSetting(hContact, "CList", "Group", &dbv)) { + if ((pGroup=TlenGroupEncode(dbv.pszVal)) != NULL) { + JabberSend(proto, "%s", nick, jid, pGroup); + JabberSend(proto, "", jid); + mir_free(pGroup); + } + DBFreeVariant(&dbv); + } + else { + JabberSend(proto, "", nick, jid); + JabberSend(proto, "", jid); + } + mir_free(nick); + DBDeleteContactSetting(hContact, "CList", "Hidden"); + } + mir_free(jid); + } + } + } + } + + return 0; +} + +int JabberContactDeleted(void *ptr, WPARAM wParam, LPARAM lParam) +{ + char *szProto; + DBVARIANT dbv; + TlenProtocol *proto = (TlenProtocol *)ptr; + + if (!proto->isOnline) // should never happen + return 0; + szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0); + if (szProto == NULL || strcmp(szProto, proto->m_szModuleName)) + return 0; + if (!DBGetContactSetting((HANDLE) wParam, proto->m_szModuleName, "jid", &dbv)) { + char *jid, *p, *q; + + jid = dbv.pszVal; + if ((p=strchr(jid, '@')) != NULL) { + if ((q=strchr(p, '/')) != NULL) + *q = '\0'; + } + if (JabberListExist(proto, LIST_ROSTER, jid)) { + // Remove from roster, server also handles the presence unsubscription process. + JabberSend(proto, "", jid); + } + + DBFreeVariant(&dbv); + } + return 0; +} + +int __cdecl TlenProtocol::UserIsTyping(HANDLE hContact, int type) +{ + DBVARIANT dbv; + JABBER_LIST_ITEM *item; + + if (!isOnline) return 0; + if (!DBGetContactSetting(hContact, m_szModuleName, "jid", &dbv)) { + if ((item=JabberListGetItemPtr(this, LIST_ROSTER, dbv.pszVal)) != NULL /*&& item->wantComposingEvent == TRUE*/) { + switch (type) { + case PROTOTYPE_SELFTYPING_OFF: + JabberSend(this, "", dbv.pszVal); + break; + case PROTOTYPE_SELFTYPING_ON: + JabberSend(this, "", dbv.pszVal); + break; + } + } + DBFreeVariant(&dbv); + } + return 0; +} + +INT_PTR TlenGetMyAvatar(void *ptr, LPARAM wParam, LPARAM lParam) +{ + TCHAR* buf = (TCHAR*)wParam; + int size = ( int )lParam; + TlenProtocol *proto = (TlenProtocol *)ptr; + + if ( buf == NULL || size <= 0 ) + return -1; + + TlenGetAvatarFileName( proto, NULL, buf, size ); + //wParam (buf) is output var + return 0; +} + +static INT_PTR CALLBACK TlenChangeAvatarDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + switch ( msg ) { + case WM_INITDIALOG: + TranslateDialogDefault( hwndDlg ); + { + HICON hIcon = GetIcolibIcon(IDI_TLEN); + SendMessage(hwndDlg, WM_SETICON, (WPARAM) ICON_BIG, (LPARAM) hIcon); + ReleaseIcolibIcon(hIcon); + } + CheckDlgButton(hwndDlg, IDC_PUBLICAVATAR, TRUE); + return TRUE; + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDOK: + { + int result = LOWORD(wParam); + if (IsDlgButtonChecked(hwndDlg, IDC_PUBLICAVATAR)) { + result |= 0x10000; + } + EndDialog(hwndDlg, result); + } + return TRUE; + } + break; + } + return 0; +} + +INT_PTR TlenSetMyAvatar(void *ptr, LPARAM wParam, LPARAM lParam) +{ + TCHAR* szFileName = ( TCHAR* )lParam; + TCHAR tFileName[ MAX_PATH ]; + int fileIn; + TlenProtocol *proto = (TlenProtocol *)ptr; + if (!proto->isOnline) return 1; + if (szFileName != NULL) { + int result = DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_USER_CHANGEAVATAR), NULL, TlenChangeAvatarDlgProc, (LPARAM) NULL); + TlenGetAvatarFileName( proto, NULL, tFileName, MAX_PATH); + if ( CopyFile( szFileName, tFileName, FALSE ) == FALSE ) { + return 1; + } + char* tFileNameA = mir_t2a(tFileName); //TODO - drop io.h + fileIn = open( tFileNameA, O_RDWR | O_BINARY, S_IREAD | S_IWRITE ); + if ( fileIn != -1 ) { + long dwPngSize = filelength(fileIn); + BYTE* pResult = (BYTE *)mir_alloc(dwPngSize); + if (pResult != NULL) { + read( fileIn, pResult, dwPngSize ); + close( fileIn ); + TlenUploadAvatar(proto, pResult, dwPngSize, (result & 0x10000) != 0); + mir_free(pResult); + } + } + mir_free(tFileName); + mir_free(tFileNameA); + } else { + TlenRemoveAvatar(proto); + } + return 0; +} + +INT_PTR TlenGetAvatarCaps(void *ptr, LPARAM wParam, LPARAM lParam) +{ + TlenProtocol *proto = (TlenProtocol *)ptr; + switch (wParam) { + case AF_MAXSIZE: + { + POINT* size = (POINT*)lParam; + if ( size ) + size->x = size->y = 64; + } + return 0; + case AF_PROPORTION: + return PIP_SQUARE; + case AF_FORMATSUPPORTED: + return (lParam == PA_FORMAT_PNG) ? 1 : 0; + case AF_ENABLED: + return (proto->tlenOptions.enableAvatars && proto->isOnline) ? 1 : 0; + case AF_DONTNEEDDELAYS: + return 1; + case AF_MAXFILESIZE: + return 10 * 1024; + case AF_DELAYAFTERFAIL: + return 0; + } + return 0; +} + +int __cdecl TlenProtocol::OnEvent(PROTOEVENTTYPE iEventType, WPARAM wParam, LPARAM lParam) +{ + //TlenProtocol *proto = (TlenProtocol *)ptr; + switch( iEventType ) { + case EV_PROTO_ONLOAD: return TlenOnModulesLoaded(this, 0, 0 ); + case EV_PROTO_ONOPTIONS: return TlenOptionsInit(this, wParam, lParam ); + case EV_PROTO_ONEXIT: return TlenPreShutdown(this, 0, 0 ); + case EV_PROTO_ONRENAME: + { + CLISTMENUITEM clmi = { 0 }; + clmi.cbSize = sizeof( CLISTMENUITEM ); + clmi.flags = CMIM_NAME | CMIF_TCHAR; + clmi.ptszName = m_tszUserName; + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hMenuRoot, ( LPARAM )&clmi ); + /* FIXME: Rename network user as well */ + } + } + return 1; +} + +// PSS_ADDED +int __cdecl TlenProtocol::AuthRecv(HANDLE hContact, PROTORECVEVENT* evt) +{ + return 1; +} + +// PSS_AUTHREQUEST +int __cdecl TlenProtocol::AuthRequest(HANDLE hContact, const PROTOCHAR* szMessage) +{ + return 1; +} + +HANDLE __cdecl TlenProtocol::ChangeInfo(int iInfoType, void* pInfoData) +{ + return NULL; +} + + +int __cdecl TlenProtocol::RecvContacts(HANDLE hContact, PROTORECVEVENT* evt) +{ + return 1; +} + + +extern INT_PTR CALLBACK TlenAccMgrUIDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); + +INT_PTR TlenAccMgrUI(void *ptr, LPARAM wParam, LPARAM lParam) +{ + return (INT_PTR) CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_ACCMGRUI), (HWND)lParam, TlenAccMgrUIDlgProc, (LPARAM) ptr); +} + +void TlenInitServicesVTbl(TlenProtocol *proto) { + + char s[128]; + + sprintf(s, "%s%s", proto->m_szModuleName, PS_GETNAME); + CreateServiceFunction_Ex(s, proto, TlenGetName); + + sprintf(s, "%s%s", proto->m_szModuleName, PS_GETAVATARINFO); + CreateServiceFunction_Ex(s, proto, TlenGetAvatarInfo); + + sprintf(s, "%s%s", proto->m_szModuleName, "/SendNudge"); + CreateServiceFunction_Ex(s, proto, TlenSendAlert); + + sprintf(s, "%s%s", proto->m_szModuleName, PS_GETAVATARCAPS); + CreateServiceFunction_Ex(s, proto, TlenGetAvatarCaps); + + sprintf(s, "%s%s", proto->m_szModuleName, PS_SETMYAVATART); + CreateServiceFunction_Ex(s, proto, TlenSetMyAvatar); + + sprintf(s, "%s%s", proto->m_szModuleName, PS_GETMYAVATART); + CreateServiceFunction_Ex(s, proto, TlenGetMyAvatar); + + sprintf(s, "%s%s", proto->m_szModuleName, PS_GETSTATUS); + CreateServiceFunction_Ex(s, proto, TlenGetStatus); + + sprintf(s, "%s%s", proto->m_szModuleName, PS_CREATEACCMGRUI); + CreateServiceFunction_Ex(s, proto, TlenAccMgrUI); + +} + +TlenProtocol::TlenProtocol( const char* aProtoName, const TCHAR* aUserName ) +{ + + m_iVersion = 2; + m_tszUserName = mir_tstrdup(aUserName); + m_szModuleName = mir_strdup(aProtoName); + m_szProtoName = mir_strdup(aProtoName); + _strlwr( m_szProtoName ); + m_szProtoName[0] = toupper( m_szProtoName[0] ); + m_iStatus = ID_STATUS_OFFLINE; + + TlenInitServicesVTbl(this); + + InitializeCriticalSection(&modeMsgMutex); + InitializeCriticalSection(&csSend); + + char text[_MAX_PATH]; + sprintf(text, "%s/%s", m_szModuleName, "Nudge"); + hTlenNudge = CreateHookableEvent(text); + + HookEventObj_Ex(ME_SYSTEM_MODULESLOADED, this, TlenSystemModulesLoaded); + HookEventObj_Ex(ME_OPT_INITIALISE, this, TlenOptionsInit); + HookEventObj_Ex(ME_DB_CONTACT_SETTINGCHANGED, this, JabberDbSettingChanged); + HookEventObj_Ex(ME_DB_CONTACT_DELETED, this, JabberContactDeleted); + HookEventObj_Ex(ME_CLIST_PREBUILDCONTACTMENU, this, TlenPrebuildContactMenu); +// HookEventObj_Ex(ME_SKIN2_ICONSCHANGED, this, TlenIconsChanged); + HookEventObj_Ex(ME_SYSTEM_PRESHUTDOWN, this, TlenPreShutdown); + + + DBVARIANT dbv; + if (!DBGetContactSetting(NULL, m_szModuleName, "LoginServer", &dbv)) { + DBFreeVariant(&dbv); + } else { + DBWriteContactSettingString(NULL, m_szModuleName, "LoginServer", "tlen.pl"); + } + if (!DBGetContactSetting(NULL, m_szModuleName, "ManualHost", &dbv)) { + DBFreeVariant(&dbv); + } else { + DBWriteContactSettingString(NULL, m_szModuleName, "ManualHost", "s1.tlen.pl"); + } + + TlenLoadOptions(this); + + JabberWsInit(this); + JabberSerialInit(this); + JabberIqInit(this); + JabberListInit(this); + +} + +TlenProtocol::~TlenProtocol() +{ + + uninitMenuItems(this); + TlenVoiceCancelAll(this); + TlenFileCancelAll(this); + if (hTlenNudge) + DestroyHookableEvent(hTlenNudge); + UnhookEvents_Ex(this); + JabberListUninit(this); + JabberIqUninit(this); + JabberSerialUninit(this); + DeleteCriticalSection(&modeMsgMutex); + DeleteCriticalSection(&csSend); + //DestroyServices_Ex(this); + JabberWsUninit(this); + + mir_free(modeMsgs.szOnline); + mir_free(modeMsgs.szAway); + mir_free(modeMsgs.szNa); + mir_free(modeMsgs.szDnd); + mir_free(modeMsgs.szFreechat); + mir_free(modeMsgs.szInvisible); + +} + + diff --git a/protocols/Tlen/src/jabber_thread.cpp b/protocols/Tlen/src/jabber_thread.cpp new file mode 100644 index 0000000000..b9fe951ee1 --- /dev/null +++ b/protocols/Tlen/src/jabber_thread.cpp @@ -0,0 +1,1467 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Tlen Protocol Plugin for Miranda NG +Copyright (C) 2002-2004 Santithorn Bunchua +Copyright (C) 2004-2007 Piotr Piastucki + +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 "commons.h" +#include "jabber_list.h" +#include "jabber_iq.h" +#include "resource.h" +#include "tlen_p2p_old.h" +#include "tlen_file.h" +#include "tlen_muc.h" +#include "tlen_voice.h" +#include "tlen_avatar.h" +#include "tlen_presence.h" +#include "tlen_picture.h" +#include +#include +#include + + +extern void __cdecl TlenProcessP2P(XmlNode *node, ThreadData *info); + + +//static void __cdecl TlenProcessInvitation(struct ThreadData *info); +static void __cdecl JabberKeepAliveThread(void *ptr); +static void JabberProcessStreamOpening(XmlNode *node, ThreadData *info); +static void JabberProcessStreamClosing(XmlNode *node, ThreadData *info); +static void JabberProcessProtocol(XmlNode *node, ThreadData *info); +static void JabberProcessMessage(XmlNode *node, ThreadData *info); +static void JabberProcessIq(XmlNode *node, ThreadData *info); +static void TlenProcessW(XmlNode *node, ThreadData *info); +static void TlenProcessM(XmlNode *node, ThreadData *info); +static void TlenProcessN(XmlNode *node, ThreadData *info); +static void TlenProcessP(XmlNode *node, ThreadData *info); +static void TlenProcessV(XmlNode *node, ThreadData *info); +static void TlenProcessAvatar(XmlNode* node, ThreadData *info); +static void TlenProcessCipher(XmlNode *node, ThreadData *info); + +static VOID NTAPI JabberDummyApcFunc(ULONG_PTR param) +{ + return; +} + +static char onlinePassword[128]; +static HANDLE hEventPasswdDlg; + +static INT_PTR CALLBACK JabberPasswordDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + char text[128]; + + switch (msg) { + case WM_INITDIALOG: + TranslateDialogDefault(hwndDlg); + sprintf(text, "%s %s", Translate("Enter password for"), (char *) lParam); + SetDlgItemTextA(hwndDlg, IDC_JID, text); + return TRUE; + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDOK: + GetDlgItemTextA(hwndDlg, IDC_PASSWORD, onlinePassword, sizeof(onlinePassword)); + //EndDialog(hwndDlg, (int) onlinePassword); + //return TRUE; + // Fall through + case IDCANCEL: + //EndDialog(hwndDlg, 0); + SetEvent(hEventPasswdDlg); + DestroyWindow(hwndDlg); + return TRUE; + } + break; + } + + return FALSE; +} + +static VOID NTAPI JabberPasswordCreateDialogApcProc(ULONG_PTR param) +{ + CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_PASSWORD), NULL, JabberPasswordDlgProc, (LPARAM) param); +} + +void __cdecl JabberServerThread(ThreadData *info) +{ + DBVARIANT dbv; + char jidStr[128]; + char *connectHost; + char *buffer; + int datalen; + XmlState xmlState; + HANDLE hContact; + int jabberNetworkBufferSize; + int oldStatus = ID_STATUS_OFFLINE; + int reconnectMaxTime; + int numRetry; + int reconnectTime; + char *str; + CLISTMENUITEM clmi; + int loginErr = 0; + JabberLog(info->proto, "Thread started"); + + + // Normal server connection, we will fetch all connection parameters + // e.g. username, password, etc. from the database. + + if (info->proto->threadData != NULL) { + // Will not start another connection thread if a thread is already running. + // Make APC call to the main thread. This will immediately wake the thread up + // in case it is asleep in the reconnect loop so that it will immediately + // reconnect. + QueueUserAPC(JabberDummyApcFunc, info->proto->threadData->hThread, 0); + JabberLog(info->proto, "Thread ended, another normal thread is running"); + mir_free(info); + return; + } + + info->proto->threadData = info; + + if (!DBGetContactSetting(NULL, info->proto->m_szModuleName, "LoginName", &dbv)) { + strncpy(info->username, dbv.pszVal, sizeof(info->username)); + info->username[sizeof(info->username)-1] = '\0'; + _strlwr(info->username); + DBWriteContactSettingString(NULL, info->proto->m_szModuleName, "LoginName", info->username); + DBFreeVariant(&dbv); + + } else { + JabberLog(info->proto, "Thread ended, login name is not configured"); + loginErr = LOGINERR_BADUSERID; + } + + if (loginErr == 0) { + if (!DBGetContactSetting(NULL, info->proto->m_szModuleName, "LoginServer", &dbv)) { + strncpy(info->server, dbv.pszVal, sizeof(info->server)); + info->server[sizeof(info->server)-1] = '\0'; + _strlwr(info->server); + DBWriteContactSettingString(NULL, info->proto->m_szModuleName, "LoginServer", info->server); + DBFreeVariant(&dbv); + } else { + JabberLog(info->proto, "Thread ended, login server is not configured"); + loginErr = LOGINERR_NONETWORK; + } + } + + if (loginErr == 0) { + if (!info->proto->tlenOptions.savePassword) { + // Ugly hack: continue logging on only the return value is &(onlinePassword[0]) + // because if WM_QUIT while dialog box is still visible, p is returned with some + // exit code which may not be NULL. + // Should be better with modeless. + onlinePassword[0] = (char) -1; + hEventPasswdDlg = CreateEvent(NULL, FALSE, FALSE, NULL); + QueueUserAPC(JabberPasswordCreateDialogApcProc, hMainThread, (DWORD) jidStr); + WaitForSingleObject(hEventPasswdDlg, INFINITE); + CloseHandle(hEventPasswdDlg); + //if ((p=(char *)DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_PASSWORD), NULL, JabberPasswordDlgProc, (LPARAM) jidStr)) != onlinePassword) { + if (onlinePassword[0] != (char) -1) { + strncpy(info->password, onlinePassword, sizeof(info->password)); + info->password[sizeof(info->password)-1] = '\0'; + } else { + JabberLog(info->proto, "Thread ended, password request dialog was canceled"); + loginErr = LOGINERR_BADUSERID; + } + } else { + if (!DBGetContactSetting(NULL, info->proto->m_szModuleName, "Password", &dbv)) { + CallService(MS_DB_CRYPT_DECODESTRING, strlen(dbv.pszVal)+1, (LPARAM) dbv.pszVal); + strncpy(info->password, dbv.pszVal, sizeof(info->password)); + info->password[sizeof(info->password)-1] = '\0'; + DBFreeVariant(&dbv); + } else { + JabberLog(info->proto, "Thread ended, password is not configured"); + loginErr = LOGINERR_BADUSERID; + } + } + } + + jabberNetworkBufferSize = 2048; + if ((buffer=(char *) mir_alloc(jabberNetworkBufferSize+1)) == NULL) { // +1 is for '\0' when debug logging this buffer + JabberLog(info->proto, "Thread ended, network buffer cannot be allocated"); + loginErr = LOGINERR_NONETWORK; + } + + if (loginErr != 0) { + info->proto->threadData = NULL; + oldStatus = info->proto->m_iStatus; + info->proto->m_iStatus = ID_STATUS_OFFLINE; + ProtoBroadcastAck(info->proto->m_szModuleName, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE) oldStatus, info->proto->m_iStatus); + ProtoBroadcastAck(info->proto->m_szModuleName, NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, loginErr); + mir_free(info); + return; + } + + _snprintf(jidStr, sizeof(jidStr), "%s@%s", info->username, info->server); + DBWriteContactSettingString(NULL, info->proto->m_szModuleName, "jid", jidStr); + + if (!DBGetContactSetting(NULL, info->proto->m_szModuleName, "ManualHost", &dbv)) { + strncpy(info->manualHost, dbv.pszVal, sizeof(info->manualHost)); + info->manualHost[sizeof(info->manualHost)-1] = '\0'; + DBFreeVariant(&dbv); + } + info->port = DBGetContactSettingWord(NULL, info->proto->m_szModuleName, "ManualPort", TLEN_DEFAULT_PORT); + info->useEncryption = info->proto->tlenOptions.useEncryption; + + if (info->manualHost[0]) + connectHost = info->manualHost; + else + connectHost = info->server; + + JabberLog(info->proto, "Thread server='%s' port='%d'", connectHost, info->port); + + + if (!DBGetContactSetting(NULL, info->proto->m_szModuleName, "AvatarHash", &dbv)) { + strcpy(info->proto->threadData->avatarHash, dbv.pszVal); + DBFreeVariant(&dbv); + } + info->avatarFormat = DBGetContactSettingDword(NULL, info->proto->m_szModuleName, "AvatarFormat", PA_FORMAT_UNKNOWN); + + + reconnectMaxTime = 10; + numRetry = 0; + + for (;;) { // Reconnect loop + + info->s = JabberWsConnect(info->proto, connectHost, info->port); + if (info->s == NULL) { + JabberLog(info->proto, "Connection failed (%d)", WSAGetLastError()); + if (info->proto->threadData == info) { + oldStatus = info->proto->m_iStatus; + info->proto->m_iStatus = ID_STATUS_OFFLINE; + ProtoBroadcastAck(info->proto->m_szModuleName, NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_NONETWORK); + ProtoBroadcastAck(info->proto->m_szModuleName, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE) oldStatus, info->proto->m_iStatus); + if (info->proto->tlenOptions.reconnect == TRUE) { + reconnectTime = rand() % reconnectMaxTime; + JabberLog(info->proto, "Sleeping %d seconds before automatic reconnecting...", reconnectTime); + SleepEx(reconnectTime * 1000, TRUE); + if (reconnectMaxTime < 10*60) // Maximum is 10 minutes + reconnectMaxTime *= 2; + if (info->proto->threadData == info) { // Make sure this is still the active thread for the main Jabber connection + JabberLog(info->proto, "Reconnecting to the network..."); + if (numRetry < MAX_CONNECT_RETRIES) + numRetry++; + oldStatus = info->proto->m_iStatus; + info->proto->m_iStatus = ID_STATUS_CONNECTING + numRetry; + ProtoBroadcastAck(info->proto->m_szModuleName, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE) oldStatus, info->proto->m_iStatus); + continue; + } + else { + JabberLog(info->proto, "Thread ended, connection failed"); + mir_free(buffer); + mir_free(info); + return; + } + } + info->proto->threadData = NULL; + } + JabberLog(info->proto, "Thread ended, connection failed"); + mir_free(buffer); + mir_free(info); + return; + } + + // Determine local IP + /* + socket = CallService(MS_NETLIB_GETSOCKET, (WPARAM) proto, 0); + struct sockaddr_in saddr; + int len; + + len = sizeof(saddr); + getsockname(socket, (struct sockaddr *) &saddr, &len); + jabberLocalIP = saddr.sin_addr.S_un.S_addr; + JabberLog("Local IP = %s", inet_ntoa(saddr.sin_addr)); + */ + + // User may change status to OFFLINE while we are connecting above + if (info->proto->m_iDesiredStatus != ID_STATUS_OFFLINE) { + + info->proto->isConnected = TRUE; + JabberForkThread(JabberKeepAliveThread, 0, info->proto); + + JabberXmlInitState(&xmlState); + JabberXmlSetCallback(&xmlState, 1, ELEM_OPEN, (void (__cdecl *)(XmlNode *,void *))JabberProcessStreamOpening, info); + JabberXmlSetCallback(&xmlState, 1, ELEM_CLOSE, (void (__cdecl *)(XmlNode *,void *))JabberProcessStreamClosing, info); + JabberXmlSetCallback(&xmlState, 2, ELEM_CLOSE, (void (__cdecl *)(XmlNode *,void *))JabberProcessProtocol, info); + + info->useAES = FALSE; + + if (info->useEncryption) { + JabberSend(info->proto, ""); + + } else { + JabberSend(info->proto, ""); + } + + JabberLog(info->proto, "Entering main recv loop"); + datalen = 0; + + for (;;) { + int recvResult, bytesParsed; + + if (info->useAES) { + recvResult = JabberWsRecvAES(info->proto, buffer+datalen, jabberNetworkBufferSize-datalen, &info->aes_in_context, info->aes_in_iv); + } else { + recvResult = JabberWsRecv(info->proto, info->s, buffer+datalen, jabberNetworkBufferSize-datalen); + } + + if (recvResult <= 0) + break; + datalen += recvResult; + + buffer[datalen] = '\0'; + JabberLog(info->proto, "RECV:%s", buffer); + + bytesParsed = JabberXmlParse(&xmlState, buffer, datalen); + JabberLog(info->proto, "bytesParsed = %d", bytesParsed); + if (bytesParsed > 0) { + if (bytesParsed < datalen) + memmove(buffer, buffer+bytesParsed, datalen-bytesParsed); + datalen -= bytesParsed; + } + else if (datalen == jabberNetworkBufferSize) { + jabberNetworkBufferSize += 2048; + JabberLog(info->proto, "Increasing network buffer size to %d", jabberNetworkBufferSize); + if ((buffer=(char *) mir_realloc(buffer, jabberNetworkBufferSize+1)) == NULL) { + JabberLog(info->proto, "Cannot reallocate more network buffer, go offline now"); + break; + } + } + else { + JabberLog(info->proto, "Unknown state: bytesParsed=%d, datalen=%d, jabberNetworkBufferSize=%d", bytesParsed, datalen, jabberNetworkBufferSize); + } + } + + JabberXmlDestroyState(&xmlState); + + info->proto->isOnline = FALSE; + info->proto->isConnected = FALSE; + + memset(&clmi, 0, sizeof(CLISTMENUITEM)); + clmi.cbSize = sizeof(CLISTMENUITEM); + clmi.flags = CMIM_FLAGS | CMIF_GRAYED; + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM) info->proto->hMenuMUC, (LPARAM) &clmi); + if (info->proto->hMenuChats != NULL){ + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM) info->proto->hMenuChats, (LPARAM) &clmi); + } + + // Set status to offline + oldStatus = info->proto->m_iStatus; + info->proto->m_iStatus = ID_STATUS_OFFLINE; + ProtoBroadcastAck(info->proto->m_szModuleName, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE) oldStatus, info->proto->m_iStatus); + + // Set all contacts to offline + hContact = db_find_first(); + while (hContact != NULL) { + str = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0); + if (str != NULL && !strcmp(str, info->proto->m_szModuleName)) { + if (DBGetContactSettingWord(hContact, info->proto->m_szModuleName, "Status", ID_STATUS_OFFLINE) != ID_STATUS_OFFLINE) { + DBWriteContactSettingWord(hContact, info->proto->m_szModuleName, "Status", ID_STATUS_OFFLINE); + } + } + hContact = db_find_next(hContact); + } + + JabberListWipeSpecial(info->proto); + } + else { + oldStatus = info->proto->m_iStatus; + info->proto->m_iStatus = ID_STATUS_OFFLINE; + ProtoBroadcastAck(info->proto->m_szModuleName, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE) oldStatus, info->proto->m_iStatus); + } + + Netlib_CloseHandle(info->s); + + if (info->proto->tlenOptions.reconnect == FALSE) + break; + + if (info->proto->threadData != info) // Make sure this is still the main Jabber connection thread + break; + reconnectTime = rand() % 10; + JabberLog(info->proto, "Sleeping %d seconds before automatic reconnecting...", reconnectTime); + SleepEx(reconnectTime * 1000, TRUE); + reconnectMaxTime = 20; + if (info->proto->threadData != info) // Make sure this is still the main Jabber connection thread + break; + JabberLog(info->proto, "Reconnecting to the network..."); + info->proto->m_iDesiredStatus = oldStatus; // Reconnect to my last status + oldStatus = info->proto->m_iStatus; + info->proto->m_iStatus = ID_STATUS_CONNECTING; + numRetry = 1; + ProtoBroadcastAck(info->proto->m_szModuleName, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE) oldStatus, info->proto->m_iStatus); + } + + JabberLog(info->proto, "Thread ended: server='%s'", info->server); + + if (info->proto->threadData == info) { + info->proto->threadData = NULL; + } + + mir_free(buffer); + if (info->streamId) mir_free(info->streamId); + JabberLog(info->proto, "Exiting ServerThread"); + mir_free(info); +} + +static void TlenSendAuth(TlenProtocol *proto) { + int iqId; + char *p; + char *str; + char text[128]; + str = TlenPasswordHash(proto->threadData->password); + sprintf(text, "%s%s", proto->threadData->streamId, str); + mir_free(str); + str = JabberSha1(text); + if ((p=JabberTextEncode(proto->threadData->username)) != NULL) { + iqId = JabberSerialNext(proto->threadData->proto); + JabberIqAdd(proto, iqId, IQ_PROC_NONE, JabberIqResultAuth); + JabberSend(proto, "%s%sttlen.pl", iqId, p /*info->username*/, str); + mir_free(p); + } + mir_free(str); +} + +static void JabberProcessStreamOpening(XmlNode *node, ThreadData *info) +{ + char *sid, *s; + + if (node->name == NULL || strcmp(node->name, "s")) + return; + + if ((sid=JabberXmlGetAttrValue(node, "i")) != NULL) { + if (info->streamId) mir_free(info->streamId); + info->streamId = mir_strdup(sid); + } + if ((s=JabberXmlGetAttrValue(node, "s")) != NULL && !strcmp(s, "1")) { + int i; + char *k1, *k2, *k3; + unsigned char aes_key[32]; + char aes_key_str[140], aes_iv_str[40]; + mpi k1_mpi, k2_mpi, aes_mpi; + size_t slen; + + k1=JabberXmlGetAttrValue(node, "k1"); + k2=JabberXmlGetAttrValue(node, "k2"); + k3=JabberXmlGetAttrValue(node, "k3"); + + memset(&info->aes_in_context, 0, sizeof (aes_context)); + memset(&info->aes_out_context, 0, sizeof (aes_context)); + memset(&aes_mpi, 0, sizeof (mpi)); + mpi_read_string(&aes_mpi, 16, k3); + mpi_write_binary(&aes_mpi, info->aes_in_iv, 16); + for (i = 0; i < 16; i++) { + info->aes_out_iv[i] = rand(); + aes_key[i] = rand(); + } + memset(&aes_mpi, 0, sizeof (mpi)); + mpi_read_binary(&aes_mpi, info->aes_out_iv, 16); + slen = 40; + mpi_write_string(&aes_mpi, 16, aes_iv_str, &slen); + aes_setkey_dec(&info->aes_in_context, aes_key, 128); + aes_setkey_enc(&info->aes_out_context, aes_key, 128); + memset(&aes_mpi, 0, sizeof (mpi)); + mpi_read_binary(&aes_mpi, aes_key, 16); + memset(&k1_mpi, 0, sizeof (mpi)); + mpi_read_string( &k1_mpi, 16, k1 ); + memset(&k2_mpi, 0, sizeof (mpi)); + mpi_read_string( &k2_mpi, 16, k2 ); + memset(&aes_mpi, 0, sizeof (mpi)); + mpi_read_binary(&aes_mpi, (unsigned char *)aes_key, 16); + mpi_exp_mod( &aes_mpi, &aes_mpi, &k1_mpi, &k2_mpi, NULL ); + slen = 140; + mpi_write_string(&aes_mpi, 16, aes_key_str, &slen); + JabberSend(info->proto, "", aes_key_str, aes_iv_str); + } else { + TlenSendAuth(info->proto); + } +} + +static void JabberProcessStreamClosing(XmlNode *node, ThreadData *info) +{ + Netlib_CloseHandle(info->proto); + if (node->name && !strcmp(node->name, "stream:error") && node->text) + MessageBoxA(NULL, Translate(node->text), Translate("Jabber Connection Error"), MB_OK|MB_ICONERROR|MB_SETFOREGROUND); +} + +static void JabberProcessProtocol(XmlNode *node, ThreadData *info) +{ + if (!strcmp(node->name, "message")) + JabberProcessMessage(node, info); + else if (!strcmp(node->name, "presence")) + TlenProcessPresence(node, info->proto); + else if (!strcmp(node->name, "iq")) + JabberProcessIq(node, info); + else if (!strcmp(node->name, "f")) + TlenProcessF(node, info); + else if (!strcmp(node->name, "w")) + TlenProcessW(node, info); + else if (!strcmp(node->name, "m")) + TlenProcessM(node, info); + else if (!strcmp(node->name, "n")) + TlenProcessN(node, info); + else if (!strcmp(node->name, "p")) + TlenProcessP(node, info); + else if (!strcmp(node->name, "v")) + TlenProcessV(node, info); + else if (!strcmp(node->name, "avatar")) + TlenProcessAvatar(node, info); + else if (!strcmp(node->name, "cipher")) + TlenProcessCipher(node, info); + else + JabberLog(info->proto, "Invalid top-level tag (only

and allowed)"); + +} + +static void TlenProcessCipher(XmlNode *node, ThreadData *info) +{ + char *type; + type=JabberXmlGetAttrValue(node, "type"); + info->useAES = TRUE; + JabberSend(info->proto, ""); + TlenSendAuth(info->proto); +} + +static void TlenProcessIqGetVersion(TlenProtocol *proto, XmlNode* node) +{ + OSVERSIONINFO osvi = { 0 }; + char mversion[256]; + char* from, *version, *mver; + char* os = NULL; + JABBER_LIST_ITEM *item; + + if (proto->m_iStatus == ID_STATUS_INVISIBLE) return; + if (!proto->tlenOptions.enableVersion) return; + if (( from=JabberXmlGetAttrValue( node, "from" )) == NULL ) return; + if (( item=JabberListGetItemPtr( proto, LIST_ROSTER, from )) ==NULL) return; + version = JabberTextEncode( TLEN_VERSION_STRING ); + osvi.dwOSVersionInfoSize = sizeof( OSVERSIONINFO ); + if ( GetVersionEx( &osvi )) { + switch ( osvi.dwPlatformId ) { + case VER_PLATFORM_WIN32_NT: + if ( osvi.dwMajorVersion == 5 ) { + if ( osvi.dwMinorVersion == 2 ) os = JabberTextEncode( Translate( "Windows Server 2003" )); + else if ( osvi.dwMinorVersion == 1 ) os = JabberTextEncode( Translate( "Windows XP" )); + else if ( osvi.dwMinorVersion == 0 ) os = JabberTextEncode( Translate( "Windows 2000" )); + } + else if ( osvi.dwMajorVersion <= 4 ) { + os = JabberTextEncode( Translate( "Windows NT" )); + } + break; + case VER_PLATFORM_WIN32_WINDOWS: + if ( osvi.dwMajorVersion == 4 ) { + if ( osvi.dwMinorVersion == 0 ) os = JabberTextEncode( Translate( "Windows 95" )); + if ( osvi.dwMinorVersion == 10 ) os = JabberTextEncode( Translate( "Windows 98" )); + if ( osvi.dwMinorVersion == 90 ) os = JabberTextEncode( Translate( "Windows ME" )); + } + break; + } } + + if ( os == NULL ) os = JabberTextEncode( Translate( "Windows" )); + + strcpy(mversion, "Miranda NG "); + CallService( MS_SYSTEM_GETVERSIONTEXT, sizeof( mversion ) - 11, ( LPARAM )mversion + 11 ); + strcat(mversion, " (Tlen v."); + strcat(mversion, TLEN_VERSION_STRING); + strcat(mversion, ")"); + mver = JabberTextEncode( mversion ); + JabberSend( proto, "%s%s%s", from, mver?mver:"", version?version:"", os?os:"" ); + if (!item->versionRequested) { + item->versionRequested = TRUE; + JabberSend(proto, "", from); + } + + if ( mver ) mir_free( mver ); + if ( version ) mir_free( version ); + if ( os ) mir_free( os ); +} + +// Support for Tlen avatars - avatar token used to access web interface +static void TlenProcessAvatar(XmlNode* node, ThreadData *info) +{ + XmlNode *tokenNode, *aNode; + tokenNode = JabberXmlGetChild(node, "token"); + aNode = JabberXmlGetChild(node, "a"); + if (tokenNode != NULL) { + char *token = tokenNode->text; + strcpy(info->avatarToken, token); + } + if (aNode != NULL) { + if (TlenProcessAvatarNode(info->proto, node, NULL)) { + } + } +} + +static void JabberProcessMessage(XmlNode *node, ThreadData *info) +{ + HANDLE hContact; + CCSDATA ccs; + PROTORECVEVENT recv; + XmlNode *bodyNode, *subjectNode, *xNode, *n; + char *from, *type, *nick, *p, *localMessage, *idStr; + DWORD msgTime; + BOOL delivered, composing; + int i; + JABBER_LIST_ITEM *item; + BOOL isChatRoomJid; + + if (!node->name || strcmp(node->name, "message")) return; + + if ((type=JabberXmlGetAttrValue(node, "type")) != NULL && !strcmp(type, "error")) { + } + else { + if ((from=JabberXmlGetAttrValue(node, "from")) != NULL) { + char *fromJid = JabberLoginFromJID(from); + if (info->proto->tlenOptions.ignoreAdvertisements && strstr(from, "b73@tlen.pl") == from) { + return; + } + // If message is from a stranger (not in roster), item is NULL + item = JabberListGetItemPtr(info->proto, LIST_ROSTER, fromJid); + isChatRoomJid = JabberListExist(info->proto, LIST_CHATROOM, from); + + if (isChatRoomJid && type != NULL && !strcmp(type, "groupchat")) { + //JabberGroupchatProcessMessage(node, userdata); + } else if (type != NULL && !strcmp(type, "pic")) { + TlenProcessPic(node, info->proto); + } else if (type != NULL && !strcmp(type, "iq")) { + XmlNode *iqNode; + // Jabber-compatible iq + if ((iqNode=JabberXmlGetChild(node, "iq")) != NULL) { + JabberXmlAddAttr(iqNode, "from", from); + JabberProcessIq(iqNode, info); + } + } else { + if ((bodyNode=JabberXmlGetChild(node, "body")) != NULL) { + if (bodyNode->text != NULL) { + if ((subjectNode=JabberXmlGetChild(node, "subject")) != NULL && subjectNode->text != NULL && subjectNode->text[0] != '\0') { + p = (char *) mir_alloc(strlen(subjectNode->text)+strlen(bodyNode->text)+5); + sprintf(p, "%s\r\n%s", subjectNode->text, bodyNode->text); + localMessage = JabberTextDecode(p); + mir_free(p); + } else { + localMessage = JabberTextDecode(bodyNode->text); + } + + msgTime = 0; + delivered = composing = FALSE; + i = 1; + while ((xNode=JabberXmlGetNthChild(node, "x", i)) != NULL) { + if ((p=JabberXmlGetAttrValue(xNode, "xmlns")) != NULL) { + if (!strcmp(p, "jabber:x:delay") && msgTime==0) { + if ((p=JabberXmlGetAttrValue(xNode, "stamp")) != NULL) { + msgTime = JabberIsoToUnixTime(p); + } + } + else if (!strcmp(p, "jabber:x:event")) { + // Check whether any event is requested + if (!delivered && (n=JabberXmlGetChild(xNode, "delivered")) != NULL) { + delivered = TRUE; + idStr = JabberXmlGetAttrValue(node, "id"); + JabberSend(info->proto, "%s", from, (idStr != NULL)?idStr:""); + } + if (item != NULL && JabberXmlGetChild(xNode, "composing") != NULL) { + composing = TRUE; + if (item->messageEventIdStr) + mir_free(item->messageEventIdStr); + idStr = JabberXmlGetAttrValue(node, "id"); + item->messageEventIdStr = (idStr == NULL)?NULL:mir_strdup(idStr); + } + } + } + i++; + } + + if (item != NULL) { + item->wantComposingEvent = composing; + if (item->isTyping) { + item->isTyping = FALSE; + if ((hContact=JabberHContactFromJID(info->proto, fromJid)) != NULL) + CallService(MS_PROTO_CONTACTISTYPING, (WPARAM) hContact, PROTOTYPE_CONTACTTYPING_OFF); + } + } + + if ((hContact=JabberHContactFromJID(info->proto, fromJid)) == NULL) { + // Create a temporary contact + if (isChatRoomJid) { + if ((p=strchr(from, '/')) != NULL && p[1]!='\0') + p++; + else + p = from; + nick = JabberTextEncode(p); + hContact = JabberDBCreateContact(info->proto, from, nick, TRUE); + } + else { + nick = JabberLocalNickFromJID(from); + hContact = JabberDBCreateContact(info->proto, from, nick, TRUE); + } + mir_free(nick); + } + + if (msgTime == 0) { + msgTime = time(NULL); + } else { + HANDLE hDbEvent = (HANDLE) CallService(MS_DB_EVENT_FINDLAST, (WPARAM) hContact, 0); + if (hDbEvent != NULL) { + DBEVENTINFO dbei = { 0 }; + dbei.cbSize = sizeof(dbei); + CallService(MS_DB_EVENT_GET, (WPARAM) hDbEvent, (LPARAM) &dbei); + if (msgTime < dbei.timestamp) { + msgTime = dbei.timestamp + 1; + } + } + if (msgTime > (DWORD)time(NULL)) { + msgTime = time(NULL); + } + } + recv.flags = 0; + recv.timestamp = (DWORD) msgTime; + recv.szMessage = localMessage; + recv.lParam = 0; + ccs.hContact = hContact; + ccs.wParam = 0; + ccs.szProtoService = PSR_MESSAGE; + ccs.lParam = (LPARAM) &recv; + CallService(MS_PROTO_CHAINRECV, 0, (LPARAM) &ccs); + + mir_free(localMessage); + } + } + } + mir_free(fromJid); + } + } +} + +static void JabberProcessIq(XmlNode *node, ThreadData *info) +{ + HANDLE hContact; + XmlNode *queryNode = NULL; + char *type, *jid, *nick; + char *xmlns = NULL; + char *idStr, *str; + int id; + int i; + JABBER_IQ_PFUNC pfunc; + + if (!node->name || strcmp(node->name, "iq")) return; + type=JabberXmlGetAttrValue(node, "type"); +// if ((type=JabberXmlGetAttrValue(node, "type")) == NULL) return; + + id = -1; + if ((idStr=JabberXmlGetAttrValue(node, "id")) != NULL) { + if (!strncmp(idStr, JABBER_IQID, strlen(JABBER_IQID))) + id = atoi(idStr+strlen(JABBER_IQID)); + } + + queryNode = JabberXmlGetChild(node, "query"); + if (queryNode != NULL) { + xmlns = JabberXmlGetAttrValue(queryNode, "xmlns"); + } + + + ///////////////////////////////////////////////////////////////////////// + // MATCH BY ID + ///////////////////////////////////////////////////////////////////////// + if ((pfunc=JabberIqFetchFunc(info->proto, id)) != NULL) { + JabberLog(info->proto, "Handling iq request for id=%d", id); + pfunc(info->proto, node); + ///////////////////////////////////////////////////////////////////////// + // MORE GENERAL ROUTINES, WHEN ID DOES NOT MATCH + ///////////////////////////////////////////////////////////////////////// + // new p2p connections + } else if (xmlns != NULL && !strcmp(xmlns, "p2p")) { + if (info->proto->tlenOptions.useNewP2P) { + TlenProcessP2P(node, info); + } + } + // RECVED: proto, " Got roster push, query has %d children", queryNode->numChild); + for (i=0; inumChild; i++) { + itemNode = queryNode->child[i]; + if (!strcmp(itemNode->name, "item")) { + if ((jid=JabberXmlGetAttrValue(itemNode, "jid")) != NULL) { + if ((str=JabberXmlGetAttrValue(itemNode, "subscription")) != NULL) { + // we will not add new account when subscription=remove + if (!strcmp(str, "to") || !strcmp(str, "both") || !strcmp(str, "from") || !strcmp(str, "none")) { + if ((name=JabberXmlGetAttrValue(itemNode, "name")) != NULL) { + nick = JabberTextDecode(name); + } else { + nick = JabberLocalNickFromJID(jid); + } + if (nick != NULL) { + if ((item=JabberListAdd(info->proto, LIST_ROSTER, jid)) != NULL) { + if (item->nick) mir_free(item->nick); + item->nick = nick; + if ((hContact=JabberHContactFromJID(info->proto, jid)) == NULL) { + // Received roster has a new JID. + // Add the jid (with empty resource) to Miranda contact list. + hContact = JabberDBCreateContact(info->proto, jid, nick, FALSE); + } + DBWriteContactSettingString(hContact, "CList", "MyHandle", nick); + if (item->group) mir_free(item->group); + if ((groupNode=JabberXmlGetChild(itemNode, "group")) != NULL && groupNode->text != NULL) { + item->group = TlenGroupDecode(groupNode->text); + JabberContactListCreateGroup(item->group); + DBWriteContactSettingString(hContact, "CList", "Group", item->group); + } + else { + item->group = NULL; + DBDeleteContactSetting(hContact, "CList", "Group"); + } + if (!strcmp(str, "none") || (!strcmp(str, "from") && strchr(jid, '@') != NULL)) { + if (DBGetContactSettingWord(hContact, info->proto->m_szModuleName, "Status", ID_STATUS_OFFLINE) != ID_STATUS_OFFLINE) + DBWriteContactSettingWord(hContact, info->proto->m_szModuleName, "Status", ID_STATUS_OFFLINE); + } + } + else { + mir_free(nick); + } + } + } + if ((item=JabberListGetItemPtr(info->proto, LIST_ROSTER, jid)) != NULL) { + if (!strcmp(str, "both")) item->subscription = SUB_BOTH; + else if (!strcmp(str, "to")) item->subscription = SUB_TO; + else if (!strcmp(str, "from")) item->subscription = SUB_FROM; + else item->subscription = SUB_NONE; + JabberLog(info->proto, "Roster push for jid=%s, set subscription to %s", jid, str); + // subscription = remove is to remove from roster list + // but we will just set the contact to offline and not actually + // remove, so that history will be retained. + if (!strcmp(str, "remove")) { + if ((hContact=JabberHContactFromJID(info->proto, jid)) != NULL) { + if (DBGetContactSettingWord(hContact, info->proto->m_szModuleName, "Status", ID_STATUS_OFFLINE) != ID_STATUS_OFFLINE) + DBWriteContactSettingWord(hContact, info->proto->m_szModuleName, "Status", ID_STATUS_OFFLINE); + JabberListRemove(info->proto, LIST_ROSTER, jid); + } + } + } + } + } + } + } + } + + } + // RECVED: proto, node); + } + // RECVED: proto, node); + } else if ( !strcmp( xmlns, "jabber:iq:version" )) { + TlenIqResultVersion(info->proto, node); + } else if ( !strcmp( xmlns, "jabber:iq:info" )) { + TlenIqResultInfo(info->proto, node); + } + } else { + char *from; + if (( from=JabberXmlGetAttrValue( node, "from" )) != NULL ) { + if ( !strcmp(from, "tcfg" )) { + TlenIqResultTcfg(info->proto, node); + } + } + } + } + // RECVED: ... + else if (!strcmp(type, "error")) { + JABBER_LIST_ITEM *item; + // Check for multi-user chat errors + char *from; + if ((from=JabberXmlGetAttrValue(node, "from")) != NULL) { + if (strstr(from, "@c") != NULL || !strcmp(from, "c")) { + TlenMUCRecvError(info->proto, from, node); + return; + } + } + + // Check for file transfer deny by comparing idStr with ft->iqId + i = 0; + while ((i=JabberListFindNext(info->proto, LIST_FILE, i)) >= 0) { + item = JabberListGetItemPtrFromIndex(info->proto,i); + if (item->ft->state==FT_CONNECTING && !strcmp(idStr, item->ft->iqId)) { + item->ft->state = FT_DENIED; + if (item->ft->hFileEvent != NULL) + SetEvent(item->ft->hFileEvent); // Simulate the termination of file server connection + } + i++; + } + } + // RECVED: ... + else if (!strcmp(type, "1")) { // Chat groups list result + char *from; + if ((from=JabberXmlGetAttrValue(node, "from")) != NULL) { + if (strcmp(from, "c") == 0) { + TlenIqResultChatGroups(info->proto, node); + } + } + } + else if (!strcmp(type, "2")) { // Chat rooms list result + char *from; + if ((from=JabberXmlGetAttrValue(node, "from")) != NULL) { + if (strcmp(from, "c") == 0) { + TlenIqResultChatRooms(info->proto, node); + } + } + } else if (!strcmp(type, "3")) { // room search result - result to iq type 3 query + char *from; + if ((from=JabberXmlGetAttrValue(node, "from")) != NULL) { + if (strcmp(from, "c") == 0) { + TlenIqResultRoomSearch(info->proto, node); + } + } + } else if (!strcmp(type, "4")) { // chat room users list + char *from; + if ((from=JabberXmlGetAttrValue(node, "from")) != NULL) { + if (strstr(from, "@c") != NULL) { + TlenIqResultChatRoomUsers(info->proto, node); + } + } + } else if (!strcmp(type, "5")) { // room name & group & flags info - sent on joining the room + char *from; + if ((from=JabberXmlGetAttrValue(node, "from")) != NULL) { + if (strstr(from, "@c") != NULL) { + TlenIqResultRoomInfo(info->proto, node); + } + } + } else if (!strcmp(type, "6")) { // new nick registered + char *from; + if ((from=JabberXmlGetAttrValue(node, "from")) != NULL) { + if (strcmp(from, "c") == 0) { + TlenIqResultUserNicks(info->proto, node); + } + } + } else if (!strcmp(type, "7")) { // user nicknames list + char *from; + if ((from=JabberXmlGetAttrValue(node, "from")) != NULL) { + if (strcmp(from, "c") == 0) { + TlenIqResultUserNicks(info->proto, node); + } + } + } else if (!strcmp(type, "8")) { // user chat rooms list + char *from; + if ((from=JabberXmlGetAttrValue(node, "from")) != NULL) { + if (strcmp(from, "c") == 0) { + TlenIqResultUserRooms(info->proto, node); + } + } + } +} + +/* + * Web messages + */ +static void TlenProcessW(XmlNode *node, ThreadData *info) +{ + HANDLE hContact; + CCSDATA ccs; + PROTORECVEVENT recv; + char *f, *e, *s, *body; + char *str, *localMessage; + int strSize; + + if (!node->name || strcmp(node->name, "w")) return; + if ((body=node->text) == NULL) return; + + if ((f=JabberXmlGetAttrValue(node, "f")) != NULL) { + + char webContactName[128]; + sprintf(webContactName, Translate("%s Web Messages"), info->proto->m_szProtoName); + if ((hContact=JabberHContactFromJID(info->proto, webContactName)) == NULL) { + hContact = JabberDBCreateContact(info->proto, webContactName, webContactName, TRUE); + } + + s = JabberXmlGetAttrValue(node, "s"); + e = JabberXmlGetAttrValue(node, "e"); + + str = NULL; + strSize = 0; + JabberStringAppend(&str, &strSize, "%s\r\n%s: ", Translate("Web message"), Translate("From")); + + if (f != NULL) + JabberStringAppend(&str, &strSize, "%s", f); + JabberStringAppend(&str, &strSize, "\r\n%s: ", Translate("E-mail")); + if (e != NULL) + JabberStringAppend(&str, &strSize, "%s", e); + JabberStringAppend(&str, &strSize, "\r\n\r\n%s", body); + + localMessage = JabberTextDecode(str); + + recv.flags = 0; + recv.timestamp = (DWORD) time(NULL); + recv.szMessage = localMessage; + recv.lParam = 0; + ccs.hContact = hContact; + ccs.wParam = 0; + ccs.szProtoService = PSR_MESSAGE; + ccs.lParam = (LPARAM) &recv; + CallService(MS_PROTO_CHAINRECV, 0, (LPARAM) &ccs); + + mir_free(localMessage); + mir_free(str); + } +} + +/* + * Typing notification, multi-user conference messages and invitations + */ +static void TlenProcessM(XmlNode *node, ThreadData *info) +{ + HANDLE hContact; + CCSDATA ccs; + PROTORECVEVENT recv; + char *f;//, *from;//username + char *tp;//typing start/stop + char *p, *n, *r, *s, *str, *localMessage; + int i; + XmlNode *xNode, *invNode, *bNode, *subjectNode; + + if (!node->name || strcmp(node->name, "m")) return; + + if ((f=JabberXmlGetAttrValue(node, "f")) != NULL) { + char *fLogin = JabberLoginFromJID(f); + if ((hContact=JabberHContactFromJID(info->proto, fLogin)) != NULL) { + if ((tp=JabberXmlGetAttrValue(node, "tp")) != NULL) { + JABBER_LIST_ITEM *item = JabberListGetItemPtr(info->proto, LIST_ROSTER, fLogin); + if (!strcmp(tp, "t")) { //contact is writing + if (item != NULL ) { + item->isTyping = TRUE; + CallService(MS_PROTO_CONTACTISTYPING, (WPARAM)hContact, (LPARAM)PROTOTYPE_CONTACTTYPING_INFINITE); + } + } + else if (!strcmp(tp, "u")) {//contact stopped writing + if (item != NULL) { + item->isTyping = FALSE; + CallService(MS_PROTO_CONTACTISTYPING, (WPARAM)hContact, (LPARAM)PROTOTYPE_CONTACTTYPING_OFF); + } + } + else if (!strcmp(tp, "a")) {//alert was received + int bAlert = TRUE; + if (info->proto->tlenOptions.alertPolicy == TLEN_ALERTS_IGNORE_ALL) { + bAlert = FALSE; + } else if (info->proto->tlenOptions.alertPolicy == TLEN_ALERTS_IGNORE_NIR) { + bAlert = IsAuthorized(info->proto, fLogin); + } + if (bAlert) { + if (info->proto->tlenOptions.useNudge) { + NotifyEventHooks(info->proto->hTlenNudge,(WPARAM) hContact,0); + } else { + if (info->proto->tlenOptions.logAlerts) { + TlenLogMessage(info->proto, hContact, 0, Translate("An alert has been received.")); + } + SkinPlaySound("TlenAlertNotify"); + } + } + } + } + } + mir_free(fLogin); + if ((p=strchr(f, '@')) != NULL) { + if ((p=strchr(p, '/')) != NULL && p[1]!='\0') { // message from user + time_t timestamp; + s = JabberXmlGetAttrValue(node, "s"); + if (s != NULL) { + timestamp = TlenTimeToUTC(atol(s)); + if (timestamp > time(NULL)) { + timestamp = time(NULL); + } + } else { + timestamp = time(NULL); + } + tp=JabberXmlGetAttrValue(node, "tp"); + bNode = JabberXmlGetChild(node, "b"); + f = JabberTextDecode(f); + if (bNode != NULL && bNode->text != NULL) { + if (tp != NULL && !strcmp(tp, "p")) { + /* MUC private message */ + str = JabberResourceFromJID(f); + hContact = JabberDBCreateContact(info->proto, f, str, TRUE); + DBWriteContactSettingByte(hContact, info->proto->m_szModuleName, "bChat", TRUE); + mir_free(str); + localMessage = JabberTextDecode(bNode->text); + recv.flags = 0; + recv.timestamp = (DWORD) timestamp; + recv.szMessage = localMessage; + recv.lParam = 0; + ccs.hContact = hContact; + ccs.wParam = 0; + ccs.szProtoService = PSR_MESSAGE; + ccs.lParam = (LPARAM) &recv; + CallService(MS_PROTO_CHAINRECV, 0, (LPARAM) &ccs); + mir_free(localMessage); + } else { + /* MUC message */ + TlenMUCRecvMessage(info->proto, f, timestamp, bNode); + } + } + mir_free(f); + } else { // message from chat room (system) + subjectNode = JabberXmlGetChild(node, "subject"); + if (subjectNode != NULL) { + f = JabberTextDecode(f); + localMessage = ""; + if (subjectNode->text != NULL) { + localMessage = subjectNode->text; + } + localMessage = JabberTextDecode(localMessage); + TlenMUCRecvTopic(info->proto, f, localMessage); + mir_free(localMessage); + mir_free(f); + } + } + } + i=1; + while ((xNode=JabberXmlGetNthChild(node, "x", i)) != NULL) { + invNode=JabberXmlGetChild(xNode, "inv"); + if (invNode != NULL) { + r = JabberTextDecode(f); + f = JabberXmlGetAttrValue(invNode, "f"); + f = JabberTextDecode(f); + n = JabberXmlGetAttrValue(invNode, "n"); + if (n != NULL && strstr(r, n) != r) { + n = JabberTextDecode(n); + } else { + n = mir_strdup(Translate("Private conference")); + //n = JabberNickFromJID(r); + } + TlenMUCRecvInvitation(info->proto, r, n, f, ""); + mir_free(n); + mir_free(r); + mir_free(f); + break; + } + i++; + } + } +} + +static void TlenMailPopup(TlenProtocol *proto, char *title, char *emailInfo) +{ + POPUPDATAEX ppd; + char * lpzContactName; + char * lpzText; + + if (!DBGetContactSettingByte(NULL, proto->m_szModuleName, "MailPopupEnabled", TRUE)) { + return; + } + lpzContactName = title; + lpzText = emailInfo; + ZeroMemory(&ppd, sizeof(ppd)); + ppd.lchContact = NULL; + ppd.lchIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_MAIL)); + strcpy(ppd.lpzContactName, lpzContactName); + strcpy(ppd.lpzText, lpzText); + ppd.colorBack = DBGetContactSettingDword(NULL, proto->m_szModuleName, "MailPopupBack", 0); + ppd.colorText = DBGetContactSettingDword(NULL, proto->m_szModuleName, "MailPopupText", 0); + ppd.PluginWindowProc = NULL; + ppd.PluginData=NULL; + if ( ServiceExists( MS_POPUP_ADDPOPUPEX )) { + BYTE delayMode; + int delay; + delayMode = DBGetContactSettingByte(NULL, proto->m_szModuleName, "MailPopupDelayMode", 0); + delay = 0; + if (delayMode==1) { + delay = DBGetContactSettingDword(NULL, proto->m_szModuleName, "MailPopupDelay", 4); + } else if (delayMode==2) { + delay = -1; + } + ppd.iSeconds = delay; + CallService(MS_POPUP_ADDPOPUPEX, (WPARAM)&ppd, 0); + + } + else if ( ServiceExists( MS_POPUP_ADDPOPUP )) { + CallService(MS_POPUP_ADDPOPUP, (WPARAM)&ppd, 0); + } +} +/* + * Incoming e-mail notification + */ +static void TlenProcessN(XmlNode *node, ThreadData *info) +{ + char *f, *s; + char *str, *popupTitle, *popupText; + int strSize; + + if (!node->name || strcmp(node->name, "n")) return; + + s = JabberXmlGetAttrValue(node, "s"); + f = JabberXmlGetAttrValue(node, "f"); + if (s != NULL && f != NULL) { + str = NULL; + strSize = 0; + + JabberStringAppend(&str, &strSize, Translate("%s mail"), info->proto->m_szProtoName); + popupTitle = JabberTextDecode(str); + mir_free(str); + + str = NULL; + strSize = 0; + + JabberStringAppend(&str, &strSize, "%s: %s\n", Translate("From"), f); + JabberStringAppend(&str, &strSize, "%s: %s", Translate("Subject"), s); + popupText = JabberTextDecode(str); + TlenMailPopup(info->proto, popupTitle, popupText); + SkinPlaySound("TlenMailNotify"); + + mir_free(popupTitle); + mir_free(popupText); + mir_free(str); + } +} + +/* + * Presence is chat rooms + */ +static void TlenProcessP(XmlNode *node, ThreadData *info) +{ + char jid[512]; + char *f, *id, *tp, *a, *n, *k; + XmlNode *sNode, *xNode, *iNode, *kNode; + int status, flags; + + if (!node->name || strcmp(node->name, "p")) return; + +// presence from users in chat room + flags = 0; + status = ID_STATUS_ONLINE; + f = JabberXmlGetAttrValue(node, "f"); + xNode = JabberXmlGetChild(node, "x"); + if (xNode != NULL) { // x subtag present (message from chat room) - change user rights only + char *temp, *iStr; + iNode = JabberXmlGetChild(xNode, "i"); + if (iNode != NULL) { + iStr = JabberXmlGetAttrValue(iNode, "i"); + temp = (char*)mir_alloc(strlen(f)+strlen(iStr)+2); + strcpy(temp, f); + strcat(temp, "/"); + strcat(temp, iStr); + f = JabberTextDecode(temp); + mir_free(temp); + node = iNode; + status = 0; + } else { + f = JabberTextDecode(f); + } + } else { + f = JabberTextDecode(f); + } + a = JabberXmlGetAttrValue(node, "z"); + if (a != NULL) { + if (atoi(a) &1 ) { + flags |= USER_FLAGS_REGISTERED; + } + } + a = JabberXmlGetAttrValue(node, "a"); + if (a != NULL) { + if (atoi(a) == 2) { + flags |= USER_FLAGS_ADMIN; + } + if (atoi(a) == 1) { + flags |= USER_FLAGS_OWNER; + } + if (atoi(a) == 3) { + //flags |= USER_FLAGS_MEMBER; + } + if (atoi(a) == 5) { + flags |= USER_FLAGS_GLOBALOWNER; + } + } + sNode = JabberXmlGetChild(node, "s"); + if (sNode != NULL) { + if (!strcmp(sNode->text, "unavailable")) { + status = ID_STATUS_OFFLINE; + } + } + kNode = JabberXmlGetChild(node, "kick"); + k = NULL; + if (kNode != NULL) { + k = JabberXmlGetAttrValue(kNode, "r"); + if (k == NULL) { + k = ""; + } + k = JabberTextDecode(k); + } + tp = JabberXmlGetAttrValue(node, "tp"); + if (tp != NULL && !strcmp(tp, "c")) { // new chat room has just been created + id = JabberXmlGetAttrValue(node, "id"); + if (id != NULL) { + n = JabberXmlGetAttrValue(node, "n"); + if (n != NULL) { + n = JabberTextDecode(n); + } else { + n = mir_strdup(Translate("Private conference"));// JabberNickFromJID(f); + } + sprintf(jid, "%s/%s", f, info->username); +// if (!DBGetContactSetting(NULL, info->proto->m_szModuleName, "LoginName", &dbv)) { + // always real username +// sprintf(jid, "%s/%s", f, dbv.pszVal); + TlenMUCCreateWindow(info->proto, f, n, 0, NULL, id); + TlenMUCRecvPresence(info->proto, jid, ID_STATUS_ONLINE, flags, k); +// DBFreeVariant(&dbv); +// } + mir_free(n); + } + } else { + TlenMUCRecvPresence(info->proto, f, status, flags, k); // user presence + } + if (k != NULL) { + mir_free(k); + } + mir_free(f); +} +/* + * Voice chat + */ +static void TlenProcessV(XmlNode *node, ThreadData *info) +{ + char jid[128]; + JABBER_LIST_ITEM *item; + char *from, *id, *e, *p; +// if (!node->name || strcmp(node->name, "v")) return; + + if ((from=JabberXmlGetAttrValue(node, "f")) != NULL) { + if (strchr(from, '@') == NULL) { + _snprintf(jid, sizeof(jid), "%s@%s", from, info->server); + } else { + _snprintf(jid, sizeof(jid), "%s", from); + } + if ((e=JabberXmlGetAttrValue(node, "e")) != NULL) { + if (!strcmp(e, "1")) { + if ((id=JabberXmlGetAttrValue(node, "i")) != NULL) { + SkinPlaySound("TlenVoiceNotify"); + TlenVoiceAccept(info->proto, id, from); + } + } else if (!strcmp(e, "3")) { + // FILE_RECV : e='3' : invalid transfer error + if ((p=JabberXmlGetAttrValue(node, "i")) != NULL) { + if ((item=JabberListGetItemPtr(info->proto, LIST_VOICE, p)) != NULL) { + if (item->ft != NULL) { + HANDLE hEvent = item->ft->hFileEvent; + item->ft->hFileEvent = NULL; + item->ft->state = FT_ERROR; + if (item->ft->s != NULL) { + Netlib_CloseHandle(item->ft->s); + item->ft->s = NULL; + if (hEvent != NULL) { + SetEvent(hEvent); + } + } else { + TlenP2PFreeFileTransfer(item->ft); + } + } else { + JabberListRemove(info->proto, LIST_VOICE, p); + } + } + } + } else if (!strcmp(e, "4")) { + // FILE_SEND : e='4' : File sending request was denied by the remote client + if ((p=JabberXmlGetAttrValue(node, "i")) != NULL) { + if ((item=JabberListGetItemPtr(info->proto, LIST_VOICE, p)) != NULL) { + if (!strcmp(item->ft->jid, jid)) { + TlenVoiceCancelAll(info->proto); + //JabberListRemove(info->proto, LIST_VOICE, p); + } + } + } + } else if (!strcmp(e, "5")) { + // FILE_SEND : e='5' : Voice request was accepted + if ((p=JabberXmlGetAttrValue(node, "i")) != NULL) { + if ((item=JabberListGetItemPtr(info->proto, LIST_VOICE, p)) != NULL) { + JabberLog(info->proto, "should start voice 1 ? %s ?? %s", jid, item->ft->jid); + if (!strcmp(item->ft->jid, jid)) { + JabberLog(info->proto, "starting voice 1"); + TlenVoiceStart(item->ft, 1); + } + } + } + } else if (!strcmp(e, "6")) { + // FILE_RECV : e='6' : IP and port information to connect to get file + if ((p=JabberXmlGetAttrValue(node, "i")) != NULL) { + if ((item=JabberListGetItemPtr(info->proto, LIST_VOICE, p)) != NULL) { + if ((p=JabberXmlGetAttrValue(node, "a")) != NULL) { + item->ft->hostName = mir_strdup(p); + if ((p=JabberXmlGetAttrValue(node, "p")) != NULL) { + item->ft->wPort = atoi(p); + TlenVoiceStart(item->ft, 0); + //JabberForkThread((void (__cdecl *)(void*))TlenVoiceReceiveThread, 0, item->ft); + } + } + } + } + } + else if (!strcmp(e, "7")) { + // FILE_RECV : e='7' : IP and port information to connect to send file + // in case the conection to the given server was not successful + if ((p=JabberXmlGetAttrValue(node, "i")) != NULL) { + if ((item=JabberListGetItemPtr(info->proto, LIST_VOICE, p)) != NULL) { + if ((p=JabberXmlGetAttrValue(node, "a")) != NULL) { + if (item->ft->hostName != NULL) mir_free(item->ft->hostName); + item->ft->hostName = mir_strdup(p); + if ((p=JabberXmlGetAttrValue(node, "p")) != NULL) { + item->ft->wPort = atoi(p); + item->ft->state = FT_SWITCH; + SetEvent(item->ft->hFileEvent); + } + } + } + } + } + else if (!strcmp(e, "8")) { + // FILE_RECV : e='8' : transfer error + if ((p=JabberXmlGetAttrValue(node, "i")) != NULL) { + if ((item=JabberListGetItemPtr(info->proto, LIST_VOICE, p)) != NULL) { + item->ft->state = FT_ERROR; + SetEvent(item->ft->hFileEvent); + } + } + } + + } + } +} + +static void __cdecl JabberKeepAliveThread(void *ptr) +{ + NETLIBSELECT nls = {0}; + + TlenProtocol *proto = (TlenProtocol *)ptr; + nls.cbSize = sizeof(NETLIBSELECT); + nls.dwTimeout = 60000; // 60000 millisecond (1 minute) + nls.hExceptConns[0] = proto->threadData->s; + for (;;) { + if (CallService(MS_NETLIB_SELECT, 0, (LPARAM) &nls) != 0) + break; + if (proto->tlenOptions.sendKeepAlive) + JabberSend(proto, " \t "); + } + JabberLog(proto, "Exiting KeepAliveThread"); +} + diff --git a/protocols/Tlen/src/jabber_util.cpp b/protocols/Tlen/src/jabber_util.cpp new file mode 100644 index 0000000000..00ce04e579 --- /dev/null +++ b/protocols/Tlen/src/jabber_util.cpp @@ -0,0 +1,647 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Tlen Protocol Plugin for Miranda NG +Copyright (C) 2002-2004 Santithorn Bunchua +Copyright (C) 2004-2007 Piotr Piastucki + +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_list.h" +#include +#include + + +HANDLE HookEventObj_Ex(const char *name, TlenProtocol *proto, MIRANDAHOOKOBJ hook) +{ + proto->hookNum ++; + proto->hHooks = (HANDLE *) mir_realloc(proto->hHooks, sizeof(HANDLE) * (proto->hookNum)); + proto->hHooks[proto->hookNum - 1] = HookEventObj(name, hook, proto); + return proto->hHooks[proto->hookNum - 1] ; +} + + +HANDLE CreateServiceFunction_Ex(const char *name, TlenProtocol *proto, MIRANDASERVICEOBJ service) { + proto->serviceNum++; + proto->hServices = (HANDLE *) mir_realloc(proto->hServices, sizeof(HANDLE) * (proto->serviceNum)); + proto->hServices[proto->serviceNum - 1] = CreateServiceFunctionObj(name, service, proto); + return proto->hServices[proto->serviceNum - 1] ; +} + +void UnhookEvents_Ex(TlenProtocol *proto) { + unsigned int i; + for (i=0; ihookNum; ++i) { + if (proto->hHooks[i] != NULL) { + UnhookEvent(proto->hHooks[i]); + } + } + mir_free(proto->hHooks); + proto->hookNum = 0; + proto->hHooks = NULL; +} + +void DestroyServices_Ex(TlenProtocol *proto) { + unsigned int i; + for (i=0; iserviceNum; ++i) { + if (proto->hServices[i] != NULL) { + DestroyServiceFunction(proto->hServices[i]); + } + } + mir_free(proto->hServices); + proto->serviceNum = 0; + proto->hServices = NULL; +} + +void JabberSerialInit(TlenProtocol *proto) +{ + InitializeCriticalSection(&proto->csSerial); + proto->serial = 0; +} + +void JabberSerialUninit(TlenProtocol *proto) +{ + DeleteCriticalSection(&proto->csSerial); +} + + +unsigned int JabberSerialNext(TlenProtocol *proto) +{ + unsigned int ret; + + EnterCriticalSection(&proto->csSerial); + ret = proto->serial; + proto->serial++; + LeaveCriticalSection(&proto->csSerial); + return ret; +} + + +void JabberLog(TlenProtocol *proto, const char *fmt, ...) +{ +#ifdef ENABLE_LOGGING + char *str; + va_list vararg; + int strsize; + char *text; + char *p, *q; + int extra; + + va_start(vararg, fmt); + str = (char *) mir_alloc(strsize=2048); + while (_vsnprintf(str, strsize, fmt, vararg) == -1) + str = (char *) mir_realloc(str, strsize+=2048); + va_end(vararg); + + extra = 0; + for (p=str; *p != '\0'; p++) + if (*p == '\n' || *p == '\r') + extra++; + text = (char *) mir_alloc(strlen("TLEN")+2+strlen(str)+2+extra); + sprintf(text, "[%s]", "TLEN"); + for (p=str,q=text+strlen(text); *p != '\0'; p++,q++) { + if (*p == '\r') { + *q = '\\'; + *(q+1) = 'r'; + q++; + } + else if (*p == '\n') { + *q = '\\'; + *(q+1) = 'n'; + q++; + } + else + *q = *p; + } + *q = '\n'; + *(q+1) = '\0'; + if (proto->hNetlibUser != NULL) { + CallService(MS_NETLIB_LOG, (WPARAM) proto->hNetlibUser, (LPARAM) text); + } + //OutputDebugString(text); + mir_free(text); + mir_free(str); +#endif +} + +// Caution: DO NOT use JabberSend() to send binary (non-string) data + +int JabberSend(TlenProtocol *proto, const char *fmt, ...) +{ + char *str; + int size; + va_list vararg; + int result = 0; + + EnterCriticalSection(&proto->csSend); + + va_start(vararg,fmt); + size = 512; + str = (char *) mir_alloc(size); + while (_vsnprintf(str, size, fmt, vararg) == -1) { + size += 512; + str = (char *) mir_realloc(str, size); + } + va_end(vararg); + + JabberLog(proto, "SEND:%s", str); + size = (int)strlen(str); + if (proto->threadData != NULL) { + if (proto->threadData->useAES) { + result = JabberWsSendAES(proto, str, size, &proto->threadData->aes_out_context, proto->threadData->aes_out_iv); + } else { + result = JabberWsSend(proto, proto->threadData->s, str, size); + } + } + LeaveCriticalSection(&proto->csSend); + + mir_free(str); + return result; +} + +char *JabberResourceFromJID(const char *jid2) +{ + char *p; + char *nick; + char* jid = mir_strdup(jid2); + + p=strchr(jid, '/'); + if (p != NULL && p[1] != '\0') { + p++; + if ((nick=(char *) mir_alloc(1+strlen(jid)-(p-jid))) != NULL) { + strncpy(nick, p, strlen(jid)-(p-jid)); + nick[strlen(jid)-(p-jid)] = '\0'; + } + } + else { + nick = mir_strdup(jid); + } + + mir_free(jid); + return nick; +} + +char *JabberNickFromJID(const char *jid2) +{ + char *p; + char *nick; + char* jid = mir_strdup(jid2); + + if ((p=strchr(jid, '@')) == NULL) + p = strchr(jid, '/'); + if (p != NULL) { + if ((nick=(char *) mir_alloc((p-jid)+1)) != NULL) { + strncpy(nick, jid, p-jid); + nick[p-jid] = '\0'; + } + } + else { + nick = mir_strdup(jid); + } + + mir_free(jid); + return nick; +} + +char *JabberLoginFromJID(const char *jid2) +{ + char *p; + char *nick; + char* jid = mir_strdup(jid2); + + p = strchr(jid, '/'); + if (p != NULL) { + if ((nick=(char *) mir_alloc((p-jid)+1)) != NULL) { + strncpy(nick, jid, p-jid); + nick[p-jid] = '\0'; + } + } + else { + nick = mir_strdup(jid); + } + + mir_free(jid); + return nick; +} + +char *JabberLocalNickFromJID(const char *jid) +{ + char *p; + char *localNick; + + p = JabberNickFromJID(jid); + localNick = JabberTextDecode(p); + mir_free(p); + return localNick; +} + +char *JabberSha1(char *str) +{ + mir_sha1_ctx sha; + DWORD digest[5]; + char* result; + + if ( str == NULL ) + return NULL; + + mir_sha1_init( &sha ); + mir_sha1_append( &sha, (mir_sha1_byte_t* )str, (int)strlen( str )); + mir_sha1_finish( &sha, (mir_sha1_byte_t* )digest ); + if ((result=(char *)mir_alloc(41)) == NULL) + return NULL; + sprintf(result, "%08x%08x%08x%08x%08x", (int)htonl(digest[0]), (int)htonl(digest[1]), (int)htonl(digest[2]), (int)htonl(digest[3]), (int)htonl(digest[4])); + return result; +} + +char *TlenSha1(char *str, int len) +{ + mir_sha1_ctx sha; + mir_sha1_byte_t digest[20]; + char* result; + int i; + + if ( str == NULL ) + return NULL; + + mir_sha1_init( &sha ); + mir_sha1_append( &sha, (mir_sha1_byte_t* )str, len); + mir_sha1_finish( &sha, digest ); + if (( result=( char* )mir_alloc( 20 )) == NULL ) + return NULL; + for (i=0; i<20; i++) + result[i]=digest[4*(i>>2)+(3-(i&0x3))]; + return result; +} + +char *TlenPasswordHash(const char *str) +{ + int magic1 = 0x50305735, magic2 = 0x12345671, sum = 7; + char *p, *res; + + if (str == NULL) return NULL; + for (p=(char *)str; *p != '\0'; p++) { + if (*p != ' ' && *p != '\t') { + magic1 ^= (((magic1 & 0x3f) + sum) * ((char) *p)) + (magic1 << 8); + magic2 += (magic2 << 8) ^ magic1; + sum += ((char) *p); + } + } + magic1 &= 0x7fffffff; + magic2 &= 0x7fffffff; + res = (char *) mir_alloc(17); + sprintf(res, "%08x%08x", magic1, magic2); + return res; +} + +char *TlenUrlEncode(const char *str) +{ + char *p, *q, *res; + unsigned char c; + + if (str == NULL) return NULL; + res = (char *) mir_alloc(3*strlen(str) + 1); + for (p=(char *)str,q=res; *p != '\0'; p++,q++) { + if (*p == ' ') { + *q = '+'; + } + else if (*p < 0x20 || *p >= 0x7f || strchr("%&+:'<>\"", *p) != NULL) { + // Convert first from CP1252 to ISO8859-2 + switch ((unsigned char) *p) { + case 0xa5: c = (unsigned char) 0xa1; break; + case 0x8c: c = (unsigned char) 0xa6; break; + case 0x8f: c = (unsigned char) 0xac; break; + case 0xb9: c = (unsigned char) 0xb1; break; + case 0x9c: c = (unsigned char) 0xb6; break; + case 0x9f: c = (unsigned char) 0xbc; break; + default: c = (unsigned char) *p; break; + } + sprintf(q, "%%%02X", c); + q += 2; + } + else { + *q = *p; + } + } + *q = '\0'; + return res; +} + +void TlenUrlDecode(char *str) +{ + char *p, *q; + unsigned int code; + + if (str == NULL) return; + for (p=q=str; *p != '\0'; p++,q++) { + if (*p == '+') { + *q = ' '; + } + else if (*p == '%' && *(p+1) != '\0' && isxdigit(*(p+1)) && *(p+2) != '\0' && isxdigit(*(p+2))) { + sscanf(p+1, "%2x", &code); + *q = (char) code; + // Convert from ISO8859-2 to CP1252 + switch ((unsigned char) *q) { + case 0xa1: *q = (char) 0xa5; break; + case 0xa6: *q = (char) 0x8c; break; + case 0xac: *q = (char) 0x8f; break; + case 0xb1: *q = (char) 0xb9; break; + case 0xb6: *q = (char) 0x9c; break; + case 0xbc: *q = (char) 0x9f; break; + } + p += 2; + } + else { + *q = *p; + } + } + *q = '\0'; +} + +char * TlenGroupDecode(const char *str) +{ + char *p, *q; + if (str == NULL) return NULL; + p = q = JabberTextDecode(str); + for (; *p != '\0'; p++) { + if (*p == '/') { + *p = '\\'; + } + } + return q; +} + +char * TlenGroupEncode(const char *str) +{ + char *p, *q; + if (str == NULL) return NULL; + p = q = mir_strdup(str); + for (; *p != '\0'; p++) { + if (*p == '\\') { + *p = '/'; + } + } + p = JabberTextEncode(q); + mir_free(q); + return p; +} + +char *JabberTextEncode(const char *str) +{ + char *s1; + + if (str == NULL) return NULL; + if ((s1=TlenUrlEncode(str)) == NULL) + return NULL; + return s1; +} + +char *JabberTextDecode(const char *str) +{ + char *s1; + + if (str == NULL) return NULL; + s1 = mir_strdup(str); + TlenUrlDecode(s1); + return s1; +} + +static char b64table[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +char *JabberBase64Encode(const char *buffer, int bufferLen) +{ + int n; + unsigned char igroup[3]; + char *p, *peob; + char *res, *r; + + if (buffer == NULL || bufferLen <= 0) return NULL; + if ((res=(char *) mir_alloc((((bufferLen+2)/3)*4) + 1)) == NULL) return NULL; + + for (p=(char*)buffer,peob=p+bufferLen,r=res; p= peob) break; + igroup[n] = (unsigned char) *p; + p++; + } + if (n > 0) { + r[0] = b64table[ igroup[0]>>2 ]; + r[1] = b64table[ ((igroup[0]&3)<<4) | (igroup[1]>>4) ]; + r[2] = b64table[ ((igroup[1]&0xf)<<2) | (igroup[2]>>6) ]; + r[3] = b64table[ igroup[2]&0x3f ]; + if (n < 3) { + r[3] = '='; + if (n < 2) + r[2] = '='; + } + r += 4; + } + } + *r = '\0'; + + return res; +} + +static unsigned char b64rtable[256]; + +char *JabberBase64Decode(const char *str, int *resultLen) +{ + char *res; + unsigned char *p, *r, igroup[4], a[4]; + int n, num, count; + + if (str == NULL || resultLen == NULL) return NULL; + if ((res=(char *) mir_alloc(((strlen(str)+3)/4)*3)) == NULL) return NULL; + + for (n=0; n<256; n++) + b64rtable[n] = (unsigned char) 0x80; + for (n=0; n<26; n++) + b64rtable['A'+n] = n; + for (n=0; n<26; n++) + b64rtable['a'+n] = n + 26; + for (n=0; n<10; n++) + b64rtable['0'+n] = n + 52; + b64rtable['+'] = 62; + b64rtable['/'] = 63; + b64rtable['='] = 0; + count = 0; + for (p=(unsigned char *)str,r=(unsigned char *)res; *p != '\0';) { + for (n=0; n<4; n++) { + if ( *p == '\r' || *p == '\n' ) { + n--; p++; + continue; + } + + if ( *p=='\0' ) { + if ( n == 0 ) + goto LBL_Exit; + mir_free( res ); + return NULL; + } + + if ( b64rtable[*p] == 0x80 ) { + mir_free( res ); + return NULL; + } + + a[n] = *p; + igroup[n] = b64rtable[*p]; + p++; + } + r[0] = igroup[0]<<2 | igroup[1]>>4; + r[1] = igroup[1]<<4 | igroup[2]>>2; + r[2] = igroup[2]<<6 | igroup[3]; + r += 3; + num = ( a[2] == '='?1:( a[3] == '='?2:3 )); + count += num; + if ( num < 3 ) break; + } +LBL_Exit: + *resultLen = count; + return res; +} + +/* + * Apply Polish Daylight Saving Time rules to get "DST-unbiased" timestamp + */ + +time_t TlenTimeToUTC(time_t time) { + struct tm *timestamp; + timestamp = gmtime(&time); + if ( (timestamp->tm_mon > 2 && timestamp->tm_mon < 9) || + (timestamp->tm_mon == 2 && timestamp->tm_mday - timestamp->tm_wday >= 25) || + (timestamp->tm_mon == 9 && timestamp->tm_mday - timestamp->tm_wday < 25)) { + //time -= 3600; + } else { + //time += 3600; + } + return time; +} + +time_t JabberIsoToUnixTime(char *stamp) +{ + struct tm timestamp; + char date[9]; + char *p; + int i, y; + time_t t; + + if (stamp == NULL) return (time_t) 0; + + p = stamp; + + // Get the date part + for (i=0; *p != '\0' && i<8 && isdigit(*p); p++,i++) + date[i] = *p; + + // Parse year + if (i == 6) { + // 2-digit year (1970-2069) + y = (date[0]-'0')*10 + (date[1]-'0'); + if (y < 70) y += 100; + } + else if (i == 8) { + // 4-digit year + y = (date[0]-'0')*1000 + (date[1]-'0')*100 + (date[2]-'0')*10 + date[3]-'0'; + y -= 1900; + } + else + return (time_t) 0; + timestamp.tm_year = y; + // Parse month + timestamp.tm_mon = (date[i-4]-'0')*10 + date[i-3]-'0' - 1; + // Parse date + timestamp.tm_mday = (date[i-2]-'0')*10 + date[i-1]-'0'; + + // Skip any date/time delimiter + for (; *p != '\0' && !isdigit(*p); p++); + + // Parse time + if (sscanf(p, "%d:%d:%d", &(timestamp.tm_hour), &(timestamp.tm_min), &(timestamp.tm_sec)) != 3) + return (time_t) 0; + + timestamp.tm_isdst = 0; // DST is already present in _timezone below + _tzset(); + t = mktime(×tamp); + t -= _timezone; + t = TlenTimeToUTC(t); + + if (t >= 0) + return t; + else + return (time_t) 0; +} + +void JabberStringAppend(char **str, int *sizeAlloced, const char *fmt, ...) +{ + va_list vararg; + char *p; + int size, len; + + if (str == NULL) return; + + if (*str == NULL || *sizeAlloced <= 0) { + *sizeAlloced = size = 2048; + *str = (char *) mir_alloc(size); + len = 0; + } + else { + len = (int)strlen(*str); + size = *sizeAlloced - (int)strlen(*str); + } + + p = *str + len; + va_start(vararg, fmt); + while (_vsnprintf(p, size, fmt, vararg) == -1) { + size += 2048; + (*sizeAlloced) += 2048; + *str = (char *) mir_realloc(*str, *sizeAlloced); + p = *str + len; + } + va_end(vararg); +} + +int JabberGetPictureType( const char* buf ) +{ + if ( buf != NULL ) { + if ( memcmp( buf, "GIF89", 5 ) == 0 ) return PA_FORMAT_GIF; + if ( memcmp( buf, "\x89PNG", 4 ) == 0 ) return PA_FORMAT_PNG; + if ( memcmp( buf, "BM", 2 ) == 0 ) return PA_FORMAT_BMP; + if ( memcmp( buf, "\xFF\xD8", 2 ) == 0 ) return PA_FORMAT_JPEG; + } + return PA_FORMAT_UNKNOWN; +} + +BOOL IsAuthorized(TlenProtocol *proto, const char *jid) +{ + JABBER_LIST_ITEM *item = JabberListGetItemPtr(proto, LIST_ROSTER, jid); + if (item != NULL) { + return item->subscription == SUB_BOTH || item->subscription == SUB_FROM; + } + return FALSE; +} + + +void TlenLogMessage(TlenProtocol *proto, HANDLE hContact, DWORD flags, const char *message) +{ + int size = (int)strlen(message) + 2; + char *localMessage = (char *)mir_alloc(size); + strcpy(localMessage, message); + localMessage[size - 1] = '\0'; + JabberDBAddEvent(proto, hContact, EVENTTYPE_MESSAGE, flags, (PBYTE)message, (DWORD)size); + mir_free(localMessage); +} diff --git a/protocols/Tlen/src/jabber_ws.cpp b/protocols/Tlen/src/jabber_ws.cpp new file mode 100644 index 0000000000..c2cb853b02 --- /dev/null +++ b/protocols/Tlen/src/jabber_ws.cpp @@ -0,0 +1,160 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Tlen Protocol Plugin for Miranda NG +Copyright (C) 2002-2004 Santithorn Bunchua +Copyright (C) 2004-2007 Piotr Piastucki + +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" + +BOOL JabberWsInit(TlenProtocol *proto) +{ + NETLIBUSER nlu = {0}; + NETLIBUSERSETTINGS nlus = {0}; + TCHAR name[128]; + + + nlu.cbSize = sizeof(nlu); + nlu.flags = NUF_OUTGOING | NUF_INCOMING | NUF_HTTPCONNS | NUF_TCHAR; // | NUF_HTTPGATEWAY; + mir_sntprintf( name, SIZEOF(name), TranslateT("%s connection"), proto->m_tszUserName); + nlu.ptszDescriptiveName = name; + nlu.szSettingsModule = proto->m_szModuleName; + proto->hNetlibUser = (HANDLE) CallService(MS_NETLIB_REGISTERUSER, 0, (LPARAM) &nlu); + + nlu.flags = NUF_OUTGOING | NUF_INCOMING | NUF_NOOPTIONS | NUF_TCHAR; + mir_sntprintf( name, SIZEOF(name), TranslateT("%s SOCKS connection"), proto->m_tszUserName); + nlu.ptszDescriptiveName = name; + proto->hFileNetlibUser = (HANDLE) CallService(MS_NETLIB_REGISTERUSER, 0, (LPARAM) &nlu); + nlus.cbSize = sizeof(nlus); + nlus.useProxy = 0; + CallService(MS_NETLIB_SETUSERSETTINGS, (WPARAM) proto->hFileNetlibUser, (LPARAM) &nlus); + + return (proto->hNetlibUser != NULL)?TRUE:FALSE; +} + +void JabberWsUninit(TlenProtocol *proto) +{ + if (proto->hNetlibUser != NULL) Netlib_CloseHandle(proto->hNetlibUser); + if (proto->hFileNetlibUser != NULL) Netlib_CloseHandle(proto->hFileNetlibUser); + proto->hNetlibUser = NULL; + proto->hFileNetlibUser = NULL; +} + +JABBER_SOCKET JabberWsConnect(TlenProtocol *proto, char *host, WORD port) +{ + NETLIBOPENCONNECTION nloc = {0}; + + nloc.cbSize = sizeof(NETLIBOPENCONNECTION); //NETLIBOPENCONNECTION_V1_SIZE; + nloc.szHost = host; + nloc.wPort = port; + nloc.flags = 0; + nloc.timeout = 6; + return (HANDLE) CallService(MS_NETLIB_OPENCONNECTION, (WPARAM) proto->hNetlibUser, (LPARAM) &nloc); +} + + +int JabberWsSend(TlenProtocol *proto, JABBER_SOCKET s, char *data, int datalen) +{ + int len; + if ((len=Netlib_Send(s, data, datalen, /*MSG_NODUMP|*/MSG_DUMPASTEXT)) == SOCKET_ERROR || len != datalen) { + JabberLog(proto, "Netlib_Send() failed, error=%d", WSAGetLastError()); + return FALSE; + } + return TRUE; +} + +int JabberWsRecv(TlenProtocol *proto, JABBER_SOCKET s, char *data, long datalen) +{ + int ret; + ret = Netlib_Recv(s, data, datalen, /*MSG_NODUMP|*/MSG_DUMPASTEXT); + if (ret == SOCKET_ERROR) { + JabberLog(proto, "Netlib_Recv() failed, error=%d", WSAGetLastError()); + return 0; + } + if (ret == 0) { + JabberLog(proto, "Connection closed gracefully"); + return 0; + } + return ret; +} + + +int JabberWsSendAES(TlenProtocol *proto, char *data, int datalen, aes_context *aes_ctx, unsigned char *aes_iv) +{ + int len, sendlen; + unsigned char aes_input[16]; + unsigned char aes_output[256]; + if (proto->threadData == NULL) { + return FALSE; + } + while (datalen > 0) { + len = 0; + while (datalen > 0 && len < 256) { + int pad = datalen < 16 ? 16 - datalen : 0; + memcpy(aes_input, data, datalen < 16 ? datalen : 16); + memset(aes_input + 16 - pad, ' ', pad); + aes_crypt_cbc(aes_ctx, AES_ENCRYPT, 16, aes_iv, aes_input, aes_output + len); + datalen -= 16; + data += 16; + len += 16; + } + if (len > 0) { + JabberLog(proto, "Sending %d bytes", len); + if ((sendlen=Netlib_Send(proto->threadData->s, (char *)aes_output, len, MSG_NODUMP)) == SOCKET_ERROR || len != sendlen) { + JabberLog(proto, "Netlib_Send() failed, error=%d", WSAGetLastError()); + return FALSE; + } + } + } + return TRUE; +} + +int JabberWsRecvAES(TlenProtocol *proto, char *data, long datalen, aes_context *aes_ctx, unsigned char *aes_iv) +{ + int ret, len = 0, maxlen = datalen; + unsigned char aes_input[16]; + unsigned char *aes_output = (unsigned char *)data; + if (proto->threadData == NULL) { + return 0; + } + for (maxlen = maxlen & ~0xF; maxlen != 0; maxlen = maxlen & 0xF) { + ret = Netlib_Recv(proto->threadData->s, data, maxlen, MSG_NODUMP); + if (ret == SOCKET_ERROR) { + JabberLog(proto, "Netlib_Recv() failed, error=%d", WSAGetLastError()); + return 0; + } + if (ret == 0) { + JabberLog(proto, "Connection closed gracefully"); + return 0; + } + data += ret; + len += ret; + maxlen -= ret; + } + + ret = len; + while (len > 15) { + memcpy(aes_input, aes_output, 16); + aes_crypt_cbc(aes_ctx, AES_DECRYPT, 16, aes_iv, aes_input, aes_output); + aes_output += 16; + len -= 16; + } + return ret; +} + diff --git a/protocols/Tlen/src/jabber_xml.cpp b/protocols/Tlen/src/jabber_xml.cpp new file mode 100644 index 0000000000..5786404dc6 --- /dev/null +++ b/protocols/Tlen/src/jabber_xml.cpp @@ -0,0 +1,568 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Tlen Protocol Plugin for Miranda NG +Copyright (C) 2002-2004 Santithorn Bunchua +Copyright (C) 2004-2007 Piotr Piastucki + +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 + +static BOOL JabberXmlProcessElem(XmlState *xmlState, XmlElemType elemType, char *elemText, char *elemAttr); +static void JabberXmlRemoveChild(XmlNode *node, XmlNode *child); + +void JabberXmlInitState(XmlState *xmlState) +{ + if (xmlState == NULL) return; + xmlState->root.name = NULL; + xmlState->root.depth = 0; + xmlState->root.numAttr = 0; + xmlState->root.maxNumAttr = 0; + xmlState->root.attr = NULL; + xmlState->root.numChild = 0; + xmlState->root.maxNumChild = 0; + xmlState->root.child = NULL; + xmlState->root.text = NULL; + xmlState->root.state = NODE_OPEN; + xmlState->callback1_open = NULL; + xmlState->callback1_close = NULL; + xmlState->callback2_open = NULL; + xmlState->callback2_close = NULL; + xmlState->userdata1_open = NULL; + xmlState->userdata1_close = NULL; + xmlState->userdata2_open = NULL; + xmlState->userdata2_close = NULL; +} + +void JabberXmlDestroyState(XmlState *xmlState) +{ + int i; + XmlNode *node; + + if (xmlState == NULL) return; + // Note: cannot use JabberXmlFreeNode() to free xmlState->root + // because it will do mir_free(xmlState->root) which is not freeable. + node = &(xmlState->root); + // Free all children first + for (i=0; inumChild; i++) + JabberXmlFreeNode(node->child[i]); + if (node->child) mir_free(node->child); + // Free all attributes + for (i=0; inumAttr; i++) { + if (node->attr[i]->name) mir_free(node->attr[i]->name); + if (node->attr[i]->value) mir_free(node->attr[i]->value); + mir_free(node->attr[i]); + } + if (node->attr) mir_free(node->attr); + // Free string field + if (node->text) mir_free(node->text); + if (node->name) mir_free(node->name); +} + +BOOL JabberXmlSetCallback(XmlState *xmlState, int depth, XmlElemType type, void (*callback)(XmlNode*, void*), void *userdata) +{ + if (depth == 1 && type == ELEM_OPEN) { + xmlState->callback1_open = callback; + xmlState->userdata1_open = userdata; + } + else if (depth == 1 && type == ELEM_CLOSE) { + xmlState->callback1_close = callback; + xmlState->userdata1_close = userdata; + } + else if (depth == 2 && type == ELEM_OPEN) { + xmlState->callback2_open = callback; + xmlState->userdata2_open = userdata; + } + else if (depth == 2 && type == ELEM_CLOSE) { + xmlState->callback2_close = callback; + xmlState->userdata2_close = userdata; + } + else + return FALSE; + + return TRUE; +} + +#define TAG_MAX_LEN 50 +#define ATTR_MAX_LEN 1024 +int JabberXmlParse(XmlState *xmlState, char *buffer, int datalen) +{ + char *p, *q, *r, *eob; + char *str; + int num; + char tag[TAG_MAX_LEN]; + char attr[ATTR_MAX_LEN]; + XmlElemType elemType = ELEM_OPEN; + + eob = buffer + datalen; + num = 0; + // Skip leading whitespaces + for (p=buffer; p TAG_MAX_LEN) { +// JabberLog("TAG_MAX_LEN too small, ignore current tag"); + } + else { + if (*(p+1) == '/') { // closing tag + strncpy(tag, p+2, r-(p+2)); + tag[r-(p+2)] = '\0'; + elemType = ELEM_CLOSE; + } + else { + if (*(r-1) == '/') { // single open/close tag + strncpy(tag, p+1, r-(p+1)-1); + tag[r-(p+1)-1] = '\0'; + elemType = ELEM_OPENCLOSE; + } + else { + strncpy(tag, p+1, r-(p+1)); + tag[r-(p+1)] = '\0'; + elemType = ELEM_OPEN; + } + } + for (;r ATTR_MAX_LEN) { +// JabberLog("ATTR_MAX_LEN too small, ignore current tag"); + } + else { + strncpy(attr, r, q-r); + if ((q-r)>0 && attr[q-r-1] == '/') { + attr[q-r-1] = '\0'; + elemType = ELEM_OPENCLOSE; + } + else + attr[q-r] = '\0'; + JabberXmlProcessElem(xmlState, elemType, tag, attr); + } + } + num += (q-p+1); + p = q + 1; + if (elemType == ELEM_CLOSE || elemType == ELEM_OPENCLOSE) { + // Skip whitespaces after end tags + for (; pnumAttr >= node->maxNumAttr) { + node->maxNumAttr = node->numAttr + 20; + node->attr = (XmlAttr **) mir_realloc(node->attr, node->maxNumAttr*sizeof(XmlAttr *)); + } + a = node->attr[node->numAttr] = (XmlAttr *) mir_alloc(sizeof(XmlAttr)); + node->numAttr++; + + // Skip possible whitespaces between key and '=' + for (;*p != '\0' && (*p == ' ' || *p == '\t'); p++); + + if (*p == '\0') { + a->name = (char *) mir_alloc(klen+1); + strncpy(a->name, kstart, klen); + a->name[klen] = '\0'; + a->value = mir_strdup(""); + break; + } + + if (*p != '=') { + a->name = (char *) mir_alloc(klen+1); + strncpy(a->name, kstart, klen); + a->name[klen] = '\0'; + a->value = mir_strdup(""); + continue; + } + + // Found '=' + p++; + + // Skip possible whitespaces between '=' and value + for (;*p != '\0' && (*p == ' ' || *p == '\t'); p++); + + if (*p == '\0') { + a->name = (char *) mir_alloc(klen+1); + strncpy(a->name, kstart, klen); + a->name[klen] = '\0'; + a->value = mir_strdup(""); + break; + } + + // Fetch value + if (*p == '\'' || *p == '"') { + p++; + vstart = p; + for (;*p != '\0' && *p != *(vstart-1); p++); + vlen = p-vstart; + if (*p != '\0') p++; + } + else { + vstart = p; + for (;*p != '\0' && *p != ' ' && *p != '\t'; p++); + vlen = p-vstart; + } + + a->name = (char *) mir_alloc(klen+1); + strncpy(a->name, kstart, klen); + a->name[klen] = '\0'; + a->value = (char *) mir_alloc(vlen+1); + strncpy(a->value, vstart, vlen); + a->value[vlen] = '\0'; + } +} + +static BOOL JabberXmlProcessElem(XmlState *xmlState, XmlElemType elemType, char *elemText, char *elemAttr) +{ + XmlNode *node, *parentNode, *n; + //BOOL activateCallback = FALSE; + char *text, *attr; + + if (elemText == NULL) return FALSE; + + if (elemType == ELEM_OPEN && !strcmp(elemText, "?xml")) { +// JabberLog("XML: skip tag"); + return TRUE; + } + + // Find active node + node = &(xmlState->root); + parentNode = NULL; + while (node->numChild>0 && node->child[node->numChild-1]->state == NODE_OPEN) { + parentNode = node; + node = node->child[node->numChild-1]; + } + + if (node->state != NODE_OPEN) return FALSE; + + text = mir_strdup(elemText); + + if (elemAttr) + attr = mir_strdup(elemAttr); + else + attr = NULL; + + switch (elemType) { + case ELEM_OPEN: + if (node->numChild >= node->maxNumChild) { + node->maxNumChild = node->numChild + 20; + node->child = (XmlNode **) mir_realloc(node->child, node->maxNumChild*sizeof(XmlNode *)); + } + n = node->child[node->numChild] = (XmlNode *) mir_alloc(sizeof(XmlNode)); + node->numChild++; + n->name = text; + n->depth = node->depth + 1; + n->state = NODE_OPEN; + n->numChild = n->maxNumChild = 0; + n->child = NULL; + n->numAttr = n->maxNumAttr = 0; + n->attr = NULL; + JabberXmlParseAttr(n, attr); + n->text = NULL; + if (n->depth == 1 && xmlState->callback1_open != NULL) + (*(xmlState->callback1_open))(n, xmlState->userdata1_open); + if (n->depth == 2 && xmlState->callback2_open != NULL) + (*xmlState->callback2_open)(n, xmlState->userdata2_open); + break; + case ELEM_OPENCLOSE: + if (node->numChild >= node->maxNumChild) { + node->maxNumChild = node->numChild + 20; + node->child = (XmlNode **) mir_realloc(node->child, node->maxNumChild*sizeof(XmlNode *)); + } + n = node->child[node->numChild] = (XmlNode *) mir_alloc(sizeof(XmlNode)); + node->numChild++; + n->name = text; + n->depth = node->depth + 1; + n->state = NODE_CLOSE; + n->numChild = n->maxNumAttr = 0; + n->child = NULL; + n->numAttr = n->maxNumAttr = 0; + n->attr = NULL; + JabberXmlParseAttr(n, attr); + n->text = NULL; + if (n->depth == 1 && xmlState->callback1_close != NULL) { + (*(xmlState->callback1_close))(n, xmlState->userdata1_close); + JabberXmlRemoveChild(node, n); + } + if (n->depth == 2 && xmlState->callback2_close != NULL) { + (*xmlState->callback2_close)(n, xmlState->userdata2_close); + JabberXmlRemoveChild(node, n); + } + break; + case ELEM_CLOSE: + if (node->name != NULL && !strcmp(node->name, text)) { + node->state = NODE_CLOSE; + if (node->depth == 1 && xmlState->callback1_close != NULL) { + (*(xmlState->callback1_close))(node, xmlState->userdata1_close); + JabberXmlRemoveChild(parentNode, node); + } + if (node->depth == 2 && xmlState->callback2_close != NULL) { + (*xmlState->callback2_close)(node, xmlState->userdata2_close); + JabberXmlRemoveChild(parentNode, node); + } + mir_free(text); + } + else { +// JabberLog("XML: Closing without opening tag", text); + mir_free(text); + if (attr) mir_free(attr); + return FALSE; + } + break; + case ELEM_TEXT: + node->text = text; + break; + default: + mir_free(text); + if (attr) mir_free(attr); + return FALSE; + } + + if (attr) mir_free(attr); + + return TRUE; +} + +char *JabberXmlGetAttrValue(XmlNode *node, char *key) +{ + int i; + + if (node == NULL || node->numAttr <= 0 || key == NULL || strlen(key) <= 0) + return NULL; + for (i=0; inumAttr; i++) { + if (node->attr[i]->name && !strcmp(key, node->attr[i]->name)) + return node->attr[i]->value; + } + return NULL; +} + +XmlNode *JabberXmlGetChild(XmlNode *node, char *tag) +{ + return JabberXmlGetNthChild(node, tag, 1); +} + +XmlNode *JabberXmlGetNthChild(XmlNode *node, char *tag, int nth) +{ + int i, num; + + if (node == NULL || node->numChild <= 0 || tag == NULL || strlen(tag) <= 0 || nth < 1) + return NULL; + num = 1; + for (i=0; inumChild; i++) { + if (node->child[i]->name && !strcmp(tag, node->child[i]->name)) { + if (num == nth) { + return node->child[i]; + } + num++; + } + } + return NULL; +} + +XmlNode *JabberXmlGetChildWithGivenAttrValue(XmlNode *node, char *tag, char *attrKey, char *attrValue) +{ + int i; + char *str; + + if (node == NULL || node->numChild <= 0 || tag == NULL || strlen(tag) <= 0 || attrKey == NULL || strlen(attrKey) <= 0 || attrValue == NULL || strlen(attrValue) <= 0) + return NULL; + for (i=0; inumChild; i++) { + if (node->child[i]->name && !strcmp(tag, node->child[i]->name)) { + if ((str=JabberXmlGetAttrValue(node->child[i], attrKey)) != NULL) + if (!strcmp(str, attrValue)) + return node->child[i]; + } + } + return NULL; +} + +static void JabberXmlRemoveChild(XmlNode *node, XmlNode *child) +{ + int i; + + if (node == NULL || child == NULL || node->numChild <= 0) return; + for (i=0; inumChild; i++) { + if (node->child[i] == child) + break; + } + if (i < node->numChild) { + for (++i; inumChild; i++) + node->child[i-1] = node->child[i]; + node->numChild--; + JabberXmlFreeNode(child); + } +} + +void JabberXmlFreeNode(XmlNode *node) +{ + int i; + + if (node == NULL) return; + // Free all children first + for (i=0; inumChild; i++) + JabberXmlFreeNode(node->child[i]); + if (node->child) mir_free(node->child); + // Free all attributes + for (i=0; inumAttr; i++) { + if (node->attr[i]->name) mir_free(node->attr[i]->name); + if (node->attr[i]->value) mir_free(node->attr[i]->value); + mir_free(node->attr[i]); + } + if (node->attr) mir_free(node->attr); + // Free string field + if (node->text) mir_free(node->text); + if (node->name) mir_free(node->name); + // Free the node itself + mir_free(node); +} + +XmlNode *JabberXmlCopyNode(XmlNode *node) +{ + XmlNode *n; + int i; + + if (node == NULL) return NULL; + n = (XmlNode *) mir_alloc(sizeof(XmlNode)); + // Copy attributes + if (node->numAttr > 0) { + n->attr = (XmlAttr **) mir_alloc(node->numAttr*sizeof(XmlAttr *)); + for (i=0; inumAttr; i++) { + n->attr[i] = (XmlAttr *) mir_alloc(sizeof(XmlAttr)); + if (node->attr[i]->name) n->attr[i]->name = mir_strdup(node->attr[i]->name); + else n->attr[i]->name = NULL; + if (node->attr[i]->value) n->attr[i]->value = mir_strdup(node->attr[i]->value); + else n->attr[i]->value = NULL; + } + } + else + n->attr = NULL; + // Recursively copy children + if (node->numChild > 0) { + n->child = (XmlNode **) mir_alloc(node->numChild*sizeof(XmlNode *)); + for (i=0; inumChild; i++) + n->child[i] = JabberXmlCopyNode(node->child[i]); + } + else + n->child = NULL; + // Copy other fields + n->numAttr = node->numAttr; + n->maxNumAttr = node->numAttr; + n->numChild = node->numChild; + n->maxNumChild = node->numChild; + n->depth = node->depth; + n->state = node->state; + n->name = (node->name)?mir_strdup(node->name):NULL; + n->text = (node->text)?mir_strdup(node->text):NULL; + + return n; +} + +XmlNode *JabberXmlCreateNode(char *name) +{ + XmlNode *n; + + if (name == NULL) + return NULL; + + n = (XmlNode *) mir_alloc(sizeof(XmlNode)); + memset(n, 0, sizeof(XmlNode)); + n->name = mir_strdup(name); + return n; +} + +void JabberXmlAddAttr(XmlNode *n, char *name, char *value) +{ + int i; + + if (n == NULL || name == NULL || value == NULL) + return; + + i = n->numAttr; + (n->numAttr)++; + n->attr = (XmlAttr **) mir_realloc(n->attr, sizeof(XmlAttr *) * n->numAttr); + n->attr[i] = (XmlAttr *) mir_alloc(sizeof(XmlAttr)); + n->attr[i]->name = mir_strdup(name); + n->attr[i]->value = mir_strdup(value); +} + +XmlNode *JabberXmlAddChild(XmlNode *n, char *name) +{ + int i; + + if (n == NULL || name == NULL) + return NULL; + + i = n->numChild; + n->numChild++; + n->child = (XmlNode **) mir_realloc(n->child, sizeof(XmlNode *) * n->numChild); + n->child[i] = (XmlNode *) mir_alloc(sizeof(XmlNode)); + memset(n->child[i], 0, sizeof(XmlNode)); + n->child[i]->name = mir_strdup(name); + return n->child[i]; +} + +void JabberXmlAddText(XmlNode *n, char *text) +{ + if (n != NULL && text != NULL) { + if (n->text) mir_free(n->text); + n->text = mir_strdup(text); + } +} + diff --git a/protocols/Tlen/src/jabber_xml.h b/protocols/Tlen/src/jabber_xml.h new file mode 100644 index 0000000000..165a8fadc5 --- /dev/null +++ b/protocols/Tlen/src/jabber_xml.h @@ -0,0 +1,79 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Tlen Protocol Plugin for Miranda NG +Copyright (C) 2002-2004 Santithorn Bunchua +Copyright (C) 2004-2007 Piotr Piastucki + +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. + +*/ + +#ifndef _JABBER_XML_H_ +#define _JABBER_XML_H_ + +typedef enum { ELEM_OPEN, ELEM_CLOSE, ELEM_OPENCLOSE, ELEM_TEXT } XmlElemType; +typedef enum { NODE_OPEN, NODE_CLOSE } XmlNodeType; + +typedef struct tagXmlAttr { + char *name; + char *value; +} XmlAttr; + +typedef struct tagXmlNode { + int depth; // depth of the current node (1=root) + char *name; // tag name of the current node + int numAttr; // number of attributes + int maxNumAttr; // internal use (num of slots currently allocated to attr) + XmlAttr **attr; // attribute list + int numChild; // number of direct child nodes + int maxNumChild; // internal use (num of slots currently allocated to child) + struct tagXmlNode **child; // child node list + char *text; + XmlNodeType state; // internal use by parser +} XmlNode; + + +typedef struct tagXmlState { + XmlNode root; // root is the document (depth = 0); + // callback for depth=n element on opening/closing + void (*callback1_open)(XmlNode *,void *); + void (*callback1_close)(XmlNode *,void *); + void (*callback2_open)(XmlNode *,void *); + void (*callback2_close)(XmlNode *,void *); + void *userdata1_open; + void *userdata1_close; + void *userdata2_open; + void *userdata2_close; +} XmlState; + +void JabberXmlInitState(XmlState *xmlState); +void JabberXmlDestroyState(XmlState *xmlState); +BOOL JabberXmlSetCallback(XmlState *xmlState, int depth, XmlElemType type, void (*callback)(XmlNode*, void*), void *userdata); +int JabberXmlParse(XmlState *xmlState, char *buffer, int datalen); +char *JabberXmlGetAttrValue(XmlNode *node, char *key); +XmlNode *JabberXmlGetChild(XmlNode *node, char *tag); +XmlNode *JabberXmlGetNthChild(XmlNode *node, char *tag, int nth); +XmlNode *JabberXmlGetChildWithGivenAttrValue(XmlNode *node, char *tag, char *attrKey, char *attrValue); +void JabberXmlFreeNode(XmlNode *node); +XmlNode *JabberXmlCopyNode(XmlNode *node); + +XmlNode *JabberXmlCreateNode(char *name); +void JabberXmlAddAttr(XmlNode *n, char *name, char *value); +XmlNode *JabberXmlAddChild(XmlNode *n, char *name); +void JabberXmlAddText(XmlNode *n, char *text); + +#endif + diff --git a/protocols/Tlen/src/resource.h b/protocols/Tlen/src/resource.h new file mode 100644 index 0000000000..6f3b59b64d --- /dev/null +++ b/protocols/Tlen/src/resource.h @@ -0,0 +1,147 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by Tlen.rc +// + +#define IDI_TLEN 100 +#define IDI_MAIL 101 +#define IDI_MUC 102 +#define IDI_CHATS 103 +#define IDI_GRANT 104 +#define IDI_REQUEST 105 +#define IDI_VOICE 106 +#define IDI_MICROPHONE 107 +#define IDI_SPEAKER 108 +#define IDI_IMAGE 109 + +#define IDD_OPTIONS_BASIC 151 +#define IDD_OPTIONS_VOICE 152 +#define IDD_OPTIONS_POPUPS 153 +#define IDD_OPTIONS_ADVANCED 154 +#define IDD_USER_INFO 155 +#define IDD_USER_VCARD 156 +#define IDD_PASSWORD 157 +#define IDD_ADVSEARCH 158 +#define IDD_VOICE 159 +#define IDD_ACCEPT_VOICE 160 +#define IDD_USER_CHANGEAVATAR 161 +#define IDD_ACCMGRUI 162 + +#define IDC_TABS 1000 +#define IDC_EDIT_USERNAME 1001 +#define IDC_SAVE 1002 +#define IDC_EDIT_PASSWORD 1003 +#define IDC_EDIT_LOGIN_SERVER 1004 +#define IDC_INFO_JID 1007 +#define IDC_INFO_RESOURCE 1008 +#define IDC_SHOW_OFFLINE 1012 +#define IDC_OFFLINE_MESSAGE 1013 +#define IDC_OFFLINE_MESSAGE_OPTION 1014 +#define IDC_VISIBILITY_SUPPORT 1015 +#define IDC_NUDGE_SUPPORT 1016 +#define IDC_LOG_ALERTS 1017 + +#define IDC_SUBSCRIPTION 1039 +#define IDC_REGISTERACCOUNT 1040 +#define IDC_SIMPLE 1041 +#define IDC_KEEPALIVE 1042 +#define IDC_HOST 1043 +#define IDC_HOSTPORT 1044 +#define IDC_USE_SSL 1045 +#define IDC_SAVEPASSWORD 1048 +#define IDC_ROSTER_ALERTS 1049 +#define IDC_PASSWORD 1050 +#define IDC_RECONNECT 1050 +#define IDC_JID 1051 +#define IDC_ROSTER_SYNC 1052 +#define IDC_ALERT_POLICY 1053 +#define IDC_MUC_POLICY 1054 +#define IDC_VOICE_POLICY 1055 +#define IDC_IGNORE_ADVERTISEMENTS 1056 +#define IDC_AVATARS 1057 +#define IDC_VERSIONINFO 1058 +#define IDC_IMAGE_POLICY 1059 +#define IDC_CITY 1060 +#define IDC_FULLNAME 1061 +#define IDC_NICKNAME 1062 +#define IDC_FIRSTNAME 1063 +#define IDC_LASTNAME 1064 +#define IDC_BIRTH 1065 +#define IDC_AGE 1065 +#define IDC_OCCUPATION 1066 +#define IDC_EMAIL 1073 +#define IDC_GENDER 1096 +#define IDC_VOICECONVERSATIONS 1097 +#define IDC_PUBLICSTATUS 1098 +#define IDC_VCQUALITY 1100 +#define IDC_VUMETERIN 1101 +#define IDC_VUMETEROUT 1102 +#define IDC_BYTESIN 1103 +#define IDC_BYTESOUT 1104 +#define IDC_MICROPHONE 1105 +#define IDC_SPEAKER 1106 +#define IDC_ACCEPT 1107 + +#define IDC_FILE_PROXY_TYPE_LABEL 1108 +#define IDC_FILE_PROXY_TYPE 1109 +#define IDC_FILE_PROXY_HOST_LABEL 1110 +#define IDC_FILE_PROXY_HOST 1111 +#define IDC_FILE_PROXY_PORT_LABEL 1112 +#define IDC_FILE_PROXY_PORT 1113 +#define IDC_FILE_PROXY_USE_AUTH 1114 +#define IDC_FILE_PROXY_USER 1115 +#define IDC_FILE_PROXY_USER_LABEL 1116 +#define IDC_FILE_PROXY_PASSWORD_LABEL 1117 +#define IDC_FILE_PROXY_PASSWORD 1118 +#define IDC_FILE_USE_PROXY 1119 +#define IDC_VOICE_DEVICE_IN 1120 +#define IDC_VOICE_DEVICE_OUT 1121 + +#define IDC_MSG_ACK 1124 +#define IDC_SERVER 1125 +#define IDC_NICK 1129 +#define IDC_LIST 1133 +#define IDC_ENTER 1144 +#define IDC_AGEFROM 1152 +#define IDC_AGETO 1153 +#define IDC_LOOKFOR 1154 +#define IDC_SCHOOL 1155 +#define IDC_FROM 1175 +#define IDC_DELAY 1180 +#define IDC_COLORBKG 1181 +#define IDC_COLORTXT 1182 +#define IDC_PREVIEW 1183 +#define IDC_ENABLEPOPUP 1184 +#define IDC_DELAY_PERMANENT 1185 +#define IDC_DELAY_CUSTOM 1186 +#define IDC_DELAY_POPUP 1187 +#define IDC_TLEN 1190 +#define IDC_GENDER_TEXT 1195 +#define IDC_OCCUPATION_TEXT 1199 +#define IDC_LOOKFOR_TEXT 1200 +#define IDC_GROUP 1203 +#define IDC_SOFTWARE 1204 +#define IDC_VERSION 1205 +#define IDC_SYSTEM 1206 +#define IDC_AVATAR 1210 +#define IDC_SETAVATAR 1211 +#define IDC_DELETEAVATAR 1212 +#define IDC_AVATAR_LIST 1213 +#define IDC_OLD_AVATAR 1214 +#define IDC_BROWSEAVATAR 1215 +#define IDC_PUBLICAVATAR 1216 + +#define IDC_STATUS 1414 +#define IDC_PLAN 1415 +#define IDC_PERSONALGROUP 1434 +#define IDC_EXTRAGROUP 1435 +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 190 +#define _APS_NEXT_COMMAND_VALUE 40017 +#define _APS_NEXT_CONTROL_VALUE 1204 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/protocols/Tlen/src/tlen.cpp b/protocols/Tlen/src/tlen.cpp new file mode 100644 index 0000000000..2feb99495e --- /dev/null +++ b/protocols/Tlen/src/tlen.cpp @@ -0,0 +1,524 @@ +/* + +Tlen Protocol Plugin for Miranda NG +Copyright (C) 2002-2004 Santithorn Bunchua +Copyright (C) 2004-2007 Piotr Piastucki + +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 "commons.h" +#include "jabber.h" +#include "tlen_muc.h" +#include "tlen_file.h" +#include "tlen_voice.h" +#include "jabber_list.h" +#include "jabber_iq.h" +#include "resource.h" +#include "tlen_picture.h" +#include +#include +#include +#include +#include +#include "m_mucc.h" + + +int hLangpack; +HINSTANCE hInst; +HANDLE hMainThread; + +PLUGININFOEX pluginInfoEx = { + sizeof(PLUGININFOEX), + "Tlen Protocol", + PLUGIN_MAKE_VERSION(TLEN_MAJOR_VERSION,TLEN_MINOR_VERSION,TLEN_RELEASE_NUM,TLEN_BUILD_NUM), + "Tlen protocol plugin for Miranda NG (version: " TLEN_VERSION_STRING ")", + "Santithorn Bunchua, Adam Strzelecki, Piotr Piastucki", + "the_leech@users.berlios.de", + "(c) 2002-2012 Santithorn Bunchua, Piotr Piastucki", + "http://miranda-ng.org/", + UNICODE_AWARE, + {0x748f8934, 0x781a, 0x528d, { 0x52, 0x08, 0x00, 0x12, 0x65, 0x40, 0x4a, 0xb3 }} +}; + +// Main jabber server connection thread global variables + +int TlenUserInfoInit(void *ptr, WPARAM wParam, LPARAM lParam); +int TlenSystemModulesLoaded(void *ptr, WPARAM wParam, LPARAM lParam); + +BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpvReserved) +{ +#ifdef _DEBUG + _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); +#endif + + hInst = hModule; + return TRUE; +} + +extern "C" __declspec(dllexport) PLUGININFOEX *MirandaPluginInfoEx(DWORD mirandaVersion) +{ + return &pluginInfoEx; +} + +extern "C" __declspec(dllexport) const MUUID interfaces[] = {MIID_PROTOCOL, MIID_LAST}; +extern "C" __declspec(dllexport) const MUUID* MirandaPluginInterfaces(void) +{ + return interfaces; +} + +struct +{ + TCHAR* szDescr; + char* szName; + int defIconID; + HANDLE hIconLibItem; +} +static iconList[] = +{ + { _T("Protocol icon"), "PROTO", IDI_TLEN }, + { _T("Tlen inbox"), "MAIL", IDI_MAIL }, + { _T("Group chats"), "MUC", IDI_MUC }, + { _T("Tlen chats"), "CHATS", IDI_CHATS }, + { _T("Grant authorization"), "GRANT", IDI_GRANT }, + { _T("Request authorization"), "REQUEST", IDI_REQUEST }, + { _T("Voice chat"), "VOICE", IDI_VOICE }, + { _T("Microphone"), "MICROPHONE", IDI_MICROPHONE }, + { _T("Speaker"), "SPEAKER", IDI_SPEAKER }, + { _T("Send image"), "IMAGE", IDI_IMAGE } +}; + +static HANDLE GetIconHandle(int iconId) { + int i; + for (i = 0; i < SIZEOF(iconList); i++) + if (iconList[i].defIconID == iconId) + return iconList[i].hIconLibItem; + return NULL; +} + +HICON GetIcolibIcon(int iconId) { + HANDLE handle = GetIconHandle(iconId); + if (handle != NULL) { + return (HICON) CallService(MS_SKIN2_GETICONBYHANDLE, 0, (LPARAM)handle); + } + return NULL; +} + +void ReleaseIcolibIcon(HICON hIcon) { + CallService( MS_SKIN2_RELEASEICON, (WPARAM)hIcon, 0 ); +} + +/* +static int TlenIconsChanged(void *ptr, WPARAM wParam, LPARAM lParam) +{ + return 0; +} +*/ + +static void TlenRegisterIcons() +{ + SKINICONDESC sid = { 0 }; + char path[MAX_PATH]; + TCHAR szSectionName[100]; + int i; + mir_sntprintf(szSectionName, SIZEOF( szSectionName ), _T("%s/%s"), _T("Protocols"), _T("Tlen")); + + GetModuleFileNameA(hInst, path, MAX_PATH); + sid.cbSize = sizeof(SKINICONDESC); + sid.cx = sid.cy = 16; + sid.ptszSection = szSectionName; + sid.pszDefaultFile = path; + sid.flags = SIDF_TCHAR; + + for ( i = 0; i < SIZEOF(iconList); i++ ) { + char szSettingName[100]; + mir_snprintf( szSettingName, sizeof( szSettingName ), "TLEN_%s", iconList[i].szName ); + sid.pszName = szSettingName; + sid.pszDescription = (char*)iconList[i].szDescr; + sid.iDefaultIndex = -iconList[i].defIconID; + iconList[i].hIconLibItem = Skin_AddIcon(&sid);; + } +} + +int TlenPrebuildContactMenu(void *ptr, WPARAM wParam, LPARAM lParam) +{ + HANDLE hContact; + DBVARIANT dbv; + CLISTMENUITEM clmi = {0}; + JABBER_LIST_ITEM *item; + TlenProtocol *proto = (TlenProtocol *)ptr; + clmi.cbSize = sizeof(CLISTMENUITEM); + if ((hContact=(HANDLE) wParam) != NULL && proto->isOnline) { + if (!DBGetContactSetting(hContact, proto->m_szModuleName, "jid", &dbv)) { + if ((item=JabberListGetItemPtr(proto, LIST_ROSTER, dbv.pszVal)) != NULL) { + if (item->subscription == SUB_NONE || item->subscription == SUB_FROM) + clmi.flags = CMIM_FLAGS; + else + clmi.flags = CMIM_FLAGS|CMIF_HIDDEN; + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM) proto->hMenuContactRequestAuth, (LPARAM) &clmi); + + if (item->subscription == SUB_NONE || item->subscription == SUB_TO) + clmi.flags = CMIM_FLAGS; + else + clmi.flags = CMIM_FLAGS|CMIF_HIDDEN; + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM) proto->hMenuContactGrantAuth, (LPARAM) &clmi); + + if (item->status != ID_STATUS_OFFLINE) + clmi.flags = CMIM_FLAGS; + else + clmi.flags = CMIM_FLAGS|CMIF_HIDDEN; + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM) proto->hMenuContactMUC, (LPARAM) &clmi); + + if (item->status != ID_STATUS_OFFLINE && !TlenVoiceIsInUse(proto)) + clmi.flags = CMIM_FLAGS; + else + clmi.flags = CMIM_FLAGS|CMIF_HIDDEN; + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM) proto->hMenuContactVoice, (LPARAM) &clmi); + + if (item->status != ID_STATUS_OFFLINE) + clmi.flags = CMIM_FLAGS; + else + clmi.flags = CMIM_FLAGS|CMIF_HIDDEN; + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM) proto->hMenuPicture, (LPARAM) &clmi); + + DBFreeVariant(&dbv); + return 0; + } + DBFreeVariant(&dbv); + } + } + clmi.flags = CMIM_FLAGS|CMIF_HIDDEN; + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM) proto->hMenuContactMUC, (LPARAM) &clmi); + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM) proto->hMenuContactVoice, (LPARAM) &clmi); + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM) proto->hMenuContactRequestAuth, (LPARAM) &clmi); + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM) proto->hMenuContactGrantAuth, (LPARAM) &clmi); + return 0; +} + +INT_PTR TlenContactMenuHandleRequestAuth(void *ptr, LPARAM wParam, LPARAM lParam) +{ + HANDLE hContact; + DBVARIANT dbv; + TlenProtocol *proto = (TlenProtocol *)ptr; + if ((hContact=(HANDLE) wParam) != NULL && proto->isOnline) { + if (!DBGetContactSetting(hContact, proto->m_szModuleName, "jid", &dbv)) { + JabberSend(proto, "", dbv.pszVal); + DBFreeVariant(&dbv); + } + } + return 0; +} + +INT_PTR TlenContactMenuHandleGrantAuth(void *ptr, LPARAM wParam, LPARAM lParam) +{ + HANDLE hContact; + DBVARIANT dbv; + TlenProtocol *proto = (TlenProtocol *)ptr; + if ((hContact=(HANDLE) wParam) != NULL && proto->isOnline) { + if (!DBGetContactSetting(hContact, proto->m_szModuleName, "jid", &dbv)) { + JabberSend(proto, "", dbv.pszVal); + DBFreeVariant(&dbv); + } + } + return 0; +} + +INT_PTR TlenContactMenuHandleSendPicture(void *ptr, LPARAM wParam, LPARAM lParam) +{ + HANDLE hContact; + TlenProtocol *proto = (TlenProtocol *)ptr; + if ((hContact=(HANDLE) wParam) != NULL && proto->isOnline) { + SendPicture(proto, hContact); + } + return 0; +} + +INT_PTR TlenMenuHandleInbox(void *ptr, LPARAM wParam, LPARAM lParam) +{ + char szFileName[ MAX_PATH ]; + DBVARIANT dbv; + NETLIBHTTPREQUEST req; + NETLIBHTTPHEADER headers[2]; + NETLIBHTTPREQUEST *resp; + char *login = NULL, *password = NULL; + char form[1024]; + char cookie[1024]; + TlenProtocol *proto = (TlenProtocol *)ptr; + if (!DBGetContactSetting(NULL, proto->m_szModuleName, "LoginName", &dbv)) { + login = mir_strdup(dbv.pszVal); + DBFreeVariant(&dbv); + } + if (DBGetContactSettingByte(NULL, proto->m_szModuleName, "SavePassword", TRUE) == TRUE) { + if (!DBGetContactSetting(NULL, proto->m_szModuleName, "Password", &dbv)) { + CallService(MS_DB_CRYPT_DECODESTRING, strlen(dbv.pszVal)+1, (LPARAM) dbv.pszVal); + password = mir_strdup(dbv.pszVal); + DBFreeVariant(&dbv); + } + } else if (proto->threadData != NULL && strlen(proto->threadData->password) > 0) { + password = mir_strdup(proto->threadData->password); + } + + ZeroMemory(&cookie, sizeof(cookie)); + if (login != NULL && password != NULL) { + mir_snprintf( form, SIZEOF(form), "username=%s&password=%s", login, password); + headers[0].szName = "Content-Type"; + headers[0].szValue = "application/x-www-form-urlencoded"; + ZeroMemory(&req, sizeof(req)); + req.cbSize = sizeof(req); + req.requestType = REQUEST_POST; + req.flags = 0; + req.headersCount = 1; + req.headers = headers; + req.pData = form; + req.dataLength = (int)strlen(form); + req.szUrl = "http://poczta.o2.pl/login.html"; + resp = (NETLIBHTTPREQUEST *)CallService(MS_NETLIB_HTTPTRANSACTION, (WPARAM)proto->hNetlibUser, (LPARAM)&req); + if (resp != NULL) { + if (resp->resultCode/100 == 2 || resp->resultCode == 302) { + int i; + for (i=0; iheadersCount; i++ ) { + if (strcmpi(resp->headers[i].szName, "Set-Cookie") == 0) { + char *start = strstr(resp->headers[i].szValue, "ssid="); + if (start != NULL) { + char *end = strstr(resp->headers[i].szValue, ";"); + start = start + 5; + if (end == NULL) { + end = resp->headers[i].szValue + strlen(resp->headers[i].szValue); + } + strncpy(cookie, start, (end - start)); + break; + } + } + } + } + CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, 0, (LPARAM)resp); + } + } + mir_free(login); + mir_free(password); + _snprintf(szFileName, sizeof(szFileName), "http://poczta.o2.pl/login.html?sid=%s", cookie); + CallService(MS_UTILS_OPENURL, (WPARAM) 1, (LPARAM) szFileName); + return 0; +} + +int TlenOnModulesLoaded(void *ptr, WPARAM wParam, LPARAM lParam) +{ + + char str[128]; + TlenProtocol *proto = (TlenProtocol *)ptr; + /* Set all contacts to offline */ + HANDLE hContact = db_find_first(); + while (hContact != NULL) { + char *szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0); + if (szProto != NULL && !strcmp(szProto, proto->m_szModuleName)) { + if (DBGetContactSettingWord(hContact, proto->m_szModuleName, "Status", ID_STATUS_OFFLINE) != ID_STATUS_OFFLINE) { + DBWriteContactSettingWord(hContact, proto->m_szModuleName, "Status", ID_STATUS_OFFLINE); + } + } + hContact = db_find_next(hContact); + } + TlenMUCInit(proto); + sprintf(str, "%s", LPGEN("Incoming mail")); + SkinAddNewSoundEx("TlenMailNotify", proto->m_szProtoName, str); + sprintf(str, "%s", LPGEN("Alert")); + SkinAddNewSoundEx("TlenAlertNotify", proto->m_szProtoName, str); + sprintf(str, "%s", LPGEN("Voice chat")); + SkinAddNewSoundEx("TlenVoiceNotify", proto->m_szProtoName, str); + + HookEventObj_Ex(ME_USERINFO_INITIALISE, proto, TlenUserInfoInit); + + return 0; +} + + +int TlenPreShutdown(void *ptr, WPARAM wParam, LPARAM lParam) +{ + TlenProtocol *proto = (TlenProtocol *)ptr; + JabberLog(proto, "TLEN TlenPreShutdown"); + return 0; +} + + +static void initMenuItems(TlenProtocol *proto) +{ + + char text[_MAX_PATH]; + CLISTMENUITEM mi, clmi; + memset(&mi, 0, sizeof(CLISTMENUITEM)); + mi.cbSize = sizeof(CLISTMENUITEM); + memset(&clmi, 0, sizeof(CLISTMENUITEM)); + clmi.cbSize = sizeof(CLISTMENUITEM); + clmi.flags = CMIM_FLAGS | CMIF_GRAYED; + + mi.pszContactOwner = proto->m_szModuleName; + mi.popupPosition = 500090000; + + strcpy(text, proto->m_szModuleName); + mi.pszService = text; + mi.ptszName = proto->m_tszUserName; + mi.position = -1999901009; + mi.pszPopupName = (char *)-1; + mi.flags = CMIF_ROOTPOPUP | CMIF_TCHAR | CMIF_ICONFROMICOLIB; + mi.icolibItem = GetIconHandle(IDI_TLEN); + proto->hMenuRoot = Menu_AddMainMenuItem(&mi); + + mi.flags = CMIF_CHILDPOPUP | CMIF_ICONFROMICOLIB; + //mi.pszPopupName = (char *)proto->hMenuRoot; + mi.hParentMenu = (HGENMENU)proto->hMenuRoot; + + proto->hMenuChats = NULL; + if (ServiceExists(MS_MUCC_NEW_WINDOW)) + { + sprintf(text, "%s/MainMenuChats", proto->m_szModuleName); + CreateServiceFunction_Ex(text, proto, TlenMUCMenuHandleChats); + mi.pszName = "Tlen Chats"; + mi.position = 2000050001; + mi.icolibItem = GetIconHandle(IDI_CHATS); + mi.pszService = text; + proto->hMenuChats = Menu_AddMainMenuItem(&mi); + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM) proto->hMenuChats, (LPARAM) &clmi); + } + + // "Multi-User Conference" + sprintf(text, "%s/MainMenuMUC", proto->m_szModuleName); + CreateServiceFunction_Ex(text, proto, TlenMUCMenuHandleMUC); + mi.pszName = "Multi-User Conference"; + mi.position = 2000050002; + mi.icolibItem = GetIconHandle(IDI_MUC); + mi.pszService = text; + proto->hMenuMUC = Menu_AddMainMenuItem(&mi); + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM) proto->hMenuMUC, (LPARAM) &clmi); + + sprintf(text, "%s/MainMenuInbox", proto->m_szModuleName); + CreateServiceFunction_Ex(text, proto, TlenMenuHandleInbox); + mi.pszName = "Tlen Mail"; + mi.position = 2000050003; + mi.icolibItem = GetIconHandle(IDI_MAIL); + mi.pszService = text; + proto->hMenuInbox = Menu_AddMainMenuItem(&mi); + + mi.hParentMenu = NULL; + + + // "Send picture" + sprintf(text, "%s/SendPicture", proto->m_szModuleName); + CreateServiceFunction_Ex(text, proto, TlenContactMenuHandleSendPicture); + mi.flags = CMIF_ICONFROMICOLIB; + mi.pszName = "Send picture"; + mi.position = -2000019030; + mi.icolibItem = GetIconHandle(IDI_IMAGE); + mi.pszService = text; + proto->hMenuPicture = Menu_AddContactMenuItem(&mi); + + // "Invite to MUC" + sprintf(text, "%s/ContactMenuMUC", proto->m_szModuleName); + CreateServiceFunction_Ex(text, proto, TlenMUCContactMenuHandleMUC); + mi.pszName = "Multi-User Conference"; + mi.position = -2000019020; + mi.icolibItem = GetIconHandle(IDI_MUC); + mi.pszService = text; + proto->hMenuContactMUC = Menu_AddContactMenuItem(&mi); + + // "Invite to voice chat" + sprintf(text, "%s/ContactMenuVoice", proto->m_szModuleName); + CreateServiceFunction_Ex(text, proto, TlenVoiceContactMenuHandleVoice); + mi.pszName = "Voice Chat"; + mi.position = -2000019010; + mi.icolibItem = GetIconHandle(IDI_VOICE); + mi.pszService = text; + proto->hMenuContactVoice = Menu_AddContactMenuItem(&mi); + + // "Request authorization" + sprintf(text, "%s/RequestAuth", proto->m_szModuleName); + CreateServiceFunction_Ex(text, proto, TlenContactMenuHandleRequestAuth); + mi.pszName = "Request authorization"; + mi.position = -2000001001; + mi.icolibItem = GetIconHandle(IDI_REQUEST); + mi.pszService = text; + proto->hMenuContactRequestAuth = Menu_AddContactMenuItem(&mi); + + // "Grant authorization" + sprintf(text, "%s/GrantAuth", proto->m_szModuleName); + CreateServiceFunction_Ex(text, proto, TlenContactMenuHandleGrantAuth); + mi.pszName = "Grant authorization"; + mi.position = -2000001000; + mi.icolibItem = GetIconHandle(IDI_GRANT); + mi.pszService = text; + proto->hMenuContactGrantAuth = Menu_AddContactMenuItem(&mi); +} + +void uninitMenuItems(TlenProtocol *proto) { + CallService(MS_CLIST_REMOVEMAINMENUITEM, (WPARAM)proto->hMenuChats, (LPARAM) 0); + CallService(MS_CLIST_REMOVEMAINMENUITEM, (WPARAM)proto->hMenuMUC, (LPARAM) 0); + CallService(MS_CLIST_REMOVEMAINMENUITEM, (WPARAM)proto->hMenuInbox, (LPARAM) 0); + CallService(MS_CLIST_REMOVEMAINMENUITEM, (WPARAM)proto->hMenuRoot, (LPARAM) 0); + CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)proto->hMenuContactMUC, (LPARAM) 0); + CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)proto->hMenuPicture, (LPARAM) 0); + CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)proto->hMenuContactVoice, (LPARAM) 0); + CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)proto->hMenuContactRequestAuth, (LPARAM) 0); + CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)proto->hMenuContactGrantAuth, (LPARAM) 0); +} + +TlenProtocol* tlenProtoInit( const char* pszProtoName, const TCHAR* tszUserName ) +{ + TlenProtocol* ppro = new TlenProtocol( pszProtoName, tszUserName ); + + return ppro; +} + +int TlenSystemModulesLoaded(void *ptr, WPARAM wParam, LPARAM lParam) +{ + + TlenProtocol *proto = (TlenProtocol *)ptr; + initMenuItems(proto); + + return 0; +} + +static int tlenProtoUninit( TlenProtocol* ppro ) +{ + delete ppro; + return 0; +} + +extern "C" int __declspec(dllexport) Load(void) +{ + PROTOCOLDESCRIPTOR pd; + + mir_getLP( &pluginInfoEx ); + + DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &hMainThread, THREAD_SET_CONTEXT, FALSE, 0); + + srand((unsigned) time(NULL)); + + TlenRegisterIcons(); + + // Register protocol module + ZeroMemory(&pd, sizeof(PROTOCOLDESCRIPTOR)); + pd.cbSize = sizeof(PROTOCOLDESCRIPTOR); + pd.szName = "TLEN"; + pd.fnInit = ( pfnInitProto )tlenProtoInit; + pd.fnUninit = ( pfnUninitProto )tlenProtoUninit; + pd.type = PROTOTYPE_PROTOCOL; + CallService(MS_PROTO_REGISTERMODULE, 0, (LPARAM) &pd); + + return 0; +} + +extern "C" int __declspec(dllexport) Unload(void) +{ + return 0; +} diff --git a/protocols/Tlen/src/tlen_advsearch.cpp b/protocols/Tlen/src/tlen_advsearch.cpp new file mode 100644 index 0000000000..5a338a3bd6 --- /dev/null +++ b/protocols/Tlen/src/tlen_advsearch.cpp @@ -0,0 +1,113 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Tlen Protocol Plugin for Miranda NG +Copyright (C) 2002-2004 Santithorn Bunchua +Copyright (C) 2004-2007 Piotr Piastucki + +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 "resource.h" + +static void InitComboBox(HWND hwndCombo, JABBER_FIELD_MAP *fieldMap) +{ + int i, n; + + n = SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM)_T("")); + SendMessage(hwndCombo, CB_SETITEMDATA, n, 0); + SendMessage(hwndCombo, CB_SETCURSEL, n, 0); + for (i=0;;i++) { + if (fieldMap[i].name == NULL) + break; + n = SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) TranslateTS(fieldMap[i].name)); + SendMessage(hwndCombo, CB_SETITEMDATA, n, fieldMap[i].id); + } +} + +INT_PTR CALLBACK TlenAdvSearchDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch(msg) { + case WM_INITDIALOG: + TranslateDialogDefault(hwndDlg); + InitComboBox(GetDlgItem(hwndDlg, IDC_GENDER), tlenFieldGender); + InitComboBox(GetDlgItem(hwndDlg, IDC_LOOKFOR), tlenFieldLookfor); + InitComboBox(GetDlgItem(hwndDlg, IDC_STATUS), tlenFieldStatus); + InitComboBox(GetDlgItem(hwndDlg, IDC_OCCUPATION), tlenFieldOccupation); + InitComboBox(GetDlgItem(hwndDlg, IDC_PLAN), tlenFieldPlan); + return TRUE; + } + return FALSE; +} + +static void FetchField(HWND hwndDlg, UINT idCtrl, char *fieldName, char **str, int *strSize) +{ + char text[512]; + char *localFieldName, *localText; + + if (hwndDlg == NULL || fieldName == NULL || str == NULL || strSize == NULL) + return; + GetDlgItemTextA(hwndDlg, idCtrl, text, sizeof(text)); + if (text[0]) { + if ((localFieldName=JabberTextEncode(fieldName)) != NULL) { + if ((localText=JabberTextEncode(text)) != NULL) { + JabberStringAppend(str, strSize, "<%s>%s", localFieldName, localText, localFieldName); + mir_free(localText); + } + mir_free(localFieldName); + } + } +} + +static void FetchCombo(HWND hwndDlg, UINT idCtrl, char *fieldName, char **str, int *strSize) +{ + int value; + char *localFieldName; + + if (hwndDlg == NULL || fieldName == NULL || str == NULL || strSize == NULL) + return; + value = (int) SendDlgItemMessage(hwndDlg, idCtrl, CB_GETITEMDATA, SendDlgItemMessage(hwndDlg, idCtrl, CB_GETCURSEL, 0, 0), 0); + if (value > 0) { + if ((localFieldName=JabberTextEncode(fieldName)) != NULL) { + JabberStringAppend(str, strSize, "<%s>%d", localFieldName, value, localFieldName); + mir_free(localFieldName); + } + } +} + +char *TlenAdvSearchCreateQuery(HWND hwndDlg, int iqId) +{ + char *str; + int strSize; + + if (hwndDlg == NULL) return NULL; + str = NULL; + FetchField(hwndDlg, IDC_FIRSTNAME, "first", &str, &strSize); + FetchField(hwndDlg, IDC_LASTNAME, "last", &str, &strSize); + FetchField(hwndDlg, IDC_NICK, "nick", &str, &strSize); + FetchField(hwndDlg, IDC_EMAIL, "email", &str, &strSize); + FetchCombo(hwndDlg, IDC_GENDER, "s", &str, &strSize); + FetchField(hwndDlg, IDC_AGEFROM, "d", &str, &strSize); + FetchField(hwndDlg, IDC_AGETO, "u", &str, &strSize); + FetchField(hwndDlg, IDC_CITY, "c", &str, &strSize); + FetchCombo(hwndDlg, IDC_OCCUPATION, "j", &str, &strSize); + FetchField(hwndDlg, IDC_SCHOOL, "e", &str, &strSize); + FetchCombo(hwndDlg, IDC_STATUS, "m", &str, &strSize); + FetchCombo(hwndDlg, IDC_LOOKFOR, "r", &str, &strSize); + FetchCombo(hwndDlg, IDC_PLAN, "p", &str, &strSize); + return str; +} diff --git a/protocols/Tlen/src/tlen_avatar.cpp b/protocols/Tlen/src/tlen_avatar.cpp new file mode 100644 index 0000000000..8acf004681 --- /dev/null +++ b/protocols/Tlen/src/tlen_avatar.cpp @@ -0,0 +1,427 @@ +/* + +Tlen Protocol Plugin for Miranda NG +Copyright (C) 2004-2007 Piotr Piastucki + +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_list.h" +#include "tlen_avatar.h" +#include +#include +#include +#include +#include + +/* TlenGetAvatarFileName() - gets a file name for the avatar image */ + +void TlenGetAvatarFileName(TlenProtocol *proto, JABBER_LIST_ITEM *item, TCHAR* ptszDest, int cbLen) +{ + DWORD dwAttributes; + int tPathLen; + int format = PA_FORMAT_PNG; + TCHAR* tszFileType; + TCHAR* tmpPath = Utils_ReplaceVarsT( TEXT("%miranda_avatarcache%") ); + tPathLen = mir_sntprintf( ptszDest, cbLen, TEXT("%s\\Tlen"), tmpPath ); + mir_free(tmpPath); + dwAttributes = GetFileAttributes( ptszDest ); + if ( dwAttributes == 0xffffffff || ( dwAttributes & FILE_ATTRIBUTE_DIRECTORY ) == 0 ) { + CallService( MS_UTILS_CREATEDIRTREET, 0, ( LPARAM )ptszDest ); + } + ptszDest[ tPathLen++ ] = '\\'; + if (item != NULL) { + format = item->avatarFormat; + } else if (proto->threadData != NULL) { + format = proto->threadData->avatarFormat; + } else { + format = DBGetContactSettingDword(NULL, proto->m_szModuleName, "AvatarFormat", PA_FORMAT_UNKNOWN); + } + tszFileType = TEXT("png"); + switch(format) { + case PA_FORMAT_JPEG: tszFileType = TEXT("jpg"); break; + case PA_FORMAT_ICON: tszFileType = TEXT("ico"); break; + case PA_FORMAT_PNG: tszFileType = TEXT("png"); break; + case PA_FORMAT_GIF: tszFileType = TEXT("gif"); break; + case PA_FORMAT_BMP: tszFileType = TEXT("bmp"); break; + } + if ( item != NULL ) { + char* hash; + hash = JabberSha1(item->jid); + TCHAR* hashT = mir_a2t(hash); + mir_free( hash ); + mir_sntprintf( ptszDest + tPathLen, MAX_PATH - tPathLen, TEXT("%s.%s"), hashT, tszFileType ); + mir_free( hashT ); + } else { + TCHAR* m_tszModuleName = mir_a2t(proto->m_szModuleName); + mir_sntprintf( ptszDest + tPathLen, MAX_PATH - tPathLen, TEXT("%s_avatar.%s"), m_tszModuleName, tszFileType ); + mir_free( m_tszModuleName ); + } +} + +static void RemoveAvatar(TlenProtocol *proto, HANDLE hContact) { + TCHAR tFileName[ MAX_PATH ]; + if (hContact == NULL) { + proto->threadData->avatarHash[0] = '\0'; + } + TlenGetAvatarFileName( proto, NULL, tFileName, sizeof tFileName ); + DeleteFile(tFileName); + DBDeleteContactSetting(hContact, "ContactPhoto", "File"); + DBDeleteContactSetting(hContact, proto->m_szModuleName, "AvatarHash"); + DBDeleteContactSetting(hContact, proto->m_szModuleName, "AvatarFormat"); + ProtoBroadcastAck(proto->m_szModuleName, NULL, ACKTYPE_AVATAR, ACKRESULT_STATUS, NULL, 0); +} + +static void SetAvatar(TlenProtocol *proto, HANDLE hContact, JABBER_LIST_ITEM *item, char *data, int len, DWORD format) { + FILE* out; + TCHAR filename[MAX_PATH]; + char md5[33]; + mir_md5_state_t ctx; + DWORD digest[4]; + + if (format == PA_FORMAT_UNKNOWN && len > 4) { + format = JabberGetPictureType(data); + } + + mir_md5_init( &ctx ); + mir_md5_append( &ctx, ( BYTE* )data, len); + mir_md5_finish( &ctx, ( BYTE* )digest ); + + sprintf( md5, "%08x%08x%08x%08x", (int)htonl(digest[0]), (int)htonl(digest[1]), (int)htonl(digest[2]), (int)htonl(digest[3])); + if (item != NULL) { + char *hash = item->avatarHash; + item->avatarFormat = format; + item->avatarHash = mir_strdup(md5); + mir_free(hash); + } else { + proto->threadData->avatarFormat = format; + strcpy(proto->threadData->avatarHash, md5); + } + TlenGetAvatarFileName(proto, item, filename, sizeof filename ); + DeleteFile(filename); + out = _tfopen( filename, TEXT("wb") ); + if ( out != NULL ) { + fwrite( data, len, 1, out ); + fclose( out ); + DBWriteContactSettingTString(hContact, "ContactPhoto", "File", filename ); + DBWriteContactSettingString(hContact, proto->m_szModuleName, "AvatarHash", md5); + DBWriteContactSettingDword(hContact, proto->m_szModuleName, "AvatarFormat", format); + } + ProtoBroadcastAck( proto->m_szModuleName, hContact, ACKTYPE_AVATAR, ACKRESULT_STATUS, NULL , 0); +} + +int TlenProcessAvatarNode(TlenProtocol *proto, XmlNode *avatarNode, JABBER_LIST_ITEM *item) { + XmlNode *aNode; + char *oldHash = NULL; + char *md5 = NULL, *type = NULL; + HANDLE hContact; + hContact = NULL; + if (item != NULL) { + if ((hContact=JabberHContactFromJID(proto, item->jid)) == NULL) return 0; + } + if (item == NULL) { + oldHash = proto->threadData->avatarHash; + } else { + oldHash = item->avatarHash; + } + if (avatarNode != NULL) { + aNode = JabberXmlGetChild(avatarNode, "a"); + if (aNode != NULL) { + type = JabberXmlGetAttrValue(aNode, "type"); + md5 = JabberXmlGetAttrValue(aNode, "md5"); + } + } + if (md5 != NULL) { + /* check contact's avatar hash - md5 */ + if (oldHash == NULL || strcmp(oldHash, md5)) { + if (item != NULL) { + item->newAvatarDownloading = TRUE; + } + TlenGetAvatar(proto, hContact); + return 1; + } + } else { + /* remove avatar */ + if (oldHash != NULL) { + if (item != NULL) { + item->avatarHash = NULL; + mir_free(oldHash); + item->newAvatarDownloading = FALSE; + } + RemoveAvatar(proto, hContact); + return 1; + } + } + return 0; +} + +void TlenProcessPresenceAvatar(TlenProtocol *proto, XmlNode *node, JABBER_LIST_ITEM *item) { + HANDLE hContact; + if ((hContact=JabberHContactFromJID(proto, item->jid)) == NULL) return; + TlenProcessAvatarNode(proto, JabberXmlGetChild(node, "avatar"), item); +} + + +static char *replaceTokens(const char *base, const char *uri, const char *login, const char* token, int type, int access) { + char *result; + int i, l, size; + l = (int)strlen(uri); + size = (int)strlen(base); + for (i = 0; i < l; ) { + if (!strncmp(uri + i, "^login^", 7)) { + size += (int)strlen(login); + i += 7; + } else if (!strncmp(uri + i, "^type^", 6)) { + size++; + i += 6; + } else if (!strncmp(uri + i, "^token^", 7)) { + size += (int)strlen(token); + i += 7; + } else if (!strncmp(uri + i, "^access^", 8)) { + size++; + i += 8; + } else { + size++; + i++; + } + } + result = (char *)mir_alloc(size +1); + strcpy(result, base); + size = (int)strlen(base); + for (i = 0; i < l; ) { + if (!strncmp(uri + i, "^login^", 7)) { + strcpy(result + size, login); + size += (int)strlen(login); + i += 7; + } else if (!strncmp(uri + i, "^type^", 6)) { + result[size++] = '0' + type; + i += 6; + } else if (!strncmp(uri + i, "^token^", 7)) { + strcpy(result + size, token); + size += (int)strlen(token); + i += 7; + } else if (!strncmp(uri + i, "^access^", 8)) { + result[size++] = '0' + access; + i += 8; + } else { + result[size++] = uri[i++]; + } + } + result[size] = '\0'; + return result; +} + + +static int getAvatarMutex = 0; + +typedef struct { + TlenProtocol *proto; + HANDLE hContact; +} TLENGETAVATARTHREADDATA; + +static void TlenGetAvatarThread(void *ptr) { + + JABBER_LIST_ITEM *item = NULL; + NETLIBHTTPREQUEST req; + NETLIBHTTPREQUEST *resp; + TLENGETAVATARTHREADDATA *data = (TLENGETAVATARTHREADDATA *)ptr; + HANDLE hContact = data->hContact; + char *request; + char *login = NULL; + if (hContact != NULL) { + char *jid = JabberJIDFromHContact(data->proto, hContact); + login = JabberNickFromJID(jid); + item = JabberListGetItemPtr(data->proto, LIST_ROSTER, jid); + mir_free(jid); + } else { + login = mir_strdup(data->proto->threadData->username); + } + if ((data->proto->threadData != NULL && hContact == NULL) || item != NULL) { + DWORD format = PA_FORMAT_UNKNOWN; + if (item != NULL) { + item->newAvatarDownloading = TRUE; + } + request = replaceTokens(data->proto->threadData->tlenConfig.mailBase, data->proto->threadData->tlenConfig.avatarGet, login, data->proto->threadData->avatarToken, 0, 0); + ZeroMemory(&req, sizeof(req)); + req.cbSize = sizeof(req); + req.requestType = data->proto->threadData->tlenConfig.avatarGetMthd; + req.flags = 0; + req.headersCount = 0; + req.headers = NULL; + req.dataLength = 0; + req.szUrl = request; + resp = (NETLIBHTTPREQUEST *)CallService(MS_NETLIB_HTTPTRANSACTION, (WPARAM)data->proto->hNetlibUser, (LPARAM)&req); + if (item != NULL) { + item->newAvatarDownloading = FALSE; + } + if (resp != NULL) { + if (resp->resultCode/100 == 2) { + if (resp->dataLength > 0) { + int i; + for (i=0; iheadersCount; i++ ) { + if (strcmpi(resp->headers[i].szName, "Content-Type") == 0) { + if (strcmpi(resp->headers[i].szValue, "image/png") == 0) { + format = PA_FORMAT_PNG; + } else if (strcmpi(resp->headers[i].szValue, "image/x-png") == 0) { + format = PA_FORMAT_PNG; + } else if (strcmpi(resp->headers[i].szValue, "image/jpeg") == 0) { + format = PA_FORMAT_JPEG; + } else if (strcmpi(resp->headers[i].szValue, "image/jpg") == 0) { + format = PA_FORMAT_JPEG; + } else if (strcmpi(resp->headers[i].szValue, "image/gif") == 0) { + format = PA_FORMAT_GIF; + } else if (strcmpi(resp->headers[i].szValue, "image/bmp") == 0) { + format = PA_FORMAT_BMP; + } + break; + } + } + SetAvatar(data->proto, hContact, item, resp->pData, resp->dataLength, format); + } else { + RemoveAvatar(data->proto, hContact); + } + } + CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, 0, (LPARAM)resp); + } + mir_free(request); + mir_free(login); + } + if (hContact == NULL) { + getAvatarMutex = 0; + } + mir_free(data); +} + +void TlenGetAvatar(TlenProtocol *proto, HANDLE hContact) { + if (hContact == NULL) { + if (getAvatarMutex != 0) { + return; + } + getAvatarMutex = 1; + } + { + TLENGETAVATARTHREADDATA *data = (TLENGETAVATARTHREADDATA *)mir_alloc(sizeof(TLENGETAVATARTHREADDATA)); + data->proto = proto; + data->hContact = hContact; + JabberForkThread(TlenGetAvatarThread, 0, data); + } +} + +typedef struct { + TlenProtocol *proto; + NETLIBHTTPREQUEST *req; +}TLENREMOVEAVATARTHREADDATA; + +static void TlenRemoveAvatarRequestThread(void *ptr) { + NETLIBHTTPREQUEST *resp; + TLENREMOVEAVATARTHREADDATA *data = (TLENREMOVEAVATARTHREADDATA*)ptr; + NETLIBHTTPREQUEST *req = (NETLIBHTTPREQUEST *)data->req; + resp = (NETLIBHTTPREQUEST *)CallService(MS_NETLIB_HTTPTRANSACTION, (WPARAM)data->proto->hNetlibUser, (LPARAM)req); + mir_free(req->szUrl); + mir_free(req->headers); + mir_free(req->pData); + mir_free(req); + if (resp != NULL) { + CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, (WPARAM)0, (LPARAM)resp); + RemoveAvatar(data->proto, NULL); + } + mir_free(data); + +} + +typedef struct { + TlenProtocol *proto; + NETLIBHTTPREQUEST *req; + char *data; + int length; +}TLENUPLOADAVATARTHREADDATA; + +static void TlenUploadAvatarRequestThread(void *ptr) { + NETLIBHTTPREQUEST *resp; + TLENUPLOADAVATARTHREADDATA * data = (TLENUPLOADAVATARTHREADDATA *) ptr; + NETLIBHTTPREQUEST *req = data->req; + resp = (NETLIBHTTPREQUEST *)CallService(MS_NETLIB_HTTPTRANSACTION, (WPARAM)data->proto->hNetlibUser, (LPARAM)req); + if (resp != NULL) { + CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, (WPARAM)0, (LPARAM)resp); + SetAvatar(data->proto, NULL, NULL, data->data, data->length, PA_FORMAT_PNG); + } + mir_free(req->szUrl); + mir_free(req->headers); + mir_free(req->pData); + mir_free(req); + mir_free(data->data); + mir_free(data); +} + +void TlenRemoveAvatar(TlenProtocol *proto) { + NETLIBHTTPREQUEST *req; + char *request; + if (proto->threadData != NULL) { + TLENREMOVEAVATARTHREADDATA *data = (TLENREMOVEAVATARTHREADDATA *)mir_alloc(sizeof(TLENREMOVEAVATARTHREADDATA)); + req = (NETLIBHTTPREQUEST *)mir_alloc(sizeof(NETLIBHTTPREQUEST)); + data->proto =proto; + data->req = req; + request = replaceTokens(proto->threadData->tlenConfig.mailBase, proto->threadData->tlenConfig.avatarRemove, "", proto->threadData->avatarToken, 0, 0); + ZeroMemory(req, sizeof(NETLIBHTTPREQUEST)); + req->cbSize = sizeof(NETLIBHTTPREQUEST); + req->requestType = proto->threadData->tlenConfig.avatarGetMthd; + req->szUrl = request; + JabberForkThread(TlenRemoveAvatarRequestThread, 0, data); + } +} + + +void TlenUploadAvatar(TlenProtocol *proto, unsigned char *data, int dataLen, int access) { + NETLIBHTTPREQUEST *req; + NETLIBHTTPHEADER *headers; + TLENUPLOADAVATARTHREADDATA *threadData; + char *request; + unsigned char *buffer; + if (proto->threadData != NULL && dataLen > 0 && data != NULL) { + char *mpartHead = "--AaB03x\r\nContent-Disposition: form-data; name=\"filename\"; filename=\"plik.png\"\r\nContent-Type: image/png\r\n\r\n"; + char *mpartTail = "\r\n--AaB03x--\r\n"; + int size, sizeHead = (int)strlen(mpartHead), sizeTail = (int)strlen(mpartTail); + request = replaceTokens(proto->threadData->tlenConfig.mailBase, proto->threadData->tlenConfig.avatarUpload, "", proto->threadData->avatarToken, 0, access); + threadData = (TLENUPLOADAVATARTHREADDATA *)mir_alloc(sizeof(TLENUPLOADAVATARTHREADDATA)); + threadData->proto = proto; + req = (NETLIBHTTPREQUEST *)mir_alloc(sizeof(NETLIBHTTPREQUEST)); + headers = (NETLIBHTTPHEADER *)mir_alloc(sizeof(NETLIBHTTPHEADER)); + ZeroMemory(req, sizeof(NETLIBHTTPREQUEST)); + req->cbSize = sizeof(NETLIBHTTPREQUEST); + req->requestType = proto->threadData->tlenConfig.avatarUploadMthd; + req->szUrl = request; + req->flags = 0; + headers[0].szName = "Content-Type"; + headers[0].szValue = "multipart/form-data; boundary=AaB03x"; + req->headersCount = 1; + req->headers = headers; + size = dataLen + sizeHead + sizeTail; + buffer = (unsigned char *)mir_alloc(size); + memcpy(buffer, mpartHead, sizeHead); + memcpy(buffer + sizeHead, data, dataLen); + memcpy(buffer + sizeHead + dataLen, mpartTail, sizeTail); + req->dataLength = size; + req->pData = (char*)buffer; + threadData->req = req; + threadData->data = (char *) mir_alloc(dataLen); + memcpy(threadData->data, data, dataLen); + threadData->length = dataLen; + JabberForkThread(TlenUploadAvatarRequestThread, 0, threadData); + } +} + diff --git a/protocols/Tlen/src/tlen_avatar.h b/protocols/Tlen/src/tlen_avatar.h new file mode 100644 index 0000000000..0a0694fe11 --- /dev/null +++ b/protocols/Tlen/src/tlen_avatar.h @@ -0,0 +1,34 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Tlen Protocol Plugin for Miranda NG +Copyright (C) 2002-2004 Santithorn Bunchua +Copyright (C) 2004-2007 Piotr Piastucki + +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. + +*/ + +#ifndef _TLEN_AVATAR_H_ +#define _TLEN_AVATAR_H_ + +void TlenProcessPresenceAvatar(TlenProtocol *proto, XmlNode *node, JABBER_LIST_ITEM *item); +int TlenProcessAvatarNode(TlenProtocol *proto, XmlNode *avatarNode, JABBER_LIST_ITEM *item); +void TlenGetAvatarFileName(TlenProtocol *proto, JABBER_LIST_ITEM *item, TCHAR* psztDest, int cbLen); +void TlenGetAvatar(TlenProtocol *proto, HANDLE hContact); +void TlenUploadAvatar(TlenProtocol *proto, unsigned char *data, int dataLen, int access); +void TlenRemoveAvatar(TlenProtocol *proto); + +#endif // _TLEN_AVATAR_H_ diff --git a/protocols/Tlen/src/tlen_file.cpp b/protocols/Tlen/src/tlen_file.cpp new file mode 100644 index 0000000000..4a02259245 --- /dev/null +++ b/protocols/Tlen/src/tlen_file.cpp @@ -0,0 +1,708 @@ +/* + +Tlen Protocol Plugin for Miranda NG +Copyright (C) 2004-2007 Piotr Piastucki + +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 +#include +#include +#include +#include "jabber_list.h" +#include "tlen_p2p_old.h" + +static void TlenFileReceiveParse(TLEN_FILE_TRANSFER *ft) +{ + int i; + char *p; + TLEN_FILE_PACKET *rpacket, *packet; + + rpacket = NULL; + if (ft->state == FT_CONNECTING) { + rpacket = TlenP2PPacketReceive(ft->s); + if (rpacket != NULL) { + p = rpacket->packet; + if (rpacket->type == TLEN_FILE_PACKET_FILE_LIST) { // list of files (length & name) + ft->fileCount = (int)(*((DWORD*)p)); + ft->files = (char **) mir_alloc(sizeof(char *) * ft->fileCount); + ft->filesSize = (long *) mir_alloc(sizeof(long) * ft->fileCount); + ft->currentFile = 0; + ft->allFileTotalSize = 0; + ft->allFileReceivedBytes = 0; + p += sizeof(DWORD); + for (i=0;ifileCount;i++) { + ft->filesSize[i] = (long)(*((DWORD*)p)); + ft->allFileTotalSize += ft->filesSize[i]; + p += sizeof(DWORD); + ft->files[i] = (char *)mir_alloc(256); + memcpy(ft->files[i], p, 256); + p += 256; + } + if ((packet=TlenP2PPacketCreate(3*sizeof(DWORD))) == NULL) { + ft->state = FT_ERROR; + } + else { + TlenP2PPacketSetType(packet, TLEN_FILE_PACKET_FILE_LIST_ACK); + TlenP2PPacketSend(ft->s, packet); + TlenP2PPacketFree(packet); + ft->state = FT_INITIALIZING; + JabberLog(ft->proto, "Change to FT_INITIALIZING"); + } + } + TlenP2PPacketFree(rpacket); + } + else { + ft->state = FT_ERROR; + } + } + else if (ft->state == FT_INITIALIZING) { + char *fullFileName; + if ((packet=TlenP2PPacketCreate(3*sizeof(DWORD))) != NULL) { + TlenP2PPacketSetType(packet, TLEN_FILE_PACKET_FILE_REQUEST); // file request + TlenP2PPacketPackDword(packet, ft->currentFile); + TlenP2PPacketPackDword(packet, 0); + TlenP2PPacketPackDword(packet, 0); + TlenP2PPacketSend(ft->s, packet); + TlenP2PPacketFree(packet); + + fullFileName = (char *) mir_alloc(strlen(ft->szSavePath) + strlen(ft->files[ft->currentFile]) + 2); + strcpy(fullFileName, ft->szSavePath); + if (fullFileName[strlen(fullFileName)-1] != '\\') + strcat(fullFileName, "\\"); + strcat(fullFileName, ft->files[ft->currentFile]); + ft->fileId = _open(fullFileName, _O_BINARY|_O_WRONLY|_O_CREAT|_O_TRUNC, _S_IREAD|_S_IWRITE); + ft->fileReceivedBytes = 0; + ft->fileTotalSize = ft->filesSize[ft->currentFile]; + JabberLog(ft->proto, "Saving to [%s] [%d]", fullFileName, ft->filesSize[ft->currentFile]); + mir_free(fullFileName); + ft->state = FT_RECEIVING; + JabberLog(ft->proto, "Change to FT_RECEIVING"); + } + else { + ft->state = FT_ERROR; + } + } + else if (ft->state == FT_RECEIVING) { + PROTOFILETRANSFERSTATUS pfts; + memset(&pfts, 0, sizeof(PROTOFILETRANSFERSTATUS)); + pfts.cbSize = sizeof(PROTOFILETRANSFERSTATUS); + pfts.hContact = ft->hContact; + pfts.pszFiles = ft->files; + pfts.totalFiles = ft->fileCount; + pfts.currentFileNumber = ft->currentFile; + pfts.totalBytes = ft->allFileTotalSize; + pfts.szWorkingDir = NULL; + pfts.szCurrentFile = ft->files[ft->currentFile]; + pfts.currentFileSize = ft->filesSize[ft->currentFile]; + pfts.currentFileTime = 0; + JabberLog(ft->proto, "Receiving data..."); + while (ft->state == FT_RECEIVING) { + rpacket = TlenP2PPacketReceive(ft->s); + if (rpacket != NULL) { + p = rpacket->packet; + if (rpacket->type == TLEN_FILE_PACKET_FILE_DATA) { // file data + int writeSize; + writeSize = rpacket->len - 2 * sizeof(DWORD) ; // skip file offset + if (_write(ft->fileId, p + 2 * sizeof(DWORD), writeSize) != writeSize) { + ft->state = FT_ERROR; + } + else { + ft->fileReceivedBytes += writeSize; + ft->allFileReceivedBytes += writeSize; + pfts.totalProgress = ft->allFileReceivedBytes; + pfts.currentFileProgress = ft->fileReceivedBytes; + ProtoBroadcastAck(ft->proto->m_szModuleName, ft->hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, (LPARAM) &pfts); + } + } + else if (rpacket->type == TLEN_FILE_PACKET_END_OF_FILE) { // end of file + _close(ft->fileId); + JabberLog(ft->proto, "Finishing this file..."); + if (ft->currentFile >= ft->fileCount-1) { + ft->state = FT_DONE; + } + else { + ft->currentFile++; + ft->state = FT_INITIALIZING; + JabberLog(ft->proto, "File received, advancing to the next file..."); + ProtoBroadcastAck(ft->proto->m_szModuleName, ft->hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, ft, 0); + } + } + TlenP2PPacketFree(rpacket); + } + else { + ft->state = FT_ERROR; + } + } + } +} + +static void TlenFileReceivingConnection(JABBER_SOCKET hConnection, DWORD dwRemoteIP, void * pExtra) +{ + JABBER_SOCKET slisten; + TLEN_FILE_TRANSFER *ft; + + TlenProtocol *proto = (TlenProtocol *)pExtra; + ft = TlenP2PEstablishIncomingConnection(proto, hConnection, LIST_FILE, TRUE); + if (ft != NULL) { + slisten = ft->s; + ft->s = hConnection; + JabberLog(ft->proto, "Set ft->s to %d (saving %d)", hConnection, slisten); + JabberLog(ft->proto, "Entering send loop for this file connection... (ft->s is hConnection)"); + while (ft->state != FT_DONE && ft->state != FT_ERROR) { + TlenFileReceiveParse(ft); + } + if (ft->state == FT_DONE) + ProtoBroadcastAck(ft->proto->m_szModuleName, ft->hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, ft, 0); + else + ProtoBroadcastAck(ft->proto->m_szModuleName, ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0); + JabberLog(ft->proto, "Closing connection for this file transfer... (ft->s is now hBind)"); + ft->s = slisten; + JabberLog(ft->proto, "ft->s is restored to %d", ft->s); + if (ft->s != hConnection) { + Netlib_CloseHandle(hConnection); + } + if (ft->hFileEvent != NULL) + SetEvent(ft->hFileEvent); + } else { + Netlib_CloseHandle(hConnection); + } +} + + +static void __cdecl TlenFileReceiveThread(TLEN_FILE_TRANSFER *ft) +{ + NETLIBOPENCONNECTION nloc; + JABBER_SOCKET s; + JabberLog(ft->proto, "Thread started: type=file_receive server='%s' port='%d'", ft->hostName, ft->wPort); + ft->mode = FT_RECV; + nloc.cbSize = NETLIBOPENCONNECTION_V1_SIZE;//sizeof(NETLIBOPENCONNECTION); + nloc.szHost = ft->hostName; + nloc.wPort = ft->wPort; + nloc.flags = 0; + ProtoBroadcastAck(ft->proto->m_szModuleName, ft->hContact, ACKTYPE_FILE, ACKRESULT_CONNECTING, ft, 0); + s = (HANDLE) CallService(MS_NETLIB_OPENCONNECTION, (WPARAM) ft->proto->hNetlibUser, (LPARAM) &nloc); + if (s != NULL) { + ft->s = s; + JabberLog(ft->proto, "Entering file receive loop"); + TlenP2PEstablishOutgoingConnection(ft, TRUE); + while (ft->state != FT_DONE && ft->state != FT_ERROR) { + TlenFileReceiveParse(ft); + } + if (ft->s) { + Netlib_CloseHandle(s); + } + ft->s = NULL; + } else { + ft->pfnNewConnectionV2 = TlenFileReceivingConnection; + JabberLog(ft->proto, "Connection failed - receiving as server"); + s = TlenP2PListen(ft); + if (s != NULL) { + HANDLE hEvent; + char *nick; + ft->s = s; + hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + ft->hFileEvent = hEvent; + ft->currentFile = 0; + ft->state = FT_CONNECTING; + nick = JabberNickFromJID(ft->jid); + JabberSend(ft->proto, "", nick, ft->iqId, ft->localName, ft->wLocalPort); + mir_free(nick); + JabberLog(ft->proto, "Waiting for the file to be received..."); + WaitForSingleObject(hEvent, INFINITE); + ft->hFileEvent = NULL; + CloseHandle(hEvent); + JabberLog(ft->proto, "Finish all files"); + Netlib_CloseHandle(s); + } else { + ft->state = FT_ERROR; + } + } + JabberListRemove(ft->proto, LIST_FILE, ft->iqId); + if (ft->state == FT_DONE) + ProtoBroadcastAck(ft->proto->m_szModuleName, ft->hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, ft, 0); + else { + char *nick; + nick = JabberNickFromJID(ft->jid); + JabberSend(ft->proto, "", nick, ft->iqId); + mir_free(nick); + ProtoBroadcastAck(ft->proto->m_szModuleName, ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0); + } + + JabberLog(ft->proto, "Thread ended: type=file_receive server='%s'", ft->hostName); + TlenP2PFreeFileTransfer(ft); +} + + + +static void TlenFileSendParse(TLEN_FILE_TRANSFER *ft) +{ + int i; + char *p, *t; + int currentFile, numRead; + char *fileBuffer; + TLEN_FILE_PACKET *rpacket, *packet; + + + if (ft->state == FT_CONNECTING) { + char filename[256]; // Must be 256 (0x100) + if ((packet=TlenP2PPacketCreate(sizeof(DWORD)+(ft->fileCount*(sizeof(filename)+sizeof(DWORD))))) != NULL) { + // Must pause a bit, sending these two packets back to back + // will break the session because the receiver cannot take it :) + SleepEx(1000, TRUE); + TlenP2PPacketSetLen(packet, 0); // Reuse packet + TlenP2PPacketSetType(packet, TLEN_FILE_PACKET_FILE_LIST); + TlenP2PPacketPackDword(packet, (DWORD) ft->fileCount); + for (i=0; ifileCount; i++) { +// struct _stat statbuf; +// _stat(ft->files[i], &statbuf); +// TlenP2PPacketPackDword(packet, statbuf.st_size); + TlenP2PPacketPackDword(packet, ft->filesSize[i]); + memset(filename, 0, sizeof(filename)); + if ((t=strrchr(ft->files[i], '\\')) != NULL) + t++; + else + t = ft->files[i]; + _snprintf(filename, sizeof(filename)-1, t); + TlenP2PPacketPackBuffer(packet, filename, sizeof(filename)); + } + TlenP2PPacketSend(ft->s, packet); + TlenP2PPacketFree(packet); + + ft->allFileReceivedBytes = 0; + ft->state = FT_INITIALIZING; + JabberLog(ft->proto, "Change to FT_INITIALIZING"); + } + else { + ft->state = FT_ERROR; + } + } + else if (ft->state == FT_INITIALIZING) { // FT_INITIALIZING + rpacket = TlenP2PPacketReceive(ft->s); + JabberLog(ft->proto, "FT_INITIALIZING: recv %d", rpacket); + if (rpacket == NULL) { + ft->state = FT_ERROR; + return; + } + JabberLog(ft->proto, "FT_INITIALIZING: recv type %d", rpacket->type); + p = rpacket->packet; + // TYPE: TLEN_FILE_PACKET_FILE_LIST_ACK will be ignored + // LEN: 0 + if (rpacket->type == TLEN_FILE_PACKET_FILE_LIST_ACK) { + + } + // Then the receiver will request each file + // TYPE: TLEN_FILE_PACKET_REQUEST + // LEN: + // (DWORD) file number + // (DWORD) 0 + // (DWORD) 0 + else if (rpacket->type == TLEN_FILE_PACKET_FILE_REQUEST) { + PROTOFILETRANSFERSTATUS pfts; + //struct _stat statbuf; + + currentFile = *((DWORD*)p); + if (currentFile != ft->currentFile) { + JabberLog(ft->proto, "Requested file (#%d) is invalid (must be %d)", currentFile, ft->currentFile); + ft->state = FT_ERROR; + } + else { + // _stat(ft->files[currentFile], &statbuf); // file size in statbuf.st_size + JabberLog(ft->proto, "Sending [%s] [%d]", ft->files[currentFile], ft->filesSize[currentFile]); + if ((ft->fileId=_open(ft->files[currentFile], _O_BINARY|_O_RDONLY)) < 0) { + JabberLog(ft->proto, "File cannot be opened"); + ft->state = FT_ERROR; + } + else { + memset(&pfts, 0, sizeof(PROTOFILETRANSFERSTATUS)); + pfts.cbSize = sizeof(PROTOFILETRANSFERSTATUS); + pfts.hContact = ft->hContact; + pfts.flags = PFTS_SENDING; + pfts.pszFiles = ft->files; + pfts.totalFiles = ft->fileCount; + pfts.currentFileNumber = ft->currentFile; + pfts.totalBytes = ft->allFileTotalSize; + pfts.szWorkingDir = NULL; + pfts.szCurrentFile = ft->files[ft->currentFile]; + pfts.currentFileSize = ft->filesSize[ft->currentFile]; //statbuf.st_size; + pfts.currentFileTime = 0; + ft->fileReceivedBytes = 0; + if ((packet = TlenP2PPacketCreate(2*sizeof(DWORD)+2048)) == NULL) { + ft->state = FT_ERROR; + } + else { + TlenP2PPacketSetType(packet, TLEN_FILE_PACKET_FILE_DATA); + fileBuffer = (char *) mir_alloc(2048); + JabberLog(ft->proto, "Sending file data..."); + while ((numRead=_read(ft->fileId, fileBuffer, 2048)) > 0) { + TlenP2PPacketSetLen(packet, 0); // Reuse packet + TlenP2PPacketPackDword(packet, (DWORD) ft->fileReceivedBytes); + TlenP2PPacketPackDword(packet, 0); + TlenP2PPacketPackBuffer(packet, fileBuffer, numRead); + if (TlenP2PPacketSend(ft->s, packet)) { + ft->fileReceivedBytes += numRead; + ft->allFileReceivedBytes += numRead; + pfts.totalProgress = ft->allFileReceivedBytes; + pfts.currentFileProgress = ft->fileReceivedBytes; + ProtoBroadcastAck(ft->proto->m_szModuleName, ft->hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, (LPARAM) &pfts); + } + else { + ft->state = FT_ERROR; + break; + } + } + mir_free(fileBuffer); + _close(ft->fileId); + if (ft->state != FT_ERROR) { + if (ft->currentFile >= ft->fileCount-1) + ft->state = FT_DONE; + else { + ft->currentFile++; + ft->state = FT_INITIALIZING; + JabberLog(ft->proto, "File sent, advancing to the next file..."); + ProtoBroadcastAck(ft->proto->m_szModuleName, ft->hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, ft, 0); + } + } + JabberLog(ft->proto, "Finishing this file..."); + TlenP2PPacketSetLen(packet, 0); // Reuse packet + TlenP2PPacketSetType(packet, TLEN_FILE_PACKET_END_OF_FILE); + TlenP2PPacketPackDword(packet, currentFile); + TlenP2PPacketSend(ft->s, packet); + TlenP2PPacketFree(packet); + } + } + } + TlenP2PPacketFree(rpacket); + } + else { + ft->state = FT_ERROR; + } + } +} + +static void TlenFileSendingConnection(JABBER_SOCKET hConnection, DWORD dwRemoteIP, void * pExtra) +{ + JABBER_SOCKET slisten; + TLEN_FILE_TRANSFER *ft; + TlenProtocol *proto = (TlenProtocol *)pExtra; + + ft = TlenP2PEstablishIncomingConnection(proto, hConnection, LIST_FILE, TRUE); + if (ft != NULL) { + slisten = ft->s; + ft->s = hConnection; + JabberLog(ft->proto, "Set ft->s to %d (saving %d)", hConnection, slisten); + + JabberLog(ft->proto, "Entering send loop for this file connection... (ft->s is hConnection)"); + while (ft->state != FT_DONE && ft->state != FT_ERROR) { + TlenFileSendParse(ft); + } + if (ft->state == FT_DONE) + ProtoBroadcastAck(ft->proto->m_szModuleName, ft->hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, ft, 0); + else + ProtoBroadcastAck(ft->proto->m_szModuleName, ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0); + JabberLog(ft->proto, "Closing connection for this file transfer... (ft->s is now hBind)"); + ft->s = slisten; + JabberLog(ft->proto, "ft->s is restored to %d", ft->s); + if (ft->s != hConnection) { + Netlib_CloseHandle(hConnection); + } + if (ft->hFileEvent != NULL) + SetEvent(ft->hFileEvent); + } else { + Netlib_CloseHandle(hConnection); + } +} + +int TlenFileCancelAll(TlenProtocol *proto) +{ + JABBER_LIST_ITEM *item; + HANDLE hEvent; + int i = 0; + + while ((i=JabberListFindNext(proto, LIST_FILE, 0)) >=0 ) { + if ((item=JabberListGetItemPtrFromIndex(proto, i)) != NULL) { + TLEN_FILE_TRANSFER *ft = item->ft; + JabberListRemoveByIndex(proto, i); + if (ft != NULL) { + if (ft->s) { + //ProtoBroadcastAck(m_szModuleName, ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0); + JabberLog(ft->proto, "Closing ft->s = %d", ft->s); + ft->state = FT_ERROR; + Netlib_CloseHandle(ft->s); + ft->s = NULL; + if (ft->hFileEvent != NULL) { + hEvent = ft->hFileEvent; + ft->hFileEvent = NULL; + SetEvent(hEvent); + } + } else { + JabberLog(ft->proto, "freeing ft struct"); + TlenP2PFreeFileTransfer(ft); + } + } + } + } + return 0; +} + +static void __cdecl TlenFileSendingThread(TLEN_FILE_TRANSFER *ft) +{ + JABBER_SOCKET s = NULL; + HANDLE hEvent; + char *nick; + + JabberLog(ft->proto, "Thread started: type=tlen_file_send"); + ft->mode = FT_SEND; + ft->pfnNewConnectionV2 = TlenFileSendingConnection; + s = TlenP2PListen(ft); + if (s != NULL) { + ProtoBroadcastAck(ft->proto->m_szModuleName, ft->hContact, ACKTYPE_FILE, ACKRESULT_CONNECTING, ft, 0); + ft->s = s; + //JabberLog("ft->s = %d", s); + //JabberLog("fileCount = %d", ft->fileCount); + + hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + ft->hFileEvent = hEvent; + ft->currentFile = 0; + ft->state = FT_CONNECTING; + + nick = JabberNickFromJID(ft->jid); + JabberSend(ft->proto, "", nick, ft->iqId, ft->localName, ft->wLocalPort); + mir_free(nick); + JabberLog(ft->proto, "Waiting for the file to be sent..."); + WaitForSingleObject(hEvent, INFINITE); + ft->hFileEvent = NULL; + CloseHandle(hEvent); + JabberLog(ft->proto, "Finish all files"); + Netlib_CloseHandle(s); + ft->s = NULL; + JabberLog(ft->proto, "ft->s is NULL"); + + if (ft->state == FT_SWITCH) { + NETLIBOPENCONNECTION nloc; + JABBER_SOCKET s; + JabberLog(ft->proto, "Sending as client..."); + ft->state = FT_CONNECTING; + nloc.cbSize = NETLIBOPENCONNECTION_V1_SIZE;//sizeof(NETLIBOPENCONNECTION); + nloc.szHost = ft->hostName; + nloc.wPort = ft->wPort; + nloc.flags = 0; + s = (HANDLE) CallService(MS_NETLIB_OPENCONNECTION, (WPARAM) ft->proto->hNetlibUser, (LPARAM) &nloc); + if (s != NULL) { + ProtoBroadcastAck(ft->proto->m_szModuleName, ft->hContact, ACKTYPE_FILE, ACKRESULT_CONNECTING, ft, 0); + ft->s = s; + TlenP2PEstablishOutgoingConnection(ft, TRUE); + JabberLog(ft->proto, "Entering send loop for this file connection..."); + while (ft->state != FT_DONE && ft->state != FT_ERROR) { + TlenFileSendParse(ft); + } + if (ft->state == FT_DONE) + ProtoBroadcastAck(ft->proto->m_szModuleName, ft->hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, ft, 0); + else + ProtoBroadcastAck(ft->proto->m_szModuleName, ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0); + JabberLog(ft->proto, "Closing connection for this file transfer... "); + Netlib_CloseHandle(s); + } else { + ft->state = FT_ERROR; + } + } + } else { + JabberLog(ft->proto, "Cannot allocate port to bind for file server thread, thread ended."); + ft->state = FT_ERROR; + } + JabberListRemove(ft->proto, LIST_FILE, ft->iqId); + switch (ft->state) { + case FT_DONE: + JabberLog(ft->proto, "Finish successfully"); + ProtoBroadcastAck(ft->proto->m_szModuleName, ft->hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, ft, 0); + break; + case FT_DENIED: + ProtoBroadcastAck(ft->proto->m_szModuleName, ft->hContact, ACKTYPE_FILE, ACKRESULT_DENIED, ft, 0); + break; + default: // FT_ERROR: + nick = JabberNickFromJID(ft->jid); + JabberSend(ft->proto, "", nick, ft->iqId); + mir_free(nick); + JabberLog(ft->proto, "Finish with errors"); + ProtoBroadcastAck(ft->proto->m_szModuleName, ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0); + break; + } + JabberLog(ft->proto, "Thread ended: type=file_send"); + TlenP2PFreeFileTransfer(ft); +} + + +TLEN_FILE_TRANSFER *TlenFileCreateFT(TlenProtocol *proto, const char *jid) { + TLEN_FILE_TRANSFER *ft; + ft = (TLEN_FILE_TRANSFER *) mir_alloc(sizeof(TLEN_FILE_TRANSFER)); + memset(ft, 0, sizeof(TLEN_FILE_TRANSFER)); + ft->proto = proto; + ft->jid = mir_strdup(jid); + return ft; +} + + +/* + * File transfer + */ +void TlenProcessF(XmlNode *node, ThreadData *info) +{ + TLEN_FILE_TRANSFER *ft; + char *from, *p, *e; + char jid[128], szFilename[MAX_PATH]; + int numFiles; + JABBER_LIST_ITEM *item; + +// if (!node->name || strcmp(node->name, "f")) return; + if (info == NULL) return; + + if ((from=JabberXmlGetAttrValue(node, "f")) != NULL) { + + if (strchr(from, '@') == NULL) { + _snprintf(jid, sizeof(jid), "%s@%s", from, info->server); + } else { + _snprintf(jid, sizeof(jid), "%s", from); + } + if ((e=JabberXmlGetAttrValue(node, "e")) != NULL) { + + if (!strcmp(e, "1")) { + // FILE_RECV : e='1' : File transfer request + ft = TlenFileCreateFT(info->proto, jid); + ft->hContact = JabberHContactFromJID(info->proto, jid); + + if ((p=JabberXmlGetAttrValue(node, "i")) != NULL) + ft->iqId = mir_strdup(p); + + szFilename[0] = '\0'; + if ((p=JabberXmlGetAttrValue(node, "c")) != NULL) { + numFiles = atoi(p); + if (numFiles == 1) { + if ((p=JabberXmlGetAttrValue(node, "n")) != NULL) { + p = JabberTextDecode(p); + strncpy(szFilename, p, sizeof(szFilename)); + mir_free(p); + } else { + strcpy(szFilename, Translate("1 File")); + } + } + else if (numFiles > 1) { + _snprintf(szFilename, sizeof(szFilename), Translate("%d Files"), numFiles); + } + } + + if (szFilename[0] != '\0' && ft->iqId != NULL) { + TCHAR* filenameT = mir_utf8decodeT((char*)szFilename); + PROTORECVFILET pre = {0}; + pre.flags = PREF_TCHAR; + pre.fileCount = 1; + pre.timestamp = time(NULL); + pre.tszDescription = filenameT; + pre.ptszFiles = &filenameT; + pre.lParam = (LPARAM)ft; + JabberLog(ft->proto, "sending chainrecv"); + CCSDATA ccs = { ft->hContact, PSR_FILE, 0, (LPARAM)&pre }; + CallService(MS_PROTO_CHAINRECV, 0, (LPARAM) &ccs); + mir_free(filenameT); + } else { + // malformed request, reject + if (ft->iqId) + JabberSend(ft->proto, "", ft->iqId, from); + else + JabberSend(ft->proto, "", from); + TlenP2PFreeFileTransfer(ft); + } + } + else if (!strcmp(e, "3")) { + // FILE_RECV : e='3' : invalid transfer error + if ((p=JabberXmlGetAttrValue(node, "i")) != NULL) { + if ((item=JabberListGetItemPtr(info->proto, LIST_FILE, p)) != NULL) { + if (item->ft != NULL) { + ProtoBroadcastAck(info->proto->m_szModuleName, item->ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, item->ft, 0); + info->proto->FileCancel(NULL, item->ft); + } + JabberListRemove(info->proto, LIST_FILE, p); + } + } + } + else if (!strcmp(e, "4")) { + // FILE_SEND : e='4' : File sending request was denied by the remote client + if ((p=JabberXmlGetAttrValue(node, "i")) != NULL) { + if ((item=JabberListGetItemPtr(info->proto, LIST_FILE, p)) != NULL) { + if (!strcmp(item->ft->jid, jid)) { + ProtoBroadcastAck(info->proto->m_szModuleName, item->ft->hContact, ACKTYPE_FILE, ACKRESULT_DENIED, item->ft, 0); + JabberListRemove(info->proto, LIST_FILE, p); + } + } + } + } + else if (!strcmp(e, "5")) { + // FILE_SEND : e='5' : File sending request was accepted + if ((p=JabberXmlGetAttrValue(node, "i")) != NULL) { + if ((item=JabberListGetItemPtr(info->proto, LIST_FILE, p)) != NULL) { + if (!strcmp(item->ft->jid, jid)) + JabberForkThread((void (__cdecl *)(void*))TlenFileSendingThread, 0, item->ft); + } + } + } + else if (!strcmp(e, "6")) { + // FILE_RECV : e='6' : IP and port information to connect to get file + if ((p=JabberXmlGetAttrValue(node, "i")) != NULL) { + if ((item=JabberListGetItemPtr(info->proto, LIST_FILE, p)) != NULL) { + if ((p=JabberXmlGetAttrValue(node, "a")) != NULL) { + item->ft->hostName = mir_strdup(p); + if ((p=JabberXmlGetAttrValue(node, "p")) != NULL) { + item->ft->wPort = atoi(p); + JabberForkThread((void (__cdecl *)(void*))TlenFileReceiveThread, 0, item->ft); + } + } + } + } + } + else if (!strcmp(e, "7")) { + // FILE_RECV : e='7' : IP and port information to connect to send file + // in case the conection to the given server was not successful + if ((p=JabberXmlGetAttrValue(node, "i")) != NULL) { + if ((item=JabberListGetItemPtr(info->proto, LIST_FILE, p)) != NULL) { + if ((p=JabberXmlGetAttrValue(node, "a")) != NULL) { + if (item->ft->hostName != NULL) mir_free(item->ft->hostName); + item->ft->hostName = mir_strdup(p); + if ((p=JabberXmlGetAttrValue(node, "p")) != NULL) { + item->ft->wPort = atoi(p); + item->ft->state = FT_SWITCH; + SetEvent(item->ft->hFileEvent); + } + } + } + } + } + else if (!strcmp(e, "8")) { + // FILE_RECV : e='8' : transfer error + if ((p=JabberXmlGetAttrValue(node, "i")) != NULL) { + if ((item=JabberListGetItemPtr(info->proto, LIST_FILE, p)) != NULL) { + item->ft->state = FT_ERROR; + if (item->ft->hFileEvent != NULL) { + SetEvent(item->ft->hFileEvent); + } else { + ProtoBroadcastAck(info->proto->m_szModuleName, item->ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, item->ft, 0); + } + } + } + } + } + } +} diff --git a/protocols/Tlen/src/tlen_file.h b/protocols/Tlen/src/tlen_file.h new file mode 100644 index 0000000000..1cd0704ea5 --- /dev/null +++ b/protocols/Tlen/src/tlen_file.h @@ -0,0 +1,34 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Tlen Protocol Plugin for Miranda NG +Copyright (C) 2002-2004 Santithorn Bunchua +Copyright (C) 2004-2007 Piotr Piastucki + +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. + +*/ + +#ifndef _TLEN_FILE_H_ +#define _TLEN_FILE_H_ + +#include +#include "jabber.h" + +extern int TlenFileCancelAll(TlenProtocol *proto); +extern void TlenProcessF(XmlNode *node, ThreadData *userdata); +extern TLEN_FILE_TRANSFER *TlenFileCreateFT(TlenProtocol *proto, const char *jid); +#endif + diff --git a/protocols/Tlen/src/tlen_muc.cpp b/protocols/Tlen/src/tlen_muc.cpp new file mode 100644 index 0000000000..5f3809d806 --- /dev/null +++ b/protocols/Tlen/src/tlen_muc.cpp @@ -0,0 +1,1069 @@ +/* + +Tlen Protocol Plugin for Miranda NG +Copyright (C) 2004-2007 Piotr Piastucki + +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_list.h" +#include "jabber_iq.h" +#include "resource.h" +#include "tlen_muc.h" + +static int TlenMUCHandleEvent(void *ptr, WPARAM wParam, LPARAM lParam); +static int TlenMUCQueryContacts(TlenProtocol *proto, const char *roomId); +static int TlenMUCSendInvitation(TlenProtocol *proto, const char *roomID, const char *user); +static int TlenMUCSendPresence(TlenProtocol *proto, const char *roomID, const char *nick, int desiredStatus); +static int TlenMUCSendMessage(TlenProtocol *proto, MUCCEVENT *event); +static int TlenMUCSendTopic(TlenProtocol *proto, MUCCEVENT *event); +static int TlenMUCSendQuery(TlenProtocol *proto, int type, const char *parent, int page); + +static int isSelf(TlenProtocol *proto, const char *roomID, const char *nick) +{ + JABBER_LIST_ITEM *item; + int result; + result=0; + item = JabberListGetItemPtr(proto, LIST_CHATROOM, roomID); + if (item != NULL) { + if (item->nick == NULL) { + if (!strcmp(nick, proto->threadData->username)) result = 1; + } else if (nick[0] == '~') { + if (!strcmp(nick+1, item->nick)) { + result = 1; + } + } + } + return result; +} + +static int stringToHex(const char *str) +{ + int i, val; + val = 0; + for (i=0;i<2;i++) { + val <<= 4; + if (str[i] >= 'A' && str[i] <= 'F') { + val += 10 + str[i]-'A'; + } else if (str[i] >= '0' && str[i] <= '9') { + val += str[i]-'0'; + } + } + return val; + +} +static char *getDisplayName(TlenProtocol *proto, const char *id) +{ + CONTACTINFO ci; + char jid[256]; + HANDLE hContact; + DBVARIANT dbv; + if (!DBGetContactSetting(NULL, proto->m_szModuleName, "LoginServer", &dbv)) { + _snprintf(jid, sizeof(jid), "%s@%s", id, dbv.pszVal); + DBFreeVariant(&dbv); + if (((hContact=JabberHContactFromJID(proto, jid)) != NULL) || !strcmp(id, proto->threadData->username)) { + ZeroMemory(&ci, sizeof(ci)); + ci.cbSize = sizeof(ci); + ci.hContact = hContact; + ci.szProto = (char *)proto->m_szModuleName; + ci.dwFlag = CNF_DISPLAY; + if (!CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM) & ci)) { + if (ci.type == CNFT_ASCIIZ) { + if (ci.pszVal) { + char* str = mir_t2a(ci.pszVal); + mir_free(ci.pszVal); + return str; + } + } + } + } + } + return mir_strdup(id); +} + +BOOL TlenMUCInit(TlenProtocol *proto) +{ + HookEventObj_Ex(ME_MUCC_EVENT, proto, TlenMUCHandleEvent); + return 0; +} +static int TlenMUCHandleEvent(void *ptr, WPARAM wParam, LPARAM lParam) +{ + HANDLE hContact; + int id; + MUCCEVENT *mucce=(MUCCEVENT *) lParam; + TlenProtocol *proto = (TlenProtocol *)ptr; + if (!strcmp(mucce->pszModule, proto->m_szModuleName)) { + switch (mucce->iType) { + case MUCC_EVENT_INVITE: + TlenMUCSendInvitation(proto, mucce->pszID, mucce->pszNick); + break; + case MUCC_EVENT_MESSAGE: + TlenMUCSendMessage(proto, mucce); + break; + case MUCC_EVENT_TOPIC: + TlenMUCSendTopic(proto, mucce); + break; + case MUCC_EVENT_LEAVE: + TlenMUCSendPresence(proto, mucce->pszID, NULL, ID_STATUS_OFFLINE); + break; + case MUCC_EVENT_QUERY_GROUPS: + TlenMUCSendQuery(proto, 1, mucce->pszID, 0); + break; + case MUCC_EVENT_QUERY_ROOMS: + TlenMUCSendQuery(proto, 2, mucce->pszID, mucce->dwData); + break; + case MUCC_EVENT_QUERY_SEARCH: + TlenMUCSendQuery(proto, 3, mucce->pszName, 0); + break; + case MUCC_EVENT_QUERY_USERS: + switch (mucce->dwFlags) { + case MUCC_EF_USER_OWNER: + id = 1; + break; + case MUCC_EF_USER_ADMIN: + id = 2; + break; + case MUCC_EF_USER_MEMBER: + id = 3; + break; + case MUCC_EF_USER_BANNED: + id = 4; + break; + case MUCC_EF_USER_MODERATOR: + id = 6; + break; + default: + id = 0; + } + TlenMUCSendQuery(proto, 4, mucce->pszID, id); + break; + case MUCC_EVENT_REGISTER_NICK: + TlenMUCSendQuery(proto, 6, mucce->pszNick, 0); + break; + case MUCC_EVENT_REMOVE_NICK: + TlenMUCSendQuery(proto, 6, mucce->pszNick, 1); + break; + case MUCC_EVENT_REGISTER_ROOM: + id = JabberSerialNext(proto); + if (proto->isOnline) { + if (mucce->pszNick != NULL) { + JabberSend(proto, "

", id, mucce->dwFlags | 0x10, mucce->pszName, mucce->pszID); + } else { + JabberSend(proto, "

", id, mucce->dwFlags | 0x10, mucce->pszName, mucce->pszID); + } + } + break; + case MUCC_EVENT_REMOVE_ROOM: + if (proto->isOnline) { + JabberSend(proto, "

", mucce->pszID); + JabberListRemove(proto, LIST_CHATROOM, mucce->pszID); + // TlenMUCSendPresence(mucce->pszID, NULL, ID_STATUS_OFFLINE); + } + break; + case MUCC_EVENT_KICK_BAN: + if (proto->isOnline) { + char *nick; + nick = JabberResourceFromJID(mucce->pszUID); + if (!isSelf(proto, mucce->pszID, nick)) { + char *reason = JabberTextEncode(mucce->pszText); + JabberSend(proto, "

", mucce->pszID, nick, mucce->dwData, reason); + mir_free(reason); + } + mir_free(nick); + } + break; + case MUCC_EVENT_UNBAN: + if (proto->isOnline) { + char *nick; + nick = JabberResourceFromJID(mucce->pszUID); + if (!isSelf(proto, mucce->pszID, nick)) { + JabberSend(proto, "

", mucce->pszID, nick); + } + mir_free(nick); + } + break; + case MUCC_EVENT_SET_USER_ROLE: + if (proto->isOnline) { + char *nick; + nick = JabberResourceFromJID(mucce->pszUID); + if (!isSelf(proto, mucce->pszID, nick)) { + if (mucce->dwFlags == MUCC_EF_USER_ADMIN) { + id = 2; + } else if (mucce->dwFlags == MUCC_EF_USER_MEMBER) { + id = 3; + } else { + id = 0; + } + JabberSend(proto, "

", mucce->pszID, nick, id); + } + mir_free(nick); + } + break; + case MUCC_EVENT_QUERY_USER_NICKS: + TlenMUCSendQuery(proto, 7, mucce->pszID, 0); + break; + case MUCC_EVENT_QUERY_USER_ROOMS: + TlenMUCSendQuery(proto, 8, mucce->pszID, 0); + break; + case MUCC_EVENT_QUERY_CONTACTS: + TlenMUCQueryContacts(proto, mucce->pszID); + break; + case MUCC_EVENT_JOIN: + if (proto->isOnline) { + if (mucce->pszID == NULL || strlen(mucce->pszID) == 0) { + if (mucce->pszName == NULL || strlen(mucce->pszName) == 0) { // create a new chat room + id = JabberSerialNext(proto); + JabberSend(proto, "

", id); + } else { // find a chat room by name + TlenMUCSendQuery(proto, 3, mucce->pszName, 0); + } + } else { // join existing chat room + if (!TlenMUCCreateWindow(proto, mucce->pszID, mucce->pszName, mucce->dwFlags, mucce->pszNick, NULL)) { + TlenMUCSendPresence(proto, mucce->pszID, mucce->pszNick, ID_STATUS_ONLINE); + } + } + } + break; + case MUCC_EVENT_START_PRIV: + if (proto->isOnline) { + JABBER_LIST_ITEM *item; + item = JabberListGetItemPtr(proto, LIST_CHATROOM, mucce->pszID); + if (item != NULL) { + char *nick; + nick = JabberResourceFromJID(mucce->pszUID); + if (!isSelf(proto, mucce->pszID, nick)) { + if (nick[0] == '~' || item->nick != NULL) { + char str[256]; + sprintf(str, "%s/%s", mucce->pszID, nick); + hContact = JabberDBCreateContact(proto, str, nick, TRUE); //(char *)mucce->pszUID + DBWriteContactSettingByte(hContact, proto->m_szModuleName, "bChat", TRUE); + CallService(MS_MSG_SENDMESSAGE, (WPARAM) hContact, (LPARAM) NULL); + } else { + DBVARIANT dbv; + if (!DBGetContactSetting(NULL, proto->m_szModuleName, "LoginServer", &dbv)) { + char str[512]; + _snprintf(str, sizeof(str), "%s@%s", nick, dbv.pszVal); + DBFreeVariant(&dbv); + hContact = JabberDBCreateContact(proto, str, nick, TRUE); + CallService(MS_MSG_SENDMESSAGE, (WPARAM) hContact, (LPARAM) NULL); + } + } + } + mir_free(nick); + } + } + break; + } + } + return 0; +} + +int TlenMUCRecvInvitation(TlenProtocol *proto, const char *roomId, const char *roomName, const char *from, const char *reason) +{ + char *nick; + int ignore, ask, groupChatPolicy; + if (roomId == NULL) return 1; + groupChatPolicy = DBGetContactSettingWord(NULL, proto->m_szModuleName, "GroupChatPolicy", 0); + ask = TRUE; + ignore = FALSE; + if (groupChatPolicy == TLEN_MUC_ASK) { + ignore = FALSE; + ask = TRUE; + } else if (groupChatPolicy == TLEN_MUC_IGNORE_ALL) { + ignore = TRUE; + } else if (groupChatPolicy == TLEN_MUC_IGNORE_NIR) { + char jid[256]; + DBVARIANT dbv; + if (!DBGetContactSetting(NULL, proto->m_szModuleName, "LoginServer", &dbv)) { + _snprintf(jid, sizeof(jid), "%s@%s", from, dbv.pszVal); + DBFreeVariant(&dbv); + } else { + strcpy(jid, from); + } + ignore = !IsAuthorized(proto, jid); + ask = TRUE; + } else if (groupChatPolicy == TLEN_MUC_ACCEPT_IR) { + char jid[256]; + JABBER_LIST_ITEM *item; + DBVARIANT dbv; + if (!DBGetContactSetting(NULL, proto->m_szModuleName, "LoginServer", &dbv)) { + _snprintf(jid, sizeof(jid), "%s@%s", from, dbv.pszVal); + DBFreeVariant(&dbv); + } else { + strcpy(jid, from); + } + item = JabberListGetItemPtr(proto, LIST_ROSTER, jid); + ask = !IsAuthorized(proto, jid); + ignore = FALSE; + } else if (groupChatPolicy == TLEN_MUC_ACCEPT_ALL) { + ask = FALSE; + ignore = FALSE; + } + if (!ignore) { + if (ask) { + MUCCEVENT mucce; + mucce.cbSize = sizeof(MUCCEVENT); + mucce.pszModule = proto->m_szModuleName; + mucce.pszID = roomId; + mucce.pszName = roomName; + mucce.iType = MUCC_EVENT_INVITATION; + mucce.pszUID = from; + nick = getDisplayName(proto, from); + mucce.pszNick = nick; + mucce.pszText = reason; + CallService(MS_MUCC_EVENT, 0, (LPARAM) &mucce); + mir_free(nick); + } else { + if (!TlenMUCCreateWindow(proto, roomId, roomName, 0, NULL, NULL)) { + TlenMUCSendPresence(proto, roomId, NULL, ID_STATUS_ONLINE); + } + } + } + return 0; +} + +int TlenMUCRecvPresence(TlenProtocol *proto, const char *from, int status, int flags, const char *kick) +{ + char str[512]; +// if (JabberListExist(LIST_CHATROOM, from)) { + char *nick, *roomId, *userId; + MUCCEVENT mucce; + roomId = JabberLoginFromJID(from); + userId = JabberResourceFromJID(from); + nick = getDisplayName(proto, userId); + mucce.cbSize = sizeof(MUCCEVENT); + mucce.pszModule = proto->m_szModuleName; + mucce.pszID = roomId; + mucce.iType = MUCC_EVENT_STATUS; + mucce.pszUID = userId;//from; + mucce.pszNick = nick; + mucce.time = time(NULL); + mucce.bIsMe = isSelf(proto, roomId, userId); + mucce.dwData = status; + mucce.dwFlags = 0; + if (flags & USER_FLAGS_GLOBALOWNER) mucce.dwFlags |= MUCC_EF_USER_GLOBALOWNER; + if (flags & USER_FLAGS_OWNER) mucce.dwFlags |= MUCC_EF_USER_OWNER; + if (flags & USER_FLAGS_ADMIN) mucce.dwFlags |= MUCC_EF_USER_ADMIN; + if (flags & USER_FLAGS_REGISTERED) mucce.dwFlags |= MUCC_EF_USER_REGISTERED; + if (status == ID_STATUS_OFFLINE && mucce.bIsMe && kick != NULL) { + mucce.iType = MUCC_EVENT_ERROR; + sprintf(str, Translate("You have been kicked. Reason: %s "), kick); + mucce.pszText = str; + } + CallService(MS_MUCC_EVENT, 0, (LPARAM) &mucce); + mir_free(roomId); + mir_free(userId); + mir_free(nick); +// } + return 0; +} + +int TlenMUCRecvMessage(TlenProtocol *proto, const char *from, long timestamp, XmlNode *bodyNode) +{ +// if (JabberListExist(LIST_CHATROOM, from)) { + char *localMessage; + char *nick, *style, *roomId, *userId; + int iStyle; + MUCCEVENT mucce; + roomId = JabberLoginFromJID(from); + userId = JabberResourceFromJID(from); + nick = getDisplayName(proto, userId); + localMessage = JabberTextDecode(bodyNode->text); + mucce.cbSize = sizeof(MUCCEVENT); + mucce.iType = MUCC_EVENT_MESSAGE; + mucce.pszID = roomId; + mucce.pszModule = proto->m_szModuleName; + mucce.pszText = localMessage; + mucce.pszUID = userId;//from; + mucce.pszNick = nick; + mucce.time = timestamp; + mucce.bIsMe = isSelf(proto, roomId, userId); + mucce.dwFlags = 0; + mucce.iFontSize = 0; + style = JabberXmlGetAttrValue(bodyNode, "f"); + if (style != NULL) { + iStyle = atoi(style); + if (iStyle & 1) mucce.dwFlags |= MUCC_EF_FONT_BOLD; + if (iStyle & 2) mucce.dwFlags |= MUCC_EF_FONT_ITALIC; + if (iStyle & 4) mucce.dwFlags |= MUCC_EF_FONT_UNDERLINE; + } + style = JabberXmlGetAttrValue(bodyNode, "c"); + if (style != NULL && strlen(style) > 5) { + iStyle = (stringToHex(style)<<16) | (stringToHex(style+2)<<8) | stringToHex(style+4); + } else { + iStyle = 0xFFFFFFFF; + } + mucce.color = (COLORREF) iStyle; + style = JabberXmlGetAttrValue(bodyNode, "s"); + if (style != NULL) { + iStyle = atoi(style); + } else { + iStyle = 0; + } + mucce.iFontSize = iStyle; + style = JabberXmlGetAttrValue(bodyNode, "n"); + if (style != NULL) { + iStyle = atoi(style)-1; + } else { + iStyle = 0; + } + mucce.iFont = iStyle; + CallService(MS_MUCC_EVENT, 0, (LPARAM) &mucce); + mir_free(roomId); + mir_free(userId); + mir_free(nick); + mir_free(localMessage); +// } + return 0; +} +int TlenMUCRecvTopic(TlenProtocol *proto, const char *from, const char *subject) +{ +// if (JabberListExist(LIST_CHATROOM, from)) { + MUCCEVENT mucce; + mucce.cbSize = sizeof(MUCCEVENT); + mucce.iType = MUCC_EVENT_TOPIC; + mucce.pszID = from; + mucce.pszModule = proto->m_szModuleName; + mucce.pszText = subject; + mucce.time = time(NULL); + CallService(MS_MUCC_EVENT, 0, (LPARAM) &mucce); +// } + return 0; +} + +int TlenMUCRecvError(TlenProtocol *proto, const char *from, XmlNode *errorNode) +{ + int errCode; + char str[512]; + JABBER_LIST_ITEM *item; + MUCCEVENT mucce; + mucce.cbSize = sizeof(MUCCEVENT); + mucce.iType = MUCC_EVENT_ERROR; + mucce.pszID = from; + mucce.pszModule = proto->m_szModuleName; + errCode = atoi(JabberXmlGetAttrValue(errorNode, "code")); + switch (errCode) { + case 403: + sprintf(str, Translate("You cannot join this chat room, because you are banned.")); + break; + case 404: + sprintf(str, Translate("Chat room not found.")); + break; + case 407: + sprintf(str, Translate("This is a private chat room and you are not one of the members.")); + break; + case 408: + sprintf(str, Translate("You cannot send any message unless you join this chat room.")); + break; + case 410: + sprintf(str, Translate("Chat room with already created.")); + break; + case 411: + sprintf(str, Translate("Nickname '%s' is already registered."), + JabberXmlGetAttrValue(errorNode, "n")); + break; + case 412: + sprintf(str, Translate("Nickname already in use, please try another one. Hint: '%s' is free."), + JabberXmlGetAttrValue(errorNode, "free")); + break; + case 413: + sprintf(str, Translate("You cannot register more than %s nicknames."), + JabberXmlGetAttrValue(errorNode, "num")); + break; + case 414: + sprintf(str, Translate("You cannot create more than %s chat rooms."), + JabberXmlGetAttrValue(errorNode, "num")); + break; + case 415: + sprintf(str, Translate("You cannot join more than %s chat rooms."), + JabberXmlGetAttrValue(errorNode, "num")); + break; + case 601: + sprintf(str, Translate("Anonymous nicknames are not allowed in this chat room.")); + break; + default: + sprintf(str, Translate("Unknown error code : %d"), errCode); + break; + } + mucce.pszText = str; + CallService(MS_MUCC_EVENT, 0, (LPARAM) &mucce); + if (proto->isOnline) { + switch (errCode) { + case 412: + item = JabberListGetItemPtr(proto, LIST_CHATROOM, from); + if (item != NULL) { + mucce.iType = MUCC_EVENT_JOIN; + mucce.dwFlags = MUCC_EF_ROOM_NICKNAMES; + mucce.pszModule = proto->m_szModuleName; + mucce.pszID = from; + mucce.pszName = item->roomName; + mucce.pszNick = JabberXmlGetAttrValue(errorNode, "free"); + CallService(MS_MUCC_EVENT, 0, (LPARAM) &mucce); + } + break; + case 601: + item = JabberListGetItemPtr(proto, LIST_CHATROOM, from); + if (item != NULL) { + mucce.iType = MUCC_EVENT_JOIN; + mucce.dwFlags = 0; + mucce.pszModule = proto->m_szModuleName; + mucce.pszID = from; + mucce.pszName = item->roomName; + mucce.pszNick = NULL; + CallService(MS_MUCC_EVENT, 0, (LPARAM) &mucce); + } + break; + } + } + return 1; +} +static int TlenMUCSendInvitation(TlenProtocol *proto, const char *roomID, const char *user) +{ + if (!proto->isOnline) { + return 1; + } + JabberSend(proto, "", roomID, user); + return 0; +} + +static int TlenMUCSendPresence(TlenProtocol *proto, const char *roomID, const char *nick, int desiredStatus) +{ + char str[512]; + char *jid; + JABBER_LIST_ITEM *item; + if (!proto->isOnline) { + return 1; + } + if (nick != NULL) { + _snprintf(str, sizeof(str), "%s/%s", roomID, nick); + } else { + _snprintf(str, sizeof(str), "%s", roomID); + } + if ((jid = JabberTextEncode(str)) != NULL) { + switch (desiredStatus) { + case ID_STATUS_ONLINE: + JabberSend(proto, "

", jid); + item = JabberListGetItemPtr(proto, LIST_CHATROOM, roomID); + if (item != NULL) { + if (item->nick != NULL) mir_free(item->nick); + item->nick = NULL; + if (nick != NULL) { + item->nick = mir_strdup(nick); + } + } + break; + default: + item = JabberListGetItemPtr(proto, LIST_CHATROOM, roomID); + if (item != NULL) { + JabberSend(proto, "

unavailable

", jid); + JabberListRemove(proto, LIST_CHATROOM, roomID); + } + break; + } + mir_free(jid); + } + return 0; +} + +static int TlenMUCSendMessage(TlenProtocol *proto, MUCCEVENT *event) +{ + char *msg, *jid; + int style; + + if (!proto->isOnline) { + return 1; + } + if ((msg = JabberTextEncode(event->pszText)) != NULL) { + if ((jid = JabberTextEncode(event->pszID)) != NULL) { + style = 0; + if (event->dwFlags & MUCC_EF_FONT_BOLD) style |=1; + if (event->dwFlags & MUCC_EF_FONT_ITALIC) style |=2; + if (event->dwFlags & MUCC_EF_FONT_UNDERLINE) style |=4; + JabberSend(proto, "%s", jid, event->iFont+1, event->iFontSize, style, event->color, msg); + mir_free(jid); + } + mir_free(msg); + } + return 0; +} + +static int TlenMUCSendTopic(TlenProtocol *proto, MUCCEVENT *event) +{ + char *msg, *jid; + if (!proto->isOnline) { + return 1; + } + if ((msg = JabberTextEncode(event->pszText)) != NULL) { + if ((jid = JabberTextEncode(event->pszID)) != NULL) { + JabberSend(proto, "%s", jid, msg); + mir_free(jid); + } + mir_free(msg); + } + return 0; +} + +static int TlenMUCSendQuery(TlenProtocol *proto, int type, const char *parent, int page) +{ + if (!proto->isOnline) { + return 1; + } + if (type == 3) { // find chat room by name + char serialId[32]; + JABBER_LIST_ITEM *item; + sprintf(serialId, JABBER_IQID"%d", JabberSerialNext(proto)); + item = JabberListAdd(proto, LIST_SEARCH, serialId); + item->roomName = mir_strdup(parent); + JabberSend(proto, "", parent, serialId); + } else { + if (parent == NULL) { + JabberSend(proto, "", type); + } else { // 1 - groups, 2 - chat rooms, 7 - user nicks, 8 - user rooms + if (type == 1 || (type == 2 && page == 0) || type == 7 || type == 8) { + JabberSend(proto, "", type, parent); + } else if (type == 2) { + JabberSend(proto, "", type, parent, page); + } else if (type == 6) { + if (page) { + JabberSend(proto, "", type, parent); + } else { + JabberSend(proto, "", type, parent); + } + } else if (type == 4) { // list of users, admins etc. + JabberSend(proto, "", parent, type, page); + } + } + } + return 0; +} + +int TlenMUCCreateWindow(TlenProtocol *proto, const char *roomID, const char *roomName, int roomFlags, const char *nick, const char *iqId) +{ + JABBER_LIST_ITEM *item; + MUCCWINDOW mucw; + if (!proto->isOnline || roomID == NULL) { + return 1; + } + if (JabberListExist(proto, LIST_CHATROOM, roomID)) { + return 0; + } + item = JabberListAdd(proto, LIST_CHATROOM, roomID); + if (roomName != NULL) { + item->roomName = mir_strdup(roomName); + } + if (nick != NULL) { + item->nick = mir_strdup(nick); + } + mucw.cbSize = sizeof(MUCCWINDOW); + mucw.iType = MUCC_WINDOW_CHATROOM; + mucw.pszModule = proto->m_szModuleName; + mucw.pszModuleName = proto->m_szProtoName; + mucw.pszID = roomID; + mucw.pszName = roomName; + mucw.pszNick = nick; + mucw.dwFlags = roomFlags; + mucw.pszStatusbarText = "hello"; + CallService(MS_MUCC_NEW_WINDOW, 0, (LPARAM) &mucw); + if (iqId != NULL) { + item = JabberListGetItemPtr(proto, LIST_INVITATIONS, iqId); + if (item !=NULL) { + TlenMUCSendInvitation(proto, roomID, item->nick); + } + JabberListRemove(proto, LIST_INVITATIONS, iqId); + } + return 0; +} + +static void TlenMUCFreeQueryResult(MUCCQUERYRESULT *result) +{ int i; + for (i=0; iiItemsNum; i++) { + if (result->pItems[i].pszID != NULL) { + mir_free((char *) result->pItems[i].pszID); + } + if (result->pItems[i].pszName != NULL) { + mir_free((char *) result->pItems[i].pszName); + } + if (result->pItems[i].pszNick != NULL) { + mir_free((char *) result->pItems[i].pszNick); + } + if (result->pItems[i].pszText != NULL) { + mir_free((char *) result->pItems[i].pszText); + } + } + mir_free((MUCCQUERYITEM *)result->pItems); +} + +void TlenIqResultChatGroups(TlenProtocol *proto, XmlNode *iqNode) +{ + XmlNode *lNode, *itemNode; + char *p, *n, *id, *f; + int i, j; + MUCCQUERYRESULT queryResult; + + if ((lNode=JabberXmlGetChild(iqNode, "l")) == NULL) return; + p = JabberXmlGetAttrValue(iqNode, "p"); + if (p == NULL) { + p=""; + } + p = JabberTextDecode(p); + queryResult.cbSize = sizeof (MUCCQUERYRESULT); + queryResult.iType = MUCC_EVENT_QUERY_GROUPS; + queryResult.pszModule = proto->m_szModuleName; + queryResult.pszParent = p; + queryResult.pItems = (MUCCQUERYITEM*)mir_alloc(sizeof(MUCCQUERYITEM) * lNode->numChild); + memset(queryResult.pItems, 0, sizeof(MUCCQUERYITEM) * lNode->numChild); + for (i=j=0; inumChild; i++) { + itemNode = lNode->child[i]; + if (!strcmp(itemNode->name, "i")) { + queryResult.pItems[j].iCount = 0; + if ((f = JabberXmlGetAttrValue(itemNode, "f")) != NULL) { + queryResult.pItems[j].iCount = !strcmp(f, "3"); + } + n = JabberXmlGetAttrValue(itemNode, "n"); + id = JabberXmlGetAttrValue(itemNode, "i"); + if (n != NULL && id != NULL) { + queryResult.pItems[j].pszID = JabberTextDecode(id); + queryResult.pItems[j].pszName = JabberTextDecode(n); + j++; + } + } + } + queryResult.iItemsNum = j; + CallService(MS_MUCC_QUERY_RESULT, 0, (LPARAM) &queryResult); + TlenMUCFreeQueryResult(&queryResult); + mir_free(p); +} + +void TlenIqResultChatRooms(TlenProtocol *proto, XmlNode *iqNode) +{ + XmlNode *lNode, *itemNode; + char *id, *c, *n, *x, *p, *px, *pn; + int i, j; + MUCCQUERYRESULT queryResult; + + if ((lNode=JabberXmlGetChild(iqNode, "l")) == NULL) return; + if ((p = JabberXmlGetAttrValue(iqNode, "p")) == NULL) return; + pn = JabberXmlGetAttrValue(lNode, "n"); + if (pn == NULL) pn = "0"; + px = JabberXmlGetAttrValue(lNode, "x"); + if (px == NULL) px = "0"; + p = JabberTextDecode(p); + queryResult.cbSize = sizeof (MUCCQUERYRESULT); + queryResult.iType = MUCC_EVENT_QUERY_ROOMS; + queryResult.pszModule = proto->m_szModuleName; + queryResult.pszParent = p; + queryResult.pItems = (MUCCQUERYITEM*)mir_alloc(sizeof(MUCCQUERYITEM) * lNode->numChild); + memset(queryResult.pItems, 0, sizeof(MUCCQUERYITEM) * lNode->numChild); + queryResult.iPage = atoi(pn); + queryResult.iLastPage = atoi(px)&2?1:0; + for (i=j=0; inumChild; i++) { + itemNode = lNode->child[i]; + if (!strcmp(itemNode->name, "i")) { + n = JabberXmlGetAttrValue(itemNode, "n"); + c = JabberXmlGetAttrValue(itemNode, "c"); + x = JabberXmlGetAttrValue(itemNode, "x"); + if ((id=JabberXmlGetAttrValue(itemNode, "i")) != NULL) { + queryResult.pItems[j].pszID = JabberTextDecode(id); + queryResult.pItems[j].pszName = JabberTextDecode(n); + queryResult.pItems[j].iCount = atoi(c); + queryResult.pItems[j].dwFlags = atoi(x); + j++; + } + } + } + queryResult.iItemsNum = j; + CallService(MS_MUCC_QUERY_RESULT, 0, (LPARAM) &queryResult); + TlenMUCFreeQueryResult(&queryResult); + mir_free(p); +} +void TlenIqResultUserRooms(TlenProtocol *proto, XmlNode *iqNode) +{ + XmlNode *lNode, *itemNode; + char *id, *n; + int i, j; + MUCCQUERYRESULT queryResult; + if ((lNode=JabberXmlGetChild(iqNode, "l")) == NULL) return; + queryResult.cbSize = sizeof (MUCCQUERYRESULT); + queryResult.iType = MUCC_EVENT_QUERY_USER_ROOMS; + queryResult.pszModule = proto->m_szModuleName; + queryResult.pItems = (MUCCQUERYITEM*)mir_alloc(sizeof(MUCCQUERYITEM) * lNode->numChild); + memset(queryResult.pItems, 0, sizeof(MUCCQUERYITEM) * lNode->numChild); + for (i=j=0; inumChild; i++) { + itemNode = lNode->child[i]; + if (!strcmp(itemNode->name, "i")) { + n = JabberXmlGetAttrValue(itemNode, "n"); + id = JabberXmlGetAttrValue(itemNode, "i"); + if (n != NULL && id != NULL) { + queryResult.pItems[j].pszID = JabberTextDecode(id); + queryResult.pItems[j].pszName = JabberTextDecode(n); + j++; + } + } + } + queryResult.iItemsNum = j; + CallService(MS_MUCC_QUERY_RESULT, 0, (LPARAM) &queryResult); + TlenMUCFreeQueryResult(&queryResult); +} +void TlenIqResultUserNicks(TlenProtocol *proto, XmlNode *iqNode) +{ + XmlNode *lNode, *itemNode; + char *n; + int i, j; + MUCCQUERYRESULT queryResult; + if ((lNode=JabberXmlGetChild(iqNode, "l")) == NULL) return; + queryResult.cbSize = sizeof (MUCCQUERYRESULT); + queryResult.iType = MUCC_EVENT_QUERY_USER_NICKS; + queryResult.pszModule = proto->m_szModuleName; + queryResult.pItems = (MUCCQUERYITEM*)mir_alloc(sizeof(MUCCQUERYITEM) * lNode->numChild); + memset(queryResult.pItems, 0, sizeof(MUCCQUERYITEM) * lNode->numChild); + for (i=j=0; inumChild; i++) { + itemNode = lNode->child[i]; + if (!strcmp(itemNode->name, "i")) { + n = JabberXmlGetAttrValue(itemNode, "n"); + queryResult.pItems[j].pszID = NULL;//JabberTextDecode(n); + queryResult.pItems[j].pszName = JabberTextDecode(n); + j++; + } + } + queryResult.iItemsNum = j; + CallService(MS_MUCC_QUERY_RESULT, 0, (LPARAM) &queryResult); + TlenMUCFreeQueryResult(&queryResult); +} +void TlenIqResultChatRoomUsers(TlenProtocol *proto, XmlNode *iqNode) +{ + XmlNode *lNode, *itemNode; + char *id, *n; + int i, j; + MUCCQUERYRESULT queryResult; + if ((lNode=JabberXmlGetChild(iqNode, "l")) == NULL) return; + if ((id=JabberXmlGetAttrValue(iqNode, "from")) == NULL) return; + queryResult.cbSize = sizeof (MUCCQUERYRESULT); + queryResult.iType = MUCC_EVENT_QUERY_USERS; + queryResult.pszModule = proto->m_szModuleName; + queryResult.pszParent = id; + queryResult.pItems = (MUCCQUERYITEM*)mir_alloc(sizeof(MUCCQUERYITEM) * lNode->numChild); + memset(queryResult.pItems, 0, sizeof(MUCCQUERYITEM) * lNode->numChild); + for (i=j=0; inumChild; i++) { + itemNode = lNode->child[i]; + if (!strcmp(itemNode->name, "i")) { + id = JabberXmlGetAttrValue(itemNode, "i"); + if (id != NULL) { + queryResult.pItems[j].pszID = JabberTextDecode(id); + n = JabberXmlGetAttrValue(itemNode, "n"); + if (n != NULL) { + queryResult.pItems[j].pszName = JabberTextDecode(n); + } + n = JabberXmlGetAttrValue(itemNode, "a"); + if (n != NULL) { + queryResult.pItems[j].pszNick = JabberTextDecode(n); + } + n = JabberXmlGetAttrValue(itemNode, "r"); + if (n != NULL) { + queryResult.pItems[j].pszText = JabberTextDecode(n); + } + n = JabberXmlGetAttrValue(itemNode, "e"); + if (n != NULL) { + queryResult.pItems[j].iCount = atoi(n); + } + n = JabberXmlGetAttrValue(itemNode, "s"); + if (n != NULL) { + queryResult.pItems[j].dwFlags = atoi(n); + } + j++; + } + } + } + queryResult.iItemsNum = j; + CallService(MS_MUCC_QUERY_RESULT, 0, (LPARAM) &queryResult); + TlenMUCFreeQueryResult(&queryResult); +} + +void TlenIqResultRoomSearch(TlenProtocol *proto, XmlNode *iqNode) +{ + char *iqId, *id; + JABBER_LIST_ITEM *item; + iqId=JabberXmlGetAttrValue(iqNode, "id"); + item=JabberListGetItemPtr(proto, LIST_SEARCH, iqId); + if ((id=JabberXmlGetAttrValue(iqNode, "i")) != NULL) { + MUCCEVENT mucce; + id = JabberTextDecode(id); + mucce.cbSize = sizeof(MUCCEVENT); + mucce.iType = MUCC_EVENT_JOIN; + mucce.pszModule = proto->m_szModuleName; + mucce.pszID = id; + mucce.pszName = id; + if (item != NULL) { + mucce.pszName = item->roomName; + } + mucce.pszNick = NULL; + mucce.dwFlags = MUCC_EF_ROOM_NICKNAMES; + CallService(MS_MUCC_EVENT, 0, (LPARAM) &mucce); + mir_free(id); + } + JabberListRemove(proto, LIST_SEARCH, iqId); +} + +void TlenIqResultRoomInfo(TlenProtocol *proto, XmlNode *iqNode) +{ + char *id, *name, *group, *flags; + if ((id=JabberXmlGetAttrValue(iqNode, "from")) != NULL) { + if ((name=JabberXmlGetAttrValue(iqNode, "n")) != NULL) { + MUCCEVENT mucce; + group = JabberXmlGetAttrValue(iqNode, "cn"); + flags = JabberXmlGetAttrValue(iqNode, "x"); + id = JabberTextDecode(id); + name = JabberTextDecode(name); + mucce.cbSize = sizeof(MUCCEVENT); + mucce.iType = MUCC_EVENT_ROOM_INFO; + mucce.pszModule = proto->m_szModuleName; + mucce.pszID = id; + mucce.pszName = name; + mucce.dwFlags = atoi(flags); + CallService(MS_MUCC_EVENT, 0, (LPARAM) &mucce); + mir_free(id); + mir_free(name); + } + } +} + + +typedef struct { + TlenProtocol *proto; + char *roomId; +} MUCSENDQUERYTHREADDATA; + +static void __cdecl TlenMUCCSendQueryResultThread(void *ptr) +{ + HANDLE hContact; + MUCCQUERYRESULT queryResult; + DBVARIANT dbv; + MUCSENDQUERYTHREADDATA* threadData = (MUCSENDQUERYTHREADDATA*)ptr; + queryResult.cbSize = sizeof (MUCCQUERYRESULT); + queryResult.iType = MUCC_EVENT_QUERY_CONTACTS; + queryResult.pszModule = threadData->proto->m_szModuleName; + queryResult.pszParent = threadData->roomId; + queryResult.iItemsNum = 0; + hContact = db_find_first(); + while (hContact != NULL) { + char *str = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0); + if (str != NULL && !strcmp(str, threadData->proto->m_szModuleName)) { + if (!DBGetContactSettingByte(hContact, threadData->proto->m_szModuleName, "bChat", FALSE)) { + if (!DBGetContactSetting(hContact, threadData->proto->m_szModuleName, "jid", &dbv)) { + if (strcmp(dbv.pszVal, "b73@tlen.pl")) { + queryResult.iItemsNum++; + } + DBFreeVariant(&dbv); + } + } + } + hContact = db_find_next(hContact); + } + queryResult.pItems = (MUCCQUERYITEM*)mir_alloc(sizeof(MUCCQUERYITEM) * queryResult.iItemsNum); + memset(queryResult.pItems, 0, sizeof(MUCCQUERYITEM) * queryResult.iItemsNum); + queryResult.iItemsNum = 0; + hContact = db_find_first(); + while (hContact != NULL) { + char *baseProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0); + if (baseProto != NULL && !strcmp(baseProto, threadData->proto->m_szModuleName)) { + if (!DBGetContactSettingByte(hContact, threadData->proto->m_szModuleName, "bChat", FALSE)) { + if (!DBGetContactSetting(hContact, threadData->proto->m_szModuleName, "jid", &dbv)) { + if (strcmp(dbv.pszVal, "b73@tlen.pl")) { + queryResult.pItems[queryResult.iItemsNum].pszID = mir_strdup(dbv.pszVal); + queryResult.pItems[queryResult.iItemsNum].pszName = mir_strdup((char *) CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM) hContact, 0)); + queryResult.iItemsNum++; + } + DBFreeVariant(&dbv); + } + } + } + hContact = db_find_next(hContact); + } + CallService(MS_MUCC_QUERY_RESULT, 0, (LPARAM) &queryResult); + TlenMUCFreeQueryResult(&queryResult); + mir_free(threadData->roomId); + mir_free(threadData); +} + + +static int TlenMUCQueryContacts(TlenProtocol *proto, const char *roomId) { + + MUCSENDQUERYTHREADDATA *threadData = (MUCSENDQUERYTHREADDATA *)mir_alloc(sizeof(MUCSENDQUERYTHREADDATA)); + threadData->proto = proto; + threadData->roomId = mir_strdup(roomId); + JabberForkThread(TlenMUCCSendQueryResultThread, 0, (void *)threadData); + return 1; +} + +INT_PTR TlenMUCMenuHandleMUC(void *ptr, LPARAM wParam, LPARAM lParam) +{ + TlenProtocol *proto = (TlenProtocol *)ptr; + if (!proto->isOnline) { + return 1; + } + JabberSend(proto, "

", JabberSerialNext(proto)); + /* + MUCCEVENT *mucce; + mucce = (MUCCEVENT *) mir_alloc (sizeof(MUCCEVENT)); + mucce->cbSize = sizeof(MUCCEVENT); + mucce->iType = MUCC_EVENT_JOIN; + mucce->dwFlags = 0; + mucce->pszModule = proto->m_szModuleName; + mucce->pszID = NULL; + mucce->pszName = NULL; + mucce->pszNick = NULL; + CallService(MS_MUCC_EVENT, 0, (LPARAM) mucce); + mir_free(mucce); + */ + return 0; +} + +INT_PTR TlenMUCMenuHandleChats(void *ptr, LPARAM wParam, LPARAM lParam) +{ + MUCCWINDOW mucw; + TlenProtocol *proto = (TlenProtocol *)ptr; + if (!proto->isOnline) { + return 1; + } + mucw.cbSize = sizeof(MUCCWINDOW); + mucw.iType = MUCC_WINDOW_CHATLIST; + mucw.pszModule = proto->m_szModuleName; + mucw.pszModuleName = proto->m_szProtoName; + CallService(MS_MUCC_NEW_WINDOW, 0, (LPARAM) &mucw); + return 0; +} + +INT_PTR TlenMUCContactMenuHandleMUC(void *ptr, LPARAM wParam, LPARAM lParam) +{ + HANDLE hContact; + DBVARIANT dbv; + JABBER_LIST_ITEM *item; + TlenProtocol *proto = (TlenProtocol *)ptr; + if (!proto->isOnline) { + return 1; + } + if ((hContact=(HANDLE) wParam) != NULL && proto->isOnline) { + if (!DBGetContactSetting(hContact, proto->m_szModuleName, "jid", &dbv)) { + char serialId[32]; + sprintf(serialId, JABBER_IQID"%d", JabberSerialNext(proto)); + item = JabberListAdd(proto, LIST_INVITATIONS, serialId); + item->nick = mir_strdup(dbv.pszVal); + JabberSend(proto, "

", serialId); + DBFreeVariant(&dbv); + } + } + return 0; +} diff --git a/protocols/Tlen/src/tlen_muc.h b/protocols/Tlen/src/tlen_muc.h new file mode 100644 index 0000000000..8409315ecd --- /dev/null +++ b/protocols/Tlen/src/tlen_muc.h @@ -0,0 +1,45 @@ +/* + +Tlen Protocol Plugin for Miranda NG +Copyright (C) 2004-2007 Piotr Piastucki + +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. + +*/ + +#ifndef _TLEN_MUC_H_ +#define _TLEN_MUC_H_ + +#include +#include "m_mucc.h" + +#define USER_FLAGS_OWNER 0x01 +#define USER_FLAGS_ADMIN 0x02 +#define USER_FLAGS_REGISTERED 0x04 +#define USER_FLAGS_GLOBALOWNER 0x08 +#define USER_FLAGS_KICKED 0x80 + +extern BOOL TlenMUCInit(TlenProtocol *proto); +extern INT_PTR TlenMUCMenuHandleMUC(void *ptr, LPARAM wParam, LPARAM lParam); +extern INT_PTR TlenMUCMenuHandleChats(void *ptr, LPARAM wParam, LPARAM lParam); +extern INT_PTR TlenMUCContactMenuHandleMUC(void *ptr, LPARAM wParam, LPARAM lParam); +extern int TlenMUCCreateWindow(TlenProtocol *proto, const char *roomID, const char *roomName, int roomFlags, const char *nick, const char *iqId); +extern int TlenMUCRecvInvitation(TlenProtocol *proto, const char *roomJid, const char *roomName, const char *from, const char *reason); +extern int TlenMUCRecvPresence(TlenProtocol *proto, const char *from, int status, int flags, const char *kick); +extern int TlenMUCRecvMessage(TlenProtocol *proto, const char *from, long timestamp, XmlNode *bodyNode); +extern int TlenMUCRecvTopic(TlenProtocol *proto, const char *from, const char *subject); +extern int TlenMUCRecvError(TlenProtocol *proto, const char *from, XmlNode *errorNode); + +#endif diff --git a/protocols/Tlen/src/tlen_p2p_new.cpp b/protocols/Tlen/src/tlen_p2p_new.cpp new file mode 100644 index 0000000000..35584f277a --- /dev/null +++ b/protocols/Tlen/src/tlen_p2p_new.cpp @@ -0,0 +1,352 @@ +/* + +Tlen Protocol Plugin for Miranda NG +Copyright (C) 2004-2007 Piotr Piastucki + +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 "tlen_p2p_old.h" +#include +#include +#include +#include +#include "jabber_list.h" + + +static void logInfo(const char *filename, const char *fmt, ...) { + SYSTEMTIME time; + char *str; + va_list vararg; + int strsize; + FILE *flog=fopen(filename,"at"); + if (flog != NULL) { + GetLocalTime(&time); + va_start(vararg, fmt); + str = (char *) mir_alloc(strsize=2048); + while (_vsnprintf(str, strsize, fmt, vararg) == -1) + str = (char *) realloc(str, strsize+=2048); + va_end(vararg); + fprintf(flog,"%04d-%02d-%02d %02d:%02d:%02d,%03d [%s]",time.wYear,time.wMonth,time.wDay,time.wHour,time.wMinute,time.wSecond,time.wMilliseconds, "INFO"); + fprintf(flog," %s\n",str); + mir_free(str); + fclose(flog); + } +} + +void __cdecl TlenNewFileReceiveThread(TLEN_FILE_TRANSFER *ft) +{ + JabberLog(ft->proto, "P2P receive thread started"); + ProtoBroadcastAck(ft->proto->m_szModuleName, ft->hContact, ACKTYPE_FILE, ACKRESULT_CONNECTING, ft, 0); +// ft->mode = FT_RECV; +// ft->currentFile = 0; +// ft->state = FT_CONNECTING; + { + FILE * fout = fopen("tlen_recv.dxx", "wt"); + SOCKADDR_IN toad; + toad.sin_family = AF_INET; + toad.sin_addr.s_addr = inet_addr(ft->hostName); + toad.sin_port = htons(ft->wPort); + if (fout != NULL) { + fprintf(fout, "START:\n"); + } + if (fout != NULL) { + fclose(fout); + } + while (ft->udps != INVALID_SOCKET) { + SOCKADDR_IN cad; + int alen; + int j, n; + unsigned char buff[1024]; + alen = sizeof(struct sockaddr); + n=recvfrom(ft->udps, (char*)buff,sizeof(buff),0, (struct sockaddr *) &cad, &alen); + if (n<0) { + break; + } + logInfo("tlen_recv.dxx", "UDP"); + fout = fopen("tlen_recv.dxx", "at"); + if (fout != NULL) { + fprintf(fout, "\n|RECV %d bytes from %s:%d|",n, inet_ntoa(cad.sin_addr), cad.sin_port); + for (j = 0; j < n; j++) { + fprintf(fout, "%02X-", buff[j]); + } + } + if (n == 1) { + alen = sizeof(struct sockaddr); + n = sendto(ft->udps, (char*)buff, n, 0,(struct sockaddr *) &toad, alen); + if (fout != NULL) { + fprintf(fout, "\n|SEND |"); + for (j = 0; j < n; j++) { + fprintf(fout, "%02X-", buff[j]); + } + } + } + if (fout != NULL) { + fprintf(fout, "\n"); + fclose(fout); + } + } + } + if (ft->udps != INVALID_SOCKET) { + closesocket(ft->udps); + } + + JabberListRemove(ft->proto, LIST_FILE, ft->iqId); + if (ft->state == FT_DONE) + ProtoBroadcastAck(ft->proto->m_szModuleName, ft->hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, ft, 0); + else { + ProtoBroadcastAck(ft->proto->m_szModuleName, ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0); + } + JabberLog(ft->proto, "P2P receive thread ended"); + TlenP2PFreeFileTransfer(ft); +} + +void __cdecl TlenNewFileSendThread(TLEN_FILE_TRANSFER *ft) +{ + JabberLog(ft->proto, "P2P send thread started"); +// ft->mode = FT_RECV; +// ProtoBroadcastAck(ft->proto->m_szModuleName, ft->hContact, ACKTYPE_FILE, ACKRESULT_CONNECTING, ft, 0); +// ft->currentFile = 0; +// ft->state = FT_CONNECTING; + { + FILE * fout = fopen("tlen_send.gxx", "wt"); + int step = 0; + SOCKADDR_IN toad; + toad.sin_family = AF_INET; + toad.sin_addr.s_addr = inet_addr(ft->hostName); + toad.sin_port = htons(ft->wPort); + + if (fout != NULL) { + fprintf(fout, "START:"); + } + if (fout != NULL) { + fclose(fout); + } + for (step = 0; step < 10; step ++) { +// while (ft->udps != INVALID_SOCKET) { + int alen; + int j, n; + unsigned char buff[1024]; + alen = sizeof(struct sockaddr); + if (step < 3 || step > 5) { + buff[0] = 1; + n = 1; + } else { + buff[0] = '$'; + buff[1] = '^'; + buff[2] = '&'; + buff[3] = '%'; + n = 4; + } + n=sendto(ft->udps, (char*)buff, n, 0, (struct sockaddr *)&toad, alen); + logInfo("tlen_send.dxx", "UDP"); + if (fout != NULL) { + fprintf(fout, "|send: %d %s %d|",n, inet_ntoa(toad.sin_addr), toad.sin_port); + for (j = 0; j < n; j++) { + fprintf(fout, "%02X-", buff[j]); + } + } + if (fout != NULL) { + fprintf(fout, "\n"); + fclose(fout); + } + SleepEx(1000, TRUE); + } + } + JabberLog(ft->proto, "P2P send thread ended"); +} + +void TlenBindUDPSocket(TLEN_FILE_TRANSFER *ft) +{ + JabberLog(ft->proto, "Binding UDP socket"); + ft->udps = socket(PF_INET, SOCK_DGRAM, 0); + if (ft->udps != INVALID_SOCKET) { + SOCKADDR_IN sin; + int len = sizeof(struct sockaddr); + memset((char *)&sin,0,sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = htonl(INADDR_ANY);; + sin.sin_port = 0; + if (bind(ft->udps, (struct sockaddr *)&sin, sizeof(sin)) >= 0) { + if (!getsockname((SOCKET)ft->udps,(SOCKADDR *)&sin,&len)) { + struct hostent *hp; + char host_name[256]; + gethostname(host_name, sizeof(host_name)); + hp = gethostbyname(host_name); + mir_snprintf(host_name, sizeof(host_name), "%u.%u.%u.%u", (unsigned char)hp->h_addr_list[0][0], + (unsigned char)hp->h_addr_list[0][1], + (unsigned char)hp->h_addr_list[0][2], + (unsigned char)hp->h_addr_list[0][3]); + + ft->wLocalPort = ntohs(sin.sin_port); + ft->localName= mir_strdup(host_name); + JabberLog(ft->proto, "UDP socket bound to %s:%d", ft->localName, ft->wLocalPort); + } + } + } +} + + +/* +aaa sends a file to bbb: + +1) aaa wants to SEND bbb a file +A SEND: +B RECV: + +2) bbb ACCEPTs +B SEND: +A RECV: + +3) aaa tries to establish p2p connection: +A SEND: +B SEND: + +3) bbb sends IP/port details +B SEND: + +*/ + +void __cdecl TlenProcessP2P(XmlNode *node, ThreadData *info) { + XmlNode *queryNode; + JABBER_LIST_ITEM *item; + char *from; + + if (info == NULL) return; + + queryNode = JabberXmlGetChild(node, "query"); + if ((from=JabberXmlGetAttrValue(node, "from")) != NULL) { + XmlNode *fs , *vs, *dcng, *dc; + /* file send */ + fs = JabberXmlGetChild(queryNode, "fs"); + /* voice send */ + vs = JabberXmlGetChild(queryNode, "vs"); + dcng = JabberXmlGetChild(queryNode, "dcng"); + dc = JabberXmlGetChild(queryNode, "dc"); + if (fs != NULL) { + char *e, *id; + /* e - step in the process (starting with 1)*/ + /* i - id of the file */ + /* s - size of the file */ + /* c - number of files */ + /* v - ??? */ + e = JabberXmlGetAttrValue(fs, "e"); + id = JabberXmlGetAttrValue(fs, "i"); + if (e != NULL) { + if (!strcmp(e, "1")) { + char *c, *s; + TLEN_FILE_TRANSFER * ft = (TLEN_FILE_TRANSFER *) mir_alloc(sizeof(TLEN_FILE_TRANSFER)); + memset(ft, 0, sizeof(TLEN_FILE_TRANSFER)); + c = JabberXmlGetAttrValue(fs, "c"); + s = JabberXmlGetAttrValue(fs, "s"); + ft->jid = mir_strdup(from); + ft->proto = info->proto; + ft->hContact = JabberHContactFromJID(info->proto, from); + ft->iqId = mir_strdup(id); + ft->fileTotalSize = atoi(s); + ft->newP2P = TRUE; + if ((item=JabberListAdd(ft->proto, LIST_FILE, ft->iqId)) != NULL) { + char fileInfo[128]; + item->ft = ft; + mir_snprintf(fileInfo, sizeof(fileInfo), "%s file(s), %s bytes", c, s); + TCHAR* filenameT = mir_utf8decodeT((char*)fileInfo); + PROTORECVFILET pre = {0}; + pre.flags = PREF_TCHAR; + pre.fileCount = 1; + pre.timestamp = time(NULL); + pre.tszDescription = filenameT; + pre.ptszFiles = &filenameT; + pre.lParam = (LPARAM)ft; + JabberLog(ft->proto, "sending chainrecv"); + CCSDATA ccs = { ft->hContact, PSR_FILE, 0, (LPARAM)&pre }; + CallService(MS_PROTO_CHAINRECV, 0, (LPARAM) &ccs); + mir_free(filenameT); + } + } else if (!strcmp(e, "3")) { + /* transfer error */ + } else if (!strcmp(e, "4")) { + /* transfer denied */ + } else if (!strcmp(e, "5")) { + /* transfer accepted */ + if ((item=JabberListGetItemPtr(info->proto, LIST_FILE, id)) != NULL) { + item->id2 = mir_strdup("84273372"); + item->ft->id2 = mir_strdup("84273372"); + JabberSend(info->proto, "", from, item->id2, id); + } + } + } + } else if (vs != NULL) { + + } else if (dcng != NULL) { + char *s, *id, *id2; + JabberLog(info->proto, "DCNG"); + s = JabberXmlGetAttrValue(dcng, "s"); + id2 = JabberXmlGetAttrValue(dcng, "i"); + id = JabberXmlGetAttrValue(dcng, "mi"); + if (!strcmp(s, "1")) { + /* Keys */ + /* n - name (file_send) */ + /* k - ??? */ + /* v - ??? */ + /* s - step */ + /* i - id of the file */ + /* ck - aes key */ + /* ks - key size (in bytes) */ + /* iv - aes initial vector */ + /* mi - p2p connection id */ + char *n, *k, *v, *ck, *iv; + n = JabberXmlGetAttrValue(dcng, "n"); + k = JabberXmlGetAttrValue(dcng, "k"); + v = JabberXmlGetAttrValue(dcng, "v"); + ck = JabberXmlGetAttrValue(dcng, "ck"); + iv = JabberXmlGetAttrValue(dcng, "iv"); + if (!strcmp(n, "file_send")) { + if ((item=JabberListGetItemPtr(info->proto, LIST_FILE, id)) != NULL) { + item->id2 = mir_strdup(id2); + item->ft->id2 = mir_strdup(id2); + TlenBindUDPSocket(item->ft); + JabberSend(info->proto, "", + item->ft->jid, item->ft->localName, item->ft->wLocalPort, item->ft->localName, item->ft->wLocalPort, item->ft->id2); + } + } + } else if (!strcmp(s, "2")) { + JabberLog(info->proto, "step = 2"); + JabberLog(info->proto, "%s",from); + JabberLog(info->proto, "%s",id2); + /* IP and port */ + if ((item=JabberListFindItemPtrById2(info->proto, LIST_FILE, id2)) != NULL) { + item->ft->hostName = mir_strdup(JabberXmlGetAttrValue(dcng, "pa")); + item->ft->wPort = atoi(JabberXmlGetAttrValue(dcng, "pp")); + TlenBindUDPSocket(item->ft); + JabberSend(info->proto, "", + item->ft->jid, item->ft->localName, item->ft->wLocalPort, item->ft->localName, item->ft->wLocalPort, item->ft->id2); + JabberForkThread((void (__cdecl *)(void*))TlenNewFileReceiveThread, 0, item->ft); + JabberForkThread((void (__cdecl *)(void*))TlenNewFileSendThread, 0, item->ft); + } + } else if (!strcmp(s, "4")) { + /* IP and port */ + if ((item=JabberListFindItemPtrById2(info->proto, LIST_FILE, id2)) != NULL) { + JabberLog(info->proto, "step = 4"); + item->ft->hostName = mir_strdup(JabberXmlGetAttrValue(dcng, "pa")); + item->ft->wPort = atoi(JabberXmlGetAttrValue(dcng, "pp")); + JabberForkThread((void (__cdecl *)(void*))TlenNewFileReceiveThread, 0, item->ft); + } + } + + } else if (dc != NULL) { + + } + } +} diff --git a/protocols/Tlen/src/tlen_p2p_old.cpp b/protocols/Tlen/src/tlen_p2p_old.cpp new file mode 100644 index 0000000000..7c1f706d49 --- /dev/null +++ b/protocols/Tlen/src/tlen_p2p_old.cpp @@ -0,0 +1,535 @@ +/* + +Tlen Protocol Plugin for Miranda NG +Copyright (C) 2004-2007 Piotr Piastucki + +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 "tlen_p2p_old.h" +#include +#include +#include +#include +#include "jabber_list.h" + + +void TlenP2PFreeFileTransfer(TLEN_FILE_TRANSFER *ft) +{ + int i; + if (ft->jid) mir_free(ft->jid); + if (ft->iqId) mir_free(ft->iqId); + if (ft->id2) mir_free(ft->id2); + if (ft->hostName) mir_free(ft->hostName); + if (ft->localName) mir_free(ft->localName); + if (ft->szSavePath) mir_free(ft->szSavePath); + if (ft->szDescription) mir_free(ft->szDescription); + if (ft->filesSize) mir_free(ft->filesSize); + if (ft->files) { + for (i=0; ifileCount; i++) { + if (ft->files[i]) mir_free(ft->files[i]); + } + mir_free(ft->files); + } + mir_free(ft); +} + +TLEN_FILE_PACKET *TlenP2PPacketCreate(int datalen) +{ + TLEN_FILE_PACKET *packet; + + if ((packet=(TLEN_FILE_PACKET *) mir_alloc(sizeof(TLEN_FILE_PACKET))) == NULL) + return NULL; + packet->packet = NULL; + if (datalen > 0) { + if ((packet->packet=(char *) mir_alloc(datalen)) == NULL) { + mir_free(packet); + return NULL; + } + } + packet->maxDataLen = datalen; + packet->type=0; + packet->len=0; + return packet; +} + +void TlenP2PPacketFree(TLEN_FILE_PACKET *packet) +{ + if (packet != NULL) { + if (packet->packet != NULL) + mir_free(packet->packet); + mir_free(packet); + } +} + +void TlenP2PPacketSetType(TLEN_FILE_PACKET *packet, DWORD type) +{ + if (packet != NULL) { + packet->type = type; + } +} + +void TlenP2PPacketSetLen(TLEN_FILE_PACKET *packet, DWORD len) +{ + if (packet != NULL) { + packet->len = len; + } +} + +void TlenP2PPacketPackDword(TLEN_FILE_PACKET *packet, DWORD data) +{ + if (packet != NULL && packet->packet != NULL) { + if (packet->len + sizeof(DWORD) <= packet->maxDataLen) { + (*((DWORD*)((packet->packet)+(packet->len)))) = data; + packet->len += sizeof(DWORD); + } + } +} + +void TlenP2PPacketPackBuffer(TLEN_FILE_PACKET *packet, char *buffer, int len) +{ + if (packet != NULL && packet->packet != NULL) { + if (packet->len + len <= packet->maxDataLen) { + memcpy((packet->packet)+(packet->len), buffer, len); + packet->len += len; + } + } +} + +void TlenP2PInit() { +} + +void TlenP2PUninit() { +} + +int TlenP2PPacketSend(JABBER_SOCKET s, TLEN_FILE_PACKET *packet) +{ + DWORD sendResult; + if (packet != NULL && packet->packet != NULL) { + Netlib_Send(s, (char *)&packet->type, 4, MSG_NODUMP); + Netlib_Send(s, (char *)&packet->len, 4, MSG_NODUMP); + sendResult=Netlib_Send(s, packet->packet, packet->len, MSG_NODUMP); + if (sendResult == SOCKET_ERROR || sendResult != packet->len) return 0; + } + return 1; +} + +TLEN_FILE_PACKET* TlenP2PPacketReceive(JABBER_SOCKET s) +{ + TLEN_FILE_PACKET *packet; + DWORD recvResult; + DWORD type, len, pos; + recvResult = Netlib_Recv(s, (char *)&type, 4, MSG_NODUMP); + if (recvResult == 0 || recvResult == SOCKET_ERROR) return NULL; + recvResult = Netlib_Recv(s, (char *)&len, 4, MSG_NODUMP); + if (recvResult == 0 || recvResult == SOCKET_ERROR) return NULL; + packet = TlenP2PPacketCreate(len); + TlenP2PPacketSetType(packet, type); + TlenP2PPacketSetLen(packet, len); + pos = 0; + while (len > 0) { + recvResult = Netlib_Recv(s, packet->packet+pos, len, MSG_NODUMP); + if (recvResult == 0 || recvResult == SOCKET_ERROR) { + TlenP2PPacketFree(packet); + return NULL; + } + len -= recvResult; + pos += recvResult; + } + return packet; +} + +void TlenP2PEstablishOutgoingConnection(TLEN_FILE_TRANSFER *ft, BOOL sendAck) +{ + char *hash; + char str[300]; + TLEN_FILE_PACKET *packet; + TlenProtocol *proto = ft->proto; + + JabberLog(proto, "Establishing outgoing connection."); + ft->state = FT_ERROR; + if ((packet = TlenP2PPacketCreate(2*sizeof(DWORD) + 20)) != NULL) { + TlenP2PPacketSetType(packet, TLEN_FILE_PACKET_CONNECTION_REQUEST); + TlenP2PPacketPackDword(packet, 1); + TlenP2PPacketPackDword(packet, (DWORD) atoi(ft->iqId)); + _snprintf(str, sizeof(str), "%08X%s%d", atoi(ft->iqId), proto->threadData->username, atoi(ft->iqId)); + hash = TlenSha1(str, (int)strlen(str)); + TlenP2PPacketPackBuffer(packet, hash, 20); + mir_free(hash); + TlenP2PPacketSend(ft->s, packet); + TlenP2PPacketFree(packet); + packet = TlenP2PPacketReceive(ft->s); + if (packet != NULL) { + if (packet->type == TLEN_FILE_PACKET_CONNECTION_REQUEST_ACK) { // acknowledge + if ((int)(*((DWORD*)packet->packet)) == atoi(ft->iqId)) { + ft->state = FT_CONNECTING; + if (sendAck) { + ProtoBroadcastAck(proto->m_szModuleName, ft->hContact, ACKTYPE_FILE, ACKRESULT_CONNECTED, ft, 0); + } + } + } + TlenP2PPacketFree(packet); + } + } +} + +TLEN_FILE_TRANSFER* TlenP2PEstablishIncomingConnection(TlenProtocol *proto, JABBER_SOCKET s, JABBER_LIST list, BOOL sendAck) +{ + JABBER_LIST_ITEM *item = NULL; + TLEN_FILE_PACKET *packet; + int i; + char str[300]; + DWORD iqId; + // TYPE: 0x1 + // LEN: + // (DWORD) 0x1 + // (DWORD) id + // (BYTE) hash[20] + packet = TlenP2PPacketReceive(s); + if (packet == NULL || packet->type != TLEN_FILE_PACKET_CONNECTION_REQUEST || packet->len<28) { + if (packet != NULL) { + TlenP2PPacketFree(packet); + } + return NULL; + } + iqId = *((DWORD *)(packet->packet+sizeof(DWORD))); + i = 0; + while ((i=JabberListFindNext(proto, list, i)) >= 0) { + if ((item=JabberListGetItemPtrFromIndex(proto, i)) != NULL) { + _snprintf(str, sizeof(str), "%d", iqId); + if (!strcmp(item->ft->iqId, str)) { + char *hash, *nick; + int j; + nick = JabberNickFromJID(item->ft->jid); + _snprintf(str, sizeof(str), "%08X%s%d", iqId, nick, iqId); + mir_free(nick); + hash = TlenSha1(str, (int)strlen(str)); + for (j=0;j<20;j++) { + if (hash[j] != packet->packet[2*sizeof(DWORD)+j]) break; + } + mir_free(hash); + if (j == 20) break; + } + } + i++; + } + TlenP2PPacketFree(packet); + if (i >=0) { + if ((packet=TlenP2PPacketCreate(sizeof(DWORD))) != NULL) { + // Send connection establishment acknowledgement + TlenP2PPacketSetType(packet, TLEN_FILE_PACKET_CONNECTION_REQUEST_ACK); + TlenP2PPacketPackDword(packet, (DWORD) atoi(item->ft->iqId)); + TlenP2PPacketSend(s, packet); + TlenP2PPacketFree(packet); + item->ft->state = FT_CONNECTING; + if (sendAck) { + ProtoBroadcastAck(item->ft->proto->m_szModuleName, item->ft->hContact, ACKTYPE_FILE, ACKRESULT_CONNECTED, item->ft, 0); + } + return item->ft; + } + } + return NULL; +} + +static void __cdecl TlenFileBindSocks4Thread(TLEN_FILE_TRANSFER* ft) +{ + BYTE buf[8]; + int status; + +// JabberLog("Waiting for the file to be sent via SOCKS..."); + status = Netlib_Recv(ft->s, (char*)buf, 8, MSG_NODUMP); +// JabberLog("accepted connection !!!"); + if ( status == SOCKET_ERROR || status < 8 || buf[1] != 90) { + status = 1; + } else { + status = 0; + } + if (!status) { + ft->pfnNewConnectionV2(ft->s, 0, NULL); + } else { + if (ft->state != FT_SWITCH) { + ft->state = FT_ERROR; + } + } + JabberLog(ft->proto, "Closing connection for this file transfer..."); +// Netlib_CloseHandle(ft->s); + if (ft->hFileEvent != NULL) + SetEvent(ft->hFileEvent); + +} +static void __cdecl TlenFileBindSocks5Thread(TLEN_FILE_TRANSFER* ft) +{ + BYTE buf[256]; + int status; + +// JabberLog("Waiting for the file to be sent via SOCKS..."); + status = Netlib_Recv(ft->s, (char*)buf, sizeof(buf), MSG_NODUMP); +// JabberLog("accepted connection !!!"); + if ( status == SOCKET_ERROR || status < 7 || buf[1] != 0) { + status = 1; + } else { + status = 0; + } + if (!status) { + ft->pfnNewConnectionV2(ft->s, 0, NULL); + } else { + if (ft->state != FT_SWITCH) { + ft->state = FT_ERROR; + } + } +// JabberLog("Closing connection for this file transfer..."); +// Netlib_CloseHandle(ft->s); + if (ft->hFileEvent != NULL) + SetEvent(ft->hFileEvent); + +} + +static JABBER_SOCKET TlenP2PBindSocks4(SOCKSBIND * sb, TLEN_FILE_TRANSFER *ft) +{ //rfc1928 + int len; + BYTE buf[256]; + int status; + struct in_addr in; + NETLIBOPENCONNECTION nloc; + JABBER_SOCKET s; + + nloc.cbSize = NETLIBOPENCONNECTION_V1_SIZE;//sizeof(NETLIBOPENCONNECTION); + nloc.szHost = sb->szHost; + nloc.wPort = sb->wPort; + nloc.flags = 0; + s = (HANDLE) CallService(MS_NETLIB_OPENCONNECTION, (WPARAM) ft->proto->hFileNetlibUser, (LPARAM) &nloc); + if (s == NULL) { +// JabberLog("Connection failed (%d), thread ended", WSAGetLastError()); + return NULL; + } + buf[0] = 4; //socks4 + buf[1] = 2; //2-bind, 1-connect + *(PWORD)(buf+2) = htons(0); // port + *(PDWORD)(buf+4) = INADDR_ANY; + if (sb->useAuth) { + strcpy((char*)buf+8, sb->szUser); + len = (int)strlen(sb->szUser); + } else { + buf[8] = 0; + len = 0; + } + len += 9; + status = Netlib_Send(s, (char*)buf, len, MSG_NODUMP); + if (status == SOCKET_ERROR || status < len) { +// JabberLog("Send failed (%d), thread ended", WSAGetLastError()); + Netlib_CloseHandle(s); + return NULL; + } + status = Netlib_Recv(s, (char*)buf, 8, MSG_NODUMP); + if (status == SOCKET_ERROR || status < 8 || buf[1] != 90) { +// JabberLog("SOCKS4 negotiation failed"); + Netlib_CloseHandle(s); + return NULL; + } + status = Netlib_Recv(s, (char*)buf, sizeof(buf), MSG_NODUMP); + if ( status == SOCKET_ERROR || status < 7 || buf[0] != 5 || buf[1] != 0) { +// JabberLog("SOCKS5 request failed"); + Netlib_CloseHandle(s); + return NULL; + } + in.S_un.S_addr = *(PDWORD)(buf+4); + strcpy(sb->szHost, inet_ntoa(in)); + sb->wPort = htons(*(PWORD)(buf+2)); + ft->s = s; + JabberForkThread((void (__cdecl *)(void*))TlenFileBindSocks4Thread, 0, ft); + return s; +} + +static JABBER_SOCKET TlenP2PBindSocks5(SOCKSBIND * sb, TLEN_FILE_TRANSFER *ft) +{ //rfc1928 + BYTE buf[512]; + int len, status; + NETLIBOPENCONNECTION nloc; + struct in_addr in; + JABBER_SOCKET s; + + nloc.cbSize = NETLIBOPENCONNECTION_V1_SIZE;//sizeof(NETLIBOPENCONNECTION); + nloc.szHost = sb->szHost; + nloc.wPort = sb->wPort; + nloc.flags = 0; + s = (HANDLE) CallService(MS_NETLIB_OPENCONNECTION, (WPARAM) ft->proto->hFileNetlibUser, (LPARAM) &nloc); + if (s == NULL) { + JabberLog(ft->proto, "Connection failed (%d), thread ended", WSAGetLastError()); + return NULL; + } + buf[0] = 5; //yep, socks5 + buf[1] = 1; //one auth method + buf[2] = sb->useAuth?2:0; // authorization + status = Netlib_Send(s, (char*)buf, 3, MSG_NODUMP); + if (status == SOCKET_ERROR || status < 3) { + JabberLog(ft->proto, "Send failed (%d), thread ended", WSAGetLastError()); + Netlib_CloseHandle(s); + return NULL; + } + status = Netlib_Recv(s, (char*)buf, 2, MSG_NODUMP); + if (status == SOCKET_ERROR || status < 2 || (buf[1] != 0 && buf[1] != 2)) { + JabberLog(ft->proto, "SOCKS5 negotiation failed"); + Netlib_CloseHandle(s); + return NULL; + } + if (buf[1] == 2) { //rfc1929 + int nUserLen, nPassLen; + PBYTE pAuthBuf; + + nUserLen = (int)strlen(sb->szUser); + nPassLen = (int)strlen(sb->szPassword); + pAuthBuf = (PBYTE)mir_alloc(3+nUserLen+nPassLen); + pAuthBuf[0] = 1; //auth version + pAuthBuf[1] = nUserLen; + memcpy(pAuthBuf+2, sb->szUser, nUserLen); + pAuthBuf[2+nUserLen]=nPassLen; + memcpy(pAuthBuf+3+nUserLen,sb->szPassword,nPassLen); + status = Netlib_Send(s, (char*)pAuthBuf, 3+nUserLen+nPassLen, MSG_NODUMP); + mir_free(pAuthBuf); + if (status == SOCKET_ERROR || status < 3 + nUserLen+nPassLen) { + JabberLog(ft->proto, "Send failed (%d), thread ended", WSAGetLastError()); + Netlib_CloseHandle(s); + return NULL; + } + status = Netlib_Recv(s, (char*)buf, sizeof(buf), MSG_NODUMP); + if (status == SOCKET_ERROR || status < 2 || buf[1] != 0) { + JabberLog(ft->proto, "SOCKS5 sub-negotiation failed"); + Netlib_CloseHandle(s); + return NULL; + } + } + + { PBYTE pInit; + int nHostLen=4; + DWORD hostIP=INADDR_ANY; + pInit=(PBYTE)mir_alloc(6+nHostLen); + pInit[0]=5; //SOCKS5 + pInit[1]=2; //bind + pInit[2]=0; //reserved + pInit[3]=1; + *(PDWORD)(pInit+4)=hostIP; + *(PWORD)(pInit+4+nHostLen)=htons(0); + status = Netlib_Send(s, (char*)pInit, 6+nHostLen, MSG_NODUMP); + mir_free(pInit); + if (status == SOCKET_ERROR || status < 6 + nHostLen) { +// JabberLog("Send failed (%d), thread ended", WSAGetLastError()); + Netlib_CloseHandle(s); + return NULL; + } + } + status = Netlib_Recv(s, (char*)buf, sizeof(buf), MSG_NODUMP); + if ( status == SOCKET_ERROR || status < 7 || buf[0] != 5 || buf[1] != 0) { +// JabberLog("SOCKS5 request failed"); + Netlib_CloseHandle(s); + return NULL; + } + if (buf[2] == 1) { // domain + len = buf[4]; + memcpy(sb->szHost, buf+5, len); + sb->szHost[len]=0; + len += 4; + } else { // ip address + in.S_un.S_addr = *(PDWORD)(buf+4); + strcpy(sb->szHost, inet_ntoa(in)); + len = 8; + } + sb->wPort = htons(*(PWORD)(buf+len)); + ft->s = s; + + JabberForkThread((void (__cdecl *)(void*))TlenFileBindSocks5Thread, 0, ft); + return s; +} + + +JABBER_SOCKET TlenP2PListen(TLEN_FILE_TRANSFER *ft) +{ + NETLIBBIND nlb = {0}; + JABBER_SOCKET s = NULL; + int useProxy; + DBVARIANT dbv; + SOCKSBIND sb; + struct in_addr in; + TlenProtocol *proto = ft->proto; + useProxy=0; + if (ft->localName != NULL) mir_free(ft->localName); + ft->localName = NULL; + ft->wPort = 0; + if (DBGetContactSettingByte(NULL, proto->m_szModuleName, "UseFileProxy", FALSE)) { + if (!DBGetContactSetting(NULL, proto->m_szModuleName, "FileProxyHost", &dbv)) { + strcpy(sb.szHost, dbv.pszVal); + DBFreeVariant(&dbv); + sb.wPort = DBGetContactSettingWord(NULL, proto->m_szModuleName, "FileProxyPort", 0); + sb.useAuth = FALSE; + strcpy(sb.szUser, ""); + strcpy(sb.szPassword, ""); + if (DBGetContactSettingByte(NULL, proto->m_szModuleName, "FileProxyAuth", FALSE)) { + sb.useAuth = TRUE; + if (!DBGetContactSetting(NULL, proto->m_szModuleName, "FileProxyUsername", &dbv)) { + strcpy(sb.szUser, dbv.pszVal); + DBFreeVariant(&dbv); + } + if (!DBGetContactSetting(NULL, proto->m_szModuleName, "FileProxyPassword", &dbv)) { + CallService(MS_DB_CRYPT_DECODESTRING, strlen(dbv.pszVal)+1, (LPARAM) dbv.pszVal); + strcpy(sb.szPassword, dbv.pszVal); + DBFreeVariant(&dbv); + } + } + switch (DBGetContactSettingWord(NULL, proto->m_szModuleName, "FileProxyType", 0)) { + case 0: // forwarding + useProxy = 1; + break; + case 1: // socks4 + s = TlenP2PBindSocks4(&sb, ft); + useProxy = 2; + break; + case 2: // socks5 + s = TlenP2PBindSocks5(&sb, ft); + useProxy = 2; + break; + } + ft->localName = mir_strdup(sb.szHost); + ft->wPort = sb.wPort; + ft->wLocalPort = sb.wPort; + } + } + if (useProxy<2) { + nlb.cbSize = sizeof(NETLIBBIND); + nlb.pfnNewConnectionV2 = ft->pfnNewConnectionV2; + nlb.wPort = 0; // Use user-specified incoming port ranges, if available + nlb.pExtra = proto; + JabberLog(ft->proto, "Calling MS_NETLIB_BINDPORT"); + s = (HANDLE) CallService(MS_NETLIB_BINDPORT, (WPARAM) ft->proto->hNetlibUser, (LPARAM) &nlb); + JabberLog(ft->proto, "listening on %d",s); + } + if (useProxy == 0) { + in.S_un.S_addr = htonl(nlb.dwExternalIP); + ft->localName = mir_strdup(inet_ntoa(in)); + ft->wPort = nlb.wPort; + ft->wLocalPort = nlb.wExPort; + } + if (s != NULL) { +// listenCount++; + } + return s; +} + +void TlenP2PStopListening(JABBER_SOCKET s) { + if (s != NULL) { +// listenCount--; +// if (listenCount <= 0) { +// Netlib_CloseHandle(s); +// } + } +} diff --git a/protocols/Tlen/src/tlen_p2p_old.h b/protocols/Tlen/src/tlen_p2p_old.h new file mode 100644 index 0000000000..4e2305310f --- /dev/null +++ b/protocols/Tlen/src/tlen_p2p_old.h @@ -0,0 +1,70 @@ +/* + +Tlen Protocol Plugin for Miranda NG +Copyright (C) 2004-2007 Piotr Piastucki + +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" + +#ifndef _TLEN_P2P_OLD_H_ +#define _TLEN_P2P_OLD_H_ + +enum { + TLEN_FILE_PACKET_CONNECTION_REQUEST = 0x01, + TLEN_FILE_PACKET_CONNECTION_REQUEST_ACK = 0x02, + TLEN_FILE_PACKET_FILE_LIST = 0x32, + TLEN_FILE_PACKET_FILE_LIST_ACK = 0x33, + TLEN_FILE_PACKET_FILE_REQUEST = 0x34, + TLEN_FILE_PACKET_FILE_DATA = 0x35, + TLEN_FILE_PACKET_END_OF_FILE = 0x37, + TLEN_VOICE_PACKET = 0x96 +}; + +typedef struct { + unsigned int maxDataLen; + char *packet; + DWORD type; + DWORD len; +} TLEN_FILE_PACKET; + +typedef struct { + char szHost[256]; + int wPort; + int useAuth; + char szUser[256]; + char szPassword[256]; +}SOCKSBIND; + +extern void TlenP2PFreeFileTransfer(TLEN_FILE_TRANSFER *ft); +extern TLEN_FILE_PACKET *TlenP2PPacketCreate(int datalen); +extern void TlenP2PPacketFree(TLEN_FILE_PACKET *packet); +extern void TlenP2PPacketSetType(TLEN_FILE_PACKET *packet, DWORD type); +extern void TlenP2PPacketSetLen(TLEN_FILE_PACKET *packet, DWORD len); +extern void TlenP2PPacketPackDword(TLEN_FILE_PACKET *packet, DWORD data); +extern void TlenP2PPacketPackBuffer(TLEN_FILE_PACKET *packet, char *buffer, int len); +extern int TlenP2PPacketSend(JABBER_SOCKET s, TLEN_FILE_PACKET *packet); +extern TLEN_FILE_PACKET* TlenP2PPacketReceive(JABBER_SOCKET s); +extern void TlenP2PEstablishOutgoingConnection(TLEN_FILE_TRANSFER *ft, BOOL sendAck); +extern TLEN_FILE_TRANSFER* TlenP2PEstablishIncomingConnection(TlenProtocol *proto, JABBER_SOCKET s, JABBER_LIST list, BOOL sendAck); +extern JABBER_SOCKET TlenP2PListen(TLEN_FILE_TRANSFER *ft); +extern void TlenP2PStopListening(JABBER_SOCKET s); + +void __cdecl TlenProcessP2P(XmlNode *node, void *userdata); + + +#endif diff --git a/protocols/Tlen/src/tlen_picture.cpp b/protocols/Tlen/src/tlen_picture.cpp new file mode 100644 index 0000000000..1120b23839 --- /dev/null +++ b/protocols/Tlen/src/tlen_picture.cpp @@ -0,0 +1,320 @@ +/* + +Tlen Protocol Plugin for Miranda NG +Copyright (C) 2002-2004 Santithorn Bunchua +Copyright (C) 2004-2009 Piotr Piastucki + +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_list.h" +#include "tlen_file.h" +#include "tlen_p2p_old.h" + +typedef struct { + TlenProtocol *proto; + JABBER_LIST_ITEM *item; +} TLENPSREQUESTTHREADDATA; + +static void LogPictureMessage(TlenProtocol *proto, const char *jid, const char *filename, BOOL isSent) +{ + char message[1024]; + const char *msg = isSent ? "Image sent file://%s" : "Image received file://%s"; + _snprintf(message, sizeof(message), Translate(msg), filename); + TlenLogMessage(proto, JabberHContactFromJID(proto, jid), isSent ? DBEF_SENT : 0, message); +} + +static void TlenPsPostThread(void *ptr) { + TLENPSREQUESTTHREADDATA *data = (TLENPSREQUESTTHREADDATA *)ptr; + TlenProtocol *proto = data->proto; + JABBER_LIST_ITEM *item = data->item; + JABBER_SOCKET socket = JabberWsConnect(proto, "ps.tlen.pl", 443); + BOOL bSent = FALSE; + if (socket != NULL) { + char header[512]; + DWORD ret; + item->ft->s = socket; + item->ft->hFileEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + _snprintf(header, sizeof(header), "", proto->threadData->username, item->ft->jid, item->ft->fileTotalSize, item->jid); + JabberWsSend(proto, socket, header, (int)strlen(header)); + ret = WaitForSingleObject(item->ft->hFileEvent, 1000 * 60 * 5); + if (ret == WAIT_OBJECT_0) { + FILE *fp = fopen( item->ft->files[0], "rb" ); + if (fp) { + int i; + char header[512]; + char fileBuffer[2048]; + _snprintf(header, sizeof(header), "", item->ft->iqId, item->jid); + JabberWsSend(proto, socket, header, (int)strlen(header)); + JabberLog(proto, "Sending picture data..."); + for (i = item->ft->filesSize[0]; i > 0; ) { + int toread = min(2048, i); + int readcount = (int)fread(fileBuffer, (size_t)1, (size_t)toread, fp); + i -= readcount; + if (readcount > 0) { + JabberWsSend(proto, socket, fileBuffer, readcount); + } + if (toread != readcount) { + break; + } + } + fclose(fp); + SleepEx(3000, TRUE); + bSent = TRUE; + } else { + /* picture not found */ + } + } else { + /* 5 minutes passed */ + } + Netlib_CloseHandle(socket); + if (bSent) { + JabberSend(proto, "", item->ft->jid, item->jid, item->ft->id2); + LogPictureMessage(proto, item->ft->jid, item->ft->files[0], TRUE); + } + TlenP2PFreeFileTransfer(item->ft); + JabberListRemove(proto, LIST_PICTURE, item->jid); + } else { + /* cannot connect to ps server */ + } + mir_free(data); +} + +static void TlenPsPost(TlenProtocol *proto, JABBER_LIST_ITEM *item) { + TLENPSREQUESTTHREADDATA *threadData = (TLENPSREQUESTTHREADDATA *)mir_alloc(sizeof(TLENPSREQUESTTHREADDATA)); + threadData->proto = proto; + threadData->item = item; + JabberForkThread(TlenPsPostThread, 0, threadData); +} + +static void TlenPsGetThread(void *ptr) { + TLENPSREQUESTTHREADDATA *data = (TLENPSREQUESTTHREADDATA *)ptr; + TlenProtocol *proto = data->proto; + JABBER_LIST_ITEM *item = data->item; + FILE *fp; + fp = fopen( item->ft->files[0], "wb" ); + if (fp) { + JABBER_SOCKET socket = JabberWsConnect(proto, "ps.tlen.pl", 443); + if (socket != NULL) { + XmlState xmlState; + char header[512]; + char fileBuffer[2048]; + JabberXmlInitState(&xmlState); + _snprintf(header, sizeof(header), "", proto->threadData->username, item->ft->jid, item->jid, item->ft->id2); + JabberWsSend(proto, socket, header, (int)strlen(header)); + JabberLog(proto, "Reveiving picture data..."); + { + int totalcount = 0; + int size = item->ft->filesSize[0]; + BOOL bHeader = TRUE; + while (TRUE) { + int readcount = JabberWsRecv(proto, socket, fileBuffer, 2048 - totalcount); + if (readcount == 0) { + break; + } + totalcount += readcount; + if (bHeader) { + char * tagend = (char*)memchr(fileBuffer, '/', totalcount); + tagend = (char*)memchr(tagend + 1, '>', totalcount - (tagend - fileBuffer) - 1); + if (tagend != NULL) { + int parsed = JabberXmlParse(&xmlState, fileBuffer, tagend - fileBuffer + 1); + if (parsed == 0) { + continue; + } + bHeader = FALSE; + totalcount -= parsed; + memmove(fileBuffer, fileBuffer+parsed, totalcount); + } + } + if (!bHeader) { + if (totalcount > 0) { + fwrite(fileBuffer, 1, totalcount, fp); + size -= totalcount; + totalcount = 0; + } + if (size == 0) { + break; + } + } + } + } + Netlib_CloseHandle(socket); + JabberLog(proto, "Picture received..."); + LogPictureMessage(proto, item->ft->jid, item->ft->files[0], FALSE); + } else { + /* cannot connect to ps server */ + } + fclose(fp); + } else { + /* cannot create file */ + } + TlenP2PFreeFileTransfer(item->ft); + JabberListRemove(proto, LIST_PICTURE, item->jid); + mir_free(data); +} + +static void TlenPsGet(TlenProtocol *proto, JABBER_LIST_ITEM *item) { + TLENPSREQUESTTHREADDATA *threadData = (TLENPSREQUESTTHREADDATA *)mir_alloc(sizeof(TLENPSREQUESTTHREADDATA)); + threadData->proto = proto; + threadData->item = item; + JabberForkThread(TlenPsGetThread, 0, threadData); +} + +void TlenProcessPic(XmlNode *node, TlenProtocol *proto) { + JABBER_LIST_ITEM *item = NULL; + char *crc, *crc_c, *idt, *size, *from, *fromRaw, *rt; + from = JabberXmlGetAttrValue(node, "from"); + fromRaw = JabberLoginFromJID(from); + idt = JabberXmlGetAttrValue(node, "idt"); + size = JabberXmlGetAttrValue(node, "size"); + crc_c = JabberXmlGetAttrValue(node, "crc_c"); + crc = JabberXmlGetAttrValue(node, "crc"); + rt = JabberXmlGetAttrValue(node, "rt"); + if (idt != NULL) { + item = JabberListGetItemPtr(proto, LIST_PICTURE, idt); + } + if (item != NULL) { + if (!strcmp(from, "ps")) { + char *st = JabberXmlGetAttrValue(node, "st"); + if (st != NULL) { + item->ft->iqId = mir_strdup(st); + item->ft->id2 = mir_strdup(rt); + if (item->ft->hFileEvent != NULL) { + SetEvent(item->ft->hFileEvent); + item->ft->hFileEvent = NULL; + } + } + } else if (!strcmp(item->ft->jid, fromRaw)) { + if (crc_c != NULL) { + if (!strcmp(crc_c, "n")) { + /* crc_c = n, picture transfer accepted */ + TlenPsPost(proto, item); + } else if (!strcmp(crc_c, "f")) { + /* crc_c = f, picture cached, no need to transfer again */ + LogPictureMessage(proto, item->ft->jid, item->ft->files[0], TRUE); + TlenP2PFreeFileTransfer(item->ft); + JabberListRemove(proto, LIST_PICTURE, idt); + } + } else if (rt != NULL) { + item->ft->id2 = mir_strdup(rt); + TlenPsGet(proto, item); + } + } + } else if (crc != NULL) { + BOOL bAccept = proto->tlenOptions.imagePolicy == TLEN_IMAGES_ACCEPT_ALL || (proto->tlenOptions.imagePolicy == TLEN_IMAGES_IGNORE_NIR && IsAuthorized(proto, from)); + if (bAccept) { + FILE* fp; + char fileName[MAX_PATH]; + char *ext = JabberXmlGetAttrValue(node, "ext"); + char *tmpPath = Utils_ReplaceVars( "%miranda_userdata%" ); + int tPathLen = mir_snprintf( fileName, MAX_PATH, "%s\\Images\\Tlen", tmpPath ); + long oldSize = 0, lSize = atol(size); + DWORD dwAttributes = GetFileAttributesA( fileName ); + if ( dwAttributes == 0xffffffff || ( dwAttributes & FILE_ATTRIBUTE_DIRECTORY ) == 0 ) { + CallService( MS_UTILS_CREATEDIRTREE, 0, ( LPARAM )fileName ); + } + mir_free(tmpPath); + fileName[ tPathLen++ ] = '\\'; + mir_snprintf( fileName + tPathLen, MAX_PATH - tPathLen, "%s.%s", crc, ext ); + fp = fopen( fileName, "rb" ); + if (fp) { + fseek(fp, 0, SEEK_END); + oldSize = ftell(fp); + fclose(fp); + } + if (oldSize != lSize) { + item = JabberListAdd(proto, LIST_PICTURE, idt); + item->ft = TlenFileCreateFT(proto, from); + item->ft->files = (char **) mir_alloc(sizeof(char *)); + item->ft->filesSize = (long *) mir_alloc(sizeof(long)); + item->ft->files[0] = mir_strdup(fileName); + item->ft->filesSize[0] = lSize; + item->ft->fileTotalSize = item->ft->filesSize[0]; + JabberSend(proto, "", from, idt); + } else { + JabberSend(proto, "", from, idt); + LogPictureMessage(proto, from, fileName, FALSE); + } + } + } + mir_free(fromRaw); +} + +BOOL SendPicture(TlenProtocol *proto, HANDLE hContact) { + DBVARIANT dbv; + if (!DBGetContactSetting(hContact, proto->m_szModuleName, "jid", &dbv)) { + char *jid = dbv.pszVal; + char szFilter[512]; + char *szFileName = (char*) mir_alloc(_MAX_PATH); + OPENFILENAMEA ofn = {0}; + CallService( MS_UTILS_GETBITMAPFILTERSTRINGS, ( WPARAM ) sizeof( szFilter ), ( LPARAM )szFilter ); + ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400; + ofn.hwndOwner = NULL; + ofn.lpstrFilter = szFilter; + ofn.lpstrCustomFilter = NULL; + ofn.lpstrFile = szFileName; + ofn.nMaxFile = _MAX_PATH; + ofn.Flags = OFN_FILEMUSTEXIST; + szFileName[0] = '\0'; + if ( GetOpenFileNameA( &ofn )) { + long size; + FILE* fp = fopen( szFileName, "rb" ); + if (fp) { + fseek(fp, 0, SEEK_END); + size = ftell(fp); + if (size > 0 && size < 256*1024) { + JABBER_LIST_ITEM *item; + mir_sha1_ctx sha; + DWORD digest[5]; + int i; + char idStr[10]; + char fileBuffer[2048]; + int id = JabberSerialNext(proto); + _snprintf(idStr, sizeof(idStr), "%d", id); + item = JabberListAdd(proto, LIST_PICTURE, idStr); + item->ft = TlenFileCreateFT(proto, jid); + item->ft->files = (char **) mir_alloc(sizeof(char *)); + item->ft->filesSize = (long *) mir_alloc(sizeof(long)); + item->ft->files[0] = szFileName; + item->ft->filesSize[0] = size; + item->ft->fileTotalSize = size; + fseek(fp, 0, SEEK_SET); + mir_sha1_init( &sha ); + for (i = item->ft->filesSize[0]; i > 0; ) { + int toread = min(2048, i); + int readcount = (int)fread(fileBuffer, (size_t)1, (size_t)toread, fp); + i -= readcount; + if (readcount > 0) { + mir_sha1_append( &sha, (mir_sha1_byte_t* )fileBuffer, readcount); + } + if (toread != readcount) { + break; + } + } + mir_sha1_finish( &sha, (mir_sha1_byte_t* )digest ); + JabberSend(proto, "", jid, + (int)htonl(digest[0]), (int)htonl(digest[1]), (int)htonl(digest[2]), (int)htonl(digest[3]), (int)htonl(digest[4]), idStr, item->ft->filesSize[0], "jpg"); + } else { + /* file too big */ + } + fclose(fp); + } + } + DBFreeVariant(&dbv); + } + return FALSE; +} diff --git a/protocols/Tlen/src/tlen_picture.h b/protocols/Tlen/src/tlen_picture.h new file mode 100644 index 0000000000..ef98b02405 --- /dev/null +++ b/protocols/Tlen/src/tlen_picture.h @@ -0,0 +1,33 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Tlen Protocol Plugin for Miranda NG +Copyright (C) 2002-2004 Santithorn Bunchua +Copyright (C) 2004-2009 Piotr Piastucki + +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. + +*/ +#ifndef _TLEN_PICTURE_H +#define _TLEN_PICTURE_H + +#include +#include "jabber.h" + +void TlenProcessPic(XmlNode *node, TlenProtocol *proto); +BOOL SendPicture(TlenProtocol *, HANDLE hContact); + +#endif /* _TLEN_PICTURE_H */ + diff --git a/protocols/Tlen/src/tlen_presence.cpp b/protocols/Tlen/src/tlen_presence.cpp new file mode 100644 index 0000000000..7dc15f41f6 --- /dev/null +++ b/protocols/Tlen/src/tlen_presence.cpp @@ -0,0 +1,318 @@ +/* + +Tlen Protocol Plugin for Miranda NG +Copyright (C) 2002-2004 Santithorn Bunchua +Copyright (C) 2004-2009 Piotr Piastucki + +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_list.h" +#include "tlen_avatar.h" + +void TlenProcessPresence(XmlNode *node, TlenProtocol *proto) +{ + HANDLE hContact; + XmlNode *showNode, *statusNode; + JABBER_LIST_ITEM *item; + char *from, *type, *nick, *show; + int status, laststatus = ID_STATUS_OFFLINE; + char *p; + + if ((from=JabberXmlGetAttrValue(node, "from")) != NULL) { + if (JabberListExist(proto, LIST_CHATROOM, from)); //JabberGroupchatProcessPresence(node, userdata); + + else { + type = JabberXmlGetAttrValue(node, "type"); + item = JabberListGetItemPtr(proto, LIST_ROSTER, from); + if (item != NULL) { + if (proto->tlenOptions.enableAvatars) { + TlenProcessPresenceAvatar(proto, node, item); + } + } + if (type == NULL || (!strcmp(type, "available"))) { + if ((nick=JabberLocalNickFromJID(from)) != NULL) { + if ((hContact=JabberHContactFromJID(proto, from)) == NULL) + hContact = JabberDBCreateContact(proto, from, nick, FALSE); + if (!JabberListExist(proto, LIST_ROSTER, from)) { + JabberLog(proto, "Receive presence online from %s (who is not in my roster)", from); + JabberListAdd(proto, LIST_ROSTER, from); + } + status = ID_STATUS_ONLINE; + if ((showNode=JabberXmlGetChild(node, "show")) != NULL) { + if ((show=showNode->text) != NULL) { + if (!strcmp(show, "away")) status = ID_STATUS_AWAY; + else if (!strcmp(show, "xa")) status = ID_STATUS_NA; + else if (!strcmp(show, "dnd")) status = ID_STATUS_DND; + else if (!strcmp(show, "chat")) status = ID_STATUS_FREECHAT; + else if (!strcmp(show, "unavailable")) { + // Always show invisible (on old Tlen client) as invisible (not offline) + status = ID_STATUS_OFFLINE; + } + } + } + + statusNode = JabberXmlGetChild(node, "status"); + if (statusNode) + p = JabberTextDecode(statusNode->text); + else + p = NULL; + JabberListAddResource(proto, LIST_ROSTER, from, status, statusNode?p:NULL); + if (p) { + DBWriteContactSettingString(hContact, "CList", "StatusMsg", p); + mir_free(p); + } else { + DBDeleteContactSetting(hContact, "CList", "StatusMsg"); + } + // Determine status to show for the contact and request version information + if (item != NULL) { + laststatus = item->status; + item->status = status; + } + if (strchr(from, '@') != NULL || DBGetContactSettingByte(NULL, proto->m_szModuleName, "ShowTransport", TRUE) == TRUE) { + if (DBGetContactSettingWord(hContact, proto->m_szModuleName, "Status", ID_STATUS_OFFLINE) != status) + DBWriteContactSettingWord(hContact, proto->m_szModuleName, "Status", (WORD) status); + } + if (item != NULL) { + if (!item->infoRequested) { + int iqId = JabberSerialNext(proto); + item->infoRequested = TRUE; + JabberSend( proto, "", iqId, from); + } + if (proto->tlenOptions.enableVersion && !item->versionRequested) { + item->versionRequested = TRUE; + if (proto->m_iStatus != ID_STATUS_INVISIBLE) { + JabberSend( proto, "", from ); + } + } + } + JabberLog(proto, "%s (%s) online, set contact status to %d", nick, from, status); + mir_free(nick); + } + } + else if (!strcmp(type, "unavailable")) { + if (!JabberListExist(proto, LIST_ROSTER, from)) { + JabberLog(proto, "Receive presence offline from %s (who is not in my roster)", from); + JabberListAdd(proto, LIST_ROSTER, from); + } + else { + JabberListRemoveResource(proto, LIST_ROSTER, from); + } + status = ID_STATUS_OFFLINE; + statusNode = JabberXmlGetChild(node, "status"); + if (statusNode) { + if (proto->tlenOptions.offlineAsInvisible) { + status = ID_STATUS_INVISIBLE; + } + p = JabberTextDecode(statusNode->text); + JabberListAddResource(proto, LIST_ROSTER, from, status, p); + if ((hContact=JabberHContactFromJID(proto, from)) != NULL) { + if (p) { + DBWriteContactSettingString(hContact, "CList", "StatusMsg", p); + } else { + DBDeleteContactSetting(hContact, "CList", "StatusMsg"); + } + } + if (p) mir_free(p); + } + if ((item=JabberListGetItemPtr(proto, LIST_ROSTER, from)) != NULL) { + // Determine status to show for the contact based on the remaining resources + item->status = status; + item->versionRequested = FALSE; + item->infoRequested = FALSE; + } + if ((hContact=JabberHContactFromJID(proto, from)) != NULL) { + if (strchr(from, '@') != NULL || DBGetContactSettingByte(NULL, proto->m_szModuleName, "ShowTransport", TRUE) == TRUE) { + if (DBGetContactSettingWord(hContact, proto->m_szModuleName, "Status", ID_STATUS_OFFLINE) != status) + DBWriteContactSettingWord(hContact, proto->m_szModuleName, "Status", (WORD) status); + } + if (item != NULL && item->isTyping) { + item->isTyping = FALSE; + CallService(MS_PROTO_CONTACTISTYPING, (WPARAM) hContact, PROTOTYPE_CONTACTTYPING_OFF); + } + JabberLog(proto, "%s offline, set contact status to %d", from, status); + } + } + else if (!strcmp(type, "subscribe")) { + if (strchr(from, '@') == NULL) { + // automatically send authorization allowed to agent/transport + JabberSend(proto, "", from); + } + else if ((nick=JabberNickFromJID(from)) != NULL) { + JabberLog(proto, "%s (%s) requests authorization", nick, from); + JabberDBAddAuthRequest(proto, from, nick); + mir_free(nick); + } + } + else if (!strcmp(type, "subscribed")) { + if ((item=JabberListGetItemPtr(proto, LIST_ROSTER, from)) != NULL) { + if (item->subscription == SUB_FROM) item->subscription = SUB_BOTH; + else if (item->subscription == SUB_NONE) { + item->subscription = SUB_TO; + } + } + } + } + } +} + +static void JabberSendPresenceTo(TlenProtocol *proto, int status, char *to) +{ + char *showBody, *statusMsg, *presenceType; + char *ptr = NULL; + + if (!proto->isOnline) return; + + // Send update for status (we won't handle ID_STATUS_OFFLINE here) + // Note: jabberModeMsg is already encoded using JabberTextEncode() + EnterCriticalSection(&proto->modeMsgMutex); + + showBody = NULL; + statusMsg = NULL; + presenceType = NULL; + switch (status) { + case ID_STATUS_ONLINE: + showBody = "available"; + statusMsg = proto->modeMsgs.szOnline; + break; + case ID_STATUS_AWAY: + case ID_STATUS_ONTHEPHONE: + case ID_STATUS_OUTTOLUNCH: + showBody = "away"; + statusMsg = proto->modeMsgs.szAway; + break; + case ID_STATUS_NA: + showBody = "xa"; + statusMsg = proto->modeMsgs.szNa; + break; + case ID_STATUS_DND: + case ID_STATUS_OCCUPIED: + showBody = "dnd"; + statusMsg = proto->modeMsgs.szDnd; + break; + case ID_STATUS_FREECHAT: + showBody = "chat"; + statusMsg = proto->modeMsgs.szFreechat; + break; + case ID_STATUS_INVISIBLE: + presenceType = "invisible"; + statusMsg = proto->modeMsgs.szInvisible; + break; + case ID_STATUS_OFFLINE: + presenceType = "unavailable"; + if (DBGetContactSettingByte(NULL, proto->m_szModuleName, "LeaveOfflineMessage", FALSE)) { + int offlineMessageOption = DBGetContactSettingWord(NULL, proto->m_szModuleName, "OfflineMessageOption", 0); + if (offlineMessageOption == 0) { + switch (proto->m_iStatus) { + case ID_STATUS_ONLINE: + ptr = mir_strdup(proto->modeMsgs.szOnline); + break; + case ID_STATUS_AWAY: + case ID_STATUS_ONTHEPHONE: + case ID_STATUS_OUTTOLUNCH: + ptr = mir_strdup(proto->modeMsgs.szAway); + break; + case ID_STATUS_NA: + ptr = mir_strdup(proto->modeMsgs.szNa); + break; + case ID_STATUS_DND: + case ID_STATUS_OCCUPIED: + ptr = mir_strdup(proto->modeMsgs.szDnd); + break; + case ID_STATUS_FREECHAT: + ptr = mir_strdup(proto->modeMsgs.szFreechat); + break; + case ID_STATUS_INVISIBLE: + ptr = mir_strdup(proto->modeMsgs.szInvisible); + break; + } + } else if (offlineMessageOption == 99) { + + } else if (offlineMessageOption < 7) { + DBVARIANT dbv; + const char *statusNames[] = {"OnDefault", "AwayDefault", "NaDefault", "DndDefault", "FreeChatDefault", "InvDefault"}; + if (!DBGetContactSetting(NULL, "SRAway", statusNames[offlineMessageOption-1], &dbv)) { + int i; + char substituteStr[128]; + ptr = mir_strdup(dbv.pszVal); + DBFreeVariant(&dbv); + for (i=0;ptr[i];i++) { + if (ptr[i] != '%') continue; + if (!_strnicmp(ptr+i,"%time%",6)) + GetTimeFormatA(LOCALE_USER_DEFAULT,TIME_NOSECONDS,NULL,NULL,substituteStr,sizeof(substituteStr)); + else if (!_strnicmp(ptr+i,"%date%",6)) + GetDateFormatA(LOCALE_USER_DEFAULT,DATE_SHORTDATE,NULL,NULL,substituteStr,sizeof(substituteStr)); + else continue; + if (strlen(substituteStr)>6) ptr=(char*)mir_realloc(ptr,strlen(ptr)+1+strlen(substituteStr)-6); + MoveMemory(ptr+i+strlen(substituteStr),ptr+i+6,strlen(ptr)-i-5); + CopyMemory(ptr+i,substituteStr,strlen(substituteStr)); + } + } + } + } + statusMsg = ptr; + break; + default: + // Should not reach here + break; + } + proto->m_iStatus = status; + if (presenceType) { + if (statusMsg) + JabberSend(proto, "%s", presenceType, statusMsg); + else + JabberSend(proto, "", presenceType); + } else { + if (statusMsg) + JabberSend(proto, "%s%s", showBody, statusMsg); + else + JabberSend(proto, "%s", showBody); + } + if (ptr) { + mir_free(ptr); + } + LeaveCriticalSection(&proto->modeMsgMutex); +} + + + +void JabberSendPresence(TlenProtocol *proto, int statusIn) +{ + int statusOut; + switch (statusIn) { + case ID_STATUS_ONLINE: + case ID_STATUS_OFFLINE: + case ID_STATUS_NA: + case ID_STATUS_FREECHAT: + case ID_STATUS_INVISIBLE: + statusOut = statusIn; + break; + case ID_STATUS_AWAY: + case ID_STATUS_ONTHEPHONE: + case ID_STATUS_OUTTOLUNCH: + default: + statusOut = ID_STATUS_AWAY; + break; + case ID_STATUS_DND: + case ID_STATUS_OCCUPIED: + statusOut = ID_STATUS_DND; + break; + } + JabberSendPresenceTo(proto, statusOut, NULL); +} + + diff --git a/protocols/Tlen/src/tlen_presence.h b/protocols/Tlen/src/tlen_presence.h new file mode 100644 index 0000000000..caf92ddab5 --- /dev/null +++ b/protocols/Tlen/src/tlen_presence.h @@ -0,0 +1,29 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Tlen Protocol Plugin for Miranda NG +Copyright (C) 2002-2004 Santithorn Bunchua +Copyright (C) 2004-2009 Piotr Piastucki + +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. + +*/ +#ifndef _TLEN_PRESENCE_H +#define _TLEN_PRESENCE_H + +void TlenProcessPresence(XmlNode *node, TlenProtocol *proto); + +#endif /* _TLEN_PRESENCE_H */ + diff --git a/protocols/Tlen/src/tlen_userinfo.cpp b/protocols/Tlen/src/tlen_userinfo.cpp new file mode 100644 index 0000000000..38463f746c --- /dev/null +++ b/protocols/Tlen/src/tlen_userinfo.cpp @@ -0,0 +1,335 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Tlen Protocol Plugin for Miranda NG +Copyright (C) 2002-2004 Santithorn Bunchua +Copyright (C) 2004-2007 Piotr Piastucki + +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 +#include +#include +#include +#include +#include "jabber_list.h" +#include "resource.h" +#include "tlen_avatar.h" + +JABBER_FIELD_MAP tlenFieldGender[] = { + { 1, _T("Male") }, + { 2, _T("Female") }, + { 0, NULL } +}; +JABBER_FIELD_MAP tlenFieldLookfor[] = { + { 1, _T("Somebody to talk") }, + { 2, _T("Friendship") }, + { 3, _T("Flirt/romance") }, + { 4, _T("Love") }, + { 5, _T("Nothing") }, + { 0, NULL } +}; +JABBER_FIELD_MAP tlenFieldStatus[] = { + { 1, _T("All") }, + { 2, _T("Available") }, + { 3, _T("Free for chat") }, + { 0, NULL } +}; +JABBER_FIELD_MAP tlenFieldOccupation[] = { + { 1, _T("Student") }, + { 2, _T("College student") }, + { 3, _T("Farmer") }, + { 4, _T("Manager") }, + { 5, _T("Specialist") }, + { 6, _T("Clerk") }, + { 7, _T("Unemployed") }, + { 8, _T("Pensioner") }, + { 9, _T("Housekeeper") }, + { 10, _T("Teacher") }, + { 11, _T("Doctor") }, + { 12, _T("Other") }, + { 0, NULL } +}; +JABBER_FIELD_MAP tlenFieldPlan[] = { + { 1, _T("I'd like to go downtown") }, + { 2, _T("I'd like to go to the cinema") }, + { 3, _T("I'd like to take a walk") }, + { 4, _T("I'd like to go to the disco") }, + { 5, _T("I'd like to go on a blind date") }, + { 6, _T("Waiting for suggestion") }, + { 0, NULL } +}; + +static INT_PTR CALLBACK TlenUserInfoDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); + +static void InitComboBox(HWND hwndCombo, JABBER_FIELD_MAP *fieldMap) +{ + int i, n; + + n = SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM)_T("")); + SendMessage(hwndCombo, CB_SETITEMDATA, n, 0); + SendMessage(hwndCombo, CB_SETCURSEL, n, 0); + for (i=0;;i++) { + if (fieldMap[i].name == NULL) + break; + n = SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) TranslateTS(fieldMap[i].name)); + SendMessage(hwndCombo, CB_SETITEMDATA, n, fieldMap[i].id); + } +} + +static void FetchField(HWND hwndDlg, UINT idCtrl, char *fieldName, char **str, int *strSize) +{ + char text[512]; + char *localFieldName, *localText; + + if (hwndDlg == NULL || fieldName == NULL || str == NULL || strSize == NULL) + return; + GetDlgItemTextA(hwndDlg, idCtrl, text, sizeof(text)); + if (text[0]) { + if ((localFieldName=JabberTextEncode(fieldName)) != NULL) { + if ((localText=JabberTextEncode(text)) != NULL) { + JabberStringAppend(str, strSize, "<%s>%s", localFieldName, localText, localFieldName); + mir_free(localText); + } + mir_free(localFieldName); + } + } +} + +static void FetchCombo(HWND hwndDlg, UINT idCtrl, char *fieldName, char **str, int *strSize) +{ + int value; + char *localFieldName; + + if (hwndDlg == NULL || fieldName == NULL || str == NULL || strSize == NULL) + return; + value = (int) SendDlgItemMessage(hwndDlg, idCtrl, CB_GETITEMDATA, SendDlgItemMessage(hwndDlg, idCtrl, CB_GETCURSEL, 0, 0), 0); + if (value > 0) { + if ((localFieldName=JabberTextEncode(fieldName)) != NULL) { + JabberStringAppend(str, strSize, "<%s>%d", localFieldName, value, localFieldName); + mir_free(localFieldName); + } + } +} + + +int TlenUserInfoInit(void *ptr, WPARAM wParam, LPARAM lParam) +{ + char *szProto; + HANDLE hContact; + OPTIONSDIALOGPAGE odp = {0}; + TlenProtocol *proto = (TlenProtocol *)ptr; + + if (!CallService(MS_PROTO_ISPROTOCOLLOADED, 0, (LPARAM) proto->m_szModuleName)) + return 0; + hContact = (HANDLE) lParam; + szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0); + if ((szProto != NULL && !strcmp(szProto, proto->m_szModuleName)) || !lParam) { + odp.cbSize = sizeof(odp); + odp.hInstance = hInst; + odp.flags = ODPF_TCHAR; + odp.pfnDlgProc = TlenUserInfoDlgProc; + odp.position = -2000000000; + odp.pszTemplate = ((HANDLE)lParam != NULL) ? MAKEINTRESOURCEA(IDD_USER_INFO):MAKEINTRESOURCEA(IDD_USER_VCARD); + odp.ptszTitle = (hContact != NULL) ? LPGENT("Account") : proto->m_tszUserName; + odp.dwInitParam = (LPARAM)proto; + UserInfo_AddPage(wParam, &odp); + + } + if (!lParam && proto->isOnline) { + CCSDATA ccs = {0}; + proto->GetInfo(0, (LPARAM) &ccs); + } + return 0; +} + +typedef struct { + TlenProtocol *proto; + HANDLE hContact; +}TLENUSERINFODLGDATA; + + +static INT_PTR CALLBACK TlenUserInfoDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + TLENUSERINFODLGDATA *data = (TLENUSERINFODLGDATA *) GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + switch (msg) { + case WM_INITDIALOG: + + data = (TLENUSERINFODLGDATA*)mir_alloc(sizeof(TLENUSERINFODLGDATA)); + data->hContact = (HANDLE) lParam; + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)data); + // lParam is hContact + TranslateDialogDefault(hwndDlg); + InitComboBox(GetDlgItem(hwndDlg, IDC_GENDER), tlenFieldGender); + InitComboBox(GetDlgItem(hwndDlg, IDC_OCCUPATION), tlenFieldOccupation); + InitComboBox(GetDlgItem(hwndDlg, IDC_LOOKFOR), tlenFieldLookfor); + + return TRUE; + case WM_TLEN_REFRESH: + { + DBVARIANT dbv; + char *jid; + int i; + JABBER_LIST_ITEM *item; + + SetDlgItemText(hwndDlg, IDC_INFO_JID, _T("")); + SetDlgItemText(hwndDlg, IDC_SUBSCRIPTION, _T("")); + SetFocus(GetDlgItem(hwndDlg, IDC_STATIC)); + + if (!DBGetContactSettingTString(data->hContact, data->proto->m_szModuleName, "FirstName", &dbv)) { + SetDlgItemText(hwndDlg, IDC_FIRSTNAME, dbv.ptszVal); + DBFreeVariant(&dbv); + } else SetDlgItemText(hwndDlg, IDC_FIRSTNAME, _T("")); + if (!DBGetContactSettingTString(data->hContact, data->proto->m_szModuleName, "LastName", &dbv)) { + SetDlgItemText(hwndDlg, IDC_LASTNAME, dbv.ptszVal); + DBFreeVariant(&dbv); + } else SetDlgItemText(hwndDlg, IDC_LASTNAME, _T("")); + if (!DBGetContactSettingTString(data->hContact, data->proto->m_szModuleName, "Nick", &dbv)) { + SetDlgItemText(hwndDlg, IDC_NICKNAME, dbv.ptszVal); + DBFreeVariant(&dbv); + } else SetDlgItemText(hwndDlg, IDC_NICKNAME, _T("")); + if (!DBGetContactSettingTString(data->hContact, data->proto->m_szModuleName, "e-mail", &dbv)) { + SetDlgItemText(hwndDlg, IDC_EMAIL, dbv.ptszVal); + DBFreeVariant(&dbv); + } else SetDlgItemText(hwndDlg, IDC_EMAIL, _T("")); + if (!DBGetContactSetting(data->hContact, data->proto->m_szModuleName, "Age", &dbv)) { + SetDlgItemInt(hwndDlg, IDC_AGE, dbv.wVal, FALSE); + DBFreeVariant(&dbv); + } else SetDlgItemText(hwndDlg, IDC_AGE, _T("")); + if (!DBGetContactSettingTString(data->hContact, data->proto->m_szModuleName, "City", &dbv)) { + SetDlgItemText(hwndDlg, IDC_CITY, dbv.ptszVal); + DBFreeVariant(&dbv); + } else SetDlgItemText(hwndDlg, IDC_CITY, _T("")); + if (!DBGetContactSettingTString(data->hContact, data->proto->m_szModuleName, "School", &dbv)) { + SetDlgItemText(hwndDlg, IDC_SCHOOL, dbv.ptszVal); + DBFreeVariant(&dbv); + } else SetDlgItemText(hwndDlg, IDC_SCHOOL, _T("")); + switch (DBGetContactSettingByte(data->hContact, data->proto->m_szModuleName, "Gender", '?')) { + case 'M': + SendDlgItemMessage(hwndDlg, IDC_GENDER, CB_SETCURSEL, 1, 0); + SetDlgItemText(hwndDlg, IDC_GENDER_TEXT, TranslateTS(tlenFieldGender[0].name)); + break; + case 'F': + SendDlgItemMessage(hwndDlg, IDC_GENDER, CB_SETCURSEL, 2, 0); + SetDlgItemText(hwndDlg, IDC_GENDER_TEXT, TranslateTS(tlenFieldGender[1].name)); + break; + default: + SendDlgItemMessage(hwndDlg, IDC_GENDER, CB_SETCURSEL, 0, 0); + SetDlgItemText(hwndDlg, IDC_GENDER_TEXT, _T("")); + break; + } + i = DBGetContactSettingWord(data->hContact, data->proto->m_szModuleName, "Occupation", 0); + if (i>0 && i<13) { + SetDlgItemText(hwndDlg, IDC_OCCUPATION_TEXT, TranslateTS(tlenFieldOccupation[i-1].name)); + SendDlgItemMessage(hwndDlg, IDC_OCCUPATION, CB_SETCURSEL, i, 0); + } else { + SetDlgItemText(hwndDlg, IDC_OCCUPATION_TEXT, _T("")); + SendDlgItemMessage(hwndDlg, IDC_OCCUPATION, CB_SETCURSEL, 0, 0); + } + i = DBGetContactSettingWord(data->hContact, data->proto->m_szModuleName, "LookingFor", 0); + if (i>0 && i<6) { + SetDlgItemText(hwndDlg, IDC_LOOKFOR_TEXT, TranslateTS(tlenFieldLookfor[i-1].name)); + SendDlgItemMessage(hwndDlg, IDC_LOOKFOR, CB_SETCURSEL, i, 0); + } else { + SetDlgItemText(hwndDlg, IDC_LOOKFOR_TEXT, _T("")); + SendDlgItemMessage(hwndDlg, IDC_LOOKFOR, CB_SETCURSEL, 0, 0); + } + i = DBGetContactSettingWord(data->hContact, data->proto->m_szModuleName, "VoiceChat", 0); + CheckDlgButton(hwndDlg, IDC_VOICECONVERSATIONS, i); + i = DBGetContactSettingWord(data->hContact, data->proto->m_szModuleName, "PublicStatus", 0); + CheckDlgButton(hwndDlg, IDC_PUBLICSTATUS, i); + if (!DBGetContactSetting(data->hContact, data->proto->m_szModuleName, "jid", &dbv)) { + jid = JabberTextDecode(dbv.pszVal); + SetDlgItemTextA(hwndDlg, IDC_INFO_JID, jid); + mir_free(jid); + jid = dbv.pszVal; + if (data->proto->isOnline) { + if ((item=JabberListGetItemPtr(data->proto, LIST_ROSTER, jid)) != NULL) { + switch (item->subscription) { + case SUB_BOTH: + SetDlgItemText(hwndDlg, IDC_SUBSCRIPTION, TranslateT("both")); + break; + case SUB_TO: + SetDlgItemText(hwndDlg, IDC_SUBSCRIPTION, TranslateT("to")); + break; + case SUB_FROM: + SetDlgItemText(hwndDlg, IDC_SUBSCRIPTION, TranslateT("from")); + break; + default: + SetDlgItemText(hwndDlg, IDC_SUBSCRIPTION, TranslateT("none")); + break; + } + SetDlgItemTextA(hwndDlg, IDC_SOFTWARE, item->software); + SetDlgItemTextA(hwndDlg, IDC_VERSION, item->version); + SetDlgItemTextA(hwndDlg, IDC_SYSTEM, item->system); + } else { + SetDlgItemText(hwndDlg, IDC_SUBSCRIPTION, TranslateT("not on roster")); + } + } + DBFreeVariant(&dbv); + } + } + break; + case WM_NOTIFY: + switch (((LPNMHDR)lParam)->idFrom) { + case 0: + switch (((LPNMHDR)lParam)->code) { + case PSN_INFOCHANGED: + { + HANDLE hContact = (HANDLE) ((LPPSHNOTIFY) lParam)->lParam; + SendMessage(hwndDlg, WM_TLEN_REFRESH, 0, (LPARAM) hContact); + } + break; + case PSN_PARAMCHANGED: + { + data->proto = ( TlenProtocol* )(( LPPSHNOTIFY )lParam )->lParam; + SendMessage(hwndDlg, WM_TLEN_REFRESH, 0, 0); + } + } + break; + } + break; + case WM_COMMAND: + if (LOWORD(wParam) == IDC_SAVE && HIWORD(wParam) == BN_CLICKED) { + char *str = NULL; + int strSize; + JabberStringAppend(&str, &strSize, "", JabberSerialNext(data->proto)); + FetchField(hwndDlg, IDC_FIRSTNAME, "first", &str, &strSize); + FetchField(hwndDlg, IDC_LASTNAME, "last", &str, &strSize); + FetchField(hwndDlg, IDC_NICKNAME, "nick", &str, &strSize); + FetchField(hwndDlg, IDC_EMAIL, "email", &str, &strSize); + FetchCombo(hwndDlg, IDC_GENDER, "s", &str, &strSize); + FetchField(hwndDlg, IDC_AGE, "b", &str, &strSize); + FetchField(hwndDlg, IDC_CITY, "c", &str, &strSize); + FetchCombo(hwndDlg, IDC_OCCUPATION, "j", &str, &strSize); + FetchField(hwndDlg, IDC_SCHOOL, "e", &str, &strSize); + FetchCombo(hwndDlg, IDC_LOOKFOR, "r", &str, &strSize); + JabberStringAppend(&str, &strSize, "%d", IsDlgButtonChecked(hwndDlg, IDC_VOICECONVERSATIONS) ? 1 : 0); + JabberStringAppend(&str, &strSize, "%d", IsDlgButtonChecked(hwndDlg, IDC_PUBLICSTATUS) ? 1 : 0); + JabberStringAppend(&str, &strSize, ""); + JabberSend(data->proto, "%s", str); + mir_free(str); + data->proto->GetInfo(NULL, 0); + } + break; + case WM_DESTROY: + mir_free(data); + break; + } + return FALSE; +} diff --git a/protocols/Tlen/src/tlen_voice.cpp b/protocols/Tlen/src/tlen_voice.cpp new file mode 100644 index 0000000000..c476d55116 --- /dev/null +++ b/protocols/Tlen/src/tlen_voice.cpp @@ -0,0 +1,1121 @@ +/* + +Tlen Protocol Plugin for Miranda NG +Copyright (C) 2004-2007 Piotr Piastucki + +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 +#include +#include +#include +#include +#include +//#include +#include "resource.h" +#include "jabber_list.h" +#include "tlen_voice.h" +#include "tlen_p2p_old.h" +#include "tlen_file.h" + +static int MODE_FREQUENCY[]= {0, 0, 8000, 11025, 22050, 44100}; +static int MODE_FRAME_SIZE[]= {0, 0, 5, 5, 10, 25}; +static int FRAMES_AVAILABLE_MAX_LIMIT = 2; +static int VU_METER_HEIGHT = 64; +static int VU_METER_WIDTH = 20; +static int VU_METER_LEVELS = 16; +static HBITMAP vuMeterBitmaps[100]; + +static void TlenVoiceReceiveParse(TLEN_FILE_TRANSFER *ft); +static void TlenVoiceSendParse(TLEN_FILE_TRANSFER *ft); +static void TlenVoiceReceivingConnection(HANDLE hNewConnection, DWORD dwRemoteIP, void * pExtra); + +static void CALLBACK TlenVoicePlaybackCallback(HWAVEOUT hwo, UINT uMsg, DWORD* dwInstance, DWORD dwParam1, DWORD dwParam2) +{ + if (uMsg == WOM_DONE) { + TLEN_VOICE_CONTROL *control = (TLEN_VOICE_CONTROL *) dwInstance; + waveOutUnprepareHeader(hwo, (WAVEHDR *) dwParam1, sizeof(WAVEHDR)); + if (control->proto->framesAvailableForPlayback > 0) { + control->proto->framesAvailableForPlayback--; + } +// playbackControl->waveHeaders[playbackControl->waveHeadersPos].dwFlags = WHDR_DONE; +// playbackControl->waveHeaders[playbackControl->waveHeadersPos].lpData = (char *) (playbackControl->waveData + playbackControl->waveHeadersPos * playbackControl->waveFrameSize); +// playbackControl->waveHeaders[playbackControl->waveHeadersPos].dwBufferLength = playbackControl->waveFrameSize * 2; +// waveOutPrepareHeader(playbackControl->hWaveOut, &playbackControl->waveHeaders[playbackControl->waveHeadersPos], sizeof(WAVEHDR)); +// waveOutWrite(playbackControl->hWaveOut, &playbackControl->waveHeaders[playbackControl->waveHeadersPos], sizeof(WAVEHDR)); + + } +} + +static DWORD WINAPI TlenVoiceRecordingThreadProc(TLEN_VOICE_CONTROL *control) +{ + MSG msg; + HWAVEIN hWaveIn; + WAVEHDR *hWaveHdr; + control->isRunning = 1; + control->stopThread = 0; + while (TRUE) { + GetMessage(&msg,NULL,0,0); + if (msg.message == MM_WIM_DATA) { +// JabberLog("recording thread running...%d", msg.message); + hWaveIn = (HWAVEIN) msg.wParam; + hWaveHdr = (WAVEHDR *) msg.lParam; + waveInUnprepareHeader(hWaveIn, hWaveHdr, sizeof(WAVEHDR)); + if (hWaveHdr->dwBytesRecorded>0 && !control->bDisable) { + control->recordingData = (short *)hWaveHdr->lpData; + TlenVoiceSendParse(control->ft); + } + if (!control->stopThread) { + waveInPrepareHeader(hWaveIn, &control->waveHeaders[control->waveHeadersPos], sizeof(WAVEHDR)); + waveInAddBuffer(hWaveIn, &control->waveHeaders[control->waveHeadersPos], sizeof(WAVEHDR)); + control->waveHeadersPos = (control->waveHeadersPos +1) % control->waveHeadersNum; + } + } + else if (msg.message == MM_WIM_CLOSE) { + break; + } + } + control->isRunning = 0; + JabberLog(control->proto, "recording thread ended..."); + return 0; +} + + +/*static void CALLBACK TlenVoiceRecordingCallback(HWAVEIN hwi, UINT uMsg, DWORD* dwInstance, DWORD dwParam1, DWORD dwParam2) +{ + if (uMsg == WIM_DATA) { + TLEN_VOICE_CONTROL *control = (TLEN_VOICE_CONTROL *) dwInstance; + if (control->waveHeaders[control->waveHeadersPos].dwBytesRecorded>0) { + control->recordingData = (short *)control->waveHeaders[control->waveHeadersPos].lpData; + TlenVoiceSendParse(control->ft); + } + waveInAddBuffer(control->hWaveIn, &control->waveHeaders[control->waveHeadersPos], sizeof(WAVEHDR)); + control->waveHeadersPos = (control->waveHeadersPos +1) % control->waveHeadersNum; + } +}*/ + +static int TlenVoicePlaybackStart(TLEN_VOICE_CONTROL *control) +{ + WAVEFORMATEX wfm; + MMRESULT mmres; + int i, j; + int iNumDevs, iSelDev; + WAVEOUTCAPS wic; + + memset(&wfm, 0, sizeof(wfm)); + wfm.cbSize = sizeof(WAVEFORMATEX); + wfm.nChannels = 1; + wfm.wBitsPerSample = 16; + wfm.nSamplesPerSec = MODE_FREQUENCY[control->codec]; + wfm.nAvgBytesPerSec = wfm.nSamplesPerSec * wfm.nChannels * wfm.wBitsPerSample/8; + wfm.nBlockAlign = 2 * wfm.nChannels; + wfm.wFormatTag = WAVE_FORMAT_PCM; + + control->waveMode = 0; + control->waveFrameSize = MODE_FRAME_SIZE[control->codec] * 160 * wfm.nChannels;// * wfm.wBitsPerSample / 8; + control->waveHeadersPos = 0; + control->waveHeadersNum = FRAMES_AVAILABLE_MAX_LIMIT + 2; + + j = DBGetContactSettingWord(NULL, control->proto->m_szModuleName, "VoiceDeviceOut", 0); + iSelDev = WAVE_MAPPER; + if (j != 0) { + iNumDevs = waveOutGetNumDevs(); + for (i = 0; i < iNumDevs; i++) { + if (!waveOutGetDevCaps(i, &wic, sizeof(WAVEOUTCAPS))) { + if (wic.dwFormats != 0) { + j--; + if (j == 0) { + iSelDev = i; + break; + } + } + } + } + } + if (!waveOutGetDevCaps(iSelDev, &wic, sizeof(WAVEOUTCAPS))) { + JabberLog(control->proto, "Playback device ID #%u: %s\r\n", iSelDev, wic.szPname); + } + + mmres = waveOutOpen(&control->hWaveOut, iSelDev, &wfm, (DWORD) &TlenVoicePlaybackCallback, (DWORD) control, CALLBACK_FUNCTION); + if (mmres != MMSYSERR_NOERROR) { + JabberLog(control->proto, "TlenVoiceStart FAILED!"); + return 1; + } + control->waveData = (short *)mir_alloc(control->waveHeadersNum * control->waveFrameSize * 2); + memset(control->waveData, 0, control->waveHeadersNum * control->waveFrameSize * 2); + control->waveHeaders = (WAVEHDR *)mir_alloc(control->waveHeadersNum * sizeof(WAVEHDR)); + JabberLog(control->proto, "TlenVoiceStart OK!"); + return 0; +} + + +static int TlenVoiceRecordingStart(TLEN_VOICE_CONTROL *control) +{ + WAVEFORMATEX wfm; + MMRESULT mmres; + int i, j; + int iNumDevs, iSelDev; + WAVEINCAPS wic; + + memset(&wfm, 0, sizeof(wfm)); + wfm.cbSize = sizeof(WAVEFORMATEX); + wfm.nChannels = 1; + wfm.wBitsPerSample = 16; + wfm.nSamplesPerSec = MODE_FREQUENCY[control->codec]; + wfm.nAvgBytesPerSec = wfm.nSamplesPerSec * wfm.nChannels * wfm.wBitsPerSample/8; + wfm.nBlockAlign = 2 * wfm.nChannels; + wfm.wFormatTag = WAVE_FORMAT_PCM; + + + control->waveMode = 0; +// control->isRunning = 1; + control->waveFrameSize = MODE_FRAME_SIZE[control->codec] * 160 * wfm.nChannels;// * wfm.wBitsPerSample / 8; + control->waveHeadersPos = 0; + control->waveHeadersNum = 2; + + control->hThread = CreateThread( NULL, + 0, + (LPTHREAD_START_ROUTINE)TlenVoiceRecordingThreadProc, + control, + 0, + (LPDWORD)&control->threadID); + + + SetThreadPriority(control->hThread, THREAD_PRIORITY_ABOVE_NORMAL); + + j = DBGetContactSettingWord(NULL, control->proto->m_szModuleName, "VoiceDeviceIn", 0); + iSelDev = WAVE_MAPPER; + if (j != 0) { + iNumDevs = waveInGetNumDevs(); + for (i = 0; i < iNumDevs; i++) { + if (!waveInGetDevCaps(i, &wic, sizeof(WAVEINCAPS))) { + if (wic.dwFormats != 0) { + j--; + if (j == 0) { + iSelDev = i; + break; + } + } + } + } + } + if (!waveInGetDevCaps(iSelDev, &wic, sizeof(WAVEINCAPS))) { + JabberLog(control->proto, "Recording device ID #%u: %s\r\n", iSelDev, wic.szPname); + } + + mmres = waveInOpen(&control->hWaveIn, iSelDev, &wfm, (DWORD) control->threadID, 0, CALLBACK_THREAD); +// mmres = waveInOpen(&control->hWaveIn, 3, &wfm, (DWORD) &TlenVoiceRecordingCallback, (DWORD) control, CALLBACK_FUNCTION); + if (mmres != MMSYSERR_NOERROR) { + PostThreadMessage(control->threadID, WIM_CLOSE, 0, 0); + JabberLog(control->proto, "TlenVoiceStart FAILED %d!", mmres); + return 1; + } + control->waveData = (short *)mir_alloc(control->waveHeadersNum * control->waveFrameSize * 2); + memset(control->waveData, 0, control->waveHeadersNum * control->waveFrameSize * 2); + control->waveHeaders = (WAVEHDR *)mir_alloc(control->waveHeadersNum * sizeof(WAVEHDR)); + for (i=0;iwaveHeadersNum;i++) { + control->waveHeaders[i].dwFlags = 0;//WHDR_DONE; + control->waveHeaders[i].lpData = (char *) (control->waveData + i * control->waveFrameSize); + control->waveHeaders[i].dwBufferLength = control->waveFrameSize *2; + mmres = waveInPrepareHeader(control->hWaveIn, &control->waveHeaders[i], sizeof(WAVEHDR)); + if (mmres != MMSYSERR_NOERROR) { + waveInClose(control->hWaveIn); +// PostThreadMessage(control->threadID, WIM_CLOSE, 0, 0); + JabberLog(control->proto, "TlenVoiceStart FAILED #2!"); + return 1; + } + } + for (i=0;iwaveHeadersNum;i++) { + waveInAddBuffer(control->hWaveIn, &control->waveHeaders[i], sizeof(WAVEHDR)); + } + waveInStart(control->hWaveIn); + JabberLog(control->proto, "TlenVoiceRStart OK!"); + return 0; +} + + +static TLEN_VOICE_CONTROL *TlenVoiceCreateVC(TlenProtocol *proto, int codec) +{ + TLEN_VOICE_CONTROL *vc; + vc = (TLEN_VOICE_CONTROL *) mir_alloc(sizeof (TLEN_VOICE_CONTROL)); + memset(vc, 0, sizeof(TLEN_VOICE_CONTROL)); + vc->gsmstate = gsm_create(); + vc->codec = codec; + vc->proto = proto; + return vc; +} +static void TlenVoiceFreeVc(TLEN_VOICE_CONTROL *vc) +{ + int i; + JabberLog(vc->proto, "-> TlenVoiceFreeVc"); + vc->stopThread = 1; + PostThreadMessage(vc->threadID, MM_WIM_CLOSE, 0, 0); + while (vc->isRunning) { + Sleep(50); + } + if (vc->hThread != NULL) CloseHandle(vc->hThread); + if (vc->hWaveIn) { + for (i=0;iwaveHeadersNum;i++) { + while (waveInUnprepareHeader(vc->hWaveIn, &vc->waveHeaders[i], sizeof(WAVEHDR)) == WAVERR_STILLPLAYING) { + Sleep(50); + } + } + while (waveInClose(vc->hWaveIn) == WAVERR_STILLPLAYING) { + Sleep(50); + } + } + if (vc->hWaveOut) { + for (i=0;iwaveHeadersNum;i++) { + while (waveOutUnprepareHeader(vc->hWaveOut, &vc->waveHeaders[i], sizeof(WAVEHDR)) == WAVERR_STILLPLAYING) { + Sleep(50); + } + } + while (waveOutClose(vc->hWaveOut) == WAVERR_STILLPLAYING) { + Sleep(50); + } + } + if (vc->waveData) mir_free(vc->waveData); + if (vc->waveHeaders) mir_free(vc->waveHeaders); + if (vc->gsmstate) gsm_release(vc->gsmstate); + JabberLog(vc->proto, "<- TlenVoiceFreeVc"); + mir_free(vc); +} + +static void TlenVoiceCrypt(char *buffer, int len) +{ + int i, j, k; + j = 0x71; + for (i=0;iproto, "Thread started: type=file_receive server='%s' port='%d'", ft->hostName, ft->wPort); + nloc.cbSize = NETLIBOPENCONNECTION_V1_SIZE;//sizeof(NETLIBOPENCONNECTION); + nloc.szHost = ft->hostName; + nloc.wPort = ft->wPort; + nloc.flags = 0; + SetDlgItemText(ft->proto->voiceDlgHWND, IDC_STATUS, TranslateT("...Connecting...")); +// ProtoBroadcastAck(ft->proto->m_szModuleName, ft->hContact, ACKTYPE_FILE, ACKRESULT_CONNECTING, ft, 0); + s = (HANDLE) CallService(MS_NETLIB_OPENCONNECTION, (WPARAM) ft->proto->hNetlibUser, (LPARAM) &nloc); + if (s != NULL) { + ft->s = s; + JabberLog(ft->proto, "Entering file receive loop"); + TlenP2PEstablishOutgoingConnection(ft, FALSE); + if (ft->state != FT_ERROR) { + ft->proto->playbackControl = NULL; + ft->proto->recordingControl = TlenVoiceCreateVC(ft->proto, 3); + ft->proto->recordingControl->ft = ft; + TlenVoiceRecordingStart(ft->proto->recordingControl); + while (ft->state != FT_DONE && ft->state != FT_ERROR) { + TlenVoiceReceiveParse(ft); + } + TlenVoiceFreeVc(ft->proto->recordingControl); + ft->proto->playbackControl = NULL; + ft->proto->recordingControl = NULL; + } + if (ft->s) { + Netlib_CloseHandle(s); + } + ft->s = NULL; + } else { + JabberLog(ft->proto, "Connection failed - receiving as server"); + ft->pfnNewConnectionV2 = TlenVoiceReceivingConnection; + s = TlenP2PListen(ft); + if (s != NULL) { + HANDLE hEvent; + char *nick; + SetDlgItemText(ft->proto->voiceDlgHWND, IDC_STATUS, TranslateT("...Waiting for connection...")); + ft->s = s; + hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + ft->hFileEvent = hEvent; + ft->currentFile = 0; + ft->state = FT_CONNECTING; + nick = JabberNickFromJID(ft->jid); + JabberSend(ft->proto, "", nick, ft->iqId, ft->localName, ft->wLocalPort); + mir_free(nick); + JabberLog(ft->proto, "Waiting for the file to be received..."); + WaitForSingleObject(hEvent, INFINITE); + ft->hFileEvent = NULL; + CloseHandle(hEvent); + JabberLog(ft->proto, "Finish all files"); + Netlib_CloseHandle(s); + } else { + ft->state = FT_ERROR; + } + } + JabberListRemove(ft->proto, LIST_VOICE, ft->iqId); + if (ft->state == FT_DONE) { + SetDlgItemText(ft->proto->voiceDlgHWND, IDC_STATUS, TranslateT("...Finished...")); + //ProtoBroadcastAck(ft->proto->m_szModuleName, ft->hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, ft, 0); + } else { + char *nick; + nick = JabberNickFromJID(ft->jid); + JabberSend(ft->proto, "", nick, ft->iqId); + mir_free(nick); + SetDlgItemText(ft->proto->voiceDlgHWND, IDC_STATUS, TranslateT("...Error...")); + //ProtoBroadcastAck(ft->proto->m_szModuleName, ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0); + } + JabberLog(ft->proto, "Thread ended: type=file_receive server='%s'", ft->hostName); + + TlenP2PFreeFileTransfer(ft); +} + +static void TlenVoiceReceivingConnection(JABBER_SOCKET hConnection, DWORD dwRemoteIP, void * pExtra) +{ + JABBER_SOCKET slisten; + TLEN_FILE_TRANSFER *ft; + TlenProtocol *proto = (TlenProtocol *)pExtra; + + ft = TlenP2PEstablishIncomingConnection(proto, hConnection, LIST_VOICE, FALSE); + if (ft != NULL) { + slisten = ft->s; + ft->s = hConnection; + JabberLog(ft->proto, "Set ft->s to %d (saving %d)", hConnection, slisten); + JabberLog(ft->proto, "Entering send loop for this file connection... (ft->s is hConnection)"); + proto->playbackControl = NULL; + proto->recordingControl = TlenVoiceCreateVC(proto, 3); + proto->recordingControl->ft = ft; + TlenVoiceRecordingStart(proto->recordingControl); + while (ft->state != FT_DONE && ft->state != FT_ERROR) { + TlenVoiceReceiveParse(ft); + } + TlenVoiceFreeVc(proto->recordingControl); + proto->playbackControl = NULL; + proto->recordingControl = NULL; + if (ft->state == FT_DONE) { + SetDlgItemText(proto->voiceDlgHWND, IDC_STATUS, TranslateT("...Finished...")); +// ProtoBroadcastAck(proto->m_szModuleName, ft->hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, ft, 0); + } else { +// ProtoBroadcastAck(proto->m_szModuleName, ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0); + SetDlgItemText(ft->proto->voiceDlgHWND, IDC_STATUS, TranslateT("...Error...")); + } + JabberLog(ft->proto, "Closing connection for this file transfer... (ft->s is now hBind)"); + ft->s = slisten; + JabberLog(ft->proto, "ft->s is restored to %d", ft->s); + } + Netlib_CloseHandle(hConnection); + if (ft != NULL && ft->hFileEvent != NULL) + SetEvent(ft->hFileEvent); +} + +static void TlenVoiceReceiveParse(TLEN_FILE_TRANSFER *ft) +{ + char *statusTxt; + int i, j; + char *p; + float val; + TLEN_FILE_PACKET *packet; + packet = TlenP2PPacketReceive(ft->s); + if (packet != NULL) { + statusTxt = " Unknown packet "; + p = packet->packet; + if (packet->type == TLEN_VOICE_PACKET) { + short *out; + int codec, chunkNum; + statusTxt = " OK "; + TlenVoiceCrypt(packet->packet+4, packet->len-4); + codec = *((int *)packet->packet); + if (codec<2 || codec>5) { + statusTxt = " Unknown codec "; + } else { + if (ft->proto->playbackControl == NULL) { + ft->proto->playbackControl = TlenVoiceCreateVC(ft->proto, codec); + TlenVoicePlaybackStart(ft->proto->playbackControl); + ft->proto->framesAvailableForPlayback = 0; + ft->proto->availOverrunValue = 0; + } else if (ft->proto->playbackControl->codec != codec) { + TlenVoiceFreeVc(ft->proto->playbackControl); + ft->proto->playbackControl = TlenVoiceCreateVC(ft->proto, codec); + TlenVoicePlaybackStart(ft->proto->playbackControl); + ft->proto->framesAvailableForPlayback = 0; + ft->proto->availOverrunValue = 0; + } + if (!ft->proto->playbackControl->bDisable) { + ft->proto->playbackControl->waveHeaders[ft->proto->playbackControl->waveHeadersPos].dwFlags = WHDR_DONE; + ft->proto->playbackControl->waveHeaders[ft->proto->playbackControl->waveHeadersPos].lpData = (char *) (ft->proto->playbackControl->waveData + ft->proto->playbackControl->waveHeadersPos * ft->proto->playbackControl->waveFrameSize); + ft->proto->playbackControl->waveHeaders[ft->proto->playbackControl->waveHeadersPos].dwBufferLength = ft->proto->playbackControl->waveFrameSize * 2; + /* + if (availPlayback == 0) { + statusTxt = "!! Buffer is empty !!"; + availPlayback++; + waveOutPrepareHeader(playbackControl->hWaveOut, &playbackControl->waveHeaders[playbackControl->waveHeadersPos], sizeof(WAVEHDR)); + waveOutWrite(playbackControl->hWaveOut, &playbackControl->waveHeaders[playbackControl->waveHeadersPos], sizeof(WAVEHDR)); + playbackControl->waveHeadersPos = (playbackControl->waveHeadersPos +1) % playbackControl->waveHeadersNum; + playbackControl->waveHeaders[playbackControl->waveHeadersPos].dwFlags = WHDR_DONE; + playbackControl->waveHeaders[playbackControl->waveHeadersPos].lpData = (char *) (playbackControl->waveData + playbackControl->waveHeadersPos * playbackControl->waveFrameSize); + playbackControl->waveHeaders[playbackControl->waveHeadersPos].dwBufferLength = playbackControl->waveFrameSize * 2; + } + */ + chunkNum = min(MODE_FRAME_SIZE[codec], (int)(packet->len - 4) / 33); + out = (short *)ft->proto->playbackControl->waveHeaders[ft->proto->playbackControl->waveHeadersPos].lpData; + for (i=0; iproto->playbackControl->gsmstate->gsmFrame[j] = packet->packet[i*33 +j +4]; + } + gsm_decode(ft->proto->playbackControl->gsmstate, out); + out += 160; + } + out = (short *)ft->proto->playbackControl->waveHeaders[ft->proto->playbackControl->waveHeadersPos].lpData; + val = 0; + for (i=0; i VU_METER_LEVELS - 1 ) { + j = VU_METER_LEVELS - 1; + } else if (j<0) { + j = 0; + } + ft->proto->playbackControl->vuMeter = j; + ft->proto->playbackControl->bytesSum += 8 + packet->len; + /* Simple logic to avoid huge delays. If a delay is detected a frame is not played */ + j = ft->proto->availOverrunValue > 0 ? -1 : 0; + while (ft->proto->framesAvailableForPlayback > FRAMES_AVAILABLE_MAX_LIMIT) { + j = 1; + SleepEx(5, FALSE); + } + ft->proto->availOverrunValue += j; + /* 40 frames - 800ms/8kHz */ + if (ft->proto->availOverrunValue < 40) { + ft->proto->framesAvailableForPlayback++; + waveOutPrepareHeader(ft->proto->playbackControl->hWaveOut, &ft->proto->playbackControl->waveHeaders[ft->proto->playbackControl->waveHeadersPos], sizeof(WAVEHDR)); + waveOutWrite(ft->proto->playbackControl->hWaveOut, &ft->proto->playbackControl->waveHeaders[ft->proto->playbackControl->waveHeadersPos], sizeof(WAVEHDR)); + ft->proto->playbackControl->waveHeadersPos = (ft->proto->playbackControl->waveHeadersPos +1) % ft->proto->playbackControl->waveHeadersNum; + } else { + ft->proto->availOverrunValue -= 10; + statusTxt = "!! Skipping frame !!"; + } + } + } + } + { + char ttt[2048]; + sprintf(ttt, "%s %d %d ", statusTxt, ft->proto->framesAvailableForPlayback, ft->proto->availOverrunValue); + SetDlgItemTextA(ft->proto->voiceDlgHWND, IDC_STATUS, ttt); + } + TlenP2PPacketFree(packet); + } + else { + if (ft->proto->playbackControl != NULL) { + TlenVoiceFreeVc(ft->proto->playbackControl); + ft->proto->playbackControl = NULL; + } + ft->state = FT_ERROR; + } +} + + +void __cdecl TlenVoiceSendingThread(TLEN_FILE_TRANSFER *ft) +{ + JABBER_SOCKET s = NULL; + HANDLE hEvent; + char *nick; + + JabberLog(ft->proto, "Thread started: type=voice_send"); + ft->pfnNewConnectionV2 = TlenVoiceReceivingConnection; + s = TlenP2PListen(ft); + if (s != NULL) { + SetDlgItemText(ft->proto->voiceDlgHWND, IDC_STATUS, TranslateT("...Waiting for connection...")); + //ProtoBroadcastAck(ft->proto->m_szModuleName, ft->hContact, ACKTYPE_FILE, ACKRESULT_CONNECTING, ft, 0); + ft->s = s; + //JabberLog("ft->s = %d", s); + //JabberLog("fileCount = %d", ft->fileCount); + + hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + ft->hFileEvent = hEvent; + ft->currentFile = 0; + ft->state = FT_CONNECTING; + + nick = JabberNickFromJID(ft->jid); + JabberSend(ft->proto, "", nick, ft->iqId, ft->localName, ft->wLocalPort); + mir_free(nick); + JabberLog(ft->proto, "Waiting for the voice data to be sent..."); + WaitForSingleObject(hEvent, INFINITE); + ft->hFileEvent = NULL; + CloseHandle(hEvent); + JabberLog(ft->proto, "Finish voice"); + Netlib_CloseHandle(s); + ft->s = NULL; + JabberLog(ft->proto, "ft->s is NULL"); + + if (ft->state == FT_SWITCH) { + NETLIBOPENCONNECTION nloc; + JABBER_SOCKET s; + JabberLog(ft->proto, "Sending as client..."); + ft->state = FT_CONNECTING; + nloc.cbSize = NETLIBOPENCONNECTION_V1_SIZE;//sizeof(NETLIBOPENCONNECTION); + nloc.szHost = ft->hostName; + nloc.wPort = ft->wPort; + nloc.flags = 0; + s = (HANDLE) CallService(MS_NETLIB_OPENCONNECTION, (WPARAM) ft->proto->hNetlibUser, (LPARAM) &nloc); + if (s != NULL) { + SetDlgItemText(ft->proto->voiceDlgHWND, IDC_STATUS, TranslateT("...Connecting...")); + //ProtoBroadcastAck(ft->proto->m_szModuleName, ft->hContact, ACKTYPE_FILE, ACKRESULT_CONNECTING, ft, 0); + ft->s = s; + TlenP2PEstablishOutgoingConnection(ft, FALSE); + if (ft->state != FT_ERROR) { + JabberLog(ft->proto, "Entering send loop for this file connection..."); + ft->proto->playbackControl = NULL; + ft->proto->recordingControl = TlenVoiceCreateVC(ft->proto, 3); + ft->proto->recordingControl->ft = ft; + TlenVoiceRecordingStart(ft->proto->recordingControl); + while (ft->state != FT_DONE && ft->state != FT_ERROR) { + TlenVoiceReceiveParse(ft); + } + } + JabberLog(ft->proto, "Closing connection for this file transfer... "); + Netlib_CloseHandle(s); + } else { + ft->state = FT_ERROR; + } + } + } else { + JabberLog(ft->proto, "Cannot allocate port to bind for file server thread, thread ended."); + ft->state = FT_ERROR; + } + JabberListRemove(ft->proto, LIST_VOICE, ft->iqId); + switch (ft->state) { + case FT_DONE: + JabberLog(ft->proto, "Finish successfully"); + SetDlgItemText(ft->proto->voiceDlgHWND, IDC_STATUS, TranslateT("...Finished...")); + //ProtoBroadcastAck(ft->proto->m_szModuleName, ft->hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, ft, 0); + break; + case FT_DENIED: + SetDlgItemText(ft->proto->voiceDlgHWND, IDC_STATUS, TranslateT("...Denied...")); + //ProtoBroadcastAck(ft->proto->m_szModuleName, ft->hContact, ACKTYPE_FILE, ACKRESULT_DENIED, ft, 0); + break; + default: // FT_ERROR: + nick = JabberNickFromJID(ft->jid); + JabberSend(ft->proto, "", nick, ft->iqId); + mir_free(nick); + JabberLog(ft->proto, "Finish with errors"); + SetDlgItemText(ft->proto->voiceDlgHWND, IDC_STATUS, TranslateT("...Error...")); + //ProtoBroadcastAck(ft->proto->m_szModuleName, ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0); + break; + } + JabberLog(ft->proto, "Thread ended: type=voice_send"); + TlenP2PFreeFileTransfer(ft); +} + +static void TlenVoiceSendParse(TLEN_FILE_TRANSFER *ft) +{ + int codec, i; + TLEN_FILE_PACKET *packet; + + codec = ft->proto->recordingControl->codec; + if ((packet=TlenP2PPacketCreate(sizeof(DWORD)+MODE_FRAME_SIZE[codec]*33)) != NULL) { + short *in; + float val; + in = ft->proto->recordingControl->recordingData; + TlenP2PPacketSetType(packet, 0x96); + packet->packet[0] = codec; + TlenP2PPacketPackDword(packet, codec); + val = 0; + for (i=0; i VU_METER_LEVELS - 1 ) { + i = VU_METER_LEVELS - 1; + } else if (i<0) { + i = 0; + } + ft->proto->recordingControl->vuMeter = i; + for (i=0; iproto->recordingControl->gsmstate, in + i * 160); + TlenP2PPacketPackBuffer(packet, (char*)ft->proto->recordingControl->gsmstate->gsmFrame, 33); + } + TlenVoiceCrypt(packet->packet+4, packet->len-4); + if (!TlenP2PPacketSend(ft->s, packet)) { + ft->state = FT_ERROR; + } + ft->proto->recordingControl->bytesSum += 8 + packet->len; + TlenP2PPacketFree(packet); + } else { + ft->state = FT_ERROR; + } +} + +int TlenVoiceCancelAll(TlenProtocol *proto) +{ + JABBER_LIST_ITEM *item; + HANDLE hEvent; + int i = 0; + + while ((i=JabberListFindNext(proto, LIST_VOICE, 0)) >=0 ) { + if ((item=JabberListGetItemPtrFromIndex(proto, i)) != NULL) { + TLEN_FILE_TRANSFER *ft = item->ft; + JabberListRemoveByIndex(proto, i); + if (ft != NULL) { + if (ft->s) { + //ProtoBroadcastAck(proto->m_szModuleName, ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0); + JabberLog(proto, "Closing ft->s = %d", ft->s); + ft->state = FT_ERROR; + Netlib_CloseHandle(ft->s); + ft->s = NULL; + if (ft->hFileEvent != NULL) { + hEvent = ft->hFileEvent; + ft->hFileEvent = NULL; + SetEvent(hEvent); + } + } else { + JabberLog(proto, "freeing (V) ft struct"); + TlenP2PFreeFileTransfer(ft); + } + } + } + } + if (proto->voiceDlgHWND != NULL) { + EndDialog(proto->voiceDlgHWND, 0); + } + return 0; +} + +INT_PTR TlenVoiceContactMenuHandleVoice(void *ptr, LPARAM wParam, LPARAM lParam) +{ + HANDLE hContact; + DBVARIANT dbv; + JABBER_LIST_ITEM *item; + TLEN_FILE_TRANSFER *ft; + TlenProtocol *proto =(TlenProtocol *)ptr; + if (!proto->isOnline) { + return 1; + } + if ((hContact=(HANDLE) wParam) != NULL) { + if (!DBGetContactSetting(hContact, proto->m_szModuleName, "jid", &dbv)) { + char serialId[32]; + sprintf(serialId, "%d", JabberSerialNext(proto)); + if ((item = JabberListAdd(proto, LIST_VOICE, serialId)) != NULL) { + ft = TlenFileCreateFT(proto, dbv.pszVal); + ft->iqId = mir_strdup(serialId); + item->ft = ft; +// JabberSend(ft->proto, "", ft->jid); +// Sleep(5000); + TlenVoiceStart(ft, 2); + JabberSend(ft->proto, "", ft->jid, serialId); + } + DBFreeVariant(&dbv); + } + } + return 0; +} + +int TlenVoiceIsInUse(TlenProtocol *proto) { + if (JabberListFindNext(proto, LIST_VOICE, 0) >= 0 || proto->voiceDlgHWND != NULL) { + JabberLog(proto, "voice in use ? %d", proto->voiceDlgHWND); + return 1; + } + return 0; +} + +static HBITMAP TlenVoiceMakeBitmap(int w, int h, int bpp, void *ptr) +{ + BITMAPINFO bmih; + HBITMAP hbm; + HDC hdc; + bmih.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmih.bmiHeader.biWidth = w&0xFFFFFFFC; + bmih.bmiHeader.biHeight = h;//&0xFFFFFFFC; + bmih.bmiHeader.biPlanes = 1; // musi byc 1 + bmih.bmiHeader.biBitCount = bpp; + bmih.bmiHeader.biCompression = BI_RGB; + bmih.bmiHeader.biSizeImage = 0; + bmih.bmiHeader.biXPelsPerMeter = 0; + bmih.bmiHeader.biYPelsPerMeter = 0; + bmih.bmiHeader.biClrUsed = 0; + bmih.bmiHeader.biClrImportant = 0; + hdc = CreateDC(_T("DISPLAY"), NULL, NULL, NULL); + hbm = CreateDIBitmap(hdc, (PBITMAPINFOHEADER) &bmih, CBM_INIT, ptr, &bmih, DIB_RGB_COLORS); + ReleaseDC(NULL,hdc); + return hbm; +} + +static void TlenVoiceInitVUMeters() +{ + int i, v, y, x, x0, col, col0; + unsigned char *pBits; + int ledWidth, ledHeight; + ledWidth = 9; + ledHeight = 6; + VU_METER_HEIGHT = ledHeight; + VU_METER_WIDTH = (VU_METER_LEVELS-1) * ledWidth; + VU_METER_WIDTH = (VU_METER_WIDTH + 3) & (~3); + pBits = (unsigned char *)mir_alloc(3*VU_METER_WIDTH*VU_METER_HEIGHT); + memset(pBits, 0x80, 3*VU_METER_WIDTH*VU_METER_HEIGHT); + for (i=0;i= i) { + if (v < 10) col0 = 0x104010; + else if (v<13) col0 = 0x404010; + else col0 = 0x401010; + } else { + if (v < 10) col0 = 0x00f000; + else if (v<13) col0 = 0xf0f000; + else col0 = 0xf00000; + } + x0 = v * ledWidth; + for (y=1;y>8) &0xFF; + pBits[3*(x+x0+y*VU_METER_WIDTH)+2] = (col>>16) &0xFF; + } + } + } + vuMeterBitmaps[i] = TlenVoiceMakeBitmap(VU_METER_WIDTH, VU_METER_HEIGHT, 24, pBits); + } + mir_free(pBits); +} + +static INT_PTR CALLBACK TlenVoiceDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + HDC hDC, hMemDC; + int v; + static int counter; + TlenProtocol *proto = (TlenProtocol *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + switch (msg) { + case WM_INITDIALOG: + proto = (TlenProtocol *)lParam; + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)proto); + proto->voiceDlgHWND = hwndDlg; + TranslateDialogDefault(hwndDlg); + SendDlgItemMessage(hwndDlg, IDC_VCQUALITY, CB_ADDSTRING, 0, (LPARAM) TranslateT("8000 Hz / 13.8 kbps")); + SendDlgItemMessage(hwndDlg, IDC_VCQUALITY, CB_ADDSTRING, 0, (LPARAM) TranslateT("11025 Hz / 19.1 kbps")); + SendDlgItemMessage(hwndDlg, IDC_VCQUALITY, CB_ADDSTRING, 0, (LPARAM) TranslateT("22050 Hz / 36.8 kbps")); + SendDlgItemMessage(hwndDlg, IDC_VCQUALITY, CB_ADDSTRING, 0, (LPARAM) TranslateT("44100 Hz / 72 kbps")); + SendDlgItemMessage(hwndDlg, IDC_VCQUALITY, CB_SETCURSEL, 1, 0); + SendDlgItemMessage(hwndDlg, IDC_MICROPHONE, BUTTONSETASFLATBTN, TRUE, 0); + SendDlgItemMessage(hwndDlg, IDC_SPEAKER, BUTTONSETASFLATBTN, TRUE, 0); + SendDlgItemMessage(hwndDlg, IDC_MICROPHONE, BUTTONSETASPUSHBTN, TRUE, 0); + SendDlgItemMessage(hwndDlg, IDC_SPEAKER, BUTTONSETASPUSHBTN, TRUE, 0); + { + HICON hIcon = GetIcolibIcon(IDI_MICROPHONE); + SendDlgItemMessage(hwndDlg, IDC_MICROPHONE, BM_SETIMAGE, IMAGE_ICON, (LPARAM) hIcon); + ReleaseIcolibIcon(hIcon); + hIcon = GetIcolibIcon(IDI_SPEAKER); + SendDlgItemMessage(hwndDlg, IDC_SPEAKER, BM_SETIMAGE, IMAGE_ICON, (LPARAM) hIcon); + ReleaseIcolibIcon(hIcon); + } + CheckDlgButton(hwndDlg, IDC_MICROPHONE, TRUE); + CheckDlgButton(hwndDlg, IDC_SPEAKER, TRUE); + TlenVoiceInitVUMeters(); + SetDlgItemText(hwndDlg, IDC_STATUS, TranslateT("...???...")); + counter = 0; + SetTimer(hwndDlg, 1, 100, NULL); + return FALSE; + case WM_TIMER: + if (proto->recordingControl != NULL && !proto->recordingControl->bDisable) { + v = proto->recordingControl->vuMeter % VU_METER_LEVELS; + if (proto->recordingControl->vuMeter >0) { + proto->recordingControl->vuMeter--; + } + } else { + v = 0; + } + hDC = GetDC(GetDlgItem(hwndDlg, IDC_VUMETERIN)); + if (NULL != (hMemDC = CreateCompatibleDC( hDC ))) { + SelectObject( hMemDC, vuMeterBitmaps[v]) ; + BitBlt( hDC, 0, 0, VU_METER_WIDTH, VU_METER_HEIGHT, hMemDC, 0, 0, SRCCOPY ) ; + DeleteDC(hMemDC); + } + ReleaseDC(GetDlgItem(hwndDlg, IDC_PLAN), hDC); + if (proto->playbackControl != NULL && !proto->playbackControl->bDisable) { + v = proto->playbackControl->vuMeter % VU_METER_LEVELS; + if (proto->playbackControl->vuMeter >0) { + proto->playbackControl->vuMeter--; + } + } else { + v = 0; + } + hDC = GetDC(GetDlgItem(hwndDlg, IDC_VUMETEROUT)); + if (NULL != (hMemDC = CreateCompatibleDC( hDC ))) { + SelectObject( hMemDC, vuMeterBitmaps[v]) ; + BitBlt( hDC, 0, 0, VU_METER_WIDTH, VU_METER_HEIGHT, hMemDC, 0, 0, SRCCOPY ) ; + DeleteDC(hMemDC); + } + ReleaseDC(GetDlgItem(hwndDlg, IDC_PLAN), hDC); + counter ++; + if (counter %10 == 0) { + char str[50]; + float fv; + if (proto->recordingControl != NULL) { + fv = (float)proto->recordingControl->bytesSum; + proto->recordingControl->bytesSum = 0; + } else { + fv = 0; + } + sprintf(str, "%.1f kB/s", fv / 1024); + SetDlgItemTextA(hwndDlg, IDC_BYTESOUT, str); + if (proto->playbackControl != NULL) { + fv = (float)proto->playbackControl->bytesSum; + proto->playbackControl->bytesSum = 0; + } else { + fv = 0; + } + sprintf(str, "%.1f kB/s", fv / 1024); + SetDlgItemTextA(hwndDlg, IDC_BYTESIN, str); + } + break; + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDCANCEL: + EndDialog(hwndDlg, 0); + return TRUE; + case IDC_VCQUALITY: + if (HIWORD(wParam) == CBN_SELCHANGE) { + if (proto->recordingControl != NULL) { + int codec; + codec = SendDlgItemMessage(hwndDlg, IDC_VCQUALITY, CB_GETCURSEL, 0, 0) + 2; + if (codec != proto->recordingControl->codec && codec > 1 && codec < 6) { + TLEN_FILE_TRANSFER *ft = proto->recordingControl->ft; + TlenVoiceFreeVc(proto->recordingControl); + proto->recordingControl = TlenVoiceCreateVC(ft->proto, codec); + proto->recordingControl->ft = ft; + TlenVoiceRecordingStart(proto->recordingControl); + } + } + } + case IDC_MICROPHONE: + if (proto->recordingControl != NULL) { + proto->recordingControl->bDisable = !IsDlgButtonChecked(hwndDlg, IDC_MICROPHONE); + } + break; + case IDC_SPEAKER: + if (proto->playbackControl != NULL) { + proto->playbackControl->bDisable = !IsDlgButtonChecked(hwndDlg, IDC_SPEAKER); + } + break; + } + break; + case WM_CLOSE: + EndDialog(hwndDlg, 0); + break; + case WM_DESTROY: + proto->voiceDlgHWND = NULL; + break; + + } + return FALSE; +} + +static void __cdecl TlenVoiceDlgThread(void *ptr) +{ + + TLEN_FILE_TRANSFER *ft = (TLEN_FILE_TRANSFER *)ptr; + TlenProtocol * proto = ft->proto; + DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_VOICE), NULL, TlenVoiceDlgProc, (LPARAM) proto); + TlenVoiceCancelAll(proto); +} + +int TlenVoiceStart(TLEN_FILE_TRANSFER *ft, int mode) +{ + + JabberLog(ft->proto, "starting voice %d", mode); + if (mode == 0) { + JabberForkThread((void (__cdecl *)(void*))TlenVoiceReceiveThread, 0, ft); + } else if (mode == 1) { + JabberForkThread((void (__cdecl *)(void*))TlenVoiceSendingThread, 0, ft); + } else { + JabberForkThread((void (__cdecl *)(void*))TlenVoiceDlgThread, 0, ft); + } + return 0; +} + +static char *getDisplayName(TlenProtocol *proto, const char *id) +{ + char jid[256]; + HANDLE hContact; + DBVARIANT dbv; + if (!DBGetContactSetting(NULL, proto->m_szModuleName, "LoginServer", &dbv)) { + _snprintf(jid, sizeof(jid), "%s@%s", id, dbv.pszVal); + DBFreeVariant(&dbv); + if ((hContact=JabberHContactFromJID(proto, jid)) != NULL) { + return mir_strdup((char *) CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM) hContact, 0)); + } + } + return mir_strdup(id); +} + +typedef struct { + TlenProtocol *proto; + JABBER_LIST_ITEM *item; +}ACCEPTDIALOGDATA; + +static INT_PTR CALLBACK TlenVoiceAcceptDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + ACCEPTDIALOGDATA * data; + char *str; + switch (msg) { + case WM_INITDIALOG: + TranslateDialogDefault(hwndDlg); + data = (ACCEPTDIALOGDATA *) lParam; + str = getDisplayName(data->proto, data->item->nick); + SetDlgItemTextA(hwndDlg, IDC_FROM, str); + mir_free(str); + return FALSE; + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDC_ACCEPT: + EndDialog(hwndDlg, 1); + return TRUE; + case IDCANCEL: + case IDCLOSE: + EndDialog(hwndDlg, 0); + return TRUE; + } + break; + case WM_CLOSE: + EndDialog(hwndDlg, 0); + break; + } + return FALSE; +} + +static void __cdecl TlenVoiceAcceptDlgThread(void *ptr) +{ + + ACCEPTDIALOGDATA *data = (ACCEPTDIALOGDATA *)ptr; + int result = DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_ACCEPT_VOICE), NULL, TlenVoiceAcceptDlgProc, (LPARAM) data); + if (result && data->proto->isOnline) { + data->item->ft = TlenFileCreateFT(data->proto, data->item->nick); + data->item->ft->iqId = mir_strdup(data->item->jid); + TlenVoiceStart(data->item->ft, 2); + JabberSend(data->proto, "", data->item->nick, data->item->jid); + } else { + if (data->proto->isOnline) { + JabberSend(data->proto, "", data->item->nick, data->item->jid); + } + JabberListRemove(data->proto, LIST_VOICE, data->item->jid); + } + mir_free(data); +} + +int TlenVoiceAccept(TlenProtocol *proto, const char *id, const char *from) +{ + JABBER_LIST_ITEM * item; + if (!TlenVoiceIsInUse(proto)) { + if ((item = JabberListAdd(proto, LIST_VOICE, id)) != NULL) { + int ask, ignore, voiceChatPolicy; + ask = TRUE; + ignore = FALSE; + voiceChatPolicy = DBGetContactSettingWord(NULL, proto->m_szModuleName, "VoiceChatPolicy", 0); + if (voiceChatPolicy == TLEN_MUC_ASK) { + ignore = FALSE; + ask = TRUE; + } else if (voiceChatPolicy == TLEN_MUC_IGNORE_ALL) { + ignore = TRUE; + } else if (voiceChatPolicy == TLEN_MUC_IGNORE_NIR) { + char jid[256]; + DBVARIANT dbv; + if (!DBGetContactSetting(NULL, proto->m_szModuleName, "LoginServer", &dbv)) { + _snprintf(jid, sizeof(jid), "%s@%s", from, dbv.pszVal); + DBFreeVariant(&dbv); + } else { + strcpy(jid, from); + } + ignore = !IsAuthorized(proto, jid); + ask = TRUE; + } else if (voiceChatPolicy == TLEN_MUC_ACCEPT_IR) { + char jid[256]; + DBVARIANT dbv; + if (!DBGetContactSetting(NULL, proto->m_szModuleName, "LoginServer", &dbv)) { + _snprintf(jid, sizeof(jid), "%s@%s", from, dbv.pszVal); + DBFreeVariant(&dbv); + } else { + strcpy(jid, from); + } + ask = !IsAuthorized(proto, jid); + ignore = FALSE; + } else if (voiceChatPolicy == TLEN_MUC_ACCEPT_ALL) { + ask = FALSE; + ignore = FALSE; + } + if (ignore) { + if (proto->isOnline) { + JabberSend(proto, "", from, id); + } + JabberListRemove(proto, LIST_VOICE, id); + } else { + item->nick = mir_strdup(from); + if (ask) { + ACCEPTDIALOGDATA *data = (ACCEPTDIALOGDATA *)mir_alloc(sizeof(ACCEPTDIALOGDATA)); + data->proto = proto; + data->item = item; + JabberForkThread((void (__cdecl *)(void*))TlenVoiceAcceptDlgThread, 0, data); + } else if (proto->isOnline) { + item->ft = TlenFileCreateFT(proto, from); + item->ft->iqId = mir_strdup(id); + TlenVoiceStart(item->ft, 2); + JabberSend(proto, "", item->nick, item->jid); + } + } + return 1; + } + } + return 0; +} + +int TlenVoiceBuildInDeviceList(TlenProtocol *proto, HWND hWnd) +{ int i, j, iNumDevs; + WAVEINCAPS wic; + iNumDevs = waveInGetNumDevs(); + SendMessage(hWnd, CB_ADDSTRING, 0, (LPARAM)TranslateT("Default")); + for (i = j = 0; i < iNumDevs; i++) { + if (!waveInGetDevCaps(i, &wic, sizeof(WAVEINCAPS))) { + if (wic.dwFormats != 0) { + SendMessage(hWnd, CB_ADDSTRING, 0, (LPARAM)wic.szPname); + j++; + } + } + } + i = DBGetContactSettingWord(NULL, proto->m_szModuleName, "VoiceDeviceIn", 0); + if (i>j) i = 0; + SendMessage(hWnd, CB_SETCURSEL, i, 0); + return 0; +} + +int TlenVoiceBuildOutDeviceList(TlenProtocol *proto, HWND hWnd) +{ int i, j, iNumDevs; + WAVEOUTCAPS woc; + iNumDevs = waveInGetNumDevs(); + SendMessage(hWnd, CB_ADDSTRING, 0, (LPARAM)TranslateT("Default")); + for (i = j = 0; i < iNumDevs; i++) { + if (!waveOutGetDevCaps(i, &woc, sizeof(WAVEOUTCAPS))) { + if (woc.dwFormats != 0) { + SendMessage(hWnd, CB_ADDSTRING, 0, (LPARAM)woc.szPname); + j++; + } + } + } + i = DBGetContactSettingWord(NULL, proto->m_szModuleName, "VoiceDeviceOut", 0); + if (i>j) i = 0; + SendMessage(hWnd, CB_SETCURSEL, i, 0); + return 0; +} diff --git a/protocols/Tlen/src/tlen_voice.h b/protocols/Tlen/src/tlen_voice.h new file mode 100644 index 0000000000..0018bb6e17 --- /dev/null +++ b/protocols/Tlen/src/tlen_voice.h @@ -0,0 +1,70 @@ +/* + +Tlen Protocol Plugin for Miranda NG +Copyright (C) 2004-2007 Piotr Piastucki + +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. + +*/ + +#ifndef _TLEN_VOICE_H_ +#define _TLEN_VOICE_H_ + +#include +#include + +#include "jabber.h" +extern "C" { + #include "codec/gsm.h" +} + +typedef struct TLEN_VOICE_CONTROL_STRUCT { + int waveMode; + int codec; + int bDisable; + + short *recordingData; + short *waveData; + WAVEHDR *waveHeaders; + int waveFrameSize; + int waveHeadersPos; + int waveHeadersNum; + +// HANDLE hEvent; + HANDLE hThread; + DWORD threadID; + HWAVEOUT hWaveOut; + HWAVEIN hWaveIn; + int isRunning; + int stopThread; + gsm_state *gsmstate; + TLEN_FILE_TRANSFER *ft; + int vuMeter; + int bytesSum; + TlenProtocol *proto; +} TLEN_VOICE_CONTROL; + + +extern void __cdecl TlenVoiceSendingThread(TLEN_FILE_TRANSFER *ft); +extern void __cdecl TlenVoiceReceiveThread(TLEN_FILE_TRANSFER *ft); +extern int TlenVoiceIsInUse(TlenProtocol *proto); +extern INT_PTR TlenVoiceContactMenuHandleVoice(void *ptr, LPARAM wParam, LPARAM lParam); +extern int TlenVoiceCancelAll(TlenProtocol *proto); +extern int TlenVoiceStart(TLEN_FILE_TRANSFER *ft, int mode) ; +extern int TlenVoiceAccept(TlenProtocol *proto, const char *id, const char *from); +extern int TlenVoiceBuildInDeviceList(TlenProtocol *proto, HWND hWnd); +extern int TlenVoiceBuildOutDeviceList(TlenProtocol *proto, HWND hWnd); +#endif + -- cgit v1.2.3