From 3b3200e91d1c76f0fdd6565c3c3bc1824d1a4a03 Mon Sep 17 00:00:00 2001 From: George Hazan Date: Sun, 15 Jul 2012 16:48:11 +0000 Subject: missing files git-svn-id: http://svn.miranda-ng.org/main/trunk@978 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- protocols/Gadu-Gadu/gg.cpp | 2 +- protocols/Gadu-Gadu/gg_proto.cpp | 805 +++++++++++++++++++++++++++++++++++++++ protocols/Gadu-Gadu/gg_proto.h | 301 +++++++++++++++ 3 files changed, 1107 insertions(+), 1 deletion(-) create mode 100644 protocols/Gadu-Gadu/gg_proto.cpp create mode 100644 protocols/Gadu-Gadu/gg_proto.h diff --git a/protocols/Gadu-Gadu/gg.cpp b/protocols/Gadu-Gadu/gg.cpp index 023d620f1a..11f2e3ce2d 100644 --- a/protocols/Gadu-Gadu/gg.cpp +++ b/protocols/Gadu-Gadu/gg.cpp @@ -33,7 +33,7 @@ PLUGININFOEX pluginInfo = { "dezred"/*antispam*/"@"/*antispam*/"gmail"/*antispam*/"."/*antispam*/"com", "© 2009-2012 Bartosz Białek, 2003-2009 Adam Strzelecki", "http://www.miranda-im.pl/", - 0, + UNICODE_AWARE, // {F3FF65F3-250E-416A-BEE9-58C93F85AB33} { 0xf3ff65f3, 0x250e, 0x416a, { 0xbe, 0xe9, 0x58, 0xc9, 0x3f, 0x85, 0xab, 0x33 } } }; diff --git a/protocols/Gadu-Gadu/gg_proto.cpp b/protocols/Gadu-Gadu/gg_proto.cpp new file mode 100644 index 0000000000..f9097a9900 --- /dev/null +++ b/protocols/Gadu-Gadu/gg_proto.cpp @@ -0,0 +1,805 @@ +//////////////////////////////////////////////////////////////////////////////// +// Gadu-Gadu Plugin for Miranda IM +// +// Copyright (c) 2003-2009 Adam Strzelecki +// Copyright (c) 2009-2012 Bartosz Białek +// +// 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 "gg.h" + +GGPROTO::GGPROTO(const char* pszProtoName, const TCHAR* tszUserName) +{ + // Init mutexes + InitializeCriticalSection(&sess_mutex); + InitializeCriticalSection(&ft_mutex); + InitializeCriticalSection(&img_mutex); + InitializeCriticalSection(&modemsg_mutex); + InitializeCriticalSection(&avatar_mutex); + InitializeCriticalSection(&sessions_mutex); + + // Init instance names + m_szModuleName = mir_strdup(pszProtoName); + m_szProtoName = GGDEF_PROTONAME; + m_iVersion = 2; + + // Register netlib user + TCHAR name[128]; + mir_sntprintf(name, SIZEOF(name), TranslateT("%s connection"), m_tszUserName); + + NETLIBUSER nlu = { 0 }; + nlu.cbSize = sizeof(nlu); + nlu.flags = NUF_TCHAR | NUF_OUTGOING | NUF_INCOMING | NUF_HTTPCONNS; + nlu.szSettingsModule = m_szModuleName; + nlu.ptszDescriptiveName = name; + + netlib = (HANDLE)CallService(MS_NETLIB_REGISTERUSER, 0, (LPARAM)&nlu); + + // Register services + createProtoService(PS_GETAVATARCAPS, &GGPROTO::getavatarcaps); + createProtoService(PS_GETAVATARINFOT, &GGPROTO::getavatarinfo); + createProtoService(PS_GETMYAVATAR, &GGPROTO::getmyavatar); + createProtoService(PS_SETMYAVATAR, &GGPROTO::setmyavatar); + + createProtoService(PS_GETMYAWAYMSG, &GGPROTO::getmyawaymsg); + createProtoService(PS_CREATEACCMGRUI, &GGPROTO::get_acc_mgr_gui); + + createProtoService(PS_LEAVECHAT, &GGPROTO::leavechat); + + // Offline contacts and clear logon time + setalloffline(); + db_set_w(NULL, m_szModuleName, GG_KEY_LOGONTIME, 0); + + DWORD dwVersion; + if ((dwVersion = db_get_b(NULL, m_szModuleName, GG_PLUGINVERSION, 0)) < pluginInfo.version) + cleanuplastplugin(dwVersion); + + links_instance_init(); + initavatarrequestthread(); + + TCHAR szPath[MAX_PATH]; + TCHAR *tmpPath = Utils_ReplaceVarsT( _T("%miranda_avatarcache%")); + mir_sntprintf(szPath, MAX_PATH, _T("%s\\%s"), tmpPath, m_szModuleName); + mir_free(tmpPath); + hAvatarsFolder = FoldersRegisterCustomPathT(m_szModuleName, "Avatars", szPath); + + tmpPath = Utils_ReplaceVarsT( _T("%miranda_userdata%")); + mir_sntprintf(szPath, MAX_PATH, _T("%s\\%s\\ImageCache"), tmpPath, m_szModuleName); + mir_free(tmpPath); + hImagesFolder = FoldersRegisterCustomPathT(m_szModuleName, "Images", szPath); +} + +GGPROTO::~GGPROTO() +{ +#ifdef DEBUGMODE + netlog("gg_proto_uninit(): destroying protocol interface"); +#endif + + // Destroy modules + block_uninit(); + img_destroy(); + keepalive_destroy(); + gc_destroy(); + + if (hMenuRoot) + CallService(MS_CLIST_REMOVEMAINMENUITEM, (WPARAM)hMenuRoot, 0); + + // Close handles + Netlib_CloseHandle(netlib); + + // Destroy mutexes + DeleteCriticalSection(&sess_mutex); + DeleteCriticalSection(&ft_mutex); + DeleteCriticalSection(&img_mutex); + DeleteCriticalSection(&modemsg_mutex); + DeleteCriticalSection(&avatar_mutex); + DeleteCriticalSection(&sessions_mutex); + + // Free status messages + if (modemsg.online) mir_free(modemsg.online); + if (modemsg.away) mir_free(modemsg.away); + if (modemsg.dnd) mir_free(modemsg.dnd); + if (modemsg.freechat) mir_free(modemsg.freechat); + if (modemsg.invisible) mir_free(modemsg.invisible); + if (modemsg.offline) mir_free(modemsg.offline); + + mir_free(m_szModuleName); + mir_free(m_tszUserName); +} + +////////////////////////////////////////////////////////// +// Dummies for function that have to be implemented + +HANDLE GGPROTO::AddToListByEvent(int flags, int iContact, HANDLE hDbEvent) { return NULL; } +int GGPROTO::Authorize(HANDLE hContact) { return 0; } +int GGPROTO::AuthDeny(HANDLE hContact, const TCHAR *szReason) { return 0; } +int GGPROTO::AuthRecv(HANDLE hContact, PROTORECVEVENT *pre) { return 0; } +int GGPROTO::AuthRequest(HANDLE hContact, const TCHAR *szMessage) { return 0; } +HANDLE GGPROTO::ChangeInfo(int iInfoType, void *pInfoData) { return NULL; } +int GGPROTO::FileResume(HANDLE hTransfer, int *action, const PROTOCHAR** szFilename) { return 0; } +HANDLE GGPROTO::SearchByEmail(const PROTOCHAR *email) { return NULL; } +int GGPROTO::RecvContacts(HANDLE hContact, PROTORECVEVENT *pre) { return 0; } +int GGPROTO::RecvUrl(HANDLE hContact, PROTORECVEVENT *pre) { return 0; } +int GGPROTO::SendContacts(HANDLE hContact, int flags, int nContacts, HANDLE *hContactsList) { return 0; } +int GGPROTO::SendUrl(HANDLE hContact, int flags, const char *url) { return 0; } +int GGPROTO::RecvAwayMsg(HANDLE hContact, int mode, PROTORECVEVENT *evt) { return 0; } +int GGPROTO::SendAwayMsg(HANDLE hContact, HANDLE hProcess, const char *msg) { return 0; } + +////////////////////////////////////////////////////////// +// when contact is added to list + +HANDLE GGPROTO::AddToList(int flags, PROTOSEARCHRESULT *psr) +{ + GGSEARCHRESULT *sr = (GGSEARCHRESULT *)psr; + uin_t uin; + + if (psr->cbSize == sizeof(GGSEARCHRESULT)) + uin = sr->uin; + else + uin = _ttoi(psr->id); + + return getcontact(uin, 1, flags & PALF_TEMPORARY ? 0 : 1, sr->nick); +} + +////////////////////////////////////////////////////////// +// checks proto capabilities + +DWORD_PTR GGPROTO::GetCaps(int type, HANDLE hContact) +{ + switch (type) { + case PFLAGNUM_1: + return PF1_IM | PF1_BASICSEARCH | PF1_EXTSEARCH | PF1_EXTSEARCHUI | PF1_SEARCHBYNAME | + PF1_MODEMSG | PF1_NUMERICUSERID | PF1_VISLIST | PF1_FILE; + case PFLAGNUM_2: + return PF2_ONLINE | PF2_SHORTAWAY | PF2_HEAVYDND | PF2_FREECHAT | PF2_INVISIBLE | + PF2_LONGAWAY; + case PFLAGNUM_3: + return PF2_ONLINE | PF2_SHORTAWAY | PF2_HEAVYDND | PF2_FREECHAT | PF2_INVISIBLE; + case PFLAGNUM_4: + return PF4_NOCUSTOMAUTH | PF4_SUPPORTTYPING | PF4_AVATARS | PF4_IMSENDOFFLINE; + case PFLAGNUM_5: + return PF2_LONGAWAY; + case PFLAG_UNIQUEIDTEXT: + return (DWORD_PTR) Translate("Gadu-Gadu Number"); + case PFLAG_UNIQUEIDSETTING: + return (DWORD_PTR) GG_KEY_UIN; + } + return 0; +} + +////////////////////////////////////////////////////////// +// loads protocol icon + +HICON GGPROTO::GetIcon(int iconIndex) +{ + if (LOWORD(iconIndex) == PLI_PROTOCOL) + { + if (iconIndex & PLIF_ICOLIBHANDLE) + return (HICON)GetIconHandle(IDI_GG); + + BOOL big = (iconIndex & PLIF_SMALL) == 0; + HICON hIcon = LoadIconEx("main", big); + + if (iconIndex & PLIF_ICOLIB) + return hIcon; + + hIcon = CopyIcon(hIcon); + ReleaseIconEx("main", big); + return hIcon; + } + + return (HICON)NULL; +} + +////////////////////////////////////////////////////////// +// user info request + +void __cdecl GGPROTO::cmdgetinfothread(void *hContact) +{ + SleepEx(100, FALSE); + netlog("gg_cmdgetinfothread(): Failed info retreival."); + ProtoBroadcastAck(m_szModuleName, hContact, ACKTYPE_GETINFO, ACKRESULT_FAILED, (HANDLE) 1, 0); +} + +int GGPROTO::GetInfo(HANDLE hContact, int infoType) +{ + gg_pubdir50_t req; + + // Custom contact info + if (hContact) + { + if (!(req = gg_pubdir50_new(GG_PUBDIR50_SEARCH))) + { + forkthread(&GGPROTO::cmdgetinfothread, hContact); + return 1; + } + + // Add uin and search it + gg_pubdir50_add(req, GG_PUBDIR50_UIN, ditoa((uin_t)db_get_b(hContact, m_szModuleName, GG_KEY_UIN, 0))); + gg_pubdir50_seq_set(req, GG_SEQ_INFO); + + netlog("gg_getinfo(): Requesting user info.", req->seq); + if (isonline()) + { + EnterCriticalSection(&sess_mutex); + if (!gg_pubdir50(sess, req)) + { + LeaveCriticalSection(&sess_mutex); + forkthread(&GGPROTO::cmdgetinfothread, hContact); + return 1; + } + LeaveCriticalSection(&sess_mutex); + } + } + // Own contact info + else + { + if (!(req = gg_pubdir50_new(GG_PUBDIR50_READ))) + { + forkthread(&GGPROTO::cmdgetinfothread, hContact); + return 1; + } + + // Add seq + gg_pubdir50_seq_set(req, GG_SEQ_CHINFO); + + netlog("gg_getinfo(): Requesting owner info.", req->seq); + if (isonline()) + { + EnterCriticalSection(&sess_mutex); + if (!gg_pubdir50(sess, req)) + { + LeaveCriticalSection(&sess_mutex); + forkthread(&GGPROTO::cmdgetinfothread, hContact); + return 1; + } + LeaveCriticalSection(&sess_mutex); + } + } + netlog("gg_getinfo(): Seq %d.", req->seq); + gg_pubdir50_free(req); + + return 1; +} + +////////////////////////////////////////////////////////// +// when basic search + +void __cdecl GGPROTO::searchthread(void *) +{ + SleepEx(100, FALSE); + netlog("gg_searchthread(): Failed search."); + ProtoBroadcastAck(m_szModuleName, NULL, ACKTYPE_SEARCH, ACKRESULT_FAILED, (HANDLE)1, 0); +} + +HANDLE GGPROTO::SearchBasic(const PROTOCHAR *id) +{ + if (!isonline()) + return (HANDLE)0; + + gg_pubdir50_t req; + if (!(req = gg_pubdir50_new(GG_PUBDIR50_SEARCH))) { + forkthread(&GGPROTO::searchthread, NULL); + return (HANDLE)1; + } + + TCHAR *ida = mir_tstrdup(id); + + // Add uin and search it + gg_pubdir50_add(req, GG_PUBDIR50_UIN, _T2A(ida)); + gg_pubdir50_seq_set(req, GG_SEQ_SEARCH); + + mir_free(ida); + + EnterCriticalSection(&sess_mutex); + if (!gg_pubdir50(sess, req)) + { + LeaveCriticalSection(&sess_mutex); + forkthread(&GGPROTO::searchthread, NULL); + return (HANDLE)1; + } + LeaveCriticalSection(&sess_mutex); + netlog("gg_basicsearch(): Seq %d.", req->seq); + gg_pubdir50_free(req); + + return (HANDLE)1; +} + +////////////////////////////////////////////////////////// +// search by details + +HANDLE GGPROTO::SearchByName(const PROTOCHAR *nick, const PROTOCHAR *firstName, const PROTOCHAR *lastName) +{ + gg_pubdir50_t req; + unsigned long crc; + char data[512] = "\0"; + + // Check if connected and if there's a search data + if (!isonline()) + return 0; + + if (!nick && !firstName && !lastName) + return 0; + + if (!(req = gg_pubdir50_new(GG_PUBDIR50_SEARCH))) + { + forkthread(&GGPROTO::searchthread, NULL); + return (HANDLE)1; + } + + // Add uin and search it + if (nick) + { + char *nickA = mir_t2a(nick); + gg_pubdir50_add(req, GG_PUBDIR50_NICKNAME, nickA); + strncat(data, nickA, sizeof(data) - strlen(data)); + mir_free(nickA); + } + strncat(data, ".", sizeof(data) - strlen(data)); + + if (firstName) + { + char *firstNameA = mir_t2a(firstName); + gg_pubdir50_add(req, GG_PUBDIR50_FIRSTNAME, firstNameA); + strncat(data, firstNameA, sizeof(data) - strlen(data)); + mir_free(firstNameA); + } + strncat(data, ".", sizeof(data) - strlen(data)); + + if (lastName) + { + char *lastNameA = mir_t2a(lastName); + gg_pubdir50_add(req, GG_PUBDIR50_LASTNAME, lastNameA); + strncat(data, lastNameA, sizeof(data) - strlen(data)); + mir_free(lastNameA); + } + strncat(data, ".", sizeof(data) - strlen(data)); + + // Count crc & check if the data was equal if yes do same search with shift + crc = crc_get(data); + + if (crc == last_crc && next_uin) + gg_pubdir50_add(req, GG_PUBDIR50_START, ditoa(next_uin)); + else + last_crc = crc; + + gg_pubdir50_seq_set(req, GG_SEQ_SEARCH); + + EnterCriticalSection(&sess_mutex); + if (!gg_pubdir50(sess, req)) + { + LeaveCriticalSection(&sess_mutex); + forkthread(&GGPROTO::searchthread, NULL); + return (HANDLE)1; + } + LeaveCriticalSection(&sess_mutex); + netlog("gg_searchbyname(): Seq %d.", req->seq); + gg_pubdir50_free(req); + + return (HANDLE)1; +} + +////////////////////////////////////////////////////////// +// search by advanced + +HWND GGPROTO::SearchAdvanced(HWND hwndDlg) +{ + gg_pubdir50_t req; + char text[64], data[512] = "\0"; + unsigned long crc; + + // Check if connected + if (!isonline()) return (HWND)0; + + if (!(req = gg_pubdir50_new(GG_PUBDIR50_SEARCH))) + { + forkthread(&GGPROTO::searchthread, NULL); + return (HWND)1; + } + + // Fetch search data + GetDlgItemTextA(hwndDlg, IDC_FIRSTNAME, text, sizeof(text)); + if (strlen(text)) + { + gg_pubdir50_add(req, GG_PUBDIR50_FIRSTNAME, text); + strncat(data, text, sizeof(data) - strlen(data)); + } + /* 1 */ strncat(data, ".", sizeof(data) - strlen(data)); + + GetDlgItemTextA(hwndDlg, IDC_LASTNAME, text, sizeof(text)); + if (strlen(text)) + { + gg_pubdir50_add(req, GG_PUBDIR50_LASTNAME, text); + strncat(data, text, sizeof(data) - strlen(data)); + } + /* 2 */ strncat(data, ".", sizeof(data) - strlen(data)); + + GetDlgItemTextA(hwndDlg, IDC_NICKNAME, text, sizeof(text)); + if (strlen(text)) + { + gg_pubdir50_add(req, GG_PUBDIR50_NICKNAME, text); + strncat(data, text, sizeof(data) - strlen(data)); + } + /* 3 */ strncat(data, ".", sizeof(data) - strlen(data)); + + GetDlgItemTextA(hwndDlg, IDC_CITY, text, sizeof(text)); + if (strlen(text)) + { + gg_pubdir50_add(req, GG_PUBDIR50_CITY, text); + strncat(data, text, sizeof(data) - strlen(data)); + } + /* 4 */ strncat(data, ".", sizeof(data) - strlen(data)); + + GetDlgItemTextA(hwndDlg, IDC_AGEFROM, text, sizeof(text)); + if (strlen(text)) + { + int yearTo = atoi(text); + int yearFrom; + time_t t = time(NULL); + struct tm *lt = localtime(&t); + int ay = lt->tm_year + 1900; + char age[16]; + + GetDlgItemTextA(hwndDlg, IDC_AGETO, age, sizeof(age)); + yearFrom = atoi(age); + + // Count & fix ranges + if (!yearTo) + yearTo = ay; + else + yearTo = ay - yearTo; + if (!yearFrom) + yearFrom = 0; + else + yearFrom = ay - yearFrom; + mir_snprintf(text, sizeof(text), "%d %d", yearFrom, yearTo); + + gg_pubdir50_add(req, GG_PUBDIR50_BIRTHYEAR, text); + strncat(data, text, sizeof(data) - strlen(data)); + } + /* 5 */ strncat(data, ".", sizeof(data) - strlen(data)); + + switch(SendDlgItemMessage(hwndDlg, IDC_GENDER, CB_GETCURSEL, 0, 0)) + { + case 1: + gg_pubdir50_add(req, GG_PUBDIR50_GENDER, GG_PUBDIR50_GENDER_FEMALE); + strncat(data, GG_PUBDIR50_GENDER_MALE, sizeof(data) - strlen(data)); + break; + case 2: + gg_pubdir50_add(req, GG_PUBDIR50_GENDER, GG_PUBDIR50_GENDER_MALE); + strncat(data, GG_PUBDIR50_GENDER_FEMALE, sizeof(data) - strlen(data)); + break; + } + /* 6 */ strncat(data, ".", sizeof(data) - strlen(data)); + + if (IsDlgButtonChecked(hwndDlg, IDC_ONLYCONNECTED)) + { + gg_pubdir50_add(req, GG_PUBDIR50_ACTIVE, GG_PUBDIR50_ACTIVE_TRUE); + strncat(data, GG_PUBDIR50_ACTIVE_TRUE, sizeof(data) - strlen(data)); + } + /* 7 */ strncat(data, ".", sizeof(data) - strlen(data)); + + // No data entered + if (strlen(data) <= 7 || (strlen(data) == 8 && IsDlgButtonChecked(hwndDlg, IDC_ONLYCONNECTED))) return (HWND)0; + + // Count crc & check if the data was equal if yes do same search with shift + crc = crc_get(data); + + if (crc == last_crc && next_uin) + gg_pubdir50_add(req, GG_PUBDIR50_START, ditoa(next_uin)); + else + last_crc = crc; + + gg_pubdir50_seq_set(req, GG_SEQ_SEARCH); + + if (isonline()) + { + EnterCriticalSection(&sess_mutex); + if (!gg_pubdir50(sess, req)) + { + LeaveCriticalSection(&sess_mutex); + forkthread(&GGPROTO::searchthread, NULL); + return (HWND)1; + } + LeaveCriticalSection(&sess_mutex); + } + netlog("gg_searchbyadvanced(): Seq %d.", req->seq); + gg_pubdir50_free(req); + + return (HWND)1; +} + +////////////////////////////////////////////////////////// +// create adv search dialog + +static INT_PTR CALLBACK gg_advancedsearchdlgproc(HWND hwndDlg,UINT message,WPARAM wParam,LPARAM lParam) +{ + switch(message) { + case WM_INITDIALOG: + TranslateDialogDefault(hwndDlg); + SendDlgItemMessage(hwndDlg, IDC_GENDER, CB_ADDSTRING, 0, (LPARAM)_T("")); // 0 + SendDlgItemMessage(hwndDlg, IDC_GENDER, CB_ADDSTRING, 0, (LPARAM)Translate("Female")); // 1 + SendDlgItemMessage(hwndDlg, IDC_GENDER, CB_ADDSTRING, 0, (LPARAM)Translate("Male")); // 2 + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDOK: + SendMessage(GetParent(hwndDlg), WM_COMMAND,MAKEWPARAM(IDOK,BN_CLICKED), (LPARAM)GetDlgItem(GetParent(hwndDlg),IDOK)); + break; + } + break; + } + return FALSE; +} + +HWND GGPROTO::CreateExtendedSearchUI(HWND owner) +{ + return CreateDialogParam(hInstance, + MAKEINTRESOURCE(IDD_GGADVANCEDSEARCH), owner, gg_advancedsearchdlgproc, (LPARAM)this); +} + +////////////////////////////////////////////////////////// +// when messsage received + +int GGPROTO::RecvMsg(HANDLE hContact, PROTORECVEVENT *pre) +{ + CCSDATA ccs = { hContact, PSR_MESSAGE, 0, ( LPARAM )pre }; + return CallService(MS_PROTO_RECVMSG, 0, ( LPARAM )&ccs); +} + +////////////////////////////////////////////////////////// +// when messsage sent + +typedef struct +{ + HANDLE hContact; + int seq; +} GG_SEQ_ACK; + +void __cdecl GGPROTO::sendackthread(void *ack) +{ + SleepEx(100, FALSE); + ProtoBroadcastAck(m_szModuleName, ((GG_SEQ_ACK *)ack)->hContact, + ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, (HANDLE) ((GG_SEQ_ACK *)ack)->seq, 0); + mir_free(ack); +} + +int GGPROTO::SendMsg(HANDLE hContact, int flags, const char *msg) +{ + uin_t uin; + + if (msg && isonline() && (uin = (uin_t)db_get_b(hContact, m_szModuleName, GG_KEY_UIN, 0))) + { + int seq; + EnterCriticalSection(&sess_mutex); + seq = gg_send_message(sess, GG_CLASS_CHAT, uin, (BYTE*)msg); + LeaveCriticalSection(&sess_mutex); + if (!db_get_b(NULL, m_szModuleName, GG_KEY_MSGACK, GG_KEYDEF_MSGACK)) + { + // Auto-ack message without waiting for server ack + GG_SEQ_ACK *ack = (GG_SEQ_ACK*)mir_alloc(sizeof(GG_SEQ_ACK)); + if (ack) + { + ack->seq = seq; + ack->hContact = hContact; + forkthread(&GGPROTO::sendackthread, ack); + } + } + return seq; + } + return 0; +} + +////////////////////////////////////////////////////////// +// visible lists + +int GGPROTO::SetApparentMode(HANDLE hContact, int mode) +{ + db_set_w(hContact, m_szModuleName, GG_KEY_APPARENT, (WORD)mode); + notifyuser(hContact, 1); + return 0; +} + +////////////////////////////////////////////////////////// +// sets protocol status + +int GGPROTO::SetStatus(int iNewStatus) +{ + int nNewStatus = gg_normalizestatus(iNewStatus); + + EnterCriticalSection(&modemsg_mutex); + m_iDesiredStatus = nNewStatus; + LeaveCriticalSection(&modemsg_mutex); + + // If waiting for connection retry attempt then signal to stop that + if (hConnStopEvent) SetEvent(hConnStopEvent); + + if (m_iStatus == nNewStatus) return 0; + netlog("gg_setstatus(): PS_SETSTATUS(%d) normalized to %d.", iNewStatus, nNewStatus); + refreshstatus(nNewStatus); + + return 0; +} + +////////////////////////////////////////////////////////// +// when away message is requested + +void __cdecl GGPROTO::getawaymsgthread(void *hContact) +{ + DBVARIANT dbv; + + SleepEx(100, FALSE); + if (!db_get_s(hContact, "CList", GG_KEY_STATUSDESCR, &dbv, DBVT_TCHAR)) + { + ProtoBroadcastAck(m_szProtoName, hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE) 1, (LPARAM) dbv.ptszVal); + netlog("gg_getawaymsg(): Reading away msg <" TCHAR_STR_PARAM ">.", dbv.ptszVal); + DBFreeVariant(&dbv); + } + else + ProtoBroadcastAck(m_szProtoName, hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE) 1, (LPARAM) NULL); +} + +HANDLE GGPROTO::GetAwayMsg(HANDLE hContact) +{ + forkthread(&GGPROTO::getawaymsgthread, hContact); + return (HANDLE)1; +} + +////////////////////////////////////////////////////////// +// when away message is being set + +int GGPROTO::SetAwayMsg(int iStatus, const PROTOCHAR *msgt) +{ + int status = gg_normalizestatus(iStatus); + char **szMsg; + char *msg = mir_t2a(msgt); + + netlog("gg_setawaymsg(): PS_SETAWAYMSG(%d, \"%s\").", iStatus, msg); + + EnterCriticalSection(&modemsg_mutex); + // Select proper msg + switch(status) + { + case ID_STATUS_ONLINE: + szMsg = &modemsg.online; + break; + case ID_STATUS_AWAY: + szMsg = &modemsg.away; + break; + case ID_STATUS_DND: + szMsg = &modemsg.dnd; + break; + case ID_STATUS_FREECHAT: + szMsg = &modemsg.freechat; + break; + case ID_STATUS_INVISIBLE: + szMsg = &modemsg.invisible; + break; + default: + LeaveCriticalSection(&modemsg_mutex); + mir_free(msg); + return 1; + } + + // Check if we change status here somehow + if (*szMsg && msg && !strcmp(*szMsg, msg) + || !*szMsg && (!msg || !*msg)) + { + if (status == m_iDesiredStatus && m_iDesiredStatus == m_iStatus) + { + netlog("gg_setawaymsg(): Message hasn't been changed, return."); + LeaveCriticalSection(&modemsg_mutex); + mir_free(msg); + return 0; + } + } + else + { + if (*szMsg) + mir_free(*szMsg); + *szMsg = msg && *msg ? mir_strdup(msg) : NULL; +#ifdef DEBUGMODE + netlog("gg_setawaymsg(): Message changed."); +#endif + } + LeaveCriticalSection(&modemsg_mutex); + + // Change the status if it was desired by PS_SETSTATUS + if (status == m_iDesiredStatus) + refreshstatus(status); + + mir_free(msg); + return 0; +} + +////////////////////////////////////////////////////////// +// sends a notification that the user is typing a message + +int GGPROTO::UserIsTyping(HANDLE hContact, int type) +{ + uin_t uin = db_get_b(hContact, m_szModuleName, GG_KEY_UIN, 0); + + if (!uin || !isonline()) return 0; + + if (type == PROTOTYPE_SELFTYPING_ON || type == PROTOTYPE_SELFTYPING_OFF) { + EnterCriticalSection(&sess_mutex); + gg_typing_notification(sess, uin, (type == PROTOTYPE_SELFTYPING_ON)); + LeaveCriticalSection(&sess_mutex); + } + + return 0; +} + +////////////////////////////////////////////////////////// +// Custom protocol event + +int GGPROTO::OnEvent(PROTOEVENTTYPE eventType, WPARAM wParam, LPARAM lParam) +{ + switch( eventType ) { + case EV_PROTO_ONLOAD: + { + hookProtoEvent(ME_OPT_INITIALISE, &GGPROTO::options_init); + hookProtoEvent(ME_USERINFO_INITIALISE, &GGPROTO::details_init); + + // Init misc stuff + gg_icolib_init(); + initpopups(); + gc_init(); + keepalive_init(); + img_init(); + block_init(); + + // Try to fetch user avatar + getUserAvatar(); + break; + } + case EV_PROTO_ONEXIT: + // Stop avatar request thread + uninitavatarrequestthread(); + + // Stop main connection session thread + threadwait(&pth_sess); + img_shutdown(); + sessions_closedlg(); + break; + + case EV_PROTO_ONOPTIONS: + return options_init(wParam, lParam); + + case EV_PROTO_ONMENU: + menus_init(); + break; + + case EV_PROTO_ONRENAME: + if (hMenuRoot) { + CLISTMENUITEM mi = {0}; + mi.cbSize = sizeof(mi); + mi.flags = CMIM_NAME | CMIF_TCHAR | CMIF_KEEPUNTRANSLATED; + mi.ptszName = m_tszUserName; + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuRoot, (LPARAM)&mi); + } + break; + + case EV_PROTO_ONCONTACTDELETED: + return contactdeleted(wParam, lParam); + + case EV_PROTO_DBSETTINGSCHANGED: + return dbsettingchanged(wParam, lParam); + } + return TRUE; +} + diff --git a/protocols/Gadu-Gadu/gg_proto.h b/protocols/Gadu-Gadu/gg_proto.h new file mode 100644 index 0000000000..57271e7ad5 --- /dev/null +++ b/protocols/Gadu-Gadu/gg_proto.h @@ -0,0 +1,301 @@ +//////////////////////////////////////////////////////////////////////////////// +// Gadu-Gadu Plugin for Miranda IM +// +// Copyright (c) 2003-2009 Adam Strzelecki +// Copyright (c) 2009-2012 Bartosz Białek +// +// 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 GGPROTO_H +#define GGPROTO_H + +struct GGPROTO; +typedef void ( __cdecl GGPROTO::*GGThreadFunc )( void* ); +typedef int ( __cdecl GGPROTO::*GGEventFunc )( WPARAM, LPARAM ); +typedef INT_PTR ( __cdecl GGPROTO::*GGServiceFunc )( WPARAM, LPARAM ); + +struct GGPROTO : public PROTO_INTERFACE +{ + GGPROTO( const char*, const TCHAR* ); + ~GGPROTO(); + + __inline void* operator new( size_t size ) + { return calloc( 1, size ); + } + __inline void operator delete( void* p ) + { free( p ); + } + + //==================================================================================== + // 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 hContact ); + virtual int __cdecl AuthDeny( HANDLE hContact, const TCHAR* szReason ); + virtual int __cdecl AuthRecv( HANDLE hContact, PROTORECVEVENT* ); + virtual int __cdecl AuthRequest( HANDLE hContact, const TCHAR* szMessage ); + + virtual HANDLE __cdecl ChangeInfo( int iInfoType, void* pInfoData ); + + virtual HANDLE __cdecl FileAllow( HANDLE hContact, HANDLE hTransfer, const TCHAR* szPath ); + virtual int __cdecl FileCancel( HANDLE hContact, HANDLE hTransfer ); + virtual int __cdecl FileDeny( HANDLE hContact, HANDLE hTransfer, const TCHAR* szReason ); + virtual int __cdecl FileResume( HANDLE hTransfer, int* action, const TCHAR** 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 TCHAR* id ); + virtual HANDLE __cdecl SearchByEmail( const TCHAR* email ); + virtual HANDLE __cdecl SearchByName( const TCHAR* nick, const TCHAR* firstName, const TCHAR* 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, PROTORECVFILET* ); + 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 TCHAR* szDescription, TCHAR** 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 m_iStatus, const TCHAR* msg ); + + virtual int __cdecl UserIsTyping( HANDLE hContact, int type ); + + virtual int __cdecl OnEvent( PROTOEVENTTYPE eventType, WPARAM wParam, LPARAM lParam ); + + ////////////////////////////////////////////////////////////////////////////////////// + // Services + + INT_PTR __cdecl blockuser(WPARAM wParam, LPARAM lParam); + INT_PTR __cdecl getmyawaymsg(WPARAM wParam, LPARAM lParam); + INT_PTR __cdecl get_acc_mgr_gui(WPARAM wParam, LPARAM lParam); + INT_PTR __cdecl leavechat(WPARAM wParam, LPARAM lParam); + + void __cdecl sendackthread(void *); + void __cdecl searchthread(void *); + void __cdecl cmdgetinfothread(void *hContact); + void __cdecl getawaymsgthread(void *hContact); + void __cdecl dccmainthread(void *); + void __cdecl ftfailthread(void *param); + void __cdecl remindpasswordthread(void *param); + + ////////////////////////////////////////////////////////////////////////////////////// + + /* Helper functions */ + int status_m2gg(int status, int descr); + int status_gg2m(int status); + void checknewuser(uin_t uin, const char* passwd); + + /* Thread functions */ + void forkthread(GGThreadFunc pFunc, void *param); + HANDLE forkthreadex(GGThreadFunc pFunc, void *param, UINT *threadId); + void threadwait(GGTHREAD *thread); + + /* Global GG functions */ + void notifyuser(HANDLE hContact, int refresh); + void setalloffline(); + void disconnect(); + HANDLE getcontact(uin_t uin, int create, int inlist, TCHAR *nick); + void __cdecl mainthread(void *empty); + int isonline(); + int refreshstatus(int status); + + void broadcastnewstatus(int newStatus); + void cleanuplastplugin(DWORD version); + int contactdeleted(WPARAM wParam, LPARAM lParam); + int dbsettingchanged(WPARAM wParam, LPARAM lParam); + void notifyall(); + void changecontactstatus(uin_t uin, int status, const char *idescr, int time, uint32_t remote_ip, uint16_t remote_port, uint32_t version); + char *getstatusmsg(int status); + void dccstart(); + void dccconnect(uin_t uin); + int gettoken(GGTOKEN *token); + void parsecontacts(char *contacts); + void remindpassword(uin_t uin, const char *email); + void menus_init(); + + /* Avatar functions */ + void getAvatarFilename(HANDLE hContact, TCHAR *pszDest, int cbLen); + void getAvatar(HANDLE hContact, char *szAvatarURL); + void requestAvatar(HANDLE hContact, int iWaitFor); + void getUserAvatar(); + void setAvatar(const TCHAR *szFilename); + void getAvatarFileInfo(uin_t uin, char **avatarurl, int *type); + + INT_PTR __cdecl getavatarcaps(WPARAM wParam, LPARAM lParam); + INT_PTR __cdecl getavatarinfo(WPARAM wParam, LPARAM lParam); + INT_PTR __cdecl getmyavatar(WPARAM wParam, LPARAM lParam); + INT_PTR __cdecl setmyavatar(WPARAM wParam, LPARAM lParam); + + void initavatarrequestthread(); + void uninitavatarrequestthread(); + + void __cdecl avatarrequestthread(void*); + void __cdecl getuseravatarthread(void*); + void __cdecl setavatarthread(void*); + + /* File transfer functions */ + HANDLE fileallow(HANDLE hContact, HANDLE hTransfer, const PROTOCHAR* szPath); + int filecancel(HANDLE hContact, HANDLE hTransfer); + int filedeny(HANDLE hContact, HANDLE hTransfer, const PROTOCHAR* szReason); + int recvfile(HANDLE hContact, PROTOFILEEVENT* pre); + HANDLE sendfile(HANDLE hContact, const PROTOCHAR* szDescription, PROTOCHAR** ppszFiles); + + HANDLE dccfileallow(HANDLE hTransfer, const PROTOCHAR* szPath); + HANDLE dcc7fileallow(HANDLE hTransfer, const PROTOCHAR* szPath); + + int dccfiledeny(HANDLE hTransfer); + int dcc7filedeny(HANDLE hTransfer); + + int dccfilecancel(HANDLE hTransfer); + int dcc7filecancel(HANDLE hTransfer); + + /* Import module */ + void import_init(HGENMENU hRoot); + + INT_PTR __cdecl import_server(WPARAM wParam, LPARAM lParam); + INT_PTR __cdecl import_text(WPARAM wParam, LPARAM lParam); + INT_PTR __cdecl remove_server(WPARAM wParam, LPARAM lParam); + INT_PTR __cdecl export_server(WPARAM wParam, LPARAM lParam); + INT_PTR __cdecl export_text(WPARAM wParam, LPARAM lParam); + + /* Keep-alive module */ + void keepalive_init(); + void keepalive_destroy(); + + /* Image reception functions */ + int img_init(); + int img_destroy(); + int img_shutdown(); + int img_sendonrequest(gg_event* e); + BOOL img_opened(uin_t uin); + void *img_loadpicture(gg_event* e, TCHAR *szFileName); + int img_display(HANDLE hContact, void *img); + int img_displayasmsg(HANDLE hContact, void *img); + + void __cdecl img_dlgcallthread(void *param); + + INT_PTR __cdecl img_recvimage(WPARAM wParam, LPARAM lParam); + INT_PTR __cdecl img_sendimg(WPARAM wParam, LPARAM lParam); + + void links_instance_init(); + + /* OAuth functions */ + char *oauth_header(const char *httpmethod, const char *url); + int oauth_checktoken(int force); + int oauth_receivetoken(); + + /* UI page initializers */ + int __cdecl options_init(WPARAM wParam, LPARAM lParam); + int __cdecl details_init(WPARAM wParam, LPARAM lParam); + + /* Groupchat functions */ + int gc_init(); + void gc_menus_init(HGENMENU hRoot); + int gc_destroy(); + char * gc_getchat(uin_t sender, uin_t *recipients, int recipients_count); + GGGC *gc_lookup(char *id); + int gc_changenick(HANDLE hContact, char *pszNick); + #define UIN2ID(uin,id) _itoa(uin,id,10) + + int __cdecl gc_event(WPARAM wParam, LPARAM lParam); + + INT_PTR __cdecl gc_openconf(WPARAM wParam, LPARAM lParam); + INT_PTR __cdecl gc_clearignored(WPARAM wParam, LPARAM lParam); + + /* Popups functions */ + void initpopups(); + void showpopup(const TCHAR* nickname, const TCHAR* msg, int flags); + + /* Sessions functions */ + INT_PTR __cdecl sessions_view(WPARAM wParam, LPARAM lParam); + void sessions_updatedlg(); + BOOL sessions_closedlg(); + void sessions_menus_init(HGENMENU hRoot); + + /* Event helpers */ + void createProtoService(const char* szService, GGServiceFunc serviceProc); + HANDLE hookProtoEvent(const char*, GGEventFunc); + void forkThread(GGThreadFunc, void* ); + HANDLE forkThreadEx(GGThreadFunc, void*, UINT* threadID = NULL); + + // Debug functions + int netlog(const char *fmt, ...); + + void block_init(); + void block_uninit(); + + ////////////////////////////////////////////////////////////////////////////////////// + + CRITICAL_SECTION ft_mutex, sess_mutex, img_mutex, modemsg_mutex, avatar_mutex, sessions_mutex; + list_t watches, transfers, requests, chats, imagedlgs, avatar_requests, avatar_transfers, sessions; + int gc_enabled, gc_id, is_list_remove, check_first_conn; + uin_t next_uin; + unsigned long last_crc; + GGTHREAD pth_dcc; + GGTHREAD pth_sess; + GGTHREAD pth_avatar; + struct gg_session *sess; + struct gg_dcc *dcc; + HANDLE hEvent; + HANDLE hConnStopEvent; + SOCKET sock; + UINT_PTR timer; + struct + { + char *online; + char *away; + char *dnd; + char *freechat; + char *invisible; + char *offline; + } modemsg; + HANDLE netlib; + HGENMENU hMenuRoot; + HGENMENU hMainMenu[7]; + HANDLE hPrebuildMenuHook; + HANDLE hBlockMenuItem; + HANDLE hImageMenuItem; + HANDLE hInstanceMenuItem; + HANDLE hAvatarsFolder; + HANDLE hImagesFolder; + HWND hwndSessionsDlg; +}; + +typedef struct +{ + int mode; + uin_t uin; + char *pass; + char *email; + GGPROTO *gg; +} GGUSERUTILDLGDATA; + +#endif -- cgit v1.2.3