summaryrefslogtreecommitdiff
path: root/protocols/Gadu-Gadu
diff options
context:
space:
mode:
Diffstat (limited to 'protocols/Gadu-Gadu')
-rw-r--r--protocols/Gadu-Gadu/gg.cpp2
-rw-r--r--protocols/Gadu-Gadu/gg_proto.cpp805
-rw-r--r--protocols/Gadu-Gadu/gg_proto.h301
3 files changed, 1107 insertions, 1 deletions
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 <ono+miranda@java.pl>
+// 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 <ono+miranda@java.pl>
+// 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