summaryrefslogtreecommitdiff
path: root/plugins/!NotAdopted
diff options
context:
space:
mode:
authorRobert Pösel <robyer@seznam.cz>2013-11-18 20:37:19 +0000
committerRobert Pösel <robyer@seznam.cz>2013-11-18 20:37:19 +0000
commit0e80ad0d4c150fa947849cdad07a7d0d34d7340e (patch)
tree7034b8267ed219c615c4b135778e80a1ede16923 /plugins/!NotAdopted
parent8598a4a7a0bc922c4c1c768b55f596cc6d8a0d44 (diff)
Add sametime protocol sources (not adopted)
git-svn-id: http://svn.miranda-ng.org/main/trunk@6935 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'plugins/!NotAdopted')
-rw-r--r--plugins/!NotAdopted/sametime/StdAfx.cpp8
-rw-r--r--plugins/!NotAdopted/sametime/StdAfx.h24
-rw-r--r--plugins/!NotAdopted/sametime/announce.icobin0 -> 1406 bytes
-rw-r--r--plugins/!NotAdopted/sametime/clist_util.cpp23
-rw-r--r--plugins/!NotAdopted/sametime/clist_util.h9
-rw-r--r--plugins/!NotAdopted/sametime/common.cpp12
-rw-r--r--plugins/!NotAdopted/sametime/common.h106
-rw-r--r--plugins/!NotAdopted/sametime/conference.cpp565
-rw-r--r--plugins/!NotAdopted/sametime/conference.h18
-rw-r--r--plugins/!NotAdopted/sametime/files.cpp421
-rw-r--r--plugins/!NotAdopted/sametime/files.h37
-rw-r--r--plugins/!NotAdopted/sametime/invite.icobin0 -> 318 bytes
-rw-r--r--plugins/!NotAdopted/sametime/messaging.cpp240
-rw-r--r--plugins/!NotAdopted/sametime/messaging.h18
-rw-r--r--plugins/!NotAdopted/sametime/online.icobin0 -> 1150 bytes
-rw-r--r--plugins/!NotAdopted/sametime/options.cpp328
-rw-r--r--plugins/!NotAdopted/sametime/options.h44
-rw-r--r--plugins/!NotAdopted/sametime/part.icobin0 -> 2294 bytes
-rw-r--r--plugins/!NotAdopted/sametime/places.cpp54
-rw-r--r--plugins/!NotAdopted/sametime/places.h11
-rw-r--r--plugins/!NotAdopted/sametime/resource.h57
-rw-r--r--plugins/!NotAdopted/sametime/resource.rc175
-rw-r--r--plugins/!NotAdopted/sametime/sametime.cpp845
-rw-r--r--plugins/!NotAdopted/sametime/sametime.h14
-rw-r--r--plugins/!NotAdopted/sametime/sametime.sln20
-rw-r--r--plugins/!NotAdopted/sametime/sametime.vcproj575
-rw-r--r--plugins/!NotAdopted/sametime/session.cpp566
-rw-r--r--plugins/!NotAdopted/sametime/session.h32
-rw-r--r--plugins/!NotAdopted/sametime/session_announce_win.cpp136
-rw-r--r--plugins/!NotAdopted/sametime/session_announce_win.h15
-rw-r--r--plugins/!NotAdopted/sametime/userlist.cpp909
-rw-r--r--plugins/!NotAdopted/sametime/userlist.h59
-rw-r--r--plugins/!NotAdopted/sametime/utils.cpp335
-rw-r--r--plugins/!NotAdopted/sametime/utils.h37
34 files changed, 5693 insertions, 0 deletions
diff --git a/plugins/!NotAdopted/sametime/StdAfx.cpp b/plugins/!NotAdopted/sametime/StdAfx.cpp
new file mode 100644
index 0000000000..97f31a3db4
--- /dev/null
+++ b/plugins/!NotAdopted/sametime/StdAfx.cpp
@@ -0,0 +1,8 @@
+// stdafx.cpp : source file that includes just the standard includes
+// sametime.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
+
+// TODO: reference any additional headers you need in STDAFX.H
+// and not in this file
diff --git a/plugins/!NotAdopted/sametime/StdAfx.h b/plugins/!NotAdopted/sametime/StdAfx.h
new file mode 100644
index 0000000000..60556805db
--- /dev/null
+++ b/plugins/!NotAdopted/sametime/StdAfx.h
@@ -0,0 +1,24 @@
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently, but
+// are changed infrequently
+//
+
+#if !defined(AFX_STDAFX_H__3A534A59_8FD6_49FB_BB74_4F88440A6B32__INCLUDED_)
+#define AFX_STDAFX_H__3A534A59_8FD6_49FB_BB74_4F88440A6B32__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+
+// Insert your headers here
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+
+#include <windows.h>
+
+// TODO: reference additional headers your program requires here
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_STDAFX_H__3A534A59_8FD6_49FB_BB74_4F88440A6B32__INCLUDED_)
diff --git a/plugins/!NotAdopted/sametime/announce.ico b/plugins/!NotAdopted/sametime/announce.ico
new file mode 100644
index 0000000000..ac9673a7dc
--- /dev/null
+++ b/plugins/!NotAdopted/sametime/announce.ico
Binary files differ
diff --git a/plugins/!NotAdopted/sametime/clist_util.cpp b/plugins/!NotAdopted/sametime/clist_util.cpp
new file mode 100644
index 0000000000..013f38d144
--- /dev/null
+++ b/plugins/!NotAdopted/sametime/clist_util.cpp
@@ -0,0 +1,23 @@
+#include "clist_util.h"
+
+int GroupNameExists(const char *name, int skipGroup)
+{
+ char idstr[33];
+ DBVARIANT dbv;
+ int i;
+
+ for (i = 0;; i++) {
+ if (i == skipGroup)
+ continue;
+ itoa(i, idstr, 10);
+ if (DBGetContactSettingStringUtf(NULL, "CListGroups", idstr, &dbv))
+ break;
+ if (strcmp(dbv.pszVal + 1, name) == 0) {
+ DBFreeVariant(&dbv);
+ return i + 1;
+ }
+ DBFreeVariant(&dbv);
+ }
+ return 0;
+}
+
diff --git a/plugins/!NotAdopted/sametime/clist_util.h b/plugins/!NotAdopted/sametime/clist_util.h
new file mode 100644
index 0000000000..5fd5aed6c6
--- /dev/null
+++ b/plugins/!NotAdopted/sametime/clist_util.h
@@ -0,0 +1,9 @@
+#ifndef _CLIST_UTIL_INC
+#define _CLIST_UTIL_INC
+
+#include "common.h"
+
+int GroupNameExists(const char *name, int skipGroup);
+int RenameGroupWithMove(int groupId, const wchar_t *szName, int move);
+
+#endif
diff --git a/plugins/!NotAdopted/sametime/common.cpp b/plugins/!NotAdopted/sametime/common.cpp
new file mode 100644
index 0000000000..c2a503f8d6
--- /dev/null
+++ b/plugins/!NotAdopted/sametime/common.cpp
@@ -0,0 +1,12 @@
+#include "common.h"
+
+int DBGetContactSettingUtf(HANDLE hContact, char *module, char *setting, DBVARIANT *dbv) {
+ DBCONTACTGETSETTING cgs;
+ cgs.szModule = module;
+ cgs.szSetting = setting;
+ cgs.pValue = dbv;
+
+ dbv->type = DBVT_UTF8;
+
+ return CallService(MS_DB_CONTACT_GETSETTING_STR, (WPARAM)hContact, (LPARAM)&cgs);
+} \ No newline at end of file
diff --git a/plugins/!NotAdopted/sametime/common.h b/plugins/!NotAdopted/sametime/common.h
new file mode 100644
index 0000000000..2249b4b0da
--- /dev/null
+++ b/plugins/!NotAdopted/sametime/common.h
@@ -0,0 +1,106 @@
+#ifndef _COMMON_H
+#define _COMMON_H
+
+#ifdef SAMETIME_EXPORTS
+#define SAMETIME_API __declspec(dllexport)
+#else
+#define SAMETIME_API __declspec(dllimport)
+#endif
+#define _WIN32_WINNT 0x400 // for QueueUserAPC
+
+#pragma warning( disable : 4503 4786 )
+
+#include <windows.h>
+//#include <winsock2.h>
+#include <commctrl.h>
+#include <process.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <time.h>
+#include <string.h>
+
+#include <newpluginapi.h>
+#include <statusmodes.h>
+#include <m_options.h>
+#include <m_langpack.h>
+#include <m_system.h>
+#include <m_skin.h>
+#include <m_netlib.h>
+#include <m_database.h>
+#include <m_protocols.h>
+#include <m_protomod.h>
+#include <m_protosvc.h>
+#include <m_ignore.h>
+#include <m_clist.h>
+#include <m_clui.h>
+#include <m_clc.h>
+#include <m_utils.h>
+#include <m_message.h>
+#include <m_idle.h>
+#include <m_addcontact.h>
+#include <m_popup.h>
+
+#include <m_updater.h>
+
+#include <m_chat.h>
+
+#include "resource.h"
+
+// sametime stuff
+extern "C" {
+#include <mw_session.h>
+#include <mw_cipher.h>
+#include <mw_st_list.h>
+//#include <mw_util.h>
+#include <mw_service.h>
+#include <mw_channel.h>
+#include <mw_srvc_im.h>
+#include <mw_srvc_aware.h>
+#include <mw_srvc_resolve.h>
+#include <mw_srvc_store.h>
+#include <mw_srvc_place.h>
+#include <mw_srvc_ft.h>
+#include <mw_srvc_conf.h>
+#include <mw_error.h>
+#include <mw_message.h>
+};
+
+// globals
+
+extern char PROTO[64];
+extern char PROTO_GROUPS[128];
+
+extern HINSTANCE hInst;
+
+extern PLUGINLINK *pluginLink;
+extern PLUGININFOEX pluginInfo;
+extern MM_INTERFACE mmi;
+extern UTF8_INTERFACE utfi;
+
+extern HANDLE mainThread;
+extern DWORD mainThreadId;
+
+extern "C" SAMETIME_API PLUGININFO* MirandaPluginInfo(DWORD mirandaVersion);
+extern "C" SAMETIME_API int Load(PLUGINLINK *link);
+extern "C" SAMETIME_API int Unload(void);
+
+extern HANDLE hNetlibUser;
+
+static inline void NLog(char *msg) {
+ CallService(MS_NETLIB_LOG, (WPARAM)hNetlibUser, (LPARAM)msg);
+}
+
+extern int previous_status, current_status;
+
+extern bool is_idle;
+
+int DBGetContactSettingUtf(HANDLE hContact, char *module, char *setting, DBVARIANT *dbv);
+
+void SetAllOffline();
+
+extern bool unicode_chat;
+extern int code_page;
+
+#define MAX_MESSAGE_SIZE (10 * 1024) // verified limit in official client, thx Periferral
+
+#endif
diff --git a/plugins/!NotAdopted/sametime/conference.cpp b/plugins/!NotAdopted/sametime/conference.cpp
new file mode 100644
index 0000000000..52e6a29c30
--- /dev/null
+++ b/plugins/!NotAdopted/sametime/conference.cpp
@@ -0,0 +1,565 @@
+#include "conference.h"
+
+typedef std::queue<std::string> InviteQueue;
+
+InviteQueue invite_queue;
+
+mwServiceConference *service_conference = 0;
+
+HANDLE hGcEvent = 0;
+
+mwLoginInfo *my_login_info = 0;
+
+mwConference *my_conference = 0;
+
+HANDLE hChatDeletedEvent = 0, hMenuBuildEvent = 0;
+
+HANDLE hLeaveChatMenuItem = 0, hCreateChatMenuItem = 0;
+
+HICON hIconLeave = 0, hIconCreate = 0;
+
+#define MS_SAMETIME_MENULEAVECHAT "/LeaveChat"
+#define MS_SAMETIME_MENUCREATECHAT "/CreateChat"
+
+void CloseMyConference() {
+ mwConference_destroy(my_conference, 0, Translate("I'm outa here."));
+ my_conference = 0;
+}
+
+/** triggered when we receive a conference invitation. Call
+ mwConference_accept to accept the invitation and join the
+ conference, or mwConference_close to reject the invitation.
+
+ @param conf the newly created conference
+ @param inviter the indentity of the user who sent the invitation
+ @param invite the invitation text
+*/
+void mwServiceConf_on_invited(mwConference *conf, mwLoginInfo *inviter, const char *invite) {
+ GList *members, *mem;
+ members = mem = mwConference_getMembers(conf);
+ for(;mem;mem=mem->next) {
+ if(my_login_info && strcmp(my_login_info->login_id, ((mwLoginInfo *)mem->data)->login_id) == 0) {
+ char *utfs = t2u(TranslateT("Invitation rejected - already present."));
+ mwConference_reject(conf, 0, utfs);
+ free(utfs);
+ return;
+ }
+ }
+ g_list_free(members);
+
+ wchar_t ws_username[128];
+ MultiByteToWideChar(CP_UTF8, 0, (const char *)inviter->user_name, -1, ws_username, 128);
+
+ wchar_t ws_invite[512];
+ MultiByteToWideChar(CP_UTF8, 0, (const char *)invite, -1, ws_invite, 128);
+
+ if(MessageBoxW(0, ws_invite, ws_username, MB_OKCANCEL) == IDOK) {
+ mwConference_accept(conf);
+ } else {
+ char *temp = t2u(TranslateT("Your invitation has been rejected."));
+ mwConference_reject(conf, 0, temp);
+ free(temp);
+ }
+
+}
+
+void ClearInviteQueue() {
+ if(!my_conference) return;
+
+ mwIdBlock idb;
+ idb.community = 0;
+
+ while(invite_queue.size()) {
+ idb.user = (char *)invite_queue.front().c_str();
+
+ HANDLE hContact = FindContactByUserId(idb.user);
+ if(!hContact) {
+ mwSametimeList *user_list = mwSametimeList_new();
+ char *utfs = t2u(TranslateT("None"));
+ mwSametimeGroup *stgroup = mwSametimeGroup_new(user_list, mwSametimeGroup_NORMAL, utfs);
+ mwSametimeUser *stuser = mwSametimeUser_new(stgroup, mwSametimeUser_NORMAL, &idb);
+
+ hContact = AddContact(stuser, (options.add_contacts ? false : true));
+ mwSametimeList_free(user_list);
+ free(utfs);
+
+ }
+
+ bool found = false;
+ GList *members, *mem;
+ members = mem = mwConference_getMembers(my_conference);
+ for(;mem;mem=mem->next) {
+ if(my_login_info && strcmp(idb.user, ((mwLoginInfo *)mem->data)->user_id) == 0) {
+ found = true;
+ break;
+ }
+ }
+ g_list_free(members);
+
+ if(!found) {
+ char *temp = t2u(TranslateT("Please join this meeting."));
+ mwConference_invite(my_conference, &idb, temp);
+ free(temp);
+ }
+
+ invite_queue.pop();
+ }
+}
+/** triggered when we enter the conference. Provides the initial
+ conference membership list as a GList of mwLoginInfo structures
+
+ @param conf the conference just joined
+ @param members mwLoginInfo list of existing conference members
+*/
+void mwServiceConf_conf_opened(mwConference *conf, GList *members) {
+ //MessageBox(0, "Conference Opened", "msg", MB_OK);
+
+ TCHAR *szId = u2t(mwConference_getName(conf));
+
+ // create new chat session
+ GCSESSION gcs = {0};
+ gcs.dwFlags = GC_TCHAR;
+ gcs.cbSize = sizeof(gcs);
+ gcs.iType = GCW_CHATROOM;
+ gcs.pszModule = PROTO;
+ gcs.ptszID = szId;
+ gcs.ptszName = u2t(mwConference_getTitle(conf));
+ gcs.dwItemData = 0;
+
+ CallServiceSync(MS_GC_NEWSESSION, 0, (LPARAM)(GCSESSION *) &gcs);
+ free((char *)gcs.pszName);
+
+ //add a group
+ GCDEST gcd = {0};
+ gcd.pszModule = PROTO;
+ gcd.ptszID = szId;
+ gcd.iType = GC_EVENT_ADDGROUP;
+
+ GCEVENT gce = {0};
+ gce.dwFlags = GC_TCHAR | GCEF_ADDTOLOG;
+ gce.cbSize = sizeof(gce);
+ gce.pDest = &gcd;
+ gce.ptszStatus = TranslateT("Normal");
+
+ CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce);
+
+ // add users
+ gcd.iType = GC_EVENT_JOIN;
+
+ GList *user = members;
+ for(;user; user=user->next) {
+
+ gce.ptszNick = u2t(((mwLoginInfo *)user->data)->user_name);
+ gce.ptszUID = u2t(((mwLoginInfo *)user->data)->login_id);
+ gce.bIsMe = (strcmp(((mwLoginInfo *)user->data)->login_id, my_login_info->login_id) == 0);
+
+ CallServiceSync(MS_GC_EVENT, 0, (LPARAM)(GCEVENT *) &gce);
+
+ free((TCHAR *)gce.ptszNick);
+ free((TCHAR *)gce.ptszUID);
+ }
+
+ // finalize setup (show window)
+ gcd.iType = GC_EVENT_CONTROL;
+ CallServiceSync(MS_GC_EVENT, SESSION_INITDONE, (LPARAM)&gce);
+
+ gcd.iType = GC_EVENT_CONTROL;
+ CallServiceSync(MS_GC_EVENT, SESSION_ONLINE, (LPARAM)&gce);
+
+ if(conf == my_conference) {
+ ClearInviteQueue();
+ }
+
+ free(szId);
+}
+
+/** triggered when a conference is closed. This is typically when
+ we've left it */
+void mwServiceConf_conf_closed(mwConference *conf, guint32 reason) {
+ //MessageBox(0, "Conference closed", "msg", MB_OK);
+
+ TCHAR *szId = u2t(mwConference_getName(conf));
+
+ GCDEST gcd = {0};
+ gcd.pszModule = PROTO;
+ gcd.ptszID = szId;
+
+ GCEVENT gce = {0};
+ gce.dwFlags = GC_TCHAR | GCEF_ADDTOLOG;
+ gce.cbSize = sizeof(gce);
+ gce.pDest = &gcd;
+ gcd.iType = GC_EVENT_CONTROL;
+
+ CallService(MS_GC_EVENT, SESSION_TERMINATE, (LPARAM)&gce);
+ free(szId);
+}
+
+/** triggered when someone joins the conference */
+void mwServiceConf_on_peer_joined(mwConference *conf, mwLoginInfo *user) {
+ TCHAR *szId = u2t(mwConference_getName(conf));
+
+ HANDLE hContact = FindContactByUserId(((mwLoginInfo *)user)->user_id);
+ if(!hContact) {
+ mwIdBlock idb;
+ idb.user = ((mwLoginInfo *)user)->user_id;
+ idb.community = 0;
+
+ mwSametimeList *user_list = mwSametimeList_new();
+ char *utfs = t2u(TranslateT("None"));
+ mwSametimeGroup *stgroup = mwSametimeGroup_new(user_list, mwSametimeGroup_NORMAL, utfs);
+ mwSametimeUser *stuser = mwSametimeUser_new(stgroup, mwSametimeUser_NORMAL, &idb);
+
+ hContact = AddContact(stuser, (options.add_contacts ? false : true));
+
+ mwSametimeList_free(user_list);
+ free(utfs);
+ }
+
+ // add user
+ GCDEST gcd;
+ gcd.pszModule = PROTO;
+ gcd.ptszID = szId;
+ gcd.iType = GC_EVENT_JOIN;
+
+ GCEVENT gce = {0};
+ gce.dwFlags = GC_TCHAR | GCEF_ADDTOLOG;
+ gce.cbSize = sizeof(gce);
+ gce.pDest = &gcd;
+ gce.ptszNick = u2t(((mwLoginInfo *)user)->user_name);
+ gce.ptszUID = u2t(((mwLoginInfo *)user)->login_id);
+ gce.pszStatus = "Normal";
+ gce.time = (DWORD)time(0);
+
+ CallServiceSync(MS_GC_EVENT, 0, (LPARAM)(GCEVENT *) &gce);
+
+ free((TCHAR *)gce.ptszNick);
+ free((TCHAR *)gce.ptszUID);
+ free(szId);
+}
+
+/** triggered when someone leaves the conference */
+void mwServiceConf_on_peer_parted(mwConference *conf, mwLoginInfo *user) {
+ TCHAR *szId = u2t(mwConference_getName(conf));
+
+ // remove user
+ GCDEST gcd;
+ gcd.pszModule = PROTO;
+ gcd.pszID = (char *)szId;
+ gcd.iType = GC_EVENT_PART;
+
+ GCEVENT gce = {0};
+ gce.dwFlags = GC_TCHAR | GCEF_ADDTOLOG;
+ gce.cbSize = sizeof(gce);
+ gce.pDest = &gcd;
+ gce.ptszNick = u2t(((mwLoginInfo *)user)->user_name);
+ gce.ptszUID = u2t(((mwLoginInfo *)user)->login_id);
+ gce.pszStatus = "Normal";
+ gce.time = (DWORD)time(0);
+
+ CallServiceSync(MS_GC_EVENT, 0, (LPARAM)(GCEVENT *) &gce);
+
+ free((TCHAR *)gce.ptszNick);
+ free((TCHAR *)gce.ptszUID);
+ free(szId);
+}
+
+/** triggered when someone says something */
+void mwServiceConf_on_text(mwConference *conf, mwLoginInfo *user, const char *what) {
+ TCHAR *szId = u2t(mwConference_getName(conf));
+
+ GCDEST gcd;
+ gcd.pszModule = PROTO;
+ gcd.pszID = (char *)szId;
+ gcd.iType = GC_EVENT_MESSAGE;
+
+ GCEVENT gce = {0};
+ gce.dwFlags = GC_TCHAR | GCEF_ADDTOLOG;
+ gce.cbSize = sizeof(gce);
+ gce.pDest = &gcd;
+
+
+ //char msg[MAX_MESSAGE_SIZE];
+ //wchar_t ws_msg[MAX_MESSAGE_SIZE];
+
+ //MultiByteToWideChar(CP_UTF8, 0, what, -1, ws_msg, MAX_MESSAGE_SIZE);
+ //WideCharToMultiByte(CallService(MS_LANGPACK_GETCODEPAGE, 0, 0), WC_COMPOSITECHECK, ws_msg, -1, msg, MAX_MESSAGE_SIZE * sizeof(char), 0, 0);
+
+ if(unicode_chat)
+ gce.ptszText = u2w(what);
+ else
+ gce.pszText = u2a(what);
+
+ gce.ptszNick = u2t(((mwLoginInfo *)user)->user_name);
+ gce.ptszUID = u2t(((mwLoginInfo *)user)->login_id);
+ gce.time = (DWORD)time(0);
+
+ CallService(MS_GC_EVENT, 0, (LPARAM)(GCEVENT *) &gce);
+
+ free((char *)gce.pszText);
+ free((TCHAR *)gce.ptszNick);
+ free((TCHAR *)gce.ptszUID);
+ free(szId);
+}
+
+/** typing notification */
+void mwServiceConf_on_typing(mwConference *conf, mwLoginInfo *who, gboolean typing) {
+}
+
+/** optional. called from mwService_free */
+void mwServiceConf_clear(mwServiceConference *srvc) {
+}
+
+mwConferenceHandler mwConference_handler = {
+ mwServiceConf_on_invited,
+ mwServiceConf_conf_opened,
+ mwServiceConf_conf_closed,
+ mwServiceConf_on_peer_joined,
+ mwServiceConf_on_peer_parted,
+ mwServiceConf_on_text,
+ mwServiceConf_on_typing,
+ mwServiceConf_clear
+};
+
+void TerminateConference(char *name) {
+ //MessageBox(0, name, "Terminating Conference", MB_OK);
+
+ GList *conferences, *conf;
+ conferences = conf = mwServiceConference_getConferences(service_conference);
+ for(;conf;conf = conf->next) {
+ if(strcmp(name, mwConference_getName((mwConference *)conf->data)) == 0) {
+ GCDEST gcd = {0};
+ gcd.pszModule = PROTO;
+ gcd.ptszID = u2t(name);
+
+ GCEVENT gce = {0};
+ gce.dwFlags = GC_TCHAR | GCEF_ADDTOLOG;
+ gce.cbSize = sizeof(gce);
+ gce.pDest = &gcd;
+ gcd.iType = GC_EVENT_CONTROL;
+
+ CallService(MS_GC_EVENT, SESSION_TERMINATE, (LPARAM)&gce);
+
+ free((TCHAR *)gcd.ptszID);
+ }
+ }
+ g_list_free(conferences);
+}
+
+
+int GcEventHook(WPARAM wParam, LPARAM lParam) {
+ GCHOOK *gch = (GCHOOK *)lParam;
+
+ if(strcmp(gch->pDest->pszModule, PROTO) != 0) return 0;
+
+ GList *conferences, *conf;
+ conferences = conf = mwServiceConference_getConferences(service_conference);
+ for(;conf;conf = conf->next) {
+ TCHAR *szId = u2t(mwConference_getName((mwConference *)conf->data));
+ if(_tcscmp(gch->pDest->ptszID, szId) == 0) {
+
+ switch(gch->pDest->iType) {
+ case GC_USER_MESSAGE:
+ {
+ //MessageBox(0, "Sending message", "Sending", MB_OK);
+ //wchar_t msg[MAX_MESSAGE_SIZE];
+ //char utf_msg[MAX_MESSAGE_SIZE];
+ //MultiByteToWideChar(CallService(MS_LANGPACK_GETCODEPAGE, 0, 0), MB_PRECOMPOSED, gch->pszText, -1, msg, MAX_MESSAGE_SIZE);
+ //WideCharToMultiByte(CP_UTF8, 0, msg, -1, utf_msg, MAX_MESSAGE_SIZE, 0, 0);
+
+ char *utf_msg;
+ if(unicode_chat)
+ utf_msg = w2u(gch->ptszText);
+ else
+ utf_msg = a2u(gch->pszText);
+
+ mwConference_sendText((mwConference *)conf->data, utf_msg);
+
+ free(utf_msg);
+ }
+ break;
+ case GC_SESSION_TERMINATE:
+ {
+ //MessageBox(0, "Terminate chat event", "msg", MB_OK);
+ if(my_conference == conf->data) CloseMyConference();
+ else {
+ char *utfs = t2u(TranslateT("I'm outa here."));
+ mwConference_destroy((mwConference *)conf->data, 0, utfs);
+ free(utfs);
+ }
+ }
+ break;
+ }
+
+ break;
+ }
+ free(szId);
+ }
+
+ g_list_free(conferences);
+
+ return 0;
+}
+
+int ChatDeleted(WPARAM wParam, LPARAM lParam) {
+ HANDLE hContact = (HANDLE)wParam;
+
+ if(DBGetContactSettingByte(hContact, PROTO, "ChatRoom", 0) == 0)
+ return 0;
+
+ DBVARIANT dbv;
+ if(!DBGetContactSetting(hContact, PROTO, "ChatRoomID", &dbv)) {
+ TerminateConference(dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+
+ return 0;
+}
+
+int CreateChat(WPARAM wParam, LPARAM lParam) {
+ HANDLE hContact = (HANDLE)wParam;
+ mwAwareIdBlock id_block;
+ mwIdBlock idb;
+ if(my_login_info && GetAwareIdFromContact(hContact, &id_block)) {
+ TCHAR title[512];
+ TCHAR *ts = u2t(my_login_info->user_name);
+
+#ifdef _UNICODE
+ swprintf(title, TranslateT("%s's Conference"), ts); // TODO: FIX potential buffer overflow
+#else
+ snprintf(title, 256, Translate("%s's Conference"), ts);
+#endif
+ free(ts);
+
+ idb.user = id_block.user;
+ idb.community = id_block.community;
+
+ invite_queue.push(idb.user);
+
+ if(!my_conference) {
+ char *utfs;
+ my_conference = mwConference_new(service_conference, utfs = t2u(title));
+ mwConference_open(my_conference);
+ free(utfs);
+ } else {
+ ClearInviteQueue();
+ }
+
+ free(id_block.user);
+ }
+
+ return 0;
+}
+
+int PrebuildContactMenu(WPARAM wParam, LPARAM lParam) {
+ HANDLE hContact = (HANDLE)wParam;
+
+
+ CLISTMENUITEM mi = {0};
+ mi.cbSize = sizeof(mi);
+ mi.flags = CMIM_FLAGS | (DBGetContactSettingByte(hContact, PROTO, "ChatRoom", 0) == 1 ? 0 : CMIF_HIDDEN);
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hLeaveChatMenuItem, (LPARAM)&mi);
+
+ // if user is already in our meeting,
+ bool not_present = true;
+ DBVARIANT dbv;
+ if(my_conference && !DBGetContactSettingUtf(hContact, PROTO, "stid", &dbv)) {
+ char *user_id = dbv.pszVal;
+
+ GList *members, *mem;
+ members = mem = mwConference_getMembers(my_conference);
+ for(;mem;mem=mem->next) {
+ if(my_login_info && strcmp(user_id, ((mwLoginInfo *)mem->data)->user_id) == 0) {
+ not_present = false;
+ break;
+ }
+ }
+ g_list_free(members);
+
+ DBFreeVariant(&dbv);
+ }
+ mi.flags = CMIM_FLAGS | CMIF_NOTOFFLINE | (DBGetContactSettingByte(hContact, PROTO, "ChatRoom", 0) == 0 && not_present ? 0 : CMIF_HIDDEN);
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hCreateChatMenuItem, (LPARAM)&mi);
+
+ return 0;
+}
+
+void InitConference(mwSession *session) {
+ my_login_info = mwSession_getLoginInfo(session);
+
+ mwSession_addService(session, (mwService *)(service_conference = mwServiceConference_new(session, &mwConference_handler)));
+
+ hGcEvent = HookEvent(ME_GC_EVENT, GcEventHook);
+
+ hChatDeletedEvent = HookEvent(ME_DB_CONTACT_DELETED, ChatDeleted);
+
+}
+
+void DeinitConference(mwSession *session) {
+ GList *conferences, *conf;
+ conferences = conf = mwServiceConference_getConferences(service_conference);
+ for(;conf;conf = conf->next) {
+ if(my_conference == conf->data) CloseMyConference();
+ else {
+ char *utfs = t2u(TranslateT("I'm outa here."));
+ mwConference_destroy((mwConference *)conf->data, 0, utfs);
+ free(utfs);
+ }
+
+ }
+ g_list_free(conferences);
+
+
+ UnhookEvent(hMenuBuildEvent);
+ hMenuBuildEvent = 0;
+ UnhookEvent(hChatDeletedEvent);
+ hChatDeletedEvent = 0;
+
+ my_login_info = 0;
+
+ UnhookEvent(hGcEvent);
+ hGcEvent = 0;
+
+ mwSession_removeService(session, mwService_CONFERENCE);
+ mwService_free((mwService *)service_conference);
+ service_conference = 0;
+}
+
+void InitConferenceMenu() {
+ CreateProtoServiceFunction(PROTO, MS_SAMETIME_MENULEAVECHAT, ChatDeleted);
+ CreateProtoServiceFunction(PROTO, MS_SAMETIME_MENUCREATECHAT, CreateChat);
+
+ hIconLeave = LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON_LEAVE));
+ hIconCreate = LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON_INVITE));
+
+ char service_function[128];
+ strcpy(service_function, PROTO);
+ char *d = service_function + strlen(service_function);
+
+ CLISTMENUITEM mi = {0};
+ mi.cbSize = sizeof(mi);
+ mi.pszContactOwner = PROTO;
+
+ mi.pszName = Translate("Leave Conference");
+ strcpy(d, MS_SAMETIME_MENULEAVECHAT);
+ mi.pszService = service_function;
+ mi.hIcon = hIconLeave;
+
+ hLeaveChatMenuItem = (HANDLE)CallService(MS_CLIST_ADDCONTACTMENUITEM, 0, (LPARAM)&mi);
+
+ mi.flags = CMIF_NOTOFFLINE;
+ mi.pszName = Translate("Start Conference");
+ strcpy(d, MS_SAMETIME_MENUCREATECHAT);
+ mi.pszService = service_function;
+ mi.hIcon = hIconCreate;
+
+ hCreateChatMenuItem = (HANDLE)CallService(MS_CLIST_ADDCONTACTMENUITEM, 0, (LPARAM)&mi);
+
+ hMenuBuildEvent = HookEvent(ME_CLIST_PREBUILDCONTACTMENU, PrebuildContactMenu);
+
+}
+
+void DeinitConferenceMenu() {
+ DestroyIcon(hIconLeave);
+ DestroyIcon(hIconCreate);
+}
+
diff --git a/plugins/!NotAdopted/sametime/conference.h b/plugins/!NotAdopted/sametime/conference.h
new file mode 100644
index 0000000000..55a74a1605
--- /dev/null
+++ b/plugins/!NotAdopted/sametime/conference.h
@@ -0,0 +1,18 @@
+#ifndef _CONFERENCE_INC
+#define _CONFERENCE_INC
+
+#include "common.h"
+#include "userlist.h"
+#include "options.h"
+#include "utils.h"
+
+#include <queue>
+#include <string>
+
+void InitConference(mwSession *session);
+void DeinitConference(mwSession *session);
+
+void InitConferenceMenu();
+void DeinitConferenceMenu();
+
+#endif \ No newline at end of file
diff --git a/plugins/!NotAdopted/sametime/files.cpp b/plugins/!NotAdopted/sametime/files.cpp
new file mode 100644
index 0000000000..d89cf401d8
--- /dev/null
+++ b/plugins/!NotAdopted/sametime/files.cpp
@@ -0,0 +1,421 @@
+#include "files.h"
+
+mwServiceFileTransfer *service_files = 0;
+
+/** an incoming file transfer has been offered */
+void mwFileTransfer_offered(mwFileTransfer *ft) {
+ //MessageBox(0, "Offered", "File Transfer", MB_OK);
+
+ const mwIdBlock *idb = mwFileTransfer_getUser(ft);
+ HANDLE hContact = FindContactByUserId(idb->user);
+
+ if(!hContact) {
+ mwSametimeList *user_list = mwSametimeList_new();
+ mwSametimeGroup *stgroup = mwSametimeGroup_new(user_list, mwSametimeGroup_NORMAL, Translate("None"));
+ mwSametimeUser *stuser = mwSametimeUser_new(stgroup, mwSametimeUser_NORMAL, (mwIdBlock *)idb);
+
+ hContact = AddContact(stuser, (options.add_contacts ? false : true));
+ }
+
+ CCSDATA ccs = {0};
+ PROTORECVEVENT pre = {0};
+
+ char filename[MAX_PATH];
+ char desc[512];
+
+ strncpy(filename, mwFileTransfer_getFileName(ft), MAX_PATH);
+
+ NLog("Sametime mwFileTransfer_offered");
+ NLog(filename);
+
+ const char *msg = mwFileTransfer_getMessage(ft);
+ if(msg) strncpy(desc, msg, 512);
+ else desc[0] = 0;
+
+ ProtoBroadcastAck(PROTO, hContact, ACKTYPE_FILE, ACKRESULT_INITIALISING, (HANDLE)ft, 0);
+
+ char *blob = (char *)malloc(sizeof(DWORD) + strlen(filename) + strlen(desc) + 2);
+
+ *(DWORD *)blob = (DWORD)(ft);
+ strcpy(blob + sizeof(DWORD), filename);
+ strcpy(blob + sizeof(DWORD) + strlen(filename) + 1, desc);
+
+ // Send chain event
+
+ ccs.szProtoService = PSR_FILE;
+ ccs.hContact = hContact;
+ ccs.wParam = (WPARAM)ft;
+ ccs.lParam = (LPARAM)&pre;
+
+ pre.flags = 0;
+ pre.timestamp = (DWORD)time(0);
+ pre.szMessage = blob;
+ pre.lParam = 0;
+
+ CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs);
+
+ free(blob);
+}
+
+//returns 0 if finished with current file
+int SendFileChunk(mwFileTransfer *ft, FileTransferClientData *ftcd) {
+ DWORD bytes_read;
+ mwOpaque o;
+
+ if(!ftcd || !ftcd->buffer)
+ return 0;
+
+ if(!ReadFile(ftcd->hFile, ftcd->buffer, FILE_BUFF_SIZE, &bytes_read, 0)) {
+ //MessageBox(0, "Closing FT - read failed", "FT Opened", MB_OK);
+ //mwFileTransfer_cancel(ft);
+ NLog("Sametime closing file transfer (SendFileChunk)");
+ mwFileTransfer_close(ft, mwFileTransfer_SUCCESS);
+ return 0;
+ }
+ o.data = (unsigned char *)ftcd->buffer;
+ o.len = bytes_read;
+
+ mwFileTransfer_send(ft, &o);
+
+ return bytes_read;
+}
+
+unsigned long __stdcall SendThread(LPVOID param) {
+ CallService(MS_SYSTEM_THREAD_PUSH, 0, 0);
+ NLog("Sametime send thread starting");
+
+ mwFileTransfer *ft = (mwFileTransfer *)param;
+ FileTransferClientData *ftcd = 0;
+
+ if(ft) ftcd = (FileTransferClientData *)mwFileTransfer_getClientData(ft);
+
+ if(!ft || !ftcd) return 1;
+
+ PROTOFILETRANSFERSTATUS pfts = {0};
+
+ pfts.cbSize = sizeof(pfts);
+ pfts.hContact = ftcd->hContact;
+ pfts.sending = (ftcd->sending ? 1 : 0);
+
+ pfts.files = 0;
+ pfts.totalFiles = ftcd->first->ft_count;
+ pfts.totalBytes = ftcd->first->totalSize;
+
+ while(SendFileChunk(ft, ftcd) && !Miranda_Terminated()) {
+
+ pfts.currentFileNumber = ftcd->ft_number;
+ pfts.totalProgress = ftcd->sizeToHere + mwFileTransfer_getSent(ft);
+
+ pfts.workingDir = ftcd->save_path;
+ pfts.currentFile = (char *)mwFileTransfer_getFileName(ft);
+ pfts.currentFileSize = mwFileTransfer_getFileSize(ft);
+ pfts.currentFileProgress = mwFileTransfer_getSent(ft);
+ pfts.currentFileTime = 0; //?
+
+ ProtoBroadcastAck(PROTO, ftcd->hContact, ACKTYPE_FILE, ACKRESULT_DATA, ftcd->hFt, (LPARAM)&pfts);
+
+ SleepEx(500,TRUE);
+ }
+
+ ProtoBroadcastAck(PROTO, ftcd->hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, ftcd->hFt, 0);
+
+ mwFileTransfer_removeClientData(ft);
+ if(ftcd->save_path) free(ftcd->save_path);
+ if(ftcd->buffer) delete[] ftcd->buffer;
+ delete ftcd;
+
+ NLog("Sametime send thread exiting");
+ CallService(MS_SYSTEM_THREAD_POP, 0, 0);
+
+ return 0;
+}
+
+/** a file transfer has been fully initiated */
+void mwFileTransfer_opened(mwFileTransfer *ft) {
+ //MessageBox(0, "Opened", "File Transfer", MB_OK);
+ NLog("Sametime mwFileTransfer_opened");
+
+ FileTransferClientData *ftcd = (FileTransferClientData *)mwFileTransfer_getClientData(ft);
+
+ if(ftcd->sending) {
+ // create a thread to send chunks - since it seems not all clients send acks for each of our chunks!
+ DWORD tid;
+ CloseHandle(CreateThread(0, 0, SendThread, (void *)ft, 0, &tid));
+ }
+}
+
+/** a file transfer has been closed. Check the status of the file
+ transfer to determine if the transfer was complete or if it had
+ been interrupted */
+void mwFileTransfer_closed(mwFileTransfer *ft, guint32 code) {
+ //MessageBox(0, "Closed", "File Transfer", MB_OK);
+ NLog("Sametime mwFileTransfer_closed");
+
+ FileTransferClientData *ftcd = (FileTransferClientData *)mwFileTransfer_getClientData(ft);
+
+ if(ftcd) {
+ if(ftcd->hFile != INVALID_HANDLE_VALUE)
+ CloseHandle(ftcd->hFile);
+
+ if(code != mwFileTransfer_SUCCESS || !mwFileTransfer_isDone(ft)) {
+ if(!ftcd->sending) {
+ char fn[MAX_PATH];
+ if(ftcd->save_path) strcpy(fn, ftcd->save_path);
+ else fn[0] = 0;
+ strcat(fn, mwFileTransfer_getFileName(ft));
+
+ DeleteFileA(fn);
+ }
+
+ if(code == mwFileTransfer_REJECTED) {
+ ProtoBroadcastAck(PROTO, ftcd->hContact, ACKTYPE_FILE, ACKRESULT_DENIED, ftcd->hFt, 0);
+ } else {
+ ProtoBroadcastAck(PROTO, ftcd->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ftcd->hFt, 0);
+ }
+
+ if(ftcd->sending) {
+ FileTransferClientData *ftcd_next = ftcd->next, *ftcd_temp;
+ while(ftcd_next) {
+ mwFileTransfer_free((mwFileTransfer *)ftcd_next->ft);
+ ftcd_temp = ftcd_next->next;
+
+ if(ftcd_next->hFile != INVALID_HANDLE_VALUE)
+ CloseHandle(ftcd->hFile);
+
+ if(ftcd_next->save_path) free(ftcd_next->save_path);
+ if(ftcd_next->buffer) delete[] ftcd_next->buffer;
+ delete ftcd_next;
+ ftcd_next = ftcd_temp;
+ }
+ } else {
+ mwFileTransfer_removeClientData(ft);
+ if(ftcd->save_path) free(ftcd->save_path);
+ if(ftcd->buffer) delete[] ftcd->buffer;
+ delete ftcd;
+
+ mwFileTransfer_free(ft);
+ }
+
+ } else {
+ if(ftcd->sending) {
+ // check if we have more files to send...
+ if(ftcd->next) {
+ ProtoBroadcastAck(PROTO, ftcd->hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, ftcd->hFt, 0);
+ mwFileTransfer_offer(ftcd->next->ft);
+ }
+ } else {
+ ProtoBroadcastAck(PROTO, ftcd->hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, ftcd->hFt, 0);
+
+ mwFileTransfer_removeClientData(ft);
+ if(ftcd->save_path) free(ftcd->save_path);
+ if(ftcd->buffer) delete[] ftcd->buffer;
+ delete ftcd;
+
+ mwFileTransfer_free(ft);
+ }
+ }
+
+ }
+
+}
+
+/** receive a chunk of a file from an inbound file transfer. */
+void mwFileTransfer_recv(mwFileTransfer *ft, struct mwOpaque *data) {
+ //MessageBox(0, "Recv", "File Transfer", MB_OK);
+
+ FileTransferClientData *ftcd = (FileTransferClientData *)mwFileTransfer_getClientData(ft);
+
+ DWORD bytes_written;
+ if(!WriteFile(ftcd->hFile, data->data, data->len, &bytes_written, 0)) {
+ //MessageBox(0, "Write failed", "msg", MB_OK);
+ mwFileTransfer_cancel(ft);
+ } else {
+ //if(mwFileTransfer_isOpen(ft))
+ mwFileTransfer_ack(ft); // acknowledge chunk
+
+ PROTOFILETRANSFERSTATUS pfts = {0};
+
+ pfts.cbSize = sizeof(pfts);
+ pfts.hContact = ftcd->hContact;
+ pfts.sending = (ftcd->sending ? 1 : 0);
+ pfts.files = 0;
+ pfts.totalFiles = 1;
+ pfts.currentFileNumber = 0;
+ pfts.totalBytes = mwFileTransfer_getFileSize(ft);
+ pfts.totalProgress = mwFileTransfer_getSent(ft);
+ pfts.workingDir = ftcd->save_path;
+ pfts.currentFile = (char *)mwFileTransfer_getFileName(ft);
+ pfts.currentFileSize = mwFileTransfer_getFileSize(ft);
+ pfts.currentFileProgress = mwFileTransfer_getSent(ft);
+ pfts.currentFileTime = 0; //?
+
+ ProtoBroadcastAck(PROTO, ftcd->hContact, ACKTYPE_FILE, ACKRESULT_DATA, ftcd->hFt, (LPARAM)&pfts);
+ }
+
+}
+
+/** received an ack for a sent chunk on an outbound file transfer.
+ this indicates that a previous call to mwFileTransfer_send has
+ reached the target and that the target has responded. */
+void mwFileTransfer_handle_ack(mwFileTransfer *ft) {
+ //MessageBox(0, "Handle ack", "File Transfer", MB_OK);
+
+ // see SendThread above - not all clients send us acks
+}
+
+/** optional. called from mwService_free */
+void mwFileTransfer_clear(mwServiceFileTransfer *srvc) {
+}
+
+mwFileTransferHandler mwFileTransfer_handler = {
+ mwFileTransfer_offered,
+ mwFileTransfer_opened,
+ mwFileTransfer_closed,
+ mwFileTransfer_recv,
+ mwFileTransfer_handle_ack,
+ mwFileTransfer_clear
+};
+
+HANDLE SendFilesToUser(HANDLE hContact, char **files, char *pszDesc) {
+ mwAwareIdBlock id_block;
+ if(GetAwareIdFromContact(hContact, &id_block)) {
+ mwIdBlock idb;
+ idb.user = id_block.user;
+ idb.community = id_block.community;
+
+ HANDLE hFile;
+ DWORD filesize;
+ FileTransferClientData *ftcd, *prev_ftcd = 0, *first_ftcd = 0;
+ mwFileTransfer *ft, *first_ft = 0;
+
+ char *fn;
+
+ for(int i = 0; files[i]; i++) {
+ hFile = CreateFileA(files[i], GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
+ if(hFile != INVALID_HANDLE_VALUE) {
+ filesize = GetFileSize(hFile, 0);
+
+ fn = strrchr(files[i], '\\');
+ if(fn) fn++;
+
+ ft = mwFileTransfer_new(service_files, &idb, pszDesc, (fn ? fn : files[i]), filesize);
+
+ ftcd = new FileTransferClientData;
+ memset((void *)ftcd, 0, sizeof(FileTransferClientData));
+
+ ftcd->ft = ft;
+ ftcd->hContact = hContact;
+
+ ftcd->next = 0;
+ if(prev_ftcd) {
+ prev_ftcd->next = ftcd; // link into list
+
+ // each node contains a pointer to the first - it will contain infor linke the count etc
+ ftcd->first = prev_ftcd->first;
+ } else {
+ ftcd->first = ftcd;
+ }
+
+ if(!first_ft) first_ft = ft;
+
+ ftcd->sending = true;
+ ftcd->hFile = hFile;
+ ftcd->hFt = (HANDLE)first_ft;
+
+ ftcd->save_path = 0;
+ ftcd->buffer = new char[FILE_BUFF_SIZE];
+
+ ftcd->ft_number = ftcd->first->ft_count;
+ ftcd->first->ft_count++;
+ ftcd->sizeToHere = ftcd->first->totalSize;
+ ftcd->first->totalSize += filesize;
+
+ mwFileTransfer_setClientData(ft, (gpointer)ftcd, 0);
+
+ prev_ftcd = ftcd;
+ }
+ }
+
+ free(id_block.user);
+
+ if(first_ft) {
+ mwFileTransfer_offer(first_ft);
+ return (HANDLE)first_ft;
+ }
+
+ }
+
+ return 0;
+}
+
+HANDLE AcceptFileTransfer(HANDLE hContact, HANDLE hFt, char *save_path) {
+ mwFileTransfer *ft = (mwFileTransfer *)(hFt);
+
+ FileTransferClientData *ftcd = new FileTransferClientData;
+ memset((void *)ftcd, 0, sizeof(FileTransferClientData));
+ ftcd->ft = ft;
+ ftcd->sending = false;
+ ftcd->hFt = (HANDLE)ft;
+
+ if(save_path) // save path
+ ftcd->save_path = _strdup(save_path);
+ else
+ ftcd->save_path = 0;
+
+ mwFileTransfer_setClientData(ft, (gpointer)ftcd, 0);
+
+ char fp[MAX_PATH];
+ char *fn = strrchr((char *)mwFileTransfer_getFileName(ft), '\\');
+ if(fn) fn++;
+
+ if(ftcd->save_path)
+ strcpy(fp, ftcd->save_path);
+ else
+ fp[0] = 0;
+
+ if(fn) strcat(fp, fn);
+ else strcat(fp, mwFileTransfer_getFileName(ft));
+
+ ftcd->hFile = CreateFileA(fp, GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_ALWAYS, 0, 0);
+ if(ftcd->hFile == INVALID_HANDLE_VALUE) {
+ //MessageBox(0, fp, "Accept - invalid handle", MB_OK);
+ mwFileTransfer_close(ft, mwFileTransfer_ERROR);
+ return 0;
+ }
+
+ ftcd->hContact = hContact;
+ mwFileTransfer_setClientData(ft, (gpointer)ftcd, 0);
+
+ mwFileTransfer_accept(ft);
+ return hFt;
+}
+
+void RejectFileTransfer(HANDLE hFt) {
+ mwFileTransfer *ft = (mwFileTransfer *)hFt;
+ mwFileTransfer_reject(ft);
+}
+
+void CancelFileTransfer(HANDLE hFt) {
+ mwFileTransfer *ft = (mwFileTransfer *)hFt;
+
+ FileTransferClientData *ftcd = (FileTransferClientData *)mwFileTransfer_getClientData(ft);
+
+ if(ftcd) {
+ while(mwFileTransfer_isDone(ftcd->ft) && ftcd)
+ ftcd = ftcd->next;
+
+ if(ftcd) mwFileTransfer_cancel(ftcd->ft);
+ } else
+ mwFileTransfer_cancel(ft);
+}
+
+void InitFiles(mwSession *session) {
+ mwSession_addService(session, (mwService *)(service_files = mwServiceFileTransfer_new(session, &mwFileTransfer_handler)));
+}
+
+void DeinitFiles(mwSession *session) {
+ mwSession_removeService(session, mwService_FILE_TRANSFER);
+ mwService_free((mwService *)service_files);
+ service_files = 0;
+}
+
diff --git a/plugins/!NotAdopted/sametime/files.h b/plugins/!NotAdopted/sametime/files.h
new file mode 100644
index 0000000000..f240c7fa61
--- /dev/null
+++ b/plugins/!NotAdopted/sametime/files.h
@@ -0,0 +1,37 @@
+#ifndef _FILES_INC
+#define _FILES_INC
+
+#include "common.h"
+#include "userlist.h"
+#include "options.h"
+
+#define FILE_BUFF_SIZE (1024 * 32)
+
+typedef struct FileTransferClientData_tag {
+ char *save_path;
+ HANDLE hFile;
+ bool sending;
+ HANDLE hContact;
+ struct FileTransferClientData_tag *next, *first;
+ HANDLE hFt;
+ char *buffer;
+
+ int ft_number;
+
+ int ft_count; // number of nodes in list - only valid in first node
+ int totalSize; // total for all files in the list - only valid in first node
+
+ int sizeToHere; // in a link list of file transfers, the sum of the filesizes of all prior nodes in the list
+ mwFileTransfer *ft;
+} FileTransferClientData;
+
+HANDLE SendFilesToUser(HANDLE hContact, char **files, char *pszDesc);
+
+HANDLE AcceptFileTransfer(HANDLE hContact, HANDLE hFt, char *save_path);
+void RejectFileTransfer(HANDLE hFt);
+void CancelFileTransfer(HANDLE hFt);
+
+void InitFiles(mwSession *session);
+void DeinitFiles(mwSession *session);
+
+#endif
diff --git a/plugins/!NotAdopted/sametime/invite.ico b/plugins/!NotAdopted/sametime/invite.ico
new file mode 100644
index 0000000000..944ebf818c
--- /dev/null
+++ b/plugins/!NotAdopted/sametime/invite.ico
Binary files differ
diff --git a/plugins/!NotAdopted/sametime/messaging.cpp b/plugins/!NotAdopted/sametime/messaging.cpp
new file mode 100644
index 0000000000..1c015de153
--- /dev/null
+++ b/plugins/!NotAdopted/sametime/messaging.cpp
@@ -0,0 +1,240 @@
+#include "messaging.h"
+
+#include <map>
+#include <queue>
+
+typedef std::queue<std::string> MessageQueue;
+typedef std::map<HANDLE, MessageQueue> ContactMessageQueue;
+
+ContactMessageQueue contact_message_queue;
+CRITICAL_SECTION q_cs;
+
+mwServiceIm *service_im = 0;
+
+void mwIm_conversation_opened(mwConversation *conv) {
+ mwIdBlock *idb = mwConversation_getTarget(conv);
+ HANDLE hContact = FindContactByUserId(idb->user);
+
+ if(!hContact) {
+ mwSametimeList *user_list = mwSametimeList_new();
+ mwSametimeGroup *stgroup = mwSametimeGroup_new(user_list, mwSametimeGroup_NORMAL, Translate("None"));
+ mwSametimeUser *stuser = mwSametimeUser_new(stgroup, mwSametimeUser_NORMAL, idb);
+
+ AddContact(stuser, (options.add_contacts ? false : true));
+ GetMoreDetails(idb->user);
+ }
+
+ ContactMessageQueue::iterator i;
+ EnterCriticalSection(&q_cs);
+ if((i = contact_message_queue.find(hContact)) != contact_message_queue.end()) {
+ while(i->second.size()) {
+ mwConversation_send(conv, mwImSend_PLAIN, (gconstpointer)i->second.front().c_str());
+ i->second.pop();
+ }
+ contact_message_queue.erase(i);
+ }
+ LeaveCriticalSection(&q_cs);
+
+ // gives linker error 'unresolved external symbol' :( So instead we will either add ciphers to the session or not (see session.cpp)
+ //mwConversation_setEncrypted(conv, options.encrypt_session);
+}
+
+/** A conversation has been closed */
+void mwIm_conversation_closed(mwConversation *conv, guint32 err) {
+ if(err & ERR_FAILURE && err != CONNECTION_RESET) {
+ char *msg = mwError(err);
+ TCHAR *ts = u2t(msg);
+ //MessageBox(0, ts, TranslateT("Sametime Error"), MB_OK | MB_ICONWARNING);
+ ShowError(TranslateTS(ts));
+ g_free(msg);
+ free(ts);
+ }
+
+ mwIdBlock *idb = mwConversation_getTarget(conv);
+ HANDLE hContact = FindContactByUserId(idb->user);
+ if(hContact) {
+ ContactMessageQueue::iterator i;
+ EnterCriticalSection(&q_cs);
+ if((i = contact_message_queue.find(hContact)) != contact_message_queue.end()) {
+ contact_message_queue.erase(i);
+ }
+ LeaveCriticalSection(&q_cs);
+ }
+}
+
+/** A message has been received on a conversation */
+void mwIm_conversation_recv(mwConversation *conv, mwImSendType type, gconstpointer msg) {
+ mwIdBlock *idb = mwConversation_getTarget(conv);
+ HANDLE hContact = FindContactByUserId(idb->user);
+
+ if(type == mwImSend_TYPING) {
+ CallService(MS_PROTO_CONTACTISTYPING, (WPARAM)hContact, (LPARAM)(GPOINTER_TO_UINT(msg) == 0 ? 0 : 2));
+ return;
+ }
+
+ if(type != mwImSend_PLAIN) return;
+
+ wchar_t temp[MAX_MESSAGE_SIZE];
+ char text[MAX_MESSAGE_SIZE];
+
+ MultiByteToWideChar(CP_UTF8, 0, (const char *)msg, -1, temp, MAX_MESSAGE_SIZE);
+ WideCharToMultiByte(CallService(MS_LANGPACK_GETCODEPAGE, 0, 0), WC_COMPOSITECHECK, temp, -1, text, MAX_MESSAGE_SIZE * sizeof(char), 0, 0);
+
+ CCSDATA ccs = {0};
+ PROTORECVEVENT pre = {0};
+
+ ccs.hContact = hContact;
+ ccs.szProtoService = PSR_MESSAGE;
+ ccs.wParam = 0;
+ ccs.lParam = (LPARAM)&pre;
+
+ pre.timestamp = (DWORD)time(0);
+
+ int tMsgBodyLen = strlen(text);
+ int tRealBodyLen = wcslen(temp);
+
+ int tMsgBufLen = (tMsgBodyLen+1) * sizeof(char) + (tRealBodyLen+1)*sizeof( wchar_t );
+ char* tMsgBuf = ( char* )malloc( tMsgBufLen );
+
+ char* p = tMsgBuf;
+
+ strcpy( p, text );
+ p += (tMsgBodyLen+1);
+
+ if ( tRealBodyLen != 0 ) {
+ wcscpy((wchar_t *)p, temp);
+ pre.flags = PREF_UNICODE;
+ }
+
+ pre.szMessage = tMsgBuf;
+
+ DBDeleteContactSetting(hContact, "CList", "Hidden");
+
+ CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs);
+
+ free(tMsgBuf);
+}
+
+mwImHandler mwIm_handler = {
+ mwIm_conversation_opened,
+ mwIm_conversation_closed,
+ mwIm_conversation_recv
+};
+
+HANDLE SendMessageToUser(HANDLE hContact, char *msg) {
+ mwIdBlock idb;
+ mwAwareIdBlock id_block;
+
+ wchar_t temp[MAX_MESSAGE_SIZE];
+ char text[MAX_MESSAGE_SIZE];
+
+ MultiByteToWideChar(CallService(MS_LANGPACK_GETCODEPAGE, 0, 0), MB_PRECOMPOSED, msg, -1, temp, MAX_MESSAGE_SIZE);
+ WideCharToMultiByte(CP_UTF8, 0, temp, -1, text, MAX_MESSAGE_SIZE * sizeof(char), 0, 0);
+
+ if(GetAwareIdFromContact(hContact, &id_block)) {
+ idb.user = id_block.user;
+ idb.community = id_block.community;
+
+ mwConversation *conv = mwServiceIm_getConversation(service_im, &idb);
+ if(conv) {
+ if(!mwConversation_isOpen(conv)) {
+ EnterCriticalSection(&q_cs);
+ contact_message_queue[hContact].push(text);
+ LeaveCriticalSection(&q_cs);
+ mwConversation_open(conv);
+ } else
+ mwConversation_send(conv, mwImSend_PLAIN, (gconstpointer)msg);
+
+ free(id_block.user);
+ return (HANDLE)conv;
+ }
+
+ free(id_block.user);
+ }
+
+ return 0;
+}
+
+HANDLE SendMessageToUserW(HANDLE hContact, wchar_t *msg) {
+ mwIdBlock idb;
+ mwAwareIdBlock id_block;
+
+ char text[MAX_MESSAGE_SIZE];
+
+ WideCharToMultiByte(CP_UTF8, 0, msg, -1, text, MAX_MESSAGE_SIZE * sizeof(char), 0, 0);
+
+ if(GetAwareIdFromContact(hContact, &id_block)) {
+ idb.user = id_block.user;
+ idb.community = id_block.community;
+
+ mwConversation *conv = mwServiceIm_getConversation(service_im, &idb);
+ if(conv) {
+ if(!mwConversation_isOpen(conv)) {
+ EnterCriticalSection(&q_cs);
+ contact_message_queue[hContact].push(text);
+ LeaveCriticalSection(&q_cs);
+
+ mwConversation_open(conv);
+ } else
+ mwConversation_send(conv, mwImSend_PLAIN, (gconstpointer)text);
+
+ free(id_block.user);
+ return (HANDLE)conv;
+ }
+
+ free(id_block.user);
+ }
+
+ return 0;
+}
+
+void SendTyping(HANDLE hContact, bool typing) {
+ mwIdBlock idb;
+ mwAwareIdBlock id_block;
+
+ if(GetAwareIdFromContact(hContact, &id_block)) {
+ idb.user = id_block.user;
+ idb.community = id_block.community;
+
+ mwConversation *conv = mwServiceIm_getConversation(service_im, &idb);
+ if(conv) {
+ if(mwConversation_isOpen(conv))
+ mwConversation_send(conv, mwImSend_TYPING, (gconstpointer)GUINT_TO_POINTER(typing ? 1 : 0));
+ }
+
+ free(id_block.user);
+ }
+}
+
+void CloseIm(HANDLE hContact) {
+ mwIdBlock idb;
+ mwAwareIdBlock id_block;
+
+ if(GetAwareIdFromContact(hContact, &id_block)) {
+ idb.user = id_block.user;
+ idb.community = id_block.community;
+
+ mwConversation *conv = mwServiceIm_getConversation(service_im, &idb);
+ if(conv) {
+ if(mwConversation_isOpen(conv))
+ mwConversation_close(conv, 0);
+ }
+ free(id_block.user);
+ }
+}
+
+void InitMessaging(mwSession *session) {
+ InitializeCriticalSection(&q_cs);
+
+ mwSession_addService(session, (mwService *)(service_im = mwServiceIm_new(session, &mwIm_handler)));
+ mwServiceIm_setClientType(service_im, mwImClient_PLAIN);
+}
+
+void DeinitMessaging(mwSession *session) {
+ mwSession_removeService(session, mwService_IM);
+ mwService_free((mwService *)service_im);
+ service_im = 0;
+
+ DeleteCriticalSection(&q_cs);
+}
+
diff --git a/plugins/!NotAdopted/sametime/messaging.h b/plugins/!NotAdopted/sametime/messaging.h
new file mode 100644
index 0000000000..d2860b220a
--- /dev/null
+++ b/plugins/!NotAdopted/sametime/messaging.h
@@ -0,0 +1,18 @@
+#ifndef _MESSAGING_INC
+#define _MESSAGING_INC
+
+#include "common.h"
+#include "userlist.h"
+#include "options.h"
+#include "utils.h"
+
+void SendTyping(HANDLE hContact, bool typing);
+HANDLE SendMessageToUser(HANDLE hContact, char *msg);
+HANDLE SendMessageToUserW(HANDLE hContact, wchar_t *msg);
+
+void CloseIm(HANDLE hContact);
+
+void InitMessaging(mwSession *session);
+void DeinitMessaging(mwSession *session);
+
+#endif
diff --git a/plugins/!NotAdopted/sametime/online.ico b/plugins/!NotAdopted/sametime/online.ico
new file mode 100644
index 0000000000..8362c83159
--- /dev/null
+++ b/plugins/!NotAdopted/sametime/online.ico
Binary files differ
diff --git a/plugins/!NotAdopted/sametime/options.cpp b/plugins/!NotAdopted/sametime/options.cpp
new file mode 100644
index 0000000000..438fab2282
--- /dev/null
+++ b/plugins/!NotAdopted/sametime/options.cpp
@@ -0,0 +1,328 @@
+#include "options.h"
+
+HWND hWndOptions = 0;
+
+Options options = {0};
+
+#define DEFAULT_ID (0x1800)
+
+#define NUM_IDS 20
+TCHAR *client_names[NUM_IDS] = {_T("Official Binary Library"), _T("Official Java Applet"), _T("Official Binary Application"),
+ _T("Official Java Application"), _T("Notes v6.5"), _T("Notes v7.0"), _T("ICT"), _T("NotesBuddy"), _T("NotesBuddy v4.15"), _T("Sanity"),
+ _T("Perl"), _T("PMR Alert"), _T("Trillian (SourceForge)"), _T("Trillian (IBM)"), _T("Meanwhile Library"), _T("Meanwhile (Python)"),
+ _T("Meanwhile (Gaim)"), _T("Meanwhile (Adium)"), _T("Meanwhile (Kopete)"), _T("Custom")};
+int client_ids[NUM_IDS] = {0x1000, 0x1001, 0x1002, 0x1003, 0x1200, 0x1210, 0x1300, 0x1400, 0x1405, 0x1600, 0x1625,
+ 0x1650, 0x16aa, 0x16bb, 0x1700, 0x1701, 0x1702, 0x1703, 0x1704, 0xFFFF};
+
+static BOOL CALLBACK DlgProcOptNet(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch ( msg ) {
+ case WM_INITDIALOG: {
+ TranslateDialogDefault( hwndDlg );
+
+ {
+ TCHAR verbuf[100];
+ WORD client_ver = GetClientVersion(), server_ver = GetServerVersion();
+ if(client_ver)
+ _stprintf(verbuf, _T("Client proto version: %03d.%03d"), (client_ver & 0xFF00) >> 8, client_ver & 0xFF);
+ else
+ _stprintf(verbuf, _T("Disconnected"));
+ SetDlgItemText(hwndDlg, IDC_ST_CLIENTVER, verbuf);
+ if(server_ver)
+ _stprintf(verbuf, _T("Server proto version: %03d.%03d"), (server_ver & 0xFF00) >> 8, server_ver & 0xFF);
+ else
+ _stprintf(verbuf, _T("Disconnected"));
+ SetDlgItemText(hwndDlg, IDC_ST_SERVERVER, verbuf);
+ }
+
+ hWndOptions = hwndDlg;
+
+ wchar_t *s;
+ s = u2w(options.server_name); SetDlgItemTextW(hwndDlg, IDC_ED_SNAME, s); free(s);
+ s = u2w(options.id); SetDlgItemTextW(hwndDlg, IDC_ED_NAME, s); free(s);
+ s = u2w(options.pword); SetDlgItemTextW(hwndDlg, IDC_ED_PWORD, s); free(s);
+
+ SetDlgItemInt(hwndDlg, IDC_ED_PORT, options.port, FALSE);
+ CheckDlgButton(hwndDlg, IDC_CHK_GETSERVERCONTACTS, options.get_server_contacts ? TRUE : FALSE);
+ CheckDlgButton(hwndDlg, IDC_CHK_ADDCONTACTS, options.add_contacts ? TRUE : FALSE);
+ CheckDlgButton(hwndDlg, IDC_CHK_IDLEAWAY, options.idle_as_away ? TRUE : FALSE);
+
+ CheckDlgButton(hwndDlg, IDC_CHK_OLDDEFAULTVER, options.use_old_default_client_ver ? TRUE : FALSE);
+ {
+ SendDlgItemMessage(hwndDlg, IDC_CMB_CLIENT, CB_RESETCONTENT, 0, 0);
+ int pos = 0;
+ bool found = false;
+
+ for(int i = 0; i < NUM_IDS; i++) {
+ pos = SendDlgItemMessage(hwndDlg, IDC_CMB_CLIENT, CB_ADDSTRING, -1, (LPARAM)client_names[i]);
+ SendDlgItemMessage(hwndDlg, IDC_CMB_CLIENT, CB_SETITEMDATA, pos, client_ids[i]);
+ if(client_ids[i] == options.client_id) {
+ found = true;
+ SendDlgItemMessage(hwndDlg, IDC_CMB_CLIENT, CB_SETCURSEL, pos, 0);
+ SetDlgItemInt(hwndDlg, IDC_ED_CLIENTID, client_ids[i], FALSE);
+ if(i != sizeof(client_ids) / sizeof(int) - 1) {
+ HWND hw = GetDlgItem(hwndDlg, IDC_ED_CLIENTID);
+ EnableWindow(hw, false);
+ }
+ }
+ }
+
+ if(!found) {
+ SendDlgItemMessage(hwndDlg, IDC_CMB_CLIENT, CB_SETCURSEL, pos, 0); // pos is last item, i.e. custom
+ SetDlgItemInt(hwndDlg, IDC_ED_CLIENTID, options.client_id, FALSE);
+ }
+ }
+
+ if(!ServiceExists(MS_POPUP_ADDPOPUP)) {
+ HWND hw = GetDlgItem(hwndDlg, IDC_RAD_ERRPOP);
+ EnableWindow(hw, FALSE);
+ }
+
+ if(!ServiceExists(MS_CLIST_SYSTRAY_NOTIFY)) {
+ HWND hw = GetDlgItem(hwndDlg, IDC_RAD_ERRBAL);
+ EnableWindow(hw, FALSE);
+ }
+
+ switch(options.err_method) {
+ case ED_POP: CheckDlgButton(hwndDlg, IDC_RAD_ERRPOP, TRUE); break;
+ case ED_MB: CheckDlgButton(hwndDlg, IDC_RAD_ERRMB, TRUE); break;
+ case ED_BAL: CheckDlgButton(hwndDlg, IDC_RAD_ERRBAL, TRUE); break;
+ }
+
+ if(options.encrypt_session)
+ CheckDlgButton(hwndDlg, IDC_RAD_ENC, TRUE);
+ else
+ CheckDlgButton(hwndDlg, IDC_RAD_NOENC, TRUE);
+
+ return FALSE;
+ }
+ case WM_COMMAND:
+ if ( HIWORD( wParam ) == EN_CHANGE && ( HWND )lParam == GetFocus()) {
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ if ( HIWORD( wParam ) == CBN_SELCHANGE) {
+ int sel = SendDlgItemMessage(hwndDlg, IDC_CMB_CLIENT, CB_GETCURSEL, 0, 0);
+ int id = SendDlgItemMessage(hwndDlg, IDC_CMB_CLIENT, CB_GETITEMDATA, sel, 0);
+ bool custom = (id == client_ids[sizeof(client_ids) / sizeof(int) - 1]);
+
+ if(!custom)
+ SetDlgItemInt(hwndDlg, IDC_ED_CLIENTID, id, FALSE);
+ else
+ SetDlgItemInt(hwndDlg, IDC_ED_CLIENTID, DEFAULT_ID, FALSE);
+
+ HWND hw = GetDlgItem(hwndDlg, IDC_ED_CLIENTID);
+ EnableWindow(hw, custom);
+
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+
+ if ( HIWORD( wParam ) == BN_CLICKED ) {
+ switch( LOWORD( wParam )) {
+ case IDC_BTN_UPLOADCONTACTS:
+ {
+ HWND hBut = GetDlgItem(hwndDlg, IDC_BTN_UPLOADCONTACTS);
+ EnableWindow(hBut, FALSE);
+ hBut = GetDlgItem(hwndDlg, IDC_BTN_IMPORTCONTACTS);
+ EnableWindow(hBut, FALSE);
+
+ ExportContactsToServer();
+
+ SendMessage(hwndDlg, WMU_STORECOMPLETE, 0, 0);
+ }
+ return TRUE;
+ case IDC_BTN_IMPORTCONTACTS:
+ {
+ OPENFILENAME ofn = {0};
+ TCHAR import_filename[MAX_PATH];
+ import_filename[0] = 0;
+
+ ofn.lStructSize = sizeof(ofn);
+ ofn.lpstrFile = import_filename;
+ ofn.hwndOwner = hwndDlg;
+ ofn.Flags = CC_FULLOPEN;
+ ofn.nMaxFile = MAX_PATH;
+ ofn.lpstrFilter = _T("All\0*.*\0");
+ ofn.nFilterIndex = 1;
+ ofn.lpstrFileTitle = NULL;
+ ofn.nMaxFileTitle = 0;
+ ofn.lpstrInitialDir = NULL;
+ ofn.Flags = OFN_PATHMUSTEXIST;
+
+ if(GetOpenFileName(&ofn) == TRUE) {
+ HWND hBut = GetDlgItem(hwndDlg, IDC_BTN_UPLOADCONTACTS);
+ EnableWindow(hBut, FALSE);
+ hBut = GetDlgItem(hwndDlg, IDC_BTN_IMPORTCONTACTS);
+ EnableWindow(hBut, FALSE);
+
+ ImportContactsFromFile(ofn.lpstrFile);
+
+ SendMessage(hwndDlg, WMU_STORECOMPLETE, 0, 0);
+ }
+ }
+ return TRUE;
+ case IDC_CHK_GETSERVERCONTACTS:
+ case IDC_CHK_ENCMESSAGES:
+ case IDC_RAD_ERRMB:
+ case IDC_RAD_ERRBAL:
+ case IDC_RAD_ERRPOP:
+ case IDC_CHK_USERCP:
+ case IDC_CHK_ADDCONTACTS:
+ case IDC_CHK_IDLEAWAY:
+ case IDC_CHK_OLDDEFAULTVER:
+ case IDC_RAD_ENC:
+ case IDC_RAD_NOENC:
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ return TRUE;
+ case IDC_RAD_ANSI:
+ case IDC_RAD_UTF8:
+ case IDC_RAD_OEM:
+ case IDC_RAD_UTF7:
+ case IDC_RAD_USERCP:
+ {
+ HWND hw = GetDlgItem(hwndDlg, IDC_CHK_USERCP);
+ EnableWindow(hw, !IsDlgButtonChecked(hwndDlg, IDC_RAD_USERCP));
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ return TRUE;
+ }
+ }
+ break;
+
+ case WMU_STORECOMPLETE:
+ {
+ HWND hBut = GetDlgItem(hwndDlg, IDC_BTN_UPLOADCONTACTS);
+ EnableWindow(hBut, TRUE);
+ hBut = GetDlgItem(hwndDlg, IDC_BTN_IMPORTCONTACTS);
+ EnableWindow(hBut, TRUE);
+ }
+ return TRUE;
+ case WM_NOTIFY:
+ if (((LPNMHDR)lParam)->code == PSN_APPLY ) {
+ wchar_t ws[2048];
+ char *utf;
+
+ GetDlgItemTextW(hwndDlg, IDC_ED_SNAME, ws, LSTRINGLEN);
+ strcpy(options.server_name, utf = w2u(ws)); free(utf);
+ GetDlgItemTextW(hwndDlg, IDC_ED_NAME, ws, LSTRINGLEN);
+ strcpy(options.id, utf = w2u(ws)); free(utf);
+ GetDlgItemTextW(hwndDlg, IDC_ED_PWORD, ws, LSTRINGLEN);
+ strcpy(options.pword, utf = w2u(ws)); free(utf);
+
+ BOOL translated;
+ int port = GetDlgItemInt(hwndDlg, IDC_ED_PORT, &translated, FALSE);
+ if(translated)
+ options.port = port;
+
+ options.get_server_contacts = (IsDlgButtonChecked(hwndDlg, IDC_CHK_GETSERVERCONTACTS) != FALSE);
+
+ int sel = SendDlgItemMessage(hwndDlg, IDC_CMB_CLIENT, CB_GETCURSEL, 0, 0);
+ int id = SendDlgItemMessage(hwndDlg, IDC_CMB_CLIENT, CB_GETITEMDATA, sel, 0);
+
+ if(id == client_ids[sizeof(client_ids) / sizeof(int) - 1]) {
+ BOOL trans;
+ id = GetDlgItemInt(hwndDlg, IDC_ED_CLIENTID, &trans, FALSE);
+ if(trans)
+ options.client_id = id;
+ } else
+ options.client_id = id;
+
+ if(IsDlgButtonChecked(hwndDlg, IDC_RAD_ERRMB)) options.err_method = ED_MB;
+ else if(IsDlgButtonChecked(hwndDlg, IDC_RAD_ERRBAL)) options.err_method = ED_BAL;
+ else if(IsDlgButtonChecked(hwndDlg, IDC_RAD_ERRPOP)) options.err_method = ED_POP;
+
+ options.add_contacts = (IsDlgButtonChecked(hwndDlg, IDC_CHK_ADDCONTACTS) != FALSE);
+ options.encrypt_session = (IsDlgButtonChecked(hwndDlg, IDC_RAD_ENC) != FALSE);
+ options.idle_as_away = (IsDlgButtonChecked(hwndDlg, IDC_CHK_IDLEAWAY) != FALSE);
+
+ options.use_old_default_client_ver = (IsDlgButtonChecked(hwndDlg, IDC_CHK_OLDDEFAULTVER) != FALSE);
+
+ SaveOptions();
+
+ return TRUE;
+ }
+ break;
+ case WM_DESTROY:
+ hWndOptions = 0;
+ break;
+ }
+
+ return FALSE;
+}
+
+int OptInit(WPARAM wParam,LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE odp = { 0 };
+ TCHAR *temp_proto = a2t(PROTO);
+
+ odp.flags = ODPF_BOLDGROUPS;
+#ifdef _UNICODE
+ odp.flags |= ODPF_UNICODE;
+#endif
+ odp.cbSize = sizeof(odp);
+ odp.position = -790000000;
+ odp.hInstance = hInst;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPTNET);
+ odp.ptszTitle = TranslateTS(temp_proto);
+ odp.ptszGroup = TranslateT("Network");
+ odp.pfnDlgProc = DlgProcOptNet;
+ CallService( MS_OPT_ADDPAGE, wParam,( LPARAM )&odp );
+
+ free(temp_proto);
+
+ return 0;
+}
+
+void LoadOptions() {
+ DBVARIANT dbv;
+
+ if(!DBGetContactSettingUtf(0, PROTO, "ServerName", &dbv)) {
+ strncpy(options.server_name, dbv.pszVal, LSTRINGLEN);
+ DBFreeVariant(&dbv);
+ }
+ if(!DBGetContactSettingUtf(0, PROTO, "stid", &dbv)) {
+ strncpy(options.id, dbv.pszVal, LSTRINGLEN);
+ DBFreeVariant(&dbv);
+ }
+ if(!DBGetContactSettingUtf(0, PROTO, "PWord", &dbv)) {
+ strncpy(options.pword, dbv.pszVal, LSTRINGLEN);
+ DBFreeVariant(&dbv);
+
+ CallService(MS_DB_CRYPT_DECODESTRING, (WPARAM)LSTRINGLEN, (LPARAM)options.pword);
+ }
+
+ options.port = DBGetContactSettingDword(0, PROTO, "ServerPort", DEFAULT_PORT);
+ options.get_server_contacts = (DBGetContactSettingByte(0, PROTO, "GetServerContacts", 1) == 1);
+ options.client_id = DBGetContactSettingDword(0, PROTO, "ClientID", DEFAULT_ID);
+
+ // if popups not installed, will be changed to 'ED_BAL' (balloons) in main.cpp, modules loaded
+ options.err_method = (ErrorDisplay)DBGetContactSettingByte(0, PROTO, "ErrorDisplay", ED_POP);
+
+ options.add_contacts = (DBGetContactSettingByte(0, PROTO, "AutoAddContacts", 0) == 1);
+ options.encrypt_session = (DBGetContactSettingByte(0, PROTO, "EncryptSession", 0) == 1);
+ options.idle_as_away = (DBGetContactSettingByte(0, PROTO, "IdleAsAway", 1) == 1);
+
+ options.use_old_default_client_ver = (DBGetContactSettingByte(0, PROTO, "UseOldClientVer", 0) == 1);
+}
+
+void SaveOptions() {
+ DBWriteContactSettingStringUtf(0, PROTO, "ServerName", options.server_name);
+
+ DBWriteContactSettingStringUtf(0, PROTO, "stid", options.id);
+ //DBWriteContactSettingString(0, PROTO, "Nick", options.id);
+
+ char buff[LSTRINGLEN];
+ strcpy(buff, options.pword);
+ CallService(MS_DB_CRYPT_ENCODESTRING, (WPARAM)LSTRINGLEN, (LPARAM)buff);
+ DBWriteContactSettingStringUtf(0, PROTO, "PWord", buff);
+
+ DBWriteContactSettingDword(0, PROTO, "ServerPort", options.port);
+ DBWriteContactSettingByte(0, PROTO, "GetServerContacts", options.get_server_contacts ? 1 : 0);
+ DBWriteContactSettingDword(0, PROTO, "ClientID", options.client_id);
+ DBWriteContactSettingByte(0, PROTO, "ErrorDisplay", options.err_method);
+
+ DBWriteContactSettingByte(0, PROTO, "AutoAddContacts", options.add_contacts ? 1 : 0);
+ DBWriteContactSettingByte(0, PROTO, "EncryptSession", options.encrypt_session ? 1 : 0);
+ DBWriteContactSettingByte(0, PROTO, "IdleAsAway", options.idle_as_away ? 1 : 0);
+
+ DBWriteContactSettingByte(0, PROTO, "UseOldClientVer", options.use_old_default_client_ver ? 1 : 0);
+}
diff --git a/plugins/!NotAdopted/sametime/options.h b/plugins/!NotAdopted/sametime/options.h
new file mode 100644
index 0000000000..b5569c0e52
--- /dev/null
+++ b/plugins/!NotAdopted/sametime/options.h
@@ -0,0 +1,44 @@
+#ifndef _OPTIONS_INC
+#define _OPTIONS_INC
+
+#include "common.h"
+#include "session.h"
+#include "userlist.h"
+#include "utils.h"
+
+#include "resource.h"
+
+#define LSTRINGLEN 256
+
+typedef enum {ED_MB, ED_POP, ED_BAL} ErrorDisplay;
+typedef enum {CPT_USER, CPT_ANSI, CPT_UTF8, CPT_OEM, CPT_UTF7} CodePageType;
+
+typedef struct Options_tag {
+ char server_name[LSTRINGLEN];
+ char id[LSTRINGLEN];
+ char pword[LSTRINGLEN];
+ int port;
+ bool get_server_contacts;
+ int client_id;
+ ErrorDisplay err_method;
+ bool add_contacts;
+ bool encrypt_session;
+ bool idle_as_away;
+ bool use_old_default_client_ver;
+} Options;
+
+extern Options options;
+
+#define DEFAULT_PORT 1533
+
+BOOL CALLBACK DlgProcOptNet(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+int OptInit(WPARAM wParam,LPARAM lParam);
+void LoadOptions();
+void SaveOptions();
+
+extern HWND hWndOptions;
+
+#define WMU_STORECOMPLETE (WM_USER + 110)
+
+#endif
diff --git a/plugins/!NotAdopted/sametime/part.ico b/plugins/!NotAdopted/sametime/part.ico
new file mode 100644
index 0000000000..1b698a76b3
--- /dev/null
+++ b/plugins/!NotAdopted/sametime/part.ico
Binary files differ
diff --git a/plugins/!NotAdopted/sametime/places.cpp b/plugins/!NotAdopted/sametime/places.cpp
new file mode 100644
index 0000000000..9012c177f0
--- /dev/null
+++ b/plugins/!NotAdopted/sametime/places.cpp
@@ -0,0 +1,54 @@
+#include "places.h"
+
+mwServicePlace *service_places = 0;
+
+void mwServicePlace_opened(struct mwPlace *place) {
+}
+
+void mwServicePlace_closed(struct mwPlace *place, guint32 code) {
+}
+
+void mwServicePlace_peerJoined(struct mwPlace *place, const struct mwIdBlock *peer) {
+}
+
+
+void mwServicePlace_peerParted(struct mwPlace *place, const struct mwIdBlock *peer) {
+}
+
+
+void mwServicePlace_peerSetAttribute(struct mwPlace *place, const struct mwIdBlock *peer, guint32 attr, struct mwOpaque *o) {
+}
+
+
+void mwServicePlace_peerUnsetAttribute(struct mwPlace *place, const struct mwIdBlock *peer, guint32 attr) {
+}
+
+
+void mwServicePlace_message(struct mwPlace *place, const struct mwIdBlock *who, const char *msg) {
+}
+
+
+void mwServicePlace_clear(struct mwServicePlace *srvc) {
+}
+
+
+mwPlaceHandler mwPlace_handler = {
+ mwServicePlace_opened,
+ mwServicePlace_closed,
+ mwServicePlace_peerJoined,
+ mwServicePlace_peerParted,
+ mwServicePlace_peerSetAttribute,
+ mwServicePlace_peerUnsetAttribute,
+ mwServicePlace_message,
+ mwServicePlace_clear
+};
+
+void InitPlaces(mwSession *session) {
+ mwSession_addService(session, (mwService *)(service_places = mwServicePlace_new(session, &mwPlace_handler)));
+}
+
+void DeinitPlaces(mwSession *session) {
+ mwSession_removeService(session, mwService_PLACE);
+ mwService_free((mwService *)service_places);
+ service_places = 0;
+}
diff --git a/plugins/!NotAdopted/sametime/places.h b/plugins/!NotAdopted/sametime/places.h
new file mode 100644
index 0000000000..a058fc6b43
--- /dev/null
+++ b/plugins/!NotAdopted/sametime/places.h
@@ -0,0 +1,11 @@
+#ifndef _PLACES_INC
+#define _PLACES_INC
+
+#include "common.h"
+#include "userlist.h"
+#include "options.h"
+
+void InitPlaces(mwSession *session);
+void DeinitPlaces(mwSession *session);
+
+#endif \ No newline at end of file
diff --git a/plugins/!NotAdopted/sametime/resource.h b/plugins/!NotAdopted/sametime/resource.h
new file mode 100644
index 0000000000..ab630bd238
--- /dev/null
+++ b/plugins/!NotAdopted/sametime/resource.h
@@ -0,0 +1,57 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by resource.rc
+//
+#define IDD_DIALOG1 101
+#define IDD_OPTNET 101
+#define IDI_ICON_PROTO 102
+#define IDI_ICON_LEAVE 104
+#define IDI_ICON_INVITE 105
+#define IDI_ANNOUNCE 107
+#define IDD_SESSIONANNOUNCE 108
+#define IDD_USERSEARCH 109
+#define IDC_ED_SNAME 1000
+#define IDC_ED_NAME 1001
+#define IDC_ED_PWORD 1002
+#define IDC_ED_PORT 1003
+#define IDC_CHK_GETSERVERCONTACTS 1004
+#define IDC_BTN_UPLOADCONTACTS 1005
+#define IDC_CHK_ENCMESSAGES 1006
+#define IDC_BTN_IMPORTCONTACTS 1007
+#define IDC_CHK_UTF8 1008
+#define IDC_CHK_ADDCONTACTS 1008
+#define IDC_CHK_IDLEAWAY 1009
+#define IDC_CMB_CLIENT 1010
+#define IDC_ED_CLIENTID 1011
+#define IDC_RAD_ERRMB 1012
+#define IDC_RAD_ERRPOP 1013
+#define IDC_RAD_ERRBAL 1014
+#define IDC_RAD_ANSI 1015
+#define IDC_CHK_OLDDEFAULTVER 1016
+#define IDC_RAD_UTF8 1017
+#define IDC_CHK_USERCP 1018
+#define IDC_RAD_OEM 1019
+#define IDC_RAD_ENC 1020
+#define IDC_RAD_UTF7 1021
+#define IDC_RAD_NOENC 1022
+#define IDC_RAD_ANSI2 1023
+#define IDC_RAD_USERCP 1024
+#define IDC_ED_ANMSG 1025
+#define IDC_LST_ANTO 1026
+#define IDC_BUT_SELALL 1027
+#define IDC_BUT_SELINV 1028
+#define IDC_ST_CLIENTVER 1029
+#define IDC_ST_SERVERVER 1030
+#define IDC_EDIT1 1031
+#define IDC_ST_LIBVER 1032
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 111
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1033
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/plugins/!NotAdopted/sametime/resource.rc b/plugins/!NotAdopted/sametime/resource.rc
new file mode 100644
index 0000000000..69992e24a9
--- /dev/null
+++ b/plugins/!NotAdopted/sametime/resource.rc
@@ -0,0 +1,175 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (Australia) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_OPTNET DIALOGEX 0, 0, 314, 203
+STYLE DS_SETFONT | WS_CHILD
+FONT 8, "MS Sans Serif", 0, 0, 0x0
+BEGIN
+ RTEXT "Server name:",IDC_STATIC,14,61,49,8
+ EDITTEXT IDC_ED_SNAME,70,57,92,14,ES_AUTOHSCROLL
+ RTEXT "Port:",IDC_STATIC,14,81,49,8
+ EDITTEXT IDC_ED_PORT,70,77,36,14,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER
+ CONTROL "Get contacts from server",IDC_CHK_GETSERVERCONTACTS,
+ "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,180,15,115,15
+ PUSHBUTTON "Upload Contacts",IDC_BTN_UPLOADCONTACTS,180,29,115,15
+ PUSHBUTTON "Import from file...",IDC_BTN_IMPORTCONTACTS,180,48,115,15
+ COMBOBOX IDC_CMB_CLIENT,10,109,114,107,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ EDITTEXT IDC_ED_CLIENTID,126,109,37,12,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER
+ RTEXT "Id:",IDC_STATIC,14,17,49,8
+ EDITTEXT IDC_ED_NAME,70,13,92,14,ES_AUTOHSCROLL
+ RTEXT "Password:",IDC_STATIC,14,39,49,8
+ EDITTEXT IDC_ED_PWORD,70,35,92,14,ES_PASSWORD | ES_AUTOHSCROLL
+ GROUPBOX "Error Display",IDC_STATIC,7,143,161,53
+ CONTROL "Use message boxes",IDC_RAD_ERRMB,"Button",BS_AUTORADIOBUTTON | WS_GROUP,20,156,122,10
+ CONTROL "Use popups",IDC_RAD_ERRPOP,"Button",BS_AUTORADIOBUTTON,20,169,122,10
+ CONTROL "Use system tray baloons",IDC_RAD_ERRBAL,"Button",BS_AUTORADIOBUTTON,21,182,122,10
+ GROUPBOX "Connection",IDC_STATIC,7,7,161,91
+ GROUPBOX "Contacts",IDC_STATIC,172,7,135,91
+ GROUPBOX "Client ID",IDC_STATIC,7,98,161,44
+ CONTROL "Auto-add new contacts",IDC_CHK_ADDCONTACTS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,180,67,115,11
+ GROUPBOX "Encryption",IDC_STATIC,172,98,135,44
+ CONTROL "40 or 128 bit",IDC_RAD_ENC,"Button",BS_AUTORADIOBUTTON | WS_GROUP,190,113,88,10
+ CONTROL "None",IDC_RAD_NOENC,"Button",BS_AUTORADIOBUTTON,190,126,88,10
+ CTEXT "Static",IDC_ST_CLIENTVER,185,165,102,12,SS_SUNKEN
+ CTEXT "Static",IDC_ST_SERVERVER,185,180,102,12,SS_SUNKEN
+ CONTROL "Treat 'idle' as 'away'",IDC_CHK_IDLEAWAY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,180,81,115,11
+ CTEXT "Meanwhile lib ver: 1.0.2",IDC_ST_LIBVER,185,150,102,12
+ GROUPBOX "",IDC_STATIC,172,143,135,53
+ CONTROL "Use old client version",IDC_CHK_OLDDEFAULTVER,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,33,127,115,11
+END
+
+IDD_SESSIONANNOUNCE DIALOG 0, 0, 286, 263
+STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Send Announcement"
+FONT 8, "MS Sans Serif"
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,95,242,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,150,242,50,14
+ EDITTEXT IDC_ED_ANMSG,10,20,264,60,ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN
+ LTEXT "Message Text:",IDC_STATIC,9,9,142,8
+ CONTROL "List1",IDC_LST_ANTO,"SysListView32",LVS_REPORT | WS_BORDER | WS_TABSTOP,10,92,197,132
+ PUSHBUTTON "Select All",IDC_BUT_SELALL,214,122,58,36
+ PUSHBUTTON "Invert\n Selection",IDC_BUT_SELINV,214,167,58,36,BS_MULTILINE
+END
+
+IDD_USERSEARCH DIALOG 0, 0, 155, 86
+STYLE DS_SETFONT | WS_POPUP
+FONT 8, "MS Sans Serif"
+BEGIN
+ EDITTEXT IDC_EDIT1,34,32,103,14,ES_AUTOHSCROLL
+ LTEXT "ID:",IDC_STATIC,18,35,10,8
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_OPTNET, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 307
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 196
+ END
+
+ IDD_SESSIONANNOUNCE, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 279
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 256
+ END
+
+ IDD_USERSEARCH, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 148
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 79
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_ICON_PROTO ICON "online.ico"
+IDI_ICON_LEAVE ICON "part.ico"
+IDI_ICON_INVITE ICON "invite.ico"
+IDI_ANNOUNCE ICON "announce.ico"
+#endif // English (Australia) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/plugins/!NotAdopted/sametime/sametime.cpp b/plugins/!NotAdopted/sametime/sametime.cpp
new file mode 100644
index 0000000000..dbc26851d7
--- /dev/null
+++ b/plugins/!NotAdopted/sametime/sametime.cpp
@@ -0,0 +1,845 @@
+// sametime.cpp: Defines the entry point for the DLL application.
+
+#include "common.h"
+#include "options.h"
+#include "session.h"
+#include "userlist.h"
+#include "messaging.h"
+#include "files.h"
+#include "conference.h"
+#include "utils.h"
+
+#define FAILED_MESSAGE_HANDLE 99998
+
+char PROTO[64];
+char PROTO_GROUPS[128];
+
+bool unicode_chat = false;
+int code_page = CP_ACP;
+MM_INTERFACE mmi;
+UTF8_INTERFACE utfi;
+
+HINSTANCE hInst;
+PLUGINLINK *pluginLink;
+
+HANDLE hNetlibUser = 0;
+
+HANDLE hWindowEventHook = 0, hIdleEventHook = 0;
+
+HANDLE mainThread;
+DWORD mainThreadId;
+
+int previous_status, current_status;
+
+bool is_idle = false;
+
+// plugin stuff
+PLUGININFOEX pluginInfo={
+ sizeof(PLUGININFOEX),
+ "Sametime Protocol",
+ PLUGIN_MAKE_VERSION(0, 5, 9, 1),
+ "Implementation of Instant Messaging for the Lotus Sametime protocol.",
+ "Scott Ellis",
+ "mail@scottellis.com.au",
+ "© 2005 Scott Ellis",
+ "http://www.scottellis.com.au/",
+ UNICODE_AWARE, //not transient
+ 0, //doesn't replace anything built-in
+ { 0xf1b0ba1b, 0xc91, 0x4313, { 0x85, 0xeb, 0x22, 0x50, 0x69, 0xd4, 0x4d, 0x1 } } // {F1B0BA1B-0C91-4313-85EB-225069D44D01}
+};
+
+extern "C" BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)
+{
+ hInst=hinstDLL;
+ return TRUE;
+}
+
+extern "C" SAMETIME_API PLUGININFO* MirandaPluginInfo(DWORD mirandaVersion)
+{
+ pluginInfo.cbSize = sizeof(PLUGININFO);
+ return (PLUGININFO*)&pluginInfo;
+}
+
+static const MUUID interfaces[] = {MIID_PROTOCOL, MIID_LAST};
+extern "C" __declspec(dllexport) const MUUID* MirandaPluginInterfaces(void)
+{
+ return interfaces;
+}
+
+
+extern "C" SAMETIME_API PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion)
+{
+ return &pluginInfo;
+}
+
+
+
+// protocol related services
+int GetCaps(WPARAM wParam,LPARAM lParam)
+{
+ int ret = 0;
+ switch (wParam) {
+ case PFLAGNUM_1:
+ //ret = PF1_IM | PF1_BASICSEARCH | PF1_ADDSEARCHRES | PF1_MODEMSG | PF1_FILE | PF1_CHAT;
+ ret = PF1_IM | PF1_BASICSEARCH | PF1_EXTSEARCHUI | PF1_ADDSEARCHRES | PF1_MODEMSG | PF1_FILE | PF1_CHAT;
+ break;
+ case PFLAGNUM_2:
+ ret = PF2_ONLINE | PF2_SHORTAWAY | PF2_HEAVYDND | PF2_LIGHTDND;
+ break;
+ case PFLAGNUM_3:
+ ret = PF2_ONLINE | PF2_SHORTAWAY | PF2_HEAVYDND;
+ break;
+ case PFLAGNUM_4:
+ ret = PF4_SUPPORTTYPING;
+ break;
+ case PFLAGNUM_5:
+ ret = PF2_LIGHTDND;
+ break;
+ case PFLAG_UNIQUEIDTEXT:
+ ret = (int) Translate("Id");
+ break;
+ case PFLAG_MAXLENOFMESSAGE:
+ ret = MAX_MESSAGE_SIZE;
+ break;
+ case PFLAG_UNIQUEIDSETTING:
+ ret = (int) "stid";
+ break;
+ }
+ return ret;
+}
+
+/** Copy the name of the protocole into lParam
+* @param wParam : max size of the name
+* @param lParam : reference to a char *, which will hold the name
+*/
+int GetName(WPARAM wParam,LPARAM lParam)
+{
+ char *name = (char *)Translate(PROTO);
+ size_t size = min(strlen(name),wParam-1); // copy only the first size bytes.
+ if(strncpy((char *)lParam,name,size)==NULL)
+ return 1;
+ ((char *)lParam)[size]='\0';
+ return 0;
+}
+
+/** Loads the icon corresponding to the status
+* Called by the CList when the status changes.
+* @param wParam : one of the following values : \n
+ <tt>PLI_PROTOCOL | PLI_ONLINE | PLI_OFFLINE</tt>
+* @return an \c HICON in which the icon has been loaded.
+*/
+int LoadIcon(WPARAM wParam,LPARAM lParam)
+{
+
+ UINT id;
+ switch (wParam & 0xFFFF)
+ {
+ case PLI_PROTOCOL:
+ id = IDI_ICON_PROTO;
+ break;
+ case PLI_ONLINE:
+ id = IDI_ICON_PROTO;
+ break;
+ case PLI_OFFLINE:
+ id = IDI_ICON_PROTO;
+ break;
+ default:
+ return (int) (HICON) NULL;
+ }
+
+ return (int) LoadImage(hInst, MAKEINTRESOURCE(id), IMAGE_ICON,
+ GetSystemMetrics(wParam & PLIF_SMALL ? SM_CXSMICON : SM_CXICON),
+ GetSystemMetrics(wParam & PLIF_SMALL ? SM_CYSMICON : SM_CYICON), 0);
+ return 0;
+}
+
+
+/** Changes the status and notifies everybody
+* @param wParam : The new mode
+* @param lParam : Allways set to 0.
+*/
+int SetStatus(WPARAM wParam,LPARAM lParam)
+{
+ if((int)wParam != ID_STATUS_OFFLINE) {
+ if(current_status == ID_STATUS_OFFLINE)
+ LogIn((int)wParam, hNetlibUser);
+ else
+ SetSessionStatus((int)wParam);
+ } else if(current_status != ID_STATUS_OFFLINE && (int)wParam == ID_STATUS_OFFLINE) {
+ LogOut();
+ }
+
+ return 0;
+}
+
+/** Returns the current status
+*/
+int GetStatus(WPARAM wParam,LPARAM lParam)
+{
+ return current_status;
+}
+
+
+//////////////////////////////////////////////////////////
+/// Copied from MSN plugin - sent acks need to be from different thread :(
+//////////////////////////////////////////////////////////
+typedef struct tag_TFakeAckParams
+{
+ HANDLE hEvent;
+ HANDLE hContact;
+ LPARAM lParam;
+} TFakeAckParams;
+
+
+static DWORD CALLBACK sttFakeAckInfoSuccess( LPVOID param )
+{
+ TFakeAckParams *tParam = ( TFakeAckParams* )param;
+ WaitForSingleObject( tParam->hEvent, INFINITE );
+
+ Sleep( 100 );
+ ProtoBroadcastAck(PROTO, tParam->hContact, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, ( HANDLE )1, 0 );
+
+ CloseHandle( tParam->hEvent );
+ free(tParam);
+ return 0;
+}
+
+static DWORD CALLBACK sttFakeAckMessageSuccess( LPVOID param )
+{
+ TFakeAckParams *tParam = ( TFakeAckParams* )param;
+ WaitForSingleObject( tParam->hEvent, INFINITE );
+
+ Sleep( 100 );
+ ProtoBroadcastAck(PROTO, tParam->hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, ( HANDLE )tParam->lParam, 0 );
+
+ CloseHandle( tParam->hEvent );
+ free(tParam);
+ return 0;
+}
+
+static DWORD CALLBACK sttFakeAckMessageFailed( LPVOID param )
+{
+ TFakeAckParams *tParam = ( TFakeAckParams* )param;
+ WaitForSingleObject( tParam->hEvent, INFINITE );
+
+ Sleep( 100 );
+ ProtoBroadcastAck(PROTO, tParam->hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, (HANDLE)FAILED_MESSAGE_HANDLE, tParam->lParam);
+
+ CloseHandle( tParam->hEvent );
+ free(tParam);
+ return 0;
+}
+
+int GetInfo(WPARAM wParam, LPARAM lParam) {
+ CCSDATA *ccs = (CCSDATA *) lParam;
+ DWORD dwThreadId;
+ HANDLE hEvent;
+ TFakeAckParams *tfap;
+
+ hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
+
+ tfap = (TFakeAckParams *)malloc(sizeof(TFakeAckParams));
+ tfap->hContact = ccs->hContact;
+ tfap->hEvent = hEvent;
+
+ CloseHandle( CreateThread( NULL, 0, sttFakeAckInfoSuccess, tfap, 0, &dwThreadId ));
+ SetEvent( hEvent );
+
+ return 0;
+}
+
+int BasicSearch(WPARAM wParam, LPARAM lParam) {
+ const char *szId = (const char *)lParam;
+
+ return (int)SearchForUser(szId);
+}
+
+int AddToList(WPARAM wParam, LPARAM lParam) {
+ MYPROTOSEARCHRESULT *mpsr = (MYPROTOSEARCHRESULT *)lParam;
+
+ return (int)AddSearchedUser(mpsr, wParam & PALF_TEMPORARY);
+}
+
+int RecvMessage(WPARAM wParam, LPARAM lParam) {
+ DBEVENTINFO dbei;
+ CCSDATA* ccs = (CCSDATA*)lParam;
+ PROTORECVEVENT* pre = (PROTORECVEVENT*)ccs->lParam;
+
+ DBDeleteContactSetting(ccs->hContact, "CList", "Hidden");
+
+ ZeroMemory(&dbei, sizeof(dbei));
+ dbei.cbSize = sizeof(dbei);
+ dbei.szModule = PROTO;
+ dbei.timestamp = pre->timestamp;
+ dbei.flags = (pre->flags & PREF_CREATEREAD) ? DBEF_READ : 0;
+ dbei.eventType = EVENTTYPE_MESSAGE;
+ dbei.cbBlob = strlen(pre->szMessage) + 1;
+ if ( pre->flags & PREF_UNICODE )
+ dbei.cbBlob *= ( sizeof( wchar_t )+1 );
+ dbei.pBlob = (PBYTE)pre->szMessage;
+
+ CallService(MS_DB_EVENT_ADD, (WPARAM)ccs->hContact, (LPARAM)&dbei);
+ return 0;
+}
+
+int STSendMessage(WPARAM wParam, LPARAM lParam) {
+ if (lParam)
+ {
+ CCSDATA* ccs = (CCSDATA*)lParam;
+
+ char *proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)ccs->hContact, 0);
+
+ if(!proto || strcmp(proto, PROTO) != 0 || DBGetContactSettingWord(ccs->hContact, PROTO, "Status", ID_STATUS_OFFLINE) == ID_STATUS_OFFLINE) {
+ HANDLE hEvent;
+ TFakeAckParams *tfap;
+
+ hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
+
+ tfap = (TFakeAckParams *)malloc(sizeof(TFakeAckParams));
+ tfap->hContact = ccs->hContact;
+ tfap->hEvent = hEvent;
+ tfap->lParam = 0;
+
+ CloseHandle( CreateThread( NULL, 0, sttFakeAckMessageFailed, tfap, 0, 0 ));
+ SetEvent( hEvent );
+ return FAILED_MESSAGE_HANDLE;
+ }
+
+ int ret = 0;
+ char *p = (char *)ccs->lParam;
+ if(ccs->wParam & PREF_UNICODE)
+ ret = (int)SendMessageToUserW(ccs->hContact, (wchar_t *)&p[strlen(p) + 1]);
+ else
+ ret = (int)SendMessageToUser(ccs->hContact, (char *)ccs->lParam);
+
+ DWORD dwThreadId;
+ HANDLE hEvent;
+ TFakeAckParams *tfap;
+
+ hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
+
+ tfap = (TFakeAckParams *)malloc(sizeof(TFakeAckParams));
+ tfap->hContact = ccs->hContact;
+ tfap->hEvent = hEvent;
+ tfap->lParam = (LPARAM)ret;
+
+ CloseHandle( CreateThread( NULL, 0, sttFakeAckMessageSuccess, tfap, 0, &dwThreadId ));
+ SetEvent( hEvent );
+
+ return ret;
+ }
+ return 0;
+}
+
+int STSendMessageW(WPARAM wParam, LPARAM lParam) {
+ if (lParam)
+ {
+ CCSDATA* ccs = (CCSDATA*)lParam;
+
+ char *proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)ccs->hContact, 0);
+
+ if(!proto || strcmp(proto, PROTO) != 0 || DBGetContactSettingWord(ccs->hContact, PROTO, "Status", ID_STATUS_OFFLINE) == ID_STATUS_OFFLINE) {
+ DWORD dwThreadId;
+ HANDLE hEvent;
+ TFakeAckParams *tfap;
+
+ hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
+
+ tfap = (TFakeAckParams *)malloc(sizeof(TFakeAckParams));
+ tfap->hContact = ccs->hContact;
+ tfap->hEvent = hEvent;
+ tfap->lParam = 0;
+
+ CloseHandle( CreateThread( NULL, 0, sttFakeAckMessageFailed, tfap, 0, &dwThreadId ));
+ SetEvent( hEvent );
+ return FAILED_MESSAGE_HANDLE;
+ }
+
+ int ret = 0;
+ char *p = (char *)ccs->lParam;
+ ret = (int)SendMessageToUserW(ccs->hContact, (wchar_t *)&p[strlen(p) + 1]);
+
+ DWORD dwThreadId;
+ HANDLE hEvent;
+ TFakeAckParams *tfap;
+
+ hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
+
+ tfap = (TFakeAckParams *)malloc(sizeof(TFakeAckParams));
+ tfap->hContact = ccs->hContact;
+ tfap->hEvent = hEvent;
+ tfap->lParam = (LPARAM)ret;
+
+ CloseHandle( CreateThread( NULL, 0, sttFakeAckMessageSuccess, tfap, 0, &dwThreadId ));
+ SetEvent( hEvent );
+
+ return ret;
+ }
+ return 0;
+}
+
+int SetAwayMessage(WPARAM wParam, LPARAM lParam) {
+ SetSessionAwayMessage(wParam, (char *)lParam);
+ return 0;
+}
+
+static DWORD CALLBACK sttRecvAway( LPVOID param )
+{
+ TFakeAckParams *tParam = ( TFakeAckParams* )param;
+ WaitForSingleObject( tParam->hEvent, INFINITE );
+
+ Sleep( 100 );
+ UserRecvAwayMessage(tParam->hContact);
+
+ CloseHandle( tParam->hEvent );
+ free(tParam);
+ return 0;
+}
+
+int GetAwayMessage(WPARAM wParam, LPARAM lParam) {
+ if (lParam && current_status != ID_STATUS_OFFLINE)
+ {
+ CCSDATA* ccs = (CCSDATA*)lParam;
+
+ DWORD dwThreadId;
+ HANDLE hEvent;
+ TFakeAckParams *tfap;
+
+ hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
+
+ tfap = (TFakeAckParams *)malloc(sizeof(TFakeAckParams));
+ tfap->hContact = ccs->hContact;
+ tfap->hEvent = hEvent;
+
+ CloseHandle( CreateThread( NULL, 0, sttRecvAway, tfap, 0, &dwThreadId ));
+ SetEvent( hEvent );
+
+ return 1;
+ }
+ return 0;
+}
+
+int RecvAwayMessage(WPARAM wParam, LPARAM lParam) {
+ CCSDATA* ccs = (CCSDATA*)lParam;
+ PROTORECVEVENT* pre = (PROTORECVEVENT*)ccs->lParam;
+
+ char *msg = utfi.utf8_decodecp(pre->szMessage, code_page, 0);
+ ProtoBroadcastAck(PROTO, ccs->hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)1, (LPARAM)msg);
+ mir_free(msg);
+
+ return 0;
+}
+
+int SendTyping(WPARAM wParam, LPARAM lParam) {
+ SendTyping((HANDLE)wParam, lParam == PROTOTYPE_SELFTYPING_ON);
+ return 0;
+}
+
+int RecvFile(WPARAM wParam, LPARAM lParam)
+{
+ DBEVENTINFO dbei;
+ CCSDATA* ccs = (CCSDATA*)lParam;
+ PROTORECVEVENT* pre = (PROTORECVEVENT*)ccs->lParam;
+ char* szDesc;
+ char* szFile;
+
+ DBDeleteContactSetting(ccs->hContact, "CList", "Hidden");
+
+ szFile = pre->szMessage + sizeof(DWORD);
+ szDesc = szFile + strlen(szFile) + 1;
+
+ ZeroMemory(&dbei, sizeof(dbei));
+ dbei.cbSize = sizeof(dbei);
+ dbei.szModule = PROTO;
+ dbei.timestamp = pre->timestamp;
+ dbei.flags = (pre->flags & PREF_CREATEREAD) ? DBEF_READ : 0;
+ dbei.eventType = EVENTTYPE_FILE;
+ dbei.cbBlob = sizeof(DWORD) + strlen(szFile) + strlen(szDesc) + 2;
+ dbei.pBlob = (PBYTE)pre->szMessage;
+
+ CallService(MS_DB_EVENT_ADD, (WPARAM)ccs->hContact, (LPARAM)&dbei);
+
+ return 0;
+}
+
+int AllowFile(WPARAM wParam, LPARAM lParam) {
+ if (lParam)
+ {
+ CCSDATA* ccs = (CCSDATA*)lParam;
+ return (int)AcceptFileTransfer(ccs->hContact, (HANDLE)(ccs->wParam), (char *)ccs->lParam);
+
+ }
+ return 0;
+}
+
+int DenyFile(WPARAM wParam, LPARAM lParam) {
+ if (lParam)
+ {
+ CCSDATA* ccs = (CCSDATA*)lParam;
+ RejectFileTransfer((HANDLE)(ccs->wParam));
+ }
+ return 0;
+}
+
+int SendFiles(WPARAM wParam, LPARAM lParam) {
+ if (lParam && current_status != ID_STATUS_OFFLINE)
+ {
+ CCSDATA* ccs = (CCSDATA*)lParam;
+
+ if (ccs->hContact && ccs->lParam && ccs->wParam) {
+ HANDLE hContact = ccs->hContact;
+ char** files = (char**)ccs->lParam;
+ char* pszDesc = (char*)ccs->wParam;
+
+ if (DBGetContactSettingWord(hContact, PROTO, "Status", ID_STATUS_OFFLINE) != ID_STATUS_OFFLINE) {
+ return (int)SendFilesToUser(hContact, files, pszDesc);
+ }
+
+ }
+ }
+ return 0; // failure
+}
+
+int CancelFile(WPARAM wParam, LPARAM lParam) {
+ if (lParam)
+ {
+ CCSDATA* ccs = (CCSDATA*)lParam;
+ CancelFileTransfer((HANDLE)(ccs->wParam));
+ }
+ return 0;
+}
+
+void CreatePluginServices() {
+ // protocol
+ CreateProtoServiceFunction(PROTO, PS_GETCAPS, GetCaps);
+ CreateProtoServiceFunction(PROTO, PS_GETNAME, GetName);
+ CreateProtoServiceFunction(PROTO, PS_SETSTATUS, SetStatus);
+ CreateProtoServiceFunction(PROTO, PS_GETSTATUS, GetStatus);
+ CreateProtoServiceFunction(PROTO, PS_LOADICON,LoadIcon);
+ CreateProtoServiceFunction(PROTO, PSS_GETINFO,GetInfo);
+
+ CreateProtoServiceFunction(PROTO, PS_BASICSEARCH,BasicSearch);
+ CreateProtoServiceFunction(PROTO, PS_ADDTOLIST,AddToList);
+
+ CreateProtoServiceFunction(PROTO, PSR_MESSAGE, RecvMessage);
+
+ CreateProtoServiceFunction(PROTO, PSS_MESSAGE, STSendMessage);
+ CreateProtoServiceFunction(PROTO, PSS_MESSAGE"W", STSendMessageW);
+
+ CreateProtoServiceFunction(PROTO, PS_SETAWAYMSG,SetAwayMessage);
+ CreateProtoServiceFunction(PROTO, PSS_GETAWAYMSG,GetAwayMessage);
+ CreateProtoServiceFunction(PROTO, PSR_AWAYMSG,RecvAwayMessage);
+
+ CreateProtoServiceFunction(PROTO, PSS_USERISTYPING, SendTyping);
+
+ CreateProtoServiceFunction(PROTO, PSR_FILE, RecvFile);
+ CreateProtoServiceFunction(PROTO, PSS_FILEALLOW, AllowFile);
+ CreateProtoServiceFunction(PROTO, PSS_FILEDENY, DenyFile);
+ CreateProtoServiceFunction(PROTO, PSS_FILE, SendFiles);
+
+ CreateProtoServiceFunction(PROTO, PSS_FILECANCEL, CancelFile);
+
+ CreateProtoServiceFunction(PROTO, PS_CREATEADVSEARCHUI, CreateSearchDialog);
+ CreateProtoServiceFunction(PROTO, PS_SEARCHBYADVANCED, SearchFromDialog);
+}
+
+void DestroyProtoServiceFunction(char *szModule, char *szService) {
+ char szFullServiceName[512];
+ strcpy(szFullServiceName, szModule);
+ strcat(szFullServiceName, szService);
+ DestroyServiceFunction(szFullServiceName);
+}
+
+void DestroyPluginServices() {
+ DestroyProtoServiceFunction(PROTO,PSS_USERISTYPING);
+
+ DestroyProtoServiceFunction(PROTO, PSR_FILE);
+ DestroyProtoServiceFunction(PROTO, PSS_FILEALLOW);
+ DestroyProtoServiceFunction(PROTO, PSS_FILEDENY);
+ DestroyProtoServiceFunction(PROTO, PSS_FILE);
+
+ DestroyProtoServiceFunction(PROTO, PSS_FILECANCEL);
+
+ DestroyProtoServiceFunction(PROTO, PS_BASICSEARCH);
+ DestroyProtoServiceFunction(PROTO, PS_ADDTOLIST);
+
+ DestroyProtoServiceFunction(PROTO, PSR_MESSAGE);
+
+ DestroyProtoServiceFunction(PROTO, PSS_MESSAGE);
+ DestroyProtoServiceFunction(PROTO, PSS_MESSAGE"W");
+
+ DestroyProtoServiceFunction(PROTO, PS_SETAWAYMSG);
+ DestroyProtoServiceFunction(PROTO, PSS_GETAWAYMSG);
+ DestroyProtoServiceFunction(PROTO, PSR_AWAYMSG);
+
+ DestroyProtoServiceFunction(PROTO, PSS_USERISTYPING);
+
+ DestroyProtoServiceFunction(PROTO, PS_GETCAPS);
+ DestroyProtoServiceFunction(PROTO, PS_GETNAME);
+ DestroyProtoServiceFunction(PROTO, PS_SETSTATUS);
+ DestroyProtoServiceFunction(PROTO, PS_GETSTATUS);
+ DestroyProtoServiceFunction(PROTO, PS_LOADICON);
+ DestroyProtoServiceFunction(PROTO, PSS_GETINFO);
+}
+
+int WindowEvent(WPARAM wParam, LPARAM lParam) {
+ MessageWindowEventData *mwed = (MessageWindowEventData *)lParam;
+
+ if(DBGetContactSettingByte(mwed->hContact, PROTO, "ChatRoom", 0))
+ return 0;
+
+ if(mwed && (mwed->uType == MSG_WINDOW_EVT_CLOSING || mwed->uType == MSG_WINDOW_EVT_CLOSE))
+ CloseIm(mwed->hContact);
+
+ return 0;
+}
+
+int IdleChanged(WPARAM wParam, LPARAM lParam) {
+ if(!(lParam & IDF_PRIVACY)) {
+ is_idle = lParam & IDF_ISIDLE ? true : false;
+ SetIdle(is_idle);
+ }
+
+ return 0;
+}
+
+int OnModulesLoaded(WPARAM wParam, LPARAM lParam) {
+
+ // register with chat module
+
+ GCREGISTER gcr = {0};
+ gcr.cbSize = sizeof(gcr);
+ gcr.pszModule = PROTO;
+ gcr.pszModuleDispName = Translate(PROTO);
+ gcr.dwFlags = GC_TCHAR;
+ int ret = CallService(MS_GC_REGISTER, 0, (LPARAM)(GCREGISTER *) &gcr);
+ if(ret == GC_REGISTER_NOUNICODE) {
+ gcr.dwFlags = 0;
+ ret = CallService(MS_GC_REGISTER, 0, (LPARAM)(GCREGISTER *) &gcr);
+ if(ret)
+ MessageBox(0, TranslateT("You must install chat.dll to enable group chat."), TranslateT("Sametime Error"), MB_OK);
+ } else {
+ if(ret)
+ MessageBox(0, TranslateT("You must install chat.dll to enable group chat."), TranslateT("Sametime Error"), MB_OK);
+ else {
+ //MessageBox(0, _T("Unicode chat"), _T("msg"), MB_OK);
+ unicode_chat = true;
+ }
+ }
+ //int ret = CallService(MS_GC_REGISTER, 0, (LPARAM)(GCREGISTER *) &gcr);
+ //if(ret) MessageBox(0, TranslateT("You must install chat.dll to enable group chat."), TranslateT("Sametime Error"), MB_OK);
+
+ if(ServiceExists(MS_UPDATE_REGISTER)) {
+ // register with updater
+ Update update = {0};
+ char szVersion[16];
+
+ update.cbSize = sizeof(Update);
+
+ update.szComponentName = pluginInfo.shortName;
+ update.pbVersion = (BYTE *)CreateVersionString(pluginInfo.version, szVersion);
+ update.cpbVersion = strlen((char *)update.pbVersion);
+
+ // these are the three lines that matter - the archive, the page containing the version string, and the text (or data)
+ // before the version that we use to locate it on the page
+ // (note that if the update URL and the version URL point to standard file listing entries, the backend xml
+ // data will be used to check for updates rather than the actual web page - this is not true for beta urls)
+ update.szBetaUpdateURL = "http://sje.twosx.net/sametime.zip";
+ update.szBetaVersionURL = "http://sje.twosx.net/ver_sametime.html";
+ update.pbBetaVersionPrefix = (BYTE *)"Sametime Protocol version ";
+
+ update.cpbBetaVersionPrefix = strlen((char *)update.pbBetaVersionPrefix);
+
+ CallService(MS_UPDATE_REGISTER, 0, (WPARAM)&update);
+ }
+
+ NETLIBUSER nl_user = {0};
+ nl_user.cbSize = sizeof(nl_user);
+ nl_user.szSettingsModule = PROTO;
+ //nl_user.flags = NUF_OUTGOING | (http_proxying_enabled ? NUF_HTTPCONNS : 0);
+ nl_user.flags = NUF_OUTGOING | NUF_HTTPCONNS;
+ nl_user.szDescriptiveName = PROTO;
+
+ hNetlibUser = (HANDLE)CallService(MS_NETLIB_REGISTERUSER, 0, (LPARAM)&nl_user);
+
+ hWindowEventHook = HookEvent(ME_MSG_WINDOWEVENT, WindowEvent);
+
+ hIdleEventHook = HookEvent(ME_IDLE_CHANGED, IdleChanged);
+
+ // funny logic :) ... try to avoid message boxes
+ // if want baloons but no balloons, try popups
+ // if want popups but no popups, try baloons
+ // if, after that, you want balloons but no balloons, revert to message boxes
+ if(options.err_method == ED_BAL && !ServiceExists(MS_CLIST_SYSTRAY_NOTIFY)) options.err_method = ED_POP;
+ if(options.err_method == ED_POP && !ServiceExists(MS_POPUP_SHOWMESSAGE)) options.err_method = ED_BAL;
+ if(options.err_method == ED_BAL && !ServiceExists(MS_CLIST_SYSTRAY_NOTIFY)) options.err_method = ED_MB;
+
+ InitSessionMenu();
+ InitConferenceMenu();
+
+ return 0;
+}
+
+int OnPreShutdown(WPARAM wParam, LPARAM lParam) {
+ if(current_status != ID_STATUS_OFFLINE) LogOut();
+
+ UnhookEvent(hIdleEventHook);
+ UnhookEvent(hWindowEventHook);
+
+ return 0;
+}
+
+int OnShutdown(WPARAM wParam, LPARAM lParam) {
+
+ //DeinitUtils();
+ DestroyPluginServices();
+
+ DeinitConferenceMenu();
+ DeinitSessionMenu();
+
+ Netlib_CloseHandle(hNetlibUser);
+
+ return 0;
+}
+
+void SetAllOffline() {
+ char *proto;
+ HANDLE hContact = ( HANDLE )CallService( MS_DB_CONTACT_FINDFIRST, 0, 0 ), hContactNext;
+ while ( hContact != NULL )
+ {
+ proto = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM )hContact,0 );
+ if ( proto && !strcmp( PROTO, proto)) {
+ if(DBGetContactSettingByte(hContact, PROTO, "ChatRoom", 0)) {
+ // clean up after chat plugin
+ hContactNext = ( HANDLE )CallService( MS_DB_CONTACT_FINDNEXT,( WPARAM )hContact, 0 );
+ CallService(MS_DB_CONTACT_DELETE, (WPARAM)hContact, 0);
+ hContact = hContactNext;
+ continue;
+ } else {
+ DBWriteContactSettingWord( hContact, PROTO, "Status", ID_STATUS_OFFLINE);
+ DBWriteContactSettingDword(hContact, PROTO, "IdleTS", 0);
+ }
+ }
+
+ hContact = ( HANDLE )CallService( MS_DB_CONTACT_FINDNEXT,( WPARAM )hContact, 0 );
+ }
+}
+
+void DeleteAllContacts() {
+ char *proto;
+ DBVARIANT dbv;
+ HANDLE hContact = ( HANDLE )CallService( MS_DB_CONTACT_FINDFIRST, 0, 0 ), hContactNext;
+ while ( hContact != NULL )
+ {
+ hContactNext = ( HANDLE )CallService( MS_DB_CONTACT_FINDNEXT,( WPARAM )hContact, 0 );
+
+ if(!DBGetContactSetting(hContact, "Protocol", "p", &dbv)) {
+ //proto = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM )hContact,0 );
+ proto = dbv.pszVal;
+ if ( proto && !strcmp( PROTO, proto)) {
+ CallService(MS_DB_CONTACT_DELETE, (WPARAM)hContact, 0);
+ }
+ DBFreeVariant(&dbv);
+ }
+
+ hContact = hContactNext;
+ }
+}
+
+bool IsUnicodeOS()
+{
+ OSVERSIONINFOW os;
+ memset(&os, 0, sizeof(OSVERSIONINFOW));
+ os.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
+ return (GetVersionExW(&os) != 0);
+}
+
+extern "C" SAMETIME_API int Load(PLUGINLINK *link)
+{
+
+ pluginLink=link;
+
+ if(!IsUnicodeOS()) {
+ MessageBox(0, TranslateT("This plugin requires a Unicode capable Windows installation."), TranslateT("Sametime Error"), MB_OK | MB_ICONERROR);
+ return 1;
+ }
+
+ if ( !ServiceExists( MS_DB_CONTACT_GETSETTING_STR )) {
+ MessageBox( 0, TranslateT( "This plugin requires db3x plugin version 0.5.1.0 or later." ), TranslateT("Sametime Error"), MB_OK );
+ return 1;
+ }
+
+ DuplicateHandle( GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &mainThread, THREAD_SET_CONTEXT, FALSE, 0 );
+ mainThreadId = GetCurrentThreadId();
+
+ previous_status = current_status = ID_STATUS_OFFLINE;
+
+ if(ServiceExists(MS_LANGPACK_GETCODEPAGE))
+ code_page = CallService(MS_LANGPACK_GETCODEPAGE, 0, 0);
+
+ mir_getMMI(&mmi);
+ mir_getUTFI(&utfi);
+
+
+ if(ServiceExists(MS_DB_SETSETTINGRESIDENT)) { // 0.6+
+ char buff[256];
+ mir_snprintf(buff, 256, "%s/%s", PROTO, "Status");
+ CallService(MS_DB_SETSETTINGRESIDENT, TRUE, (LPARAM)buff);
+ mir_snprintf(buff, 256, "%s/%s", PROTO, "IdleTS");
+ CallService(MS_DB_SETSETTINGRESIDENT, TRUE, (LPARAM)buff);
+ }
+
+ InitAwayMsg();
+ InitCritSection();
+
+ // Get module name from DLL file name
+ {
+ char* str1;
+ char str2[MAX_PATH];
+
+ GetModuleFileNameA(hInst, str2, MAX_PATH);
+ str1 = strrchr(str2, '\\');
+ if (str1 != NULL && strlen(str1+1) > 4) {
+ strncpy(PROTO, str1+1, strlen(str1+1)-4);
+ PROTO[strlen(str1+1)-3] = 0;
+ }
+ CharUpperA(PROTO);
+
+ strcpy(PROTO_GROUPS, PROTO);
+ strcat(PROTO_GROUPS, "_GROUPS");
+ }
+
+ PROTOCOLDESCRIPTOR pd = {0};
+ pd.cbSize = sizeof(pd);
+ pd.szName = PROTO;
+ pd.type = PROTOTYPE_PROTOCOL;
+ CallService(MS_PROTO_REGISTERMODULE,0,(LPARAM)&pd);
+
+ InitUtils();
+
+ CreatePluginServices();
+
+ LoadOptions();
+
+ //DeleteAllContacts(); //!!!
+
+ SetAllOffline();
+
+ HookEvent(ME_SYSTEM_MODULESLOADED, OnModulesLoaded);
+ HookEvent(ME_OPT_INITIALISE, OptInit );
+ HookEvent(ME_SYSTEM_PRESHUTDOWN, OnPreShutdown);
+ HookEvent(ME_SYSTEM_SHUTDOWN, OnShutdown);
+
+ return 0;
+}
+
+extern "C" SAMETIME_API int Unload(void)
+{
+ DeinitUtils();
+
+ DeinitAwayMsg();
+ DeinitCritSection();
+
+ return 0;
+}
+
diff --git a/plugins/!NotAdopted/sametime/sametime.h b/plugins/!NotAdopted/sametime/sametime.h
new file mode 100644
index 0000000000..14438b2c4f
--- /dev/null
+++ b/plugins/!NotAdopted/sametime/sametime.h
@@ -0,0 +1,14 @@
+
+// The following ifdef block is the standard way of creating macros which make exporting
+// from a DLL simpler. All files within this DLL are compiled with the SAMETIME_EXPORTS
+// symbol defined on the command line. this symbol should not be defined on any project
+// that uses this DLL. This way any other project whose source files include this file see
+// SAMETIME_API functions as being imported from a DLL, wheras this DLL sees symbols
+// defined with this macro as being exported.
+#ifdef SAMETIME_EXPORTS
+#define SAMETIME_API __declspec(dllexport)
+#else
+#define SAMETIME_API __declspec(dllimport)
+#endif
+
+
diff --git a/plugins/!NotAdopted/sametime/sametime.sln b/plugins/!NotAdopted/sametime/sametime.sln
new file mode 100644
index 0000000000..40d9d775e1
--- /dev/null
+++ b/plugins/!NotAdopted/sametime/sametime.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sametime", "sametime.vcproj", "{BE22A21F-73B7-453F-86A0-B867F0056490}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {BE22A21F-73B7-453F-86A0-B867F0056490}.Debug|Win32.ActiveCfg = Debug|Win32
+ {BE22A21F-73B7-453F-86A0-B867F0056490}.Debug|Win32.Build.0 = Debug|Win32
+ {BE22A21F-73B7-453F-86A0-B867F0056490}.Release|Win32.ActiveCfg = Release|Win32
+ {BE22A21F-73B7-453F-86A0-B867F0056490}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/plugins/!NotAdopted/sametime/sametime.vcproj b/plugins/!NotAdopted/sametime/sametime.vcproj
new file mode 100644
index 0000000000..164d37a650
--- /dev/null
+++ b/plugins/!NotAdopted/sametime/sametime.vcproj
@@ -0,0 +1,575 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="sametime"
+ ProjectGUID="{BE22A21F-73B7-453F-86A0-B867F0056490}"
+ RootNamespace="sametime"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory=".\Release"
+ IntermediateDirectory=".\Release"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ Description="create meanwhile import library"
+ CommandLine="lib /name:meanwhile /def:../meanwhile/Release/meanwhile.def"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="NDEBUG"
+ MkTypLibCompatible="true"
+ SuppressStartupBanner="true"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Release/sametime.tlb"
+ HeaderFileName=""
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="&quot;..\meanwhile\meanwhile-1.0.2\src&quot;;..\..\include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;SAMETIME_EXPORTS;UNICODE;_UNICODE"
+ StringPooling="true"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="true"
+ PrecompiledHeaderFile=".\Release/sametime.pch"
+ AssemblerListingLocation=".\Release/"
+ ObjectFile=".\Release/"
+ ProgramDataBaseFileName=".\Release/"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ DisableSpecificWarnings="4996"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="3081"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ IgnoreImportLibrary="true"
+ AdditionalDependencies="../meanwhile/glib/lib/glib-2.0.lib meanwhile.lib"
+ OutputFile=".\Release/sametime.dll"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile=".\Release/sametime.pdb"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ ImportLibrary=".\Release/sametime.lib"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ SuppressStartupBanner="true"
+ OutputFile=".\Release/sametime.bsc"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory=".\Debug"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ Description="create meanwhile import library"
+ CommandLine="lib /name:meanwhile /def:../meanwhile/Debug/meanwhile.def"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="_DEBUG"
+ MkTypLibCompatible="true"
+ SuppressStartupBanner="true"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Debug/sametime.tlb"
+ HeaderFileName=""
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="&quot;..\meanwhile\meanwhile-1.0.2\src&quot;;..\..\include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;SAMETIME_EXPORTS;UNICODE;_UNICODE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ PrecompiledHeaderFile=".\Debug/sametime.pch"
+ AssemblerListingLocation=".\Debug/"
+ ObjectFile=".\Debug/"
+ ProgramDataBaseFileName=".\Debug/"
+ BrowseInformation="1"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ DebugInformationFormat="4"
+ DisableSpecificWarnings="4996"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="3081"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ IgnoreImportLibrary="true"
+ AdditionalDependencies="../meanwhile/glib/lib/glib-2.0.lib meanwhile.lib"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ ModuleDefinitionFile="../meanwhile/Debug/meanwhile.def"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile=".\Debug/sametime.pdb"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ ImportLibrary=".\Debug/sametime.lib"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ SuppressStartupBanner="true"
+ OutputFile=".\Debug/sametime.bsc"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+ >
+ <File
+ RelativePath="clist_util.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="common.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="conference.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="files.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="messaging.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="options.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="places.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="sametime.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="session.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="session_announce_win.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="userlist.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="utils.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl"
+ >
+ <File
+ RelativePath="clist_util.h"
+ >
+ </File>
+ <File
+ RelativePath="common.h"
+ >
+ </File>
+ <File
+ RelativePath="conference.h"
+ >
+ </File>
+ <File
+ RelativePath="files.h"
+ >
+ </File>
+ <File
+ RelativePath="messaging.h"
+ >
+ </File>
+ <File
+ RelativePath="options.h"
+ >
+ </File>
+ <File
+ RelativePath="places.h"
+ >
+ </File>
+ <File
+ RelativePath="resource.h"
+ >
+ </File>
+ <File
+ RelativePath="session.h"
+ >
+ </File>
+ <File
+ RelativePath="session_announce_win.h"
+ >
+ </File>
+ <File
+ RelativePath="userlist.h"
+ >
+ </File>
+ <File
+ RelativePath="utils.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+ >
+ <File
+ RelativePath="announce.ico"
+ >
+ </File>
+ <File
+ RelativePath="ico00001.ico"
+ >
+ </File>
+ <File
+ RelativePath="icon1.ico"
+ >
+ </File>
+ <File
+ RelativePath="invite.ico"
+ >
+ </File>
+ <File
+ RelativePath="online.ico"
+ >
+ </File>
+ <File
+ RelativePath="part.ico"
+ >
+ </File>
+ <File
+ RelativePath="resource.rc"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <File
+ RelativePath="ReadMe.txt"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/plugins/!NotAdopted/sametime/session.cpp b/plugins/!NotAdopted/sametime/session.cpp
new file mode 100644
index 0000000000..33cc2f7468
--- /dev/null
+++ b/plugins/!NotAdopted/sametime/session.cpp
@@ -0,0 +1,566 @@
+#include "session.h"
+#include <glib.h>
+
+HANDLE sessionThread = 0;
+DWORD session_thread_id = 0;
+
+CRITICAL_SECTION session_cs;
+
+HANDLE server_connection = 0;
+mwSession *session = 0;
+
+HANDLE hSessionSyncEvent = 0;
+
+int idle_timerid = 0;
+bool idle_status = false;
+int login_status;
+bool first_online = true; // set our status after the first online status comes from the server
+
+
+#define MS_SAMETIME_MENUANNOUNCESESSION "/SessionAnnounce"
+HICON hIconProto, hIconAnnounce;
+HANDLE hSessionAnnounceMenuItem;
+
+struct {
+ char *szOnline;
+ char *szAway;
+ char *szDND;
+} AwayMessages;
+
+void CALLBACK sttMainThreadStatusCallback( ULONG dwParam ) {
+ if(current_status != dwParam) {
+ previous_status = current_status;
+ current_status = dwParam;
+ ProtoBroadcastAck(PROTO,NULL,ACKTYPE_STATUS,ACKRESULT_SUCCESS, (HANDLE)previous_status, current_status);
+ }
+}
+
+void __cdecl SessionClear(struct mwSession *) {
+}
+
+int __cdecl SessionWrite(mwSession *, const unsigned char *buf, gsize len) {
+ if(!server_connection) return 1;
+ if(Netlib_Send(server_connection, (const char *)buf, len, 0) == SOCKET_ERROR)
+ return 1;
+ return 0;
+}
+
+void __cdecl SessionClose(mwSession *) {
+ Netlib_CloseHandle(server_connection);
+ server_connection = 0;
+}
+
+void SessionStarted() {
+ //PUShowMessage("Session started", SM_NOTIFY);
+ UserListCreate();
+ if(options.get_server_contacts) UserListAddStored();
+}
+
+void SessionStopping() {
+ UserListDestroy();
+}
+
+void InitMeanwhileServices() {
+ if(options.encrypt_session) {
+ mwSession_addCipher(session, mwCipher_new_RC2_128(session));
+ mwSession_addCipher(session, mwCipher_new_RC2_40(session));
+ }
+
+ InitUserList(session);
+ InitMessaging(session);
+ InitFiles(session);
+ InitConference(session);
+}
+
+void DeinitMeanwhileServices() {
+ DeinitConference(session);
+ DeinitFiles(session);
+ DeinitMessaging(session);
+ DeinitUserList(session);
+
+ mwCipher_free(mwSession_getCipher(session, mwCipher_RC2_40));
+ mwCipher_free(mwSession_getCipher(session, mwCipher_RC2_128));
+}
+
+void __cdecl SessionStateChange(mwSession *s, mwSessionState state, gpointer info) {
+
+ switch(state) {
+ case mwSession_STARTING:
+ break;
+ case mwSession_HANDSHAKE:
+ break;
+ case mwSession_HANDSHAKE_ACK:
+ break;
+ case mwSession_STARTED:
+ SessionStarted();
+ break;
+ case mwSession_STOPPING:
+ if((int)info) {// & ERR_FAILURE) {
+ char *msg = mwError((int)info);
+ //MessageBoxA(0, Translate(msg), Translate("Sametime Error"), MB_OK | MB_ICONWARNING);
+ TCHAR *ts = u2t(msg);
+ ShowError(TranslateTS(ts));
+ g_free(msg);
+ free(ts);
+ }
+
+ SessionStopping();
+ break;
+ case mwSession_STOPPED:
+ break;
+
+ case mwSession_LOGIN_REDIR:
+ //options.server_name = str((char *)info);
+ strcpy(options.server_name, (char *)info);
+ LogOut();
+ LogIn(login_status, hNetlibUser);
+ break;
+ case mwSession_LOGIN_CONT:
+ break;
+
+ case mwSession_LOGIN:
+ break;
+ case mwSession_LOGIN_ACK:
+ break;
+
+ case mwSession_UNKNOWN:
+ break;
+ }
+}
+
+void __cdecl SessionAdmin(struct mwSession *, const char *text) {
+ TCHAR *tt = u2t(text);
+ MessageBox(0, tt, TranslateT("Sametime Administrator Message"), MB_OK);
+ free(tt);
+}
+
+void __cdecl SessionAnnounce(struct mwSession *, struct mwLoginInfo *from, gboolean may_reply, const char *text) {
+ TCHAR buff[256], *tt1, *tt2;
+#ifdef _UNICODE
+ _snwprintf(buff, 256, TranslateT("Session Announcement - from '%s'"), tt1 = u2t(from->user_name));
+#else
+ _snprintf(buff, 256, TranslateT("Session Announcement - from '%s'"), tt1 = u2t(from->user_name));
+#endif
+ MessageBox(0, TranslateTS(tt2 = u2t(text)), buff, MB_OK);
+ free(tt1); free(tt2);
+}
+
+void __cdecl SessionSetPrivacyInfo(struct mwSession *) {
+}
+
+void __cdecl SessionSetUserStatus(struct mwSession *session) {
+ int new_status;
+ struct mwUserStatus us;
+ mwUserStatus_clone(&us, mwSession_getUserStatus(session));
+
+ switch(us.status) {
+ case mwStatus_ACTIVE:
+ new_status = ID_STATUS_ONLINE;
+ break;
+ case mwStatus_AWAY:
+ new_status = ID_STATUS_AWAY;
+ if(idle_status) {
+ // ignore setting to away by idle module, after we've set ourselves idle
+ // most standard clients represent idle and away the same way anyway,
+ // but this allows miranda users to make use of the idle timestamp
+
+ // but show our status in clist as away
+ QueueUserAPC(sttMainThreadStatusCallback, mainThread, new_status);
+
+ mwUserStatus_clear(&us);
+ return;
+ }
+ break;
+ case mwStatus_BUSY:
+ new_status = ID_STATUS_DND;
+ break;
+ case mwStatus_IDLE:
+ new_status = ID_STATUS_AWAY;
+ if(!first_online && !options.idle_as_away) { // show our status in clist as away if idle when going online or treating idle as away
+ mwUserStatus_clear(&us);
+ return;
+ }
+ break;
+ case 8: // new 'in a meeting' status, not handled by meanwhile lib
+ new_status = ID_STATUS_OCCUPIED;
+ break;
+ default:
+ {
+ char buff[512];
+ sprintf(buff, "Unknown user status: %d", us.status);
+ PUShowMessage(buff, SM_WARNING);
+ }
+ mwUserStatus_clear(&us);
+ // just go online...to prevent us getting stuck 'connecting'
+ new_status = ID_STATUS_ONLINE;
+ break;
+ }
+
+ if(first_online) {
+ first_online = false;
+ //PUShowMessage("Setting login status", SM_NOTIFY);
+ SetSessionStatus(login_status);
+ } else
+ QueueUserAPC(sttMainThreadStatusCallback, mainThread, new_status);
+
+ mwUserStatus_clear(&us);
+}
+
+void UpdateSelfStatus() {
+ EnterCriticalSection(&session_cs);
+ if(session) SessionSetUserStatus(session);
+ LeaveCriticalSection(&session_cs);
+}
+
+int SetSessionStatus(int status) {
+ struct mwUserStatus us;
+
+ if(idle_timerid) KillTimer(0, idle_timerid);
+
+ us.time = (DWORD)time(0);
+ //us.time = 0;
+
+ switch(status) {
+ case ID_STATUS_FREECHAT:
+ case ID_STATUS_ONLINE:
+ us.desc = AwayMessages.szOnline; us.status = mwStatus_ACTIVE;
+ break;
+ case ID_STATUS_NA:
+ case ID_STATUS_INVISIBLE:
+ case ID_STATUS_ONTHEPHONE:
+ case ID_STATUS_OUTTOLUNCH:
+ case ID_STATUS_AWAY:
+ us.desc = AwayMessages.szAway; us.status = mwStatus_AWAY;
+ break;
+ case ID_STATUS_OCCUPIED:
+ case ID_STATUS_DND:
+ us.desc = AwayMessages.szDND; us.status = mwStatus_BUSY;
+ break;
+ default:
+ // act as online for unsupported status
+ us.desc = AwayMessages.szOnline; us.status = mwStatus_ACTIVE; break;
+ }
+
+ mwSession_setUserStatus(session, &us);
+
+ return 0;
+}
+
+VOID CALLBACK IdleTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) {
+ KillTimer(0, idle_timerid);
+ idle_timerid = 0;
+
+ if(idle_status) {
+ struct mwUserStatus us;
+
+ us.time = (DWORD)time(0);
+ us.status = mwStatus_IDLE;
+ us.desc = 0;
+ mwSession_setUserStatus(session, &us);
+ } else
+ SetSessionStatus(current_status);
+}
+
+int SetIdle(bool idle) {
+
+ // set a timer, to wait for any autoaway module which might set our status
+ if(idle && !idle_status) {
+ idle_status = true;
+ if(!idle_timerid)
+ idle_timerid = SetTimer(0, 0, 200, IdleTimerProc);
+ } else if(idle_status) {
+ idle_status = false;
+ if(!idle_timerid)
+ idle_timerid = SetTimer(0, 0, 200, IdleTimerProc);
+ }
+
+ return 0;
+}
+
+void SetSessionAwayMessage(int status, char *msg) {
+ if(status == ID_STATUS_ONLINE) {
+ if(AwayMessages.szOnline) free(AwayMessages.szOnline);
+ if(msg) {
+ AwayMessages.szOnline = _strdup(msg);
+ } else AwayMessages.szOnline = 0;
+ } else if(status == ID_STATUS_AWAY) {
+ if(AwayMessages.szAway) free(AwayMessages.szAway);
+ if(msg) {
+ AwayMessages.szAway = _strdup(msg);
+ } else AwayMessages.szAway = 0;
+ } else if(status == ID_STATUS_DND) {
+ if(AwayMessages.szDND) free(AwayMessages.szDND);
+ if(msg) {
+ AwayMessages.szDND = _strdup(msg);
+ } else AwayMessages.szDND = 0;
+ } else
+ return; // unsupported status
+
+ SetSessionStatus(status); // update current away message
+}
+
+void WINAPI NullAPC (DWORD dwData) {
+ // This function intentionally left blank
+}
+
+void WakeThread(HANDLE hThread) {
+ QueueUserAPC(NullAPC, hThread, 0);
+}
+
+unsigned long __stdcall KeepAliveThread(LPVOID param) {
+ CallService(MS_SYSTEM_THREAD_PUSH, 0, 0);
+ //PUShowMessage("KA Thread start", SM_NOTIFY);
+
+ while(1) {// && !mwSession_isStopped(session)) {
+ SleepEx(30000, TRUE);
+
+ EnterCriticalSection(&session_cs);
+ if(!session) {
+ LeaveCriticalSection(&session_cs);
+ break;
+ }
+ if(mwSession_isStarted(session) && !Miranda_Terminated() && session) {
+ mwSession_sendKeepalive(session);
+ //PUShowMessage("KA", SM_NOTIFY);
+ }
+ LeaveCriticalSection(&session_cs);
+ }
+
+ //PUShowMessage("KA Thread end", SM_NOTIFY);
+ CallService(MS_SYSTEM_THREAD_POP, 0, 0);
+ return 0;
+}
+
+bool continue_connect;
+
+int waitcallback(unsigned int *timeout) {
+ return continue_connect ? 1 : 0;
+}
+
+unsigned long __stdcall SessionThread(LPVOID param) {
+ HANDLE hNetlibUser = (HANDLE)param;
+
+ CallService(MS_SYSTEM_THREAD_PUSH, 0, 0);
+
+ continue_connect = true;
+
+ //setup
+ NETLIBOPENCONNECTION conn_data = {0};
+ conn_data.cbSize = sizeof(NETLIBOPENCONNECTION);
+ conn_data.flags = NLOCF_V2;
+ conn_data.szHost = options.server_name;
+ conn_data.wPort = options.port;
+ conn_data.timeout = 20;
+ conn_data.waitcallback = waitcallback;
+
+ QueueUserAPC(sttMainThreadStatusCallback, mainThread, ID_STATUS_CONNECTING);
+
+ server_connection = (HANDLE)CallService(MS_NETLIB_OPENCONNECTION, (WPARAM)hNetlibUser, (LPARAM)&conn_data);
+
+ if(!server_connection) {
+ QueueUserAPC(sttMainThreadStatusCallback, mainThread, ID_STATUS_OFFLINE);
+ if(continue_connect) { // real timeout - not user cancelled
+ //MessageBox(0, "No server connection!", "Error", MB_OK);
+ ShowError(TranslateT("No server connection!"));
+ }
+ CallService(MS_SYSTEM_THREAD_POP, 0, 0);
+ return 1;
+ }
+
+ mwSessionHandler handler = {0};
+ handler.clear = SessionClear;
+ handler.io_write = SessionWrite;
+ handler.io_close = SessionClose;
+ handler.on_stateChange = SessionStateChange;
+ handler.on_admin = SessionAdmin;
+ handler.on_announce = SessionAnnounce;
+ handler.on_setPrivacyInfo = SessionSetPrivacyInfo;
+ handler.on_setUserStatus = SessionSetUserStatus;
+
+ EnterCriticalSection(&session_cs);
+ session = mwSession_new(&handler);
+
+ InitMeanwhileServices();
+
+ mwSession_setProperty(session, mwSession_AUTH_USER_ID, options.id, NULL);
+ mwSession_setProperty(session, mwSession_AUTH_PASSWORD, options.pword, NULL);
+ mwSession_setProperty(session, mwSession_CLIENT_TYPE_ID, (void *)options.client_id, NULL);
+
+ if(options.use_old_default_client_ver) {
+ mwSession_setProperty(session, mwSession_CLIENT_VER_MAJOR, GUINT_TO_POINTER(DBGetContactSettingWord(0, PROTO, "ClientVersionMajor", MW_PROTOCOL_VERSION_MAJOR)), 0);
+ mwSession_setProperty(session, mwSession_CLIENT_VER_MINOR, GUINT_TO_POINTER(DBGetContactSettingWord(0, PROTO, "ClientVersionMinor", MW_PROTOCOL_VERSION_MINOR)), 0);
+ } else {
+ mwSession_setProperty(session, mwSession_CLIENT_VER_MAJOR, GUINT_TO_POINTER(DBGetContactSettingWord(0, PROTO, "ClientVersionMajor", 0x001e)), 0);
+ mwSession_setProperty(session, mwSession_CLIENT_VER_MINOR, GUINT_TO_POINTER(DBGetContactSettingWord(0, PROTO, "ClientVersionMinor", 0x196f)), 0);
+ }
+
+ mwSession_start(session);
+ LeaveCriticalSection(&session_cs);
+
+ DWORD tid;
+ HANDLE hKAThread = CreateThread(0, 0, KeepAliveThread, 0, 0, &tid);
+
+ //SetEvent(hSessionSyncEvent);
+
+ unsigned char *recv_buffer = new unsigned char[1024 * 32];
+ int bytes;
+ //while(session && server_connection && mwSession_getState(session) != mwSession_STOPPED) {
+ while(server_connection) {// && session) {// && !mwSession_isStopped(session)) { // break on error
+ bytes = Netlib_Recv(server_connection, (char *)recv_buffer, 1024 * 32, 0);
+
+ if(bytes == 0) {
+ break;
+ } else if(bytes == SOCKET_ERROR) {
+ // this is normal - e.g. socket closed due to log off, during blocking read above
+ break;
+ } else {
+ EnterCriticalSection(&session_cs);
+ mwSession_recv(session, recv_buffer, bytes);
+ LeaveCriticalSection(&session_cs);
+ }
+ }
+ delete recv_buffer;
+
+ EnterCriticalSection(&session_cs);
+ DeinitMeanwhileServices();
+
+ mwSession *old_session = session;
+ session = 0; // kills keepalive thread, if awake
+
+ mwSession_free(old_session);
+ LeaveCriticalSection(&session_cs);
+
+ // wake alive thread
+
+ WakeThread(hKAThread);
+ WaitForSingleObject(hKAThread, INFINITE);
+ CloseHandle(hKAThread);
+
+ QueueUserAPC(sttMainThreadStatusCallback, mainThread, ID_STATUS_OFFLINE);
+ SetAllOffline();
+
+ first_online = true;
+
+ CallService(MS_SYSTEM_THREAD_POP, 0, 0);
+ return 0;
+}
+
+WORD GetClientVersion() {
+ if(!session) return 0;
+
+ WORD retval = 0;
+
+ retval = (int)mwSession_getProperty(session, mwSession_CLIENT_VER_MAJOR) << 8;
+ retval |= (int)mwSession_getProperty(session, mwSession_CLIENT_VER_MINOR);
+
+ return retval;
+}
+
+WORD GetServerVersion() {
+ if(!session) return 0;
+
+ WORD retval = 0;
+
+ retval = (int)mwSession_getProperty(session, mwSession_SERVER_VER_MAJOR) << 8;
+ retval |= (int)mwSession_getProperty(session, mwSession_SERVER_VER_MINOR);
+
+ return retval;
+}
+
+int LogIn(int ls, HANDLE hNetlibUser) {
+ EnterCriticalSection(&session_cs);
+ if(session) {
+ LeaveCriticalSection(&session_cs);
+ return 0;
+ }
+ LeaveCriticalSection(&session_cs);
+
+ login_status = ls;
+
+ //hSessionSyncEvent = CreateEvent(NULL, true, false, NULL);
+ sessionThread = CreateThread(0, 0, SessionThread, (void *)hNetlibUser, 0, &session_thread_id);
+
+
+ // we can't wait for the thread - critical section (csHooks) from core is locked during call to this function,
+ // and hooks are created in the individual init sections...
+
+ CloseHandle(sessionThread);
+ //WaitForSingleObject(hSessionSyncEvent, INFINITE);
+ //CloseHandle(hSessionSyncEvent);
+ //hSessionSyncEvent = 0;
+
+ return 0;
+}
+
+int LogOut() {
+ continue_connect = false;
+
+ EnterCriticalSection(&session_cs);
+ if(session && server_connection && current_status != ID_STATUS_OFFLINE && !mwSession_isStopped(session) && !mwSession_isStopping(session))
+ mwSession_stop(session, 0);
+ LeaveCriticalSection(&session_cs);
+
+ return 0;
+}
+
+void InitAwayMsg() {
+ AwayMessages.szOnline = 0;
+ AwayMessages.szAway = 0;
+ AwayMessages.szDND = 0;
+}
+
+void DeinitAwayMsg() {
+ if(AwayMessages.szOnline) free(AwayMessages.szOnline);
+ if(AwayMessages.szAway) free(AwayMessages.szAway);
+ if(AwayMessages.szDND) free(AwayMessages.szDND);
+}
+
+void SendAnnouncement(AnnouncementData *ad) {
+ char *utfs = t2u(ad->msg);
+ if(session && ad && ad->recipients) mwSession_sendAnnounce(session, false , utfs, ad->recipients);
+ free(utfs);
+}
+
+int SessionAnnounce(WPARAM wParam, LPARAM lParam) {
+ CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_SESSIONANNOUNCE), GetDesktopWindow(), SessionAnnounceDialogProc, (LPARAM)SendAnnouncement);
+ return 0;
+}
+
+void InitSessionMenu() {
+ CreateProtoServiceFunction(PROTO, MS_SAMETIME_MENUANNOUNCESESSION, SessionAnnounce);
+
+ hIconAnnounce = LoadIcon(hInst, MAKEINTRESOURCE(IDI_ANNOUNCE));
+ hIconProto = LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON_PROTO));
+
+ char service_function[128];
+ strcpy(service_function, PROTO);
+ char *d = service_function + strlen(service_function);
+
+ CLISTMENUITEM mi = {0};
+ mi.cbSize = sizeof(mi);
+ mi.popupPosition = 500085001;
+ mi.pszPopupName = PROTO;
+ mi.position = 2000060000;
+
+ mi.pszName = Translate("Send Announcement...");
+ strcpy(d, MS_SAMETIME_MENUANNOUNCESESSION);
+ mi.pszService = service_function;
+
+ mi.hIcon = hIconProto;
+ //mi.hIcon = hIconAnnounce; // first submenu icon is used as icon for main menu popup...
+
+ hSessionAnnounceMenuItem = (HANDLE)CallService(MS_CLIST_ADDMAINMENUITEM, 0, (LPARAM)&mi);
+}
+
+void DeinitSessionMenu() {
+ DestroyIcon(hIconProto);
+ DestroyIcon(hIconAnnounce);
+}
+
+void InitCritSection() {
+ InitializeCriticalSection(&session_cs);
+
+}
+void DeinitCritSection() {
+ DeleteCriticalSection(&session_cs);
+}
diff --git a/plugins/!NotAdopted/sametime/session.h b/plugins/!NotAdopted/sametime/session.h
new file mode 100644
index 0000000000..afe1d03c2c
--- /dev/null
+++ b/plugins/!NotAdopted/sametime/session.h
@@ -0,0 +1,32 @@
+#ifndef _SESSION_INC
+#define _SESSION_INC
+
+#include "common.h"
+#include "options.h"
+#include "userlist.h"
+#include "messaging.h"
+#include "files.h"
+#include "conference.h"
+#include "utils.h"
+#include "session_announce_win.h"
+
+WORD GetClientVersion();
+WORD GetServerVersion();
+
+int SetIdle(bool idle);
+int LogIn(int status, HANDLE hNetlibUser);
+int SetSessionStatus(int status);
+void SetSessionAwayMessage(int status, char *msg);
+int LogOut();
+
+void UpdateSelfStatus();
+
+void InitAwayMsg();
+void DeinitAwayMsg();
+
+void InitSessionMenu();
+void DeinitSessionMenu();
+
+void InitCritSection();
+void DeinitCritSection();
+#endif \ No newline at end of file
diff --git a/plugins/!NotAdopted/sametime/session_announce_win.cpp b/plugins/!NotAdopted/sametime/session_announce_win.cpp
new file mode 100644
index 0000000000..144922881c
--- /dev/null
+++ b/plugins/!NotAdopted/sametime/session_announce_win.cpp
@@ -0,0 +1,136 @@
+#include "session_announce_win.h"
+
+
+INT_PTR CALLBACK SessionAnnounceDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
+ switch(uMsg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ SetWindowLong(hwndDlg, GWL_USERDATA, lParam); // save lParam
+ SendMessage(GetDlgItem(hwndDlg, IDC_LST_ANTO),LVM_SETEXTENDEDLISTVIEWSTYLE, 0,LVS_EX_FULLROWSELECT | LVS_EX_CHECKBOXES);
+
+ {
+ LVCOLUMN lvc;
+ // Initialize the LVCOLUMN structure.
+ // The mask specifies that the format, width, text, and
+ // subitem members of the structure are valid.
+ lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
+ lvc.fmt = LVCFMT_LEFT;
+
+ lvc.iSubItem = 0;
+ lvc.pszText = TranslateT("Recipients");
+ lvc.cx = 300; // width of column in pixels
+ ListView_InsertColumn(GetDlgItem(hwndDlg, IDC_LST_ANTO), 0, &lvc);
+ }
+
+ //enumerate plugins, fill in list
+ {
+ ListView_DeleteAllItems(GetDlgItem(hwndDlg, IDC_LST_ANTO));
+
+ LVITEM lvI;
+
+ // Some code to create the list-view control.
+ // Initialize LVITEM members that are common to all
+ // items.
+ lvI.mask = LVIF_TEXT | LVIF_PARAM;// | LVIF_NORECOMPUTE;// | LVIF_IMAGE;
+
+ char *proto;
+ HANDLE hContact = ( HANDLE )CallService( MS_DB_CONTACT_FINDFIRST, 0, 0 );
+ while ( hContact != NULL )
+ {
+ proto = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM )hContact,0 );
+ if ( proto && !strcmp( PROTO, proto)) {
+ if(DBGetContactSettingByte(hContact, PROTO, "ChatRoom", 0) == 0
+ && DBGetContactSettingWord(hContact, PROTO, "Status", ID_STATUS_OFFLINE) != ID_STATUS_OFFLINE)
+ {
+ lvI.iSubItem = 0;
+ lvI.lParam = (LPARAM)hContact;
+ lvI.pszText = (TCHAR *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GCDNF_TCHAR);
+ lvI.iItem = ListView_InsertItem(GetDlgItem(hwndDlg, IDC_LST_ANTO), &lvI);
+
+ }
+ }
+
+ hContact = ( HANDLE )CallService( MS_DB_CONTACT_FINDNEXT,( WPARAM )hContact, 0 );
+ }
+ }
+
+ return 0;
+
+ case WM_CLOSE:
+ DestroyWindow(hwndDlg);
+ break;
+
+ case WM_COMMAND:
+ if ( HIWORD( wParam ) == BN_CLICKED ) {
+ switch( LOWORD( wParam )) {
+ case IDC_BUT_SELALL: {
+ int size = ListView_GetItemCount(GetDlgItem(hwndDlg, IDC_LST_ANTO));
+ for(int i = 0; i < size; i++) ListView_SetCheckState(GetDlgItem(hwndDlg, IDC_LST_ANTO), i, true);
+ }
+ return 0;
+ case IDC_BUT_SELINV: {
+ int size = ListView_GetItemCount(GetDlgItem(hwndDlg, IDC_LST_ANTO));
+ for(int i = 0; i < size; i++)
+ ListView_SetCheckState(GetDlgItem(hwndDlg, IDC_LST_ANTO), i,
+ !ListView_GetCheckState(GetDlgItem(hwndDlg, IDC_LST_ANTO), i)
+ );
+ }
+ return 0;
+ case IDOK: {
+ // build AnnouncementData
+ AnnouncementData ad;
+ DBVARIANT dbv;
+ LVITEM lvI = {0};
+
+ char id[1024];
+ strcpy(id, "@U"); // documentation says prepend '@U' to usernames and '@G' to notes group names - but
+ char *p = id + 2; // it's wrong - it works for a list of user id's with no prefix - so we'll do both
+
+ // build recipient list
+ ad.recipients = 0;
+
+ int size = ListView_GetItemCount(GetDlgItem(hwndDlg, IDC_LST_ANTO));
+ int send_count = 0;
+ for(int i = 0; i < size; i++) {
+ if(ListView_GetCheckState(GetDlgItem(hwndDlg, IDC_LST_ANTO), i)) {
+ lvI.iItem = i;
+ lvI.iSubItem = 0;
+ lvI.mask = LVIF_PARAM;
+ ListView_GetItem(GetDlgItem(hwndDlg, IDC_LST_ANTO), &lvI);
+
+ if(!DBGetContactSettingUtf((HANDLE)lvI.lParam, PROTO, "stid", &dbv)) {
+ ad.recipients = g_list_prepend(ad.recipients, _strdup(dbv.pszVal));
+ strcpy(p, dbv.pszVal);
+ ad.recipients = g_list_prepend(ad.recipients, _strdup(id));
+ send_count++;
+ DBFreeVariant(&dbv);
+ }
+ }
+ }
+
+ // call function pointed to by lParam
+ if(send_count > 0) {
+ GetWindowText(GetDlgItem(hwndDlg, IDC_ED_ANMSG), ad.msg, MAX_MESSAGE_SIZE);
+ SendAnnounceFunc f = (SendAnnounceFunc)GetWindowLong(hwndDlg, GWL_USERDATA);
+ f(&ad);
+ }
+
+ // clean up recipient list
+ for(GList *rit = ad.recipients; rit; rit = rit->next) {
+ free(rit->data);
+ }
+ if(ad.recipients) g_list_free(ad.recipients);
+
+ DestroyWindow(hwndDlg);
+ }
+ return 0;
+ case IDCANCEL:
+ DestroyWindow(hwndDlg);
+ return 0;
+ }
+ }
+ break;
+ }
+
+ return 0;
+} \ No newline at end of file
diff --git a/plugins/!NotAdopted/sametime/session_announce_win.h b/plugins/!NotAdopted/sametime/session_announce_win.h
new file mode 100644
index 0000000000..e311af9b9f
--- /dev/null
+++ b/plugins/!NotAdopted/sametime/session_announce_win.h
@@ -0,0 +1,15 @@
+#ifndef _SESSION_ANNOUNCE_WIN_INC
+#define _SESSION_ANNOUNCE_WIN_INC
+
+#include "common.h"
+
+typedef struct {
+ TCHAR msg[MAX_MESSAGE_SIZE];
+ GList *recipients;
+} AnnouncementData;
+
+typedef void (*SendAnnounceFunc)(AnnouncementData *ad);
+
+INT_PTR CALLBACK SessionAnnounceDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+#endif
diff --git a/plugins/!NotAdopted/sametime/userlist.cpp b/plugins/!NotAdopted/sametime/userlist.cpp
new file mode 100644
index 0000000000..416e521e5f
--- /dev/null
+++ b/plugins/!NotAdopted/sametime/userlist.cpp
@@ -0,0 +1,909 @@
+#include "userlist.h"
+#include "session.h"
+
+mwServiceStorage *service_storage = 0;
+mwServiceAware *service_aware = 0;
+mwServiceResolve *service_resolve = 0;
+
+mwAwareList *aware_list = 0;
+
+HANDLE hContactDeletedEvent = 0;
+
+HANDLE FindContactByUserId(const char *id) {
+ char *proto;
+ DBVARIANT dbv;
+ HANDLE hContact = ( HANDLE )CallService( MS_DB_CONTACT_FINDFIRST, 0, 0 );
+ while ( hContact != NULL )
+ {
+ proto = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM )hContact,0 );
+ if ( proto && !strcmp( PROTO, proto)) {
+ if(!DBGetContactSettingUtf(hContact, PROTO, "stid", &dbv)) {
+ if(dbv.pszVal && strcmp(id, dbv.pszVal) == 0) {
+ DBFreeVariant(&dbv);
+ return hContact;
+ }
+ DBFreeVariant(&dbv);
+ }
+ }
+ hContact = ( HANDLE )CallService( MS_DB_CONTACT_FINDNEXT,( WPARAM )hContact, 0 );
+ }
+
+ return 0;
+}
+
+bool GetAwareIdFromContact(HANDLE hContact, mwAwareIdBlock *id_block) {
+ char *proto = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM )hContact,0 );
+ DBVARIANT dbv;
+ if ( proto && !strcmp( PROTO, proto)) {
+ if(!DBGetContactSettingUtf(hContact, PROTO, "stid", &dbv)) {
+ if(dbv.pszVal) {
+ id_block->type = mwAware_USER;
+ id_block->user = _strdup(dbv.pszVal);
+ id_block->community = 0;
+ DBFreeVariant(&dbv);
+ return true;
+ }
+ DBFreeVariant(&dbv);
+ }
+ }
+ return false;
+}
+
+void SetContactGroup(HANDLE hContact, const char *name) {
+ if(ServiceExists(MS_CLIST_GROUPRENAME"W"))
+ DBWriteContactSettingStringUtf(hContact, "CList", "Group", name);
+ else {
+ wchar_t buff[512];
+ char mb[512];
+
+ MultiByteToWideChar(CP_UTF8, 0, name, -1, buff, 512);
+ WideCharToMultiByte(CallService(MS_LANGPACK_GETCODEPAGE, 0, 0), 0, buff, -1, mb, 512, 0, 0);
+
+ DBWriteContactSettingString(hContact, "CList", "Group", mb);
+ }
+
+}
+
+void AddGroup(const char *name, bool expanded) {
+ if(name && strcmp(name, "MetaContacts Hidden Group") == 0)
+ return;
+
+ if(name && strcmp(name, Translate("None")) == 0)
+ return;
+
+ HANDLE hGroup = (HANDLE)GroupNameExists(name, -1);
+ if(!hGroup) {
+ wchar_t namew[512];
+ MultiByteToWideChar(CP_UTF8, 0, name, -1, namew, 512);
+
+ hGroup = (HANDLE)CallService(MS_CLIST_GROUPCREATE, 0, 0);
+
+ if(ServiceExists(MS_CLIST_GROUPRENAME"W")) {
+ CallService(MS_CLIST_GROUPRENAME"W", (WPARAM)hGroup, (LPARAM)namew);
+ } else {
+ char mb[512];
+ WideCharToMultiByte(CallService(MS_LANGPACK_GETCODEPAGE, 0, 0), 0, namew, -1, mb, 512, 0, 0);
+
+ CallService(MS_CLIST_GROUPRENAME, (WPARAM)hGroup, (LPARAM)mb);
+ }
+
+ }
+
+ // doesn't call clui! arg!
+ //CallService(MS_CLIST_GROUPSETEXPANDED, (WPARAM)hGroup, (LPARAM)(expanded ? 1 : 0));
+
+ HWND hwndClist = (HWND)CallService(MS_CLUI_GETHWND, 0, 0);
+ HWND hwndClc = FindWindowEx(hwndClist, 0, CLISTCONTROL_CLASS, 0);
+
+ HANDLE hItem = (HANDLE)SendMessage(hwndClc, CLM_FINDGROUP, (WPARAM)hGroup, 0);
+ SendMessage(hwndClc, CLM_EXPAND, (WPARAM)hItem, (LPARAM) (expanded ? 1 : 0));
+}
+
+
+HANDLE AddContact(mwSametimeUser *user, bool temporary) {
+ const char *id = mwSametimeUser_getUser(user);
+ const char *name = mwSametimeUser_getShortName(user);
+ const char *nick = mwSametimeUser_getAlias(user);
+ //const char *nick = mwSametimeUser_getShortName(user);
+ mwSametimeUserType type = mwSametimeUser_getType(user);
+
+ HANDLE hContact = FindContactByUserId(id);
+ bool new_contact = false;
+ if(!hContact) {
+ hContact = (HANDLE)CallService(MS_DB_CONTACT_ADD, 0, 0);
+ new_contact = true;
+ } else if(!temporary) {
+ DBDeleteContactSetting(hContact, "CList", "NotOnList");
+ DBDeleteContactSetting(hContact, "CList", "Hidden");
+ }
+
+ if(hContact) {
+ // add to miranda
+ if(new_contact) DBWriteContactSettingStringUtf(hContact, PROTO, "stid", id);
+
+ if(name && strlen(name))
+ DBWriteContactSettingStringUtf(hContact, PROTO, "Name", name);
+
+ if(nick && strlen(nick)) {
+ DBWriteContactSettingStringUtf(hContact, PROTO, "Nick", nick);
+ } else if(name && strlen(name)) {
+ DBWriteContactSettingStringUtf(hContact, PROTO, "Nick", name);
+ } else {
+ DBWriteContactSettingStringUtf(hContact, PROTO, "Nick", id);
+ }
+
+ DBWriteContactSettingByte(hContact, PROTO, "type", (BYTE)type);
+
+ if(new_contact) {
+ CallService(MS_PROTO_ADDTOCONTACT, (WPARAM)hContact, (LPARAM)PROTO);
+
+ //add to our awareness list
+ mwAwareIdBlock id_block;
+ if(GetAwareIdFromContact(hContact, &id_block)) {
+
+ GList *gl;
+
+ gl = g_list_prepend(NULL, &id_block);
+ mwAwareList_addAware(aware_list, gl);
+
+ g_list_free(gl);
+
+ free(id_block.user);
+ }
+ }
+
+ if(temporary) {
+ DBWriteContactSettingByte(hContact, "CList", "NotOnList", 1);
+ DBWriteContactSettingByte(hContact, "CList", "Hidden", 1);
+ } else {
+ DBDeleteContactSetting(hContact, "CList", "NotOnList");
+ DBDeleteContactSetting(hContact, "CList", "Hidden");
+ }
+ }
+
+ return hContact;
+}
+
+void ImportContactsFromList(mwSametimeList *user_list, bool temporary) {
+ // add contacts
+ mwSametimeGroup *stgroup;
+ mwSametimeUser *stuser;
+
+ GList *gl, *gtl, *ul, *utl;
+
+ const char *group_name;
+ const char *group_alias;
+ mwSametimeGroupType group_type;
+ bool group_open;
+
+ gl = gtl = mwSametimeList_getGroups(user_list);
+ for(; gl; gl = gl->next) {
+ char buff[256];
+
+ stgroup = (mwSametimeGroup *) gl->data;
+
+ group_name = mwSametimeGroup_getName(stgroup);
+ group_alias = mwSametimeGroup_getAlias(stgroup);
+ if(!group_alias) group_alias = group_name;
+
+ group_type = mwSametimeGroup_getType(stgroup);
+ group_open = (mwSametimeGroup_isOpen(stgroup) != 0);
+
+ mir_snprintf(buff, 256, "GN_%s", group_alias);
+ DBWriteContactSettingStringUtf(0, PROTO_GROUPS, buff, group_name);
+ mir_snprintf(buff, 256, "GT_%s", group_alias);
+ DBWriteContactSettingByte(0, PROTO_GROUPS, buff, (BYTE)group_type);
+ mir_snprintf(buff, 256, "GO_%s", group_alias);
+ DBWriteContactSettingByte(0, PROTO_GROUPS, buff, (BYTE)(group_open ? 1 : 0));
+
+ // inverse mapping
+ mir_snprintf(buff, 256, "GA_%s", group_name);
+ DBWriteContactSettingStringUtf(0, PROTO_GROUPS, buff, group_alias);
+
+ AddGroup(group_alias, group_open);
+
+ if(group_type == mwSametimeGroup_DYNAMIC) {
+
+ mwAwareIdBlock id_block;
+ id_block.type = mwAware_GROUP;
+ id_block.user = (char *)group_name;
+ id_block.community = 0;
+
+ GList *gl;
+
+ gl = g_list_prepend(NULL, &id_block);
+ mwAwareList_addAware(aware_list, gl);
+
+ g_list_free(gl);
+ }
+
+ ul = utl = mwSametimeGroup_getUsers(stgroup);
+ for(; ul; ul = ul->next) {
+
+ stuser = (mwSametimeUser *) ul->data;
+ HANDLE hContact = AddContact(stuser, temporary);
+
+ if(hContact && group_alias && strcmp(group_alias, Translate("None")) != 0 && strcmp(group_alias, "MetaContacts Hidden Group") != 0) {
+ SetContactGroup(hContact, group_alias);
+ // mark contact as belonging to dynamic group
+ }
+ }
+ g_list_free(utl);
+ }
+ g_list_free(gtl);
+
+
+}
+
+void ExportContactsToList(mwSametimeList *user_list) {
+ mwSametimeGroup *stgroup = 0;
+ char *group_name;
+ char *group_alias;
+ mwSametimeGroupType group_type;
+ bool group_open;
+
+ mwSametimeUser *stuser;
+ char *user_alias;
+ char *user_shortName;
+ mwSametimeUserType user_type;
+
+ char *proto;
+ DBVARIANT dbv, dbv2;
+ char buff[256];
+ HANDLE hContact = ( HANDLE )CallService( MS_DB_CONTACT_FINDFIRST, 0, 0 );
+ mwAwareIdBlock id_block;
+
+ mwIdBlock uid;
+
+ GList *gl = 0;
+ while ( hContact != NULL )
+ {
+ proto = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM )hContact,0 );
+ if ( proto && !strcmp( PROTO, proto)) {
+ if(!DBGetContactSettingUtf(hContact, PROTO, "stid", &dbv)) {
+ if(dbv.pszVal) {
+ if(GetAwareIdFromContact(hContact, &id_block)) {
+ if(!DBGetContactSettingUtf(hContact, "CList", "Group", &dbv2)) {
+ group_alias = _strdup(dbv2.pszVal);
+ DBFreeVariant(&dbv2);
+ } else
+ group_alias = _strdup(Translate("None"));
+
+ if(group_alias) {
+ mir_snprintf(buff, 256, "GT_%s", group_alias);
+ group_type = (mwSametimeGroupType)DBGetContactSettingByte(0, PROTO_GROUPS, buff, (BYTE)mwSametimeGroup_NORMAL);
+ // apparently we don't want to upload contacts in dynamic groups - see gaim sametime plugin comments
+ if(group_type == mwSametimeGroup_DYNAMIC) {
+ DBFreeVariant(&dbv);
+ free(id_block.user);
+ free(group_alias);
+ hContact = ( HANDLE )CallService( MS_DB_CONTACT_FINDNEXT,( WPARAM )hContact, 0 );
+ continue;
+ }
+
+
+ mir_snprintf(buff, 256, "GN_%s", group_alias);
+ if(!DBGetContactSettingUtf(0, PROTO_GROUPS, buff, &dbv2)) {
+ group_name = _strdup(dbv2.pszVal);
+ DBFreeVariant(&dbv2);
+ } else
+ group_name = _strdup(group_alias);
+
+ //group_open = (DBGetContactSettingByte(0, PROTO_GROUPS, buff, 0) == 1);
+ HANDLE hGroup = (HANDLE)GroupNameExists(group_alias, -1);
+ if(hGroup) {
+ int expanded;
+ CallService(MS_CLIST_GROUPGETNAME, (WPARAM)hGroup, (LPARAM)&expanded);
+ group_open = (expanded != 0);
+ } else {
+ mir_snprintf(buff, 256, "GO_%s", group_alias);
+ group_open = (DBGetContactSettingByte(0, PROTO_GROUPS, buff, 0) == 1);
+ }
+
+
+ stgroup = 0;
+ stgroup = mwSametimeList_findGroup(user_list, group_name);
+ if(!stgroup) {
+ if(group_name) stgroup = mwSametimeGroup_new(user_list, group_type, group_name);
+ mwSametimeGroup_setAlias(stgroup, group_alias);
+ mwSametimeGroup_setOpen(stgroup, group_open);
+ }
+
+ free(group_name);
+ free(group_alias);
+
+ if(!DBGetContactSettingUtf(hContact, PROTO, "Name", &dbv2)) {
+ user_shortName = _strdup(dbv2.pszVal);
+ DBFreeVariant(&dbv2);
+ } else
+ user_shortName = 0;
+
+ if(!DBGetContactSettingUtf(hContact, "CList", "MyHandle", &dbv2)) {
+ user_alias = _strdup(dbv2.pszVal);
+ DBFreeVariant(&dbv2);
+ } else
+ user_alias = 0;
+
+ user_type = (mwSametimeUserType)DBGetContactSettingByte(hContact, PROTO, "type", (BYTE)mwSametimeUser_NORMAL);
+
+ uid.user = id_block.user;
+ uid.community = id_block.community;
+
+ stuser = mwSametimeUser_new(stgroup, user_type, &uid);
+ if(user_shortName) {
+ mwSametimeUser_setShortName(stuser, user_shortName);
+ free(user_shortName);
+ }
+ if(user_alias) {
+ mwSametimeUser_setAlias(stuser, user_alias);
+ free(user_alias);
+ }
+ }
+
+ free(id_block.user);
+ }
+ }
+ DBFreeVariant(&dbv);
+ }
+ }
+ hContact = ( HANDLE )CallService( MS_DB_CONTACT_FINDNEXT,( WPARAM )hContact, 0 );
+ }
+}
+
+void ImportContactsFromFile(TCHAR *filename) {
+#ifdef _UNICODE
+#else
+ std::ifstream in(filename);
+ std::string text;
+ std::string line;
+ if(in.is_open()) {
+ while(!in.eof()) {
+ std::getline(in, line);
+ text += line;
+ text += "\r\n";
+ }
+ in.close();
+
+ mwSametimeList *new_list = mwSametimeList_load(text.c_str());
+
+ ImportContactsFromList(new_list, false);
+
+ mwSametimeList_free(new_list);
+
+ }
+#endif
+
+}
+
+void ExportContactsToServer() {
+ mwSametimeList *user_list;
+ mwStorageUnit *unit;
+
+ mwPutBuffer *buff;
+ mwOpaque *op;
+
+ if(MW_SERVICE_IS_DEAD(service_storage)) {
+ //MessageBox(0, "Failed to upload contacts - Storage service unavailable.", "Error", MB_OK);
+ ShowError(TranslateT("Failed to upload contacts - Storage service unavailable."));
+ return;
+ }
+
+ user_list = mwSametimeList_new();
+ ExportContactsToList(user_list);
+
+ buff = mwPutBuffer_new();
+ mwSametimeList_put(buff, user_list);
+ mwSametimeList_free(user_list);
+
+ /* put the buffer contents into a storage unit */
+ unit = mwStorageUnit_new(mwStore_AWARE_LIST);
+ op = mwStorageUnit_asOpaque(unit);
+ mwPutBuffer_finalize(op, buff);
+
+ /* save the storage unit to the service */
+ mwServiceStorage_save(service_storage, unit, NULL, NULL, NULL);
+}
+
+void load_users_callback(mwServiceStorage *srvc, guint32 result, mwStorageUnit *item, gpointer data) {
+ if(mwStorageUnit_getKey(item) == mwStore_AWARE_LIST) {
+ mwGetBuffer *buff = mwGetBuffer_wrap(mwStorageUnit_asOpaque(item));
+
+ if(mwGetBuffer_remaining(buff)) {
+ mwSametimeList *user_list = mwSametimeList_new();
+
+ mwSametimeList_get(buff, user_list);
+ ImportContactsFromList(user_list, false);
+
+ mwSametimeList_free(user_list);
+ }
+ }
+}
+
+
+void UserListAddStored() {
+ mwStorageUnit *unit;
+
+ unit = mwStorageUnit_new(mwStore_AWARE_LIST);
+ mwServiceStorage_load(service_storage, unit, load_users_callback, 0, 0);
+}
+
+int ContactDeleted(WPARAM wParam, LPARAM lParam) {
+ mwAwareIdBlock id_block;
+ HANDLE hContact = (HANDLE)wParam;
+
+ if(DBGetContactSettingByte(hContact, PROTO, "ChatRoom", 0))
+ return 0;
+
+ if(GetAwareIdFromContact(hContact, &id_block)) {
+ GList *gl;
+
+ gl = g_list_prepend(NULL, &id_block);
+ mwAwareList_removeAware(aware_list, gl);
+
+ g_list_free(gl);
+
+ free(id_block.user);
+ }
+
+ return 0;
+}
+
+void mwServiceAware_on_attrib(mwServiceAware *srvc, mwAwareAttribute *attrib) {
+
+}
+
+
+void mwServiceAware_clear(mwServiceAware *srvc) {
+}
+
+
+mwAwareHandler mwAware_handler = {
+ mwServiceAware_on_attrib,
+ mwServiceAware_clear
+};
+
+void mwResolve_handler_dyngroup(mwServiceResolve *srvc, guint32 id, guint32 code, GList *results, gpointer data) {
+ mwResolveResult *result;
+ mwResolveMatch *match;
+
+ mwSametimeGroup *stgroup = (mwSametimeGroup *)data;
+
+ g_return_if_fail(results != NULL);
+
+ if(results) {
+ result = (mwResolveResult *)results->data;
+ if(result && result->matches) {
+
+ match = (mwResolveMatch *)result->matches->data;
+ if(match) {
+ mwIdBlock uid;
+ uid.user = match->id;
+ uid.community = 0;
+ mwSametimeUser *stuser = mwSametimeUser_new(stgroup, mwSametimeUser_NORMAL, &uid);
+ mwSametimeUser_setShortName(stuser, match->name);
+
+ HANDLE hContact = AddContact(stuser, false);
+
+ const char *group_name = mwSametimeGroup_getName(stgroup);
+ const char *group_alias = mwSametimeGroup_getAlias(stgroup);
+ if(!group_alias) group_alias = group_name;
+ if(hContact && group_alias && strcmp(group_alias, Translate("None")) && strcmp(group_alias, "MetaContacts Hidden Group")) {
+ SetContactGroup(hContact, group_alias);
+ }
+ }
+ }
+ }
+
+
+ if(stgroup)
+ mwSametimeList_free(mwSametimeGroup_getList(stgroup));
+}
+
+void mwAwareList_on_aware(mwAwareList *list, mwAwareSnapshot *aware) {
+ HANDLE hContact = FindContactByUserId(aware->id.user);
+ char *group = 0;
+ DBVARIANT dbv;
+
+ // update self - necessary for some servers
+ if(aware->online && !DBGetContactSettingUtf(0, PROTO, "stid", &dbv) && strcmp(aware->id.user, dbv.pszVal) == 0) {
+ int new_status = ID_STATUS_OFFLINE;
+
+ switch(aware->status.status) {
+ case mwStatus_ACTIVE:
+ new_status = ID_STATUS_ONLINE;
+ break;
+ case mwStatus_AWAY:
+ new_status = ID_STATUS_AWAY;
+ break;
+ case mwStatus_IDLE:
+ new_status = ID_STATUS_IDLE;
+ break;
+ case mwStatus_BUSY:
+ new_status = ID_STATUS_DND;
+ break;
+ }
+ if(new_status != ID_STATUS_IDLE) //SetSessionStatus(new_status);
+ UpdateSelfStatus();
+
+ DBFreeVariant(&dbv);
+ }
+
+ if(hContact && !DBGetContactSettingUtf(hContact, "CList", "Group", &dbv)) {
+ group = _strdup(dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+
+ if(aware->group && (!group || strcmp(aware->group, group) || !hContact)) {
+ // dynamic group member we're not already aware of
+ // resolve server alias to user id via resolver
+ mwSametimeList *user_list = mwSametimeList_new();
+ mwSametimeGroup *stgroup = mwSametimeGroup_new(user_list, mwSametimeGroup_DYNAMIC, aware->group);
+ char buff[256];
+ mir_snprintf(buff, 256, "GA_%s", aware->group);
+ if(!DBGetContactSettingUtf(0, PROTO_GROUPS, buff, &dbv)) {
+ mwSametimeGroup_setAlias(stgroup, dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+
+ GList *query = g_list_prepend(0, (void *)aware->id.user);
+
+ mwServiceResolve_resolve(service_resolve, query, mwResolveFlag_USERS, mwResolve_handler_dyngroup, (gpointer)stgroup, 0);
+
+ g_list_free(query);
+ } else if(hContact) {
+
+ if(aware->online) {
+ int new_status = ID_STATUS_OFFLINE;
+
+ switch(aware->status.status) {
+ case mwStatus_ACTIVE:
+ new_status = ID_STATUS_ONLINE;
+ DBWriteContactSettingDword(hContact, PROTO, "IdleTS", 0);
+ DBWriteContactSettingWord(hContact, PROTO, "Status", new_status);
+ break;
+ case mwStatus_AWAY:
+ new_status = ID_STATUS_AWAY;
+ DBWriteContactSettingDword(hContact, PROTO, "IdleTS", 0);
+ DBWriteContactSettingWord(hContact, PROTO, "Status", new_status);
+ break;
+ case mwStatus_IDLE:
+ if(options.idle_as_away) {
+ new_status = ID_STATUS_AWAY;
+ DBWriteContactSettingWord(hContact, PROTO, "Status", new_status);
+ }
+ DBWriteContactSettingDword(hContact, PROTO, "IdleTS", (DWORD)time(0));
+ break;
+ case mwStatus_BUSY:
+ new_status = ID_STATUS_DND;
+ DBWriteContactSettingWord(hContact, PROTO, "Status", new_status);
+ DBWriteContactSettingDword(hContact, PROTO, "IdleTS", 0);
+ break;
+ }
+ } else
+ DBWriteContactSettingWord(hContact, PROTO, "Status", ID_STATUS_OFFLINE);
+
+ if(service_aware) {
+ const char *desc = mwServiceAware_getText(service_aware, &aware->id);
+ if(desc)
+ //DBWriteContactSettingStringUtf(hContact, PROTO, "StatusMsg", desc);
+ DBWriteContactSettingStringUtf(hContact, "CList", "StatusMsg", desc);
+ else
+ //DBWriteContactSettingStringUtf(hContact, PROTO, "StatusMsg", "");
+ //DBDeleteContactSetting(hContact, PROTO, "StatusMsg");
+ DBDeleteContactSetting(hContact, "CList", "StatusMsg");
+ }
+ }
+
+ if(group) free(group);
+}
+
+
+void mwAwareList_on_attrib(mwAwareList *list, mwAwareIdBlock *id, mwAwareAttribute *attrib) {
+}
+
+
+void mwAwareList_clear(mwAwareList *list) {
+}
+
+
+mwAwareListHandler mwAwareList_handler = {
+ mwAwareList_on_aware,
+ mwAwareList_on_attrib,
+ mwAwareList_clear
+};
+
+void UserListCreate() {
+ mwServiceAware_unsetAttribute(service_aware, mwAttribute_SPEAKERS);
+ mwServiceAware_unsetAttribute(service_aware, mwAttribute_MICROPHONE);
+ mwServiceAware_unsetAttribute(service_aware, mwAttribute_VIDEO_CAMERA);
+
+ mwServiceAware_setAttributeBoolean(service_aware, mwAttribute_AV_PREFS_SET, TRUE);
+
+ mwServiceAware_setAttributeBoolean(service_aware, mwAttribute_FILE_TRANSFER, TRUE);
+
+
+ aware_list = mwAwareList_new(service_aware, &mwAwareList_handler);
+
+ // add all contacts
+
+ char *proto;
+ DBVARIANT dbv;
+ HANDLE hContact = ( HANDLE )CallService( MS_DB_CONTACT_FINDFIRST, 0, 0 );
+ mwAwareIdBlock id_block;
+ GList *gl = 0;
+
+ while ( hContact != NULL )
+ {
+ proto = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM )hContact,0 );
+ if (DBGetContactSettingByte(hContact, PROTO, "ChatRoom", 0) == 0 && proto && !strcmp( PROTO, proto)) {
+ if(!DBGetContactSettingUtf(hContact, PROTO, "stid", &dbv)) {
+ if(dbv.pszVal) {
+ if(GetAwareIdFromContact(hContact, &id_block)) {
+ // add user to aware list
+ gl = g_list_prepend(0, &id_block);
+
+ mwAwareList_addAware(aware_list, gl);
+
+ free(id_block.user);
+ g_list_free(gl);
+ }
+ }
+ DBFreeVariant(&dbv);
+ }
+ }
+ hContact = ( HANDLE )CallService( MS_DB_CONTACT_FINDNEXT,( WPARAM )hContact, 0 );
+ }
+
+
+ // add self - might be necessary for some servers
+ if(!DBGetContactSettingUtf(0, PROTO, "stid", &dbv)) {
+ id_block.type = mwAware_USER;
+ id_block.user = dbv.pszVal;
+ id_block.community = 0;
+
+ gl = g_list_prepend(0, &id_block);
+ mwAwareList_addAware(aware_list, gl);
+ g_list_free(gl);
+
+ DBFreeVariant(&dbv);
+ }
+}
+
+void UserListDestroy() {
+ mwAwareList_free(aware_list);
+ aware_list = 0;
+}
+
+void UserRecvAwayMessage(HANDLE hContact) {
+
+ DBVARIANT dbv;
+ char buff[512];
+ buff[0] = 0;
+
+ if(!DBGetContactSettingUtf(hContact, "CList", "StatusMsg", &dbv) && strlen(dbv.pszVal)) {
+ strncpy(buff, dbv.pszVal, 512);
+ buff[511] = 0;
+ DBFreeVariant(&dbv);
+ }
+
+ CCSDATA ccs = {0};
+ PROTORECVEVENT pre = {0};
+
+ ccs.hContact = hContact;
+ ccs.szProtoService = PSR_AWAYMSG;
+ ccs.wParam = 0;
+ ccs.lParam = (LPARAM)&pre;
+
+ pre.timestamp = (DWORD)time(0);
+ if(strlen(buff))
+ pre.szMessage = buff;
+ else
+ pre.szMessage = 0;
+
+ CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs);
+}
+
+void mwResolve_handler(mwServiceResolve *srvc, guint32 id, guint32 code, GList *results, gpointer data) {
+ bool advanced = (data != 0);
+
+ MYCUSTOMSEARCHRESULTS mcsr = {0};
+ mcsr.nSize = sizeof(MYCUSTOMSEARCHRESULTS);
+ //MYPROTOSEARCHRESULT mpsr = {0};
+ //mpsr.cbSize = sizeof(MYPROTOSEARCHRESULT);
+ mcsr.psr.nick = mcsr.psr.name;
+
+ mcsr.nFieldCount = 4;
+ TCHAR fields[4][512];
+ TCHAR *fields_addr[4];
+ mcsr.pszFields = fields_addr;
+ mcsr.pszFields[0] = fields[0];
+ mcsr.pszFields[1] = fields[1];
+ mcsr.pszFields[2] = fields[2];
+ mcsr.pszFields[3] = fields[3];
+
+ if(advanced) {
+ // send column names
+ mcsr.psr.cbSize = 0;
+ _tcsncpy(mcsr.pszFields[0], TranslateT("Id"), 512);
+ _tcsncpy(mcsr.pszFields[1], TranslateT("Name"), 512);
+ _tcsncpy(mcsr.pszFields[2], TranslateT("Description"), 512);
+ _tcsncpy(mcsr.pszFields[3], TranslateT("Group?"), 512);
+ ProtoBroadcastAck(PROTO,NULL,ACKTYPE_SEARCH, ACKRESULT_SEARCHRESULT, (HANDLE)id, (LPARAM)&mcsr);
+ }
+
+ mcsr.psr.cbSize = sizeof(MYPROTOSEARCHRESULT);
+
+ if(code == mwResolveCode_SUCCESS) {
+ GList *ri = results, *mri;
+ for(;ri;ri = ri->next) {
+ mri = ((mwResolveResult *)ri->data)->matches;
+ for(;mri;mri = mri->next) {
+ strncpy(mcsr.psr.stid, ((mwResolveMatch *)mri->data)->id, 256);
+ mcsr.psr.stid[255] = 0;
+ MultiByteToWideChar(CP_UTF8, 0, mcsr.psr.stid, -1, mcsr.pszFields[0], 512);
+
+ strncpy(mcsr.psr.name, ((mwResolveMatch *)mri->data)->name, 256);
+ mcsr.psr.name[255] = 0;
+ MultiByteToWideChar(CP_UTF8, 0, mcsr.psr.name, -1, mcsr.pszFields[1], 512);
+
+ if(((mwResolveMatch *)mri->data)->desc)
+ MultiByteToWideChar(CP_UTF8, 0, ((mwResolveMatch *)mri->data)->desc, -1, mcsr.pszFields[2], 512);
+ else
+ mcsr.pszFields[2][0] = 0;
+
+ mcsr.psr.group = (((mwResolveMatch *)mri->data)->type == mwResolveMatch_GROUP);
+ //MultiByteToWideChar(CP_UTF8, 0, mcsr.psr.name, -1, mcsr.pszFields[1], 512);
+ _tcsncpy(mcsr.pszFields[3], mcsr.psr.group ? TranslateT("True") : TranslateT("False"), 512);
+
+ if(advanced)
+ ProtoBroadcastAck(PROTO,NULL,ACKTYPE_SEARCH, ACKRESULT_SEARCHRESULT, (HANDLE)id, (LPARAM)&mcsr);
+ else
+ ProtoBroadcastAck(PROTO,NULL,ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)id, (LPARAM)&mcsr.psr);
+ }
+ }
+ ProtoBroadcastAck(PROTO,NULL,ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)id, 0);
+ }
+}
+
+void mwResolve_handler_details(mwServiceResolve *srvc, guint32 id, guint32 code, GList *results, gpointer data) {
+ MYPROTOSEARCHRESULT mpsr = {0};
+ mpsr.cbSize = sizeof(mpsr);
+ mpsr.nick = mpsr.name;
+
+ if(code == mwResolveCode_SUCCESS) {
+ GList *ri = results, *mri;
+ for(;ri;ri = ri->next) {
+ mri = ((mwResolveResult *)ri->data)->matches;
+ for(;mri;mri = mri->next) {
+
+ HANDLE hContact = FindContactByUserId(((mwResolveMatch *)mri->data)->id);
+ if(hContact) {
+ char *name = ((mwResolveMatch *)mri->data)->name;
+ if(name && strlen(name)) {
+ DBWriteContactSettingStringUtf(hContact, PROTO, "Name", name);
+ DBWriteContactSettingStringUtf(hContact, PROTO, "Nick", name);
+ }
+ }
+ }
+ }
+ }
+}
+
+int SearchForUser(const char *name) {
+ if(current_status != ID_STATUS_OFFLINE && service_resolve) {
+ GList *query = g_list_prepend(0, (void *)name);
+
+ guint32 id = mwServiceResolve_resolve(service_resolve, query, (mwResolveFlag)(mwResolveFlag_USERS | mwResolveFlag_GROUPS), mwResolve_handler, 0, 0);
+
+ g_list_free(query);
+ return id; // search handle
+ }
+
+ return 0; // fail
+}
+
+int GetMoreDetails(const char *name) {
+ if(current_status != ID_STATUS_OFFLINE && service_resolve) {
+ GList *query = g_list_prepend(0, (void *)name);
+
+ guint32 id = mwServiceResolve_resolve(service_resolve, query, (mwResolveFlag)(mwResolveFlag_USERS | mwResolveFlag_UNIQUE), mwResolve_handler_details, 0, 0);
+
+ g_list_free(query);
+ return id; // search handle
+ }
+
+ return 0; // fail
+}
+
+static BOOL CALLBACK SearchDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ {
+ TranslateDialogDefault( hwndDlg );
+ break;
+ }
+ }
+ return 0;
+}
+
+int CreateSearchDialog(WPARAM wParam, LPARAM lParam) {
+ //MessageBox(0, _T("Creating Dialog"), _T("CreateSearchDialog"), MB_OK);
+ return (int)CreateDialog(hInst, MAKEINTRESOURCE(IDD_USERSEARCH), (HWND)lParam, SearchDialogFunc);
+}
+
+int SearchFromDialog(WPARAM wParam, LPARAM lParam) {
+ //MessageBox(0, _T("Searching..."), _T("SearchFromDialog"), MB_OK);
+ HWND hWnd = (HWND)lParam;
+ TCHAR buf[512];
+ if(GetDlgItemText(hWnd, IDC_EDIT1, buf, 512)) {
+ if(current_status != ID_STATUS_OFFLINE && service_resolve) {
+ char name[512];
+#ifdef _UNICODE
+ WideCharToMultiByte(CP_UTF8, 0, buf, -1, name, 512, 0, 0);
+#else
+ strncpy(name, buf, 512);
+#endif
+
+ GList *query = g_list_prepend(0, (void *)name);
+
+ guint32 id = mwServiceResolve_resolve(service_resolve, query, (mwResolveFlag)(mwResolveFlag_USERS | mwResolveFlag_GROUPS), mwResolve_handler, (void *)1, 0);
+
+ g_list_free(query);
+ return id; // search handle
+ }
+ }
+ return 0;
+}
+
+HANDLE AddSearchedUser(MYPROTOSEARCHRESULT *mpsr, bool temporary) {
+ HANDLE hContact = 0;
+
+ mwSametimeList *user_list = mwSametimeList_new();
+ mwSametimeGroup *stgroup = 0;
+ if(mpsr->group) {
+ stgroup = mwSametimeGroup_new(user_list, mwSametimeGroup_DYNAMIC, mpsr->stid);
+ mwSametimeGroup_setAlias(stgroup, mpsr->name);
+ ImportContactsFromList(user_list, temporary);
+ } else {
+ stgroup = mwSametimeGroup_new(user_list, mwSametimeGroup_NORMAL, Translate("None"));
+
+ mwIdBlock uid;
+ uid.user = mpsr->stid;
+ uid.community = 0;
+ mwSametimeUser *stuser = mwSametimeUser_new(stgroup, mwSametimeUser_NORMAL, &uid);
+ mwSametimeUser_setShortName(stuser, mpsr->name);
+
+ hContact = AddContact(stuser, temporary);
+ mwSametimeList_free(mwSametimeGroup_getList(stgroup));
+ }
+
+
+ return hContact;
+}
+
+void InitUserList(mwSession *session) {
+ mwSession_addService(session, (mwService *)(service_storage = mwServiceStorage_new(session)));
+ mwSession_addService(session, (mwService *)(service_resolve = mwServiceResolve_new(session)));
+ mwSession_addService(session, (mwService *)(service_aware = mwServiceAware_new(session, &mwAware_handler)));
+
+ hContactDeletedEvent = HookEvent(ME_DB_CONTACT_DELETED, ContactDeleted);
+}
+
+void DeinitUserList(mwSession *session) {
+ UnhookEvent(hContactDeletedEvent);
+ hContactDeletedEvent = 0;
+
+ mwSession_removeService(session, mwService_AWARE);
+ mwService_free((mwService *)service_aware);
+ service_aware = 0;
+
+ mwSession_removeService(session, mwService_RESOLVE);
+ mwService_free((mwService *)service_resolve);
+ service_resolve = 0;
+
+ mwSession_removeService(session, mwService_STORAGE);
+ mwService_free((mwService *)service_storage);
+ service_storage = 0;
+}
+
diff --git a/plugins/!NotAdopted/sametime/userlist.h b/plugins/!NotAdopted/sametime/userlist.h
new file mode 100644
index 0000000000..be674b0e5f
--- /dev/null
+++ b/plugins/!NotAdopted/sametime/userlist.h
@@ -0,0 +1,59 @@
+#ifndef _USERLIST_INC
+#define _USERLIST_INC
+
+#include "common.h"
+#include "utils.h"
+
+#include <fstream>
+#include <string>
+#include <iostream>
+
+#include "clist_util.h"
+
+typedef struct {
+ int cbSize;
+ char *nick;
+ char *firstName;
+ char *lastName;
+ char *email;
+ char reserved[16];
+
+ char name[256];
+ char stid[256];
+ bool group;
+
+} MYPROTOSEARCHRESULT;
+
+typedef struct {
+ size_t nSize;
+ int nFieldCount;
+ TCHAR ** pszFields;
+ MYPROTOSEARCHRESULT psr;
+} MYCUSTOMSEARCHRESULTS;
+
+HANDLE FindContactByUserId(const char *id);
+bool GetAwareIdFromContact(HANDLE hContact, mwAwareIdBlock *id_block);
+
+int SearchForUser(const char *name);
+int GetMoreDetails(const char *name);
+
+int CreateSearchDialog(WPARAM wParam, LPARAM lParam);
+int SearchFromDialog(WPARAM wParam, LPARAM lParam);
+
+HANDLE AddSearchedUser(MYPROTOSEARCHRESULT *mpsr, bool temporary);
+
+HANDLE AddContact(mwSametimeUser *user, bool temporary);
+
+void UserListCreate();
+void UserListAddStored();
+void UserListDestroy();
+
+void ImportContactsFromFile(TCHAR *filename);
+void ExportContactsToServer();
+
+void UserRecvAwayMessage(HANDLE hContact);
+
+void InitUserList(mwSession *session);
+void DeinitUserList(mwSession *session);
+
+#endif \ No newline at end of file
diff --git a/plugins/!NotAdopted/sametime/utils.cpp b/plugins/!NotAdopted/sametime/utils.cpp
new file mode 100644
index 0000000000..bac35f5009
--- /dev/null
+++ b/plugins/!NotAdopted/sametime/utils.cpp
@@ -0,0 +1,335 @@
+#include "utils.h"
+
+HICON hProtoIcon;
+
+//LRESULT CALLBACK NullWindowProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
+static int NullWindowProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
+{
+ switch( message ) {
+ case WM_COMMAND: {
+ if (HIWORD(wParam) == STN_CLICKED) { //It was a click on the Popup.
+ PUDeletePopUp( hWnd );
+ return TRUE;
+ }
+ break;
+ }
+
+ case WM_CONTEXTMENU:
+ PUDeletePopUp( hWnd );
+ return TRUE;
+ }
+
+ return DefWindowProc(hWnd, message, wParam, lParam);
+}
+
+void CALLBACK sttPopupProcA( ULONG param ) {
+//DWORD sttPopupProcA(LPVOID param) {
+ POPUPDATAEX* ppd = ( POPUPDATAEX* )param;
+
+ if ( ServiceExists(MS_POPUP_ADDPOPUPEX) )
+ CallService( MS_POPUP_ADDPOPUPEX, ( WPARAM )ppd, 0 );
+ else
+ if ( ServiceExists(MS_POPUP_ADDPOPUP) )
+ CallService( MS_POPUP_ADDPOPUP, ( WPARAM )ppd, 0 );
+
+ free( ppd );
+
+ //return 0;
+}
+
+void CALLBACK sttPopupProcW( ULONG param ) {
+//DWORD sttPopupProcW(LPVOID param) {
+ POPUPDATAW* ppd = ( POPUPDATAW* )param;
+
+ if ( ServiceExists(MS_POPUP_ADDPOPUPW) )
+ CallService( MS_POPUP_ADDPOPUPW, ( WPARAM )ppd, 0 );
+
+ free( ppd );
+
+ //return 0;
+}
+
+void ShowPopupA( const char* line1, const char* line2, int flags )
+{
+ if(CallService(MS_SYSTEM_TERMINATED, 0, 0)) return;
+
+ if ( !ServiceExists( MS_POPUP_ADDPOPUP )) {
+ char title[256];
+ sprintf(title, "%s Message", PROTO);
+
+ if(line1 && line2) {
+ char *message = new char[strlen(line1) + strlen(line2) + 2]; // newline and null terminator
+ sprintf(message, "%s\n%s", line1, line2);
+ MessageBoxA( NULL, message, title, MB_OK | MB_ICONINFORMATION );
+ delete message;
+ } else if(line1) {
+ MessageBoxA( NULL, line1, title, MB_OK | MB_ICONINFORMATION );
+ } else if(line2) {
+ MessageBoxA( NULL, line2, title, MB_OK | MB_ICONINFORMATION );
+ }
+ return;
+ }
+
+ POPUPDATAEX* ppd = ( POPUPDATAEX* )malloc( sizeof( POPUPDATAEX ));
+ memset((void *)ppd, 0, sizeof(POPUPDATAEX));
+
+ ppd->lchContact = NULL;
+ ppd->lchIcon = hProtoIcon;
+
+ if(line1 && line2) {
+ strncpy( ppd->lpzContactName, line1, MAX_CONTACTNAME );
+ strncpy( ppd->lpzText, line2, MAX_SECONDLINE );
+ } else if(line1) strncpy( ppd->lpzText, line1, MAX_SECONDLINE );
+ else if(line2) strncpy( ppd->lpzText, line2, MAX_SECONDLINE );
+
+ //ppd->colorBack = GetSysColor( COLOR_BTNFACE );
+ //ppd->colorText = GetSysColor( COLOR_WINDOWTEXT );
+ //ppd->colorText = 0x00FFFFFF; // for old popup modules
+ //ppd->colorBack = POPUP_USE_SKINNED_BG;
+
+ ppd->iSeconds = 0;
+
+ ppd->PluginWindowProc = ( WNDPROC )NullWindowProc;
+ ppd->PluginData = NULL;
+
+ QueueUserAPC( sttPopupProcA , mainThread, ( ULONG )ppd );
+ //CloseHandle(CreateThread(0, 0, (LPTHREAD_START_ROUTINE)sttPopupProcA, (LPVOID)ppd, 0, 0));
+ //sttPopupProcA((ULONG)ppd);
+}
+
+void ShowPopupW( const wchar_t* line1, const wchar_t* line2, int flags )
+{
+ if(CallService(MS_SYSTEM_TERMINATED, 0, 0)) return;
+
+ if ( !ServiceExists( MS_POPUP_ADDPOPUPW )) {
+ wchar_t title[256], *ws;
+ swprintf(title, L"%s Message", TranslateW(ws = a2w(PROTO)));
+ free(ws);
+
+ if(line1 && line2) {
+ wchar_t *message = new wchar_t[wcslen(line1) + wcslen(line2) + 2]; // newline and null terminator
+ swprintf(message, L"%s\n%s", line1, line2);
+ MessageBoxW( NULL, message, title, MB_OK | MB_ICONINFORMATION );
+ delete message;
+ } else if(line1) {
+ MessageBoxW( NULL, line1, title, MB_OK | MB_ICONINFORMATION );
+ } else if(line2) {
+ MessageBoxW( NULL, line2, title, MB_OK | MB_ICONINFORMATION );
+ }
+ return;
+ }
+
+ POPUPDATAW* ppd = ( POPUPDATAW* )malloc( sizeof( POPUPDATAW ));
+ memset((void *)ppd, 0, sizeof(POPUPDATAW));
+
+ ppd->lchContact = NULL;
+ ppd->lchIcon = hProtoIcon;
+
+ if(line1 && line2) {
+ wcsncpy( ppd->lpwzContactName, line1, MAX_CONTACTNAME );
+ wcsncpy( ppd->lpwzText, line2, MAX_SECONDLINE );
+ } else if(line1) wcsncpy( ppd->lpwzText, line1, MAX_SECONDLINE );
+ else if(line2) wcsncpy( ppd->lpwzText, line2, MAX_SECONDLINE );
+
+ //ppd->colorBack = GetSysColor( COLOR_BTNFACE );
+ //ppd->colorText = GetSysColor( COLOR_WINDOWTEXT );
+ //ppd->colorText = 0x00FFFFFF; // for old popup modules
+ //ppd->colorBack = POPUP_USE_SKINNED_BG;
+
+ ppd->iSeconds = 0;
+
+ ppd->PluginWindowProc = ( WNDPROC )NullWindowProc;
+ ppd->PluginData = NULL;
+
+ QueueUserAPC( sttPopupProcW , mainThread, ( ULONG )ppd );
+ //CloseHandle(CreateThread(0, 0, (LPTHREAD_START_ROUTINE)sttPopupProcW, (LPVOID)ppd, 0, 0));
+ //sttPopupProcW((ULONG)ppd);
+}
+
+void ShowWarning(TCHAR *msg) {
+ TCHAR buffer[512];
+ ErrorDisplay disp = options.err_method;
+ // funny logic :) ... try to avoid message boxes
+ // if want baloons but no balloons, try popups
+ // if want popups but no popups, try baloons
+ // if, after that, you want balloons but no balloons, revert to message boxes
+ if(disp == ED_BAL && !ServiceExists(MS_CLIST_SYSTRAY_NOTIFY)) disp = ED_POP;
+ if(disp == ED_POP && !ServiceExists(MS_POPUP_SHOWMESSAGE)) disp = ED_BAL;
+ if(disp == ED_BAL && !ServiceExists(MS_CLIST_SYSTRAY_NOTIFY)) disp = ED_MB;
+
+#ifdef _UNICODE
+ wsprintf(buffer, L"%s Warning", TranslateTS(PROTO));
+#else
+ sprintf(buffer, "%s Warning", Translate(PROTO));
+#endif
+
+
+ switch(disp) {
+ case ED_POP:
+ ShowPopup(buffer, msg, 0);
+ break;
+ case ED_MB:
+ MessageBox(0, msg, buffer, MB_OK | MB_ICONWARNING);
+ break;
+ case ED_BAL:
+ {
+ MIRANDASYSTRAYNOTIFY sn = {0};
+ sn.cbSize = sizeof(sn);
+ sn.szProto = PROTO;
+ sn.szInfoTitle = t2a(buffer);
+ sn.szInfo = t2a(msg);
+ sn.dwInfoFlags = NIIF_WARNING;
+ sn.uTimeout = 10;
+
+ CallService(MS_CLIST_SYSTRAY_NOTIFY, 0, (LPARAM)&sn);
+
+ free(sn.szInfoTitle);
+ free(sn.szInfo);
+ }
+
+ break;
+ }
+}
+
+void ShowError(TCHAR *msg) {
+ TCHAR buffer[512];
+ ErrorDisplay disp = options.err_method;
+ // funny logic :) ... try to avoid message boxes
+ // if want baloons but no balloons, try popups
+ // if want popups but no popups, try baloons
+ // if, after that, you want balloons but no balloons, revert to message boxes
+ if(disp == ED_BAL && !ServiceExists(MS_CLIST_SYSTRAY_NOTIFY)) disp = ED_POP;
+ if(disp == ED_POP && !ServiceExists(MS_POPUP_SHOWMESSAGE)) disp = ED_BAL;
+ if(disp == ED_BAL && !ServiceExists(MS_CLIST_SYSTRAY_NOTIFY)) disp = ED_MB;
+
+#ifdef _UNICODE
+ wchar_t *ws = a2w(PROTO);
+ wsprintf(buffer, L"%s Error", TranslateW(ws));
+ free(ws);
+#else
+ sprintf(buffer, "%s Error", Translate(PROTO));
+#endif
+
+
+ switch(disp) {
+ case ED_POP:
+ ShowPopup(buffer, msg, 0);
+ break;
+ case ED_MB:
+ MessageBox(0, msg, buffer, MB_OK | MB_ICONWARNING);
+ break;
+ case ED_BAL:
+ {
+ MIRANDASYSTRAYNOTIFY sn = {0};
+ sn.cbSize = sizeof(sn);
+ sn.szProto = PROTO;
+ sn.szInfoTitle = t2a(buffer);
+ sn.szInfo = t2a(msg);
+ sn.dwInfoFlags = NIIF_ERROR;
+ sn.uTimeout = 10;
+
+ CallService(MS_CLIST_SYSTRAY_NOTIFY, 0, (LPARAM)&sn);
+
+ free(sn.szInfoTitle);
+ free(sn.szInfo);
+ }
+
+ break;
+ }
+}
+
+
+void InitUtils() {
+ hProtoIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_ICON_PROTO), IMAGE_ICON, SM_CXSMICON, SM_CYSMICON, 0);
+ //hProtoIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_ICON_PROTO), IMAGE_ICON, SM_CXICON, SM_CYICON, 0);
+}
+
+void DeinitUtils() {
+ DestroyIcon(hProtoIcon);
+}
+
+char *w2u(const wchar_t *ws) {
+ if(ws) {
+ int size = WideCharToMultiByte(CP_UTF8, 0, ws, -1, 0, 0, 0, 0);
+ char *buff = (char *)malloc(size);
+ WideCharToMultiByte(CP_UTF8, 0, ws, -1, buff, size, 0, 0);
+ return buff;
+ } else
+ return 0;
+}
+
+wchar_t *u2w(const char *utfs) {
+ if(utfs) {
+ int size = MultiByteToWideChar(CP_UTF8, 0, utfs, -1, 0, 0);
+ wchar_t *buff = (wchar_t *)malloc(size * sizeof(wchar_t));
+ MultiByteToWideChar(CP_UTF8, 0, utfs, -1, buff, size);
+ return buff;
+ } else
+ return 0;
+}
+
+wchar_t *a2w(const char *as) {
+ int size = MultiByteToWideChar(code_page, 0, as, -1, 0, 0);
+ wchar_t *buff = (wchar_t *)malloc(size * sizeof(wchar_t));
+ MultiByteToWideChar(code_page, 0, as, -1, buff, size);
+ return buff;
+}
+
+char *w2a(const wchar_t *ws) {
+ int size = WideCharToMultiByte(code_page, 0, ws, -1, 0, 0, 0, 0);
+ char *buff = (char *)malloc(size);
+ WideCharToMultiByte(code_page, 0, ws, -1, buff, size, 0, 0);
+ return buff;
+}
+
+char *t2a(const TCHAR *ts) {
+#ifdef _UNICODE
+ return w2a(ts);
+#else
+ return _strdup(ts);
+#endif
+}
+
+TCHAR *a2t(const char *as) {
+#ifdef _UNICODE
+ return a2w(as);
+#else
+ return _strdup(as);
+#endif
+}
+
+TCHAR *u2t(const char *utfs) {
+#ifdef _UNICODE
+ return u2w(utfs);
+#else
+ wchar_t *ws = u2w(utfs);
+ char *ret = w2a(ws);
+ free(ws);
+ return ret;
+#endif
+}
+
+char *t2u(const TCHAR *ts) {
+#ifdef _UNICODE
+ return w2u(ts);
+#else
+ wchar_t *ws = a2w(ts);
+ char *ret = w2u(ws);
+ free(ws);
+ return ret;
+#endif
+}
+
+char *u2a(const char *utfs) {
+ wchar_t *ws = u2w(utfs);
+ char *ret = w2a(ws);
+ free(ws);
+ return ret;
+}
+
+char *a2u(const char *as) {
+ wchar_t *ws = a2w(as);
+ char *ret = w2u(ws);
+ free(ws);
+ return ret;
+}
diff --git a/plugins/!NotAdopted/sametime/utils.h b/plugins/!NotAdopted/sametime/utils.h
new file mode 100644
index 0000000000..600562cf60
--- /dev/null
+++ b/plugins/!NotAdopted/sametime/utils.h
@@ -0,0 +1,37 @@
+#ifndef _UTILS_INC
+#define _UTILS_INC
+
+#include "common.h"
+#include "options.h"
+
+wchar_t *a2w(const char *as);
+char *w2a(const wchar_t *ws);
+
+char *w2u(const wchar_t *ws);
+wchar_t *u2w(const char *ws);
+
+TCHAR *u2t(const char *utfs);
+char *t2u(const TCHAR *ts);
+
+char *t2a(const TCHAR *ts);
+TCHAR *a2t(const char *as);
+
+char *u2a(const char *utfs);
+char *a2u(const char *as);
+
+void InitUtils();
+void DeinitUtils();
+
+void ShowPopupA( const char* line1, const char* line2, int flags = 0);
+void ShowPopupW( const wchar_t* line1, const wchar_t* line2, int flags = 0);
+
+#ifdef _UNICODE
+#define ShowPopup ShowPopupW
+#else
+#define ShowPopup ShowPopupA
+#endif
+
+void ShowWarning(TCHAR *msg);
+void ShowError(TCHAR *msg);
+
+#endif