From 964a7089f8a243fed81b9fc293512c7e2be6ce18 Mon Sep 17 00:00:00 2001 From: "(no author)" <(no author)@4f64403b-2f21-0410-a795-97e2b3489a10> Date: Tue, 3 Jun 2008 13:27:13 +0000 Subject: import sametime plugin source git-svn-id: https://server.scottellis.com.au/svn/mim_plugs@412 4f64403b-2f21-0410-a795-97e2b3489a10 --- sametime/conference.cpp | 565 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 565 insertions(+) create mode 100644 sametime/conference.cpp (limited to 'sametime/conference.cpp') diff --git a/sametime/conference.cpp b/sametime/conference.cpp new file mode 100644 index 0000000..52e6a29 --- /dev/null +++ b/sametime/conference.cpp @@ -0,0 +1,565 @@ +#include "conference.h" + +typedef std::queue 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); +} + -- cgit v1.2.3